pax_global_header00006660000000000000000000000064135536027270014524gustar00rootroot0000000000000052 comment=a04808c16cfc126d9fe572ae7c4b5a3d39de5796 trusted-firmware-a-2.2/000077500000000000000000000000001355360272700151115ustar00rootroot00000000000000trusted-firmware-a-2.2/.checkpatch.conf000066400000000000000000000055001355360272700201330ustar00rootroot00000000000000# # Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # # Configure how the Linux checkpatch script should be invoked in the context of # the Trusted Firmware source tree. # # This is not Linux so don't expect a Linux tree! --no-tree # The Linux kernel expects the SPDX license tag in the first line of each file. # We don't follow this in the Trusted Firmware. --ignore SPDX_LICENSE_TAG # This clarifes the lines indications in the report. # # E.g.: # Without this option, we have the following output: # #333: FILE: drivers/arm/gic/arm_gic.c:160: # So we have 2 lines indications (333 and 160), which is confusing. # We only care about the position in the source file. # # With this option, it becomes: # drivers/arm/gic/arm_gic.c:160: --showfile # Don't show some messages like the list of ignored types or the suggestion to # use "--fix" or report changes to the maintainers. --quiet # # Ignore the following message types, as they don't necessarily make sense in # the context of the Trusted Firmware. # # COMPLEX_MACRO generates false positives. --ignore COMPLEX_MACRO # Commit messages might contain a Gerrit Change-Id. --ignore GERRIT_CHANGE_ID # Do not check the format of commit messages, as Gerrit's merge commits do not # preserve it. --ignore GIT_COMMIT_ID # FILE_PATH_CHANGES reports this kind of message: # "added, moved or deleted file(s), does MAINTAINERS need updating?" # We do not use this MAINTAINERS file process in TF. --ignore FILE_PATH_CHANGES # AVOID_EXTERNS reports this kind of messages: # "externs should be avoided in .c files" # We don't follow this convention in TF. --ignore AVOID_EXTERNS # NEW_TYPEDEFS reports this kind of messages: # "do not add new typedefs" # We allow adding new typedefs in TF. --ignore NEW_TYPEDEFS # Avoid "Does not appear to be a unified-diff format patch" message --ignore NOT_UNIFIED_DIFF # VOLATILE reports this kind of messages: # "Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt" # We allow the usage of the volatile keyword in TF. --ignore VOLATILE # BRACES reports this kind of messages: # braces {} are not necessary for any arm of this statement --ignore BRACES # 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 trusted-firmware-a-2.2/.editorconfig000066400000000000000000000036211355360272700175700ustar00rootroot00000000000000# # Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Trusted Firmware-A Coding style spec for editors. # References: # [EC] http://editorconfig.org/ # [CONT] contributing.rst # [LCS] Linux Coding Style # (https://www.kernel.org/doc/html/v4.10/process/coding-style.html) # [PEP8] Style Guide for Python Code # (https://www.python.org/dev/peps/pep-0008) root = true # set default to match [LCS] .c/.h settings. # This will also apply to .S, .mk, .sh, Makefile, .dts, etc. [*] # Not specified, but fits current ARM-TF sources. charset = utf-8 # Not specified, but implicit for "LINUX coding style". end_of_line = lf # [LCS] Chapter 1: Indentation # "and thus indentations are also 8 characters" indent_size = 8 # [LCS] Chapter 1: Indentation # "Outside of comments,...spaces are never used for indentation" indent_style = tab # Not specified by [LCS], but sensible insert_final_newline = true # [LCS] Chapter 2: Breaking long lines and strings # "The limit on the length of lines is 80 columns" # This is a "soft" requirement for Arm-TF, and should not be the sole # reason for changes. max_line_length = 80 # [LCS] Chapter 1: Indentation # "Tabs are 8 characters" tab_width = 8 # [LCS] Chapter 1: Indentation # "Get a decent editor and don't leave whitespace at the end of lines." # [LCS] Chapter 3.1: Spaces # "Do not leave trailing whitespace at the ends of lines." trim_trailing_whitespace = true # Adjustment for ReStructuredText (RST) documentation [*.{rst}] indent_size = 4 indent_style = space # Adjustment for python which prefers a different style [*.py] # [PEP8] Indentation # "Use 4 spaces per indentation level." indent_size = 4 indent_style = space # [PEP8] Maximum Line Length # "Limit all lines to a maximum of 79 characters." max_line_length = 79 trusted-firmware-a-2.2/.gitignore000066400000000000000000000012761355360272700171070ustar00rootroot00000000000000# Ignore miscellaneous files cscope.* *.swp *.patch *~ .project .cproject # Ignore build directory build/ # Ignore build products from tools tools/**/*.o tools/renesas/rcar_layout_create/*.bin tools/renesas/rcar_layout_create/*.srec tools/renesas/rcar_layout_create/*.map tools/renesas/rcar_layout_create/*.elf tools/fiptool/fiptool tools/fiptool/fiptool.exe tools/cert_create/src/*.o tools/cert_create/src/**/*.o tools/cert_create/cert_create tools/cert_create/cert_create.exe tools/marvell/doimage/doimage tools/amlogic/doimage tools/stm32image/*.o tools/stm32image/stm32image tools/stm32image/stm32image.exe tools/sptool/sptool tools/sptool/sptool.exe # GNU GLOBAL files GPATH GRTAGS GSYMS GTAGS trusted-firmware-a-2.2/Makefile000066400000000000000000001033641355360272700165600ustar00rootroot00000000000000# # Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # # Trusted Firmware Version # VERSION_MAJOR := 2 VERSION_MINOR := 2 # Default goal is build all images .DEFAULT_GOAL := all # Avoid any implicit propagation of command line variable definitions to # sub-Makefiles, like CFLAGS that we reserved for the firmware images' # usage. Other command line options like "-s" are still propagated as usual. MAKEOVERRIDES = MAKE_HELPERS_DIRECTORY := make_helpers/ include ${MAKE_HELPERS_DIRECTORY}build_macros.mk include ${MAKE_HELPERS_DIRECTORY}build_env.mk ################################################################################ # Default values for build configurations, and their dependencies ################################################################################ include ${MAKE_HELPERS_DIRECTORY}defaults.mk # Assertions enabled for DEBUG builds by default ENABLE_ASSERTIONS := ${DEBUG} ENABLE_PMF := ${ENABLE_RUNTIME_INSTRUMENTATION} PLAT := ${DEFAULT_PLAT} ################################################################################ # Checkpatch script options ################################################################################ CHECKCODE_ARGS := --no-patch # Do not check the coding style on imported library files or documentation files INC_LIB_DIRS_TO_CHECK := $(sort $(filter-out \ include/lib/libfdt \ include/lib/libc, \ $(wildcard include/lib/*))) INC_DIRS_TO_CHECK := $(sort $(filter-out \ include/lib, \ $(wildcard include/*))) LIB_DIRS_TO_CHECK := $(sort $(filter-out \ lib/compiler-rt \ lib/libfdt% \ lib/libc, \ $(wildcard lib/*))) ROOT_DIRS_TO_CHECK := $(sort $(filter-out \ lib \ include \ docs \ %.rst, \ $(wildcard *))) CHECK_PATHS := ${ROOT_DIRS_TO_CHECK} \ ${INC_DIRS_TO_CHECK} \ ${INC_LIB_DIRS_TO_CHECK} \ ${LIB_DIRS_TO_CHECK} ################################################################################ # Process build options ################################################################################ # Verbose flag ifeq (${V},0) Q:=@ ECHO:=@echo CHECKCODE_ARGS += --no-summary --terse else Q:= ECHO:=$(ECHO_QUIET) endif ifneq ($(findstring s,$(filter-out --%,$(MAKEFLAGS))),) Q:=@ ECHO:=$(ECHO_QUIET) endif export Q ECHO # Process Debug flag $(eval $(call add_define,DEBUG)) ifneq (${DEBUG}, 0) BUILD_TYPE := debug TF_CFLAGS += -g ifneq ($(findstring clang,$(notdir $(CC))),) ASFLAGS += -g else ASFLAGS += -g -Wa,--gdwarf-2 endif # Use LOG_LEVEL_INFO by default for debug builds LOG_LEVEL := 40 else BUILD_TYPE := release # Use LOG_LEVEL_NOTICE by default for release builds LOG_LEVEL := 20 endif # Default build string (git branch and commit) ifeq (${BUILD_STRING},) BUILD_STRING := $(shell git describe --always --dirty --tags 2> /dev/null) endif VERSION_STRING := v${VERSION_MAJOR}.${VERSION_MINOR}(${BUILD_TYPE}):${BUILD_STRING} # The cert_create tool cannot generate certificates individually, so we use the # target 'certificates' to create them all ifneq (${GENERATE_COT},0) FIP_DEPS += certificates FWU_FIP_DEPS += fwu_certificates endif # Process BRANCH_PROTECTION value and set # Pointer Authentication and Branch Target Identification flags ifeq (${BRANCH_PROTECTION},0) # Default value turns off all types of branch protection BP_OPTION := none else ifneq (${ARCH},aarch64) $(error BRANCH_PROTECTION requires AArch64) else ifeq (${BRANCH_PROTECTION},1) # Enables all types of branch protection features BP_OPTION := standard ENABLE_BTI := 1 ENABLE_PAUTH := 1 else ifeq (${BRANCH_PROTECTION},2) # Return address signing to its standard level BP_OPTION := pac-ret ENABLE_PAUTH := 1 else ifeq (${BRANCH_PROTECTION},3) # Extend the signing to include leaf functions BP_OPTION := pac-ret+leaf ENABLE_PAUTH := 1 else $(error Unknown BRANCH_PROTECTION value ${BRANCH_PROTECTION}) endif # USE_SPINLOCK_CAS requires AArch64 build ifeq (${USE_SPINLOCK_CAS},1) ifneq (${ARCH},aarch64) $(error USE_SPINLOCK_CAS requires AArch64) else $(info USE_SPINLOCK_CAS is an experimental feature) endif endif ################################################################################ # Toolchain ################################################################################ HOSTCC := gcc export HOSTCC CC := ${CROSS_COMPILE}gcc CPP := ${CROSS_COMPILE}cpp AS := ${CROSS_COMPILE}gcc AR := ${CROSS_COMPILE}ar LINKER := ${CROSS_COMPILE}ld OC := ${CROSS_COMPILE}objcopy OD := ${CROSS_COMPILE}objdump NM := ${CROSS_COMPILE}nm PP := ${CROSS_COMPILE}gcc -E DTC := dtc # Use ${LD}.bfd instead if it exists (as absolute path or together with $PATH). ifneq ($(strip $(wildcard ${LD}.bfd) \ $(foreach dir,$(subst :, ,${PATH}),$(wildcard ${dir}/${LINKER}.bfd))),) LINKER := ${LINKER}.bfd endif ifeq (${ARM_ARCH_MAJOR},7) target32-directive = -target arm-none-eabi # Will set march32-directive from platform configuration else target32-directive = -target armv8a-none-eabi # Set the compiler's target architecture profile based on ARM_ARCH_MINOR option ifeq (${ARM_ARCH_MINOR},0) march32-directive = -march=armv8-a march64-directive = -march=armv8-a else march32-directive = -march=armv8.${ARM_ARCH_MINOR}-a march64-directive = -march=armv8.${ARM_ARCH_MINOR}-a endif endif ifneq ($(findstring armclang,$(notdir $(CC))),) TF_CFLAGS_aarch32 = -target arm-arm-none-eabi $(march32-directive) TF_CFLAGS_aarch64 = -target aarch64-arm-none-eabi $(march64-directive) LD = $(LINKER) AS = $(CC) -c -x assembler-with-cpp $(TF_CFLAGS_$(ARCH)) CPP = $(CC) -E $(TF_CFLAGS_$(ARCH)) PP = $(CC) -E $(TF_CFLAGS_$(ARCH)) else ifneq ($(findstring clang,$(notdir $(CC))),) TF_CFLAGS_aarch32 = $(target32-directive) $(march32-directive) TF_CFLAGS_aarch64 = -target aarch64-elf $(march64-directive) LD = $(LINKER) AS = $(CC) -c -x assembler-with-cpp $(TF_CFLAGS_$(ARCH)) CPP = $(CC) -E PP = $(CC) -E else TF_CFLAGS_aarch32 = $(march32-directive) TF_CFLAGS_aarch64 = $(march64-directive) LD = $(LINKER) endif ifeq (${AARCH32_INSTRUCTION_SET},A32) TF_CFLAGS_aarch32 += -marm else ifeq (${AARCH32_INSTRUCTION_SET},T32) TF_CFLAGS_aarch32 += -mthumb else $(error Error: Unknown AArch32 instruction set ${AARCH32_INSTRUCTION_SET}) endif TF_CFLAGS_aarch32 += -mno-unaligned-access TF_CFLAGS_aarch64 += -mgeneral-regs-only -mstrict-align ifneq (${BP_OPTION},none) TF_CFLAGS_aarch64 += -mbranch-protection=${BP_OPTION} endif ASFLAGS_aarch32 = $(march32-directive) ASFLAGS_aarch64 = $(march64-directive) WARNING1 := -Wextra WARNING1 += -Wmissing-declarations WARNING1 += -Wmissing-format-attribute WARNING1 += -Wmissing-prototypes WARNING1 += -Wold-style-definition WARNING1 += -Wunused-const-variable WARNING2 := -Waggregate-return WARNING2 += -Wcast-align WARNING2 += -Wnested-externs WARNING2 += -Wshadow WARNING2 += -Wlogical-op WARNING2 += -Wmissing-field-initializers WARNING2 += -Wsign-compare WARNING3 := -Wbad-function-cast WARNING3 += -Wcast-qual WARNING3 += -Wconversion WARNING3 += -Wpacked WARNING3 += -Wpadded WARNING3 += -Wpointer-arith WARNING3 += -Wredundant-decls WARNING3 += -Wswitch-default ifeq (${W},1) WARNINGS := $(WARNING1) else ifeq (${W},2) WARNINGS := $(WARNING1) $(WARNING2) else ifeq (${W},3) WARNINGS := $(WARNING1) $(WARNING2) $(WARNING3) endif WARNINGS += -Wunused -Wno-unused-parameter \ -Wdisabled-optimization \ -Wvla ifeq ($(findstring clang,$(notdir $(CC))),) # not using clang WARNINGS += -Wunused-but-set-variable \ -Wmaybe-uninitialized \ -Wpacked-bitfield-compat \ -Wshift-overflow=2 else # using clang WARNINGS += -Wshift-overflow -Wshift-sign-overflow endif ifneq (${E},0) ERRORS := -Werror endif CPPFLAGS = ${DEFINES} ${INCLUDES} ${MBEDTLS_INC} -nostdinc \ -Wmissing-include-dirs $(ERRORS) $(WARNINGS) ASFLAGS += $(CPPFLAGS) $(ASFLAGS_$(ARCH)) \ -ffreestanding -Wa,--fatal-warnings TF_CFLAGS += $(CPPFLAGS) $(TF_CFLAGS_$(ARCH)) \ -ffreestanding -fno-builtin -Wall -std=gnu99 \ -Os -ffunction-sections -fdata-sections ifeq (${SANITIZE_UB},on) TF_CFLAGS += -fsanitize=undefined -fno-sanitize-recover endif ifeq (${SANITIZE_UB},trap) TF_CFLAGS += -fsanitize=undefined -fno-sanitize-recover \ -fsanitize-undefined-trap-on-error endif GCC_V_OUTPUT := $(shell $(CC) -v 2>&1) ifneq ($(findstring armlink,$(notdir $(LD))),) TF_LDFLAGS += --diag_error=warning --lto_level=O1 TF_LDFLAGS += --remove --info=unused,unusedsymbols else TF_LDFLAGS += --fatal-warnings -O1 TF_LDFLAGS += --gc-sections endif TF_LDFLAGS += $(TF_LDFLAGS_$(ARCH)) DTC_FLAGS += -I dts -O dtb DTC_CPPFLAGS += -nostdinc -Iinclude -undef -x assembler-with-cpp ################################################################################ # Common sources and include directories ################################################################################ include lib/compiler-rt/compiler-rt.mk BL_COMMON_SOURCES += common/bl_common.c \ common/tf_log.c \ common/${ARCH}/debug.S \ drivers/console/multi_console.c \ lib/${ARCH}/cache_helpers.S \ lib/${ARCH}/misc_helpers.S \ plat/common/plat_bl_common.c \ plat/common/plat_log_common.c \ plat/common/${ARCH}/plat_common.c \ plat/common/${ARCH}/platform_helpers.S \ ${COMPILER_RT_SRCS} ifeq ($(notdir $(CC)),armclang) BL_COMMON_SOURCES += lib/${ARCH}/armclang_printf.S endif ifeq (${SANITIZE_UB},on) BL_COMMON_SOURCES += plat/common/ubsan.c endif INCLUDES += -Iinclude \ -Iinclude/arch/${ARCH} \ -Iinclude/lib/cpus/${ARCH} \ -Iinclude/lib/el3_runtime/${ARCH} \ ${PLAT_INCLUDES} \ ${SPD_INCLUDES} include common/backtrace/backtrace.mk ################################################################################ # Generic definitions ################################################################################ include ${MAKE_HELPERS_DIRECTORY}plat_helpers.mk BUILD_BASE := ./build BUILD_PLAT := ${BUILD_BASE}/${PLAT}/${BUILD_TYPE} SPDS := $(sort $(filter-out none, $(patsubst services/spd/%,%,$(wildcard services/spd/*)))) # Platforms providing their own TBB makefile may override this value INCLUDE_TBBR_MK := 1 ################################################################################ # Include SPD Makefile if one has been specified ################################################################################ ifneq (${SPD},none) ifeq (${ARCH},aarch32) $(error "Error: SPD is incompatible with AArch32.") endif ifdef EL3_PAYLOAD_BASE $(warning "SPD and EL3_PAYLOAD_BASE are incompatible build options.") $(warning "The SPD and its BL32 companion will be present but ignored.") endif # We expect to locate an spd.mk under the specified SPD directory SPD_MAKE := $(wildcard services/spd/${SPD}/${SPD}.mk) ifeq (${SPD_MAKE},) $(error Error: No services/spd/${SPD}/${SPD}.mk located) endif $(info Including ${SPD_MAKE}) include ${SPD_MAKE} # If there's BL32 companion for the chosen SPD, we expect that the SPD's # Makefile would set NEED_BL32 to "yes". In this case, the build system # supports two mutually exclusive options: # * BL32 is built from source: then BL32_SOURCES must contain the list # of source files to build BL32 # * BL32 is a prebuilt binary: then BL32 must point to the image file # that will be included in the FIP # If both BL32_SOURCES and BL32 are defined, the binary takes precedence # over the sources. endif ################################################################################ # Include the platform specific Makefile after the SPD Makefile (the platform # makefile may use all previous definitions in this file) ################################################################################ include ${PLAT_MAKEFILE_FULL} $(eval $(call MAKE_PREREQ_DIR,${BUILD_PLAT})) ifeq (${ARM_ARCH_MAJOR},7) include make_helpers/armv7-a-cpus.mk endif ifeq ($(ENABLE_PIE),1) TF_CFLAGS += -fpie TF_LDFLAGS += -pie --no-dynamic-linker else PIE_FOUND := $(findstring --enable-default-pie,${GCC_V_OUTPUT}) ifneq ($(PIE_FOUND),) TF_CFLAGS += -fno-PIE endif endif # Include the CPU specific operations makefile, which provides default # values for all CPU errata workarounds and CPU specific optimisations. # This can be overridden by the platform. include lib/cpus/cpu-ops.mk ifeq (${ARCH},aarch32) NEED_BL32 := yes ################################################################################ # Build `AARCH32_SP` as BL32 image for AArch32 ################################################################################ ifneq (${AARCH32_SP},none) # We expect to locate an sp.mk under the specified AARCH32_SP directory AARCH32_SP_MAKE := $(wildcard bl32/${AARCH32_SP}/${AARCH32_SP}.mk) ifeq (${AARCH32_SP_MAKE},) $(error Error: No bl32/${AARCH32_SP}/${AARCH32_SP}.mk located) endif $(info Including ${AARCH32_SP_MAKE}) include ${AARCH32_SP_MAKE} endif endif ################################################################################ # Include libc if not overridden ################################################################################ ifeq (${OVERRIDE_LIBC},0) include lib/libc/libc.mk endif ################################################################################ # Check incompatible options ################################################################################ ifdef EL3_PAYLOAD_BASE ifdef PRELOADED_BL33_BASE $(warning "PRELOADED_BL33_BASE and EL3_PAYLOAD_BASE are \ incompatible build options. EL3_PAYLOAD_BASE has priority.") endif ifneq (${GENERATE_COT},0) $(error "GENERATE_COT and EL3_PAYLOAD_BASE are incompatible build options.") endif ifneq (${TRUSTED_BOARD_BOOT},0) $(error "TRUSTED_BOARD_BOOT and EL3_PAYLOAD_BASE are incompatible build options.") endif endif ifeq (${NEED_BL33},yes) ifdef EL3_PAYLOAD_BASE $(warning "BL33 image is not needed when option \ BL33_PAYLOAD_BASE is used and won't be added to the FIP file.") endif ifdef PRELOADED_BL33_BASE $(warning "BL33 image is not needed when option \ PRELOADED_BL33_BASE is used and won't be added to the FIP \ file.") endif endif # When building for systems with hardware-assisted coherency, there's no need to # use USE_COHERENT_MEM. Require that USE_COHERENT_MEM must be set to 0 too. ifeq ($(HW_ASSISTED_COHERENCY)-$(USE_COHERENT_MEM),1-1) $(error USE_COHERENT_MEM cannot be enabled with HW_ASSISTED_COHERENCY) 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") endif # For RAS_EXTENSION, require that EAs are handled in EL3 first ifeq ($(RAS_EXTENSION),1) ifneq ($(HANDLE_EA_EL3_FIRST),1) $(error For RAS_EXTENSION, HANDLE_EA_EL3_FIRST must also be 1) endif endif # When FAULT_INJECTION_SUPPORT is used, require that RAS_EXTENSION is enabled ifeq ($(FAULT_INJECTION_SUPPORT),1) ifneq ($(RAS_EXTENSION),1) $(error For FAULT_INJECTION_SUPPORT, RAS_EXTENSION must also be 1) endif endif # DYN_DISABLE_AUTH can be set only when TRUSTED_BOARD_BOOT=1 ifeq ($(DYN_DISABLE_AUTH), 1) ifeq (${TRUSTED_BOARD_BOOT}, 0) $(error "TRUSTED_BOARD_BOOT must be enabled for DYN_DISABLE_AUTH to be set.") endif endif # If pointer authentication is used in the firmware, make sure that all the # registers associated to it are also saved and restored. # Not doing it would leak the value of the keys used by EL3 to EL1 and S-EL1. ifeq ($(ENABLE_PAUTH),1) ifeq ($(CTX_INCLUDE_PAUTH_REGS),0) $(error Pointer Authentication requires CTX_INCLUDE_PAUTH_REGS=1) endif endif ifeq ($(CTX_INCLUDE_PAUTH_REGS),1) ifneq (${ARCH},aarch64) $(error CTX_INCLUDE_PAUTH_REGS requires AArch64) else $(info CTX_INCLUDE_PAUTH_REGS is an experimental feature) endif endif ifeq ($(ENABLE_PAUTH),1) $(info Pointer Authentication is an experimental feature) endif ifeq ($(ENABLE_BTI),1) $(info Branch Protection is an experimental feature) endif ifeq ($(CTX_INCLUDE_MTE_REGS),1) ifneq (${ARCH},aarch64) $(error CTX_INCLUDE_MTE_REGS requires AArch64) else $(info CTX_INCLUDE_MTE_REGS is an experimental feature) endif endif ################################################################################ # Process platform overrideable behaviour ################################################################################ # Using BL2 implies that a BL33 image also needs to be supplied for the FIP and # Certificate generation tools. This flag can be overridden by the platform. ifdef BL2_SOURCES ifdef EL3_PAYLOAD_BASE # If booting an EL3 payload there is no need for a BL33 image # in the FIP file. NEED_BL33 := no else ifdef PRELOADED_BL33_BASE # If booting a BL33 preloaded image there is no need of # another one in the FIP file. NEED_BL33 := no else NEED_BL33 ?= yes endif endif endif # If SCP_BL2 is given, we always want FIP to include it. ifdef SCP_BL2 NEED_SCP_BL2 := yes endif # For AArch32, BL31 is not currently supported. ifneq (${ARCH},aarch32) ifdef BL31_SOURCES # When booting an EL3 payload, there is no need to compile the BL31 image nor # put it in the FIP. ifndef EL3_PAYLOAD_BASE NEED_BL31 := yes endif endif endif # Process TBB related flags ifneq (${GENERATE_COT},0) # Common cert_create options ifneq (${CREATE_KEYS},0) $(eval CRT_ARGS += -n) $(eval FWU_CRT_ARGS += -n) ifneq (${SAVE_KEYS},0) $(eval CRT_ARGS += -k) $(eval FWU_CRT_ARGS += -k) endif endif # Include TBBR makefile (unless the platform indicates otherwise) ifeq (${INCLUDE_TBBR_MK},1) include make_helpers/tbbr/tbbr_tools.mk endif endif ifneq (${FIP_ALIGN},0) FIP_ARGS += --align ${FIP_ALIGN} endif ################################################################################ # Include libraries' Makefile that are used in all BL ################################################################################ include lib/stack_protector/stack_protector.mk ################################################################################ # Auxiliary tools (fiptool, cert_create, etc) ################################################################################ # Variables for use with Certificate Generation Tool CRTTOOLPATH ?= tools/cert_create CRTTOOL ?= ${CRTTOOLPATH}/cert_create${BIN_EXT} # Variables for use with Firmware Image Package FIPTOOLPATH ?= tools/fiptool FIPTOOL ?= ${FIPTOOLPATH}/fiptool${BIN_EXT} # Variables for use with sptool SPTOOLPATH ?= tools/sptool SPTOOL ?= ${SPTOOLPATH}/sptool${BIN_EXT} # Variables for use with ROMLIB ROMLIBPATH ?= lib/romlib ################################################################################ # Include BL specific makefiles ################################################################################ ifdef BL1_SOURCES NEED_BL1 := yes include bl1/bl1.mk endif ifdef BL2_SOURCES NEED_BL2 := yes include bl2/bl2.mk endif ifdef BL2U_SOURCES NEED_BL2U := yes include bl2u/bl2u.mk endif ifeq (${NEED_BL31},yes) ifdef BL31_SOURCES include bl31/bl31.mk endif endif ifdef FDT_SOURCES NEED_FDT := yes endif ################################################################################ # Build options checks ################################################################################ $(eval $(call assert_boolean,COLD_BOOT_SINGLE_CPU)) $(eval $(call assert_boolean,CREATE_KEYS)) $(eval $(call assert_boolean,CTX_INCLUDE_AARCH32_REGS)) $(eval $(call assert_boolean,CTX_INCLUDE_FPREGS)) $(eval $(call assert_boolean,CTX_INCLUDE_PAUTH_REGS)) $(eval $(call assert_boolean,CTX_INCLUDE_MTE_REGS)) $(eval $(call assert_boolean,DEBUG)) $(eval $(call assert_boolean,DYN_DISABLE_AUTH)) $(eval $(call assert_boolean,EL3_EXCEPTION_HANDLING)) $(eval $(call assert_boolean,ENABLE_AMU)) $(eval $(call assert_boolean,ENABLE_ASSERTIONS)) $(eval $(call assert_boolean,ENABLE_MPAM_FOR_LOWER_ELS)) $(eval $(call assert_boolean,ENABLE_PIE)) $(eval $(call assert_boolean,ENABLE_PMF)) $(eval $(call assert_boolean,ENABLE_PSCI_STAT)) $(eval $(call assert_boolean,ENABLE_RUNTIME_INSTRUMENTATION)) $(eval $(call assert_boolean,ENABLE_SPE_FOR_LOWER_ELS)) $(eval $(call assert_boolean,ENABLE_SPM)) $(eval $(call assert_boolean,ENABLE_SVE_FOR_NS)) $(eval $(call assert_boolean,ERROR_DEPRECATED)) $(eval $(call assert_boolean,FAULT_INJECTION_SUPPORT)) $(eval $(call assert_boolean,GENERATE_COT)) $(eval $(call assert_boolean,GICV2_G0_FOR_EL3)) $(eval $(call assert_boolean,HANDLE_EA_EL3_FIRST)) $(eval $(call assert_boolean,HW_ASSISTED_COHERENCY)) $(eval $(call assert_boolean,NS_TIMER_SWITCH)) $(eval $(call assert_boolean,OVERRIDE_LIBC)) $(eval $(call assert_boolean,PL011_GENERIC_UART)) $(eval $(call assert_boolean,PROGRAMMABLE_RESET_ADDRESS)) $(eval $(call assert_boolean,PSCI_EXTENDED_STATE_ID)) $(eval $(call assert_boolean,RAS_EXTENSION)) $(eval $(call assert_boolean,RESET_TO_BL31)) $(eval $(call assert_boolean,SAVE_KEYS)) $(eval $(call assert_boolean,SEPARATE_CODE_AND_RODATA)) $(eval $(call assert_boolean,SPIN_ON_BL1_EXIT)) $(eval $(call assert_boolean,SPM_MM)) $(eval $(call assert_boolean,TRUSTED_BOARD_BOOT)) $(eval $(call assert_boolean,USE_COHERENT_MEM)) $(eval $(call assert_boolean,USE_ROMLIB)) $(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,BL2_INV_DCACHE)) $(eval $(call assert_boolean,USE_SPINLOCK_CAS)) $(eval $(call assert_numeric,ARM_ARCH_MAJOR)) $(eval $(call assert_numeric,ARM_ARCH_MINOR)) $(eval $(call assert_numeric,BRANCH_PROTECTION)) ifdef KEY_SIZE $(eval $(call assert_numeric,KEY_SIZE)) endif ifeq ($(filter $(SANITIZE_UB), on off trap),) $(error "Invalid value for SANITIZE_UB: can be one of on, off, trap") endif ################################################################################ # Add definitions to the cpp preprocessor based on the current build options. # This is done after including the platform specific makefile to allow the # platform to overwrite the default options ################################################################################ $(eval $(call add_define,ARM_ARCH_MAJOR)) $(eval $(call add_define,ARM_ARCH_MINOR)) $(eval $(call add_define,COLD_BOOT_SINGLE_CPU)) $(eval $(call add_define,CTX_INCLUDE_AARCH32_REGS)) $(eval $(call add_define,CTX_INCLUDE_FPREGS)) $(eval $(call add_define,CTX_INCLUDE_PAUTH_REGS)) $(eval $(call add_define,EL3_EXCEPTION_HANDLING)) $(eval $(call add_define,CTX_INCLUDE_MTE_REGS)) $(eval $(call add_define,ENABLE_AMU)) $(eval $(call add_define,ENABLE_ASSERTIONS)) $(eval $(call add_define,ENABLE_BTI)) $(eval $(call add_define,ENABLE_MPAM_FOR_LOWER_ELS)) $(eval $(call add_define,ENABLE_PAUTH)) $(eval $(call add_define,ENABLE_PIE)) $(eval $(call add_define,ENABLE_PMF)) $(eval $(call add_define,ENABLE_PSCI_STAT)) $(eval $(call add_define,ENABLE_RUNTIME_INSTRUMENTATION)) $(eval $(call add_define,ENABLE_SPE_FOR_LOWER_ELS)) $(eval $(call add_define,ENABLE_SPM)) $(eval $(call add_define,ENABLE_SVE_FOR_NS)) $(eval $(call add_define,ERROR_DEPRECATED)) $(eval $(call add_define,FAULT_INJECTION_SUPPORT)) $(eval $(call add_define,GICV2_G0_FOR_EL3)) $(eval $(call add_define,HANDLE_EA_EL3_FIRST)) $(eval $(call add_define,HW_ASSISTED_COHERENCY)) $(eval $(call add_define,LOG_LEVEL)) $(eval $(call add_define,NS_TIMER_SWITCH)) $(eval $(call add_define,PL011_GENERIC_UART)) $(eval $(call add_define,PLAT_${PLAT})) $(eval $(call add_define,PROGRAMMABLE_RESET_ADDRESS)) $(eval $(call add_define,PSCI_EXTENDED_STATE_ID)) $(eval $(call add_define,RAS_EXTENSION)) $(eval $(call add_define,RESET_TO_BL31)) $(eval $(call add_define,SEPARATE_CODE_AND_RODATA)) $(eval $(call add_define,RECLAIM_INIT_CODE)) $(eval $(call add_define,SPD_${SPD})) $(eval $(call add_define,SPIN_ON_BL1_EXIT)) $(eval $(call add_define,SPM_MM)) $(eval $(call add_define,TRUSTED_BOARD_BOOT)) $(eval $(call add_define,USE_COHERENT_MEM)) $(eval $(call add_define,USE_ROMLIB)) $(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,BL2_INV_DCACHE)) $(eval $(call add_define,USE_SPINLOCK_CAS)) ifeq (${SANITIZE_UB},trap) $(eval $(call add_define,MONITOR_TRAPS)) endif # Define the EL3_PAYLOAD_BASE flag only if it is provided. ifdef EL3_PAYLOAD_BASE $(eval $(call add_define,EL3_PAYLOAD_BASE)) else # Define the PRELOADED_BL33_BASE flag only if it is provided and # EL3_PAYLOAD_BASE is not defined, as it has priority. ifdef PRELOADED_BL33_BASE $(eval $(call add_define,PRELOADED_BL33_BASE)) endif endif # Define the DYN_DISABLE_AUTH flag only if set. ifeq (${DYN_DISABLE_AUTH},1) $(eval $(call add_define,DYN_DISABLE_AUTH)) endif ifneq ($(findstring armlink,$(notdir $(LD))),) $(eval $(call add_define,USE_ARM_LINK)) endif ################################################################################ # Build targets ################################################################################ .PHONY: all msg_start clean realclean distclean cscope locate-checkpatch checkcodebase checkpatch fiptool sptool fip fwu_fip certtool dtbs .SUFFIXES: all: msg_start msg_start: @echo "Building ${PLAT}" ifeq (${ERROR_DEPRECATED},0) # Check if deprecated declarations and cpp warnings should be treated as error or not. ifneq ($(findstring clang,$(notdir $(CC))),) CPPFLAGS += -Wno-error=deprecated-declarations else CPPFLAGS += -Wno-error=deprecated-declarations -Wno-error=cpp endif # __ASSEMBLY__ is deprecated in favor of the compiler-builtin __ASSEMBLER__. ASFLAGS += -D__ASSEMBLY__ # AARCH32/AARCH64 macros are deprecated in favor of the compiler-builtin __aarch64__. ifeq (${ARCH},aarch32) $(eval $(call add_define,AARCH32)) else $(eval $(call add_define,AARCH64)) endif endif # !ERROR_DEPRECATED $(eval $(call MAKE_LIB_DIRS)) $(eval $(call MAKE_LIB,c)) # Expand build macros for the different images ifeq (${NEED_BL1},yes) $(eval $(call MAKE_BL,1)) endif ifeq (${NEED_BL2},yes) ifeq (${BL2_AT_EL3}, 0) FIP_BL2_ARGS := tb-fw endif $(if ${BL2}, $(eval $(call TOOL_ADD_IMG,bl2,--${FIP_BL2_ARGS})),\ $(eval $(call MAKE_BL,2,${FIP_BL2_ARGS}))) endif ifeq (${NEED_SCP_BL2},yes) $(eval $(call TOOL_ADD_IMG,scp_bl2,--scp-fw)) endif ifeq (${NEED_BL31},yes) BL31_SOURCES += ${SPD_SOURCES} $(if ${BL31}, $(eval $(call TOOL_ADD_IMG,bl31,--soc-fw)),\ $(eval $(call MAKE_BL,31,soc-fw))) endif # If a BL32 image is needed but neither BL32 nor BL32_SOURCES is defined, the # build system will call TOOL_ADD_IMG to print a warning message and abort the # process. Note that the dependency on BL32 applies to the FIP only. ifeq (${NEED_BL32},yes) BUILD_BL32 := $(if $(BL32),,$(if $(BL32_SOURCES),1)) $(if ${BUILD_BL32}, $(eval $(call MAKE_BL,32,tos-fw)),\ $(eval $(call TOOL_ADD_IMG,bl32,--tos-fw))) endif # Add the BL33 image if required by the platform ifeq (${NEED_BL33},yes) $(eval $(call TOOL_ADD_IMG,bl33,--nt-fw)) endif ifeq (${NEED_BL2U},yes) $(if ${BL2U}, $(eval $(call TOOL_ADD_IMG,bl2u,--ap-fwu-cfg,FWU_)),\ $(eval $(call MAKE_BL,2u,ap-fwu-cfg,FWU_))) endif # Expand build macros for the different images ifeq (${NEED_FDT},yes) $(eval $(call MAKE_DTBS,$(BUILD_PLAT)/fdts,$(FDT_SOURCES))) endif locate-checkpatch: ifndef CHECKPATCH $(error "Please set CHECKPATCH to point to the Linux checkpatch.pl file, eg: CHECKPATCH=../linux/scripts/checkpatch.pl") else ifeq (,$(wildcard ${CHECKPATCH})) $(error "The file CHECKPATCH points to cannot be found, use eg: CHECKPATCH=../linux/scripts/checkpatch.pl") endif endif clean: @echo " CLEAN" $(call SHELL_REMOVE_DIR,${BUILD_PLAT}) ${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean ${Q}${MAKE} --no-print-directory -C ${ROMLIBPATH} clean realclean distclean: @echo " REALCLEAN" $(call SHELL_REMOVE_DIR,${BUILD_BASE}) $(call SHELL_DELETE_ALL, ${CURDIR}/cscope.*) ${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean ${Q}${MAKE} --no-print-directory -C ${SPTOOLPATH} clean ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean ${Q}${MAKE} --no-print-directory -C ${ROMLIBPATH} clean checkcodebase: locate-checkpatch @echo " CHECKING STYLE" @if test -d .git ; then \ git ls-files | grep -E -v 'libfdt|libc|docs|\.rst' | \ while read GIT_FILE ; \ do ${CHECKPATCH} ${CHECKCODE_ARGS} -f $$GIT_FILE ; \ done ; \ else \ find . -type f -not -iwholename "*.git*" \ -not -iwholename "*build*" \ -not -iwholename "*libfdt*" \ -not -iwholename "*libc*" \ -not -iwholename "*docs*" \ -not -iwholename "*.rst" \ -exec ${CHECKPATCH} ${CHECKCODE_ARGS} -f {} \; ; \ fi checkpatch: locate-checkpatch @echo " CHECKING STYLE" @if test -n "${CHECKPATCH_OPTS}"; then \ echo " with ${CHECKPATCH_OPTS} option(s)"; \ fi ${Q}COMMON_COMMIT=$$(git merge-base HEAD ${BASE_COMMIT}); \ 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} ${CHECKPATCH_OPTS} - || true; \ git diff --format=email "$$commit~..$$commit" \ -- ${CHECK_PATHS} | \ ${CHECKPATCH} ${CHECKPATCH_OPTS} - || true; \ done certtool: ${CRTTOOL} .PHONY: ${CRTTOOL} ${CRTTOOL}: ${Q}${MAKE} PLAT=${PLAT} USE_TBBR_DEFS=${USE_TBBR_DEFS} --no-print-directory -C ${CRTTOOLPATH} @${ECHO_BLANK_LINE} @echo "Built $@ successfully" @${ECHO_BLANK_LINE} ifneq (${GENERATE_COT},0) certificates: ${CRT_DEPS} ${CRTTOOL} ${Q}${CRTTOOL} ${CRT_ARGS} @${ECHO_BLANK_LINE} @echo "Built $@ successfully" @echo "Certificates can be found in ${BUILD_PLAT}" @${ECHO_BLANK_LINE} endif ${BUILD_PLAT}/${FIP_NAME}: ${FIP_DEPS} ${FIPTOOL} ${Q}${FIPTOOL} create ${FIP_ARGS} $@ ${Q}${FIPTOOL} info $@ @${ECHO_BLANK_LINE} @echo "Built $@ successfully" @${ECHO_BLANK_LINE} ifneq (${GENERATE_COT},0) fwu_certificates: ${FWU_CRT_DEPS} ${CRTTOOL} ${Q}${CRTTOOL} ${FWU_CRT_ARGS} @${ECHO_BLANK_LINE} @echo "Built $@ successfully" @echo "FWU certificates can be found in ${BUILD_PLAT}" @${ECHO_BLANK_LINE} endif ${BUILD_PLAT}/${FWU_FIP_NAME}: ${FWU_FIP_DEPS} ${FIPTOOL} ${Q}${FIPTOOL} create ${FWU_FIP_ARGS} $@ ${Q}${FIPTOOL} info $@ @${ECHO_BLANK_LINE} @echo "Built $@ successfully" @${ECHO_BLANK_LINE} fiptool: ${FIPTOOL} fip: ${BUILD_PLAT}/${FIP_NAME} fwu_fip: ${BUILD_PLAT}/${FWU_FIP_NAME} .PHONY: ${FIPTOOL} ${FIPTOOL}: ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${FIPTOOLPATH} sptool: ${SPTOOL} .PHONY: ${SPTOOL} ${SPTOOL}: ${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${SPTOOLPATH} .PHONY: libraries romlib.bin: libraries ${Q}${MAKE} PLAT_DIR=${PLAT_DIR} BUILD_PLAT=${BUILD_PLAT} ENABLE_BTI=${ENABLE_BTI} ARM_ARCH_MINOR=${ARM_ARCH_MINOR} INCLUDES='${INCLUDES}' DEFINES='${DEFINES}' --no-print-directory -C ${ROMLIBPATH} all cscope: @echo " CSCOPE" ${Q}find ${CURDIR} -name "*.[chsS]" > cscope.files ${Q}cscope -b -q -k help: @echo "usage: ${MAKE} [PLAT=] [OPTIONS] [TARGET]" @echo "" @echo "PLAT is used to specify which platform you wish to build." @echo "If no platform is specified, PLAT defaults to: ${DEFAULT_PLAT}" @echo "" @echo "platform = ${PLATFORM_LIST}" @echo "" @echo "Please refer to the User Guide for a list of all supported options." @echo "Note that the build system doesn't track dependencies for build " @echo "options. Therefore, if any of the build options are changed " @echo "from a previous build, a clean build must be performed." @echo "" @echo "Supported Targets:" @echo " all Build all individual bootloader binaries" @echo " bl1 Build the BL1 binary" @echo " bl2 Build the BL2 binary" @echo " bl2u Build the BL2U binary" @echo " bl31 Build the BL31 binary" @echo " bl32 Build the BL32 binary. If ARCH=aarch32, then " @echo " this builds secure payload specified by AARCH32_SP" @echo " certificates Build the certificates (requires 'GENERATE_COT=1')" @echo " fip Build the Firmware Image Package (FIP)" @echo " fwu_fip Build the FWU Firmware Image Package (FIP)" @echo " checkcodebase Check the coding style of the entire source tree" @echo " checkpatch Check the coding style on changes in the current" @echo " branch against BASE_COMMIT (default origin/master)" @echo " clean Clean the build for the selected platform" @echo " cscope Generate cscope index" @echo " distclean Remove all build artifacts for all platforms" @echo " certtool Build the Certificate generation tool" @echo " fiptool Build the Firmware Image Package (FIP) creation tool" @echo " sptool Build the Secure Partition Package creation tool" @echo " dtbs Build the Device Tree Blobs (if required for the platform)" @echo "" @echo "Note: most build targets require PLAT to be set to a specific platform." @echo "" @echo "example: build all targets for the FVP platform:" @echo " CROSS_COMPILE=aarch64-none-elf- make PLAT=fvp all" trusted-firmware-a-2.2/bl1/000077500000000000000000000000001355360272700155675ustar00rootroot00000000000000trusted-firmware-a-2.2/bl1/aarch32/000077500000000000000000000000001355360272700170125ustar00rootroot00000000000000trusted-firmware-a-2.2/bl1/aarch32/bl1_arch_setup.c000066400000000000000000000006361355360272700220560ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "../bl1_private.h" /******************************************************************************* * TODO: Function that does the first bit of architectural setup. ******************************************************************************/ void bl1_arch_setup(void) { } trusted-firmware-a-2.2/bl1/aarch32/bl1_context_mgmt.c000066400000000000000000000122441355360272700224270ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "../bl1_private.h" /* * Following arrays will be used for context management. * There are 2 instances, for the Secure and Non-Secure contexts. */ static cpu_context_t bl1_cpu_context[2]; static smc_ctx_t bl1_smc_context[2]; /* Following contains the next cpu context pointer. */ static void *bl1_next_cpu_context_ptr; /* Following contains the next smc context pointer. */ static void *bl1_next_smc_context_ptr; /* Following functions are used for SMC context handling */ void *smc_get_ctx(unsigned int security_state) { assert(sec_state_is_valid(security_state)); return &bl1_smc_context[security_state]; } void smc_set_next_ctx(unsigned int security_state) { assert(sec_state_is_valid(security_state)); bl1_next_smc_context_ptr = &bl1_smc_context[security_state]; } void *smc_get_next_ctx(void) { return bl1_next_smc_context_ptr; } /* Following functions are used for CPU context handling */ void *cm_get_context(uint32_t security_state) { assert(sec_state_is_valid(security_state)); return &bl1_cpu_context[security_state]; } void cm_set_next_context(void *cpu_context) { assert(cpu_context); bl1_next_cpu_context_ptr = cpu_context; } void *cm_get_next_context(void) { return bl1_next_cpu_context_ptr; } /******************************************************************************* * Following function copies GP regs r0-r4, lr and spsr, * from the CPU context to the SMC context structures. ******************************************************************************/ static void copy_cpu_ctx_to_smc_ctx(const regs_t *cpu_reg_ctx, smc_ctx_t *next_smc_ctx) { next_smc_ctx->r0 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R0); next_smc_ctx->r1 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R1); next_smc_ctx->r2 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R2); next_smc_ctx->r3 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R3); next_smc_ctx->lr_mon = read_ctx_reg(cpu_reg_ctx, CTX_LR); next_smc_ctx->spsr_mon = read_ctx_reg(cpu_reg_ctx, CTX_SPSR); next_smc_ctx->scr = read_ctx_reg(cpu_reg_ctx, CTX_SCR); } /******************************************************************************* * Following function flushes the SMC & CPU context pointer and its data. ******************************************************************************/ static void flush_smc_and_cpu_ctx(void) { flush_dcache_range((uintptr_t)&bl1_next_smc_context_ptr, sizeof(bl1_next_smc_context_ptr)); flush_dcache_range((uintptr_t)bl1_next_smc_context_ptr, sizeof(smc_ctx_t)); flush_dcache_range((uintptr_t)&bl1_next_cpu_context_ptr, sizeof(bl1_next_cpu_context_ptr)); flush_dcache_range((uintptr_t)bl1_next_cpu_context_ptr, sizeof(cpu_context_t)); } /******************************************************************************* * This function prepares the context for Secure/Normal world images. * Normal world images are transitioned to HYP(if supported) else SVC. ******************************************************************************/ void bl1_prepare_next_image(unsigned int image_id) { unsigned int security_state, mode = MODE32_svc; image_desc_t *image_desc; entry_point_info_t *next_bl_ep; /* Get the image descriptor. */ image_desc = bl1_plat_get_image_desc(image_id); assert(image_desc); /* Get the entry point info. */ next_bl_ep = &image_desc->ep_info; /* Get the image security state. */ security_state = GET_SECURITY_STATE(next_bl_ep->h.attr); /* Prepare the SPSR for the next BL image. */ if ((security_state != SECURE) && (GET_VIRT_EXT(read_id_pfr1()))) { mode = MODE32_hyp; } next_bl_ep->spsr = SPSR_MODE32(mode, SPSR_T_ARM, SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS); /* Allow platform to make change */ bl1_plat_set_ep_info(image_id, next_bl_ep); /* Prepare the cpu context for the next BL image. */ cm_init_my_context(next_bl_ep); cm_prepare_el3_exit(security_state); cm_set_next_context(cm_get_context(security_state)); /* Prepare the smc context for the next BL image. */ smc_set_next_ctx(security_state); copy_cpu_ctx_to_smc_ctx(get_regs_ctx(cm_get_next_context()), smc_get_next_ctx()); /* * If the next image is non-secure, then we need to program the banked * non secure sctlr. This is not required when the next image is secure * because in AArch32, we expect the secure world to have the same * SCTLR settings. */ if (security_state == NON_SECURE) { cpu_context_t *ctx = cm_get_context(security_state); u_register_t ns_sctlr; /* Temporarily set the NS bit to access NS SCTLR */ write_scr(read_scr() | SCR_NS_BIT); isb(); ns_sctlr = read_ctx_reg(get_regs_ctx(ctx), CTX_NS_SCTLR); write_sctlr(ns_sctlr); isb(); write_scr(read_scr() & ~SCR_NS_BIT); isb(); } /* * Flush the SMC & CPU context and the (next)pointers, * to access them after caches are disabled. */ flush_smc_and_cpu_ctx(); /* Indicate that image is in execution state. */ image_desc->state = IMAGE_STATE_EXECUTED; print_entry_point_info(next_bl_ep); } trusted-firmware-a-2.2/bl1/aarch32/bl1_entrypoint.S000066400000000000000000000053341355360272700221140ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include .globl bl1_vector_table .globl bl1_entrypoint /* ----------------------------------------------------- * Setup the vector table to support SVC & MON mode. * ----------------------------------------------------- */ vector_base bl1_vector_table b bl1_entrypoint b report_exception /* Undef */ b bl1_aarch32_smc_handler /* SMC call */ b report_exception /* Prefetch abort */ b report_exception /* Data abort */ b report_exception /* Reserved */ b report_exception /* IRQ */ b report_exception /* FIQ */ /* ----------------------------------------------------- * bl1_entrypoint() is the entry point into the trusted * firmware code when a cpu is released from warm or * cold reset. * ----------------------------------------------------- */ func bl1_entrypoint /* --------------------------------------------------------------------- * If the reset address is programmable then bl1_entrypoint() is * executed only on the cold boot path. Therefore, we can skip the warm * boot mailbox mechanism. * --------------------------------------------------------------------- */ el3_entrypoint_common \ _init_sctlr=1 \ _warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \ _secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \ _init_memory=1 \ _init_c_runtime=1 \ _exception_vectors=bl1_vector_table /* ----------------------------------------------------- * Perform BL1 setup * ----------------------------------------------------- */ bl bl1_setup /* ----------------------------------------------------- * Jump to main function. * ----------------------------------------------------- */ bl bl1_main /* ----------------------------------------------------- * Jump to next image. * ----------------------------------------------------- */ /* * Get the smc_context for next BL image, * program the gp/system registers and save it in `r4`. */ bl smc_get_next_ctx mov r4, r0 /* Only turn-off MMU if going to secure world */ ldr r5, [r4, #SMC_CTX_SCR] tst r5, #SCR_NS_BIT bne skip_mmu_off /* * MMU needs to be disabled because both BL1 and BL2/BL2U execute * in PL1, and therefore share the same address space. * BL2/BL2U will initialize the address space according to its * own requirement. */ bl disable_mmu_icache_secure stcopr r0, TLBIALL dsb sy isb skip_mmu_off: /* Restore smc_context from `r4` and exit secure monitor mode. */ mov r0, r4 monitor_exit endfunc bl1_entrypoint trusted-firmware-a-2.2/bl1/aarch32/bl1_exceptions.S000066400000000000000000000073261355360272700220650ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include .globl bl1_aarch32_smc_handler func bl1_aarch32_smc_handler /* On SMC entry, `sp` points to `smc_ctx_t`. Save `lr`. */ str lr, [sp, #SMC_CTX_LR_MON] /* ------------------------------------------------ * SMC in BL1 is handled assuming that the MMU is * turned off by BL2. * ------------------------------------------------ */ /* ---------------------------------------------- * Detect if this is a RUN_IMAGE or other SMC. * ---------------------------------------------- */ mov lr, #BL1_SMC_RUN_IMAGE cmp lr, r0 bne smc_handler /* ------------------------------------------------ * Make sure only Secure world reaches here. * ------------------------------------------------ */ ldcopr r8, SCR tst r8, #SCR_NS_BIT blne report_exception /* --------------------------------------------------------------------- * Pass control to next secure image. * Here it expects r1 to contain the address of a entry_point_info_t * structure describing the BL entrypoint. * --------------------------------------------------------------------- */ mov r8, r1 mov r0, r1 bl bl1_print_next_bl_ep_info #if SPIN_ON_BL1_EXIT bl print_debug_loop_message debug_loop: b debug_loop #endif mov r0, r8 bl bl1_plat_prepare_exit stcopr r0, TLBIALL dsb sy isb /* * Extract PC and SPSR based on struct `entry_point_info_t` * and load it in LR and SPSR registers respectively. */ ldr lr, [r8, #ENTRY_POINT_INFO_PC_OFFSET] ldr r1, [r8, #(ENTRY_POINT_INFO_PC_OFFSET + 4)] msr spsr_xc, r1 /* Some BL32 stages expect lr_svc to provide the BL33 entry address */ cps #MODE32_svc ldr lr, [r8, #ENTRY_POINT_INFO_LR_SVC_OFFSET] cps #MODE32_mon add r8, r8, #ENTRY_POINT_INFO_ARGS_OFFSET ldm r8, {r0, r1, r2, r3} eret endfunc bl1_aarch32_smc_handler /* ----------------------------------------------------- * Save Secure/Normal world context and jump to * BL1 SMC handler. * ----------------------------------------------------- */ func smc_handler /* ----------------------------------------------------- * Save the GP registers. * ----------------------------------------------------- */ smccc_save_gp_mode_regs /* * `sp` still points to `smc_ctx_t`. Save it to a register * and restore the C runtime stack pointer to `sp`. */ mov r6, sp ldr sp, [r6, #SMC_CTX_SP_MON] ldr r0, [r6, #SMC_CTX_SCR] and r7, r0, #SCR_NS_BIT /* flags */ /* Switch to Secure Mode */ bic r0, #SCR_NS_BIT stcopr r0, SCR isb /* If caller is from Secure world then turn on the MMU */ tst r7, #SCR_NS_BIT bne skip_mmu_on /* Turn on the MMU */ mov r0, #DISABLE_DCACHE bl enable_mmu_svc_mon /* Enable the data cache. */ ldcopr r9, SCTLR orr r9, r9, #SCTLR_C_BIT stcopr r9, SCTLR isb skip_mmu_on: /* Prepare arguments for BL1 SMC wrapper. */ ldr r0, [r6, #SMC_CTX_GPREG_R0] /* smc_fid */ mov r1, #0 /* cookie */ mov r2, r6 /* handle */ mov r3, r7 /* flags */ bl bl1_smc_wrapper /* Get the smc_context for next BL image */ bl smc_get_next_ctx mov r4, r0 /* Only turn-off MMU if going to secure world */ ldr r5, [r4, #SMC_CTX_SCR] tst r5, #SCR_NS_BIT bne skip_mmu_off /* Disable the MMU */ bl disable_mmu_icache_secure stcopr r0, TLBIALL dsb sy isb skip_mmu_off: /* ----------------------------------------------------- * Do the transition to next BL image. * ----------------------------------------------------- */ mov r0, r4 monitor_exit endfunc smc_handler trusted-firmware-a-2.2/bl1/aarch64/000077500000000000000000000000001355360272700170175ustar00rootroot00000000000000trusted-firmware-a-2.2/bl1/aarch64/bl1_arch_setup.c000066400000000000000000000020521355360272700220550ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "../bl1_private.h" /******************************************************************************* * Function that does the first bit of architectural setup that affects * execution in the non-secure address space. ******************************************************************************/ void bl1_arch_setup(void) { /* Set the next EL to be AArch64 */ write_scr_el3(read_scr_el3() | SCR_RW_BIT); } /******************************************************************************* * Set the Secure EL1 required architectural state ******************************************************************************/ void bl1_arch_next_el_setup(void) { u_register_t next_sctlr; /* Use the same endianness than the current BL */ next_sctlr = (read_sctlr_el3() & SCTLR_EE_BIT); /* Set SCTLR Secure EL1 */ next_sctlr |= SCTLR_EL1_RES1; write_sctlr_el1(next_sctlr); } trusted-firmware-a-2.2/bl1/aarch64/bl1_context_mgmt.c000066400000000000000000000051671355360272700224420ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "../bl1_private.h" /* * Following array will be used for context management. * There are 2 instances, for the Secure and Non-Secure contexts. */ static cpu_context_t bl1_cpu_context[2]; /* Following contains the cpu context pointers. */ static void *bl1_cpu_context_ptr[2]; void *cm_get_context(uint32_t security_state) { assert(sec_state_is_valid(security_state)); return bl1_cpu_context_ptr[security_state]; } void cm_set_context(void *context, uint32_t security_state) { assert(sec_state_is_valid(security_state)); bl1_cpu_context_ptr[security_state] = context; } /******************************************************************************* * This function prepares the context for Secure/Normal world images. * Normal world images are transitioned to EL2(if supported) else EL1. ******************************************************************************/ void bl1_prepare_next_image(unsigned int image_id) { unsigned int security_state, mode = MODE_EL1; image_desc_t *image_desc; entry_point_info_t *next_bl_ep; #if CTX_INCLUDE_AARCH32_REGS /* * Ensure that the build flag to save AArch32 system registers in CPU * context is not set for AArch64-only platforms. */ if (el_implemented(1) == EL_IMPL_A64ONLY) { ERROR("EL1 supports AArch64-only. Please set build flag " "CTX_INCLUDE_AARCH32_REGS = 0\n"); panic(); } #endif /* Get the image descriptor. */ image_desc = bl1_plat_get_image_desc(image_id); assert(image_desc); /* Get the entry point info. */ next_bl_ep = &image_desc->ep_info; /* Get the image security state. */ security_state = GET_SECURITY_STATE(next_bl_ep->h.attr); /* Setup the Secure/Non-Secure context if not done already. */ if (!cm_get_context(security_state)) cm_set_context(&bl1_cpu_context[security_state], security_state); /* Prepare the SPSR for the next BL image. */ if ((security_state != SECURE) && (el_implemented(2) != EL_IMPL_NONE)) { mode = MODE_EL2; } next_bl_ep->spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); /* Allow platform to make change */ bl1_plat_set_ep_info(image_id, next_bl_ep); /* Prepare the context for the next BL image. */ cm_init_my_context(next_bl_ep); cm_prepare_el3_exit(security_state); /* Indicate that image is in execution state. */ image_desc->state = IMAGE_STATE_EXECUTED; print_entry_point_info(next_bl_ep); } trusted-firmware-a-2.2/bl1/aarch64/bl1_entrypoint.S000066400000000000000000000042571355360272700221240ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .globl bl1_entrypoint /* ----------------------------------------------------- * bl1_entrypoint() is the entry point into the trusted * firmware code when a cpu is released from warm or * cold reset. * ----------------------------------------------------- */ func bl1_entrypoint /* --------------------------------------------------------------------- * If the reset address is programmable then bl1_entrypoint() is * executed only on the cold boot path. Therefore, we can skip the warm * boot mailbox mechanism. * --------------------------------------------------------------------- */ el3_entrypoint_common \ _init_sctlr=1 \ _warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \ _secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \ _init_memory=1 \ _init_c_runtime=1 \ _exception_vectors=bl1_exceptions /* -------------------------------------------------------------------- * Perform BL1 setup * -------------------------------------------------------------------- */ bl bl1_setup #if ENABLE_PAUTH /* -------------------------------------------------------------------- * Program APIAKey_EL1 and enable pointer authentication. * -------------------------------------------------------------------- */ bl pauth_init_enable_el3 #endif /* ENABLE_PAUTH */ /* -------------------------------------------------------------------- * Initialize platform and jump to our c-entry point * for this type of reset. * -------------------------------------------------------------------- */ bl bl1_main #if ENABLE_PAUTH /* -------------------------------------------------------------------- * Disable pointer authentication before jumping to next boot image. * -------------------------------------------------------------------- */ bl pauth_disable_el3 #endif /* ENABLE_PAUTH */ /* -------------------------------------------------- * Do the transition to next boot image. * -------------------------------------------------- */ b el3_exit endfunc bl1_entrypoint trusted-firmware-a-2.2/bl1/aarch64/bl1_exceptions.S000066400000000000000000000176471355360272700221010ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* ----------------------------------------------------------------------------- * Very simple stackless exception handlers used by BL1. * ----------------------------------------------------------------------------- */ .globl bl1_exceptions vector_base bl1_exceptions /* ----------------------------------------------------- * Current EL with SP0 : 0x0 - 0x200 * ----------------------------------------------------- */ vector_entry SynchronousExceptionSP0 mov x0, #SYNC_EXCEPTION_SP_EL0 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SynchronousExceptionSP0 vector_entry IrqSP0 mov x0, #IRQ_SP_EL0 bl plat_report_exception no_ret plat_panic_handler end_vector_entry IrqSP0 vector_entry FiqSP0 mov x0, #FIQ_SP_EL0 bl plat_report_exception no_ret plat_panic_handler end_vector_entry FiqSP0 vector_entry SErrorSP0 mov x0, #SERROR_SP_EL0 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SErrorSP0 /* ----------------------------------------------------- * Current EL with SPx: 0x200 - 0x400 * ----------------------------------------------------- */ vector_entry SynchronousExceptionSPx mov x0, #SYNC_EXCEPTION_SP_ELX bl plat_report_exception no_ret plat_panic_handler end_vector_entry SynchronousExceptionSPx vector_entry IrqSPx mov x0, #IRQ_SP_ELX bl plat_report_exception no_ret plat_panic_handler end_vector_entry IrqSPx vector_entry FiqSPx mov x0, #FIQ_SP_ELX bl plat_report_exception no_ret plat_panic_handler end_vector_entry FiqSPx vector_entry SErrorSPx mov x0, #SERROR_SP_ELX bl plat_report_exception no_ret plat_panic_handler end_vector_entry SErrorSPx /* ----------------------------------------------------- * Lower EL using AArch64 : 0x400 - 0x600 * ----------------------------------------------------- */ vector_entry SynchronousExceptionA64 /* Enable the SError interrupt */ msr daifclr, #DAIF_ABT_BIT str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] /* Expect only SMC exceptions */ mrs x30, esr_el3 ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH cmp x30, #EC_AARCH64_SMC b.ne unexpected_sync_exception b smc_handler64 end_vector_entry SynchronousExceptionA64 vector_entry IrqA64 mov x0, #IRQ_AARCH64 bl plat_report_exception no_ret plat_panic_handler end_vector_entry IrqA64 vector_entry FiqA64 mov x0, #FIQ_AARCH64 bl plat_report_exception no_ret plat_panic_handler end_vector_entry FiqA64 vector_entry SErrorA64 mov x0, #SERROR_AARCH64 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SErrorA64 /* ----------------------------------------------------- * Lower EL using AArch32 : 0x600 - 0x800 * ----------------------------------------------------- */ vector_entry SynchronousExceptionA32 mov x0, #SYNC_EXCEPTION_AARCH32 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SynchronousExceptionA32 vector_entry IrqA32 mov x0, #IRQ_AARCH32 bl plat_report_exception no_ret plat_panic_handler end_vector_entry IrqA32 vector_entry FiqA32 mov x0, #FIQ_AARCH32 bl plat_report_exception no_ret plat_panic_handler end_vector_entry FiqA32 vector_entry SErrorA32 mov x0, #SERROR_AARCH32 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SErrorA32 func smc_handler64 /* ---------------------------------------------- * Detect if this is a RUN_IMAGE or other SMC. * ---------------------------------------------- */ mov x30, #BL1_SMC_RUN_IMAGE cmp x30, x0 b.ne smc_handler /* ------------------------------------------------ * Make sure only Secure world reaches here. * ------------------------------------------------ */ mrs x30, scr_el3 tst x30, #SCR_NS_BIT b.ne unexpected_sync_exception /* ---------------------------------------------- * Handling RUN_IMAGE SMC. First switch back to * SP_EL0 for the C runtime stack. * ---------------------------------------------- */ ldr x30, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP] msr spsel, #MODE_SP_EL0 mov sp, x30 /* --------------------------------------------------------------------- * Pass EL3 control to next BL image. * Here it expects X1 with the address of a entry_point_info_t * structure describing the next BL image entrypoint. * --------------------------------------------------------------------- */ mov x20, x1 mov x0, x20 bl bl1_print_next_bl_ep_info ldp x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET] msr elr_el3, x0 msr spsr_el3, x1 ubfx x0, x1, #MODE_EL_SHIFT, #2 cmp x0, #MODE_EL3 b.ne unexpected_sync_exception bl disable_mmu_icache_el3 tlbi alle3 dsb ish /* ERET implies ISB, so it is not needed here */ #if SPIN_ON_BL1_EXIT bl print_debug_loop_message debug_loop: b debug_loop #endif mov x0, x20 bl bl1_plat_prepare_exit ldp x6, x7, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x30)] ldp x4, x5, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x20)] ldp x2, x3, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x10)] ldp x0, x1, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x0)] eret endfunc smc_handler64 unexpected_sync_exception: mov x0, #SYNC_EXCEPTION_AARCH64 bl plat_report_exception no_ret plat_panic_handler /* ----------------------------------------------------- * Save Secure/Normal world context and jump to * BL1 SMC handler. * ----------------------------------------------------- */ smc_handler: /* ----------------------------------------------------- * Save x0-x29 and ARMv8.3-PAuth (if enabled) registers. * If Secure Cycle Counter is not disabled in MDCR_EL3 * when ARMv8.5-PMU is implemented, save PMCR_EL0 and * disable Cycle Counter. * TODO: Revisit to store only SMCCC specified registers. * ----------------------------------------------------- */ bl save_gp_pmcr_pauth_regs #if ENABLE_PAUTH /* ----------------------------------------------------- * Load and program stored APIAKey firmware key. * Re-enable pointer authentication in EL3, as it was * disabled before jumping to the next boot image. * ----------------------------------------------------- */ bl pauth_load_bl1_apiakey_enable #endif /* ----------------------------------------------------- * Populate the parameters for the SMC handler. We * already have x0-x4 in place. x5 will point to a * cookie (not used now). x6 will point to the context * structure (SP_EL3) and x7 will contain flags we need * to pass to the handler. * ----------------------------------------------------- */ mov x5, xzr mov x6, sp /* ----------------------------------------------------- * Restore the saved C runtime stack value which will * become the new SP_EL0 i.e. EL3 runtime stack. It was * saved in the 'cpu_context' structure prior to the last * ERET from EL3. * ----------------------------------------------------- */ ldr x12, [x6, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP] /* --------------------------------------------- * Switch back to SP_EL0 for the C runtime stack. * --------------------------------------------- */ msr spsel, #MODE_SP_EL0 mov sp, x12 /* ----------------------------------------------------- * Save the SPSR_EL3, ELR_EL3, & SCR_EL3 in case there * is a world switch during SMC handling. * ----------------------------------------------------- */ mrs x16, spsr_el3 mrs x17, elr_el3 mrs x18, scr_el3 stp x16, x17, [x6, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3] str x18, [x6, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3] /* Copy SCR_EL3.NS bit to the flag to indicate caller's security */ bfi x7, x18, #0, #1 /* ----------------------------------------------------- * Go to BL1 SMC handler. * ----------------------------------------------------- */ bl bl1_smc_handler /* ----------------------------------------------------- * Do the transition to next BL image. * ----------------------------------------------------- */ b el3_exit trusted-firmware-a-2.2/bl1/bl1.ld.S000066400000000000000000000127141355360272700167740ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT) OUTPUT_ARCH(PLATFORM_LINKER_ARCH) ENTRY(bl1_entrypoint) MEMORY { ROM (rx): ORIGIN = BL1_RO_BASE, LENGTH = BL1_RO_LIMIT - BL1_RO_BASE RAM (rwx): ORIGIN = BL1_RW_BASE, LENGTH = BL1_RW_LIMIT - BL1_RW_BASE } SECTIONS { . = BL1_RO_BASE; ASSERT(. == ALIGN(PAGE_SIZE), "BL1_RO_BASE address is not aligned on a page boundary.") #if SEPARATE_CODE_AND_RODATA .text . : { __TEXT_START__ = .; *bl1_entrypoint.o(.text*) *(.text*) *(.vectors) . = ALIGN(PAGE_SIZE); __TEXT_END__ = .; } >ROM /* .ARM.extab and .ARM.exidx are only added because Clang need them */ .ARM.extab . : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >ROM .ARM.exidx . : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >ROM .rodata . : { __RODATA_START__ = .; *(.rodata*) /* Ensure 8-byte alignment for descriptors and ensure inclusion */ . = ALIGN(8); __PARSER_LIB_DESCS_START__ = .; KEEP(*(.img_parser_lib_descs)) __PARSER_LIB_DESCS_END__ = .; /* * Ensure 8-byte alignment for cpu_ops so that its fields are also * aligned. Also ensure cpu_ops inclusion. */ . = ALIGN(8); __CPU_OPS_START__ = .; KEEP(*(cpu_ops)) __CPU_OPS_END__ = .; /* * No need to pad out the .rodata section to a page boundary. Next is * the .data section, which can mapped in ROM with the same memory * attributes as the .rodata section. */ __RODATA_END__ = .; } >ROM #else ro . : { __RO_START__ = .; *bl1_entrypoint.o(.text*) *(.text*) *(.rodata*) /* Ensure 8-byte alignment for descriptors and ensure inclusion */ . = ALIGN(8); __PARSER_LIB_DESCS_START__ = .; KEEP(*(.img_parser_lib_descs)) __PARSER_LIB_DESCS_END__ = .; /* * Ensure 8-byte alignment for cpu_ops so that its fields are also * aligned. Also ensure cpu_ops inclusion. */ . = ALIGN(8); __CPU_OPS_START__ = .; KEEP(*(cpu_ops)) __CPU_OPS_END__ = .; *(.vectors) __RO_END__ = .; } >ROM #endif ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__, "cpu_ops not defined for this platform.") . = BL1_RW_BASE; ASSERT(BL1_RW_BASE == ALIGN(PAGE_SIZE), "BL1_RW_BASE address is not aligned on a page boundary.") /* * The .data section gets copied from ROM to RAM at runtime. * Its LMA should be 16-byte aligned to allow efficient copying of 16-bytes * aligned regions in it. * Its VMA must be page-aligned as it marks the first read/write page. * * It must be placed at a lower address than the stacks if the stack * protector is enabled. Alternatively, the .data.stack_protector_canary * section can be placed independently of the main .data section. */ .data . : ALIGN(16) { __DATA_RAM_START__ = .; *(.data*) __DATA_RAM_END__ = .; } >RAM AT>ROM stacks . (NOLOAD) : { __STACKS_START__ = .; *(tzfw_normal_stacks) __STACKS_END__ = .; } >RAM /* * The .bss section gets initialised to 0 at runtime. * Its base address should be 16-byte aligned for better performance of the * zero-initialization code. */ .bss : ALIGN(16) { __BSS_START__ = .; *(.bss*) *(COMMON) __BSS_END__ = .; } >RAM /* * The xlat_table section is for full, aligned page tables (4K). * Removing them from .bss avoids forcing 4K alignment on * the .bss section. The tables are initialized to zero by the translation * tables library. */ xlat_table (NOLOAD) : { *(xlat_table) } >RAM #if USE_COHERENT_MEM /* * The base address of the coherent memory section must be page-aligned (4K) * to guarantee that the coherent data are stored on their own pages and * are not mixed with normal data. This is required to set up the correct * memory attributes for the coherent data page tables. */ coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) { __COHERENT_RAM_START__ = .; *(tzfw_coherent_mem) __COHERENT_RAM_END_UNALIGNED__ = .; /* * Memory page(s) mapped to this section will be marked * as device memory. No other unexpected data must creep in. * Ensure the rest of the current memory page is unused. */ . = ALIGN(PAGE_SIZE); __COHERENT_RAM_END__ = .; } >RAM #endif __BL1_RAM_START__ = ADDR(.data); __BL1_RAM_END__ = .; __DATA_ROM_START__ = LOADADDR(.data); __DATA_SIZE__ = SIZEOF(.data); /* * The .data section is the last PROGBITS section so its end marks the end * of BL1's actual content in Trusted ROM. */ __BL1_ROM_END__ = __DATA_ROM_START__ + __DATA_SIZE__; ASSERT(__BL1_ROM_END__ <= BL1_RO_LIMIT, "BL1's ROM content has exceeded its limit.") __BSS_SIZE__ = SIZEOF(.bss); #if USE_COHERENT_MEM __COHERENT_RAM_UNALIGNED_SIZE__ = __COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__; #endif ASSERT(. <= BL1_RW_LIMIT, "BL1's RW section has exceeded its limit.") } trusted-firmware-a-2.2/bl1/bl1.mk000066400000000000000000000013531355360272700166000ustar00rootroot00000000000000# # Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # BL1_SOURCES += bl1/bl1_main.c \ bl1/${ARCH}/bl1_arch_setup.c \ bl1/${ARCH}/bl1_context_mgmt.c \ bl1/${ARCH}/bl1_entrypoint.S \ bl1/${ARCH}/bl1_exceptions.S \ lib/cpus/${ARCH}/cpu_helpers.S \ lib/cpus/errata_report.c \ lib/el3_runtime/${ARCH}/context_mgmt.c \ plat/common/plat_bl1_common.c \ plat/common/${ARCH}/platform_up_stack.S \ ${MBEDTLS_SOURCES} ifeq (${ARCH},aarch64) BL1_SOURCES += lib/cpus/aarch64/dsu_helpers.S \ lib/el3_runtime/aarch64/context.S endif ifeq (${TRUSTED_BOARD_BOOT},1) BL1_SOURCES += bl1/bl1_fwu.c endif BL1_LINKERFILE := bl1/bl1.ld.S trusted-firmware-a-2.2/bl1/bl1_fwu.c000066400000000000000000000516441355360272700173040ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bl1_private.h" /* * Function declarations. */ static int bl1_fwu_image_copy(unsigned int image_id, uintptr_t image_src, unsigned int block_size, unsigned int image_size, unsigned int flags); static int bl1_fwu_image_auth(unsigned int image_id, uintptr_t image_src, unsigned int image_size, unsigned int flags); static int bl1_fwu_image_execute(unsigned int image_id, void **handle, unsigned int flags); static register_t bl1_fwu_image_resume(register_t image_param, void **handle, unsigned int flags); static int bl1_fwu_sec_image_done(void **handle, unsigned int flags); static int bl1_fwu_image_reset(unsigned int image_id, unsigned int flags); __dead2 static void bl1_fwu_done(void *client_cookie, void *reserved); /* * This keeps track of last executed secure image id. */ static unsigned int sec_exec_image_id = INVALID_IMAGE_ID; /******************************************************************************* * Top level handler for servicing FWU SMCs. ******************************************************************************/ register_t bl1_fwu_smc_handler(unsigned int smc_fid, register_t x1, register_t x2, register_t x3, register_t x4, void *cookie, void *handle, unsigned int flags) { switch (smc_fid) { case FWU_SMC_IMAGE_COPY: SMC_RET1(handle, bl1_fwu_image_copy(x1, x2, x3, x4, flags)); case FWU_SMC_IMAGE_AUTH: SMC_RET1(handle, bl1_fwu_image_auth(x1, x2, x3, flags)); case FWU_SMC_IMAGE_EXECUTE: SMC_RET1(handle, bl1_fwu_image_execute(x1, &handle, flags)); case FWU_SMC_IMAGE_RESUME: SMC_RET1(handle, bl1_fwu_image_resume(x1, &handle, flags)); case FWU_SMC_SEC_IMAGE_DONE: SMC_RET1(handle, bl1_fwu_sec_image_done(&handle, flags)); case FWU_SMC_IMAGE_RESET: SMC_RET1(handle, bl1_fwu_image_reset(x1, flags)); case FWU_SMC_UPDATE_DONE: bl1_fwu_done((void *)x1, NULL); default: assert(0); /* Unreachable */ break; } SMC_RET1(handle, SMC_UNK); } /******************************************************************************* * Utility functions to keep track of the images that are loaded at any time. ******************************************************************************/ #ifdef PLAT_FWU_MAX_SIMULTANEOUS_IMAGES #define FWU_MAX_SIMULTANEOUS_IMAGES PLAT_FWU_MAX_SIMULTANEOUS_IMAGES #else #define FWU_MAX_SIMULTANEOUS_IMAGES 10 #endif static unsigned int bl1_fwu_loaded_ids[FWU_MAX_SIMULTANEOUS_IMAGES] = { [0 ... FWU_MAX_SIMULTANEOUS_IMAGES-1] = INVALID_IMAGE_ID }; /* * Adds an image_id to the bl1_fwu_loaded_ids array. * Returns 0 on success, 1 on error. */ static int bl1_fwu_add_loaded_id(unsigned int image_id) { int i; /* Check if the ID is already in the list */ for (i = 0; i < FWU_MAX_SIMULTANEOUS_IMAGES; i++) { if (bl1_fwu_loaded_ids[i] == image_id) return 0; } /* Find an empty slot */ for (i = 0; i < FWU_MAX_SIMULTANEOUS_IMAGES; i++) { if (bl1_fwu_loaded_ids[i] == INVALID_IMAGE_ID) { bl1_fwu_loaded_ids[i] = image_id; return 0; } } return 1; } /* * Removes an image_id from the bl1_fwu_loaded_ids array. * Returns 0 on success, 1 on error. */ static int bl1_fwu_remove_loaded_id(unsigned int image_id) { int i; /* Find the ID */ for (i = 0; i < FWU_MAX_SIMULTANEOUS_IMAGES; i++) { if (bl1_fwu_loaded_ids[i] == image_id) { bl1_fwu_loaded_ids[i] = INVALID_IMAGE_ID; return 0; } } return 1; } /******************************************************************************* * This function checks if the specified image overlaps another image already * loaded. It returns 0 if there is no overlap, a negative error code otherwise. ******************************************************************************/ static int bl1_fwu_image_check_overlaps(unsigned int image_id) { const image_desc_t *image_desc, *checked_image_desc; const image_info_t *info, *checked_info; uintptr_t image_base, image_end; uintptr_t checked_image_base, checked_image_end; checked_image_desc = bl1_plat_get_image_desc(image_id); checked_info = &checked_image_desc->image_info; /* Image being checked mustn't be empty. */ assert(checked_info->image_size != 0); checked_image_base = checked_info->image_base; checked_image_end = checked_image_base + checked_info->image_size - 1; /* No need to check for overflows, it's done in bl1_fwu_image_copy(). */ for (int i = 0; i < FWU_MAX_SIMULTANEOUS_IMAGES; i++) { /* Skip INVALID_IMAGE_IDs and don't check image against itself */ if ((bl1_fwu_loaded_ids[i] == INVALID_IMAGE_ID) || (bl1_fwu_loaded_ids[i] == image_id)) continue; image_desc = bl1_plat_get_image_desc(bl1_fwu_loaded_ids[i]); /* Only check images that are loaded or being loaded. */ assert (image_desc && image_desc->state != IMAGE_STATE_RESET); info = &image_desc->image_info; /* There cannot be overlaps with an empty image. */ if (info->image_size == 0) continue; image_base = info->image_base; image_end = image_base + info->image_size - 1; /* * Overflows cannot happen. It is checked in * bl1_fwu_image_copy() when the image goes from RESET to * COPYING or COPIED. */ assert (image_end > image_base); /* Check if there are overlaps. */ if (!(image_end < checked_image_base || checked_image_end < image_base)) { VERBOSE("Image with ID %d overlaps existing image with ID %d", checked_image_desc->image_id, image_desc->image_id); return -EPERM; } } return 0; } /******************************************************************************* * This function is responsible for copying secure images in AP Secure RAM. ******************************************************************************/ static int bl1_fwu_image_copy(unsigned int image_id, uintptr_t image_src, unsigned int block_size, unsigned int image_size, unsigned int flags) { uintptr_t dest_addr; unsigned int remaining; /* Get the image descriptor. */ image_desc_t *image_desc = bl1_plat_get_image_desc(image_id); if (!image_desc) { WARN("BL1-FWU: Invalid image ID %u\n", image_id); return -EPERM; } /* * The request must originate from a non-secure caller and target a * secure image. Any other scenario is invalid. */ if (GET_SECURITY_STATE(flags) == SECURE) { WARN("BL1-FWU: Copy not allowed from secure world.\n"); return -EPERM; } if (GET_SECURITY_STATE(image_desc->ep_info.h.attr) == NON_SECURE) { WARN("BL1-FWU: Copy not allowed for non-secure images.\n"); return -EPERM; } /* Check whether the FWU state machine is in the correct state. */ if ((image_desc->state != IMAGE_STATE_RESET) && (image_desc->state != IMAGE_STATE_COPYING)) { WARN("BL1-FWU: Copy not allowed at this point of the FWU" " process.\n"); return -EPERM; } if ((!image_src) || (!block_size) || check_uptr_overflow(image_src, block_size - 1)) { WARN("BL1-FWU: Copy not allowed due to invalid image source" " or block size\n"); return -ENOMEM; } if (image_desc->state == IMAGE_STATE_COPYING) { /* * There must have been at least 1 copy operation for this image * previously. */ assert(image_desc->copied_size != 0); /* * The image size must have been recorded in the 1st copy * operation. */ image_size = image_desc->image_info.image_size; assert(image_size != 0); assert(image_desc->copied_size < image_size); INFO("BL1-FWU: Continuing image copy in blocks\n"); } else { /* image_desc->state == IMAGE_STATE_RESET */ INFO("BL1-FWU: Initial call to copy an image\n"); /* * image_size is relevant only for the 1st copy request, it is * then ignored for subsequent calls for this image. */ if (!image_size) { WARN("BL1-FWU: Copy not allowed due to invalid image" " size\n"); return -ENOMEM; } /* Check that the image size to load is within limit */ if (image_size > image_desc->image_info.image_max_size) { WARN("BL1-FWU: Image size out of bounds\n"); return -ENOMEM; } /* Save the given image size. */ image_desc->image_info.image_size = image_size; /* Make sure the image doesn't overlap other images. */ if (bl1_fwu_image_check_overlaps(image_id)) { image_desc->image_info.image_size = 0; WARN("BL1-FWU: This image overlaps another one\n"); return -EPERM; } /* * copied_size must be explicitly initialized here because the * FWU code doesn't necessarily do it when it resets the state * machine. */ image_desc->copied_size = 0; } /* * If the given block size is more than the total image size * then clip the former to the latter. */ remaining = image_size - image_desc->copied_size; if (block_size > remaining) { WARN("BL1-FWU: Block size is too big, clipping it.\n"); block_size = remaining; } /* Make sure the source image is mapped in memory. */ if (bl1_plat_mem_check(image_src, block_size, flags)) { WARN("BL1-FWU: Source image is not mapped.\n"); return -ENOMEM; } if (bl1_fwu_add_loaded_id(image_id)) { WARN("BL1-FWU: Too many images loaded at the same time.\n"); return -ENOMEM; } /* Allow the platform to handle pre-image load before copying */ if (image_desc->state == IMAGE_STATE_RESET) { if (bl1_plat_handle_pre_image_load(image_id) != 0) { ERROR("BL1-FWU: Failure in pre-image load of image id %d\n", image_id); return -EPERM; } } /* Everything looks sane. Go ahead and copy the block of data. */ dest_addr = image_desc->image_info.image_base + image_desc->copied_size; memcpy((void *) dest_addr, (const void *) image_src, block_size); flush_dcache_range(dest_addr, block_size); image_desc->copied_size += block_size; image_desc->state = (block_size == remaining) ? IMAGE_STATE_COPIED : IMAGE_STATE_COPYING; INFO("BL1-FWU: Copy operation successful.\n"); return 0; } /******************************************************************************* * This function is responsible for authenticating Normal/Secure images. ******************************************************************************/ static int bl1_fwu_image_auth(unsigned int image_id, uintptr_t image_src, unsigned int image_size, unsigned int flags) { int result; uintptr_t base_addr; unsigned int total_size; /* Get the image descriptor. */ image_desc_t *image_desc = bl1_plat_get_image_desc(image_id); if (!image_desc) return -EPERM; if (GET_SECURITY_STATE(flags) == SECURE) { if (image_desc->state != IMAGE_STATE_RESET) { WARN("BL1-FWU: Authentication from secure world " "while in invalid state\n"); return -EPERM; } } else { if (GET_SECURITY_STATE(image_desc->ep_info.h.attr) == SECURE) { if (image_desc->state != IMAGE_STATE_COPIED) { WARN("BL1-FWU: Authentication of secure image " "from non-secure world while not in copied state\n"); return -EPERM; } } else { if (image_desc->state != IMAGE_STATE_RESET) { WARN("BL1-FWU: Authentication of non-secure image " "from non-secure world while in invalid state\n"); return -EPERM; } } } if (image_desc->state == IMAGE_STATE_COPIED) { /* * Image is in COPIED state. * Use the stored address and size. */ base_addr = image_desc->image_info.image_base; total_size = image_desc->image_info.image_size; } else { if ((!image_src) || (!image_size) || check_uptr_overflow(image_src, image_size - 1)) { WARN("BL1-FWU: Auth not allowed due to invalid" " image source/size\n"); return -ENOMEM; } /* * Image is in RESET state. * Check the parameters and authenticate the source image in place. */ if (bl1_plat_mem_check(image_src, image_size, \ image_desc->ep_info.h.attr)) { WARN("BL1-FWU: Authentication arguments source/size not mapped\n"); return -ENOMEM; } if (bl1_fwu_add_loaded_id(image_id)) { WARN("BL1-FWU: Too many images loaded at the same time.\n"); return -ENOMEM; } base_addr = image_src; total_size = image_size; /* Update the image size in the descriptor. */ image_desc->image_info.image_size = total_size; } /* * Authenticate the image. */ INFO("BL1-FWU: Authenticating image_id:%d\n", image_id); result = auth_mod_verify_img(image_id, (void *)base_addr, total_size); if (result != 0) { WARN("BL1-FWU: Authentication Failed err=%d\n", result); /* * Authentication has failed. * Clear the memory if the image was copied. * This is to prevent an attack where this contains * some malicious code that can somehow be executed later. */ if (image_desc->state == IMAGE_STATE_COPIED) { /* Clear the memory.*/ zero_normalmem((void *)base_addr, total_size); flush_dcache_range(base_addr, total_size); /* Indicate that image can be copied again*/ image_desc->state = IMAGE_STATE_RESET; } /* * Even if this fails it's ok because the ID isn't in the array. * The image cannot be in RESET state here, it is checked at the * beginning of the function. */ bl1_fwu_remove_loaded_id(image_id); return -EAUTH; } /* Indicate that image is in authenticated state. */ image_desc->state = IMAGE_STATE_AUTHENTICATED; /* Allow the platform to handle post-image load */ result = bl1_plat_handle_post_image_load(image_id); if (result != 0) { ERROR("BL1-FWU: Failure %d in post-image load of image id %d\n", result, image_id); /* * Panic here as the platform handling of post-image load is * not correct. */ plat_error_handler(result); } /* * Flush image_info to memory so that other * secure world images can see changes. */ flush_dcache_range((uintptr_t)&image_desc->image_info, sizeof(image_info_t)); INFO("BL1-FWU: Authentication was successful\n"); return 0; } /******************************************************************************* * This function is responsible for executing Secure images. ******************************************************************************/ static int bl1_fwu_image_execute(unsigned int image_id, void **handle, unsigned int flags) { /* Get the image descriptor. */ image_desc_t *image_desc = bl1_plat_get_image_desc(image_id); /* * Execution is NOT allowed if: * image_id is invalid OR * Caller is from Secure world OR * Image is Non-Secure OR * Image is Non-Executable OR * Image is NOT in AUTHENTICATED state. */ if ((!image_desc) || (GET_SECURITY_STATE(flags) == SECURE) || (GET_SECURITY_STATE(image_desc->ep_info.h.attr) == NON_SECURE) || (EP_GET_EXE(image_desc->ep_info.h.attr) == NON_EXECUTABLE) || (image_desc->state != IMAGE_STATE_AUTHENTICATED)) { WARN("BL1-FWU: Execution not allowed due to invalid state/args\n"); return -EPERM; } INFO("BL1-FWU: Executing Secure image\n"); #ifdef __aarch64__ /* Save NS-EL1 system registers. */ cm_el1_sysregs_context_save(NON_SECURE); #endif /* Prepare the image for execution. */ bl1_prepare_next_image(image_id); /* Update the secure image id. */ sec_exec_image_id = image_id; #ifdef __aarch64__ *handle = cm_get_context(SECURE); #else *handle = smc_get_ctx(SECURE); #endif return 0; } /******************************************************************************* * This function is responsible for resuming execution in the other security * world ******************************************************************************/ static register_t bl1_fwu_image_resume(register_t image_param, void **handle, unsigned int flags) { image_desc_t *image_desc; unsigned int resume_sec_state; unsigned int caller_sec_state = GET_SECURITY_STATE(flags); /* Get the image descriptor for last executed secure image id. */ image_desc = bl1_plat_get_image_desc(sec_exec_image_id); if (caller_sec_state == NON_SECURE) { if (!image_desc) { WARN("BL1-FWU: Resume not allowed due to no available" "secure image\n"); return -EPERM; } } else { /* image_desc must be valid for secure world callers */ assert(image_desc); } assert(GET_SECURITY_STATE(image_desc->ep_info.h.attr) == SECURE); assert(EP_GET_EXE(image_desc->ep_info.h.attr) == EXECUTABLE); if (caller_sec_state == SECURE) { assert(image_desc->state == IMAGE_STATE_EXECUTED); /* Update the flags. */ image_desc->state = IMAGE_STATE_INTERRUPTED; resume_sec_state = NON_SECURE; } else { assert(image_desc->state == IMAGE_STATE_INTERRUPTED); /* Update the flags. */ image_desc->state = IMAGE_STATE_EXECUTED; resume_sec_state = SECURE; } INFO("BL1-FWU: Resuming %s world context\n", (resume_sec_state == SECURE) ? "secure" : "normal"); #ifdef __aarch64__ /* Save the EL1 system registers of calling world. */ cm_el1_sysregs_context_save(caller_sec_state); /* Restore the EL1 system registers of resuming world. */ cm_el1_sysregs_context_restore(resume_sec_state); /* Update the next context. */ cm_set_next_eret_context(resume_sec_state); *handle = cm_get_context(resume_sec_state); #else /* Update the next context. */ cm_set_next_context(cm_get_context(resume_sec_state)); /* Prepare the smc context for the next BL image. */ smc_set_next_ctx(resume_sec_state); *handle = smc_get_ctx(resume_sec_state); #endif return image_param; } /******************************************************************************* * This function is responsible for resuming normal world context. ******************************************************************************/ static int bl1_fwu_sec_image_done(void **handle, unsigned int flags) { image_desc_t *image_desc; /* Make sure caller is from the secure world */ if (GET_SECURITY_STATE(flags) == NON_SECURE) { WARN("BL1-FWU: Image done not allowed from normal world\n"); return -EPERM; } /* Get the image descriptor for last executed secure image id */ image_desc = bl1_plat_get_image_desc(sec_exec_image_id); /* image_desc must correspond to a valid secure executing image */ assert(image_desc); assert(GET_SECURITY_STATE(image_desc->ep_info.h.attr) == SECURE); assert(EP_GET_EXE(image_desc->ep_info.h.attr) == EXECUTABLE); assert(image_desc->state == IMAGE_STATE_EXECUTED); #if ENABLE_ASSERTIONS int rc = bl1_fwu_remove_loaded_id(sec_exec_image_id); assert(rc == 0); #else bl1_fwu_remove_loaded_id(sec_exec_image_id); #endif /* Update the flags. */ image_desc->state = IMAGE_STATE_RESET; sec_exec_image_id = INVALID_IMAGE_ID; INFO("BL1-FWU: Resuming Normal world context\n"); #ifdef __aarch64__ /* * Secure world is done so no need to save the context. * Just restore the Non-Secure context. */ cm_el1_sysregs_context_restore(NON_SECURE); /* Update the next context. */ cm_set_next_eret_context(NON_SECURE); *handle = cm_get_context(NON_SECURE); #else /* Update the next context. */ cm_set_next_context(cm_get_context(NON_SECURE)); /* Prepare the smc context for the next BL image. */ smc_set_next_ctx(NON_SECURE); *handle = smc_get_ctx(NON_SECURE); #endif return 0; } /******************************************************************************* * This function provides the opportunity for users to perform any * platform specific handling after the Firmware update is done. ******************************************************************************/ __dead2 static void bl1_fwu_done(void *client_cookie, void *reserved) { NOTICE("BL1-FWU: *******FWU Process Completed*******\n"); /* * Call platform done function. */ bl1_plat_fwu_done(client_cookie, reserved); assert(0); } /******************************************************************************* * This function resets an image to IMAGE_STATE_RESET. It fails if the image is * being executed. ******************************************************************************/ static int bl1_fwu_image_reset(unsigned int image_id, unsigned int flags) { image_desc_t *image_desc = bl1_plat_get_image_desc(image_id); if ((!image_desc) || (GET_SECURITY_STATE(flags) == SECURE)) { WARN("BL1-FWU: Reset not allowed due to invalid args\n"); return -EPERM; } switch (image_desc->state) { case IMAGE_STATE_RESET: /* Nothing to do. */ break; case IMAGE_STATE_INTERRUPTED: case IMAGE_STATE_AUTHENTICATED: case IMAGE_STATE_COPIED: case IMAGE_STATE_COPYING: if (bl1_fwu_remove_loaded_id(image_id)) { WARN("BL1-FWU: Image reset couldn't find the image ID\n"); return -EPERM; } if (image_desc->copied_size) { /* Clear the memory if the image is copied */ assert(GET_SECURITY_STATE(image_desc->ep_info.h.attr) == SECURE); zero_normalmem((void *)image_desc->image_info.image_base, image_desc->copied_size); flush_dcache_range(image_desc->image_info.image_base, image_desc->copied_size); } /* Reset status variables */ image_desc->copied_size = 0; image_desc->image_info.image_size = 0; image_desc->state = IMAGE_STATE_RESET; /* Clear authentication state */ auth_img_flags[image_id] = 0; break; case IMAGE_STATE_EXECUTED: default: assert(0); /* Unreachable */ break; } return 0; } trusted-firmware-a-2.2/bl1/bl1_main.c000066400000000000000000000173571355360272700174320ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bl1_private.h" /* BL1 Service UUID */ DEFINE_SVC_UUID2(bl1_svc_uid, 0xd46739fd, 0xcb72, 0x9a4d, 0xb5, 0x75, 0x67, 0x15, 0xd6, 0xf4, 0xbb, 0x4a); static void bl1_load_bl2(void); #if ENABLE_PAUTH uint64_t bl1_apiakey[2]; #endif /******************************************************************************* * Helper utility to calculate the BL2 memory layout taking into consideration * the BL1 RW data assuming that it is at the top of the memory layout. ******************************************************************************/ void bl1_calc_bl2_mem_layout(const meminfo_t *bl1_mem_layout, meminfo_t *bl2_mem_layout) { assert(bl1_mem_layout != NULL); assert(bl2_mem_layout != NULL); /* * Remove BL1 RW data from the scope of memory visible to BL2. * This is assuming BL1 RW data is at the top of bl1_mem_layout. */ assert(BL1_RW_BASE > bl1_mem_layout->total_base); bl2_mem_layout->total_base = bl1_mem_layout->total_base; bl2_mem_layout->total_size = BL1_RW_BASE - bl1_mem_layout->total_base; flush_dcache_range((uintptr_t)bl2_mem_layout, sizeof(meminfo_t)); } /******************************************************************************* * Setup function for BL1. ******************************************************************************/ void bl1_setup(void) { /* Perform early platform-specific setup */ bl1_early_platform_setup(); /* Perform late platform-specific setup */ bl1_plat_arch_setup(); #if CTX_INCLUDE_PAUTH_REGS /* * Assert that the ARMv8.3-PAuth registers are present or an access * fault will be triggered when they are being saved or restored. */ assert(is_armv8_3_pauth_present()); #endif /* CTX_INCLUDE_PAUTH_REGS */ } /******************************************************************************* * Function to perform late architectural and platform specific initialization. * It also queries the platform to load and run next BL image. Only called * by the primary cpu after a cold boot. ******************************************************************************/ void bl1_main(void) { unsigned int image_id; /* Announce our arrival */ NOTICE(FIRMWARE_WELCOME_STR); NOTICE("BL1: %s\n", version_string); NOTICE("BL1: %s\n", build_message); INFO("BL1: RAM %p - %p\n", (void *)BL1_RAM_BASE, (void *)BL1_RAM_LIMIT); print_errata_status(); #if ENABLE_ASSERTIONS u_register_t val; /* * Ensure that MMU/Caches and coherency are turned on */ #ifdef __aarch64__ val = read_sctlr_el3(); #else val = read_sctlr(); #endif assert(val & SCTLR_M_BIT); assert(val & SCTLR_C_BIT); assert(val & SCTLR_I_BIT); /* * Check that Cache Writeback Granule (CWG) in CTR_EL0 matches the * provided platform value */ val = (read_ctr_el0() >> CTR_CWG_SHIFT) & CTR_CWG_MASK; /* * If CWG is zero, then no CWG information is available but we can * at least check the platform value is less than the architectural * maximum. */ if (val != 0) assert(CACHE_WRITEBACK_GRANULE == SIZE_FROM_LOG2_WORDS(val)); else assert(CACHE_WRITEBACK_GRANULE <= MAX_CACHE_LINE_SIZE); #endif /* ENABLE_ASSERTIONS */ /* Perform remaining generic architectural setup from EL3 */ bl1_arch_setup(); #if TRUSTED_BOARD_BOOT /* Initialize authentication module */ auth_mod_init(); #endif /* TRUSTED_BOARD_BOOT */ /* Perform platform setup in BL1. */ bl1_platform_setup(); #if ENABLE_PAUTH /* Store APIAKey_EL1 key */ bl1_apiakey[0] = read_apiakeylo_el1(); bl1_apiakey[1] = read_apiakeyhi_el1(); #endif /* ENABLE_PAUTH */ /* Get the image id of next image to load and run. */ image_id = bl1_plat_get_next_image_id(); /* * We currently interpret any image id other than * BL2_IMAGE_ID as the start of firmware update. */ if (image_id == BL2_IMAGE_ID) bl1_load_bl2(); else NOTICE("BL1-FWU: *******FWU Process Started*******\n"); bl1_prepare_next_image(image_id); console_flush(); } /******************************************************************************* * This function locates and loads the BL2 raw binary image in the trusted SRAM. * Called by the primary cpu after a cold boot. * TODO: Add support for alternative image load mechanism e.g using virtio/elf * loader etc. ******************************************************************************/ static void bl1_load_bl2(void) { image_desc_t *image_desc; image_info_t *image_info; int err; /* Get the image descriptor */ image_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID); assert(image_desc); /* Get the image info */ image_info = &image_desc->image_info; INFO("BL1: Loading BL2\n"); err = bl1_plat_handle_pre_image_load(BL2_IMAGE_ID); if (err) { ERROR("Failure in pre image load handling of BL2 (%d)\n", err); plat_error_handler(err); } err = load_auth_image(BL2_IMAGE_ID, image_info); if (err) { ERROR("Failed to load BL2 firmware.\n"); plat_error_handler(err); } /* Allow platform to handle image information. */ err = bl1_plat_handle_post_image_load(BL2_IMAGE_ID); if (err) { ERROR("Failure in post image load handling of BL2 (%d)\n", err); plat_error_handler(err); } NOTICE("BL1: Booting BL2\n"); } /******************************************************************************* * Function called just before handing over to the next BL to inform the user * about the boot progress. In debug mode, also print details about the BL * image's execution context. ******************************************************************************/ void bl1_print_next_bl_ep_info(const entry_point_info_t *bl_ep_info) { #ifdef __aarch64__ NOTICE("BL1: Booting BL31\n"); #else NOTICE("BL1: Booting BL32\n"); #endif /* __aarch64__ */ print_entry_point_info(bl_ep_info); } #if SPIN_ON_BL1_EXIT void print_debug_loop_message(void) { NOTICE("BL1: Debug loop, spinning forever\n"); NOTICE("BL1: Please connect the debugger to continue\n"); } #endif /******************************************************************************* * Top level handler for servicing BL1 SMCs. ******************************************************************************/ register_t bl1_smc_handler(unsigned int smc_fid, register_t x1, register_t x2, register_t x3, register_t x4, void *cookie, void *handle, unsigned int flags) { #if TRUSTED_BOARD_BOOT /* * Dispatch FWU calls to FWU SMC handler and return its return * value */ if (is_fwu_fid(smc_fid)) { return bl1_fwu_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); } #endif switch (smc_fid) { case BL1_SMC_CALL_COUNT: SMC_RET1(handle, BL1_NUM_SMC_CALLS); case BL1_SMC_UID: SMC_UUID_RET(handle, bl1_svc_uid); case BL1_SMC_VERSION: SMC_RET1(handle, BL1_SMC_MAJOR_VER | BL1_SMC_MINOR_VER); default: break; } WARN("Unimplemented BL1 SMC Call: 0x%x \n", smc_fid); SMC_RET1(handle, SMC_UNK); } /******************************************************************************* * BL1 SMC wrapper. This function is only used in AArch32 mode to ensure ABI * compliance when invoking bl1_smc_handler. ******************************************************************************/ register_t bl1_smc_wrapper(uint32_t smc_fid, void *cookie, void *handle, unsigned int flags) { register_t x1, x2, x3, x4; assert(handle); get_smc_params_from_ctx(handle, x1, x2, x3, x4); return bl1_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); } trusted-firmware-a-2.2/bl1/bl1_private.h000066400000000000000000000012231355360272700201460ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BL1_PRIVATE_H #define BL1_PRIVATE_H #include #include /****************************************** * Function prototypes *****************************************/ void bl1_arch_setup(void); void bl1_arch_next_el_setup(void); void bl1_prepare_next_image(unsigned int image_id); register_t bl1_fwu_smc_handler(unsigned int smc_fid, register_t x1, register_t x2, register_t x3, register_t x4, void *cookie, void *handle, unsigned int flags); #endif /* BL1_PRIVATE_H */ trusted-firmware-a-2.2/bl1/tbbr/000077500000000000000000000000001355360272700165205ustar00rootroot00000000000000trusted-firmware-a-2.2/bl1/tbbr/tbbr_img_desc.c000066400000000000000000000034601355360272700214520ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include image_desc_t bl1_tbbr_image_descs[] = { { .image_id = FWU_CERT_ID, SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, VERSION_1, image_info_t, 0), .image_info.image_base = BL2_BASE, .image_info.image_max_size = BL2_LIMIT - BL2_BASE, SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, VERSION_1, entry_point_info_t, SECURE), }, #if NS_BL1U_BASE { .image_id = NS_BL1U_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_1, entry_point_info_t, NON_SECURE | EXECUTABLE), .ep_info.pc = NS_BL1U_BASE, }, #endif #if SCP_BL2U_BASE { .image_id = SCP_BL2U_IMAGE_ID, SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, VERSION_1, image_info_t, 0), .image_info.image_base = SCP_BL2U_BASE, .image_info.image_max_size = SCP_BL2U_LIMIT - SCP_BL2U_BASE, SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, VERSION_1, entry_point_info_t, SECURE), }, #endif #if BL2U_BASE { .image_id = BL2U_IMAGE_ID, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_1, image_info_t, 0), .image_info.image_base = BL2U_BASE, .image_info.image_max_size = BL2U_LIMIT - BL2U_BASE, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_1, entry_point_info_t, SECURE | EXECUTABLE), .ep_info.pc = BL2U_BASE, }, #endif #if NS_BL2U_BASE { .image_id = NS_BL2U_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_1, entry_point_info_t, NON_SECURE), }, #endif BL2_IMAGE_DESC, { .image_id = INVALID_IMAGE_ID, } }; trusted-firmware-a-2.2/bl2/000077500000000000000000000000001355360272700155705ustar00rootroot00000000000000trusted-firmware-a-2.2/bl2/aarch32/000077500000000000000000000000001355360272700170135ustar00rootroot00000000000000trusted-firmware-a-2.2/bl2/aarch32/bl2_arch_setup.c000066400000000000000000000007261355360272700220600ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "../bl2_private.h" /******************************************************************************* * Place holder function to perform any Secure SVC specific architectural * setup. At the moment there is nothing to do. ******************************************************************************/ void bl2_arch_setup(void) { } trusted-firmware-a-2.2/bl2/aarch32/bl2_el3_entrypoint.S000066400000000000000000000043451355360272700226620ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl bl2_entrypoint .globl bl2_run_next_image func bl2_entrypoint /* Save arguments x0-x3 from previous Boot loader */ mov r9, r0 mov r10, r1 mov r11, r2 mov r12, r3 el3_entrypoint_common \ _init_sctlr=1 \ _warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \ _secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \ _init_memory=1 \ _init_c_runtime=1 \ _exception_vectors=bl2_vector_table /* * Restore parameters of boot rom */ mov r0, r9 mov r1, r10 mov r2, r11 mov r3, r12 /* --------------------------------------------- * Perform BL2 setup * --------------------------------------------- */ bl bl2_el3_setup /* --------------------------------------------- * Jump to main function. * --------------------------------------------- */ bl bl2_main /* --------------------------------------------- * Should never reach this point. * --------------------------------------------- */ no_ret plat_panic_handler endfunc bl2_entrypoint func bl2_run_next_image mov r8,r0 /* * MMU needs to be disabled because both BL2 and BL32 execute * in PL1, and therefore share the same address space. * BL32 will initialize the address space according to its * own requirement. */ bl disable_mmu_icache_secure stcopr r0, TLBIALL dsb sy isb mov r0, r8 bl bl2_el3_plat_prepare_exit /* * Extract PC and SPSR based on struct `entry_point_info_t` * and load it in LR and SPSR registers respectively. */ ldr lr, [r8, #ENTRY_POINT_INFO_PC_OFFSET] ldr r1, [r8, #(ENTRY_POINT_INFO_PC_OFFSET + 4)] msr spsr_xc, r1 /* Some BL32 stages expect lr_svc to provide the BL33 entry address */ cps #MODE32_svc ldr lr, [r8, #ENTRY_POINT_INFO_LR_SVC_OFFSET] cps #MODE32_mon add r8, r8, #ENTRY_POINT_INFO_ARGS_OFFSET ldm r8, {r0, r1, r2, r3} eret endfunc bl2_run_next_image trusted-firmware-a-2.2/bl2/aarch32/bl2_el3_exceptions.S000066400000000000000000000010001355360272700226110ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl bl2_vector_table vector_base bl2_vector_table b bl2_entrypoint b report_exception /* Undef */ b report_exception /* SVC call */ b report_exception /* Prefetch abort */ b report_exception /* Data abort */ b report_exception /* Reserved */ b report_exception /* IRQ */ b report_exception /* FIQ */ trusted-firmware-a-2.2/bl2/aarch32/bl2_entrypoint.S000066400000000000000000000066461355360272700221250ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl bl2_vector_table .globl bl2_entrypoint vector_base bl2_vector_table b bl2_entrypoint b report_exception /* Undef */ b report_exception /* SVC call */ b report_exception /* Prefetch abort */ b report_exception /* Data abort */ b report_exception /* Reserved */ b report_exception /* IRQ */ b report_exception /* FIQ */ func bl2_entrypoint /*--------------------------------------------- * Save arguments x0 - x3 from BL1 for future * use. * --------------------------------------------- */ mov r9, r0 mov r10, r1 mov r11, r2 mov r12, r3 /* --------------------------------------------- * Set the exception vector to something sane. * --------------------------------------------- */ ldr r0, =bl2_vector_table stcopr r0, VBAR isb /* -------------------------------------------------------- * Enable the instruction cache - disable speculative loads * -------------------------------------------------------- */ ldcopr r0, SCTLR orr r0, r0, #SCTLR_I_BIT bic r0, r0, #SCTLR_DSSBS_BIT stcopr r0, SCTLR isb /* --------------------------------------------- * Since BL2 executes after BL1, it is assumed * here that BL1 has already has done the * necessary register initializations. * --------------------------------------------- */ /* --------------------------------------------- * Invalidate the RW memory used by the BL2 * image. This includes the data and NOBITS * sections. This is done to safeguard against * possible corruption of this memory by dirty * cache lines in a system cache as a result of * use by an earlier boot loader stage. * --------------------------------------------- */ ldr r0, =__RW_START__ ldr r1, =__RW_END__ sub r1, r1, r0 bl inv_dcache_range /* --------------------------------------------- * Zero out NOBITS sections. There are 2 of them: * - the .bss section; * - the coherent memory section. * --------------------------------------------- */ ldr r0, =__BSS_START__ ldr r1, =__BSS_SIZE__ bl zeromem #if USE_COHERENT_MEM ldr r0, =__COHERENT_RAM_START__ ldr r1, =__COHERENT_RAM_UNALIGNED_SIZE__ bl zeromem #endif /* -------------------------------------------- * Allocate a stack whose memory will be marked * as Normal-IS-WBWA when the MMU is enabled. * There is no risk of reading stale stack * memory after enabling the MMU as only the * primary cpu is running at the moment. * -------------------------------------------- */ bl plat_set_my_stack /* --------------------------------------------- * Initialize the stack protector canary before * any C code is called. * --------------------------------------------- */ #if STACK_PROTECTOR_ENABLED bl update_stack_protector_canary #endif /* --------------------------------------------- * Perform BL2 setup * --------------------------------------------- */ mov r0, r9 mov r1, r10 mov r2, r11 mov r3, r12 bl bl2_setup /* --------------------------------------------- * Jump to main function. * --------------------------------------------- */ bl bl2_main /* --------------------------------------------- * Should never reach this point. * --------------------------------------------- */ no_ret plat_panic_handler endfunc bl2_entrypoint trusted-firmware-a-2.2/bl2/aarch64/000077500000000000000000000000001355360272700170205ustar00rootroot00000000000000trusted-firmware-a-2.2/bl2/aarch64/bl2_arch_setup.c000066400000000000000000000011371355360272700220620ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "../bl2_private.h" /******************************************************************************* * Place holder function to perform any S-EL1 specific architectural setup. At * the moment there is nothing to do. ******************************************************************************/ void bl2_arch_setup(void) { /* Give access to FP/SIMD registers */ write_cpacr(CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE)); } trusted-firmware-a-2.2/bl2/aarch64/bl2_el3_entrypoint.S000066400000000000000000000052351355360272700226660ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl bl2_entrypoint .globl bl2_el3_run_image .globl bl2_run_next_image func bl2_entrypoint /* Save arguments x0-x3 from previous Boot loader */ mov x20, x0 mov x21, x1 mov x22, x2 mov x23, x3 el3_entrypoint_common \ _init_sctlr=1 \ _warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \ _secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \ _init_memory=1 \ _init_c_runtime=1 \ _exception_vectors=bl2_el3_exceptions /* --------------------------------------------- * Restore parameters of boot rom * --------------------------------------------- */ mov x0, x20 mov x1, x21 mov x2, x22 mov x3, x23 /* --------------------------------------------- * Perform BL2 setup * --------------------------------------------- */ bl bl2_el3_setup #if ENABLE_PAUTH /* --------------------------------------------- * Program APIAKey_EL1 and enable pointer authentication. * --------------------------------------------- */ bl pauth_init_enable_el3 #endif /* ENABLE_PAUTH */ /* --------------------------------------------- * Jump to main function. * --------------------------------------------- */ bl bl2_main /* --------------------------------------------- * Should never reach this point. * --------------------------------------------- */ no_ret plat_panic_handler endfunc bl2_entrypoint func bl2_run_next_image mov x20,x0 /* --------------------------------------------- * MMU needs to be disabled because both BL2 and BL31 execute * in EL3, and therefore share the same address space. * BL31 will initialize the address space according to its * own requirement. * --------------------------------------------- */ bl disable_mmu_icache_el3 tlbi alle3 bl bl2_el3_plat_prepare_exit #if ENABLE_PAUTH /* --------------------------------------------- * Disable pointer authentication before jumping * to next boot image. * --------------------------------------------- */ bl pauth_disable_el3 #endif /* ENABLE_PAUTH */ ldp x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET] msr elr_el3, x0 msr spsr_el3, x1 ldp x6, x7, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x30)] ldp x4, x5, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x20)] ldp x2, x3, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x10)] ldp x0, x1, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x0)] eret endfunc bl2_run_next_image trusted-firmware-a-2.2/bl2/aarch64/bl2_el3_exceptions.S000066400000000000000000000063421355360272700226340ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* ----------------------------------------------------------------------------- * Very simple stackless exception handlers used by BL2. * ----------------------------------------------------------------------------- */ .globl bl2_el3_exceptions vector_base bl2_el3_exceptions /* ----------------------------------------------------- * Current EL with SP0 : 0x0 - 0x200 * ----------------------------------------------------- */ vector_entry SynchronousExceptionSP0 mov x0, #SYNC_EXCEPTION_SP_EL0 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SynchronousExceptionSP0 vector_entry IrqSP0 mov x0, #IRQ_SP_EL0 bl plat_report_exception no_ret plat_panic_handler end_vector_entry IrqSP0 vector_entry FiqSP0 mov x0, #FIQ_SP_EL0 bl plat_report_exception no_ret plat_panic_handler end_vector_entry FiqSP0 vector_entry SErrorSP0 mov x0, #SERROR_SP_EL0 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SErrorSP0 /* ----------------------------------------------------- * Current EL with SPx: 0x200 - 0x400 * ----------------------------------------------------- */ vector_entry SynchronousExceptionSPx mov x0, #SYNC_EXCEPTION_SP_ELX bl plat_report_exception no_ret plat_panic_handler end_vector_entry SynchronousExceptionSPx vector_entry IrqSPx mov x0, #IRQ_SP_ELX bl plat_report_exception no_ret plat_panic_handler end_vector_entry IrqSPx vector_entry FiqSPx mov x0, #FIQ_SP_ELX bl plat_report_exception no_ret plat_panic_handler end_vector_entry FiqSPx vector_entry SErrorSPx mov x0, #SERROR_SP_ELX bl plat_report_exception no_ret plat_panic_handler end_vector_entry SErrorSPx /* ----------------------------------------------------- * Lower EL using AArch64 : 0x400 - 0x600 * ----------------------------------------------------- */ vector_entry SynchronousExceptionA64 mov x0, #SYNC_EXCEPTION_AARCH64 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SynchronousExceptionA64 vector_entry IrqA64 mov x0, #IRQ_AARCH64 bl plat_report_exception no_ret plat_panic_handler end_vector_entry IrqA64 vector_entry FiqA64 mov x0, #FIQ_AARCH64 bl plat_report_exception no_ret plat_panic_handler end_vector_entry FiqA64 vector_entry SErrorA64 mov x0, #SERROR_AARCH64 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SErrorA64 /* ----------------------------------------------------- * Lower EL using AArch32 : 0x600 - 0x800 * ----------------------------------------------------- */ vector_entry SynchronousExceptionA32 mov x0, #SYNC_EXCEPTION_AARCH32 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SynchronousExceptionA32 vector_entry IrqA32 mov x0, #IRQ_AARCH32 bl plat_report_exception no_ret plat_panic_handler end_vector_entry IrqA32 vector_entry FiqA32 mov x0, #FIQ_AARCH32 bl plat_report_exception no_ret plat_panic_handler end_vector_entry FiqA32 vector_entry SErrorA32 mov x0, #SERROR_AARCH32 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SErrorA32 trusted-firmware-a-2.2/bl2/aarch64/bl2_entrypoint.S000066400000000000000000000071241355360272700221220ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl bl2_entrypoint func bl2_entrypoint /*--------------------------------------------- * Save arguments x0 - x3 from BL1 for future * use. * --------------------------------------------- */ mov x20, x0 mov x21, x1 mov x22, x2 mov x23, x3 /* --------------------------------------------- * Set the exception vector to something sane. * --------------------------------------------- */ adr x0, early_exceptions msr vbar_el1, x0 isb /* --------------------------------------------- * Enable the SError interrupt now that the * exception vectors have been setup. * --------------------------------------------- */ msr daifclr, #DAIF_ABT_BIT /* --------------------------------------------- * Enable the instruction cache, stack pointer * and data access alignment checks and disable * speculative loads. * --------------------------------------------- */ mov x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT) mrs x0, sctlr_el1 orr x0, x0, x1 bic x0, x0, #SCTLR_DSSBS_BIT msr sctlr_el1, x0 isb /* --------------------------------------------- * Invalidate the RW memory used by the BL2 * image. This includes the data and NOBITS * sections. This is done to safeguard against * possible corruption of this memory by dirty * cache lines in a system cache as a result of * use by an earlier boot loader stage. * --------------------------------------------- */ adr x0, __RW_START__ adr x1, __RW_END__ sub x1, x1, x0 bl inv_dcache_range /* --------------------------------------------- * Zero out NOBITS sections. There are 2 of them: * - the .bss section; * - the coherent memory section. * --------------------------------------------- */ adrp x0, __BSS_START__ add x0, x0, :lo12:__BSS_START__ adrp x1, __BSS_END__ add x1, x1, :lo12:__BSS_END__ sub x1, x1, x0 bl zeromem #if USE_COHERENT_MEM adrp x0, __COHERENT_RAM_START__ add x0, x0, :lo12:__COHERENT_RAM_START__ adrp x1, __COHERENT_RAM_END_UNALIGNED__ add x1, x1, :lo12:__COHERENT_RAM_END_UNALIGNED__ sub x1, x1, x0 bl zeromem #endif /* -------------------------------------------- * Allocate a stack whose memory will be marked * as Normal-IS-WBWA when the MMU is enabled. * There is no risk of reading stale stack * memory after enabling the MMU as only the * primary cpu is running at the moment. * -------------------------------------------- */ bl plat_set_my_stack /* --------------------------------------------- * Initialize the stack protector canary before * any C code is called. * --------------------------------------------- */ #if STACK_PROTECTOR_ENABLED bl update_stack_protector_canary #endif /* --------------------------------------------- * Perform BL2 setup * --------------------------------------------- */ mov x0, x20 mov x1, x21 mov x2, x22 mov x3, x23 bl bl2_setup #if ENABLE_PAUTH /* --------------------------------------------- * Program APIAKey_EL1 * and enable pointer authentication. * --------------------------------------------- */ bl pauth_init_enable_el1 #endif /* ENABLE_PAUTH */ /* --------------------------------------------- * Jump to main function. * --------------------------------------------- */ bl bl2_main /* --------------------------------------------- * Should never reach this point. * --------------------------------------------- */ no_ret plat_panic_handler endfunc bl2_entrypoint trusted-firmware-a-2.2/bl2/bl2.ld.S000066400000000000000000000104741355360272700167770ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT) OUTPUT_ARCH(PLATFORM_LINKER_ARCH) ENTRY(bl2_entrypoint) MEMORY { RAM (rwx): ORIGIN = BL2_BASE, LENGTH = BL2_LIMIT - BL2_BASE } SECTIONS { . = BL2_BASE; ASSERT(. == ALIGN(PAGE_SIZE), "BL2_BASE address is not aligned on a page boundary.") #if SEPARATE_CODE_AND_RODATA .text . : { __TEXT_START__ = .; *bl2_entrypoint.o(.text*) *(.text*) *(.vectors) . = ALIGN(PAGE_SIZE); __TEXT_END__ = .; } >RAM /* .ARM.extab and .ARM.exidx are only added because Clang need them */ .ARM.extab . : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM .ARM.exidx . : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >RAM .rodata . : { __RODATA_START__ = .; *(.rodata*) /* Ensure 8-byte alignment for descriptors and ensure inclusion */ . = ALIGN(8); __PARSER_LIB_DESCS_START__ = .; KEEP(*(.img_parser_lib_descs)) __PARSER_LIB_DESCS_END__ = .; . = ALIGN(PAGE_SIZE); __RODATA_END__ = .; } >RAM #else ro . : { __RO_START__ = .; *bl2_entrypoint.o(.text*) *(.text*) *(.rodata*) /* Ensure 8-byte alignment for descriptors and ensure inclusion */ . = ALIGN(8); __PARSER_LIB_DESCS_START__ = .; KEEP(*(.img_parser_lib_descs)) __PARSER_LIB_DESCS_END__ = .; *(.vectors) __RO_END_UNALIGNED__ = .; /* * Memory page(s) mapped to this section will be marked as * read-only, executable. No RW data from the next section must * creep in. Ensure the rest of the current memory page is unused. */ . = ALIGN(PAGE_SIZE); __RO_END__ = .; } >RAM #endif /* * Define a linker symbol to mark start of the RW memory area for this * image. */ __RW_START__ = . ; /* * .data must be placed at a lower address than the stacks if the stack * protector is enabled. Alternatively, the .data.stack_protector_canary * section can be placed independently of the main .data section. */ .data . : { __DATA_START__ = .; *(.data*) __DATA_END__ = .; } >RAM stacks (NOLOAD) : { __STACKS_START__ = .; *(tzfw_normal_stacks) __STACKS_END__ = .; } >RAM /* * The .bss section gets initialised to 0 at runtime. * Its base address should be 16-byte aligned for better performance of the * zero-initialization code. */ .bss : ALIGN(16) { __BSS_START__ = .; *(SORT_BY_ALIGNMENT(.bss*)) *(COMMON) __BSS_END__ = .; } >RAM /* * The xlat_table section is for full, aligned page tables (4K). * Removing them from .bss avoids forcing 4K alignment on * the .bss section. The tables are initialized to zero by the translation * tables library. */ xlat_table (NOLOAD) : { *(xlat_table) } >RAM #if USE_COHERENT_MEM /* * The base address of the coherent memory section must be page-aligned (4K) * to guarantee that the coherent data are stored on their own pages and * are not mixed with normal data. This is required to set up the correct * memory attributes for the coherent data page tables. */ coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) { __COHERENT_RAM_START__ = .; *(tzfw_coherent_mem) __COHERENT_RAM_END_UNALIGNED__ = .; /* * Memory page(s) mapped to this section will be marked * as device memory. No other unexpected data must creep in. * Ensure the rest of the current memory page is unused. */ . = ALIGN(PAGE_SIZE); __COHERENT_RAM_END__ = .; } >RAM #endif /* * Define a linker symbol to mark end of the RW memory area for this * image. */ __RW_END__ = .; __BL2_END__ = .; __BSS_SIZE__ = SIZEOF(.bss); #if USE_COHERENT_MEM __COHERENT_RAM_UNALIGNED_SIZE__ = __COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__; #endif ASSERT(. <= BL2_LIMIT, "BL2 image has exceeded its limit.") } trusted-firmware-a-2.2/bl2/bl2.mk000066400000000000000000000014471355360272700166060ustar00rootroot00000000000000# # Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # BL2_SOURCES += bl2/bl2_image_load_v2.c \ bl2/bl2_main.c \ bl2/${ARCH}/bl2_arch_setup.c \ lib/locks/exclusive/${ARCH}/spinlock.S \ plat/common/${ARCH}/platform_up_stack.S \ ${MBEDTLS_SOURCES} ifeq (${ARCH},aarch64) BL2_SOURCES += common/aarch64/early_exceptions.S endif ifeq (${BL2_AT_EL3},0) BL2_SOURCES += bl2/${ARCH}/bl2_entrypoint.S BL2_LINKERFILE := bl2/bl2.ld.S else BL2_SOURCES += bl2/${ARCH}/bl2_el3_entrypoint.S \ bl2/${ARCH}/bl2_el3_exceptions.S \ lib/cpus/${ARCH}/cpu_helpers.S \ lib/cpus/errata_report.c ifeq (${ARCH},aarch64) BL2_SOURCES += lib/cpus/aarch64/dsu_helpers.S endif BL2_LINKERFILE := bl2/bl2_el3.ld.S endif trusted-firmware-a-2.2/bl2/bl2_el3.ld.S000066400000000000000000000140451355360272700175400ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT) OUTPUT_ARCH(PLATFORM_LINKER_ARCH) ENTRY(bl2_entrypoint) MEMORY { #if BL2_IN_XIP_MEM ROM (rx): ORIGIN = BL2_RO_BASE, LENGTH = BL2_RO_LIMIT - BL2_RO_BASE RAM (rwx): ORIGIN = BL2_RW_BASE, LENGTH = BL2_RW_LIMIT - BL2_RW_BASE #else RAM (rwx): ORIGIN = BL2_BASE, LENGTH = BL2_LIMIT - BL2_BASE #endif } #if !BL2_IN_XIP_MEM #define ROM RAM #endif SECTIONS { #if BL2_IN_XIP_MEM . = BL2_RO_BASE; ASSERT(. == ALIGN(PAGE_SIZE), "BL2_RO_BASE address is not aligned on a page boundary.") #else . = BL2_BASE; ASSERT(. == ALIGN(PAGE_SIZE), "BL2_BASE address is not aligned on a page boundary.") #endif #if SEPARATE_CODE_AND_RODATA .text . : { __TEXT_START__ = .; __TEXT_RESIDENT_START__ = .; *bl2_el3_entrypoint.o(.text*) *(.text.asm.*) __TEXT_RESIDENT_END__ = .; *(.text*) *(.vectors) . = ALIGN(PAGE_SIZE); __TEXT_END__ = .; } >ROM .rodata . : { __RODATA_START__ = .; *(.rodata*) /* Ensure 8-byte alignment for descriptors and ensure inclusion */ . = ALIGN(8); __PARSER_LIB_DESCS_START__ = .; KEEP(*(.img_parser_lib_descs)) __PARSER_LIB_DESCS_END__ = .; /* * Ensure 8-byte alignment for cpu_ops so that its fields are also * aligned. Also ensure cpu_ops inclusion. */ . = ALIGN(8); __CPU_OPS_START__ = .; KEEP(*(cpu_ops)) __CPU_OPS_END__ = .; . = ALIGN(PAGE_SIZE); __RODATA_END__ = .; } >ROM ASSERT(__TEXT_RESIDENT_END__ - __TEXT_RESIDENT_START__ <= PAGE_SIZE, "Resident part of BL2 has exceeded its limit.") #else ro . : { __RO_START__ = .; __TEXT_RESIDENT_START__ = .; *bl2_el3_entrypoint.o(.text*) *(.text.asm.*) __TEXT_RESIDENT_END__ = .; *(.text*) *(.rodata*) /* * Ensure 8-byte alignment for cpu_ops so that its fields are also * aligned. Also ensure cpu_ops inclusion. */ . = ALIGN(8); __CPU_OPS_START__ = .; KEEP(*(cpu_ops)) __CPU_OPS_END__ = .; /* Ensure 8-byte alignment for descriptors and ensure inclusion */ . = ALIGN(8); __PARSER_LIB_DESCS_START__ = .; KEEP(*(.img_parser_lib_descs)) __PARSER_LIB_DESCS_END__ = .; *(.vectors) __RO_END_UNALIGNED__ = .; /* * Memory page(s) mapped to this section will be marked as * read-only, executable. No RW data from the next section must * creep in. Ensure the rest of the current memory page is unused. */ . = ALIGN(PAGE_SIZE); __RO_END__ = .; } >ROM #endif ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__, "cpu_ops not defined for this platform.") #if BL2_IN_XIP_MEM . = BL2_RW_BASE; ASSERT(BL2_RW_BASE == ALIGN(PAGE_SIZE), "BL2_RW_BASE address is not aligned on a page boundary.") #endif /* * Define a linker symbol to mark start of the RW memory area for this * image. */ __RW_START__ = . ; /* * .data must be placed at a lower address than the stacks if the stack * protector is enabled. Alternatively, the .data.stack_protector_canary * section can be placed independently of the main .data section. */ .data . : { __DATA_RAM_START__ = .; *(.data*) __DATA_RAM_END__ = .; } >RAM AT>ROM stacks (NOLOAD) : { __STACKS_START__ = .; *(tzfw_normal_stacks) __STACKS_END__ = .; } >RAM /* * The .bss section gets initialised to 0 at runtime. * Its base address should be 16-byte aligned for better performance of the * zero-initialization code. */ .bss : ALIGN(16) { __BSS_START__ = .; *(SORT_BY_ALIGNMENT(.bss*)) *(COMMON) __BSS_END__ = .; } >RAM /* * The xlat_table section is for full, aligned page tables (4K). * Removing them from .bss avoids forcing 4K alignment on * the .bss section. The tables are initialized to zero by the translation * tables library. */ xlat_table (NOLOAD) : { *(xlat_table) } >RAM #if USE_COHERENT_MEM /* * The base address of the coherent memory section must be page-aligned (4K) * to guarantee that the coherent data are stored on their own pages and * are not mixed with normal data. This is required to set up the correct * memory attributes for the coherent data page tables. */ coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) { __COHERENT_RAM_START__ = .; *(tzfw_coherent_mem) __COHERENT_RAM_END_UNALIGNED__ = .; /* * Memory page(s) mapped to this section will be marked * as device memory. No other unexpected data must creep in. * Ensure the rest of the current memory page is unused. */ . = ALIGN(PAGE_SIZE); __COHERENT_RAM_END__ = .; } >RAM #endif /* * Define a linker symbol to mark end of the RW memory area for this * image. */ __RW_END__ = .; __BL2_END__ = .; #if BL2_IN_XIP_MEM __BL2_RAM_START__ = ADDR(.data); __BL2_RAM_END__ = .; __DATA_ROM_START__ = LOADADDR(.data); __DATA_SIZE__ = SIZEOF(.data); /* * The .data section is the last PROGBITS section so its end marks the end * of BL2's RO content in XIP memory.. */ __BL2_ROM_END__ = __DATA_ROM_START__ + __DATA_SIZE__; ASSERT(__BL2_ROM_END__ <= BL2_RO_LIMIT, "BL2's RO content has exceeded its limit.") #endif __BSS_SIZE__ = SIZEOF(.bss); #if USE_COHERENT_MEM __COHERENT_RAM_UNALIGNED_SIZE__ = __COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__; #endif #if BL2_IN_XIP_MEM ASSERT(. <= BL2_RW_LIMIT, "BL2's RW content has exceeded its limit.") #else ASSERT(. <= BL2_LIMIT, "BL2 image has exceeded its limit.") #endif } trusted-firmware-a-2.2/bl2/bl2_image_load_v2.c000066400000000000000000000062211355360272700211640ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "bl2_private.h" /******************************************************************************* * This function loads SCP_BL2/BL3x images and returns the ep_info for * the next executable image. ******************************************************************************/ struct entry_point_info *bl2_load_images(void) { bl_params_t *bl2_to_next_bl_params; bl_load_info_t *bl2_load_info; const bl_load_info_node_t *bl2_node_info; int plat_setup_done = 0; int err; /* * Get information about the images to load. */ bl2_load_info = plat_get_bl_image_load_info(); assert(bl2_load_info); assert(bl2_load_info->head); assert(bl2_load_info->h.type == PARAM_BL_LOAD_INFO); assert(bl2_load_info->h.version >= VERSION_2); bl2_node_info = bl2_load_info->head; while (bl2_node_info) { /* * Perform platform setup before loading the image, * if indicated in the image attributes AND if NOT * already done before. */ if (bl2_node_info->image_info->h.attr & IMAGE_ATTRIB_PLAT_SETUP) { if (plat_setup_done) { WARN("BL2: Platform setup already done!!\n"); } else { INFO("BL2: Doing platform setup\n"); bl2_platform_setup(); plat_setup_done = 1; } } err = bl2_plat_handle_pre_image_load(bl2_node_info->image_id); if (err) { ERROR("BL2: Failure in pre image load handling (%i)\n", err); plat_error_handler(err); } if (!(bl2_node_info->image_info->h.attr & IMAGE_ATTRIB_SKIP_LOADING)) { INFO("BL2: Loading image id %d\n", bl2_node_info->image_id); err = load_auth_image(bl2_node_info->image_id, bl2_node_info->image_info); if (err) { ERROR("BL2: Failed to load image (%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; } /* * Get information to pass to the next image. */ bl2_to_next_bl_params = plat_get_next_bl_params(); assert(bl2_to_next_bl_params); assert(bl2_to_next_bl_params->head); assert(bl2_to_next_bl_params->h.type == PARAM_BL_PARAMS); assert(bl2_to_next_bl_params->h.version >= VERSION_2); assert(bl2_to_next_bl_params->head->ep_info); /* Populate arg0 for the next BL image if not already provided */ if (bl2_to_next_bl_params->head->ep_info->args.arg0 == (u_register_t)0) bl2_to_next_bl_params->head->ep_info->args.arg0 = (u_register_t)bl2_to_next_bl_params; /* Flush the parameters to be passed to next image */ plat_flush_next_bl_params(); return bl2_to_next_bl_params->head->ep_info; } trusted-firmware-a-2.2/bl2/bl2_main.c000066400000000000000000000074571355360272700174340ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include "bl2_private.h" #ifdef __aarch64__ #define NEXT_IMAGE "BL31" #else #define NEXT_IMAGE "BL32" #endif #if !BL2_AT_EL3 /******************************************************************************* * Setup function for BL2. ******************************************************************************/ void bl2_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { /* Perform early platform-specific setup */ bl2_early_platform_setup2(arg0, arg1, arg2, arg3); /* Perform late platform-specific setup */ bl2_plat_arch_setup(); #if CTX_INCLUDE_PAUTH_REGS /* * Assert that the ARMv8.3-PAuth registers are present or an access * fault will be triggered when they are being saved or restored. */ assert(is_armv8_3_pauth_present()); #endif /* CTX_INCLUDE_PAUTH_REGS */ } #else /* if BL2_AT_EL3 */ /******************************************************************************* * Setup function for BL2 when BL2_AT_EL3=1. ******************************************************************************/ void bl2_el3_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { /* Perform early platform-specific setup */ bl2_el3_early_platform_setup(arg0, arg1, arg2, arg3); /* Perform late platform-specific setup */ bl2_el3_plat_arch_setup(); #if CTX_INCLUDE_PAUTH_REGS /* * Assert that the ARMv8.3-PAuth registers are present or an access * fault will be triggered when they are being saved or restored. */ assert(is_armv8_3_pauth_present()); #endif /* CTX_INCLUDE_PAUTH_REGS */ } #endif /* BL2_AT_EL3 */ /******************************************************************************* * The only thing to do in BL2 is to load further images and pass control to * next BL. The memory occupied by BL2 will be reclaimed by BL3x stages. BL2 * runs entirely in S-EL1. ******************************************************************************/ void bl2_main(void) { entry_point_info_t *next_bl_ep_info; NOTICE("BL2: %s\n", version_string); NOTICE("BL2: %s\n", build_message); /* Perform remaining generic architectural setup in S-EL1 */ bl2_arch_setup(); #if TRUSTED_BOARD_BOOT /* Initialize authentication module */ auth_mod_init(); #endif /* TRUSTED_BOARD_BOOT */ /* initialize boot source */ bl2_plat_preload_setup(); /* Load the subsequent bootloader images. */ next_bl_ep_info = bl2_load_images(); #if !BL2_AT_EL3 #ifndef __aarch64__ /* * For AArch32 state BL1 and BL2 share the MMU setup. * Given that BL2 does not map BL1 regions, MMU needs * to be disabled in order to go back to BL1. */ disable_mmu_icache_secure(); #endif /* !__aarch64__ */ console_flush(); #if ENABLE_PAUTH /* * Disable pointer authentication before running next boot image */ pauth_disable_el1(); #endif /* ENABLE_PAUTH */ /* * Run next BL image via an SMC to BL1. Information on how to pass * control to the BL32 (if present) and BL33 software images will * be passed to next BL image as an argument. */ smc(BL1_SMC_RUN_IMAGE, (unsigned long)next_bl_ep_info, 0, 0, 0, 0, 0, 0); #else /* if BL2_AT_EL3 */ NOTICE("BL2: Booting " NEXT_IMAGE "\n"); print_entry_point_info(next_bl_ep_info); console_flush(); #if ENABLE_PAUTH /* * Disable pointer authentication before running next boot image */ pauth_disable_el3(); #endif /* ENABLE_PAUTH */ bl2_run_next_image(next_bl_ep_info); #endif /* BL2_AT_EL3 */ } trusted-firmware-a-2.2/bl2/bl2_private.h000066400000000000000000000011631355360272700201530ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BL2_PRIVATE_H #define BL2_PRIVATE_H #include /****************************************** * Forward declarations *****************************************/ struct entry_point_info; /****************************************** * Function prototypes *****************************************/ void bl2_arch_setup(void); struct entry_point_info *bl2_load_images(void); void bl2_run_next_image(const struct entry_point_info *bl_ep_info); #endif /* BL2_PRIVATE_H */ trusted-firmware-a-2.2/bl2u/000077500000000000000000000000001355360272700157555ustar00rootroot00000000000000trusted-firmware-a-2.2/bl2u/aarch32/000077500000000000000000000000001355360272700172005ustar00rootroot00000000000000trusted-firmware-a-2.2/bl2u/aarch32/bl2u_entrypoint.S000066400000000000000000000066621355360272700224750ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl bl2u_vector_table .globl bl2u_entrypoint vector_base bl2u_vector_table b bl2u_entrypoint b report_exception /* Undef */ b report_exception /* SVC call */ b report_exception /* Prefetch abort */ b report_exception /* Data abort */ b report_exception /* Reserved */ b report_exception /* IRQ */ b report_exception /* FIQ */ func bl2u_entrypoint /*--------------------------------------------- * Save from r1 the extents of the trusted ram * available to BL2U for future use. * r0 is not currently used. * --------------------------------------------- */ mov r11, r1 mov r10, r2 /* --------------------------------------------- * Set the exception vector to something sane. * --------------------------------------------- */ ldr r0, =bl2u_vector_table stcopr r0, VBAR isb /* -------------------------------------------------------- * Enable the instruction cache - disable speculative loads * -------------------------------------------------------- */ ldcopr r0, SCTLR orr r0, r0, #SCTLR_I_BIT bic r0, r0, #SCTLR_DSSBS_BIT stcopr r0, SCTLR isb /* --------------------------------------------- * Since BL2U executes after BL1, it is assumed * here that BL1 has already has done the * necessary register initializations. * --------------------------------------------- */ /* --------------------------------------------- * Invalidate the RW memory used by the BL2U * image. This includes the data and NOBITS * sections. This is done to safeguard against * possible corruption of this memory by dirty * cache lines in a system cache as a result of * use by an earlier boot loader stage. * --------------------------------------------- */ ldr r0, =__RW_START__ ldr r1, =__RW_END__ sub r1, r1, r0 bl inv_dcache_range /* --------------------------------------------- * Zero out NOBITS sections. There are 2 of them: * - the .bss section; * - the coherent memory section. * --------------------------------------------- */ ldr r0, =__BSS_START__ ldr r1, =__BSS_SIZE__ bl zeromem /* -------------------------------------------- * Allocate a stack whose memory will be marked * as Normal-IS-WBWA when the MMU is enabled. * There is no risk of reading stale stack * memory after enabling the MMU as only the * primary cpu is running at the moment. * -------------------------------------------- */ bl plat_set_my_stack /* --------------------------------------------- * Initialize the stack protector canary before * any C code is called. * --------------------------------------------- */ #if STACK_PROTECTOR_ENABLED bl update_stack_protector_canary #endif /* --------------------------------------------- * Perform early platform setup & platform * specific early arch. setup e.g. mmu setup * --------------------------------------------- */ mov r0, r11 mov r1, r10 bl bl2u_early_platform_setup bl bl2u_plat_arch_setup /* --------------------------------------------- * Jump to main function. * --------------------------------------------- */ bl bl2u_main /* --------------------------------------------- * Should never reach this point. * --------------------------------------------- */ no_ret plat_panic_handler endfunc bl2u_entrypoint trusted-firmware-a-2.2/bl2u/aarch64/000077500000000000000000000000001355360272700172055ustar00rootroot00000000000000trusted-firmware-a-2.2/bl2u/aarch64/bl2u_entrypoint.S000066400000000000000000000066531355360272700225020ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl bl2u_entrypoint func bl2u_entrypoint /*--------------------------------------------- * Store the extents of the tzram available to * BL2U and other platform specific information * for future use. x0 is currently not used. * --------------------------------------------- */ mov x20, x1 mov x21, x2 /* --------------------------------------------- * Set the exception vector to something sane. * --------------------------------------------- */ adr x0, early_exceptions msr vbar_el1, x0 isb /* --------------------------------------------- * Enable the SError interrupt now that the * exception vectors have been setup. * --------------------------------------------- */ msr daifclr, #DAIF_ABT_BIT /* --------------------------------------------- * Enable the instruction cache, stack pointer * and data access alignment checks and disable * speculative loads. * --------------------------------------------- */ mov x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT) mrs x0, sctlr_el1 orr x0, x0, x1 bic x0, x0, #SCTLR_DSSBS_BIT msr sctlr_el1, x0 isb /* --------------------------------------------- * Invalidate the RW memory used by the BL2U * image. This includes the data and NOBITS * sections. This is done to safeguard against * possible corruption of this memory by dirty * cache lines in a system cache as a result of * use by an earlier boot loader stage. * --------------------------------------------- */ adr x0, __RW_START__ adr x1, __RW_END__ sub x1, x1, x0 bl inv_dcache_range /* --------------------------------------------- * Zero out NOBITS sections. There are 2 of them: * - the .bss section; * - the coherent memory section. * --------------------------------------------- */ ldr x0, =__BSS_START__ ldr x1, =__BSS_SIZE__ bl zeromem /* -------------------------------------------- * Allocate a stack whose memory will be marked * as Normal-IS-WBWA when the MMU is enabled. * There is no risk of reading stale stack * memory after enabling the MMU as only the * primary cpu is running at the moment. * -------------------------------------------- */ bl plat_set_my_stack /* --------------------------------------------- * Initialize the stack protector canary before * any C code is called. * --------------------------------------------- */ #if STACK_PROTECTOR_ENABLED bl update_stack_protector_canary #endif /* --------------------------------------------- * Perform early platform setup & platform * specific early arch. setup e.g. mmu setup * --------------------------------------------- */ mov x0, x20 mov x1, x21 bl bl2u_early_platform_setup bl bl2u_plat_arch_setup #if ENABLE_PAUTH /* --------------------------------------------- * Program APIAKey_EL1 * and enable pointer authentication. * --------------------------------------------- */ bl pauth_init_enable_el1 #endif /* --------------------------------------------- * Jump to bl2u_main function. * --------------------------------------------- */ bl bl2u_main /* --------------------------------------------- * Should never reach this point. * --------------------------------------------- */ no_ret plat_panic_handler endfunc bl2u_entrypoint trusted-firmware-a-2.2/bl2u/bl2u.ld.S000066400000000000000000000074241355360272700173520ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT) OUTPUT_ARCH(PLATFORM_LINKER_ARCH) ENTRY(bl2u_entrypoint) MEMORY { RAM (rwx): ORIGIN = BL2U_BASE, LENGTH = BL2U_LIMIT - BL2U_BASE } SECTIONS { . = BL2U_BASE; ASSERT(. == ALIGN(PAGE_SIZE), "BL2U_BASE address is not aligned on a page boundary.") #if SEPARATE_CODE_AND_RODATA .text . : { __TEXT_START__ = .; *bl2u_entrypoint.o(.text*) *(.text*) *(.vectors) . = ALIGN(PAGE_SIZE); __TEXT_END__ = .; } >RAM /* .ARM.extab and .ARM.exidx are only added because Clang need them */ .ARM.extab . : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM .ARM.exidx . : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >RAM .rodata . : { __RODATA_START__ = .; *(.rodata*) . = ALIGN(PAGE_SIZE); __RODATA_END__ = .; } >RAM #else ro . : { __RO_START__ = .; *bl2u_entrypoint.o(.text*) *(.text*) *(.rodata*) *(.vectors) __RO_END_UNALIGNED__ = .; /* * Memory page(s) mapped to this section will be marked as * read-only, executable. No RW data from the next section must * creep in. Ensure the rest of the current memory page is unused. */ . = ALIGN(PAGE_SIZE); __RO_END__ = .; } >RAM #endif /* * Define a linker symbol to mark start of the RW memory area for this * image. */ __RW_START__ = . ; /* * .data must be placed at a lower address than the stacks if the stack * protector is enabled. Alternatively, the .data.stack_protector_canary * section can be placed independently of the main .data section. */ .data . : { __DATA_START__ = .; *(.data*) __DATA_END__ = .; } >RAM stacks (NOLOAD) : { __STACKS_START__ = .; *(tzfw_normal_stacks) __STACKS_END__ = .; } >RAM /* * The .bss section gets initialised to 0 at runtime. * Its base address should be 16-byte aligned for better performance of the * zero-initialization code. */ .bss : ALIGN(16) { __BSS_START__ = .; *(SORT_BY_ALIGNMENT(.bss*)) *(COMMON) __BSS_END__ = .; } >RAM /* * The xlat_table section is for full, aligned page tables (4K). * Removing them from .bss avoids forcing 4K alignment on * the .bss section. The tables are initialized to zero by the translation * tables library. */ xlat_table (NOLOAD) : { *(xlat_table) } >RAM #if USE_COHERENT_MEM /* * The base address of the coherent memory section must be page-aligned (4K) * to guarantee that the coherent data are stored on their own pages and * are not mixed with normal data. This is required to set up the correct * memory attributes for the coherent data page tables. */ coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) { __COHERENT_RAM_START__ = .; *(tzfw_coherent_mem) __COHERENT_RAM_END_UNALIGNED__ = .; /* * Memory page(s) mapped to this section will be marked * as device memory. No other unexpected data must creep in. * Ensure the rest of the current memory page is unused. */ . = ALIGN(PAGE_SIZE); __COHERENT_RAM_END__ = .; } >RAM #endif /* * Define a linker symbol to mark end of the RW memory area for this * image. */ __RW_END__ = .; __BL2U_END__ = .; __BSS_SIZE__ = SIZEOF(.bss); ASSERT(. <= BL2U_LIMIT, "BL2U image has exceeded its limit.") } trusted-firmware-a-2.2/bl2u/bl2u.mk000066400000000000000000000005521355360272700171540ustar00rootroot00000000000000# # Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # BL2U_SOURCES += bl2u/bl2u_main.c \ bl2u/${ARCH}/bl2u_entrypoint.S \ plat/common/${ARCH}/platform_up_stack.S ifeq (${ARCH},aarch64) BL2U_SOURCES += common/aarch64/early_exceptions.S endif BL2U_LINKERFILE := bl2u/bl2u.ld.S trusted-firmware-a-2.2/bl2u/bl2u_main.c000066400000000000000000000031221355360272700177670ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * This function is responsible to: * Load SCP_BL2U if platform has defined SCP_BL2U_BASE * Perform platform setup. * Go back to EL3. ******************************************************************************/ void bl2u_main(void) { NOTICE("BL2U: %s\n", version_string); NOTICE("BL2U: %s\n", build_message); #if SCP_BL2U_BASE int rc; /* Load the subsequent bootloader images */ rc = bl2u_plat_handle_scp_bl2u(); if (rc) { ERROR("Failed to load SCP_BL2U (%i)\n", rc); panic(); } #endif /* Perform platform setup in BL2U after loading SCP_BL2U */ bl2u_platform_setup(); console_flush(); #ifndef __aarch64__ /* * For AArch32 state BL1 and BL2U share the MMU setup. * Given that BL2U does not map BL1 regions, MMU needs * to be disabled in order to go back to BL1. */ disable_mmu_icache_secure(); #endif /* !__aarch64__ */ /* * Indicate that BL2U is done and resume back to * normal world via an SMC to BL1. * x1 could be passed to Normal world, * so DO NOT pass any secret information. */ smc(FWU_SMC_SEC_IMAGE_DONE, 0, 0, 0, 0, 0, 0, 0); wfi(); } trusted-firmware-a-2.2/bl31/000077500000000000000000000000001355360272700156525ustar00rootroot00000000000000trusted-firmware-a-2.2/bl31/aarch64/000077500000000000000000000000001355360272700171025ustar00rootroot00000000000000trusted-firmware-a-2.2/bl31/aarch64/bl31_entrypoint.S000066400000000000000000000166451355360272700222760ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include .globl bl31_entrypoint .globl bl31_warm_entrypoint /* ----------------------------------------------------- * bl31_entrypoint() is the cold boot entrypoint, * executed only by the primary cpu. * ----------------------------------------------------- */ func bl31_entrypoint /* --------------------------------------------------------------- * Stash the previous bootloader arguments x0 - x3 for later use. * --------------------------------------------------------------- */ mov x20, x0 mov x21, x1 mov x22, x2 mov x23, x3 /* -------------------------------------------------------------------- * If PIE is enabled, fixup the Global descriptor Table and dynamic * relocations * -------------------------------------------------------------------- */ #if ENABLE_PIE mov_imm x0, BL31_BASE mov_imm x1, BL31_LIMIT bl fixup_gdt_reloc #endif /* ENABLE_PIE */ #if !RESET_TO_BL31 /* --------------------------------------------------------------------- * For !RESET_TO_BL31 systems, only the primary CPU ever reaches * bl31_entrypoint() during the cold boot flow, so the cold/warm boot * and primary/secondary CPU logic should not be executed in this case. * * Also, assume that the previous bootloader has already initialised the * SCTLR_EL3, including the endianness, and has initialised the memory. * --------------------------------------------------------------------- */ el3_entrypoint_common \ _init_sctlr=0 \ _warm_boot_mailbox=0 \ _secondary_cold_boot=0 \ _init_memory=0 \ _init_c_runtime=1 \ _exception_vectors=runtime_exceptions #else /* --------------------------------------------------------------------- * For RESET_TO_BL31 systems which have a programmable reset address, * bl31_entrypoint() is executed only on the cold boot path so we can * skip the warm boot mailbox mechanism. * --------------------------------------------------------------------- */ el3_entrypoint_common \ _init_sctlr=1 \ _warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \ _secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \ _init_memory=1 \ _init_c_runtime=1 \ _exception_vectors=runtime_exceptions /* --------------------------------------------------------------------- * For RESET_TO_BL31 systems, BL31 is the first bootloader to run so * there's no argument to relay from a previous bootloader. Zero the * arguments passed to the platform layer to reflect that. * --------------------------------------------------------------------- */ mov x20, 0 mov x21, 0 mov x22, 0 mov x23, 0 #endif /* RESET_TO_BL31 */ /* -------------------------------------------------------------------- * Perform BL31 setup * -------------------------------------------------------------------- */ mov x0, x20 mov x1, x21 mov x2, x22 mov x3, x23 bl bl31_setup #if ENABLE_PAUTH /* -------------------------------------------------------------------- * Program APIAKey_EL1 and enable pointer authentication * -------------------------------------------------------------------- */ bl pauth_init_enable_el3 #endif /* ENABLE_PAUTH */ /* -------------------------------------------------------------------- * Jump to main function * -------------------------------------------------------------------- */ bl bl31_main /* -------------------------------------------------------------------- * Clean the .data & .bss sections to main memory. This ensures * that any global data which was initialised by the primary CPU * is visible to secondary CPUs before they enable their data * caches and participate in coherency. * -------------------------------------------------------------------- */ adr x0, __DATA_START__ adr x1, __DATA_END__ sub x1, x1, x0 bl clean_dcache_range adr x0, __BSS_START__ adr x1, __BSS_END__ sub x1, x1, x0 bl clean_dcache_range b el3_exit endfunc bl31_entrypoint /* -------------------------------------------------------------------- * This CPU has been physically powered up. It is either resuming from * suspend or has simply been turned on. In both cases, call the BL31 * warmboot entrypoint * -------------------------------------------------------------------- */ func bl31_warm_entrypoint #if ENABLE_RUNTIME_INSTRUMENTATION /* * This timestamp update happens with cache off. The next * timestamp collection will need to do cache maintenance prior * to timestamp update. */ pmf_calc_timestamp_addr rt_instr_svc, RT_INSTR_EXIT_HW_LOW_PWR mrs x1, cntpct_el0 str x1, [x0] #endif /* * On the warm boot path, most of the EL3 initialisations performed by * 'el3_entrypoint_common' must be skipped: * * - Only when the platform bypasses the BL1/BL31 entrypoint by * programming the reset address do we need to initialise SCTLR_EL3. * In other cases, we assume this has been taken care by the * entrypoint code. * * - No need to determine the type of boot, we know it is a warm boot. * * - Do not try to distinguish between primary and secondary CPUs, this * notion only exists for a cold boot. * * - No need to initialise the memory or the C runtime environment, * it has been done once and for all on the cold boot path. */ el3_entrypoint_common \ _init_sctlr=PROGRAMMABLE_RESET_ADDRESS \ _warm_boot_mailbox=0 \ _secondary_cold_boot=0 \ _init_memory=0 \ _init_c_runtime=0 \ _exception_vectors=runtime_exceptions /* * We're about to enable MMU and participate in PSCI state coordination. * * The PSCI implementation invokes platform routines that enable CPUs to * participate in coherency. On a system where CPUs are not * cache-coherent without appropriate platform specific programming, * having caches enabled until such time might lead to coherency issues * (resulting from stale data getting speculatively fetched, among * others). Therefore we keep data caches disabled even after enabling * the MMU for such platforms. * * On systems with hardware-assisted coherency, or on single cluster * platforms, such platform specific programming is not required to * enter coherency (as CPUs already are); and there's no reason to have * caches disabled either. */ #if HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY mov x0, xzr #else mov x0, #DISABLE_DCACHE #endif bl bl31_plat_enable_mmu #if ENABLE_PAUTH /* -------------------------------------------------------------------- * Program APIAKey_EL1 and enable pointer authentication * -------------------------------------------------------------------- */ bl pauth_init_enable_el3 #endif /* ENABLE_PAUTH */ bl psci_warmboot_entrypoint #if ENABLE_RUNTIME_INSTRUMENTATION pmf_calc_timestamp_addr rt_instr_svc, RT_INSTR_EXIT_PSCI mov x19, x0 /* * Invalidate before updating timestamp to ensure previous timestamp * updates on the same cache line with caches disabled are properly * seen by the same core. Without the cache invalidate, the core might * write into a stale cache line. */ mov x1, #PMF_TS_SIZE mov x20, x30 bl inv_dcache_range mov x30, x20 mrs x0, cntpct_el0 str x0, [x19] #endif b el3_exit endfunc bl31_warm_entrypoint trusted-firmware-a-2.2/bl31/aarch64/crash_reporting.S000066400000000000000000000246641355360272700224330ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include .globl report_unhandled_exception .globl report_unhandled_interrupt .globl el3_panic #if CRASH_REPORTING /* ------------------------------------------------------ * The below section deals with dumping the system state * when an unhandled exception is taken in EL3. * The layout and the names of the registers which will * be dumped during a unhandled exception is given below. * ------------------------------------------------------ */ .section .rodata.crash_prints, "aS" print_spacer: .asciz " = 0x" gp_regs: .asciz "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",\ "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",\ "x16", "x17", "x18", "x19", "x20", "x21", "x22",\ "x23", "x24", "x25", "x26", "x27", "x28", "x29", "" el3_sys_regs: .asciz "scr_el3", "sctlr_el3", "cptr_el3", "tcr_el3",\ "daif", "mair_el3", "spsr_el3", "elr_el3", "ttbr0_el3",\ "esr_el3", "far_el3", "" non_el3_sys_regs: .asciz "spsr_el1", "elr_el1", "spsr_abt", "spsr_und",\ "spsr_irq", "spsr_fiq", "sctlr_el1", "actlr_el1", "cpacr_el1",\ "csselr_el1", "sp_el1", "esr_el1", "ttbr0_el1", "ttbr1_el1",\ "mair_el1", "amair_el1", "tcr_el1", "tpidr_el1", "tpidr_el0",\ "tpidrro_el0", "par_el1", "mpidr_el1", "afsr0_el1", "afsr1_el1",\ "contextidr_el1", "vbar_el1", "cntp_ctl_el0", "cntp_cval_el0",\ "cntv_ctl_el0", "cntv_cval_el0", "cntkctl_el1", "sp_el0", "isr_el1", "" #if CTX_INCLUDE_AARCH32_REGS aarch32_regs: .asciz "dacr32_el2", "ifsr32_el2", "" #endif /* CTX_INCLUDE_AARCH32_REGS */ panic_msg: .asciz "PANIC in EL3.\nx30" excpt_msg: .asciz "Unhandled Exception in EL3.\nx30" intr_excpt_msg: .asciz "Unhandled Interrupt Exception in EL3.\nx30" /* * Helper function to print from crash buf. * The print loop is controlled by the buf size and * ascii reg name list which is passed in x6. The * function returns the crash buf address in x0. * Clobbers : x0 - x7, sp */ func size_controlled_print /* Save the lr */ mov sp, x30 /* load the crash buf address */ mrs x7, tpidr_el3 test_size_list: /* Calculate x5 always as it will be clobbered by asm_print_hex */ mrs x5, tpidr_el3 add x5, x5, #CPU_DATA_CRASH_BUF_SIZE /* Test whether we have reached end of crash buf */ cmp x7, x5 b.eq exit_size_print ldrb w4, [x6] /* Test whether we are at end of list */ cbz w4, exit_size_print mov x4, x6 /* asm_print_str updates x4 to point to next entry in list */ bl asm_print_str /* x0 = number of symbols printed + 1 */ sub x0, x4, x6 /* update x6 with the updated list pointer */ mov x6, x4 bl print_alignment ldr x4, [x7], #REGSZ bl asm_print_hex bl asm_print_newline b test_size_list exit_size_print: mov x30, sp ret endfunc size_controlled_print /* ----------------------------------------------------- * This function calculates and prints required number * of space characters followed by "= 0x", based on the * length of ascii register name. * x0: length of ascii register name + 1 * ------------------------------------------------------ */ func print_alignment /* The minimum ascii length is 3, e.g. for "x0" */ adr x4, print_spacer - 3 add x4, x4, x0 b asm_print_str endfunc print_alignment /* * Helper function to store x8 - x15 registers to * the crash buf. The system registers values are * copied to x8 to x15 by the caller which are then * copied to the crash buf by this function. * x0 points to the crash buf. It then calls * size_controlled_print to print to console. * Clobbers : x0 - x7, sp */ func str_in_crash_buf_print /* restore the crash buf address in x0 */ mrs x0, tpidr_el3 stp x8, x9, [x0] stp x10, x11, [x0, #REGSZ * 2] stp x12, x13, [x0, #REGSZ * 4] stp x14, x15, [x0, #REGSZ * 6] b size_controlled_print endfunc str_in_crash_buf_print /* ------------------------------------------------------ * This macro calculates the offset to crash buf from * cpu_data and stores it in tpidr_el3. It also saves x0 * and x1 in the crash buf by using sp as a temporary * register. * ------------------------------------------------------ */ .macro prepare_crash_buf_save_x0_x1 /* we can corrupt this reg to free up x0 */ mov sp, x0 /* tpidr_el3 contains the address to cpu_data structure */ mrs x0, tpidr_el3 /* Calculate the Crash buffer offset in cpu_data */ add x0, x0, #CPU_DATA_CRASH_BUF_OFFSET /* Store crash buffer address in tpidr_el3 */ msr tpidr_el3, x0 str x1, [x0, #REGSZ] mov x1, sp str x1, [x0] .endm /* ----------------------------------------------------- * This function allows to report a crash (if crash * reporting is enabled) when an unhandled exception * occurs. It prints the CPU state via the crash console * making use of the crash buf. This function will * not return. * ----------------------------------------------------- */ func report_unhandled_exception prepare_crash_buf_save_x0_x1 adr x0, excpt_msg mov sp, x0 /* This call will not return */ b do_crash_reporting endfunc report_unhandled_exception /* ----------------------------------------------------- * This function allows to report a crash (if crash * reporting is enabled) when an unhandled interrupt * occurs. It prints the CPU state via the crash console * making use of the crash buf. This function will * not return. * ----------------------------------------------------- */ func report_unhandled_interrupt prepare_crash_buf_save_x0_x1 adr x0, intr_excpt_msg mov sp, x0 /* This call will not return */ b do_crash_reporting endfunc report_unhandled_interrupt /* ----------------------------------------------------- * This function allows to report a crash (if crash * reporting is enabled) when panic() is invoked from * C Runtime. It prints the CPU state via the crash * console making use of the crash buf. This function * will not return. * ----------------------------------------------------- */ func el3_panic msr spsel, #MODE_SP_ELX prepare_crash_buf_save_x0_x1 adr x0, panic_msg mov sp, x0 /* This call will not return */ b do_crash_reporting endfunc el3_panic /* ------------------------------------------------------------ * The common crash reporting functionality. It requires x0 * and x1 has already been stored in crash buf, sp points to * crash message and tpidr_el3 contains the crash buf address. * The function does the following: * - Retrieve the crash buffer from tpidr_el3 * - Store x2 to x6 in the crash buffer * - Initialise the crash console. * - Print the crash message by using the address in sp. * - Print x30 value to the crash console. * - Print x0 - x7 from the crash buf to the crash console. * - Print x8 - x29 (in groups of 8 registers) using the * crash buf to the crash console. * - Print el3 sys regs (in groups of 8 registers) using the * crash buf to the crash console. * - Print non el3 sys regs (in groups of 8 registers) using * the crash buf to the crash console. * ------------------------------------------------------------ */ func do_crash_reporting /* Retrieve the crash buf from tpidr_el3 */ mrs x0, tpidr_el3 /* Store x2 - x6, x30 in the crash buffer */ stp x2, x3, [x0, #REGSZ * 2] stp x4, x5, [x0, #REGSZ * 4] stp x6, x30, [x0, #REGSZ * 6] /* Initialize the crash console */ bl plat_crash_console_init /* Verify the console is initialized */ cbz x0, crash_panic /* Print the crash message. sp points to the crash message */ mov x4, sp bl asm_print_str /* Print spaces to align "x30" string */ mov x0, #4 bl print_alignment /* load the crash buf address */ mrs x0, tpidr_el3 /* report x30 first from the crash buf */ ldr x4, [x0, #REGSZ * 7] bl asm_print_hex bl asm_print_newline /* Load the crash buf address */ mrs x0, tpidr_el3 /* Now mov x7 into crash buf */ str x7, [x0, #REGSZ * 7] /* Report x0 - x29 values stored in crash buf*/ /* Store the ascii list pointer in x6 */ adr x6, gp_regs /* Print x0 to x7 from the crash buf */ bl size_controlled_print /* Store x8 - x15 in crash buf and print */ bl str_in_crash_buf_print /* Load the crash buf address */ mrs x0, tpidr_el3 /* Store the rest of gp regs and print */ stp x16, x17, [x0] stp x18, x19, [x0, #REGSZ * 2] stp x20, x21, [x0, #REGSZ * 4] stp x22, x23, [x0, #REGSZ * 6] bl size_controlled_print /* Load the crash buf address */ mrs x0, tpidr_el3 stp x24, x25, [x0] stp x26, x27, [x0, #REGSZ * 2] stp x28, x29, [x0, #REGSZ * 4] bl size_controlled_print /* Print the el3 sys registers */ adr x6, el3_sys_regs mrs x8, scr_el3 mrs x9, sctlr_el3 mrs x10, cptr_el3 mrs x11, tcr_el3 mrs x12, daif mrs x13, mair_el3 mrs x14, spsr_el3 mrs x15, elr_el3 bl str_in_crash_buf_print mrs x8, ttbr0_el3 mrs x9, esr_el3 mrs x10, far_el3 bl str_in_crash_buf_print /* Print the non el3 sys registers */ adr x6, non_el3_sys_regs mrs x8, spsr_el1 mrs x9, elr_el1 mrs x10, spsr_abt mrs x11, spsr_und mrs x12, spsr_irq mrs x13, spsr_fiq mrs x14, sctlr_el1 mrs x15, actlr_el1 bl str_in_crash_buf_print mrs x8, cpacr_el1 mrs x9, csselr_el1 mrs x10, sp_el1 mrs x11, esr_el1 mrs x12, ttbr0_el1 mrs x13, ttbr1_el1 mrs x14, mair_el1 mrs x15, amair_el1 bl str_in_crash_buf_print mrs x8, tcr_el1 mrs x9, tpidr_el1 mrs x10, tpidr_el0 mrs x11, tpidrro_el0 mrs x12, par_el1 mrs x13, mpidr_el1 mrs x14, afsr0_el1 mrs x15, afsr1_el1 bl str_in_crash_buf_print mrs x8, contextidr_el1 mrs x9, vbar_el1 mrs x10, cntp_ctl_el0 mrs x11, cntp_cval_el0 mrs x12, cntv_ctl_el0 mrs x13, cntv_cval_el0 mrs x14, cntkctl_el1 mrs x15, sp_el0 bl str_in_crash_buf_print mrs x8, isr_el1 bl str_in_crash_buf_print #if CTX_INCLUDE_AARCH32_REGS /* Print the AArch32 registers */ adr x6, aarch32_regs mrs x8, dacr32_el2 mrs x9, ifsr32_el2 bl str_in_crash_buf_print #endif /* CTX_INCLUDE_AARCH32_REGS */ /* Get the cpu specific registers to report */ bl do_cpu_reg_dump bl str_in_crash_buf_print /* Print some platform registers */ plat_crash_print_regs bl plat_crash_console_flush /* Done reporting */ no_ret plat_panic_handler endfunc do_crash_reporting #else /* CRASH_REPORTING */ func report_unhandled_exception report_unhandled_interrupt: no_ret plat_panic_handler endfunc report_unhandled_exception #endif /* CRASH_REPORTING */ func crash_panic no_ret plat_panic_handler endfunc crash_panic trusted-firmware-a-2.2/bl31/aarch64/ea_delegate.S000066400000000000000000000172771355360272700214630ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include .globl handle_lower_el_ea_esb .globl enter_lower_el_sync_ea .globl enter_lower_el_async_ea /* * Function to delegate External Aborts synchronized by ESB instruction at EL3 * vector entry. This function assumes GP registers x0-x29 have been saved, and * are available for use. It delegates the handling of the EA to platform * handler, and returns only upon successfully handling the EA; otherwise * panics. On return from this function, the original exception handler is * expected to resume. */ func handle_lower_el_ea_esb mov x0, #ERROR_EA_ESB mrs x1, DISR_EL1 b ea_proceed endfunc handle_lower_el_ea_esb /* * This function forms the tail end of Synchronous Exception entry from lower * EL, and expects to handle Synchronous External Aborts from lower EL and CPU * Implementation Defined Exceptions. If any other kind of exception is detected, * then this function reports unhandled exception. * * Since it's part of exception vector, this function doesn't expect any GP * registers to have been saved. It delegates the handling of the EA to platform * handler, and upon successfully handling the EA, exits EL3; otherwise panics. */ func enter_lower_el_sync_ea /* * Explicitly save x30 so as to free up a register and to enable * branching. */ str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] mrs x30, esr_el3 ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH /* Check for I/D aborts from lower EL */ cmp x30, #EC_IABORT_LOWER_EL b.eq 1f cmp x30, #EC_DABORT_LOWER_EL b.eq 1f /* Save GP registers */ stp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] stp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] stp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4] /* Get the cpu_ops pointer */ bl get_cpu_ops_ptr /* Get the cpu_ops exception handler */ ldr x0, [x0, #CPU_E_HANDLER_FUNC] /* * If the reserved function pointer is NULL, this CPU does not have an * implementation defined exception handler function */ cbz x0, 2f mrs x1, esr_el3 ubfx x1, x1, #ESR_EC_SHIFT, #ESR_EC_LENGTH blr x0 b 2f 1: /* Test for EA bit in the instruction syndrome */ mrs x30, esr_el3 tbz x30, #ESR_ISS_EABORT_EA_BIT, 3f /* * Save general purpose and ARMv8.3-PAuth registers (if enabled). * If Secure Cycle Counter is not disabled in MDCR_EL3 when * ARMv8.5-PMU is implemented, save PMCR_EL0 and disable Cycle Counter. */ bl save_gp_pmcr_pauth_regs #if ENABLE_PAUTH /* Load and program APIAKey firmware key */ bl pauth_load_bl31_apiakey #endif /* Setup exception class and syndrome arguments for platform handler */ mov x0, #ERROR_EA_SYNC mrs x1, esr_el3 adr x30, el3_exit b delegate_sync_ea 2: ldp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] ldp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4] 3: /* Synchronous exceptions other than the above are assumed to be EA */ ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] no_ret report_unhandled_exception endfunc enter_lower_el_sync_ea /* * This function handles SErrors from lower ELs. * * Since it's part of exception vector, this function doesn't expect any GP * registers to have been saved. It delegates the handling of the EA to platform * handler, and upon successfully handling the EA, exits EL3; otherwise panics. */ func enter_lower_el_async_ea /* * Explicitly save x30 so as to free up a register and to enable * branching */ str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] /* * Save general purpose and ARMv8.3-PAuth registers (if enabled). * If Secure Cycle Counter is not disabled in MDCR_EL3 when * ARMv8.5-PMU is implemented, save PMCR_EL0 and disable Cycle Counter. */ bl save_gp_pmcr_pauth_regs #if ENABLE_PAUTH /* Load and program APIAKey firmware key */ bl pauth_load_bl31_apiakey #endif /* Setup exception class and syndrome arguments for platform handler */ mov x0, #ERROR_EA_ASYNC mrs x1, esr_el3 adr x30, el3_exit b delegate_async_ea endfunc enter_lower_el_async_ea /* * Prelude for Synchronous External Abort handling. This function assumes that * all GP registers have been saved by the caller. * * x0: EA reason * x1: EA syndrome */ func delegate_sync_ea #if RAS_EXTENSION /* * Check for Uncontainable error type. If so, route to the platform * fatal error handler rather than the generic EA one. */ ubfx x2, x1, #EABORT_SET_SHIFT, #EABORT_SET_WIDTH cmp x2, #ERROR_STATUS_SET_UC b.ne 1f /* Check fault status code */ ubfx x3, x1, #EABORT_DFSC_SHIFT, #EABORT_DFSC_WIDTH cmp x3, #SYNC_EA_FSC b.ne 1f no_ret plat_handle_uncontainable_ea 1: #endif b ea_proceed endfunc delegate_sync_ea /* * Prelude for Asynchronous External Abort handling. This function assumes that * all GP registers have been saved by the caller. * * x0: EA reason * x1: EA syndrome */ func delegate_async_ea #if RAS_EXTENSION /* * Check for Implementation Defined Syndrome. If so, skip checking * Uncontainable error type from the syndrome as the format is unknown. */ tbnz x1, #SERROR_IDS_BIT, 1f /* * Check for Uncontainable error type. If so, route to the platform * fatal error handler rather than the generic EA one. */ ubfx x2, x1, #EABORT_AET_SHIFT, #EABORT_AET_WIDTH cmp x2, #ERROR_STATUS_UET_UC b.ne 1f /* Check DFSC for SError type */ ubfx x3, x1, #EABORT_DFSC_SHIFT, #EABORT_DFSC_WIDTH cmp x3, #DFSC_SERROR b.ne 1f no_ret plat_handle_uncontainable_ea 1: #endif b ea_proceed endfunc delegate_async_ea /* * Delegate External Abort handling to platform's EA handler. This function * assumes that all GP registers have been saved by the caller. * * x0: EA reason * x1: EA syndrome */ func ea_proceed /* * If the ESR loaded earlier is not zero, we were processing an EA * already, and this is a double fault. */ ldr x5, [sp, #CTX_EL3STATE_OFFSET + CTX_ESR_EL3] cbz x5, 1f no_ret plat_handle_double_fault 1: /* Save EL3 state */ mrs x2, spsr_el3 mrs x3, elr_el3 stp x2, x3, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3] /* * Save ESR as handling might involve lower ELs, and returning back to * EL3 from there would trample the original ESR. */ mrs x4, scr_el3 mrs x5, esr_el3 stp x4, x5, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3] /* * Setup rest of arguments, and call platform External Abort handler. * * x0: EA reason (already in place) * x1: Exception syndrome (already in place). * x2: Cookie (unused for now). * x3: Context pointer. * x4: Flags (security state from SCR for now). */ mov x2, xzr mov x3, sp ubfx x4, x4, #0, #1 /* Switch to runtime stack */ ldr x5, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP] msr spsel, #MODE_SP_EL0 mov sp, x5 mov x29, x30 #if ENABLE_ASSERTIONS /* Stash the stack pointer */ mov x28, sp #endif bl plat_ea_handler #if ENABLE_ASSERTIONS /* * Error handling flows might involve long jumps; so upon returning from * the platform error handler, validate that the we've completely * unwound the stack. */ mov x27, sp cmp x28, x27 ASM_ASSERT(eq) #endif /* Make SP point to context */ msr spsel, #MODE_SP_ELX /* Restore EL3 state and ESR */ ldp x1, x2, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3] msr spsr_el3, x1 msr elr_el3, x2 /* Restore ESR_EL3 and SCR_EL3 */ ldp x3, x4, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3] msr scr_el3, x3 msr esr_el3, x4 #if ENABLE_ASSERTIONS cmp x4, xzr ASM_ASSERT(ne) #endif /* Clear ESR storage */ str xzr, [sp, #CTX_EL3STATE_OFFSET + CTX_ESR_EL3] ret x29 endfunc ea_proceed trusted-firmware-a-2.2/bl31/aarch64/runtime_exceptions.S000066400000000000000000000334041355360272700231560ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include .globl runtime_exceptions .globl sync_exception_sp_el0 .globl irq_sp_el0 .globl fiq_sp_el0 .globl serror_sp_el0 .globl sync_exception_sp_elx .globl irq_sp_elx .globl fiq_sp_elx .globl serror_sp_elx .globl sync_exception_aarch64 .globl irq_aarch64 .globl fiq_aarch64 .globl serror_aarch64 .globl sync_exception_aarch32 .globl irq_aarch32 .globl fiq_aarch32 .globl serror_aarch32 /* * Macro that prepares entry to EL3 upon taking an exception. * * With RAS_EXTENSION, this macro synchronizes pending errors with an ESB * instruction. When an error is thus synchronized, the handling is * delegated to platform EA handler. * * Without RAS_EXTENSION, this macro just saves x30, and unmasks * Asynchronous External Aborts. */ .macro check_and_unmask_ea #if RAS_EXTENSION /* Synchronize pending External Aborts */ esb /* Unmask the SError interrupt */ msr daifclr, #DAIF_ABT_BIT /* * Explicitly save x30 so as to free up a register and to enable * branching */ str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] /* Check for SErrors synchronized by the ESB instruction */ mrs x30, DISR_EL1 tbz x30, #DISR_A_BIT, 1f /* * Save general purpose and ARMv8.3-PAuth registers (if enabled). * If Secure Cycle Counter is not disabled in MDCR_EL3 when * ARMv8.5-PMU is implemented, save PMCR_EL0 and disable Cycle Counter. */ bl save_gp_pmcr_pauth_regs bl handle_lower_el_ea_esb /* Restore general purpose, PMCR_EL0 and ARMv8.3-PAuth registers */ bl restore_gp_pmcr_pauth_regs 1: #else /* Unmask the SError interrupt */ msr daifclr, #DAIF_ABT_BIT str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] #endif .endm /* --------------------------------------------------------------------- * This macro handles Synchronous exceptions. * Only SMC exceptions are supported. * --------------------------------------------------------------------- */ .macro handle_sync_exception #if ENABLE_RUNTIME_INSTRUMENTATION /* * Read the timestamp value and store it in per-cpu data. The value * will be extracted from per-cpu data by the C level SMC handler and * saved to the PMF timestamp region. */ mrs x30, cntpct_el0 str x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29] mrs x29, tpidr_el3 str x30, [x29, #CPU_DATA_PMF_TS0_OFFSET] ldr x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29] #endif mrs x30, esr_el3 ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH /* Handle SMC exceptions separately from other synchronous exceptions */ cmp x30, #EC_AARCH32_SMC b.eq smc_handler32 cmp x30, #EC_AARCH64_SMC b.eq smc_handler64 /* Synchronous exceptions other than the above are assumed to be EA */ ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] b enter_lower_el_sync_ea .endm /* --------------------------------------------------------------------- * This macro handles FIQ or IRQ interrupts i.e. EL3, S-EL1 and NS * interrupts. * --------------------------------------------------------------------- */ .macro handle_interrupt_exception label /* * Save general purpose and ARMv8.3-PAuth registers (if enabled). * If Secure Cycle Counter is not disabled in MDCR_EL3 when * ARMv8.5-PMU is implemented, save PMCR_EL0 and disable Cycle Counter. */ bl save_gp_pmcr_pauth_regs #if ENABLE_PAUTH /* Load and program APIAKey firmware key */ bl pauth_load_bl31_apiakey #endif /* Save the EL3 system registers needed to return from this exception */ mrs x0, spsr_el3 mrs x1, elr_el3 stp x0, x1, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3] /* Switch to the runtime stack i.e. SP_EL0 */ ldr x2, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP] mov x20, sp msr spsel, #MODE_SP_EL0 mov sp, x2 /* * Find out whether this is a valid interrupt type. * If the interrupt controller reports a spurious interrupt then return * to where we came from. */ bl plat_ic_get_pending_interrupt_type cmp x0, #INTR_TYPE_INVAL b.eq interrupt_exit_\label /* * Get the registered handler for this interrupt type. * A NULL return value could be 'cause of the following conditions: * * a. An interrupt of a type was routed correctly but a handler for its * type was not registered. * * b. An interrupt of a type was not routed correctly so a handler for * its type was not registered. * * c. An interrupt of a type was routed correctly to EL3, but was * deasserted before its pending state could be read. Another * interrupt of a different type pended at the same time and its * type was reported as pending instead. However, a handler for this * type was not registered. * * a. and b. can only happen due to a programming error. The * occurrence of c. could be beyond the control of Trusted Firmware. * It makes sense to return from this exception instead of reporting an * error. */ bl get_interrupt_type_handler cbz x0, interrupt_exit_\label mov x21, x0 mov x0, #INTR_ID_UNAVAILABLE /* Set the current security state in the 'flags' parameter */ mrs x2, scr_el3 ubfx x1, x2, #0, #1 /* Restore the reference to the 'handle' i.e. SP_EL3 */ mov x2, x20 /* x3 will point to a cookie (not used now) */ mov x3, xzr /* Call the interrupt type handler */ blr x21 interrupt_exit_\label: /* Return from exception, possibly in a different security state */ b el3_exit .endm vector_base runtime_exceptions /* --------------------------------------------------------------------- * Current EL with SP_EL0 : 0x0 - 0x200 * --------------------------------------------------------------------- */ vector_entry sync_exception_sp_el0 #ifdef MONITOR_TRAPS stp x29, x30, [sp, #-16]! mrs x30, esr_el3 ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH /* Check for BRK */ cmp x30, #EC_BRK b.eq brk_handler ldp x29, x30, [sp], #16 #endif /* MONITOR_TRAPS */ /* We don't expect any synchronous exceptions from EL3 */ b report_unhandled_exception end_vector_entry sync_exception_sp_el0 vector_entry irq_sp_el0 /* * EL3 code is non-reentrant. Any asynchronous exception is a serious * error. Loop infinitely. */ b report_unhandled_interrupt end_vector_entry irq_sp_el0 vector_entry fiq_sp_el0 b report_unhandled_interrupt end_vector_entry fiq_sp_el0 vector_entry serror_sp_el0 no_ret plat_handle_el3_ea end_vector_entry serror_sp_el0 /* --------------------------------------------------------------------- * Current EL with SP_ELx: 0x200 - 0x400 * --------------------------------------------------------------------- */ vector_entry sync_exception_sp_elx /* * This exception will trigger if anything went wrong during a previous * exception entry or exit or while handling an earlier unexpected * synchronous exception. There is a high probability that SP_EL3 is * corrupted. */ b report_unhandled_exception end_vector_entry sync_exception_sp_elx vector_entry irq_sp_elx b report_unhandled_interrupt end_vector_entry irq_sp_elx vector_entry fiq_sp_elx b report_unhandled_interrupt end_vector_entry fiq_sp_elx vector_entry serror_sp_elx no_ret plat_handle_el3_ea end_vector_entry serror_sp_elx /* --------------------------------------------------------------------- * Lower EL using AArch64 : 0x400 - 0x600 * --------------------------------------------------------------------- */ vector_entry sync_exception_aarch64 /* * This exception vector will be the entry point for SMCs and traps * that are unhandled at lower ELs most commonly. SP_EL3 should point * to a valid cpu context where the general purpose and system register * state can be saved. */ check_and_unmask_ea handle_sync_exception end_vector_entry sync_exception_aarch64 vector_entry irq_aarch64 check_and_unmask_ea handle_interrupt_exception irq_aarch64 end_vector_entry irq_aarch64 vector_entry fiq_aarch64 check_and_unmask_ea handle_interrupt_exception fiq_aarch64 end_vector_entry fiq_aarch64 vector_entry serror_aarch64 msr daifclr, #DAIF_ABT_BIT b enter_lower_el_async_ea end_vector_entry serror_aarch64 /* --------------------------------------------------------------------- * Lower EL using AArch32 : 0x600 - 0x800 * --------------------------------------------------------------------- */ vector_entry sync_exception_aarch32 /* * This exception vector will be the entry point for SMCs and traps * that are unhandled at lower ELs most commonly. SP_EL3 should point * to a valid cpu context where the general purpose and system register * state can be saved. */ check_and_unmask_ea handle_sync_exception end_vector_entry sync_exception_aarch32 vector_entry irq_aarch32 check_and_unmask_ea handle_interrupt_exception irq_aarch32 end_vector_entry irq_aarch32 vector_entry fiq_aarch32 check_and_unmask_ea handle_interrupt_exception fiq_aarch32 end_vector_entry fiq_aarch32 vector_entry serror_aarch32 msr daifclr, #DAIF_ABT_BIT b enter_lower_el_async_ea end_vector_entry serror_aarch32 #ifdef MONITOR_TRAPS .section .rodata.brk_string, "aS" brk_location: .asciz "Error at instruction 0x" brk_message: .asciz "Unexpected BRK instruction with value 0x" #endif /* MONITOR_TRAPS */ /* --------------------------------------------------------------------- * The following code handles secure monitor calls. * Depending upon the execution state from where the SMC has been * invoked, it frees some general purpose registers to perform the * remaining tasks. They involve finding the runtime service handler * that is the target of the SMC & switching to runtime stacks (SP_EL0) * before calling the handler. * * Note that x30 has been explicitly saved and can be used here * --------------------------------------------------------------------- */ func smc_handler smc_handler32: /* Check whether aarch32 issued an SMC64 */ tbnz x0, #FUNCID_CC_SHIFT, smc_prohibited smc_handler64: /* NOTE: The code below must preserve x0-x4 */ /* * Save general purpose and ARMv8.3-PAuth registers (if enabled). * If Secure Cycle Counter is not disabled in MDCR_EL3 when * ARMv8.5-PMU is implemented, save PMCR_EL0 and disable Cycle Counter. */ bl save_gp_pmcr_pauth_regs #if ENABLE_PAUTH /* Load and program APIAKey firmware key */ bl pauth_load_bl31_apiakey #endif /* * Populate the parameters for the SMC handler. * We already have x0-x4 in place. x5 will point to a cookie (not used * now). x6 will point to the context structure (SP_EL3) and x7 will * contain flags we need to pass to the handler. */ mov x5, xzr mov x6, sp /* * Restore the saved C runtime stack value which will become the new * SP_EL0 i.e. EL3 runtime stack. It was saved in the 'cpu_context' * structure prior to the last ERET from EL3. */ ldr x12, [x6, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP] /* Switch to SP_EL0 */ msr spsel, #MODE_SP_EL0 /* * Save the SPSR_EL3, ELR_EL3, & SCR_EL3 in case there is a world * switch during SMC handling. * TODO: Revisit if all system registers can be saved later. */ mrs x16, spsr_el3 mrs x17, elr_el3 mrs x18, scr_el3 stp x16, x17, [x6, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3] str x18, [x6, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3] /* Copy SCR_EL3.NS bit to the flag to indicate caller's security */ bfi x7, x18, #0, #1 mov sp, x12 /* Get the unique owning entity number */ ubfx x16, x0, #FUNCID_OEN_SHIFT, #FUNCID_OEN_WIDTH ubfx x15, x0, #FUNCID_TYPE_SHIFT, #FUNCID_TYPE_WIDTH orr x16, x16, x15, lsl #FUNCID_OEN_WIDTH /* Load descriptor index from array of indices */ adr x14, rt_svc_descs_indices ldrb w15, [x14, x16] /* Any index greater than 127 is invalid. Check bit 7. */ tbnz w15, 7, smc_unknown /* * Get the descriptor using the index * x11 = (base + off), w15 = index * * handler = (base + off) + (index << log2(size)) */ adr x11, (__RT_SVC_DESCS_START__ + RT_SVC_DESC_HANDLE) lsl w10, w15, #RT_SVC_SIZE_LOG2 ldr x15, [x11, w10, uxtw] /* * Call the Secure Monitor Call handler and then drop directly into * el3_exit() which will program any remaining architectural state * prior to issuing the ERET to the desired lower EL. */ #if DEBUG cbz x15, rt_svc_fw_critical_error #endif blr x15 b el3_exit smc_unknown: /* * Unknown SMC call. Populate return value with SMC_UNK and call * el3_exit() which will restore the remaining architectural state * i.e., SYS, GP and PAuth registers(if any) prior to issuing the ERET * to the desired lower EL. */ mov x0, #SMC_UNK str x0, [x6, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] b el3_exit smc_prohibited: ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] mov x0, #SMC_UNK eret #if DEBUG rt_svc_fw_critical_error: /* Switch to SP_ELx */ msr spsel, #MODE_SP_ELX no_ret report_unhandled_exception #endif endfunc smc_handler /* --------------------------------------------------------------------- * The following code handles exceptions caused by BRK instructions. * Following a BRK instruction, the only real valid cause of action is * to print some information and panic, as the code that caused it is * likely in an inconsistent internal state. * * This is initially intended to be used in conjunction with * __builtin_trap. * --------------------------------------------------------------------- */ #ifdef MONITOR_TRAPS func brk_handler /* Extract the ISS */ mrs x10, esr_el3 ubfx x10, x10, #ESR_ISS_SHIFT, #ESR_ISS_LENGTH /* Ensure the console is initialized */ bl plat_crash_console_init adr x4, brk_location bl asm_print_str mrs x4, elr_el3 bl asm_print_hex bl asm_print_newline adr x4, brk_message bl asm_print_str mov x4, x10 mov x5, #28 bl asm_print_hex_bits bl asm_print_newline no_ret plat_panic_handler endfunc brk_handler #endif /* MONITOR_TRAPS */ trusted-firmware-a-2.2/bl31/bl31.ld.S000066400000000000000000000225031355360272700171370ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT) OUTPUT_ARCH(PLATFORM_LINKER_ARCH) ENTRY(bl31_entrypoint) MEMORY { RAM (rwx): ORIGIN = BL31_BASE, LENGTH = BL31_LIMIT - BL31_BASE } #ifdef PLAT_EXTRA_LD_SCRIPT #include #endif SECTIONS { . = BL31_BASE; ASSERT(. == ALIGN(PAGE_SIZE), "BL31_BASE address is not aligned on a page boundary.") __BL31_START__ = .; #if SEPARATE_CODE_AND_RODATA .text . : { __TEXT_START__ = .; *bl31_entrypoint.o(.text*) *(.text*) *(.vectors) . = ALIGN(PAGE_SIZE); __TEXT_END__ = .; } >RAM .rodata . : { __RODATA_START__ = .; *(.rodata*) /* Ensure 8-byte alignment for descriptors and ensure inclusion */ . = ALIGN(8); __RT_SVC_DESCS_START__ = .; KEEP(*(rt_svc_descs)) __RT_SVC_DESCS_END__ = .; #if ENABLE_PMF /* Ensure 8-byte alignment for descriptors and ensure inclusion */ . = ALIGN(8); __PMF_SVC_DESCS_START__ = .; KEEP(*(pmf_svc_descs)) __PMF_SVC_DESCS_END__ = .; #endif /* ENABLE_PMF */ /* * Ensure 8-byte alignment for cpu_ops so that its fields are also * aligned. Also ensure cpu_ops inclusion. */ . = ALIGN(8); __CPU_OPS_START__ = .; KEEP(*(cpu_ops)) __CPU_OPS_END__ = .; /* * Keep the .got section in the RO section as it is patched * prior to enabling the MMU and having the .got in RO is better for * security. GOT is a table of addresses so ensure 8-byte alignment. */ . = ALIGN(8); __GOT_START__ = .; *(.got) __GOT_END__ = .; /* Place pubsub sections for events */ . = ALIGN(8); #include . = ALIGN(PAGE_SIZE); __RODATA_END__ = .; } >RAM #else ro . : { __RO_START__ = .; *bl31_entrypoint.o(.text*) *(.text*) *(.rodata*) /* Ensure 8-byte alignment for descriptors and ensure inclusion */ . = ALIGN(8); __RT_SVC_DESCS_START__ = .; KEEP(*(rt_svc_descs)) __RT_SVC_DESCS_END__ = .; #if ENABLE_PMF /* Ensure 8-byte alignment for descriptors and ensure inclusion */ . = ALIGN(8); __PMF_SVC_DESCS_START__ = .; KEEP(*(pmf_svc_descs)) __PMF_SVC_DESCS_END__ = .; #endif /* ENABLE_PMF */ /* * Ensure 8-byte alignment for cpu_ops so that its fields are also * aligned. Also ensure cpu_ops inclusion. */ . = ALIGN(8); __CPU_OPS_START__ = .; KEEP(*(cpu_ops)) __CPU_OPS_END__ = .; /* * Keep the .got section in the RO section as it is patched * prior to enabling the MMU and having the .got in RO is better for * security. GOT is a table of addresses so ensure 8-byte alignment. */ . = ALIGN(8); __GOT_START__ = .; *(.got) __GOT_END__ = .; /* Place pubsub sections for events */ . = ALIGN(8); #include *(.vectors) __RO_END_UNALIGNED__ = .; /* * Memory page(s) mapped to this section will be marked as read-only, * executable. No RW data from the next section must creep in. * Ensure the rest of the current memory page is unused. */ . = ALIGN(PAGE_SIZE); __RO_END__ = .; } >RAM #endif ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__, "cpu_ops not defined for this platform.") #if ENABLE_SPM #ifndef SPM_SHIM_EXCEPTIONS_VMA #define SPM_SHIM_EXCEPTIONS_VMA RAM #endif /* * Exception vectors of the SPM shim layer. They must be aligned to a 2K * address, but we need to place them in a separate page so that we can set * individual permissions to them, so the actual alignment needed is 4K. * * There's no need to include this into the RO section of BL31 because it * doesn't need to be accessed by BL31. */ spm_shim_exceptions : ALIGN(PAGE_SIZE) { __SPM_SHIM_EXCEPTIONS_START__ = .; *(.spm_shim_exceptions) . = ALIGN(PAGE_SIZE); __SPM_SHIM_EXCEPTIONS_END__ = .; } >SPM_SHIM_EXCEPTIONS_VMA AT>RAM PROVIDE(__SPM_SHIM_EXCEPTIONS_LMA__ = LOADADDR(spm_shim_exceptions)); . = LOADADDR(spm_shim_exceptions) + SIZEOF(spm_shim_exceptions); #endif /* * Define a linker symbol to mark start of the RW memory area for this * image. */ __RW_START__ = . ; /* * .data must be placed at a lower address than the stacks if the stack * protector is enabled. Alternatively, the .data.stack_protector_canary * section can be placed independently of the main .data section. */ .data . : { __DATA_START__ = .; *(.data*) __DATA_END__ = .; } >RAM /* * .rela.dyn needs to come after .data for the read-elf utility to parse * this section correctly. Ensure 8-byte alignment so that the fields of * RELA data structure are aligned. */ . = ALIGN(8); __RELA_START__ = .; .rela.dyn . : { } >RAM __RELA_END__ = .; #ifdef BL31_PROGBITS_LIMIT ASSERT(. <= BL31_PROGBITS_LIMIT, "BL31 progbits has exceeded its limit.") #endif stacks (NOLOAD) : { __STACKS_START__ = .; *(tzfw_normal_stacks) __STACKS_END__ = .; } >RAM /* * The .bss section gets initialised to 0 at runtime. * Its base address should be 16-byte aligned for better performance of the * zero-initialization code. */ .bss (NOLOAD) : ALIGN(16) { __BSS_START__ = .; *(.bss*) *(COMMON) #if !USE_COHERENT_MEM /* * Bakery locks are stored in normal .bss memory * * Each lock's data is spread across multiple cache lines, one per CPU, * but multiple locks can share the same cache line. * The compiler will allocate enough memory for one CPU's bakery locks, * the remaining cache lines are allocated by the linker script */ . = ALIGN(CACHE_WRITEBACK_GRANULE); __BAKERY_LOCK_START__ = .; __PERCPU_BAKERY_LOCK_START__ = .; *(bakery_lock) . = ALIGN(CACHE_WRITEBACK_GRANULE); __PERCPU_BAKERY_LOCK_END__ = .; __PERCPU_BAKERY_LOCK_SIZE__ = ABSOLUTE(__PERCPU_BAKERY_LOCK_END__ - __PERCPU_BAKERY_LOCK_START__); . = . + (__PERCPU_BAKERY_LOCK_SIZE__ * (PLATFORM_CORE_COUNT - 1)); __BAKERY_LOCK_END__ = .; /* * If BL31 doesn't use any bakery lock then __PERCPU_BAKERY_LOCK_SIZE__ * will be zero. For this reason, the only two valid values for * __PERCPU_BAKERY_LOCK_SIZE__ are 0 or the platform defined value * PLAT_PERCPU_BAKERY_LOCK_SIZE. */ #ifdef PLAT_PERCPU_BAKERY_LOCK_SIZE ASSERT((__PERCPU_BAKERY_LOCK_SIZE__ == 0) || (__PERCPU_BAKERY_LOCK_SIZE__ == PLAT_PERCPU_BAKERY_LOCK_SIZE), "PLAT_PERCPU_BAKERY_LOCK_SIZE does not match bakery lock requirements"); #endif #endif #if ENABLE_PMF /* * Time-stamps are stored in normal .bss memory * * The compiler will allocate enough memory for one CPU's time-stamps, * the remaining memory for other CPUs is allocated by the * linker script */ . = ALIGN(CACHE_WRITEBACK_GRANULE); __PMF_TIMESTAMP_START__ = .; KEEP(*(pmf_timestamp_array)) . = ALIGN(CACHE_WRITEBACK_GRANULE); __PMF_PERCPU_TIMESTAMP_END__ = .; __PERCPU_TIMESTAMP_SIZE__ = ABSOLUTE(. - __PMF_TIMESTAMP_START__); . = . + (__PERCPU_TIMESTAMP_SIZE__ * (PLATFORM_CORE_COUNT - 1)); __PMF_TIMESTAMP_END__ = .; #endif /* ENABLE_PMF */ __BSS_END__ = .; } >RAM /* * The xlat_table section is for full, aligned page tables (4K). * Removing them from .bss avoids forcing 4K alignment on * the .bss section. The tables are initialized to zero by the translation * tables library. */ xlat_table (NOLOAD) : { *(xlat_table) } >RAM #if USE_COHERENT_MEM /* * The base address of the coherent memory section must be page-aligned (4K) * to guarantee that the coherent data are stored on their own pages and * are not mixed with normal data. This is required to set up the correct * memory attributes for the coherent data page tables. */ coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) { __COHERENT_RAM_START__ = .; /* * Bakery locks are stored in coherent memory * * Each lock's data is contiguous and fully allocated by the compiler */ *(bakery_lock) *(tzfw_coherent_mem) __COHERENT_RAM_END_UNALIGNED__ = .; /* * Memory page(s) mapped to this section will be marked * as device memory. No other unexpected data must creep in. * Ensure the rest of the current memory page is unused. */ . = ALIGN(PAGE_SIZE); __COHERENT_RAM_END__ = .; } >RAM #endif /* * Define a linker symbol to mark end of the RW memory area for this * image. */ __RW_END__ = .; __BL31_END__ = .; ASSERT(. <= BL31_LIMIT, "BL31 image has exceeded its limit.") } trusted-firmware-a-2.2/bl31/bl31.mk000066400000000000000000000052601355360272700167470ustar00rootroot00000000000000# # Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ################################################################################ # Include SPM Makefile ################################################################################ ifeq (${ENABLE_SPM},1) ifeq (${SPM_MM},1) ifeq (${EL3_EXCEPTION_HANDLING},0) $(error EL3_EXCEPTION_HANDLING must be 1 for SPM support) endif $(info Including makefile of SPM based on MM) include services/std_svc/spm_mm/spm.mk else $(info Including SPM makefile) include services/std_svc/spm/spm.mk endif endif include lib/psci/psci_lib.mk BL31_SOURCES += bl31/bl31_main.c \ bl31/interrupt_mgmt.c \ bl31/aarch64/bl31_entrypoint.S \ bl31/aarch64/crash_reporting.S \ bl31/aarch64/ea_delegate.S \ bl31/aarch64/runtime_exceptions.S \ bl31/bl31_context_mgmt.c \ common/runtime_svc.c \ lib/cpus/aarch64/dsu_helpers.S \ plat/common/aarch64/platform_mp_stack.S \ services/arm_arch_svc/arm_arch_svc_setup.c \ services/std_svc/std_svc_setup.c \ ${PSCI_LIB_SOURCES} \ ${SPM_SOURCES} ifeq (${ENABLE_PMF}, 1) BL31_SOURCES += lib/pmf/pmf_main.c endif ifeq (${EL3_EXCEPTION_HANDLING},1) BL31_SOURCES += bl31/ehf.c endif ifeq (${SDEI_SUPPORT},1) ifeq (${EL3_EXCEPTION_HANDLING},0) $(error EL3_EXCEPTION_HANDLING must be 1 for SDEI support) endif BL31_SOURCES += services/std_svc/sdei/sdei_dispatch.S \ services/std_svc/sdei/sdei_event.c \ services/std_svc/sdei/sdei_intr_mgmt.c \ services/std_svc/sdei/sdei_main.c \ services/std_svc/sdei/sdei_state.c endif ifeq (${ENABLE_SPE_FOR_LOWER_ELS},1) BL31_SOURCES += lib/extensions/spe/spe.c endif ifeq (${ENABLE_AMU},1) BL31_SOURCES += lib/extensions/amu/aarch64/amu.c \ lib/extensions/amu/aarch64/amu_helpers.S endif ifeq (${ENABLE_SVE_FOR_NS},1) BL31_SOURCES += lib/extensions/sve/sve.c endif ifeq (${ENABLE_MPAM_FOR_LOWER_ELS},1) BL31_SOURCES += lib/extensions/mpam/mpam.c endif ifeq (${WORKAROUND_CVE_2017_5715},1) BL31_SOURCES += lib/cpus/aarch64/wa_cve_2017_5715_bpiall.S \ lib/cpus/aarch64/wa_cve_2017_5715_mmu.S endif BL31_LINKERFILE := bl31/bl31.ld.S # Flag used to indicate if Crash reporting via console should be included # in BL31. This defaults to being present in DEBUG builds only ifndef CRASH_REPORTING CRASH_REPORTING := $(DEBUG) endif $(eval $(call assert_boolean,CRASH_REPORTING)) $(eval $(call assert_boolean,EL3_EXCEPTION_HANDLING)) $(eval $(call assert_boolean,SDEI_SUPPORT)) $(eval $(call add_define,CRASH_REPORTING)) $(eval $(call add_define,EL3_EXCEPTION_HANDLING)) $(eval $(call add_define,SDEI_SUPPORT)) trusted-firmware-a-2.2/bl31/bl31_context_mgmt.c000066400000000000000000000046301355360272700213520ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /******************************************************************************* * This function returns a pointer to the most recent 'cpu_context' structure * for the calling CPU that was set as the context for the specified security * state. NULL is returned if no such structure has been specified. ******************************************************************************/ void *cm_get_context(uint32_t security_state) { assert(security_state <= NON_SECURE); return get_cpu_data(cpu_context[security_state]); } /******************************************************************************* * This function sets the pointer to the current 'cpu_context' structure for the * specified security state for the calling CPU ******************************************************************************/ void cm_set_context(void *context, uint32_t security_state) { assert(security_state <= NON_SECURE); set_cpu_data(cpu_context[security_state], context); } /******************************************************************************* * This function returns a pointer to the most recent 'cpu_context' structure * for the CPU identified by `cpu_idx` that was set as the context for the * specified security state. NULL is returned if no such structure has been * specified. ******************************************************************************/ void *cm_get_context_by_index(unsigned int cpu_idx, unsigned int security_state) { assert(sec_state_is_valid(security_state)); return get_cpu_data_by_index(cpu_idx, cpu_context[security_state]); } /******************************************************************************* * This function sets the pointer to the current 'cpu_context' structure for the * specified security state for the CPU identified by CPU index. ******************************************************************************/ void cm_set_context_by_index(unsigned int cpu_idx, void *context, unsigned int security_state) { assert(sec_state_is_valid(security_state)); set_cpu_data_by_index(cpu_idx, cpu_context[security_state], context); } trusted-firmware-a-2.2/bl31/bl31_main.c000066400000000000000000000163721355360272700175740ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if ENABLE_RUNTIME_INSTRUMENTATION PMF_REGISTER_SERVICE_SMC(rt_instr_svc, PMF_RT_INSTR_SVC_ID, RT_INSTR_TOTAL_IDS, PMF_STORE_ENABLE) #endif /******************************************************************************* * This function pointer is used to initialise the BL32 image. It's initialized * by SPD calling bl31_register_bl32_init after setting up all things necessary * for SP execution. In cases where both SPD and SP are absent, or when SPD * finds it impossible to execute SP, this pointer is left as NULL ******************************************************************************/ static int32_t (*bl32_init)(void); /******************************************************************************* * Variable to indicate whether next image to execute after BL31 is BL33 * (non-secure & default) or BL32 (secure). ******************************************************************************/ static uint32_t next_image_type = NON_SECURE; /* * Implement the ARM Standard Service function to get arguments for a * particular service. */ uintptr_t get_arm_std_svc_args(unsigned int svc_mask) { /* Setup the arguments for PSCI Library */ DEFINE_STATIC_PSCI_LIB_ARGS_V1(psci_args, bl31_warm_entrypoint); /* PSCI is the only ARM Standard Service implemented */ assert(svc_mask == PSCI_FID_MASK); return (uintptr_t)&psci_args; } /******************************************************************************* * Simple function to initialise all BL31 helper libraries. ******************************************************************************/ void __init bl31_lib_init(void) { cm_init(); } /******************************************************************************* * Setup function for BL31. ******************************************************************************/ void bl31_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { /* Perform early platform-specific setup */ bl31_early_platform_setup2(arg0, arg1, arg2, arg3); /* Perform late platform-specific setup */ bl31_plat_arch_setup(); #if CTX_INCLUDE_PAUTH_REGS /* * Assert that the ARMv8.3-PAuth registers are present or an access * fault will be triggered when they are being saved or restored. */ assert(is_armv8_3_pauth_present()); #endif /* CTX_INCLUDE_PAUTH_REGS */ } /******************************************************************************* * BL31 is responsible for setting up the runtime services for the primary cpu * before passing control to the bootloader or an Operating System. This * function calls runtime_svc_init() which initializes all registered runtime * services. The run time services would setup enough context for the core to * switch to the next exception level. When this function returns, the core will * switch to the programmed exception level via an ERET. ******************************************************************************/ void bl31_main(void) { NOTICE("BL31: %s\n", version_string); NOTICE("BL31: %s\n", build_message); /* Perform platform setup in BL31 */ bl31_platform_setup(); /* Initialise helper libraries */ bl31_lib_init(); #if EL3_EXCEPTION_HANDLING INFO("BL31: Initialising Exception Handling Framework\n"); ehf_init(); #endif /* Initialize the runtime services e.g. psci. */ INFO("BL31: Initializing runtime services\n"); runtime_svc_init(); /* * All the cold boot actions on the primary cpu are done. We now need to * decide which is the next image (BL32 or BL33) and how to execute it. * If the SPD runtime service is present, it would want to pass control * to BL32 first in S-EL1. In that case, SPD would have registered a * function to initialize bl32 where it takes responsibility of entering * S-EL1 and returning control back to bl31_main. Once this is done we * can prepare entry into BL33 as normal. */ /* * If SPD had registered an init hook, invoke it. */ if (bl32_init != NULL) { INFO("BL31: Initializing BL32\n"); int32_t rc = (*bl32_init)(); if (rc == 0) WARN("BL31: BL32 initialization failed\n"); } /* * We are ready to enter the next EL. Prepare entry into the image * corresponding to the desired security state after the next ERET. */ bl31_prepare_next_image_entry(); console_flush(); /* * Perform any platform specific runtime setup prior to cold boot exit * from BL31 */ bl31_plat_runtime_setup(); } /******************************************************************************* * Accessor functions to help runtime services decide which image should be * executed after BL31. This is BL33 or the non-secure bootloader image by * default but the Secure payload dispatcher could override this by requesting * an entry into BL32 (Secure payload) first. If it does so then it should use * the same API to program an entry into BL33 once BL32 initialisation is * complete. ******************************************************************************/ void bl31_set_next_image_type(uint32_t security_state) { assert(sec_state_is_valid(security_state)); next_image_type = security_state; } uint32_t bl31_get_next_image_type(void) { return next_image_type; } /******************************************************************************* * This function programs EL3 registers and performs other setup to enable entry * into the next image after BL31 at the next ERET. ******************************************************************************/ void __init bl31_prepare_next_image_entry(void) { entry_point_info_t *next_image_info; uint32_t image_type; #if CTX_INCLUDE_AARCH32_REGS /* * Ensure that the build flag to save AArch32 system registers in CPU * context is not set for AArch64-only platforms. */ if (el_implemented(1) == EL_IMPL_A64ONLY) { ERROR("EL1 supports AArch64-only. Please set build flag " "CTX_INCLUDE_AARCH32_REGS = 0\n"); panic(); } #endif /* Determine which image to execute next */ image_type = bl31_get_next_image_type(); /* Program EL3 registers to enable entry into the next EL */ next_image_info = bl31_plat_get_next_image_ep_info(image_type); assert(next_image_info != NULL); assert(image_type == GET_SECURITY_STATE(next_image_info->h.attr)); INFO("BL31: Preparing for EL3 exit to %s world\n", (image_type == SECURE) ? "secure" : "normal"); print_entry_point_info(next_image_info); cm_init_my_context(next_image_info); cm_prepare_el3_exit(image_type); } /******************************************************************************* * This function initializes the pointer to BL32 init function. This is expected * to be called by the SPD after it finishes all its initialization ******************************************************************************/ void bl31_register_bl32_init(int32_t (*func)(void)) { bl32_init = func; } trusted-firmware-a-2.2/bl31/ehf.c000066400000000000000000000366511355360272700165730ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * Exception handlers at EL3, their priority levels, and management. */ #include #include #include #include #include #include #include #include #include #include #include /* Output EHF logs as verbose */ #define EHF_LOG(...) VERBOSE("EHF: " __VA_ARGS__) #define EHF_INVALID_IDX (-1) /* For a valid handler, return the actual function pointer; otherwise, 0. */ #define RAW_HANDLER(h) \ ((ehf_handler_t) ((((h) & EHF_PRI_VALID_) != 0U) ? \ ((h) & ~EHF_PRI_VALID_) : 0U)) #define PRI_BIT(idx) (((ehf_pri_bits_t) 1u) << (idx)) /* * Convert index into secure priority using the platform-defined priority bits * field. */ #define IDX_TO_PRI(idx) \ ((((unsigned) idx) << (7u - exception_data.pri_bits)) & 0x7fU) /* Check whether a given index is valid */ #define IS_IDX_VALID(idx) \ ((exception_data.ehf_priorities[idx].ehf_handler & EHF_PRI_VALID_) != 0U) /* Returns whether given priority is in secure priority range */ #define IS_PRI_SECURE(pri) (((pri) & 0x80U) == 0U) /* To be defined by the platform */ extern const ehf_priorities_t exception_data; /* Translate priority to the index in the priority array */ static unsigned int pri_to_idx(unsigned int priority) { unsigned int idx; idx = EHF_PRI_TO_IDX(priority, exception_data.pri_bits); assert(idx < exception_data.num_priorities); assert(IS_IDX_VALID(idx)); return idx; } /* Return whether there are outstanding priority activation */ static bool has_valid_pri_activations(pe_exc_data_t *pe_data) { return pe_data->active_pri_bits != 0U; } static pe_exc_data_t *this_cpu_data(void) { return &get_cpu_data(ehf_data); } /* * Return the current priority index of this CPU. If no priority is active, * return EHF_INVALID_IDX. */ static int get_pe_highest_active_idx(pe_exc_data_t *pe_data) { if (!has_valid_pri_activations(pe_data)) return EHF_INVALID_IDX; /* Current priority is the right-most bit */ return (int) __builtin_ctz(pe_data->active_pri_bits); } /* * Mark priority active by setting the corresponding bit in active_pri_bits and * programming the priority mask. * * This API is to be used as part of delegating to lower ELs other than for * interrupts; e.g. while handling synchronous exceptions. * * This API is expected to be invoked before restoring context (Secure or * Non-secure) in preparation for the respective dispatch. */ void ehf_activate_priority(unsigned int priority) { int cur_pri_idx; unsigned int old_mask, run_pri, idx; pe_exc_data_t *pe_data = this_cpu_data(); /* * Query interrupt controller for the running priority, or idle priority * if no interrupts are being handled. The requested priority must be * less (higher priority) than the active running priority. */ run_pri = plat_ic_get_running_priority(); if (priority >= run_pri) { ERROR("Running priority higher (0x%x) than requested (0x%x)\n", run_pri, priority); panic(); } /* * If there were priority activations already, the requested priority * must be less (higher priority) than the current highest priority * activation so far. */ cur_pri_idx = get_pe_highest_active_idx(pe_data); idx = pri_to_idx(priority); if ((cur_pri_idx != EHF_INVALID_IDX) && (idx >= ((unsigned int) cur_pri_idx))) { ERROR("Activation priority mismatch: req=0x%x current=0x%x\n", priority, IDX_TO_PRI(cur_pri_idx)); panic(); } /* Set the bit corresponding to the requested priority */ pe_data->active_pri_bits |= PRI_BIT(idx); /* * Program priority mask for the activated level. Check that the new * priority mask is setting a higher priority level than the existing * mask. */ old_mask = plat_ic_set_priority_mask(priority); if (priority >= old_mask) { ERROR("Requested priority (0x%x) lower than Priority Mask (0x%x)\n", priority, old_mask); panic(); } /* * If this is the first activation, save the priority mask. This will be * restored after the last deactivation. */ if (cur_pri_idx == EHF_INVALID_IDX) pe_data->init_pri_mask = (uint8_t) old_mask; EHF_LOG("activate prio=%d\n", get_pe_highest_active_idx(pe_data)); } /* * Mark priority inactive by clearing the corresponding bit in active_pri_bits, * and programming the priority mask. * * This API is expected to be used as part of delegating to to lower ELs other * than for interrupts; e.g. while handling synchronous exceptions. * * This API is expected to be invoked after saving context (Secure or * Non-secure), having concluded the respective dispatch. */ void ehf_deactivate_priority(unsigned int priority) { int cur_pri_idx; pe_exc_data_t *pe_data = this_cpu_data(); unsigned int old_mask, run_pri, idx; /* * Query interrupt controller for the running priority, or idle priority * if no interrupts are being handled. The requested priority must be * less (higher priority) than the active running priority. */ run_pri = plat_ic_get_running_priority(); if (priority >= run_pri) { ERROR("Running priority higher (0x%x) than requested (0x%x)\n", run_pri, priority); panic(); } /* * Deactivation is allowed only when there are priority activations, and * the deactivation priority level must match the current activated * priority. */ cur_pri_idx = get_pe_highest_active_idx(pe_data); idx = pri_to_idx(priority); if ((cur_pri_idx == EHF_INVALID_IDX) || (idx != ((unsigned int) cur_pri_idx))) { ERROR("Deactivation priority mismatch: req=0x%x current=0x%x\n", priority, IDX_TO_PRI(cur_pri_idx)); panic(); } /* Clear bit corresponding to highest priority */ pe_data->active_pri_bits &= (pe_data->active_pri_bits - 1u); /* * Restore priority mask corresponding to the next priority, or the * one stashed earlier if there are no more to deactivate. */ cur_pri_idx = get_pe_highest_active_idx(pe_data); if (cur_pri_idx == EHF_INVALID_IDX) old_mask = plat_ic_set_priority_mask(pe_data->init_pri_mask); else old_mask = plat_ic_set_priority_mask(priority); if (old_mask > priority) { ERROR("Deactivation priority (0x%x) lower than Priority Mask (0x%x)\n", priority, old_mask); panic(); } EHF_LOG("deactivate prio=%d\n", get_pe_highest_active_idx(pe_data)); } /* * After leaving Non-secure world, stash current Non-secure Priority Mask, and * set Priority Mask to the highest Non-secure priority so that Non-secure * interrupts cannot preempt Secure execution. * * If the current running priority is in the secure range, or if there are * outstanding priority activations, this function does nothing. * * This function subscribes to the 'cm_exited_normal_world' event published by * the Context Management Library. */ static void *ehf_exited_normal_world(const void *arg) { unsigned int run_pri; pe_exc_data_t *pe_data = this_cpu_data(); /* If the running priority is in the secure range, do nothing */ run_pri = plat_ic_get_running_priority(); if (IS_PRI_SECURE(run_pri)) return NULL; /* Do nothing if there are explicit activations */ if (has_valid_pri_activations(pe_data)) return NULL; assert(pe_data->ns_pri_mask == 0u); pe_data->ns_pri_mask = (uint8_t) plat_ic_set_priority_mask(GIC_HIGHEST_NS_PRIORITY); /* The previous Priority Mask is not expected to be in secure range */ if (IS_PRI_SECURE(pe_data->ns_pri_mask)) { ERROR("Priority Mask (0x%x) already in secure range\n", pe_data->ns_pri_mask); panic(); } EHF_LOG("Priority Mask: 0x%x => 0x%x\n", pe_data->ns_pri_mask, GIC_HIGHEST_NS_PRIORITY); return NULL; } /* * Conclude Secure execution and prepare for return to Non-secure world. Restore * the Non-secure Priority Mask previously stashed upon leaving Non-secure * world. * * If there the current running priority is in the secure range, or if there are * outstanding priority activations, this function does nothing. * * This function subscribes to the 'cm_entering_normal_world' event published by * the Context Management Library. */ static void *ehf_entering_normal_world(const void *arg) { unsigned int old_pmr, run_pri; pe_exc_data_t *pe_data = this_cpu_data(); /* If the running priority is in the secure range, do nothing */ run_pri = plat_ic_get_running_priority(); if (IS_PRI_SECURE(run_pri)) return NULL; /* * If there are explicit activations, do nothing. The Priority Mask will * be restored upon the last deactivation. */ if (has_valid_pri_activations(pe_data)) return NULL; /* Do nothing if we don't have a valid Priority Mask to restore */ if (pe_data->ns_pri_mask == 0U) return NULL; old_pmr = plat_ic_set_priority_mask(pe_data->ns_pri_mask); /* * When exiting secure world, the current Priority Mask must be * GIC_HIGHEST_NS_PRIORITY (as set during entry), or the Non-secure * priority mask set upon calling ehf_allow_ns_preemption() */ if ((old_pmr != GIC_HIGHEST_NS_PRIORITY) && (old_pmr != pe_data->ns_pri_mask)) { ERROR("Invalid Priority Mask (0x%x) restored\n", old_pmr); panic(); } EHF_LOG("Priority Mask: 0x%x => 0x%x\n", old_pmr, pe_data->ns_pri_mask); pe_data->ns_pri_mask = 0; return NULL; } /* * Program Priority Mask to the original Non-secure priority such that * Non-secure interrupts may preempt Secure execution (for example, during * Yielding SMC calls). The 'preempt_ret_code' parameter indicates the Yielding * SMC's return value in case the call was preempted. * * This API is expected to be invoked before delegating a yielding SMC to Secure * EL1. I.e. within the window of secure execution after Non-secure context is * saved (after entry into EL3) and Secure context is restored (before entering * Secure EL1). */ void ehf_allow_ns_preemption(uint64_t preempt_ret_code) { cpu_context_t *ns_ctx; unsigned int old_pmr __unused; pe_exc_data_t *pe_data = this_cpu_data(); /* * We should have been notified earlier of entering secure world, and * therefore have stashed the Non-secure priority mask. */ assert(pe_data->ns_pri_mask != 0U); /* Make sure no priority levels are active when requesting this */ if (has_valid_pri_activations(pe_data)) { ERROR("PE %lx has priority activations: 0x%x\n", read_mpidr_el1(), pe_data->active_pri_bits); panic(); } /* * Program preempted return code to x0 right away so that, if the * Yielding SMC was indeed preempted before a dispatcher gets a chance * to populate it, the caller would find the correct return value. */ ns_ctx = cm_get_context(NON_SECURE); assert(ns_ctx != NULL); write_ctx_reg(get_gpregs_ctx(ns_ctx), CTX_GPREG_X0, preempt_ret_code); old_pmr = plat_ic_set_priority_mask(pe_data->ns_pri_mask); EHF_LOG("Priority Mask: 0x%x => 0x%x\n", old_pmr, pe_data->ns_pri_mask); pe_data->ns_pri_mask = 0; } /* * Return whether Secure execution has explicitly allowed Non-secure interrupts * to preempt itself (for example, during Yielding SMC calls). */ unsigned int ehf_is_ns_preemption_allowed(void) { unsigned int run_pri; pe_exc_data_t *pe_data = this_cpu_data(); /* If running priority is in secure range, return false */ run_pri = plat_ic_get_running_priority(); if (IS_PRI_SECURE(run_pri)) return 0; /* * If Non-secure preemption was permitted by calling * ehf_allow_ns_preemption() earlier: * * - There wouldn't have been priority activations; * - We would have cleared the stashed the Non-secure Priority Mask. */ if (has_valid_pri_activations(pe_data)) return 0; if (pe_data->ns_pri_mask != 0U) return 0; return 1; } /* * Top-level EL3 interrupt handler. */ static uint64_t ehf_el3_interrupt_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { int ret = 0; uint32_t intr_raw; unsigned int intr, pri, idx; ehf_handler_t handler; /* * Top-level interrupt type handler from Interrupt Management Framework * doesn't acknowledge the interrupt; so the interrupt ID must be * invalid. */ assert(id == INTR_ID_UNAVAILABLE); /* * Acknowledge interrupt. Proceed with handling only for valid interrupt * IDs. This situation may arise because of Interrupt Management * Framework identifying an EL3 interrupt, but before it's been * acknowledged here, the interrupt was either deasserted, or there was * a higher-priority interrupt of another type. */ intr_raw = plat_ic_acknowledge_interrupt(); intr = plat_ic_get_interrupt_id(intr_raw); if (intr == INTR_ID_UNAVAILABLE) return 0; /* Having acknowledged the interrupt, get the running priority */ pri = plat_ic_get_running_priority(); /* Check EL3 interrupt priority is in secure range */ assert(IS_PRI_SECURE(pri)); /* * Translate the priority to a descriptor index. We do this by masking * and shifting the running priority value (platform-supplied). */ idx = pri_to_idx(pri); /* Validate priority */ assert(pri == IDX_TO_PRI(idx)); handler = (ehf_handler_t) RAW_HANDLER( exception_data.ehf_priorities[idx].ehf_handler); if (handler == NULL) { ERROR("No EL3 exception handler for priority 0x%x\n", IDX_TO_PRI(idx)); panic(); } /* * Call registered handler. Pass the raw interrupt value to registered * handlers. */ ret = handler(intr_raw, flags, handle, cookie); return (uint64_t) ret; } /* * Initialize the EL3 exception handling. */ void __init ehf_init(void) { unsigned int flags = 0; int ret __unused; /* Ensure EL3 interrupts are supported */ assert(plat_ic_has_interrupt_type(INTR_TYPE_EL3) != 0); /* * Make sure that priority water mark has enough bits to represent the * whole priority array. */ assert(exception_data.num_priorities <= (sizeof(ehf_pri_bits_t) * 8U)); assert(exception_data.ehf_priorities != NULL); /* * Bit 7 of GIC priority must be 0 for secure interrupts. This means * platforms must use at least 1 of the remaining 7 bits. */ assert((exception_data.pri_bits >= 1U) || (exception_data.pri_bits < 8U)); /* Route EL3 interrupts when in Secure and Non-secure. */ set_interrupt_rm_flag(flags, NON_SECURE); set_interrupt_rm_flag(flags, SECURE); /* Register handler for EL3 interrupts */ ret = register_interrupt_type_handler(INTR_TYPE_EL3, ehf_el3_interrupt_handler, flags); assert(ret == 0); } /* * Register a handler at the supplied priority. Registration is allowed only if * a handler hasn't been registered before, or one wasn't provided at build * time. The priority for which the handler is being registered must also accord * with the platform-supplied data. */ void ehf_register_priority_handler(unsigned int pri, ehf_handler_t handler) { unsigned int idx; /* Sanity check for handler */ assert(handler != NULL); /* Handler ought to be 4-byte aligned */ assert((((uintptr_t) handler) & 3U) == 0U); /* Ensure we register for valid priority */ idx = pri_to_idx(pri); assert(idx < exception_data.num_priorities); assert(IDX_TO_PRI(idx) == pri); /* Return failure if a handler was already registered */ if (exception_data.ehf_priorities[idx].ehf_handler != EHF_NO_HANDLER_) { ERROR("Handler already registered for priority 0x%x\n", pri); panic(); } /* * Install handler, and retain the valid bit. We assume that the handler * is 4-byte aligned, which is usually the case. */ exception_data.ehf_priorities[idx].ehf_handler = (((uintptr_t) handler) | EHF_PRI_VALID_); EHF_LOG("register pri=0x%x handler=%p\n", pri, handler); } SUBSCRIBE_TO_EVENT(cm_entering_normal_world, ehf_entering_normal_world); SUBSCRIBE_TO_EVENT(cm_exited_normal_world, ehf_exited_normal_world); trusted-firmware-a-2.2/bl31/interrupt_mgmt.c000066400000000000000000000201701355360272700210760ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /******************************************************************************* * Local structure and corresponding array to keep track of the state of the * registered interrupt handlers for each interrupt type. * The field descriptions are: * * 'flags' : Bit[0], Routing model for this interrupt type when execution is * not in EL3 in the secure state. '1' implies that this * interrupt will be routed to EL3. '0' implies that this * interrupt will be routed to the current exception level. * * Bit[1], Routing model for this interrupt type when execution is * not in EL3 in the non-secure state. '1' implies that this * interrupt will be routed to EL3. '0' implies that this * interrupt will be routed to the current exception level. * * All other bits are reserved and SBZ. * * 'scr_el3[2]' : Mapping of the routing model in the 'flags' field to the * value of the SCR_EL3.IRQ or FIQ bit for each security state. * There are two instances of this field corresponding to the * two security states. ******************************************************************************/ typedef struct intr_type_desc { interrupt_type_handler_t handler; uint32_t flags; uint32_t scr_el3[2]; } intr_type_desc_t; static intr_type_desc_t intr_type_descs[MAX_INTR_TYPES]; /******************************************************************************* * This function validates the interrupt type. ******************************************************************************/ static int32_t validate_interrupt_type(uint32_t type) { if ((type == INTR_TYPE_S_EL1) || (type == INTR_TYPE_NS) || (type == INTR_TYPE_EL3)) return 0; return -EINVAL; } /******************************************************************************* * This function validates the routing model for this type of interrupt ******************************************************************************/ static int32_t validate_routing_model(uint32_t type, uint32_t flags) { uint32_t rm_flags = (flags >> INTR_RM_FLAGS_SHIFT) & INTR_RM_FLAGS_MASK; if (type == INTR_TYPE_S_EL1) return validate_sel1_interrupt_rm(rm_flags); if (type == INTR_TYPE_NS) return validate_ns_interrupt_rm(rm_flags); if (type == INTR_TYPE_EL3) return validate_el3_interrupt_rm(rm_flags); return -EINVAL; } /******************************************************************************* * This function returns the cached copy of the SCR_EL3 which contains the * routing model (expressed through the IRQ and FIQ bits) for a security state * which was stored through a call to 'set_routing_model()' earlier. ******************************************************************************/ uint32_t get_scr_el3_from_routing_model(uint32_t security_state) { uint32_t scr_el3; assert(sec_state_is_valid(security_state)); scr_el3 = intr_type_descs[INTR_TYPE_NS].scr_el3[security_state]; scr_el3 |= intr_type_descs[INTR_TYPE_S_EL1].scr_el3[security_state]; scr_el3 |= intr_type_descs[INTR_TYPE_EL3].scr_el3[security_state]; return scr_el3; } /******************************************************************************* * This function uses the 'interrupt_type_flags' parameter to obtain the value * of the trap bit (IRQ/FIQ) in the SCR_EL3 for a security state for this * interrupt type. It uses it to update the SCR_EL3 in the cpu context and the * 'intr_type_desc' for that security state. ******************************************************************************/ static void set_scr_el3_from_rm(uint32_t type, uint32_t interrupt_type_flags, uint32_t security_state) { uint32_t flag, bit_pos; flag = get_interrupt_rm_flag(interrupt_type_flags, security_state); bit_pos = plat_interrupt_type_to_line(type, security_state); intr_type_descs[type].scr_el3[security_state] = flag << bit_pos; /* * Update scr_el3 only if there is a context available. If not, it * will be updated later during context initialization which will obtain * the scr_el3 value to be used via get_scr_el3_from_routing_model() */ if (cm_get_context(security_state) != NULL) cm_write_scr_el3_bit(security_state, bit_pos, flag); } /******************************************************************************* * This function validates the routing model specified in the 'flags' and * updates internal data structures to reflect the new routing model. It also * updates the copy of SCR_EL3 for each security state with the new routing * model in the 'cpu_context' structure for this cpu. ******************************************************************************/ int32_t set_routing_model(uint32_t type, uint32_t flags) { int32_t rc; rc = validate_interrupt_type(type); if (rc != 0) return rc; rc = validate_routing_model(type, flags); if (rc != 0) return rc; /* Update the routing model in internal data structures */ intr_type_descs[type].flags = flags; set_scr_el3_from_rm(type, flags, SECURE); set_scr_el3_from_rm(type, flags, NON_SECURE); return 0; } /****************************************************************************** * This function disables the routing model of interrupt 'type' from the * specified 'security_state' on the local core. The disable is in effect * till the core powers down or till the next enable for that interrupt * type. *****************************************************************************/ int disable_intr_rm_local(uint32_t type, uint32_t security_state) { uint32_t bit_pos, flag; assert(intr_type_descs[type].handler != NULL); flag = get_interrupt_rm_flag(INTR_DEFAULT_RM, security_state); bit_pos = plat_interrupt_type_to_line(type, security_state); cm_write_scr_el3_bit(security_state, bit_pos, flag); return 0; } /****************************************************************************** * This function enables the routing model of interrupt 'type' from the * specified 'security_state' on the local core. *****************************************************************************/ int enable_intr_rm_local(uint32_t type, uint32_t security_state) { uint32_t bit_pos, flag; assert(intr_type_descs[type].handler != NULL); flag = get_interrupt_rm_flag(intr_type_descs[type].flags, security_state); bit_pos = plat_interrupt_type_to_line(type, security_state); cm_write_scr_el3_bit(security_state, bit_pos, flag); return 0; } /******************************************************************************* * This function registers a handler for the 'type' of interrupt specified. It * also validates the routing model specified in the 'flags' for this type of * interrupt. ******************************************************************************/ int32_t register_interrupt_type_handler(uint32_t type, interrupt_type_handler_t handler, uint32_t flags) { int32_t rc; /* Validate the 'handler' parameter */ if (handler == NULL) return -EINVAL; /* Validate the 'flags' parameter */ if ((flags & INTR_TYPE_FLAGS_MASK) != 0U) return -EINVAL; /* Check if a handler has already been registered */ if (intr_type_descs[type].handler != NULL) return -EALREADY; rc = set_routing_model(type, flags); if (rc != 0) return rc; /* Save the handler */ intr_type_descs[type].handler = handler; return 0; } /******************************************************************************* * This function is called when an interrupt is generated and returns the * handler for the interrupt type (if registered). It returns NULL if the * interrupt type is not supported or its handler has not been registered. ******************************************************************************/ interrupt_type_handler_t get_interrupt_type_handler(uint32_t type) { if (validate_interrupt_type(type) != 0) return NULL; return intr_type_descs[type].handler; } trusted-firmware-a-2.2/bl32/000077500000000000000000000000001355360272700156535ustar00rootroot00000000000000trusted-firmware-a-2.2/bl32/optee/000077500000000000000000000000001355360272700167675ustar00rootroot00000000000000trusted-firmware-a-2.2/bl32/optee/optee.mk000066400000000000000000000007101355360272700204320ustar00rootroot00000000000000# # Copyright (c) 2016-2019, Arm Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # This makefile only aims at complying with Trusted Firmware-A build process so # that "optee" is a valid TF-A AArch32 Secure Playload identifier. ifneq ($(ARCH),aarch32) $(error This directory targets AArch32 support) endif $(eval $(call add_define,AARCH32_SP_OPTEE)) $(info Trusted Firmware-A built for OP-TEE payload support) trusted-firmware-a-2.2/bl32/sp_min/000077500000000000000000000000001355360272700171405ustar00rootroot00000000000000trusted-firmware-a-2.2/bl32/sp_min/aarch32/000077500000000000000000000000001355360272700203635ustar00rootroot00000000000000trusted-firmware-a-2.2/bl32/sp_min/aarch32/entrypoint.S000066400000000000000000000207761355360272700227360ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include .globl sp_min_vector_table .globl sp_min_entrypoint .globl sp_min_warm_entrypoint .globl sp_min_handle_smc .globl sp_min_handle_fiq .macro route_fiq_to_sp_min reg /* ----------------------------------------------------- * FIQs are secure interrupts trapped by Monitor and non * secure is not allowed to mask the FIQs. * ----------------------------------------------------- */ ldcopr \reg, SCR orr \reg, \reg, #SCR_FIQ_BIT bic \reg, \reg, #SCR_FW_BIT stcopr \reg, SCR .endm .macro clrex_on_monitor_entry #if (ARM_ARCH_MAJOR == 7) /* * ARMv7 architectures need to clear the exclusive access when * entering Monitor mode. */ clrex #endif .endm vector_base sp_min_vector_table b sp_min_entrypoint b plat_panic_handler /* Undef */ b sp_min_handle_smc /* Syscall */ b plat_panic_handler /* Prefetch abort */ b plat_panic_handler /* Data abort */ b plat_panic_handler /* Reserved */ b plat_panic_handler /* IRQ */ b sp_min_handle_fiq /* FIQ */ /* * The Cold boot/Reset entrypoint for SP_MIN */ func sp_min_entrypoint #if !RESET_TO_SP_MIN /* --------------------------------------------------------------- * Preceding bootloader has populated r0 with a pointer to a * 'bl_params_t' structure & r1 with a pointer to platform * specific structure * --------------------------------------------------------------- */ mov r9, r0 mov r10, r1 mov r11, r2 mov r12, r3 /* --------------------------------------------------------------------- * For !RESET_TO_SP_MIN systems, only the primary CPU ever reaches * sp_min_entrypoint() during the cold boot flow, so the cold/warm boot * and primary/secondary CPU logic should not be executed in this case. * * Also, assume that the previous bootloader has already initialised the * SCTLR, including the CPU endianness, and has initialised the memory. * --------------------------------------------------------------------- */ el3_entrypoint_common \ _init_sctlr=0 \ _warm_boot_mailbox=0 \ _secondary_cold_boot=0 \ _init_memory=0 \ _init_c_runtime=1 \ _exception_vectors=sp_min_vector_table /* --------------------------------------------------------------------- * Relay the previous bootloader's arguments to the platform layer * --------------------------------------------------------------------- */ #else /* --------------------------------------------------------------------- * For RESET_TO_SP_MIN systems which have a programmable reset address, * sp_min_entrypoint() is executed only on the cold boot path so we can * skip the warm boot mailbox mechanism. * --------------------------------------------------------------------- */ el3_entrypoint_common \ _init_sctlr=1 \ _warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \ _secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \ _init_memory=1 \ _init_c_runtime=1 \ _exception_vectors=sp_min_vector_table /* --------------------------------------------------------------------- * For RESET_TO_SP_MIN systems, BL32 (SP_MIN) is the first bootloader * to run so there's no argument to relay from a previous bootloader. * Zero the arguments passed to the platform layer to reflect that. * --------------------------------------------------------------------- */ mov r9, #0 mov r10, #0 mov r11, #0 mov r12, #0 #endif /* RESET_TO_SP_MIN */ #if SP_MIN_WITH_SECURE_FIQ route_fiq_to_sp_min r4 #endif mov r0, r9 mov r1, r10 mov r2, r11 mov r3, r12 bl sp_min_early_platform_setup2 bl sp_min_plat_arch_setup /* Jump to the main function */ bl sp_min_main /* ------------------------------------------------------------- * Clean the .data & .bss sections to main memory. This ensures * that any global data which was initialised by the primary CPU * is visible to secondary CPUs before they enable their data * caches and participate in coherency. * ------------------------------------------------------------- */ ldr r0, =__DATA_START__ ldr r1, =__DATA_END__ sub r1, r1, r0 bl clean_dcache_range ldr r0, =__BSS_START__ ldr r1, =__BSS_END__ sub r1, r1, r0 bl clean_dcache_range bl smc_get_next_ctx /* r0 points to `smc_ctx_t` */ /* The PSCI cpu_context registers have been copied to `smc_ctx_t` */ b sp_min_exit endfunc sp_min_entrypoint /* * SMC handling function for SP_MIN. */ func sp_min_handle_smc /* On SMC entry, `sp` points to `smc_ctx_t`. Save `lr`. */ str lr, [sp, #SMC_CTX_LR_MON] smccc_save_gp_mode_regs clrex_on_monitor_entry /* * `sp` still points to `smc_ctx_t`. Save it to a register * and restore the C runtime stack pointer to `sp`. */ mov r2, sp /* handle */ ldr sp, [r2, #SMC_CTX_SP_MON] ldr r0, [r2, #SMC_CTX_SCR] and r3, r0, #SCR_NS_BIT /* flags */ /* Switch to Secure Mode*/ bic r0, #SCR_NS_BIT stcopr r0, SCR isb ldr r0, [r2, #SMC_CTX_GPREG_R0] /* smc_fid */ /* Check whether an SMC64 is issued */ tst r0, #(FUNCID_CC_MASK << FUNCID_CC_SHIFT) beq 1f /* SMC32 is not detected. Return error back to caller */ mov r0, #SMC_UNK str r0, [r2, #SMC_CTX_GPREG_R0] mov r0, r2 b sp_min_exit 1: /* SMC32 is detected */ mov r1, #0 /* cookie */ bl handle_runtime_svc /* `r0` points to `smc_ctx_t` */ b sp_min_exit endfunc sp_min_handle_smc /* * Secure Interrupts handling function for SP_MIN. */ func sp_min_handle_fiq #if !SP_MIN_WITH_SECURE_FIQ b plat_panic_handler #else /* FIQ has a +4 offset for lr compared to preferred return address */ sub lr, lr, #4 /* On SMC entry, `sp` points to `smc_ctx_t`. Save `lr`. */ str lr, [sp, #SMC_CTX_LR_MON] smccc_save_gp_mode_regs clrex_on_monitor_entry /* load run-time stack */ mov r2, sp ldr sp, [r2, #SMC_CTX_SP_MON] /* Switch to Secure Mode */ ldr r0, [r2, #SMC_CTX_SCR] bic r0, #SCR_NS_BIT stcopr r0, SCR isb push {r2, r3} bl sp_min_fiq pop {r0, r3} b sp_min_exit #endif endfunc sp_min_handle_fiq /* * The Warm boot entrypoint for SP_MIN. */ func sp_min_warm_entrypoint /* * On the warm boot path, most of the EL3 initialisations performed by * 'el3_entrypoint_common' must be skipped: * * - Only when the platform bypasses the BL1/BL32 (SP_MIN) entrypoint by * programming the reset address do we need to initialied the SCTLR. * In other cases, we assume this has been taken care by the * entrypoint code. * * - No need to determine the type of boot, we know it is a warm boot. * * - Do not try to distinguish between primary and secondary CPUs, this * notion only exists for a cold boot. * * - No need to initialise the memory or the C runtime environment, * it has been done once and for all on the cold boot path. */ el3_entrypoint_common \ _init_sctlr=PROGRAMMABLE_RESET_ADDRESS \ _warm_boot_mailbox=0 \ _secondary_cold_boot=0 \ _init_memory=0 \ _init_c_runtime=0 \ _exception_vectors=sp_min_vector_table /* * We're about to enable MMU and participate in PSCI state coordination. * * The PSCI implementation invokes platform routines that enable CPUs to * participate in coherency. On a system where CPUs are not * cache-coherent without appropriate platform specific programming, * having caches enabled until such time might lead to coherency issues * (resulting from stale data getting speculatively fetched, among * others). Therefore we keep data caches disabled even after enabling * the MMU for such platforms. * * On systems with hardware-assisted coherency, or on single cluster * platforms, such platform specific programming is not required to * enter coherency (as CPUs already are); and there's no reason to have * caches disabled either. */ #if HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY mov r0, #0 #else mov r0, #DISABLE_DCACHE #endif bl bl32_plat_enable_mmu #if SP_MIN_WITH_SECURE_FIQ route_fiq_to_sp_min r0 #endif bl sp_min_warm_boot bl smc_get_next_ctx /* r0 points to `smc_ctx_t` */ /* The PSCI cpu_context registers have been copied to `smc_ctx_t` */ b sp_min_exit endfunc sp_min_warm_entrypoint /* * The function to restore the registers from SMC context and return * to the mode restored to SPSR. * * Arguments : r0 must point to the SMC context to restore from. */ func sp_min_exit monitor_exit endfunc sp_min_exit trusted-firmware-a-2.2/bl32/sp_min/sp_min.ld.S000066400000000000000000000154701355360272700211560ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include OUTPUT_FORMAT(elf32-littlearm) OUTPUT_ARCH(arm) ENTRY(sp_min_vector_table) MEMORY { RAM (rwx): ORIGIN = BL32_BASE, LENGTH = BL32_LIMIT - BL32_BASE } #ifdef PLAT_SP_MIN_EXTRA_LD_SCRIPT #include #endif SECTIONS { . = BL32_BASE; ASSERT(. == ALIGN(PAGE_SIZE), "BL32_BASE address is not aligned on a page boundary.") #if SEPARATE_CODE_AND_RODATA .text . : { __TEXT_START__ = .; *entrypoint.o(.text*) *(.text*) *(.vectors) . = ALIGN(PAGE_SIZE); __TEXT_END__ = .; } >RAM /* .ARM.extab and .ARM.exidx are only added because Clang need them */ .ARM.extab . : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >RAM .ARM.exidx . : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >RAM .rodata . : { __RODATA_START__ = .; *(.rodata*) /* Ensure 4-byte alignment for descriptors and ensure inclusion */ . = ALIGN(4); __RT_SVC_DESCS_START__ = .; KEEP(*(rt_svc_descs)) __RT_SVC_DESCS_END__ = .; /* * Ensure 4-byte alignment for cpu_ops so that its fields are also * aligned. Also ensure cpu_ops inclusion. */ . = ALIGN(4); __CPU_OPS_START__ = .; KEEP(*(cpu_ops)) __CPU_OPS_END__ = .; /* Place pubsub sections for events */ . = ALIGN(8); #include . = ALIGN(PAGE_SIZE); __RODATA_END__ = .; } >RAM #else ro . : { __RO_START__ = .; *entrypoint.o(.text*) *(.text*) *(.rodata*) /* Ensure 4-byte alignment for descriptors and ensure inclusion */ . = ALIGN(4); __RT_SVC_DESCS_START__ = .; KEEP(*(rt_svc_descs)) __RT_SVC_DESCS_END__ = .; /* * Ensure 4-byte alignment for cpu_ops so that its fields are also * aligned. Also ensure cpu_ops inclusion. */ . = ALIGN(4); __CPU_OPS_START__ = .; KEEP(*(cpu_ops)) __CPU_OPS_END__ = .; /* Place pubsub sections for events */ . = ALIGN(8); #include *(.vectors) __RO_END_UNALIGNED__ = .; /* * Memory page(s) mapped to this section will be marked as * read-only, executable. No RW data from the next section must * creep in. Ensure the rest of the current memory block is unused. */ . = ALIGN(PAGE_SIZE); __RO_END__ = .; } >RAM #endif ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__, "cpu_ops not defined for this platform.") /* * Define a linker symbol to mark start of the RW memory area for this * image. */ __RW_START__ = . ; .data . : { __DATA_START__ = .; *(.data*) __DATA_END__ = .; } >RAM #ifdef BL32_PROGBITS_LIMIT ASSERT(. <= BL32_PROGBITS_LIMIT, "BL32 progbits has exceeded its limit.") #endif stacks (NOLOAD) : { __STACKS_START__ = .; *(tzfw_normal_stacks) __STACKS_END__ = .; } >RAM /* * The .bss section gets initialised to 0 at runtime. * Its base address should be 8-byte aligned for better performance of the * zero-initialization code. */ .bss (NOLOAD) : ALIGN(8) { __BSS_START__ = .; *(.bss*) *(COMMON) #if !USE_COHERENT_MEM /* * Bakery locks are stored in normal .bss memory * * Each lock's data is spread across multiple cache lines, one per CPU, * but multiple locks can share the same cache line. * The compiler will allocate enough memory for one CPU's bakery locks, * the remaining cache lines are allocated by the linker script */ . = ALIGN(CACHE_WRITEBACK_GRANULE); __BAKERY_LOCK_START__ = .; __PERCPU_BAKERY_LOCK_START__ = .; *(bakery_lock) . = ALIGN(CACHE_WRITEBACK_GRANULE); __PERCPU_BAKERY_LOCK_END__ = .; __PERCPU_BAKERY_LOCK_SIZE__ = ABSOLUTE(__PERCPU_BAKERY_LOCK_END__ - __PERCPU_BAKERY_LOCK_START__); . = . + (__PERCPU_BAKERY_LOCK_SIZE__ * (PLATFORM_CORE_COUNT - 1)); __BAKERY_LOCK_END__ = .; #ifdef PLAT_PERCPU_BAKERY_LOCK_SIZE ASSERT(__PERCPU_BAKERY_LOCK_SIZE__ == PLAT_PERCPU_BAKERY_LOCK_SIZE, "PLAT_PERCPU_BAKERY_LOCK_SIZE does not match bakery lock requirements"); #endif #endif #if ENABLE_PMF /* * Time-stamps are stored in normal .bss memory * * The compiler will allocate enough memory for one CPU's time-stamps, * the remaining memory for other CPUs is allocated by the * linker script */ . = ALIGN(CACHE_WRITEBACK_GRANULE); __PMF_TIMESTAMP_START__ = .; KEEP(*(pmf_timestamp_array)) . = ALIGN(CACHE_WRITEBACK_GRANULE); __PMF_PERCPU_TIMESTAMP_END__ = .; __PERCPU_TIMESTAMP_SIZE__ = ABSOLUTE(. - __PMF_TIMESTAMP_START__); . = . + (__PERCPU_TIMESTAMP_SIZE__ * (PLATFORM_CORE_COUNT - 1)); __PMF_TIMESTAMP_END__ = .; #endif /* ENABLE_PMF */ __BSS_END__ = .; } >RAM /* * The xlat_table section is for full, aligned page tables (4K). * Removing them from .bss avoids forcing 4K alignment on * the .bss section. The tables are initialized to zero by the translation * tables library. */ xlat_table (NOLOAD) : { *(xlat_table) } >RAM __BSS_SIZE__ = SIZEOF(.bss); #if USE_COHERENT_MEM /* * The base address of the coherent memory section must be page-aligned (4K) * to guarantee that the coherent data are stored on their own pages and * are not mixed with normal data. This is required to set up the correct * memory attributes for the coherent data page tables. */ coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) { __COHERENT_RAM_START__ = .; /* * Bakery locks are stored in coherent memory * * Each lock's data is contiguous and fully allocated by the compiler */ *(bakery_lock) *(tzfw_coherent_mem) __COHERENT_RAM_END_UNALIGNED__ = .; /* * Memory page(s) mapped to this section will be marked * as device memory. No other unexpected data must creep in. * Ensure the rest of the current memory page is unused. */ . = ALIGN(PAGE_SIZE); __COHERENT_RAM_END__ = .; } >RAM __COHERENT_RAM_UNALIGNED_SIZE__ = __COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__; #endif /* * Define a linker symbol to mark end of the RW memory area for this * image. */ __RW_END__ = .; __BL32_END__ = .; } trusted-firmware-a-2.2/bl32/sp_min/sp_min.mk000066400000000000000000000031371355360272700207620ustar00rootroot00000000000000# # Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ifneq (${ARCH}, aarch32) $(error SP_MIN is only supported on AArch32 platforms) endif include lib/psci/psci_lib.mk INCLUDES += -Iinclude/bl32/sp_min BL32_SOURCES += bl32/sp_min/sp_min_main.c \ bl32/sp_min/aarch32/entrypoint.S \ common/runtime_svc.c \ plat/common/aarch32/plat_sp_min_common.c\ services/std_svc/std_svc_setup.c \ ${PSCI_LIB_SOURCES} ifeq (${ENABLE_PMF}, 1) BL32_SOURCES += lib/pmf/pmf_main.c endif ifeq (${ENABLE_AMU}, 1) BL32_SOURCES += lib/extensions/amu/aarch32/amu.c\ lib/extensions/amu/aarch32/amu_helpers.S endif ifeq (${WORKAROUND_CVE_2017_5715},1) BL32_SOURCES += bl32/sp_min/wa_cve_2017_5715_bpiall.S \ bl32/sp_min/wa_cve_2017_5715_icache_inv.S endif BL32_LINKERFILE := bl32/sp_min/sp_min.ld.S # Include the platform-specific SP_MIN Makefile # If no platform-specific SP_MIN Makefile exists, it means SP_MIN is not supported # on this platform. SP_MIN_PLAT_MAKEFILE := $(wildcard ${PLAT_DIR}/sp_min/sp_min-${PLAT}.mk) ifeq (,${SP_MIN_PLAT_MAKEFILE}) $(error SP_MIN is not supported on platform ${PLAT}) else include ${SP_MIN_PLAT_MAKEFILE} endif RESET_TO_SP_MIN := 0 $(eval $(call add_define,RESET_TO_SP_MIN)) $(eval $(call assert_boolean,RESET_TO_SP_MIN)) # Flag to allow SP_MIN to handle FIQ interrupts in monitor mode. The platform # port is free to override this value. It is default disabled. SP_MIN_WITH_SECURE_FIQ ?= 0 $(eval $(call add_define,SP_MIN_WITH_SECURE_FIQ)) $(eval $(call assert_boolean,SP_MIN_WITH_SECURE_FIQ)) trusted-firmware-a-2.2/bl32/sp_min/sp_min_main.c000066400000000000000000000200611355360272700215740ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sp_min_private.h" /* Pointers to per-core cpu contexts */ static void *sp_min_cpu_ctx_ptr[PLATFORM_CORE_COUNT]; /* SP_MIN only stores the non secure smc context */ static smc_ctx_t sp_min_smc_context[PLATFORM_CORE_COUNT]; /****************************************************************************** * Define the smccc helper library APIs *****************************************************************************/ void *smc_get_ctx(unsigned int security_state) { assert(security_state == NON_SECURE); return &sp_min_smc_context[plat_my_core_pos()]; } void smc_set_next_ctx(unsigned int security_state) { assert(security_state == NON_SECURE); /* SP_MIN stores only non secure smc context. Nothing to do here */ } void *smc_get_next_ctx(void) { return &sp_min_smc_context[plat_my_core_pos()]; } /******************************************************************************* * This function returns a pointer to the most recent 'cpu_context' structure * for the calling CPU that was set as the context for the specified security * state. NULL is returned if no such structure has been specified. ******************************************************************************/ void *cm_get_context(uint32_t security_state) { assert(security_state == NON_SECURE); return sp_min_cpu_ctx_ptr[plat_my_core_pos()]; } /******************************************************************************* * This function sets the pointer to the current 'cpu_context' structure for the * specified security state for the calling CPU ******************************************************************************/ void cm_set_context(void *context, uint32_t security_state) { assert(security_state == NON_SECURE); sp_min_cpu_ctx_ptr[plat_my_core_pos()] = context; } /******************************************************************************* * This function returns a pointer to the most recent 'cpu_context' structure * for the CPU identified by `cpu_idx` that was set as the context for the * specified security state. NULL is returned if no such structure has been * specified. ******************************************************************************/ void *cm_get_context_by_index(unsigned int cpu_idx, unsigned int security_state) { assert(security_state == NON_SECURE); return sp_min_cpu_ctx_ptr[cpu_idx]; } /******************************************************************************* * This function sets the pointer to the current 'cpu_context' structure for the * specified security state for the CPU identified by CPU index. ******************************************************************************/ void cm_set_context_by_index(unsigned int cpu_idx, void *context, unsigned int security_state) { assert(security_state == NON_SECURE); sp_min_cpu_ctx_ptr[cpu_idx] = context; } static void copy_cpu_ctx_to_smc_stx(const regs_t *cpu_reg_ctx, smc_ctx_t *next_smc_ctx) { next_smc_ctx->r0 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R0); next_smc_ctx->r1 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R1); next_smc_ctx->r2 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R2); next_smc_ctx->lr_mon = read_ctx_reg(cpu_reg_ctx, CTX_LR); next_smc_ctx->spsr_mon = read_ctx_reg(cpu_reg_ctx, CTX_SPSR); next_smc_ctx->scr = read_ctx_reg(cpu_reg_ctx, CTX_SCR); } /******************************************************************************* * This function invokes the PSCI library interface to initialize the * non secure cpu context and copies the relevant cpu context register values * to smc context. These registers will get programmed during `smc_exit`. ******************************************************************************/ static void sp_min_prepare_next_image_entry(void) { entry_point_info_t *next_image_info; cpu_context_t *ctx = cm_get_context(NON_SECURE); u_register_t ns_sctlr; /* Program system registers to proceed to non-secure */ next_image_info = sp_min_plat_get_bl33_ep_info(); assert(next_image_info); assert(NON_SECURE == GET_SECURITY_STATE(next_image_info->h.attr)); INFO("SP_MIN: Preparing exit to normal world\n"); psci_prepare_next_non_secure_ctx(next_image_info); smc_set_next_ctx(NON_SECURE); /* Copy r0, lr and spsr from cpu context to SMC context */ copy_cpu_ctx_to_smc_stx(get_regs_ctx(cm_get_context(NON_SECURE)), smc_get_next_ctx()); /* Temporarily set the NS bit to access NS SCTLR */ write_scr(read_scr() | SCR_NS_BIT); isb(); ns_sctlr = read_ctx_reg(get_regs_ctx(ctx), CTX_NS_SCTLR); write_sctlr(ns_sctlr); isb(); write_scr(read_scr() & ~SCR_NS_BIT); isb(); } /****************************************************************************** * Implement the ARM Standard Service function to get arguments for a * particular service. *****************************************************************************/ uintptr_t get_arm_std_svc_args(unsigned int svc_mask) { /* Setup the arguments for PSCI Library */ DEFINE_STATIC_PSCI_LIB_ARGS_V1(psci_args, sp_min_warm_entrypoint); /* PSCI is the only ARM Standard Service implemented */ assert(svc_mask == PSCI_FID_MASK); return (uintptr_t)&psci_args; } /****************************************************************************** * The SP_MIN main function. Do the platform and PSCI Library setup. Also * initialize the runtime service framework. *****************************************************************************/ void sp_min_main(void) { NOTICE("SP_MIN: %s\n", version_string); NOTICE("SP_MIN: %s\n", build_message); /* Perform the SP_MIN platform setup */ sp_min_platform_setup(); /* Initialize the runtime services e.g. psci */ INFO("SP_MIN: Initializing runtime services\n"); runtime_svc_init(); /* * We are ready to enter the next EL. Prepare entry into the image * corresponding to the desired security state after the next ERET. */ sp_min_prepare_next_image_entry(); /* * Perform any platform specific runtime setup prior to cold boot exit * from SP_MIN. */ sp_min_plat_runtime_setup(); console_flush(); } /****************************************************************************** * This function is invoked during warm boot. Invoke the PSCI library * warm boot entry point which takes care of Architectural and platform setup/ * restore. Copy the relevant cpu_context register values to smc context which * will get programmed during `smc_exit`. *****************************************************************************/ void sp_min_warm_boot(void) { smc_ctx_t *next_smc_ctx; cpu_context_t *ctx = cm_get_context(NON_SECURE); u_register_t ns_sctlr; psci_warmboot_entrypoint(); smc_set_next_ctx(NON_SECURE); next_smc_ctx = smc_get_next_ctx(); zeromem(next_smc_ctx, sizeof(smc_ctx_t)); copy_cpu_ctx_to_smc_stx(get_regs_ctx(cm_get_context(NON_SECURE)), next_smc_ctx); /* Temporarily set the NS bit to access NS SCTLR */ write_scr(read_scr() | SCR_NS_BIT); isb(); ns_sctlr = read_ctx_reg(get_regs_ctx(ctx), CTX_NS_SCTLR); write_sctlr(ns_sctlr); isb(); write_scr(read_scr() & ~SCR_NS_BIT); isb(); } #if SP_MIN_WITH_SECURE_FIQ /****************************************************************************** * This function is invoked on secure interrupts. By construction of the * SP_MIN, secure interrupts can only be handled when core executes in non * secure state. *****************************************************************************/ void sp_min_fiq(void) { uint32_t id; id = plat_ic_acknowledge_interrupt(); sp_min_plat_fiq_handler(id); plat_ic_end_of_interrupt(id); } #endif /* SP_MIN_WITH_SECURE_FIQ */ trusted-firmware-a-2.2/bl32/sp_min/sp_min_private.h000066400000000000000000000004341355360272700223310ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SP_MIN_PRIVATE_H #define SP_MIN_PRIVATE_H void sp_min_main(void); void sp_min_warm_boot(void); void sp_min_fiq(void); #endif /* SP_MIN_PRIVATE_H */ trusted-firmware-a-2.2/bl32/sp_min/wa_cve_2017_5715_bpiall.S000066400000000000000000000032741355360272700232130ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include .globl wa_cve_2017_5715_bpiall_vbar vector_base wa_cve_2017_5715_bpiall_vbar /* We encode the exception entry in the bottom 3 bits of SP */ add sp, sp, #1 /* Reset: 0b111 */ add sp, sp, #1 /* Undef: 0b110 */ add sp, sp, #1 /* Syscall: 0b101 */ add sp, sp, #1 /* Prefetch abort: 0b100 */ add sp, sp, #1 /* Data abort: 0b011 */ add sp, sp, #1 /* Reserved: 0b010 */ add sp, sp, #1 /* IRQ: 0b001 */ nop /* FIQ: 0b000 */ /* * Invalidate the branch predictor, `r0` is a dummy register * and is unused. */ stcopr r0, BPIALL isb /* * As we cannot use any temporary registers and cannot * clobber SP, we can decode the exception entry using * an unrolled binary search. * * Note, if this code is re-used by other secure payloads, * the below exception entry vectors must be changed to * the vectors specific to that secure payload. */ tst sp, #4 bne 1f tst sp, #2 bne 3f /* Expected encoding: 0x1 and 0x0 */ tst sp, #1 /* Restore original value of SP by clearing the bottom 3 bits */ bic sp, sp, #0x7 bne plat_panic_handler /* IRQ */ b sp_min_handle_fiq /* FIQ */ 1: tst sp, #2 bne 2f /* Expected encoding: 0x4 and 0x5 */ tst sp, #1 bic sp, sp, #0x7 bne sp_min_handle_smc /* Syscall */ b plat_panic_handler /* Prefetch abort */ 2: /* Expected encoding: 0x7 and 0x6 */ tst sp, #1 bic sp, sp, #0x7 bne sp_min_entrypoint /* Reset */ b plat_panic_handler /* Undef */ 3: /* Expected encoding: 0x2 and 0x3 */ tst sp, #1 bic sp, sp, #0x7 bne plat_panic_handler /* Data abort */ b plat_panic_handler /* Reserved */ trusted-firmware-a-2.2/bl32/sp_min/wa_cve_2017_5715_icache_inv.S000066400000000000000000000034411355360272700240340ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include .globl wa_cve_2017_5715_icache_inv_vbar vector_base wa_cve_2017_5715_icache_inv_vbar /* We encode the exception entry in the bottom 3 bits of SP */ add sp, sp, #1 /* Reset: 0b111 */ add sp, sp, #1 /* Undef: 0b110 */ add sp, sp, #1 /* Syscall: 0b101 */ add sp, sp, #1 /* Prefetch abort: 0b100 */ add sp, sp, #1 /* Data abort: 0b011 */ add sp, sp, #1 /* Reserved: 0b010 */ add sp, sp, #1 /* IRQ: 0b001 */ nop /* FIQ: 0b000 */ /* * Invalidate the instruction cache, which we assume also * invalidates the branch predictor. This may depend on * other CPU specific changes (e.g. an ACTLR setting). */ stcopr r0, ICIALLU isb /* * As we cannot use any temporary registers and cannot * clobber SP, we can decode the exception entry using * an unrolled binary search. * * Note, if this code is re-used by other secure payloads, * the below exception entry vectors must be changed to * the vectors specific to that secure payload. */ tst sp, #4 bne 1f tst sp, #2 bne 3f /* Expected encoding: 0x1 and 0x0 */ tst sp, #1 /* Restore original value of SP by clearing the bottom 3 bits */ bic sp, sp, #0x7 bne plat_panic_handler /* IRQ */ b sp_min_handle_fiq /* FIQ */ 1: /* Expected encoding: 0x4 and 0x5 */ tst sp, #2 bne 2f tst sp, #1 bic sp, sp, #0x7 bne sp_min_handle_smc /* Syscall */ b plat_panic_handler /* Prefetch abort */ 2: /* Expected encoding: 0x7 and 0x6 */ tst sp, #1 bic sp, sp, #0x7 bne sp_min_entrypoint /* Reset */ b plat_panic_handler /* Undef */ 3: /* Expected encoding: 0x2 and 0x3 */ tst sp, #1 bic sp, sp, #0x7 bne plat_panic_handler /* Data abort */ b plat_panic_handler /* Reserved */ trusted-firmware-a-2.2/bl32/tsp/000077500000000000000000000000001355360272700164615ustar00rootroot00000000000000trusted-firmware-a-2.2/bl32/tsp/aarch64/000077500000000000000000000000001355360272700177115ustar00rootroot00000000000000trusted-firmware-a-2.2/bl32/tsp/aarch64/tsp_entrypoint.S000066400000000000000000000312341355360272700231410ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "../tsp_private.h" .globl tsp_entrypoint .globl tsp_vector_table /* --------------------------------------------- * Populate the params in x0-x7 from the pointer * to the smc args structure in x0. * --------------------------------------------- */ .macro restore_args_call_smc ldp x6, x7, [x0, #TSP_ARG6] ldp x4, x5, [x0, #TSP_ARG4] ldp x2, x3, [x0, #TSP_ARG2] ldp x0, x1, [x0, #TSP_ARG0] smc #0 .endm .macro save_eret_context reg1 reg2 mrs \reg1, elr_el1 mrs \reg2, spsr_el1 stp \reg1, \reg2, [sp, #-0x10]! stp x30, x18, [sp, #-0x10]! .endm .macro restore_eret_context reg1 reg2 ldp x30, x18, [sp], #0x10 ldp \reg1, \reg2, [sp], #0x10 msr elr_el1, \reg1 msr spsr_el1, \reg2 .endm func tsp_entrypoint _align=3 /* --------------------------------------------- * Set the exception vector to something sane. * --------------------------------------------- */ adr x0, tsp_exceptions msr vbar_el1, x0 isb /* --------------------------------------------- * Enable the SError interrupt now that the * exception vectors have been setup. * --------------------------------------------- */ msr daifclr, #DAIF_ABT_BIT /* --------------------------------------------- * Enable the instruction cache, stack pointer * and data access alignment checks and disable * speculative loads. * --------------------------------------------- */ mov x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT) mrs x0, sctlr_el1 orr x0, x0, x1 bic x0, x0, #SCTLR_DSSBS_BIT msr sctlr_el1, x0 isb /* --------------------------------------------- * Invalidate the RW memory used by the BL32 * image. This includes the data and NOBITS * sections. This is done to safeguard against * possible corruption of this memory by dirty * cache lines in a system cache as a result of * use by an earlier boot loader stage. * --------------------------------------------- */ adr x0, __RW_START__ adr x1, __RW_END__ sub x1, x1, x0 bl inv_dcache_range /* --------------------------------------------- * Zero out NOBITS sections. There are 2 of them: * - the .bss section; * - the coherent memory section. * --------------------------------------------- */ ldr x0, =__BSS_START__ ldr x1, =__BSS_SIZE__ bl zeromem #if USE_COHERENT_MEM ldr x0, =__COHERENT_RAM_START__ ldr x1, =__COHERENT_RAM_UNALIGNED_SIZE__ bl zeromem #endif /* -------------------------------------------- * Allocate a stack whose memory will be marked * as Normal-IS-WBWA when the MMU is enabled. * There is no risk of reading stale stack * memory after enabling the MMU as only the * primary cpu is running at the moment. * -------------------------------------------- */ bl plat_set_my_stack /* --------------------------------------------- * Initialize the stack protector canary before * any C code is called. * --------------------------------------------- */ #if STACK_PROTECTOR_ENABLED bl update_stack_protector_canary #endif /* --------------------------------------------- * Perform TSP setup * --------------------------------------------- */ bl tsp_setup #if ENABLE_PAUTH /* --------------------------------------------- * Program APIAKey_EL1 * and enable pointer authentication * --------------------------------------------- */ bl pauth_init_enable_el1 #endif /* ENABLE_PAUTH */ /* --------------------------------------------- * Jump to main function. * --------------------------------------------- */ bl tsp_main /* --------------------------------------------- * Tell TSPD that we are done initialising * --------------------------------------------- */ mov x1, x0 mov x0, #TSP_ENTRY_DONE smc #0 tsp_entrypoint_panic: b tsp_entrypoint_panic endfunc tsp_entrypoint /* ------------------------------------------- * Table of entrypoint vectors provided to the * TSPD for the various entrypoints * ------------------------------------------- */ vector_base tsp_vector_table b tsp_yield_smc_entry b tsp_fast_smc_entry b tsp_cpu_on_entry b tsp_cpu_off_entry b tsp_cpu_resume_entry b tsp_cpu_suspend_entry b tsp_sel1_intr_entry b tsp_system_off_entry b tsp_system_reset_entry b tsp_abort_yield_smc_entry /*--------------------------------------------- * This entrypoint is used by the TSPD when this * cpu is to be turned off through a CPU_OFF * psci call to ask the TSP to perform any * bookeeping necessary. In the current * implementation, the TSPD expects the TSP to * re-initialise its state so nothing is done * here except for acknowledging the request. * --------------------------------------------- */ func tsp_cpu_off_entry bl tsp_cpu_off_main restore_args_call_smc endfunc tsp_cpu_off_entry /*--------------------------------------------- * This entrypoint is used by the TSPD when the * system is about to be switched off (through * a SYSTEM_OFF psci call) to ask the TSP to * perform any necessary bookkeeping. * --------------------------------------------- */ func tsp_system_off_entry bl tsp_system_off_main restore_args_call_smc endfunc tsp_system_off_entry /*--------------------------------------------- * This entrypoint is used by the TSPD when the * system is about to be reset (through a * SYSTEM_RESET psci call) to ask the TSP to * perform any necessary bookkeeping. * --------------------------------------------- */ func tsp_system_reset_entry bl tsp_system_reset_main restore_args_call_smc endfunc tsp_system_reset_entry /*--------------------------------------------- * This entrypoint is used by the TSPD when this * cpu is turned on using a CPU_ON psci call to * ask the TSP to initialise itself i.e. setup * the mmu, stacks etc. Minimal architectural * state will be initialised by the TSPD when * this function is entered i.e. Caches and MMU * will be turned off, the execution state * will be aarch64 and exceptions masked. * --------------------------------------------- */ func tsp_cpu_on_entry /* --------------------------------------------- * Set the exception vector to something sane. * --------------------------------------------- */ adr x0, tsp_exceptions msr vbar_el1, x0 isb /* Enable the SError interrupt */ msr daifclr, #DAIF_ABT_BIT /* --------------------------------------------- * Enable the instruction cache, stack pointer * and data access alignment checks * --------------------------------------------- */ mov x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT) mrs x0, sctlr_el1 orr x0, x0, x1 msr sctlr_el1, x0 isb /* -------------------------------------------- * Give ourselves a stack whose memory will be * marked as Normal-IS-WBWA when the MMU is * enabled. * -------------------------------------------- */ bl plat_set_my_stack /* -------------------------------------------- * Enable MMU and D-caches together. * -------------------------------------------- */ mov x0, #0 bl bl32_plat_enable_mmu #if ENABLE_PAUTH /* --------------------------------------------- * Program APIAKey_EL1 * and enable pointer authentication * --------------------------------------------- */ bl pauth_init_enable_el1 #endif /* ENABLE_PAUTH */ /* --------------------------------------------- * Enter C runtime to perform any remaining * book keeping * --------------------------------------------- */ bl tsp_cpu_on_main restore_args_call_smc /* Should never reach here */ tsp_cpu_on_entry_panic: b tsp_cpu_on_entry_panic endfunc tsp_cpu_on_entry /*--------------------------------------------- * This entrypoint is used by the TSPD when this * cpu is to be suspended through a CPU_SUSPEND * psci call to ask the TSP to perform any * bookeeping necessary. In the current * implementation, the TSPD saves and restores * the EL1 state. * --------------------------------------------- */ func tsp_cpu_suspend_entry bl tsp_cpu_suspend_main restore_args_call_smc endfunc tsp_cpu_suspend_entry /*------------------------------------------------- * This entrypoint is used by the TSPD to pass * control for `synchronously` handling a S-EL1 * Interrupt which was triggered while executing * in normal world. 'x0' contains a magic number * which indicates this. TSPD expects control to * be handed back at the end of interrupt * processing. This is done through an SMC. * The handover agreement is: * * 1. PSTATE.DAIF are set upon entry. 'x1' has * the ELR_EL3 from the non-secure state. * 2. TSP has to preserve the callee saved * general purpose registers, SP_EL1/EL0 and * LR. * 3. TSP has to preserve the system and vfp * registers (if applicable). * 4. TSP can use 'x0-x18' to enable its C * runtime. * 5. TSP returns to TSPD using an SMC with * 'x0' = TSP_HANDLED_S_EL1_INTR * ------------------------------------------------ */ func tsp_sel1_intr_entry #if DEBUG mov_imm x2, TSP_HANDLE_SEL1_INTR_AND_RETURN cmp x0, x2 b.ne tsp_sel1_int_entry_panic #endif /*------------------------------------------------- * Save any previous context needed to perform * an exception return from S-EL1 e.g. context * from a previous Non secure Interrupt. * Update statistics and handle the S-EL1 * interrupt before returning to the TSPD. * IRQ/FIQs are not enabled since that will * complicate the implementation. Execution * will be transferred back to the normal world * in any case. The handler can return 0 * if the interrupt was handled or TSP_PREEMPTED * if the expected interrupt was preempted * by an interrupt that should be handled in EL3 * e.g. Group 0 interrupt in GICv3. In both * the cases switch to EL3 using SMC with id * TSP_HANDLED_S_EL1_INTR. Any other return value * from the handler will result in panic. * ------------------------------------------------ */ save_eret_context x2 x3 bl tsp_update_sync_sel1_intr_stats bl tsp_common_int_handler /* Check if the S-EL1 interrupt has been handled */ cbnz x0, tsp_sel1_intr_check_preemption b tsp_sel1_intr_return tsp_sel1_intr_check_preemption: /* Check if the S-EL1 interrupt has been preempted */ mov_imm x1, TSP_PREEMPTED cmp x0, x1 b.ne tsp_sel1_int_entry_panic tsp_sel1_intr_return: mov_imm x0, TSP_HANDLED_S_EL1_INTR restore_eret_context x2 x3 smc #0 /* Should never reach here */ tsp_sel1_int_entry_panic: no_ret plat_panic_handler endfunc tsp_sel1_intr_entry /*--------------------------------------------- * This entrypoint is used by the TSPD when this * cpu resumes execution after an earlier * CPU_SUSPEND psci call to ask the TSP to * restore its saved context. In the current * implementation, the TSPD saves and restores * EL1 state so nothing is done here apart from * acknowledging the request. * --------------------------------------------- */ func tsp_cpu_resume_entry bl tsp_cpu_resume_main restore_args_call_smc /* Should never reach here */ no_ret plat_panic_handler endfunc tsp_cpu_resume_entry /*--------------------------------------------- * This entrypoint is used by the TSPD to ask * the TSP to service a fast smc request. * --------------------------------------------- */ func tsp_fast_smc_entry bl tsp_smc_handler restore_args_call_smc /* Should never reach here */ no_ret plat_panic_handler endfunc tsp_fast_smc_entry /*--------------------------------------------- * This entrypoint is used by the TSPD to ask * the TSP to service a Yielding SMC request. * We will enable preemption during execution * of tsp_smc_handler. * --------------------------------------------- */ func tsp_yield_smc_entry msr daifclr, #DAIF_FIQ_BIT | DAIF_IRQ_BIT bl tsp_smc_handler msr daifset, #DAIF_FIQ_BIT | DAIF_IRQ_BIT restore_args_call_smc /* Should never reach here */ no_ret plat_panic_handler endfunc tsp_yield_smc_entry /*--------------------------------------------------------------------- * This entrypoint is used by the TSPD to abort a pre-empted Yielding * SMC. It could be on behalf of non-secure world or because a CPU * suspend/CPU off request needs to abort the preempted SMC. * -------------------------------------------------------------------- */ func tsp_abort_yield_smc_entry /* * Exceptions masking is already done by the TSPD when entering this * hook so there is no need to do it here. */ /* Reset the stack used by the pre-empted SMC */ bl plat_set_my_stack /* * Allow some cleanup such as releasing locks. */ bl tsp_abort_smc_handler restore_args_call_smc /* Should never reach here */ bl plat_panic_handler endfunc tsp_abort_yield_smc_entry trusted-firmware-a-2.2/bl32/tsp/aarch64/tsp_exceptions.S000066400000000000000000000100001355360272700230730ustar00rootroot00000000000000/* * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /* ---------------------------------------------------- * The caller-saved registers x0-x18 and LR are saved * here. * ---------------------------------------------------- */ #define SCRATCH_REG_SIZE #(20 * 8) .macro save_caller_regs_and_lr sub sp, sp, SCRATCH_REG_SIZE stp x0, x1, [sp] stp x2, x3, [sp, #0x10] stp x4, x5, [sp, #0x20] stp x6, x7, [sp, #0x30] stp x8, x9, [sp, #0x40] stp x10, x11, [sp, #0x50] stp x12, x13, [sp, #0x60] stp x14, x15, [sp, #0x70] stp x16, x17, [sp, #0x80] stp x18, x30, [sp, #0x90] .endm .macro restore_caller_regs_and_lr ldp x0, x1, [sp] ldp x2, x3, [sp, #0x10] ldp x4, x5, [sp, #0x20] ldp x6, x7, [sp, #0x30] ldp x8, x9, [sp, #0x40] ldp x10, x11, [sp, #0x50] ldp x12, x13, [sp, #0x60] ldp x14, x15, [sp, #0x70] ldp x16, x17, [sp, #0x80] ldp x18, x30, [sp, #0x90] add sp, sp, SCRATCH_REG_SIZE .endm /* ---------------------------------------------------- * Common TSP interrupt handling routine * ---------------------------------------------------- */ .macro handle_tsp_interrupt label /* Enable the SError interrupt */ msr daifclr, #DAIF_ABT_BIT save_caller_regs_and_lr bl tsp_common_int_handler cbz x0, interrupt_exit_\label /* * This interrupt was not targetted to S-EL1 so send it to * the monitor and wait for execution to resume. */ smc #0 interrupt_exit_\label: restore_caller_regs_and_lr eret .endm .globl tsp_exceptions /* ----------------------------------------------------- * TSP exception handlers. * ----------------------------------------------------- */ vector_base tsp_exceptions /* ----------------------------------------------------- * Current EL with _sp_el0 : 0x0 - 0x200. No exceptions * are expected and treated as irrecoverable errors. * ----------------------------------------------------- */ vector_entry sync_exception_sp_el0 b plat_panic_handler end_vector_entry sync_exception_sp_el0 vector_entry irq_sp_el0 b plat_panic_handler end_vector_entry irq_sp_el0 vector_entry fiq_sp_el0 b plat_panic_handler end_vector_entry fiq_sp_el0 vector_entry serror_sp_el0 b plat_panic_handler end_vector_entry serror_sp_el0 /* ----------------------------------------------------- * Current EL with SPx: 0x200 - 0x400. Only IRQs/FIQs * are expected and handled * ----------------------------------------------------- */ vector_entry sync_exception_sp_elx b plat_panic_handler end_vector_entry sync_exception_sp_elx vector_entry irq_sp_elx handle_tsp_interrupt irq_sp_elx end_vector_entry irq_sp_elx vector_entry fiq_sp_elx handle_tsp_interrupt fiq_sp_elx end_vector_entry fiq_sp_elx vector_entry serror_sp_elx b plat_panic_handler end_vector_entry serror_sp_elx /* ----------------------------------------------------- * Lower EL using AArch64 : 0x400 - 0x600. No exceptions * are handled since TSP does not implement a lower EL * ----------------------------------------------------- */ vector_entry sync_exception_aarch64 b plat_panic_handler end_vector_entry sync_exception_aarch64 vector_entry irq_aarch64 b plat_panic_handler end_vector_entry irq_aarch64 vector_entry fiq_aarch64 b plat_panic_handler end_vector_entry fiq_aarch64 vector_entry serror_aarch64 b plat_panic_handler end_vector_entry serror_aarch64 /* ----------------------------------------------------- * Lower EL using AArch32 : 0x600 - 0x800. No exceptions * handled since the TSP does not implement a lower EL. * ----------------------------------------------------- */ vector_entry sync_exception_aarch32 b plat_panic_handler end_vector_entry sync_exception_aarch32 vector_entry irq_aarch32 b plat_panic_handler end_vector_entry irq_aarch32 vector_entry fiq_aarch32 b plat_panic_handler end_vector_entry fiq_aarch32 vector_entry serror_aarch32 b plat_panic_handler end_vector_entry serror_aarch32 trusted-firmware-a-2.2/bl32/tsp/aarch64/tsp_request.S000066400000000000000000000013531355360272700224150ustar00rootroot00000000000000/* * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .globl tsp_get_magic /* * This function raises an SMC to retrieve arguments from secure * monitor/dispatcher, saves the returned arguments the array received in x0, * and then returns to the caller */ func tsp_get_magic /* Save address to stack */ stp x0, xzr, [sp, #-16]! /* Load arguments */ ldr w0, _tsp_fid_get_magic /* Raise SMC */ smc #0 /* Restore address from stack */ ldp x4, xzr, [sp], #16 /* Store returned arguments to the array */ stp x0, x1, [x4, #0] ret endfunc tsp_get_magic .align 2 _tsp_fid_get_magic: .word TSP_GET_ARGS trusted-firmware-a-2.2/bl32/tsp/tsp.ld.S000066400000000000000000000070451355360272700200170ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT) OUTPUT_ARCH(PLATFORM_LINKER_ARCH) ENTRY(tsp_entrypoint) MEMORY { RAM (rwx): ORIGIN = TSP_SEC_MEM_BASE, LENGTH = TSP_SEC_MEM_SIZE } SECTIONS { . = BL32_BASE; ASSERT(. == ALIGN(PAGE_SIZE), "BL32_BASE address is not aligned on a page boundary.") #if SEPARATE_CODE_AND_RODATA .text . : { __TEXT_START__ = .; *tsp_entrypoint.o(.text*) *(.text*) *(.vectors) . = ALIGN(PAGE_SIZE); __TEXT_END__ = .; } >RAM .rodata . : { __RODATA_START__ = .; *(.rodata*) . = ALIGN(PAGE_SIZE); __RODATA_END__ = .; } >RAM #else ro . : { __RO_START__ = .; *tsp_entrypoint.o(.text*) *(.text*) *(.rodata*) *(.vectors) __RO_END_UNALIGNED__ = .; /* * Memory page(s) mapped to this section will be marked as * read-only, executable. No RW data from the next section must * creep in. Ensure the rest of the current memory page is unused. */ . = ALIGN(PAGE_SIZE); __RO_END__ = .; } >RAM #endif /* * Define a linker symbol to mark start of the RW memory area for this * image. */ __RW_START__ = . ; .data . : { __DATA_START__ = .; *(.data*) __DATA_END__ = .; } >RAM #ifdef TSP_PROGBITS_LIMIT ASSERT(. <= TSP_PROGBITS_LIMIT, "TSP progbits has exceeded its limit.") #endif stacks (NOLOAD) : { __STACKS_START__ = .; *(tzfw_normal_stacks) __STACKS_END__ = .; } >RAM /* * The .bss section gets initialised to 0 at runtime. * Its base address should be 16-byte aligned for better performance of the * zero-initialization code. */ .bss : ALIGN(16) { __BSS_START__ = .; *(SORT_BY_ALIGNMENT(.bss*)) *(COMMON) __BSS_END__ = .; } >RAM /* * The xlat_table section is for full, aligned page tables (4K). * Removing them from .bss avoids forcing 4K alignment on * the .bss section. The tables are initialized to zero by the translation * tables library. */ xlat_table (NOLOAD) : { *(xlat_table) } >RAM #if USE_COHERENT_MEM /* * The base address of the coherent memory section must be page-aligned (4K) * to guarantee that the coherent data are stored on their own pages and * are not mixed with normal data. This is required to set up the correct * memory attributes for the coherent data page tables. */ coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) { __COHERENT_RAM_START__ = .; *(tzfw_coherent_mem) __COHERENT_RAM_END_UNALIGNED__ = .; /* * Memory page(s) mapped to this section will be marked * as device memory. No other unexpected data must creep in. * Ensure the rest of the current memory page is unused. */ . = ALIGN(PAGE_SIZE); __COHERENT_RAM_END__ = .; } >RAM #endif /* * Define a linker symbol to mark the end of the RW memory area for this * image. */ __RW_END__ = .; __BL32_END__ = .; __BSS_SIZE__ = SIZEOF(.bss); #if USE_COHERENT_MEM __COHERENT_RAM_UNALIGNED_SIZE__ = __COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__; #endif ASSERT(. <= BL32_LIMIT, "BL32 image has exceeded its limit.") } trusted-firmware-a-2.2/bl32/tsp/tsp.mk000066400000000000000000000021471355360272700176240ustar00rootroot00000000000000# # Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # INCLUDES += -Iinclude/bl32/tsp BL32_SOURCES += bl32/tsp/tsp_main.c \ bl32/tsp/aarch64/tsp_entrypoint.S \ bl32/tsp/aarch64/tsp_exceptions.S \ bl32/tsp/aarch64/tsp_request.S \ bl32/tsp/tsp_interrupt.c \ bl32/tsp/tsp_timer.c \ common/aarch64/early_exceptions.S \ lib/locks/exclusive/aarch64/spinlock.S BL32_LINKERFILE := bl32/tsp/tsp.ld.S # This flag determines if the TSPD initializes BL32 in tspd_init() (synchronous # method) or configures BL31 to pass control to BL32 instead of BL33 # (asynchronous method). TSP_INIT_ASYNC := 0 $(eval $(call assert_boolean,TSP_INIT_ASYNC)) $(eval $(call add_define,TSP_INIT_ASYNC)) # Include the platform-specific TSP Makefile # If no platform-specific TSP Makefile exists, it means TSP is not supported # on this platform. TSP_PLAT_MAKEFILE := $(wildcard ${PLAT_DIR}/tsp/tsp-${PLAT}.mk) ifeq (,${TSP_PLAT_MAKEFILE}) $(error TSP is not supported on platform ${PLAT}) else include ${TSP_PLAT_MAKEFILE} endif trusted-firmware-a-2.2/bl32/tsp/tsp_interrupt.c000066400000000000000000000105721355360272700215540ustar00rootroot00000000000000/* * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "tsp_private.h" /******************************************************************************* * This function updates the TSP statistics for S-EL1 interrupts handled * synchronously i.e the ones that have been handed over by the TSPD. It also * keeps count of the number of times control was passed back to the TSPD * after handling the interrupt. In the future it will be possible that the * TSPD hands over an S-EL1 interrupt to the TSP but does not expect it to * return execution. This statistic will be useful to distinguish between these * two models of synchronous S-EL1 interrupt handling. The 'elr_el3' parameter * contains the address of the instruction in normal world where this S-EL1 * interrupt was generated. ******************************************************************************/ void tsp_update_sync_sel1_intr_stats(uint32_t type, uint64_t elr_el3) { uint32_t linear_id = plat_my_core_pos(); tsp_stats[linear_id].sync_sel1_intr_count++; if (type == TSP_HANDLE_SEL1_INTR_AND_RETURN) tsp_stats[linear_id].sync_sel1_intr_ret_count++; #if LOG_LEVEL >= LOG_LEVEL_VERBOSE spin_lock(&console_lock); VERBOSE("TSP: cpu 0x%lx sync s-el1 interrupt request from 0x%llx\n", read_mpidr(), elr_el3); VERBOSE("TSP: cpu 0x%lx: %d sync s-el1 interrupt requests," " %d sync s-el1 interrupt returns\n", read_mpidr(), tsp_stats[linear_id].sync_sel1_intr_count, tsp_stats[linear_id].sync_sel1_intr_ret_count); spin_unlock(&console_lock); #endif } /****************************************************************************** * This function is invoked when a non S-EL1 interrupt is received and causes * the preemption of TSP. This function returns TSP_PREEMPTED and results * in the control being handed over to EL3 for handling the interrupt. *****************************************************************************/ int32_t tsp_handle_preemption(void) { uint32_t linear_id = plat_my_core_pos(); tsp_stats[linear_id].preempt_intr_count++; #if LOG_LEVEL >= LOG_LEVEL_VERBOSE spin_lock(&console_lock); VERBOSE("TSP: cpu 0x%lx: %d preempt interrupt requests\n", read_mpidr(), tsp_stats[linear_id].preempt_intr_count); spin_unlock(&console_lock); #endif return TSP_PREEMPTED; } /******************************************************************************* * TSP interrupt handler is called as a part of both synchronous and * asynchronous handling of TSP interrupts. Currently the physical timer * interrupt is the only S-EL1 interrupt that this handler expects. It returns * 0 upon successfully handling the expected interrupt and all other * interrupts are treated as normal world or EL3 interrupts. ******************************************************************************/ int32_t tsp_common_int_handler(void) { uint32_t linear_id = plat_my_core_pos(), id; /* * Get the highest priority pending interrupt id and see if it is the * secure physical generic timer interrupt in which case, handle it. * Otherwise throw this interrupt at the EL3 firmware. * * There is a small time window between reading the highest priority * pending interrupt and acknowledging it during which another * interrupt of higher priority could become the highest pending * interrupt. This is not expected to happen currently for TSP. */ id = plat_ic_get_pending_interrupt_id(); /* TSP can only handle the secure physical timer interrupt */ if (id != TSP_IRQ_SEC_PHY_TIMER) return tsp_handle_preemption(); /* * Acknowledge and handle the secure timer interrupt. Also sanity check * if it has been preempted by another interrupt through an assertion. */ id = plat_ic_acknowledge_interrupt(); assert(id == TSP_IRQ_SEC_PHY_TIMER); tsp_generic_timer_handler(); plat_ic_end_of_interrupt(id); /* Update the statistics and print some messages */ tsp_stats[linear_id].sel1_intr_count++; #if LOG_LEVEL >= LOG_LEVEL_VERBOSE spin_lock(&console_lock); VERBOSE("TSP: cpu 0x%lx handled S-EL1 interrupt %d\n", read_mpidr(), id); VERBOSE("TSP: cpu 0x%lx: %d S-EL1 requests\n", read_mpidr(), tsp_stats[linear_id].sel1_intr_count); spin_unlock(&console_lock); #endif return 0; } trusted-firmware-a-2.2/bl32/tsp/tsp_main.c000066400000000000000000000345161355360272700204500ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "tsp_private.h" /******************************************************************************* * Lock to control access to the console ******************************************************************************/ spinlock_t console_lock; /******************************************************************************* * Per cpu data structure to populate parameters for an SMC in C code and use * a pointer to this structure in assembler code to populate x0-x7 ******************************************************************************/ static tsp_args_t tsp_smc_args[PLATFORM_CORE_COUNT]; /******************************************************************************* * Per cpu data structure to keep track of TSP activity ******************************************************************************/ work_statistics_t tsp_stats[PLATFORM_CORE_COUNT]; /******************************************************************************* * The TSP memory footprint starts at address BL32_BASE and ends with the * linker symbol __BL32_END__. Use these addresses to compute the TSP image * size. ******************************************************************************/ #define BL32_TOTAL_LIMIT BL32_END #define BL32_TOTAL_SIZE (BL32_TOTAL_LIMIT - (unsigned long) BL32_BASE) static tsp_args_t *set_smc_args(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7) { uint32_t linear_id; tsp_args_t *pcpu_smc_args; /* * Return to Secure Monitor by raising an SMC. The results of the * service are passed as an arguments to the SMC */ linear_id = plat_my_core_pos(); pcpu_smc_args = &tsp_smc_args[linear_id]; write_sp_arg(pcpu_smc_args, TSP_ARG0, arg0); write_sp_arg(pcpu_smc_args, TSP_ARG1, arg1); write_sp_arg(pcpu_smc_args, TSP_ARG2, arg2); write_sp_arg(pcpu_smc_args, TSP_ARG3, arg3); write_sp_arg(pcpu_smc_args, TSP_ARG4, arg4); write_sp_arg(pcpu_smc_args, TSP_ARG5, arg5); write_sp_arg(pcpu_smc_args, TSP_ARG6, arg6); write_sp_arg(pcpu_smc_args, TSP_ARG7, arg7); return pcpu_smc_args; } /******************************************************************************* * Setup function for TSP. ******************************************************************************/ void tsp_setup(void) { /* Perform early platform-specific setup */ tsp_early_platform_setup(); /* Perform late platform-specific setup */ tsp_plat_arch_setup(); #if ENABLE_PAUTH /* * Assert that the ARMv8.3-PAuth registers are present or an access * fault will be triggered when they are being saved or restored. */ assert(is_armv8_3_pauth_present()); #endif /* ENABLE_PAUTH */ } /******************************************************************************* * TSP main entry point where it gets the opportunity to initialize its secure * state/applications. Once the state is initialized, it must return to the * SPD with a pointer to the 'tsp_vector_table' jump table. ******************************************************************************/ uint64_t tsp_main(void) { NOTICE("TSP: %s\n", version_string); NOTICE("TSP: %s\n", build_message); INFO("TSP: Total memory base : 0x%lx\n", (unsigned long) BL32_BASE); INFO("TSP: Total memory size : 0x%lx bytes\n", BL32_TOTAL_SIZE); uint32_t linear_id = plat_my_core_pos(); /* Initialize the platform */ tsp_platform_setup(); /* Initialize secure/applications state here */ tsp_generic_timer_start(); /* Update this cpu's statistics */ tsp_stats[linear_id].smc_count++; tsp_stats[linear_id].eret_count++; tsp_stats[linear_id].cpu_on_count++; #if LOG_LEVEL >= LOG_LEVEL_INFO spin_lock(&console_lock); INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu on requests\n", read_mpidr(), tsp_stats[linear_id].smc_count, tsp_stats[linear_id].eret_count, tsp_stats[linear_id].cpu_on_count); spin_unlock(&console_lock); #endif return (uint64_t) &tsp_vector_table; } /******************************************************************************* * This function performs any remaining book keeping in the test secure payload * after this cpu's architectural state has been setup in response to an earlier * psci cpu_on request. ******************************************************************************/ tsp_args_t *tsp_cpu_on_main(void) { uint32_t linear_id = plat_my_core_pos(); /* Initialize secure/applications state here */ tsp_generic_timer_start(); /* Update this cpu's statistics */ tsp_stats[linear_id].smc_count++; tsp_stats[linear_id].eret_count++; tsp_stats[linear_id].cpu_on_count++; #if LOG_LEVEL >= LOG_LEVEL_INFO spin_lock(&console_lock); INFO("TSP: cpu 0x%lx turned on\n", read_mpidr()); INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu on requests\n", read_mpidr(), tsp_stats[linear_id].smc_count, tsp_stats[linear_id].eret_count, tsp_stats[linear_id].cpu_on_count); spin_unlock(&console_lock); #endif /* Indicate to the SPD that we have completed turned ourselves on */ return set_smc_args(TSP_ON_DONE, 0, 0, 0, 0, 0, 0, 0); } /******************************************************************************* * This function performs any remaining book keeping in the test secure payload * before this cpu is turned off in response to a psci cpu_off request. ******************************************************************************/ tsp_args_t *tsp_cpu_off_main(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7) { uint32_t linear_id = plat_my_core_pos(); /* * This cpu is being turned off, so disable the timer to prevent the * secure timer interrupt from interfering with power down. A pending * interrupt will be lost but we do not care as we are turning off. */ tsp_generic_timer_stop(); /* Update this cpu's statistics */ tsp_stats[linear_id].smc_count++; tsp_stats[linear_id].eret_count++; tsp_stats[linear_id].cpu_off_count++; #if LOG_LEVEL >= LOG_LEVEL_INFO spin_lock(&console_lock); INFO("TSP: cpu 0x%lx off request\n", read_mpidr()); INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu off requests\n", read_mpidr(), tsp_stats[linear_id].smc_count, tsp_stats[linear_id].eret_count, tsp_stats[linear_id].cpu_off_count); spin_unlock(&console_lock); #endif /* Indicate to the SPD that we have completed this request */ return set_smc_args(TSP_OFF_DONE, 0, 0, 0, 0, 0, 0, 0); } /******************************************************************************* * This function performs any book keeping in the test secure payload before * this cpu's architectural state is saved in response to an earlier psci * cpu_suspend request. ******************************************************************************/ tsp_args_t *tsp_cpu_suspend_main(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7) { uint32_t linear_id = plat_my_core_pos(); /* * Save the time context and disable it to prevent the secure timer * interrupt from interfering with wakeup from the suspend state. */ tsp_generic_timer_save(); tsp_generic_timer_stop(); /* Update this cpu's statistics */ tsp_stats[linear_id].smc_count++; tsp_stats[linear_id].eret_count++; tsp_stats[linear_id].cpu_suspend_count++; #if LOG_LEVEL >= LOG_LEVEL_INFO spin_lock(&console_lock); INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu suspend requests\n", read_mpidr(), tsp_stats[linear_id].smc_count, tsp_stats[linear_id].eret_count, tsp_stats[linear_id].cpu_suspend_count); spin_unlock(&console_lock); #endif /* Indicate to the SPD that we have completed this request */ return set_smc_args(TSP_SUSPEND_DONE, 0, 0, 0, 0, 0, 0, 0); } /******************************************************************************* * This function performs any book keeping in the test secure payload after this * cpu's architectural state has been restored after wakeup from an earlier psci * cpu_suspend request. ******************************************************************************/ tsp_args_t *tsp_cpu_resume_main(uint64_t max_off_pwrlvl, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7) { uint32_t linear_id = plat_my_core_pos(); /* Restore the generic timer context */ tsp_generic_timer_restore(); /* Update this cpu's statistics */ tsp_stats[linear_id].smc_count++; tsp_stats[linear_id].eret_count++; tsp_stats[linear_id].cpu_resume_count++; #if LOG_LEVEL >= LOG_LEVEL_INFO spin_lock(&console_lock); INFO("TSP: cpu 0x%lx resumed. maximum off power level %lld\n", read_mpidr(), max_off_pwrlvl); INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu suspend requests\n", read_mpidr(), tsp_stats[linear_id].smc_count, tsp_stats[linear_id].eret_count, tsp_stats[linear_id].cpu_suspend_count); spin_unlock(&console_lock); #endif /* Indicate to the SPD that we have completed this request */ return set_smc_args(TSP_RESUME_DONE, 0, 0, 0, 0, 0, 0, 0); } /******************************************************************************* * This function performs any remaining bookkeeping in the test secure payload * before the system is switched off (in response to a psci SYSTEM_OFF request) ******************************************************************************/ tsp_args_t *tsp_system_off_main(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7) { uint32_t linear_id = plat_my_core_pos(); /* Update this cpu's statistics */ tsp_stats[linear_id].smc_count++; tsp_stats[linear_id].eret_count++; #if LOG_LEVEL >= LOG_LEVEL_INFO spin_lock(&console_lock); INFO("TSP: cpu 0x%lx SYSTEM_OFF request\n", read_mpidr()); INFO("TSP: cpu 0x%lx: %d smcs, %d erets requests\n", read_mpidr(), tsp_stats[linear_id].smc_count, tsp_stats[linear_id].eret_count); spin_unlock(&console_lock); #endif /* Indicate to the SPD that we have completed this request */ return set_smc_args(TSP_SYSTEM_OFF_DONE, 0, 0, 0, 0, 0, 0, 0); } /******************************************************************************* * This function performs any remaining bookkeeping in the test secure payload * before the system is reset (in response to a psci SYSTEM_RESET request) ******************************************************************************/ tsp_args_t *tsp_system_reset_main(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7) { uint32_t linear_id = plat_my_core_pos(); /* Update this cpu's statistics */ tsp_stats[linear_id].smc_count++; tsp_stats[linear_id].eret_count++; #if LOG_LEVEL >= LOG_LEVEL_INFO spin_lock(&console_lock); INFO("TSP: cpu 0x%lx SYSTEM_RESET request\n", read_mpidr()); INFO("TSP: cpu 0x%lx: %d smcs, %d erets requests\n", read_mpidr(), tsp_stats[linear_id].smc_count, tsp_stats[linear_id].eret_count); spin_unlock(&console_lock); #endif /* Indicate to the SPD that we have completed this request */ return set_smc_args(TSP_SYSTEM_RESET_DONE, 0, 0, 0, 0, 0, 0, 0); } /******************************************************************************* * TSP fast smc handler. The secure monitor jumps to this function by * doing the ERET after populating X0-X7 registers. The arguments are received * in the function arguments in order. Once the service is rendered, this * function returns to Secure Monitor by raising SMC. ******************************************************************************/ tsp_args_t *tsp_smc_handler(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7) { uint64_t results[2]; uint64_t service_args[2]; uint32_t linear_id = plat_my_core_pos(); /* Update this cpu's statistics */ tsp_stats[linear_id].smc_count++; tsp_stats[linear_id].eret_count++; INFO("TSP: cpu 0x%lx received %s smc 0x%llx\n", read_mpidr(), ((func >> 31) & 1) == 1 ? "fast" : "yielding", func); INFO("TSP: cpu 0x%lx: %d smcs, %d erets\n", read_mpidr(), tsp_stats[linear_id].smc_count, tsp_stats[linear_id].eret_count); /* Render secure services and obtain results here */ results[0] = arg1; results[1] = arg2; /* * Request a service back from dispatcher/secure monitor. This call * return and thereafter resume execution */ tsp_get_magic(service_args); #if CTX_INCLUDE_MTE_REGS /* * Write a dummy value to an MTE register, to simulate usage in the * secure world */ write_gcr_el1(0x99); #endif /* Determine the function to perform based on the function ID */ switch (TSP_BARE_FID(func)) { case TSP_ADD: results[0] += service_args[0]; results[1] += service_args[1]; break; case TSP_SUB: results[0] -= service_args[0]; results[1] -= service_args[1]; break; case TSP_MUL: results[0] *= service_args[0]; results[1] *= service_args[1]; break; case TSP_DIV: results[0] /= service_args[0] ? service_args[0] : 1; results[1] /= service_args[1] ? service_args[1] : 1; break; default: break; } return set_smc_args(func, 0, results[0], results[1], 0, 0, 0, 0); } /******************************************************************************* * TSP smc abort handler. This function is called when aborting a preempted * yielding SMC request. It should cleanup all resources owned by the SMC * handler such as locks or dynamically allocated memory so following SMC * request are executed in a clean environment. ******************************************************************************/ tsp_args_t *tsp_abort_smc_handler(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7) { return set_smc_args(TSP_ABORT_DONE, 0, 0, 0, 0, 0, 0, 0); } trusted-firmware-a-2.2/bl32/tsp/tsp_private.h000066400000000000000000000100571355360272700211750ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TSP_PRIVATE_H #define TSP_PRIVATE_H /* Definitions to help the assembler access the SMC/ERET args structure */ #define TSP_ARGS_SIZE 0x40 #define TSP_ARG0 0x0 #define TSP_ARG1 0x8 #define TSP_ARG2 0x10 #define TSP_ARG3 0x18 #define TSP_ARG4 0x20 #define TSP_ARG5 0x28 #define TSP_ARG6 0x30 #define TSP_ARG7 0x38 #define TSP_ARGS_END 0x40 #ifndef __ASSEMBLER__ #include #include /* For CACHE_WRITEBACK_GRANULE */ #include #include #include typedef struct work_statistics { /* Number of s-el1 interrupts on this cpu */ uint32_t sel1_intr_count; /* Number of non s-el1 interrupts on this cpu which preempted TSP */ uint32_t preempt_intr_count; /* Number of sync s-el1 interrupts on this cpu */ uint32_t sync_sel1_intr_count; /* Number of s-el1 interrupts returns on this cpu */ uint32_t sync_sel1_intr_ret_count; uint32_t smc_count; /* Number of returns on this cpu */ uint32_t eret_count; /* Number of entries on this cpu */ uint32_t cpu_on_count; /* Number of cpu on requests */ uint32_t cpu_off_count; /* Number of cpu off requests */ uint32_t cpu_suspend_count; /* Number of cpu suspend requests */ uint32_t cpu_resume_count; /* Number of cpu resume requests */ } __aligned(CACHE_WRITEBACK_GRANULE) work_statistics_t; typedef struct tsp_args { uint64_t _regs[TSP_ARGS_END >> 3]; } __aligned(CACHE_WRITEBACK_GRANULE) tsp_args_t; /* Macros to access members of the above structure using their offsets */ #define read_sp_arg(args, offset) ((args)->_regs[offset >> 3]) #define write_sp_arg(args, offset, val) (((args)->_regs[offset >> 3]) \ = val) /* * Ensure that the assembler's view of the size of the tsp_args is the * same as the compilers */ CASSERT(TSP_ARGS_SIZE == sizeof(tsp_args_t), assert_sp_args_size_mismatch); void tsp_get_magic(uint64_t args[4]); tsp_args_t *tsp_cpu_resume_main(uint64_t max_off_pwrlvl, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7); tsp_args_t *tsp_cpu_suspend_main(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7); tsp_args_t *tsp_cpu_on_main(void); tsp_args_t *tsp_cpu_off_main(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7); /* Generic Timer functions */ void tsp_generic_timer_start(void); void tsp_generic_timer_handler(void); void tsp_generic_timer_stop(void); void tsp_generic_timer_save(void); void tsp_generic_timer_restore(void); /* S-EL1 interrupt management functions */ void tsp_update_sync_sel1_intr_stats(uint32_t type, uint64_t elr_el3); /* Data structure to keep track of TSP statistics */ extern spinlock_t console_lock; extern work_statistics_t tsp_stats[PLATFORM_CORE_COUNT]; /* Vector table of jumps */ extern tsp_vectors_t tsp_vector_table; /* functions */ int32_t tsp_common_int_handler(void); int32_t tsp_handle_preemption(void); tsp_args_t *tsp_abort_smc_handler(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7); tsp_args_t *tsp_smc_handler(uint64_t func, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7); tsp_args_t *tsp_system_reset_main(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7); tsp_args_t *tsp_system_off_main(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5, uint64_t arg6, uint64_t arg7); uint64_t tsp_main(void); #endif /* __ASSEMBLER__ */ #endif /* TSP_PRIVATE_H */ trusted-firmware-a-2.2/bl32/tsp/tsp_timer.c000066400000000000000000000060021355360272700206310ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "tsp_private.h" /******************************************************************************* * Data structure to keep track of per-cpu secure generic timer context across * power management operations. ******************************************************************************/ typedef struct timer_context { uint64_t cval; uint32_t ctl; } timer_context_t; static timer_context_t pcpu_timer_context[PLATFORM_CORE_COUNT]; /******************************************************************************* * This function initializes the generic timer to fire every 0.5 second ******************************************************************************/ void tsp_generic_timer_start(void) { uint64_t cval; uint32_t ctl = 0; /* The timer will fire every 0.5 second */ cval = read_cntpct_el0() + (read_cntfrq_el0() >> 1); write_cntps_cval_el1(cval); /* Enable the secure physical timer */ set_cntp_ctl_enable(ctl); write_cntps_ctl_el1(ctl); } /******************************************************************************* * This function deasserts the timer interrupt and sets it up again ******************************************************************************/ void tsp_generic_timer_handler(void) { /* Ensure that the timer did assert the interrupt */ assert(get_cntp_ctl_istatus(read_cntps_ctl_el1())); /* * Disable the timer and reprogram it. The barriers ensure that there is * no reordering of instructions around the reprogramming code. */ isb(); write_cntps_ctl_el1(0); tsp_generic_timer_start(); isb(); } /******************************************************************************* * This function deasserts the timer interrupt prior to cpu power down ******************************************************************************/ void tsp_generic_timer_stop(void) { /* Disable the timer */ write_cntps_ctl_el1(0); } /******************************************************************************* * This function saves the timer context prior to cpu suspension ******************************************************************************/ void tsp_generic_timer_save(void) { uint32_t linear_id = plat_my_core_pos(); pcpu_timer_context[linear_id].cval = read_cntps_cval_el1(); pcpu_timer_context[linear_id].ctl = read_cntps_ctl_el1(); flush_dcache_range((uint64_t) &pcpu_timer_context[linear_id], sizeof(pcpu_timer_context[linear_id])); } /******************************************************************************* * This function restores the timer context post cpu resumption ******************************************************************************/ void tsp_generic_timer_restore(void) { uint32_t linear_id = plat_my_core_pos(); write_cntps_cval_el1(pcpu_timer_context[linear_id].cval); write_cntps_ctl_el1(pcpu_timer_context[linear_id].ctl); } trusted-firmware-a-2.2/common/000077500000000000000000000000001355360272700164015ustar00rootroot00000000000000trusted-firmware-a-2.2/common/aarch32/000077500000000000000000000000001355360272700176245ustar00rootroot00000000000000trusted-firmware-a-2.2/common/aarch32/debug.S000066400000000000000000000110521355360272700210350ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .globl asm_assert .globl do_panic .globl report_exception /* Since the max decimal input number is 65536 */ #define MAX_DEC_DIVISOR 10000 /* The offset to add to get ascii for numerals '0 - 9' */ #define ASCII_OFFSET_NUM '0' .section .rodata.panic_str, "aS" panic_msg: .asciz "PANIC at PC : 0x" panic_end: .asciz "\r\n" /*********************************************************** * The common implementation of do_panic for all BL stages ***********************************************************/ func do_panic /* Have LR copy point to PC at the time of panic */ sub r6, lr, #4 /* Initialize crash console and verify success */ bl plat_crash_console_init cmp r0, #0 beq 1f /* Print panic message */ ldr r4, =panic_msg bl asm_print_str /* Print LR in hex */ mov r4, r6 bl asm_print_hex /* Print new line */ ldr r4, =panic_end bl asm_print_str bl plat_crash_console_flush 1: mov lr, r6 b plat_panic_handler endfunc do_panic /*********************************************************** * This function is called from the vector table for * unhandled exceptions. It reads the current mode and * passes it to platform. ***********************************************************/ func report_exception mrs r0, cpsr and r0, #MODE32_MASK bl plat_report_exception no_ret plat_panic_handler endfunc report_exception #if ENABLE_ASSERTIONS .section .rodata.assert_str, "aS" assert_msg1: .asciz "ASSERT: File " assert_msg2: #if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION) /****************************************************************** * Virtualization comes with the UDIV/SDIV instructions. If missing * write file line number in hexadecimal format. ******************************************************************/ .asciz " Line 0x" #else .asciz " Line " #endif /* --------------------------------------------------------------------------- * Assertion support in assembly. * The below function helps to support assertions in assembly where we do not * have a C runtime stack. Arguments to the function are : * r0 - File name * r1 - Line no * Clobber list : lr, r0 - r6 * --------------------------------------------------------------------------- */ func asm_assert #if LOG_LEVEL >= LOG_LEVEL_INFO /* * Only print the output if LOG_LEVEL is higher or equal to * LOG_LEVEL_INFO, which is the default value for builds with DEBUG=1. */ /* Stash the parameters already in r0 and r1 */ mov r5, r0 mov r6, r1 /* Initialize crash console and verify success */ bl plat_crash_console_init cmp r0, #0 beq 1f /* Print file name */ ldr r4, =assert_msg1 bl asm_print_str mov r4, r5 bl asm_print_str /* Print line number string */ ldr r4, =assert_msg2 bl asm_print_str /* Test for maximum supported line number */ ldr r4, =~0xffff tst r6, r4 bne 1f mov r4, r6 #if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION) /****************************************************************** * Virtualization comes with the UDIV/SDIV instructions. If missing * write file line number in hexadecimal format. ******************************************************************/ bl asm_print_hex #else /* Print line number in decimal */ mov r6, #10 /* Divide by 10 after every loop iteration */ ldr r5, =MAX_DEC_DIVISOR dec_print_loop: udiv r0, r4, r5 /* Quotient */ mls r4, r0, r5, r4 /* Remainder */ add r0, r0, #ASCII_OFFSET_NUM /* Convert to ASCII */ bl plat_crash_console_putc udiv r5, r5, r6 /* Reduce divisor */ cmp r5, #0 bne dec_print_loop #endif bl plat_crash_console_flush 1: #endif /* LOG_LEVEL >= LOG_LEVEL_INFO */ no_ret plat_panic_handler endfunc asm_assert #endif /* ENABLE_ASSERTIONS */ /* * This function prints a string from address in r4 * Clobber: lr, r0 - r4 */ func asm_print_str mov r3, lr 1: ldrb r0, [r4], #0x1 cmp r0, #0 beq 2f bl plat_crash_console_putc b 1b 2: bx r3 endfunc asm_print_str /* * This function prints a hexadecimal number in r4. * In: r4 = the hexadecimal to print. * Clobber: lr, r0 - r3, r5 */ func asm_print_hex mov r3, lr mov r5, #32 /* No of bits to convert to ascii */ 1: sub r5, r5, #4 lsr r0, r4, r5 and r0, r0, #0xf cmp r0, #0xa blo 2f /* Add by 0x27 in addition to ASCII_OFFSET_NUM * to get ascii for characters 'a - f'. */ add r0, r0, #0x27 2: add r0, r0, #ASCII_OFFSET_NUM bl plat_crash_console_putc cmp r5, #0 bne 1b bx r3 endfunc asm_print_hex trusted-firmware-a-2.2/common/aarch64/000077500000000000000000000000001355360272700176315ustar00rootroot00000000000000trusted-firmware-a-2.2/common/aarch64/debug.S000066400000000000000000000113721355360272700210470ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl asm_print_str .globl asm_print_hex .globl asm_print_hex_bits .globl asm_print_newline .globl asm_assert .globl do_panic /* Since the max decimal input number is 65536 */ #define MAX_DEC_DIVISOR 10000 /* The offset to add to get ascii for numerals '0 - 9' */ #define ASCII_OFFSET_NUM 0x30 #if ENABLE_ASSERTIONS .section .rodata.assert_str, "aS" assert_msg1: .asciz "ASSERT: File " assert_msg2: .asciz " Line " /* * This macro is intended to be used to print the * line number in decimal. Used by asm_assert macro. * The max number expected is 65536. * In: x4 = the decimal to print. * Clobber: x30, x0, x1, x2, x5, x6 */ .macro asm_print_line_dec mov x6, #10 /* Divide by 10 after every loop iteration */ mov x5, #MAX_DEC_DIVISOR dec_print_loop: udiv x0, x4, x5 /* Get the quotient */ msub x4, x0, x5, x4 /* Find the remainder */ add x0, x0, #ASCII_OFFSET_NUM /* Convert to ascii */ bl plat_crash_console_putc udiv x5, x5, x6 /* Reduce divisor */ cbnz x5, dec_print_loop .endm /* --------------------------------------------------------------------------- * Assertion support in assembly. * The below function helps to support assertions in assembly where we do not * have a C runtime stack. Arguments to the function are : * x0 - File name * x1 - Line no * Clobber list : x30, x0, x1, x2, x3, x4, x5, x6. * --------------------------------------------------------------------------- */ func asm_assert #if LOG_LEVEL >= LOG_LEVEL_INFO /* * Only print the output if LOG_LEVEL is higher or equal to * LOG_LEVEL_INFO, which is the default value for builds with DEBUG=1. */ mov x5, x0 mov x6, x1 /* Ensure the console is initialized */ bl plat_crash_console_init /* Check if the console is initialized */ cbz x0, _assert_loop /* The console is initialized */ adr x4, assert_msg1 bl asm_print_str mov x4, x5 bl asm_print_str adr x4, assert_msg2 bl asm_print_str /* Check if line number higher than max permitted */ tst x6, #~0xffff b.ne _assert_loop mov x4, x6 asm_print_line_dec bl plat_crash_console_flush _assert_loop: #endif /* LOG_LEVEL >= LOG_LEVEL_INFO */ no_ret plat_panic_handler endfunc asm_assert #endif /* ENABLE_ASSERTIONS */ /* * This function prints a string from address in x4. * In: x4 = pointer to string. * Clobber: x30, x0, x1, x2, x3 */ func asm_print_str mov x3, x30 1: ldrb w0, [x4], #0x1 cbz x0, 2f bl plat_crash_console_putc b 1b 2: ret x3 endfunc asm_print_str /* * This function prints a hexadecimal number in x4. * In: x4 = the hexadecimal to print. * Clobber: x30, x0 - x3, x5 */ func asm_print_hex mov x5, #64 /* No of bits to convert to ascii */ /* Convert to ascii number of bits in x5 */ asm_print_hex_bits: mov x3, x30 1: sub x5, x5, #4 lsrv x0, x4, x5 and x0, x0, #0xf cmp x0, #0xA b.lo 2f /* Add by 0x27 in addition to ASCII_OFFSET_NUM * to get ascii for characters 'a - f'. */ add x0, x0, #0x27 2: add x0, x0, #ASCII_OFFSET_NUM bl plat_crash_console_putc cbnz x5, 1b ret x3 endfunc asm_print_hex /* * Helper function to print newline to console * Clobber: x0 */ func asm_print_newline mov x0, '\n' b plat_crash_console_putc endfunc asm_print_newline /*********************************************************** * The common implementation of do_panic for all BL stages ***********************************************************/ .section .rodata.panic_str, "aS" panic_msg: .asciz "PANIC at PC : 0x" /* --------------------------------------------------------------------------- * do_panic assumes that it is invoked from a C Runtime Environment ie a * valid stack exists. This call will not return. * Clobber list : if CRASH_REPORTING is not enabled then x30, x0 - x6 * --------------------------------------------------------------------------- */ /* This is for the non el3 BL stages to compile through */ .weak el3_panic func do_panic #if CRASH_REPORTING str x0, [sp, #-0x10]! mrs x0, currentel ubfx x0, x0, #2, #2 cmp x0, #0x3 ldr x0, [sp], #0x10 b.eq el3_panic #endif panic_common: /* * el3_panic will be redefined by the BL31 * crash reporting mechanism (if enabled) */ el3_panic: mov x6, x30 bl plat_crash_console_init /* Check if the console is initialized */ cbz x0, _panic_handler /* The console is initialized */ adr x4, panic_msg bl asm_print_str mov x4, x6 /* The panic location is lr -4 */ sub x4, x4, #4 bl asm_print_hex bl plat_crash_console_flush _panic_handler: /* Pass to plat_panic_handler the address from where el3_panic was * called, not the address of the call from el3_panic. */ mov x30, x6 b plat_panic_handler endfunc do_panic trusted-firmware-a-2.2/common/aarch64/early_exceptions.S000066400000000000000000000063741355360272700233440ustar00rootroot00000000000000/* * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /* ----------------------------------------------------------------------------- * Very simple stackless exception handlers used by BL2 and BL31 stages. * BL31 uses them before stacks are setup. BL2 uses them throughout. * ----------------------------------------------------------------------------- */ .globl early_exceptions vector_base early_exceptions /* ----------------------------------------------------- * Current EL with SP0 : 0x0 - 0x200 * ----------------------------------------------------- */ vector_entry SynchronousExceptionSP0 mov x0, #SYNC_EXCEPTION_SP_EL0 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SynchronousExceptionSP0 vector_entry IrqSP0 mov x0, #IRQ_SP_EL0 bl plat_report_exception no_ret plat_panic_handler end_vector_entry IrqSP0 vector_entry FiqSP0 mov x0, #FIQ_SP_EL0 bl plat_report_exception no_ret plat_panic_handler end_vector_entry FiqSP0 vector_entry SErrorSP0 mov x0, #SERROR_SP_EL0 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SErrorSP0 /* ----------------------------------------------------- * Current EL with SPx: 0x200 - 0x400 * ----------------------------------------------------- */ vector_entry SynchronousExceptionSPx mov x0, #SYNC_EXCEPTION_SP_ELX bl plat_report_exception no_ret plat_panic_handler end_vector_entry SynchronousExceptionSPx vector_entry IrqSPx mov x0, #IRQ_SP_ELX bl plat_report_exception no_ret plat_panic_handler end_vector_entry IrqSPx vector_entry FiqSPx mov x0, #FIQ_SP_ELX bl plat_report_exception no_ret plat_panic_handler end_vector_entry FiqSPx vector_entry SErrorSPx mov x0, #SERROR_SP_ELX bl plat_report_exception no_ret plat_panic_handler end_vector_entry SErrorSPx /* ----------------------------------------------------- * Lower EL using AArch64 : 0x400 - 0x600 * ----------------------------------------------------- */ vector_entry SynchronousExceptionA64 mov x0, #SYNC_EXCEPTION_AARCH64 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SynchronousExceptionA64 vector_entry IrqA64 mov x0, #IRQ_AARCH64 bl plat_report_exception no_ret plat_panic_handler end_vector_entry IrqA64 vector_entry FiqA64 mov x0, #FIQ_AARCH64 bl plat_report_exception no_ret plat_panic_handler end_vector_entry FiqA64 vector_entry SErrorA64 mov x0, #SERROR_AARCH64 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SErrorA64 /* ----------------------------------------------------- * Lower EL using AArch32 : 0x600 - 0x800 * ----------------------------------------------------- */ vector_entry SynchronousExceptionA32 mov x0, #SYNC_EXCEPTION_AARCH32 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SynchronousExceptionA32 vector_entry IrqA32 mov x0, #IRQ_AARCH32 bl plat_report_exception no_ret plat_panic_handler end_vector_entry IrqA32 vector_entry FiqA32 mov x0, #FIQ_AARCH32 bl plat_report_exception no_ret plat_panic_handler end_vector_entry FiqA32 vector_entry SErrorA32 mov x0, #SERROR_AARCH32 bl plat_report_exception no_ret plat_panic_handler end_vector_entry SErrorA32 trusted-firmware-a-2.2/common/backtrace/000077500000000000000000000000001355360272700203205ustar00rootroot00000000000000trusted-firmware-a-2.2/common/backtrace/backtrace.c000066400000000000000000000201531355360272700224040ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* Maximum number of entries in the backtrace to display */ #define UNWIND_LIMIT 20U /* * If -fno-omit-frame-pointer is used: * * - AArch64: The AAPCS defines the format of the frame records and mandates the * usage of r29 as frame pointer. * * - AArch32: The format of the frame records is not defined in the AAPCS. * However, at least GCC and Clang use the same format. When they are forced * to only generate A32 code (with -marm), they use r11 as frame pointer and a * similar format as in AArch64. If interworking with T32 is enabled, the * frame pointer is r7 and the format is different. This is not supported by * this implementation of backtrace, so it is needed to use -marm. */ /* Frame records form a linked list in the stack */ struct frame_record { /* Previous frame record in the list */ struct frame_record *parent; /* Return address of the function at this level */ uintptr_t return_addr; }; /* * Strip the Pointer Authentication Code (PAC) from the address to retrieve the * original one. * * The PAC field is stored on the high bits of the address and defined as: * - PAC field = Xn[54:bottom_PAC_bit], when address tagging is used. * - PAC field = Xn[63:56, 54:bottom_PAC_bit], without address tagging. * * With bottom_PAC_bit = 64 - TCR_ELx.TnSZ */ #if ENABLE_PAUTH static uintptr_t demangle_address(uintptr_t addr) { unsigned int el, t0sz, bottom_pac_bit; uint64_t tcr, pac_mask; /* * Different virtual address space size can be defined for each EL. * Ensure that we use the proper one by reading the corresponding * TCR_ELx register. */ el = get_current_el(); if (el == 3U) { tcr = read_tcr_el3(); } else if (el == 2U) { tcr = read_tcr_el2(); } else { tcr = read_tcr_el1(); } /* T0SZ = TCR_ELx[5:0] */ t0sz = tcr & 0x1f; bottom_pac_bit = 64 - t0sz; pac_mask = (1ULL << bottom_pac_bit) - 1; /* demangle the address with the computed mask */ return (addr & pac_mask); } #endif /* ENABLE_PAUTH */ static const char *get_el_str(unsigned int el) { if (el == 3U) { return "EL3"; } else if (el == 2U) { return "EL2"; } else { return "S-EL1"; } } /* * Returns true if the address points to a virtual address that can be read at * the current EL, false otherwise. */ #ifdef __aarch64__ static bool is_address_readable(uintptr_t addr) { unsigned int el = get_current_el(); #if ENABLE_PAUTH /* * When pointer authentication is enabled, the LR value saved on the * stack contains a PAC. It must be stripped to retrieve the return * address. */ addr = demangle_address(addr); #endif if (el == 3U) { ats1e3r(addr); } else if (el == 2U) { ats1e2r(addr); } else { ats1e1r(addr); } isb(); /* If PAR.F == 1 the address translation was aborted. */ if ((read_par_el1() & PAR_F_MASK) != 0U) return false; return true; } #else /* !__aarch64__ */ static bool is_address_readable(uintptr_t addr) { unsigned int el = get_current_el(); if (el == 3U) { write_ats1cpr(addr); } else if (el == 2U) { write_ats1hr(addr); } else { write_ats1cpr(addr); } isb(); /* If PAR.F == 1 the address translation was aborted. */ if ((read64_par() & PAR_F_MASK) != 0U) return false; return true; } #endif /* __aarch64__ */ /* * Returns true if all the bytes in a given object are in mapped memory and an * LDR using this pointer would succeed, false otherwise. */ static bool is_valid_object(uintptr_t addr, size_t size) { assert(size > 0U); if (addr == 0U) return false; /* Detect overflows */ if ((addr + size) < addr) return false; /* A pointer not aligned properly could trigger an alignment fault. */ if ((addr & (sizeof(uintptr_t) - 1U)) != 0U) return false; /* Check that all the object is readable */ for (size_t i = 0; i < size; i++) { if (!is_address_readable(addr + i)) return false; } return true; } /* * Returns true if the specified address is correctly aligned and points to a * valid memory region. */ static bool is_valid_jump_address(uintptr_t addr) { if (addr == 0U) return false; /* Check alignment. Both A64 and A32 use 32-bit opcodes */ if ((addr & (sizeof(uint32_t) - 1U)) != 0U) return false; if (!is_address_readable(addr)) return false; return true; } /* * Returns true if the pointer points at a valid frame record, false otherwise. */ static bool is_valid_frame_record(struct frame_record *fr) { return is_valid_object((uintptr_t)fr, sizeof(struct frame_record)); } /* * Adjust the frame-pointer-register value by 4 bytes on AArch32 to have the * same layout as AArch64. */ static struct frame_record *adjust_frame_record(struct frame_record *fr) { #ifdef __aarch64__ return fr; #else return (struct frame_record *)((uintptr_t)fr - 4U); #endif } static void unwind_stack(struct frame_record *fr, uintptr_t current_pc, uintptr_t link_register) { uintptr_t call_site; static const char *backtrace_str = "%u: %s: 0x%lx\n"; const char *el_str = get_el_str(get_current_el()); if (!is_valid_frame_record(fr)) { printf("ERROR: Corrupted frame pointer (frame record address = %p)\n", fr); return; } if (fr->return_addr != link_register) { printf("ERROR: Corrupted stack (frame record address = %p)\n", fr); return; } /* The level 0 of the backtrace is the current backtrace function */ printf(backtrace_str, 0U, el_str, current_pc); /* * The last frame record pointer in the linked list at the beginning of * the stack should be NULL unless stack is corrupted. */ for (unsigned int i = 1U; i < UNWIND_LIMIT; i++) { /* If an invalid frame record is found, exit. */ if (!is_valid_frame_record(fr)) return; /* * A32 and A64 are fixed length so the address from where the * call was made is the instruction before the return address, * which is always 4 bytes before it. */ call_site = fr->return_addr - 4U; #if ENABLE_PAUTH /* * When pointer authentication is enabled, the LR value saved on * the stack contains a PAC. It must be stripped to retrieve the * return address. */ call_site = demangle_address(call_site); #endif /* * If the address is invalid it means that the frame record is * probably corrupted. */ if (!is_valid_jump_address(call_site)) return; printf(backtrace_str, i, el_str, call_site); fr = adjust_frame_record(fr->parent); } printf("ERROR: Max backtrace depth reached\n"); } /* * Display a backtrace. The cookie string parameter is displayed along the * trace to help filter the log messages. * * Many things can prevent displaying the expected backtrace. For example, * compiler optimizations can use a branch instead of branch with link when it * detects a tail call. The backtrace level for this caller will not be * displayed, as it does not appear in the call stack anymore. Also, assembly * functions will not be displayed unless they setup AAPCS compliant frame * records on AArch64 and compliant with GCC-specific frame record format on * AArch32. * * Usage of the trace: addr2line can be used to map the addresses to function * and source code location when given the ELF file compiled with debug * information. The "-i" flag is highly recommended to improve display of * inlined function. The *.dump files generated when building each image can * also be used. * * WARNING: In case of corrupted stack, this function could display security * sensitive information past the beginning of the stack so it must not be used * in production build. This function is only compiled in when ENABLE_BACKTRACE * is set to 1. */ void backtrace(const char *cookie) { uintptr_t return_address = (uintptr_t)__builtin_return_address(0U); struct frame_record *fr = __builtin_frame_address(0U); /* Printing the backtrace may crash the system, flush before starting */ (void)console_flush(); fr = adjust_frame_record(fr); printf("BACKTRACE: START: %s\n", cookie); unwind_stack(fr, (uintptr_t)&backtrace, return_address); printf("BACKTRACE: END: %s\n", cookie); } trusted-firmware-a-2.2/common/backtrace/backtrace.mk000066400000000000000000000015601355360272700225720ustar00rootroot00000000000000# # Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Enable backtrace by default in DEBUG AArch64 builds ifeq (${ARCH},aarch32) ENABLE_BACKTRACE := 0 else ENABLE_BACKTRACE := ${DEBUG} endif ifeq (${ENABLE_BACKTRACE},1) # Force the compiler to include the frame pointer TF_CFLAGS += -fno-omit-frame-pointer BL_COMMON_SOURCES += common/backtrace/backtrace.c endif ifeq (${ARCH},aarch32) ifeq (${ENABLE_BACKTRACE},1) ifneq (${AARCH32_INSTRUCTION_SET},A32) $(error Error: AARCH32_INSTRUCTION_SET=A32 is needed \ for ENABLE_BACKTRACE when compiling for AArch32.) endif endif endif $(eval $(call assert_boolean,ENABLE_BACKTRACE)) $(eval $(call add_define,ENABLE_BACKTRACE)) trusted-firmware-a-2.2/common/bl_common.c000066400000000000000000000160621355360272700205170ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #if TRUSTED_BOARD_BOOT # ifdef DYN_DISABLE_AUTH static int disable_auth; /****************************************************************************** * API to dynamically disable authentication. Only meant for development * systems. This is only invoked if DYN_DISABLE_AUTH is defined. *****************************************************************************/ void dyn_disable_auth(void) { INFO("Disabling authentication of images dynamically\n"); disable_auth = 1; } # endif /* DYN_DISABLE_AUTH */ /****************************************************************************** * Function to determine whether the authentication is disabled dynamically. *****************************************************************************/ static int dyn_is_auth_disabled(void) { # ifdef DYN_DISABLE_AUTH return disable_auth; # else return 0; # endif } #endif /* TRUSTED_BOARD_BOOT */ uintptr_t page_align(uintptr_t value, unsigned dir) { /* Round up the limit to the next page boundary */ if ((value & (PAGE_SIZE - 1U)) != 0U) { value &= ~(PAGE_SIZE - 1U); if (dir == UP) value += PAGE_SIZE; } return value; } /******************************************************************************* * Internal function to load an image at a specific address given * an image ID and extents of free memory. * * If the load is successful then the image information is updated. * * Returns 0 on success, a negative error code otherwise. ******************************************************************************/ static int load_image(unsigned int image_id, image_info_t *image_data) { uintptr_t dev_handle; uintptr_t image_handle; uintptr_t image_spec; uintptr_t image_base; size_t image_size; size_t bytes_read; int io_result; assert(image_data != NULL); assert(image_data->h.version >= VERSION_2); image_base = image_data->image_base; /* Obtain a reference to the image by querying the platform layer */ io_result = plat_get_image_source(image_id, &dev_handle, &image_spec); if (io_result != 0) { WARN("Failed to obtain reference to image id=%u (%i)\n", image_id, io_result); return io_result; } /* Attempt to access the image */ io_result = io_open(dev_handle, image_spec, &image_handle); if (io_result != 0) { WARN("Failed to access image id=%u (%i)\n", image_id, io_result); return io_result; } INFO("Loading image id=%u at address 0x%lx\n", image_id, image_base); /* Find the size of the image */ io_result = io_size(image_handle, &image_size); if ((io_result != 0) || (image_size == 0U)) { WARN("Failed to determine the size of the image id=%u (%i)\n", image_id, io_result); goto exit; } /* Check that the image size to load is within limit */ if (image_size > image_data->image_max_size) { WARN("Image id=%u size out of bounds\n", image_id); io_result = -EFBIG; goto exit; } /* * image_data->image_max_size is a uint32_t so image_size will always * fit in image_data->image_size. */ image_data->image_size = (uint32_t)image_size; /* We have enough space so load the image now */ /* TODO: Consider whether to try to recover/retry a partially successful read */ io_result = io_read(image_handle, image_base, image_size, &bytes_read); if ((io_result != 0) || (bytes_read < image_size)) { WARN("Failed to load image id=%u (%i)\n", image_id, io_result); goto exit; } INFO("Image id=%u loaded: 0x%lx - 0x%lx\n", image_id, image_base, (uintptr_t)(image_base + image_size)); exit: (void)io_close(image_handle); /* Ignore improbable/unrecoverable error in 'close' */ /* TODO: Consider maintaining open device connection from this bootloader stage */ (void)io_dev_close(dev_handle); /* Ignore improbable/unrecoverable error in 'dev_close' */ return io_result; } static int load_auth_image_internal(unsigned int image_id, image_info_t *image_data, int is_parent_image) { int rc; #if TRUSTED_BOARD_BOOT if (dyn_is_auth_disabled() == 0) { unsigned int parent_id; /* Use recursion to authenticate parent images */ rc = auth_mod_get_parent_id(image_id, &parent_id); if (rc == 0) { rc = load_auth_image_internal(parent_id, image_data, 1); if (rc != 0) { return rc; } } } #endif /* TRUSTED_BOARD_BOOT */ /* Load the image */ rc = load_image(image_id, image_data); if (rc != 0) { return rc; } #if TRUSTED_BOARD_BOOT if (dyn_is_auth_disabled() == 0) { /* Authenticate it */ rc = auth_mod_verify_img(image_id, (void *)image_data->image_base, image_data->image_size); if (rc != 0) { /* Authentication error, zero memory and flush it right away. */ zero_normalmem((void *)image_data->image_base, image_data->image_size); flush_dcache_range(image_data->image_base, image_data->image_size); return -EAUTH; } } #endif /* TRUSTED_BOARD_BOOT */ /* * Flush the image to main memory so that it can be executed later by * any CPU, regardless of cache and MMU state. If TBB is enabled, then * the file has been successfully loaded and authenticated and flush * only for child images, not for the parents (certificates). */ if (is_parent_image == 0) { flush_dcache_range(image_data->image_base, image_data->image_size); } return 0; } /******************************************************************************* * Generic function to load and authenticate an image. The image is actually * loaded by calling the 'load_image()' function. Therefore, it returns the * same error codes if the loading operation failed, or -EAUTH if the * authentication failed. In addition, this function uses recursion to * authenticate the parent images up to the root of trust. ******************************************************************************/ int load_auth_image(unsigned int image_id, image_info_t *image_data) { int err; do { err = load_auth_image_internal(image_id, image_data, 0); } while ((err != 0) && (plat_try_next_boot_source() != 0)); return err; } /******************************************************************************* * Print the content of an entry_point_info_t structure. ******************************************************************************/ void print_entry_point_info(const entry_point_info_t *ep_info) { INFO("Entry point address = 0x%lx\n", ep_info->pc); INFO("SPSR = 0x%x\n", ep_info->spsr); #define PRINT_IMAGE_ARG(n) \ VERBOSE("Argument #" #n " = 0x%llx\n", \ (unsigned long long) ep_info->args.arg##n) PRINT_IMAGE_ARG(0); PRINT_IMAGE_ARG(1); PRINT_IMAGE_ARG(2); PRINT_IMAGE_ARG(3); #ifdef __aarch64__ PRINT_IMAGE_ARG(4); PRINT_IMAGE_ARG(5); PRINT_IMAGE_ARG(6); PRINT_IMAGE_ARG(7); #endif #undef PRINT_IMAGE_ARG } trusted-firmware-a-2.2/common/desc_image_load.c000066400000000000000000000247571355360272700216430ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include static bl_load_info_t bl_load_info; static bl_params_t next_bl_params; /******************************************************************************* * This function flushes the data structures so that they are visible * in memory for the next BL image. ******************************************************************************/ void flush_bl_params_desc(void) { flush_bl_params_desc_args(bl_mem_params_desc_ptr, bl_mem_params_desc_num, &next_bl_params); } /******************************************************************************* * This function flushes the data structures specified as arguments so that they * are visible in memory for the next BL image. ******************************************************************************/ void flush_bl_params_desc_args(bl_mem_params_node_t *mem_params_desc_ptr, unsigned int mem_params_desc_num, bl_params_t *next_bl_params_ptr) { assert(mem_params_desc_ptr != NULL); assert(mem_params_desc_num != 0U); assert(next_bl_params_ptr != NULL); flush_dcache_range((uintptr_t)mem_params_desc_ptr, sizeof(*mem_params_desc_ptr) * mem_params_desc_num); flush_dcache_range((uintptr_t)next_bl_params_ptr, sizeof(*next_bl_params_ptr)); } /******************************************************************************* * This function returns the index for given image_id, within the * image descriptor array provided by bl_image_info_descs_ptr, if the * image is found else it returns -1. ******************************************************************************/ int get_bl_params_node_index(unsigned int image_id) { unsigned int index; assert(image_id != INVALID_IMAGE_ID); for (index = 0U; index < bl_mem_params_desc_num; index++) { if (bl_mem_params_desc_ptr[index].image_id == image_id) return (int)index; } return -1; } /******************************************************************************* * This function returns the pointer to `bl_mem_params_node_t` object for * given image_id, within the image descriptor array provided by * bl_mem_params_desc_ptr, if the image is found else it returns NULL. ******************************************************************************/ bl_mem_params_node_t *get_bl_mem_params_node(unsigned int image_id) { int index; assert(image_id != INVALID_IMAGE_ID); index = get_bl_params_node_index(image_id); if (index >= 0) return &bl_mem_params_desc_ptr[index]; else return NULL; } /******************************************************************************* * This function creates the list of loadable images, by populating and * linking each `bl_load_info_node_t` type node, using the internal array * of image descriptor provided by bl_mem_params_desc_ptr. It also populates * and returns `bl_load_info_t` type structure that contains head of the list * of loadable images. ******************************************************************************/ bl_load_info_t *get_bl_load_info_from_mem_params_desc(void) { unsigned int index = 0; /* If there is no image to start with, return NULL */ if (bl_mem_params_desc_num == 0U) return NULL; /* Assign initial data structures */ bl_load_info_node_t *bl_node_info = &bl_mem_params_desc_ptr[index].load_node_mem; bl_load_info.head = bl_node_info; SET_PARAM_HEAD(&bl_load_info, PARAM_BL_LOAD_INFO, VERSION_2, 0U); /* Go through the image descriptor array and create the list */ for (; index < bl_mem_params_desc_num; index++) { /* Populate the image information */ bl_node_info->image_id = bl_mem_params_desc_ptr[index].image_id; bl_node_info->image_info = &bl_mem_params_desc_ptr[index].image_info; /* Link next image if present */ if ((index + 1U) < bl_mem_params_desc_num) { /* Get the memory and link the next node */ bl_node_info->next_load_info = &bl_mem_params_desc_ptr[index + 1U].load_node_mem; bl_node_info = bl_node_info->next_load_info; } } return &bl_load_info; } /******************************************************************************* * This function creates the list of executable images, by populating and * linking each `bl_params_node_t` type node, using the internal array of * image descriptor provided by bl_mem_params_desc_ptr. It also populates * and returns `bl_params_t` type structure that contains head of the list * of executable images. ******************************************************************************/ bl_params_t *get_next_bl_params_from_mem_params_desc(void) { unsigned int count; unsigned int img_id = 0U; unsigned int link_index = 0U; bl_params_node_t *bl_current_exec_node = NULL; bl_params_node_t *bl_last_exec_node = NULL; bl_mem_params_node_t *desc_ptr; /* If there is no image to start with, return NULL */ if (bl_mem_params_desc_num == 0U) return NULL; /* Get the list HEAD */ for (count = 0U; count < bl_mem_params_desc_num; count++) { desc_ptr = &bl_mem_params_desc_ptr[count]; if ((EP_GET_EXE(desc_ptr->ep_info.h.attr) == EXECUTABLE) && (EP_GET_FIRST_EXE(desc_ptr->ep_info.h.attr) == EP_FIRST_EXE)) { next_bl_params.head = &desc_ptr->params_node_mem; link_index = count; break; } } /* Make sure we have a HEAD node */ assert(next_bl_params.head != NULL); /* Populate the HEAD information */ SET_PARAM_HEAD(&next_bl_params, PARAM_BL_PARAMS, VERSION_2, 0U); /* * Go through the image descriptor array and create the list. * This bounded loop is to make sure that we are not looping forever. */ for (count = 0U; count < bl_mem_params_desc_num; count++) { desc_ptr = &bl_mem_params_desc_ptr[link_index]; /* Make sure the image is executable */ assert(EP_GET_EXE(desc_ptr->ep_info.h.attr) == EXECUTABLE); /* Get the memory for current node */ bl_current_exec_node = &desc_ptr->params_node_mem; /* Populate the image information */ bl_current_exec_node->image_id = desc_ptr->image_id; bl_current_exec_node->image_info = &desc_ptr->image_info; bl_current_exec_node->ep_info = &desc_ptr->ep_info; if (bl_last_exec_node != NULL) { /* Assert if loop detected */ assert(bl_last_exec_node->next_params_info == NULL); /* Link the previous node to the current one */ bl_last_exec_node->next_params_info = bl_current_exec_node; } /* Update the last node */ bl_last_exec_node = bl_current_exec_node; /* If no next hand-off image then break out */ img_id = desc_ptr->next_handoff_image_id; if (img_id == INVALID_IMAGE_ID) break; /* Get the index for the next hand-off image */ link_index = get_bl_params_node_index(img_id); assert((link_index > 0U) && (link_index < bl_mem_params_desc_num)); } /* Invalid image is expected to terminate the loop */ assert(img_id == INVALID_IMAGE_ID); return &next_bl_params; } /******************************************************************************* * This function populates the entry point information with the corresponding * config file for all executable BL images described in bl_params. ******************************************************************************/ void populate_next_bl_params_config(bl_params_t *bl2_to_next_bl_params) { bl_params_node_t *params_node; unsigned int fw_config_id; uintptr_t hw_config_base = 0, fw_config_base; bl_mem_params_node_t *mem_params; assert(bl2_to_next_bl_params != NULL); /* * Get the `bl_mem_params_node_t` corresponding to HW_CONFIG * if available. */ mem_params = get_bl_mem_params_node(HW_CONFIG_ID); if (mem_params != NULL) hw_config_base = mem_params->image_info.image_base; for (params_node = bl2_to_next_bl_params->head; params_node != NULL; params_node = params_node->next_params_info) { fw_config_base = 0; switch (params_node->image_id) { case BL31_IMAGE_ID: fw_config_id = SOC_FW_CONFIG_ID; break; case BL32_IMAGE_ID: fw_config_id = TOS_FW_CONFIG_ID; break; case BL33_IMAGE_ID: fw_config_id = NT_FW_CONFIG_ID; break; default: fw_config_id = INVALID_IMAGE_ID; break; } if (fw_config_id != INVALID_IMAGE_ID) { mem_params = get_bl_mem_params_node(fw_config_id); if (mem_params != NULL) fw_config_base = mem_params->image_info.image_base; } /* * Pass hw and tb_fw config addresses to next images. NOTE - for * EL3 runtime images (BL31 for AArch64 and BL32 for AArch32), * arg0 is already used by generic code. Take care of not * overwriting the previous initialisations. */ if (params_node == bl2_to_next_bl_params->head) { if (params_node->ep_info->args.arg1 == 0U) params_node->ep_info->args.arg1 = fw_config_base; if (params_node->ep_info->args.arg2 == 0U) params_node->ep_info->args.arg2 = hw_config_base; } else { if (params_node->ep_info->args.arg0 == 0U) params_node->ep_info->args.arg0 = fw_config_base; if (params_node->ep_info->args.arg1 == 0U) params_node->ep_info->args.arg1 = hw_config_base; } } } /******************************************************************************* * Helper to extract BL32/BL33 entry point info from arg0 passed to BL31, for * platforms that are only interested in those. Platforms that need to extract * more information can parse the structures themselves. ******************************************************************************/ void bl31_params_parse_helper(u_register_t param, entry_point_info_t *bl32_ep_info_out, entry_point_info_t *bl33_ep_info_out) { bl_params_node_t *node; bl_params_t *v2 = (void *)(uintptr_t)param; #if !ERROR_DEPRECATED if (v2->h.version == PARAM_VERSION_1) { struct { /* Deprecated version 1 parameter structure. */ param_header_t h; image_info_t *bl31_image_info; entry_point_info_t *bl32_ep_info; image_info_t *bl32_image_info; entry_point_info_t *bl33_ep_info; image_info_t *bl33_image_info; } *v1 = (void *)(uintptr_t)param; assert(v1->h.type == PARAM_BL31); if (bl32_ep_info_out) *bl32_ep_info_out = *v1->bl32_ep_info; if (bl33_ep_info_out) *bl33_ep_info_out = *v1->bl33_ep_info; return; } #endif /* !ERROR_DEPRECATED */ assert(v2->h.version == PARAM_VERSION_2); assert(v2->h.type == PARAM_BL_PARAMS); for (node = v2->head; node; node = node->next_params_info) { if (node->image_id == BL32_IMAGE_ID) if (bl32_ep_info_out) *bl32_ep_info_out = *node->ep_info; if (node->image_id == BL33_IMAGE_ID) if (bl33_ep_info_out) *bl33_ep_info_out = *node->ep_info; } } trusted-firmware-a-2.2/common/fdt_fixup.c000066400000000000000000000152451355360272700205440ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * Contains generic routines to fix up the device tree blob passed on to * payloads like BL32 and BL33 (and further down the boot chain). * This allows to easily add PSCI nodes, when the original DT does not have * it or advertises another method. * Also it supports to add reserved memory nodes to describe memory that * is used by the secure world, so that non-secure software avoids using * that. */ #include #include #include #include #include #include static int append_psci_compatible(void *fdt, int offs, const char *str) { return fdt_appendprop(fdt, offs, "compatible", str, strlen(str) + 1); } /* * Those defines are for PSCI v0.1 legacy clients, which we expect to use * the same execution state (AArch32/AArch64) as TF-A. * Kernels running in AArch32 on an AArch64 TF-A should use PSCI v0.2. */ #ifdef __aarch64__ #define PSCI_CPU_SUSPEND_FNID PSCI_CPU_SUSPEND_AARCH64 #define PSCI_CPU_ON_FNID PSCI_CPU_ON_AARCH64 #else #define PSCI_CPU_SUSPEND_FNID PSCI_CPU_SUSPEND_AARCH32 #define PSCI_CPU_ON_FNID PSCI_CPU_ON_AARCH32 #endif /******************************************************************************* * dt_add_psci_node() - Add a PSCI node into an existing device tree * @fdt: pointer to the device tree blob in memory * * Add a device tree node describing PSCI into the root level of an existing * device tree blob in memory. * This will add v0.1, v0.2 and v1.0 compatible strings and the standard * function IDs for v0.1 compatibility. * An existing PSCI node will not be touched, the function will return success * in this case. This function will not touch the /cpus enable methods, use * dt_add_psci_cpu_enable_methods() for that. * * Return: 0 on success, -1 otherwise. ******************************************************************************/ int dt_add_psci_node(void *fdt) { int offs; if (fdt_path_offset(fdt, "/psci") >= 0) { WARN("PSCI Device Tree node already exists!\n"); return 0; } offs = fdt_path_offset(fdt, "/"); if (offs < 0) return -1; offs = fdt_add_subnode(fdt, offs, "psci"); if (offs < 0) return -1; if (append_psci_compatible(fdt, offs, "arm,psci-1.0")) return -1; if (append_psci_compatible(fdt, offs, "arm,psci-0.2")) return -1; if (append_psci_compatible(fdt, offs, "arm,psci")) return -1; if (fdt_setprop_string(fdt, offs, "method", "smc")) return -1; if (fdt_setprop_u32(fdt, offs, "cpu_suspend", PSCI_CPU_SUSPEND_FNID)) return -1; if (fdt_setprop_u32(fdt, offs, "cpu_off", PSCI_CPU_OFF)) return -1; if (fdt_setprop_u32(fdt, offs, "cpu_on", PSCI_CPU_ON_FNID)) return -1; return 0; } /* * Find the first subnode that has a "device_type" property with the value * "cpu" and which's enable-method is not "psci" (yet). * Returns 0 if no such subnode is found, so all have already been patched * or none have to be patched in the first place. * Returns 1 if *one* such subnode has been found and successfully changed * to "psci". * Returns -1 on error. * * Call in a loop until it returns 0. Recalculate the node offset after * it has returned 1. */ static int dt_update_one_cpu_node(void *fdt, int offset) { int offs; /* Iterate over all subnodes to find those with device_type = "cpu". */ for (offs = fdt_first_subnode(fdt, offset); offs >= 0; offs = fdt_next_subnode(fdt, offs)) { const char *prop; int len; prop = fdt_getprop(fdt, offs, "device_type", &len); if (!prop) continue; if (memcmp(prop, "cpu", 4) != 0 || len != 4) continue; /* Ignore any nodes which already use "psci". */ prop = fdt_getprop(fdt, offs, "enable-method", &len); if (prop && memcmp(prop, "psci", 5) == 0 && len == 5) continue; if (fdt_setprop_string(fdt, offs, "enable-method", "psci")) return -1; /* * Subnode found and patched. * Restart to accommodate potentially changed offsets. */ return 1; } if (offs == -FDT_ERR_NOTFOUND) return 0; return offs; } /******************************************************************************* * dt_add_psci_cpu_enable_methods() - switch CPU nodes in DT to use PSCI * @fdt: pointer to the device tree blob in memory * * Iterate over all CPU device tree nodes (/cpus/cpu@x) in memory to change * the enable-method to PSCI. This will add the enable-method properties, if * required, or will change existing properties to read "psci". * * Return: 0 on success, or a negative error value otherwise. ******************************************************************************/ int dt_add_psci_cpu_enable_methods(void *fdt) { int offs, ret; do { offs = fdt_path_offset(fdt, "/cpus"); if (offs < 0) return offs; ret = dt_update_one_cpu_node(fdt, offs); } while (ret > 0); return ret; } #define HIGH_BITS(x) ((sizeof(x) > 4) ? ((x) >> 32) : (typeof(x))0) /******************************************************************************* * fdt_add_reserved_memory() - reserve (secure) memory regions in DT * @dtb: pointer to the device tree blob in memory * @node_name: name of the subnode to be used * @base: physical base address of the reserved region * @size: size of the reserved region * * Add a region of memory to the /reserved-memory node in a device tree in * memory, creating that node if required. Each region goes into a subnode * of that node and has a @node_name, a @base address and a @size. * This will prevent any device tree consumer from using that memory. It * can be used to announce secure memory regions, as it adds the "no-map" * property to prevent mapping and speculative operations on that region. * * See reserved-memory/reserved-memory.txt in the (Linux kernel) DT binding * documentation for details. * * Return: 0 on success, a negative error value otherwise. ******************************************************************************/ int fdt_add_reserved_memory(void *dtb, const char *node_name, uintptr_t base, size_t size) { int offs = fdt_path_offset(dtb, "/reserved-memory"); uint32_t addresses[3]; if (offs < 0) { /* create if not existing yet */ offs = fdt_add_subnode(dtb, 0, "reserved-memory"); if (offs < 0) return offs; fdt_setprop_u32(dtb, offs, "#address-cells", 2); fdt_setprop_u32(dtb, offs, "#size-cells", 1); fdt_setprop(dtb, offs, "ranges", NULL, 0); } addresses[0] = cpu_to_fdt32(HIGH_BITS(base)); addresses[1] = cpu_to_fdt32(base & 0xffffffff); addresses[2] = cpu_to_fdt32(size & 0xffffffff); offs = fdt_add_subnode(dtb, offs, node_name); fdt_setprop(dtb, offs, "no-map", NULL, 0); fdt_setprop(dtb, offs, "reg", addresses, 12); return 0; } trusted-firmware-a-2.2/common/fdt_wrappers.c000066400000000000000000000075311355360272700212530ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* Helper functions to offer easier navigation of Device Tree Blob */ #include #include #include #include #include /* * Read cells from a given property of the given node. At most 2 cells of the * property are read, and pointer is updated. Returns 0 on success, and -1 upon * error */ int fdtw_read_cells(const void *dtb, int node, const char *prop, unsigned int cells, void *value) { const uint32_t *value_ptr; uint32_t hi = 0, lo; int value_len; assert(dtb != NULL); assert(prop != NULL); assert(value != NULL); assert(node >= 0); /* We expect either 1 or 2 cell property */ assert(cells <= 2U); /* Access property and obtain its length (in bytes) */ value_ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop), &value_len); if (value_ptr == NULL) { WARN("Couldn't find property %s in dtb\n", prop); return -1; } /* Verify that property length accords with cell length */ if (NCELLS((unsigned int)value_len) != cells) { WARN("Property length mismatch\n"); return -1; } if (cells == 2U) { hi = fdt32_to_cpu(*value_ptr); value_ptr++; } lo = fdt32_to_cpu(*value_ptr); if (cells == 2U) *((uint64_t *) value) = ((uint64_t) hi << 32) | lo; else *((uint32_t *) value) = lo; return 0; } /* * Read cells from a given property of the given node. Any number of 32-bit * cells of the property can be read. The fdt pointer is updated. Returns 0 on * success, and -1 on error. */ int fdtw_read_array(const void *dtb, int node, const char *prop, unsigned int cells, void *value) { const uint32_t *value_ptr; int value_len; assert(dtb != NULL); assert(prop != NULL); assert(value != NULL); assert(node >= 0); /* Access property and obtain its length (in bytes) */ value_ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop), &value_len); if (value_ptr == NULL) { WARN("Couldn't find property %s in dtb\n", prop); return -1; } /* Verify that property length accords with cell length */ if (NCELLS((unsigned int)value_len) != cells) { WARN("Property length mismatch\n"); return -1; } uint32_t *dst = value; for (unsigned int i = 0U; i < cells; i++) { dst[i] = fdt32_to_cpu(value_ptr[i]); } return 0; } /* * Read string from a given property of the given node. Up to 'size - 1' * characters are read, and a NUL terminator is added. Returns 0 on success, * and -1 upon error. */ int fdtw_read_string(const void *dtb, int node, const char *prop, char *str, size_t size) { const char *ptr; size_t len; assert(dtb != NULL); assert(node >= 0); assert(prop != NULL); assert(str != NULL); assert(size > 0U); ptr = fdt_getprop_namelen(dtb, node, prop, (int)strlen(prop), NULL); if (ptr == NULL) { WARN("Couldn't find property %s in dtb\n", prop); return -1; } len = strlcpy(str, ptr, size); if (len >= size) { WARN("String of property %s in dtb has been truncated\n", prop); return -1; } return 0; } /* * Write cells in place to a given property of the given node. At most 2 cells * of the property are written. Returns 0 on success, and -1 upon error. */ int fdtw_write_inplace_cells(void *dtb, int node, const char *prop, unsigned int cells, void *value) { int err, len; assert(dtb != NULL); assert(prop != NULL); assert(value != NULL); assert(node >= 0); /* We expect either 1 or 2 cell property */ assert(cells <= 2U); if (cells == 2U) *(uint64_t *)value = cpu_to_fdt64(*(uint64_t *)value); else *(uint32_t *)value = cpu_to_fdt32(*(uint32_t *)value); len = (int)cells * 4; /* Set property value in place */ err = fdt_setprop_inplace(dtb, node, prop, value, len); if (err != 0) { WARN("Modify property %s failed with error %d\n", prop, err); return -1; } return 0; } trusted-firmware-a-2.2/common/image_decompress.c000066400000000000000000000043441355360272700220600ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include static uintptr_t decompressor_buf_base; static uint32_t decompressor_buf_size; static decompressor_t *decompressor; static struct image_info saved_image_info; void image_decompress_init(uintptr_t buf_base, uint32_t buf_size, decompressor_t *_decompressor) { decompressor_buf_base = buf_base; decompressor_buf_size = buf_size; decompressor = _decompressor; } void image_decompress_prepare(struct image_info *info) { /* * If the image is compressed, it should be loaded into the temporary * buffer instead of its final destination. We save image_info, then * override ->image_base and ->image_max_size so that load_image() will * transfer the compressed data to the temporary buffer. */ saved_image_info = *info; info->image_base = decompressor_buf_base; info->image_max_size = decompressor_buf_size; } int image_decompress(struct image_info *info) { uintptr_t compressed_image_base, image_base, work_base; uint32_t compressed_image_size, work_size; int ret; /* * The size of compressed data has been filled by load_image(). * Read it out before restoring image_info. */ compressed_image_size = info->image_size; compressed_image_base = info->image_base; *info = saved_image_info; assert(compressed_image_size <= decompressor_buf_size); image_base = info->image_base; /* * Use the rest of the temporary buffer as workspace of the * decompressor since the decompressor may need additional memory. */ work_base = compressed_image_base + compressed_image_size; work_size = decompressor_buf_size - compressed_image_size; ret = decompressor(&compressed_image_base, compressed_image_size, &image_base, info->image_max_size, work_base, work_size); if (ret) { ERROR("Failed to decompress image (err=%d)\n", ret); return ret; } /* image_base is updated to the final pos when decompressor() exits. */ info->image_size = image_base - info->image_base; flush_dcache_range(info->image_base, info->image_size); return 0; } trusted-firmware-a-2.2/common/runtime_svc.c000066400000000000000000000121231355360272700211020ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /******************************************************************************* * The 'rt_svc_descs' array holds the runtime service descriptors exported by * services by placing them in the 'rt_svc_descs' linker section. * The 'rt_svc_descs_indices' array holds the index of a descriptor in the * 'rt_svc_descs' array. When an SMC arrives, the OEN[29:24] bits and the call * type[31] bit in the function id are combined to get an index into the * 'rt_svc_descs_indices' array. This gives the index of the descriptor in the * 'rt_svc_descs' array which contains the SMC handler. ******************************************************************************/ uint8_t rt_svc_descs_indices[MAX_RT_SVCS]; #define RT_SVC_DECS_NUM ((RT_SVC_DESCS_END - RT_SVC_DESCS_START)\ / sizeof(rt_svc_desc_t)) /******************************************************************************* * Function to invoke the registered `handle` corresponding to the smc_fid in * AArch32 mode. ******************************************************************************/ uintptr_t handle_runtime_svc(uint32_t smc_fid, void *cookie, void *handle, unsigned int flags) { u_register_t x1, x2, x3, x4; unsigned int index; unsigned int idx; const rt_svc_desc_t *rt_svc_descs; assert(handle != NULL); idx = get_unique_oen_from_smc_fid(smc_fid); assert(idx < MAX_RT_SVCS); index = rt_svc_descs_indices[idx]; if (index >= RT_SVC_DECS_NUM) SMC_RET1(handle, SMC_UNK); rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START; get_smc_params_from_ctx(handle, x1, x2, x3, x4); return rt_svc_descs[index].handle(smc_fid, x1, x2, x3, x4, cookie, handle, flags); } /******************************************************************************* * Simple routine to sanity check a runtime service descriptor before using it ******************************************************************************/ static int32_t validate_rt_svc_desc(const rt_svc_desc_t *desc) { if (desc == NULL) return -EINVAL; if (desc->start_oen > desc->end_oen) return -EINVAL; if (desc->end_oen >= OEN_LIMIT) return -EINVAL; if ((desc->call_type != SMC_TYPE_FAST) && (desc->call_type != SMC_TYPE_YIELD)) return -EINVAL; /* A runtime service having no init or handle function doesn't make sense */ if ((desc->init == NULL) && (desc->handle == NULL)) return -EINVAL; return 0; } /******************************************************************************* * This function calls the initialisation routine in the descriptor exported by * a runtime service. Once a descriptor has been validated, its start & end * owning entity numbers and the call type are combined to form a unique oen. * The unique oen is used as an index into the 'rt_svc_descs_indices' array. * The index of the runtime service descriptor is stored at this index. ******************************************************************************/ void __init runtime_svc_init(void) { int rc = 0; uint8_t index, start_idx, end_idx; rt_svc_desc_t *rt_svc_descs; /* Assert the number of descriptors detected are less than maximum indices */ assert((RT_SVC_DESCS_END >= RT_SVC_DESCS_START) && (RT_SVC_DECS_NUM < MAX_RT_SVCS)); /* If no runtime services are implemented then simply bail out */ if (RT_SVC_DECS_NUM == 0U) return; /* Initialise internal variables to invalid state */ (void)memset(rt_svc_descs_indices, -1, sizeof(rt_svc_descs_indices)); rt_svc_descs = (rt_svc_desc_t *) RT_SVC_DESCS_START; for (index = 0U; index < RT_SVC_DECS_NUM; index++) { rt_svc_desc_t *service = &rt_svc_descs[index]; /* * An invalid descriptor is an error condition since it is * difficult to predict the system behaviour in the absence * of this service. */ rc = validate_rt_svc_desc(service); if (rc != 0) { ERROR("Invalid runtime service descriptor %p\n", (void *) service); panic(); } /* * The runtime service may have separate rt_svc_desc_t * for its fast smc and yielding smc. Since the service itself * need to be initialized only once, only one of them will have * an initialisation routine defined. Call the initialisation * routine for this runtime service, if it is defined. */ if (service->init != NULL) { rc = service->init(); if (rc != 0) { ERROR("Error initializing runtime service %s\n", service->name); continue; } } /* * Fill the indices corresponding to the start and end * owning entity numbers with the index of the * descriptor which will handle the SMCs for this owning * entity range. */ start_idx = (uint8_t)get_unique_oen(service->start_oen, service->call_type); end_idx = (uint8_t)get_unique_oen(service->end_oen, service->call_type); assert(start_idx <= end_idx); assert(end_idx < MAX_RT_SVCS); for (; start_idx <= end_idx; start_idx++) rt_svc_descs_indices[start_idx] = index; } } trusted-firmware-a-2.2/common/tf_log.c000066400000000000000000000033541355360272700200240ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* Set the default maximum log level to the `LOG_LEVEL` build flag */ static unsigned int max_log_level = LOG_LEVEL; /* * The common log function which is invoked by TF-A code. * This function should not be directly invoked and is meant to be * only used by the log macros defined in debug.h. The function * expects the first character in the format string to be one of the * LOG_MARKER_* macros defined in debug.h. */ void tf_log(const char *fmt, ...) { unsigned int log_level; va_list args; const char *prefix_str; /* We expect the LOG_MARKER_* macro as the first character */ log_level = fmt[0]; /* Verify that log_level is one of LOG_MARKER_* macro defined in debug.h */ assert((log_level > 0U) && (log_level <= LOG_LEVEL_VERBOSE)); assert((log_level % 10U) == 0U); if (log_level > max_log_level) return; prefix_str = plat_log_get_prefix(log_level); while (*prefix_str != '\0') { (void)putchar(*prefix_str); prefix_str++; } va_start(args, fmt); (void)vprintf(fmt + 1, args); va_end(args); } /* * The helper function to set the log level dynamically by platform. The * maximum log level is determined by `LOG_LEVEL` build flag at compile time * and this helper can set a lower (or equal) log level than the one at compile. */ void tf_log_set_max_level(unsigned int log_level) { assert(log_level <= LOG_LEVEL_VERBOSE); assert((log_level % 10U) == 0U); /* Cap log_level to the compile time maximum. */ if (log_level <= (unsigned int)LOG_LEVEL) max_log_level = log_level; } trusted-firmware-a-2.2/dco.txt000066400000000000000000000026151355360272700164230ustar00rootroot00000000000000Developer Certificate of Origin Version 1.1 Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 1 Letterman Drive Suite D4700 San Francisco, CA, 94129 Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Developer's Certificate of Origin 1.1 By making a contribution to this project, I certify that: (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it. (d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. trusted-firmware-a-2.2/docs/000077500000000000000000000000001355360272700160415ustar00rootroot00000000000000trusted-firmware-a-2.2/docs/Makefile000066400000000000000000000013141355360272700175000ustar00rootroot00000000000000# # Copyright (c) 2019, ARM Limited. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Minimal makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build SPHINXPROJ = TrustedFirmware-A SOURCEDIR = . BUILDDIR = build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) trusted-firmware-a-2.2/docs/about/000077500000000000000000000000001355360272700171535ustar00rootroot00000000000000trusted-firmware-a-2.2/docs/about/acknowledgements.rst000066400000000000000000000012771355360272700232460ustar00rootroot00000000000000Contributor Acknowledgements ============================ .. note:: This file is only relevant for legacy contributions, to acknowledge the specific contributors referred to in "Arm Limited and Contributors" copyright notices. As contributors are now encouraged to put their name or company name directly into the copyright notices, this file is not relevant for new contributions. See the :ref:`License` document for the correct template to use for new contributions. - Linaro Limited - Marvell International Ltd. - NVIDIA Corporation - NXP Semiconductors - Socionext Inc. - STMicroelectronics - Xilinx, Inc. -------------- *Copyright (c) 2019, Arm Limited. All rights reserved.* trusted-firmware-a-2.2/docs/about/contact.rst000066400000000000000000000031071355360272700213410ustar00rootroot00000000000000Support & Contact ----------------- We welcome any feedback on |TF-A| and there are several methods for providing it or for obtaining support. .. warning:: If you think you have found a security vulnerability, please report this using the process defined in the :ref:`Security Handling` document. Mailing Lists ^^^^^^^^^^^^^ Public mailing lists for TF-A and the wider Trusted Firmware project are hosted on TrustedFirmware.org. The mailing lists can be used for general enquiries, enhancement requests and issue reports, or to follow and participate in technical or organizational discussions around the project. These discussions include design proposals, advance notice of changes and upcoming events. The relevant lists for the TF-A project are: - `TF-A development`_ - `TF-A-Tests development`_ You can see a `summary of all the lists`_ on the TrustedFirmware.org website. Issue Tracker ^^^^^^^^^^^^^ Specific issues may be raised using the `issue tracker`_ on the TrustedFirmware.org website. Using this tracker makes it easy for the maintainers to prioritise and respond to your ticket. Arm Licensees ^^^^^^^^^^^^^ Arm licensees have an additional support conduit - they may contact Arm directly via their partner managers. .. _`issue tracker`: https://developer.trustedfirmware.org .. _`TF-A development`: https://lists.trustedfirmware.org/pipermail/tf-a/ .. _`TF-A-Tests development`: https://lists.trustedfirmware.org/pipermail/tf-a-tests/ .. _`summary of all the lists`: https://lists.trustedfirmware.org -------------- *Copyright (c) 2019, Arm Limited. All rights reserved.* trusted-firmware-a-2.2/docs/about/features.rst000066400000000000000000000126071355360272700215310ustar00rootroot00000000000000Feature Overview ================ This page provides an overview of the current |TF-A| feature set. For a full description of these features and their implementation details, please see the documents that are part of the *Components* and *System Design* chapters. The :ref:`Change Log & Release Notes` provides details of changes made since the last release. Current features ---------------- - Initialization of the secure world, for example exception vectors, control registers and interrupts for the platform. - Library support for CPU specific reset and power down sequences. This includes support for errata workarounds and the latest Arm DynamIQ CPUs. - Drivers to enable standard initialization of Arm System IP, for example Generic Interrupt Controller (GIC), Cache Coherent Interconnect (CCI), Cache Coherent Network (CCN), Network Interconnect (NIC) and TrustZone Controller (TZC). - A generic |SCMI| driver to interface with conforming power controllers, for example the Arm System Control Processor (SCP). - SMC (Secure Monitor Call) handling, conforming to the `SMC Calling Convention`_ using an EL3 runtime services framework. - |PSCI| library support for CPU, cluster and system power management use-cases. This library is pre-integrated with the AArch64 EL3 Runtime Software, and is also suitable for integration with other AArch32 EL3 Runtime Software, for example an AArch32 Secure OS. - A minimal AArch32 Secure Payload (*SP_MIN*) to demonstrate |PSCI| library integration with AArch32 EL3 Runtime Software. - Secure Monitor library code such as world switching, EL1 context management and interrupt routing. When a Secure-EL1 Payload (SP) is present, for example a Secure OS, the AArch64 EL3 Runtime Software must be integrated with a Secure Payload Dispatcher (SPD) component to customize the interaction with the SP. - A Test SP and SPD to demonstrate AArch64 Secure Monitor functionality and SP interaction with PSCI. - SPDs for the `OP-TEE Secure OS`_, `NVIDIA Trusted Little Kernel`_ and `Trusty Secure OS`_. - A Trusted Board Boot implementation, conforming to all mandatory TBBR requirements. This includes image authentication, Firmware Update (or recovery mode), and packaging of the various firmware images into a Firmware Image Package (FIP). - Pre-integration of TBB with the Arm CryptoCell product, to take advantage of its hardware Root of Trust and crypto acceleration services. - Reliability, Availability, and Serviceability (RAS) functionality, including - A Secure Partition Manager (SPM) to manage Secure Partitions in Secure-EL0, which can be used to implement simple management and security services. - An |SDEI| dispatcher to route interrupt-based |SDEI| events. - An Exception Handling Framework (EHF) that allows dispatching of EL3 interrupts to their registered handlers, to facilitate firmware-first error handling. - A dynamic configuration framework that enables each of the firmware images to be configured at runtime if required by the platform. It also enables loading of a hardware configuration (for example, a kernel device tree) as part of the FIP, to be passed through the firmware stages. - Support for alternative boot flows, for example to support platforms where the EL3 Runtime Software is loaded using other firmware or a separate secure system processor, or where a non-TF-A ROM expects BL2 to be loaded at EL3. - Support for the GCC, LLVM and Arm Compiler 6 toolchains. - Support for combining several libraries into a "romlib" image that may be shared across images to reduce memory footprint. The romlib image is stored in ROM but is accessed through a jump-table that may be stored in read-write memory, allowing for the library code to be patched. - A prototype implementation of a Secure Partition Manager (SPM) that is based on the SPCI Alpha 1 and SPRT draft specifications. - Support for ARMv8.3 pointer authentication in the normal and secure worlds. The use of pointer authentication in the normal world is enabled whenever architectural support is available, without the need for additional build flags. Use of pointer authentication in the secure world remains an experimental configuration at this time and requires the ``BRANCH_PROTECTION`` option to be set to non-zero. - Position-Independent Executable (PIE) support. Initially for BL31 only, with further support to be added in a future release. Still to come ------------- - Support for additional platforms. - Refinements to Position Independent Executable (PIE) support. - Continued support for the draft SPCI specification, to enable the use of secure partition management in the secure world. - Documentation enhancements. - Ongoing support for new architectural features, CPUs and System IP. - Ongoing support for new Arm system architecture specifications. - Ongoing security hardening, optimization and quality improvements. .. _SMC Calling Convention: http://infocenter.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf .. _OP-TEE Secure OS: https://github.com/OP-TEE/optee_os .. _NVIDIA Trusted Little Kernel: http://nv-tegra.nvidia.com/gitweb/?p=3rdparty/ote_partner/tlk.git;a=summary .. _Trusty Secure OS: https://source.android.com/security/trusty -------------- *Copyright (c) 2019, Arm Limited. All rights reserved.* trusted-firmware-a-2.2/docs/about/index.rst000066400000000000000000000002401355360272700210100ustar00rootroot00000000000000About ===== .. toctree:: :maxdepth: 1 :caption: Contents :numbered: features release-information maintainers contact acknowledgements trusted-firmware-a-2.2/docs/about/maintainers.rst000066400000000000000000000210701355360272700222170ustar00rootroot00000000000000Maintainers =========== Trusted Firmware-A (TF-A) is an Arm maintained project. All contributions are ultimately merged by the maintainers listed below. Technical ownership of some parts of the codebase is delegated to the sub-maintainers listed below. An acknowledgement from these sub-maintainers may be required before the maintainers merge a contribution. Main maintainers ---------------- :M: Dan Handley :G: `danh-arm`_ :M: Soby Mathew :G: `soby-mathew`_ :M: Sandrine Bailleux :G: `sandrine-bailleux-arm`_ :M: Alexei Fedorov :G: `AlexeiFedorov`_ :M: Paul Beesley :G: `pbeesley-arm`_ :M: György Szing :G: `gyuri-szing`_ Allwinner ARMv8 platform port ----------------------------- :M: Andre Przywara :G: `Andre-ARM`_ :M: Samuel Holland :G: `smaeul`_ :F: docs/plat/allwinner.rst :F: plat/allwinner/ :F: drivers/allwinner/ Amlogic Meson S905 (GXBB) platform port --------------------------------------- :M: Andre Przywara :G: `Andre-ARM`_ :F: docs/plat/meson-gxbb.rst :F: drivers/amlogic/ :F: plat/amlogic/gxbb/ Amlogic Meson S905x (GXL) platform port --------------------------------------- :M: Remi Pommarel :G: `remi-triplefault`_ :F: docs/plat/meson-gxl.rst :F: drivers/amlogic/gxl :F: plat/amlogic/gxl/ Amlogic Meson S905X2 (G12A) platform port ----------------------------------------- :M: Carlo Caione :G: `carlocaione`_ :F: docs/plat/meson-g12a.rst :F: drivers/amlogic/g12a :F: plat/amlogic/g12a/ Armv7-A architecture port ------------------------- :M: Etienne Carriere :G: `etienne-lms`_ Arm System Guidance for Infrastructure / Mobile FVP platforms ------------------------------------------------------------- :M: Nariman Poushin :G: `npoushin`_ :M: Thomas Abraham :G: `thomas-arm`_ :F: plat/arm/css/sgi/ :F: plat/arm/css/sgm/ :F: plat/arm/board/sgi575/ :F: plat/arm/board/sgm775/ Console API framework --------------------- :M: Julius Werner :G: `jwerner-chromium`_ :F: drivers/console/ :F: include/drivers/console.h :F: plat/common/aarch64/crash_console_helpers.S coreboot support libraries -------------------------- :M: Julius Werner :G: `jwerner-chromium`_ :F: drivers/coreboot/ :F: include/drivers/coreboot/ :F: include/lib/coreboot.h :F: lib/coreboot/ eMMC/UFS drivers ---------------- :M: Haojian Zhuang :G: `hzhuang1`_ :F: drivers/partition/ :F: drivers/synopsys/emmc/ :F: drivers/synopsys/ufs/ :F: drivers/ufs/ :F: include/drivers/dw_ufs.h :F: include/drivers/ufs.h :F: include/drivers/synopsys/dw_mmc.h HiSilicon HiKey and HiKey960 platform ports ------------------------------------------- :M: Haojian Zhuang :G: `hzhuang1`_ :F: docs/plat/hikey.rst :F: docs/plat/hikey960.rst :F: plat/hisilicon/hikey/ :F: plat/hisilicon/hikey960/ HiSilicon Poplar platform port ------------------------------ :M: Shawn Guo :G: `shawnguo2`_ :F: docs/plat/poplar.rst :F: plat/hisilicon/poplar/ Intel SocFPGA platform ports ---------------------------- :M: Tien Hock Loh :G: `thloh85-intel`_ :M: Hadi Asyrafi :G: mabdulha :F: plat/intel/soc :F: drivers/intel/soc/ MediaTek platform ports ----------------------- :M: Yidi Lin (林以廸) :G: `mtk09422`_ :F: plat/mediatek/ Marvell platform ports and SoC drivers -------------------------------------- :M: Konstantin Porotchkin :G: `kostapr`_ :F: docs/marvell/ :F: plat/marvell/ :F: drivers/marvell/ :F: tools/marvell/ NVidia platform ports --------------------- :M: Varun Wadekar :G: `vwadekar`_ :F: docs/plat/nvidia-tegra.rst :F: include/lib/cpus/aarch64/denver.h :F: lib/cpus/aarch64/denver.S :F: plat/nvidia/ NXP QorIQ Layerscape platform ports ----------------------------------- :M: Jiafei Pan :G: `qoriq-open-source`_ :F: docs/plat/ls1043a.rst :F: plat/layerscape/ NXP i.MX 7 WaRP7 platform port and SoC drivers ---------------------------------------------- :M: Bryan O'Donoghue :G: `bryanodonoghue`_ :M: Jun Nie :G: `niej`_ :F: docs/plat/warp7.rst :F: plat/imx/common/ :F: plat/imx/imx7/ :F: drivers/imx/timer/ :F: drivers/imx/uart/ :F: drivers/imx/usdhc/ NXP i.MX 8 platform port ------------------------ :M: Anson Huang :G: `Anson-Huang`_ :F: docs/plat/imx8.rst :F: plat/imx/ NXP i.MX8M platform port ------------------------ :M: Jacky Bai :G: `JackyBai`_ :F: doc/plat/imx8m.rst :F: plat/imx/imx8m/ OP-TEE dispatcher ----------------- :M: Jens Wiklander :G: `jenswi-linaro`_ :F: docs/spd/optee-dispatcher.rst :F: services/spd/opteed/ QEMU platform port ------------------ :M: Jens Wiklander :G: `jenswi-linaro`_ :F: docs/plat/qemu.rst :F: plat/qemu/ Raspberry Pi 3 platform port ---------------------------- :M: Ying-Chun Liu (PaulLiu) :G: `grandpaul`_ :F: docs/plat/rpi3.rst :F: plat/rpi3/ :F: drivers/rpi3/ :F: include/drivers/rpi3/ Renesas rcar-gen3 platform port ------------------------------- :M: Jorge Ramirez-Ortiz :G: `ldts`_ :M: Marek Vasut :G: `marex`_ :F: docs/plat/rcar-gen3.rst :F: plat/renesas/rcar :F: drivers/renesas/rcar :F: tools/renesas/rcar_layout_create RockChip platform port ---------------------- :M: Tony Xie :G: `TonyXie06`_ :G: `rockchip-linux`_ :M: Heiko Stuebner :G: `mmind`_ :F: plat/rockchip/ STM32MP1 platform port ---------------------- :M: Yann Gautier :G: `Yann-lms`_ :F: docs/plat/stm32mp1.rst :F: drivers/st/ :F: fdts/stm32\* :F: include/drivers/st/ :F: include/dt-bindings/\*/stm32\* :F: plat/st/ :F: tools/stm32image/ Synquacer platform port ----------------------- :M: Sumit Garg :G: `b49020`_ :F: docs/plat/synquacer.rst :F: plat/socionext/synquacer/ Texas Instruments platform port ------------------------------- :M: Andrew F. Davis :G: `glneo`_ :F: docs/plat/ti-k3.rst :F: plat/ti/ TLK/Trusty secure payloads -------------------------- :M: Varun Wadekar :G: `vwadekar`_ :F: docs/spd/tlk-dispatcher.rst :F: docs/spd/trusty-dispatcher.rst :F: include/bl32/payloads/tlk.h :F: services/spd/tlkd/ :F: services/spd/trusty/ UniPhier platform port ---------------------- :M: Masahiro Yamada :G: `masahir0y`_ :F: docs/plat/socionext-uniphier.rst :F: plat/socionext/uniphier/ Xilinx platform port -------------------- :M: Siva Durga Prasad Paladugu :G: `sivadur`_ :F: docs/plat/xilinx-zynqmp.rst :F: plat/xilinx/ .. _AlexeiFedorov: https://github.com/AlexeiFedorov .. _Andre-ARM: https://github.com/Andre-ARM .. _Anson-Huang: https://github.com/Anson-Huang .. _bryanodonoghue: https://github.com/bryanodonoghue .. _b49020: https://github.com/b49020 .. _carlocaione: https://github.com/carlocaione .. _danh-arm: https://github.com/danh-arm .. _etienne-lms: https://github.com/etienne-lms .. _glneo: https://github.com/glneo .. _grandpaul: https://github.com/grandpaul .. _gyuri-szing: https://github.com/gyuri-szing .. _hzhuang1: https://github.com/hzhuang1 .. _JackyBai: https://github.com/JackyBai .. _jenswi-linaro: https://github.com/jenswi-linaro .. _jwerner-chromium: https://github.com/jwerner-chromium .. _kostapr: https://github.com/kostapr .. _ldts: https://github.com/ldts .. _marex: https://github.com/marex .. _masahir0y: https://github.com/masahir0y .. _mmind: https://github.com/mmind .. _mtk09422: https://github.com/mtk09422 .. _niej: https://github.com/niej .. _npoushin: https://github.com/npoushin .. _pbeesley-arm: https://github.com/pbeesley-arm .. _qoriq-open-source: https://github.com/qoriq-open-source .. _remi-triplefault: https://github.com/repk .. _rockchip-linux: https://github.com/rockchip-linux .. _sandrine-bailleux-arm: https://github.com/sandrine-bailleux-arm .. _shawnguo2: https://github.com/shawnguo2 .. _sivadur: https://github.com/sivadur .. _smaeul: https://github.com/smaeul .. _soby-mathew: https://github.com/soby-mathew .. _thloh85-intel: https://github.com/thloh85-intel .. _thomas-arm: https://github.com/thomas-arm .. _TonyXie06: https://github.com/TonyXie06 .. _vwadekar: https://github.com/vwadekar .. _Yann-lms: https://github.com/Yann-lms trusted-firmware-a-2.2/docs/about/release-information.rst000066400000000000000000000075731355360272700236640ustar00rootroot00000000000000Release Processes ================= Project Release Cadence ----------------------- The project currently aims to do a release once every 6 months which will be tagged on the master branch. There will be a code freeze (stop merging non-essential changes) up to 4 weeks prior to the target release date. The release candidates will start appearing after this and only bug fixes or updates required for the release will be merged. The maintainers are free to use their judgement on what changes are essential for the release. A release branch may be created after code freeze if there are significant changes that need merging onto the integration branch during the merge window. The release testing will be performed on release candidates and depending on issues found, additional release candidates may be created to fix the issues. :: |<----------6 months---------->| |<---4 weeks--->| |<---4 weeks--->| +-----------------------------------------------------------> time | | | | code freeze ver w.x code freeze ver y.z Upcoming Releases ~~~~~~~~~~~~~~~~~ These are the estimated dates for the upcoming release. These may change depending on project requirement and partner feedback. +-----------------+---------------------------+------------------------------+ | Release Version | Target Date | Expected Code Freeze | +=================+===========================+==============================+ | v2.0 | 1st week of Oct '18 | 1st week of Sep '18 | +-----------------+---------------------------+------------------------------+ | v2.1 | 5th week of Mar '19 | 1st week of Mar '19 | +-----------------+---------------------------+------------------------------+ | v2.2 | 4th week of Oct '19 | 1st week of Oct '19 | +-----------------+---------------------------+------------------------------+ | v2.3 | 4th week of Mar '20 | 1st week of Mar '20 | +-----------------+---------------------------+------------------------------+ Removal of Deprecated Interfaces -------------------------------- As mentioned in the :ref:`Platform Compatibility Policy`, this is a live document cataloging all the deprecated interfaces in TF-A project and the Release version after which it will be removed. +--------------------------------+-------------+---------+---------------------------------------------------------+ | Interface | Deprecation | Removed | Comments | | | Date | after | | | | | Release | | +================================+=============+=========+=========================================================+ | ``AARCH32``/``AARCH64`` macros | Oct '19 | v2.3 | Deprecated in favor of ``__aarch64__`` | +--------------------------------+-------------+---------+---------------------------------------------------------+ | ``__ASSEMBLY__`` macro | Oct '19 | v2.3 | Deprecated in favor of ``__ASSEMBLER__`` | +--------------------------------+-------------+---------+---------------------------------------------------------+ | Prototype SPCI-based SPM | Oct '19 | v2.2 | Based on outdated Alpha 1 spec. Will be replaced with | | (services/std_svc/spm) | | | alternative methods of secure partitioning support. | +--------------------------------+-------------+---------+---------------------------------------------------------+ -------------- *Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.* trusted-firmware-a-2.2/docs/change-log.rst000066400000000000000000003236271355360272700206140ustar00rootroot00000000000000Change Log & Release Notes ========================== This document contains a summary of the new features, changes, fixes and known issues in each release of Trusted Firmware-A. Version 2.2 ----------- New Features ^^^^^^^^^^^^ - Architecture - Enable Pointer Authentication (PAuth) support for Secure World - Adds support for ARMv8.3-PAuth in BL1 SMC calls and BL2U image for firmware updates. - Enable Memory Tagging Extension (MTE) support in both secure and non-secure worlds - Adds support for the new Memory Tagging Extension arriving in ARMv8.5. MTE support is now enabled by default on systems that support it at EL0. - To enable it at ELx for both the non-secure and the secure world, the compiler flag ``CTX_INCLUDE_MTE_REGS`` includes register saving and restoring when necessary in order to prevent information leakage between the worlds. - Add support for Branch Target Identification (BTI) - Build System - Modify FVP makefile for CPUs that support both AArch64/32 - AArch32: Allow compiling with soft-float toolchain - Makefile: Add default warning flags - Add Makefile check for PAuth and AArch64 - Add compile-time errors for HW_ASSISTED_COHERENCY flag - Apply compile-time check for AArch64-only CPUs - build_macros: Add mechanism to prevent bin generation. - Add support for default stack-protector flag - spd: opteed: Enable NS_TIMER_SWITCH - plat/arm: Skip BL2U if RESET_TO_SP_MIN flag is set - Add new build option to let each platform select which implementation of spinlocks it wants to use - CPU Support - DSU: Workaround for erratum 798953 and 936184 - Neoverse N1: Force cacheable atomic to near atomic - Neoverse N1: Workaround for erratum 1073348, 1130799, 1165347, 1207823, 1220197, 1257314, 1262606, 1262888, 1275112, 1315703, 1542419 - Neoverse Zeus: Apply the MSR SSBS instruction - cortex-a76AE: Support added for Cortex-A76AE CPU - cortex-a76: Workaround for erratum 1257314, 1262606, 1262888, 1275112, 1286807 - cortex-a65/a65AE: Support added for Cortex-A65 and Cortex-A65AE CPUs - cortex-a65: Enable AMU for Cortex-A65 - cortex-a55: Workaround for erratum 1221012 - cortex-a35: Workaround for erratum 855472 - cortex-a9: Workaround for erratum 794073 - Drivers - console: Allow the console to register multiple times - delay: Timeout detection support - gicv3: Enabled multi-socket GIC redistributor frame discovery and migrated ARM platforms to the new API - Adds ``gicv3_rdistif_probe`` function that delegates the responsibility of discovering the corresponding redistributor base frame to each CPU itself. - sbsa: Add SBSA watchdog driver - st/stm32_hash: Add HASH driver - ti/uart: Add an AArch32 variant - Library at ROM (romlib) - Introduce BTI support in Library at ROM (romlib) - New Platforms Support - amlogic: g12a: New platform support added for the S905X2 (G12A) platform - amlogic: meson/gxl: New platform support added for Amlogic Meson S905x (GXL) - arm/a5ds: New platform support added for A5 DesignStart - arm/corstone: New platform support added for Corstone-700 - intel: New platform support added for Agilex - mediatek: New platform support added for MediaTek mt8183 - qemu/qemu_sbsa: New platform support added for QEMU SBSA platform - renesas/rcar_gen3: plat: New platform support added for D3 - rockchip: New platform support added for px30 - rockchip: New platform support added for rk3288 - rpi: New platform support added for Raspberry Pi 4 - Platforms - arm/common: Introduce wrapper functions to setup secure watchdog - arm/fvp: Add Delay Timer driver to BL1 and BL31 and option for defining platform DRAM2 base - arm/fvp: Add Linux DTS files for 32 bit threaded FVPs - arm/n1sdp: Add code for DDR ECC enablement and BL33 copy to DDR, Initialise CNTFRQ in Non Secure CNTBaseN - arm/juno: Use shared mbedtls heap between BL1 and BL2 and add basic support for dynamic config - imx: Basic support for PicoPi iMX7D, rdc module init, caam module init, aipstz init, IMX_SIP_GET_SOC_INFO, IMX_SIP_BUILDINFO added - intel: Add ncore ccu driver - mediatek/mt81*: Use new bl31_params_parse() helper - nvidia: tegra: Add support for multi console interface - qemu/qemu_sbsa: Adding memory mapping for both FLASH0/FLASH1 - qemu: Added gicv3 support, new console interface in AArch32, and sub-platforms - renesas/rcar_gen3: plat: Add R-Car V3M support, new board revision for H3ULCB, DBSC4 setting before self-refresh mode - socionext/uniphier: Support console based on multi-console - st: stm32mp1: Add OP-TEE, Avenger96, watchdog, LpDDR3, authentication support and general SYSCFG management - ti/k3: common: Add support for J721E, Use coherent memory for shared data, Trap all asynchronous bus errors to EL3 - xilinx/zynqmp: Add support for multi console interface, Initialize IPI table from zynqmp_config_setup() - PSCI - Adding new optional PSCI hook ``pwr_domain_on_finish_late`` - This PSCI hook ``pwr_domain_on_finish_late`` is similar to ``pwr_domain_on_finish`` but is guaranteed to be invoked when the respective core and cluster are participating in coherency. - Security - Speculative Store Bypass Safe (SSBS): Further enhance protection against Spectre variant 4 by disabling speculative loads/stores (SPSR.SSBS bit) by default. - UBSAN support and handlers - Adds support for the Undefined Behaviour sanitizer. There are two types of support offered - minimalistic trapping support which essentially immediately crashes on undefined behaviour and full support with full debug messages. - Tools - cert_create: Add support for bigger RSA key sizes (3KB and 4KB), previously the maximum size was 2KB. - fiptool: Add support to build fiptool on Windows. Changed ^^^^^^^ - Architecture - Refactor ARMv8.3 Pointer Authentication support code - backtrace: Strip PAC field when PAUTH is enabled - Prettify crash reporting output on AArch64. - Rework smc_unknown return code path in smc_handler - Leverage the existing ``el3_exit()`` return routine for smc_unknown return path rather than a custom set of instructions. - BL-Specific - Invalidate dcache build option for BL2 entry at EL3 - Add missing support for BL2_AT_EL3 in XIP memory - Boot Flow - Add helper to parse BL31 parameters (both versions) - Factor out cross-BL API into export headers suitable for 3rd party code - Introduce lightweight BL platform parameter library - Drivers - auth: Memory optimization for Chain of Trust (CoT) description - bsec: Move bsec_mode_is_closed_device() service to platform - cryptocell: Move Cryptocell specific API into driver - gicv3: Prevent pending G1S interrupt from becoming G0 interrupt - mbedtls: Remove weak heap implementation - mmc: Increase delay between ACMD41 retries - mmc: stm32_sdmmc2: Correctly manage block size - mmc: stm32_sdmmc2: Manage max-frequency property from DT - synopsys/emmc: Do not change FIFO TH as this breaks some platforms - synopsys: Update synopsys drivers to not rely on undefined overflow behaviour - ufs: Extend the delay after reset to wait for some slower chips - Platforms - amlogic/meson/gxl: Remove BL2 dependency from BL31 - arm/common: Shorten the Firmware Update (FWU) process - arm/fvp: Remove GIC initialisation from secondary core cold boot - arm/sgm: Temporarily disable shared Mbed TLS heap for SGM - hisilicon: Update hisilicon drivers to not rely on undefined overflow behaviour - imx: imx8: Replace PLAT_IMX8* with PLAT_imx8*, remove duplicated linker symbols and deprecated code include, keep only IRQ 32 unmasked, enable all power domain by default - marvell: Prevent SError accessing PCIe link, Switch to xlat_tables_v2, do not rely on argument passed via smc, make sure that comphy init will use correct address - mediatek: mt8173: Refactor RTC and PMIC drivers - mediatek: mt8173: Apply MULTI_CONSOLE framework - nvidia: Tegra: memctrl_v2: fix "overflow before widen" coverity issue - qemu: Simplify the image size calculation, Move and generalise FDT PSCI fixup, move gicv2 codes to separate file - renesas/rcar_gen3: Convert to multi-console API, update QoS setting, Update IPL and Secure Monitor Rev2.0.4, Change to restore timer counter value at resume, Update DDR setting rev.0.35, qos: change subslot cycle, Change periodic write DQ training option. - rockchip: Allow SOCs with undefined wfe check bits, Streamline and complete UARTn_BASE macros, drop rockchip-specific imported linker symbols for bl31, Disable binary generation for all SOCs, Allow console device to be set by DTB, Use new bl31_params_parse functions - rpi/rpi3: Move shared rpi3 files into common directory - socionext/uniphier: Set CONSOLE_FLAG_TRANSLATE_CRLF and clean up console driver - socionext/uniphier: Replace DIV_ROUND_UP() with div_round_up() from utils_def.h - st/stm32mp: Split stm32mp_io_setup function, move stm32_get_gpio_bank_clock() to private file, correctly handle Clock Spreading Generator, move oscillator functions to generic file, realign device tree files with internal devs, enable RTCAPB clock for dual-core chips, use a common function to check spinlock is available, move check_header() to common code - ti/k3: Enable SEPARATE_CODE_AND_RODATA by default, Remove shared RAM space, Drop _ADDRESS from K3_USART_BASE to match other defines, Remove MSMC port definitions, Allow USE_COHERENT_MEM for K3, Set L2 latency on A72 cores - PSCI - PSCI: Lookup list of parent nodes to lock only once - Secure Partition Manager (SPM): SPCI Prototype - Fix service UUID lookup - Adjust size of virtual address space per partition - Refactor xlat context creation - Move shim layer to TTBR1_EL1 - Ignore empty regions in resource description - Security - Refactor SPSR initialisation code - SMMUv3: Abort DMA transactions - For security DMA should be blocked at the SMMU by default unless explicitly enabled for a device. SMMU is disabled after reset with all streams bypassing the SMMU, and abortion of all incoming transactions implements a default deny policy on reset. - Moves ``bl1_platform_setup()`` function from arm_bl1_setup.c to FVP platforms' fvp_bl1_setup.c and fvp_ve_bl1_setup.c files. - Tools - cert_create: Remove RSA PKCS#1 v1.5 support Resolved Issues ^^^^^^^^^^^^^^^ - Architecture - Fix the CAS spinlock implementation by adding a missing DSB in ``spin_unlock()`` - AArch64: Fix SCTLR bit definitions - Removes incorrect ``SCTLR_V_BIT`` definition and adds definitions for ARMv8.3-Pauth `EnIB`, `EnDA` and `EnDB` bits. - Fix restoration of PAuth context - Replace call to ``pauth_context_save()`` with ``pauth_context_restore()`` in case of unknown SMC call. - BL-Specific Issues - Fix BL31 crash reporting on AArch64 only platforms - Build System - Remove several warnings reported with W=2 and W=1 - Code Quality Issues - SCTLR and ACTLR are 32-bit for AArch32 and 64-bit for AArch64 - Unify type of "cpu_idx" across PSCI module. - Assert if power level value greater then PSCI_INVALID_PWR_LVL - Unsigned long should not be used as per coding guidelines - Reduce the number of memory leaks in cert_create - Fix type of cot_desc_ptr - Use explicit-width data types in AAPCS parameter structs - Add python configuration for editorconfig - BL1: Fix type consistency - Enable -Wshift-overflow=2 to check for undefined shift behavior - Updated upstream platforms to not rely on undefined overflow behaviour - Coverity Quality Issues - Remove GGC ignore -Warray-bounds - Fix Coverity #261967, Infinite loop - Fix Coverity #343017, Missing unlock - Fix Coverity #343008, Side affect in assertion - Fix Coverity #342970, Uninitialized scalar variable - CPU Support - cortex-a12: Fix MIDR mask - Drivers - console: Remove Arm console unregister on suspend - gicv3: Fix support for full SPI range - scmi: Fix wrong payload length - Library Code - libc: Fix sparse warning for __assert() - libc: Fix memchr implementation - Platforms - rpi: rpi3: Fix compilation error when stack protector is enabled - socionext/uniphier: Fix compilation fail for SPM support build config - st/stm32mp1: Fix TZC400 configuration against non-secure DDR - ti/k3: common: Fix RO data area size calculation - Security - AArch32: Disable Secure Cycle Counter - Changes the implementation for disabling Secure Cycle Counter. For ARMv8.5 the counter gets disabled by setting ``SDCR.SCCD`` bit on CPU cold/warm boot. For the earlier architectures PMCR register is saved/restored on secure world entry/exit from/to Non-secure state, and cycle counting gets disabled by setting PMCR.DP bit. - AArch64: Disable Secure Cycle Counter - For ARMv8.5 the counter gets disabled by setting ``MDCR_El3.SCCD`` bit on CPU cold/warm boot. For the earlier architectures PMCR_EL0 register is saved/restored on secure world entry/exit from/to Non-secure state, and cycle counting gets disabled by setting PMCR_EL0.DP bit. Deprecations ^^^^^^^^^^^^ - Common Code - Remove MULTI_CONSOLE_API flag and references to it - Remove deprecated `plat_crash_console_*` - Remove deprecated interfaces `get_afflvl_shift`, `mpidr_mask_lower_afflvls`, `eret` - AARCH32/AARCH64 macros are now deprecated in favor of ``__aarch64__`` - ``__ASSEMBLY__`` macro is now deprecated in favor of ``__ASSEMBLER__`` - Drivers - console: Removed legacy console API - console: Remove deprecated finish_console_register - tzc: Remove deprecated types `tzc_action_t` and `tzc_region_attributes_t` - Secure Partition Manager (SPM): - Prototype SPCI-based SPM (services/std_svc/spm) will be replaced with alternative methods of secure partitioning support. Known Issues ^^^^^^^^^^^^ - Build System Issues - dtb: DTB creation not supported when building on a Windows host. This step in the build process is skipped when running on a Windows host. A known issue from the 1.6 release. - Platform Issues - arm/juno: System suspend from Linux does not function as documented in the user guide Following the instructions provided in the user guide document does not result in the platform entering system suspend state as expected. A message relating to the hdlcd driver failing to suspend will be emitted on the Linux terminal. - mediatek/mt6795: This platform does not build in this release Version 2.1 ----------- New Features ^^^^^^^^^^^^ - Architecture - Support for ARMv8.3 pointer authentication in the normal and secure worlds The use of pointer authentication in the normal world is enabled whenever architectural support is available, without the need for additional build flags. Use of pointer authentication in the secure world remains an experimental configuration at this time. Using both the ``ENABLE_PAUTH`` and ``CTX_INCLUDE_PAUTH_REGS`` build flags, pointer authentication can be enabled in EL3 and S-EL1/0. See the :ref:`Firmware Design` document for additional details on the use of pointer authentication. - Enable Data Independent Timing (DIT) in EL3, where supported - Build System - Support for BL-specific build flags - Support setting compiler target architecture based on ``ARM_ARCH_MINOR`` build option. - New ``RECLAIM_INIT_CODE`` build flag: A significant amount of the code used for the initialization of BL31 is not needed again after boot time. In order to reduce the runtime memory footprint, the memory used for this code can be reclaimed after initialization. Certain boot-time functions were marked with the ``__init`` attribute to enable this reclamation. - CPU Support - cortex-a76: Workaround for erratum 1073348 - cortex-a76: Workaround for erratum 1220197 - cortex-a76: Workaround for erratum 1130799 - cortex-a75: Workaround for erratum 790748 - cortex-a75: Workaround for erratum 764081 - cortex-a73: Workaround for erratum 852427 - cortex-a73: Workaround for erratum 855423 - cortex-a57: Workaround for erratum 817169 - cortex-a57: Workaround for erratum 814670 - cortex-a55: Workaround for erratum 903758 - cortex-a55: Workaround for erratum 846532 - cortex-a55: Workaround for erratum 798797 - cortex-a55: Workaround for erratum 778703 - cortex-a55: Workaround for erratum 768277 - cortex-a53: Workaround for erratum 819472 - cortex-a53: Workaround for erratum 824069 - cortex-a53: Workaround for erratum 827319 - cortex-a17: Workaround for erratum 852423 - cortex-a17: Workaround for erratum 852421 - cortex-a15: Workaround for erratum 816470 - cortex-a15: Workaround for erratum 827671 - Documentation - Exception Handling Framework documentation - Library at ROM (romlib) documentation - RAS framework documentation - Coding Guidelines document - Drivers - ccn: Add API for setting and reading node registers - Adds ``ccn_read_node_reg`` function - Adds ``ccn_write_node_reg`` function - partition: Support MBR partition entries - scmi: Add ``plat_css_get_scmi_info`` function Adds a new API ``plat_css_get_scmi_info`` which lets the platform register a platform-specific instance of ``scmi_channel_plat_info_t`` and remove the default values - tzc380: Add TZC-380 TrustZone Controller driver - tzc-dmc620: Add driver to manage the TrustZone Controller within the DMC-620 Dynamic Memory Controller - Library at ROM (romlib) - Add platform-specific jump table list - Allow patching of romlib functions This change allows patching of functions in the romlib. This can be done by adding "patch" at the end of the jump table entry for the function that needs to be patched in the file jmptbl.i. - Library Code - Support non-LPAE-enabled MMU tables in AArch32 - mmio: Add ``mmio_clrsetbits_16`` function - 16-bit variant of ``mmio_clrsetbits`` - object_pool: Add Object Pool Allocator - Manages object allocation using a fixed-size static array - Adds ``pool_alloc`` and ``pool_alloc_n`` functions - Does not provide any functions to free allocated objects (by design) - libc: Added ``strlcpy`` function - libc: Import ``strrchr`` function from FreeBSD - xlat_tables: Add support for ARMv8.4-TTST - xlat_tables: Support mapping regions without an explicitly specified VA - Math - Added softudiv macro to support software division - Memory Partitioning And Monitoring (MPAM) - Enabled MPAM EL2 traps (``MPAMHCR_EL2`` and ``MPAM_EL2``) - Platforms - amlogic: Add support for Meson S905 (GXBB) - arm/fvp_ve: Add support for FVP Versatile Express platform - arm/n1sdp: Add support for Neoverse N1 System Development platform - arm/rde1edge: Add support for Neoverse E1 platform - arm/rdn1edge: Add support for Neoverse N1 platform - arm: Add support for booting directly to Linux without an intermediate loader (AArch32) - arm/juno: Enable new CPU errata workarounds for A53 and A57 - arm/juno: Add romlib support Building a combined BL1 and ROMLIB binary file with the correct page alignment is now supported on the Juno platform. When ``USE_ROMLIB`` is set for Juno, it generates the combined file ``bl1_romlib.bin`` which needs to be used instead of bl1.bin. - intel/stratix: Add support for Intel Stratix 10 SoC FPGA platform - marvell: Add support for Armada-37xx SoC platform - nxp: Add support for i.MX8M and i.MX7 Warp7 platforms - renesas: Add support for R-Car Gen3 platform - xilinx: Add support for Versal ACAP platforms - Position-Independent Executable (PIE) PIE support has initially been added to BL31. The ``ENABLE_PIE`` build flag is used to enable or disable this functionality as required. - Secure Partition Manager - New SPM implementation based on SPCI Alpha 1 draft specification A new version of SPM has been implemented, based on the SPCI (Secure Partition Client Interface) and SPRT (Secure Partition Runtime) draft specifications. The new implementation is a prototype that is expected to undergo intensive rework as the specifications change. It has basic support for multiple Secure Partitions and Resource Descriptions. The older version of SPM, based on MM (ARM Management Mode Interface Specification), is still present in the codebase. A new build flag, ``SPM_MM`` has been added to allow selection of the desired implementation. This flag defaults to 1, selecting the MM-based implementation. - Security - Spectre Variant-1 mitigations (``CVE-2017-5753``) - Use Speculation Store Bypass Safe (SSBS) functionality where available Provides mitigation against ``CVE-2018-19440`` (Not saving x0 to x3 registers can leak information from one Normal World SMC client to another) Changed ^^^^^^^ - Build System - Warning levels are now selectable with ``W=<1,2,3>`` - Removed unneeded include paths in PLAT_INCLUDES - "Warnings as errors" (Werror) can be disabled using ``E=0`` - Support totally quiet output with ``-s`` flag - Support passing options to checkpatch using ``CHECKPATCH_OPTS=`` - Invoke host compiler with ``HOSTCC / HOSTCCFLAGS`` instead of ``CC / CFLAGS`` - Make device tree pre-processing similar to U-boot/Linux by: - Creating separate ``CPPFLAGS`` for DT preprocessing so that compiler options specific to it can be accommodated. - Replacing ``CPP`` with ``PP`` for DT pre-processing - CPU Support - Errata report function definition is now mandatory for CPU support files CPU operation files must now define a ``_errata_report`` function to print errata status. This is no longer a weak reference. - Documentation - Migrated some content from GitHub wiki to ``docs/`` directory - Security advisories now have CVE links - Updated copyright guidelines - Drivers - console: The ``MULTI_CONSOLE_API`` framework has been rewritten in C - console: Ported multi-console driver to AArch32 - gic: Remove 'lowest priority' constants Removed ``GIC_LOWEST_SEC_PRIORITY`` and ``GIC_LOWEST_NS_PRIORITY``. Platforms should define these if required, or instead determine the correct priority values at runtime. - delay_timer: Check that the Generic Timer extension is present - mmc: Increase command reply timeout to 10 milliseconds - mmc: Poll eMMC device status to ensure ``EXT_CSD`` command completion - mmc: Correctly check return code from ``mmc_fill_device_info`` - External Libraries - libfdt: Upgraded from 1.4.2 to 1.4.6-9 - mbed TLS: Upgraded from 2.12 to 2.16 This change incorporates fixes for security issues that should be reviewed to determine if they are relevant for software implementations using Trusted Firmware-A. See the `mbed TLS releases`_ page for details on changes from the 2.12 to the 2.16 release. - Library Code - compiler-rt: Updated ``lshrdi3.c`` and ``int_lib.h`` with changes from LLVM master branch (r345645) - cpu: Updated macro that checks need for ``CVE-2017-5715`` mitigation - libc: Made setjmp and longjmp C standard compliant - libc: Allowed overriding the default libc (use ``OVERRIDE_LIBC``) - libc: Moved setjmp and longjmp to the ``libc/`` directory - Platforms - Removed Mbed TLS dependency from plat_bl_common.c - arm: Removed unused ``ARM_MAP_BL_ROMLIB`` macro - arm: Removed ``ARM_BOARD_OPTIMISE_MEM`` feature and build flag - arm: Moved several components into ``drivers/`` directory This affects the SDS, SCP, SCPI, MHU and SCMI components - arm/juno: Increased maximum BL2 image size to ``0xF000`` This change was required to accommodate a larger ``libfdt`` library - SCMI - Optimized bakery locks when hardware-assisted coherency is enabled using the ``HW_ASSISTED_COHERENCY`` build flag - SDEI - Added support for unconditionally resuming secure world execution after |SDEI| event processing completes |SDEI| interrupts, although targeting EL3, occur on behalf of the non-secure world, and may have higher priority than secure world interrupts. Therefore they might preempt secure execution and yield execution to the non-secure |SDEI| handler. Upon completion of |SDEI| event handling, resume secure execution if it was preempted. - Translation Tables (XLAT) - Dynamically detect need for ``Common not Private (TTBRn_ELx.CnP)`` bit Properly handle the case where ``ARMv8.2-TTCNP`` is implemented in a CPU that does not implement all mandatory v8.2 features (and so must claim to implement a lower architecture version). Resolved Issues ^^^^^^^^^^^^^^^ - Architecture - Incorrect check for SSBS feature detection - Unintentional register clobber in AArch32 reset_handler function - Build System - Dependency issue during DTB image build - Incorrect variable expansion in Arm platform makefiles - Building on Windows with verbose mode (``V=1``) enabled is broken - AArch32 compilation flags is missing ``$(march32-directive)`` - BL-Specific Issues - bl2: ``uintptr_t is not defined`` error when ``BL2_IN_XIP_MEM`` is defined - bl2: Missing prototype warning in ``bl2_arch_setup`` - bl31: Omission of Global Offset Table (GOT) section - Code Quality Issues - Multiple MISRA compliance issues - Potential NULL pointer dereference (Coverity-detected) - Drivers - mmc: Local declaration of ``scr`` variable causes a cache issue when invalidating after the read DMA transfer completes - mmc: ``ACMD41`` does not send voltage information during initialization, resulting in the command being treated as a query. This prevents the command from initializing the controller. - mmc: When checking device state using ``mmc_device_state()`` there are no retries attempted in the event of an error - ccn: Incorrect Region ID calculation for RN-I nodes - console: ``Fix MULTI_CONSOLE_API`` when used as a crash console - partition: Improper NULL checking in gpt.c - partition: Compilation failure in ``VERBOSE`` mode (``V=1``) - Library Code - common: Incorrect check for Address Authentication support - xlat: Fix XLAT_V1 / XLAT_V2 incompatibility The file ``arm_xlat_tables.h`` has been renamed to ``xlat_tables_compat.h`` and has been moved to a common folder. This header can be used to guarantee compatibility, as it includes the correct header based on ``XLAT_TABLES_LIB_V2``. - xlat: armclang unused-function warning on ``xlat_clean_dcache_range`` - xlat: Invalid ``mm_cursor`` checks in ``mmap_add`` and ``mmap_add_ctx`` - sdei: Missing ``context.h`` header - Platforms - common: Missing prototype warning for ``plat_log_get_prefix`` - arm: Insufficient maximum BL33 image size - arm: Potential memory corruption during BL2-BL31 transition On Arm platforms, the BL2 memory can be overlaid by BL31/BL32. The memory descriptors describing the list of executable images are created in BL2 R/W memory, which could be possibly corrupted later on by BL31/BL32 due to overlay. This patch creates a reserved location in SRAM for these descriptors and are copied over by BL2 before handing over to next BL image. - juno: Invalid behaviour when ``CSS_USE_SCMI_SDS_DRIVER`` is not set In ``juno_pm.c`` the ``css_scmi_override_pm_ops`` function was used regardless of whether the build flag was set. The original behaviour has been restored in the case where the build flag is not set. - Tools - fiptool: Incorrect UUID parsing of blob parameters - doimage: Incorrect object rules in Makefile Deprecations ^^^^^^^^^^^^ - Common Code - ``plat_crash_console_init`` function - ``plat_crash_console_putc`` function - ``plat_crash_console_flush`` function - ``finish_console_register`` macro - AArch64-specific Code - helpers: ``get_afflvl_shift`` - helpers: ``mpidr_mask_lower_afflvls`` - helpers: ``eret`` - Secure Partition Manager (SPM) - Boot-info structure Known Issues ^^^^^^^^^^^^ - Build System Issues - dtb: DTB creation not supported when building on a Windows host. This step in the build process is skipped when running on a Windows host. A known issue from the 1.6 release. - Platform Issues - arm/juno: System suspend from Linux does not function as documented in the user guide Following the instructions provided in the user guide document does not result in the platform entering system suspend state as expected. A message relating to the hdlcd driver failing to suspend will be emitted on the Linux terminal. - arm/juno: The firmware update use-cases do not work with motherboard firmware version < v1.5.0 (the reset reason is not preserved). The Linaro 18.04 release has MB v1.4.9. The MB v1.5.0 is available in Linaro 18.10 release. - mediatek/mt6795: This platform does not build in this release Version 2.0 ----------- New Features ^^^^^^^^^^^^ - Removal of a number of deprecated APIs - A new Platform Compatibility Policy document has been created which references a wiki page that maintains a listing of deprecated interfaces and the release after which they will be removed. - All deprecated interfaces except the MULTI_CONSOLE_API have been removed from the code base. - Various Arm and partner platforms have been updated to remove the use of removed APIs in this release. - This release is otherwise unchanged from 1.6 release Issues resolved since last release ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - No issues known at 1.6 release resolved in 2.0 release Known Issues ^^^^^^^^^^^^ - DTB creation not supported when building on a Windows host. This step in the build process is skipped when running on a Windows host. Known issue from 1.6 version. - As a result of removal of deprecated interfaces the Nvidia Tegra, Marvell Armada 8K and MediaTek MT6795 platforms do not build in this release. Also MediaTek MT8173, NXP QorIQ LS1043A, NXP i.MX8QX, NXP i.MX8QMa, Rockchip RK3328, Rockchip RK3368 and Rockchip RK3399 platforms have not been confirmed to be working after the removal of the deprecated interfaces although they do build. Version 1.6 ----------- New Features ^^^^^^^^^^^^ - Addressing Speculation Security Vulnerabilities - Implement static workaround for CVE-2018-3639 for AArch32 and AArch64 - Add support for dynamic mitigation for CVE-2018-3639 - Implement dynamic mitigation for CVE-2018-3639 on Cortex-A76 - Ensure |SDEI| handler executes with CVE-2018-3639 mitigation enabled - Introduce RAS handling on AArch64 - Some RAS extensions are mandatory for Armv8.2 CPUs, with others mandatory for Armv8.4 CPUs however, all extensions are also optional extensions to the base Armv8.0 architecture. - The Armv8 RAS Extensions introduced Standard Error Records which are a set of standard registers to configure RAS node policy and allow RAS Nodes to record and expose error information for error handling agents. - Capabilities are provided to support RAS Node enumeration and iteration along with individual interrupt registrations and fault injections support. - Introduce handlers for Uncontainable errors, Double Faults and EL3 External Aborts - Enable Memory Partitioning And Monitoring (MPAM) for lower EL's - Memory Partitioning And Monitoring is an Armv8.4 feature that enables various memory system components and resources to define partitions. Software running at various ELs can then assign themselves to the desired partition to control their performance aspects. - When ENABLE_MPAM_FOR_LOWER_ELS is set to 1, EL3 allows lower ELs to access their own MPAM registers without trapping to EL3. This patch however, doesn't make use of partitioning in EL3; platform initialisation code should configure and use partitions in EL3 if required. - Introduce ROM Lib Feature - Support combining several libraries into a self-called "romlib" image, that may be shared across images to reduce memory footprint. The romlib image is stored in ROM but is accessed through a jump-table that may be stored in read-write memory, allowing for the library code to be patched. - Introduce Backtrace Feature - This function displays the backtrace, the current EL and security state to allow a post-processing tool to choose the right binary to interpret the dump. - Print backtrace in assert() and panic() to the console. - Code hygiene changes and alignment with MISRA C-2012 guideline with fixes addressing issues complying to the following rules: - MISRA rules 4.9, 5.1, 5.3, 5.7, 8.2-8.5, 8.8, 8.13, 9.3, 10.1, 10.3-10.4, 10.8, 11.3, 11.6, 12.1, 14.4, 15.7, 16.1-16.7, 17.7-17.8, 20.7, 20.10, 20.12, 21.1, 21.15, 22.7 - Clean up the usage of void pointers to access symbols - Increase usage of static qualifier to locally used functions and data - Migrated to use of u_register_t for register read/write to better match AArch32 and AArch64 type sizes - Use int-ll64 for both AArch32 and AArch64 to assist in consistent format strings between architectures - Clean up TF-A libc by removing non arm copyrighted implementations and replacing them with modified FreeBSD and SCC implementations - Various changes to support Clang linker and assembler - The clang assembler/preprocessor is used when Clang is selected. However, the clang linker is not used because it is unable to link TF-A objects due to immaturity of clang linker functionality at this time. - Refactor support APIs into Libraries - Evolve libfdt, mbed TLS library and standard C library sources as proper libraries that TF-A may be linked against. - CPU Enhancements - Add CPU support for Cortex-Ares and Cortex-A76 - Add AMU support for Cortex-Ares - Add initial CPU support for Cortex-Deimos - Add initial CPU support for Cortex-Helios - Implement dynamic mitigation for CVE-2018-3639 on Cortex-A76 - Implement Cortex-Ares erratum 1043202 workaround - Implement DSU erratum 936184 workaround - Check presence of fix for errata 843419 in Cortex-A53 - Check presence of fix for errata 835769 in Cortex-A53 - Translation Tables Enhancements - The xlat v2 library has been refactored in order to be reused by different TF components at different EL's including the addition of EL2. Some refactoring to make the code more generic and less specific to TF, in order to reuse the library outside of this project. - SPM Enhancements - General cleanups and refactoring to pave the way to multiple partitions support - SDEI Enhancements - Allow platforms to define explicit events - Determine client EL from NS context's SCR_EL3 - Make dispatches synchronous - Introduce jump primitives for BL31 - Mask events after CPU wakeup in |SDEI| dispatcher to conform to the specification - Misc TF-A Core Common Code Enhancements - Add support for eXecute In Place (XIP) memory in BL2 - Add support for the SMC Calling Convention 2.0 - Introduce External Abort handling on AArch64 External Abort routed to EL3 was reported as an unhandled exception and caused a panic. This change enables Trusted Firmware-A to handle External Aborts routed to EL3. - Save value of ACTLR_EL1 implementation-defined register in the CPU context structure rather than forcing it to 0. - Introduce ARM_LINUX_KERNEL_AS_BL33 build option, which allows BL31 to directly jump to a Linux kernel. This makes for a quicker and simpler boot flow, which might be useful in some test environments. - Add dynamic configurations for BL31, BL32 and BL33 enabling support for Chain of Trust (COT). - Make TF UUID RFC 4122 compliant - New Platform Support - Arm SGI-575 - Arm SGM-775 - Allwinner sun50i_64 - Allwinner sun50i_h6 - NXP QorIQ LS1043A - NXP i.MX8QX - NXP i.MX8QM - NXP i.MX7Solo WaRP7 - TI K3 - Socionext Synquacer SC2A11 - Marvell Armada 8K - STMicroelectronics STM32MP1 - Misc Generic Platform Common Code Enhancements - Add MMC framework that supports both eMMC and SD card devices - Misc Arm Platform Common Code Enhancements - Demonstrate PSCI MEM_PROTECT from el3_runtime - Provide RAS support - Migrate AArch64 port to the multi console driver. The old API is deprecated and will eventually be removed. - Move BL31 below BL2 to enable BL2 overlay resulting in changes in the layout of BL images in memory to enable more efficient use of available space. - Add cpp build processing for dtb that allows processing device tree with external includes. - Extend FIP io driver to support multiple FIP devices - Add support for SCMI AP core configuration protocol v1.0 - Use SCMI AP core protocol to set the warm boot entrypoint - Add support to Mbed TLS drivers for shared heap among different BL images to help optimise memory usage - Enable non-secure access to UART1 through a build option to support a serial debug port for debugger connection - Enhancements for Arm Juno Platform - Add support for TrustZone Media Protection 1 (TZMP1) - Enhancements for Arm FVP Platform - Dynamic_config: remove the FVP dtb files - Set DYNAMIC_WORKAROUND_CVE_2018_3639=1 on FVP by default - Set the ability to dynamically disable Trusted Boot Board authentication to be off by default with DYN_DISABLE_AUTH - Add librom enhancement support in FVP - Support shared Mbed TLS heap between BL1 and BL2 that allow a reduction in BL2 size for FVP - Enhancements for Arm SGI/SGM Platform - Enable ARM_PLAT_MT flag for SGI-575 - Add dts files to enable support for dynamic config - Add RAS support - Support shared Mbed TLS heap for SGI and SGM between BL1 and BL2 - Enhancements for Non Arm Platforms - Raspberry Pi Platform - Hikey Platforms - Xilinx Platforms - QEMU Platform - Rockchip rk3399 Platform - TI Platforms - Socionext Platforms - Allwinner Platforms - NXP Platforms - NVIDIA Tegra Platform - Marvell Platforms - STMicroelectronics STM32MP1 Platform Issues resolved since last release ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - No issues known at 1.5 release resolved in 1.6 release Known Issues ^^^^^^^^^^^^ - DTB creation not supported when building on a Windows host. This step in the build process is skipped when running on a Windows host. Known issue from 1.5 version. Version 1.5 ----------- New features ^^^^^^^^^^^^ - Added new firmware support to enable RAS (Reliability, Availability, and Serviceability) functionality. - Secure Partition Manager (SPM): A Secure Partition is a software execution environment instantiated in S-EL0 that can be used to implement simple management and security services. The SPM is the firmware component that is responsible for managing a Secure Partition. - SDEI dispatcher: Support for interrupt-based |SDEI| events and all interfaces as defined by the |SDEI| specification v1.0, see `SDEI Specification`_ - Exception Handling Framework (EHF): Framework that allows dispatching of EL3 interrupts to their registered handlers which are registered based on their priorities. Facilitates firmware-first error handling policy where asynchronous exceptions may be routed to EL3. Integrated the TSPD with EHF. - Updated PSCI support: - Implemented PSCI v1.1 optional features `MEM_PROTECT` and `SYSTEM_RESET2`. The supported PSCI version was updated to v1.1. - Improved PSCI STAT timestamp collection, including moving accounting for retention states to be inside the locks and fixing handling of wrap-around when calculating residency in AArch32 execution state. - Added optional handler for early suspend that executes when suspending to a power-down state and with data caches enabled. This may provide a performance improvement on platforms where it is safe to perform some or all of the platform actions from `pwr_domain_suspend` with the data caches enabled. - Enabled build option, BL2_AT_EL3, for BL2 to allow execution at EL3 without any dependency on TF BL1. This allows platforms which already have a non-TF Boot ROM to directly load and execute BL2 and subsequent BL stages without need for BL1. This was not previously possible because BL2 executes at S-EL1 and cannot jump straight to EL3. - Implemented support for SMCCC v1.1, including `SMCCC_VERSION` and `SMCCC_ARCH_FEATURES`. Additionally, added support for `SMCCC_VERSION` in PSCI features to enable discovery of the SMCCC version via PSCI feature call. - Added Dynamic Configuration framework which enables each of the boot loader stages to be dynamically configured at runtime if required by the platform. The boot loader stage may optionally specify a firmware configuration file and/or hardware configuration file that can then be shared with the next boot loader stage. Introduced a new BL handover interface that essentially allows passing of 4 arguments between the different BL stages. Updated cert_create and fip_tool to support the dynamic configuration files. The COT also updated to support these new files. - Code hygiene changes and alignment with MISRA guideline: - Fix use of undefined macros. - Achieved compliance with Mandatory MISRA coding rules. - Achieved compliance for following Required MISRA rules for the default build configurations on FVP and Juno platforms : 7.3, 8.3, 8.4, 8.5 and 8.8. - Added support for Armv8.2-A architectural features: - Updated translation table set-up to set the CnP (Common not Private) bit for secure page tables so that multiple PEs in the same Inner Shareable domain can use the same translation table entries for a given stage of translation in a particular translation regime. - Extended the supported values of ID_AA64MMFR0_EL1.PARange to include the 52-bit Physical Address range. - Added support for the Scalable Vector Extension to allow Normal world software to access SVE functionality but disable access to SVE, SIMD and floating point functionality from the Secure world in order to prevent corruption of the Z-registers. - Added support for Armv8.4-A architectural feature Activity Monitor Unit (AMU) extensions. In addition to the v8.4 architectural extension, AMU support on Cortex-A75 was implemented. - Enhanced OP-TEE support to enable use of pageable OP-TEE image. The Arm standard platforms are updated to load up to 3 images for OP-TEE; header, pager image and paged image. The chain of trust is extended to support the additional images. - Enhancements to the translation table library: - Introduced APIs to get and set the memory attributes of a region. - Added support to manage both privilege levels in translation regimes that describe translations for 2 Exception levels, specifically the EL1&0 translation regime, and extended the memory map region attributes to include specifying Non-privileged access. - Added support to specify the granularity of the mappings of each region, for instance a 2MB region can be specified to be mapped with 4KB page tables instead of a 2MB block. - Disabled the higher VA range to avoid unpredictable behaviour if there is an attempt to access addresses in the higher VA range. - Added helpers for Device and Normal memory MAIR encodings that align with the Arm Architecture Reference Manual for Armv8-A (Arm DDI0487B.b). - Code hygiene including fixing type length and signedness of constants, refactoring of function to enable the MMU, removing all instances where the virtual address space is hardcoded and added comments that document alignment needed between memory attributes and attributes specified in TCR_ELx. - Updated GIC support: - Introduce new APIs for GICv2 and GICv3 that provide the capability to specify interrupt properties rather than list of interrupt numbers alone. The Arm platforms and other upstream platforms are migrated to use interrupt properties. - Added helpers to save / restore the GICv3 context, specifically the Distributor and Redistributor contexts and architectural parts of the ITS power management. The Distributor and Redistributor helpers also support the implementation-defined part of GIC-500 and GIC-600. Updated the Arm FVP platform to save / restore the GICv3 context on system suspend / resume as an example of how to use the helpers. Introduced a new TZC secured DDR carve-out for use by Arm platforms for storing EL3 runtime data such as the GICv3 register context. - Added support for Armv7-A architecture via build option ARM_ARCH_MAJOR=7. This includes following features: - Updates GICv2 driver to manage GICv1 with security extensions. - Software implementation for 32bit division. - Enabled use of generic timer for platforms that do not set ARM_CORTEX_Ax=yes. - Support for Armv7-A Virtualization extensions [DDI0406C_C]. - Support for both Armv7-A platforms that only have 32-bit addressing and Armv7-A platforms that support large page addressing. - Included support for following Armv7 CPUs: Cortex-A12, Cortex-A17, Cortex-A7, Cortex-A5, Cortex-A9, Cortex-A15. - Added support in QEMU for Armv7-A/Cortex-A15. - Enhancements to Firmware Update feature: - Updated the FWU documentation to describe the additional images needed for Firmware update, and how they are used for both the Juno platform and the Arm FVP platforms. - Enhancements to Trusted Board Boot feature: - Added support to cert_create tool for RSA PKCS1# v1.5 and SHA384, SHA512 and SHA256. - For Arm platforms added support to use ECDSA keys. - Enhanced the mbed TLS wrapper layer to include support for both RSA and ECDSA to enable runtime selection between RSA and ECDSA keys. - Added support for secure interrupt handling in AArch32 sp_min, hardcoded to only handle FIQs. - Added support to allow a platform to load images from multiple boot sources, for example from a second flash drive. - Added a logging framework that allows platforms to reduce the logging level at runtime and additionally the prefix string can be defined by the platform. - Further improvements to register initialisation: - Control register PMCR_EL0 / PMCR is set to prohibit cycle counting in the secure world. This register is added to the list of registers that are saved and restored during world switch. - When EL3 is running in AArch32 execution state, the Non-secure version of SCTLR is explicitly initialised during the warmboot flow rather than relying on the hardware to set the correct reset values. - Enhanced support for Arm platforms: - Introduced driver for Shared-Data-Structure (SDS) framework which is used for communication between SCP and the AP CPU, replacing Boot-Over_MHU (BOM) protocol. The Juno platform is migrated to use SDS with the SCMI support added in v1.3 and is set as default. The driver can be found in the plat/arm/css/drivers folder. - Improved memory usage by only mapping TSP memory region when the TSPD has been included in the build. This reduces the memory footprint and avoids unnecessary memory being mapped. - Updated support for multi-threading CPUs for FVP platforms - always check the MT field in MPDIR and access the bit fields accordingly. - Support building for platforms that model DynamIQ configuration by implementing all CPUs in a single cluster. - Improved nor flash driver, for instance clearing status registers before sending commands. Driver can be found plat/arm/board/common folder. - Enhancements to QEMU platform: - Added support for TBB. - Added support for using OP-TEE pageable image. - Added support for LOAD_IMAGE_V2. - Migrated to use translation table library v2 by default. - Added support for SEPARATE_CODE_AND_RODATA. - Applied workarounds CVE-2017-5715 on Arm Cortex-A57, -A72, -A73 and -A75, and for Armv7-A CPUs Cortex-A9, -A15 and -A17. - Applied errata workaround for Arm Cortex-A57: 859972. - Applied errata workaround for Arm Cortex-A72: 859971. - Added support for Poplar 96Board platform. - Added support for Raspberry Pi 3 platform. - Added Call Frame Information (CFI) assembler directives to the vector entries which enables debuggers to display the backtrace of functions that triggered a synchronous abort. - Added ability to build dtb. - Added support for pre-tool (cert_create and fiptool) image processing enabling compression of the image files before processing by cert_create and fiptool. This can reduce fip size and may also speed up loading of images. The image verification will also get faster because certificates are generated based on compressed images. Imported zlib 1.2.11 to implement gunzip() for data compression. - Enhancements to fiptool: - Enabled the fiptool to be built using Visual Studio. - Added padding bytes at the end of the last image in the fip to be facilitate transfer by DMA. Issues resolved since last release ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - TF-A can be built with optimisations disabled (-O0). - Memory layout updated to enable Trusted Board Boot on Juno platform when running TF-A in AArch32 execution mode (resolving `tf-issue#501`_). Known Issues ^^^^^^^^^^^^ - DTB creation not supported when building on a Windows host. This step in the build process is skipped when running on a Windows host. Version 1.4 ----------- New features ^^^^^^^^^^^^ - Enabled support for platforms with hardware assisted coherency. A new build option HW_ASSISTED_COHERENCY allows platforms to take advantage of the following optimisations: - Skip performing cache maintenance during power-up and power-down. - Use spin-locks instead of bakery locks. - Enable data caches early on warm-booted CPUs. - Added support for Cortex-A75 and Cortex-A55 processors. Both Cortex-A75 and Cortex-A55 processors use the Arm DynamIQ Shared Unit (DSU). The power-down and power-up sequences are therefore mostly managed in hardware, reducing complexity of the software operations. - Introduced Arm GIC-600 driver. Arm GIC-600 IP complies with Arm GICv3 architecture. For FVP platforms, the GIC-600 driver is chosen when FVP_USE_GIC_DRIVER is set to FVP_GIC600. - Updated GICv3 support: - Introduced power management APIs for GICv3 Redistributor. These APIs allow platforms to power down the Redistributor during CPU power on/off. Requires the GICv3 implementations to have power management operations. Implemented the power management APIs for FVP. - GIC driver data is flushed by the primary CPU so that secondary CPU do not read stale GIC data. - Added support for Arm System Control and Management Interface v1.0 (SCMI). The SCMI driver implements the power domain management and system power management protocol of the SCMI specification (Arm DEN 0056ASCMI) for communicating with any compliant power controller. Support is added for the Juno platform. The driver can be found in the plat/arm/css/drivers folder. - Added support to enable pre-integration of TBB with the Arm TrustZone CryptoCell product, to take advantage of its hardware Root of Trust and crypto acceleration services. - Enabled Statistical Profiling Extensions for lower ELs. The firmware support is limited to the use of SPE in the Non-secure state and accesses to the SPE specific registers from S-EL1 will trap to EL3. The SPE are architecturally specified for AArch64 only. - Code hygiene changes aligned with MISRA guidelines: - Fixed signed / unsigned comparison warnings in the translation table library. - Added U(_x) macro and together with the existing ULL(_x) macro fixed some of the signed-ness defects flagged by the MISRA scanner. - Enhancements to Firmware Update feature: - The FWU logic now checks for overlapping images to prevent execution of unauthenticated arbitrary code. - Introduced new FWU_SMC_IMAGE_RESET SMC that changes the image loading state machine to go from COPYING, COPIED or AUTHENTICATED states to RESET state. Previously, this was only possible when the authentication of an image failed or when the execution of the image finished. - Fixed integer overflow which addressed TFV-1: Malformed Firmware Update SMC can result in copy of unexpectedly large data into secure memory. - Introduced support for Arm Compiler 6 and LLVM (clang). TF-A can now also be built with the Arm Compiler 6 or the clang compilers. The assembler and linker must be provided by the GNU toolchain. Tested with Arm CC 6.7 and clang 3.9.x and 4.0.x. - Memory footprint improvements: - Introduced `tf_snprintf`, a reduced version of `snprintf` which has support for a limited set of formats. The mbedtls driver is updated to optionally use `tf_snprintf` instead of `snprintf`. - The `assert()` is updated to no longer print the function name, and additional logging options are supported via an optional platform define `PLAT_LOG_LEVEL_ASSERT`, which controls how verbose the assert output is. - Enhancements to TF-A support when running in AArch32 execution state: - Support booting SP_MIN and BL33 in AArch32 execution mode on Juno. Due to hardware limitations, BL1 and BL2 boot in AArch64 state and there is additional trampoline code to warm reset into SP_MIN in AArch32 execution state. - Added support for Arm Cortex-A53/57/72 MPCore processors including the errata workarounds that are already implemented for AArch64 execution state. - For FVP platforms, added AArch32 Trusted Board Boot support, including the Firmware Update feature. - Introduced Arm SiP service for use by Arm standard platforms. - Added new Arm SiP Service SMCs to enable the Non-secure world to read PMF timestamps. Added PMF instrumentation points in TF-A in order to quantify the overall time spent in the PSCI software implementation. - Added new Arm SiP service SMC to switch execution state. This allows the lower exception level to change its execution state from AArch64 to AArch32, or vice verse, via a request to EL3. - Migrated to use SPDX[0] license identifiers to make software license auditing simpler. .. note:: Files that have been imported by FreeBSD have not been modified. [0]: https://spdx.org/ - Enhancements to the translation table library: - Added version 2 of translation table library that allows different translation tables to be modified by using different 'contexts'. Version 1 of the translation table library only allows the current EL's translation tables to be modified. Version 2 of the translation table also added support for dynamic regions; regions that can be added and removed dynamically whilst the MMU is enabled. Static regions can only be added or removed before the MMU is enabled. The dynamic mapping functionality is enabled or disabled when compiling by setting the build option PLAT_XLAT_TABLES_DYNAMIC to 1 or 0. This can be done per-image. - Added support for translation regimes with two virtual address spaces such as the one shared by EL1 and EL0. The library does not support initializing translation tables for EL0 software. - Added support to mark the translation tables as non-cacheable using an additional build option `XLAT_TABLE_NC`. - Added support for GCC stack protection. A new build option ENABLE_STACK_PROTECTOR was introduced that enables compilation of all BL images with one of the GCC -fstack-protector-* options. A new platform function plat_get_stack_protector_canary() was introduced that returns a value used to initialize the canary for stack corruption detection. For increased effectiveness of protection platforms must provide an implementation that returns a random value. - Enhanced support for Arm platforms: - Added support for multi-threading CPUs, indicated by `MT` field in MPDIR. A new build flag `ARM_PLAT_MT` is added, and when enabled, the functions accessing MPIDR assume that the `MT` bit is set for the platform and access the bit fields accordingly. Also, a new API `plat_arm_get_cpu_pe_count` is added when `ARM_PLAT_MT` is enabled, returning the Processing Element count within the physical CPU corresponding to `mpidr`. - The Arm platforms migrated to use version 2 of the translation tables. - Introduced a new Arm platform layer API `plat_arm_psci_override_pm_ops` which allows Arm platforms to modify `plat_arm_psci_pm_ops` and therefore dynamically define PSCI capability. - The Arm platforms migrated to use IMAGE_LOAD_V2 by default. - Enhanced reporting of errata workaround status with the following policy: - If an errata workaround is enabled: - If it applies (i.e. the CPU is affected by the errata), an INFO message is printed, confirming that the errata workaround has been applied. - If it does not apply, a VERBOSE message is printed, confirming that the errata workaround has been skipped. - If an errata workaround is not enabled, but would have applied had it been, a WARN message is printed, alerting that errata workaround is missing. - Added build options ARM_ARCH_MAJOR and ARM_ARM_MINOR to choose the architecture version to target TF-A. - Updated the spin lock implementation to use the more efficient CAS (Compare And Swap) instruction when available. This instruction was introduced in Armv8.1-A. - Applied errata workaround for Arm Cortex-A53: 855873. - Applied errata workaround for Arm-Cortex-A57: 813419. - Enabled all A53 and A57 errata workarounds for Juno, both in AArch64 and AArch32 execution states. - Added support for Socionext UniPhier SoC platform. - Added support for Hikey960 and Hikey platforms. - Added support for Rockchip RK3328 platform. - Added support for NVidia Tegra T186 platform. - Added support for Designware emmc driver. - Imported libfdt v1.4.2 that addresses buffer overflow in fdt_offset_ptr(). - Enhanced the CPU operations framework to allow power handlers to be registered on per-level basis. This enables support for future CPUs that have multiple threads which might need powering down individually. - Updated register initialisation to prevent unexpected behaviour: - Debug registers MDCR-EL3/SDCR and MDCR_EL2/HDCR are initialised to avoid unexpected traps into the higher exception levels and disable secure self-hosted debug. Additionally, secure privileged external debug on Juno is disabled by programming the appropriate Juno SoC registers. - EL2 and EL3 configurable controls are initialised to avoid unexpected traps in the higher exception levels. - Essential control registers are fully initialised on EL3 start-up, when initialising the non-secure and secure context structures and when preparing to leave EL3 for a lower EL. This gives better alignment with the Arm ARM which states that software must initialise RES0 and RES1 fields with 0 / 1. - Enhanced PSCI support: - Introduced new platform interfaces that decouple PSCI stat residency calculation from PMF, enabling platforms to use alternative methods of capturing timestamps. - PSCI stat accounting performed for retention/standby states when requested at multiple power levels. - Simplified fiptool to have a single linked list of image descriptors. - For the TSP, resolved corruption of pre-empted secure context by aborting any pre-empted SMC during PSCI power management requests. Issues resolved since last release ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - TF-A can be built with the latest mbed TLS version (v2.4.2). The earlier version 2.3.0 cannot be used due to build warnings that the TF-A build system interprets as errors. - TBBR, including the Firmware Update feature is now supported on FVP platforms when running TF-A in AArch32 state. - The version of the AEMv8 Base FVP used in this release has resolved the issue of the model executing a reset instead of terminating in response to a shutdown request using the PSCI SYSTEM_OFF API. Known Issues ^^^^^^^^^^^^ - Building TF-A with compiler optimisations disabled (-O0) fails. - Trusted Board Boot currently does not work on Juno when running Trusted Firmware in AArch32 execution state due to error when loading the sp_min to memory because of lack of free space available. See `tf-issue#501`_ for more details. - The errata workaround for A53 errata 843419 is only available from binutils 2.26 and is not present in GCC4.9. If this errata is applicable to the platform, please use GCC compiler version of at least 5.0. See `PR#1002`_ for more details. Version 1.3 ----------- New features ^^^^^^^^^^^^ - Added support for running TF-A in AArch32 execution state. The PSCI library has been refactored to allow integration with **EL3 Runtime Software**. This is software that is executing at the highest secure privilege which is EL3 in AArch64 or Secure SVC/Monitor mode in AArch32. See :ref:`PSCI Library Integration guide for Armv8-A AArch32 systems`. Included is a minimal AArch32 Secure Payload, **SP-MIN**, that illustrates the usage and integration of the PSCI library with EL3 Runtime Software running in AArch32 state. Booting to the BL1/BL2 images as well as booting straight to the Secure Payload is supported. - Improvements to the initialization framework for the PSCI service and Arm Standard Services in general. The PSCI service is now initialized as part of Arm Standard Service initialization. This consolidates the initializations of any Arm Standard Service that may be added in the future. A new function ``get_arm_std_svc_args()`` is introduced to get arguments corresponding to each standard service and must be implemented by the EL3 Runtime Software. For PSCI, a new versioned structure ``psci_lib_args_t`` is introduced to initialize the PSCI Library. **Note** this is a compatibility break due to the change in the prototype of ``psci_setup()``. - To support AArch32 builds of BL1 and BL2, implemented a new, alternative firmware image loading mechanism that adds flexibility. The current mechanism has a hard-coded set of images and execution order (BL31, BL32, etc). The new mechanism is data-driven by a list of image descriptors provided by the platform code. Arm platforms have been updated to support the new loading mechanism. The new mechanism is enabled by a build flag (``LOAD_IMAGE_V2``) which is currently off by default for the AArch64 build. **Note** ``TRUSTED_BOARD_BOOT`` is currently not supported when ``LOAD_IMAGE_V2`` is enabled. - Updated requirements for making contributions to TF-A. Commits now must have a 'Signed-off-by:' field to certify that the contribution has been made under the terms of the :download:`Developer Certificate of Origin <../dco.txt>`. A signed CLA is no longer required. The :ref:`Contributor's Guide` has been updated to reflect this change. - Introduced Performance Measurement Framework (PMF) which provides support for capturing, storing, dumping and retrieving time-stamps to measure the execution time of critical paths in the firmware. This relies on defining fixed sample points at key places in the code. - To support the QEMU platform port, imported libfdt v1.4.1 from https://git.kernel.org/pub/scm/utils/dtc/dtc.git - Updated PSCI support: - Added support for PSCI NODE_HW_STATE API for Arm platforms. - New optional platform hook, ``pwr_domain_pwr_down_wfi()``, in ``plat_psci_ops`` to enable platforms to perform platform-specific actions needed to enter powerdown, including the 'wfi' invocation. - PSCI STAT residency and count functions have been added on Arm platforms by using PMF. - Enhancements to the translation table library: - Limited memory mapping support for region overlaps to only allow regions to overlap that are identity mapped or have the same virtual to physical address offset, and overlap completely but must not cover the same area. This limitation will enable future enhancements without having to support complex edge cases that may not be necessary. - The initial translation lookup level is now inferred from the virtual address space size. Previously, it was hard-coded. - Added support for mapping Normal, Inner Non-cacheable, Outer Non-cacheable memory in the translation table library. This can be useful to map a non-cacheable memory region, such as a DMA buffer. - Introduced the MT_EXECUTE/MT_EXECUTE_NEVER memory mapping attributes to specify the access permissions for instruction execution of a memory region. - Enabled support to isolate code and read-only data on separate memory pages, allowing independent access control to be applied to each. - Enabled SCR_EL3.SIF (Secure Instruction Fetch) bit in BL1 and BL31 common architectural setup code, preventing fetching instructions from non-secure memory when in secure state. - Enhancements to FIP support: - Replaced ``fip_create`` with ``fiptool`` which provides a more consistent and intuitive interface as well as additional support to remove an image from a FIP file. - Enabled printing the SHA256 digest with info command, allowing quick verification of an image within a FIP without having to extract the image and running sha256sum on it. - Added support for unpacking the contents of an existing FIP file into the working directory. - Aligned command line options for specifying images to use same naming convention as specified by TBBR and already used in cert_create tool. - Refactored the TZC-400 driver to also support memory controllers that integrate TZC functionality, for example Arm CoreLink DMC-500. Also added DMC-500 specific support. - Implemented generic delay timer based on the system generic counter and migrated all platforms to use it. - Enhanced support for Arm platforms: - Updated image loading support to make SCP images (SCP_BL2 and SCP_BL2U) optional. - Enhanced topology description support to allow multi-cluster topology definitions. - Added interconnect abstraction layer to help platform ports select the right interconnect driver, CCI or CCN, for the platform. - Added support to allow loading BL31 in the TZC-secured DRAM instead of the default secure SRAM. - Added support to use a System Security Control (SSC) Registers Unit enabling TF-A to be compiled to support multiple Arm platforms and then select one at runtime. - Restricted mapping of Trusted ROM in BL1 to what is actually needed by BL1 rather than entire Trusted ROM region. - Flash is now mapped as execute-never by default. This increases security by restricting the executable region to what is strictly needed. - Applied following erratum workarounds for Cortex-A57: 833471, 826977, 829520, 828024 and 826974. - Added support for Mediatek MT6795 platform. - Added support for QEMU virtualization Armv8-A target. - Added support for Rockchip RK3368 and RK3399 platforms. - Added support for Xilinx Zynq UltraScale+ MPSoC platform. - Added support for Arm Cortex-A73 MPCore Processor. - Added support for Arm Cortex-A72 processor. - Added support for Arm Cortex-A35 processor. - Added support for Arm Cortex-A32 MPCore Processor. - Enabled preloaded BL33 alternative boot flow, in which BL2 does not load BL33 from non-volatile storage and BL31 hands execution over to a preloaded BL33. The User Guide has been updated with an example of how to use this option with a bootwrapped kernel. - Added support to build TF-A on a Windows-based host machine. - Updated Trusted Board Boot prototype implementation: - Enabled the ability for a production ROM with TBBR enabled to boot test software before a real ROTPK is deployed (e.g. manufacturing mode). Added support to use ROTPK in certificate without verifying against the platform value when ``ROTPK_NOT_DEPLOYED`` bit is set. - Added support for non-volatile counter authentication to the Authentication Module to protect against roll-back. - Updated GICv3 support: - Enabled processor power-down and automatic power-on using GICv3. - Enabled G1S or G0 interrupts to be configured independently. - Changed FVP default interrupt driver to be the GICv3-only driver. **Note** the default build of TF-A will not be able to boot Linux kernel with GICv2 FDT blob. - Enabled wake-up from CPU_SUSPEND to stand-by by temporarily re-routing interrupts and then restoring after resume. Issues resolved since last release ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Known issues ^^^^^^^^^^^^ - The version of the AEMv8 Base FVP used in this release resets the model instead of terminating its execution in response to a shutdown request using the PSCI ``SYSTEM_OFF`` API. This issue will be fixed in a future version of the model. - Building TF-A with compiler optimisations disabled (``-O0``) fails. - TF-A cannot be built with mbed TLS version v2.3.0 due to build warnings that the TF-A build system interprets as errors. - TBBR is not currently supported when running TF-A in AArch32 state. Version 1.2 ----------- New features ^^^^^^^^^^^^ - The Trusted Board Boot implementation on Arm platforms now conforms to the mandatory requirements of the TBBR specification. In particular, the boot process is now guarded by a Trusted Watchdog, which will reset the system in case of an authentication or loading error. On Arm platforms, a secure instance of Arm SP805 is used as the Trusted Watchdog. Also, a firmware update process has been implemented. It enables authenticated firmware to update firmware images from external interfaces to SoC Non-Volatile memories. This feature functions even when the current firmware in the system is corrupt or missing; it therefore may be used as a recovery mode. - Improvements have been made to the Certificate Generation Tool (``cert_create``) as follows. - Added support for the Firmware Update process by extending the Chain of Trust definition in the tool to include the Firmware Update certificate and the required extensions. - Introduced a new API that allows one to specify command line options in the Chain of Trust description. This makes the declaration of the tool's arguments more flexible and easier to extend. - The tool has been reworked to follow a data driven approach, which makes it easier to maintain and extend. - Extended the FIP tool (``fip_create``) to support the new set of images involved in the Firmware Update process. - Various memory footprint improvements. In particular: - The bakery lock structure for coherent memory has been optimised. - The mbed TLS SHA1 functions are not needed, as SHA256 is used to generate the certificate signature. Therefore, they have been compiled out, reducing the memory footprint of BL1 and BL2 by approximately 6 KB. - On Arm development platforms, each BL stage now individually defines the number of regions that it needs to map in the MMU. - Added the following new design documents: - :ref:`Authentication Framework & Chain of Trust` - :ref:`Firmware Update (FWU)` - :ref:`CPU Reset` - :ref:`PSCI Power Domain Tree Structure` - Applied the new image terminology to the code base and documentation, as described in the :ref:`Image Terminology` document. - The build system has been reworked to improve readability and facilitate adding future extensions. - On Arm standard platforms, BL31 uses the boot console during cold boot but switches to the runtime console for any later logs at runtime. The TSP uses the runtime console for all output. - Implemented a basic NOR flash driver for Arm platforms. It programs the device using CFI (Common Flash Interface) standard commands. - Implemented support for booting EL3 payloads on Arm platforms, which reduces the complexity of developing EL3 baremetal code by doing essential baremetal initialization. - Provided separate drivers for GICv3 and GICv2. These expect the entire software stack to use either GICv2 or GICv3; hybrid GIC software systems are no longer supported and the legacy Arm GIC driver has been deprecated. - Added support for Juno r1 and r2. A single set of Juno TF-A binaries can run on Juno r0, r1 and r2 boards. Note that this TF-A version depends on a Linaro release that does *not* contain Juno r2 support. - Added support for MediaTek mt8173 platform. - Implemented a generic driver for Arm CCN IP. - Major rework of the PSCI implementation. - Added framework to handle composite power states. - Decoupled the notions of affinity instances (which describes the hierarchical arrangement of cores) and of power domain topology, instead of assuming a one-to-one mapping. - Better alignment with version 1.0 of the PSCI specification. - Added support for the SYSTEM_SUSPEND PSCI API on Arm platforms. When invoked on the last running core on a supported platform, this puts the system into a low power mode with memory retention. - Unified the reset handling code as much as possible across BL stages. Also introduced some build options to enable optimization of the reset path on platforms that support it. - Added a simple delay timer API, as well as an SP804 timer driver, which is enabled on FVP. - Added support for NVidia Tegra T210 and T132 SoCs. - Reorganised Arm platforms ports to greatly improve code shareability and facilitate the reuse of some of this code by other platforms. - Added support for Arm Cortex-A72 processor in the CPU specific framework. - Provided better error handling. Platform ports can now define their own error handling, for example to perform platform specific bookkeeping or post-error actions. - Implemented a unified driver for Arm Cache Coherent Interconnects used for both CCI-400 & CCI-500 IPs. Arm platforms ports have been migrated to this common driver. The standalone CCI-400 driver has been deprecated. Issues resolved since last release ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - The Trusted Board Boot implementation has been redesigned to provide greater modularity and scalability. See the :ref:`Authentication Framework & Chain of Trust` document. All missing mandatory features are now implemented. - The FVP and Juno ports may now use the hash of the ROTPK stored in the Trusted Key Storage registers to verify the ROTPK. Alternatively, a development public key hash embedded in the BL1 and BL2 binaries might be used instead. The location of the ROTPK is chosen at build-time using the ``ARM_ROTPK_LOCATION`` build option. - GICv3 is now fully supported and stable. Known issues ^^^^^^^^^^^^ - The version of the AEMv8 Base FVP used in this release resets the model instead of terminating its execution in response to a shutdown request using the PSCI ``SYSTEM_OFF`` API. This issue will be fixed in a future version of the model. - While this version has low on-chip RAM requirements, there are further RAM usage enhancements that could be made. - The upstream documentation could be improved for structural consistency, clarity and completeness. In particular, the design documentation is incomplete for PSCI, the TSP(D) and the Juno platform. - Building TF-A with compiler optimisations disabled (``-O0``) fails. Version 1.1 ----------- New features ^^^^^^^^^^^^ - A prototype implementation of Trusted Board Boot has been added. Boot loader images are verified by BL1 and BL2 during the cold boot path. BL1 and BL2 use the PolarSSL SSL library to verify certificates and images. The OpenSSL library is used to create the X.509 certificates. Support has been added to ``fip_create`` tool to package the certificates in a FIP. - Support for calling CPU and platform specific reset handlers upon entry into BL3-1 during the cold and warm boot paths has been added. This happens after another Boot ROM ``reset_handler()`` has already run. This enables a developer to perform additional actions or undo actions already performed during the first call of the reset handlers e.g. apply additional errata workarounds. - Support has been added to demonstrate routing of IRQs to EL3 instead of S-EL1 when execution is in secure world. - The PSCI implementation now conforms to version 1.0 of the PSCI specification. All the mandatory APIs and selected optional APIs are supported. In particular, support for the ``PSCI_FEATURES`` API has been added. A capability variable is constructed during initialization by examining the ``plat_pm_ops`` and ``spd_pm_ops`` exported by the platform and the Secure Payload Dispatcher. This is used by the PSCI FEATURES function to determine which PSCI APIs are supported by the platform. - Improvements have been made to the PSCI code as follows. - The code has been refactored to remove redundant parameters from internal functions. - Changes have been made to the code for PSCI ``CPU_SUSPEND``, ``CPU_ON`` and ``CPU_OFF`` calls to facilitate an early return to the caller in case a failure condition is detected. For example, a PSCI ``CPU_SUSPEND`` call returns ``SUCCESS`` to the caller if a pending interrupt is detected early in the code path. - Optional platform APIs have been added to validate the ``power_state`` and ``entrypoint`` parameters early in PSCI ``CPU_ON`` and ``CPU_SUSPEND`` code paths. - PSCI migrate APIs have been reworked to invoke the SPD hook to determine the type of Trusted OS and the CPU it is resident on (if applicable). Also, during a PSCI ``MIGRATE`` call, the SPD hook to migrate the Trusted OS is invoked. - It is now possible to build TF-A without marking at least an extra page of memory as coherent. The build flag ``USE_COHERENT_MEM`` can be used to choose between the two implementations. This has been made possible through these changes. - An implementation of Bakery locks, where the locks are not allocated in coherent memory has been added. - Memory which was previously marked as coherent is now kept coherent through the use of software cache maintenance operations. Approximately, 4K worth of memory is saved for each boot loader stage when ``USE_COHERENT_MEM=0``. Enabling this option increases the latencies associated with acquire and release of locks. It also requires changes to the platform ports. - It is now possible to specify the name of the FIP at build time by defining the ``FIP_NAME`` variable. - Issues with dependencies on the 'fiptool' makefile target have been rectified. The ``fip_create`` tool is now rebuilt whenever its source files change. - The BL3-1 runtime console is now also used as the crash console. The crash console is changed to SoC UART0 (UART2) from the previous FPGA UART0 (UART0) on Juno. In FVP, it is changed from UART0 to UART1. - CPU errata workarounds are applied only when the revision and part number match. This behaviour has been made consistent across the debug and release builds. The debug build additionally prints a warning if a mismatch is detected. - It is now possible to issue cache maintenance operations by set/way for a particular level of data cache. Levels 1-3 are currently supported. - The following improvements have been made to the FVP port. - The build option ``FVP_SHARED_DATA_LOCATION`` which allowed relocation of shared data into the Trusted DRAM has been deprecated. Shared data is now always located at the base of Trusted SRAM. - BL2 Translation tables have been updated to map only the region of DRAM which is accessible to normal world. This is the region of the 2GB DDR-DRAM memory at 0x80000000 excluding the top 16MB. The top 16MB is accessible to only the secure world. - BL3-2 can now reside in the top 16MB of DRAM which is accessible only to the secure world. This can be done by setting the build flag ``FVP_TSP_RAM_LOCATION`` to the value ``dram``. - Separate translation tables are created for each boot loader image. The ``IMAGE_BLx`` build options are used to do this. This allows each stage to create mappings only for areas in the memory map that it needs. - A Secure Payload Dispatcher (OPTEED) for the OP-TEE Trusted OS has been added. Details of using it with TF-A can be found in :ref:`OP-TEE Dispatcher` Issues resolved since last release ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - The Juno port has been aligned with the FVP port as follows. - Support for reclaiming all BL1 RW memory and BL2 memory by overlaying the BL3-1/BL3-2 NOBITS sections on top of them has been added to the Juno port. - The top 16MB of the 2GB DDR-DRAM memory at 0x80000000 is configured using the TZC-400 controller to be accessible only to the secure world. - The Arm GIC driver is used to configure the GIC-400 instead of using a GIC driver private to the Juno port. - PSCI ``CPU_SUSPEND`` calls that target a standby state are now supported. - The TZC-400 driver is used to configure the controller instead of direct accesses to the registers. - The Linux kernel version referred to in the user guide has DVFS and HMP support enabled. - DS-5 v5.19 did not detect Version 5.8 of the Cortex-A57-A53 Base FVPs in CADI server mode. This issue is not seen with DS-5 v5.20 and Version 6.2 of the Cortex-A57-A53 Base FVPs. Known issues ^^^^^^^^^^^^ - The Trusted Board Boot implementation is a prototype. There are issues with the modularity and scalability of the design. Support for a Trusted Watchdog, firmware update mechanism, recovery images and Trusted debug is absent. These issues will be addressed in future releases. - The FVP and Juno ports do not use the hash of the ROTPK stored in the Trusted Key Storage registers to verify the ROTPK in the ``plat_match_rotpk()`` function. This prevents the correct establishment of the Chain of Trust at the first step in the Trusted Board Boot process. - The version of the AEMv8 Base FVP used in this release resets the model instead of terminating its execution in response to a shutdown request using the PSCI ``SYSTEM_OFF`` API. This issue will be fixed in a future version of the model. - GICv3 support is experimental. There are known issues with GICv3 initialization in the TF-A. - While this version greatly reduces the on-chip RAM requirements, there are further RAM usage enhancements that could be made. - The firmware design documentation for the Test Secure-EL1 Payload (TSP) and its dispatcher (TSPD) is incomplete. Similarly for the PSCI section. - The Juno-specific firmware design documentation is incomplete. Version 1.0 ----------- New features ^^^^^^^^^^^^ - It is now possible to map higher physical addresses using non-flat virtual to physical address mappings in the MMU setup. - Wider use is now made of the per-CPU data cache in BL3-1 to store: - Pointers to the non-secure and secure security state contexts. - A pointer to the CPU-specific operations. - A pointer to PSCI specific information (for example the current power state). - A crash reporting buffer. - The following RAM usage improvements result in a BL3-1 RAM usage reduction from 96KB to 56KB (for FVP with TSPD), and a total RAM usage reduction across all images from 208KB to 88KB, compared to the previous release. - Removed the separate ``early_exception`` vectors from BL3-1 (2KB code size saving). - Removed NSRAM from the FVP memory map, allowing the removal of one (4KB) translation table. - Eliminated the internal ``psci_suspend_context`` array, saving 2KB. - Correctly dimensioned the PSCI ``aff_map_node`` array, saving 1.5KB in the FVP port. - Removed calling CPU mpidr from the bakery lock API, saving 160 bytes. - Removed current CPU mpidr from PSCI common code, saving 160 bytes. - Inlined the mmio accessor functions, saving 360 bytes. - Fully reclaimed all BL1 RW memory and BL2 memory on the FVP port by overlaying the BL3-1/BL3-2 NOBITS sections on top of these at runtime. - Made storing the FP register context optional, saving 0.5KB per context (8KB on the FVP port, with TSPD enabled and running on 8 CPUs). - Implemented a leaner ``tf_printf()`` function, allowing the stack to be greatly reduced. - Removed coherent stacks from the codebase. Stacks allocated in normal memory are now used before and after the MMU is enabled. This saves 768 bytes per CPU in BL3-1. - Reworked the crash reporting in BL3-1 to use less stack. - Optimized the EL3 register state stored in the ``cpu_context`` structure so that registers that do not change during normal execution are re-initialized each time during cold/warm boot, rather than restored from memory. This saves about 1.2KB. - As a result of some of the above, reduced the runtime stack size in all BL images. For BL3-1, this saves 1KB per CPU. - PSCI SMC handler improvements to correctly handle calls from secure states and from AArch32. - CPU contexts are now initialized from the ``entry_point_info``. BL3-1 fully determines the exception level to use for the non-trusted firmware (BL3-3) based on the SPSR value provided by the BL2 platform code (or otherwise provided to BL3-1). This allows platform code to directly run non-trusted firmware payloads at either EL2 or EL1 without requiring an EL2 stub or OS loader. - Code refactoring improvements: - Refactored ``fvp_config`` into a common platform header. - Refactored the fvp gic code to be a generic driver that no longer has an explicit dependency on platform code. - Refactored the CCI-400 driver to not have dependency on platform code. - Simplified the IO driver so it's no longer necessary to call ``io_init()`` and moved all the IO storage framework code to one place. - Simplified the interface the the TZC-400 driver. - Clarified the platform porting interface to the TSP. - Reworked the TSPD setup code to support the alternate BL3-2 initialization flow where BL3-1 generic code hands control to BL3-2, rather than expecting the TSPD to hand control directly to BL3-2. - Considerable rework to PSCI generic code to support CPU specific operations. - Improved console log output, by: - Adding the concept of debug log levels. - Rationalizing the existing debug messages and adding new ones. - Printing out the version of each BL stage at runtime. - Adding support for printing console output from assembler code, including when a crash occurs before the C runtime is initialized. - Moved up to the latest versions of the FVPs, toolchain, EDK2, kernel, Linaro file system and DS-5. - On the FVP port, made the use of the Trusted DRAM region optional at build time (off by default). Normal platforms will not have such a "ready-to-use" DRAM area so it is not a good example to use it. - Added support for PSCI ``SYSTEM_OFF`` and ``SYSTEM_RESET`` APIs. - Added support for CPU specific reset sequences, power down sequences and register dumping during crash reporting. The CPU specific reset sequences include support for errata workarounds. - Merged the Juno port into the master branch. Added support for CPU hotplug and CPU idle. Updated the user guide to describe how to build and run on the Juno platform. Issues resolved since last release ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Removed the concept of top/bottom image loading. The image loader now automatically detects the position of the image inside the current memory layout and updates the layout to minimize fragmentation. This resolves the image loader limitations of previously releases. There are currently no plans to support dynamic image loading. - CPU idle now works on the publicized version of the Foundation FVP. - All known issues relating to the compiler version used have now been resolved. This TF-A version uses Linaro toolchain 14.07 (based on GCC 4.9). Known issues ^^^^^^^^^^^^ - GICv3 support is experimental. The Linux kernel patches to support this are not widely available. There are known issues with GICv3 initialization in the TF-A. - While this version greatly reduces the on-chip RAM requirements, there are further RAM usage enhancements that could be made. - The firmware design documentation for the Test Secure-EL1 Payload (TSP) and its dispatcher (TSPD) is incomplete. Similarly for the PSCI section. - The Juno-specific firmware design documentation is incomplete. - Some recent enhancements to the FVP port have not yet been translated into the Juno port. These will be tracked via the tf-issues project. - The Linux kernel version referred to in the user guide has DVFS and HMP support disabled due to some known instabilities at the time of this release. A future kernel version will re-enable these features. - DS-5 v5.19 does not detect Version 5.8 of the Cortex-A57-A53 Base FVPs in CADI server mode. This is because the ```` reported by the FVP in this version has changed. For example, for the Cortex-A57x4-A53x4 Base FVP, the ```` reported by the FVP is ``FVP_Base_Cortex_A57x4_A53x4``, while DS-5 expects it to be ``FVP_Base_A57x4_A53x4``. The temporary fix to this problem is to change the name of the FVP in ``sw/debugger/configdb/Boards/ARM FVP/Base_A57x4_A53x4/cadi_config.xml``. Change the following line: :: System Generator:FVP_Base_A57x4_A53x4 to System Generator:FVP_Base_Cortex-A57x4_A53x4 A similar change can be made to the other Cortex-A57-A53 Base FVP variants. Version 0.4 ----------- New features ^^^^^^^^^^^^ - Makefile improvements: - Improved dependency checking when building. - Removed ``dump`` target (build now always produces dump files). - Enabled platform ports to optionally make use of parts of the Trusted Firmware (e.g. BL3-1 only), rather than being forced to use all parts. Also made the ``fip`` target optional. - Specified the full path to source files and removed use of the ``vpath`` keyword. - Provided translation table library code for potential re-use by platforms other than the FVPs. - Moved architectural timer setup to platform-specific code. - Added standby state support to PSCI cpu_suspend implementation. - SRAM usage improvements: - Started using the ``-ffunction-sections``, ``-fdata-sections`` and ``--gc-sections`` compiler/linker options to remove unused code and data from the images. Previously, all common functions were being built into all binary images, whether or not they were actually used. - Placed all assembler functions in their own section to allow more unused functions to be removed from images. - Updated BL1 and BL2 to use a single coherent stack each, rather than one per CPU. - Changed variables that were unnecessarily declared and initialized as non-const (i.e. in the .data section) so they are either uninitialized (zero init) or const. - Moved the Test Secure-EL1 Payload (BL3-2) to execute in Trusted SRAM by default. The option for it to run in Trusted DRAM remains. - Implemented a TrustZone Address Space Controller (TZC-400) driver. A default configuration is provided for the Base FVPs. This means the model parameter ``-C bp.secure_memory=1`` is now supported. - Started saving the PSCI cpu_suspend 'power_state' parameter prior to suspending a CPU. This allows platforms that implement multiple power-down states at the same affinity level to identify a specific state. - Refactored the entire codebase to reduce the amount of nesting in header files and to make the use of system/user includes more consistent. Also split platform.h to separate out the platform porting declarations from the required platform porting definitions and the definitions/declarations specific to the platform port. - Optimized the data cache clean/invalidate operations. - Improved the BL3-1 unhandled exception handling and reporting. Unhandled exceptions now result in a dump of registers to the console. - Major rework to the handover interface between BL stages, in particular the interface to BL3-1. The interface now conforms to a specification and is more future proof. - Added support for optionally making the BL3-1 entrypoint a reset handler (instead of BL1). This allows platforms with an alternative image loading architecture to re-use BL3-1 with fewer modifications to generic code. - Reserved some DDR DRAM for secure use on FVP platforms to avoid future compatibility problems with non-secure software. - Added support for secure interrupts targeting the Secure-EL1 Payload (SP) (using GICv2 routing only). Demonstrated this working by adding an interrupt target and supporting test code to the TSP. Also demonstrated non-secure interrupt handling during TSP processing. Issues resolved since last release ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Now support use of the model parameter ``-C bp.secure_memory=1`` in the Base FVPs (see **New features**). - Support for secure world interrupt handling now available (see **New features**). - Made enough SRAM savings (see **New features**) to enable the Test Secure-EL1 Payload (BL3-2) to execute in Trusted SRAM by default. - The tested filesystem used for this release (Linaro AArch64 OpenEmbedded 14.04) now correctly reports progress in the console. - Improved the Makefile structure to make it easier to separate out parts of the TF-A for re-use in platform ports. Also, improved target dependency checking. Known issues ^^^^^^^^^^^^ - GICv3 support is experimental. The Linux kernel patches to support this are not widely available. There are known issues with GICv3 initialization in the TF-A. - Dynamic image loading is not available yet. The current image loader implementation (used to load BL2 and all subsequent images) has some limitations. Changing BL2 or BL3-1 load addresses in certain ways can lead to loading errors, even if the images should theoretically fit in memory. - TF-A still uses too much on-chip Trusted SRAM. A number of RAM usage enhancements have been identified to rectify this situation. - CPU idle does not work on the advertised version of the Foundation FVP. Some FVP fixes are required that are not available externally at the time of writing. This can be worked around by disabling CPU idle in the Linux kernel. - Various bugs in TF-A, UEFI and the Linux kernel have been observed when using Linaro toolchain versions later than 13.11. Although most of these have been fixed, some remain at the time of writing. These mainly seem to relate to a subtle change in the way the compiler converts between 64-bit and 32-bit values (e.g. during casting operations), which reveals previously hidden bugs in client code. - The firmware design documentation for the Test Secure-EL1 Payload (TSP) and its dispatcher (TSPD) is incomplete. Similarly for the PSCI section. Version 0.3 ----------- New features ^^^^^^^^^^^^ - Support for Foundation FVP Version 2.0 added. The documented UEFI configuration disables some devices that are unavailable in the Foundation FVP, including MMC and CLCD. The resultant UEFI binary can be used on the AEMv8 and Cortex-A57-A53 Base FVPs, as well as the Foundation FVP. .. note:: The software will not work on Version 1.0 of the Foundation FVP. - Enabled third party contributions. Added a new contributing.md containing instructions for how to contribute and updated copyright text in all files to acknowledge contributors. - The PSCI CPU_SUSPEND API has been stabilised to the extent where it can be used for entry into power down states with the following restrictions: - Entry into standby states is not supported. - The API is only supported on the AEMv8 and Cortex-A57-A53 Base FVPs. - The PSCI AFFINITY_INFO api has undergone limited testing on the Base FVPs to allow experimental use. - Required C library and runtime header files are now included locally in TF-A instead of depending on the toolchain standard include paths. The local implementation has been cleaned up and reduced in scope. - Added I/O abstraction framework, primarily to allow generic code to load images in a platform-independent way. The existing image loading code has been reworked to use the new framework. Semi-hosting and NOR flash I/O drivers are provided. - Introduced Firmware Image Package (FIP) handling code and tools. A FIP combines multiple firmware images with a Table of Contents (ToC) into a single binary image. The new FIP driver is another type of I/O driver. The Makefile builds a FIP by default and the FVP platform code expect to load a FIP from NOR flash, although some support for image loading using semi- hosting is retained. .. note:: Building a FIP by default is a non-backwards-compatible change. .. note:: Generic BL2 code now loads a BL3-3 (non-trusted firmware) image into DRAM instead of expecting this to be pre-loaded at known location. This is also a non-backwards-compatible change. .. note:: Some non-trusted firmware (e.g. UEFI) will need to be rebuilt so that it knows the new location to execute from and no longer needs to copy particular code modules to DRAM itself. - Reworked BL2 to BL3-1 handover interface. A new composite structure (bl31_args) holds the superset of information that needs to be passed from BL2 to BL3-1, including information on how handover execution control to BL3-2 (if present) and BL3-3 (non-trusted firmware). - Added library support for CPU context management, allowing the saving and restoring of - Shared system registers between Secure-EL1 and EL1. - VFP registers. - Essential EL3 system registers. - Added a framework for implementing EL3 runtime services. Reworked the PSCI implementation to be one such runtime service. - Reworked the exception handling logic, making use of both SP_EL0 and SP_EL3 stack pointers for determining the type of exception, managing general purpose and system register context on exception entry/exit, and handling SMCs. SMCs are directed to the correct EL3 runtime service. - Added support for a Test Secure-EL1 Payload (TSP) and a corresponding Dispatcher (TSPD), which is loaded as an EL3 runtime service. The TSPD implements Secure Monitor functionality such as world switching and EL1 context management, and is responsible for communication with the TSP. .. note:: The TSPD does not yet contain support for secure world interrupts. .. note:: The TSP/TSPD is not built by default. Issues resolved since last release ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Support has been added for switching context between secure and normal worlds in EL3. - PSCI API calls ``AFFINITY_INFO`` & ``PSCI_VERSION`` have now been tested (to a limited extent). - The TF-A build artifacts are now placed in the ``./build`` directory and sub-directories instead of being placed in the root of the project. - TF-A is now free from build warnings. Build warnings are now treated as errors. - TF-A now provides C library support locally within the project to maintain compatibility between toolchains/systems. - The PSCI locking code has been reworked so it no longer takes locks in an incorrect sequence. - The RAM-disk method of loading a Linux file-system has been confirmed to work with the TF-A and Linux kernel version (based on version 3.13) used in this release, for both Foundation and Base FVPs. Known issues ^^^^^^^^^^^^ The following is a list of issues which are expected to be fixed in the future releases of TF-A. - The TrustZone Address Space Controller (TZC-400) is not being programmed yet. Use of model parameter ``-C bp.secure_memory=1`` is not supported. - No support yet for secure world interrupt handling. - GICv3 support is experimental. The Linux kernel patches to support this are not widely available. There are known issues with GICv3 initialization in TF-A. - Dynamic image loading is not available yet. The current image loader implementation (used to load BL2 and all subsequent images) has some limitations. Changing BL2 or BL3-1 load addresses in certain ways can lead to loading errors, even if the images should theoretically fit in memory. - TF-A uses too much on-chip Trusted SRAM. Currently the Test Secure-EL1 Payload (BL3-2) executes in Trusted DRAM since there is not enough SRAM. A number of RAM usage enhancements have been identified to rectify this situation. - CPU idle does not work on the advertised version of the Foundation FVP. Some FVP fixes are required that are not available externally at the time of writing. - Various bugs in TF-A, UEFI and the Linux kernel have been observed when using Linaro toolchain versions later than 13.11. Although most of these have been fixed, some remain at the time of writing. These mainly seem to relate to a subtle change in the way the compiler converts between 64-bit and 32-bit values (e.g. during casting operations), which reveals previously hidden bugs in client code. - The tested filesystem used for this release (Linaro AArch64 OpenEmbedded 14.01) does not report progress correctly in the console. It only seems to produce error output, not standard output. It otherwise appears to function correctly. Other filesystem versions on the same software stack do not exhibit the problem. - The Makefile structure doesn't make it easy to separate out parts of the TF-A for re-use in platform ports, for example if only BL3-1 is required in a platform port. Also, dependency checking in the Makefile is flawed. - The firmware design documentation for the Test Secure-EL1 Payload (TSP) and its dispatcher (TSPD) is incomplete. Similarly for the PSCI section. Version 0.2 ----------- New features ^^^^^^^^^^^^ - First source release. - Code for the PSCI suspend feature is supplied, although this is not enabled by default since there are known issues (see below). Issues resolved since last release ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - The "psci" nodes in the FDTs provided in this release now fully comply with the recommendations made in the PSCI specification. Known issues ^^^^^^^^^^^^ The following is a list of issues which are expected to be fixed in the future releases of TF-A. - The TrustZone Address Space Controller (TZC-400) is not being programmed yet. Use of model parameter ``-C bp.secure_memory=1`` is not supported. - No support yet for secure world interrupt handling or for switching context between secure and normal worlds in EL3. - GICv3 support is experimental. The Linux kernel patches to support this are not widely available. There are known issues with GICv3 initialization in TF-A. - Dynamic image loading is not available yet. The current image loader implementation (used to load BL2 and all subsequent images) has some limitations. Changing BL2 or BL3-1 load addresses in certain ways can lead to loading errors, even if the images should theoretically fit in memory. - Although support for PSCI ``CPU_SUSPEND`` is present, it is not yet stable and ready for use. - PSCI API calls ``AFFINITY_INFO`` & ``PSCI_VERSION`` are implemented but have not been tested. - The TF-A make files result in all build artifacts being placed in the root of the project. These should be placed in appropriate sub-directories. - The compilation of TF-A is not free from compilation warnings. Some of these warnings have not been investigated yet so they could mask real bugs. - TF-A currently uses toolchain/system include files like stdio.h. It should provide versions of these within the project to maintain compatibility between toolchains/systems. - The PSCI code takes some locks in an incorrect sequence. This may cause problems with suspend and hotplug in certain conditions. - The Linux kernel used in this release is based on version 3.12-rc4. Using this kernel with the TF-A fails to start the file-system as a RAM-disk. It fails to execute user-space ``init`` from the RAM-disk. As an alternative, the VirtioBlock mechanism can be used to provide a file-system to the kernel. -------------- *Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.* .. _SDEI Specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf .. _tf-issue#501: https://github.com/ARM-software/tf-issues/issues/501 .. _PR#1002: https://github.com/ARM-software/arm-trusted-firmware/pull/1002#issuecomment-312650193 .. _mbed TLS releases: https://tls.mbed.org/tech-updates/releases trusted-firmware-a-2.2/docs/components/000077500000000000000000000000001355360272700202265ustar00rootroot00000000000000trusted-firmware-a-2.2/docs/components/arm-sip-service.rst000066400000000000000000000071771355360272700240020ustar00rootroot00000000000000Arm SiP Services ================ This document enumerates and describes the Arm SiP (Silicon Provider) services. SiP services are non-standard, platform-specific services offered by the silicon implementer or platform provider. They are accessed via ``SMC`` ("SMC calls") instruction executed from Exception Levels below EL3. SMC calls for SiP services: - Follow `SMC Calling Convention`_; - Use SMC function IDs that fall in the SiP range, which are ``0xc2000000`` - ``0xc200ffff`` for 64-bit calls, and ``0x82000000`` - ``0x8200ffff`` for 32-bit calls. The Arm SiP implementation offers the following services: - Performance Measurement Framework (PMF) - Execution State Switching service Source definitions for Arm SiP service are located in the ``arm_sip_svc.h`` header file. Performance Measurement Framework (PMF) --------------------------------------- The :ref:`Performance Measurement Framework ` allows callers to retrieve timestamps captured at various paths in TF-A execution. Execution State Switching service --------------------------------- Execution State Switching service provides a mechanism for a non-secure lower Exception Level (either EL2, or NS EL1 if EL2 isn't implemented) to request to switch its execution state (a.k.a. Register Width), either from AArch64 to AArch32, or from AArch32 to AArch64, for the calling CPU. This service is only available when Trusted Firmware-A (TF-A) is built for AArch64 (i.e. when build option ``ARCH`` is set to ``aarch64``). ``ARM_SIP_SVC_EXE_STATE_SWITCH`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Arguments: uint32_t Function ID uint32_t PC hi uint32_t PC lo uint32_t Cookie hi uint32_t Cookie lo Return: uint32_t The function ID parameter must be ``0x82000020``. It uniquely identifies the Execution State Switching service being requested. The parameters *PC hi* and *PC lo* defines upper and lower words, respectively, of the entry point (physical address) at which execution should start, after Execution State has been switched. When calling from AArch64, *PC hi* must be 0. When execution starts at the supplied entry point after Execution State has been switched, the parameters *Cookie hi* and *Cookie lo* are passed in CPU registers 0 and 1, respectively. When calling from AArch64, *Cookie hi* must be 0. This call can only be made on the primary CPU, before any secondaries were brought up with ``CPU_ON`` PSCI call. Otherwise, the call will always fail. The effect of switching execution state is as if the Exception Level were entered for the first time, following power on. This means CPU registers that have a defined reset value by the Architecture will assume that value. Other registers should not be expected to hold their values before the call was made. CPU endianness, however, is preserved from the previous execution state. Note that this switches the execution state of the calling CPU only. This is not a substitute for PSCI ``SYSTEM_RESET``. The service may return the following error codes: - ``STATE_SW_E_PARAM``: If any of the parameters were deemed invalid for a specific request. - ``STATE_SW_E_DENIED``: If the call is not successful, or when TF-A is built for AArch32. If the call is successful, the caller wouldn't observe the SMC returning. Instead, execution starts at the supplied entry point, with the CPU registers 0 and 1 populated with the supplied *Cookie hi* and *Cookie lo* values, respectively. -------------- *Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.* .. _SMC Calling Convention: http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html trusted-firmware-a-2.2/docs/components/exception-handling.rst000066400000000000000000000645451355360272700245560ustar00rootroot00000000000000Exception Handling Framework ============================ This document describes various aspects of handling exceptions by Runtime Firmware (BL31) that are targeted at EL3, other than SMCs. The |EHF| takes care of the following exceptions when targeted at EL3: - Interrupts - Synchronous External Aborts - Asynchronous External Aborts |TF-A|'s handling of synchronous ``SMC`` exceptions raised from lower ELs is described in the `Firmware Design document`__. However, the |EHF| changes the semantics of `interrupt handling`__ and `synchronous exceptions`__ other than SMCs. .. __: firmware-design.rst#handling-an-smc .. __: `Interrupt handling`_ .. __: `Effect on SMC calls`_ The |EHF| is selected by setting the build option ``EL3_EXCEPTION_HANDLING`` to ``1``, and is only available for AArch64 systems. Introduction ------------ Through various control bits in the ``SCR_EL3`` register, the Arm architecture allows for asynchronous exceptions to be routed to EL3. As described in the :ref:`Interrupt Management Framework` document, depending on the chosen interrupt routing model, TF-A appropriately sets the ``FIQ`` and ``IRQ`` bits of ``SCR_EL3`` register to effect this routing. For most use cases, other than for the purpose of facilitating context switch between Normal and Secure worlds, FIQs and IRQs routed to EL3 are not required to be handled in EL3. However, the evolving system and standards landscape demands that various exceptions are targeted at and handled in EL3. For instance: - Starting with ARMv8.2 architecture extension, many RAS features have been introduced to the Arm architecture. With RAS features implemented, various components of the system may use one of the asynchronous exceptions to signal error conditions to PEs. These error conditions are of critical nature, and it's imperative that corrective or remedial actions are taken at the earliest opportunity. Therefore, a *Firmware-first Handling* approach is generally followed in response to RAS events in the system. - The Arm `SDEI specification`_ defines interfaces through which Normal world interacts with the Runtime Firmware in order to request notification of system events. The |SDEI| specification requires that these events are notified even when the Normal world executes with the exceptions masked. This too implies that firmware-first handling is required, where the events are first received by the EL3 firmware, and then dispatched to Normal world through purely software mechanism. For |TF-A|, firmware-first handling means that asynchronous exceptions are suitably routed to EL3, and the Runtime Firmware (BL31) is extended to include software components that are capable of handling those exceptions that target EL3. These components—referred to as *dispatchers* [#spd]_ in general—may choose to: .. _delegation-use-cases: - Receive and handle exceptions entirely in EL3, meaning the exceptions handling terminates in EL3. - Receive exceptions, but handle part of the exception in EL3, and delegate the rest of the handling to a dedicated software stack running at lower Secure ELs. In this scheme, the handling spans various secure ELs. - Receive exceptions, but handle part of the exception in EL3, and delegate processing of the error to dedicated software stack running at lower secure ELs (as above); additionally, the Normal world may also be required to participate in the handling, or be notified of such events (for example, as an |SDEI| event). In this scheme, exception handling potentially and maximally spans all ELs in both Secure and Normal worlds. On any given system, all of the above handling models may be employed independently depending on platform choice and the nature of the exception received. .. [#spd] Not to be confused with `Secure Payload Dispatcher`__, which is an EL3 component that operates in EL3 on behalf of Secure OS. .. __: firmware-design.rst#secure-el1-payloads-and-dispatchers The role of Exception Handling Framework ---------------------------------------- Corollary to the use cases cited above, the primary role of the |EHF| is to facilitate firmware-first handling of exceptions on Arm systems. The |EHF| thus enables multiple exception dispatchers in runtime firmware to co-exist, register for, and handle exceptions targeted at EL3. This section outlines the basics, and the rest of this document expands the various aspects of the |EHF|. In order to arbitrate exception handling among dispatchers, the |EHF| operation is based on a priority scheme. This priority scheme is closely tied to how the Arm GIC architecture defines it, although it's applied to non-interrupt exceptions too (SErrors, for example). The platform is required to `partition`__ the Secure priority space into priority levels as applicable for the Secure software stack. It then assigns the dispatchers to one or more priority levels. The dispatchers then register handlers for the priority levels at runtime. A dispatcher can register handlers for more than one priority level. .. __: `Partitioning priority levels`_ .. _ehf-figure: .. image:: ../resources/diagrams/draw.io/ehf.svg A priority level is *active* when a handler at that priority level is currently executing in EL3, or has delegated the execution to a lower EL. For interrupts, this is implicit when an interrupt is targeted and acknowledged at EL3, and the priority of the acknowledged interrupt is used to match its registered handler. The priority level is likewise implicitly deactivated when the interrupt handling concludes by EOIing the interrupt. Non-interrupt exceptions (SErrors, for example) don't have a notion of priority. In order for the priority arbitration to work, the |EHF| provides APIs in order for these non-interrupt exceptions to assume a priority, and to interwork with interrupts. Dispatchers handling such exceptions must therefore explicitly activate and deactivate the respective priority level as and when they're handled or delegated. Because priority activation and deactivation for interrupt handling is implicit and involves GIC priority masking, it's impossible for a lower priority interrupt to preempt a higher priority one. By extension, this means that a lower priority dispatcher cannot preempt a higher-priority one. Priority activation and deactivation for non-interrupt exceptions, however, has to be explicit. The |EHF| therefore disallows for lower priority level to be activated whilst a higher priority level is active, and would result in a panic. Likewise, a panic would result if it's attempted to deactivate a lower priority level when a higher priority level is active. In essence, priority level activation and deactivation conceptually works like a stack—priority levels stack up in strictly increasing fashion, and need to be unstacked in strictly the reverse order. For interrupts, the GIC ensures this is the case; for non-interrupts, the |EHF| monitors and asserts this. See `Transition of priority levels`_. Interrupt handling ------------------ The |EHF| is a client of *Interrupt Management Framework*, and registers the top-level handler for interrupts that target EL3, as described in the :ref:`Interrupt Management Framework` document. This has the following implications: - On GICv3 systems, when executing in S-EL1, pending Non-secure interrupts of sufficient priority are signalled as FIQs, and therefore will be routed to EL3. As a result, S-EL1 software cannot expect to handle Non-secure interrupts at S-EL1. Essentially, this deprecates the routing mode described as `CSS=0, TEL3=0`__. .. __: interrupt-framework-design.rst#el3-interrupts In order for S-EL1 software to handle Non-secure interrupts while having |EHF| enabled, the dispatcher must adopt a model where Non-secure interrupts are received at EL3, but are then `synchronously`__ handled over to S-EL1. .. __: interrupt-framework-design.rst#secure-payload - On GICv2 systems, it's required that the build option ``GICV2_G0_FOR_EL3`` is set to ``1`` so that *Group 0* interrupts target EL3. - While executing in Secure world, |EHF| sets GIC Priority Mask Register to the lowest Secure priority. This means that no Non-secure interrupts can preempt Secure execution. See `Effect on SMC calls`_ for more details. As mentioned above, with |EHF|, the platform is required to partition *Group 0* interrupts into distinct priority levels. A dispatcher that chooses to receive interrupts can then *own* one or more priority levels, and register interrupt handlers for them. A given priority level can be assigned to only one handler. A dispatcher may register more than one priority level. Dispatchers are assigned interrupt priority levels in two steps: Partitioning priority levels ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Interrupts are associated to dispatchers by way of grouping and assigning interrupts to a priority level. In other words, all interrupts that are to target a particular dispatcher should fall in a particular priority level. For priority assignment: - Of the 8 bits of priority that Arm GIC architecture permits, bit 7 must be 0 (secure space). - Depending on the number of dispatchers to support, the platform must choose to use the top *n* of the 7 remaining bits to identify and assign interrupts to individual dispatchers. Choosing *n* bits supports up to 2\ :sup:`n` distinct dispatchers. For example, by choosing 2 additional bits (i.e., bits 6 and 5), the platform can partition into 4 secure priority ranges: ``0x0``, ``0x20``, ``0x40``, and ``0x60``. See `Interrupt handling example`_. .. note:: The Arm GIC architecture requires that a GIC implementation that supports two security states must implement at least 32 priority levels; i.e., at least 5 upper bits of the 8 bits are writeable. In the scheme described above, when choosing *n* bits for priority range assignment, the platform must ensure that at least ``n+1`` top bits of GIC priority are writeable. The priority thus assigned to an interrupt is also used to determine the priority of delegated execution in lower ELs. Delegated execution in lower EL is associated with a priority level chosen with ``ehf_activate_priority()`` API (described `later`__). The chosen priority level also determines the interrupts masked while executing in a lower EL, therefore controls preemption of delegated execution. .. __: `ehf-apis`_ The platform expresses the chosen priority levels by declaring an array of priority level descriptors. Each entry in the array is of type ``ehf_pri_desc_t``, and declares a priority level, and shall be populated by the ``EHF_PRI_DESC()`` macro. .. warning:: The macro ``EHF_PRI_DESC()`` installs the descriptors in the array at a computed index, and not necessarily where the macro is placed in the array. The size of the array might therefore be larger than what it appears to be. The ``ARRAY_SIZE()`` macro therefore should be used to determine the size of array. Finally, this array of descriptors is exposed to |EHF| via the ``EHF_REGISTER_PRIORITIES()`` macro. Refer to the `Interrupt handling example`_ for usage. See also: `Interrupt Prioritisation Considerations`_. Programming priority ~~~~~~~~~~~~~~~~~~~~ The text in `Partitioning priority levels`_ only describes how the platform expresses the required levels of priority. It however doesn't choose interrupts nor program the required priority in GIC. The `Firmware Design guide`__ explains methods for configuring secure interrupts. |EHF| requires the platform to enumerate interrupt properties (as opposed to just numbers) of Secure interrupts. The priority of secure interrupts must match that as determined in the `Partitioning priority levels`_ section above. .. __: firmware-design.rst#configuring-secure-interrupts See `Limitations`_, and also refer to `Interrupt handling example`_ for illustration. Registering handler ------------------- Dispatchers register handlers for their priority levels through the following API: .. code:: c int ehf_register_priority_handler(int pri, ehf_handler_t handler) The API takes two arguments: - The priority level for which the handler is being registered; - The handler to be registered. The handler must be aligned to 4 bytes. If a dispatcher owns more than one priority levels, it has to call the API for each of them. The API will succeed, and return ``0``, only if: - There exists a descriptor with the priority level requested. - There are no handlers already registered by a previous call to the API. Otherwise, the API returns ``-1``. The interrupt handler should have the following signature: .. code:: c typedef int (*ehf_handler_t)(uint32_t intr_raw, uint32_t flags, void *handle, void *cookie); The parameters are as obtained from the top-level `EL3 interrupt handler`__. .. __: interrupt-framework-design.rst#el3-runtime-firmware The `SDEI dispatcher`__, for example, expects the platform to allocate two different priority levels—``PLAT_SDEI_CRITICAL_PRI``, and ``PLAT_SDEI_NORMAL_PRI``—and registers the same handler to handle both levels. .. __: sdei.rst Interrupt handling example -------------------------- The following annotated snippet demonstrates how a platform might choose to assign interrupts to fictitious dispatchers: .. code:: c #include #include #include ... /* * This platform uses 2 bits for interrupt association. In total, 3 upper * bits are in use. * * 7 6 5 3 0 * .-.-.-.----------. * |0|b|b| ..0.. | * '-'-'-'----------' */ #define PLAT_PRI_BITS 2 /* Priorities for individual dispatchers */ #define DISP0_PRIO 0x00 /* Not used */ #define DISP1_PRIO 0x20 #define DISP2_PRIO 0x40 #define DISP3_PRIO 0x60 /* Install priority level descriptors for each dispatcher */ ehf_pri_desc_t plat_exceptions[] = { EHF_PRI_DESC(PLAT_PRI_BITS, DISP1_PRIO), EHF_PRI_DESC(PLAT_PRI_BITS, DISP2_PRIO), EHF_PRI_DESC(PLAT_PRI_BITS, DISP3_PRIO), }; /* Expose priority descriptors to Exception Handling Framework */ EHF_REGISTER_PRIORITIES(plat_exceptions, ARRAY_SIZE(plat_exceptions), PLAT_PRI_BITS); ... /* List interrupt properties for GIC driver. All interrupts target EL3 */ const interrupt_prop_t plat_interrupts[] = { /* Dispatcher 1 owns interrupts d1_0 and d1_1, so assigns priority DISP1_PRIO */ INTR_PROP_DESC(d1_0, DISP1_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(d1_1, DISP1_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), /* Dispatcher 2 owns interrupts d2_0 and d2_1, so assigns priority DISP2_PRIO */ INTR_PROP_DESC(d2_0, DISP2_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(d2_1, DISP2_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), /* Dispatcher 3 owns interrupts d3_0 and d3_1, so assigns priority DISP3_PRIO */ INTR_PROP_DESC(d3_0, DISP3_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(d3_1, DISP3_PRIO, INTR_TYPE_EL3, GIC_INTR_CFG_LEVEL), }; ... /* Dispatcher 1 registers its handler */ ehf_register_priority_handler(DISP1_PRIO, disp1_handler); /* Dispatcher 2 registers its handler */ ehf_register_priority_handler(DISP2_PRIO, disp2_handler); /* Dispatcher 3 registers its handler */ ehf_register_priority_handler(DISP3_PRIO, disp3_handler); ... See also the `Build-time flow`_ and the `Run-time flow`_. Activating and Deactivating priorities -------------------------------------- A priority level is said to be *active* when an exception of that priority is being handled: for interrupts, this is implied when the interrupt is acknowledged; for non-interrupt exceptions, such as SErrors or `SDEI explicit dispatches`__, this has to be done via calling ``ehf_activate_priority()``. See `Run-time flow`_. .. __: sdei.rst#explicit-dispatch-of-events Conversely, when the dispatcher has reached a logical resolution for the cause of the exception, the corresponding priority level ought to be deactivated. As above, for interrupts, this is implied when the interrupt is EOId in the GIC; for other exceptions, this has to be done via calling ``ehf_deactivate_priority()``. Thanks to `different provisions`__ for exception delegation, there are potentially more than one work flow for deactivation: .. __: `delegation-use-cases`_ .. _deactivation workflows: - The dispatcher has addressed the cause of the exception, and decided to take no further action. In this case, the dispatcher's handler deactivates the priority level before returning to the |EHF|. Runtime firmware, upon exit through an ``ERET``, resumes execution before the interrupt occurred. - The dispatcher has to delegate the execution to lower ELs, and the cause of the exception can be considered resolved only when the lower EL returns signals complete (via an ``SMC``) at a future point in time. The following sequence ensues: #. The dispatcher calls ``setjmp()`` to setup a jump point, and arranges to enter a lower EL upon the next ``ERET``. #. Through the ensuing ``ERET`` from runtime firmware, execution is delegated to a lower EL. #. The lower EL completes its execution, and signals completion via an ``SMC``. #. The ``SMC`` is handled by the same dispatcher that handled the exception previously. Noticing the conclusion of exception handling, the dispatcher does ``longjmp()`` to resume beyond the previous jump point. As mentioned above, the |EHF| provides the following APIs for activating and deactivating interrupt: .. _ehf-apis: - ``ehf_activate_priority()`` activates the supplied priority level, but only if the current active priority is higher than the given one; otherwise panics. Also, to prevent interruption by physical interrupts of lower priority, the |EHF| programs the *Priority Mask Register* corresponding to the PE to the priority being activated. Dispatchers typically only need to call this when handling exceptions other than interrupts, and it needs to delegate execution to a lower EL at a desired priority level. - ``ehf_deactivate_priority()`` deactivates a given priority, but only if the current active priority is equal to the given one; otherwise panics. |EHF| also restores the *Priority Mask Register* corresponding to the PE to the priority before the call to ``ehf_activate_priority()``. Dispatchers typically only need to call this after handling exceptions other than interrupts. The calling of APIs are subject to allowed `transitions`__. See also the `Run-time flow`_. .. __: `Transition of priority levels`_ Transition of priority levels ----------------------------- The |EHF| APIs ``ehf_activate_priority()`` and ``ehf_deactivate_priority()`` can be called to transition the current priority level on a PE. A given sequence of calls to these APIs are subject to the following conditions: - For activation, the |EHF| only allows for the priority to increase (i.e. numeric value decreases); - For deactivation, the |EHF| only allows for the priority to decrease (i.e. numeric value increases). Additionally, the priority being deactivated is required to be the current priority. If these are violated, a panic will result. Effect on SMC calls ------------------- In general, Secure execution is regarded as more important than Non-secure execution. As discussed elsewhere in this document, EL3 execution, and any delegated execution thereafter, has the effect of raising GIC's priority mask—either implicitly by acknowledging Secure interrupts, or when dispatchers call ``ehf_activate_priority()``. As a result, Non-secure interrupts cannot preempt any Secure execution. SMCs from Non-secure world are synchronous exceptions, and are mechanisms for Non-secure world to request Secure services. They're broadly classified as *Fast* or *Yielding* (see `SMCCC`__). .. __: `http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html` - *Fast* SMCs are atomic from the caller's point of view. I.e., they return to the caller only when the Secure world has finished serving the request. Any Non-secure interrupts that become pending meanwhile cannot preempt Secure execution. - *Yielding* SMCs carry the semantics of a preemptible, lower-priority request. A pending Non-secure interrupt can preempt Secure execution handling a Yielding SMC. I.e., the caller might observe a Yielding SMC returning when either: #. Secure world completes the request, and the caller would find ``SMC_OK`` as the return code. #. A Non-secure interrupt preempts Secure execution. Non-secure interrupt is handled, and Non-secure execution resumes after ``SMC`` instruction. The dispatcher handling a Yielding SMC must provide a different return code to the Non-secure caller to distinguish the latter case. This return code, however, is not standardised (unlike ``SMC_UNKNOWN`` or ``SMC_OK``, for example), so will vary across dispatchers that handle the request. For the latter case above, dispatchers before |EHF| expect Non-secure interrupts to be taken to S-EL1 [#irq]_, so would get a chance to populate the designated preempted error code before yielding to Non-secure world. The introduction of |EHF| changes the behaviour as described in `Interrupt handling`_. When |EHF| is enabled, in order to allow Non-secure interrupts to preempt Yielding SMC handling, the dispatcher must call ``ehf_allow_ns_preemption()`` API. The API takes one argument, the error code to be returned to the Non-secure world upon getting preempted. .. [#irq] In case of GICv2, Non-secure interrupts while in S-EL1 were signalled as IRQs, and in case of GICv3, FIQs. Build-time flow --------------- Please refer to the `figure`__ above. .. __: `ehf-figure`_ The build-time flow involves the following steps: #. Platform assigns priorities by installing priority level descriptors for individual dispatchers, as described in `Partitioning priority levels`_. #. Platform provides interrupt properties to GIC driver, as described in `Programming priority`_. #. Dispatcher calling ``ehf_register_priority_handler()`` to register an interrupt handler. Also refer to the `Interrupt handling example`_. Run-time flow ------------- .. _interrupt-flow: The following is an example flow for interrupts: #. The GIC driver, during initialization, iterates through the platform-supplied interrupt properties (see `Programming priority`_), and configures the interrupts. This programs the appropriate priority and group (Group 0) on interrupts belonging to different dispatchers. #. The |EHF|, during its initialisation, registers a top-level interrupt handler with the `Interrupt Management Framework`__ for EL3 interrupts. This also results in setting the routing bits in ``SCR_EL3``. .. __: interrupt-framework-design.rst#el3-runtime-firmware #. When an interrupt belonging to a dispatcher fires, GIC raises an EL3/Group 0 interrupt, and is taken to EL3. #. The top-level EL3 interrupt handler executes. The handler acknowledges the interrupt, reads its *Running Priority*, and from that, determines the dispatcher handler. #. The |EHF| programs the *Priority Mask Register* of the PE to the priority of the interrupt received. #. The |EHF| marks that priority level *active*, and jumps to the dispatcher handler. #. Once the dispatcher handler finishes its job, it has to immediately *deactivate* the priority level before returning to the |EHF|. See `deactivation workflows`_. .. _non-interrupt-flow: The following is an example flow for exceptions that targets EL3 other than interrupt: #. The platform provides handlers for the specific kind of exception. #. The exception arrives, and the corresponding handler is executed. #. The handler calls ``ehf_activate_priority()`` to activate the required priority level. This also has the effect of raising GIC priority mask, thus preventing interrupts of lower priority from preempting the handling. The handler may choose to do the handling entirely in EL3 or delegate to a lower EL. #. Once exception handling concludes, the handler calls ``ehf_deactivate_priority()`` to deactivate the priority level activated earlier. This also has the effect of lowering GIC priority mask to what it was before. Interrupt Prioritisation Considerations --------------------------------------- The GIC priority scheme, by design, prioritises Secure interrupts over Normal world ones. The platform further assigns relative priorities amongst Secure dispatchers through |EHF|. As mentioned in `Partitioning priority levels`_, interrupts targeting distinct dispatchers fall in distinct priority levels. Because they're routed via the GIC, interrupt delivery to the PE is subject to GIC prioritisation rules. In particular, when an interrupt is being handled by the PE (i.e., the interrupt is in *Active* state), only interrupts of higher priority are signalled to the PE, even if interrupts of same or lower priority are pending. This has the side effect of one dispatcher being starved of interrupts by virtue of another dispatcher handling its (higher priority) interrupts. The |EHF| doesn't enforce a particular prioritisation policy, but the platform should carefully consider the assignment of priorities to dispatchers integrated into runtime firmware. The platform should sensibly delineate priority to various dispatchers according to their nature. In particular, dispatchers of critical nature (RAS, for example) should be assigned higher priority than others (|SDEI|, for example); and within |SDEI|, Critical priority |SDEI| should be assigned higher priority than Normal ones. Limitations ----------- The |EHF| has the following limitations: - Although there could be up to 128 Secure dispatchers supported by the GIC priority scheme, the size of descriptor array exposed with ``EHF_REGISTER_PRIORITIES()`` macro is currently limited to 32. This serves most expected use cases. This may be expanded in the future, should use cases demand so. - The platform must ensure that the priority assigned to the dispatcher in the exception descriptor and the programmed priority of interrupts handled by the dispatcher match. The |EHF| cannot verify that this has been followed. -------------- *Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.* .. _SDEI specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf trusted-firmware-a-2.2/docs/components/firmware-update.rst000066400000000000000000000316561355360272700240670ustar00rootroot00000000000000Firmware Update (FWU) ===================== Introduction ------------ This document describes the design of the Firmware Update (FWU) feature, which enables authenticated firmware to update firmware images from external interfaces such as USB, UART, SD-eMMC, NAND, NOR or Ethernet to SoC Non-Volatile memories such as NAND Flash, LPDDR2-NVM or any memory determined by the platform. This feature functions even when the current firmware in the system is corrupt or missing; it therefore may be used as a recovery mode. It may also be complemented by other, higher level firmware update software. FWU implements a specific part of the Trusted Board Boot Requirements (TBBR) specification, Arm DEN0006C-1. It should be used in conjunction with the :ref:`Trusted Board Boot` design document, which describes the image authentication parts of the Trusted Firmware-A (TF-A) TBBR implementation. Scope ~~~~~ This document describes the secure world FWU design. It is beyond its scope to describe how normal world FWU images should operate. To implement normal world FWU images, please refer to the "Non-Trusted Firmware Updater" requirements in the TBBR. FWU Overview ------------ The FWU boot flow is primarily mediated by BL1. Since BL1 executes in ROM, and it is usually desirable to minimize the amount of ROM code, the design allows some parts of FWU to be implemented in other secure and normal world images. Platform code may choose which parts are implemented in which images but the general expectation is: - BL1 handles: - Detection and initiation of the FWU boot flow. - Copying images from non-secure to secure memory - FWU image authentication - Context switching between the normal and secure world during the FWU process. - Other secure world FWU images handle platform initialization required by the FWU process. - Normal world FWU images handle loading of firmware images from external interfaces to non-secure memory. The primary requirements of the FWU feature are: #. Export a BL1 SMC interface to interoperate with other FWU images executing at other Exception Levels. #. Export a platform interface to provide FWU common code with the information it needs, and to enable platform specific FWU functionality. See the :ref:`Porting Guide` for details of this interface. TF-A uses abbreviated image terminology for FWU images like for other TF-A images. See the :ref:`Image Terminology` document for an explanation of these terms. The following diagram shows the FWU boot flow for Arm development platforms. Arm CSS platforms like Juno have a System Control Processor (SCP), and these use all defined FWU images. Other platforms may use a subset of these. |Flow Diagram| Image Identification -------------------- Each FWU image and certificate is identified by a unique ID, defined by the platform, which BL1 uses to fetch an image descriptor (``image_desc_t``) via a call to ``bl1_plat_get_image_desc()``. The same ID is also used to prepare the Chain of Trust (Refer to the :ref:`Authentication Framework & Chain of Trust` document for more information). The image descriptor includes the following information: - Executable or non-executable image. This indicates whether the normal world is permitted to request execution of a secure world FWU image (after authentication). Secure world certificates and non-AP images are examples of non-executable images. - Secure or non-secure image. This indicates whether the image is authenticated/executed in secure or non-secure memory. - Image base address and size. - Image entry point configuration (an ``entry_point_info_t``). - FWU image state. BL1 uses the FWU image descriptors to: - Validate the arguments of FWU SMCs - Manage the state of the FWU process - Initialize the execution state of the next FWU image. FWU State Machine ----------------- BL1 maintains state for each FWU image during FWU execution. FWU images at lower Exception Levels raise SMCs to invoke FWU functionality in BL1, which causes BL1 to update its FWU image state. The BL1 image states and valid state transitions are shown in the diagram below. Note that secure images have a more complex state machine than non-secure images. |FWU state machine| The following is a brief description of the supported states: - RESET: This is the initial state of every image at the start of FWU. Authentication failure also leads to this state. A secure image may yield to this state if it has completed execution. It can also be reached by using ``FWU_SMC_IMAGE_RESET``. - COPYING: This is the state of a secure image while BL1 is copying it in blocks from non-secure to secure memory. - COPIED: This is the state of a secure image when BL1 has completed copying it to secure memory. - AUTHENTICATED: This is the state of an image when BL1 has successfully authenticated it. - EXECUTED: This is the state of a secure, executable image when BL1 has passed execution control to it. - INTERRUPTED: This is the state of a secure, executable image after it has requested BL1 to resume normal world execution. BL1 SMC Interface ----------------- BL1_SMC_CALL_COUNT ~~~~~~~~~~~~~~~~~~ :: Arguments: uint32_t function ID : 0x0 Return: uint32_t This SMC returns the number of SMCs supported by BL1. BL1_SMC_UID ~~~~~~~~~~~ :: Arguments: uint32_t function ID : 0x1 Return: UUID : 32 bits in each of w0-w3 (or r0-r3 for AArch32 callers) This SMC returns the 128-bit `Universally Unique Identifier`_ for the BL1 SMC service. BL1_SMC_VERSION ~~~~~~~~~~~~~~~ :: Argument: uint32_t function ID : 0x3 Return: uint32_t : Bits [31:16] Major Version Bits [15:0] Minor Version This SMC returns the current version of the BL1 SMC service. BL1_SMC_RUN_IMAGE ~~~~~~~~~~~~~~~~~ :: Arguments: uint32_t function ID : 0x4 entry_point_info_t *ep_info Return: void Pre-conditions: if (normal world caller) synchronous exception if (ep_info not EL3) synchronous exception This SMC passes execution control to an EL3 image described by the provided ``entry_point_info_t`` structure. In the normal TF-A boot flow, BL2 invokes this SMC for BL1 to pass execution control to BL31. FWU_SMC_IMAGE_COPY ~~~~~~~~~~~~~~~~~~ :: Arguments: uint32_t function ID : 0x10 unsigned int image_id uintptr_t image_addr unsigned int block_size unsigned int image_size Return: int : 0 (Success) : -ENOMEM : -EPERM Pre-conditions: if (image_id is invalid) return -EPERM if (image_id is non-secure image) return -EPERM if (image_id state is not (RESET or COPYING)) return -EPERM if (secure world caller) return -EPERM if (image_addr + block_size overflows) return -ENOMEM if (image destination address + image_size overflows) return -ENOMEM if (source block is in secure memory) return -ENOMEM if (source block is not mapped into BL1) return -ENOMEM if (image_size > free secure memory) return -ENOMEM if (image overlaps another image) return -EPERM This SMC copies the secure image indicated by ``image_id`` from non-secure memory to secure memory for later authentication. The image may be copied in a single block or multiple blocks. In either case, the total size of the image must be provided in ``image_size`` when invoking this SMC for the first time for each image; it is ignored in subsequent calls (if any) for the same image. The ``image_addr`` and ``block_size`` specify the source memory block to copy from. The destination address is provided by the platform code. If ``block_size`` is greater than the amount of remaining bytes to copy for this image then the former is truncated to the latter. The copy operation is then considered as complete and the FWU state machine transitions to the "COPIED" state. If there is still more to copy, the FWU state machine stays in or transitions to the COPYING state (depending on the previous state). When using multiple blocks, the source blocks do not necessarily need to be in contiguous memory. Once the SMC is handled, BL1 returns from exception to the normal world caller. FWU_SMC_IMAGE_AUTH ~~~~~~~~~~~~~~~~~~ :: Arguments: uint32_t function ID : 0x11 unsigned int image_id uintptr_t image_addr unsigned int image_size Return: int : 0 (Success) : -ENOMEM : -EPERM : -EAUTH Pre-conditions: if (image_id is invalid) return -EPERM if (secure world caller) if (image_id state is not RESET) return -EPERM if (image_addr/image_size is not mapped into BL1) return -ENOMEM else // normal world caller if (image_id is secure image) if (image_id state is not COPIED) return -EPERM else // image_id is non-secure image if (image_id state is not RESET) return -EPERM if (image_addr/image_size is in secure memory) return -ENOMEM if (image_addr/image_size not mapped into BL1) return -ENOMEM This SMC authenticates the image specified by ``image_id``. If the image is in the RESET state, BL1 authenticates the image in place using the provided ``image_addr`` and ``image_size``. If the image is a secure image in the COPIED state, BL1 authenticates the image from the secure memory that BL1 previously copied the image into. BL1 returns from exception to the caller. If authentication succeeds then BL1 sets the image state to AUTHENTICATED. If authentication fails then BL1 returns the -EAUTH error and sets the image state back to RESET. FWU_SMC_IMAGE_EXECUTE ~~~~~~~~~~~~~~~~~~~~~ :: Arguments: uint32_t function ID : 0x12 unsigned int image_id Return: int : 0 (Success) : -EPERM Pre-conditions: if (image_id is invalid) return -EPERM if (secure world caller) return -EPERM if (image_id is non-secure image) return -EPERM if (image_id is non-executable image) return -EPERM if (image_id state is not AUTHENTICATED) return -EPERM This SMC initiates execution of a previously authenticated image specified by ``image_id``, in the other security world to the caller. The current implementation only supports normal world callers initiating execution of a secure world image. BL1 saves the normal world caller's context, sets the secure image state to EXECUTED, and returns from exception to the secure image. FWU_SMC_IMAGE_RESUME ~~~~~~~~~~~~~~~~~~~~ :: Arguments: uint32_t function ID : 0x13 register_t image_param Return: register_t : image_param (Success) : -EPERM Pre-conditions: if (normal world caller and no INTERRUPTED secure image) return -EPERM This SMC resumes execution in the other security world while there is a secure image in the EXECUTED/INTERRUPTED state. For normal world callers, BL1 sets the previously interrupted secure image state to EXECUTED. For secure world callers, BL1 sets the previously executing secure image state to INTERRUPTED. In either case, BL1 saves the calling world's context, restores the resuming world's context and returns from exception into the resuming world. If the call is successful then the caller provided ``image_param`` is returned to the resumed world, otherwise an error code is returned to the caller. FWU_SMC_SEC_IMAGE_DONE ~~~~~~~~~~~~~~~~~~~~~~ :: Arguments: uint32_t function ID : 0x14 Return: int : 0 (Success) : -EPERM Pre-conditions: if (normal world caller) return -EPERM This SMC indicates completion of a previously executing secure image. BL1 sets the previously executing secure image state to the RESET state, restores the normal world context and returns from exception into the normal world. FWU_SMC_UPDATE_DONE ~~~~~~~~~~~~~~~~~~~ :: Arguments: uint32_t function ID : 0x15 register_t client_cookie Return: N/A This SMC completes the firmware update process. BL1 calls the platform specific function ``bl1_plat_fwu_done``, passing the optional argument ``client_cookie`` as a ``void *``. The SMC does not return. FWU_SMC_IMAGE_RESET ~~~~~~~~~~~~~~~~~~~ :: Arguments: uint32_t function ID : 0x16 unsigned int image_id Return: int : 0 (Success) : -EPERM Pre-conditions: if (secure world caller) return -EPERM if (image in EXECUTED) return -EPERM This SMC sets the state of an image to RESET and zeroes the memory used by it. This is only allowed if the image is not being executed. -------------- *Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.* .. _Universally Unique Identifier: https://tools.ietf.org/rfc/rfc4122.txt .. |Flow Diagram| image:: ../resources/diagrams/fwu_flow.png .. |FWU state machine| image:: ../resources/diagrams/fwu_states.png trusted-firmware-a-2.2/docs/components/index.rst000066400000000000000000000004471355360272700220740ustar00rootroot00000000000000Components ========== .. toctree:: :maxdepth: 1 :caption: Contents :numbered: spd/index arm-sip-service exception-handling firmware-update platform-interrupt-controller-API ras romlib-design sdei secure-partition-manager-design xlat-tables-lib-v2-design trusted-firmware-a-2.2/docs/components/platform-interrupt-controller-API.rst000066400000000000000000000252001355360272700274250ustar00rootroot00000000000000Platform Interrupt Controller API ================================= This document lists the optional platform interrupt controller API that abstracts the runtime configuration and control of interrupt controller from the generic code. The mandatory APIs are described in the :ref:`Porting Guide `. Function: unsigned int plat_ic_get_running_priority(void); [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : unsigned int This API should return the priority of the interrupt the PE is currently servicing. This must be be called only after an interrupt has already been acknowledged via ``plat_ic_acknowledge_interrupt``. In the case of Arm standard platforms using GIC, the *Running Priority Register* is read to determine the priority of the interrupt. Function: int plat_ic_is_spi(unsigned int id); [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Return : int The API should return whether the interrupt ID (first parameter) is categorized as a Shared Peripheral Interrupt. Shared Peripheral Interrupts are typically associated to system-wide peripherals, and these interrupts can target any PE in the system. Function: int plat_ic_is_ppi(unsigned int id); [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Return : int The API should return whether the interrupt ID (first parameter) is categorized as a Private Peripheral Interrupt. Private Peripheral Interrupts are typically associated with peripherals that are private to each PE. Interrupts from private peripherals target to that PE only. Function: int plat_ic_is_sgi(unsigned int id); [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Return : int The API should return whether the interrupt ID (first parameter) is categorized as a Software Generated Interrupt. Software Generated Interrupts are raised by explicit programming by software, and are typically used in inter-PE communication. Secure SGIs are reserved for use by Secure world software. Function: unsigned int plat_ic_get_interrupt_active(unsigned int id); [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Return : int This API should return the *active* status of the interrupt ID specified by the first parameter, ``id``. In case of Arm standard platforms using GIC, the implementation of the API reads the GIC *Set Active Register* to read and return the active status of the interrupt. Function: void plat_ic_enable_interrupt(unsigned int id); [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Return : void This API should enable the interrupt ID specified by the first parameter, ``id``. PEs in the system are expected to receive only enabled interrupts. In case of Arm standard platforms using GIC, the implementation of the API inserts barrier to make memory updates visible before enabling interrupt, and then writes to GIC *Set Enable Register* to enable the interrupt. Function: void plat_ic_disable_interrupt(unsigned int id); [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Return : void This API should disable the interrupt ID specified by the first parameter, ``id``. PEs in the system are not expected to receive disabled interrupts. In case of Arm standard platforms using GIC, the implementation of the API writes to GIC *Clear Enable Register* to disable the interrupt, and inserts barrier to make memory updates visible afterwards. Function: void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority); [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Argument : unsigned int Return : void This API should set the priority of the interrupt specified by first parameter ``id`` to the value set by the second parameter ``priority``. In case of Arm standard platforms using GIC, the implementation of the API writes to GIC *Priority Register* set interrupt priority. Function: int plat_ic_has_interrupt_type(unsigned int type); [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Return : int This API should return whether the platform supports a given interrupt type. The parameter ``type`` shall be one of ``INTR_TYPE_EL3``, ``INTR_TYPE_S_EL1``, or ``INTR_TYPE_NS``. In case of Arm standard platforms using GICv3, the implementation of the API returns ``1`` for all interrupt types. In case of Arm standard platforms using GICv2, the API always return ``1`` for ``INTR_TYPE_NS``. Return value for other types depends on the value of build option ``GICV2_G0_FOR_EL3``: - For interrupt type ``INTR_TYPE_EL3``: - When ``GICV2_G0_FOR_EL3`` is ``0``, it returns ``0``, indicating no support for EL3 interrupts. - When ``GICV2_G0_FOR_EL3`` is ``1``, it returns ``1``, indicating support for EL3 interrupts. - For interrupt type ``INTR_TYPE_S_EL1``: - When ``GICV2_G0_FOR_EL3`` is ``0``, it returns ``1``, indicating support for Secure EL1 interrupts. - When ``GICV2_G0_FOR_EL3`` is ``1``, it returns ``0``, indicating no support for Secure EL1 interrupts. Function: void plat_ic_set_interrupt_type(unsigned int id, unsigned int type); [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Argument : unsigned int Return : void This API should set the interrupt specified by first parameter ``id`` to the type specified by second parameter ``type``. The ``type`` parameter can be one of: - ``INTR_TYPE_NS``: interrupt is meant to be consumed by the Non-secure world. - ``INTR_TYPE_S_EL1``: interrupt is meant to be consumed by Secure EL1. - ``INTR_TYPE_EL3``: interrupt is meant to be consumed by EL3. In case of Arm standard platforms using GIC, the implementation of the API writes to the GIC *Group Register* and *Group Modifier Register* (only GICv3) to assign the interrupt to the right group. For GICv3: - ``INTR_TYPE_NS`` maps to Group 1 interrupt. - ``INTR_TYPE_S_EL1`` maps to Secure Group 1 interrupt. - ``INTR_TYPE_EL3`` maps to Secure Group 0 interrupt. For GICv2: - ``INTR_TYPE_NS`` maps to Group 1 interrupt. - When the build option ``GICV2_G0_FOR_EL3`` is set to ``0`` (the default), ``INTR_TYPE_S_EL1`` maps to Group 0. Otherwise, ``INTR_TYPE_EL3`` maps to Group 0 interrupt. Function: void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target); [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : int Argument : u_register_t Return : void This API should raise an EL3 SGI. The first parameter, ``sgi_num``, specifies the ID of the SGI. The second parameter, ``target``, must be the MPIDR of the target PE. In case of Arm standard platforms using GIC, the implementation of the API inserts barrier to make memory updates visible before raising SGI, then writes to appropriate *SGI Register* in order to raise the EL3 SGI. Function: void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode, u_register_t mpidr); [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Argument : unsigned int Argument : u_register_t Return : void This API should set the routing mode of Share Peripheral Interrupt (SPI) specified by first parameter ``id`` to that specified by the second parameter ``routing_mode``. The ``routing_mode`` parameter can be one of: - ``INTR_ROUTING_MODE_ANY`` means the interrupt can be routed to any PE in the system. The ``mpidr`` parameter is ignored in this case. - ``INTR_ROUTING_MODE_PE`` means the interrupt is routed to the PE whose MPIDR value is specified by the parameter ``mpidr``. In case of Arm standard platforms using GIC, the implementation of the API writes to the GIC *Target Register* (GICv2) or *Route Register* (GICv3) to set the routing. Function: void plat_ic_set_interrupt_pending(unsigned int id); [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Return : void This API should set the interrupt specified by first parameter ``id`` to *Pending*. In case of Arm standard platforms using GIC, the implementation of the API inserts barrier to make memory updates visible before setting interrupt pending, and writes to the GIC *Set Pending Register* to set the interrupt pending status. Function: void plat_ic_clear_interrupt_pending(unsigned int id); [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Return : void This API should clear the *Pending* status of the interrupt specified by first parameter ``id``. In case of Arm standard platforms using GIC, the implementation of the API writes to the GIC *Clear Pending Register* to clear the interrupt pending status, and inserts barrier to make memory updates visible afterwards. Function: unsigned int plat_ic_set_priority_mask(unsigned int id); [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Return : int This API should set the priority mask (first parameter) in the interrupt controller such that only interrupts of higher priority than the supplied one may be signalled to the PE. The API should return the current priority value that it's overwriting. In case of Arm standard platforms using GIC, the implementation of the API inserts to order memory updates before updating mask, then writes to the GIC *Priority Mask Register*, and make sure memory updates are visible before potential trigger due to mask update. Function: unsigned int plat_ic_get_interrupt_id(unsigned int raw); [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Return : unsigned int This API should extract and return the interrupt number from the raw value obtained by the acknowledging the interrupt (read using ``plat_ic_acknowledge_interrupt()``). If the interrupt ID is invalid, this API should return ``INTR_ID_UNAVAILABLE``. In case of Arm standard platforms using GIC, the implementation of the API masks out the interrupt ID field from the acknowledged value from GIC. -------------- *Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.* trusted-firmware-a-2.2/docs/components/ras.rst000066400000000000000000000246501355360272700215540ustar00rootroot00000000000000Reliability, Availability, and Serviceability (RAS) Extensions ============================================================== This document describes |TF-A| support for Arm Reliability, Availability, and Serviceability (RAS) extensions. RAS is a mandatory extension for Armv8.2 and later CPUs, and also an optional extension to the base Armv8.0 architecture. In conjunction with the |EHF|, support for RAS extension enables firmware-first paradigm for handling platform errors: exceptions resulting from errors are routed to and handled in EL3. Said errors are Synchronous External Abort (SEA), Asynchronous External Abort (signalled as SErrors), Fault Handling and Error Recovery interrupts. The |EHF| document mentions various `error handling use-cases`__. .. __: exception-handling.rst#delegation-use-cases For the description of Arm RAS extensions, Standard Error Records, and the precise definition of RAS terminology, please refer to the Arm Architecture Reference Manual. The rest of this document assumes familiarity with architecture and terminology. Overview -------- As mentioned above, the RAS support in |TF-A| enables routing to and handling of exceptions resulting from platform errors in EL3. It allows the platform to define an External Abort handler, and to register RAS nodes and interrupts. RAS framework also provides `helpers`__ for accessing Standard Error Records as introduced by the RAS extensions. .. __: `Standard Error Record helpers`_ The build option ``RAS_EXTENSION`` when set to ``1`` includes the RAS in run time firmware; ``EL3_EXCEPTION_HANDLING`` and ``HANDLE_EA_EL3_FIRST`` must also be set ``1``. .. _ras-figure: .. image:: ../resources/diagrams/draw.io/ras.svg See more on `Engaging the RAS framework`_. Platform APIs ------------- The RAS framework allows the platform to define handlers for External Abort, Uncontainable Errors, Double Fault, and errors rising from EL3 execution. Please refer to the porting guide for the `RAS platform API descriptions`__. .. __: ../getting_started/porting-guide.rst#external-abort-handling-and-ras-support Registering RAS error records ----------------------------- RAS nodes are components in the system capable of signalling errors to PEs through one one of the notification mechanisms—SEAs, SErrors, or interrupts. RAS nodes contain one or more error records, which are registers through which the nodes advertise various properties of the signalled error. Arm recommends that error records are implemented in the Standard Error Record format. The RAS architecture allows for error records to be accessible via system or memory-mapped registers. The platform should enumerate the error records providing for each of them: - A handler to probe error records for errors; - When the probing identifies an error, a handler to handle it; - For memory-mapped error record, its base address and size in KB; for a system register-accessed record, the start index of the record and number of continuous records from that index; - Any node-specific auxiliary data. With this information supplied, when the run time firmware receives one of the notification mechanisms, the RAS framework can iterate through and probe error records for error, and invoke the appropriate handler to handle it. The RAS framework provides the macros to populate error record information. The macros are versioned, and the latest version as of this writing is 1. These macros create a structure of type ``struct err_record_info`` from its arguments, which are later passed to probe and error handlers. For memory-mapped error records: .. code:: c ERR_RECORD_MEMMAP_V1(base_addr, size_num_k, probe, handler, aux) And, for system register ones: .. code:: c ERR_RECORD_SYSREG_V1(idx_start, num_idx, probe, handler, aux) The probe handler must have the following prototype: .. code:: c typedef int (*err_record_probe_t)(const struct err_record_info *info, int *probe_data); The probe handler must return a non-zero value if an error was detected, or 0 otherwise. The ``probe_data`` output parameter can be used to pass any useful information resulting from probe to the error handler (see `below`__). For example, it could return the index of the record. .. __: `Standard Error Record helpers`_ The error handler must have the following prototype: .. code:: c typedef int (*err_record_handler_t)(const struct err_record_info *info, int probe_data, const struct err_handler_data *const data); The ``data`` constant parameter describes the various properties of the error, including the reason for the error, exception syndrome, and also ``flags``, ``cookie``, and ``handle`` parameters from the `top-level exception handler`__. .. __: interrupt-framework-design.rst#el3-interrupts The platform is expected populate an array using the macros above, and register the it with the RAS framework using the macro ``REGISTER_ERR_RECORD_INFO()``, passing it the name of the array describing the records. Note that the macro must be used in the same file where the array is defined. Standard Error Record helpers ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The |TF-A| RAS framework provides probe handlers for Standard Error Records, for both memory-mapped and System Register accesses: .. code:: c int ras_err_ser_probe_memmap(const struct err_record_info *info, int *probe_data); int ras_err_ser_probe_sysreg(const struct err_record_info *info, int *probe_data); When the platform enumerates error records, for those records in the Standard Error Record format, these helpers maybe used instead of rolling out their own. Both helpers above: - Return non-zero value when an error is detected in a Standard Error Record; - Set ``probe_data`` to the index of the error record upon detecting an error. Registering RAS interrupts -------------------------- RAS nodes can signal errors to the PE by raising Fault Handling and/or Error Recovery interrupts. For the firmware-first handling paradigm for interrupts to work, the platform must setup and register with |EHF|. See `Interaction with Exception Handling Framework`_. For each RAS interrupt, the platform has to provide structure of type ``struct ras_interrupt``: - Interrupt number; - The associated error record information (pointer to the corresponding ``struct err_record_info``); - Optionally, a cookie. The platform is expected to define an array of ``struct ras_interrupt``, and register it with the RAS framework using the macro ``REGISTER_RAS_INTERRUPTS()``, passing it the name of the array. Note that the macro must be used in the same file where the array is defined. The array of ``struct ras_interrupt`` must be sorted in the increasing order of interrupt number. This allows for fast look of handlers in order to service RAS interrupts. Double-fault handling --------------------- A Double Fault condition arises when an error is signalled to the PE while handling of a previously signalled error is still underway. When a Double Fault condition arises, the Arm RAS extensions only require for handler to perform orderly shutdown of the system, as recovery may be impossible. The RAS extensions part of Armv8.4 introduced new architectural features to deal with Double Fault conditions, specifically, the introduction of ``NMEA`` and ``EASE`` bits to ``SCR_EL3`` register. These were introduced to assist EL3 software which runs part of its entry/exit routines with exceptions momentarily masked—meaning, in such systems, External Aborts/SErrors are not immediately handled when they occur, but only after the exceptions are unmasked again. |TF-A|, for legacy reasons, executes entire EL3 with all exceptions unmasked. This means that all exceptions routed to EL3 are handled immediately. |TF-A| thus is able to detect a Double Fault conditions in software, without needing the intended advantages of Armv8.4 Double Fault architecture extensions. Double faults are fatal, and terminate at the platform double fault handler, and doesn't return. Engaging the RAS framework -------------------------- Enabling RAS support is a platform choice constructed from three distinct, but related, build options: - ``RAS_EXTENSION=1`` includes the RAS framework in the run time firmware; - ``EL3_EXCEPTION_HANDLING=1`` enables handling of exceptions at EL3. See `Interaction with Exception Handling Framework`_; - ``HANDLE_EA_EL3_FIRST=1`` enables routing of External Aborts and SErrors to EL3. The RAS support in |TF-A| introduces a default implementation of ``plat_ea_handler``, the External Abort handler in EL3. When ``RAS_EXTENSION`` is set to ``1``, it'll first call ``ras_ea_handler()`` function, which is the top-level RAS exception handler. ``ras_ea_handler`` is responsible for iterating to through platform-supplied error records, probe them, and when an error is identified, look up and invoke the corresponding error handler. Note that, if the platform chooses to override the ``plat_ea_handler`` function and intend to use the RAS framework, it must explicitly call ``ras_ea_handler()`` from within. Similarly, for RAS interrupts, the framework defines ``ras_interrupt_handler()``. The RAS framework arranges for it to be invoked when a RAS interrupt taken at EL3. The function bisects the platform-supplied sorted array of interrupts to look up the error record information associated with the interrupt number. That error handler for that record is then invoked to handle the error. Interaction with Exception Handling Framework --------------------------------------------- As mentioned in earlier sections, RAS framework interacts with the |EHF| to arbitrate handling of RAS exceptions with others that are routed to EL3. This means that the platform must partition a `priority level`__ for handling RAS exceptions. The platform must then define the macro ``PLAT_RAS_PRI`` to the priority level used for RAS exceptions. Platforms would typically want to allocate the highest secure priority for RAS handling. .. __: exception-handling.rst#partitioning-priority-levels Handling of both `interrupt`__ and `non-interrupt`__ exceptions follow the sequences outlined in the |EHF| documentation. I.e., for interrupts, the priority management is implicit; but for non-interrupt exceptions, they're explicit using `EHF APIs`__. .. __: exception-handling.rst#interrupt-flow .. __: exception-handling.rst#non-interrupt-flow .. __: exception-handling.rst#activating-and-deactivating-priorities -------------- *Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.* trusted-firmware-a-2.2/docs/components/romlib-design.rst000066400000000000000000000113701355360272700235150ustar00rootroot00000000000000Library at ROM ============== This document provides an overview of the "library at ROM" implementation in Trusted Firmware-A (TF-A). Introduction ~~~~~~~~~~~~ The "library at ROM" feature allows platforms to build a library of functions to be placed in ROM. This reduces SRAM usage by utilising the available space in ROM. The "library at ROM" contains a jump table with the list of functions that are placed in ROM. The capabilities of the "library at ROM" are: 1. Functions can be from one or several libraries. 2. Functions can be patched after they have been programmed into ROM. 3. Platform-specific libraries can be placed in ROM. 4. Functions can be accessed by one or more BL images. Index file ~~~~~~~~~~ .. image:: ../resources/diagrams/romlib_design.png :width: 600 Library at ROM is described by an index file with the list of functions to be placed in ROM. The index file is platform specific and its format is: :: lib function [patch] lib -- Name of the library the function belongs to function -- Name of the function to be placed in library at ROM [patch] -- Option to patch the function It is also possible to insert reserved spaces in the list by using the keyword "reserved" rather than the "lib" and "function" names as shown below: :: reserved The reserved spaces can be used to add more functions in the future without affecting the order and location of functions already existing in the jump table. Also, for additional flexibility and modularity, the index file can include other index files. For an index file example, refer to ``lib/romlib/jmptbl.i``. Wrapper functions ~~~~~~~~~~~~~~~~~ .. image:: ../resources/diagrams/romlib_wrapper.png :width: 600 When invoking a function of the "library at ROM", the calling sequence is as follows: BL image --> wrapper function --> jump table entry --> library at ROM The index file is used to create a jump table which is placed in ROM. Then, the wrappers refer to the jump table to call the "library at ROM" functions. The wrappers essentially contain a branch instruction to the jump table entry corresponding to the original function. Finally, the original function in the BL image(s) is replaced with the wrapper function. The "library at ROM" contains a necessary init function that initialises the global variables defined by the functions inside "library at ROM". Script ~~~~~~ There is a ``romlib_generate.py`` Python script that generates the necessary files for the "library at ROM" to work. It implements multiple functions: 1. ``romlib_generate.py gentbl [args]`` - Generates the jump table by parsing the index file. 2. ``romlib_generator.py genvar [args]`` - Generates the jump table global variable (**not** the jump table itself) with the absolute address in ROM. This global variable is, basically, a pointer to the jump table. 3. ``romlib_generator.py genwrappers [args]`` - Generates a wrapper function for each entry in the index file except for the ones that contain the keyword ``patch``. The generated wrapper file is called ``.s``. 4. ``romlib_generator.py pre [args]`` - Preprocesses the index file which means it resolves all the include commands in the file recursively. It can also generate a dependency file of the included index files which can be directly used in makefiles. Each ``romlib_generate.py`` function has its own manual which is accessible by runing ``romlib_generator.py [function] --help``. ``romlib_generate.py`` requires Python 3 environment. Patching of functions in library at ROM ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``romlib_generator.py genwrappers`` does not generate wrappers for the entries in the index file that contain the keyword ``patch``. Thus, it allows calling the function from the actual library by breaking the link to the "library at ROM" version of this function. The calling sequence for a patched function is as follows: BL image --> function Build library at ROM ~~~~~~~~~~~~~~~~~~~~~ The environment variable ``CROSS_COMPILE`` must be set as per the user guide. In the below example the usage of ROMLIB together with mbed TLS is demonstrated to showcase the benefits of library at ROM - it's not mandatory. .. code:: shell make PLAT=fvp \ MBEDTLS_DIR= \ TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 \ ARM_ROTPK_LOCATION=devel_rsa \ ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem \ BL33= \ USE_ROMLIB=1 \ all fip -------------- *Copyright (c) 2019, Arm Limited. All rights reserved.* trusted-firmware-a-2.2/docs/components/sdei.rst000066400000000000000000000340771355360272700217170ustar00rootroot00000000000000SDEI: Software Delegated Exception Interface ============================================ This document provides an overview of the SDEI dispatcher implementation in Trusted Firmware-A (TF-A). Introduction ------------ Software Delegated Exception Interface (|SDEI|) is an Arm specification for Non-secure world to register handlers with firmware to receive notifications about system events. Firmware will first receive the system events by way of asynchronous exceptions and, in response, arranges for the registered handler to execute in the Non-secure EL. Normal world software that interacts with the SDEI dispatcher (makes SDEI requests and receives notifications) is referred to as the *SDEI Client*. A client receives the event notification at the registered handler even when it was executing with exceptions masked. The list of SDEI events available to the client are specific to the platform [#std-event]_. See also `Determining client EL`_. .. _general SDEI dispatch: The following figure depicts a general sequence involving SDEI client executing at EL2 and an event dispatch resulting from the triggering of a bound interrupt. A commentary is provided below: .. uml:: ../resources/diagrams/plantuml/sdei_general.puml As part of initialisation, the SDEI client binds a Non-secure interrupt [1], and the SDEI dispatcher returns a platform dynamic event number [2]. The client then registers a handler for that event [3], enables the event [5], and unmasks all events on the current PE [7]. This sequence is typical of an SDEI client, but it may involve additional SDEI calls. At a later point in time, when the bound interrupt triggers [9], it's trapped to EL3. The interrupt is handed over to the SDEI dispatcher, which then arranges to execute the registered handler [10]. The client terminates its execution with ``SDEI_EVENT_COMPLETE`` [11], following which the dispatcher resumes the original EL2 execution [13]. Note that the SDEI interrupt remains active until the client handler completes, at which point EL3 does EOI [12]. Other than events bound to interrupts, as depicted in the sequence above, SDEI events can be explicitly dispatched in response to other exceptions, for example, upon receiving an *SError* or *Synchronous External Abort*. See `Explicit dispatch of events`_. The remainder of this document only discusses the design and implementation of SDEI dispatcher in TF-A, and assumes that the reader is familiar with the SDEI specification, the interfaces, and their requirements. Defining events --------------- A platform choosing to include the SDEI dispatcher must also define the events available on the platform, along with their attributes. The platform is expected to provide two arrays of event descriptors: one for private events, and another for shared events. The SDEI dispatcher provides ``SDEI_PRIVATE_EVENT()`` and ``SDEI_SHARED_EVENT()`` macros to populate the event descriptors. Both macros take 3 arguments: - The event number: this must be a positive 32-bit integer. - For an event that has a backing interrupt, the interrupt number the event is bound to: - If it's not applicable to an event, this shall be left as ``0``. - If the event is dynamic, this should be specified as ``SDEI_DYN_IRQ``. - A bit map of `Event flags`_. To define event 0, the macro ``SDEI_DEFINE_EVENT_0()`` should be used. This macro takes only one parameter: an SGI number to signal other PEs. To define an event that's meant to be explicitly dispatched (i.e., not as a result of receiving an SDEI interrupt), the macro ``SDEI_EXPLICIT_EVENT()`` should be used. It accepts two parameters: - The event number (as above); - Event priority: ``SDEI_MAPF_CRITICAL`` or ``SDEI_MAPF_NORMAL``, as described below. Once the event descriptor arrays are defined, they should be exported to the SDEI dispatcher using the ``REGISTER_SDEI_MAP()`` macro, passing it the pointers to the private and shared event descriptor arrays, respectively. Note that the ``REGISTER_SDEI_MAP()`` macro must be used in the same file where the arrays are defined. Regarding event descriptors: - For Event 0: - There must be exactly one descriptor in the private array, and none in the shared array. - The event should be defined using ``SDEI_DEFINE_EVENT_0()``. - Must be bound to a Secure SGI on the platform. - Explicit events should only be used in the private array. - Statically bound shared and private interrupts must be bound to shared and private interrupts on the platform, respectively. See the section on `Configuration within Exception Handling Framework`_. - Both arrays should be one-dimensional. The ``REGISTER_SDEI_MAP()`` macro takes care of replicating private events for each PE on the platform. - Both arrays must be sorted in the increasing order of event number. The SDEI specification doesn't have provisions for discovery of available events on the platform. The list of events made available to the client, along with their semantics, have to be communicated out of band; for example, through Device Trees or firmware configuration tables. See also `Event definition example`_. Event flags ~~~~~~~~~~~ Event flags describe the properties of the event. They are bit maps that can be ``OR``\ ed to form parameters to macros that define events (see `Defining events`_). - ``SDEI_MAPF_DYNAMIC``: Marks the event as dynamic. Dynamic events can be bound to (or released from) any Non-secure interrupt at runtime via the ``SDEI_INTERRUPT_BIND`` and ``SDEI_INTERRUPT_RELEASE`` calls. - ``SDEI_MAPF_BOUND``: Marks the event as statically bound to an interrupt. These events cannot be re-bound at runtime. - ``SDEI_MAPF_NORMAL``: Marks the event as having *Normal* priority. This is the default priority. - ``SDEI_MAPF_CRITICAL``: Marks the event as having *Critical* priority. Event definition example ------------------------ .. code:: c static sdei_ev_map_t plat_private_sdei[] = { /* Event 0 definition */ SDEI_DEFINE_EVENT_0(8), /* PPI */ SDEI_PRIVATE_EVENT(8, 23, SDEI_MAPF_BOUND), /* Dynamic private events */ SDEI_PRIVATE_EVENT(100, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), SDEI_PRIVATE_EVENT(101, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC) /* Events for explicit dispatch */ SDEI_EXPLICIT_EVENT(2000, SDEI_MAPF_NORMAL); SDEI_EXPLICIT_EVENT(2000, SDEI_MAPF_CRITICAL); }; /* Shared event mappings */ static sdei_ev_map_t plat_shared_sdei[] = { SDEI_SHARED_EVENT(804, 0, SDEI_MAPF_DYNAMIC), /* Dynamic shared events */ SDEI_SHARED_EVENT(3000, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), SDEI_SHARED_EVENT(3001, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC) }; /* Export SDEI events */ REGISTER_SDEI_MAP(plat_private_sdei, plat_shared_sdei); Configuration within Exception Handling Framework ------------------------------------------------- The SDEI dispatcher functions alongside the Exception Handling Framework. This means that the platform must assign priorities to both Normal and Critical SDEI interrupts for the platform: - Install priority descriptors for Normal and Critical SDEI interrupts. - For those interrupts that are statically bound (i.e. events defined as having the ``SDEI_MAPF_BOUND`` property), enumerate their properties for the GIC driver to configure interrupts accordingly. The interrupts must be configured to target EL3. This means that they should be configured as *Group 0*. Additionally, on GICv2 systems, the build option ``GICV2_G0_FOR_EL3`` must be set to ``1``. See also :ref:`porting_guide_sdei_requirements`. Determining client EL --------------------- The SDEI specification requires that the *physical* SDEI client executes in the highest Non-secure EL implemented on the system. This means that the dispatcher will only allow SDEI calls to be made from: - EL2, if EL2 is implemented. The Hypervisor is expected to implement a *virtual* SDEI dispatcher to support SDEI clients in Guest Operating Systems executing in Non-secure EL1. - Non-secure EL1, if EL2 is not implemented or disabled. See the function ``sdei_client_el()`` in ``sdei_private.h``. Explicit dispatch of events --------------------------- Typically, an SDEI event dispatch is caused by the PE receiving interrupts that are bound to an SDEI event. However, there are cases where the Secure world requires dispatch of an SDEI event as a direct or indirect result of a past activity, such as receiving a Secure interrupt or an exception. The SDEI dispatcher implementation provides ``sdei_dispatch_event()`` API for this purpose. The API has the following signature: .. code:: c int sdei_dispatch_event(int ev_num); The parameter ``ev_num`` is the event number to dispatch. The API returns ``0`` on success, or ``-1`` on failure. The following figure depicts a scenario involving explicit dispatch of SDEI event. A commentary is provided below: .. uml:: ../resources/diagrams/plantuml/sdei_explicit_dispatch.puml As part of initialisation, the SDEI client registers a handler for a platform event [1], enables the event [3], and unmasks the current PE [5]. Note that, unlike in `general SDEI dispatch`_, this doesn't involve interrupt binding, as bound or dynamic events can't be explicitly dispatched (see the section below). At a later point in time, a critical event [#critical-event]_ is trapped into EL3 [7]. EL3 performs a first-level triage of the event, and a RAS component assumes further handling [8]. The dispatch completes, but intends to involve Non-secure world in further handling, and therefore decides to explicitly dispatch an event [10] (which the client had already registered for [1]). The rest of the sequence is similar to that in the `general SDEI dispatch`_: the requested event is dispatched to the client (assuming all the conditions are met), and when the handler completes, the preempted execution resumes. Conditions for event dispatch ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ All of the following requirements must be met for the API to return ``0`` and event to be dispatched: - SDEI events must be unmasked on the PE. I.e. the client must have called ``PE_UNMASK`` beforehand. - Event 0 can't be dispatched. - The event must be declared using the ``SDEI_EXPLICIT_EVENT()`` macro described above. - The event must be private to the PE. - The event must have been registered for and enabled. - A dispatch for the same event must not be outstanding. I.e. it hasn't already been dispatched and is yet to be completed. - The priority of the event (either Critical or Normal, as configured by the platform at build-time) shouldn't cause priority inversion. This means: - If it's of Normal priority, neither Normal nor Critical priority dispatch must be outstanding on the PE. - If it's of a Critical priority, no Critical priority dispatch must be outstanding on the PE. Further, the caller should be aware of the following assumptions made by the dispatcher: - The caller of the API is a component running in EL3; for example, a RAS driver. - The requested dispatch will be permitted by the Exception Handling Framework. I.e. the caller must make sure that the requested dispatch has sufficient priority so as not to cause priority level inversion within Exception Handling Framework. - The caller must be prepared for the SDEI dispatcher to restore the Non-secure context, and mark that the active context. - The call will block until the SDEI client completes the event (i.e. when the client calls either ``SDEI_EVENT_COMPLETE`` or ``SDEI_COMPLETE_AND_RESUME``). - The caller must be prepared for this API to return failure and handle accordingly. Porting requirements -------------------- The porting requirements of the SDEI dispatcher are outlined in the :ref:`Porting Guide `. Note on writing SDEI event handlers ----------------------------------- *This section pertains to SDEI event handlers in general, not just when using the TF-A SDEI dispatcher.* The SDEI specification requires that event handlers preserve the contents of all registers except ``x0`` to ``x17``. This has significance if event handler is written in C: compilers typically adjust the stack frame at the beginning and end of C functions. For example, AArch64 GCC typically produces the following function prologue and epilogue: :: c_event_handler: stp x29, x30, [sp,#-32]! mov x29, sp ... bl ... ... ldp x29, x30, [sp],#32 ret The register ``x29`` is used as frame pointer in the prologue. Because neither a valid ``SDEI_EVENT_COMPLETE`` nor ``SDEI_EVENT_COMPLETE_AND_RESUME`` calls return to the handler, the epilogue never gets executed, and registers ``x29`` and ``x30`` (in the case above) are inadvertently corrupted. This violates the SDEI specification, and the normal execution thereafter will result in unexpected behaviour. To work this around, it's advised that the top-level event handlers are implemented in assembly, following a similar pattern as below: :: asm_event_handler: /* Save link register whilst maintaining stack alignment */ stp xzr, x30, [sp, #-16]! bl c_event_handler /* Restore link register */ ldp xzr, x30, [sp], #16 /* Complete call */ ldr x0, =SDEI_EVENT_COMPLETE smc #0 b . -------------- *Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.* .. rubric:: Footnotes .. [#std-event] Except event 0, which is defined by the SDEI specification as a standard event. .. [#critical-event] Examples of critical events are *SError*, *Synchronous External Abort*, *Fault Handling interrupt* or *Error Recovery interrupt* from one of RAS nodes in the system. .. _SDEI specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf .. _Software Delegated Exception Interface: `SDEI specification`_ trusted-firmware-a-2.2/docs/components/secure-partition-manager-design.rst000066400000000000000000000764321355360272700271500ustar00rootroot00000000000000Secure Partition Manager ************************ Background ========== In some market segments that primarily deal with client-side devices like mobile phones, tablets, STBs and embedded devices, a Trusted OS instantiates trusted applications to provide security services like DRM, secure payment and authentication. The Global Platform TEE Client API specification defines the API used by Non-secure world applications to access these services. A Trusted OS fulfils the requirements of a security service as described above. Management services are typically implemented at the highest level of privilege in the system, i.e. EL3 in Trusted Firmware-A (TF-A). The service requirements are fulfilled by the execution environment provided by TF-A. The following diagram illustrates the corresponding software stack: |Image 1| In other market segments that primarily deal with server-side devices (e.g. data centres and enterprise servers) the secure software stack typically does not include a Global Platform Trusted OS. Security functions are accessed through other interfaces (e.g. ACPI TCG TPM interface, UEFI runtime variable service). Placement of management and security functions with diverse requirements in a privileged Exception Level (i.e. EL3 or S-EL1) makes security auditing of firmware more difficult and does not allow isolation of unrelated services from each other either. Introduction ============ A **Secure Partition** is a software execution environment instantiated in S-EL0 that can be used to implement simple management and security services. Since S-EL0 is an unprivileged Exception Level, a Secure Partition relies on privileged firmware (i.e. TF-A) to be granted access to system and processor resources. Essentially, it is a software sandbox in the Secure world that runs under the control of privileged software, provides one or more services and accesses the following system resources: - Memory and device regions in the system address map. - PE system registers. - A range of synchronous exceptions (e.g. SMC function identifiers). Note that currently TF-A only supports handling one Secure Partition. A Secure Partition enables TF-A to implement only the essential secure services in EL3 and instantiate the rest in a partition in S-EL0. Furthermore, multiple Secure Partitions can be used to isolate unrelated services from each other. The following diagram illustrates the place of a Secure Partition in a typical Armv8-A software stack. A single or multiple Secure Partitions provide secure services to software components in the Non-secure world and other Secure Partitions. |Image 2| The TF-A build system is responsible for including the Secure Partition image in the FIP. During boot, BL2 includes support to authenticate and load the Secure Partition image. A BL31 component called **Secure Partition Manager (SPM)** is responsible for managing the partition. This is semantically similar to a hypervisor managing a virtual machine. The SPM is responsible for the following actions during boot: - Allocate resources requested by the Secure Partition. - Perform architectural and system setup required by the Secure Partition to fulfil a service request. - Implement a standard interface that is used for initialising a Secure Partition. The SPM is responsible for the following actions during runtime: - Implement a standard interface that is used by a Secure Partition to fulfil service requests. - Implement a standard interface that is used by the Non-secure world for accessing the services exported by a Secure Partition. A service can be invoked through a SMC. Alternatively, a partition can be viewed as a thread of execution running under the control of the SPM. Hence common programming concepts described below are applicable to a partition. Description =========== The previous section introduced some general aspects of the software architecture of a Secure Partition. This section describes the specific choices made in the current implementation of this software architecture. Subsequent revisions of the implementation will include a richer set of features that enable a more flexible architecture. Building TF-A with Secure Partition support ------------------------------------------- SPM is supported on the Arm FVP exclusively at the moment. The current implementation supports inclusion of only a single Secure Partition in which a service always runs to completion (e.g. the requested services cannot be preempted to give control back to the Normal world). It is not currently possible for BL31 to integrate SPM support and a Secure Payload Dispatcher (SPD) at the same time; they are mutually exclusive. In the SPM bootflow, a Secure Partition image executing at S-EL0 replaces the Secure Payload image executing at S-EL1 (e.g. a Trusted OS). Both are referred to as BL32. A working prototype of a SP has been implemented by re-purposing the EDK2 code and tools, leveraging the concept of the *Standalone Management Mode (MM)* in the UEFI specification (see the PI v1.6 Volume 4: Management Mode Core Interface). This will be referred to as the *Standalone MM Secure Partition* in the rest of this document. To enable SPM support in TF-A, the source code must be compiled with the build flag ``ENABLE_SPM=1``, along with ``EL3_EXCEPTION_HANDLING=1``. On Arm platforms the build option ``ARM_BL31_IN_DRAM`` must be set to 1. Also, the location of the binary that contains the BL32 image (``BL32=path/to/image.bin``) must be specified. First, build the Standalone MM Secure Partition. To build it, refer to the `instructions in the EDK2 repository`_. Then build TF-A with SPM support and include the Standalone MM Secure Partition image in the FIP: .. code:: shell BL32=path/to/standalone/mm/sp BL33=path/to/bl33.bin \ make PLAT=fvp ENABLE_SPM=1 ARM_BL31_IN_DRAM=1 fip all Describing Secure Partition resources ------------------------------------- TF-A exports a porting interface that enables a platform to specify the system resources required by the Secure Partition. Some instructions are given below. However, this interface is under development and it may change as new features are implemented. - A Secure Partition is considered a BL32 image, so the same defines that apply to BL32 images apply to a Secure Partition: ``BL32_BASE`` and ``BL32_LIMIT``. - The following defines are needed to allocate space for the translation tables used by the Secure Partition: ``PLAT_SP_IMAGE_MMAP_REGIONS`` and ``PLAT_SP_IMAGE_MAX_XLAT_TABLES``. - The functions ``plat_get_secure_partition_mmap()`` and ``plat_get_secure_partition_boot_info()`` have to be implemented. The file ``plat/arm/board/fvp/fvp_common.c`` can be used as an example. It uses the defines in ``include/plat/arm/common/arm_spm_def.h``. - ``plat_get_secure_partition_mmap()`` returns an array of mmap regions that describe the memory regions that the SPM needs to allocate for a Secure Partition. - ``plat_get_secure_partition_boot_info()`` returns a ``secure_partition_boot_info_t`` struct that is populated by the platform with information about the memory map of the Secure Partition. For an example of all the changes in context, you may refer to commit ``e29efeb1b4``, in which the port for FVP was introduced. Accessing Secure Partition services ----------------------------------- The `SMC Calling Convention`_ (*Arm DEN 0028B*) describes SMCs as a conduit for accessing services implemented in the Secure world. The ``MM_COMMUNICATE`` interface defined in the `Management Mode Interface Specification`_ (*Arm DEN 0060A*) is used to invoke a Secure Partition service as a Fast Call. The mechanism used to identify a service within the partition depends on the service implementation. It is assumed that the caller of the service will be able to discover this mechanism through standard platform discovery mechanisms like ACPI and Device Trees. For example, *Volume 4: Platform Initialisation Specification v1.6. Management Mode Core Interface* specifies that a GUID is used to identify a management mode service. A client populates the GUID in the ``EFI_MM_COMMUNICATE_HEADER``. The header is populated in the communication buffer shared with the Secure Partition. A Fast Call appears to be atomic from the perspective of the caller and returns when the requested operation has completed. A service invoked through the ``MM_COMMUNICATE`` SMC will run to completion in the partition on a given CPU. The SPM is responsible for guaranteeing this behaviour. This means that there can only be a single outstanding Fast Call in a partition on a given CPU. Exchanging data with the Secure Partition ----------------------------------------- The exchange of data between the Non-secure world and the partition takes place through a shared memory region. The location of data in the shared memory area is passed as a parameter to the ``MM_COMMUNICATE`` SMC. The shared memory area is statically allocated by the SPM and is expected to be either implicitly known to the Non-secure world or discovered through a platform discovery mechanism e.g. ACPI table or device tree. It is possible for the Non-secure world to exchange data with a partition only if it has been populated in this shared memory area. The shared memory area is implemented as per the guidelines specified in Section 3.2.3 of the `Management Mode Interface Specification`_ (*Arm DEN 0060A*). The format of data structures used to encapsulate data in the shared memory is agreed between the Non-secure world and the Secure Partition. For example, in the `Management Mode Interface specification`_ (*Arm DEN 0060A*), Section 4 describes that the communication buffer shared between the Non-secure world and the Management Mode (MM) in the Secure world must be of the type ``EFI_MM_COMMUNICATE_HEADER``. This data structure is defined in *Volume 4: Platform Initialisation Specification v1.6. Management Mode Core Interface*. Any caller of a MM service will have to use the ``EFI_MM_COMMUNICATE_HEADER`` data structure. Runtime model of the Secure Partition ===================================== This section describes how the Secure Partition interfaces with the SPM. Interface with SPM ------------------ In order to instantiate one or more secure services in the Secure Partition in S-EL0, the SPM should define the following types of interfaces: - Interfaces that enable access to privileged operations from S-EL0. These operations typically require access to system resources that are either shared amongst multiple software components in the Secure world or cannot be directly accessed from an unprivileged Exception Level. - Interfaces that establish the control path between the SPM and the Secure Partition. This section describes the APIs currently exported by the SPM that enable a Secure Partition to initialise itself and export its services in S-EL0. These interfaces are not accessible from the Non-secure world. Conduit ^^^^^^^ The `SMC Calling Convention`_ (*Arm DEN 0028B*) specification describes the SMC and HVC conduits for accessing firmware services and their availability depending on the implemented Exception levels. In S-EL0, the Supervisor Call exception (SVC) is the only architectural mechanism available for unprivileged software to make a request for an operation implemented in privileged software. Hence, the SVC conduit must be used by the Secure Partition to access interfaces implemented by the SPM. A SVC causes an exception to be taken to S-EL1. TF-A assumes ownership of S-EL1 and installs a simple exception vector table in S-EL1 that relays a SVC request from a Secure Partition as a SMC request to the SPM in EL3. Upon servicing the SMC request, Trusted Firmware-A returns control directly to S-EL0 through an ERET instruction. Calling conventions ^^^^^^^^^^^^^^^^^^^ The `SMC Calling Convention`_ (*Arm DEN 0028B*) specification describes the 32-bit and 64-bit calling conventions for the SMC and HVC conduits. The SVC conduit introduces the concept of SVC32 and SVC64 calling conventions. The SVC32 and SVC64 calling conventions are equivalent to the 32-bit (SMC32) and the 64-bit (SMC64) calling conventions respectively. Communication initiated by SPM ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ A service request is initiated from the SPM through an exception return instruction (ERET) to S-EL0. Later, the Secure Partition issues an SVC instruction to signal completion of the request. Some example use cases are given below: - A request to initialise the Secure Partition during system boot. - A request to handle a runtime service request. Communication initiated by Secure Partition ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ A request is initiated from the Secure Partition by executing a SVC instruction. An ERET instruction is used by TF-A to return to S-EL0 with the result of the request. For instance, a request to perform privileged operations on behalf of a partition (e.g. management of memory attributes in the translation tables for the Secure EL1&0 translation regime). Interfaces ^^^^^^^^^^ The current implementation reserves function IDs for Fast Calls in the Standard Secure Service calls range (see `SMC Calling Convention`_ (*Arm DEN 0028B*) specification) for each API exported by the SPM. This section defines the function prototypes for each function ID. The function IDs specify whether one or both of the SVC32 and SVC64 calling conventions can be used to invoke the corresponding interface. Secure Partition Event Management ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The Secure Partition provides an Event Management interface that is used by the SPM to delegate service requests to the Secure Partition. The interface also allows the Secure Partition to: - Register with the SPM a service that it provides. - Indicate completion of a service request delegated by the SPM Miscellaneous interfaces ------------------------ ``SPM_VERSION_AARCH32`` ^^^^^^^^^^^^^^^^^^^^^^^ - Description Returns the version of the interface exported by SPM. - Parameters - **uint32** - Function ID - SVC32 Version: **0x84000060** - Return parameters - **int32** - Status On success, the format of the value is as follows: - Bit [31]: Must be 0 - Bits [30:16]: Major Version. Must be 0 for this revision of the SPM interface. - Bits [15:0]: Minor Version. Must be 1 for this revision of the SPM interface. On error, the format of the value is as follows: - ``NOT_SUPPORTED``: SPM interface is not supported or not available for the client. - Usage This function returns the version of the Secure Partition Manager implementation. The major version is 0 and the minor version is 1. The version number is a 31-bit unsigned integer, with the upper 15 bits denoting the major revision, and the lower 16 bits denoting the minor revision. The following rules apply to the version numbering: - Different major revision values indicate possibly incompatible functions. - For two revisions, A and B, for which the major revision values are identical, if the minor revision value of revision B is greater than the minor revision value of revision A, then every function in revision A must work in a compatible way with revision B. However, it is possible for revision B to have a higher function count than revision A. - Implementation responsibilities If this function returns a valid version number, all the functions that are described subsequently must be implemented, unless it is explicitly stated that a function is optional. See `Error Codes`_ for integer values that are associated with each return code. Secure Partition Initialisation ------------------------------- The SPM is responsible for initialising the architectural execution context to enable initialisation of a service in S-EL0. The responsibilities of the SPM are listed below. At the end of initialisation, the partition issues a ``SP_EVENT_COMPLETE_AARCH64`` call (described later) to signal readiness for handling requests for services implemented by the Secure Partition. The initialisation event is executed as a Fast Call. Entry point invocation ^^^^^^^^^^^^^^^^^^^^^^ The entry point for service requests that should be handled as Fast Calls is used as the target of the ERET instruction to start initialisation of the Secure Partition. Architectural Setup ^^^^^^^^^^^^^^^^^^^ At cold boot, system registers accessible from S-EL0 will be in their reset state unless otherwise specified. The SPM will perform the following architectural setup to enable execution in S-EL0 MMU setup ^^^^^^^^^ The platform port of a Secure Partition specifies to the SPM a list of regions that it needs access to and their attributes. The SPM validates this resource description and initialises the Secure EL1&0 translation regime as follows. 1. Device regions are mapped with nGnRE attributes and Execute Never instruction access permissions. 2. Code memory regions are mapped with RO data and Executable instruction access permissions. 3. Read Only data memory regions are mapped with RO data and Execute Never instruction access permissions. 4. Read Write data memory regions are mapped with RW data and Execute Never instruction access permissions. 5. If the resource description does not explicitly describe the type of memory regions then all memory regions will be marked with Code memory region attributes. 6. The ``UXN`` and ``PXN`` bits are set for regions that are not executable by S-EL0 or S-EL1. System Register Setup ^^^^^^^^^^^^^^^^^^^^^ System registers that influence software execution in S-EL0 are setup by the SPM as follows: 1. ``SCTLR_EL1`` - ``UCI=1`` - ``EOE=0`` - ``WXN=1`` - ``nTWE=1`` - ``nTWI=1`` - ``UCT=1`` - ``DZE=1`` - ``I=1`` - ``UMA=0`` - ``SA0=1`` - ``C=1`` - ``A=1`` - ``M=1`` 2. ``CPACR_EL1`` - ``FPEN=b'11`` 3. ``PSTATE`` - ``D,A,I,F=1`` - ``CurrentEL=0`` (EL0) - ``SpSel=0`` (Thread mode) - ``NRW=0`` (AArch64) General Purpose Register Setup ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SPM will invoke the entry point of a service by executing an ERET instruction. This transition into S-EL0 is special since it is not in response to a previous request through a SVC instruction. This is the first entry into S-EL0. The general purpose register usage at the time of entry will be as specified in the "Return State" column of Table 3-1 in Section 3.1 "Register use in AArch64 SMC calls" of the `SMC Calling Convention`_ (*Arm DEN 0028B*) specification. In addition, certain other restrictions will be applied as described below. 1. ``SP_EL0`` A non-zero value will indicate that the SPM has initialised the stack pointer for the current CPU. The value will be 0 otherwise. 2. ``X4-X30`` The values of these registers will be 0. 3. ``X0-X3`` Parameters passed by the SPM. - ``X0``: Virtual address of a buffer shared between EL3 and S-EL0. The buffer will be mapped in the Secure EL1&0 translation regime with read-only memory attributes described earlier. - ``X1``: Size of the buffer in bytes. - ``X2``: Cookie value (*IMPLEMENTATION DEFINED*). - ``X3``: Cookie value (*IMPLEMENTATION DEFINED*). Runtime Event Delegation ------------------------ The SPM receives requests for Secure Partition services through a synchronous invocation (i.e. a SMC from the Non-secure world). These requests are delegated to the partition by programming a return from the last ``SP_EVENT_COMPLETE_AARCH64`` call received from the partition. The last call was made to signal either completion of Secure Partition initialisation or completion of a partition service request. ``SP_EVENT_COMPLETE_AARCH64`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Description Signal completion of the last SP service request. - Parameters - **uint32** - Function ID - SVC64 Version: **0xC4000061** - **int32** - Event Status Code Zero or a positive value indicates that the event was handled successfully. The values depend upon the original event that was delegated to the Secure partition. They are described as follows. - ``SUCCESS`` : Used to indicate that the Secure Partition was initialised or a runtime request was handled successfully. - Any other value greater than 0 is used to pass a specific Event Status code in response to a runtime event. A negative value indicates an error. The values of Event Status code depend on the original event. - Return parameters - **int32** - Event ID/Return Code Zero or a positive value specifies the unique ID of the event being delegated to the partition by the SPM. In the current implementation, this parameter contains the function ID of the ``MM_COMMUNICATE`` SMC. This value indicates to the partition that an event has been delegated to it in response to an ``MM_COMMUNICATE`` request from the Non-secure world. A negative value indicates an error. The format of the value is as follows: - ``NOT_SUPPORTED``: Function was called from the Non-secure world. See `Error Codes`_ for integer values that are associated with each return code. - **uint32** - Event Context Address Address of a buffer shared between the SPM and Secure Partition to pass event specific information. The format of the data populated in the buffer is implementation defined. The buffer is mapped in the Secure EL1&0 translation regime with read-only memory attributes described earlier. For the SVC64 version, this parameter is a 64-bit Virtual Address (VA). For the SVC32 version, this parameter is a 32-bit Virtual Address (VA). - **uint32** - Event context size Size of the memory starting at Event Address. - **uint32/uint64** - Event Cookie This is an optional parameter. If unused its value is SBZ. - Usage This function signals to the SPM that the handling of the last event delegated to a partition has completed. The partition is ready to handle its next event. A return from this function is in response to the next event that will be delegated to the partition. The return parameters describe the next event. - Caller responsibilities A Secure Partition must only call ``SP_EVENT_COMPLETE_AARCH64`` to signal completion of a request that was delegated to it by the SPM. - Callee responsibilities When the SPM receives this call from a Secure Partition, the corresponding syndrome information can be used to return control through an ERET instruction, to the instruction immediately after the call in the Secure Partition context. This syndrome information comprises of general purpose and system register values when the call was made. The SPM must save this syndrome information and use it to delegate the next event to the Secure Partition. The return parameters of this interface must specify the properties of the event and be populated in ``X0-X3/W0-W3`` registers. Secure Partition Memory Management ---------------------------------- A Secure Partition executes at S-EL0, which is an unprivileged Exception Level. The SPM is responsible for enabling access to regions of memory in the system address map from a Secure Partition. This is done by mapping these regions in the Secure EL1&0 Translation regime with appropriate memory attributes. Attributes refer to memory type, permission, cacheability and shareability attributes used in the Translation tables. The definitions of these attributes and their usage can be found in the `Armv8-A ARM`_ (*Arm DDI 0487*). All memory required by the Secure Partition is allocated upfront in the SPM, even before handing over to the Secure Partition for the first time. The initial access permissions of the memory regions are statically provided by the platform port and should allow the Secure Partition to run its initialisation code. However, they might not suit the final needs of the Secure Partition because its final memory layout might not be known until the Secure Partition initialises itself. As the Secure Partition initialises its runtime environment it might, for example, load dynamically some modules. For instance, a Secure Partition could implement a loader for a standard executable file format (e.g. an PE-COFF loader for loading executable files at runtime). These executable files will be a part of the Secure Partition image. The location of various sections in an executable file and their permission attributes (e.g. read-write data, read-only data and code) will be known only when the file is loaded into memory. In this case, the Secure Partition needs a way to change the access permissions of its memory regions. The SPM provides this feature through the ``SP_MEMORY_ATTRIBUTES_SET_AARCH64`` SVC interface. This interface is available to the Secure Partition during a specific time window: from the first entry into the Secure Partition up to the first ``SP_EVENT_COMPLETE`` call that signals the Secure Partition has finished its initialisation. Once the initialisation is complete, the SPM does not allow changes to the memory attributes. This section describes the standard SVC interface that is implemented by the SPM to determine and change permission attributes of memory regions that belong to a Secure Partition. ``SP_MEMORY_ATTRIBUTES_GET_AARCH64`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Description Request the permission attributes of a memory region from S-EL0. - Parameters - **uint32** Function ID - SVC64 Version: **0xC4000064** - **uint64** Base Address This parameter is a 64-bit Virtual Address (VA). There are no alignment restrictions on the Base Address. The permission attributes of the translation granule it lies in are returned. - Return parameters - **int32** - Memory Attributes/Return Code On success the format of the Return Code is as follows: - Bits[1:0] : Data access permission - b'00 : No access - b'01 : Read-Write access - b'10 : Reserved - b'11 : Read-only access - Bit[2]: Instruction access permission - b'0 : Executable - b'1 : Non-executable - Bit[30:3] : Reserved. SBZ. - Bit[31] : Must be 0 On failure the following error codes are returned: - ``INVALID_PARAMETERS``: The Secure Partition is not allowed to access the memory region the Base Address lies in. - ``NOT_SUPPORTED`` : The SPM does not support retrieval of attributes of any memory page that is accessible by the Secure Partition, or the function was called from the Non-secure world. Also returned if it is used after ``SP_EVENT_COMPLETE_AARCH64``. See `Error Codes`_ for integer values that are associated with each return code. - Usage This function is used to request the permission attributes for S-EL0 on a memory region accessible from a Secure Partition. The size of the memory region is equal to the Translation Granule size used in the Secure EL1&0 translation regime. Requests to retrieve other memory region attributes are not currently supported. - Caller responsibilities The caller must obtain the Translation Granule Size of the Secure EL1&0 translation regime from the SPM through an implementation defined method. - Callee responsibilities The SPM must not return the memory access controls for a page of memory that is not accessible from a Secure Partition. ``SP_MEMORY_ATTRIBUTES_SET_AARCH64`` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - Description Set the permission attributes of a memory region from S-EL0. - Parameters - **uint32** - Function ID - SVC64 Version: **0xC4000065** - **uint64** - Base Address This parameter is a 64-bit Virtual Address (VA). The alignment of the Base Address must be greater than or equal to the size of the Translation Granule Size used in the Secure EL1&0 translation regime. - **uint32** - Page count Number of pages starting from the Base Address whose memory attributes should be changed. The page size is equal to the Translation Granule Size. - **uint32** - Memory Access Controls - Bits[1:0] : Data access permission - b'00 : No access - b'01 : Read-Write access - b'10 : Reserved - b'11 : Read-only access - Bit[2] : Instruction access permission - b'0 : Executable - b'1 : Non-executable - Bits[31:3] : Reserved. SBZ. A combination of attributes that mark the region with RW and Executable permissions is prohibited. A request to mark a device memory region with Executable permissions is prohibited. - Return parameters - **int32** - Return Code - ``SUCCESS``: The Memory Access Controls were changed successfully. - ``DENIED``: The SPM is servicing a request to change the attributes of a memory region that overlaps with the region specified in this request. - ``INVALID_PARAMETER``: An invalid combination of Memory Access Controls has been specified. The Base Address is not correctly aligned. The Secure Partition is not allowed to access part or all of the memory region specified in the call. - ``NO_MEMORY``: The SPM does not have memory resources to change the attributes of the memory region in the translation tables. - ``NOT_SUPPORTED``: The SPM does not permit change of attributes of any memory region that is accessible by the Secure Partition. Function was called from the Non-secure world. Also returned if it is used after ``SP_EVENT_COMPLETE_AARCH64``. See `Error Codes`_ for integer values that are associated with each return code. - Usage This function is used to change the permission attributes for S-EL0 on a memory region accessible from a Secure Partition. The size of the memory region is equal to the Translation Granule size used in the Secure EL1&0 translation regime. Requests to change other memory region attributes are not currently supported. This function is only available at boot time. This interface is revoked after the Secure Partition sends the first ``SP_EVENT_COMPLETE_AARCH64`` to signal that it is initialised and ready to receive run-time requests. - Caller responsibilities The caller must obtain the Translation Granule Size of the Secure EL1&0 translation regime from the SPM through an implementation defined method. - Callee responsibilities The SPM must preserve the original memory access controls of the region of memory in case of an unsuccessful call.  The SPM must preserve the consistency of the S-EL1 translation regime if this function is called on different PEs concurrently and the memory regions specified overlap. Error Codes ----------- .. csv-table:: :header: "Name", "Value" ``SUCCESS``,0 ``NOT_SUPPORTED``,-1 ``INVALID_PARAMETER``,-2 ``DENIED``,-3 ``NO_MEMORY``,-5 ``NOT_PRESENT``,-7 -------------- *Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.* .. _Armv8-A ARM: https://developer.arm.com/docs/ddi0487/latest/arm-architecture-reference-manual-armv8-for-armv8-a-architecture-profile .. _instructions in the EDK2 repository: https://github.com/tianocore/edk2-staging/blob/AArch64StandaloneMm/HowtoBuild.MD .. _Management Mode Interface Specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0060a/DEN0060A_ARM_MM_Interface_Specification.pdf .. _SDEI Specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf .. _SMC Calling Convention: http://infocenter.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf .. |Image 1| image:: ../resources/diagrams/secure_sw_stack_tos.png .. |Image 2| image:: ../resources/diagrams/secure_sw_stack_sp.png trusted-firmware-a-2.2/docs/components/spd/000077500000000000000000000000001355360272700210145ustar00rootroot00000000000000trusted-firmware-a-2.2/docs/components/spd/index.rst000066400000000000000000000002601355360272700226530ustar00rootroot00000000000000Secure Payload Dispatcher (SPD) =============================== .. toctree:: :maxdepth: 1 :caption: Contents optee-dispatcher tlk-dispatcher trusty-dispatcher trusted-firmware-a-2.2/docs/components/spd/optee-dispatcher.rst000066400000000000000000000005521355360272700250100ustar00rootroot00000000000000OP-TEE Dispatcher ================= `OP-TEE OS`_ is a Trusted OS running as Secure EL1. To build and execute OP-TEE follow the instructions at `OP-TEE build.git`_ -------------- *Copyright (c) 2014-2018, Arm Limited and Contributors. All rights reserved.* .. _OP-TEE OS: https://github.com/OP-TEE/build .. _OP-TEE build.git: https://github.com/OP-TEE/build trusted-firmware-a-2.2/docs/components/spd/tlk-dispatcher.rst000066400000000000000000000053571355360272700244760ustar00rootroot00000000000000Trusted Little Kernel (TLK) Dispatcher ====================================== TLK dispatcher (TLK-D) adds support for NVIDIA's Trusted Little Kernel (TLK) to work with Trusted Firmware-A (TF-A). TLK-D can be compiled by including it in the platform's makefile. TLK is primarily meant to work with Tegra SoCs, so while TF-A only supports TLK on Tegra, the dispatcher code can only be compiled for other platforms. In order to compile TLK-D, we need a BL32 image to be present. Since, TLKD just needs to compile, any BL32 image would do. To use TLK as the BL32, please refer to the "Build TLK" section. Once a BL32 is ready, TLKD can be included in the image by adding "SPD=tlkd" to the build command. Trusted Little Kernel (TLK) --------------------------- TLK is a Trusted OS running as Secure EL1. It is a Free Open Source Software (FOSS) release of the NVIDIA® Trusted Little Kernel (TLK) technology, which extends technology made available with the development of the Little Kernel (LK). You can download the LK modular embedded preemptive kernel for use on Arm, x86, and AVR32 systems from https://github.com/travisg/lk NVIDIA implemented its Trusted Little Kernel (TLK) technology, designed as a free and open-source trusted execution environment (OTE). TLK features include: • Small, pre-emptive kernel • Supports multi-threading, IPCs, and thread scheduling • Added TrustZone features • Added Secure Storage • Under MIT/FreeBSD license NVIDIA extensions to Little Kernel (LK) include: • User mode • Address-space separation for TAs • TLK Client Application (CA) library • TLK TA library • Crypto library (encrypt/decrypt, key handling) via OpenSSL • Linux kernel driver • Cortex A9/A15 support • Power Management • TrustZone memory carve-out (reconfigurable) • Page table management • Debugging support over UART (USB planned) TLK is hosted by NVIDIA on http://nv-tegra.nvidia.com under the 3rdparty/ote\_partner/tlk.git repository. Detailed information about TLK and OTE can be found in the Tegra\_BSP\_for\_Android\_TLK\_FOSS\_Reference.pdf manual located under the "documentation" directory\_. Build TLK --------- To build and execute TLK, follow the instructions from "Building a TLK Device" section from Tegra\_BSP\_for\_Android\_TLK\_FOSS\_Reference.pdf manual. Input parameters to TLK ----------------------- TLK expects the TZDRAM size and a structure containing the boot arguments. BL2 passes this information to the EL3 software as members of the bl32\_ep\_info struct, where bl32\_ep\_info is part of bl31\_params\_t (passed by BL2 in X0) Example ~~~~~~~ :: bl32_ep_info->args.arg0 = TZDRAM size available for BL32 bl32_ep_info->args.arg1 = unused (used only on Armv7-A) bl32_ep_info->args.arg2 = pointer to boot args trusted-firmware-a-2.2/docs/components/spd/trusty-dispatcher.rst000066400000000000000000000021161355360272700252440ustar00rootroot00000000000000Trusty Dispatcher ================= Trusty is a a set of software components, supporting a Trusted Execution Environment (TEE) on mobile devices, published and maintained by Google. Detailed information and build instructions can be found on the Android Open Source Project (AOSP) webpage for Trusty hosted at https://source.android.com/security/trusty Boot parameters --------------- Custom boot parameters can be passed to Trusty by providing a platform specific function: .. code:: c void plat_trusty_set_boot_args(aapcs64_params_t *args) If this function is provided ``args->arg0`` must be set to the memory size allocated to trusty. If the platform does not provide this function, but defines ``TSP_SEC_MEM_SIZE``, a default implementation will pass the memory size from ``TSP_SEC_MEM_SIZE``. ``args->arg1`` can be set to a platform specific parameter block, and ``args->arg2`` should then be set to the size of that block. Supported platforms ------------------- Out of all the platforms supported by Trusted Firmware-A, Trusty is only verified and supported by NVIDIA's Tegra SoCs. trusted-firmware-a-2.2/docs/components/xlat-tables-lib-v2-design.rst000066400000000000000000000454301355360272700255460ustar00rootroot00000000000000Translation (XLAT) Tables Library ================================= This document describes the design of the translation tables library (version 2) used by Trusted Firmware-A (TF-A). This library provides APIs to create page tables based on a description of the memory layout, as well as setting up system registers related to the Memory Management Unit (MMU) and performing the required Translation Lookaside Buffer (TLB) maintenance operations. More specifically, some use cases that this library aims to support are: #. Statically allocate translation tables and populate them (at run-time) based on a description of the memory layout. The memory layout is typically provided by the platform port as a list of memory regions; #. Support for generating translation tables pertaining to a different translation regime than the exception level the library code is executing at; #. Support for dynamic mapping and unmapping of regions, even while the MMU is on. This can be used to temporarily map some memory regions and unmap them later on when no longer needed; #. Support for non-identity virtual to physical mappings to compress the virtual address space; #. Support for changing memory attributes of memory regions at run-time. About version 1 and version 2 ----------------------------- This document focuses on version 2 of the library, whose sources are available in the ``lib/xlat_tables_v2`` directory. Version 1 of the library can still be found in ``lib/xlat_tables`` directory but it is less flexible and doesn't support dynamic mapping. Although potential bug fixes will be applied to both versions, future features enhancements will focus on version 2 and might not be back-ported to version 1. Therefore, it is recommended to use version 2, especially for new platform ports. However, please note that version 2 is still in active development and is not considered stable yet. Hence, compatibility breaks might be introduced. From this point onwards, this document will implicitly refer to version 2 of the library. Design concepts and interfaces ------------------------------ This section presents some of the key concepts and data structures used in the translation tables library. `mmap` regions ~~~~~~~~~~~~~~ An ``mmap_region`` is an abstract, concise way to represent a memory region to map. It is one of the key interfaces to the library. It is identified by: - its physical base address; - its virtual base address; - its size; - its attributes; - its mapping granularity (optional). See the ``struct mmap_region`` type in ``xlat_tables_v2.h``. The user usually provides a list of such mmap regions to map and lets the library transpose that in a set of translation tables. As a result, the library might create new translation tables, update or split existing ones. The region attributes specify the type of memory (for example device or cached normal memory) as well as the memory access permissions (read-only or read-write, executable or not, secure or non-secure, and so on). In the case of the EL1&0 translation regime, the attributes also specify whether the region is a User region (EL0) or Privileged region (EL1). See the ``MT_xxx`` definitions in ``xlat_tables_v2.h``. Note that for the EL1&0 translation regime the Execute Never attribute is set simultaneously for both EL1 and EL0. The granularity controls the translation table level to go down to when mapping the region. For example, assuming the MMU has been configured to use a 4KB granule size, the library might map a 2MB memory region using either of the two following options: - using a single level-2 translation table entry; - using a level-2 intermediate entry to a level-3 translation table (which contains 512 entries, each mapping 4KB). The first solution potentially requires less translation tables, hence potentially less memory. However, if part of this 2MB region is later remapped with different memory attributes, the library might need to split the existing page tables to refine the mappings. If a single level-2 entry has been used here, a level-3 table will need to be allocated on the fly and the level-2 modified to point to this new level-3 table. This has a performance cost at run-time. If the user knows upfront that such a remapping operation is likely to happen then they might enforce a 4KB mapping granularity for this 2MB region from the beginning; remapping some of these 4KB pages on the fly then becomes a lightweight operation. The region's granularity is an optional field; if it is not specified the library will choose the mapping granularity for this region as it sees fit (more details can be found in `The memory mapping algorithm`_ section below). Translation Context ~~~~~~~~~~~~~~~~~~~ The library can create or modify translation tables pertaining to a different translation regime than the exception level the library code is executing at. For example, the library might be used by EL3 software (for instance BL31) to create translation tables pertaining to the S-EL1&0 translation regime. This flexibility comes from the use of *translation contexts*. A *translation context* constitutes the superset of information used by the library to track the status of a set of translation tables for a given translation regime. The library internally allocates a default translation context, which pertains to the translation regime of the current exception level. Additional contexts may be explicitly allocated and initialized using the ``REGISTER_XLAT_CONTEXT()`` macro. Separate APIs are provided to act either on the default translation context or on an alternative one. To register a translation context, the user must provide the library with the following information: * A name. The resulting translation context variable will be called after this name, to which ``_xlat_ctx`` is appended. For example, if the macro name parameter is ``foo``, the context variable name will be ``foo_xlat_ctx``. * The maximum number of `mmap` regions to map. Should account for both static and dynamic regions, if applicable. * The number of sub-translation tables to allocate. Number of translation tables to statically allocate for this context, excluding the initial lookup level translation table, which is always allocated. For example, if the initial lookup level is 1, this parameter would specify the number of level-2 and level-3 translation tables to pre-allocate for this context. * The size of the virtual address space. Size in bytes of the virtual address space to map using this context. This will incidentally determine the number of entries in the initial lookup level translation table : the library will allocate as many entries as is required to map the entire virtual address space. * The size of the physical address space. Size in bytes of the physical address space to map using this context. The default translation context is internally initialized using information coming (for the most part) from platform-specific defines: - name: hard-coded to ``tf`` ; hence the name of the default context variable is ``tf_xlat_ctx``; - number of `mmap` regions: ``MAX_MMAP_REGIONS``; - number of sub-translation tables: ``MAX_XLAT_TABLES``; - size of the virtual address space: ``PLAT_VIRT_ADDR_SPACE_SIZE``; - size of the physical address space: ``PLAT_PHY_ADDR_SPACE_SIZE``. Please refer to the :ref:`Porting Guide` for more details about these macros. Static and dynamic memory regions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The library optionally supports dynamic memory mapping. This feature may be enabled using the ``PLAT_XLAT_TABLES_DYNAMIC`` platform build flag. When dynamic memory mapping is enabled, the library categorises mmap regions as *static* or *dynamic*. - *Static regions* are fixed for the lifetime of the system. They can only be added early on, before the translation tables are created and populated. They cannot be removed afterwards. - *Dynamic regions* can be added or removed any time. When the dynamic memory mapping feature is disabled, only static regions exist. The dynamic memory mapping feature may be used to map and unmap transient memory areas. This is useful when the user needs to access some memory for a fixed period of time, after which the memory may be discarded and reclaimed. For example, a memory region that is only required at boot time while the system is initializing, or to temporarily share a memory buffer between the normal world and trusted world. Note that it is up to the caller to ensure that these regions are not accessed concurrently while the regions are being added or removed. Although this feature provides some level of dynamic memory allocation, this does not allow dynamically allocating an arbitrary amount of memory at an arbitrary memory location. The user is still required to declare at compile-time the limits of these allocations ; the library will deny any mapping request that does not fit within this pre-allocated pool of memory. Library APIs ------------ The external APIs exposed by this library are declared and documented in the ``xlat_tables_v2.h`` header file. This should be the reference point for getting information about the usage of the different APIs this library provides. This section just provides some extra details and clarifications. Although the ``mmap_region`` structure is a publicly visible type, it is not recommended to populate these structures by hand. Instead, wherever APIs expect function arguments of type ``mmap_region_t``, these should be constructed using the ``MAP_REGION*()`` family of helper macros. This is to limit the risk of compatibility breaks, should the ``mmap_region`` structure type evolve in the future. The ``MAP_REGION()`` and ``MAP_REGION_FLAT()`` macros do not allow specifying a mapping granularity, which leaves the library implementation free to choose it. However, in cases where a specific granularity is required, the ``MAP_REGION2()`` macro might be used instead. As explained earlier in this document, when the dynamic mapping feature is disabled, there is no notion of dynamic regions. Conceptually, there are only static regions. For this reason (and to retain backward compatibility with the version 1 of the library), the APIs that map static regions do not embed the word *static* in their functions names (for example ``mmap_add_region()``), in contrast with the dynamic regions APIs (for example ``mmap_add_dynamic_region()``). Although the definition of static and dynamic regions is not based on the state of the MMU, the two are still related in some way. Static regions can only be added before ``init_xlat_tables()`` is called and ``init_xlat_tables()`` must be called while the MMU is still off. As a result, static regions cannot be added once the MMU has been enabled. Dynamic regions can be added with the MMU on or off. In practice, the usual call flow would look like this: #. The MMU is initially off. #. Add some static regions, add some dynamic regions. #. Initialize translation tables based on the list of mmap regions (using one of the ``init_xlat_tables*()`` APIs). #. At this point, it is no longer possible to add static regions. Dynamic regions can still be added or removed. #. Enable the MMU. #. Dynamic regions can continue to be added or removed. Because static regions are added early on at boot time and are all in the control of the platform initialization code, the ``mmap_add*()`` family of APIs are not expected to fail. They do not return any error code. Nonetheless, these APIs will check upfront whether the region can be successfully added before updating the translation context structure. If the library detects that there is insufficient memory to meet the request, or that the new region will overlap another one in an invalid way, or if any other unexpected error is encountered, they will print an error message on the UART. Additionally, when asserts are enabled (typically in debug builds), an assertion will be triggered. Otherwise, the function call will just return straight away, without adding the offending memory region. Library limitations ------------------- Dynamic regions are not allowed to overlap each other. Static regions are allowed to overlap as long as one of them is fully contained inside the other one. This is allowed for backwards compatibility with the previous behaviour in the version 1 of the library. Implementation details ---------------------- Code structure ~~~~~~~~~~~~~~ The library is divided into 4 modules: - **Core module** Provides the main functionality of the library, such as the initialization of translation tables contexts and mapping/unmapping memory regions. This module provides functions such as ``mmap_add_region_ctx`` that let the caller specify the translation tables context affected by them. See ``xlat_tables_core.c``. - **Active context module** Instantiates the context that is used by the current BL image and provides helpers to manipulate it, abstracting it from the rest of the code. This module provides functions such as ``mmap_add_region``, that directly affect the BL image using them. See ``xlat_tables_context.c``. - **Utilities module** Provides additional functionality like debug print of the current state of the translation tables and helpers to query memory attributes and to modify them. See ``xlat_tables_utils.c``. - **Architectural module** Provides functions that are dependent on the current execution state (AArch32/AArch64), such as the functions used for TLB invalidation, setup the MMU, or calculate the Physical Address Space size. They do not need a translation context to work on. See ``aarch32/xlat_tables_arch.c`` and ``aarch64/xlat_tables_arch.c``. From mmap regions to translation tables ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A translation context contains a list of ``mmap_region_t``, which holds the information of all the regions that are mapped at any given time. Whenever there is a request to map (resp. unmap) a memory region, it is added to (resp. removed from) the ``mmap_region_t`` list. The mmap regions list is a conceptual way to represent the memory layout. At some point, the library has to convert this information into actual translation tables to program into the MMU. Before the ``init_xlat_tables()`` API is called, the library only acts on the mmap regions list. Adding a static or dynamic region at this point through one of the ``mmap_add*()`` APIs does not affect the translation tables in any way, they only get registered in the internal mmap region list. It is only when the user calls the ``init_xlat_tables()`` that the translation tables are populated in memory based on the list of mmap regions registered so far. This is an optimization that allows creation of the initial set of translation tables in one go, rather than having to edit them every time while the MMU is disabled. After the ``init_xlat_tables()`` API has been called, only dynamic regions can be added. Changes to the translation tables (as well as the mmap regions list) will take effect immediately. The memory mapping algorithm ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The mapping function is implemented as a recursive algorithm. It is however bound by the level of depth of the translation tables (the Armv8-A architecture allows up to 4 lookup levels). By default [#granularity]_, the algorithm will attempt to minimize the number of translation tables created to satisfy the user's request. It will favour mapping a region using the biggest possible blocks, only creating a sub-table if it is strictly necessary. This is to reduce the memory footprint of the firmware. The most common reason for needing a sub-table is when a specific mapping requires a finer granularity. Misaligned regions also require a finer granularity than what the user may had originally expected, using a lot more memory than expected. The reason is that all levels of translation are restricted to address translations of the same granularity as the size of the blocks of that level. For example, for a 4 KiB page size, a level 2 block entry can only translate up to a granularity of 2 MiB. If the Physical Address is not aligned to 2 MiB then additional level 3 tables are also needed. Note that not every translation level allows any type of descriptor. Depending on the page size, levels 0 and 1 of translation may only allow table descriptors. If a block entry could be able to describe a translation, but that level does not allow block descriptors, a table descriptor will have to be used instead, as well as additional tables at the next level. |Alignment Example| The mmap regions are sorted in a way that simplifies the code that maps them. Even though this ordering is only strictly needed for overlapping static regions, it must also be applied for dynamic regions to maintain a consistent order of all regions at all times. As each new region is mapped, existing entries in the translation tables are checked to ensure consistency. Please refer to the comments in the source code of the core module for more details about the sorting algorithm in use. TLB maintenance operations ~~~~~~~~~~~~~~~~~~~~~~~~~~ The library takes care of performing TLB maintenance operations when required. For example, when the user requests removing a dynamic region, the library invalidates all TLB entries associated to that region to ensure that these changes are visible to subsequent execution, including speculative execution, that uses the changed translation table entries. A counter-example is the initialization of translation tables. In this case, explicit TLB maintenance is not required. The Armv8-A architecture guarantees that all TLBs are disabled from reset and their contents have no effect on address translation at reset [#tlb-reset-ref]_. Therefore, the TLBs invalidation is deferred to the ``enable_mmu*()`` family of functions, just before the MMU is turned on. TLB invalidation is not required when adding dynamic regions either. Dynamic regions are not allowed to overlap existing memory region. Therefore, if the dynamic mapping request is deemed legitimate, it automatically concerns memory that was not mapped in this translation regime and the library will have initialized its corresponding translation table entry to an invalid descriptor. Given that the TLBs are not architecturally permitted to hold any invalid translation table entry [#tlb-no-invalid-entry]_, this means that this mapping cannot be cached in the TLBs. .. rubric:: Footnotes .. [#granularity] That is, when mmap regions do not enforce their mapping granularity. .. [#tlb-reset-ref] See section D4.9 ``Translation Lookaside Buffers (TLBs)``, subsection ``TLB behavior at reset`` in Armv8-A, rev C.a. .. [#tlb-no-invalid-entry] See section D4.10.1 ``General TLB maintenance requirements`` in Armv8-A, rev C.a. -------------- *Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.* .. |Alignment Example| image:: ../resources/diagrams/xlat_align.png trusted-firmware-a-2.2/docs/conf.py000066400000000000000000000054501355360272700173440ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # Copyright (c) 2019, Arm Limited. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # # Configuration file for the Sphinx documentation builder. # # See the options documentation at http://www.sphinx-doc.org/en/master/config import os # -- Project information ----------------------------------------------------- project = 'Trusted Firmware-A' # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = ['sphinx.ext.autosectionlabel', 'sphinxcontrib.plantuml'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix(es) of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. language = None # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path . exclude_patterns = [] # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # Load the contents of the global substitutions file into the 'rst_prolog' # variable. This ensures that the substitutions are all inserted into each page. with open('global_substitutions.txt', 'r') as subs: rst_prolog = subs.read() # Minimum version of sphinx required needs_sphinx = '2.0' # -- Options for HTML output ------------------------------------------------- # Don't show the "Built with Sphinx" footer html_show_sphinx = False # Don't show copyright info in the footer (we have this content in the page) html_show_copyright = False # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = "sphinx_rtd_theme" # The logo to display in the sidebar html_logo = 'resources/TrustedFirmware-Logo_standard-white.png' # Options for the "sphinx-rtd-theme" theme html_theme_options = { 'collapse_navigation': False, # Can expand and collapse sidebar entries 'prev_next_buttons_location': 'both', # Top and bottom of the page 'style_external_links': True # Display an icon next to external links } # -- Options for autosectionlabel -------------------------------------------- # Only generate automatic section labels for document titles autosectionlabel_maxdepth = 1 # -- Options for plantuml ---------------------------------------------------- plantuml_output_format = 'svg_img' trusted-firmware-a-2.2/docs/design/000077500000000000000000000000001355360272700173125ustar00rootroot00000000000000trusted-firmware-a-2.2/docs/design/auth-framework.rst000066400000000000000000001176161355360272700230140ustar00rootroot00000000000000Authentication Framework & Chain of Trust ========================================= The aim of this document is to describe the authentication framework implemented in Trusted Firmware-A (TF-A). This framework fulfills the following requirements: #. It should be possible for a platform port to specify the Chain of Trust in terms of certificate hierarchy and the mechanisms used to verify a particular image/certificate. #. The framework should distinguish between: - The mechanism used to encode and transport information, e.g. DER encoded X.509v3 certificates to ferry Subject Public Keys, hashes and non-volatile counters. - The mechanism used to verify the transported information i.e. the cryptographic libraries. The framework has been designed following a modular approach illustrated in the next diagram: :: +---------------+---------------+------------+ | Trusted | Trusted | Trusted | | Firmware | Firmware | Firmware | | Generic | IO Framework | Platform | | Code i.e. | (IO) | Port | | BL1/BL2 (GEN) | | (PP) | +---------------+---------------+------------+ ^ ^ ^ | | | v v v +-----------+ +-----------+ +-----------+ | | | | | Image | | Crypto | | Auth | | Parser | | Module |<->| Module |<->| Module | | (CM) | | (AM) | | (IPM) | | | | | | | +-----------+ +-----------+ +-----------+ ^ ^ | | v v +----------------+ +-----------------+ | Cryptographic | | Image Parser | | Libraries (CL) | | Libraries (IPL) | +----------------+ +-----------------+ | | | | | | v v +-----------------+ | Misc. Libs e.g. | | ASN.1 decoder | | | +-----------------+ DIAGRAM 1. This document describes the inner details of the authentication framework and the abstraction mechanisms available to specify a Chain of Trust. Framework design ---------------- This section describes some aspects of the framework design and the rationale behind them. These aspects are key to verify a Chain of Trust. Chain of Trust ~~~~~~~~~~~~~~ A CoT is basically a sequence of authentication images which usually starts with a root of trust and culminates in a single data image. The following diagram illustrates how this maps to a CoT for the BL31 image described in the `TBBR-Client specification`_. :: +------------------+ +-------------------+ | ROTPK/ROTPK Hash |------>| Trusted Key | +------------------+ | Certificate | | (Auth Image) | /+-------------------+ / | / | / | / | L v +------------------+ +-------------------+ | Trusted World |------>| BL31 Key | | Public Key | | Certificate | +------------------+ | (Auth Image) | +-------------------+ / | / | / | / | / v +------------------+ L +-------------------+ | BL31 Content |------>| BL31 Content | | Certificate PK | | Certificate | +------------------+ | (Auth Image) | +-------------------+ / | / | / | / | / v +------------------+ L +-------------------+ | BL31 Hash |------>| BL31 Image | | | | (Data Image) | +------------------+ | | +-------------------+ DIAGRAM 2. The root of trust is usually a public key (ROTPK) that has been burnt in the platform and cannot be modified. Image types ~~~~~~~~~~~ Images in a CoT are categorised as authentication and data images. An authentication image contains information to authenticate a data image or another authentication image. A data image is usually a boot loader binary, but it could be any other data that requires authentication. Component responsibilities ~~~~~~~~~~~~~~~~~~~~~~~~~~ For every image in a Chain of Trust, the following high level operations are performed to verify it: #. Allocate memory for the image either statically or at runtime. #. Identify the image and load it in the allocated memory. #. Check the integrity of the image as per its type. #. Authenticate the image as per the cryptographic algorithms used. #. If the image is an authentication image, extract the information that will be used to authenticate the next image in the CoT. In Diagram 1, each component is responsible for one or more of these operations. The responsibilities are briefly described below. TF-A Generic code and IO framework (GEN/IO) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ These components are responsible for initiating the authentication process for a particular image in BL1 or BL2. For each BL image that requires authentication, the Generic code asks recursively the Authentication module what is the parent image until either an authenticated image or the ROT is reached. Then the Generic code calls the IO framework to load the image and calls the Authentication module to authenticate it, following the CoT from ROT to Image. TF-A Platform Port (PP) ^^^^^^^^^^^^^^^^^^^^^^^ The platform is responsible for: #. Specifying the CoT for each image that needs to be authenticated. Details of how a CoT can be specified by the platform are explained later. The platform also specifies the authentication methods and the parsing method used for each image. #. Statically allocating memory for each parameter in each image which is used for verifying the CoT, e.g. memory for public keys, hashes etc. #. Providing the ROTPK or a hash of it. #. Providing additional information to the IPM to enable it to identify and extract authentication parameters contained in an image, e.g. if the parameters are stored as X509v3 extensions, the corresponding OID must be provided. #. Fulfill any other memory requirements of the IPM and the CM (not currently described in this document). #. Export functions to verify an image which uses an authentication method that cannot be interpreted by the CM, e.g. if an image has to be verified using a NV counter, then the value of the counter to compare with can only be provided by the platform. #. Export a custom IPM if a proprietary image format is being used (described later). Authentication Module (AM) ^^^^^^^^^^^^^^^^^^^^^^^^^^ It is responsible for: #. Providing the necessary abstraction mechanisms to describe a CoT. Amongst other things, the authentication and image parsing methods must be specified by the PP in the CoT. #. Verifying the CoT passed by GEN by utilising functionality exported by the PP, IPM and CM. #. Tracking which images have been verified. In case an image is a part of multiple CoTs then it should be verified only once e.g. the Trusted World Key Certificate in the TBBR-Client spec. contains information to verify SCP_BL2, BL31, BL32 each of which have a separate CoT. (This responsibility has not been described in this document but should be trivial to implement). #. Reusing memory meant for a data image to verify authentication images e.g. in the CoT described in Diagram 2, each certificate can be loaded and verified in the memory reserved by the platform for the BL31 image. By the time BL31 (the data image) is loaded, all information to authenticate it will have been extracted from the parent image i.e. BL31 content certificate. It is assumed that the size of an authentication image will never exceed the size of a data image. It should be possible to verify this at build time using asserts. Cryptographic Module (CM) ^^^^^^^^^^^^^^^^^^^^^^^^^ The CM is responsible for providing an API to: #. Verify a digital signature. #. Verify a hash. The CM does not include any cryptography related code, but it relies on an external library to perform the cryptographic operations. A Crypto-Library (CL) linking the CM and the external library must be implemented. The following functions must be provided by the CL: .. code:: c void (*init)(void); int (*verify_signature)(void *data_ptr, unsigned int data_len, void *sig_ptr, unsigned int sig_len, void *sig_alg, unsigned int sig_alg_len, void *pk_ptr, unsigned int pk_len); int (*verify_hash)(void *data_ptr, unsigned int data_len, void *digest_info_ptr, unsigned int digest_info_len); These functions are registered in the CM using the macro: .. code:: c REGISTER_CRYPTO_LIB(_name, _init, _verify_signature, _verify_hash); ``_name`` must be a string containing the name of the CL. This name is used for debugging purposes. Image Parser Module (IPM) ^^^^^^^^^^^^^^^^^^^^^^^^^ The IPM is responsible for: #. Checking the integrity of each image loaded by the IO framework. #. Extracting parameters used for authenticating an image based upon a description provided by the platform in the CoT descriptor. Images may have different formats (for example, authentication images could be x509v3 certificates, signed ELF files or any other platform specific format). The IPM allows to register an Image Parser Library (IPL) for every image format used in the CoT. This library must implement the specific methods to parse the image. The IPM obtains the image format from the CoT and calls the right IPL to check the image integrity and extract the authentication parameters. See Section "Describing the image parsing methods" for more details about the mechanism the IPM provides to define and register IPLs. Authentication methods ~~~~~~~~~~~~~~~~~~~~~~ The AM supports the following authentication methods: #. Hash #. Digital signature The platform may specify these methods in the CoT in case it decides to define a custom CoT instead of reusing a predefined one. If a data image uses multiple methods, then all the methods must be a part of the same CoT. The number and type of parameters are method specific. These parameters should be obtained from the parent image using the IPM. #. Hash Parameters: #. A pointer to data to hash #. Length of the data #. A pointer to the hash #. Length of the hash The hash will be represented by the DER encoding of the following ASN.1 type: :: DigestInfo ::= SEQUENCE { digestAlgorithm DigestAlgorithmIdentifier, digest Digest } This ASN.1 structure makes it possible to remove any assumption about the type of hash algorithm used as this information accompanies the hash. This should allow the Cryptography Library (CL) to support multiple hash algorithm implementations. #. Digital Signature Parameters: #. A pointer to data to sign #. Length of the data #. Public Key Algorithm #. Public Key value #. Digital Signature Algorithm #. Digital Signature value The Public Key parameters will be represented by the DER encoding of the following ASN.1 type: :: SubjectPublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier{PUBLIC-KEY,{PublicKeyAlgorithms}}, subjectPublicKey BIT STRING } The Digital Signature Algorithm will be represented by the DER encoding of the following ASN.1 types. :: AlgorithmIdentifier {ALGORITHM:IOSet } ::= SEQUENCE { algorithm ALGORITHM.&id({IOSet}), parameters ALGORITHM.&Type({IOSet}{@algorithm}) OPTIONAL } The digital signature will be represented by: :: signature ::= BIT STRING The authentication framework will use the image descriptor to extract all the information related to authentication. Specifying a Chain of Trust --------------------------- A CoT can be described as a set of image descriptors linked together in a particular order. The order dictates the sequence in which they must be verified. Each image has a set of properties which allow the AM to verify it. These properties are described below. The PP is responsible for defining a single or multiple CoTs for a data image. Unless otherwise specified, the data structures described in the following sections are populated by the PP statically. Describing the image parsing methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The parsing method refers to the format of a particular image. For example, an authentication image that represents a certificate could be in the X.509v3 format. A data image that represents a boot loader stage could be in raw binary or ELF format. The IPM supports three parsing methods. An image has to use one of the three methods described below. An IPL is responsible for interpreting a single parsing method. There has to be one IPL for every method used by the platform. #. Raw format: This format is effectively a nop as an image using this method is treated as being in raw binary format e.g. boot loader images used by TF-A. This method should only be used by data images. #. X509V3 method: This method uses industry standards like X.509 to represent PKI certificates (authentication images). It is expected that open source libraries will be available which can be used to parse an image represented by this method. Such libraries can be used to write the corresponding IPL e.g. the X.509 parsing library code in mbed TLS. #. Platform defined method: This method caters for platform specific proprietary standards to represent authentication or data images. For example, The signature of a data image could be appended to the data image raw binary. A header could be prepended to the combined blob to specify the extents of each component. The platform will have to implement the corresponding IPL to interpret such a format. The following enum can be used to define these three methods. .. code:: c typedef enum img_type_enum { IMG_RAW, /* Binary image */ IMG_PLAT, /* Platform specific format */ IMG_CERT, /* X509v3 certificate */ IMG_MAX_TYPES, } img_type_t; An IPL must provide functions with the following prototypes: .. code:: c void init(void); int check_integrity(void *img, unsigned int img_len); int get_auth_param(const auth_param_type_desc_t *type_desc, void *img, unsigned int img_len, void **param, unsigned int *param_len); An IPL for each type must be registered using the following macro: .. code:: c REGISTER_IMG_PARSER_LIB(_type, _name, _init, _check_int, _get_param) - ``_type``: one of the types described above. - ``_name``: a string containing the IPL name for debugging purposes. - ``_init``: initialization function pointer. - ``_check_int``: check image integrity function pointer. - ``_get_param``: extract authentication parameter function pointer. The ``init()`` function will be used to initialize the IPL. The ``check_integrity()`` function is passed a pointer to the memory where the image has been loaded by the IO framework and the image length. It should ensure that the image is in the format corresponding to the parsing method and has not been tampered with. For example, RFC-2459 describes a validation sequence for an X.509 certificate. The ``get_auth_param()`` function is passed a parameter descriptor containing information about the parameter (``type_desc`` and ``cookie``) to identify and extract the data corresponding to that parameter from an image. This data will be used to verify either the current or the next image in the CoT sequence. Each image in the CoT will specify the parsing method it uses. This information will be used by the IPM to find the right parser descriptor for the image. Describing the authentication method(s) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ As part of the CoT, each image has to specify one or more authentication methods which will be used to verify it. As described in the Section "Authentication methods", there are three methods supported by the AM. .. code:: c typedef enum { AUTH_METHOD_NONE, AUTH_METHOD_HASH, AUTH_METHOD_SIG, AUTH_METHOD_NUM } auth_method_type_t; The AM defines the type of each parameter used by an authentication method. It uses this information to: #. Specify to the ``get_auth_param()`` function exported by the IPM, which parameter should be extracted from an image. #. Correctly marshall the parameters while calling the verification function exported by the CM and PP. #. Extract authentication parameters from a parent image in order to verify a child image e.g. to verify the certificate image, the public key has to be obtained from the parent image. .. code:: c typedef enum { AUTH_PARAM_NONE, AUTH_PARAM_RAW_DATA, /* Raw image data */ AUTH_PARAM_SIG, /* The image signature */ AUTH_PARAM_SIG_ALG, /* The image signature algorithm */ AUTH_PARAM_HASH, /* A hash (including the algorithm) */ AUTH_PARAM_PUB_KEY, /* A public key */ } auth_param_type_t; The AM defines the following structure to identify an authentication parameter required to verify an image. .. code:: c typedef struct auth_param_type_desc_s { auth_param_type_t type; void *cookie; } auth_param_type_desc_t; ``cookie`` is used by the platform to specify additional information to the IPM which enables it to uniquely identify the parameter that should be extracted from an image. For example, the hash of a BL3x image in its corresponding content certificate is stored in an X509v3 custom extension field. An extension field can only be identified using an OID. In this case, the ``cookie`` could contain the pointer to the OID defined by the platform for the hash extension field while the ``type`` field could be set to ``AUTH_PARAM_HASH``. A value of 0 for the ``cookie`` field means that it is not used. For each method, the AM defines a structure with the parameters required to verify the image. .. code:: c /* * Parameters for authentication by hash matching */ typedef struct auth_method_param_hash_s { auth_param_type_desc_t *data; /* Data to hash */ auth_param_type_desc_t *hash; /* Hash to match with */ } auth_method_param_hash_t; /* * Parameters for authentication by signature */ typedef struct auth_method_param_sig_s { auth_param_type_desc_t *pk; /* Public key */ auth_param_type_desc_t *sig; /* Signature to check */ auth_param_type_desc_t *alg; /* Signature algorithm */ auth_param_type_desc_t *tbs; /* Data signed */ } auth_method_param_sig_t; The AM defines the following structure to describe an authentication method for verifying an image .. code:: c /* * Authentication method descriptor */ typedef struct auth_method_desc_s { auth_method_type_t type; union { auth_method_param_hash_t hash; auth_method_param_sig_t sig; } param; } auth_method_desc_t; Using the method type specified in the ``type`` field, the AM finds out what field needs to access within the ``param`` union. Storing Authentication parameters ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A parameter described by ``auth_param_type_desc_t`` to verify an image could be obtained from either the image itself or its parent image. The memory allocated for loading the parent image will be reused for loading the child image. Hence parameters which are obtained from the parent for verifying a child image need to have memory allocated for them separately where they can be stored. This memory must be statically allocated by the platform port. The AM defines the following structure to store the data corresponding to an authentication parameter. .. code:: c typedef struct auth_param_data_desc_s { void *auth_param_ptr; unsigned int auth_param_len; } auth_param_data_desc_t; The ``auth_param_ptr`` field is initialized by the platform. The ``auth_param_len`` field is used to specify the length of the data in the memory. For parameters that can be obtained from the child image itself, the IPM is responsible for populating the ``auth_param_ptr`` and ``auth_param_len`` fields while executing the ``img_get_auth_param()`` function. The AM defines the following structure to enable an image to describe the parameters that should be extracted from it and used to verify the next image (child) in a CoT. .. code:: c typedef struct auth_param_desc_s { auth_param_type_desc_t type_desc; auth_param_data_desc_t data; } auth_param_desc_t; Describing an image in a CoT ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ An image in a CoT is a consolidation of the following aspects of a CoT described above. #. A unique identifier specified by the platform which allows the IO framework to locate the image in a FIP and load it in the memory reserved for the data image in the CoT. #. A parsing method which is used by the AM to find the appropriate IPM. #. Authentication methods and their parameters as described in the previous section. These are used to verify the current image. #. Parameters which are used to verify the next image in the current CoT. These parameters are specified only by authentication images and can be extracted from the current image once it has been verified. The following data structure describes an image in a CoT. .. code:: c typedef struct auth_img_desc_s { unsigned int img_id; const struct auth_img_desc_s *parent; img_type_t img_type; const auth_method_desc_t *const img_auth_methods; const auth_param_desc_t *const authenticated_data; } auth_img_desc_t; A CoT is defined as an array of pointers to ``auth_image_desc_t`` structures linked together by the ``parent`` field. Those nodes with no parent must be authenticated using the ROTPK stored in the platform. Implementation example ---------------------- This section is a detailed guide explaining a trusted boot implementation using the authentication framework. This example corresponds to the Applicative Functional Mode (AFM) as specified in the TBBR-Client document. It is recommended to read this guide along with the source code. The TBBR CoT ~~~~~~~~~~~~ The CoT can be found in ``drivers/auth/tbbr/tbbr_cot.c``. This CoT consists of an array of pointers to image descriptors and it is registered in the framework using the macro ``REGISTER_COT(cot_desc)``, where 'cot_desc' must be the name of the array (passing a pointer or any other type of indirection will cause the registration process to fail). The number of images participating in the boot process depends on the CoT. There is, however, a minimum set of images that are mandatory in TF-A and thus all CoTs must present: - ``BL2`` - ``SCP_BL2`` (platform specific) - ``BL31`` - ``BL32`` (optional) - ``BL33`` The TBBR specifies the additional certificates that must accompany these images for a proper authentication. Details about the TBBR CoT may be found in the :ref:`Trusted Board Boot` document. Following the :ref:`Porting Guide`, a platform must provide unique identifiers for all the images and certificates that will be loaded during the boot process. If a platform is using the TBBR as a reference for trusted boot, these identifiers can be obtained from ``include/common/tbbr/tbbr_img_def.h``. Arm platforms include this file in ``include/plat/arm/common/arm_def.h``. Other platforms may also include this file or provide their own identifiers. **Important**: the authentication module uses these identifiers to index the CoT array, so the descriptors location in the array must match the identifiers. Each image descriptor must specify: - ``img_id``: the corresponding image unique identifier defined by the platform. - ``img_type``: the image parser module uses the image type to call the proper parsing library to check the image integrity and extract the required authentication parameters. Three types of images are currently supported: - ``IMG_RAW``: image is a raw binary. No parsing functions are available, other than reading the whole image. - ``IMG_PLAT``: image format is platform specific. The platform may use this type for custom images not directly supported by the authentication framework. - ``IMG_CERT``: image is an x509v3 certificate. - ``parent``: pointer to the parent image descriptor. The parent will contain the information required to authenticate the current image. If the parent is NULL, the authentication parameters will be obtained from the platform (i.e. the BL2 and Trusted Key certificates are signed with the ROT private key, whose public part is stored in the platform). - ``img_auth_methods``: this points to an array which defines the authentication methods that must be checked to consider an image authenticated. Each method consists of a type and a list of parameter descriptors. A parameter descriptor consists of a type and a cookie which will point to specific information required to extract that parameter from the image (i.e. if the parameter is stored in an x509v3 extension, the cookie will point to the extension OID). Depending on the method type, a different number of parameters must be specified. This pointer should not be NULL. Supported methods are: - ``AUTH_METHOD_HASH``: the hash of the image must match the hash extracted from the parent image. The following parameter descriptors must be specified: - ``data``: data to be hashed (obtained from current image) - ``hash``: reference hash (obtained from parent image) - ``AUTH_METHOD_SIG``: the image (usually a certificate) must be signed with the private key whose public part is extracted from the parent image (or the platform if the parent is NULL). The following parameter descriptors must be specified: - ``pk``: the public key (obtained from parent image) - ``sig``: the digital signature (obtained from current image) - ``alg``: the signature algorithm used (obtained from current image) - ``data``: the data to be signed (obtained from current image) - ``authenticated_data``: this array pointer indicates what authentication parameters must be extracted from an image once it has been authenticated. Each parameter consists of a parameter descriptor and the buffer address/size to store the parameter. The CoT is responsible for allocating the required memory to store the parameters. This pointer may be NULL. In the ``tbbr_cot.c`` file, a set of buffers are allocated to store the parameters extracted from the certificates. In the case of the TBBR CoT, these parameters are hashes and public keys. In DER format, an RSA-4096 public key requires 550 bytes, and a hash requires 51 bytes. Depending on the CoT and the authentication process, some of the buffers may be reused at different stages during the boot. Next in that file, the parameter descriptors are defined. These descriptors will be used to extract the parameter data from the corresponding image. Example: the BL31 Chain of Trust ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Four image descriptors form the BL31 Chain of Trust: .. code:: c static const auth_img_desc_t trusted_key_cert = { .img_id = TRUSTED_KEY_CERT_ID, .img_type = IMG_CERT, .parent = NULL, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &subject_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &trusted_nv_ctr, .plat_nv_ctr = &trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &trusted_world_pk, .data = { .ptr = (void *)trusted_world_pk_buf, .len = (unsigned int)PK_DER_LEN } }, [1] = { .type_desc = &non_trusted_world_pk, .data = { .ptr = (void *)non_trusted_world_pk_buf, .len = (unsigned int)PK_DER_LEN } } } }; static const auth_img_desc_t soc_fw_key_cert = { .img_id = SOC_FW_KEY_CERT_ID, .img_type = IMG_CERT, .parent = &trusted_key_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &trusted_world_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &trusted_nv_ctr, .plat_nv_ctr = &trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &soc_fw_content_pk, .data = { .ptr = (void *)content_pk_buf, .len = (unsigned int)PK_DER_LEN } } } }; static const auth_img_desc_t soc_fw_content_cert = { .img_id = SOC_FW_CONTENT_CERT_ID, .img_type = IMG_CERT, .parent = &soc_fw_key_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &soc_fw_content_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &trusted_nv_ctr, .plat_nv_ctr = &trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &soc_fw_hash, .data = { .ptr = (void *)soc_fw_hash_buf, .len = (unsigned int)HASH_DER_LEN } }, [1] = { .type_desc = &soc_fw_config_hash, .data = { .ptr = (void *)soc_fw_config_hash_buf, .len = (unsigned int)HASH_DER_LEN } } } }; static const auth_img_desc_t bl31_image = { .img_id = BL31_IMAGE_ID, .img_type = IMG_RAW, .parent = &soc_fw_content_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &soc_fw_hash } } } }; The **Trusted Key certificate** is signed with the ROT private key and contains the Trusted World public key and the Non-Trusted World public key as x509v3 extensions. This must be specified in the image descriptor using the ``img_auth_methods`` and ``authenticated_data`` arrays, respectively. The Trusted Key certificate is authenticated by checking its digital signature using the ROTPK. Four parameters are required to check a signature: the public key, the algorithm, the signature and the data that has been signed. Therefore, four parameter descriptors must be specified with the authentication method: - ``subject_pk``: parameter descriptor of type ``AUTH_PARAM_PUB_KEY``. This type is used to extract a public key from the parent image. If the cookie is an OID, the key is extracted from the corresponding x509v3 extension. If the cookie is NULL, the subject public key is retrieved. In this case, because the parent image is NULL, the public key is obtained from the platform (this key will be the ROTPK). - ``sig``: parameter descriptor of type ``AUTH_PARAM_SIG``. It is used to extract the signature from the certificate. - ``sig_alg``: parameter descriptor of type ``AUTH_PARAM_SIG``. It is used to extract the signature algorithm from the certificate. - ``raw_data``: parameter descriptor of type ``AUTH_PARAM_RAW_DATA``. It is used to extract the data to be signed from the certificate. Once the signature has been checked and the certificate authenticated, the Trusted World public key needs to be extracted from the certificate. A new entry is created in the ``authenticated_data`` array for that purpose. In that entry, the corresponding parameter descriptor must be specified along with the buffer address to store the parameter value. In this case, the ``tz_world_pk`` descriptor is used to extract the public key from an x509v3 extension with OID ``TRUSTED_WORLD_PK_OID``. The BL31 key certificate will use this descriptor as parameter in the signature authentication method. The key is stored in the ``plat_tz_world_pk_buf`` buffer. The **BL31 Key certificate** is authenticated by checking its digital signature using the Trusted World public key obtained previously from the Trusted Key certificate. In the image descriptor, we specify a single authentication method by signature whose public key is the ``tz_world_pk``. Once this certificate has been authenticated, we have to extract the BL31 public key, stored in the extension specified by ``bl31_content_pk``. This key will be copied to the ``plat_content_pk`` buffer. The **BL31 certificate** is authenticated by checking its digital signature using the BL31 public key obtained previously from the BL31 Key certificate. We specify the authentication method using ``bl31_content_pk`` as public key. After authentication, we need to extract the BL31 hash, stored in the extension specified by ``bl31_hash``. This hash will be copied to the ``plat_bl31_hash_buf`` buffer. The **BL31 image** is authenticated by calculating its hash and matching it with the hash obtained from the BL31 certificate. The image descriptor contains a single authentication method by hash. The parameters to the hash method are the reference hash, ``bl31_hash``, and the data to be hashed. In this case, it is the whole image, so we specify ``raw_data``. The image parser library ~~~~~~~~~~~~~~~~~~~~~~~~ The image parser module relies on libraries to check the image integrity and extract the authentication parameters. The number and type of parser libraries depend on the images used in the CoT. Raw images do not need a library, so only an x509v3 library is required for the TBBR CoT. Arm platforms will use an x509v3 library based on mbed TLS. This library may be found in ``drivers/auth/mbedtls/mbedtls_x509_parser.c``. It exports three functions: .. code:: c void init(void); int check_integrity(void *img, unsigned int img_len); int get_auth_param(const auth_param_type_desc_t *type_desc, void *img, unsigned int img_len, void **param, unsigned int *param_len); The library is registered in the framework using the macro ``REGISTER_IMG_PARSER_LIB()``. Each time the image parser module needs to access an image of type ``IMG_CERT``, it will call the corresponding function exported in this file. The build system must be updated to include the corresponding library and mbed TLS sources. Arm platforms use the ``arm_common.mk`` file to pull the sources. The cryptographic library ~~~~~~~~~~~~~~~~~~~~~~~~~ The cryptographic module relies on a library to perform the required operations, i.e. verify a hash or a digital signature. Arm platforms will use a library based on mbed TLS, which can be found in ``drivers/auth/mbedtls/mbedtls_crypto.c``. This library is registered in the authentication framework using the macro ``REGISTER_CRYPTO_LIB()`` and exports three functions: .. code:: c void init(void); int verify_signature(void *data_ptr, unsigned int data_len, void *sig_ptr, unsigned int sig_len, void *sig_alg, unsigned int sig_alg_len, void *pk_ptr, unsigned int pk_len); int verify_hash(void *data_ptr, unsigned int data_len, void *digest_info_ptr, unsigned int digest_info_len); The mbedTLS library algorithm support is configured by both the ``TF_MBEDTLS_KEY_ALG`` and ``TF_MBEDTLS_KEY_SIZE`` variables. - ``TF_MBEDTLS_KEY_ALG`` can take in 3 values: `rsa`, `ecdsa` or `rsa+ecdsa`. This variable allows the Makefile to include the corresponding sources in the build for the various algorithms. Setting the variable to `rsa+ecdsa` enables support for both rsa and ecdsa algorithms in the mbedTLS library. - ``TF_MBEDTLS_KEY_SIZE`` sets the supported RSA key size for TFA. Valid values include 1024, 2048, 3072 and 4096. .. note:: If code size is a concern, the build option ``MBEDTLS_SHA256_SMALLER`` can be defined in the platform Makefile. It will make mbed TLS use an implementation of SHA-256 with smaller memory footprint (~1.5 KB less) but slower (~30%). -------------- *Copyright (c) 2017-2019, Arm Limited and Contributors. All rights reserved.* .. _TBBR-Client specification: https://developer.arm.com/docs/den0006/latest/trusted-board-boot-requirements-client-tbbr-client-armv8-a trusted-firmware-a-2.2/docs/design/cpu-specific-build-macros.rst000066400000000000000000000377011355360272700250050ustar00rootroot00000000000000Arm CPU Specific Build Macros ============================= This document describes the various build options present in the CPU specific operations framework to enable errata workarounds and to enable optimizations for a specific CPU on a platform. Security Vulnerability Workarounds ---------------------------------- TF-A exports a series of build flags which control which security vulnerability workarounds should be applied at runtime. - ``WORKAROUND_CVE_2017_5715``: Enables the security workaround for `CVE-2017-5715`_. This flag can be set to 0 by the platform if none of the PEs in the system need the workaround. Setting this flag to 0 provides no performance benefit for non-affected platforms, it just helps to comply with the recommendation in the spec regarding workaround discovery. Defaults to 1. - ``WORKAROUND_CVE_2018_3639``: Enables the security workaround for `CVE-2018-3639`_. Defaults to 1. The TF-A project recommends to keep the default value of 1 even on platforms that are unaffected by CVE-2018-3639, in order to comply with the recommendation in the spec regarding workaround discovery. - ``DYNAMIC_WORKAROUND_CVE_2018_3639``: Enables dynamic mitigation for `CVE-2018-3639`_. This build option should be set to 1 if the target platform contains at least 1 CPU that requires dynamic mitigation. Defaults to 0. .. _arm_cpu_macros_errata_workarounds: CPU Errata Workarounds ---------------------- TF-A exports a series of build flags which control the errata workarounds that are applied to each CPU by the reset handler. The errata details can be found in the CPU specific errata documents published by Arm: - `Cortex-A53 MPCore Software Developers Errata Notice`_ - `Cortex-A57 MPCore Software Developers Errata Notice`_ - `Cortex-A72 MPCore Software Developers Errata Notice`_ The errata workarounds are implemented for a particular revision or a set of processor revisions. This is checked by the reset handler at runtime. Each errata workaround is identified by its ``ID`` as specified in the processor's errata notice document. The format of the define used to enable/disable the errata workaround is ``ERRATA__``, where the ``Processor name`` is for example ``A57`` for the ``Cortex_A57`` CPU. Refer to :ref:`firmware_design_cpu_errata_reporting` for information on how to write errata workaround functions. All workarounds are disabled by default. The platform is responsible for enabling these workarounds according to its requirement by defining the errata workaround build flags in the platform specific makefile. In case these workarounds are enabled for the wrong CPU revision then the errata workaround is not applied. In the DEBUG build, this is indicated by printing a warning to the crash console. In the current implementation, a platform which has more than 1 variant with different revisions of a processor has no runtime mechanism available for it to specify which errata workarounds should be enabled or not. The value of the build flags is 0 by default, that is, disabled. A value of 1 will enable it. For Cortex-A9, the following errata build flags are defined : - ``ERRATA_A9_794073``: This applies errata 794073 workaround to Cortex-A9 CPU. This needs to be enabled for all revisions of the CPU. For Cortex-A15, the following errata build flags are defined : - ``ERRATA_A15_816470``: This applies errata 816470 workaround to Cortex-A15 CPU. This needs to be enabled only for revision >= r3p0 of the CPU. - ``ERRATA_A15_827671``: This applies errata 827671 workaround to Cortex-A15 CPU. This needs to be enabled only for revision >= r3p0 of the CPU. For Cortex-A17, the following errata build flags are defined : - ``ERRATA_A17_852421``: This applies errata 852421 workaround to Cortex-A17 CPU. This needs to be enabled only for revision <= r1p2 of the CPU. - ``ERRATA_A17_852423``: This applies errata 852423 workaround to Cortex-A17 CPU. This needs to be enabled only for revision <= r1p2 of the CPU. For Cortex-A35, the following errata build flags are defined : - ``ERRATA_A35_855472``: This applies errata 855472 workaround to Cortex-A35 CPUs. This needs to be enabled only for revision r0p0 of Cortex-A35. For Cortex-A53, the following errata build flags are defined : - ``ERRATA_A53_819472``: This applies errata 819472 workaround to all CPUs. This needs to be enabled only for revision <= r0p1 of Cortex-A53. - ``ERRATA_A53_824069``: This applies errata 824069 workaround to all CPUs. This needs to be enabled only for revision <= r0p2 of Cortex-A53. - ``ERRATA_A53_826319``: This applies errata 826319 workaround to Cortex-A53 CPU. This needs to be enabled only for revision <= r0p2 of the CPU. - ``ERRATA_A53_827319``: This applies errata 827319 workaround to all CPUs. This needs to be enabled only for revision <= r0p2 of Cortex-A53. - ``ERRATA_A53_835769``: This applies erratum 835769 workaround at compile and link time to Cortex-A53 CPU. This needs to be enabled for some variants of revision <= r0p4. This workaround can lead the linker to create ``*.stub`` sections. - ``ERRATA_A53_836870``: This applies errata 836870 workaround to Cortex-A53 CPU. This needs to be enabled only for revision <= r0p3 of the CPU. From r0p4 and onwards, this errata is enabled by default in hardware. - ``ERRATA_A53_843419``: This applies erratum 843419 workaround at link time to Cortex-A53 CPU. This needs to be enabled for some variants of revision <= r0p4. This workaround can lead the linker to emit ``*.stub`` sections which are 4kB aligned. - ``ERRATA_A53_855873``: This applies errata 855873 workaround to Cortex-A53 CPUs. Though the erratum is present in every revision of the CPU, this workaround is only applied to CPUs from r0p3 onwards, which feature a chicken bit in CPUACTLR_EL1 to enable a hardware workaround. Earlier revisions of the CPU have other errata which require the same workaround in software, so they should be covered anyway. For Cortex-A55, the following errata build flags are defined : - ``ERRATA_A55_768277``: This applies errata 768277 workaround to Cortex-A55 CPU. This needs to be enabled only for revision r0p0 of the CPU. - ``ERRATA_A55_778703``: This applies errata 778703 workaround to Cortex-A55 CPU. This needs to be enabled only for revision r0p0 of the CPU. - ``ERRATA_A55_798797``: This applies errata 798797 workaround to Cortex-A55 CPU. This needs to be enabled only for revision r0p0 of the CPU. - ``ERRATA_A55_846532``: This applies errata 846532 workaround to Cortex-A55 CPU. This needs to be enabled only for revision <= r0p1 of the CPU. - ``ERRATA_A55_903758``: This applies errata 903758 workaround to Cortex-A55 CPU. This needs to be enabled only for revision <= r0p1 of the CPU. - ``ERRATA_A55_1221012``: This applies errata 1221012 workaround to Cortex-A55 CPU. This needs to be enabled only for revision <= r1p0 of the CPU. For Cortex-A57, the following errata build flags are defined : - ``ERRATA_A57_806969``: This applies errata 806969 workaround to Cortex-A57 CPU. This needs to be enabled only for revision r0p0 of the CPU. - ``ERRATA_A57_813419``: This applies errata 813419 workaround to Cortex-A57 CPU. This needs to be enabled only for revision r0p0 of the CPU. - ``ERRATA_A57_813420``: This applies errata 813420 workaround to Cortex-A57 CPU. This needs to be enabled only for revision r0p0 of the CPU. - ``ERRATA_A57_814670``: This applies errata 814670 workaround to Cortex-A57 CPU. This needs to be enabled only for revision r0p0 of the CPU. - ``ERRATA_A57_817169``: This applies errata 817169 workaround to Cortex-A57 CPU. This needs to be enabled only for revision <= r0p1 of the CPU. - ``ERRATA_A57_826974``: This applies errata 826974 workaround to Cortex-A57 CPU. This needs to be enabled only for revision <= r1p1 of the CPU. - ``ERRATA_A57_826977``: This applies errata 826977 workaround to Cortex-A57 CPU. This needs to be enabled only for revision <= r1p1 of the CPU. - ``ERRATA_A57_828024``: This applies errata 828024 workaround to Cortex-A57 CPU. This needs to be enabled only for revision <= r1p1 of the CPU. - ``ERRATA_A57_829520``: This applies errata 829520 workaround to Cortex-A57 CPU. This needs to be enabled only for revision <= r1p2 of the CPU. - ``ERRATA_A57_833471``: This applies errata 833471 workaround to Cortex-A57 CPU. This needs to be enabled only for revision <= r1p2 of the CPU. - ``ERRATA_A57_859972``: This applies errata 859972 workaround to Cortex-A57 CPU. This needs to be enabled only for revision <= r1p3 of the CPU. For Cortex-A72, the following errata build flags are defined : - ``ERRATA_A72_859971``: This applies errata 859971 workaround to Cortex-A72 CPU. This needs to be enabled only for revision <= r0p3 of the CPU. For Cortex-A73, the following errata build flags are defined : - ``ERRATA_A73_852427``: This applies errata 852427 workaround to Cortex-A73 CPU. This needs to be enabled only for revision r0p0 of the CPU. - ``ERRATA_A73_855423``: This applies errata 855423 workaround to Cortex-A73 CPU. This needs to be enabled only for revision <= r0p1 of the CPU. For Cortex-A75, the following errata build flags are defined : - ``ERRATA_A75_764081``: This applies errata 764081 workaround to Cortex-A75 CPU. This needs to be enabled only for revision r0p0 of the CPU. - ``ERRATA_A75_790748``: This applies errata 790748 workaround to Cortex-A75 CPU. This needs to be enabled only for revision r0p0 of the CPU. For Cortex-A76, the following errata build flags are defined : - ``ERRATA_A76_1073348``: This applies errata 1073348 workaround to Cortex-A76 CPU. This needs to be enabled only for revision <= r1p0 of the CPU. - ``ERRATA_A76_1130799``: This applies errata 1130799 workaround to Cortex-A76 CPU. This needs to be enabled only for revision <= r2p0 of the CPU. - ``ERRATA_A76_1220197``: This applies errata 1220197 workaround to Cortex-A76 CPU. This needs to be enabled only for revision <= r2p0 of the CPU. - ``ERRATA_A76_1257314``: This applies errata 1257314 workaround to Cortex-A76 CPU. This needs to be enabled only for revision <= r3p0 of the CPU. - ``ERRATA_A76_1262606``: This applies errata 1262606 workaround to Cortex-A76 CPU. This needs to be enabled only for revision <= r3p0 of the CPU. - ``ERRATA_A76_1262888``: This applies errata 1262888 workaround to Cortex-A76 CPU. This needs to be enabled only for revision <= r3p0 of the CPU. - ``ERRATA_A76_1275112``: This applies errata 1275112 workaround to Cortex-A76 CPU. This needs to be enabled only for revision <= r3p0 of the CPU. For Neoverse N1, the following errata build flags are defined : - ``ERRATA_N1_1073348``: This applies errata 1073348 workaround to Neoverse-N1 CPU. This needs to be enabled only for revision r0p0 and r1p0 of the CPU. - ``ERRATA_N1_1130799``: This applies errata 1130799 workaround to Neoverse-N1 CPU. This needs to be enabled only for revision <= r2p0 of the CPU. - ``ERRATA_N1_1165347``: This applies errata 1165347 workaround to Neoverse-N1 CPU. This needs to be enabled only for revision <= r2p0 of the CPU. - ``ERRATA_N1_1207823``: This applies errata 1207823 workaround to Neoverse-N1 CPU. This needs to be enabled only for revision <= r2p0 of the CPU. - ``ERRATA_N1_1220197``: This applies errata 1220197 workaround to Neoverse-N1 CPU. This needs to be enabled only for revision <= r2p0 of the CPU. - ``ERRATA_N1_1257314``: This applies errata 1257314 workaround to Neoverse-N1 CPU. This needs to be enabled only for revision <= r3p0 of the CPU. - ``ERRATA_N1_1262606``: This applies errata 1262606 workaround to Neoverse-N1 CPU. This needs to be enabled only for revision <= r3p0 of the CPU. - ``ERRATA_N1_1262888``: This applies errata 1262888 workaround to Neoverse-N1 CPU. This needs to be enabled only for revision <= r3p0 of the CPU. - ``ERRATA_N1_1275112``: This applies errata 1275112 workaround to Neoverse-N1 CPU. This needs to be enabled only for revision <= r3p0 of the CPU. - ``ERRATA_N1_1315703``: This applies errata 1315703 workaround to Neoverse-N1 CPU. This needs to be enabled only for revision <= r3p0 of the CPU. - ``ERRATA_N1_1542419``: This applies errata 1542419 workaround to Neoverse-N1 CPU. This needs to be enabled only for revisions r3p0 - r4p0 of the CPU. DSU Errata Workarounds ---------------------- Similar to CPU errata, TF-A also implements workarounds for DSU (DynamIQ Shared Unit) errata. The DSU errata details can be found in the respective Arm documentation: - `Arm DSU Software Developers Errata Notice`_. Each erratum is identified by an ``ID``, as defined in the DSU errata notice document. Thus, the build flags which enable/disable the errata workarounds have the format ``ERRATA_DSU_``. The implementation and application logic of DSU errata workarounds are similar to `CPU errata workarounds`_. For DSU errata, the following build flags are defined: - ``ERRATA_DSU_798953``: This applies errata 798953 workaround for the affected DSU configurations. This errata applies only for those DSUs that revision is r0p0 (on r0p1 it is fixed). However, please note that this workaround results in increased DSU power consumption on idle. - ``ERRATA_DSU_936184``: This applies errata 936184 workaround for the affected DSU configurations. This errata applies only for those DSUs that contain the ACP interface **and** the DSU revision is older than r2p0 (on r2p0 it is fixed). However, please note that this workaround results in increased DSU power consumption on idle. CPU Specific optimizations -------------------------- This section describes some of the optimizations allowed by the CPU micro architecture that can be enabled by the platform as desired. - ``SKIP_A57_L1_FLUSH_PWR_DWN``: This flag enables an optimization in the Cortex-A57 cluster power down sequence by not flushing the Level 1 data cache. The L1 data cache and the L2 unified cache are inclusive. A flush of the L2 by set/way flushes any dirty lines from the L1 as well. This is a known safe deviation from the Cortex-A57 TRM defined power down sequence. Each Cortex-A57 based platform must make its own decision on whether to use the optimization. - ``A53_DISABLE_NON_TEMPORAL_HINT``: This flag disables the cache non-temporal hint. The LDNP/STNP instructions as implemented on Cortex-A53 do not behave in a way most programmers expect, and will most probably result in a significant speed degradation to any code that employs them. The Armv8-A architecture (see Arm DDI 0487A.h, section D3.4.3) allows cores to ignore the non-temporal hint and treat LDNP/STNP as LDP/STP instead. Enabling this flag enforces this behaviour. This needs to be enabled only for revisions <= r0p3 of the CPU and is enabled by default. - ``A57_DISABLE_NON_TEMPORAL_HINT``: This flag has the same behaviour as ``A53_DISABLE_NON_TEMPORAL_HINT`` but for Cortex-A57. This needs to be enabled only for revisions <= r1p2 of the CPU and is enabled by default, as recommended in section "4.7 Non-Temporal Loads/Stores" of the `Cortex-A57 Software Optimization Guide`_. -------------- *Copyright (c) 2014-2019, Arm Limited and Contributors. All rights reserved.* .. _CVE-2017-5715: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5715 .. _CVE-2018-3639: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3639 .. _Cortex-A53 MPCore Software Developers Errata Notice: http://infocenter.arm.com/help/topic/com.arm.doc.epm048406/index.html .. _Cortex-A57 MPCore Software Developers Errata Notice: http://infocenter.arm.com/help/topic/com.arm.doc.epm049219/index.html .. _Cortex-A72 MPCore Software Developers Errata Notice: http://infocenter.arm.com/help/topic/com.arm.doc.epm012079/index.html .. _Cortex-A57 Software Optimization Guide: http://infocenter.arm.com/help/topic/com.arm.doc.uan0015b/Cortex_A57_Software_Optimization_Guide_external.pdf .. _Arm DSU Software Developers Errata Notice: http://infocenter.arm.com/help/topic/com.arm.doc.epm138168/index.html trusted-firmware-a-2.2/docs/design/firmware-design.rst000066400000000000000000003500341355360272700231340ustar00rootroot00000000000000Firmware Design =============== Trusted Firmware-A (TF-A) implements a subset of the Trusted Board Boot Requirements (TBBR) Platform Design Document (PDD) for Arm reference platforms. The TBB sequence starts when the platform is powered on and runs up to the stage where it hands-off control to firmware running in the normal world in DRAM. This is the cold boot path. TF-A also implements the `Power State Coordination Interface PDD`_ as a runtime service. PSCI is the interface from normal world software to firmware implementing power management use-cases (for example, secondary CPU boot, hotplug and idle). Normal world software can access TF-A runtime services via the Arm SMC (Secure Monitor Call) instruction. The SMC instruction must be used as mandated by the SMC Calling Convention (`SMCCC`_). TF-A implements a framework for configuring and managing interrupts generated in either security state. The details of the interrupt management framework and its design can be found in :ref:`Interrupt Management Framework`. TF-A also implements a library for setting up and managing the translation tables. The details of this library can be found in :ref:`Translation (XLAT) Tables Library`. TF-A can be built to support either AArch64 or AArch32 execution state. Cold boot --------- The cold boot path starts when the platform is physically turned on. If ``COLD_BOOT_SINGLE_CPU=0``, one of the CPUs released from reset is chosen as the primary CPU, and the remaining CPUs are considered secondary CPUs. The primary CPU is chosen through platform-specific means. The cold boot path is mainly executed by the primary CPU, other than essential CPU initialization executed by all CPUs. The secondary CPUs are kept in a safe platform-specific state until the primary CPU has performed enough initialization to boot them. Refer to the :ref:`CPU Reset` for more information on the effect of the ``COLD_BOOT_SINGLE_CPU`` platform build option. The cold boot path in this implementation of TF-A depends on the execution state. For AArch64, it is divided into five steps (in order of execution): - Boot Loader stage 1 (BL1) *AP Trusted ROM* - Boot Loader stage 2 (BL2) *Trusted Boot Firmware* - Boot Loader stage 3-1 (BL31) *EL3 Runtime Software* - Boot Loader stage 3-2 (BL32) *Secure-EL1 Payload* (optional) - Boot Loader stage 3-3 (BL33) *Non-trusted Firmware* For AArch32, it is divided into four steps (in order of execution): - Boot Loader stage 1 (BL1) *AP Trusted ROM* - Boot Loader stage 2 (BL2) *Trusted Boot Firmware* - Boot Loader stage 3-2 (BL32) *EL3 Runtime Software* - Boot Loader stage 3-3 (BL33) *Non-trusted Firmware* Arm development platforms (Fixed Virtual Platforms (FVPs) and Juno) implement a combination of the following types of memory regions. Each bootloader stage uses one or more of these memory regions. - Regions accessible from both non-secure and secure states. For example, non-trusted SRAM, ROM and DRAM. - Regions accessible from only the secure state. For example, trusted SRAM and ROM. The FVPs also implement the trusted DRAM which is statically configured. Additionally, the Base FVPs and Juno development platform configure the TrustZone Controller (TZC) to create a region in the DRAM which is accessible only from the secure state. The sections below provide the following details: - dynamic configuration of Boot Loader stages - initialization and execution of the first three stages during cold boot - specification of the EL3 Runtime Software (BL31 for AArch64 and BL32 for AArch32) entrypoint requirements for use by alternative Trusted Boot Firmware in place of the provided BL1 and BL2 Dynamic Configuration during cold boot ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Each of the Boot Loader stages may be dynamically configured if required by the platform. The Boot Loader stage may optionally specify a firmware configuration file and/or hardware configuration file as listed below: - HW_CONFIG - The hardware configuration file. Can be shared by all Boot Loader stages and also by the Normal World Rich OS. - TB_FW_CONFIG - Trusted Boot Firmware configuration file. Shared between BL1 and BL2. - SOC_FW_CONFIG - SoC Firmware configuration file. Used by BL31. - TOS_FW_CONFIG - Trusted OS Firmware configuration file. Used by Trusted OS (BL32). - NT_FW_CONFIG - Non Trusted Firmware configuration file. Used by Non-trusted firmware (BL33). The Arm development platforms use the Flattened Device Tree format for the dynamic configuration files. Each Boot Loader stage can pass up to 4 arguments via registers to the next stage. BL2 passes the list of the next images to execute to the *EL3 Runtime Software* (BL31 for AArch64 and BL32 for AArch32) via `arg0`. All the other arguments are platform defined. The Arm development platforms use the following convention: - BL1 passes the address of a meminfo_t structure to BL2 via ``arg1``. This structure contains the memory layout available to BL2. - When dynamic configuration files are present, the firmware configuration for the next Boot Loader stage is populated in the first available argument and the generic hardware configuration is passed the next available argument. For example, - If TB_FW_CONFIG is loaded by BL1, then its address is passed in ``arg0`` to BL2. - If HW_CONFIG is loaded by BL1, then its address is passed in ``arg2`` to BL2. Note, ``arg1`` is already used for meminfo_t. - If SOC_FW_CONFIG is loaded by BL2, then its address is passed in ``arg1`` to BL31. Note, ``arg0`` is used to pass the list of executable images. - Similarly, if HW_CONFIG is loaded by BL1 or BL2, then its address is passed in ``arg2`` to BL31. - For other BL3x images, if the firmware configuration file is loaded by BL2, then its address is passed in ``arg0`` and if HW_CONFIG is loaded then its address is passed in ``arg1``. BL1 ~~~ This stage begins execution from the platform's reset vector at EL3. The reset address is platform dependent but it is usually located in a Trusted ROM area. The BL1 data section is copied to trusted SRAM at runtime. On the Arm development platforms, BL1 code starts execution from the reset vector defined by the constant ``BL1_RO_BASE``. The BL1 data section is copied to the top of trusted SRAM as defined by the constant ``BL1_RW_BASE``. The functionality implemented by this stage is as follows. Determination of boot path ^^^^^^^^^^^^^^^^^^^^^^^^^^ Whenever a CPU is released from reset, BL1 needs to distinguish between a warm boot and a cold boot. This is done using platform-specific mechanisms (see the ``plat_get_my_entrypoint()`` function in the :ref:`Porting Guide`). In the case of a warm boot, a CPU is expected to continue execution from a separate entrypoint. In the case of a cold boot, the secondary CPUs are placed in a safe platform-specific state (see the ``plat_secondary_cold_boot_setup()`` function in the :ref:`Porting Guide`) while the primary CPU executes the remaining cold boot path as described in the following sections. This step only applies when ``PROGRAMMABLE_RESET_ADDRESS=0``. Refer to the :ref:`CPU Reset` for more information on the effect of the ``PROGRAMMABLE_RESET_ADDRESS`` platform build option. Architectural initialization ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ BL1 performs minimal architectural initialization as follows. - Exception vectors BL1 sets up simple exception vectors for both synchronous and asynchronous exceptions. The default behavior upon receiving an exception is to populate a status code in the general purpose register ``X0/R0`` and call the ``plat_report_exception()`` function (see the :ref:`Porting Guide`). The status code is one of: For AArch64: :: 0x0 : Synchronous exception from Current EL with SP_EL0 0x1 : IRQ exception from Current EL with SP_EL0 0x2 : FIQ exception from Current EL with SP_EL0 0x3 : System Error exception from Current EL with SP_EL0 0x4 : Synchronous exception from Current EL with SP_ELx 0x5 : IRQ exception from Current EL with SP_ELx 0x6 : FIQ exception from Current EL with SP_ELx 0x7 : System Error exception from Current EL with SP_ELx 0x8 : Synchronous exception from Lower EL using aarch64 0x9 : IRQ exception from Lower EL using aarch64 0xa : FIQ exception from Lower EL using aarch64 0xb : System Error exception from Lower EL using aarch64 0xc : Synchronous exception from Lower EL using aarch32 0xd : IRQ exception from Lower EL using aarch32 0xe : FIQ exception from Lower EL using aarch32 0xf : System Error exception from Lower EL using aarch32 For AArch32: :: 0x10 : User mode 0x11 : FIQ mode 0x12 : IRQ mode 0x13 : SVC mode 0x16 : Monitor mode 0x17 : Abort mode 0x1a : Hypervisor mode 0x1b : Undefined mode 0x1f : System mode The ``plat_report_exception()`` implementation on the Arm FVP port programs the Versatile Express System LED register in the following format to indicate the occurrence of an unexpected exception: :: SYS_LED[0] - Security state (Secure=0/Non-Secure=1) SYS_LED[2:1] - Exception Level (EL3=0x3, EL2=0x2, EL1=0x1, EL0=0x0) For AArch32 it is always 0x0 SYS_LED[7:3] - Exception Class (Sync/Async & origin). This is the value of the status code A write to the LED register reflects in the System LEDs (S6LED0..7) in the CLCD window of the FVP. BL1 does not expect to receive any exceptions other than the SMC exception. For the latter, BL1 installs a simple stub. The stub expects to receive a limited set of SMC types (determined by their function IDs in the general purpose register ``X0/R0``): - ``BL1_SMC_RUN_IMAGE``: This SMC is raised by BL2 to make BL1 pass control to EL3 Runtime Software. - All SMCs listed in section "BL1 SMC Interface" in the :ref:`Firmware Update (FWU)` Design Guide are supported for AArch64 only. These SMCs are currently not supported when BL1 is built for AArch32. Any other SMC leads to an assertion failure. - CPU initialization BL1 calls the ``reset_handler()`` function which in turn calls the CPU specific reset handler function (see the section: "CPU specific operations framework"). - Control register setup (for AArch64) - ``SCTLR_EL3``. Instruction cache is enabled by setting the ``SCTLR_EL3.I`` bit. Alignment and stack alignment checking is enabled by setting the ``SCTLR_EL3.A`` and ``SCTLR_EL3.SA`` bits. Exception endianness is set to little-endian by clearing the ``SCTLR_EL3.EE`` bit. - ``SCR_EL3``. The register width of the next lower exception level is set to AArch64 by setting the ``SCR.RW`` bit. The ``SCR.EA`` bit is set to trap both External Aborts and SError Interrupts in EL3. The ``SCR.SIF`` bit is also set to disable instruction fetches from Non-secure memory when in secure state. - ``CPTR_EL3``. Accesses to the ``CPACR_EL1`` register from EL1 or EL2, or the ``CPTR_EL2`` register from EL2 are configured to not trap to EL3 by clearing the ``CPTR_EL3.TCPAC`` bit. Access to the trace functionality is configured not to trap to EL3 by clearing the ``CPTR_EL3.TTA`` bit. Instructions that access the registers associated with Floating Point and Advanced SIMD execution are configured to not trap to EL3 by clearing the ``CPTR_EL3.TFP`` bit. - ``DAIF``. The SError interrupt is enabled by clearing the SError interrupt mask bit. - ``MDCR_EL3``. The trap controls, ``MDCR_EL3.TDOSA``, ``MDCR_EL3.TDA`` and ``MDCR_EL3.TPM``, are set so that accesses to the registers they control do not trap to EL3. AArch64 Secure self-hosted debug is disabled by setting the ``MDCR_EL3.SDD`` bit. Also ``MDCR_EL3.SPD32`` is set to disable AArch32 Secure self-hosted privileged debug from S-EL1. - Control register setup (for AArch32) - ``SCTLR``. Instruction cache is enabled by setting the ``SCTLR.I`` bit. Alignment checking is enabled by setting the ``SCTLR.A`` bit. Exception endianness is set to little-endian by clearing the ``SCTLR.EE`` bit. - ``SCR``. The ``SCR.SIF`` bit is set to disable instruction fetches from Non-secure memory when in secure state. - ``CPACR``. Allow execution of Advanced SIMD instructions at PL0 and PL1, by clearing the ``CPACR.ASEDIS`` bit. Access to the trace functionality is configured not to trap to undefined mode by clearing the ``CPACR.TRCDIS`` bit. - ``NSACR``. Enable non-secure access to Advanced SIMD functionality and system register access to implemented trace registers. - ``FPEXC``. Enable access to the Advanced SIMD and floating-point functionality from all Exception levels. - ``CPSR.A``. The Asynchronous data abort interrupt is enabled by clearing the Asynchronous data abort interrupt mask bit. - ``SDCR``. The ``SDCR.SPD`` field is set to disable AArch32 Secure self-hosted privileged debug. Platform initialization ^^^^^^^^^^^^^^^^^^^^^^^ On Arm platforms, BL1 performs the following platform initializations: - Enable the Trusted Watchdog. - Initialize the console. - Configure the Interconnect to enable hardware coherency. - Enable the MMU and map the memory it needs to access. - Configure any required platform storage to load the next bootloader image (BL2). - If the BL1 dynamic configuration file, ``TB_FW_CONFIG``, is available, then load it to the platform defined address and make it available to BL2 via ``arg0``. - Configure the system timer and program the `CNTFRQ_EL0` for use by NS-BL1U and NS-BL2U firmware update images. Firmware Update detection and execution ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ After performing platform setup, BL1 common code calls ``bl1_plat_get_next_image_id()`` to determine if :ref:`Firmware Update (FWU)` is required or to proceed with the normal boot process. If the platform code returns ``BL2_IMAGE_ID`` then the normal boot sequence is executed as described in the next section, else BL1 assumes that :ref:`Firmware Update (FWU)` is required and execution passes to the first image in the :ref:`Firmware Update (FWU)` process. In either case, BL1 retrieves a descriptor of the next image by calling ``bl1_plat_get_image_desc()``. The image descriptor contains an ``entry_point_info_t`` structure, which BL1 uses to initialize the execution state of the next image. BL2 image load and execution ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In the normal boot flow, BL1 execution continues as follows: #. BL1 prints the following string from the primary CPU to indicate successful execution of the BL1 stage: :: "Booting Trusted Firmware" #. BL1 loads a BL2 raw binary image from platform storage, at a platform-specific base address. Prior to the load, BL1 invokes ``bl1_plat_handle_pre_image_load()`` which allows the platform to update or use the image information. If the BL2 image file is not present or if there is not enough free trusted SRAM the following error message is printed: :: "Failed to load BL2 firmware." #. BL1 invokes ``bl1_plat_handle_post_image_load()`` which again is intended for platforms to take further action after image load. This function must populate the necessary arguments for BL2, which may also include the memory layout. Further description of the memory layout can be found later in this document. #. BL1 passes control to the BL2 image at Secure EL1 (for AArch64) or at Secure SVC mode (for AArch32), starting from its load address. BL2 ~~~ BL1 loads and passes control to BL2 at Secure-EL1 (for AArch64) or at Secure SVC mode (for AArch32) . BL2 is linked against and loaded at a platform-specific base address (more information can be found later in this document). The functionality implemented by BL2 is as follows. Architectural initialization ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ For AArch64, BL2 performs the minimal architectural initialization required for subsequent stages of TF-A and normal world software. EL1 and EL0 are given access to Floating Point and Advanced SIMD registers by clearing the ``CPACR.FPEN`` bits. For AArch32, the minimal architectural initialization required for subsequent stages of TF-A and normal world software is taken care of in BL1 as both BL1 and BL2 execute at PL1. Platform initialization ^^^^^^^^^^^^^^^^^^^^^^^ On Arm platforms, BL2 performs the following platform initializations: - Initialize the console. - Configure any required platform storage to allow loading further bootloader images. - Enable the MMU and map the memory it needs to access. - Perform platform security setup to allow access to controlled components. - Reserve some memory for passing information to the next bootloader image EL3 Runtime Software and populate it. - Define the extents of memory available for loading each subsequent bootloader image. - If BL1 has passed TB_FW_CONFIG dynamic configuration file in ``arg0``, then parse it. Image loading in BL2 ^^^^^^^^^^^^^^^^^^^^ BL2 generic code loads the images based on the list of loadable images provided by the platform. BL2 passes the list of executable images provided by the platform to the next handover BL image. The list of loadable images provided by the platform may also contain dynamic configuration files. The files are loaded and can be parsed as needed in the ``bl2_plat_handle_post_image_load()`` function. These configuration files can be passed to next Boot Loader stages as arguments by updating the corresponding entrypoint information in this function. SCP_BL2 (System Control Processor Firmware) image load ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Some systems have a separate System Control Processor (SCP) for power, clock, reset and system control. BL2 loads the optional SCP_BL2 image from platform storage into a platform-specific region of secure memory. The subsequent handling of SCP_BL2 is platform specific. For example, on the Juno Arm development platform port the image is transferred into SCP's internal memory using the Boot Over MHU (BOM) protocol after being loaded in the trusted SRAM memory. The SCP executes SCP_BL2 and signals to the Application Processor (AP) for BL2 execution to continue. EL3 Runtime Software image load ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ BL2 loads the EL3 Runtime Software image from platform storage into a platform- specific address in trusted SRAM. If there is not enough memory to load the image or image is missing it leads to an assertion failure. AArch64 BL32 (Secure-EL1 Payload) image load ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ BL2 loads the optional BL32 image from platform storage into a platform- specific region of secure memory. The image executes in the secure world. BL2 relies on BL31 to pass control to the BL32 image, if present. Hence, BL2 populates a platform-specific area of memory with the entrypoint/load-address of the BL32 image. The value of the Saved Processor Status Register (``SPSR``) for entry into BL32 is not determined by BL2, it is initialized by the Secure-EL1 Payload Dispatcher (see later) within BL31, which is responsible for managing interaction with BL32. This information is passed to BL31. BL33 (Non-trusted Firmware) image load ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ BL2 loads the BL33 image (e.g. UEFI or other test or boot software) from platform storage into non-secure memory as defined by the platform. BL2 relies on EL3 Runtime Software to pass control to BL33 once secure state initialization is complete. Hence, BL2 populates a platform-specific area of memory with the entrypoint and Saved Program Status Register (``SPSR``) of the normal world software image. The entrypoint is the load address of the BL33 image. The ``SPSR`` is determined as specified in Section 5.13 of the `Power State Coordination Interface PDD`_. This information is passed to the EL3 Runtime Software. AArch64 BL31 (EL3 Runtime Software) execution ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ BL2 execution continues as follows: #. BL2 passes control back to BL1 by raising an SMC, providing BL1 with the BL31 entrypoint. The exception is handled by the SMC exception handler installed by BL1. #. BL1 turns off the MMU and flushes the caches. It clears the ``SCTLR_EL3.M/I/C`` bits, flushes the data cache to the point of coherency and invalidates the TLBs. #. BL1 passes control to BL31 at the specified entrypoint at EL3. Running BL2 at EL3 execution level ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Some platforms have a non-TF-A Boot ROM that expects the next boot stage to execute at EL3. On these platforms, TF-A BL1 is a waste of memory as its only purpose is to ensure TF-A BL2 is entered at S-EL1. To avoid this waste, a special mode enables BL2 to execute at EL3, which allows a non-TF-A Boot ROM to load and jump directly to BL2. This mode is selected when the build flag BL2_AT_EL3 is enabled. The main differences in this mode are: #. BL2 includes the reset code and the mailbox mechanism to differentiate cold boot and warm boot. It runs at EL3 doing the arch initialization required for EL3. #. BL2 does not receive the meminfo information from BL1 anymore. This information can be passed by the Boot ROM or be internal to the BL2 image. #. Since BL2 executes at EL3, BL2 jumps directly to the next image, instead of invoking the RUN_IMAGE SMC call. We assume 3 different types of BootROM support on the platform: #. The Boot ROM always jumps to the same address, for both cold and warm boot. In this case, we will need to keep a resident part of BL2 whose memory cannot be reclaimed by any other image. The linker script defines the symbols __TEXT_RESIDENT_START__ and __TEXT_RESIDENT_END__ that allows the platform to configure correctly the memory map. #. The platform has some mechanism to indicate the jump address to the Boot ROM. Platform code can then program the jump address with psci_warmboot_entrypoint during cold boot. #. The platform has some mechanism to program the reset address using the PROGRAMMABLE_RESET_ADDRESS feature. Platform code can then program the reset address with psci_warmboot_entrypoint during cold boot, bypassing the boot ROM for warm boot. In the last 2 cases, no part of BL2 needs to remain resident at runtime. In the first 2 cases, we expect the Boot ROM to be able to differentiate between warm and cold boot, to avoid loading BL2 again during warm boot. This functionality can be tested with FVP loading the image directly in memory and changing the address where the system jumps at reset. For example: -C cluster0.cpu0.RVBAR=0x4022000 --data cluster0.cpu0=bl2.bin@0x4022000 With this configuration, FVP is like a platform of the first case, where the Boot ROM jumps always to the same address. For simplification, BL32 is loaded in DRAM in this case, to avoid other images reclaiming BL2 memory. AArch64 BL31 ~~~~~~~~~~~~ The image for this stage is loaded by BL2 and BL1 passes control to BL31 at EL3. BL31 executes solely in trusted SRAM. BL31 is linked against and loaded at a platform-specific base address (more information can be found later in this document). The functionality implemented by BL31 is as follows. Architectural initialization ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Currently, BL31 performs a similar architectural initialization to BL1 as far as system register settings are concerned. Since BL1 code resides in ROM, architectural initialization in BL31 allows override of any previous initialization done by BL1. BL31 initializes the per-CPU data framework, which provides a cache of frequently accessed per-CPU data optimised for fast, concurrent manipulation on different CPUs. This buffer includes pointers to per-CPU contexts, crash buffer, CPU reset and power down operations, PSCI data, platform data and so on. It then replaces the exception vectors populated by BL1 with its own. BL31 exception vectors implement more elaborate support for handling SMCs since this is the only mechanism to access the runtime services implemented by BL31 (PSCI for example). BL31 checks each SMC for validity as specified by the `SMC Calling Convention PDD`_ before passing control to the required SMC handler routine. BL31 programs the ``CNTFRQ_EL0`` register with the clock frequency of the system counter, which is provided by the platform. Platform initialization ^^^^^^^^^^^^^^^^^^^^^^^ BL31 performs detailed platform initialization, which enables normal world software to function correctly. On Arm platforms, this consists of the following: - Initialize the console. - Configure the Interconnect to enable hardware coherency. - Enable the MMU and map the memory it needs to access. - Initialize the generic interrupt controller. - Initialize the power controller device. - Detect the system topology. Runtime services initialization ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ BL31 is responsible for initializing the runtime services. One of them is PSCI. As part of the PSCI initializations, BL31 detects the system topology. It also initializes the data structures that implement the state machine used to track the state of power domain nodes. The state can be one of ``OFF``, ``RUN`` or ``RETENTION``. All secondary CPUs are initially in the ``OFF`` state. The cluster that the primary CPU belongs to is ``ON``; any other cluster is ``OFF``. It also initializes the locks that protect them. BL31 accesses the state of a CPU or cluster immediately after reset and before the data cache is enabled in the warm boot path. It is not currently possible to use 'exclusive' based spinlocks, therefore BL31 uses locks based on Lamport's Bakery algorithm instead. The runtime service framework and its initialization is described in more detail in the "EL3 runtime services framework" section below. Details about the status of the PSCI implementation are provided in the "Power State Coordination Interface" section below. AArch64 BL32 (Secure-EL1 Payload) image initialization ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If a BL32 image is present then there must be a matching Secure-EL1 Payload Dispatcher (SPD) service (see later for details). During initialization that service must register a function to carry out initialization of BL32 once the runtime services are fully initialized. BL31 invokes such a registered function to initialize BL32 before running BL33. This initialization is not necessary for AArch32 SPs. Details on BL32 initialization and the SPD's role are described in the "Secure-EL1 Payloads and Dispatchers" section below. BL33 (Non-trusted Firmware) execution ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ EL3 Runtime Software initializes the EL2 or EL1 processor context for normal- world cold boot, ensuring that no secure state information finds its way into the non-secure execution state. EL3 Runtime Software uses the entrypoint information provided by BL2 to jump to the Non-trusted firmware image (BL33) at the highest available Exception Level (EL2 if available, otherwise EL1). Using alternative Trusted Boot Firmware in place of BL1 & BL2 (AArch64 only) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Some platforms have existing implementations of Trusted Boot Firmware that would like to use TF-A BL31 for the EL3 Runtime Software. To enable this firmware architecture it is important to provide a fully documented and stable interface between the Trusted Boot Firmware and BL31. Future changes to the BL31 interface will be done in a backwards compatible way, and this enables these firmware components to be independently enhanced/ updated to develop and exploit new functionality. Required CPU state when calling ``bl31_entrypoint()`` during cold boot ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This function must only be called by the primary CPU. On entry to this function the calling primary CPU must be executing in AArch64 EL3, little-endian data access, and all interrupt sources masked: :: PSTATE.EL = 3 PSTATE.RW = 1 PSTATE.DAIF = 0xf SCTLR_EL3.EE = 0 X0 and X1 can be used to pass information from the Trusted Boot Firmware to the platform code in BL31: :: X0 : Reserved for common TF-A information X1 : Platform specific information BL31 zero-init sections (e.g. ``.bss``) should not contain valid data on entry, these will be zero filled prior to invoking platform setup code. Use of the X0 and X1 parameters ''''''''''''''''''''''''''''''' The parameters are platform specific and passed from ``bl31_entrypoint()`` to ``bl31_early_platform_setup()``. The value of these parameters is never directly used by the common BL31 code. The convention is that ``X0`` conveys information regarding the BL31, BL32 and BL33 images from the Trusted Boot firmware and ``X1`` can be used for other platform specific purpose. This convention allows platforms which use TF-A's BL1 and BL2 images to transfer additional platform specific information from Secure Boot without conflicting with future evolution of TF-A using ``X0`` to pass a ``bl31_params`` structure. BL31 common and SPD initialization code depends on image and entrypoint information about BL33 and BL32, which is provided via BL31 platform APIs. This information is required until the start of execution of BL33. This information can be provided in a platform defined manner, e.g. compiled into the platform code in BL31, or provided in a platform defined memory location by the Trusted Boot firmware, or passed from the Trusted Boot Firmware via the Cold boot Initialization parameters. This data may need to be cleaned out of the CPU caches if it is provided by an earlier boot stage and then accessed by BL31 platform code before the caches are enabled. TF-A's BL2 implementation passes a ``bl31_params`` structure in ``X0`` and the Arm development platforms interpret this in the BL31 platform code. MMU, Data caches & Coherency '''''''''''''''''''''''''''' BL31 does not depend on the enabled state of the MMU, data caches or interconnect coherency on entry to ``bl31_entrypoint()``. If these are disabled on entry, these should be enabled during ``bl31_plat_arch_setup()``. Data structures used in the BL31 cold boot interface '''''''''''''''''''''''''''''''''''''''''''''''''''' These structures are designed to support compatibility and independent evolution of the structures and the firmware images. For example, a version of BL31 that can interpret the BL3x image information from different versions of BL2, a platform that uses an extended entry_point_info structure to convey additional register information to BL31, or a ELF image loader that can convey more details about the firmware images. To support these scenarios the structures are versioned and sized, which enables BL31 to detect which information is present and respond appropriately. The ``param_header`` is defined to capture this information: .. code:: c typedef struct param_header { uint8_t type; /* type of the structure */ uint8_t version; /* version of this structure */ uint16_t size; /* size of this structure in bytes */ uint32_t attr; /* attributes: unused bits SBZ */ } param_header_t; The structures using this format are ``entry_point_info``, ``image_info`` and ``bl31_params``. The code that allocates and populates these structures must set the header fields appropriately, and the ``SET_PARAM_HEAD()`` a macro is defined to simplify this action. Required CPU state for BL31 Warm boot initialization ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When requesting a CPU power-on, or suspending a running CPU, TF-A provides the platform power management code with a Warm boot initialization entry-point, to be invoked by the CPU immediately after the reset handler. On entry to the Warm boot initialization function the calling CPU must be in AArch64 EL3, little-endian data access and all interrupt sources masked: :: PSTATE.EL = 3 PSTATE.RW = 1 PSTATE.DAIF = 0xf SCTLR_EL3.EE = 0 The PSCI implementation will initialize the processor state and ensure that the platform power management code is then invoked as required to initialize all necessary system, cluster and CPU resources. AArch32 EL3 Runtime Software entrypoint interface ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To enable this firmware architecture it is important to provide a fully documented and stable interface between the Trusted Boot Firmware and the AArch32 EL3 Runtime Software. Future changes to the entrypoint interface will be done in a backwards compatible way, and this enables these firmware components to be independently enhanced/updated to develop and exploit new functionality. Required CPU state when entering during cold boot ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This function must only be called by the primary CPU. On entry to this function the calling primary CPU must be executing in AArch32 EL3, little-endian data access, and all interrupt sources masked: :: PSTATE.AIF = 0x7 SCTLR.EE = 0 R0 and R1 are used to pass information from the Trusted Boot Firmware to the platform code in AArch32 EL3 Runtime Software: :: R0 : Reserved for common TF-A information R1 : Platform specific information Use of the R0 and R1 parameters ''''''''''''''''''''''''''''''' The parameters are platform specific and the convention is that ``R0`` conveys information regarding the BL3x images from the Trusted Boot firmware and ``R1`` can be used for other platform specific purpose. This convention allows platforms which use TF-A's BL1 and BL2 images to transfer additional platform specific information from Secure Boot without conflicting with future evolution of TF-A using ``R0`` to pass a ``bl_params`` structure. The AArch32 EL3 Runtime Software is responsible for entry into BL33. This information can be obtained in a platform defined manner, e.g. compiled into the AArch32 EL3 Runtime Software, or provided in a platform defined memory location by the Trusted Boot firmware, or passed from the Trusted Boot Firmware via the Cold boot Initialization parameters. This data may need to be cleaned out of the CPU caches if it is provided by an earlier boot stage and then accessed by AArch32 EL3 Runtime Software before the caches are enabled. When using AArch32 EL3 Runtime Software, the Arm development platforms pass a ``bl_params`` structure in ``R0`` from BL2 to be interpreted by AArch32 EL3 Runtime Software platform code. MMU, Data caches & Coherency '''''''''''''''''''''''''''' AArch32 EL3 Runtime Software must not depend on the enabled state of the MMU, data caches or interconnect coherency in its entrypoint. They must be explicitly enabled if required. Data structures used in cold boot interface ''''''''''''''''''''''''''''''''''''''''''' The AArch32 EL3 Runtime Software cold boot interface uses ``bl_params`` instead of ``bl31_params``. The ``bl_params`` structure is based on the convention described in AArch64 BL31 cold boot interface section. Required CPU state for warm boot initialization ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ When requesting a CPU power-on, or suspending a running CPU, AArch32 EL3 Runtime Software must ensure execution of a warm boot initialization entrypoint. If TF-A BL1 is used and the PROGRAMMABLE_RESET_ADDRESS build flag is false, then AArch32 EL3 Runtime Software must ensure that BL1 branches to the warm boot entrypoint by arranging for the BL1 platform function, plat_get_my_entrypoint(), to return a non-zero value. In this case, the warm boot entrypoint must be in AArch32 EL3, little-endian data access and all interrupt sources masked: :: PSTATE.AIF = 0x7 SCTLR.EE = 0 The warm boot entrypoint may be implemented by using TF-A ``psci_warmboot_entrypoint()`` function. In that case, the platform must fulfil the pre-requisites mentioned in the :ref:`PSCI Library Integration guide for Armv8-A AArch32 systems`. EL3 runtime services framework ------------------------------ Software executing in the non-secure state and in the secure state at exception levels lower than EL3 will request runtime services using the Secure Monitor Call (SMC) instruction. These requests will follow the convention described in the SMC Calling Convention PDD (`SMCCC`_). The `SMCCC`_ assigns function identifiers to each SMC request and describes how arguments are passed and returned. The EL3 runtime services framework enables the development of services by different providers that can be easily integrated into final product firmware. The following sections describe the framework which facilitates the registration, initialization and use of runtime services in EL3 Runtime Software (BL31). The design of the runtime services depends heavily on the concepts and definitions described in the `SMCCC`_, in particular SMC Function IDs, Owning Entity Numbers (OEN), Fast and Yielding calls, and the SMC32 and SMC64 calling conventions. Please refer to that document for more detailed explanation of these terms. The following runtime services are expected to be implemented first. They have not all been instantiated in the current implementation. #. Standard service calls This service is for management of the entire system. The Power State Coordination Interface (`PSCI`_) is the first set of standard service calls defined by Arm (see PSCI section later). #. Secure-EL1 Payload Dispatcher service If a system runs a Trusted OS or other Secure-EL1 Payload (SP) then it also requires a *Secure Monitor* at EL3 to switch the EL1 processor context between the normal world (EL1/EL2) and trusted world (Secure-EL1). The Secure Monitor will make these world switches in response to SMCs. The `SMCCC`_ provides for such SMCs with the Trusted OS Call and Trusted Application Call OEN ranges. The interface between the EL3 Runtime Software and the Secure-EL1 Payload is not defined by the `SMCCC`_ or any other standard. As a result, each Secure-EL1 Payload requires a specific Secure Monitor that runs as a runtime service - within TF-A this service is referred to as the Secure-EL1 Payload Dispatcher (SPD). TF-A provides a Test Secure-EL1 Payload (TSP) and its associated Dispatcher (TSPD). Details of SPD design and TSP/TSPD operation are described in the "Secure-EL1 Payloads and Dispatchers" section below. #. CPU implementation service This service will provide an interface to CPU implementation specific services for a given platform e.g. access to processor errata workarounds. This service is currently unimplemented. Additional services for Arm Architecture, SiP and OEM calls can be implemented. Each implemented service handles a range of SMC function identifiers as described in the `SMCCC`_. Registration ~~~~~~~~~~~~ A runtime service is registered using the ``DECLARE_RT_SVC()`` macro, specifying the name of the service, the range of OENs covered, the type of service and initialization and call handler functions. This macro instantiates a ``const struct rt_svc_desc`` for the service with these details (see ``runtime_svc.h``). This structure is allocated in a special ELF section ``rt_svc_descs``, enabling the framework to find all service descriptors included into BL31. The specific service for a SMC Function is selected based on the OEN and call type of the Function ID, and the framework uses that information in the service descriptor to identify the handler for the SMC Call. The service descriptors do not include information to identify the precise set of SMC function identifiers supported by this service implementation, the security state from which such calls are valid nor the capability to support 64-bit and/or 32-bit callers (using SMC32 or SMC64). Responding appropriately to these aspects of a SMC call is the responsibility of the service implementation, the framework is focused on integration of services from different providers and minimizing the time taken by the framework before the service handler is invoked. Details of the parameters, requirements and behavior of the initialization and call handling functions are provided in the following sections. Initialization ~~~~~~~~~~~~~~ ``runtime_svc_init()`` in ``runtime_svc.c`` initializes the runtime services framework running on the primary CPU during cold boot as part of the BL31 initialization. This happens prior to initializing a Trusted OS and running Normal world boot firmware that might in turn use these services. Initialization involves validating each of the declared runtime service descriptors, calling the service initialization function and populating the index used for runtime lookup of the service. The BL31 linker script collects all of the declared service descriptors into a single array and defines symbols that allow the framework to locate and traverse the array, and determine its size. The framework does basic validation of each descriptor to halt firmware initialization if service declaration errors are detected. The framework does not check descriptors for the following error conditions, and may behave in an unpredictable manner under such scenarios: #. Overlapping OEN ranges #. Multiple descriptors for the same range of OENs and ``call_type`` #. Incorrect range of owning entity numbers for a given ``call_type`` Once validated, the service ``init()`` callback is invoked. This function carries out any essential EL3 initialization before servicing requests. The ``init()`` function is only invoked on the primary CPU during cold boot. If the service uses per-CPU data this must either be initialized for all CPUs during this call, or be done lazily when a CPU first issues an SMC call to that service. If ``init()`` returns anything other than ``0``, this is treated as an initialization error and the service is ignored: this does not cause the firmware to halt. The OEN and call type fields present in the SMC Function ID cover a total of 128 distinct services, but in practice a single descriptor can cover a range of OENs, e.g. SMCs to call a Trusted OS function. To optimize the lookup of a service handler, the framework uses an array of 128 indices that map every distinct OEN/call-type combination either to one of the declared services or to indicate the service is not handled. This ``rt_svc_descs_indices[]`` array is populated for all of the OENs covered by a service after the service ``init()`` function has reported success. So a service that fails to initialize will never have it's ``handle()`` function invoked. The following figure shows how the ``rt_svc_descs_indices[]`` index maps the SMC Function ID call type and OEN onto a specific service handler in the ``rt_svc_descs[]`` array. |Image 1| Handling an SMC ~~~~~~~~~~~~~~~ When the EL3 runtime services framework receives a Secure Monitor Call, the SMC Function ID is passed in W0 from the lower exception level (as per the `SMCCC`_). If the calling register width is AArch32, it is invalid to invoke an SMC Function which indicates the SMC64 calling convention: such calls are ignored and return the Unknown SMC Function Identifier result code ``0xFFFFFFFF`` in R0/X0. Bit[31] (fast/yielding call) and bits[29:24] (owning entity number) of the SMC Function ID are combined to index into the ``rt_svc_descs_indices[]`` array. The resulting value might indicate a service that has no handler, in this case the framework will also report an Unknown SMC Function ID. Otherwise, the value is used as a further index into the ``rt_svc_descs[]`` array to locate the required service and handler. The service's ``handle()`` callback is provided with five of the SMC parameters directly, the others are saved into memory for retrieval (if needed) by the handler. The handler is also provided with an opaque ``handle`` for use with the supporting library for parameter retrieval, setting return values and context manipulation; and with ``flags`` indicating the security state of the caller. The framework finally sets up the execution stack for the handler, and invokes the services ``handle()`` function. On return from the handler the result registers are populated in X0-X3 before restoring the stack and CPU state and returning from the original SMC. Exception Handling Framework ---------------------------- Please refer to the `Exception Handling Framework`_ document. Power State Coordination Interface ---------------------------------- TODO: Provide design walkthrough of PSCI implementation. The PSCI v1.1 specification categorizes APIs as optional and mandatory. All the mandatory APIs in PSCI v1.1, PSCI v1.0 and in PSCI v0.2 draft specification `Power State Coordination Interface PDD`_ are implemented. The table lists the PSCI v1.1 APIs and their support in generic code. An API implementation might have a dependency on platform code e.g. CPU_SUSPEND requires the platform to export a part of the implementation. Hence the level of support of the mandatory APIs depends upon the support exported by the platform port as well. The Juno and FVP (all variants) platforms export all the required support. +-----------------------------+-------------+-------------------------------+ | PSCI v1.1 API | Supported | Comments | +=============================+=============+===============================+ | ``PSCI_VERSION`` | Yes | The version returned is 1.1 | +-----------------------------+-------------+-------------------------------+ | ``CPU_SUSPEND`` | Yes\* | | +-----------------------------+-------------+-------------------------------+ | ``CPU_OFF`` | Yes\* | | +-----------------------------+-------------+-------------------------------+ | ``CPU_ON`` | Yes\* | | +-----------------------------+-------------+-------------------------------+ | ``AFFINITY_INFO`` | Yes | | +-----------------------------+-------------+-------------------------------+ | ``MIGRATE`` | Yes\*\* | | +-----------------------------+-------------+-------------------------------+ | ``MIGRATE_INFO_TYPE`` | Yes\*\* | | +-----------------------------+-------------+-------------------------------+ | ``MIGRATE_INFO_CPU`` | Yes\*\* | | +-----------------------------+-------------+-------------------------------+ | ``SYSTEM_OFF`` | Yes\* | | +-----------------------------+-------------+-------------------------------+ | ``SYSTEM_RESET`` | Yes\* | | +-----------------------------+-------------+-------------------------------+ | ``PSCI_FEATURES`` | Yes | | +-----------------------------+-------------+-------------------------------+ | ``CPU_FREEZE`` | No | | +-----------------------------+-------------+-------------------------------+ | ``CPU_DEFAULT_SUSPEND`` | No | | +-----------------------------+-------------+-------------------------------+ | ``NODE_HW_STATE`` | Yes\* | | +-----------------------------+-------------+-------------------------------+ | ``SYSTEM_SUSPEND`` | Yes\* | | +-----------------------------+-------------+-------------------------------+ | ``PSCI_SET_SUSPEND_MODE`` | No | | +-----------------------------+-------------+-------------------------------+ | ``PSCI_STAT_RESIDENCY`` | Yes\* | | +-----------------------------+-------------+-------------------------------+ | ``PSCI_STAT_COUNT`` | Yes\* | | +-----------------------------+-------------+-------------------------------+ | ``SYSTEM_RESET2`` | Yes\* | | +-----------------------------+-------------+-------------------------------+ | ``MEM_PROTECT`` | Yes\* | | +-----------------------------+-------------+-------------------------------+ | ``MEM_PROTECT_CHECK_RANGE`` | Yes\* | | +-----------------------------+-------------+-------------------------------+ \*Note : These PSCI APIs require platform power management hooks to be registered with the generic PSCI code to be supported. \*\*Note : These PSCI APIs require appropriate Secure Payload Dispatcher hooks to be registered with the generic PSCI code to be supported. The PSCI implementation in TF-A is a library which can be integrated with AArch64 or AArch32 EL3 Runtime Software for Armv8-A systems. A guide to integrating PSCI library with AArch32 EL3 Runtime Software can be found at :ref:`PSCI Library Integration guide for Armv8-A AArch32 systems`. .. _firmware_design_sel1_spd: Secure-EL1 Payloads and Dispatchers ----------------------------------- On a production system that includes a Trusted OS running in Secure-EL1/EL0, the Trusted OS is coupled with a companion runtime service in the BL31 firmware. This service is responsible for the initialisation of the Trusted OS and all communications with it. The Trusted OS is the BL32 stage of the boot flow in TF-A. The firmware will attempt to locate, load and execute a BL32 image. TF-A uses a more general term for the BL32 software that runs at Secure-EL1 - the *Secure-EL1 Payload* - as it is not always a Trusted OS. TF-A provides a Test Secure-EL1 Payload (TSP) and a Test Secure-EL1 Payload Dispatcher (TSPD) service as an example of how a Trusted OS is supported on a production system using the Runtime Services Framework. On such a system, the Test BL32 image and service are replaced by the Trusted OS and its dispatcher service. The TF-A build system expects that the dispatcher will define the build flag ``NEED_BL32`` to enable it to include the BL32 in the build either as a binary or to compile from source depending on whether the ``BL32`` build option is specified or not. The TSP runs in Secure-EL1. It is designed to demonstrate synchronous communication with the normal-world software running in EL1/EL2. Communication is initiated by the normal-world software - either directly through a Fast SMC (as defined in the `SMCCC`_) - or indirectly through a `PSCI`_ SMC. The `PSCI`_ implementation in turn informs the TSPD about the requested power management operation. This allows the TSP to prepare for or respond to the power state change The TSPD service is responsible for. - Initializing the TSP - Routing requests and responses between the secure and the non-secure states during the two types of communications just described Initializing a BL32 Image ~~~~~~~~~~~~~~~~~~~~~~~~~ The Secure-EL1 Payload Dispatcher (SPD) service is responsible for initializing the BL32 image. It needs access to the information passed by BL2 to BL31 to do so. This is provided by: .. code:: c entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t); which returns a reference to the ``entry_point_info`` structure corresponding to the image which will be run in the specified security state. The SPD uses this API to get entry point information for the SECURE image, BL32. In the absence of a BL32 image, BL31 passes control to the normal world bootloader image (BL33). When the BL32 image is present, it is typical that the SPD wants control to be passed to BL32 first and then later to BL33. To do this the SPD has to register a BL32 initialization function during initialization of the SPD service. The BL32 initialization function has this prototype: .. code:: c int32_t init(void); and is registered using the ``bl31_register_bl32_init()`` function. TF-A supports two approaches for the SPD to pass control to BL32 before returning through EL3 and running the non-trusted firmware (BL33): #. In the BL32 setup function, use ``bl31_set_next_image_type()`` to request that the exit from ``bl31_main()`` is to the BL32 entrypoint in Secure-EL1. BL31 will exit to BL32 using the asynchronous method by calling ``bl31_prepare_next_image_entry()`` and ``el3_exit()``. When the BL32 has completed initialization at Secure-EL1, it returns to BL31 by issuing an SMC, using a Function ID allocated to the SPD. On receipt of this SMC, the SPD service handler should switch the CPU context from trusted to normal world and use the ``bl31_set_next_image_type()`` and ``bl31_prepare_next_image_entry()`` functions to set up the initial return to the normal world firmware BL33. On return from the handler the framework will exit to EL2 and run BL33. #. The BL32 setup function registers an initialization function using ``bl31_register_bl32_init()`` which provides a SPD-defined mechanism to invoke a 'world-switch synchronous call' to Secure-EL1 to run the BL32 entrypoint. .. note:: The Test SPD service included with TF-A provides one implementation of such a mechanism. On completion BL32 returns control to BL31 via a SMC, and on receipt the SPD service handler invokes the synchronous call return mechanism to return to the BL32 initialization function. On return from this function, ``bl31_main()`` will set up the return to the normal world firmware BL33 and continue the boot process in the normal world. Crash Reporting in BL31 ----------------------- BL31 implements a scheme for reporting the processor state when an unhandled exception is encountered. The reporting mechanism attempts to preserve all the register contents and report it via a dedicated UART (PL011 console). BL31 reports the general purpose, EL3, Secure EL1 and some EL2 state registers. A dedicated per-CPU crash stack is maintained by BL31 and this is retrieved via the per-CPU pointer cache. The implementation attempts to minimise the memory required for this feature. The file ``crash_reporting.S`` contains the implementation for crash reporting. The sample crash output is shown below. :: x0 :0x000000004F00007C x1 :0x0000000007FFFFFF x2 :0x0000000004014D50 x3 :0x0000000000000000 x4 :0x0000000088007998 x5 :0x00000000001343AC x6 :0x0000000000000016 x7 :0x00000000000B8A38 x8 :0x00000000001343AC x9 :0x00000000000101A8 x10 :0x0000000000000002 x11 :0x000000000000011C x12 :0x00000000FEFDC644 x13 :0x00000000FED93FFC x14 :0x0000000000247950 x15 :0x00000000000007A2 x16 :0x00000000000007A4 x17 :0x0000000000247950 x18 :0x0000000000000000 x19 :0x00000000FFFFFFFF x20 :0x0000000004014D50 x21 :0x000000000400A38C x22 :0x0000000000247950 x23 :0x0000000000000010 x24 :0x0000000000000024 x25 :0x00000000FEFDC868 x26 :0x00000000FEFDC86A x27 :0x00000000019EDEDC x28 :0x000000000A7CFDAA x29 :0x0000000004010780 x30 :0x000000000400F004 scr_el3 :0x0000000000000D3D sctlr_el3 :0x0000000000C8181F cptr_el3 :0x0000000000000000 tcr_el3 :0x0000000080803520 daif :0x00000000000003C0 mair_el3 :0x00000000000004FF spsr_el3 :0x00000000800003CC elr_el3 :0x000000000400C0CC ttbr0_el3 :0x00000000040172A0 esr_el3 :0x0000000096000210 sp_el3 :0x0000000004014D50 far_el3 :0x000000004F00007C spsr_el1 :0x0000000000000000 elr_el1 :0x0000000000000000 spsr_abt :0x0000000000000000 spsr_und :0x0000000000000000 spsr_irq :0x0000000000000000 spsr_fiq :0x0000000000000000 sctlr_el1 :0x0000000030C81807 actlr_el1 :0x0000000000000000 cpacr_el1 :0x0000000000300000 csselr_el1 :0x0000000000000002 sp_el1 :0x0000000004028800 esr_el1 :0x0000000000000000 ttbr0_el1 :0x000000000402C200 ttbr1_el1 :0x0000000000000000 mair_el1 :0x00000000000004FF amair_el1 :0x0000000000000000 tcr_el1 :0x0000000000003520 tpidr_el1 :0x0000000000000000 tpidr_el0 :0x0000000000000000 tpidrro_el0 :0x0000000000000000 dacr32_el2 :0x0000000000000000 ifsr32_el2 :0x0000000000000000 par_el1 :0x0000000000000000 far_el1 :0x0000000000000000 afsr0_el1 :0x0000000000000000 afsr1_el1 :0x0000000000000000 contextidr_el1 :0x0000000000000000 vbar_el1 :0x0000000004027000 cntp_ctl_el0 :0x0000000000000000 cntp_cval_el0 :0x0000000000000000 cntv_ctl_el0 :0x0000000000000000 cntv_cval_el0 :0x0000000000000000 cntkctl_el1 :0x0000000000000000 sp_el0 :0x0000000004010780 Guidelines for Reset Handlers ----------------------------- TF-A implements a framework that allows CPU and platform ports to perform actions very early after a CPU is released from reset in both the cold and warm boot paths. This is done by calling the ``reset_handler()`` function in both the BL1 and BL31 images. It in turn calls the platform and CPU specific reset handling functions. Details for implementing a CPU specific reset handler can be found in Section 8. Details for implementing a platform specific reset handler can be found in the :ref:`Porting Guide` (see the ``plat_reset_handler()`` function). When adding functionality to a reset handler, keep in mind that if a different reset handling behavior is required between the first and the subsequent invocations of the reset handling code, this should be detected at runtime. In other words, the reset handler should be able to detect whether an action has already been performed and act as appropriate. Possible courses of actions are, e.g. skip the action the second time, or undo/redo it. Configuring secure interrupts ----------------------------- The GIC driver is responsible for performing initial configuration of secure interrupts on the platform. To this end, the platform is expected to provide the GIC driver (either GICv2 or GICv3, as selected by the platform) with the interrupt configuration during the driver initialisation. Secure interrupt configuration are specified in an array of secure interrupt properties. In this scheme, in both GICv2 and GICv3 driver data structures, the ``interrupt_props`` member points to an array of interrupt properties. Each element of the array specifies the interrupt number and its attributes (priority, group, configuration). Each element of the array shall be populated by the macro ``INTR_PROP_DESC()``. The macro takes the following arguments: - 10-bit interrupt number, - 8-bit interrupt priority, - Interrupt type (one of ``INTR_TYPE_EL3``, ``INTR_TYPE_S_EL1``, ``INTR_TYPE_NS``), - Interrupt configuration (either ``GIC_INTR_CFG_LEVEL`` or ``GIC_INTR_CFG_EDGE``). .. _firmware_design_cpu_ops_fwk: CPU specific operations framework --------------------------------- Certain aspects of the Armv8-A architecture are implementation defined, that is, certain behaviours are not architecturally defined, but must be defined and documented by individual processor implementations. TF-A implements a framework which categorises the common implementation defined behaviours and allows a processor to export its implementation of that behaviour. The categories are: #. Processor specific reset sequence. #. Processor specific power down sequences. #. Processor specific register dumping as a part of crash reporting. #. Errata status reporting. Each of the above categories fulfils a different requirement. #. allows any processor specific initialization before the caches and MMU are turned on, like implementation of errata workarounds, entry into the intra-cluster coherency domain etc. #. allows each processor to implement the power down sequence mandated in its Technical Reference Manual (TRM). #. allows a processor to provide additional information to the developer in the event of a crash, for example Cortex-A53 has registers which can expose the data cache contents. #. allows a processor to define a function that inspects and reports the status of all errata workarounds on that processor. Please note that only 2. is mandated by the TRM. The CPU specific operations framework scales to accommodate a large number of different CPUs during power down and reset handling. The platform can specify any CPU optimization it wants to enable for each CPU. It can also specify the CPU errata workarounds to be applied for each CPU type during reset handling by defining CPU errata compile time macros. Details on these macros can be found in the :ref:`Arm CPU Specific Build Macros` document. The CPU specific operations framework depends on the ``cpu_ops`` structure which needs to be exported for each type of CPU in the platform. It is defined in ``include/lib/cpus/aarch64/cpu_macros.S`` and has the following fields : ``midr``, ``reset_func()``, ``cpu_pwr_down_ops`` (array of power down functions) and ``cpu_reg_dump()``. The CPU specific files in ``lib/cpus`` export a ``cpu_ops`` data structure with suitable handlers for that CPU. For example, ``lib/cpus/aarch64/cortex_a53.S`` exports the ``cpu_ops`` for Cortex-A53 CPU. According to the platform configuration, these CPU specific files must be included in the build by the platform makefile. The generic CPU specific operations framework code exists in ``lib/cpus/aarch64/cpu_helpers.S``. CPU specific Reset Handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~ After a reset, the state of the CPU when it calls generic reset handler is: MMU turned off, both instruction and data caches turned off and not part of any coherency domain. The BL entrypoint code first invokes the ``plat_reset_handler()`` to allow the platform to perform any system initialization required and any system errata workarounds that needs to be applied. The ``get_cpu_ops_ptr()`` reads the current CPU midr, finds the matching ``cpu_ops`` entry in the ``cpu_ops`` array and returns it. Note that only the part number and implementer fields in midr are used to find the matching ``cpu_ops`` entry. The ``reset_func()`` in the returned ``cpu_ops`` is then invoked which executes the required reset handling for that CPU and also any errata workarounds enabled by the platform. This function must preserve the values of general purpose registers x20 to x29. Refer to Section "Guidelines for Reset Handlers" for general guidelines regarding placement of code in a reset handler. CPU specific power down sequence ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ During the BL31 initialization sequence, the pointer to the matching ``cpu_ops`` entry is stored in per-CPU data by ``init_cpu_ops()`` so that it can be quickly retrieved during power down sequences. Various CPU drivers register handlers to perform power down at certain power levels for that specific CPU. The PSCI service, upon receiving a power down request, determines the highest power level at which to execute power down sequence for a particular CPU. It uses the ``prepare_cpu_pwr_dwn()`` function to pick the right power down handler for the requested level. The function retrieves ``cpu_ops`` pointer member of per-CPU data, and from that, further retrieves ``cpu_pwr_down_ops`` array, and indexes into the required level. If the requested power level is higher than what a CPU driver supports, the handler registered for highest level is invoked. At runtime the platform hooks for power down are invoked by the PSCI service to perform platform specific operations during a power down sequence, for example turning off CCI coherency during a cluster power down. CPU specific register reporting during crash ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ If the crash reporting is enabled in BL31, when a crash occurs, the crash reporting framework calls ``do_cpu_reg_dump`` which retrieves the matching ``cpu_ops`` using ``get_cpu_ops_ptr()`` function. The ``cpu_reg_dump()`` in ``cpu_ops`` is invoked, which then returns the CPU specific register values to be reported and a pointer to the ASCII list of register names in a format expected by the crash reporting framework. .. _firmware_design_cpu_errata_reporting: CPU errata status reporting ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Errata workarounds for CPUs supported in TF-A are applied during both cold and warm boots, shortly after reset. Individual Errata workarounds are enabled as build options. Some errata workarounds have potential run-time implications; therefore some are enabled by default, others not. Platform ports shall override build options to enable or disable errata as appropriate. The CPU drivers take care of applying errata workarounds that are enabled and applicable to a given CPU. Refer to :ref:`arm_cpu_macros_errata_workarounds` for more information. Functions in CPU drivers that apply errata workaround must follow the conventions listed below. The errata workaround must be authored as two separate functions: - One that checks for errata. This function must determine whether that errata applies to the current CPU. Typically this involves matching the current CPUs revision and variant against a value that's known to be affected by the errata. If the function determines that the errata applies to this CPU, it must return ``ERRATA_APPLIES``; otherwise, it must return ``ERRATA_NOT_APPLIES``. The utility functions ``cpu_get_rev_var`` and ``cpu_rev_var_ls`` functions may come in handy for this purpose. For an errata identified as ``E``, the check function must be named ``check_errata_E``. This function will be invoked at different times, both from assembly and from C run time. Therefore it must follow AAPCS, and must not use stack. - Another one that applies the errata workaround. This function would call the check function described above, and applies errata workaround if required. CPU drivers that apply errata workaround can optionally implement an assembly function that report the status of errata workarounds pertaining to that CPU. For a driver that registers the CPU, for example, ``cpux`` via ``declare_cpu_ops`` macro, the errata reporting function, if it exists, must be named ``cpux_errata_report``. This function will always be called with MMU enabled; it must follow AAPCS and may use stack. In a debug build of TF-A, on a CPU that comes out of reset, both BL1 and the runtime firmware (BL31 in AArch64, and BL32 in AArch32) will invoke errata status reporting function, if one exists, for that type of CPU. To report the status of each errata workaround, the function shall use the assembler macro ``report_errata``, passing it: - The build option that enables the errata; - The name of the CPU: this must be the same identifier that CPU driver registered itself with, using ``declare_cpu_ops``; - And the errata identifier: the identifier must match what's used in the errata's check function described above. The errata status reporting function will be called once per CPU type/errata combination during the software's active life time. It's expected that whenever an errata workaround is submitted to TF-A, the errata reporting function is appropriately extended to report its status as well. Reporting the status of errata workaround is for informational purpose only; it has no functional significance. Memory layout of BL images -------------------------- Each bootloader image can be divided in 2 parts: - the static contents of the image. These are data actually stored in the binary on the disk. In the ELF terminology, they are called ``PROGBITS`` sections; - the run-time contents of the image. These are data that don't occupy any space in the binary on the disk. The ELF binary just contains some metadata indicating where these data will be stored at run-time and the corresponding sections need to be allocated and initialized at run-time. In the ELF terminology, they are called ``NOBITS`` sections. All PROGBITS sections are grouped together at the beginning of the image, followed by all NOBITS sections. This is true for all TF-A images and it is governed by the linker scripts. This ensures that the raw binary images are as small as possible. If a NOBITS section was inserted in between PROGBITS sections then the resulting binary file would contain zero bytes in place of this NOBITS section, making the image unnecessarily bigger. Smaller images allow faster loading from the FIP to the main memory. Linker scripts and symbols ~~~~~~~~~~~~~~~~~~~~~~~~~~ Each bootloader stage image layout is described by its own linker script. The linker scripts export some symbols into the program symbol table. Their values correspond to particular addresses. TF-A code can refer to these symbols to figure out the image memory layout. Linker symbols follow the following naming convention in TF-A. - ``__
_START__`` Start address of a given section named ``
``. - ``__
_END__`` End address of a given section named ``
``. If there is an alignment constraint on the section's end address then ``__
_END__`` corresponds to the end address of the section's actual contents, rounded up to the right boundary. Refer to the value of ``__
_UNALIGNED_END__`` to know the actual end address of the section's contents. - ``__
_UNALIGNED_END__`` End address of a given section named ``
`` without any padding or rounding up due to some alignment constraint. - ``__
_SIZE__`` Size (in bytes) of a given section named ``
``. If there is an alignment constraint on the section's end address then ``__
_SIZE__`` corresponds to the size of the section's actual contents, rounded up to the right boundary. In other words, ``__
_SIZE__ = __
_END__ - _
_START__``. Refer to the value of ``__
_UNALIGNED_SIZE__`` to know the actual size of the section's contents. - ``__
_UNALIGNED_SIZE__`` Size (in bytes) of a given section named ``
`` without any padding or rounding up due to some alignment constraint. In other words, ``__
_UNALIGNED_SIZE__ = __
_UNALIGNED_END__ - __
_START__``. Some of the linker symbols are mandatory as TF-A code relies on them to be defined. They are listed in the following subsections. Some of them must be provided for each bootloader stage and some are specific to a given bootloader stage. The linker scripts define some extra, optional symbols. They are not actually used by any code but they help in understanding the bootloader images' memory layout as they are easy to spot in the link map files. Common linker symbols ^^^^^^^^^^^^^^^^^^^^^ All BL images share the following requirements: - The BSS section must be zero-initialised before executing any C code. - The coherent memory section (if enabled) must be zero-initialised as well. - The MMU setup code needs to know the extents of the coherent and read-only memory regions to set the right memory attributes. When ``SEPARATE_CODE_AND_RODATA=1``, it needs to know more specifically how the read-only memory region is divided between code and data. The following linker symbols are defined for this purpose: - ``__BSS_START__`` - ``__BSS_SIZE__`` - ``__COHERENT_RAM_START__`` Must be aligned on a page-size boundary. - ``__COHERENT_RAM_END__`` Must be aligned on a page-size boundary. - ``__COHERENT_RAM_UNALIGNED_SIZE__`` - ``__RO_START__`` - ``__RO_END__`` - ``__TEXT_START__`` - ``__TEXT_END__`` - ``__RODATA_START__`` - ``__RODATA_END__`` BL1's linker symbols ^^^^^^^^^^^^^^^^^^^^ BL1 being the ROM image, it has additional requirements. BL1 resides in ROM and it is entirely executed in place but it needs some read-write memory for its mutable data. Its ``.data`` section (i.e. its allocated read-write data) must be relocated from ROM to RAM before executing any C code. The following additional linker symbols are defined for BL1: - ``__BL1_ROM_END__`` End address of BL1's ROM contents, covering its code and ``.data`` section in ROM. - ``__DATA_ROM_START__`` Start address of the ``.data`` section in ROM. Must be aligned on a 16-byte boundary. - ``__DATA_RAM_START__`` Address in RAM where the ``.data`` section should be copied over. Must be aligned on a 16-byte boundary. - ``__DATA_SIZE__`` Size of the ``.data`` section (in ROM or RAM). - ``__BL1_RAM_START__`` Start address of BL1 read-write data. - ``__BL1_RAM_END__`` End address of BL1 read-write data. How to choose the right base addresses for each bootloader stage image ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ There is currently no support for dynamic image loading in TF-A. This means that all bootloader images need to be linked against their ultimate runtime locations and the base addresses of each image must be chosen carefully such that images don't overlap each other in an undesired way. As the code grows, the base addresses might need adjustments to cope with the new memory layout. The memory layout is completely specific to the platform and so there is no general recipe for choosing the right base addresses for each bootloader image. However, there are tools to aid in understanding the memory layout. These are the link map files: ``build///bl/bl.map``, with ```` being the stage bootloader. They provide a detailed view of the memory usage of each image. Among other useful information, they provide the end address of each image. - ``bl1.map`` link map file provides ``__BL1_RAM_END__`` address. - ``bl2.map`` link map file provides ``__BL2_END__`` address. - ``bl31.map`` link map file provides ``__BL31_END__`` address. - ``bl32.map`` link map file provides ``__BL32_END__`` address. For each bootloader image, the platform code must provide its start address as well as a limit address that it must not overstep. The latter is used in the linker scripts to check that the image doesn't grow past that address. If that happens, the linker will issue a message similar to the following: :: aarch64-none-elf-ld: BLx has exceeded its limit. Additionally, if the platform memory layout implies some image overlaying like on FVP, BL31 and TSP need to know the limit address that their PROGBITS sections must not overstep. The platform code must provide those. TF-A does not provide any mechanism to verify at boot time that the memory to load a new image is free to prevent overwriting a previously loaded image. The platform must specify the memory available in the system for all the relevant BL images to be loaded. For example, in the case of BL1 loading BL2, ``bl1_plat_sec_mem_layout()`` will return the region defined by the platform where BL1 intends to load BL2. The ``load_image()`` function performs bounds check for the image size based on the base and maximum image size provided by the platforms. Platforms must take this behaviour into account when defining the base/size for each of the images. Memory layout on Arm development platforms ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The following list describes the memory layout on the Arm development platforms: - A 4KB page of shared memory is used for communication between Trusted Firmware and the platform's power controller. This is located at the base of Trusted SRAM. The amount of Trusted SRAM available to load the bootloader images is reduced by the size of the shared memory. The shared memory is used to store the CPUs' entrypoint mailbox. On Juno, this is also used for the MHU payload when passing messages to and from the SCP. - Another 4 KB page is reserved for passing memory layout between BL1 and BL2 and also the dynamic firmware configurations. - On FVP, BL1 is originally sitting in the Trusted ROM at address ``0x0``. On Juno, BL1 resides in flash memory at address ``0x0BEC0000``. BL1 read-write data are relocated to the top of Trusted SRAM at runtime. - BL2 is loaded below BL1 RW - EL3 Runtime Software, BL31 for AArch64 and BL32 for AArch32 (e.g. SP_MIN), is loaded at the top of the Trusted SRAM, such that its NOBITS sections will overwrite BL1 R/W data and BL2. This implies that BL1 global variables remain valid only until execution reaches the EL3 Runtime Software entry point during a cold boot. - On Juno, SCP_BL2 is loaded temporarily into the EL3 Runtime Software memory region and transferred to the SCP before being overwritten by EL3 Runtime Software. - BL32 (for AArch64) can be loaded in one of the following locations: - Trusted SRAM - Trusted DRAM (FVP only) - Secure region of DRAM (top 16MB of DRAM configured by the TrustZone controller) When BL32 (for AArch64) is loaded into Trusted SRAM, it is loaded below BL31. The location of the BL32 image will result in different memory maps. This is illustrated for both FVP and Juno in the following diagrams, using the TSP as an example. .. note:: Loading the BL32 image in TZC secured DRAM doesn't change the memory layout of the other images in Trusted SRAM. CONFIG section in memory layouts shown below contains: :: +--------------------+ |bl2_mem_params_descs| |--------------------| | fw_configs | +--------------------+ ``bl2_mem_params_descs`` contains parameters passed from BL2 to next the BL image during boot. ``fw_configs`` includes soc_fw_config, tos_fw_config and tb_fw_config. **FVP with TSP in Trusted SRAM with firmware configs :** (These diagrams only cover the AArch64 case) :: DRAM 0xffffffff +----------+ : : |----------| |HW_CONFIG | 0x83000000 |----------| (non-secure) | | 0x80000000 +----------+ Trusted SRAM 0x04040000 +----------+ loaded by BL2 +----------------+ | BL1 (rw) | <<<<<<<<<<<<< | | |----------| <<<<<<<<<<<<< | BL31 NOBITS | | BL2 | <<<<<<<<<<<<< | | |----------| <<<<<<<<<<<<< |----------------| | | <<<<<<<<<<<<< | BL31 PROGBITS | | | <<<<<<<<<<<<< |----------------| | | <<<<<<<<<<<<< | BL32 | 0x04002000 +----------+ +----------------+ | CONFIG | 0x04001000 +----------+ | Shared | 0x04000000 +----------+ Trusted ROM 0x04000000 +----------+ | BL1 (ro) | 0x00000000 +----------+ **FVP with TSP in Trusted DRAM with firmware configs (default option):** :: DRAM 0xffffffff +--------------+ : : |--------------| | HW_CONFIG | 0x83000000 |--------------| (non-secure) | | 0x80000000 +--------------+ Trusted DRAM 0x08000000 +--------------+ | BL32 | 0x06000000 +--------------+ Trusted SRAM 0x04040000 +--------------+ loaded by BL2 +----------------+ | BL1 (rw) | <<<<<<<<<<<<< | | |--------------| <<<<<<<<<<<<< | BL31 NOBITS | | BL2 | <<<<<<<<<<<<< | | |--------------| <<<<<<<<<<<<< |----------------| | | <<<<<<<<<<<<< | BL31 PROGBITS | | | +----------------+ +--------------+ | CONFIG | 0x04001000 +--------------+ | Shared | 0x04000000 +--------------+ Trusted ROM 0x04000000 +--------------+ | BL1 (ro) | 0x00000000 +--------------+ **FVP with TSP in TZC-Secured DRAM with firmware configs :** :: DRAM 0xffffffff +----------+ | BL32 | (secure) 0xff000000 +----------+ | | |----------| |HW_CONFIG | 0x83000000 |----------| (non-secure) | | 0x80000000 +----------+ Trusted SRAM 0x04040000 +----------+ loaded by BL2 +----------------+ | BL1 (rw) | <<<<<<<<<<<<< | | |----------| <<<<<<<<<<<<< | BL31 NOBITS | | BL2 | <<<<<<<<<<<<< | | |----------| <<<<<<<<<<<<< |----------------| | | <<<<<<<<<<<<< | BL31 PROGBITS | | | +----------------+ 0x04002000 +----------+ | CONFIG | 0x04001000 +----------+ | Shared | 0x04000000 +----------+ Trusted ROM 0x04000000 +----------+ | BL1 (ro) | 0x00000000 +----------+ **Juno with BL32 in Trusted SRAM :** :: Flash0 0x0C000000 +----------+ : : 0x0BED0000 |----------| | BL1 (ro) | 0x0BEC0000 |----------| : : 0x08000000 +----------+ BL31 is loaded after SCP_BL2 has Trusted SRAM been sent to SCP 0x04040000 +----------+ loaded by BL2 +----------------+ | BL1 (rw) | <<<<<<<<<<<<< | | |----------| <<<<<<<<<<<<< | BL31 NOBITS | | BL2 | <<<<<<<<<<<<< | | |----------| <<<<<<<<<<<<< |----------------| | SCP_BL2 | <<<<<<<<<<<<< | BL31 PROGBITS | |----------| <<<<<<<<<<<<< |----------------| | | <<<<<<<<<<<<< | BL32 | | | +----------------+ | | 0x04001000 +----------+ | MHU | 0x04000000 +----------+ **Juno with BL32 in TZC-secured DRAM :** :: DRAM 0xFFE00000 +----------+ | BL32 | (secure) 0xFF000000 |----------| | | : : (non-secure) | | 0x80000000 +----------+ Flash0 0x0C000000 +----------+ : : 0x0BED0000 |----------| | BL1 (ro) | 0x0BEC0000 |----------| : : 0x08000000 +----------+ BL31 is loaded after SCP_BL2 has Trusted SRAM been sent to SCP 0x04040000 +----------+ loaded by BL2 +----------------+ | BL1 (rw) | <<<<<<<<<<<<< | | |----------| <<<<<<<<<<<<< | BL31 NOBITS | | BL2 | <<<<<<<<<<<<< | | |----------| <<<<<<<<<<<<< |----------------| | SCP_BL2 | <<<<<<<<<<<<< | BL31 PROGBITS | |----------| +----------------+ 0x04001000 +----------+ | MHU | 0x04000000 +----------+ Library at ROM --------------- Please refer to the :ref:`Library at ROM` document. Firmware Image Package (FIP) ---------------------------- Using a Firmware Image Package (FIP) allows for packing bootloader images (and potentially other payloads) into a single archive that can be loaded by TF-A from non-volatile platform storage. A driver to load images from a FIP has been added to the storage layer and allows a package to be read from supported platform storage. A tool to create Firmware Image Packages is also provided and described below. Firmware Image Package layout ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The FIP layout consists of a table of contents (ToC) followed by payload data. The ToC itself has a header followed by one or more table entries. The ToC is terminated by an end marker entry, and since the size of the ToC is 0 bytes, the offset equals the total size of the FIP file. All ToC entries describe some payload data that has been appended to the end of the binary package. With the information provided in the ToC entry the corresponding payload data can be retrieved. :: ------------------ | ToC Header | |----------------| | ToC Entry 0 | |----------------| | ToC Entry 1 | |----------------| | ToC End Marker | |----------------| | | | Data 0 | | | |----------------| | | | Data 1 | | | ------------------ The ToC header and entry formats are described in the header file ``include/tools_share/firmware_image_package.h``. This file is used by both the tool and TF-A. The ToC header has the following fields: :: `name`: The name of the ToC. This is currently used to validate the header. `serial_number`: A non-zero number provided by the creation tool `flags`: Flags associated with this data. Bits 0-31: Reserved Bits 32-47: Platform defined Bits 48-63: Reserved A ToC entry has the following fields: :: `uuid`: All files are referred to by a pre-defined Universally Unique IDentifier [UUID] . The UUIDs are defined in `include/tools_share/firmware_image_package.h`. The platform translates the requested image name into the corresponding UUID when accessing the package. `offset_address`: The offset address at which the corresponding payload data can be found. The offset is calculated from the ToC base address. `size`: The size of the corresponding payload data in bytes. `flags`: Flags associated with this entry. None are yet defined. Firmware Image Package creation tool ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The FIP creation tool can be used to pack specified images into a binary package that can be loaded by TF-A from platform storage. The tool currently only supports packing bootloader images. Additional image definitions can be added to the tool as required. The tool can be found in ``tools/fiptool``. Loading from a Firmware Image Package (FIP) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Firmware Image Package (FIP) driver can load images from a binary package on non-volatile platform storage. For the Arm development platforms, this is currently NOR FLASH. Bootloader images are loaded according to the platform policy as specified by the function ``plat_get_image_source()``. For the Arm development platforms, this means the platform will attempt to load images from a Firmware Image Package located at the start of NOR FLASH0. The Arm development platforms' policy is to only allow loading of a known set of images. The platform policy can be modified to allow additional images. Use of coherent memory in TF-A ------------------------------ There might be loss of coherency when physical memory with mismatched shareability, cacheability and memory attributes is accessed by multiple CPUs (refer to section B2.9 of `Arm ARM`_ for more details). This possibility occurs in TF-A during power up/down sequences when coherency, MMU and caches are turned on/off incrementally. TF-A defines coherent memory as a region of memory with Device nGnRE attributes in the translation tables. The translation granule size in TF-A is 4KB. This is the smallest possible size of the coherent memory region. By default, all data structures which are susceptible to accesses with mismatched attributes from various CPUs are allocated in a coherent memory region (refer to section 2.1 of :ref:`Porting Guide`). The coherent memory region accesses are Outer Shareable, non-cacheable and they can be accessed with the Device nGnRE attributes when the MMU is turned on. Hence, at the expense of at least an extra page of memory, TF-A is able to work around coherency issues due to mismatched memory attributes. The alternative to the above approach is to allocate the susceptible data structures in Normal WriteBack WriteAllocate Inner shareable memory. This approach requires the data structures to be designed so that it is possible to work around the issue of mismatched memory attributes by performing software cache maintenance on them. Disabling the use of coherent memory in TF-A ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ It might be desirable to avoid the cost of allocating coherent memory on platforms which are memory constrained. TF-A enables inclusion of coherent memory in firmware images through the build flag ``USE_COHERENT_MEM``. This flag is enabled by default. It can be disabled to choose the second approach described above. The below sections analyze the data structures allocated in the coherent memory region and the changes required to allocate them in normal memory. Coherent memory usage in PSCI implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``psci_non_cpu_pd_nodes`` data structure stores the platform's power domain tree information for state management of power domains. By default, this data structure is allocated in the coherent memory region in TF-A because it can be accessed by multiple CPUs, either with caches enabled or disabled. .. code:: c typedef struct non_cpu_pwr_domain_node { /* * Index of the first CPU power domain node level 0 which has this node * as its parent. */ unsigned int cpu_start_idx; /* * Number of CPU power domains which are siblings of the domain indexed * by 'cpu_start_idx' i.e. all the domains in the range 'cpu_start_idx * -> cpu_start_idx + ncpus' have this node as their parent. */ unsigned int ncpus; /* * Index of the parent power domain node. */ unsigned int parent_node; plat_local_state_t local_state; unsigned char level; /* For indexing the psci_lock array*/ unsigned char lock_index; } non_cpu_pd_node_t; In order to move this data structure to normal memory, the use of each of its fields must be analyzed. Fields like ``cpu_start_idx``, ``ncpus``, ``parent_node`` ``level`` and ``lock_index`` are only written once during cold boot. Hence removing them from coherent memory involves only doing a clean and invalidate of the cache lines after these fields are written. The field ``local_state`` can be concurrently accessed by multiple CPUs in different cache states. A Lamport's Bakery lock ``psci_locks`` is used to ensure mutual exclusion to this field and a clean and invalidate is needed after it is written. Bakery lock data ~~~~~~~~~~~~~~~~ The bakery lock data structure ``bakery_lock_t`` is allocated in coherent memory and is accessed by multiple CPUs with mismatched attributes. ``bakery_lock_t`` is defined as follows: .. code:: c typedef struct bakery_lock { /* * The lock_data is a bit-field of 2 members: * Bit[0] : choosing. This field is set when the CPU is * choosing its bakery number. * Bits[1 - 15] : number. This is the bakery number allocated. */ volatile uint16_t lock_data[BAKERY_LOCK_MAX_CPUS]; } bakery_lock_t; It is a characteristic of Lamport's Bakery algorithm that the volatile per-CPU fields can be read by all CPUs but only written to by the owning CPU. Depending upon the data cache line size, the per-CPU fields of the ``bakery_lock_t`` structure for multiple CPUs may exist on a single cache line. These per-CPU fields can be read and written during lock contention by multiple CPUs with mismatched memory attributes. Since these fields are a part of the lock implementation, they do not have access to any other locking primitive to safeguard against the resulting coherency issues. As a result, simple software cache maintenance is not enough to allocate them in coherent memory. Consider the following example. CPU0 updates its per-CPU field with data cache enabled. This write updates a local cache line which contains a copy of the fields for other CPUs as well. Now CPU1 updates its per-CPU field of the ``bakery_lock_t`` structure with data cache disabled. CPU1 then issues a DCIVAC operation to invalidate any stale copies of its field in any other cache line in the system. This operation will invalidate the update made by CPU0 as well. To use bakery locks when ``USE_COHERENT_MEM`` is disabled, the lock data structure has been redesigned. The changes utilise the characteristic of Lamport's Bakery algorithm mentioned earlier. The bakery_lock structure only allocates the memory for a single CPU. The macro ``DEFINE_BAKERY_LOCK`` allocates all the bakery locks needed for a CPU into a section ``bakery_lock``. The linker allocates the memory for other cores by using the total size allocated for the bakery_lock section and multiplying it with (PLATFORM_CORE_COUNT - 1). This enables software to perform software cache maintenance on the lock data structure without running into coherency issues associated with mismatched attributes. The bakery lock data structure ``bakery_info_t`` is defined for use when ``USE_COHERENT_MEM`` is disabled as follows: .. code:: c typedef struct bakery_info { /* * The lock_data is a bit-field of 2 members: * Bit[0] : choosing. This field is set when the CPU is * choosing its bakery number. * Bits[1 - 15] : number. This is the bakery number allocated. */ volatile uint16_t lock_data; } bakery_info_t; The ``bakery_info_t`` represents a single per-CPU field of one lock and the combination of corresponding ``bakery_info_t`` structures for all CPUs in the system represents the complete bakery lock. The view in memory for a system with n bakery locks are: :: bakery_lock section start |----------------| | `bakery_info_t`| <-- Lock_0 per-CPU field | Lock_0 | for CPU0 |----------------| | `bakery_info_t`| <-- Lock_1 per-CPU field | Lock_1 | for CPU0 |----------------| | .... | |----------------| | `bakery_info_t`| <-- Lock_N per-CPU field | Lock_N | for CPU0 ------------------ | XXXXX | | Padding to | | next Cache WB | <--- Calculate PERCPU_BAKERY_LOCK_SIZE, allocate | Granule | continuous memory for remaining CPUs. ------------------ | `bakery_info_t`| <-- Lock_0 per-CPU field | Lock_0 | for CPU1 |----------------| | `bakery_info_t`| <-- Lock_1 per-CPU field | Lock_1 | for CPU1 |----------------| | .... | |----------------| | `bakery_info_t`| <-- Lock_N per-CPU field | Lock_N | for CPU1 ------------------ | XXXXX | | Padding to | | next Cache WB | | Granule | ------------------ Consider a system of 2 CPUs with 'N' bakery locks as shown above. For an operation on Lock_N, the corresponding ``bakery_info_t`` in both CPU0 and CPU1 ``bakery_lock`` section need to be fetched and appropriate cache operations need to be performed for each access. On Arm Platforms, bakery locks are used in psci (``psci_locks``) and power controller driver (``arm_lock``). Non Functional Impact of removing coherent memory ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Removal of the coherent memory region leads to the additional software overhead of performing cache maintenance for the affected data structures. However, since the memory where the data structures are allocated is cacheable, the overhead is mostly mitigated by an increase in performance. There is however a performance impact for bakery locks, due to: - Additional cache maintenance operations, and - Multiple cache line reads for each lock operation, since the bakery locks for each CPU are distributed across different cache lines. The implementation has been optimized to minimize this additional overhead. Measurements indicate that when bakery locks are allocated in Normal memory, the minimum latency of acquiring a lock is on an average 3-4 micro seconds whereas in Device memory the same is 2 micro seconds. The measurements were done on the Juno Arm development platform. As mentioned earlier, almost a page of memory can be saved by disabling ``USE_COHERENT_MEM``. Each platform needs to consider these trade-offs to decide whether coherent memory should be used. If a platform disables ``USE_COHERENT_MEM`` and needs to use bakery locks in the porting layer, it can optionally define macro ``PLAT_PERCPU_BAKERY_LOCK_SIZE`` (see the :ref:`Porting Guide`). Refer to the reference platform code for examples. Isolating code and read-only data on separate memory pages ---------------------------------------------------------- In the Armv8-A VMSA, translation table entries include fields that define the properties of the target memory region, such as its access permissions. The smallest unit of memory that can be addressed by a translation table entry is a memory page. Therefore, if software needs to set different permissions on two memory regions then it needs to map them using different memory pages. The default memory layout for each BL image is as follows: :: | ... | +-------------------+ | Read-write data | +-------------------+ Page boundary | | +-------------------+ | Exception vectors | +-------------------+ 2 KB boundary | | +-------------------+ | Read-only data | +-------------------+ | Code | +-------------------+ BLx_BASE .. note:: The 2KB alignment for the exception vectors is an architectural requirement. The read-write data start on a new memory page so that they can be mapped with read-write permissions, whereas the code and read-only data below are configured as read-only. However, the read-only data are not aligned on a page boundary. They are contiguous to the code. Therefore, the end of the code section and the beginning of the read-only data one might share a memory page. This forces both to be mapped with the same memory attributes. As the code needs to be executable, this means that the read-only data stored on the same memory page as the code are executable as well. This could potentially be exploited as part of a security attack. TF provides the build flag ``SEPARATE_CODE_AND_RODATA`` to isolate the code and read-only data on separate memory pages. This in turn allows independent control of the access permissions for the code and read-only data. In this case, platform code gets a finer-grained view of the image layout and can appropriately map the code region as executable and the read-only data as execute-never. This has an impact on memory footprint, as padding bytes need to be introduced between the code and read-only data to ensure the segregation of the two. To limit the memory cost, this flag also changes the memory layout such that the code and exception vectors are now contiguous, like so: :: | ... | +-------------------+ | Read-write data | +-------------------+ Page boundary | | +-------------------+ | Read-only data | +-------------------+ Page boundary | | +-------------------+ | Exception vectors | +-------------------+ 2 KB boundary | | +-------------------+ | Code | +-------------------+ BLx_BASE With this more condensed memory layout, the separation of read-only data will add zero or one page to the memory footprint of each BL image. Each platform should consider the trade-off between memory footprint and security. This build flag is disabled by default, minimising memory footprint. On Arm platforms, it is enabled. Publish and Subscribe Framework ------------------------------- The Publish and Subscribe Framework allows EL3 components to define and publish events, to which other EL3 components can subscribe. The following macros are provided by the framework: - ``REGISTER_PUBSUB_EVENT(event)``: Defines an event, and takes one argument, the event name, which must be a valid C identifier. All calls to ``REGISTER_PUBSUB_EVENT`` macro must be placed in the file ``pubsub_events.h``. - ``PUBLISH_EVENT_ARG(event, arg)``: Publishes a defined event, by iterating subscribed handlers and calling them in turn. The handlers will be passed the parameter ``arg``. The expected use-case is to broadcast an event. - ``PUBLISH_EVENT(event)``: Like ``PUBLISH_EVENT_ARG``, except that the value ``NULL`` is passed to subscribed handlers. - ``SUBSCRIBE_TO_EVENT(event, handler)``: Registers the ``handler`` to subscribe to ``event``. The handler will be executed whenever the ``event`` is published. - ``for_each_subscriber(event, subscriber)``: Iterates through all handlers subscribed for ``event``. ``subscriber`` must be a local variable of type ``pubsub_cb_t *``, and will point to each subscribed handler in turn during iteration. This macro can be used for those patterns that none of the ``PUBLISH_EVENT_*()`` macros cover. Publishing an event that wasn't defined using ``REGISTER_PUBSUB_EVENT`` will result in build error. Subscribing to an undefined event however won't. Subscribed handlers must be of type ``pubsub_cb_t``, with following function signature: .. code:: c typedef void* (*pubsub_cb_t)(const void *arg); There may be arbitrary number of handlers registered to the same event. The order in which subscribed handlers are notified when that event is published is not defined. Subscribed handlers may be executed in any order; handlers should not assume any relative ordering amongst them. Publishing an event on a PE will result in subscribed handlers executing on that PE only; it won't cause handlers to execute on a different PE. Note that publishing an event on a PE blocks until all the subscribed handlers finish executing on the PE. TF-A generic code publishes and subscribes to some events within. Platform ports are discouraged from subscribing to them. These events may be withdrawn, renamed, or have their semantics altered in the future. Platforms may however register, publish, and subscribe to platform-specific events. Publish and Subscribe Example ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A publisher that wants to publish event ``foo`` would: - Define the event ``foo`` in the ``pubsub_events.h``. .. code:: c REGISTER_PUBSUB_EVENT(foo); - Depending on the nature of event, use one of ``PUBLISH_EVENT_*()`` macros to publish the event at the appropriate path and time of execution. A subscriber that wants to subscribe to event ``foo`` published above would implement: .. code:: c void *foo_handler(const void *arg) { void *result; /* Do handling ... */ return result; } SUBSCRIBE_TO_EVENT(foo, foo_handler); Reclaiming the BL31 initialization code ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A significant amount of the code used for the initialization of BL31 is never needed again after boot time. In order to reduce the runtime memory footprint, the memory used for this code can be reclaimed after initialization has finished and be used for runtime data. The build option ``RECLAIM_INIT_CODE`` can be set to mark this boot time code with a ``.text.init.*`` attribute which can be filtered and placed suitably within the BL image for later reclamation by the platform. The platform can specify the filter and the memory region for this init section in BL31 via the plat.ld.S linker script. For example, on the FVP, this section is placed overlapping the secondary CPU stacks so that after the cold boot is done, this memory can be reclaimed for the stacks. The init memory section is initially mapped with ``RO``, ``EXECUTE`` attributes. After BL31 initialization has completed, the FVP changes the attributes of this section to ``RW``, ``EXECUTE_NEVER`` allowing it to be used for runtime data. The memory attributes are changed within the ``bl31_plat_runtime_setup`` platform hook. The init section section can be reclaimed for any data which is accessed after cold boot initialization and it is upto the platform to make the decision. .. _firmware_design_pmf: Performance Measurement Framework --------------------------------- The Performance Measurement Framework (PMF) facilitates collection of timestamps by registered services and provides interfaces to retrieve them from within TF-A. A platform can choose to expose appropriate SMCs to retrieve these collected timestamps. By default, the global physical counter is used for the timestamp value and is read via ``CNTPCT_EL0``. The framework allows to retrieve timestamps captured by other CPUs. Timestamp identifier format ~~~~~~~~~~~~~~~~~~~~~~~~~~~ A PMF timestamp is uniquely identified across the system via the timestamp ID or ``tid``. The ``tid`` is composed as follows: :: Bits 0-7: The local timestamp identifier. Bits 8-9: Reserved. Bits 10-15: The service identifier. Bits 16-31: Reserved. #. The service identifier. Each PMF service is identified by a service name and a service identifier. Both the service name and identifier are unique within the system as a whole. #. The local timestamp identifier. This identifier is unique within a given service. Registering a PMF service ~~~~~~~~~~~~~~~~~~~~~~~~~ To register a PMF service, the ``PMF_REGISTER_SERVICE()`` macro from ``pmf.h`` is used. The arguments required are the service name, the service ID, the total number of local timestamps to be captured and a set of flags. The ``flags`` field can be specified as a bitwise-OR of the following values: :: PMF_STORE_ENABLE: The timestamp is stored in memory for later retrieval. PMF_DUMP_ENABLE: The timestamp is dumped on the serial console. The ``PMF_REGISTER_SERVICE()`` reserves memory to store captured timestamps in a PMF specific linker section at build time. Additionally, it defines necessary functions to capture and retrieve a particular timestamp for the given service at runtime. The macro ``PMF_REGISTER_SERVICE()`` only enables capturing PMF timestamps from within TF-A. In order to retrieve timestamps from outside of TF-A, the ``PMF_REGISTER_SERVICE_SMC()`` macro must be used instead. This macro accepts the same set of arguments as the ``PMF_REGISTER_SERVICE()`` macro but additionally supports retrieving timestamps using SMCs. Capturing a timestamp ~~~~~~~~~~~~~~~~~~~~~ PMF timestamps are stored in a per-service timestamp region. On a system with multiple CPUs, each timestamp is captured and stored in a per-CPU cache line aligned memory region. Having registered the service, the ``PMF_CAPTURE_TIMESTAMP()`` macro can be used to capture a timestamp at the location where it is used. The macro takes the service name, a local timestamp identifier and a flag as arguments. The ``flags`` field argument can be zero, or ``PMF_CACHE_MAINT`` which instructs PMF to do cache maintenance following the capture. Cache maintenance is required if any of the service's timestamps are captured with data cache disabled. To capture a timestamp in assembly code, the caller should use ``pmf_calc_timestamp_addr`` macro (defined in ``pmf_asm_macros.S``) to calculate the address of where the timestamp would be stored. The caller should then read ``CNTPCT_EL0`` register to obtain the timestamp and store it at the determined address for later retrieval. Retrieving a timestamp ~~~~~~~~~~~~~~~~~~~~~~ From within TF-A, timestamps for individual CPUs can be retrieved using either ``PMF_GET_TIMESTAMP_BY_MPIDR()`` or ``PMF_GET_TIMESTAMP_BY_INDEX()`` macros. These macros accept the CPU's MPIDR value, or its ordinal position respectively. From outside TF-A, timestamps for individual CPUs can be retrieved by calling into ``pmf_smc_handler()``. :: Interface : pmf_smc_handler() Argument : unsigned int 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 Return : uintptr_t smc_fid: Holds the SMC identifier which is either `PMF_SMC_GET_TIMESTAMP_32` when the caller of the SMC is running in AArch32 mode or `PMF_SMC_GET_TIMESTAMP_64` when the caller is running in AArch64 mode. x1: Timestamp identifier. x2: The `mpidr` of the CPU for which the timestamp has to be retrieved. This can be the `mpidr` of a different core to the one initiating the SMC. In that case, service specific cache maintenance may be required to ensure the updated copy of the timestamp is returned. x3: A flags value that is either 0 or `PMF_CACHE_MAINT`. If `PMF_CACHE_MAINT` is passed, then the PMF code will perform a cache invalidate before reading the timestamp. This ensures an updated copy is returned. The remaining arguments, ``x4``, ``cookie``, ``handle`` and ``flags`` are unused in this implementation. PMF code structure ~~~~~~~~~~~~~~~~~~ #. ``pmf_main.c`` consists of core functions that implement service registration, initialization, storing, dumping and retrieving timestamps. #. ``pmf_smc.c`` contains the SMC handling for registered PMF services. #. ``pmf.h`` contains the public interface to Performance Measurement Framework. #. ``pmf_asm_macros.S`` consists of macros to facilitate capturing timestamps in assembly code. #. ``pmf_helpers.h`` is an internal header used by ``pmf.h``. Armv8-A Architecture Extensions ------------------------------- TF-A makes use of Armv8-A Architecture Extensions where applicable. This section lists the usage of Architecture Extensions, and build flags controlling them. In general, and unless individually mentioned, the build options ``ARM_ARCH_MAJOR`` and ``ARM_ARCH_MINOR`` select the Architecture Extension to target when building TF-A. Subsequent Arm Architecture Extensions are backward compatible with previous versions. The build system only requires that ``ARM_ARCH_MAJOR`` and ``ARM_ARCH_MINOR`` have a valid numeric value. These build options only control whether or not Architecture Extension-specific code is included in the build. Otherwise, TF-A targets the base Armv8.0-A architecture; i.e. as if ``ARM_ARCH_MAJOR`` == 8 and ``ARM_ARCH_MINOR`` == 0, which are also their respective default values. See also the *Summary of build options* in :ref:`User Guide`. For details on the Architecture Extension and available features, please refer to the respective Architecture Extension Supplement. Armv8.1-A ~~~~~~~~~ This Architecture Extension is targeted when ``ARM_ARCH_MAJOR`` >= 8, or when ``ARM_ARCH_MAJOR`` == 8 and ``ARM_ARCH_MINOR`` >= 1. - By default, a load-/store-exclusive instruction pair is used to implement spinlocks. The ``USE_SPINLOCK_CAS`` build option when set to 1 selects the spinlock implementation using the ARMv8.1-LSE Compare and Swap instruction. Notice this instruction is only available in AArch64 execution state, so the option is only available to AArch64 builds. Armv8.2-A ~~~~~~~~~ - The presence of ARMv8.2-TTCNP is detected at runtime. When it is present, the Common not Private (TTBRn_ELx.CnP) bit is enabled to indicate that multiple Processing Elements in the same Inner Shareable domain use the same translation table entries for a given stage of translation for a particular translation regime. Armv8.3-A ~~~~~~~~~ - Pointer authentication features of Armv8.3-A are unconditionally enabled in the Non-secure world so that lower ELs are allowed to use them without causing a trap to EL3. In order to enable the Secure world to use it, ``CTX_INCLUDE_PAUTH_REGS`` must be set to 1. This will add all pointer authentication system registers to the context that is saved when doing a world switch. The TF-A itself has support for pointer authentication at runtime that can be enabled by setting ``BRANCH_PROTECTION`` option to non-zero and ``CTX_INCLUDE_PAUTH_REGS`` to 1. This enables pointer authentication in BL1, BL2, BL31, and the TSP if it is used. These options are experimental features. Note that Pointer Authentication is enabled for Non-secure world irrespective of the value of these build flags if the CPU supports it. If ``ARM_ARCH_MAJOR == 8`` and ``ARM_ARCH_MINOR >= 3`` the code footprint of enabling PAuth is lower because the compiler will use the optimized PAuth instructions rather than the backwards-compatible ones. Armv8.5-A ~~~~~~~~~ - Branch Target Identification feature is selected by ``BRANCH_PROTECTION`` option set to 1. This option defaults to 0 and this is an experimental feature. - Memory Tagging Extension feature is unconditionally enabled for both worlds (at EL0 and S-EL0) if it is only supported at EL0. If instead it is implemented at all ELs, it is unconditionally enabled for only the normal world. To enable it for the secure world as well, the build option ``CTX_INCLUDE_MTE_REGS`` is required. If the hardware does not implement MTE support at all, it is always disabled, no matter what build options are used. Armv7-A ~~~~~~~ This Architecture Extension is targeted when ``ARM_ARCH_MAJOR`` == 7. There are several Armv7-A extensions available. Obviously the TrustZone extension is mandatory to support the TF-A bootloader and runtime services. Platform implementing an Armv7-A system can to define from its target Cortex-A architecture through ``ARM_CORTEX_A = yes`` in their ``platform.mk`` script. For example ``ARM_CORTEX_A15=yes`` for a Cortex-A15 target. Platform can also set ``ARM_WITH_NEON=yes`` to enable neon support. Note that using neon at runtime has constraints on non secure world context. TF-A does not yet provide VFP context management. Directive ``ARM_CORTEX_A`` and ``ARM_WITH_NEON`` are used to set the toolchain target architecture directive. Platform may choose to not define straight the toolchain target architecture directive by defining ``MARCH32_DIRECTIVE``. I.e: .. code:: make MARCH32_DIRECTIVE := -mach=armv7-a Code Structure -------------- TF-A code is logically divided between the three boot loader stages mentioned in the previous sections. The code is also divided into the following categories (present as directories in the source code): - **Platform specific.** Choice of architecture specific code depends upon the platform. - **Common code.** This is platform and architecture agnostic code. - **Library code.** This code comprises of functionality commonly used by all other code. The PSCI implementation and other EL3 runtime frameworks reside as Library components. - **Stage specific.** Code specific to a boot stage. - **Drivers.** - **Services.** EL3 runtime services (eg: SPD). Specific SPD services reside in the ``services/spd`` directory (e.g. ``services/spd/tspd``). Each boot loader stage uses code from one or more of the above mentioned categories. Based upon the above, the code layout looks like this: :: Directory Used by BL1? Used by BL2? Used by BL31? bl1 Yes No No bl2 No Yes No bl31 No No Yes plat Yes Yes Yes drivers Yes No Yes common Yes Yes Yes lib Yes Yes Yes services No No Yes The build system provides a non configurable build option IMAGE_BLx for each boot loader stage (where x = BL stage). e.g. for BL1 , IMAGE_BL1 will be defined by the build system. This enables TF-A to compile certain code only for specific boot loader stages All assembler files have the ``.S`` extension. The linker source files for each boot stage have the extension ``.ld.S``. These are processed by GCC to create the linker scripts which have the extension ``.ld``. FDTs provide a description of the hardware platform and are used by the Linux kernel at boot time. These can be found in the ``fdts`` directory. .. rubric:: References - `Trusted Board Boot Requirements CLIENT (TBBR-CLIENT) Armv8-A (ARM DEN0006D)`_ - `Power State Coordination Interface PDD`_ - `SMC Calling Convention PDD`_ - :ref:`Interrupt Management Framework` -------------- *Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.* .. _Power State Coordination Interface PDD: http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf .. _SMCCC: http://infocenter.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf .. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf .. _Power State Coordination Interface PDD: http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf .. _Arm ARM: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0487a.e/index.html .. _SMC Calling Convention PDD: http://infocenter.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf .. _Trusted Board Boot Requirements CLIENT (TBBR-CLIENT) Armv8-A (ARM DEN0006D): https://developer.arm.com/docs/den0006/latest/trusted-board-boot-requirements-client-tbbr-client-armv8-a .. |Image 1| image:: ../resources/diagrams/rt-svc-descs-layout.png trusted-firmware-a-2.2/docs/design/index.rst000066400000000000000000000003651355360272700211570ustar00rootroot00000000000000System Design ============= .. toctree:: :maxdepth: 1 :caption: Contents :numbered: auth-framework cpu-specific-build-macros firmware-design interrupt-framework-design psci-pd-tree reset-design trusted-board-boot trusted-firmware-a-2.2/docs/design/interrupt-framework-design.rst000066400000000000000000001416121355360272700253470ustar00rootroot00000000000000Interrupt Management Framework ============================== This framework is responsible for managing interrupts routed to EL3. It also allows EL3 software to configure the interrupt routing behavior. Its main objective is to implement the following two requirements. #. It should be possible to route interrupts meant to be handled by secure software (Secure interrupts) to EL3, when execution is in non-secure state (normal world). The framework should then take care of handing control of the interrupt to either software in EL3 or Secure-EL1 depending upon the software configuration and the GIC implementation. This requirement ensures that secure interrupts are under the control of the secure software with respect to their delivery and handling without the possibility of intervention from non-secure software. #. It should be possible to route interrupts meant to be handled by non-secure software (Non-secure interrupts) to the last executed exception level in the normal world when the execution is in secure world at exception levels lower than EL3. This could be done with or without the knowledge of software executing in Secure-EL1/Secure-EL0. The choice of approach should be governed by the secure software. This requirement ensures that non-secure software is able to execute in tandem with the secure software without overriding it. Concepts -------- Interrupt types ~~~~~~~~~~~~~~~ The framework categorises an interrupt to be one of the following depending upon the exception level(s) it is handled in. #. Secure EL1 interrupt. This type of interrupt can be routed to EL3 or Secure-EL1 depending upon the security state of the current execution context. It is always handled in Secure-EL1. #. Non-secure interrupt. This type of interrupt can be routed to EL3, Secure-EL1, Non-secure EL1 or EL2 depending upon the security state of the current execution context. It is always handled in either Non-secure EL1 or EL2. #. EL3 interrupt. This type of interrupt can be routed to EL3 or Secure-EL1 depending upon the security state of the current execution context. It is always handled in EL3. The following constants define the various interrupt types in the framework implementation. .. code:: c #define INTR_TYPE_S_EL1 0 #define INTR_TYPE_EL3 1 #define INTR_TYPE_NS 2 Routing model ~~~~~~~~~~~~~ A type of interrupt can be either generated as an FIQ or an IRQ. The target exception level of an interrupt type is configured through the FIQ and IRQ bits in the Secure Configuration Register at EL3 (``SCR_EL3.FIQ`` and ``SCR_EL3.IRQ`` bits). When ``SCR_EL3.FIQ``\ =1, FIQs are routed to EL3. Otherwise they are routed to the First Exception Level (FEL) capable of handling interrupts. When ``SCR_EL3.IRQ``\ =1, IRQs are routed to EL3. Otherwise they are routed to the FEL. This register is configured independently by EL3 software for each security state prior to entry into a lower exception level in that security state. A routing model for a type of interrupt (generated as FIQ or IRQ) is defined as its target exception level for each security state. It is represented by a single bit for each security state. A value of ``0`` means that the interrupt should be routed to the FEL. A value of ``1`` means that the interrupt should be routed to EL3. A routing model is applicable only when execution is not in EL3. The default routing model for an interrupt type is to route it to the FEL in either security state. Valid routing models ~~~~~~~~~~~~~~~~~~~~ The framework considers certain routing models for each type of interrupt to be incorrect as they conflict with the requirements mentioned in Section 1. The following sub-sections describe all the possible routing models and specify which ones are valid or invalid. EL3 interrupts are currently supported only for GIC version 3.0 (Arm GICv3) and only the Secure-EL1 and Non-secure interrupt types are supported for GIC version 2.0 (Arm GICv2) (see `Assumptions in Interrupt Management Framework`_). The terminology used in the following sub-sections is explained below. #. **CSS**. Current Security State. ``0`` when secure and ``1`` when non-secure #. **TEL3**. Target Exception Level 3. ``0`` when targeted to the FEL. ``1`` when targeted to EL3. Secure-EL1 interrupts ^^^^^^^^^^^^^^^^^^^^^ #. **CSS=0, TEL3=0**. Interrupt is routed to the FEL when execution is in secure state. This is a valid routing model as secure software is in control of handling secure interrupts. #. **CSS=0, TEL3=1**. Interrupt is routed to EL3 when execution is in secure state. This is a valid routing model as secure software in EL3 can handover the interrupt to Secure-EL1 for handling. #. **CSS=1, TEL3=0**. Interrupt is routed to the FEL when execution is in non-secure state. This is an invalid routing model as a secure interrupt is not visible to the secure software which violates the motivation behind the Arm Security Extensions. #. **CSS=1, TEL3=1**. Interrupt is routed to EL3 when execution is in non-secure state. This is a valid routing model as secure software in EL3 can handover the interrupt to Secure-EL1 for handling. Non-secure interrupts ^^^^^^^^^^^^^^^^^^^^^ #. **CSS=0, TEL3=0**. Interrupt is routed to the FEL when execution is in secure state. This allows the secure software to trap non-secure interrupts, perform its book-keeping and hand the interrupt to the non-secure software through EL3. This is a valid routing model as secure software is in control of how its execution is preempted by non-secure interrupts. #. **CSS=0, TEL3=1**. Interrupt is routed to EL3 when execution is in secure state. This is a valid routing model as secure software in EL3 can save the state of software in Secure-EL1/Secure-EL0 before handing the interrupt to non-secure software. This model requires additional coordination between Secure-EL1 and EL3 software to ensure that the former's state is correctly saved by the latter. #. **CSS=1, TEL3=0**. Interrupt is routed to FEL when execution is in non-secure state. This is a valid routing model as a non-secure interrupt is handled by non-secure software. #. **CSS=1, TEL3=1**. Interrupt is routed to EL3 when execution is in non-secure state. This is an invalid routing model as there is no valid reason to route the interrupt to EL3 software and then hand it back to non-secure software for handling. EL3 interrupts ^^^^^^^^^^^^^^ #. **CSS=0, TEL3=0**. Interrupt is routed to the FEL when execution is in Secure-EL1/Secure-EL0. This is a valid routing model as secure software in Secure-EL1/Secure-EL0 is in control of how its execution is preempted by EL3 interrupt and can handover the interrupt to EL3 for handling. However, when ``EL3_EXCEPTION_HANDLING`` is ``1``, this routing model is invalid as EL3 interrupts are unconditionally routed to EL3, and EL3 interrupts will always preempt Secure EL1/EL0 execution. See `exception handling`__ documentation. .. __: exception-handling.rst#interrupt-handling #. **CSS=0, TEL3=1**. Interrupt is routed to EL3 when execution is in Secure-EL1/Secure-EL0. This is a valid routing model as secure software in EL3 can handle the interrupt. #. **CSS=1, TEL3=0**. Interrupt is routed to the FEL when execution is in non-secure state. This is an invalid routing model as a secure interrupt is not visible to the secure software which violates the motivation behind the Arm Security Extensions. #. **CSS=1, TEL3=1**. Interrupt is routed to EL3 when execution is in non-secure state. This is a valid routing model as secure software in EL3 can handle the interrupt. Mapping of interrupt type to signal ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The framework is meant to work with any interrupt controller implemented by a platform. A interrupt controller could generate a type of interrupt as either an FIQ or IRQ signal to the CPU depending upon the current security state. The mapping between the type and signal is known only to the platform. The framework uses this information to determine whether the IRQ or the FIQ bit should be programmed in ``SCR_EL3`` while applying the routing model for a type of interrupt. The platform provides this information through the ``plat_interrupt_type_to_line()`` API (described in the :ref:`Porting Guide`). For example, on the FVP port when the platform uses an Arm GICv2 interrupt controller, Secure-EL1 interrupts are signaled through the FIQ signal while Non-secure interrupts are signaled through the IRQ signal. This applies when execution is in either security state. Effect of mapping of several interrupt types to one signal ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ It should be noted that if more than one interrupt type maps to a single interrupt signal, and if any one of the interrupt type sets **TEL3=1** for a particular security state, then interrupt signal will be routed to EL3 when in that security state. This means that all the other interrupt types using the same interrupt signal will be forced to the same routing model. This should be borne in mind when choosing the routing model for an interrupt type. For example, in Arm GICv3, when the execution context is Secure-EL1/ Secure-EL0, both the EL3 and the non secure interrupt types map to the FIQ signal. So if either one of the interrupt type sets the routing model so that **TEL3=1** when **CSS=0**, the FIQ bit in ``SCR_EL3`` will be programmed to route the FIQ signal to EL3 when executing in Secure-EL1/Secure-EL0, thereby effectively routing the other interrupt type also to EL3. Assumptions in Interrupt Management Framework --------------------------------------------- The framework makes the following assumptions to simplify its implementation. #. Although the framework has support for 2 types of secure interrupts (EL3 and Secure-EL1 interrupt), only interrupt controller architectures like Arm GICv3 has architectural support for EL3 interrupts in the form of Group 0 interrupts. In Arm GICv2, all secure interrupts are assumed to be handled in Secure-EL1. They can be delivered to Secure-EL1 via EL3 but they cannot be handled in EL3. #. Interrupt exceptions (``PSTATE.I`` and ``F`` bits) are masked during execution in EL3. #. Interrupt management: the following sections describe how interrupts are managed by the interrupt handling framework. This entails: #. Providing an interface to allow registration of a handler and specification of the routing model for a type of interrupt. #. Implementing support to hand control of an interrupt type to its registered handler when the interrupt is generated. Both aspects of interrupt management involve various components in the secure software stack spanning from EL3 to Secure-EL1. These components are described in the section `Software components`_. The framework stores information associated with each type of interrupt in the following data structure. .. code:: c typedef struct intr_type_desc { interrupt_type_handler_t handler; uint32_t flags; uint32_t scr_el3[2]; } intr_type_desc_t; The ``flags`` field stores the routing model for the interrupt type in bits[1:0]. Bit[0] stores the routing model when execution is in the secure state. Bit[1] stores the routing model when execution is in the non-secure state. As mentioned in Section `Routing model`_, a value of ``0`` implies that the interrupt should be targeted to the FEL. A value of ``1`` implies that it should be targeted to EL3. The remaining bits are reserved and SBZ. The helper macro ``set_interrupt_rm_flag()`` should be used to set the bits in the ``flags`` parameter. The ``scr_el3[2]`` field also stores the routing model but as a mapping of the model in the ``flags`` field to the corresponding bit in the ``SCR_EL3`` for each security state. The framework also depends upon the platform port to configure the interrupt controller to distinguish between secure and non-secure interrupts. The platform is expected to be aware of the secure devices present in the system and their associated interrupt numbers. It should configure the interrupt controller to enable the secure interrupts, ensure that their priority is always higher than the non-secure interrupts and target them to the primary CPU. It should also export the interface described in the :ref:`Porting Guide` to enable handling of interrupts. In the remainder of this document, for the sake of simplicity a Arm GICv2 system is considered and it is assumed that the FIQ signal is used to generate Secure-EL1 interrupts and the IRQ signal is used to generate non-secure interrupts in either security state. EL3 interrupts are not considered. Software components ------------------- Roles and responsibilities for interrupt management are sub-divided between the following components of software running in EL3 and Secure-EL1. Each component is briefly described below. #. EL3 Runtime Firmware. This component is common to all ports of TF-A. #. Secure Payload Dispatcher (SPD) service. This service interfaces with the Secure Payload (SP) software which runs in Secure-EL1/Secure-EL0 and is responsible for switching execution between secure and non-secure states. A switch is triggered by a Secure Monitor Call and it uses the APIs exported by the Context management library to implement this functionality. Switching execution between the two security states is a requirement for interrupt management as well. This results in a significant dependency on the SPD service. TF-A implements an example Test Secure Payload Dispatcher (TSPD) service. An SPD service plugs into the EL3 runtime firmware and could be common to some ports of TF-A. #. Secure Payload (SP). On a production system, the Secure Payload corresponds to a Secure OS which runs in Secure-EL1/Secure-EL0. It interfaces with the SPD service to manage communication with non-secure software. TF-A implements an example secure payload called Test Secure Payload (TSP) which runs only in Secure-EL1. A Secure payload implementation could be common to some ports of TF-A, just like the SPD service. Interrupt registration ---------------------- This section describes in detail the role of each software component (see `Software components`_) during the registration of a handler for an interrupt type. EL3 runtime firmware ~~~~~~~~~~~~~~~~~~~~ This component declares the following prototype for a handler of an interrupt type. .. code:: c typedef uint64_t (*interrupt_type_handler_t)(uint32_t id, uint32_t flags, void *handle, void *cookie); The ``id`` is parameter is reserved and could be used in the future for passing the interrupt id of the highest pending interrupt only if there is a foolproof way of determining the id. Currently it contains ``INTR_ID_UNAVAILABLE``. The ``flags`` parameter contains miscellaneous information as follows. #. Security state, bit[0]. This bit indicates the security state of the lower exception level when the interrupt was generated. A value of ``1`` means that it was in the non-secure state. A value of ``0`` indicates that it was in the secure state. This bit can be used by the handler to ensure that interrupt was generated and routed as per the routing model specified during registration. #. Reserved, bits[31:1]. The remaining bits are reserved for future use. The ``handle`` parameter points to the ``cpu_context`` structure of the current CPU for the security state specified in the ``flags`` parameter. Once the handler routine completes, execution will return to either the secure or non-secure state. The handler routine must return a pointer to ``cpu_context`` structure of the current CPU for the target security state. On AArch64, this return value is currently ignored by the caller as the appropriate ``cpu_context`` to be used is expected to be set by the handler via the context management library APIs. A portable interrupt handler implementation must set the target context both in the structure pointed to by the returned pointer and via the context management library APIs. The handler should treat all error conditions as critical errors and take appropriate action within its implementation e.g. use assertion failures. The runtime firmware provides the following API for registering a handler for a particular type of interrupt. A Secure Payload Dispatcher service should use this API to register a handler for Secure-EL1 and optionally for non-secure interrupts. This API also requires the caller to specify the routing model for the type of interrupt. .. code:: c int32_t register_interrupt_type_handler(uint32_t type, interrupt_type_handler handler, uint64_t flags); The ``type`` parameter can be one of the three interrupt types listed above i.e. ``INTR_TYPE_S_EL1``, ``INTR_TYPE_NS`` & ``INTR_TYPE_EL3``. The ``flags`` parameter is as described in Section 2. The function will return ``0`` upon a successful registration. It will return ``-EALREADY`` in case a handler for the interrupt type has already been registered. If the ``type`` is unrecognised or the ``flags`` or the ``handler`` are invalid it will return ``-EINVAL``. Interrupt routing is governed by the configuration of the ``SCR_EL3.FIQ/IRQ`` bits prior to entry into a lower exception level in either security state. The context management library maintains a copy of the ``SCR_EL3`` system register for each security state in the ``cpu_context`` structure of each CPU. It exports the following APIs to let EL3 Runtime Firmware program and retrieve the routing model for each security state for the current CPU. The value of ``SCR_EL3`` stored in the ``cpu_context`` is used by the ``el3_exit()`` function to program the ``SCR_EL3`` register prior to returning from the EL3 exception level. .. code:: c uint32_t cm_get_scr_el3(uint32_t security_state); void cm_write_scr_el3_bit(uint32_t security_state, uint32_t bit_pos, uint32_t value); ``cm_get_scr_el3()`` returns the value of the ``SCR_EL3`` register for the specified security state of the current CPU. ``cm_write_scr_el3_bit()`` writes a ``0`` or ``1`` to the bit specified by ``bit_pos``. ``register_interrupt_type_handler()`` invokes ``set_routing_model()`` API which programs the ``SCR_EL3`` according to the routing model using the ``cm_get_scr_el3()`` and ``cm_write_scr_el3_bit()`` APIs. It is worth noting that in the current implementation of the framework, the EL3 runtime firmware is responsible for programming the routing model. The SPD is responsible for ensuring that the routing model has been adhered to upon receiving an interrupt. .. _spd-int-registration: Secure payload dispatcher ~~~~~~~~~~~~~~~~~~~~~~~~~ A SPD service is responsible for determining and maintaining the interrupt routing model supported by itself and the Secure Payload. It is also responsible for ferrying interrupts between secure and non-secure software depending upon the routing model. It could determine the routing model at build time or at runtime. It must use this information to register a handler for each interrupt type using the ``register_interrupt_type_handler()`` API in EL3 runtime firmware. If the routing model is not known to the SPD service at build time, then it must be provided by the SP as the result of its initialisation. The SPD should program the routing model only after SP initialisation has completed e.g. in the SPD initialisation function pointed to by the ``bl32_init`` variable. The SPD should determine the mechanism to pass control to the Secure Payload after receiving an interrupt from the EL3 runtime firmware. This information could either be provided to the SPD service at build time or by the SP at runtime. Test secure payload dispatcher behavior ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. note:: Where this document discusses ``TSP_NS_INTR_ASYNC_PREEMPT`` as being ``1``, the same results also apply when ``EL3_EXCEPTION_HANDLING`` is ``1``. The TSPD only handles Secure-EL1 interrupts and is provided with the following routing model at build time. - Secure-EL1 interrupts are routed to EL3 when execution is in non-secure state and are routed to the FEL when execution is in the secure state i.e **CSS=0, TEL3=0** & **CSS=1, TEL3=1** for Secure-EL1 interrupts - When the build flag ``TSP_NS_INTR_ASYNC_PREEMPT`` is zero, the default routing model is used for non-secure interrupts. They are routed to the FEL in either security state i.e **CSS=0, TEL3=0** & **CSS=1, TEL3=0** for Non-secure interrupts. - When the build flag ``TSP_NS_INTR_ASYNC_PREEMPT`` is defined to 1, then the non secure interrupts are routed to EL3 when execution is in secure state i.e **CSS=0, TEL3=1** for non-secure interrupts. This effectively preempts Secure-EL1. The default routing model is used for non secure interrupts in non-secure state. i.e **CSS=1, TEL3=0**. It performs the following actions in the ``tspd_init()`` function to fulfill the requirements mentioned earlier. #. It passes control to the Test Secure Payload to perform its initialisation. The TSP provides the address of the vector table ``tsp_vectors`` in the SP which also includes the handler for Secure-EL1 interrupts in the ``sel1_intr_entry`` field. The TSPD passes control to the TSP at this address when it receives a Secure-EL1 interrupt. The handover agreement between the TSP and the TSPD requires that the TSPD masks all interrupts (``PSTATE.DAIF`` bits) when it calls ``tsp_sel1_intr_entry()``. The TSP has to preserve the callee saved general purpose, SP_EL1/Secure-EL0, LR, VFP and system registers. It can use ``x0-x18`` to enable its C runtime. #. The TSPD implements a handler function for Secure-EL1 interrupts. This function is registered with the EL3 runtime firmware using the ``register_interrupt_type_handler()`` API as follows .. code:: c /* Forward declaration */ interrupt_type_handler tspd_secure_el1_interrupt_handler; int32_t rc, flags = 0; set_interrupt_rm_flag(flags, NON_SECURE); rc = register_interrupt_type_handler(INTR_TYPE_S_EL1, tspd_secure_el1_interrupt_handler, flags); if (rc) panic(); #. When the build flag ``TSP_NS_INTR_ASYNC_PREEMPT`` is defined to 1, the TSPD implements a handler function for non-secure interrupts. This function is registered with the EL3 runtime firmware using the ``register_interrupt_type_handler()`` API as follows .. code:: c /* Forward declaration */ interrupt_type_handler tspd_ns_interrupt_handler; int32_t rc, flags = 0; set_interrupt_rm_flag(flags, SECURE); rc = register_interrupt_type_handler(INTR_TYPE_NS, tspd_ns_interrupt_handler, flags); if (rc) panic(); .. _sp-int-registration: Secure payload ~~~~~~~~~~~~~~ A Secure Payload must implement an interrupt handling framework at Secure-EL1 (Secure-EL1 IHF) to support its chosen interrupt routing model. Secure payload execution will alternate between the below cases. #. In the code where IRQ, FIQ or both interrupts are enabled, if an interrupt type is targeted to the FEL, then it will be routed to the Secure-EL1 exception vector table. This is defined as the **asynchronous mode** of handling interrupts. This mode applies to both Secure-EL1 and non-secure interrupts. #. In the code where both interrupts are disabled, if an interrupt type is targeted to the FEL, then execution will eventually migrate to the non-secure state. Any non-secure interrupts will be handled as described in the routing model where **CSS=1 and TEL3=0**. Secure-EL1 interrupts will be routed to EL3 (as per the routing model where **CSS=1 and TEL3=1**) where the SPD service will hand them to the SP. This is defined as the **synchronous mode** of handling interrupts. The interrupt handling framework implemented by the SP should support one or both these interrupt handling models depending upon the chosen routing model. The following list briefly describes how the choice of a valid routing model (see `Valid routing models`_) effects the implementation of the Secure-EL1 IHF. If the choice of the interrupt routing model is not known to the SPD service at compile time, then the SP should pass this information to the SPD service at runtime during its initialisation phase. As mentioned earlier, an Arm GICv2 system is considered and it is assumed that the FIQ signal is used to generate Secure-EL1 interrupts and the IRQ signal is used to generate non-secure interrupts in either security state. Secure payload IHF design w.r.t secure-EL1 interrupts ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #. **CSS=0, TEL3=0**. If ``PSTATE.F=0``, Secure-EL1 interrupts will be triggered at one of the Secure-EL1 FIQ exception vectors. The Secure-EL1 IHF should implement support for handling FIQ interrupts asynchronously. If ``PSTATE.F=1`` then Secure-EL1 interrupts will be handled as per the synchronous interrupt handling model. The SP could implement this scenario by exporting a separate entrypoint for Secure-EL1 interrupts to the SPD service during the registration phase. The SPD service would also need to know the state of the system, general purpose and the ``PSTATE`` registers in which it should arrange to return execution to the SP. The SP should provide this information in an implementation defined way during the registration phase if it is not known to the SPD service at build time. #. **CSS=1, TEL3=1**. Interrupts are routed to EL3 when execution is in non-secure state. They should be handled through the synchronous interrupt handling model as described in 1. above. #. **CSS=0, TEL3=1**. Secure-EL1 interrupts are routed to EL3 when execution is in secure state. They will not be visible to the SP. The ``PSTATE.F`` bit in Secure-EL1/Secure-EL0 will not mask FIQs. The EL3 runtime firmware will call the handler registered by the SPD service for Secure-EL1 interrupts. Secure-EL1 IHF should then handle all Secure-EL1 interrupt through the synchronous interrupt handling model described in 1. above. Secure payload IHF design w.r.t non-secure interrupts ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ #. **CSS=0, TEL3=0**. If ``PSTATE.I=0``, non-secure interrupts will be triggered at one of the Secure-EL1 IRQ exception vectors . The Secure-EL1 IHF should co-ordinate with the SPD service to transfer execution to the non-secure state where the interrupt should be handled e.g the SP could allocate a function identifier to issue a SMC64 or SMC32 to the SPD service which indicates that the SP execution has been preempted by a non-secure interrupt. If this function identifier is not known to the SPD service at compile time then the SP could provide it during the registration phase. If ``PSTATE.I=1`` then the non-secure interrupt will pend until execution resumes in the non-secure state. #. **CSS=0, TEL3=1**. Non-secure interrupts are routed to EL3. They will not be visible to the SP. The ``PSTATE.I`` bit in Secure-EL1/Secure-EL0 will have not effect. The SPD service should register a non-secure interrupt handler which should save the SP state correctly and resume execution in the non-secure state where the interrupt will be handled. The Secure-EL1 IHF does not need to take any action. #. **CSS=1, TEL3=0**. Non-secure interrupts are handled in the FEL in non-secure state (EL1/EL2) and are not visible to the SP. This routing model does not affect the SP behavior. A Secure Payload must also ensure that all Secure-EL1 interrupts are correctly configured at the interrupt controller by the platform port of the EL3 runtime firmware. It should configure any additional Secure-EL1 interrupts which the EL3 runtime firmware is not aware of through its platform port. Test secure payload behavior ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The routing model for Secure-EL1 and non-secure interrupts chosen by the TSP is described in Section `Secure Payload Dispatcher`__. It is known to the TSPD service at build time. .. __: #spd-int-registration The TSP implements an entrypoint (``tsp_sel1_intr_entry()``) for handling Secure-EL1 interrupts taken in non-secure state and routed through the TSPD service (synchronous handling model). It passes the reference to this entrypoint via ``tsp_vectors`` to the TSPD service. The TSP also replaces the default exception vector table referenced through the ``early_exceptions`` variable, with a vector table capable of handling FIQ and IRQ exceptions taken at the same (Secure-EL1) exception level. This table is referenced through the ``tsp_exceptions`` variable and programmed into the VBAR_EL1. It caters for the asynchronous handling model. The TSP also programs the Secure Physical Timer in the Arm Generic Timer block to raise a periodic interrupt (every half a second) for the purpose of testing interrupt management across all the software components listed in `Software components`_. Interrupt handling ------------------ This section describes in detail the role of each software component (see Section `Software components`_) in handling an interrupt of a particular type. EL3 runtime firmware ~~~~~~~~~~~~~~~~~~~~ The EL3 runtime firmware populates the IRQ and FIQ exception vectors referenced by the ``runtime_exceptions`` variable as follows. #. IRQ and FIQ exceptions taken from the current exception level with ``SP_EL0`` or ``SP_EL3`` are reported as irrecoverable error conditions. As mentioned earlier, EL3 runtime firmware always executes with the ``PSTATE.I`` and ``PSTATE.F`` bits set. #. The following text describes how the IRQ and FIQ exceptions taken from a lower exception level using AArch64 or AArch32 are handled. When an interrupt is generated, the vector for each interrupt type is responsible for: #. Saving the entire general purpose register context (x0-x30) immediately upon exception entry. The registers are saved in the per-cpu ``cpu_context`` data structure referenced by the ``SP_EL3``\ register. #. Saving the ``ELR_EL3``, ``SP_EL0`` and ``SPSR_EL3`` system registers in the per-cpu ``cpu_context`` data structure referenced by the ``SP_EL3`` register. #. Switching to the C runtime stack by restoring the ``CTX_RUNTIME_SP`` value from the per-cpu ``cpu_context`` data structure in ``SP_EL0`` and executing the ``msr spsel, #0`` instruction. #. Determining the type of interrupt. Secure-EL1 interrupts will be signaled at the FIQ vector. Non-secure interrupts will be signaled at the IRQ vector. The platform should implement the following API to determine the type of the pending interrupt. .. code:: c uint32_t plat_ic_get_interrupt_type(void); It should return either ``INTR_TYPE_S_EL1`` or ``INTR_TYPE_NS``. #. Determining the handler for the type of interrupt that has been generated. The following API has been added for this purpose. .. code:: c interrupt_type_handler get_interrupt_type_handler(uint32_t interrupt_type); It returns the reference to the registered handler for this interrupt type. The ``handler`` is retrieved from the ``intr_type_desc_t`` structure as described in Section 2. ``NULL`` is returned if no handler has been registered for this type of interrupt. This scenario is reported as an irrecoverable error condition. #. Calling the registered handler function for the interrupt type generated. The ``id`` parameter is set to ``INTR_ID_UNAVAILABLE`` currently. The id along with the current security state and a reference to the ``cpu_context_t`` structure for the current security state are passed to the handler function as its arguments. The handler function returns a reference to the per-cpu ``cpu_context_t`` structure for the target security state. #. Calling ``el3_exit()`` to return from EL3 into a lower exception level in the security state determined by the handler routine. The ``el3_exit()`` function is responsible for restoring the register context from the ``cpu_context_t`` data structure for the target security state. Secure payload dispatcher ~~~~~~~~~~~~~~~~~~~~~~~~~ Interrupt entry ^^^^^^^^^^^^^^^ The SPD service begins handling an interrupt when the EL3 runtime firmware calls the handler function for that type of interrupt. The SPD service is responsible for the following: #. Validating the interrupt. This involves ensuring that the interrupt was generated according to the interrupt routing model specified by the SPD service during registration. It should use the security state of the exception level (passed in the ``flags`` parameter of the handler) where the interrupt was taken from to determine this. If the interrupt is not recognised then the handler should treat it as an irrecoverable error condition. An SPD service can register a handler for Secure-EL1 and/or Non-secure interrupts. A non-secure interrupt should never be routed to EL3 from from non-secure state. Also if a routing model is chosen where Secure-EL1 interrupts are routed to S-EL1 when execution is in Secure state, then a S-EL1 interrupt should never be routed to EL3 from secure state. The handler could use the security state flag to check this. #. Determining whether a context switch is required. This depends upon the routing model and interrupt type. For non secure and S-EL1 interrupt, if the security state of the execution context where the interrupt was generated is not the same as the security state required for handling the interrupt, a context switch is required. The following 2 cases require a context switch from secure to non-secure or vice-versa: #. A Secure-EL1 interrupt taken from the non-secure state should be routed to the Secure Payload. #. A non-secure interrupt taken from the secure state should be routed to the last known non-secure exception level. The SPD service must save the system register context of the current security state. It must then restore the system register context of the target security state. It should use the ``cm_set_next_eret_context()`` API to ensure that the next ``cpu_context`` to be restored is of the target security state. If the target state is secure then execution should be handed to the SP as per the synchronous interrupt handling model it implements. A Secure-EL1 interrupt can be routed to EL3 while execution is in the SP. This implies that SP execution can be preempted while handling an interrupt by a another higher priority Secure-EL1 interrupt or a EL3 interrupt. The SPD service should be able to handle this preemption or manage secure interrupt priorities before handing control to the SP. #. Setting the return value of the handler to the per-cpu ``cpu_context`` if the interrupt has been successfully validated and ready to be handled at a lower exception level. The routing model allows non-secure interrupts to interrupt Secure-EL1 when in secure state if it has been configured to do so. The SPD service and the SP should implement a mechanism for routing these interrupts to the last known exception level in the non-secure state. The former should save the SP context, restore the non-secure context and arrange for entry into the non-secure state so that the interrupt can be handled. Interrupt exit ^^^^^^^^^^^^^^ When the Secure Payload has finished handling a Secure-EL1 interrupt, it could return control back to the SPD service through a SMC32 or SMC64. The SPD service should handle this secure monitor call so that execution resumes in the exception level and the security state from where the Secure-EL1 interrupt was originally taken. Test secure payload dispatcher Secure-EL1 interrupt handling ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The example TSPD service registers a handler for Secure-EL1 interrupts taken from the non-secure state. During execution in S-EL1, the TSPD expects that the Secure-EL1 interrupts are handled in S-EL1 by TSP. Its handler ``tspd_secure_el1_interrupt_handler()`` expects only to be invoked for Secure-EL1 originating from the non-secure state. It takes the following actions upon being invoked. #. It uses the security state provided in the ``flags`` parameter to ensure that the secure interrupt originated from the non-secure state. It asserts if this is not the case. #. It saves the system register context for the non-secure state by calling ``cm_el1_sysregs_context_save(NON_SECURE);``. #. It sets the ``ELR_EL3`` system register to ``tsp_sel1_intr_entry`` and sets the ``SPSR_EL3.DAIF`` bits in the secure CPU context. It sets ``x0`` to ``TSP_HANDLE_SEL1_INTR_AND_RETURN``. If the TSP was preempted earlier by a non secure interrupt during ``yielding`` SMC processing, save the registers that will be trashed, which is the ``ELR_EL3`` and ``SPSR_EL3``, in order to be able to re-enter TSP for Secure-EL1 interrupt processing. It does not need to save any other secure context since the TSP is expected to preserve it (see section `Test secure payload dispatcher behavior`_). #. It restores the system register context for the secure state by calling ``cm_el1_sysregs_context_restore(SECURE);``. #. It ensures that the secure CPU context is used to program the next exception return from EL3 by calling ``cm_set_next_eret_context(SECURE);``. #. It returns the per-cpu ``cpu_context`` to indicate that the interrupt can now be handled by the SP. ``x1`` is written with the value of ``elr_el3`` register for the non-secure state. This information is used by the SP for debugging purposes. The figure below describes how the interrupt handling is implemented by the TSPD when a Secure-EL1 interrupt is generated when execution is in the non-secure state. |Image 1| The TSP issues an SMC with ``TSP_HANDLED_S_EL1_INTR`` as the function identifier to signal completion of interrupt handling. The TSPD service takes the following actions in ``tspd_smc_handler()`` function upon receiving an SMC with ``TSP_HANDLED_S_EL1_INTR`` as the function identifier: #. It ensures that the call originated from the secure state otherwise execution returns to the non-secure state with ``SMC_UNK`` in ``x0``. #. It restores the saved ``ELR_EL3`` and ``SPSR_EL3`` system registers back to the secure CPU context (see step 3 above) in case the TSP had been preempted by a non secure interrupt earlier. #. It restores the system register context for the non-secure state by calling ``cm_el1_sysregs_context_restore(NON_SECURE)``. #. It ensures that the non-secure CPU context is used to program the next exception return from EL3 by calling ``cm_set_next_eret_context(NON_SECURE)``. #. ``tspd_smc_handler()`` returns a reference to the non-secure ``cpu_context`` as the return value. Test secure payload dispatcher non-secure interrupt handling ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The TSP in Secure-EL1 can be preempted by a non-secure interrupt during ``yielding`` SMC processing or by a higher priority EL3 interrupt during Secure-EL1 interrupt processing. When ``EL3_EXCEPTION_HANDLING`` is ``0``, only non-secure interrupts can cause preemption of TSP since there are no EL3 interrupts in the system. With ``EL3_EXCEPTION_HANDLING=1`` however, any EL3 interrupt may preempt Secure execution. It should be noted that while TSP is preempted, the TSPD only allows entry into the TSP either for Secure-EL1 interrupt handling or for resuming the preempted ``yielding`` SMC in response to the ``TSP_FID_RESUME`` SMC from the normal world. (See Section `Implication of preempted SMC on Non-Secure Software`_). The non-secure interrupt triggered in Secure-EL1 during ``yielding`` SMC processing can be routed to either EL3 or Secure-EL1 and is controlled by build option ``TSP_NS_INTR_ASYNC_PREEMPT`` (see Section `Test secure payload dispatcher behavior`_). If the build option is set, the TSPD will set the routing model for the non-secure interrupt to be routed to EL3 from secure state i.e. **TEL3=1, CSS=0** and registers ``tspd_ns_interrupt_handler()`` as the non-secure interrupt handler. The ``tspd_ns_interrupt_handler()`` on being invoked ensures that the interrupt originated from the secure state and disables routing of non-secure interrupts from secure state to EL3. This is to prevent further preemption (by a non-secure interrupt) when TSP is reentered for handling Secure-EL1 interrupts that triggered while execution was in the normal world. The ``tspd_ns_interrupt_handler()`` then invokes ``tspd_handle_sp_preemption()`` for further handling. If the ``TSP_NS_INTR_ASYNC_PREEMPT`` build option is zero (default), the default routing model for non-secure interrupt in secure state is in effect i.e. **TEL3=0, CSS=0**. During ``yielding`` SMC processing, the IRQ exceptions are unmasked i.e. ``PSTATE.I=0``, and a non-secure interrupt will trigger at Secure-EL1 IRQ exception vector. The TSP saves the general purpose register context and issues an SMC with ``TSP_PREEMPTED`` as the function identifier to signal preemption of TSP. The TSPD SMC handler, ``tspd_smc_handler()``, ensures that the SMC call originated from the secure state otherwise execution returns to the non-secure state with ``SMC_UNK`` in ``x0``. It then invokes ``tspd_handle_sp_preemption()`` for further handling. The ``tspd_handle_sp_preemption()`` takes the following actions upon being invoked: #. It saves the system register context for the secure state by calling ``cm_el1_sysregs_context_save(SECURE)``. #. It restores the system register context for the non-secure state by calling ``cm_el1_sysregs_context_restore(NON_SECURE)``. #. It ensures that the non-secure CPU context is used to program the next exception return from EL3 by calling ``cm_set_next_eret_context(NON_SECURE)``. #. ``SMC_PREEMPTED`` is set in x0 and return to non secure state after restoring non secure context. The Normal World is expected to resume the TSP after the ``yielding`` SMC preemption by issuing an SMC with ``TSP_FID_RESUME`` as the function identifier (see section `Implication of preempted SMC on Non-Secure Software`_). The TSPD service takes the following actions in ``tspd_smc_handler()`` function upon receiving this SMC: #. It ensures that the call originated from the non secure state. An assertion is raised otherwise. #. Checks whether the TSP needs a resume i.e check if it was preempted. It then saves the system register context for the non-secure state by calling ``cm_el1_sysregs_context_save(NON_SECURE)``. #. Restores the secure context by calling ``cm_el1_sysregs_context_restore(SECURE)`` #. It ensures that the secure CPU context is used to program the next exception return from EL3 by calling ``cm_set_next_eret_context(SECURE)``. #. ``tspd_smc_handler()`` returns a reference to the secure ``cpu_context`` as the return value. The figure below describes how the TSP/TSPD handle a non-secure interrupt when it is generated during execution in the TSP with ``PSTATE.I`` = 0 when the ``TSP_NS_INTR_ASYNC_PREEMPT`` build flag is 0. |Image 2| Secure payload ~~~~~~~~~~~~~~ The SP should implement one or both of the synchronous and asynchronous interrupt handling models depending upon the interrupt routing model it has chosen (as described in section `Secure Payload`__). .. __: #sp-int-registration In the synchronous model, it should begin handling a Secure-EL1 interrupt after receiving control from the SPD service at an entrypoint agreed upon during build time or during the registration phase. Before handling the interrupt, the SP should save any Secure-EL1 system register context which is needed for resuming normal execution in the SP later e.g. ``SPSR_EL1``, ``ELR_EL1``. After handling the interrupt, the SP could return control back to the exception level and security state where the interrupt was originally taken from. The SP should use an SMC32 or SMC64 to ask the SPD service to do this. In the asynchronous model, the Secure Payload is responsible for handling non-secure and Secure-EL1 interrupts at the IRQ and FIQ vectors in its exception vector table when ``PSTATE.I`` and ``PSTATE.F`` bits are 0. As described earlier, when a non-secure interrupt is generated, the SP should coordinate with the SPD service to pass control back to the non-secure state in the last known exception level. This will allow the non-secure interrupt to be handled in the non-secure state. Test secure payload behavior ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The TSPD hands control of a Secure-EL1 interrupt to the TSP at the ``tsp_sel1_intr_entry()``. The TSP handles the interrupt while ensuring that the handover agreement described in Section `Test secure payload dispatcher behavior`_ is maintained. It updates some statistics by calling ``tsp_update_sync_sel1_intr_stats()``. It then calls ``tsp_common_int_handler()`` which. #. Checks whether the interrupt is the secure physical timer interrupt. It uses the platform API ``plat_ic_get_pending_interrupt_id()`` to get the interrupt number. If it is not the secure physical timer interrupt, then that means that a higher priority interrupt has preempted it. Invoke ``tsp_handle_preemption()`` to handover control back to EL3 by issuing an SMC with ``TSP_PREEMPTED`` as the function identifier. #. Handles the secure timer interrupt interrupt by acknowledging it using the ``plat_ic_acknowledge_interrupt()`` platform API, calling ``tsp_generic_timer_handler()`` to reprogram the secure physical generic timer and calling the ``plat_ic_end_of_interrupt()`` platform API to signal end of interrupt processing. The TSP passes control back to the TSPD by issuing an SMC64 with ``TSP_HANDLED_S_EL1_INTR`` as the function identifier. The TSP handles interrupts under the asynchronous model as follows. #. Secure-EL1 interrupts are handled by calling the ``tsp_common_int_handler()`` function. The function has been described above. #. Non-secure interrupts are handled by calling the ``tsp_common_int_handler()`` function which ends up invoking ``tsp_handle_preemption()`` and issuing an SMC64 with ``TSP_PREEMPTED`` as the function identifier. Execution resumes at the instruction that follows this SMC instruction when the TSPD hands control to the TSP in response to an SMC with ``TSP_FID_RESUME`` as the function identifier from the non-secure state (see section `Test secure payload dispatcher non-secure interrupt handling`_). Other considerations -------------------- Implication of preempted SMC on Non-Secure Software ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A ``yielding`` SMC call to Secure payload can be preempted by a non-secure interrupt and the execution can return to the non-secure world for handling the interrupt (For details on ``yielding`` SMC refer `SMC calling convention`_). In this case, the SMC call has not completed its execution and the execution must return back to the secure payload to resume the preempted SMC call. This can be achieved by issuing an SMC call which instructs to resume the preempted SMC. A ``fast`` SMC cannot be preempted and hence this case will not happen for a fast SMC call. In the Test Secure Payload implementation, ``TSP_FID_RESUME`` is designated as the resume SMC FID. It is important to note that ``TSP_FID_RESUME`` is a ``yielding`` SMC which means it too can be be preempted. The typical non secure software sequence for issuing a ``yielding`` SMC would look like this, assuming ``P.STATE.I=0`` in the non secure state : .. code:: c int rc; rc = smc(TSP_YIELD_SMC_FID, ...); /* Issue a Yielding SMC call */ /* The pending non-secure interrupt is handled by the interrupt handler and returns back here. */ while (rc == SMC_PREEMPTED) { /* Check if the SMC call is preempted */ rc = smc(TSP_FID_RESUME); /* Issue resume SMC call */ } The ``TSP_YIELD_SMC_FID`` is any ``yielding`` SMC function identifier and the smc() function invokes a SMC call with the required arguments. The pending non-secure interrupt causes an IRQ exception and the IRQ handler registered at the exception vector handles the non-secure interrupt and returns. The return value from the SMC call is tested for ``SMC_PREEMPTED`` to check whether it is preempted. If it is, then the resume SMC call ``TSP_FID_RESUME`` is issued. The return value of the SMC call is tested again to check if it is preempted. This is done in a loop till the SMC call succeeds or fails. If a ``yielding`` SMC is preempted, until it is resumed using ``TSP_FID_RESUME`` SMC and completed, the current TSPD prevents any other SMC call from re-entering TSP by returning ``SMC_UNK`` error. -------------- *Copyright (c) 2014-2019, Arm Limited and Contributors. All rights reserved.* .. _SMC calling convention: http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html .. |Image 1| image:: ../resources/diagrams/sec-int-handling.png .. |Image 2| image:: ../resources/diagrams/non-sec-int-handling.png trusted-firmware-a-2.2/docs/design/psci-pd-tree.rst000066400000000000000000000327211355360272700223450ustar00rootroot00000000000000PSCI Power Domain Tree Structure ================================ Requirements ------------ #. A platform must export the ``plat_get_aff_count()`` and ``plat_get_aff_state()`` APIs to enable the generic PSCI code to populate a tree that describes the hierarchy of power domains in the system. This approach is inflexible because a change to the topology requires a change in the code. It would be much simpler for the platform to describe its power domain tree in a data structure. #. The generic PSCI code generates MPIDRs in order to populate the power domain tree. It also uses an MPIDR to find a node in the tree. The assumption that a platform will use exactly the same MPIDRs as generated by the generic PSCI code is not scalable. The use of an MPIDR also restricts the number of levels in the power domain tree to four. Therefore, there is a need to decouple allocation of MPIDRs from the mechanism used to populate the power domain topology tree. #. The current arrangement of the power domain tree requires a binary search over the sibling nodes at a particular level to find a specified power domain node. During a power management operation, the tree is traversed from a 'start' to an 'end' power level. The binary search is required to find the node at each level. The natural way to perform this traversal is to start from a leaf node and follow the parent node pointer to reach the end level. Therefore, there is a need to define data structures that implement the tree in a way which facilitates such a traversal. #. The attributes of a core power domain differ from the attributes of power domains at higher levels. For example, only a core power domain can be identified using an MPIDR. There is no requirement to perform state coordination while performing a power management operation on the core power domain. Therefore, there is a need to implement the tree in a way which facilitates this distinction between a leaf and non-leaf node and any associated optimizations. -------------- Design ------ Describing a power domain tree ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To fulfill requirement 1., the existing platform APIs ``plat_get_aff_count()`` and ``plat_get_aff_state()`` have been removed. A platform must define an array of unsigned chars such that: #. The first entry in the array specifies the number of power domains at the highest power level implemented in the platform. This caters for platforms where the power domain tree does not have a single root node, for example, the FVP has two cluster power domains at the highest level (1). #. Each subsequent entry corresponds to a power domain and contains the number of power domains that are its direct children. #. The size of the array minus the first entry will be equal to the number of non-leaf power domains. #. The value in each entry in the array is used to find the number of entries to consider at the next level. The sum of the values (number of children) of all the entries at a level specifies the number of entries in the array for the next level. The following example power domain topology tree will be used to describe the above text further. The leaf and non-leaf nodes in this tree have been numbered separately. :: +-+ |0| +-+ / \ / \ / \ / \ / \ / \ / \ / \ / \ / \ +-+ +-+ |1| |2| +-+ +-+ / \ / \ / \ / \ / \ / \ / \ / \ +-+ +-+ +-+ +-+ |3| |4| |5| |6| +-+ +-+ +-+ +-+ +---+-----+ +----+----| +----+----+ +----+-----+-----+ | | | | | | | | | | | | | | | | | | | | | | | | | | v v v v v v v v v v v v v +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +--+ +--+ +--+ |0| |1| |2| |3| |4| |5| |6| |7| |8| |9| |10| |11| |12| +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +-+ +--+ +--+ +--+ This tree is defined by the platform as the array described above as follows: .. code:: c #define PLAT_NUM_POWER_DOMAINS 20 #define PLATFORM_CORE_COUNT 13 #define PSCI_NUM_NON_CPU_PWR_DOMAINS \ (PLAT_NUM_POWER_DOMAINS - PLATFORM_CORE_COUNT) unsigned char plat_power_domain_tree_desc[] = { 1, 2, 2, 2, 3, 3, 3, 4}; Removing assumptions about MPIDRs used in a platform ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To fulfill requirement 2., it is assumed that the platform assigns a unique number (core index) between ``0`` and ``PLAT_CORE_COUNT - 1`` to each core power domain. MPIDRs could be allocated in any manner and will not be used to populate the tree. ``plat_core_pos_by_mpidr(mpidr)`` will return the core index for the core corresponding to the MPIDR. It will return an error (-1) if an MPIDR is passed which is not allocated or corresponds to an absent core. The semantics of this platform API have changed since it is required to validate the passed MPIDR. It has been made a mandatory API as a result. Another mandatory API, ``plat_my_core_pos()`` has been added to return the core index for the calling core. This API provides a more lightweight mechanism to get the index since there is no need to validate the MPIDR of the calling core. The platform should assign the core indices (as illustrated in the diagram above) such that, if the core nodes are numbered from left to right, then the index for a core domain will be the same as the index returned by ``plat_core_pos_by_mpidr()`` or ``plat_my_core_pos()`` for that core. This relationship allows the core nodes to be allocated in a separate array (requirement 4.) during ``psci_setup()`` in such an order that the index of the core in the array is the same as the return value from these APIs. Dealing with holes in MPIDR allocation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ For platforms where the number of allocated MPIDRs is equal to the number of core power domains, for example, Juno and FVPs, the logic to convert an MPIDR to a core index should remain unchanged. Both Juno and FVP use a simple collision proof hash function to do this. It is possible that on some platforms, the allocation of MPIDRs is not contiguous or certain cores have been disabled. This essentially means that the MPIDRs have been sparsely allocated, that is, the size of the range of MPIDRs used by the platform is not equal to the number of core power domains. The platform could adopt one of the following approaches to deal with this scenario: #. Implement more complex logic to convert a valid MPIDR to a core index while maintaining the relationship described earlier. This means that the power domain tree descriptor will not describe any core power domains which are disabled or absent. Entries will not be allocated in the tree for these domains. #. Treat unallocated MPIDRs and disabled cores as absent but still describe them in the power domain descriptor, that is, the number of core nodes described is equal to the size of the range of MPIDRs allocated. This approach will lead to memory wastage since entries will be allocated in the tree but will allow use of a simpler logic to convert an MPIDR to a core index. Traversing through and distinguishing between core and non-core power domains ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To fulfill requirement 3 and 4, separate data structures have been defined to represent leaf and non-leaf power domain nodes in the tree. .. code:: c /******************************************************************************* * The following two data structures implement the power domain tree. The tree * is used to track the state of all the nodes i.e. power domain instances * described by the platform. The tree consists of nodes that describe CPU power * domains i.e. leaf nodes and all other power domains which are parents of a * CPU power domain i.e. non-leaf nodes. ******************************************************************************/ typedef struct non_cpu_pwr_domain_node { /* * Index of the first CPU power domain node level 0 which has this node * as its parent. */ unsigned int cpu_start_idx; /* * Number of CPU power domains which are siblings of the domain indexed * by 'cpu_start_idx' i.e. all the domains in the range 'cpu_start_idx * -> cpu_start_idx + ncpus' have this node as their parent. */ unsigned int ncpus; /* Index of the parent power domain node */ unsigned int parent_node; ----- } non_cpu_pd_node_t; typedef struct cpu_pwr_domain_node { u_register_t mpidr; /* Index of the parent power domain node */ unsigned int parent_node; ----- } cpu_pd_node_t; The power domain tree is implemented as a combination of the following data structures. .. code:: c non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS]; cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT]; Populating the power domain tree ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``populate_power_domain_tree()`` function in ``psci_setup.c`` implements the algorithm to parse the power domain descriptor exported by the platform to populate the two arrays. It is essentially a breadth-first-search. The nodes for each level starting from the root are laid out one after another in the ``psci_non_cpu_pd_nodes`` and ``psci_cpu_pd_nodes`` arrays as follows: :: psci_non_cpu_pd_nodes -> [[Level 3 nodes][Level 2 nodes][Level 1 nodes]] psci_cpu_pd_nodes -> [Level 0 nodes] For the example power domain tree illustrated above, the ``psci_cpu_pd_nodes`` will be populated as follows. The value in each entry is the index of the parent node. Other fields have been ignored for simplicity. :: +-------------+ ^ CPU0 | 3 | | +-------------+ | CPU1 | 3 | | +-------------+ | CPU2 | 3 | | +-------------+ | CPU3 | 4 | | +-------------+ | CPU4 | 4 | | +-------------+ | CPU5 | 4 | | PLATFORM_CORE_COUNT +-------------+ | CPU6 | 5 | | +-------------+ | CPU7 | 5 | | +-------------+ | CPU8 | 5 | | +-------------+ | CPU9 | 6 | | +-------------+ | CPU10 | 6 | | +-------------+ | CPU11 | 6 | | +-------------+ | CPU12 | 6 | v +-------------+ The ``psci_non_cpu_pd_nodes`` array will be populated as follows. The value in each entry is the index of the parent node. :: +-------------+ ^ PD0 | -1 | | +-------------+ | PD1 | 0 | | +-------------+ | PD2 | 0 | | +-------------+ | PD3 | 1 | | PLAT_NUM_POWER_DOMAINS - +-------------+ | PLATFORM_CORE_COUNT PD4 | 1 | | +-------------+ | PD5 | 2 | | +-------------+ | PD6 | 2 | | +-------------+ v Each core can find its node in the ``psci_cpu_pd_nodes`` array using the ``plat_my_core_pos()`` function. When a core is turned on, the normal world provides an MPIDR. The ``plat_core_pos_by_mpidr()`` function is used to validate the MPIDR before using it to find the corresponding core node. The non-core power domain nodes do not need to be identified. -------------- *Copyright (c) 2017-2018, Arm Limited and Contributors. All rights reserved.* trusted-firmware-a-2.2/docs/design/reset-design.rst000066400000000000000000000167701355360272700224500ustar00rootroot00000000000000CPU Reset ========= This document describes the high-level design of the framework to handle CPU resets in Trusted Firmware-A (TF-A). It also describes how the platform integrator can tailor this code to the system configuration to some extent, resulting in a simplified and more optimised boot flow. This document should be used in conjunction with the :ref:`Firmware Design` document which provides greater implementation details around the reset code, specifically for the cold boot path. General reset code flow ----------------------- The TF-A reset code is implemented in BL1 by default. The following high-level diagram illustrates this: |Default reset code flow| This diagram shows the default, unoptimised reset flow. Depending on the system configuration, some of these steps might be unnecessary. The following sections guide the platform integrator by indicating which build options exclude which steps, depending on the capability of the platform. .. note:: If BL31 is used as the TF-A entry point instead of BL1, the diagram above is still relevant, as all these operations will occur in BL31 in this case. Please refer to section 6 "Using BL31 entrypoint as the reset address" for more information. Programmable CPU reset address ------------------------------ By default, TF-A assumes that the CPU reset address is not programmable. Therefore, all CPUs start at the same address (typically address 0) whenever they reset. Further logic is then required to identify whether it is a cold or warm boot to direct CPUs to the right execution path. If the reset vector address (reflected in the reset vector base address register ``RVBAR_EL3``) is programmable then it is possible to make each CPU start directly at the right address, both on a cold and warm reset. Therefore, the boot type detection can be skipped, resulting in the following boot flow: |Reset code flow with programmable reset address| To enable this boot flow, compile TF-A with ``PROGRAMMABLE_RESET_ADDRESS=1``. This option only affects the TF-A reset image, which is BL1 by default or BL31 if ``RESET_TO_BL31=1``. On both the FVP and Juno platforms, the reset vector address is not programmable so both ports use ``PROGRAMMABLE_RESET_ADDRESS=0``. Cold boot on a single CPU ------------------------- By default, TF-A assumes that several CPUs may be released out of reset. Therefore, the cold boot code has to arbitrate access to hardware resources shared amongst CPUs. This is done by nominating one of the CPUs as the primary, which is responsible for initialising shared hardware and coordinating the boot flow with the other CPUs. If the platform guarantees that only a single CPU will ever be brought up then no arbitration is required. The notion of primary/secondary CPU itself no longer applies. This results in the following boot flow: |Reset code flow with single CPU released out of reset| To enable this boot flow, compile TF-A with ``COLD_BOOT_SINGLE_CPU=1``. This option only affects the TF-A reset image, which is BL1 by default or BL31 if ``RESET_TO_BL31=1``. On both the FVP and Juno platforms, although only one core is powered up by default, there are platform-specific ways to release any number of cores out of reset. Therefore, both platform ports use ``COLD_BOOT_SINGLE_CPU=0``. Programmable CPU reset address, Cold boot on a single CPU --------------------------------------------------------- It is obviously possible to combine both optimisations on platforms that have a programmable CPU reset address and which release a single CPU out of reset. This results in the following boot flow: |Reset code flow with programmable reset address and single CPU released out of reset| To enable this boot flow, compile TF-A with both ``COLD_BOOT_SINGLE_CPU=1`` and ``PROGRAMMABLE_RESET_ADDRESS=1``. These options only affect the TF-A reset image, which is BL1 by default or BL31 if ``RESET_TO_BL31=1``. Using BL31 entrypoint as the reset address ------------------------------------------ On some platforms the runtime firmware (BL3x images) for the application processors are loaded by some firmware running on a secure system processor on the SoC, rather than by BL1 and BL2 running on the primary application processor. For this type of SoC it is desirable for the application processor to always reset to BL31 which eliminates the need for BL1 and BL2. TF-A provides a build-time option ``RESET_TO_BL31`` that includes some additional logic in the BL31 entry point to support this use case. In this configuration, the platform's Trusted Boot Firmware must ensure that BL31 is loaded to its runtime address, which must match the CPU's ``RVBAR_EL3`` reset vector base address, before the application processor is powered on. Additionally, platform software is responsible for loading the other BL3x images required and providing entry point information for them to BL31. Loading these images might be done by the Trusted Boot Firmware or by platform code in BL31. Although the Arm FVP platform does not support programming the reset base address dynamically at run-time, it is possible to set the initial value of the ``RVBAR_EL3`` register at start-up. This feature is provided on the Base FVP only. It allows the Arm FVP port to support the ``RESET_TO_BL31`` configuration, in which case the ``bl31.bin`` image must be loaded to its run address in Trusted SRAM and all CPU reset vectors be changed from the default ``0x0`` to this run address. See the :ref:`User Guide` for details of running the FVP models in this way. Although technically it would be possible to program the reset base address with the right support in the SCP firmware, this is currently not implemented so the Juno port doesn't support the ``RESET_TO_BL31`` configuration. The ``RESET_TO_BL31`` configuration requires some additions and changes in the BL31 functionality: Determination of boot path ~~~~~~~~~~~~~~~~~~~~~~~~~~ In this configuration, BL31 uses the same reset framework and code as the one described for BL1 above. Therefore, it is affected by the ``PROGRAMMABLE_RESET_ADDRESS`` and ``COLD_BOOT_SINGLE_CPU`` build options in the same way. In the default, unoptimised BL31 reset flow, on a warm boot a CPU is directed to the PSCI implementation via a platform defined mechanism. On a cold boot, the platform must place any secondary CPUs into a safe state while the primary CPU executes a modified BL31 initialization, as described below. Platform initialization ~~~~~~~~~~~~~~~~~~~~~~~ In this configuration, when the CPU resets to BL31 there are no parameters that can be passed in registers by previous boot stages. Instead, the platform code in BL31 needs to know, or be able to determine, the location of the BL32 (if required) and BL33 images and provide this information in response to the ``bl31_plat_get_next_image_ep_info()`` function. Additionally, platform software is responsible for carrying out any security initialisation, for example programming a TrustZone address space controller. This might be done by the Trusted Boot Firmware or by platform code in BL31. -------------- *Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.* .. |Default reset code flow| image:: ../resources/diagrams/default_reset_code.png .. |Reset code flow with programmable reset address| image:: ../resources/diagrams/reset_code_no_boot_type_check.png .. |Reset code flow with single CPU released out of reset| image:: ../resources/diagrams/reset_code_no_cpu_check.png .. |Reset code flow with programmable reset address and single CPU released out of reset| image:: ../resources/diagrams/reset_code_no_checks.png trusted-firmware-a-2.2/docs/design/trusted-board-boot.rst000066400000000000000000000222511355360272700235660ustar00rootroot00000000000000Trusted Board Boot ================== The Trusted Board Boot (TBB) feature prevents malicious firmware from running on the platform by authenticating all firmware images up to and including the normal world bootloader. It does this by establishing a Chain of Trust using Public-Key-Cryptography Standards (PKCS). This document describes the design of Trusted Firmware-A (TF-A) TBB, which is an implementation of the `Trusted Board Boot Requirements (TBBR)`_ specification, Arm DEN0006D. It should be used in conjunction with the :ref:`Firmware Update (FWU)` design document, which implements a specific aspect of the TBBR. Chain of Trust -------------- A Chain of Trust (CoT) starts with a set of implicitly trusted components. On the Arm development platforms, these components are: - A SHA-256 hash of the Root of Trust Public Key (ROTPK). It is stored in the trusted root-key storage registers. - The BL1 image, on the assumption that it resides in ROM so cannot be tampered with. The remaining components in the CoT are either certificates or boot loader images. The certificates follow the `X.509 v3`_ standard. This standard enables adding custom extensions to the certificates, which are used to store essential information to establish the CoT. In the TBB CoT all certificates are self-signed. There is no need for a Certificate Authority (CA) because the CoT is not established by verifying the validity of a certificate's issuer but by the content of the certificate extensions. To sign the certificates, the PKCS#1 SHA-256 with RSA Encryption signature scheme is used with a RSA key length of 2048 bits. Future version of TF-A will support additional cryptographic algorithms. The certificates are categorised as "Key" and "Content" certificates. Key certificates are used to verify public keys which have been used to sign content certificates. Content certificates are used to store the hash of a boot loader image. An image can be authenticated by calculating its hash and matching it with the hash extracted from the content certificate. The SHA-256 function is used to calculate all hashes. The public keys and hashes are included as non-standard extension fields in the `X.509 v3`_ certificates. The keys used to establish the CoT are: - **Root of trust key** The private part of this key is used to sign the BL2 content certificate and the trusted key certificate. The public part is the ROTPK. - **Trusted world key** The private part is used to sign the key certificates corresponding to the secure world images (SCP_BL2, BL31 and BL32). The public part is stored in one of the extension fields in the trusted world certificate. - **Non-trusted world key** The private part is used to sign the key certificate corresponding to the non secure world image (BL33). The public part is stored in one of the extension fields in the trusted world certificate. - **BL3-X keys** For each of SCP_BL2, BL31, BL32 and BL33, the private part is used to sign the content certificate for the BL3-X image. The public part is stored in one of the extension fields in the corresponding key certificate. The following images are included in the CoT: - BL1 - BL2 - SCP_BL2 (optional) - BL31 - BL33 - BL32 (optional) The following certificates are used to authenticate the images. - **BL2 content certificate** It is self-signed with the private part of the ROT key. It contains a hash of the BL2 image. - **Trusted key certificate** It is self-signed with the private part of the ROT key. It contains the public part of the trusted world key and the public part of the non-trusted world key. - **SCP_BL2 key certificate** It is self-signed with the trusted world key. It contains the public part of the SCP_BL2 key. - **SCP_BL2 content certificate** It is self-signed with the SCP_BL2 key. It contains a hash of the SCP_BL2 image. - **BL31 key certificate** It is self-signed with the trusted world key. It contains the public part of the BL31 key. - **BL31 content certificate** It is self-signed with the BL31 key. It contains a hash of the BL31 image. - **BL32 key certificate** It is self-signed with the trusted world key. It contains the public part of the BL32 key. - **BL32 content certificate** It is self-signed with the BL32 key. It contains a hash of the BL32 image. - **BL33 key certificate** It is self-signed with the non-trusted world key. It contains the public part of the BL33 key. - **BL33 content certificate** It is self-signed with the BL33 key. It contains a hash of the BL33 image. The SCP_BL2 and BL32 certificates are optional, but they must be present if the corresponding SCP_BL2 or BL32 images are present. Trusted Board Boot Sequence --------------------------- The CoT is verified through the following sequence of steps. The system panics if any of the steps fail. - BL1 loads and verifies the BL2 content certificate. The issuer public key is read from the verified certificate. A hash of that key is calculated and compared with the hash of the ROTPK read from the trusted root-key storage registers. If they match, the BL2 hash is read from the certificate. .. note:: The matching operation is platform specific and is currently unimplemented on the Arm development platforms. - BL1 loads the BL2 image. Its hash is calculated and compared with the hash read from the certificate. Control is transferred to the BL2 image if all the comparisons succeed. - BL2 loads and verifies the trusted key certificate. The issuer public key is read from the verified certificate. A hash of that key is calculated and compared with the hash of the ROTPK read from the trusted root-key storage registers. If the comparison succeeds, BL2 reads and saves the trusted and non-trusted world public keys from the verified certificate. The next two steps are executed for each of the SCP_BL2, BL31 & BL32 images. The steps for the optional SCP_BL2 and BL32 images are skipped if these images are not present. - BL2 loads and verifies the BL3x key certificate. The certificate signature is verified using the trusted world public key. If the signature verification succeeds, BL2 reads and saves the BL3x public key from the certificate. - BL2 loads and verifies the BL3x content certificate. The signature is verified using the BL3x public key. If the signature verification succeeds, BL2 reads and saves the BL3x image hash from the certificate. The next two steps are executed only for the BL33 image. - BL2 loads and verifies the BL33 key certificate. If the signature verification succeeds, BL2 reads and saves the BL33 public key from the certificate. - BL2 loads and verifies the BL33 content certificate. If the signature verification succeeds, BL2 reads and saves the BL33 image hash from the certificate. The next step is executed for all the boot loader images. - BL2 calculates the hash of each image. It compares it with the hash obtained from the corresponding content certificate. The image authentication succeeds if the hashes match. The Trusted Board Boot implementation spans both generic and platform-specific BL1 and BL2 code, and in tool code on the host build machine. The feature is enabled through use of specific build flags as described in the :ref:`User Guide`. On the host machine, a tool generates the certificates, which are included in the FIP along with the boot loader images. These certificates are loaded in Trusted SRAM using the IO storage framework. They are then verified by an Authentication module included in TF-A. The mechanism used for generating the FIP and the Authentication module are described in the following sections. Authentication Framework ------------------------ The authentication framework included in TF-A provides support to implement the desired trusted boot sequence. Arm platforms use this framework to implement the boot requirements specified in the `Trusted Board Boot Requirements (TBBR)`_ document. More information about the authentication framework can be found in the :ref:`Authentication Framework & Chain of Trust` document. Certificate Generation Tool --------------------------- The ``cert_create`` tool is built and runs on the host machine as part of the TF-A build process when ``GENERATE_COT=1``. It takes the boot loader images and keys as inputs (keys must be in PEM format) and generates the certificates (in DER format) required to establish the CoT. New keys can be generated by the tool in case they are not provided. The certificates are then passed as inputs to the ``fiptool`` utility for creating the FIP. The certificates are also stored individually in the in the output build directory. The tool resides in the ``tools/cert_create`` directory. It uses OpenSSL SSL library version 1.0.1 or later to generate the X.509 certificates. Instructions for building and using the tool can be found in the :ref:`User Guide`. -------------- *Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved.* .. _X.509 v3: https://tools.ietf.org/rfc/rfc5280.txt .. _Trusted Board Boot Requirements (TBBR): https://developer.arm.com/docs/den0006/latest/trusted-board-boot-requirements-client-tbbr-client-armv8-a trusted-firmware-a-2.2/docs/getting_started/000077500000000000000000000000001355360272700212305ustar00rootroot00000000000000trusted-firmware-a-2.2/docs/getting_started/docs-build.rst000066400000000000000000000050121355360272700240050ustar00rootroot00000000000000Building Documentation ====================== To create a rendered copy of this documentation locally you can use the `Sphinx`_ tool to build and package the plain-text documents into HTML-formatted pages. If you are building the documentation for the first time then you will need to check that you have the required software packages, as described in the *Prerequisites* section that follows. .. note:: An online copy of the documentation is available at https://www.trustedfirmware.org/docs/tf-a, if you want to view a rendered copy without doing a local build. Prerequisites ------------- For building a local copy of the |TF-A| documentation you will need, at minimum: - Python 3 (3.5 or later) - PlantUML (1.2017.15 or later) You must also install the Python modules that are specified in the ``requirements.txt`` file in the root of the ``docs`` directory. These modules can be installed using ``pip3`` (the Python Package Installer). Passing this requirements file as an argument to ``pip3`` automatically installs the specific module versions required by |TF-A|. An example set of installation commands for Ubuntu 18.04 LTS follows, assuming that the working directory is ``docs``: .. code:: shell sudo apt install python3 python3-pip plantuml pip3 install [--user] -r requirements.txt .. note:: Several other modules will be installed as dependencies. Please review the list to ensure that there will be no conflicts with other modules already installed in your environment. Passing the optional ``--user`` argument to ``pip3`` will install the Python packages only for the current user. Omitting this argument will attempt to install the packages globally and this will likely require the command to be run as root or using ``sudo``. .. note:: More advanced usage instructions for *pip* are beyond the scope of this document but you can refer to the `pip homepage`_ for detailed guides. Building rendered documentation ------------------------------- From the ``docs`` directory of the project, run the following commands. It is important to note that you will not get the correct result if the commands are run from the project root directory, as that would invoke the top-level Makefile for |TF-A| itself. .. code:: shell make clean make html Output from the build process will be placed in: :: /docs/build/html/ -------------- *Copyright (c) 2019, Arm Limited. All rights reserved.* .. _Sphinx: http://www.sphinx-doc.org/en/master/ .. _pip homepage: https://pip.pypa.io/en/stable/ trusted-firmware-a-2.2/docs/getting_started/image-terminology.rst000066400000000000000000000170111355360272700254120ustar00rootroot00000000000000Image Terminology ================= This page contains the current name, abbreviated name and purpose of the various images referred to in the Trusted Firmware project. General Notes ------------- - Some of the names and abbreviated names have changed to accommodate new requirements. The changed names are as backward compatible as possible to minimize confusion. Where applicable, the previous names are indicated. Some code, documentation and build artefacts may still refer to the previous names; these will inevitably take time to catch up. - The main name change is to prefix each image with the processor it corresponds to (for example ``AP_``, ``SCP_``, ...). In situations where there is no ambiguity (for example, within AP specific code/documentation), it is permitted to omit the processor prefix (for example, just BL1 instead of ``AP_BL1``). - Previously, the format for 3rd level images had 2 forms; ``BL3`` was either suffixed with a dash ("-") followed by a number (for example, ``BL3-1``) or a subscript number, depending on whether rich text formatting was available. This was confusing and often the dash gets omitted in practice. Therefore the new form is to just omit the dash and not use subscript formatting. - The names no longer contain dash ("-") characters at all. In some places (for example, function names) it's not possible to use this character. All dashes are either removed or replaced by underscores ("_"). - The abbreviation BL stands for BootLoader. This is a historical anomaly. Clearly, many of these images are not BootLoaders, they are simply firmware images. However, the BL abbreviation is now widely used and is retained for backwards compatibility. - The image names are not case sensitive. For example, ``bl1`` is interchangeable with ``BL1``, although mixed case should be avoided. Trusted Firmware Images ----------------------- AP Boot ROM: ``AP_BL1`` ~~~~~~~~~~~~~~~~~~~~~~~ Typically, this is the first code to execute on the AP and cannot be modified. Its primary purpose is to perform the minimum initialization necessary to load and authenticate an updateable AP firmware image into an executable RAM location, then hand-off control to that image. AP RAM Firmware: ``AP_BL2`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is the 2nd stage AP firmware. It is currently also known as the "Trusted Boot Firmware". Its primary purpose is to perform any additional initialization required to load and authenticate all 3rd level firmware images into their executable RAM locations, then hand-off control to the EL3 Runtime Firmware. EL3 Runtime Firmware: ``AP_BL31`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Also known as "SoC AP firmware" or "EL3 monitor firmware". Its primary purpose is to handle transitions between the normal and secure world. Secure-EL1 Payload (SP): ``AP_BL32`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Typically this is a TEE or Trusted OS, providing runtime secure services to the normal world. However, it may refer to a more abstract Secure-EL1 Payload (SP). Note that this abbreviation should only be used in systems where there is a single or primary image executing at Secure-EL1. In systems where there are potentially multiple SPs and there is no concept of a primary SP, this abbreviation should be avoided; use the recommended **Other AP 3rd level images** abbreviation instead. AP Normal World Firmware: ``AP_BL33`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For example, UEFI or uboot. Its primary purpose is to boot a normal world OS. Other AP 3rd level images: ``AP_BL3_XXX`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The abbreviated names of the existing 3rd level images imply a load/execution ordering (for example, ``AP_BL31 -> AP_BL32 -> AP_BL33``). Some systems may have additional images and/or a different load/execution ordering. The abbreviated names of the existing images are retained for backward compatibility but new 3rd level images should be suffixed with an underscore followed by text identifier, not a number. In systems where 3rd level images are provided by different vendors, the abbreviated name should identify the vendor as well as the image function. For example, ``AP_BL3_ARM_RAS``. SCP Boot ROM: ``SCP_BL1`` (previously ``BL0``) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Typically, this is the first code to execute on the SCP and cannot be modified. Its primary purpose is to perform the minimum initialization necessary to load and authenticate an updateable SCP firmware image into an executable RAM location, then hand-off control to that image. This may be performed in conjunction with other processor firmware (for example, ``AP_BL1`` and ``AP_BL2``). This image was previously abbreviated as ``BL0`` but in some systems, the SCP may directly load/authenticate its own firmware. In these systems, it doesn't make sense to interleave the image terminology for AP and SCP; both AP and SCP Boot ROMs are ``BL1`` from their own point of view. SCP RAM Firmware: ``SCP_BL2`` (previously ``BL3-0``) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is the 2nd stage SCP firmware. It is currently also known as the "SCP runtime firmware" but it could potentially be an intermediate firmware if the SCP needs to load/authenticate multiple 3rd level images in future. This image was previously abbreviated as BL3-0 but from the SCP's point of view, this has always been the 2nd stage firmware. The previous name is too AP-centric. Firmware Update (FWU) Images ---------------------------- The terminology for these images has not been widely adopted yet but they have to be considered in a production Trusted Board Boot solution. AP Firmware Update Boot ROM: ``AP_NS_BL1U`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Typically, this is the first normal world code to execute on the AP during a firmware update operation, and cannot be modified. Its primary purpose is to load subsequent firmware update images from an external interface and communicate with ``AP_BL1`` to authenticate those images. During firmware update, there are (potentially) multiple transitions between the secure and normal world. The "level" of the BL image is relative to the world it's in so it makes sense to encode "NS" in the normal world images. The absence of "NS" implies a secure world image. AP Firmware Update Config: ``AP_BL2U`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This image does the minimum necessary AP secure world configuration required to complete the firmware update operation. It is potentially a subset of ``AP_BL2`` functionality. SCP Firmware Update Config: ``SCP_BL2U`` (previously ``BL2-U0``) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This image does the minimum necessary SCP secure world configuration required to complete the firmware update operation. It is potentially a subset of ``SCP_BL2`` functionality. AP Firmware Updater: ``AP_NS_BL2U`` (previously ``BL3-U``) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is the 2nd stage AP normal world firmware updater. Its primary purpose is to load a new set of firmware images from an external interface and write them into non-volatile storage. Other Processor Firmware Images ------------------------------- Some systems may have additional processors to the AP and SCP. For example, a Management Control Processor (MCP). Images for these processors should follow the same terminology, with the processor abbreviation prefix, followed by underscore and the level of the firmware image. For example, MCP Boot ROM: ``MCP_BL1`` ~~~~~~~~~~~~~~~~~~~~~~~~~ MCP RAM Firmware: ``MCP_BL2`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ trusted-firmware-a-2.2/docs/getting_started/index.rst000066400000000000000000000003331355360272700230700ustar00rootroot00000000000000Getting Started =============== .. toctree:: :maxdepth: 1 :caption: Contents :numbered: user-guide docs-build image-terminology porting-guide psci-lib-integration-guide rt-svc-writers-guide trusted-firmware-a-2.2/docs/getting_started/porting-guide.rst000066400000000000000000003372171355360272700245540ustar00rootroot00000000000000Porting Guide ============= Introduction ------------ Porting Trusted Firmware-A (TF-A) to a new platform involves making some mandatory and optional modifications for both the cold and warm boot paths. Modifications consist of: - Implementing a platform-specific function or variable, - Setting up the execution context in a certain way, or - Defining certain constants (for example #defines). The platform-specific functions and variables are declared in ``include/plat/common/platform.h``. The firmware provides a default implementation of variables and functions to fulfill the optional requirements. These implementations are all weakly defined; they are provided to ease the porting effort. Each platform port can override them with its own implementation if the default implementation is inadequate. Some modifications are common to all Boot Loader (BL) stages. Section 2 discusses these in detail. The subsequent sections discuss the remaining modifications for each BL stage in detail. This document should be read in conjunction with the TF-A :ref:`User Guide`. Please refer to the :ref:`Platform Compatibility Policy` for the policy regarding compatibility and deprecation of these porting interfaces. Only Arm development platforms (such as FVP and Juno) may use the functions/definitions in ``include/plat/arm/common/`` and the corresponding source files in ``plat/arm/common/``. This is done so that there are no dependencies between platforms maintained by different people/companies. If you want to use any of the functionality present in ``plat/arm`` files, please create a pull request that moves the code to ``plat/common`` so that it can be discussed. Common modifications -------------------- This section covers the modifications that should be made by the platform for each BL stage to correctly port the firmware stack. They are categorized as either mandatory or optional. Common mandatory modifications ------------------------------ A platform port must enable the Memory Management Unit (MMU) as well as the instruction and data caches for each BL stage. Setting up the translation tables is the responsibility of the platform port because memory maps differ across platforms. A memory translation library (see ``lib/xlat_tables/``) is provided to help in this setup. Note that although this library supports non-identity mappings, this is intended only for re-mapping peripheral physical addresses and allows platforms with high I/O addresses to reduce their virtual address space. All other addresses corresponding to code and data must currently use an identity mapping. Also, the only translation granule size supported in TF-A is 4KB, as various parts of the code assume that is the case. It is not possible to switch to 16 KB or 64 KB granule sizes at the moment. In Arm standard platforms, each BL stage configures the MMU in the platform-specific architecture setup function, ``blX_plat_arch_setup()``, and uses an identity mapping for all addresses. If the build option ``USE_COHERENT_MEM`` is enabled, each platform can allocate a block of identity mapped secure memory with Device-nGnRE attributes aligned to page boundary (4K) for each BL stage. All sections which allocate coherent memory are grouped under ``coherent_ram``. For ex: Bakery locks are placed in a section identified by name ``bakery_lock`` inside ``coherent_ram`` so that its possible for the firmware to place variables in it using the following C code directive: :: __section("bakery_lock") Or alternatively the following assembler code directive: :: .section bakery_lock The ``coherent_ram`` section is a sum of all sections like ``bakery_lock`` which are used to allocate any data structures that are accessed both when a CPU is executing with its MMU and caches enabled, and when it's running with its MMU and caches disabled. Examples are given below. The following variables, functions and constants must be defined by the platform for the firmware to work correctly. File : platform_def.h [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Each platform must ensure that a header file of this name is in the system include path with the following constants defined. This will require updating the list of ``PLAT_INCLUDES`` in the ``platform.mk`` file. Platform ports may optionally use the file ``include/plat/common/common_def.h``, which provides typical values for some of the constants below. These values are likely to be suitable for all platform ports. - **#define : PLATFORM_LINKER_FORMAT** Defines the linker format used by the platform, for example ``elf64-littleaarch64``. - **#define : PLATFORM_LINKER_ARCH** Defines the processor architecture for the linker by the platform, for example ``aarch64``. - **#define : PLATFORM_STACK_SIZE** Defines the normal stack memory available to each CPU. This constant is used by ``plat/common/aarch64/platform_mp_stack.S`` and ``plat/common/aarch64/platform_up_stack.S``. - **define : CACHE_WRITEBACK_GRANULE** Defines the size in bits of the largest cache line across all the cache levels in the platform. - **#define : FIRMWARE_WELCOME_STR** Defines the character string printed by BL1 upon entry into the ``bl1_main()`` function. - **#define : PLATFORM_CORE_COUNT** Defines the total number of CPUs implemented by the platform across all clusters in the system. - **#define : PLAT_NUM_PWR_DOMAINS** Defines the total number of nodes in the power domain topology tree at all the power domain levels used by the platform. This macro is used by the PSCI implementation to allocate data structures to represent power domain topology. - **#define : PLAT_MAX_PWR_LVL** Defines the maximum power domain level that the power management operations should apply to. More often, but not always, the power domain level corresponds to affinity level. This macro allows the PSCI implementation to know the highest power domain level that it should consider for power management operations in the system that the platform implements. For example, the Base AEM FVP implements two clusters with a configurable number of CPUs and it reports the maximum power domain level as 1. - **#define : PLAT_MAX_OFF_STATE** Defines the local power state corresponding to the deepest power down possible at every power domain level in the platform. The local power states for each level may be sparsely allocated between 0 and this value with 0 being reserved for the RUN state. The PSCI implementation uses this value to initialize the local power states of the power domain nodes and to specify the requested power state for a PSCI_CPU_OFF call. - **#define : PLAT_MAX_RET_STATE** Defines the local power state corresponding to the deepest retention state possible at every power domain level in the platform. This macro should be a value less than PLAT_MAX_OFF_STATE and greater than 0. It is used by the PSCI implementation to distinguish between retention and power down local power states within PSCI_CPU_SUSPEND call. - **#define : PLAT_MAX_PWR_LVL_STATES** Defines the maximum number of local power states per power domain level that the platform supports. The default value of this macro is 2 since most platforms just support a maximum of two local power states at each power domain level (power-down and retention). If the platform needs to account for more local power states, then it must redefine this macro. Currently, this macro is used by the Generic PSCI implementation to size the array used for PSCI_STAT_COUNT/RESIDENCY accounting. - **#define : BL1_RO_BASE** Defines the base address in secure ROM where BL1 originally lives. Must be aligned on a page-size boundary. - **#define : BL1_RO_LIMIT** Defines the maximum address in secure ROM that BL1's actual content (i.e. excluding any data section allocated at runtime) can occupy. - **#define : BL1_RW_BASE** Defines the base address in secure RAM where BL1's read-write data will live at runtime. Must be aligned on a page-size boundary. - **#define : BL1_RW_LIMIT** Defines the maximum address in secure RAM that BL1's read-write data can occupy at runtime. - **#define : BL2_BASE** Defines the base address in secure RAM where BL1 loads the BL2 binary image. Must be aligned on a page-size boundary. This constant is not applicable when BL2_IN_XIP_MEM is set to '1'. - **#define : BL2_LIMIT** Defines the maximum address in secure RAM that the BL2 image can occupy. This constant is not applicable when BL2_IN_XIP_MEM is set to '1'. - **#define : BL2_RO_BASE** Defines the base address in secure XIP memory where BL2 RO section originally lives. Must be aligned on a page-size boundary. This constant is only needed when BL2_IN_XIP_MEM is set to '1'. - **#define : BL2_RO_LIMIT** Defines the maximum address in secure XIP memory that BL2's actual content (i.e. excluding any data section allocated at runtime) can occupy. This constant is only needed when BL2_IN_XIP_MEM is set to '1'. - **#define : BL2_RW_BASE** Defines the base address in secure RAM where BL2's read-write data will live at runtime. Must be aligned on a page-size boundary. This constant is only needed when BL2_IN_XIP_MEM is set to '1'. - **#define : BL2_RW_LIMIT** Defines the maximum address in secure RAM that BL2's read-write data can occupy at runtime. This constant is only needed when BL2_IN_XIP_MEM is set to '1'. - **#define : BL31_BASE** Defines the base address in secure RAM where BL2 loads the BL31 binary image. Must be aligned on a page-size boundary. - **#define : BL31_LIMIT** Defines the maximum address in secure RAM that the BL31 image can occupy. For every image, the platform must define individual identifiers that will be used by BL1 or BL2 to load the corresponding image into memory from non-volatile storage. For the sake of performance, integer numbers will be used as identifiers. The platform will use those identifiers to return the relevant information about the image to be loaded (file handler, load address, authentication information, etc.). The following image identifiers are mandatory: - **#define : BL2_IMAGE_ID** BL2 image identifier, used by BL1 to load BL2. - **#define : BL31_IMAGE_ID** BL31 image identifier, used by BL2 to load BL31. - **#define : BL33_IMAGE_ID** BL33 image identifier, used by BL2 to load BL33. If Trusted Board Boot is enabled, the following certificate identifiers must also be defined: - **#define : TRUSTED_BOOT_FW_CERT_ID** BL2 content certificate identifier, used by BL1 to load the BL2 content certificate. - **#define : TRUSTED_KEY_CERT_ID** Trusted key certificate identifier, used by BL2 to load the trusted key certificate. - **#define : SOC_FW_KEY_CERT_ID** BL31 key certificate identifier, used by BL2 to load the BL31 key certificate. - **#define : SOC_FW_CONTENT_CERT_ID** BL31 content certificate identifier, used by BL2 to load the BL31 content certificate. - **#define : NON_TRUSTED_FW_KEY_CERT_ID** BL33 key certificate identifier, used by BL2 to load the BL33 key certificate. - **#define : NON_TRUSTED_FW_CONTENT_CERT_ID** BL33 content certificate identifier, used by BL2 to load the BL33 content certificate. - **#define : FWU_CERT_ID** Firmware Update (FWU) certificate identifier, used by NS_BL1U to load the FWU content certificate. - **#define : PLAT_CRYPTOCELL_BASE** This defines the base address of Arm® TrustZone® CryptoCell and must be defined if CryptoCell crypto driver is used for Trusted Board Boot. For capable Arm platforms, this driver is used if ``ARM_CRYPTOCELL_INTEG`` is set. If the AP Firmware Updater Configuration image, BL2U is used, the following must also be defined: - **#define : BL2U_BASE** Defines the base address in secure memory where BL1 copies the BL2U binary image. Must be aligned on a page-size boundary. - **#define : BL2U_LIMIT** Defines the maximum address in secure memory that the BL2U image can occupy. - **#define : BL2U_IMAGE_ID** BL2U image identifier, used by BL1 to fetch an image descriptor corresponding to BL2U. If the SCP Firmware Update Configuration Image, SCP_BL2U is used, the following must also be defined: - **#define : SCP_BL2U_IMAGE_ID** SCP_BL2U image identifier, used by BL1 to fetch an image descriptor corresponding to SCP_BL2U. .. note:: TF-A does not provide source code for this image. If the Non-Secure Firmware Updater ROM, NS_BL1U is used, the following must also be defined: - **#define : NS_BL1U_BASE** Defines the base address in non-secure ROM where NS_BL1U executes. Must be aligned on a page-size boundary. .. note:: TF-A does not provide source code for this image. - **#define : NS_BL1U_IMAGE_ID** NS_BL1U image identifier, used by BL1 to fetch an image descriptor corresponding to NS_BL1U. If the Non-Secure Firmware Updater, NS_BL2U is used, the following must also be defined: - **#define : NS_BL2U_BASE** Defines the base address in non-secure memory where NS_BL2U executes. Must be aligned on a page-size boundary. .. note:: TF-A does not provide source code for this image. - **#define : NS_BL2U_IMAGE_ID** NS_BL2U image identifier, used by BL1 to fetch an image descriptor corresponding to NS_BL2U. For the the Firmware update capability of TRUSTED BOARD BOOT, the following macros may also be defined: - **#define : PLAT_FWU_MAX_SIMULTANEOUS_IMAGES** Total number of images that can be loaded simultaneously. If the platform doesn't specify any value, it defaults to 10. If a SCP_BL2 image is supported by the platform, the following constants must also be defined: - **#define : SCP_BL2_IMAGE_ID** SCP_BL2 image identifier, used by BL2 to load SCP_BL2 into secure memory from platform storage before being transferred to the SCP. - **#define : SCP_FW_KEY_CERT_ID** SCP_BL2 key certificate identifier, used by BL2 to load the SCP_BL2 key certificate (mandatory when Trusted Board Boot is enabled). - **#define : SCP_FW_CONTENT_CERT_ID** SCP_BL2 content certificate identifier, used by BL2 to load the SCP_BL2 content certificate (mandatory when Trusted Board Boot is enabled). If a BL32 image is supported by the platform, the following constants must also be defined: - **#define : BL32_IMAGE_ID** BL32 image identifier, used by BL2 to load BL32. - **#define : TRUSTED_OS_FW_KEY_CERT_ID** BL32 key certificate identifier, used by BL2 to load the BL32 key certificate (mandatory when Trusted Board Boot is enabled). - **#define : TRUSTED_OS_FW_CONTENT_CERT_ID** BL32 content certificate identifier, used by BL2 to load the BL32 content certificate (mandatory when Trusted Board Boot is enabled). - **#define : BL32_BASE** Defines the base address in secure memory where BL2 loads the BL32 binary image. Must be aligned on a page-size boundary. - **#define : BL32_LIMIT** Defines the maximum address that the BL32 image can occupy. If the Test Secure-EL1 Payload (TSP) instantiation of BL32 is supported by the platform, the following constants must also be defined: - **#define : TSP_SEC_MEM_BASE** Defines the base address of the secure memory used by the TSP image on the platform. This must be at the same address or below ``BL32_BASE``. - **#define : TSP_SEC_MEM_SIZE** Defines the size of the secure memory used by the BL32 image on the platform. ``TSP_SEC_MEM_BASE`` and ``TSP_SEC_MEM_SIZE`` must fully accommodate the memory required by the BL32 image, defined by ``BL32_BASE`` and ``BL32_LIMIT``. - **#define : TSP_IRQ_SEC_PHY_TIMER** Defines the ID of the secure physical generic timer interrupt used by the TSP's interrupt handling code. If the platform port uses the translation table library code, the following constants must also be defined: - **#define : PLAT_XLAT_TABLES_DYNAMIC** Optional flag that can be set per-image to enable the dynamic allocation of regions even when the MMU is enabled. If not defined, only static functionality will be available, if defined and set to 1 it will also include the dynamic functionality. - **#define : MAX_XLAT_TABLES** Defines the maximum number of translation tables that are allocated by the translation table library code. To minimize the amount of runtime memory used, choose the smallest value needed to map the required virtual addresses for each BL stage. If ``PLAT_XLAT_TABLES_DYNAMIC`` flag is enabled for a BL image, ``MAX_XLAT_TABLES`` must be defined to accommodate the dynamic regions as well. - **#define : MAX_MMAP_REGIONS** Defines the maximum number of regions that are allocated by the translation table library code. A region consists of physical base address, virtual base address, size and attributes (Device/Memory, RO/RW, Secure/Non-Secure), as defined in the ``mmap_region_t`` structure. The platform defines the regions that should be mapped. Then, the translation table library will create the corresponding tables and descriptors at runtime. To minimize the amount of runtime memory used, choose the smallest value needed to register the required regions for each BL stage. If ``PLAT_XLAT_TABLES_DYNAMIC`` flag is enabled for a BL image, ``MAX_MMAP_REGIONS`` must be defined to accommodate the dynamic regions as well. - **#define : PLAT_VIRT_ADDR_SPACE_SIZE** Defines the total size of the virtual address space in bytes. For example, for a 32 bit virtual address space, this value should be ``(1ULL << 32)``. - **#define : PLAT_PHY_ADDR_SPACE_SIZE** Defines the total size of the physical address space in bytes. For example, for a 32 bit physical address space, this value should be ``(1ULL << 32)``. If the platform port uses the IO storage framework, the following constants must also be defined: - **#define : MAX_IO_DEVICES** Defines the maximum number of registered IO devices. Attempting to register more devices than this value using ``io_register_device()`` will fail with -ENOMEM. - **#define : MAX_IO_HANDLES** Defines the maximum number of open IO handles. Attempting to open more IO entities than this value using ``io_open()`` will fail with -ENOMEM. - **#define : MAX_IO_BLOCK_DEVICES** Defines the maximum number of registered IO block devices. Attempting to register more devices this value using ``io_dev_open()`` will fail with -ENOMEM. MAX_IO_BLOCK_DEVICES should be less than MAX_IO_DEVICES. With this macro, multiple block devices could be supported at the same time. If the platform needs to allocate data within the per-cpu data framework in BL31, it should define the following macro. Currently this is only required if the platform decides not to use the coherent memory section by undefining the ``USE_COHERENT_MEM`` build flag. In this case, the framework allocates the required memory within the the per-cpu data to minimize wastage. - **#define : PLAT_PCPU_DATA_SIZE** Defines the memory (in bytes) to be reserved within the per-cpu data structure for use by the platform layer. The following constants are optional. They should be defined when the platform memory layout implies some image overlaying like in Arm standard platforms. - **#define : BL31_PROGBITS_LIMIT** Defines the maximum address in secure RAM that the BL31's progbits sections can occupy. - **#define : TSP_PROGBITS_LIMIT** Defines the maximum address that the TSP's progbits sections can occupy. If the platform port uses the PL061 GPIO driver, the following constant may optionally be defined: - **PLAT_PL061_MAX_GPIOS** Maximum number of GPIOs required by the platform. This allows control how much memory is allocated for PL061 GPIO controllers. The default value is #. $(eval $(call add_define,PLAT_PL061_MAX_GPIOS)) If the platform port uses the partition driver, the following constant may optionally be defined: - **PLAT_PARTITION_MAX_ENTRIES** Maximum number of partition entries required by the platform. This allows control how much memory is allocated for partition entries. The default value is 128. For example, define the build flag in ``platform.mk``: PLAT_PARTITION_MAX_ENTRIES := 12 $(eval $(call add_define,PLAT_PARTITION_MAX_ENTRIES)) - **PLAT_PARTITION_BLOCK_SIZE** The size of partition block. It could be either 512 bytes or 4096 bytes. The default value is 512. For example, define the build flag in ``platform.mk``: PLAT_PARTITION_BLOCK_SIZE := 4096 $(eval $(call add_define,PLAT_PARTITION_BLOCK_SIZE)) The following constant is optional. It should be defined to override the default behaviour of the ``assert()`` function (for example, to save memory). - **PLAT_LOG_LEVEL_ASSERT** If ``PLAT_LOG_LEVEL_ASSERT`` is higher or equal than ``LOG_LEVEL_VERBOSE``, ``assert()`` prints the name of the file, the line number and the asserted expression. Else if it is higher than ``LOG_LEVEL_INFO``, it prints the file name and the line number. Else if it is lower than ``LOG_LEVEL_INFO``, it doesn't print anything to the console. If ``PLAT_LOG_LEVEL_ASSERT`` isn't defined, it defaults to ``LOG_LEVEL``. If the platform port uses the Activity Monitor Unit, the following constants may be defined: - **PLAT_AMU_GROUP1_COUNTERS_MASK** This mask reflects the set of group counters that should be enabled. The maximum number of group 1 counters supported by AMUv1 is 16 so the mask can be at most 0xffff. If the platform does not define this mask, no group 1 counters are enabled. If the platform defines this mask, the following constant needs to also be defined. - **PLAT_AMU_GROUP1_NR_COUNTERS** This value is used to allocate an array to save and restore the counters specified by ``PLAT_AMU_GROUP1_COUNTERS_MASK`` on CPU suspend. This value should be equal to the highest bit position set in the mask, plus 1. The maximum number of group 1 counters in AMUv1 is 16. File : plat_macros.S [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Each platform must ensure a file of this name is in the system include path with the following macro defined. In the Arm development platforms, this file is found in ``plat/arm/board//include/plat_macros.S``. - **Macro : plat_crash_print_regs** This macro allows the crash reporting routine to print relevant platform registers in case of an unhandled exception in BL31. This aids in debugging and this macro can be defined to be empty in case register reporting is not desired. For instance, GIC or interconnect registers may be helpful for troubleshooting. Handling Reset -------------- BL1 by default implements the reset vector where execution starts from a cold or warm boot. BL31 can be optionally set as a reset vector using the ``RESET_TO_BL31`` make variable. For each CPU, the reset vector code is responsible for the following tasks: #. Distinguishing between a cold boot and a warm boot. #. In the case of a cold boot and the CPU being a secondary CPU, ensuring that the CPU is placed in a platform-specific state until the primary CPU performs the necessary steps to remove it from this state. #. In the case of a warm boot, ensuring that the CPU jumps to a platform- specific address in the BL31 image in the same processor mode as it was when released from reset. The following functions need to be implemented by the platform port to enable reset vector code to perform the above tasks. Function : plat_get_my_entrypoint() [mandatory when PROGRAMMABLE_RESET_ADDRESS == 0] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : uintptr_t This function is called with the MMU and caches disabled (``SCTLR_EL3.M`` = 0 and ``SCTLR_EL3.C`` = 0). The function is responsible for distinguishing between a warm and cold reset for the current CPU using platform-specific means. If it's a warm reset, then it returns the warm reset entrypoint point provided to ``plat_setup_psci_ops()`` during BL31 initialization. If it's a cold reset then this function must return zero. This function does not follow the Procedure Call Standard used by the Application Binary Interface for the Arm 64-bit architecture. The caller should not assume that callee saved registers are preserved across a call to this function. This function fulfills requirement 1 and 3 listed above. Note that for platforms that support programming the reset address, it is expected that a CPU will start executing code directly at the right address, both on a cold and warm reset. In this case, there is no need to identify the type of reset nor to query the warm reset entrypoint. Therefore, implementing this function is not required on such platforms. Function : plat_secondary_cold_boot_setup() [mandatory when COLD_BOOT_SINGLE_CPU == 0] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void This function is called with the MMU and data caches disabled. It is responsible for placing the executing secondary CPU in a platform-specific state until the primary CPU performs the necessary actions to bring it out of that state and allow entry into the OS. This function must not return. In the Arm FVP port, when using the normal boot flow, each secondary CPU powers itself off. The primary CPU is responsible for powering up the secondary CPUs when normal world software requires them. When booting an EL3 payload instead, they stay powered on and are put in a holding pen until their mailbox gets populated. This function fulfills requirement 2 above. Note that for platforms that can't release secondary CPUs out of reset, only the primary CPU will execute the cold boot code. Therefore, implementing this function is not required on such platforms. Function : plat_is_my_cpu_primary() [mandatory when COLD_BOOT_SINGLE_CPU == 0] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : unsigned int This function identifies whether the current CPU is the primary CPU or a secondary CPU. A return value of zero indicates that the CPU is not the primary CPU, while a non-zero return value indicates that the CPU is the primary CPU. Note that for platforms that can't release secondary CPUs out of reset, only the primary CPU will execute the cold boot code. Therefore, there is no need to distinguish between primary and secondary CPUs and implementing this function is not required. Function : platform_mem_init() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This function is called before any access to data is made by the firmware, in order to carry out any essential memory initialization. Function: plat_get_rotpk_info() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void *, void **, unsigned int *, unsigned int * Return : int This function is mandatory when Trusted Board Boot is enabled. It returns a pointer to the ROTPK stored in the platform (or a hash of it) and its length. The ROTPK must be encoded in DER format according to the following ASN.1 structure: :: AlgorithmIdentifier ::= SEQUENCE { algorithm OBJECT IDENTIFIER, parameters ANY DEFINED BY algorithm OPTIONAL } SubjectPublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier, subjectPublicKey BIT STRING } In case the function returns a hash of the key: :: DigestInfo ::= SEQUENCE { digestAlgorithm AlgorithmIdentifier, digest OCTET STRING } The function returns 0 on success. Any other value is treated as error by the Trusted Board Boot. The function also reports extra information related to the ROTPK in the flags parameter: :: ROTPK_IS_HASH : Indicates that the ROTPK returned by the platform is a hash. ROTPK_NOT_DEPLOYED : This allows the platform to skip certificate ROTPK verification while the platform ROTPK is not deployed. When this flag is set, the function does not need to return a platform ROTPK, and the authentication framework uses the ROTPK in the certificate without verifying it against the platform value. This flag must not be used in a deployed production environment. Function: plat_get_nv_ctr() ~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void *, unsigned int * Return : int This function is mandatory when Trusted Board Boot is enabled. It returns the non-volatile counter value stored in the platform in the second argument. The cookie in the first argument may be used to select the counter in case the platform provides more than one (for example, on platforms that use the default TBBR CoT, the cookie will correspond to the OID values defined in TRUSTED_FW_NVCOUNTER_OID or NON_TRUSTED_FW_NVCOUNTER_OID). The function returns 0 on success. Any other value means the counter value could not be retrieved from the platform. Function: plat_set_nv_ctr() ~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void *, unsigned int Return : int This function is mandatory when Trusted Board Boot is enabled. It sets a new counter value in the platform. The cookie in the first argument may be used to select the counter (as explained in plat_get_nv_ctr()). The second argument is the updated counter value to be written to the NV counter. The function returns 0 on success. Any other value means the counter value could not be updated. Function: plat_set_nv_ctr2() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void *, const auth_img_desc_t *, unsigned int Return : int This function is optional when Trusted Board Boot is enabled. If this interface is defined, then ``plat_set_nv_ctr()`` need not be defined. The first argument passed is a cookie and is typically used to differentiate between a Non Trusted NV Counter and a Trusted NV Counter. The second argument is a pointer to an authentication image descriptor and may be used to decide if the counter is allowed to be updated or not. The third argument is the updated counter value to be written to the NV counter. The function returns 0 on success. Any other value means the counter value either could not be updated or the authentication image descriptor indicates that it is not allowed to be updated. Common mandatory function modifications --------------------------------------- The following functions are mandatory functions which need to be implemented by the platform port. Function : plat_my_core_pos() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : unsigned int This function returns the index of the calling CPU which is used as a CPU-specific linear index into blocks of memory (for example while allocating per-CPU stacks). This function will be invoked very early in the initialization sequence which mandates that this function should be implemented in assembly and should not rely on the availability of a C runtime environment. This function can clobber x0 - x8 and must preserve x9 - x29. This function plays a crucial role in the power domain topology framework in PSCI and details of this can be found in :ref:`PSCI Power Domain Tree Structure`. Function : plat_core_pos_by_mpidr() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : u_register_t Return : int This function validates the ``MPIDR`` of a CPU and converts it to an index, which can be used as a CPU-specific linear index into blocks of memory. In case the ``MPIDR`` is invalid, this function returns -1. This function will only be invoked by BL31 after the power domain topology is initialized and can utilize the C runtime environment. For further details about how TF-A represents the power domain topology and how this relates to the linear CPU index, please refer :ref:`PSCI Power Domain Tree Structure`. Function : plat_get_mbedtls_heap() [when TRUSTED_BOARD_BOOT == 1] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Arguments : void **heap_addr, size_t *heap_size Return : int This function is invoked during Mbed TLS library initialisation to get a heap, by means of a starting address and a size. This heap will then be used internally by the Mbed TLS library. Hence, each BL stage that utilises Mbed TLS must be able to provide a heap to it. A helper function can be found in `drivers/auth/mbedtls/mbedtls_common.c` in which a heap is statically reserved during compile time inside every image (i.e. every BL stage) that utilises Mbed TLS. In this default implementation, the function simply returns the address and size of this "pre-allocated" heap. For a platform to use this default implementation, only a call to the helper from inside plat_get_mbedtls_heap() body is enough and nothing else is needed. However, by writting their own implementation, platforms have the potential to optimise memory usage. For example, on some Arm platforms, the Mbed TLS heap is shared between BL1 and BL2 stages and, thus, the necessary space is not reserved twice. On success the function should return 0 and a negative error code otherwise. Common optional modifications ----------------------------- The following are helper functions implemented by the firmware that perform common platform-specific tasks. A platform may choose to override these definitions. Function : plat_set_my_stack() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This function sets the current stack pointer to the normal memory stack that has been allocated for the current CPU. For BL images that only require a stack for the primary CPU, the UP version of the function is used. The size of the stack allocated to each CPU is specified by the platform defined constant ``PLATFORM_STACK_SIZE``. Common implementations of this function for the UP and MP BL images are provided in ``plat/common/aarch64/platform_up_stack.S`` and ``plat/common/aarch64/platform_mp_stack.S`` Function : plat_get_my_stack() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : uintptr_t This function returns the base address of the normal memory stack that has been allocated for the current CPU. For BL images that only require a stack for the primary CPU, the UP version of the function is used. The size of the stack allocated to each CPU is specified by the platform defined constant ``PLATFORM_STACK_SIZE``. Common implementations of this function for the UP and MP BL images are provided in ``plat/common/aarch64/platform_up_stack.S`` and ``plat/common/aarch64/platform_mp_stack.S`` Function : plat_report_exception() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Return : void A platform may need to report various information about its status when an exception is taken, for example the current exception level, the CPU security state (secure/non-secure), the exception type, and so on. This function is called in the following circumstances: - In BL1, whenever an exception is taken. - In BL2, whenever an exception is taken. The default implementation doesn't do anything, to avoid making assumptions about the way the platform displays its status information. For AArch64, this function receives the exception type as its argument. Possible values for exceptions types are listed in the ``include/common/bl_common.h`` header file. Note that these constants are not related to any architectural exception code; they are just a TF-A convention. For AArch32, this function receives the exception mode as its argument. Possible values for exception modes are listed in the ``include/lib/aarch32/arch.h`` header file. Function : plat_reset_handler() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void A platform may need to do additional initialization after reset. This function allows the platform to do the platform specific initializations. Platform specific errata workarounds could also be implemented here. The API should preserve the values of callee saved registers x19 to x29. The default implementation doesn't do anything. If a platform needs to override the default implementation, refer to the :ref:`Firmware Design` for general guidelines. Function : plat_disable_acp() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This API allows a platform to disable the Accelerator Coherency Port (if present) during a cluster power down sequence. The default weak implementation doesn't do anything. Since this API is called during the power down sequence, it has restrictions for stack usage and it can use the registers x0 - x17 as scratch registers. It should preserve the value in x18 register as it is used by the caller to store the return address. Function : plat_error_handler() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : int Return : void This API is called when the generic code encounters an error situation from which it cannot continue. It allows the platform to perform error reporting or recovery actions (for example, reset the system). This function must not return. The parameter indicates the type of error using standard codes from ``errno.h``. Possible errors reported by the generic code are: - ``-EAUTH``: a certificate or image could not be authenticated (when Trusted Board Boot is enabled) - ``-ENOENT``: the requested image or certificate could not be found or an IO error was detected - ``-ENOMEM``: resources exhausted. TF-A does not use dynamic memory, so this error is usually an indication of an incorrect array size The default implementation simply spins. Function : plat_panic_handler() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This API is called when the generic code encounters an unexpected error situation from which it cannot recover. This function must not return, and must be implemented in assembly because it may be called before the C environment is initialized. .. note:: The address from where it was called is stored in x30 (Link Register). The default implementation simply spins. Function : plat_get_bl_image_load_info() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : bl_load_info_t * This function returns pointer to the list of images that the platform has populated to load. This function is invoked in BL2 to load the BL3xx images. Function : plat_get_next_bl_params() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : bl_params_t * This function returns a pointer to the shared memory that the platform has kept aside to pass TF-A related information that next BL image needs. This function is invoked in BL2 to pass this information to the next BL image. Function : plat_get_stack_protector_canary() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : u_register_t This function returns a random value that is used to initialize the canary used when the stack protector is enabled with ENABLE_STACK_PROTECTOR. A predictable value will weaken the protection as the attacker could easily write the right value as part of the attack most of the time. Therefore, it should return a true random number. .. warning:: For the protection to be effective, the global data need to be placed at a lower address than the stack bases. Failure to do so would allow an attacker to overwrite the canary as part of the stack buffer overflow attack. Function : plat_flush_next_bl_params() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This function flushes to main memory all the image params that are passed to next image. This function is invoked in BL2 to flush this information to the next BL image. Function : plat_log_get_prefix() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Return : const char * This function defines the prefix string corresponding to the `log_level` to be prepended to all the log output from TF-A. The `log_level` (argument) will correspond to one of the standard log levels defined in debug.h. The platform can override the common implementation to define a different prefix string for the log output. The implementation should be robust to future changes that increase the number of log levels. Modifications specific to a Boot Loader stage --------------------------------------------- Boot Loader Stage 1 (BL1) ------------------------- BL1 implements the reset vector where execution starts from after a cold or warm boot. For each CPU, BL1 is responsible for the following tasks: #. Handling the reset as described in section 2.2 #. In the case of a cold boot and the CPU being the primary CPU, ensuring that only this CPU executes the remaining BL1 code, including loading and passing control to the BL2 stage. #. Identifying and starting the Firmware Update process (if required). #. Loading the BL2 image from non-volatile storage into secure memory at the address specified by the platform defined constant ``BL2_BASE``. #. Populating a ``meminfo`` structure with the following information in memory, accessible by BL2 immediately upon entry. :: meminfo.total_base = Base address of secure RAM visible to BL2 meminfo.total_size = Size of secure RAM visible to BL2 By default, BL1 places this ``meminfo`` structure at the end of secure memory visible to BL2. It is possible for the platform to decide where it wants to place the ``meminfo`` structure for BL2 or restrict the amount of memory visible to BL2 by overriding the weak default implementation of ``bl1_plat_handle_post_image_load`` API. The following functions need to be implemented by the platform port to enable BL1 to perform the above tasks. Function : bl1_early_platform_setup() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This function executes with the MMU and data caches disabled. It is only called by the primary CPU. On Arm standard platforms, this function: - Enables a secure instance of SP805 to act as the Trusted Watchdog. - Initializes a UART (PL011 console), which enables access to the ``printf`` family of functions in BL1. - Enables issuing of snoop and DVM (Distributed Virtual Memory) requests to the CCI slave interface corresponding to the cluster that includes the primary CPU. Function : bl1_plat_arch_setup() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This function performs any platform-specific and architectural setup that the platform requires. Platform-specific setup might include configuration of memory controllers and the interconnect. In Arm standard platforms, this function enables the MMU. This function helps fulfill requirement 2 above. Function : bl1_platform_setup() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This function executes with the MMU and data caches enabled. It is responsible for performing any remaining platform-specific setup that can occur after the MMU and data cache have been enabled. if support for multiple boot sources is required, it initializes the boot sequence used by plat_try_next_boot_source(). In Arm standard platforms, this function initializes the storage abstraction layer used to load the next bootloader image. This function helps fulfill requirement 4 above. Function : bl1_plat_sec_mem_layout() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : meminfo * This function should only be called on the cold boot path. It executes with the MMU and data caches enabled. The pointer returned by this function must point to a ``meminfo`` structure containing the extents and availability of secure RAM for the BL1 stage. :: meminfo.total_base = Base address of secure RAM visible to BL1 meminfo.total_size = Size of secure RAM visible to BL1 This information is used by BL1 to load the BL2 image in secure RAM. BL1 also populates a similar structure to tell BL2 the extents of memory available for its own use. This function helps fulfill requirements 4 and 5 above. Function : bl1_plat_prepare_exit() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : entry_point_info_t * Return : void This function is called prior to exiting BL1 in response to the ``BL1_SMC_RUN_IMAGE`` SMC request raised by BL2. It should be used to perform platform specific clean up or bookkeeping operations before transferring control to the next image. It receives the address of the ``entry_point_info_t`` structure passed from BL2. This function runs with MMU disabled. Function : bl1_plat_set_ep_info() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int image_id, entry_point_info_t *ep_info Return : void This function allows platforms to override ``ep_info`` for the given ``image_id``. The default implementation just returns. Function : bl1_plat_get_next_image_id() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : unsigned int This and the following function must be overridden to enable the FWU feature. BL1 calls this function after platform setup to identify the next image to be loaded and executed. If the platform returns ``BL2_IMAGE_ID`` then BL1 proceeds with the normal boot sequence, which loads and executes BL2. If the platform returns a different image id, BL1 assumes that Firmware Update is required. The default implementation always returns ``BL2_IMAGE_ID``. The Arm development platforms override this function to detect if firmware update is required, and if so, return the first image in the firmware update process. Function : bl1_plat_get_image_desc() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int image_id Return : image_desc_t * BL1 calls this function to get the image descriptor information ``image_desc_t`` for the provided ``image_id`` from the platform. The default implementation always returns a common BL2 image descriptor. Arm standard platforms return an image descriptor corresponding to BL2 or one of the firmware update images defined in the Trusted Board Boot Requirements specification. Function : bl1_plat_handle_pre_image_load() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int image_id Return : int This function can be used by the platforms to update/use image information corresponding to ``image_id``. This function is invoked in BL1, both in cold boot and FWU code path, before loading the image. Function : bl1_plat_handle_post_image_load() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int image_id Return : int This function can be used by the platforms to update/use image information corresponding to ``image_id``. This function is invoked in BL1, both in cold boot and FWU code path, after loading and authenticating the image. The default weak implementation of this function calculates the amount of Trusted SRAM that can be used by BL2 and allocates a ``meminfo_t`` structure at the beginning of this free memory and populates it. The address of ``meminfo_t`` structure is updated in ``arg1`` of the entrypoint information to BL2. Function : bl1_plat_fwu_done() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int image_id, uintptr_t image_src, unsigned int image_size Return : void BL1 calls this function when the FWU process is complete. It must not return. The platform may override this function to take platform specific action, for example to initiate the normal boot flow. The default implementation spins forever. Function : bl1_plat_mem_check() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : uintptr_t mem_base, unsigned int mem_size, unsigned int flags Return : int BL1 calls this function while handling FWU related SMCs, more specifically when copying or authenticating an image. Its responsibility is to ensure that the region of memory identified by ``mem_base`` and ``mem_size`` is mapped in BL1, and that this memory corresponds to either a secure or non-secure memory region as indicated by the security state of the ``flags`` argument. This function can safely assume that the value resulting from the addition of ``mem_base`` and ``mem_size`` fits into a ``uintptr_t`` type variable and does not overflow. This function must return 0 on success, a non-null error code otherwise. The default implementation of this function asserts therefore platforms must override it when using the FWU feature. Boot Loader Stage 2 (BL2) ------------------------- The BL2 stage is executed only by the primary CPU, which is determined in BL1 using the ``platform_is_primary_cpu()`` function. BL1 passed control to BL2 at ``BL2_BASE``. BL2 executes in Secure EL1 and and invokes ``plat_get_bl_image_load_info()`` to retrieve the list of images to load from non-volatile storage to secure/non-secure RAM. After all the images are loaded then BL2 invokes ``plat_get_next_bl_params()`` to get the list of executable images to be passed to the next BL image. The following functions must be implemented by the platform port to enable BL2 to perform the above tasks. Function : bl2_early_platform_setup2() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : u_register_t, u_register_t, u_register_t, u_register_t Return : void This function executes with the MMU and data caches disabled. It is only called by the primary CPU. The 4 arguments are passed by BL1 to BL2 and these arguments are platform specific. On Arm standard platforms, the arguments received are : arg0 - Points to load address of HW_CONFIG if present arg1 - ``meminfo`` structure populated by BL1. The platform copies the contents of ``meminfo`` as it may be subsequently overwritten by BL2. On Arm standard platforms, this function also: - Initializes a UART (PL011 console), which enables access to the ``printf`` family of functions in BL2. - Initializes the storage abstraction layer used to load further bootloader images. It is necessary to do this early on platforms with a SCP_BL2 image, since the later ``bl2_platform_setup`` must be done after SCP_BL2 is loaded. Function : bl2_plat_arch_setup() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This function executes with the MMU and data caches disabled. It is only called by the primary CPU. The purpose of this function is to perform any architectural initialization that varies across platforms. On Arm standard platforms, this function enables the MMU. Function : bl2_platform_setup() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This function may execute with the MMU and data caches enabled if the platform port does the necessary initialization in ``bl2_plat_arch_setup()``. It is only called by the primary CPU. The purpose of this function is to perform any platform initialization specific to BL2. In Arm standard platforms, this function performs security setup, including configuration of the TrustZone controller to allow non-secure masters access to most of DRAM. Part of DRAM is reserved for secure world use. Function : bl2_plat_handle_pre_image_load() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Return : int This function can be used by the platforms to update/use image information for given ``image_id``. This function is currently invoked in BL2 before loading each image. Function : bl2_plat_handle_post_image_load() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int Return : int This function can be used by the platforms to update/use image information for given ``image_id``. This function is currently invoked in BL2 after loading each image. Function : bl2_plat_preload_setup [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This optional function performs any BL2 platform initialization required before image loading, that is not done later in bl2_platform_setup(). Specifically, if support for multiple boot sources is required, it initializes the boot sequence used by plat_try_next_boot_source(). Function : plat_try_next_boot_source() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : int This optional function passes to the next boot source in the redundancy sequence. This function moves the current boot redundancy source to the next element in the boot sequence. If there are no more boot sources then it must return 0, otherwise it must return 1. The default implementation of this always returns 0. Boot Loader Stage 2 (BL2) at EL3 -------------------------------- When the platform has a non-TF-A Boot ROM it is desirable to jump directly to BL2 instead of TF-A BL1. In this case BL2 is expected to execute at EL3 instead of executing at EL1. Refer to the :ref:`Firmware Design` document for more information. All mandatory functions of BL2 must be implemented, except the functions bl2_early_platform_setup and bl2_el3_plat_arch_setup, because their work is done now by bl2_el3_early_platform_setup and bl2_el3_plat_arch_setup. These functions should generally implement the bl1_plat_xxx() and bl2_plat_xxx() functionality combined. Function : bl2_el3_early_platform_setup() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : u_register_t, u_register_t, u_register_t, u_register_t Return : void This function executes with the MMU and data caches disabled. It is only called by the primary CPU. This function receives four parameters which can be used by the platform to pass any needed information from the Boot ROM to BL2. On Arm standard platforms, this function does the following: - Initializes a UART (PL011 console), which enables access to the ``printf`` family of functions in BL2. - Initializes the storage abstraction layer used to load further bootloader images. It is necessary to do this early on platforms with a SCP_BL2 image, since the later ``bl2_platform_setup`` must be done after SCP_BL2 is loaded. - Initializes the private variables that define the memory layout used. Function : bl2_el3_plat_arch_setup() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This function executes with the MMU and data caches disabled. It is only called by the primary CPU. The purpose of this function is to perform any architectural initialization that varies across platforms. On Arm standard platforms, this function enables the MMU. Function : bl2_el3_plat_prepare_exit() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This function is called prior to exiting BL2 and run the next image. It should be used to perform platform specific clean up or bookkeeping operations before transferring control to the next image. This function runs with MMU disabled. FWU Boot Loader Stage 2 (BL2U) ------------------------------ The AP Firmware Updater Configuration, BL2U, is an optional part of the FWU process and is executed only by the primary CPU. BL1 passes control to BL2U at ``BL2U_BASE``. BL2U executes in Secure-EL1 and is responsible for: #. (Optional) Transferring the optional SCP_BL2U binary image from AP secure memory to SCP RAM. BL2U uses the SCP_BL2U ``image_info`` passed by BL1. ``SCP_BL2U_BASE`` defines the address in AP secure memory where SCP_BL2U should be copied from. Subsequent handling of the SCP_BL2U image is implemented by the platform specific ``bl2u_plat_handle_scp_bl2u()`` function. If ``SCP_BL2U_BASE`` is not defined then this step is not performed. #. Any platform specific setup required to perform the FWU process. For example, Arm standard platforms initialize the TZC controller so that the normal world can access DDR memory. The following functions must be implemented by the platform port to enable BL2U to perform the tasks mentioned above. Function : bl2u_early_platform_setup() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : meminfo *mem_info, void *plat_info Return : void This function executes with the MMU and data caches disabled. It is only called by the primary CPU. The arguments to this function is the address of the ``meminfo`` structure and platform specific info provided by BL1. The platform may copy the contents of the ``mem_info`` and ``plat_info`` into private storage as the original memory may be subsequently overwritten by BL2U. On Arm CSS platforms ``plat_info`` is interpreted as an ``image_info_t`` structure, to extract SCP_BL2U image information, which is then copied into a private variable. Function : bl2u_plat_arch_setup() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This function executes with the MMU and data caches disabled. It is only called by the primary CPU. The purpose of this function is to perform any architectural initialization that varies across platforms, for example enabling the MMU (since the memory map differs across platforms). Function : bl2u_platform_setup() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This function may execute with the MMU and data caches enabled if the platform port does the necessary initialization in ``bl2u_plat_arch_setup()``. It is only called by the primary CPU. The purpose of this function is to perform any platform initialization specific to BL2U. In Arm standard platforms, this function performs security setup, including configuration of the TrustZone controller to allow non-secure masters access to most of DRAM. Part of DRAM is reserved for secure world use. Function : bl2u_plat_handle_scp_bl2u() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : int This function is used to perform any platform-specific actions required to handle the SCP firmware. Typically it transfers the image into SCP memory using a platform-specific protocol and waits until SCP executes it and signals to the Application Processor (AP) for BL2U execution to continue. This function returns 0 on success, a negative error code otherwise. This function is included if SCP_BL2U_BASE is defined. Boot Loader Stage 3-1 (BL31) ---------------------------- During cold boot, the BL31 stage is executed only by the primary CPU. This is determined in BL1 using the ``platform_is_primary_cpu()`` function. BL1 passes control to BL31 at ``BL31_BASE``. During warm boot, BL31 is executed by all CPUs. BL31 executes at EL3 and is responsible for: #. Re-initializing all architectural and platform state. Although BL1 performs some of this initialization, BL31 remains resident in EL3 and must ensure that EL3 architectural and platform state is completely initialized. It should make no assumptions about the system state when it receives control. #. Passing control to a normal world BL image, pre-loaded at a platform- specific address by BL2. On ARM platforms, BL31 uses the ``bl_params`` list populated by BL2 in memory to do this. #. Providing runtime firmware services. Currently, BL31 only implements a subset of the Power State Coordination Interface (PSCI) API as a runtime service. See Section 3.3 below for details of porting the PSCI implementation. #. Optionally passing control to the BL32 image, pre-loaded at a platform- specific address by BL2. BL31 exports a set of APIs that allow runtime services to specify the security state in which the next image should be executed and run the corresponding image. On ARM platforms, BL31 uses the ``bl_params`` list populated by BL2 in memory to do this. If BL31 is a reset vector, It also needs to handle the reset as specified in section 2.2 before the tasks described above. The following functions must be implemented by the platform port to enable BL31 to perform the above tasks. Function : bl31_early_platform_setup2() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : u_register_t, u_register_t, u_register_t, u_register_t Return : void This function executes with the MMU and data caches disabled. It is only called by the primary CPU. BL2 can pass 4 arguments to BL31 and these arguments are platform specific. In Arm standard platforms, the arguments received are : arg0 - The pointer to the head of `bl_params_t` list which is list of executable images following BL31, arg1 - Points to load address of SOC_FW_CONFIG if present arg2 - Points to load address of HW_CONFIG if present arg3 - A special value to verify platform parameters from BL2 to BL31. Not used in release builds. The function runs through the `bl_param_t` list and extracts the entry point information for BL32 and BL33. It also performs the following: - Initialize a UART (PL011 console), which enables access to the ``printf`` family of functions in BL31. - Enable issuing of snoop and DVM (Distributed Virtual Memory) requests to the CCI slave interface corresponding to the cluster that includes the primary CPU. Function : bl31_plat_arch_setup() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This function executes with the MMU and data caches disabled. It is only called by the primary CPU. The purpose of this function is to perform any architectural initialization that varies across platforms. On Arm standard platforms, this function enables the MMU. Function : bl31_platform_setup() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This function may execute with the MMU and data caches enabled if the platform port does the necessary initialization in ``bl31_plat_arch_setup()``. It is only called by the primary CPU. The purpose of this function is to complete platform initialization so that both BL31 runtime services and normal world software can function correctly. On Arm standard platforms, this function does the following: - Initialize the generic interrupt controller. Depending on the GIC driver selected by the platform, the appropriate GICv2 or GICv3 initialization will be done, which mainly consists of: - Enable secure interrupts in the GIC CPU interface. - Disable the legacy interrupt bypass mechanism. - Configure the priority mask register to allow interrupts of all priorities to be signaled to the CPU interface. - Mark SGIs 8-15 and the other secure interrupts on the platform as secure. - Target all secure SPIs to CPU0. - Enable these secure interrupts in the GIC distributor. - Configure all other interrupts as non-secure. - Enable signaling of secure interrupts in the GIC distributor. - Enable system-level implementation of the generic timer counter through the memory mapped interface. - Grant access to the system counter timer module - Initialize the power controller device. In particular, initialise the locks that prevent concurrent accesses to the power controller device. Function : bl31_plat_runtime_setup() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void The purpose of this function is allow the platform to perform any BL31 runtime setup just prior to BL31 exit during cold boot. The default weak implementation of this function will invoke ``console_switch_state()`` to switch console output to consoles marked for use in the ``runtime`` state. Function : bl31_plat_get_next_image_ep_info() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : uint32_t Return : entry_point_info * This function may execute with the MMU and data caches enabled if the platform port does the necessary initializations in ``bl31_plat_arch_setup()``. This function is called by ``bl31_main()`` to retrieve information provided by BL2 for the next image in the security state specified by the argument. BL31 uses this information to pass control to that image in the specified security state. This function must return a pointer to the ``entry_point_info`` structure (that was copied during ``bl31_early_platform_setup()``) if the image exists. It should return NULL otherwise. Function : bl31_plat_enable_mmu [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : uint32_t Return : void This function enables the MMU. The boot code calls this function with MMU and caches disabled. This function should program necessary registers to enable translation, and upon return, the MMU on the calling PE must be enabled. The function must honor flags passed in the first argument. These flags are defined by the translation library, and can be found in the file ``include/lib/xlat_tables/xlat_mmu_helpers.h``. On DynamIQ systems, this function must not use stack while enabling MMU, which is how the function in xlat table library version 2 is implemented. Function : plat_init_apkey [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : uint128_t This function returns the 128-bit value which can be used to program ARMv8.3 pointer authentication keys. The value should be obtained from a reliable source of randomness. This function is only needed if ARMv8.3 pointer authentication is used in the Trusted Firmware by building with ``BRANCH_PROTECTION`` option set to non-zero. Function : plat_get_syscnt_freq2() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : unsigned int This function is used by the architecture setup code to retrieve the counter frequency for the CPU's generic timer. This value will be programmed into the ``CNTFRQ_EL0`` register. In Arm standard platforms, it returns the base frequency of the system counter, which is retrieved from the first entry in the frequency modes table. #define : PLAT_PERCPU_BAKERY_LOCK_SIZE [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When ``USE_COHERENT_MEM = 0``, this constant defines the total memory (in bytes) aligned to the cache line boundary that should be allocated per-cpu to accommodate all the bakery locks. If this constant is not defined when ``USE_COHERENT_MEM = 0``, the linker calculates the size of the ``bakery_lock`` input section, aligns it to the nearest ``CACHE_WRITEBACK_GRANULE``, multiplies it with ``PLATFORM_CORE_COUNT`` and stores the result in a linker symbol. This constant prevents a platform from relying on the linker and provide a more efficient mechanism for accessing per-cpu bakery lock information. If this constant is defined and its value is not equal to the value calculated by the linker then a link time assertion is raised. A compile time assertion is raised if the value of the constant is not aligned to the cache line boundary. .. _porting_guide_sdei_requirements: SDEI porting requirements ~~~~~~~~~~~~~~~~~~~~~~~~~ The |SDEI| dispatcher requires the platform to provide the following macros and functions, of which some are optional, and some others mandatory. Macros ...... Macro: PLAT_SDEI_NORMAL_PRI [mandatory] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This macro must be defined to the EL3 exception priority level associated with Normal |SDEI| events on the platform. This must have a higher value (therefore of lower priority) than ``PLAT_SDEI_CRITICAL_PRI``. Macro: PLAT_SDEI_CRITICAL_PRI [mandatory] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This macro must be defined to the EL3 exception priority level associated with Critical |SDEI| events on the platform. This must have a lower value (therefore of higher priority) than ``PLAT_SDEI_NORMAL_PRI``. **Note**: |SDEI| exception priorities must be the lowest among Secure priorities. Among the |SDEI| exceptions, Critical |SDEI| priority must be higher than Normal |SDEI| priority. Functions ......... Function: int plat_sdei_validate_entry_point(uintptr_t ep) [optional] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: Argument: uintptr_t Return: int This function validates the address of client entry points provided for both event registration and *Complete and Resume* |SDEI| calls. The function takes one argument, which is the address of the handler the |SDEI| client requested to register. The function must return ``0`` for successful validation, or ``-1`` upon failure. The default implementation always returns ``0``. On Arm platforms, this function is implemented to translate the entry point to physical address, and further to ensure that the address is located in Non-secure DRAM. Function: void plat_sdei_handle_masked_trigger(uint64_t mpidr, unsigned int intr) [optional] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :: Argument: uint64_t Argument: unsigned int Return: void |SDEI| specification requires that a PE comes out of reset with the events masked. The client therefore is expected to call ``PE_UNMASK`` to unmask |SDEI| events on the PE. No |SDEI| events can be dispatched until such time. Should a PE receive an interrupt that was bound to an |SDEI| event while the events are masked on the PE, the dispatcher implementation invokes the function ``plat_sdei_handle_masked_trigger``. The MPIDR of the PE that received the interrupt and the interrupt ID are passed as parameters. The default implementation only prints out a warning message. Power State Coordination Interface (in BL31) -------------------------------------------- The TF-A implementation of the PSCI API is based around the concept of a *power domain*. A *power domain* is a CPU or a logical group of CPUs which share some state on which power management operations can be performed as specified by `PSCI`_. Each CPU in the system is assigned a cpu index which is a unique number between ``0`` and ``PLATFORM_CORE_COUNT - 1``. The *power domains* are arranged in a hierarchical tree structure and each *power domain* can be identified in a system by the cpu index of any CPU that is part of that domain and a *power domain level*. A processing element (for example, a CPU) is at level 0. If the *power domain* node above a CPU is a logical grouping of CPUs that share some state, then level 1 is that group of CPUs (for example, a cluster), and level 2 is a group of clusters (for example, the system). More details on the power domain topology and its organization can be found in :ref:`PSCI Power Domain Tree Structure`. BL31's platform initialization code exports a pointer to the platform-specific power management operations required for the PSCI implementation to function correctly. This information is populated in the ``plat_psci_ops`` structure. The PSCI implementation calls members of the ``plat_psci_ops`` structure for performing power management operations on the power domains. For example, the target CPU is specified by its ``MPIDR`` in a PSCI ``CPU_ON`` call. The ``pwr_domain_on()`` handler (if present) is called for the CPU power domain. The ``power-state`` parameter of a PSCI ``CPU_SUSPEND`` call can be used to describe composite power states specific to a platform. The PSCI implementation defines a generic representation of the power-state parameter, which is an array of local power states where each index corresponds to a power domain level. Each entry contains the local power state the power domain at that power level could enter. It depends on the ``validate_power_state()`` handler to convert the power-state parameter (possibly encoding a composite power state) passed in a PSCI ``CPU_SUSPEND`` call to this representation. The following functions form part of platform port of PSCI functionality. Function : plat_psci_stat_accounting_start() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : const psci_power_state_t * Return : void This is an optional hook that platforms can implement for residency statistics accounting before entering a low power state. The ``pwr_domain_state`` field of ``state_info`` (first argument) can be inspected if stat accounting is done differently at CPU level versus higher levels. As an example, if the element at index 0 (CPU power level) in the ``pwr_domain_state`` array indicates a power down state, special hardware logic may be programmed in order to keep track of the residency statistics. For higher levels (array indices > 0), the residency statistics could be tracked in software using PMF. If ``ENABLE_PMF`` is set, the default implementation will use PMF to capture timestamps. Function : plat_psci_stat_accounting_stop() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : const psci_power_state_t * Return : void This is an optional hook that platforms can implement for residency statistics accounting after exiting from a low power state. The ``pwr_domain_state`` field of ``state_info`` (first argument) can be inspected if stat accounting is done differently at CPU level versus higher levels. As an example, if the element at index 0 (CPU power level) in the ``pwr_domain_state`` array indicates a power down state, special hardware logic may be programmed in order to keep track of the residency statistics. For higher levels (array indices > 0), the residency statistics could be tracked in software using PMF. If ``ENABLE_PMF`` is set, the default implementation will use PMF to capture timestamps. Function : plat_psci_stat_get_residency() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int, const psci_power_state_t *, int Return : u_register_t This is an optional interface that is is invoked after resuming from a low power state and provides the time spent resident in that low power state by the power domain at a particular power domain level. When a CPU wakes up from suspend, all its parent power domain levels are also woken up. The generic PSCI code invokes this function for each parent power domain that is resumed and it identified by the ``lvl`` (first argument) parameter. The ``state_info`` (second argument) describes the low power state that the power domain has resumed from. The current CPU is the first CPU in the power domain to resume from the low power state and the ``last_cpu_idx`` (third parameter) is the index of the last CPU in the power domain to suspend and may be needed to calculate the residency for that power domain. Function : plat_get_target_pwr_state() [optional] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : unsigned int, const plat_local_state_t *, unsigned int Return : plat_local_state_t The PSCI generic code uses this function to let the platform participate in state coordination during a power management operation. The function is passed a pointer to an array of platform specific local power state ``states`` (second argument) which contains the requested power state for each CPU at a particular power domain level ``lvl`` (first argument) within the power domain. The function is expected to traverse this array of upto ``ncpus`` (third argument) and return a coordinated target power state by the comparing all the requested power states. The target power state should not be deeper than any of the requested power states. A weak definition of this API is provided by default wherein it assumes that the platform assigns a local state value in order of increasing depth of the power state i.e. for two power states X & Y, if X < Y then X represents a shallower power state than Y. As a result, the coordinated target local power state for a power domain will be the minimum of the requested local power state values. Function : plat_get_power_domain_tree_desc() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : const unsigned char * This function returns a pointer to the byte array containing the power domain topology tree description. The format and method to construct this array are described in :ref:`PSCI Power Domain Tree Structure`. The BL31 PSCI initialization code requires this array to be described by the platform, either statically or dynamically, to initialize the power domain topology tree. In case the array is populated dynamically, then plat_core_pos_by_mpidr() and plat_my_core_pos() should also be implemented suitably so that the topology tree description matches the CPU indices returned by these APIs. These APIs together form the platform interface for the PSCI topology framework. Function : plat_setup_psci_ops() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : uintptr_t, const plat_psci_ops ** Return : int This function may execute with the MMU and data caches enabled if the platform port does the necessary initializations in ``bl31_plat_arch_setup()``. It is only called by the primary CPU. This function is called by PSCI initialization code. Its purpose is to let the platform layer know about the warm boot entrypoint through the ``sec_entrypoint`` (first argument) and to export handler routines for platform-specific psci power management actions by populating the passed pointer with a pointer to BL31's private ``plat_psci_ops`` structure. A description of each member of this structure is given below. Please refer to the Arm FVP specific implementation of these handlers in ``plat/arm/board/fvp/fvp_pm.c`` as an example. For each PSCI function that the platform wants to support, the associated operation or operations in this structure must be provided and implemented (Refer section 4 of :ref:`Firmware Design` for the PSCI API supported in TF-A). To disable a PSCI function in a platform port, the operation should be removed from this structure instead of providing an empty implementation. plat_psci_ops.cpu_standby() ........................... Perform the platform-specific actions to enter the standby state for a cpu indicated by the passed argument. This provides a fast path for CPU standby wherein overheads of PSCI state management and lock acquisition is avoided. For this handler to be invoked by the PSCI ``CPU_SUSPEND`` API implementation, the suspend state type specified in the ``power-state`` parameter should be STANDBY and the target power domain level specified should be the CPU. The handler should put the CPU into a low power retention state (usually by issuing a wfi instruction) and ensure that it can be woken up from that state by a normal interrupt. The generic code expects the handler to succeed. plat_psci_ops.pwr_domain_on() ............................. Perform the platform specific actions to power on a CPU, specified by the ``MPIDR`` (first argument). The generic code expects the platform to return PSCI_E_SUCCESS on success or PSCI_E_INTERN_FAIL for any failure. plat_psci_ops.pwr_domain_off() .............................. Perform the platform specific actions to prepare to power off the calling CPU and its higher parent power domain levels as indicated by the ``target_state`` (first argument). It is called by the PSCI ``CPU_OFF`` API implementation. The ``target_state`` encodes the platform coordinated target local power states for the CPU power domain and its parent power domain levels. The handler needs to perform power management operation corresponding to the local state at each power level. For this handler, the local power state for the CPU power domain will be a power down state where as it could be either power down, retention or run state for the higher power domain levels depending on the result of state coordination. The generic code expects the handler to succeed. plat_psci_ops.pwr_domain_suspend_pwrdown_early() [optional] ........................................................... This optional function may be used as a performance optimization to replace or complement pwr_domain_suspend() on some platforms. Its calling semantics are identical to pwr_domain_suspend(), except the PSCI implementation only calls this function when suspending to a power down state, and it guarantees that data caches are enabled. When HW_ASSISTED_COHERENCY = 0, the PSCI implementation disables data caches before calling pwr_domain_suspend(). If the target_state corresponds to a power down state and it is safe to perform some or all of the platform specific actions in that function with data caches enabled, it may be more efficient to move those actions to this function. When HW_ASSISTED_COHERENCY = 1, data caches remain enabled throughout, and so there is no advantage to moving platform specific actions to this function. plat_psci_ops.pwr_domain_suspend() .................................. Perform the platform specific actions to prepare to suspend the calling CPU and its higher parent power domain levels as indicated by the ``target_state`` (first argument). It is called by the PSCI ``CPU_SUSPEND`` API implementation. The ``target_state`` has a similar meaning as described in the ``pwr_domain_off()`` operation. It encodes the platform coordinated target local power states for the CPU power domain and its parent power domain levels. The handler needs to perform power management operation corresponding to the local state at each power level. The generic code expects the handler to succeed. The difference between turning a power domain off versus suspending it is that in the former case, the power domain is expected to re-initialize its state when it is next powered on (see ``pwr_domain_on_finish()``). In the latter case, the power domain is expected to save enough state so that it can resume execution by restoring this state when its powered on (see ``pwr_domain_suspend_finish()``). When suspending a core, the platform can also choose to power off the GICv3 Redistributor and ITS through an implementation-defined sequence. To achieve this safely, the ITS context must be saved first. The architectural part is implemented by the ``gicv3_its_save_disable()`` helper, but most of the needed sequence is implementation defined and it is therefore the responsibility of the platform code to implement the necessary sequence. Then the GIC Redistributor context can be saved using the ``gicv3_rdistif_save()`` helper. Powering off the Redistributor requires the implementation to support it and it is the responsibility of the platform code to execute the right implementation defined sequence. When a system suspend is requested, the platform can also make use of the ``gicv3_distif_save()`` helper to save the context of the GIC Distributor after it has saved the context of the Redistributors and ITS of all the cores in the system. The context of the Distributor can be large and may require it to be allocated in a special area if it cannot fit in the platform's global static data, for example in DRAM. The Distributor can then be powered down using an implementation-defined sequence. plat_psci_ops.pwr_domain_pwr_down_wfi() ....................................... This is an optional function and, if implemented, is expected to perform platform specific actions including the ``wfi`` invocation which allows the CPU to powerdown. Since this function is invoked outside the PSCI locks, the actions performed in this hook must be local to the CPU or the platform must ensure that races between multiple CPUs cannot occur. The ``target_state`` has a similar meaning as described in the ``pwr_domain_off()`` operation and it encodes the platform coordinated target local power states for the CPU power domain and its parent power domain levels. This function must not return back to the caller. If this function is not implemented by the platform, PSCI generic implementation invokes ``psci_power_down_wfi()`` for power down. plat_psci_ops.pwr_domain_on_finish() .................................... This function is called by the PSCI implementation after the calling CPU is powered on and released from reset in response to an earlier PSCI ``CPU_ON`` call. It performs the platform-specific setup required to initialize enough state for this CPU to enter the normal world and also provide secure runtime firmware services. The ``target_state`` (first argument) is the prior state of the power domains immediately before the CPU was turned on. It indicates which power domains above the CPU might require initialization due to having previously been in low power states. The generic code expects the handler to succeed. plat_psci_ops.pwr_domain_on_finish_late() [optional] ........................................................... This optional function is called by the PSCI implementation after the calling CPU is fully powered on with respective data caches enabled. The calling CPU and the associated cluster are guaranteed to be participating in coherency. This function gives the flexibility to perform any platform-specific actions safely, such as initialization or modification of shared data structures, without the overhead of explicit cache maintainace operations. The ``target_state`` has a similar meaning as described in the ``pwr_domain_on_finish()`` operation. The generic code expects the handler to succeed. plat_psci_ops.pwr_domain_suspend_finish() ......................................... This function is called by the PSCI implementation after the calling CPU is powered on and released from reset in response to an asynchronous wakeup event, for example a timer interrupt that was programmed by the CPU during the ``CPU_SUSPEND`` call or ``SYSTEM_SUSPEND`` call. It performs the platform-specific setup required to restore the saved state for this CPU to resume execution in the normal world and also provide secure runtime firmware services. The ``target_state`` (first argument) has a similar meaning as described in the ``pwr_domain_on_finish()`` operation. The generic code expects the platform to succeed. If the Distributor, Redistributors or ITS have been powered off as part of a suspend, their context must be restored in this function in the reverse order to how they were saved during suspend sequence. plat_psci_ops.system_off() .......................... This function is called by PSCI implementation in response to a ``SYSTEM_OFF`` call. It performs the platform-specific system poweroff sequence after notifying the Secure Payload Dispatcher. plat_psci_ops.system_reset() ............................ This function is called by PSCI implementation in response to a ``SYSTEM_RESET`` call. It performs the platform-specific system reset sequence after notifying the Secure Payload Dispatcher. plat_psci_ops.validate_power_state() .................................... This function is called by the PSCI implementation during the ``CPU_SUSPEND`` call to validate the ``power_state`` parameter of the PSCI API and if valid, populate it in ``req_state`` (second argument) array as power domain level specific local states. If the ``power_state`` is invalid, the platform must return PSCI_E_INVALID_PARAMS as error, which is propagated back to the normal world PSCI client. plat_psci_ops.validate_ns_entrypoint() ...................................... This function is called by the PSCI implementation during the ``CPU_SUSPEND``, ``SYSTEM_SUSPEND`` and ``CPU_ON`` calls to validate the non-secure ``entry_point`` parameter passed by the normal world. If the ``entry_point`` is invalid, the platform must return PSCI_E_INVALID_ADDRESS as error, which is propagated back to the normal world PSCI client. plat_psci_ops.get_sys_suspend_power_state() ........................................... This function is called by the PSCI implementation during the ``SYSTEM_SUSPEND`` call to get the ``req_state`` parameter from platform which encodes the power domain level specific local states to suspend to system affinity level. The ``req_state`` will be utilized to do the PSCI state coordination and ``pwr_domain_suspend()`` will be invoked with the coordinated target state to enter system suspend. plat_psci_ops.get_pwr_lvl_state_idx() ..................................... This is an optional function and, if implemented, is invoked by the PSCI implementation to convert the ``local_state`` (first argument) at a specified ``pwr_lvl`` (second argument) to an index between 0 and ``PLAT_MAX_PWR_LVL_STATES`` - 1. This function is only needed if the platform supports more than two local power states at each power domain level, that is ``PLAT_MAX_PWR_LVL_STATES`` is greater than 2, and needs to account for these local power states. plat_psci_ops.translate_power_state_by_mpidr() .............................................. This is an optional function and, if implemented, verifies the ``power_state`` (second argument) parameter of the PSCI API corresponding to a target power domain. The target power domain is identified by using both ``MPIDR`` (first argument) and the power domain level encoded in ``power_state``. The power domain level specific local states are to be extracted from ``power_state`` and be populated in the ``output_state`` (third argument) array. The functionality is similar to the ``validate_power_state`` function described above and is envisaged to be used in case the validity of ``power_state`` depend on the targeted power domain. If the ``power_state`` is invalid for the targeted power domain, the platform must return PSCI_E_INVALID_PARAMS as error. If this function is not implemented, then the generic implementation relies on ``validate_power_state`` function to translate the ``power_state``. This function can also be used in case the platform wants to support local power state encoding for ``power_state`` parameter of PSCI_STAT_COUNT/RESIDENCY APIs as described in Section 5.18 of `PSCI`_. plat_psci_ops.get_node_hw_state() ................................. This is an optional function. If implemented this function is intended to return the power state of a node (identified by the first parameter, the ``MPIDR``) in the power domain topology (identified by the second parameter, ``power_level``), as retrieved from a power controller or equivalent component on the platform. Upon successful completion, the implementation must map and return the final status among ``HW_ON``, ``HW_OFF`` or ``HW_STANDBY``. Upon encountering failures, it must return either ``PSCI_E_INVALID_PARAMS`` or ``PSCI_E_NOT_SUPPORTED`` as appropriate. Implementations are not expected to handle ``power_levels`` greater than ``PLAT_MAX_PWR_LVL``. plat_psci_ops.system_reset2() ............................. This is an optional function. If implemented this function is called during the ``SYSTEM_RESET2`` call to perform a reset based on the first parameter ``reset_type`` as specified in `PSCI`_. The parameter ``cookie`` can be used to pass additional reset information. If the ``reset_type`` is not supported, the function must return ``PSCI_E_NOT_SUPPORTED``. For architectural resets, all failures must return ``PSCI_E_INVALID_PARAMETERS`` and vendor reset can return other PSCI error codes as defined in `PSCI`_. On success this function will not return. plat_psci_ops.write_mem_protect() ................................. This is an optional function. If implemented it enables or disables the ``MEM_PROTECT`` functionality based on the value of ``val``. A non-zero value enables ``MEM_PROTECT`` and a value of zero disables it. Upon encountering failures it must return a negative value and on success it must return 0. plat_psci_ops.read_mem_protect() ................................ This is an optional function. If implemented it returns the current state of ``MEM_PROTECT`` via the ``val`` parameter. Upon encountering failures it must return a negative value and on success it must return 0. plat_psci_ops.mem_protect_chk() ............................... This is an optional function. If implemented it checks if a memory region defined by a base address ``base`` and with a size of ``length`` bytes is protected by ``MEM_PROTECT``. If the region is protected then it must return 0, otherwise it must return a negative number. .. _porting_guide_imf_in_bl31: Interrupt Management framework (in BL31) ---------------------------------------- BL31 implements an Interrupt Management Framework (IMF) to manage interrupts generated in either security state and targeted to EL1 or EL2 in the non-secure state or EL3/S-EL1 in the secure state. The design of this framework is described in the :ref:`Interrupt Management Framework` A platform should export the following APIs to support the IMF. The following text briefly describes each API and its implementation in Arm standard platforms. The API implementation depends upon the type of interrupt controller present in the platform. Arm standard platform layer supports both `Arm Generic Interrupt Controller version 2.0 (GICv2)`_ and `3.0 (GICv3)`_. Juno builds the Arm platform layer to use GICv2 and the FVP can be configured to use either GICv2 or GICv3 depending on the build flag ``FVP_USE_GIC_DRIVER`` (See FVP platform specific build options in :ref:`User Guide` for more details). See also: `Interrupt Controller Abstraction APIs`__. .. __: ../design/platform-interrupt-controller-API.rst Function : plat_interrupt_type_to_line() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : uint32_t, uint32_t Return : uint32_t The Arm processor signals an interrupt exception either through the IRQ or FIQ interrupt line. The specific line that is signaled depends on how the interrupt controller (IC) reports different interrupt types from an execution context in either security state. The IMF uses this API to determine which interrupt line the platform IC uses to signal each type of interrupt supported by the framework from a given security state. This API must be invoked at EL3. The first parameter will be one of the ``INTR_TYPE_*`` values (see :ref:`Interrupt Management Framework`) indicating the target type of the interrupt, the second parameter is the security state of the originating execution context. The return result is the bit position in the ``SCR_EL3`` register of the respective interrupt trap: IRQ=1, FIQ=2. In the case of Arm standard platforms using GICv2, S-EL1 interrupts are configured as FIQs and Non-secure interrupts as IRQs from either security state. In the case of Arm standard platforms using GICv3, the interrupt line to be configured depends on the security state of the execution context when the interrupt is signalled and are as follows: - The S-EL1 interrupts are signaled as IRQ in S-EL0/1 context and as FIQ in NS-EL0/1/2 context. - The Non secure interrupts are signaled as FIQ in S-EL0/1 context and as IRQ in the NS-EL0/1/2 context. - The EL3 interrupts are signaled as FIQ in both S-EL0/1 and NS-EL0/1/2 context. Function : plat_ic_get_pending_interrupt_type() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : uint32_t This API returns the type of the highest priority pending interrupt at the platform IC. The IMF uses the interrupt type to retrieve the corresponding handler function. ``INTR_TYPE_INVAL`` is returned when there is no interrupt pending. The valid interrupt types that can be returned are ``INTR_TYPE_EL3``, ``INTR_TYPE_S_EL1`` and ``INTR_TYPE_NS``. This API must be invoked at EL3. In the case of Arm standard platforms using GICv2, the *Highest Priority Pending Interrupt Register* (``GICC_HPPIR``) is read to determine the id of the pending interrupt. The type of interrupt depends upon the id value as follows. #. id < 1022 is reported as a S-EL1 interrupt #. id = 1022 is reported as a Non-secure interrupt. #. id = 1023 is reported as an invalid interrupt type. In the case of Arm standard platforms using GICv3, the system register ``ICC_HPPIR0_EL1``, *Highest Priority Pending group 0 Interrupt Register*, is read to determine the id of the pending interrupt. The type of interrupt depends upon the id value as follows. #. id = ``PENDING_G1S_INTID`` (1020) is reported as a S-EL1 interrupt #. id = ``PENDING_G1NS_INTID`` (1021) is reported as a Non-secure interrupt. #. id = ``GIC_SPURIOUS_INTERRUPT`` (1023) is reported as an invalid interrupt type. #. All other interrupt id's are reported as EL3 interrupt. Function : plat_ic_get_pending_interrupt_id() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : uint32_t This API returns the id of the highest priority pending interrupt at the platform IC. ``INTR_ID_UNAVAILABLE`` is returned when there is no interrupt pending. In the case of Arm standard platforms using GICv2, the *Highest Priority Pending Interrupt Register* (``GICC_HPPIR``) is read to determine the id of the pending interrupt. The id that is returned by API depends upon the value of the id read from the interrupt controller as follows. #. id < 1022. id is returned as is. #. id = 1022. The *Aliased Highest Priority Pending Interrupt Register* (``GICC_AHPPIR``) is read to determine the id of the non-secure interrupt. This id is returned by the API. #. id = 1023. ``INTR_ID_UNAVAILABLE`` is returned. In the case of Arm standard platforms using GICv3, if the API is invoked from EL3, the system register ``ICC_HPPIR0_EL1``, *Highest Priority Pending Interrupt group 0 Register*, is read to determine the id of the pending interrupt. The id that is returned by API depends upon the value of the id read from the interrupt controller as follows. #. id < ``PENDING_G1S_INTID`` (1020). id is returned as is. #. id = ``PENDING_G1S_INTID`` (1020) or ``PENDING_G1NS_INTID`` (1021). The system register ``ICC_HPPIR1_EL1``, *Highest Priority Pending Interrupt group 1 Register* is read to determine the id of the group 1 interrupt. This id is returned by the API as long as it is a valid interrupt id #. If the id is any of the special interrupt identifiers, ``INTR_ID_UNAVAILABLE`` is returned. When the API invoked from S-EL1 for GICv3 systems, the id read from system register ``ICC_HPPIR1_EL1``, *Highest Priority Pending group 1 Interrupt Register*, is returned if is not equal to GIC_SPURIOUS_INTERRUPT (1023) else ``INTR_ID_UNAVAILABLE`` is returned. Function : plat_ic_acknowledge_interrupt() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : uint32_t This API is used by the CPU to indicate to the platform IC that processing of the highest pending interrupt has begun. It should return the raw, unmodified value obtained from the interrupt controller when acknowledging an interrupt. The actual interrupt number shall be extracted from this raw value using the API `plat_ic_get_interrupt_id()`__. .. __: ../design/platform-interrupt-controller-API.rst#function-unsigned-int-plat-ic-get-interrupt-id-unsigned-int-raw-optional This function in Arm standard platforms using GICv2, reads the *Interrupt Acknowledge Register* (``GICC_IAR``). This changes the state of the highest priority pending interrupt from pending to active in the interrupt controller. It returns the value read from the ``GICC_IAR``, unmodified. In the case of Arm standard platforms using GICv3, if the API is invoked from EL3, the function reads the system register ``ICC_IAR0_EL1``, *Interrupt Acknowledge Register group 0*. If the API is invoked from S-EL1, the function reads the system register ``ICC_IAR1_EL1``, *Interrupt Acknowledge Register group 1*. The read changes the state of the highest pending interrupt from pending to active in the interrupt controller. The value read is returned unmodified. The TSP uses this API to start processing of the secure physical timer interrupt. Function : plat_ic_end_of_interrupt() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : uint32_t Return : void This API is used by the CPU to indicate to the platform IC that processing of the interrupt corresponding to the id (passed as the parameter) has finished. The id should be the same as the id returned by the ``plat_ic_acknowledge_interrupt()`` API. Arm standard platforms write the id to the *End of Interrupt Register* (``GICC_EOIR``) in case of GICv2, and to ``ICC_EOIR0_EL1`` or ``ICC_EOIR1_EL1`` system register in case of GICv3 depending on where the API is invoked from, EL3 or S-EL1. This deactivates the corresponding interrupt in the interrupt controller. The TSP uses this API to finish processing of the secure physical timer interrupt. Function : plat_ic_get_interrupt_type() [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : uint32_t Return : uint32_t This API returns the type of the interrupt id passed as the parameter. ``INTR_TYPE_INVAL`` is returned if the id is invalid. If the id is valid, a valid interrupt type (one of ``INTR_TYPE_EL3``, ``INTR_TYPE_S_EL1`` and ``INTR_TYPE_NS``) is returned depending upon how the interrupt has been configured by the platform IC. This API must be invoked at EL3. Arm standard platforms using GICv2 configures S-EL1 interrupts as Group0 interrupts and Non-secure interrupts as Group1 interrupts. It reads the group value corresponding to the interrupt id from the relevant *Interrupt Group Register* (``GICD_IGROUPRn``). It uses the group value to determine the type of interrupt. In the case of Arm standard platforms using GICv3, both the *Interrupt Group Register* (``GICD_IGROUPRn``) and *Interrupt Group Modifier Register* (``GICD_IGRPMODRn``) is read to figure out whether the interrupt is configured as Group 0 secure interrupt, Group 1 secure interrupt or Group 1 NS interrupt. Crash Reporting mechanism (in BL31) ----------------------------------- BL31 implements a crash reporting mechanism which prints the various registers of the CPU to enable quick crash analysis and debugging. This mechanism relies on the platform implementing ``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. .. note:: Platforms are responsible for making sure that they only mark consoles for use in the crash scope that are able to support this, i.e. that are written in assembly and conform with the register clobber rules for putc() (x0-x2, x16-x17) and flush() (x0-x3, x16-x17) crash callbacks. In some cases (such as debugging very early crashes that happen before the normal boot console can be set up), platforms may want to control crash output more explicitly. These platforms may instead provide custom implementations for these. They are executed outside of a C environment and without a stack. Many console drivers provide functions named ``console_xxx_core_init/putc/flush`` that are designed to be used by these functions. See Arm platforms (like juno) for an example of this. Function : plat_crash_console_init [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : int 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. Function : plat_crash_console_putc [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : int Return : int This API is used by the crash reporting mechanism to print a character on the designated crash console. It must only use general purpose registers x1 and x2 to do its work. The parameter and the return value are in general purpose register x0. Function : plat_crash_console_flush [mandatory] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : int This API is used by the crash reporting mechanism to force write of all buffered data on the designated crash console. It should only use general purpose registers x0 through x5 to do its work. The return value is 0 on successful completion; otherwise the return value is -1. External Abort handling and RAS Support --------------------------------------- Function : plat_ea_handler ~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : int Argument : uint64_t Argument : void * Argument : void * Argument : uint64_t Return : void This function is invoked by the RAS framework for the platform to handle an External Abort received at EL3. The intention of the function is to attempt to resolve the cause of External Abort and return; if that's not possible, to initiate orderly shutdown of the system. The first parameter (``int ea_reason``) indicates the reason for External Abort. Its value is one of ``ERROR_EA_*`` constants defined in ``ea_handle.h``. The second parameter (``uint64_t syndrome``) is the respective syndrome presented to EL3 after having received the External Abort. Depending on the nature of the abort (as can be inferred from the ``ea_reason`` parameter), this can be the content of either ``ESR_EL3`` or ``DISR_EL1``. The third parameter (``void *cookie``) is unused for now. The fourth parameter (``void *handle``) is a pointer to the preempted context. The fifth parameter (``uint64_t flags``) indicates the preempted security state. These parameters are received from the top-level exception handler. If ``RAS_EXTENSION`` is set to ``1``, the default implementation of this function iterates through RAS handlers registered by the platform. If any of the RAS handlers resolve the External Abort, no further action is taken. If ``RAS_EXTENSION`` is set to ``0``, or if none of the platform RAS handlers could resolve the External Abort, the default implementation prints an error message, and panics. Function : plat_handle_uncontainable_ea ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : int Argument : uint64_t Return : void This function is invoked by the RAS framework when an External Abort of Uncontainable type is received at EL3. Due to the critical nature of Uncontainable errors, the intention of this function is to initiate orderly shutdown of the system, and is not expected to return. This function must be implemented in assembly. The first and second parameters are the same as that of ``plat_ea_handler``. The default implementation of this function calls ``report_unhandled_exception``. Function : plat_handle_double_fault ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : int Argument : uint64_t Return : void This function is invoked by the RAS framework when another External Abort is received at EL3 while one is already being handled. I.e., a call to ``plat_ea_handler`` is outstanding. Due to its critical nature, the intention of this function is to initiate orderly shutdown of the system, and is not expected recover or return. This function must be implemented in assembly. The first and second parameters are the same as that of ``plat_ea_handler``. The default implementation of this function calls ``report_unhandled_exception``. Function : plat_handle_el3_ea ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Return : void This function is invoked when an External Abort is received while executing in EL3. Due to its critical nature, the intention of this function is to initiate orderly shutdown of the system, and is not expected recover or return. This function must be implemented in assembly. The default implementation of this function calls ``report_unhandled_exception``. Build flags ----------- There are some build flags which can be defined by the platform to control inclusion or exclusion of certain BL stages from the FIP image. These flags need to be defined in the platform makefile which will get included by the build system. - **NEED_BL33** By default, this flag is defined ``yes`` by the build system and ``BL33`` build option should be supplied as a build option. The platform has the option of excluding the BL33 image in the ``fip`` image by defining this flag to ``no``. If any of the options ``EL3_PAYLOAD_BASE`` or ``PRELOADED_BL33_BASE`` are used, this flag will be set to ``no`` automatically. C Library --------- To avoid subtle toolchain behavioral dependencies, the header files provided by the compiler are not used. The software is built with the ``-nostdinc`` flag to ensure no headers are included from the toolchain inadvertently. Instead the required headers are included in the TF-A source tree. The library only contains those C library definitions required by the local implementation. If more functionality is required, the needed library functions will need to be added to the local implementation. Some C headers have been obtained from `FreeBSD`_ and `SCC`_, while others have been written specifically for TF-A. Some implementation files have been obtained from `FreeBSD`_, others have been written specifically for TF-A as well. The files can be found in ``include/lib/libc`` and ``lib/libc``. SCC can be found in http://www.simple-cc.org/. A copy of the `FreeBSD`_ sources can be obtained from http://github.com/freebsd/freebsd. Storage abstraction layer ------------------------- In order to improve platform independence and portability a storage abstraction layer is used to load data from non-volatile platform storage. Currently storage access is only required by BL1 and BL2 phases and performed inside the ``load_image()`` function in ``bl_common.c``. .. uml:: ../resources/diagrams/plantuml/io_framework_usage_overview.puml It is mandatory to implement at least one storage driver. For the Arm development platforms the Firmware Image Package (FIP) driver is provided as the default means to load data from storage (see the "Firmware Image Package" section in the :ref:`User Guide`). The storage layer is described in the header file ``include/drivers/io/io_storage.h``. The implementation of the common library is in ``drivers/io/io_storage.c`` and the driver files are located in ``drivers/io/``. .. uml:: ../resources/diagrams/plantuml/io_arm_class_diagram.puml Each IO driver must provide ``io_dev_*`` structures, as described in ``drivers/io/io_driver.h``. These are returned via a mandatory registration function that is called on platform initialization. The semi-hosting driver implementation in ``io_semihosting.c`` can be used as an example. Each platform should register devices and their drivers via the storage abstraction layer. These drivers then need to be initialized by bootloader phases as required in their respective ``blx_platform_setup()`` functions. .. uml:: ../resources/diagrams/plantuml/io_dev_registration.puml The storage abstraction layer provides mechanisms (``io_dev_init()``) to initialize storage devices before IO operations are called. .. uml:: ../resources/diagrams/plantuml/io_dev_init_and_check.puml The basic operations supported by the layer include ``open()``, ``close()``, ``read()``, ``write()``, ``size()`` and ``seek()``. Drivers do not have to implement all operations, but each platform must provide at least one driver for a device capable of supporting generic operations such as loading a bootloader image. The current implementation only allows for known images to be loaded by the firmware. These images are specified by using their identifiers, as defined in ``include/plat/common/common_def.h`` (or a separate header file included from there). The platform layer (``plat_get_image_source()``) then returns a reference to a device and a driver-specific ``spec`` which will be understood by the driver to allow access to the image data. The layer is designed in such a way that is it possible to chain drivers with other drivers. For example, file-system drivers may be implemented on top of physical block devices, both represented by IO devices with corresponding drivers. In such a case, the file-system "binding" with the block device may be deferred until the file-system device is initialised. The abstraction currently depends on structures being statically allocated by the drivers and callers, as the system does not yet provide a means of dynamically allocating memory. This may also have the affect of limiting the amount of open resources per driver. -------------- *Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.* .. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf .. _Arm Generic Interrupt Controller version 2.0 (GICv2): http://infocenter.arm.com/help/topic/com.arm.doc.ihi0048b/index.html .. _3.0 (GICv3): http://infocenter.arm.com/help/topic/com.arm.doc.ihi0069b/index.html .. _FreeBSD: https://www.freebsd.org .. _SCC: http://www.simple-cc.org/ trusted-firmware-a-2.2/docs/getting_started/psci-lib-integration-guide.rst000066400000000000000000000577301355360272700271140ustar00rootroot00000000000000PSCI Library Integration guide for Armv8-A AArch32 systems ========================================================== This document describes the PSCI library interface with a focus on how to integrate with a suitable Trusted OS for an Armv8-A AArch32 system. The PSCI Library implements the PSCI Standard as described in `PSCI spec`_ and is meant to be integrated with EL3 Runtime Software which invokes the PSCI Library interface appropriately. **EL3 Runtime Software** refers to software executing at the highest secure privileged mode, which is EL3 in AArch64 or Secure SVC/ Monitor mode in AArch32, and provides runtime services to the non-secure world. The runtime service request is made via SMC (Secure Monitor Call) and the call must adhere to `SMCCC`_. In AArch32, EL3 Runtime Software may additionally include Trusted OS functionality. A minimal AArch32 Secure Payload, SP-MIN, is provided in Trusted Firmware-A (TF-A) to illustrate the usage and integration of the PSCI library. The description of PSCI library interface and its integration with EL3 Runtime Software in this document is targeted towards AArch32 systems. Generic call sequence for PSCI Library interface (AArch32) ---------------------------------------------------------- The generic call sequence of PSCI Library interfaces (see `PSCI Library Interface`_) during cold boot in AArch32 system is described below: #. After cold reset, the EL3 Runtime Software performs its cold boot initialization including the PSCI library pre-requisites mentioned in `PSCI Library Interface`_, and also the necessary platform setup. #. Call ``psci_setup()`` in Monitor mode. #. Optionally call ``psci_register_spd_pm_hook()`` to register callbacks to do bookkeeping for the EL3 Runtime Software during power management. #. Call ``psci_prepare_next_non_secure_ctx()`` to initialize the non-secure CPU context. #. Get the non-secure ``cpu_context_t`` for the current CPU by calling ``cm_get_context()`` , then programming the registers in the non-secure context and exiting to non-secure world. If the EL3 Runtime Software needs additional configuration to be set for non-secure context, like routing FIQs to the secure world, the values of the registers can be modified prior to programming. See `PSCI CPU context management`_ for more details on CPU context management. The generic call sequence of PSCI library interfaces during warm boot in AArch32 systems is described below: #. After warm reset, the EL3 Runtime Software performs the necessary warm boot initialization including the PSCI library pre-requisites mentioned in `PSCI Library Interface`_ (Note that the Data cache **must not** be enabled). #. Call ``psci_warmboot_entrypoint()`` in Monitor mode. This interface initializes/restores the non-secure CPU context as well. #. Do step 5 of the cold boot call sequence described above. The generic call sequence of PSCI library interfaces on receipt of a PSCI SMC on an AArch32 system is described below: #. On receipt of an SMC, save the register context as per `SMCCC`_. #. If the SMC function identifier corresponds to a SMC32 PSCI API, construct the appropriate arguments and call the ``psci_smc_handler()`` interface. The invocation may or may not return back to the caller depending on whether the PSCI API resulted in power down of the CPU. #. If ``psci_smc_handler()`` returns, populate the return value in R0 (AArch32)/ X0 (AArch64) and restore other registers as per `SMCCC`_. PSCI CPU context management --------------------------- PSCI library is in charge of initializing/restoring the non-secure CPU system registers according to `PSCI specification`_ during cold/warm boot. This is referred to as ``PSCI CPU Context Management``. Registers that need to be preserved across CPU power down/power up cycles are maintained in ``cpu_context_t`` data structure. The initialization of other non-secure CPU system registers which do not require coordination with the EL3 Runtime Software is done directly by the PSCI library (see ``cm_prepare_el3_exit()``). The EL3 Runtime Software is responsible for managing register context during switch between Normal and Secure worlds. The register context to be saved and restored depends on the mechanism used to trigger the world switch. For example, if the world switch was triggered by an SMC call, then the registers need to be saved and restored according to `SMCCC`_. In AArch64, due to the tight integration with BL31, both BL31 and PSCI library use the same ``cpu_context_t`` data structure for PSCI CPU context management and register context management during world switch. This cannot be assumed for AArch32 EL3 Runtime Software since most AArch32 Trusted OSes already implement a mechanism for register context management during world switch. Hence, when the PSCI library is integrated with a AArch32 EL3 Runtime Software, the ``cpu_context_t`` is stripped down for just PSCI CPU context management. During cold/warm boot, after invoking appropriate PSCI library interfaces, it is expected that the EL3 Runtime Software will query the ``cpu_context_t`` and write appropriate values to the corresponding system registers. This mechanism resolves 2 additional problems for AArch32 EL3 Runtime Software: #. Values for certain system registers like SCR and SCTLR cannot be unilaterally determined by PSCI library and need inputs from the EL3 Runtime Software. Using ``cpu_context_t`` as an intermediary data store allows EL3 Runtime Software to modify the register values appropriately before programming them. #. The PSCI library provides appropriate LR and SPSR values (entrypoint information) for exit into non-secure world. Using ``cpu_context_t`` as an intermediary data store allows the EL3 Runtime Software to store these values safely until it is ready for exit to non-secure world. Currently the ``cpu_context_t`` data structure for AArch32 stores the following registers: R0 - R3, LR (R14), SCR, SPSR, SCTLR. The EL3 Runtime Software must implement accessors to get/set pointers to CPU context ``cpu_context_t`` data and these are described in `CPU Context management API`_. PSCI Library Interface ---------------------- The PSCI library implements the `PSCI Specification`_. The interfaces to this library are declared in ``psci_lib.h`` and are as listed below: .. code:: c u_register_t psci_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); int psci_setup(const psci_lib_args_t *lib_args); void psci_warmboot_entrypoint(void); void psci_register_spd_pm_hook(const spd_pm_ops_t *pm); void psci_prepare_next_non_secure_ctx(entry_point_info_t *next_image_info); The CPU context data 'cpu_context_t' is programmed to the registers differently when PSCI is integrated with an AArch32 EL3 Runtime Software compared to when the PSCI is integrated with an AArch64 EL3 Runtime Software (BL31). For example, in the case of AArch64, there is no need to retrieve ``cpu_context_t`` data and program the registers as it will done implicitly as part of ``el3_exit``. The description below of the PSCI interfaces is targeted at integration with an AArch32 EL3 Runtime Software. The PSCI library is responsible for initializing/restoring the non-secure world to an appropriate state after boot and may choose to directly program the non-secure system registers. The PSCI generic code takes care not to directly modify any of the system registers affecting the secure world and instead returns the values to be programmed to these registers via ``cpu_context_t``. The EL3 Runtime Software is responsible for programming those registers and can use the proposed values provided in the ``cpu_context_t``, modifying the values if required. PSCI library needs the flexibility to access both secure and non-secure copies of banked registers. Hence it needs to be invoked in Monitor mode for AArch32 and in EL3 for AArch64. The NS bit in SCR (in AArch32) or SCR_EL3 (in AArch64) must be set to 0. Additional requirements for the PSCI library interfaces are: - Instruction cache must be enabled - Both IRQ and FIQ must be masked for the current CPU - The page tables must be setup and the MMU enabled - The C runtime environment must be setup and stack initialized - The Data cache must be enabled prior to invoking any of the PSCI library interfaces except for ``psci_warmboot_entrypoint()``. For ``psci_warmboot_entrypoint()``, if the build option ``HW_ASSISTED_COHERENCY`` is enabled however, data caches are expected to be enabled. Further requirements for each interface can be found in the interface description. Interface : psci_setup() ~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : const psci_lib_args_t *lib_args Return : void This function is to be called by the primary CPU during cold boot before any other interface to the PSCI library. It takes ``lib_args``, a const pointer to ``psci_lib_args_t``, as the argument. The ``psci_lib_args_t`` is a versioned structure and is declared in ``psci_lib.h`` header as follows: .. code:: c typedef struct psci_lib_args { /* The version information of PSCI Library Interface */ param_header_t h; /* The warm boot entrypoint function */ mailbox_entrypoint_t mailbox_ep; } psci_lib_args_t; The first field ``h``, of ``param_header_t`` type, provides the version information. The second field ``mailbox_ep`` is the warm boot entrypoint address and is used to configure the platform mailbox. Helper macros are provided in ``psci_lib.h`` to construct the ``lib_args`` argument statically or during runtime. Prior to calling the ``psci_setup()`` interface, the platform setup for cold boot must have completed. Major actions performed by this interface are: - Initializes architecture. - Initializes PSCI power domain and state coordination data structures. - Calls ``plat_setup_psci_ops()`` with warm boot entrypoint ``mailbox_ep`` as argument. - Calls ``cm_set_context_by_index()`` (see `CPU Context management API`_) for all the CPUs in the platform Interface : psci_prepare_next_non_secure_ctx() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : entry_point_info_t *next_image_info Return : void After ``psci_setup()`` and prior to exit to the non-secure world, this function must be called by the EL3 Runtime Software to initialize the non-secure world context. The non-secure world entrypoint information ``next_image_info`` (first argument) will be used to determine the non-secure context. After this function returns, the EL3 Runtime Software must retrieve the ``cpu_context_t`` (using cm_get_context()) for the current CPU and program the registers prior to exit to the non-secure world. Interface : psci_register_spd_pm_hook() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : const spd_pm_ops_t * Return : void As explained in `Secure payload power management callback`_, the EL3 Runtime Software may want to perform some bookkeeping during power management operations. This function is used to register the ``spd_pm_ops_t`` (first argument) callbacks with the PSCI library which will be called appropriately during power management. Calling this function is optional and need to be called by the primary CPU during the cold boot sequence after ``psci_setup()`` has completed. Interface : psci_smc_handler() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : 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 Return : u_register_t This function is the top level handler for SMCs which fall within the PSCI service range specified in `SMCCC`_. The function ID ``smc_fid`` (first argument) determines the PSCI API to be called. The ``x1`` to ``x4`` (2nd to 5th arguments), are the values of the registers r1 - r4 (in AArch32) or x1 - x4 (in AArch64) when the SMC is received. These are the arguments to PSCI API as described in `PSCI spec`_. The 'flags' (8th argument) is a bit field parameter and is detailed in 'smccc.h' header. It includes whether the call is from the secure or non-secure world. The ``cookie`` (6th argument) and the ``handle`` (7th argument) are not used and are reserved for future use. The return value from this interface is the return value from the underlying PSCI API corresponding to ``smc_fid``. This function may not return back to the caller if PSCI API causes power down of the CPU. In this case, when the CPU wakes up, it will start execution from the warm reset address. Interface : psci_warmboot_entrypoint() ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: Argument : void Return : void This function performs the warm boot initialization/restoration as mandated by `PSCI spec`_. For AArch32, on wakeup from power down the CPU resets to secure SVC mode and the EL3 Runtime Software must perform the prerequisite initializations mentioned at top of this section. This function must be called with Data cache disabled (unless build option ``HW_ASSISTED_COHERENCY`` is enabled) but with MMU initialized and enabled. The major actions performed by this function are: - Invalidates the stack and enables the data cache. - Initializes architecture and PSCI state coordination. - Restores/Initializes the peripheral drivers to the required state via appropriate ``plat_psci_ops_t`` hooks - Restores the EL3 Runtime Software context via appropriate ``spd_pm_ops_t`` callbacks. - Restores/Initializes the non-secure context and populates the ``cpu_context_t`` for the current CPU. Upon the return of this function, the EL3 Runtime Software must retrieve the non-secure ``cpu_context_t`` using ``cm_get_context()`` and program the registers prior to exit to the non-secure world. EL3 Runtime Software dependencies --------------------------------- The PSCI Library includes supporting frameworks like context management, cpu operations (cpu_ops) and per-cpu data framework. Other helper library functions like bakery locks and spin locks are also included in the library. The dependencies which must be fulfilled by the EL3 Runtime Software for integration with PSCI library are described below. General dependencies ~~~~~~~~~~~~~~~~~~~~ The PSCI library being a Multiprocessor (MP) implementation, EL3 Runtime Software must provide an SMC handling framework capable of MP adhering to `SMCCC`_ specification. The EL3 Runtime Software must also export cache maintenance primitives and some helper utilities for assert, print and memory operations as listed below. The TF-A source tree provides implementations for all these functions but the EL3 Runtime Software may use its own implementation. **Functions : assert(), memcpy(), memset(), printf()** These must be implemented as described in ISO C Standard. **Function : flush_dcache_range()** :: Argument : uintptr_t addr, size_t size Return : void This function cleans and invalidates (flushes) the data cache for memory at address ``addr`` (first argument) address and of size ``size`` (second argument). **Function : inv_dcache_range()** :: Argument : uintptr_t addr, size_t size Return : void This function invalidates (flushes) the data cache for memory at address ``addr`` (first argument) address and of size ``size`` (second argument). **Function : do_panic()** :: Argument : void Return : void This function will be called by the PSCI library on encountering a critical failure that cannot be recovered from. This function **must not** return. CPU Context management API ~~~~~~~~~~~~~~~~~~~~~~~~~~ The CPU context management data memory is statically allocated by PSCI library in BSS section. The PSCI library requires the EL3 Runtime Software to implement APIs to store and retrieve pointers to this CPU context data. SP-MIN demonstrates how these APIs can be implemented but the EL3 Runtime Software can choose a more optimal implementation (like dedicating the secure TPIDRPRW system register (in AArch32) for storing these pointers). **Function : cm_set_context_by_index()** :: Argument : unsigned int cpu_idx, void *context, unsigned int security_state Return : void This function is called during cold boot when the ``psci_setup()`` PSCI library interface is called. This function must store the pointer to the CPU context data, ``context`` (2nd argument), for the specified ``security_state`` (3rd argument) and CPU identified by ``cpu_idx`` (first argument). The ``security_state`` will always be non-secure when called by PSCI library and this argument is retained for compatibility with BL31. The ``cpu_idx`` will correspond to the index returned by the ``plat_core_pos_by_mpidr()`` for ``mpidr`` of the CPU. The actual method of storing the ``context`` pointers is implementation specific. For example, SP-MIN stores the pointers in the array ``sp_min_cpu_ctx_ptr`` declared in ``sp_min_main.c``. **Function : cm_get_context()** :: Argument : uint32_t security_state Return : void * This function must return the pointer to the ``cpu_context_t`` structure for the specified ``security_state`` (first argument) for the current CPU. The caller must ensure that ``cm_set_context_by_index`` is called first and the appropriate context pointers are stored prior to invoking this API. The ``security_state`` will always be non-secure when called by PSCI library and this argument is retained for compatibility with BL31. **Function : cm_get_context_by_index()** :: Argument : unsigned int cpu_idx, unsigned int security_state Return : void * This function must return the pointer to the ``cpu_context_t`` structure for the specified ``security_state`` (second argument) for the CPU identified by ``cpu_idx`` (first argument). The caller must ensure that ``cm_set_context_by_index`` is called first and the appropriate context pointers are stored prior to invoking this API. The ``security_state`` will always be non-secure when called by PSCI library and this argument is retained for compatibility with BL31. The ``cpu_idx`` will correspond to the index returned by the ``plat_core_pos_by_mpidr()`` for ``mpidr`` of the CPU. Platform API ~~~~~~~~~~~~ The platform layer abstracts the platform-specific details from the generic PSCI library. The following platform APIs/macros must be defined by the EL3 Runtime Software for integration with the PSCI library. The mandatory platform APIs are: - plat_my_core_pos - plat_core_pos_by_mpidr - plat_get_syscnt_freq2 - plat_get_power_domain_tree_desc - plat_setup_psci_ops - plat_reset_handler - plat_panic_handler - plat_get_my_stack The mandatory platform macros are: - PLATFORM_CORE_COUNT - PLAT_MAX_PWR_LVL - PLAT_NUM_PWR_DOMAINS - CACHE_WRITEBACK_GRANULE - PLAT_MAX_OFF_STATE - PLAT_MAX_RET_STATE - PLAT_MAX_PWR_LVL_STATES (optional) - PLAT_PCPU_DATA_SIZE (optional) The details of these APIs/macros can be found in the :ref:`Porting Guide`. All platform specific operations for power management are done via ``plat_psci_ops_t`` callbacks registered by the platform when ``plat_setup_psci_ops()`` API is called. The description of each of the callbacks in ``plat_psci_ops_t`` can be found in PSCI section of the :ref:`Porting Guide`. If any these callbacks are not registered, then the PSCI API associated with that callback will not be supported by PSCI library. Secure payload power management callback ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ During PSCI power management operations, the EL3 Runtime Software may need to perform some bookkeeping, and PSCI library provides ``spd_pm_ops_t`` callbacks for this purpose. These hooks must be populated and registered by using ``psci_register_spd_pm_hook()`` PSCI library interface. Typical bookkeeping during PSCI power management calls include save/restore of the EL3 Runtime Software context. Also if the EL3 Runtime Software makes use of secure interrupts, then these interrupts must also be managed appropriately during CPU power down/power up. Any secure interrupt targeted to the current CPU must be disabled or re-targeted to other running CPU prior to power down of the current CPU. During power up, these interrupt can be enabled/re-targeted back to the current CPU. .. code:: c typedef struct spd_pm_ops { void (*svc_on)(u_register_t target_cpu); int32_t (*svc_off)(u_register_t __unused); void (*svc_suspend)(u_register_t max_off_pwrlvl); void (*svc_on_finish)(u_register_t __unused); void (*svc_suspend_finish)(u_register_t max_off_pwrlvl); int32_t (*svc_migrate)(u_register_t from_cpu, u_register_t to_cpu); int32_t (*svc_migrate_info)(u_register_t *resident_cpu); void (*svc_system_off)(void); void (*svc_system_reset)(void); } spd_pm_ops_t; A brief description of each callback is given below: - svc_on, svc_off, svc_on_finish The ``svc_on``, ``svc_off`` callbacks are called during PSCI_CPU_ON, PSCI_CPU_OFF APIs respectively. The ``svc_on_finish`` is called when the target CPU of PSCI_CPU_ON API powers up and executes the ``psci_warmboot_entrypoint()`` PSCI library interface. - svc_suspend, svc_suspend_finish The ``svc_suspend`` callback is called during power down bu either PSCI_SUSPEND or PSCI_SYSTEM_SUSPEND APIs. The ``svc_suspend_finish`` is called when the CPU wakes up from suspend and executes the ``psci_warmboot_entrypoint()`` PSCI library interface. The ``max_off_pwrlvl`` (first parameter) denotes the highest power domain level being powered down to or woken up from suspend. - svc_system_off, svc_system_reset These callbacks are called during PSCI_SYSTEM_OFF and PSCI_SYSTEM_RESET PSCI APIs respectively. - svc_migrate_info This callback is called in response to PSCI_MIGRATE_INFO_TYPE or PSCI_MIGRATE_INFO_UP_CPU APIs. The return value of this callback must correspond to the return value of PSCI_MIGRATE_INFO_TYPE API as described in `PSCI spec`_. If the secure payload is a Uniprocessor (UP) implementation, then it must update the mpidr of the CPU it is resident in via ``resident_cpu`` (first argument). The updates to ``resident_cpu`` is ignored if the secure payload is a multiprocessor (MP) implementation. - svc_migrate This callback is only relevant if the secure payload in EL3 Runtime Software is a Uniprocessor (UP) implementation and supports migration from the current CPU ``from_cpu`` (first argument) to another CPU ``to_cpu`` (second argument). This callback is called in response to PSCI_MIGRATE API. This callback is never called if the secure payload is a Multiprocessor (MP) implementation. CPU operations ~~~~~~~~~~~~~~ The CPU operations (cpu_ops) framework implement power down sequence specific to the CPU and the details of which can be found at :ref:`firmware_design_cpu_ops_fwk`. The TF-A tree implements the ``cpu_ops`` for various supported CPUs and the EL3 Runtime Software needs to include the required ``cpu_ops`` in its build. The start and end of the ``cpu_ops`` descriptors must be exported by the EL3 Runtime Software via the ``__CPU_OPS_START__`` and ``__CPU_OPS_END__`` linker symbols. The ``cpu_ops`` descriptors also include reset sequences and may include errata workarounds for the CPU. The EL3 Runtime Software can choose to call this during cold/warm reset if it does not implement its own reset sequence/errata workarounds. -------------- *Copyright (c) 2016-2019, Arm Limited and Contributors. All rights reserved.* .. _PSCI spec: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf .. _SMCCC: https://silver.arm.com/download/ARM_and_AMBA_Architecture/AR570-DA-80002-r0p0-00rel0/ARM_DEN0028A_SMC_Calling_Convention.pdf .. _PSCI specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf .. _PSCI Specification: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf trusted-firmware-a-2.2/docs/getting_started/rt-svc-writers-guide.rst000066400000000000000000000311331355360272700257710ustar00rootroot00000000000000EL3 Runtime Service Writer's Guide ===================================================== Introduction ------------ This document describes how to add a runtime service to the EL3 Runtime Firmware component of Trusted Firmware-A (TF-A), BL31. Software executing in the normal world and in the trusted world at exception levels lower than EL3 will request runtime services using the Secure Monitor Call (SMC) instruction. These requests will follow the convention described in the SMC Calling Convention PDD (`SMCCC`_). The `SMCCC`_ assigns function identifiers to each SMC request and describes how arguments are passed and results are returned. SMC Functions are grouped together based on the implementor of the service, for example a subset of the Function IDs are designated as "OEM Calls" (see `SMCCC`_ for full details). The EL3 runtime services framework in BL31 enables the independent implementation of services for each group, which are then compiled into the BL31 image. This simplifies the integration of common software from Arm to support `PSCI`_, Secure Monitor for a Trusted OS and SoC specific software. The common runtime services framework ensures that SMC Functions are dispatched to their respective service implementation - the :ref:`Firmware Design` document provides details of how this is achieved. The interface and operation of the runtime services depends heavily on the concepts and definitions described in the `SMCCC`_, in particular SMC Function IDs, Owning Entity Numbers (OEN), Fast and Standard calls, and the SMC32 and SMC64 calling conventions. Please refer to that document for a full explanation of these terms. Owning Entities, Call Types and Function IDs -------------------------------------------- The SMC Function Identifier includes a OEN field. These values and their meaning are described in `SMCCC`_ and summarized in table 1 below. Some entities are allocated a range of of OENs. The OEN must be interpreted in conjunction with the SMC call type, which is either *Fast* or *Yielding*. Fast calls are uninterruptible whereas Yielding calls can be pre-empted. The majority of Owning Entities only have allocated ranges for Fast calls: Yielding calls are reserved exclusively for Trusted OS providers or for interoperability with legacy 32-bit software that predates the `SMCCC`_. :: Type OEN Service Fast 0 Arm Architecture calls Fast 1 CPU Service calls Fast 2 SiP Service calls Fast 3 OEM Service calls Fast 4 Standard Service calls Fast 5-47 Reserved for future use Fast 48-49 Trusted Application calls Fast 50-63 Trusted OS calls Yielding 0- 1 Reserved for existing Armv7-A calls Yielding 2-63 Trusted OS Standard Calls *Table 1: Service types and their corresponding Owning Entity Numbers* Each individual entity can allocate the valid identifiers within the entity range as they need - it is not necessary to coordinate with other entities of the same type. For example, two SoC providers can use the same Function ID within the SiP Service calls OEN range to mean different things - as these calls should be specific to the SoC. The Standard Runtime Calls OEN is used for services defined by Arm standards, such as `PSCI`_. The SMC Function ID also indicates whether the call has followed the SMC32 calling convention, where all parameters are 32-bit, or the SMC64 calling convention, where the parameters are 64-bit. The framework identifies and rejects invalid calls that use the SMC64 calling convention but that originate from an AArch32 caller. The EL3 runtime services framework uses the call type and OEN to identify a specific handler for each SMC call, but it is expected that an individual handler will be responsible for all SMC Functions within a given service type. Getting started --------------- TF-A has a ``services`` directory in the source tree under which each owning entity can place the implementation of its runtime service. The `PSCI`_ implementation is located here in the ``lib/psci`` directory. Runtime service sources will need to include the ``runtime_svc.h`` header file. Registering a runtime service ----------------------------- A runtime service is registered using the ``DECLARE_RT_SVC()`` macro, specifying the name of the service, the range of OENs covered, the type of service and initialization and call handler functions. .. code:: c #define DECLARE_RT_SVC(_name, _start, _end, _type, _setup, _smch) - ``_name`` is used to identify the data structure declared by this macro, and is also used for diagnostic purposes - ``_start`` and ``_end`` values must be based on the ``OEN_*`` values defined in ``smccc.h`` - ``_type`` must be one of ``SMC_TYPE_FAST`` or ``SMC_TYPE_YIELD`` - ``_setup`` is the initialization function with the ``rt_svc_init`` signature: .. code:: c typedef int32_t (*rt_svc_init)(void); - ``_smch`` is the SMC handler function with the ``rt_svc_handle`` signature: .. code:: c typedef uintptr_t (*rt_svc_handle_t)(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); Details of the requirements and behavior of the two callbacks is provided in the following sections. During initialization the services framework validates each declared service to ensure that the following conditions are met: #. The ``_start`` OEN is not greater than the ``_end`` OEN #. The ``_end`` OEN does not exceed the maximum OEN value (63) #. The ``_type`` is one of ``SMC_TYPE_FAST`` or ``SMC_TYPE_YIELD`` #. ``_setup`` and ``_smch`` routines have been specified ``std_svc_setup.c`` provides an example of registering a runtime service: .. code:: c /* Register Standard Service Calls as runtime service */ DECLARE_RT_SVC( std_svc, OEN_STD_START, OEN_STD_END, SMC_TYPE_FAST, std_svc_setup, std_svc_smc_handler ); Initializing a runtime service ------------------------------ Runtime services are initialized once, during cold boot, by the primary CPU after platform and architectural initialization is complete. The framework performs basic validation of the declared service before calling the service initialization function (``_setup`` in the declaration). This function must carry out any essential EL3 initialization prior to receiving a SMC Function call via the handler function. On success, the initialization function must return ``0``. Any other return value will cause the framework to issue a diagnostic: :: Error initializing runtime service and then ignore the service - the system will continue to boot but SMC calls will not be passed to the service handler and instead return the *Unknown SMC Function ID* result ``0xFFFFFFFF``. If the system must not be allowed to proceed without the service, the initialization function must itself cause the firmware boot to be halted. If the service uses per-CPU data this must either be initialized for all CPUs during this call, or be done lazily when a CPU first issues an SMC call to that service. Handling runtime service requests --------------------------------- SMC calls for a service are forwarded by the framework to the service's SMC handler function (``_smch`` in the service declaration). This function must have the following signature: .. code:: c typedef uintptr_t (*rt_svc_handle_t)(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); The handler is responsible for: #. Determining that ``smc_fid`` is a valid and supported SMC Function ID, otherwise completing the request with the *Unknown SMC Function ID*: .. code:: c SMC_RET1(handle, SMC_UNK); #. Determining if the requested function is valid for the calling security state. SMC Calls can be made from both the normal and trusted worlds and the framework will forward all calls to the service handler. The ``flags`` parameter to this function indicates the caller security state in bit[0], where a value of ``1`` indicates a non-secure caller. The ``is_caller_secure(flags)`` and ``is_caller_non_secure(flags)`` can be used to test this condition. If invalid, the request should be completed with: .. code:: c SMC_RET1(handle, SMC_UNK); #. Truncating parameters for calls made using the SMC32 calling convention. Such calls can be determined by checking the CC field in bit[30] of the ``smc_fid`` parameter, for example by using: :: if (GET_SMC_CC(smc_fid) == SMC_32) ... For such calls, the upper bits of the parameters x1-x4 and the saved parameters X5-X7 are UNDEFINED and must be explicitly ignored by the handler. This can be done by truncating the values to a suitable 32-bit integer type before use, for example by ensuring that functions defined to handle individual SMC Functions use appropriate 32-bit parameters. #. Providing the service requested by the SMC Function, utilizing the immediate parameters x1-x4 and/or the additional saved parameters X5-X7. The latter can be retrieved using the ``SMC_GET_GP(handle, ref)`` function, supplying the appropriate ``CTX_GPREG_Xn`` reference, e.g. .. code:: c uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6); #. Implementing the standard SMC32 Functions that provide information about the implementation of the service. These are the Call Count, Implementor UID and Revision Details for each service documented in section 6 of the `SMCCC`_. TF-A expects owning entities to follow this recommendation. #. Returning the result to the caller. The `SMCCC`_ allows for up to 256 bits of return value in SMC64 using X0-X3 and 128 bits in SMC32 using W0-W3. The framework provides a family of macros to set the multi-register return value and complete the handler: .. code:: c SMC_RET1(handle, x0); SMC_RET2(handle, x0, x1); SMC_RET3(handle, x0, x1, x2); SMC_RET4(handle, x0, x1, x2, x3); The ``cookie`` parameter to the handler is reserved for future use and can be ignored. The ``handle`` is returned by the SMC handler - completion of the handler function must always be via one of the ``SMC_RETn()`` macros. .. note:: The PSCI and Test Secure-EL1 Payload Dispatcher services do not follow all of the above requirements yet. Services that contain multiple sub-services ------------------------------------------- It is possible that a single owning entity implements multiple sub-services. For example, the Standard calls service handles ``0x84000000``-``0x8400FFFF`` and ``0xC4000000``-``0xC400FFFF`` functions. Within that range, the `PSCI`_ service handles the ``0x84000000``-``0x8400001F`` and ``0xC4000000``-``0xC400001F`` functions. In that respect, `PSCI`_ is a 'sub-service' of the Standard calls service. In future, there could be additional such sub-services in the Standard calls service which perform independent functions. In this situation it may be valuable to introduce a second level framework to enable independent implementation of sub-services. Such a framework might look very similar to the current runtime services framework, but using a different part of the SMC Function ID to identify the sub-service. TF-A does not provide such a framework at present. Secure-EL1 Payload Dispatcher service (SPD) ------------------------------------------- Services that handle SMC Functions targeting a Trusted OS, Trusted Application, or other Secure-EL1 Payload are special. These services need to manage the Secure-EL1 context, provide the *Secure Monitor* functionality of switching between the normal and secure worlds, deliver SMC Calls through to Secure-EL1 and generally manage the Secure-EL1 Payload through CPU power-state transitions. TODO: Provide details of the additional work required to implement a SPD and the BL31 support for these services. Or a reference to the document that will provide this information.... -------------- *Copyright (c) 2014-2019, Arm Limited and Contributors. All rights reserved.* .. _SMCCC: http://infocenter.arm.com/help/topic/com.arm.doc.den0028a/index.html .. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022c/DEN0022C_Power_State_Coordination_Interface.pdf trusted-firmware-a-2.2/docs/getting_started/user-guide.rst000066400000000000000000003015131355360272700240360ustar00rootroot00000000000000User Guide ========== This document describes how to build Trusted Firmware-A (TF-A) and run it with a tested set of other software components using defined configurations on the Juno Arm development platform and Arm Fixed Virtual Platform (FVP) models. It is possible to use other software components, configurations and platforms but that is outside the scope of this document. This document assumes that the reader has previous experience running a fully bootable Linux software stack on Juno or FVP using the prebuilt binaries and filesystems provided by Linaro. Further information may be found in the `Linaro instructions`_. It also assumes that the user understands the role of the different software components required to boot a Linux system: - Specific firmware images required by the platform (e.g. SCP firmware on Juno) - Normal world bootloader (e.g. UEFI or U-Boot) - Device tree - Linux kernel image - Root filesystem This document also assumes that the user is familiar with the `FVP models`_ and the different command line options available to launch the model. This document should be used in conjunction with the :ref:`Firmware Design`. Host machine requirements ------------------------- The minimum recommended machine specification for building the software and running the FVP models is a dual-core processor running at 2GHz with 12GB of RAM. For best performance, use a machine with a quad-core processor running at 2.6GHz with 16GB of RAM. The software has been tested on Ubuntu 16.04 LTS (64-bit). Packages used for building the software were installed from that distribution unless otherwise specified. The software has also been built on Windows 7 Enterprise SP1, using CMD.EXE, Cygwin, and Msys (MinGW) shells, using version 5.3.1 of the GNU toolchain. Tools ----- Install the required packages to build TF-A with the following command: .. code:: shell sudo apt-get install device-tree-compiler build-essential gcc make git libssl-dev Download and install the AArch32 (arm-eabi) or AArch64 little-endian (aarch64-linux-gnu) GCC 8.3-2019.03 cross compiler from `Arm Developer page`_. Optionally, TF-A can be built using clang version 4.0 or newer or Arm Compiler 6. See instructions below on how to switch the default compiler. In addition, the following optional packages and tools may be needed: - ``device-tree-compiler`` (dtc) package if you need to rebuild the Flattened Device Tree (FDT) source files (``.dts`` files) provided with this software. The version of dtc must be 1.4.6 or above. - For debugging, Arm `Development Studio 5 (DS-5)`_. - To create and modify the diagram files included in the documentation, `Dia`_. This tool can be found in most Linux distributions. Inkscape is needed to generate the actual \*.png files. TF-A has been tested with pre-built binaries and file systems from `Linaro Release 19.06`_. Alternatively, you can build the binaries from source using instructions provided at the `Arm Platforms User guide`_. Getting the TF-A source code ---------------------------- Clone the repository from the Gerrit server. The project details may be found on the `arm-trusted-firmware-a project page`_. We recommend the "`Clone with commit-msg hook`" clone method, which will setup the git commit hook that automatically generates and inserts appropriate `Change-Id:` lines in your commit messages. Checking source code style ~~~~~~~~~~~~~~~~~~~~~~~~~~ Trusted Firmware follows the `Linux Coding Style`_ . When making changes to the source, for submission to the project, the source must be in compliance with this style guide. Additional, project-specific guidelines are defined in the :ref:`Coding Style & Guidelines` document. To assist with coding style compliance, the project Makefile contains two targets which both utilise the `checkpatch.pl` script that ships with the Linux source tree. The project also defines certain *checkpatch* options in the ``.checkpatch.conf`` file in the top-level directory. .. note:: Checkpatch errors will gate upstream merging of pull requests. Checkpatch warnings will not gate merging but should be reviewed and fixed if possible. To check the entire source tree, you must first download copies of ``checkpatch.pl``, ``spelling.txt`` and ``const_structs.checkpatch`` available in the `Linux master tree`_ *scripts* directory, then set the ``CHECKPATCH`` environment variable to point to ``checkpatch.pl`` (with the other 2 files in the same directory) and build the `checkcodebase` target: .. code:: shell make CHECKPATCH=/linux/scripts/checkpatch.pl checkcodebase To just check the style on the files that differ between your local branch and the remote master, use: .. code:: shell make CHECKPATCH=/linux/scripts/checkpatch.pl checkpatch If you wish to check your patch against something other than the remote master, set the ``BASE_COMMIT`` variable to your desired branch. By default, ``BASE_COMMIT`` is set to ``origin/master``. Building TF-A ------------- - Before building TF-A, the environment variable ``CROSS_COMPILE`` must point to the cross compiler. For AArch64: .. code:: shell export CROSS_COMPILE=/bin/aarch64-linux-gnu- For AArch32: .. code:: shell export CROSS_COMPILE=/bin/arm-eabi- It is possible to build TF-A using Clang or Arm Compiler 6. To do so ``CC`` needs to point to the clang or armclang binary, which will also select the clang or armclang assembler. Be aware that the GNU linker is used by default. In case of being needed the linker can be overridden using the ``LD`` variable. Clang linker version 6 is known to work with TF-A. In both cases ``CROSS_COMPILE`` should be set as described above. Arm Compiler 6 will be selected when the base name of the path assigned to ``CC`` matches the string 'armclang'. For AArch64 using Arm Compiler 6: .. code:: shell export CROSS_COMPILE=/bin/aarch64-linux-gnu- make CC=/bin/armclang PLAT= all Clang will be selected when the base name of the path assigned to ``CC`` contains the string 'clang'. This is to allow both clang and clang-X.Y to work. For AArch64 using clang: .. code:: shell export CROSS_COMPILE=/bin/aarch64-linux-gnu- make CC=/bin/clang PLAT= all - Change to the root directory of the TF-A source tree and build. For AArch64: .. code:: shell make PLAT= all For AArch32: .. code:: shell make PLAT= ARCH=aarch32 AARCH32_SP=sp_min all Notes: - If ``PLAT`` is not specified, ``fvp`` is assumed by default. See the `Summary of build options`_ for more information on available build options. - (AArch32 only) ``AARCH32_SP`` is the AArch32 EL3 Runtime Software and it corresponds to the BL32 image. A minimal ``AARCH32_SP``, sp_min, is provided by TF-A to demonstrate how PSCI Library can be integrated with an AArch32 EL3 Runtime Software. Some AArch32 EL3 Runtime Software may include other runtime services, for example Trusted OS services. A guide to integrate PSCI library with AArch32 EL3 Runtime Software can be found at :ref:`PSCI Library Integration guide for Armv8-A AArch32 systems`. - (AArch64 only) The TSP (Test Secure Payload), corresponding to the BL32 image, is not compiled in by default. Refer to the `Building the Test Secure Payload`_ section below. - By default this produces a release version of the build. To produce a debug version instead, refer to the "Debugging options" section below. - The build process creates products in a ``build`` directory tree, building the objects and binaries for each boot loader stage in separate sub-directories. The following boot loader binary files are created from the corresponding ELF files: - ``build///bl1.bin`` - ``build///bl2.bin`` - ``build///bl31.bin`` (AArch64 only) - ``build///bl32.bin`` (mandatory for AArch32) where ```` is the name of the chosen platform and ```` is either ``debug`` or ``release``. The actual number of images might differ depending on the platform. - Build products for a specific build variant can be removed using: .. code:: shell make DEBUG= PLAT= clean ... where ```` is ``0`` or ``1``, as specified when building. The build tree can be removed completely using: .. code:: shell make realclean Summary of build options ~~~~~~~~~~~~~~~~~~~~~~~~ The TF-A build system supports the following build options. Unless mentioned otherwise, these options are expected to be specified at the build command line and are not to be modified in any component makefiles. Note that the build system doesn't track dependency for build options. Therefore, if any of the build options are changed from a previous build, a clean build must be performed. Common build options ^^^^^^^^^^^^^^^^^^^^ - ``AARCH32_INSTRUCTION_SET``: Choose the AArch32 instruction set that the compiler should use. Valid values are T32 and A32. It defaults to T32 due to code having a smaller resulting size. - ``AARCH32_SP`` : Choose the AArch32 Secure Payload component to be built as as the BL32 image when ``ARCH=aarch32``. The value should be the path to the directory containing the SP source, relative to the ``bl32/``; the directory is expected to contain a makefile called ``.mk``. - ``ARCH`` : Choose the target build architecture for TF-A. It can take either ``aarch64`` or ``aarch32`` as values. By default, it is defined to ``aarch64``. - ``ARM_ARCH_MAJOR``: The major version of Arm Architecture to target when compiling TF-A. Its value must be numeric, and defaults to 8 . See also, *Armv8 Architecture Extensions* and *Armv7 Architecture Extensions* in :ref:`Firmware Design`. - ``ARM_ARCH_MINOR``: The minor version of Arm Architecture to target when compiling TF-A. Its value must be a numeric, and defaults to 0. See also, *Armv8 Architecture Extensions* in :ref:`Firmware Design`. - ``BL2``: This is an optional build option which specifies the path to BL2 image for the ``fip`` target. In this case, the BL2 in the TF-A will not be built. - ``BL2U``: This is an optional build option which specifies the path to BL2U image. In this case, the BL2U in TF-A will not be built. - ``BL2_AT_EL3``: This is an optional build option that enables the use of BL2 at EL3 execution level. - ``BL2_IN_XIP_MEM``: In some use-cases BL2 will be stored in eXecute In Place (XIP) memory, like BL1. In these use-cases, it is necessary to initialize the RW sections in RAM, while leaving the RO sections in place. This option enable this use-case. For now, this option is only supported when BL2_AT_EL3 is set to '1'. - ``BL2_INV_DCACHE``: This is an optional build option which control dcache invalidation upon BL2 entry. Some platform cannot handle cache operations during entry as the coherency unit is not yet initialized. This may cause crashing. Leaving this option to '1' (default) will allow the operation. This option is only relevant when BL2_AT_EL3 is set to '1'. - ``BL31``: This is an optional build option which specifies the path to BL31 image for the ``fip`` target. In this case, the BL31 in TF-A will not be built. - ``BL31_KEY``: This option is used when ``GENERATE_COT=1``. It specifies the file that contains the BL31 private key in PEM format. If ``SAVE_KEYS=1``, this file name will be used to save the key. - ``BL32``: This is an optional build option which specifies the path to BL32 image for the ``fip`` target. In this case, the BL32 in TF-A will not be built. - ``BL32_EXTRA1``: This is an optional build option which specifies the path to Trusted OS Extra1 image for the ``fip`` target. - ``BL32_EXTRA2``: This is an optional build option which specifies the path to Trusted OS Extra2 image for the ``fip`` target. - ``BL32_KEY``: This option is used when ``GENERATE_COT=1``. It specifies the file that contains the BL32 private key in PEM format. If ``SAVE_KEYS=1``, this file name will be used to save the key. - ``BL33``: Path to BL33 image in the host file system. This is mandatory for ``fip`` target in case TF-A BL2 is used. - ``BL33_KEY``: This option is used when ``GENERATE_COT=1``. It specifies the file that contains the BL33 private key in PEM format. If ``SAVE_KEYS=1``, this file name will be used to save the key. - ``BRANCH_PROTECTION``: Numeric value to enable ARMv8.3 Pointer Authentication and ARMv8.5 Branch Target Identification support for TF-A BL images themselves. If enabled, it is needed to use a compiler (e.g GCC 9.1 and later versions) that supports the option ``-mbranch-protection``. Selects the branch protection features to use: - 0: Default value turns off all types of branch protection - 1: Enables all types of branch protection features - 2: Return address signing to its standard level - 3: Extend the signing to include leaf functions The table below summarizes ``BRANCH_PROTECTION`` values, GCC compilation options and resulting PAuth/BTI features. +-------+--------------+-------+-----+ | Value | GCC option | PAuth | BTI | +=======+==============+=======+=====+ | 0 | none | N | N | +-------+--------------+-------+-----+ | 1 | standard | Y | Y | +-------+--------------+-------+-----+ | 2 | pac-ret | Y | N | +-------+--------------+-------+-----+ | 3 | pac-ret+leaf | Y | N | +-------+--------------+-------+-----+ This option defaults to 0 and this is an experimental feature. Note that Pointer Authentication is enabled for Non-secure world irrespective of the value of this option if the CPU supports it. - ``BUILD_MESSAGE_TIMESTAMP``: String used to identify the time and date of the compilation of each build. It must be set to a C string (including quotes where applicable). Defaults to a string that contains the time and date of the compilation. - ``BUILD_STRING``: Input string for VERSION_STRING, which allows the TF-A build to be uniquely identified. Defaults to the current git commit id. - ``CFLAGS``: Extra user options appended on the compiler's command line in addition to the options set by the build system. - ``COLD_BOOT_SINGLE_CPU``: This option indicates whether the platform may release several CPUs out of reset. It can take either 0 (several CPUs may be brought up) or 1 (only one CPU will ever be brought up during cold reset). Default is 0. If the platform always brings up a single CPU, there is no need to distinguish between primary and secondary CPUs and the boot path can be optimised. The ``plat_is_my_cpu_primary()`` and ``plat_secondary_cold_boot_setup()`` platform porting interfaces do not need to be implemented in this case. - ``CRASH_REPORTING``: A non-zero value enables a console dump of processor register state when an unexpected exception occurs during execution of BL31. This option defaults to the value of ``DEBUG`` - i.e. by default this is only enabled for a debug build of the firmware. - ``CREATE_KEYS``: This option is used when ``GENERATE_COT=1``. It tells the certificate generation tool to create new keys in case no valid keys are present or specified. Allowed options are '0' or '1'. Default is '1'. - ``CTX_INCLUDE_AARCH32_REGS`` : Boolean option that, when set to 1, will cause the AArch32 system registers to be included when saving and restoring the CPU context. The option must be set to 0 for AArch64-only platforms (that is on hardware that does not implement AArch32, or at least not at EL1 and higher ELs). Default value is 1. - ``CTX_INCLUDE_FPREGS``: Boolean option that, when set to 1, will cause the FP registers to be included when saving and restoring the CPU context. Default is 0. - ``CTX_INCLUDE_MTE_REGS``: Enables register saving/reloading support for ARMv8.5 Memory Tagging Extension. A value of 0 will disable saving/reloading and restrict the use of MTE to the normal world if the CPU has support, while a value of 1 enables the saving/reloading, allowing the use of MTE in both the secure and non-secure worlds. Default is 0 (disabled) and this feature is experimental. - ``CTX_INCLUDE_PAUTH_REGS``: Boolean option that, when set to 1, enables Pointer Authentication for Secure world. This will cause the ARMv8.3-PAuth registers to be included when saving and restoring the CPU context as part of world switch. Default value is 0 and this is an experimental feature. Note that Pointer Authentication is enabled for Non-secure world irrespective of the value of this flag if the CPU supports it. - ``DEBUG``: Chooses between a debug and release build. It can take either 0 (release) or 1 (debug) as values. 0 is the default. - ``DISABLE_BIN_GENERATION``: Boolean option to disable the generation of the binary image. If set to 1, then only the ELF image is built. 0 is the default. - ``DYN_DISABLE_AUTH``: Provides the capability to dynamically disable Trusted Board Boot authentication at runtime. This option is meant to be enabled only for development platforms. ``TRUSTED_BOARD_BOOT`` flag must be set if this flag has to be enabled. 0 is the default. - ``E``: Boolean option to make warnings into errors. Default is 1. - ``EL3_PAYLOAD_BASE``: This option enables booting an EL3 payload instead of the normal boot flow. It must specify the entry point address of the EL3 payload. Please refer to the "Booting an EL3 payload" section for more details. - ``ENABLE_AMU``: Boolean option to enable Activity Monitor Unit extensions. This is an optional architectural feature available on v8.4 onwards. Some v8.2 implementations also implement an AMU and this option can be used to enable this feature on those systems as well. Default is 0. - ``ENABLE_ASSERTIONS``: This option controls whether or not calls to ``assert()`` are compiled out. For debug builds, this option defaults to 1, and calls to ``assert()`` are left in place. For release builds, this option defaults to 0 and calls to ``assert()`` function are compiled out. This option can be set independently of ``DEBUG``. It can also be used to hide any auxiliary code that is only required for the assertion and does not fit in the assertion itself. - ``ENABLE_BACKTRACE``: This option controls whether to enables backtrace dumps or not. It is supported in both AArch64 and AArch32. However, in AArch32 the format of the frame records are not defined in the AAPCS and they are defined by the implementation. This implementation of backtrace only supports the format used by GCC when T32 interworking is disabled. For this reason enabling this option in AArch32 will force the compiler to only generate A32 code. This option is enabled by default only in AArch64 debug builds, but this behaviour can be overridden in each platform's Makefile or in the build command line. - ``ENABLE_MPAM_FOR_LOWER_ELS``: Boolean option to enable lower ELs to use MPAM feature. MPAM is an optional Armv8.4 extension that enables various memory system components and resources to define partitions; software running at various ELs can assign themselves to desired partition to control their performance aspects. When this option is set to ``1``, EL3 allows lower ELs to access their own MPAM registers without trapping into EL3. This option doesn't make use of partitioning in EL3, however. Platform initialisation code should configure and use partitions in EL3 as required. This option defaults to ``0``. - ``ENABLE_PIE``: Boolean option to enable Position Independent Executable(PIE) support within generic code in TF-A. This option is currently only supported in BL31. Default is 0. - ``ENABLE_PMF``: Boolean option to enable support for optional Performance Measurement Framework(PMF). Default is 0. - ``ENABLE_PSCI_STAT``: Boolean option to enable support for optional PSCI functions ``PSCI_STAT_RESIDENCY`` and ``PSCI_STAT_COUNT``. Default is 0. In the absence of an alternate stat collection backend, ``ENABLE_PMF`` must be enabled. If ``ENABLE_PMF`` is set, the residency statistics are tracked in software. - ``ENABLE_RUNTIME_INSTRUMENTATION``: Boolean option to enable runtime instrumentation which injects timestamp collection points into TF-A to allow runtime performance to be measured. Currently, only PSCI is instrumented. Enabling this option enables the ``ENABLE_PMF`` build option as well. Default is 0. - ``ENABLE_SPE_FOR_LOWER_ELS`` : Boolean option to enable Statistical Profiling extensions. This is an optional architectural feature for AArch64. The default is 1 but is automatically disabled when the target architecture is AArch32. - ``ENABLE_SPM`` : Boolean option to enable the Secure Partition Manager (SPM). Refer to :ref:`Secure Partition Manager` for more details about this feature. Default is 0. - ``ENABLE_SVE_FOR_NS``: Boolean option to enable Scalable Vector Extension (SVE) for the Non-secure world only. SVE is an optional architectural feature for AArch64. Note that when SVE is enabled for the Non-secure world, access to SIMD and floating-point functionality from the Secure world is disabled. This is to avoid corruption of the Non-secure world data in the Z-registers which are aliased by the SIMD and FP registers. The build option is not compatible with the ``CTX_INCLUDE_FPREGS`` build option, and will raise an assert on platforms where SVE is implemented and ``ENABLE_SVE_FOR_NS`` set to 1. The default is 1 but is automatically disabled when the target architecture is AArch32. - ``ENABLE_STACK_PROTECTOR``: String option to enable the stack protection checks in GCC. Allowed values are "all", "strong", "default" and "none". The default value is set to "none". "strong" is the recommended stack protection level if this feature is desired. "none" disables the stack protection. For all values other than "none", the ``plat_get_stack_protector_canary()`` platform hook needs to be implemented. The value is passed as the last component of the option ``-fstack-protector-$ENABLE_STACK_PROTECTOR``. - ``ERROR_DEPRECATED``: This option decides whether to treat the usage of deprecated platform APIs, helper functions or drivers within Trusted Firmware as error. It can take the value 1 (flag the use of deprecated APIs as error) or 0. The default is 0. - ``EL3_EXCEPTION_HANDLING``: When set to ``1``, enable handling of exceptions targeted at EL3. When set ``0`` (default), no exceptions are expected or handled at EL3, and a panic will result. This is supported only for AArch64 builds. - ``FAULT_INJECTION_SUPPORT``: ARMv8.4 extensions introduced support for fault injection from lower ELs, and this build option enables lower ELs to use Error Records accessed via System Registers to inject faults. This is applicable only to AArch64 builds. This feature is intended for testing purposes only, and is advisable to keep disabled for production images. - ``FIP_NAME``: This is an optional build option which specifies the FIP filename for the ``fip`` target. Default is ``fip.bin``. - ``FWU_FIP_NAME``: This is an optional build option which specifies the FWU FIP filename for the ``fwu_fip`` target. Default is ``fwu_fip.bin``. - ``GENERATE_COT``: Boolean flag used to build and execute the ``cert_create`` tool to create certificates as per the Chain of Trust described in :ref:`Trusted Board Boot`. The build system then calls ``fiptool`` to include the certificates in the FIP and FWU_FIP. Default value is '0'. Specify both ``TRUSTED_BOARD_BOOT=1`` and ``GENERATE_COT=1`` to include support for the Trusted Board Boot feature in the BL1 and BL2 images, to generate the corresponding certificates, and to include those certificates in the FIP and FWU_FIP. Note that if ``TRUSTED_BOARD_BOOT=0`` and ``GENERATE_COT=1``, the BL1 and BL2 images will not include support for Trusted Board Boot. The FIP will still include the corresponding certificates. This FIP can be used to verify the Chain of Trust on the host machine through other mechanisms. Note that if ``TRUSTED_BOARD_BOOT=1`` and ``GENERATE_COT=0``, the BL1 and BL2 images will include support for Trusted Board Boot, but the FIP and FWU_FIP will not include the corresponding certificates, causing a boot failure. - ``GICV2_G0_FOR_EL3``: Unlike GICv3, the GICv2 architecture doesn't have inherent support for specific EL3 type interrupts. Setting this build option to ``1`` assumes GICv2 *Group 0* interrupts are expected to target EL3, both by `platform abstraction layer`__ and `Interrupt Management Framework`__. This allows GICv2 platforms to enable features requiring EL3 interrupt type. This also means that all GICv2 Group 0 interrupts are delivered to EL3, and the Secure Payload interrupts needs to be synchronously handed over to Secure EL1 for handling. The default value of this option is ``0``, which means the Group 0 interrupts are assumed to be handled by Secure EL1. .. __: `platform-interrupt-controller-API.rst` .. __: `interrupt-framework-design.rst` - ``HANDLE_EA_EL3_FIRST``: When set to ``1``, External Aborts and SError Interrupts will be always trapped in EL3 i.e. in BL31 at runtime. When set to ``0`` (default), these exceptions will be trapped in the current exception level (or in EL1 if the current exception level is EL0). - ``HW_ASSISTED_COHERENCY``: On most Arm systems to-date, platform-specific software operations are required for CPUs to enter and exit coherency. However, newer systems exist where CPUs' entry to and exit from coherency is managed in hardware. Such systems require software to only initiate these operations, and the rest is managed in hardware, minimizing active software management. In such systems, this boolean option enables TF-A to carry out build and run-time optimizations during boot and power management operations. This option defaults to 0 and if it is enabled, then it implies ``WARMBOOT_ENABLE_DCACHE_EARLY`` is also enabled. If this flag is disabled while the platform which TF-A is compiled for includes cores that manage coherency in hardware, then a compilation error is generated. This is based on the fact that a system cannot have, at the same time, cores that manage coherency in hardware and cores that don't. In other words, a platform cannot have, at the same time, cores that require ``HW_ASSISTED_COHERENCY=1`` and cores that require ``HW_ASSISTED_COHERENCY=0``. Note that, when ``HW_ASSISTED_COHERENCY`` is enabled, version 2 of translation library (xlat tables v2) must be used; version 1 of translation library is not supported. - ``JUNO_AARCH32_EL3_RUNTIME``: This build flag enables you to execute EL3 runtime software in AArch32 mode, which is required to run AArch32 on Juno. By default this flag is set to '0'. Enabling this flag builds BL1 and BL2 in AArch64 and facilitates the loading of ``SP_MIN`` and BL33 as AArch32 executable images. - ``KEY_ALG``: This build flag enables the user to select the algorithm to be used for generating the PKCS keys and subsequent signing of the certificate. It accepts 2 values: ``rsa`` and ``ecdsa``. The default value of this flag is ``rsa`` which is the TBBR compliant PKCS#1 RSA 2.1 scheme. - ``KEY_SIZE``: This build flag enables the user to select the key size for the algorithm specified by ``KEY_ALG``. The valid values for ``KEY_SIZE`` depend on the chosen algorithm. +-----------+------------------------------------+ | KEY_ALG | Possible key sizes | +===========+====================================+ | rsa | 1024, 2048 (default), 3072, 4096 | +-----------+------------------------------------+ | ecdsa | unavailable | +-----------+------------------------------------+ - ``HASH_ALG``: This build flag enables the user to select the secure hash algorithm. It accepts 3 values: ``sha256``, ``sha384`` and ``sha512``. The default value of this flag is ``sha256``. - ``LDFLAGS``: Extra user options appended to the linkers' command line in addition to the one set by the build system. - ``LOG_LEVEL``: Chooses the log level, which controls the amount of console log output compiled into the build. This should be one of the following: :: 0 (LOG_LEVEL_NONE) 10 (LOG_LEVEL_ERROR) 20 (LOG_LEVEL_NOTICE) 30 (LOG_LEVEL_WARNING) 40 (LOG_LEVEL_INFO) 50 (LOG_LEVEL_VERBOSE) All log output up to and including the selected log level is compiled into the build. The default value is 40 in debug builds and 20 in release builds. - ``NON_TRUSTED_WORLD_KEY``: This option is used when ``GENERATE_COT=1``. It specifies the file that contains the Non-Trusted World private key in PEM format. If ``SAVE_KEYS=1``, this file name will be used to save the key. - ``NS_BL2U``: Path to NS_BL2U image in the host file system. This image is optional. It is only needed if the platform makefile specifies that it is required in order to build the ``fwu_fip`` target. - ``NS_TIMER_SWITCH``: Enable save and restore for non-secure timer register contents upon world switch. It can take either 0 (don't save and restore) or 1 (do save and restore). 0 is the default. An SPD may set this to 1 if it wants the timer registers to be saved and restored. - ``OVERRIDE_LIBC``: This option allows platforms to override the default libc for the BL image. It can be either 0 (include) or 1 (remove). The default value is 0. - ``PL011_GENERIC_UART``: Boolean option to indicate the PL011 driver that the underlying hardware is not a full PL011 UART but a minimally compliant generic UART, which is a subset of the PL011. The driver will not access any register that is not part of the SBSA generic UART specification. Default value is 0 (a full PL011 compliant UART is present). - ``PLAT``: Choose a platform to build TF-A for. The chosen platform name must be subdirectory of any depth under ``plat/``, and must contain a platform makefile named ``platform.mk``. For example, to build TF-A for the Arm Juno board, select PLAT=juno. - ``PRELOADED_BL33_BASE``: This option enables booting a preloaded BL33 image instead of the normal boot flow. When defined, it must specify the entry point address for the preloaded BL33 image. This option is incompatible with ``EL3_PAYLOAD_BASE``. If both are defined, ``EL3_PAYLOAD_BASE`` has priority over ``PRELOADED_BL33_BASE``. - ``PROGRAMMABLE_RESET_ADDRESS``: This option indicates whether the reset vector address can be programmed or is fixed on the platform. It can take either 0 (fixed) or 1 (programmable). Default is 0. If the platform has a programmable reset address, it is expected that a CPU will start executing code directly at the right address, both on a cold and warm reset. In this case, there is no need to identify the entrypoint on boot and the boot path can be optimised. The ``plat_get_my_entrypoint()`` platform porting interface does not need to be implemented in this case. - ``PSCI_EXTENDED_STATE_ID``: As per PSCI1.0 Specification, there are 2 formats possible for the PSCI power-state parameter: original and extended State-ID formats. This flag if set to 1, configures the generic PSCI layer to use the extended format. The default value of this flag is 0, which means by default the original power-state format is used by the PSCI implementation. This flag should be specified by the platform makefile and it governs the return value of PSCI_FEATURES API for CPU_SUSPEND smc function id. When this option is enabled on Arm platforms, the option ``ARM_RECOM_STATE_ID_ENC`` needs to be set to 1 as well. - ``RAS_EXTENSION``: When set to ``1``, enable Armv8.2 RAS features. RAS features are an optional extension for pre-Armv8.2 CPUs, but are mandatory for Armv8.2 or later CPUs. When ``RAS_EXTENSION`` is set to ``1``, ``HANDLE_EA_EL3_FIRST`` must also be set to ``1``. This option is disabled by default. - ``RESET_TO_BL31``: Enable BL31 entrypoint as the CPU reset vector instead of the BL1 entrypoint. It can take the value 0 (CPU reset to BL1 entrypoint) or 1 (CPU reset to BL31 entrypoint). The default value is 0. - ``RESET_TO_SP_MIN``: SP_MIN is the minimal AArch32 Secure Payload provided in TF-A. This flag configures SP_MIN entrypoint as the CPU reset vector instead of the BL1 entrypoint. It can take the value 0 (CPU reset to BL1 entrypoint) or 1 (CPU reset to SP_MIN entrypoint). The default value is 0. - ``ROT_KEY``: This option is used when ``GENERATE_COT=1``. It specifies the file that contains the ROT private key in PEM format. If ``SAVE_KEYS=1``, this file name will be used to save the key. - ``SANITIZE_UB``: This option enables the Undefined Behaviour sanitizer. It can take 3 values: 'off' (default), 'on' and 'trap'. When using 'trap', gcc and clang will insert calls to ``__builtin_trap`` on detected undefined behaviour, which defaults to a ``brk`` instruction. When using 'on', undefined behaviour is translated to a call to special handlers which prints the exact location of the problem and its cause and then panics. .. note:: Because of the space penalty of the Undefined Behaviour sanitizer, this option will increase the size of the binary. Depending on the memory constraints of the target platform, it may not be possible to enable the sanitizer for all images (BL1 and BL2 are especially likely to be memory constrained). We recommend that the sanitizer is enabled only in debug builds. - ``SAVE_KEYS``: This option is used when ``GENERATE_COT=1``. It tells the certificate generation tool to save the keys used to establish the Chain of Trust. Allowed options are '0' or '1'. Default is '0' (do not save). - ``SCP_BL2``: Path to SCP_BL2 image in the host file system. This image is optional. If a SCP_BL2 image is present then this option must be passed for the ``fip`` target. - ``SCP_BL2_KEY``: This option is used when ``GENERATE_COT=1``. It specifies the file that contains the SCP_BL2 private key in PEM format. If ``SAVE_KEYS=1``, this file name will be used to save the key. - ``SCP_BL2U``: Path to SCP_BL2U image in the host file system. This image is optional. It is only needed if the platform makefile specifies that it is required in order to build the ``fwu_fip`` target. - ``SDEI_SUPPORT``: Setting this to ``1`` enables support for Software Delegated Exception Interface to BL31 image. This defaults to ``0``. When set to ``1``, the build option ``EL3_EXCEPTION_HANDLING`` must also be set to ``1``. - ``SEPARATE_CODE_AND_RODATA``: Whether code and read-only data should be isolated on separate memory pages. This is a trade-off between security and memory usage. See "Isolating code and read-only data on separate memory pages" section in :ref:`Firmware Design`. This flag is disabled by default and affects all BL images. - ``SPD``: Choose a Secure Payload Dispatcher component to be built into TF-A. This build option is only valid if ``ARCH=aarch64``. The value should be the path to the directory containing the SPD source, relative to ``services/spd/``; the directory is expected to contain a makefile called ``.mk``. - ``SPIN_ON_BL1_EXIT``: This option introduces an infinite loop in BL1. It can take either 0 (no loop) or 1 (add a loop). 0 is the default. This loop stops execution in BL1 just before handing over to BL31. At this point, all firmware images have been loaded in memory, and the MMU and caches are turned off. Refer to the "Debugging options" section for more details. - ``SP_MIN_WITH_SECURE_FIQ``: Boolean flag to indicate the SP_MIN handles secure interrupts (caught through the FIQ line). Platforms can enable this directive if they need to handle such interruption. When enabled, the FIQ are handled in monitor mode and non secure world is not allowed to mask these events. Platforms that enable FIQ handling in SP_MIN shall implement the api ``sp_min_plat_fiq_handler()``. The default value is 0. - ``TRUSTED_BOARD_BOOT``: Boolean flag to include support for the Trusted Board Boot feature. When set to '1', BL1 and BL2 images include support to load and verify the certificates and images in a FIP, and BL1 includes support for the Firmware Update. The default value is '0'. Generation and inclusion of certificates in the FIP and FWU_FIP depends upon the value of the ``GENERATE_COT`` option. .. warning:: This option depends on ``CREATE_KEYS`` to be enabled. If the keys already exist in disk, they will be overwritten without further notice. - ``TRUSTED_WORLD_KEY``: This option is used when ``GENERATE_COT=1``. It specifies the file that contains the Trusted World private key in PEM format. If ``SAVE_KEYS=1``, this file name will be used to save the key. - ``TSP_INIT_ASYNC``: Choose BL32 initialization method as asynchronous or synchronous, (see "Initializing a BL32 Image" section in :ref:`Firmware Design`). It can take the value 0 (BL32 is initialized using synchronous method) or 1 (BL32 is initialized using asynchronous method). Default is 0. - ``TSP_NS_INTR_ASYNC_PREEMPT``: A non zero value enables the interrupt routing model which routes non-secure interrupts asynchronously from TSP to EL3 causing immediate preemption of TSP. The EL3 is responsible for saving and restoring the TSP context in this routing model. The default routing model (when the value is 0) is to route non-secure interrupts to TSP allowing it to save its context and hand over synchronously to EL3 via an SMC. .. note:: When ``EL3_EXCEPTION_HANDLING`` is ``1``, ``TSP_NS_INTR_ASYNC_PREEMPT`` must also be set to ``1``. - ``USE_ARM_LINK``: This flag determines whether to enable support for ARM linker. When the ``LINKER`` build variable points to the armlink linker, this flag is enabled automatically. To enable support for armlink, platforms will have to provide a scatter file for the BL image. Currently, Tegra platforms use the armlink support to compile BL3-1 images. - ``USE_COHERENT_MEM``: This flag determines whether to include the coherent memory region in the BL memory map or not (see "Use of Coherent memory in TF-A" section in :ref:`Firmware Design`). It can take the value 1 (Coherent memory region is included) or 0 (Coherent memory region is excluded). Default is 1. - ``USE_ROMLIB``: This flag determines whether library at ROM will be used. This feature creates a library of functions to be placed in ROM and thus reduces SRAM usage. Refer to :ref:`Library at ROM` for further details. Default is 0. - ``USE_SPINLOCK_CAS``: Setting this build flag to 1 selects the spinlock implementation variant using the ARMv8.1-LSE compare-and-swap instruction. Notice this option is experimental and only available to AArch64 builds. - ``V``: Verbose build. If assigned anything other than 0, the build commands are printed. Default is 0. - ``VERSION_STRING``: String used in the log output for each TF-A image. Defaults to a string formed by concatenating the version number, build type and build string. - ``W``: Warning level. Some compiler warning options of interest have been regrouped and put in the root Makefile. This flag can take the values 0 to 3, each level enabling more warning options. Default is 0. - ``WARMBOOT_ENABLE_DCACHE_EARLY`` : Boolean option to enable D-cache early on the CPU after warm boot. This is applicable for platforms which do not require interconnect programming to enable cache coherency (eg: single cluster platforms). If this option is enabled, then warm boot path enables D-caches immediately after enabling MMU. This option defaults to 0. Arm development platform specific build options ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``ARM_BL31_IN_DRAM``: Boolean option to select loading of BL31 in TZC secured DRAM. By default, BL31 is in the secure SRAM. Set this flag to 1 to load BL31 in TZC secured DRAM. If TSP is present, then setting this option also sets the TSP location to DRAM and ignores the ``ARM_TSP_RAM_LOCATION`` build flag. - ``ARM_CONFIG_CNTACR``: boolean option to unlock access to the ``CNTBase`` frame registers by setting the ``CNTCTLBase.CNTACR`` register bits. The frame number ```` is defined by ``PLAT_ARM_NSTIMER_FRAME_ID``, which should match the frame used by the Non-Secure image (normally the Linux kernel). Default is true (access to the frame is allowed). - ``ARM_DISABLE_TRUSTED_WDOG``: boolean option to disable the Trusted Watchdog. By default, Arm platforms use a watchdog to trigger a system reset in case an error is encountered during the boot process (for example, when an image could not be loaded or authenticated). The watchdog is enabled in the early platform setup hook at BL1 and disabled in the BL1 prepare exit hook. The Trusted Watchdog may be disabled at build time for testing or development purposes. - ``ARM_LINUX_KERNEL_AS_BL33``: The Linux kernel expects registers x0-x3 to have specific values at boot. This boolean option allows the Trusted Firmware to have a Linux kernel image as BL33 by preparing the registers to these values before jumping to BL33. This option defaults to 0 (disabled). For AArch64 ``RESET_TO_BL31`` and for AArch32 ``RESET_TO_SP_MIN`` must be 1 when using it. If this option is set to 1, ``ARM_PRELOADED_DTB_BASE`` must be set to the location of a device tree blob (DTB) already loaded in memory. The Linux Image address must be specified using the ``PRELOADED_BL33_BASE`` option. - ``ARM_PLAT_MT``: This flag determines whether the Arm platform layer has to cater for the multi-threading ``MT`` bit when accessing MPIDR. When this flag is set, the functions which deal with MPIDR assume that the ``MT`` bit in MPIDR is set and access the bit-fields in MPIDR accordingly. Default value of this flag is 0. Note that this option is not used on FVP platforms. - ``ARM_RECOM_STATE_ID_ENC``: The PSCI1.0 specification recommends an encoding for the construction of composite state-ID in the power-state parameter. The existing PSCI clients currently do not support this encoding of State-ID yet. Hence this flag is used to configure whether to use the recommended State-ID encoding or not. The default value of this flag is 0, in which case the platform is configured to expect NULL in the State-ID field of power-state parameter. - ``ARM_ROTPK_LOCATION``: used when ``TRUSTED_BOARD_BOOT=1``. It specifies the location of the ROTPK hash returned by the function ``plat_get_rotpk_info()`` for Arm platforms. Depending on the selected option, the proper private key must be specified using the ``ROT_KEY`` option when building the Trusted Firmware. This private key will be used by the certificate generation tool to sign the BL2 and Trusted Key certificates. Available options for ``ARM_ROTPK_LOCATION`` are: - ``regs`` : return the ROTPK hash stored in the Trusted root-key storage registers. The private key corresponding to this ROTPK hash is not currently available. - ``devel_rsa`` : return a development public key hash embedded in the BL1 and BL2 binaries. This hash has been obtained from the RSA public key ``arm_rotpk_rsa.der``, located in ``plat/arm/board/common/rotpk``. To use this option, ``arm_rotprivk_rsa.pem`` must be specified as ``ROT_KEY`` when creating the certificates. - ``devel_ecdsa`` : return a development public key hash embedded in the BL1 and BL2 binaries. This hash has been obtained from the ECDSA public key ``arm_rotpk_ecdsa.der``, located in ``plat/arm/board/common/rotpk``. To use this option, ``arm_rotprivk_ecdsa.pem`` must be specified as ``ROT_KEY`` when creating the certificates. - ``ARM_TSP_RAM_LOCATION``: location of the TSP binary. Options: - ``tsram`` : Trusted SRAM (default option when TBB is not enabled) - ``tdram`` : Trusted DRAM (if available) - ``dram`` : Secure region in DRAM (default option when TBB is enabled, configured by the TrustZone controller) - ``ARM_XLAT_TABLES_LIB_V1``: boolean option to compile TF-A with version 1 of the translation tables library instead of version 2. It is set to 0 by default, which selects version 2. - ``ARM_CRYPTOCELL_INTEG`` : bool option to enable TF-A to invoke Arm® TrustZone® CryptoCell functionality for Trusted Board Boot on capable Arm platforms. If this option is specified, then the path to the CryptoCell SBROM library must be specified via ``CCSBROM_LIB_PATH`` flag. For a better understanding of these options, the Arm development platform memory map is explained in the :ref:`Firmware Design`. Arm CSS platform specific build options ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``CSS_DETECT_PRE_1_7_0_SCP``: Boolean flag to detect SCP version incompatibility. Version 1.7.0 of the SCP firmware made a non-backwards compatible change to the MTL protocol, used for AP/SCP communication. TF-A no longer supports earlier SCP versions. If this option is set to 1 then TF-A will detect if an earlier version is in use. Default is 1. - ``CSS_LOAD_SCP_IMAGES``: Boolean flag, which when set, adds SCP_BL2 and SCP_BL2U to the FIP and FWU_FIP respectively, and enables them to be loaded during boot. Default is 1. - ``CSS_USE_SCMI_SDS_DRIVER``: Boolean flag which selects SCMI/SDS drivers instead of SCPI/BOM driver for communicating with the SCP during power management operations and for SCP RAM Firmware transfer. If this option is set to 1, then SCMI/SDS drivers will be used. Default is 0. Arm FVP platform specific build options ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``FVP_CLUSTER_COUNT`` : Configures the cluster count to be used to build the topology tree within TF-A. By default TF-A is configured for dual cluster topology and this option can be used to override the default value. - ``FVP_INTERCONNECT_DRIVER``: Selects the interconnect driver to be built. The default interconnect driver depends on the value of ``FVP_CLUSTER_COUNT`` as explained in the options below: - ``FVP_CCI`` : The CCI driver is selected. This is the default if 0 < ``FVP_CLUSTER_COUNT`` <= 2. - ``FVP_CCN`` : The CCN driver is selected. This is the default if ``FVP_CLUSTER_COUNT`` > 2. - ``FVP_MAX_CPUS_PER_CLUSTER``: Sets the maximum number of CPUs implemented in a single cluster. This option defaults to 4. - ``FVP_MAX_PE_PER_CPU``: Sets the maximum number of PEs implemented on any CPU in the system. This option defaults to 1. Note that the build option ``ARM_PLAT_MT`` doesn't have any effect on FVP platforms. - ``FVP_USE_GIC_DRIVER`` : Selects the GIC driver to be built. Options: - ``FVP_GIC600`` : The GIC600 implementation of GICv3 is selected - ``FVP_GICV2`` : The GICv2 only driver is selected - ``FVP_GICV3`` : The GICv3 only driver is selected (default option) - ``FVP_USE_SP804_TIMER`` : Use the SP804 timer instead of the Generic Timer for functions that wait for an arbitrary time length (udelay and mdelay). The default value is 0. - ``FVP_HW_CONFIG_DTS`` : Specify the path to the DTS file to be compiled to DTB and packaged in FIP as the HW_CONFIG. See :ref:`Firmware Design` for details on HW_CONFIG. By default, this is initialized to a sensible DTS file in ``fdts/`` folder depending on other build options. But some cases, like shifted affinity format for MPIDR, cannot be detected at build time and this option is needed to specify the appropriate DTS file. - ``FVP_HW_CONFIG`` : Specify the path to the HW_CONFIG blob to be packaged in FIP. See :ref:`Firmware Design` for details on HW_CONFIG. This option is similar to the ``FVP_HW_CONFIG_DTS`` option, but it directly specifies the HW_CONFIG blob instead of the DTS file. This option is useful to override the default HW_CONFIG selected by the build system. ARM JUNO platform specific build options ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``JUNO_TZMP1`` : Boolean option to configure Juno to be used for TrustZone Media Protection (TZ-MP1). Default value of this flag is 0. Debugging options ~~~~~~~~~~~~~~~~~ To compile a debug version and make the build more verbose use .. code:: shell make PLAT= DEBUG=1 V=1 all AArch64 GCC uses DWARF version 4 debugging symbols by default. Some tools (for example DS-5) might not support this and may need an older version of DWARF symbols to be emitted by GCC. This can be achieved by using the ``-gdwarf-`` flag, with the version being set to 2 or 3. Setting the version to 2 is recommended for DS-5 versions older than 5.16. When debugging logic problems it might also be useful to disable all compiler optimizations by using ``-O0``. .. warning:: Using ``-O0`` could cause output images to be larger and base addresses might need to be recalculated (see the **Memory layout on Arm development platforms** section in the :ref:`Firmware Design`). Extra debug options can be passed to the build system by setting ``CFLAGS`` or ``LDFLAGS``: .. code:: shell CFLAGS='-O0 -gdwarf-2' \ make PLAT= DEBUG=1 V=1 all Note that using ``-Wl,`` style compilation driver options in ``CFLAGS`` will be ignored as the linker is called directly. It is also possible to introduce an infinite loop to help in debugging the post-BL2 phase of TF-A. This can be done by rebuilding BL1 with the ``SPIN_ON_BL1_EXIT=1`` build flag. Refer to the `Summary of build options`_ section. In this case, the developer may take control of the target using a debugger when indicated by the console output. When using DS-5, the following commands can be used: :: # Stop target execution interrupt # # Prepare your debugging environment, e.g. set breakpoints # # Jump over the debug loop set var $AARCH64::$Core::$PC = $AARCH64::$Core::$PC + 4 # Resume execution continue Building the Test Secure Payload ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The TSP is coupled with a companion runtime service in the BL31 firmware, called the TSPD. Therefore, if you intend to use the TSP, the BL31 image must be recompiled as well. For more information on SPs and SPDs, see the :ref:`Secure-EL1 Payloads and Dispatchers ` section in the :ref:`Firmware Design` document. First clean the TF-A build directory to get rid of any previous BL31 binary. Then to build the TSP image use: .. code:: shell make PLAT= SPD=tspd all An additional boot loader binary file is created in the ``build`` directory: :: build///bl32.bin Building and using the FIP tool ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Firmware Image Package (FIP) is a packaging format used by TF-A to package firmware images in a single binary. The number and type of images that should be packed in a FIP is platform specific and may include TF-A images and other firmware images required by the platform. For example, most platforms require a BL33 image which corresponds to the normal world bootloader (e.g. UEFI or U-Boot). The TF-A build system provides the make target ``fip`` to create a FIP file for the specified platform using the FIP creation tool included in the TF-A project. Examples below show how to build a FIP file for FVP, packaging TF-A and BL33 images. For AArch64: .. code:: shell make PLAT=fvp BL33=/bl33.bin fip For AArch32: .. code:: shell make PLAT=fvp ARCH=aarch32 AARCH32_SP=sp_min BL33=/bl33.bin fip The resulting FIP may be found in: :: build/fvp//fip.bin For advanced operations on FIP files, it is also possible to independently build the tool and create or modify FIPs using this tool. To do this, follow these steps: It is recommended to remove old artifacts before building the tool: .. code:: shell make -C tools/fiptool clean Build the tool: .. code:: shell make [DEBUG=1] [V=1] fiptool The tool binary can be located in: :: ./tools/fiptool/fiptool Invoking the tool with ``help`` will print a help message with all available options. Example 1: create a new Firmware package ``fip.bin`` that contains BL2 and BL31: .. code:: shell ./tools/fiptool/fiptool create \ --tb-fw build///bl2.bin \ --soc-fw build///bl31.bin \ fip.bin Example 2: view the contents of an existing Firmware package: .. code:: shell ./tools/fiptool/fiptool info /fip.bin Example 3: update the entries of an existing Firmware package: .. code:: shell # Change the BL2 from Debug to Release version ./tools/fiptool/fiptool update \ --tb-fw build//release/bl2.bin \ build//debug/fip.bin Example 4: unpack all entries from an existing Firmware package: .. code:: shell # Images will be unpacked to the working directory ./tools/fiptool/fiptool unpack /fip.bin Example 5: remove an entry from an existing Firmware package: .. code:: shell ./tools/fiptool/fiptool remove \ --tb-fw build//debug/fip.bin Note that if the destination FIP file exists, the create, update and remove operations will automatically overwrite it. The unpack operation will fail if the images already exist at the destination. In that case, use -f or --force to continue. More information about FIP can be found in the :ref:`Firmware Design` document. Building FIP images with support for Trusted Board Boot ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Trusted Board Boot primarily consists of the following two features: - Image Authentication, described in :ref:`Trusted Board Boot`, and - Firmware Update, described in :ref:`Firmware Update (FWU)` The following steps should be followed to build FIP and (optionally) FWU_FIP images with support for these features: #. Fulfill the dependencies of the ``mbedtls`` cryptographic and image parser modules by checking out a recent version of the `mbed TLS Repository`_. It is important to use a version that is compatible with TF-A and fixes any known security vulnerabilities. See `mbed TLS Security Center`_ for more information. The latest version of TF-A is tested with tag ``mbedtls-2.16.2``. The ``drivers/auth/mbedtls/mbedtls_*.mk`` files contain the list of mbed TLS source files the modules depend upon. ``include/drivers/auth/mbedtls/mbedtls_config.h`` contains the configuration options required to build the mbed TLS sources. Note that the mbed TLS library is licensed under the Apache version 2.0 license. Using mbed TLS source code will affect the licensing of TF-A binaries that are built using this library. #. To build the FIP image, ensure the following command line variables are set while invoking ``make`` to build TF-A: - ``MBEDTLS_DIR=`` - ``TRUSTED_BOARD_BOOT=1`` - ``GENERATE_COT=1`` In the case of Arm platforms, the location of the ROTPK hash must also be specified at build time. Two locations are currently supported (see ``ARM_ROTPK_LOCATION`` build option): - ``ARM_ROTPK_LOCATION=regs``: the ROTPK hash is obtained from the Trusted root-key storage registers present in the platform. On Juno, this registers are read-only. On FVP Base and Cortex models, the registers are read-only, but the value can be specified using the command line option ``bp.trusted_key_storage.public_key`` when launching the model. On both Juno and FVP models, the default value corresponds to an ECDSA-SECP256R1 public key hash, whose private part is not currently available. - ``ARM_ROTPK_LOCATION=devel_rsa``: use the ROTPK hash that is hardcoded in the Arm platform port. The private/public RSA key pair may be found in ``plat/arm/board/common/rotpk``. - ``ARM_ROTPK_LOCATION=devel_ecdsa``: use the ROTPK hash that is hardcoded in the Arm platform port. The private/public ECDSA key pair may be found in ``plat/arm/board/common/rotpk``. Example of command line using RSA development keys: .. code:: shell MBEDTLS_DIR= \ make PLAT= TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 \ ARM_ROTPK_LOCATION=devel_rsa \ ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem \ BL33=/ \ all fip The result of this build will be the bl1.bin and the fip.bin binaries. This FIP will include the certificates corresponding to the Chain of Trust described in the TBBR-client document. These certificates can also be found in the output build directory. #. The optional FWU_FIP contains any additional images to be loaded from Non-Volatile storage during the :ref:`Firmware Update (FWU)` process. To build the FWU_FIP, any FWU images required by the platform must be specified on the command line. On Arm development platforms like Juno, these are: - NS_BL2U. The AP non-secure Firmware Updater image. - SCP_BL2U. The SCP Firmware Update Configuration image. Example of Juno command line for generating both ``fwu`` and ``fwu_fip`` targets using RSA development: :: MBEDTLS_DIR= \ make PLAT=juno TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 \ ARM_ROTPK_LOCATION=devel_rsa \ ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem \ BL33=/ \ SCP_BL2=/ \ SCP_BL2U=/ \ NS_BL2U=/ \ all fip fwu_fip .. note:: The BL2U image will be built by default and added to the FWU_FIP. The user may override this by adding ``BL2U=/`` to the command line above. .. note:: Building and installing the non-secure and SCP FWU images (NS_BL1U, NS_BL2U and SCP_BL2U) is outside the scope of this document. The result of this build will be bl1.bin, fip.bin and fwu_fip.bin binaries. Both the FIP and FWU_FIP will include the certificates corresponding to the Chain of Trust described in the TBBR-client document. These certificates can also be found in the output build directory. Building the Certificate Generation Tool ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``cert_create`` tool is built as part of the TF-A build process when the ``fip`` make target is specified and TBB is enabled (as described in the previous section), but it can also be built separately with the following command: .. code:: shell make PLAT= [DEBUG=1] [V=1] certtool For platforms that require their own IDs in certificate files, the generic 'cert_create' tool can be built with the following command. Note that the target platform must define its IDs within a ``platform_oid.h`` header file for the build to succeed. .. code:: shell make PLAT= USE_TBBR_DEFS=0 [DEBUG=1] [V=1] certtool ``DEBUG=1`` builds the tool in debug mode. ``V=1`` makes the build process more verbose. The following command should be used to obtain help about the tool: .. code:: shell ./tools/cert_create/cert_create -h Building a FIP for Juno and FVP ------------------------------- This section provides Juno and FVP specific instructions to build Trusted Firmware, obtain the additional required firmware, and pack it all together in a single FIP binary. It assumes that a `Linaro Release`_ has been installed. .. note:: Pre-built binaries for AArch32 are available from Linaro Release 16.12 onwards. Before that release, pre-built binaries are only available for AArch64. .. warning:: Follow the full instructions for one platform before switching to a different one. Mixing instructions for different platforms may result in corrupted binaries. .. warning:: The uboot image downloaded by the Linaro workspace script does not always match the uboot image packaged as BL33 in the corresponding fip file. It is recommended to use the version that is packaged in the fip file using the instructions below. .. note:: For the FVP, the kernel FDT is packaged in FIP during build and loaded by the firmware at runtime. See `Obtaining the Flattened Device Trees`_ section for more info on selecting the right FDT to use. #. Clean the working directory .. code:: shell make realclean #. Obtain SCP_BL2 (Juno) and BL33 (all platforms) Use the fiptool to extract the SCP_BL2 and BL33 images from the FIP package included in the Linaro release: .. code:: shell # Build the fiptool make [DEBUG=1] [V=1] fiptool # Unpack firmware images from Linaro FIP ./tools/fiptool/fiptool unpack /[SOFTWARE]/fip.bin The unpack operation will result in a set of binary images extracted to the current working directory. The SCP_BL2 image corresponds to ``scp-fw.bin`` and BL33 corresponds to ``nt-fw.bin``. .. note:: The fiptool will complain if the images to be unpacked already exist in the current directory. If that is the case, either delete those files or use the ``--force`` option to overwrite. .. note:: For AArch32, the instructions below assume that nt-fw.bin is a normal world boot loader that supports AArch32. #. Build TF-A images and create a new FIP for FVP .. code:: shell # AArch64 make PLAT=fvp BL33=nt-fw.bin all fip # AArch32 make PLAT=fvp ARCH=aarch32 AARCH32_SP=sp_min BL33=nt-fw.bin all fip #. Build TF-A images and create a new FIP for Juno For AArch64: Building for AArch64 on Juno simply requires the addition of ``SCP_BL2`` as a build parameter. .. code:: shell make PLAT=juno BL33=nt-fw.bin SCP_BL2=scp-fw.bin all fip For AArch32: Hardware restrictions on Juno prevent cold reset into AArch32 execution mode, therefore BL1 and BL2 must be compiled for AArch64, and BL32 is compiled separately for AArch32. - Before building BL32, the environment variable ``CROSS_COMPILE`` must point to the AArch32 cross compiler. .. code:: shell export CROSS_COMPILE=/bin/arm-eabi- - Build BL32 in AArch32. .. code:: shell make ARCH=aarch32 PLAT=juno AARCH32_SP=sp_min \ RESET_TO_SP_MIN=1 JUNO_AARCH32_EL3_RUNTIME=1 bl32 - Save ``bl32.bin`` to a temporary location and clean the build products. :: cp /bl32.bin make realclean - Before building BL1 and BL2, the environment variable ``CROSS_COMPILE`` must point to the AArch64 cross compiler. .. code:: shell export CROSS_COMPILE=/bin/aarch64-linux-gnu- - The following parameters should be used to build BL1 and BL2 in AArch64 and point to the BL32 file. .. code:: shell make ARCH=aarch64 PLAT=juno JUNO_AARCH32_EL3_RUNTIME=1 \ BL33=nt-fw.bin SCP_BL2=scp-fw.bin \ BL32=/bl32.bin all fip The resulting BL1 and FIP images may be found in: :: # Juno ./build/juno/release/bl1.bin ./build/juno/release/fip.bin # FVP ./build/fvp/release/bl1.bin ./build/fvp/release/fip.bin Booting Firmware Update images ------------------------------------- When Firmware Update (FWU) is enabled there are at least 2 new images that have to be loaded, the Non-Secure FWU ROM (NS-BL1U), and the FWU FIP. Juno ~~~~ The new images must be programmed in flash memory by adding an entry in the ``SITE1/HBI0262x/images.txt`` configuration file on the Juno SD card (where ``x`` depends on the revision of the Juno board). Refer to the `Juno Getting Started Guide`_, section 2.3 "Flash memory programming" for more information. User should ensure these do not overlap with any other entries in the file. :: NOR10UPDATE: AUTO ;Image Update:NONE/AUTO/FORCE NOR10ADDRESS: 0x00400000 ;Image Flash Address [ns_bl2u_base_address] NOR10FILE: \SOFTWARE\fwu_fip.bin ;Image File Name NOR10LOAD: 00000000 ;Image Load Address NOR10ENTRY: 00000000 ;Image Entry Point NOR11UPDATE: AUTO ;Image Update:NONE/AUTO/FORCE NOR11ADDRESS: 0x03EB8000 ;Image Flash Address [ns_bl1u_base_address] NOR11FILE: \SOFTWARE\ns_bl1u.bin ;Image File Name NOR11LOAD: 00000000 ;Image Load Address The address ns_bl1u_base_address is the value of NS_BL1U_BASE - 0x8000000. In the same way, the address ns_bl2u_base_address is the value of NS_BL2U_BASE - 0x8000000. FVP ~~~ The additional fip images must be loaded with: :: --data cluster0.cpu0="/ns_bl1u.bin"@0x0beb8000 [ns_bl1u_base_address] --data cluster0.cpu0="/fwu_fip.bin"@0x08400000 [ns_bl2u_base_address] The address ns_bl1u_base_address is the value of NS_BL1U_BASE. In the same way, the address ns_bl2u_base_address is the value of NS_BL2U_BASE. EL3 payloads alternative boot flow ---------------------------------- On a pre-production system, the ability to execute arbitrary, bare-metal code at the highest exception level is required. It allows full, direct access to the hardware, for example to run silicon soak tests. Although it is possible to implement some baremetal secure firmware from scratch, this is a complex task on some platforms, depending on the level of configuration required to put the system in the expected state. Rather than booting a baremetal application, a possible compromise is to boot ``EL3 payloads`` through TF-A instead. This is implemented as an alternative boot flow, where a modified BL2 boots an EL3 payload, instead of loading the other BL images and passing control to BL31. It reduces the complexity of developing EL3 baremetal code by: - putting the system into a known architectural state; - taking care of platform secure world initialization; - loading the SCP_BL2 image if required by the platform. When booting an EL3 payload on Arm standard platforms, the configuration of the TrustZone controller is simplified such that only region 0 is enabled and is configured to permit secure access only. This gives full access to the whole DRAM to the EL3 payload. The system is left in the same state as when entering BL31 in the default boot flow. In particular: - Running in EL3; - Current state is AArch64; - Little-endian data access; - All exceptions disabled; - MMU disabled; - Caches disabled. Booting an EL3 payload ~~~~~~~~~~~~~~~~~~~~~~ The EL3 payload image is a standalone image and is not part of the FIP. It is not loaded by TF-A. Therefore, there are 2 possible scenarios: - The EL3 payload may reside in non-volatile memory (NVM) and execute in place. In this case, booting it is just a matter of specifying the right address in NVM through ``EL3_PAYLOAD_BASE`` when building TF-A. - The EL3 payload needs to be loaded in volatile memory (e.g. DRAM) at run-time. To help in the latter scenario, the ``SPIN_ON_BL1_EXIT=1`` build option can be used. The infinite loop that it introduces in BL1 stops execution at the right moment for a debugger to take control of the target and load the payload (for example, over JTAG). It is expected that this loading method will work in most cases, as a debugger connection is usually available in a pre-production system. The user is free to use any other platform-specific mechanism to load the EL3 payload, though. Booting an EL3 payload on FVP ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The EL3 payloads boot flow requires the CPU's mailbox to be cleared at reset for the secondary CPUs holding pen to work properly. Unfortunately, its reset value is undefined on the FVP platform and the FVP platform code doesn't clear it. Therefore, one must modify the way the model is normally invoked in order to clear the mailbox at start-up. One way to do that is to create an 8-byte file containing all zero bytes using the following command: .. code:: shell dd if=/dev/zero of=mailbox.dat bs=1 count=8 and pre-load it into the FVP memory at the mailbox address (i.e. ``0x04000000``) using the following model parameters: :: --data cluster0.cpu0=mailbox.dat@0x04000000 [Base FVPs] --data=mailbox.dat@0x04000000 [Foundation FVP] To provide the model with the EL3 payload image, the following methods may be used: #. If the EL3 payload is able to execute in place, it may be programmed into flash memory. On Base Cortex and AEM FVPs, the following model parameter loads it at the base address of the NOR FLASH1 (the NOR FLASH0 is already used for the FIP): :: -C bp.flashloader1.fname="/" On Foundation FVP, there is no flash loader component and the EL3 payload may be programmed anywhere in flash using method 3 below. #. When using the ``SPIN_ON_BL1_EXIT=1`` loading method, the following DS-5 command may be used to load the EL3 payload ELF image over JTAG: :: load /el3-payload.elf #. The EL3 payload may be pre-loaded in volatile memory using the following model parameters: :: --data cluster0.cpu0="/el3-payload>"@address [Base FVPs] --data="/"@address [Foundation FVP] The address provided to the FVP must match the ``EL3_PAYLOAD_BASE`` address used when building TF-A. Booting an EL3 payload on Juno ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If the EL3 payload is able to execute in place, it may be programmed in flash memory by adding an entry in the ``SITE1/HBI0262x/images.txt`` configuration file on the Juno SD card (where ``x`` depends on the revision of the Juno board). Refer to the `Juno Getting Started Guide`_, section 2.3 "Flash memory programming" for more information. Alternatively, the same DS-5 command mentioned in the FVP section above can be used to load the EL3 payload's ELF file over JTAG on Juno. Preloaded BL33 alternative boot flow ------------------------------------ Some platforms have the ability to preload BL33 into memory instead of relying on TF-A to load it. This may simplify packaging of the normal world code and improve performance in a development environment. When secure world cold boot is complete, TF-A simply jumps to a BL33 base address provided at build time. For this option to be used, the ``PRELOADED_BL33_BASE`` build option has to be used when compiling TF-A. For example, the following command will create a FIP without a BL33 and prepare to jump to a BL33 image loaded at address 0x80000000: .. code:: shell make PRELOADED_BL33_BASE=0x80000000 PLAT=fvp all fip Boot of a preloaded kernel image on Base FVP ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following example uses a simplified boot flow by directly jumping from the TF-A to the Linux kernel, which will use a ramdisk as filesystem. This can be useful if both the kernel and the device tree blob (DTB) are already present in memory (like in FVP). For example, if the kernel is loaded at ``0x80080000`` and the DTB is loaded at address ``0x82000000``, the firmware can be built like this: .. code:: shell CROSS_COMPILE=aarch64-linux-gnu- \ make PLAT=fvp DEBUG=1 \ RESET_TO_BL31=1 \ ARM_LINUX_KERNEL_AS_BL33=1 \ PRELOADED_BL33_BASE=0x80080000 \ ARM_PRELOADED_DTB_BASE=0x82000000 \ all fip Now, it is needed to modify the DTB so that the kernel knows the address of the ramdisk. The following script generates a patched DTB from the provided one, assuming that the ramdisk is loaded at address ``0x84000000``. Note that this script assumes that the user is using a ramdisk image prepared for U-Boot, like the ones provided by Linaro. If using a ramdisk without this header,the ``0x40`` offset in ``INITRD_START`` has to be removed. .. code:: bash #!/bin/bash # Path to the input DTB KERNEL_DTB=/ # Path to the output DTB PATCHED_KERNEL_DTB=/ # Base address of the ramdisk INITRD_BASE=0x84000000 # Path to the ramdisk INITRD=/ # Skip uboot header (64 bytes) INITRD_START=$(printf "0x%x" $((${INITRD_BASE} + 0x40)) ) INITRD_SIZE=$(stat -Lc %s ${INITRD}) INITRD_END=$(printf "0x%x" $((${INITRD_BASE} + ${INITRD_SIZE})) ) CHOSEN_NODE=$(echo \ "/ { \ chosen { \ linux,initrd-start = <${INITRD_START}>; \ linux,initrd-end = <${INITRD_END}>; \ }; \ };") echo $(dtc -O dts -I dtb ${KERNEL_DTB}) ${CHOSEN_NODE} | \ dtc -O dtb -o ${PATCHED_KERNEL_DTB} - And the FVP binary can be run with the following command: .. code:: shell /FVP_Base_AEMv8A-AEMv8A \ -C pctl.startup=0.0.0.0 \ -C bp.secure_memory=1 \ -C cluster0.NUM_CORES=4 \ -C cluster1.NUM_CORES=4 \ -C cache_state_modelled=1 \ -C cluster0.cpu0.RVBAR=0x04020000 \ -C cluster0.cpu1.RVBAR=0x04020000 \ -C cluster0.cpu2.RVBAR=0x04020000 \ -C cluster0.cpu3.RVBAR=0x04020000 \ -C cluster1.cpu0.RVBAR=0x04020000 \ -C cluster1.cpu1.RVBAR=0x04020000 \ -C cluster1.cpu2.RVBAR=0x04020000 \ -C cluster1.cpu3.RVBAR=0x04020000 \ --data cluster0.cpu0="/bl31.bin"@0x04020000 \ --data cluster0.cpu0="/"@0x82000000 \ --data cluster0.cpu0="/"@0x80080000 \ --data cluster0.cpu0="/"@0x84000000 Boot of a preloaded kernel image on Juno ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Trusted Firmware must be compiled in a similar way as for FVP explained above. The process to load binaries to memory is the one explained in `Booting an EL3 payload on Juno`_. .. _user_guide_run_fvp: Running the software on FVP --------------------------- The latest version of the AArch64 build of TF-A has been tested on the following Arm FVPs without shifted affinities, and that do not support threaded CPU cores (64-bit host machine only). .. note:: The FVP models used are Version 11.6 Build 45, unless otherwise stated. - ``FVP_Base_AEMv8A-AEMv8A`` - ``FVP_Base_AEMv8A-AEMv8A-AEMv8A-AEMv8A-CCN502`` - ``FVP_Base_RevC-2xAEMv8A`` - ``FVP_Base_Cortex-A32x4`` - ``FVP_Base_Cortex-A35x4`` - ``FVP_Base_Cortex-A53x4`` - ``FVP_Base_Cortex-A55x4+Cortex-A75x4`` - ``FVP_Base_Cortex-A55x4`` - ``FVP_Base_Cortex-A57x1-A53x1`` - ``FVP_Base_Cortex-A57x2-A53x4`` - ``FVP_Base_Cortex-A57x4-A53x4`` - ``FVP_Base_Cortex-A57x4`` - ``FVP_Base_Cortex-A72x4-A53x4`` - ``FVP_Base_Cortex-A72x4`` - ``FVP_Base_Cortex-A73x4-A53x4`` - ``FVP_Base_Cortex-A73x4`` - ``FVP_Base_Cortex-A75x4`` - ``FVP_Base_Cortex-A76x4`` - ``FVP_Base_Cortex-A76AEx4`` - ``FVP_Base_Cortex-A76AEx8`` - ``FVP_Base_Cortex-A77x4`` (Version 11.7 build 36) - ``FVP_Base_Neoverse-N1x4`` - ``FVP_Base_Zeusx4`` - ``FVP_CSS_SGI-575`` (Version 11.3 build 42) - ``FVP_CSS_SGM-775`` (Version 11.3 build 42) - ``FVP_RD_E1Edge`` (Version 11.3 build 42) - ``FVP_RD_N1Edge`` - ``Foundation_Platform`` The latest version of the AArch32 build of TF-A has been tested on the following Arm FVPs without shifted affinities, and that do not support threaded CPU cores (64-bit host machine only). - ``FVP_Base_AEMv8A-AEMv8A`` - ``FVP_Base_Cortex-A32x4`` .. note:: The ``FVP_Base_RevC-2xAEMv8A`` FVP only supports shifted affinities, which is not compatible with legacy GIC configurations. Therefore this FVP does not support these legacy GIC configurations. .. note:: The build numbers quoted above are those reported by launching the FVP with the ``--version`` parameter. .. note:: Linaro provides a ramdisk image in prebuilt FVP configurations and full file systems that can be downloaded separately. To run an FVP with a virtio file system image an additional FVP configuration option ``-C bp.virtioblockdevice.image_path="/`` can be used. .. note:: The software will not work on Version 1.0 of the Foundation FVP. The commands below would report an ``unhandled argument`` error in this case. .. note:: FVPs can be launched with ``--cadi-server`` option such that a CADI-compliant debugger (for example, Arm DS-5) can connect to and control its execution. .. warning:: Since FVP model Version 11.0 Build 11.0.34 and Version 8.5 Build 0.8.5202 the internal synchronisation timings changed compared to older versions of the models. The models can be launched with ``-Q 100`` option if they are required to match the run time characteristics of the older versions. The Foundation FVP is a cut down version of the AArch64 Base FVP. It can be downloaded for free from `Arm's website`_. The Cortex-A models listed above are also available to download from `Arm's website`_. Please refer to the FVP documentation for a detailed description of the model parameter options. A brief description of the important ones that affect TF-A and normal world software behavior is provided below. Obtaining the Flattened Device Trees ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Depending on the FVP configuration and Linux configuration used, different FDT files are required. FDT source files for the Foundation and Base FVPs can be found in the TF-A source directory under ``fdts/``. The Foundation FVP has a subset of the Base FVP components. For example, the Foundation FVP lacks CLCD and MMC support, and has only one CPU cluster. .. note:: It is not recommended to use the FDTs built along the kernel because not all FDTs are available from there. The dynamic configuration capability is enabled in the firmware for FVPs. This means that the firmware can authenticate and load the FDT if present in FIP. A default FDT is packaged into FIP during the build based on the build configuration. This can be overridden by using the ``FVP_HW_CONFIG`` or ``FVP_HW_CONFIG_DTS`` build options (refer to the `Arm FVP platform specific build options`_ section for detail on the options). - ``fvp-base-gicv2-psci.dts`` For use with models such as the Cortex-A57-A53 Base FVPs without shifted affinities and with Base memory map configuration. - ``fvp-base-gicv2-psci-aarch32.dts`` For use with models such as the Cortex-A32 Base FVPs without shifted affinities and running Linux in AArch32 state with Base memory map configuration. - ``fvp-base-gicv3-psci.dts`` For use with models such as the Cortex-A57-A53 Base FVPs without shifted affinities and with Base memory map configuration and Linux GICv3 support. - ``fvp-base-gicv3-psci-1t.dts`` For use with models such as the AEMv8-RevC Base FVP with shifted affinities, single threaded CPUs, Base memory map configuration and Linux GICv3 support. - ``fvp-base-gicv3-psci-dynamiq.dts`` For use with models as the Cortex-A55-A75 Base FVPs with shifted affinities, single cluster, single threaded CPUs, Base memory map configuration and Linux GICv3 support. - ``fvp-base-gicv3-psci-aarch32.dts`` For use with models such as the Cortex-A32 Base FVPs without shifted affinities and running Linux in AArch32 state with Base memory map configuration and Linux GICv3 support. - ``fvp-foundation-gicv2-psci.dts`` For use with Foundation FVP with Base memory map configuration. - ``fvp-foundation-gicv3-psci.dts`` (Default) For use with Foundation FVP with Base memory map configuration and Linux GICv3 support. Running on the Foundation FVP with reset to BL1 entrypoint ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following ``Foundation_Platform`` parameters should be used to boot Linux with 4 CPUs using the AArch64 build of TF-A. .. code:: shell /Foundation_Platform \ --cores=4 \ --arm-v8.0 \ --secure-memory \ --visualization \ --gicv3 \ --data="/"@0x0 \ --data="/"@0x08000000 \ --data="/"@0x80080000 \ --data="/"@0x84000000 Notes: - BL1 is loaded at the start of the Trusted ROM. - The Firmware Image Package is loaded at the start of NOR FLASH0. - The firmware loads the FDT packaged in FIP to the DRAM. The FDT load address is specified via the ``hw_config_addr`` property in ``TB_FW_CONFIG`` for FVP. - The default use-case for the Foundation FVP is to use the ``--gicv3`` option and enable the GICv3 device in the model. Note that without this option, the Foundation FVP defaults to legacy (Versatile Express) memory map which is not supported by TF-A. - In order for TF-A to run correctly on the Foundation FVP, the architecture versions must match. The Foundation FVP defaults to the highest v8.x version it supports but the default build for TF-A is for v8.0. To avoid issues either start the Foundation FVP to use v8.0 architecture using the ``--arm-v8.0`` option, or build TF-A with an appropriate value for ``ARM_ARCH_MINOR``. Running on the AEMv8 Base FVP with reset to BL1 entrypoint ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following ``FVP_Base_RevC-2xAEMv8A`` parameters should be used to boot Linux with 8 CPUs using the AArch64 build of TF-A. .. code:: shell /FVP_Base_RevC-2xAEMv8A \ -C pctl.startup=0.0.0.0 \ -C bp.secure_memory=1 \ -C bp.tzc_400.diagnostics=1 \ -C cluster0.NUM_CORES=4 \ -C cluster1.NUM_CORES=4 \ -C cache_state_modelled=1 \ -C bp.secureflashloader.fname="/" \ -C bp.flashloader0.fname="/" \ --data cluster0.cpu0="/"@0x80080000 \ --data cluster0.cpu0="/"@0x84000000 .. note:: The ``FVP_Base_RevC-2xAEMv8A`` has shifted affinities and requires a specific DTS for all the CPUs to be loaded. Running on the AEMv8 Base FVP (AArch32) with reset to BL1 entrypoint ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following ``FVP_Base_AEMv8A-AEMv8A`` parameters should be used to boot Linux with 8 CPUs using the AArch32 build of TF-A. .. code:: shell /FVP_Base_AEMv8A-AEMv8A \ -C pctl.startup=0.0.0.0 \ -C bp.secure_memory=1 \ -C bp.tzc_400.diagnostics=1 \ -C cluster0.NUM_CORES=4 \ -C cluster1.NUM_CORES=4 \ -C cache_state_modelled=1 \ -C cluster0.cpu0.CONFIG64=0 \ -C cluster0.cpu1.CONFIG64=0 \ -C cluster0.cpu2.CONFIG64=0 \ -C cluster0.cpu3.CONFIG64=0 \ -C cluster1.cpu0.CONFIG64=0 \ -C cluster1.cpu1.CONFIG64=0 \ -C cluster1.cpu2.CONFIG64=0 \ -C cluster1.cpu3.CONFIG64=0 \ -C bp.secureflashloader.fname="/" \ -C bp.flashloader0.fname="/" \ --data cluster0.cpu0="/"@0x80080000 \ --data cluster0.cpu0="/"@0x84000000 Running on the Cortex-A57-A53 Base FVP with reset to BL1 entrypoint ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following ``FVP_Base_Cortex-A57x4-A53x4`` model parameters should be used to boot Linux with 8 CPUs using the AArch64 build of TF-A. .. code:: shell /FVP_Base_Cortex-A57x4-A53x4 \ -C pctl.startup=0.0.0.0 \ -C bp.secure_memory=1 \ -C bp.tzc_400.diagnostics=1 \ -C cache_state_modelled=1 \ -C bp.secureflashloader.fname="/" \ -C bp.flashloader0.fname="/" \ --data cluster0.cpu0="/"@0x80080000 \ --data cluster0.cpu0="/"@0x84000000 Running on the Cortex-A32 Base FVP (AArch32) with reset to BL1 entrypoint ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following ``FVP_Base_Cortex-A32x4`` model parameters should be used to boot Linux with 4 CPUs using the AArch32 build of TF-A. .. code:: shell /FVP_Base_Cortex-A32x4 \ -C pctl.startup=0.0.0.0 \ -C bp.secure_memory=1 \ -C bp.tzc_400.diagnostics=1 \ -C cache_state_modelled=1 \ -C bp.secureflashloader.fname="/" \ -C bp.flashloader0.fname="/" \ --data cluster0.cpu0="/"@0x80080000 \ --data cluster0.cpu0="/"@0x84000000 Running on the AEMv8 Base FVP with reset to BL31 entrypoint ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following ``FVP_Base_RevC-2xAEMv8A`` parameters should be used to boot Linux with 8 CPUs using the AArch64 build of TF-A. .. code:: shell /FVP_Base_RevC-2xAEMv8A \ -C pctl.startup=0.0.0.0 \ -C bp.secure_memory=1 \ -C bp.tzc_400.diagnostics=1 \ -C cluster0.NUM_CORES=4 \ -C cluster1.NUM_CORES=4 \ -C cache_state_modelled=1 \ -C cluster0.cpu0.RVBAR=0x04010000 \ -C cluster0.cpu1.RVBAR=0x04010000 \ -C cluster0.cpu2.RVBAR=0x04010000 \ -C cluster0.cpu3.RVBAR=0x04010000 \ -C cluster1.cpu0.RVBAR=0x04010000 \ -C cluster1.cpu1.RVBAR=0x04010000 \ -C cluster1.cpu2.RVBAR=0x04010000 \ -C cluster1.cpu3.RVBAR=0x04010000 \ --data cluster0.cpu0="/"@0x04010000 \ --data cluster0.cpu0="/"@0xff000000 \ --data cluster0.cpu0="/"@0x88000000 \ --data cluster0.cpu0="/"@0x82000000 \ --data cluster0.cpu0="/"@0x80080000 \ --data cluster0.cpu0="/"@0x84000000 Notes: - If Position Independent Executable (PIE) support is enabled for BL31 in this config, it can be loaded at any valid address for execution. - Since a FIP is not loaded when using BL31 as reset entrypoint, the ``--data=""@`` parameter is needed to load the individual bootloader images in memory. BL32 image is only needed if BL31 has been built to expect a Secure-EL1 Payload. For the same reason, the FDT needs to be compiled from the DT source and loaded via the ``--data cluster0.cpu0="/"@0x82000000`` parameter. - The ``FVP_Base_RevC-2xAEMv8A`` has shifted affinities and requires a specific DTS for all the CPUs to be loaded. - The ``-C cluster.cpu.RVBAR=@`` parameter, where X and Y are the cluster and CPU numbers respectively, is used to set the reset vector for each core. - Changing the default value of ``ARM_TSP_RAM_LOCATION`` will also require changing the value of ``--data=""@`` to the new value of ``BL32_BASE``. Running on the AEMv8 Base FVP (AArch32) with reset to SP_MIN entrypoint ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following ``FVP_Base_AEMv8A-AEMv8A`` parameters should be used to boot Linux with 8 CPUs using the AArch32 build of TF-A. .. code:: shell /FVP_Base_AEMv8A-AEMv8A \ -C pctl.startup=0.0.0.0 \ -C bp.secure_memory=1 \ -C bp.tzc_400.diagnostics=1 \ -C cluster0.NUM_CORES=4 \ -C cluster1.NUM_CORES=4 \ -C cache_state_modelled=1 \ -C cluster0.cpu0.CONFIG64=0 \ -C cluster0.cpu1.CONFIG64=0 \ -C cluster0.cpu2.CONFIG64=0 \ -C cluster0.cpu3.CONFIG64=0 \ -C cluster1.cpu0.CONFIG64=0 \ -C cluster1.cpu1.CONFIG64=0 \ -C cluster1.cpu2.CONFIG64=0 \ -C cluster1.cpu3.CONFIG64=0 \ -C cluster0.cpu0.RVBAR=0x04002000 \ -C cluster0.cpu1.RVBAR=0x04002000 \ -C cluster0.cpu2.RVBAR=0x04002000 \ -C cluster0.cpu3.RVBAR=0x04002000 \ -C cluster1.cpu0.RVBAR=0x04002000 \ -C cluster1.cpu1.RVBAR=0x04002000 \ -C cluster1.cpu2.RVBAR=0x04002000 \ -C cluster1.cpu3.RVBAR=0x04002000 \ --data cluster0.cpu0="/"@0x04002000 \ --data cluster0.cpu0="/"@0x88000000 \ --data cluster0.cpu0="/"@0x82000000 \ --data cluster0.cpu0="/"@0x80080000 \ --data cluster0.cpu0="/"@0x84000000 .. note:: The load address of ```` depends on the value ``BL32_BASE``. It should match the address programmed into the RVBAR register as well. Running on the Cortex-A57-A53 Base FVP with reset to BL31 entrypoint ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following ``FVP_Base_Cortex-A57x4-A53x4`` model parameters should be used to boot Linux with 8 CPUs using the AArch64 build of TF-A. .. code:: shell /FVP_Base_Cortex-A57x4-A53x4 \ -C pctl.startup=0.0.0.0 \ -C bp.secure_memory=1 \ -C bp.tzc_400.diagnostics=1 \ -C cache_state_modelled=1 \ -C cluster0.cpu0.RVBARADDR=0x04010000 \ -C cluster0.cpu1.RVBARADDR=0x04010000 \ -C cluster0.cpu2.RVBARADDR=0x04010000 \ -C cluster0.cpu3.RVBARADDR=0x04010000 \ -C cluster1.cpu0.RVBARADDR=0x04010000 \ -C cluster1.cpu1.RVBARADDR=0x04010000 \ -C cluster1.cpu2.RVBARADDR=0x04010000 \ -C cluster1.cpu3.RVBARADDR=0x04010000 \ --data cluster0.cpu0="/"@0x04010000 \ --data cluster0.cpu0="/"@0xff000000 \ --data cluster0.cpu0="/"@0x88000000 \ --data cluster0.cpu0="/"@0x82000000 \ --data cluster0.cpu0="/"@0x80080000 \ --data cluster0.cpu0="/"@0x84000000 Running on the Cortex-A32 Base FVP (AArch32) with reset to SP_MIN entrypoint ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following ``FVP_Base_Cortex-A32x4`` model parameters should be used to boot Linux with 4 CPUs using the AArch32 build of TF-A. .. code:: shell /FVP_Base_Cortex-A32x4 \ -C pctl.startup=0.0.0.0 \ -C bp.secure_memory=1 \ -C bp.tzc_400.diagnostics=1 \ -C cache_state_modelled=1 \ -C cluster0.cpu0.RVBARADDR=0x04002000 \ -C cluster0.cpu1.RVBARADDR=0x04002000 \ -C cluster0.cpu2.RVBARADDR=0x04002000 \ -C cluster0.cpu3.RVBARADDR=0x04002000 \ --data cluster0.cpu0="/"@0x04002000 \ --data cluster0.cpu0="/"@0x88000000 \ --data cluster0.cpu0="/"@0x82000000 \ --data cluster0.cpu0="/"@0x80080000 \ --data cluster0.cpu0="/"@0x84000000 Running the software on Juno ---------------------------- This version of TF-A has been tested on variants r0, r1 and r2 of Juno. To execute the software stack on Juno, installing the latest Arm Platforms software deliverables is recommended. Please install the deliverables by following the `Instructions for using Linaro's deliverables on Juno`_. Preparing TF-A images ~~~~~~~~~~~~~~~~~~~~~ After building TF-A, the files ``bl1.bin`` and ``fip.bin`` need copying to the ``SOFTWARE/`` directory of the Juno SD card. Other Juno software information ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Please visit the `Arm Platforms Portal`_ to get support and obtain any other Juno software information. Please also refer to the `Juno Getting Started Guide`_ to get more detailed information about the Juno Arm development platform and how to configure it. Testing SYSTEM SUSPEND on Juno ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The SYSTEM SUSPEND is a PSCI API which can be used to implement system suspend to RAM. For more details refer to section 5.16 of `PSCI`_. To test system suspend on Juno, at the linux shell prompt, issue the following command: .. code:: shell echo +10 > /sys/class/rtc/rtc0/wakealarm echo -n mem > /sys/power/state The Juno board should suspend to RAM and then wakeup after 10 seconds due to wakeup interrupt from RTC. -------------- *Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.* .. _Arm Developer page: https://developer.arm.com/open-source/gnu-toolchain/gnu-a/downloads .. _Linaro Release: http://releases.linaro.org/members/arm/platforms .. _Linaro Release 19.06: http://releases.linaro.org/members/arm/platforms/19.06 .. _Linaro instructions: https://git.linaro.org/landing-teams/working/arm/arm-reference-platforms.git/about .. _Arm Platforms User guide: https://git.linaro.org/landing-teams/working/arm/arm-reference-platforms.git/about/docs/user-guide.rst .. _Instructions for using Linaro's deliverables on Juno: https://community.arm.com/dev-platforms/w/docs/303/juno .. _Arm Platforms Portal: https://community.arm.com/dev-platforms/ .. _Development Studio 5 (DS-5): https://developer.arm.com/products/software-development-tools/ds-5-development-studio .. _arm-trusted-firmware-a project page: https://review.trustedfirmware.org/admin/projects/TF-A/trusted-firmware-a .. _`Linux Coding Style`: https://www.kernel.org/doc/html/latest/process/coding-style.html .. _Linux master tree: https://github.com/torvalds/linux/tree/master/ .. _Dia: https://wiki.gnome.org/Apps/Dia/Download .. _mbed TLS Repository: https://github.com/ARMmbed/mbedtls.git .. _mbed TLS Security Center: https://tls.mbed.org/security .. _Arm's website: `FVP models`_ .. _FVP models: https://developer.arm.com/products/system-design/fixed-virtual-platforms .. _Juno Getting Started Guide: http://infocenter.arm.com/help/topic/com.arm.doc.dui0928e/DUI0928E_juno_arm_development_platform_gsg.pdf .. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf trusted-firmware-a-2.2/docs/global_substitutions.txt000066400000000000000000000033751355360272700230710ustar00rootroot00000000000000.. |AArch32| replace:: :term:`AArch32` .. |AArch64| replace:: :term:`AArch64` .. |API| replace:: :term:`API` .. |CoT| replace:: :term:`CoT` .. |COT| replace:: :term:`COT` .. |CSS| replace:: :term:`CSS` .. |CVE| replace:: :term:`CVE` .. |DS-5| replace:: :term:`DS-5` .. |DT| replace:: :term:`DT` .. |EL| replace:: :term:`EL` .. |EHF| replace:: :term:`EHF` .. |FDT| replace:: :term:`FDT` .. |FIP| replace:: :term:`FIP` .. |FVP| replace:: :term:`FVP` .. |FWU| replace:: :term:`FWU` .. |GIC| replace:: :term:`GIC` .. |ISA| replace:: :term:`ISA` .. |Linaro| replace:: :term:`Linaro` .. |MMU| replace:: :term:`MMU` .. |MPAM| replace:: :term:`MPAM` .. |MPIDR| replace:: :term:`MPIDR` .. |OEN| replace:: :term:`OEN` .. |OP-TEE| replace:: :term:`OP-TEE` .. |OTE| replace:: :term:`OTE` .. |PDD| replace:: :term:`PDD` .. |PMF| replace:: :term:`PMF` .. |PSCI| replace:: :term:`PSCI` .. |RAS| replace:: :term:`RAS` .. |ROT| replace:: :term:`ROT` .. |SCMI| replace:: :term:`SCMI` .. |SCP| replace:: :term:`SCP` .. |SDEI| replace:: :term:`SDEI` .. |SDS| replace:: :term:`SDS` .. |SEA| replace:: :term:`SEA` .. |SiP| replace:: :term:`SiP` .. |SIP| replace:: :term:`SIP` .. |SMC| replace:: :term:`SMC` .. |SMCCC| replace:: :term:`SMCCC` .. |SoC| replace:: :term:`SoC` .. |SP| replace:: :term:`SP` .. |SPCI| replace:: :term:`SPCI` .. |SPD| replace:: :term:`SPD` .. |SPM| replace:: :term:`SPM` .. |SVE| replace:: :term:`SVE` .. |TBB| replace:: :term:`TBB` .. |TBBR| replace:: :term:`TBBR` .. |TEE| replace:: :term:`TEE` .. |TF-A| replace:: :term:`TF-A` .. |TF-M| replace:: :term:`TF-M` .. |TLB| replace:: :term:`TLB` .. |TLK| replace:: :term:`TLK` .. |TSP| replace:: :term:`TSP` .. |TZC| replace:: :term:`TZC` .. |UEFI| replace:: :term:`UEFI` .. |WDOG| replace:: :term:`WDOG` .. |XLAT| replace:: :term:`XLAT`trusted-firmware-a-2.2/docs/glossary.rst000066400000000000000000000056041355360272700204430ustar00rootroot00000000000000Glossary ======== This glossary provides definitions for terms and abbreviations used in the TF-A documentation. You can find additional definitions in the `Arm Glossary`_. .. glossary:: :sorted: AArch32 32-bit execution state of the ARMv8 ISA AArch64 64-bit execution state of the ARMv8 ISA API Application Programming Interface CoT COT Chain of Trust CSS Compute Sub-System CVE Common Vulnerabilities and Exposures. A CVE document is commonly used to describe a publicly-known security vulnerability. DS-5 Arm Development Studio 5 DT Device Tree EL Exception Level EHF Exception Handling Framework FDT Flattened Device Tree FIP Firmware Image Package FVP Fixed Virtual Platform FWU FirmWare Update GIC Generic Interrupt Controller ISA Instruction Set Architecture Linaro A collaborative engineering organization consolidating and optimizing open source software and tools for the Arm architecture. MMU Memory Management Unit MPAM Memory Partitioning And Monitoring. An optional Armv8.4 extension. MPIDR Multiprocessor Affinity Register OEN Owning Entity Number OP-TEE Open Portable Trusted Execution Environment. An example of a :term:`TEE` OTE Open-source Trusted Execution Environment PDD Platform Design Document PMF Performance Measurement Framework PSCI Power State Coordination Interface RAS Reliability, Availability, and Serviceability extensions. A mandatory extension for the Armv8.2 architecture and later. An optional extension to the base Armv8 architecture. ROT Root of Trust SCMI System Control and Management Interface SCP System Control Processor SDEI Software Delegated Exception Interface SDS Shared Data Storage SEA Synchronous External Abort SiP SIP Silicon Provider SMC Secure Monitor Call SMCCC :term:`SMC` Calling Convention SoC System on Chip SP Secure Partition SPCI Secure Partition Client Interface SPD Secure Payload Dispatcher SPM Secure Partition Manager SVE Scalable Vector Extension TBB Trusted Board Boot TBBR Trusted Board Boot Requirements TEE Trusted Execution Environment TF-A Trusted Firmware-A TF-M Trusted Firmware-M TLB Translation Lookaside Buffer TLK Trusted Little Kernel. A Trusted OS from NVIDIA. TSP Test Secure Payload TZC TrustZone Controller UEFI Unified Extensible Firmware Interface WDOG Watchdog XLAT Translation (abbr.). For example, "XLAT table". .. _`Arm Glossary`: https://developer.arm.com/support/arm-glossarytrusted-firmware-a-2.2/docs/index.rst000066400000000000000000000076601355360272700177130ustar00rootroot00000000000000Trusted Firmware-A Documentation ================================ .. toctree:: :maxdepth: 1 :hidden: Home about/index getting_started/index process/index components/index design/index plat/index perf/index security_advisories/index change-log glossary license Trusted Firmware-A (TF-A) provides a reference implementation of secure world software for `Armv7-A and Armv8-A`_, including a `Secure Monitor`_ executing at Exception Level 3 (EL3). It implements various Arm interface standards, such as: - The `Power State Coordination Interface (PSCI)`_ - `Trusted Board Boot Requirements CLIENT (TBBR-CLIENT)`_ - `SMC Calling Convention`_ - `System Control and Management Interface (SCMI)`_ - `Software Delegated Exception Interface (SDEI)`_ Where possible, the code is designed for reuse or porting to other Armv7-A and Armv8-A model and hardware platforms. This release provides a suitable starting point for productization of secure world boot and runtime firmware, in either the AArch32 or AArch64 execution states. Users are encouraged to do their own security validation, including penetration testing, on any secure world code derived from TF-A. In collaboration with interested parties, we will continue to enhance |TF-A| with reference implementations of Arm standards to benefit developers working with Armv7-A and Armv8-A TrustZone technology. Getting Started --------------- The |TF-A| documentation contains guidance for obtaining and building the software for existing, supported platforms, as well as supporting information for porting the software to a new platform. The **About** chapter gives a high-level overview of |TF-A| features as well as some information on the project and how it is organized. Refer to the documents in the **Getting Started** chapter for information about the prerequisites and requirements for building |TF-A|. The **Processes & Policies** chapter explains the project's release schedule and process, how security disclosures are handled, and the guidelines for contributing to the project (including the coding style). The **Components** chapter holds documents that explain specific components that make up the |TF-A| software, the :ref:`Exception Handling Framework`, for example. In the **System Design** chapter you will find documents that explain the design of portions of the software that involve more than one component, such as the :ref:`Trusted Board Boot` process. **Platform Ports** provides a list of the supported hardware and software-model platforms that are supported upstream in |TF-A|. Most of these platforms also have additional documentation that has been provided by the maintainers of the platform. The results of any performance evaluations are added to the **Performance & Testing** chapter. **Security Advisories** holds a list of documents relating to |CVE| entries that have previously been raised against the software. -------------- *Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.* .. _Armv7-A and Armv8-A: https://developer.arm.com/products/architecture/a-profile .. _Secure Monitor: http://www.arm.com/products/processors/technologies/trustzone/tee-smc.php .. _Power State Coordination Interface (PSCI): http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf .. _Trusted Board Boot Requirements CLIENT (TBBR-CLIENT): https://developer.arm.com/docs/den0006/latest/trusted-board-boot-requirements-client-tbbr-client-armv8-a .. _System Control and Management Interface (SCMI): http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/DEN0056A_System_Control_and_Management_Interface.pdf .. _Software Delegated Exception Interface (SDEI): http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf .. _SMC Calling Convention: http://infocenter.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf trusted-firmware-a-2.2/docs/license.rst000066400000000000000000000067271355360272700202310ustar00rootroot00000000000000License ======= The software is provided under a BSD-3-Clause license (below). Contributions to this project are accepted under the same license with developer sign-off as described in the :ref:`Contributor's Guide`. :: Copyright (c) [XXXX-]YYYY, . All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. - Neither the name of Arm nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SPDX Identifiers ---------------- Individual files contain the following tag instead of the full license text. :: SPDX-License-Identifier: BSD-3-Clause This enables machine processing of license information based on the SPDX License Identifiers that are here available: http://spdx.org/licenses/ Other Projects -------------- This project contains code from other projects as listed below. The original license text is included in those source files. - The libc source code is derived from `FreeBSD`_ and `SCC`_. FreeBSD uses various BSD licenses, including BSD-3-Clause and BSD-2-Clause. The SCC code is used under the BSD-3-Clause license with the author's permission. - The libfdt source code is disjunctively dual licensed (GPL-2.0+ OR BSD-2-Clause). It is used by this project under the terms of the BSD-2-Clause license. Any contributions to this code must be made under the terms of both licenses. - The LLVM compiler-rt source code is disjunctively dual licensed (NCSA OR MIT). It is used by this project under the terms of the NCSA license (also known as the University of Illinois/NCSA Open Source License), which is a permissive license compatible with BSD-3-Clause. Any contributions to this code must be made under the terms of both licenses. - The zlib source code is licensed under the Zlib license, which is a permissive license compatible with BSD-3-Clause. - Some STMicroelectronics platform source code is disjunctively dual licensed (GPL-2.0+ OR BSD-3-Clause). It is used by this project under the terms of the BSD-3-Clause license. Any contributions to this code must be made under the terms of both licenses. .. _FreeBSD: http://www.freebsd.org .. _SCC: http://www.simple-cc.org/ trusted-firmware-a-2.2/docs/perf/000077500000000000000000000000001355360272700167755ustar00rootroot00000000000000trusted-firmware-a-2.2/docs/perf/index.rst000066400000000000000000000002101355360272700206270ustar00rootroot00000000000000Performance & Testing ===================== .. toctree:: :maxdepth: 1 :caption: Contents :numbered: psci-performance-juno trusted-firmware-a-2.2/docs/perf/psci-performance-juno.rst000066400000000000000000000361171355360272700237450ustar00rootroot00000000000000PSCI Performance Measurements on Arm Juno Development Platform ============================================================== This document summarises the findings of performance measurements of key operations in the Trusted Firmware-A Power State Coordination Interface (PSCI) implementation, using the in-built Performance Measurement Framework (PMF) and runtime instrumentation timestamps. Method ------ We used the `Juno R1 platform`_ for these tests, which has 4 x Cortex-A53 and 2 x Cortex-A57 clusters running at the following frequencies: +-----------------+--------------------+ | Domain | Frequency (MHz) | +=================+====================+ | Cortex-A57 | 900 (nominal) | +-----------------+--------------------+ | Cortex-A53 | 650 (underdrive) | +-----------------+--------------------+ | AXI subsystem | 533 | +-----------------+--------------------+ Juno supports CPU, cluster and system power down states, corresponding to power levels 0, 1 and 2 respectively. It does not support any retention states. We used the upstream `TF master as of 31/01/2017`_, building the platform using the ``ENABLE_RUNTIME_INSTRUMENTATION`` option: .. code:: shell make PLAT=juno ENABLE_RUNTIME_INSTRUMENTATION=1 \ SCP_BL2= \ BL33= \ all fip When using the debug build of TF, there was no noticeable difference in the results. The tests are based on an ARM-internal test framework. The release build of this framework was used because the results in the debug build became skewed; the console output prevented some of the tests from executing in parallel. The tests consist of both parallel and sequential tests, which are broadly described as follows: - **Parallel Tests** This type of test powers on all the non-lead CPUs and brings them and the lead CPU to a common synchronization point. The lead CPU then initiates the test on all CPUs in parallel. - **Sequential Tests** This type of test powers on each non-lead CPU in sequence. The lead CPU initiates the test on a non-lead CPU then waits for the test to complete before proceeding to the next non-lead CPU. The lead CPU then executes the test on itself. In the results below, CPUs 0-3 refer to CPUs in the little cluster (A53) and CPUs 4-5 refer to CPUs in the big cluster (A57). In all cases CPU 4 is the lead CPU. ``PSCI_ENTRY`` refers to the time taken from entering the TF PSCI implementation to the point the hardware enters the low power state (WFI). Referring to the TF runtime instrumentation points, this corresponds to: ``(RT_INSTR_ENTER_HW_LOW_PWR - RT_INSTR_ENTER_PSCI)``. ``PSCI_EXIT`` refers to the time taken from the point the hardware exits the low power state to exiting the TF PSCI implementation. This corresponds to: ``(RT_INSTR_EXIT_PSCI - RT_INSTR_EXIT_HW_LOW_PWR)``. ``CFLUSH_OVERHEAD`` refers to the part of ``PSCI_ENTRY`` taken to flush the caches. This corresponds to: ``(RT_INSTR_EXIT_CFLUSH - RT_INSTR_ENTER_CFLUSH)``. Note there is very little variance observed in the values given (~1us), although the values for each CPU are sometimes interchanged, depending on the order in which locks are acquired. Also, there is very little variance observed between executing the tests sequentially in a single boot or rebooting between tests. Given that runtime instrumentation using PMF is invasive, there is a small (unquantified) overhead on the results. PMF uses the generic counter for timestamps, which runs at 50MHz on Juno. Results and Commentary ---------------------- ``CPU_SUSPEND`` to deepest power level on all CPUs in parallel ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-------+---------------------+--------------------+--------------------------+ | CPU | ``PSCI_ENTRY`` (us) | ``PSCI_EXIT`` (us) | ``CFLUSH_OVERHEAD`` (us) | +=======+=====================+====================+==========================+ | 0 | 27 | 20 | 5 | +-------+---------------------+--------------------+--------------------------+ | 1 | 114 | 86 | 5 | +-------+---------------------+--------------------+--------------------------+ | 2 | 202 | 58 | 5 | +-------+---------------------+--------------------+--------------------------+ | 3 | 375 | 29 | 94 | +-------+---------------------+--------------------+--------------------------+ | 4 | 20 | 22 | 6 | +-------+---------------------+--------------------+--------------------------+ | 5 | 290 | 18 | 206 | +-------+---------------------+--------------------+--------------------------+ A large variance in ``PSCI_ENTRY`` and ``PSCI_EXIT`` times across CPUs is observed due to TF PSCI lock contention. In the worst case, CPU 3 has to wait for the 3 other CPUs in the cluster (0-2) to complete ``PSCI_ENTRY`` and release the lock before proceeding. The ``CFLUSH_OVERHEAD`` times for CPUs 3 and 5 are higher because they are the last CPUs in their respective clusters to power down, therefore both the L1 and L2 caches are flushed. The ``CFLUSH_OVERHEAD`` time for CPU 5 is a lot larger than that for CPU 3 because the L2 cache size for the big cluster is lot larger (2MB) compared to the little cluster (1MB). ``CPU_SUSPEND`` to power level 0 on all CPUs in parallel ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-------+---------------------+--------------------+--------------------------+ | CPU | ``PSCI_ENTRY`` (us) | ``PSCI_EXIT`` (us) | ``CFLUSH_OVERHEAD`` (us) | +=======+=====================+====================+==========================+ | 0 | 116 | 14 | 8 | +-------+---------------------+--------------------+--------------------------+ | 1 | 204 | 14 | 8 | +-------+---------------------+--------------------+--------------------------+ | 2 | 287 | 13 | 8 | +-------+---------------------+--------------------+--------------------------+ | 3 | 376 | 13 | 9 | +-------+---------------------+--------------------+--------------------------+ | 4 | 29 | 15 | 7 | +-------+---------------------+--------------------+--------------------------+ | 5 | 21 | 15 | 8 | +-------+---------------------+--------------------+--------------------------+ There is no lock contention in TF generic code at power level 0 but the large variance in ``PSCI_ENTRY`` times across CPUs is due to lock contention in Juno platform code. The platform lock is used to mediate access to a single SCP communication channel. This is compounded by the SCP firmware waiting for each AP CPU to enter WFI before making the channel available to other CPUs, which effectively serializes the SCP power down commands from all CPUs. On platforms with a more efficient CPU power down mechanism, it should be possible to make the ``PSCI_ENTRY`` times smaller and consistent. The ``PSCI_EXIT`` times are consistent across all CPUs because TF does not require locks at power level 0. The ``CFLUSH_OVERHEAD`` times for all CPUs are small and consistent since only the cache associated with power level 0 is flushed (L1). ``CPU_SUSPEND`` to deepest power level on all CPUs in sequence ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-------+---------------------+--------------------+--------------------------+ | CPU | ``PSCI_ENTRY`` (us) | ``PSCI_EXIT`` (us) | ``CFLUSH_OVERHEAD`` (us) | +=======+=====================+====================+==========================+ | 0 | 114 | 20 | 94 | +-------+---------------------+--------------------+--------------------------+ | 1 | 114 | 20 | 94 | +-------+---------------------+--------------------+--------------------------+ | 2 | 114 | 20 | 94 | +-------+---------------------+--------------------+--------------------------+ | 3 | 114 | 20 | 94 | +-------+---------------------+--------------------+--------------------------+ | 4 | 195 | 22 | 180 | +-------+---------------------+--------------------+--------------------------+ | 5 | 21 | 17 | 6 | +-------+---------------------+--------------------+--------------------------+ The ``CFLUSH_OVERHEAD`` times for lead CPU 4 and all CPUs in the non-lead cluster are large because all other CPUs in the cluster are powered down during the test. The ``CPU_SUSPEND`` call powers down to the cluster level, requiring a flush of both L1 and L2 caches. The ``CFLUSH_OVERHEAD`` time for CPU 4 is a lot larger than those for the little CPUs because the L2 cache size for the big cluster is lot larger (2MB) compared to the little cluster (1MB). The ``PSCI_ENTRY`` and ``CFLUSH_OVERHEAD`` times for CPU 5 are low because lead CPU 4 continues to run while CPU 5 is suspended. Hence CPU 5 only powers down to level 0, which only requires L1 cache flush. ``CPU_SUSPEND`` to power level 0 on all CPUs in sequence ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-------+---------------------+--------------------+--------------------------+ | CPU | ``PSCI_ENTRY`` (us) | ``PSCI_EXIT`` (us) | ``CFLUSH_OVERHEAD`` (us) | +=======+=====================+====================+==========================+ | 0 | 22 | 14 | 5 | +-------+---------------------+--------------------+--------------------------+ | 1 | 22 | 14 | 5 | +-------+---------------------+--------------------+--------------------------+ | 2 | 21 | 14 | 5 | +-------+---------------------+--------------------+--------------------------+ | 3 | 22 | 14 | 5 | +-------+---------------------+--------------------+--------------------------+ | 4 | 17 | 14 | 6 | +-------+---------------------+--------------------+--------------------------+ | 5 | 18 | 15 | 6 | +-------+---------------------+--------------------+--------------------------+ Here the times are small and consistent since there is no contention and it is only necessary to flush the cache to power level 0 (L1). This is the best case scenario. The ``PSCI_ENTRY`` times for CPUs in the big cluster are slightly smaller than for the CPUs in little cluster due to greater CPU performance. The ``PSCI_EXIT`` times are generally lower than in the last test because the cluster remains powered on throughout the test and there is less code to execute on power on (for example, no need to enter CCI coherency) ``CPU_OFF`` on all non-lead CPUs in sequence then ``CPU_SUSPEND`` on lead CPU to deepest power level ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The test sequence here is as follows: 1. Call ``CPU_ON`` and ``CPU_OFF`` on each non-lead CPU in sequence. 2. Program wake up timer and suspend the lead CPU to the deepest power level. 3. Call ``CPU_ON`` on non-lead CPU to get the timestamps from each CPU. +-------+---------------------+--------------------+--------------------------+ | CPU | ``PSCI_ENTRY`` (us) | ``PSCI_EXIT`` (us) | ``CFLUSH_OVERHEAD`` (us) | +=======+=====================+====================+==========================+ | 0 | 110 | 28 | 93 | +-------+---------------------+--------------------+--------------------------+ | 1 | 110 | 28 | 93 | +-------+---------------------+--------------------+--------------------------+ | 2 | 110 | 28 | 93 | +-------+---------------------+--------------------+--------------------------+ | 3 | 111 | 28 | 93 | +-------+---------------------+--------------------+--------------------------+ | 4 | 195 | 22 | 181 | +-------+---------------------+--------------------+--------------------------+ | 5 | 20 | 23 | 6 | +-------+---------------------+--------------------+--------------------------+ The ``CFLUSH_OVERHEAD`` times for all little CPUs are large because all other CPUs in that cluster are powerered down during the test. The ``CPU_OFF`` call powers down to the cluster level, requiring a flush of both L1 and L2 caches. The ``PSCI_ENTRY`` and ``CFLUSH_OVERHEAD`` times for CPU 5 are small because lead CPU 4 is running and CPU 5 only powers down to level 0, which only requires an L1 cache flush. The ``CFLUSH_OVERHEAD`` time for CPU 4 is a lot larger than those for the little CPUs because the L2 cache size for the big cluster is lot larger (2MB) compared to the little cluster (1MB). The ``PSCI_EXIT`` times for CPUs in the big cluster are slightly smaller than for CPUs in the little cluster due to greater CPU performance. These times generally are greater than the ``PSCI_EXIT`` times in the ``CPU_SUSPEND`` tests because there is more code to execute in the "on finisher" compared to the "suspend finisher" (for example, GIC redistributor register programming). ``PSCI_VERSION`` on all CPUs in parallel ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Since very little code is associated with ``PSCI_VERSION``, this test approximates the round trip latency for handling a fast SMC at EL3 in TF. +-------+-------------------+ | CPU | TOTAL TIME (ns) | +=======+===================+ | 0 | 3020 | +-------+-------------------+ | 1 | 2940 | +-------+-------------------+ | 2 | 2980 | +-------+-------------------+ | 3 | 3060 | +-------+-------------------+ | 4 | 520 | +-------+-------------------+ | 5 | 720 | +-------+-------------------+ The times for the big CPUs are less than the little CPUs due to greater CPU performance. We suspect the time for lead CPU 4 is shorter than CPU 5 due to subtle cache effects, given that these measurements are at the nano-second level. -------------- *Copyright (c) 2019, Arm Limited and Contributors. All rights reserved.* .. _Juno R1 platform: https://www.arm.com/files/pdf/Juno_r1_ARM_Dev_datasheet.pdf .. _TF master as of 31/01/2017: https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/tree/?id=c38b36d trusted-firmware-a-2.2/docs/plat/000077500000000000000000000000001355360272700170015ustar00rootroot00000000000000trusted-firmware-a-2.2/docs/plat/allwinner.rst000066400000000000000000000030451355360272700215300ustar00rootroot00000000000000Allwinner ARMv8 SoCs ==================== Trusted Firmware-A (TF-A) implements the EL3 firmware layer for Allwinner SoCs with ARMv8 cores. Only BL31 is used to provide proper EL3 setup and PSCI runtime services. U-Boot's SPL acts as a loader, loading both BL31 and BL33 (typically U-Boot). Loading is done from SD card, eMMC or SPI flash, also via an USB debug interface (FEL). BL31 lives in SRAM A2, which is documented to be accessible from secure world only. Current limitations: - Missing PMIC support After building bl31.bin, the binary must be fed to the U-Boot build system to include it in the FIT image that the SPL loader will process. bl31.bin can be either copied (or sym-linked) into U-Boot's root directory, or the environment variable BL31 must contain the binary's path. See the respective `U-Boot documentation`_ for more details. To build for machines with an A64 or H5 SoC: .. code:: shell make CROSS_COMPILE=aarch64-linux-gnu- PLAT=sun50i_a64 DEBUG=1 bl31 To build for machines with an H6 SoC: .. code:: shell make CROSS_COMPILE=aarch64-linux-gnu- PLAT=sun50i_h6 DEBUG=1 bl31 .. _U-Boot documentation: http://git.denx.de/?p=u-boot.git;f=board/sunxi/README.sunxi64;hb=HEAD Trusted OS dispatcher --------------------- One can boot Trusted OS(OP-TEE OS, bl32 image) along side bl31 image on Allwinner A64. In order to include the 'opteed' dispatcher in the image, pass 'SPD=opteed' on the command line while compiling the bl31 image and make sure the loader (SPL) loads the Trusted OS binary to the beginning of DRAM (0x40000000). trusted-firmware-a-2.2/docs/plat/fvp_ve.rst000066400000000000000000000045021355360272700210210ustar00rootroot00000000000000Arm Versatile Express ===================== Versatile Express (VE) family development platform provides an ultra fast environment for prototyping Armv7 System-on-Chip designs. VE Fixed Virtual Platforms (FVP) are simulations of Versatile Express boards. The platform in Trusted Firmware-A has been verified with Arm Cortex-A5 and Cortex-A7 VE FVP's. This platform is tested on and only expected to work with single core models. Boot Sequence ------------- BL1 --> BL2 --> BL32(sp_min) --> BL33(u-boot) --> Linux kernel How to build ------------ Code Locations ~~~~~~~~~~~~~~ - `U-boot `__ - `Trusted Firmware-A `__ Build Procedure ~~~~~~~~~~~~~~~ - Obtain arm toolchain. The software stack has been verified with linaro 6.2 `arm-linux-gnueabihf `__. Set the CROSS_COMPILE environment variable to point to the toolchain folder. - Fetch and build u-boot. Make the .config file using the command: .. code:: shell make ARCH=arm vexpress_aemv8a_aarch32_config Make the u-boot binary for Cortex-A5 using the command: .. code:: shell make ARCH=arm SUPPORT_ARCH_TIMER=no Make the u-boot binary for Cortex-A7 using the command: .. code:: shell make ARCH=arm - Build TF-A: The make command for Cortex-A5 is: .. code:: shell make PLAT=fvp_ve ARCH=aarch32 ARM_ARCH_MAJOR=7 ARM_CORTEX_A5=yes \ AARCH32_SP=sp_min FVP_HW_CONFIG_DTS=fdts/fvp-ve-Cortex-A5x1.dts \ ARM_XLAT_TABLES_LIB_V1=1 BL33= all fip The make command for Cortex-A7 is: .. code:: shell make PLAT=fvp_ve ARCH=aarch32 ARM_ARCH_MAJOR=7 ARM_CORTEX_A7=yes \ AARCH32_SP=sp_min FVP_HW_CONFIG_DTS=fdts/fvp-ve-Cortex-A7x1.dts \ BL33= all fip Run Procedure ~~~~~~~~~~~~~ The following model parameters should be used to boot Linux using the build of Trusted Firmware-A made using the above make commands: .. code:: shell ./ \ -C motherboard.flashloader1.fname= \ --data cluster.cpu0=@0x80080000 \ --data cluster.cpu0=@0x84000000 trusted-firmware-a-2.2/docs/plat/hikey.rst000066400000000000000000000122261355360272700206470ustar00rootroot00000000000000HiKey ===== HiKey is one of 96boards. Hisilicon Kirin6220 processor is installed on HiKey. More information are listed in `link`_. How to build ------------ Code Locations ~~~~~~~~~~~~~~ - Trusted Firmware-A: `link `__ - OP-TEE `link `__ - edk2: `link `__ - OpenPlatformPkg: `link `__ - l-loader: `link `__ - uefi-tools: `link `__ - atf-fastboot: `link `__ Build Procedure ~~~~~~~~~~~~~~~ - Fetch all the above repositories into local host. Make all the repositories in the same ${BUILD\_PATH}. .. code:: shell git clone https://github.com/ARM-software/arm-trusted-firmware -b integration git clone https://github.com/OP-TEE/optee_os git clone https://github.com/96boards-hikey/edk2 -b testing/hikey960_v2.5 git clone https://github.com/96boards-hikey/OpenPlatformPkg -b testing/hikey960_v1.3.4 git clone https://github.com/96boards-hikey/l-loader -b testing/hikey960_v1.2 git clone https://git.linaro.org/uefi/uefi-tools git clone https://github.com/96boards-hikey/atf-fastboot - Create the symbol link to OpenPlatformPkg in edk2. .. code:: shell $cd ${BUILD_PATH}/edk2 $ln -sf ../OpenPlatformPkg - Prepare AARCH64 && AARCH32 toolchain. Prepare python. - If your hikey hardware is built by CircuitCo, update *uefi-tools/platform.config* first. *(optional)* **Uncomment the below sentence. Otherwise, UEFI can't output messages on serial console on hikey.** .. code:: shell BUILDFLAGS=-DSERIAL_BASE=0xF8015000 If your hikey hardware is built by LeMaker, nothing to do. - Build it as debug mode. Create your own build script file or you could refer to **build\_uefi.sh** in l-loader git repository. .. code:: shell BUILD_OPTION=DEBUG export AARCH64_TOOLCHAIN=GCC5 export UEFI_TOOLS_DIR=${BUILD_PATH}/uefi-tools export EDK2_DIR=${BUILD_PATH}/edk2 EDK2_OUTPUT_DIR=${EDK2_DIR}/Build/HiKey/${BUILD_OPTION}_${AARCH64_TOOLCHAIN} # Build fastboot for Trusted Firmware-A. It's used for recovery mode. cd ${BUILD_PATH}/atf-fastboot CROSS_COMPILE=aarch64-linux-gnu- make PLAT=hikey DEBUG=1 # Convert DEBUG/RELEASE to debug/release FASTBOOT_BUILD_OPTION=$(echo ${BUILD_OPTION} | tr '[A-Z]' '[a-z]') cd ${EDK2_DIR} # Build UEFI & Trusted Firmware-A ${UEFI_TOOLS_DIR}/uefi-build.sh -b ${BUILD_OPTION} -a ../arm-trusted-firmware -s ../optee_os hikey - Generate l-loader.bin and partition table for aosp. The eMMC capacity is either 8GB or 4GB. Just change "aosp-8g" to "linux-8g" for debian. .. code:: shell cd ${BUILD_PATH}/l-loader ln -sf ${EDK2_OUTPUT_DIR}/FV/bl1.bin ln -sf ${EDK2_OUTPUT_DIR}/FV/bl2.bin ln -sf ${BUILD_PATH}/atf-fastboot/build/hikey/${FASTBOOT_BUILD_OPTION}/bl1.bin fastboot.bin make hikey PTABLE_LST=aosp-8g Setup Console ------------- - Install ser2net. Use telnet as the console since UEFI fails to display Boot Manager GUI in minicom. **If you don't need Boot Manager GUI, just ignore this section.** .. code:: shell $sudo apt-get install ser2net - Configure ser2net. .. code:: shell $sudo vi /etc/ser2net.conf Append one line for serial-over-USB in below. *#ser2net.conf* .. code:: shell 2004:telnet:0:/dev/ttyUSB0:115200 8DATABITS NONE 1STOPBIT banner - Start ser2net .. code:: shell $sudo killall ser2net $sudo ser2net -u - Open the console. .. code:: shell $telnet localhost 2004 And you could open the console remotely, too. Flash images in recovery mode ----------------------------- - Make sure Pin3-Pin4 on J15 are connected for recovery mode. Then power on HiKey. - Remove the modemmanager package. This package may cause the idt tool failure. .. code:: shell $sudo apt-get purge modemmanager - Run the command to download recovery.bin into HiKey. .. code:: shell $sudo python hisi-idt.py -d /dev/ttyUSB1 --img1 recovery.bin - Update images. All aosp or debian images could be fetched from `link `__. .. code:: shell $sudo fastboot flash ptable prm_ptable.img $sudo fastboot flash loader l-loader.bin $sudo fastboot flash fastboot fip.bin $sudo fastboot flash boot boot.img $sudo fastboot flash cache cache.img $sudo fastboot flash system system.img $sudo fastboot flash userdata userdata.img Boot UEFI in normal mode ------------------------ - Make sure Pin3-Pin4 on J15 are open for normal boot mode. Then power on HiKey. - Reference `link `__ .. _link: https://www.96boards.org/documentation/consumer/hikey/ trusted-firmware-a-2.2/docs/plat/hikey960.rst000066400000000000000000000123311355360272700211030ustar00rootroot00000000000000HiKey960 ======== HiKey960 is one of 96boards. Hisilicon Hi3660 processor is installed on HiKey960. More information are listed in `link`_. How to build ------------ Code Locations ~~~~~~~~~~~~~~ - Trusted Firmware-A: `link `__ - OP-TEE: `link `__ - edk2: `link `__ - OpenPlatformPkg: `link `__ - l-loader: `link `__ - uefi-tools: `link `__ Build Procedure ~~~~~~~~~~~~~~~ - Fetch all the above 5 repositories into local host. Make all the repositories in the same ${BUILD\_PATH}. .. code:: shell git clone https://github.com/ARM-software/arm-trusted-firmware -b integration git clone https://github.com/OP-TEE/optee_os git clone https://github.com/96boards-hikey/edk2 -b testing/hikey960_v2.5 git clone https://github.com/96boards-hikey/OpenPlatformPkg -b testing/hikey960_v1.3.4 git clone https://github.com/96boards-hikey/l-loader -b testing/hikey960_v1.2 git clone https://git.linaro.org/uefi/uefi-tools - Create the symbol link to OpenPlatformPkg in edk2. .. code:: shell $cd ${BUILD_PATH}/edk2 $ln -sf ../OpenPlatformPkg - Prepare AARCH64 toolchain. - If your hikey960 hardware is v1, update *uefi-tools/platform.config* first. *(optional)* **Uncomment the below sentence. Otherwise, UEFI can't output messages on serial console on hikey960 v1.** .. code:: shell BUILDFLAGS=-DSERIAL_BASE=0xFDF05000 If your hikey960 hardware is v2 or newer, nothing to do. - Build it as debug mode. Create script file for build. .. code:: shell BUILD_OPTION=DEBUG export AARCH64_TOOLCHAIN=GCC5 export UEFI_TOOLS_DIR=${BUILD_PATH}/uefi-tools export EDK2_DIR=${BUILD_PATH}/edk2 EDK2_OUTPUT_DIR=${EDK2_DIR}/Build/HiKey960/${BUILD_OPTION}_${AARCH64_TOOLCHAIN} cd ${EDK2_DIR} # Build UEFI & Trusted Firmware-A ${UEFI_TOOLS_DIR}/uefi-build.sh -b ${BUILD_OPTION} -a ../arm-trusted-firmware -s ../optee_os hikey960 - Generate l-loader.bin and partition table. *Make sure that you're using the sgdisk in the l-loader directory.* .. code:: shell cd ${BUILD_PATH}/l-loader ln -sf ${EDK2_OUTPUT_DIR}/FV/bl1.bin ln -sf ${EDK2_OUTPUT_DIR}/FV/bl2.bin ln -sf ${EDK2_OUTPUT_DIR}/FV/fip.bin ln -sf ${EDK2_OUTPUT_DIR}/FV/BL33_AP_UEFI.fd make hikey960 Setup Console ------------- - Install ser2net. Use telnet as the console since UEFI will output window that fails to display in minicom. .. code:: shell $sudo apt-get install ser2net - Configure ser2net. .. code:: shell $sudo vi /etc/ser2net.conf Append one line for serial-over-USB in *#ser2net.conf* :: 2004:telnet:0:/dev/ttyUSB0:115200 8DATABITS NONE 1STOPBIT banner - Start ser2net .. code:: shell $sudo killall ser2net $sudo ser2net -u - Open the console. .. code:: shell $telnet localhost 2004 And you could open the console remotely, too. Boot UEFI in recovery mode -------------------------- - Fetch that are used in recovery mode. The code location is in below. `link `__ - Prepare recovery binary. .. code:: shell $cd tools-images-hikey960 $ln -sf ${BUILD_PATH}/l-loader/l-loader.bin $ln -sf ${BUILD_PATH}/l-loader/fip.bin $ln -sf ${BUILD_PATH}/l-loader/recovery.bin - Prepare config file. .. code:: shell $vi config # The content of config file ./sec_usb_xloader.img 0x00020000 ./sec_uce_boot.img 0x6A908000 ./recovery.bin 0x1AC00000 - Remove the modemmanager package. This package may causes hikey\_idt tool failure. .. code:: shell $sudo apt-get purge modemmanager - Run the command to download recovery.bin into HiKey960. .. code:: shell $sudo ./hikey_idt -c config -p /dev/ttyUSB1 - UEFI running in recovery mode. When prompt '.' is displayed on console, press hotkey 'f' in keyboard. Then Android fastboot app is running. The timeout of prompt '.' is 10 seconds. - Update images. .. code:: shell $sudo fastboot flash ptable prm_ptable.img $sudo fastboot flash xloader sec_xloader.img $sudo fastboot flash fastboot l-loader.bin $sudo fastboot flash fip fip.bin $sudo fastboot flash boot boot.img $sudo fastboot flash cache cache.img $sudo fastboot flash system system.img $sudo fastboot flash userdata userdata.img - Notice: UEFI could also boot kernel in recovery mode, but BL31 isn't loaded in recovery mode. Boot UEFI in normal mode ------------------------ - Make sure "Boot Mode" switch is OFF for normal boot mode. Then power on HiKey960. - Reference `link `__ .. _link: https://www.96boards.org/documentation/consumer/hikey/hikey960 trusted-firmware-a-2.2/docs/plat/imx8.rst000066400000000000000000000037051355360272700204250ustar00rootroot00000000000000NXP i.MX 8 Series ================= The i.MX 8 series of applications processors is a feature- and performance-scalable multi-core platform that includes single-, dual-, and quad-core families based on the Arm® Cortex® architecture—including combined Cortex-A72 + Cortex-A53, Cortex-A35, and Cortex-M4 based solutions for advanced graphics, imaging, machine vision, audio, voice, video, and safety-critical applications. The i.MX8QM is with 2 Cortex-A72 ARM core, 4 Cortex-A53 ARM core and 1 Cortex-M4 system controller. The i.MX8QX is with 4 Cortex-A35 ARM core and 1 Cortex-M4 system controller. The System Controller (SC) represents the evolution of centralized control for system-level resources on i.MX8. The heart of the system controller is a Cortex-M4 that executes system controller firmware. Boot Sequence ------------- Bootrom --> BL31 --> BL33(u-boot) --> Linux kernel How to build ------------ Build Procedure ~~~~~~~~~~~~~~~ - Prepare AARCH64 toolchain. - Build System Controller Firmware and u-boot firstly, and get binary images: scfw_tcm.bin and u-boot.bin - Build TF-A Build bl31: .. code:: shell CROSS_COMPILE=aarch64-linux-gnu- make PLAT= bl31 Target_SoC should be "imx8qm" for i.MX8QM SoC. Target_SoC should be "imx8qx" for i.MX8QX SoC. Deploy TF-A Images ~~~~~~~~~~~~~~~~~~ TF-A binary(bl31.bin), scfw_tcm.bin and u-boot.bin are combined together to generate a binary file called flash.bin, the imx-mkimage tool is used to generate flash.bin, and flash.bin needs to be flashed into SD card with certain offset for BOOT ROM. The system controller firmware, u-boot and imx-mkimage will be upstreamed soon, this doc will be updated once they are ready, and the link will be posted. .. _i.MX8: https://www.nxp.com/products/processors-and-microcontrollers/applications-processors/i.mx-applications-processors/i.mx-8-processors/i.mx-8-family-arm-cortex-a53-cortex-a72-virtualization-vision-3d-graphics-4k-video:i.MX8 trusted-firmware-a-2.2/docs/plat/imx8m.rst000066400000000000000000000024321355360272700205760ustar00rootroot00000000000000NXP i.MX 8M Series ================== The i.MX 8M family of applications processors based on Arm Corte-A53 and Cortex-M4 cores provide high-performance computing, power efficiency, enhanced system reliability and embedded security needed to drive the growth of fast-growing edge node computing, streaming multimedia, and machine learning applications. Boot Sequence ------------- Bootrom --> SPL --> BL31 --> BL33(u-boot) --> Linux kernel How to build ------------ Build Procedure ~~~~~~~~~~~~~~~ - Prepare AARCH64 toolchain. - Build spl and u-boot firstly, and get binary images: u-boot-spl.bin, u-boot-nodtb.bin and dtb for the target board. - Build TF-A Build bl31: .. code:: shell CROSS_COMPILE=aarch64-linux-gnu- make PLAT= bl31 Target_SoC should be "imx8mq" for i.MX8MQ SoC. Target_SoC should be "imx8mm" for i.MX8MM SoC. Deploy TF-A Images ~~~~~~~~~~~~~~~~~~ TF-A binary(bl31.bin), u-boot-spl.bin u-boot-nodtb.bin and dtb are combined together to generate a binary file called flash.bin, the imx-mkimage tool is used to generate flash.bin, and flash.bin needs to be flashed into SD card with certain offset for BOOT ROM. the u-boot and imx-mkimage will be upstreamed soon, this doc will be updated once they are ready, and the link will be posted. trusted-firmware-a-2.2/docs/plat/index.rst000066400000000000000000000070371355360272700206510ustar00rootroot00000000000000Platform Ports ============== .. toctree:: :maxdepth: 1 :caption: Contents :numbered: :hidden: allwinner meson-gxbb meson-gxl meson-g12a fvp_ve hikey hikey960 intel-agilex intel-stratix10 marvell/index mt8183 nvidia-tegra warp7 imx8 imx8m ls1043a poplar qemu qemu-sbsa rpi3 rpi4 rcar-gen3 rockchip socionext-uniphier synquacer stm32mp1 ti-k3 xilinx-versal xilinx-zynqmp This section provides a list of supported upstream *platform ports* and the documentation associated with them. The list of suported Arm |FVP| platforms is outlined in the following section. .. note:: In addition to the platforms ports listed within the table of contents, there are several additional platforms that are supported upstream but which do not currently have associated documentation: - Arm Juno Software Development Platform. Various |AArch32| and |AArch64| builds of this release have been tested on r0, r1 and r2 variants of the `Juno Arm Development Platform`_. - Arm Neoverse N1 System Development Platform (N1SDP) - Arm Neoverse Reference Design N1 Edge (RD-N1-Edge) FVP - Arm Neoverse Reference Design E1 Edge (RD-E1-Edge) FVP - Arm SGI-575 and SGM-775 - MediaTek MT6795 and MT8173 SoCs Fixed Virtual Platform (FVP) Support ------------------------------------ The latest version of the AArch64 build of TF-A has been tested on the following Arm FVPs without shifted affinities, and that do not support threaded CPU cores (64-bit host machine only). .. note:: The FVP models used are Version 11.6 Build 45, unless otherwise stated. - ``FVP_Base_AEMv8A-AEMv8A`` - ``FVP_Base_AEMv8A-AEMv8A-AEMv8A-AEMv8A-CCN502`` - ``FVP_Base_RevC-2xAEMv8A`` - ``FVP_Base_Cortex-A32x4`` - ``FVP_Base_Cortex-A35x4`` - ``FVP_Base_Cortex-A53x4`` - ``FVP_Base_Cortex-A55x4+Cortex-A75x4`` - ``FVP_Base_Cortex-A55x4`` - ``FVP_Base_Cortex-A57x1-A53x1`` - ``FVP_Base_Cortex-A57x2-A53x4`` - ``FVP_Base_Cortex-A57x4-A53x4`` - ``FVP_Base_Cortex-A57x4`` - ``FVP_Base_Cortex-A72x4-A53x4`` - ``FVP_Base_Cortex-A72x4`` - ``FVP_Base_Cortex-A73x4-A53x4`` - ``FVP_Base_Cortex-A73x4`` - ``FVP_Base_Cortex-A75x4`` - ``FVP_Base_Cortex-A76x4`` - ``FVP_Base_Cortex-A76AEx4`` (Tested with internal model) - ``FVP_Base_Cortex-A76AEx8`` (Tested with internal model) - ``FVP_Base_Cortex-A77x4`` (Version 11.7 build 36) - ``FVP_Base_Zeusx4`` - ``FVP_Base_Neoverse-N1x4`` (Tested with internal model) - ``FVP_CSS_SGI-575`` (Version 11.3 build 42) - ``FVP_CSS_SGM-775`` (Version 11.3 build 42) - ``FVP_RD_E1Edge`` (Version 11.3 build 42) - ``FVP_RD_N1Edge`` (Version 11.3 build 42) - ``Foundation_Platform`` The latest version of the AArch32 build of TF-A has been tested on the following Arm FVPs without shifted affinities, and that do not support threaded CPU cores (64-bit host machine only). - ``FVP_Base_AEMv8A-AEMv8A`` - ``FVP_Base_Cortex-A32x4`` .. note:: The ``FVP_Base_RevC-2xAEMv8A`` FVP only supports shifted affinities. The *Foundation* and *Base* FVPs can be downloaded free of charge. See the `Arm FVP website`_. All the above platforms have been tested with `Linaro Release 19.06`_. -------------- *Copyright (c) 2019, Arm Limited. All rights reserved.* .. _Juno Arm Development Platform: http://www.arm.com/products/tools/development-boards/versatile-express/juno-arm-development-platform.php .. _Arm FVP website: https://developer.arm.com/products/system-design/fixed-virtual-platforms .. _Linaro Release 19.06: http://releases.linaro.org/members/arm/platforms/19.06 trusted-firmware-a-2.2/docs/plat/intel-agilex.rst000066400000000000000000000043251355360272700221210ustar00rootroot00000000000000Intel Agilex SoCFPGA ======================== Agilex SoCFPGA is a FPGA with integrated quad-core 64-bit Arm Cortex A53 processor. Upon boot, Boot ROM loads bl2 into OCRAM. Bl2 subsequently initializes the hardware, then loads bl31 and bl33 (UEFI) into DDR and boots to bl33. :: Boot ROM --> Trusted Firmware-A --> UEFI How to build ------------ Code Locations ~~~~~~~~~~~~~~ - Trusted Firmware-A: `link `__ - UEFI (to be updated with new upstreamed UEFI): `link `__ Build Procedure ~~~~~~~~~~~~~~~ - Fetch all the above 2 repositories into local host. Make all the repositories in the same ${BUILD\_PATH}. - Prepare the AARCH64 toolchain. - Build UEFI using Agilex platform as configuration This will be updated to use an updated UEFI using the latest EDK2 source .. code:: bash make CROSS_COMPILE=aarch64-linux-gnu- device=agx - Build atf providing the previously generated UEFI as the BL33 image .. code:: bash make CROSS_COMPILE=aarch64-linux-gnu- bl2 fip PLAT=agilex BL33=PEI.ROM Install Procedure ~~~~~~~~~~~~~~~~~ - dd fip.bin to a A2 partition on the MMC drive to be booted in Agilex board. - Generate a SOF containing bl2 .. code:: bash aarch64-linux-gnu-objcopy -I binary -O ihex --change-addresses 0xffe00000 bl2.bin bl2.hex quartus_cpf --bootloader bl2.hex - Configure SOF to board .. code:: bash nios2-configure-sof Boot trace ---------- :: INFO: DDR: DRAM calibration success. INFO: ECC is disabled. NOTICE: BL2: v2.1(debug) NOTICE: BL2: Built INFO: BL2: Doing platform setup NOTICE: BL2: Booting BL31 INFO: Entry point address = 0xffe1c000 INFO: SPSR = 0x3cd NOTICE: BL31: v2.1(debug) NOTICE: BL31: Built INFO: ARM GICv2 driver initialized INFO: BL31: Initializing runtime services WARNING: BL31: cortex_a53 INFO: BL31: Preparing for EL3 exit to normal world INFO: Entry point address = 0x50000 INFO: SPSR = 0x3c9 trusted-firmware-a-2.2/docs/plat/intel-stratix10.rst000066400000000000000000000054621355360272700225120ustar00rootroot00000000000000Intel Stratix 10 SoCFPGA ======================== Stratix 10 SoCFPGA is a FPGA with integrated quad-core 64-bit Arm Cortex A53 processor. Upon boot, Boot ROM loads bl2 into OCRAM. Bl2 subsequently initializes the hardware, then loads bl31 and bl33 (UEFI) into DDR and boots to bl33. :: Boot ROM --> Trusted Firmware-A --> UEFI How to build ------------ Code Locations ~~~~~~~~~~~~~~ - Trusted Firmware-A: `link `__ - UEFI (to be updated with new upstreamed UEFI): `link `__ Build Procedure ~~~~~~~~~~~~~~~ - Fetch all the above 2 repositories into local host. Make all the repositories in the same ${BUILD\_PATH}. - Prepare the AARCH64 toolchain. - Build UEFI using Stratix 10 platform as configuration This will be updated to use an updated UEFI using the latest EDK2 source .. code:: bash make CROSS_COMPILE=aarch64-linux-gnu- device=s10 - Build atf providing the previously generated UEFI as the BL33 image .. code:: bash make CROSS_COMPILE=aarch64-linux-gnu- bl2 fip PLAT=stratix10 BL33=PEI.ROM Install Procedure ~~~~~~~~~~~~~~~~~ - dd fip.bin to a A2 partition on the MMC drive to be booted in Stratix 10 board. - Generate a SOF containing bl2 .. code:: bash aarch64-linux-gnu-objcopy -I binary -O ihex --change-addresses 0xffe00000 bl2.bin bl2.hex quartus_cpf --bootloader bl2.hex - Configure SOF to board .. code:: bash nios2-configure-sof Boot trace ---------- :: INFO: DDR: DRAM calibration success. INFO: ECC is disabled. INFO: Init HPS NOC's DDR Scheduler. NOTICE: BL2: v2.0(debug):v2.0-809-g7f8474a-dirty NOTICE: BL2: Built : 17:38:19, Feb 18 2019 INFO: BL2: Doing platform setup INFO: BL2: Loading image id 3 INFO: Loading image id=3 at address 0xffe1c000 INFO: Image id=3 loaded: 0xffe1c000 - 0xffe24034 INFO: BL2: Loading image id 5 INFO: Loading image id=5 at address 0x50000 INFO: Image id=5 loaded: 0x50000 - 0x550000 NOTICE: BL2: Booting BL31 INFO: Entry point address = 0xffe1c000 INFO: SPSR = 0x3cd NOTICE: BL31: v2.0(debug):v2.0-810-g788c436-dirty NOTICE: BL31: Built : 15:17:16, Feb 20 2019 INFO: ARM GICv2 driver initialized INFO: BL31: Initializing runtime services WARNING: BL31: cortex_a53: CPU workaround for 855873 was missing! INFO: BL31: Preparing for EL3 exit to normal world INFO: Entry point address = 0x50000 INFO: SPSR = 0x3c9 UEFI firmware (version 1.0 built at 11:26:18 on Nov 7 2018) trusted-firmware-a-2.2/docs/plat/ls1043a.rst000066400000000000000000000046651355360272700206350ustar00rootroot00000000000000NXP QorIQ® LS1043A ================== The QorIQ® LS1043A processor is NXP's first quad-core, 64-bit Arm®-based processor for embedded networking. The LS1023A (two core version) and the LS1043A (four core version) deliver greater than 10 Gbps of performance in a flexible I/O package supporting fanless designs. This SoC is a purpose-built solution for small-form-factor networking and industrial applications with BOM optimizations for economic low layer PCB, lower cost power supply and single clock design. The new 0.9V versions of the LS1043A and LS1023A deliver addition power savings for applications such as Wireless LAN and to Power over Ethernet systems. LS1043ARDB Specification: ------------------------- Memory subsystem: * 2GByte DDR4 SDRAM (32bit bus) * 128 Mbyte NOR flash single-chip memory * 512 Mbyte NAND flash * 16 Mbyte high-speed SPI flash * SD connector to interface with the SD memory card Ethernet: * XFI 10G port * QSGMII with 4x 1G ports * Two RGMII ports PCIe: * PCIe2 (Lanes C) to mini-PCIe slot * PCIe3 (Lanes D) to PCIe slot USB 3.0: two super speed USB 3.0 type A ports UART: supports two UARTs up to 115200 bps for console More information are listed in `ls1043`_. Boot Sequence ------------- Bootrom --> TF-A BL1 --> TF-A BL2 --> TF-A BL1 --> TF-A BL31 --> BL32(Tee OS) --> TF-A BL31 --> BL33(u-boot) --> Linux kernel How to build ------------ Build Procedure ~~~~~~~~~~~~~~~ - Prepare AARCH64 toolchain. - Build u-boot and OPTee firstly, and get binary images: u-boot.bin and tee.bin - Build TF-A for Nor boot Build bl1: .. code:: shell CROSS_COMPILE=aarch64-linux-gnu- make PLAT=ls1043 bl1 Build fip: .. code:: shell CROSS_COMPILE=aarch64-linux-gnu- make PLAT=ls1043 fip \ BL33=u-boot.bin NEED_BL32=yes BL32=tee.bin SPD=opteed Deploy TF-A Images ~~~~~~~~~~~~~~~~~~ - Deploy TF-A images on Nor flash Alt Bank. .. code:: shell => tftp 82000000 bl1.bin => pro off all;era 64100000 +$filesize;cp.b 82000000 64100000 $filesize => tftp 82000000 fip.bin => pro off all;era 64120000 +$filesize;cp.b 82000000 64120000 $filesize Then change to Alt bank and boot up TF-A: .. code:: shell => cpld reset altbank .. _ls1043: https://www.nxp.com/products/processors-and-microcontrollers/arm-based-processors-and-mcus/qoriq-layerscape-arm-processors/qoriq-layerscape-1043a-and-1023a-multicore-communications-processors:LS1043A?lang_cd=en trusted-firmware-a-2.2/docs/plat/marvell/000077500000000000000000000000001355360272700204435ustar00rootroot00000000000000trusted-firmware-a-2.2/docs/plat/marvell/build.rst000066400000000000000000000211331355360272700222740ustar00rootroot00000000000000TF-A Build Instructions for Marvell Platforms ============================================= This section describes how to compile the Trusted Firmware-A (TF-A) project for Marvell's platforms. Build Instructions ------------------ (1) Set the cross compiler .. code:: shell > export CROSS_COMPILE=/path/to/toolchain/aarch64-linux-gnu- (2) Set path for FIP images: Set U-Boot image path (relatively to TF-A root or absolute path) .. code:: shell > export BL33=path/to/u-boot.bin For example: if U-Boot project (and its images) is located at ``~/project/u-boot``, BL33 should be ``~/project/u-boot/u-boot.bin`` .. note:: *u-boot.bin* should be used and not *u-boot-spl.bin* Set MSS/SCP image path (mandatory only for Armada80x0) .. code:: shell > export SCP_BL2=path/to/mrvl_scp_bl2*.img (3) Armada-37x0 build requires WTP tools installation. See below in the section "Tools and external components installation". Install ARM 32-bit cross compiler, which is required for building WTMI image for CM3 .. code:: shell > sudo apt-get install gcc-arm-linux-gnueabi (4) Clean previous build residuals (if any) .. code:: shell > make distclean (5) Build TF-A There are several build options: - DEBUG Default is without debug information (=0). in order to enable it use ``DEBUG=1``. Must be disabled when building UART recovery images due to current console driver implementation that is not compatible with Xmodem protocol used for boot image download. - LOG_LEVEL Defines the level of logging which will be purged to the default output port. LOG_LEVEL_NONE 0 LOG_LEVEL_ERROR 10 LOG_LEVEL_NOTICE 20 LOG_LEVEL_WARNING 30 LOG_LEVEL_INFO 40 LOG_LEVEL_VERBOSE 50 - USE_COHERENT_MEM This flag determines whether to include the coherent memory region in the BL memory map or not. - LLC_ENABLE Flag defining the LLC (L3) cache state. The cache is enabled by default (``LLC_ENABLE=1``). - MARVELL_SECURE_BOOT Build trusted(=1)/non trusted(=0) image, default is non trusted. - BLE_PATH Points to BLE (Binary ROM extension) sources folder. Only required for A8K builds. The parameter is optional, its default value is ``plat/marvell/a8k/common/ble``. - MV_DDR_PATH For A7/8K, use this parameter to point to mv_ddr driver sources to allow BLE build. For A37x0, it is used for ddr_tool build. Usage example: MV_DDR_PATH=path/to/mv_ddr The parameter is optional for A7/8K, when this parameter is not set, the mv_ddr sources are expected to be located at: drivers/marvell/mv_ddr. However, the parameter is necessary for A37x0. For the mv_ddr source location, check the section "Tools and external components installation" - DDR_TOPOLOGY For Armada37x0 only, the DDR topology map index/name, default is 0. Supported Options: - DDR3 1CS (0): DB-88F3720-DDR3-Modular (512MB); EspressoBIN (512MB) - DDR4 1CS (1): DB-88F3720-DDR4-Modular (512MB) - DDR3 2CS (2): EspressoBIN V3-V5 (1GB) - DDR4 2CS (3): DB-88F3720-DDR4-Modular (4GB) - DDR3 1CS (4): DB-88F3720-DDR3-Modular (1GB) - DDR4 1CS (5): EspressoBin V7 (1GB) - DDR4 2CS (6): EspressoBin V7 (2GB) - CUSTOMER (CUST): Customer board, DDR3 1CS 512MB - CLOCKSPRESET For Armada37x0 only, the clock tree configuration preset including CPU and DDR frequency, default is CPU_800_DDR_800. - CPU_600_DDR_600 - CPU at 600 MHz, DDR at 600 MHz - CPU_800_DDR_800 - CPU at 800 MHz, DDR at 800 MHz - CPU_1000_DDR_800 - CPU at 1000 MHz, DDR at 800 MHz - CPU_1200_DDR_750 - CPU at 1200 MHz, DDR at 750 MHz - BOOTDEV For Armada37x0 only, the flash boot device, default is ``SPINOR``. Currently, Armada37x0 only supports ``SPINOR``, ``SPINAND``, ``EMMCNORM`` and ``SATA``: - SPINOR - SPI NOR flash boot - SPINAND - SPI NAND flash boot - EMMCNORM - eMMC Download Mode Download boot loader or program code from eMMC flash into CM3 or CA53 Requires full initialization and command sequence - SATA - SATA device boot - PARTNUM For Armada37x0 only, the boot partition number, default is 0. To boot from eMMC, the value should be aligned with the parameter in U-Boot with name of ``CONFIG_SYS_MMC_ENV_PART``, whose value by default is 1. For details about CONFIG_SYS_MMC_ENV_PART, please refer to the U-Boot build instructions. - WTMI_IMG For Armada37x0 only, the path of the WTMI image can point to an image which does nothing, an image which supports EFUSE or a customized CM3 firmware binary. The default image is wtmi.bin that built from sources in WTP folder, which is the next option. If the default image is OK, then this option should be skipped. - WTP For Armada37x0 only, use this parameter to point to wtptools source code directory, which can be found as a3700_utils.zip in the release. Usage example: ``WTP=/path/to/a3700_utils`` For example, in order to build the image in debug mode with log level up to 'notice' level run .. code:: shell > make DEBUG=1 USE_COHERENT_MEM=0 LOG_LEVEL=20 PLAT= all fip And if we want to build a Armada37x0 image in debug mode with log level up to 'notice' level, the image has the preset CPU at 1000 MHz, preset DDR3 at 800 MHz, the DDR topology of DDR4 2CS, the image boot from SPI NOR flash partition 0, and the image is non trusted in WTP, the command line is as following .. code:: shell > make DEBUG=1 USE_COHERENT_MEM=0 LOG_LEVEL=20 CLOCKSPRESET=CPU_1000_DDR_800 \ MARVELL_SECURE_BOOT=0 DDR_TOPOLOGY=3 BOOTDEV=SPINOR PARTNUM=0 PLAT=a3700 all fip Supported MARVELL_PLATFORM are: - a3700 (for both A3720 DB and EspressoBin) - a70x0 - a70x0_amc (for AMC board) - a80x0 - a80x0_mcbin (for MacciatoBin) Special Build Flags -------------------- - PLAT_RECOVERY_IMAGE_ENABLE When set this option to enable secondary recovery function when build atf. In order to build UART recovery image this operation should be disabled for a70x0 and a80x0 because of hardware limitation (boot from secondary image can interrupt UART recovery process). This MACRO definition is set in ``plat/marvell/a8k/common/include/platform_def.h`` file. For more information about build options, please refer to section 'Summary of build options' in the :ref:`User Guide`. Build output ------------ Marvell's TF-A compilation generates 7 files: - ble.bin - BLe image - bl1.bin - BL1 image - bl2.bin - BL2 image - bl31.bin - BL31 image - fip.bin - FIP image (contains BL2, BL31 & BL33 (U-Boot) images) - boot-image.bin - TF-A image (contains BL1 and FIP images) - flash-image.bin - Image which contains boot-image.bin and SPL image. Should be placed on the boot flash/device. Tools and external components installation ------------------------------------------ Armada37x0 Builds require installation of 3 components ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (1) ARM cross compiler capable of building images for the service CPU (CM3). This component is usually included in the Linux host packages. On Debian/Ubuntu hosts the default GNU ARM tool chain can be installed using the following command .. code:: shell > sudo apt-get install gcc-arm-linux-gnueabi Only if required, the default tool chain prefix ``arm-linux-gnueabi-`` can be overwritten using the environment variable ``CROSS_CM3``. Example for BASH shell .. code:: shell > export CROSS_CM3=/opt/arm-cross/bin/arm-linux-gnueabi (2) DDR initialization library sources (mv_ddr) available at the following repository (use the "mv_ddr-armada-atf-mainline" branch): https://github.com/MarvellEmbeddedProcessors/mv-ddr-marvell.git (3) Armada3700 tools available at the following repository (use the latest release branch): https://github.com/MarvellEmbeddedProcessors/A3700-utils-marvell.git Armada70x0 and Armada80x0 Builds require installation of an additional component ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ (1) DDR initialization library sources (mv_ddr) available at the following repository (use the "mv_ddr-armada-atf-mainline" branch): https://github.com/MarvellEmbeddedProcessors/mv-ddr-marvell.git trusted-firmware-a-2.2/docs/plat/marvell/index.rst000066400000000000000000000002771355360272700223120ustar00rootroot00000000000000Marvell ======= .. toctree:: :maxdepth: 1 :caption: Contents build porting misc/mvebu-a8k-addr-map misc/mvebu-amb misc/mvebu-ccu misc/mvebu-io-win misc/mvebu-iob trusted-firmware-a-2.2/docs/plat/marvell/misc/000077500000000000000000000000001355360272700213765ustar00rootroot00000000000000trusted-firmware-a-2.2/docs/plat/marvell/misc/mvebu-a8k-addr-map.rst000066400000000000000000000111411355360272700254100ustar00rootroot00000000000000Address decoding flow and address translation units of Marvell Armada 8K SoC family =================================================================================== :: +--------------------------------------------------------------------------------------------------+ | +-------------+ +--------------+ | | | Memory +----- DRAM CS | | |+------------+ +-----------+ +-----------+ | Controller | +--------------+ | || AP DMA | | | | | +-------------+ | || SD/eMMC | | CA72 CPUs | | AP MSS | +-------------+ | || MCI-0/1 | | | | | | Memory | | |+------+-----+ +--+--------+ +--------+--+ +------------+ | Controller | +-------------+ | | | | | | +----- Translaton | |AP | | | | | | | | +-------------+ |Configuration| | | | | +-----+ +-------------------------Space | | | | | +-------------+ | CCU | +-------------+ | | | | | MMU +---------+ Windows | +-----------+ +-------------+ | | | +-| translation | | Lookup +---- +--------- AP SPI | | | | +-------------+ | | | | +-------------+ | | | +-------------+ | | | IO | +-------------+ | | +------------| SMMU +---------+ | | Windows +--------- AP MCI0/1 | | | | translation | +------------+ | Lookup | +-------------+ | | +---------+---+ | | +-------------+ | | - | | +--------- AP STM | | | +----------------- | | +-------------+ | | AP | | +-+---------+ | +---------------------------------------------------------------|----------------------------------+ +-------------|-------------------------------------------------|----------------------------------+ | CP | +-------------+ +------+-----+ +-------------------+ | | | | | | +------- SB CFG Space | | | | | DIOB | | | +-------------------+ | | | | Windows ----------------- IOB | +-------------------+ | | | | Control | | Windows +------| SB PCIe-0 - PCIe2 | | | | | | | Lookup | +-------------------+ | | | +------+------+ | | +-------------------+ | | | | | +------+ SB NAND | | | | | +------+-----+ +-------------------+ | | | | | | | | | | | | +------------------+ +------------+ +------+-----+ +-------------------+ | | | Network Engine | | | | +------- SB SPI-0/SPI-1 | | | | Security Engine | | PCIe, MSS | | RUNIT | +-------------------+ | | | SATA, USB | | DMA | | Windows | +-------------------+ | | | SD/eMMC | | | | Lookup +------- SB Device Bus | | | | TDM, I2C | | | | | +-------------------+ | | +------------------+ +------------+ +------------+ | | | +--------------------------------------------------------------------------------------------------+ trusted-firmware-a-2.2/docs/plat/marvell/misc/mvebu-amb.rst000066400000000000000000000030601355360272700240020ustar00rootroot00000000000000AMB - AXI MBUS address decoding =============================== AXI to M-bridge decoding unit driver for Marvell Armada 8K and 8K+ SoCs. The Runit offers a second level of address windows lookup. It is used to map transaction towards the CD BootROM, SPI0, SPI1 and Device bus (NOR). The Runit contains eight configurable windows. Each window defines a contiguous, address space and the properties associated with that address space. :: Unit Bank ATTR Device-Bus DEV_BOOT_CS 0x2F DEV_CS0 0x3E DEV_CS1 0x3D DEV_CS2 0x3B DEV_CS3 0x37 SPI-0 SPI_A_CS0 0x1E SPI_A_CS1 0x5E SPI_A_CS2 0x9E SPI_A_CS3 0xDE SPI_A_CS4 0x1F SPI_A_CS5 0x5F SPI_A_CS6 0x9F SPI_A_CS7 0xDF SPI SPI_B_CS0 0x1A SPI_B_CS1 0x5A SPI_B_CS2 0x9A SPI_B_CS3 0xDA BOOT_ROM BOOT_ROM 0x1D UART UART 0x01 Mandatory functions ------------------- - marvell_get_amb_memory_map Returns the AMB windows configuration and the number of windows Mandatory structures -------------------- - amb_memory_map Array that include the configuration of the windows. Every window/entry is a struct which has 2 parameters: - Base address of the window - Attribute of the window Examples -------- .. code:: c struct addr_map_win amb_memory_map[] = { {0xf900, AMB_DEV_CS0_ID}, }; trusted-firmware-a-2.2/docs/plat/marvell/misc/mvebu-ccu.rst000066400000000000000000000015031355360272700240150ustar00rootroot00000000000000Marvell CCU address decoding bindings ===================================== CCU configration driver (1st stage address translation) for Marvell Armada 8K and 8K+ SoCs. The CCU node includes a description of the address decoding configuration. Mandatory functions ------------------- - marvell_get_ccu_memory_map Return the CCU windows configuration and the number of windows of the specific AP. Mandatory structures -------------------- - ccu_memory_map Array that includes the configuration of the windows. Every window/entry is a struct which has 3 parameters: - Base address of the window - Size of the window - Target-ID of the window Example ------- .. code:: c struct addr_map_win ccu_memory_map[] = { {0x00000000f2000000, 0x00000000e000000, IO_0_TID}, /* IO window */ }; trusted-firmware-a-2.2/docs/plat/marvell/misc/mvebu-io-win.rst000066400000000000000000000026211355360272700244470ustar00rootroot00000000000000Marvell IO WIN address decoding bindings ======================================== IO Window configration driver (2nd stage address translation) for Marvell Armada 8K and 8K+ SoCs. The IO WIN includes a description of the address decoding configuration. Transactions that are decoded by CCU windows as IO peripheral, have an additional layer of decoding. This additional address decoding layer defines one of the following targets: - **0x0** = BootRom - **0x1** = STM (Serial Trace Macro-cell, a programmer's port into trace stream) - **0x2** = SPI direct access - **0x3** = PCIe registers - **0x4** = MCI Port - **0x5** = PCIe port Mandatory functions ------------------- - marvell_get_io_win_memory_map Returns the IO windows configuration and the number of windows of the specific AP. Mandatory structures -------------------- - io_win_memory_map Array that include the configuration of the windows. Every window/entry is a struct which has 3 parameters: - Base address of the window - Size of the window - Target-ID of the window Example ------- .. code:: c struct addr_map_win io_win_memory_map[] = { {0x00000000fe000000, 0x000000001f00000, PCIE_PORT_TID}, /* PCIe window 31Mb for PCIe port*/ {0x00000000ffe00000, 0x000000000100000, PCIE_REGS_TID}, /* PCI-REG window 64Kb for PCIe-reg*/ {0x00000000f6000000, 0x000000000100000, MCIPHY_TID}, /* MCI window 1Mb for PHY-reg*/ }; trusted-firmware-a-2.2/docs/plat/marvell/misc/mvebu-iob.rst000066400000000000000000000030011355360272700240070ustar00rootroot00000000000000Marvell IOB address decoding bindings ===================================== IO bridge configration driver (3rd stage address translation) for Marvell Armada 8K and 8K+ SoCs. The IOB includes a description of the address decoding configuration. IOB supports up to n (in CP110 n=24) windows for external memory transaction. When a transaction passes through the IOB, its address is compared to each of the enabled windows. If there is a hit and it passes the security checks, it is advanced to the target port. Mandatory functions ------------------- - marvell_get_iob_memory_map Returns the IOB windows configuration and the number of windows Mandatory structures -------------------- - iob_memory_map Array that includes the configuration of the windows. Every window/entry is a struct which has 3 parameters: - Base address of the window - Size of the window - Target-ID of the window Target ID options ----------------- - **0x0** = Internal configuration space - **0x1** = MCI0 - **0x2** = PEX1_X1 - **0x3** = PEX2_X1 - **0x4** = PEX0_X4 - **0x5** = NAND flash - **0x6** = RUNIT (NOR/SPI/BootRoom) - **0x7** = MCI1 Example ------- .. code:: c struct addr_map_win iob_memory_map[] = { {0x00000000f7000000, 0x0000000001000000, PEX1_TID}, /* PEX1_X1 window */ {0x00000000f8000000, 0x0000000001000000, PEX2_TID}, /* PEX2_X1 window */ {0x00000000f6000000, 0x0000000001000000, PEX0_TID}, /* PEX0_X4 window */ {0x00000000f9000000, 0x0000000001000000, NAND_TID} /* NAND window */ }; trusted-firmware-a-2.2/docs/plat/marvell/porting.rst000066400000000000000000000143171355360272700226650ustar00rootroot00000000000000TF-A Porting Guide for Marvell Platforms ======================================== This section describes how to port TF-A to a customer board, assuming that the SoC being used is already supported in TF-A. Source Code Structure --------------------- - The customer platform specific code shall reside under ``plat/marvell//_cust`` (e.g. 'plat/marvell/a8k/a7040_cust'). - The platform name for build purposes is called ``_cust`` (e.g. ``a7040_cust``). - The build system will reuse all files from within the soc directory, and take only the porting files from the customer platform directory. Files that require porting are located at ``plat/marvell//_cust`` directory. Armada-70x0/Armada-80x0 Porting ------------------------------- SoC Physical Address Map (marvell_plat_config.c) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This file describes the SoC physical memory mapping to be used for the CCU, IOWIN, AXI-MBUS and IOB address decode units (Refer to the functional spec for more details). In most cases, using the default address decode windows should work OK. In cases where a special physical address map is needed (e.g. Special size for PCIe MEM windows, large memory mapped SPI flash...), then porting of the SoC memory map is required. .. note:: For a detailed information on how CCU, IOWIN, AXI-MBUS & IOB work, please refer to the SoC functional spec, and under ``docs/marvell/misc/mvebu-[ccu/iob/amb/io-win].txt`` files. boot loader recovery (marvell_plat_config.c) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Background: Boot rom can skip the current image and choose to boot from next position if a specific value (``0xDEADB002``) is returned by the ble main function. This feature is used for boot loader recovery by booting from a valid flash-image saved in next position on flash (e.g. address 2M in SPI flash). Supported options to implement the skip request are: - GPIO - I2C - User defined - Porting: Under marvell_plat_config.c, implement struct skip_image that includes specific board parameters. .. warning:: To disable this feature make sure the struct skip_image is not implemented. - Example: In A7040-DB specific implementation (``plat/marvell/a8k/a70x0/board/marvell_plat_config.c``), the image skip is implemented using GPIO: mpp 33 (SW5). Before resetting the board make sure there is a valid image on the next flash address: -tftp [valid address] flash-image.bin -sf update [valid address] 0x2000000 [size] Press reset and keep pressing the button connected to the chosen GPIO pin. A skip image request message is printed on the screen and boot rom boots from the saved image at the next position. DDR Porting (dram_port.c) ~~~~~~~~~~~~~~~~~~~~~~~~~ This file defines the dram topology and parameters of the target board. The DDR code is part of the BLE component, which is an extension of ARM Trusted Firmware (TF-A). The DDR driver called mv_ddr is released separately apart from TF-A sources. The BLE and consequently, the DDR init code is executed at the early stage of the boot process. Each supported platform of the TF-A has its own DDR porting file called dram_port.c located at ``atf/plat/marvell/a8k//board`` directory. Please refer to '/doc/porting_guide.txt' for detailed porting description. The build target directory is "build//release/ble". Comphy Porting (phy-porting-layer.h or phy-default-porting-layer.h) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Background: Some of the comphy's parameters value depend on the HW connection between the SoC and the PHY. Every board type has specific HW characteristics like wire length. Due to those differences some comphy parameters vary between board types. Therefore each board type can have its own list of values for all relevant comphy parameters. The PHY porting layer specifies which parameters need to be suited and the board designer should provide relevant values. .. seealso:: For XFI/SFI comphy type there is procedure "rx_training" which eases process of suiting some of the parameters. Please see *uboot_cmd* section: rx_training. The PHY porting layer simplifies updating static values per board type, which are now grouped in one place. .. note:: The parameters for the same type of comphy may vary even for the same board type, it is because the lanes from comphy-x to some PHY may have different HW characteristic than lanes from comphy-y to the same (multiplexed) or other PHY. - Porting: The porting layer for PHY was introduced in TF-A. There is one file ``drivers/marvell/comphy/phy-default-porting-layer.h`` which contains the defaults. Those default parameters are used only if there is no appropriate phy-porting-layer.h file under: ``plat/marvell///board/phy-porting-layer.h``. If the phy-porting-layer.h exists, the phy-default-porting-layer.h is not going to be included. .. warning:: Not all comphy types are already reworked to support the PHY porting layer, currently the porting layer is supported for XFI/SFI and SATA comphy types. The easiest way to prepare the PHY porting layer for custom board is to copy existing example to a new platform: - cp ``plat/marvell/a8k/a80x0/board/phy-porting-layer.h`` "plat/marvell///board/phy-porting-layer.h" - adjust relevant parameters or - if different comphy index is used for specific feature, move it to proper table entry and then adjust. .. note:: The final table size with comphy parameters can be different, depending on the CP module count for given SoC type. - Example: Example porting layer for armada-8040-db is under: ``plat/marvell/a8k/a80x0/board/phy-porting-layer.h`` .. note:: If there is no PHY porting layer for new platform (missing phy-porting-layer.h), the default values are used (drivers/marvell/comphy/phy-default-porting-layer.h) and the user is warned: .. warning:: "Using default comphy parameters - it may be required to suit them for your board". trusted-firmware-a-2.2/docs/plat/meson-g12a.rst000066400000000000000000000020011355360272700213750ustar00rootroot00000000000000Amlogic Meson S905X2 (G12A) =========================== The Amlogic Meson S905X2 is a SoC with a quad core Arm Cortex-A53 running at ~1.8GHz. It also contains a Cortex-M3 used as SCP. This port is a minimal implementation of BL31 capable of booting mainline U-Boot and Linux: - SCPI support. - Basic PSCI support (CPU_ON, CPU_OFF, SYSTEM_RESET, SYSTEM_OFF). Note that CPU0 can't be turned off, so there is a workaround to hide this from the caller. - GICv2 driver set up. - Basic SIP services (read efuse data, enable/disable JTAG). In order to build it: .. code:: shell CROSS_COMPILE=aarch64-linux-gnu- make DEBUG=1 PLAT=g12a This port has been tested on a SEI510 board. After building it, follow the instructions in the `gxlimg repository` or `U-Boot repository`_, replacing the mentioned **bl31.img** by the one built from this port. .. _gxlimg repository: https://github.com/repk/gxlimg/blob/master/README.g12a .. _U-Boot repository: https://github.com/u-boot/u-boot/blob/master/board/amlogic/sei510/README trusted-firmware-a-2.2/docs/plat/meson-gxbb.rst000066400000000000000000000016441355360272700216010ustar00rootroot00000000000000Amlogic Meson S905 (GXBB) ========================= The Amlogic Meson S905 is a SoC with a quad core Arm Cortex-A53 running at 1.5Ghz. It also contains a Cortex-M3 used as SCP. This port is a minimal implementation of BL31 capable of booting mainline U-Boot and Linux: - SCPI support. - Basic PSCI support (CPU_ON, CPU_OFF, SYSTEM_RESET, SYSTEM_OFF). Note that CPU0 can't be turned off, so there is a workaround to hide this from the caller. - GICv2 driver set up. - Basic SIP services (read efuse data, enable/disable JTAG). In order to build it: .. code:: shell CROSS_COMPILE=aarch64-linux-gnu- make DEBUG=1 PLAT=gxbb bl31 This port has been tested in a ODROID-C2. After building it, follow the instructions in the `U-Boot repository`_, replacing the mentioned **bl31.bin** by the one built from this port. .. _U-Boot repository: https://github.com/u-boot/u-boot/blob/master/board/amlogic/odroid-c2/README.odroid-c2 trusted-firmware-a-2.2/docs/plat/meson-gxl.rst000066400000000000000000000017741355360272700214550ustar00rootroot00000000000000Amlogic Meson S905x (GXL) ========================= The Amlogic Meson S905x is a SoC with a quad core Arm Cortex-A53 running at 1.5Ghz. It also contains a Cortex-M3 used as SCP. This port is a minimal implementation of BL31 capable of booting mainline U-Boot and Linux: - SCPI support. - Basic PSCI support (CPU_ON, CPU_OFF, SYSTEM_RESET, SYSTEM_OFF). Note that CPU0 can't be turned off, so there is a workaround to hide this from the caller. - GICv2 driver set up. - Basic SIP services (read efuse data, enable/disable JTAG). In order to build it: .. code:: shell CROSS_COMPILE=aarch64-linux-gnu- make DEBUG=1 PLAT=gxl This port has been tested on a Lepotato. After building it, follow the instructions in the `gxlimg repository` or `U-Boot repository`_, replacing the mentioned **bl31.img** by the one built from this port. .. _gxlimg repository: https://github.com/repk/gxlimg/blob/master/README .. _U-Boot repository: https://github.com/u-boot/u-boot/blob/master/board/amlogic/p212/README.libretech-cc trusted-firmware-a-2.2/docs/plat/mt8183.rst000066400000000000000000000006771355360272700205110ustar00rootroot00000000000000MediaTek 8183 ============= MediaTek 8183 (MT8183) is a 64-bit ARM SoC introduced by MediaTek in early 2018. The chip incorporates eight cores - four Cortex-A53 little cores and Cortex-A73. Both clusters can operate at up to 2 GHz. Boot Sequence ------------- :: Boot Rom --> Coreboot --> TF-A BL31 --> Depthcharge --> Linux Kernel How to Build ------------ .. code:: shell make CROSS_COMPILE=aarch64-linux-gnu- PLAT=mt8183 DEBUG=1 trusted-firmware-a-2.2/docs/plat/nvidia-tegra.rst000066400000000000000000000132441355360272700221110ustar00rootroot00000000000000NVIDIA Tegra ============ - .. rubric:: T186 :name: t186 The NVIDIA® Parker (T186) series system-on-chip (SoC) delivers a heterogeneous multi-processing (HMP) solution designed to optimize performance and efficiency. T186 has Dual NVIDIA Denver 2 ARM® CPU cores, plus Quad ARM Cortex®-A57 cores, in a coherent multiprocessor configuration. The Denver 2 and Cortex-A57 cores support ARMv8, executing both 64-bit Aarch64 code, and 32-bit Aarch32 code including legacy ARMv7 applications. The Denver 2 processors each have 128 KB Instruction and 64 KB Data Level 1 caches; and have a 2MB shared Level 2 unified cache. The Cortex-A57 processors each have 48 KB Instruction and 32 KB Data Level 1 caches; and also have a 2 MB shared Level 2 unified cache. A high speed coherency fabric connects these two processor complexes and allows heterogeneous multi-processing with all six cores if required. - .. rubric:: T210 :name: t210 T210 has Quad Arm® Cortex®-A57 cores in a switched configuration with a companion set of quad Arm Cortex-A53 cores. The Cortex-A57 and A53 cores support Armv8-A, executing both 64-bit Aarch64 code, and 32-bit Aarch32 code including legacy Armv7-A applications. The Cortex-A57 processors each have 48 KB Instruction and 32 KB Data Level 1 caches; and have a 2 MB shared Level 2 unified cache. The Cortex-A53 processors each have 32 KB Instruction and 32 KB Data Level 1 caches; and have a 512 KB shared Level 2 unified cache. - .. rubric:: T132 :name: t132 Denver is NVIDIA's own custom-designed, 64-bit, dual-core CPU which is fully Armv8-A architecture compatible. Each of the two Denver cores implements a 7-way superscalar microarchitecture (up to 7 concurrent micro-ops can be executed per clock), and includes a 128KB 4-way L1 instruction cache, a 64KB 4-way L1 data cache, and a 2MB 16-way L2 cache, which services both cores. Denver implements an innovative process called Dynamic Code Optimization, which optimizes frequently used software routines at runtime into dense, highly tuned microcode-equivalent routines. These are stored in a dedicated, 128MB main-memory-based optimization cache. After being read into the instruction cache, the optimized micro-ops are executed, re-fetched and executed from the instruction cache as long as needed and capacity allows. Effectively, this reduces the need to re-optimize the software routines. Instead of using hardware to extract the instruction-level parallelism (ILP) inherent in the code, Denver extracts the ILP once via software techniques, and then executes those routines repeatedly, thus amortizing the cost of ILP extraction over the many execution instances. Denver also features new low latency power-state transitions, in addition to extensive power-gating and dynamic voltage and clock scaling based on workloads. Directory structure ------------------- - plat/nvidia/tegra/common - Common code for all Tegra SoCs - plat/nvidia/tegra/soc/txxx - Chip specific code Trusted OS dispatcher --------------------- Tegra supports multiple Trusted OS'. - Trusted Little Kernel (TLK): In order to include the 'tlkd' dispatcher in the image, pass 'SPD=tlkd' on the command line while preparing a bl31 image. - Trusty: In order to include the 'trusty' dispatcher in the image, pass 'SPD=trusty' on the command line while preparing a bl31 image. This allows other Trusted OS vendors to use the upstream code and include their dispatchers in the image without changing any makefiles. These are the supported Trusted OS' by Tegra platforms. Tegra132: TLK Tegra210: TLK and Trusty Tegra186: Trusty Scatter files ------------- Tegra platforms currently support scatter files and ld.S scripts. The scatter files help support ARMLINK linker to generate BL31 binaries. For now, there exists a common scatter file, plat/nvidia/tegra/scat/bl31.scat, for all Tegra SoCs. The `LINKER` build variable needs to point to the ARMLINK binary for the scatter file to be used. Tegra platforms have verified BL31 image generation with ARMCLANG (compilation) and ARMLINK (linking) for the Tegra186 platforms. Preparing the BL31 image to run on Tegra SoCs --------------------------------------------- .. code:: shell CROSS_COMPILE=/bin/aarch64-none-elf- make PLAT=tegra \ TARGET_SOC= SPD= bl31 Platforms wanting to use different TZDRAM\_BASE, can add ``TZDRAM_BASE=`` to the build command line. The Tegra platform code expects a pointer to the following platform specific structure via 'x1' register from the BL2 layer which is used by the bl31\_early\_platform\_setup() handler to extract the TZDRAM carveout base and size for loading the Trusted OS and the UART port ID to be used. The Tegra memory controller driver programs this base/size in order to restrict NS accesses. typedef struct plat\_params\_from\_bl2 { /\* TZ memory size */ uint64\_t tzdram\_size; /* TZ memory base */ uint64\_t tzdram\_base; /* UART port ID \*/ int uart\_id; /* L2 ECC parity protection disable flag \*/ int l2\_ecc\_parity\_prot\_dis; /* SHMEM base address for storing the boot logs \*/ uint64\_t boot\_profiler\_shmem\_base; } plat\_params\_from\_bl2\_t; Power Management ---------------- The PSCI implementation expects each platform to expose the 'power state' parameter to be used during the 'SYSTEM SUSPEND' call. The state-id field is implementation defined on Tegra SoCs and is preferably defined by tegra\_def.h. Tegra configs ------------- - 'tegra\_enable\_l2\_ecc\_parity\_prot': This flag enables the L2 ECC and Parity Protection bit, for Arm Cortex-A57 CPUs, during CPU boot. This flag will be enabled by Tegrs SoCs during 'Cluster power up' or 'System Suspend' exit. trusted-firmware-a-2.2/docs/plat/poplar.rst000066400000000000000000000125701355360272700210350ustar00rootroot00000000000000Poplar ====== Poplar is the first development board compliant with the 96Boards Enterprise Edition TV Platform specification. The board features the Hi3798C V200 with an integrated quad-core 64-bit Arm Cortex A53 processor and high performance Mali T720 GPU, making it capable of running any commercial set-top solution based on Linux or Android. It supports a premium user experience with up to H.265 HEVC decoding of 4K video at 60 frames per second. :: SOC Hisilicon Hi3798CV200 CPU Quad-core Arm Cortex-A53 64 bit DRAM DDR3/3L/4 SDRAM interface, maximum 32-bit data width 2 GB USB Two USB 2.0 ports One USB 3.0 ports CONSOLE USB-micro port for console support ETHERNET 1 GBe Ethernet PCIE One PCIe 2.0 interfaces JTAG 8-Pin JTAG EXPANSION INTERFACE Linaro 96Boards Low Speed Expansion slot DIMENSION Standard 160×120 mm 96Boards Enterprice Edition form factor WIFI 802.11AC 2*2 with Bluetooth CONNECTORS One connector for Smart Card One connector for TSI At the start of the boot sequence, the bootROM executes the so called l-loader binary whose main role is to change the processor state to 64bit mode. This must happen prior to invoking Trusted Firmware-A: :: l-loader --> Trusted Firmware-A --> u-boot How to build ------------ Code Locations ~~~~~~~~~~~~~~ - Trusted Firmware-A: `link `__ - l-loader: `link `__ - u-boot: `link `__ Build Procedure ~~~~~~~~~~~~~~~ - Fetch all the above 3 repositories into local host. Make all the repositories in the same ${BUILD\_PATH}. - Prepare the AARCH64 toolchain. - Build u-boot using poplar_defconfig .. code:: bash make CROSS_COMPILE=aarch64-linux-gnu- poplar_defconfig make CROSS_COMPILE=aarch64-linux-gnu- - Build atf providing the previously generated u-boot.bin as the BL33 image .. code:: bash make CROSS_COMPILE=aarch64-linux-gnu- all fip SPD=none PLAT=poplar BL33=u-boot.bin - Build l-loader (generated the final fastboot.bin) 1. copy the atf generated files fip.bin and bl1.bin to l-loader/atf/ 2. export ARM_TRUSTED_FIRMWARE=${ATF_SOURCE_PATH) 3. make Install Procedure ----------------- - Copy l-loader/fastboot.bin to a FAT partition on a USB pen drive. - Plug the USB pen drive to any of the USB2 ports - Power the board while keeping S3 pressed (usb_boot) The system will boot into a u-boot shell which you can then use to write the working firmware to eMMC. Boot trace ---------- :: Bootrom start Boot Media: eMMC Decrypt auxiliary code ...OK lsadc voltage min: 000000FE, max: 000000FF, aver: 000000FE, index: 00000000 Entry boot auxiliary code Auxiliary code - v1.00 DDR code - V1.1.2 20160205 Build: Mar 24 2016 - 17:09:44 Reg Version: v134 Reg Time: 2016/03/18 09:44:55 Reg Name: hi3798cv2dmb_hi3798cv200_ddr3_2gbyte_8bitx4_4layers.reg Boot auxiliary code success Bootrom success LOADER: Switched to aarch64 mode LOADER: Entering ARM TRUSTED FIRMWARE LOADER: CPU0 executes at 0x000ce000 INFO: BL1: 0xe1000 - 0xe7000 [size = 24576] NOTICE: Booting Trusted Firmware NOTICE: BL1: v1.3(debug):v1.3-372-g1ba9c60 NOTICE: BL1: Built : 17:51:33, Apr 30 2017 INFO: BL1: RAM 0xe1000 - 0xe7000 INFO: BL1: Loading BL2 INFO: Loading image id=1 at address 0xe9000 INFO: Image id=1 loaded at address 0xe9000, size = 0x5008 NOTICE: BL1: Booting BL2 INFO: Entry point address = 0xe9000 INFO: SPSR = 0x3c5 NOTICE: BL2: v1.3(debug):v1.3-372-g1ba9c60 NOTICE: BL2: Built : 17:51:33, Apr 30 2017 INFO: BL2: Loading BL31 INFO: Loading image id=3 at address 0x129000 INFO: Image id=3 loaded at address 0x129000, size = 0x8038 INFO: BL2: Loading BL33 INFO: Loading image id=5 at address 0x37000000 INFO: Image id=5 loaded at address 0x37000000, size = 0x58f17 NOTICE: BL1: Booting BL31 INFO: Entry point address = 0x129000 INFO: SPSR = 0x3cd INFO: Boot bl33 from 0x37000000 for 364311 Bytes NOTICE: BL31: v1.3(debug):v1.3-372-g1ba9c60 NOTICE: BL31: Built : 17:51:33, Apr 30 2017 INFO: BL31: Initializing runtime services INFO: BL31: Preparing for EL3 exit to normal world INFO: Entry point address = 0x37000000 INFO: SPSR = 0x3c9 U-Boot 2017.05-rc2-00130-gd2255b0 (Apr 30 2017 - 17:51:28 +0200)poplar Model: HiSilicon Poplar Development Board BOARD: Hisilicon HI3798cv200 Poplar DRAM: 1 GiB MMC: Hisilicon DWMMC: 0 In: serial@f8b00000 Out: serial@f8b00000 Err: serial@f8b00000 Net: Net Initialization Skipped No ethernet found. Hit any key to stop autoboot: 0 starting USB... USB0: USB EHCI 1.00 scanning bus 0 for devices... 1 USB Device(s) found USB1: USB EHCI 1.00 scanning bus 1 for devices... 4 USB Device(s) found scanning usb for storage devices... 1 Storage Device(s) found scanning usb for ethernet devices... 1 Ethernet Device(s) found USB device 0: Device 0: Vendor: SanDisk Rev: 1.00 Prod: Cruzer Blade Type: Removable Hard Disk Capacity: 7632.0 MB = 7.4 GB (15630336 x 512) ... is now current device Scanning usb 0:1... => trusted-firmware-a-2.2/docs/plat/qemu-sbsa.rst000066400000000000000000000031201355360272700214240ustar00rootroot00000000000000QEMU SBSA Target ================ Trusted Firmware-A (TF-A) implements the EL3 firmware layer for QEMU SBSA Armv8-A. While running Qemu from command line, we need to supply two Flash images. First Secure BootRom is supplied by -pflash argument. This Flash image is made by EDK2 build system by composing BL1 and FIP. Second parameter for Qemu is responsible for Non-secure rom which also given with -pflash argument and contains of UEFI and EFI variables (also made by EDK2 build system). Semihosting is not used When QEMU starts all CPUs are released simultaneously, BL1 selects a primary CPU to handle the boot and the secondaries are placed in a polling loop to be released by normal world via PSCI. BL2 edits the FDT, generated by QEMU at run-time to add a node describing PSCI and also enable methods for the CPUs. Current limitations: - Only cold boot is supported - No instructions for how to load a BL32 (Secure Payload) To build TF-A: :: git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git tfa cd tfa export CROSS_COMPILE=aarch64-linux-gnu- make PLAT=qemu_sbsa all fip Images will be placed at build/qemu_sbsa/release (bl1.bin and fip.bin). Need to copy them into top directory for EDK2 compilation. :: cp build/qemu_sbsa/release/bl1.bin ../ cp build/qemu_sbsa/release/fip.bin ../ Those images cannot be used by itself (no semihosing support). Flash images are built by EDK2 build system, refer to edk2-platform repo for full build instructions. :: git clone https://github.com/tianocore/edk2-platforms.git Platform/Qemu/SbsaQemu/Readme.md trusted-firmware-a-2.2/docs/plat/qemu.rst000066400000000000000000000033301355360272700205010ustar00rootroot00000000000000QEMU virt Armv8-A ================= Trusted Firmware-A (TF-A) implements the EL3 firmware layer for QEMU virt Armv8-A. BL1 is used as the BootROM, supplied with the -bios argument. When QEMU starts all CPUs are released simultaneously, BL1 selects a primary CPU to handle the boot and the secondaries are placed in a polling loop to be released by normal world via PSCI. BL2 edits the Flattened Device Tree, FDT, generated by QEMU at run-time to add a node describing PSCI and also enable methods for the CPUs. An ARM64 defconfig v4.5 Linux kernel is known to boot, FDT doesn't need to be provided as it's generated by QEMU. Current limitations: - Only cold boot is supported - No build instructions for QEMU\_EFI.fd and rootfs-arm64.cpio.gz - No instructions for how to load a BL32 (Secure Payload) ``QEMU_EFI.fd`` can be dowloaded from http://snapshots.linaro.org/components/kernel/leg-virt-tianocore-edk2-upstream/latest/QEMU-KERNEL-AARCH64/RELEASE_GCC49/QEMU_EFI.fd Boot binaries, except BL1, are primarily loaded via semi-hosting so all binaries has to reside in the same directory as QEMU is started from. This is conveniently achieved with symlinks the local names as: - ``bl2.bin`` -> BL2 - ``bl31.bin`` -> BL31 - ``bl33.bin`` -> BL33 (``QEMU_EFI.fd``) - ``Image`` -> linux/Image To build: .. code:: shell make CROSS_COMPILE=aarch64-none-elf- PLAT=qemu To start (QEMU v2.6.0): .. code:: shell qemu-system-aarch64 -nographic -machine virt,secure=on -cpu cortex-a57 \ -kernel Image \ -append console=ttyAMA0,38400 keep_bootcon root=/dev/vda2 \ -initrd rootfs-arm64.cpio.gz -smp 2 -m 1024 -bios bl1.bin \ -d unimp -semihosting-config enable,target=native trusted-firmware-a-2.2/docs/plat/rcar-gen3.rst000066400000000000000000000217501355360272700213210ustar00rootroot00000000000000Renesas R-Car ============= "R-Car" is the nickname for Renesas' system-on-chip (SoC) family for car information systems designed for the next-generation of automotive computing for the age of autonomous vehicles. The scalable R-Car hardware platform and flexible software platform cover the full product range, from the premium class to the entry level. Plug-ins are available for multiple open-source software tools. Renesas R-Car Gen3 evaluation boards: ------------------------------------- +------------+-----------------+-----------------------------+ | | Standard | Low Cost Boards (LCB) | +============+=================+=============================+ | R-Car H3 | - Salvator-X | - R-Car Starter Kit Premier | | | - Salvator-XS | | +------------+-----------------+-----------------------------+ | R-Car M3-W | - Salvator-X | | | | - Salvator-XS | - R-Car Starter Kit Pro | +------------+-----------------+-----------------------------+ | R-Car M3-N | - Salvator-X | | | | - Salvator-XS | | +------------+-----------------+-----------------------------+ | R-Car V3M | - Eagle | - Starter Kit | +------------+-----------------+-----------------------------+ | R-Car V3H | - Condor | - Starter Kit | +------------+-----------------+-----------------------------+ | R-Car D3 | - Draak | | +------------+-----------------+-----------------------------+ `boards info `__ The current TF-A port has been tested on the R-Car H3 Salvator-X Soc_id r8a7795 revision ES1.1 (uses a Secure Payload Dispatcher) :: ARM CA57 (ARMv8) 1.5 GHz quad core, with NEON/VFPv4, L1$ I/D 48K/32K, L2$ 2MB ARM CA53 (ARMv8) 1.2 GHz quad core, with NEON/VFPv4, L1$ I/D 32K/32K, L2$ 512K Memory controller for LPDDR4-3200 4GB in 2 channels, each 64-bit wide Two- and three-dimensional graphics engines, Video processing units, 3 channels Display Output, 6 channels Video Input, SD card host interface, USB3.0 and USB2.0 interfaces, CAN interfaces Ethernet AVB PCI Express Interfaces Memories INTERNAL 384KB SYSTEM RAM DDR 4 GB LPDDR4 HYPERFLASH 64 MB HYPER FLASH (512 MBITS, 160 MHZ, 320 MBYTES/S) QSPI FLASH 16MB QSPI (128 MBITS,80 MHZ,80 MBYTES/S)1 HEADER QSPI MODULE EMMC 32 GB EMMC (HS400 240 MBYTES/S) MICROSD-CARD SLOT (SDR104 100 MBYTES/S) Overview -------- On the rcar-gen3 the BOOTROM starts the cpu at EL3; for this port BL2 will therefore be entered at this exception level (the Renesas' ATF reference tree [1] resets into EL1 before entering BL2 - see its bl2.ld.S) BL2 initializes DDR (and on some platforms i2c to interface to the PMIC) before determining the boot reason (cold or warm). During suspend all CPUs are switched off and the DDR is put in backup mode (some kind of self-refresh mode). This means that BL2 is always entered in a cold boot scenario. Once BL2 boots, it determines the boot reason, writes it to shared memory (BOOT_KIND_BASE) together with the BL31 parameters (PARAMS_BASE) and jumps to BL31. To all effects, BL31 is as if it is being entered in reset mode since it still needs to initialize the rest of the cores; this is the reason behind using direct shared memory access to BOOT_KIND_BASE _and_ PARAMS_BASE instead of using registers to get to those locations (see el3_common_macros.S and bl31_entrypoint.S for the RESET_TO_BL31 use case). Depending on the boot reason BL31 initializes the rest of the cores: in case of suspend, it uses a MBOX memory region to recover the program counters. [1] https://github.com/renesas-rcar/arm-trusted-firmware How to build ------------ The TF-A build options depend on the target board so you will have to refer to those specific instructions. What follows is customized to the H3 SiP Salvator-X development system used in this port. Build Tested: ~~~~~~~~~~~~~ RCAR_OPT="LSI=H3 RCAR_DRAM_SPLIT=1 RCAR_LOSSY_ENABLE=1" MBEDTLS_DIR=$mbedtls_src $ MBEDTLS_DIR=$mbedtls_src_tree make clean bl2 bl31 rcar_layout_tool \ PLAT=rcar ${RCAR_OPT} SPD=opteed System Tested: ~~~~~~~~~~~~~~ * mbed_tls: git@github.com:ARMmbed/mbedtls.git [devel] commit 552754a6ee82bab25d1bdf28c8261a4518e65e4d Merge: 68dbc94 f34a4c1 Author: Simon Butcher Date: Thu Aug 30 00:57:28 2018 +0100 * optee_os: https://github.com/BayLibre/optee_os Until it gets merged into OP-TEE, the port requires Renesas' Trusted Environment with a modification to support power management. commit 80105192cba9e704ebe8df7ab84095edc2922f84 Author: Jorge Ramirez-Ortiz Date: Thu Aug 30 16:49:49 2018 +0200 plat-rcar: cpu-suspend: handle the power level Signed-off-by: Jorge Ramirez-Ortiz * u-boot: The port has beent tested using mainline uboot. commit 4cdeda511f8037015b568396e6dcc3d8fb41e8c0 Author: Fabio Estevam Date: Tue Sep 4 10:23:12 2018 -0300 * linux: The port has beent tested using mainline kernel. commit 7876320f88802b22d4e2daf7eb027dd14175a0f8 Author: Linus Torvalds Date: Sun Sep 16 11:52:37 2018 -0700 Linux 4.19-rc4 TF-A Build Procedure ~~~~~~~~~~~~~~~~~~~~ - Fetch all the above 4 repositories. - Prepare the AARCH64 toolchain. - Build u-boot using r8a7795_salvator-x_defconfig. Result: u-boot-elf.srec .. code:: bash make CROSS_COMPILE=aarch64-linux-gnu- r8a7795_salvator-x_defconfig make CROSS_COMPILE=aarch64-linux-gnu- - Build atf Result: bootparam_sa0.srec, cert_header_sa6.srec, bl2.srec, bl31.srec .. code:: bash RCAR_OPT="LSI=H3 RCAR_DRAM_SPLIT=1 RCAR_LOSSY_ENABLE=1" MBEDTLS_DIR=$mbedtls_src_tree make clean bl2 bl31 rcar \ PLAT=rcar ${RCAR_OPT} SPD=opteed - Build optee-os Result: tee.srec .. code:: bash make -j8 PLATFORM="rcar" CFG_ARM64_core=y Install Procedure ~~~~~~~~~~~~~~~~~ - Boot the board in Mini-monitor mode and enable access to the Hyperflash. - Use the XSL2 Mini-monitor utility to accept all the SREC ascii transfers over serial. Boot trace ---------- Notice that BL31 traces are not accessible via the console and that in order to verbose the BL2 output you will have to compile TF-A with LOG_LEVEL=50 and DEBUG=1 :: Initial Program Loader(CA57) Rev.1.0.22 NOTICE: BL2: PRR is R-Car H3 Ver.1.1 NOTICE: BL2: Board is Salvator-X Rev.1.0 NOTICE: BL2: Boot device is HyperFlash(80MHz) NOTICE: BL2: LCM state is CM NOTICE: AVS setting succeeded. DVFS_SetVID=0x53 NOTICE: BL2: DDR1600(rev.0.33)NOTICE: [COLD_BOOT]NOTICE: ..0 NOTICE: BL2: DRAM Split is 4ch NOTICE: BL2: QoS is default setting(rev.0.37) NOTICE: BL2: Lossy Decomp areas NOTICE: Entry 0: DCMPAREACRAx:0x80000540 DCMPAREACRBx:0x570 NOTICE: Entry 1: DCMPAREACRAx:0x40000000 DCMPAREACRBx:0x0 NOTICE: Entry 2: DCMPAREACRAx:0x20000000 DCMPAREACRBx:0x0 NOTICE: BL2: v2.0(release):v2.0-rc0-32-gbcda69a NOTICE: BL2: Built : 16:41:23, Oct 2 2018 NOTICE: BL2: Normal boot INFO: BL2: Doing platform setup INFO: BL2: Loading image id 3 NOTICE: BL2: dst=0xe6322000 src=0x8180000 len=512(0x200) NOTICE: BL2: dst=0x43f00000 src=0x8180400 len=6144(0x1800) WARNING: r-car ignoring the BL31 size from certificate,using RCAR_TRUSTED_SRAM_SIZE instead INFO: Loading image id=3 at address 0x44000000 NOTICE: rcar_file_len: len: 0x0003e000 NOTICE: BL2: dst=0x44000000 src=0x81c0000 len=253952(0x3e000) INFO: Image id=3 loaded: 0x44000000 - 0x4403e000 INFO: BL2: Loading image id 4 INFO: Loading image id=4 at address 0x44100000 NOTICE: rcar_file_len: len: 0x00100000 NOTICE: BL2: dst=0x44100000 src=0x8200000 len=1048576(0x100000) INFO: Image id=4 loaded: 0x44100000 - 0x44200000 INFO: BL2: Loading image id 5 INFO: Loading image id=5 at address 0x50000000 NOTICE: rcar_file_len: len: 0x00100000 NOTICE: BL2: dst=0x50000000 src=0x8640000 len=1048576(0x100000) INFO: Image id=5 loaded: 0x50000000 - 0x50100000 NOTICE: BL2: Booting BL31 INFO: Entry point address = 0x44000000 INFO: SPSR = 0x3cd VERBOSE: Argument #0 = 0xe6325578 VERBOSE: Argument #1 = 0x0 VERBOSE: Argument #2 = 0x0 VERBOSE: Argument #3 = 0x0 VERBOSE: Argument #4 = 0x0 VERBOSE: Argument #5 = 0x0 VERBOSE: Argument #6 = 0x0 VERBOSE: Argument #7 = 0x0 U-Boot 2018.09-rc3-00028-g3711616 (Sep 27 2018 - 18:50:24 +0200) CPU: Renesas Electronics R8A7795 rev 1.1 Model: Renesas Salvator-X board based on r8a7795 ES2.0+ DRAM: 3.5 GiB Flash: 64 MiB MMC: sd@ee100000: 0, sd@ee140000: 1, sd@ee160000: 2 Loading Environment from MMC... OK In: serial@e6e88000 Out: serial@e6e88000 Err: serial@e6e88000 Net: eth0: ethernet@e6800000 Hit any key to stop autoboot: 0 => trusted-firmware-a-2.2/docs/plat/rockchip.rst000066400000000000000000000027711355360272700213440ustar00rootroot00000000000000Rockchip SoCs ============= Trusted Firmware-A supports a number of Rockchip ARM SoCs from both AARCH32 and AARCH64 fields. This includes right now: - px30: Quad-Core Cortex-A53 - rk3288: Quad-Core Cortex-A17 (past A12) - rk3328: Quad-Core Cortex-A53 - rk3368: Octa-Core Cortex-A53 - rk3399: Hexa-Core Cortex-A53/A72 Boot Sequence ------------- For AARCH32: Bootrom --> BL1/BL2 --> BL32 --> BL33 --> Linux kernel For AARCH64: Bootrom --> BL1/BL2 --> BL31 --> BL33 --> Linux kernel BL1/2 and BL33 can currently be supplied from either: - Coreboot + Depthcharge - U-Boot - either separately as TPL+SPL or only SPL How to build ------------ Rockchip SoCs expect TF-A's BL31 (AARCH64) or BL32 (AARCH32) to get integrated with other boot software like U-Boot or Coreboot, so only these images need to get build from the TF-A repository. For AARCH64 architectures the build command looks like make CROSS_COMPILE=aarch64-linux-gnu- PLAT=rk3399 bl32 while AARCH32 needs a slightly different command make ARCH=aarch32 CROSS_COMPILE=arm-linux-gnueabihf- PLAT=rk3288 AARCH32_SP=sp_min bl32 Both need replacing the PLAT argument with the platform from above you want to build for and the CROSS_COMPILE argument with you cross- compilation toolchain. How to deploy ------------- Both upstream U-Boot and Coreboot projects contain instructions on where to put the built images during their respective build process. So after successfully building TF-A just follow their build instructions to continue. trusted-firmware-a-2.2/docs/plat/rpi3.rst000066400000000000000000000477401355360272700204240ustar00rootroot00000000000000Raspberry Pi 3 ============== The `Raspberry Pi 3`_ is an inexpensive single-board computer that contains four Arm Cortex-A53 cores. The following instructions explain how to use this port of the TF-A with the default distribution of `Raspbian`_ because that's the distribution officially supported by the Raspberry Pi Foundation. At the moment of writing this, the officially supported kernel is a AArch32 kernel. This doesn't mean that this port of TF-A can't boot a AArch64 kernel. The `Linux tree fork`_ maintained by the Foundation can be compiled for AArch64 by following the steps in `AArch64 kernel build instructions`_. **IMPORTANT NOTE**: This port isn't secure. All of the memory used is DRAM, which is available from both the Non-secure and Secure worlds. This port shouldn't be considered more than a prototype to play with and implement elements like PSCI to support the Linux kernel. Design ------ The SoC used by the Raspberry Pi 3 is the Broadcom BCM2837. It is a SoC with a VideoCore IV that acts as primary processor (and loads everything from the SD card) and is located between all Arm cores and the DRAM. Check the `Raspberry Pi 3 documentation`_ for more information. This explains why it is possible to change the execution state (AArch64/AArch32) depending on a few files on the SD card. We only care about the cases in which the cores boot in AArch64 mode. The rules are simple: - If a file called ``kernel8.img`` is located on the ``boot`` partition of the SD card, it will load it and execute in EL2 in AArch64. Basically, it executes a `default AArch64 stub`_ at address **0x0** that jumps to the kernel. - If there is also a file called ``armstub8.bin``, it will load it at address **0x0** (instead of the default stub) and execute it in EL3 in AArch64. All the cores are powered on at the same time and start at address **0x0**. This means that we can use the default AArch32 kernel provided in the official `Raspbian`_ distribution by renaming it to ``kernel8.img``, while TF-A and anything else we need is in ``armstub8.bin``. This way we can forget about the default bootstrap code. When using a AArch64 kernel, it is only needed to make sure that the name on the SD card is ``kernel8.img``. Ideally, we want to load the kernel and have all cores available, which means that we need to make the secondary cores work in the way the kernel expects, as explained in `Secondary cores`_. In practice, a small bootstrap is needed between TF-A and the kernel. To get the most out of a AArch32 kernel, we want to boot it in Hypervisor mode in AArch32. This means that BL33 can't be in EL2 in AArch64 mode. The architecture specifies that AArch32 Hypervisor mode isn't present when AArch64 is used for EL2. When using a AArch64 kernel, it should simply start in EL2. Placement of images ~~~~~~~~~~~~~~~~~~~ The file ``armstub8.bin`` contains BL1 and the FIP. It is needed to add padding between them so that the addresses they are loaded to match the ones specified when compiling TF-A. This is done automatically by the build system. The device tree block is loaded by the VideoCore loader from an appropriate file, but we can specify the address it is loaded to in ``config.txt``. The file ``kernel8.img`` contains a kernel image that is loaded to the address specified in ``config.txt``. The `Linux kernel tree`_ has information about how a AArch32 Linux kernel image is loaded in ``Documentation/arm/Booting``: :: The zImage may also be placed in system RAM and called there. The kernel should be placed in the first 128MiB of RAM. It is recommended that it is loaded above 32MiB in order to avoid the need to relocate prior to decompression, which will make the boot process slightly faster. There are no similar restrictions for AArch64 kernels, as specified in the file ``Documentation/arm64/booting.txt``. This means that we need to avoid the first 128 MiB of RAM when placing the TF-A images (and specially the first 32 MiB, as they are directly used to place the uncompressed AArch32 kernel image. This way, both AArch32 and AArch64 kernels can be placed at the same address. In the end, the images look like the following diagram when placed in memory. All addresses are Physical Addresses from the point of view of the Arm cores. Again, note that this is all just part of the same DRAM that goes from **0x00000000** to **0x3F000000**, it just has different names to simulate a real secure platform! :: 0x00000000 +-----------------+ | ROM | BL1 0x00020000 +-----------------+ | FIP | 0x00200000 +-----------------+ | | | ... | | | 0x01000000 +-----------------+ | DTB | (Loaded by the VideoCore) +-----------------+ | | | ... | | | 0x02000000 +-----------------+ | Kernel | (Loaded by the VideoCore) +-----------------+ | | | ... | | | 0x10000000 +-----------------+ | Secure SRAM | BL2, BL31 0x10100000 +-----------------+ | Secure DRAM | BL32 (Secure payload) 0x11000000 +-----------------+ | Non-secure DRAM | BL33 +-----------------+ | | | ... | | | 0x3F000000 +-----------------+ | I/O | 0x40000000 +-----------------+ The area between **0x10000000** and **0x11000000** has to be manually protected so that the kernel doesn't use it. The current port tries to modify the live DTB to add a memreserve region that reserves the previously mentioned area. If this is not possible, the user may manually add ``memmap=16M$256M`` to the command line passed to the kernel in ``cmdline.txt``. See the `Setup SD card`_ instructions to see how to do it. This system is strongly discouraged. The last 16 MiB of DRAM can only be accessed by the VideoCore, that has different mappings than the Arm cores in which the I/O addresses don't overlap the DRAM. The memory reserved to be used by the VideoCore is always placed at the end of the DRAM, so this space isn't wasted. Considering the 128 MiB allocated to the GPU and the 16 MiB allocated for TF-A, there are 880 MiB available for Linux. Boot sequence ~~~~~~~~~~~~~ The boot sequence of TF-A is the usual one except when booting an AArch32 kernel. In that case, BL33 is booted in AArch32 Hypervisor mode so that it can jump to the kernel in the same mode and let it take over that privilege level. If BL33 was running in EL2 in AArch64 (as in the default bootflow of TF-A) it could only jump to the kernel in AArch32 in Supervisor mode. The `Linux kernel tree`_ has instructions on how to jump to the Linux kernel in ``Documentation/arm/Booting`` and ``Documentation/arm64/booting.txt``. The bootstrap should take care of this. This port support a direct boot of the Linux kernel from the firmware (as a BL33 image). Alternatively, U-Boot or other bootloaders may be used. Secondary cores ~~~~~~~~~~~~~~~ This port of the Trusted Firmware-A supports ``PSCI_CPU_ON``, ``PSCI_SYSTEM_RESET`` and ``PSCI_SYSTEM_OFF``. The last one doesn't really turn the system off, it simply reboots it and asks the VideoCore firmware to keep it in a low power mode permanently. The kernel used by `Raspbian`_ doesn't have support for PSCI, so it is needed to use mailboxes to trap the secondary cores until they are ready to jump to the kernel. This mailbox is located at a different address in the AArch32 default kernel than in the AArch64 kernel. Kernels with PSCI support can use the PSCI calls instead for a cleaner boot. Also, this port of TF-A has another Trusted Mailbox in Shared BL RAM. During cold boot, all secondary cores wait in a loop until they are given given an address to jump to in this Mailbox (``bl31_warm_entrypoint``). Once BL31 has finished and the primary core has jumped to the BL33 payload, it has to call ``PSCI_CPU_ON`` to release the secondary CPUs from the wait loop. The payload then makes them wait in another waitloop listening from messages from the kernel. When the primary CPU jumps into the kernel, it will send an address to the mailbox so that the secondary CPUs jump to it and are recognised by the kernel. Build Instructions ------------------ To boot a AArch64 kernel, only the AArch64 toolchain is required. To boot a AArch32 kernel, both AArch64 and AArch32 toolchains are required. The AArch32 toolchain is needed for the AArch32 bootstrap needed to load a 32-bit kernel. The build system concatenates BL1 and the FIP so that the addresses match the ones in the memory map. The resulting file is ``armstub8.bin``, located in the build folder (e.g. ``build/rpi3/debug/armstub8.bin``). To know how to use this file, follow the instructions in `Setup SD card`_. The following build options are supported: - ``RPI3_BL33_IN_AARCH32``: This port can load a AArch64 or AArch32 BL33 image. By default this option is 0, which means that TF-A will jump to BL33 in EL2 in AArch64 mode. If set to 1, it will jump to BL33 in Hypervisor in AArch32 mode. - ``PRELOADED_BL33_BASE``: Used to specify the address of a BL33 binary that has been preloaded by any other system than using the firmware. ``BL33`` isn't needed in the build command line if this option is used. Specially useful because the file ``kernel8.img`` can be loaded anywhere by modifying the file ``config.txt``. It doesn't have to contain a kernel, it could have any arbitrary payload. - ``RPI3_DIRECT_LINUX_BOOT``: Disabled by default. Set to 1 to enable the direct boot of the Linux kernel from the firmware. Option ``RPI3_PRELOADED_DTB_BASE`` is mandatory when the direct Linux kernel boot is used. Options ``PRELOADED_BL33_BASE`` will most likely be needed as well because it is unlikely that the kernel image will fit in the space reserved for BL33 images. This option can be combined with ``RPI3_BL33_IN_AARCH32`` in order to boot a 32-bit kernel. The only thing this option does is to set the arguments in registers x0-x3 or r0-r2 as expected by the kernel. - ``RPI3_PRELOADED_DTB_BASE``: Auxiliary build option needed when using ``RPI3_DIRECT_LINUX_BOOT=1``. This option allows to specify the location of a DTB in memory. - ``RPI3_RUNTIME_UART``: Indicates whether the UART should be used at runtime or disabled. ``-1`` (default) disables the runtime UART. Any other value enables the default UART (currently UART1) for runtime messages. - ``RPI3_USE_UEFI_MAP``: Set to 1 to build ATF with the altername memory mapping required for an UEFI firmware payload. These changes are needed to be able to run Windows on ARM64. This option, which is disabled by default, results in the following memory mappings: :: 0x00000000 +-----------------+ | ROM | BL1 0x00010000 +-----------------+ | DTB | (Loaded by the VideoCore) 0x00020000 +-----------------+ | FIP | 0x00030000 +-----------------+ | | | UEFI PAYLOAD | | | 0x00200000 +-----------------+ | Secure SRAM | BL2, BL31 0x00300000 +-----------------+ | Secure DRAM | BL32 (Secure payload) 0x00400000 +-----------------+ | | | | | Non-secure DRAM | BL33 | | | | 0x01000000 +-----------------+ | | | ... | | | 0x3F000000 +-----------------+ | I/O | - ``BL32``: This port can load and run OP-TEE. The OP-TEE image is optional. Please use the code from `here `__. Build the Trusted Firmware with option ``BL32=tee-header_v2.bin BL32_EXTRA1=tee-pager_v2.bin BL32_EXTRA2=tee-pageable_v2.bin`` to put the binaries into the FIP. .. warning:: If OP-TEE is used it may be needed to add the following options to the Linux command line so that the USB driver doesn't use FIQs: ``dwc_otg.fiq_enable=0 dwc_otg.fiq_fsm_enable=0 dwc_otg.nak_holdoff=0``. This will unfortunately reduce the performance of the USB driver. It is needed when using Raspbian, for example. - ``TRUSTED_BOARD_BOOT``: This port supports TBB. Set this option to 1 to enable it. In order to use TBB, you might want to set ``GENERATE_COT=1`` to let the contents of the FIP automatically signed by the build process. The ROT key will be generated and output to ``rot_key.pem`` in the build directory. It is able to set ROT_KEY to your own key in PEM format. Also in order to build, you need to clone mbed TLS from `here `__. ``MBEDTLS_DIR`` must point at the mbed TLS source directory. - ``ENABLE_STACK_PROTECTOR``: Disabled by default. It uses the hardware RNG of the board. The following is not currently supported: - AArch32 for TF-A itself. - ``EL3_PAYLOAD_BASE``: The reason is that you can already load anything to any address by changing the file ``armstub8.bin``, so there's no point in using TF-A in this case. - ``MULTI_CONSOLE_API=0``: The multi console API must be enabled. Note that the crash console uses the internal 16550 driver functions directly in order to be able to print error messages during early crashes before setting up the multi console API. Building the firmware for kernels that don't support PSCI ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This is the case for the 32-bit image of Raspbian, for example. 64-bit kernels always support PSCI, but they may not know that the system understands PSCI due to an incorrect DTB file. First, clone and compile the 32-bit version of the `Raspberry Pi 3 TF-A bootstrap`_. Choose the one needed for the architecture of your kernel. Then compile TF-A. For a 32-bit kernel, use the following command line: .. code:: shell CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3 \ RPI3_BL33_IN_AARCH32=1 \ BL33=../rpi3-arm-tf-bootstrap/aarch32/el2-bootstrap.bin For a 64-bit kernel, use this other command line: .. code:: shell CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3 \ BL33=../rpi3-arm-tf-bootstrap/aarch64/el2-bootstrap.bin However, enabling PSCI support in a 64-bit kernel is really easy. In the repository `Raspberry Pi 3 TF-A bootstrap`_ there is a patch that can be applied to the Linux kernel tree maintained by the Raspberry Pi foundation. It modifes the DTS to tell the kernel to use PSCI. Once this patch is applied, follow the instructions in `AArch64 kernel build instructions`_ to get a working 64-bit kernel image and supporting files. Building the firmware for kernels that support PSCI ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For a 64-bit kernel: .. code:: shell CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3 \ PRELOADED_BL33_BASE=0x02000000 \ RPI3_PRELOADED_DTB_BASE=0x01000000 \ RPI3_DIRECT_LINUX_BOOT=1 For a 32-bit kernel: .. code:: shell CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi3 \ PRELOADED_BL33_BASE=0x02000000 \ RPI3_PRELOADED_DTB_BASE=0x01000000 \ RPI3_DIRECT_LINUX_BOOT=1 \ RPI3_BL33_IN_AARCH32=1 AArch64 kernel build instructions --------------------------------- The following instructions show how to install and run a AArch64 kernel by using a SD card with the default `Raspbian`_ install as base. Skip them if you want to use the default 32-bit kernel. Note that this system won't be fully 64-bit because all the tools in the filesystem are 32-bit binaries, but it's a quick way to get it working, and it allows the user to run 64-bit binaries in addition to 32-bit binaries. 1. Clone the `Linux tree fork`_ maintained by the Raspberry Pi Foundation. To speed things up, do a shallow clone of the desired branch. .. code:: shell git clone --depth=1 -b rpi-4.18.y https://github.com/raspberrypi/linux cd linux 2. Configure and compile the kernel. Adapt the number after ``-j`` so that it is 1.5 times the number of CPUs in your computer. This may take some time to finish. .. code:: shell make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- bcmrpi3_defconfig make -j 6 ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- 3. Copy the kernel image and the device tree to the SD card. Replace the path by the corresponding path in your computers to the ``boot`` partition of the SD card. .. code:: shell cp arch/arm64/boot/Image /path/to/boot/kernel8.img cp arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b.dtb /path/to/boot/ cp arch/arm64/boot/dts/broadcom/bcm2710-rpi-3-b-plus.dtb /path/to/boot/ 4. Install the kernel modules. Replace the path by the corresponding path to the filesystem partition of the SD card on your computer. .. code:: shell make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \ INSTALL_MOD_PATH=/path/to/filesystem modules_install 5. Follow the instructions in `Setup SD card`_ except for the step of renaming the existing ``kernel7.img`` (we have already copied a AArch64 kernel). Setup SD card ------------- The instructions assume that you have an SD card with a fresh install of `Raspbian`_ (or that, at least, the ``boot`` partition is untouched, or nearly untouched). They have been tested with the image available in 2018-03-13. 1. Insert the SD card and open the ``boot`` partition. 2. Rename ``kernel7.img`` to ``kernel8.img``. This tricks the VideoCore bootloader into booting the Arm cores in AArch64 mode, like TF-A needs, even though the kernel is not compiled for AArch64. 3. Copy ``armstub8.bin`` here. When ``kernel8.img`` is available, The VideoCore bootloader will look for a file called ``armstub8.bin`` and load it at address **0x0** instead of a predefined one. 4. To enable the serial port "Mini UART" in Linux, open ``cmdline.txt`` and add ``console=serial0,115200 console=tty1``. 5. Open ``config.txt`` and add the following lines at the end (``enable_uart=1`` is only needed to enable debugging through the Mini UART): :: enable_uart=1 kernel_address=0x02000000 device_tree_address=0x01000000 If you connect a serial cable to the Mini UART and your computer, and connect to it (for example, with ``screen /dev/ttyUSB0 115200``) you should see some text. In the case of an AArch32 kernel, you should see something like this: :: NOTICE: Booting Trusted Firmware NOTICE: BL1: v1.4(release):v1.4-329-g61e94684-dirty NOTICE: BL1: Built : 00:09:25, Nov 6 2017 NOTICE: BL1: Booting BL2 NOTICE: BL2: v1.4(release):v1.4-329-g61e94684-dirty NOTICE: BL2: Built : 00:09:25, Nov 6 2017 NOTICE: BL1: Booting BL31 NOTICE: BL31: v1.4(release):v1.4-329-g61e94684-dirty NOTICE: BL31: Built : 00:09:25, Nov 6 2017 [ 0.266484] bcm2835-aux-uart 3f215040.serial: could not get clk: -517 Raspbian GNU/Linux 9 raspberrypi ttyS0 raspberrypi login: Just enter your credentials, everything should work as expected. Note that the HDMI output won't show any text during boot. .. _default Arm stub: https://github.com/raspberrypi/tools/blob/master/armstubs/armstub7.S .. _default AArch64 stub: https://github.com/raspberrypi/tools/blob/master/armstubs/armstub8.S .. _Linux kernel tree: https://github.com/torvalds/linux .. _Linux tree fork: https://github.com/raspberrypi/linux .. _Raspberry Pi 3: https://www.raspberrypi.org/products/raspberry-pi-3-model-b/ .. _Raspberry Pi 3 TF-A bootstrap: https://github.com/AntonioND/rpi3-arm-tf-bootstrap .. _Raspberry Pi 3 documentation: https://www.raspberrypi.org/documentation/ .. _Raspbian: https://www.raspberrypi.org/downloads/raspbian/ trusted-firmware-a-2.2/docs/plat/rpi4.rst000066400000000000000000000075351355360272700204230ustar00rootroot00000000000000Raspberry Pi 4 ============== The `Raspberry Pi 4`_ is an inexpensive single-board computer that contains four Arm Cortex-A72 cores. Also in contrast to previous Raspberry Pi versions this model has a GICv2 interrupt controller. This port is a minimal port to support loading non-secure EL2 payloads such as a 64-bit Linux kernel. Other payloads such as U-Boot or EDK-II should work as well, but have not been tested at this point. **IMPORTANT NOTE**: This port isn't secure. All of the memory used is DRAM, which is available from both the Non-secure and Secure worlds. The SoC does not seem to feature a secure memory controller of any kind, so portions of DRAM can't be protected properly from the Non-secure world. Build Instructions ------------------ There are no real configuration options at this point, so there is only one universal binary (bl31.bin), which can be built with: .. code:: shell CROSS_COMPILE=aarch64-linux-gnu- make PLAT=rpi4 DEBUG=1 Copy the generated build/rpi4/debug/bl31.bin to the SD card, either renaming it to ``armstub8.bin`` or adding an entry starting with ``armstub=``, then followed by the respective file name to ``config.txt``. You should have AArch64 code in the file loaded as the "kernel", as BL31 will drop into AArch64/EL2 to the respective load address. arm64 Linux kernels are known to work this way. Other options that should be set in ``config.txt`` to properly boot 64-bit kernels are: :: enable_uart=1 arm_64bit=1 enable_gic=1 The BL31 code will patch the provided device tree blob in memory to advertise PSCI support, also will add a reserved-memory node to the DT to tell the non-secure payload to not touch the resident TF-A code. If you connect a serial cable between the Mini UART and your computer, and connect to it (for example, with ``screen /dev/ttyUSB0 115200``) you should see some text from BL31, followed by the output of the EL2 payload. The command line provided is read from the ``cmdline.txt`` file on the SD card. TF-A port design ---------------- In contrast to the existing Raspberry Pi 3 port this one here is a BL31-only port, also it deviates quite a lot from the RPi3 port in many other ways. There is not so much difference between the two models, so eventually those two could be (more) unified in the future. As with the previous models, the GPU and its firmware are the first entity to run after the SoC gets its power. The on-chip Boot ROM loads the next stage (bootcode.bin) from flash (EEPROM), which is again GPU code. This part knows how to access the MMC controller and how to parse a FAT filesystem, so it will load further compononents and configuration files from the first FAT partition on the SD card. To accommodate this existing way of configuring and setting up the board, we use as much of this workflow as possible. If bootcode.bin finds a file called ``armstub8.bin`` on the SD card or it gets pointed to such code by finding a ``armstub=`` key in ``config.txt``, it will load this file to the beginning of DRAM (address 0) and execute it in AArch64 EL3. But before doing that, it will also load a "kernel" and the device tree into memory. The load addresses have a default, but can also be changed by setting them in ``config.txt``. If the GPU firmware finds a magic value in the armstub image file, it will put those two load addresses in memory locations near the beginning of memory, where TF-A code picks them up. To keep things simple, we will just use the kernel load address as the BL33 entry point, also put the DTB address in the x0 register, as requested by the arm64 Linux kernel boot protocol. This does not necessarily mean that the EL2 payload needs to be a Linux kernel, a bootloader or any other kernel would work as well, as long as it can cope with having the DT address in register x0. If the payload has other means of finding the device tree, it could ignore this address as well. trusted-firmware-a-2.2/docs/plat/socionext-uniphier.rst000066400000000000000000000100001355360272700233560ustar00rootroot00000000000000Socionext UniPhier ================== Socionext UniPhier Armv8-A SoCs use Trusted Firmware-A (TF-A) as the secure world firmware, supporting BL2 and BL31. UniPhier SoC family implements its internal boot ROM, which loads 64KB [1]_ image from a non-volatile storage to the on-chip SRAM, and jumps over to it. TF-A provides a special mode, BL2-AT-EL3, which enables BL2 to execute at EL3. It is useful for platforms with non-TF-A boot ROM, like UniPhier. Here, a problem is BL2 does not fit in the 64KB limit if :ref:`Trusted Board Boot (TBB) ` is enabled. To solve this issue, Socionext provides a first stage loader called `UniPhier BL`_. This loader runs in the on-chip SRAM, initializes the DRAM, expands BL2 there, and hands the control over to it. Therefore, all images of TF-A run in DRAM. The UniPhier platform works with/without TBB. See below for the build process of each case. The image authentication for the UniPhier platform fully complies with the Trusted Board Boot Requirements (TBBR) specification. The UniPhier BL does not implement the authentication functionality, that is, it can not verify the BL2 image by itself. Instead, the UniPhier BL assures the BL2 validity in a different way; BL2 is GZIP-compressed and appended to the UniPhier BL. The concatenation of the UniPhier BL and the compressed BL2 fits in the 64KB limit. The concatenated image is loaded by the internal boot ROM (and verified if the chip fuses are blown). Boot Flow --------- 1. The Boot ROM This is hard-wired ROM, so never corrupted. It loads the UniPhier BL (with compressed-BL2 appended) into the on-chip SRAM. If the SoC fuses are blown, the image is verified by the SoC's own method. 2. UniPhier BL This runs in the on-chip SRAM. After the minimum SoC initialization and DRAM setup, it decompresses the appended BL2 image into the DRAM, then jumps to the BL2 entry. 3. BL2 (at EL3) This runs in the DRAM. It extracts more images such as BL31, BL33 (optionally SCP_BL2, BL32 as well) from Firmware Image Package (FIP). If TBB is enabled, they are all authenticated by the standard mechanism of TF-A. After loading all the images, it jumps to the BL31 entry. 4. BL31, BL32, and BL33 They all run in the DRAM. See :ref:`Firmware Design` for details. Basic Build ----------- BL2 must be compressed for the reason above. The UniPhier's platform makefile provides a build target ``bl2_gzip`` for this. For a non-secure boot loader (aka BL33), U-Boot is well supported for UniPhier SoCs. The U-Boot image (``u-boot.bin``) must be built in advance. For the build procedure of U-Boot, refer to the document in the `U-Boot`_ project. To build minimum functionality for UniPhier (without TBB):: make CROSS_COMPILE= PLAT=uniphier BL33= bl2_gzip fip Output images: - ``bl2.bin.gz`` - ``fip.bin`` Optional features ----------------- - Trusted Board Boot `mbed TLS`_ is needed as the cryptographic and image parser modules. Refer to the :ref:`User Guide` for the appropriate version of mbed TLS. To enable TBB, add the following options to the build command:: TRUSTED_BOARD_BOOT=1 GENERATE_COT=1 MBEDTLS_DIR= - System Control Processor (SCP) If desired, FIP can include an SCP BL2 image. If BL2 finds an SCP BL2 image in FIP, BL2 loads it into DRAM and kicks the SCP. Most of UniPhier boards still work without SCP, but SCP provides better power management support. To include SCP BL2, add the following option to the build command:: SCP_BL2= - BL32 (Secure Payload) To enable BL32, add the following options to the build command:: SPD= BL32= If you use TSP for BL32, ``BL32=`` is not required. Just add the following:: SPD=tspd .. [1] Some SoCs can load 80KB, but the software implementation must be aligned to the lowest common denominator. .. _UniPhier BL: https://github.com/uniphier/uniphier-bl .. _U-Boot: https://www.denx.de/wiki/U-Boot .. _mbed TLS: https://tls.mbed.org/ trusted-firmware-a-2.2/docs/plat/stm32mp1.rst000066400000000000000000000066421355360272700211310ustar00rootroot00000000000000STMicroelectronics STM32MP1 =========================== STM32MP1 is a microprocessor designed by STMicroelectronics based on a dual Arm Cortex-A7. It is an Armv7-A platform, using dedicated code from TF-A. The STM32MP1 chip also embeds a Cortex-M4. More information can be found on `STM32MP1 Series`_ page. Design ------ The STM32MP1 resets in the ROM code of the Cortex-A7. The primary boot core (core 0) executes the boot sequence while secondary boot core (core 1) is kept in a holding pen loop. The ROM code boot sequence loads the TF-A binary image from boot device to embedded SRAM. The TF-A image must be properly formatted with a STM32 header structure for ROM code is able to load this image. Tool stm32image can be used to prepend this header to the generated TF-A binary. At compilation step, BL2, BL32 and DTB file are linked together in a single binary. The stm32image tool is also generated and the header is added to TF-A binary. This binary file with header is named tf-a-stm32mp157c-ev1.stm32. It can then be copied in the first partition of the boot device. Memory mapping ~~~~~~~~~~~~~~ :: 0x00000000 +-----------------+ | | ROM 0x00020000 +-----------------+ | | | ... | | | 0x2FFC0000 +-----------------+ \ | | | | ... | | | | | 0x2FFD8000 +-----------------+ | | TF-A DTB | | Embedded SRAM 0x2FFDC000 +-----------------+ | | BL2 | | 0x2FFEF000 +-----------------+ | | BL32 | | 0x30000000 +-----------------+ / | | | ... | | | 0x40000000 +-----------------+ | | | | Devices | | 0xC0000000 +-----------------+ \ | | | 0xC0100000 +-----------------+ | | BL33 | | Non-secure RAM (DDR) | ... | | | | | 0xFFFFFFFF +-----------------+ / Boot sequence ~~~~~~~~~~~~~ ROM code -> BL2 (compiled with BL2_AT_EL3) -> BL32 (SP_min) -> BL33 (U-Boot) or if Op-TEE is used: ROM code -> BL2 (compiled with BL2_AT_EL3) -> OP-TEE -> BL33 (U-Boot) Build Instructions ------------------ To build with SP_min: .. code:: bash make CROSS_COMPILE=arm-linux-gnueabihf- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=sp_min DTB_FILE_NAME=stm32mp157c-ev1.dtb cd make stm32mp15_trusted_defconfig make DEVICE_TREE=stm32mp157c-ev1 all To build TF-A with with Op-TEE support: .. code:: bash make CROSS_COMPILE=arm-linux-gnueabihf- PLAT=stm32mp1 ARCH=aarch32 ARM_ARCH_MAJOR=7 AARCH32_SP=optee 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. .. _STM32MP1 Series: https://www.st.com/en/microcontrollers-microprocessors/stm32mp1-series.html trusted-firmware-a-2.2/docs/plat/synquacer.rst000066400000000000000000000074261355360272700215560ustar00rootroot00000000000000Socionext Synquacer =================== Socionext's Synquacer SC2A11 is a multi-core processor with 24 cores of Arm Cortex-A53. The Developerbox, of 96boards, is a platform that contains this processor. This port of the Trusted Firmware only supports this platform at the moment. More information are listed in `link`_. How to build ------------ Code Locations ~~~~~~~~~~~~~~ - Trusted Firmware-A: `link `__ - edk2: `link `__ - edk2-platforms: `link `__ - edk2-non-osi: `link `__ Boot Flow ~~~~~~~~~ SCP firmware --> TF-A BL31 --> UEFI(edk2) Build Procedure ~~~~~~~~~~~~~~~ - Firstly, in addition to the “normal†build tools you will also need a few specialist tools. On a Debian or Ubuntu operating system try: .. code:: shell sudo apt install acpica-tools device-tree-compiler uuid-dev - Secondly, create a new working directory and store the absolute path to this directory in an environment variable, WORKSPACE. It does not matter where this directory is created but as an example: .. code:: shell export WORKSPACE=$HOME/build/developerbox-firmware mkdir -p $WORKSPACE - Run the following commands to clone the source code: .. code:: shell cd $WORKSPACE git clone https://github.com/ARM-software/arm-trusted-firmware -b master git clone https://github.com/tianocore/edk2.git -b master git clone https://github.com/tianocore/edk2-platforms.git -b master git clone https://github.com/tianocore/edk2-non-osi.git -b master - Build ATF: .. code:: shell cd $WORKSPACE/arm-trusted-firmware make -j`nproc` PLAT=synquacer PRELOADED_BL33_BASE=0x8200000 bl31 fiptool tools/fiptool/fiptool create \ --tb-fw ./build/synquacer/release/bl31.bin \ --soc-fw ./build/synquacer/release/bl31.bin \ --scp-fw ./build/synquacer/release/bl31.bin \ ../edk2-non-osi/Platform/Socionext/DeveloperBox/fip_all_arm_tf.bin - Build EDK2: .. code:: shell cd $WORKSPACE export PACKAGES_PATH=$WORKSPACE/edk2:$WORKSPACE/edk2-platforms:$WORKSPACE/edk2-non-osi export ACTIVE_PLATFORM="Platform/Socionext/DeveloperBox/DeveloperBox.dsc" export GCC5_AARCH64_PREFIX=aarch64-linux-gnu- unset ARCH . edk2/edksetup.sh make -C edk2/BaseTools build -p $ACTIVE_PLATFORM -b RELEASE -a AARCH64 -t GCC5 -n `nproc` -D DO_X86EMU=TRUE - The firmware image, which comprises the option ROM, ARM trusted firmware and EDK2 itself, can be found $WORKSPACE/../Build/DeveloperBox/RELEASE_GCC5/FV/. Use SYNQUACERFIRMWAREUPDATECAPSULEFMPPKCS7.Cap for UEFI capsule update and SPI_NOR_IMAGE.fd for the serial flasher. Note #1: -t GCC5 can be loosely translated as “enable link-time-optimizationâ€; any version of gcc >= 5 will support this feature and may be used to build EDK2. Note #2: Replace -b RELEASE with -b DEBUG to build a debug. Install the System Firmware ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - Providing your Developerbox is fully working and has on operating system installed then you can adopt your the newly compiled system firmware using the capsule update method:. .. code:: shell sudo apt install fwupdate sudo fwupdate --apply {50b94ce5-8b63-4849-8af4-ea479356f0e3} \ SYNQUACERFIRMWAREUPDATECAPSULEFMPPKCS7.Cap sudo reboot - Alternatively you can install SPI_NOR_IMAGE.fd using the `board recovery method`_. .. _link: https://www.96boards.org/product/developerbox/ .. _board recovery method: https://www.96boards.org/documentation/enterprise/developerbox/installation/board-recovery.md.html trusted-firmware-a-2.2/docs/plat/ti-k3.rst000066400000000000000000000026601355360272700204660ustar00rootroot00000000000000Texas Instruments K3 ==================== Trusted Firmware-A (TF-A) implements the EL3 firmware layer for Texas Instruments K3 SoCs. Boot Flow --------- :: R5(U-Boot) --> TF-A BL31 --> BL32(OP-TEE) --> TF-A BL31 --> BL33(U-Boot) --> Linux \ Optional direct to Linux boot \ --> BL33(Linux) Texas Instruments K3 SoCs contain an R5 processor used as the boot master, it loads the needed images for A53 startup, because of this we do not need BL1 or BL2 TF-A stages. Build Instructions ------------------ https://github.com/ARM-software/arm-trusted-firmware.git TF-A: .. code:: shell make CROSS_COMPILE=aarch64-linux-gnu- PLAT=k3 SPD=opteed all OP-TEE: .. code:: shell make ARCH=arm CROSS_COMPILE64=aarch64-linux-gnu- PLATFORM=k3 CFG_ARM64_core=y all R5 U-Boot: .. code:: shell make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- am65x_evm_r5_defconfig make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- SYSFW= A53 U-Boot: .. code:: shell make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- am65x_evm_a53_defconfig make ARCH=arm CROSS_COMPILE=aarch64-linux-gnu- ATF= TEE= Deploy Images ------------- .. code:: shell cp tiboot3.bin tispl.bin u-boot.img /sdcard/boot/ trusted-firmware-a-2.2/docs/plat/warp7.rst000066400000000000000000000162661355360272700206060ustar00rootroot00000000000000NXP i.MX7 WaRP7 =============== The Trusted Firmware-A port for the i.MX7Solo WaRP7 implements BL2 at EL3. The i.MX7S contains a BootROM with a High Assurance Boot (HAB) functionality. This functionality provides a mechanism for establishing a root-of-trust from the reset vector to the command-line in user-space. Boot Flow --------- BootROM --> TF-A BL2 --> BL32(OP-TEE) --> BL33(U-Boot) --> Linux In the WaRP7 port we encapsulate OP-TEE, DTB and U-Boot into a FIP. This FIP is expected and required Build Instructions ------------------ We need to use a file generated by u-boot in order to generate a .imx image the BootROM will boot. It is therefore _required_ to build u-boot before TF-A and furthermore it is _recommended_ to use the mkimage in the u-boot/tools directory to generate the TF-A .imx image. U-Boot ~~~~~~ https://git.linaro.org/landing-teams/working/mbl/u-boot.git .. code:: shell git checkout -b rms-atf-optee-uboot linaro-mbl/rms-atf-optee-uboot make warp7_bl33_defconfig; make u-boot.imx arch=ARM CROSS_COMPILE=arm-linux-gnueabihf- OP-TEE ~~~~~~ https://github.com/OP-TEE/optee_os.git .. code:: shell make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- PLATFORM=imx PLATFORM_FLAVOR=mx7swarp7 ARCH=arm CFG_PAGEABLE_ADDR=0 CFG_DT_ADDR=0x83000000 CFG_NS_ENTRY_ADDR=0x87800000 TF-A ~~~~ https://github.com/ARM-software/arm-trusted-firmware.git The following commands assume that a directory exits in the top-level TFA build directory "fiptool_images". "fiptool_images" contains - u-boot.bin The binary output from the u-boot instructions above - tee-header_v2.bin - tee-pager_v2.bin - tee-pageable_v2.bin Binary outputs from the previous OPTEE build steps It is also assumed copy of mbedtls is available on the path path ../mbedtls https://github.com/ARMmbed/mbedtls.git At the time of writing HEAD points to 0592ea772aee48ca1e6d9eb84eca8e143033d973 .. code:: shell mkdir fiptool_images cp /path/to/optee/out/arm-plat-imx/core/tee-header_v2.bin fiptool_images cp /path/to/optee/out/arm-plat-imx/core/tee-pager_v2.bin fiptool_images cp /path/to/optee/out/arm-plat-imx/core/tee-pageable_v2.bin fiptool_images make CROSS_COMPILE=${CROSS_COMPILE} PLAT=warp7 ARCH=aarch32 ARM_ARCH_MAJOR=7 \ ARM_CORTEX_A7=yes AARCH32_SP=optee PLAT_WARP7_UART=1 GENERATE_COT=1 \ TRUSTED_BOARD_BOOT=1 USE_TBBR_DEFS=1 MBEDTLS_DIR=../mbedtls \ NEED_BL32=yes BL32=fiptool_images/tee-header_v2.bin \ BL32_EXTRA1=fiptool_images/tee-pager_v2.bin \ BL32_EXTRA2=fiptool_images/tee-pageable_v2.bin \ BL33=fiptool_images/u-boot.bin certificates all /path/to/u-boot/tools/mkimage -n /path/to/u-boot/u-boot.cfgout -T imximage -e 0x9df00000 -d ./build/warp7/debug/bl2.bin ./build/warp7/debug/bl2.bin.imx FIP ~~~ .. code:: shell cp /path/to/uboot/u-boot.bin fiptool_images cp /path/to/linux/arch/boot/dts/imx7s-warp.dtb fiptool_images tools/cert_create/cert_create -n --rot-key "build/warp7/debug/rot_key.pem" \ --tfw-nvctr 0 \ --ntfw-nvctr 0 \ --trusted-key-cert fiptool_images/trusted-key-cert.key-crt \ --tb-fw=build/warp7/debug/bl2.bin \ --tb-fw-cert fiptool_images/trusted-boot-fw.key-crt\ --tos-fw fiptool_images/tee-header_v2.bin \ --tos-fw-cert fiptool_images/tee-header_v2.bin.crt \ --tos-fw-key-cert fiptool_images/tee-header_v2.bin.key-crt \ --tos-fw-extra1 fiptool_images/tee-pager_v2.bin \ --tos-fw-extra2 fiptool_images/tee-pageable_v2.bin \ --nt-fw fiptool_images/u-boot.bin \ --nt-fw-cert fiptool_images/u-boot.bin.crt \ --nt-fw-key-cert fiptool_images/u-boot.bin.key-crt \ --hw-config fiptool_images/imx7s-warp.dtb tools/fiptool/fiptool create --tos-fw fiptool_images/tee-header_v2.bin \ --tos-fw-extra1 fiptool_images/tee-pager_v2.bin \ --tos-fw-extra2 fiptool_images/tee-pageable_v2.bin \ --nt-fw fiptool_images/u-boot.bin \ --hw-config fiptool_images/imx7s-warp.dtb \ --tos-fw-cert fiptool_images/tee-header_v2.bin.crt \ --tos-fw-key-cert fiptool_images/tee-header_v2.bin.key-crt \ --nt-fw-cert fiptool_images/u-boot.bin.crt \ --nt-fw-key-cert fiptool_images/u-boot.bin.key-crt \ --trusted-key-cert fiptool_images/trusted-key-cert.key-crt \ --tb-fw-cert fiptool_images/trusted-boot-fw.key-crt warp7.fip Deploy Images ------------- First place the WaRP7 into UMS mode in u-boot this should produce an entry in /dev like /dev/disk/by-id/usb-Linux_UMS_disk_0_WaRP7-0xf42400d3000001d4-0\:0 .. code:: shell => ums 0 mmc 0 Next flash bl2.imx and warp7.fip bl2.imx is flashed @ 1024 bytes warp7.fip is flash @ 1048576 bytes .. code:: shell sudo dd if=bl2.bin.imx of=/dev/disk/by-id/usb-Linux_UMS_disk_0_WaRP7-0xf42400d3000001d4-0\:0 bs=512 seek=2 conv=notrunc # Offset is 1MB 1048576 => 1048576 / 512 = 2048 sudo dd if=./warp7.fip of=/dev/disk/by-id/usb-Linux_UMS_disk_0_WaRP7-0xf42400d3000001d4-0\:0 bs=512 seek=2048 conv=notrunc Remember to umount the USB device pefore proceeding .. code:: shell sudo umount /dev/disk/by-id/usb-Linux_UMS_disk_0_WaRP7-0xf42400d3000001d4-0\:0* Signing BL2 ----------- A further step is to sign BL2. The image_sign.sh and bl2_sign.csf files alluded to blow are available here. https://github.com/bryanodonoghue/atf-code-signing It is suggested you use this script plus the example CSF file in order to avoid hard-coding data into your CSF files. Download both "image_sign.sh" and "bl2_sign.csf" to your arm-trusted-firmware top-level directory. .. code:: shell #!/bin/bash SIGN=image_sign.sh TEMP=`pwd`/temp BL2_CSF=bl2_sign.csf BL2_IMX=bl2.bin.imx CST_PATH=/path/to/cst-2.3.2 CST_BIN=${CST_PATH}/linux64/cst #Remove temp rm -rf ${TEMP} mkdir ${TEMP} # Generate IMX header /path/to/u-boot/tools/mkimage -n u-boot.cfgout.warp7 -T imximage -e 0x9df00000 -d ./build/warp7/debug/bl2.bin ./build/warp7/debug/bl2.bin.imx > ${TEMP}/${BL2_IMX}.log # Copy required items to $TEMP cp build/warp7/debug/bl2.bin.imx ${TEMP} cp ${CST_PATH}/keys/* ${TEMP} cp ${CST_PATH}/crts/* ${TEMP} cp ${BL2_CSF} ${TEMP} # Generate signed BL2 image ./${SIGN} image_sign_mbl_binary ${TEMP} ${BL2_CSF} ${BL2_IMX} ${CST_BIN} # Copy signed BL2 to top-level directory cp ${TEMP}/${BL2_IMX}-signed . cp ${BL2_RECOVER_CSF} ${TEMP} The resulting bl2.bin.imx-signed can replace bl2.bin.imx in the Deploy Images section above, once done. Suggested flow for verifying. 1. Followed all previous steps above and verify a non-secure ATF boot 2. Down the NXP Code Singing Tool 3. Generate keys 4. Program the fuses on your board 5. Replace bl2.bin.imx with bl2.bin.imx-signed 6. Verify inside u-boot that "hab_status" shows no events 7. Subsequently close your board. If you have HAB events @ step 6 - do not lock your board. To get a good over-view of generating keys and programming the fuses on the board read "High Assurance Boot for Dummies" by Boundary Devices. https://boundarydevices.com/high-assurance-boot-hab-dummies/ trusted-firmware-a-2.2/docs/plat/xilinx-versal.rst000066400000000000000000000023771355360272700223510ustar00rootroot00000000000000Xilinx Versal ============= Trusted Firmware-A implements the EL3 firmware layer for Xilinx Versal. The platform only uses the runtime part of TF-A as Xilinx Versal already has a BootROM (BL1) and PMC FW (BL2). BL31 is TF-A. BL32 is an optional Secure Payload. BL33 is the non-secure world software (U-Boot, Linux etc). To build: ```bash make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal bl31 ``` To build ATF for different platform (for now its just versal virtual "versal_virt") ```bash make RESET_TO_BL31=1 CROSS_COMPILE=aarch64-none-elf- PLAT=versal VERSAL_PLATFORM=versal_virt bl31 ``` Xilinx Versal platform specific build options --------------------------------------------- * `VERSAL_ATF_MEM_BASE`: Specifies the base address of the bl31 binary. * `VERSAL_ATF_MEM_SIZE`: Specifies the size of the memory region of the bl31 binary. * `VERSAL_BL32_MEM_BASE`: Specifies the base address of the bl32 binary. * `VERSAL_BL32_MEM_SIZE`: Specifies the size of the memory region of the bl32 binary. * `VERSAL_CONSOLE`: Select the console driver. Options: - `pl011`, `pl011_0`: ARM pl011 UART 0 - `pl011_1` : ARM pl011 UART 1 * `VERSAL_PLATFORM`: Select the platform. Options: - `versal_virt` : Versal Virtual platform trusted-firmware-a-2.2/docs/plat/xilinx-zynqmp.rst000066400000000000000000000041231355360272700224020ustar00rootroot00000000000000Xilinx Zynq UltraScale+ MPSoC ============================= Trusted Firmware-A (TF-A) implements the EL3 firmware layer for Xilinx Zynq UltraScale + MPSoC. The platform only uses the runtime part of TF-A as ZynqMP already has a BootROM (BL1) and FSBL (BL2). BL31 is TF-A. BL32 is an optional Secure Payload. BL33 is the non-secure world software (U-Boot, Linux etc). To build: .. code:: bash make CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp bl31 To build bl32 TSP you have to rebuild bl31 too: .. code:: bash make CROSS_COMPILE=aarch64-none-elf- PLAT=zynqmp SPD=tspd bl31 bl32 ZynqMP platform specific build options -------------------------------------- - ``ZYNQMP_ATF_MEM_BASE``: Specifies the base address of the bl31 binary. - ``ZYNQMP_ATF_MEM_SIZE``: Specifies the size of the memory region of the bl31 binary. - ``ZYNQMP_BL32_MEM_BASE``: Specifies the base address of the bl32 binary. - ``ZYNQMP_BL32_MEM_SIZE``: Specifies the size of the memory region of the bl32 binary. - ``ZYNQMP_CONSOLE``: Select the console driver. Options: - ``cadence``, ``cadence0``: Cadence UART 0 - ``cadence1`` : Cadence UART 1 FSBL->TF-A Parameter Passing ---------------------------- The FSBL populates a data structure with image information for TF-A. TF-A uses that data to hand off to the loaded images. The address of the handoff data structure is passed in the ``PMU_GLOBAL.GLOBAL_GEN_STORAGE6`` register. The register is free to be used by other software once TF-A has brought up further firmware images. Power Domain Tree ----------------- The following power domain tree represents the power domain model used by TF-A for ZynqMP: :: +-+ |0| +-+ +-------+---+---+-------+ | | | | | | | | v v v v +-+ +-+ +-+ +-+ |0| |1| |2| |3| +-+ +-+ +-+ +-+ The 4 leaf power domains represent the individual A53 cores, while resources common to the cluster are grouped in the power domain on the top. trusted-firmware-a-2.2/docs/process/000077500000000000000000000000001355360272700175175ustar00rootroot00000000000000trusted-firmware-a-2.2/docs/process/coding-guidelines.rst000066400000000000000000000545441355360272700236560ustar00rootroot00000000000000Coding Style & Guidelines ========================= The following sections contain TF coding guidelines. They are continually evolving and should not be considered "set in stone". Feel free to question them and provide feedback. Some of the guidelines may also apply to other codebases. .. note:: The existing TF codebase does not necessarily comply with all the below guidelines but the intent is for it to do so eventually. Checkpatch overrides -------------------- Some checkpatch warnings in the TF codebase are deliberately ignored. These include: - ``**WARNING: line over 80 characters**``: Although the codebase should generally conform to the 80 character limit this is overly restrictive in some cases. - ``**WARNING: Use of volatile is usually wrong``: see `Why the “volatile†type class should not be used`_ . Although this document contains some very useful information, there are several legitimate uses of the volatile keyword within the TF codebase. Headers and inclusion --------------------- Header guards ^^^^^^^^^^^^^ For a header file called "some_driver.h" the style used by the Trusted Firmware is: .. code:: c #ifndef SOME_DRIVER_H #define SOME_DRIVER_H
#endif /* SOME_DRIVER_H */ Include statement ordering ^^^^^^^^^^^^^^^^^^^^^^^^^^ All header files that are included by a source file must use the following, grouped ordering. This is to improve readability (by making it easier to quickly read through the list of headers) and maintainability. #. *System* includes: Header files from the standard *C* library, such as ``stddef.h`` and ``string.h``. #. *Project* includes: Header files under the ``include/`` directory within TF are *project* includes. #. *Platform* includes: Header files relating to a single, specific platform, and which are located under the ``plat/`` directory within TF, are *platform* includes. Within each group, ``#include`` statements must be in alphabetical order, taking both the file and directory names into account. Groups must be separated by a single blank line for clarity. The example below illustrates the ordering rules using some contrived header file names; this type of name reuse should be otherwise avoided. .. code:: c #include #include #include #include #include #include "./a_header.h" Include statement variants ^^^^^^^^^^^^^^^^^^^^^^^^^^ Two variants of the ``#include`` directive are acceptable in the TF codebase. Correct use of the two styles improves readability by suggesting the location of the included header and reducing ambiguity in cases where generic and platform-specific headers share a name. For header files that are in the same directory as the source file that is including them, use the ``"..."`` variant. For header files that are **not** in the same directory as the source file that is including them, use the ``<...>`` variant. Example (bl1_fwu.c): .. code:: c #include #include #include #include "bl1_private.h" Platform include paths ^^^^^^^^^^^^^^^^^^^^^^ Platforms are allowed to add more include paths to be passed to the compiler. The ``PLAT_INCLUDES`` variable is used for this purpose. This is needed in particular for the file ``platform_def.h``. Example: .. code:: c PLAT_INCLUDES += -Iinclude/plat/myplat/include Types and typedefs ------------------ Use of built-in *C* and *libc* data types ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The TF codebase should be kept as portable as possible, especially since both 64-bit and 32-bit platforms are supported. To help with this, the following data type usage guidelines should be followed: - Where possible, use the built-in *C* data types for variable storage (for example, ``char``, ``int``, ``long long``, etc) instead of the standard *C99* types. Most code is typically only concerned with the minimum size of the data stored, which the built-in *C* types guarantee. - Avoid using the exact-size standard *C99* types in general (for example, ``uint16_t``, ``uint32_t``, ``uint64_t``, etc) since they can prevent the compiler from making optimizations. There are legitimate uses for them, for example to represent data of a known structure. When using them in struct definitions, consider how padding in the struct will work across architectures. For example, extra padding may be introduced in AArch32 systems if a struct member crosses a 32-bit boundary. - Use ``int`` as the default integer type - it's likely to be the fastest on all systems. Also this can be assumed to be 32-bit as a consequence of the `Procedure Call Standard for the Arm Architecture`_ and the `Procedure Call Standard for the Arm 64-bit Architecture`_ . - Avoid use of ``short`` as this may end up being slower than ``int`` in some systems. If a variable must be exactly 16-bit, use ``int16_t`` or ``uint16_t``. - Avoid use of ``long``. This is guaranteed to be at least 32-bit but, given that `int` is 32-bit on Arm platforms, there is no use for it. For integers of at least 64-bit, use ``long long``. - Use ``char`` for storing text. Use ``uint8_t`` for storing other 8-bit data. - Use ``unsigned`` for integers that can never be negative (counts, indices, sizes, etc). TF intends to comply with MISRA "essential type" coding rules (10.X), where signed and unsigned types are considered different essential types. Choosing the correct type will aid this. MISRA static analysers will pick up any implicit signed/unsigned conversions that may lead to unexpected behaviour. - For pointer types: - If an argument in a function declaration is pointing to a known type then simply use a pointer to that type (for example: ``struct my_struct *``). - If a variable (including an argument in a function declaration) is pointing to a general, memory-mapped address, an array of pointers or another structure that is likely to require pointer arithmetic then use ``uintptr_t``. This will reduce the amount of casting required in the code. Avoid using ``unsigned long`` or ``unsigned long long`` for this purpose; it may work but is less portable. - For other pointer arguments in a function declaration, use ``void *``. This includes pointers to types that are abstracted away from the known API and pointers to arbitrary data. This allows the calling function to pass a pointer argument to the function without any explicit casting (the cast to ``void *`` is implicit). The function implementation can then do the appropriate casting to a specific type. - Use ``ptrdiff_t`` to compare the difference between 2 pointers. - Use ``size_t`` when storing the ``sizeof()`` something. - Use ``ssize_t`` when returning the ``sizeof()`` something from a function that can also return an error code; the signed type allows for a negative return code in case of error. This practice should be used sparingly. - Use ``u_register_t`` when it's important to store the contents of a register in its native size (32-bit in AArch32 and 64-bit in AArch64). This is not a standard *C99* type but is widely available in libc implementations, including the FreeBSD version included with the TF codebase. Where possible, cast the variable to a more appropriate type before interpreting the data. For example, the following struct in ``ep_info.h`` could use this type to minimize the storage required for the set of registers: .. code:: c typedef struct aapcs64_params { u_register_t arg0; u_register_t arg1; u_register_t arg2; u_register_t arg3; u_register_t arg4; u_register_t arg5; u_register_t arg6; u_register_t arg7; } aapcs64_params_t; If some code wants to operate on ``arg0`` and knows that it represents a 32-bit unsigned integer on all systems, cast it to ``unsigned int``. These guidelines should be updated if additional types are needed. Avoid anonymous typedefs of structs/enums in headers ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ For example, the following definition: .. code:: c typedef struct { int arg1; int arg2; } my_struct_t; is better written as: .. code:: c struct my_struct { int arg1; int arg2; }; This allows function declarations in other header files that depend on the struct/enum to forward declare the struct/enum instead of including the entire header: .. code:: c #include void my_func(my_struct_t *arg); instead of: .. code:: c struct my_struct; void my_func(struct my_struct *arg); Some TF definitions use both a struct/enum name **and** a typedef name. This is discouraged for new definitions as it makes it difficult for TF to comply with MISRA rule 8.3, which states that "All declarations of an object or function shall use the same names and type qualifiers". The Linux coding standards also discourage new typedefs and checkpatch emits a warning for this. Existing typedefs will be retained for compatibility. Libc functions that are banned or to be used with caution --------------------------------------------------------- Below is a list of functions that present security risks and either must not be used (Banned) or are discouraged from use and must be used with care (Caution). +------------------------+-----------+--------------------------------------+ | libc function | Status | Comments | +========================+===========+======================================+ | ``strcpy, wcscpy``, | Banned | use strlcpy instead | | ``strncpy`` | | | +------------------------+-----------+--------------------------------------+ | ``strcat, wcscat``, | Banned | use strlcat instead | | ``strncat`` | | | +------------------------+-----------+--------------------------------------+ | ``sprintf, vsprintf`` | Banned | use snprintf, vsnprintf | | | | instead | +------------------------+-----------+--------------------------------------+ | ``snprintf`` | Caution | ensure result fits in buffer | | | | i.e : snprintf(buf,size...) < size | +------------------------+-----------+--------------------------------------+ | ``vsnprintf`` | Caution | inspect va_list match types | | | | specified in format string | +------------------------+-----------+--------------------------------------+ | ``strtok`` | Banned | use strtok_r or strsep instead | +------------------------+-----------+--------------------------------------+ | ``strtok_r, strsep`` | Caution | inspect for terminated input buffer | +------------------------+-----------+--------------------------------------+ | ``ato*`` | Banned | use equivalent strto* functions | +------------------------+-----------+--------------------------------------+ | ``*toa`` | Banned | Use snprintf instead | +------------------------+-----------+--------------------------------------+ The `libc` component in the codebase will not add support for the banned APIs. Error handling and robustness ----------------------------- Using CASSERT to check for compile time data errors ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Where possible, use the ``CASSERT`` macro to check the validity of data known at compile time instead of checking validity at runtime, to avoid unnecessary runtime code. For example, this can be used to check that the assembler's and compiler's views of the size of an array is the same. .. code:: c #include define MY_STRUCT_SIZE 8 /* Used by assembler source files */ struct my_struct { uint32_t arg1; uint32_t arg2; }; CASSERT(MY_STRUCT_SIZE == sizeof(struct my_struct), assert_my_struct_size_mismatch); If ``MY_STRUCT_SIZE`` in the above example were wrong then the compiler would emit an error like this: :: my_struct.h:10:1: error: size of array ‘assert_my_struct_size_mismatch’ is negative Using assert() to check for programming errors ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In general, each secure world TF image (BL1, BL2, BL31 and BL32) should be treated as a tightly integrated package; the image builder should be aware of and responsible for all functionality within the image, even if code within that image is provided by multiple entities. This allows us to be more aggressive in interpreting invalid state or bad function arguments as programming errors using ``assert()``, including arguments passed across platform porting interfaces. This is in contrast to code in a Linux environment, which is less tightly integrated and may attempt to be more defensive by passing the error back up the call stack. Where possible, badly written TF code should fail early using ``assert()``. This helps reduce the amount of untested conditional code. By default these statements are not compiled into release builds, although this can be overridden using the ``ENABLE_ASSERTIONS`` build flag. Examples: - Bad argument supplied to library function - Bad argument provided by platform porting function - Internal secure world image state is inconsistent Handling integration errors ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Each secure world image may be provided by a different entity (for example, a Trusted Boot vendor may provide the BL2 image, a TEE vendor may provide the BL32 image and the OEM/SoC vendor may provide the other images). An image may contain bugs that are only visible when the images are integrated. The system integrator may not even have access to the debug variants of all the images in order to check if asserts are firing. For example, the release variant of BL1 may have already been burnt into the SoC. Therefore, TF code that detects an integration error should _not_ consider this a programming error, and should always take action, even in release builds. If an integration error is considered non-critical it should be treated as a recoverable error. If the error is considered critical it should be treated as an unexpected unrecoverable error. Handling recoverable errors ^^^^^^^^^^^^^^^^^^^^^^^^^^^ The secure world **must not** crash when supplied with bad data from an external source. For example, data from the normal world or a hardware device. Similarly, the secure world **must not** crash if it detects a non-critical problem within itself or the system. It must make every effort to recover from the problem by emitting a ``WARN`` message, performing any necessary error handling and continuing. Examples: - Secure world receives SMC from normal world with bad arguments. - Secure world receives SMC from normal world at an unexpected time. - BL31 receives SMC from BL32 with bad arguments. - BL31 receives SMC from BL32 at unexpected time. - Secure world receives recoverable error from hardware device. Retrying the operation may help here. - Non-critical secure world service is not functioning correctly. - BL31 SPD discovers minor configuration problem with corresponding SP. Handling unrecoverable errors ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In some cases it may not be possible for the secure world to recover from an error. This situation should be handled in one of the following ways: 1. If the unrecoverable error is unexpected then emit an ``ERROR`` message and call ``panic()``. This will end up calling the platform-specific function ``plat_panic_handler()``. 2. If the unrecoverable error is expected to occur in certain circumstances, then emit an ``ERROR`` message and call the platform-specific function ``plat_error_handler()``. Cases 1 and 2 are subtly different. A platform may implement ``plat_panic_handler`` and ``plat_error_handler`` in the same way (for example, by waiting for a secure watchdog to time-out or by invoking an interface on the platform's power controller to reset the platform). However, ``plat_error_handler`` may take additional action for some errors (for example, it may set a flag so the platform resets into a different mode). Also, ``plat_panic_handler()`` may implement additional debug functionality (for example, invoking a hardware breakpoint). Examples of unexpected unrecoverable errors: - BL32 receives an unexpected SMC response from BL31 that it is unable to recover from. - BL31 Trusted OS SPD code discovers that BL2 has not loaded the corresponding Trusted OS, which is critical for platform operation. - Secure world discovers that a critical hardware device is an unexpected and unrecoverable state. - Secure world receives an unexpected and unrecoverable error from a critical hardware device. - Secure world discovers that it is running on unsupported hardware. Examples of expected unrecoverable errors: - BL1/BL2 fails to load the next image due to missing/corrupt firmware on disk. - BL1/BL2 fails to authenticate the next image due to an invalid certificate. - Secure world continuously receives recoverable errors from a hardware device but is unable to proceed without a valid response. Handling critical unresponsiveness ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If the secure world is waiting for a response from an external source (for example, the normal world or a hardware device) which is critical for continued operation, it must not wait indefinitely. It must have a mechanism (for example, a secure watchdog) for resetting itself and/or the external source to prevent the system from executing in this state indefinitely. Examples: - BL1 is waiting for the normal world to raise an SMC to proceed to the next stage of the secure firmware update process. - A Trusted OS is waiting for a response from a proxy in the normal world that is critical for continued operation. - Secure world is waiting for a hardware response that is critical for continued operation. Security considerations ----------------------- Part of the security of a platform is handling errors correctly, as described in the previous section. There are several other security considerations covered in this section. Do not leak secrets to the normal world ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The secure world **must not** leak secrets to the normal world, for example in response to an SMC. Handling Denial of Service attacks ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The secure world **should never** crash or become unusable due to receiving too many normal world requests (a *Denial of Service* or *DoS* attack). It should have a mechanism for throttling or ignoring normal world requests. Performance considerations -------------------------- Avoid printf and use logging macros ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ``debug.h`` provides logging macros (for example, ``WARN`` and ``ERROR``) which wrap ``tf_log`` and which allow the logging call to be compiled-out depending on the ``make`` command. Use these macros to avoid print statements being compiled unconditionally into the binary. Each logging macro has a numerical log level: .. code:: c #define LOG_LEVEL_NONE 0 #define LOG_LEVEL_ERROR 10 #define LOG_LEVEL_NOTICE 20 #define LOG_LEVEL_WARNING 30 #define LOG_LEVEL_INFO 40 #define LOG_LEVEL_VERBOSE 50 By default, all logging statements with a log level ``<= LOG_LEVEL_INFO`` will be compiled into debug builds and all statements with a log level ``<= LOG_LEVEL_NOTICE`` will be compiled into release builds. This can be overridden from the command line or by the platform makefile (although it may be necessary to clean the build directory first). For example, to enable ``VERBOSE`` logging on FVP: ``make PLAT=fvp LOG_LEVEL=50 all`` Use const data where possible ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ For example, the following code: .. code:: c struct my_struct { int arg1; int arg2; }; void init(struct my_struct *ptr); void main(void) { struct my_struct x; x.arg1 = 1; x.arg2 = 2; init(&x); } is better written as: .. code:: c struct my_struct { int arg1; int arg2; }; void init(const struct my_struct *ptr); void main(void) { const struct my_struct x = { 1, 2 }; init(&x); } This allows the linker to put the data in a read-only data section instead of a writeable data section, which may result in a smaller and faster binary. Note that this may require dependent functions (``init()`` in the above example) to have ``const`` arguments, assuming they don't need to modify the data. Library and driver code ----------------------- TF library code (under ``lib/`` and ``include/lib``) is any code that provides a reusable interface to other code, potentially even to code outside of TF. In some systems drivers must conform to a specific driver framework to provide services to the rest of the system. TF has no driver framework and the distinction between a driver and library is somewhat subjective. A driver (under ``drivers/`` and ``include/drivers/``) is defined as code that interfaces with hardware via a memory mapped interface. Some drivers (for example, the Arm CCI driver in ``include/drivers/arm/cci.h``) provide a general purpose API to that specific hardware. Other drivers (for example, the Arm PL011 console driver in ``drivers/arm/pl011/pl011_console.S``) provide a specific hardware implementation of a more abstract library API. In the latter case there may potentially be multiple drivers for the same hardware device. Neither libraries nor drivers should depend on platform-specific code. If they require platform-specific data (for example, a base address) to operate then they should provide an initialization function that takes the platform-specific data as arguments. TF common code (under ``common/`` and ``include/common/``) is code that is re-used by other generic (non-platform-specific) TF code. It is effectively internal library code. .. _`Why the “volatile†type class should not be used`: https://www.kernel.org/doc/html/latest/process/volatile-considered-harmful.html .. _`Procedure Call Standard for the Arm Architecture`: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042f/IHI0042F_aapcs.pdf .. _`Procedure Call Standard for the Arm 64-bit Architecture`: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0055b/IHI0055B_aapcs64.pdf trusted-firmware-a-2.2/docs/process/contributing.rst000066400000000000000000000157031355360272700227660ustar00rootroot00000000000000Contributor's Guide =================== Getting Started --------------- - Make sure you have a Github account and you are logged on `developer.trustedfirmware.org`_. - Create an `issue`_ for your work if one does not already exist. This gives everyone visibility of whether others are working on something similar. - If you intend to include Third Party IP in your contribution, please raise a separate `issue`_ for this and ensure that the changes that include Third Party IP are made on a separate topic branch. - Clone `Trusted Firmware-A`_ on your own machine as suggested in the :ref:`User Guide`. - Create a local topic branch based on the `Trusted Firmware-A`_ ``master`` branch. Making Changes -------------- - Make commits of logical units. See these general `Git guidelines`_ for contributing to a project. - Follow the :ref:`Coding Style & Guidelines`. - Use the checkpatch.pl script provided with the Linux source tree. A Makefile target is provided for convenience (see the "Checking source code style" section in the :ref:`User Guide`). - Keep the commits on topic. If you need to fix another bug or make another enhancement, please create a separate `issue`_ and address it on a separate topic branch. - Avoid long commit series. If you do have a long series, consider whether some commits should be squashed together or addressed in a separate topic. - Make sure your commit messages are in the proper format. If a commit fixes an `issue`_, include a reference. - Where appropriate, please update the documentation. - Consider whether the :ref:`User Guide`, :ref:`Porting Guide`, :ref:`Firmware Design` or other in-source documentation needs updating. - Ensure that each changed file has the correct copyright and license information. Files that entirely consist of contributions to this project should have a copyright notice and BSD-3-Clause SPDX license identifier of the form as shown in :ref:`license`. Files that contain changes to imported Third Party IP files should retain their original copyright and license notices. For significant contributions you may add your own copyright notice in following format: :: Portions copyright (c) [XXXX-]YYYY, . All rights reserved. where XXXX is the year of first contribution (if different to YYYY) and YYYY is the year of most recent contribution. is your name or your company name. - If you are submitting new files that you intend to be the technical sub-maintainer for (for example, a new platform port), then also update the :ref:`maintainers` file. - For topics with multiple commits, you should make all documentation changes (and nothing else) in the last commit of the series. Otherwise, include the documentation changes within the single commit. - Please test your changes. As a minimum, ensure that Linux boots on the Foundation FVP. See :ref:`user_guide_run_fvp` for more information. For more extensive testing, consider running the `TF-A Tests`_ against your patches. Submitting Changes ------------------ - Ensure that each commit in the series has at least one ``Signed-off-by:`` line, using your real name and email address. The names in the ``Signed-off-by:`` and ``Author:`` lines must match. If anyone else contributes to the commit, they must also add their own ``Signed-off-by:`` line. By adding this line the contributor certifies the contribution is made under the terms of the :download:`Developer Certificate of Origin <../../dco.txt>`. More details may be found in the `Gerrit Signed-off-by Lines guidelines`_. - Ensure that each commit also has a unique ``Change-Id:`` line. If you have cloned the repository with the "`Clone with commit-msg hook`" clone method (as advised on the :ref:`User Guide`), this should already be the case. More details may be found in the `Gerrit Change-Ids documentation`_. - Submit your changes for review at https://review.trustedfirmware.org targeting the ``integration`` branch. - The changes will then undergo further review and testing by the :ref:`maintainers`. Any review comments will be made directly on your patch. This may require you to do some rework. Refer to the `Gerrit Uploading Changes documentation`_ for more details. - When the changes are accepted, the :ref:`maintainers` will integrate them. - Typically, the :ref:`maintainers` will merge the changes into the ``integration`` branch. - If the changes are not based on a sufficiently-recent commit, or if they cannot be automatically rebased, then the :ref:`maintainers` may rebase it on the ``master`` branch or ask you to do so. - After final integration testing, the changes will make their way into the ``master`` branch. If a problem is found during integration, the merge commit will be removed from the ``integration`` branch and the :ref:`maintainers` will ask you to create a new patch set to resolve the problem. Binary Components ----------------- - Platforms may depend on binary components submitted to the `Trusted Firmware binary repository`_ if they require code that the contributor is unable or unwilling to open-source. This should be used as a rare exception. - All binary components must follow the contribution guidelines (in particular licensing rules) outlined in the `readme.rst `_ file of the binary repository. - Binary components must be restricted to only the specific functionality that cannot be open-sourced and must be linked into a larger open-source platform port. The majority of the platform port must still be implemented in open source. Platform ports that are merely a thin wrapper around a binary component that contains all the actual code will not be accepted. - Only platform port code (i.e. in the ``plat/`` directory) may rely on binary components. Generic code must always be fully open-source. -------------- *Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.* .. _developer.trustedfirmware.org: https://developer.trustedfirmware.org .. _issue: https://developer.trustedfirmware.org/project/board/1/ .. _Trusted Firmware-A: https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git .. _Git guidelines: http://git-scm.com/book/ch5-2.html .. _Gerrit Uploading Changes documentation: https://review.trustedfirmware.org/Documentation/user-upload.html .. _Gerrit Signed-off-by Lines guidelines: https://review.trustedfirmware.org/Documentation/user-signedoffby.html .. _Gerrit Change-Ids documentation: https://review.trustedfirmware.org/Documentation/user-changeid.html .. _TF-A Tests: https://git.trustedfirmware.org/TF-A/tf-a-tests.git/about/ .. _Trusted Firmware binary repository: https://review.trustedfirmware.org/admin/repos/tf-binaries .. _tf-binaries-readme: https://git.trustedfirmware.org/tf-binaries.git/tree/readme.rst trusted-firmware-a-2.2/docs/process/faq.rst000066400000000000000000000076131355360272700210270ustar00rootroot00000000000000Frequently-Asked Questions (FAQ) ================================ How do I update my changes? --------------------------- Often it is necessary to update your patch set before it is merged. Refer to the `Gerrit Upload Patch Set documentation`_ on how to do so. If you need to modify an existing patch set with multiple commits, refer to the `Gerrit Replace Changes documentation`_. How long will my changes take to merge into ``integration``? ------------------------------------------------------------ This can vary a lot, depending on: * How important the patch set is considered by the TF maintainers. Where possible, you should indicate the required timescales for merging the patch set and the impact of any delay. Feel free to add a comment to your patch set to get an estimate of when it will be merged. * The quality of the patch set. Patches are likely to be merged more quickly if they follow the coding guidelines, have already had some code review, and have been appropriately tested. * The impact of the patch set. For example, a patch that changes a key generic API is likely to receive much greater scrutiny than a local change to a specific platform port. * How much opportunity for external review is required. For example, the TF maintainers may not wait for external review comments to merge trivial bug-fixes but may wait up to a week to merge major changes, or ones requiring feedback from specific parties. * How many other patch sets are waiting to be integrated and the risk of conflict between the topics. * If there is a code freeze in place in preparation for the release. Please refer the :ref:`Release Processes` document for more details. * The workload of the TF maintainers. How long will it take for my changes to go from ``integration`` to ``master``? ------------------------------------------------------------------------------ This depends on how many concurrent patches are being processed at the same time. In simple cases where all potential regressions have already been tested, the delay will be less than 1 day. If the TF maintainers are trying to merge several things over the course of a few days, it might take up to a week. Typically, it will be 1-2 days. The worst case is if the TF maintainers are trying to make a release while also receiving patches that will not be merged into the release. In this case, the patches will be merged onto ``integration``, which will temporarily diverge from the release branch. The ``integration`` branch will be rebased onto ``master`` after the release, and then ``master`` will be fast-forwarded to ``integration`` 1-2 days later. This whole process could take up 4 weeks. Please refer to the :ref:`Release Processes` document for code freeze dates. The TF maintainers will inform the patch owner if this is going to happen. It is OK to create a patch based on commits that are only available in ``integration`` or another patch set, rather than ``master``. There is a risk that the dependency commits will change (for example due to patch set rework or integration problems). If this happens, the dependent patch will need reworking. What are these strange comments in my changes? ---------------------------------------------- All the comments from ``ci-bot-user`` are associated with Continuous Integration infrastructure. The links published on the comment are not currently accessible, but would be after the CI has been transitioned to `trustedfirmware.org`_. Please refer to https://github.com/ARM-software/tf-issues/issues/681 for more details on the timelines. -------------- *Copyright (c) 2019, Arm Limited. All rights reserved.* .. _Gerrit Upload Patch Set documentation: https://review.trustedfirmware.org/Documentation/intro-user.html#upload-patch-set .. _Gerrit Replace Changes documentation: https://review.trustedfirmware.org/Documentation/user-upload.html#push_replace .. _trustedfirmware.org: https://www.trustedfirmware.org/ trusted-firmware-a-2.2/docs/process/index.rst000066400000000000000000000003341355360272700213600ustar00rootroot00000000000000Processes & Policies ==================== .. toctree:: :maxdepth: 1 :caption: Contents :numbered: security platform-compatibility-policy coding-guidelines contributing faq security-hardening trusted-firmware-a-2.2/docs/process/platform-compatibility-policy.rst000066400000000000000000000031561355360272700262460ustar00rootroot00000000000000Platform Compatibility Policy ============================= Introduction ------------ This document clarifies the project's policy around compatibility for upstream platforms. Platform compatibility policy ----------------------------- Platform compatibility is mainly affected by changes to Platform APIs (as documented in the :ref:`Porting Guide`), driver APIs (like the GICv3 drivers) or library interfaces (like xlat_table library). The project will try to maintain compatibility for upstream platforms. Due to evolving requirements and enhancements, there might be changes affecting platform compatibility which means the previous interface needs to be deprecated and a new interface introduced to replace it. In case the migration to the new interface is trivial, the contributor of the change is expected to make good effort to migrate the upstream platforms to the new interface. The deprecated interfaces are listed inside :ref:`Release Processes` as well as the release after which each one will be removed. When an interface is deprecated, the page must be updated to indicate the release after which the interface will be removed. This must be at least 1 full release cycle in future. For non-trivial interface changes, an email should be sent out to the `TF-A public mailing list`_ to notify platforms that they should migrate away from the deprecated interfaces. Platforms are expected to migrate before the removal of the deprecated interface. -------------- *Copyright (c) 2018-2019, Arm Limited and Contributors. All rights reserved.* .. _TF-A public mailing list: https://lists.trustedfirmware.org/mailman/listinfo/tf-a trusted-firmware-a-2.2/docs/process/security-hardening.rst000066400000000000000000000036361355360272700240650ustar00rootroot00000000000000Security hardening ================== This page contains guidance on what to check for additional security measures, including build options that can be modified to improve security or catch issues early in development. Build options ------------- Several build options can be used to check for security issues. Refer to the :ref:`User Guide` for detailed information on the specific build options. - The ``BRANCH_PROTECTION`` build flag can be used to enable Pointer Authentication and Branch Target Identification. - The ``ENABLE_STACK_PROTECTOR`` build flag can be used to identify buffer overflows. - The ``W`` build flag can be used to enable a number of compiler warning options to detect potentially incorrect code. - W=0 (default value) The ``Wunused`` with ``Wno-unused-parameter``, ``Wdisabled-optimization`` and ``Wvla`` flags are enabled. The ``Wunused-but-set-variable``, ``Wmaybe-uninitialized`` and ``Wpacked-bitfield-compat`` are GCC specific flags that are also enabled. - W=1 Adds ``Wextra``, ``Wmissing-declarations``, ``Wmissing-format-attribute``, ``Wmissing-prototypes``, ``Wold-style-definition`` and ``Wunused-const-variable``. - W=2 Adds ``Waggregate-return``, ``Wcast-align``, ``Wnested-externs``, ``Wshadow``, ``Wlogical-op``, ``Wmissing-field-initializers`` and ``Wsign-compare``. - W=3 Adds ``Wbad-function-cast``, ``Wcast-qual``, ``Wconversion``, ``Wpacked``, ``Wpadded``, ``Wpointer-arith``, ``Wredundant-decls`` and ``Wswitch-default``. Refer to the GCC or Clang documentation for more information on the individual options: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html and https://clang.llvm.org/docs/DiagnosticsReference.html. NB: The ``Werror`` flag is enabled by default in TF-A and can be disabled by setting the ``E`` build flag to 0. -------------- *Copyright (c) 2019, Arm Limited. All rights reserved.* trusted-firmware-a-2.2/docs/process/security-reporting.asc000066400000000000000000000051541355360272700240720ustar00rootroot00000000000000-----BEGIN PGP PUBLIC KEY BLOCK----- Version: PGP Desktop 10.2.0 (Build 2317) mQENBFey/QMBCACyxJaLsMYU794ZfzLdY172tHXRJfP0X3b34HU35G7kYl1zNiYc /NoygtQdtDv/aW1B2A/YTNhGge+gX4BWAREd5CYDbdPEoMWC395/qbnmMmez7YNY PEJ9Iq9e5AayAWwZTL1zgKwdvE+WTwWok/nMbsifJSEdhdrOIHNqRcZgplUUyZ2R sDqFtSbACO3xj4Psk8KJ23Ax7UZgULouZOJaHOnyq8F9V/U7zWvX4Odf96XaC1Em cUTsG0kQfa7Y4Hqqjzowq366I4k2o2LAtuLPWNCvq5jjEceLs2+qV4cNLgyL2dzO wtUL6EdkrGfkxsPHpsVKXig4wjeX9ehCSqRlABEBAAG0PVRydXN0ZWQgRmlybXdh cmUgU2VjdXJpdHkgPHRydXN0ZWQtZmlybXdhcmUtc2VjdXJpdHlAYXJtLmNvbT6J AYwEEAECAHYFAley/SEwFIAAAAAAIAAHcHJlZmVycmVkLWVtYWlsLWVuY29kaW5n QHBncC5jb21wZ3BtaW1lCAsJCAcDAgEKAhkBGRhsZGFwOi8va2V5c2VydmVyLnBn cC5jb20FGwMAAAAFFgADAgEFHgEAAAAGFQgJCgMCAAoJEDq378tFoN/QFJsH/0ly H91LYYzKIQrbolQw7Rp47lgzH88uN1rInYpW2GaTbjwPffAhYJ4VsN8RaiFskD9m DjMg4vY8p0jPTCUX1Acq20Wq0Ybv3HcrtjUp4ie0+rLUi3043yJyKFMWkJC2Kr+p SobnxSrAie4HDFUgSaPoh9Qf1zXEzOavdgcziMiyS5iVUf6NXYZ9z82OTZ6TdPKS u+L5zOHTdrV3+hD54w00Xa+EIE7u4v0to6Uwm977508hyGuvpOVq+u7+S3qJQvnY +JheStbgLsm6CyoRjyrlTE01ujAD6hI6Ef9yMgEljOBEy4phKAJ67SCRLEOiCp5U YHFCULwhzIyg2y3WmZSJASIEEAECAAwFAlezAnwFAwASdQAACgkQlxC4m8pXrXzd GAf/T8YEICI9qQt2vnCtCbBvVaTc2sAphVZ51kZVDqCDPB7znDtJYRBpi/9IPELt mYwIElMx2mqmahVaeUghmbzmcLZe8QHUi8GanO1mh+ook6uyjRojSIq6VUVV5uUf tuscfhpilOvUclqMqYEIgXfl08YwS40Kmmj0qokwad0co0zGQ8GEhlgMi2yvJfiG fPS0Xcn1J0980E/VgJQCAKwZvukrbb32WVwuhgepqs/4/62PZNxglcErioFt6P0A ik4t9Hr0uErqCeEKiYtmEw5e9ioRdX7CV+tJgIk907Tpv6E0iDFRJHmJBvmsz82O stOazS3wZ5Xck7asTqkvoyo9Z7kBDQRXsv0DAQgAsmL1UUIWyoNmYJWixSPDmclP 0ul3T1FCOsIlWTeVeshnHByYdgZOfce78ETCUoq8G7qvYm4GRrEDpqVbxqTxJioP 4Li05WDdNCKzSoqWd8ADA48gYnnJEu2NhA7ZkEC6u3+Mdbmd3M0J6nsAWeE0BV1p F5zI600sJuoH2QNWB7Kv5N3GCFE4IgCIH8MwDo4Y4FTZtygx4GjEtSExiOIz+bpX 2+GkFCQGpIyLHLP4FmQmrsNzsIdEyFuG0IdoVuQ2PtNLiw+Wkm7CXWgRmFx/dtPN eVnOFWdbTtjBWVv/Z6zbANos2knfc75KR4FCQ6pWRvVeJuMuMopUDkfFDMtR8QAR AQABiQJBBBgBAgErBQJXsv0EBRsMAAAAwF0gBBkBCAAGBQJXsv0DAAoJENaB8ph8 s9hu/nsH/Rx696ZR+1vZi5qCTUwo6s0Qa15x4OuyJEM85VgMLVY7/MZpp1Y8If6u A5BynQpy4QIPxIRsRx6twduW9/gb8UVhpMRPyuJ+5sSv0/KeUqkPbKSUGro2zGlR sjqPrchi6uafWZqOR/y/DNkEvkgZZaP+f9xs2qWKuoF08yTioo76QoroA4DVuVAT MkDFe9d3natAmfmjO4kvxuthg3y7R+sdXrCHpYYJZdbiR6gyj7e8whlSLwHQT3lz 7QBL/CvVvL/dmhu5pk8fsksbehepMQTkCJ6GGEamOPEhwh7IvlzhEt97U4uzjuMd BPjqOCes+4QTmn/+lMTySG0kXxnHOEUACgkQOrfvy0Wg39D8Jgf/Uf3epkMOJ9xm N1l5vW8tQQ6RR055YQxQ9P6JMyCQGEJmGOcvrasCho69wMQDy4AYVtJaZd25LH/3 LX/lcyDOP4C9VYXM+IxlcaRmjBKqWx9UzQeeioIkfmjMpJFU846ZP1dacge0lPx8 p6ocPbM0rkv0xuF/dwkDQd4BPSmv4/3/UM8FRoYo8Q7SHkDR98wJ8FCm6k9wRtWC K/jzmBswY2TewAHom3jLzTM0FZ/n5Sini3EGAI2EvnQrxWRpeE7ZOkHKqLHEOaHl zeST4U/cUgxhwgnhbGJ7zmrFsHpYnnZYM3mIKfQ3/EhksZ68TF9IB1tfUiQTij4r 9jWa0ybRdQ== =nZZb -----END PGP PUBLIC KEY BLOCK----- trusted-firmware-a-2.2/docs/process/security.rst000066400000000000000000000120231355360272700221160ustar00rootroot00000000000000Security Handling ================= Security Disclosures -------------------- We disclose all security vulnerabilities we find, or are advised about, that are relevant to Trusted Firmware-A. We encourage responsible disclosure of vulnerabilities and inform users as best we can about all possible issues. We disclose TF-A vulnerabilities as Security Advisories, all of which are listed at the bottom of this page. Any new ones will, additionally, be announced as issues in the project's `issue tracker`_ with the ``security-advisory`` tag. You can receive notification emails for these by watching the "Trusted Firmware-A" project at https://developer.trustedfirmware.org/. Found a Security Issue? ----------------------- Although we try to keep TF-A secure, we can only do so with the help of the community of developers and security researchers. If you think you have found a security vulnerability, please **do not** report it in the `issue tracker`_. Instead send an email to trusted-firmware-security@arm.com Please include: * Trusted Firmware-A version (or commit) affected * A description of the concern or vulnerability * Details on how to replicate the vulnerability, including: - Configuration details - Proof of concept exploit code - Any additional software or tools required We recommend using :download:`this PGP/GPG key <./security-reporting.asc>` for encrypting the information. This key is also available at http://keyserver.pgp.com and LDAP port 389 of the same server. The fingerprint for this key is: :: 1309 2C19 22B4 8E87 F17B FE5C 3AB7 EFCB 45A0 DFD0 If you would like replies to be encrypted, please provide your public key. Please give us the time to respond to you and fix the vulnerability before going public. We do our best to respond and fix any issues quickly. We also need to ensure providers of products that use TF-A have a chance to consider the implications of the vulnerability and its remedy. Afterwards, we encourage you to write-up your findings about the TF-A source code. Attribution ----------- We will name and thank you in the :ref:`Change Log & Release Notes` distributed with the source code and in any published security advisory. Security Advisories ------------------- +-----------+------------------------------------------------------------------+ | ID | Title | +===========+==================================================================+ | |TFV-1| | Malformed Firmware Update SMC can result in copy of unexpectedly | | | large data into secure memory | +-----------+------------------------------------------------------------------+ | |TFV-2| | Enabled secure self-hosted invasive debug interface can allow | | | normal world to panic secure world | +-----------+------------------------------------------------------------------+ | |TFV-3| | RO memory is always executable at AArch64 Secure EL1 | +-----------+------------------------------------------------------------------+ | |TFV-4| | Malformed Firmware Update SMC can result in copy or | | | authentication of unexpected data in secure memory in AArch32 | | | state | +-----------+------------------------------------------------------------------+ | |TFV-5| | Not initializing or saving/restoring PMCR_EL0 can leak secure | | | world timing information | +-----------+------------------------------------------------------------------+ | |TFV-6| | Trusted Firmware-A exposure to speculative processor | | | vulnerabilities using cache timing side-channels | +-----------+------------------------------------------------------------------+ | |TFV-7| | Trusted Firmware-A exposure to cache speculation vulnerability | | | Variant 4 | +-----------+------------------------------------------------------------------+ | |TFV-8| | Not saving x0 to x3 registers can leak information from one | | | Normal World SMC client to another | +-----------+------------------------------------------------------------------+ .. _issue tracker: https://developer.trustedfirmware.org/project/board/1/ .. _this PGP/GPG key: security-reporting.asc .. |TFV-1| replace:: :ref:`Advisory TFV-1 (CVE-2016-10319)` .. |TFV-2| replace:: :ref:`Advisory TFV-2 (CVE-2017-7564)` .. |TFV-3| replace:: :ref:`Advisory TFV-3 (CVE-2017-7563)` .. |TFV-4| replace:: :ref:`Advisory TFV-4 (CVE-2017-9607)` .. |TFV-5| replace:: :ref:`Advisory TFV-5 (CVE-2017-15031)` .. |TFV-6| replace:: :ref:`Advisory TFV-6 (CVE-2017-5753, CVE-2017-5715, CVE-2017-5754)` .. |TFV-7| replace:: :ref:`Advisory TFV-7 (CVE-2018-3639)` .. |TFV-8| replace:: :ref:`Advisory TFV-8 (CVE-2018-19440)` -------------- *Copyright (c) 2019, Arm Limited. All rights reserved.* trusted-firmware-a-2.2/docs/requirements.txt000066400000000000000000000001031355360272700213170ustar00rootroot00000000000000sphinx>=2.0.0 sphinx-rtd-theme>=0.4.3 sphinxcontrib-plantuml>=0.15 trusted-firmware-a-2.2/docs/resources/000077500000000000000000000000001355360272700200535ustar00rootroot00000000000000trusted-firmware-a-2.2/docs/resources/TrustedFirmware-Logo_standard-white.png000066400000000000000000000133021355360272700276030ustar00rootroot00000000000000‰PNG  IHDR,<Ü܇ZsRGB®ÎégAMA± üa pHYs  d_‘tEXtSoftwarepaint.net 4.1.6ýN è3IDATx^í œÕÇkÀÀcŒWLLâîF£1.:Ýá\ñ@ŒxÏ(jŒ’ÝŽ1§+FÐéîÀsuWPŽŽd£ƒ‘¨H<0<@%€ŠßïÕ¿õ^¿î鞃vÞ÷óù}ªþÿÿ«êšžî_W½zUx<Çãñx<Çãñx<ŠªŠnAºr°Dnîª+G©äM¹I'^•9Çãi&Þ°<ÏNƒ7,ÇÓa¨®èÙCy4ÂLÖ;òÛÖæä#¥/©Dƒ³¦•ØâÎGJÔµÃö­öx<’tòlÊô`bò°­trNª.[íñx:%Å®uÒÉ AªâT‰<”l6{ï¶mÛfŠt‹ÁºzA×Ah˜¤=ŽNbXø"uƒöhJø2”C=m¡ÖEVå)Þ' Þ·÷$­@jrO6¡%ÐË¢E²( kf¸Vµ^r’”<ŠNbXø€¿m)BË÷Âæ(YU‡ÛØÛÏ=‘HåRÚa„oU^ß0,Ä«¥Th¿Iå²oKZøF)y:-5¬‰WíÔŽê×¥æÔŸ”e†N+«öBªük·©¿Ø£®a~y]äõ —õ¨_ýÕ`Z¶«,U:-7¬ù¬7—Á° 75ó)í0ä¥xýO%­@\’aY”Ë>$)µ^()%O§¢¹†U{éAe5Ão 2ƒÞ†™dmu›úH¶G}c\ÛÊë–—×7^³÷´Æ=e-ÅÓrÃZ"Ÿ÷fåOUuX°™ʰˆ¤Øð?M°ôK”nŠ$‹rYª_ ÝUJÚÓé(Õ°î[^V{ÊéþÚ&—ð´`\ë¹×ÌŸ¿‹¬µiZÞ‡Õô!½‰ZœK‘ëëP/YU‡ÛnÖËRÚaÈKk$­ÀöØ{X )µ XÿnxMö?æ¿l  ^±ÿ’m»IÚ€uhohO(çHËvçò‘ÐÆèóD¬¶EÔ]Ò Ôøú\·ÛHɵ=Q;JBÿ}9gß*ò½¥cˆÛp:T]%M5¨wEþHh æoÂôzè hiÒÔØuÁv%î*Ú°2ç‰=ªå¶9¹TȰ´pÈØ}Ö²>²öÂ(ÃJÜ©·;“Dê1¯Aüžä©œ¿ ¹ý¡ïC³ ÅÐB(E@yßQã——Æ^'ËÕCç#·+d ‹(Цن…eo•׊T!%Ön´jC?„ÖBBäiw ÄÿÃlËû˜²íèèó²Ì?Cü;7rƒ1ýbèYËØ† ®¸¼jƵ³ˆ-µ %­@|0×x†”ˆùyšq½Ä<4þ3Ô_šjP¶ A~†þ ¡úlHSâ…AÛ¤‰©ÍÐu˜m~—N³I÷Û_ø«bzjÒ°ºNÑ{U[lcʧ¢ ‹ªkXÓsÖª¯ÈËä'4¬Éz»ÓÉ˃‰'ï.ÕfƒDÑ_¢x[̯‡økõ‘¤˜û´«—TDÎ:%¯@{ûl;Ï/ƒÞ [˜ ÿt ¤þ~¤a¥ £ÕÊ,{´Ij9 ö(”óËŠÍà¯ÒÌùÇeV#‹)Po‰aÍ’e"ôÞ6æï S!h«Ï(.ëjxÖò3™7@~%4 ú@R9 v‘Ú€ùs$­@ÎKšù‹%­AîWRfý÷’fþ=LT¿æo³!ˆÀDÕ0eÔbUë=>„9†…ú_ k ³ óØSvghóS÷×bžGq#ž'¥v¢aUUíd/¶Í¨•jX¢{å•s逆…˜ýì»ànû(èëÒ®$Ã"’æ²ìÑ ¾EJ Ä?“’ñD)q{…ÙÔVKIƒÜx)+ßI™”Yÿ ‹ö¬”X[$9â_JI˜ÁÆž›”(•z¦V÷ýa¾hÃÂë¼ Yýwä Ã㤤@ýXÉ+o‚ŒÃbÄöáæ¹RbíI3O3W_|L–´¹¿°†Ù2̯³*_Ç<Á’W v½ö^šî«Âü)’V æ žˆx_bö5©÷SûA}f÷Yò|ÿ‡Cß¡ÐÜ6ê ÒœíO“tDÎÎr<+¨÷1OΆÔúcú³4Q þ²¬¢ÈgX·]Ó=H\g›R>õ¹odökÍî þGêÖnÎö™·ÚmP•×7.”-0é†e÷ß8o©ƒv-1,ÞÙ‡o@<{7ÓÃ1uA¾ a!Õ ¹øî=á"Íâ²™gʾ$¡q£¬Öù¢ 1Ù–YzzšB“²hS†UЈ"šj‡¸÷ Ku„{!Vý^Â8Ä'È<ÛòïºOBÆ<±2BBbãl.RnÁÃdãPÝÚhÃBȳÉqr í÷—Z©´ã ê<†Õ¥öÔ mSʧÝjf—¼ö.zó•ì•OÞ‘÷Â’ìòMᑿ7·”´§Õkvã±²Ûé†eï!´ºa,?Êéä%È“UÐe]sÄ¿pˆR©%Ò`]ú:¿8È—²‡Uôÿmí½‰ø¡X‡0,‚X6c~¤;Ô1ÏqMúŒ æ9äW2æYa=® ó4+žøÐ æ/‡«ð,5;Ú5ˆK5¬>R+•lXã+ö jEÕ•Wº «,3ä1Û˜òéüÇÃ÷ü±5Ïew© rìÃÚoî*mZ'=õ†ÓœœšÝ¨ûe44¬tò<½ÝžÑ àŸÖ憅ø)i¤¤‘´©–û”ïÚF®w6&zl æ›2¬ý¤Ô$hËþ¹HLx„”ˆŸ“Õ ob=ó­fX@› ÖÛ‘ +nP¯CÏIHhú<+§†J`ÊñM¦À¼:›Ø8[Œø9èHÌòB~vºÛæ%rö7YùCxi\È] ±ó] ¹Ò¯Ti6wœphN<“z^‰wú´ «ºªGðIdHMéîe¿ÅßÍ›ûc‹:ÝǾøŽªÝ¼ìÝ\cÊ#®”-ÙŽÚÃJ®Ú¾ÝÉ?SŽwŽ.üìü¶ØÃÊùb¢1þGÒH³C–ƒ/Á.š›1ê?Æ7,Ä—KÉÀÑ®dÃBšw‘ÐØë È]/ebŽ]2žG€œ1Hñl)i»PÊÅÿñ² k¦”r@­Ê{™VÚëe±vÂeXŒ&×^w —?£4Þÿø3§AÙêY×`þJv@Ãγ%hÇqKÆå6¨;û°0ËëÃNÁ&@;^ŸfŒ=€äõáæyÉKRÊ ÚÐÄŒK1ÿHÊ9 Fô H¡U ËÞ-ËD2¬!ÈÛ—Àí—KI¸¹†ÕWÊ Äs¥¤AÚô9VJ¤Ù‡É«Œ½qÂàI bΩ½4LmÃ2:ômPÿˆ?¦9¯EæÒ(iÞŽ¸ +3èFÛ l¹ kéúÆìíK6ôÖæõ»ÅVù¬sPæNdXmÿ Z+í4Èñ0÷} ;þ¶£ó<Ä6νYÇT(çâd”Ù‡ÂÓéññ@\æ6i¢@ЧÌÙ·×a[Žðæõj‡Is Êü]Ù‡Üü.”†âw-Ðg”s›9$#Ò@)5 ÚÞ`-«ûµ ¤d€f(Úæ| gÿ—ÿ Äm£‰Ñ,ôèvX?x<ûÇ{} ¹|÷y¢9r`舗} jòÖÊ\Ú±/…ïï·¤Ö/yîa*!6úe<ž–áÚêá­dLã±ÕÖ†Õ}úŠ/ÈÖ„´‘ay<žŽL¦ò€ •˜øm¨ÄÒÚZµOî¿-2—ÚØ°^—-Ù ‹ãǶo÷LõXÇóÿ˜lPT'V–W¡OŒÍ1,P–ütd:.kXO4ðÊëŒa eXÉKõvÓx=O'ÃuHHj¾]ðN .ÃÚðáÆì³o/7´õSóÊ’¢ k–ÕEü!¡ÇãÉkXÿ]Õ+È Ì{ã¾=&œÝú™óúÜ‚¼¶å§ImWÃÒÀÕQë Ëãñä5,Àg ÚF×ðy×e3/Õ;5¹¡1;åÕ†jWoÌž¸`äâZé6%oX§a©‡¤¦­°ª5뎣u`ç> î Ëãñ4,2yÔ±¥>€‚*Ù°êÖí1guoyÕ\¼ay<ž& t™tæ9Aª²à0[¥Vy]Ãæ^3–çÞ´/NÖ¶pð#/Úå#Ÿ8bú`))sä/ïy ¦“ ›¥ÄŸSÈ‹PÿâÃxáðÅRöx<-†ÏòK%†éþÔRÉÛ›2,ÒeÒˆK‚teÑ÷È*Ö°ÊëÞ+Ÿ½:ï-]44¬tòçz»ïLœTU9Ÿz[,0Þz–üòI"¼ƒG¤óNŽÚ<1ÏË9æCÏ@—@ê &¦ζ|HG”óês¡­jAÇÓ TWô†AM Ò‰;”RÉG‹1,…?ð¸1åS1†…=«e=æ¬þš¬½0¡a͉m÷øàþM^B’Ùcz ROø@ÌKYV ®îûƒyï¿¿8¯ãýÈáÈ„œ7ãóx<­A‡„“/Ú¿,3tö¶>‹”­Â†Õð4>˜¿Úy}›“V>$„Ùðº¼$4@ž"W7§Ã”†•RžD³[!¡¹îÞ°<ž¶¤Tʨ9·o<=ÈôÿÈ6+ÊeXåõzÔ5Tw›³Êè'*ŠÖ7¬ÿƒôMÕâ ?ô]™§a÷˜GÌC@×ý‹¼ay²/ ¥ RO‡‰@|.ÄG-†îA;ã¶Çˆû!ï|]æ!vÞóä<ëÈgn“²Çãiu&Tî3x,H'^v*•\CÛì¬Ebí\5*•X½å¬EJ%¶:ó‘8^lò ‚·$noàU¼Õpγ=ÏŽBÝä/9_"7¬³]>Š9ìä¨w"`L7Cƒ$dÌ{˜s¤û-’òx<;oXN`L|FŸœò"ô;è]è!È8äôx<;oXAñyn<³h>4Ããñ´|ÐC*é|Λ†÷µÃŒz¤|-HW ÈM*y•Ìy<Çãñx<Çãñx<Çãñx<žÒ‚ï:š^qOuIEND®B`‚trusted-firmware-a-2.2/docs/resources/diagrams/000077500000000000000000000000001355360272700216425ustar00rootroot00000000000000trusted-firmware-a-2.2/docs/resources/diagrams/Makefile000066400000000000000000000051351355360272700233060ustar00rootroot00000000000000# # Copyright (c) 2015-2019, Arm Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # # This Makefile generates the image files used in the Trusted Firmware-A # document from the dia file. # # The PNG files in the present directory have been generated using Dia version # 0.97.2, which can be obtained from https://wiki.gnome.org/Apps/Dia/Download # # generate_image use the tool dia generate png from dia file # $(1) = layers # $(2) = image file name # $(3) = image file format # $(4) = addition opts # $(5) = dia source file define generate_image dia --show-layers=$(1) --filter=$(3) --export=$(2) $(4) $(5) endef RESET_DIA = reset_code_flow.dia RESET_PNGS = \ default_reset_code.png \ reset_code_no_cpu_check.png \ reset_code_no_boot_type_check.png \ reset_code_no_checks.png \ # The $(RESET_DIA) file is organized in several layers. # Each image is generated by combining and exporting the appropriate set of # layers. default_reset_code_layers = "Frontground,Background,cpu_type_check,boot_type_check" reset_code_no_cpu_check_layers = "Frontground,Background,no_cpu_type_check,boot_type_check" reset_code_no_boot_type_check_layers= "Frontground,Background,cpu_type_check,no_boot_type_check" reset_code_no_checks_layers = "Frontground,Background,no_cpu_type_check,no_boot_type_check" default_reset_code_opts = reset_code_no_cpu_check_opts = reset_code_no_boot_type_check_opts = reset_code_no_checks_opts = INT_DIA = int_handling.dia INT_PNGS = \ sec-int-handling.png \ non-sec-int-handling.png # The $(INT_DIA) file is organized in several layers. # Each image is generated by combining and exporting the appropriate set of # layers. non-sec-int-handling_layers = "non_sec_int_bg,legend,non_sec_int_note,non_sec_int_handling" sec-int-handling_layers = "sec_int_bg,legend,sec_int_note,sec_int_handling" non-sec-int-handling_opts = --size=1692x sec-int-handling_opts = --size=1570x XLAT_DIA = xlat_align.dia XLAT_PNG = xlat_align.png xlat_align_layers = "bg,translations" xlat_align_opts = all:$(RESET_PNGS) $(INT_PNGS) $(XLAT_PNG) $(RESET_PNGS):$(RESET_DIA) $(call generate_image,$($(patsubst %.png,%_layers,$@)),$@,png,$($(patsubst %.png,%_opts,$@)),$<) $(INT_PNGS):$(INT_DIA) $(call generate_image,$($(patsubst %.png,%_layers,$@)),$@,png,$($(patsubst %.png,%_opts,$@)),$<) $(XLAT_PNG):$(XLAT_DIA) $(call generate_image,$($(patsubst %.png,%_layers,$@)),$(patsubst %.png,%.svg,$@),svg,$($(patsubst %.png,%_opts,$@)),$<) inkscape -z $(patsubst %.png,%.svg,$@) -e $@ -d 45 trusted-firmware-a-2.2/docs/resources/diagrams/default_reset_code.png000066400000000000000000001215041355360272700261730ustar00rootroot00000000000000‰PNG  IHDRžÜ¦}ó×bKGDÿÿÿ ½§“ IDATxœìÝi\W¢÷ñS¬bƒÍn ˆ :ŠŠq— .71›ãoB5Ñè03.3ÑoâdF3&3j¼Q#5Ë$ fôšÅh|Ä…D *Td“­©çE™–Ý6Ð ÝÅïûñEשêS§ª«ºÿOŸ–dY€ãsjëÖA´€Jm D[¨Ñ*A´€Jm D[¨Ñ*A´€Jm D[¨Ñ*A´€J¸Ô]H¾žÜVíh‡æùÌkë&¨ ½¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P —ÖÜÙ_ýøÙšÏ²¾Éª©¬ñ ó‹º?jÌoƸut3µýêøÕ#g8e`½òœ“9É÷%¿–ýZ½ò??øçs‡Ï !œ\œ|»úÆN9{dóšúúˆ×æ'Üó«{š÷t´¾Ö‹¶güý™¿Ç=÷È+xy\(8´éPNFNøàp+îeLÒ˜ûÝg¨1üðŸÞyâÝݺȸH+Ö»ÕJÑV®•wþ~ç½ÏÞûÀÒ”’à¨àG×=*˲¢øJñ®…»ÎÿßygWç>ãû<ô§‡Ü<êwååma{Ö·YÞAÞ÷>s¯É=IÂÉÅÉÉũט^=sÏä*ÑÖÔ.-ßµpW^fÞ®…»öþio˜Óþ2ÍF§VÔJcmsÏäýT4èÑAõÊ%IB¼ûä»Î®ÎK-ýíþßfŸÈNýCjÃ6?µY¤]ž¹|æû3o>l~w†jÃÙýg ,4v ›ÚE£åÿg¢.R7ñ&¾tâ%r-€£h¥h[ZX*„ÐvÑ6\•.?뛬_½ú+wO÷NÆÿaü7ï}#×Êõ¶¹tìÒÃËvuwõ ñ‰!ÞÔŽ>[ýÙ|ßù¿íüÛ 7 zx·ÝÌìÂ’]ÀQ´R´õô÷BÜȽÑpUQN‘[G7e!„_˜_ueuÙÕ²zÛtôíØÑ»£²Ð#ÀÔŽÆüv̺këÖ®]üÕâ¾øaß+ûÌìÂ’]ÀQ´R´írwï ï£ï­W.˲w°wUy•Ò­+„¸véš‹»‹ÆOSw3möæ›5•5Êbɕ󻓜¤Î=;÷} oÆGBS»0³kÉIjÑ ÕµR´•œ¤I¯O:´éÐǯ~|5ëjMeMÞÙ¼¿Û‘õMV@€°a©KR+Ë*K Jö½²oðÔÁõ’eçžCú„øë!DMeÍÁMîIµ5µ†*C^fÞ‰='‚z !LíÂÌ®½½òÈ·é9€uIÊŠäëÉ6ÝÙ_ýøïÕÿÎú&ËPeð ÷0iÀˆ™#Ü<ÜnäÞØµh×ùÿ;ïìâÜg|Ÿ‡_~X™ì¶î¼¶×._ÛþÂöòëå®\õ ú´ä43óÚJN’W€—>AÿÈòG:útB˜Ú…©òs‡Ïýïüÿ--,ñtÊÓ¶8ó|æÙ¢Z€v«U£-ê"ÚX?´ • Ú@%ˆ¶P ¢-T‚h • Ú@%\¬[qfYw{—»»Œ_2¾çˆž 7«;amëûñ«?[óYÖ7Y5•5~a~Q÷GùÍ·Žn¦¿¬÷²ñ?øñÁÊÓkkj““æükÎ]÷ÞÕ&í@£¬ßk;&iÌšü5ËN. ¾iÚ¦²keu×ʲl¨6Ä¿ßm@7+îT©Ö’-3>Îxë‘·‚¢‚æÿ{þŠVü÷Æÿ.-(ÍÉȱ¤ñ°gVîµBI8¹8uôî8jî¨ýoíÏÿ!?|HøÊÁ+£‰>wè\IAÉ£kM3}䬑=„+¯–8ì侓—_éòÔæ§¾ùßoüõ€\+ù͘¸çâ„þràðæÃÅyÅ_ͰÄac’Æ(»ª[m—^]ŠrŠ’>ORVe}“õ׉]~v¹òëb ¹VÞùû÷>{ïKPJ‚£‚]÷èíß­h¬ñÖ?E°DÛŸÛuÌÙÕÙ¿»¿²xrßÉ9{æh|5 ·üòŸ_>ý÷§}ºúüý鿯p}ÿGú¿tü¥Ëß]þË„¿ô¹¿_˜Ÿ6H;kç,ßPßœ“9'o ìØïÁ~õª-/*_ÖkYÞÙ<^§ÔÙBÿº¹V‘{&·è§¢Aª×I’Ì7öÏúÑöà_~ù/+Ë*5¾šiæ॔Ç<Óh®BÄΈUòèÀÉwü~Çý/Þ/9I=†÷¼+0ûd¶_˜_ÿGú+[†ô üØàï~oŒ¶Æj;zwŒ~8úË-_>²â‘ªòªã©Çg0»ÞŽJ K…Ú.Ú¦6öÏúÑvXâ°„y îww{ÝòNºN¦ž¢ÕÝÊšnÝ:v’œ$ãbeI¥â侓ûÿ²ÿÚ¥k’$U”TDŒŒh´ÚaO{÷©w\öàw©ßùû„ «·#OO!ÄÜÊ ïìêl¨¹=·¦ºF)4}Ьm•xÚ°¼áú[¨øJñߟùûÌ÷göÑS’¤½/ï-8_ÐhµÝ‡u×xkN}zêË­_}bhêºÜÝÅ;ÈûèûGƒû×-—eY©§ÑÆû†úÖÝcá…B!„o7ßælÄæµ­,­Bõ’$éFÞow~kfãa‰Ã>}ýÓ‹ß^ltf1ÉIšôú¤C›}üêÇW³®ÖTÖäÍÛñ»Yßd™©sðcƒ¿ÜòeæÌª›UW³®~¸ôȑƞfØ ~ÌZzüׂÿJ¾/ÙÓϳ£oÇÈQ‘7‹nšÚxÐÔA{—ïejÈAÔ}QÏ¥>÷ïÕÿþâí/ U¿p¿“ÔëÄ­gðcƒ«+ªw¿¸ûjÖU¯&rTäƒËléQÀÚ¤Ûó^ ‘|=¹ ›bµ†Úe½–=þÖãw¾»­Ûró|æµuTÅ$4É—ÿü²C§úx}[7­Í$Xnqøb·ŽnOþíIã h?Tm_ýñÕ¶nÚŒÚ$ Ý"Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P I–å¶nC#’¯'Û¨æy>ólT3Ú½¶P ¢-T‚h • Ú@%\Úºm ›­¾¢†F\äk{ µÐk • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • ÚZ_å‡ ÞŸý¢ïåšÜÿéS´o‰\Uffû¼ÕËŽniX^•óÝåž ˯ü9îÒ|éÒ|éR’ëO+î*9¸®ÙMÍ{=ºüØöf?À®¸´uÔæfÆ¿ ÿ>Å+.Éû‘5.Þ!ÕçJ½U•sÂ=|¸÷ÒiÌ‹Þ÷ýI6TWü°¿ð ®ºÞ"ÇX±~GD´µ*¹öÚÎç=ï}Þû•J[p?ßGß²,„0ç^ßõBÅùƒ’³[Ç>x?ôšäÖ±^†¢ËW·O¯ÊúÊÙ;ÄóÞÙ¦÷$ 'ÉÉÅ£×ý.Õ¹"ǘªßTùõ]s«óN_Û5·hï"÷#ý¦¥Øæ¤´$XSun†¡([3è‰ú+$IQøîDáì´ô¼î·G«²]OMjXCÁæÉ.Úàåy3?*=¼ÁüîdCuÅÙמWº„MÕoªÜgâzW]/߉ëƒ^Ê"× ÚZ“¡´@ᢠn¸ª:?³2ëˆï¯’ܽœ;é´ãW”}“"äÚzÛT]úÚûá7$×.>¡â˜ÚQñg¯\š/]þ­[þ†qžÃgºubª~Kö  D[krö BÔÜÈi¸ÊP”-¹iœ<”E¿îru…¡¬°Þ6Nýœ:úÜÚ& §©uó‡ÐurèZC—Åg*~H/Ú·ÄTý–ì@ˆ¶ÖäÚ%ÊÙ;¤¼át²ìì"W•Õ–(5ײ$wgÝ­œµÁµ7‹äšJe±¶$ïû“œ\;ë;öp3ãCSõßa¿P’UIN¾“Þ*9ôÖ_ª¹zA®©¬Î;umÇs•YG\"ÜÆ^OM’+K %Wnì[¢œX/YºvÖ»…ô/9°V!×T–L6½'YÔÖȆªê¼Óå'>p êkª~óûuöÒUçgÚð„´"¢­•yD=øÜçU—Žæ½1 ûEß”Ç\|BÝ‚£…$ù?½S®*Ïy9<ïõþ®A}}YÓðéþOí¨ø>-ï{òߊwïoj/ÅŸ­¼”äzùwùíÖu€ÏÄõ&ë7»ßN ˾ݚ½Ø§pó$œ €V%ɲÜÖmhDòu3–-2Ïg^7[ÕF\œ×Ö-í½¶P ¢-T‚h • Ú@%ˆ¶P ¢-TÂ¥­`¿ªóNíYX™uD®*wñ õèó°÷ƒÿÓš ¨ÊùîJò½]_+µzÍ•?.þleeÖ¹¦Òů»GÔÃÚ1‹%7Í•?ÇUž;(„Ü=ݺDiǿҡg¼"gYˆ÷øšÁOÝz~mÍ¥$×À9û;Ügõ¶4½¶&ȵùþËYÔeáÉW ý·»øuoë6™%˲¡Ú’ ofü+ÿ­× ~ç Y‘ï÷ß[jKó«rN(k;y1tMuð²Kîá1›®-»jËFX½¶3ÜøÉPtÙkä|çN]„nÁÑnÁÑʪڊâ¢= ožÚ+WWtˆHðôg'¿¢öfQÑÞ+Nï«-¿îp—ß“ï¹FŠs¯ïz¡âüAÉÙ­cŸG¼zMrë(„È]©ïxÏÔÊs ¥’k¿Ç7»vé#„0]¾º}zUÖWÎÞ!ž÷Î6¶§äÀš’à Å?9kü<‡ýºÓ˜•òÜ•úŽÑ“+Î0”ä»u‰ª)ÊÖ%}¥¬ªÌ:Rð×qÁËs%7Íí“k¯í|ÞóÞç½X©¸÷ó}ômqû—;$áäâÔÑÇkÔïŠ÷¯®Î?ëc³Ó `MDÛÆ9kƒ\"®½?ËëÞç܆¹ø„W]ýç4ÉÙµËïKnšë»ç_ÝúTÀ¯÷ ! ÿñ˜$9užĹ“®:»—¢ð݉ξaAKÏË•e…ïþêzj’ï” J=7Oí |î3'ïâ´ÿ¹¶ãùÎ/|!„(Ø<ÙM×;`ù‡†Òü‚·Ç×iOHà¬O\|êr¾+ØxŸK`dÇ~•Uå'S;Ï9à¤ñ«-¿ž³,¸:®·¢ìËw:öô¹VˆêÜ CQ¶fÐõX’ê”{Orvuñ¿Ë g U0 ÁÉ©ó¼ÿ¸‡/N{í§å=~ZѳüØv!DÍÕožÞç;e£“Æ_rõð~èõ›g>ª­¸QsõBÅ™O|ý›³6HHN®]ú8kƒªó3+³Žøþ*ÙÉÝ˹“N;~EÙ7)B®Uöà3ÓÉÃ[áõPÕå£Bˆêü̪K_{?ü†äÚÁÅ'´Sücs:öŸââ.$É-¤¿fpbÅ÷iÆUž1³œ4~B§Ž>£'•~ù®B®*+?þ¾fè³õËPZ „pÑ›:î’ƒër–ê./ð,9¸ÎoÚ?œ½:[鄨½¶&9{z?ðªxàU¹²´ôÈÛ…ÿœÖ¥KoCi¡RÞšAÆÍœ:h E9†’<É­£³6¨n †¢lÉMãä ,ºøu—«+ e…ΞBg¿R.¹zÈÕ7Em¡(Û©£ŸSGŸ[Ûô4Vuódjñþ55ײ$Iª­(î1úv;;ÝÞ©ç°…ïNò~pUùw;œ}ºº‡ mpPBˆš9n?·ªÏa3:%,tr÷”Ü=…’³kݼrM•Rx‡3кˆ¶w&¹{zÅ%}´´ê§ÿçÞm¨$Ý‚N´¿ØÆÅ]®*7ç*csÎÞ!rUYmi’nk®eI.îÆDÛ³6¸öf‘\S)¹¸ !jKò”rCqnáß§Ìü¸CÏx!IE{×üp{×uƸwuÒøÞ<µ·ôËw=tÙ !\»D9{‡”Ýb:|‹,+c$7s']½g¹ø†ÕÝcMá9!„‹o¸©h Hhœ¡8¯è_¿¯Ê>.W•Õ–_+þüUa¨väâßÃ#rìµ÷¦Šs…µ¥å'v !\ü{tнö¿¿6ç Y®ÎÍ0çºD¸‡ ½žš$W–J®ÜØ·D38QH&Ϲkg½[Hÿ’k…rMeÉÁd¥\®,B¸õ’d¸ñSù·ÛÌ´ÜsØŒâO_®ºø•f`ƒµBÉÉwÒ[%‡ÞºññK5W/È5•Õy§®íx®2눙:5ƒŸ*ýòŠÌÏäªòš«®ø»£ëuQ´9zm'¹u¬½y£0åQCQ¶äâîªëíÿlªK@„Â/ñ½½teÝpehGÔƒûMBø?¹½hϼՃäŠb—€žþ‰ï‰N]üŸÞy}× 9/‡Kή}ñyøuóûõjǵíÓË¿{_rõè ÿ¯ÊKß!\"´ÿµ,/9ÆÙ3À©£_‡È±µ7¯›ªA3(±hï‹Q:™ràõPàsŸÿû•’/Öˆ*¿š×ïÄ­WçàD¹úæõÝ¿©¹zÁIãç9ÖûÁUw<‡­L’oÏúdG’¯'Û¨æy>óºÙªnûPkÈYìûøf»ïkë¦!ÄÅymÝÐn0 AmJ¿Ü$uÐzèǵuCZT%{±ä¦ñr›™½jE´U•WMŽÁP=úö D[¨Ñ*A´€Jm D[¨Ñ*A´€Jm D[¨Ñ*A´€Jm D[¨Ñ*áÒÖ hçµu ~Ö-ÙV5ÛÏ1´zm D[¨Ñ*ÑÇÚ¶_Û¤¶n=.·u À-ôÚ@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶°ÔêDÔÂÛ‹Ëv iš8“skñäe!M?]·aâViš¦ ×'Å]IbÝ'ͯ*z±Ø~Äz-öh K%ô§²E~ñ­Å´ Ñ;D¤Ÿ¾µ˜~JèƒDEUɲ¨64§ />,ªÿ!Š7‰7Ÿ ߟlN%@­ˆ¶°T¿Páï%ÒO !DY¥8qI,zðÖ¢"ý”ˆï}ëñšDäï„׳"lžXùáíô¿KwˆØ—…þ÷âð÷Bÿ;±ú#û²ðxJÄüIä\«þ%:ϳĚoƒ$ gáá&î:‘‘}«<·HLN³EÈ1çÊ\ùÜq:GÌMaóDâëž$Жˆ¶°”$‰¸»ÅþÓBñŸ³b@¸×W|qVȲ¨•ÅgEÂÏÑ6ÄW|²Po»#ÞüTìúúv%©GEj’È|CÄÝ-„ïž„ÖCÄ-%âÂ:±k¾X´]\È7Ù’jƒø÷Iq>_ ïy«dâ:áê"ίGWˆcY"i‹¹òõ‰¢W°XŸ(²’EÊ,ëž$Жˆ¶h‚„¨[Ý´é§E|/ÐItÖŠï.Šc?Šâ›bT¯[›M*„$‰þa"1V¤º]ìÑÂÏóöâœ1¢wˆðì ¦Åˆ‚±|²Ð¸‹zÙEÏj¤¯¤ išp{RŒ[%fÆ‹!w !Df®8òƒH~Bxu:o±b²HùBÔÊ&Ë€ZmÑ ½Å¹+âòU‘–!FõBˆ¸»EÚ)‘~ZDw>š[›¥#^¡/ˆn/ˆ·ÓEAñíê Æ5.jÜ…N+œ¤Ÿ;ˆ’ŠFð‡G„¼U¶ˆ3¯‹ôÓbÉ!„Ⱦ&4î" Ó­mºŠŠjQXb²¨ÑMÐS'ºú‰¾ßç‰!=„"®—H?%öŸ Q·¶É-SÞË&Š‹Éââ›bÖhQ·ŸTjXiÓ9IB$& Bˆ_QVy;@g wWáïe²\áÄ…€ñ ¦‰ï%VíÃz 7!„©‡2Å¡ÌÛmKn !Dß®B’ÄO×ŶÃÖÜ»,‹ƒ¨ª§sÄ߈¾¡B¡CïI[Ei…¸rC,y_$Æ 'Éd¹B§™¹Öl°D[4MB”È+ñ?« è$BýEeµˆÕß*‰è"–ýJÄüIÄüIÌzWŒíkͽ¯üP¸>)<ž£WŠáb}¢BH’Ø9_”WŠðù¢ÿ‹¢o¨XóßæÊ… [ ŸbR²5›Ú–$Ëöøµšäë¶Jó|æÙ¨æfèf³\u±Ñ£Üf•áø¥Çíñ }¢×*A´€Jm D[¨Ñ*A´€Jm D[¨Ñ*A´€Jm D[¨Ñ*A´€Jm D[¨Ñ*A´€Jm D[¨Ñ*A´€Jm D[¨Ñ*A´€J¸´uЊ—ÛrïÛ$[ÕܶÇì½¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P ¢-T‚h • Ú@%ˆ¶P I–e›ïC’l½ ¨€¼µ¹Ï|Üæ×0p.¶¨”,‹f¦ýb±ùI´WÖŒ¶$ZX‘1é’q€…¬mI´°)2.°Pó£­å‰¶†óBîxE‘q€yÍù™%¡–8‹–°è3\¾F„M¶æq¶p‡«n+ÑÜbi´5/H´h\„À<‹¢­©HAž@ëãj¦Ü9Ú6š$ˆh[\– !s?´+IRÃ!˲ÝˆŠŠ ©1wÝuW kŽŽŽÞ¾}{“žòÝwßyzz6,‹‹«Û¶éÓ§ !¸eË–6²]iô:lôŠí‡ÉÉ¿±W¬C‡%%%Êã &ôêÕë•W^B89ý"Á˲\SSãêêÚMB±`Á‚¥K—*•f,X° ::ºÞf­ÖÎ6?!Í&Ërà U’Zã磀j¼×Ö±:këòü™³³³«««ò¸cÇŽB½^¿téÒØØX½^øðaNwèÐ!åYG5ö°®]»6,,ÌÛÛ;((hÅŠBˆ¹sçž>}zîܹaaa‰‰‰BˆâââÙ³gwíÚ5 `êÔ©………Ês/_¾ùä“âââÝ»w¿ùæ›»ví2µ#SåTs‰€–h$ÚÖëñRSh˜5k–ŸŸŸ™ \\\ ÃñãÇKJJ´Zí=÷ÜÓp›üqß¾}7nô÷÷÷ððxýõ×?úè£7ndff~ýõ×o¼ñF‡BCC,X`j/kÖ¬ñÿÙ·ß~{ÇvΙ3§wïÞžžžÓ¦M+((X¾|¹F£1bDdddvvvŸ>}ÒÓÓsss¯_¿>{öì´´4Q'ÚN™2%<<\’¤þýû'&&*kîÈÔAÝá„Ú“z*·´CõÇÚª8× !‚‚‚̺ Ç IDAToн{÷üão½õÖSO=5`À€åË—9²Þ6YYY’$ 4ÈX¢Õjsrrrssýüü|||”ž={šÚËŒ3~ÿûß+ïØNã¢F£Ñétơ椤dôèÑŸþyuuu||üèÑ£§M›vîܹ¼¼¼˜˜!Djjêš5k”6=ºÑšM”V«5uv¨ÞÐ[ÝÐÞ˜ü™P]®¿ î^^^ÊãºãJ'Mš4iÒ¤›7o®[·n„ W¯^•$©îÑBCC%I:qâD½ØçääTTTTYY© ŸÍËË3Õ //¯ ÛyG Ï?ÿ|MMÍèÑ£ûô铟Ÿ¿mÛ¶áÇ{xxäææN™2åã?Ž—$iñâÅ?üðC£;2uP§Ñ/–€vâÚU&0`Àž={„ÉÉÉJáÙ³gÓÓÓ+++=<<Œ“ètºÌÌLåq=ÆŽ;}úôÜÜ\!DAAÁÎ;…z½¾ÿþk×®BTVVë´µ#FdggðÁ ’$5jõêÕÊhå+e}ûö•$é§Ÿ~Ú¶m›©JL”£kW—40ù52õuÙÖ³jÕªãÇ÷éÓ'!!Á8êàæÍ›‹/ ôõõÝ´iÓÎ;•l´pá­[·úøøLš4IñÞ{ï >ÜËËkèСƙvìØ‘––vÏ=÷ÄÇÇÇÇÇ·Îh4š¡C‡êtº®]» !Š‹‹•½GDD,[¶,&&&&&fÖ¬YcÇŽ5S©ƒr8ª¿t€)¿ŒX·‹‹|ÇÅ• @ût»×–4Õ0õP7‹æµìÑ*A´€Jm D[¨DãÑ–/•7*::zûöíöV•…¸eËóÛ´~«l„ €öév´Uë„_²,WWW·u+,e»Ö.X°`ðàÁ¶¨ÙΩõ ™àèý^z½~éÒ¥±±±z½þðáÃÅÅųgÏîÚµk@@ÀÔ©S •ÍÖ®]æíí´bÅ ¥°ÑçÎ{úôé¹s熅…%&&ÖÛ©úõzýÿøÇQ£FEEE 8ðäÉ“VU·µS§N2dˆ±æ#GŽtêÔ©¬¬¬á.^¼xÔ¨Qƒ Љ‰ÉÈÈPÊsss'Ož2gΜòòr¥üµ×^ûú믛Ô*åè—.h>ù—̬r,‘‘‘QQQ………Êâ<0a„‚‚‚òòò_ÿú×ãÇ—e933ÓÓÓó‡~e¹¨¨èÛo¿5³±,Ëýúõ{ï½÷Ý©§DFF8ðúõë²,¯Zµ*66¶Ñªê¶öÚµkʪgŸ}vúôéàÝwß­Ôœ’’ZQQ!Ëò°aÃ{ì±âââÜÜÜaÆ͜9SÙ~À€ÿüç?›Ô*¥šk4•¹hëÐÉ 22òÏþ³òøÂ… ’$åçç+‹7nÜ$©¨¨èüùóï¿ÿ~qq±ñ‰¦6–M'?3O‰ŒŒüÛßþ¦”Ÿ>}ÚÃÃCyÜ0Ú[+ËòO<‘””$Ërii©——ב#G=ÀuëÖƒƒƒ?ù䓳gÏ !Œ-IKKëСƒÁ`D[KZåˆTs€f¨? Aþe8pèÿÛ RdeeI’4hР°°°°°°¾}ûjµÚœœœîÝ»ÿãÿøË_þ¢ÓéFŒqðàA3›Ù‘ù§øûû+<<4ÙÌSLiXUÝXëëë»wïÞwß}÷ÙgŸ5UÉùóç•555/^  )+++((PÒmVV–»»»1Å6£UÄ¡ÿ VÑH”id=4ôèÑcìØ±Ó§OÏÍÍBìܹSqöìÙôôôÊÊJ€€WWW3 !t:]ff¦åõ›aª*£3f¼üòË_}õÕOµ$J5ÑÖ"­h›W·®„„„S§Nåçç+‹iii½{÷NOOWÓÓÓõz}PP%Uɲ\]]m«†šÅÌg±…¡ ­æŽ¯ˆ.ÑÖœ6I´Í«ŸŒ+„èׯŸ¿¿¿’eËÊÊNœ8±hÑ¢ºÑ6>>^y¼fÍšÈÈH//¯°°°•+WkÐëõK—.Õëõ‡Öëõ«W¯Žõððˆ‰‰ÉÉÉYµjUçÎÖ¬YÓhΜ93dÈ­V;|øðŒŒ ¥077wòäÉ!!!sæÌ)//7S>wîÜÓ§OÏ;7,,,11Ñ6§ ùPÛÊA“˜¸ÖÝѶv’h›·G%à¶ÏH’$ÅÅÅíß¿_ñŸÿügÀ€ãÆûâ‹/dY®­­ýâ‹/”-CBB>ùä“âââÝ»w¿ùæ›»ví2V’šššššš™™'„xçw6lØPPP ÕjãââJJJ.\¸°k×®E‹]¸p¡a6nܸyóæÂÂÂqãÆ?¾²²R1qâDWW×óçÏ=zôرcIIIÊÆ–¯_¿¾W¯^ëׯÏÊÊJII±í)G`êC™PëXL½^Ö -DÛÛì6Ñ6¯ ŽÊ$$$(Ý´Jm@@@çοûî»cÇŽ5JÙlÊ”)ááá’$õïß?111--ÍXìY³üüüŒ‹sæÌéÝ»·§§ç´iÓ –/_®ÑhFŒyüøñ† ˜={v¯^½\]]—,YRQQqàÀÌÌÌ#GŽ$''{yyétº+V¤¤¤ÔÖÖš*·ñC¨U™F_;+&¢­#%چȸõ$$$œ;wîòåËiiiJ‹‹KKKKOOŽŽöññQ6KMM1bDhhh·nÝÞ~ûí‚‚c õã5N§srr2.–””4l@XX˜òÀÙÙ¹k×®999ÙÙÙ& @)ïÞ½{EEEaa¡©r+ Pƒ†^vøYŒf0p[^sû¶h"ã*zöìÙµk×>øàûï¿2dˆ"...==}ÿþýÆÑ¹¹¹S¦LY¶lÙÅ‹/^¼8kÖ¬ºç­…ççâŋʃÁpùòåààಲ2czÎÊÊrww÷÷÷7U.„0hhÏ͵mÒ؈-Òm»ûUY¢mˆŒ¿jÕªaƹ¹¹ !FŽyèСC‡£­ÒÛÚ·o_e.°mÛ¶Yqï6l8{ölMMÍ«¯¾êîî1tèФ¤¤ÒÒÒ+W®,Y²$11ÑÉÉÉT¹B§ÓeffZ±Uàpȵí„Õ_ÖömçûÎWþ™ßÌqmCí6ã&$$äåå'C ­¬¬ŒUJ"""–-[3kÖ¬±cÇZqï3fÌHLLôõõÝ»wïž={ÜÝÝ%IÚ¹sgyyyxxxÿþýûöí«Ì®`ª\±pá­[·úøøLš4ÉŠmÇ¥Žf4ªÞ‹ÛÂX"Ùçµ’|=Ù*õÜ1Ë*ìó$X%׊ OÅ6›èÇÛÅ˧zu¯ÏvrK¢Ù¸ZT¯Þ¯r{`­]?´K¢m”ñxÍd\>0m‹\Û>ɲ\÷¥—¤fv¿ª*Ú’h-dIÆ­»ÖÞϘíúƒØ?ÞTÍÞ?€`UõÒmó¨!Ú’h›Mmàà¤imÝØæuÜ:p´µ$ÑÅ,DÆØ>kÚ¡–wÜ:^´%ÑÚÐVêvÙòùѬŽ[‡™üË’Ù»Ô4uW›³ðdªrú0 ž¸¸¸%K–´Î¾¢££·oßÞ:ûÐ$«W¯ŽŠŠ2..[¶L’¤3gÎ(‹'OžT¦K·]âââ”Ï\WW×»îºkݺuͮʞßjZäì=Ú’hÛP7Y–«««Ûº€Œ²MHH8uêT~~¾²˜––Ö»wïôôte1==]¯××ûµvSš}ß½øâ‹ÕÕÕÅÅÅo¾ùæÂ… ?ûì³fTâXš-ì4Ú’híBètºC‡)=êéé©<Öëõ«W¯Žõððˆ‰‰ÉÉÉYµjUçÎŒ?Æ¡×ë/^lIûVcŸîýúõó÷÷W²lYYÙ‰'-ZT7Ú-Èv÷$I...÷ßDD„ñmÄÔ{E£å ßjìMK.ûж–¤"m›#ãzçw6lØPPP ÕjãââJJJ.\¸°k×®E‹]¸pAÙæÃ?ܽ{÷7ß|3sæÌñãÇWVVÖ­aýúõ½zõZ¿~}VVVJJŠbâĉ®®®çÏŸ?zôè±cÇ’’’êítÔ¨QBˆ´´´°°°ƒ*•— ùä“OŠ‹‹wïÞýæ›oîÚµËøÜÔÔÔÔÔÔÌÌ̸¸8 Û؈ýwÙ !$IŠ‹‹Û¿¿â?ÿùÏ€Æ÷Å_Ȳ\[[ûÅ_ÑÝÖ÷]uuõ¿ÿýïóçÏ>\)1õ^Ñhy÷;פ,aÑ–Dë š–qám h‰9sæôîÝÛÓÓsÚ´iË—/×h4#FŒˆŒŒ<~ü¸²ÍÌ™3½½½…O>ù¤Á`8pà€™ 3339’œœìåå¥ÓéV¬X‘’’R[[[w›€€€>}ú¤§§çææ^¿~}öìÙiii¢N´2eJxx¸$Iýû÷OLLTÖ*fÍšåççפö­Àž?ë”nZ¥6  sçÎß}÷ݱcÇŠ‹‹G¥lf»ûî•W^‘$ÉÍÍmܸq3gÎ2dˆ0ý^aÉ{ˆÝjöeЖіD«–fÜi·þ¡½i'¯»qŒF£ÑétNNNÆEe€B§Ó·×ét999f*ÌÎÎÖh4Êb÷îÝ+** ëm6zôèÏ?ÿ<--->>^y|îܹ¼¼¼˜˜!Djjêˆ#BCC»uëööÛo+ý»õlyûË©òÆOHH8wîÜåË—ÓÒÒ” —–––žžíãã£lf»ûîøƒ,˃áÌ™3éééÊ7\M½WXø¢2mmI´*FÆ…êxѽ¼¼***”ÇÍø„8þ¼ò ¦¦æâÅ‹ÁÁÁõ60~° !BBBÊÊÊŒŠYYYîîîþþþõž’–––––6zôè>}úäççoÛ¶møðá¹¹¹S¦LY¶lÙÅ‹/^¼8kÖ¬º·'ã…Ð ÔqãõìÙ³k×®|ðÁ÷߯ô˜ÆÅÅ¥§§ïß¿ß8¡î;'''½^?a„?üP˜~¯0óR÷­FeZïÀH´í ¦8ú+>`À€={ö!***’““›úô7ž:uªººzùòåÊ`»ºt:]ff¦ò8""bèСIII¥¥¥W®\Y²dIbbbä#FdggðÁ ’$5jõêÕʧ¬ÒëÓ·o_eN¢mÛ¶5ýˆ+pô¿®øøøU«V 6ÌÍÍM1räÈC‡:tÈmmzßɲ\SSSUUuúôé>ø oß¾Âô{…™÷ºo5*cóhëp‰¶u&³Å|rUUU¿ùÍoºuëÖ±cǘ˜˜“'OZ·þæ!ã¢Q÷rßÄV­Zuüøñ>}ú$$$Œ9²©õÌž=û™gžñóóûôÓO÷ìÙãîî^oƒ… nݺÕÇÇgÒ¤I’$íܹ³¼¼<<<¼ÿþ}ûömôKÓfèС:®k×®Bˆ„„„ââbå›ÚË–-‹‰‰‰‰‰™5kÖØ±c›|ä€õ˜ºñë—òòòŒ“!„††VVVÆÆÆ*%6½ïV®\éêêêáá1zôè¬_¿^aê½ÂÌ{HÝ·+6Ϻš×ÛÝœ絨^ Z`Ÿ—o\\\LLÌŸþô§êêêýû÷O˜0aïÞ½cÆŒiFUÑÑÑ‹-š:uj“V5Û7Ö®]ûôÓOkµÚgžy&//ïÿþïÿ¬X¿µXxuÊ[mÝ´ó)Vy­íù³-::úé§Ÿž7o^ ëÑëõ«V­zä‘G¬Òªö¬îÛïvË’¿á–övû£mýâf·ìÚ°f¯­T‡™Í쪶Q¶ž4®Þªõë×+ãuGŽéÔ©SYY™0= fqqñìÙ³»ví0uêTeÀŸV«ýãÿØ­[7ooïèèh»ý $ý¸¨Çž_說ªôôôŒŒŒ¡C‡¶u[U±çŽMn±VÛQë9r¤òõꪪO?ýÔÃÃãË/¿TV 6ì±Ç+..ÎÍÍ6lØÌ™3Í—÷ë×ï½÷Þkt/uW]»vÍÃÃ###CY|öÙg§OŸ®<ŽŒŒ¼û_¿.ËrJJJhhhEE…,Ë<ðÀ„  ÊËËýë_?¾nåûöíóõõUfÚs6½ÂáˆÚú’¼mêÔ©AAA+V¬°Jm‘‘‘»wï¶JUí\[_¡°¡¶¾¸`_šqm4ÿRë5ZoðÜüùó•ò³gÏ !òóó•Å´´´: Så²ÅÑV–å'žx"))I–åÒÒR//¯#GŽ(å‘‘‘ëÖ­3nüÉ'Ÿ\¸pA’$ãoܸ!IRQQ‘²xìØ1­V{ðàA+Ve¥7F8¼¶¾aïÚú … µõÅûÒŒk£ùî²QŽø{T­?iÜŒ3¶lÙR]]½cÇŽ®]»Öý¯Ï†³`feeI’4hР°°°°°°¾}ûjµZã옟|òɈ#FŒÑ’3Ðúñ:öÆ¥…Ï7¦[ó¹Ä¸Ö’4l'Œ“ÆíÚµkÅŠÆÉá”ÛpÒ¸zåÂì¤qõVÅÆÆúúúîÝ»÷Ýwß}öÙgë®j8 fhh¨$I'NœÐjµ kîÓ§O```‹¾•g “·2èÖÔÒhk¤¦Œ+ËrMMMmmí¹sçN÷׿þµ¬¬¬á¤qõÊ…ÙI㮚1cÆË/¿|úô麿4-„ظqãÃ?±bÅ eLww÷±cÇNŸ>ýÍ7ßìÒ¥KAAÁÁƒ“wÔÖÖÚó¹U0IB{sÇÏ->ÛÐl¼QØ-Kn|Àê¬?¯m£Ã#²d.…¶Ò “Æ5\•˜˜xæÌ™|Ð8¶AÑè,˜ï½÷^PPÐðáý¼¼†zèÐ!ãöééé;wî´Ù¹i _tyë­hìðµÖëõ©©©-¯ÇŠÓWÛb&솸eË{h TÏo|Ûiý»¦ßËVëµmÈAûq8`jUppp½.Uóå#GŽüþûï­ªá*oooooïz£„z½þ«¯¾ªW¨Õj“““ý%¤–üÆ„ÐG‹FñŠ·œò_L®®®V©mÁ‚ÑÑÑV© 0…ßȺ÷o]íü^nÚUA?n+Ø´i“V«7n\[7Äj装)öÿŠŸ9sfÈ!Z­vøðáVŸÙZ˜˜šZ¡×ëÿøÇ?Ž5***jàÀÊo 6¬J¯×/]º466V¯×O:µ©c›:×^{í믿nRKËYxãÛy 0uó kß¿uµÛ{¹¿× Z'Ú‘qMñññY¾|ùßþö73ß3“d+”‰±¿úê«'žx¢nùÆO:U]]½|ùrebl3 ¶Ä[4Ctñ6ãæ-¸ëjç÷r“…ÝE[£u×Ö)ÿÌoFÆm$Z´73fÌHLLTºR”ù¤­;³µ™©©e¦*…åc›i°%îØ@ÝšzóŠÜ¿uq/[ÎNûü“¯72cë|ßù–<×>ÈYyÔcmaVÝ.â.n*ƒÁ¼yóæûî»ÏX¨×ëW­Zå(_Em’_L ä½}°D½_/k?ïÞ¿u©ø^6¥yÓ~)ìe¬­%Œ=¸æ3.ãq[ÈVãhçå€YÓøã§ùÔ71vðÞ¢òãö>©­´ëû×)Ú‘qmo†ÊÇÇG£ÑlÛ¶Íþ¿XÎn¿Lf]Ü¿ µð/;½n`ž%Ãìó`Û‰v¢%ÿý„ö†«EÅê}*ñú¶7-¿²×¶Q–tåÒkD¢Ø!Y–Ûç°4Ô½,v IDAT¼¢žhkDÆ5ƒD p ídXVù«F…ÑÖˆŒkD¢8Šz·¤ÛvÂZcQÔmÚmÆ%Ñé¶½±âëöõu¼u×ÖÝñ7TðüÂ@eúsæY÷Åm½¶ 󜙳épý¸ôÑT£á÷Éè»U¥†é¥…¯r;¶F*ȸ$Z€*‘nUÏê¹Vm.ã’hª×hº|º9¾FcŒU^V¢m}vžqI´€v¥Ñ™né¾uh¶Ëµ‚hk†]e\ mè:îs€Ú(²tߪ€MC­‚h{gm˜qI´(Luß×¶z‹`)3yÆê/Ѷ š”qE ^-- 5Ú}« ãÚ!óyÆF¯Ѷ9,ɸ¢é·‰P0%3í¾5â Ä!Øî/¢m‹X%ã’hh3Ý·°s¶îV'ÚZGS3®åH´4ÊÂ_؃V(B´µ2«ÜfÄY,W76síG›Œ{&ÚÚJ32.‰íßü`öûf²Í¢< M»ýXÞjYÍÛë!·§¶n€úÉ?3µAè:Yùg£>|xüøñ¾¾¾¦OŸ>K–,)++3³ýÀ·lÙÒ°ü»ï¾óôô´Q#ZŽhÛz\›&ZÅ¿þõ¯„„„~ýú9r$??Ë–-ùùù'Nœ°éNÚÑVÍjkkŸþùçŸ~åÊ•‘‘‘¦_¿~o¿ýö°aĹ¹¹“'O ™3gNyyyÃ._¾úè£ 6´F£š‹h«fBˆààà†«2339’œœìåå¥ÓéV¬X‘’’R[[[o›¯¿þú7ÞèСChhè‚ Z©ÝÍB´U³€€!DNNNÃUÙÙÙFÙ@ѽ{÷ŠŠŠÂÂÂzÛøùùùøø(‹={ö´q{Z„h«fQQQ!!! §;e9$$¤¬¬LéÖBdee¹»»ûûû×Ý,88¸¨¨¨²²RYÌËËk…64ÑVÍœœœÞzë­·Þz륗^ºpáBeeå©S§ž{î¹#GŽDDD :4))©´´ôÊ•+K–,ILLtrúÅõ ×ëû÷ï¿víZ!Deeerrr€Eˆ¶*÷ÐC}þùçG0`€¯¯ïc=-IÒÎ;ËËËÃÃÃû÷ïß·oß5kÖ4|úŽ;ÒÒÒî¹çžøøøøøøÖo?€å$ûüÑŽäë¶ê œç3ÏF5[¨î“ÙnRÛ‹m|”à—ø5²VA¯-T‚h • Ú@%ˆ¶P ¢-T‚h • Úªœ^¯OMMµJUÑÑÑÛ·o·JU¶@´€JmÕïÌ™3C† ÑjµÃ‡ÏÈÈ0–çææNž<9000$$dΜ9åååfÊçÎ{úôé¹s熅…%&&¶Í‘˜E´U¿7nÞ¼¹°°pܸqãǯ¬¬TÊ'Nœèêêzþüù£G;v,))ÉLùúõë{õêµ~ýú¬¬¬”””6;Óˆ¶ê7{öì^½z¹ºº.Y²¤¢¢âÀBˆÌÌÌ#GŽ$''{yyétº+V¤¤¤ÔÖÖš*o냸3¢­ú………)œ»víš““#„ÈÎÎÖh4ʪîÝ»WTTš*o‹†4 ÑVý.^¼¨<0 —/_B„„„”••(«²²²ÜÝÝýýýM• !œœ¸Z€]#¬¨ß† Ξ=[SSóꫯº»»ÇÅÅ !"""†š””TZZzåÊ•%K–$&&:99™*BètºÌÌÌ6>Óˆ¶ê7cÆŒÄÄD__ß½{÷îÙ³ÇÝÝ]!IÒÎ;ËËËÃÃÃû÷ïß·oß5kÖ˜)B,\¸pëÖ­>>>“&MjËã0A’e¹­ÛЈäëÉ6ªyžÏ<Õl!I’ŒC×Ùêä_l㣿´Mºó6BHÓn?–·ZVóãö˜åÚ ½¶P ¢-ðÿÙ»ÿ¨&®„üwXøÚÒˆ1B@ Yå§H æ€X|l­UtEÄ¥-l[*Šà\÷TPÛR>ëÒF+(ØŠ@Q°*¿$ß?ætš Éð3„÷ëøG2sçν“hÞÞÜÌh Ñ ¢-D[0ˆ¶` mÀ@ Ú€@´h Ñ ¢-D[0ˆ¶` Œ'ºŽ¢(–½õ1ª{mScÙC†QÛ±¥P ªŒD[=‚![€‘À„„1§P(ا%ÀÔD…ê¶Wq|ìÚb 0j«/0d 0ÕèU‘kµh;0ã` Úê ÙLMZŽÅbÈVKˆ¶ã·c ÑvâaÈ`*rDC¶ÚC´?¸Sˆ¶ C¶À2.‹![ ÚŽ+ ÜŒDÛ‰„![ ©Å­®mÇnÆ5*I ÉÂXà `r;¡UXR^\WÛ!Û?ã#òwˆ¶09 ÚL^È 0Ö˜œ€ ` mÀ@zøâF ¾ÀŒ~´ÐC`0ZÔaBD[0ˆ¶` mÀ@ Ú€@´h Ñ ¢-D[0ˆ¶` mÀ@ Ú€@´h Ñ ¢-D[0ˆ¶` mÀ@ Ú€@´h Ñ ¢-}¶þþþñññÊ[Äbñ±cdž]áÕ«WÍÌÌFÜ.Ý,X°`È6+—qwwÏËËÞáÚVk'˜¤JKK—/_niiÉår]\\âãã;;; !þþþEQÅãñ|||JJJèòb±øèÑ£ÌáýýýE]ºtI¥Z>²Gòq¯eyµ û_ߣí)о¾¾ ¯|ëÖ­Ï?ÿü°Ëhsøð C=úæôéÓnnneeeÍÍÍÇŽknn¾ví½wûöí}}}õõõ2™,00ðÁƒÚ×<’O|]?yñ‰¯Ö䎶ÉÉÉNNN<O"‘$%%1Û¥RéŽ;|}}¥Riiié/¿üòÒK/™››;;;—––Òe¾øâ 777úñÿ÷›˜˜´··BNœ8A¿ÀZVÞÖÖ¶qãÆY³f ‚ÖÖÖÁíÜ·oß•+W˜ÃwíÚµxñbggç \¿~]¥Lttô7¢££%IXX˜ÊášZ¥ö\H$æææ"‘(11‘¥ö“666®]»ÖÚÚZ,oÞ¼¹««‹½/zk`` ******))ÉÉɉË庹¹eddøøøÐ(Š266¶°°Ø²eKGGGUU•ö•3Ÿž,‘t™~Ü|âk0¹£­X,>þ|[[[AAÁ'Ÿ|òå—_2» «««ýýý×®]+‹›ššÎ;÷é§ŸÒ/^\QQÑÒÒB)..–H$—/_¦h_yhhèýû÷åry}}=ŸÏ²ÙEEEk×®ŠŠRÙ›––6wîÜ´´´ÚÚÚììlí»¬âÖ­[ .\xôèÑÍ›7_yå–ØOºf͓۷o———ÿðñ±±Zö@ßTTT444¼þúë*Û)ŠRÙ’››kbb2gΜáh|>î >ñÿÓ$ˆ¶ÉÉÉVJ™]ÁÁÁöööEyxx„……3»"##§OŸN©®®¾råÊG}ôÌ3ÏØÚÚnݺ•. \\\JJJ>|¸qãFúp&ÚjSù;wŠŠŠÒÓÓ­¬¬8ÎþýûÏ;÷øñcömذÁÜÜœ²råÊòòr®K«T?}úT.—···óùüùóçëZ­ººº¬¬,55•Çã …ÂÄÄÄììì‘÷`üÑ£Z3gÎÔT %%E(𙙥¤¤äääØØØ ïDãóqOð‰ÿŸ&A´ˆˆ¸ªÄÚÚšÙUXXèççgkkkgg—‘‘A¿Yi"‘ˆ~ÐÐÐ0}út úésÏ=Ç”Y²dÉ… Š‹‹_|ñEúñÏ?ÿÜÔÔ$“É´¬¼¶¶–¢(///‰D"‘H\]]ù|þÝ»wÙ{deeE?àp8ÝÝÝýýýÚ_ –V©pppÈÉÉ9tèP(ôóó£Ç¤uªÖÐÐÀårSmOO3ïb$}ô'ˇ5<šššêêêBBBè&&&Ê?°yòä ½‘åDãóqOð‰ÿŸŒ'ºCãñxb±˜yú‡?ü~ÐØØüüãÅ_¤(jÛ¶m?ýôSŒùZaæÌ™=êíí6m!¤©©‰)Õßß¿dÉ—æææ'N,\¸ÃáhY¹­­-EQ×®]ãóù£Øe##õÿå`oÕ`AAAAAAÝÝÝ)))«W¯~ðàASS“¦4T,wvv¶´´ÐïõÚÚÚiÓ¦1ïo€ÉÅÙÙ™¾Û’»»»òv…BA¾s¹\¡P¨r”D"QþÌýùçŸ !ööö#iÉh}Ü|â+™£¶šÐ¿úruu¥(êÞ½{'NœP[L*•zxx8p€ÒÛÛ›ššÊìòóókhhø¿ÿû¿€€Š¢/^üñÇÓ³´¬|öìÙK—.}ûí·éi---ùùù#ïšP(¬®®¼]ËVѪªªJJJz{{9Ž@  ÿgÉRƒ¦“:::z{{ÇÆÆvttÜ¿?>>>,,LÓß =gddtðàÁƒ&$$ÔÔÔôööVVVnÚ´©¬¬Œå¨ðð𬬬¯¾úª«««¦¦fË–-K–,a¾ÅžQù¸'øÄÿO“¬¹ÊwîÜ)“Éd2YddäÒ¥K5•>>tŠ¢Œ-,,¶lÙÒÑÑQUU¥}åûöí»rå ýX*•îÚµkñâÅÎÎÎ ,¸~ýºJ™èèè7nDGGK$’°°0•Ó““œœx<žD"IJJòtH$æææ"‘(11‘¥–ó666®]»ÖÚÚZ,oÞ¼¹««‹9—¦îè3¶ ¯¿þºÊvåå+h¹¹¹&&&sæÌö¹ŠŠŠ ***Ö®]¥²7--mîܹiiiµµµÙÙÙ*{ÅbñùóçÛÚÚ >ùä“/¿ü’åD·nÝJHH¸pá£GnÞ¼ùÊ+¯°TÂrÞ5kÖ˜˜˜Ü¾}»¼¼ü‡~ˆÕ¾;zÈÀ£mKK !dæÌ™š ¤¤¤…B33³”””œœ›aŸkÆ æææ„•+W–——ëtlpp°½½=EQaaaÅÅÅ,…Ÿ>}*—ËÛÛÛù|þüùó‡QIuuuYYYjj*Ç …‰‰‰ÙÙÙ£Ò€ aÑöèÑ£ÔoTv BÈÝ»w5qõêÕ¦¦¦ºººz£‰‰I__SæÉ“'ôFöfXYYÑ8Nwww¿ö](,,ôóó³µµµ³³ËÈÈ ¹&999‡ …~~~—/_F% \.—¾>t===­­­£Ò€ aÑ6<<\ñ•]ÎÎÎb±xð ˜’\.—µUÞ+‘H~úé'æéÏ?ÿL±··a;ŒÔ_íÆÆÆààà;wÖÕÕÕÕÕEFF   ‹/¶¶¶.[¶lõêÕ …‚¥µç‹ÅLü­­­6mg&#Cˆ¶,ŒŒŒxð`xõdee¹¹¹577Ÿ:uJ›ò …¢¯¯O׳lݺõùçŸ^mŽIù±®`|LâhKQ”±±±……Å–-[:::ªªªT $'';99ñx<‰D’””DoŒŽŽ¾qãFtt´D" {ë­·Ž9rúôi‰DòÙgŸB×®]kmm-‹7oÞÜÕÕE(•JwìØáëë+•JKKK¥RéÇìëëËápd2ÙÝ»w÷îÝkcc#Ô.ëµoß¾+W®0UíÚµkñâÅÎÎÎ ,¸~ýºr•ª«¶S,ç:pà€D"177‰D‰‰‰Ú_•zX.‹Ú¾Œ?ã‰nÀ(ÈÍÍ511™3gŽÊv±X|þüy‰DrõêÕeË–999­Y³&--í›o¾yÿý÷CBBèbE™››ôÑGôÓ5kÖH$’Û·owvvþéOŠýôÓOé]………—.]š>}:ý4++ëäÉ“vvvÁÁÁþþþÁÁÁ555ßÿý’%KV­ZåààÀÒæ¢¢¢¯¾úÊÜÜüïÿ{TTÔ×_ÍìÜÂ!;¥é,·nÝJHHËåsæÌyüøñíÛ·uº2ÊX. K_ÆÓ$µMII …fff)))999666*‚ƒƒííí)Šòðð +..²Îêêê²²²ÔÔT' ³³³轑‘‘L®%„lÞ¼yÞ¼yfff¡¡¡---»wïær¹~~~NNNr¹œýD6l077'„¬\¹²¼¼\û^ëÔ)ccã§OŸÊåòööv>Ÿ?þüaTB†º,Ãî ÀèÒßh{ôèQê7j DDD\½zµ©©©®®Ní@caa¡ŸŸŸ­­­]FFFKKË'mhhàr¹€~êààÐÓÓÓÚÚJ?‰DÊ…™§\.W(1OÛÛÛÙOdeeE?àp8ÝÝÝýýýC¶mrppÈÉÉ9tèP(ôóó»|ùò0*!C]–a÷¦ `”¨}ƒéo´ WüFm:Pš™™©ÝÛØØ¼sçκºººººÈÈH¦&ƒ&‹;;;™¨W[[;mÚ4&ºiºˆ£NS Y:¥IPPÐÅ‹[[[—-[¶zõj…B1Œ+Ã~Yô„þFÛ¢ÇM]]])ŠºwïÞ‰'˜]B¡°ººZíQŽŽŽÞÞÞ±±±÷ïß c‰ÂcDS Y:¥VUUUIIIoo/‡Ã&&&ì•h:¯ž\v›NwîÜ)“Éd2YddäÒ¥K™]qqqÇ·°° R9Š¢¨üüü®®.{{{WWWµ·;kšZÈÒ)µº»»·mÛfmmmii™™™™ŸŸOQÔ0®Œž\vÔßhkU‹Ò7õ£R!Áû É ­¦5R¡¿?V×®æ?ã#òw;j S ¢-D[0ˆ¶` mÀ@ Ú€ÐÇhûÞ{ïQuîÜ9]”J¥………ƒ·/X°àرcôcww÷¼¼¼á5l$Dz·J›íj ¨4iÈcUÊhS^­aœ`¬é]´}òäIvv¶››[ff¦Ú …¢¯¯O§:·nÝúüóÏFët3Œ¦-ZËR@מŽÖ•™¨+  Lï¢í©S§ ÅáÇϜ9ÓÔÔÄl—J¥;vìðõõ•J¥¥¥¥=Ú´i“ݳÏ>;þ|fyØ;wî,Z´ÈÔÔÔÓÓóúõëôÆ}ûö]¹r…}ãÆèèh‰DFikkÛ¸qã¬Y³AHHHkk+}Èàú+ ¿ýö[º|yy¹™™™Ú¦&'';99ñx<‰D’””4ä`Z+•JwíÚµxñbggç hÓf!D›ó*—?pà€D"177‰D‰‰‰,•°Ÿ·±±qíÚµÖÖÖb±xóæÍ]]]ÌeQۀѢwÑ6##cݺu^^^ŽŽŽGUÞUXXXXXX]]íïï¿~ýúººº²²²Geggóx<ºLzzzjjꃼ½½£¢¢T*OKK›;wnZZZmmmvv6!$44ôþýûr¹¼¾¾žÏ燇‡Ó%×?øXÊM‹ÅçÏŸokk+((øä“O¾üòKí¯FQQQAAAEEÅÚµkµéŽ2Î{ëÖ­„„„ .Ì`Ò°]WWWccã0`dô{—mmm)ŠºvíZío>|8wî\Mõ+Káñx===ôc&½©4µ±±188xçÎuuuuuu‘‘‘ƒ;>*Mb ã¼AAA/^lmm]¶lÙêÕ« K%šÎ+‹;;;™\[[;mÚ4&ÑŒ)=špöìÙæææ²²²«¿ÉÈÈ(((xðàJÉÙ³g/]ºôwÞillT(ÚÇ\¡PÈü挮çí·ß¦oiiÉÏÏg©_ùXBˆ§§ç™3g!===©©©jO×ÞÞNquu¥(êÞ½{'NœÐéšèÔ‘œ·ªªª¤¤¤··—ÃáöJ4×ÑÑÑÛÛ;66¶££ãþýûñññaaašr0ÀèÒ£Ìqøðá5kÖÌŸ?_ü›ððp›œœœÁ…óòòf̘áååÅçóÃÂÂ覸¸¸ãÇ[XXBrssE"ÑÂ… y<ž··7sǵõ«»wï^¹\îââ°hÑ"µ§sttܹs§L&“Éd‘‘‘K—.ƕѾ;Ã>oww÷¶mÛ¬­­---333óóó)Šb©DÓy)ŠÊÏÏïêê²··÷ððpuuMNNÅþ° Fåûq剳£û…;Lex_€á8¡æWFƒQ¡¿?V×®æ?ã#òwz4j tƒ'ñ IDAT0ˆ¶` mÀ@ Ú€@´h Ñ ¢-D[0ˆ¶` mÀ@ Ú€@´h Ñ ¢-D[0ˆ¶` mÀ@ Ú€@´h Ñ ¢-D[0ˆ¶` mÀ@zEzC¨-D[0ˆ¶` Fg®­B¡•z©SG·BÆ_-þ:F5kIy.²mÊ(_7FÝ÷†F…ê¶Wq|ìÚb 0j 01UG¢-À$€¬ D[€ ƒÀ:ºmô°–m&bë(B´ÐkȾÚC´˜`¯£Ñ@!õêÑ`â!ÂŽ D[=…¼«+D[½€ ;rˆ¶úIwmôâìOtÀ`Q5ÑM˜Ä¨PíÊ…â"ÿ£¶` mÀ@ Ú€À\[ …b¢›†IyJ7FmÀ@ Ú€@´h Ñ ¢-D[0ˆ¶` mÀ@ Ú€@´h Ñ ¢-D[0ˆ¶` mÀ@ Ú€@´п¿?EQEñx<Ÿ’’zû7V¬Xaeeejj*•Jãââ˜CJKK—/_niiÉår]\\âãã;;;éªâããGØww÷¼¼¼Vb0mt³}ûö¾¾¾úúz™LøàÁƒ—_~Y$]¿~½µµ5//ÏÁÁ.|úô退77·²²²æææcÇŽ577_»vmb»`¨mtCQ”±±±……Å–-[:::ªªªîÝ»÷Ë/¿ÄÄÄ̘1ÃÔÔÔÝÝ}Æ „¨¨¨¨¨¨¤¤$'''.—ëææ–‘‘áããÃRÿ$‰¹¹¹H$JLL¤7¶µµmܸqÖ¬Y $$¤µµ•}ãÆèèh‰DF …ß~û-}Hyy¹™™ýX*•nÛ¶mñâÅ^^^2™¬¢¢bì®ÏB´¦ÜÜ\“9sæˆD"GGÇÈÈÈÏ?ÿ¼¾¾ž)PQQÑÐÐðú믫HQ”¦:oݺ•páÂ…Gݼyó•W^¡·‡††Þ¿_.—×××óùüððpBHZZÚܹsÓÒÒjkk³³³Ù[{êÔ©‚‚‚ÿûß6lX¾|yooïðz­Ïmt“’’" ÍÌÌRRRrrrlllŒŒŒ¾ùæ›… îÛ·oöìÙÏ=÷=ÿµ¥¥…2sæLí+766~úô©\.oooçóùóçÏ'„ܹs§¨¨(==ÝÊÊŠÃáìß¿ÿܹs?Ö©Ù6l077'„¼ñÆOŸ>½té’N‡O ˆ¶º‰ˆˆ¸zõjSSS]]]HH½ÑÚÚzÏž=ßÿýÇ7nÜzýúu@@¹{÷®ö•;88äää:tH(úùù]¾|™R[[KQ”———D"‘H$®®®|>_§j !B¡Pù±®‡O ˆ¶ºár¹ô¨­Ú½fff±±±Ï<óÌ?þèìì,‹;¦RF¡P°ÔtñâÅÖÖÖeË–­^½Z¡PØÚÚRuíÚµÚß<|øpîܹ„#£ÿˆs<¯§§‡~LÏÇeܾ}›~Ðßß_WW§ÓXòdh 0RMMMï½÷ž\.ïììüõ×_÷ìÙÓ××çååeddtðàÁƒ&$$ÔÔÔôööVVVnÚ´©¬¬LSUUUU%%%½½½G ˜˜˜BfÏž½téÒ·ß~»±±‘ÒÒÒ’ŸŸO— …ÕÕÕÌážžžgΜ!„ôôô¤¦¦*לžž^YYÙ××·{÷n‡ãïï?Wb‚!ÚŒ”©©éãÇ×­['fÏž]TTTXXèèèHY¹rå… ÊËË===---ׯ_okkëîªîîîmÛ¶Y[[[ZZfffæççÓ¿9ËÍ͉D .äñxÞÞÞÌmâââŽ?naaDÙ»w¯\.wqq X´h‘rÍ7n|óÍ7§OŸþÏþóÌ™3Ó¦MÃ+2A(öñð‰’ú0uèBÃòW‹¿ŽQÍZRþE¤mÊX]üº î%!ÿù©§Ÿ‘cêJ¥{÷î]µjÕD7dô)¿Í0j Âx¢`àXîZG©QÝ;vã¸ÑÀðUUUMtÆ&$Œ-æaÈ`$mÀ@ ÚŽ9-n1d 0Bˆ¶ªüýý)Š¢(ŠÇãùøø”””ÐÛ,X0xi1îîîyyyÌÓk×®¹ººZ[[Ža‹u¡ÒBC‚h;†¸Å-€¾Ù¾}{___}}½L& |ðàÁðêÉÊÊrssknn>uê”6å E__ßðΈ¶jPelllaa±eË–ŽŽŽÁwHNNvrrâñx‰$))‰Þ}ãÆèèh‰DöÖ[o9räôéÓ‰ä³Ï>#„466®]»ÖÚÚZ,oÞ¼¹««‹>P*•îØ±Ã××W*•–––J¥Ò?þØ××—ÃáÈd²»wïîÝ»×ÆÆF $''ní$‰¹¹¹H$JLL¤7¶µµmܸqÖ¬Y $$¤µµup !B¡YÛ¬¼¼ÜÌÌŒiÒ¶mÛ/^ìåå%“É***F÷ Üükœ( M÷¸Å-€>ËÍÍ511™3gŽÊv±X|þüy‰DrõêÕeË–999­Y³&--í›o¾yÿý÷CBBèbE™››ôÑGôÓ5kÖH$’Û·owvvþéOŠýôÓOé]………—.]š>}:ý4++ëäÉ“vvvÁÁÁþþþÁÁÁ555ßÿý’%KV­ZåààÀ´äÖ­[ r¹|Μ9?¾}û6½=44ÔÄÄD.—s¹Ü˜˜˜ððð³gÏn!‹S§N}÷Ýwæææ999Ë—/¿uë–ž/Ï‹Q[5RRR„B¡™™YJJJNNŽJàà`{{{Š¢<<<Š‹‹‡¬³ººº¬¬,55•Çã …ÂÄÄÄìììzodd$“k !›7ož7ož™™YhhhKKËîÝ»¹\®ŸŸŸ“““\.W®ÖØØøéÓ§r¹¼½½ÏçÏŸ?Ÿrç΢¢¢ôôt+++‡³ÿþsçÎ=~üX§‹°aÃsssBÈo¼ñôéÓK—.étøøC´?jgÜbÈ`B=z”úÚW¯^mjjª««S;ÀYXXèççgkkkgg—‘‘ÑÒÒ2äI¸\®@  Ÿ:88ôôôÐó!"‘H¹0ó”Ëå …B###æi{{»rI‡œœœC‡ …B??¿Ë—/Bjkk)Šòòò’H$‰ÄÕÕ•Ïçß½{wÈF* …Êu=|ü!ÚÀT®øÚt d&žªhll Þ¹sg]]]]]]dd$S“A‹ÅL®­­6mš••ýTSÈÖFPPÐÅ‹[[[—-[¶zõj…BakkKQÔµk×jóðáùsçn!Çëéé¡39›ÆÌmèïﯫ«›9sæ°[8>mÇ•Ê_ ÙLRô¸©««+EQ÷îÝ;qâ³K(VWW«=ÊÑÑÑÛÛ;66¶££ãþýûñññaaa,QXKUUU%%%½½½G ˜˜˜BfÏž½téÒ·ß~»±±‘ÒÒÒ’ŸŸ¯¶…žžžgΜ!„ôôô¤¦¦*לžž^YYÙ××·{÷n‡ãïï?¦Ž5DÛq¢ö+úŠþ3Q­€áqttܹs§L&“Éd‘‘‘K—.evÅÅÅ?~ÜÂÂ"((Hå(Š¢òó󻺺ìíí=<<\]]ÕÞî@WÝÝÝÛ¶m³¶¶¶´´ÌÌÌÌÏϧ#Gnn®H$Z¸p!Çóööfnƒ Ò½{÷Êår—€€€E‹)×¼qãÆ7ß|súôéÿüç?Ïœ9£ç¿!#„PZ®•5ÎR¦]hXþjñ×1ªY-]¿Y­qܺqí%À(É×p0éç‡ ¦üW¯Ú¤#•J÷îÝ»jÕª‰nÈ”ßf¸ùטö‡43‚‹¹ ºB´MZ&Zú¿­ì…‘qt…h; tJ´ƒŸ"〼›þC´&í§ 9µ@&äZ˜ CB´ÕÍ(&Z–C´Ì¸1@ nþ¥öÕJ %#9öõàöa„7n¬X±ÂÊÊÊÔÔT*•ÆÅÅs®^½ªé†Þ#TZZº|ùrKKK.—ëââßÙÙIñ÷÷§ß<ÏÇǧ¤¤„./‹=ÊÞßßOQ”þ/Š0ZmÙèšhÇ¢ ȸì^~ùe‘HtýúõÖÖÖ¼¼<‡‰n…BÑ××§MÉÓ§O¸¹¹•••577;v¬¹¹ùÚµkôÞíÛ·÷õõÕ××Ëd²ÀÀÀŒe« Ê{ï½GQÔ¹sçt=P*•Þ¾`Á‚cÇŽÑÝÝÝóòò†×°‘ËÞªaÝ&D[5ô!ÑûttÀ:3ÒîÝ»÷Ë/¿ÄÄÄ̘1ÃÔÔÔÝÝ}Æ ô®¶¶¶7Κ5K „„„0+>zôhÓ¦MvvvÏ>ûìüùóéåX×®]kmm-‹7oÞÜÕÕE–J¥»víZ¼x±³³ó‚ ®_¿Noÿå—_^zé%sssggçÒÒR¦=ÉÉÉNNN<O"‘$%%1Û¥RéŽ;|}}¥RiHHÈ /¼Àì*++{öÙgéáXÆÀÀ@TTTTTTRR’““—ËussËÈÈðññ¡ Pelllaa±eË–ŽŽŽÉ8Ó`BŸNo_¿~}]]]YYÙ£G²³³y<!dÍš5&&&·oß.//ÿá‡bcc™zŠŠŠ ***Ö®]Eo\»v­X,njj:wîܧŸ~Ê‹ÅçÏŸokk+((øä“O¾üòKfWaaaaaauuuffæõë×+++éíYYYëÖ­ãr¹Ê¯¨¨hhhxýõ×Uú;øÍÍÍ511™3gŽÎ×`J:uê”B¡8|øð™3gššš˜íÊc¥¥¥jÇA!wîÜY´h‘©©©§§'3Þ±oß¾+W®B¢££oܸ-‘Hˆ.ã,ƒ …ÌúaåååÌä7•¦jUÑäÀ‰ÄÜÜ\$%&&ÒÕ¶S§&mÛ¶mñâÅ^^^2™¬¢¢b˜/ψ!ÚNšD;2.!ÄÈÈè›o¾Y¸pá¾}ûfÏžýÜsÏÑߛܹs§¨¨(==ÝÊÊŠÃáìß¿ÿܹs?®©©9þüáÇE"‘‘‘‘‹‹‹H$ª®®.++KMMåñxB¡0111;;{``€>ņ ÌÍÍ !+W®,//'„TWW_¹rå£>zæ™glmm·nÝÊ´'88ØÞÞž¢(°°°ââbfWddäôéÓ !ô†Ÿ}ö!¤³³ó‹/¾xë­·TúÕÒÒB™9s¦¦Ž§¤¤…B33³”””œœ›Qº¢.##cݺu^^^ŽŽŽÊ¿O JcþþþjÇA!ééé©©©<ðööfÆ;iiisçÎMKK«­­ÍÎÎ&ºŒ³ >–…rSYFU»uëVBBÂ… =ztóæÍW^y…Þ®¶:5éÔ©Sÿþ÷¿7lذ|ùòÞÞ^öòcdêÞ!ax7£ÕOZÞZÙ;):¥=kkë={öìÙ³§££####44tÞ¼y­­­Eyyy1Åø|þÝ»w›ššLMME"‘r \.W ÐOzzzZ[[­­­ !VVVôv‡ÓÝÝÝßßßÐÐ0}út zûsÏ=ÇTUXX˜œœ\[[KQT[[Û’%K˜]Ê'ˆˆ Ú»wïÉ“'gÍšåíí­Ò)º1wïÞeZ¥""""..ÎÌÌLùl&&&ÊßL=yò„Þ8Ę2jjjŠ‹‹wïÞMyíµ×233ãââ˜ÏGf ‚¹{÷.ýO·‹‹ SCtt´»»;!dãÆCNB ÇYîß¿O”ìß¿ßÜÜüñãÇ<ÐT¿–˜¦B‚ƒƒę́ʚ5k4hllüôéS¹\nccÃçóçÏŸÏÒN>Ÿ¯}“˜‘ 7Þxcûöí—.]z饗tí×ÈM­QÛ˘É;F« ]Çq l(×ÌÌ,66ö™gžùñÇmmm)ŠºvíZío>|8wî\;;»®®®ÆÆFåÅbqgg'=PJ©­­6m“h›9sæ£G˜ÿ2ßg566ïܹ³®®®®®.22RùµP¾Ú¾¾¾–––gÏžýì³ÏÙBœÅbñàéÿL…\.—µUÞ+‘H~úé'æéÏ?ÿL±··×ÔÃsôèQ–ϸ¬¬,z@!44´¦¦æâÅ‹Ì^f ¢¶¶vð8ù>ÍÌÌŒï`i =Òáåå%‘H$‰««+=ÎÂR¿–”-,,ôóó³µµµ³³ËÈÈ`>ÎÔrppÈÉÉ9tèP(ôóó»|ù2K;uj’P(T~¬ëá£eJDÛËú{±Ñºu—>о/“=ã655½÷Þ{r¹¼³³ó×_ݳgO__Ÿ——×ìÙ³—.]úöÛoÓ)¶¥¥%??ŸBoçw EEEEcc££££··wlllGGÇýû÷ãããÃÂÂŒŒ4þíJ¥ „ôöö¦¦¦ÒÛÛÛÛ !®®®EÝ»wïĉ,-ˆˆøÛßþö¯ýkð„ZBˆ‘‘ÑÁƒ<˜PSSÓÛÛ[YY¹iÓ¦²²2–:ÃÃó²²¾úê«®®®ššš-[¶,Y²d$ÿtL:áááš>ûûû9òË/¿XYYYYYÑ–‡f 0Ÿ†jÇA´¤üñ¡Ó8‹Ê±„×ÓÓC?f&éª4•}TE­   ‹/¶¶¶.[¶lõêÕ …BS;ujÒíÛ·éýýýuuu,sêÆ”!G[]íø´jüvÆ555}üøñºuëÁìÙ³‹ŠŠ  !¹¹¹"‘háÂ…<ÏÛÛ›™öž——7cÆ ///>ŸÖÞÞNQT~~~WW—½½½‡‡‡««krr2ûyOžÿüsfKÿìÙ³cbbÞ}÷]©TºwïÞU«VÑ»>|wîܹ¶¶¶çž{.77×ÑÑQ¹Lmm­½½}__Ÿ±±ñ‚ bbb^{í5BÈåË—#""ZZZòóó?~œpúôiú'+V¬HIIÑT¿Ê±µµµo¼ñÆÃ‡Ÿ}öÙ+V$&&vttBTšúá‡fgg ‚éÓ§ÛØØ<|ø¦Ê­bÈåòÈÈȪªª?üᎎŽû÷ï÷õõ%„hj§öM /((¸yóæÜ¹sÓÓÓÝÜÜÆüýòÛÌp¢-í0 ãN ôôôäää›7o²Ì|˜RôêóôÞ$“^µ)B%m3å·Ù¤¿CíHèzkÛ\ÆÑѰ͂úÿ¸Voœ°OC®5“5Ú"ÑŽ.-3.³/2î‰÷<œè& É4bÄü, ¿ ;:-çKÿŸ†Œ3ú‡•<ÏÇǧ¤¤„Þ>*k²³(--]¾|¹¥¥%—Ëuqq‰§aÖÔ±X¬|Ïùþþ~Š¢.]º¤RíX7¦¸ªªª‰š bDÛ)xë.} ýÅDÆCµ}ûö¾¾¾úúz™L8ø7Ô£îôéÓnnneeeÍÍÍÇŽknn¾víÚÈÛ3Q ÜŒ3ý¶ ÕÚÿŸ EQÆÆÆ[¶léè訪ªR) iÝvµKÏkZGž100•””äääÄårÝÜÜ222|||´l f{BˆT*ݵk×âÅ‹,XpýúõÁåu]’@OèÝ\[üf_ŸaJ.LM¹¹¹&&&sæÌQÙN¯Û.‘H®^½ºlÙ2'''zqËõëו•• …ÂÊÊJzéùÐÐP¹\ÎårcbbÂÃÃÏž=«\[EEECCÃà%<ÿuÓÔí}õÕWæææÿûߣ¢¢¾þúk-» çôeÔְ׿5<Ç…© %%…^Í8%%%''ÇÆÆF¥@pp°½½=EQ̺íä·¥ç>,‰ŒŒŒ\\\D"½>{zzº••‡ÃÙ¿ÿ¹sç?~¬\½6&Ëú=C¶G{ÌRï+W®,//\@mצ¬ï¾ûnÅŠÓ§Oçp8R©tãÆ:}m2 c7?ÞÝÝ=//o,jÖm‘h';d\ÐÆ$}õ#""®^½ÚÔÔTWW2¸€ÚuÛÕ. ¯Íúìôºt,«®«m‰‰I__SæÉ“'ôFö®YYYÑ8Nwww¿6]˜šN:àììüí·ß¶¶¶ž?ÞÙÙyì~—©P(úúú0?~Ø&&Ú"Ñd\Ò¤{é¹\.=Jªv¯¦uÛÕ. ϲ>;ÃÙÙY,þ¼dþZ©mD"ùé§Ÿ˜§?ÿü3!ÄÞÞ~˜}fíÀ400°yóæÍ›7ïÙ³çü#—Ë•H$QQQ‰‰‰tMÓè5Mjg)¿cÇ___©TZZZªÅúõëëêêÊÊÊ=z”MOßgܺu+!!áÂ… =ºyóæ+¯¼Âr¢´´´¹s禥¥ÕÖÖfgg³÷ýÔ©Sÿþ÷¿7lذ|ùòÞÞÞ!/—>óhK)a/©o‰vŒî.9s\žŸF'ÅÜÜ\‘H´páBçííÍ “([¹rå… ÊËË===---ׯ_okkëîîÎÒŒ°°°?üðÝwßµ²²Z´hѬY³FžDYº0ÕЃÌ$ø””:пãdŸF?xR;{ùÈÈÈéÓ§«4@íô}寯ÆOŸ>•Ëåííí|>þüùCžHKLûßxã§OŸŽ4úi¬î0ÙotpúôéàààØØØääd±XüóÏ?Ÿÿæ›onذá»ï¾›Àö¨P~•qkPF¿âúùrkúG\ùGW|ðÁ|0¸Œ……EFF†ÊF>ŸŸšššššÊ~^™LvîÜ9íÛC‰ŒŒŒŒŒd¯V¹ÙÊ?‘H$jÿÖÔ5ƒtôèÑ¿üå/ôc•¿ôÄô»wïÒ³ácbbbbb233÷îÝK”¦Ñ3åéiô|>Ÿ¨›ÔÎ^^í÷-j§ï+sppÈÉÉ9xð`xx¸§§çîÝ»-ZÄ~"- …BåÇ,¿Ð+£Ÿ¿k×.;;;sssww÷Ѽ£ Ó`0¼Ö0±ÂÃÃ5}<¹¸¸ˆÅbM_†h3^ûòjã“Úéû*‚‚‚.^¼ØÚÚºlÙ²Õ«W+ –ýGöãñx===ôc•ûmß¾}›~Ðßß_WWÇrÿý¢ ãy®q@¯ý#—ËÕî]´hÑ|@?NNN611ijjR(3gÎT(ÙÙÙ¶¶¶=== …âÕW_]½zuKKKWW×;ï¼³|ùråÊ‹ŠŠ,--¿þúë‘tœá›&­‰~W‚žÂ›d22€W­°°ð™gžÙ±cÇO?ýÔÓÓSWW÷æ›oΙ3‡Þ»lÙ²   {÷î)Šæææ“'OÒÛœœ èÇwîÜ!„ôõõiY^¡Pxzzþïÿþ/ýxéÒ¥¯¾úê½{÷®_¿N˸yófqq1>lmm=00Àr¢eË–íÚµ‹9|ݺuÿýßÿ­P(º»»_~ùe.—Ë´ÇÖÖ¶¢¢âÉ“' ³fÍ¢O¡Ÿ”ßf#µ5Œ1ÚÁÆíî’AAAŸ}ö!¤³³ó‹/¾xë­·˜½ƒç¸°O‘ËåþóŸ |}}‡×ž 1éÞ0¥Ëåò^xÁÌÌÌÇÇg``àôéÓô^m¦Ñ+Óµ<Ñ0}ŸÑÝݽmÛ6kkkKKËÌÌÌüü|:˜i:Q\\ÜñãÇéBÙ»w¯\.wqq X´h‘rÍ7n|óÍ7§OŸþÏþóÌ™3Ó¦MÓúšM¨ÑÊÈctŠ 1ä¨mLLLccc{{»òv‰D’‘‘Á<¥ç|ûí·*‡+Ú*Н¿þÚÚÚúÉ“'GŽ™;w.³ÝÉÉ)//yêé陕•URRbddd§ÄÜܼ²²’.“””´bÅŠávzâá»&›‰~3‚žÂ›d2«6I©Œ"ë9å·Ùˆ~FÆÔÅ>pËìUL’øÂÜ]Rå‡É …‚î }wI•£´¼»¤Ê___KK˳gÏ~öÙgÊC¶DÝfêŒÚià...ÖÖÖ:õThù‹C€!Ît͸D¿c.}wÉuëÖ™šš†‡‡Ïœ9“¾CÂk¯½Fß!A­ðððØØØÿú¯ÿ’ÉdMMMšî.) Un¶ñ·¿ýíÆ_~ù¥òöôôôÀÀ@GGÇÄÄD‡ãïï?mÚ4úÖ˜Ÿ|òÉŒ3ZZZ._¾L¡@¡çÖŒÒ5[ÚÇYýüí<èjÈ_‰Ù¦(ðK2¹Q¾C‚¦ÁáÁ´œ§;QÆîî’*s\èoÞ¼¹bÅ úÆ" µs\Xæè””” ¾ ¼^ÑòE·MQ0Ƨa0Æá…Öf)v•N_»vÍÕÕÕÚÚ:00pLÛ6v˜^Ó}gÏž¥oÆ9lZÞ™Ûà©0xUUU«V­šèV ÇXÝ×–Lþé ctwÉE‹ݺuKy‹¹¹¹¹¹¹ÊlBˆT*ý׿þ¥²‘åÖ˜)))ì§ž(ZþAvªÑçW<++ËÍÍíÇÔ²¼B¡èïï711ÓVédëÖ­ôÿÆ•ûR[[»k×® nÀX…v cwìdffòùü—^zi¢2Êt£ŸV>£W\›Ï“““œœx<žD"IJJ¢7ªÜpú­·Þ:räÈéÓ§% }“ÆÆÆµk×Z[[‹ÅâÍ›7wuu1gT^ó]*•~üñǾ¾¾G&“ݽ{wïÞ½666 99Ym›Õ®ü®Óm­‰†õåéè•û"‘H^xáåh˾0ýà¶ ^}^›ëÉÒr€Q7†£¶ƒMöqܱ`aaÁårOœ8¡òó²É c´Àb¬_÷S§N}÷Ýwæææ999Ë—/¿uë–ÊÝjÄbñùóç%ÉÕ«W—-[æää´fÍš´´´o¾ùæý÷ß ¡‹QennþÑGÑO׬Y#‘Hnß¾ÝÙÙù§?ý)66öÓO?¥w^ºt‰Y0++ëäÉ“vvvÁÁÁþþþÁÁÁ555ßÿý’%KV­Zåàà Üzåw¹\>gΜÇ3¿ÕÔ‘ÐÐP¹\ÎårcbbÂÃÃÏž=KY¿~½‘‘QYY™P(¬¬¬T^_>++K¹/gÏž‰‰aö²¨¶mƒ/”–×SSËFÝÄÄ)Œã2>|ØÐÐàçç§²}ÒÍqÁ-°Ÿ×}Èσƒƒííí)Šòðð +..²Îêêê²²²ÔÔT' ³³³™5ÿTÖ|ß¼yó¼yóÌÌÌBCC[ZZvïÞÍårýüüœœœär¹JÍjW~×ÔM·µr}yMØdi›®×sTÖ²`áïïOñx<Ÿ’’zû7V¬Xaeeejj*•Jãââ˜CJKK—/_niiÉår]\\âããé[vúûûÇÇÇksRí'”çÔóaü´ÀðLðH!2îd‡D Ú·—~ÈÏ ýüülmmíìì222èõYØ544p¹\æWž===ÌWê*9’yJß"ù6†Ëå¶··=zTù¯ ½òû¡C‡„B¡ŸŸßåË—Y:¬OO-puu¥W„r}yMØdi›2m®§¦–ëÚ`Û·oïë뫯¯—Éd<xùå—E"Ñõë×[[[óòò˜¯MNŸ>àææVVVÖÜÜ|ìØ±ææfú–ö“ÝÖ­[Ÿþù‰nÅÓ—/Áu͸ˆ¹HûW‰ÆûŠçÁÁÁ;w««««‹ŒŒdþÍa™$‹;;;™ÐV[[;mÚ4+++ú©Nÿ ^§~ðÊïš:¢iExmÖ—WkÈÕ¶MùBiy=YÖ²-EXlÙ²¥£££ªªêÞ½{¿üòKLLÌŒ3LMMÝÝÝ7lØ@ˆŠŠŠŠŠJJJrrrâr¹nnn>>>,õ«L=×rÞ9ÖÔsmfík:=Éž©g×®]‹/vvv^°`Áõë×ujÚÃÙÏ®éµÓúÇn ¾¾D[ý~ʯCÿØwœiÁ‘ha¢¤§§WVVöõõíÞ½›¾´ò^zuJWWWŠ¢îÝ»§|{¾Á7œf8::z{{ÇÆÆvttÜ¿?>>>,,lT&ÇWUU•””ôöör8@ |ƒ…Á™={6}[k:Œ¶´´Ð7û£·¿óÎ; …¢¢¢B˘Ë~ ¦¶)_(-¯§¦–Œ…ÜÜ\“9sæˆD"GGÇÈÈÈÏ?ÿ¼¾¾ž)PQQÑÐÐðú믫ÈòéFO=¿pá£GnÞ¼ùÊ+¯¤¥¥Í;7--­¶¶6;;›ü6ï¼­­­  à“O>anT?¸dhhèýû÷åry}}=ŸÏ|Ƭ¬¬O?ý´¥¥…Ïçûûû···×ÔÔ|ùå—ï¿ÿ~MM ËéTTTT¬]»6**J×ö >œÆrvµ‡¬_¿¾®®®¬¬ìÑ£GÙÙÙô´~m®Ãðè]´e¤üšÂüa/‰Œ;¦p3Z˜DØWÜÃÃcpkY:¢é¶Ö*™^+÷åÕW_}õÕWÙdo›Ê…Òòz²Ü@GýË_þB?VûgfffffÆl´¶¶Þ³gÏž={:::222BCCçÍ›GÏ›¿{÷®Ê2I,è©ç ÷ôôܽ{÷¢E‹TÊ&''Ó3ËÛÚÚ–,Y¢¶*fê9³…žzÎçó•‹±ÏÚ×þtÌÔ)‡ÓÝÝÝßßolüÁ½=šg9ûàCÔNë×ò: Ï䈶 dܱ†D ú&<<œý k:jÚkff»cÇŽüqýúõb±øØ±c*+Œ* –OÀ      îîî”””Õ«W?xð`ð¼óüã/¾ø"EQÛ¶mûé§Ÿ˜½j§ž$ñŸnH#l®gg¦õϘ1c$çÕžþNH`‡¹ £ ? CÒÔÔôÞ{ïÉåòÎÎÎ_ýuÏž=}}}^^^FFF>>%%%j‹-X°àرcãÜ6½…h«§¶oßÞ××W__/“É}pɬ¬¬“'OÚÙÙûûû×ÔÔ|ÿý÷K–,Yµj•ƒƒƒX,>þ¼D"¹zõê²eËœœœÖ¬Y£RíÇgΜYYY9oÞ<ºÎuëÖq¹Üqë/À°aÔVO¥¤¤…B33³”””œœz{dd¤Ú\KÙ¼yó¼yóÌÌÌBCC[ZZvïÞÍårýüüœœœär9!$88ØÞÞž¢(°°°ââbæX¦Z ‹   Ï>ûŒÒÙÙùÅ_¼õÖ[cÞ[€Ñ€h«§"""®^½ÚÔÔTWWÂl‰Dšavq¹\¡PhddÄ'2uÉH³¥!æv@@"ua“a(çÿ¢Y× §§çñ:W?ŸWÐÞ½Ïuª)_ÛÒ>5€2ñ‚„@õçéð·ü¸:´bÅŠ—_~ùë_ÿzš¦÷ÜsÏ»ï¾{ÖÛ.Z´¨¡¡á…^øíok²jˆÕv¬ènçΛ¦é|ÐÕÕ•ãâ[n¹å§?ýéŸÿüçU«VUê€Å²ÚŽ3gÎ\·n][[[ccã”)S–-[väÈ‘s]ÜÞÞ~ï½÷~ûÛßnll¬ä!Š‘†ùð6ÙP¦;¯ž¼ºLwÎÓà¿úó“Ÿ$ÉgŸ}6}úôßýîwW]uUµÏº(¯pûïøß׊–GòýZ±¯Ê_á€sóƒv+ 8‹Í›7×××ó›ß¬öAFÁ jòäÉ™L¦««kà{,ÔiËP9^ƒ 2³‘¶DBÚ i¨;v\}õÕ ™LfΜ9kÖ¬9~üx’$K–,IÓ4MÓººº… ¾öÚký×777ÿþ÷¿øðO?ý4MÓ7Þx£g¨i¢çž{néÒ¥óæÍëîî>|øð–-[>¼k×®þ÷Þ{ï½§OŸÞ¿[[Û5×\óÏþ³º§„´ Ι3g:;;;;;ׯ_?kÖ¬L&3oÞ¼M›6-\¸°ÿ‚4MÇ?yòä»îºëرcï¼óNu iœÝ»w8p`ÕªUCÞ>øÇ˜õ{ê©§&L˜ðÅ/~±RGšïkœ¾¾¾$I¦OŸ~® yä‘Í›7;vlÊ”)O<ñÄ\PÁÓ„KÚ§±±1I’ƒöÿb¸[n¹åî»ïž4iÒ¤I“Þ8a„ӧOüö?ÿùOÿË|X€€xABpfÏžÝÜܼeË–!oÏf³ý¿Èd2MMMƒ»6I’ÖÖÖwß}wà·ï½÷^’$3fÌ(óa"mƒ3nܸ7nܸqíÚµ½½½§NzóÍ7o½õÖîîîuóÍ7?öØc¯¾úê‰'z{{ïºë®o|ãÓ¦M«Ø±ªNÚ†hùòåÛ·oïééY°`ACCÃM7ÝÔÒÒ2þüÒÞÞþóŸÿü?øÁÔ©S¯¸âŠ /¼°«««b×Úª­­í¥—^þö?…¡££££££Œg›Õ€HH["!mˆ„´ Ò€HH["!mˆ„´ Ò€HH["!mˆ„´ Ò€HH["!mˆÄøj€dÿé¨ÞÛòH¶œÇ¨UV[€ê“ª%aµ-¯4굀 o6ë7`:à\¬¶A¬Å“¶å5ªÖd ŒHä mB![Š$mË.Ï-Öd ŒHûä&m"^Š!m+aÄEÖd ŒHõŒHÚ„EÂLÚVHŽ]Öd ŒHïäCÚGÈÆO#«œl6ëÇPº«tåèÞ›}²|g‰„Õ DrÆ©ZrÒ¶¢†l´&[`D觃ó!m%ja,¬¥Uš×Ú i°îHî¨öþ§†>oUgáflR·@?œ'«-@5ÉÖ’¶AÓ¾ù“¶U&^K¥ôß×Ök")¯EÕ;*V[€ê“°%!m¥wGKÚAÈOÚ„Hé@Ú„BÎIÚGãFÚDÔCÚ„EÝLÚ i @$¤-‘¶DBÚ i @$¤-‘¶DBÚ i @$¤-‘¶DBÚ i @$¤-‘¶DBÚ‰ÐÓvÇŽW_}uCCC&“™3gΚ5kŽ?^Ú‡˜?þÓO?=ðÛË.»lË–-¥}ˆ|î9øšŽ4øš‚ŸB>åtÚ>÷ÜsK—.7o^ww÷áÇ·lÙrøðá]»vëúl6{úôé"ô‡?üáW¿úÕ"oRÀ=s\3Ú#•ê)”ãSP>á¦í™3g:;;;;;ׯ_?kÖ¬L&3oÞ¼M›6-\¸pÈ•_|ñüãE‹]|ñÅ;vìhjjúÓŸþÔÿ®žžžI“& \ö“ŸüäÊ+¯œ={öe—]ö·¿ý-I’Ûo¿ý­·ÞºýöÛ[[[ÛÛÛ“$yàþò—¿ |È/~ñ‹E‹Mœ8±­­íàÁƒ÷ßÿ\ÐØØøÐCõ_óñÇÿûß¿ð o¼ñÆ>úhøsrÏáÇ|Mî#=ôÐC³fͪ««kmm]¿~ýY?uƒ¯øá‡[[[Ï;ï¼iÓ¦Ýwß}9n’ûq:tà 7œþùÍÍÍ·ÝvÛ‰'r?€Ê 7mwïÞ}àÀU«V y{š¦Ã/Þ¶mÛ¶mÛöìÙ³dÉ’÷|ñÅŸ}öÙÝ»wßpà I’<ú裗\rÉ£>ºwïÞÇ|ø‡<öØc¿þõ¯ûúúêëë—,YrôèÑÞÞÞgžyæG?úQooo’$+W®üðÃwîܹÿþúúú›o¾yħ6üƒå>Rssó+¯¼òñÇ?û쳿üå/Ÿyæ™ô÷¿ÿ}íÚµÛ·oÿ׿þõöÛoë[ßÊq“Ü{Ýu×M˜0áý÷ßïééùë_ÿzçwæùt*&Ü´íëëK’dúôéù\ÜÑÑ1eÊ”/ûÞ÷¾wÞyç%I²|ùòžžž|î|Ûm·}éK_š4iÒÊ•+ûúú~ö³Ÿe2™Å‹Ïš5kçÎÿøÇ?^|ñÅßüæ7S§N8qâƒ>øÒK/ýûßÿ.ù1¬X±bÆŒiš^zé¥íííøÃr\<~üøÏ>ûlçÎG­¯¯ÿò—¿\ÀM’$Ù³gOww÷† êêêšššî»ï¾ÇüÌ™3Å?€ 7m“$9xð`>O›6-ŸË¦NÚÿ‹‰'~òÉ'Ÿ~úiþwÎd2MMMãÆøíÑ£G÷îÝ›¦éW¾ò•ÖÖÖÖÖÖ¹sçÖ××xæŽ1`Û¶m‹/nii¹è¢‹6mÚÔÿçòùÏþ‰'žøÕ¯~ÕÔÔ´xñâ?þñÜ$I’d2™þ"ý·=yòäÀK/Šy:%nÚΞ=»¹¹yøÿ¡ŸÍf‡_<øU uuu'OžìÿõY_ù:Ä@­ ¥¥%MÓ]»víý¯#GŽ\rÉ%ß0÷‘:´bÅŠuëÖíÛ·oß¾}gýl výõ׿þúë}ôÑUW]uíµ×f³Ù79×ã677?~| €÷îÝû¹Ï}n hnÚŽ7nãÆ7n\»vmooï©S§Þ|óÍ[o½µ»»;÷.X°àùçŸO’ääÉ“6lñšššöìÙSØ!¿ð…/,[¶ì»ßýî¡C‡’$éëëÛºuka·ÊçHGM’dîܹiš~ðÁ]]]¹ïóÎ;ï¼öÚk§Nš8qbccã„ rßä\;sæÌË/¿üÎ;ï6ÙPÚX=yu™îœ§Á¯E.ùç `,³Ú i @$¤-‘¶DBÚ i @$¤-‘¶DBÚ i @$¤-‘¶DBÚ i @$¤-‘¶DBÚ i @$¤-‘¶DBÚ i @$¤-‘¶DBÚ i @$¤-‘¶DBÚ i @$¤-‘¶DBÚ i @$¤-‘¶DBÚ i @$¤-‘¶DBÚ i @$¤-‘_íD.MÓQ½7›Í–ó81³Ú i[^£ZaM¶Å¶DBÚ–]ž[¬É HÒ€HHÛJq‘5ÙOÚ i[!9vY“-@IH["!m+ç¬ë¬É T¤-‘¶5d£5Ù”´ Ò¶Ò–Z“-@iI["1¾Ú‹ìµå`µ Ò€HH["!mˆ„´ Ò€HH["!mˆ„´ Ò€HH["!mˆ„´ Ò€HH["!mˆÄøj fu¥Õ>ÁhÎðl9Ï„4›­Ü“ÜpdCÅ«x«'¯®ö€ZrQ-}…Köù %BÚæo ¤­$Œ9ºJ¦†b±†ŽZ„Цm í 5tT z ê¬¶c‹‡«‰5´&Y •NÛšXCkâ@€T#@uYmÆñ eø&øñJª iø&øñ€ÀiG€*²ÚŒ²Ê(Øe4؃•GuÒ6Øe4؃5DAT‹Õ`LÜPv̪–¶î£ ¨Q: *¬¶ñ“ÚP!A­¤AsÔ²½IDAT¦Rª™¶A­¤Aˆ€š¨<«-@äD6TT [i Ǩ¸*§m [i Ç"£)*Ìj 3y UPõŴꨞê§mÕÓªˆ˜²¨¤ê§-e"¬¡jª¸›ŽáÉ6 $m«¸›šlrÓ—DÚPr’ª¬*ëéØžl“pÒ¶*ë©É¨ • P¡¤-%$¦!ÞPÇüd›•¶ÞPM¶@%iM€ (m(  ©Ø’j²M’$´´­Ø’j²*Oq”[Xi @‘4§{ªÉö¿‚KÛ ì©&[ Zt'@Y—¶L:C Êºªšl 1m˺ªšlêRŸåbÚPÑ A+Ó¶j²ýÿMÛ2m«&[  LM[FE.C (ùÂj²&Ü´-ùÂj²¡DÊ!Ü´ OBjF wV“íÙ¶%ÜYM¶@hô(@ɶŒH"C)ÉÚj²=‡ÐÓ¶$k«É“*(­ÐÓ€Ä1Ô¤"7W“í¹Õ@Ú¹¹šliS€ª´à¬d1Ô°‚—W“mNµ‘¶/¯&[ |  Tj#mBCÍ+`5ÙŽ¤fÒ¶€ýÕd Ô P5“¶ ‰Q­°&Û<ÔRÚŽj…5ÙµE­¯–Ò€DCdòÜbM¶ù©±´Ís‹5ÙµH³©ÆÒ`Œ“¿¡Y“mÞj/mG\dM¶@íR®Å¨½´³„/D+Ç.k²šLÛ»¬É¨uú `5™¶cä…Èu5ÙŽR­¦íY×Y“- P˜ZM[€1Eì˜0d£5ÙŽ^ §íÖd ÄDË †Ó`Œ¹0† ,µ&Û‚ÔvÚ,µ&[ >Š`´ÆWûä"pa̱×!Íf}úˆÁÿ`dvüwŬ/IEND®B`‚trusted-firmware-a-2.2/docs/resources/diagrams/draw.io/000077500000000000000000000000001355360272700232055ustar00rootroot00000000000000trusted-firmware-a-2.2/docs/resources/diagrams/draw.io/ehf.svg000066400000000000000000000661441355360272700245030ustar00rootroot00000000000000
Interrupt Management Framework
Interrupt Management Framework
Interrupt
Type
[Not supported by viewer]
Interrupt
Interrupt
NS
NS
S-EL1
S-EL1
EL3
EL3
SPD handlers
SPD handlers
Exception Handling Framework
Exception Handling Framework
GIC PMR
GIC PMR
RAS
RAS
SPM
[Not supported by viewer]
SDEI Critical
SDEI Critical
SDEI Normal
SDEI Normal
NS priorities
NS priorities
0xFF
0xFF
0x0
[Not supported by viewer]
Interrupt Priority
[Not supported by viewer]
EHF APIs
EHF APIs
Non-interrupt exceptions use EHF APIs to program GIC PMR to arbitrate priority levels
Non-interrupt exceptions use EHF APIs to program GIC PMR to arbitrate priority levels
Decreasing Priority
Decreasing Priority
Secure Priority levels
Secure Priority levels
trusted-firmware-a-2.2/docs/resources/diagrams/draw.io/ehf.xml000066400000000000000000000062341355360272700244760ustar00rootroot000000000000007Vxbc9o4FP41PMaj++UxF2g703Yyzc5s++iCAt4azAiTkP31K2EbLMuAAzYhmaUzrX0k+XLu59Nxe/h2uvqkw/nkWzJScQ+B0aqH73oIIcCY+cdSXjIKhEBklLGORjltS3iI/lU5EeTUZTRSC2dimiRxGs1d4jCZzdQwdWih1smzO+0xid27zsOx8ggPwzD2qX9Ho3RSvAaT24HPKhpP8lsLxLOB3+Hwz1gny1l+vx7Cj+tfNjwNi2vlL7qYhKPkuUTC/R6+1UmSZkfT1a2KLXMLtmXrBjtGN8+t1SxtskDgbMVTGC9V8cjrB0tfCmasX0fZBaCHb54nUaoe5uHQjj4b+RvaJJ3G5gyaw0Wqkz8bppn3uXmM4vg2iRNtzmfJTG0mFUTDI7D+mRH/+fNXelI6VasSKX+fTyqZqlS/mCkb9ctWFLoH8vPnkiBBQZyUhEgL7Qtz7Rlvrr3loDnImVjPUOTx88ssVVov56khfwtnRnOm9uUQGOhwqp4T/cfj+AEeh4t5pvSP0crK5QDTDX/vSB8OaDv8hQQEABEuMCScUMmJw2/Eavnts3tDPIXdwue3x001MradnyY6nSTjZBbG/S31xtXwEqf/UWn6kruncJkmhrS9wtckme/UesNf/fIzv+L65Jc9CfYKYZEs9TB/6pyraajHqpiVu1X7QnslpVUcptGT68zq2JwvvU+itUbmEsZWwpxgIglBmEvoGpSoyC17xPwaW9Fdax2+lKbN7YTF3rtW7kMrmpBdcasXmzdupCqkRlNYbFh7M4qezOHYHpaNtRj+rYvRgmJuVVpTc5m/XuZq1+Sqd50k09/LxametWUjR9KoAIOScsEEIxI3sXHXLeCOTB7CGkFegsk3MmvkmzVp26obc9I3iZL+V1k6G13bzMqcDeNwsYiGLt/2ObxX8KrMGNSQMbnOGv0DEFWCv6entC7y57QT/WbFgeFqPpHpgecovetAigKKuBAQECAkct9JEh7QRh54e+FiYvL4uFDOnCMcaRGGSmrz/cH3a+1ljda3XffF4LYd30ZseJMSYkSFFFhIV2VqfBunATDhSHDMAJVE7Nagk8xRenx9uOp/hR+GtSiP6OdnbVETvM+YUZcKyrcKGsgPv/2vuGMdHQwG6PYsOkpqQsaZdLRVldwXjs+vrsW0liuXI0oMp7BxAyvB7RYcyMdWHu7vrOaEs1Gs9OI0oxmFi8l6biMLylGojrEXymBgC0ZhchgGMT4cWhuVDZzuVoTG5kXfcwgoci7HqPBFGBU1pSLEDAOOIQSbGF9fxZ+2+nST9FPX96QE8mKVgAEUMCwJoAgQwlzEqCiEdunAaxafrgJ+0dtfDdU8jZKZIX+2vjmajXv78NnLTW72O2CyLR1f64IhqhadRzlhfhH21xJW4eA6dfhF68jOcQ7aZD0QYQkpxxxJwfZlPa9cTQEOeMs4rehURxZGQqmPZK3Jgyg+kyvH+Bzq0tQssZ+pfvpiVoH7bz86dn53tC/uyNvmpfjIvJTCALXhFH2F/3F9IqC2K8S8Ql2bc5cTGGQbRRl/3Q1BWlNRN+JuGzW1D6nV7NY83H9rulnzTmVAjtXwFmSAfezt4a7/xVBudZRGwzD+OGx+Q1XHPi6Xs/l7oqcfiMlHe+s2mIw8JtutDzDXUWKVWZ2I6VRBG2r/1LLZC5ds/TuHAI6FcVAbu7/4XVfwea7tpH2Ff3zjKoGDii9rGQ3F3ab1b1j61Qm1yOm6btXhmAaQG2khwYkg1MVOKG62UXyqrtC2daUJVhvH0XyhDvvUBt1yLbhMJnnAGJJEQkmocYSuMdFNmex4zQ2o4mAtrUAtpC717aiM3rR1bmto0JJNltpO8rsYSukex8I1NZtUhdadv/6mfu52ab5RraL0ZzHPHHfjNVvf1d7hvxAyxioABAICJonb3Ua4GYUSEJ7/7V6+aRcPpySwli8QRVAKgFyXSfi+m7TlqJG5CwdYEIgFF7QC/bH9uPyB1S3vzVAfmAerwcAzBOOQ0zqQqdJjXtN2HsbReGZOh8p2uRmCde+2AL3OB6bRaBTvCimueXUSRAQmAQfb7TBXLyHFXgShJu120NmaeNIGRkXrIrIHpIAVaAikfGghgj1CpAS9nRDraqe9LdD3WV378q6kqpM0XO/m4bsr2ZmYGYMBEoAxCQmRwkOCUM1O27kEzZrkEwf6eZ32kiL6X9kqv5wCWAIp8oN7pSPzrFZ+rzWvgxH/PB28QuAAccYhYwwgyt1yihBmdxGwsWlCBDo2MRAMBMjkHZRxigmolApYNKvZjoiwrMHHXkepBTglKbwY0dN1/7iAQjCJqwWckZmps00ilMmfdiF60rBcP0b0dV+//C/6yxF9h1bfBDE9NhgAVpI/tBDwB4oFJDB1j5TSomySu51phOOgiANUsIKn7WpFU/zuCK3g3UIODbssDqE7TZGLA72wO1WtDEiwpuBDLpwr1I6eYWa8jwCUUISkyTGq2+cNdaCjj32YDyP2P5uiHFzff2l3s2swuKG8s3SdQMNliSRmAqDqN8uG80f2xbWRrfPW07ICx1t7aOKCeZzKgvD+fTQ1UoWQcyglBQTjqvskVSS9qV9eNwyVftS7sPBHO/DSPuzyPZldRaUSXRXNq8YawXKhzN9lAwXGadr96WSsw6k5KvV1ZUOh/h2lOkxVb7ONbeUXqycV+wZ+GRV+N10HPKAlD1HpEat3EUiYRRxaPSRCEsY7Kuj5sTlc3TZNNUyX4u02+p4SVS/EOUgqA4QpwVICIFglgaOs0o3Q1DXsvyysXrZFZ+DvoN+poVbhIutX34J1F2m054HljEACyZDddMk+oHakg+sb4C0uhznkhCMIhWQdGXHN971quNTKkd1le94zCdE4290QukmRN32355eiaIKkXFofywat2ezl/sqX7pTWwbalbj7prNlGhQEt/SqZOzFpfXm4kfM9td8F79v69FdDHEi4szWEM6+LfEcoOhwzzOn2/w7Lpm//hzbc/w8=trusted-firmware-a-2.2/docs/resources/diagrams/draw.io/ras.svg000066400000000000000000000541771355360272700245310ustar00rootroot00000000000000

<div><br></div>
plat_ea_handler()
plat_ea_handler()
ras_ea_handler()
ras_ea_handler()
ras_interrupt_handler()
ras_interrupt_handler()
Exception Handling Framework
Exception Handling Framework
RAS
priority level handler
[Not supported by viewer]
RAS error records
RAS error records
RAS interrupts array
RAS interrupts array
RAS framework
RAS framework
Iterate and probe
<i>Iterate and probe</i>
Error handler
Error handler
Bisect and lookup
<i>Bisect and lookup</i>
Error handler
Error handler
SER helpers
SER helpers
External Abort
External Abort
Interrupt
[Not supported by viewer]
Interrupt Priority
Interrupt Priority
EHF APIs
EHF APIs
trusted-firmware-a-2.2/docs/resources/diagrams/draw.io/ras.xml000066400000000000000000000044441355360272700245220ustar00rootroot000000000000005VtLc6M4EP41rto9rAs9eB2TjD0zVbtVqclhd05TipFtNhhRQk7i/fUrQGBAECsJYGcml0Ajgfi6++tWN56hm93zZ06S7V8soNEMWsHzDH2aQQgtx5H/MsmhkABgeYVkw8NAyY6Cu/A/qoSWku7DgKaNgYKxSIRJU7hicUxXoiEjnLOn5rA1i5pPTciGaoK7FYl06d9hILblazj+8cIXGm626tEedIsL92T1sOFsH6vnzSBa53/F5R0p76VeNN2SgD3VRGgxQzecMVEc7Z5vaJSBW8JWzFv2XK3WzWksjCaoGY8k2tNyyfnCxKEEI38dmk2wZuj6aRsKepeQVXb1SepfyrZiF8kzIA9TwdlDBZp8n+t1GEU3LGJcnscsltOuA5Ju8xtmM/Qll2uiXNDnmki9wmfKdlTwgxyirmKs4CztrYT36ag8WI7Z1vSGHCUkymA21b2PoMkDhVsPhug0hjSQ9qVOGRdbtmExiRZH6XUT5Rqi/1IhDspFyF4wKTre4U/Gkl7ke5FN2Z6v1MrUWgXhG1qiUoiyNb+IPqcREeFj02e6kFRTb1koF1JpDcGW1ryWMoo1qVktfVTLMFIRxh0qciKR2WL4KA83IserEN3ztkTevzFuOO2m8iXFVUZZUrCKSJqGq1K8DKNyGI2DcpDyISlR163JjGRsi2i78XgGATV7SOTKf1DyY0viIKL8t9/H5EEZFj7hBVjaw/AfaHuSo/NfNabOf3gA+kMGIWQoB1G2X/eOCawf6RRZDhvOI4zh1tDmJP2ohos9A8N1RjJcaH/kuI07jHJwmjaFUg+vmVFKmqac7xMxmW0ulwvb98exTeT7c3s668R6iDpD3vF2Iz6VsRgZuT1N3oH8uef6wIPAdgCSim4oHgNnXq5k+ExEJ6HF84omImSxFH/JHCeMN/JwycmOPjH+MJUPFSNrV6z8b6CUBTQx97yms3UFAsuaWxC7HgLYxbbvIt3zAIBzu1/9ps7nGPheFIVJSk8DTtKkKFGsw+dMSa8hfHM8oY3mwIE+9oGPbey6TgtPt7LhRlJYotUAcRAM3en4651poUSdH/5Rk/KT79nJ3DagsTdGb1uP3s65gje41DzoJb0YoezrKONRIoo0EXKoDUiywJD2Bxzc2rBhG9Y1dnp8s6wnD4oVvDUI+R0WoJVHvl3d9dVDtLEJDxkPRYZJRB/z8rDKAd9cZHlVlHs5ptWNbNQoJ2829yGq4hxuadHryigNwpw9RNnSugi3f8nJX0GudR/3p8kaoY/mjpur0cUetkHLpUE7ivYkja8lD+i0NyatGv+J8TI96CeP009rF+UKwh2kKNdFQ8NZZKPrkJ3cEiE3qHEugRZ8V6wy3E8ZhS3g6TYNBjdq44LTuDxxAfW9LrzPV+ArV1PDO4+8FpUg8fyJK8aD9H0BctJSiguaHFIVSCYp83X1fi4rvVU7jTL2GdttR35bvtzYwc/1W0GlrarhKiRADwuFQ1T1xXSWt/3J4QP7BOroWY/nEzqnF5Cue4tM8rVEF1yt1n5Ht59E4SYLsiua6UsKMpDCFYmu1IVdGARRXyWlqcEBgG/XdX1D3OEAuCOTwtJAGc4FBNau5BwNXtM1NvquRmWx9QzLXedXaaFE0OxJcZC9IGf3tLZBDYfZnk7aZGszzaRNNtRR31Z5TFUQGA9JZfYDgOibtNhHA1FPCX9q2oAdtOGejTbgadq4DtOsxl+yRsTYwz45A22MmqBM2/9Eev/gpyCOqWEcd/czLluYfSfa+FSngzrKDfUZSic6ddwtvuVajhLKx97Cj/mlzqRbeGRQGHxze6CyWvPOwNDfL7/cJkCup0M9UZMA6xvFXwl5eEbkuz4MycrVJBt1dS8pVNPEZezRh9ZRqwEBbJ15ur7tH2K/jrv261qz82tZhzLsZP6carJbX5z4eDo16bliTSfWbdWM/iUUkX3OZjd10RGsR9PFhE28KfaqrazxLb+nsV9U1x/WHMCmvkqGe2eN3sa4ZQie39JwT/NWu5UD27eyDQv+r+1uA7c70exb2Ynxfd3tcjlsvU7pu7/h1LOkxZdlFqZvv+pJ/sWyjkYxHcbea8bAhU09uKNxjjw9/kKyUNfxd6ho8T8=trusted-firmware-a-2.2/docs/resources/diagrams/fwu_flow.png000066400000000000000000005064711355360272700242150ustar00rootroot00000000000000‰PNG  IHDRÕŒïÆ„’sRGB®ÎégAMA± üa pHYsÂÂnÐu>ÿ¥IDATx^ìýíónG]çòœço8Ê£óäÔïÑyÀLM¥N•L•äF…T ”Â1Þí0Í0PöoF#ð Æè@Ýb±£¹ w‘ŒÀ„@@¹ [À¨39oò‘¶é^«oÖµÖuu÷z]•J}÷uõêõù¼>½z­~¯Ow?å >€ @€ @€¶!ð”mª¥V@€ @€ @O ?Ò @€ @€ ­ ?nE–z!@€ @€ ôGÚ @€ @€ °ôÇ­ÈR/ @€ @€ €þH€ @€ @€¶"€þ¸Yê… @€ @€Ði€ @€ @€ÀVз"K½€ @€ @€ú#m€ @€ @ØŠúãVd©€ @€ @@¤ @€ @€ @[@ÜŠ,õB€ @€ @è´@€ @€ @`+è[‘¥^@€ @€ @ý‘6@€ @€ lEýq+²Ô @€ @€  ?Ò @`/xàGyd/ÞâgóÔ õy衇š·ô Å… n¹å–;ï¼&Ç Î9Æ" «Æº”±Ü›v èÊš\OVÜbÚmIX¶'è{Š6¾BØ+ ÌžúÔ§>å)OÑÿŸùÌgî~7D@íP Ò>;—Û^üâÛåéžþô§7-L@Û¤­¸Ë‡{\Û±Ç:×oë–½âÓrt°moÐ÷qüÝ5½ŸTj‰Lõÿ.ÞUî:Z8¿*l†®±*Z*[H@íÐé{NYò9äž±,lU¶WÜãöùSúÝ…þÈ-æ”M„sC "€þH£€@7$ê&ZþyÛÛÞøæßƒ‘`º üq }Îsž£JûTådIÑV£²L¾`læ·#E9Ý“(‚š [ÕŽÛNO¶,CŸðäþ¨(*-Å×]çc_Ž¡?^¼xÑù¥?Ôrj›oöîo¯Ë/XÍpÚ§Œ¬µ*(\Šì!ê&û´£3ÒM9ÈÜãio»:VÝEââ²Î$AL"j_ÜÃ-fW­g €þ8@qa/âéiAªHðO=@hüŸ+±— ¶ççbMÄü4غ›MSÓ}ˆ~ÕP¤\Ôh¯9oe‘ßœ² 礴Å×ÚV^¢^ÿ®ä sjuñ-ì®pÎ8û¦öš*¿ûë\%Jâd…%ÎáðXeUDÊR|ÅÉaZËâÇ=n1º]¨+¥ðž¥ËJú~Nûúãn1»jÀ8;ôÇ‚ˆ {!P>±g ôǽ´ŒUý\¬‰ ?úq0õÄvÒX5>+TV«©çiЋ*«‡£–ád*ßâk­Ê÷– +ÅÆ„|i± :%†Ç÷îÚÈÚ»¶þÉ ÏŠðãèK‡¤¯VévÒ«è«\°­U¢‹Ëž% ³ö—ëvY¥»…cêW¯^µ ʲª¨ƒ°‡[L6â€@kÐ[‹ö@`–€?`ÈÎKR8ÃÂ-À¬ªœEœF%°XAô›ÄbŒGhWA¤llã>6‰2–'ÖüÁÁø«‡#г2ó¯'ãî„G½%³ÿœRVu!dïþñ›æL†pV-[Z†¯#»¿×Òem|‰Ù”ö8“«ÁÕ?ªb½¸0úãbt-¸ºÀç÷ºsWVpY%$ÈÕÍKÄ·¼0ßy·˜–[/¶A`’ú# Ýðµ?Ökt±øØnHaè+5è=ê‰q…¯)ØDìšÕ‰]ܪçì^¥µ¯nÕ‰)ןޟ´[8ž¬?ɉðÇçþM¼JÐ/¹ûÇiM‰SøVùWú2ØÕf*áêúc¢m(5;žú½8‘óÄmå°Ó£?ƯѣWøüŽbîJÑeˆûs=Ãêæ­«?îáÓhÃÅ,Ì@¤u@ %#nœÁÐV ,=®¢ÈlGåÈc³Å·#àj.G¤5-Ë:‚GÙS¬ŽUZûêVe9´V`xþì?]Mþ•"í«ðî/ÕÀO\JœÂW l̾œaÛÚS4J¶ÃO¡ï­]kÙSÞ±¯uFê9Õ¾ýQ~i²s%=ù°ºyëêkuGG4§€À~ ?î'ÖxÚ=ÂH÷~âÀI ,~\;p»µÓG›-Ƹ5Õ_Ž"Xº®ßU WÇ*­}u«ŽÐxÖ=Åð|ÁQ+¢è³l½Ëò»¿Ÿï££æâ¨~ j/óDU‡L¶ðM*ÉÕ¹ ²*Ãt݆}’ÚÊ;ö“˜ÇI—X]à+Ôem°®ë䪋«›‡þ¸¬p:"€þØQ°0uïÊG {'…ÿX¬¬¢È`xæÐ#ÍcÜŽ€«¹ …ß픨G°Á)VÇ*­}u«9í!ÈçþU®ô•ßý¥”HœaþQU+- žjNkÅ´V´7+>¨½Í®êØO{ásör« |åú£ŒÌ^P«›‡þXÞ6( N  ?v8ÌÞ#òÈ· ¬ž?âÝiì(Û].( êQ^è£ÁIVઠގÚÂLv”87ÜR…n× •Ô¹ÒÛÛ9#K·±ÆœË—æp¹Â †:»|q@Ì`-ŽS’m±o`‰¼Ð¹‚³‹^ÉÙK.›Å£ÇBEf’°òì|§dC¢µÌy·"Õéf UÍyA”ýëË¿ZeF°ÇK¶)ÚµDY&­2º Å@FÊT¸ì‰ã;ICm>-߬ŽØ¤ÂÖž¾â\k‡£P/—¶Êuƒ%{Œº†­Ö´0.é ocqG¤ù†jTv·Rhô÷—›¯Í¹ÕÓüíhÊ•¾ò»°3Ò\bBÕO去tKwÔ‚V=Ù ô<ª'Øí§ä¶¸à–ê?*d;só®äéÂJ.îü«:v;פï"ŸxD ‚µî }ò)~<ðïì=vëñ¯â’6T²8ª§HÂ… µø—jð Qò_\Uú£ŸO=)è—늣Àúú®§MßÊ×¾1ú; ánýÞb\/ÜþÊ[uù°k²× Z¾ÝËß“• 1(@¤@ å#9—üÇŽ¹w74ò‡–X<…øÕÚ³¸þ5y¬ Û\ø¹Ù±“ §oUƒ=Ÿp<¨V¶Š·Ý42éÑȼþ¸=^hß7Cg_𨴖ţÇEÆ/ã‚ë¶e‘fyºAÔ\{pùŽÍ‰ò\KŽýJ¬Ë¦«Éo‡Á±ÎCº­Bv ߘ¬ ¥†)8“W‡ëÊ[iš†*Ô¹æ¬Z%sœKZ{6FU×Ú!( sâ∧{³eIsþý"ÑNÙI€«´1?|Ö~âÙ»²mÙðÞ™íw׎d0»Pé+¿û¶ÌX5X° ¿>ÃäÃ1ç_;ì>«ô"›ŠÅ²[ªÏªPD.‰àUÇ®N8í»í9–nŸ«ßÐã¤9&*<ûÅk€ºî¥|­ÕCànLs÷ÄÄÝ<}õ»ÍÚP•þ˜-\¢?ZcK;¥_'ß9kÚ–Ü2ú½Å¸Gwû+oÕUîøÞš8‘=h-hiÙG ì–úãnCãý(y~M{U¥?šÈ8)ë$ôG=ÆçO îpž“ì¹<9€)_Å߯n@ë4¬Ä´µì“ºlbÐî‚XŽ×ÌËRuø”P¥‰øí­dÜ WL…<焃¸Éù¹H“¯ñUÕQN7fߤ¹!k¡sövjåÃÔ`ýÇ´•~~ "’Ýf·¤m¸:'yŽÏ’Öž Gáµv8 ?Žê‚šB°àW:L~s-ïv®ÕÆüðÉžIññpýqndîÇ=«éÇ¢pZÔóñ&ny±m~èÓ÷J×°ý×{®¶êª«£J.\ó[jÀ*+"—°=¼ó/ïØ ¯Á¬î°ú =x@Ê2q­.È{­zç7ù ý ­ä½”u,ÙÛФ6Z®?v ¾ÁYIÑ/ìƒ]–ÿXÞØÄ<¾”îz­ÂC&{¹ÓÞbý±¼Ug{³ôCc‰È{àcg¶Ã§À® ?î*Ü8Û7ãëÁs¼ 0ú£¿Ta›"¿ùT±`ȧ:U2~QÝÊz 7ñÜ&×#ºÄÀ)ØyÓ.:ÔÍ·Rmäxw`8Ò$KZ{6%×Ú*(‚7I òAÒh:èsúZÚqàe/“¸]±ùá úOß¶*Ù+ðÚÑ7?o´pPW~÷÷Uáþ×Îrÿ,%‚òd(iÕÙK#h±UðÉËÂIqðð[ªÏ*«esKWéü ;ö@‘#öôeŸøLæ$ïÕoèþ’ÏÄnëñ£ŽÅ×Çëîñ'ݤWA@Ònˆ“·ÂØ0·DúYBufµïøZ«Ò},“O¶Ù»€ï‚‹Ž:s}lt<ÜëÁÌ‚òßLOV®›í÷ãë…­ZÎ=Þܰkîv`„ý·¹ =yÚ¢Fö«þ_ÒoS%ÐK(QM(Ì™[•ÿè?øOÿº!êÉäËFÝ´4rv–è!)x¼ó4½,O>5ú4æÒ²âwz‰ñ˜o^¼À¥ÑÐ}}NÚ ^TΙ Q;h¢q@ÍŒ ³@Åæ.“`L2ý8+0¡,nÕs}iIkÏÞ6J¬Z …ßÀJ^¸ksn|[’P¼ «dÝ66×ù÷ý]¸´_¶# ê©J+¶Ê ïþÁµ$ßU63iN`-iÕÙ†t¡Uú£\5ã¸û]å–šÍ ó}L?®¬Õù—t숯`M6’à¾9÷D±ú =~@Šï&¾|oÏîa5úƒ;fâ¹h‹8«tÞàîYn˜í¯%UéY½P„9ý7x0HÜÇK†0AßRÞµp‹‰Eó`€ ï‚ÆH‡þý:v™X÷½þ]c®§µ7%ý6e PBý±„e ÐÂHÂÖ’›wüü—̓ˆ%žÉUð’ÍÎæž³Iþ°|n’`¼\â.ý¥G¢lR¡oÒÜ]|Þò¥¦|h٨͵“òǵ †E&Zðuj¿Î ý!68ÆÏ1eè¹V·V”ƒÁsV I´´™S1·`˜j/ºýOœn™nNê‘ðW?˱yA¼Ê“VW÷âV=w™”´öìm#kÕŠ(‚e'm‹³‰u…Îñ÷õ—lþ×á½Íºm,îˆÔx²×i6 ®€Or²·ñCŸ]‹À× &5”–HÕÎÂÉû]ù<}¿‹ †µÙV]ˆÑ¯§J pÅs•[jù:žéé+vþ%ú£O5ýž2è|&¯ñuoèAàL[œ¼*ãG»¹žª$v£¤q¼µ¯ /¢Ébåúc0ŸiR½Êê– —6¸Ð¤’!Lp¢ò[L¬?N¢ $xki“î m§“9Ö¸iœ»è; 4nŽ@ xÍûä\™ÙÏäÏ’›w •<÷úcâ-Y0@J<þf7LðŸÞæê™L6œ|Îók[ü–¯d7†xýÇ»ô\ß‹DŠSúb(\;\L‚)rñ8¤<%xÖOŸ7ͧ$ʵú£e›_:•¦¤§‹.S#þ#Î݈O‘M‘ð 2Mâ&}÷àפóÌs·êBý1Ýë×Én'kÕº(ü0MjÜ“£š¹ž¤¼_J´É,X/SÍÊÙ6_Ù×K%W–+ã0imöœÎ ŸøN—Õ4çTÿè‹üë.h!å1-¿•<‡øµù@âcË›nú–ZØï¥Ó‹Vìü³úc „fÓ{ýÆ0yÓ ®£oèþ˜x%,–’xMÔ9yƒØ(‰÷ëÖV ÛOVà«êšT¸Pì žšJnµ–¸ò%¯ÇË û„òî¨0fóF·˜@Lè¶AŸ_8ìš,¶z[Ü 8p?Ð÷k<ížÀ¤š6'L¾ÈªÕ e¿Ú´ì•½gW=ޤGþ?˜ ú²¯jK$‰I´o­¤xø“DùãZÀ¡$#,(“]º¨pY"I¬’9(—³c<ÃR…±JR<<ï¬J”mò%qQ &%ý¬ïoPó‚©©%"]U8J\¨b8—›¶ju~Ë™‡8¹A†¥{’ Q®„Ød™Â¸¬ÛÆ‚«XÑɪuµf®ò”+;uùÝ?±|„ïÅ\|ÓÉz®†Ä³0¦Y¤~=…Zƒ«3qãXñ–Z¨ã¤ÊöÞTžøi$ƒÆ߯׽¡í<ýJÀç–¾~³S6 ª›ÛaxKæ½úL&Ÿê³×Q\ Ûnƒ%5-uîiíðgΠ‹K¸Y2„ ü-쎹Ŕwz~ÉôP"û蛽[-hc4ôGZº!P>±Ç…ôcÇܽ+ʾ·S”?dŸKH®ŒŽõwÓµ''ç×ä­z•G¨ïjñf•Ó Ê‡?I>®Å­«V,‘_ÓùUÆ’è”ô…õ”c¬•rÏÕ­ÕÎì%ÇÜ«¿‰f“7pB1\0 ÞjL±<%m@ejN¶ö´U«£ÈJK}ÜË­8õØÒ"ÞÆeÝ6„o­Q½k9þ«¯D/W˜i ΩÊUBjâ–—x=à|L^Óì…V>«Jè+ÞRK¦«§—I]·óÏÞ›J";÷D1™c˜=cP[6¡²üI¬¼™¥PHaÞe9“ì5?±«r‘ô?ú&k蟓ª‚®éÀŽ´ÄÍò±Æä0!±ÂF#·˜µZµß²ipU¦EóÂ6F1¤  ?ÒB Ð ÿ™ÀŸI! äæ]ò +©ÖÉÞýš³–¤gÂú¹<¾ä?$ùÃÅÅÓ– ½Ë:°-±kËÇ­q [è‰õ%§«z+ì Ûp9ÆÂ yµåc¿‚ôÏø#ñK}H0ÉŠh…¹Ã‰°fsôÒîÌ Êñ Øûžôg2í:mÕ(ü€¯—ünPíÁ×Mb…ѱ¾¦š[—ô«¦ÉšÓ9>‡_D‰vR˜¡\¥/û‹õ_”,|¸e×µHßñ cš½Ð6ÒkÍK—Ï™žZQÛÓå³µùAÏN>ˆŸ(â—ÖÙ3&ž'ï&åHåqL7×Z $›‡h…Ë™d¯)+àŸ7ý>æ'd»Í+q³|¬áP¶“Fn1…ÖAL§‡g[x°Ò‘Qø WØÞ(˜ú#­ÝðG é‚9—JnÞ%‰gÊo„~ÍYKÒ/®Ýáf’ï{0¯Çÿ©ä¾«ñ¶ÔŒýG‡¹´—¬SÛ*Ñ9P‹–5’ò ÀÔA0û$Ô™¢×VU[þ(Ë‹rŒñnž9-ë_·ûœkféN­E¼m}|/è—‹ßeÇó±k%A”‡£ð~PÒÚ³U(m,@‘˜ñçºA§áºÈÆÍ¬¶›CQ—uÛ˜Œ)¿²AŒ ”«<¾_é[O‚@x*-œ»49(‹ÎZQÖIË1ãÁ’?«2%zƒªËPõ¤7"_Ð/¡?–(5I±sýªûÞM÷%~?;Ïïu³:Wú®Tx™¬ÛÆtDÙ{«+è€Ù«ØÏúI¼ý*!àÃÌöÿéÛk"OÍ—&'£_Ó,Òeí_Õ¦s}’Ùèøæú@‚ÌÓì¾vëvþè“*ý€zÌæ>Ô< g¯¦¹'öÄCoa%æÅéu‰çgôGƒ“–€·véõÉœF|à‹ÆÂ¶D±ý@ÜO¬ñ´{%#´“%w¬’‡‰ÄSԑ󃩗ΰ8—G?ùÏ@.OÁhM®Ñ+¦îé@=øŸDn‘3¬ïáA¯m÷þ¨/$®v ý1±cF mßÈÑ-Hô[åÅúãგp— êñÛap/h¢%Yxzþ.Lz*Ù@`-MÄa)iíÙX¤­Z ¿” ðå§*úšëýÚ|ñ¥¶Kp(ŒËºmlSýÑ7µ69Ñß–ðƒ¨Sn<7Ú÷ÏèÚII+ŒiÕÕQØXå»–•'y%¬MhµÙ+¥Pʲ²[èþSS<¯¿öVR¾VB„ŠÉQjނēó©òäÈ6ò@|ÔÕÑÏúg¶Ñ+ »£’6¨9ýZ{i¬Ûªk}ýòêäÅ9¾‘ÞT û1Šíú㢌ƒXpƒL<îŒ1ÿZúO-.Ä}éèüÇç~ÉF þó“jž{Ø-yà(yÆò£æýÀT£ÂËÀ\+YGÌU[2!º‘ogblP+eO½b”åBáS¯JÖ ©…qLË¢ˆ-Ô ›h"¬ š_IK(G!Þ’“f«*× ¯Ä«üëÔ%5¸”Æ`Ø÷WkíÖU5ÜZÐ ®;o4J+à_˵âcz9…»y döNä÷‡näé§¾Î=B¬u­-Ðß- >«XÒ]Ж²Ñ÷ëœ|µ9—=´nç¿…þ˜ŽBí­$+öe›¥‹Ey3K‹VÇ Aâ|Tý1è«Ü–„þ8úãá1 tí¥QuCTárË,±Û™••¿Îv˜€ú#mÝ($ü)¹c•<$ž¢Žœÿ(Küa’ 6Ü;vùÌhsÞ¹§½ G,%·ù’ÓùxÁ7ëìæ§s5û˜n• òëO¬V"µøUeO½b”uÞòÑQ­#‹#ëÌ¢ˆO‘Ð4ÑÄŒÅì5¶­Dø.G!ÞU¢–¶j#“)lÎ’àʧZÏMÊ.ä+ŒËºmlñà0ëc°l¢"˜ýø„ã–;cáÝ?ÈÅ+™Ð(ÎЬ‘§Éj%÷¯Â˜fa.z0,Ÿä¹¬Ú´µ“I‚Ù‰êA;œ DTyÇ^ØŠü3¦o‹µ·’ì‚§% ÌÌ+oféçÞUzòòøl {ør&…M¥ð¼…µ¥Íó#ž”¸Y2„éú³V«®zôMÚ7‰È‹‚bYèYD€@+<;¦—ܼKTk‡T=­Z¯÷?—Ëã?³Ú³¾oÏ\†Qùãi‰w…N9Â~ȲKz­ÒRËG°Áéüö9÷–»ÑÜàçÀLÃø)jÝ(WŽTx2}f•hNVR…À ¸“yRiãcÚì©qÍ 5Ó.¬/Ä^Þ`¦­ÚÅdãt ‚ë÷®ÖC:›—KÊ/“uÛXí¨°IÂnz+³¹^nî6T~÷O¼*˜¢¹ñ¡³<˜¹('\Æ¥­éåŽÖÅÏ£ApƒFÈds×ÑdXã¦â?쪅dW ÊϽü±¾ðôÇPCõ.‚ GÜÃÌõ®«¼)ŒËºm¬öNTØ$Jòp'« V~˜,S~÷/©M§(¹Ø¯ |› cš¥Z«?üdcÞî–hX>º´Ò·bçŸ})l.4~ùÉë}Ýza³4óÊ›Yöõ˜!ð›}¡Xr©f¯¦ç-¬s ý±‘[ÌŠ­zñó^÷Õ[`aÓ¢ØÀÐ.®F |2çyö9¬êùÏ¥¤Z+œ}>ö-/¿ç;*¸ãe\ü÷ùz¶.Éå)Jæ)”;åP¬øp\xIë…g5 @(L̲ †+i 2Ë3Øç4¡ û×Îä:këF9¥§©pðì+c #µ¬XÕeŒê'G¡>Þô ÿõÀÜrBþå<'"8dzúâÁj6%TËL¢¶ì`c ²Çïeƒ»Þ'cçlP,ü†šíJ0f ¸JÖmcU—@‰#Á%_§dߘò»PÛ\*zá(è9mQËô5^Ó4Ø*ýQéí©…»É¾`˶ÿ]¦þ.YWÚê\±ó϶ê`N}Z-i–ëÞЫž?Ë›Yöõ˜!ðR­þ˜Ý9ÛJ­@áy k+×ë**ã ,/o'-ÜbʭͶj¾l· táÍ"[ à ?Ò Ð òÈœK%w¬wš’jͤªa¹%Á â6FšËÂó«u[¤!>ùIñBõþsCb„Vî” b îeÇK*¯ÁÏ!™’Aâ•©„RŽ&Û•ýö¸¤áhvmÌc¯ãqé\tVŒ²œ­]FÓo?²$-AÊMÕ_2n2då—¡‚Œê'‡A˜k-Áe2w…ã^‘™T–Õ ƒF’ÞÔ†#{W8Žþ¸ sÍïˆÜß“-*œ»ÞõÆá]6ÜJôH…m¬üȶ+ÌT­…ã_e“=|ÕÝß§:—¦Zx' .1‹~Z]-išm‰þ(Îñ& µ™õ«ÜRƒàîni­Ö¬Õù—´j_Ml(Ü7çZQ¬?ÎÁ¯½¡ÏÝì:æ^>3Î…B5mõ7Ð…ç-ìúÒ=II_´DèÌ*ïŽÖ}Œ)¹cÂˬM¿RM[¢Î\À5d“  Û Å à@¤=@ U#¬T4w¿)–øõŸ\ô‡ÓÙçþÉUzûàù놗ú#ÖhÖÕå]0fÐ3Š|‰Jk&;]øÌ¡óWKtŠƒÌ³î£âTV8›®˜j)íC¿ê#×171Ó3V?]=¦ÃúíÁU;9&\1Ê Y ÉÙ㼋ðAy‘=úÒIoji:\þÊxÃ^2²ìíLõL~‚àêŒs*p0„ªÓÉ¿qZPÔÆæ:__.´ÚŒ†µ}T 0¯*—'Žì]á8ú£ÌX…¹Tk™ìã·‡´½lùpkÝ6¶lp˜h ÜÙôŸª»>)†Þèƒ~)û†)Ó!·¡@Šû(¹÷Q²°äÅÌ·ÔIcJ2a×êüKZu|9»Ç ëZƒû¦E|NO_ý†^Ø,«šYÉê1CP«?}µ»ÚM0»àIÜkSŒ_ŸûO¾óÅ/~ñÅ‹k¥< @à†ÞH 0€@/Ð{‰vB€ @€ @ ?èýÅ ‹!@€ @€ Ð ôÇ^"…€ @€ @èúc1Ãb@€ @€ ôBý±—Ha' @€ @€ú#€þØ_̰€ @€ @½@ì%RØ @€ @€ þ ?ö3,† @€ @€@/Ð{‰vB€ @€ @ ?èýÅ ‹!@€ @€ Ð ôÇ^"…€ @€ @èúc1Ãb@€ @€ ôBý±—Ha' @€ @€ú#€þØ_̰€ @€ @½@ì%RØ @€ @€ þ ?ö3,† @€ @€@/Ð{‰vB€ @€ @ ?èýÅ ‹!@€ @€ Ð ôÇ^"…€ @€ @èúc1Ãb@€ @€ ôBý±—Ha' @€ @€ú#€þØ_̰€ @€ @½@ì%RØ @€ @€ þ ?ö3,† @€ @€@/Ð{‰vB€ @€ @ ?èýÅ ‹!@€ @€ Ð ôÇ^"…€ @€ @èúc1Ãb@€ @€ ôBý±—Ha' @€ @€ú#€þØ_̰€ @€ @½@ì%RØ @€ @€ þ ?ö3,† @€ @€@/Ð{‰vB€ @€ @ ?èýÅ ‹!@€ @€ Ð ôÇ^"…€ @€ @èúc1Ãb@€ @€ ôBý±—Ha' @€ @€ú#€þØ_̰€ @€ @½@ì%RØ @€ @€ þ ?ö3,† @€ @€@/Ð{‰vB€ @€ @ ?èýÅ ‹!@€ @€ Ð ôÇ^"…€ @€ @èúc1Ãb@€ @€ ôBý±—Ha' @€ @€ú#€þØ_̰€ @€ @½@ì%RØ @€ @€ þ ?ö3,† @€ @€@/Ð{‰vB€ @€ @ ?èýÅ ‹!@€ @€ Ð ôÇ^"…€ @€ @èúc1Ãb@€ @€ ôBý±—Ha' @€ @€ú#€þØ_̰€ @€ @½@ì%RØ @€ PMàÖ[o­>† @€V%€þ¸*N*ƒ @h‰À3žñŒ–ÌÁ@€ °Gè{Œ:>C€ @ÜI q€ –  ?¶lƒ @8ˆúãAø8€ ¬Aýq ŠÔ@€ Ð$ôÇ&ÂQ€ ì‹úã¾â·€ @`WÐwnœ… @ MèmÆ« @€V €þ¸Dª€ @‡@<ŒGC€ 4Lý±áà` @{!€þ¸—Hã' @Ø!³³³zË€ @ )èM…c @€ @€ 0ôǡ‰3€ @€ @hŠúcSáÀ@€ @€  Eýq¨pâ  @€€O€õi€ @àäÐO € @ØŠû_oE–z!@€@1ôÇbT„ @èúcoÃ^@€$€þ8`Pq € @À ?Ò @€ÀÉ  ?ž<@€ °ôÇ­ÈR/ @(&€þXŒŠ‚€ @½@ì-bØ @€À€Ð *.A€ ôGZ @89ôÇ“‡ @€¶"€þ¸Yê… @ÅЋQQ€ @ 7ggg½™Œ½€ @`4è£E @€ @€ ÐôÇvb%€ @€ @úãhÅ@€ @€ ´Cý±X`  @€ÀÊXÿqe T@€ê  ?Ö3ã@€ N°ÿu'ÂL@€F&€þ8rtñ € ìœúãÎîC€ ÐôÇ¢€ € @›@Ü+•B€ è5´( @€ ÐôǮ…±€ ŒIýq̸â @€€ ?Ò @€ÀÉ  ?ž<@€ °ôÇ­ÈR/ @(&€þXŒŠ‚€ @½@ì-bØ @€À€Ð *.A€ ³³3P@€ œ–úãiùsv@€ @€ ŒLýqäèâ @€ @€NKýñ´ü9; @€ @€F&€þ8rtñ € ìœë?î¼à> @-@l! Ø@€ ° ö¿Þ+•B€ è5´( @€ ÐôǮ…±€ ŒIýq̸â @€€ ?Ò @€ÀÉ  ?ž<@€ °ôÇ­ÈR/ @(&€þXŒŠ‚€ !\¹råòåËÚ”Ã>çÏŸ?ç}Ü÷÷ÝwŸŠ á1Nìšúã®Ãó€ ´Aý±8` @`3=öØ¥K—n½õÖn¸AZÌ7Þ(½1Ð%5Ú'Ð%UþÚk¯½é¦›î¾ûn —›ÙHÅØŠúãVd©€ @,FEA@€@W$ÞvÛmÒ¯»î:‰’ ~øá\½zõþûï¿pá‚„KUuóÍ7ß{ï½ êᜄúãI°sR@€ à@¤=@€†"ðè£Þu×]’%þáþá§>õ©ÿ³Þç _øÂ[ßúVIJŠ”¸ùàƒÅgF$ ”ÞÝÂ'@€ ÐôÇž¢…­€ )Ês¼þúëo¿ýöueÇXÀüÊW¾"qóùϾTN­I\ @€ Ì@¤m@€º' ©ÖÚFFÊã›ßüæõ’‹júØÇ>¦S£Bv߆p€ @›@Ü -C€¶' ½e”ó(ùïï|g‘^¸M!S!•ÉŒìícÎ @€ ÐôÇΆ¹€ G@{RkÇãç<Îi˜þð‡%Aj]HmYC˜ ÐÖl$˜@€Àž  ?î9úø@½ÐRRú´'µÖaÜ&£qy­ZR3ÁY²×¶5œÝì=\Hq€ þ ?ö3,† Ðg‰úЇþw«Ÿ/ùË?÷s?§ôÌG ÷[ €þØB°€ @ÜyÀ}@èŒÀ¥K—^øÂ~þóŸoU{üW»^õªWimÊǼ3Ę;ôDZâ‰7€ tIý±Ë°a4 ì“€&\ÿò/ÿò׿þõöÅG³PkSž;wŽå ÷Ù\ñý±‘@` @{&€þ¸çèã; tC@ž6˜~ÃÞЋòèìÔšÁó7£+Ù‘fW¶gÑÛ‰–@€ °[è» =ŽC€@$>*ð¡‡êT|4³5gü'ò'ï½÷Þ> cå@Ð &®@€ Ð+ôÇ^#‡Ý€ °švý¼ç=ïŸøÄ?÷ÿùÚ×¾¦,NmÞ½‡Àác;ÎÎÎÚ1K @€À>  ?î3îx @}¸é¦›ÞûÞ÷ö¯=þ‹ŸûÜç$§*£³úX @€ ¬Aýq ŠÔ@Ø€€v»~ýë_?ŒøhŽh"¹Ö‚|üñÇ7F•€ @€@‹Ð[Œ 6A€.^¼øò—¿|0ñÑÜyÇ;Þ¡½¼ 1 @€ °è; 4nB€@O´H¢–JÔ‚‰CêrêÎ;ï¼ýöÛ{ ¶vK€õ» †C€ 0ôÇqb‰'€ 0-¨EµTâ¨â£ùõó?ÿól‡=F‹mÜ ö¿n<@˜@€À ?î!Êø@ÝЈçÎûà?ø ¿ð ßùßùíO~ôÇ‹^ô¢OúÓÿ4Ðç«_ýªdÖ+W®t í“úcŸqÃj@€†"€þ8T8q€z'p÷ÝwkmDiŽOyòcú£û{ ùñ#ùÈý÷ß¿EÍÙ:xà‰­½‡ û'€þØx€0€ =@ÜC”ñ€ú ðØc=ëYÏzÚÓžfÊãßøF“ðÞúÖ·þðÿ°¾É*z ˜¾©tËÇ~³°ûhš=[‰þØsô°€ A ?HÜ€ Ü|óͯ}ík-ÛQšc î)Qñp½/®á´úãg?ûÙ믿^³Î.´Iý±Í¸` @»"€þ¸«pã, ´K@+!>ç9ÏÑThK~\WjTµúL*˜%ú£–ž´JÖ ´Âñ¹æ¾ýë_áÂ…vƒe@ì<€˜@€ÀÐGˆ">@€À´ìãÛßþvÓõq“¯c!Rs¥m]Èø'i|ö“ ­°Õ©¶²q™•Áâ’öÏ ZþÞïý^ Jý3Ðí×~Mô½ì±yâî\neɹïuˆ6¢Ñ¬sÍ= ˆ¸Ð ôǃ‚I€ ìúãÞ"Ž¿€ Ð"K~üÇ'?¦ßéÿï{ßûì›àóðÃ[™·¼å-ÁOšÁm"£}oÿTamŸ­¿Mt¿ÚþÚþF7þ¯:üŽ;î°_¿ç{¾G‡«gÛƒ>èNíNª íì®fóbò{yájøõ_ÿõ»îº«ÅÀ`SÿÎÎÎúw @€@ßÐûŽÖC€À,ùÑô8§úI¼“bèëtN°3EO¿ú£éƒ¿ú«¿êK™LüÓ‘† AmV@Z¤)’þhJ¥Œ·ï%;:±rò{©™®†¿ýÛ¿eÈ1Z2^@€ @ &€þH«€ œ˜€Æøðå?©x~fb¬BšF©2þQÊI´/dió©caÑÿfN”ˆé§RºCâ³Xþ£/2Za™øÞ¥aZaMâ¾ûî»O N@€ l@ýq¨T @¨! ù¡¯yÍk•ð‹_ü¢¿f¢TB—Zèç6ú_*£0P M[ŒÓ$KôGK±LäEºéáÁ¤ï /2Ðõëdù~ô£7Þxc 6ÊB€ @}@ì#NX @ÐÔãÏ|æ3sYŠRë\.¤6¥qÅ,»ÐŸmÅ|EÒŸÊ-urr*÷\þ£›=më9úËj\W”_ZSë`h\; Ö< vN @€|è´@€À) \¾|ù…/|azŠ´[KÑÏ%Ô2Žþl7-:¨J’¥e2Zá¹%#ã“¥'5}Û•Ñj’ŸøÄ'Â2*ï§[þå_þ¥f‚»Éàö·>ÊÍ,wðw~çw.\¸Ð]1¸eè-GÛ @Ø ôÇ7!@ E?þøw}×w}éK_*Tè²úã+^ñ ¿*•·¼HýßÔ@û§þð‹i¿›¾í—‘¼è—‘"—Ñ7¯yÍk¬˜³-Ø '¨'íéÏüÌÏÜwß}-† ›º%€þØmè0€ q ?ŽK<  (=ð}ï{ßú£‰ƒÒƒz,Q¿ºï•ÕißøÚ¥ý4I‰ŒV¿Ÿð¨òö¥Ë”T ¤•4]RŠd°NeÚMé°×]wÝÕ«W{Œ#67Ký±ÙÐ` @û!€þ¸ŸXã) ´HàâÅ‹/{ÙËjõG©–Òõ‘¶è2±Ï‰†Aå–íè‹•6í:aC,PZaûÞŸa}ÈúÊ|¼é¦›Z 6õLý±çèa; @ƒ@$¸@Pºß3ŸùÌ¿û»¿ûjÁç]ïzW0»Ùþùƒ?øƒŸýìgƒ 4ñY?½ð…/Œ+6ÉRµÙOöÏÛn»mÒ„|à¦WÆ¿JµYÛî'g¡«¼À­)ò’—¼äÞ{ïí4Ž˜Ý,íòÔ¬m@€vBýq'ÆM@h—ÀÍ7ßüæ7¿¹D§sêžrõ·C%ê› SUÀ2%ýO ?J£4Ó¶” êÑYìq=vöUôÇÏ}îsš|­1Û–A€ @‹ ?.ÂÆA€ õhÞ±ö]©ÒýìB%?Næ'šÈ˜øø•H‚tå¥'új¦%9&>R!ÏÔ<ô[o½u=¨Ô@€ ´Bý±•H` ì–€’þ®¿þú¿þë¿ÎJs³›M:”Pè×`_JXÔQñG³ªƒÓýÕ_ý•jp*¤dM+`ú£¾Ÿ¬'˜g½xþõ³Ÿýì+W®ì¶ à8 @€&€þ8ppq €º! =a^ùÊW.Ömu°Dã¤(™=… ¸Ú¤HêŸn›’c—éo}ë[ÏŸ?ßM´0´+¬ÿØU¸0€ 1  ?ŽW¼‚ ¾¦@Ω{ MmôçMÛ¼lqÆÑß‘Ær]åñÒ“‹K–œ”äǾšk_Ö²ÿu_ñÂZ@€†$€þ8dXq €ú# ÈW¼âŸüh¥H[‡Q¿ã;¾CßëÿîûK—.YáW¿úÕq­šm_~üãWI¿€¶Òþ¶oû6èÊØ>3~宼*·c_ÿú×§}q¿¾å-o!ù±¿öÚÅèýÄ K!@–úã°¡Å1@è‹€R o¸á%&d»„þ(‘ÑÔF'ªKÔG¨€×fÖš^-‰Ð‰‰¶½µFW –2U§©Šúé%/y‰ê‘d©?t”¾ÄP;\ß«€Î¥S§…H’ûj¨ÝY‹þØ]È0€ ñ ?ŽS<‚ ^ ØFØËôGe¡$?¿SƒÝ«õ+¦FS ý„ÅÀ Ù33H”4éŸ1®Ê¯ùÿðÙöº×öÚ‰Ýè 3!@™úãÈÑÅ7@莀f"k>rZ‚Œ'_[ye)ê§xB´¾Qn£²õQ¶ãäáúÒ èãgPÆ*¤+&1>—›Ó­©ääÔoW§&z+åó±Çë.LÜôÇŽ‚…©€ ŒJýqÔÈâ tIàÑGýþïÿþ/~ñ‹…‹'v]Lë]jÕË.ã„Ñý@ì'VX @€À°Ð‡ -ŽA€@§.^¼ø²—½¬ka±Äøw¼ã7ÝtS§1Â쎠?v,L… @`Tè£F¿ @ c.\øíßþí«ã~>úÑ>ÿùÏ— Ó;!pvvÖ‰¥˜ @€†%€þ8lhq €º& ÜÀ·¿ýíC*û·{ã7j¦y×Âx@€ @ úc!(ŠA€ŽJ@Ê£2•'8˜©Ýf~â'~âòåËG¥ÉÉ @€ Ó@<{Î @HP†à³Ÿýle Ž$Aþ—ÿò_´À%‘‡ @€öCýq?±ÆS@èÀý÷߯lÁaôG-j©¥-û ÷L€õ{޶C€ 0ôÇA‰€ 0*»ï¾[9ƒHZÎ’ ¯Gm¥-ûÅþ×-GÛ @Ø ôÇ7!@ cwÝu×OÿôOá _øJ·Ÿ×¿þõüñŽÃ€é}@ì3nX @€ÀPЇ 'Î@€À¨î»ï¾ù‘ùøÇ?Þ)ÙTù›·ÝvÛ¨¡Á¯Æ  ?6 ̃ @`Ð÷e|„ \¹rE;b¿ÿýïïH‚Ô:/zÑ‹Øpf„ö×­è݆Ã!@‡úã8±Ä@žÀc=vîܹ?øƒ?èB‚üÈG>rã7^¾|yø¸à`ËÐ[޶A€ °è; 4nB€À ´„â­·ÞªéÌKÚmFٚʄ;ntKý±ÛÐa8 @ã@'–x@û! M±ìÇ~L † ªÒ/\¸ Ýf´g÷~"‚§Í@l64@€À~ ?î'Öx @Cмæn¸áU¯zÕ#<òåf>üÇ,«´a÷P¬q¦gggg=›í€ @`è#D @`·¤ôIï{ãßxròÝï~÷þèÞ|óÍZ¤r·áÀq@€ @ &€þH«€ ôM@zŸV„ü¾ïû¾×¿þõŸÿüç/Dšò¨qØj¦ï–„õ€ @؆úã6\©€ p\ZuQ›Ò\ýõ¯}ík?õ©OA…”Ö©ÙÖ(Ç3gƒ @€@Ðû‹C€æ(òöÛo¿îºë^ô¢iRöFéJxü…_øE³­Éy¤56N€õæA€ °è{ˆ2>B€ÀîÜÿýš”}íµ×JˆTFä>ð3"¯\¹"AÓdGMµ¾téÛ[ï®Uõé0û_÷7¬† @`(èC…g @>Ç\B¤2"o¼ñFi‘š+ýë¿þëwÞyç»Þõ®O~ò“_úæG¿üå/×—î›Ï}îsúç›Þô&•ÿ©Ÿú©ïÿþï×Ìn š’Ù^†6ÖôǾⅵ€  IýqȰâ @ $ tEÍ•Ö\Ô .(QiŒÒeìóïÿý¿×ÿÿÝ¿ûwî›k®¹Fe4½Zåï»ï¾‡~ è”úc§Ãl@€F"€þ8R4ñ€ °„ÀsŸû\S—Ì1h› »íø` @» €þ¸‹0ã$ @ A@©Žè´Q  ?ŽYü‚ @ #è S!@›@Ü+•¶Aý±8` @»&€þ¸ëðã< @@Ði@8¸¸@€@/Ð{‰vB€¶"€þ¸Yêm€€öPjÀ L€ @»&€þ¸ëðã< @@Ði€ @€ÀvзcKÍ€ > ?ö'¬„ @€@ŸÐûŒVC€Ö#€þ¸Kj‚ @€Bè´ @€ÀÞ  ?î½ í?ë?^œƒ @ è}Ä +!@Û@ÜŽ-5Ÿœû_Ÿ<@€Ði€ ½@Ü{ ÚôǡËs€ ôAý±8a% @`;èÛ±¥æ“@â„•€ í ?nÇ–šONýñä!À@€ €þH€ ìúãÞ[ÀÐþŸ íÎA€  ?v$L„ lJýqS¼T@€ @ÜyÀ}@€Àè4@€ @`;èÛ±¥f@€@ÐûˆVB€ @ Oè}Æ «!@ë@\%55G€õ› A€ °?èû‹9C€¾•ú#-b`ì=ppq € ^ ?ö)ì„ lEýq+²ÔÛôÇ‚€ € ìúãÞ[þC€Ði@8¸¸@€@/Ð{‰vB€¶"€þ¸Yêm€úcAÀ@€öNýqï-ÿ!@è´  ?\\ƒ @ è½D ;!@[@ÜŠ,õ6@ý± ` @{'€þ¸÷€ÿ€ ôGÚÀÀÐ.®A€ Ð ôÇ^"…€ ­ ?nE–z pvvÖ€˜@€vMýq×áÇy@€€ ?Ò @€ í ?nÇ–š!@}@ì#NX @€ >  ?ö7¬† ¬Gýq=–Ô@€ „Ði€ ½@Ü{ ÚÖ:¼8@€@ÐûˆVB€¶#€þ¸[j>9ö¿>y0€  ?Ò @{'€þ¸÷0´ÿèC‡ç @èƒúcqÂJ@€ÀvзcKÍ''€þxò` @@¤ @€öNýqï-`hÿч/ÎA€ ÐôÇ>â„•€ í ?nÇ–šONýñä!À@€ €þH€ ìúãÞ[ÀÐþ£?^œƒ @ è}Ä +!@Û@ÜŽ-5ŸœúãÉC€€ @ý‘6@Ø;ôǽ·€¡ý?;;Ú?œƒ @@ì H˜@Ø”úã¦x©€ @;'€þ¸ó€û€ 'Ði€ @€ÀvзcKÍ€ > ?ö'¬„ @€@ŸÐûŒVC€Ö#€þ¸KjjŽë?6 ‚ @`Ð÷s<† |+ôGZÄÀØÿzààâ @½@ì%RØ @ØŠúãVd©·è  @Ø;ôǽ·ü‡  ?Ò&€þ8ppq € ^ ?ö)ì„ lEýq+²ÔÛôÇ‚€ € ìúãÞ[þC€Ði@8¸¸@€@/Ð{‰vB€¶"€þ¸Yêm€úcAÀ@€öNýqï-ÿ!@è´  ?\\ƒ @ è½D ;!@[@ÜŠ,õ6@àìì¬+0€ ìšúã®Ãó€ @¤@€ @Û@ÜŽ-5C€ú €þØGœ°€ @}@ì3nX @Xúãz,© € @  ?Ò& @{'€þ¸÷0´ÿ¬ÿ8txq€ > ?ö'¬„ lGýq;¶Ô|rì}ò` @@¤ @€öNýqï-`hÿч/ÎA€ ÐôÇ>â„•€ í ?nÇ–šONýñä!À@€ €þH€ ìúãÞ[ÀÐþ£?^œƒ @ è}Ä +!@Û@ÜŽ-5ŸœúãÉC€€ @ý‘6@Ø;ôǽ·€¡ýG:¼8@€@ÐûˆVB€¶#€þ¸[j>9ôÇ“‡ @€ú#m€ °wè{oCûvv6´8@€: €þØA0€ °)ôÇMñR9 @€vNýqç ÷!@`üñK—.]¾|yÒÛ´þøðÃßu×]=öØ.Há$ @€ °6ôǵ‰R @ =wß}·VÁÓgr.jB¼ÿþû¯¹æxóÍ7·çA€ @@ì H˜@8À}÷Ýgúã¤9§?:ñQG]¸pá@8'!Àú'ÁÎI!@€€Oý‘ö@Ø©0sä¤þè‹7Ýt“fpïNG€ý¯‡ )A€ ÐôÇþb†Å€ eæ$ÈXD|\F˜£$€þØ`P0 € ½@Ü[Äñ€vM`R‚ ôGÄÇ]7‘áœG.¤8@€@Ðû‹C€!K¾þˆøx[ŽmúcƒAÁ$@€öFýqoÇ_@€ÀéôGÄGÇxÐÇ‹)A€ ÐôÇîB†Á€ øäõ×_o[Ó\sÍ5öά€˜*Ú €þØF°€ ]@Üuøq€öLÀ— ÝÖØˆ{nCúŽþ8dXq € ¾ ?ö/¬… ¬I – É|\“/u5@@¼+0€ ìšúã®Ãó€ p8Ë—/ß{ï½Ò8¤Üi!Eû¸Í~^!¯Hàºë®s´õÇí·ß~ñâEÅâêÕ«‡Ç” ¾<öØcºüïºë® .ø=ƒ[SbÅ·ª|ºÙ9à7ß|³n…÷Ýwß•+Wúj?X @G €þxÈœ€F# ±®Ô®óçÏk¦¡— º´y‹ÀöyôÑG;òù–[nù7ÿæß<ûÙÏ~üñÇ{1Ûä÷‘îpÛm·)×^{í7Þ¨>üðýø‚€À2Ò¹$8Þpà öBBï!î¾ûn¿gè¨O[FàäG)¸½ŠÓQ°ºbÝõ !8yŒ0€@#Ð f@€@¤*jpûüç?_c]©]ï|ç;ÿŸö|ìc“ !IBidâtpia"j(ÃN=°úaé\oxÃ>õ©Oµ×íÝ¢¯|å+o}ë[%A*UŠ¤ÞØé¥QM) @£@-¢ø@[P‡Ä,M4“žõáxï#ËNü—*!mB …t e决ťÑ~¬ÿØ~Œ -”€¥X‰uÒ³þðÿð _øB']ÑÞÍÔ»:Ó‹µJ‰’% ÃM1@Œúã`Å@X™€K°”ÄAŠM¿ché¡$+gåöAuÍ`ÿëæC”7P/t ë%Þ((±®ß¾hç–¿ï}ïÓ4yÉǬ‘oô”€ 0ôÇáBŠC€ °ÍÛµ-e4ŸwçƒÆ1Ü— ©Iš¼¹R¡š ?v¤¤‰ZõB/¤?¢<ŽÑ+Rýð­·ÞÊŒìÞ¯Mì‡ PEý± …!@`´Î£†FJ{T²Æã=¼p”ǪìÉÊ>øà.ZóîDì· èU­zÁTëñúð7¿ùÍ ®Öê½zõj¿MË!@ œúc9+JB€À.Ø„k þ7Ÿq üÅ_ü…öR^Õ.Úô¾Dì1þšp­låŸû¹Ÿû›¿ù›qû¡½{öõ¯ý·û·Õ3»Ç‹›!Ô@¬%Fy@™€Ö|á _øå/yïãÂ}øÿªW½J+{²/ÍÈ—ôO ?v_%Äií í0³~hï^~ò“Ÿ”ɲÝ]§ @ –úc-1ÊC€À°”nóò—¿|ïcÁùÿÖ·¾Us±Y†lØ«ý±·Ðjá]e +Cyg]Ñ®ÝÕ;?庒ÞÛÅŠ½€ê ?Öñ¢4  I@é6¡H·ÙçøCúô–ƒòÒ–Sä?vY%Á)9×ûìŠIHïèRÅT@  ?.€Æ!€ 0­‡»ÎëÏþóR=î½÷Þ¡Z6Îó™Ií×~Me?ò‘”øÒ—¾dë’òÝ•‘©ö åçÆkêx– ÜÿýRÿÜc¨W´m®{TǨ_ÿàþ 6L=糟ýìïüÎïÔÿõ÷\ %UõØfpIµ*“î±Í;?W[¶@¡ нãï8þ|Ë-Û @`ôÇÐ8€! ½ßò–·,5{ˆFŒO™ú<õ©OÕ896[ß«xÉ€Vƒd+¬Íf h˜2a5ŸÙƒ\á¸Ñ­€!Ýÿøo5¾÷{¿×:4õl“¢:Fý*‘ÑïUüžÐõµªaR¦ÌvGU=¶:Þò8Ûc›w²|ÎÈl¬w‡¸óÎ;o¿ýöÚ/6B€@)ôÇRR”ƒ ÁÜu×]¿ñ¿qÈ©ÁcÝõ'~â'\¤ÆÏ6j%ÈýQ#s¨ïATLÿçÿüŸ7Ýt³ÿ†¹ÞYÿ±åPJëÎsžs’0\Ç8Ù7ª+ˆõGÉ…Ö êX |êoõuú²ä-N|Ë¨ê± õÇÂ;+/f l}Ôb ,ˆÑòÅ‹m€j  ?Ö£< Œ@@£m¶>¿þ¹ª$õ ¦ZgõG7ÞÖ[ >åÙ7Ç÷}Å3ÊÓÛn»m„†ŽìÝpÊ/­_ŠÿŠoyU¦?º,Hm?ëz…gDê(õ“ñá%–TõØ%úcy•³J<¤ b4|íb %ЗPã@蚀øÓt¿¯~õ«ÿ4ÜG˨™D¨?|ç>ýéOû·»¾¿ãŽ;üïíK3çH¨ÒßøÆ7ªÀ\åÃQü†C¿ò+¿rñâÅ®Û9Æg<ã h“€T~iý§ê@LTïg¤þXâôG÷½;d-›«zì’¸¼Ç6ït ˜ó%[`-‰z”«›õc=ÖfÆ*@¨"€þX…‹Â€ 0-ð÷¿þ×ÿ:ÂØéø§H P—é¾ %£ß㻼Ñ%O?ëYÏbÜ;ÀþØf- }£ë·¤Z'&¾õ­oµ×6Áë™9ý1V*KN7Y¦ªÇ®íÓå³òb¶Àb¯«|ûÛßÎ^4m^ÂX@ –úc-1ÊC€@ß.]ºôK¿ôKU㟎 Ï 8m€- R‰Uù»ÕåøŸþéŸj‡¢¾›;Ö“ÿØj8ù{ ?™ÑR õßãÅúãÿðO*•‹ïU=ö>õG±Õ ¡šµÐjCÆ.@(%€þXJŠr€ 0-7¦¤¶Ï~ö³‹‡‹89@•æh#m žû³ó¯÷¬?2îà’— ä?6Ç“'?êêöõG·B…¿E¬?ºbÖ¯sܪzìÝê<ðÀ¹sçlƘ@UЫpQ€ú&p÷ÝwÿÚ¯ýÚ‚Qb/‡¸ª†Öîc"ãäœAôÇtdßóž÷hŒ¾ýî­Gl­ 4ò(XÌÑrýõcýQÝ…úXë6­ð*dU½[ýQØÙ »µ«{ , €þ¸‡@€@—´–Ÿ¦qýíßþí?ŽûyßûÞçÆÛÇ*®Û¯še\‚ÄU®?JÊQægög•«Õe‹Çè'  ?¶Öì=ÐÉûÓ]ï÷Å/~ÑúýèEf›~²IÙ±©*ãw­îZ§ªzìÚ8]Þ¼“s6g Ô:{Hù~ô£Ïþó¥\·Ö˜±€Ê  ?–³¢$ ôMàÂ… ÿãüC†@í;9àÔ—› ù=ßó=¾èÙ˜jÜ«…êúnúû¶þììlßÚòÞ’[xèNpT¯øðçõG'P:R‰ÙÎ$.PÕcïY:iÖR®ÛjÍX@5ÐkhQ€º% äG zÿþïÿ~Á±£CÔ_ýÕ_5 òÁt¡?–÷W~åW.^¼ØmÛÇp4DàöÛoÿ­ßú­’ënë2±þ¨3Z—hbb"ÿÑÙ&¥ÒêÑç-oyK­ÍU=öÎõGiÖ×_=) ]̘@ ’úc%0ŠC€@Ÿ™ñW;:­-Ÿ Æj#úc á÷¿ÿýì~ÐçuÕÍ„ô™Ï|¦äºÛºÌ¤þxÇw81±D”‘’ «:R߯ª{çú£¸±Fs×3A¨!€þXC‹²€ Ð-éGR‘¶О¼þªÑ¬KöaýÇl஽öÚ«W¯vÛü1M¸råŠáÍ^nÇ)0©?êÔö½–ª(ÔÝ!…i#ú£Ý,Üdó˜¹mÈ3¹üåqŸåÿøo½õÖ&š2F@€@=ôÇzf@½r$ýHó¶†ÿ¼÷½ïµäý8ë’t´žûÉ¥í”IT^rx×e~é—~éÒ¥K½5|ìýÖl§(¯~õ«é œþØ£iÔnµ\à²Wu¤~mU=vmœ-Ÿ0[+–دZ¸#ëþÑ h öu×]×N{Æ@¨"€þX…‹Â€ Ð%)GÒŽ6F:á‰æœn‘2 )}óª†ÍÙÑì ßúÔò'¢ä¦.[ÿîfÿëvšÀ 7Üðñ|뫵°þ9ýQ‡+ùÑ$H_üð‡?¬C~ÿ÷?¨ßò-‘°ðÔ®XU]ÛgË›åúø/¥d›ÄGƒÜ/j½Û¢üóž÷<-aÜN“Æ@('€þXΊ’€ Ð+›nºéÝï~÷c¡ÖêtNýéŒú0xvßåõOK›pé>n@nßüøÿxk6²Gråݨò^¯ÛþØHð}ôQm¶Ñº Ú„þ(©Ñmlíò]犯Ôõé…„þïŠéŸ l¨ê±ç ËB ¦vöÚÛmž£?ä‚>%S±ØºÀÇuÑæEÚ¨‘&€ PEý± …!@ ?üØâ}뎂ڬÍM²vÉ;ö‡Æ“ jP˜íŸAy7ƒÛxãmfÇl—¼à—/_îïؽÅè4»îºë¿ÿ÷ÿ¾ÝZ[sBTUÒÝ,lW³ä9§Í¹.Qß,ž¤\ÕcÏö»â=¶/8úYŸš‡^‹ôå•?«,ÚFš4f@€@ôÇ*\† þÜ{ï½/}éK0.jä5 >s¶i@¶oÜ!sô},h6a 3” tÛm·õwìÞbôÇFš€m¶Åµ¹¬Nëý”Úõ©O5îHËæ‘ÔÜÊ…€j ?ÖТ, ôF@{†<÷¹Ïmy…mP—Ò¸z»°§'°ý±£­_SÑOIc zèõÌ8€ú!pùòå¼àý޲°¼)¯~õ«™ÌÛÏÕ¥ ¸ùæ›ï¹çž¦.gŒé—€¶ÓŽê µoL è(@Ý@ìw„Ù åè=öHÆ-DíܹsþçÞàEI=в*Z\¥…† € PNý±œ%!@ ?è=Ž-›µý±¿.à‰'˜ªÙBÔЛíÖz4 ý±…‹ Ô@¬%Fy@è‰úccËfmFìéâÿ¦­è-Dù×Ívk=Æüë.jl€ PKý±–å!@ '¶ÿÌ×ù@` ÿí¿ý7öŸééúÒVôÇB¦ýgþèþh«: ðu.ê.jl€ PKý±–å!@ 'Z"Jµ®A`·ÜrË¥K—zº°ý±6€þ¸JD%Fý±Ë+ Ô@¬ãEi@è‹ÀÕ«W¿ë»¾‹1V!ð3?ó3÷Ýw__—Ö"U´Ð”8¬ôáU.ÃŽ*ùù'?Ü…©ûØÇn¸á†Z56@€@ôÇ*\† þ\wÝu<òHêFþÉŸüÉ·û·ÿÐýЂcW<䵯}­Ì~¤ý?ð?üp×À¾-Fl!þî%߯Øç¸ªÔí¨óQ´Eå‡Ô©Îù)OyŠl;¤’ÝúvðgögçÏŸo¡Uc T@¬ÂEa@èÀM7ݤ¡o£¸›¿û»¿[CÜ`ìýÁ~ð=3¿ÎO~ò“*¥ÿgO¤b–È£M–×—f=Òþò—¿¬Mú»vo1úc M@½äûlW³ €õï~÷»]á§=íi*¦ÿ'ؼô¥/Uý~mú§FÔñ!6ØÖÙG$ý Ÿ>üáßxãý]»·øììl÷ NàñÇ—|¿zç`Ý:Ÿe} unêåVéƒJ¬ò¿üË¿´ï]ϬïÝ—þ!êœ-_2¨§¼޽°{ÄÜíÀw¼ävàê—kÕÎÝ>6½¼ìe/»xñâéÛ4@€@%ôÇJ`‡ ÞÜ{ï½/yÉKV÷¶P¡t@5ùÚ7FCJmjdüqovÀiUiœ©Á¤þÖéÜP6– mtV3[€¶Ø†ßû½ß»í¶ÛzkþØ V¨ÓxßûÞ·øœ<Ð:±àµGy˜Õ]èúÒDk ~謊S;pRô}Ñßú¨ÎøµÓU«sîv ±êu” ëbÌ]µ“§Þôv =å´³\+Í; @ ˜úc1* B€@Ÿ”w£-h¾ô¥/­;îm¡6 ßsÏ=±þ'ÑÄ—è7?÷¹ÏùÇÚQ“õÛ¨X7-ÀY݆¼à—/_îó"Àjœž€mA³â…9™®úh˜=W‰þ¨·/~Ÿ&EÏŽJ÷±ÖOúŸ³ÊSÅ'õG+¼ï‘=AÊgVô3ßJna:¼î ÙÛÇF·ƒ‡zˆÍgN1c EÐaã @芀-™‹öU@y(s“õ²ccó4;€œ¢µe¾ÄSã!w_HÖ~þóŸ×FFÒ²»jø †(gM™k+ö ÖÅ’ÙŠúcºœõœ0ê —f•¬•x7iv¬?ÎÍÈ.gèòWÑ- ÔÞxeoÝî¸ãlèªÆ@5ÐkhQ€ú$péÒ¥[n¹¥|ÌÖEÉÃÇÞÙä$ >çôG›^˜˜Ódg¤šÐÍ7ßÜgó߻լÿØN Pæšò×Öºöm‘ÁxõÆ­õǬ¨7Ù:ýÑ­ÉXžÐ'•gMu±(¹T-ß±Ñíà¹Ï}îƒ>ØN“Æ@('€þXΊ’€ Ð+«W¯j öWÇúØØû…/|aà–{gÝuÎlI¿ÀþàZ~e|”­ù5ùSÕ),ü‹¿ø‹’ {½öm7û_·iÁJ^[ëw P,îÝüë*“ÜN2ïz×»&t3¬ý_þ¨/'{QÕôŸøÀìeÊWYè [úÌ™êJÖ޲巸üõ_ÿµòÐÛiÏX@UЫpQ€z%`[,µyÔÜÈySýÑ ¼u–‹?ÿÕ_ýU›Ð[uíµ×JÅîµõïÛnôÇvâåÊ•g?ûÙ‹/Cÿ@u2ÖÆÊZy¸LL¼ƒ‘…–!¿†ñõÇÏ~ö³vjÿR¬?ª6{Ïdä‚~õ„úã·m{}ë­·¶Óž±€ª ?Vá¢0 ôJàî»ï~å+_¹Ê¸·‘JÒco[_,øÃ×l‹yj›®Ú¾«6®ž­ðœU@[f†”ké×½6ýÝÛþØT¸þúë5›xÙ•è5©Ö¹.Ë4»l¸@tºç\N¢©“ñ¯¾þhýªu§®[žóÈí7­Âµ*¤ÓcoxÃ|ž…·ƒª|ÉÕo?ó3?£¥œ›jÏ@åÐËYQ€:&ðØci냿û»¿;|ÜÛB ÙÜ~Ÿ Q¨dÀ醯®*¥,È9«8[ ý²—½Ly7·þ}›ŽþØTü5ÿZ[ˆ~]'¦÷š´WÒ.Ð]òã\6bzV¸úÏ@ÂsJeZQµjM²,ŸŽwàKð©ävP«W®{;Ðäk‰×lÖÔåŒ1€ª ?Vá¢0 tLàÂ… wÝu×áãÞjH̪si5*|Ë œV‰Fû.r2»ÇÏL$H¶@¯Ê†}èC7ÞxcÇí~÷¦£?6Õ¤IE’–TuÆ…“¬ËûÀZýÑ-@1÷&«Šúú£«MS¶å`BÔ¯’;å—S!ýzâ®^󻘻Sè\A1WÆJÞä?®u;Ð Íchª1c  T@¬ÂEa@蘀R %$>î=pؼÊá%úcöDµN«ÐÒô™UÖŽç³Fž¼3þ:¾æŸ4ý±µ®²F‰þ˜í=ªú+õºV>‘~8·-˜, æ_ûªŸŽÊêV^¢¡ëN”ŒsO¸þ£¬­Â›–Þ=ÿùÏ'ù±µk{ T@¬ÂEa@蛀ƽ¯xÅ+þ¾ÿÖÀ²¡¦þ¼yÉK^¢ï¿íÛ¾-ëåw|Çw¨¤þŸ-Pås§°Ÿ^ýêW×ÖÙfùw¼ã7ÝtSß~÷Ö£?¶Ö,ò3ŸùÌ!W}¢£+ï­¿Rù¬%êi­°T¿Da+£}«ã2fUÐß^ºtÉzò׿þõÖ«—tݦrº’ª9ø¨Z3 q§,¬½””_ñvÀ{ Ö®bì °€úãh@½XeÜ›©§€ íN¢?ÚÈsrœøÁf/ùNY‹“ ×Õ5åÙ:Ûlª¸uŒqŸl.Ìé²ßêá _X¨*šÐY’)yBýqÅÛホ1 €@ôÇ X… 18î]<`^÷@ëjȺþ89NÌC´¹„%£âuQlQÛ¿øEMÕš¡c´y¼€@kO4ÙÎÍ5výÀºúcÉDcúãÿ¸ìÑGLöHsú£ Û’ŽñºêÞ5/;®ÍLRâd¶ë;¡þ¸Öíà-oyËùóç[k½Ø@  ?.€Æ!€ Ð7ͨ}îsŸ+);xk¹€%ËÄ)9nì/ ¦oü±±KcŒKZJ‘ §u"$5ŽÕG%Ý 9f'Ø-“œ´íe/{ÙÅ‹ûnèX¶ è ÇÞð†Åƒõ`ñêå} õfòâ>Ьr+-ªœìQñÖ!'4ÁD÷hÚ¥%ûïoœô)PÖë×oO®2Àtúã¤ý¾t›½¨f‰¡‚»¸o&ß„e“FÓÑ×®ßÚv†÷@m_ÇX@ ”úc))ÊA€ÀH4*ûéŸþé«=4;Ø«/ùËm;ùÑXÑ•ÿÿá?¤‹ÍÐòï|g Ï¥döÌõ¶KÑ8¤¿g_Xÿ±ÙèkA^íïôž÷¼gYáÞÁ,îê÷„ÖÅ% Ø!z›eg·’¿ù›¿9ç‹Ó' دA—®Ú& З’K ]¾|9q;P]~;PIëáKn.®°bTbçdÉŽY·Ùëà Ô@¬%Fy@„Àí·ß.abñШ…mhK“y:ö¥†£Îrý=WÒ³2"5òÔç†nH °Í £-ÀYlÃ< ½¤Œ ÒÐwïû_·ÜtjA ¥¹-¸`çÞÁ¨ªÂ>ÐOè 1{ô:'Q•{“°$èoUᜧv®XXT—«Ž×z`uʼnx²æ„ þ¹Jn \²ÜI±¾ {Èíà?ÿçÿ|ï½÷¶Üz± €ª ?Vá¢0  E@«Jim©ãÞF±üÄCLVt¤d¾âé6ªŠé~C]áO:ƒþØxL¥[ýÈüˆ’Ý\Ô¼ó>¨®Xÿ_à‡~;øíßþí .4Þt1€ª ?Vá¢0  E@9nJ½ùèG?Úéðð1ÞŠŽÛ¼1t™_R@~ìÇ~ìÁª•ïÞôÇö›Àâ1l öÉ…¿FdÐeýÞGx;xûÛß®‰ùí·[,„ *èU¸( @£xôÑGŸýìgúÓŸÞb v„:mA®C渭e¤mVLÁ[«òãÔÃt¿Ñ.ï'ýAì"¬Z CùnµWº:ëyj\±¼&D«ö×R\±òN«:äv 7‚z/(Ç»h· @åÐËYQ€Æ$ ¬F;ïÿû¿Òádž¾šˆ}ZÛåW~ŲNkÆâ³K†Væ£vƒ³‰ïÛ+ôÇ^â/ýQï¾ð…/T]È–j§.¨ê¨u kÞ}ìcëÖÙom‡ÜþôOÿT{ΨCî¥Ñb' ”@,gEI@–€&ÞjË‘?øƒ?èqȧ¡ï_üÅ_œÖr eÆimX|ö|à µý°í{ߎ¡?ví7¢µ ?þñW]Îê|ÔUBáí,¾üÆoü†e&ó±£ S!T@¬ÂEa@–€Ö‚¼õÖ[o»í¶íFeÔÜ ?þã?&ÝfØ«úIÇÐûНÒuIvšÞ`×…I’,ú§Zsðûj«X @UЫpQ€'p÷Ýwk.©4] Y7RróÍ7ß,éyðf½o÷5º‹¿%¤¿þõ¯?ü§†ö |ä#‘â¬=ˆºk¨ @UЫpQ€Æ' y¸Ú‘FiqíÛ°p1eWiš§äæñ4B Cz+ ×ʉ«‹½¸OàÀãÐZŸ¯}ík%>>üðÃ6RL† :èu¼( @{  üG¥Åýðÿð»ßýî/ó‹€fwJÔЈ÷ÁÜCcÆGôK@9q×_½„ÈGyd¬~o¾¬—| îí·ß΂ý^¡X@ Šúc. C€ÀŽH¨ÒÀ½èEª,@@†„ x™è·£ËWû' ãÏØ9ÁÜ×Ö4÷Þ{¯z`½WøÑýÑ;3%2ìá¥k…Ç_ø…_P˜”ð¨Üs-¬Û°œ÷Ñôj)Šc].Ñ€úãš„¦fëò׋É‘~Ï ÉÚÛõBÔ,~W,ÁQ·BmðÅëŸ=\tø@ –úc-1ÊC€$€F3`PqéI´mBGh® S!@ Šúc. C€Æ$À w̸âú#m +tÅ]… c!@ ‚úc,ŠB€F%À wÔÈâm›6КkGÁÂT@¨"€þX…‹Â€ 1 0è3®xõÄZ è…]q/‘ÂN@¨%€þXKŒò€  0è0¨¸ôF€®¸·ˆa/ ”@,%E9@€ÀÀô\\ƒz!@WÜK¤°€j  ?Ö£< @`@ z *.A½ +î-bØ @¥ÐKIQ€ 00½wç®±þãÎ@_îÓ÷/¬… rèå¬( @–ƒÞaC»{ÇhÛ»o= ¹ö-l… è5´( @”ƒÞA‹[Oжi ¹v,L… *èU¸( @“ƒÞ1ãŠWO ?Òz"@WÜS´°€j ?ÖТ, @`P z ,n¡?Òz"@WÜS´°€j ?ÖТ, @`P z ,n¡?Òz"@WÜS´°€j ?ÖТ, @`P z ,n¡?Òz"@WÜS´°€j ?ÖТ, @`P z l7n=ôÐC<ðÀæöÕ¶yä‘- Pg/új®½PÅN@húc QÀ@€À‰ 0è=qNtzSý‚ÏÕ«W9ÁOÛ™ùÔ§>õ™Ï|æ!õ›©q ggg‡T{Ìc/\¸ HÇdÞÚ¹èŠ[‹ö@€ÀZÐ×"I=€ Ž 0èí8x˜.µë)Ñç–[n±*%ç?ªü‹_üâà„ú2þX%“?¹/%·YUwÞy§Nô¶·½ÍÕ,-RÅžþô§ûb¨ý+•2É9b¿VIxsÆûnªÎç<ç9iÒ2C;§\á‹/N~¯vˆT`+,³eLöDœC[! v·mGWÜJ„°€Ö&€þ¸6Qêƒ tH€Ao‡A[ÁdÓøæòM”Ff¤ª°¾ 2Óï$8úýoâbNwSµúÕ÷ÇNŸKeÌfWX橘¾‘y:©i‘NB-a6ç£Ò Z)ŒNO­odá¤Iv.?mӄ׳)Ó5+W®œ;w.– 銻+ÆC€@‚ú#Í€ ’nvÚ-/ `ú£/œI.1µÎ/™®Ä•ŒEFûi2éÏ Û'Hf Nge&SÉ ƒÛŸ7ᣠ – 9©3Véq*h¡ëŽÀ¤‰þØ]1€  ?‚¢ ƒ€ÍF >–H¥±ýäòpvH<ÝÒæ<º:vòp¨b*œpO•èìf•*ñg‰ÊQÎÁ ÷(˜›;I­þ(┽õGMD•l'Ýͧcú£‰qqº¥ŸŠ˜={výǸ†*ežKö<\d vsÉ–Å$]ñ–¼©€NIýñ”ô97 l£Ë{²?L˜°Ü¢Xû³Câ¹ õ½›à'mÙ©ã ¯À$S@L¡0MÄŸ/©¬+z-ErÝÚªZƒÞ*\Ã^ ?Æ—RV4\sùvi»K5(lR ‰Åù“=ƒ‹Q¶mOêAÞe‰syŽUù2{®³¦ÕáˆO ³Íz€ N  ?v8̆ 0&ÄÀ[Dœ åöLj—f ªZ¬?ÚþmRœV’•/«â´nmU§fÐ[…k˜Â&«ùë?ú:`Ð •šgZa°M‰6—Ð'uI÷¥]ø~òrp:S÷ôåÜšÙ¶Thù˜é¤Ëɰ–þ8'ÔÓêp$ àKÙæ =@€@§Ð; fC“@:ñ'þU~—,鑆(ËôG› ™Øw"­êp_¸œŒ™Ê¸Éã§ÕµBGŸ›o¾Yój;úÜ}÷Ý—[ú<úè£j–ÏëüÖn Ò]böG,óY%~±ÉµædµÉkÓ/l¹Ìn‘„ø’´~Àlˆ·çÎ :ý¶›MzÑÉ­õÇ`Sš1»{¼ò8 2Û\Á@è”úc§Ãl@cHë&Iøº€}ciGþ ÍxE¹eú£ 4úLîná¦c;åEçµÀ8aÔ4 (AZ™¾”¸£+;V'j;B°5èmIËÛrï½÷v$>ÊTµ¦äÝ{î¹ÇäÅDþ£]Yj½úÃö•¶¶ê7H§Qú[]» Á/™ÐÓù˺v|Í1ÖuËÍtJ¢¹¥Ø~›ñí{ê@¥¯Äµò­ã¬+¡©v~ß}÷å/ΖJ<öØcGè?W9…Iè«À¤@húcƒAÁ$@û%Ö'UE‰q¶£Uås\¬?Zî•$‰`}:U.{ÜÖ·&¾X :íJ¡¿­LœVfrŒ~5æj;Nk`Ð{ÎM%+«‚š5ìàÊÊVâ\^¬?ª›÷mKÁNêv©î‚uç-ÑÔV}u_ú¸ýñüùóMÉèYc®»î:5€¾>Mõ@X‹úãZ$©€V à¬üé\½¦3º©& 8I—Eb…b±þ¨³»|¨xóë¹ÓÁäÍ@yq)W“©dsËØ­Àw¾ ôÇMñ¶YyVV‹5ÓýôÆl%%úc išÈèi+!è£Lä„þhç²’î\ ?ú8§?Ú‹“ÉëÚú– 0ÈÙ¥ÚlTXµ˜€Ú6ù‹éq  ´Oý±ýa! °é“þ'‘ÆhsœŽ%<šâ`bA0ôýQuºæT³¿À\áŠþ„Jga¼P]am[4ôÇ-¨6^gVV‹µxEÔl%BÕúñkÆØ4ðÄ’¬:‰z.ay™þè¯öPèãœþh‡Ú–¹½wпvV7ÏÄGMÁ¦+^-B€@#Ð f@€À7¤óUÀ¦aš² ¡»“!l¾¤iަÓ¥Ô-<:‹)¤N:L(†*¬bf¤åšæŽBä28&¬¬6)¨™ºç–[ÍV’Õãu]]Wа«ØŸ-3ü…_U>ž$®õT'í·M·×šíÜ Ò¢ã­½ÍÎ9¡ö˜mƒs“€uRôÇc’ç\€ pLèǤ͹ @ C`N%t‡ÙˆÝf2ª°Ó--˦fOŽÞWÑcucN14Fÿ·u!mM:ôG.€¦¸uL%wwYMê¦õ»l>W‰¿ÿŒþvÛU;—çdµÉ鯓¬Ùã+ƒö»Ð,;Ò-ËPB;¶ß’©õ‰5V]w9ëU‡}oŽèÿöOÿìÎNѳ_íe†>ñ²Ùn°Ä/ÊôBÀÑ{‰vB€Àè  q lE dàm³/MˆôSŸLݰåá⩎sÚ‡-Í6¹]¾‘“ú£%iúuNοŽ×ƒ#ÿq«†E½3¤µâ£þéôGiˆúg|uè(· «[™Ñ® ÷qÜ™ã]¡ì'ÿ¥‚+<ר…ìWî¶½ÖEgC,}&â?i¿m 厲•gãKÄžü5– MuŸISãÝ´h¼ÄGôÇck€ €þH€ †”è&@X¢“oº%™ÒLÉT1÷kàíäÜOWFƒÃ ¼é›îÔ“+»ÅZgᕞ=¹NÜÖAbÒßÖ„©?AÀtÃCYb0Áù ƒc]’£Ÿie& ÄGW›Ò-Qt®€½‰{°}¡ªFÄ⣠£+n$:˜@«@\)B€Àr%ú£Ïý9˜v>Ë¢š«Á²œlÞ¨)*o³¤ã}`œ¶íŒ‰þ!~ê¢QõëcùPAþ£Û»Æ)‰<Ǹ¶å4kŽdÐ[C‹²+°ÆÔÃôú+{rpu,þx0Â>*˜ÑûVB€À"è‹°q lC Dts!cÝÐƹD*©~&8ºåQ&\ѹ²‡Xn£Yn3U%£ØQö¥Í`Õ?KôǸ¶mH‡µ¢?‡3g™$`u¼"Á!¸¤ïX¦¡Úv°6¥ý³jÕ…C,)?v åg§ä1 œ?^»]Çg¤+>f8 “úã1is.@Ȱ™ŒYLñövHÉL+ÝAêƒò ó­T­¢¹““‡¨*«Ð·<ø2ðKÿŒ'wÛᓵe™X€Aï9ü@RÞ×]y@—˜½PÛ¶?‚O¼Bå.~x¼¬ÄáuRC_èŠûŠÖB€@9ôÇrV”„  K€Aﰡݽc´íÝ7žÐ\{жB€@ ôÇZ”…  J€Aï Å-6ô  ôD€®¸§ha+ Ô@¬¡EY@€À ôXÜB¤ ôD€®¸§ha+ Ô@¬¡EY@€À ôXÜB¤ ôD€®¸§ha+ Ô@¬¡EY@€À ôXÜB¤ ôD€®¸§ha+ Ô@¬¡EY@€À ôXÜzâìì è…]q/‘ÂN@¨%€þXKŒò€  0è0¨¸ôF€®¸·ˆa/ ”@,%E9@€ÀÀô\\ƒz!@WÜK¤°€j  ?Ö£< @`@ z *.A½ +î-bØ @¥ÐKIQ€ 00½wç®±þãÎ@_îÓ÷/¬… rèå¬( @–ƒÞaC»{ÇhÛ»o= ¹ö-l… è5´( @”ƒÞA‹[Oжi ¹v,L… *èU¸( @“ƒÞ1ãŠWO ?Òz"@WÜS´°€j ?ÖТ, @`P z ,n¡?Òz"@WÜS´°€j ?ÖТ, @`P z ,n¡?Òz"@WÜS´°€j ?ÖТ, @`P z ,n¡?Òz"@WÜS´°€j ?ÖТ, @`P z ,n¡?Òz"@WÜS´°€j ?ÖТ, @`P z ,n=qvvôB€®¸—Ha' Ô@¬%Fy@€À€ôT\‚z#@WÜ[İ€J  ?–’¢ @`` z.®A½ +î%RØ @µÐk‰Q€ 0 ½— ÞÐ÷1ì… R襤(@˜ƒÞƒ»s×Xÿqç  /÷éŠûŠÖB€@9ôÇrV”„  K€Aﰡݽc´íÝ7žÐ\{жB€@ ôÇZ”…  J€Aï Å­'hÛ4‚ŽÐ\; ¦B€@ôÇ*\† ŒI€Aï˜qÅ«'Ði= +î)ZØ @5ÐkhQ€ 0(½ƒ·Ði= +î)ZØ @5ÐkhQ€ 0(½ƒ·Ði= +î)ZØ @5ÐkhQ€ 0(½ƒ·Ði= +î)ZØ @5ÐkhQ€ 0(½ƒ·Ði= +î)ZØ @5ÐkhQ€ 0(½ƒ·ž8;;ƒz!@WÜK¤°€j  ?Ö£< @`@ z *.A½ +î-bØ @¥ÐKIQ€ 00½× ^Ð÷)ì„ ZèµÄ(@ƒÞƒŠK€@oèŠ{‹öB€@)ôÇRR”ƒ  L€AïÀÁݹk¬ÿ¸óЗûtÅ}Å k!@ œúc9+JB€†%À wØÐîÞ1Úöî›@Oh®=E [!@ †úc -ÊB€%À wÐÀâ к➢…­€ PCý±†e!@ƒ`Ð;h`q è‰]qOÑÂV@¨!€þXC‹²€  <öØc×]w݈žá ž ?ö-l… è5´( @‘À£>zýõ×è>Aè‰úcOÑÂV@¨!€þXC‹²€   ?vÕç<ç9.\èÔxÌÀÕ«WŸúÔ§ÞrË-ã¹v4ІšA€À‘  ?8§ƒ 4Gýñ<ôÐC<ðÀ#‰Å4m{%ËáCŸ iM1«¡^h{+†þ¸·ˆã/ ý@ÜO¬ñ€ 0M@ú㳞õ¬óçÏ'vj†]L@¸l:°Í¤yt’Pœ"ç'ˆúcI"›é;A¡}iÆøg¶)›Nûsym¦f:µ¨jeɬ6@+ñ.-¥™›Aþc¼ÿL àº,ÈË3ªþžB‹ÁžD ñA™=þGñš[ ¡?úúø=÷ܣŸ”@ä^@£@5²ø@(% ýñßþÛ«q/ŸBwÜq‡ƒ+ÕÆ©~fŸ¯£»Ðø ,.Öƒù­&Ìé¤~v›¯.ù:£éq®ßÔª•%¯?¨cÉL¾LfZꥥ|V}&Ó}¥~1Ø“è‰iÑf‰¹’ȃ-×c)9Ó©Ûê[.ó©!€þXuyR€:"€þØQ°0€ ° iÿñ?þGöœ9®Ë’sùb¾¨ç¯êhÚŸK  ôG“ÉÒó¯ƒ@3;;ÿZeœIfÛ+ÙNjù›¾mÙškõÇ`õÆIà&{Mî®ò“ó¯mN± Å»?»SL&–D¼ÄÇe`WÔKK³Ž´•ù5™™ÈŒ~K8SÆ ?Ò @`Tè£F¿ @¥lýÇ+W® A–"›*—ÞgÙIT¦ò¸u÷ý±d#ãÉõõJôG§3º5 Í“#uj›¬Ï˜“ÌøôzŽ>*;‘?y9™^#2Ú²šZ ?&²ÿæB_rŠe`öän<µëTš°›ÞØ'ëH\ÀeDÆp²ë?ë“reíêXôÇ]…g!ìŠúã®Â³€ nÿ$ÈCÚG ÆëºUÝÔT;W ?šØ§²ÏæŒ™KôG§36èDöŒœÌw›3)Þ;; ЪJ$*&4Êx;欦výqXëšr?ã¥ÁÚðI°.{1Ëj²@ÐŒYý1-†fÛÉn  ?î6ô8@`xèÇ!@NT9$È’æ"q0Nú ĸ@¸qbS0½:ÐuvË£Tm©üD7/;V…JôG§3êð ÐŒ×ÿ'ÓÖÌÈ`GcKÕL'3Æ0M‡Õ¹ü—G•;“,É18Êë(}ﯽ˜ÕÔJôG(±Ysá)Œ^-XKœô·Pw /Önå¸t-STe¼%³ŽL˜KGMèVOz ’«lŸeÐ÷w¼† °è{ˆ2>B€R|ý ²¤­¸Í^¤¦ImÑÇ$3?ç+–MXÔ÷þ)býQ¿Zm*iõ[Z¢¯éTíãŸÎjö´_ÍŒÄ^g’i”fϲ9¶&iÙá®6Uè7Ës4®Œý3M³šZ‰þ8—âç“ÉNÜ^ Öµ 3ÃÜ,ŸÒî×µª¬¶`¥Q÷“ûà …“0m’x¬2'ôÇ`·¥’ Š2Žú#€F%€þ8jdñ € PJ Б KÀYf™Œbi,Vµ$*éË ÕÎÏP ´$¿~É=¾&e¹‡A ¡Ê$òø¬r¨b±œ¤\9Sú&7ñ5«T2+É%0ÊÛܪ’ÀŸ×LueäZ¼)$K•)IµÓ±s%͆9k OqXÅQ,.¢šA¶eÊMÕ z¬ª€˜iåÁÇ•±cýFåØ8Öòw®Ä-?k6Ði€ 0<ôÇáCŒƒ€ XD‚,l4’Š”¬wˆ`”>‘Õ—±ÙÜYµ±Ð‹=³¤¿XtÛ3“C|·•(Yüq1Cò£ã@@hœúcãÂ<@€Àæ&õG“ ÏŸ?¿ùé9Á"–?¸èPúWbˆX¶bƒ°­Õ·SäW4µÍªÐÛŒ VA€ÀáÐgH € ¾ Ìé}{5ºõ¶0ß²…·`#áÉ­Õ8ùG<{z 3ªê´iàU‡¿p¼bcðÍñMJœ‘´ÜÃþx @‡ f  ?6 ƒ ‰úã‘@¯}­ÁW»KòÚ&ük}=êÛÑX±æÉEý/W<×áUM.pxµû©ýq?±ÆS@{#€þ¸·ˆã/ @ $€þH›€ ÐôÇ¢€ € °ôÇ-¨R' ì…€m²é$G@‰þxÈœ€@–úc @ Sè³!ì‹€d>íá•Ó´Óü· @´Ÿ>ú£ý…äæ ¡?¶Ðœ°a#wÜqÇF5S-V'€þ¸:R*„ F ?6Ì€ YÚ#Âd>ý_¤ûû´[¬jµ;™¤ÿ[þ£ûgDì1jØ\Hý±ÅZ €þØB°€¶ €þ¸Uê„ Õh{ SµÛ¯«TKˆ<íF¶­ï§É£«y~ĊЛSA˜%€þH〠Q  ?ŽYü‚ 0)zÒ}ñ1á˜ɇz(ëù*Âe ?ÊBÙÙélôÇl›¡ #@<dN@'!€þxìœ€Š”‹zšþì/ŨÅ"ýÜrË-úõêÕ«®˜þéÊèûÉÔE[ÞqÎPý*ÁQsÃU@‚¦É‘%êg‘çÇ-„þx\Þœ €À4ôGZ ŒJýqÔÈâ H7”Ƨÿ§±Ii‹Ò+%š2¨º£L´ík´w>vˆ«ÙñÕC-.™ÞRF…Ms”Ži•¯’Vy’°¡?ž{w'ÕEÑ©ÂÞê î·ÚHƒÕ¢?6L‚ U ?®‚‘J @`¦¦ÇÌ“¥è´+ã/Îhò¢Ko”j©~Ö¤4J—Þ8ç›í9¨šu:åTnBd›JÑ·á:Z­º^|Y4÷zöÇ^±¤Õau¤Ù>­gÙ®[Ìämý±³@b. @,FEA@8:ýÑvÄL3õÐ¥7šþè˜F¬ç8Y­K™t©—î§És\Ý Ñëx±´Ê­}ºZ¸Y¡ šüïÕ %:Tº’ æàŸ®*Óèý•Xm‚xÍSK vš&¹O6©ÙgÛ¯“Êq¿Œ4½«ÊØu¿Òµ±ÍVz†#¶…Ô© »ËoÄæ›qåÊ•sçÎÅ$úãÎîC˜úãÀÁÅ5@Ý(Ù|Ææ>®Z¦ËÕšœ+ÛÑ%-™ÑäÓ;©^þâY(4ôǦÂác-Ù¹ÿq꛵7¿€ýÓ—çÒ•¨1»šu ©êî£kÁì‰y+¬O 5Úé|…Ñ®5Õ /õ±Ë§|.°³ß7K‚SX™„¸æÐÉS'–zȾŠh¡ñÝŽ)­A\d§½˜a} !“ “$úã\tÔoT½·h$ʘ@Žú#€Ú%`ƒê`3™ÀÜÅúc0b·½nLs´Ÿæ6ÝÖè=P:| ² µ"`ˆþØì5P"«Jœ%*úJ\¶çþ\ë5E>¸íÒ ‡UU¬?Æetq•¯QÛïv|r–§}´F]×Á[wø`úcóÔú®tÚìµ0¤a±Ù…þ¨A×þ‘Òä½~ÈVS€F%€þ8jdñ €ÀLÔ¨#áL,m¨°I0Uó¯u”«j²Î@é†^&AÆ[ßtôÇfÔ•'…³ g+Éê–7(ò&ÄâW¬××Òž´?JÓ>ÊHKäœKO^Q”¿–`¨ÿ«Ú ÙPÿ´-°&“íWu_.íÔXŹ¢î,VÀ÷K?¹mu`plºs« å'H]èå]Êá|\ è+¤*@'!€þx윀J ˜®O$tùS&ùÊH°ŸuœG©Ü«xnÅLjIdvÌ ½ì¤“«Ë•z{¢rè'Ÿ?mvœýÑòQÌÉv)¹_çòË'\\&!,ÓX ?ÚÔuS'¥Ír—míœuˆpÞdˆùÕ÷Ë*÷?þ¬Õ´ó×Iç%| ýq.˜è7ṡ ðú#€š&`-m¬.‘QÿÔÿm­F“3\ޤ-x'Ä~õw¢°Á¹U¢6w,˜µjÇ:i ½Dš›pí¤Wºcõ‡Ô‡¦±~«qèÍkþhº¿zi¶çþœ85ù½“Lksgœ[ÿÑ×Ôª€ÇöÇ/ }<Žþh]–Î%«\W` ݺœÖM9eÐ-xççßÖõ«½‰ ®úý´ <… 0ôÇ1∀Æ'`+£YJѤ·Ò>ôëäÂj~ÊU2—Þd!¥±:“tê`jêÜúnmÆIúã5×\£q/Ÿ¦ÜqÇ&«™fç>þÞÖÖ¶mdnÂw£?ÆË4ú£[ÂÕ–µµ¬môÇ‘6¾@ˆ  ?Ò* @{'€þØl ˜Ü:FÃu§èMê–èö8ÎV’Õ­Â@S˜œ#iöøùzöôl3 }ãæÛoj…êñw´°oì,îc5Û®SNæ öOÿ¼NÔ“BçžÜx'ÎÍ24ÁE•ÛükN;‰P¿ºŸŒ˜ŸŒiÄd¶ ¹e"ú£Œ1 Zg ÔÒ¹)öÍ^cˆÃèÁÅå¤EÓÚ°¿ »/ ÛkŒô†Wc· ¼ƒ 0*ôÇQ#‹_€ R襤Ž^ÎÏ(4EÉ>nx¯1¼ÿO3ЖbtÚV¶ç–™TÖlM·@SðOáƒ1…ËÜš†&ª@¹ø¨š'íWþs>šaæWü òe•› j¦.˜‘=ÇÐdS­rÓÍB±õ Î+½ÒäK}ô‡ÂœÅ÷bÕlúgщŒÿÑ2'œ ‹*ÔûüëÉe”­ñÕö Ÿ ÞpØÕá#3’¦Ë…@ kè]‡ã!@+@\âèU®[I˜@ÖÅæò²sn)K“ôÕÕÚÈ[þãäQ†h®BýZ»@DPÛáÆ×:Kù9“âcwú£5f÷1g-=Ù½!¬oR¸ËÚòøîš«KVw¡©“è\M€z'€þØ{±€ p(ôÇC îàxËÝëB=Ü4ÊÀš\WqÓ“®Uy"7s­SPO!óçÏk·ë¸pù–ä|üŒE·B‚KÂõSžÕX>¯å9êo[ÎÕ—Ëý,‡÷ðW …¡¡ lDýq#°T @è†úc7¡:¡¦8Ä˺b‘RÀ‚僒fxˆasÇšÒ¯;7£| VÔ¹Œ@ú£\ 2ã¬^õ¶îêÜfëúÞÿ5Îüµn‚ù¿ËBÀQ€ °ôÇÀR- @ è݄꤆jääzˆ‹²u*Ÿ~3 3Ùî@©9J4ëW<ÝŽLS5÷¢?6 c @  è]„ #!@@Ü.UC(&€þXŒŠ‚€ ÐôÇΆ¹€vN@S´”-uÂY™‰Ý!ú úc¿±Ãr@`$è#E_ @À'€þH{€ ­h¶æê ÆKþ[}ºrÿmSÎu—À+?ûv%Ñ·cKÍ''pÇwœÜ €@!ôÇBPƒ î ?v2 † Ð ÛøR­ò¶ÀheÛbúÇMÔyuöÀríà›´À5;DkÛ­»šÞbKУãÀö œµo$BÀ ?Ò @`Tè£F¿ œ˜€ö¬”ò¨Hý™Ê6)5M´TÇMg[¯žº8äè‹Ñq    ?®“ª @ )èM…c ŒC@É}Ò×ämn;K{J6tù†úÃ)˜*é ûú£ÊH%Ô¦®sÔôÓd«W¯º ­Lç¨_M9• þÙu¢IER_ª’ÉŸ¬~Õão;k˜þhõ›ÒêŸ:d®ÎÕ[ úãêH©€Àè  q tAý±‹0a$ ÎH>“¸fi&ä*áäBŠãœRéænÛ n·ê¢éªSú¦þ°b:0$ñÎtO+ ÿûâ Înßè@W¿KÒ”ñîK÷‡g_Ú‰œ%úÛI™¶ü¥oƒ¾1;u®àrǹ _ýcïVo è«#¥B@  ?.€Æ!€ ÐôÇ.„‘€:# Åæ(=NûúšœÉêéüGË”¦)­Ð´<Š·Vi´o”f¨s©Xƒig7…Ô’.Mˆ”˜h çòýQZÍ:£HnºÝiô½þ¶ÄFw S'ù&׺JŒd@oõÖ€þ¸:R*l‡ë?¶ ,É@Ì"¢ tJý±ÓÀa6 ¦ ø™Œ24ÿJôG}%Î)ƒqÂcPpvhS¹ÝV6¦?ú’¥¤Ãà›Éõ“Lú R;MôŒ?¦$:‰Ó°¹–7¨v–e{ø¶ôÇBPë‘‚NQÛ­Í4×݆Ç! Oýqøã  c°„G_Ýsk):S²ùiýÑ¥Z…¾àh^ ë¹YÛV~R[ Ž*Ñc]5Á:–Sc;M' ¼3KË\`ôÇÃRC³tš †Åh®´ @•ú㨑Å/@'#`j£Òýlg}LVóÓú¶ÓMæ³éÕþÇ7`Eý1½8£NdÚ¨[Ò×cýÑM wÉ›[Äýq ªÔÙF%h®%”(@=@ì1jØ @ iÒÎâý[Lt»BkC<dNq*« :§r„óîÀêÍÕÞJŒó?¦-ÆK£a;D¿ÀMÊtïçôÇÉ{w6v:Ê™ª{´Íð'.Ø?GüyA«Íl»À¹ýäþ¹õ&oY÷)@`Ð÷e|„ p<“[²èôÁ²Œ6>ñ׈´9Ú¾œge‚QÁäÀ&Øp&#ÅΗëAÇäþ3~¹iãºxÑÆX‘Œo“‹W!xèG€Ì)NE`uAçTŽpÞ=X½¹Î©„‚9y“µ—ˆÁíØé’þ=z]ýÑäB‹6TƸ瓳âö@â?i¸&¯²‡Ö…€NKýñ´ü9; Ñ$†:66pû8» ‹‹/Ú !>־рDsã¥tâ¤JZm:ÊÒ0-“Â[JôGÛEGGiü£ò–ñè6ŸËòDô“Mþ2Ûlg‡ë'›S¤|JZµoìÖ,!ŨŸ¬ÚM úã¦x©ü´VtNëg›ÀêÍ5qSÉøW»ãįñìöç'E®¨?ÚMyR(tá^ ?šÍ“ˤ ?Ž}á Ð&ôÇ6ã‚U€º$`ó§âI[æŒ-å„6¶á„“ÛlÍ)ßs ˆn •¥EØ)ý1>P¤ Ÿ\G°û~Š× r-h¨ÂN În'JœÅMòŠ-wò¥êôÇ]òηñW±7^¶H°ºbð‚puý1 vþhS+‚9Ývò7mÆT@`’ú# € °wè{oø´A`#ýÑvtqçk°è°­b«òb GÆ\µûÏ$fIû11ýѬrŸ sÓ¦SØÇʳ%\…èm´w¬€öEýq_ñÆ[@€@Lý‘V@ [è±lèz.±Ñ_nØ’Mà3]2H$\+ÿ±J”…“BªŒ4Ò‰é%Ñ[híØìúãÞ"Ž¿€ ú#mb`¬ÿ8ppÇsm ý1˜7@³MÏ,çÑÄ;+`š£åš.¬²–þh»½¥tòbùþצŸ’ÿ8Þ5‚G€@¿Ðû–C€Ö!€þ¸Gji’Àê‚N“^bÔ Vo®s*¡ãå6¶¶¹Ø¾`ç’}]Ò¸–þ¨ ­ªu÷Ÿ¹zõjÂwò¹`pèŠúcWáÂX@€ÀÐ7€J•­X]ÐiÅ1ì‘ÀêÍ5«?šü'…Ñö¢ñ mEå'êÿJ xÛ¯±hh •“»¾ÌE̶ážËU´£ØfÄöŽO€À¾ ?î+Þx @ˆ <üðÃ7Üpd 0$Õ!)áT#Vo®%ú£ä?³ÿû$Ú*Š.ie´kv¼Æ¢äË’3´m®·´iàî#éÓéž ôG›Ùíf”û5“ÿØHƒÇ @`WÐwnœ… L¸|ùò¹sç@@§%pýÑ2c©Îô»ÄâŒnËÛÆ–‰¬M~4à¦uê#Ôjsª¨°sûÏø)““¥}éo“mµ¡?ž¶sv@`ŸÐ÷w¼† ü+ôGZ œD´•õQJcÁ¾—8GÙ‘¦9šL)½ïâÅ‹ËHê@›ÓmUé£ÊµŒ£Õf'Š?î\¦WÔÈ#}ÏìN;µÌ~Ž‚ 4ôGZ @`ïÐ÷ÞðhƒÀêúãqÜR‚abgêZTUz/šÚ )@-@l! Ø@8%ôÇSÒçÜ€¾I Sý‘B€²Ð³ˆ(@œúcÖF U;Ìöè#6wJ@Ó]'7ýèÔcš=˜þ¨nÊsœûÎ5ç‚ #@<2pN@`×4©*øØÒNúÿÜÔ­Ä÷n~–þ˜+¦Ia‹§qÙ„²É‰`±#Áòö®@¼ì½üO—ߺѠ?BØbwH ‰c•Ûâh%ç›™˜2©EÓÜ…“°A?M¶ð«¤;$.ÛÄ…ï~J\G®LÂG•qKË•–\ÉN£™ÛÄéqöú4h4ÖÓ›&ÙÄí Lºéš°îÏ·óƉœ±¸¹zþ£syR¶œîôÇX¥5×l¹‰@cµð¹f¶¢þX2©|™þ8×,Óúã\RjÉ%¶Û2è» =ŽCžúãð!ÆA@­ÈÊv±c¹3Á Ö”FöZú£›|Ff§“®/6göHô±o&×l!EÈå?">–_-¶äŸÂ§ï©_ Šõ;%íÀIý1mƤ ˜ÖMwi•ÖÔMîŒ5£uõÇàýÁd~èêúc°ì¬·ð¥3ý(de;ËtÁB¬£&óIý¬ÀõGsjn½QsÇNgÑwŸ`3n›3ný›­97“ºDL‹éåWÜNJ¢?î$и @`‡Ðwt\† p6ˆµ ‰îȈ.-ÈôSÿb5d-ý1+1øòâ7Öuó>þÌD³ÇìÔǼžÚÑk/ ·³Óò\ ¾þçúp~(lsúc|}ùÒ”SÇdpM7ÈuõG—×l¬&g²¯®?W«ûg­þè_×–@áõ÷#òKZˆýó®¨?fßñ8ý1pÄOÍ6{üìŸë¾Òú£¿-Ï=÷Ü£ý¬ød  ?ÖöÔ‡ ^ ?ö)ì„ Ð=¬þhCYèš>bê¤ ìm7«ÑÇqý1›ÿh)W6Ÿœym.´£?^{íµúòɸãŽ;\óSã´›ö7©?Û» qËôGÿ\®!¥õG_gôÕ1»ÖLë7í)^nÕ½ð¯»Bµ4蹂?™t¼ºþ\­²ÜÞjÔꉴA»–(ßM?eÛz9ÿ½ËêúcIþcÜ~\˜œ=–ÿhÆÏ-HšÖý_}ôQåYóÉ@ìþY @`†ú#M€ŽD ››ãë2¾>â‹t¦•ìµôǪù×ñV Žc` Âçðíè>ø rsüñ#5ˆNã¦Ø»Ý~ƒ•øüYÆÁ~(l“mf.KÑa¶LCÓ㓚D«c¬v þhׯÎåOþµáò&ÅÐxÚ¸™:×9”,•Xë¬)ÑrÄŸÞ®J|…7¶sEý±Ä©¬j0¿ë Ìu†ñ®b]ô[¹‚þ¸Yê… S@¬ðÝ}8qCÈÊvòÞäÅ‹/“@M¾Ñ¨>Ðn ØärúÞT—’VB7=ÙÐjÈ:Hä%5¥?Ê»»ï¾;˜~[Â2"àKcqÄí×XQ €µÀô¼àI nN˜óCceuLl2²d¦XÓ¯&êª ¢츒msB› Œ·+:¾r­g˜T<[Ðο&1óÌþ8‘ÐÜ÷R÷Óf³x­€ê™ËU´úè®ÓósTítYýQöZN1#€þHK€ Q  ?öY=¼Z6­9e{~ÕSozéŸ^}Æn@ sYÙNþ™2b%ý±®MͶïcuÌÍZõ{? ³­W¬z7cUÅNêò1³ŽÄój[Ó9+²óæ¶­ùj¨A»2ÉÌIc±þhÂb¬ ÀrÍb I§ó[`,ë”è¦ÆRtn÷d—þæ»lbe•ºäOŸÚ*÷¯hÝ®¬É‡œÃõG[Êsî *+Û™GfF|Qyß!ŸÀä †+±tìd·.4èÁlkµ³ŽL°jcå7­?Ö¶m/ÚNjGì$P˜ @ÕЫ‘ü=ÚówúSûÀzr¿0ž@V¶3&ÿMÊ+öý¤žèFÝ:‹}¬žÉ5ËÒ¨MX±sùU¹±·9âNdø½î¤§sâNƒú£øh¶æbß&;h Ì­cè´E×8cýÑ ‹AZ_Ü\cvõ›nå.Š`GxwádÕ@gƒì|Ÿ»î¬˜sÐ5{»@ª¦Ö&²ùbyË’ý -}E®?¦OÌÊvÊB¿À°ÃÍÉVgFÐçÌN·[‡ÎÚŒÃhotœ%îWûÃõ`sžNЉ ý1Øviñµ¶·Ñ÷qü… °èÅÚÒyrÚã¿ü^¾«cg0è“€FæNÇ3øo¤t¨X<õÒO¼\±ô%7¨N¤2eùIE²Ó¹‘¹¯cªw ÄÇÀ°IO5õRÅâäMÙYµ‚^ÖøÜúîXíB£½h´#Í‚Úöpˆš±? Áä¿m+Ðú2¸O p¾ôãÐYkqš þP#qâ¦ÉˆAå“òP Ù©š''SO^w¾IîúRIߞˆ§›º~ ®nñ´‰Ìî2LLïPÉÉÎa®Û‰¯G7 }Ò˾Ì^ª²Ù:‡ø5Éyw:µ×çèCžâtvÕf}©ê ¸é'ÿûÛoúgÜSÙQÁ$qÕi¹E3 ›ÅŒú#-€@ t'u÷ÊìÃôÇÎâˆz–ÕØ­ÿhO®N\öÚ¼3"˜ @ˆõGU)¡áÆo|ôÑG®~ä 켇s‹;[¢ÜvçÝaÍ“Bð9¬åòÜdóµêµôÇQ#‹_€@_,ÁrNC_Ž4e-úcSáÈã_‰I…–¤U[.ô[!@`U“ú£Î ñQY«žŠÊÖ!`‰Uk›®sâAkÑ#  ‡ÍÀH|ßT]–/X+öhxu"q‰`éFûç¦y¸µž¢çÖsåÑ£ã@ôEÀ_`¤ê…Û)QùFlù°]ÐÑ·`‹þ¸ÕMêô;õ5h‹›P¦R@`\¶|[â³çœqôǾZl;ÞõÇöÀä¢þ2ŽÁÊŒ§õHý-OªËB€þ¸ŒGA ;ñ¦…¢n±ÄžfÝÑhÐ`ôÇ-‚‚þ¸ÕMêô;õV›œƒJ!@`—Ðwvœ†š#€þØ\H0Û˜ÜT6±Íš³ýq›€„µ¢?nÁýq ª›Ôè+.ù¤ G¶'£›Îc;´ÖžB/ºýíb-É(]{™oÄCt/ùç ëûxG·…¨-ÕŸž]eûE(l“ŸM‚J¥€Ú €þØF°Ø;ôǽ·üß Iý±dZúãqÚúãœÑ· ºIÁüëU–|²ÕyܾNÁú©0 \Ê£íx3ù™[Ï¢*£³¤Ÿu{»üP-«;5[ƒ#áEãkWmÒì¨ØôÇ}Äy§^ÞqÇ;õ·;$€þØaÐ0K¸§å¹Ah6/§d\¼Ä ŽùVè[´ôÇ-¨nU§ß1¾ÐxB1ô58‰zi”˜í\Uq=[ë±ø(c&§®Ë§]Îéöýž·§ØªYS/ ÐôÇ‚€ [@ÜŠ,õn@ýq¨T  ¸´m˜5Ö£?'œè[pFÜ‚êVuú×€IiÙ×#s¦r›M1V_¦MÇöe¸D¸–¨;Õì&JÛDfW ÈÜTTæ¦;¯›W>©?‰¥–­)¿Œ†MÇö}\%ót«&B½€@\„ƒ ¬Lýqe TV øúc0 MϺC¶…àœ”¡¡º?ŸR‡d·“õ øàvÇ fF–xþ¸Å…‚þ¸ÕmëL,VX¢BúRVGóµÎøµ†ÿë‚YÉ[ë%Û‡ùÉÙ­±ƒ›Ä¶a¦v@G$€þxDØ}ŸjÅŒ‰¾Aôi½žå˜ÃÑxèÐæA`-ñÐ2Hœë®kõÇô&«&ÌI×Kç0ƽÆó2ƒ´MßNÓ Ò›.øƒqe%6«ÈŠZ¤®dw‡´\€þ¸VS÷ëAÜ‚ê1êôß6+0êBJ<\¦%ÅÀtÅ`æ²z(ÿ5Ÿ7Õåfö ÛË”Îr7ïü^lA’ùD@à8Ðù÷³XÎBööÚ»›Úoi,iãU »¯`§îwg¶ž«'§Ý ?vJ †À2±þ¨>ÁªÏ©låúcZï 4:‘Žãë²sRÝKë%›ÖÚæ“3>k¤?Á1H{ŒwšMÜÑ—5ìôQè[P=R¶´b<ÛòŸ'»ZÅÍ¿zƒ‹<;;;KaSý1½j¯Ùæ{—}dWyÿ•T:Y2ë; 4Eý±©pƸ9S6_É}\1›ä>úg|LT¢ÂAÍþ?ýûc piœ`%ãÝðtT0Ñ{;ûÒ>%36|ý6,o¬þô Bgsq3,þ^êû’çŠÓ¶"™Õíɇg˜ÓFÊÎ~åÊ•sçÎÅ$úc ÑÁ€:m7sÙ.XßlòŽV®?*¡î’º—ÙZŠúèï Ç0qõõGÿ(»õ¸çŸ[`§/ê®_ãmoU›¿ …þiÃêësëÈù^Û‘Îe¯Ní¤–¹{"úãWúãTZgB…Œ¯¥òÞÊ|H”÷Å8ˆrç7ÕK&ˆÕö)µåËQP€Ài  ?ž–úìö ìQ²?YÐ/`Cš@ŠJT¢Gs¿r{‹é¾q·x=èÒ•»-Ʋ— Eœ_îõ§t”‰‰Y±ÌÇböë@®JìŸ\h_Î=Hèq.“:ãœþh+ Ö™9r£ ÊÙÉw«&þÙ6N7I`R‚D¤µ@`'&õGùî«c“ÝuáˆÞ­ë.6÷ÍO*Š\,&ãù‘sú£ã¼ÅÀ‡Eg ä× /rî^fާ_s;ÐN69Æþ[\‰è[P=MñŒìø F|y»L„¹?\g19’±_—=”Ÿ\ ^ÝdQ¸Þp±Ë§iœ€@ŽúcŽÐ)OËj²,ÎÜÄ(ÿ5d¶ó0¡µYêÂÍíf< ú£• *qÖd‚rl¿ 0ü:Ó>%·˜}|®ÁôÇ Îß85õ”{÷çŽ%HôÇÝ7 ì…ÀœþL޳üJôG{eè>éþ@"˜Ì+ŒõÇl*½o§Y27i:^êqî e:×V²K¥•Ì EÜâRDÜ‚êÉꌗx^ øW‘ß%•ü=žþ8ù§úãÉš8'†¶!€þ¸ ×ujÍJ‡±pf·{_ÌV’ÕãŒE;‹M•ÒÇŸIˆ_6´(™š0‡,¶?–JÓ>:sÂÜŠú£óTóx„&b2fnâ˜ý°ÒP*MeüÙ¡¾±Ivþ±6ÎÌŽ×i»ÔR@ Ñ ˜Q#˜Óå›?J•¸ýÑO~,ÉyÏ&]ç’éþX¾bcbzD°KxVgL4?µhòùýq‹Ë ýq ª§¬3X¶Vו¿N| ?–dü¹2Až‚ßušÿè»P…B²úþ)[9ç†Ö&€þ¸6Ñ5ëËJ‡GÐmÓ¹`ð`zj·?ü_'ó³V&¨Å,Cdƺµþh#.Ɉî1×#Ýó†Ê˜>è¼¶µùÝÇ€Å!ŽåW§?ÆKïû‰«v`ÉÐqÍFL]I¾‰þHcÀN$ôÇ {1xcT¢?úâZÉ '?Ò¿e¸X¤%ÑÉ•Ov 6¶M«ŠYݰ°ýø¡?B;¼úãá ›«!xîô/'_L¼X(qi0ýq™„ZŠ2€Ú'€þØrŒjõG½!3‰ÍU–­ÄÌÍ¿¶±Pp¯tú£ Îh|.aAYË^àöâãqôGSÅMOe–ª÷¸¦ÒÚ?]Þ¨k{vˆý*}‰°J´8Îå?ê×8•µåö¿Ûœ‰þ¸“ˆã&ú£à …ù¸²úc ç• öÑ­*Vý±áò)Y;}ÃÒ4ü’YݰÄ_{nqÑ ¡^ ýñp†-Öà¿ðG ¾4‰þxø:-Æ› Ô@¬gv¼#ì9ÈÓ÷ÇvÓW1ûXÉÉY ‰JÌŸ9ýÑ¤Æ ‡Â×íÃMòŠ5>·DŒlP±Ú9S“{ 5Ö£éÁÖÆñy š-Ë%Á1‘–X«?ÚÈj2‡ÅôǹŸŽ×¬9SDÀ$HôGšvB ­¸ý}V×[6äOçfÕº8jY;ÑwÒÔ}7ÑÇ úœþXžå¢×òîAÉ¢q…%˾º£Jú¯ÚnqÅlÐ,. @h™€é6ôåÓ;î¸Ãîn¶õ³ûÄOí¾øO¶ÊVR¢? ¾þ¨Ã-YÖ5œ¿l¯m“SKf„97ûm•@°kJ rEí™'xõL…6YpËFú£ZWS­cŒ@Ë7 lƒÖ"ÍøóseTØÍÈŽ‹— r}!Þ¯¦v -JY; ?ê™DOîÕ¬ÿÖßõüǵZu¶ôÇ,¢. $^_ø?Õfø,ü÷*‹ß¢g»]wF›µdŸ¹ÌÍÚnqE5¶ËV‚Ñ€¾I€üÇ–ÛBVVóÅ)›˜ìtÀ@¿›|Âö}Oç?¦õG›£m¯$ÉwúÕ­3UþCpÛ|»J² ÌÓãä?ú£{äRPý¤Q•±ç"ý?8|#ý±åf¿CÛÔ¤ÉÜaÜqy·²á`_·†rV×[¦?úCéxi²ÚöÉõG‰¾Í¾Úÿþx´Ëýñh¨w¢@ Zò¯ÃCV‚r«² _ ÛÒ:/¿äZú£jö«]æÂñâÊ™ lFýq3´+Tœ•ÕqÊש?ê\–¬aýéw“6‹¢|ñåI6Äò7¶Ö?³ë õGZ柠‰¸!“ÿ´ƒþ¸Â…Ôv&>j 6ùm ë °¬þ¨3ùJ¢KDL¯ÛèžF|1xùç‹sOì½Z[÷*BÜ‚ê&uê1´dÕöà=I<3:P'³é g|)sN´ÃmÕ§¹é`Ö5ÌMâÄÇóƒ¾)íÂ&A¥R@m@l#ÓVÔêªÅ$¶÷Ÿ ”>34˜­oÜ,ã¬þ8Yaö‘c2s-ý1†fö˜TZþ’r2‡trþuÂ_SrÝ ¸XŒw æw'B”l¹ñïÄ6'>Ê_ôÇ7!P¢?Ú Ýéh–<´‘þ˜˜@˜Q( díôÛ@!KüyëB§Næ9e3:Ñ·¸HÑ· ºInJŽ.¡¹ùJº´‚4ãìŦjÓ=ˆíÀèoÂèÜ 6ÚÖ©ƒ¥ÖÝøÄŒÓÜ ,ëUã•&lwÈ GzÅüÇ ‹sÎç²ìÿÂ=¿6iT @`è@]­Êú£Ý^ý{w¶3wnþõä÷±þ¨ì¹?¿âû»Ë”,Ä4i¿}¹ÖükƒL ±— A.§™›s çôÍI¼ëæžûfÄú£Ç¥V - ÅðÅGU‚þ¸˜$B /…Š[<¤[^V×ó‡Øé¹“ àd>`V­‹ágíœ<{Öà´%ÁFÞ‰w‡Yз¸ Ð· ºI §KÑÊc0ððm²‡Z÷QUöZÀ=ÁëÙTý….9{ÞM¤Úbó~U²JUép[íÕ7{òa=ðKª›Ðáú¿_¹,q®¨? ‹ß³È+\Úˆ°¾”ÏÛ¤)P) µ  ?®MtÍúìöÜôá)~^T³l%iýQ¿ÆIs“ú£›‡á›dÆ8ìþ^5í °ß=`ørá¤îE¬ÛºÇŒ±¨ՠÿÛ¯î,“Ï= Ìé¶’µNmÏ9îAË^»™"öŽ6˜Ô—:V› Á›Ý @NNU…¾'N®ÙX©«’@ >¢?Vò£8:&P¨?ÊC˜oSݱ“wR_øËÊyþÝßõ“‡dÕºFôGÜôZsYз¸ºÐ· ºIþµäNþ3}½©‹¾€èjýjƒ„X÷œ´GÕN¦mÎYŸ}#ýQÑ ’´]Ï;‰"xÜß$ØT @à¸ÐË»îlºIÙý(ø¸Z©Ñ¾·¢Ý‡l%nbÚ\lbÒ¨&„ų(tgL’ôæÞhÚØ¦vêØ~ã|;'}t¾L2ŒGYV‰{ÐYâI6&™Ëª°”ÉI†1·øŒt(·©·IÁyªÊí]opý3XÊfòÁÉž' gÏÕµTJWˆÅGU@þc%EŠC Wåúc<äOœ¤»Êw+œ/5L®Š–UëÑ};Ó9CYз¸´Ð· ºUºü®dN…T™x¢SlS*ýQN®V¾HÚäK·ƒ`"ãÜ>«½èÁÞ;ñXÞV; f=¢?íÚD<jN@h”úc£iÌ,½#L/¨²À^·›ŠÍ6ˆ?%KÊ,8ï>Ñ «_ñt'!CÜI qµú£ÍB„³„þ§LÚ$÷ª/˜}¨š ƒ½èjWÁDFÛZÖ>þî¸~1ôÇ£]èGC͉ @@l40˜ìŒúãÎŽ»û%P«?Š”?#Ø„ÈôbÄ’Õ&gmOîy~;Õ‘þX¸½­_ ýñh×!úãÑPs"@€@£Ð fA;#€þ¸³€ãî~ ,Ð+˜;<¹WµÏ4ža‹Òç¦]»ª:Òe³Ü™^ÝJÖÒ ôÇ£]‡èGC͉ @@l40˜ìŒúãÎŽ»û% ÕE¤jÊsí2#JÜss¨ ñi.¶qû¬ºíUË7›•¢§Â28½•M` ÛºY}S„B…³4Ìù’µÄßZÖ¶¨Õþ ÈfÞ\=Í ° maKËCÌ"¢ @`pèƒ÷ N ?v(Ì„ jèÕÈ8€ 0ôÇÁŠ;€@§Ð; fC€@–úc @ƒ@<Àûvïììlßð¾'è=E [!@ †úc -ÊB€F$€þ8bTñé_ èÐ:"@sí(X˜ @UЫpQ€ 0 ôǃŠKß$€ C[èˆÍµ£`a* T@¬ÂEa@€À€Ð *.¡?Ò:$€þØaÐ0€Š ?a¢ @``è×th ¹v,L… *èU¸( @úã€AÅ¥o@С-tD€æÚQ°0€ª ?Vá¢0 @`@è—Ði@ì0h˜ @EЋ0Q€ 00ôǃ‹k:´ŽÐ\; ¦B€@ôÇ*\†  HýqÀ âÒ7 œ½@ì%RØ @µÐk‰Q€ 0ôÇÑ"Š?€@ŸÐûŒVC€@žúcž% @c@;¾xôBý±—Ha' Ô@¬%Fy@€ÀhÐG‹(þ@}@ì3nX @yèyF”€ ŒMýqìøîÜ;ÖÜyèË}ôǾⅵ€ PNý±œ%!@c@3®xõ$BGh® S!@ Šúc. C€$€þ8`Pqé›th  ¹v,L… *èU¸( @À½÷Þ{óÍ7è.A€üGÚ@Wл ÆB€@ôÇ X…  IàÒ¥K·Þzë®áth ¹v,L… *èU¸( @úã€AÅ¥o@С-tD€æÚQ°0€ª ?Vá¢0 @`@è—Ði@ì0h˜ @EЋ0Q¨}OúÓŸúäGní‹_übWÛ#µé~vÔ‚ TxŒë*†ëÖv÷G:úcÇÑ ÖdÌf2‹?šþX2™ZåŠ/6"Žþ¸Xª…ö@ýqQÞ­:» }ŽÓ\{Œ6C`uËfúùIå+­Éxin¼¯™Î«»s`…ë*†ëÖv k{;ý±ïˆWuLÁâÖÅ”tL~GVµ×ö1á¢?“6ç‚#€þ8X@qÇ'€ C{èˆÍµ£`a*¶#àÏÆ+I2K‚Ɏ幓þ…Klç{\óºŠáºµ“ÃçBì;ˆ~Ç$•0íŒ+¬þÅïb²SUáSE<yÎ  @ýq€ âÂÚFGh® S!°?s¨$aH–ûÓ*Ó¨0sÈ×ã ϵã“5¯«®[Û‘Qô~:ôǾ#¨ìh—)í,œB'¥²<¥ÑïȲ§p4õÚDýÎ"ÑSu úgù:“«]ÈY½üQmª*~-S«?Ê/ÕcÊNUîO`gýǾ/ ¬‡*  ?V£xOtzŠÖîm¥¹î¾ ß àkdïg†tˆ¯ ˜DP¸E„ÅNR(ϵ"ع[jf¹þ(qm6Ý9ˆþØ÷…õ€@%ôÇJ`NOÑÚ½­4×Ý7@à_øcê’5ý5ËWZÓÉü‘oɉŽ¡uÃuk;>®ÏˆþØuø¾a|aÇäR¸MÔ+ßÒÚïÈÒ›eK×K(N‚´W1 ©Ôc‰“Õ.Ó}áÕ7Éß`';ËÓ6»oL8ì•úã^#¿ ¿tvæQœ¤¹ŽIü€À¡üaxI&ãä¹d1G?'»¥í¡^-:~]ÅpÝÚ9´ßƒÐ»½?“:‘/í/þh>û/:Sa^áÅ‹9OÚäk}‚'-ÙðêÕ«“ô}ýQÕÎiš ôÇX|tFúg ¬Eìþ"Á@ Gý1Gˆß;&pvvÖ±õ˜¾3è; 8îB`–€?tÍ.ƒ¬™ææJBJ#ögIfÏrªh­«®[Û©˜tz^ôÇN÷¯fvþâv°¿¨í\ÇTxqúÙ”¦-Æ™Û*ä„Ï©¥¾þ諟¶‚¤>ê‹ulðr&«“Jî DÆÀȹ™ãèÝ_$8ä ?æñ; c@<eÎCìt&£¿fZ0šNûZ¢ ÌÕ0¹gÃ!hUáä,ÉBQ">µY|¿¸¶C\ãX#€þ8BKðeµI±,XüÑ|ö/¼¹w~ç•X·ÑUUB°ó³5¥TNNèöOꖮȊ€Yý1ØDl²ÂɹÞÙSІðØ7ôÇ}Çï!V ?¶ ì€@ü ‹éLF7·q}ù”êÂ9‘†„èƒù‚öO}_2Ý[ޏ-j]µúÒ·9Øv¢J1”nkµùêŒNy¨ª­V0” è#„Ó—ÿ&UB§ú:c¶còû£¹ƒ=p4c:ÍÔ¯s22ÐÓ‚¦;WVôUÚ„–Kè#\$ø$  ?Ò@ ´@ý±…(`!à'Ф—€tC]+æ¸Ó[8dÑ…Fýñ7ñ† Ræ–Y³ªÒëÂMîœS®ÊYÔ˜§SK,¯­‘f0’è#DÓO·žì˜‚þÈùì÷ “{]•ôGåÝ¢7»’E ?f÷˶jÓ¦ÎR·ª ýq„‹ $ôGÈÀXÿqààŽçúãx1Å#,&P2aQ•ûù@6vöõÄþ9Q̆ð ]/Þ"±Ù¬¯?J©ô¥RWO5U¨fwšu+Åù{Ï.Ž. €þ¸Zs‡¤7³ö Ò¶Ó“ß)Ð>¿Ë˜1c^~ç'iûúcÉV_%úcm¾Sè͵x ‚Ö&€þ¸6Qêkˆ‚NCÁÀ”škŽ¿C`_üó\&£?¨·¡k°Í2m´Ä@>ž ¨eŒ­®¨ÆÚŒ˜Åûúc°Œ›¿u­os‰þèk&/Ú|pk»Gøâ&úã©®"ôÇS‘_ù¼ Eψ}iáÒOlL¤mû§N¼è˜“,ãôÆÂE'‚éüG¿C,I¨D\¹R Ð6ôǶãƒu@Ð9—Íõ¸¼9Z'à gs)AÁâæRÉ =»›UåuÈÜ"ÁNs VN&<êg *”èY#evœÂYžíÔzCéÄ>ôÇN•33±qÕÜâqÇ$úÅK3ÄV愦WÒÝZL/w²ä?æZ¿CÝ@ì>„80OA‡ÖÑškGÁÂT@ví2_jôçPûjàdþM:ɹì¦û' æP» cý1;<ÏêAòãÜŽq"'úãÚ° ôÇ#ßêt‰õ ç4SSú@;|™þ˜ž ½…þè¿ë(ÑÉܪ¥R/ Ð$ôÇ&ÂQë@ÐY‡#µ…Íõ(˜9 z"ÎRôÇã~¡/\Nªl~ÄæÚ…›¸P_ÓÔçÉ9Ýþ˜Þ×;Ö&}ñ5ôB–‰þxä+ýñÈÀ7<ÝdÇ”XüÑLñ…Kÿòóû£ônÑsËÄ&\EܰP5 zèõÌ8¢:Ý„ CŸx‚æJ+€éíü‘u0m9½@™?³{nJu°Ž¤´…ltüj'¥@ßBù/›ÿX²J¦³\Ù‘¬ÿ˜ãFÐ7{‚jýKÝå0't&NvLþ;„ĪŽËòýÙâñ2ä?ž õpJ@`ßÐ÷ÿÁ½GÐ<Àc¹Gs+žxø£ãXÑK¬™æ+}±Â˜V'Íng›B­Ð?dr ¶oÕÜDé€ZZ &’gEÒ¬š¹B̨b†úã8Mcr3ëôâæüdÇTÒéØeúcz7˜-ôÇÚMº™=Î…'€@ôÇHé•‚N¯‘Û¥Ý4×]†§!"ÞÌÚ ÛciÒVI?~‰ Ë~NRÉDé}`Á@;­Ö*è'¼ÞÐOåSO® [²†cÜ1ùUÍm³å¬¯]ZQ¦¤·ÖÙÿzå–Gu€@ÿÐû!Ì8;;ƒz!€þØK¤°Ç$0·™õÜâf[B˜óS—&Wi´ÒiC“‚% ã™”›ê%IšèÇlºÁ¹ÐOýS“ñ'D·øŠ?k;»•ÒDçå¼Í&Ho¡?ú3¾Kz¥Ýâúá¤F@Ç"€þx,Òœ€@Šú#íˆ Ìí›XüÑ*™Û»Æ-ݦ‰ Ë ôGÿ¤Zf1ÞúuÁ@;­¦÷–ˆa¢?žðCç†@Ã|•ÍT³BÑß"ÂÒ’²³¶?Í(­rºC|Uar2åêú£ïQZg0#}ÁýñÈMýñÈÀ7?]œÉX(#ú“És…)ÖÎ%IŠA†c 9:Y3æ½þ(Sc7}#-)RÅÐ7o©œh‰úcKÑÀ–• è¬ ”ê¶$@sÝ’.uC oÁž±îŸéa{°<¢ÿÏ’ÅÖü~z±HÁ-Ñ+·Ðý‰Œn™ËÉ`YSèG¾$Ð ü§Ó%ç÷MÙnÂl2áÒ´?Ò*á¤'ªDÝߤ iufg‚Û gFIŸh–ø¹–iÊòk2ÙSÜÜœqýál(œ„~ŒÐr@Û@܆+µ6AA§‰0`Dšk'JA`üý ü¿3 ÝHÙeù[Ôf§*ëpÿD‰%ÔìDþ({NÝB TÅ‹/N¶xÊ&úã‘/$ôÇ#?Þ餚-ÎV™n¬SKæ“Úhý]Ò»ùt˜¡S”ŸEªJ›·À†ã˜3AXúãz,©©9:Í…ƒæ Ð\i€À¹ϲCà8ùFJb¡ôo¢0™!¤ø$&ko¡?Ò§ÎK“ó !Ð&×"€þ¸Iê ôJý±×ÈawHi…͵•H`š$O4,Ylmr‹ˆÂY’Âëž:©wÉF±¾™HÉÜH”à,þ¦™…ÁMýÓÙ€þxäfŽþxdàœ€ ÐôÇæB‚Aë@ÐY%5mN€æº9bNž ÄJ_Éž þÞ5N¤«šê7™z9·ÙCz>øFú£¢LŸ4Ïp¡?žê"@<yÎ @h…úc+‘ÀŽ œmP+UB`è›`¥RŒBÀß©Õôµìâæz \–dMÌ&7Q4>C…9äÛé:£ÛI"ýIÙ觺 ÐOEžóB€Z!€þØJ$°Ø7ôÇ}Çï!' ‰MsŸ¥ éÿ囵*RÚ¥ôA}l{†ü™¦Jè@;»¿û«Ít.Ü|B¥Uƒ™Qnƒ¯çö–qUiÁJö-Ôß(U¢DH}²µ•[HÉè%”(@™úãÈÑÅ7@ èýÄ K!@ Žúc/JC€Æ#€þ8^Lñè‘úcQÃf@(!€þXB‰2€ ‘  ?ŽÝÝûÆú»o=@ì)ZØ @5ÐkhQ€ 0"ôÇ£ŠOÿBA‡¦ÐškGÁÂT@¨"€þX…‹Â€   ?T\ú&ÚBGh® S!@ Šúc. C€$€þ8FPø»Ñu½@ÐY—gPÛ#_ÿ?]ýß›žbW•Ó\wnœ… °+è» 7ÎB€& ?Ð,nyèžú–¯H À—u]@ÐY—gP o]¼4×uyR ´Cý±X`  @à4&õÇ¿ûÇÿsîC_?A}žõâ£ÿøôûþ^" ý÷œË_óÕÀgÞÿU}©‰d±øëvl,#Þùéo©\µ½íóÿäsÒQúÒ}#cœ%î]”&iæ˜UaP‰+`–Û?/|âqýSÿ£d>.ˆžiXsè¬Â Œ ë›à\ײYn:AÇðªLp”}_ž=ª:}¤ MP¡Âç— LuQ¶JddìH–¡ßÒ¬’8"VÿdU…:<ÀReU5Ùœ².P`’ú# €F%€þ8jdñ € PJ Ö?zõÿÞvõò—˜Ï[ÊPòÍSþðKb¤.IN2ùÉוôOоJè×.ùÏjÐÿ-LµÙOúÃU®oœ”iÇúB˜ŠÙ!’–ÜNsœT¦d¹ø,cô½;Öjž”ÌL+EöÍr:ÊGg"¦_.+cRþ3 ϾñO{­2tŒ§)eÁ!“_&\0Kd¤Y»lò®o­;Īu¾X\&É24Dfƒ‹›VB´Ÿ¬9épk™¾¢]åźsÖÍ@ÜaÐq€ÀN ?î$и @˜%èïýâ?ÿßù÷Ÿü*kºU´’|ÝP–/è¸d7ý19KÚ$KýzL RýWÿé[æV«¤ÓíØX‰›K¬3 ,ÈÄ´/SušNܬR¦²Mü ’1ÅÇWiͰ ŒhØ÷¾±mÊã“ ã4GSr}¡6þ&as ÅZÉ ÿѤÀàKµg¿™í‡Ølˆ3R–ÄÚbÓ„þ¨Æã7'3Àg^eAäËlÜ)0Gý‘¶@£@5²ø@(%àë¿û×ÿøŒwý½&_—L¹' $´#d$KM&ºI¬¦ûøâ”˜^Ø1NëKèG2Æ£`Æ®*™Tƒ¿*e*Ý:,m3HH ±2“I£Í^'mû¿þÓo¸2A¶cmò£qKL—6ÒJb¬?Öš1ÙÞæZNÉjºªˆª(KÈÎz]beDý‘f@£@5²ø@(%àôÇW|ü®àk_'ñ±”Ü¿–3QirUD_œS*M¨H¦W¦õ¬Iõ'­?Ú!¾¨g2Ÿ[?ш›UÊTdIî¡• »tÕZÞ¤m¦Ÿ:×?i‰¾ ±N8X"Çúã\«HЋõnó%V®KÚr,×F9VÀKÎK™˜ú#­€F%€þ8jdñ € PJÀôÇçþå×Ùp¦YTÎÖÔšÙ:Y‰Œ&5'ßú£MÇNÈš:—‰GAR^ZŒ/[QQß›yÁÊ’é9ξLO󜜨‡Á¯›“^RŸl¸@5s«7NJ¢Ù4XÙë‰Ï9€Á‰lï  “´Ä«ß‚î7³Zý1^sñ¥´óÑwÞp€ÀÀÐ.®A€Š\¼ô'ÿïßþÀÿäÄŽÆEÇSèIÊU´µÿô :ÁrN Šs-ÉÑV ôÇÉ\¹I .XpÐêqÛ¤èŸúÏ—Ì‚t9Û Å¼ð¥(@ý•"k•©Dë(ÈÒe²ú£¹ˆÂn½E‡½ª » [DÌß6:›ig bêv׉7æN£³–fÿÙßÁ‚ž%xuŠx»k‡“3Í'¥Æ)¹ òn £?î6ô8@`xèÇ!@ÿ‹Yîÿ-#ðÒÿõ†XRŽÛšYêÏÜdØ §Ïß>x±þl™mõ8}Êþðå¤ kÒýjj”›š‹Míë– h– Âÿïo.ó1Xñ°ª›JëTH7;¾J4 ÍHý7—6;g• ¨)Ë®_Ä,ÔÍ‘ Ƕ6ʾ¨ªËaÙuÄQ"ðÿ¼ð®ª¦Ha@€@/Ð{‰vB€¶"ð¿ùÿ¯ßù{άÈ×2ìüÉȾäïBãvž±³ú£iCAnc`g¼ñˆ«g2ÍîfìšéL_s´\NÿŒµÊT‚ª1Én­ãcœôÝigNu5iO¢ž\›L(«]ùqÒ ›õìÄ;ËlMXk•¸Üf¤lN˜  ?î3îx @øWND‚\Ö,\œmbûX ¡«0h¬L°\`¬?:¡M%U¡ ¸-nœ …%ú£iL¶éG &ºÍU‚mIÌS¯t¬TBó×ÊOÎäM#uK(ÚJˆúÏôP‹Î2%­Œ#P²6e­þ˜ÒL“u^»U>}QÒÈûÖÚþBþ–>1ðÚ†gFºöfÐ-;(c…Õœ\Þ¨5'ÿ?íª(ÏIÕµ~Qý‘6@£@5²ø@(%àëH¥Ô¾µœD“{L{šÌ( ¤FI{q1«'Pu*'0YåÂü½xöëdå±k±Øgeìpýç Rþá:»Ôù›^¤2AU§0…ÎU¥ç•L”ÑÙãœÓI¯çôÇIβ3¡?–˜ª|8V›àHø3æH⪆gðýÿTmt—±óÊ‹àX÷Ï@n.Œr°—z•# ?Ò$ @`Tè£F¿ @¥ýQ‡1»”Ý·–Sf™é;ËÏ¥š'u+Û1fn“–lµ‡XÑß’ªT¦V¹«t,éo2ëÓ§Th†Š-ØÛúpltl:4ÁJÙ°“j«šëN˜à& ŒAýqŒ8â @`9X4 ò{ïÿêòJ9òˆlFíâ Ä#Zz‚S•ŸU9ƒéýpÊ«ÚOI&_¯kôÇaR 4Eý±©p`  @à&õÇØÁ) `³z¨`åCƒ…ã®|¾5ªSò£ž6c±;n6ù:ž ¿F@öXú㣎πöAýqqÆK@€À<ôÇZ‡¦f+wo»©ßµˆæVtß×V¸“òÝq³Ý‡v#¸‰þxÈœ€NBýñ$Ø9) @ !è S @Üqðq€ÀàÐ0îA€²Ð³ˆ(Ð/ªõûuËÇ €þ8Fñ€bè´ @€ÀÞ  Æ,ÑÿôIDAT?î½ í?‚ÎÐáÍ9šëhÅ@ø&ôGÚ @`ï.^¼xÛm·íþJAgÐÀŽéÍu̸â <ñú#­€ °wš ÊÕ½7‚qýGÐ7¶zFs0¨¸@O@¤!@€öNýqï-`hÿt†ïhÎÑ\G‹(þ@€À7  ?Ò @{'€þ¸÷0´ÿ:C‡w4çh®£E @ý‘6@€€@¤% LAgààŽçÍu¼˜â òi € ½@Ü{ (óÿ¿û粂m•Úƒ £Ð<òõÿ“æþôûþþÅþz[±Ù±5ç>ôõ¿ûÇ‰í¡¹î8ì¸@`×Ðw~œ‡ ˆú#Í Kà–‡þá)ø¥‡®þïlÉÖ ø{+I¤«u¡¶üñÝ—ø¨ÐH^LŸZâãSßò•¬Ly|û÷yÆË_úçg¼ëïc ýqŸí¯!ìú㢌€ ôÇfÛÇÅGÿQÂ_üŸ3øÂ'÷Õ?c)QÉÜOV§js'’tõÌû¿êþ©%xé¿8)RG©°/Ûɤç\þš¾´ÿTO•¨'áÌÎåþó 3“T§jNghÊ#3 ÷Ü÷&íéÀf[ˆ ‹õGáQ( r“ÈvB9)A¢?¶ , u  ?®Ë“Ú @ý@l6fRܤ9åÎýáË‚~û;ÐË•˜lçþ ÎåÇ·}þŸôÓŸþGw^K‡œL»³ŸœþuõŸ¾!{éÕ¦ŸLˆÌ&ëù1ûøhµ5X™9ýQzœaxýQÎNʬsß7Ûþ‡7,– ч:BØ-ôÇ݆Ç!@`J)’äQ²øÚ 'Û¬ ôÇÍÐZqZVSíAâžÒMž“bèέÄJ&rýL4ô1‘Ñj²ýÑþH¢²³Ml¿ì ΛðÑòþT@Læ¸ÁòçÜTòc§“èË[Kw% ý±»b0 @,E1@8%)þÌxöåIŒ³Ü1Ë f§žÄžÅ'E\Œnë³Òa,œ™Æäë}ÙJ²úcœ±hª¢É“Ò¤KE,<{‚d\C<ã8q–ßxÍ™ËÜÜZ”Ä©nA)Ÿn~º?^—eqªŒŸLj¾ë÷«¯ÏJl &M«N•te|ÊôtÓÌãIô–ÇÚøtò­¯©ë÷%HôÇ„I€ ° ôÇU0R  lH@Ãòÿ?{kÝ‘Ö÷¢¾:çfïËs}‚¥}s¤è\íd[BŠ)ÁFKNh[œ4p:(² Y)Äl«lÔ|,'¦÷˜@¿ I7–LºÛlÌ—a›—¦q6mhúín·»¡9ÿ×ÿöÓåªñ9çsÔ¨ñ›ZZZkÎUOýªæ\sþÖSUÖ|– ñó¶)8Kßÿ¿®bµªñ«¡=·âQy×§ÿôRZžêig"ɱLoÌòýÔ8Çy•ìÑR+7*:kûG÷Ý ØC“yXà¥dHMÉKÔ³ Kù›eª¦þÑ›oÆ?E²é© çÎK®_š@(HüãÒh©€j!€¬e$ˆ€: (ÇÇŸäÓõ¤^G9|ÖÄÚó¹¹Þdóò'XMk5Ï®øÊ’ã<ícò—»£ŽV2Å?fÖ>“Œéÿ Jÿ¨úåÓg_¹ûáÀó"ó¡ 'æxžŸÿ8×?f‹Í­ 5|©Dö‹RÔ+²Ó¤N3Í´¾Lƒœ˜ÿxÏ/Îvs'Lãm/ùÉ—?³ùsbÿé•ÏÈ?þ¿þñ·Tø7‚ @çÀ?žÏ @`-'疥ݥ$ʰø¨¯’²3>"]RêKR­ã‘ùŒ*l$iA°HZåZ(ëýŸ~ü·S‡UÿÏÿãþó½$4Eœ'X˜Xh<0µÒüG?_¬ÚÓ?sýu§Oì\díçKgyÇãÿ8Èé²¾ŒßÆ?]‚]IþcçZõð™GNÿ "8ágÕ—ÔBŽúÇÒQNô›¼ÚÐh'ýOE¯·–`ñƒ¨“€wG ì—þq¿cGä€Ú'0Å›t:J_‚ÃeÒü ëÅHo´5H³&å(Ë5§q›”ìBÕ¬æ2TùPí.ÿ±rž †7úÈöðTÏ6­Ä÷íÿ8Å?êrK|mØ:àÝÐÜi:ãÏžø«úÇ,Ÿz`|;úÎ)›3øÕ#K¦Î†¸s¤2G‰\ð9xªB>ª­]øGŸÀ>ýy±ÃÎe ‹ÔL%€ pøÇËp¦@8…ÀoÒùIÛö0r%:…Hæ(³ùàÝÛ–H½ŒîÊ—S@¬| þqeÀ§W?ú(åTyÏh%ŽoØ?f™Gå¸r»±5„µÿuØÜV¿øGLOƒ”Ò”m%¦ %Ï$PÊÇÆü£^:†·E- 'N¨yüã™óË!lNÿ¸ù ôˆÞŒJÿâÏós×_모ª³ÎL1dVÔò¢<úf£‹¬v˜<¯ gÃ¥¯ˆ0Džï·ã›~øŒZôÓ*ýR¯³=.CÛ¥”¢L °“[Tò®L!tÇûÎïV¿Ô»ÎõÚ>ÜÚ1œlÊ3R±,¿RaøQ}wHb’¶¢_3 ![Ó¤Ný¬Jú’7«}4X§|lÆ?ÆŒ§R&"c~†[Ï^,åãQ'#³u@“Ï:‡þñ8cMO!ì’€ÕIùy^jÒg¼ØMd¹ŠÙyÖe¥µÒ$#Uåb(I—}[_¹ÑÈiÚnücµƒåÕ¾åW¬éšåñé!_OŠÑJ\›žéU)“l³‚ð•ÜÔ\©ù¨hg™Ç¨ß¹“ñµêx çde…«F²xåœÅ‘ž\á—=ûIv]^ÞÀúkÿÿÏ"^ÏÙÐúñÜ·L”1×k” ¸|Ј=ª}Y¾geN&Ï…€ °üãVäi€&ð¯nög}÷îfΧˆ*N r’‘S£‹EW¢>»3MtÉ8;ÍÞêŒÒ—«6 Ò÷,sª/=jRŸ/^ÿxqä;kÐ{\ø¸Û¥¥û?žY§ÅÊðŽ´g6±Þå~_/MëѨ¶æü£ÿ·çúæ¹—þQÎ’p³}K² nÕ{ËV;p@£ð£ˆ(@gô§‘øÒg›T…¤ µBV¦AGþc,ô=,;§Zö9Ö„Æ1U¨O\Ò ¾§ÌJ­s«øÇ­Èï¨]/Ý]6`=_²ÄÆì×TaœÜô‚BG/D;•°¢§dùêɳèb.8]׋yàükÿG°|š ïj’mÇÜ™¨KöîzJÍ€.Cÿxδ@çP–—šöíg¯=} <ÓÏ6®¤o¨_wnßVv BRÓY6ÇÉëLÏÅtÒõøÇ“°ë"»\î‡x…HLNÿ»þ¼ˆÄ_PèìzçÄô(sFkW%°àt]/Îÿè'u™#ì ÇìœwiJohàÚù{_åøÇõ”š!\†þñ2œi€¶$åV „R~FÚ2îKµ¼iÚy ÑüÇExíBè,ÒS*i€À.¦ë¨,ÿM˜ýmõš}÷æ¶^O€l`Ó@ðL@hŸÀDÿèMîÒ=ªÚGóFñècvsBç˜CC¯K»˜®£þ±Ì\N×_{3ÇtAú7Ú1—{ÿÈó€ÀÞ à÷>‚Ä@ã&úG(:àù øÇñ9D‰ÝØ…ÐÙ-]_˜À.¦ë€ìü7ž7…Œÿíe§Íˆ ÀެÉr³HÿgÓ…gÕA¸,üãeyÓ lD oÃÇ,œ‰Å6êÄZÍâ×"K½؅Щ€!TA`Ó5ücv`” z1µþŸçÝãL¶Ø2Ë”[L÷Ô%¶®A_¶“øÇ*&(A@8ƒþñ x\ @h‚þ±‰a¤Ýv!t<˜À.¦«“³/9ÄD+H§1ú‡ôè*)EïÿèúÙ'¿¥»F¦5¨ŒÖ%°þšç ½À?î}‰€ p.üã¹¹¾bšÞGGhx ]øGEœe>ú×´'r”²ŠÊd,ÏÂv1ÝŸ>ZYã±#Š*<æž!€š!€lf(é @àDøÇÁq E ìÅ?.Úi*ƒ CÀ?b˜é$ @`€þ‘é@ øÇF @` øÇ5¨R' @`Oð{-b…Ú%€lwlé £À?}Ð@€þ‘9Ð0ölxpÛëþ±½1¥G€ `øGf @àèðGŸM÷¡Óôð¶Ö9¦kk#J @àMøGæ 쉀ŽÈ¼ýg?®S5· º<£s«Hlÿ¸ LªªB§¶!žLW¦ ´JÿØêÈÒ/@Ûxè×_“+¼ã™O,ŠôßmïùØ£/~zÁ:§W¥v7l}zœsKâç£üŽ tv4X„Ête@€@«ð­Ž,ý‚ °=ÉGÙ:}½xó/OˆFWÉ]f©ŽójW­g‘_å3eH'tÍ—Üýì'ï{þS'_¾à…øÇaRUm:µñ `º2= @ UøÇVG–~AؘÀùŒÌ£R õý4ËÖ©/æê¸êjëÅ“COrüãÉ踰~úLjƒÓ•É@­À?¶:²ô €ÀÆ”Ü'¿¦ ôÝ?d·Rí)Ù0ò õCL•ŒÂ©TY§ÿä³}]ÕCn~ösQ¡ËdyŽzÔæT1¤­«¡N#©;UIçC®_õ¼üÚç"N`ÿèúÓGUL¿ê’¾:ZüãâH©°zÆ‚HF 0]GQ€vJÿ¸Ó#l@U>“\sÚ£E^f ;7R”Œ Sk·½‚;v]´Tò›úÁÅÊ-&%ïì=]@ßS9¨Ö}.Œú#ISÁÇñƒ//³/ÝPD¢ŸCezûË4ÝãaS[YêNŒ¨M/\vÍÎyƒ¬úéDpç@èœÇ«/J€ézQÜ4@$€¼ lš‚ pÚ<1œ£|œ~Nýš0ŒúÇáüGgÊiÊÚå¥K¼µK£ïQš¡ÚR±,Ó­Û:éÒ"R2ÑCÔ—ÿ˜ùG]èšÕ¢R7ãlݯŸØMØNä?Z×F%&™Ñ[|áGJ…õÐô®'"À0ËøGçÝo0ÒWFŦ\>Üͨa †ÑýOÂH—Sd‘ŒVË… •àWKµ€M Ídˆr ö¨´,›öYJ`VÖºªòRî8ÊÆ­§ÊRê0»§sÿÇ,$«Ï,µÓÒ³¼Ù$†â4–¬#ÎÍl£[9í Ÿ‰³ÿ8Å ¬J`mÿèÄüHÀ÷ò²9?Êøi.ã(¦¥N$㿆Y%ÙYso¢þ,Bïd’¶>°ñKù¾bb؃ 3 àÏÈå€ ðç“ÔîÅ^ŠQôLÿŸ…\a*­ð2¯«¶]¾Ó-fWMñ}Ÿp:çD©SË8íI³Þ9’m.ÏŸ‚øÇóR ó ¬êý×ÄÎQ’ôG?—OtïíõÝ»¤›Ø9úË«f2ç0ôÆ@uz‹dëÎôÿsþÑåãr0ü_É—Îÿkž?jÔ@Sà§P¢  Ì `Û¨\†Xe­–¦õ­çýéÂ˫ӯ4€ýãðæŒþl–næ˜~Ò+ýc, /ƒÏrCfŒÇ„¢øÇ (@`u«úGÿ=Ê’ôÓ_ËýLÜaí1âbåÝo{8=I¿|à%éßÓÿ¨†²óÜ@šIþãê3• Ì'€œÏŒ+ @`@ºn+[cŸÖöq®tç&S—ñNÊL“,·±Ï?:­#ûZuÒáWÅKåÛ`ÿÇmùÓú,«úÇáœ}¯Ð×@À[ ”K†»Üù s B–›ÙW­ÿÚâgÍ4 C¸<üãå™Ó" – ÄFŠ™>‹¤HwÞÛ? ,£V™ý箿Έ/èû>ª•Ëùs”ÏunfìfåÅ×qXgš¹éTÝã&-öéìêzþÑf0VRûÇ}+¼º¼<’»ïˆ¼ÕÇ• @à¯þ ÿÈ,€ þñè3 éþkz7Ý?:×õü£ÏŠI—K‡Å ‚qZºo‰.‘γé[É?jÛG›Ð8FfÀ?zëärçtxi¹êLûw65cè  ýÀ?îg¬ˆ€ °üã:\©€À<«úÇ8Mb.ŽhËNŽŽ£`\ÆÅb™ó‚þÑ'³¥‘dç°eѪ¤ 8·1½Ü•”'ÈeÅüë”=ç¥!@`üã4N”‚ ´KÿØîØÒ3@`OÖó¢ õÈRxö‰ú’°+W(«˜Œ¤ry=%EF¡~x2V5æÑ?(ª,’²L´«x²Ë;ý£;þÔ—ŸpZÎÉÝäB@Èà™€ £À?}Ð@ «úÇ:ºH€ pPøÇƒ<݆ ü#“€@ ð5Œ1@€ÀðkP¥N@€Àžà÷4ZÄ ´K`×þñÚï¼Þ¹2:îTv‡ŽžA€Àü#S€ ptøÇ£ÏúÔA`×þñú+·ö[øR:0 l@ÿ¸tš„ TEÿXÕpœLyöë •p N#pó³ŸÓA%¾øéÓ.窔À®ý#C @ €dz@€ŽN Ó?þÙg>÷௽vt4“ûŸ.<ÌDŒrÕy²/Þü˾úô ¨Xg™´òô,Zצúo{ÏÇtÒkTÞy>¬—U+:¶ C÷뫼ßUI0ù¡¾b>÷´ä&uyÀŸNiÑ­÷}E¿Ü—ò\'m ŒN‰ÅçÇ©»‡geÒ2ÉX°.ÕgûÆ—f]F_—Ý#¡H§Já¬áöqÉ“Ÿ.ì%€dr@€@«ð­Ž,ý‚ °ú´¬ÏÌþ*¥€;–ɬA\®OÎÏýÙ_œÐç¨ÁŸÞË0Ô¨6GQIùùßAv&ãpš¯9¡›Ã—”þñ7oþå_úæó;éâáÕ_¡  ü‹e~N]žïÑ—~èë‹Òå*“ÍÍjß•ë}¥3§T?q‰ ûËvÉ?ga¨GX>‰²ò—«6×pZœDž[/ýW_ÀY‹¦_®-½Çýõ@”}TØ÷÷ –âÌF¤¼ÜJG-éJ}™ÙÀ¹Ã¬ ­P;0§+°h·ï™µ”tHéKMö/ CÎr-Å<ÐÙ?¦OÏ¢N¶}<³î(GÕ÷¤ƒ;ðú£ÓYR5ýÌ,ø}#8w>¼<þñà€îCh˜þ±áÁ¥k€ê%àä &¥R‘ø°y‰ÔH•ÑÏéÇþ°ú0¯¯‰}©”%ŽÌ-†ñLå΀tÖU|Ú·AÈÓîüãÿñûŸùâ_ø„_×;{*‹Ì“y@|‡*õ´»bûæ ²tî¹æá¤Bk£Ì'øG·RZòH…KézJ§•ÏRSÊñ{‰º*/Ÿ¼'´¸ª´øÏ è+­—Jÿèi0<‘²zÊ×–r ¼þ”Q•…gÁ÷NtÊ À?2= @ UøÇVG–~A¨šÀè'U/÷DÎÍ™âkR.¥[,åÂpþcF¹ `_þñ{~ûÓ÷>÷©×H|œóì)óûª{¼›aæ,FONˆ›B1[D–OùY Ì-®ê]ÿ€^ª¡Ó?ú¥fúFµùÇ¹ËØ§L–Á?pÐé2 ƒÀ?d é& ºø|_¢¢W}Ž®M.Å„?Õw®âìì§[ÌäÅ,ÿXÞ‘üº_ygNxž8él Q1æ€Ó 3Á$]åçBæ;U^§Óö™UtCÒÙŽÙÓð8€Ôî5’1;½á -®íýß‘éÜvJÊáJù–Ñéÿ)ÁÄuŠéΔÆÎí>ËìËžM\‚d@€@«ð­Ž,ý‚ P5NÎöG‹ˆ'*¿òÓ²S¨¦‚Q6¤3²Õ©ƒqð÷_^ÅyÉñ{×ãÿþÿýäoþo~ý’¶Ô–·öóþ}åôKP9èºÇƹ ÿøÿþ'þ§ÿmΜ9ÿyå“”<©Bå¤s ;þ%pþ1“qe„®m8ÿ1óŒ*­¤»IÎZÙ=ØG5K·ì3ø³XXÔÒÉ꡾'ã9Fêk0œîÓ‘Ÿ~p–»YvG³Ë­wνa¬`²SŒ²y’^Þ9Üw 8ÿYÖv ä?¶=¾ô€À‘ à<úô€@"(îM÷Y†×ô•×îyæõ¡Ý6A_‘ö5Ñ?:u«´»ðWWWR{½ÔóÁ/VÂfs ü”]dx«ÓöðÝñ)jÑ1„pOQÍåZÚl`_Ž!µÿ‘N˜þà„‡óËuÖçøGõ.[:íáNß^DÕu¾¶˜jßÜë‹c»fÁ_¤SK=÷[þq¿cGä€ 0LÿÈ  í Äx§íL9@VÅÒ$¯Îƒ F;Öé­`¼Lñ–8³R®ç%£a/^àÚµkO>ùäóû ä"l³9“y¢8æXs,MUë;ÿz8-®Ó¦àÅQ!ÎAN{­_½§agB\gR¤.ïä ×*ñßõ]ßõÞ÷¾W¸P£s¦,Pºïá´ØkϦ/*,ýcŸR ‘^7k•tæ½óc6 ]aé%S¹ÖyÆNêRG1fëгÀR%Ú÷ßÇÙ)gñ}ÿÒÐ6¯Yï²_c|Ëg},p^Ï?f{àç’ËÇp©‡›ó¯G§ý”øÇ)”(@{$€Üã¨3  ”kTG×0®ägå?ËGSV[Œ\$ÁÕ0–áQ' G$ ú¤éØT4ª*%Q6Ã;÷Ôóµú®‰äúmC ¥;6F‹SžC¶Å¤}__>¯åš3欓ƒݪ2e›ÃS>ªî„Ï÷'q;Hï¡ïY÷SIçlPk\óµáUô114¦š eM”q0V¨ž¨*à;ã+¯³à»ÂÑsÃNxŠêü㡆›ÎB8ü㡆›ÎB¨‚€>èÚ§D4þ¸ž~l¶¶ÓÇõØÈÌ.O÷DVÑÉ2Üá2·QçÏZ¯Ä§èüÇD§´]WØ©'ª¿ú«Ô?¢ çJ£»‘Úé øÇÎûþQª(ŽÕvýÖ‘÷—îØ8Ë?úIW #‡‘ÍØ”‰Ÿ¿ÑÙm³¸ utÇÊáÇñ8 ì•þq¯#GÜ€ ¥à—"¹U=Î#Þªõ¬ÝØ— Ý#2ýy[»7JiÊÒõÑJÎ)°;€>¼òa=gD.y-þñ’´i €.IÿxIÚ´@"à-¾ê‘5"2Ø þ±†Qh)†ÎãΖzºR_¸Øú«Å?Ö?FD@§À?žÆ« @ v};3ú~s]{.þñ‚°i €@/ü#“€Z%€ludé @`*üãTR”ƒ °&üãšt©€¶$€Ü’>mC€j €¬aˆa%?þøJ5S-'€\)B€@%ð• a@€6#€Ü = CHà™€ Ð*üc«#K¿ @S à§’¢ 5 àפKÝ€ °%üã–ôi€ Püc £@ €ðÌ@h•þ±Õ‘¥_€ ©ðSIQ€ÀšðkÒ¥n@Ø’þqKú´ @¨þ±†Q œFàæg?÷ÜŸýÅðµ/¿ö¹»Ÿýä‹7ÿò´&¸jqþÚkö™Ï•ÕâGM…€ P üc%A€ Íà7C¿Ÿ†¯¿ò™ÛöãX£joó1|ôÅOßöžéûp$>)ÈÍ£%øÀŸþÅÿÂ'^+„0þ‘@­À?¶:²ô € 0•þq*©‹—“ï“ÿʾR ˜èôƒ×~çuÉ©ìKwª7²ŠåCqËøvÇ3ŸÐWüª†\¬DòôŸ|ö¾ç?¥¤¼xH÷È|ÉùKΩkݺ¿ôëùLVƒêÔCÃzTÝétpÂÛçæ¬ö*W¥ô¬È¹Ø ò¬ÉvÉÂ?ùòg¾¬0ÂøÇKmA€À% à/I›¶ @5À?Ö8*oÄ$/&g”}¥°, GåûÒ¹Lè?ÿàT¸T –Å"]NÒJ5¤:Ò2K_eJ]æìŒ[—"ÔCnq4Y¯Œ?ü£ãÌ$¦…^}ì€SznEª®ó~=´Sÿ¨>ŠR6«Aw>ôë¯U;ÛØ÷üö§µ;í8þñ€Ó€.C8üãAšnB€z à«v…Yþ£DRœ]²ì+ËŒöÑ®Ó ªÚ¬N‹9«ÀLwfÎÎf0-£Ø²K†cs£Œ2+]gšÊ7àÕ–.WeMú‡¬¹ƒøGõ:#9:%(pò²ÑþñÌi€6!€Ü;B€*"€¬h0Þʨ0* (10Óˆ£•¸ÍÿXÖ`ɨŒÈ2s0ó[‚¾ÖSU:à½üÜõ¯í¥V%ªÊõé±h]eRAìØ¤Gc¹ÖÅ h–´¨kU2ʤë¯Ý„‰9€4kÕsƒ%ص=ßµ [k±þ±¶Ñ!@XŠþq)’Ô@Ø+ücµ#7*隸¹ÑJÜý>ÿèu»Ù:ëŒVZ醌¥,s$g/ãwšgšD9¼þ:š[Û?ºïN´ôrïØ‡Ñ €{”B󣂬²ÕÓeÌÙH¥þÑ{\ºi·’¦ŽÚ§FrÖ@Px%:…FgÑèDüãJ„©€j €¬aˆ€ °%üã–ôÛU‡}n.uL£• ûGoà˜­ËÉh;™J®Ì?ÆJ퓵WV¿‹I[TüUùGCÅ)t>‡ÇbÏJ/!W1gAšaº£eš¢8Ë?z(;÷ ÅÌ>ßÿì3ŸûëOßüð'ÿ’üÇ G‡ @`øÇE0R  @`ÇðÕžE[¶ÿcm§û˶8LWãzMnç&}ù±Ô:m7•Œiþ]¸¶ôüe§+:#oÖÉ3nÑ }éù3º'ÛArUÿ8=f£(·˜,…iju}¼Oß±à‹ûG‡'Õ¥f}i›ÂoÿÍ×vôuïsŸR^á^¾þ?ÿíÿÃþ8þ±ÚWcƒ 3 àÏÈå€ ÝØ|åÓ·0ÙÑ—6w›kmì×b-­ý^æÓ•¶Ë•ÄjܾtÈaÿ˜úÄR2ºNgóuž­îøäk빬¶á§PéÝ´’ªücæ+­ÝëøŠSqÜwÇ/YžÌ3꽪:Û 3›'n%=içñ|f®˜ÓI)s§ñ¶åÿßÿÌŽ^%äo Êñîÿ¢Ð@€@ü#ó€ ptÿÏÿý7Boíâ‡ÿÇû>>Wl[^çKÌ1á³üÇìð4·Q‚Ï{fºO8fÅÎñV`ÎàëônKÁ[´•‚OÂ2~휘©ØJüc©Ãúu>³ÒÁ½0­©…õåÀ ¯¿žÿè/Ž—êÿ×ýÊkÿÛ‡o\„¼rÚ KÀ?^š8íA€j#°»üÇÚ®Ϩ:Ì ”‡_+¶ÑJÿ9þQ—ÛyùüåôÜ•ÎDWvÆŸU2±ÎÒåEÇ;­œûRæ$öx'Cß)Õ˜­£/“@}j¶û¢¹ì~Ö þq½'àejþÿþÖ§¿õ7>D;þñ2Ìi€.Oÿxyæ´@¨‹þ±®ñH¢U‡Yò4˜¥ücvzL)¯¿r+'Ñ'8ûGo9ý8šN6­¡ðÎñˆœRšåœÌ–NÿèA™žuh’±žºì~–e9×?rþLUÏw-×>•þ±ªÑ!@XþqA˜T@Ø%ücµÃ6×?ª#sZ¡­Ä%ûò½Ø¹óüë´Õ ÀS3èM!Ó›]át©×ºã¤*?Ó?:òL̹ã™7”0§} ڷ륎ÃN)¹Ýhűjo™ŽHÙ¨ç€BÍÈ[\N7¿Õ>/š L£ùw?ðÉ×þò Â?63¸t€2øG¦ @àèðÕ΀QuXðÁÊ鯂£• ûGŸ’m+™yíTÒj,ü£Ô˜îñ±*^}l5VnR90Ž?/KŸÅi-q•ï‘@Œ¾õC¬›Žk‡è_SêÅÈßÔµŽ³”†Ã¢³Ï?:¥Qµ)x·®&â¹E=äÔQu!/¨ ØEz§È0Âe£±?¦ JîÔtó[íó¢À~óæ_þÏ?ÿ‰?ûÌ[=þ±Á¥€ PÀ?2+ @G'€¬vXŠÙ"Åר[ôUé‚XÙWÖë>w¦b¥Áìô*éµÕiþc{íû­#g§é\I–i1—}”ûU~e‰Ri¨ö}¥ªs&c™Ô·ŒÍIAúÚ‹”ƒu¤9ëþ¬þ¸VeœÕ¨Ø"ѧú” ä]Ûèl™5^ŠÀ+Ÿþœäã‡?™¤>¾Q5þq)ÂÔ@µÀ?Ö6"Ä@¸4ü㥉OnO:/“ú55JΉËêSú›ŠÅŠ]«4+Ð?—‹pµ 8ÍLë,óæ|ÎLg&jÎ*—MSŸÊ+¤>s7€D—¤'·ô¥ï•§»¨G¡ËGû"Qý}M8Mr®?ͺ¦HN€0yÊô\$øóàø²g?ùüÇþ¢¤d†@€@«ð­Ž,ý‚ L%€œJê¨å¼˜}½ð9´æ¾¦Ãܳ¼÷Õ»f¢Å?63”t€2øG¦ @àèðGŸúŸí$8áŠñ"J3,ÓÓ{Æ«¸` ç–‡º\0„³šÊÖbŸU¯Fÿ¸Z*† à7š‡ lNÿ¸ùÔ€4é;Áù´ø}–ËÀײÍdzÕ&ë¦ÏÛ5ô­—_ª~êY„þqŒT@À?V8(„@¸(üãEqï¶±Åmà¾òw;n¾'øÇ=±B€ÀøÇ9´( @h‘þ±ÅQ¥O€Àþà÷7fD @Óà§q¢ @ ]øÇvÇ–žA{"€ÜÓh+ Ì!€œC‹²€  à[Uúôy¦ÂŽ0]w4X„ @³àgá¢0 @ AøÇ•.½I¡Ã\ئ뎋P!@`üã,\† 4HÿØà Ò%ü#s`‡ð;4B† Ið“0Q€ Ð0ücÃK×®®®€½À?îe¤ˆ€æÀ?Î%Fy@€@kð­(ýöIÿ¸Ïq#j@'€gD @€@Ûðm/½ƒöBÿ¸—‘"N@˜Kÿ8—å!@­À?¶6¢ôØ'üã>Ǩ!@`œþqœ% @mÀ?¶=¾ïû?|ì«ûøÇ}ÑB€ÀtøÇé¬( @h“þ±Íq¥Wo@è0vD€éº£Á"T@˜Eÿ8 …!@ À?68¨téMæÂŽ0]w4X„ @³àgá¢0 @ AøÇ•.á™;$€Üá 2 L"€œ„‰B€ † à\º†ÐaìˆÓuGƒE¨€ 0‹þq. C€$€lpPéÒ›:Ì…`ºîh°€fÀ?ÎÂEa@€@ƒð *]Â?2vHÿ¸ÃA#d@˜Dÿ8 … @ À?6<¸t ¡Ãئ뎋P!@`üã,\† 4HÿØà Ò¥7 \]]{!€ÜËH' Ì%€œKŒò€ Öà[Qúì“þqŸãFÔ€ 0Nÿ8Έ€ ¶ àÛ_zì…þq/#Eœ€ 0—þq.1ÊC€Z#€lmDé °OøÇ}ŽQC€À8üã8#J@€Ú&€l{|Þ;ö<øØW÷ñû/¢… éðÓYQ€ Ð&üc›ãJ¯Þ €Ða"ìˆÓuGƒE¨€ 0‹þq. C€$€lpPéÒ›:Ì…`ºîh°€fÀ?ÎÂEa@€@ƒð *]Â?2vHÿ¸ÃA#d@˜Dÿ8 … @ À?6<¸t ¡Ãئ뎋P!@`üã,\† 4HÿØà Ò¥7 t˜ ;"ÀtÝÑ`* Ì"€œ…‹Â€  àTº„dìþq‡ƒFÈ€ 0‰þq& A€&€lxpéB‡9°#L× ¡B€À,øÇY¸( @hþ±ÁA¥Ko¸ººöBÿ¸—‘"N@˜Kÿ8—å!@­À?¶6¢ôØ'üã>Ǩ!@`œþqœ% @mÀ?¶=¾ôØ üã^FŠ8!@`.üã\b”‡ ´FÿØÚˆÒ@`Ÿðû7¢† qøÇqF”€ ´MÿØöø¼wìÿxð °¯îã÷5^D @Ó à§³¢$ @ MøÇ6Ç•^½A¡ÃDئ뎋P!@`üã,\† 4HàÁ|þùçì]‚þ‘9°+øÇ] ÁB€À øÇ°( @h’þ±Éa¥S&€Ða&ìˆÓuGƒE¨€ 0‹þq. C€$€lpPéÒ›:Ì…`ºîh°€fÀ?ÎÂEa@€@ƒð *]Â?2vHÿ¸ÃA#d@˜Dÿ8 … @ À?6<¸t ¡Ãئ뎋P!@`üã,\† 4HÿØà Ò¥7 t˜ ;"ÀtÝÑ`* Ì"€œ…‹Â€  àTºô&««+`@`/ð{)â„ ¹ðs‰Q€ Ðück#J }À?îs܈€Æ àÇQ€ Ð6ücÛãKï ½À?îe¤ˆ€æÀ?Î%Fy@€@kð­(ýöIÿ¸Ïq#j@'€gD @€@ÛðmïÁ{ÇþŸûê>þq_ãE´€ 0þq:+JB€Ú$€ls\éÕ:L„`ºîh°€fÀ?ÎÂEa@€@ƒð *]z“B‡¹°#L× ¡B€À,øÇY¸( @hþ±ÁA¥KøGæÀ àw8h„ @“à'a¢ @ aøÇ†—®!t˜;"ÀtÝÑ`* Ì"€œ…‹Â€  àTºô&„saG˜®;,B… Yð³pQ€ Ð ücƒƒJ—ðÌÀ?îpЀ&À?NÂD!@€@Ãð .]Cè0vD€éº£Á"T@˜Eÿ8 …!@ À?68¨téMWWWÀ€À^à÷2RÄ @s àç£< @ 5øÇÖF”þ@û$€Üç¸5 ŒÀ?Ž3¢ @ møÇ¶Ç—ÞA{!€ÜËH' Ì%€œKŒò€ Öà[Qúì“þqŸãFÔ€ 0Nÿ8Έ€ ¶ àÛ߃÷Žý>öÕ}üã¾Æ‹h!@`:üãtV”„ ´IÿØæ¸Ò«7 t˜;"ÀtÝÑ`* Ì"€œ…‹Â€  àTºô&„saG˜®;,B… Yð³pQ€ Ð ücƒƒJ—ðÌÀ?îpЀ&À?NÂD!@€@Ãð Ý}÷ÝO<ñĬKê/ŒÐ£k×®]¿~½þAw60#zg¡#Ÿn×–vG1d’7ºàb;…ÙÙqU2<.iäM<ôÐCi™D*¦xÒŽèç,kUýêèÂ)yG>*µ÷\Ü¬ÇøÇÍÐÓ0 ¬Lÿ¸2`ª‡ TO ó/¼ðÂ<ðÊ+¯TxSJ!ÙÊEzš4Sª-•ì¿úRðlÁô=ó¾V.Ì šÓQÌR,õP¡À"ÏÎ?ºUi&ïœAYú,E›j¯Åýãpï$t$-ìG1»#î‚ni&¦c³sô-*wÇmH3¼fžÑè›ز ]8€È)xw$œu:%¦ûGµ•ɦžT;ì þq‡ƒFÈ€ 0‰þq& A€&úǧžzJ¿Ê×4Üß:»¦ ¸áÔ?K%û¯,].œ \’lZ&È|IšJb Ýzš·8œ‚g[š…! gÍ—å6ºpÈÍeýãhï®®®ìKá|H[¸Ë€“¥@ÎJ~ìt‹n"Í'†Ÿå‡–Æy–tZhß2ð:Ÿ, G…lxpé ƒÀ?|Ð}@€À_…|òÉ'yä‘×_(—'àD¶ã_B*u.VÀº_•X]•K†‡“*ÏÖS+07—yFÝ#VVå®…¿[Ö?$„z³ìËld³ÔÅÎØ,gch²ÈYÉþQwfÐFá§½(S2gùÇÌ_~æÓbJÿÈ|€ V à[Yú@˜JÀþñ±Çc¸©ÈV(g $›Ö·Œ7¤R¦Ã‹×>{Mnê'š¬R&Ž^˜)³XÁíðÒ^LOî›»ÿãhA¦ïXs‹DÎÿØÙ#÷z`GÎr¦t61QY¡õnúäåÝ…Îôئ9UŽÀ?2E @ UøÇVG–~A€¦ø†oø†w¼ãçO­‚rKˆ ½»_VeH%'ôeÎ+NÉücæ×:ôʒGÕž]adÆñÙ¾0Œ^©·ÌœÒ»Î­*ƒCÌ€LH£ïÕwÒÎöŒ=ÓÔ×QøiÍeè,ÿ¨ªØr‰§ï2uà—áH-€ Püc}cBD€ ËøÛûoÅW|…² ¹­G@¦LöÝ”ê1W±8Ú8KIK¥’wZ #–žbœùÇÎóR²ùU.ÙVßé”̸¥Ò3‹É5§>+3û”_ÌÜüÇ)½û[ëo l¬9ìÕGÆ2=°“É”'n€5^ß4¸Ó7ß,‰ L•,¤NÕ˜f_êà)ÍÆ¾Û7¦ô‘2'À?žŒŽ !@ røÇʈð @«xûÛßþU_õUïÿû¼I@{kNñlNå$¦þ1;þ%uËúG™©8 Z?d+ôSoåÝ'ªGÓØüè‚ùSü£„Î\ÿÖÕ?t®MvÓÙJó)ÏÕ,ÿQîX¹¢&I¯óUÌfFÿîø}ï{߀…¿ÿþûœ۪ÄÊD¢  @`_ðû/¢… ,O@wê§~Šc¯—'{^¶H±,7“Jáþ¼;Yæ™­­ÎâȾ0–q.d¶Û¿–KÅôSzgÿØw°kÈè…uÕUçöœ¶l¹³ûYG¦øG»n*œ è9þñ¼9ËÕç ÿñ\‚\@µÀ?Ö:2Ä@¸Ÿ?£••(ÈK!ŸÔN–Ü—I¥8/;;ï%“‰a©šô%Y–ßG'+T‰°Pu¡DãPš´õ©Ý©R¨õ?¥wö}ç«d‡ùLéu³ ´¨$Ä)adz:Eä#¹;1Ž®¿ž45)´üãjh©€6&€Üxh€ °9ûG…‚Ü|,Ò†ýc“¥2™Ñ6ªóh¯Ûí‚S˜­™êÏΛæ•Åe ¡][v¿‚IÜıí„Nç"eÕ_¶8±×ŽmCÿ8 ˜÷Ü,G<[¶„OëÈÄ¢Ø,øÇY¸( @;"€ÜÑ`* @`áQ«ðV©×üFY-ÈÍ$]¹¨Ö÷d‹‹Kÿ(S©ªTL60=²F—G‹¥ø›hâlËCg2öùD«U];*0w§Ó“ 턎ƒQýé>‰-Nìõ°T²ÓÉÓø;›ÈN¹cX>ª­H MOQÍ"3ík‘=ð´ùK©eà—áH-€ Püc}cBD€ ËHý# ò²ì¿Ð𥒅ž¾§»–þÑél±h×uunæh›YÖ~*;P;êÞÿQÅâ–lƒEohhéÙ‰ÔÆ- ©o•ôð  ÷ÎB'ðêß:µé"þq`ûÅë”Ã4’µÃHËèQ+Bç6f¹žT,znغ¦­”û`Æ"ú­f>í¦ðÌ@h•þ±Õ‘¥_€ ©2ÿˆ‚œ nér> Ù¶H^/ËS»~ýz™¨{tˆRütgšøÊ4Ið©rµ’y([­ìÎòÀë²Ç Òd—ù~¥×õqR*ýíŒy:ã¾Þ…Ðñ©âax¥óÊ9Qƒª†Î’ne r¯X›~-µ`V&ü£†;½6ý9›0êµ²oýUqˆÐtÔ”\þq=¶Ô @ÛÀ?nËŸÖ!@Û(ý£äÃ?¼}pDp^±Ûä"Ü«««‹ ü|#Nüœ»Šü’fm±ùã†ð˦ñU Á@€À‚ð ¤*@€À. túÇ]ö„ Ï  <¸á¬½3ê>Ð¥Î[ÜK‡mK•ýº—€›ÿØüÓA@‡%€<ìÐÓq@€Àç à™ "P›ŠJ×Ç"âôm’XÛÀyùöÀ’óÚF:×6"øÇÚF„x @`)øÇ¥HR @`¯ð{¹¥ã–8KOˆ^ºúyõy¿ËÛ¼ê(ÝE@™Ùþ¡pÚ–þq[þ´@ëÀ?®Ç–š!@û €ÜÇ8åI.¼ÿãI1r>OÿÈT€ V à[Yú@˜Jÿ8•åvH¡³ÃA;nÈL×ãŽ==‡ Ð:ücë#Lÿ @cðc„x|ÇüñGOè#€<Ø€Ó]@"€<Ð`ÓU@€@'ü#€@ ð5Œ1@€ÀðkP¥N@€Àžà÷4ZÄ ´KÿØîØÒ3@G'€<ú  ÿ€ ü#s€@ ð5Œ1@€ÀðkP¥N@€Àžà÷4ZÛÅúòË/¿øâ‹ÛµOËçxî¹çέ‚ëW&€\0ÕC€Àf𛡧a@€@%ð• DåaÜ~ûí÷Ýw_åA3¼G}T£3l‡%o»í¶'žx☈öÒküã^FŠ8!@`.üã\b”‡ ´FÿXíˆ*åP^©¼]»vÍ1_¿~=}ôŽ;î"Ì<Ôp%õÇQ•¼•ìÕÓO?¬î¾ûnÓ÷Œž.Ñý¡µ ‹›~μŒ_ªãi n´ &-sóæMÁQ±²uE[ÆìkÝÍéÑnRR=Ò茦7jzè¶I„4Zxì±Ç^yå•ì~ü#S€Z%€ludé @`*üãTR/çœ5ù/›£¸…}³xJ ø×TÏ W"¿ÕêB]ž6$÷çNëÎLù°n™jts©ã{衇\­îÔM-N‘e;â÷åŽ$kÂeäZˆÚìB·bŒV´ìøÅgÁxƒ™”UØÙ¸¨Ý£n²ˆ~èEJ¼ôÒK÷ßÿ7ÒÖðaO#€ °üãÐi€ PücUÑ3ªÕJqæDÅÔÄV-ö¹6g J#¦±Yz:¥±Œ9uyeåQ*q"ö2~Ý“Õ9ÜG{7%?ÊBÁ?– بeÕýl'ŽÅÖ  gÁ<ðÌ3ÏDåøÇ58S' Ô@ÿXÃ( @`KøÇ-é¶=ª;÷f¹¹´ý>ÿh—.¾ÖUöe™ü²ó:gÙo'„,ÔaPÒŽ¾OÌ-˜ÿ¨þ:ÁPßUm–l¨_S·Î$D?*ƒi§rau´âiþ£²ƒ–gÔ…Ùµ¥ ®vò$°×_ýᇎ„eüãAÆnB8 üã.C€ÞBÿX턨Ä?zÄLŠÙ?ZD¦–ŽÏFw'ì…N§9Ö øG¯^·ÌÄ«î÷êx¯Ïóñ²t?ª[¬žît£™~Mý£+Ooi.ê.–“Wû|\/0íéÇ?®™š!@`[øÇmùÓ: @`{øÇíÇ '‚üc¬5Ž*G+‰’}rªóþðvmaÓúöLÚ,àeüîcºŽxb/ãmeýÔ\œ7m†‘æ&\éJp÷(œ£®Ê¶øÌö¦ðÃùOª™5@^„À“O>ùÈ#àI%€ P!üc…ƒBH€ ‹À?^÷œÆìËÒ´89¬ô”çìü™ÎĺÑJFýcç¢ÝðºÜ™}kœ};2ëðkU^Æ_.è®Ê?–[LZÑfO©ú`îΩ17ÿ1ˆurvmåÑ4sf%e×"ðÔSOÉ?Nßu­8¨€ °üã P©€ °+wÝu—>ôr«Àã?n­fg·ôlëÔ?Z>–;-ŽV2Å?–Õ¦þQæQM[Œö媌-[gϘ,~©LëN}%áUùÇÒ$:Û1[žæ0FÖj¶È]XÖðV“š`µÍyâ½ ïêÁB€&À?NÂD!@€@ÃȬvpGµZ&§¬±ÒÉ‚SN€é[ªÆ`•Ýéí %ûü£/”_³=Ì‚õYüYOGA¹þ‹­¿Îº“îü;<:!4¢±£t~kzÔÏzþ±ÚiØÀ”ù(ÿxãÆÃ ã€ Ð0ücÃK× @“à'aڢШV+åTxÀˆw´’(yŽ”G³‘öjK’¥sAwà¾øÓJ&öq[ÿ¨UØ ½•§cGŠhl‰Üâ™·A›z^襘ý7@O“€ pøÇ‹`¦@€@ÅðÕΨV+åTvŒº6ZÉÿX®).“"Áç­‡7y¬Í?Qv µ±Ì Uå;nçúëßš6êLÏéçÏĈìÿ˜æWV;ù˜å£2ñ‡w: @àPð‡n: @è €¬vZŒªÃÎä¸L™V2ê‡Ï¿ŽËµ¶:‡ü’êÊl—âé\Ð=àãÊ-#—]ž1Û¢1;¥Ú¦‡S—1w²*¥pvaväHZIéF][j„³S­}Iç ÷Y&´ÚçEc…|T¿ð .Ý €d2@€ŽNÿXí è<:F²)Œ^§tbœq?GUùšôaþeü^c®zbýr_]³pEëi0éòçz2t.ìV:Þé;«Zmõ­a÷ªÜë¯Õœ~E¨Gã!K“1MLè-¶‰ð¡SÕJfKû«ö)Ð|`©|Ä?6?Üt€À‘ à<úô€ p‹þ±ÚyfFj¡ÃvÌ’Œé¯¾Ó[1†Û­$º¯K:Íš·ÎÖó¦M¤m¸Â~ê¡ØÓÐÒP¦ËG]Þ¿êLŠîë£Sä)½ø9 RÅ•ƒ·BÕ'¬ÈîcXrPýé&íÊWZ_Ú‡j8²VÜÁT«fW˜¶¢fežVû¼h&°L>ª_ä?63¸t€2øG¦ @àèðGŸú¾·’• K¥á„f·)¢8³“a"§IfârV”Îì¼ÄˆújÓ£}Qõ]’Õv~ð³zJáa¥|Ä?2g @ aøÇ†—®A€&À?NÂtìBÎaÜ…=\u ”~ع¯âª.Uù@næRMPÏt?ü°œÉÊ“ÿ8 %!@`_ðû/¢… ,Oÿ¸<ÓæjTæÝè©Ö'tÚ;-ÜN¨s½K¼¨y¿¶oEùzĨy.üã\b”‡ ½À?îe¤ˆ€ °ûï¿¿LÃY«1êÝ-Ò¹â9êÜ–1½óœÊ¹6% ]#•¼¹_yzÑÄ?d é& À?pÐé2 @à-î½÷ÞW^y(€ °-üã¶üi€Ö#€\-5C€öAÿ¸q"J@ uøÇÖG˜þA8.üãqÇžžC€LÿÈL€ Püc £@ € °üãT©€ °'øÇ=±Î$ðøãϼ‚âØŒþq3ô4 @+À?® ˜ê!@ÕÀ?V?Dx:„Îéì¸ò☮GNƒ€ p!øÇ ¦@€@µðÕ O¡s>Cj¸¦ëÅPÓ \˜þñÂÀi€ PücuCB@˸ººZ®2j‚Àºðëò¥v@ØŽþq;ö´ @¨ƒþ±Žq @àèðGŸô€@»ðíŽ-=ƒ L#€œÆ‰R€Ö%€\—/µC€ÀvðÛ±§e@€@ðuŒQ@G'€<ú  ÿ€Ú%€lwlé @`üã4N”Ú%öÜå°5hüãQGž~ChŸþ±ý1¦‡€Ú ðÄOÜ}÷Ýw¼q»ï¾ûž~úé6úUC/ð5Œ1¬D¡³Xª]ƒÓu ªÔ @5À?Ö0 Ä@#äo»í¶Ûo¿ÝþQ?èׇzp‹À?.‚‘Jê$€Ð©s\ˆª“Ó•‰@­À?¶:²ô €@;,•ó˜véÑGU:d;Ü´'øÇMñÓøº:ëò¥öE 0]ÅIe€ PücEƒA(€ PвkÉljªñå—_~î¹çF1¾øâ‹*9Zì8ðÇëö¡sÀAßo—™®û;"‡ aøGf TMÀÉ£»=^¿~=Öe{™v&"u§R&],–rG-åV¬ýꫪ´DpøÇ%(RG¥:• au`º2/ @ UøÇVG–~Ah„€  nÃqޤÄâµkפ-uSžc\h)éuÜ*¯ï¶. ÕXfYºLZI#L‹nà[Yú%¦ÁŽ0]w4X„ @³àgá¢0 \”€d¢Åâp«¶7oÞŒbåªmY£û£Œõ¢”¥ï)E§•åE;¼QcøÇÀÓì% t.A™6"ÐÒtÕÆ)GX@°ÐÈS  ö àÛcz@`¿¦øG§.–gag>±”‰®™»þZÕúŒ>Õø‡r1W«Ãƒludé °/ÛúG­(ÿ™—- Û†—Dmþãž6çmOÒ´ÄÿXkY!þq_“Ÿh!æ à›b:@`ßâlëôxwÉ{BéÓN¹h«<ÏÚŸCâs‘.TêD¹Ã£Ó™ÓµéåûÆúÖèñ-&}ɰÿ#SbG¶òÞiÑ‹ ýw0‘R±JÚ{•èo V¬ãr=ªË§¬¿Æ?îhr* 3 àÏÈå€ °:T­O2ÊLÔgÝôƒ·|rÛú¨£*f?èm¡²M!ãs‘­¥jpYôn«š*6º|u«5€\ -oO`=¡³}߈ 9ëM×?añ>ÿ‘Õ?ç\8 £e¢þ>ê{.à­¿ÿçç?Óþí¿¹i™l¬ÊtEÿýMwsž•ÿXvüÇæžtØ7üã¾Çè!„€?Ù ú¦.é§+È4;#;13]ÌßË…fþ•}2düãA&ÝlŒÀzB§1Pt§ëM×?a~(]d`#™ž—¥ÿÛ01ËÄô²e⨌ӫýwYî2…éþÑÿST£éåøÇ¦41@øG& 솀>ÛèÓˆ>e˾ÜÝ©O *Pž…m{èBQI_·;?±ØK¦»Ýï†Ú„@Éœ‰"{%°žÐÙ+⮘ÀzÓµOÆõýuþ—[vò[ü…Íôß\ÿ¨zÒÿNôr£Ž6“¤øÇŠg:¡AG$€<â¨Óg@$Ðùé¨äàObY…Š) dàsÔÞyâ÷>‚Ä?@`=¡v,N`½éÚ'ãìøÊÿÛ9Ã15zúçŸþ çŒE§+z ¾w¦:ÿÙí<&Óˆýcß9uøÇÅç'B8‡þñz\ @»!0Ñ?zw–_i)Ù™V¹›þŠlcéE'õ„À!°8õ¦ë°,w#Éü£Ÿ¾Ë êæ¿•ËúGÁÌÎ…›â½Ð;=5;ÿ¸øü¤B@çÀ?žCk!@`7ô9$Ýʪ3n¯á*óµ+VçŠïÝt~,Püã!ß1Ç|ÇÑúÁlåK—Ê;;¾tsÆtýuߟιùêL8ŽúGV.Yð¬É6©Œ©äÍ"³½&6Ñè. à7€N“€ pyâÄb—Õñ«â¥r@ \Þ?ê¯^vÔŒBuÖüÓ®yNTŒ¬É2ÓÐêptÿÇ,ïÒi•±Ú`Ø?ËGõÂA–jµ\Z>qt(@çÀ?žCk!@-À?¶0ŠôØ?µý£|_z30[?é<ïö¨`¼½cxÀ,ÿQF/ÝÿQ—XºÝ,þ¦øGí)éxÔVyd¶«UmiÌþ7aøÍ¬Gé?˜éÀ¢/$oõ4¹ý?è Ð2ücË£Kß @Sà§P¢  µ ¬êíÓ[¤ZA:Ñ?¤çPKäYÛ¹€~öæ4{1­Ae$‡×_»|zSùl%µ[ÉnΩt<åM•¤c¤³’*€|\{S? NøG& @àèðGŸoô¿<€,!ÀÐ×3ÐëùG%f©‚Ù¸«€|Ÿò û[Óýé£å´q™GóT…[šhcåÎdÌl,ʘ]§”hùîélQ÷G×Ò½ëw" pøÇ#Œ2}„  èôúpÈöüÇ™7^PÉ'óãŒxÚÓ2ïì˜jèõzþ±†Þ ™þñÈ£Oß!@·”þQòñÁ¼qã€.F@«}*‚o±›ÐZE/fÈ'Ò¢B_[jDe$¥•«¶,ÅIW¥Ä{¸ìæeÊ$êÔUª0«$Ð¥Ë0%µõk§ÚvOîÞu.«±¾ÀŒ‘úç¾›á TÕ×D_wb°Ü¢â×=zÞ¥å ¤oij1-vÍeîE:º¶sÚœ6\uüã9ô¸€j&€¬ytˆ € p ™D>^ú[ÛïóÞj’PJE´JmÕ¯Þé,µ„i>¯ÖŲu‘>ÕÁÒ0*×=!¶|m¬šTµ>ÛÁ^,na¸:Å–Oœ(…—‚ÑýqíÀ¶å»Âñw¶naª‡:Ïáu0Æ%—v6ë¾Íæ@U©cv‚á‰ÍõÒk}gçâhï‹§ºÜ*³œ}þѽHg—O@&ßyÊÀ­]ÿ¸6aê‡ ­à·"O»€ Z¤þù¸É¨X½¥¦I9ŒiŠbdÉõå©YYZ¦õÄ)±YnJ†ôµiÇ,¡ŠÙ‹eyyqÈCê1CeÆkøGÇoÍšµ>Ý?¦Ý/ ]Ü?¦#•1œ;ý£„uz<ˆ“R³A™îÕÖ\ºÉÓäâ0Êô€À1 à9îô€@-æ.Z\6îjO]ð.þº)#é[ò…D>.;Á¦×Ö§Š¢\Ë2×\@“$Ò3ÿè ‡gQ鞆ý£“ï²t9?—ÓTGÇ–e5®áÝ´“øÊüЉùé`mâËFòË©Užå½Öû¯6ÓŸÇ,‰<æ¸Ók@G €<Â(ÓG@ ð¿Î5ŒçÔ¾Fã6,+Y£X¬ÄtB“­Ó EöÈÇU!WîAX.©S*y2KÀ¥ ŠÕ¢}e¹3`Œµ]VføÙQš>¯€Ž]#Óú³çøâþÑ}ôs¤s÷^üc)—/é=.}oøÔ8ZÓøÇ£8ý… pøÇãŒ5=… p»°rÑåÄJ%,ôYºÔ+—ñ­û¸¥¶<“¾éÛ˜o""³ä3=t›UÉÜÂòúЇ8pf.·Ë{ÿGÝ:OPQC1 ¼J·<=ÆÿÈü£—cOr«Ãt7À¨'»3³Šé´ôÿ'TÀáe;K¦õ,îÓSk:3wá•xhyšf N÷N€Í^(få?ö¥|.8É©j üãJ” =À?îqÔˆ€À¥ 81Ç.c8—ª/²¾·—ñøh}òѱ²ž¥j˜4_ñ_ñÀpÚõ¥ŸWomOϲÈxÕ³,Û®1\R™{˜&fþqŠÀò%›6JíyßRéiÏ;øäuÈÁ„ñô‹FºSäâþÑ‹¯ÍÒ.KÓ^Ü?:+9»éÎYéáišsT•”ásÇÍ9óÅ'øÇEþ‰²íóhï­ã÷>‚Ä@}ðÌ @'Fh³ZdB:è‡0˜r鮋! $ä,ë*}ºVr‡²¨ÐëO³Ô°Ö;÷ÔŠ¤s¢·e,cÐ%q~ˆ~ÎÎå_8em£wЋ’>Vb–×΢ė|É—èC/·­<þøã¡Ïâ,c{öL‰ì¶,Q.M<Ù?fÏד)¶ToeY“*éGmCc•ö|Yÿè„Çôu£Ì"\Ü?º³ÙmîóÔnÑÇëæAÌ`'úGEù*q‚t%š[=hW”Š~ÂË8—@€*'€¬|€€Àöâh …â,›Ì£u …Ô;øsuz ‘áív.‘ü•©;¸ô–êË…dsçJÒâ}­—I‘ÖˆQ‰.Œ†"Â2ÖÉZ­¦·ðD"椶ÞeìÚ¬obñõÚçä|ù—¹ò³„»ígÞ#pva:‘R—”n˜>=,ó~R ïš]bê–0†%Œ›ýWš ‘ë‡é;KžêëK€ÿ±¡›Ñ¥ªtqÿØùÿ€ÓücúÔÖЯ?ñŒ)þQ…=7ÊW‰“ýãŸyÛwüÇíÇ€ @`øÇu¸R+ †8ÃÈαó„ÙQÿ8œÿhÏ"E¢ßn+ýx *ý™Ü»¤e‚®A÷+H°€ëÑ×zé]³—Žê*Õ‘¨~uÓ©—ÞM2Õ}ùÞÔ/ÖÒNÜÌÑÎÈßÕP™M¹øäÒþüà•tƒ‚\œíÉfî)sIñk¶ßb&ýëðž 'ûÇÐ…ª?U¥þ/…žö’Sþ]aJsý£_2ûï_ÓxöâKí;Å?ºŒ^jÊ™†<ùÙ·á…øÇ áÓ4 ¬Jÿ¸*^*‡ ÐL ”ŸiGý£(”²ÏhÊÌlùdyÚF¶À³S.dAv¶žÝY>kÝÙ9„}«>³Â¥OÉvÇë¬Üú¦ÔF2’K–“µëó¯µÿ# ²žgì°ôóÂçM§{öe2Ñÿ0He\ÙÁÎçï”üG? Cú??³43/é¦ýh§íóe}ƒâ F$?ú‡ìßñ:SÖ“½ÚD¾×«•y~þ£ZϰúGèËoíë_a²«bÔêy 3üã1Ç^C8üãF™>B8€ýE* ÊÏ®gúÇl1c&P:•DúQ¿ÓdâoŠt¾áÄdÃÎÜÉÌò …ÑwƱÆÉBÁâ&]SÙ'DNÚäJûGÝ‚\„çÜJ”vZ*$O€0àÙÁ©…ÎþK¯-“=±Kß§’žíSkŠŒg§½ö3´OÉ•ÿuеåºéQŒ}¾Ò–?í²!dú>Ýë kkÿ¨ú;ÓÝV§[œµþzX>ª âlèÕµNnÿ€ ,Nÿ¸8R*„ Jà+€ P)ÛÆ4èüо¶´gIoiJ×Rþqtí§ºé2¾)†Ô¹”—;°Îàû™µ‚±%1çPöM«æ?z ¢ /ÿTŒ¬:Eâ™æÂ¦tF.“YïÒ?Æ®‚*éÓN∛Ø1°…Sü£bóA·lóAû¾¾s[ÞýݦÃïÜ ¢—7ITwÃYQiù¯®ÍgGdËÕ™øÇE0îºMþôiµy_<ùn›GØL>¡hà¨îfzº‹Žàw1L @'À?žK @ ›€ÆèÖuçì¼æÂsèO¹Ü{ðuæ.õÝ!õ˜»¯__ º¤*üã9“Šk!,Eÿ¸Iê Úàkâ \šþñÒÄi€@ü#ó€Z%€ludé @`*üãTR”ƒ °&üãšt©€¶$€Ü’>mC€j €¬aˆ€þ‘9@­À?¶:²ô € 0•þq*)ÊAX“þqMºÔ @[À?nIŸ¶!@5À?Ö0 Ä@ÿÈ€ V à[Yú@˜Jÿ8•å ¬Iÿ¸&]ê† - à·¤OÛ€ àk…úcxñÅ}ôÑúã<`„7oÞ|î¹ç†;Îðíbbàw1L @'À?žK @MÀ?Ö<œÒFRKÙ- 8}¨¯#•t>u¦ÞñÆ-kº³ÅNöòË/»Zµ8x¤êék´ï¡,fÙº²†>§:OxnÏ,//|Ûm· +HuäöÛoÇ Ÿ‰zÁ˯]»VNEüã‚„© €ª"€¬j8€ °üãЧ5)ó%¯TÞÂ"Ia¤J0é¦;Óê‡+QùÎ&|g(­§Ÿ~Z¿>ñÄQ³/Ô÷¬+ºD÷gžëî»ïNÒ¯°“J¿ûøÐCeVQfz4«M]P26³¿ëtsº¤ìã´Ñ»\©)þQÑx.- ¸qãÆƒ>˜=ðÌ@h•þ±Õ‘¥_€ ©ðSI]¼œ]žÓÖÒ[däY<É+ùQY9k¾T¥ W’Vkµ—Þ=¾ï¾û2u>±S¦(<…¤œÿ¨‡tíèzáhÚñËÆåÖˆª°,Ó7D Ò$àª3ÕQúXÝ—‡½øD¦Án¥‚Ä?2W @ UøÇVG–~A€¦À?N%uñr¡ÞúZ.÷ìžRW8ZIT>ë§ ³ìBßãKÒ…Ïeþcyí,eüJ›ÕGO¥…væf*˜Æòûºé%Ø©·5^ƒ@¦ ñk@¦N@¨þ±†Q @û#PìGwÊžn•w{ʶz£9\ûè¹ãÞ¯‚²Û¦ìd·@üãR$¯gTvгYn.¹Ï?vú,[E§Ô•©ˆ‘ÿèÕÓÃ+£‡¹uBÈBé¢ð²œ^ÿ®ïJüL×ÂëIí;³û£û~T0Óuî>7&Ûƒ2Zñµéúk=ädÏÈŠM¯ÍæÆâ3– O *Hüã ¹€vAÿ¸‹a"H@uðjÊìÖØ¶bS¶ÕșҀy½jPòêÑÌõ¤û륙/6wºàç»XùJü£§z¶n7f©WCÇ£ùÙÞ‘³vB8ͱ^À?:'TO/÷ñy©.9Yg&¦)¥!p;_g2ýšúG?äÖ}K¨·€¼ä¿7fõa ‡‚Ä?vÐq@ÍÀ?6?Ät€ÀòüáY)6é>qÙ‘Ë·:¹ÆEÎXðçyõQÖ@bÅë73‡2à]>./uƒzã;;S ñ“G»ñ‚ÙÖ‡N§MåQ6 õÍW¹ÿcìŸXVûò]g6Wc–úh=ï\Oéøœ#é4ÉÎ’.!8ž4IpTÔöÅæû\íçµàXÈF+Æ.ËÍ ozèö\ÿØ91Ä©©lüɳ·îYAâ÷6nÄ @S à§’¢ ¤’¢OœÕ@i`»éᕟù-YÒe¤Î"[@ííê2høÇéÃqØ’ÖjÙ-L_ˆ³Èt+óÝÂF T’>µ;™;ŸS©%wN´…`gŽáõë×#X…gåßuBPH©Ê¬Í?ª¿é¤u>u*LõhJÕéÒXÖð©ž>ì“«ÂŽKAÊ?N?¾Â. @ þ‘¹@³ ˆ3Õ¥OÚÙ‡[ï_–.Þô=^¥˜}&w4N9ôþe©eÈv=SI}T‹2úôîÄCÝœ›™eeª-µ¨võаéüÌŸ¥%øÇ’i ­ÿxçwêC/·Ú<þøãóýL±ÃÒ-KT­ä|ÿèåöó}kœõž€‘Ø™ùÛùb”ůó9†ÑhúïªJû¶lþcépÃÏ:ùÔ7ûG¿ÉWúßåëázþQ¬¶9O<"p×]wÍþ«Ì€ ê à«"„ PaÿèO˙Ԉœ/<´­pJTvkºuš D2‘¥CŠ$•ª9r¬"#, ßðÝn©iÒjËÏü>F£L=›˜IäÀR—ZdÿÇúždŸh4­/›¨e–ît7§’}¹Ã£ùºÖOÛ3¦²KŽºÂ(ß !ëé((×ÖçF×öa]ãu)~HWdûUÂÿ>‰î¯ç«ö‡ L%å•yXt€&€lxpé µø³´d_šË“6f[a׿Ï‘Ôck Çl+·È _éLF×?ì]¦Ó•xSÈôˆŒH×êÄÕ}Ô…i§|ÉôüÇÎ#€ñkMІêÕjå$¬yñ¨V+'avLH·)ù†}®Í8[1]|S€SªÍ?–ÙÍŽ9]W>qœ;úÕ&;@| Â”Æ37š4ù %ðYɉ¢ØÚ,½ÿãÚmQ? @`øÇM°Ó( }ÍT÷üyÛ’Ócásš;™~–§ùG'7ù4ê¸9ÂÎÝ'–ÿè#Ý£41s4ÏKU¹õTÂzøñû~\$úü£§Vú¼­$ºÒçýtÈôYg±Ÿ¡éó¢ÜÖB­|FôíŒßÏÇø§ÂÄ>ˆ9?ÓcõL׺465šî/‘…Ýɰ”¾*6d(Ù c”ÉpÅkQ4YÅ΄k¶J>áò‹Ì÷ƒ6òQýÇ?tÐm@ €<À ÓE@K˜²–0N|βí&,)Ò[$guJèÁiþÑÎËFuOvLmöy>Ë9ʶ¶œ’ÿËÉËAÀ?.=1¬Ï¾ÌOŠôš¬s†p7‘ÑJ\Ÿt ™të|ªÚ-fþ1ë‚®ÀÊøý2’ftvö1§€½4˜ôé¯âÕÉ…ýkö &VÃÿ#éc»^zC ]p‹~ÈŠ0}ññk…¾ÇÁ;Y eV£/Q+º¥Ru8øŸBÕw)•øÇꇋ!@àtøÇÓÙq% ØâSåWæ? [Ï?oH—…Ô©u²«Qÿh£Ñ§Z:×´:Œa‹O<2nGº`…š'™|Ô¯a”dÐÒ_Ý®žqº3gÕD´º¤/-±œ“*Yº9U%G¦ÖSµ')é}|ÓUçϗô²øõk™¹\ö±Ó?¦0³?(*ÅfèþvæG?=zoǨ\%ÓüÇ@ÔÙnnî] ²V,XS¥«·¥ï‘\Ynˆ±àD¥ªdòQ5ðj|F. ]À?îb˜€@]Fý£>Û28û/5}ÉAÑÃáôœòÑrs´² /~X2Yòít‹Ù"Êaÿò1Û5/Úê;òÂ=ší™óƒO¼g<Âåó€ûع}/Ý÷kNߦ{éE3q–òÿØÌàÒ@( à™€ 0›À¨´tŠ“³ü"Ï([ÂmǦŠÞ–1ͫҵñÙµE:~ðÉ4·±ï¬Œ)XZºÅr3¸ÿh«[Ÿ|T ÎEÒ-Ýú-¬åܱ٣˜\€<‡ÞA®µ|OWò¤ãY7õ„½äÿ–…<úïŸe›£¶a?ü°œÉÊðjÌ´ V à[Yú@`E±Yº’1]ê˜ Á°l/WùØìLéC ÆÆ‘ÞìÌ…ÓÕ¦Þ¾Í˽'Zæ?—»]ßiw ¶\³~íÃëÇ£©-ËÄ¢WÇæÅ”Ò¨­onå J|â]ñÙÒPÕž¢Ëv¨sax<¦ŸQ³lT}µé!µ…4½ã~)žµ ÅôÊ)¹^—"I=€ Pücm#B<€v@@Ÿ`3­¦_ãc¹~È>¢»|ºÕšï‰}в|"ïÂf)WÞðÎjO?+ÓP?de┆T*+Ý„N?÷>£1Pᬪ*;£¶,þÑ~s€R sUÖÊ&Ÿx/¹&ô\[Ü^íË?îz×¾]©3x^뢂 ó àÏgH € }àï¾Çè!VðjÜÊHÒ@È à™€ £àïÑgý‡ê À«qã@€ °<üãòL©€ °/|âÝ×x- Ð*^[Yú@øGæ @àèøÄ{ôÐtÿ¯®®šîkНÆM ' „þ‘é@8:>ñ}4ݦwÓÃÛZ瘮­(ý 7 à™ € £àïÑg@Óýgz7=¼­uŽéÚÚˆÒ@À?2 @0>ñ2&ÀônxpÛëÓµ½1¥G€ `ä?2 @G'À'ޣπ¦ûÏônzx[ëÓµµ¥?€ ð&ü#s€ pt|â=ú hºÿL驪·µÎ1][Qú@øGæ @&À'^fBÃ˜Þ n{]cº¶7¦ô€L€üGf @àèøÄ{ôÐtÿ™ÞMokcº¶6¢ô€Þ$€d.@€ŽN€O¼GŸM÷ÿêêªéþѹ¦ðjÜÔpÒ@Hà™€ £àïÑgý‡ê À«qã@€ °<üãòL©€ °/|âÝ×x- Ð*^[Yú@øGæ @àèøÄ{ô@ÿ!:ðj\Ç8 ,Oÿ¸Æ‰(O"Àô> mC€éº wZ… õ à×gL € º ð‰·îñ!º³0½ÏÂÇÅ—%Àt½,oZƒ ËÀ?^Ž5-A€ê$À'Þ:Ç…¨!Àô^#•\†Óõ2œi€.Oÿxyæ´@¨‹Ÿxë¢Y”Ó{QœT¶.¦ëº|©€¶#€ÜŽ=-C€ê À'Þ:Æ(V!Àô^+•®C€éºWj… í à·"€ lK€O¼Ûò§õU 0½WÅKåË`º.Ë“Ú @ øÇzÆ‚H @Ûàï6Üiõ"˜ÞÁL#Ë`º.ÑZ @ >øÇúÆ„ˆ @—%À'ÞËò¦µ‹¸ºººh{43ðj|<.… ª à«‚ƒ \€Ÿx/™& ŒàÕx @`§ð;8† ,F€O¼‹¡¤"@gàÕø x\ @UÀ?V=<@¸>ñ^2M@%À«ñ(" @€ÀN àw:p„ @XŒŸxCIE€Î À«ñ𸀪&€¬zx€ p|â½dš€ 0J€WãQD€ À?îtà€ °>ñ.†²²Šzè¡û² gÇž~úé;î¸ãå—_ÞqêWãºÇ‡è @àtøÇÓÙq% @  ŸxoÞ¼yíÚµ6:¸a/dj„ñÑ7nO<ñD‰¶9ºJe^|ñŲÕë’Ûn»-Äëׯ;’ôæÖIÙ„/)ïWåiTº¼o¶ôß7(®9»Eåã æi=%ÀYÓhÅ$âéDF‹e:©ö1I[QÓÏ=÷\Yr`\ØI·Î‘Òýj¥o Óûo¿ýv¤öz/)øÇõØR3 lKÿ¸-Z‡ lO üÄ+ùøàƒÞ¸qcûàöŒd$ ¾ûåŽE‡¤tí륬ˤº°r³Êõkª8%‰²š]>»ÙFÝ}÷ݺ¿[¾¤4Vª<-ï–½P…*6˵©§eQ¹dþKQ‘-oYÃÝPgäj(âéŒ6šöå1ˆYH±s&dí9“é¾!°y,§JjcM¬œc|j9¯öü­.vücuCB@€ °üãB ©€ °[Ù'^äã"#i)¦›–¬ºBi TñXKY •©‘¾ÄZ-•k¾ßúOEåúA1­_Wéž´/ŽG.)½ElªPJ.-ï JݲzX*÷’™Ê2+¿èxÐ6­³§Nô ,Z=eÜã¶\•ˆgxÊ¥xÕ¢Íu)—;°j1M3Ô´4ÀtLgùG‘˜±‹. õÖBW¯­8˜Å ’NÇËö4ôÚg§OfþqŠiê4DÃÚ3¦ëšææðÒ¥ÙÞ0U~ö‘Áç ÍlÙø¨œ°rÿXZ×)ò ÷ÔJsZçúÇ>c¾ì3蘵á9îô€Àà0Êô€ 0D@Ÿx‘kLç zup™®˜®R¥Ž/õ–G‹¯Ó.tÚ¨aEe 4=>{T€.î¥Ó3£ËщÝ3ËMÝÝŸÖ»CN¸¸ÔHãé<мoo\Þ™;Ý?Z4§;Ìõ†“ªê5ž>ǬÿxÌq§×€Ž@ÿx„Q¦€ ÿÈi×+M9š8"Y?¤Ö)5\þ9u”é{©þMîsG2cwZÌ¥·>k©ÔÂHrL³)íï²”ÃÅýcdië"½4‹D݉ó¯ÓJb¿Â‰÷Yú²b;ç¡®MÎ?O‚¬B‘,ë4ÿ8°·éJϦ#T‹<Â(ÓG@Ç$€<æ¸Ók@€Àè/·Å <þøã؇S[…JK Wvü‹—G~Ù‚þ1Ë Ì’7|ôÂjÿì.8ëQÿíßÿý7nܘw¥gÈœQ–agAi;™íÞ˜%3N1M}ù¡;cO–QÉl-¶M½dT²xþã°Œ3¯;ù5ŒS.žÿ¸ 4ö̽Né”çX™zyŽœù$ øò™"€ Ð*üc«#K¿ @S xÿÇxà™gž™z åæÈ,Of¸B¥Y®¥ºªô£»ïuÚ¨QEå4LY*‡š­·»t¬÷}5»S³ÔÛ”üGûÙpµ)þqà@ä}-Ϥ6¥•9qu¶˜Ü2e2ZÏÒoÓ¨|U¦ƒÝ£YKÈ'ö”bøGæ ´JÿØêÈÒ/@€ÀTþÄûúë¯?üðÃÙÂÌ©UPnaÿhµgÕ˜e)fþÑö§”€ª!V"ŸæUƒ[×Þ‚Ùºf{([¹ò,x4Ã&uN t«È¨ôðÈÍ´®MW[úÇ)û”\¤^–ݹ°œ•ÿ8 Ý‘¬6ß©KtN¤¾žNbŠ À?2= @ UøÇVG–~A€¦H?ñ>öØc¤5M7XNêMÒ'„ ~°Y yW¦Åù`âl_?»¡l7CW¥&b7Iý æ¢Xº“c„9š"§’Ž¡,ióØi©t•­œMÕ¤W§' 7ìÃˆé‡¨Ä Å¼õºp ÊXž¦ƒ¨nª}¹“'ûGŸ S¤Ó7pšK%ÛÁõ˜¦›E–ü¼°Ä®£1cËôUKêlÛÍEž5T‚d@€@«ð­Ž,ý‚ L%}â}òÉ'yä¥CN½žr]R‘g7”9 Ò?Æ™Îá€\qéà …ô¡ŠÒcfùÇ8<ºÔUîBß¹.2.àÎõQIüàKìÝ2#fnº¹Lçù×)•説)ÓeŽ5íȰ,{‹šG…iÖ¿fb·,£{ÜDçCº3«Ál³þvZË”6Ïþe à—åIm€ Püc=cA$€ m”ŸxŸzê)Áš¦˜mÙÎ[U^›œ”–nÒ‘™Uô£‘Àè¾Ê–ù§*Ö™”ª U­*—$R4MÕ–)o*3e+F•)slº`…¾PY-÷·\¦=e<Õ)Ý|­ï,ëql1c;kÈø«’€Ñ„zaÈê—ªHúsä峯XÊ[”LýéDäÞ¥·lÚÄèdÅÜDy¹‹•Cé.xÆê‡’˜jëœZSF–2Sà§P¢  ì‘þq£FÌ€ % t~â}á…´ä’ÍP×e ”ûH^¶}Z›JÀ¾ojé­Ë9±·SMnZ íã[Eú@]ðÌ @€ÀÑ ð‰·Éà¬:cµa—»TêãÕx£FÌ€ 0…þq %Ê@€Z&À'ÞVG·ÜãoÞj=o¹bzOçÂê ¾LÓò;:tÞ[Už¶²þ2<÷Þ ¯Æ{A⇠>øGæ @àèøÄÛê Ð΃õ$Öy¿Ë[=¡¶:éW›³HmT’àÕ˜)@­À?¶:²ô € 0•Ÿx§’¢ 5 ðj¼&]ê† - à·¤OÛ€ ð‰·†Q @¼3 @ UøÇVG–~A€¦àïTR”Û!çŸ~‡QòA ðj|ЧÛ€@ÿx€A¦‹€ A|âe‚4L€éÝðà¶×5¦k{cJ @ÀðÌ@€ÀÑ ð‰÷è3 éþ3½›ÞÖ:ÇtmmDé ¼IÿÈ\€ Ÿx>šî?Ó»éám­sL×ÖF”þ@€þ‘9@€€ ð‰—™Ð0¦wÃÛ^ט®í)=‚  ÿ‘™@8:>ñ}4ݦwÓÃÛZ瘮­(ý 7 à™ € £àïÑg@Óýgz7=¼­uŽéÚÚˆÒ@À?2 @0>ñ2&ÀônxpÛëÓµ½1¥G€ `ä?2 @G'À'ޣπ¦ûuuÕtÿè\Sx5nj8é  $ðL@€ÀÑ ð‰÷è3€þCuàÕ¸Žq @Xžþqy¦Ô@Ø>ñîk¼ˆh•¯Æ­Ž,ý‚ ü#s€ pt|â=ú  ÿ€@x5®cˆ€–'€\ž)5B€vDàõ×_¿óÎ;w0¡B`öœ…‹ÂÛÀ?nËŸÖ!@`=øÇõØR3 @`^yå•{ï½w"N"€Ð9 mC€éº wZ… õ à×gL € Š à+B[€BgˆTq)L×K‘¦@¸4ü㥉Ó @ *øÇª†ƒ`'€ÐY)®G€éº[j† m à·åOë€ à7š_™BgeÀT¿$¦ë’4© €j"€¬i4ˆ€ pqøÇ‹#§Á‹@è\7G€éz?®† z àë"ƒ \€þñibC áÓô\L×¹Ä(@{!€ÜËH' @`øÇU°Ri5:Õ Œ`ºŽ3¢ ì“þñÜq{饗žþù«««Ç{ìÁ7ozëÀíî¼óÎ`~íÚµw¿ûÝ‹W_}õÜAåz@G"€<Òh±¯z“vÄnÓç}À?îs܈€Æ àÇu–¸qãÆ»Þõ®·½q“Ó[ÛëׯK~ùvb¥\6“À믿ÌŸ|òIˆÆâž{î¹ÿþûå"¥†gÖGq@G$€<â¨Óg@ JøÇ*‡…  @`øÇyŸ}öYå9Þ{ï½2\?ò#?ò»¿û»ŸãVßú­ß ;¬¼È^xaÞ0S€À‘à4Úô¨šþ±êá!8@8ƒþq¼›7o*Ãñ®»îzç;ßùž÷¼çå—_®Ï¹Q âû±{à”©IåKNo A8üã‘F›¾BUÀ?V=<@gÀ?ŽÃ“·Ò"kùÇüãH¾øèG?ªDHãSO=5>䔀 p$øÇ#öûÊþGõÝöÿ¸Û¡#p@!€ôÌ3Ïh©µ¼•ìÕN½a§”¸úÈ#hí<{tòÒ@ à™ m@è´=¾õŽéÚØ€Ò@øÇîÉ ?%KõðóԺ=ƒ©Ý!}j¶âµ€ð̶ tÚ߯zÇtml@é à‡æ€\ã7~ã‹/¾ø—ÜÚ%ðK¿ôKÚ’娼BÀ?2Ú&€Ði{|ëÓµ±¥;€ €ìž:ŸDës¿ïû¾¯]íFϾ@àµ×^ûŽïø­¯ç€À‘ à<úGè;Bç£ÜL™®Í % Œë¯¿äÕW_՚ܟû¹ŸCÑŠ€ÈÖ±æ:âœW@Ç$€<渧×ãŒu=eº60ˆt€: à?E[j5î¯ýÚ¯J½ÑYøà?¨Ñ饗x™€ p@øÇú¡ºŒÐ9Ôpï½³L×½ ñC€@üã-2ÚPúéþàðq‡%ðáXsàÙgŸåÅ€ÀÑà6âGë/Bçh#¾ëþ2]w=|@𥣮uÚ̧>õ©¿àvlûØÇ4^xá^2 ŠþñPÃ}ÀÎ^]]°×ty§ð;8† QG÷úÐuß}÷I<íμý»÷ï¾ó­·_üÅ_ü½ßû½Îޏàh•ªbÿË7ýð¿ñå%ºSý›óoúj-0ƆþøÿXóA;Ž>s(@ øÇf†’Ž@{'€Üû? ô8´Ô‘#_ÿõ_ÿ;¿ó; ¯Óš–ã»­ëvûí·¿ýíoÏê”—tYýÐל̣œcYeY›ä£Š©¡¾ªF œÖå‹]¥=@u ‘NBçU€ÀAà2Ðt¨Ÿþ±þ1"B@8À¡ý£N=þÀ>p1±µ`C¡¿å[¾%’ C fÒpŠôµN{ÔMÕÊ0ZGf‰“£zq´À‚Vªêgögyä‘ÓžQ\@`wð»2†Z%€ludé ×?^»víGôGWXkWÛ§íþtK—NOñR–?ù“?™†­«¬ ³TÇQ½8Z`m8‹Ôÿ}ß÷}O>ù$/€Ž@ÿx„Q>rÙÿñÈ£¿»¾ãw7d @ Ô?^¿~ý»¿û»?»Û›Ži¶gÔi'>ò‘|Ñ}‘îüñÇãþ¾Â£½ÿš¯ùU¥ Ó’Ö‹Ù³ Œ¶[IöÏþÇaO|¡ °køÇ]Á@èŒ"¢@=˜®õŒ‘@€À²ŽèuºÈW~åW~ò“Ÿ¬ÄsÆ€R\Ð?vªÆãøÇ?ú£?º÷Þ{ÙrÙWjƒ*$€¬pPiAaRÕÚ˜®k¦~@ØŠÀý£W^Ÿ`ý깤Ï?þÜÏýœ“•y~þã—}Ù—9ÿQ¿ÿû¿ÿÝï~÷VONÚ… pøÇËp¦•­ t¶"O»'`ºžK @`çoܸ¡3¯wü(/Öéå}ŒŒÖM§ªôäõ×N¥”…œµ¼z4A²;‰æ‰Re•0»‹'3AB8þñ4n\µ½ŒqŠÓ•i@­8œ|øá‡ÿëý¯£â©ò¡%ãÖ© ûdåhã(åTÖ?ªãJ•UÂl«Ïú@@ðLƒ¶ tÚ߯zÇtml@é cùG%?Þwß}ŸÙÿíƒü ÏŸ‘sŒ[Ü£üÇ´‹QX?LìúK/½d›™U¥Ëyä·ÛWÕh‰1TRìŸø„f5sxÕ€ Ð*üc«#K¿L¡ÃLئ뎋P!@`cùÇxàW~åW*[ç„Ñ©uç7ó7ÛBþƒð¢þü£×që{ä¨^-pNÇ7¹V ³J›õ¼¢0 À?îh°õ qÉV˜®[‘§]@X›Àüã3Ï<ó/þÅ¿ØD`-Þè€RüÞïý^+È^xÁíÎõÊyt†cg¾ä¨^-°8 T¨´YR ×~1¢~@`+øÇ­ÈÓîe\]]]¦!ZÀùðç3¤@¨“Àü£¼ØÏüÌÏ\ÀU] ‰a¥è¥Óêï þqX>pýµþÄOüÄc=Vçs˜¨ œIÿx&@.‡ °üãR$©€j#pÿøúë¯ßsÏ=ú§z9x&Vò–º=þøã}½pÓRœÚ#²³Œ+é\»}2+5ñ{¿÷{÷Þ{omÏ^â °üã"©€Àùðç3¤@¨“ÀQü£Œ~衇d!Û¸}à°(ÔYâè­6òC…Ókcáv\ØÇ*ò+˯¾úªUmm Ž^°»Î—0¢‚Î'€<Ÿ!5@X„þqŒT@8ŠÔâÙÿøÿc3F¬O)J>úèIÀèìÿ(çh¡9*Um¤If…%ËÖ›aþƒ?øƒl UáK!AçÀ?žÏj&ÀŸïšG‡Ø2øG¦ ´Jà(þñî»ïþÃ?üÃf\X(Eù¾ôæÜC}Oek_a]¨c²Å$R&uaV¡•pÌÐÙ3zµ6šÔMeܺn-©Þèø/ÿò/ëüôV_è pdøÇ#þúŽÐ9Â(7ÓG¦k3CIG @ #pÿ¨“ ¿þ뿾ù˜Cû¾¸ÉJ)þú¯ÿzÚÙЋYáH“Tùò¡¬Ú’^*£°täÏþì϶„:íËW~åWêS:/"€#€ll@é eÌýÀ?îw숀† Â?¾ë]ïú÷ÿþß7&Å$ •ؘÝúúØYX׆©,«JïÉ„f´"³©5MÎÔ†}Åš!ÿÝßýÝׯ_ç5¥×®]{â‰'* †0vJàå—_Þiäˆ\–'µÕF¡SۈϦ+Ó€Z%pÿ¨e³Z<ûin8ÀûÞ÷>™ÖòµàæÍ›ra­¾F¤ýzñÅíºE™¬€°èžŒÌ@%"ÙYÜU=ýôÓʺMý£ª}.¹uz%=^Æ“†§jÝVg1]®ËV[zè„ ðÜŸý…¾†/œR愦+¿äæg?wB„¾øé;žùÄí?ûñ»ŸýäÄËo¿ýv-5±pÃÅð .]„Ó`G˜®;,B… Yáïºë®~ô£ç©'®†À§µÿþûïÏž`JÕ7nܘõÄÛia‰9Y?)›ì²/+à…ùÚ}5íï@%²xi;<½'4ŸêÔýiµú5Ý4@¿ªL¦uçwÜÑ _*3«! [M«~_^®:õÐ,yßóŸ’&»í=Ó—~ЯYµ/¿ö9I´´Œ~}ñæ_ºØµßy]¥_é£gWVƒ~•¿Ë®u }†ï³ò{úO>›–T´² µ¼ü¡_MEw²îÝt‡èËŸøÈgSÕºò‰zè!;YøÇ‰†b;%€ÐÙéÀ3l¦ë1Ç^C8öý£e–G@žAà|ÿøÇï¼óÎôuAFRÙµÇÙÒêp@´e¤ÿìæRm7ZI¶y,_ˆe‹Ê´5»Eg@*QImj7³þѾRêòp‘iØ úGÙ1™29G ;Y3;¾4R?Û<ê!9>}¹L¨@Ý£G%Úü¨+Ô£}F¯ó™+t ªÊ-f&Ôé„—»Q}w»ÔTAªº§tšªÍ×öå~Ú?*¤YƒHÞvÖUš¢}ZyV={/ŒÜûÿ0„3dG˜®;,B… YÚ÷2D_÷u_w¾{¢ˆ€•Œ¶ŸcO=õÔƒ>ع wÖ“pG…GÕaYÀ®0Õˆ£•ŒúG-ë–3’+LÑ•nÑê3MðY¦¤¤S/£‰¥ü£¡Åb|fͬó¤&³2q•ýcêïäìÊj‡§–ZÉòm$Ó`üc–ð(q™p²<í1ê‡Í}Z;½ ÿ¸Ó#ì‰:AQ¬L×F @` íûÇ÷¾÷½ò¸3,Bà¾ážþy=Ÿ|òIí©£uÖxZV[ç¨:ì,°¸,_‹XŸL³5ücÆÜ¶q ÿh+7Üg·X®ÈN#,ýã-I‚ä”)TúÇ2-qºÔs¿ÒdÉ•üc߆˜¡Ê¨l£©TY–`ã§ŒúÕ0]Ýq{‘óg´rÙ©‚Ù kw|Jcé•â7åÂtúeù^Á=}ÿÇl&ûø—t]ùÉùå…Õy£zÔk½cñ¸\­dlgi{«ï¾S]ÓUÚ›2*Iƒ·YÖ¬ÞõsóÌàñgär@KÀ?.E’z @ 6íûG-ºùÁüÁ•­Õ…Àßù;çË¿ü˵íc…7eej¶¯wSâgçÑÕégHoZ+.11¤áV}^¿ôÒKu¾9À?Ö9.Dµö\Š$õ\€þñi€6!о”DøWÿê_-➨Z¤ù“?ù“G;ö:^›FÕaVÀk–3‡8ZI4ש ûVË–…U2Kcœâ;n+¤Åý£») ™ÙÃ)˨mßì%1õëð~‘]J=ç5Ô©é›â¯¿’_åæ¶õ}&·3ª˜ï{ßûVMm~ÛÛÞ¦–uÞî¼óÎMÞ…Ð(.@¡sÈ4±¦ëR$©€j#оôùׯqƒÀ|þÌ7Ž© íæFóÓZ­K$"ãµo´’)þ±sýuy§îI6õŽMßËWêáýÓVæ¾ÊKA¦'G— „Ë ;ÏŸ™Ûngz`f?Gý£ÏŠÑW)@—]=7ÿñ4ÿ8—a3åÉlf(éH'„cG˜®;,B… YðKH)ê8 ûG=ÇŽ© ½0yÀ?–¬íd!ã…i´’aÿ¨Ý$;Sû6…TaWØ·qd&F;å£Ê ìXn9ëUX…Sëç­!;—-!Ô7ʤ ¥ç¶Ø§ç,cÈádÌ‘¸‰ÎUáÃZ³ïü™´£ë¯åC;wÒô…oÙs³gGѹHw]ÿ¸ëá#øQQD¨‡Óµž± @X–@ûþñ…^øº¯ûºÃø1:º.y´W_}ÕOÂ*ÈQuØYÀz.N¡­dØ?Þ²uoÜÒ—ÂN·¨ (Sõ9ì2£!çrªÚ´éÎõÚº³ÏcÊ|eg¼8O0NŽv:d¹G¡® —çÃ^÷n:Í4ðÃòш:s9ÝJzRvöWmÿØ×z&XU¬oGÑeÿÖV^þ±ò"¼3 tÎÈå—$Àt½$mÚ‚ Khß?Þ¼yóïý½¿·®”Z³öŸþéŸþ¢/ú¢üÿñš¬^÷¯þꯪ_ú¥_ºzKk6ðÑ~ô®»îJŸŸGSV‡ÖéM¹ÆÒéµifzrôh%£þÑ«ªKÿè¼Hß|øŒ~ˆØ¬™Ò2.)1êÜF—Ïn©mô¹Ø®DzQ:2ZÉ^µ2"í¿d•ˆ§/g;fë—½£%]KUàRþQuº~Gâ&´Ÿã†à{¢ŒðRk–<•.L¿n~ösqyìSiëª õƒ÷»ÌŽ¥~Ëh¾‘8™f€–KÅGóUa´î€-pU³Ž I›óΞ:4é’zkk ÿXÛˆϲ:Ëò¤¶U 0]WÅKå€ °!öý£àÞsÏ=R kŠ©ë–³Ógãþá.ÛÐ)Ìßó=ßóßñr”þð‡g¡k;oY=*#u8½f×ÙY^þQ™UÛôv/SR+¯xàìéz()'YSÞ‚‰Ž{Ò£’þ)%=ûtgˆ¼ÑJ¾`¯’«Ò ؘî)©GeSu¨_³DŲŒÊ{a¸",Í£ïÉ*QI™Çp¯eÇ9°Ñ¤\˜¬¢œÍ£~-7O”´©Œbrg‘8éÎÉTUˆéW‰cȾ䢨ù•­—ìs/Ò¾¤Š³üû·Tþ£jN[w/2ùèYqÎöþý^°iüã‚0©ªB …ú0]™€ Ð*CøGòÁ~ðS;¼ýÎïüŽ´nYìO>ùäßü›Ó[¾9»pb³kÓzôPTò/ÿå¿tÍSªÕ¹±®¶¯¼kS"ç”Úê,óã?þã=öXùZ ùð÷úQa¿¼dßçÍv>Tìp$ÎVeN8Ûz´Úó diñkšÿèVä:¥,;9¥ËºDÅÒzJz4«J”:+WëJÒTÓúž­|wx£§ϪþðõžC¡s=®½0¦ë…Ó \ŒÀ!üãÕÕÕüÀÔ©´†£’9-L_8Gדytváÿïÿ}J7]Xße ³[ê'úÇ?þã?ÖU© 팡ϥN ¸’2òJ:NýbON àœµ:)0-9¯36¢Êø|¤2Uöh ðGñ£õWïÖeú»_øÇýŽ‘C€À0CøÇ—^zéþÃX‰Ãš†E¡„cz•Ó ËlG¹È_ù•_™R¿«•^.<Å?*6צ¨l!ò%ùýÐM ²Â2Úü1[YÌëËV´[ŸæR…{ö)¤ô°ïMødÛ5–¿nUÖ,²/I ÿxIÚ´@`€þ‘é@­8„ÔàÝ{ï½ÚÙ°B¥5’db§Îë”’³º¶ ”£TmÚ†RŒúJ§sN_'>«SkÖ~Åßê Áû¥œµl È=öb˜Ë³{Öhtuêß JVU^óƒ_6füã²<© €ÀÉð'£ãB@¨œÀQüã»Þõ®Ç|mEµlý’zÎ+̪µ=<'‹pAÿ¨Å×Ó÷‹ôÊñ‰J. óüÚþí¿ý·ï~÷»+> àO€Æ%€Ö €\ƒ*uB€@ Žâurñ;ÞñŽOîêæ“¯¿ñ¿1‹:Ö;ŸÜ›ðÃ5D>ãĆFËèCrÓ¿üË¿<±ÎzŠ}õWµò×ð¤%@ËÀ?.Ë“Új#Àþµñ À?2= @ UGñ¿{î¹ç÷ÿ÷ëñY£‘ôYBk>§F*£p´ž²ÀVþQ‘Dòæ aoxÉ‹/¾ø¶·½­ÕWúœþñà ùî#tšâ–:Ètmi4é  ¤ä¿ë»¾ëúõë:¬¹M[ÕýÂ/üByá?úGÿ(ΛVšä\ Ùwþu–k9šÏ˜6¥¼ Qɹ4¶-¯ÅûZÂÏk & à›V::L†`ºîh°€f8¼qãÆÛßþöm5ÖôÖc©r§T=ÚÿÑÑ7YÈé‹šÓ £'T¦Nñ‰sËïÔ?jæhþÌzjQ€À^à÷2RÄy„ÎiܸjL×M°Ó( \€Àü£h>üðÃ?÷s?7]nXRÚÑf°Ï?:6YH=Ÿë…å"õszKí¤ý£²ʨòõüc&:7ä<¥i¥Í*yöÏFš€ ° üã&Øiôb:CMCç`ºžÏ @ NÇòNüÄnÏ<󌭢~÷Û¿ýÛ]øoü¿áÂú!MlLÒ£í¯ý5Ý£«†kvµ*<€ L)ïÀ"Ή5oXìOÿôOï½÷ÞW_}µÎ'0QA8Ÿþñ|†ÔP3„NÍ£Cl¦+S€Z%p,ÿ¨Q|ì±Ç~ìÇ~lCŸ5±éYþ1Ü_øJuS60½éžhzsÿ¨ý+'rؼػßýîk×®µúü§_€DÿÈ4h›B§íñm¬wLׯ”î@€@8œT"ÛW~åW*©ms±5€-á”üGUõÛ¿ýÛÓËoîGS/Gá\¦ÀïýÞï)ùñõ×_ç%€@Ãð .]„Ó`G˜®;,B… YçEGélJj»ŒÀ:§[Â4oq 6mï8}½ö†þqbÓçp[ðÚïùžïyòÉ'g=£( @`wð»2žEàêêjVy C`CøÇ áÓ4 ¬JàˆþñæÍ›o{ÛÛ”Ú¶ ¨Z£*o•¨SbÒÊôG´3yP+š§ïÕ8QNÙÏ1mJùéIšk Uç¯þê¯>ðÀ$?®úDå€@ ð5Œ1@ü#Ó€Z%pDÿ¨±|öÙg¿å[¾e–º|a™Çò¨–p|zTK³uûÁüÁ/ýÒ/uòãÄdIK@]•í©_Ó¢­²˜4¨(ï2uª<îÑ£)7oj9ý@›Ë3µBÿïxÇ /¼Ðê3Ÿ~AøG& Jà+€ Å Ô?Š£ÏQ.dµ·ÿò_þ‹m]áóÏ?_žmÖob_ì;oisÿú_ÿë¾bŠÁmÅÑÛ%ÿþßÿûiH.×NŒv“bßömßöÔSO-þ|£B@À?V8(„“þñ˜ãN¯!Àqý£F÷‘GùÏÿù?o¢·&6jQøó?ÿóYy©Iå?Jäù&QxãÆ‰uª˜qwÞTUf ;‹©“í«J÷+δ¶XQ>=ÔMJþÈüg^áåïœ>>ýôÓwÜqÇõë×Ï©„k+$ çþË/¿\a`«†¤\om7±jT °ÿã†ðiz.üã\b”‡ ½8´ÔÖ~>øàsÏ=·‰äšÒ¨ò½ä”Âõ—±N•²¬9Ô÷¿ÿýš{y9NI"©"I@Ýzè! Á”†zôÑG‡=²ìa_W~÷ÝwwV®†î»ï¾Ûo¿=mQU•7Ðl×ý¦²¯u•û5ªk©‡æÎwMõ?ñÄ™hs…ÙíÅ_,›Ð®$Ã>7˜éåUg0Ó+™RRêqŸR²¥2zYæu¯¥¥/„SbG˜®;,B… YíEJ‹Î”ôñ‘|¤N#Ö¹»ÎPG£úøú_èCºÿþû;]Ϭç…×& %O¤¥ïR„þYB-Úõ=ÙiTrmQ&³xª'*×þY­Äå¾V 2U„&»©€ g²R÷ËÜù’’UZ^ŽOÅRå’𥠭MÝ®¿§5»Âì–v\M«¹¬˜*‘ÿ>â%%EÕç1%ec¤Ê˜Ý®d¨«-ëñåž*,Ð=ÑÀ/ :§[¼¤öùÕß¾´Züãâ©°*ª†ƒ`† 0]™!€ Ð*£ûG«Ö}í×~íþᎴM xÍr¶y“HÎlÔ¹œ²gÖ³ÞåÒÐ’Ñ/½ôR«Ïö–úe– Ç,Ç0S_.›MœÅVªðT§%WVyª¨d»T&U]ª¡Ï »Ê’ @§!•ùÒýö‚þÑU åšbV )›ÜüÇоºÐÅA5ÌÒ ¦¹¢¡SŸë¹"X‰¹~•èôeVÔ]+ïW%®?&¿GJ1gɪñ_‡R.·ôÄq_ô*§´h׎èþ±½Q¦G)„óaG˜®;,B… Yð·p飗äoüÆo|¼¾›Ó%ïê mFD¿ôK¿¤^ȥθæ²EuTwö|Ö‰Â& £”¨,pî[çv~ºßË«3wf;V&¦•dJË.oÀ?Êše¶T—„ý̼›åfØÏý£ÃØÜ°ìWFµÔ¾.0kÌrìäC]sšŒy£YJ£DaY8ÔjɹÓ?væ“FgG9\x¶¯Ñœ0êß-Ï<óŒ+Ç?®™:ë!€Ð©g,ˆd”Óu @`§ðŸ8åƒèÃØÏüÌÏ\ÖzMjMçÏÈßM*Zq!õâ·~ë·ê ð§~ê§4ú¯¾úêNŸÆ Ûòn ã–\^ã\®v’£ÏIý£Ý_™ˆ×)7Ó;‡ý£ÃH3 -ל͗u$s¦õøGC;oÄNwË¢ƒª¥m§(,—®›’4hYù þÑM·½[œµòÃ?lwŒ<à«è¡ºŒÐ9Ôpï½³L×½ ñC€@üãÈ(DÆtöqŽŒ¨V" ­Ðtº>Šó2±#^ó+QØ·Ygx¨NSN*óþuøL«ÆÌiûGͰËó èLuemAÿè¶ìêpÞŸ™§ËÒO›0}¹«/Ž 2±¾lMT(BS žÙ¦–©á)uÊ£3|xÑi}¯ð*½ª§øÇ ‡†$€ÐY&U­M€éº6aê‡ ­àsòú$ömßömýèGW²]T[ÀðŽw¼ãÉ'ŸÜêé·`»Ï>ûì¡v®tºœ$‘¾K6•–*$W¹öÙÙsVT™v^/çHfyy!%ÓÍÓ¨,ï—ÅñÙ™ê*åæ‚þ1ŽÜQ¯;5bçþ1K3åwòìíóFbw8Å5Ût2ü£|tvá ùŠùäþÖ¡^¿é›¾é¾áê•!p„ÎiܸjL×M°Ó( \€þ±òSO=õÕ_ýÕu®Å®GÞí=’ýÑ}ÛÛÞ¦¬Ÿ <ÍÖnB›¸éÝê—|É—ü“òO<Àí}ï{ŸÊ4¥§9gB0$—¥[ºj8]àÜé‡Ç˪+ówvšÙ-Ý¡ÒÖ2Mîó£YxáÑ"†ý£›³¹³ºÍzaé-Í‚Ó'yŸ´õ3Â3°Åg†%åæŸÃcvúG÷%nÙäm}zg÷Rò‡ø‡ïºë®¾lâ½ô‚8!ÐGàêê 8Ø üã^FŠ8!@`.üc71eÆi-ö?ý§ÿôñÿœ[[¤Š¾æk¾F«›Ùðñ»¾ë»ônU7å1ɨ6ÓÓ3ž·jqtX¤Ôd©dzîJvºñ ù¥"T¾3;U9=•%õŒþ9¢MY¹zYÿhnqhu¶Ü>.;ÿ:P/ⳡI_Ó‡Šù’ÌgééˆgH;Gª\q’ôñÇ÷“ë7)ȹï!(@ËÀ?.Ë“Ú @ øÇ¡±Çѱ$ßú­ßzãÆ¶ÜA{£C®å”ßùÎwj@ëyžIøÇ6Ò9O"Óç„>_›Ù«ta¯õSø¦ÎýËïӲR6|ªrø;çBF+^!î_U&ÛŸq ÿè˜}ZKº*|Ø0f¬N¦rhÒJ²…í³‚Ébóˆ›d§)Ä@öåi}¯ùª÷¿ÿý’½0Ö œØ ôÀ?27 @ UøÇñ‘ÕâV-ÔUºr¿Úò…^øÎïüÎûï¿¿IC‡´f ‹WfÏ…ÌʼRæ­¬Ëó²Kÿ˜ ¬K׆gôð¸?éö+»;}Yšå7þBÖU¢óÈ—¾ª²Â§µ8Øèú£ûÃþÑÆ›¥£„NðNP=ŽÔ²k½6~í×~íicÊU€ ° üã‚0© €ª"€œ4:Y+[ï½÷^­Ûýþïÿ~¥Ñí×Ä*r-Ÿ—8Önž2Èï}ï{' ö á5h©®*%—Ý–Wé¦çgÞÊÿy r6Bu¥Ç×D™)þ1<£êO÷£tðŠD‚2õ’®|`/ÂóDg‡ó WèøÏ´r}þÑÊ/íþÀqÛe$¥tUr‚tÙíð…aRÈ’Ú3ö§~ê§ô}Ò‚À °ÿãí¸!ã;öô€@ëðóFX)z«T‘{î¹GÒç§ú§¥óvÑÙ?ù“?Ñgie;j9¡–ÏK70ôÑü£dŸÜPºg_èE?ŸKÉe‹—®ÑvÉÒ[¹*‰°t÷FµR²SNñ!I3ªûÙ—sWjS]â8G×Ç œÂÖ%é‘Ü¢”eŽ MãÒ÷ô  „î^´atúGEåšS5lXºà8ú< Îµáæ–ujÊHu*æy*vRÚòQ×”ŽÜÉ æ):§Pãš0]7O³€ °:ü㉈ut‰>ýꌽKPRä?ÿçÿ\y‘ÿé?ý§_xóöáøcû¹ýÐýÐwÞù?ñû ùc¿þë¿´¹øó7³RÕ‘GyDÙŽÇ9Ëõhþ16.´ZÒ-ËËë”\VTÙîŠÞ*´IëO³áJO7ÅjÙ3ZƒJ¢¥/=Þú°Ï'†q³ tBßÜTÄHít QIºÜ;ª2ú!K4±ˆ$~MÍæÀ«ª‡F—‹˜nJÀŒHÊeïá‚õC”wSÆ1%OÓ*;ÏŸÑéˆtnñy⟊Š/ ù¨ñ¡-@¡³Dª¸¦ë¥HÓ \šþqâJёʋ”öR ‰oJ¾;Ây©öQ„ƒ¶œø?ûì³Í§:vÎ×£ùGAí’³óêZ©¨lÏDBJ“étl”îÌ4™Êt¦ÊFé~k8ý¬¥´Òª\¾º×N ͬ®{”ÉbËëò–­ÊO•å(Ø=Hå#þq#H̳ tfá¢ð¶˜®Ûò§u@Xþq=¶{ªÙ‘õw{³$ÖúÇmGʉu™ßÜ6¤æ[WâäÄ%Þ磰œ=¿žjkÈä#þ±Ú‘"°¥ t–"I= Àt½dš€ Mà7Á^]£øÇê†dN@øÇ9´–)ëÔ¿eꢖš(ãRrù„ôÒš:1‹vQÚ~Zˆõ×;>B=Bçh\²¦ëVäi€Ö&€\›ð>êÇ?îcœz¢Ä?^~ø¼E`¹à÷ò‘¸E/Eï»]&›¯†Îço†ç׳¯ðû/¢K¡3—å7$ÀtÝ>MC€Àªð«âÝMåøÇÝ UW øÇM†ïb˧ô®÷WC SX ”ÑÂdÉÇrÉ3«­ÿrücýcD„ç@èœCk/L€ézaà4@#€¼êªÂ?V=ø 8öHÿ¸ÇQ#fÔCÿXÏX  ppøÇƒOº@ aøÇ†wF×Èœ«¾¢øÇúÆ„ˆ °'øÇ=±Î'Àþó™qÅf𛡧a@X™þqeÀ;©ÿ¸“êÿ¸ëá#xlNÿ¸ùÀª:«â¥òe 0]—åIm€ Püc=c±e$øÇ-éŸÝ6þñl„TCÀ?zøÐy„ι.2]ÛKz@o%€dFÜ"€Üõ<À?îzø›À?n>°*„Ϊx©|YL×eyR ÔCÿXÏXl þqKúg·<!@àÐð‡þt¡s€An§‹L×vÆ’ž@€À[ à™·àw=ð»>‚‡Àæð›¬J¡³*^*_–ÓuYžÔ@õÀ?Ö3[F‚Ü’þÙmãÏFH84ü㡇ÿGè`Ûé"Óµ±¤'€ ðVøGfÄ-øÇ]Ïü㮇à!°9üãæC@«@謊—Ê—%Àt]–'µA€@=ðõŒÅ–‘à·¤vÛøÇ³RMÿxèá?@篮®ÐKºØüc#I7 @  €dRÜ"€Üõ<À?îzø›À?n>@ÀðÌ@h•þ±Õ‘×/üã<^••Æ?V6 „À?îlÀh—þ±Ý±¥g€ŽNÿxôÿkÕÛ|{$€Üã¨3ê!€¬g,ˆ88üãÁ'݇ Ð0ücÃ;£kä?΀U_Qüc}cBDØüãžF‹Xç`ÿÇù̸b3øÇÍÐÓ0 ¬Lÿ¸2àTÜÉ@u‡‰Üõð<6'€Ü|`UUñRù²˜®Ëò¤6@¨‡þ±ž±Ø2üã–ôÏnÿx6B*€À¡ à=üèûÊ+¯8„Ì?¾ôÒKÏ<óŒ¬ÖwÞ©‡ž|òÉ‹GJƒ3àgÀ¢( PÀ?2)Ú&puuÕvé]Kð-&} ”þñXóA)VŠéM:Ò¿ê‡òÑ{äÇÊg þ±ò"<TNÿXù pøÇãŒ5=… p4øÇ£ø_9rúäÇú§þ±þ1"BÔLÿXóè p(øÇC 7… p(øÇC ÷­Îv¦@öéH’w1?ð»&‚„@µðÕÍÑ{ñÅõ_Ò£õ:ëï£>zß}÷‘»<òèÓw@mÀ?¶=¾Ý½›žIòã.æþqÃD¨–þ±Ú¡9Z`wß}÷wÜqN¯Ÿ{ã–ÕpáýeQçváå—_ŽKžxâ‰Ûn»íé§Ÿž[ å÷H@ïÉuØc9þqãHÌ€ 0…þq ¥ÖÊLL$ùq/ÜËH'ê$€¬s\.•­_vKó³ÊÎ+íØ@%·Þ¤ÛÜSÕ)ï–¶«†|iiôÔœîO=ôÐCºG5è¦T :ÒeŒÊC̆ÀeÆEõ¨]P^«{tmy¿js_Ò>fñ_l&ÐÐå ܸqãÁLäèt½|´@X„þqŒû«dJ $É{Wüã^FŠ8!P'ücãr™¨”-ha×çËÖ|ò}áp%’nq³ÂKï‰Ô?ÛÆ4P!Ù'¦2Ñê¡TêZ“ÄÔÍ.2!G…NĹélô°´a4œNÿØy¿û¢‡Ò´ÍÅe&­lB S£Óu“ i€ p>üãù wYÃh $É;Wü㎋P!P!üc…ƒr±¬ÞV=—tE[¸ÂÑJ¢;™7L»išÞãÂv‹‘&Ùé‡Íà¨Ð)ãW>ZYç@+6†òžÎâ<Ó?–© ›4´ TAŽN×M"¤Q@€Àùðç3Ük Ã)$?îh\ñ;,B…@…ðÊÅBU‡¼Ê8RöF+õ®!Í©Ô%öZ˜Ü§&]íhë£B§³†2-qÀ?^¿~Ý6ÖUéUOÙå‹M Ú„@(ÈÑéºIx4 @8Ÿþñ|†{­a ’äÇ} *þq_ãE´¨þ±¶¹d<£òî2þQÿHrt d*õ²/‰ÿ¸»!#`TEÿXÕp\8˜Î£cÒsW²³YâLêtCÆÑJFý£u[zøŒ.IœÄb*K=çã_l!䬅¿¯õÍ{bfñ\Ø?–BöÂsƒæ6! ÿ˜ˆ½I4 @Xœþqq¤;«°L$ùqgCHþã!PüãÅDÉM¢]Ïí•W^éT‡åÙÖáæüC–¨8ZÉDÿ˜ Dç"k;ÁÎô@=d=ê µq¤+¼ººâòükop™õô’þѾ՜5aÔ…znzë(AÆm%ò÷ß¿².öºDC€ ËÀ?^†s½­d)$?Ö;Tý‘‘ÿ¸ÇQ#fÔCÀþÑûŽq[•€´ÂJÎâ´jß÷¾÷.Î x£Æì êÑJñʸTÓÎÍXž, i{8p¨wöìëŒßÍ¥•\Ò?zxþQÿ¨®Ç¡·‰^‚¾ê«¾êƒü`=#ˆ€ °üã"÷]IšIòãÇÿ¸ÇQ#fÔC€üÇzÆâò‘ŒªÃ²@yÌh%çøÇt´Ï¤~úé§G·Gœâ #ª¾ø³J¦ÔÙwþŒ½mçö”}kÏY}ù§Ãæ-¾ð òJLÞ<€ ,Nÿ¸8ÒýU)$?îoðÞˆÿ¸Ó#lTBÿXÉ@lƨ:, ”§ÁŒV2ê±Xž?“Ý)ó¨{TxÔ?vJ½>ÂðnB‘—1tjÍÑn2[htUO=õç_¯J˜Ê!@`[øÇmù×ÒºS I~¬eóÌ3iTN×Ú  ì”@íþñsÜ Ð"eß\âwúúKب„þ±’8xNús:á²·eÿæ.m’'Õ\ išØœÀî¦ëæÄ€öBÿآܢOÕXöÍ%þq//¸Ä : àë—Få}—í¸V@ëo®÷[ì¼-ÛÜùµÙÃf'êœ_-5ì…À²o÷Òkâ„ #À?Voª°E˾¹Ä?áÅš>B`=øÇõØRó,ÚOþñæÍ›³®.¬\BýÍíÜœ±Î3¦œ»«jÙ·ˆ»ë>C€@Ãð-Ê-úT=eß\â~¦k¸üã ÓĆ–ý›»aGhú˜®Geú@à˜ðÕ›*l‘À²o.ñÇ|ù¦×XŠþq)’ÔS'«««:#*”–}‹a@€@=ð-Ê-úT=eß\âëyI%ì‘þq£FÌ€@“–}‹Ø$":@;%€¬ÞT`‹–}s‰Üéë/aC øÇJ‚0 ,ûž€ zÔîÿ’Z$°ì›Küc=/©D=xöÙgßùÎwî1rb† Ðeß"6‡î@€À® à[”[ô©z˾¹Ä?îúU˜à!°9÷¾÷½zÙ< €ÀJØÿq%°T»eß"®!uB€N#€¬ÞT`‹–}s‰<íå« À?2Ú&°ìßܶYÑ»Í 0]7€ •à[”[ô©z˾¹Ä?®ôúHµ8üãAú°Ý\öoîa1ÒñË`º^†3­@€Àå à·7U¿ÿÉ¿øÅW?ó›þÙíC!‚KXöÍ%þñò/´–à[MúRXöo.„!°*¦ëªx©€6$pÿ(µ'Á×÷u)ãÔÝηüÚ§nÿÙßöžéëû>ôéщ^ÔÜW&åvr`)ö¾JTf¸þ^(È>u;ZíÉ:ÿÂeß\â7| ¥i4@ÿØÀ Ò…ËþÍ5V%Àt]/•C€À†j÷±Ä-Ÿ5_ö%KµD#§Ôñ{Ÿø¬bû_~þ¦bxê^ÿ-Ij6Õeµ¢&²(ßþKŸLáèçïüÍO¹Œ‚IAé¡ôщ½ý7¿ýZY‰îL/W‹*íGhViVÆ£bÕNŒ½b˾¹Ä?nøJÓh€þ±A¤ øGæ@–}‹Øz@m8„”ÛŠ¯ðhqÏzŽi´æõ™¥ž£Zùw¿ûiýœ9>Ý£2_öÁOèQ—ÑϺǂϱÙ9úËå¥,Gû†L¨«~µîT[Y™Nÿèòq¹Ð÷Eü£B:Á¨NïûpÉeß\âÛx9¦ØŠþq+ò´{ËþͽLÌ´rXL×Ã=‡ нßë‚ÝbߊcûÐ=m6ûÖJ»›©c-eÙ€ì4žº­ôÞV2e8+ ´LÀ<-ÿ1F3.<¯sðÞå‰jrÙ7—ä?®ýBIýh›þ±íñ¥w€ÀŽ,ûqG'T@hžþñ þÑ'¥ØC…@Ì Óc‘²,U˜>«½Ô¯éÑôWåW§þÙ0Óu:+JB€À¾àçùG[­é믵Ëaêø²ãkJõ–¹¹°~iêߨôY1i»añ¢B;5¥7¦5ëé<›¾•ü£€83tÞ€TlNHØ—ÓHUgÉy8y3NÓNÕªƒI·¹,Ѧb³«–}sIþã¾^v‰µÀ?Ö6"ij,eÿæ.µA #ÀteJ@€@«j÷ŸYúæ³\ÊZù[>îƒòéô¡—>þù•¿²u* k}¹~v1•×Uñ«ïL›PÛ¢2ªÄ6-šp£ÙåVœªD÷ëK¿Z8ÆUÙ¯e_^ø³ÏoÝ耕_Z8Ž‚I‹©¤.®¥íž0î N#QÓ„´ŒJºÀ?øÀçwÃŒËýƒîîˆÍF³Œ?ŽRsß{ãS1|Áßðõ•¡;Evɲo.ñ­¾@Ó/\†þñ2œie+ËþÍݪ´{L׃ 4Ý„ p@‡ó2J™½²’~’²zKo?ûÊköwú’@üÓO½®ËÃU©¼_}aÖ„Å¥kÐCršQ¿¶•ÔCúž5*Û—XÆ¥)€Ôßuº0…îLíêÝS–TCzȱ©!u0ÂÓáOÖm¦—~)ª,’²L´«x²Ë;ý£Â+‰¥œûâ— 4g}O£J‡L|ÊYq2¸pÙ7—øÇ¾vÓe,Hÿ¸ LªªÀ²s+ì !µD€éÚÒhÒ@H Î?žoލçXöÍ%þ‘—u@àøÇsèqmý–ý›[‰pט®»>‚‡ øÇóU5@`6eß\ây•‡Î!€<‡×ÖOàêêªþ ‰&°ì[D¨B€ê!€œmޏ –«w.ŽöÙšt e–}s‰¬ç%•H °GøÇ=Ž1CMXö-b“ˆè ì”þ3v ï\9ðUnjyJ3í^³ì›KüãN_ •À?V2„@`Ù·ˆð„ ÔCÿØ®â¢gXöÍ%þ±ž—T"À à÷8jÄ 4I`Ù·ˆM"¢S€ °SµûÇ×¹A E˾¹Ä?îôõ—°!P üc%A+`ÿÇ•ÀRí–}‹¸F„Ô @8þ±E¹EŸª'°ì›Küãi/\˜þ‘™Ð6eÿæ¶ÍŠÞmN€éºù ¬DÿX½©"À ,ûæÿ¸Òë#ÕBà ðèÃvsÙ¿¹‡ÅHÇ/C€ézδ@—'€lQnѧê ,ûæÿxù—NZ„@Kð-&}) ,û7ÂX•ÓuU¼T@À?Voª°E˾¹Ä?nøJÓh€þ±A¤ –ý› j¬J€éº*^*‡ à[”[ô©z˾¹Ä?nøJÓh€þ±A¤ øGæ@–}‹Øz@m¨Ý?~š[õ~íÕ×þ×ßúdõa~úwÿüÓßñÂ'ôõ3/jóh—}s‰lãå˜^@`+øÇ­ÈÓîe,û7÷21ÓÊa 0];ôt€@óä¥É¬Ÿ Ô@™ô!é¶÷ÿѸÃR±´EÕ0 ½~ü#· ÷•qU2h·«ßùÔ@ ë75zÛ{>6È"1üƒÜÔ×ܪä¿ègþ<¾æ^¾xùeß\⛥¦ƒX•þqU¼T¾9eÿænÞh›Óµíñ¥w€ŽLà(þñ?wSŽ,ô“~Ö=™T’ÕÒýQL?üÍÿöñ‚úÙÆ—j“òë3SòqYù¬ÂìBÕæe…’X_s–€}5,®ÏÒ /ì=ˆÀG?ñÚõéÁuæã°Æ]•UT¾ì›Küã‘_Äé;Î'€<Ÿ!5ÔLàêêªæðˆ )eß"€ PCøGYB‹¹ORfYõ¢¤dG]¥;UÒÎÈt§l—¾ôƒ¡ò;•ý£®ry}ÙF›µÒŽYð¹¹>ã©GU³¿_Æ E+ö T8NlÝp.Lf ¹eß\âëyI%ì‘þq£FÌ€@“–}‹Ø$":@;%pÿøM¿2²@ث̈”?Rz]êSóZsØ?¦Zb–ùz¶c®PÑf:<Ýß§}¡•hóþ±Îh d–5¹¹ˆ\öÍ%þq§¯¿„ Jà+€ °ì[DxB€ê!pÿèÄõÒ}‰‡£êpÀjEþãh%JxT=ÖŽÚ?ê»;RîÉ}£þQK¹]X_ÊÍNbQý–°jËe:¬u%®a QÉ¡*™¥ˆêª¬ZWªw4ÈÈ]Õ±n]5¤)®ÝµÅâtýœö:úâÎflˆê¤qšÊ\öÍ%þ±ž—T"À à÷8jÄ 4I`Ù·ˆM"¢S€ °S‡ðN”?ê<ø¸S–R©L]´7ìË7쬶St:=ÓæË†1‹3ü£î/ó4u¡í¤õå@þ£%š¾[e:˜Ô¸YáÙ-ª€»œUèh³IŠÇ±¥KÝÝ…l)tj]§—ŸæÇF½ßa¤ðS úù„soúìä²o.ñ;}ý%lTBÿXÉ@ÆJØÿq%°T»eß"®!uB€N#pÿ^Ïò.³{>Ý¥\õœ™£Ò?Ʋè)û?ªQR6”Ú·NÃþ±3AÒ&Ñ»FûGyØtsIkÙØà2ö¸LSs¬n¶OLdœÓ·:Ëè´¾L«ëŒÔÂ)A¦úrâþeb©U¯âá3ü´w!(#7ó´lÇòªeß\âO{ùã*@ÀðÌ„¶ ,û7·mVônsL×͇€ @`%Gñ@2M^«›¥¦voÀ.YEùü‰ª8P»ÏL•ç_«õò°;¯TJ–¦,Ð?§kÉÒèȇýcÙ»¬¼3Óe޲l=ÜnŸ´p çëÓµÌ6˜©©ÊN’9Ù?–œÃÀ¦‡žg)¢øÇ•^‰¨ØþqCø4} @¦‰¥0]—"I=€ PùG›#Ÿj¦¹ÍòÖ—±¹<«:üTzþu$?––[:–K°Ó³Eß™¼›â˜®RÞä1K÷ËVF»Ù!à™j6€®Á‚ÕÁ{¢¡Ì'àô OóŽª×2´3¶Eä²o.ɬ텕x °/øÇ}ÑÎ%°ìßܹ­S³0]gá¢0 ìˆÀáü£åQ$3êçrÕm§`JóGO[¶Aë\Ì›%ú9%3ö´ðÊöLÌ ©×D;G/dÃþQ!¹¼‹•Û;–ºí|ÿè¬LÛFŸÐ- é¹ iþ¦¹Í òÿ˜®=÷ »¶X”ÜÑk¡B'À?žŒŽ wA¡³‹a"H`º2 @ UõeFa–÷W*ÈrÿÇá<¸Ò?ZtvÆ’úǰoQæ½&ÚYf8ûG{ÀTžÎÍ̶ƒLÝ€“OoU©«¼ç£4Ÿ»-'Ÿä9þ±ÓJ¬í†ýc4m¹ûúʲ)OÒ(|_ª7&†¯Íü¬BÅ?N|¡ °køÇ]Á¸ºº-CTBÿXÉ@ ,NàþÑzQâ̺M:/’3U')&›¦2*œ Ê'_ºu`t,Ç]`«*ŸÉ5Ý©{ìÒ@…isÊ TÉl™¶ê)+ïl1 U—HðéË×f•Dlq‰ú«:³ÕÍŠM5ˆ’+qxÃdÜÙ,`ÝÓ©_ç©e(•g¤¾L)yZ™Nÿ(Q*ÝÓê?ÚUú¬ù¬!óí¾ûîK èW ¨ |–vr™n¥`Òó%«<“eYâ­ QD’þ 4u;³tUaßs'ŠÏYGxš,p¹Ã}«/ COCÏXÖwsÖžŸ¶|¾pú¤õk—nׯ_Ϯʞ¹¢{ü¿ÝæþÓE—»¡¸TÆy ~“IkÈ8cç˜:òÔlöM’éè(ÙI`Ù·ˆëAÖd¸ð¿ú^Öë#5C€À²ð«È'@yÀo|þ㵇.´4üGÿç¤ácÿ×-“¨ïéå_úþ[uþØï¾åÎ(ð¾ßÿÄmïù˜ÚUµiU«tor¥ŠÄ½³ý¡ßþDv©Âv¿:Ë`<äÔ»ÉW]pÙ7—øÇe_©í¤cô¡Bcæ~ìOãìü$œÞ©èß”¦|”êÌ*šë¤L_Õ¨NwÐÒ?J>>øàƒ7nܽ–Ë;Ý4±åqa¤aL$êN÷%í¾û¾  ¥XÚÌì™›ý—Å*yú“7bŽHM¡Ò¢¼zZúr‹éÌ6ÎS³=Í2OœÇ,¶ì[Ä•<ƒVjQÕ¢¼×cKÍ€.Cÿ¸¼¥² Ô—”Y_íRi. Å&§ÎåuM]›Šéé¼¾ }‰š^¾?§Öè>ªkŠM_v²ieÒ‘†à2¶º'Ä«kÐwùQýpjD]·ì›Küãe^.ie%‘ÑàÏÒÙ§ÙÎ…ÌÎâqIëKëðŽŒVQRR‚Τ*çj…ÖIu€ó­ô=ò†ôkºOe 7­[jv²æ"T Eº\ô"tU8‚è®P i'o7™ùGäã9SÝŽ)ÍI”GKõ<pÊv@~:¤³QSËÓ }ލr•Œe°žÌiüFIÅüÔÈžt¾S·,Ör3îœåª&"õs$MfL/œèËKÊ„¾eý£_2—g¼épœiO:cötJ]­ïéž ´4Õ¦³ÆÔñ,¾oïÄ©Òp±eß"® ÿ¸Xª… Ð6üãòNÊIú.YVfü©=é¶R&jÅ´îïôÊyõn®ó^©Å?*’²) [ZÊb–|ÌücZÀT<ìòùN˾¹Ä?¶ý2ÝvïÒt-§>eIarü!ÙjƹNþÈíÜ®Xé;]§²ÐÉ$”J$¥æ£uûŸ““Z]˜%XÅ'üÌ5XK)¬«œ¼æÁõσ›p/¤²Þ…ý±™µ`µ!-3¡&NžÔ?"'Bë+6`|‰ d./­ÍÚNòôÂát¹Òp ûG;ÍLÏ©{À,¡Ïs8fø,W5‘ªU+Y¢e\{²|ûÛßž°¸ÔÇ#›nž˜úG¯ž.s$'’Q±Î˜ýr‘ΊÑ8Às“dzw(ÙG`Ù·ˆ+qÆ?®–j!´M vÿø‰ÞþÚOßJúûå?¾å×ôCÖƒ÷þÞ-™ø7þëŸôìÛí–eÓw•Q=ªP_ÔÅ3/ßT…ºäoÜÔÏQ2~V£’zY zTMè~5‘ÝtïüíW?¡ªV?Ä͵•W¥•¨@t¡³§¦ªy€ƒ;¥8£ŒÂŠaz»˜2˾¹Ä?¶ý2Ývï²t­ò“ó¨ 5S~°·|LOHÈê÷‡íòP…p n]WÅÇûÒŒ¸L™`•~2ïT«áI³¤$.³,³™`tiÞSÙ‰“'ü#òq"±böA˜„¥êt7aä3ÿèû‡S\m¸2ƒ?ìK)æé§ïe†fçÓ§œù‚SJ±)`ÓÿFd®Ó—ŸìË¿¹‹ûG…‰«ÑÙ2ÿ±Ì*Bf ûåkætÿxfþ£ZÍMï%§Xö-â”O(3Å?úß~š$úsÖù’8Z@ÿ ÑKÿo§ ñÝ'Œ—@¨Šþqa[%¡ZMšL²,kÀ|ÃÞ-õ®$upY…zÈ˽ã+¤§.TUn1µá+m6íCSè_õ¥ £€~vô…¾D_Z1݇ÏQõ‰BkÄNV[éU`Ê… ê Õ-ûæÿXÕ«*ÁL'`——*§(¦TÎô™”t®bÈÄÎÏé'œN·˜]5Å?–ki‡)eŸ²FãLõD§nÎþù8}ê”´„ÒöÞz¨œíª6Œ|æ;—÷faX'e`Ø?ú#}ªÔu‹ñd,åæÜ\¹Q¼é#Ü—lmïâþQ=uÒtz›îïÜ£ôééŸã¿Ù3ײGžuÄvæÅA·8‰(;„zzü–¼éåsÇ4ëïèS` eß"Niñ„2£þÑÿ„ðß2ÿ/0ý×HìrëôÈ^»¢†¸ÿxÂHq  ªàvKr¡Õœ¨ïivjÃɃá§ÈJUžå?†I´ªÓ—L¢ì¡¾œÒwúW7—ºÂŒÎštG|•BÒ%?úá[ÝÔWj-;í¡ªr»éÍI er訜xჺBu˾¹Ä?VõªJ0Ó xígúéW)Ù§”eýcætü©ÆŸâæLFïÿ8š%äuÖÒ#[§Y^‰™eð'ì)ÿøßù83}ê—Œó[¬·²Â¡‡lôÒñò=–nÙ\õ¬^|Ý™>4*©×Ë4¨‹)ϱ(égkjÍæºªQ¼Ù#J¶¸´ ,o³rúÒ§g–¦Z>sXêõÃ, éîg7…š»=Ñ?:ÑÕc·¹cjƒéiùüóÏ_Uy{ç;ß©·Ý–}‹8ú¼;­À°ôÄHÿã×™x=Ôkî SÛD0~ e©I¯O ˜« @ øÇ…Ý’_»ÒÎÅÂSÒ÷,f(ß7%ľTAÕé¿N§éÕÐQ2VsGÓ¾' ÆAfv5 ÕÕZnJYÆ£i‚ç@ï²N‰§ïI«š§Â2˾¹Ä?ÖðbJ 'H³ü™Ù0ÒÿkûÇΨø<¿Tþã°ô!3ºùÄdݲ,ÿXfopí{Þóž{î¹gG§]¿þúë’Þ^yå?œ›š©o{>l|³àÏñ™£õÙzÅÎ15Y³N¶™bK³WŒò¿åI>‹ûGÅé\Âô6ÑßEüÙÓÓ}·Xì{âÇN²*™ÙÃÒè~D+h~ÍØe¢¯Â4ΓýcjÉ«õÏ>ûl…¯!-ûñ„?ÍS.x2–ÿYQ…‘ðØWyv]ù4ì4æSB¥  ÔCÿ¸¤›rž`º¶Ú‰„i’àtÿ¨ÕÍ.<œ,éôùÇrtg^6î'][¶8Úp§ËÀ½Â:.é㨚ÃB†¾œå½Ü!ék`Ñ÷’c¹r]˾¹Ä?Öó’J$Ó ÄFŠ™AË–^À?Ž~à/…•†´3Í-r‹üQ¿Ó vµ1êÏ?Ë"íõßý»W/J;ºÝyçuf3½ï}ïKÁF²[še–~®ÎŽI;󳕶ÙÔÍ.ñ£mqyÌ·ØüÑ¥{Œfsr¸æü£U¹æÈÓ5›køÇòé¦4C§µÿãÁ^é‹Éðëgg÷ugð”ø=@åtš›ÿ8wg‰é Ž\rÙ·ˆ+‘x2úe­Ü€¢ïéà§|º;J߸òUh¥ÞQ- ¬Dÿ¸¤g²#ó>‰þr²a*éF—-+ ÐsS«9Á?–RÒ2127KÿèNðOq:§ó%-jGS;-UÃ?*†åÞKäúu-ûæÿ¸Òë#Õ®JÀ6ÊÀé§wP~ä(íFçGî>c be‚UÖåéùÙ¡Yا ;ëÍM¤ëa½-5VY–\`™n.†‡òG~äG¾ôK¿tGù«ÎÌÅ+ϦkŸ-JO_ »sÕb(Û1 Õe²%½SücxÆØüÑ5‡Gð,Í„Bç¬ö…3v¬-|×Jè·è¹íÞ¹ö<ž_kŸ?“ýw!þ‰2ìý*‘&ÀϽ>ã3×?ZvÎ¥Î-DÓ1Í"ÌÁÕþü¼¥Zµ«û³ ;ïÔ…>OÆ…íÓ RZ¿/ÑýH‹¦-UÞ×fM”õtvjbs•[öÍ%þq¥×Gª]•À@’Nö™ÜZì>âKú1&|‡ÍKø—Qÿh×é¬+wV‚C"#<Ëÿ˜Ji”HrL[½âš½õ•?GEþ£udgÆœ]mp¨.2±zWѪÚÖ_{ÿÇxà™gžYuÐYy:|1[…ePLì¸?KfŒ¹:À°SNñ±öYs2ýx'D¹’ljùÙѹß蔼´#®_adK¡ gÊââÎó²Õ„ƒ¼€LmK<©'úljϋEü£‘–ÿ/‰@=Z*žr{>—íàÄ®Q,%°ì[ĕ؎úÇòŸ‹élñ^Ϻ'û‹Å?®4jT @`søÇÅ<• Ý¿þÍK®¥_–hÏÿÑçRýú÷ÿûOLý£mਲœåKñç¨ô}=ÿhç>Ôéÿå#Cúÿ8ñÿ8Åê!Pž¥›Æ–ù/0´(ô'çìk]ë3.BdÔ?êBï½è ã‡Yû?ª’XG©Â]f­§ ¹¹øx–^N A+g«¥É#Ós©Rà>ÿZ›*>üðÃÓw£«g:UIèàˆ*[}Ÿ¹¹‹YJZ¹˜Úõ”æHÏ& ô2—VwNñá[–çhû4“Ÿ2Ùœ)×MPŸ¯,³¡í³ 6†3“·¿ýíY ö¤ FÌû„\öïÝiÍç笛Ö+C¶KCvXÍ(¥Î˜ÝPjäï°|tîNF8;<$B+šGûHØ»ì<¼^ýJgK™"½â•SK/tåßt&  ì‹þq1ÿè…ÕeuJuÌ­ÞBöù’?üØÍHrÌü£3+õ•¥7¦mM÷j¥lÝ jh)ÿ¨^Gm®ÓŠ3ë£ÚÍŠ)M2’C§øGU;,1àE+ZöÍ%þq_/»Dkú,­gUòQ}¤Ñçg`éÂrm—SU,ªU™,c«óBU(ám(ËjËHTgYÌ5¤K_ËÖÕ{Q&†¨Né ݰ¾g‘Ë¥‚›îwÎ;mvÙ?úÚÇ{¬Ü·ë´jx•]¹dMìc8EÙødî¸ô!â%›\¿¾ûÈš[}Î=3_åÐØ$ê–-ߎ³¼;\xÿ8:É~pÖÉÎÓ*2ÃV7R‰ÕŸ³& [çüïLaöëO_œ¥ø¶lþÑ ƒ™ô¯þïB úô„eÇœÖà&2ÚÑ®ÃöM#eÎ.ŸÝÒ§¼-OÚíß™ú<àS~./ûq‡ŸAz´|Jf ;óz¾dÏ£lw=ñ]`ÖkËJ}§Z@8™þq«¤ôƬÆLMÊ—YAʯI5êKV.-“ùG…˜.^îŒxºŒuâZm-¡)Ùçkcñµ3.Ï\íÔ¯è \§¶QI ¾3Š9’XÓ=ê'®ã^fŒ­eÙ7—øÇ“_¹Ô?ê×'Ÿ|ò‘GQ:$pN à½-z|ËV(—2ËËŸ³b¥´˜ö‡ð¸YwFœe¢¢Hõ*ÐiÙ¤#}æ%£Eï]Îâ™ÐM÷­c½˜ 2™ˆ²Õ¯}ÏÒ¶ì¾uF§TUmå X',—y¯^SŸ6¡>:rÝüPyÕ01]žªCÕPr‹ê´¤†É]î¼e¬z¿ãJªíòÈò)ÃM™Q˾Emî´¥ ׄ‰'ŽS ýj g_©]@÷ëQ'ògþ1Ã}ìþ~ZÀ\@5À?.c•¤ÌäÑúñ$Ú²ìEùJßDê×t¶ʶVôqØ©%LCwmQƒÒ= ½ËÖ³dL×–Öïfû?–AÆ%ÃŒb®ÖüCÚë’[6Zj¥s;ËeuÍZ–}s‰¬áÅ” °_ï~÷»ßõ®w¥ñ?õÔS:`z Au¿½@ä‘”ªÏØ¥+“[Rg:p_B«jpÒkYÀJ¨Ï®Ú÷΄ߵ[<9çwz`Á› ä&%íR7iºíF—}‹¸«Ì†§þQê)“Úöòz± ¥èÜýš¾`Æÿ6â_ªp`'„õzJÍ€ °üãš’iBÝ2z™4œpÑbE.к·ÂŽXI‘£eës-ûæÿ¸Ô "õ@à˜®Þ¸e}á…´ä1ì·×^žÌGôlËé=}ˆáÙÇ 2ÓgѬ’˾EœÕ4…!@«¨Ý?~œZ$°ì›Kü㪯’Tæ túÇæ{Ýj½V±žÞy—ÆÛB=ùo®òL•“uDà2•,](ÝyÈø¸ 4áUós×oó^Z?yºî¥ƒÄ @‡%€lQnѧê ,ûæÿxØWp:EàÁXI%Þæ¯žõÂÞCpàvnËþÍ]#àÝùGM³é'ç¬A¬á:럮 çk€ °*ücõ¦Š[$°ì›Kü㪯’Tæ à›âƒwpÙ¿¹‡I÷×&Àt]›0õC€ÀVð-Ê-úT=eß\â·z¥]´AÿØÆ8Ò‹>ËþÍ…3V%Àt]/•C€À†ðÕ›*l‘À²o.ñ¾†Ò4 €l`éÂeÿæ‚«`º®Š—Ê!@`CøÇå}ªžÀ²o.ñ¾†Ò4 €l`éþ‘9Ðeß"¶Á„^@€@j÷Î -XöÍ%þ±—cz­à·"O»—!°ìßÜËÄL+‡%Àt=ìÐÓq@ÍÀ?¶(·èSõ–}s‰lþ•šB`UøÇUñRùæ4Ã7 0‘À²o'6J1@€Àà«7UØ"eß\â/ðZIh˜þ±áÁ¥k€À¾,ûq_}'Z@h›þ±E¹EŸª'°ì›KücÛ/Óô.%pýúõÛ߸里ÌÝwß­ûÓ;_|ñEßé›~~úé§§ó|衇âZýpÇwèž›7o¦5¸~5ÔYíO<¡«¢’ûî»/+æ‡ÊkU¡î¿víÚôhÏ)‰<‡×BXÀ²o Œª @gÀ?Voª°E˾¹Ä?žù:Èå;"ðè£ÞöÆM^/ Û¦/î|ùå—õ«JÊúé*ËÄòª¾«°.×…º\•ø×LúÎçž{®¬GöÐqFëúU¾2-ÙçU¡ ëÂË þñ2œi€À(eß"Ž6G@€ÀÅà[”[ô©z˾¹Ä?^쓆6'`ÿ(‹Wê¹Ì?ºd–BXfMŽúÇÔ-ÊBfuøGµ•6§zìCÓdIüãæ3ŠŽ@€ý0ÊÍôqÙ·ˆÃXôGJÅÊÜ|]¥¿³ú÷[z¹ø_qºÍ]O zT›¯õåú].ÐýÙéÒ´¤@ºE¢ÿ2¦º/åÕô@µÍÌ:@ ~øÇêM¶H`Ù7—øÇú_j‰p)¶Šúds—®†Îü£egfâÄ`J·X¦%øÇ²•²0þqâXP çXöoî9‘p-F \rºú¯Rgº}¶b@îÏ+¬ÿüï´Ya}I\î_3ÅÙ÷7QÐb B´®Â©‚ôÛƒÎuÙÛƒÑ!  ¬D vÿø1n!ðáø?ü‡ÿððiF>¶ì›KüãJ¯T[!ÀÐgÿfmtæ?v¦uLìW© ý,ýxƒœ“b͘e*éõ²s+éÔiaìqøNëé~¯ºätõßMß²tÂÌ?ºL::°gnÑk²v‡ýcìà¬=úoú'ÿ¸ß9Oä€ÀqTíïºë.ý æöhn/ø*ƒ\&UUN ü£³!Ò.™Œý•™}¬šØÇÌ-ª’¬ÅÈȘò‘Þñè–¶Nþãı X%ÊSž* l8ŒK ­€èµQ¯'}gaET*sÎe¶ê]Ãíj“ìX³KNWÿQó¿Ö²‰‘úGÿýRás¢ü{§äÇ,‰rÀ?fMËEf;AãÏ®… pUûÇË  °à{ðÁ¡±GøÇ=Ž1ŸF õþÈ›:• ¬¤cÅ–Š~2ÏBŠk#=ÄŸÓÒbÓóýA+[†žM'lgo˜>'(o¡£Žø×¹IÜÞåEé§LuÔ¿aÔýRÝ^j.ÓNLAnâýG*}BeþÑmõžûŸ¼èpö÷N*³ü Ø÷7±¤æ—”tûȽ?…yn@8üãFy¼øÇqF—À?V<8„¶0ì3vú‘©Ï?:}Þ¶(™þÙ©t‹±çTT2Å?ª°?S•Ë´ñ ÏF«þL^æ•«•eúP ¤Ñe>B5øIçgAš9UúDz *?+—ª¬ÁíN9P^orü ' yÿXŽ—½ïþFŸ=ûèVª 7ñÂdÃÿoè|¾û_'~퉗þ¥óÏâtÿè’œ?³ùM”€Þ$€d.Ü"€Üõ<À?îzø~RŽH(è#‡ý£Zé\=Ðz§[Ì2,¦øG—ÉÖÆÐ'¨2†ò íY”æ¾zã6÷*Ê_ŒÀ\ÿ¨À²™y¾tÞ\vX­ŸteæT&¹|­ ŸC¬„P¾ôÒ›=mHûž\ &OÉ«úŸ ’#òž™™Õz½RsûÆúQ]•ý§D…³EÓÑŠ©¦4üý‘~È®u*7K°Ï™k\ r+ÿè•Åó´ÓS{ÿ3/{5eRúÇ2¡r¢,“ã)й±ÃèÛƒÑà)@‹À?.‚q÷•àw=„øÇ]ÁÏ"P‡ØôÆ€_èŒaÿèJúÖ};æRøÃÕ¬Õâ³0f…ñçлÀµ5øGç–ûŸZ ;s*}4“¹N³Ð•ü¿‡ÔâõJõúü£  óÅ¢§Þ~Ñ·ÒÉz…{<«§;õqöb˜þj2é-]Wë’™5^‰€äVþQŠÿçéçNÿèŽë™î ‚ŸE sq¨?2eþ±Üà,ýd5¥ÑNÿ˜-ùΖŠ!Ö„¦ñÄâÙ)A.Rÿ¸Æõ*™ë¥–2wp~þcyR­úOºòxÜ,_®;OÞy0ƒPöÑÆ$•}#rÿèÎê5GÍE—³l?ýà :K4œ£:™\sýãpþã…Ó«×{^4Y³¤Þ“ÏÚšàÙßÍ8¨Ê›3ä,Ÿðwªóé™ýI} G»%"üã93k!\†þñ2œkoÿXû ƇÜõðü,þÑŸ”²<#ŒIO™»ÔŸ‹¢§&¥‚Àþ%-ãÃ1œXVÔwÆ-ó/®Aß] Z¹Xò£BÅ?Κ„—/Ó;’ãRËVž-S®jt?Gâ–Þâ~u>ÅB5f¹º©¼ð„eVÊ Û7ÇйFrlÁõd‹”Gå…š¸˜ÌðÚìdwš{ᬮÎæúG“ìóG®­sô/?·i±$ ÷äÙ‰ØëQ*× ø ޶hzÊÓ-½|À?Fóp!;÷.ðF)™sC]85C88üãÁ'Àç»Üõ<À?îzø~É;}(?{x9X*eô1ÞŸ¬By”GÁ7®”tåª0Ó‚e™p+Þd­ó–µëJ"NµÒé fšUøÞ{ïõ_nµxüñÇ-’<¯:-væ-æ²çH”I+éœfÃþ1›W©¼ÈN³í”_1Ûçn™ApÓº¥½˜b.æ³!°^ÌÄ«iû?±Kf¹2z ÿhþš`µÍyâ1»îºkÖËøi…;÷-‰?[ñ$-“ ;O¯Ž¡|z–• <…‡å£›öåY´ë NÃÅU€ p&ü㙹ÿ¸ëÄ?îzø~m>~aíVί_öa«8É<øV­aX«erÊ “uKC:ýu§§ÈîL×?vúG‡¤L@§ýÎJÁëìTvg¨Ëïÿ¨ÞeOgÃ)ÿ!¡;#':¶ÕËþÕ±ž\uÞRùiœÿ¨…ا]>ëªÎçµ…Ó¨]›f¯ÿâ¿§z‘ñSxV"³'¿kÐͧÆe‹Y™ôÏ·RlQCùÇÝIÖ~úøÑxÞqàÒ¬‰Aa@+À?®vgÕâw6`o ÿ¸ëá#xlNÿ¸ù 0Ë?Zdjà2þQM[gdé–½[$yÊÍ¥¦¯Tz ÇVù±¬5³'™¦”%±ëQ¿N>ÆÀûðôÉPùó¢ÉðôÔÐt½Œ|Œ'lI26ñCzFûž¸ivÍ:|Æ2­¡s+†²ŒŸàž´·ÌÆ&QX‘gϲ&g‚ ° øÇ] ÓêAâWG¼føÇ5éRwƒ|°ÃÀíh'Ãâ+Ÿåsýc"ýš®œÖ_—9}eò”W{‘õð ëáN•#ÒY~AÿhD»4Ì µ“açúë‰ç®ykÈXš–ÏN*ösåQåÏ‘6“|¼ðù×z­èssº?ËÔpsý£º£¥Í±± ~=ß?v:µEÙ©ü’ Èœ¾â”Ù ”\‰nQòœüGUâË3a‘«ã¶ä_6iídUžu0Û´.Ó‹Y×Ü÷ÔwúÇN47ׄVþìh&<ËGŸÝL§è @ %€d>Ü"€Üõ<À?îzø›À?n>ÃØ=e»aÉ;Ý¢‚ ]¦¬¤LõíËt…ÙRÇNÿè’ÙæqÆ]ˆ’³ÎYÊ Ä96é‘P ¼ 5²žíõ"˜ôm‹9U¢Êª5n™È9l„ûÆæt F#¢ïFáÑws~ÈA¦í:&h¾jÔ?úUë¾ÇËÌfå“ÿ á…|ô{ò}õº/31îßWwˆ€Ö#€\ížjÆ?îi´ŠXñ»>‚‡Àæð›ÁpqÖsš´nÑ›-–g¹¤Ž,Vd§5XGfM{óÁÎE‹™Ó…>ä½ Þr0 éüCÞK¶uië Ô½Éq¿Ê[–ì,»çJ¬Pí"ËŽúÇ>†#*×ϱÚgzøQÓKÝhÐö£^›¶Rœ'FÙ‹Nk\ùS íðRù¸GÿSºsÆÎ—ˆ¶”ÞA€@ü#sãüã®çþq×ÃGðØœþqó!ØEç{+oîvÂÎqgò9!¡Lqfú/bpšä9»4 pð~|}ˆvëëC”Õf=ëäñ3ásùµx¸IDAT0L>îÑ?vnÚÉ}Ï#& þñ€ƒÞÑeüã®çþq×ÃGðØœþqó!ØEönézç]„½¸Ð‘‡Ý¯¿“6M7ÝË6çÃ?œv}‚.o˜]ƒ –à[ÍÓû‚<]Wâ+B€ÀŽ àw°*„Ϊx©|YL×eyR ÔCÿXÏXl þqKúg·<!@àÐð‡þt¡s€An§‹L×vÆ’ž@€À[ à™·àw=ð»>‚‡Àæð›¬J¡³*^*_–ÓuYžÔ@õÀ?Ö3[F‚Ü’þÙmãÏFH84ü㡇ÿGè`Ûé"Óµ±¤'€ ðVøGfÄ-ö<ð8öHÿ¸ÇQ#fÔCÿXÏXÉ4Ãר–:!°üãT©€j €¬a¶áž{Ü>"˜Oÿ8ŸW@_ €d6@¨„ïÆ+€ Å àGºË |ðAüã.Gî ñû;"‡@ ð5Œ1@ü#Ó€Z%€ludçõ ÿ8We¥ñ• á@`gð;0Â…Ú%€lwlé £À?}¸ÿøÇ]Ïü㮇à!°9üãæC@«`ÿÇUñRù²ðËò¤6@¨‡þ±ž±Ø2üã–ôÏnÿx6B*€À¡ à=üèÜüã®çþq×ÃGðØœþqó! €U °ÿãªx©|YøÇeyR ÔCÿXÏXl þqKúg·<!@àÐð‡þt¡s€An§‹L×vÆ’ž@€À[ à™·àw=ð»>‚‡Àæð›¬J¡³*^*_–ÓuYžÔ@õÀ?Ö3[F‚Ü’þÙmãÏFH84ü㡇ÿGè`Ûé"Óµ±¤'€ ðVøGfÄ-øÇ]Ïü㮇à!°9üãæC@«@謊—Ê—%Àt]–'µA€@=ðõŒÅ–‘à·¤vÛøÇ³RMÿxèá?@ç:ävºÈtmg,é  ¼•þ‘q‹þq×óÿ¸ëá#xlNÿ¸ùÀª:«â¥òe 0]—åIm€ Püc=cq‰Hô!ó…^([ð¯¾úê»ßýî7n\">Ú8‰þñ$l\|žþ‘©Ð6„NÛãÛX (Ý €<ÖdxòÉ'õ¶æÞ{ïÕ§ÍW^y%:_úÇ×_ý½ï}ï;ßùN•¿ÿþû…io½Å?îmĈuÀ?Ö5D³4Í𥫤>¬Eÿ¸Yê… ­ à·˶/«xÏ=÷èMÜÞö¶·I>Þ}÷ݾG?‡‹Œ2Ï<óÌeäµyðóxQx+ü#3€@%ð• a@'mxþùç•Æä÷–v J~Jý?/N@„ZZÀä5 /½ôÒ #¸ö%øÇµ WW¿S §ßH~¬n‹€ðõB føÇšG‡Ø CÀ?j¸é,Ú  Þ®]»& vçwfL"ŒÜÖe-lçÌü*ÏLP~øaé`m©·v ëÇ?NÕN±2rØE’üXÿØãë#"„@Íô¢·&5GHl€Bÿx¦›h€€DÁc=¦å•<ðÀýؽüòËŸãVŸÿùŸ×û|‘¼°ÑÒ-ø6™øÇM°oÜèôH’7ªiÍã§q¢ ÐMÿÈÌh›û?¶=¾õÿØØ€Ò´G@ {yä¥:*·î=ïyÏG?úÑÊœátø¥_ú%ç¨*/R:h«i‰ÜŠüÿ¿½·{º£*óþ9~Ž~ÿÃÈùsøŒx0åõT™å@RS#ФJLéS*ñFfð- fF+·¦T¢hÔŸáÅj@ˆ¢á-*†·&Bˆ€B@™ç —^³X«»wï~Ù½ºûÓ•º¹ï½W_ëZŸÕ{ß÷þp­^Cö[¿’âÇ!ç©vßøÇÚ¨hÀ?rYL›BgÚó;±Ñq¹NlB¦D@ËxUð(õÃþðùçŸÇó‘ÀÃ?l"rÕƒœÒÂc©SIñã@mŠ?C`ôð£ŸBPI¡Ã2"\®#š,R…À|?~|ûöí’V*x£t#爀Ë«|UÂGw\åeŒ\%íŒúªS9ˆψÑxRÁ?Žg®È9À?æ8+äÔ„Nw,‰Ô;.×ÞÓ ° y•.É<~õ«_¥æqbó·¿ý­î ¹yóæ•í„\æÅ7­¶Õ%?Žh¶ñ#š,R…@†ðN )uH¡Ó!LBõM€ËµoÂćêÐv%Ú[æóŸÿüÓO?ýމ¸ýöÛ%VsSHücýWßÔZV—@Rü8¢ùÆ?Žh²HÀ?f8)¤Ô!„N‡0 Õ7.×¾ ¨IàÀ’÷ÝwßDµÃzYfÝÜSލæåѬþ±·‰œUVIñã¸&ÿ8®ù"[äFÿ˜ÛŒO·:Ýò$Z¯¸\{ÅKp@ &={öœþùGÅÒ͇€nî©åØÚe¨æEÒ þ±´éœRVIñã¸æÿ8®ù"[äFÿ˜ÛŒO·:Ýò$Z¯¸\{ÅKp@ í|ñÅŸ8qb>ê‘{î¹GE¯ýÝÿXç8å6i $Å£›oüã覌„!ücVÓA2X[[ë<&!ÐücO` Ô! }®µ-òµ×^‹›-ßÿþ÷R*€­sÁ,Ûÿ¸,±©µOK )~ÝãG7e$ ¬à³š’æLÿ8çÙg얀̀¶BþñügŽyxî¹ç.ºè¢>$þqØ×x½‡%?f1%K&\Í!WÀ?rA@È„þ1“‰ Ì€¶ùö·¿½bóö•¯|å_ÿõ_õµ¬ßÏ}îsj>ûÈ#èñ7½éM§vÚûÞ÷¾Š Gd¡ÂCÑ~ö³Ÿžø«_ýJ-•UuXÅT›w¼ãJO_ËÒpE«À¾°ÁÂÑ5k ù®w½«ó…ØøÇ¾±ÄCK )~ã㬑3ò!€Ìg.Ș9üãÌ/†¡¨&I; 7sUÏ’Ë;åo‡baœSO=UM"¨ÆöxxèY¿ÉHbF¡ìG©ÃÔ Jê)õUÑQYz©ÓTÖQY´… Œ·æ)>ú¨d·ÛÑà‡zçÕ¯•@Rü˜×¬ÔÎÿX !øG.‹iàþӞ߉ÿ8± e8}ûö½ÿýﯩ¥:l&çâOFO:2 žúGÕÚYª+ÔaÑ#æéÊŠ«s¶sÕ‘—@*²õ›fµÐ?Ú t¢‚X@÷›©µ\¨6èp:ÒPÚŽF;b«^­«ËÿØÉqDZHŠG:‹øÇ‘NiC øÇL&‚4z"€Ðé ,aû ÀåÚUbB:¤2·§žzªW“UÜUY6yº:þÑÌ ì^ÔXµŠÍFQèøÊ:вZèeQ•[”‰1g-Ä^¨6è{ÖDU ó»zeíUާßÁ˜nKMñ]½!ó$€œç¼ÏgÔùÌõFÊå:Idmx}î¹çj¥í‹Cª»”’{Ík^óÃþÐôœ¾‰ѳz\-ýñô‘–¹»ã‹âœsÎ9–^ø¸ùÇèÁ… üîw¿³´uzظ¬ko³°Á®Û7Py©ÖËvrUgíõ ø%L‘@·\â;y7$fKÿ8Û©ŸÉÀ»ý;h s(\®C‘§_Ì“À–-[~ô£µWTÍ"¸Ôé¶HYº­¦”kÖizV™ã+TÍü£:¯|öÙg»Ú‹ÿ8E¹Å˜²'Ðí—øÇyþ¹À¨!ÐücW$‰“'nçæ9F²š .×ÉL%@þ´»±Š»²x â„þÑK ¿üå/‡¡ÒjGÓ…z<,ŠlÐûÂCëHUíë}§H›.,o\Ø ÍÀëŸ+I-UÝþ’Æ?foªHpŠºýãÿØþ­˜3üãœgcïöwîˆ1Æ p¹Ÿ®!07Ã?J~…þQ?®wNýãu×]g‹µõT´œ¹¾P[¸Úv¹QR‡íý£UMꈢ-Ô‹ 4rƒ³Î?ÿüýû÷·|à§(·SöºýãÿØò}Ó!0søÇ™_“~·¿s'‹K€ËuXþôùÐÞ³]tQÕá)‘,¼IbáÝU#iwb!½ RߨaÁ K,›­¿¶€ZcÑ[¨6èp:ªCýæ7¿i¿‰Eîþñ/˜"nÿ¸Ä?ÎçF >àû JÌ|tû;7Ÿq‘É$ p¹NrZ2$ —ôë_ÿú…AÛo¿Ý4ŸgqÉ%—Ø#Ú•Û4s§–Q¦jpÆg„RR²ÙhÌñY¿~Ø#zJå–aXϰ~_ï}ï{-ø¢³\/–E[Ø ~í[~èC’¶ns1ã§(·SöºýãÿØæMs!ü#×À´ ¬­­M{€ŒnJºýqJd  Ð!Y$¹¤öBªe„Ô?ºpÔZìjÿhÏÊBÚªm;š)ÈÔñ)¬B¹—¼é¦›RCZsì¾Zü³ŸýlzÊB½¸°AÍ4:iö‡?üaýúõ'Ožl|)â³7U$8EÝþq‰lüȉ€€à¹ ¬˜@Ùç·nÿD\ñ è½ÿœuÖYrI8©6A ýcTYVÿö+?è+¦äSáø,¬ -›ùG Ð"¸Nuý£’×m1wîÜÙø:Ç?NQn1¦ì tûÇ%þ±ñ; 'BøG®@«' ÏÿZü¸mÛ6í?öþ‰xìØ±]»vmܸ1j³úlé˜ÝuñýïO×ù)…þQ½˜4ëWÇ?ª™Ê­2]©½0í ÿèK§øÇ…òÑGªª×_—éË…Cë¼Áàû JÌ|pÿÇ|æ‚LB*<óÌ3M2V?rÙ@Ýxó›ß¬Å×z ü¸í¶Ûlc–4?Úö/&àÔ²:[™J«\Ø2ãõéSvsÉ0C7†ÕùTÄ Oô´õMП½÷Þ{Ÿ,O@7²l¼ÿ˜½©"Á)À?vûK”h€@øÇ6ô87ÝþÎͼd8"»wï®–*„ÑpHÈŸ€¶`~×»Þ•‰Ìªð®Þ"«(ù%5ù8Ý­¢¦ï+xÙ¹êËz—sôëøÇ¥’±ÆRœ‘9Õ~÷ÉLæËÒøùÏÞøwSîþñEL‘@·Ÿ…¸ÿcþ¿éÉ9À?æ<;äÖž@·¿sÛçC„tÈ ©=jÁ@ CÛ·oÿ¯ÿú¯L|V…T†áÆÖîæLÿYi¤¾×¡fæétV.¬@}ã‡ÇÔ#a„0°½¾¿à‚ ´£gýÇHžºgTR«6(}ã;êh3î…CXqÝ6äøñã .KüãåcÊž@·Ÿ…ð Þû8pøG.†ièöwî´Y1ºÕa,óR“«Ï‡!iнeï¿ÿþ몲îªý£¼›KÀÐÙ…ÂÑ´£éÈfò1P]ë+mº©‹·‰¾1Si+Ç+Eˆ€htéY¦#3”JþßþíßT¿ßà•‚ÌÞT‘à tûYÿØà½S ü#×ÀLtû;w&Ðæ* ”•@Rü¸ÊY /Ì€dÖ[ßúÖL䣥!YqÇF%¬g ï~(Ûh¥‚:ÚßÑÒ ñ—6¶Gì-/kP=XB+¾mDr”yšG›µn¸AI6xÉà§(·Söºý,„lðÞÇ)€þ‘k`&ºý;h s•t;¶´R[Ó¬2‡‰õuøðá×½îu^xáÄÆ çÜsÏÕ0wíÚ=®Gô¸ „oÛ¶MÚq饗.Eæ¾ûîós ì5×\SØišŒ5S2:˃¤§kGiV6•ea—Ŭk‡ëÂеmˆ ×óhGà‰'žÐ쯩Üýã ¶§ ¬ž@·Ÿ…ð Þû8À?r Ì„@·¿sga®˜À–-["ÙxwÑgžgwwÜq‡?Ê[e˜žnš&ýwóÍ7·ÌÍÆ¨ãÔSOnĦøz\ ¼ ¡°–fõ}¡ì+KÉúéúÆð†ŠÓÚšMÙCö®–‘¶i6Ìe…iK¶8]¥s*¬>xð`4yÉo}ë[íÔgCàezQ¥ç²/üãêÕ=Bà…n? á—}ã£= àþ\Ó&ÐíïÜi³btC&ý£ŠµÀm¨d&ÐoÎþ±+¡æc”žS!d8k‘TåcÔFös©âÐÔ-ªÇ(f…Taw*~4›êKücç¯;Yé7F·qؼyó-·Ü2yvÅW\\ï˜<ŠþxÞyç©xÙëÿˆ ƒÀºý,„\öö€þ‘k`>t¥ù –‘Ž—@XIñcËylïÃâAKF²,ZÑœ&©uÊ Û,ô ’öžöåqT‡¹¼È?š+¬³ {¡[´zF?¥Â?¦a­3L ÿØòš/<]ÿCo,áêuý¿ ­ËîÏIeùµ¯}mõ0þìOúÓLr]ŸúÔ§Ü!wÿ˜Õ½Q県ÝEuκ;þ±_±Ä„š þ±7΂ Ð!ý±}úé§ëOD}m°¨­ÃL&*õZ*(Ã%µŽN„Ëõ£$šªól}±¾Z]¡ÝýÐW§At–ÝrÑ)—É>‹cÍìPm`¨ðìYk Ü¢…Õaòî­œ0HäU{Ør 3þqÔ/ ­¹öËLï0£ó\ ¾çž{$ë ‚sЏòÊ+üÿ]üãZIUìd¤@¶=SzîÇä«wkÒ ÒMß«“Ö=euT·Q§Km¥Æú½å rÙÓ— üJÓ¾ã/›Oçíñ£þ-Nò˜üãÄ&”á@#% G ?C!5Ò žvêÓ‚;%UðÙvkBI=û^ ÒD¤±BÂèΉ~VئðV†êÑV"[I=n3=¸:Òúhû±â–a¥¢©±ßS2òzÜœfã»(¦þÑÖt‡—ªL«©ìõU£’j}œ×ÿØÐž!è3tBàk_ûZƒßVøÇ%ÌÒk^óšŠ:^¹¹ÓN;­°N »‘\;ãŒ3Âh:Qž±0‹¹Tí¡"G=¦‘Í'Ö7›‘\öô%(¿Ò´ïøËæÓy{üc¯¿b ,Eÿ¸.C艀ÙŠÛãmìõùÈ·fÖJj«F ﮘ.v¶6á†Î¦Ë>™®¿6E™Íúqìt—•éþ3aQg í?ãf6œ©úþ1½¥¹àBi»p¹zû«e&öìÙ£ÛA¾å-oéÄ=ßûÞ÷ô bÙ—þq ³$)æ‡9¾ð²ZÅð8çœsôË ´2‰fõÔM7ݤU«(ÉXf -¦þ©Ÿ¨†bÑzŒT£*ša ëëŸ^Ñ‹"+½H°.›^ÍQäÓ ÿ¸ì[í!þàûcKä4X”CÚä0Oï|ç;£°ùq)_þò—uå4öQ½a*Ŭz1ºqat–õ^¶Át¡P³°Ñ¦Ø*¬(Œâ˜¬4 šúG=¨h¶Ýb.u;Ètÿk#Ó þѬ®ŽèF™5ý£æw©ëÆ׿þõˆ3tB`šþ±4}Ñ=MeÍF~ûÛß®·xýáë-íf¨á#ö”6iZ­YÝø@=j¨f§ÛY:]Aú¸?k‘ÛŒ·ïsñóüPÁ¨!'ücžóBV]èöwnWYè@WþѪÓ*¿jÿhÕ|eK§ ýcÚ‘uZfåܱº4¯gúG ¨ff*SX1im£âX¤o@Q³þÑÎ ËE«GJýcW/ÝKTŸuÖY}Î%þLàW:Ñuüã7¿ùM½½j©µg&í=²0éo¼1T‡O<ñ„~ÔWS–Jã‚ .xøá‡Ã8zÜm¦¾QëÔö ×ÝXÕØâØ÷az¦Sý†OE–0:=Ýá>Œ¬ïuºÂ*‡H³êq=¨ôÔ£¥g¦§a†q¢Q;(=®hê®?¥»pÖ6èö³û_wõ‹™8˜'üã<ç}>£îöwî|¸1RŒ—À ý£&Ë÷™©ð6§Õ+»Óy/t‹Ñšñ:þÑú-\^³þq¼×ä°™K>nÚ´éöÛoÇ?.üœNƒšð5AuӬ޴5Ú¡&3ש½ê„"ñgÅŒ2kÜ–rëkèûÂÜì{kc‡Y¹¨(RIÚ³jï§„Þ³0 oàÁ=%Êì§EöLÌŸz§az6´fSêÖ3ô8!Iõh£ ɨÓnæ»ë(Ý~Â?ûÞ!0vøÇ±Ï ùWèöw.´!ü 묿.Ü',iL™šÅK‰G§×q…á)…í#È cš| o¦vQVj7‹l°ÍEþWéÊ24ùxðàAÝÒMkð»þ\K¼™Ð}µµú²—qî÷Ìv2úGónQ ^j$°Pü)Ž í\uÕTF¹®¿Ž”õS@W¥òƒ–ª§WíÃQDŽUaÃÅæ§ÂlZ¨(=yF¥qy†z¤0ù-~ϳ ²ÛÏBøÇeßøh„ð\Ó&ÐíïÜi³bt˜Ô?š o°hb+\%.š®¹þ:ZËlú¯zÿ™HÃ¥ÛIk",ç¥ö±±Sl;l_$î[lûäVg˜^…nÑT(k_í«å£N÷âͨ÷tßi\¢+…ËGëQ¿Op@  _úÒ—Ü_ÿ¸P7¨öîË¢“#eV§ïBñçòÑ"DaøÇ4“w^VYÓ?Ú’s¹×²¡YÍc¸&½ðþ‘,¬î­iqBÛ¨ä—]í^gFÚ·Ñÿ}êé^Èû÷ï_Ù/3:‚&Cÿ8™©d …ð\˜ Ý‹P7”wK×ûÑ’qª+4ÛÕ•T)H»¢™Ä­œ}|eârÐv†qÛ¸0NÙ­”2ôŠ,#):E‡o&SÿªpÕhtÀP¼¦mÔÌFgOÙ¦7áŠÑp·qk£„m,®8ë'LK#ÉG=²nÝ:UuaŸÆCnáî»ïSÆcÈUâeçÎ˾Öð mRµ´g£»+¦¢°NßuÄ_”LKÿ¨×§«ßô gê¤aU“eKžEÃ"GmêøÇBok’×K) ãTäS~Om®¼òÊžü£Ìæ²o´‡ €ä˜6üã´ç—ÑAÀ ˜³KÅ¢50)iÖL‡LeTðظþQšÌJÍ!ê«×ÎŽË;µtá¨SL·Yz&ìÒÒEXæ¥A#ÿ¨î,`§:Ã(í¬3ÔÃôÒ6®w]‰†9¤–Ö x3[KÎÞŒ@*gãÆ*XéÃnéÃøßøÆ£Gö¼MÌË/¿\W”rkdŒçÚŒ<ôÐC=%¯×æ¾}û–½8ñ S…L—{vãÂÔKV$QGüuâUºhqÂû'.å­ Qq¢áèñ(lè(kúÇTkZ¤—RŽÈ?Zý£nÃÑíÁQ–}û£= `ð\ Ó&€œöü2:„¬¾/Ý^ÙÚÈ—…Ïzž=ýhí#O'§=âÖRõz]GÓdÃõàžƒ×QǪòI/€4mµ±kFNcF¥‹*W\ØÆyªqtºýXhWõ¸>ÔœÂ^¸àë(”ö'ßw¿ûÝÎ…”$—}ÞïZòYhÙ·*ÚCýÀ?öÇ–È9hp¢Ò&@`ÒªÉQ¤M’Ó&°eË–Â…q;vìøÏÿüÏÎ?ÞÚ'qÕÖ„‘¥>Â"¤ðû°Ñü‰Žê%Ò¶Ù¬•séÐ7uÌšbZcO̳*3’Ö 56a–I\­”¡ˆœ’5«é‹<%—6!ÿ^¥ðÓO?}úé§7xá¾úÊü£é6ɸ¸ºÊMóÕïu5þцŠü¨ß…iX„¨âÚaôÊìÊ?ê .ü_øÇ¯N `ÿ3|÷îÝ € @`Y£öVÎYqÖW.‹ˆöùÐâëù—y®ëôà]wݶ ½›Ÿ·¼õÖ[M)꛲¼Ì±„ÑìG=^=3ÒÞ,4˜>ø`zºõõ±},|*LÀ¼‡%5«Ÿˆ%…¶0ìõ×_ï)U óê·®'ü¹Ûo¿]l\ØøÇú&ðU- ý£Ý\ ÿQv¡è5ª:ùÊ2)¹Pü)~uý£Yÿ(~T<ùGåfyÖ¬ŒT 9õ©5hfª°¶1ô˜vÉðà¼þ9€þ‘k€ И€íîÒøôaO´a*56CzïœÀ™gžùûßÿ¾C!%ff0Ši’n¡J«ã­ØÐý¦¼¡Û7ɄбXÊ0òöx¨A½AêÍWè­õfJF)-µ·˜ m©ZÖfîÅò·oÊÔíUW]U³ße¯‡f›ÏèbÆ?véýÂÒ7ÑáåĪ1´fVèú¼?ÿh‚Ò¤§«æŸkAY<]Ж[}ÿh¯“pÈî ½k»ªIÃp°^¬~ÕÀ@¥ë»­âø %êiüc翜Ì„õ3™h† @¨Ø"¦ó¾úX]ÿØGÄ–€þêÓ&EËú¦Šö¶ „>Ë÷ç£ÊJuôøã»‚(Ë­PŒÚY¦#5ºÂP,ºÐh ­CÿhºV5º…êV¢ÖôKa¥gãáèÄf7l¥×sõ2K}¹LÍ£=½ftÅ›y4W¡í­¥Ÿ®oÒöQ2inº4­;»RE&ã)Y|kàýV§!ÑÀ½ÈY׺kG}£Mƒ†³#1o(iá0õ.àÐÔ²iô šE}õzUÔÎý‡ý½Kï€@HÿÈõ0mÜÿqÚóËè @ >íYü¾÷½¯þçÖ…-ÓC;¥N)Ÿš-”he ,”zV‰QËJÚ³ Å·°©LëB2Þ`aªÞr!4‰WÉk_ôSêç\ÑRÿÓåì³Ï®É…-s¯ìA üc³7,΂ú €ìƒ*1ó!ÀïÜ|æ‚L @`X'Ož|ÃÞðÔSOuò¹¢Ân¡J«/Ñ S](õ,»RÊÜYudêæÊü£¢5&¶0Õúþ1Ì¡Ž4ÍÚmIÖ—¾ô¥ÆÿgÿØø*âD4'Àg¡aïÒ; @ý#×À|ð;w>sÍH!@`!K.¹ä?øÁ³]¾Æ9 æþ±ºŸ[n¹Å< ¾Y*#‹þùçžå·>Œžµ³¬¯·½ímV¶qÿèZ(kùÀ,•¤5vÿ¸ðÜšÐ,Nt*äLǸ0êçwÞ^f… r÷-Ñp:ò$Àg¡foXœôA€úÇ>¨3üÎÍg.È€'°{÷îüã|L®Ð[¦ÒT§6áqíµ×†]בhiªÖ¯ÝÀ±p ¦ü¶nÝZá%Sß—úG7• ¨ö²–ËZH‹©s#eé©YÙ©ƒ®B×é"móè£j £Æ×0þ±v΂@+|jüžÅ‰€@çð#%`Vø›Õt   KàøñãÚ´ýÉ'Ÿlõö•“U~XV^gj/=¢zÃ:-Êó±Çs¹Y8‹:RQÖ?zþzP1-T¡Ôãr‚>¢e-¤ÅLÅ)Ô£úGÛvÔxêwìØ±mÛ¶Æ0þ±1yN„@s|jüžÅ‰€@çð#%`Vø›Õt   N@é?þã?ššýÛ™+‹Ë꣢¿þÑÖMêEË˪#Uz™0òj`(fµÔ³²™ò­¡…¬¹f¼¬þ1õŒ¯¿v¼wÞygûé–³^¿~ý±cÇ_ÀøÇö³@,M€ÏBß³8èœþ±s¤ÌŠ¿s³š’ Á h‰$­¥]úsì«OXè–ò-ë¥/­0ZÇæå›>×ñ&+Ýf–Õ?†¡¬ê3¬+´êÈèðS¼ÿã²x«¯9k™ë6WoîþñL‘Ÿ…Ú¼mq. Ð-üc·<‰–~çæ6#ä@ƒعsçå—_Þò£ößÿýßKÃékçïþîïôÔG?úÑê.öîÝk.Oß,LæÊ+¯´Æú¦¬± ýÔ@½6°¬¢¾l*Ô)öý´]ƒê¥¯:1ðÆŸ¸M™}æ3Ÿ‰"Øã…‡žòÆ?ùÉOª›Y_ÅqöÙg{4ëtÿþýeñê4m ë9«Sk>¨gí°d¤ö*: ã›,; Ð,ç \Š‚µ,à—¾ô¥Æó{ÇwlÚ´©å¶3~‘ãO'B 9üãà¿hIpøG.†iàwî´ç—ÑA€@K;vìØ¶m[³·Ò2\ÿøÿ®"ÄhKhÿ1j¬ [Z³üàeqìqWŸúÆ´`Å@¬¯2o(Og1£ЬÝ?†Ö¦›WV AŠÓƒT@³fúZ*T±j¬Q˜” »¨“°·ùÝï~§MŠŽ9Òòü¦H€ÏB]½…hOÿØž!r&ÀïÜœg‡Ü @ [¶l¹é¦›–’SÖX~°°ò®A¨–§X™aZ‰Ù2ìxO¯#d+FwìØ±÷¼ç=èðú̽þqŠê‰1AàO|êð]ŒP€@KøÇ–9=süÎÍ|‚H€' ¶ªt»ë®»è6[ä+ÙàÜ®N±…ÒmjýºÊ$Ÿ8&d/¾þÄ'>±k×®n¯Lü#. à³P·odDƒÚÀ?¶¡Ç¹ùàwnþsD†€ 08-³•‚|à–5hv‹Æhñï²AZ¶×ÊåÂeà-ÃŽ÷t²Í†píµ×nݺµókÿ8€{¢KðY¨ó÷2B à£ãÄQàwî(¦‰$!@`p’V6lÐþÔË~`·ÚÃßþö·ËžØUû¯ýëùÈG~ùË_vpìq쾜bÒ` 2]mx]Ò¹ûǧ9 0E|ü—+ @NÿÈÅ0müÎöü2:@è€îú§*ÈïÿûKy+Óª \ê,÷GàÓŸþtù¨Ô=wîÜÙá†Â?NQn1¦ì ðY¨§w4ÂB à@ã”àwîˆ&‹T!@`pºä%—\¢"¸þì‘3$ð«_ýJêY»f÷wâ³7U$8E|êïMÈ€À²ðË£ý¸¬­­+a²…  N@EpøÀ(iÌPö‘Ò7Þ(ùxèС^/¼¬ýãºuë¤i8 0=º¶{}a€@}øÇú¬h @€fB`ïÞ½ï|ç;e¦ú^ÄÌ„€œ£j]·lÙ¢jú¾°³ö}žø€ èý} @€ „$§ô‡â»ßýnmJ3Åu‰³ÓÑ£G¯¾újíTÓß £Wþ‘·@€À¬ lÚ´©×[½Ì.ƒ‡ @#' ?µ/ö‡?üam=kc7¡Á_wÝuëׯ߾}û ÊýòÇ?Žü€ô!@íàÛñãìÜ pÿÇÜgˆü @` öìÙ£Z¹Ïþ󇞈›ÝPn½õÖsÎ9G÷_Ò^ç+¾îð+Nw€ ¼àóš²éš{¾uM”x€ 0SÚ{ÇŽÚÌ@[Ó|ãß rDòòæ›oÖ}Uó¨¿ü5qƒ\ÁøÇA°Ó) @ øÇ\f‚<ú!€ì‡+Q!@`¾tëp“Yª¤ûâ¿ÈÝ!ó‘ªTýþ÷¿¯…óRÆ›7oÖ}µ¡ù€W-þq@øt @žþqø9 ƒ> àû¤Kl@˜5UÒé>'º;ä[Þò–÷¾÷½r‘º±à-¯Oq¬–Àoû[#¯YÐòjí$íxÉ%—háü*oòXñzÀ?ÎúÍ‚ÁC€ð\Ó&€œöü2:@È€ ëöíÛ')ó¥¿-uè÷/Ç* ØÚjš…]»ve¸½$þ1‡—*9@€#€ =¯„þq%˜é€ 0üÙÐß,âûcKd@€ÀàG0I¤Ø‚$ZÀãT@€À¼ðgCóì-‘!@# €Á$‘b |hS!@ó"ÀŸ ýÍ7þ±?¶D† Œ€þq“DŠ-è.H-ÎæT@€fDÿØßdãûcKd@€ÀàG0I¤@€ Ð?ücŒñý±%2 @`ð#˜$R„ @èŸþ±?ÆøÇþØ€ 0øÇL)B€ ôOÿØcücl‰ @üã&‰[àþ-àq* @`^ðýÍ7þ±?¶D† Œ€þq“DŠ-ðA¢ü#Vo\ðÓWb„€ j¬¿æ ™6µµµiÑA€À ŒÈ?~ö³Ÿ}Í+Ǹ|ÙvKÿ8÷)† @xü# °2Û¶m»ùæ›WÖÝ:ºï¾û><‡‘2F@ $ ›srÉã‚ .8í´Óôµì¼… –ìð¯Í/¹ä’SN9Eþ±Ùé=¥¬D£ð¸é¦›¬ÓC‡Y}¦qÎ9ç„'žqÆŠægU'Üäž(uÿÈ; @`î ýãñãÇ¥ 掆ñC`¢îøÛ‘ŽOÏ,”Yj#çUƦ"ø5×\£ ¡To¨õFT?C… ³ªˆžZjbÄs«x3<¥ŒgY†©O¬ ¤Nßüæ7¿îu¯[jD4†&@ ”2Ó›°¾–I¥… šÙ¨–þñ¶WŽf]Wœ%*…‡ 6íDõk ÂüÁô\‰È…yöya¿ƒ7À?Nàm‡!@€ZHý£þï† <Ø*.'Cù¸ð O=õTÿÈ$oÚ@ý¨§Ô`×®]e¹[©‰;÷ÜsÃàúþÒK/ ãÈ”éAD ?ø™nÓSj¥a³P·)²?n§6SJzj)Êø¤C eÃô¡é{=YH=b¡ÒjÐp [FÉÙ}Íïr##@ G3ñ…°•fþQÕˆæ7ÃÃãWûGÝàÅÎRå£*"ím¿BïZXüc¯ BC€ 3È?8p`ãÆGŽÉ9grƒ@}ÜÿÑY™z3ç('c¥ïCEèÖ¬¬žÎõ_ªðÌKJ«©7Åæ¦ONñ%@=³„æòÂØæ‹&ZŠÓN‰tžF¤Ç=xçþ1LÒnJIiCåi%“zÄUc˜³kÜ4HäË(…þ×gý-! À?¶´æU›Y§Ú?FU™ªš4©?<*bâ'ðêc€ 4!úÇ={ölÚ´©pÍc“М °ÿµO‚T—DUô4ågޝp¡±UöIÀEþÑNÑ×hÂUGéñuK‡è¬ K¨8‘¾ ¥¤âD7ˆ°”¼–°ÿXhB#ëgò1-ELùØ\ØãQûBÿX½Â:*,ÍàeG €@ïôÛíù%×¾öµzÏÑײó6Љ?}åxøá‡+:׳ÖÌÚ\|ñÅêW¾¯ðké£6zܤ^YkÏ=÷T)ì×ü£r«Haï)YÌ·¿ýí1ëCNƒÔcMÑÕ™ÍêI_x1²þº÷7:€ dNÀýãÎ;ígž0éA`)øGÇUXQ´VK˜ÊD[l…ŠiacZ«M“·ðÁjÿhµ–ay¦UPÚ*ïHüEÁWà5«atéi §ÜBs¹`!l£4ðævY‚½Ô;!0v«ñ’Yrjº­¡ìÒW\á÷Lô#ë$E¥Æa3úÇo¼1li‚24wrm¶k¶ùGû>íWñÍèy³jýç ÷áë¸ÅÂ664Ñþæ7¿éÃÑ#Zn —=îÃy <¼©¥±RÌT骋lÊ6𣲀 Í£5À?Žý=‡ü!@m ˜ܺu+δEÉùYÀ?ú´XEa™ 3óeаÐTšø“Œü£É¯pauá…Š¶jÿh¶1¬û3Á§³Òô"#¹ÿ ¼°`3‚ï²Ò…©UnF«àÃQWS²øÖfádù%)@ !ÕøG«õ“®’Û2 ¨ï]E¥”O<ñ„Y-oæ?Fõ’eþ”"KPzLsVÒXèC½èYYp5ž+ð>„B1Wæ…H¶Ñé¹Ôƒr¬…‡ñ-¬)B¡p·«GÂfFU-­™‚‡S²µN [¦N³Ž‚Ä?6|©s @`2Î:ë,}j­Ønb2#e ó$€ôy·j;}–ˆ¶ñîõÌ0¦ë‚­ê0ò…‹ˆ£‹-•‰nÍ*VGU&@ub´Ü¼døPVã£^ªËK š{Æphv¢/T/« 7 O÷ÔNõî<_ïŒó!°JÿhªPN©(ÒÝ“Û@_+-ÏVó…–JþKåuá# e-\ç[±ØY§[ûpi¶;Ðê…Õê·óúG—ª!“TÌUøGS½‚e<íHĢˆÝY©Î öh*½Î4Z^mçFc±Ó«k™‹Ä?Îç݉‘B€Š ¼þõ¯ÿ§ú'Ýö‘+ pÙe—éïàUú{w•ÝeÛ×þýûõ î|m¾ì-Õ…Vëgí#ÿh«w”.,ÐóUÁ°<3º«£9Ú qwy^˜éïqãòÆÓ^èý#¨}“î6ÚO•´kº9VO€­ÛøKk•VìÓEͦ¢ÂJÃ2£ç¥y «ä,Bè+ü£%à+”=¸{Ìêî¢RM«ëÔʵú÷tÓiÁ¥ücT¶éB³ìñê{bªk#ªØ”°7 U£1LËHUù˜:â…ÓÊúëU¾3Ð @ _úû¶·½MÁ¬þ£=ÎÀîÝ»WlèðÜü£¾)³>E„EŽ¡Ã²Õľ MX¯×Ø?†«Œ•ÆBÿZKS¢^äJº¥VvGÉ×yk.+lìªþQ9^«jl\ÿhÅ¡:®¿þúü¿ºH è~&zÃá€ÀÊÔô>ÞláÝ Ó&à Z¤ù¼eºKIõþ3á(–ò…*MÑ*rNûŠþïN4ØjÿèÊÒo§c.»þ:õ‰ec,{<ê±Ð?F¦…š2=1Z·¾P}¦c§þ±ÎŸ´ L™€>/Ý~ûíl{=å9ž÷ØX]6ÿ¶lÙ¥•™/ÿ1Ü…&ª7,\]}YSu…þ±zggOɲM}¨yÉèÖ‡«©Œ6ê bÊÜj9ÝöFKËýkÊücõë¸zõ÷¼ß=¦I`•õ…þ1ŽU‡þQAô¬õý£›ÁPú÷eÎ4õ*ŸüëöÛûOxsÃjÿºK»ñb¢+Ö_·÷J^ñL룕چ=\_Vê«éñÓ|[aT€ ^ Øþ3DAöÊ™àCÐÙCu¿ÑÒéÈaùª…ôê< ªpÿ™tEp8üŠõ×ÕþÑ»¶o<¦¯÷MiÂîl«îÂÈѽ#ëÌQ™Ú‹n|i£e›PGv2Ý ÜN—ÓÄ?Ö™Ú@™øG_.]!Ëö¿o n5Sgýµ›A;1=nAÓþþúÃÝeýZÔžü£í yë­·šRt·h§¸‘ Ûßu×]Êõ–ýè÷ôÆ×_½EP¨}ìcj`--²: ú3µ®õ£?ëÊR+ˆBùpô}5뱺™ ?J©ðÁúSacŒP[2ÑÀ³þãNÞ98ÏpŒ;wîŒnþhÔ!˜á(®ºê*{\íõ”‚ˆ¼áM¯“:çþq&oM € PJ Ð? “!€Ìg*ËöŠÉ'Ã1fbb7*™ã@ÈXŠ@cÿ(U$—J(»'`¡‰sÿ¨³Üš“Ò©uR{·“濤ÍKêÛK„¥--±HÃ=øàƒ¡3ú-‹|™:]èÕ—Ê*+šyæa´Âë8k#‹g>7<ÅøúÇš++‹ìÒPCSÀpfüqk ·¨özÖ1´³"6GÑ¥¢^ôxýñzKüãR/pC€&Hÿ8ÁIeHüc>—ƒofIJÑÂêtstÇÉLÒŽÒyÔóŠEèy¦MV€@Kmü£)!7P|e:)ôÖÆŒUµ~²È  çP¿eYªuÆÒ@™îñ©˜ +DêmŒöTaa£Ç¬3MÄð-_òœ@=üãè§TÀ?fuè®…ÑM'LOæ.uŽá#£zª*¥øqÀ«ˆ®!0öþ±Ž\Kýc³h“'+#-,tõÉûËÿ8Ô{ýB€r!€Ìe&È£øÇ~¸€†$ ßnÏöÜrË-¶Úºÿ®è¡wv'MYÈx ììÚk¯µEÖú¦¿$ðC¾_Ð7 @ øÇfú#€ì-‘!@`(øÇþLÙT#ßyç¾MmæÞÞñüóÏïuàøÇ¡Þ+è€ üc.3AýÀ?öÕ¨€ 0$ÕøG3VÔ?ö*æVü±Ç“g4íèÇÛÞö6mÔwøÇ!ß/è€ üc³@ýX[[ë/8‘!@ƒXìÛI>ðƒ¼QÐ) @ #øÇŒ&ƒT @€@ ²9Ïp@`<ð5^Ö4 LšþqÒÓËà @˜ üãxÌ™¾Lÿ8Á·!†@XŠþq)\4† @ƒÀ?bõÆEÿ8ø› @€&€xè¾gÜÿ±gÀ„‡ àÇeßÈÿ8ÀÛ]B€²"€Ìj:H¦sìÝ9RB€ÀàôÛí8ÆCÿ8ø› @€&€xè¾gøÇž€ €y#Ó— àx› K@€@VðYMÉtNÿØ9RB€ÀàðX½qÀ?þ¦A€ àžºï™þ±gÀ„‡ àÇeßÈÿ8ÀÛ]B€²"€Ìj:H¦søÇΑ€' ßnâ€ÀxàÓ @€ÀÀðOÝ÷LÿØ3`ÂC€Àðã1odú2üãot @ÈŠþ1«é ™Î à;GJ@@œþ«7.øÇÁß4H€ 00üãÀ@÷=X[[ë¹ÂC€VMÿ8.ûF¶øÇU¿GÐ @ 7øÇÜf„| @€@5Ùœ§9 0øGÞÓ @s'€œûÀø!@üãxÌ™¾Lÿ8¶÷ò… tMÿØ5QâA€ ~ à±zã"€ì÷è€ ü àóŸ#2lC€û?¶¡Ç¹€ 'üã¸ìÙâó|'!+@€ÀêàWÇšž† Àþ×CP§O@è—€~»=ÅñÀ?öûŽ@t@€@þðù϶!€lCs!@ OëÖ­Ó/8Œ…€®ØSò|-‘ @«!€\ gzŠþq(òô @€œþ‘‹€ 0køÇYOÿ œÁ$3D@€r'€Ì}†È€ Ð+üc¯x >8üãàS@€ @ÿÈ54$°íÁ“ú×ðä’Óðæ£/v³:šº»ô¾çÛ÷xüÅ—ç¾ãiŠX1üãŠÓÝŠ àW œî @€@JÿÈU1 uuá½'^·÷™Ã'^&³Wz=wÿs§Þô'û§dvyaa2rOeÿ:—t “YM‘Ÿnû2àÄÔ%¤Pºœª£iÖNùÎSw<ùç–*‚âT«Ì®í–ÃäôIÀ?NrZ”À?r1@€ Á àŸ‚™&`j¯pðrFø Ædß¼ïY% )—$a¤<õcuQž¹§²]I:õ’Uy]æþÑ&%´™*QL=cÿX§ŽüÚnü¢àÄiÀ?N{~ÝÚÚ @€†%€–ÿ|{¯ð*[k_ŒÖ˜¬Ÿ¤•¤G¸æw/,¬kScåìÿ¬ˆÏìJvXؘOxbæþÑ&%„_¨øÇÂSêøÇa¯íN& “$€œä´2(@€ äCÿ˜Ï\Ì+“ ÿ8,³Há¢Ýšþ1L»'QØSØÆÀó÷ÑÐ÷Qs"z%€ì/Á!@€ ü#×À0*ü£î–ÞÿQ?Z5¢<  /ý˜Vê¿iczÇFÕù³:½z1u˜›t¤ý¸Ôý(+D¡n%©,f4ýÖ]jÈ~»@‰3[ºk‘+nk¨aêŸÎõñºK5°Öo4 éE71ô)°Õè¾¢9ò6Aѹ6;+½7¢fÍièY­k®@—ò1,ÑÅ fÞ‘¾÷á[G¶"Ûþ—’Õ˜¿NÊâxý£`Z›ô:Œ®mëÝù(a^ô:{øÇÙ_€ @€@¿ðýò%z ÿ©éG56;fÊ4\hÐÜÚ0¦êB›cÝÙ³ŠP½Ã‰Œ••@Êىˮ/“hVJi&Î\žþ¹>³~ÝÉTz%f}ÿèrÍ¡Y¨¯'$`KÎõ¬šyG&1í§ tŽá÷’n$´ÖÀÂú]5=¬fЄ M«A«öjÅ/,Võ ÂhÕþÑÍlá^ÆÕþÑñp¥n^]ÛÖ—ñ±ö¼c@`øÇA°ÓéÊpÿÇ•¡¦#@€ PFÿȵ1 ¥ü£‰-—€&qÂb:“GªžóÁ¤j,Ô‘aËÂñ›9²]h¼qá®#e§§ŠÓt[XáhÚ4|ݘZª õH…› êE«(ŒjPáŽ:jUÞE³cÀSëºÿ EmÔ‹2Œ1ûæ®Ð¶«ŽÜhˆ7]oC Q›t7«X]}E³\qÿÇP|›“ Ó‹N4#ìÁ^–üVéuð3˜äY‘ý¯g=ý € <àó˜‡ùe±¬ ‹ÈLä¹ÖIïØ(œ¡è1 ”.þ-£nšÌ2 …š¹­:sU( -¥héw$­æÑVG¥sõýc¤bMó…ÞÑÒ*1#áë¢0’¼…ò±0Ûh‡–ôˆf6E‚µQT Çúþ±âKÓ¨ðáC Bxͤþ1Zq_çê¢ :'€ì)³"€Ìj:H€ yÀ?ÎsÞ‡õ²þ1Zz%s:æìü_T[g…uz°úÎâb-åÚ|A±w$–q,ôÙÛú?«à ×›ý´l£ø5ë#IšÊ²Âšåþ4d_¢žúÇtº/—NK#­ =Ö´¦Ë¤U¢Õc §À,›±µúM‹zÒúþ±â[Ê?Fš;ºf¢¹°¹Vîü8ü[Ò¼3À?Î{þ§?züãôç˜B€ =ücöS4Ñ;÷fš¢‘×óåºe÷s´’:_k?º\«£ÿlº*ücšdä­Óp¯_uH%iÿè7£´ô TTÿXæM¢EuîÓñ†®pYÿ(·èd|ñ²¾1†æ7ÃIÏÜ?*g»·¦]fXȉ¾Û`XøÇL)¶ €lS!@€@7ðÝp$ʲ:÷5—W›ÀŠ*=ùt‰´+Hs[éäÂWøÇ…[Ù˜þ³Ñ {ò6êhÙúþQ¬´3ÔgeåŽË6½YÖ?ú=4íëÑ×Å/¼cfÅý©tªâ4 ¹°>wÙí!8öÊ‘2)ô„¦Aÿ8yd€ Œš@±|ò…—6ÝsbÔ#ùÌ tèMu…ú¬zìÑÍ ÃÆæ§"É(Éåj5©ŠB ^]ãf¹IB™'Õ“\X2Y¨íL;šÉ5¨Qía™ç5Œé5`‹©S)b·N­lÐö™1V¦ðÒÛ/¦Û¿DޝptÕ¨ oåY¸ª½zýu8.{M^ó:¤"'Ož<óÌ3·lÙ²gÏ}ïφþñСCÛ·o×#øG®ŸÉÀ?Nf* @ã%Pà%ÿá–gö?õçñŽŠÌó'Сtn!bZÊ8èñP9E;–„¬üža{űlë[ÎB{U(éô IëÝ£†™„E‘e{%/”‰odÊì^™Þ‘¾±ÁÖ\í#uX¸.[ƒõÌ­A8MÖoµ4Eö]k¢Åצ8ÃhVÍ9Êþ±0βþQ®6”Ñuôtþ¯k2ÌŸÀÎ;åbìX·nݦM›¤#ßð†7lܸQßûSz0ÿ±!jÀ?ÖE3@€ ÐØ?"ûcMä€WúZc}cÂ+òAuômÁlêÊï`èÅw!¼³ad ÂÄÂjG¿¢ l‘yº¨Ê¯pZ˪ç,¸=ëë¬ýþöˆÕôéPQˆ=X¶orÿhÂ1̪pÿë²û?:;+¬Ù4…F¡yCkàz·ºðаè”H#zœh:Òh~”]oaaiœeýct‹Ì…â•7tBÀJ Ý3–}Cñc'´ ’ µµµL2! @€ 0[¯òÈÇÙ^«¸ªÞ‘í{«Œ³]˜½J.úÑRUƒôVŒzDVNÎK Lß»ÈS{‰?=hO-¼ÅžNT|S„ú&l¯8ê"Œ\ˆ®0=k—°ó 8Wg¥%œ! ®qUÂÀ†Y¥­¯p\’zJF‘õUß[ƒê)°d¢¾ÒGœ¼mP.ÐVuaýú¼(›lÚÕ†·”^áu¢³ìJðÌë_`!Õ4NJ5E”^Û6|Áaó™Õ¿ ͶÇÝ»wWûGB· @€ú ð?þùØ_bB€r#°aÆ ¹wïÞÜ&@€ @`Ôþê‘£žE’‡ Ô' ÃXæ¥&ëÇ¡% @€ :^öÈÇ:¤h@˜ ²HŠ'3Å Ä pÿG.@€ 08SƒÏ @€VLàÀi ¤¶¦Yqt`ÿë@¦ @€ PMà”ÿïÿÚ6“å_Oþá–g¸ !@¹زeK¤ wîÜ™[’äöðí€ ´$pʯÿåß||ÿSnˆÓ!@ƒ†þQÅ'OžQþ¤ šð5AÑ € ôGà¯÷ü??yæÛ‡_è¯"C€ °’âÇÜf‡|º"€ìŠ$q @€@cÝÿúÄ_þûMûžýÂC>4&ɉ€ ‘8vìØé§Ÿ.;£¯ú~dÙ“.êÀ?ÖãD+@€ Ð#¿úGëá¼»NlºçD½€ œlÛ¶MvF_sJŠ\ Ð%üc—4‰@€x•T„Ëï~ýÏ©’€ ÉPÙãºuë(~œüDÏy€øÇ9Ï>c‡ @ ±TZ_{ômÙüä /e’"i@€VC@[²ìß¿ïÞ½k¯6lˆvˆæÇ‘ÐTÚœîÚµKS¬ƒÍvVóšÊ¡Í{i @˜3ÿ(·ýñϺ䜹0ö8wÿsoæ’ëú}Çÿòº½Ïì:¾R ±ê‚¼ðÞ^îGQçjï¯÷†8¦{šêþvïÞ­mXÎ>ûl™5YªM›6éGsU‘Óú¼F&³lsºuëVM±ÝòR…ŸúF:th^8- @€VK Ø?®6zƒÀË”zÓŸÑ!;žüó)ßyêÒûžï0æ¬Bé‚ÔeéCÖ]]¢u®ö¨÷Y‘_Í`9¢íž7nÜxæ™g^vÙe?ùÉO~øá—8fFàOúÓ/ùKùGÙçõë×ë&˜XÍH/€ @˜ü㬦;ßÁÖ12ùf?tf7}Qžñø‹¯ºgþ±å´à[ÌótU;nß¾ÝeÓ½÷Þ;3áÆpK >|øÚk¯u%­Úy^Ãd@€ 1À?ŽqÖ&˜3þ±Í¤J>ªÔQÂ1 ‚lƒTçöWXçjï¯÷–XÆ{úñãÇeUãöÕ¯~•RG4d'žxâ?ø-Ãg]öx_òaæÜÿqóÈ( @5ü㨧/ÇäuÛÁŠ´$ÅŸ(ØÚ¨ÌȨq¤ÕšYq û¢©Mšu 3,rص:­Ho!:þqa… ê“×pF+l «¯Ÿ0‡…ä­ñÂLÊÚÔ4€—V‡ðj/¼ä*ìgÍQן¬9´Ô6#;vì0óøüóÏ£Þ P“€Vå«TVËóÙ|ìoì=ö$@€&@ÿ8IÌeÚUCÊF…x&nBï#£ý4üY}sÍï^µ/JêµqŠ=XPOE[ÖHÃéAXJ@?ê«%fß§°ì,-^3ÔŠfµ´§,ôFŠ‚…µÑ^%iþÑV0ÓšY„tž©žVX+CÙ¨0ûÞxýc8ŠtC5 9‡9Ja‹V&õêN5­Í P-¤]B*¡Íï'£Zðµ0Ñ€ ôIÿØ'Ý9Å–I‘9’v‘¹ÛöàIß»CnÈüŽœ‹=«ÆúÆ EªKªE ô Úè“S‘[´‘ —!›€³ÈŠ Ü këÌ"YÂêW-Ýéq% ¦ºLJÚašM3Å©Ce>QÍlÈ–Xäh45³¡&³GŒ€ºŽ,›g¢ü ¾z×÷îImøN^]Xw¡Hµ©±m²ÕÞê(ªýN“:µ€…—¶‘´YVÂ)› #£Æn'½¥hy–íÜmzÑ®4»6¢+!šw Üø„lÃI·)NáD0ºD•â[Ž¥7ÎvÉ¥XÔûÂëmNo6uǪ•³*^û÷ÿ÷£Gþ…-œ8qBų²ì‡^÷å—Y;ücfB:€ Ì‘þq޳Þù˜e‚Ì£…‘Ý™ý åWí•ùG³Ta¹Ÿû;ÅÓBÿh…fCޤ›Zš OÔX¢¦åif Ü0F®Ó4YÁ”SXõ©½´‹²QT¬¿GaØCi嬸ʲJÛkPéD{ViyfªðÒÓÓ‹GqªÇ­UÌ ‹×pÞM/ú¤¤“ž^“Õþ1ÍÐ/ø¢ËÛ7¸ÞFù>Ò]Ò»ví:ÿüóe‹ðgèœÀç?ÿùK.¹D7íî‚%Rïð½#¦@€ °ˆþq!ž¯A Â™ J%`Xgù&{*õnÖ‹Õ¾Õ÷é}úÇBÚ(ËÐñVÏv§!èGo=›º¿HŠ…÷I\x?ÄÔÿŽ"œ)¯ GaΗ*G¢-rd…—†Ÿ|´ÅŒÚ^'Öc”ƒÁ¬(\µeËÞKظpà‘Â+ô‘ ­ðÕ®Ù°4à iƒë­Æ+uúMd…¶nÝú™Ï|¦sëD@8þð‡ª®eSš½¡àG4Y¤ @€ÀT à§:³+×Bÿ˜JÀ…þ1uO¹ùG»‰aôϹ[M¨r¶Û2šÛ 9,ô %Ùê7 Wã.T¨®h+êÝ?¦£+Ý!–Õ¥z2&LõÏÉÔ÷~óJO&ºïd8dW–Ö8ª¥-ôу…1z°±lÌ¡Ú?V_o+}ÁçÚ™¶Ù¼yów¾óLú&pß}÷mذáÀ¹¾ÈëUð\€ @`pøÇÁ§` D WÃ!*ªA´d;4˜¦ReÙlýuõRc…úÀ­l0¼!fõ×Uu†+ºÃ¦wWxâÂúG»™c…Ö´øÖµÛžÎѽ#-¨Ñ]C§Vè©#{¸ðõàÛò” ë¯ x™!µa.Ë¡býõÂëm!´94|<÷Üsñ‹_ü™+!ðøãk™ÿ¾}ûæðúû×ÖÖÆ>ò‡ @c'€û f‘¡qQeb%¼ëŸm0Rf¦Ì‹…»kV|>˜ÖšuïSè¡R^©¼[¸þº0Ã0rÓv°Y¶þ1Œ™Ž7pÑí…þQ§×YOíe X&…3²Ð?.+×R‰­›.TÞ‘"· o ^“õ…@xÁGV7½ÿct‡êË{áõ–Å»À IhÙµ*‘+Ñntò?žzê)Yï#GŽ zùÓ9 @€F@ÿ8‚IÊ?EÛ;Ø+¬VÎŒ¹ýh«zõÕdP(ã"Ac5q bNGòÎâ‡7…´ Vƒ¦a5þQ=Z†¡ÀRnÑm½\QfÐr[Ê?*š·ZÒ…[HWë׈³M:rw¦Ó•v´ÃŒ%_Qñg—¨·œÐê%úG× ^N¨sE¬¬Ø3ªÔ ç=¼äì”P^ÛÀýSé5Yám°áé–F}:WímÈ"–^ÞQïÕ×[þo}g¨{>~ûÛßFŒA`õ|ðAÝ Rå·}_äć @€À¨ àG=}%ïŠÍLо†åx~C¶â¾„6*.&°ìIÆpÀ¾=‹5c*¬ƒëcýuš¡åV½…ù›iÒ×¥ü£.'„Fsïm­´ž­Sÿ¨f65þÏzŒY›­ Mbá•çšØ¢)a îËîªTÃÁÚée—»+´f:Ñäl$^Í€[ÚÑÔ(¯ ÏjÿèÝ#øéu8ØAÃË;ºP£Þ£WDá 2z;Xm*;wîÔ–Ä«Oô#pÛm·©üvµW=½A€ @`dð#›°ÌÓ•s”F)ܬيÚìÙô‚²9é†3zPjI§¤{a;‹iÆMKh£ ú1\÷]H/=Ëä]t¢‰ªÕÌ3Té³:%o3 X˜¿m±’OÇb(Bé( 9ûÔˆv: 6Ló‰ /?eq¢öî1 —MwÅ]&­½í-îF4j/55&éõ.·k¬pú “·4!Jx!‹¬f…§Û¸ìõ¶pv&Ù@wß{ÿû߃À°®¹æšíÛ·Oò%6AqÿÇiÌ#£€ @`Ôð]Nߦ{N<ùÂËë…9 0%VXZ¨•3fû~¦7èÌp ¤´À¡C‡Þõ®wé|ú'z‡€\|ñÅ{öìYxÑÒ`ì=v:… @!üc—×Ãmüó?Üò̉— ›8 0¶Lx,ãÁ?Že¦Zæ©=gÞúÖ·>úè£/r@ Ï>û¬ö¢‘oyaszð}P%& @XŠþq)\‹ûð oª±Luq Z@ *{´Ûkæ‘Îâ,ð‹M¢…nûø¹Ï}.ïD ø+ýèG[¶l™ÄËkjƒÀ?NmF @#$€ì~Ò.¿ÿy-Äî>.!0›B”K­në$\ç–šµ:£ÑTüxÖYg=öØc¨/dE@78pàÀ¯ ú¬"€äú€ @ƒÀ?ö2ò²½„&( ÙÐ^Úñ#+ñD2ßüæ76l˜ý 4;øÇ즄„ @˜üc_s®UØZ‹ÝWtâB˜+cÇŽ©øQ·ÛCxA C]tÑÞ½{çúêÌtÜøÇL'†´ @˜üc_³­]h´v¤é«âB˜%mÛ¶}ýë_Yxä‘GÎ>ûlÝ"`–¯ÎLÌtbH € 9À?ö8ÛO¾ðÒÿ¾ùøCϲv ÌŠÀÁƒu‹½gžy&KõDRx™€vFÒþH³zaf>صµµÌ3$=@€ 0y§¨FO›Ûò¯?ÿëûOOþ2b€€VC`ëÖ­×]w– 9P äúõëWóŠ @€ Œ‚õýNÓÿ½íÙݽØoD‡ 0Ò:’;9»'rƒ€œ{ÕÍë’B€ @`üc—ÈywøÂCܪG„†fEàÀZ|Þ‚@þ®ºê*ÖüÎê݉ÁB€ TÀ?öu…üûoŸÿÀ¯žï+:q!Ð7ï{öÔ›þÔ>Þ}Çÿb¡ôïÂ{O´˜y„Kï{^#Õ¨3ÏsJéIè\yå•ÚÙƒ™¸óÎ;7nÜ8¥Wߨǂ õô‘< @Ó €ìe¿öè ëïx®—ÐmD`בÌ‹>ñRàu{Ÿ±gíŸ~Üö`\¸j²Iÿ®ùÝ e)è)k£îªÓ¼ùè‹®ê¬Ç0l(òô¬Zª}ðÜýÏ…ÙV¤T‡– ¿NËê6ÊS÷Q•y«™øG÷Ž'Ùã¾ýµS7‚¶¾ÿþû3O}¤wÆgœvÚi÷Þ{oãà‡Rú¦qN\ŠÀYguäÈ‘º7íú$Àþ×}Ò%6 @¨EÿX ÓR¤ŠtÛÇE-EíÕå×$³ZˆO55¦©XTSÙ7=% gÿüÇ0Š·ªÎœ ÚHÀU$/]hq”•©:;Ër“!µÁŸUïÐ2±sõ¯½=\6BÙì˜HípÖ2%øøÇUΑTŽ„ÎR¨°ñ%¯ÇŽ+|ö³Ÿý¬žýÖ·¾UÖ‘Þ>¥"¼æ5¯9å”Sn»í¶¥Î ë\Eh¤qïFÕýØf,ÓXñ‰Ÿþô§wíÚµÊ×}•À?rm@€ Á à;ž‚_ÿËÿùÉ3O¾PPd×qO“·¬«†aFÏj ™yCrüÅ—Ìñ…u…ný¢Çý,³Šæ¤*ü£ô´ÉǨnNòÑü£Eˆ<©Tê,S“áW\ÿX8;ªÙ4‡;é óUƒÃ?®x®wìØñ…/|¡½B2—'VÊžÕ×2;YñlûÜÊ"ŒÚ? µ©ÏèРVorû›£4ò­·Þºyóæ¿Lè®þ‘ €  NÿØåyþ%ÉLJž¥ô±U)63\úFÿÒûëIáIýHº.¦Nû–Ë“³EÍöMÔ&ò.ChþÑÖqÖfZí¤ùÁ ÿh9TCkP¶ª×ÆR]_ŽN.ÕC·4r¡O,ƒ\8;BjúÕD]hšô¬ºŽV‘[žj¬$õžÕèì{{ܾIÓVwjY­°}Ùåhq ™„ ¨Yaò¡T›Â)cuv«÷‚WŸ¼iÓ¦Ÿÿüçíý‘Ö K„ékꦛn2G&5V¸NYë õ¬¾.›†œb–iÍ…ÑFí% ©×?^pÁ6"9(HM¨òi0­ÕwüøñuëÖ©M‡¯B5#€lƳ @€@‡ðÂüï7í{vÿSÜ ®RÓXá¿°2Ñn°hõƒö5ª,ìÛýšÕ¦·&¬ï¥“쾑ú´È’YÕþÑ*1«o¶hV«l\¿~™¡Ý¶Ò¤¡SNü£­÷µäúƉ•ÍNÜzqÉë«Ë}Ê¢ÒN=®$5^;ÑÔª STÃȦ}Ð/=N„ßÓ’¯¦dž7f(4=o–bý£1Œ® Ô´zGN–Êyâ‰'žo}\qŦÃÒHòb^£§ +ÒfÍ ŸªÎëâ‹/.ë´Î€¬ßŸþô§u¶Ñ¹6´6Ašõ^6v“¹…Ѭ£Æg½öµ¯U&úÚ8BÙ‰çž{îÁƒ»z §1ücctœ@€º"€ìŠ$q:#PVÿ¨ÚCs@扤uÌïToub낽M¡þ‹”EJu’‰0åf.êÔw»8+«O4MY}kK¿ÿ£š•í–r¨ænŽÌD­P8´ÐoFþÑ„ u­ö6p—hKÕ?š+´®Í}b¸?»NU›\Óæ-mKÃRÕéJÏf?ˆµ· J5¨¸0,šÓÅ¥PJ…Ý…þ±ðªXèš;{ÍÌ •’u¢‡î¹çž2çÊŠ£îLáÉ—=üðÃËf‚L=ã7Þ8”¦¯?ÿø¡}hïÞ½3xæ>Dücî3D~€ Ì€þq“<Â!®.,1[¨xL¹>3i-ݵÒ<[@m½˜ä ɹÔƒ©¯ôJÌêúÇ…w‡´½\Qae!Ó:ßNGYUïµ]XMå_HÛÇn+¾£[a¦%œia¦‰Ô¨Ñ lø Áf$VxßÌp ên¡Œ¶A™+Œ*L ”+ËÂ:Óˆ[tÿÇèYK¸þJù¾LWšòÎ;ï¼e­_Y{+'TµcÔÀ–H«¼±°.ÏbT%'©8zÐεe¼2kYå–ö¬¹6}oÇ7¿ùͰwuQ̰ØÓëõàÛßþvïK)ŽQÁ=šõUQÿ¨lm²j_ÖÇbÍüH]m˜U™{­ŸR„Ôƒ+r˜va]jVôB}¬}vÂA5PÌ…¡;–ê¾¥+}©ÐYü#× @œþqð) ©+”Y:Ó|bÅ]ö ­PäžBÿhíÓû3†þÑœ¦·1î•Y§šþшHüY§…ù¨w·‹Ð ÷H Ç¢ŽªýcjT Û§ÂÎ7ä‰&8š‘ÔQšMå]Ú2­Ü,d%PxÍDXaQwÛhµµ•ÄÖ¼E)ï ìÞ½ûÒK/íÊ?Ê:¥&ÑÊñd£äž ×;[•\h-uеtuåžÑõ¢Ù·ôŸåcq숨="ýçOyG:7Ââ«È=”Îõ.¢õ×QãГªP4ŒlÒ‘Z/SSæ½þ±°#wµžR¤m:¢|¢P…mtŠC°5àéÑÕ*õï}ï{—]vÙÂË›}ÐÅÓwć @¨&€ä É‘@j¸Êê w‹ö!Y šLmŠbÿҒɨŒÎô\T‘:;sU¾Œ:ôbÕõVKXçž•>;%,á 'LIšõ©OuåÍ|EÖÌLœiAóVQ`*%­¶.ôbªOLóJfYp3_v„E|濤íA P“}nÓBíèÅ•®ÃrK—zî%õˆ¥dGص$©=ŽÔ¥jXéé5¡~º¾±¬ÂÞ '¨Ð?:¨¨vÒ;ŠjHž—%Z3eV‰ª£¨¶ÑÚ>è©j >e65‘ÄlsÕ]ýõÚ`g$/2Ò„ @€@ð=Â%tceþ1½£_X{˜v绚˜Â ÿ…Ž…5’Ñ] kmgçPÿUûG¿«àRd¬Ü²L¨ùm1 cJ@ èE£m©ÚH¨ùý.ûÇt—ê´h1Z£­4«4šBÖTøG?¥4çhf6º*–šnoºòÊ+Û˜ t©µäT¨MB™_3] ¸BeY˜OaËŠû?šÅK—<‡ÌýcT——žk}aæ–¤+È0‚=˜VPºÄt ha£ëF)==Ââc×7vØrïŠ<]Åz¨¨øÔb¦+è½½±êˆd¢|eªMSeÜÕ•ö³ŸýLû¶ó¢† @€ð\9H ‘m#“%[ƒ\¶Å°ù °øÑ…Z¨ÓŠHK \<ùGßoĶÃvˆÕþÑUZ\Y=Õ«¶ ïTèËÖ_‡£ i[¹eh¯¿NCYVý­¿1šz., µk&Z³o˜_Íü£‰])×èªÈñ56¶œ:÷©z ×ûV3î¡jº6µOÏÕƒÕ÷@ +û Í—)³è–‘ji%a ¡¯ÔŽâ¤7[¬ÞNÇâ¸à3\Ñ èÂb¦ù®@WüBåjuŽeAÜ«z×e[¢Û.穇-,nÅ?Žíý€|!@€ÆGÿ8¾9›CÆÑ]²i²PÙzÛ²2·Â-‰Cæz1õæÎÂrËÈ?ºG‹ÖS/ô&-º3 Ê­$3Uf¦ÒìY}N¬^ÓmÝ…²5…úÇ´ž4Õˆ…³“jÐÂ[v¦Ùv¸þ:|iTlÿR¸ÿLYqšùG_˜.Ï÷¬4ö´t/çNƸ}ûö¯|å+]U¥)Žù)W]~óGï"ª’+pa>¾°ºpûš2ÿXs_ìté·uÀ²;Wº ×_G"¶‘’+¬4ûY¿þÑ)g¿-cTœè)y¥dX2úD©yÌt»KØžŽ´hÿØÉ‹4ç Üÿ1çÙ!7@€fBÿ8“‰Ù0ÝRI¹´…Æ2;zVë«Õ–m]QiujnúRÿèzÑÁ¥þÑw‡Õ— ý£ZbêTäûìf‹^uhÉ(C{Ê»c5Wè'ZQ©f8ÙæÍñÉ»é_ -ô¾?µ-¾¶MT¢ŠÈÂÙ),Ã4ÎÖµMešmWþQñ½#%ŸV°†X ¸F§–úgC‘ÝÌ?š%·eþÑFÍ–ÞìuÛgº×?Ê|…· oþh&Ζ˵°:2TuŠã«‰ÕÞ¨ˆ¯Ú?–é…½Ôô;J§OUW/FÏÚ"•†¯ÈÖ#mîÿhÊ/ºùca¥dH5lï÷m´Ä¢­Ã[^†üû°úÿØçk7‹ØìÅ4 @ó&€œ÷ügüÆ7¾ñ¡‡2§†÷õµTÅ\Ô¿ßD2|Üï«>èõQ„Ë/¿ÜŒ^õȼþ1jæUŠþxY˰þÑWw M””çÕW_-zJ‡¾¹á†êLHÙØ­ Eö Š_‡FÚéÝwßmWVö¬M™º¨“¡ûÇ:—jóÝï~÷²Ë.«s…Ó¦WøÇ^ñ€ Ô!€¬C‰6+ÂýgÆ:˜1ämK¹¹ÏcçsµgÏž~ô£K©Ÿ…¥ÏÌv™ö E˜kJKžÎ¾‘äŠbʾBÿè}EÓŠ «]Þ²þQ{.ŠNu¤ô쩊®Í½špt %ið2ÿè¶QÝÙ¹ÞoM³ö©Ø¥T¦pÕ—• ¯«°V©oݺµó——%€\–í!@€@çð#% 2"€\ñd®å_q“ìîàÁƒïxÇ;–R?u›e³ò7yÆè¯¡K«#CAÕEÚY‘­s)yôèѨ—Ââ;ÉA=îÆ³¾ôÞÝ3ª;“qv„{×QViñ % Ek{¹ÈÚŠæ:Ëü£ÞЖZ¡eaÝ¢kJ¸sçΨksˆ¡DŽ*"Ãö‘JNËH댫N­ÊWª“|IŽkPøÇqÍÙB€ 0IøÇIN+ƒ‚À_ Ø.=õ×#® Ýq²ÎÝ?Ût1ÛsOžKµ w)IË­hÑ_ØÆwÙ'%'Íç;;§Õ‚î:ÕX'ºî”Ÿ².t®Ù==U\Ö÷^B¨S,š½4ˆPOÉßY{g!*I¿ç£31ÍšÖZFSPáSWë+©†¨* …úrãiFX][‹£#ô’n]u®hÛÙ£ÙqŠc}¥ÃRו7¾ð ÷íÛ7Û—m>Ç?æ3d@€Àl àg;õ €À˜œy晇n¦Êβ{ šG+lãÒÍW"GÍÌîù¡öR`©áÒY¦áüË-<²{ú1lPß?ª#‰¶(š´š* ƒH½¥[Eë‘h´¯P6…çžÔ†S­ +ü£‹¿°»pc묲òHõ˜Kç(ks®µæ±+ÿøÖ·¾õСCcz™M4WüãD'–aA€ 0&øÇ1͹B˜--[¶è.Ïu}ÜúÊq×]wÖãÖ ¢[µùØ+ÇUW]eÍì¬ôoyýõ×§Ïêt‹“>[ðñÇWG>ø`E4ZY« ÖµŽ4shÚNÝEù&6ÕÓRA¸ o˜’€¤cÔ#NÌɦ¡Ó+Fç§x³²‹aÙKOÎwݺu³}Áf5píJŸU>$@€fHÿ8ÃIgÈ€ÆGÀ¶À^ÖѾ=É;[ž†’³35Ù¾—éEصk›_!@€ú!€ì‡+Q!@ SÇÃÞ0=K•ÿˆÌ?Ö?Ú²e}Í«ÏP;¶«b·ÓÁ @€ 0VøÇ±ÎyC˜ÝõïöÛo_½HšyZél7[ÔWÝJÒÖ2û&9z°pøÌ¡=õÔSºc©¤ùÜ^¤Œ€ @…ð\€ 0ÚÚåŠ+®˜¹Ødø2Œ¶u´ÙŽ,dzSÈA2Ì­Ó½{÷nÞ¼y¯«dÉýg0É € Ü àsŸ!òƒ #päÈ‘³Î:ëYŽáÜyç·¼rè›á²AÏŸüä'uÿG^¹™`ÿëL&‚4 @˜3üãœgŸ±C 6ÜsÏ=#ðO¤8oåÒå#{uM7]üãtç–‘A€ 0øÇÑL‰B€€ÖQnß¾}Þj‹ÑçNà¿øÅÆyµæCÿ˜Ï\  @³%€œíÔ3p@ã#pìØ1•@>ú裹+(ò›1~ðƒºÿãø^]ÓÍÿ8ݹed€ Œ†þq4SE¢€ ¶ ÍŒíCÏš€¶h×Fí¼T³"€Ìj:H€ yÀ?ÎsÞ5 ±8yòäúõëyä‘g8 w¼ãë«k¢yã':± € 1À?Ži¶È€D`÷îÝÿøÇóSOd4w7ÝtÓ–-[x‘æFÿ˜ÛŒ @3$€œá¤3d@£' »@Þ}÷Ýs×]Œ?'üãU™«[”ŽþÕ5¹hߪɉA€ ‘À?ŽlÂH€D@û{h—œì¹ÌÀŽ;¶mÛÆË€ @H à¹* @`”6oÞüãÿxîÒ‹ñçAàPMîñãÇGùZ"i@€ ôLÿØ3`ÂC€@?äz6nÜøë_ÿZßp@`@Zs­K‘mgúy¡€ @` ðS˜EÆ@`žŽ9¢í†ÿð‡? èžèùÈGöìÙ3Ï×à(FÍýG1M$ @€À´ à§=¿Œ€ÀÄ ìß¿ÿ=ïy CÛÚ¾}ûÄ_f#û_|I€ )À?Na 9عsçå—_>”~¢ß9øÑ~¤ûÎùÕ7бãG1M$ @€À´ à§=¿Œ€À,lݺõÚk¯³cì«'Àž3cysÁ?Že¦È€ À?Nxr ¹8yò¤ÊоúÕ¯þ‰+!ðóŸÿ\{Îè¤syyœøÇ1ϹC€ 0øÇ‰L$À mÛ¶}âŸxâ‰'V" èd¾¾ñolÚ´IÛ^ó¢üã(¦‰$!@˜6üã´ç—ÑA˜]»vi;šC‡Í×1òž h±¿•ÜÎë¥5æÑâÇ<{ä@€ÀDà'2‘ €ŒÀ´0öÎ;ïìYC~v´ÚZv[ûñZüã¸æ‹l!@˜$üã$§•AA˜5y")H-’!cÀ½¸õÖ[7lذÿþY¿´Æ9øµµµq&NÖ€ @`:ðÓ™KF@N@ËcµHöŸÿùŸo¸á†§9 Ђ€*jßûÞ÷ê†ì6Ã;  @€šÀ?6ãÆY€ 0ºä–-[Þýîwÿìg?k! 8u¦~øáË.»ìì³ÏÞ·oß.wR„ @€@®ð¹Î yA€@G´fV˱?ð,+-7}úé§oÞ¼Y5ÇŽ[î¢uÆØÿ:ãÉ!5@€æBÿ8—™fœ€ yܶm›ní§=j>ó™Ï|ýë_¿å–[~ÿûß?Å1º¥£ö&Ò"kÝtݺu²ÒrÓüc}V´„ @=À?ö–°€ @ÃÀ??d@€Àì àg € L—þqºsËÈ @ üãh¦ŠD!@€–%€\–í!@€@çð#%  @€@.´ËP.© @˜+üã\gžqC€ @€ @ øÇþÓ @€ @€æJÿ8×™gÜ€ @€ @èŸþ±Æô@€ 0îÿ8xº… @ÿCÿÈÕ@€ 0Yì=Ù©e`€ Œ‡þqÿ¥IDATx^ìýkÐ_Å}ç‹Rû왢¦Îž¡ÎÞµ‹:/¦¨©qµkêl^L¥¨l*‡³=Ô1•A¼°µÏ1ØeÂÛJ"3$f‚C‚!ƒ“ÁƉ•Da°MP0!Vp9 ²ƒ…, –•`É0—!‰›ÎWþ)­¦×õ¿®½º?«(êÑóôêÕýéËêõí_ÿ~gœà‚ @€ @€%pÆ ¹‘ @€ @€ pÑN@€ @€ º ”ì @€ @€ €èF€ @€ @€ÀÀÝJv€ @€ @@t£@€ @€ @``ˆn%;@€ @€  ºÑ @€ @€ 00D·’ @€ @€Ýè€ @€ @˜¢ÛÀ@É€ @€ @ˆnô@€ @€  LÑm` d@€ @€ D7ú @€ @€&€è60P²ƒ @€ @€¢}€ @€ @@t(ÙA€ @€ @Ñ>@€ 4ØýÃkÿþý‚ @ %D·– H@€ L lذጼÐÝ2íT€V'€è¶:3î€ @q0£$»â.)¥[ .¸À‰ný;Õ¡C‡nºé& yú¿~^J @X¢Ûê̸€ Þô¥­On}É·¼®¼òJ÷LÚ¼ë/ÝÞ¾,z¢»qóæÍÝn,j*ƒe»RaôômÛ¶u+OUÉo¿ýv+ŒÓGôƒ=BõEÝhßâ~Ê­[·ú½T½H ×-+w—ú³ŸçJ½±ç£»Ý>¬èæç¶ê¨éV~î‚ ÌBÑmì<€ ;Y¸øÂPãÏ’2‰G¾®$M¤ Íà.?ÃúÛýuWQºr…iŸ§=чÐSz„@k+"5é­ +ÒøJÁöÑÝü£šK9³9¬èæ#]uÔÐ9!@ "€è¶ Æ¢¨€ tôÝDÁÿh÷àjI– t¨–®©d>æn,fÝŠU«1kÎ*µËô'þÖ××YÏÕÿ#ì⥢[g‘tmm­´uúŸÙ¢Û¨xÉ€R%€è–jËR/@€@Ô|ÑÍfÖ_‰–þY/„+/m.;ZJ<¾]R©¥Ø¼¢[ â¨0ª©~é|º©Ì¾l$ò¥=CéŸÎŠR·>çw†ªâuËy»³,£TjóØæq~?ôsÎJts}ëË6}†4€ °\ˆnËm;J@X0ž'+}¥©¥üQ´W’šÖ†`£22¯èæk‚*I•vcŽÉ¤ ¢[›vwiüöõ%³ngu]n¦2`¥J­šxð¢ê˜vä:㪈H@(@t£W@€ 0ž¢›Jìka6kC7g¬ÔXsAm4©›Qt êU%¨¹jÖø¿ÃÒ­ª3øíëSêàŒÌïöNµ¹5¸èÖ8ôH@H€¢[H @Ë#Ð_tó-¼mÖª¼ž5*¾C·ª§Ì(ºùõê ùýÑ­è¦4¾üÔ2ˆ‡Ë9è* R²TÔå͆”€Ò%€è–nÛR3@€@Äú‹nñ üÚ»SR=}´ù7¶QXfÝúct•Etk)ºµÑaK³òÏD[ô)Y *jÄÓEƒ ì ºe×äT€ þjQp²²ÞfÍw¤åk|AMO,E‰èÖÍÒ͆ê bSØ/ÝUs€WXdð%I0U»ô³~Soæ2ŒƒGoÛ¶­¾ÇªA‹OWuZF§mÅömÓ+ŠÙºj:/„+)YªŽZA™œUÓÆcÅAaÔdÊʜʹöª'VUT5±ŠäÚ]?·±þS]\+W5“ë™A+¹ßÍV­¾hŒÝg; @ ˆn™44Õ„ ÄE ¿è¦úønÝj¢^úòœ9¿o)“µ4þj™[±úCŽÍ®ª>”ºº b¼ÖëÔãLp)½ÅÝXªšUø-fU#&*g_ *Þ«âUI¥íÇC±};„SðQ»sÊ-E·Àû[)meÕRdTákšLe+ͧXTµ~|ý¾^o¯ÖÒáÒ]U%o<`îš{š>Ó¾w‘€Ò&€è–vûR;@€@¤úëMª˜oœUc³æë;&Kµ94ªd~!kBUÎ(ºªY£á^Ð|U±F8³?ZŒ§ñÞ¢õSûÛ«D7¿õëU¿FÏ}õƒ¤Ø¾AðÜ6cÌ/­£ÑFtóÍë9«œõº›8Ôk”N'-æµ±ùT˜ì+‰nÖ«9´éü“õ™6]‚4€ D·Z™:B€¢#0ˆèÖRûðºÿéæ]«ôj£‰èÆE·¢ÑÞâɪìŸUô5w`Ð~(Zù6GúYEU-¢K?IQ8“¬ã?Â<ºTî ÔÕB§¥ò貓ƒAñÖ××;Òöõóos ²4“ÆæÏ"e¢Š ¯ª©‡ê‡@D«1øÀLÌåfíåÿµ˜ÿ ÿgëÅTÚlUÑ-x¢u6ëº~§­Ëjý)ûLçÎÆ€ D·Ä”ê@€–A`Ñͼôí]u¸Ò}™;À×2ª ©Ú«ióŠn¦^zYÍaÛªþÑò,­»Ý*¤U’“Îñù«ñ ×F‚ñ‹í‹­*Ciβô•šz9¦~Ì”¶¯_æÆ³¾­¥¯!¶ÝôˆªîhIUÆnþ‘Ø*hîüfQ/+5‘+ê¡ÁSªúF›zµiŽA[­¬U§‰'î3˘…)% ŒOÑm|Æ<€ ¡D·ÆP¤E‡nVÿ“¾T§ð¿ÒëU•yE7Õ¥Ô?šYŸµ÷h¶ªè&M­Ñ«e+·‘`üä @5ò¢/GÖÈ1£³´}ý~Õ˜¹+p²QtSÙ$35ºêóGA)@rªi8u²˜IQt«ÊÄOY5pÚ´xQJ.=¯œ°®Òv'î3Š€ D·LšjB€â"àuÛG~ýUUz_o*=Φpgæ´û:Eé‡z©®ÒbÌ.º™îV´ 2ã –ÒÛª¢[›þÔÒ¢°ã·RðYßðªÆÔ®¾.Uíëw¡Kºõ¶èÖ†³ßÉKu.ŸC£]^éÑ­F¶ó‡d•i›÷û³~®ñ×X»éûL›V#  ä@Ñ-‡V¦Ž€ èø_Ýnø• ê#¿ÑàÈ)#Á÷£ZçK-õöb1ˆnj`²ÊÙ¼JXÂ:Ç¢›²m§ãzðJ:Z{sÅšRU…U] »ñP¢[cÛùV£Ý\£èVx9’¥¹µiñöenËÓ÷™è&\ @3@t› <… äM`UÑ­æ;ßW.ŠÚœûtìàê¥ÿ¯QÛèJÒCãSZöI*UÒ›Qc.Ô(Ü´,@¬ œ6ŒË¶ñ\°_€6Pc½jªà¦J®¹}Ñ­¥½a=‡•ŠÚ(X·iñ6=§¨—ÚÖMßg; @ ˆn™44Õ„ ÄE ÝôU\U¹‡W­üs Á)?_n¨wS˜ÿTy¾/…Ø^noéò¬CË™ôVÓ)i @ ˆn9´2u„ DG`@½ÉW‚ê*‡n†ÃWL‚Ó—þy´ë0Ë'BÑÍ Vzà´Ê¤®è¦IÙQ›JéSþþåÎ×èm$«‘¯¢šÇºÆ«Mê‡GMû^ü‹Òp½Í×JJ–U_]Z¸È~>Åöd¬­TÔ¨D·YúLt.‚ ™ ºÍžÇB€ò&0ˆàV«rèf7Ö¸W_IG[)±ßìÃB¨êPÅ ¥gu»‰nU&uE?}ƒˆn~!Û¸ôÓ´´r*b¬oßšp åÚ+YjÄbüÐRˆnA ÎÒgòžÝ©= œ&€èFo€ @`ÃêMU¡H\ReÞUjˆä›Æ´ õ¹èÈ‹f Vlò¢›oØ(!º5š¹ù CIT ƒúö­ ÖéwËÒðmD7Óµ”Û¬ ÝêE·iúÌ S*„ ( ºEÙ, € :aE7_øp2Y½C7ìË"ξ(µÊ;¾ß>UvvmèCh£î5fX“ÀÈÝÅMZ¸I¹ ®6Šdûã¥5G‰ûÀ©¿·± ~p¦M ‡6¢›ŸFR?Ñ#Èõ^ÛkmŠê0Fu¼t–>3^o$g@XD·eµ¥… $B`!À±(8êºÙ½~„Á?”ªœ‰ûC©ASU¾äWžµ±møGeUtT·’¥›¯ò(·i²Q±RáÛ‹nm”¬64VJÓX_t†f¾ÇÀªÆmT²©´Ê½`}Û 2Ö‹ê#Jt›¥Ï¬ÔÁH @ @tK¸q© @ ^ƒ~õŠ¢@½C7»×·†sö_‡R¬þ£W:ÃXj!5R›ž­zŠníåÂFÅj%ÑM‰Á6V!pÕoáïRšF%«¥ž[/ºùzkgÇvEVt›¥Ï Þ É€JÑm¡ G±!@Ë&0¸èV4,r‚EýÉÍàp¨/ ´TÐOn–6U …´1©ëÓäÊËJ–n핯6ÚS{K·@¨’¡b&-ïmS_“Rð-eñqõJVûs‘õm×bµ ‡E‹n~á§é3m’€r €è–C+SG@€@tÝÝÁ×Îê?³}ÉL)ý‚Uæ h'7[~ÕûÆbc;tS•Á¥ˆn¾ºZcØîÞFt Â)´´P›Ft ¿<5"` ·E‹nÓ÷™a{ ¹A€Àr º-·í(9 @`ÁÝ|eAƒŸ¿÷«º|ÉLÊ‚V:ˆx»oTë‚(+y‚s1 ¦6æx,Xêb¬½]U âÔ¾Q鳺¬Ô»­–gŸ¡ÒFt ˜¸X®õ²àP¢›ŸOé}ÕIÕ©éŸëëë’€‹ÂÜ¢E·éûLŸþƽ€ D·”Z“º@€C`%¥e­|Û±–B‰åìÛ9¹d%ƒ mÛ¶¹õƒ©~¥ÅÖ÷ ¸u6ss2™=®ê€ªŒ°ü Öˆ‰í}ÌùLUùƒjÖns ¸ýn£OÜgZNY$ƒ ä º%ßÄT€ #1D· ¤¦©mÔ–@¶°¥œ«oLd9H5Ч¾jê.=(øú b#(gåæ?NE*ê‰Ò«:D`¯§Ûõ)bªEPεøæ„úki½bå—S÷J«Ò£•𝨂²Æ ê¥4JìpégÓÚ,åJv‹Ÿ–êO`NØæ¡JV ùÒªt4ý³Ø¾U=Êq®s4]úk½¹\cQ#Ý&î31ι” €æ €è6už @ÈžÀ¢[`ÎÓÆÔÈÚ!Ð#ÚÈ%¥ Xjëä[À?÷Qܬ¥raÍë•ÄRÕÒåœI,•Õ¤ò™cÒÁLÌi—EÚ*L©}¢ ø§ D·bs4K6*YÅ.í*è×Qڢ˪¦SµïŸÅ~ÒXÔÈE7oÊ>“ý@8EÑ®@€À ÆÝJE¨z‡nVs?ê‚ =å0Ù‘µ¤˜´ñÅÖ¦a¤¤”ÊOE¯ç¸*]¦T´òÏó•>³Ps Ý({Uq«j RõpEÒ£«Nû¶!ÜÒÒMYɶÎçÐØ÷Ú(Y’Šjz”ëHmD7•°ÔøÑ/³2,µ…lSTÓï¥þã¦?^je›¬Ï´éW¤  ºåÐÊÔ€ §ôq®ÿ¯z³¦2.[˹½°¥”V»±>US ;˜\¹Ì%ÍTù_ëÜNî(¥¯wØ¥£­T;ê+M5¢UØŒUw÷D×"mÎùÚyIÿÑ*IÍyXá²Ó¯j+†îÕŸú÷.×”mªà·é{®×©¨õ]" ã·º»LMs\MG2¯‚ÅÎY?ÛÕI{ÖJKâÿªö톽Ѻpš>Óy s# $FÑ-±¥:€ ÄEÀ|fé\h«ª§{bO–OËL†z¨=N¹5š‰ æÊÐáÞ–Õœ=™Õq¨ ›Ûìp: ‡>Ó ·@€ÀP݆"I>€ @€ @8EÑ®@€ @€ º ”ì @€ @€ €èF€ @€ @€ÀÀÝJv€ @€ @@t£@€ @€ @``ˆn%;@€ @€  ºÑ @€ @€ 00D·’ @€ @€Ýè€ @€ @˜¢ÛÀ@É€ @€ @ˆnô@€ @€  LÑm` d@€ @€ D7ú @€ @€&€è60P²ƒ @€ @€¢}€ @€ @@t(ÙA€ @€ @Ñ>@€ @€ º ”ì @€ @€ €èF€ @€ @€ÀÀÝJv€ @€ @@t£@€ @€ @``ˆn%;@€ @€  ºÑ @€ @€ 00D·’ @€ @€Ýè€ @€ @˜¢ÛÀ@É€ @€ @ˆnô@€ @€  LÑm` d@€ @€ D7ú @€ @€&€è60P²ƒ @€ @€¢}€ @€ @@t(ÙA€ @€ @Ñ>@€ @€ º ”ì @€ @€ €èF€ @€ @€ÀÀÝJv€ @€ @@t£@€ @€ @``ˆn%;@€ @€  ºÑ @€ @€ 00D·’ @€ @€Ýè€ @€ @˜¢ÛÀ@É€ @€ @ˆnô@€ @€  LÑm` d@€ @€ D7ú @€ @€&€è60P²ƒ @€ @€¢}€ @€ @@t(ÙA€ @€ @Ñ>@€ @€ º ”ì @€ @€ €èF€ @€ @€ÀÀÝJv€ @€ @@t£@€ @€ @``ˆn%;@€ @€  ºÑ @€ @€ 00D·’ @€ @€Ýè€ @€ @˜¢ÛÀ@É€ @€ @ˆnô@€ @€  LÑm` d@€ @€ D7ú @€ @€&€è60P²ƒ @€ @€¢}€ @€ @@t(ÙA€ @€ @Ñ>@`5kkkW^yå»¼ë‚ .¸ýöÛWË…Ôõõõ 6£À€ @€@ÝÒhGjLAàСC†Î¨¸¤ÂmݺuŠr$÷ŒÝ»wT1L®rT€ @È”¢[¦ Oµ!U ÈK’Üô³8»ÜïõóªÙ’^Ýè€ @€@zÝÒkSjŒB@'â&•ÜæÍ›M†åÙ©gŠè–z S?@€ äHÑ-ÇV§Î€@Îœí¦›n*½]ÒÛ¶mÛ:äÌ-ˆnô@€ @ =ˆnéµ)5‚†'à«B׆@Þ9"ºåÝþÔ€ @i@tK³]© 0,¡T¡ýû÷ëhªlåt) jûBêFEiÐ]º]…©ºQªù«î’b¨¥º¡ýÉÏÙž¨ÿ×茺Ū£«þÑ5•mÄ«"àç zõukÏY·ø­ÓR]uMÓ@z*•µ‹u¡–…lßÓH @€  EÑm(’ä¤LÀ©BrëÖí ©„’bäSY•«¸zÝD+½±xÊuÆ æu®ê¬ZÈÉ– µ?)%S}ý¨¥¾êô? ?Zóô­°&z©2´¿š¨' ÁsõO¿Q$EÄêË*½j]Zý>û᯴i”••æÐžò)–S²&ã‚ @™°-äâfmæX¨þ¼ÝæåÏÓ!ÅðC”*’éJåöƒ089Æ„Ze#æßèÒ»-Ì @}D7e(n¥"/6k´j@‰zK7_t«bº›LÕŠ ì7Ò=‹­¦~z«Kð›RUT¹ù-X¼ÑýµØ¸èIqs+ï t®ÔI @€À²Ø&¥]Z>Õ^K-N–»“çbšù«8«NûËjß Jk‹O]«.ì'(Û²趬ö¢´€Àl|u&0­ª/“Ó‰t—ħàøYU¦dN¸±EƒíÝùFR¾ÕP¢›­Wl‰¦géÑUêž~ï+YúÙ­u—w>´–¢›« £á7Šþêþi X©lÅ–r•Õ½NU§ô9ë?ÿ^5¢_Sצ;<ÔÕb%zÎŒÑ7T9-l.¢Ûló† DI 0Æ×‚¡¦˜Ž>¢¬â©BÏ@û¯õu¹jó–mѽb^tÁÓÝ¢j DM X¾´Ù=“RæN–š³U)e¬Säbj‹o„5ˆèV_ZéQ¥B¡o%×~k±¥èfe d,ßâÌzŸ_¤¢fÂbi·sFsEµÎ ©Emѵx½º=‰k5Ço£3€ 9]mÔ»è]èJ#8  Å¹ù½µu²U C­nÑ­·â]ˆnC‘$@ E^½R@¡ÑÏšvçJW9¾ÑVÙ`ñ4 èV£—¹LUWòöÆníE·Ò#¢þQ‚Ò‡ºVXÕý™Ë9LÝïKýµ¹†(þµ=LJUc³ •„ ô&àV#níQ³ Z®¼âÖxªfq{Û<#³|êÖ›–Û+ºÕw¼»ÝÆcK΀@šJ]àWyÜw§kv]Ÿ—[!³ª°%ºÕáû†{UÅè µݪT¼F²Þ:¯¦›:¤¥¢[éyUåVuWgz>ŸUý ¦9© @µÜjÄww[µcº\yÅ-˜K÷e¡Þ»•åöŠnõï.D·ñØ’3 2¢ô¦·~ð¾où®*5§ª²±j£õ ¤P%$ÙszU³YÚá,dKÑ­ª^šZÐê;¬èÖ‡žD¢ý¹Ý”G uƒ @ š€¿†qæ`U6_-—¬±ñ^h±cÃXUðÕRˆnC‘$@ G¾ã| >àŸ(ô‚™q{éUÔ׺½ä±t«Ý|þš­ê$ÑMÅP“™+»ª¤O‡º¸­*K´*óÆ>ôÜ1dc«¬jvtsŠÔ€ €/º9[ûª`îíWžÊJ $·ÔÏõ{²2 âJÙo,V賕ؾØ5]CåÑòÏ↭T$»Qç0t—ù’+õ:bá¹tÕÜiQ§¥K;û“£¤ì‰ú¿‡¥õ²'úmTZ°ÆáR·Ø²àËž[J£CÓ[ó[§åØ5ÆÅ£S¥ìªª~7z*•µ‹u¡ ˆn€êHdqnõƒH—β)¢TõO÷趆˜@tshS£zýÎg:¯è¦€ZÐw W¬]ðnvÑŠD\g(ö¤(¼&òÖX52n!@È–€/º B½±[›•§TŒªÅ’~_%¹Å°-¥üøn¹¥¢vk&wº¢h«e†U+@©ªF–siEìC P¸YŸ¢ zXq¥­G»†V³Užpj@µ\Ÿ»–-®Ÿ}—5þf¶KYãº4½Ûׯ‘ÞjnôKXÔݺÑ+®Ï]!]O@tk9I@ Ž€oÄä6²Ü:ÃÄ‘úË÷ÝÖféS,Í /õz¥Ì=‡ª©Týb%ÑÍSªîºÜÆ ~¨9äëP(Ñð×mÍ£UvzÅ•Dç¥*C€ T ¢›峸c׸òô7˜mÛÏ._Å(PÜbX¦FþÚ)¸½óbÆ•A?¬j4ç _©*e'¸1¨K°–d}®LÅÍZ!XNû4Ü‚ÖÿåJ&o-E·bËú½Â:›ë?ÅnSêKÚ—K›F(mn¿£VÝhÅ P¨²èù'QŠs Ñ-Õi–zA“ðíöÝΉ[g¬º’h\ú”Öm—zKÑ­&ØBî-_êUV]œ]þACHuïW½Ý‹fÿÁ‚ÕUÍ—S‹Ûzº«ÔjÝåÖŸžú›¿Yµƒuh#n @`AܪÃmëúÂGP‘–+1­y”‰¯Vø‚‹þZÜp-.™ÜAK;jàÖQíC‡ù…÷ÃD(«öK,ÇG?òª¸8ôËì/Míà§UÇ_µ>·%«©oæÅW9ý5­~ï[?û•m߇[ö +˜þïh¨ø–[²ªu¬`NW„l·ëÆ iôO—sqõ[uŒÚ' 2¨^âÖ™^q”^[¨».è־ב€@%÷Zò_´Ý´3=ßúkœ¥ê¥^ÓÌòV·.Òò¥>¸èÖX*ÑÍ-|çJ\ïj­ñq«Òó÷<Û÷“UŸBz@€G ¸,ô——8U³ ôˆR5šŽ[ü˜.S´Nj òÐH¾h…çt½ª{}?!¥qá]©ó½FïxÒ›1hõ¹iy5›¬5îMÁyV&-}¢é®–ëskÙ`!êŽYáƒçúE*®ð%WUÙ-º&ÐCµÎµZ1C×KÍ ºÑ«ÚÔ/ö:D·ÆQL@Íüw°Û<ñ—)+™sëyn§Ji*–Ië'{«UùGpï¿Ò÷Û§ª©­¿Fi†Ò:EË—úà¢[ã2¨Tts¥mß4Fb zUhÝ$„ @ ¥+ßîÌ,jVbnyY£øøËà@+ñŸXºAèk(é»B:»9-kµ.Ôô§JrÞâ‚5s½:S¯HÖ¬ká¾ÉXM(—CUgXt:\…½åú¼¨¸Y†r•Òç`®zbÃ1 zT=„ª­t÷ÙUTñ™Rzˆn,7B(! ©¶^5«²Øwó{£ÐRâ5Gü€¯¿¬)æ¸*(&h#º¹×’^ŸÝN”V¶åK}zÑ­ô¥î¿b«sU£Èe8½*³v†1 @9¨Ú–sKiZ³k¹tqÉ:·:­9øÙ(µiÇÀó†©oʹ¸âª7zrÏ*-•«f{{±6û£mD·š¥£ÛÖ­Q¯:œ¿i¹>¯jÙÆNÉZUt«?‰Rj[à‹€T×™ž¯ÌÖŸ8ÁÒ­Í&  ;Mß¶cVº}TåÜAÔü€õ/Ë@Ôó÷ ‹‚ŠaÔþï‡p ô©ÀÆ»³¥›jä«5kW•Z¾ÔÝjvØ|ïg߀Q$õâ·Ë—¨‘h»ÑSÅKëî[æ¯jJ™û¦þ€ ¤ Ti=þÒÔ-äÚˆnõ²BÕšÊ)/v^ÁrK£'–^5ífÒ›“ÆJ€´”ŸŠ;¯Ýް "ºU I†ÂA®Ùão)5úlçZŸ7ŽËFÑ­ô{­ê®>ô\žj šŽèÖØ¦$€ pÚ@ÚDAtñÂK7j|‡÷æóË- ô³ÞŽöR/ÎÔ¾–gÕJÂܦV™UŸå? oû~ÅFmiéæ =v”U¥r5RñÜZ§~qÃKÝW6Ul+°Ô+¡v4l¹VÜ Ösî8ƒûA¨‹¢d7z®ÕÌù«]jY÷¦oR€Á @€@j´žâú¡J^i©OùºO°î,ºžÚü…V£·9íîò#<¸"Ù’¸êr÷ºE`{~›@tó¥ŸÆÕëw1¬Ïƒ2¨½´Ðu›Üú¡ñ;¨ØC\ôÞbõûÐóƒ[w*5Ñ@tËaÊ¥Ž€@_8E–áÃ׊êŒý¦Ô4̽Jï*ngS¿—²rÖ[}D7¡Ôš£¾`öÜö¶W3î¤ïúª™sˆn¾å [¸UŽËA¿)Bè@¯fÝi/ø}»>÷C€ °@5Z¨@ŠPt«Y<7ŠnÖ\~`S_ ôE·ªe¹ÿ{·–‹_tkS¥ˆn’¢¾FÁúÜßM÷?¬ü`©Å¯§Æ§øe(ÒS÷úªÒè7þ'¢ÛgPŠ ÌA@º†Ùµê›™5zv0»¤¢rgórÍíÎêÊ—rjžhS¿ÿ ýìV'ö§*Ñ­êO¥¼­`E¶ÉSsò´˜›i…UOwªZcéµj÷V鞦‘U%°Ûƒª=ËÄV]þKÝ?\PÚp~ ôª"­J¯*}“à9F Ï„ @ õVAÌÐE7;yPzµßÖõ·-Ý]Nt¢òó«ÞoýgÅ/ºùG"ªªÖ~§vÆMq?2†}Yø=Á­Û‹§j‚/ àã«ôL’)}èéÃÇ?Šd›â®xˆnQ̉X½«üרª%÷ïm¿hPJwc›'ú…l“¾sš€Fûyç'Žtc{ÂnW³ÑÚ2תôzö½‘Б- @±¨Ý|› ó|b»Á¾¬ÿûú5^UÓÎÇKáéʯª9ÄYÀ•nB×<7ZÑÍI¨«Æm«‡<—èæwÎÒŶëÛèæ»NLäL¹+­ï°ô|k ×ÁÝÎd@¹°=4ý¿~õé’åÂ…zB€  FWb~èƒyÅ™Õb¨z\„¢[7íÌ¶ÆÆªªåÂe[*¶YOú¶{vÀ¹D7'àV)ÝÜI×Txg'™µfÑ>8=ß D·»%YA€@úÚˆn.4ت›¨é㣆€ ŒO QëñÝe8™£¸nqù´‰Œ©]É@››Wtó×c¾ìÒRI,¶’»±½M™#P%!Õ/Ûˆn-X¬ÚéæÝ»n©èæJÛÒ埣1½  ˆn«ö=ÒC€@ÖÜ{T‹'E#-²ÐËÛ­ÉV}ñgM–ÊC€ 0FåBÏqz[·E7?MÑ…–Ö7š Š?ªè¦ç–"sepg^K»öÈ}u²ÔxJ+CeîÿÉ?ÍZ\7:Å­x¶×JÕFtsÉ”‰Jؾ:õ)gÝJëâÛ‘ùÒ/íJ®¥Ç ç:žyFtªO’ dAÀùeÁœùº~¤Rw­Y0¢’€ ÌJ èæË ¥>Ý|ÝÇT¡¢œá+ÐiJÑÍ©Òðb’½ü%YP0ßkXUL*yûÕŸ‚}ó@åxg¶\¾ÿ8Ñðo ìãüøª=E7?$kÕŽ¯j‚qŠn¾²È”~°²€³êâ·ø¡ºô{]ª{Õ9ÓnôԚʳ8"œ,è|Ñ ºÍ:òp@X ·¨ª d®·ì€; $D‘!@˜“@KÑ­îão7šÈeÛRœ‰œ~_zârTK·@d1mŮƂÕÄÇôÃP,_ ÑSô,e Ä8_—Ô-ú§ÿ+pOÑ­(9©TnWØ/^•¹b±³ÎeéæË”Â¥Z¨$ê¨Î>±Ê³ž°ûí^ºJ· ‹• úRzî7"”³ß²î[ÑmΩgC€Àr ØëßvvÙ²©Þ]ërëKÉ!@X –¢[Q¬)­`ývc•¡¬FÝ¤ÅøZIQd©)˜•­^£Ñ_‹¶{ºÑìŠQ2íDapU•Ó”ÊAD7åã«{U’S}0¿Øs‰n*CM39Ìjˆ¾w<_p,갥ͺ*=_~-Òö]ø!º-eÚ¤œ€ @€ fæòBWÿV’,q©`ä&•Áßk´G=¨FÇÑN¤Û’¬*´maêj¯ùY©‚f^ä_Ê­¾`–ƒžh Š·×ï¡ÚøDÓøÜåŸL´2”FZ08UAŠHKiè¡Ê¡¾q‹YÙݪ§7¶¬„-»½êð‡ Ó,A©¤ï-%¦:Ú¾E¡¡ÔšÏÜí™:¦{K{ãªôJÓQ#º5OX¤€ @€ @ˆ€Ôj´EwpUZÞ”U@t›’6Ï‚ @€ @Œ€®WÓÝÃMF€ @€ @9pîùjÎS;/lUÇKG…¥ÛH`É€ @€ @`\~lÓRÝÍ{PHa¼ò!ºÇ–œ!@€ @€F$   ~,ZýlÁìòÿT·aÄ’8è6*^2‡ @€ @‘€t7gïfQJƒKêÛÄ6nV[D·[¬!@€ @€& éíöÛo×aRgæ¶yófýS¿Ÿàé¥@t›‹<Ï… @€ @H–¢[²MKÅ @€ @€æ"€è6yž @€ @€ ,D·d›–ŠA€ @€ ÌEÑm.ò<€ @€ @ YˆnÉ6-ƒ @€ @˜‹¢Û\äy. @€ @€@²Ý’mZ*@€ @€ 0D·¹Èó\@€ @€ d º%Û´T € @€ @`.ˆns‘ç¹€ @€ @É@tK¶i© @€ @€À\Ýæ"Ïs!@€ @€’%€è–lÓR1@€ @€ ¹ ºÍEžçB€ @€ $KÑ-Ù¦¥b€ @€ @s@t›‹<Ï… @€ @H–¢[²MKÅ @€ @€æ"€è6yž @€ @€ ,D·d›–ŠA€ @€ ÌEÑm.ò<€ @€ @ YˆnÉ6-ƒ @€ @˜‹¢Û\äy. @€ @€@²Ý’mZ*@€ @€ 0D·¹Èó\@€ @€ d º%Û´T € @€ @`.ˆns‘ç¹€ @€ @É@tK¶i© @€ @€À\Ýæ"Ïs!@€ @€’%€è–lÓR1@€ @€ ¹ ºÍEžçB€ @€ $KÑ-Ù¦¥b€ @€ @s@t›‹<Ï… @€ @H–¢[²MKÅ @€ @€æ"€è6yž @€ @€ ,D·d›–ŠA€ @€ ÌEÑm.ò<€ @€ @ YˆnÉ6-ƒ @€ @˜‹¢Û\äy. @€ @€@²Ý’mZ*@€ @€ 0D·¹Èó\@€ @€ d º%Û´T € @€ @`.ˆns‘ç¹€ @€ @É@tK¶i© @€ @€À\Ýæ"Ïs!@€ @€’%€è–lÓR1@€ @€ ¹ ºÍEžçB€ @€ $KÑ-Ù¦¥b€ @€ @s@t›‹<Ï… @€ @H–¢[²MKÅ @€ @€æ"€è6yž @€ @€ ,D·d›–ŠA€ @€ ÌEÑm.ò<€Àè¶mÛvÓM7ùÙºu«~³¶¶VólýUitoiËsÿþýõ¥W%³ëöÛo?tèP^¿t ÜÙªœ]Vª]i©ü4UÕ ¼{÷n?«"Iû«Ýµ¾¾>z[ò@€ @`iÝ–Öb”€@k\pÁgœáô#)Dú§]Uº›~o Þõ®w•>G¿×_•sU)ô” 6XvÙÏú¥»EEr%ñ$ÂÆŠnÞ¼Ùåï~¤· + ð+ÿRJ—•~П®¼òÊ HºKÉŠ’bcÉI@€ $OÑ-ù&¦‚€@¾Ñͤ.SŠú‘a’4¦¦%Áɦ̩i¥J“aùK>s $o™òåä?+‰ž¢ük¥¦R,' ê•ß‹iT*ûePAc%qÍÊ£¬"Î⯨¯U)q+Õ‚Ä€ @€@ªÝRmYê@àD©è¦_Vij¤¤4I“ªJ`¿7±I:Z±“®ŠòE:'ºun$³È+5¸s&lVÎÒ4¦»ù†u+,¸½(±aæÖ¹ù¸€ @9@tË¡•©# )*ÑÍô#™­\ÌMêX©èf’œimvn4¸ÝìàªlèüÄýE7;ÁZåÄÍžeiJÒZ]ü*E·b5}• 3·LÕ† @€@kˆn­Q‘€ÀÒT‰n&'MÀœçµRÑMr›4,³#3K±@ϲǵ †Ð_t+Uý‚ö©OcuöwEÑÍ„9Ÿ’/´aæ¶´Ñ@y!@€ 05D·©‰ó<@“¨ÝŠª™)Jf;V*ºù–î ŒÚÚaVwç]Î`Z/µˆË"B”žu‰ÓpŠ¢›ÊV‹EÑÍ’Õ+»Ñb/è2%KWÑRlpÑÍ2,uç΄Zšà¨ÕJnV~võÝÜ]Mà´3ýpöƒ¯¬Ú¦éÏyè{„,í¡N›C˜c.‚ @€@<Ýâi JÄKÀ j7?yJÕÒQA>†UUœ^ãä³;÷…­t±Qt36³bóé¢[Õ9Íb„PgÀ·wS²a}ºù2™rvj ~šæG55c7ß;›$9SÜ‚à§=E·Æ¾ë;Ýs½èŠÇ^ksX¸Q† ¨OZ¶&ÉÝýÌëêB:³ÜXH@€ @@t&YAË&°ç¥“žÔ¤PøöJCù<ëS‡c/)/NM \£è¦çš,œ õE7ÓÑJÚí¾38ýFé-O™Ôt=åélÐJ£—*}ÕSJù(7« {–ýàg¢Y?Lj©‰ÜØ¢[û&¶~躢 gΟÌÜVÕà‚ô²»”·q÷k–³y—[IÌm_RB€ @ gˆn9·>u‡@Ž,FÌÇüãŸ=U wÆS†K&d8ó´}ës:âÚ¶m›(¹ls-­ê—~Ã[š +èÜ¥û¥¬á‚LŠ·û°¿Jz“‹7)Y²DÓíÊ$x„ lêÿPLÖØGu‹=Hök*vi¼QW%+-ŒžRdUõèz *N’:ÑÖzt´žg™_9ŒæÔêP-E>€ @Ù@t˶é©8’%àÄ;Äg'øúxU³“z&Cè¿{<¬§ÿ{;YˆTlù|ËMõÛþ§¡M\¶ f·|HÔ€ @#@t.YCãàeÊ— aæaM¢@7›µRX󩇎œ!à„iE`èiòiÆqÒÁâ90pè`€ @0ˆnô@ vú†×—¼™­éóþü‡_í¦¬™Žse…µZœ //l¾ÿµâÏ¥Kã¬ËBKeaCdËæ+Ú«ú’³«vàÚ"9(”ÄBPl@€ t#€èÖwA£З¹o:Ó›U¿ó%ÆùGAcµQÊJ¦£(u÷æ~ø¤­d\BÀô8s‰h楫F‘hîªS•N@€ 6D·´Û—ÚA Rv8tËÁŽŸîþw»Ñp¢-Ò–¦Xypg½¯{âXŠÛ׬Pea'oty`£–€ @‰@tK¼©f'`ÞÜu8´Ã׸ÿ)Î µÙ›’@`%¾¶nñLä<±ýÙp?1Wq6öWz4‰!@€ D·Z2@ æšÝ?ºê¶¾É%Ìé›Cg)tê Nˆ×`—¬¦ßR‰3?qš%,bNâèb€ @‘@t‹¼("%`®d¿võ7O7IZËÏf‹u(oPúÞ6Ÿk2‡‰´’ ˜Š€©övä\J\ËHÄ6Ÿh2±^óÒTåå9€ @h&€èÖ̈€Àμi&lrºÔ>x¨™¥lzüä÷°ü4q@ŒŽ¬D@6qDÕN§¶ Ú 9ÊÜÃiÖÂ=ÜJÀI @€ 0,D·ay’OÀìM,:¡¾r[Ú›8ïKvì‹°‹ïTQ0?qšgÌGdËÇšÇÌ=œd8f§(–BA€ 4 º¥Ù®Ô - t;%ªo]žg°%d’A£p¦¸:·ÞÒ×¥Ú&v¸ @€ 0D·1¨’'"%Ðᔨ‚!ØQû:ÅÿZ¤MK± €ÛNÐÜÕÆé¤,æ0…£A€  NÑmp¤dXô9%*wæ¸`‹¥!) Л€œ×æ ÜÚXÙ)œ{éýp2€ @È”¢[¦ OµÓ# GEæq\¬Z:bã”hzÝ€A- (ÆÂÝÏœŒ£™P&½õñ—5©ZÌeM³ÄHmI˜d€ @ˆnô,’€oµ¡/ÆúÏEý•S¢‹lf LEàÅ×O†h¸ùÉcrXÙh §8ªvîS¸©Ú‡ç@€ E@t[d³Qè ¬d”qÖ'?ÝS¢vª  B@³®¦P “ªIµ~oCœ¥Öéøª\gòt2 @H€¢[HÒ$`ÙäT¨!›ì26î>N”XiöjÌM@ad4ÁjšÕd+‰­^ƒÓœl.áÐàæn7ž@€æ$€è6'}ž GÀljó9ggEõí'‡D²Å# LO@‚šLá,@j£§dJÌŒ=}3ñD@€ 0#D·áóè¬ È·Å=¸hç‘sjðám—älHv’ç²Gå!DIÀŽ£J\«w gþàtjõÞC¯Ëz.ʪP(@€ a º Ñ\ ÐH@W¦²µqä\ts4©, DH@³·¹¨×à´é"gœÁEØ‚ € ô'€èÖŸ!9@ œ€•ÊvÉ®#:ZsøÈâØqÑ}ëo€# ×”5Ù,Ÿ»£Îœ:ÙÊé] kèÄP@€ !D· *H@ŸU:*³…úÏ*™6H‰“Ê&Û7ŽØd @ >Ú’qîjâ¢j·Fo ½S0yޝ ) @hEÑ­&A Š€œøè‘ŒêƒÙé³J¾ÛPÙèH€ ³œÁé jý{Ä<ÁI­Ã³']€ ,…¢ÛRZŠrÆB@†iò~m®Ùä»êШï*›SB±4å€ =³˜®÷K cjmöHªÃ#AôíI!@Èš¢[ÖÍOå[ÐÑùâÑ¡Ñú0£ý€¯ –TI¬ìÿá•U•©lήÆe,©¥Ðé%%ËëþO$@€  º “¬Ò! Û4ù±–‚VuÎl t¼”OtÚžš@`»wï~ׯC‡=YfAÀ<Áé„©6xjŒ¬åÊ7pYt* @€À º-¡•(ã$dÎÖx¢Çw͆WIš…‡@`ñLq;ãŒ3®¼òÊÅW† DC ñe^ä AçU£)5 @y@tË«½©­O@ª™¼³Õ[ Èš@ž­åßšC£t@ ·иeU:…*›ëzp«R%= @èOÑ­?CrXl´Æ?ÎÙ¾"ÿ8²zÃ:`IMKY!*ÅM‡L9g_s%R"¹GÐ.‘\Ô8!µ#¨8FH¤É© @@t‹¸q(Ú@¤é|¾1t8´ÊælÁ&@à*ÅÍùwÓÀ‚À¨L€“±vÕ>“a•QPGm2‡ @ [ˆnÙ6}â7¡­ÆÛ´Ô7;k#¿ÔxgK¼7P=LN ^q“7yy»à‚ &/Ì—Àáco+@Pœ,ãôW‰tJ™/&j@€%€è6(N2›ÀÑ·N4†u³s£·=}Lþ§ç+)O†'Ш¸ÝtÓMÝ6lØ8ª+YÀ™¸*pYÆ)~·Þªz·rA€ t&€èÖ7ÎOÀ mç?üjÕ¹Q·u¯oŒùKL Ô 4*n[·nݼy³ŒÝôCê0¨ßȳ›ö¢äAÑNKߤ8€[@+RD@€b%€èkËP® m„6mÑË…ÎÑpF†~LI â¦òÈÌM×”ãYhCÀ<3TícÉZœó§m0’€ 8ˆnt†eÐÐzmmËhHJ ¤ èĨLØ®¼òJ¿–N‰3Ó6ý_itÂ4iTnÙäêôÞC¯kûª*ª¢ÙùÓeדÒC€ ‘ º ˜ì{Й—›Ÿ¬;ób‹~} ¡fn…†$pûí·×(nú“â'`æ6$qò™€9€“GÔÒó§ú¥Å?ŇÃÈí@ö€ ,’¢Û"›-áBï[?µ¸¯ñîlGGÚîT ilÜT©µµµ¢)\•¥9ÕùuO«:*“sý•PE9ôê@€@Kˆn-A‘lD’Ï$¢ÉSLÕ1 m#6YCƒ(*nÊÞΟîß¿¿ôQ:yª£©U´td^Ü‹[ŽÞŠá´m¦Ð¨[ç­Ý‹27C€ °|ˆnËoÃÅÖÀÜ´Um˜Û’]'Vdû¶Ø*Rp@ _¦¯ù!J:¤ƒ¥ú}E¿W•ú¦À kϽ‘j @€@ZÝÒjÏIj£°v¡µ.úg1ïÈ ^†wäIš‚‡@ &Ш¸Insàd(·àªRt4вA®ß.|ôÕâÒž¢¾5!äï€ ÄHÑ-ÆV‰°LrÅrï¡W, QaÉ)  Ô+nòø&¿oíÔýa-('`ê[iàÔ·Ái“! @c@t›ð²ó—6™­mÜýšLØŠ›Ïç?üªN…~tÙmLé!É È„Íâ*È-x¸Émú“s·uëVý“¦“·œ™€­@d>íÛÌ-Áã!@èAÑ­¼to­9塵¯VÀÚ…æiºíOÍ Ñ HY 7‰k:CêËmV‹À0zxb%Ш¾),C¬e§\€ äNÑ-÷à×ßÖµ¥Udé&{7"Ò]  NÀÉmRÜ$±ùáMÍÌ­h7xÈñ¨Y¥ÈÏì ûŽbz#RB@€@nÝrkñ’úÖï!_ñØkòæ&@œÀ¶mÛ윩&5K7 mîAfææËpƒ— !°85öør|!c|-lW) @€@’Ý’lÖV•RlY®á-¥,AÀþýûï6ËÞ×Ý0s9Y&EÀÔ7 mE¿o2ÏgË0©Æ¦2€ e@t[f»õ+µ´¶ÒØÄëÇ•»! @Àt·Ûo¿3·h’Et°ôæ'»c=Pßla³oý­<0PK@€¢#€è]“ŒW µçÞÐYѳãÊʦÇîy ?Äã±'g@+0ÝM—â-·)Œ©ŒãÜ¥C©>],IS' ÅŒ–4ÒÚõMz1 Ro|ê@ˆ‘¢[Œ­2l™´Á«¨”µ`ŠÖ6,grƒ 0õõuóõ¶¶¶æòôÀI•³ËüÁùnà†*ù@`Ѫ6-*Ô¢«Fá!@XD·5ÖjE­:j!K7µØùìÚVãIj@“Ö˜¹™7‹dê›¶)e1üÂdåäAˆœ€¹¯½hçŽFÞR€ *D·ÔZVëË-Kœ ŸyÿË8N­±© (*õÍÜ,Þ‚9z+­1ÞßíTk0 ¹PêôÍŽít0Ðd@€À; º¥Ó#tŒT&lE—m>úªd8”é´45’&°{÷nékÒÑ\-MƒÛ¼ysU½]Ô¤ÁP9 @@–þÅÅ’6&åô–Cð% @€ÝëRÓ´I[ŒØ¥ßÜöô1mí&V_ª@ m:=ê»i“ fŽÛêk­c§iÒæFí О@Õ±S ßÚ3$% @m`éÖ†R¤i´%«YmÏúžJØ­´µ( Ö|¯m WZ4s“í› âüüäôÍ7Žký(B kr€{ÝÇ‚h§,¥²îT€ 0(D·AqN’Y•iÛùŸŒÑÝúÐã^ŒJ ž~ãîלŮf¶ ƒìyG-™C€ 01D·qÞˆ´™)ÛØbí‹€Ü!¬B@†Î¹©TàËpÏw»®Ãhz_¬ÂéiÑÝ:£ãFL@@¾Þüñ®™íº'Ž™é«oæf?ËDn‚"ñ@€¦!€è6"g/øÇˆd¸Á©q“5 °|’¢Ü´©oÔ´çL¹èÃÛ}rËZ_æÛPºÛæÍ›;ß΀ÀØtÊÁ·kûŸ|åŸüñËEÑM±Æ. ùC€ 0D·QP§‡´Æj6~”Ò) %Ð<é7ÀÌÄ(xçÞôÃêpY&_B—¤Œ˜€F·¤vG¶(ºé7,æNv€ ù º Ï^K%,¸U”VW)y#ž9B8qBF^nÚ¼â±×²B¢w„ªìªŸ¼‰_VKe!P$ ð)ÿëÚz©Üf¿Ôf-KGz @ ˆnC¶cðá¤5“L†|yAH‘@Ί›kOÃF;7Ó˜ºlݺõÊ+¯ÔÑÔ 6èç;u‚@t䪲Fq³?é,jtå¦@€ ¬NÑmufwáöd¶À¡Áà’ .;äkã´ª\È“ûoÿÕ-ÕLÚÙJ}dÛ¶mºëŒ^ïúá¥ô›ýû÷¯”‰!•(NBãñR3vsANWÊŸÄ€ DEÑm˜æÐIç”G ò>L¾ä@ i²çÊöTiiÃÊbzãîÓGMµÓæ”™ŒÔ$™µ×Ý,½.¸­­­©$‡ºé¦›L}ÓÏIw:*ÙHêíÝï~¶‚ò`@€"€è6HÅ×sNÜðÅ3P²€ò  ÉÓY|äæÇ­¾…oØwÔ}+¦Ä°º›SÜn¿ýö »wï–è&%.H-!0~ð]76/UMÚÓ®ˆ< €  ºõ…ê+n:ÄY€¾@¹ȃ€>AµKa_žÒ•ò¨ô µ”×'?–ëPº›ìÚÌÆ­Êƒ›ìÝôW™®ÐT$…@yøuÓ]¹Í¥Q8㦼ù; @Q@t«lž={ölß¾}Ë;¯Mï¼þÏk¯ÿçŸÿ®­ÎÙò×›oøÅ ý®]»öîÝu p€&' éÂG_µÉSgóñ€YÚþ¦ÎPönæÇmóæÍUm.¹M ŠFp“÷tÈ›–Ê‚UÆnšúü÷œæt@P@ø!I ;v쨗åáÚk¯ Ò?òÈ#H ‹èPˆn'›éðáÃê÷wÝu—>3Ô¹/½ôÒ [\?öïÞýÏ?ýu[-uû£úgÍMÊS9+ =ëàÁƒ‹è€À®þæ©ã“úøäüT áau7Ôt€´¾M9^:FŸ'Odþ&ÀRâ4J‰Sä„Rîü‡_ ,—@7©¡…q: RCäÝ#SÑí…^´|ë­·^sÍ5+uh?ñ¿¼þs¶<:ó÷ž¼àß¿§C>—_~ù-·Ü¢’¨<‘wŠ@ 'ãÇkËA×oîÜï¾-õóSO=Õ3ç´ot·6•­Š«`GGkÌÜÚdN@`<N‰û¿{åß>øýÿç—ž×lyë×öÛäÉ®íxäÉ€ÀP‘:h Á-&5èèRÃP-Û9ŸŒD·õõuY`ÊÖLý¯'Vÿó¯|I+¡ÿþ ßû‘Kßß?C•J" J¨rvnNn„ 0Í]îT¾ àeÛL¶ï~÷»ÍNþÿýkŸ7ÑM?èŸW]uU0…Z2-d¬Cú¨r¾î&£˜6Mlº›T6?±‰nÁ/«r“÷7¥ÔeáM¹  èHæ¶mÛ4ËÙŒ·qãF&¼øâ‹ÝÁ"93q?WÍ«ZCr–bÀ"+@+\jè//ø9˜Ô [¤†•šu¨Ä‰‹n2¬ÐÛwÞYü¨ëßô=ιîÓçÿø{ûgä ÒªÌ*ùPÍL>€†% /FÍQúÆ“4¦¯A jö‰è”²‹ 9t»ùÉc PU$3è0¯šÒïl×rAùë7úLÕ_‡­Nü¹ù‘^u­M*H¦à¤ÝOJ°ÓT‹·`—<ÁskSÒ@" ³EÚUÕôuã7jÓ„fGœR¦9Mi:°rÄN¿3UNÓ¦yÿÑDŠÇŸ`¹€@#'5ô9<7¸’И¡^²CÒ[Iåo¬# !¬è¦å‹¾ýôØØíbN ò«~^ҹɖ€mâé+Quúbt_tš£&xm˦¤oHÀ¾ZUùâÌç{RîŸÜ±Ü-;®“$ŸIP“úVÕ7®¼òJÚ¤ÍÉÆM)µ2³ð UO‡ífä4Øñ"­âd¦ëúë¯×ô¥ßL³¨“°ÛÑ× öET€{î¹Ãá4zµ€æ% Å§–£iH úLЗRÝôU&±ÀD¿¬¦•Š3é· IwÙÊÉ>ýË32ÔPTT/Â/L0$x àðí…5¡é³Mö‘ÌEfȬYÚ –Ã÷䎟ò%zÿËÒà:ôU‰hÝt•5Å­ô¯¦»qÔ´snɇ€¼H;²k“¡Y7¶a¡i&7+2p°‚Å3“[Srƒ 0ÍçúêŸFjÐë£Tj0.vµ ÿØ(†(½ "YÞ×|3月è¦UŽV= ;5~Ôwõ §/·ÎvþŶ4Ë;'UtrÔ8ŠU<¼!Î8fx4r `“ªÞë²0ƒ²˜í#܇®}OÊ´$á]»ëž8v*jv×À¯¦»™-›ïßMLq+µƒdýIÒ[ýŸ:B`%Z•imæoÄüéâ<|ËfYK_í(çc/¼R³’€€VjТz$©A+öžÎëu»ŠÃ^Qb}oñ¢›º¬öëV•®,½s(8ýjCŸ¯n˱[á5¨¦9¡X§:€@ mȆW“ªlÇô%¶DéJß“ÚäÐ ™ð®ÝÆÝ¯™îvᣯvëÏZ>JbóE4™°Õ(nö³ƒ«9šÚ­0Ü…Ð8òg›é“ý¹éËÊ6­¥¾io˜­þHÉH‰@¶RƒL…$V¤Ô”óÖeÁ¢›Æ€¹õYéÒªBF_þò—Ÿþù·ã¸T’¯|å+æõc¥º˜£\ÆÃ¼Cˆ§C æÓŽiFŠcvìU M­_üâµ¹¢+1aE¢8wǺén-ƒ*4öRY½56µà§:€Ð˜ 6-½4Uš]í_þå_öšªâ¸ùСCvfJœd8Âۥݩ ÐH 1©A[éݤmÆ7²"A#EŠnZë¬t’ÔÂHhÓ’"޵Me)TÂûî»ÏÌLÚ p’Þ´×ÚØØ$€ ]ƒùÁÔ†&ÉW^y%òI²Cñ¾ûÝïJ'²Èš*'ˆù0A7Ûùƒ7ϼÿeÓÝÖžëâÜ-(¤9z«/¹ sXºMо<"N:4ªïM&r"©Í‰cÇŽu˜‘"¿å[ßú–y×Z”o­8û!¥‚F% s+Yö,KjÐjß6ÚK úL@jèÙå&ºIn“ÀÔ¾‹,Údãá‡VùåP©e}=·C +:än¶¿ÿû¿ÿ†Ä Ÿ©2H±*Ëð-éí¶§O9w;ûÁW{»gïmô×¶ÿþ6Â\Ïbp;â$ “ m2›ÕÎh]·Þ_›…PB—š G<Ó>ع7fæÌDW=öØ\k¿Hž«%¨íUh[wé{1w9ÊLO@[Ñ-ýVéû:áÓ!Îr©A¯ƒ%[›¾w¹'F-ºé½®íµ6 ¯¡’Ï7ä“O>)+•6Xt.`¹“3Ž  ô8c4|~õ!*Sb“Þô=¹ÐÙòŽÇMt;om½g¿5mëÖ­~>úضßËN'LÝŸÜ/ÑÝzbçö ˜ÉƒÖZrp6Ôl“@>)™ GØë( 01I Zþµù¦Îj÷¥½Ô ü….ž'îiz\¼¢›Î“¶ &ÕðWlfðß8Mˆ¡¶%§ïX<ˆ„€<ÛÙ(Œ5ª>zeZ/;b³•^¢¯7Ém¦»ÉË[Ÿ^çô5Ùµ­ýðÒaRim&«7³q“H‡îÖ;÷FEÀNWHnÓWG2ÙUp{wÝuWTmGa ´' @1m‚ dû:ÐÙÁ6Rƒ\Âñ.hÓëbÝZyf;ŠÒ[£D­ µŽlÓ!H$C@ú‘T$ ä¶6_ž’Þtj@gg0¯ƒ¥&ºõÀËý#*XˆRwIt ü¸O•j£Xéñï–ÌÔ‘gEdò ¨:9ÜÖf”ôfï–—yŽj åÐntfH z´´òÁ±UãpˆKtÓŠG¯ðFë-É®™ÄÚk³îQ3øo”Þ´šÄGã Ò åÈ"“JKj9“Ì–ZŠ-Î`~ãî×LwÛôøÑþXFmRÐtÉŠM@ü «ü¸5Æaè_*r€Àx,Z—bp1 ®D@¥dJ-ËY^Ž×9ÉŠ€íF7~2kNKÕGüJ3¼K¬¥ d„6Ü8mZÕW#Ý´WÖhä)ɹ­j´˜ôV/YŠðâŒ8†šgəРÏd#Í Ý^®Ü%Ïwú_Á¼ Üμÿe‰núc·ª‘âü¸ ºe2½¤WM™<˜l$Ó-¦¾nùN¦„Ëôº5‚’! ©¡1 ¡ÏH 5Rƒ¤·z©AŽ­ä5™>3`EbÝômSß„$øÿn³’Ó߯,ÒøìCdDB@;xšKõñÃlÙf¶¬O# AM• 2˜—Û€ÆnÅ.íGNÓ7?/Õ¹Tû¥Ž£îÞ½;’AA1 PEÀNWhŒ-¡ÿ„)ÉRÂ¥ÖŸrC—ƒ ¹8¯7Ô’aJ>QûÌùm¤- —è"yÔN;¿è¦EOý±jE—ã„ÔJÃCNÁëÃPhatøðáQû™CSЧŽÜëè’Ùr¥Ù²>±Î(…>&ã_=ŒjìæŸ*u‘iAâš8s§Z‡ÇêmÊϳºP@gÉm:€?àtAVú³×P·Fá.@ƒÔ £rõÆ=,žW}µ‘dH>xk.7ÙE·Æ#¥ùÈG¾÷½ï½Åµ:çž{î~áj¦ì?—;n)9Û¶m“’~àÀÕ§ îh& ÃSú’ŒõàŒÝn~²WÓ wý¸Iw³¨¦végýÆî’ôæ[½1T!!må~øÃÖ2©yð“bu’2õ>³O„=Ÿ"A 7’tþ£æsXïÏ«Oó'ïh#5(Dln]®ª¾sŠnõGJÍȳ['à.GÀ<ÕÌ5:›¿Ã¨" ¼o¼ñŸøÄÑ£G™úÆ# 5™t·È9c·³|åè[à 97‘¦&Ý­˜Ž(Ø‚þï[0Ã7gõ6L!È$ÛÕÏ}îsãÍä,?þø#AÔËȈ‚@ý‘RI ÚReÆîIà±Ç«÷”‡Ô`ƒaÑ­ñH)=€»>Å?ó™ÏÔèn‹°àˆbò¦ˆŒ€vð4~¿ò•¯ 8cUÍ¥7ß|säGM±Û–ƒÇ‡ê­AÓúl9[:vòœ€IéÛ@_Ìrxùå—uZ…£¦ƒwc2„ 4)ÕrNsÔ3aÐòXÎH õÝrÑMއj¢”êÌ#ncŒO™¼ÕxyÓŸˆjÚ8ƒ“QО¬â9€?Æ„Y“gäGM÷­¿eá.ÚydúîjgKƒ0 Óƒ'B H@ê4 ¾²&ž09jÊ`„&&Ð(5`à6Æ‹@Îõ OæRÃÔ¢›ì2j¤ù€àrŒa`yêèµ>Ñ«th¬ ÄïÄonÌXøSŸúGJÇ›0krŽü¨éù¿jº›N›vë`ï*ž-•¯7E5•ùñL;SåÆž6JËK©?³L<”£¦=;0·Cí Hq«—ðà6Þ[É œk¤†œ]¼M*ºIଠ֫#ãurväʤÆþ3rEíç\RB Urç¯#¥²]eZ›‘€5•£Š»ÙŽ›è6l8…65ugKeò&Î[ÐòþÖ&Ò@`Xv_ºÏŒÓ¶/1¹r¶qÉ €€O ^j`¯zš—QýQÓl¥†éD7!®Òz$Hó9Í0°§È¡Iý'«"^`ˆ–€vð°žr¶¬Ö}÷ݧ(±Å¢qáÎݱ>eO¶³¥¦»¹6oÞ¼ÿþ)‹Á³ àèLþ)dÎÔæºâ®Ð?!ŒA@VTUÆ=H ¿êš*€ø ò<'Ýä{¨Jq#jûÄÃÀWoÿ‰ãÛÈÇ-ÅË“³Ì–õU‹ë¯¿^~£ê“—ì:bÆn{^zs²‚)©imú!i:Yxíõ~ô£å ~TÓæ¿øÅÈcÑ0‚ %¨1îAj˜å-P/5ÄyRdÔž?…è&§JqÓñœYú55QMµ*µç‘9 °¹\Ô$&ÎÞ²ÔÞ´iSTº›B—šèvÛÓÇVêf›â¦#¥+…:íü8n„@=mÛ¶i…‰âá„)æÚ¨ˆÍ@˜,—€,§"œí¥†¬^£‹nÒnª†NÜbÚu¬j VEË}ýPòÄ`²ÃlYS Ô±_ùk¤ã8r*†©LÞ&(’SÜ&x€@#}€}⟈|ÒȹxnT4v*@qe}Õ—¬œ¸å<ÓFR÷©AAáòÑÝÆÝj75@$]bh×±j¶Êj0Äù.¡T›EŒ‚㟨KGät/’{ÎC¯ÈÒí¬^»<(nc&ÿ•èЊFÅ?cd^Byü‘p<+õ1C‘¨‘ˆXÏ[FRC•»½|¤†E7­{J¥Aúxú%í:V ΙFò^¡yÐñ|Œ‚—2Kï{ß‹Gw»â±×¦që&ÑM§JóžÔ:*Ú0׊EáM–2cd^NkÂDw‹jQ,ˆ@Í©R¤†ØÞ/5RƒŽÖ-¨×u.êX¢[Õ0²C Ò؆•G!MÛ¥T'%ÚTçÆèC@Š&qN˜U¥’Ó½Ht·éݺõéêÜ þJ˜­eM˜¶QîÖ¿ó“r# S UÆ=?üð²fÂLJ«–*©!ŸQD7ù¯--{ò7¹b%P3ò î›Û ŒúFE@ƒNŠ[¬³åª$ðÒK/ýäOþäÁƒçíN»u›·²<Z²?ðÀLL‹#ðÌ3ÏhÂ|á…èÀZ¨ŠU*©aç΋›ó)ðw¾ó7–ÊDÉK Ën;vì¨RܤéäÓ«ZS­~ªƒ´Ô–S!É ž´ž·…N#[i ær覦çîXïÙ¹‘`‹bѳ®¾b y‡§xÈ™À#<‚Ô°Ü9¿Fj¸çž{îØ‹n»ví*u ¦_¢¸-exh0TJQMx0P5DB@ë‰~ô£K™1(g)íæ)žéúúœ‚×ykëÝμôX ‘ Š‘'-ӢމhÑþú¯ÿ:wÚyŽSj AÔH šF= æSøÝM6ƒô“3RtSÔ¶*Å SÏe ¤ªs¦j_MvöcŠdhˆIq{íµ×–5iPÚ"M¤ÒÝfŒ†¾q÷©X :jšÌ¡"ð `œÌÜ«/énto@U$5TÙ… 5,ë]¡Ô0˜è&ÿ5UÃàOÿôO—Õ(­hòª’P÷îÝËûƒ€Öònƒâ–Ì$¬‰TQ™æÒÝ®{â˜0ÝþìctWò„À¼´Eñ‘|$™é‚ŠÈ+_î´ç5< %P#5àÐs‰¯9úÏJjFtÓÅå—_^z¾úÞ{ï]b? Ì"ðçþç¥m*§oóž™ZèÛ‚bC ž€ÖRÜ䆟ù'%3~FÞqฉnúÑÄìÙ³GŠ[)Í–ª‹Â%ïN;±‘Hu 0©aëÖ­‰MƒùTG;ÓùH ÈnÚ˜*EFè½¥}.–¶¬l7&˜ayò! ØmRÜäæ`é“å/øÂ¾pûí·Oߙמ{ÃD·Mþé<ã`‹"á™VúÒv§=Þ¸ g¤J©!Õ9?©aÑ­*j/¡÷ÒRNKu7–D©¾Ø¨×,» °iÌ™¥µŸ>Åǘ¸kÉ•›‰nW<öÚÄæq€L®¼òJÅ*IxÆÈ¹j²^Tôg<™Œ7‚ÈË" 8~¥Ÿ¢H i¼)d«˜ƒÔÐWt;|øp©+7Bï¥1 ¬ŸùÌgŠƒAǰY-ë¥Ei£% Ó4ا4gë¢SÃ’ ôÆœ²"ºMI›gMF@&xðI{”Ñ÷UW]…'“ÉÆ‚@´Òžíó‘z‰nÚlTh¶¢#Ÿ_¸%Jl„èà[iC³$Šö-EÁ–B@ž‰´«ŸØŒAuŠä2VöŒSUp¢Û…¾º”á@9!PO€p¥™Ì®r+Œ'fdN©!“ _ÕÔ§PÚRC/ÑMNjJ  ôi‘Oɤ¦Úu,5idI”ùëê÷$ Wn2€ú‡ø‡Lf’Ì«9½s7;^ŠèÖsœr{$äÊM&Á2™Hqîɸ£˜‹@©Ô ñ©!½·€>…J¥mWÏÕý†}nwÑMîiJÏßê£"½~@D *˜)Î݆“ä–k¯½V±{˜aò!0±s7ÝÎ[[ÏjXQÙ$ ˜ÉÃþýûó™.2¯)ÎÝ’ÈT - TI øcIõÕP%5¤Òº£èÆùêT»{}½´ëXjÛøÔSOµœ@I8¬5¦òœL²­õÄÎÝLt;ç¡WwX:™<°­›Û̉s·¥[Ênª¤ü±¤ý(•$>ÈO·ŽÏ]E7YgÅ—÷½ï}/¾øâ\é8räÈe—]Vlzù»§OS,‚€âhé 1•î„AÍÊ üÍßüÍdÎÝLt;w–n‹˜(d%™<ÈJ”9%C_ýêWñdÂÔÜhÔ¿7/½ôÒgŸ}6Ãi0Ÿ*볨Լ¤†)}"1ܺˆn¥ÖžŠe©‰|úD¶5ýÎw¾£¶.΃2c|’gªôæ~­=ülg’Ì+®øèwÞyçØÝûÅ×߯§ÛØÉò}© “mÝl§Í_ûµ_Û¶mÛ=G@1¨:Xº{÷îl§Á|*^åG~éRÃÊ¢›¾%35ÙüçÓ2¯écä\}Ù>è0 ‹L¦ä@@RÃÆ‹_š¿ýÛ¿ó4˜UÝõÆ/õgµè·ÀÊ¢›6ç‹°ùÏj$¨²jñb7¸ñÆsxPGô$ ©E¶Ó,ÍmÚ ê+Ûpy…ïÙ—êo_{î ³t»â1D·QI“ùˆvíÚõ‘|$óé‚ê?ôÐC,2Gfd h”J Ú§dÌŠÀÇ?þñĤ†ÕD7k/-Ôo8$•Õ0Peu¢¾ôin£yéPd Hjá0~nsfi}µ¤Ø¾}ûxýÞC¯›èvþ£ã=…œ!0Nâ3U:ò‚Ê"s¼±FΈ@©Ô ñåÛßþ6“aV$5”ž­\î[`5Ñ­4~ÖžYWYŽ+*З_~ùÒÝÆðÊ¡ È"©%ÏIƒZ´¤Ðœ¹¾>V”ƒ-›èvÛÓÇST-a[¶la‘ÉÌiôÕ­-+™ wª…™*~]þÆoüÓ`†î½÷ÞÒà } ¬ ºíر£4b)‡¤2ª²Ú]¶¾Å.q×]wñ΀J ÈF ¡—òœ3Kk­Ý 9øi¼\÷Ä1Ýî~æõ‘A¶€L4a²ÈdÂtôí½t_Úãr†ÀÒ ”J 2wâ-í[ TjXè[ ­èV?á/þâ/²íT\AdJÝ>|xéó>å‡Àn½õVíÛ0u@À'0^D…Kv1Ñmßú[côgò„À¨tº‚E&³¥O€ˆ £Ž82‡ÀŒdõ_zœPþ™³% çd"*´Ý´Oü„l{|MÅKÝ*ÐØŒ³6†@œöîÝ«ø L#ŒQáÜëRÜÎzàå8G¥‚@ ™<üÂ/üÓDT`Þ€@’J¥¢èð sZ‰n:U?CRŒõ‹/¾¸8Ÿ1ÉW•‚@gW]uŽ`™3K ŒQáÅ×ß63·ó~µs§åFÌB@§+Þ÷¾÷±ÈdÂ,%@D…YF%…Àxª¤B5òxñÅKM '5´ÝJµç­[·Ò ¥n1vïÍDÎK$ðÈ#|ô£eÆ€@)‰ 7nÖ5ìμi¢Û¦Ç ]ºÄ9#ë2Ëc ž³™-«hûJ›XY*´ 50á×xàŠö=‹“šE·RíY;85dx8¥nñì–Ö ‘Úô"€™f=Á„ßqàTèRýЫïr3¦%€™³e#mbi+kÚŽÉÓ Q 54Îx$(•–eìÖ,º•jÏ ¸FóCÀøêW¿ZT Ç É7Ê”O¦fnÌ–7v»â±×ÌÒmÏKoŽÖµÉÃÀÌ­qº ÆnÃ& ÔÖØíì_!ŠBD³EiGÀÌܾÿýï3]@ žÀÏýÜÏaìÖnT‘ ñ@j`ªoI`éRCƒèVª=þóŸoI‡dùÀØ-Þ%›•€¾ ômÏT@M;Ð0”g·µçÞ037Ù»ÍÚýy8V#`fn7æC@[Yxv[mt‘ñ¸ë®»Š‡¥ò™ÉÛ×téRCè†öܾR–®@Ç÷&¢D)ÀÌé±=¡ŒÝ®{☉nw?óz £ˆ:äA3·ös)Ec·<&j™,ÍùÅÀ”œ¨cz¯"°h©¡NtÃÌN¿íKàÙ-Ù#ëD3·•æe»qÎC'Ï–žyÿË/¾þv§žËM˜fnÌ+áò|úÌ0¨x$"& 93·•&½Ì/ÚØ­RtÃÌ-ónÝ¡úòôWܯg7ícD<áS4ŒHàÚk¯ýÚ×¾Öa4qK¶úÛnì[ËÌÜ.|ôÕ;7YC`h—_~ùßþíßf;ö©x2|XV»¡ ùA`©0së0ãqËrÝ*E·mÛ¶¡=Ó³W%Pjì¶}ûö¥¾(7zЗ€Þ «"ÒgN ¿±Û ûŽšèvÛÓÇzô_n…À¤° Î|êëV}ŒÝ&¥< ÃرcRC·y/ç»JÝäp¸Ž9VN•¢Û¦M›‚‘À뜻x˺—»©/Õɸå–[¾ô¥/µ;$ƒ€#ðáxÏž=»¶-Õ޼Õ9n„ÀÄ´Tø«¿ú+æ¬J@án>Pÿ3ò‘U.ºÉH/¨ÉOþäOfÕœT¶õ– ÿ,Âì3ò±Jñ–E€ }æîýØÇ>&w'U}þhűÑ=/½iŠÛ¹;Ö—5^(mæ¡À¤×‡€–{÷îÍ|Q},ˆÀ5×\|*^vÙe}&îÍŠ€Éųɑ÷ÿÑMæyø5̪ã^Ù?ú£?*v!ÖC‘Ïo@2›—ÌÁGæC@Ao¥ÛVõÉ+{­TwÛô8!Çd5-ØÙÍgr£¦ZvÞzë­õWô#€«1¦Á¬ò, §°k×®~sÜ»KD·;ï¼³¨˜|ÿûßϪ-©lê-K4ûw¨‘{NtžúÓŸþtŸAĽn+õ¶8n$·É–M!Jƒ?½øúÛgÞÿ²þ¤ÿW™Âå4 ©ëbH.‘h‡@g?øÁ4av;’¿˜qBA! ù(J :'ÞyàÆÜ˜– Ýxã1‘ÑMï­ ùÈGrkKêÛ“ÀÏýÜÏÍ>YÅ<P¶ \uÕUûöíë9ˆ¸=sò(|Ï=÷»¥!•²¦ü¿Þüä1;[*{·;3YA`TZ(„;»™Owý«¯eç#<2j_%s@`¸±ê?ã‘ïýÚ¯Rƒ,~b–BÑmÏž=EíùþûïW¸ ОÀŸüÉŸ;ë¡AÞUd9ƒÊ3EûÁBJ”øÆ7¾!§'ÅÞ~÷3§â“ž·¶î,Ú;m榟##Ž€ÎƒlÞ¼™I= hÙ¹™£ù(~!þáþaÏ€Ûs#ðWõWÅŽ¤(vÑŽ²Pt»å–[Šªáúúzn I}{PŸYœÙg´£”‚-‹€NèÿÞïý^ÏÄí©·Òpƒþï·É¨M±JMws¿ÄÌmYÓ¥•P"¹„ñž´ìܰaƒþϘ‚b&Ptc%%;÷œ¸=CšóÙªÆòìƒ"Ýu;(½ÂCdØŠT¹?üãA_’ 7{§›€fÑ¿û»¿ë?‚È¿õ[¿%×'A•ÐfÇHí?ýó/¿å¼¹aæ6ö'ÿ hŒkaÀÎ.sÝ ´ìŒÙÌaÀCVX.9` >1vdÌ0“;î¸cA'Lß!ºiG½h§·¶¶–a+RåþJÍ>w¹ï JF É$ÿDý‡9@@4‹nÚ´)èug?øŠ/ºéçÿÇ—Oýæ¶§5vQ@ riò¡}ˆÁAÈŽÎëÄÓ½)  ([Š«A&À 3‘–¢r¥uEœã|6‹®èi¶"UîO@{×Ŧ¥~Áã” ¨‡ÿú¯ÿzÿáC0f亢B”Š›ûçÿøe‚–v²Ü2'Ûo¿ýóŸÿ<ƒƒÐ '*æÏ<Md‹Z”82Șg&EgVÅ"M½r¢¿¿Ct»þú냑ð“?ù“y6!µ„€v°tÖz¢1Çc’& YëàAf21AH¾µçÞ¨Ýôû«¿y”ã¥IO0©UN猞xâ ;†"på•Wr¢"µi‚ú$D è;žÈcCÍ~yæ£Er 5”† ‹a ½Ct+Š…r(“gRëAÈü‚ÎZÇ0 )ÃÒ hÅ:xÙƒLŒ€ì€d 䯅ÖˆnúÓY¼|ó“Ç\TÓ¥(ÊŸ0 ¸ÄH‡À€diÎ‰Š„' ª¶tEßñœpÌ0+M.ÚNÆQç´è¦­¡b¡åP&Ãö£ÊCÐö‚ÎZ/ýMFùg' YTÛìC ò€h•5ëÛ²e«Ýü w8~àȃ›rA ><òˆö¨æ€,Íeo_g§D€À‰R‡nœpÌ0+M.J Z]D8ÞN‹nE‡nrÈEH© »ï°U^ÐYëÇ'EZº ;{›ðݺÿð«-E7K¦¨¦’Þ–5Ž(m&pèÆ78ܺe2{PÍ%(uèÆéÁ§ÁÜ2Tüº@wóˆÄ3RN‹nE‡n„”ʭ׎QßµŽgXR’…¸öÚk¿öµ¯1ŽÈ3gûØÇvìØaƒB§G[Šn’Û6=Ž‹·…Î%YûòË/úé§sÚÔ} òF½wïÞ,†•„À¢ºq:dŒ90·ø†o!gPû±}¹­Ï åÞxÈ£6‹˜ÙÆ# ]ŠúÄ3) && ù£ôKp¼I€œ³"P*5Äædà¤èöÈ#Mò²j**;6âþ–ÿ¿ðxܨÔŸñƒ9ö4’sþ¯¼òÊ¿ûÿ\µ¤™xNàqiøÐ‡>ô±Øœ œÝn½õV≤Ýg¯Ý"Bùfû.¤âý è$‹Î³Ì>Ð(@ˆÇל’C$äQ[† ÖĪöþÃøÑýÑŸú©ŸZP½.»ì2ùɉ¤ÃS dN@;ÓÔ %Í‚æŠ?7 úص×^Õ¸;)ºmÚ´)(åoýÖoÅ·ª„Q}-·RK/y1”/–ÿQM¦'õgg‰|œ~÷»ßýä'?ù ÿxmÙ²E¿‰¼Ì®xöÕ§ÿ/¥Àƒ—“x|=)·ÇCàÝï~÷BE5‹ª0š'Ãþõ¿þ×gœq†4ø´6^†ìRÄ3Þ) ´3H ¿þë¿>Þð;g¤†± wÈ?~©á¤è¶qãÆ`$,×ì_Ÿ”ZT]Z7è›í¡‡êЖÜÒ‡€Œ€Š4y A êÞ}ÈØ÷>þøãšúìÃÉ¿lJÔ_Ç.@ÿü]áµÖéŸÛs _2ÓEæ9|øðE8‹j2´ù\Óã¨sÚE7}ÒËyNæcêC Ú™>ÿðÿpÔYk¼Ì‘ÆcÛ'çø¥†“¢Û¥—^Œ„¯ýë}ª=ã½²á¨ÝÜŸdâ1c!ív/'ØÀl,Ì Ô£Ý"yóQŒ*kϽ¡ÿ:ð9~ü¸ 7)cd¢éÎ)VúA—&ûÁ}°Åoòf¥ûÛr þCåyÿý÷ßrË-ú'·@` ÷z}ÏKovÈY‡þtôo¨q1M>q΢ÒmÛm‰¢›Žì¨Õ:ôOn'P´ïÑ’fšÙ{ð§ 5 Žt ã—NŠnE5$ÑÍ>,ýÏK§»Ålïæv/'XK ÒÑ3ÑÉ»b7“T1ø´N†èLàð±·Ï¸ï¥ }uUé-fÃ?øƒ?p“ÞW\ˆkZ:Ø×Tüæc*¹ ¿8Ø8vN t¹Ÿïܽ¹ÃØùƒ75a^²ëȪÒÛž={äð¸ó@˜þƘgQénÌÞKÝtÔHn¤†íóät#Pݦ—ùOÌDjX__ïÖcǸ«\t‹ß9QUOõåç`ë/P¦õý9ow¯yzz#A;ÛEÑMRÅ}z¤<åä‚ .8tèËÿÊ+¯Ôo#¢æ‰ú«ÒèÞÒ4–çÖ­[krÐ-™]zèÚÚZ^a’]÷C‡HÉ*‰ËªôAz®ŸÆªæ3±‚?¡«XeÝUúû‘´4Û‹vÑgäªÒ[Ì¢›3g«2ï}þùç5.â„i´3ö4Ó UX§ýŸ5×´©’+j•› 5±§ÙئM•Ð/°¦Mª·WÉþýûƒF±»Š¿ïßvmr8wǺM˜+Io‹ݘE—(ºaÜf“ÓHÕ¾©ašp›§Ä/5œ! °8Tî6Õ‹0Mè¦ÒÊ{‘3ú¨±Æ7“ »Ú|‹vK\³9™žè&Ub颛>lÔyvïÞmï'ýàúR•j¦ß[šw½ë]Å·št(ý¾ê¯N½R]îcÌnÑ?]†®$–Ò]«FJ¶ ºgÙƒ|¹Pßu¥i”2 àêe…±l]}=ê7X©ÏKýrvÑmËÁãö ¹’ô¦] i”1χ1ï1DÈ-Î"-Qt›eÚÔT㦛9Ý?úá´éfW7‡kJÔÄbS}Õ i‰§ùj*>å†}Gý ³¥ôöÈ#üÜÏý\œ£¬X*·ªÌyEt›kˆñ\¤A ø ¸ÜÖóJ mL›ý8U¯Úô¤Ù”*ZñŒ 3ªÔ¥¬‡‚rÖÿ¯¥¾tæÔ¼ùŽáô.(1 ‘ ±þ©§KÈ+:2/&–wÆâaXwBV]h»¨ØÅ‘ ©"ž‘ÐX’Ò¯Gûà©’ŠìcÏþ_Ì_z–Ý«ÎV4^Sz}n™¾˜’Ù'e ºù2\c]Š ¬vîÏHó«VšFÒžij~!ƒï@ÕÎ>z]5‹Š5:T§ó-Gß:qæý/ûŸ‘m¬Þ¢5Üp~Ð:œÊÔdhS–¨ÚŒd—û(µS«î*~¬ÚÌ©©µª`–ƒ¿5b·ÑKµ)â'k|®?‰-wE8ÙjÂ\\Ðçé§MÛêÐ Lªú§ ìšD5m¬4£ÚoÜþDq’,ÝÀè<ûu¸ñÀ‘·‚Ù²ÕÛöíÛUò¥,f¢E  -Yê§~ª”§ œO›«æp»=HïÂì,Qt{ôÑG¯½öÚ½š[ a È›P>ö=ÃJ š–'MøëmæGj(v3}  Û™ûäV.º-e1T³'Yê Më’K7ÿ¯¾èf?ßRÜ¹Í AÁ¤ÙU%ÊYï±TÎ[JcE>GQé×£~©¡@r²¬Ì0ÁΕŠn¦ÇY²@íÒí:X´U•ÐL6ú|=Úgj½•™‰kÅrš6ü©¨©‡Á?#1s3ÂòéVüŒ¬—ÞâÝÜ.VÛþdlèŸÅ}6›¸ô ýIÿ/ΟA\ì§*mË}èºùͲÕïýÏê¨_jBnóÜ 7»7¨ >ÂÉVèòŠÒ8SE•`âiÓ̇u9qmAÓfÀʽDÜÜ^œ'ç5s3¶ç<ôJé„Ycõ¶ Ñ-æYÔf³9ÌM‰Á,W:‡++­r‹S·ÛžJé¢:æõçMƒ£š½) †"Pjߓ꡺¥M°þ½`~–âH Â¥ vÚ—è&ó΢ó{´¾lõ–n¾òl úŽrMBVVA_÷íÝüÕ‰V6J¬Ëí(³ÿ\å©”‰œ+L¢›4˜GBã«¥êëÑ>„Š^Û¤O™ÖV*ºÙ]v´ôÃÉWjµ¿èÖæYV‹¢û6+LP…b¬¾®ç§‰ÄÌÍêrÅc¯•~CÖ8óÒM&UFUs©»Qš ÌMow7éiB+dp–~Ð,'C9Ýb¶Ã¥û5_q.$Ÿ_òzÑÍþjÖs5W»çå3W'ù©:öK•ÊrŠÛ{PEºøâ‹gª¨L­ÿþ÷?.7Ìñÿ·öܦ©{”º*ªf¦(™Z©èfgKmXÚ—•¯:•~ê—îòcÕYbËÐ]UñR‹A›ÏÆ4œàkPÑZUΊae6×u¾MŸ€ÏØ+Þ³³üxiQ‰ÓATë: ü«¿ú«Ìo+=ÂM\m¼®ºœÝ¤TíÔ&´@ɪ·qõå?7ë ñJàêE·R¥ÌÖ+AQÝì¬`DÀ»­ÄyÊÄÿ¯ÿë®ÿÖ«3ŽŽ•­Ñ1å´YºÿáO›þ™Ó§Í¢èfscÇÍÜæš6/x¤í„éœÞyç¿û»¿;åÀéü¬ÈgÑ*Ñ­têsœ]°¿×[ºua œî¶,K7×\zé¥ñ|nQdK hß#³ýÎÓòì7N&5øúC½kf¤ëúЇQKhñŒ»3$å»ì²ËfïÐ Ð8ôW츾øUüÔô•f÷ù˜q¿ß¬ õržslì:&)ºÙHø¿vO£Ql >öícõ¢[ÑVË×ÔŠ¢›ùPó?¥•ª(r™¥˜»|#¸¿­:ú,Ôe6}*yQ´ïÆ@pj­Ô8ýÏ[ïð´T·ÏÅRmËŸÝlékynâ-øÜ„Hc¥ú›3½zÑ­Ô[i©\aŠEuv_@£ÞøÁo´U7">È5¢ÛàÓfQt³ý ÿ vM¢Ú«0Vš'51Z˜ÀÌÍŽfìV4s[Ê´)éíC·}öþûïu° •ùRfÑ@«7Ú-Ntnª¬ZÊ.ѧ›úÀâLƒãù8¤$@QtKÛ¾g(©!ðdUµŽÔàÞøEÑMÐìÉ=³*ÝR Z(øê˜–ª¥;uþÉSý\~î;­¨î)YñÃÏO¦ÅÌÝ÷€/¢[$VŒFÑMƒÐ§àûk+µt+Æ^låê-Ý¯Ñ ­~Žhs{ñ”SgÑÒÍ}ÚÑÑ*çtöaüu)_î¨iä¢[ÕwTéwiãÇU©ÙZ½èVeŽáô;¿„UæfC‰nîØiqºn¬ûP_òÝòILt|Ú¬·t³9v¨è¥cL›6‹ššfj`àsÀͺæÙ-p]·”is¡¢[´³hqÖò794˯¢œ›u«Œ)"Ÿ«fTD·žŸˆÜA¤-º'5øjšÉzV15RÃbD·Gy$Õã¥N_S¯ Ó‚7´/ºãÁ?}㈪HO~¼…FË»|D7Y<©§ýè{6œ÷þÿdÿýò_Ó‰˜øÿ;pä­zK7ýÕŒ×̘Ë45÷¢*Zº™Òä>®ì‡À¨¡hÈP•a›Ï¿ú·fͳÜõi‚¿¶ÉÐr.={+à3öŠŸzühKÍ7òã¥nò)µ«úJiü¸r_t~¶ÝD70Áw¯Ve£1”覊»o΢اa¸®nòYç»þí›þôðÑGÇJÖ@®±tcÚ,E`SÙÕ%º• |Åiv¥i³¦ðAÎA]ì¯sM›ÿß¿nöéxv[ÐñÒøgÑÑ­~5럻o4pn|/tžÓÆ»‘㥃È%dþŠ¢›¢LŽ7öÇÎÙÿ´[jpÑoüù<°òAj¨Ýâ:^šðAkߨ-P‹ÍzK7gžVtäÇÈóǃû–k”Ÿ]æ¾7ñ$-ÝŠÞ %øöŸÊ'Ë¡þëÑ}ƒÉ(LZB¡TW2yN ìô¥»ìóÌ…5[†À›Oi†ýE7«Z•U…{hÑ$Íþäûö¶ßôÝ&kÓÒ%HÁ^_)2@ãÇU©în¢›^“ÁǞ˼hE? è,˜”³Û•‰ÜiÑâ 7&ž6í¾?ýº1>¸è6ø´ÙSt›kÚL;Bü³hK7³}óלIŠnR˜kN๥-fÆ–ÆÆË¿Tt }ÑÍ|‡ ,±ýÉ?—juf7çbð™ƒm?™³t âô´š—º}ú*[™ŠX>úAåô‹jß„æiÈÒèûe`Z²hÑ­ê²Tn3¤êÉrÞÙæU=q·ÐþÈd£Éƒ;›é{ÿ©ÝÜÜ[,†“ÀÌÏÖþiSGl(ÑÍd>7»Xï7M‡Ç-ñ²q¯bðiSó’énæJÒÍföËâñÒx¦Í…Šnç<ôJ©èV*·Ù„ç.EÕŒ|-•ÃVÕÈÜ^ê¨ûùçŸ_5ÃóÛà·|ýë_ß´iSÚZµƒÀ"”ŠnZÒ >ê§É°Ftp³±™Ù6 RCè•ÔpF>#Á}ÑYOõ\zY}\^kZßq›kl§@û¦%¾,]z—nžè‹nº]clšydÔ§E7M¸‹x[8û²Òo¶@_+Yø¢›~ª:ÈY´’“ù˜ýÒ¿ôõè»Ð.Fè³Ä›íFÔ.^ž{–„8p¡H]š 0ö”åŠnGß:qæý/ß5r[䢛{ýk)+jC^ · áv Juº*›5·)ÝZp KÍ(œŠ§éÑúU©¹ñP¢›u‰ój’¢›FPé9Í>Ó¦¦Ds¬L›þÞ@„ÓæE79’+*n5rÛE·ÈgÑR9¬tk¤fW`ÚnqvpíwŽG]L¶ÌÑ­qÕGLC@F¥ß€-ÇrlÉjD·a¥†šÅ°­cz€Ô`D¾ƒž¶ÑM­xt™W0‚JÇž8àø'LÕwo»í6g¡ŸüÇÜܺôú§nÑŸþæoþF¿Ôÿý¸ úÙ¥ô¯»´óærþÜç>gGœ”•_TÌ?ú«î²Ç-³YŽJ7,N¸|§™îyŠ,Ñ‚“žúgpJ´˜FÖ×»Q/žâqQW¼ÒÛ-étÑÌĬXÀXÃþ¹’¥›ËS*›=H-å¦BZ]Uuñ«\¿}ÊA±1“-ûßr›eøÔSOýÄOüDœcSs—I6­…ü“?ù›úÜäæ&¥×_ýôÏ=÷œ›'ï¹çÿOÁÄ«”å¬Á,WLàN¶–’t¢›ÿW?ªCñ.ßþ®ôqÊS|ÌÑ.7ŸÇÙ”{÷î½êª«ûpT fœ6ÝLeÖ»ñO›Uó±äõï‘);À ûÞv¦Qn³²ÉëÏþìÏÆ9ÊJKó,êD7¿äšŸÝ¬ëÏÆ.æv[»×Àš±Ý/u¯¿‚­šÃãlÊ?û³?»þúë§< ¨"PzÚ)Ω£±T“I æqØt•Jëó@Ç@j«ØÍ´rŽgTž¡¢”±±ÏÅ™ ~$b–ú±¿ 쉊ÿ D7—ÀÈìãÖ_ÍhÕ$(æ\\Êø" Kï NþU¥’Œ»tÑ-žAKIÆ#àΖ¶”Û¬$’åG Ú!ì(èŸvù󒯯ù³¨Ó¤|hþ¦‚ÕÚÝâ„3Í®ú¥ûXÕ$Hx>.¿$þ´\ü&TÊž¢›n×#jf{•9ø¤ewíÚÅi©ñÆ>9w àΖ¶”Ûìv?’aÕ²Ñ΢¥¢›*åÄ2ûf³dÍÉn&Ö“N§Óܨ4ú«îr™[õ—%ºýñÿñ-·ÜÒ¡Ws  08â7 –4-§ßØ’M&5ï@Lð÷Ñ‘ÔI^~ùåÈ¥†rÑ-Õ‘ &ñ?ƒï7­9jÔ±ÀN¤T3ÅÍß'´™BŸpUéíÛ¯ø«åQ±0˵t+ÝŸÓɰH ÔÎý²Êœ-O’‡½-3·•ä¶Eˆn&3UMnššŠr˜–¥éƒ_·rKg:ç«Z¥³¢¿Šò)ª¯¡,Ýô\—•³qó¿E£ý¶Dt›l^bÚlƒzçÞÔ„¹’ܶ\Ñ-ÚY´Jt«/pÑÙß;ñgo­™Ýœ‰èÖf\(¸ôÒKAD&ϱ©i-ËS/º (5TíÛVJPZ¤†øí{NŠnŰËÝÔçÜwTpÊé_þa¢â“d¦E†3Ñú ”ÚåŸEµ»ìp¨Ÿ²^ÓçhÞ¬Hª>2õD;UjW•HË9bÞdêQEù™×ÒØ,ÆBÍUÒaìRE›ÿÚsoè¿Å;~ü¸fÑy‡XãÓ5Ÿh‚ò§ šÉG¹Yú`~+NƒöÜà §æF⪺˕ÙÙ ×|Ô©0vÔ¯©6÷l>/}„{>-YÌ\?¸œüWc—׈z¤>øà7ÞØ¡rËJ˜6[âº÷Ðë{^z³eb?™¼^vÙe# “Q³pµ °j¾²ãHþ4^“Xèüeª¨.[-§ucé¢zTà}2ÿÝßýÝ;ï¼³Cÿä@`p7n >e‹Úg€Ïxï”Rƒ&a_ 05 fQ³ÔP*ºémðÎÜ9Ó¢[J#aÆAÈ£khC#˜m%RtîµÜØž@½ÉFà“®}¶¤ ¨{ç<¢Ûª(œß· ŒyÍ0¤j£ÞIܪõ6=§¥&›v˜6GEùyüa‡mûÜz΢í”IÊÏ~ö³ ‚1jO&s@ %¢Ôp÷Ýwg2QÍiÈsEäö='E7ùfJù_ÿëOÉ„€æÖ -Î#xË÷ Éò$pùå—?ùä“™ çb5{~.Ú©Éa6q= kÒ ?F.['ÿ•ÚÁõ|zÏÛõ^¾ë®»ò_Ô:1Úu“û•ž#"±Û{΢‰Ñè_n¸aÇŽ‰ ª…¸öÚkƒÏÀ_ýÕ_í?ÌÉŽ€Žƒ}LRoTãå¤è¦+A)—XŠ?Í­AãœTT…éI@QÒ+-þ‘8R û|.º³¥æ³hòp:TPÖ”Qyó‰aÜQÌE@!ƒÏÀ 6t×Ü*Ú™úØ­·Þ:W‡/}îIÑMØE[4*$ ¹5ècÛ·oj$Pô!°mÛ¶œMåÝçbUX˜šÉÄ™ž 8áÔg¥ÅŸ´¶bxVýFÆ>âÚ¹š|Cö¡ÜÌw)J'>³hçY%Õå¯VÑ£êó9(§÷üóϧ:Q¯é hg:´ÚjÐÝd€]ô<—³¢é;JÚOÔ¬Zì`:ZÕH 0èC@ýùꫯN{ ×ÔNQDå­›4»±ƒZד¶Ä5{´»zf8êíz#Ëo`Ÿ.ʽˆ‡€özårkÔ!³¸ÌûÌ¢‹«ìØÖIüØÅ3ú( ¦'ð /”~ Ž=>ŠLRïô]½æ‰'E7` ª7V>íDMG%POd}}=ª‘@a Ї€úó{ÞóžQÇ™çL@å7°Oå^ÄC@{½r¹•óˆ¦î£Pð.ùЧÃS@@ÖúÚ€“Q§Á¬2×ÎtQËŠÍ%ËIÑM—¶Ðƒ²Ê7«Î:jeÿøÿ8è]_|1¯$F@½SùQg’œ3ç2±é"óê°K‘ól6AÝ?ùÉOÆv°(ó!Oõ! ø9ÁÇàg?ûÙ f‘íL]¥Å6èN‰n„òÍ¡GÎUÇb<‘k®¹&¶‘@y Г€zµŒ:çe<7mò(¿=»(·C r¹%Ç[i[j7ïŠí`Q¤¦ïÕ<¨"°eË–@‘“1†?yfH@nл"tÉrJtÓzPVù'ʰͨòÞ÷¾÷½ë®»îâµÄ¨W˨sŒDžà2±é‚ê°KÁ´6—^zIÞ£b€@T?§xP£u¤y€l³" 7è] ’UÿWaN‰nÚB/úŸûÖ·¾•UƒQÙ1(D`i˜ŽØFå@O:[ú¡}hŒADž™Ð,ºqãÆžý“Û!íÛ·ßtÓM™mª?¿ü˿ܴiST½Â@ŠŸSüÔhc Ϭ(öw±kiÛ ;%º)€i1ªÈûoÿ-«6£²c(Qj`º4¶‰€òô' YT^Š4õ1ŽÈ3g:¶,³ þ]” þ“ýfÎ㚺D@&秈g¤S8 8VŒ¥0Ò<@¶ù(Qª›>|8¶¡wJtS±´/Œ¬6òé¯ãÕ´èÐÈØfÊ3yÐÔ?Þh"ç< h•÷«¡z)ù@  fljŠ<ç´Qk­sF²©‰¤“S @ÀÐ"9ä¯vÔÙ€Ìs «ùø£(hœÝŠeûÆYë:ë¨u”sÀ`$¨§ñ‚@’î¹çžO~ò“£(2Ï€6‡±NrÆÈ¼R áʼnР'´Q«,csM˜™,ª8 h‘\<È‘Q§Ä2/úŽ×ê"Â!pZt+uëÆYë:ëxuÔ&vqz•ë«GE‚@Ú]'ÓxóIž9k•APÿÎIˆ€ì7eř縦Ö#±y„Aëbz”³8xð`ñ«"#M†™d» ßñ§E7 ?ÎZgÒA'«¦6±‹¡jäúj–¹ž‡B`šEÙµ›l†ÉáAšEãܲ›`4ñˆ´ È~S¶ð9Œbê8›Ëš&íCí °\Š |r@d²é1É-Èwü;D·âYkܺ%ÙA'«Ý–û^¤äÝàÖm²é%“áЭÛHä®EÀ­[&óØdÕÄ¡Û">…Ì–À-·Üˆn™lzLòAE‡nÑžy‡èV^9Q‘íü6xÅuÎHv4Kéü”Ð"¹øm(%nðÙ€ s Pê;^îbãYïÝTÄ¢[7™íåÐlÔqp:¥C·8‡=¥•€ÌC!öäU ø…(‡È=gnÏ@©+9hß'NŠn2õ×NQ0dö™[CRßžŠqKurY½kâþÍã 0 …ÎyüñÇ{"nÏœ€Nèk:K桘Œ€:môÌ3Ïd>Þ©~OzžlÌò ô$P”®¾úêž3·çFà—~é—Šn¬b6vE7"}(ÖõPn]¹O}ÿáþA¦ÂA/ºõÖ[{ÎÑÜ¥°¦}÷fNàÅ_”ñ /,¥ÏSNt& eç]wÝ•ù§ú}è#E&;»Ç 7B`JrÃR4vÛ¿ŸI€{³" ErQjˆÜعDt+aŠÙgV]¹geÕ[ˆ[:åÛ‹gÅF@Z‰|öGÜž3‡~'˜±kÊ3½{÷bæót׿îZv²³;Òð$[ N@nXŠß‰RâúOä ù(v¡hã–Ú*Ýô[ jÂz(“N|3‡¬f¹+«ÏvvcÝ” E¥Rƒ\ã83Uª~çw~§(5Äoì\.ºil\ýõA}䢈ÈT»ïPõRQ? zŽLˆyß@ CÒM¤ž 5¸È'üà÷ìÙ“á¡Ê9Ø´ifùÌrÖTr­DÛœÇu‡À ¥Yü¹qÀ¹1ɬJ¥†E;WŠnòEW /•d÷°Rê!Ån#Ýa‰/Ê ž”æ'~â'_d•Ç\nU{ö=n‡ÀâhÙù³?û³9Œqê8 ¯|å+út_\o§À€@©ÔðÉO~rÀù¬Ò# U¡T¡Š@UŠn:%Ÿ2»¥×YÇ«Q©ö¬]‹õõõøG%„Àô1 O‚ñ9§G@ºCä˜Æ)ä Ü,Ñ9½AMÆ# -ío1| Å(•0vo¶L#gÍù<¥>£ÓÊñ÷ÿJÑME/õqˆ±[]vŒZ”š¹Åï×0þQJ —Kc·1¦š„óÄÌm¹ƒ’÷'€±[“ÛUÃÌ­ÿ #ÌH TjÀ‰ü³eyjÎ_bbu¢ÆnitÐÉjñþ÷¿¡ÚóŒï<l7&›‚xfnÉOT°†€–7nħOSÙ4UÀÌù‹&€Ô0ÍT™ÌS–kæÖ ºaì–L "‹ÖžýÆ¢ð‘Àvc‚ù'G|ç;ß‘ây¦x•€ ð铯„6v-vCÁ7FídŒM€sucO•Éä¿t©¡ÎÒMìT–AÓ«\x'¢ö,«·E±ûuBþ±ÛßüÍß0g@ žÀm·Ý¦Õ'ã90c·¿ÿû¿gº€@=ì‚sž(¨{2ô©(Ÿ\E'ò?øÁ˜!àXºÔÐ ºiHË'WñôìŸþéŸÒ à¨?; ñ¤’y#R‘žÌØ5¤2Hkâг³q;–N@Ò³h¦ ÔÐ>Qž—>Ò)?Œ@©Ô GáÌpvïÞ½t©¡Yt+U ¥5¢@3Rí™xR¼M!à`ìÆ„‰™ÚÀØÙ²‘fnm†i °¥RÃûÞ÷>¤†Æ™0Ÿšó‹¢Û²¤†fÑ :ŸÝ­¦÷ÝwßÒµçE¼“(ä¢ `ìÖmzÉä.ÌÜ=º)üà0vËdêëVMÌÜqdy ”»)Œi·)‚»#ƉºV¢[©­Ø8ÝH¬Ow¨Î³Ï>»aÆ¥kÏó¾ixz&0vë0ÃdrË/ýÒ/mß¾=“@5!ÐHc·L¦¾nÕüà?¸gÏžÆ^D@`)ª¤†¿ýÛ¿í6KpW2dð(³Ç¤†V¢[•±ÛÏÿüÏ'Ó¢T¤_ù•_ÁÌm)¯4Ê9/½{÷^}õÕÝw%L@Ž*®¹æšy;'O‡@lvìØÁ"3áy¯sÕ¾üå/ßxã±uWÊô$Pjìö3?ó3ç nLƒÀoþæo¦!5´ÝÖ××/½ôÒbwîÜ™F‹R‹dá_ì24®K¥‚7®:O¦”þÛßþv1¸­~³Ä·@[ÑM£H‡_Š Ëûßÿ~ܦԹWªKiüÀï3çr/& —„™r0¥y&íÄŠÏ¥ÝÝ„ûûlßZ¬JàW~åWäa}²þƃ y 5¬:I¦”^>¬J–.]jè"ºinÚ´©¨»½÷½ïýþ÷¿/ŸÐ\©ÐÂ÷ø@±éq¡N ç}©ðôœ ìÝ»WÖòS©NÔ«Š€6¨ôeÎÌyøS÷U Ècìu×]Ǭ’!9ÊÔqÕCz@`Ñ®½öZ¤† '|UYG)ÅOpð£è¦8îï~÷»‹DX¥=XôÌNá!0 {î¹Gc*íIƒÚ´5¥]ŠÃ‡ÏÒåx(–K@§òÿ÷Ÿ)%+:]¡ “Ï˶”ÝHj¸øâ‹‘²šðUÙÏ|æ3ÅF×oöìÙÓ­#ÅsWGÑMؾ}{)–D©RWnêâéДË"`¾ŠR4¨W‘€¶¦ˆò¼¬AJi#! ãP™ˆÊP”‰%²—ÉÛº‘ @Љ h±„ÔÉloÕüêW¿ZÚârÉ2qßãqÝE7•æ–[n©rî–UÉ¡²U®Ü°ùcX’g>4{h_ã+‡i„:jSJÖ:ùtoj a ÈDTHðd’É\*Kp¶u‡Aäe(dª#V쾤÷¨’´Ù¶¬N[UÚ^¢›ùçÄuzý>¨Q•+7ű%biµ˜‘ÎÝ’ŸB­‚¸r›q”ñèdàÜ-“ WnÉŒY*Î$5\sÍ5E©A¡uð‰œÒ» ©¡—è¦!TåÜíg~æg É †RWniœ¯îüàF HçnÉÌ–UÁ•ۀㅬ2'€s·ä'L\¹e>Æ©>8—:wûùŸÿùägÂ|*˜ƒÔÐWtÓ¨rîö‹¿ø‹ùô•„kZåÑ0óÕ¼Õ  œ»%<‹ªj¸r‹d QŒàÜ-íÙWn Rª T9wûå_þå´'ÃLj—‰Ô0€è¦AUêÜM–PṲ́»¤ZÍûî»OíxñügÿìÄgÜõ/ÿå»ìÇô›dÎWøJ +ô! Ï ™ÐãÜ-ɹTë v)úŒî…@@@Ç,>ðàÜ-É S{öÚΧÏCpJ»éƒTë«$§Á|*eRCñJOjFt«rî&‚3]î°qáJ/ÿ‘‘âfÿ½ðOÿé/þoÿ®ÜxB`p2¡—îöw÷wË4(y‘€ÖÚ—¼·!2'ðÔSOIwÓIb³.[™kªRUÎÝ$5|ñ‹_Lļ:UáJ“ô?Œè¦á¡]ÇÒ× <ð@>½'™šþÅ_ü…¢Ã8áùÎõ¯Žÿwÿ“ÞNlÜxâða^ €À°ôùÁ~ód&R­'®½öÚa; ¹AF`×®]:¸î–Ì„©ç[o½•î @ H Ê¹›¾Ue&’Ì4˜OE©ÁiÒöìÙ“ÞLtòeŸ><òéC Ôô›ßüæ{ÞóžÀÔSön{ÿù??­»uÖ‰;îHoHP#ÌK@)h˜EU­'¤¸i{vÞÅÓ!0;vàN; S;ô7ÞxcÂ}•ªA= hgºÔÄGúRò^¥Rƒ)rá׳ŸÄyû¢›jXåéP Žà.«7d[Zy•Ú°aCéùê“^6¶l9!¹íO›ž8ÿüûöÅÙ¹)J@æÒݲ‚Ò¨¸^yrH¡º,´Rl,…À¶mÛp§½ôiSÌŠ&ÄÅRå„À\´B.5ñAjXÐ[ FjÐ }®®5ösÝTܪ`¦ÒqÐÝâï}ï{K·»îºëTwÔÁR/uº›~¸îºGŽÝYÉùÐDJèø'̪j"•⦣ùôXj  (P î´—;a²E1ãØáÑXL|–;Û«ä5RCÚ1džÝ4t…¬Tµ‘ýWõW¯pÅJàé§Ÿ®RÜî¼óÎpR–ÕÛ9眖ÞÎ=W‚ëâ&n h HæV´¦Xg ÊUIÀbÈÏi´]‹‚A =òö…/|‰iq´òÔ„Ix®ô†$5‚ÀxªL|"<ñÄURCò1ÇFÝ4Æ´ú)ÕÝìÐuä"Ïâ}ãß(úq³F¬²n“›oòvÅXïCιØ-óp(–H ÊÄ©!Ú·IÔC̱±D7^­~Ju7ý’UQlãAJh•âÖ< äÓMžÝœô&oòûÆ A@º›ö0b›1(O)û€Dq¢ã“V& `Ú#üýßÿ}&¨EЊÛʽœ $ ã H ‹˜íUHI ¥ÎøÔ‚2vÎÁ¡çˆ¢›ðI¯© ŸûÜç–ÒK’/ç—¾ô¥ªa°Bè½Ûn#ÀïAŒAàž{î‘·çŸ>ù¹hÑ´H·1†yB =}†q0?þ¹ôk_ûŠ[û^MJ@ ”€6ZâŸðenUÕLW]uU&1ÇFÝ46êu7Ì7b$òR5 VPÜl"”×ðK.9mòvæ™Xà AÈ{Åu×]‡îÜYZ¹+år®N&èO@1µQítAÁzè!­03ùÐêߟɨ!P£»!5Ä𺑡Š›:𸢛én5ƒUѼƒA†Z­£©§Â)œ}ö;,¬­ñ¶€zP”ô~ðƒr6ï¤ÁÓ‹d3/ÅÈž=œÛ!0 6*¢«eòpýõ×w\aØEÈ H…@Í9SNŠÌû.¨òò/ýaeãž…w×ÑE7ã#·DUâÎ>ðEy›·Cdøt}ºÿüÏÿ|U£hòêÕ±K,¼øb¯<¹ÙØ»w¯t79ËpÊŠ¶Êú€ÌmÝý@À2<òÈ#?ýÓ?ÍFET“§öz“Q·ŒáA)!8×H ¬œ§èå«WððÆ=‹í·‰nâ#·DUÜ埦S„zÿûß_Õ 3LÞ³‡ Ã$ü#¹ “Q•BnO9cð¬*²™ç’Ñ h ìÙ³GììF2‡ÿò/ÿò`+Ìhûƒf" ç©A§Ú#™ s(†¤† 6ŒeÜ3SëùØéD7tÇŽUûÕ*ÚþÊ¡Î^GöªiMX=»TxûÍ7¿#ÀÂ…žP´S.@ +í)ÐâŸÌ>™ä\3–w×fä>@` Ú¨Ÿf¹íÏy¾š½îÒ=¥~nÛ¶mŠ&ç€@®dà\ó‘KŒiÞõRƒlóìž“ŠnB,·D_|q•ðɆ䨃¡ÞÎS“”¦ªQ†,\tÑ;,H‰ÓT.@ ¹»ñÆe5@h…Qç̨̪Tº§¶‘:µ7A“xá…d ÌÎî,³¥*ÅSº§¬'mudI@SMÔ€W«Q_’ö­JçÑï‡7îYN'ŸZtí:^zé¥Uí![DY$ŽÚ!ò̼ÞÎSÓÓèë¡b€…;—3R()¢# «­8j:ñ”®ˆÏRÜd¸]‡ @€@5ldgwâÙR“Ö)ÅSº'}€À4$5ÔènxµéE ©á½ï}o•Â#ã™^MÓâ|Ê ¢›@Ø®c*G9#uˆ<³­ Ö«VФ”é):¨b)\wÝi“·3Î8qÅ'°0zž‘&-,8j:Ù¬nGJ‰‰¸{i'j•:m.rÔt² ÓŽ”âÄ-õQEý #F©AûðuP¤ôòË/g¯zÑÍF§ÞÄ5º›<ýcòÖ0ˆáOüÄOÔpÖùö©? eàvÞy§¥·³ÏVWˆq¦LXŽšöŸ'ÛäÀ‘Ò%ŒÊ5m3ÝõOÑR†" 0;F©@Žýg{-uì¦FjPÀ±©¥†Ù{^YæÝTí:Ö5Uûýâ/þâw¿ûÝ—¹V' n¢W3dy;–·6}]nÝÎ<ó´ô&§o´¹4€@‘€5Ý»wïêSw4àH)ƒ)ЗØúOÿ‰åeóÜ×)ŧ?ýiŽ”¦4^¨ –K@ ãz©A>Èxtšé_>tèÔH :Rš³·`ÔÌ,º©4öŸ:z½uëÖn½!Û»ô‰(n5Ã@',&:RZ3O—XXî¼NÉ!0+ Ò÷©O}ê¹çžËvê¼âZ®éãœ#¥³vmá hÓW^ä|cðI#ç ¿þõ¯ÿÇÿø9R:|%G@ +¹öÚkk>ŠõÉÌ»`Õ7×—¾ô%9⯡ʑÒèD7+P½ý§ZTFz—¯Ú!2L/JõFž‚×ä½÷žÐ Sùw³ÿÎ=÷º¾W¸/s²ßV(î7þÉŸüI†³ß°UÖžL-F2“y¯¥ú˜‰€¾Äî¼óN93ÑYÈag s³Óò1ªíŸ™Ú“ÇB¨$ å± ¯ê[ñ.hóò²Ýè’úGJ‹q~K7W¦Æ£¦Ö„˜€V‘Ÿú1 #¥;vìˆnJV,…«¯~G€ý“ ѵZ™_ýõ?ýÓ?ÍiÓ6«‡Ò4ÚÁ“ܦ%Ú2šœRB] È»³ÎBþ—ÿò_X^vž0uE&LjºöA  U±¶¥ë¿”µy ƒÎ“aÚ7Únt£ÔÀ» ´7G$º©|Úu”_ÿú¶”JÍx†´VŠ2^«×ïM²Œ:j» ÜdææLÞdþ.@ Eææ´i‡ÕíàÝxãQÏ–º7AU´ÉiÓ¦'ÕÒ] xz È ˜s½Ô`>å‘Þü7‚¤9ë¬w]%n,žkú\¢›T½\êmÆvbÕFnÓ··XE>ž*^1À‚\¿qA«p§M×ÖÖ:|Måv çIWïbÜt¸Ó¦83i3ùsž4®OM 3pFjh9Õ·‘pÆÒ8†bݬÐ2M¬6bCE1Gª¶M§I,ä¶úà¤ÆGçIï¹çžÆ~W…1U0Sgò¦ §R⸠Nd±%²2FÀÑ[Õ[@r›vðtè€ó¤º7A úÓ¾¯Ì]qîSãÌDß`š09C”N¿§&È€ œ‘jä‘–étÒŽÅs›Ñ¯è¦Ò·9mjÒRVË£–rÛΓÖ÷лï~G€…óÎ#ÀB›!M”м!GoHoÁòÂÉm æÃñ(Æ `äeXvY­-ÛìLÛ7˜ä6íæÊ’šÞ@`ÑZž65+Ÿ|Œ ÛK ú²ÀKË!µèfuhyÚTãá½ï}¯¬R=ƒ­Ã/|á áBL…\ÒyÒš®ªX W\ñŽ ×]G€…–c›d(pÒ›´ùÄJ8}=j“¹‘”pÒ'ôíL&rƒHŒ@{©AÑ®?÷¹Ï%,5üÑý‘â°5¼U'•óèÄz¨ÕY€èfõä‘G$$µéfø¦N#•*/Æçž{NŸÇÒ×[Ö=Aƒÿb€…íÛGd´ h¹ _§Ú¥Ð<™À$¹j0ÖH»{S; K@Ò[Î'ôMnKpm9l/!7@`Ვ´Š–Ô Þ!M‹àuЭ§/Ftë ½YœÓåîOÊ“Êßr˜u[²þ5Ž=éÖMÎÝœ£79}#ÀB·AÏ]ø!Ç+¢±¤·„wí=N¯ûzÄXƒA¬DÀÌ„eæ 3îWÕú—˜Þ>Ãø¾Z©ŸX4•¤7}¤k’\®Çd¹.Õª¸1&©³ûáuЧo/LtsÒ[›˜#®‹lذA]J«‡ø×I*¡Ê©ÒªÌ-MÛLnÓѧ,ãÞ}ûÞ`ᬳ°°Œ†£”ô¦èéz¦d |ß*v³$•¹Šv&pEq¤hˆš€Â,Ød¢óZ­é,ÂÕ´ú2Ëo‘öc†KÑr4u{P8@#Ðgu©AÇG–"5h’_Ujàuг£-Rt³:›¯öÊ”¥Ô.¥LÒ¤ã9|ªE›Ê£R©l«V'¹Íïæ[¶œÜæLÞÎ?_]¡ç0àv@@3ªÞÁú˜Ô®]ß´ôÙºu«æU9ži®^éä€ÀPôI&MJæ¢OTøê›Lù,ˆ³‚·nÛ¶À2CuòJ ÔpñÜø¿ü/ïþ±sŸðZvj9§Ô pj®œüû÷üØ¿{w£ò£Ô0N]°èæ¤7ü7ö˜ÒøÀ>õ©OýÙŸýÙ“O>ùÒ´×}ôQ=]eèVx™ldaÝVÚïK,è* Ѐ¬À´—¥I™9hÑ éqÚ©q€§iv5G°ú¾ýöÛe™Ò wC(' eJƳZi¶ùÄ'>!¯ÒLaÓf¡ðç?ÿy­E%·)ªŒlŸil@p$½ÕH üOÿ“ A¶Ÿ}ö²¤†}φÿþ ßû§ÿí»ú¡JˆÈZja,^t3&2aоœÌº Xv—Ö2ñÐFŸÄéWNßûÞ÷¤¯é#P9ë;°³Êf…Ädãô(X[;qî¹§MÞÎ>ûF˜#È2Oú˜Ô¤ª7®ÏôeeÛ·Ú¦Õ<6öl©üµ Ö¶„ž(}M;ZO²31E«ó @ æ ¹§è6±°àçD·ó¡ë‘¯Çª ûj²¢›14ÿDö‰8W·îð\•VÛ¤DÙ[a,,HŒã‚Æ! ïI}ÔÉÖŠi£/:™›I ÓË[ŸyúØÓ‡e7ƒ8gD,›b²)OÛQ”©¤'Ê@CkqªE®€†' _iZÔiúÒ iAÀ´o¡ÉMó§&L›ôª âöÿÃK×}ã¥?ý»¥N»nÂT>:b¯<í´‡Îºj[BO”×9v&†oQr„ ?´ùxæ]ïZ–Ôð¿Þ|·Yº}úÉWhÆi$.ºùõ‰¨•‡m9vÂÆ¾Åü©„„ØëÞõåøŠ+N›¼i¼îºXè”;!°ÙÁI Ó$¦Ï<}ìéÃ2X‚H˜söðþRëü V7Ú%~²)O|{¯Ð $…–@@‹=MnÚBЄi3^°:ÕÄø“þ©¹õþoô¼>þÙŸ±iÓ?áŸÝ„©|tÄ^y²Œ\BûSF@ vÐJçLèbÞY7­tÈ_Rƒv}´J×¢ú†}GMtÛrðxͰ€Jd$ºù­¡Þ¦…Ž…{ïÐkÝ-UÁJZæ©§›µ?n5†+ §àX8ç, ‰—¼ Е€LwõAX¼¤ÖuÍ’û ¤I`ËÓ¯ü÷¿`ßEúïß>ø}›<9‘f{S+@`‰<Ñ-$oõ—ZJ Uɪ¤D·éûZ¦¢[Z‹ßì¿¥'¸ëÿÍ¿‘¶­ÿ·¶©±§­H=‹³QãöuY·ÉÆíÌ3O[½ÉNvp\€ @ b{^zóÂG_urÛ™÷¿¬¤£oE\bŠ@ O¢[CgüMjp.YÚ¨+¥YIj@t›¾·"º•3÷ÏIi„èÒA'gÃo?|ç_ü i:Oÿÿƒÿ{Y®Yz»$rK_ÃŽcúž}ò‰Å òûÆ@€â#ðâëo_ýÍS§~Lt»dבGÐÛâk*J@@Ú‰nETvøÃ\²¸+ܼÁ¥D·é;/¢[Wæ÷Þ{ÚŠJ?sEK@‘LÏÔÅ6UœS,DÛX € %Ûž>vÖ/;·óÖÖמ{#KT€ÀBtÝæ­¢Ûôüݺ2?ï¼Ó:Ž~抙€–nÜxº½tì” 1·eƒ dC`û³oœ»cÝÉm’Þ$ÀeS{* @`±ÝÛtÑ­pßÌÍÆn@Nz“,(¨‚3yS°…µµI Àà @€À?ÐÑQ ur›~ØôøQ2… ,€¢Û)Š""ºujßÌÍÆn@N}“Xpº›~P€…_œº<€ Œ HY»î‰c ’à7OØ·Žû¶ŒûU‡GÑmqM6SÝV_4sÃØmuŠsÞ±gÏ yvsÒ›<¾`aÎöàÙ€ ŒÜýÌëg?øŠ“ÛÎyè•{½žQý©* 4 º¥ÑŽã×ÑmuÆE37ŒÝV§8ÿ·ÝöŽ ^H€…ù…@€Ò%°óožÿð«Nn“¥ÛÍO;Š}[º-NÍ ” º¥ÜºCÖ ÑmEšUfn»­2Šä °pÉ%ï°pà 't• €  Gàð±·¯xì5ß}ÛÆÝ¯é—Ã=œ @`ZˆnÓò^îÓÝVl»*37ŒÝVQrX8ûìwXع3¢âQ@€K@†l2gSLR§¸·¶.“·ÅVˆ‚C€À ºÑÚ@tkÇÉRÕ›¹aì¶ Ë¸Ò*–âjJ@X<íϾqîŽu'·É•ÛŽ/¾VT€Ýè­ ºµF¥„õfn»­Â2Æ´2pó,Èü 1¶e‚ ÄN@¡H/ÚyÄ?Oªp¥ Z{¹) ´$€¥[KPÙ'CtkÝÚ˜¹aìÖg¼ o¾ù.º¨>À•W^¹mÛ¶x«CÉ @˜€”5ék¾Ü&õMÜ„EàQ€ 0>D·ñ§ñD·ÖíØÆÌ c·Ö8£N¨ ÒÚ¬5õß™gžWvIn;ãŒ3.¸à‚¨«Cá @˜„€Nê ©SÜt¶T'L'y2 i ºMË{¹OCtk×víÍÜ0vkGt©ÔèMÞõ®wIt[[[[@u(" @£PlEHpr›"'(~‚¢(pA€@šÝÒl×ák…èÖŽi{37ŒÝÚ]F*XØ´é´É›÷ê«Oè—?¼6oÞ,ÅMÇKýºÜtÓMû÷ï_Fí(% @½ >ööÆÝ¯ùçI¯xì5ý²wÆd@@t‹¸q¢*¢[‹æpfn:fxÅ'n¸áÄm·q“™AéÿúY¿ÑïõW¥ÁØ­Ô%%Q€_uU‹:$ë6)n²t[__wu1N¿Üºuë’*HY!@X€ ÙnØwôÌû_vŠÛù¿*“·Õsâ@XD·¥µØ\åEtkA^‚‹<|)åÑ£ïH}Î9'õ5ýß¿”F)•^wq¥D@nÝLQ•´zâ„ü¸I_óÅ5'ÃItÃË[J-O] @E÷zýœ‡N»o“+·»ŸyP€ D·\Zºo=ÝšJD“[ýÒ«Tts)uW Ò5=Š¿ÇN@múüê:C*ÅmÆ ~M†³?Éä-öºP>@€:P(Ò }ÕY·ÉÒMáJ´´SfÜ@Ë$€è¶Ìv›¾Ôˆn=˜×‹n=2æÖ˜ :tH¶lºôƒ+§imòï&Û·À.æºP6@€Ú²¶éñ£¾û¶Kv9p„p í’€@*ÝRiɱëèÖƒ0¢[x˽UnfÑæªàd8ùw3·n»wï^n)9 @E·=}L1IâvîŽõíϾ(@È”¢[¦ ¿rµÝVFvúD·ðzë¶mÛ¤©.ÛL†»ýöÛU)ýIFp ­ņ @ H`í¹7Î[[wr›¤7 p€‚ ¬ ºeÝü+TÑmXaRD·ðz«5ékŠ™àÊo2œóïVEAªœýÕ¿}¡(6 @ ::ª¤þyÒ«¿y÷m94=u„ Ð@Ñ.ÒŽ¢[;N¥©ÝzÀ[â­vt4’`þÝöï߯Ù9Ó À‚~¯c§f gš¦pKl}Ê @Y8úÖ‰öU§¸)xž—ÞÌ •… JˆntŽvÝÚqBtëÁ)™[eÔj&Ã9ÿn2a ܽ©îºË´6%ó¢&ƒ…Š@€#p÷3¯Ÿýà+NnÓÏúMbu¤:€ Ћ¢[/|ÝŒèÖ£±±të/[Mbóý»Y S?Š‚â™Z%¢&@€*@€# [6Y´9¹M–n²w“Õ @àÝèí ºµãTš Ñ­¼n•”øw³( :dªÚIz³Òݬ²þAÔªO @)8|ìmùkóÝ·É››~™R©   FÑm0”‰g„èÖ£ÝzÀKàVÙµ•úwSÕô'“ضnÝj5 ¢ÕWz)t2…K U€ ,Ž€¢‘*&©SÜ«TKW @Ó@t›Žõ²Ÿ„èÖ£ýÝzÀKïV‹¢ íÌ Üô‹® «xÕ¯¾9z#ÀBz]‚A€@ü¶?ûƹ;ÖÜ&éíŽÇã/6%„ ™ ºÍÜ‹y<¢[¦Btë/½[užÔ´³b„ÓâAT«¾;‚*;8ìÒÃB @q8pä­‹vñÏ“nzü苯sž4Îæ¢T€"#€èYƒD[D·MƒèÖ^z·Zœig²kókgÑœg7÷'<µ#¨ºÑ»à°jzˆ¨ @ RÖ®{☂$8ÅMêÛ¾uÂ%ÄÐ8”€ÀB º-¤¡f/&¢[&@të/É[ÝyRW;;sªk}}ݯ²‹jj¡NM˜sà’„C¥ @1ØrðøÙ¾âä¶szåÞC¯ÇP0Ê@K"€è¶¤Öš³¬ˆn=è#ºõ€—É­æ¯íöÛo÷e8;mª?¹_Z²¢f— %ª @˜€Àμyþï:¹M–n7?yì(öm ç€Ò#€è–^›ŽS#D·\ÝzÀËáVY®âšNžÊê-ø¥P˜5\)ÙÊÉΠ⸠@è@àð±·¯xì5ß}ÛÆÝ¯é—²â@€ÀIˆnôƒvÝÚq*M…èÖ^·š×6g¿fgHM_Óå<¸)E; ˜È×›~i"ݨC©Òàr@G!@ƒ!›ÌÙ“Ô)n2v“ÉÛ ™“  äKÑ-ß¶_­æˆn«ñzGjD·ðr»Õœ¸I83›5®T¶of'IÎgbéMŒÓŸt骩u¸~Ë­óP_@èF`û³oÈe›“ÛäÊíŽÇ»eÅ]€ w@t£C´#€èÖŽSi*D·ð²ºUæiÒÎtùvj2p3çnfËæ u ]ÕÝ‚î–Uÿ¡²€ °*…"U@Rß}›Â•*héªù€ PNўю¢[;Nˆn=8qk ÅX0ÝÍ¥‘ÐæÛÄïµ3§œ3¥_A€Š¤¬mzü¨ï¾Mê›48XA€†$€è6$Í”óBtëѺXºõ€Ç­Ž@EÁÌßü€§+Émº¥&l!@yÐéQ!uŠÛ¹;ÖuÂ4OÔ€Æ%€è6.ßtrGtëÑ–ˆn=àq«0»6'µZP…ªH¦ZàŽÓ¦t'@ÈœÀÚsoœ·¶îä6ENPüEQà‚ ŒBÑm¬ fŠèÖ£QÝzÀãV# ˆ ¾]›E8uMM•“í[àÜͧgàf§t*@ÈÀácooÜýšžôêoÕ/3DA•!@`:ˆnÓ±^ö“Ýz´¢[xÜj$–I2“›ýÓD7ßÍD7³†[__¸mÛ¶Í,ãì ,à€ @H˜€ ÙnØwôÌû_vŠÛù¿ºóo&\eª@±@t‹¥%b/¢[Btë[ß;[Qt³d²}3Y-0y3=N¿”™›éwõfq`‡ ¤AàÞC¯ŸóÐi÷mråv÷3¯§Q5j@ €è¶€FŠ¢ˆˆn=šÑ­Ý$Ÿÿjúšï¾Íަ:pºE†oæL†ƒ0 @ I{^zóÂG_uÖm²t»î Ü·%ÙÔT €@ÄÝ"nœ¨Š†èÖ£9ÝzÀãÖ*f°ÄF5\ ÆIž3Û·â™S™Ò» @ I/¾þö¦ÇúîÛ.ÙuäÀÂ%$ÙÚT €@ÜÝânŸxJ‡èÖ£-ÝzÀãÖ*¦¦ùÑttÔô5çúM÷šá[©Ml!@é¸íécŠIê·sw¬+bizÕ¤F€ ° ˆnËh§ùK‰èÖ£ ÝzÀãÖ»wï6MMÿ—ÙšÙ¾ùökføfJœÒèT)€ °D¥öÑÅŠÈY›\¶9¹M®ÜäÐm‰õ¥Ì€ ¢}¢D·vœJS!ºõ€Ç­Ãašï©ÍÏÜlÖt™7})YJý`âZ1Š‚™¿µü¦¶"ä@‘0#ëzç Eª€¤NnS R…+UÐÒÈ«Fñ @m ºµ%•{:D·=Ñ­à¢@A @`tU~?ï8pÜwßvîŽõíϾ1zix @`zˆnÓ3_æÝÚ¶›íë–šÿXI]¾xÑ6_ÒA`:ûSôÔV|Ž–*™oª`pU‚=s gYÑáGh:²„ Íü¥2'¡îE°öÜç­­;7IoŠŸWM(  @`@ˆnÂL:+D·¶ÍkLŠ*ƒ-:Ýen³¸ °Auo_S+VÁ·Œ“Ç7‹ÞPz¼hÕ§€ POÀ¬›K·XÌÛ†ñ·«¿yôð1ܷѹ @ iˆnI7Ctk Ól‚‚Ô¦ÄéOZZÉÀn¨mÀäLbó7k>®T:ëíú¿+©ÙÓYL†É‹Ï!@`D¶¡8ûÏs> l»qçÞ”™Ûù¿ºç¥7G,YC€"!€èICD_ D·¶MT òXt$l*Ænm™’nVfªæô²ªH¦VÆ*#8¹~3cOýŸ ³¶'‡ 0 -c|;èbvÂÈb¡6Fo¹Bd@Ý hÅ$63᷌ܣ½/4Ï›«s/Pï ´{Q¸€ 9D·È(šâ!ºµm ;:ê õþ°”‘~雵͚tˆ€@¥[U”:+µ}}Iz+~ªEP-Š@Í|ãµâö‰¹Ð$ïL›$§u‘-‡ðïÙL™€ D·”Zs̺ ºµ¥ëk¡i'/ŠAM›à][¦¤‹Œ€©f9›,àj>¨GoºW‰eøYÍ( TpÆk5öζìÑÿ‹>4ÌYAixw C€’%€è–lÓ\1D·€Ú w¹ˆ]. ­8}7ó+dMRD@À!rfN_.õThŽÞŠF¬*ʄӦ´*E€ PIÀb@™dæ~®ñ$P¥¬Y&¥AN¡@H“¢[ší:|­ÝVcª¥d5-: ׸8R/„€t7³w3ë¶zOm5ŽÞŠaF€bBÈ‚€5¡Ím«TÅÌ1"5s¾ÝȾc]‡JB€€@t£'´#€èÖŽ© —õ}%Sµ*7=v˜ºÊêÁ”;,Ýrê5ÔX sS[ZÜšÀõ’œ|,¦þ€ П¢[†yä€è–G;SK J ÞMG“,øÝ Ï$3@†@²V?½«t˜ @H€¢[8IÝÚb–á¸k¼¤Ð–)éK ÞÍÎ¥–:÷Ñè ÂÝb›‚C‰¨9Z±×‰ôª@ý ºõg˜GˆnmÛÙ\™Š[éo8aÑ–)é–IÀEò--~Ï4HcgšÐÝ–Ùò”H‡@}ÈÑšÀ&ÉáÙ6®@M @ D·nÜò» Ñ­m›k—“¸¦u§/±Ó6wÒA`!Ì>¢ÊÍ<þ˜¯·¢²Vïn!(& Åq±…%--q²Vï% 4žõb PP@€À ÝÁ˜A&ˆnmÑ­-)Ò%MÀ„³ªuö §o<³ õ)p()é~Aå  ˜arUÄ›úÀæF}-Æv¥L€ 0;_$zéì°” ºµm)D·¶¤H—:ªo0ßMæ&ÀéÿfdA<ÓÔûõƒb$P¯Ù_KÏŠj·í“kE™ @ó8pÑmÞXÐÓÝÚ6¢[[R¤Ë’@©!›>äì,ª}×Ï4Ë®A¥!9 Ô›³¹©»´ˆ«÷ms¶φ 8 ºÅÙ.Q– Ñ­m³E7ÛƧ[[‚¤Kš@•!›¾èì³­Ê \ÒT¨ ‰h²­ŠQc“°Þß/S}`„ª»&ª ÄIÑ-Îv‰²Tˆnm›EšB•W—…©ÓÿÛfJ:$A Þå¶}ïU¹K•€ 0'ú·£ ¥Çÿë]jÚ_±Dž³ýx6 ,Ž¢Ûâšl¾#ºÍÇž'C 5òìdÓi¯@‡Ÿø‘9±sg*U§€æ' ] ›i«v8ÌœM[ ¥eEt›¿ ) ,‹¢Û²ÚkÖÒ"ºÍŠŸ‡C uNA¦p§*zÉ%§|ŽnÚtBA¸ @ 7‹R*çk6å–Škö'‹lã_Ú5©Ñãz @)@tK±UGª¢[°ZÝjWÙ¼¼ii«en•#•.¹sR!àÇ3=Y'©lçwJt;ãŒgŸ}âÞ{S©+õ€ 0¹—u\äèõõu¿@¥~”¦JŒ›­2<€ ?D·øÛ(š"º­ÖÒÚìøFpé—Rß‚îjY“i¨ô"tóÍ'Î<ó´ôvÑE'tæ” €z°uˆe`ž4ƒXOî÷RÙ´w(Θ.õ×£,Ü @H€Œ >ö±“ÿýÎï,«ªkϽñ±oÓ{^zsY%_niÝVh;·ŠUD™ðhÁjkVýÞ”8ý“·€’4i²ªÐˆÐ)©¥T6im2v³ÿ¤ÁI‰ã‚ ®‚ëÎË[ ¨¹pÒ¶w¨»ŠN»û @É7ûü¯¿"Œ©ØTäSGǯï"ºµekSŠûÆî~[È6F8mû<ÒA`ùæn-Õ S'½>–ßæÔ˜‡€–§CÖü°¦»éÒ6¡_&}è7ºÛæi*ž @ $PzÜ­ô\T•3m.â˜×pˆnmÙj9[êØ¿ßt·åí¶•$&& Ã쫯>­»I€»î:,LÜ<H€€ùÐÔÚZuц‡³Í·„ª¸¥ Tœ*@€& 5ÀŒÊë¯ØLp$M4ùÔßY*Œ×‹ÝÚ²Õ²µQýÕ¦±ódÜ6_ÒA;wž8÷ÜwXؾ*€ О€me› ›V,ºÌÀM¿7Ý­q ÓþY¤„ @hIÑ­%¨mD7·äm›)é G€ t@?$ÐÁ¯Š‹]cvm~¢T–øô/@€ 01D·¶ÀÅ¥·™èF°¶LI€€boûÎ:ëÄm· €@V,NzyšZfà†§¶¬z •… @ rˆnmÈÁõ›ÏÆ´ÃuÛB9ز% °°gOõN©Ž{÷îݳgÏŽ;¶x×wÞ¹©ìºþúëýdúY÷ê:¬(·\ȉ€„¶>.Ø´;ÄRÈ u… ŒH@ïhóáPmÛ¶mÄB¬žµ¤‰–>ݰZnÛ;ÝÚ’²ƒ5þujC bsضz¤ƒ@T`áŠ+ GFUF c$I »ë®»´‘¤¶qãÆ /¼ðšk®ÑÏ7Þx£¯¦)©iÁõÈ#¢›Is.+Så$áéF°C I2OÓšØb w6U³p¥K €  ½t@˜¹e…è¶B‹K·6·Ä¥—D·š¿®ð’BF€ Qö„^xAú×­·Þ*eMúš¤1 d²b»çž{Æ0O“Ñœ©r’ðô =ñÒK/Õúþ%! ÕhoYb™Vó=7™%|[,…ÕOj@€š4™¸Ýd‡Þ"49×n\Í%‰C~\jjÿ^Gt«Ã§þ‡åZ¯þÅÍèI@ÖmA€…e[Õ3Wn_•ÀñãÇ¥|é“þª«®’æ%ýKoè¹4/©~R÷$ºIõ{÷»ß}íµ×Jï{ê©§V­é! ¡§{ TÛÁ–H S @€ÀH´gf–%]©ØÒ:¬ØýwþFb›F¶ˆnuíØ&xBý€Z@ jûö…î¸#ê§R8Éj2a3mKg<#Ô¶¤îÚµËÔÀ‹/¾X…”â€3¸T:`FõÐþ¹Eõ묎­£+Qè)Û­ô,C€r& ƒnfÝf¢USbT±Í[½+vOCû) ¿Ðg!º!º-´ëRìü(À‚♞qÆ©ÿÎ?ÿ„Ä8®ÿüóo/öúÖ·¾%õM¶o: +tcb#o´% ‰Í»Z ›èæû_“LlÇR$ÉÙmK–t€ ñ ضÙâLÛŠÅÆ´müÎòŽ' º!ºMÜåxz%ȹçž6yÓÏÛ·÷Î4ß d¶}ûv‹ªÃ¤ßýîw+µ•ü+_ùŠt7©oÒà–b²—o_LºææpM—¶Ç«*jžŒmϼ ÝUf½CžÜ@€€,Ñ´MÅÖòÓ¶Ù;0¢¢Ûì@`u °pà 'Î<ó´ôvÅXX•£LÛn¹å#Õÿ{ì±”´¶ .¯¼òÊ}÷ݧ3§å™NžàVeEzô! iÛ7­}kò‘)œ%[õd´;ŽªøUïíS/î… dBÀ¸uÛ›‹’--lKO‹ΓÎÒˆnˆn³t< !ȧ›<»9/oòø&¿o\-(Ö§bHúò—¿|ìØ±„å¶ jZjÈÎȤ7´‰=…$ÃÛ­wۜ气ADB²ZéiSui³[Šÿæa€’  @`Zzáúñ–%`9on ø0móŽû4D7D·q{¹C`tXX±ŽXJnS¬Ï‡~8­-¨©ÜÕ™ô¶eˤ·Uºi;0ûµâÍ&™éOþγ%v1ô'çå-ÈÁVÿ:ðÒFÎëXtnƒ @À#X zÎÝ–e²·è>ˆè†è¶èLá!ðC‡ŸÐñRgò¦c§:|ª#¨\={öÈq›ŽXæ,·ùê›ÎœJt“ô&î…^ ³@`<&•JfvèÃ7mS‡4Ë5¥77mº¤¯ù·k‰o¿gÅ<^«‘3 @ Š€öÆü  K `jÕqÑWíÌ©ENç¢[[ .6}r††$ p A€^!?äkr›®´·u3Ü“ô¦P­HoCŽDò*(Zº™?fsÁf?ûK^äÔÔ7gõf›Säel¡S@€’$à¾éÕ¼²c®²oø¦…G½ÛÙ˜+ÙÝêÚH+]Ûjæ‚–A@Öm×]wÚäM¶o²€{ñÅe~„RÊ€KAÛõ89¶“ôvùå——ºÍ¡eÈ25vP´ÊîÌD7ÿ ©zšSÙô³D4“O²ßTuÈ­éSkiê@(0ËâĆGjZÍ¥•†9‡ÅØh¼†Ct-9C3 ÀÂÁ+V€T$…Jh”œH`dõvë­·ê®<ßÍÔwyìR Ø)ÑÒª’…G¨9 jë]÷põGV[jW Ü€ "Û?«¿"ÝÌ:¾Í…è6^·EtkËVÔõ"±ûkÛIŒJàŽ;N(ž©sôvÑE'$ÆåqI3’r¤x©Hj«øÖ·¾eôˆ±Çp¦–Zªšã6Û+:–Ax„à©Ec·aŠE.€  A Ip;õ÷ØÎÉib.³/N{ ÑMÊó@tkËÖVÒm.ŽC·eJ:ŒM@6n|G€…›oN;À‚>õ¥I3’r´ªØDzŸ€6ݱcÇØ”üÓ `\¤Qý,ÌØ­¨Ç©úJi†rx2N£3P @€ à ºµí :¤Ý([Ž„´eJ:LC@Î9ç´ô¦` ;wNó䉟²}ûvéDR‹Ï!ðüóÏßxãòˆwðàÁ‰›’Ç-Ž€ü(K53¡Íô5éhÁ¦±  ÄVA‰t.>©ûåâêN!@€ª ºÑ7 ¤`An’‡3A:Ñ z™8 ùzÕUWIÐÌ`œPÅf¦‘w×ôßk›ip›6ån^–M’³ËÌߨ®kFO @€À|tnT§Iü˜Hó•e…'›5½–XÓ¯@m褈nC%?@ Z{öœ8ÿüÓ&ogŸ}â-lû‚=õÔS:Oú•¯|å-®q=zôæ›o–¦yüøñöíBÊô˜ ›®R-ZÔú¿×êÖ45­t}àÌLãY§×I¨ $IÀÞéö®_qºvõ\¬'ý • û|Ó÷OD·é™óD@`V·ÝX8p`Öõz¸B”Jq;pàÀ8r¹ž& 8°2yã¨i¯þºð›µTuÑŠ n‹¥àªèD7³e[xÕ)> @ k²q“¥›½ëM}[ÐΙmø9õMµX¢ÕÞrû¢[Û¶“g*i¼Ô}ÛæH:@`. °pÉ%a€…¹ Óõ¹:Rzýõ×êSŸ’ÚØ4$nrÔ´k‡Má>­´Î–ÜfÒ[P%[Îê—Z—kÜ´6-\HSâ,¥Ð ¨ äMÀ÷Õ·E˜™‹ §¾-Îjo¹ýÑ­mÛ½´-)ÒA`)ä¥K'LÏ8ãÔ‹ °°wï^©??üð4bOq8jº”ñ=F9¥šY´;gªÅ«ÿ“ä$·™³6Î\¹é—ÒÊÇ(yB€ 0 ·(Ú¾i%³Ó7ÝŒ’oû¶,«½iZyا ºµå©Õs½™›:qÁËÚæK:@`F/¾xâºëNënà6m:¡_Æ}Ù‘Òï}ï{hasà¨iÜCd¬ÒÙ:Û´6SÖüµµýÕ¦K U>ŒÇjò… LEÀ‰nî.¹-¦*ÈÊÏñE7w³ì÷IþÊ9rC;ˆní8Õ¦Ò2Úv¶m˜Å,oP[²€@zvî ,Ü{o´µ¼õÖ[u¤t.±‰ç::j*éSQ,¢í*¬½Áe•¦wzÕ9§©ID ‚$è^;©Ñá¹Ü@€À"E7[Ò•y–X–èæëøŸ¯û!ºugëKÚæºeAqLºW›;!*›o,Èõ[L—Bg*€æ}÷݇ò —_~YºÛ®]»bê&”¥;SÍ,>©~Ó–b^¾77Ûöí×Ìü­{ ¸€ ¸ ø¢[ @k€ÀõDTUq–nÅbËHË¡ñ Ñ­ [S²ç:±KU¹YÊvÑEqX⦰ :Õ‰ÞD1Œ€\¼}ô£Ý.ÿ€\I0Íù‹(õC”jÍD&µ¿²lM¢/P @€@ ÝœàW2U@HŒ€mÅ™ Ñj)~¥Ì.oqÅN¬ó ºµmPóŒ¨KKpNŽ´¥F:,š€ ÜÎ;ï´ô&ó·–§¯¸â¤f7Äuøðay Ó>òVü>÷¹ÏÉéÞÍNÓ0Û4½ÙÝ#ŽfJœ©lZaÛòÚâ'ø¶l– 4bétÕàI€ ŒIÀœºj°,)À,÷Wì1[r†¼ÝV€®Îj ·ÉÛØd®ÀޤX.X8óÌÓÒ›œ¾5X0©nÏžž•>xð ·ï}ï{ñëM”ÐÈéº[Ïn?ýífªæû41Í)q²_3(ú? ÌÙ°Ÿ¾Õx" @`Jø>›’vbÏBt[¹AƒÀºÎ“ËÊq °A€…³Î:!%®êÒ)T;—*gp=.Ù¸éT)ŠÛâäÅ@tkK¯èf[âÊÛm+I:@`%ûöP0S'®ý‹qâŸü“w>µ?)˜i»K/xàd$'*òÚk¯é¤ðÞ½{Ûµ?©&%°oý­‹v9ã¾—ôßù¾®gAK­4¶T´d< € È´1~7Å ª‚ËH‚Z£[Œ6µ‹ª^Ë* ¢Û²Ú‹ÒBñP´ùnsÒ[é·ÝÖXn¹Þ×BUb^zé%énO=õTc Ád^|ýíM5¹Íþ“ú¦_ªæÙ?¡köÒ&k@ˆ€’B IRÜüX õÆnçž{Béßy%ÉÝvÛIInÓ¦~üÇ%»ä'7QãS¬öª«®’µã€½,ó¬$®Ibsr›¤7 p™3¡ú€  E@_ý®´þŠP ¿¶¦RŸü»Za(häcݺô hmÄRè‚’{ I-×\sÍ·¿ým$¨œ |úÓŸ¾ë®»òëþÃ×XGGu€Ô?Ozõ7êéðO"G@€r%à¾ýÍÚ¦êR²¨é^}Ý_¥oDUò” ƒè¶Bk*‰N„9ßm·”غ+$) pℤ .9ëMÔ]tÈô}ï{ß /¼À˜èLàè['nØwTAœâ¦à ¡Ð9Cn„ @¥ôí/c7iXî²oÅßDÐD7I~9Íð­ø›¨JžRaÝÚ¶¦sÙ¦^«>*õ-ÂxÀm+C:@`&Y$µHpAx‚ÀW¿úÕ믿~¦ž¸øÇÞýÌëg?øŠ“Ûôó½‡^_|­¨ @Q(zu×yÌÀ®­ø›Ù«b¢[àtÞD7¿lÅßÌ^ò” €èÖ¶5í<©ôlùqk{é ¼“€DI-èM0ùÈGvíÚÅ(Y‰€lÙÎøU'·ÉÒMön²zã‚ @#@t lÙ"ºµme´¶¶¤HTxä‘G>úÑ¢7AÀ ¢ÂJ³ÅácoË_›ï¾mãî×ôË•2!1 @X•¢ÛªÄHï ºué :XªsÑ2Õ¥s¦èq] r2# ø —]vÙ3Ï<ƒä‘,ÿì¾IDATŸZÎ7?yL1IâvÞÚº"–¶¼—d€ @ D·>ô2¿Ñmµ }MÁбKtøtÛ¶m«åEj@ 'wÞy§Äzô&ˆ¨Ð8 lösw¬ûîÛî8p¼ñ.@€ ¡E7åøJ[ŠO7™fC’8t ÅŠ|ˆn+t *“ÛôÅU0K7].ž©~¹Bv$…²!@ü´¶DT¨š ö­¿uÑÎ#þyÒM}ñuΓf3uRQ@€@–{¸-PãÀ™W)ÝVhoSÜK¡xÏÚÚšIoØ»­”¤Ȇ€Î¡á _@x‚@íÙ<õÔSÙ ˆæŠJY»î‰c ’à7©oÒàšï$ @‚€Ìkô™?DN“æ!}PÒÄrUÂIaMò0D·¶˜õÍ\¥¸Y²Ò”*ßm›;é t `æ†ÖÖHc7ØrðøÙ¾âä¶szåÞC¯§;CP3@€b$Pz¤4Æ‚¾³L2m“p[<-…èÖ¶-¤¦iÔÕ§–Nÿn ”tȆfn’ Dc7M ;ðæù¿êä6ENPü„£Ø·e3[RQ@€@<Ýâi‹E—Ñ­mó­Ødk*•Í¿ßDåà—m@:@ Efæöꫯ¾ÎZ™»>ööÆÝ¯ùîÛôOý2ÅY:A€ °ˆn h¤%Ñ­m+E·Òè$ ™m)X‘€ÌÜ>ÿùÏ#7A  <ÝdÈ&s6µ9ÅMÆn2y[q¨‘€  I`¡Ÿö/² ‘¢[[ŠmD7ëßúÆn›)é ¤ `æÖFi"#ð¥/}é–[nIzL„•“³6¹lsr›\¹É¡[V¨, @q@t‹³]W*D·¶M¶aúõõuwCÑÒÍ‚-(¤-SÒA uwÞyçïýÞï!*A %CÖadiµ©Œ“õS(R$ur›•*\©‚–æPwê@€@üÝâo£E”Ñ­m3mݺU‚š^pù÷+ØÑKÛ%R'püøq (ßÿþ÷[ .$ƒ€è0ròæÒRÖ6=~Ôwß&õM\êSõƒ @`IÝ–ÔZ—Ñm…Æ1c7ÿÒoÜýŠ« ?mÛ¶m…I ¤Kàž{îùßø „$¬D yc·;÷Ý·»c}û³o¤; P3@€–JÑm©-Y¹Ý"kФBફ®Ú·oßJ‚ ‰! Òj¥Ø¦2N×cí¹7Î[[wn’Þ?!½jR#@€Ò €è–F;Î^ D·Ù›€@ xê©§‰ H«•b›Ò¨8|ìí»_óÏ“^ýÍ£úeJu¤.€ $FÑ-±«:ˆns‘ç¹€@Ê¡ÐAlâGà²Ë.;xð`#äè['nØwTAœâvþïîyéͪF @H›€'Ê…Ôë¸{÷î%;Õ2#ºµmYR°8 õ—¼¼ùNÛæN:@ -—^z)!Ñ:PÐ[é¶K÷zýÿßÞ½ÅÞ]Öû¾çÒ‹}a².–ÉÚÉöb™m².–ûÂ̘½›ìÄÌÄf*$k¶É†¡Yb—ÂJ­€U°ŠV¶8­"N‹+‡ªø·`¡ò§JA(VÊÁRKÑRÅþÕRþ)mQèþÀ×ùôéï4~çñü~Ï{¤!eôwxž×ï0~ã3žÃ[î:æâ6ýýæg_z¥(? €D( Voú¦¯L`XuWú¦’«ÿÍ@ÓÃai畖ЭìqTÖ¦ÙK˼ȕ˚²#صk×G?úÑÚ +" ÄV¹íp¯µe[tÿK.nSK7µwS«7^ € €À\0¬ kÿþý*°…úËÊ•+õÎý]fB·²‡Ï¸)Ps/åÜ:wõßÄ;„neMY‘ ¬]»öŽ;î 9B ‰Àe—]¶gÏžÁ]"Ï¿òšÆkó‡o{߮㓷 îHR`@8K@q•B«!fXjæ¦Æn®äŠ56lØpøðap?„ne-tó—V¸¦ÐÍØÒï”Ý:Ë!€ÀXN:µxñâ—^z©Iàº(·Uz;¬ËbýÓ'5'©KÜÞ>· K‡UJ‹ €ØWþ!fX¢ÎšéYú6гC<9 ÝÊ5B·²R,‡@Üsss×\s¢7^48zô¨z˜j ƒ¸ž®)bsq›¢7pƒ(9…D@Ê øílü¶oágXºYMý¶oÃê0[þH…³$¡[ÙcAèVVŠåˆ[`ÕªU<ð@“´…u0¥·Êp¿žÔuTHýþ¤3OœP'ÓÀ‹Mñ@@™Û,òæc5¶ÙÏ*~èæöhÓEªä‰^}ý)’½º•=Єne¥Xˆ¬o©¦0&6B ¹ÀÖ­[Cîaª‰®xò¤&Ip‰›&OÐ ߨ: €Œ\ º©½›ßg3Øú§C7e…š’Õz›ºuwàÝÊÚ¦C7­™˜3Áfäe"…²¦,‡Àè4o©Xmž¶°$ò¦7?ûÊ[î:æâ¶·n?vûáWFwAS!@@à,º¥çUPô¦+X/º%æU°YM™W¡»GèVÖVg!'bY,–C VÍtË-·!Ж€žÞ8ÔõôàŸÿúÎû^rq›Zº]½ï„Z½ñB@F/0;;kÝHõ_7AÈY›;"JÖ%×s¦¢ÃѲ©WЭèèû³^S?H†"°|ùò'Ÿ|²­À…í ðå/yË–-œÿó'_»ä±þðmKw¿¬7)Å@@:Pû%êýæ¦þÔß5 ZG»kq³éyêR:ˆ”°E„énŠÐ­È?³Két{G`4”›t#'B E=­^½zêç¼²}î©“š“Ô%nïØ± &oS/@@zpMÛ(}J8ë ëZä "%ìáhö¼ B7B·žO9v‡ÀhvîÜyÕUWµ¸°)Ž=ª$wº×̶?þåís .nÓPn×<5Ý"±w@@ Oølp1º +%ìó˜ö¶/B7B·ÞN6v„ÀÈÐŒ¬ )ë¶oáÕ¿ð¸ßŸtæ‰Ï¿BÒ‘ßʨ € €@[„n„nmKlØ–.]úÛßþ¶‹Ø…mÆ,ðo|cÓ¦M=_]JÖ®xò¤&Ip‰›Ò7ep=ƒÝ!€ € 0hB7B·AŸÀPæçç—,Ys6DÝ;øùÏ>33Ó牮ޣêCêâ¶·n?¦¦}€}!€ € hL4›K¡à`±U¤k¯½¶¸äš]!Ì’ T„n„n#8©ÓضmÛg?ûÙŽb6³€› £‡³\s#¼ó¾—\ܦ™4‚fQà… €D. ÐÊMJ0 ÐMãйW ŠMèÖÝéMèFèÖÝÙÅ–ˆH€ÝbÎź®{ú͟|méî—ýáÛ.|äe½Ñ5LU@@Í¢ ÄMÉÔàæR°¬PåÊŒ«ã; ÝÝÆwVS#¦ °zõê{ï½÷$/:Ь¸š·£ÓZ ÙԜ;MÝÔ䭣ݱY@@`pj#¦ôjpÅVD¨ÄM?ß®äc*0¡¡Û˜Îgê‚ÀÔ–-[vàÀò6‰ÀÉ믿~óæÍeN¯Ý~ø Ùæ¸i(·M‡N•ÙË € €‘Xt¥aÑW_õÅQÉwïÞ=¸’©À„n„nc:Ÿ© ÓPïÂw¿ûÝ„Ct$ð½ï}oݺuOn%nïØ±0q1[@S‘.ºÿÌðmjé¦éJ5iiÉÕY @ˆD@¡Õ@C7…„nS?K ÝŠ‚a½¦~(.pèС .¸ £À…Í"ððÃOœÀTy™Ú©);›8ï–œyâ„?|Ûß?xüàq¦Kü6Cñ@@`: MÝK5,Útvß`¯šnU¡ÛŽ;lƒU› º5d}@@ãmiÔ-²!:˜ŸŸ?ï¼óŠ/´Kû[Ž¶ç…¢áØ®?xJs’ºÄíís U{¤r½#€ €± h@7ånšS~X·¸™I§{ÔÝÊú+$Ö•6ñ¥zp—bY–C·¥Q·: \Ø,X¼xqÁ‡ËŽ#q9ZÞ lZFOÝbŠÞÖ?}’k@@`¢Àì쬚Œ) PO8õ6-xMÜTÏ ¸yWh{p³²öÌØdw„neõlªÝ2/Æ),kÊrŒE@ãmiÔ­ð³¡ë®»îSŸúTøåŒ³„?{ã•WwM;¥™:2¯õ'õ'CXºûåÄbó'_{ß®ã~R5‹Ó›c¹þ¨ € й€ÆGS«±â@@ t^Žê;ÐcäÄcˆs³V—˜Î„neÝ­[qªm]¦ ÝÊš²cX±bÅ£>xT¤@Ç>n‡˜»=óÌ3Å™Tàø‹7ñè\sÍ5sss™WŒ&@ð5 ëæ5åqWï;¡wÜš<¡¸ÿéX.Jê €´, Þšjé¦Îmyà‚íÈ©†l úí)˜k‹Íý‡¡[ÙsÁNÐâ¥mZB·²¦,‡ÀXÔõï¹çž›¬üÝßýÝ}ãõOÿôOn}‰±Në{lqƒ¢³ÄpÓ¦M-n6œMM<:꿬^Ìé+æÁ?ÿÕOÜìï Ú´äÍϾ¢©Ü¿êïzg,×õ@@@`„ne¡[Y)–C >E‹MŒo”¹vÝÊÝ&._c'žxBÙ…e®;1Ö©±ÇW).¼ ÝÔC¶ÅoªÏ¶uÎÖ­[×®]›¸¶ÔM3!¤C·ÿ´íØÿ}ÿKî}µtS 7qVÓø.\jŒ €´& áwÚþFíàÓ­µó µ!B·²¶j):±‡6ÝKËj²#8zô¨î“ ÷¾÷½ Ý·Yô¶}ûö‰«T]À6®|jˆ¡[qáYª^2,Ó¢°ª[\õB7EiéÄ-ñŽFs;xüÕ]pT@QÀ} ±d“ÊT¦Ñ¤mð﹄neO]Bú6[«#ô@/³² ,‡)ùùù%K–=j}f¡’:–Ú_.¼ðÂV²!##ÝZ·š¸Á‰)ØÄ-TZ`âîî¿ÿþU«VùgŸ†fókK¦o³/þ·{4c)—, € €@„n= q„nešMT V02âŽ;ôE:Ø¡ËÖ“å@ ¢@™ÐM"­™›Ò7ë)ÙESB·J9׾¥}Î;11t{øá‡gffüsó;2:–úÑ›æL¨x.³8 € €@MB·špc_ЭÂ^¹r¥¾ƒ©í¥òµÄjnþàô?UØ‹"€ÀöìÙs饗'8´©w¤³®xNõ¦Ô£y£³i ‰¡Ílô1ºÙÿê¥Ò\ÁÒ±ŽíE/m-o_nu- Åly½ ºÇj1ºƒ‰{)Sxõ*Ml6®šº²TG‹ùµÈ\ÒfJucð©q¢óÌSruTÊLõà/oÛœºiz\M’ë®Ï=uÖŒ¥yLmF^ € €] ºu-<ÐíºU;pjÈfß–ÕêÍz>ë/zÙ;Ó­ÚæX†/01ts}K-Žqÿk\æËâ3%8éM§3ZÌMÑø‹ßžÎ_ñ»ßý®›šÀVÑ’i‘:úÑèÜ.´m3QBÛ‹íW{I¬•ÞKÉ»ÅÒ{”§—ç¿´£D^¥„‰*»Š'&“Í\ÌN—§‚¥e 0…œ6ÑF&†n‡Zºt©].û^-êXúƦî=L‡¡ € 0eûÖ_æ5傞½{MìP¦ÌÖ´(¨’©0„n•¦’µDÖ¦óX£¹1ßGeJV@`;wî¼êª« Zº)Óq9”-æ&UÈk9U)t³lËrìõòC"ë¸PÉð3¦ÌöknÛZ“¹ N[ðÓ¹[zß5è+ÞKÉÂç…njç*îväÞñSK{Ó–±Z¨:nI?p´q÷üÍ:ÏD<'ÆÙ6ݘ}™-UY?²ôñrfÒ*X?tS¿Ñ‰ó'¸Þ|ç‹·~e—•@@¦# Æ7Öæ¦àeñÖtÊ—³We“Jý·†D„nÝ8B·ú¶åm Sׯ3k"€@J`Û¶mjL^ºY|ã·ks]½DÝF*…n‰µ&Î^šn׿²tã;K Ó’ëÍšXÅE{•ö¢*X•ó Ÿº¹Ø+Ѯ͔%B7ýo"åôûäf6ÙS‘òR0— %v­0oØ>—¬ùŸ‚N?0ÍÛŠ·hÑ"}×qsKª;*×. € €@wt/íÎvÐ[&tôá£ð 0}âÐM‘JfhUœ1uºiãéNš®!X"{²÷3çZuAXæÈq•öR/t+Uþ5qj×ê°jèV0!†;è~¨ê’Ö4¦Ëþ 2> ݯб4‘Í-Ýýò‰W§½P@@`”„n£<¬Í+EèVÙP ÜÔÃTW”5ÔÔì 6l oieGV@`ê¸÷ß¿ÿôÿuËãX8‘™ïXS,%P‰uÃ%ºgÚb†n‰>’¶G×¢Í/ˉ2»jIËýhɵt+¿¿Ê•Zº¹z³:L Ý2£C×O6/sy_f5Ýô›ºFy™Gܵ›+hé¦~ ÿï}g׿ÇjoÝ~LÝNíÏ…¼¬)ìϦC§4¬›ý™?ùÚ(.;* €'@èÜ! £@„nÕŽƒÆn³iÒ/}RWms,ƒP–¡˜Ã¥Û¿œ™ï¤û–Úbþä˜é; Ý2cÌþ›.1Ìk2–.gñ„ó!Ôè^:qh¼‰‰›È+RqEÜáSX–¹kçgˆ-ã&f|¶‹÷^ø?/ÿùu/u!šfTìDÁ@@Q ºêp¶WB· –jצ/Q6m‚Z·i@7½ÔêMÝܦ4y«Ê¢ P@ô”zøq›r·ÿ~Ë/_ÈÊÜŠ[Šåõè캥[ùÐÍŸrÁM&àÿÅ~~ð7ØgèVcefa:"Jµbº‰.·%+’ÉâÆhóC·âTqâ쥪Ž~Ú9zôè/ŠŒ €D!0Ð4@‡h?ÔÝ JèVÖVáš¾[*w[XXÈ\G1œЗ¢²[d9”€â¶õOŸ|Ë]gZ·)nSW¾Ïßù@ÞD ®©ÍS™x¹h&Ý;2–nC7‹œüÖ^%³ª¼Aå*u/­ºiyÕ±è°ÝÐÍdüΧÍC7›H € € E€Ð­ì‘RܦælŰZÀé›Û@ãí²,‡@|Ï¿òšÆÆzó/úCh½o×ñÿüWaL¤àÏJ™Ù-ÝÞL¬Tè–® Ûf˜¡›‚MuIÌaZ¯{iA?Ù<B·øîÔ@F" ¶56¤{ñ+´&8Š&b”y…Vò‘œ7oTƒÐ­ìÑÔ™ª ¬xiõ6Õ÷g5y+»Q–C°4ðüÌɸM³@îyáõ¸Í^;wî¼êª«ÒQ‹æ_Í”Ñd¾Šç ͤ¿ Õjëd¦H™³+”ÖgèV<…_NW‘t£Âz¡[æü¤Å2 ÇtÓ°z‹/ûr¡t € €À8òvOü¬®Å‚ª¿ŠtâfeN¼OèÖÝ#t+k[&tÓ¶´˜:š•Ý(Ë!€@¨¿ª¸íM[ÏjݦI!õ~¢È{öì¹ôÒKÓK™ÎnFK5æo¡ >s!Qzh¶ÖC77&??i8¡›‹5'¯àXÔ Ý\Ó9~Òbw¬3çZu±`Þ쥇Zºti¨— åB@Æ,`ã¹û/ ì®èJƒP%Þ_Áúð…_ÎєЭì¡,º©õ¦.y"9t[nY=ª–°~ð¤æK–§¸MÑ›r[Ø5Ërm ôŽŸÑè­5œ-ïš³ùW ä‡>~Hdi^™ï´5û×DNd×*‰8ÉU0Ýü­É^ò o ÇôòÛºŠËÙ_Ñ0ÓŠ¾§nת‘R9çŸYqE¢þ!Ðÿ¦ƒÎÄf-¡Ó›™Î: ‰”°ÌaÕN5_ǪU«¸b( € €Àßz¹Ñ½”Sa¢¡ÛD¢³Ðp‰nâ›ïõh` …j”,À´n?üÊ;ï;+n{ëöc×ns5X´hÑÄmõPT¤˜F¯Ì°)o›¶JfŠT¯.´-W-O¥Ö.¼+[Áîœg%œ2Uv{/³e-Sf›~E~øÃ®]»vÚ ûG@x]€–nœ%ÝJBYL Üt©½›ÿR7køÆ ¸ùÙWÞ±cÁoݦ¸mÓ¡SµK¾xñâçž{®R´ÄÂT¸ùæ›iI]û eE@@ ‰€Ãø/õtQû5Êñß íiME"¸°Y¬ŸÿREšø°n¡§D$ dMùš·)}S“·†+V¬Ð¦•2F ’À¿øÅÙÙÙ†'*«#€ €Ô𻸹¾né¿h±ïnõ~-(­ÿO àº+Fä[&t‹ü úD! £¦Mƒµùq›†rk·ߺuë¾ûÝïVÊPXJ—\rÉÞ½{£¸\©$ € ˜@¢™[ÁÿVðÓÊÝʼ4T}h%MyÝÊJµÌäd-‹År# éG?÷TFܦùZ,ãæÍ›¿öµ¯UÊPXJê );ZFaIÊ hÄ@Xù¤d@@.ݺPé6 ÝêØÙÙYèMq›ú–Ößk"€@G ‘Úü¸M㸩átoq›•}õêÕ÷Þ{où…%(/ 5n`ƒ«„U@@Ú tkÏrô["t«sˆwìØ¡AÜl^…‹/¾X›ÖÙ ë €@3šˆÛÞr×1ÅmšB¡Ù†ë¬½qãÆo¼ñe^t  5n`ó’u@@Z tkt¼$t«vl•¯)e³¸M¹›Ò·jë³4´!°íYtÿK~ë6ÅmëŸ>y¢ó¡ÛrK¿mÛ6u0ï oa“± ¼ð šºôÔ©Sm\:l@@ ±¡[cÂx6@èVáXû³%·U€cQÚ¸ýð+ïØ±àÇmoÝ~L“ïL1n³ÊÍÏÏ/Y²$ö|ˆúw ðÐCÍÌÌ´w ±%@@f„nÍü¢Z›Ð­ìá¶þ¤6|ÛîÂWÙ-²TP²öö¹³â6ýoPs]/_¾ü—¿üe© ›ŒZàºë®Û²eK•k…e@@º tëRwdÛ&t+{@m΄2/%re7Êr 0I@MØ”¬©9›ßºMÝÔämÒª}ÿ»æ2þÎw¾u>Då;¸è¢‹8Ð÷ÙÌþ@@òÝ87J º•¥Ò\¥ê^Zæµ°°Pv£,‡ùŠÛ4L›kóã6 å¦ùÂdÓü’še²ƒÔ…MÆ+päÈ èæ O©@@HÝ"=ðuªMèVGu@ ª€&!Q×ì’kiúQMBšˆÛ4Qi°q›ÕKû{Þóžxó!jÞÀÜÜÜêÕ«K^8,† € Ї¡[Ê#Ù¡ÛH$Õ@ XÍ:¢95¢^û÷ï/.çüÉ×ã¶7ßù¢ßºMqÛžþlý‚1¬[¹SÔ›d@·A\ø@â t‹ëx7ª-¡[#>VFÅmnånjìV°°â¶™'N¼iëYqÛ…¼|ðø«BfX·¨²*Ï€nºü)* €Ä"@èË‘n¡ž„neÕ3ΚêL|MlËSv—,‡À\ܦ‘‹ë¡XMáš·éï—̺•=n„ne¥X.·éÒP”¦p-s 7‚ÅmŘŽFNãp)1i·°*Ç?üáïÙ³g4A@Æ#@è6žcÙyMÝʧC7E ÊÓ­¬ ËBÀR3üքͺŽê¿ú_ׄͯ¨5vÓ•IÜfuWV¢Ä„ÜÚ¿ùÍo–.]:Š{•@@F'@è6ºCÚ]…ÝÊÚªÁŽ^ÅK+‰P ‘ÙÞ§ìnX€¬‹¨r4ËÝü’Z{·ÌdÍ»ÙZñ¼4׳Ï>[;saÅÈn¼ñÆ7Æs½PS@@`H„nC:ZS.+¡Û”»G`@Öl-3}žØØ-½–¶6â„Z‰‰r“È“#ª_[àüóÏ?tèЀn@ˆH€Ð-¢ƒÝ´ª„n ¯»îô5לÖy!€ÍRšÙlÍæIÈlì–XK«[ó·‰­G‡ëªÄD¹IíÌ…cøÅ/~±bÅŠážü”@¹¡ÛÈp›Õ#tk ùÖ·ž>çœÓú//F'×ÔZ´e†eê|š7²›[ËÅmŠçÒ³ŽLqùòåO<ñDÌáu¯'pÝu×mÙ²ed—ÕA@Æ#@è6žcÙyMݺ5ÀcÕ,#Ë Å †o³Æn™U³Æn6©Âèã6Pn¢ô¤^ìÂZÑ <ÿüóšBáèÑ£!ß"( € µ¡[Ô‡¿Zå ݪyµ4¡[ÔfMñ™š­ù[Áü¤®l­á ZºõYµAìË»ýùÏ&tB OàÇ?þ1ÍÜq9SH@@à4¡'AiB·ÒTé Ýà±j?JÍÔ¢Íò5ånþNË„nZÞÄ%Z´©WiAÏÓ~ª6¬½Ðظ­X€fnú¢)- €D-@èõá¯VyB·j^g-MèÖU»°¸Í¦%UWP5vKì±dè¦Æq6½©2;emz©›­›9 [×õèöiìFèV @3·^×@" t‹ôÀש6¡[µ¿­CèÖU»ÐJÊåíÈ"¹23X»6-ì^Z7âu]£¡oãÆ›6m"{B ! ~ÇK—.U,;ô3œò#€ €±ºÅr¤[¨'¡[DB·x¬Ú…€ú0ºM±æiy;²Šg/õ×ÕÆÕbN¯â¹º¨×8¶yêÔ©eË–ýú׿&uBÀøêW¿ªy6Æq’S @@ ›o>}Î9¯ÿ¹úêaÕ÷ê}'ÎùÁ ú³éЩa•|¸¥%tkpìÝà±jëj¦M¡˜Û²uM4Ió›¶Yûµ¼ÆnÊãÊ´ƒk½"#ÞàÎ;¯¼òJ"'œÀ¯~õ«åË—+ñiOÕ@@± lÚDè6¶cÚY}Ýк5ÀcÕÖÒ¡›8¿±›þ7ÃYc·ÌÑÙÔDNÿ4;;Ûz9#ß f¨Ô^¤N˜Àå—_¾k×®È/ ª € L€Ðm`lšÅ%tk OèÖU ¤‡T³Mó'ø[v󖺿$V´pMÿêæ'u30tMmXø˜WgFâ6'Àü 1ß ¨; € X€ÐmÀ¯ï¢º5'tk€ÇªM”¯Yˆæ·D³vm‰EíMkï–7õån½Y‡S›ð´I Y·@@xi/²§È˜?» € 0TB·¡¹)”›Ð­:¡[”G²B·’Э«–pq[ÁˆlÚŽkòfc·-,,$6n£¶Yc77O·•9Ý-£N¦333ƒOÇ‹WTëׯ߲eKw§[F@èV€Ð­[ßQmЭÁá$tk€Çªe¬…Úþýû'.¬ìÆ&@°ÿ&ĹÆnjÝÆ< 1{[`~~þ¢‹.úÃþUäye™±´·ë‹!€ €] ºu%;Âíº58¨„n ðXµŒ@ùáØ”²ÙÔ¥nºÒD×QkìFë¶2ì}.³sçÎ+®¸"ò*žêÿú׿^¾|yº-jŸ§ûB@h*@èÖT0¢õ ÝlB·x¬ZF s8¶›nº)=›?uib‚·#­Xf§,Ó³€wûö·¿OðmM=ÊPn=_\ì@èD€Ð­Öqn”ЭÁq%tk€Çª%üáØ”šÙt¥ê%šXÝÝìŸlE½ÈÚJROk1w‹$†c(·i]bì@hY€Ð­eÐ1oŽÐ­ÁÑ%tk€Çª%\c7¯-sS±%F›%q+é<ÝÅÜmô¹C¹M÷cï € €@›„nmjŽ|[„n 0¡[ùÉOŽ>{г‚ åÚåFy@@F„nøâZ™Ð­Áñ&tk€íªÖETí×Ê Xc7­U° ¡[yÏ`—Ü´iÓ 7Üg,5âZkvZMž ÆŒÁžx @@ š¡[5¯¨—&tkpø ÝàE¸ª†]³.¢UC7YYc·t_QÞiËéÞ"Dz•×­[wÛm·8Š­jš«‘»Ïå h¾Ë™™™§Ÿ~ú¯A Ü~ûík×®åÄF@­¡Ûhmû#tk`JèÖoL«ª]› ܦÿ*Y³–njòæê¨pÍ»iD6šMKÖ›QaLnÔe¢À¡C‡ÔÞÜm@™‰Ûijš@@Á º þöWB·Ö„n ðF³ª Ôfgg *e݈ÛFsÜ{«ˆÚ»-_¾üÑGPðmQo¸áÚ¸õvi°#@@`j„nS£ÞŽ Ý3B·x£YÕZ®Mœ™Ôesµ+ž'®övXqpMýL5Ÿi´aÖ *þéOZC¹ îì¢À € €•Ý*“Å»¡[ƒcOèÖo«Z”¦Ü-³:úWÔ6kìV£W©×ʨã`°ÊÝV¯^½}ûöAÄO±ò¹çž»âŠ+¶mÛá™I•@@Ýb<ê5ëLèVîõÕÝàcU%h™Y˜²6ElÊã4v›«©Fy³î¥‰ºk¸¼$Ž1àÆqž´R‹S§N)wÓa±EZ×Wý?ò‘ìܹ³•£ÌF@@ @è6€ƒJ Ý B·xÃZ5¯k§ò²Dè¦dÍâ6{%zžZƒ5±¹ OµJDËØä ZebßÕaaRÚ&2L‡žCÅS<Ít¡ž¿{öìirLY@@``„n;`Ó,.¡[}B·xCYUmÖ,üJçbªÂ† ôO+W®tÕQ@¦¬MišÞÑß-5óÿÕMrj‘\:S#nʹ1­rjà°ÏþóêÒO¶fM5»…æ–=pàÀ´Îö‹ € 0B·é¸r¯„n ¡[¼¡¬ª6nŠÆ, KçnÖcTÿšWô4 öN^6ûWZ· åô˜V95Uî>ð'Ÿ|2Ì4*†RÝzë­JÜÔ·tZçûE@˜š¡ÛÔ臷cB·njЭÞ€VU¦¦¶lyíÝìý¼AÙÒݬÿ©þ›) åóþi@bµ5°RèsÇwÄpUGmŸüä'×­[§Qöz8Ðì@@ 8B·àI¸"tkplÝà¸jb²QWB7?ifîfs)¤§G°ÕmzÓ‚¦p:P¤¡hJÓ5kÖÐÕ´ÏHκ”ÎÍÍ å$¡œ € €í ºµo:Ú-º58´„n ðB[UmÙ“ú¡›ËÔ2s7ëªRÄæ×KÍÖŠÛÁ…†@y†(@WÓÞB7ëRªÉ†xžPf@@ÖÝZ£ÿ†ÝcB·xA­êÜ–î(ªàÌoªæ&õ«`oj1uÕ, zY§wòzž%@a-@WÓ®s7º”ú¡ð € €@Ë„n-ƒŽys„n Ž.¡[¼ VµÐMyYfc·D覒[Ä–èRjmål’À%Ú¾Uk 3&ëjúéOú™gžy‘W«<ð]JÇt±P@@ ©¡[SÁˆÖ'tkp° Ýà…¶ªò2×133C—Ò.êˆ €” t++År§ Ýœ„n ðB[ÕB·ôd£*§ÞWË5ýÓ† \ßR ¤•ÙÞ-´zQžØÔäM'êûßÿþ‡~8Þ´¬šó›ßT‚Éœ ±]AÔ@˜,@è6Ùˆ%þ&@èÖàT tk€×óªjûc½D­Ø\1l86ý¯Åæ/fó“Zë6ý«ÿOän=GvWRÀFy£·i½ðMýI·mܸQ fIpC@¡Àü|v¥&†nNWãöï<þjº Wï;qÎ^ПM‡N¥ÿuß«Ûþø—é–||{'tkpL Ýàõ¹ª¾9[dfÿÍœÙÀæ–nìf#¾)_Ë ìé)\ŸÕa_” ·iÕÐþ¤%O-C@¢¸ýöÓúÖõÕ§!Z^è¦nýúÓoûëÿêK¡›’µwÞ÷ÒõO=ÿÊk®,™¡ÛüÉ×Ö?}òís ZeÏ jÁG¸sB·•Э^Ï«ª›‚37×A:wó§PH4v³ÐMëö\fv‡@sëmú|àî»ï®š@Eµ¼æ<ùú׿NÒæ§[@@F%ðŽwœ>çœ×ÿ¼ó¯§oJÓ4øÇ>ö·7ÕYJÿ{ýõ¯ÿÓßÿýßÞ|Ë[NŸ81u„wìx=DÓŸ7m}qÑý/éÏOžüvþíÍ÷>ôÒÌ'ô¦‚9[LÞ·ëøÔ‹=¾º58¦„n ð:]U®)Dó“5×~M šµwK4OSC67+Bº±[欦V#ТÀÞ½{W¯^­ÞˆÞÒI¢ÅmK—.Ý´iýI[<ëØ € 05v³Ð­üŸi7s3vkìVéÍܺ8c ݨº5ÀëtU}‹NÇd®ýšr7‹Íq³—ºÙÿj ÚŽý+¡[§Ç‹÷# ÞˆÞüÐMI¿ò•¯·õsú±@@`¨®±[™Ü-ŒfnFí»•‰ÞhæÖÑùIè֖Э^׫ZÒÌÆn.eós7KÙ\©lò—ʺu}¼Ø~o½þùßÿþ÷£ê@šˆÛÖ­[§¸móæÍ´nëíÜcG € €À *5v £™›9WjìF3·ŽNNB·°„n ðº^Õºˆº£¶»Ä`m~{·D覅ýÆnû÷ïïºÀl>:´víÚüÇTôväÈ‘xÒ7eŽ·mÙ²åÔ©Œ9›ú< ì @@`%»…ÔÌÍ`K6v£™[wç!¡[[B·x=¬j[Ac7KÖ,›K‡nÎïÚCÙ= ÌÏÏ+z;ï¼ó>ýéO?ðÀ#ŽÞÔUüÖ[oÕ„Äm=Ÿcì@ƒ@ÉÆn!5s3ö’ÝhæÖÝYJèÖÀ–Э^«–iì¦bXGT½üî¥=] ˆ€úWnÛ¶mffF ß4Æ™f]SúvÇw|âŸX¼x±¸©j˜S @@ Llì^37žØØfnžŠ„n x Ýàõ³j¢?©vš¬ÍŠár7ͱÐOÁØ  ¨á›Æ8[¶l™F|Ó•¢y†›¾=üðÃjħ¬mÍš5sssjS$@@! Llì^37ãØØfnž‡„n x ÝàuºêüÉ×>±ïä‰WO[c7Eoþî3“Ú?­\¹òÚk¯í´Tl¡hÄ· 6¨Û©úcþÛ¿ýÛ®]»^Âë÷¿ÿýÝwß­¬M}HW¬X¡âL’0”SŽr"€ €(hìj37S-hìF3·®O¤tM) {ê©§Zl §†lÚæ÷¿ÿ}Eljj§iJý4íæM›˜aô'D@ÂÈlìv37ÌlìF3·Î.B·úȯü—ÿrúœs^ÿ/¯) ì8ò—E÷¿äÇmo¹ëØçž:éâ6+ýI§t|ØmêË©>§šAíà”…i<5åbjƒ¦€L â–¹—†‡S‚–~é õÓŠöR+6½´M Ó¦ˆMMí´£(L©$ ðdS·>î~œ €@@‰Æn4sSÝù[ÿ9ÑØfnýœT„nÎö|£ïxjÊ¡ï{ö²6þë7ÿù?+tûíúO‰÷Ý*ú‹¶ íhkt}j÷„VNŸŽÛ4ˆ›&OÈ|©±[¢‡i»åak à èA÷=5ˆÓ н4<œ{tWZç/f_/õRŸVT@± $~±p·DýØà?XjFiû§ÄÓ¦:û»U4M³ý2Ñú׳±âS/@ ‘@¢±[•fn™QCÞM>Aèwó·Ÿ¥5ÞKù¨!ÑØfnNƒÒ+Ǻin;}µÛ¶m›ÎW ¤'=ÓØóÞÑ€Üîë_ÆsŒÚ\ÌÌh‚Ì„¶[EÑ´m-sË̬WúD=³ î‰„þ­Ûm:ė󖬂 € è'÷;„æ{±/Qj¬çCý¡Q)ýGÇ’¿7X#{Ù/y[Ö˜× €± ¸ÆnùÍÜÊG å›3ÛÛö*1ò¢÷Ušfn½³‘†nʃmJ>Ívçú.U ‰ë¡D°­½+ŒSI´ë’ÏXõö;޵”¬)_ó;“ê–q󳯌£vÔ@Æ$ ¯Fêz¯çLë)ß[{´D:ƒ©Ÿ“Õ¦XMáø¹wL'uAi ¸Æn©fnŠÃBŽ\c7š¹õvþDº¹Gýº¨Fmz ¡¾~¨TIT{ chðô©¯£×LÆmï¼ï%Ý/z»NØ € 0Q@Ïuj¹¦Fgz®Ó»úÞU¾ýÂÄ×^@?úZ©ø¹·¶!+"€I5vûfn5èK½¢}©0jÐG’ {¥Z¨å ÍÜú<ŸGºé=uð´H+œGŸ¼¬k@W‚ʩҪÌ*yä?H*nÓ0mšÁoݦ¡Ü4BŸ ûB@òÔYA<ÕMmÊÔƒÁÚ”Ûƒ!ñs¯Â8µŒãà"€T8qóÍû>ðû=âu_«º‘Þ–W,hÃ^)jøŸ»áºÙ9è ´¡›=ýèÐTƒë¼©5•Y%WùU Õ¥·"iúÑ«÷xó/úq›òøÿü×@JH1@@ rý\ªq¬•µÙÓÚà¾À¨üŠmt9 ùo½‘ŸÌTÊ è—û¡åŸ?ó™ÁõÜwQƒÊ¯ÄP^ÁþJTþˆ¾äØB7%¸.«ºçž{^þKµpéaýa»>¡çO¾vÅ“'qÛÒÝ/Óç¼ky¶ €eÔ[S-,«úÑ~tìØ±¡?o>òÈ#.=ÔÈ2,ƒÄ& –Š,«Ò—ô“'Oýæß}÷Yz¨€Cë5’ÐM ãÕZRO?jØùƒü`O?‰ X5R½T;ÕQ5eG€ƒÇ_yâÄ›¶žÕºíÂG^Öûc½ü¨ € E@ Ù4ô‡:j^‚oûÛ‡ú×­DùõR_#õeR_ÀôÅRÙâP åDºÐWoѦ;¿îÿúJþÜsÏìæ¯¨A? ég$E úIi”QCw§G™->tSÞ¬\Ö¢¨ñ=ý¤¯gÕÑâE=©îeŽqøË(VS¸æ÷$Uô¦Ž¸-ücG @½€¾X7LEQO=õÔȾn¥«£¯”úb©o˜úFۇџÞTòôÛƒE Š¢žyæ™Ñßü5è'¥‘E !œÞÝ9)xRÞ¬\vô@º‚j ªºK`ÐCê4ª®£~ܦޥŠÛÔÉ4„˃2 € €@ÌŠÛì×m·Ý6‚žDU˜ÕíT¹›zZÐç4æ«€º#¡€E úí!æ¨AS;:jç¼dè¦c¯'EN žª>=Œly ˆbˆ¿CjJMŒˆÛ4y‚¦Pçò $ € §€ëKç7.ÿù—¿ü¥ýÎáÔ^qžüÔ˜5بᡇ²¨!äYYq®,tÓïlvàõËÛÈâ³&Õ™Êïµg6Øqä/‹îÉÛÞr×±õOŸ<ÁÐmƒ¸gPH@F-y_м'Rõ«ÕxÛjô§yNG}ü©D*`-{ô"nó?5¨É›RHš<×¾0ºiâN5nWêLÜ–÷0d¿CJ©‡IN5ÚÚÛ窞v·~å÷·½uû±ëž"n«*Éò € к€:“ÒÀ¡øg`øcýmùöÕúéÇ@`Zú­…–=Å7ýîbŸt8­q– t[XXаµÊ’*5iɺR’•ÄäVã„(³Š22ËÎÊ,lËÜüì+ïØ±à·nSܶéЩò[`I@@ #S§NÙät4p(óÀ¬èMß¾ÔöIî::!Ù,ô# ¯Ìš$AY-{ÊÜü½)ÔO/šÎ»Ÿ4޽„º©»€4ƒR™“€eœ€Í9ÕQûÿK;añY™ÙE•¬)_óã6¥ojò6Žë‡Z € €ÀÐô»½¾qé{W„S%4yxÖp?zÚTX©ÈrèçåGÔbW71Í×ÙäNáºêTn³³³ž3õªnè¦ zÕbK1ª¦-ðTn^e¹IO†’¬wrd®¥Í%hš !oËj §aÚq›†r#nkñX°)@h" ßê5N™~·æ™gš?zE¸Å”ÖH„a¶›œ‡¬‹= è ²ÚêªÅ.QC½O®cÇŽYgĶêùÜèbw!†nú¹LŸßJOéOZïHL8%Iy¶ò#ä¾…Wß´õEº©Óhú¤Ôô£Ÿ{ê¤æFð[·)nÓü ]œÁl@¨!°eË=#ÝsÏ=Í·"ß‚"K}}U|I‡£ç!« €@ŸúR¼iÓ&ýT ¶º‘ߺ›Wß¶Ú°aCw[õynt·¯àB7µð×à¬4òl~ ø[§TŽz¨4-Ñrméî—ýSS \½ïÄ›ï<“Ê)w{ß®ãµç9íî¼gË € ­€Ú8è—¾'è·úvŸ¸bÞšâËîÆ6‰ö\¥â Т€šeé6¥ÐÁZü´ºí¶Û¤J{ç‚5¬ÐM€ZøÓȳÅkÀmJª²U“·Ú·-Åg~ã5ý]­ÞlâÑù“¯Íwâĉ.Ÿ¶bß¶š¼éióÀ£<‹¨ N@_~ Ýpà ±ß;®¿š¼)ÒaVëôD覶ˆ6Moǧ›]à‰'ž¨ÚþSñe&n¯¿9{¦3©â6µwS«·Á݈)0 €Œ[@’ ͹Æã`”6sÛûš¢v BÀæ§Ön=ÜúØ…¢ikZØAœ½rú¡›:<~ô£=räçho/¾ø¢ÌK¶ÿTˆ–˜á¬îÐMã¸i47â¶Þ®[v„ €å”þ(RÔÛ³;RsÂ/}éKt5-–²$´. Ñ«.»ì2¢†>?’5|üã/5´~ÄÃÜà4C7µóÔ:<öy°/'P¦ý§†lÓÄ£¹ÍÜÞèaú¿ß}LS(„y~S*@ˆY@]JW¯^­ô‡.¥Sy¦«iÌWuG`Š50zÕTîüÚi™¨aЧGÏ»žZè¦Fþêä¨ö‡Ó:دu5UûÏ‚©FÔ]´8q³½þਫ਼O\v‡ € hd=çÜwß}<õMQÀºšjþ NW@ ¢†)ÞóÝ®'F ýœ !ìe:¡›R}úªåagCäe°öŸ™ý®o?üJ™Äͺ—Ò·4„ë™2 € €€ èK—·ßÿþ÷‘?é…P}53Ôü[¶láäDº já¶oe°¨ann®ëƒøö§ºé—.ÑÓÈ?œ‹AÇBG$ñ ä¾…W¥• Ý´Øß?x\}Qy!€ €SÐÈÙLJßwÃyÚTI¾ò•¯h|¥©ŸF, |‡¨!¨;¿¢†O}êS‘7vî;tÓo\ÌÔÔeà £ã²yóf»+>{ûÜBùÄÍ–$wñUC@`(jæ  £HÜ|àÔøJk×®ʉD9@`XJv”ïи'À›¿¢†˜té5t´~ã ð$ H&pà 7h2YÝ[/|ä媉¹Û°>“(- €£З.%n|é öáöG?ú‘¦¶8uŠá€GyýQ)¦& ¨AÉN°·> ¦]Ö­[7µócª;î/tÓïZÌþŦÉdÿç¿ü»f,øç­Ûes´w›êÍÎ@ˆWÀzT„ÿ¸y 5µÅªU«4±l¼g*5GV6lØ@Ôþ'Ë~ðƒ5kÖDø£K¡›Xõ‹–~× ÿ< „àÈV?Ø €ô!@Š=Ç>òÈ#333än}\ì± ¨qÏm·Ý6 `ÌE½çž{"lìÜyèf‰“µëÒÒñŠðbûçõC@`´4sÖ£¦J»ÿ~r·Ñ^T ¾hÜ3¸›ÿC=[ÔÐy覄Š3w*P`5»¾î–ì@¨) 6nt,â³+¹[Í3žÕ@à µq£;Ýoþ±ån݆núÕñÖ[oý+¯a Ü~ûíÑvÈ € B@3'h·a>jQê¿>øàƒ±5yÄeE!_À~ná6:P;ï¼3žÉ¬; ݸ zøÅÖ,æÉ}Ãÿ°¡„ €Ä,077÷©O}jO\1WáÇ?þ1½+b¾Š©;56oÞ|à 7Ä|çAÝoºé¦7Ö8úƒ[¥«Ð_GpX¾ò•¯h.°ÁÙ@Æ-°k×®üã/¿üòhº¢­½+Æ}©R;Ú j͇…’Så§ížn­“ÐmçÎzÍ©@EÔkC·¶O_Š„ €q 8pàƒü ‰ÛhSé]ç…L­¨* Ÿ[>úÑŽæÖGEbˆÚÝøÕq|WŽžh•¢êÈV½'²< € к€·Ë.»ì…^ßCWÌ5úÒ—¾4;;ÛúÙÂ@`4D £üŒPŠ:åÐg Q^ª”r7] {öìÍ-›Š € €Àæç畸=ûì³c}芹^¡Oãô ñ´¤Ì еQÃX?F5´º-,,\|ñÅ<õbøÓŸþ¤ã{ôèÑ®ï§l@È8uêÔÌÌÌO<1ÖÇ­È륯^zÚ¦+äCa¬3ê´ºíÝ»WÏ@L ÃÅ £¬c­#>¾»95B@`4À…:ªJ [Ô1†ù삽Ö(A ¨¿¹nþD ‘|.(jß8ò-„nô¯ŽäpÕÔ°}jö¯ãÔí˜Â € €ÀˆÔëD}Ob{芶¾ î6âk™ª!P^@=Í•¸©×y´7ÃØ*>ÊÁÝZÝÊ-¶+AõÕà}:îåo—,‰ €Ô`(·Ÿ6Ü­öõŠŒF€¡Ü"¼ùop·¦¡C¹ExX•Üm4fT@Ê-Ú§Mw ù¤lt-ÀPnÑÞüG6¸[£ÐíÀüà?þ^ñ è¸ëèëèúnËö@@ ZÊíüc|ZÔøuO}êSsssÑžÿThl(7¢†h? 5ŒfùF¡ÛŠ+üñhÏ*®£¯s ÚO*Ž €] ¬[·îöÛoç¡+Zå­Ë–-c(á®/4¶@h«V­úÙÏ~í­ŠÿêW¿RÔ AýB;3k”§~è¦ÖžŸýìg9"øçþçÙÙÙg« € €ÅjP¯–‘?kQý[o½uÆ \, ÀÎ;?þñs÷‹\à_þå_4šÙNûš¡›~nºà‚ hêùe êëÐÓ°º~Œàb   € ”€fK×oÝ?@@J;wî¼êª«&>i°4v«te±0 XgîlLhÔP*t£™ÛÄÃÏN`¸ tàŸF@q ,_¾|ß¾}l/fI/£í§ ™¹Óa{”ú‹~ë[›Do4s㲪Ýê_°¬‰@D Uï{,?ÄÆn“C7²gÎìê–¯3'Œ›9¥@`` ¼Î9ç—)ÊÑÿÚK¡Xfeüe2£Ÿ·½ímZ]ÿͳPteûÕ2î¥ÿÕ›J¦l-·ý]ÉWIb•ßÕÅþ¢Õ•îù«kwVÚÄËß‹_TÛˆ+¤Ü¬Øé"i ú§ôvo&V´}%ð3K˜¹Ó’2,†Àிþô9ç¼þ§VôF3·ÏZ¬Bc·Áß7¨@ôD ÜÉk ®±ÛäÐi¤jœ¬¢nù:s¢ÿ:‰ÐÍR$˹Î=÷ÜÌ-ê×~[ÀOëÜ’uÙf3[¥©œí"ŸiE­åÞ,ȳJÖÓb/¥lÖL̶¯wT~··—DS2×ÒM¶ Ú´½ã2ÊJ¡›Ë"óâHq™L"˜3íD iéVò4`±q <ÿüé7½éo¹[õèmÕªU<ðOTÐӦƞç5E­ˆ@`Ù²e¿þõ¯«^ø,¹ÀàúÕMÝvíÚõÑ~4òƒJõë èÌÑùÁ‡UD eÌÐMo*Zò›tù{µ<.±¢[@ïkËüxË-`¡ÒÄ^¢m…n~´§(ͬtè–ÇšX>±XÕÐÍšÚåUßÒL[À/vqZ>!ØCøû¿?ºUiõ¦ÐDÑI½‡ ÖŠ\àë_ÿúæÍ›‡r‰PNðöîÝûÁ~0ò›Õ¯'pÍ5×ÌÍÍ å‚šº­]»öŽ;î¨ÁZ‘ èÌÑù3”+r"Ž@^èf©Y¢3¦Š­ñÚ,3Ê Ý¬·¦em™Q‘­žƕϳJê¥;xjżú„n9k„nj¡–ÙŠÐÑ¥‹MèVòˆ³X\ë×'C·rÑÝ‹"blR}Mw«ÑãºÐ¨-cÐ#¨ú 6¹°n´Ã^ (tÓ¸†‹/ÖHuÑK*ÞD@gŽÎ¦SËÇ"õèO  „ÊÌz¬![:½²[`d=­ÅVb`¸¼öqé wÑÒ-NÜ‹8oʈ¡›Ñ¥[ÒLB·þÎ~ö4h›oÎÝ&EoL¡Ðäq‹u™Naз ­S(p÷n"0¬éŠB75ØS³½&¬¹À†}è7Ë–¾újþ' ¯51%BøÝïŠ[~¥S3kþf=3ã3?§³™Ã¥ƒ¼ÄPeîqÐ.çO`Z<§jâQ2‘^©)™¾,%šïeŽéæ—f#ÐYE2§.µìÒO±Ù™ {—ÒN2¶¼ó ¢}€¦â± <ø`Qè–½:tè‚ .ˆüy‰ê7ø÷ÿ÷7Æ~õQ†&À0VMî{¬+þçÖ—‚AœøE¡ƒÚr678ößþÛäço{ çHàškŠC7ëðè§f6Л}Þ¤C7KÙü©±¹¹>Ó ÍìKµìåZÆY¦—mÄ^ys;d~Zz寮¿'¢.·¿ ‰Íõ¥µ|ÍÞêµtK;X guÏ ÝüâY¥þVåo<½hz˜™ î'˜gºì²²ŸæÞ §ŠKš4|Þ`õ˜˜¼kß9)$ 5kÖlß¾=æ{uo(ðØc­X±bWVnèÆ ¶ OV—À«jæF’‚å&…n–¬¹Ô̯-3t³vd~31k+ç7O+hé–˜@`bÇω{–^)§Ó_´qÛµ›xÔVŸØÒÍíÅM~ªmº_ºj‡nfåò;?ͬÖÒM±ügIbx#z[ºtéï~÷;žšh"pÙe—íÙ³gâg €@  cÕäŽÇºN`É’%óóóœÕÅÈ Ý4¨í—¿üe]¼h"ðU«~¢¯ ¡uâ ¹<'æ†ÁÖ] jzh¾¤FR“&°XÖx-1ífº¥›µYÓûþ+Ñû²`L·DØÔVèæš¶iƒ™‘_^ÿÐÌ3 Ë\C³Ú¡›uÔµ†{ÖBÐM.QmL7B·˜S$ê^Ià-oyvåÊËÿ×ÿjò˜ÁºH`ëÖ­LÞþ×NJˆ€ضmÛg?ûYn_4øÆ7¾±iÓ¦ð¯¬ÜÐMƒÚ>ùä“ XEÌ*þ€%0q6OT¹AǬü‰-E²eüW¢‡©%w™³—vº©Ì™ù-ïjD{–-Zƒ>kýW0¦›?D"òs­-«…nALS,ŒZ„üóF´eÓ³iw¿m\~yÙfžoyËiMuzâ„‚Å%<,!ÐP`aaÉ»¦x¿g×T˜™™ùùÏÞðÂgu~ûÛߪ½|ÕÓ¯ÿå³C7Ô–£ˆ@+:—tFõr³G*01t³HHm²qUbE[Àï[j J¸\[9—Rù=+[¡[:#«º%æµ(MßÁ'€ùø ‰ÐÍÉ$b;B·^J»o2)üGܦ²éC·)gÒÊÉ\@“¿i ¸¾Ïyö‡ÕtÛ×Í?ò[ÕoKàƒüàÞ½{«Ÿ†½®‘ºÑ·´­“€íH@ý”uFõz^³3†,01t³Îg ÞÿF}+¦{nšŠå\gþ?}Úº¬ÚœnŽ7µ¨ß´RÇÏôAH§W®Øn0µâÐM¹Xbâ+¼ß´Íö’h»gÚÄ™[­Ñœ^~ƒ8B·!_O”½GÛo/jéæÅmV& Âu饗ò¤„@+ô0íñRgW4 oi+7=6bƒèašº­^½Zß8´" sIgT£{3+#“ÀÄÐÍU‰\É_Ñú-gKú“~jyË›,³—ý¯k–9{©(?ifèfEuu±½¤{ÅÚ0v–ùÿjÿ›˜Á*˜XLoúÓ¶jké\Òšú‰¤Ë›½4Ño·¼CL§3uI@=F3ÇtKÅm†¢qXô¬ÜÊ“A`(Œbº#PW²X€;v‹ꧬÞÊ_lÙ¡›†E µ‹§Bä›Ò¹¤3*ð+â!Ž€&âTÊã÷ŽÔÿú£ž©¨ÊËüViVx¿X殎ö¯~èfÿ¤üKÙ–eI™ Ø./7sèDC-©-'ꢵWù‰•þžÈ³ô¿ºY!mjQ{)­KDiNúZô–hgË$ök°é…U`½éWÓ)ùå$t›x°ÀÈ4®J"tˉÛÌ1}">l½úC™Ænä÷ª‡À$ Â¥”¼õ;ŒS`czf„n꫞±q3jÝ‘À úZOú€àß@@ GàùçO¿éMgB·Â¸M›Ðó†~Ó³rGl6BM†¨nk\¢ ²Àüü¼òñoPT¹; U¡+B>í3B7ZûwwBD»åAôµùB¥l €-pýõKÜ&ÅmV‹;w^uÕUÑ>Qñ.Ï$è[…Cà ÆŽïâîù6o¹å–t7š .¸ŒÐÖþ‘Ÿµ]T}­ƒº2) Ãиoé¡þ;‰áç†U;J‹“ÞùÎÓåâ6Û”žõ”ÜÅ#ÛŒV€ñL&_§,À´;>Ú[twòÉ'—/_>íS»hÿÉÐÖþÝ 1oy}­C¾P) º~€(Ý ¨o©fQ8q¢ü^ô|¬§ä˜¨{úçÀåÏC–Dž;¾‹[Û´+z>™Ëï.º1};§lGá÷µ.Ù°$ €Ôp?ÅuôÈÁf£øò—¿¬ÎkµÏLVDN”‰+öEÅ»Ѐ¶¢Ó³·ÉÆ“¡ºuw*D¾e†ukr¡². €£`@·ÈŸ »«>úæ.AEF)À€nÝÝý"ßràú%C7t‹ü|í®ú ë6ÊÏN*… €@UuëÖ}ï{ßë-G+À°nU/F–G OU«V=ðÀÑÞ ¨xwë– ÝÔö¹çž;É ¶t^éìêó¶Î¾@@ @}ïºÿþûÛ~Ð`{¼.pî¹ç*z ð´§H °lÙ2õ0åV…@ëÇŽ{÷»ßì%vVèfCl´NÀ0À8 ö*¥` €ŒIà¼óΛŸŸçé.DxL÷ ê2&µrR,ÒÅUÏ6À’%Kôhæ%sVè¶wïÞK.¹„c†@G:»tŽ…y%P*@èA€ï]=e±Yøâ¿8;;ÛÙÌ.@ ’À¡C‡.¸àîTt$°råÊ]»vU:'{[ø¬ÐmÛ¶m×^{mG l]:Çz;¹Ù €„&`³×ñP„@GßúÖ·6nÜÚiOy@À¦ÐéèÂg³„ü‹ËY¡›>¢ôAÅC #ƒø¸E@ r¹¹¹k®¹¦£' 6‹À½÷Þ»zõêȯ2ª@€›7o¾þúë¹G!БÀÍ7ß¼aÆÏ|é¬ÐMQú êHÍ"ÀcP˜wJ… €@o›6múÆ7¾ÁC ¨)¥kïí|fG PR`íÚµ[·níèÂg³h‚&MÓTòlìy±³B7æádíT€Ç ž/ov‡ €@hkÖ¬¹ë®»:}Þ`ã1 >‡]h×#åA 7+V<úè£1ߨ{§!G g…nšODTZ°ñ©<÷ÜsŸzãõÄOL¥¶SƒzûTcG €„)°|ùrͪ4ŧvŽÀöíÛíµÝ"…<‡]˜W%¥B Å‹ë;i»{ë[ÓMéïþîïÞûÞ÷¶¾e6Ø\`âGÆ¢E‹z8“kìâLèÆ|"Íσ`·ð³Ÿýìœ7^­?ÖT­²æ¬Ñ™VãLe@@ëß»ôóÌ3ÏT} aùô\j¨:ˆ-–'ä9ìFp Sj,,,èæ_æ2WݦÕR¤£›R™Š7_æºë®Sùõßæ› s N°QÙÐmêó‰|÷»ßý¯“^aþðKNèÆcPO)VA@`G=÷Üs[|pR{E6z~lq›lª7‰ß ê•$ä9ìÆq!S ª ¨ó%—\2ñŠÖ ŸÄë5•𨣛ÒÄŠ·²€> nZ‘e+µ(ØÈÄ£lÔp&tÛ¶mÛµ×^ÛµTDw¥%þ2²'ª>û{†ºéÓ™Võ6Íò € 0ùùyuýkñiSý€Z Ýô𸛠L”×Wµ.ú{æíwâ7¨‰Î\@3uè«û®ª€ÀhöìÙs饗N¼¢íw{éö>qù ïè¦T£œ™«ÞB7ý··Öß¡}d5„ºécR!Qú5¦È¶ç¬çÝÜV‚½Fó‘FE@V ä÷®òßOÚ ÝÚÝZùZ„³dÏ_8;Ú¡[°w ­@Éö=.6ê(<𸥏£›R+7ù‰…·ß”¥´²»2é™kâî‚΄n›7o¾þúëËàv´ÌDÄŽö;•ÍN¼fÚ-UÏ»+(¼Î1iÑ~ÞPq@b tk÷¯õ­õü4ÞÑî¶nݺvíÚ˜/4êŽ@heB7õ'µ¬Íu2m}8ò‰_Š;º)µr¯žXøVöRi#=sMÜ]°¿¸œ Ýtr«”•”Û]x"b»»›îÖz¾fzÞ]m°WBhŸL”@ñ ´>‚p»mÓÚÝÚt5ëí½ç§ñŽvGè6¾[5ºÀ–-[¾üå/ß—ìl½J]“·z·²¼µ&~)îè¦ÔJ-&¾•½TÚHÏ\wlÔp&tÛ¸qã·¾õ­JÊí.<ÑßÝ…^¨ 23üV/Tõ×+sNb%èZѽ&Ш,R›ò—Oô‘Ö^ vg³«´®ðÖìóŸþ韬³ºÖµ¾ÙzéŸÒ¤Ú‚UÖ^ú»Þ)O,oíKùDƒ½†þIFù@_ Lc‡J—y1™«ôOî‘ÉüÓ3Xz¼{s_óܳY^;‹’Ï“öè6âžèTWM¿¨ök|®‹PÕGMÛrB@[+~˜´iïÜ€J*¡CÈ।€«¦ÿD­½Ø¡©ôð_þĸÿþûW­Zþå@ ˆG`bûÝ–íl·>Ý-‹ç¨zc,ùwÝ3A:5Ë{üÒ‘s3zøS4èÍÌyÊõ„a›JÏçà_ .ÏÊÜHºR™ÛÌ-ÒKÒ/†Ÿâ%²ÈtíÉÆÞÏ»[?šyä·Çï @~z ÝìqK=zþ-·¸‡iÕcÉïà.Lp{·¯ÕîΙ97hÕ£ Ýl³Ú¦þây×›~2P²ðyˆ6Xžíȵbvwf÷›‡+•þI«Xþàò„z~hc?ƒéeÕ±"¥»ú5ùȸ뮻֬YSïít­3¡ÛêÕ«ï½÷ÞÚ¿)5_ÑÏËìxø¯ÌŽv¨\ìêjâ IeK‡eîÇCû§Dvë"çt¸®wüíW½à?Zæ¥`N#Ý”Ï]œ wkð-T"éGÅSÝtŽéLëôœfã € ¦ÀÄÆUŸ'‹C7{PL<ü¸úôoìͬ`UŸ'Ý㜊¡gŽ|âvš~mÞÒͿԺ/`鿉MϪ ¸æ*‰”S«~C‰v[º:théÒ¥a^” 8Š;Õ)Ù·›•[vßÇ3ÇVêú;xú†ìné| êÑÞ>ü6òî™~[Ÿ¼oô™a~앸Ój_~»o-©…têâŠTã#Ã>pý½¸Oy+m⣡áGF°ÍœÏ„nj†­RV}Öiqyÿ¹Ä®:ÿ•8‰Æêv)ºƒš8WtõÚ¦2Ms–_—¼+']ߎ.ø‚¸+Ç¿ÞÜóSæEèr·©‡nÁ^ q~þQk@úh}ቡ[úÇË‚17ŠC·Ï“~£‰ÌÄÍõÕcjúûL+¡[Á“aºÉFqèVCÀEœé¯Í~îFèÖçeȾè_@íÔ )/:Èü>î’¸Ì{cGßÁ ’µ¼ß]jÜ]á "¿AtÉV;™a.%ÈëËY&ÏÉ‹&Š?2\j‘:7ÿþßð##ب!ÄÐM5ýʼØü(Ô¶ô³… ã2O©ôñv—A™ˆª‹ ÞÝbò >ïóÇ’—h™‹­•e‚½úÿìa €Ä&ÐúÂÅ¡[úKKqƒµâЭêó¤öåwãÈ{Žr;M·/hºå 䬸T âbÖÕ~ø\´hQlõE dâö=é¾¥þ½:ó>ÖÅwpÿ¦ùK@ægDcqÚwcœ˜Qdob î2·Ù¼ßÃ]Þ—‰™Ù¨áGF°ÍœÏ„nû@# ”Aïh™zŸ»®ÝiAÓ0÷Oé^«Ö©ØÚÁ¹³Á•¤xžÐ&OBÅ׌Hg–9ݳøršx‰vtLÓ›%t ùã²!€ ЩÀ C·ªÏ“¿¿ùý6òÒ1-Sï»eñ“a^s¿â§ñyߥ­îõþË<µºuz!³qª „nîv”nŠUð»E½ãÄ/ÅÅ7¥ÌûjcŸ¡[ù|é[« "ê…n~ßÒÌLÃÊæ73jø‘1€Ð-œî¥U[˜ûCBdÆdþ鎫îtèV¦$]\ðÅ=m]ýö¨Å—ÓÄûK™Ç—V–!t«úÅò €ŒF`Æ 7ß|s+OʼnUqä”÷ÔTf­‚'Éĸ%C¥‰Íê=jÖû9¶LèV^`âógG¡›zò.^¼x4W A`ÃÇ´s¡ÒÝ0ëÝÞ” B·ò7Fÿ§”Ìnmí¶t«ºÙÌÖï0Q©ôCe2ʉ2¡áÑìÞ½{—/_àõr¦¥ÛªU«î¿ÿþƒªnªÞç®>Vý"sÔ6×LQ×IÞËïi\©$]\ð®ÖÅàWv(¡›Î1i^  @ºèy"…v»—V}žkè&‡’OÔÍ¿AUý6aËÛØ¡ëë‹í#¬@A3g÷]Þ‚žÄË"½™è€ßÅwð‰7í‚Эü1äÐÍŸ¤Õ¿Ï»¿Ä=¹dèVð‘¡=ºy$šdÛ¾çLèÖzƒÿª“•¢.·qÿ̰ 2½ßªùn¥’tqÁW*€Õ7ïJ°xW=Xµ—ߺu«Î´`?( €t'0‚Ð-sÜë¼ç¢2OtSiéÖ°{iÉç@7Hqz²?ÛBŸ’ûò#tëîfËÔÈ‹Ü@OÛC%fÅéâ;øÄ›Rq÷Òò7«0»—º²î؉ˆ³^÷Ò‰Ÿn ±æ„n“OŸ»þƒ-=;FÕã]0'CºîšÉœ¤^ëÐY½N“JÛKºÕû b-@F °mÛ¶k¯½¶Å‡‹¼çŸ2EÓñYñZUŸ''~3‡‰›­÷¨Y¼Y7&rb`–2ÍòÚfÖâ_¾k<ü—9y‚ýÞ5‚K˜* PO ïw§ÊóKoªkWæm¤Þqâ·ì÷À‰÷ð‚¡·î¥eîÛxê…n5îð ?2‚δtk}”2Šþ25ŽŠ~÷Ìdÿ«Wâ"ïÁ"¯„½Ç ®™Ì©p]‘ÃÃM¼à«¶ÎsuÌÌþÜä»™vÕ#Õdùo}ë[7n¬w³f-@´À C·ªÏ“­‡n•5Ý#hæ“a½¾B5ÜWµôܬþ1e†Q.ÿüIè6è»…¥@fèæ¾të»jÁîîf®¢vߦ+Ý'~¯ºÕ¸1öÙÒÍõ œ8EdAþP/ts ¤2Qæoø‘1€ÐMW¿þ뿞˜ÞË?ÅË”B3?XĶeË[þî»ï¶wt´ü-<þøã™ïûËüÐ-}¯+(Cq€Y¼‚”@%×*îóÎy&Ф£ãFÖ«ô‘á>mµåt’™iø]\k|d¨]äºuë‚:ó­0gZº…ºérwæËÑë±Ó"ñ¸à¦Dºä:X:oì¨k#:ÉôO6ð¡\ÝÙ©]h›ú_­¢ >óTv;u×ÞÝ%açhú\Tàô6ˆ-91Z±‚Û¾çLè–y%4ùÀ«º®;ÅíÀ¤_þ!q§T¢Á—~tmâŸü3Fw‡Ó[y™n¢$ö’H^[óò¼ÐÍ‚nû‰àOg˜¿Yý=ñ¿‰ &ÚÖù›u,SÝt·Õ™6”ʉ €- ºùßÇÜsTâwÓJÏ“m…nþo±þs©ý.›ù¨é•]#ÅôÓ¬{²u±š[>ñôXI@›Õoçäªß#üå ÝZ¼fÙ­¤£×@,Ýä6}ù»ØÈo†\ãÆhw¤Ä·{ÿ;x½ÐM›­tc¬º¾àצÄÏ0™ùƒïé'Z×j—ÈüÀ1ï#CÉIA¦‘@~dºMþè´ö/wAº%3#$kÞeÎ{ÕUjmÄÜËΡÌNZ7½|âO·}¥Z–ÛK{±_]Q™­¨e,ßµWfÃZ—ûeÖóSæí‚O,iûR‘´/ÿ·Êɇ¤ƒ%ÝZùÜb# € Q@ÓJ^pÁ->_(!ÒãMú;›‡ì/s_öP”Ùƒ2ñ(•ùm°üó¤u’(þJY\ÔÚšþ·¯DUžt7ÊšØKÛI/\^À6«-øOàî9Ù~0Ö+ï±¶Þ©ÂÂC¼9Pæq ìÚµkåÊ•þm_„õÊû&ž¹°nªþû­/¾iç}âX‘Êß]DYw'S5@(þ4I¤ ™iIÂS–·X‘ò>Ë&~d¨"~Fᓼnŵ?2¾øÅ/ÎÎÎx)iéÖú(õ>&YkÜW^y¥ÚðJ H € еÀüüü’%KÆý¨Hí š<RÂîŠlc‡®¯/¶@°­7sîî–‡+lûž3¡Û.ºè¢áSòAèÓ™ìçC@NÞýîw¿øâ‹ƒxht!cÝ4Y‡tz³q¨$pôèÑsÏ=wÐ7U ¾À%—\²wïÞJgf? Ÿ ÝN:¥Ç ð))á tŽéLëçäf/ € šÀ²eËžzê©A?Ì ¢ð1‡nÁ~ï íb¤<ô)À/.ƒøìt!ì*Þíó¬.¹¯3¡›VXºté3Ï<3hh ²€Î.c%OMC@ñ ¬^½úÞ{ï ùqee‹9t[¼xñÂÂÂø®j„À –/_®VHã¸ÁR‹ž{î9ÝüüFÎ ÝV­Z¥ñ¶¤HãÐÙ¥s,Ì+R!€ €@7nÔ8÷ãx° ¹цn‡>ï¼óz8“ÙTX³fÍ]wÝòm“² Z@ã®X±¢Ò9ÙÛÂg…n6l¸ùæ›mMáCÐÙ¥s¬·“›!€ €@hÛ¶mÓPÇ!?®Œ£lšƒO3Ê%fúGÕŠk¡I5Ã`h§=åAM›6i’“îBÔq*?üá×®]æ…vVè¦ V5ÍêTŒØi ÁNâæÅI©@Ÿ€ºiÈ­{¨ãT¾ûÝï®[·n|5B`èšÞD“œLå¶ÀNcøÚ×¾¶yóæ0/“³B7ý4´råÊ uœŠ€Î.ca^ ” @zÐ`[ïyÏ{¦òÂNc¸îºë¶lÙÒÙÌ.@ ’À.ºè¢îBÔq*W^y¥³ªtNö¶ðY¡SùNåüˆg§ÁÎ'ÒÛõÆŽ@@@Cnià­xž¨iŸüÄË0N:¥ Lû¼°¯¨.¸à‚C‡…yòŸº©ˆšñáÈ‘#/óB mWÁÎ'æÅI©@¥€†:~ä‘GÚ~Ð`{¼.ò÷®Q^ÎT òúÅå÷¿ÿ=·*ºP¤«`·üÙØç’ÉÐMSùþò—¿ìBmF. óJgWŸ'7ûB@4ä–ÞŠü¹ˆêw!ð /è{W€ç ¹¥¨AÝÀc¾MQ÷.ôKž~Ï ö’I†n*(úuqD¾Mt ö@Á@è_@Ý@Ô$ò§#ªß®€¾Éë'Þ`Òîÿ*c( àêÞîµÏÖ"Ðoxú%/À³Ý)#tÛ¸qã7Þù‘£úí èŒÒyò•@Ù@@ 7†uk÷A‹­I€Ýz»~ÙµÖÛuë見%#t£¯uëç¬ÚÚþäkÏ¿òZí»9+"€ €@ÈŒgÂÃaë×]wÝ–-[B>í)8pࢋ.jýògƒ1 „?v|FèF_ë˜OÙ.ê^©µ¿â¶™'N¼uû±¯ò©„ €£`<“.ºbÞ¦¾Éëûüh/*†ÀXÔ üÈ‘#1߬¨{»áŸºér¦¯u»çAä[+ÙÚßâ¶7m}ñœ¼pÉc'Æò±B=¨, 6Òš‚Ç_mÇŽz禛n*ØÖáǵ̆ 2—Ù¿¿þU[..-f/mJÛL,¯7Ýî/Z«|%ý-¨^™ë–Ù‹™Ø+QN­žç …ý=£¹JYyü:úP¾Xy–D]YßùÎw"F¢úm è;¼¾wqY!€@ø«W¯ž››këÚg;‘ bìøìо֑Ÿ»íVâôí~ܦÄMüó_ÃÿÀ „t$ð®w½ëœsÎÙ½{·ÛþÛÞö6½£W"úñ à–ñWt Ø6µL^™•"{î¹¶Œ½ìïzÓ­¢-[1¯‚R%v—¹•ÍÂÊìÅUÇ•ÖOÙìÍtMmË~i­ÊzùÕL¬è–ñW´$^¼*lA ìܹS]BÚ}ä`kÑ è;¼¾ÉúŠ ðD" nàê íÍŠŠ·+ _ïò~kç‚ÊÝÖ­ÝS!ò­ è–ŽÛ”¸½}n!œ+„’ п@^è–—%©„ú°±ä(‘ÖYáié}Ûlfs9¥Q–²ù­Æ´ÖÊ•+õ¾Kñ,´ÒvôÿUž(½…‹/¾Ø¶™ˆö öb«è¿¶ŠZ«éï~"V>tóût³>Gg°éÐM˜¾C¥åÑX± hX7]\ƒ"òÇ$ªßŠÀ¾ð…‰­¹Çz)Q/†%pèС .¸ • Ÿ pùå—ïÚµ+ðK ;tS¡5ëªæ^å("ÐP oß̸͚¹]ñäÉÀ/Ї@§™¡›‚$E`Š~Ô­2½w­¢—R¡ÌÐÍegÚˆo¹íäq~å"³ÚÕÏÜB¢¾÷¢å‹Û”U ÝÌMJéz)ÎÓÖôE.3tËlTX‡ˆP`ÕªUjïÖðIƒÕÀyçwôèÑ/"ªŒÀ–-[¦Ÿ*¹w!ÐP@ èæ¯9 ¿ rC·7ÞxãÇy!ÐL@g‘Î%ÿ2(ˆÛ,t[ÿ4¡[à÷ Š×­@^覧“DO+‡b8k–º¹¬MJô÷ôh~ñ‚ºMŒÃ&º´ºY¦–Ù0Í P5t³†~™AžÞTî–î—š>FëÎ P—À«¯¾ºÙƒk#pü¾ûîS€Ë%†CؼyóW¿úUn^4PWåuëÖ…Úç†njöyþùç7T`uté\²+abÜf¡Ûí‡_ ÿÊ¡„t'ºiÖÈ+‘7Y”¦Í Ý,’³ÁÌ%ZlÙ6õf™®‘…n‰mâ^\ԼܭFèf­}o­Ó® ݺ;ÛÙräúuZ¿QÿéOây &ŠnàF~5Q}$ v©z|mrÕ³.¸ä’KöîÝþ™Ÿº©è+V¬øÅ/~ÁáD ¶€ÎEåã6 ݾú›S;Žü…?Ä)pðø«¡[:5Sðd­±òB7ë éò©t U0T\â3̲'-ïO`Zi Ęnʳl¸4¿kg™½¸±Ø´b:z«ºcb:ë´+„¼ÐM{÷)ŒKG0ÎS—Z#POàþË¿_;ûÓÚO¬ˆÀóÏ?¯yKÃï^þ×BJˆ@Ÿ333=ôw0j üæ7¿Ñh}ž´µ÷UºÙÄ"µX?ÿúÝδg§&ê èCdíÚµµ¿ ±"LE`Û¶mŸùÌgê]õ¬…€4†Õ¦M›¦röVÝiQè¦fŸK–,ÑÏGTjèÌùÿßçýŒ  *L ݬs¥›NÁÏÔÒ¡›µŒó'Ò¶wü–eéˆÊµÞJL‡:±ãçÄO ¿¥›kæææ!µÕ+íEEµèÍßH½Ð-!ã:í´tËœHЭjÚÂòHà¢þXãIƒUÀ‡?üá={öLübJ@­Sßóž÷5p¯- ¨j~~>¨³:¯0E¡›ÖÑ ¤š´6+Æ,àµÝóÂ_ß·ëxù/ïüé¢û_âOljyõ>þœPÿ¬â–njw¦ŒÉÚ—YNäF"K‡n–šY7I÷²ÖaîS¡`L·Ä+Åa™Ÿ:é-ØÞý)Y«îÅMƒPÐ…ÖóT©DÝ]væÒ:¿ÓnÕÐMG3* \øïÛÿõ[7ÅüÈDÝk <ûì³p_º($$Ö¬Yó£ý¨öåÏŠ1 ¸a¬qYMݘU*æS¹a݃ږÞô•u…D #âÐM;uÓ)Ø_\1Ò¡›¥H‰ÐÍš†¹œË:¨úQTÞ«ÆaiŸô¬§ßGµÆ^by-ÝÒ#â%V´V„ZÌL)ttª³YL€É»>qżú7Þ¨F\J 0D]»v]~ùå1ßÁ¨{m/|á •Æ•žî2!tcV©ÚçAä+j&2ýð˜Ô¶Lô¶éЩé^ìé L ÝlVMKˆüŽ¢‰ÐÍóû–Z½,{rý1­U—^éÎ’=´tSylï®ZóÐÍeg‰ã˜Ï.Am­-Ê´)ìEè6Ý+‚½Ç Àä]‘?7Ö®þù矯Ð6†k„:"0J}aT{ÕÚwVŒS@½’uæ,,, 墘º©ú¶yóæ8'µ®- s&ýUß]ÅÑÛçž:9”ë‡r"Ð…ÀÄÐÍ‚*ë%êÏÝ™ÈÈ\ƒ¸t!mÁ,†Ó›~{7%PÝéæÉŠív]ºé_U/×£Ö>¤,)sÛ´ÖsªŽ¿˜%qéùIõ¦Ÿ6¾ßi—Э‹“œm"`ò®ÚO\1¯8¬îE\õ  jˆù^»îꕬ¾Éº &‡nL§PûlˆvEeÏš¾WgNñ•½]øÈ˺„(*­ ” Ý2#$?t³ökyS‹¦Û‚)ŸrAžEr–=©0‰6h–gù¯Ì®©™,™škjg«dÎ^êA[Ø/ƒý=ÑL/³:~0gûJS»üÑ/ÉÙKUŒÖO6ˆ@$j¯'Ú;DûèX¯âW^yåÎ;#¹F¨&£ j¨w÷‹|­‹.ºèÀº"&‡nª tä§uÕê7sK\éèíM[_<ñê€."ŠŠ@Ë¡@1–ßdZ7áDÓQ5CÓ2ú¯¿oµðr+juýÝŸ À_ÒVOÿ« g¦(Ji]ænbSÿ/y{ÉtÑŠéf°zÇOî&îEåTnhåÌkT«xNÛÑZL•ò[½¹‚u¢œz'1HDÓ¨Ó¯–O6‡@L4v«ú¸ùòO<ñÄòåËcºD¨+ã jˆüf^µú÷ÜsÏêÕ«‡u1” ÝH «ž ‘/_c|DôưnúPZ@ ÐØ-ò§ÇªÕ§™[Ã+ŽÕD€¨¡êÝ/òå×ÌMZ©ÐMË­]»V¿üG~€©~&Ù³‹ÞÝÿR @ú ±[™-–‘ÍÜú¹$Ù ýÐØ{I&QC?'sæ^ʆnê4«Lñ%^Lhž=[ô6òµ)^ìª $zKÿoÕ ²<Ä&`Ý~÷»ßMzÖàßc ™[l7ê;nkìöç?ÿ9ö[õŸ$З-ïU0ñø(¨Ô°öQ?KQùI?þ8£¹Õ¾ÄX0ˆ&Ýùø÷—†5TÝhìÆ™>Q` Ùs˜Ÿ=” @Øhï0ñY‹hæÛmúÆ @ÔÀ½}¢Àp£† ¡Ý&ž‘/0Üì9†O2êˆ €À hìùódqõiæ6ˆ«˜B"PC€ÆnÜü 5T Ý”@_rÉ%t·æzÈnö\ãSU@@  5vÓ4èüãyÜB -@3·..:¶‰@D Üó 5T Ýt5òó#C¦Àm·Ý¶nݺî×”@-0;;û…/|'.?ýéOW­Z5ès›Â#€@ÀÆ7mÚÄ­„ÀУ†Ê¡Kq ¤4јF´ÕOÓ|Š € €Íô\¡Ž„¥)<”`FnþN`“çÔ ÝÔ´[CÙ1£׃ÎÍ­¡Ÿ£ËÜ@Y@()°°°°lÙ2¥-Mý»þ¼aû €D.À&‘?p2Bäwª§€¢Mœò«_ý*ò`ÌÕÓTõ[ºéúßµk×å—_ó©yÝiêç§ µF@ 7 a¡,ègí3§õ­éí|cG ˆQC´·}«ø˜¦jlºé‚T×ÂoûÛtƒWl?øÁÖ®]ÈM™b € €ÀX¶lÙ²~ýúØ´¨¯~ö³Ÿ©©ãXOlê…ÅD Ñ~Œ,jhº©å§> 5e´'Dœß·oŸZü2‡Ÿ” € Ѓ€MfçCW´µþío«§Í£Göp‚± P€¨!Îûÿø¢†¦¡›.NM/¢I%þð‡?ÄyNDXk=ýèH3Øxk¦H € 0>=néÙã׿þu„Ï]ÑVùÃþðž={Æw2S#(/@ÔÛGÀ(£†B7]3;wî¼âŠ+b;!¢­ï§?ýémÛ¶•¿W²$ € ÐP`ïÞ½Jaô8íXT¿á†Ê­á%ÃêŒC€¨!ª›ÿ(£†vB7]Ïô¸ŽäbYÿêq|Q @b`p·Hž6Ê-†Ë™:"P^€¨!’›ÿX£†ÖB7z\Çp%Œ¯uù{=K"€ €ÀÔÜmôœ å6õ«Œ šQÃèïüªàˆ£†ÖB7]™ô¸÷Å0ÊþÕ¡}¢P@(`p·q?mªv åÆÒD ã¾ù;jh3tÓµAë_ Ÿüä'çææø @@¦(Ààn#~ÚT'²Í›7Oñìb× ¬QÈoþãŽZÝt‰ÎÎÎ~þóŸñ gÕx ö㇂!€ ›À®]»4…“*Œì¡ô¶Ûn[·n]l'3õEòšÍOíìÖGuF5´ºéšÑdCšrˆ³g4: 7n,7dI@@ S¾zæ9Ó*òãÿXöuzΰqQÃÈnþßþö·ºàÌ,¨B'¡›ö§ß©ôkÕÈNˆ8«3Ö9DÆ}aS;@F/Àd¦£y4Õt¥«V­ÒXé£?i© 4`2ÓÑÜüï¼óÎ5kÖ4?%ßBW¡›ªÍôR#¸~ò“Ÿè(ð“˜â!€ €@œ4yÁÓæc=633£ŠÄySk¨!°víZ5 Á 0æ*(jPdÃÏ-†nâS^£_®b>“]÷Ý»wë(†Ë ÆžU@@ ¾z úió׿þõŠ+4<_çe@¡è+ªò¥6ƒ¾Æ\xýÜ¢›$QC‡¡›®XFJm}ôÑc¼†& £Æ¯ŽCùÔ¡œ €Ä, _yõÕkhZ”÷ØüüüòåËõߘÏ^êŽõ”×(µ!jâgÉÓO?­›< œ» Ýtýè—+] bâÙm™u¼”¸ñ T@@ Oë]Aî6¬W=gêióÀ}ž*ì Æ$ Ô†ÜmXw~•6¨¡óÐMWµýŠE=”ëAGŠ_ÇôiD]@½€¾z©«ÑöíÛ‡ò¸y9íK‰Ûè/L*ˆ@×j⣛ÉÏþóÈoªC©¾u§‹­qO¡›®4 ¡ù2ü‹ALj^¥]6°}@h]À†ø¹ýöÛÃÜŠ¼„O>ù$‰[ëç?D ZÒŠ¨!üOe£&nº0{ Ý´'ž„¿ î¸ã=­ÆÓ¹:ÚO&*Ž €ÀX4¯Â 7ÜþCW´%T3ý[3‡±^nÔ @l~t ù“%æÆ=ý…n–»éIèÛßþvÈgC´eÓMjÍš5‘L ÈÇÅ@@Ö6mÚôùÏ>Ú'º+®/]JÜø}·õsž "€€5|ó›ß ùmÙ5(6jè5t³{Á†7^ÑžpaV\¿ ë&ÅÍ@Àììì'?ùÉçž{.Ìç®8K¥/]êQí—®\VTð6nܸnݺ8ï±ÁÖZIhäQÃB7]«›7oþô§?ìi[Áôk°~ÿJ @@’sssW\q¹[ µö¥‹Ä­äÙËb P[`Ë–-D ÜùU E JBkÍq¬8ÐMvÛ¶mûÀ>pèСpNˆK"ÿøÃú5xg3µ@@œÀ®]».ºè" Ûá3^8UVî©/À|éâÂDÞˆBøÐØùÈGˆtÚO-tÓ¾÷îÝ»lÙ2æ™Ö%ñÀ,_¾|Ïž=½ÝþØ € Ч€~_ÔÓ£kOëiS‰§üõ¸ÏƒÎ¾@¢†iÝöm¿š¨TQ~úâTœrè¦Ýk U¨Çoý_ÄMóõ=z”Ë@±€M䥯Vt5íùSY§7åž#>»¨+@ÔÐó=ßíNã h΢wiL³¥›+„†xS'GºšösUX—Rq öã‚!€ €@ëjlEWÓ~5µëRÊ n­ŸÆlª (j`T«ÞnþÖ¥”ñgi¡›Ê¤NŽú)L{;!âÜ]J«Þ¦Y@Æ!@WÓ~ž~éR:Žë…Z 0ºšösó§KiÞ%Jè¦ò©ý¡:<~ýë_‘W7²¥Kéh><¨ €Tp]M9ÒÍÓVì[ýþ÷¿O—Òª§%Ë#€@×ÖÕô+_ùJì÷èÎêO—Ò‚s8 ÐÍJ©nïÿû~øáη7,O©Ò¥´ë»9ÛG@ðÔÕtéÒ¥wß}wŒ…ÕùÀêUD—ÒðÏJˆ@´êjzþùç«ïWg7Â7ü裪/]J‡º©¬úÌÖÀ{ â™gž‰ñ´mµÎ2”¤<¥í핊#€ €¾€:X¬^½Z!‘ºµúäãÆÔlPÝ)˜¨ŽK ÂÐ8êûõ‰O|‚¨¡ùÇÕáÇ׭[§ÖÍú$ ÿÐO±„ÁµtsúRÞ·Þzkó³!Ú-HO†LÓ>Å Œ]#€ €@°»víÒ·u8¢·ií§å;vèiSÝ)Ôu7ØMÁ@_`nnN7.õˆ¬}ëcE & Ã-[¶pjM7tSÑÕõZÑ©+ÒÛ´êU-1¹IO†O@@âPT¤Gô6­ú¨©å­?©†IÒtuqž<Ô†+ ¯ÉêIoÓ7ëOªÁÔf|¸'@Ÿ%:t35VTïHT5_¬qNĶДd%1yöy!±/@®½M+=0ÓŸt¸§:%G_€Þ¦•nþô'­wù t³ŠÍÎÎêGH Aô–waHF>R’U½³µ@@hÔÛTe4®ÚpUúÏŠÛnºé&=mÒŸ4ÚË„Š#0>õ6ÕmM½ÄèmbÔ@Òçÿ`B7ÕMM@õÞyçq=$.Ý4‰=ÑŸ´ÆeÀ* € €€ ØÜ¦Do‰§M·mذ.E\, 02 5 8‰è-º¹–=D µÏù!…nVI®ÿJPܦRw GBÜVû2`E@@À zsœîq׌[€¨!3j nkxÚ/tKDoÑþéâ6EòLÕð2`u@@ -`ÑÛW\¡q£ãéCšŽÛô‹Öm\  ‰€Eoê`GÔ Zö4?퇺¹èÍýùÀDò0¤šêú×# q[ó €- € €Å;wî\¾|¹¢·;î¸#’§MÍÇ¥‰¹º„KbpQÃŽ;"¹ù?üðÃD ­ŸóÃ݇®‡™™™üÇÔÐfzJå%¡zÙÀmª©êKë¶Ö/6ˆ €ä (z[³fÍâÅ‹•FékÉ(Ÿ6Õ‘Bó$œþùšPBsÑÀËÐWïU«VÙÈòc4}MɸbÅ ¢†ÖÏù‘„næ2??¯¡Íô”ðþ÷¿ÿÖ[oÇä#ª…ꢩ^ªêØúIÀ@@Ê(‡R¥¯%ú­W_QÆ1Ï©&Iøþ÷¿ÿ‘|Dß*5pÛ¡C‡ÊP°  €ºØ«Ÿ™¾’ëg ý81ލACv*jøÀ>`횉::ŸGº9#=)‡ÖsÃÇ>ö±­[·þéOzah/•Y%Wù-SW::Ø, € €@U}9ÑW}QÑו[n¹åàÁƒC{Ø|½¼wß}·k¾·k×®ª,Ä& Ÿ%ôㄾ¤ë‡ ý\ñûßÿ~p7‹>ñ‰O¨í¶5ß‹í ö\ßq†nÑ:¼ûÝïÖóúfÞ{ï½_÷߿ʩҪÌ*¹Êßó Áî@@Ê èëŠýÖ«æ_úÒ—cþLáÚ¿ýÛ¿éëâ¢E‹V¯^MO¢òÇš%@' {©FPn¥Ni5ÞÖGQƒh»¨annŽ£ÙÀÈC7‡¨ç!õÍTgl=^|èCÒ£†.’@8ÿÑG㵩œ„Íýœýì@hK@ÍÔùH1–¾ƒ…ösïž={ÔJ](T6õݸq#íÚÚ:îl"P§4‹ÔnFQƒ‚­£•MQƒh5ôºÆºù²zìУ†8tæéáCW…Ú…*÷í'™Ö^´/íQûåѧÿ3ž="€ €] ø?÷ªM™žúÔUO€½5‚Ó¾Ô{HûU"µÂÓì«ê¥.ÌÐõ¡gû ³€¢[F LÃ8ÅÓ2ÆÐÍqëÌÓÇ® µ Uî« N¿þ)œÖÿêE+¿üå/¶†ÓFÔËÀžx´eíÂ2fíBûåÑgЧ>»F@zP“=õ© ªžõ¨iM!4ŠˆžÕIßÐ>mjûÚŽ¶¦ÇKmY»PÇíK»Ð~ÕHã÷PMv 0•¨Aw{¢†Ï½¨C·ôѯzôѤTzFÑÊf'ÑS‹½ì É©ç¶{¾qïë·D·Š=ñ¨—=ñhËÌ!_ ” @èZ@Oƒz&ÔHjz>Tw$µAóÕ/ÕÚ´_‚õÌé¿©ÙüUÔ¤BÛÑÖô«-Ó–­ë#Èö@Qƒ å¿4B¨nþú¯ÿf^Ô ¢†G¤·UÝÊRÛ’ÿRÏm÷|ãÞç·Ä² ,‡ € p¶€ú¥úO›öK°ž9ý75q*l €cHD !T7ýן¨a GœÐm Žb#€ € € €„+@èd € € € € tè£Ø € € € €á º…{l( € € € €À@Ýzà(6 € € € €@¸„náJ† € € € 0PB·8Š € € € ®¡[¸Ç†’!€ € € € T€Ðm Žb#€ € € €„+@èd € € € € tè£Ø € € € €á º…{l( € € € €À@Ýzà(6 € € € €@¸„náJ† € € € 0PB·8Š € € € ®¡[¸Ç†’!€ € € € T€Ðm Žb#€ € € €„+@èd € € € € tè£Ø € € € €á º…{l( € € € €À@Ýzà(6 € € € €@¸„náJ† € € € 0PB·8Š € € € ®¡[¸Ç†’!€ € € € T€Ðm Žb#€ € € €„+@èd € € € € tè£Ø € € € €á º…{l( € € € €À@Ýzà(6 € € € €@¸„náJ† € € € 0PB·8Š € € € ®¡[¸Ç†’!€ € € € T€Ðm Žb#€ € € €„+@èd € € € € tè£Ø € € € €á º…{l( € € € €À@Ýzà(6 € € € €@¸„náJ† € € € 0PB·8Š € € € ®¡[¸Ç†’!€ € € € T€Ðm Žb#€ € € €„+@èd € € € € tè£Ø € € € €á º…{l( € € € €À@Ýzà(6 € € € €@¸„náJ† € € € 0PB·8Š € € € ®¡[¸Ç†’!€ € € € T€Ðm Žb#€ € € €„+@èd € € € € tè£Ø € € € €á º…{l( € € € €À@Ýzà(6 € € € €@¸„náJ† € € € 0PB·8Š € € € ®¡[¸Ç†’!€ € € € T€Ðm Žb#€ € € €„+@èd € € € € tè£Ø € € € €á º…{l( € € € €À@Ýzà(6 € € € €@¸„náJ† € € € 0PB·8Š € € € ®¡[¸Ç†’!€ € € € T€Ðm Žb#€ € € €„+@èd € € € € tè£Ø € € € €á º…{l( € € € €À@Ýzà(6 € € € €@¸„náJ† € € € 0PB·8Š € € € ®¡[¸Ç†’!€ € € € T€Ðm Žb#€ € € €„+@èd € € € € tè£Ø € € € €á º…{l( € € € €À@Ýzà(6 € € € €@¸„náJ† € € € 0PB·8Š € € € ®¡[¸Ç†’!€ € € € T€Ðm Žb#€ € € €„+@èd € € € € tè£Ø € € € €á º…{l( € € € €À@Ýzà(6 € € € €@¸„náJ† € € € 0PB·8Š € € € ®¡[¸Ç†’!€ šÀÁ㯆V$Ê㮽öÚw½ë]o{ÛÛôß;v 3]ÙÙYˆ‹/¾xºÅ(³÷JE=÷ÜsU/­RfË,ƒ €@ä„n‘ŸT@ —¾y3„ZÕAÞk;:yEÕÁõ«iu$t«p»dQ@èÝ¢?@@ ¢À›ï|± wÄXo–‘)>(nìæ‡nÊ;2k³ʵƒKçn‚…‰ ë´)×Õ%h–ä"7i©?öœëÜjÕ´¤Æ-àÇC‰9O-O±&{þUr« 5è³"Ù’ú‹¢›q"ý~ñ™e±Þµ‰ÕÓ=yýi(\DhePý׺`§ª…?ôž«c"…ôÑ\â™>7Ê„nVÔDeÝ´i+’ÒÕ;‚îØ„nÊjýãb· NaöÒŠwMGˆT€Ð-ÒOµ@¨-ðö¹…âÐ-üVoÖ]Ô‚žâvU.MsqXf»$C¤£?¹›hnQý´EûM„J‰('r þ®—›€Õe‹V<ý“ ïÊokIÀ•ÜþN-t³—µM³¨Ñ…2™ï'’»tÝýLÇ•ÊÑ’Öµº$Ú…¹…ýé_‹kÞ©µã3 {Yaü÷¡žöë÷v³ÜúçF™Ð-óÜp‡ ¶ºèÓ¦öt“‡„nå·5t§¡ÛÄk™@¡§ €-lûã_Þr×™i=ËdR^fvBK7¿jïÛu\ÃÀµ@Üö&¬“]qô–ÈD2§S°0N/‹¢ÒQ‹ЭL ,ý)Ó&ÎßZ^¾ã¸¥#—!¦;“¦“ º¹6t¶we¾ŸÈŒ B·D}Óm©\K:—'º­ÙAñ PPk­åB7§®q™þ5óý‰GÄvê;— ÝÜ~ýÏo½è¿o›‹2ëAUП*$/tsMà.w#t+s9³  €„nœ €´ pá#/8DûÁ ^qäƒ1wS àºË¥Û|¹Í…G.úñÏ‹B\Û´tÔâZQ•9Ï2ûN\±8tK$b~Î’™‹¥Ûô¹6V‰¼fâûÅ%·üËo¤fË[²ã7”+`I×&.sïy;-~¿£ÐÍ…€þ0m–႟mY½\HZЂ2ïfj»óÜ?O,øËl«˜ŽD'žŸ,€ €@´„nÑz*Ž ЦÀ¾…W—î~yÑý/Åðgâ˜n.ÂSܶþé“'^m“ºõm%úÍù-¿Ò¹†%‰ˆÄï Ù0tsý^•€¤Û åÕ½8tËl””n æo<¬¤;6ÚÂUßO”ßö’γÒÕ)z\+<·t£³tÕÒ;Í+LÞûÚ¦š¡Y^½êµtÓFcZutt,LtAX¢A¥VlåšL%pB·ÖoAl@`Ä„n#>¸T @NÞº}rGÚAÄm¾Ž?B™{?ºYû#…$’‘Ìü¢Ò˜nÚB™~¯‰ãZ#t+N¦ÿZ5\Ë[¾aè–×Ü,‘‹õº ÜõMvÜÕè^*wþXªkMÞ Íú{¦{Ñæuó,y Ý:¹E²Q@þC€Ðs@ª ¼ikјnƒ‹Û\åÝpø.ÜIçen.2ߢ ¿á[:ÿJo¶ ·Örc“eöõ7R;tKÏi› ³¥[fÓ?ו²·–nÖÄLDj¤f34iéæ´­vvÐm(7¿?©íÔ?ÓŠ{"—<‚„ne.F–A@ ¶¡[m:VD@ Fù“¯å 7ܸÍÈD›©ÌFj.ìH´QÊË/\*”—pœFêmjE*îjZ#t+Ó9Ñí4–n™­º\Ùs¶æ5«Ú4±¼;è‰fwµ»—êèûSÖ¦[·ÙicïûÓ´róNÚ‚Ö‚t/ñ¾O@ê ºÕ•c=@¢Øqä/éÐmq›¦å)þ(c™¡››Ø1s2ÓÌü˵Êë ™ž”Ó\Å%óB{¿`]W‹ôYœž*tê¡[AÀ”èð[\kK¯2’+ù~ù|³Ì쥆ïÀmD?ÎZ³JÌÞw]Mm­VŽ`Þù“®3Ð-Ê?•F¨)@èVŽÕ@ˆSà’ÇNø¡Ûã6¥Ê¬Ÿ{i^Îô¬—yñùãyY?S÷ÊŒZ´/[EÿM,¯m€0ËãÒ-ÚÒ=XÓ'^ù$È­›×þÎ9øíò¦º¹.º —ùïw:¦[fÔåô›×•ÝtPìô°¨Ë¯‹ÿ¾z³ú‡¾•#˜ºe‚;íÄèuqÞ ©5 €eÝÊ(±  €¼. yHÝÔ¥CŒÛüˆÁ†¥W2¢—&—£ù¡X^èf­«Ûçåö¾K1,zS¼¢ Epaœ–±–MzSÉŽ­âšÈ4…³Ø.³0Åñ“­å;¨H®©önãx)Ѱ6Sz%z›º *oÊü'›³2Ó!o[X[Sjc;Mw5µ”¤,Þ©Z¥i§éÖpzGïûmÖ2 ì´ß‡Ìúæ9ø¸2h_™ÛÌ«ŽVTœžþ’Ù°¸Öy;­ú¾+†KSŸ ‰cabéÙûyÇÅ6ÒäÚòvá¶ìÎUãÇ€Z € е¡[×Âl@@@@ :B·è9F@@@èZ€Ð­ka¶ € € € ¡[t‡œ #€ € € €t-@èÖµ0ÛG@@@ˆN€Ð-ºCN…@@@@º tëZ˜í#€ € € €D'@èÝ!§Â € € € €] ºu-Ìö@@@@¢ t‹îSa@@@@®ݺfû € € € €Ñ ºEwÈ©0 € € € €@ׄn] ³}@@@@èÝ¢;äT@@@@ kB·®…Ù> € € € €@t„nÑr*Œ € € € е¡[×Âl@@@@ :B·è9F@@@èZ€Ð­ka¶ € € € ¡[t‡œ #€ € € €t-@èÖµ0ÛG@@@ˆN€Ð-ºCN…@@@@º tëZ˜í#€ € € €D'@èÝ!§Â € € € €] ºu-Ìö@@@@¢ t‹îSa@@@@®ݺfû € € € €Ñ ºEwÈ©0 € € € €@ׄn] ³}@@@@èÝ¢;äT@@@@ kB·®…Ù> € € € €@t„nÑr*Œ € € € е¡[×Âl@@@@ :B·è9F@@@èZ€Ð­ka¶ € € € ¡[t‡œ #€ € € €t-@èÖµ0ÛG@@@ˆN€Ð-ºCN…@@@@º tëZ˜í#€ € € €D'@èÝ!§Â € € € €] ºu-Ìö@@@@¢ t‹îSa@@@@®ݺfû € € € €Ñ ºEwÈ©0 € € € €@ׄn] ³}@@@@èÝ¢;äT@@@@ kB·®…Ù> € ГÀîÝ»7lØ ÿö´?v3@ýû÷—?C´dù…ˆA‘@èV€Ð­[_¶Ž € TÊ Úª‹vªW[[Óvnºé¦·½ímçüÇëÚk¯mqãljLvž”‰Ò´ŒPeuA@ -B·¶$Ù € IàðáÃ_|± ªô½Y•r1{_/¥Z«wî¹çÚÂ+W®Ì\xvvÖ–±,Cy×»ÞUfËwmÛÔÆUÕKíÝ&®Âq ºÅyÜ©5 €ÀTݦÂÎN@@`šJÜ,z°ØK/„ùz`¹¶cZ ¸ÄʹÜÂÚ`zaea.ksYž½“¹|y ÅvV—ò«°d´„nÑz*Ž п¡[ÿæì@¦, a–Rù}Wf&R¨ugd%@κq6 € €@-çŸ/ ݽ©…‘¡ÌoÄ”îšh”GÒù—ËÑJ*—é÷šØTqè–™Få5nòs·bÕp-oùD±]KC…>ú{¢Íïà7³„ÈOÙò2#w5ZºeºÙ¾å±ÿ-Ó(ÌN3wŽ™€2\kSæÞO·§K¤u~Õ\#;×-¯²™¡[A²FèVòše1@òÝ87@h[@MÀ4¼W þ·ÿmrî6œi\”h1ä78J oŸxKgRÁ˜ne&R°sQq!N™VoµC·¼Öa‰vU…nª©<ýpÍo\–˜ÇÀfð_®½a™&f­‡néòè¥fÅð%ÎKëäHoÓ½Œ‹ë˜øWB·¶ïél@š„n5áX @lë¯/•Ceކ6î7ƒëÍõM´òC7t¿ëeºU:ïÈmâ¤PÉR#…e&}¶ñ‚>‰öO‰î´®H‰›Ý…n¶GÕÎ%ž®£nq }½DgØLØvC·â®¬ÅGÖdÖBÍ‚Äû™g]æ~ÓíÑ*…néÓÞ•Ÿ–n/R@@ X€Ð3@V–.%tËxßûN<Ø*w›Ë릗ˆ?ܰý™ÑFæ›–§ä%\e2šz–„néÑ÷]1Ò]‡n¶ëÄ|é¾½yPÅ]em­¼­ŒéV£[n™ÓÑJ+ëRê÷ÙÑSsØ6 ê˜h=ç*[œ¨ús#äõ]%t+s@Y@B7N@Z˜Ÿ?}õÕ±üyó›Ë&ŒŠÛöìiºþÆÔ´ÇŸ ÁmÈå2®hfRã¦ìÌl`UÄåMÖ©‰éÍ\© ‚³DÉÓ!KÁº®iŠôd ý„n ºÌi+2º ];õ¿³³³¶Š›94oä8?„*p³¤L‡¾¸iÁÙé¶`㻹ýº&¦æ°MåÕQÿ”Îã*µts[HOÉêZ2{iýÛ k"€Ä-@è÷ñ§ö €4(Ó6¤¸Íêj‘„"—7)ˆ±7ý–GnÉDK7R$æ—ô7ž—Ù~Õ4ɺ‹*ËP˜báÞQ1´¢?o©J˜îÁš>b5ÆtsµHŒç\\eå̬lÕ÷ý’«¦~S2«{Âßâ'•0‘ êý„È5ÍÓ\¦&F¿ó¦víÚÚ2~ï]?ür2y­ Ûq•Ò•WN¼ž\iÝ€nnÛ²½Ÿý:úç­›¦Ã_¾jèæf’uå/À™XA@@'@èÆÉ€ €µÔQ´8t /n³z*N²t߆Òþ7ÑØ'¯O¢5VÊl¹Vw¸ RÝ®Ý_\C»(?r…œåÔ Ýó¹¦Lô¸=útº™¿ÍH××/¡-æˆü³ÖÅF‰ŠøÁ™ËýèPÚK¶t3 ?óKU²±«Tbyw†dnÇbÄôy›ˆMUª¡›Vñg’uµËÄ©u³`%@" t‹ôÀSm@š hzÖ¼Ð-Ô¸ÍUYÍ‚”+¹¸D)ƒ5@K˜(žÓ2énwZLoúíªÜжJ^LfM´\0¤%U ¿Rzt©ÒNáˆm*ñOVG75AæW@“pHw8µfhi‡ªïûкRrúK^˲D ­¦é™%t~KF·_›,Õvªl#éC9Ñ-]xs.9A­C/¿9¡ÅÁö~Ez¿™“‹OB«oP;u‡£§é}ƒõ@ˆI€Ð-¦£M]@hQ`ýúŒÐ-ø¸­E6… € €@¡§ €Ôxç;Ï ÝˆÛj)² € €ÀXÝÆzd© €] ìÛw&q#nëRšm#€ € T€Ðm Žb#€ 0U+®x=t#n›êA`ç € €! º…|t( €¡ Ì̜޳'ÔÂQ.@@¦/@è6ýc@ @@@@F&@è6²Ju@@@@¦/@è6ýc@ @@@@F&ðÿŒ,x*ZÿØIEND®B`‚trusted-firmware-a-2.2/docs/resources/diagrams/int_handling.dia000066400000000000000000000245771355360272700247760ustar00rootroot00000000000000‹í}]s·’ö½Ëç&©¢`|,7g+›(W9yË»çREI#™»©"©Ø¾ÙßþRI`83Ä€¤ÔªrÒ#60Ä<è§ñt÷¿ÿÇ·»ÛÞßÅt6šŒzK~Û+Æ—“«Ñøæ§·ÿõù·ýö?þùæß¯Fón¦Ã»žýñ̽úéí—ùüþßÞ½ûúõ+ºý>Î'St;z@³âÝÿ oo‡ïìEïÞþóM¯÷ü®†ó¡{oñîp>ŸŽ.æEo<¼+~z{1¼üß›éäa|õ¶¼jqÝåäv2íý=¼ýéí?®ýÏÛw‹y·ò9Ÿ}?¼).¦Åðãí1m>ú¾˜®ìÝýd6²—Ì¿ßo\ù÷ßg×,®šÙ‹Æ7ÿüÇÏüåo<}Vh Q#ó»áôf4Þ´cïÍmy#(Ò”R{3„Ñ+®Èòž47w‘×Üm^sÓ¼æF³óûÉt>Žæ›&/&“Ûb8.­Î§E{;³Ëá­]bUÓÚa×£ù|²eü×ÃÛY ”o?>mMŸÜ›éèªúÁ]¹"ò)_GWó/çß:º]å§ïèÓÿÍF·Ehô£ñ<ÙÇOóñëߎGï§_ßq5”ŸÝ®t! Ñ|{¸y]³-ËlõšÈ'}Y\önÛ]_¿®î)ßZÛ¬½‰Ûá÷bºÜ§&ãóYqyn¿Áó‹›·½Å—¼@gwÂíå÷+ó^y'üÞâÝÉÅÿ—óÅíùívòõòËp:ïôþsòíí“Ûb–ÑÕOoÿ^Y`‘ûb?ÓèlíÒÅÅ÷“Ç)•¢B"L‰ç·»r‰VÚ½¸›ÚYÇ7·Å£i²0­•P¸}M Â:ÅHŠÛâîür2¯x#yî‚·íÑ,v'ñÌN×<ÿщ¬)F7_æÛÌs‰ˆâÏÌïnýb2½*¦õfÁåá" M6€Uˆ[ÃÖ'¨SÒhÊv·:ë½V×øZíntöeòõ<@%ê{Kíì–Õùtx5z˜mÿ’¥Yý‘»à~xuµî·m'xšçÅ·yì;]ÝÛ‚Wƾ;ÏmW¯‘¡ª5¸c:Ïã¦Ý¿ö®‡w£ÛïvœÃñìmo6ÿî¶=»•ð{qûw1]×ooû1E+ø­j¼úÃÓ #´k†ö "¶û•P.ÒYH”ÃcœÎ´%B7㻢jaㇻ€'[ÓnÐ5«ñ»å?•^Rµótfý‹«áôÊúNŸÝ£ø,æ³pžHJçÉ.Ì­Û`W‚Îì<-MK$û·ÐTø±È$cÙ/è~`€{›Î"ÂBIªņJŠ…Ù ìU¬ù—|8#ðÅ8¯pøá|hŸ6Œ°å»õyìÆ»íø- Ϭ.Ho.Y…³+–‘qû—שÃX­×Þ¾²är@Rƾ$H‰TéâºYîGáÝ@1K¶—”— nÿ¨„cˆ‚éf¬zéC*.° :Í *Ùoþ»Ó0b º©š ¯H‘Æv˜6úRmðv¦·ñẌ¸õ'­ÃJÛY¬r½jºi͵fü´Æ¦ÜÔWKä­µY…ÇÖ–«¶LÌq ¸nIæ8³~$i‡÷ßypíPíÅÕ#°u<È*_n›7!²í¨,Kí'i¤¹_l?~Ò£}£©÷“ÜA€}ƒ"ÎÔ BLKn{ŸÆóÑ]ÑsWÿ6šÞ}N @ÒcAÒ-OÊkÂQ¼mÆ‹·3ã–°äÇ[°üÃh\8/O–\îóÄ>1¹ã’±’Ýj¡ÔÀ E Ú§Úö’'Oãñy1¾òÓÝùVsìL$OpjWÝå}xœaYH;3·v]Õ=} 3®–6÷wÎëÍû}j[(,Áý½ξÜã›:sÇy©=J¢Ê`1GïÅ¥$S@8 CdNl?±·.îH³àYq¡´ØKðM‘g@N9ß øÁ7¾½\ÊH1Âbo/$ö&“{JÑÅòØOðíiÒEßìr5² ¾™|û|öñW@Í£9²ØòX@¤ "mÍ"m*e¤m¹©“= 2oÜ"´tˆMÜTÛ1a–=ÔV}/‚¶1e¤ sL!Ò‘¶Ãˆ´…ÞŠ…ãØôfn`=èYxN¸}Êž’§VoCÕM¨:!̱V +­R'e+Ó¦\ÆÛu ñ(Z§S†ÎÖ•·‘–‚^X(%K<ù^dGÃA±¦ØÑÒt,kåa5µ~…j+¨«ËÝÌU¼ê»šZ¬Ê»jšuÕÔv8À¶ ’›Z оúô°5¬Hkã"G¨`Øf4u#óµ¨_«ðl­(ˆ]´Ò¥Ta“(âP;ãwmŒVñºí‘°)ÈåâåÂŽOsF‰…™”ŒêIJªµÏl¢¹3ÒŸŒ+„)f­üqQ)’£÷›UÕûs2î—ÓâÍéüîô±(dZd¦Õ¶G¡ý ×êàr­Ò 9N}>qÂ!¥níå| @>f-Yd|¯BŽ.nH3!‡<!_á„ ä!9^î‘$.%„ a©@Çqä:B’;J1¹O!ÇÓtIa1]è8^Zþ9™ÞYhø×dz{ȹ9±ôÕaˆLk.÷…œÛ s€˜£™˜ƒÐ”±Gü˜[Ìᤘ(OprŒ(ÇX.ôÙÕ•÷"x9Ç”ñ>UÈhyS æ8B5G’ò¼„%U˜‰Ç*¹8÷qˆµMeq±¹¤HDïÑu…Þä÷¡A‰^ޏxN=Yî½Öƒf^BÞ–VÕè-.®Åµ„½íG5z_ñ êAÔèeqîJô*¨ÐÛåáiÒ ½Ika0Œ¸Tb?EzŸŒ/Êô2ëQé—S¥·”’ôN?Àƒ”l[ý !r½;kM’W ¡²¬Ë‘ÚOÕ7€²H‡+Ñ;°^„,ƒaïGlÒÅi"6±è±¢óà Ä& 6± ˆM@lÒmÕ2äêÎL ¹ÉÑËM’× ± d!G"û‘›< @¹º!–q0EE¦_ZáÀÍ#ÂÍÊǤ& 5i(5I[8d¹¯‡9e·ÇºÆgYzÛ¾(¦qä’ê`"C÷eCªïDø¸®HA èL:Ñ™¬½Q¾ô½¥·všþbÁÈw¥oÒoº)žém-¸CX¶þ0º"D}´\-iجsz»""9ÁˆÑÆd” >ð„íKDµd¬ý*0«æŒƒ’8‹²öÊöÃÚĦdÝê#xT‹ZØÙÄ føÓÂä&îT¹Í Ø…r>œN'_«>Ÿ$øüó¢5ó¹Û®ñ%´ïjàŽ˜v+ªnRà£pÝìx÷ðèM¹‹“È9äáf«4º.ÙnB³WÛâ|:ý\Á°›ûAV½3Ÿn>Žz:¿ì¹…« ¯Ñ¶Î-7ÌŠ››‹3ámx«Ëà½Í ×m±mÂÙ¦£™Ä¤8ÞaG%‰@j-7²#‡P1£¨v)'Ìu›Á‚Ø×®Åhw06áˆãè®$»Üp Á%—p?.!%) ’ A„–ƒ4/¬qP–0ÓÒ¶ ô¨|ó?~éýðùìãùoï=ÿtzö_œþ¸_ñn2žÌî‡—Å¦ÃøËäa:*¦/Þ]Œ®_ð_¨ÇƒCšOˆõâ„%®2>ZsÅ;.Ýeydhø©˜=Ü®šß›…Û~[óÈs~4Œ._@ÃEúÕÜk KXÎkÑWÖ=£‹¹;›Ò¢Ÿ…BËœ­i;‚Í]ýXJ8¿ÿôWïôÛeq?·ßÔs>„zÎ뺭áC¯èŒ3Ttn¢®©VÖ´)CÉ“Ûï±à"O…”Ø·œX;Uí%í$­=Ås(ɘuyß Âß± ¾½_çA•LÍIž7;Zb!s#U½‹5R¦ÞÅXÚio½k:í¨¦–¦•µ¥Z‚ÒÔLT~²Ç|ŽÉ.d‡j¨HæÛØÕKÜ#óõ©qŒ3Yz6.îNü‹l=j’͹vƒšpy¦v5N¶·b˜¾Šv5üB`v‘­]M (Ìß®ZÆÅèšbX—Ì»ýï«a{îÓ4H"“9QK&uÖ IiS•AލPÂïëÇ$)ßzÖæýx^L§÷óÞïNu\LÖ"r_ì99ºÈIk¢V_U2|¥þ(ƒØ¿ò1µG›DìšÇÆý¿9VtÝ"aü̇ŸñÅ øùš"Ï:]äKáI8c ‹8)¿¦Þ,Æ.˜E1Fö C†±|èè܃Á/£ýÕÁ ÍÀÕîAeˆ×»—WkD¿Ž@´Iˆf$ÍÒi‰fþaÕe(Z{ ¸ÎŠN5kˆEC,bÑ‹Ò?§÷øŽ!}±h†SúÚû¡XҜ΄öœÖõ0_8…ðÀr;Øj.d4ËB©XãC9þtG‰Ä,M–FJоõ«IŽ,9kpÝwKž†Å€$]*1F’bnò$G'¸Ô¸è®í…lâÌÙĵ’}$û&ÈÄaL’Ô3Ï´þzy¸ŸcŒ6ÊÙÆH0Ø+Ю®Ï0±†w©P¯æÕ! K‚0iËј}ˆòx1†jjͬ•-uɮʺ0y&6áÙ+ x0‡Y…C=”#«‡’!y „¤Ø{$Ƈ´ºGH‹9!­=Œ вñ¶{mÉ‚Ñ ’”—DDDî"èX²Ä:_Pî„ -²É¬wçº*øJíâåš8¾¾š!ÝœA̰ìÉL7L3€˜Ä pü—çø`<ÁH¾õ‘©d:OBÚ]Õóæs$J‹R÷iòýŠ9Ö¼ì©ôÐòÒÿ¶S¶+ÐìÐ,ºÄAÉðz²éj°³dÙt±úAµ<²s!-*\hKš>Û¨mÙ%;K7çƒgg qòŒq¬;vþLÆŸ\ô)ÂÈÙA’³dy§D»ü„¸vr¹‰¥I%ÔÒ2åè™+iv¤õùìã¯=×BÀ]eN)È]ÜÀË€—=ãe&é©Ù¦ê¨ëC3kÑ’¢Å™™@†d>3K1ãƒ'eÑçGfœÁ‘2 eàÍd=2ãÈPÈÿ=DRÆq:/B¸=•°|N„5Hí®Vvkªø´¬ø6šhÆÉXx)öDÀ8IJÀ}p»f`Ö¤”²E—'U^–dÒP„ H0 aàÏT’0"‘–ÀÂ’…Ñt®‘‰* 5ð%¼M§ÿpÎCÒP?s´=@½xø-ºÐ¦M{FÓXBýb¸þGÇF_žD8lu FŸþ*2–ËM8m`jÀÔ€©S¯¦BÃÈ]ý+õr“©ñ”"FW¬V&Èo$ctF…ß̽’;®¦BõAÊh¶³”1¶Ä¤I{FÒ’•!Å„rÊñ&zFbú”øWÙ8ZºYGŽ 8x5q¬à1’ Í’£%¬ÂŒcãFfó$JƒLzGÂá6uB@Õ¸µû‰Yx1{=Ll{ [ž®Ü‡¯Õj‰ËÇÄœ’Q¿;k­ô€ÚEïz–ØQh¾+ŠW”´m4û@Ø×¸6iîâØ6KÛV·=бû fu›Óî8¿pÉÛÔ-p+ ß6ß§Ú›¯õM&¶^¿ÿ¯è®wÌUMVÁœˆp’¯dÝÒ&F\ ¨«$æìmM„ÓO§ŸÁU=ˆcÐøbo¼ÕgÞj²"ÎSšøJÚ:Ÿ¼kÑŸæ„"ÆLé¯ú×ÖT:£»Z9ýX§š$UÇÁa‡ÖcqXE²|qGÑeYã˜eÃÛ'£Š¹Š í»7ì ùûrZðå‡ÏgÏ?~:=ýããçÓ_ÜŸ{7Of÷ÃËbÓ‘ýeò0Óצæ‹.qðcß­Û.:ä讽×N6#Hh¶õðxs¹2ê hr¤y dYù%Öå0,¯X0mÿîSíóÈvG\EÓù-ˆji6J"•Ê^7ª5knžý(³»ù %MH>¤|A25¥Ôî¿Å ÓÉÆ†É ¼¾¾VW»[ kF z©¯|ÛÕòšz›6vËgé|:¼=̶}Ï®æúêÜ}a™Ïv¹­¸ÃV˵kêÜ5‘ülÝÌ›ùsI¢’mÇuéÚ9um‡vì…@ܺvT’œw±sï8xmMW9yuAÛ]˸«WíìÙkKþJ“zL¾{JŸ*„‰Êì2-LKD…ò>“%´n$”;æY6Û›³‡»bðpœ0¥Ìúnœ ,±6bèW¹î_>úáŒèׄìn£»-`6px“”Á²ô öD")Ô>ìÂò‚ÁžP멨½0Ød·,0X`°À`Á¾P{‘` ìñ0Xž˜Á2· ÂŒfg° ÓÊugd ßôÖîëDÉ£Ç=ÿŽ£²£Yï½ßÅtúp?/®•ÒV<@i_6¥í°´ %Š®²€D,_pg“û(£«Ã0bþdVè|õçNûÚ5=ï¡Ë8‡ÚPÛj@âE&ÅšAŠ»¸¾„~Myj¤‰¢Ë”œ°"µcJ¸Øê‰ßê½·a_±`¡n£è‰oAý(ú6Ï£ã˜ú6ÿ£ë˜úV/¤û€zÈé< òHŽ) álgï7œí<»YP$豎(š­’z. )âK&)™9šýdšøH E\(Ÿ*å|Œ’¬Ç~(½Ç«ËŽ(‰ ‰•O„´A¥U¥uÒ3G\Vw–æå>s\˜æ¾í¤CiW³Ä„?Fo-_P¼?±Eå’(~AP¼a?Nn¿GŠ™“8Ч|ôLèüQ<©”ò¶‰VækBù'vÁŸØçþ³ãavü¹o0ùà3ì•?II¹©q¹C³÷ ׸ÜESWXI$¨+µ‡RF5* ‘\ån¶<áÊßH’êùd‹Ú *pºÕÙº4ªe¥ä’7~´åoÞúëüìã·§à¿9)AÕ©Z(âØF½ iò"Ž©¬n]nñ¬Ô-pº¨¥È²ê$ÓMþà•’ 镜,BIJ‚P„’Ù„’%­cHrJb(É’¹Ö‡åŽñ«|¥õK“ 1éN©˜¦>7I“ãmÒÛR@– Ò¢«èеgt§LhsUä b8'[sRœQQ’5Z†ŠóRµd?‚œ6²¢)× ¨P5 jà×d£jî0еHÀÔ%©m{o)’Êa˜–gÓD𼂏ëBimKÍ”tm~8çÆñ;­…ä)*ZU4ûi|7‚óÁeë¹(™@Fjû³¥ñÏQ)dö—îëг2¡­óº*­[Á.ƒ¨yÓwCÊä™6m—"SîsLàÌ÷hÚpaÔšp+ã$æTrús2î—ÓâMïý²–Sï‡÷Ÿþú$ךýRù8€äú•tZ{£|y;ü^LýËÇWK÷d2>Ÿ—çv9's矎f£ ÷ŒyÖû¬ßOSÐÊx¬ ÷ë+Ûu/ë³õF‘»VÚC ¾4C°¢!¢Ï¢ÌΠ•Õ5l®‡ßõ‘{³-`Ÿ”€ý ¯¿ØïÆ:g7½ÑØWæûú¥÷æ_Š7öº©}¬z3÷£ùw §Ckl4[€~ï‡_ÎÎz?õpïǾ{×®oÚ®¦yqÕ›Ožm|(þ.n{¬÷ÃçÓÌýÎ=k6ð¼>ÿùxöùçϧ轻>º¡4 {6‘·¦#¨$––c¡(ÅÒzÁÌ0½«Jx[Ø9üü´±U+2ÚšŠ!5æo¡î8ßäaÞÀö8ª?vÉ·òŒ/n* ¸›óŽd=Ú AÎ#A"[{a× ×Y”NŠOHß•,ÛR —m7J– 9EO½¸8æ‰U¹ˆ_² ×f~ ÉÕÔ``~/‰ù¹g—Àü€ùó;æ'\í4Â6@üø©t•*á„:‡™åb~K“¾ºÒ@#Æ´²ÌO+ËôqbÖs Ééüîô±(@Ù0Âø J”ð%LV¨ÂÆù£±\€ê°ò,nÀ %!ÌÅͶ.´ûÅÊ1 áÀ_,.®Åµ6lØà•ûˆjO)ÐÁ¤ƒÉŠa0†0s}š±ý;—ûòdS_·P ¨Ž²ªR˼ÿÅ—4Àã'€ ¥ÿÝÈþßUöo4Ýg‘5ÿ¥ ‚h©øgNð¯81‡/ø?;±hÚUkýí¯Ç¥þO)ö²…àŸxñ¾û×€Ô?¬é_×ÿ“Ñ«SôN©áœi"¹%¦¬kEàÑ9ÿQÈù—é:Ðö†—óÑß `Wì »^>AìÚ2]&[•VœPiqqø¨ûÊm+ÇNmÁåà–ÜoÔxlŸZ‹/³Çkù/¥ßQ.ÏùÄ¡öÿžþÝ~¡rÝÚÆçnzµ‘즆U”\¿uBë+R"*ûaËמ…ñ/°&õÁ¢µ…’}$“L ˆ@RJmÍ £‰lo¿¢^JÍùU„öRBWš m³2JEU”f©†R£J ;›ÇÍ-Z˜ÜlVRÅ+›—U© ¶üüP)•fûP[Ã5¾±„v#}_ª%bøŠ´qU„4˜) ZÚì‚Qµ1ra)BÚGW9Àâ»{ˆ5£M¢+¾äoïÿ:ÿùçO¿ü.ù;Fkuti^’"Ý98Ú|‘ÀhŽrIuj EWp;“5 p…c¡ÍÍÅã Û¢ [K" Íž«@ô³Åð7¢ži\F©%ÒgH©ÎÑÐÕÚÃF8c–2 œe‰EŸZ’b‘Åa Ï6x—ndB·xˆÞ"9pç&…¤-]~(uiuî /Wz¨5Húd` í7MÏ–jªumòqé—?Zd+Ý­ž—îæ”¿ A›fÃ+R@én•¨l¿Å%¼'eÑCÝî•étݪ¹OR^ó„»t¼A‚Œ²A"¡-E@Šms¥_°°"ëdd/NF–*¢IŠ qÁE=Œè<ÄbmaÁuß·`Uf@Ü ¦.’Á Yb,‘ù/¤Ä ˆ²@”e/Q,q°>Þ(µÖ]ýPjŸ/gˆqÇàöyËV=4ÅLëGX(~è Be‹°è¥Ã¢¸Àb×ôvˆ°@„",@Xê–…!–C ±$ËÛ#1GMi6çÁ$Hºö ¡œ¿N·zgïÓÃx>º+|ûêßFÓ»¯Ãi0v0YÜwy©q—¦Q–Óï¨@D:%¾6¬ÓL‰gÔYâ\r§`¡SWb›cÝ2ù/Y©9Ë ã …pWÖrPëA•hH¥É‡Ã)[ Ac ë« ¹jll=„²ö´ñv4Ç}¥VŸ¼)en²m´3¹õ›Id1{Z3Æ»L,Át-±„l<¯_'¿ÎW·MKiŠÄ»gä- ‡ Œ™êŠ%æ¦O,É&Lz(VD;Ë\ Þ1ǦmŒLë­ °8 `2Ì]Qm=]N4Cµ5PĹPM¦B5ƒá,ª¹ÞßZ=¢µŠÆ"ª­O3ŠjI£ÔÔŽÔˆÜ Ôôž@M¥!ÍÔri™4[KœZ’æ>eˆ)–…1oL1Š|îJCÁMÊ ”9;eÖ;Qf’Š2ï.K’–çkvºCݹfÌšÂÞ”âF ì+ÆóYyDä)ãžlð:²›‚f 4cûÑŒ%ËÌc±¬™yΠËÌcºÔŒél-§SMµ®nL ½Rð=Ióš™y«•æ èÆ@7º1\ä\,¼)Š$”{?@Ù˜I–™Ç8R2gf^i°Ì̳«Ìpzä©yXX‘u ±W¡Ûη Ù5Ø]‚í ¥ƺgKJÒëõª|»Q0È­ÒO-Ȩ6 ‡¯Q‹lmàÒz³.Ä9UZhkÆõœ -•$æÔUt;–6`‡_Ì.ÚÙ3¤¤'qV´5±²É„ªXÙ~­E¶Ë2# aªå˪²M:¨²ÝÕ¡†¡)5ò•tµ¨%:Þ·t›$Í“þ^³Â`¹®×·m8È€ƒŒŒ&Y ›w¸à>ÍU$È&¸$ôq½î³–L3ÕúùïroáÎ1à‚{ . ¦ê7 §IO1x²S ¿Êxˆá¥ëH31ÐHp‚!Ô‘"ÕŸ“é}\ÿ5™Þ^j-PË,¬»" Ñ‚iÍeÖÃŒðr†³ 8Ë(S$9ËàÈ5e]ŸeX3Ôš)Ï2\÷¬Ö6fì4·ƒ;Ìàh•EI‡p˜‡¯ö0Ãe*à0£óÃŒwIÒkó#†µ–î ÕRRÞù¡Æs‹TÊv§$Zr× Œì4‚ü-åʦðï—MáŸ]úÃoïÿú:Ëåï,W¹¢Û™…îrw—ky ›¤›&A”êzþ,p÷hw© µx' 6b ¥ŠrW_…)–©¼y|Î>S6(†ç™Oyku–Ðx-,M’\ÙEso/òÐ,CS_Â5íSîŸsß÷»¤TáŸg èŒ#=ÒAhÏ㎴ó¹1)PÒ Í…‡-cÝ‘ÎQòÉ#T\]>ãÑ„…:ªæç§ŸN?ÍOGã ¸èKêt¾ýÌÌULç':âÆ힬ZsØ™³Þ¡¢®—ÂeÍPÁvP@Ç„Š]Í6¢Slp¤ÖÊbœ6LšU“;L2ªMìÒ;Œª·²5µÓ#&÷±«”ˆÛuˆÍl…4ˆ­ü´ƒñ4ÀËÈïe,ºìŒ(×êåz¤C/#Ñ!˜$Úç1¼¯Ù Ìêïó sL)æºñ))Ü™œ¡»XßÑùÀz§ß.‹{_boyåÛÙN¦M{€¦è:ôÚP’üËH3‚ŽpÑÇœ½5Î|'wWxŽúWݳŸDSòäÈŸêaP/H´ L˜À}öË}X’-žÙµÄ<ŸÅ”šî7ù…=ƒ8Uf@5âF{óÖg5Ç„?ŸÏ>þº©GüÝú³pŠ/eà?¯ÿð„@ë1»=ÿq ;5y<þáÈP™ïøg×¹2âB1®„Tk¬€ÿÿþ.F›ÃްÑÐ~ H²Çs¤ wûž2CFœݎ$á¢ÆYWXòc;ü)¾æC{€¡èš¢ó’ˆÎö„‚“䦺ŠêŽ9+¤8ë¾Úæ²Å£µG¥ægÞ4¢ çɈˆÏ8ÞçÖ]k$äD@NäD[NÁ*Q¸\rÂpJeŽpyiO"M•tH‰™ôö…¢G•qöÇ/?|>ûxþûÏþúáô×ó³óÓäüýŸŸ?í%yÿÉx2»^›Žä/“‡é¨˜¾†€yl1ƒùÚæ:¡`È it.½5ÆõB.D]ôZËlr¡'z°Ár†ˆÁâ©™µDË!Zaªj!JךA°|¿Áò$9á”#ÎŒq‘¡tµÐÒžBF33 öoª¸ÛxÕÇ'²ÈçI€Jh _Â@z^Yðœ¤I_„‡9ÒJf žËò šcL]DHs©ûD &3UŠN8gçNÔÄ v±sˆ]ìœ$I³u­m5] W÷8ùhŽ!M,NbĨòÖ…PPO<Å­žbt½‚£øÊ¢ã„¦TYìê Õ@kNêÒ#lÀ„5[ª Ó݇ÈSÍö`ƒäiI¹ÄJq'[˜@‚ä$/£‰—aa™:X–H`9µû’“$9µŒ!£…vÌCJÚýAø3{X*=`v‹×Œ¹­×îúȢ佫âz4.®ÞØE5ýÞó÷€iÀ_ÅÀ^ÿI™NK­ãl¨È•OëÌq*– µÔî·D³l µ;Ïö€ùUÂRK£¤ÔÚ˜]n*ðà?À^qJ-åˆRÁÿì—ÿ$K©•B¹­ÏÂfžœZoϹÓeR-ÃÞ¾ ²j‰jgÕF–-ž×FxdÊúA»&Ž6, ¤4F>Vrõ¥y>³ól¹„äR*ë§H!…àÀw€ïß/£M !Wî_B ¡=ó•ŠïPWÎÂn¸‹,|gap!\ æøŽßø±8>¾³h!ñx!´Ø'Š,eà@GÎVÞiË‹ôæøë@ææJ;!ßî“®eT|5A3 ›Ï,82¤O5"j7ã1nÔá|#ôhCd3A´ÚÈ×O‰âöG™Ý G©Qˆ*Á]¬)¥Z‰â„é$ÖC°µZ×××êêb7{1¦0WÐK}%v3WÅ—ê0¦æˇã|:¼=̪¿Oìâ+?;®ácÛÆÙš[‰ùC5ü¦fžS}ö¶eëlâ#%ð’Ú&â)Pê«U(Æ%£”§±r—“ßH$„¤1v˜j»LíŒÆÝ¦í¼n››sžªÜ§¿kËðL2‡Å:åÜ}ÕØˆ\KiR F˜²>‹r{\Ÿ*ÄÄ®ûܾ@ëÏÉôÎ>¹ÿšLo¯Ü•ŸŠÙÃ]1,[bÑÖ—!‚q,¥â$'–ÅWøK3œÌê³Áj>Ø/7XaBHqBÈeÙMWå£& ñ=G„f$‚‰¦\› "%€ 2dð…;P5ç³AB3@ R’ Jß¶óŒdЙ$Îc¸NßÊ×¶ Â7üê¨`ïÍhÖ-›)WgK>H)³çK¬Sñ²Ú|0²È?\{£|y;ü^LýËÇWËRRÅMa}ÄÞߣÙèÂ=ÞL*º¤Iªl¸Â~ºO Ò”Öó¶Ì ©ûL!‘¡[}’9ÖÓYR‹A"UQ­z:K…ä ‰Ü¥ ÷ -•4zýcm¡åõuq}q$BË8KlÆAÞ ªìEÃŒ—w2†´qgRqçÖÈuÈR1@êrŒ÷™Ý×WgðÑ(F”1p€*AwľhàïXá[>É¥f 3BfRå$|Uk(ßÑQ¾0n¶EN^Ç- cgp›ÄZú•fNP\&¡}²Í„ðÌrfúŒ"ƒSŒ%޵°´)š®Kê¿—NNßû:šé.Õõ½ÅßÅm/ðëå%ç㛢W Ä[ŸÆf`œŽÛŽ) ÉíÚ#ŒÌŸ˜öˆtˆnkº ¦ëõöÍ!Ömì `oƒìÎñ:l·…h‘¢™ëÛ£ˆ£2F‰¼ýÌ6ÓX»ÚµÙgN¨!Ž¢{_zH¾ÞÞà&ànYÿ¸¸T&\Œ„À´oÁމ¥šîÒ6GJbîJˆ]ŽEàcÙ/à~*æÓqïz:¹ë]/Àp÷@q·ú1ÜÜ¥*q,ÂH®úLº~ $w,biLîrE©{­Yбìwž}_~™NÆ“‡YïýRÞÈ{°!†ª÷!o =¤U¸8ÖZ‘ê”í­3·.EVtvmf•1Î1FÈÕˆ ¦ú‹û)Îw£M›Ý†`÷*¦¥tWs­xð›/ walg&Ò1›ÕÃv°Ê1i*jg>ÜD1ðØË„¶B s )ªš+&C+Ï3 k&1¬)í#ú¹aMQ£ü˜bê Ö(bLˆ}ÀZä6„aã®ÖÜH€µÃ…µHóÙÝ™]1”†&C¤Ym¼º|ÍpjOT;‡dwEëÇ‘TL.A¾®AžŽ~ÖîÆ&,W–™”õ41+&Uüâ~Üe†ŠÿîrsÝc•§SÓªz"CÌ£¸ó§o®Kʈ.¥™›]`ªøqU=j•ø¤¡Ãåðš5èß«õ<»†5@1e'õnÇ9þ‰RõŸ¯ªìD.mú·ñëkc‰Å& ¦É•Ò[±a‘1'Srž­çry=ZÌìÙjkà‚¡:1‰—…/ÏÊU¡‹ßFÈ·µy”ü2ê(-£ÑhUʼen^A¦B%ÕÛŒCœ ýú¶yÏÙ®A•Ç TË¥²L¹B"WæC¯Šêߊˆ„|¡ÀÖÊÒ‰o&¬ª;—–ÔÓj5‡/­ˆx¸»h¥ƒ•[à±­ö®üßÌ•Áó0áÚ™¨IY1Eëý½:Mê½ý½iYøÈåÏî<=Vò”‡C÷®õœZÔwá›Yv¨+b²óâSr$eß¿ùt¿B_¬OЧ͂.Áor9¼J>+5ûñó”/R#“2dŠŸë&%øyvxštµ’7#òóìø4é [æÇÉÎ×Ó©©[k_÷6n•¹ó+“zJ•lç™ùâÏëjx\³žÍ'ttÔ*wžŸ?tm}òåçlwÇFÓúo±¹UôV1‰—vyW¦­ä› ÛNî0ÑR`_á@Ä“q;:þTäÓ=ZF[ô”«½ÿ”~¿:Úxpܸ۬Û1Go=9ôªùž.-“Òo1Ô^.­Óoê=åhãÝ*`x ÿ!†½‰èOê©5ŠŸNʼ¯«q³÷Øm©³m=žPݤòœÝá+Ÿ¦¼üÈk+r{wäQ‘…Cùor!jóɈï˜"Óm„.¿Òp¤9OP•á@•'OøÛ­Ø*BWi)°Ü÷W_÷Öå¿OJÖ£°[¢ŸÿÃü7EXŒ›SPjfiËû@-çîÔ,%ó^) 8npƒþ¡!s*:pOORO«ÕüñÏ;EÇèywÛõ#üM µCÌ©›[ÏGïÓÕ¸ÚûϺWÈ·)óZ-£9zù‹«÷wèj8n[ÿq½‚Táz`2r¤‰‡¯/{‘~CWcƌyÃe^+Wæž¼öÝõ‡{JnüED×ÉÎßκž¥ÀÞB`#Ø•žõ€ZŽËáÉ9Š\™"Gœ—‘óDïvLâ´k2¶»-øÖå¼³ž¤ÞÁ‹Ÿ]G¯s“aƒZ¿Ãá`[[¨®=>q$â'ݤ˜í¦üÇ5/冘?ÿ™õàÅ]Èc\—õnvª7V¨Ëb®Çì>}guÑ!{cz|0¬´Kî=qõ…ªøò|Îöê÷sslRß½‡Ã­® ÀØFû"åjjÖýG/NfŠŸ;+à[ ê°¤M£Q*;W<©wýѾ¿.,Ñvn2lp›™U4@͈Œ9uàʺÃNAS†tú¤”ö'#V¿³Iwèå<¾ËOš· ¯­„Ì;»ÂçÊböÇ5›Öÿ7¯N%[ªÔò?þ™“x¹h%kÞ¾ÙÛ­O䛸ÇÔ] •ôæÃíWïmÒjÕEëêu™Üçs3‹Ò/ÿORO,M^³€BY¸czw§‰Ý?Á=¨sþ½ýGØÝ]l™Ãá¾3x§¯{½-¯=Øu(|¹îÐϽóØÎë°Ú”_Ž4ñ÷so‰ó“ØCßjÖ=îŽÿòŸ)y±õï·²rãt5·™ß°®-v5.Ô2r…øÂ­î==TtZ®“­Ï›¶–¾ÆË¤CÌo'¦Å$^b=Îôcå·f0Š?Î~ú á[v´ñ^0êDÉÕñ’2¢:=^ZÉûì—vûSoçäèÚ»:6Ðñ+';?#Ä µRFΓ¿¯,MÏ~¤«Y8L뿹žKóW]Â[±b[ºû÷…ÿO@ãqÍÞìõ•³Ï ® ðhu+öŒR]@Dr…„C?ÏE¨5Êm'ßÊ“~øv³ œÔmc™Ã›J²à[ûº´½wB£U‘\!QªdÞ݈()#zÓñIʼÿ·å´o6cpçU"¡£ñâ€ZG$tlî?R£U'¥ßbkTjyTì‰Àzݬ-õ^R¸+ÃhÃnþ¤«íÙ|‚»½ou‡ûÚjÝq(GèÇú-Xôeé-½vâýìÜZÖL`•wåÚ­·ç,íÚkœK½¶ÖÎÁ[ôôæû‡V«5Æ ^;–›aíçë/ßÿS®mpææ©ÙOØ2ßÌrB·_XË åáÐdL§5ºÃ+÷·?K¹ž“—´íÔ ¥JÆVòxüÁ]Vvi1[a@I·kËwvþV·Ù£B•¿íät±4YoûÂ÷’èçÿ¤åİe;‘K÷ Ñ5+lظýIÌscGQ5^Ä%3»SÑ›·î ¿™‘™-•Ê=ŽÝ±ûȰѳš·vc„×NS­Ù²B) ¿·Mw*Gšt!êåæƒZb#t©éøÀ´ø¹wnV [fíÁ K=6>O–ÁÖðÍ­¦ Ü×ȧ¿ñ€: ‰ïÀÉ÷ñÍEìa®,ý×ct`U˜Ô;sóG]UÏæã±¤TÍP«5|ü±£¨ ‰)CÇ:ú/{Ð`ЀÐáoômÕ2ˆËåу‡O{œòÃÛJ½ @ÕëÙ|¢®|áÎf¥ZΖÃnþ¤[J/У{sŸÁFL΀­,œØr†äyN^áî\®ÙÝÖ8Ú64^hPg8Ùù éºZ·ÑEvn‘+_”lÆ%¢´œÝ4;‘K«†½k,Ê×Ç#¢c'ΚÀ¶¹ï­HJN#¢F /ŸÛ÷(êßcmúkφW§ÅG|ºt¾¥¥a˜‚…±#…×N}çÆþ!lY­Q<Œ #¢œ¼¤[O±•\¯_ÈGF‹L‹¥À.´ÙÜÕœ¾íWø¸wÐs€>¾ú´_®;¼ùø¯Gñ狵áQÔÓãºã¶ý1L¯fôìÑ¡¾·'-üèk¦/9—˜rôxYXNÚÒ±}HѳNŽö+–Í¿yåð§Kç/þà#ůµƒt卨¿‰èâÝß4Z5[ì3ÈÁªžq"SÔÂ÷ ¡kÑš–c‚¾a¬x Žjæ7¼¹ÿ(Ýáþó‹‹l»DÄ&õî>;©;öéZcÁ½æ”JÕò%s‰èî½G[ÿ8`ìp wëö}¶Ð¶up_ýÉ‘F W,›Ïápj0.€Bžmæ–lùqü¹Br7ö{Èåp»Í6^h`‚x\sç"Ólí¬¼º…¼gÄx îêÞê}[+¶,•gž¿³©èYnN^R†ø{àáÐÐÙÆ«¦|]åååOž0ܯa}"Z¶bMn®ž%ËÄ0Ìñ¿ÏŽŸò^ý€®ÛÆÎ^m:‡ŽY¹úW±$÷U—H¥2vïÝ_·ìfkîÜ}øÖÌýƒzZ:5o;hêŒoܺWþ*Ÿªcæð±ÓÃÇÌöj؉oÓÈÕ»]ïS6ý¶G©T•rUDdÔìw?mÜ¢¯µs°µsp³Ö/û.5-£X³Sÿ^dû;qÚûzïóûö¿Ø‹—}W´^÷BmÞº—ˆ´ZížýÇÛu!´oÊúmܼ«ò]€šaÆã7õ.œí¢Ö(®Þß)•g±‡>.míEžÆ LL!Nȼ­;ì×ñ s3K#Æuß\Ô¯ÃËÕô®Üß.SHt‡Ü¤ÌhÝnå)¨Ò|™™oŲùD”ž‘õÍw+z‡ä”ôî}Æñöî}Çâ’•JUfVÎå«7/û®aãÐ}ý]úå™Ù …rÑÇ߆´²õýOcãäò‚»÷ý±ã`û®#u»^”)¤eS¶Ÿ —åR¤¤¦wï3~ØèY‡Žþ›”œ¦R©Ó3²Îœ½üÎÜe-Û~þ"±ä%bIî¨ñsÛwñ˦ÇJ¥2©T}ÿÉÊÕ¿6iÑoçž# ÃT4ŒRäˆ%æÍw›¼àú(veÀæÁ+Ó¨aþî­tåè/ÿßòîgŒpÀ”]yü‡no®†^Ýê¹¶6n<P§y»µõõèÄ–Jé¥{/÷ å&f¼Lêy9Ôth¯1©4ŸˆÆŽÔ¤±ýðãÖqÈþ$$¦´ë2üâ¥H" -B»wøxÑÌ cߨçåNDÙ9â1çoظ£”;<8lú÷k·0 Ó¥S›©“F„vï ð‰H£ÑÌ_ø¹J¥.O$ž®ÁÍ‘B¡ì7dڣDZåïEJjz‡n£Ø^5 ø`Áô_Ö¾øƒ™­Cšу‡O{öŸXl cV¶¸C·Qb›7~gú¸LïÔ¡—ËÍK~Ù´K£Ñ–?†2egK–~ºæ‰¨YP`¯ÐN^žn͚ܨy^ŽþºrzNáÿ¢<®Y“zت’F«ŠŒÙ­;ìÐ ‹J@eu ž¥+_¹÷§nx³äÌûºžŽ~5×k,OšOD<oå—ñ¶B¡üh骽;Ö—çZF3rÜÜĤT" hpâЖ† ¼u§>\²rÍú­Dôî_„´lÚ¡]K½7a³TM›øïßùSãF…«~ܺs¿ÏÀ)YÙâĤÔýÿ?fH™Áp8œß7¯jÛy˜Z­yø(6¸ÍÀoŽ™7kr£À†¥_¨ÕjÇNz7.>‰ˆÖ~·lî¬IìŽÀDôÕg W®Þ´dù÷Ï_$~óÝÆo¾ø€­gfÌÄùlÞÐÎÎfç¶5úu×Ýðʵ[ìkhfÆ+3ìòû÷LxÔ½Gî.;¶­éÑ­}%»FádëÅ7²ß™«þÿ͹«] okÔ¸ÀÔĤ\*P~¡ëãÞÑÝ©™qãàáܼ¾[»¸Ô"’+sc/5òîNDÜ1¢œ}iÙ¼Éñƒ[ìíl‰H¥RÿüëÎÆ-úö<õøßgKÙØ÷à‘ÙnËÏywîT]:Œˆ¸\îâÞéÚ¹ múm® ‡;w…ˆø|ó«ç÷ÍèQÇö!áa{<Ü]Êv9ÝŽz  OÙZ,£gXÀ(¸®“G±JwûÆz,:þ”®Œo ª4-òžõô8[àÊ…;*VÂæ¤5G«Õ*J"âp8kV.ár¹DôÞ¢¯´Ú²§ŽþôËv¶°há 6•VÌÇβ²²$¢KWnÜŽz ÷&ž®Gl²±±*V¯Ë”±#Ë©oï.w®›6y¤.±õï™KƒG¼íÔsóÖ½zgò®ûéw"²±±úäã¹%Ïr8œ)‡QvŽ8%µ0õüÃú©ãå X…>zÿvŠq1tŒEÈ·.Vãéd”HÀT©5ŠG‰gزOàW¯»QÃÓá_¯‡OÀ–£Ÿÿ£Ñªˆˆ+Sîš!äOî@ nÖè­©£ˆ(òæÝ]{éêõn,›#¾~ã.{væôñzoèè`7ala÷ŸÓázÛXXôNSuuqb Jê‘w=­¿~ûàì‡ ßv°·c+Ÿ¿H|{ÎÒÆ-úË-Š%¹W#nQß^]ø|s½7 ð÷e Obž³—\¹v‹­ùðý·+[eØØXÍŸ=¥d½]# ŠÿŠs°öÖÛÀ0©âÇ*‚-ûzvÁ¦·PUøæV>Ù²R-OÉzHD\·V Ü‚ë;7vµÅß·ÆôùòìØº?ùN&+\óK$Òó9àþƒv4_=/wkkÑ«nØøÿÙîE?®P$…CÿtaTH}oÏ•_}˜ð4|óÏ_ëÓÅ>‹ïÔcô™³—uÍ¢ï?agæî?x’#ôÓû_—žcÙÆì"÷İ—¸º8¹8;›aœô¾ÎtŒÈÖÒÑÛ¹q×—ëÚù6FŒjFÇî…vÂ2ÿ íúª ïÞ»[þÇ%%'}ÿÃ÷Ýzwó ô±w³oÞ¦ù°ÑÃ6nÞXPPP¥Ý€Z*9ûåzå^.!FŒL^äµk çÎܧw£úÞ>®.[¶œýÖ[;¦V—k·CèÕ¹“³È²Ìÿöê©÷ªè»øx #ËÏß²qcH“ÆÎ"K7›â‰ÊTô%)ó>qÇ_x–z7.ãa®<Ûx¹¹:/ùp6%&¥®^÷c­gødFfáOªèRz%ù5¬ÏÒ3²*‰Þáei)œ>môý['wþ¾ÆÉÑžˆäò‚é³–è…º^”‡••ˆŠt¤Q`ƒÊGXytŒH©VÄg<|–vOWcaޤT•Jõõʯ›…4ûä³O®G^OKK+((xóäÔ¿§Þ[ô^Ó–MŸ¿whï–-ZZZZ>}zðÈA±Xœœ’ŸŸ/*J«Õ>~ôpä AŸóíÌyóŒj]1vbiŸ¼¼«`FcfFÆçËÊøƒ <Ü›qˆ"JË~BHêÕ*B¡Åʯ>7yA~¾ü»5›W}ý‘Þ¤žnæé³ç ¥Ü-öY<[Э‘g, xÏš1áÛï7ѽè'l¥³Sa/ž>‹óòt+Ï}œØBÌÓ„QåûÏШ%2$±DÄáèYSLÕÜYsƒ›WÓÍ…ÂF.„_èÚ¹ëæ_6M~õÙW£'Œ¿®Ñh–|ºäÜ?=`ÊdJ1[ð­± T‡Å ßc3zþë~ù¥MûöºSÙYY[6nüiír™¬@eÊë9s‚‚«ëKde5aÊTÝážÛÙuœ*ŠonÅ7)UR"Ê/’zµÍ˜‘×ýôûµëw6üºãƒ÷¦[뛳ٸ‘‡Ãa&>!Y&“[ZêmôèI,[jP—OPS¶ð<®0Ù¤qa/î?x"—…eÞD7ë61)U"ɳµ-׺×G’›Wá¸Ke@À$q8œÕ+WwïÚ}È !ņ“ÛÙÙmÝ´Õ¿©?]‹¸&‹íììŒ&T»eáN ,Ý Õ )1ñÔ‰D$°°Ø}ð`}_ߢg?\ºtب‘‡öx÷ýŒ#èáàè¸öçŸu‡‡ì—åç1¨Ó,ø6lRO®Q­˜Æ:gͪ¥D$“ÉW­Þd­oM='GûÖ!͈H«ÕnÚºGï}Ä’Ü{޲徽»T[¼DD*•Z·)í«<-\5@7ÌÐÉÑ>¤ES"R«5ë6ü^ž¹º8é”弄ˆ<Ü ‡R§¥eêmPú€ÇRÐ0U<oè¡zˆðòôªï]¸ÐmZzZÍÆ5‡!F¡*Lê øXªÞÝ;wØBHëÖÅ2z:þ.]Z%ë¤@-¤ûÒ¨@™KHêÕBÚµ;jý¼iç«öŸ3s"[Xùý&‰DÏ´U« ëÛ·mѪePµK ÃÌœ÷I—žcW¯ûíUCˆsÄ’?wb˽{vÖÕÏ5‰-|ùí†Ä¤Ôò^4ë·ß÷§gd½ªA}oÏë—Ž™8ÿʵ[ùùòÏ\ú÷Ì%ÝY[[ë kWLûF „:eâðvmš/Z²òøßg‰H*•]¾z³X›Á·o]]rËŽúÞž‘—Ÿ²àBøu­V{:ìÒé°KE´lÞD7–Ô4àÚ…£'ο{ï‘F£‰ˆŒŠˆŒÒøŸ.ß²y“¢—ŒÚ¯gŽaç®ÑÓØ8]ž1ÀßwÿÎ7ò«L÷ è˜0­V›œšœ˜pàà¨Õjv'¾½û;:¨Ã8ÎO›6÷éÚE­V?yü¨[Û¶“¦M›>kV™©=­V;cÊd6öÕªïÞš9“Çã±§–hW¬_³ú«O?ñbÝwß/ûüå÷O Ã̘4‰ÍèÙÚÚnÜö{¯¾/ßÈ"¯]ûì“e[þÜ^…=":væþ½{nîî¿lÝÚ¹k·Ê÷À´!©WKY[‹¾\±ðí9KKiãåévéìÞ#ÇÏìÚsôjÄíôŒ,+‘(ÀßgðÀž3gŒs°¯¹Íõ6<öצèûOùçß3—“RSRÓù|sw7—íZŽÖ`ÿîz×'"w—sÿì<vy÷¾c/]OIÍàp8n®NíÛ¶;jР=JN hpëꑇNíÿëdDäôŒ,¡Ð¯Aýþ}»Íœ1¾dÍÌŒwâЖŸ6n?véNÔÃ…"ÀÏwâ¸7Þš:Z$‘Un®ÔàîЕ(¥ IDAT¨aë6¬svrÖ{jÉGKlªî+ýSÿž1vDÑš^¡½–-^Ö®m»ªz¼¶š5o¾ë¯ƒoO™,‹U*ÕÖM›¶nÚÔ£g¯é³fõìÓG—ä*æÄ‘#W/]"¢…-~{Μ¢§¸\î»ïpöôé«—.ý¹õ·¥Ÿ}¦ûãåïcÇ.ž?GD|>ÿäùóÅR‡mÚ·?~úL•wð^T”••õÞÃGš_Þ°^”é—õëœõBø`ÉÇôµ’zFpãŠþ•òŠ™ñæ˜oŽ)½ ‡Ã:¸÷ÐÁ½Ëÿt++KFþ´”v¶6¥7x• ¦AM–/™WÑ 9NŸ^ûôê\vÓÿãñxcF3r`9Û ü÷ß}ëýwßÒ{V’v§de™/TQtjÒ®=»^uê½yïUaR¯$ssó´ô4­Vûªï·Ê¯G¯^ç®E¬úê«}»v²‹wŸ ;s.쌷ς8ÑÜܼØ%¿þ¼ˆ¬­mÞ_¼¸ä 9ÎØ ®^º”“““–šêæîÎÖoüéG¶0}fÙƒ«Ðü÷–Ìè‘¡½(Ӿݯü„0gÁ$õ –ÇK€*Ó¦U›?¶üñí—ßΟ3¿Më6DtòŸ“c&Ž;ilžTφõåU¯Þú#£ïÏ{o¡½½=[ÿâŹs:†´¼U´±D"¹AD=z÷âóùzoØÐÏŸ-Ä>Ñ]yí[ž·pauôB/kk›³g—¬7¬&#õÀôE„G7 ®9;;9ZwxãæÏ¾úìÌÙ3ÇN3ảÃ'°&T‰zÞÞË¿ürÑ’%íÛ÷óºuìâw/ž=Ð3tÇþýÝz„²ÍÝ¿Ïè;zð óAËÒï™G]ˆˆ?xÀ^åìâòªÙ©ÕÁÑÙÉÊʺd½a½(sW¯×Ä'€ê€‘zÕ¥u«Ö÷ìÒ© »pîàáƒÆŽLŠÐÒrâÔ©—nÞܸm›ƒ£#ÈåïÍž-—ÉØ™™™å¿›HdÅ222Ø‚`ÍM¼-…a½0y©PÌÍÍÌ[~9œˆöìÛ3b؈2/¨.—;bô˜V­ÛôìÔ1777!>þÐýã'O!"F«eÛ :ô«Uß•~GGG¶ »ŠË©# ë€ÉCR z…´a Ñ¢ ˜0Ÿ ¦Íx{Ýêï‰èÁýûl¥£“[xëáéYÎ[9ü?/ö,¶Â›(2 SÑKÊdX/L^­Hº˜0@À²²²Œ ˜¶FM›°…ø/ØB`ãÆìr®>,ËËyݬÛ䤤ÜÜÜò\" ÙBn®¤Üñ–—a½0yHêT–L.+ålÔ½Â=1¸ ¥R©t;Ò¾ÊóØX¶ ÛÝÂÁÑ1¸E "R«Õ¿þ¼¡œÏrvqiܤ0?¸iÃOå¹ÄÍÝ-d¤§ëmðâù‹r>½$Ãz`òÔ¨”ûï7 iv-BÿZZ­öû¾gË={ô¬Á¸Àt0 óÁüùƒz÷úyý:vØ’ÄbñÞ]»Ør÷Зï8ÓgÎd kV®LNJ*ç§LŸÁ6¬]—’œ¬7$¥R©;t÷ð` Ñw獵¥k|òøñV­,ç£õ2¬¦ I=ÃiµÚ)oNINIî=°÷ç_.‘ügÎQn^î‚„ #"ssó™3f)L¨Û®\ ßõçZ­öÓ?íØáøáÃÅf¡FFDŒúFÜóçDäçÐoÐ Ý©‘cDZÃÜdùùý{t¸r¥ØÍoFFÎ{çb¹Â “'7ô÷'"©4¯O×.Å &%&Ž1|é¢t5BaËV­ˆH­V¯X²D¥R±õjµzÓ† ÓÆ337¯Ì+`X/L6ÊÓ·nÃ:g'çR|¼èc[[ÛŠ^8hÀ Î;²ä“ÉoMV*•߬úfíúµ½{õnØ ¡P(ŒysþâùŒŒ ¶ñʯVú5ô«dGàõÔ©K×7mZ8gŽJ¥z=mÂx‘•UÓfÍÜÜÝórs_<®›xkmm³é?ø|¾îZ33³ßwïÚ#5%%9)iHß>]»÷hâáåû4æ^TÔ•ðp"êÔµËØ uWY…ÛvíÜ«§D"IMIܧw‹–­[óÍù7oDÞ¾yS©PÑĩӚ·lÉ^2{þ»3¦L&¢ý{v߈¼ÞºM[†a"®^Iˆ·±±Ù²}Çè7†ü Ö‹2ý²~½nª²^ /.ù ¡ô«ú Ø¡sg¶œ™‘±w×΢gUJ%iµÚ ëÖê*ëûøzãò‡ ÀBRLß®=»Jo0oö<½I½Ò/ôòôêܱóƒß¸|þò¼÷æ]‹¸&/=~´X3‘¥hõªÕS&N©hØ:c'Llզ͊%Kþ=y’ˆò¥ÒëW¯küóo[uËáéÔóö>~éiS¯„‡kµÚógÃΟ +Ú Yóæºù³:›49uáÂ['>ˆŽÖh47##oFFêÎò‚EK–4kÞ\W3hèЮÝ{\<ŽˆžÇÆêòŒ ýý·îØ©Û|Ã`†õ¢tûv—ñ á¹sK~B(ý*OO]R/5%eÅ’%%Û0 S´¾w¿~HêÔ¨¬ &Aa'Ã"®Gì=°÷úëÉ)Éb±Ø§¾O`@`›Vm¦Nšêäädì ÎóÜyேœ8rø\XXJRRZjª9ŸïêæÖ¦m»ÁÆõî×ËÕ¿Ê–›»ûᓧΟ ;¸oÿÕË—ÒRS9Ž‹«kë6m‡Õ§v{ÙbüüÎ^¹zìС#‡ÞŠŒÌÌȰ°°ðmذgŸ¾S§O/–A333Û}ðà–_7ž ‹¾{WQPÐÐßÔØq¦L±‰ˆÈÚÚ&/¯\{龊a½0Uœ76dKõœç\oÜhªÉ+?DÆœ*Z³xø!߯Xñ€‰Qk_ìoÅ–½\[ëó»QôëÔ䤌Ûlù›±Q@ƒ¤wçîCŽÐÏÙ«M]ß6Èd:P ’zÕ«uÇ¡¡_™ÿuóª ïÜ}X¡'¦¥g~úźf­X95spoÕ¡ÛÈŸ~Ù®P(ˇ£ÇÏÑ ¡<¯’1¸¬ü|ùO¿l÷mÔ#ô3³ªð¢ª%;RÃ?Ž„Ä”Ï¾Zß¶óp—zm-ìšøv›0uᙳ—†©h_ŠÂF&%ürä¨ñóÒÒ3ÙÃ|’_»~çÚõ;[ÿØäÀ¯õ¼ÜËs“£ÇÈhÈ žÕh©d2ùO·‡»~ù†\^`ð}ŒØFóÃÛ–~ºZ©Té*ãâ“ââ“ví=:vÔ ­¿~+ZÔ|``Ô«!S'puyå¶wõ½+¶ë¶^Obžñ¶D’GD]:µЯ[Ar÷¾cObžßŽz0xÄÛ—Ï¥ß$1)õæíh€ß;´³Þ5БôŒ¬–®ªäMJïHµöB©TŸòÞ_‡O‘¹¹Ù½šäˆsoÞŠ¾tåíÙœËåîØ¶3€aÔ«!ïÎÚ"¸qµ>b΂lFoù’y+–ÍgF/š9rüÜ㟺ûðûµ›?]:¿ô›ÿû,õìÑÑÊÊRoƒ舕•è­©£t‡¿o?hÀ¢x¥w¤Z{ñÃ[ÙŒ^¿>]·üò§‡«îÔC§¦L_$“Éwí=:}ÚèÝÚWS `ÚÔ3W#nŸ9{™ˆ:´kùéÒyº!`ÿ÷Í«ü›öÌK~øqÛÂùoY[‹J¹ÏÑaD4d ÑæÞ‘“£ý–_¾ÑîÙ[pt°UG;¶——ïnÊjéÃǪµ#U¢<1b/þØq-ÔÚÙÁPû!©WC¶ï:üªS¼7½’Y¤ü|9[`‡ãé¥Ë÷åý?XÌÑaD4x@™¦jíH•(OGŒÕ‹¨»Ù¤^`@ƒ‘ÃúWÓSÀäaú­)Ð IcæUmt§¸\=?ôÇOž=‰yneeÙ½k»êˆ°ÆÔæŽ0 óþâoØÄç˰[—#õjÈíˆc-‚WÓÍE"![ÈÊ¿ªMVvá)+‘eɳìè¶~½» üÒŸU­©¼rvÄ(½8þ÷¹°sWˆ¨ypã‘ÃúÕðÓÀ”`¤ž)°¶±…¬ìœWµÑÒ5.êÿëÐÕÆíb+¤ÖväilÜÔ‘¹¹Ù/ë?×;^ œY0õ½=ÙBv¶äUmØA|‚’Dddf_¹v‹Ëåè×½Úb¬ µ¶#9bÉ á3²sÄD´ö»O:´ki술nCRÏøù²…ç/ô6ÈËËÏÌÊ!¢À€%Ljý}ê¼V«íܱ•n‡Ü:ªvvD¥R7÷ñ“gD4iüÐYo7vDPç!©g ¬­E ˆèÎ݇IÉi%ü®Ñhˆ¨UË ’gÙ)«ƒ–±ïmíW ;Â0Ììw—Ÿ=•ˆš7Þøãº]M †¤ž‰Ô¿[8þ÷Ù’g(¬4 G±SŠÎ\$¢ÁB«3ÀjW ;¢ÑhÞ™»l˶}DÐàÔÑ­––Bc¦I=1~ì¶ðÇŽƒ Ã=•#f‡°9ØÛõé٥؅ç.\ËÏ—4`ÇúÕ]µ­#*•zÒ›lÞº—ˆüÖ;¹ÝÍÕÙØA€‰@RÏD„´h:h@(]¸ýÍwuõ*•zƬ¥9b ½¿à-‘¨øH±#ÇÏÑÚ4eÕ0µª#ŠãfïÞwŒˆ|}¼ÎžÚáéájì Àt˜;€×Åšu¿•Üv¶¨eϱ³µ©è…CõêÚ¹ [þqÍò«×nee‹—~ºúÒ•ûõ(P(¶ï:u÷!µi¼pþ›Å.×jµÇN„ÑAåÍ…Ö‘ò÷"=#ëÏ‡ŠžU*Ul¨ß¯Ý¢«là[oø} îHµþ8òòò‡ŽžÉ®£Çår§MyäØIn^n®”]Ù°¨÷濉|T’z5dû®Ã¥7X0ošÞ,Rézy¹éÒa>õ½ŽÜ]:¿më`cRY&Ó€òCRï5Õ¿o·þ}»;Š*`2(?L¿¨cÔ¨cÔ¨cÔ¨cÔ¨cÔ¨cÌŒF«TidÆŽ 4ævÆ öBRÀhâs®)ÔyÆŽ  Ô·ïÀ7³2vP1OSŽŸ»·ÄØQ¼’Ïbzï;ÆŽ öBRÀhÎÇ|›ž÷ÐØQTiíO8šù; €×ˆé$õ¦^ÌWd; €Åáp[y1vPÓL'©ñl_¢ø±£¨Q<®9’z¯• é£Odì(@?33×tþ:„ºM¥`ÆØAÔøµ P+ˆlxÆ br­Z…OÜ5-2î·©G€¦µ?á(ÂTýZÊBÄŠ¸ÆŽ€ˆ(']­Vã3@ÙÔ¨8di…ÑPÇhÔ ’zÆbšI=k;qŒ@µÉÏÕj5øCàõešI= K xS&—jµcÆ&q¹\| µ¢Sõª…i&õLžPÄå™!©µFƒ©úÕ#Úê$õê$õê$õê$õê$õê$õê$õê$õê$õê$õê$õê$õê$õê$õê$õê$õê$õê$õê$õê$õê$õê$õê$õê$õªÀ¶ÏÓ?ôâê‰GdË#"†ad¹Zöò{—ež~üë=¬íyŠÇ²<í«N}ß©ºŸ ƒ¤”¡E·²Çß•GÌùõòü[ϰ¯ßX rsÒÕ{×dÞ¹¿kUf“v–®e¼+u²ÔEÂ0$k"OKmÈJzªÜ»&sú®•²t²ÜW&õjÖÔ€ÜY´ìÏz 7x„B.Ù»˜½õ™«ÐŠ«Õ0O£ *t7‡¬íy¡£mÇ,t"¢Ûçó dÕžq“åiªûå‘zPežF|?3‰ˆ½e?hºƒ±Ã©2÷ëÃ/r³5^þüeÖ+»5ÀëÁ³!¿X¹€cçl&—*åRSrMÛ[‘FÍ䤩Ý} ïÿ^ïçr©öÝõÛ‹6ÞðAʽ˲¢ÿœ¿{')önÁwûXÙñ®žÈ»pP’ò\iïbÖ¨åð9lò‘ˆnœ–nYžÆ–“Ÿ)gvˆe˺‰Ãì}F-pê9æå²zº›‹l¸göH.ÍÍNU;º›uaÛ}¤-‡CZ ¶WréH®8CãÑß}„M»~Ö%ûÿHqvŸäYtA¾DãÝHм‹¨Ûp[¾˜x!©Æ”‘¨JS‘_°…awPÈ ³–Ö†g¹²RÕ{×dÞ8#eÓâUiñ’„ÇŠE›<9""%×ÙÓ¼ _›'ÖðÌ8º™ÂBQÙÍJUoÿ:çî¥|ö05NµwM¦JÁôe»eyZÔÅÂúçÑÏ£ ”L—¡/—d:·Oò×OY5cfÎЏ¯Ë^—?¸.Ÿñ¥kE—5“¤^ŰC38Zò»W){5ÎíúL­bʳ äë)=Aµ|t<5ig9­{É©/”+Æ%QûþÖS—»”lð,º`ÕŒ$"õ®cϱvÕ/T š¹s1ÿІlFK¡£m=ýŠâ+§ÈÓR"Ùpm SÛ°0¥@®½À©UO+"æÂÁÜ¿·å<‹.x|SÞ¨µˆšu²lÖÉûꉼ?¾Lwõ6/¶ûmé~^”¢”3£8µè.*È×îü6#ö^ÁÉ?rî^ÊOŠUŽ}ß©y‘,O»ý›ô'ÿÈé4ØZ·™ïÝðü}k3BÛöµâ™qÒT¿-O»ž~(7t 6ÛxM!©g†¡}?d-üÙƒƒqö2·´æÊò´  C%_ÆÇ7庂Þñl¡~c‡ö@ùÝ>—?»Sl±ÊÑï9ui`FéàOY·ÎçK2Ô*%cçl6n‘s×aeo}[ £¥¬TÕѹÿîQ¿Éö•úÌ¡÷öôiRømÍ·¢¯Èâ+¢¯Èؤ^¥0ôþ/º¯‚&-uY16^.Õf&©?ØèÉNI¶w¥I»|1)!;UòBÅV* ˜½?dÑä¥Î­zZ±—»z›¿ýµëòQñ§¶çtncfŽ·"€ªôä–|Íœä2›5 ¶Xô«'[~ñPqf—8)V™™¤²´áz Úõ³njUl­Œ=«3Ïè9\²qàÙ:™Õo$è6ÜÖËßÀ/8൅¤žbîÈo“¶ µ2v u‡C>M,DÈòÄI¦Úιøÿ‡o®—Ÿ“®ÎHT¹Ô3/Ö á‰’ˆ8\ª€w>€š ­Ò-(ÒT™I*¶,r´†Ñ2^ÙÉ©è˲ÅC∈a©X«Q3l}—¡6•³Öw’.£ÇòoaÿX!ÎPW涬>íŠîv«onãÀËÍÖôŸjWt‘AO?¾ÐŠ+—jÅj¶þÆivªº^€ ä¿o7Næ­„#å™Éj·úÅC@ep¹Ý¢º,v­3sÏìåǾ °|`}Ö™Ýb]½$Ss/Svï²,läo\Kþ±cÎçˆlyD¤V1¹ÙI¦&þ‘"üpnÛ¾VS–¹}@éÔ3ûÇØ_볂;‰Ìøkߦ‚2"Ь(ö>ÇhéÉ-9 „\…\ûø¦¼dR/þ±‚ˆ<|ùÅÞn :Tùb3¾t•djÄê¨ðüK‡s÷®É¼wY6k•[™+Ä©”L±,[‹®¢Ð1¶!•LÇá´µˆr³«`»[=7·çåfkôÖË¥ZÝCcîȉ¨QkaÉAˆNžæ)ÏHT!©PµüZX¬;ë[´fɰ¸ìTõØœØÝ±Šºr<ÍèunÓi°‹YF¢*î¡âônñóûa{$#æ9»$¨“¥î“•VKéñÊðùa{%×ÿ‘ºûòûO±¯¶ž€©ARÏ¡cloÉÉNSÿ»S<ðMüÎ5„O“Âi³ O”ÁEEO¥¼PJÅK+nH¨Õ¥£¹nÈ‹®ODj“üLIDõ¿rYÃÚ€[ŽaG¯'3sŽ£»™£»YÃ`‹ÐѶ_OK|! Û#î7¹Œß¨ºô¢VÃ|6>!-^eëÄ«|FO/ûO˜©Ž{ïsf çÒþÿ¡lóô.ñé]b½íórª ç»|4—ˆº µ·È™­±qà5 ¶è8Ø:üpnQeÌ$àrÉ͇?j…í•\<˜[ÙEàu‚¤ž!D6¼®ÃlÎî“ü³=§ã k{— ¿Œy9šó$÷.Ë2’T5ãàjÖ¤e·¶®Þz\<*ø~f­ óµ°ä¦'¨ŽnÊ~|Cž'Ötd=y©KÑ6?œöZqÅê3»%Qáùâtµ‹Y³Ž–ý&ÛÛ8òØf¥¨Oý™ó B–/ÑzúñB„}'ÚYèÛÀQ¥dn…Iï^–±sÐÌÌ9®ÞæíúYwfSÉaá>M óq ÅN± êùYø .¥'7åŒ–Š®F‘òBÉιÓe‹ªò×¶Liñª³û$÷¯ÉÄéj¡ˆÛ0Ø¢÷»†Á!ÞÊfçl6xºÃΕå–™ÔÓáò8Ãf;n\œ~8·Çh;“­Æyùó=è_jÀÝ×D;PªZ²ÜU±Æ!×ÚžW¿‘ ¨“e›ÞVXïàuÀ0ÿDADMÚZ;eaÉí=¾ú…„Z…íŒ ¯â IDAT•䤫¥µ¯*£Ó…¤ž! dÚ~Sì/ÍU0‡~Îzs…k….¿þ¯t×ÊŒÙ˪RãT©q’óå˜f?ðÍW~3#ËÓ&=U®_®é@D^~ŇªIÅš˜;òß?K—I Ûd$ªÎî“Ü»,[´ÉÓÆyZºýëteAá8Ø»±w ¢/Ëmòä[¼|°FÍ\=‘wbkNNúË™n*óââÅÅísùs׸m_QÖv<'óÌdUü+’z šYø6µ ¢<±&ù¹²è²S •lÁ§ÄH½j}mõ:@r`}–ZUøzæ‰5w.æG…ç÷o‡OóåÄþœªVȵåŸSß¼«È7ÈâytÁÁ Y³WŸÌþóÓ-ºWGÙ8™‘w  œß1¼&jÕrWlc†aäRmf²*3Yuó¬ôø–ì·>wm„í¼L‡CŽîæ©/”q-{ˆÊ¾àÕlÿ?C!Ó"©儤ž!2­/t´Ý©?s®ÿ#í>Ò¶üÚ®Ïûó«t¶ÜYäß‚oÁ‰½[pû|¾JÉß’-ËÕŒ~ÏIïµ)Ï•¿-OSȵÞ¾M-rÒÕ¾M‹'žÎí—œ; !†‚»ˆ| ²RÔ×ÿÍS)˜Œ$Õ±ÍÙž ù{VgòÌ8mûX¹ùðS_(#ÏH-%Ä(®Ì+ºûä ù;¾Í "Kknó."Ÿ& 7ñ©òê‰<©Xóä¶üÂ_’Þ*ðÕSI>M™Éªì4u¾DÃ~t&"FK1·åDäÛTàæÃ/\VhRÍš™s<þç óê~mKºp0wÏêL¶ì×Ü¢QK‘ 7þ±ânxþéúçʼÎônfMD’,  ­¸|AVÉäphø‡Õ³’ï†ç?¹-hùŸI¸";žLªÍ—ŸªU*ÍÇåi55”+ô ¶ˆ8™÷äVFÍ`ÙlZµÜUÑÆâ õ ù§þg¥¨×ÌNž¿Ö½šÖ€Ú£u/«ã[²ÿÝ‘cíÀëV‰]éSãUDÄáµ=2zP^HêB!gˆ¨Ï$»KGs¥b;5™mñâ”ãOÑÔ8Õ®UDdÎçL]îÒªgán†ÝFؾx øùÔÜ,ÍÙ}’ÀVÂæ]õ|ϳ㛠Yžvü‡Î]†Ú¼jÄÙÙ}KkîìUî~- óŒ]‡Ù|;=‘ÑÒ壹Z-9¸šÍûÁÝÝ·0jµqq*Ý+.šÔ éaØ:×/Ø¢÷ø—3sÛujóíô¤|‰æÌqѶ•ŒæÛTp㌔ˆâŸ(·)üÈ›«ÌÏÕr8äÓÔ‚Ë%Ÿ¦‚Ç7änÊ‹îkÉÎØõòç}z ¼¶Å¤Å«ö¯Í$"—FÎs c§»0/G³÷‡Ì§¥}MLÛþu™¶Žf}&ÚýWÆ0…‹Ñx7”çiQþ-„Í:YÞ»,ûëǬÅÿý=lëÄËHTÅÞ-h×ÏZWybkΓÛòÊtÁÆÑŒˆr³4Zma‚¯Z…ôXŸ•™¬:½KÒor¥¾GxmÕärWvÎfÝGÚ¶îeµþ½”øGŠ­Ÿ¦¯ØSOï '`2úM¶{v¯àA„lÿÚÌ3»Å}&صïo-´ªØ?|­†ùçO15ln üðûÂììNK+îï8Ñ‹‡Šk§òÊsáß[³ÙyšoÌtÐeX>MÓ¿(œÆ{ä×lF«çòœtõà]‡•–urp3ûp“§.£GDõ ‚:X‘VKõümñÔeôˆ¨yW»TSjœJ¥x9ö„Ã¥ë=Ïp(öIÔÙË¼Ó k"’djâŸ9[!EöÊxyŸÇ·äDäéÇ·´â‘ !ÅÜ–ëÆÅ0ZJ|ª¤ êÕÀk[Ì¿;Äì{³ë9ö?I k{ÞôÏ]ñ%@Qâ õѹ‡~ÎÚ¸8õÅ…VK C™IªmŸ¥Ý»,ãph€A{½ åÈáPÜCEä™ÿ¤Ñ›¶·$¢«'ònœ‘*äÚœtõþµ™Ç6gë]^³üÜ}Í9\’Iµá‡s†”L~®¾ß)UDdËcßhŽlÌÚ¿.‹Ýƒ}Ýöý}EV}0 e.wUþ¯'CB­ˆˆ]îªô–Vv¼_ºšó9âLõåc¹ê3sÎÜÕnÃç8Šl¸9iê½k2‰Û¹2#3IUæµj“•¢Žº˜¿zvrÌ9‡CCÞv¨˜Àd`¤ž!t Òubsþ/IÒS塟³ZvYX––$Uȵ·Îå‘•¯Øv®¬€–Bÿ˜;òägÊħŠzŧÚ9™õ™XÆHŽ­Ý|Н§îÓÄâÞe…ޱµuúÏÃ!Ÿ&v3Yq†ÚÙ˼è)½Ø¥îˆ('M­¿Eùx ¸<ŽVÃÝ+ƒ]PO7. Ä‚ˆäRmü%»‚^z¢Š]7§èÖ·5óÚ¥Q3ì0CÛ÷b×*0·ÏåÏî[²^hÅ]ýoyZŽœï:ÆvÎj÷ß?O‹º˜u1ŸË%3>‡ýuÊåÒ°9Ž­ ™¤æÙß~€õÕy‡ù{÷EÙ5pøÌ¶d³é½Ñ!é]APŠ€"(bCÁî«  ( VÔGl *bWDAP) ‚R¤÷P ½g“Íî¼â² !}³ÉÿúåÃì=÷ÌœYevæÌ]R» 0é çþáõ»Þwí7™ÙÖž=k/ÑhdüôÐüëwï¤Vâ@vþ!º×xoù%çëד—ÍO-ÈWÞì7æaç¾{Õ誱~YiE«>ËXóMÆšo2|µùªý2˜“imßÇ9OÀ‘«†» ‰Òwäý÷ÊìÍ«r£™-PÏi´ÊàÛýûñÝòKŽýñpÃYÊv§ÿˆ %;"ìX—{ÿåÎ÷K¾Ú±“ƒ†€²ÑR¯2Tõ\RO£‘›'‹HVªuÕ§éÅJíAvlO½aW»žÆ‹µ©î<àÜíæÁm¥të5Ì»øyµB|˺õô <—æËL)ëÍs^Žíèn󆲊›Ã¤U-©§÷P¢[äüy"b³É‘ù"ÒêüY³Ë<í§|pë¹/¤¸r³vÿ&æjÿ»?\h¨ŽéêéÍ@¶hl¶ÒÿÊYÓ~ÑlÛÃøÜ×ošÜ¢£§·¿VµIdsC¯a>3¾j\¡éᜌ¼'P§WÒέûîßi(½ýµO-Šî|¥É?XçiÒ´în|tNdŸ>Fïªþƒ?=ôê[üÃë­EÒ´­G@‰!ö«—¢È¨‚¦.ˆê3§Q+sž- TÛu ÷¯…ÿgfŦi¦îW{‹È¯_¤¯YœY<±U%Tt¸+ûhz§b ŠçàP¿y5ýFù>óY£GÞŽhÔÊÃfUW|œ¾ô½R^%ê ŠˆÎ?D¦kv™g÷k¼o~,øåÿ5±_¯ üh©WU1]]®2íX—»úëÌ+®ó ‰Ò‹ˆ‡Qc)pN¥=×;8ꢿB¢Îý)µ\å2z"Rö4µÅkm¶RîtÏœ´lü)ëŸÕ9%Sx…æªÞ¤6mçw¨ )ÞbŸòòô±Bû¤½­ÎwÖ”æ<ý“dW¾ˆ¿ˆœŠ-O/MXã$Öþw›væÜC9·‹ê“q{¼ôée*WÓè­t³ß ›/1ˆU…ö¦›»¾y)åáºû_sž·ÏŸ>#|K¦.ˆ*u·×Üæ_êt@:½rã#A7>âÜ:¯Ôý\lçO/Š.µ|Æ—J-oÑѳEG¦Ñ*ÃUÃ]EèDÄf“´3EŽ#Ÿ¨ßEÚõòjÛÃëï¥þöeÆê¯3®ëzÁs·ã;P´Ô«cÒé•"‹úýœsïaJ9/û\ Ì©¬#ÿó->jt¦rJ8R8ûþ„çÆÅýöeFFеMwã5·úßùlèmO†T×!ì=yUUìýí5‹HdsƒcÛ7û‹îã{Íöö‘ G ¥Ä€úµÿÝÚ“"F3=ê.W wyîEc]¸©PË\wO F«Øl Õ‹–zÕ 8RÍ­þ+?Mß¹>÷Ø^sóöžž^¥4û2žÏôe§]´×jqX/ç[ï5¿ùP¢¥Põ4i®½+ ÷µ>Å}xì2W×QšžïB›p¤°ÙežÇö˜Å¡ï­]ë®ÆŸDr³lɧ,¡ô G E¤iÛ Å«ýïÖàyn'9Ü©P§¹d¸«â9¾*:¯7÷b)TKíô£Õ+zƒR¯Z«4d”…¤^õz§ÿ¦Y™)Öe Ò&¿YêŒaç¾íä„‹^דϿ4vj¡]ËTU>›•l)TM¾šÉs£¢[ÕTŸ‘ð&O/9ÏfŸÐÖÞR/¦Ë]Ìš^æ¡÷P,êñ½f“Ÿ6=©HDš´» ©Wûßmñx:iIüJàìÃ]õ½Þ÷À–¼¥óÒâc V|œn)PG—˜ëFoPL~ZQ4⬠ŠÔµèàÙ÷:_½GëHI¶`Σ§‡Üá?èf§ þÎßsìCj6oÏj I½êáaÔŒ~0hÑ I‡¶åú'¿Ô¤^‹ŽžZb-RnË»Øûœ=sí ­»¹rÚ£³q–ÓÇ E¤Û ïšË艈¢‘&í<mË?[›i=g‘V/8w^iÑÁóà¶üc{ÍáçþmÚö‚ŸÆÚÿnÇœûZŽî2Ûl¢ávwPkÃ]¥$ZDD«S‚"/:à/w·eUNvºuÉœÔërûßè×¼½‡—6=©hǺœ_¿Ì‘>#|ü‚®@M!Qmzñ±·l~šGiI=O/M§+M"’™býsYVÉ G÷˜lÉ‘°ÆúÆ­=JV¨5¹Yçzª†—’öÍN/k’ÜŠjÖÎSDN)<¶·@DÂë}ƒœöìi¸c{ Šˆ·¿Ö)°ÚÿnM~Z{à”DËÎßsJVHI´äW~Š=Psja¸«[óE¤qJOt îýpÐ臃 žÊÑ=ægž}fLÜcƒ¿x{üò…é…fµ]/¯[¦TÛpäPI½j£hdì¤ 9¶×»#¿Ô:#&huŠˆ,}/uçú\ÇUñ‡ >zæ¬}ùºûJÞ¥6…79× mß_ùªÃqªMV±pÆÙR·ÒžÏÅY +Ìjz™‡ˆ˜smÛÖäÈùi1œØ ŽØûç6më¡”¸=®¹ïöbçÕ̹é;¿y3%îÐχwä¿rw‚½½=p¡‹Ý–؇»‘šî*áháÎ?rE¤ÏpŸKVà¾Eßæÿâw¯¿?°Ùež>þZ^ ojèÜßôð›ÿ÷VD…ºí@EÑý¶:5kïÙk˜Ïæ•ÙYi¥·e‹ln÷xð—¯%šÕÓÎtêgjÙÙÓà©9¶Ç¼}]N¡Y‘þ£}» ô®ÝÀ™|5MÛyœØ_»3Þ”ÓWŒôõòÕ$Å[6­È>¾×®K;SÊý¯oйÿvþ‘Û¬½gç+Må9V³ó£ãmù%[JÌ’aפ­‡ÁS)4«[˱,Y§æ¾Û‹Wïa>—gÙiÎJµÎ¾?¡ûÕÞMÛyêôÊÁmyÛV窪ê ­ÞV B\2ÜUFrчÓÏØ¬jp¤¾çßÔ¨³–6)c­_°nØÃî ¸ä~Æ=<îñàê‹ @CGR¯šÝð@àÎßsËh¢Õo”¯ÞCùúõ”‚|ÛÎõ¹ŽmÊ pÝ=µé%Üõlè«Ìy¶½åíý+¯¸|À~7<øÌè¸ì çtU`¸.ª…!áháÙ8ËOŸ³®™NéS~Áº€P]zR‘½I Ó,v:½Ò¢£ç-çš 6mWúÍw }·;/E#¼1÷ñÓÇ÷š Íê¦åÙ›–gÛ7ñÑM|!lëêœ?¾Ï¬Ä@µ¨Íá®TUÒÎm_—óËç9Vƒ§2áùP#Ýb@M!©WÍüCtCïô_6?­Œ:½‡ù´ëéµnIæÞyÉ «U Óµíé5`ŒoxÓœ•¢B›ž_Üè§Òcwä§ž.ò Ô¶êjì?Ú×þ6Û?TW2©§(rÏKa_¼šw¨À7P—‘\\¾‘¡›^æaŸÓ6$JïRúÿ“­»íƒâÉEZêÙÕÄw[Æy™|5SDýµ"kóÊœ„£ùjp¤®ËïAãü¼ýµG÷˜+wDP-F?ä¨]þQÚÑ=æ’¿ËÕ2ÜÕž?óž~BU%?ÇVd9×Õ7$J?ñŰ2îXªŽ¤^ÅÌÿ«Å%ë”§éµoöúû¯¿¯\ ÇZvò¼äqË®Ók¨O¯¡ÒåÚÿ\ûŸRö ÖÝ>­ô;ÝéŸF—ZÞÔ0e~TÙ¡–Tž 憎:þÒ Ú¥¾[)ó¼4¹b¤ï#}K®r‡ÿ;üËÐ-z!éÀ–¼ºœ§ÔûpW½†xoZ‘½{C^J‚%?×¥o¢ï{½ïe½½JŽÒ[QEÕ>îŠÞC Ó5iëѱ¯©çoûP¿5‡¤ ¶e¥Y7¯Ì‘ ?d‘ÔPu.±€k‘ÔT›oÞHù}ÉE‡’ìr•ÉÞ2×7P;àF¿ý›óÝâW‹Ñ@ýARPÍšqv×úsåÇ÷šï5šÕ~£|E¤IO“Æœk;¶§ mOcñÞoÏK¡z|Ÿ¹UçËcwšE¤u7£ˆ¨ªü¼(ý×/2 òm"¢7(–Bõà¶üƒÛò“â-Ãï.e2ÍROAUeÝ·™ßÏMµ©:½b4ilÉ?°%ÿ–ü{^ smʃ¤ ùáý´CÛòGLè~O^¶5¢ÙI½÷¦ž.ÌWÇN î<Àdε}ùjòÑ=敟¦ïþ37áhá¸Çƒ;õ3åeÛ>%éÄþ‚•Ÿ¦_1ÒG£U4Z%¦‹q÷Ÿ¹±;ó‹“zªMï0‡Dë“OYýóoROUåÈ®|‰éjE‘äSƒ§rݽAm{z…75˜sm«>MÿõËŒ•Ÿ¤÷½Î×/X[žSؽ!÷Û·S<ŒšÛž é9Ä[«S’â- gœÝ½!wÃÒ¬73 0€Š¡Ï Ù¹>wÜ”Û蛷÷tì+"¢ÊãïG¼Ù/0LÙÜpÇôPÉϱ¥$M™5àF¿€0]TKÃO…ŠHÚ™¢Ó',öíÚt7ŠÈáùÅ{J<^˜›i½ê&?^9üÏ¿å)‰–Ì«_°6´‘Þ^rÓ£A/}ßxÐ8ÿÈæF¼|47<ÙÜPdQ·þ–]žS(4«‹ßJ‘ñÓCúŒðÑéE‘°Æú{g…i4²êóô"‹Z­ß"€ú–z€j¶c]îý—u*õ@ÐÐñþ—ܶqk{ŸÙR ¾Ý¿QŒGñÇð&zß@mVšuØ]þŽu£ZŒÞšü[Fr‘½¼M£ˆœØW`)Tí}]ý“/"1]ŒZ{Ûk¶¨zEDbw˜E¤uW£r>hòsn‹§(ÓÕ˜x¬0%±¨<§°muNÚ™¢F1]^0 _p¤¾u7ã­ù)‰EáMô—ür -õÕLQD§Wœþ4Ι±Òõ¸Æ[¹øørŠÆyO€¶Œò¬4«ýcD3ƒo ¶È¢žØo¶—ÞžïaÔD6×7¿Ì£È¢Ýs®Ü±ï­“B³zt·ùÿe}ýzòÞMy"’‘TJR¯ä)ÄîÌ‘6Ý%O-8J/"ɧ,=g( -õÕ¬óÓ}³Â+·­FW±)#´úÒëŸë·{¾W«¢HënÆ­¿åÄî0·êlTm»#¿I[ViÞÑsÍâÌCÿäÛ»è:Î’Q,ñXáú¥Y›WeççØDÄ?DgÏQZ­¥t›-y ÉE"òÛW¿}•Qj´ÙéÖòž0ˆI=@Ѧ‡=©—/ÿ H¬^fŠ5ù”Å?Dgo@g÷û’Lûˆxú˜®éÓ²“§ÉO»ü£´å ÓË{lUD$º•!²¹¡ÔõÍè{  bHê{ã»c{ TÛ¹3ìé<ŸmdsÃñý…fõØÞsÍôŠûÉÆÇ,~3E£Uî}9¬Ó•¦ÊÚ7X'"[{ŒŸZ§Œ©h‚#õÁ‘ú‚|[Ò)ËÑÝf­NiÖÞÓ¾ªu7£ÍªžØo>¾Ï¹ïíÎßsUUÚõ2V:£'"-;zŠÈáífk³Ü¨$õ …}Ô¼øCGw››¶ó0xžkgÏâÙe>±¿@Dbºxob)PEÄÓ낟ËB³zâ@AùÛõ*“‡Q“’hùí«Ì*ŸˆÔ4ö¤ÞÎõ¹éIEö¾·v­ºEbwäŸ^ÕtŠ ’z€†Â'@ÕÂp´P£‘=WµînŒ- Ô^™ I=@µ÷xð¸ÇƒËSsꂨK–”gíÓ‹¢K-Ÿñe£RËŸý¢ôò ºñ‘ RWùøkoŸâTÑÌ0ÿ¯å ²X‹ŽžNÉD¨ÆÔÜ I=ÀÍÔÜ I=ÀÍÔÜ I=ÀÍÔÜ I=ÀÍÔÜ I=ÀÍÔÜ I=ÀÍÔÜ I=ÀÍÔÜ I=ÀÍÔÜ I=ÀÍÔÜ I=ÀÍè\ÀÅr³¬yÙVWGˆˆØl®Žp$õ ¡SUQUW¨ˆú™Ô+,àçõ™Ê›+€ˆ¥PµÒªužÍÊ95¢~&õ2S‹\@ÍÊÎ ¥ JôZ“¯WcWGQO(ŠM”s)lÕ¦Q\Oý Óx¸: N«ŸI=Ôƒ§Fs~¶síÇ€[Rñ0ž»§±©–B—¡Ah>¤yøWGQOl?õÜñ´ïíËWÇ,ñólíÚx4$õP%&NîI= òTán‡.u¨O4ÅÇ_k_.È·Y i êºú“ÔëÔhXÓà®®Ž¢Á9iþÕlK¥oËÛ]MãQêÏ?ad¤0n€Kkrµ¯g”«£¨‡,jvœe±}9ÈÔ²ß@ׯS_õ®€ú£þdº4îê¢ÿÞnÎKEQÄÜíêpà_è=þíLWd¡YꃘÐ!1¡ô•«~Ù…ñqGÏ%õB¼ÛôšäÚx¸!ÑPÛêORGZâp®3]~®-'“Îtʉ'sU¢ª¼JPHê¡JŠ®nŠ»,â†&}\E½U &Ÿ.Zi_󹬭ׯS¿Ñ¥î'pàfHê€Ëtkt§«C¨Ï’òwž>q.©íߣGØ®@]¦:$õÞTw quÔ •)¹Ô[$õP]x©  n¹ Ý ×(À¸’z¨" àèM Üx  2¸ÙPëHêê+Ç–züÞ(ï)€›á!P?©â8¦/Ï”E½ ©Ç¸’z¨^j¨»TÇ–zP~\3€ ©¨Ÿ.|ëÀ#:€2©¼©n†¤ªCJ¨{Zê)üÞ( óe·ÃCªˆ×Úê(ÆÔPI\0TïÔ>’z€úŠaï”ï)€›!©‡j¢ðÀ  nQ™(@%qÍPE¼'Pt®+n@Q´®Ôg^úˆc;û[­ÆÓÕáhHê¡JZ\媊hx`PÇ0¦€òóÐúµ o_1vtm0ÜQëЉ­C'º: I=TI§Ð]\ Ýo”—QÒ#ì WGÀeRS“âNqu"";÷ÔjyNP.\,õ“ÊD |öïݱðƒÙ®ŽBDdÞKM&oWGÀ=ÔÔOz° IDATÞú¨6·¨¢Š¨Až—¹:¨N$õõS€G«^áÓ]Ô’zœÞªÀ?¢°6¿Ç+7‰TI=Î m^Фs^m15Þ@R@%h\€Š!©¸’z€›!©¸’z€›!©¸’z€›!©¸’z€›!©¸’z€›!©¸«€{Û›¼,¿(CQ­bè6ÎÕáTF®åÌáŒ%"¢ˆ„;Gy÷uuD—@RU²/õ§ s¼ˆ´&’zÀMåÙ2ß¾Ü.ð’z î£û-ªFU]@ƒCK=@ý”j>³AE%ÚûÊWG .s|O©¸, €r£¥ª ·¿ê–TóÞÉs¶'¿³=éíÔü}®pi“§N6úC£C“’’J®ÍÌÌ4úþÆÔÔÔÚ­Ø?Ûÿ¹ãî;ºöîЬM³1ãÆ,ùß›ÍæÂ I=T‰*t¿PG©Žã(üÞ(#ŠÔ%Ù9ÙÏ¿ü¼«£(ݓӟì;°ï’ÿ-9pð€Ùl>sæÌÏ«~¾ãî; xú´«£4,<äê«MЖ@ÙßS*\3\MQ”EŸ-Ú½w·«qöÙ—ŸÍ™7GDîpï¦ß7<|ríªµ¯¿úztTôÖm[ç½?ÏÕ’z€úIe„,•£pÅp±qcÇ©ªúÄSO¨u¬å¢Ï‰ÈÄÿL|çwºtîzyï˾ÿáí›·¿úÒ«3Ÿ™áê I=Tn~Ôm\¥Àm\Õÿª.»ü±áå?//ÿV»÷î¾÷Á{»_Þ=4:tÐÐAÏ>ÿlfV¦SCýÉÉɪª~úŧW\uEPDPÇî'M™”›—[öþUUݵk—ˆ ºjÓ*oŸG~Ô`08•ïÚ±ãá{îéÕ©cLtÔM#G~4~©CïÅŸ<ùĤG‡ô¿²qHp‡–-}àÓ‰‰ŽZD„‡˜¼þX·ÖiÃ[ÇŒ1yý÷å—‹K†_=(Ää•–šjÎÏñÙg;´lbòZüÕ—•ˆ P÷‘ÔÔWŽéø½P6ÚöÖ!¹¹¹3§Ï‘iÏL+((¸d}UUß™ûN¿ý>ÿêó}öYŠ,›þÞ4û­Ù=¯è¹éïM%ëÇÅÇŸ0þþ‡ïß¾c{^~^ì‘Ø->jxÙ EiÒ¤‰ˆlß¹½!Éóæ »jÀ⯾<§Ñj_»æ©Ç»sÜÍf³cÍÏ-ê׳Ǣ?ܾm›Íf;súôWŸ}Ú¯{·ý{÷^ò(“’’|ÇØ±sÞ|ãÌéÓ"Òî²öç£RËÀ-ð¨ŸTÕaL=žÐ”cê¹\nnîà«_ÞûòcǽÿÁû—¬¿à£Óž™VXX8éÿ&Åî‹MIHù{ýß½{õŽ‹»~Ìõ‡c;Õ5vÔŠŸW¼þêëÇ?vðØ´©ÓDdó–Í¿¯ÿ½ìÝxÃ"òæ;oÎ}nÙÙÆ½[¦?1Uo0¼óþûÇÏ&8qò¯;;vî¼jÅŠO.,®öÍ—_<öðC¹99׎¹~붸ä”ݱGž4¹S—®1mÚ\òÄ/æå™37üñûÔ§§oÚ±ãçµëZ·mk/_µbEy¢¸ ’z¨‡!«¸ýP·0¦€ò»ðŠËÉÍQåµ—^‘WþûJrrr•333g¾0SD{ô±W^|%:*Z«ÕvêØi岕;tÌÉÍyöùg6Qå׿>|ÿÃáááá3§ÏìÜ©³ˆ¬úuUÙM}lêÕ¯¶Z­SŸšÚ¾kû÷¼W²‡¯ˆX Õï?Ú!"sÞŸëø; ƒ¢(-[Å,úò+­Vûγ E$;;kÆ“OŠÈ˜±7/úêë¶íÚi4šˆÈÈ™/¿üí?êtºòcN~þé§Wß|ë‰éÓ[Å´îÑ«—½_p~^Þô©S.ÀÔÔW$õ”WŒ:$''GDztï1n츬ì¬f½PFå¥?.ÍÊÎò6yO™4űÜÓÓó©©O‰ÈO+~JMMu\5eÒ”îݺ;–ôíÓWDO_0’]Iƒaé·K_~þ倀€S §òñmZüßäÿ;~â¸cµƒÛrÒ’ó:têtÝèÑŽå›6í{eÿ¤³gOž8."Ëø!==Ýàá1㥗4š žË´ZmÙ‘”­cçÎwN˜àTøÃ÷Kâãâ.ÀÔÔŒ©îä|ŠõÅ™/=úñž}{DDÑ”’oݸi£ˆôìÑ3 ÀiÕàk‹ˆªª›6_0²žSMDBCBE$))é’¡étºÇ},v_ìÜ·çv¸¬Cn^îG‹>êØ½ã‹¯¼X<ÝD|l¾ˆôë?@)1úC“fMEäıã"²iß"Ò­GȨ¨K·BF[òЛþÜXž¨n„‡T’7àZŽcêÑîÀ%¨ŽSë ®ˆŽŠžüèd›ÍöäÓOªªjò2•¬súÌiiÖ´YÉU^F¯°°09}útÙÒëõ"RöDŽL^¦ wMØüçæ¿ÿ±c‡ŽEEE³^›5ã…çìks2ŠDä½9¼œþ>ûøcIN:+"öY,Z´lY΃–ŸN[J×Ý3‰‰å‰ àF*?R "Â4ê.‡GtžÑ”éÂ.uÈc>¶èÓEëþX·ò—•×½ÖäeÊÍËu¬pÉ)k/Y§ÒE¹fÐ5ƒ®4}æô·ß}{î{óî})Ú'@g?Øe:´mwY©¶nÛNDì-ûjíÕ¸ýK¸dT7BRP?1QÔ&/ÓKϽ4áþ /ÌzaØaÞ>ÞNI½ððp9qòDÉmóòóΜ9#"‘‘5¡F£™1}ÆÜ÷ç/ð ÐyûêD¤cç.sæÏ/cÃÐP)_§W{â¯ÈRT•8ÃÂÃËÀÐýP_9v¦ã÷@Ù^и·Ž7v\×.]wíÞõãò}}|ÖöéÝGD¶nÛš™é<íšukì ½{ö®–HÌfs©å½ÁÓÃSDlV‘è–ž"²qÃz‹ÅRÆÞzôî-"ÿlÛšRæô¾","ii©Nå¹¹¹¥U/]¯>}ÊÀðƒª¡÷-€ºŠ–z*GáŠQÇh4šÙ¯Ì‘g½èååå´vôõ£½MÞYÙYo½û–cyAAÁ¬×f‰Èð¡ÃCBBªÆî=»c:ÄÌ™7§xBŒb?.ÿ1'7GD"›{ŠHLW“‡§.îĉ÷æ¼SƯ»áƒ‡G^nîk/½èÔA8;;Ëñ£½‘Ý–¿þr,œýʬM6”?þ£F™¼½/ÀÔC•t ¿ýŠè¯ˆ~°gÄÝ®Ž.tÁ°÷<¢(‹¯¡i¯ðé½ÂŸîöT´wW‡g—÷¾|Ì cöØ·k÷.§U3Ÿ)"¯Í~íÙçŸM\Ô¶MÛj à•_ {é•—þÞü÷ß›ÿvZ{Í kÞ|ýÙ?]aÿØx«FþƒÞycöüwßÿî»!¡¡yyy¹99"’žšvõ!öj“ŸxòÌéÓŸ.\¸ø«/õ¥§ÑhÎÏÿÓ‰‰:u²W÷„ùs禦¤Üsçx{‰V«3~fFæ³Óž,ÿ)ÜóàƒIgÏ^2*€» ¥ ¾bL=¨?š4nòèÖºJQ”Ç'=¾~õú[ÇÝÚ¶M[V×»WïÉLþç¯ú]ѯºPeò#“÷îØûü³Ï÷èÞ#88ØÃãMë6׸î‡ï~X¶d™ÑÓÓ¡²<ó +V¯¹uüí;vÌÉɉŒŒyà Ÿ-þö½… ‹«iµÚ×ß™³ø‡e7»¥MÛ¶¦K·nx`ãöƒ‡ +®ôÛ†?¯92<"ÂÇÇ·_ÿK–/¿åŽñ~þ~=…òDpÊó[Ø—·~xø×F5dɦ·¶Æ®r,™6z“Ñà<Ø6ê“äüÝIù;Dµ©¢6ñ¹ÆÇÐÈÕê³"kÁ‹ßu³/G‡u»eð'. ³á_~0Û¾ÜqHV“Îyµyô¿¿ H>îa_ž÷ÁR“É»6À|µj|Bòûò+÷¢û- ~ 1v 1vtuP#莸’z€›!©¸’z€›!©¸’z€›!©¸’zàNöìÚµõï¿]…?ztÝšÕ®Ž.«”—ªªOMyüð»Ç½¼\Éä‡:x`ÿ?ûö›¼½]4X´Ô·±nõêÍ›6=ðÈ#®Íè‰È£S§¤¦¤|ðÞ<׆ I=µaòÔÉFã-ão©ô²s²þÆn½»UcT.—““bòê×½¼'õÆk¯úúúN¸ÿâ’iM1yýç¶[«Ù ÿš†…^Þ¹ó­cF/_¶¬¨¨èbû?qìØsO?ݯ{·¦a¡Í®ìÑý…gž‰?y²dÍuéÖmÞÛo›óóË< ‘Ôà222\BõËH¯ÀI;rdË_]?fŒ¯¯oyê{xzFDFFDF†…‡‰=üÛªUÿ¹õ–AWôIIN.Yÿƒyó®èÞmÞ;o

ÛÃÓsÿÞ½OMyÜ©òüwßþÄÔ‚‚ž—_þÙâowÇÙu8vÑW_wíÞÝœŸ?õÑG.Xà´Éµ#G*ŠòÍ—_”ÿÕ…¤÷P?[êU$S¹ìûï}}}¯¸òÊJHQ”à{|ð•ÙoˆÈŠeËrr²‹×Ø·ï…gŸ‘Ûî¼ëÇ_~6bDDdddTÔˆë¯_±fíMãn‘OM‹=|ÈqŸ!¡¡½úôù}Íšôôz˜o€:ޤªdcÂ{kOþwíÉÿnLxÏÕ±TRªy߆Äi&>õgâS§rÖ»:œ†eàÐFcrr²ªªŸ~ñéW]Ô±{ÇIS&åæåWûîûïŒþÆ!#†ˆÈþƒûþFûߢÏ9îmÇÎïŸØ¡[‡Èf‘#nñþïÛl¶R˜šššoÎæ¹gš·inô7~ùÍ—e¯ onô7®ý}­ÓÞFß<Úèo|éÕ— ß~jmˆÉëì™3y¹¹¯ÏzùòΣ:·ŽybÒ£IgÏW[úÝw!&¯QC‡ŠÈÁŠ¿ûâ“OJý®ÒÒÒŽÄîÖ³§Á`¨Ø·ìô \sˆX,–„S§Š ßüïk‹%<"â¿o½¥Õjëëtº7çÎ .,(xçõÙN{ëÝç ›Í¶óŸª t®îíxÆÆ\KŠˆ˜ôÁWD=èêp*#×rúXæ¹AÁü=ZF{W¦ª".>î±'[ò¿%ö±GbcÄîܽsÝ/ëE“ÉÔ¼Yó¬ì¬””½^ß(º‘½¦¯Ï¹¡åTU·`ÞÓÏ>m±X ƒ¯¯ïšukÖ¬[³vÝÚÏ}îééétÄä”ä)§¬Y·Æþ±}»öåYU!?-]ºà½y'ŽSEUÕ„S§}øáŠ\þÛêf-ZˆˆÉÛ»ióæÙYY©))z½>ªÑ¹“òññ)u‡;¶m‘ö:V.žb¹¹9ö??ûBffæò~‘yÄàáQrO£ñþ‡~ù¹ç–~¿äÕ·Þôöþ7Âö:ˆÈ?[·\uõÕU P!´Ô)® !5vÔŠŸW¼þêëÇ?vðØ´©ÓDdó–Í¿¯ÿÝ^áÚ¡×îÛ±oÖ ³D¤U‹Vûvì³ÿ¹aŒ½Âò•˧N›jÐæÏŸ|*9.6n×Ö];u^¾rùGŸ8Ïð "3^˜ñûúß§O›¾sËÎßý½m›¶åYU!OMyÜœŸ?Œ‹MH\°è/“)éìÙ™O?e¯0xذ­{ö>÷òË"Ò¢eË­{öÚÿ®3¦ÔîÜþˆ\Ö±Cåâ)ö¿o¿‘€€€°ðp{É?[¶ØçýåŽñÛêÖñwŠHaAÁŽ åµïØQDvÐRj-õõÓ±Ìågò¶ˆh‘Á÷zë#]€ºKÕÕ!4tŠ¢üºâ×îݺÛ?Μ>sÕ¯«vîÚ¹ê×UWõ¿ê’›çåçMyrŠˆ,˜· 8ÍÓ*æëϾnßµýì·fß{÷½N]VZñÓœ7çÜs÷=%÷Vƪ ¹¼oßE_~lÿ8zìX£—×ø›Ç®\¾üð¡ƒ1­ÛTt‡gNŸ‘èó­+Êf³Š‹[ôá‡sß~KD:ÕÞ RDöîÙ-"þþþÛ<$4ÔËdÊËÍÝ»kw¿þŠË5n,"gÏœ©\T€J#©¨Ÿ’òwÄfüϾp3I=eú7©§ÐRϦLšRœÑ³ëÛ§ïÎ];O'–gó%ÿ[שc§Ñ£F;–7mÒ´¿þk_{üÄñÖ1­WuîÔyâ&–º·2VUÈð‘×gôìpêÔê_~©DRÏ>Oˆ¯Ÿ_ù7ùmÕªŽ­ZŠˆÍfKKMµX,öò;'L¸÷Á‡Š«¥§¦‰H£&MÊØ•¢(7>xà@ZZšc¹ÁÃÃÃÓ“‰2 ö‘ÔC•ðZ@¥ªÿŽŒÎ:€Šàšáó¸@¡!¡"’””TžÍÿÜø§ˆ ¸r@qÓ³bÍš6‘cÇ9%õn¾ñæ’•/¹ªŠ´Zm‡NNŠ‹«Äæ™é"âãë[þM ÌæÓ‰$F¯9òÞ‡º¢ßGZ EÄßÿ¢Íôì‚‚D¤° À©ÜÏÏ/“¤Ô:ÆÔÔWŽoxDP•×”u^¯µ|ÿmì úÞ™ûNñ¬¸Å ?Y("IÉÎÉAî¢íÊXUu!¡¡"òd%¶-,,”óßL95*97/97ïtfVËV1"î”Ñ“ó]zíÝ{˘ çûÛ:Òëõ……å P-h©‡êAGuÍ…)=®QÊæpͨ™&Z¨QöÜ_ÇöÛµkWj…vmJ/¯}999RÙ¼¡€¿ˆdggOpQ~:î™^¸ë–qŸ}üñ=>ØêÂv‹öŽ·ññqªª^¬•¢ÕjMÒRSEÄ?0°rQ*¤ª UÔ9<¢(/æþraaa"röìY«õ‚¼Þ ×Ýàmò>qòÄ;sß©¡C‡‡…‹È_›ÿr,œõÚ¬ 7\d )9!ì[ÿ}­°°0ºQ£á#¯+. ‘¤³gœNª¤¶í/‘ýûöV0ö]Þ·ïàaÃDdæÓOÙlÿ¦õzý-·ß!"Ÿ.\˜•UJKÀôôô/?ýTDš4ÉiV{<í.»¬ÒQ*‡¤ªˆ;`uÕ×'^<@}жM[F“‘™±ð“…ªªæåçÙg3Ÿ)"3^˜ñÄÓO$''‹ˆªªÇOŸ2mʪ_WUýЃ¯,"Ÿõù’ÿ-ÉÍËMHL˜úÔÔ_y1¦UÌÅ6yãÕW¾çž#±‡UUMLHxzê”… ˆÈôçŸ÷4‹«µnÓV£Ñdff~öñǪªæçå•ÌÚuëÑCDöï­|RODžyþEQvnß¾tÉ=p'=ñDPppvvÖ}wÝiÎÏw\•—›{Ïwä忆GDÜ4nœÓ÷íÙ#"]{ô¨JT€J ©¨ŸÛÝ(Œ©à˜/Û=DFD޽q¬ˆ<úø£‘Í"Çÿ÷ÍÿÚW=tßCS&OQUõÝ÷Þmܪq“˜&¡Ñ¡í:·›7Þâ%‹«~è wM6›ÍwÜ}GpdpËv-ßÿàýóLüÏÄ‹mÒ£W¯ÿ}÷íå;7 îÓêÃ÷Þ‘Çžœ6ú¦±ŽÕ""#í%OLz4&:ªEdÄ;¯¿^ê›·héçç·sûöªœHÛË.»ù¶ÛEäå™3 ÌæârÿE_~e0VÿòËÕ}û~ýùg8xàÀŸ|rUŸËÿX·ÖÓhüäëo<<=vh§[w’zPÛxÈÔWŒ© 2¸bÔqóßÿÈCÄ´Š)²uëÚ-**Ê^®(Ê‹3_\»jí·ßÙ±Cǜ율¨¨®¿áÛ¯¾ýxÁÇU?nPPÐÆuGáëã;àÊ+~X1þ¶ñ~~~Ûä¦[n]÷÷ߣǎ ˆqýõß.ûñ©3œº¯ŠÈ;ï¿ÿÀ#´lc)*êÜ­[äù“r¢Ñh rìÈ‘ØÃ‡ªr.O>óŒÁÃ#>.îÃùï;–_Þ·ïO¿­nÚ¼ù¡ƒ¹ÿþ~Ý»õëÞmòC;r$¦u›•k×u+ѯ°°pÍ/¿4mÞ¼yË–U P Êó[Ø—·~xø×F·óÙÞqùEé"âm½­Ý箸¨%›ÞÚ{A×›i£7 ¾®Šµ`Câ´c™ËíË7´XákhâÚxÔedzV¬OxÒ¾Ü3lZÛÀÛ]ÜQ‘µàÅïºÙ——¼yì`ʬ×gßóàƒÕ{”5¿þ:î†QOÏœ9ù‰'«wÏÅ,ËŠeËÖ®^ýõ矉ȕ®špÿýC®½V«Õ–¬¼ö·ßnuý´gŸ}|ÚS5OíØðÇ/ ?˜m_î8$«Iç¼Ú<úßß$÷°/Ïû`©Éä]›GàF¾Z5>!y‡}ù•{ÑRP_1è'€òR…5Àq&ŠêÒàÀÐÐ¥ß}§ª5õ3§×ëGÝxãœùóo¸é&9u*þò¾}KÍè‰ÈÒム›ÆÝRCÁÊ@RP?9>ì(üÞ(7E!©‡ºK§ÓM¼ÿþû÷ÿºreMkÆ‹/……‡;rdà彿ùâóôôtUU322Μ>m¯·dñ7ÃFŒhÜ´iM(‰‡Tѹ‡fFŸP÷8´àÀ%жnãÞ‡ šýʬšk¬gݨÑòßV·hÕêT|üÿÝw_LtTt`@«¨ÈÇ~È^aî[oZ­Ö§f>W£a.†¤ ~º`ö[^<(“Êì·pÞÞ>SŸžÞ¡S's~~M«ióæ¶n{÷ƒú_5°QãÆŠFÓºMÛаpûÚÈèè»&NlÛ®]M‡(•ÎÕÀ½ lò„UµˆˆNñpu,à„Gtåaê9¨Ñ<{j/À£•«Ã.aâý÷×Ú±ôzý¸Ûnw[)³Ç<úø”Z PI=TI´O7W‡CK=åå¥ óòsu¨?&½2ð–ÁŸ¸: @=G÷[@ýtáHC$õÔ+´ÔÔOíƒþÓÌïZUUU­¿«Ã€êDRP?;»:œXÕ‚Kª¢hÑŠ¢(¢U"š’%®ŽPבÔ€Z’ž·÷£w•£¢¢Ø|ö|Ÿ¢UD#çsÊùÜ_ÉE4Š¢=_nßP¹`s{IqêðÜæ%*;—8îü\‡­Î'%í«ìåeVvˆüg$â|EQjt` U›­ævÕ†¤ÔUµ–·¢ªªb¹p:wˆˆH‰Ì`Éœ Æ)“X2§éX9Ã;µç˜tUUUT›œ9ì©ÚDUU±‰‡·-n·ñô!OWŸ7\€¤Ô•]uPŦªÕšñÔKX˲֛³5$õÔ5$õ –xè¢ý†¨bUU›=3¥ŠUDUUëù6Uu*¹°²ª–¾¹½D¬ç²]¨V‘W‡ÎHê@-ñóŒéÕdvM¥¬ `‰’R2‰¥T¶ªlhUÅ&ÿ.«+9÷ñbiÊR2˜¥—”;§y©ÊÅš+È'ØÚ®KsK®ñbljQzþ>¹xFUQô¯Aë¯×z—1ŠV«­‹%Æ; IDATDx&’zP¯œrNW“óI¸±’éEQmVÕŸñ󑔯ó-gœê{ê‚Zß>êñ;´ŠGY»[zÞž„Ì5‰Yks N–V嬈hC„oÿ™ ÑÕvJ$’z€Ä>ŸoqÆÓj3OÿþpòÇù–$§š&CtëЉM®Ó(úKïV4^½:uˆx,Ë|ôtֺĬµiy{Fþ³©…‰™kºDM¯¦³Ðp‘Ô4DE¶¼c©‹'ZP”ê´ÊÇ£i›Ð{ù_«(•éëëÙÂ׳EëЉù–¤ÓYë2פänµ©Eöµ¦Nº ªF Á#©hX,Ö죩_Ç&^hÍpZåçÙªMè½Q~ƒå¢#ß•ŸQÚ<èææA7[¬Ù§³×'f®9›½1Òw`Õ÷ $õ E¡5#6ùó£©_[¬ÙN«ŒíÚ„Þé7Pj`0B½Ö§±ÿðÆþÃU±Yóª}ÿ ’z€ú¯ (õpò§ÇRÙœsj^Ú†ÝîÓ·&ÒyNÑèµÞ察”ó׉´¥¾WEøö×i¼j.0n‡¤ >Ë·$NþøxÚ÷V›ÙiU°©{Û°ûC½{¹$°òˆÏXŸ±2>c¥F1„x÷ˆòá7ÀSâ길I=@ý”W˜x(yቴlj¡Óª0Ÿ>mBï 6uuI`太¶ÓY¿Û—mjáÙìg³7* /xuˆòé;ÐÛ£‰KàJ$õõMNAÜ¡äâÒ*žsö<%Â÷Ê6¡÷zu¨ÆÃÍÞ˜’û}¹iàh“!ºZv›[_r*Uliy»Òòví9ý¦¯g‹Hß‘¾¼.«…¾Ãê’z¨’ŸM·XóQL†AM¦¹:€ÊˆË^³/íSQDétO”w_WG ò²ÌG%}Ÿ¹RUmŽåŠh"ý¶ ½Ïߨ¦Úšœ³åPòÇöåPïÞÕ•Ôóöhrýe›ÏælJÌ\s:k}É_–ùh–ùèÁ¤ Z¿FþÃÚ†=è¡ ¨–C¨ûHê¡JÎæ(´æŠˆQõühÔ¾ü¢ä¤¼íöåVþ£] €JË4:pvAbæU.Lç)šh¿¡mBïõõláªØ*M«ñ´·ÅSUkJÞöÄÌ5‰Yëò ªZ3O¤-m1Ù%Ap ’zhèTQ>Ñ pKÇRïHxÉ©P£èùhz·Gc—DUEbêbêÑ)òÉŒüC‰Yk3×fšWõéÍô¸@ƒBRP?m>3+³ð¨ˆ¢ˆruãŠh\wARpK~ž1Ž5Š¡IàõmB&z"kãðJm^:cc›vaåžJÌZ›˜¹&5og¤ïÀZŒ€ë‘ÔC5©Õß0¸´Tó¾äü]®ŽÔ’ S—ïžÉ9[´f7Æ„üǨsuP5Îdˆn<¾Uðx›j)9Ã/€ú¤ªH½tp .PÊïß+†BK=Àmµ {à´±]ë ¿«c©mE¯Qô察˜µ.9gs¤ïÀ`SwE¡Cà–Hêê§ ÇÇâ€ú/ØÔ=ØÔÝÕQ¸‡¸ô2WIùÒ õð½2ÒoP˜w­ÆÓÕq¨’z¨.<0¨kŠÓz ×(eSU&ÊЀXmg³7Ú— ­'Ó<™þ£¢hÛ…=Ø&ô^ׯ ühd‹*¹ðêUµÙh¦ B(@½—a>PdËw*TUkZÞ—Ä rh©¨¯xë ü¸b¨"wz!äÕyx»u§3×%f­MÊÙR<Æ^ëãÚÀT-õP=Üé @CqþV7.EºßhXï·ÆÆ:ÕóXÇ€Ã|¼[7оnÈàÞ¿Àl®båäƒÓßø›ÇÖN5êí×ÿûß—_>sú´«AYt®Ô ªªfeemß¶mû¶m‹>üpÉòmÛµs¬0ã©iïÏ™SüñhlìÜ·ßúáû%?¯]Y¹ƒfffŽuý¶-[ŠKR’“×ÿ¾nýïë>ù裭{ö–±­ÍfKKKûëÏ?ÿúóÏÏ?Y´tåªÀÀÀÊ…Go½þz^nîàaÃÂ#".Y9<"¢e«˜àààZ Žh©@½2{ΜCqñö?ƒ‡‡ˆ<ÿÊ+Å%¥¥½ö?q*5ídRò¦;¦?÷œÑË+éìÙ ·ÝfµZ‹ë¬\¾ÜžÑ›pß}»ÇÆ%§|ñÝ’àSññÜ}w¥£ôÀýÛ¶lñõõ}þ•WþÙ·?!=cÿñŸûÝu£GkµÚR7~Ýu§RÓN¥¦;sæ· Ž{³ˆìß»wÊ#ÿWé0*jȵ×¥Žï-\Xk1Ô3_~ù¯;ï}è!WÒàÐR€zÅäímòöv,ñò2•±‰ÁÃÃÃÓSDZÅ´ž4õ‰€À )ü_ìáC›þÜЯÿ{7_{UD®tõ«o¾e/ríµs?øpÜ £6nX¿å¯¿z^~yEC?yrù²e"òþÇ‹f/ :|øÐáÃOÅÇ—º•¢ÑØ£õðôìܵëüE‹ -…?-]ºü‡’“’BBC+F%è †²¿R ¦ÑR€†è¯l;õ¬}ÙbÍr\5rÔ(ûÂþó½_NÚ¹}»ˆŒŸ0Á±æ Áƒ5n,"?-û¡1ìÚ¹SD¼L¦«‡ )¹6ºQ£rîgÂ}÷‰ˆªª»vì‘•Ë—‡˜¼š……Å8áTóîÛo 1y:Ôf³U"àò«t ›6l¸çÎñbZEø·ˆ5tè§ 8UÛ³k×wßm¯Öºq£Ûn³iÆ’{~õ “ן|²uóæ1Ç7 mqó…ýíÞycvñÈ€y¹¹"rM¿¾ŽÃ&=ëXßi0Á²'ÊPUõÛ¯¿ºnÈà–‘Q=:´zê§ŠÈØë¯ 1y-˜;79)鱇êвET`@¿îݾþü³2vÞ`ÑR€†¨ÐšYd͵/kÇU:½Þ¾Pd-²/üs>Ô£W/§ýôèÝ;>.nÛæÍ•ˆ¡ÈbKa¡ÕjÕh*ßð(:ú\ú/##]D†qû]w}ñÉ'ßwï+Wïùûoÿ´t©ŸŸßÜ?¬ÊáÊ£1¨ªúôÔ)½ÿ¾ý£ŸŸŸ¹ `ã†õ7¬/0›û·~øÞ{Ï<ù„='èíí“–šúëÊ•¿­Z5ëõÙx d0ÿlÝòääI………~~~ÙÙÙkûmýºuŸ~³¸¸u¤ˆD7jÔ§_?ûòß7Úl¶Ž;{ûøWÐ Žû,®|øàÁ”ää2¾ õÿÙ»ëð(®5À߬ŕx‚nAÅ]ƒ(”‹(î-Áiqw‚• …àî$@p !î¾>÷¡Ûí&D6!›l~ïÝ繇3gÎ|;÷¹›ÝoްìØáÃ:HDB¡ÐÈÈ(èÓ§›7Ÿ8zÔ÷·*U5ÚÇÇÇwhÑ<4$D Èåò·oÞL5ŠÇç÷ðs6W)0R $’)RTe>ï?I½›W¯r… ®¹ÂÇÀDdhddïà ÑO™²åˆ(óNµ¹Q­f "’ÉdË/fYV‹8_¾|¨kaaÉ–,_QÞÕõÞ;[6|ÝÙ#2"bÖäÉDôçÚµ¹˜yaýêU;·lafÒô¯?†G„ÆÆ]¹s·‹§§ú͹xîÜœéÓø|þ¬ßÿ%ìsTÔ§Èȹ 0 óÛÌÜXE íÙS«Nǯ^†G¼þÔÅÓS.—ùkRR’ªMï¾ýN^¸È½ ŒˆhÕ†ªš“.ZYY©÷©ªoÙºMö÷áÀÞ½GdfñŸËƒ¢¢?FDÞ¸ÿ JÕª±11#‡ Q_·‘³uãGgg¿€€ˆ¤äûOŸÕ«_ŸˆV,]šýUJ $õJ"©ZRòldDÄ¡¿öOŸ4‘ˆJ—-Û¦];îPll,•Êj9nÛÓ„„-&´Vv«ÒÅÓ“ˆÖ®\ѤnÝ¥ \¿r%%%9Ç5xoßÎj×­ËŒML6ïÜ%–.XðöÍ"š4ftbbbÏ>}¸5ò錯¯ÆüSîuâèQU›<Űê?ˆhŽ—×Üù󹕆©]·îžƒ‡~üé'®˲ófÏ""¯ÅK¦ÎšÍ%ÚÌÌÌ'M›>tÄ…B±mãÆÌÑí9x¨L¹rDTÊÆfÛî=öñqqGÈÿ­ÈѦµk‰è—_9n·sKõš5÷:,^½xqýÊör¹|ÏÁJ•݈ȵR¥Õ7QðçÏ™'2—pHêäKXÒå‡!3¹W’ø½®ÃÉ-õuô*:9ÚšÛ™šÔ¬è:~äȸØX'gçÝ|¸ q‹¬©þ©ŽÛ³‚ˆÒÓÓ´cË.ïŸáñxÞ¯Yþgßîž•]\úv÷¼yýÚ·Na•J‰X,‹SR’ŸŒ6ìÔñãDÔÅÓÓÎÞ^Õ¬~Æ“gÌ”J$c†ý²sëÖ«—.9»¸¬X·^‹ µ–ûÎ:™‘žnii9fÂÄÌGKÙØp…G~ 426:b„F›.Ý»ÑÝÛ·2ŸÞ¦];õ!–††Ý{÷&¢+—.jûÎr+$((ðÃ{"8d¨z}…Š›4mFDW3ÅЩkWõÝNª×¬ijjFDÁÁAß;ÚâkêA¾xý?–UQ)£ò*,Öu8Úx·çuü>"†a˜fNØ××uDPÌ$e¼ M<Ç•ËZyZVÖm<¹¡dåreÆ·ŽŽ7n®×|#ccz†a27VU*Úl=adl¼vóæ)3føÿûöõþ¤¥¦^¿råú•+c'NšŸÕ¤Ë³§N¹”²Ö¨¬Rµêª šƒÔ¦Ìœyíò¥Çþþ³§NafãŽZ™YÇ.]6îØ™¹Þ8ÓMËe O="¢FMšd™9ý·™¿?1 Ó§»§Æ!qFEFD°,«ñ¿TÍÚµ5רY“ˆÞ½y“͵ Ä»·o‰H(V­^]ãP­:unݸþöµf å+¸jÔØÚÛ¥¦¦¤¥j“5ÖcHêA¾¤Éb¹¤ž±Ð*ÇÆE“T™š.æÊ Vs{A½$W¤ý»LÛëÏAæææb‰äÉ#ÿ9S§mÛ¸ÑÒÒrÚì9ªÆ&&D$‹3w¥ª422Ò:ž2åÊM˜2u”©r¹üá½{kW¬¸~õʦuk5iÒ©k×oÅãñÌÍÍݪUëêÙ}Èðᆙë·mû¡^="0hpÓæ-´ŽP³g¡0—ùÁ\ÆÀí5áèä”}o1ÑÑD”ž––å^·D¤T*¥‰jø$Ǻ”F3®&!!!7o!?â‰ÈÂÒ’ÏçkÆ`SJÕ@f´|Ÿˆ¾÷†ÅŦߨ/͞Šý#UügÝ:‘¡¡……E«6m8ahd´|É’~~ª\ž%...sWÜr{¢ÿ@ФY³C¾¾î ‘Ͼ½™ÛtíÑ#&-=&-=*%õCXø™ËWFŸ9£Ç9vè0W¸vùR!ä° '†6íÛsw Ë—FF/ùÙœtI=ÐO'?õ8þ±Óñ¯„ŽÖu,Pô!©ù“Õ¤Ô"N¦øæfeË—9f,˲óçþ;Rϵb%"gdDGEi´ç¶/(ïª9e2?x<^gOO"úø!0?ý<ðó[¿j¥ÈÀ A£FááSÆ-  >[["  ˾·\6Ó›eƆ¶ßƒ••5%%&fÞå6>6Žˆ,-1óOKHêAþü›Ô/~Ã@¿¥Ê¾¤HCS¤!i²]ÇPäÈ”š[ߪ5~¼ÈÀàÑǪIÝ6ä þh4öø€ˆêÿÓ  H%"4çlæ^JJòèáà Åìyóvû´¶¶>ãë{pÿ¾‚‹± c¨ë^Ÿˆøùe9ÇY¥^ýúDôîÍ›ˆðð܇ñâÙ3ÍšçωȭJÕ,ÛsÓ]åryî/ñ-nUª‘L&{óê•Æ¡gDT¥ZÖ1@ŽÔý¤šJÀà©ä„U©‡ (!¤Šì’z6¶¶½úô%¢ÕËÿäjœ]\j×­KDû¼w©·¼qí*7R¯kZ„wçÖÍÌõ±øÔ‰DT©J-ºåÌœ4948¸aãÆc&L´wpX¾vÍž6-èÓ'­ûü~1töô426NJJÚ¸vMæ~¹BýFÊ–/¯T*—xyen¦T*ƒ?Î\õòå¨ÈHÕ?%b1·_p«¶m³ ÛÜœˆ"ó’7ü–2åÊU¬T™ˆþÚ³[½þS`ཻwˆ¨u»öù¿JÉ„¤è;ì OÔ€b/-55>.Ž{q5ééiªîÙg6Óo9£Æ#¢ûwïÞ»s‡«™I%’¸ØØëW¯ôêÚ…Ø5pð-º%¢G=tÐØÄdÓö<ˆº÷îݳOŸ´ÔÔÑÃ~É<4¯dR©ê–ª¿Ô—ÌËS ÖÖÖSfÎ$¢?/^âåÅí›ADo^½3lØ‘¸òx¼K—ÑaŸc† S%Ãü·ooêî¾ÏÛ;s´âŒŒ¡úsé×ø¸¸Q¿ ŠŒ´´´ì7p`–ïŽÛ-wçÖ­©©Ù%siì¤IDä½}ûöM›¸˜¯_¾Òÿ'¹\^µZµÖíÚåÿ%v¿…|ÁŠšPd±ôuo, º€œa™pÐ/Ó&L8vøz×ìÙ^³gsåw!¡Ö¥Jɲ©GDÕkÖlÒ¬™ßíÛ«ÿüóhÓ¦DÔÅÓsĘ1;6oÞ¾iÓöM›T-œ·ìÜõíž²ÃíˆzïÎUêPÝ”™³¾5”,{a_¾LŸ8ˆæ/YZ®BUýòµëîݹóèáÃUü1cî\íbæ\yªlùòÚ…Q¦\¹{OŸÎ˜;·I³f6¶¶ÀÀа\… }û8{åêìyó´èS©TŽ><))©eë6CGŒP?dii¹nËV"Zýç™,@ÚÅÀ0̲•«N^¸Ø½woGÇôôt_аqã?V¯D´ÏÛû§ÿËÜà]Œw|ÚS!ßLÈ7¯b7Â@`]è1@~a¤|Gwoß²51ÎñÕ¥mÕ)<¨©»»K)ë®~þ±·ï±cJ¥R£çYS&«÷`ofZõBÛ¦?L?îÕ‹9¦qºÆkèÏ øF´ÔÔ[ãfõÝ3²µ³>jT…ŠGŸå¹ é/“¯'œ ŒýKÁJ¾s¤ð]`¤|G|ߨÄD½&=-ˆD"‘@(TUq…y³gmY¿^UyéüùKçÏoݸa·ÏAG''þ ­­­‰H"‘ÄDGGEF> Øçíýc¿ŸÖoÛ&T»D–x<ž¡‘QæzCÃ<¼I]HLHÌæè²U«³9*U$«ÊBžYÅ…I=øŽ<~ø!8:F½¦^Õ*¡!!®Y;pÈÆ÷ïã2zCGŒøyð'gçÏ?>}òdóúuýý·nذ`Ù2SÚuì¸û€WV(?ìóöÞ¶qã±Ã‡ÜªV™4}FöáuöôT^¼$%f—ÔËžL‘†'ä›dߊ&$õ ¨Ø¿g 6lùÚu\­]ÃÆ ´ÏÛ{ø¨ÑÙŸÎçó+»UYüçr"Ú¶qãî;&N›Î0ÌwŽZ7´>W•Ôò̈ôóþè=¬©E˲/ž=#¢–­Ûh2553a¢H$ÊeWž=zQxXX|\œÖñÄÇÇWvq¶51æ6Pyú䉭‰qi›Ra_¾¨×‡Ϙ4±C‹æelmjVt8ztDx¸zƒgãFŒhT»Veç>ݺíܺ5óB]Ú¶±51ŽŠŒLOK[±tIã:uœ­­ê¸Už1ibtT׿ÄÑ£¶&Æ=:v$¢·oÞ¨ÖükÏ~¶mܨÑÿ«/Æ9«ïÃIm>¯vbslrr2eÂò¬Ï¾½íš5-ckãQ§öÌÉ“¸ÙÓ sHê@‘À0L™2e‰èY@@>»²wpà i©©Zwbmm=gþ"ZÃ06¶¶ù‰çC‡ÖªS'"<|Óºµ\ßíÛׯ^qrv7i²ªÙ¡M76-5µs·n·ü…ÄÄ>ÿ8nÒäÚuëU®R…ˆ.œ=;wÆt¡H´nË–ÏQÑo‚‚ï=}Z«N gÏîݵ+óugO›*ÎÈØ´sçÛàaáÛvï161‰ŽŠòš3›ˆÚwêäÿâåü%KˆÈµbEÿ/¹W÷Þ½³y/ÞÛ·{Íž-•JGO³Ì·ìºëæîu©RÇ&4$¤_ÏÞg>¥¯žΞ]²|ÅËŸ^~œ2sù?xpûæ ­o)$õ ¨˜8mz«6m Åo3g4¬Usç–-YNÍž\._·j%5jÒDcãÝÌÎøú:˜›i¼vmÛÆåóù®YKDëW¯ cYvÉ‚ùDäµx‰‘±1×&%%yÞÌ™DÔ»o¿Ý>«V«Æãñœ¼–,9rê”@ ÈHOŸ;}­ß²uÀ Á"‘ˆa˜Š•*ï>àÃçó×­Z)•J5¢jÜ´éûúö`]ª”¥¥e¯¾}·zï&¢ógμ÷6¯7„ˆ’’’–xyÑøÉSf-˜be/àñ¨teƒ%»{Ô¨U+-5uñ¼y™Ïbæä…‹¿Žkïàààè8{Þ¼ZuêÑ•‹µˆ ’zPTˆD"ŸãÇç-^leeöåËìiSkVt6a|ðçÏ9ž+•HBƒƒÏŸ9Ó½c‡{wî0 3û÷,U™)2QŸ^Z¿aË32–xy]¿råá½{ <ùþ},4$¤fíÚž½z©-S®\Óæ-¢£¢‚ƒ4ß]—nžÜìZ•ö:q³}µK¨ñ=‘’’lbj:~êT™2EUobl5uæ,":wútæõ'L™Z¯~}õšÆM›‘ÆZ Hê@"ÆOžòôÝûU6V«Q#=-mï®]ujÿ¹xqæm%ˆèŒ¯/·M„³µU½jUõëûðÞ=[;»í{ö6iÖ,ÇËuíÑ#&-]ã5|Ô(õ6¿/\hnn~ä Ï´‰ˆhÉòê;êúݾCDî 89;gy ¿;w‰¨Y‹–™÷á-[¾}Ê9eÉçókÖ®MD¡!!96Îìþ]?"ªß ¡•••TñïàGß¼MûöDIJìƒ{÷4ÎÒÈQ79&*Z‹ `!©Eޱ‰É _~¹qÿÁ‘“§jÔª%—ËW.[ºè÷ß3·404ttrrtrrvqqoРgŸ>ËV®zòúM,¨`llmÇOJD¡ÁÁýü\×Ý]ýhdD¹V¬ø­Ó#ÃÉhóúuªmjU¯}ÞÞD•›0lí츴x \\Q¦øw¤žondllgo¯j“=¡PHD,a£ Ýè:(Þ”¬œˆˆ††AŽŠ%–”,«dˆ!"†ái¥]a¦UÛ¶-Z·^øÛo›Ö­Ý²aýˆ1c4ĵëØq÷Ÿï†R©¼tþ*2òųgªËÏ'"…"‹u¿Ãcÿ¤¤$Ù“z7®]ãÊ ÿéŠ$õð¨ Hxùüy*n[֯ϼ!ƹS§ÒRS‰¨A£F…Õò%‹ccb† ^ÞÕµÇ?ÖoØ02"âE‹T <{öŠ’ åéñ#RR’‰¨k&¦¦!AA›×¯ËåE4jÖ,ÿS*•º”.Ý¥›'WÃ-„©PdLT×­gOSÓ””äMk×:š·ªã4»šÃ¸J6ƒDä¸rÙR"êй3· HêAÁÀm(RR¤!{ßÔÜ÷¦Ö¾·µï„ÏÖu8Pô©ÿ Ç÷9zð`lL̼ٳº¶kû÷‘Ã!AA‰‰‰o^½Z¾dÉØ_GQÿÿ ⦑š7¯_ïܲÅÄÔtê¬ÙDÄ0ÌÒ•«†Ù±yóËçϹ6¶vvƒÆ¶#¢['’÷.ŠþƲlDxøöM›êº¹½xöÌÚÚzÎoÀ Ûñku4su+Ëãñ꺻=úî“€ö:qoí·… Ï^¹:`Ðàµj¥¦¦:99wëÙsßá#›wíÊRŸþ®ß¿ß«o_kkkGǮݻ9yjö¼y\QeÝ–-£'L¨X©²L.¯ãîžý" ÃL˜2õ›}ûp«RU 4ðð7iò-ÿGMš5Ëç=€ÂÇÌØêÊ•JÛ¸ë²^·Ñ@ñ"WJv=ÿºšƒ“iín—ë6€ló[ãÿá‚zͬ^~F"s]Åß[’ô³ïǯÛs»Zx6uúæ#k"ºñ[`¢/Wî^Á×Ò ¢nãâH®,:êΕ]ìÝû·ß£Óp °½Þñ*òëê&å68š·Ôº«.mÛ<¼wo銕#ÆŒ)˜à@_ø\À•—x‡Á x¦ E‹å±@køÐÝ˼U€¬©zH}&–Ç€œáI%@Ñ# O)å± b•òØd_×þR*Hhc¦$Ë(y"9 uQ® ©zIí:ƒ¤äOŠÉ„’dV®`åriŠ\œ¡TÊI!dzøþbyâ !Od&à ùŒ€/70—‘Hב}’z =|ý€" PÅC¬<‰'g$HS,&ƒ.(夔³2±"#QAD CæiÆ¥ X¡H"²b‹ÞÏ $õ@/aM=È ï€ƒ µó„GJY’"5#)R¢”ë:5,Kâ$¥8)ƒÇÏ0µ Ì $"K%¡yàHê€>ÂF - ïÝ:{媮C(<ÊTebrB„Có (S*(9\Â03G±•iÏB×}…¤|û€¢ä¿Óor„a5…ŠG CI|Jxº4ù<(X–’Ã¥ÂøDóÒb‰µ‚Ñýf<]ð=¨%õü±€°˜³Pˆ¬D”÷!=(vdbe܇t&.ZȦë:$õ@á÷9@Ñ$R¦1ñ± Á ’†â+%BªˆŠ7P$ë6 $õ  à73)Hê@žà—%ä –ãÌ%›&JH—ê:€üJ‹‘‰¿$È“tÖÔí±,¾þ@õß5õð%r þ¥oEú‡RTÊÝ$ñß\È7³5m(âÞ’ÿBe†"6!-VVhWø®ÄÉJ?YäÈ—òMuFêö†1X , æ"¾‰®ÃPƒÝo /D|C¾•!ßÊ€oÅ0|]‡¬¥G#[ã%^^ßj°rÙR[ãŽ-[h}‰òÖ?¶w;ɽìL©êSSSlMŒ›Õw׺çž|íEĪÇ_¼îOI“~)´ëòY“œ…Œè•ô¹".Q ëäê©ÚòŒ×8¢ë(²ðŸ‘z ’z‡yót|/»y¾zñâÒ…ós,ȲÁ¥ó牨³§§Ö— ,EËÌõ‰ ‰Z÷ùÈ)ª²oV8eˆeÄŇJ çr…)5Jfe˜ 4·WúÈ9ŒÔ½„‘zðUçn݈èõË—_BC3‰ŽxüXÕ¬`%%¡¤žTžø1î`lÚUˆg^8—6”%&…èf(@!Hú"6”Æþu1RôCŒˆgʱ|Æ@×á€.U¯Y³tÙ²¡ÁÁ—/\:b„ÆÑ«—.Qe·*+U.ðK'&&xŸyÄ&d¼‰H¾‘|#1ãÆƒÏ©'`¥Òø4…¬H/5J¥G¦ ]Òe<ã¼.Fꀲ1ªÕßíþ·ûܸÛMÖu8 K Ãp£ð.?—ùè¥ («azÏÆѨv­Ê.Î}ºuÛ¹u«R©Ì|zhpðŒI;´h^ÆÖ¦fE׉£GG„‡щ£GmMŒ{tìHDoß¼±51æ^íÙ£~ú«/ÆÙ¼Aýòöö]Ûµ].Nœ‘±è÷ßkVtµ51>ìsà[oYÉJ£Rî„->÷¦ÝµýÞDmMÌx«±ƒ‡€g\8«ˆŠ$‰©ÑXJô\F’B‘Åÿy¿+ŒÔ=×¥›ç¶oß¼™‘žndüïP™LvãÊUúï‚z,ËîØ¼yþÜ92™L$™™›ß¸võƵ«7¯]ݹo¿¡¡ªåþÝ»Ÿ53-5•ˆ ##"|öí={Ò÷Ô¥Ë&¦¦å*THINŽ‹ …Î¥Ks§˜™™©®²eÃú%^^R©”;ýŸß?¿ãGlÙåݨI“Ìï"66fî´é7®]åþY­zo½ßÿKÈxý­£"¾…“EëÒ–r¾qù&dÅé1˜x %Bj¤Ä¸|ª„Wx;áb¤è¹Ö¥JIÄâ[7n¨×?¸ç—’’ìèäT»n]Uå…³gçΘ.‰ÖmÙò9*úMPð½§OkÕ©sáìÙ½»v©š:ð×”qcÓRS;wëvËÿQHLìóã&M®]·^å*UÚwêäÿâåü%KˆÈµbEÿ/¹W÷Þ½¹Ó½·o÷š=[*•Ž8éé»÷ÁÑ1×üî5ðð é׳Gà‡÷™ßÅ/¯Û7oLŸ3×/ àܵënU«~ëýÚš6Ì\ifP¾²íЖ®ûºV¿åî²ÐδqÞn¢V’äŒDE!\@ç¤éJ^FZa^I=Ðs c—®”iîåó_çÞòx_g¤§Ï>ˆÖoÙ:`Ð`‘HÄ0LÅJ•wðáóùëV­äÖ¥¤$Ï›9“ˆz÷í·Ûç`ÕjÕx<ž£““×’%GNr˜—””´ÄË‹ˆÆOž2éRg>Ÿ_³vígÏÕ¨U+-5uñ¼,¶ä>wúô«×̘;·Re·‰D¢oõïdÞš+0 ÏÆ¤^MÇ©Üδw;UÓqJ)“ºLa¥ø$—$bÇ[(AÒbÄB¶ð†¦"©úïŸeõγì¿KË]¾pˆ:©-¨çû÷±Ðšµk{öê¥~z™råš6oô™ˆÎøú&$$ˆ æ-^¬Jrøüœª;ã{"%%ÙÄÔtüÔ©êõ††SgÎ"¢s§OÇÇÅiœU«NÁÆåæÍZ›Ôv¶hW¿ôânÕî´pÝ[Ùvˆ©AÙÜœX°„²”Œxyá_@W$©J´ðë!©ú¯E«VÆ&&‘/Ÿ?çj‚?þðþ……E“¦ÍTÍüîÜ%¢f-Z2 £ÑCÙòåˆ(èÓg"ò»}‡ˆÜ4prvÖ"˜ûwýˆ¨~ƒ†VVV‡Ú´oOD,Ë>¸wïßZVID½úöÍU–ây”]]Öª{áìoûMR©So¡DaI)‘jlJóý ©úÏÐȨu»vDtåâ®æòÅ‹DÔ¾Sg¡P¨jND›×¯SíW«zíóö&¢˜è("ŠŒˆ "׊µ †;Ëj026¶³·çÚ¤J‚ßÇì¹ñqP\ús"ð‹Ó^—|’ËR°é-”8ñR!Ò¬óâô‰ µÎݺñõ½|ñâä3éŸì^gµ¹·DÄMέ^³fÕjÕ³ìÄ­j5"R*•D”Ëqs™©OÎtHÉ’œˆ^Gn¹øn½ªšˆ$òí.§|¥$=so¡Ä‘¥+åb™À0ç¦ù†¤”í:v>Œ724¼së–ÈÀ UÛ¶êm숨Vºë·nͦ+[;;úg*®¸«„«jJqTª_xÒõ˜1QqDdh•Hd¢~V²$P»ËéO.‘I i"@Ñ¡TÉå…“oÃô[(,--hÖ\©TÞ¸råîíÛ±¸U›6&¦¦êm5iBDwoߒɲ›:ÚÀÈ?ò‰É¦Ï'"…B©QÏ]屿tܧ øã~AãN¿nz/hbp‚ïS¿0®kÍGúð™ŠÊäú½rya-,PÄÈ iŒ*’zPRtöô$¢Ë.\¾pžˆºxzj4èÚ£‡‰©iHPÐæõë²édzgO‘AzZÚŸ‹iÌ¥MIIV•¹Õñ¢£"ŠÿlÑ­gOSÓ””äßýøø‹WDòM…RBDr{Ö;ˆj551³XU©j?ªM¥#VÆ5‰ÈHhŸ·^è”HéA Å*°Q@êÔµ+]»|éâ¹s<¯}§Î ¬­­çÌó"¢%^^¿ÏšÉ ÄcY6øóç9Ó§]¹x‘kfkg7yút"Ú³sçø_ýøá˲ááÛ7mªëæöâÙ3®™[•ª</))iŸ·7˲éé DdeeÅ]åøŽ·¾[âc䬒Â¥k'„‡¼“ f/˜Õ©êÅ6•ŽV³kiTµîNbYÍñ‰%«d g\¬©%…£“S½úõŸ?õïØ¥‹ªŸÏ_±n}çnžÇzñìiHHH]ww÷† 'OŸÁͺå¬Û²ÅÖÞîòù áuÜÝœUW™0ejËÖmþX1úÓëÄȰØ:õj6òhÇF7øÐ€|IËH¯ÚªAžNù¹gße3½Tÿ”ÉdGΜ¸õàî§Ðàà/¡&FÆŽöÍ6öl×¹zå*™O¯×¹yl|œz Ã0¥,­lKÙØ–²©^¹jçVíkW«‘Ë`Ê8¹p#ãRVÖyz#P˜Ô=ÄbÍ{È<¬€¢âÂ+ ×-ÿ¦ªKÄq‰ñ/ß½Þ²W·¶æOže[Ê&ûNX–MˆMˆøþÖ¿-ûwµnÒ|Õ¼%¥,sNÒø‹‰‰Ið—ОºZš[ä÷ýÀwƒ¤ LT€"¿Ï OÔ>40¼òÇ@(úsÎÊÈèè5;7Q¥ò®ÃûÒ8Z±l®pîúåÑs&sëB8;86voèlï˜!}ò{üP,Ÿ¾rþñ‹€c[÷¹8:ktÂ0Œ÷ŠM\Y"“&&%Æ%Æû=~xïñC¥RyÍïVŸQƒÏî9jdh˜}ü`hŸŸµzëP¨Ôƒ|Àz™Pta£ ÐRzO ¿ç•ï>~à’zNö™rÄñœ?p½©¿Ž;h¸@ðoÞ&19éÍk||V¯\ÕÁÎ!óé<†×¦i ÊñCF†EF Ÿ1þÕû7AŸ¶þå=yø˜ü¼;(:ð;ô6Ê€¼iñJŸŸûn×z-ãʧ.Ÿ+À€A·0Rô6Ê€<Á“н°È®P·z­o}‰Íý~ê*W¨hafž”’ü94X¡TðyÙå?nÕ¯+unÕnë²µê‡X–½îwë€ïÑO!A_"ÂÍLM«¸Vîܪ]¿n½„B¡A~ ©ù¯¿PDa£ (v*”)ËÞ~|_°=3 ãhç”’¬T*3ÄbSc-:‘ʤæ»yÿ®ªF/¹ïŽÿ½í>{æMšÙ¶iË‹rI=ÐKêkê!©9øïs|h€nÔªZÃ@d ‘J.ß¾~ììÉ»t/¨žårù§ "240412Ö®“ÅëWp=÷šuþ׫Ÿ“ƒcð—Ѐ—ÏŽ;ô%D"‘T´KHêöxŒÀÎØcaà¤ëpþ…‘z'¢òre:±,K,Ãäa•"€dafþûÄé¿­XLDSÍ9ræÄÄ_F5©ß(ÿëÉ\ºuM*“QÃ:õ´ëM®P>}œˆªUr;²y7ÙÖ£nƒ~Ýz:òî£]ÚtÈgWHêö =+¯×uYÂH=ȇßtÑÿzý””’¼jûF¥Ry?Àÿþxÿê•«ìÙ·{ûΦ&¦ZtȲ샧¦-þú—n`Ï~Úš!QƒÚõ4–ÏsvpêÛµ§vÝB~ ©z»ß@qÄ0Ìø!#›7üaÍÎM×ünÑ«÷ofÿ¹`Ñúå=;v=pXg—o«d•WïÜäÊR¹,6>6:6æÆý;Ï^¿ä*{wîÞ¡Eí+ãäbld”ž‘qãÞ¤”d 3síú„¤è!¾¥•¡±,kÀ·Ðu8yP»Z=«·}úëÄ‘cç|“SRÒ32œ8rèäß¿ô8{ì ‹|˲C§É²C¡P8zà°É#Æh=“W üعǾ¿‡…vÒgäÏC{vì¦Ý†PPÔ=Tμ}9óöºŽ@{ËU˜?yÖ¬1“N]>¿ëо7ïJÅŽƒ{_¼}í³q—€ŸÃ"°6VÖNŽ.Nµ«ÕìÞ¾‹“½C>ã™?evjZêñ §C¾Ì]¾hÙÆÕ=;vëß½w ¿6Z± IDAT·jùì´ƒ¤@eh`Ø·kÏ>]zø^:ûÛŠÅ)©)÷üwøìý¿a-ù<þg¿çß/Ÿ¿vþ}»õÚ°gÛ]ÿû©éiûÚüPÓ›0½Z%·ïwiÈO×@v†éÙ¡ëæÅ«¸~xüâ)ײ~­º#Z˜±±,;ÑkæÇàÏ“ÌÞ{ì`¯NžÕ*¹…„‡íÿûÐÿ{DÔ³CW;ÛÂŒ ÔÐ1¡P¸bî¢ÖMšÿ±yMЗ™Lvëß­~êmDBÑàûO1V$fl ì[ðçÜå‹îøß xõ<àÕsMê7Z6k~a†„¤@QÀ0LçÖíÛ7o}ë¡ß¥[×^>‹ŽMIKuqt*Wº¬[…ŠCúüìhg¯“ØÊ—.ë³açó7¯N^:{÷Ñý°È‰TZÖ¥t…ÒeûyönÕ¸Y!OBRà{ss­rÿUnZ ‚ÖMš·nÒ<÷?9wKÛ¸²àZ¶ü·B­Uµz­ªÕ ðZØ( ˜AR ˜AR ˜AR ˜ÁF =¹R™ö’ˆ!"c¡•µay]G ˜Œç2e*Ããhâ¡ëpr†¤h/Cžpöã®ìjÙ¢m¹9º@;#—ÆŠ_C¼AUŸë:€œaú-”t,±º o0RôPª,,UΈ¬ *‰øæºŽŠ8$õ ˜AR´÷ŸgÚ £»@4}H<ñ3 x@RôÐ:0øc¹…é·P\àw|€"„UÛ(?Ñ G,& ”ï?¶û¹G•Võ½V-eY|þë‰5;7•ñ¨^Æ£ú¹k—tKáARòPdaM=È ÓoJЇö½ûø!=#c÷ÑŸB‚t€öºà;ÀCWÈJ'®`bd\Êʺ@úŒŒ‰:xò þq€µ¥UôY|án$õ ``v)ê3鬩9Ó€’bÔÀ_LLL‚¿„öìÐÕÒÜ¢@ú ú´fçf"òl×i,ÜBƒ¤h«Ï@†é·ªo5 ƒO ='†öù¹`ûŒOL(Ø‹5ÜBƒÁ  ‡þ3RI=øž’’tB‚»QhÔ½„‘z |b@žalš:Ü >Ÿ_øÕ9L¿=IJ©ÚÁ'€žûü¹U¿®DÔ¹U»­ËÖfyè䮃u«×R(§.Ÿ?ræÄ»À÷R¹¬z¥*õŒ0ÄÔØD£½Šú?[xü°ív«§gdøø=wýR`ЧôŒ ;Û&î õî_«jõoÅyÚûpíj5’SR6íÛqîÚ¥à°P‘Pôöº¿@ ÈM›£g}§.šKDsÇOùóÐÌ7¤U¿®ƒ?óyüÏ~ϳ àÄŽî5ë$§¤ì?~èÜõËŸ‚?óür.e:¶h;¤ïÏZßÜß uq‰ñ»¸|ûZpX(Çw-[®W'ÏÿõúÉÌÄ4›³ô’z —ÔFêa…,ÈV €ÅÆÇÅ%ÆO˜7óöC?Uå½'þ÷žø_ºuýïmûŒ´èöáÓÇc›­ªùvä̉#gNŒòëô‘²\Ú5!91<*²ÿ¸_>‡s5U*Vym£µÈè¨ó7®ü¶bQL\¬ªòù›WÏß¼ÚüÐþµÛ+W¨˜×>µ»o^²hnJjŠªæÙë—Ï^¿üûÜÉÆõæ5=€¤hOÈ3rµlND,±ö&UuÀ¿°¦䉓É–‰X>c ëX@÷®Þ¹ñÛŠEÑQ®eË·ù¡…©‰éëo/ܸBD¯Þ¿9|úï¡}‘£ƒÏ†D´Þ{Ûý"Z1w‘³ƒ#׉•…¥zŸwýïš2J&“ñx¼¾]{6¬íneaùþsàþㇿD„mܳÝÚÂjxÿA™ƒ‰ŽY¶qÕçÐ`G;ûM¥Ri…²å´h£µkÿŒŒ‰"¢f ›´jÜL(>{óâÚÝ[ñ‰ ÑQýÇ»z𔥹Eîï†v·âÒ­k#gOR*•DäZ¶| ¦•Ë»ò{ô€Ë0Ôû-FÔí ­Û–›«ë(²„5õ ØÏÐuP„øœ<Æ0Ìì±SFþ<”ÇûºÁáÓǧ/ùˆ¶ûìÒçg†aŒŒš6hLDOþ͵©_«®kÙò™;ŒKˆóÛT™LVÊÒzÿºm5ܪqõmš¶ø_¯~æ»÷ÄùÖu?vénin¡qîêã"tÿqþ”Ù††Yœ›6Z‹Œ‰²-e³ú÷¥-<~ø§®ÿ—ˆ°ÿMù1øsL\ìêN›Ë»¡Ý­ˆ‰‹²h—Ñë×­×’¿‹„"îR©ôñ=ºlóõ|%6ʽ„‘z %#cï›Fÿo˜*£GD}ºô(íäBDa‘á‰ÉyÛàuë_Þ I‰D´fþ2U‹cjbºpê\'–ˆO_9ŸùÜð¨ÈvÍZ-é•M¶.7m´Vŵòå¾j=""Gç —såcgOfˆÅ¹ìM»[±ãàÞä”"jÞ¨Éò9 U="âñx{õÖo`ÞßY±‡¤è!+ƒ*eÌZ—6kUÚ´¥o¦ëp 8iáñC›¦-4*y<^íª5¸rDtTî{S(‡O'¢z5j·ôhš¹›k¥ eÊчÏ3ðù^“f©§µk£µ eÊZ[Ze®¯áV­nõZD”šžöþS`nºÒîV°,û÷ùS\yÖ˜ÉY.·—e¥ÞCRô›UßV.ë[»lh]z£™ÐE×á€>°µ.ÅÔwxÈÑ«wo¹‘}ƒÝÔ•s)CDªm.Ô5÷hZÆ9‡/´¹ió=Ô«Y‡+„F|ÉM{ínŧ nŽ eÊi î+á°¦@Î ¿NnU*”¹?+$<”+¬Ù¹yÍÎÍÙ´ ŠÌâ¢"QæJ-Ú|ö6¶\!4<,7íµ»_"¹7ˆTÔø^’’“¹Ã0<&»“™wÉ(⌌¸·L^Ž´»I)_W0t²wÔ&Jý…¤À÷bfjÊ& 3yøÝS°Tô¬,,sÓ^»[aldÌâò žÃšzß‹³ƒWxöúEá_ÿÏÀ;û:¶´“snÚkw+JYYs…𨈼D§ÿÔПÿ5»¢P(2­U¥º‰‘1=zœ’R¨‘ÙXÛp…¸„,†¹±,+•É´ë9)%ùî£\Ù£nU}6wC»[QµbeŸOD¯?¼Ëå<ßI=íÙªgYÍ …Ý;t!¢ä””¥WjdDŽvö\áÅÛW™®óÞž«k3ÛypoJj µðøÁæŸ})Û»¡Ý­040lìÞˆˆÄñž£>™(”ŠwŸóþŠ=$õ´çìðu‡+·¯gÙ`ü‘Ü5Ÿ“ÇÖîÚ"—Ë5¼|÷úÝÇß#6GgSS"zô<ÀïŸuD¤P*þؼfõŽ9öpåÎÍÕ;6fˆÅê•>'mÚ·“ˆ†™øËhõCÙß ínÅ/}r…-ûw»vIýPBRâ I£4*Kl” ½®m:.Ù¸J&“í<´ˆÕ­’š:fÐp®³ƒã†E+F̘ P*VïØxñ敎-ÛU«äÆ0ÌÇàÏ~\¿w»a÷£[ö2 S°±þ¯W¿-ûwÑÀI¿þع{ÅrâÎ\½ö¥nõZ•Ê»9s"›¤2éÚ][ŽžõíТmµJn1q±÷ž<¼õÀ;:ñ—QõkÕÍýÝÐîV´þ¡y—6Î^½(–ˆG͙ܡE÷šuìmíÞ}üpô¬oL\¬ƒ­}dLTÁÞº¢I=íÙÙØÿiЖý»X–Ýqp{‰È@d0ì§ÿˆ ¸6m›¶<°açD¯™Q±Ñ¯Þ¿}õþ­z<ÏÙÞ1]œaòÏN¯hDÿÁ§.Ÿ‹ —Ëå‡Ný­ªïزíªß{9ýém›¶´´°8vö¤÷áýêõ|ʯcÇ þU£}ŽwC‹[Á0ÌšyKe2Ù¥[׈èâÍ«o^UµŸ0t”g»NmtÏë)îÔÈ—™£'•u.}þÆåw“R’œœÖqOMOS%õˆ¨‰{ÃÛŸ?zÖ÷âÍ«¯?¼KLJ466.íèÜØ½á Þý˹”ùN±ÙX—:í}hÓ¾/Ÿ½ûøÁÈȨFåª{õk׬Ã0VÙŸnnj¶ú÷¥?uë}øôñ'/Ÿ…†‡9ØÙ5kØä—¾+•wÍò”ÂÐÀpÇŸë/ß¾~ä̉€WÏ’m­K5ª[HŸŸëÕ¨-–ˆ3Ÿ¢÷˜[¿þPÚÆm\—õºà;9æ·ÆÿÃõšY½üŒD溊ôŒ\!YtÔ+»Ø»÷o¿G§á@¾DF~™5u(Wv©žQ·kRa^ý½Ÿé»Û¦\yò´EµëzæÕ 0:$9*‹­`¡¸øü¹U¿®DÔµMÇÍKVé:œâÄĊǸ¸(ˆ_à=û\À•—x‡2 kJ%’³E’zÅ ’zÅ 6ÊíI)ŸoseKƒÒަ5u€v>%•³D$`Œ*XtÑu89CR´—&‹½ºŽ+W)ÕI=(¦žÄ¬I“E‘±ÀI=(0ýJ:–eu@Þ`¤衈´iòH†ˆˆWμ=Ÿ1ÐuDPÄ!©ð®eˇÜ¥ë( ;HêöðHЬ7ñ…¦^çÊN&MŒHê@.1º W0ýôKJU™ÁOtÐ;Hê€^RKÌ ©9`ÿùÐ`ð‰Å’zÿþfÆ@(RØÿ|@ä>3 x@Rô’úªŸøc9ÂRÁPÌàwè!–ÅPbÈ“¦ß⊠$õ ?ÔŸiã0)ø€}†¤è%l”y ¶'>1 x@Rô‹| OX¬©Å ’z ‡Ôã 5¬œ[¹ý>ûu0$õ@{x¢ E‹5õ(::ÚçOTTÔ®=»t @Q§6ù¶„~b@±ƒ¤èÀäé“,¾õê?¨¿FKõšo9sþLϾ=ËV.kå`5¶û™]ó¢BßKˆ(û¤^î#)²RRSŒ,Ü=Ü5êíììFÿ:º¢kÅ c&è$0€b «pž@×!è#âÎ((ü ƒoÀw<ÏÈÐ(s½¡¡ažúIJNš2cŠÏ!®O ‹° „° ò¿œ:p¶íÀ9@T$:‘˜˜ø­C«—¯.ÌHþÏÞ]‡Gquq>³¾ÙM²Q¢ÄJ ÁRÁõkK…¶´8k‘(ÒÒ¢Á­Ðâ…ŃC ÛÊ|,]&!ldIø½Ï>“3wlÂÎÉ;•î@(k¸H„÷_ÀSVÈ(:õ 4ðñJ%°kà–[JßOèùЭ۷¶hÖbê÷SëÕ­'—ÉÿºÜoéÏ'ÂNgnþ%á‡A‘®ÎQ$§$;€*O¿(c ¿Qá=Åð‰­O¸ý*½€N—B/9x¤U‹Vr™œˆ,«I¾ü©šTÎÓ¨Ù‹/;ÁòUÌH=x[˜S ÌðPp€÷UE½ùñ3†“ ulûj_N¦ús9T¤Z¾µxÜÿ;YV(f6"JMK+eçIIInR…T{‡¯Î¿×ÿ•*¤–v–‘º`ø‹ðQãFµlÛÒÊÞÊÝÛ}èð¡QÑQz^»>dèÚõk;¸9tíÙuùªå†Û M§6R…4&&&3+óç¹?×iXGQMQ£fQãFÅÆÆêšíصCªvìÚ‘ˆîÞ¿«› pýÆõÜ~–._Zð nÞ¾ùõw_7hÚÀÖɶm§¶Sššš–Z°™¶‡øøx–eÿøóæ5·²·òkà7:htfVæÛG€w˜å'µ¬¾¬eõE EocçPE0¾±S0Ž {óãö[0œLhÝÄaˆ±³(¡Œ Ï#¢fMš•²/KKËŸ¦þ4rìÈ©?MíØ]f"ÓÆ§ÏœNDãFsrtÒFÖý±nâ÷323ˆH"‘DÇDÿñçûì;zèhíšµ‰ˆeÙà•ÁßOý^©TŠD"33³ã'?yüÄÉ›ÖoÒ›Âo÷¾ÝÁ+‚Ÿ>{Ê0 ˲‘«Ö®ÚwpßñÃÇ=Ü=ˆH&“¹»¹§¥§%$$…Bg'gí†f¦fÅ–]¼xÚŒiyyyÚ<Ï_<þâùí;·¯_½¾ÐÓõâ勱ÇîܽSûå£Ç=~v3ìä‘“˜Sª†:ÖC@U£á‹"F•‡Y›àýÂ0D‚ ª¶a¤T5J¥òܱ—‹FE³jÓϼVÍZ¥ïó‹Á_ø×ñŠŽZ¸x¡6röÜÙNüãèà8fÔmäÏ-5,#3£[@·«®&F%>¹÷dÌÈ1uýëúxùhÛ<|pü¤ñ"¡hÅÒññ/½¸qå†ÿƒ‡®Ù°Fo§ã&ŽËÎÎ^»bíËÇ/£ŸGÿ±æ™‰,66vò”ÉÚ]:u¹sýÎ쳉¨†G;×ïh_½{7Ôhåš•“¦LÊËË=bô£;".ž¹Ø¤q“/_tïÝýᣇ7éѯÇ߇þþuî¯Ïî?{zÿé¤ñ“ˆèÒåK§Îœ2ø”@Õ¦æKD2Ôà½#”2¸bö…00š½û÷Ê­äz¯«WÜá÷Ó¾÷õ÷µu¶ýmüeF-ûcÀ´£J2CÖ3áóù‹æ/"¢ßþɲ¬v˜Þì³M¤&D”–ž6áû DÔ¿oÿ­›¶Öô©ÉãñìfϘ}`÷@@DYÙYAƒˆheðÊÁ‰D ÃxÖðܲq ŸÏŸ¿`¾vèœN‹f-.‡^4`•••B¡è×§ßú5ë‰èÀ¡÷Ü7쥦¦NŸ1ˆÆŽ;gæ'G'>Ÿ_ǯÎá}‡ýjûedfLýijÁ­†9ú÷ÑáC‡ÛÙÙÙÛÙOÿaº" 9bXPå©H(6; €Š&µ)iÅì E=0&u,kø=?~öüYNNY˜Ù9JÛÔ·_ÂgY¾1“F  þxpvNö´ÓŽ?váâ…&›ôíÝW»vïþ½ÉÉÉb±øçŸ~æåŸ—Ï5§ÆÎÝ;_¼|QǯN¯½¸ \]\?lùallì³çϸñîݺ[[[s#]:vÑÞê{䨑’TA{öïIKO“ËäA£ƒ¸q‰D2yüd":ð÷ÄÄD½­‚F5¨ß€iѬœ.@‡ 1Q¼oøRaÅ<ú–PÔ#êØ#;%[ïõí×ßÜá¦õ›îß¼"äÄØQcãââÆM׫/m¯L2™9}¦¹™ùæ­›GŽIDóçÌ×Í(w6ô,5¬ßÐÑÁ±¨½„ž %¢Ö­Zœ‡ÎÍÕˆž>{Z|ž|>ßßÏŸˆ^¼|ñƃ*Ô¹ó爨QÃFz«:´ï@D,Ëž¿t^o¯À¼lml‰(..ΰ4à} É%æx\¼G„&ŒZdRa»CQª±XìRÝ¥i“¦?ÿôóµ‹×ªU«vìø±%Ë–”Uÿ666ãF#¢ðáÿð¿úõ^?ø;:&šˆj|P£˜ÍµãÚ-]¤{L­îµvÃZ"Š‹sÌÖÖ–ˆÂÃà ;mžÚ¢©IµjÕˆ(::úý…B"*ͰJ¨òT$–ZUÐäbï¹­XÉ«¸¢ž~ U“ƒ½ÃÔÉS‡¾fýšñcÇ—IŸæÐ‘CÚ司8–eucî4 ÿ(Xm ̯–Ÿ¯¯o¡ |½ s¥g¤_`ཋ/ÃióG©ÊŠZ,Érò25ÆN Üñ… IM*ìÞ[BQª0¿Z~Dôâå‹Ì¬L™‰¬ônÞ¶ù⥋];w½yûæ±ãÇöìÛ£›O;€®øûgíììˆÈ¿ŽÿÊà•çð<ü99Ø;¶¹6m'z²²³bbbJÓ9€ž<¾L^-#éi–±(w¦â\YEî·ß@¥WÔȲ˜Ø"273—JÊàùS©i©ßOû^ Ìýyî¬gQФ í¸9"jÒ¨ ]¹z%>>¾¨š5iFDgBÏ(•JÃrˆ‰‰¹qó†nwZ|ŸˆÔuIzÐæpåê•ÔÔT½UÇO×.p;(%µT.1ÃÌzPÅ $r˜a˜‰AK¿—;÷î,_µ\.“O?™ˆ†ù}Þï Ã,[¹ìæ­›Ddkk;aì"Z½nõWß~õèñ#–e£¢£–®XêUËK;¼ÎÒÒrúÔéD4mÆ´ ßOÐŽéÓf4)(ähˆÞNçü2gÈÐ!=dY62*2hRЊÕ+ˆhÆ´ܱ‡>Þ></%5e통,Ëfeg%''u ÚæÍŸ7õ§©QÑQæÖ[=Ân„™HMfþ8³ô§ €+Gliî,1våÅÌ^”+¶¨øý¢¨F³wÿ^¹•¼àËÁMN·¢Z.]±ÔÁÞaÏö=vvvhÙ¶¥¹­¹µƒµ¯¿ïÖí[ù|þœ™sZ·j]ÊLX–4F­V9F7Š­~½úƒ?¬ÑhFŒ¡}JÆÄ ‰C>BDmý˯Ÿ•½•‡ÇøI㉡ȨHíVþ4&ˆeÙ%Ë–T¯QÝÅÓÅÖÉÖ×ß7xEð¶Ûô²jܨñö]Ûë4¬ceoõïÁ+‚‰hÒøIýúôã6s°wÐFFåàæ`WÝî—ß)æ`‡}3lÖ³„Báüó=|<¬¬5otîÂ9Gǽ;÷úxû¼ñt¼ ñÔr…ÌZhìDÊžÔœÏ(ÌÕŒÞÞ(ê€1© £Qò|´B[KDÔ¦u›°Ëa¿Îùµi“¦VVVVSÓ§æ ƒ®]¸6jø¨Òg²s÷γçÎÚØØŒ>’»ÉŒi3æŠËW.kïóåóù‹_¼oç¾ýúzûòx¼úõê÷Íwa—ºtê¢Ý„a˜™Ógž91øãÁ~µý2Ò3{vï¹}óöu+×é¥4¨ÿ Kg/õëÓÏÒÒÒÞξ{·îûwíŸþÃô‚w¯X²bä°‘ž5O˜š§4v.’*{Ól¸i ¨'—o*°ZÊSR_ä¨U¸5*ŸÌ$j¹yÏÄØ¹ ¨KÅ“¨eÕ$åÄge&ªŒ@‰˜Xð¥¶Ò‘•æÝxð,Šz`¸Œ¼¸;‰""ª&«ébÖØÈ äßøEÄjˆa5o‹ÆNà½À“%´Ø›ZZ¦ä$æf%¡´ï.©9ßÄV¬™eñ¤ÆÎå5õÀp™ÊİØmÚåÚ6=PÔ(+'BN;€÷ËíÄu,«&"+‰ŠzIňT[¾ƒÒÒ*E¥ÌˆËS+qC.¼+x’Ûˆø2¡Fj–Ec§£E=ÆØ ¼ÔŒ0[bÃH4¦Š,63›Ñ(óÒTyYU |PÑøBFd› X€g"ÍãÉ”ïÆÍ¶¡¨eŸ€àr7icž:axBžÌ×òSc§ï<ÆÇ/—''S9 Ì•rMO­$†eYUJ6oìü êÒ¨I 2 C<ž†'Pó¥¹$4vRo†¢”>þÀ;ênÒ¦Le4IÖ(êÀÛÀß)Þ *ªxÂפ쌙 ¼*㜎ïèB€ÒÑýÕ×çðüÒ€JE=(+ø ïö¿;ép}%Áâþ¨lPÔÃáã/¼Ã^ÔkÜ¢±T!6cZQMgÏ›-UH[µkUæI¤g¤KÒúMê—yÏPÖþû¥Áà/P9 ¨Uî¯ ÃtëÚˆBŽ„ÕøÐ‘CDÔ½k÷2O#%%¥Ìû õ ¬àÚðŽy=R/0 ˆnݹõ2âeÁvqqq×þ½FDݺ•yÉ)ÉeÞ'”îÍøPS¤6ÚÈ­äOž>1v"P¥|6p€ÌäêåËÆN òAQª¤×sêÕ®UÛ¥º >r¸`»#ÿ!"o/oÏžežFêT:å]ÒS©TkÖ¯iߥ½½«½©µiõÕ»tï²pÉÂGq›É­äR…TªîÚ³‹×h4.ž.ÚUËW-×ëüLè™ÁCרYÃÜÖÜÖɶeÛ–óæÏKLL,“Ì>xáâ…>½úx¸{pã —,ÔæSüËÅÓåmOõÔÛ‰ÌRæèîØ¾Kûe+—åää|,%ïvϾ=Ü–&&vÕíZ¶m9{Þìädý?Û øxÐ/CŸh_#{n·‘™p_ŸöïÇmüiÿ~z Šjlgfª îÛ¥ÿfðusÕ®Z³bE¡ÝV3•{9;vì°fùò\Ρ/ZXÌÞu/_7×·ÍöÏ tqGK‹ÚxôêÒeñï¿ó☠‰hæ´©oüÆ€õ  âLúÉ0 £…WhQOÔ¦w=ìú¡CjׯíàæÐµg×å«–k4šBwþ"|Ô¸Q-Û¶´²·r÷v:|hTtíØµCªvìÚ‘ˆîÞ¿«» \¿q=wó›·o~ýÝ× š6°u²mÛ©íÔŸ¦¦¦¥êí¢M§6R…4111;'{ÊSܽݥ é_[ÿ2ä¼@a*lšàÔÔÔ¶ÛŽ3"ô|hJJŠJ¥Š?yúää©“{ôíQè&»÷íæ~z>4..®`3F3rìÈŽ];nß¹="2"///=#ý굫?ÎúqÖÜY¥Ï\£ÑLÿi:Ã0ÇM,eWœnIII¡çCÇMתm«¤¤¤R&ó¶Ý²,›š–zõÚÕ™sfÖmR÷ν;e’@ íß»‡ûå…s¡ñ…½¸´‡v!4trи–Ù+¡¼Üܘèè³§OÍœ:µ¾÷რmV§nÝ6íÛŸ?{öøÑ£™@€¢”Ì* ï½§ßvïÖˆN9••Åm¦T*Ÿ8Nœ õX–]ºbé‡í?ükë_/^¾àóùÇO;alÿÿõ/8*dÝë4m°jíª«×®jXMtLôþQ¿Iý[wnÉd2w7wkkk" …înîÚ—™©™nG‹–.jÙ¦å¦Í›îÜ»£T)Ï_Ÿ_°½›«[È‘î/®Ý{w3 ãêâª×ròÔɫ׭fæë/¿¾zájJlÊËÇ/·lÜÒ²yË2ÉüØñcwïßmܨ±·þA}õMÄ“îKf"#¢Y?ÎâÃ.…vˆ(°k`rLrrLrìËØs'ÏõïÛŸˆnݹ5|ÌðÒÔ[uþ0<9&9!*!ìrØOS2‘šÄÆÆþoðÿÔjµ^Ëüd#æ»Îù£ûƒ/¹¯ek×ì¶c—.zÍŠjìâæv,$$;ëõ›aÿîÝ ÃTwu-Øm@``DbRDbÒÓ˜˜cgC{÷ëODwoß9BÛà˯¿ÑÛ£‰LFDSgÎäÏý{ݰlù|~DbÒ“è˜ aa —-«áé•––öù gN,˜-}<ø3"Z±dI¡k (c'•ž~ ï°|²lÒ¨‰••UbbâÉÓ':è¿x>-=ÍÁÞ¡®]mäàáƒã'—™È–,X2°ß@¡Pøèñ£ÁC<|p͆5Ǿ¾ÒûsËŸÃF #¢nݦO™îãå³tùÒ°a>^>µkÖîҩ˦͛¾þîë5®]¼¦—ßÊ5+'M™DD£GŒ6t˜½ýí;·G}ñÒÅî½»Ÿ;uNïvài3¦:sê‡I?ôíÕ7%%¥àu5” ¦ÜŠzá/Â÷ØGDëV­ëÒ©‹6hkkÛµs×®»:égÀ /8rôHÏî=‰H£Ñì=°·q£Æ Ã<®köïõ—._JD3¦Í¤ ŠÅâ=zöxúìié“׎2îÛ«oÁUR‰T*‘Œ›˜˜XYYé 8 DÄãñ$ I$’zuëmX½!//oϾ={÷ï‹‹³µµ5ì Þª[±X¬mìåé5aÜKKËcFòÆžÀl…<ýV©TQž2¯à ›E1•›¶û¨]È‘ìœl"ÚµgÃ0=óM<§Ñh<@D}zõ)Éïœ>{Z©Tº¹ºU«V­”]p ¥+ÿ•íóˆJÞ­@øê7*•ª (†ÜÔô£¶m…„ädgѾݻ†éÚã ³ê8½>4ã<–½^ƒŽŽDôÏ‘B4jÚ”ˆN?^¡iTr(êA)p.ŒËï^C°ºçZ¼úíÔ¦u™‰,:&úæ­›ÚȳçÏ<| 0Wèæœ =JD­[µf ÌêæêFDº»ØÎ†ž%¢†õ::8ݹó爨QÃFz«:´ï@D,Ëž¿”of½þ}úÌ Ê^¹ý ÕªY‹ˆ”JåÌ93Ù ìÙ½gfVæÑcGµ÷Þ6¨ßÀÉщÛàᣇééDÔ°AÃ2ÏYK;ÑgýzõKß•a'¡ Ýºæææ¥ÏÊ€nOœ<¡]ððð(¾eêÖ³gVfæ?Gjï½­× £“Ó›7#"¢ˆ×‡¦(·ßÀ·V-"ºuãF¡kýëÕ#¢ë×®ååæVhZ•ŠzPqn¾}u}.•HÛ·kOÿÎÓ-tîÔY(j#Ú×.ZºH÷°ZÝk통Dÿê9ƒÚ§UÔø †aéi7× õ˜HM´ca¢££¹ñ7ÞÒ ¥P·ßz{yv $¢_ÿÕ¿‘ÿ³~|ôpÞüyD$>úð£Ñ#F·iݦÐMÌÍÌÛ~ÔöpÈa© iŸ˜Á•–öª"&—ÉË)혘"Ò>λô 8 FûüñÑàgJjwÄ}x¥NVv–öúÙÁÞÁ°ÎàmñASûé,˱RMùíÈDj²|Éò‰AwíÙuòôÉK—/edf;~ìØñc£GŒž3sN¡[õìÞóð‘Û6oªW·^uçêå—^Q´S|Z(ô§ 0Œ'aÿÁývú{÷õö ^\šLJÓíðo‡ÿ4í'm¥UÏ~²€Ïllý{·YÆ›˜Ò¸S@ÀÒÕk Æ mLD={ Ùúç&ÿzõœ«ùfø{ÿ~'+K½ ·ÏoK–µII¼m¶zÞø—0……"##=)ÿ”²P Ü~ †3ZúZøZøZw­&ó1v:\š‚!…BѪE+FóωΜ=“““Óî£vܱ-Íš4#¢3¡g´S¹£I£&Dtåê•øøøbšñy|"Rkôçƒ×îèÊÕ+©©©z«ŽŸ<ÎÝT†xžŠ¾^ý¼,úW7-|°Xruq7zÜÁ=£Ã£þ}´]›vD´pɇھ[—nB¡P£ÑúðYSSSíBFfF9%œ›—KD"qY>tûmO‚ÇS(Íš4ûeö/¡§BËjð`Iº ž“s`÷ÏžK—/]¸xaá½ñIl“ʄæùé¦zàõ›Ó˜ˆ:u}õf(á½·ÚCkܬÙÌ¹óŽ µ*Ý{Ûlõdef‘©™YQ Ä iŸ%¢TAº{Wõî¤ÓÎåtøèaí„zݹk{ö”ËäÏß/Zº¨øþ{uï%‹3³2 ÎõÎJ{Wll¬Þs{uï%—ÉÓÒÓ,YÀçææÎž7›ˆ:ØØ”ãp!x‚–Í[îÛ¹OûŒ‹›6ÚL¡PÌœ>sèWCûöî[p­n*½Bÿ– í#}RSôÿQ&JrzöÈNÉÎNÉÎLÊŒ~}<äøˆïFH%ÒRîú­º‹Å‰ÄÜܼ]›v{wì•J¤³æÎÒ>B¤")Š)3f|ùÍ7=ûòfÐéÚ£G|fV|fVlzƣȨƒÇþ:b„DZÚ3VJQ‘‘Ddgo_Tƒ”äd"²(0ÆŠ‚¢TA «MhTmRÃjkZ}Áw èFDGÿ9ú÷á¿y<^—Ž]¸k---§ONDÓfL›ðýí(<–eŸ=4)H÷„ "²µµ0v­^·ú«o¿zôø˲QÑQKW,õªåuãæ«Gûùxûðx¼”Ô”µÖ²,›••œœ•yÞÂÂB»£yóçMýijTt”F£¹uçV@€°a&R“™?Î,ßï ×½kw"zôäQQmF µà×ÎNÎWyÖð”™Èˆè굫唡µ¥5%¥$•SÿT²“ðîpsuöí0–e'O\ñ{ÿn䨹¿/pr.äÍðŽ»{û6Õ®S§¨©))DdieUq9Tr(ê@äeÑßÇòc_ËO<Ì»qãö ê7HJJŠˆŒhÞ´yÁ{¬†}3,hL˲K–-©^£º‹§‹­“­¯¿oðŠàm;·q[N š8äó!Dô×Ö¿üøYÙ[yøxŒŸ4žŠŒŠÔí®_Ÿ~D4jÜ(Gw‡NŸ¸ï¸ßõŸCÓò‡}3lÖ³„Báüó=|<¬¬5otîÂ9Gǽ;÷úxcN€÷Hnn. ø†ÌvÍçóºÑÎÝ;õ—OOO" ^ë”æ$T¼‘ߋŗ¯\>vü˜±s©®_»ADm;t,´AdD„J¥"¢ž^š@e†¢¼_t»ÕÞŠ«‡a˜™Ógž91øãÁ~µý2Ò3{vï¹}óöu+×q[òùüÅ¿/Þ·sßÀþ}½}y<^ýzõ¿ûæ»°Ka]:½¸bÉŠ‘ÃF ¬1b‰ù—3­ÅŠ4–47V0 3nô¸3ÿœ4`·€/hҸɘ‘c®]¸Ö²yËr=`‰‰‰§Ïž.ÏÉÉÙ³oyyXËöÍ0†až<}RèÔÏž?3¬[í4 ×®•²*Ï“PÁlllúõîGDÚøBñ²³²¦Lœ@DÎÕ«·ëXxQïúµkDäèäT!KåøS@Y?vüø±ã‹oÓ´IÓ¦Mš¾±+†a:´ëС]‡¢›°±yçZ y⛣áþŸû4õo?ë¡f"ÿ:þkW¬-~/'BN¼1x÷¥¤¦têÖ©E³Ÿüï“ÍZ8:8¦§§‡Ý ›ýËìÛwoÑgŸ|fXÏ6úfÈ7+V¯˜òã”—/¿þòkwŒŒŒó—Î/ööò^ðë‚7÷R4mQïÆjµšÏç—¦«ò; oøwÃ7mÞtî¹Ðó¡-šµÐÅ5jÊÎPgJsõžâÊðxÚÙ ¹”yy…>ìµÐÆF÷VÙææää)óâcã.ž?·lÑâ÷ïñx¼ßƒƒ‚¯@oüû/5iÖ¼ÌÓ¨ÂPÔ(ìËôSa Ë’rîé­ ík[}%:%-0m9,ô|hèùЂk'ŸÔ¾m{ƒ;Ÿ?w~VVÖÆ¿6®X½bÅêÜUÞ^Þw«U׿®‡»Ç“§ONŸ=ݦu©ž\®'¡‚ùÕòkÙ¼åÙsgçþ:÷àžƒºøã›™K‚2‰žO¦}Üö–––^FèuräÐ!¯ê… L+´±Ñ•<[µZí”ÿy¦¦f‹W®lݦm‘>DD=úô)£dÞ (ê”-öeÆ©ñË )çÙÕ¶úêEO>#2Jf`D®.®7®ÜرkÇé³§ï?¼Ÿœœ,ìš4n2ä³!%\ >Ÿ¿2xeÿ¾ý×ý±î⥋ñ ñb‘ØËË«kç®ÚÙ?Kƒa˜Áž6cÚŽ];JYÔ+דPñF|7âì¹³ÇO¿zíjƒú ŒÎ;G$),,<½¼?lÛfð—CŠ{øðÁý{wîØV«VÔ͹P(f í’³µ×ð€ÅÆÍ œì<¿àÊ£ndR¯óR‘™±ò*Š}™qúF|pÁrž‰ šŸõW(z¡œ•QLLŒ—Ÿ—‰‰ÉóÏÅb±±ÓyG©Ô¹3wÔ×.;U«?°Ã£¦S™Ì™1ã÷ysG š2c†±sy%&&bҸϵËN5³ëvM­È½?ûƃä­Nò]Í:é‚Ñ™¥ì)dz×iºkÂÿþu1kçf ë'2ãìÔæÕMÛé‚ÏÓŽS­ËÆi™«N6`IJœ1F”§I×ä?"Rª3ùŒþ@Z½óPBšü¨Í@ïk†*d\Ya Ýi™*içzÇÈ- •EzóŠjiPïg^–ÇXhçåôÎaÞâcØ1– gFÛ®°@¾è<ªõÀpYÊä'ɧ´Ë¦"{õ  pª•í—õB/ÎgÄ»¥|ë×!†)Ï+%*Içå\G(iåÚ9Sž„ÿ]N—£Rt^¶— z‰”g!¦Ä–ÿEvù|o™’JC±doør­ô•û7çmò.ÇŸÑòýýY¢bS…+Ó:lÁÞKÖ¨rx'O>@YCQൈÛR&×"àS§ÈŒPn\ÍæîyÜÅÛb`M«Ï¸0PÂJŸJz TŠ:BI;/· ÕòTR¢ÎßflË[+‡:,CÅ~Óy ŸÇõÎò±ÞV|žX7;Û«ânÉpƒ 'šo8•ˆo&Xê$| • G/7©À†Çˆþë¥ðÎó*ÃIã5S¡³†UêÍÅîܩ߈ˆaøÜ{¹ÇÈ’:%÷‰6.äÉMÿ»RÛB™ˆˆxij–Ô’‹œò‘ÔO!®Á òy[i]]ξMÜ૆ˆ,ò÷#äÉdM-%>Ü ˜oî(oa)ñâ¥|+'y«¢;ç¸.Α•¤·¡­«Y+‰/7(:¹™u¶çÛ£™ÈÕÝ< ÀóuÎäOà¿=æëÜBìYCÑGïÀ­$5½,ú™‹Ü¹Áj&õò»ÿë”Éw°úÇN¤{pû±7iÂcDf"WnÐIþ¡‰Àš{;9¹šuøoÛ|G§T O£Q¾³Rû¥™ÜA–ÿMRÝ"ÐÒ¤ŽDhà º[õµ3kÉzˆjXš£J¤|§®D? BÎT€Däeû•RÆÏ?÷kM»‘ju–Þ›Ñßar"†òg,4}õ*˜U£ê¿pg~$">OÚØå·B¤ÐCÖÅùœ‰HÀ—5w ðäÜ D`ÝÂm…Þ©‹[º¯*ðÌ ùN•ÕU>ã#ù|©œsgtñbÓÏß[¥]þÀúGó¶%ܰxŽŽ®eÒTIÌ„¯þ{s¶ö°Ø¸Ù@å‘þïßO&k—ëUÔÐ~°qó(ÆÎó ®< áF&õ:/™ÕŒbÓöÕºÛo?hœ)·*xË[9º{Ò4/›GDæfkïˆÏ¾y#a™^iˆ<mi/.ëššUêÝ\ž~”!AuÓ6ºKšéÿQáרE_ñò±ƒ¬)·Ÿ¨Œsž´šI]PÍæÅf]òLm8s¨©49ñ¯žìQ¢ŠŒn½ˆ'·àTšœ¤Üû"ž)÷JX¥ÉJÉ},â››‰\tÁPI©Ô¹3wÔ×.;U«?°Ã£¦íEò+/¿×.û;þ 7á @™Øòidü«Zæ|õ#õ 40¬Ê‹­{®UuýI²ÊÕƒP9q¦Û²‘úµs^‘}3,a9w25•&ëvâÚûÉ[¼-Ô´ú\¯Óz†xƒ`ˆ§7Ëñ‘ƒ¬¹^PÀ“p§x7˜€'±•úšp %âÉ­$5Ëb&zCiˆHÈ“ Er½ ˆ'´G© ÿ¸â‚¤4rŸñ_°Ïc ñPµ«8ùFŸâ¼@åP¦³ÏT-ÖR¿vÎË\·8É[q/õUš¬Û‰ëv=îp5î·œWCÆ *(çÙ¾Ê Šzo`-­ÝÖyY€Û'ù‡ùK{Ùw×ïzÒñjÜ|”ö*¯r~Ú ¼‡ð[*Šz`8üOïkI­¶ÎÁ]ݶ:Ë[(ímØõ¤ÃÕØ_³U‰ÆK †Ûo òAQà-XIj¶q^ÚÕm›³ü£ü¥½œ;Iì~ÒñJì/Ùª#f¥‚šT(êAÙ`|€÷ˆ•Ä·ó’®nÛMõK{w“6î~Ò ¥=€J·@僢”>À{ÍJâÓÆiI7·íÕMÛ,íízÜñJì¼lU¼3€’àΩ‡e@e¢@©XJ|>rZÜÍmGuÓ¶ÜÒžšÍ½›´i×ãN—cçf©âŒ˜!À;åLè©BúÆW›Nmt›\û÷Ú'_|R¯I= ; 7o·ÞzïܽS£Ñèõ¯œºïr1mÏpþ“U³¹÷’þÚý¸ó¥˜Ù(íÁ{®yÓæ Q ÜWuçêD´pþBnðï½ÑÆ¿6.^LD_ùõùSçÆŸ9ñëÜ_®\½¢]¥§S‡NOî=yrïIÄ“ˆ´ø´ë—®ÿv8mݾuÁâ…6¾{çòâ“îs÷» gme+ Þ±[Ç¢†Ëé›T"=|äpjZjÁU‡ÊÈÌH$…îkæ Ÿ~ùiJjJMŸš«—¯¾sýÎã»·ý¹­oï¾™ÓgNÏÍÍ->[¨P¸P€ !0vU…سµÓ‚äÜG7â—¿Hÿ‡¥W7â©ÙÜûÉ›¥ì¬¡è]Çú[‰ÀÒ¸y¼ûÖo\ODC>²è·EÚˆ­­mÓ&MJ$•°«^Ý{QdTdbbb¡;Ò-›[Hÿ\ÿ§D"‰Ž‰þcÓe›[‡vˆhëö­zñäää#ÿiݪu¡#õfÿ2;77×ÞÎ~ù’床žNÿ¾ý½½¼‹Êª0õÀpSðF ñ:jK{u¥=ó@¹ÐѸ‰¼û†qqq!¢Ãþ-eWvvvÚ…ŒÌŒ7îÖÝͽwÞD´yÛæ²ÍÍÌÔ¬Y“f§ÏžÖ›qo÷¾ÝJ¥²oï¾iiiz›$''ïÞ»›ˆ¾Ÿø½nžABQ (Ä|èø[ ûnW³N|FTÛúkcgP9ôéÙ‡ˆ~_ôûÒåKK3mÜÃG‰ˆa›ÂÖëÿ¥²e‹–Dtëö­bЀ䖑™Ñ§W–eõm±uûV¡Pؽk÷´tý¢^èùPí³tôP’]€Ñqk?@ùAQÊ þx…øƒç÷þà˜©ÐÉØ¹TãÇŽoצZ­?y|­zµ–­\VèS&ЧR©æ/˜ODÍš4Ó=l—‹åõ´Wå®.®D¤V«_¾|Y†¹¥§§÷éÙ‡ÏçoÝñú܈ȈÐó¡Úw²°°HOO×Ûäî½»DT­Z5¹Lþ†ã£2{xÙѾ,Lj;x/ ¨†³5ñìâñ³öUÃâ#c§P9HVÆN Ò‰D{¶ïùù§Ÿ-,,""#ÆMçáí1b̈gÏŸ½qÛÜÜÜðáèеCèùP†a¦O™^hK©Àª}õ•íœW´s^QÛê+ú¯¨GDÉ)Ée˜[^^žMû¶íÃn„=xø@ܾs; ì?P›³Þ& ‰ DäîæþÆããRH½kÙÒ¾,Mê;x/ ¨†“ÌMh_fbc§U@ ;jì£;–.\Z»fí̬Ì5ë×ø5ð›9g¦ö¾T={÷ï•*¤R…TQMáíçÝoP¿ /ØÚÚn\»±eó–…î‚ψdÍå-å-,%>D¤R©´«xLqŸ–ß67­ý‘n°Þ¶ÛÌLÍ:wì\xk–ˆ¨˜Þཅ¢¼ëd&²/?ûòRè¥ý»öûÕöS©T³çÍžò㔂-%‰ƒ½ƒƒ½ƒ“£Sà ûöîûÛ¼ßî߼ߧWŸ’ïîyøsí‚B¡(ÃÜ´ºÈeò]{v±,ûäé“›·oöêÑ«ÐçÞ‘¥¥%•dd"¼oPÔ€Êa˜ömÛ_8}aôˆÑD´8xqdT¤^›N:=¹÷äɽ'î<:óÏ™k7~÷ÍwoûÜXmQO(êîÃ-“Ü´d&²îݺ?züèÖ[ûî§ÿî½-”—§ÅÅÅefe¾Õ!@•‡¢T&<oÚÓZ­»V»8~ò8Õõ¯[ÔºRæ6hÀ "Ú½w÷Þ{Z4kQTKݪ-Û¶¼U&P塨靖œœBã"¡H"–‘J©*óÞ¾{ûÀ߈è“AŸ”Sn¶üÐÎÎnÝë._¹< ß¯ÈÏä¶¶¶]:u!¢yóçååå•ðà}€¢¼‹nÞºéYÛsqð₉ØpFf5nظlwõñg«T*W×bîŠ-en|>¿ŸþñññD4 ß€âSš<~2ŸÏˆŒ4Z­Vë­ý;äïAƒ|l.Ty(êÀ»hó¶Íñññ˜Ø¶sÛm;¶=ž’’rûîíYsg :„ˆ>ýß§vvve²/–eÃ_„/Zº¨Q‹F>0‘šü±æ™‰¬ürÔùÕö«éS³øÜÔo0ëÇYD´~ãúÖZïÙ·'*:*%%å굫#ÇŽì3 Ïž}{´C à½"0v…˜3sN5Ûj³æÌºxéâÅKõÖ¶oÛ~áo K¹‹C!‡\<]X–MMMÕÝÜêîæ¾iݦzuë•knµkÕ¾zÉÒ²$yŽ1Z"‘Lž:ù굫ƒâ®‰D3§Ï|«gû@Õ€¢¼‹†3rÌ€~6ýµéàáƒÏž?KOOwsuó¬áùÅà/:´ëÀ0L)w‘——GDR‰ÔÙɹ^Ýzô  Ë;7†aüjù•<Õ¡_ è°jíª#G„¿W*•ŽŽŽÚuøú˯µOÈ€÷ 3a…‡vÉÙÚkxÀbãfPNvž_påQ72©×y©ÈÌXù@¡6m_½ïÐ6ír³IVÕ+tJø–Ûd§ñ‰ÈÜÌbíâ¹k¨TêÜ™;êk—ªÕØaƒQÓ€*hsȧ‘ñ×µËs¾z€9õ*õ*õ*õ*õ*õ*õ*±¨ÜRs¼Hþ[»loÖÚZVϸùÀûE=0\tÆÍ‹Qk†ˆÈת›§e;cgðÖÒ•g"'Cä,ÿ¨¶õWÆÎ*Ÿ´œ§ã×k—%Bõ àö[0\Ž:=.ë~læýØÌûYªDc§`µ&'!ûfBöÍøì›iʆu²tùR©BÚ¦Sn°M§6R…téò¥e‘&@>(êAYaŒ€!XbuË >Ò@%¢¼ëÆŒ#UH~:°Ðµ999R…TªÞ¼u³Ô»BQ*õà=Ǿ¹ À;E=x¿±Ü¢Fê€!pó>T<õ XL@UŠÁhx<|®Œÿ€Š€Pe%$$Ìýun«v­Üì]í»tï²}çv½6Ý?ÚôIz²šeéð®›Í?jneoå×ÀotÐè̬ÌB»=qêÄÇŸìáãááã1à“/]455}«Ä®‡]2tHíúµÜºöìº|ÕrF£×FûðÜÄÄÄìœì)?Nq÷v—*¤oµ¨ÂÆN ì±,;ç—9 /ÈÈÌ "‰D’““sòôÉ“§O>~òøû‰ßëµOŒQmû=áê?O´_>züèÑãGa7ÃN9É0 ·ÛÙófÿ<ïg–e‰ˆÏçï;°ïÀßš6nZòÄ‚W?õ{¥R)‰ÌÌÌŽŸ<~üäñ'OlZ¿I"‘èµOˆtüäqÃÎTU©UÃ0OŸ=•šH™ýËÕ W"¢ŸG9†ˆæý6/&&F¯}ðØèg3‡Mn÷ìþ³§÷ŸN?‰ˆ.]¾têÌ)n³»vÌš;‹eÙA…]K‰M¹vñÚÿüïÜ…s%Lìàáƒã' E+–®ˆˆñèÅ+7üëø<|p͆5ÛO›1íÔ™S?Lú!ìrØ©£§ 6€÷Šz`8SE@Ú»¯T!-ø²°³(´ý/³¹vwÄw#júÔäóù …âçŸ~öõöÍËËÛ¾Kÿ&\bhÜ2Ç>ƒÚÙÙÙÛÙOÿaº" 9¢k’“ýÃôˆè“AŸ¬Y¾ÆËÓK øzû®Z¶j¸ %9„¬ì¬ ‰AD´2xåà‹D"†aý 6@Qª¬;÷î¬]¿vóÖÍ©i©Dä`ï ˆH¥R±Åëò™P($"í1´î?¼ODîç£÷·hé¢EKÚ .>N/¢M*ó@EÀG¨š–¯Z4)ˆˆ:wè<øÓÁÍ›4·´´œ5wÖÏs.j¦Ø›”J% ø†„Ö–ýjùùúúÚÀ×»ð8€õ lÿ  ‚ݼusÜÄqà¯?þêÖ¥[™ôéêâJD‘Q‘÷`ggGDþuüW¯,“”ཅe€áðô[xgí=°—eÙvmÚ½¹¢WâO4Ú¢Þ¿aÿfçd–U³&͈èLèí ?ƒ¡¨UPNN™ššrƒYÙY×þ½VìvÅÝ|ЩC'‘H”œœ¼aãn<3+Sûü7êØS.“?^Ôœz%„¢”<” Þ%µkÖ&¢¿ý}ñÒE"ÊÉÉ9qêDóÖÍCކܧ“£ÓçŸ~NDã'_¾jyrrrnnî©3§Útlsìø±‚íå29½Œx©‹XZZNŸ:ˆ¦Í˜6áû ñññDIJì³çÏ‚&•&70. iÍzNÓë9ýXÏéG[Ó¦ÆNÞ (ê᪛5ìï³¶¿Ïšþ>k¼,Û;€×zõèUÓ§ffVæG?r÷v·s± è —Ëÿåw½–|ž”ˆü¬¾êáqÀÏú›â»2iŠ·—·Z­;a¬ƒ›ƒ­³mçÀÎqñqóçÎ/ظŽ_"Z¼x성ºà°o† bYvɲ%ÕkTwñt±u²õõ÷ ^¼mç¶Ò6‰LääfÙÇͲ·›eos‰§±Ó€÷Šz`8!Oª;)ÄÎ ±³˜oúæ à}Å’¦‚÷(‹C„|1ø g'ç””o/ïùsçŸréÌ¥ýlp6s»} ph„z¨vjq¨g’”³wóé'ן—µÓ^%84B=ØGbΞM±#~8ùй¬]ö®ÀÁêÀžrvÿûø†SÃÎgýnïZ¡j€Zþêøì¿7Æ>¶áÔÃç³ÿ¬™‚¡ªª^&Ô3‰Ïþkã©G6žz4>ûïê. À¡ê ØꙜÏþcéa?Æ>–³»ú ph:{ç§V$Ô39—õû¹¬ßÃ=»FÒw¨Žª¡j¯¸¬ßâ²~‹ðº.:ð©@}{{—P[ê Tx¦ž¥³™ÛÏfnðº>:hT {Ûªª ÀqêÀ1œÍüõlæöú^=¢ƒF¸GÙ»{"Ô@µ«Ä=õ.5ҙ̟ÏdþÒÀ«gtÐSþî­«hXC¨€ê§VU¨W4ÜéÌm§3jXïÆèÀQ~î‘U:8€ ÔÔF{6zë\«6¸Œ¼,i!ߘ¶áÔ0EEDDQE¤¸¥¨±¨­¸Ñ¢³w»Ø_Q¤dKñÖ–-¦íŠþcn,±/Ë)ŠR²³iÏ%û\¬¿hÀ¢ˆ¢(š‹¬7±>|¥dµRjï–'¤äÁ*wzñt™Û¬Ï‰Õá+ÅçïR\ì_|¢-¿MVç¤ø¬—<'æÆÒ'Ð<‚Rr_E§Ðª¥äV¡Œ3`ÙXê–ü¹RÌšOšƒªŽÿG«±[c3¶5¬wStÐS~n-«aµ¡ 6ʺ`·¡Œª!>ûo{í¸œâ̱¬¨Ñœu–v­³NE)±¹¹³˜ÃâK£åp1´ÊvE¥Pͯ¶s¢Æfl>±õðÆÈzÚ&.¯jÛ‘Mº_{c—«®·o jÞ…ì}G?5-7ðëî}£]ËP'ê¡òN¤þºýÌ{"¢(rMØ#‘þ·Ø»"œžZtsº2ïQW£Ó[kUŒÇö_(,H±w!Ò¨ASB= ÎÉ)ˆ?“ö£iÙ×£¡€jG¨‡Ê+Tós Eo Æ<ûÀ hE«ÕVë.TUUÅX~Ÿ‹W@@mE¨‡ªÂ‡`WjȠLJ z¼f÷©Šy“jšUôßE«UÓ²yUQ«E7Õ¢«eçâÁÕ-ª¨Å[X7–ØÊ4ÔÅ1‹§f]ábcÉÎ"ÖR²$U-Q€åî¤ô!¨ªÅ~K6–>¥/ž’c–U€Z¢˜â©h%+/ÚÜhñÌ…çäâN­Ï‰ÕÞ-ú”ø6‰U©¥ÎIÑ‘—lQ-NEgµD1jÉ}Yö/Ô²*±8(sgËsRêg Dg«Ÿ+‹Ÿó ‹¡?%~®,¨,Êü£~ñ ØÐ×k IDATP…õPyïà 9–úíîÄùŠ¢QD¹&ä¹õʹþÅâJYà@IË?ñÝñ;«ipâÒÌç.æÏBÉOC×ûjô:ܤ“®ÿþàS“{ Ô8›cV¶!Þ´lPsì[ €"Õó§@âÒܧ»Àá^.áïI¿¢Fè½ «e—àêy™ëúª¡ÀÙ”¼ksí€Z¡Ì{\ ­âÚÜ÷îvÃ=]B«vd¨„2gü@µ"ÔÕàò[µï°Z£ÊÞ6h·¾Ú>î¡ ©ª1 *qŸ"5‚PàlJN"Ôœ‡VqkéwOۀǖï¤Iõ€Z¡œ¸®¯VþFù?ä¦õ©¹‚¡ª·¢P›ð   *#ÖsÕÖkí÷`”ÿPWm½š/À¡êáJ0«@mTrž÷Ôj‰o\µÞQþC[û?èªñ²WAPàlTµÐâ+f굂ùAnZŸ(ÿa­ýp!θ„zçà&ðQUƒÙæjUŒö.ª¡®€PYþuœ{êpJ„zçÃÓo89B=T>6¨=,î©§ð/¨| PÓø¨ƒÊS¹ü@­Tòžz¼Ãà„õ·?9;â­€š@¨p6<(€Ó#ÔÃàïOj)î©ÀÉñQàl¸§§G¨p>L$àätö.L§qóp 0}xÖiÜì]±|67÷Ô5 Ðóª["׉ˆ(âªõ±w9êB=T^«€¾­úÚ» (¥ÄD=B=Pít½—[C{W náò[€ó±œ©Ç¿tœ3õÎÆEëé¦õQETEa¦'D¨p6ׇ¿aï zqQà`õC¨8B=ÀÁê†Pp0„z€ƒ!Ô ¡à`õC¨8B=ÀÁê†Pp0:{–kHÏ1¤Šˆ"âáèªõ°wE`‰™ü;AUDZ>ü˜½+àüõPy‡/lÜ÷±i¹wãç›ú^oßzÀ.Œª!ÏbZ6³í[ €:‚ËoÃL=T E{—E² ÎÕEQ4^.ö.ª¡ÀÙl;3&9÷ ˆ(Švh«=ö.ª—ßœZ¼À$bΊPUDá“3€ÚÃ"Ö¨~ ˆÔ8B=Tžzñc3Ô"æßN ÿÌpR|Ú8Õhï @]Æì5Pàl.ÎÔãBNŠPW‚?@¨åõ8'B=€óážzœŸvP5¦Ã¨5Ô‹÷ÔãWçD¨‡ÊS¹ú@­dñô[€šÁû5Pà|ŠÿæÀƒ28)B=T>9¨…øÕÀ9êáJpý-€ÚH•¢{êñ  ΊO;§sñ–ŸÌÔàœõP5xú-€Úƒepz:{æéâ%""ª«ÎËÎÕ@i<(Ôˆ`¯k´û·è Þ¨„z¨¼–þ½[ú÷¶wPšy¦^MLHìÉǶlÛ2}Úô‡x¨vj%EQ´ö®@ÝÂå·gc~PF \€›°tùÒøøøEŸ.ªî}€¡ †Œ›8Nï«¿ÔkðÐÁV=-[.eíkï¾÷îF-ù…úu¸ºÃ°Ç‡íÙ»ÇÏ-2À½M€{”Ÿ[‹ê< ‘ààà‘#F6oÖ|ÌScÌ™z_}ç.«{ïê,.¿Ô(F£w×—nwww¯Ð8iéiã'_º|©iLŸ#G9zd媕ïÏ}ÿ‘¡TM¹6xûÍ·­ZRSSklïê&fêjÔýîLŠK*ýZüáâ ³}çöå+—_×íºk7ÆŸŽ‹‰;vàØýî‘1ãÇœ>sºzÊ·IJjŠ÷ . Ô8¤ÛûÞþûöß7®ÝØãº^ž^"ñéÇŸúxû †¿í´cmÌÔPÝõŽªmT[¦Ä?dzw}xx¸ˆ¤¥§]vóÝÿî~üÉÇÛunÞ$¼ßÝý>øð£Ñü„ ¹páBx“p½¯Þt…¯Ù?»ÿÑûêýCýÏœ=cjéÕ·—ÞW?ÿƒù"òÕ×_é}õ·ô»ED:`¾càâÏ+6ÊG¨pÇO?|ä°ˆtíÒµœnªªÎ_0ÿ†Þ7|¹üËØÓ±Z­v˶-ã'¿oÈ}¹¹¹¦>þþþ/¿ð²ˆ¼ðò YÙYæm§MŸ&"Ï>ólýˆú¥GöôôlÚ¤i`` ˆ¸¸¸4mÒÔôò®ç]uG „z§PPPðÍwßô»»ŸÑhõä¨vmÚ•Óyík'N™èêâº`þ‚Ä3‰±Gc÷ü¹'ºCôÚÖ~üéÇæn{4ºCtܹ¸wç¾kjùuǯ›·nŽ7v\™#ßÖ÷¶ý»÷¿öÊk"Ò¢Y‹ý»÷›^ïXuÇ „z€šõÝšï¼¼¬^ >ZPé§¾85*:*¸Að‡‡äççÏ™=ç­™o•Ó?;'{Âä "²ð½…Ãæêêª(JË-—}¾L«ÕÎzgV~~¾©§V«3kŽˆÌ~wöÙ¸³ªªš¦é½öÊkzJ WŽPPÓ KQUµÒ£;v,ædŒé²Y///ƒÁPXXXNÿU߬Š=Û¡}‡ýX¶7nÔø†ëoˆ9cn¼æêk†=8,'7çÅW^Ü´eÓo»~ërm—AUºZ¨„z€ÕÿÎþ9©9V¯‘#FVzÀ%‹—Ú{h놭ãÇŽOHHxvò³î`¾5^iÛwl‘ž=z*ŠbµªIã&"r"æ„eãôiÓ}¼}–._:fü™5sVé  †ê›››[£†ºvé:ãåïú;$$dÓ–MóÞŸw©þqçâDdÎü9æGÓš_‹>]$" ‰ –ýƒ‚‚ž}æY9{jÈýC:wê\Í—§³wT™ð°ðž{aô3£?^üñÄñËìcºÔ·}ÛöQQQevˆjU¢Ýh4®ß¸Þ´œ˜ ª*3õØ¡À©´oÛ^DbOÇfegyzx–î*"Ñ¢¾·Ð–—®Xºë÷]ýní·÷¿½›¶lúvõ·V7〚Çå·‡t©gkœ?/">Þ>zw}™ºué&"¿lÿ¥  à²{IKO›úâTN÷úŒ×_}éU™0eBFfFù[i5Z)4–÷¼¸„z‡4é¹I³ßmí©ªºøóÅ"Ò1º£FSö¿qwßy·—§×ÉS'çÌŸsÙ½¼:óÕÄÄÄáoÖ´Ù=î¹æêkÎ?÷ÊŒWÊß*$$DDâããË/T¡ÀñÄ‹ûð“Ÿéùû†Ü÷×ߪªs2æÑ'ýa㊢Lž0ùRÛúûûO{ašˆ¼øÊ‹“¦NJLLÓæ¦LØðãsÏý÷ðá^ž^ÏM|NDEyû·Eyáû{÷í-§¼Ö­Zk4šÔ´ÔEŸ.RU5;';%%¥ÊÔ>ªj4³M/£šoïrÔ „z¨¼´¼³±éš^¹†4{—À1|·æ;¯¯Ò¯ð&á6öœ¿`~xXø·+¿ ý~ý÷×ßt½O°O`x`TtÔò•˵ZíÌé3{öèYN £ž5aÜUUç½?¯a‹†Z6 ®õÞ‚÷V¬Zaê£ªê¸ ã ÇdjìÜ©ó°‡ƧÇ?m4/5~xXø½÷Ü+"cŸÞ$<´aè›o¿y%' ÔrIÙ¯þïZÓëÀù÷ì]€:e òަlùûü—¦åÛšÍhPï*ûÖÀQ”yQª±°ŒŒ¬ìËWU‘^={ýûÇ¿K¾\òÍêoŽŸ8žžžÞ¦u›:L?)²edù(Š2}ÚôÛn¹í³/>Û½g÷±cÇ4hÕ:jð}ƒûÝÚÏÔgÕ7«~ÝñkPPИÑc,·}åÅW¾[óÝþ±øóÅ=üØ¥v±`Þ‚à à ?nˆ‹‹ëÜ©sDD„EùF…?ªà¼T)ûοPµõPU{ ¶{ç­wÞyë*ìéãí3zäèÑ#GW®ž®]ºvíÒõRk 4hà ÒíAAAçN³lÙºakénnnnoÌxãoX6æ3]ø"&}C¿&+´Š[åÊ!ÔÕ¸Ô£'À¾â²~E4.ZÏ@÷¶ö.GD¤À˜uð—.|–W˜&"GR¾jíÿ ½‹àÀõÎfsìªE$À=ª_“•ö-¦À˜u(eÙþäOó SÍû’µôÄd=•F¨‡ªÁÅ·j%{þr2³¥,û/ùÓ¼BëGßú¸5Í+LóÐÛ¥0N€PàlÌw§Vû<Â`Ì9œ²ü¿äOrKÅy¡WG ñàÉB8…yj¡Àɨrñ‘s5ýöÚ`Ì=’ºò¿äE9†d«U!£ƒF…z\SÃ%pJ„z§¢^Lôj4Ò+Tó§˜â¼$«UÁ¢G…y^[ƒå;≂j¡*O-ño³ÍÔB5ñ«©PÍ;’²j_òÇ9†D«UAúÑA£Ã=»Ö@êB=€sQ-gêUï=õ Õü£©_ïKú(Û`µ*Pß¾cШpÏîÕZ€:‹PàTT1^üB©®™z…jþ±Ôoö&}”mˆ·ZèÞ6:hT„×õÕ´kB=Tö –(yO½ªÿÕdT ަ~»/ù£¬‚sV«Ü£¢ƒFÕ÷êÁ T7B=\ îÿ  ª®_MFÕp<í»½IfÄY­òwoôT¯žÄyÔU¼PÓõN¬jÞ^UÃñ´5{“fœµZåïÞªCàS ëÝÈ[y5‰PU…O³jµJ”¡ª…ÇӾߛ´ £àŒÕ*?·–ÑAO5¬w¿JQ‹.–WM ª]>¯ŠˆVq³} ¼Â4£Z ÅÛŠˆÑ(Y)Úª/¹œ2«÷±<¥êáJpù-€ªd™Ç]Á …_)•SQU-<‘¾vOÒÂŒüX«µ¾nÍ£ƒž ÷쮊š_˜Y´Û¢@AUÅRHq‹êªñÖiÜmÜ{^aj®á‚j‘P-gŇ¤Š¨®ïz® l¹À˜•”óŸeµrñ´›/úRM}¯lYDNel2sÌg dF£‡7Eí êÝè¡ ¶q丬ɹ‡,Ï@ñà¦1æñEÔ`}GÛŸR’šwìpÊJëR/ž‘‹çDu×tgëéùéÌxUŒG(:/%ζµ{øt]ˆ#ÿ•0+>ûÓ8–礸`QE5} TQÛ<ÒÌç.GŽI_÷wÂ;æ3 %¾ƒjÑ÷¶h•¬ïØ«Á|GÎ6$¬:zsñ€ÅÃ\ÚÈ?tßûxrîA1CL!{ÖÝÖƒlÜÀAêj‹/¾úxõúU1Rhñ©¤wE7öñö›:}èÞ¤éù§¬Vùº5ë8²‘wE4ëN>”³×Æ1¯ ŸÙÌç;NY±;qž{ßrCÄl;gäŸþ1ö1;ë4îC"ÿ²±³ˆüqþõÒϾׯ¶‡z±[§¬´±s”ÿC¶‡zYç¥,µ±s=׆ õb36—xs¹ ŒÙ¶œžwÊöŸ½\CŠí#Œ9YçmìœoÌ´}dEÛφ”|âMÃÔ=„z¨"¼à,ò S¶Ç=gÕè¡ ¹*äÙÆÞ}Í—ôVð×^õ%¹B®è$GE©Èàº.üS¡³]±óQ+~ö*þM$Ôà`4Š«Þ¥hε‹¶ž}‹PGê¡òôÍZøõ2ý-ÝCçgïr jhEÑ–¼ŒWr ‰g3 pòvm\ÜVK¢·ŠTQ‘Ü­âjET3¼jáM'1ÿÀ(Š"ŠˆRüó£˜Ú¥oötw½.Èj„â1‹÷UôS¤xèB/=’5¢ p*J1&W‹Ÿ|E‘ Ü/Ä£³‡.XiÙî\¡ÁümRÌaù…·k#7­õ›–Ì‚39†$Ó²Ÿ[¤N£·}ï¥5Œhr%›pPþínk½ÙÞU¨[õPyÍ|ohæ[Û-€íêt®5š¡¤ÅëŒ…Šˆ¸h¼înºvoò‡'Ò¾7ªÓZUŒÇÓ¾?‘¶®±÷­Ÿðqk¨oë¢ñSŒ¢X†!HQ xº„Ù^‰Ÿ{Ëf>w)E›[f4JqxcÊD p²}dw­»€ÇÍéEȧ(ŠÆ<¾i§ŠR±ç t ]`̾8²Rbü’Ùø¸5µ}äHßAáž]‹ó )y’Å2{Q¼*rªƒôno¼LDJÅœ”™—µŠ«í#‹È=-6™CC‹Á‹9O‹‹ÖÓö‘o¬?Çœ²U­&Þ·7ñ¾½Ê‡7­o¿&¶^C]QW‡L2-ôSM{¨õµQ»Þé ókr›?ÊI/бê¹6è6½Cà“{“><ž¶Ú2Ú‹I_w2ý‡ÆÞ·´|Ò×­YuTRßë† =¡Âvz]`§àgªcd±ýi åçéçY#»jëêÛUÇÈ"bûƒ/*êÊë 'À›BÊæåÑ-ìå»›­oé{Fq1·«bŒIÿa͉»>ûljÞ1;V Î"Ô <^.á]Ã^Ðl}¤ß}–`ªb<™¾q͉?Ÿ’wÄŽ¨ƒõ¸fÐÖ3O'ç´[}ê B=*ÆC|mèÔÍhíÿ U´w:cÛÚ˜{·žœ»ßnõ¨õ¨ ]ð5!S6ßå?T§q·X£žÎüimÌý[N?•”³Ïnõpj„zTž^xuȤÍ6¶ñ¦Óè-Ö¨g2YwrðæÓO&æìµ[}œ¡WJ¯ ¸*dâÀfÛ<ªÓxX®:›¹}ýÉ6Å>‘ó¯½Êà|õ¨î:ÿÎÁã6ߨ.à1§åª¸¬?œ|pSìð„ììUgB¨@Ur×úu 7°ùÆvÃ]4^–«â²~ûáÔбÅgÿm¯ò8B=ªž›Ö·SÐØÍ7¶|µd´w>ë÷ §†ñx\W‚P€êâ¦õéôôÀæ?v|ÒU[ÏÜàÞ:À=ÊŽ…pt„zT/W­wtÐèÍ~Œåªõ‘ö#E{×Àéì]u‚«¶^‡À‘mý/yqÃz7Ú»ŽP€š£UÜ:>iï*8ÜÝÝ"ÂC"ÂCÂBƒ †ÂÃGN¬ûaÛÀûGuîvWBb²½«« ¥Jÿ¬‘‘õÂËïTá€Î„PÏ>nï{ã™ã;Îß³3ûÂñ±¿Ï™õ‚»»ÛÞ}‡ÆŒÅÞÕÙ®º.ÀUåãÅ+÷ì=XMã˜YÞýªjÿN  îà·€šG¨gŠ¢Œ5lîìEä›Õ32²ì]” ¹ÿNUUÇMš¡ªÜ¸Ô$>–Ç@¨W‹ôíÓCD §Ïœ³lÿ{÷ßزÝÍáWõé÷ðü–F«m ï/ü²K~a4¿îî{G~±lµe7ßÐŽŠ¾ùæ­;¬6ì7`¸¢oþÒ«s-¯ëuŸ¢ož˜l0¾õÎG‘í{ëýÚ´Ž¾eÞûŸ›R6ƒ¡pöœEƒû|2¶WÌÃÏþ¾!£ÌwÀ¶T^¦›nìÖ¹cÛm?ïZ½v³-ýEdÏÞƒŒ˜ÜîªÛ¼ƒ;\ÓýϽ0+--£t7󡩪úÉg_]ÝýnÏ€v‘í{zfZVVŽûÎ…?"¨ZüVPtö.eff›|}½M ªªÎ}ﳉS_/(0¸ººøx×Û´eû¦-Û7mݾbÉ\ww7s·ƒŸú~ÝViØ <##ë»ï7}÷ý¦¥+Ö¬ûöc¥²÷{>{öñ‘Ï™†‘C‡yö•œÜܧG<ì™ÕßÅm1ÿåÆü—ÛÚ{ÃħZ›·µ±òKÉÊÊ™>mÜmý›0eæ­}npss-§³ªªoÏýdꋳòó DÄÝÝmûο¶ïükÙÊï¿X<ûºnW•yhcÆ¿²bÕ:Ó—GŽÆ9³ûß;¶­¬ôé‹ßÀñ0S¯Y¶ò{ñ÷ó 2µ¬Y»å™‰¯ººº,Z03#qo|ìï‡öüØ)ºÍšµ[~¼Ì¼áêµ›¿_·ÕßÏw÷ïߟ:òKrÜ_ûþZ[ßžt%ÕŸøé—ßß}ëùSG~Ù÷×ún]:‰Èko~ЧßÃ?ýòû¼·§}û눖4hå&"sßýÊòѽ6V~)™YY}ûôèÞµóñ±ó>ø¼üÎï/ür”™ùùžy<ö诙I{ÿÙµ¦[—N§bÏÞz×£‡œ(½Éíý_³nË»o=³óì‰ÏO%"¿ý¾{ëO¿Uè'Ã]±€£ Ô³?£Ñsò̤©oLŸ9_Dž›ô¤)‰ËÎÎ;aºˆ|²ðG‡ ruuQ%²eÓUËÞÓjµ¯ÏZhš˜&"¿ÿ±GD ¼5º}kQ¥m›–ë¾ýøž»û^Iaªªþ¼iÙØÑ7lÞ¶MËE fŠHZZƉ˜Ø_7/=ò¡à°zÍ]z.XDΜN8xè˜iCÛ+¿”ÌÌlEQf¿1UD¦Ïœ_ÎSÓÒ§N›%"“Æxkæ”õôZmÇQ[~Xݾuffös/Ì*½•¢(?ýøåØÑ‡…‡‡OŸ6®StY¿á§J*àÀ¸…/pD„zö±nöúͺ×oÖ=¼I7wߨ¦­{¾õÎG"òÑ”š IDATÄãƒÇŽzØÔgŪu§bÏvì5hÀ­–Û6i\ÿƺœO<kj‰‘]ü›““[…ENzvDÇQæ/[E6 ‘ÿMÕ®m¤?*.¢¹«ÞK#"gãâ+Zù¥˜®D¾öêCî¿+==óÅWÞ½Tϯ¿Ý˜žžéåå1yÂËvww·çŸ%"ß}¿))9Åj«Éž¸æª–-=®»Æò@]b™ê1S8B=ûÈÍÍ;6.þÜù„‚ƒˆô¿£÷¶_.˜7ÝÅ¥èF‡¿lÿSDzõìZúÚ¦MˆÈñEÑØ€þ·„…ïÙ{°s·»}úUnn^•©ÑXï788 Ìöz~Z‰OHªhå—¢¿·ž9}‚^ïþÑ'+öî;$"Åú'ö׊H—k:úûùZ­ºµÏ "¢ªêŽÛxhæCuw×PYüöPÓõìc`ÿ¾jÎ15çXAÆáÈ–ME$,,¸gk-û˜fÍž³HÑ7·z}¸h¹X$PáaÁ[~XÒåšèƒ‡Ž?>ò¹úͺO˜2³:ò)W—2Ûu.Šˆ¨Å×®Ø^ùe5¨6qÜp£Ñ8~òkªªzzê­:ÄKâ¬ÐЇ‡>4$HDâÎ]~þ)KU¹ü€ºGåAÀñô[;Óé´3§OpßS.Z>æ©¡­"›™W™¦í[·jYæ¶m,Ú[·j¶cÛÊÍ[wÎ_ðù÷ë¶Îž³è£Å+–}öîm}{Vcõ—x\¡Ê/kÒø/^±eÛÎu?lëw[/OO}VVŽÕ¾.ÅôÇv’:P..¿އPÏþúßÑ»Ë5Ñ»þøwòóo®þj¡¹Ýô ÜNÑm>Yøº-ãh4š>7_×çæëöýwxÂs3ܼý¾‡ÆÙ·9,4XŠã-Ó¥¾Õ­¢•—ÏÓSÿú«“†>6áÅWÞ½ýÖëyyY†z¦}ÅœÑ>pD»Àá:‡½Ëà¼Ý›ÝÐì3Ó«yà{— NàžzµE»¶‘Ãðé’¯§¾8{À]·¸»»‰È˜QÃÎÇ'½>kÁ;ó¿3oqHp`Vv¶)¹KNN5=#//¿ctÔ®?þôÀhEQZ¶h’™™ezþìë¯NlÞ¬‘iüÝÿî¼Å‰Iîh¬©E«Õ~²ðõÔ´Œñ“fT®æFÞ×6ò¾VDô.+D-WÙRyE½1cÒêµ›óòò­ÚÇŒ–›—÷ÂËï¼>kÁ본»»åææ‰HýˆÐ/¿ÕºyåŽÔM¼o·w ÆL½Zäåƺ¹¹žŠ=;ïƒÏM-Š¢Ìœ>aûÖݾuFfVýˆ°{îîûÝÊK>™eêãåå1ÿ—þþmõà lØ <æäi­V{ë-7lÝðÅägŸ0à÷çŽoûßÑ;<,ØÛÛ«WÏ®›Ö}öÈÐ{|}êUDZØRyE5nTÿÙ±•¹¯ÉÏ>±ë—¯z Tëæ:¶[—NÇ ß÷÷ú®¿æÊŽ 6R&-hfZj9úö¹ö­ªÉªïüytƒeË”;õ®ÞöªeZ²ò£ÕëW˜–» ¾ÐÐzfnµÚüAPNºVD|¼ýÍýª&w p†Â¼é_u6-×é<¸Ï§v-à„–nz6q·iyæðÃÌÔ ¡à`õC¨8B=ÀÁê†Pp0:{e=î¥÷|q©µû÷]µlþ¥zzyyD„‡6oÖèÑa÷ÜyûÍ:ÖríæåIÿü”&"o>Rzäþwö_öù²_¶ÿrK¿[.[d×.]·nØjËáPµõÔ^F¯w+ÝîînÝèîîàï+"F£š’švøÈ‰ÃGN¬ûa[ûv­6­û,8(Àª¿¢ˆ^RjwÑjµžž–íYÙY"âêêê¢s17êÝõ•<0® ¡€Úëî;û˜gä•ïö¾7š{ªªš˜taùʵ“Ÿsï¾CcÆ¿²|É«þ-¢=wm<¡wõ.s´î]»'Å%Y¶D¶‹Œ=ûî¬wúHÅ€*Æ=õ8EQ‚ƒÆŒ6wö‹"òÍêYö. €ªD¨ÀiõíÓCD §Ïœ³w-T%B=ûøóï½÷?4¶M§¾z¿6áMºÝ1pÄŠUëŒF£½ëªv¶xFF–¢oÞ¶ó­•Þ˕癙mZðõ-û2[¡ž<;ùµk®°bÕºåææ;Ÿ°výÖûÛ­ç ³qñö®®Ùxà)©iW¸£+ÎaÙÊïEÄßÏ7,4ÈÞµP•õjÚâÏW½=÷9bÈ_;¿;j×ö­+Þ}ëùõÃ~ÿsÏ;s?±wÕÅöOI¹âPïŠG@-ñõwt^‘V¯÷|QþVF£1æä™ISߘ>s¾ˆ<7éIE±~Êí‘ÝYAaá^^–¯-¨®#€S+(Ì8—þ³é•–{ÔÞå¨xúmMûxñJyâñÁïÏyÙÔؽkçG‡ úð“åOj×ê*æDê¯ Ù‡LËíƒx¸”ÓÙöOIM¿Â®|Ô………V-ªª–î¶nöúͺ‹ˆÑ¨&%_((0˜ÚŸx|ðØQ_Éȧw8eeFþ)Qé4F«¸Ú»"Ž'3?vçÉѦåf÷GGüϾõ¨ ˜©W£TUݽ瀈ô¾©»Õªzõ<Ÿû˜««‹Uûß»ÿöøÄ–ín¿ªO¿‡ç°äR·Þ;yêÌSc§]{ý@Ï€vM»=öäs–×´ú†vTôÍ7oÝaµU¿Ã}ó—^kÙx]¯û}ó¤ä”œœÜ)ϿѴ›¢oþù—ßZUuC×q7w|ëÑÁs缿(+?åÊ|ùWk}óo""ûUôÍM/S ("‰I^}ý½.=„_åÖùæÛ†š®¯4»ì:¥°»ýûª9Ǭ^£G>TºgnnÞÙ¸ø³qñçÎ'˜½þwôÞ¶ñË󦻸”ñ׋–=/$Äç¤æX¾FŽY퇨}NflÜá³ýÉŸîOþTU ö.À&ÌÔ«QŠ¢4nqðÐñ¿ÿùo`ÿ¾åwVUuî{ŸMœúzAÁÕÕÅǻަ-Û7mÙ¾iëöK溻»Yvþè“ã'Ï0=ÀÝÝ-î\Â'Ÿ}õÍê?ÿ¸´}»V•«61ñ¦oÚ²Ýôe»¶‘VU¹¸hÝ=•ƒäü#'õÀËß.ýتªŠ¸—§G³¦ ÓÓ3“.¸¸è67µ{{{©ª:}æü·ÞùÈ|Œ¹¹y[¶íܲmçÑc'_œúôeG¨è)…cØ¿ïªeóEÄ`(lÛùÖÃGN„…÷ìq­½ë8ë;6@E©Âõj3õjÚ}÷Ü."o¾ýÑ»óçåå—ÓsÍÚ-ÏL|ÕÕÕeÑ‚™‰{ãc?´çÇNÑm֬ݲðãe–=?û⛣þ—™™ÝÿŽÞûþZŸ•¼ïÌñÇ ïܱmTë•.uꋳ¶þôÛ´ÿ9øïÆ?}Õ¦u «ª~øwě뿼¢aÃH· ?üfUU%¼ßm½Žíßúæk“E¤e‹&Çöo5½îx›¢(ÇOÄzèõo¿ù¿}­ÏLÚ{áÜßÇ ‘o¼î|ÂeG¨Ð)…ãÒé´3§O‘-?tø¸½Ë8n¿¡^M{nâÈ>7_WXX8nâŒmoš÷þçii¥»egçŒ0]D>YøÆ£Ã¹ºº(ŠÙ²éªeïiµÚ×g-ÌÏ/0õLOÏ?é5yà¾;¿^þ^Û6-5MDxÈ›¯MÞøýbN[éR¿û~Óüw¦½ôü˜V‘ͺ^ÛÑÕÕŪ*­¢HHC—¯…hµ˪*}àåxûÍÿ?°mÜÓ´mÓR«Õúùú¼1cR›¨ùùËV®½ìæ¶ŸR8ºþwôîrMtaaáäçß´w-‡`ê1S8B½šæêê²îÛEo̘äïç{ú̹1ϾѬۓO¿p"æ´e·«ÖŠ=Û±CÔ ·Z¶7i\ÿƺœO<kjùú» RRÝÜ\ߘ1I£)ñ Õj+Ÿè‰H§è6O<>Ø–ªÃ]®».Ú²ªÒl<ðrøûzyyX¶(Šbº¾2æäå±ý”ÂÑ)ŠòÆŒÉ"²fí–ŸýÃÞåIé¦ÔN„zv Ói'{ô×…ó_mß®UVVΗE¶¿yÚô9æ'6ü²ýOéÕ³kéw–M›4‘ã'Š(SfqíÕêG„Vmƒï»ÃjïVUYÞ*¢Qã0˪ÊdËÛ";;gÇoðá—O¶~ÃO"ræÌùËneû)…èqÝÕýnë%"¦ÌäA(€òq÷+U? ¨i<(Ãn<=õ#»ø£÷ý¸yû”çßüwïÁW^›—““kºœéÁµ³ç,š=gQ™›Ç'$™âÎ%ˆHËMª¼ÂÒ—î–[Õq˪ÊQþ—ï¿ýG.Z¶déw¦Kw#ÂCt:ˆ.ÿ :ÛO)œÃk/?»î‡mý³oùWk¸ïN{—¨Íõ€ã!Ô³3EQné}}Oþß›³Þýøí¹ŸŒ5¬~D¨ªª"Ò¡}ë¶Q-ËܰMq»iRÍ\*bUUBöÁ´¼8ÓªFÞ׺j½Ú\¢ÚÒ.uàål2ÿƒ%¦›âÝ~kÏdžÝ{]÷«ü}_zuîË3æV¢øÒl/5æëï6è¼"K·ûx×KŽû«ümÛµöà€O—|=õÅÙîºÅjí‘ÝYAa᥷òööŽ‹‰«tÁÇÇ\àõjFóʋϼ;±ÁP¸ûßõ#BÃBƒD¤St›O¾^þ¶!ÁbÃ¥£¦Ô¯ àò3ÚÊaUÕϧß9”¼Á´jP«)þîž-XúÀËìfT {÷óì+:ö«/çßuÇÍW^<EaaaÆ2K{ù…±ËV~*öì¼>or­M# ¹Vว^MËÍÍ+³ÝÕÕÅÝÝMD "r]·«Dä§_v]6†ëÖ¥“ˆüþç¿ ‰Éåt ð‘ä ©Ví™™Y¶–^‘ªJ³ñÀ¥øù……F)Tó÷'­Yz`Øg+?WUµÏÍ×Û’èYŽP%Å£æÍç%5çØ¥^©çw[õ\µl~éA6ÏM= æ›8n¸¹ñæû'-h6iA³ ñ9©9V¯ó±eߟñð¾Ã9©9 }¤Ê`w–÷ÔS˜©¡^úwïÁF-{¼=÷“ÒwîÿvͦÌÌlézmGxw_//˜“gfÏù¸ü1ïÐ×ÍÍ5++gÚô9¦+LÍÒÓ3ÍËa¡Á"²ã·¿-;¼òÚ¼ =´ÜªÊ{lû‹HhH ˆœ?Ÿ°çü×K<¼ýÌ{YI±þïz^–Ûfgçüù÷ÞÒ»+!>Ñr*–í§ –#Ô«Q_,ý.!1ùÙɯ]ÓýKW¬‰9y&%5m߇_zuî°Ç'ŠÈ#Cï1¥oþ¾¯N/"S_œ=~Ò Ó,'²eSÛë·ª*%)[DTU’Î<7å=˪*}à"Ò2²¡F£¤¦e¼ñþ¬¬üäü\5+ÝèÓ0MDÖ¬Û¼s×?"’››·y뎫º÷/s§Q­[h4šÔÔô-WU5;;çBJªí§Ô-%þ,ÊL=ว^zkæ”À—^»s×?¦pÊÒ-½¯ïÝ—Ì_Ž5ì||Òë³¼3oñ;ó‡feg›&µ%'§ÞÖ·§¹çÿ&?w.aáÇË>ÿòÛÏ¿üV¯wÏÉÉ?_Ÿ³gÏwì%"#»ÿÝy‹“.ÜÿÐXÓVZ­ö“…¯§¦eŒŸ4ÃöC(Y•xûkórÔ¼£HlVšÑ²ªJx1gÒš=©__ÕÛó™ËÞJ\½ 9/GíuŸÏƒO·ùm¥þÐÁSÝo¼7<,8ùBj^^þ5Wu˜÷ö´§Ç¿l5`DxÈà{ïørùê§ÆNûß´·3³²ÆŽzø­™Sl?¥ nâò[•Ão5P¯F)Š2qÜð!÷ßõ钯׬Ý|"ætzFfÓ& Zµl6üÑûúöéaù[EQfNŸÐï¶?ùlÕ?»ÿ;rìdÃám£Z<8¸ÿýn²V«Õ~0÷•þwôþrùêÝ{œŸÚµÔ´Ôœƒ[ŽÞkZnpoLjì[§´tÃг‰EÏœ9ü03õ`7¹†ô½‰ßìOZ_˜mµ*Ô³MçÐ!õëu¶Kaµ¡ªJn!‘cHÝ“°ê@ÒÚcŽÕªp¯öB‡DxEWimåàB9àxõp%*ü8Û²'~åäõc®Õªˆz;‡ ójWEµؤä³o¹Õ=€ÊpÕú4ô»Ã´ìïÑ޾Ũ#õPy‘þ·„z¶5-{¸ø—ß9« éß„•‡’7ŒyV«x_Õ9dHˆgTµT P®ö#r ŠÃ=B=•áá~uƒ×ì]€º…P•æÕΖ‰u™‰ÿƯ8tac¡Ñêž÷J#ïk:… öˆ¬¦ .«WO{—Pa„z¨Fùñ»ã—¾ð£Q5”\£4öéÚ9tH ¾¹] ph„z¨éyçþ‰_v4e‹Uœ§ˆÒÄ÷ºN!CôMìU€£#ÔCKË;ûOüÒc)ÛŒj¡e»¢hšúöèò€Ÿ{#{ÕàõP5Œª!-/îŸø¥ÇSVU£å*EÑ„z¶iæÛÃÓ%(=ÿ\zþyE4Š¢ˆ(Š(ŠhDE4Š(¢˜ZQ4^.ž.æAr éÙ†d]€»ÎÛܘW˜™_˜é®óqÑèÍÆƒ1Ïr"Š¢(ŠhLÅ·hx¼pP„z¨‡/ü¸óì…9jÑcãŠh]G‹ø¬ƒç2÷ËÜW¡1;† ¾&ìaó—GS¶î<ûA—ðÇ;27îOZóç¹Ïz4Û:à6sãßç¿Ø“°Êæý˜ò>EDéÑ`l¤óŠ?Î}r i]φût57þvvá‰Ô_{5šlù„gÞ?“ùOQVh™W*)™`*¢hŠ”.áÃõÍÌãìŽ_ž}¨køo·psã?ñKSsOw‰á¡ó³lÌÌO¼t0Z2¾,N0EÓ&ðN7­—yœ#6ç¦GܮӸYžjƒ1·UÀ­–¡çñÔ_ŒªA¢ˆÈÅC(Æ*"ŠhÌ-a^í,#˜˜}TQ4–G-")¹§´Š‹åQ«¢få'–ÖœÏjùWœØšŽTá©…€º€PW$ÛòsìÛ±é”^¥Ó¸ n½øDÚöø¬ƒ•¹Ô4:µ¨Ù²©hJ`™6RUU-N"K$’c^^a¦Zò"â¼ÂŒÌ‚ÄBµÀ²1« )5÷tEvzq4Ë/㳞JÛÕ)dˆeãÙŒÝq™{;‡>(¡^Lꎤœc•Øc ¿^–¡ÞÞÄUÉ91-ýn¶ õþ<÷iF~|¤E¹øûá×Ósò 3+±Ç'¢7X~¹öø$UUmÿE›ºòÐO—ÀÛ|in*(ÌþòÀC•Ø—kð¨%æ/ó 3¾Ø?Äß½ñÝ-çšu®ÑBò²Kl˜šw|Ëé‘RÅš£Òâ„T4¥Ú‹’D÷Ö׆N5“žê÷ó¯{DwinLÉ;úoâ{až×´ò{Àܘœ{àà…%r1ó½8‡Ô"VJfµŠ"J ¾mÃz7›ÇIˉMߨoæÙÅâpŽËÚ¨o¤ooYFRÎ^E4bF‹bPÓ®Í9©uIÞ®ê¹60“mˆÏÈ?Sϵ‡.Ø¢1!×ìéî¦õ17æ.ä3̱lÉã2íèb%¦>F‹ÿs •B-”P•dT $­ýóügù…Yev0óVêU¹ñ¥dT'ªˆ˜æ¾Y7J=+¥äবϺ ÓL´ªØ£Õ8R´Ã²¼ŠöX*-ç¬Z5VzwÖ{,µ;S¿ªù&Z—­ªcžU«ˆhu¢Ñ–ØÐ¨ægÄUbÅÅòËcf\Ö­ÆÕ²1×p!6c³‹ÆC.³’UpîxÚ÷•Øcsßþ–¡^JîÑçDù?dê%æìý#þõOZ†zç²~û3þÍJì±cÐèöOš¿ŒI[ÿWÂìkB¦´öÐÜx8eÅÞ¤…ÝÃ^mîÛßܸ'iÁ¡”¥Ú× õDëÀŸç??›±ÛÜ-×þ{Ü¢½ _GߨÏ*ÏrnŠ(çL]úa®Z/W­u£UJeâãQ%…5(•“ŠH3ߥ-Er%ºFÀAwOÎ[Ì\]´<;X‚P‰N:»7l~LÒ9óF'»²Mý_­æùŸ“Zˆ¯KÍ.•§E$œ<¹êz‰¬ö䌸?®/9³©žOŸš^ôŠƒV(kŠáœíúìy^qp¶óÍÖh¯s±wp)x%Îv>ή>ÙË8T(ãP![£»cU÷{c¾üñsiêçÒ4[c…2m+”i›­±r¹n•ËuËÓÁÛWéY ò ” ÔÃÃí ›û÷ŸîyÞV”êž›¼â˜#¿0çïZ§kð'á ÇE¬ŠL<Õž”~køÂãÑëû>WݳƒþÞ©;B=<œƒÞÕ<Ñóv®úxÐ[ÞΖvù t­X¥^ØÃ‡"WE%žÉjOL¿±7lþ±è |ûVóh¯Sø×`b<\Cßç/Äþší¨/Ó$àåžr>oûP¦™.®Æ<¹Êü1Þ„´è߯Í9µ¾¡ßóUÜŸÊ6r"ÔÃÃÙ霚¾~åöŸÍf››5¯*”m\¡l£+·Œ\u3ùbVû´ÈÝW?=µ®¡ï UÜÛæª Yõ`‘ŠåZT,×¢¦ú”„zЊR±\‹GË5¿·çpäêØ”«Y+âRÃv^™v$êë†~/Vr{œh@ —–w-î'QE-çTÅÛµ‰Ö°}„zÈ¿“1›#OšB·AƒíÜózE”Ên­*•ky1î·C‘«o§†g­ŠM¹ú¿Ë“=œ*6ò±b¹æB´ŠÆ_QÓ’Ò£DD¯s|<`šÖå°JÉÑÇ®O5-WôèE¨ ê!ÿ¢“΄Æí5-7õ5ßÿšEìÞ¦²ÛçcwŽZŸ‘µêVJè/¡¼ •ùõ{¤\S¢=Pè"ÿˆK½("v:g­k°Ó”^)ñ)ñ;†Z8¥ˆˆˆ¢èªz´ëS}é凗qð5_u#ùâ¶Ðñ‰§ ñt&êÿ¤aÐ…B-Ô%xzê•FƔÑkNÄ|[Õã©'Ê׺œ{è}uÏU=ž:{ë—#QkÒ¢Mí~.µü]jk[«péöÖ°„Ý"Š¢(!ž¯•s¬¤uE¬¡°„z¥NhÜÞýá‹ÒcDäìÍí5<;ú8W׺¨ìtŠ] ÏNU=Ú¹¹íhÔºÄôüúi]ëp+õLhüϦåªnÏ–Ó¶VA¥O °>„z¥ÈíÔð}a ®Ý9œÕ¢ŠúgøOW™•¿Þóù·¾ØÖ+öµ¼ºÖðìxúÆ–À2õ ÿl’jÔºVÆìñ[«A¨W*dSF­;½1SM7o¯X®EóÀ×µªÊB:Å®Žww­«`5ÌG±ax,¶ŠPÏö]‰ÿs_ØÂ;i‘æeý[._¶±VU@qPõXâÿ¿ ࢠÿ¸€(n„z¶ìNZä¾°…Wâÿ4o´Ó9Öóy¶žï³zÅ¡ 'Pé 2¿41É;€<áó °„z¶)SM?½ñhÔº cªy{…²MZ½YÖÁ_«Â ¨©b>¦÷çl¡žmÚ:ñJüó–2¾Íßx´ÜcZ•ÅC½§1<œÙD\6€Õ Ô³Mu¼{f…zzÅ>ħwß¾v:Ç¢<'‚”æSssi'\4€Õ Ô³MeêUvo}1vwP™†-ƒ—s ,šó¨ß´£(Œ©À|¤Ö‡PÏfµ zË×¹zïZÅŠ1õäÙ¿ísÑO<¿ øÑ…Áf9è]‹3Ñãw€ƒÇoä— `Eõ*Ϫ(y˜(@^ñ‘@a㪠8êlŒy¨Ç¯9y¡ð]°ÜílÊ==n¸?`£˜(`cS@^ݽn0F0€|s´ó¨áûºiÙÍPSÛb”„zÈ¿†~/Ôôì"""ªÁÞMãj@Dîí©Çý9K<8#Ó˜*":…ÏÆòÉÑΣ¦ï`­«PºðÁùçáTQœ´.²£§€¼ñ1ÔÓº€>öõÏ[rRNg08Þ·˜¼”bwûA«æ}:Þòãì ›5þ/Ór·*ŸºØ{´2”0Ô˓䌸;iQ¦eU5Ê1PÒù˜zŠ¢øx{Üî¬EäÛï·ß¹“˜µö䩳cÞŸ."¯¾ôÌo;¾îÖõ©Àß @¿žÝþ³ï× ÿíÛMDÞywÊ™³‹ºNmÅÆÅk]¬FñM”Ñ¡}+IOϸ‘Õ8yúçééþ> f¬×ëÍ··³Ó/Y0ÙÛË#55mê'‹ rê›·â<)†àÕ_o6o?tä¤bvö¨m^’ˆ\¾öæ°ñMïåâY'°RóW_/üzT¶c>zªÿ€QUë<åШ}——æ/\m4ÞÓ3®eÛ>Š!8"2:11ùãÉs«×mïäV³B•Çß6>2*&k³u·(†à6ÿyADNÿ}>k(À/—o0?Îìù˳püÄ?/S§Q§²>uò¹÷>˜yûöœ¯Ý´{tÌMUU—­ÜظEÏ:ÕBÚ ~{|bbrÞþP2_¨—dZps+kZˆ»ÿÍæm"2bØ«ŽŽ9w1œÞ~ëeY¿i«yÿ¾¼òôp›üñyïƒOÌ“¬÷ÇÏ‘1ï *äŸÕøÅ²õuuZ¸dÍ_‡ŽÆëÑËVn¬Ý°ã‰“gL¨ª:gþŠÇžè½jÍwW®†ëõº;÷¾5âã}ÞHIIÍvêMßn«Û¤óG“æž;šššv-,bá’5õ›>}áâÓ®.Ε+Uðöò{{»Ê•*˜~Ê–u}ÐËQUuÖœ¥Mï¹bõ7§NŸKOÏØ»ÿд™‹ê6érãfì}w¹r5¼o¿·_}ý½CGN&%%Ÿ;úùâ5í:÷SU5ŸÐVñ…zk7ü("înþ~Þ¦–?3͇ûr¿^Úë•þ½E$55íàá9ûÀWú4¨W+üzÔÌÙ_˜Z~Ûó×/ÿÛè7jøÀ¬ÍV~õí Áï'$$uïÚî䡟ož »¸oÔð ë×®Y£Ši›¶ì|{Ô$û¥‹¦Þ‰9uõÀ™ã¿4¨Wë‡-;¹6Ûy‡¾3!99eÕÒ™Ñ×þºqøë•Ÿ¹¸"£bF¾7Õ´A—Nm/œÞ5cÊ©Z¥â…Ó»L?Ïöêô ×òùâ5#ßš––>òíWÏïI¸qâÈŸ?4oÖàÊÕð½ûÝw—ÎÝü°uçìOÆ]Ý~iÿ¸w‹ÈŽîÚýG>ÿB "õŒFcèå°Ñc§Oœ:_DÞýº¢(¦UÇOþ#"înå<ÜÝ´»¯—‹‹ADŽø'÷}³y›kµl? }eZ«×ëÌùXD¦ÏZ©ªª©›ÞŒ)cœ ¦mâãFŒž""Ï÷yú›u jתªÓé|gL³ýÇåvvzIJJ6r¢ˆ,[<ý•þÏ88Ø+ŠR­j¥Mkèõúi3§¥¥›WÕªeãcmyñùî^žîînåú>ÛuÍòÏDäûÿ÷Ï™ü w;~ìø™"2zÄ O¦¾[>È_¯×ׯ[sçÏ«ë…Ô0…¤9)вû—5Ƽäïçàï3qüðõj‰ÈOÛvç£h«HB½­Û~ ªÜ"¨r‹€ŠÍÜjVªÑú“Ͼ‘×ô6ø¥¬ÍnÞŒ‘G ÌåPŠ¢<úHˆÜ|Àƒ¥æ2s0¼´Y“z¯ô&99eì‡3·ïسïÃÍ›5xî™.Y|³yÛ­Ø8GG‡é“Gët÷üÍd÷·~ÓÖ+WÃë×­ùLÏŽæT|4¨ÍÍ"£b.…^5oïÑ­½éÑÚ,]:µ1=íûÓöÝ}E9}óÝöøøWWç1#™·;99Ž{oðƒö3òµ&êš·´jÙDDrŽ€’Ï®(š’’š--ê޵ݰ!/µnÕÔ¼1-=]DÜÝËå~4O7IMMË}³^Ý;lZ;?÷m¦NùÍæm«¿Þ¼gß!™=s\V·AùmÏ_"Ò´qÝ @¿á÷½E¤mëÇÌw4©T±¼ˆ\¼tµzµÊ¹Ô ×ëë׫y-,âÊÕðÜ«½¯=ûŠH³&õsvoìØþ‰_Oºï^:]öj}|j€¶Š¤§^¯îÔä jò…ô;g«U­$"þþ>Ù=©P>@D®GDç~´°ðHy¤Bnú,äãí9æ×Däò•°~/ôhÜ0Ä|­©’ªU*ærSX9kÎÒ¬ij³~–,]'–Åd¾>^¦òñLEšÄlœ N÷›oä¾ìííD„‰2¬Q‘ôÔû÷èvú©Göìóæ’¥ë†¾Ù/[6Óƒ·W®†«ªš³ã›Iffæµ°1=„[@F£qËO»LËQÑ7²×h4ŠÈƒ*11¥`uCjÔ®Yõ¾Ôz@»9ÓL¾vúüüå?$†Ëµx؆¢ õD¤{×vÍšÔûó¯ccÆÍø~ãbóU-/"ÉÉ)—¯„W|ôþ™Ý…‹WÒÓ3DäAäÉê¯7ïÿóÈÓ]ž<~âÌö{6}·Í|høbšº·A½ZËOËw¡—¯‰H@€O>ö5zù>½ü’’’SRR‹á=˜K͸y6z©iÙݹNy·Ž¹oWä³ß*Š2}òùaËNÓ uYj׬êåé." —¬yÐîŸ/Y#"ÕªVªY#¸€•ܾ}gôØévvúYÓÆN›4JDÞ9ÑÔiΤy³"ràà±è˜›:HËæDd÷Æ|ˆˆŒ>züï¬Ó™˜&âÈÌ4>twS‹»ŸmÕŽûòWR¾í_üí¹!ßžòí¹·R2²×`¶_yyKè3[BŸý5l¨Öµ°Vi™ñço¬6ýDÝÙ«u9J…"õD¤UËÆ]:µ‘‘ïN5=âjboo÷Ò‹½DdñÒµ·oßÉ¹ã­Ø¸¥+6ˆÈÈ·d›Ž6>š47:ææëŸ®üHŸÞ›5©w="úà ³³6èݳƒ££Cbbòø‰s²=åŸ`ZèÕ£ƒ««sèå°Ys¾´ä¤·nÝÎÖ2yúçiiéÊôxº}V£Ÿ¯—ˆDFÅdffæ~ÀÞ=;¸º:ÇÇ'ÌüìžRSÓ&L™gII…(>ízLÒù˜¤ó1IçTyHå%Slê¹›)ÿÜLù;.õ¢ÖµXª8B=™òñ;Š¢:rrÝÆ-æícǼáíåŸðüKÓ“SÌW%&&÷ùï°ÄÄäŸÿöíVÀN>7oá*WWçÞ""Š¢ÌýôCEQæ~¾ò؉LÛøúxý†ˆ,úâë—Ž>w>TUÕðëQsæ¯x¤Z+S÷:O·IãGˆÈØg=ÙÔ§OUÕK¡×†œøÓ¶ÝÙÎ;qêüþF=wIUÕ°ðÈa#'.Xô•ˆL™ðŽÁà”µYÍUt:]\\ü’¥ëTUMJJ¾wßâá~·€ÉÓ?á×£ŒF㉓gÚuîäØi½¾˜Þл˜fX?•Ï4 WÅ£˜Æ_«S»Zÿÿö\±ú›±ÎêÙí?NNަvw·r›Ö.h×¹ßOÛv7jÑ}äÛš4ª+"8:ãÓ%ç/\6œ¾]¿0kû\|³y›kµœíåÊ–¹~pÈð233G èãíijoÜ0ä•þ½—®ØøÆ[ìûuƒ©'àûcÞ¼½øËµ«Ö|·jÍwƒ“)jtw+Y¿nM:¸dÔi3}6oùgó–ûúx%&%%$$‰ÈÍ›q:´6?ûcMë¯Ýð£ù¡DdÜ»ƒû>ÛÕ|³Àß¾Ïv]³îû7‡ü§ ‰‰Ã¿ôÉÔwïûJ‡šúÁÇŸM›¹hÚÌENNŽ))©"è×½áÈš•ïNl°w{è_Øž¿¢¦ÞH>)¢(¢´«°ÄNç¬uEJ>n¿€õ)¾I>þ`ØÚ ?^¹>oáªQÃfµ·jÙxÏÎuÏ÷þ÷?^yíž«FõÊ_¯œ]/¤†…§¸ï³«™ÆÌõ›¶þ¶ç/oÏC_5_5eÂÈo6oÿó¯c_.ß0èÕçDD¯×/œ;¡{×vkÖ}ôøß—¯„5nÒ¬i½±£ßðóõ6í¥(ÊÔ‰#»tj³lå¦#GO»p¹Bù€Ú5«ü·o÷§»<™íì/>ßýË…S'M[°gßA£ÑجIýA¯>÷Ÿvç¬s颩¾>ž[·í¿Ù¸aHP ßƒ^¦¢(cÞy­Ý“-gÏ[~øè©«×®7oÖ Åc ÇŽyí\Y ÿ®Šï(n§^ŠI>aZ6ÊÃÇ*k¤Œ^TÙ´TÞ«ÚÎsµª#==ãÛï·oß±gùªM"òd›æCÞx±k§¶¦$¬Q˶}öýqxÎ̆î¯u-EeÛ¥¯Ä0-÷«½Þ`Gß@”\›övðü6ó–w{î78h˜ƒ£¨üru@D⟦åç«ýi¯sÕ¶%ßÚ³ÍÒŒ "RÖáÑ•·ç/\®ßôé«¿¹§ªjlÜíëÑZ—†Üð!@ qo¤Wâ~Í(Q@aà†@q+qw;ÊìÙ¹®j•ŠW¯]yÐÏ€FNn5=üü¾Ö¥!;&uPÝÓEš×,ñÿi.Àj”¸POD*WªpêðÏ+¾˜ñTÛTÔét5kûùzi]À ˜ß p /xòX‘’2¦^6öövýÿÛ³ÿ{j]ÀêЉ@Þðð°F%4Ô³{w­×º„bÀhôJ4ÆÔ`™¬4|žVƒ»€MQS@)@¨°1fcêê°ß((>u(~„zÈ?>ÿ(2X@Uï^7¸'V„P`cè©´EÿÅP`STæð\4€Õ ÔCáPxÆ @ ¡2‹%€üâó °vZ€Âtææ¶ÉMËýû;ê]‹ø„ô*PâdõÔãÙ[ã# €‚r´ólT~¢iÙÅ¡¼¶Å(%õlʵ;‡.Åí1-×óy¦¨C½ÖåßÉ0¦š–Š<@ ýÿÍ9=nX¦{å-ªEUuнֵ°Vöz×GÜ»k]€Ò…Pùçlï¡u =õä•«}€Ö%äcêl cê°}ôÔØ”6As3ÕTQU•A²Ø.B=€Má1:¥ßV†P2døGŠ!¸¬Oݨè9×ÆÝŽW ÁŠ!øÆÍØâ¯-ËÁÃ'ž{qX­ îµ*6ïÚkÐúM[F£†%h…Pwݹ“øÁÇŸi]Åý½3fJ“–=×oÚú÷?RRR#"£·ü´ë¹‡5oýLøõ(­«(n„z¸KQ”/—o8~â­ ÉnùªMŸÎ]&"o záÐþÍ‘WþÜ»kýìOÆ•ò?pðøgs—i] @q#ÔÃ]/<÷´ªªÃGOVÕ’5_ä—Ë7ˆÈkú~>çã†õkûúxµx¬á°!/>²mæ´÷¦L©uÅPw=Ù¦yÃúµýíÏï·üÏò½ŽŸøçåAcê4êTÖ§îãO>÷Þ3oß¾“s³–mû(†à蘛ªª.[¹±q‹.žuª…´üöøÄÄä\ޝªêÑã‹H»'[d[U¦ŒË;Ã^up°ÏÖ~øè©þFU­ó”g@£ö]^š¿põƒ†Þ»|%ìÍaã›>ÞËųN`¥æ¯¾þžùün~õCðÿví˶W—žCðG“ææ|7nÆ&'§¼;î“ÀJÍCðª5ßå£*€‡"ÔÃ]‰‰ÉÇ‘‘ïNMMM{èöªªÎš³´Éã=W¬þæÔéséé{÷š6sQÝ&]öî?tß]®\ ïÛïíW_ïБ“IIÉç·~¾xM»Îýré¨(Ê£ŠÈá#§,)iÎü=Ñ{Õšï®\ ×ëu;vî}kÄÇ=ú¼‘’’šmã/–­¯Ó¨ÓÂ%kþ:tÜh4^ˆ^¶rcí†Oœ<óÐ=HLÌ­nϼ>}ÖâëÑ"R§vµ¼V` B=Ü•˜Ø¡}«5¼xéê¼…«ºýç‹×Œ|wjZZúÈ·\=¿'áÆ‰#þмYƒ+WÃ;v{åì¹K9wéÜ}À[wÎþdÜõÐýá—ö{w°ˆüqàè®Ýär¢>½;‹ÈŒO¿˜=yîiã[v¾=j’ƒƒýÒESïÄœˆºzàÌñ_Ô«õÖ‹¿\k¾åʯ¾4øý„„¤î]Û<ôSâÍ“a÷>°aýÚ5kTyèk±ÎܵûñïýçØöý»7ÖªQ%OUXˆPw%$$)Š2kúX™8u~tÌÍ\6Ž»?vüL=bÐ'Sß-ä¯×ëë×­¹óçÕõBj$$$½÷ÁÌœ{)вû—5Ƽäïçàï3qüðõj‰ÈOÛvçr®÷F½Ñþ©–™™™ÃGM®RûÉyŸ¯ºï¾IIÉÃFN‘e‹§¿Òÿ{EQªU­´ií½^?mæâ´´tÓ–ññ #FO‘çû<ýͺµkUÕét¾3¦ŒÙþãr;;½ea÷±ùÇó?ÿѸ¡Õ«U~¬i}{Ë«°¡žM©P¶Im¯n¦{½sžöMHH‘¦ë¾ð\·øø„'ÌÎeão¾ÛŸàêêÓ³£y{ÅGƒÚ<Ñ,2*æRèÕ»ÅoÞv+6ÎÑÑaúäÑ:Ý=ÿ èõùOôD¤A½Z¯ 蛿ª,G¨gSªy´oô¦éÇQïš§}U¹;°ÝÔ‰# §/–­7.§SîódϾƒ"Ò¬I}w·l«:¶BDTUÝ·ÿp¶U:’­ÅÇÇSD¢¢oä^›~ôˆAWÏïY<RHꉉɋ¿\[-ä©ñçdM7ñûÞƒ"Ò¶õcŠ’ý,•*–‘‹—îÆg¿íùKDš6®è—ûyóªoŸ®ÙÎnyU–#ÔCvåƒüG h4GŒ™¢ªª‹‹!ç6¦‰ L±T6ÎÎ?_o¹‘[ÿ;{{;Ée¢ s..†A¯>wìÀÛ~X^/¤FFFæ„)óÞ÷‰i­©»ß¬9KCp¶Ÿ%K׉Yth*¾j•Š–œ4Or>ºkyU–³Óº”D£G úrùú¿îßúó¯]:µuq1$&&›o{ gê•fYR—gŠ¢ü§Ýãížl1æý3gùéÜeC÷ ô3•T7¤FíšUï»c­ÿo7uîËÙu®(X^€åõp..†i“F÷{uä‡fwîØ¦Œ«k¶PÏßÏ[DB/‡åÜ7))9"2ZD|Š®BN7á÷gÏ_ž‘‘yôØßA~¦’Ô«µlñ´Ü÷õõñ ž{5¥~éé©ÓòªX¯”ŒGÃ'‰ˆ¨ª—kÃ*^ý´®€íãñ[Üß Ï=ݨA£Çÿþî‡_Ê–Í><_ËæDdߟïï±òÔ3+O=“aL1­Ú±sŸi¡y³…RIJJê}ÛìœE$=#=«¤Ý¿ÿùÐÎT؃ÇrŸá×ËÓ]DnÞŠËÖžhiéy© h¨f¬=×|ݹëεÜyíM­Ë`­2)×oï¼~{çõø]±I§´.@©@¨‡ûÓét³gŽ‘ñç¸8gVQ©ñ IDAT¯wÏ®®ÎI é[V‡¥dħdÄ›ÚSSÓ&L™'"];·õñö,xÇNüóHÕVŸÎ]–5!F–ï~Øaš±÷±¦õE¤W®®Î¡—ÃfÍù2÷cöîÙÁÑÑ!11yüÄ9Ùž#ŽOÈZö÷ó‘}Ü3ÝÇ„)óLólXÈòª€FÔ´ÌøÔÌÛ©™qéÆ<|u -B=Û«Ó©ÓçŽÿ;Û*w·IãGˆÈÏ+b7/¼“a4Oœ<Ó®sÿ#ÇN;;¦M](5|õõæè˜›ïŒ™òø“Ï}½þ‡ÐËa±q·Ož:ûѤ¹ýŒ‘—ûõ6¥ožwKûᬣ'›zᩪz)ôÚ°‘Ú¶;똾>^cG¿!"‹¾øú¥£ÏUU5üzÔœù+©Ö*ëÅvhßJDV¬þfý¦­‰‰Éaá‘ÃGM?qNµª•,¯ßòª€&T)ša€Šcê!7Ó'þ~ËÿRSÓr®:¸ÿÑ뛿šwzÛª¸m«â>rjlzN6(Ðï«åŸÖ¬\(|2õ]__¯&ÍÝÿç‘ýɶö?í_0û#ó’"£nL›¹è³yË?›·Ü×Ç+1)ÉÔ›ïæÍ¸NZgmùþ˜7¯GD/þríª5ß­ZóÁà”œœ""înåÂÃ#ë×­)"ƒ^}nö¼å17n=÷â0Ó^z½~Ùâiq·ïŒ=Ùò—`yU Å÷—º§fÆŠè\ìý:?ºVër”|„zÀ*ÑS¹yô‘ w†½zßUŠ¢ôz¥ê˜/›v,ã_ÑÁÎNß¼YƒQÞ<üÓ7)¬E5|àùS;'üNÓÆu½½<jT¯Üãéö?m^úó÷Ë 'ó§N¹w×úWú?S/¤Æ„Ä @ÿÞ=:lÞ°hõ²™æ‡Õëõ çNøùûeÿíÛ­VÍ*:Ò¸aÈ[oöûûض.Úš¶ñòt?¸ï»î]Ûøû”-ëÚ¶õc;¶®|¹_o·reòú,¬ @¡Hɼ•œq39#&%ã–Öµ°:ŠÖXJ½¨²i©¼Wµ!çj[ ¬ËF]O8aZ~5ä;£¶õ¹Ø´ÿ³ƒç·™·¼Ûs¿Á¡¬Võ è¬?÷xJf¬ˆ¸Úö Þ®u9JºL5õ«3 M˾Î:<²BÓr`Å22S'n¼ûo)È·aßö+4-Å-1-lÛ™Ž¦åòn›T˜¡m=lÒ×Ûú…Ç5-Ox–žz›’õ¢ð;ÀÙϚ¥ÐSXnx6&k²lnÎä× ùÆ@q#ÔCþ1¬4€(k"Kzܰ Ÿh2¦ÕP<õ6†ÑòÄ좡ðe°vZ€Ât3ùbRFœi9ÀµŽ^q(¶S+|PB¨Y=õøâ €Í"Ô³)G¢Ö^ŠÛcZ~¡æjWŸ">!Ýa”8ÿ>ð— ,`þ”W `EèŰ)Œ© Ì¿¤äº¬¡ ‚”Y÷ç\—@1áÛDÅP òø-€ˆžzòàÞ~z\7€Õ Ô´7{þrÅܲmóÆ–mû(†àÙó—kU`¥T•žzòë€Â@ïÅ‚P`c˜(@^pï ¬¡ž2ü#ÅÜ»ï|áÎDÅ\»aÇB¬J²ÏW¬7ÏyzE¹ÿ¦¤¤*†`Å|ìÄ?…Z#m0Q€à‡­;g2îzèþðKûŸ£®ˆ\:•röðÝ>b]:µ½pz׌)cD¤j•ŠNï2ý<Û«“iƒ¶ì|{Ô$û¥‹¦Þ‰9uõÀ™ã¿4¨Wë‡-;¹6ÛéÆ~8s×î?Æ¿?ôŸcÛ÷ïÞX«FKVåÕÐw&$'§¬Z:3úÚ_·"½ò3CdTÌÈ÷¦ZòŠ NQ”‹—®: ŸÎxÿ䡟nœ¸qxÔð"2yúç‘Ñ9wÉöFŒ{w°ˆüqàè®Ý˜o¶nã–&ÍUUõÅç»ÿsl{JÜß§ÿÜï…{ö´°¶Âz¿¦SìôŠƒ^qÔ+Žß¬=õ¬›¢(»YÓ¤Q]Ó_Zï®3WϦžÚŸ$ý¾{RRò°‘EdÙâéY¡Xµª•6­]P¥ö“Óf.~cÐ öYÛoþqǹ^ø|ÎCå²*¯Zµl¼iío¯»3Fõ}¶«³ÁÐýÙ׿ÿñÿœ¹X£zåüö›ÍÛC°…:ãý³?vuu6ýÑÝ­ÜôÉ£Ú¾ûôßç×nØ2bè+Ù¶ÏöFL?ü§m»;ýÓ¶ÝO¶injLNNóþ yéÅ^ËO3õà«U³Êò%Óü}¦ÌXøÐª ñýVžzÖmÌÈײ‚$1عÕlè)" 7ítÊÃç^X¿ië•«áõëÖ|¦gGóöеy¢YdT̥Ыæí êÕzm@ßû*—UyÕ£[û¬DϤK§6åƒüEä§í» ååéá–•è™(ŠÒºUS ½|-çöÙÞiÕ²‰ˆ„_ÊjÙ¶ã÷kaöÇWî]ÄÛÛ¢9ï ñýVžzÖM§»'j4¤Uu»m2Ó)¥²³½çCwÿ}ïAiÛú1%Ç ¶•*–‘‹—®V¯öoϸ¾}ºæÜò¡« N¯×ׯWóZXÄ•«áù>H¯î6­Ÿ³=%%Õà^ëA{%%%=þ÷‰“gNž>·í—ßD$,,2çfÙÞñññ‘¨èY-ÿsAD֯藯WP˜ï°j„z¶ÆÞÞNDLó0<”©Ù¬9KgÍYzß Ì3)±³{`ï¿\V _/¹|%¬HÏbîÔés‹—®]ýõæÛ·ïˆH`€¯ˆ¤gdX²{Î7âŸ3E$¸ò#ù.©ß/`ÕõJ5SäT7¤FíšUï»A­´¿;wEÄN_Lÿbç/\m½®sÇÖ¯ö¶e‹FžnMšûñä¹ù>fzzºˆ˜’Áü±¢÷ )B½RÍËÇUDê†TYùŬ":…éñÏôt‹z·åÂ4’]@€O!Ôô0ÇNü3ô vvúkæwëúTa¶â£åE$,ü>OïZÈßÏ[DÔ«µlñ´Âª X#&Ê(ôz½ˆdf³µW ±‘Ÿvý¼ų̀³·¶§e&ú©½<ÝEäæ­¸lí y8WDdôÑã‹Hóf L-zE…âÛÍÛUUmÿÔã…˜è‰HÅGƒDäð‘SÉÉ)ù;BËæDd÷ï<$VP¯Tðóõ‘Ȩ˜ÌÌL³fõÑÇn8t7®§¯\òû®:ýÜŽË“.ßÞŸ©¦Ö©ýý|Dd߇Í'L™÷Ûž¿´Ë­[·³µLžþyZZz…ò=žnojyÀ+*))©"R¶Œ«ycRRòÁÃ' rØNZ;8ØßŠ[ºb£y{bbò¶_~·ä½ztpuu½6kΗ©X;B½R¡f*:...~ÉÒuªª&%%ߊ‹I:otŠéöš‡ˆ|¿èæÆ97ãn&_ŠÛ³íÒÇŸnïÙûµ^_m^!bÑ„¹èо•ˆ¬XýÍúM[“ÃÂ#‡š<~âœjU+=h—‰Sç÷0êì¹Kªª†…G9qÁ¢¯DdÊ„w §\^QKÍR§ºˆü°õûÿ<""))©ÿÛµ¯Q‹î?mÛ]Öòðò³"òö¨Ió®¾—šš¶k÷-Û>»}ÇžœÛ»º:‹ÈµkY-žn“Æ‘±Î1zrtÌMQUõRèµa#'°<`EõJ…Àß¾Ïv‘7‡÷ häæWêŒEÞÎU{V7tpÿ./ù©ªì\7ªÓåÑ/¿ýdèèÿ|³êø¼³×üÝï@IJ[)—ó}êA¯>çíå‘’’úÜ‹Ã\½ê”n9oáªe‹§½6 ïƒvy¬iýµ~¬^·½‹gòÁ-ç.X)"ãÞlz ¹¼¢|™Í3=;Ö®U511¹E›g+5wó«ß®sÿ2®®ó>_À#4nXê•333ßñ±g@£²>uŸìøbTôÍ93?ȹqýºµDäÓ¹ËÞñqVãÐÁýßùºªªŸÍ[î[¡©ß#ÍÊúÔ­\³ÍÜ+¿^ÿcËÖ‚P¯´Xºhꈡ¯T«Z)=#½qà@?ñv®Ú"èï?ÿíÛ-:öªV¡ªSJ’ÑÝGß ­ëÓý^ï›},jýÆ3¯ÝL¾˜¿ózyºÜ÷]÷®íü}Ê–umÛú±[W¾Ü¯·[¹2ÚåÅç»;°¥ï³]==Üü}zvû϶–O?\§»çŸë}_Q¡pttØµí«¯ô©P> 6.¾fõà93?Ø÷놶­+à‘½½<üþíø÷‡¶jÙ¸L/O÷×ô=zà‡úv˹ñˆa¯´{²¥³³áúõè¬FEQ¦N¹w×úWú?S/¤Æ„Ä @ÿÞ=:lÞ°hõ²™,X eô¢Ê¦¥ò^Õ†tž«m5ÐV†1õòí?ÎÇî »sĨÞ3ƒ©[_QвmŸ}ž3󃡃ûõ¹PÚlÚÿÙÁóÛÌ[Þí¹ßàPV«z€ÉÈL¸±¡i9È·aßö+4-`ƒ¾ÞÖ/<æ¨iyêÀ³vÚVƒÅNçìÞ:ؽuJÆí‹q¿ŸÝ•xÆ4¬^÷¶ÅV†Q-’9ml¡îÃÉ®\-¯®µ¼ºÆ§FœÝu1nwe÷Ö97Ë0¦˜8EQìu†â® ÀT1¦“Ñ)özÅQã‚X§ÔŒ›{C_7-{»6 ñ©m=JB=d÷Ö»¤¤¤ÜÛæ¶C¦äÜ21ýF¦1Ý´\Öѿ৾zYDÖ÷Ãé wíÐîéí ~L€\$¥GmºÐδüH™ö­ƒ>Õ¶Vʨ¦Ç%Ÿ1-»8i[ €R‚PÙEEÇ$%'[¼¹Þô‰ûv–HKO‘ø; QÑw ~@€Ü©¢f-+І…°v\A7B=€-Q3Œ©Š¢ˆˆNìE¯u=¬ ÷äÀjêáEìŠuΊVOÕÎHåÃ4€üKθ¹á|kÓry×6mËù´Ý  B=<‹GF›7ŠóŒÑ—lt/Î3°9ÿ>FG‡–1»npáÖC§uš{ÆÆâw€ª¨"ª½ÎUër ¨êlG9ÇJÏTÙ¥uPäxü°2„z€•!Ô¬ ¡`eõ+C¨XB=ÀÊêV†P°2„z€•!Ô¬ ¡`eõ+C¨X;­ 4“aL‰O»¬ˆ"Šâ¨ws¶óѺ"V)5#vûÙΦe¿2-›T˜¡m=JB=”^q©ç·^îkZ®îþ|S¿±ÚÖÀjÓ32ŒIÚ– ”àñ[”fªÖ° ŠÖ(uè©°Ƥ„ôÓctNz7G½»Ö(éÌ#=EážX B=€íˆN>ºãêk¦å¯×ë{Ѷ("<~ °ªúoŸ…§`Xäž¾zšUG„z[bê)üŽ7|¬7<Û¡Òã@©L”¬¡À–˜?~ –àË…‚ €âF¨°÷ö¸áw›Å À†0Q€¼Ryü@!S¹°(„zÛqOO=…PÀé—À*êl cc(¾ ÖƒP`Kèq T ÔØUŒYË„z,C_…€Š¡ÀvÜ;,5Ÿ­Ø,B=€-a¢ yÃDгß(„z[ÂÍ9€‚ຬ†ÖPhÌÇÔãæ€eèP )fÿ E‹P`Kè© oteüœ«¢Š¨eÊk]kå`çÖ+ä¤ÖU(]õ¶ƒ‰2䕇Sÿ<²\ë*òŒ1õ¶Ä¬§e°]ôÔØG½›¡¾*FÕ`ç¥u9PTõ¶#еe kK­«€"Çã·€•!Ô¬ ¡`eõ+C¨XB=ÀÊêV†P°2„z€•!Ô¬ ¡`eì´.%Wb¬Ý/ó}²5:»ez?šzå˜sQœÑ˜YG°5„zx Õ(©‰ÿöåtóO¯Ú"Á·rªj”ðÓ†Ä8½†µ”f„zx8÷€ôª-|*¦šþ¨è¤Êc Ç~.§mUPb¨i™wLK:ÅÎNW$Ï6€9B=dçå鑜’bZ.ã›T?¦\`B¶mk¥D©˜žž®Š*"Š(zCá–áêÌoAPä’3bb’O*¢ˆH9ÇJeѺ"V)-óΧ[˜–}Ë´hYq‘¶õ( õÝçŸL‘ˆÄS‡#W‡ß ͶÖ^g¨åýt]ïÞo4,»æïÒ¢EÄÙÞãÅZk5¨ `n$Ÿú5l¨i¹÷°:^µ­ÀB„zÈîz‰Ñ_]O8ž­ÝAï\Ë«[ˆwO'»²w›Tµ¸‹€’ÇÔኡþžpìpäW '³µ;è]j{u ñéé¨/£Ia`¡;i×n§…*¢ˆ(N5 vžZW ¤3%r—Â=9€BAïÅPYÔ?—ÜL¾hÞä w ñîQÇ»»ƒÞ5×}ù  D¸rgÇáèOMËm‚fW(ó”¶õ°6|¤VƒPY”†~/ü:ÁôG}™Ÿžµ½º9è]´ƒÊPJ˜{¯KÜœ°Ÿg€U"Ôÿ*–kîi¨”˜~#Ä»g-¯nzæŸ`uõäÕ¿× ®ÀŠêÁœÒ¦Âhw§ò:%oÿ0@I¡šßœsiW\7€Õ ÔÃ=< µ.òïäÉ($|ðPÜtZ@!2f-ÑS€eèá ¬¡žíKL¿¡u PLîíoÃÍ9ЀªÒ@qàñ[›¥Šz)nϑȯìÊt þ¤ˆNQ‡€ Ç €¼¹÷֛밄z6HõRÜo‡#¿ŽM¹bj‰H8áï¢mUP TÕhö'nÎX‚±8€U"Ô³)ªj¼·ûHÔÚ¸”«æí‡#×t &Ô`ûÌ{+Üœ°]„z6¨f^ŒÛ}$òë¸Ô°l«\ì½*»?Q4§½{óÌ3nJ óçè¸4°í«D¨gõŒjæ…Ø]G¢ÖÞN ϶ªŒƒ_}ßçªy´Ó)¼ÑJ B=¥Y3ªçcw‰ZŸ‘mUYGÿ¾}«¸?Iœ T¹çñ[fx`&þP¸°($>Ö*6åÊ÷çG¤f&dk/ëÐÀ÷ù*îmuŠ¾è«øÿßU \ „0›(ƒ ËÐÃX%B=kŸ‘-Ñ+çØÐï…Ên­‹%΀’螯Åù¾@1¦€|S‹C iÙÉÞ[Ûb”„zÖÊI_Î×¥ºN±¿‘tÁÅÁ«ïóÁn­¥XŸ5«ìöDjf¢ˆ8êËçyàÁèq o\탂ËuUÔrŽ•´.€µ²Ó9w¨¾Më*”.„zÖÊ×¥F÷*sD$*錯s5Mî]›¾Qü'€\¨Ìb ¼ !Þ†­«È3B=«çë\]ë ä §€RP`;;@ÁŦžHüSDQü]š¹9k]«”iLÝyþÓ²·k“V•–j[€Ò€PÏŠe=~+"™jºâXÌüu}Yjf‚ˆ”s $ÔÖ(&ùØÁ¨é¦åþ õ€µ`L=+–-ÔÓ°› h]k¥pPìè©gÅtf¡ž‘PD®'îO»¢ˆ"¢T,×ÙAçªuEJ:UUµ.€íá 8êY±¬‰2DÄ4¶”râ6‡ÆÿdZpiîà@¨à¡Ìî½:Ú«Áã·VLóÇoùú @ÉÃÍ9€ü㪬¡žÓiê@I£š…z mÀ2|M ¬¡žÓëþ}zÚ¨fhX wÎJ ó›s.MN庬¡ž»çñ[mÆÔã›m%‹ù€÷|ߊ<·Òê þ‘b~ÐOï¾CrÙ²ŒwHõºí»ôøí÷Û322óqäÝ¿Èe›¬Ÿ–mûÜ·x¿€èq  ¸n«Áì·"":Î`pÌÙî䔽ÑÉÉÑÓÃMDŒF56îöÙs—Ξ»´õç_CêTß±u¥·gžŽ¬×ë\\ æí‰‰É"âà`ooÿï[c08Ý·lóžzFmC=F£P2Ü3¦—&yD_…ÂüÑ(:„z""=žn¿ií|K¶ìÜ¡MÖ–ªªÆÜ¸µnÖ1ãfœ8yfèˆ ëVÏÉÓ‘oÑ8áÆIó–G«=qåjø‚ÙxùÙ‡£×™÷ÔÓdL=~W(iè© ¯ø<¬¡^þ)Šâãí9tpƒÁiÐà÷¿ý~û;‰eʸ[!Þ=k{=­Sìít÷é ¥*ƬezܰĽj¸n«QÚÇÔ+Ú·‘ôôŒkaÅy^;“ƒÞµd$z|P2ÜÓá†K€¼á©}`Eõ ABB’iÁÍ­¬¶•3†ŠPòÐã@^ñyX%B½B°vÃ"âáîæïç­u-PªÝ3Q¡ ¨| PÞûÚ IDATpýPìõDD¾Ù¼ÍεZ¶Ÿ‹¾Ê}/£Ñz9lôØé§Î‘÷F¿žs¦ÅüÙêðû @‰Áì· ‚ë€BA`ʼn2îÊÌÌÌÖrßgK·nû5¨r 1Õ7o¥§ßsöµ}‡ ~© GœùDÜœ° Ì€U"Ôéսæµó-Ù2%%5üz”yK÷®í† y©u«¦<2 °êÈÛoŠè¼]›˜–Ë9UÕ¶¥¡^Þd…t™µv<{î’¿¿Ïƒ=ë2døGÙž vuu ð ®üÈ+ý{?Ýù);;}¶]êûö5ªéª¨;·b¬T¦¿Ÿ2e\ΟÚéëã•mmÜíxw¿"vÐËÓ]‹ˆÜÛš›s–ð6Ô«ç=DDUU£›c°Öå°V:žU¥¥ZW t!ÔË';;ýÔ‰#{öysÉÒuCßìW½Ze­+*NNŽžn"b4ª±q·Ïž»töÜ¥­?ÿR§úŽ­+}¼=Í7®ïÛG£25sçNâ¶dÁd­ ð fÑ)Œ àá¼ !Þ†­«È3nxò¯{×vÍšÔËÌÌ3n†ÖµšÎÚ„]ÜvqßõÐýI·NE]=0gæNNŽ'Nž:b‚ÖÕiOQ”/—o8~â­ pæcêÑO€ #ÔË?EQ¦O#"?lÙùÛž¿´.§ð)Šâãí9tpÿ¹³>‘o¿ß~çN¢ÖEiì…çžVUuøèÉÌv”L•Êu ñTÇk`Ï:ÅAër ¨êH«–»tj+"#ßj4º½•êо•ˆ¤§g\ ‹0o?|ôTÿ£ªÖyÊ3 Qû./Íÿ?öî;¬‰lð7 BïÝ‚(* X°­®]ìbYÝ]õ®]\+*ö‚]ìºv콡¢" X;bDzïÌýc4Æ€ˆDð÷>yîœ9çÌ7ÃsãÍ—S¶ì/üòòòÿÛvÐþ7GMÃFÕj·ê3`ìÃg$«i4d„µ¯øÞ’jؽïHFX{Áâ ’…­Ú d„µcãòó V­ÝaaÝQ¨YÏÒ¶óÆÿöqY¶üü‚Õëwյ餪kݼM¿‡ÏyG%‰¼Híoa×°¾ßµ€3žWJRŸˆ½øß¨ ;¨éÙ´nÿÇ̹n))i…«‰oeY÷½Ç›´ì£¬ÝÀº£Ó¤ùY%¼ÔVïÕPwB#݉ô&ñ‘Ô€ª kê•ÕÒ…SÏ_ô»ÿðɑ㞃ö¬èpÊEzz&w ¡¡Æ°,»aóÞi³–çåå+(È««©^ö¹yÙçæeß›G÷oPTˆ«9wî¼/U¯f”––áqî²Ç¹Ë‡Žž=z'ÔrnÜû°ˆcgrÝÑËWo'L]”•ýïØ!ƒ†N:sîcº-àn`ÀÝÀŒŒÌÑ#‰Û–0ò¯ÉÈÈr?Ù¡÷pg—e];µŠK°,»fƒû¬yn¹¹yD¤¨(¸éÿ¦ÿýÃÇÎؽºU‹ÆEÞÚ„)‹Žž8Ͻ}ò:8äQàó[~ÇJý¸ êÁH="¢“^r*…_ÚFE¤]¤4¨o1ô¯¾D4kÞêììöüó8|ìiijèr%g=}&M[¬  ¿kë²´¸ ˜°;/{7²­wÖÓgÛÎÃâ†g<¯œ;ï«¥©ñèι÷¯¯'DÞrÿ‚C—¶ÿ í_–UOÇÑW¯ßY·jÎû×ןܿо-]¹¥S÷aW¯ßÙ¸f~XðÇw=›6¶!¢e«¶æçˆÛ–0ò¯IÏÈèÒé·–ÍíÞ¾ Û¸e_ñ•ÿÛvÐÙeYnnžó¤aÁ7Òボmaßè}XD×^ÿ¼zý®p“n½Gœ=ï³nÕœÈÿˆwþs\œˆèöG¾Wo×#€ª I½ Š$*øvK¢…s'  ïÃ"ŠÌò”¥çŠ%‰BBçÏZáºlÍœ>†ËÄeffMtv%"÷m+þÚ_AAža óZ'oæóùËݶqÓˆèÎÝÇDÔß±«­µ%1 S¿žùùÓ;ûõéR–ÀX–½vùðÄñêW3ª_Ï|×ÖeD”’’ö.$ìÆ•#ãÇþ]ÍÄкAÝÿ-!¢÷a/^¾á–<ò¯IOÏdfõŠYDäºlSl\Â×j&§¤ÎšïFDÓ§ŒZµÌ¥š‰!ŸÏohcåsq¿­µezzæÌ¹n…[1 sÕûàÄñà ôŒ õ\çOnd[ˆ.x]-Õ£€ªéWŸ~»ií‚Mk”±fõjFÙÉÏKݳ¤ÐW×J^9O”uþ­K(¯€ÍÓU²ø½ºó÷^®°ó^~&f-‰H$bãóòò¹òÑ#MtÆ=qþ}XDC«þ}»J¶5­iò{û+¾·Þ…„Õµ0#"c#}" ¸˜••-*–=<Îô©£ÚX‰ßÖµ0Ó×Ó‰‰Ÿ=éA} q¹uƒºêêª))i‘1\yÉ#ÿn&r³&6þÑëà‘3ó­ÛºÑµÈš'O_JMMWQQšá‹ˆŒ)þ™À/#õ*1†x1/ã³Þ&e‡¥çÊ&é“Ëeôz÷èèwéàÖ®òòSÀ×oÞ#¢vm›žB[Ë´½}ƽíÛ»³¡Þã v-zíÚs¼ðôäÒáñ¤¯«§§]t¹®6ÅÄÆoä_ÃÒÇMo—¹: …Š;Ü=yIDd¸ó¼Eëºuý]UEE2©Ç]+$4¼pÃÌ̬¨èX"22Ò+{ð ÂôÛÊM<WVÓo%1 ³bÉ ":ëésíÆ]qy«‰èêõ€ïÍÄ5¨oáyjg-Ójéé™ÜòvDÄ푘,U9==£,Á©Ô‘ÍŸôlܨÁ£ÇÏOŸõVSS)|­;÷“SR¥Z]ö¹Å´°o$“0àWƒ¤^åÆç•cRˆ~kÕ¤»C;"rvY&‰¸BÇ>]TT”BBÃW¯ßY|óè˜8n»X1yy9ÓšÕˆ(3óã 6n¼Þ­Û_l±héFÉ4¢¬”<òâñxëÜæÑ|×õÊJ_,«×¯o¥ÔÔt·µ_\+''wÑÒDÔ£[;n€ï…¤^åÆÔ“õšzbKNeæþÃ'GŽ{r%ÚZ‹çO!¢YóVO™¾$6.ˆX–}òa¢³ë¯«\µ¼¼|Ç?œ¬v>qÚ‹Kí±,{êÌ%¿k|>¿uË&\µ.~#¢=ûO=q>##+<"zò´%ó]×sÛtÈV #ÿ.-›Û ptxúìõ£ÇÏ%˵4?^kÉŠÿfÎu‹ˆŒ‰DAO^vì6ôaà3%%ár×é2¸%ø%aM½ÊM<ýVT>#õˆ¨A}‹¡õݳÿä¬y«ûöꬨ( ¢ NC£câ—»m]»q÷Ú»õõt223¹Ì]BB2· FNNnC[«€»ýgƼŽizz·ÿìòÅÓj›Õàú5üuwÇÅ'þñ÷Ä7Åç»o[žœ’6eú™ßNI"ÿ^+–L?ãy%''·ðµ²sræ.\»Ümër·­ŠŠ‚ìì"2168°{•eí2ß ü¢0R¯r+×5õÄÎ((¼‹Ø¸eWÂ0Ì2W盾GÿÚßÖÚ2-=ÃÄØ°_Ÿ.Ƕîwwãꨨ(mZ»àÁí3Ãþv¬^Í($ôŸÏïÚ¹¯×SG‹;×ÑÖ¼wëtï õÔÔTÚµm~ùüÞÿ é§¡®Z÷R’È¿WÍ&S'/òZ3¦Ž¸~òïÁ½­,kËÉñ[Ø7š6yä“Ú´nZ¶û€_3}«wTMÇb|·  |¯S¯ÇÇeÃðFÙ\¬èp~^'ü×Þ ö’,qéë/TP«¨x ŠÉ/Èq=nÇ›èÛ ê´§BÃ%QTŠK, ä4t”WtDPò÷ˆ;^6ò¦ßVn<æã_eE,+b˜:ôòvÄ6–DDŒ²¼Ž^¿yi™ˆH¿‘qƒˆ!"sþ³ŠŽ*%–Ý~?‰;ÖVnØÖl_ÅÆ¿$õ*7ñô["*`óäÁ¼úÓø³"6Ÿˆt„fHê@eŸýäEâAîØX¹%’zPY`M½ÊM*©W‘TF,+’xÇTXPÉ1ø€#õ*7žDR¯ü6À¨,ž%ìÎ*H bøŒ ¡îøŠ ¼ ©W¹Yëõ­£õ;‘ç3ò |å~}öÓ~•€ŸÂ›䜷D$ÇSBRJ†ýv€ïÂâƒ~$õ*7#›Šà'Â~úrŽ)0PB’ß¼Pi`M=¨BX$õà—€¤”Þç1øY~,}ZðŸKPR_ŒÕ«°(¾’zP%á›9”>: Ôð?’zPu`M=ø~XÏ*%$õ@&ðå~Ø•¾+‘ÔÃï ,~-€I=(ìÔ?–ý¸¦¾™@©à£* $õà ÷ýñ÷Äzº5ë™¶èá8êè‰ó"‘èÛ-+¹’ÜxZZ#¬]ß®k©¯Rö ¤°Q”~¤€Ê I=ølꌥM[õ=zâüóo²³s¢¢c=/øþñ÷ÄmûGDÆTtt娄7ž”œRÆ •½ø¬©ßKrú-@¥¤^”ŸZŠ%Ÿwï;±fƒ;õç}è÷7}®[5§š‰á{×np/ܤjü®]òOJ*sR¯Ì=@ñX¬©¿¹Šd/ r{dú“z:=êjwðUKØjçîcD4zÄ ÿÖ/äJôõtZ6·ûghÿíîGþ;¤¼Â­h%¿ñ¤äÔ2^«ì=À·ˆGêUµ_­†îãçã:ßõïÁWt,UÊ?Rbæ>”>?à‡«jßy ;?õMòµ´Üè€ÈžýyíÃÚø¬·ßlŲì£Çω¨cû–R§TU•§N®  /UþàÑÓ=‹bæ ›Ú9dј{›¶ìÿÚÒ{¡ïÃÇMœß¬µ£²vãZ-†™)9§Uà!#¬}Å÷–T«î}G2ÂÚ o,lÕn #¬Ÿ”••í2g•q­Œ°ö¾ƒ§%£:bšyƒÚF;uVLTßuãGŽ{2ÂÚ¿wþ“ˆž=f„µ¹—$¢¸øÄÅË7Ûÿæ¨mÔXËЮƒÃÃÇÎIööÍJ<&Þ(£Š‰=täPLLÌ®=»*:€ªG2­‡/å UcRüìÔ«j^&^,årÇù¢œ— ^'_;<åmòU›ÿµV ÃÔ¬aLD>ýæ%X–]¿iOó6ý.¦%FçóxÌãÛñÿNYØgàØìì©Ê;Ü6hì°eûÁ»÷‹D¢È¨X÷½ÇëÛu zò²Ô÷—Ø«ÿ˜«·EFÅQƒú’Qí;xú}XŸÏ»ìsókQ}ï«(+™Õª®«£EDòòrfµªs/55–e-ÝX˲íÜ…kïÜ{œ™••”œâãç?xèäEK7–¤‡Rð“˜úÔ0¯¡i iÓÄf舡ƒ—$’!MniþvLó·CšÜ.&’ŸVZzšPChgo'U®§§7vÔØÚfµ'Œ›P!ÀÏI½ªFKÑTM`$UñìJ貃Ïÿ¾½?3/±È†ûu#¢•kv¬Û´;''·˜Kœõô™4m±‚‚üÙzë|LW^¨¹ñL›F¶õÎzúlÛyX²æÞ§F9ÍNOÏìÝ£ã“û2ž„¿½5mòH»†õ­,ë”úgÍsó½z{þì //ù_=^ϲŽdT»¶.K‹ Š »óò±w‘Q•âÆ»;´{óÌwåÒDd^ÇôÍ3_î5ÀÑa˜·ï”„Â5+g?¹!=>(1êÁ´É#‰hÉŠÿ¢¢c¿ÙCY‚øyðxˆ>ð(戩F«ú:= ”ëI6œ9m¬ÀCï+7'O[²f½û´É#‡üÙG]]zI¾Ì̬‰Î®Dä¾m…íïçä*š©w;lT§~ûånÛÆŽú“›²ššš>eúR"<°ç~w7GDÆFú+—Î(((àóù¥¾Gs—·lX4fäà"£âÒdDda^ëÄáÍRQVÂ/Æš•³7¯[¨¢¢Ä½ÕÔP_±dú…KWŸ=>|ÌsÊ„Šo^–à~=»÷<¼O9è›þ7;ÒªE«¹³æ6jØHEY%"2bÊô)g=ÏN˜2¡C»ÕLª߃måÑK Täk{—=ž,)9©¢Cøå˜ªuÕÔáæÊ©)˜Vt8Py1v&‹*:øµ`¤^Õd \¯C™Zíolð·’¼–ä)›ÿ6éê™à)‡ž‰J—+(ÈŸ?½kÅ’éZš£&L]dlÖbÌ¿sß…|l~ôÄù÷a m¬ú÷íj®Õ‘{UWkjZÓä÷6öÑ1qïB¸š'=¼“’…K¦s=±²dôˆ¨‘m½Ñ#¾˜F'•dyᨠ+áC[KCœÑã0 Óö·fDúíNÊ<@ÕÓ­K·;7ï\ò¼ô[«ßT”UˆÈØÈxÏÎ=êjêùùùþ·ýKÜS¥nSÌH=('ÚŠVfê=ÍÔ{™©÷ÊiWt8%…¤^U¦$¯egðןVû;Ôœ)5.ˆÒrcòE_¬×&'ÇŸ>eTXðm›[7¨›‘‘µmça ëó]׋wl¸~óµkÛœ)´=\-ÓjDôöÝÇ Ôµw‰¨YcÙÞ× =¤®^ò¨ŠT’/‰Ì̬[·lÙ~pÜÄù¼®Qxxô7[•1x€ª§¾U}©_„ŠB###"JIM)c牉‰F¦FB á¡#‡$Ë>z(Ôjh…G„‹ ߇½Ÿ8ubëö­µ µkÕ­5fü˜È¨H©>1fD»F¦FÝûtß²}‹ÔçF».í„ÂèèèŒÌŒ%Ë—Ø4±ÑÐרS¯ÎÄ©cb>ïtüäq¡†°s÷ÎDôüåsñR€âIÇ\?›¶l*|SAOƒFÕ¸yc=½ö]ÚÏ]8·ÈÅõDzìÞ{[þÞRÛPÛº±õ$çI™ß÷ ¢aúmÕÇcäÌ4Úši´MÈzû4þì›$?.—§.06Qk\¸¾²²pÔð?Fþ3ÐûÊM—9+ƒ^,Zº1++›[ŽÛ¸võú]«×½cLl~>>~>¾~¾ûwï—ZÂïÔ™S›·n~òŽa–eÃ#·ïÚ~ÆóŒÏE³ZfD¤¬¬\Ë´VjZj||¼¼¼¼x–±šªZ17˲ì†Íæ-š—››ËÅéàïàìıÝ;v·°oQ¸I؇°)3¦œ8u‚{ü&8øMp`P ß%¿Â?-ÀO I½_ˆ¶Ð¬MµÉöF#^&\zïYO§G1«A3 Ó¹cëŽí[Θ½ÒmÝÎ5Ü'8 516`Y–ˆl¬-ë[™Ù°Þ§rn¬ÊùŠXò¨¾ék7^L“M[ös‹âuëÚvøÐ­Z6ÖÖÒX°xÃÂ%~pðUO^^Þ¹óçfÏŸ-‰œÆ8qÙ´â©ÈÕÑèWL…†þã¾×=ðqຠëf»Ì&¢·n\ñ½bldŸï}Å{Ü„q1113çÌk: ì?Ð}›;7ØÈÐh颥â}~2³2g8ѶÍÛû8r=›×1?¼ïpýFõÝÖºúg”‚‚‚8€V-ZÞwXGG‡{; ß¡’pÀàç.œ{ùêe]‹º¥xD)))óÍ'¢)§,Y¸„+´±¶¹xæb›Žm‚žÍ]8÷è£R­†ñ>ïÝØîãHíù³ç{y{>ôòöBR Ášz¿.>£ ù6;;§Èj òŠŠ"ÊËÏ#¢V-ÑÕëßLõ°oDDwîÆÆ%SMG[“ˆ¥×†OOÿŽžJUa%¼qú´¿GAÁ«eò¸Ä²l§­K’Ñ+²‡²ðS)(„ˆZ:oÞ¼ ÉÎÎ&"•üüü‚‚YEÒ´IÓ¡ ÍÊΚ·hÞeŸË·nÛ7³ïïØŸ;ëqÖ#))I ,Y¸äkûüœ8u"ìC˜µMßÞ}%+Ô¬Q³Më6111!¡!’å½zôgô8¸©¾—._*á}I9}ötjZªŠ²Šó$gÉrEEÅ™Ófѹóç¤?'9‹3zœV-ZQáåàg†¤½¨aþÛš î…÷…8}örzz&5iRˆûtQQQ _½~gñ}öëÛE PÈÈÈšïº^êëtjjºøØÐ@ˆnÝþb¢Ù¢¥¹}6J¨äQI)É7oÖ+1Ð×!¢è˜8ÉÌ—TSýbXPffÖ½ATH‘=”:x€ŸJïž½³’³¤^cG-u‡ûwïôÒ×ËwÊÄ)±±±SgLí;°/—ã“I$®ó]ÕÕÔ94aÊ"r[æ&^.àÆÍDÔÄ®‰±‘ñ×®róÖM"jû[Û‹ ˜Ö4%¢w!ÏçÛZÛQ؇Rn†sËÿ5mÒTSSSêT§ŽˆˆeYÿ;ÒûK¥)‰HOWˆbccKTL¿"¢É3ÅÆ%L±tåš­Võkéék+(Ègdd…¾‹zLD¦uô]]Tôx ¿¾uíÿ ™sÝ÷°±5 D”–šñôÉ[“jzÕªž©Z¿Ùƒû/¶î8äsí¦m# uu•ŒŒ¬w‘ï¿èÖ£•¶ŽeåeÑ÷£¯C‚»tj3¨oïÕëv­Û´Û¼֫×ßøJ,¦­¥±xþ”IÓÏš·:66ÁeÚ=]m–eCBÃ×oÞÓ¹Ck‡.m‹lxàwã'O{9ù«y³FªááÑ'=.­Z»ƒˆþ7¤—v$"+Ë:</99uû®#cFÎÊÊÎÎɱnP—ˆÎž¿âð°…}£ì윛þ÷'L]ôâåÛ—+²‡RPµ ‚ÕkÔ¨^£¹}s§1N-Ú¶¸ìsyã§M™&“þuuu§Nš:oѼ÷aïÿüãO»FvâSQÑQDT§vbšsãÚÖoZ¿~Óú"+ÄÆ};G¦§§GDïß¿ÿ®ÈŸ8¹¢%¡’¾¾~LLLTTÔ7û‘——§Oë{@e°b3 IDAT¤µlÕ0&.îõ˰˜˜Ä˜˜D©³ºzuke$ó2(ˆ´õTÍÌMÞ¾ôæiÐ@¾ @”Ÿ_@DÉ)©r‚Ïc@ô5«Ç„…F¿ ~Æç󸙧òòráѹ¹D¤©£¢ ÏÍÉó½rÏ÷ʽéÓÝø|¾û¶åÉ)iS¦/)ù-Lp¿ÜmëÚ»×nÜ­¯§“‘™É µKHHþZ^lÕ2}}‹7ø<ôx(u¶sÇÖ›×-¿56Ò4 ÇÁ#gÆMœ?{þšôŒŒ‰NÃ/˜²bõ¶§Ï^·ü}€‘¡^BbrNNnÓÆ6×ÌÿwÊB©‹ìaÕ2—Òðë024š;sîøIãwîÞ)«¤žH$ºpéw˲¬xÌ]IöùáR`Öõ­­¬¬Š¬`U·èrIiéiDÄ/´£w Ÿ†ãâGª ªBR>ªUÇØ¨šnxXlLTbffv~^’²@EE©zM}]}é‰]u­jèëk~‹MINÏHÏ* TU•Œ«ééjIVc¦­™¡VDx\jrFffކ¦Š†¦jmsâÇýä[µ±yþ$$9)e©es»9.N¿·±ß½ïÄwÅÏ0Ì2Wçî¿»ï=ñðÑÓ×oB«W3ªoUç¯A½{vo_L«i“GþùG¯=ûOžõ¼ò.äCjZz-ÓjuÍÍFþ3°K§ß¤¾ÕïÚºL_Oû¼×ÕˆÈè&vÖ&Æ‚¯×ÙóW_º|#.>Ѫnía;Žý×ëà"¯X¸‡RðK±®oMDaÂ223”•”ËÞá¡£‡îtïÚ=èiÐeŸË§Ïœ¯ŽÇ  +~þ¬ÙÚØnÛ¼­Ô1„¾%"#C£Ò5çbà:‘’™•]–Îà'‡¤|¦¨¨PÛÜÄÒÚ¨ÐðéõæˆHßDEßDzÉ"k×T7®©þµš,KD»fu‰ÈÎÖzጩ\ùÿ†ôûß~RmnúJoã(¥es»–Í튯S˜‘¡Þ¬écgMÿöâ_Âê³V¯˜%Y¨«£µ}³ô B+ËÚlÖ›öÀ)]ðUŒäˆ9IÑ1ÑD¤®¦.T–ý*)©)³æÍ’““[¾dùÃG‡ âìâܱCGUU"²ojôøÑ{÷ïÅÅÅéêêÙC û‡Žº~óz^^7}õ{EGG?zÌ]N\Èçñ‰¨@T¢-A¸îÝ¿—’’¢®þÅǬŸw Ù9T%Hê´câä?nºV^6Ïk½Þ»üä¦Ïœn``0eâÉÔ˲»÷í&¢†¶ ïóP ‹—-Ž‹‹;j¬Y-³Z¦µ6mÝt÷ÞÝEK­Z¶Šˆúöêë2Ç%#3Ãu™ëúÕë%#IMKUSU#¢>=û¸Ìv }º~ÓzçÉÎ_½Ò'‰IÒ+¬X½"77·šIµž=zŠ õõõ‰(&&¦  @¼Óî×ôíÕ×e¶KjZêÚkÌY .ÏÉÉYºb)uëÒíkII¨ì°û-ü,"£"·»oŸ³`ÎÀ?Þp¿  €eÙÐFÿsñÒE†af8Ï(ûUž½x¶eûe•™ÓfÃ0kV¬aæ¿mÿ= ""==½éS¦Ñ÷#ÇŽ ~̲ldT䦭›,ê[pÃë´´´æÏODóÍ›>kz\\qÑ:»8{y{I]tÙÊe#ÆŒxüšeÙˆÈgç­;¶Ñ¢y‹$ÇZÖµäñxÉ)É»öìbY63+3))ék7¢©©ÉŰÂmÅÜ…s#£"E"Ñ“gOºõîø8PI¨äºÀµì ~NHê€ xœõPÑV)ü22•^Óík57mÝddhtúØiƒsεnßZ]O]ÇHÇÊÖêȱ#|>™ë²¶¿µ-c$,ËNvž\PP0yÂdñ(6»FvCÿ*‰þò/·KÆ ç#þ7‚ˆ9hÝØZÛPÛÌÒlšË4b("2‚kå4ÚÉy²3˲ÿÛX½Nõæ5ôLô¬l­6oÝ|ô„ôZÍš6;vò˜MmCíÚVµ7oÝLD.Ó\ô YÍÈЈ+™8u¢‘©‘Auƒ•kVs³N£/X,//ï¶ÖÍÌÒLÛH»i˦·nß262ö8áaY×ò› *)$õ@6 Š"*(b©Í"kKDÔ®m»À»«–­jnß\[[[ÄŠêYÖüÇà·L?±ì‘œ8uâÆ­ºººÆOl²hÞ" u»÷îró|ù|þ†5Μ83hà «ºV<Ï®‘ݸÑãï:tqàš0 ã:ßÕ×Ëwè_C­X§§¥÷éÕçØ¡cîÛÜ¥BøÁ–u-åøröÍì'O˜üàöƒÖ-[—ðq@eÄLßjÆUÓ±ßmCÅFeÎ’•OŸqÇ]'ÅTÔšz’eÈÖ ÿµ÷‚¿˜éÒ×_¨ VQñÀ¯£]—v·n»-wsãTѱ@9Ê/Èq=þqÓ3}»AöTh8Pò÷ˆ;^6òFê”;–ýq?–À¯»ß”Upü~"–ˆrÚÕ5ºUt8Põ!©¿®WIG#Òo1ÔD†ª¼IEG•UPä*.©§©TI=øÔ€_WRΫé~ܱÎ8’¯ØpJ kêÀ¯KrÉK¦ã€ÊÁ§üX©UK¢«áSbˆuA­†ºã+:"""_/ߊJ_È Ò@Rª–…¥]áŽõòÒϑԀŸ6§Yî÷ðC`ú-Tsèü%"ùÍSç Áw¨"XUtPÉ1Hê@¥¤TIøf%„YrP)!©UÄ—[X"©%ôå\€JI=¨2ðÍÊ¿@™à#~,$õ ÒhÖª™PC8oѼ¯œgÏ»'iþvňFÖ c¥¥§ 5„vöv²í*‹é· {ø`€I=¨4ztïAD^—¼Š<Ë’èÉÍ "²m£,óßÊ“““eÛ!ü4ðÝ*%$õ ÒèÙ­'=yöäCø‡ÂgcââB_ä‘me™Ï¡KJN’m‡e¤T ê7¨Q½]¼t±ðÙË—¯‘AMýêò©%õÅ@=,ˆ•’zPi0 Ó£[úJRï’÷e"²ýM™ˆæã?p3¢]#S£î}ºoÙ¾E$Ùùû°÷§Nlݾµ¶¡v­ºµÆŒIDÇOj;wïLDÏ_>j¹×î}»%›= 5nTãæõLôÚwi?wáܔԩK´ëÒN¨!LHHÈÊΚ³`N­ºµ„ƒG–ñ±€¬`£ ¨Dä*:€ïЫG¯M[6]½~53+SI¨$.ÏËËóõ»JD¶m•¹–e7oÛ>^^^¾šI5®‰šªšøB6o˜·h^nn.×Ü?Àß?Àÿ؉c»wìnaßBêââãœG8ûøùpoë[Õ—õC€ï€2@vðÃüP©•‰}S{mmíììl¿k~’åþþiiiºr5,DDÄx^ôœæ2MA^a릭qáqaÁaï=¶µ±õ¼è¹sÏNɶpšè”ž‘Þ£[û·ï'D&¼}ñvò„É mZZX:tqxöèÙÒEK‰¨ŽYgžq/Ç>Ž\óm;·¹ÌqÉÍÍôï¤àgÁññ×ì›Ù‡}ëåØëuðk©[˜·hÞÕëWg»Ì¼xÕûªe]Ër{ZPI=Yoœ ¿&üZ?’zP™ÈÉÉuïÚˆ.z}1—›kÛF™›w››]à<Ùˆ¶mÞ6ô¯¡ Ø×1?¼ï0ŸÏw[ëÆª#¢Ô´Ô鳦ÑÀþì?RϲÇ324Zºhé¹Sçää¾1¤=%%eþ¢ùD4eâ”e®ËLŒMø|¾µÍÅ3­X§g¤Ï]8WªÉ¹óçÖ®Z;ÇeŽ…¹E³¦Ídñ`@0ý*$õ ’éѽ]ðºÀ²Ÿ÷òö""›ß>ν½áö!ÌÆÚ¦oï¾’mkÖ¨Ù¦u›˜˜˜Ð®Äã¬GRR’@ X²p ÷Å?‹|>ÿ›Áœ>{:5-UEYÅy’³d¹¢¢âÌi3‰èÜùs ’§lmlGüoD‰oÊÔ€lXé;YŒ·2o¦ýGEÇ¿¬©•L»¶í”•”£¢£‚žÙXÛQHhȫׯÔÕÕÌ~\)ïéý"jû[[¦Ðd:Óš¦Dô.ä…¹ݸyƒˆšØ5162.E0·üoQÓ&M555¥NuêØ‰ˆX–õ¿ãßᇸ|`¿…£€Šb­3ºŽF?""b•ä *8¨Ìêê¬èàׂ‘zPÉ…;t¤O£óÄ;uàË}L–%ÄfÑúMëśՊ_»öì"¢Ø¸X®fTtÕ©]§tÁp͹D¡%¡’¾¾>EEEI–sJ/üHj 5õ•ìô•ìô•Ëñ¿Ýàç€ïPùôìÖÓ㬇×e¯Î3ˆèÒåKDäàÐ)›KV³®omeeUdVu?–‹D""*õÐ9É)À…qÝ_ Ô€Ê§kç®rrrwïÝMLLT*^»qM tíØ3“©Ë±WLÜQ„­í¶ÍÛŠïJOOˆÞ…¼+]$Dú>´ð©Ì¬Ìèèh"224*]ç_ƒé·PùhhhüÖê7‘HtÅ÷Êõ׳³³;üÞAMEÓ@¹™¡r3Ceû¶-»Ñõ›×óòòŠïʾ©=Ý»/..®˜j|Ÿˆ DRå-ì[pÍSRR¤NùøùH^@†Ô€J©g÷žDtÑû"· ^Ï=%ÏöéÙGEY%ô}èúMë‹ï§o¯¾ #3Ãu™«Ô<ÙÔ´Tñ1·:^LLLAATse•Ô´Ôµ×J–çää,]±”ˆºu馫«[Š(’zP)õèÖƒˆ¼¯xŸ¿xžÇã9tv<«¥¥5î|"š·hÞôYÓ¹Qx,ˆ„†8»8‹wØ "==½éS¦Ñ÷#ÇŽ ~̲ldT䦭›,ê[<ú¸HŸe]K—œ’¼kÏ.–e3³2“’’ˆHSS“»Ð ·sÎŒŠ‰DOž=éÖ»[àã@%¡’ë×ôDàW‚¤TJF†Fí'&&†G„·lÞRGGGª‚Óh'çÉÎ,Ënüocõ:Õk˜×Ð3ѳ²µÚ¼uóÑG%kÎpž1â#ˆèà‘ƒÖ­µ µÍ,ͦ¹L#†""#Ä—ÐoMœ:ÑÈÔÈ ºÁÊ5+ÅZ¼`±¼¼¼ÛZ73K3m#í¦-›Þº}ËØÈØã„‡e]ËrðëAR*«žÝ>N¹å¦âJaÆu¾«¯—ïп†Z7°NOK766îӫϱCÇÜ·¹KÖäóùÖl8sâÌ ƒ¬êZñx<»FvãF ¼èÐåóÀ­·Npš`^Çvò‚d¹H$2¨aÏÚ´e¿TçW¯ßŸ/Y³[—nÛ6o+܃‚@Aòíèñ£ïÞ»«®¦>súÌ^=z%''ß}p÷ðÑÃOž>)K¨¦5M½.yefe* •¸’S§†©Q½FèûP©Ê%ŒVlØßü¯xoüo#’z? $õ * }~êÌ%":ྺ»C;®P_O§g÷ö=»·ûY¸‰cï.«Öî¸péZ¿>]ˆH$òðnÞ¬!Ã0’I½ûŸ¬Û´‡ˆ–.šêâ<†+Ôh9öîâØ»ËÛwae~çîcDôGÿî…O …ŠB¡báre%%mM©ÂR<"âñx\–MQQиQƒƒ{Öäææž8íuÒãRLl¼¾žô6£%§©©^8H)**J**J’%ÊJÂbZ)* êêªæµþèß½ƒÃßwGŽ›üÔG*õö½¢¢"Y˜[LŸ:]KKëßÉÿ¾zýêÆ­mk+YS^A^[[»øÞÞ‡½?sî ¹owo¿ §§×½k÷î]»ÿP–P{÷ì½vÃÚKÞ—úôêCD"‘ÈãœG³¦Í†)œÔ+I´’ºt¢êwÍïCø‡j&ÕÊ'ÈÖÔƒªìaà3"RV:ti[ølõjF… {tk§¨(8þiY½·îGÇÄõwì*UmÃæ½"‘ȬVõi“GîĬVõ2Fž˜|ô÷*ÅC(’Ó˜¿‰ˆeÙŸ–1¤r¥¬,\¿z.…„†_¼tM¶÷éÙ‡;xú¬4!ðq )+)wéÔ¥ðÙ2&˺uí¦¨¨xÒãã²z·nߊ‰‰qìíX|«* º:ˆD¢‡ȤC(#$õ *ËËË'¢Üܼ‚Q ›¨ªªtêÐê¼—_VV6;yžaÇÞ_¤`D"‘ǹËD4°_·2û¿kyyùµL«èë–±«R<„"‰Óe߆¢¼5mlcbl@DdÔ““ÿ8º9??¿Íóòòˆ(7/·  @–a‘ªŠj‡ß;x]òÊÊÎ"¢“§O2 Ó»goYõß¼Ys"ºâ{EV@Y ©U™uýºD”——?ßu˲%lÕ¯O׌Œ¬‹Þ׸¹·M31”¬ðêuHZZ5kb+ó˜9·üQ;ë²wUº‡P˜x¢®†ºZÙ£*oÖ êÑ£À2í;Q˜¯ßÇMEÌÌÌJѼ~½úD”——çºÌµ,‹¯éÓ«OFf†÷eonîmc»Æ&Æ&²êÜ®¡=xô '§ô› €¬ ©U™e]³>=;ѲU[-m;ÏY°æÒå©©éÅ·êÙ­½‚‚üñ“?ͽuªúqí3Óš2˘H¹{ÿ1}ÊL•QéBaÿmû8ïÒ®Qý²ÄS­v+FX[êåy¡¸xKsC"ŠˆŒ‘Io,ËFEGí?´ÂÔ DT£zNí;IÕñ8ë!Ô~?y\\§®EÝžÝ{Ѫ5«l›Ú.X¼à²ÏåÔ´T™IDݺ)((œô8ù͹·%‰VJƒú ˆ('''èI¬€RÃFPÅؽzÂÔE»÷|õúÝ’ÿ‘œ¿ýï-œ'èЮe‘MÔÕU;¶oåyÑ—Û—Û1CRJjw ¢¢\NaGEÇ‘®Ž–Lz+ÅC‰DÙÙ9D”››ü6tÝÆÝÇO]$¢>=;•}Fð $T$¢Ô´ïÎ]J1¨a Ubld|xßa@PdýoÚ½c÷ÔéS÷Ü÷:øõ ·D$''÷{›ß'ý;©]ÛveŒV]M½ýïí/z]ä6ÀåvÌ@ ª¢š–ž-ÃnªŒ È•"6Ÿˆ„òúzÃ+:¨úÔƒ*NII¸s˲Ù3œŽ<ïãwûö‡éé™—.߸tù†ó¤«–¹Ùª_Ÿ.ç/úíÙ²q£5ªÿà˜‰(>!‰ˆ45ÕeÒ[)Âé³ÞBÍzR…õ¬êlÛ¼¸ŒÁÝ;oh¨'U¨®¦ZÆn¥0 #Û9ãÇŽ_8o!—2“Ò½k÷[w.WRú¢²’PiËÆ-3œgœ<}Òïšß»wÒ3Ò/û\¾ìsyÒ¿“–¹.+c„}zõ¹xéâþCû5lT½ÚW7l)a´R444ÒÒÓââË$ÀOånÌòèŒ;D 1L§ê;ùߨ¢àkÞ&±¹D¤®h¤ü˜~ ¿Óš&3¦ŽööÜ“õèª÷¡NZ‘Ûºgνê¯äååD"Q‘›Ïª©ªpééåpNN. dØç÷>ÇÓÔPoÕ¢ñš•³ïÝ<]öÁƒššê:ÚšR/yyÿÀ‘™E©R{ÿú}RtRôûès§Î™×1ß´eÓº 늬)'/§^yyù•kÖ¨9uÒTÏÓžQÏ{wh׈Öm\wî¹öµ¬e‡òòò"‘¨ø}o¿+Z1EEE"ÊÊÊ*a•BF^dRNpRÎë¤ìW,[š}*’zðk‘“ã·iÝôâ÷fMlˆÈ}_Ñ+ˆij¨/sæ4æ¯?úw/|Ö´f5î $4¼œâÔÒÔ ¢ä™­¶&©$Á±w6ë ›õ¦ ãubÔƒ>G&ÿû?¡P±<â)áÑDdThHà÷ŠŠŠêêêÚuð8î!T.^¾Ø?À_1ÉÉɵnÙú̉3M7!¢}û÷qå<Þ7>œ¿¶í²†††ë|×1#Çôwì/« Å’’“ˆH[K[æ=T –d¿süš*—É"_ƒ¤üŠx<^Ÿ^ˆèupè×êL8|ÓÚÕ«>eanª¬,¤OÛY”M"JLL.§þ©d¡ò zò’ˆÚJÏ . Óš¦NcX–9w¦ »%"׫{/" ~Ì•ˆ§ÁÞ$·  €> š+ÒÄñ×®Z[ͤšlƒ$¢ääd"ÒÖþy“z)9ïŸß³[":zâ<—a‘¹ºæµˆ(ä}yä”å!üÌî=úED];µ‘mÏÆMwïݽìsY¶=çää‘ÿã4dmî #CzŠ7W"®ðÄG„ççç‘…¹Å¾tÉå³Y Ù/²Ÿ'd?KÏ‹¬èp 2BRdC€àG@Rª²ø„$¿k…˳³sNœö""K ³Òõ<Ái(Ã0oÞ¾_½~Wá³ïB>”®[±–-ìˆèþƒ'eì‡Êó!üœ23³&O[BD5ª;ti+ÛÎuuu8 "nãÚï•píÆµÂåÙÙÙ§Ïœ&" ‹ù2Óš¦ÊJÊDtõúUÉšééwïß%"+K«RP> "c“ò(+’sè0ÿJ ß½ RBRª²ääÔv]þjÓqÐî}'Þ¾ ËÉÉ‹Oô¾r³ƒÃ'O_ÑðaJ׳}SÛq£ÿ$"—9«ÆO^ðüÅ›Üܼ„Ä䳞>í»þ½fC™¾ïÒªEc"zôøyÙG–ßC(?éé™ñ IÜ‹+ÉÈÌ—ž‘š“ššü&Ô}ïñ&­úܺÃìí€ IDATý€ÇãíøoIy B?n<ݺ}ë¦ÿMÉò¼Ü¼„¢$%%‰ë$§$wéÑ¥£CÇ}÷½ y—““Å÷ŠCo‡§ÏŸѰ¿‡q5åååÿüÍ™?g÷¾Ý‰‰‰999õÐ799YYI™Ë-–ZI¢•òàÑ"jÔÄ<§ ¥,—._¬Hâ ’zP"ø=*)ï8 ðSá6¸~óÞõ›÷ ŸãâÔ¹cëRw¾Þmnfföî}'6o=°yëÉS–uË:öÍ®aýÚf5Þ¼}ïw- C»–eéª\B9óï܃GÎH–8»,svYÆÇ…ßÓÑÖŸ*((j~±vžššÊîí+:¶oU±Y×·nݲõ[7–¯ZîyÚS\~Þ뼉™IáúZZZï"¸cîoqÓÿ¦TBã2Í¥cûŽâ·‹.~øðÞý{ã&Œ7aœ¸\QQÑ}»»–V™¶!.I´R.z]$¢Z­Ã·©¥ÞÃZ{”ªÂO7dO2Ýûµ ‚ª$õ *3­iòò±÷‘ãž~×^¼|›˜”,''gl¤ß¾ÑèƒZ6·+Kç|>ß}ÛòÁ{ìp?êð06.A P°´¨Ý³{ûÑ#•1r†aþÚÖ<·#Ç=˘Ô+ׇðóPP×ÒÔ°¬kÖ±}«Ñ#þà¶.'ÿŽû÷Æ­>~>÷Üol׸ä kÖ¨ùøÞãã'_»qíåë—IIIrrrF†FöÍìG Ñܾ¹deeŸ‹>;Üw9~äåË—Ù9Ù††íÚ¶›O gIô>Íûì;G¿ð‰‰Ù/*(X X JPi`£ €ŸZŸžúôìTÑQÀ/mø°á… Uäì æ5Ðõ4aWpò©6çÓ6,Í',Í·šJkÝ1:Šõd¨ôÅH=üjU’zPŠV%¬¹|ñ´IãÿW®Á|“¢†•HT úrÁµõª̵xÁâñcÇÿÀÐ*7eyƒf³èŒ|šàþ:é¸djïCúÕéWUZÛèŒÕZÿ˜xX’üc¸ ”Ëbæ>TJHê@id'?¯è¾Cvòsì~[~”äôšê»4Ðñ4Áýuò±|Q¶øTDúˆôFÊ-ltÇê –{(_|3(|x@Yà3~(ÌNÊé4ÑŸîhæ]_û9ž’ä©È ÿ‹¡{‡ ɼ_®1|¹Ïþ_5”6©€J I=E9-;½)ýj_j =Bž§,y**ãŽ×ûa^ï‡EgÜ)·ëKŒÔcð”DR{ì€,°øµ~L¿ð5éMª§ý¿ç‰û^&Ì¥‹OÅdÞ¿6\O©‘ÎX#åæ²½.ÖÔ€ dg²ˆe ˆHž¯ZѱÀ/I=(¾zCÝëi {‘tàyâþÜ‚Tñ©ØÌ‡—ÃFê ­mtÆ«´’Ý5%GRJ¤µñÊQ÷"ÿåêߥšF׊~-˜åH¯j£3Ö±¶wCÝ| ÉSqYAW>Œ9òGxú5™¬iÅb£ ø~Š|MeyeyCeyCÿß*ŒÔ€*Ž%–X–ˆý¸PCDÄŠ¾¨“+JgÙ<_C2”•'bó•å %k¦å†±$bYK,ûñ?YѧWE,±ÄŠX""–%±\ÒW²“ì'*#€ˆ •í%â}Hóã3É‘klîûÔË»â.ññÒŸ.ññÒ\«‘8Éñÿ0¿%.aÙ¿ð‰*òÆŽµ/‰ óE7"g|ïåˆHU¡ºdR/O”ù(n£¶¢Õ—I½Ô' ; ”šJf$¼H)þP wÓo¤\¸špÌ‚3fèSL¼›™©O3-LÍH¸k˜{ØôÀ´Ì|§ØDÌg*¢Hã?¹óïP1)²hd–jÞ¶¢(fË¢ÝmÙ¬¦Å£Hshü> ±å†çËÒûQ¹S˜ÃåhDSÑ幈¤ƒ·3þȺWÒ2ãEì, À#nï¾½m;µ}`µ&›ìھ˰}äï#_Îýòô?§/†]tww<øñ—z¾Ô½kw&Ë;ÕðÑÃ|sï/¬F£ñöööõñ}<øñý>˜Keg'gOOÏÇë?Þ¾mûž=zêt:É›üƶêÿVuéÔ%ǦÞ|ûÍ+WˆÈŽÍ;žnötö 7nÜX´tÑ–í[B/„&''WªX©}ÛöƒÞT¡|…ì•@éARæR“¬6›L¦šž’q+_‡˜§E ,³¦ 6W’=7#Ygò‘ûÌViñÍ®1‡ìŒ’S‘Éá^ê³å•rH±Ý¹pó[]P3§å0(÷Î5ŠªdIêY"§lš’í_jN÷Ùâ[ªæÐø}2}Y‡"Øÿ†ÈÍ2}ŠˆD&ÿºÑì¼6ûšez«îvçä§,!¡l©WI«Õ:9:™–$%'‰ˆN§³µ±5:Ø;6ÆN;gÞcyddäÖí[·nß:gþœ•ß­ôóõ“¬ìíí=ÊxˆHjZjTTTddäÑcG/[Ü»gï¯ç}mkk›½²^ÕÇߊ»v)l݆uSgLývÑ·žlôÀkÉol"òÃêrLê%ßNÞ¸ic.çZóãš¡#†ÆÝŠ3–üwö¿ÿÎþ·hÉ¢ùsæ¿ØãÅF J*’z(æÌ“J†´Èƒ{ )–& T³ÉØrlüNa"ËΙ½ñlžc?¬:ãTiŽçpÿs¡ˆ"Š¢ˆ"¢˜n›…ªÓ:ÙÛ¸™å³lÜuÞEkZè¢óÉT3C˜¢Q¹Ó²(†$ "Š¢("Ê„ÈÄÛ±ÆÍ~åw²õU²6îïÔ<5Ó<Ë\Ùµ]¦š*¢1¿–;g4n+Šh ×e(7k§^Ù~JÖ¡©Š({×i\L µû'Ë7\‚"ŠˆÆd[QDs÷×£1^©¡ÜlGƹe…¹f;Úz·©¸ØNëjZ覫ܡò÷&¿ ÃEÉÝs~)Š¢hÌ®]«déaçaW«gõ=Z½±$!-üü­ ŠhÓ¯d¹FÅ®f™^•}ÓÁ¦ìÍ7Æò&½o–­˜¥·faû5Äëv¼öÁõXä©&OÅDĘ–Ô¬W3ürø—3¿|ýÕ×Í*/ÿ~¹!k6àͯýï5?ÿÐ ¡GŽ™ýÕìÞ3oÎÇS?6;¤]›v?,ÿÁ°™™yîü¹ÅËÏ ™»rõÊÚ5k9æ~•#®ElܼñÓÏ?½~©mç¶ܘcw¹‡‰ÍÁÞaÛŽm·âo¹¹º™íÚºmkbR¢½½}JJŠd³ì»e‡ ‘ºµë:¬iã¦vvvGþ>²výÚ5?®™ÈûEÓÁª"RÖ¡jŸW|ë™–s¬ÓدŸù) i®¬§0þhH¦”u¨jÚNE×FN¶^f…ÕÊ<ëåXÃ#ë…×õìTÙ­ñOŠF¹{÷ ©(cî)kJQœl=LÛiPî•@¯6YÖ-}Ê`c¿~vZgÓ–•ƪ¢Ï¡å{ù¦7dîÕˆ«7nÜðôôÌ¥fÙ²eÿoéÿ5hÒàZäµo¿ûvÈ ![›VmÖmX·rõJ³¤^llìŽ_w´xº…½½}ö£¦:=55Õ×Ç7䫳áÃ"ÒëÅ^¹\( ¬6{ KJ<ùÑúÐŽçâ~4ÍèiÛî/t ØÒØç=2zr¤(J¥J•Däïc?dS>>>†Ä¤ÄV®Z¥j®=DdŪ›«‹kÓÆMûý·ˆk¦åë~Z—žžþbããã͉]·aˆL;Á8Ï €)’z€‚”œu(rÚúÐÿŮ֫éÆrbSݽ{·€-M|?p²õµb„}/t{AD¾˜ýÅܹ©©©·söÜYQÅË+OÃü›7k."'OÌ% hAl‰I‰/tAUÕ5?®1-_¹z¥­­íóžO0OêíÛ¿O¯×‹Hïž½ór P ‘ÔŒÛ1^ÿxÝùöÿÆþ©Þ[ãBQ´nÏw­º©©ïGζ9, fFݪe«ÌÌÌÑãG?öøcóοo¾rÑeddÌœ5SDš6nj¶ðîýT®TYD233/_¾\€±%$$¼Ðí­V»rÍJcá•«Wöíß×®u»2eÊ$$$˜òÏ™D¤\¹rÎNÎ’z€‡•’qóðõO×…¶;sóÿ2Õ{ýVÑTuëÔµêÆf~Ó\t¬!€âE§Ó­_½~Ú‡ÓÊ”)såê•‘cGÔ 2|ÈŰ‹<655õRø¥M[7µéÔfßþ}Š¢L~/¯«*’z"[€±¥¥¥yyyµ~®õ±ãÇþ;ûŸ¡põÚÕ"òR¯— 1›s#FDªV©*÷AR`¹ÔÌØ#Q_üÚöŸ›Ë3ô)ÆrE4U\Û?ðSs¿]u•¬!€bÊÆÆfÄ»#Î>7÷˹õêÖKJNZ´tQàSfL1ŒK5³aãww÷rîµkõìÓóÀÁÞÞÞË/oþTó<ž4#ãΠ%·ÉùÍफ़/‰ˆ±³Þª5«\]\Û·mŸsmUD$—ÖHê,‘šyëï¨/מo{êÆ’ ýmc¹"šÊ®mºT]÷´ÿgnº*VŒ@ àäèôækoÚwhãëfddLÿdú{ä°~½½½½Ÿ¯ŸŸ¯_yÿò Ÿhøb?ÿäóOüûB÷ò~º°Ka† ww÷ŒÍ c‡ŽÎNÎ?®ÿQUÕÐ ¡'NèÞµ{ŽëÞŠˆ‡‡‡ˆä¥g"(µHêò'-3þhôÜÏ·=ycQ†>ÙdRÑå¹ÎU×>ãÿ…»]5«Å ÄQ¥õs­üv`Øa"2gÞœ«WÍê´kÓ.ôLhè™Ðs§ÏíýuïòÅ˽5(¿ëÆ’z¶¶¶Æq¸›“£ÓóŸ?wþÜÉÓ'7nÞ(wÇÞæ¨fš"•”œ”¯K¥I=@^¥éÇ„üÚöDÌ‚t½éÒJçg;WYýlùÙeìjX->%šF£™4q’Mffæ±Ç ã;wï‘úÁõï×î!cëÓ»ˆ¬Û°næ åýË7kÚì~5»~XõC¾"¥I=@žœ‹[»öÜsÇ¢ç¥efY¥Ñß¹y§*+[VøÊþ¶µbP¤¤¤äX®³ÕÙÛÙ‹HFzFŸôÔ?§6mÙ$"ÿëó¿BŠí™æÏøøø,ùvÉŸ‡ÿìݳ·FsßâÞÞÞÚu‘Of~’––v¿j 4#©È“ØÔóéú,£ÀüœžêXyE« !eíëZ+*%ω“'jÔ«1gÞœìËDlܼ11)QD5lT°'¸ñÊk¯dddT®T9—Q±›V«íõB¯èèhéݳwî!=^«Õ^¹zeبa™™™f{·lßÒ§oŸìËæ°¢C—Fî¼?lðÑ«S­ €R¤,”˜½ôd7ÃkwøLk‡ ÐÕ+ÛÏFsg<š¯S£ö•ÿ¯uÅ…žÖ @ɳbÕŠèèè±Ç>×þ¹UkV…] ‹‹‹;õÏ©©Oí÷v?yõåW}|| ä\ªª~w WßIUƒšÔüï쎎ß.úÖÉÑ©ðbëÓ«ˆÖ ¬[ûCžhðÄÔ¦ŠÈÒåK[´i±þ§õ×"âââþ:ò×ÐC_èýÂúŸÖºxDD&üq-þ·kñ¿E'¶v,Jk€bKUÓ2ïLŸ¡Ïy €’ÄÁƳ†{Ï›)g‚½—sl`íp”X3¦Ì(ç]nꌩú8¿ÝÿíŽí;~½øë?ï¸~)==Ýßß¿M«6Þ`X!À£ãáß _HêÁBª¨ÆmEøë” dô ÿNþ—Ë^_ß1#ÇŒ9æíÌúlÖ¬Ïfåñ¤Ù+o {)æöÉ<^H±>z:—½ÊW˜2yÊ”ÉSò"(˜S¥˜j|NÉCJE}pxh$õ€b†¤ O¶@±dœQ„éD@ñBR£K9€uÔ@iÆsJP,‘ÔCA`ívP\ÝMêñy+$õ`!•ÇÚ aN=‡ïJŠI=”^|óÅI=žk€b˘Öã (NHêÁR<×%ˆeÃoç†ÌupwhÙ®¥iaËv-Üæ†Ì- Ðr@R¥Ó€bФ ÃU@Á>z¸ƒ»ÃK¯¾”ãÞ””ww‡'OX~•á· o#ŠI=XŒÇÚÖAR¥Ï)0Æõ(6ÖŘ¢h #V,›XÀêE«ˆF lòO£á9€;šUY ª™"¢ÕØ[;¥ŸB`!W;¿AÛo¼½e¥±Öàž˜˜˜?ûøéVOûUñó­ìÛáù«×®6«cX£¶±sÈÿjWŒœÿ¶®¬oÙÀ'‡–”œ”c³»öìzåõWjÔèý¿ÞtqqÉW`Gí÷v¿z êùUñëÔ­SÈ×!z½>ÇÀnܸq;åö{¼WµVUw‡|€Ux8–uª_Ö©¾»CmkÇ T §JUUg|:cÖœY‰I‰"booŸ’’²û·Ý»Û}>ôü„±Ìê‡_1vÄÚuk ?ž;îÜùsÇNÛ½c·¢(¦ÍNÿdú´O¦©ª*"Z­ö§M?mÚ²©I£&ylÞÂyÞŸžž®Óé\]]wîÞ¹s÷Î]»w}·ô;{{ó~=Ñ1Ñ£úÚ¹{§e÷”xôÔ@É¡(Ê…‹>þé_þйs-ìÚð¡ÃEä“Ï?‰ŒŒ4«ßµg×-[·|öñgÿ½xáß ãF‘CÚ³wiµ5?®™úñTUUûôîsìÏcq×ãŽ<òrï—ÿ8ðGÛ¼móèq£u¶ºsD_‰?~üðñà àÍÛ6/Z¶({ýIMÚ³wÏÄqýylÏÏ{²W¥I=<Ò6lÜààîýUƧLŽõ?þé?Çþ2hHÝÚuµZ­»»û´§Õ©U'--mõæƒpEùyËσßìãããëã;yâäà `ÙþóvcÛ)·'Nž("ÿëó¿E!‹jÖ¨iccS§V¯ç=f䘼\BòíäQcG‰ÈÂy û¾ÒW§Ó)ŠR£z–ÿ ÕjgΚ™––fvȦ-›f}6ë½qïÕ¬Q³Ñ“ò|·@iAR%Ї‡‡³“³i‰¢(O7ZDÂ.…™U5lÔ ž0-iÖ´™ˆD\‹0–üòë/W®^Ñét“ß›l:&WD¼<½òÒÚukÃ/‡uïÚÝ´¼r¥ÊÏ4æúõëÃ.šÜïõ~yi”NÌ©€GZ×.]XþCöò”””ûuÖ3H¾|üøñ“§OžþçôÏ¿þ,"W®^1«“}ùZo/o‰ŠŠ2–œù÷ŒˆÔ®ïïçoÑȾ?ö‰H‹§[˜åE¤Jå*"ráâ…š5jš–÷z¡WöÊF$õPÒœ>szñÒÅ+V®¸KDü|ýlllD$##ãÇÚÚÚŠˆaA ƒÏþ+"U,ŽÇÐïoöÜÙ³çÎαBTt”Y‰!`€ûá³J”¯CF%"íÛ´ïûjß§?åáá1õã©Ó>žfYƒééé"b£µü“³!EøX`:ur¬P§VÎå÷CR%lj“'FŽiccóý·ßwîй@Ú¬\©²ˆ\¸jq >>>"¼pÞ €…2PrlØ´AUÕV-[TFOî&õþ>ö÷í”Û–µÐ´qSÙ»o¯¡ÓÀÃ#©€’#%%ED\\\L “o'ùûˆÅm¶kÓN§ÓÅÆÆ.[¾Ì´<)9ɰþÆuëÒÍÙÉ9ìRØýæÔóÈSà IDATÈ/’z(9êÕ­'"[¶n9xè ˆ¤¤¤ìÚ³ë©Omÿy»Åm–÷/ÿú«¯‹Èèñ£C¾‰MMMݳwO˶-ÙùKöúÎNÎ"rùÊec‰‡‡Çä÷'‹È¤&™0&::ZDTU½vqÔ¸Q(µHê äèÞµ{ÝÚu“’“žmûlÕZU}*ùtìÚÑÙÙù‹O¿x˜fß÷^­šµ233GŒáWÅÏ»‚wû.í£¢£f~<3{å À ™3oΈ1#Œ…ï¼õΨá£TUýjþW«W¬T£’wyï:Áuæ-˜·jíª‡‰ ”N$õPrØÙÙmß´ý¾oT(_!..®VÍZ3?ž¹{ÇîO·x˜f===÷îÜ;qÜÄfM›¹8»”õ(Ûïõ~‡öz©çKÙ+¿ûλÏ=ûœ£ƒcĵc¡¢(S&OÙµ}WßWúÖ LLHô÷÷ïö|·Õ+V/Y¸äab¥«ßà5ë³Y³>›u¿½ööö·ãrX¹ÂÓÓsÞìyf…µkÕ6«¼kû®›6dذ!ò—»8»¼7î½÷ƽgVž=OOÏÍë7çØx“ÆMš4n’ã®`Šžz@1CR(fHêÅ sêÁBªªOÍLEQ´Š­ÆÞÚ€GQbzÄÙØUu˾a§u³v,9Hͼ%¢QÑê´.Ö@1¶'ôÕôÌÕÁÖ§Y•Ö@ÉGRŠK½¼ú߆íšmZTiÝxÀ£I¯¦Ÿ¼±øL슚ezÕõxÝÁ¦¬µ#ÊbóÅž‰éWEÄÞÆ£Wõ½Ö@1–r1-3ND2õiÖŽ@©Àð["E4"’¡¿}úƲu¡m_ÿävF´µƒ2¥þ£ˆbÝ8ò…¤ ‚À}(÷>'dèSþ¹ùÝçÛŠœžœqÝŠAå„Ï3ï"ŠI=XH½ûX J¶œ™j꿱+Öo0rJRú5«DeÄGPL‘Ô@!ºß°ÖL5í¿ØUëB;ì¿öaV;+1&õèc  ð´@Q ©€B•[²L¯¦Ÿ‹[»>´ã×ÞKH /²˜²cN=P¼ÔƒÅî=}R>€œ)ʃ?pêÕŒóqÖ_è¼/bB|ZXáuªÒ¡K$õðHPÕÌÐ[7„vÙ{ul\jh‘¶¨NPHê e_(#wªè/ÆoÙx¡ÛoWGƦž+¤¨rÂÈPœØX;W UycI²L}XüŽKñ¿Tpiäù¶‡}­ Ss(b$õPˆò2§Þý¨¢Oø5πℤ,F—rð`þð/"鈤?|y*çØ  šå!%(^Hê 0=Äœz¹¸–tèZÒ¡rŽO{ôqjô-ñœK$õP x² €9Uô¢ªª¨ªèETUUå>Ûª¨"zUÔ»?êM¿ï¶*rç(U¯ÊEUÕ»uî5•µPô¢ÞÛVÕ»ˆ^½W®ŠñØ;QeÙ¾³qçÔ9ÖÉ4†§×§ÞM¾žü׎ð7ÿÝQU“âk§u³¨m¦ê!"6ŠzÚqÌÃÓ ¸qÇÖݦÅ_‹)’z°µ /Œù‘ÒžÙ¹xY¶ï¶™—ð²Ô‘»§Ö«"’§ðr»Ãv–:yHÒÝü¡,JáñI7“-=Z#¢5Rþ~˜0Êyù=ÌáùBRð(:ºÅMk[¤9‘ÔDí̸õ¡Éì˨üõP$HêÁBÅÖÕÎ×°mocÉhÈÅíx­µN­Jf|Ú%k€XãÀ£ UµªªŠˆR8s‰€’z°PûŠ/Õ^fí(ÈE4¢(Š(ŠhDEQä>ÛŠ("E”»?jDE¹³ml*˶"rç(E£ÊE1|»ËåŒw›5œQ£(w¢Ü=P4ro[¹Ûì½í;wNcmÂ˲mVß°mr ÷ O#w¾Ó*ŠhT5ý—ËoÖ/TѸv>l–(‘"bk§¶UHçÊQ|´íß{å<²ìm¼¬€Ò…¤àQakcë`ïhñá™jŠ^Í4lÛh i…üJ×'ÛèD§u%³cº] ™EDò^n—cØÎRçn’ÎtûîM»[ߤŽÅÿÀ`1½š^Í*¢©âÖ!Ès «®Ò*åµ»¥ª]‘Žz+≌Hê½»¿Ö»ûk~(rú•Ä=†iìÚWZädëSp¡xœKUDSÙµm× 7]•‚m !©(!ùLh$¬s8·”"šJ®­‚<¹ÛU+¨6Š)’zxô)]Z{½SÆ®†µ#x$Ô@!²l‚KÓ*8?äõNYûÚ@‰@R…M±dA çfÁ^ƒ=í+ð€Š;’z(\Š(j>“z~NM‚½†x9RHÅI=2EÉ{NÏÇ©Q}Ïw¼/Ì€Š=’z(\ŠhTÉ|`µrŽ ‚½û86,‚Š;’z(\Š(¹WðvöâëÔ¨hâ(Hê °Ý7©çéXßë?§§Š2€€¤ —’Óœzeíë{ .ïü´5"(öHê °iLð°¯ìùN—¹ôà@îHê pçÔ+cW=ÈkP%—V¤óI=.Ew»€ ÏA•\[+Y{íÀ2$õP¸÷^³LOzç ’z(\5Ëô²v% I=X(CŸ›rÙ°í`ëîlëeÝxÀжÿÛ!5#FDl˵©¹ÉÚá(ùHêÁB7SÂÖŸ}×°ý˜çóO•dÝxÀŠ2õ)úÛ"’¡O±v,J&*Šzê¡ 0í5€G@|Ú¥L}Š(ŠˆânÀ ›J0’z°jíÀÌþk“®'1l¿RëˆV±³n< t¡¯€¢E/@‰ÄÇj`-tPHê¡(|yðPM>@ó¾ d#©K©<}ðˆQM“züP’ñPB¨¢¿÷ƒBO=%I=¾<xЃ@iARãË3€G‹é»sê€"ÆÇEŒ¤ Ä0¦õz(ÙHêJU½3§ÏÉ€U1ª @Q © ©fÝÀúø  ´ ©(1î&õ yéÛ7ß~³rÍÊß­ø®PϹ ©(!LfÔ+Ä¿nQQQ+V®¸~ýúâe‹ ï,;’z( ¾£á£‡;¸;ÜïõÒ«/™Õ4-¹ŸÍÛ6wëÙ­RJe|Ê5 êÛ¯ïñÇ »T)Š9õ¼½½X- ÚÐAC… ‰ î 7(¼ó€G_Œ)k(á4ƒ½Cör{{û|µs+þÖˆ1#V¬\ahÓÍÍíì¹³gÏ]½võü9ó_õuQMW¿-D_|ú…YI\\\¡žÌÐSP¸ºtê“ýµôë¥ùjgßþ}+W¯lÖ´ÙŽÍ;®_¾q1âü?ç»tê""CG ½|å²ʈ‹µÖ©À#BQ´ÅF£Ø( ½gÞk`!ÖÉߥ¾á+´›}yk‡ äëØ®ã¡}‡êÔª£ÑÜy"åïç¿lѲ*5ªÜŠ¿µÿÀ~ûw’zŠRÔ¬è©Ú×Úaí”.ôÔƒ…<ì+w ø¸SÀ'>©S¶£µÃP*ür¸V«Ý¹{çˆ1#z½Ü+%%ÅPÇÃÃãÃ÷?‘÷?|?)9Éxìä)“Edä°‘åýsè•ìääTµJUOOO±µµ­Z¥ªáåêâZðW w‘ÔKéééë6¬ëÔ­“^¯çíwêÕ­çi_ÏDZa9Ç^Áf•7oÛšôËÎ_<иQã{¼hq´PHê W×.]oÇÝ6{ 0Ðâ¿[úÝ¿'þݵ}׈wGDEE;²{¯îÆ©ñ²Û÷Ç>iñt E1Ÿk¯Jå*"ráâÓÂ)“§¸¹º­X¹b舡"2sÆÌì€u‘Ô3vvv•*VjҸɴ§9x¤\¹r¿ìüå«ù_ݯ~ĵ™=w¶qiZãkñ²Å"eZßËËkä°‘"r)üÒ˽_nðxƒB¾ È7k€åü|ýÞÿþàaƒ-]4zÄèë†ú>X§N+Ô©•¥\¯×oݱհ¥ª*=õ>>"¼pÞÂì{³[±jÅÁC;µïtâÔ‰_vþ²þ§õf“ñ€Õ1üP<ÜomÈë‘"âæêæ`ïc…¦›ŠÈÞ}{ÓÓÓx–[ñ·&Lš`ccóñ´§~0UDF•˜ûQZVD2õ¹­×ˆ¤ x3~Ìç_~n–ÚSUuéò¥"R?¸¾F“óµn]º9;9‡] ›=wöÏ2uÆÔèèèþoô¨ðB÷žløäµÈkMû(÷£Ê•+'"ׯ_Ï}^(($õÅ@ĵˆ¯—|ýÞïõz¹×_GþÊÌÌTUõbØÅ7ÞzcÛŽmŠ¢Œ5ö~ÇzxxL~²ˆLúhÒ˜ c¢££EÄpø¨q£¶ÿ¼ÝXóô™Ó!_‡8;9=^DEùâ“/E™¿pþ‰“'r ¯v­Ú&îVÜâe‹UUM¾[`ÙÔ® 78—uÎþò«â—ÇšsÌõóõ[¿z½Ï¦­›š?×ÜÍÛÍÓϳNp•«WjµÚSf´xºE.1¼óÖ;£†RUõ«ù_U¬^±RJÞå½ë×™·`Þªµ« uTU>jxffæð¡Ã½¼¼ … oÐ÷•¾z½~Ȉ!z½þ~íûùúõ|¡§ˆ¼;ò]¿*~>}>ýâÓ‡¹i;’z€B—™}f9²kŠ*"Ò²EËcûlÆgM7)[¶¬^Õ×­]·Oï>Gyw𻹠(Ê”ÉSvmßÕ÷•¾õýýý»=ßmõŠÕK.1ÔY»níïüîåå5tðPÓc?šô‘»›ûŸ‡ÿ4Œó½Ÿ_-úÎÐÕkd¤g4x¼¿¿¾nä‹2fA€a«‚gÍÁçX7($k÷Ï:|n»iɸîût®ÖŠP€†Ž{-"òŠˆØÚëÛ½U”§¾uÝvï²²†íÖ-:½õÚ°¢<;)™©SÖ40l—/×à¥6ˬ Z±ýÕ«ÑG Û3úÿGO= ˜!©€èÕŒsqkDͲv Š%k@é¢W3Boýt"æëÄô«Š¢­îÞÝUWÉÚA€‡•–§ªªˆªˆFgãníp”|$õ`¡Ûq×O*¢ˆˆ›}yûÊÖŽuªšzk㉘… éWŒ%'b4ó›aÝÀÀÃÛy®WrZ„ˆØÙ”íTgµÃPò‘Ôƒ…nÞû%lªa»~¹^Oú¾aÝxàQ¦ª™¡ñ›OÄ,HH»l¶+"i¿*z… 1äI= ‘ªf^ˆßrí’Ù.7»ªAž+»¶%À2$õ`1ÕÚ@¿_›¦OW]ån›­‰*ú‹·¶ ‰O 3Û妫äõve×ö¤ó< ’z€Âø¨A±^÷aUôañÛG‡ÜJ»h¶ËUW)Ès`·¤ó(éè (ð½‚á·w>@+ŠþºÒy/tÛ{uŒYFÏUW©™ßô®›ªºu"£ŠØ;ýúÕ­Zeåÿ}gí@0zêÁB*OŸ}òä3;ÜìõúË} øF´ÄÄ/'ÇæO4ȾËËÛ»ßÛoW­VííÁCŠ>0…Šžz(Vœ¾ ŒTõîðÛ¢xSRÃv‹ž›zÖl‡³­ ç[n]4 dÈB«Ñ::9™–$'%‰ˆN§³±µ5:Ø;6&2gޱüzdäÏÛ¶ý¼mÛ‚¹_-]ñƒ¯ŸŸYûvöö"’ššu=2òøÑ£Ë—,y¡Wï9 Úšœ"GÆÞÁ!{¹½}>.ÒâbãrÙ;ãó/Š,E‰ï°Ão<ª wN=5-Ǧü“rònêÝaãªIÌb¼ß.º åŸÎcË)™±çb×fYîl¨ú{¿GQETE4Á^ƒóزˆYšw7à{¿2cðÆ QEêxüÏÝ. -Ÿ¿õSDâY~ewb–ì…埩îÞ#—Ö2Ò4û¾+›÷ëzx™é%3AXªª'‘-Ÿ3Ûåìì2hè»yoªK×n çθzõæe==-‹çæÍ›ëÅÆÆÎ[´¨çK÷¦Ø;ö÷ß­›7³wp8xì¸iø—/]újÖÇ=óÏ?nnn-[·÷þû¦ã…=úÍüù‡ÿ<{ãFPýÇÛvìøÆ€M–¿Ý[=÷ç§B/¸¸¸Ì›ýåºÕkÂÃ/yyyµiß~Ôø ÞåʉÈú5k¼Ö×Pÿß3g¼œîüž5o¾±ó£¡©Ÿ|úÖà,ïü§Ož\0wîñ¿\¿\7°^ã&M‡Žåêêjví†ÃÏ„]*ëéùÃwË—~óÍÿþëçïÿ̳ÏNž:Íl<5€¢DRbð-€B5oñg¡ÿË×!±©î†÷&Mün]¿ £n­ ¶]ƒŽGÏI9e¶ËѦ\ gÿjîݵŠÎ´<êöѽWÇdMÖdÍ}“9"Ž6^]ª®Ë{,þçø¨ë×'O¿|Õê6íÛ·iß~åÿ}7ä­·ªUûý¯#y¹–%_=yüxyçÝaý òñõýçÔ©±#†>x°W·®¿îÛW­z ³C^êÞ-))iÚ§Ÿ=ߣ‡ªªK¿ùæ‹O>>|èÐï¿íyºÅ³q_X®P§GiÁ“%U¦>‡ šÆÑNëV@«aä7eóH¤ÞòÕr>So…s>SoùûÓ–¯’/…—Ô+Ôtá#ño@q÷î¨ÑÏ>×*33ó½±cž ¬·($$>>>¿dddÌþ|¦ˆ4jÚôE7oØàãêböZ¼ðÎã=­Vûɬ/EdÎ_D\½ªªê´?‘ÉS§98Þôš’¤_;;FDzôìµtŵëÔÑh4¾~~“§M[½q£Ííä䉣G‰Èœ}^í«ÓéE©V½ÆÒïWhµÚÙŸÏ4t3Õ¤Y³=õ|©GÙ²îîîÝ{ö\°d©ˆlÛ¼ùìæËvåÅ­[·¦Mž,"C†ø`útÿòåµZm½  õ[¶>˜”˜8uÒ¤ìG)ŠòÓöÞy§œ¯ïøI“ƒƒEä×;,ˆ@ §,ƧjEDk[Ôo8ÆI²|5ñ >óMbz„qo|ZØÞ«cŽG‡z¾]Å­½ÙÔuÎÁÆK²$³EQ ™ Ec CÅÁ&ƒ€Üíªgª©w[6¦åNá½IÞ§½‘2v5RâLÂSLØ(&gTDW]å¼·ìlëWŵãÝpï5uï†Ü‰WQ\l+ä½e­FWÛã³[z÷®(Yï’""6óM¹¨áþby§æ†ûi¼Ï÷‚WÓ߯§C½¼·ìïÔÌÎ×=Ë¿åî-ÈzŸEÄÉö£MM9Ùú¶,ÿ•d½Ï&7ÜøÎpQù{²Û¢ü—z5ý^œŠÙ¿ç{÷YÅY—×ÁÈ"ì5°ŽÇÿLn©ÉoóÞ¿Ã;…¶÷ùWýåô%Ù U53CM13ë?ìäŒèu¡í ?WtnÙ¢|^GFçˆÇœ@ÁÒét+Ö­ ùjÎWŸ~õÊ•ñ£FN™<éÅÞ½‡ Q©J•ÜMKM½yêäɹ_ÎúóÀEQÆ¿ŸC¢*»ÌÌL³Õä™ÐO>ÙçÕ¾+–;mòä½zýyà@ÃÆ»½øâÝýÊß»“’âõ6:eÒÔ©fäiµZÙðãÚËááõ‚‚ºtïnº·båÊÍž~æ·Ý».…]¬^#Ëì;w15ܦ}{ÿòå¯^¹òëŽ5jÖÊËu™Ú¼a}BB¼“³ó‘#MËíìí1Ü* IDATGŽ÷úË}¶nÚtóÆ ²Y¦(:bäãOâÍo­]µjñÂÿœ:õíâÅßûí°ÑcFO˜ýÿÙÍ6WŠ0òòöžþÙ̦͛?ðtºv]úýþÔ¾ÿÑG›7¬_ýÊûÿ‘iŸ~fšÐ?wô¶ˆÔuöó÷Ïñðýûþ‘æÏ´Èþ R•ʲ[Â.˜'õ²3t¬»zåÊåðð\RNþ±_Džhød™2æo¿Ïµi#"ªª:p }§N¦»²ßmÃpæèëQÄ @ðÁ€Ð(¶ÕÝ_è°¥©ïGf‹œÆ§…í‹¿!´sè­ªjþl@±B?;àåèäôêoì9xhõO ÌÈȘ9cú”÷ßÏ^ÓÎÞÞ×ÏÏ×ÏÏ¿|ù v{ñÅ3?ÿûŸ3]_x¡ ‚ñôò2tp»|éR¯>/×oÐà^œ:¿„›¶"R¾ŠÇýŒˆ‘ùsf{99š½–/Y""ÑQ×ó†—··! .!òÚ51ä³qpt4,ªk¨“;[[[aúWÀªè© 9ÙzÖ*{g¸Š—ƒù,ªPòh›êîÝܺ\¸µéįÒ.wŧ]Ú1áxÌ‚@Ï·\;)ŠÖŠqÈ;žº»á«¾Zx½EQžmÕê™–-?zï½y³¿ ùjNÿAƒÌ:ĵn×î]í’^¯ÿyÛ6ÃvTÔuUU}îž®ºØÃ¾£Èn?·–÷;Ü0˜·n½zµëÔͱBÍÚuòFbb¢ˆØØXò^Íu’YÃåä^À#‚¤,äa_ù™ Ã\JbSͽ[€[—ÐøÍ'b&¤Ýö’þGÄÄ1 ˨êÖ¹€VÒPˆtZצ¾X; ù ÑhƽÿþÂys322N?~¿Q®…gõ+<Ø®cÇÓ'Oîþõ×MëכΎgè@váâý/çã#"Áõç,Xð0a„‡…‰ˆ¯¯ÇbË¡—ßíääë‘‘·  ˆ1ü€|Sm5·ç»UÝÔÌoº«®’鮄´Ë\{}hÇsq?êÕ kE@q—š’’c¹­Nggo/"éééE‘ÄÇÇ8q¢ÍG3>~ÿ£)"2qÌèÄÄc…†‹È‘¿ÇDGçØB£¦MEäß÷>Lð×##O?n<ˆh´ZÉÌÔçåpC G¾uë–Ù®=»v6ž¼Û2€GI=,¤(Ú·.]65÷ûØlAØÄô«û¯M^ÚñlÜZÚ¡ ïN8\«fÈœ9z½y¢jëÆI‰‰"Ò°Q£"ŽêÓiSc¢£_ëׯJ@@×^xâÉ'#¯]ûxÊc….ݺéìì’“’>™:ÅlkBB¼ˆtêÚÕÉÙ9<,lþœÙyz´ˆ,[´hÈ€¡çΩªz-"âëyóê׬yòøq “&‹È´É“ß7ÖСOUÕK/N=ê×;²Ÿ÷óg îßÿü¹³ªªF\½:aô¨Å ŠÈÄ?´wp0Ô©Y«¶F£¹uëÖò%KTU½œœ=hT¦LC ³>ýdê¤I×""ôzý?§NõèÜéıcŽŽï›¤)<ʘˆ¦ŠkÇÊ®íÃâ·ŸˆY—jÜ•˜qàÚ‡'b¾®W¶_5÷nZEgÅ8(>˜>Ý«œ÷§Ó¦>xððÁƒf{ŸmÕêÓY³ ü¤›7lðquÉ^îêêúßå+ãF ÏÌÌÚòëÎ>¯ö},0011ÑÏÏ¿s·nËW­ž¿xqö^|©Ï÷ìéáááãëÛéùçWÿ´qü¤I†¢ÑìC‡V«^#=##¸AƒÜ—Qe舑Û÷üÖó¥>5kÕ¶±±iظñàaÃ÷þ«ióæyeÌ‚ÃVÏšƒ;αn4PHÖîŸuøÜvÓ’qÝ÷;è\­hòÇ#Oÿ{ܰÝaÄu­­š{ý”š¤ùy®·aû‰à&ã†Y8Eý¥ø_OĄĦž3Ûåhã]ϳ_u÷ZÅî¡b<222S§¬i`Ø._®ÁKm–Y5”[=÷çÓ?›ÙÐ kÇà‘°bû«W£¶gôÿžz E4•]Ût®úc‹ò³ÊØÕ0Ý•œu(rúºóíÏÜüž^{ Ù— ’z"E4•\Zw©úã³å¿ô°¯eº+9#êÏë3VžmF^@~±PE@©èÒª¢Ësá »OÄ„ÜH9cÜáçÔ„A¸ò‹¤EF©èÒ²¢Ë³—÷¹‘òˆä9ÐÚQ(~HêPÄ” ÎÏVpnq%qodò_öµ­€â‡¤V¡”w~¦¼ó3Ö<¢¶üºÓÚ!x¤±PPÌÔŠ’z@1CR(fX(€‡u+ål¦>UD4Š»«Û(tôÔƒ…âS#ŽG­5¼¢’ÿµv8ù–šwúÆÒÓ7–ž¾±ìjâ>k‡ ÐµhÜÈËÉqÚäÉ÷«0sÆt/'Çv-,Yžþà¥á»Ï÷Ù}¾Ïïúeß›˜˜àåäØü‰´ 9"© ÝL¹t0âÃëjÂ1k‡o)7ÿŠúü¯¨ÏÿŠšy1~›µÃPè:tî""?o¿ïÿï?oÛ&"ºt)ðSÇÅÆx›J9’z(¥TQÛŠ(VŒ@Ñèй³ˆüsêÔ•Ë—³ïŽŠ:z䈱ZÁºGR@#©‹©&Û|ð¨«[¯^…J•Dä—íÛ³ïÝùó©Q³Vµê5 üÔqq±Þ&€RޤJ-“‡”<£JEQ ½ð~Þ¶5ûÞŸ·o—œºé?ztpÿþ‚k”÷±sçE èõúì‡GG¤þðYôÇo^yûéãõª¼;pൈY¿f—“c×víDäß3g¼œ ¯ÿ[¶ÌôðÓ'Oyë­§>Q¥\¹N­[M4)>>>ûY:¶zÎËÉñæ)·oOyÿýzÕ¼œW­øÞ² Xcõ[@Èê¥DÇÎ]Îûûo¿ÝNNvpt4–§§§ïùu§dPOUÕoæÏÿ`â„ôôtNçâêºg×Î=»vþ¶kç¢åßÙÙÛk~·té„1‡R’3EÄV§‰¼vmÅòo·ü´aãÏ¿89;W®Z5!>þFLŒ­­­… †C\\\Œg ùjδɓÓÒÒDÄÎÞþÐþý‡öï_·fuÈâ%š6Í~11ÑGÞ³k§áÇ:u+Ø» X §,”e>(6nìQ¶ljJÊÞ={LËØŸïëçT¿¾±pû–-ÇŒ¶Õéf‡„\¼u&ìÒcǃƒ·oÙòíâÅÆj+¿ÿ¿ƒßIIÎ ~ÚiÒ÷Böž8w~ð°áAõ¯Q«V›öíŸ<õÁ´i"P­Úá“§ ¯ç{ô0¾äë¯'Ÿ––öλÎýwöRTô®ý6n|9<¼W·®çÏÍ~Ó&Oþý·=£'LÜôèÖ]»kÖ®]÷ À#ޤJ)ÊJ!›v;I¶¸¿l»3öV£¹ó5ùvròÄÑ£DdNÈ‚>¯öÕétŠ¢T«^cé÷+´ZíìÏg:Ö%$ÄO;VDš¶/÷Ö ¿ª:E#¾~~“§M[½q£Í†ÇݺukÚäÉ"2døˆ¦O÷/_^«ÕÖ Z¿eëcI‰‰S'MÊ~ÔÖM›>þbÖ˜‰«×¨Ù°Q#N÷ðw@±CR†ß¥ÇÝiõ¶©ê½Ì¾aéŒö&êmøqíåððzAA]ºw7=¼båÊÍž~&êúõKaEdó† ±±±:;»ÞC«)Y¿akµÚ³yÃú„„x'gç!#Gš–ÛÙÛ;ND¶nÚtóÆ ³£ƒƒû¾ùfž®@ÉER‚Á 8R\@‰ó̳Ï::9E^»vêÄ CÉ¥‹ÏýÏÍÍ­i³æÆjû÷ý!"ÍŸi¡d›o¨R•Ê"vᢈìÿ}Ÿˆ4hØÐ£œÁüc¿ˆ<ÑðÉ2eʘíz®MQUõÐf»º÷ì™=*¥ I=”VªiR¯Ç@iaïàвukùuÇvCÉ/;vˆH›ölmmÕ"#"DdþœÙÆõj¯åK–ˆHtÔu‰¼vMDªU³l¿ápC–ÐŒƒ££w¹rÆ:¦l´,z €Õo¥L‡Î7oØðËŽÃÇŒ•»Ù½&coEÄ08·n½zµëÔͱ‘šµëˆˆ^¯‹ûÍ©jn]† Íæ^@©ER€‰¥@q”u¡ ¥HëvímllŽüùçÍ›7ìí÷íÝ«³³{¶U+Ó:å||D$0¸þœ riÊËÛ[î Å5Π—œá,áa—²ïºœ|=2RD||}óÞ €Òƒá·°‹@±Çð[ ”rwwªùÓz½~ϯ¿þñûï©))Ïþ?{÷Eÿqü;Û7½7BïUDPì§"M±£ˆzž½{‡EÅ;ëzg=ËY~6°`APT&ŠÒ”^ !}7Ùlùý±¸LJ²Ùììl^χ»ÙïÎÎ|&l&3ïùÎwN?=1)I=ÏqÇ/„Xºx‘Ïç;Ì¢Ž>\±òçŽJïaf3Bˆ@@nÔ\ËÊ+jjj½µð»ï‚ÆoÎFhoõíÎèñã…óçÍ›?o®bÌøñf{II»vìxáßÏf9ã'L°X­®ºº_ÚÖ¨çƒÓéMGÇÛWº7¨ç7aBbR’Óéxþ™gÔí^çéÇþ!„8kôè¬ìì–o€øG¨€vªA?=ž# ´3g+„ønþ×_}ù¥Á`8óìÑfÈÈȸïÁiBˆ¿O›öÀ=w——• !EÙ¹}û}SþöÍW_gËÎɹcÊ!Ä·îysú¾Ò]>E%ÅÅÿ}þùÁ½{¯ýõ×àl½ûô5 555o½þº¢(õ.WUU•"===¸–O>ñ胖˲¼aݺóÇ]³zµ=!áéÓ£ô 7„z“Ò’q"b¡оä3theeåžÝ»‡ŸpBfVVÓy®¹ñÆÛþú7EQ^úÏúvéܯk—®y¹Côå…>úàƒÐlwÜu÷W_-„X>×9íâ]7ž´vPÏ÷ß5E’¤’ââÐêλð"!Ä]·ßÖ«°C÷‚ügŸz*´–¦O7›ÍÏþóéA={tÊÎ:ù¸aË—.-èÐáý?éݧo›ÿ,èÊ@»ÅEJ ];{ܸ_~þY1z츃ΠIÒÔG9óì³ßyë­5«Wmݲ¥°°cŸþý.¼dâ¨1cB³Ƨžýwîà_¾ÿbKÑ&OE‰ð!C† »cÊ]Á»nƒž}ñÅìÜœùsç•”=dHA‡¡µÜzç_O9íô—Ÿ{î×U«vï.4|øqÃGÜ~×]©©©mù o„zˆ®l=âA@»vûߦÜþ·)Gœm؈ÃFŒ8ü<’$vÆŸFœ2@a4ØGt~¦é<«õ‘Çä±Çº„AGýü«¯±˜9ß|{Äy´„zS†­ó°ü+ƒÓyI4­  ¦œcrnŠ¢%ÓÖOërŽàŽ)w¼ôÊK‡z÷Üñç¾÷Ö{‡š3)1©   {·îWLºbÌÙcL¦gÍYò¢%‹Î{Ö‹1|Äwó¾;âl@\Rø°Ö%h_õ¦4[§Á¶NZW>»){`æ_´®¢e ƒÝfoÚn³Ùš¶d¤g!dE®®®Þ´yӦ͛æ~5w`ÿsfÏÉnò0ÍÃ/Ùh4&&$ªÛë\uB‹Åb6™C]h „z€nŒ;>Ô#ïðF9*4§¢(ååå3?š9õ¡©kׯ½óî;ß~ýí-ù„'”—«[z콫h×3O?sÕä«Z¸ xú-ç$IÊÎξéú›þùÄ?…Ÿ~þ©³Ö©uQ Uõ€öâÌ?)„ðù|»wïÖºÐ*„z@{Q[[œHKKÓ¶ÐJ„z@{1ó£™Bˆôôô¼Ü<­k­B¨èÆìÏf'e&5úï¥W^:ü§dYÞ±sÇ}Þ÷Ø“ !îºó.I’"²d ž~ èI hÔ¢(JÓÙæ}=¯{ßîBY‘+**|>_°ý/Wýå¦ëojÍ’@, ÔtãÜñç¾÷Ö{Í™Óív—«[Æwó 7Ÿ4ò¤V.Än¿âйãÏ­¯®¯¯®w–;{õì%„ÈÏË?T¢t‡Pˆg&“iú´éBˆ×Þxmã¦Z—"ƒPˆsãÆŒvì°@ 0uÚT­kZkGåÇûj—k]hPˆs’$ýýá¿ !¾˜ûÅ⥋µ.Ÿ7P³¦ä©ÅÛ®Y¸uò¾Ú´.´D¨Ä¿‘Ç=j´âž©÷Ȳ¬u9@˜6—½å Ô !*êV-ÞvíÂ-——:—i]hƒPh~ðaI’~Yõˬfi] EÈ[+<£¹ÂµzÉöël™Tê\ªUU B=@7f6;)3©é] ŽøÙýLš8Iñà#ºÝî.ˆIF÷ýf@þVSºº½Òõë’í×íhoõ= ŒhÖµÜ÷€ÕjÝU´ëÅÿ¾Ù%Ña2$ôÎþó¨>óæßyˆhï2¢=í„IëÙŒ§fÌxjF+çìXرº´:ì%«m\»±¥"ÅdHè•}U·ÌK¶U|°©ìeè­Jך%Û¯ÏHØ7÷Ƽä‘ѬªÔ¹Ô'× !$aìú§h®@ûD¨‡0•¹6m¬ü:8Ý-í¤‚¤AÚÖÐRïÎ •o ! !:$žÐ1ùT­+Ð&ƒ½Wö•Ý2/>X´·véö2öͽ!/ùÄèÔ³¦ä)‡{k°0B=Q@¨‡0U{v¯/ÿ<8fíH¨tÇå/ÝXõApÚlH$Ôô(ím¯˜¹±ìEè­J×Ú¥ÛoLOÐo´'iX'Dcê!øãôHQB“κf2Ø{f_qvŸyƒ ¦XM™ê·ª\ë–n¿é»ÍKß ¡j  ;„z€ Öâ€Ñ`ë™59íÙLYê·ªê×/Ûq3Ñ€xB¨€vŠÓz .£½Q}æ*¸ëÑÞ%%Ž…m°àÚ€¨"ÔCHüõº¤:¥—8žâŠÑ`ë™uù¨>óŽ*¸ÛfÊV¿UU¿aÙŽ[¾Ý|q±cñ>ý"ÔCØøãâ)¸d4X{dMÕgîQ÷ØÌ ¢½êúß~Øqë·›/*v|Ù³…s%QA¨€vŠo 0¬=².Õû ÑÞï?츭-¢=hk&­ @|àÊ6´gŠ"IHê?ŠE–$ƒ¤º‚¨(Yšž2)ž@ª¨þ÷@àb”¬éÀAK@ñd¯É`W7úeW@ñY I’d 5úäÚ€â;PfÃÅjuB›1Ý ™C/ݪ€ì±›²Ôk¬÷—o¢)W½F—¿tÿnÔÁ£ëM1wR/ÇéÝP¼©Önê`w»¬øÓ­=ÕK©òlЬ4Þ–Æki´:IH™¶þêå”ׯ•$c¦­Ÿê“rYý£dÍ´õ 5ÊŠ¿¼~M“Í9ÔÏöÀÏÁh°eÛ }  xK]+-†Ä,û P£_®ßWÿ‹Å˜šejôœeõ«ºðƒ­.ôÿŠÍ”‘c?:´O ºÔõs‚)G½Fo Fµû¿Àu¾’²ú_²ðÐzl}ƒÜTKgõ¾ݥ®•éÖžêŸjg[Yý¯™¶~é¶Þ¡Æ*÷Ær÷ÚF+S­NiøÎÍ϶­þ×)w¯+¯_“›p¬úK²ÏõK¹{}aÒ‰)–.¡Æ’ºåUžMêâýmð¥ê”tjªµ[h9»kU¹7vI•léjÜéœ_ãÙÚ#mB‚)7Ô¸­æ §¯HQä†ki¼±Mÿqû¤_¢^ÎæêÞ]ý3¯´ÓC¿U¾Sçß{TÖõfCb¨qmÅkn…hàßõ^hHÎ&CBè3«ËžsªË½WýúséSÅ{\Þýê¥ÿTúìÂýß#“}çÊÝÓ³–ЄA²S8M¨¬(ºÏlL>ºàÞPK@ñ¬,zÐnΘÿ×P£7P³zÏßõ/xÐÍ ²›s*¸'ôÒã¯úe÷´dk×ùw„]ÞâÕÅÿH³÷ë—{c¨ÑáÞº¶äŸ‡^‹P¿¥ÞØŒ„Aýón ½]ãÞøkñ“9IÃûä\j¬p­^¿÷ßù)§ö̺<ÔXê\öû¾—¾–Æ»ô[˜zVÏì+Bó–8¾ÿmßK]ÒÏí–yq¬Ëºf^°£â£ ¥/¨÷Áh/ÍÞ§oÎõ+ìýéÇEM¶ëÈj=®€’%„„´Òv]KPËÌʹý¯Ó[¹ñPaRý€¶µðµ¬#Ï9ÁÝ[r–ØUVËWmù)ؼÿÝÞ !rŸÜ!tÎ#*Ý¿}StC‡¤OÈ?p\^êúyáž;»$:.ï¾PãîÚï—߯^ÔAW§:ÙÿÿÝSÇ«O,w:ç/)¾¯oú¥Çä8=ÛR={ùÞ郲®”um¨qCåÛ+÷ýëà«k²“WŸ5 ξU½œu¯¯Ü7㸼ûú¤_j\UöŸµå¯Œ,øG÷Ôñ¡ÆŸJÿ½ê=Ñr'<Ñ-uLèåŠÒ'6VÍ<½ãó…I'‡—•<´Ýñå¨Îoæ& 5.Ús×îÚpNÌÎîòvŽ}pèåâ=÷×-=§Ûì4kPã‚Ý·•ÕÿzAù‰æüPãü]×V{¶†±Æ {~—`Ê ½ü¦èF‡wÇe½R‡ _í¼Êí¯œÜwúƒ_î˜è—Ý-]A2_Þg•ºeîÎÉCÒŽ‡ZdÅ7wǤdKÇóºÏ 5z5swNnéê„)–.º¡ZNõü]×dÙŒéú~¨±ÎW2×uù‰ÃÏìôj¨ÑáÝþMÑ a¬± ñ„3:½zYãݾ`÷í]RÎRÿ†:¼»š~p_ýêE{¦„±ÆÞé©C½2ׯK‹ïùgu¨·×µbùÞéÇdߦõv×-ùeߌ0Ö8$çu¨W\»lUÙ¿‡ç=¨õvÕ.X_ñ?»)Cêíp|µ©zVkL6ªC½]Îo6Wœaë«õv8æîp|Ÿ8BÆm­ù¬¸nYkì”tšz9Û_–ÔýØ3m‚:ÔÛZóY…{}ÿŒÉêPoKõÇïÎ0ÖxTö&qà÷n[ÍNßîcsï2Š¡Þ–šÏür]£Po«ãÓäÌЫò•7gu&ƒ½Q¨WT5ÇjÊT‡zŠâ/ªþ2ÙÚUêdOQõ\Ñr)¶îê—¹¾Ø± 3¡JÝè“ëJßËŠ¿AcÀ±×¹X´œÑ`m¸gYíOž_áõW—Õ®HV}»„eyÝ/a¬1Ý>@ýÒ¨®r­ËM±¿ÉÚ=ëRYñ­)yÚlLòjCsV×ÿþÃÎÛßÞ©h—7Œõ !B§Ø5b[¸KØÏëõ´r â¡ Ö¹jŒGž)Ò F%!5 „«ÖçjÑÝjõKYñ×û˽G£F·¿Ò'שŠ×Óð³ÍPô+Šì—ëtO 6 @ñ("аQ–ÎÖlÍ¿®Ó†W€štÜhÃnãR ¡Ð¦½×Û÷8êü IDATr…Ôœ­V <׌Åïÿ9·Ñ׿  WšÌþ66ÿ’gßö oÓßÐF ðxˆþcâ׿-5$I´ñw²y¿QøõoØ$™„fc²:Ô È.Δè»*ÚR³CŠðs„fIBÕo‘\xLäÑcD[çm´èXJĵ_MpÙÍùÚ´ePºÿGÝf¿ Qƒ%ΣҰËnÓG»´ñscš½ð=“Z’Ôp4ùòº_¶V¼'„pyKÔícjÏì+i5ÛÄWÁƒQ‰òPC²Ÿ¡4¡Â›'6âDbBRJrjóç(ÞPÇ7³!Á(Y?ÿ%Ø=¾új“Él·'ˆ§7’êrÚc3¦©_…9Ñœo5f4h4X“ÌÍi2ØU÷¯I]øAÖ+I ¦~[ŒIiÖö†·5Y©éÖ^mÆŒ [Õ2¯å «B¨ï ¾Ì¶eoXF’¹CŽ}°Í˜©nL¶tRÝÛôgØ`-êמfíQx¼­áO5ÃÖÛ+×XŒ ¾6YöÍXÝAÚ­†Ëɱc’ìC’º1?qx¢9Ïd°©;$L·ö<ÈϰavÔ´ “Ô`9“ÿT(Wá%„èšr¶OnÜu´G깪—¡Õ5ø¢6ÝüFKBôN¿¤Ñ-raì—q¹Uu“£Âd°õÏøc¤*©Áò›n”úKe35ø÷2e]›`ÊS7ÚŒiGe]¯¾‘S‘`Î=:û&ÕZ,óP[,,Ù\¨^N’¹`HΩ–®êF»±Á—9(ÃÖçØÜ»¹ðÆ?ä-껳…™¶ÃóȰõQ7æ& ‘?M=h ¢CâHk~ÚáW×ô÷B¡¾±WÑ)ù´$sêk/„]SFgØúd«†BôJ¿ ?ñ¸#~QU•ì™Õð®Æ>é;&ŸÒ¨Œ™éžzNš¥Á}”ƒsnéç¿\4ÔägxÍOmx?æÐœ)^Ù‘hÊW7ÏŸæ—]¶†ßÕ“:<Þ™Þä_Jj¼:¡žÁbLQ/çÔÂËŠW=Ȧâ¬Î¯5½Lrv§·_žIð97³ßÙÇ?*úOz½¿°Æ.<³÷g~CÛY}æ4ªÁjÊÕgî!ÿI‡ü.©ÇBØM¹cú}×háÉÖ®cû-4HuczÂÀqý7Ü”Cÿªfj´ÆÌ„Áç ø±Qc^ò‰çø¹Ñ†wL=»pàÍZËÿo´÷BˆNéã:¥ NWÔ­ÚPúü¾ÚECcjÏìÉÝ3/5“~”ž µ¼¼257¼^íaš÷lŽÏÍ-4‹t×Kû‡Tè˜Õûæ1ÿÖ¶èȦÊù v=œYxsÿ¬qÚÖÞ‡Ëf¬Ø*ë†?ÒC þ€gú¬ý×- s‡L<ó MËAcu«6”¾°¯vy£v‹1¥Göä™—™û¯Ü¼ùú³ ¾Ý?èIWVhêåæuxâŸoDsÕbß»ó&ï)Û?,òc×l¤§ >è>Ü’áÏ`?I¢k Ÿ*êVm(}q_íÚ›Æy /„zˆ€6tެá˜Dì”4Éñ¬ÂµzÃÞšÆyfcrϬÉ=²&çÐ5B=„‰C`1†Ý€ãz¯*]¿n(}¡Ô¹¬Q»Ù˜Ü3ëòY“ÌÆdM €"ÔÄÕí·M€#"ÒâC¥k͆ÒJKµ›I=².ï™u9q€¸A¨‡H`ø*ZSºÛ|øQéZ»¡ôùCÄy“zd]ÞèÑÆ w„zS~Ò€Ó;ß#„P„’“Ð[ër€eh± [ß“:<ܤ[9žôªÒµö·Òö:—4j7“zd^Ö#{2q€¸D¨‡0¥XòS,ùZWû10€0$˜rº¦ŒÖº á«t­ý­ôŽÎÅÚÍÆ¤î™—ö̾‚8@#ÔÄõ˜z„zĹ*׺ ¥/îu.jÔn6&uÏœØ3û ‹1U“ jõñ 7aèȂDŽP¡äØÖºÐVªê×ÿVúb‰cQ£a1M†ÄY—çh?õñ ÅÒ9ÅÒYë*@›R~Øq[±cA£Ö?â¼Écš&e€&õº YM™ê×&Cb÷¬‰½²¯ ÎÐêô¡OÎ5;«>•ŸÉÐ=kb¯¬+-&â<í¡@,Ý3'$S¯ì«ˆó´s„zÝT0Eë &´.@Ëê:C¨è ¡ 3„z€Îê:C¨è ¡ 3„z€Îê:cÒºèU‘cźòOƒÓ³Ï+L>FÛzZj¯kźŠ×„BH½Ó.ê˜|ªÆ4¡ÂTë+ÛåXœî–v¢¶Å„¡Þ_¶§vIpºCâ ÚÐ"Ü~‹ˆ´. ŠÖ„‰žz“ÂA0€X²Ý1w{Í!$!‰£²®Ï´õ׺": 48œá"%ÐB=@¹VÛbZ„Ûo&E(¡iIHVÐÞÐSV”>QR·\IHÒÿk7ej]P_¤\¤ºB¨ˆµ¾â*Ïæà´"Ú@Ÿõ€žpû- >(GžQØu½"ÔCØ8CôÉ_7ͤÚuÐQè §=€¸ 00€Vb×ô„PÀÓohŽGrƒÂ@·õñAufÎMtš‹ë@¯õñ aO=; '„zˆ:ÅОú:þºhn¾úÅiÂÄ4bŠ¢p€0ðŒ W„z€øÀ™9€v„PxP€–£“/Ð-B=„ÛoÄ…GXh%ö@WLZ@êc8¼5_¥˜,aí($‘”ᯭhñ·ßKÏÍE¨‡àü€öÆÔv§ºÄÞ{W×÷ç®5ö ’}nr:m‚ ¤pa@láÌ@«p‘@¤$¤zP+„è4¨þ´kÊ;¨×º"ñ‰žzÓ€ìñ½3ÎB¡XMÉW Ýkpû-ÊÐ<ý2&÷L;?xUÀbLѺq¢÷‰µFóþ#K‚|ô˜šŽë×|ÆÝ¸pìS&³Án6ص®Bè© ÅL»‰ã ]vù—\zmk–à Ôü^þÜ®šÏBÇ'™¼§_SÓ=}RÌ?%ks"¸¯ÀêâÊa2›Mæ0‡Ò ² û±‰v«;ÿ—=8Ü[‚²âÛ\ù¿âÚow¸?7ù„HT  ½#ÔăS Ÿ•¯¢ÈŠP Ý€Æ2ŸÞsÖ–ò·+}Ñ/ïV¯Î[´dûõ…©gUp·Íœ­m…ô޽€x`3¦'˜rÍùIæn¿±À ™ze_uF¯Ùù)'«Ûw×|õõ¦ñ[ËßUY«ÚÄB=ÚJ‚¥àø.ÏèüŒÝœjôjW?öÕÆ±@ïõh[©§ŸÙûÓžY“%Éjìóg K w„z´9“!aPÁ”Óz¼Ÿ‘0P‘‘pT—Œó´. €Ž1”8Q’fïsjw¶UÌÊL€x ˆÐc¸ék , 't…PaRŒAÃA0Í…vJì‘Ä?B=@<]i`T,-ÁEJ W„z€ø@O=­Â%íÄ^ço Zë*D¡"€C`š;ðô[FÅÐl<(@Déà Äã¯Z±ëÞ/6œì Ôh] €Öâé·€ø@O=aàö[mC‰ÅÊæ²7‹ª¿ vÓ“¯Öåh-zêâcêhöâ^yÝ/Uõ´®@Äê!"8  1…žzZ.ôŒÝ!ÔC˜ƒ@Láé·ÂÂí·@¯õñá3s” <ì=€®ê!è pû-ВĵÑÅÓo&ƒd0Jæý/øë@k ÊÐrÉd”¬B!‰«ÝZçè‚ûý²+8m0˜?3´¡Â44oòмÉZWPä?¦õ4×±¹w›{·ÖUˆ)¶îZ— }á‚$ ¨n¾%Ôÿ詈É(IF¡(’Äõ*ñP.éµTë zèÎè ¡ 3„z€Î0¦ñÏjÊH´tNK¨m1ZP€øwLá4­Kh“ðd¯$û Šì«pÈ!Ñfä€0g&Ë’A1˜dƒÙ/,ZWÔ,„zÄ®{î¼ãµ—_>Ô»cÏ=÷ï¼{¨9“’òó ºvïvéä+Fc25š³ä¥‹;jÔ‹6bÄœo¾=âlGd>³·FñÀãðûÝrÀ¯ÈþÖ/8’²jƒQÍ’É*YR̳Q2ýÖdŸ°j]Ù!êë ƒÍnoÚn³ÚµXm¶ŒŒ !„,ËÕÕÕ[6oÚ²yÓüyóú ðÑs²²³[´d£Á˜˜¨nwÕÕ !,‹Él5ÚmYBóIB±z« ~¯«Â[[P”Ö, “r@ñ¹•úB’„5¥.!Óª˜-Kš{Ï¥ Ô Ö?>Ô#ïðÎ5*4§¢(ååŸÌšõðS7¬[wïßþúÊ›oµhÉÃO8aç¾2uË1}ûíÚõÄŒg&]ye˶á` B¶úªµîš½zä!¦(Šp×ÈîšzÉPŸœWoJ¶y-iX’P€ø$IRVvö57Þh³Ûï¼ù¦9Ÿ~Z[ëLJJÖº®ý¬r­\í¨*öÐ5±L‘…£Ø+IÞä<·%=©Þ˜ªuEûÅ\×AY§q†ÂçóíÙ½[ëZ„  ž}®Ž=$zÐEޝs[u‚»Ô¨ø´.GB=â^]]mp"55MÛJ„fÅc®)­Ø\ç­•µ®hŸ[®Øì’Ê÷™e—Öµêï>ž9K‘žžž›—§m%–@¨(¯ÞåtЃn9÷zû*­‡¶eê뾘=;/%¹Ñ¯½üòá?%Ëò®;¾ÿþ>þ˜â¶)S$IŠÈ’ÃcQêü¥UŽo[,ˆ¦º2Ÿ»¨Êæ¯Ö°”€F-ÊÁ†£›?oÞ ž=„²,WVTø|ûÿºâꫯ½ñ¦Ö,¹•Ìr} ¼ª®"&#ZÏí” {Ö|“ǘ¤I„z“O®÷Ëîà´Õ˜lø.ñœÅ-„$„d3¦I’QëŠèØÏES+]¿§Oë9Ód°GvùcÏ=÷ï¼Ûœ9=nwIq±ºeô¸q×ÞtÓ 'žÔÊ%·†Qø¤šªÚR=ÄW•ß`©6e™ü[ô×Nƒ0­Üû¿îû08=¾ÇÓùIµ­ ¥~*}lkÍgÁé Ý¿H±tÑ´úVïÛëôìøã•–Ï…t~¿ÿÄ¡C·lÞ”›—w¨D/:$¡X\•»=Ö´‘ÚR_º­JNÉ•£>Æcê!š Ê  Ò ž™L¦©<"„xëõ×7oÚ¨a%6_uÍ.·†mªf·Ûæ­Œþz õ&…ƒ`1Dqª<*O Ú'×i] Ýhx<ÃEJqhô¸qC‡ LªU &Åë­¨ ø8…DÜ’µ×e–]Q^/¡@÷ürý›N|Ó‰ïoùÝî[µ. VH’ôàôG…óæÌY¶x±&5X<Õµe ¥‡8W_0Õ;¢¼RÆÔCH\Ù )u_öGZ‚n#"(FCFŒyæÙg=wîÒí·•¦íßïÝ÷k›); k7+nW7Þ¢]pîõ$vuz ÉQ[#=õ®6xÀ9„Kêñ§ @s©g¸H ŽM}øI’œŽjYñÿ‹ÚªMG}u j«4äsɆú¨ÞKO=€î) £b€¢´Aˆ/fÏÎK9H ”””M»÷þ³}û÷¿ø²IBÌø’Ï(üž*žx‹v¤®ÌmK¨÷Jöè¬Žî €8@¨ <ì=èIàšóÙ»§N• ‡LZ³äÃ0ûœõUÑëhÎã”Þè=¸žz7߈ ÆÔ“8-öbÕãÿšñø¿f´rÎÂŽGSìø.¼%«ýòÛïÍÕ땹õíŒìñ «‹…ôÔÄúÚ—) ­…ßëä¡·hwê+½f¥»Î õ , @[ Ÿ~Ë @s±÷€¶c”=^'÷Þ¢Ýñ¹d£?JO|&ÔCظ² fð  ÀÞ@+±iÀà÷ø<œ6¢Ý‘Bø£gêt¾6ÂÅÙ&´¿Ÿ½,Ú)B=šMuÀÈP÷Z€ÓMh32ûX´SJ J_~B=„›ÝÄ EÈ¡izêÄE‘<Y‰Î…CB=@œ!ÔÐ\ê9¹$FO=´W²_1êÐ<ôöÐVõ<úíTÀã"=U õ Œ`@SŠ¢~PÚ€$N‹’8(C{%EëSÖ¸d7¥§Ù:ïZ1I­ËЮ5SÃiÍ–`ÎIµvТŠq`  U†uzJQ|B!$³1Qãj´» Lƒs/œ{‰ÖU@S¤zškXî½Z— ~XŒ)Z—pGw¸·Þ­Ái«1CÛb´¡ 0*ÀØÍyv³ÖEˆB=€îI˜bé¬EÅnÊÔºhs„zÝK4çMè>Gë* zx  3„z€Îê:C¨è ¡ 3„zÄ'E h]€¶bÒºInù^Ç¢bÇ‚ ×êÑ}¾1¬ZW òõˆ5î%ŽïK «\ë!÷Õ.ÏO9YÛ´B=ôJV¼eµ+J Kß»|%Mg(q,$Ôâ¡:ãñWíu..q,(uþà—ë5›A²ØÌÙÑ, @Ôê '[Êßùµø !”CÍh)ÌO99?åÔ¬Ä!‰ >ñ» €ž$˜óš&z’dȰÊO9%?å”[wM M„zèINò£d (!„ɘ›<"?唼䓬¦t­K=„zè‰ÉÐ1}´Q²æ§œ’4Ì ™µ®€õ&§w¯Ë_-„„Ȱu1lZWÐ2Õž­>¹VI‘e ƒÖбe;n.u. Né·ÀbLmɧ•²ÚÙIÚÿ!…´dùâ¡´zßÌ ås‚Óç÷~>ËÞCÛzZjEéãÅu?§'ö^n1$i[]S”€¬øB¯šó_ ¶´vi‰cá^ÇbŸìÛ÷{‹)­í*gõ’Ö€>Ôyw—8¾/q,(¯[)+þPû^çâNéã4, €¾ê!LŠÒ¬KO~ÙUíÙ*I!$»)3Á”«uEôAQu¥á%€6¥¹Òµ¦Ä±°Ä±ÐáÞzÐyŠ õ4¡@÷*=çî¸<8Ý/cò±¹wi[}"Öy~ÙUê\VâX¸×¹Øã¯<ÔlÉœ“t\aÚYѬ €Þê!8 1EÝ׆}€æãÎmkCé ›ËÞ<Ô»VSf~ÊIù)§ä$0ìÑ, @ Ôèžú:!êh.u¤Ç%{vïÜ]´=ìo-«­©·§W8—š ‰B1UØÏi– lvÿ@‹ÜÙ_# Q$~ ½k0Ž=ËÐ~êâ@Ãs{ ½ûåç%Íz£uËØÿìÚ•â™à„dgÝb0Ûd9 U™K·ØJ·X]5²k„XsÐEX,VB=ÍA¨‡ˆà €–uÏ @³ñà/mL‘ÅÆ%Iž:CékÀÏQ €H"ÔCØ8;õ„‡~¾ÚÜö• Z— >êtOQ8-ÐZ#rPé4¨>9ÛÍ5ný1Ñ]kˆæè¡"‚ƒ`ÚâA¡pç€CÈëéÎíá‰æwýj'ÔÐ"ì2&‚ÄÆÔ.Žg€^ÑSÔ§å\¯hwêê]}O=¶E¹lÂEÝ=-ôÒçóÍüâ“E?.ÝV´sçî¢D{B~nÞ‰ÃFŒ?ctÿ^}º„cFŸT^Y¡n‘$)3-=;3+;3«¯¾£O=ó¨~ÂØ 9õÜë@[Š"‡¦Ù!ûh¿æ-üæ‘gŸÜ]²'Ôâö¸+ª+×mÜðâÛ¯ûÓÙÝqOvfÖ—£(JyUeyUåo[6-úqÙ‹o¿vÚñ'ýóÁ¿g¦e´eùh§õq†Óráàæ}Ð5«ÙòÄ}7jÜ»oߌWŸBôìÚý/'7z·GçnÁ‰/Ì¿á¾;‚Ï^ë—?bȰ¹ùõn÷–Û–­üÉíqþÍÜ•kW}øÒ[…ùš®Z’¤×Ÿz>8íñy«kª+ª+—­ü釕?ɲüݲE^Åœ7fÙm¶Èn2@¨ˆª1õ$n¿Ð\Œ¾ÓÆé IDAT qÃd2MA£Æ[7C½‚ܼ¦ï¹=îûžx8˜èýõÚ[nšü“é@TRí¨yü…ïΞտWß¼œ¼ƒ.Á Nyr£Æ[®¼nÏÞ’¿ÜuËúM¿mÙ±í¥ÿ{ýŽ¿ÜöÖÅ™"‚+۴ă2„IQ‡zì= =Z²byeu•bä±#n½ê:u¢'„HKI}üž‡>ýƒç}Úd4¶hÉòòŸ™öXpú³ù_Fª` „žz“¢pe@¬P„¬zÅi9€ppIÚ§={K‚ƒû’1`|Ø»èÕ­GjrJÓ±½hg@ ‡Œ·îÜ~êÅc…Ÿ¿þÁQý8œÎçßzåËï¾Þ¹§Èb¶ü¾`…:mtÕ׿;{Ö— ¾Þ²c›«¾>'+ûø!Ã&Ÿ?qPßþM—¬(Ê‚e‹Þ™=kÛ®»KŠ““’útï5úÔ3.wžÙlÍ6kÎì¿N¿_qÿ-»î²«š.çÔ‹ÇnݹÝh0n_¶æ •úÚ{ƒûªw»ßÿìÿülëÎm‰ ‰}{ôº~ÒŸG;"TÌÜ…ß¼õá»ë6ý–`Kè׫Ϩ“O¿hìƒá}ÎÚbcã¡”iïÚ1ehpÚl°k[ €v¾6‘md6&îÁ“¿ ]êÖ©spâ÷­›"¾pI’òsòjœY–ëÝÄ#~¤ÊQ]\ºwâÍÞ^´3ØÒ§GOu¢÷Óê•7Mý[iù¾PËî’=3¿ødæŸÜ|åµS®»UMz}Þ«§Üüýò¥¡O¥gIåKVüðßwßxðö»ÿ4ò”ÖofPyeÅï[7Ýpß[wn¶¸êëË*Êý¸ì‰ûž8þ‚ªšê;§ß÷í’ïƒï:œÎ½e¥ß-ý~õú5ßÛx<ÄߨA¨‡0 Ìž00{‚ÖU€¢A¦G_Í74wŠÖ%46¨ï«Åêñzæ/^ðáœO/sNî÷û·íÚ!„°Ym‰ö„æ|d_yÙcÏýs{ÑÎüœÜ“‡ôz½Ý:w ½»tÅòÉw^ïóù ÃEc' ;jHzjÚ¦í[ÞþøƒÝ%{ž{ã¿©éêG‚<úï§‚!×G_~ÞÅyù;w­Z÷ë‡_~¶c÷.ÇÁýfñÂ9 ¾r8ƒúö?uĉ®úúï–- |ÓþùØQ}Þòà”ÍÛ·v,(sÚ™f“yÙÊW®]-„x÷Ó'_pi¿ž½-0–76Fêt¯ÁP÷<(Í–šœòÀmS¦>õ¨âÎé÷Íüâ“Ûþ|ýñC;Ô­¸-òõ¢ï¼>¯bØÑÇ4sÿzå¹âÒ½—žsÁCwÞk³6x`nEUåSÿêóù2Ó2Þ~öå½ûÛOyòåç]|õ”›øeÅ“/={Á˜sÒRR…þ@àƒÏ?BôëÙ{æ oï?>øØ‹ÇwËU×-ýùÇ1§ŸÕúm yï³ãßïz`Ò„‹ƒ{çµ7_zóÕ«Ö¯q{Üc¯¼Ð\uѤn»+8:a@üíÑ>úòS!Ä+ï½9ãÁèhccg>ݳ™Ò /H‘Ÿx\’¹@ër '—ŸwÉ”ëo ë¶|ÕŠ‰·\=úŠ ßùdfm]mØËTeùª{tjðå¤ 7óƒÅ¥{Ï8ñÔÜ=­Q¢'„xéÿ^¯ª©BÌxè±PÈ””˜ôÈ_ï7 nûóoæwí)ªw»…ÇuL£å:ä\46Â÷Þ%%$¾ñ¯/?ï’P|™hO¸áò«ƒÓ²¢<ò×û¾óÞÐóFŒãíWßœ^·qC£¥ÅøÆÆzêt/Ç>øŒNÿÕº è’$I·\yÝIÃN˜ñêóß-[$„X¿é·{Ÿxxú¿Ÿœ0jÜ “®îÔ¡ð0—94Nœ×ï+¯,ßW^¶pù’_7¬ 6ž?úœ³N>½™Å˜ŒÆi·ßÓôÁyO´cuÊð‘M?Ø»{ÏnºlÙ±móö­Á–N… v»«¾~áKjœŽÔä”fÖž“Ž;þäá'4j<`Pp¢c~‡+/¼´Ñ»;tÌL˨¨®,Ù·WÝû#õ@{wT¿oüëÅ-;¶ýß'3?ür¶ÃétÕ׿óÉÌ÷?ýèÏOº÷¦;ÕO«PS媿ÝxзÌfó “®¾ãš›3ïIÃG4C\¿ñ÷jG¢ipÒ¥°Ó–ÛBOØ0™LŒ>÷­ÞÛ¹§hÌ•^wÙUFkÎÃ:"(3=S’$EQ5CvfVEu¥Ãét{ܡΉ:ÝØè#ÔBˆ]º=tÇ=÷Üxûgóç¾öþ[¿mÙ¯¼÷æÚß7¼ûÜk¡[G#+=£ /¿0¯à¨~Ï9sLAn^‹ °Y,mßU\œ˜ñê 3^}á0K(.=Ðëí¡;ï­­«ýxÞç»öì¾ÿÉé=÷¯ £ÆM<çüF7´¶“Ñh6™ƒ ”ݶ?È Èr¨Q§}„zج¶‹ÆN¸p̹³¿ž3õ©GµÎå«V¼òî¡âÔŒãöekÚº¤‡#8!I’á°† >8"Èd4>óÐã;ï?o¼¼tÅòZWÝÛ¿ÿöÇïgæŸÔ8ÿÏÓO¾ôìˆcŽíÞ¹[ZJJiyÙÆ­›W®]œsè Á×]v•¶ÕvÈËÿÏô§®¹ëÖ€ø×+Ï}õý7£N9£_ÏÞ’$mݹ}ÙÏ?.øañ°£‡ÌzñMI’E¹mÚÝ[wn¿ýá{ßüð½óÎ߯gï»}Wñž·?zÉŠ„Λ“•\¸Ýf»ü¼‹_|û5!Ĥۯ½`ô9=ºt«¬®úâÛy»öìÜPÏ®Ýg~ñI|llÜ Ôí‘Ùl~êþé§Òã/ÌØ±{—Ïç[ôã²E?.SÏc1[®¸`â×Üd1[´ª3äO#Oyç?¯Þ6íîÒò}ë7ý¾~Óïêw C‡Ü|—»>Ñž IÒ³?qÿ“Ó—¬øaÕú5«Ö¯i´¨ã‡÷Ø=©[®™xÅgóçîÙ[ì÷ûßÿì£Pû¨SþôÏ©¾>ó6Û¬ƒkÓ„z ’$iôigžyÒi‹~Zöõ¢ïV­ûu_y¹³®¶0¿ KÇν»õ¸òÂËBãÍł㇠[üÑÜYsfõý·6o¬®©NHHè˜ßaÄa“ÏŸØ¥°Shή;¿ûŸW×ü¶þÓ¯ç,ýyùž½%¯·saÇn;_<þüSGœØèn⬌ÌÏ_ÿù·^]µî×[7Ûíö½úN:ïâ3N(BѺ€0êt¯¸nÙò½§Gü#)u¼¶õÐ!zêáö[„I}e[â8€¦öµa ì:€Îêâ—„‡Ûo€^êtOQè© ¡~¾\ºC¨‡ˆà8€¶T=õx„%€v€Paãv±B²ê¡€f;ÐÏ—]ÐB=@\á:ͧºý@gõ ÐO¿ÐÞê!LÜ| †(Œ© <ì=Øu½!Ôècêh5v@gõŒ`@kªžzì‘´„z— ¸bEÃý¡€æR=(ƒ]ÐB=@P÷ÔãO€0êáÌÁq0-)ŠjL=vHZ€;€^ê!lˆê=©€f;0œ» 3&­ €^&±šR‚'Òfƒ]ër´s<(@8º¥Žuª…PL̽!ÔC˜údŽê#Fi]ѸŸÐ4×ÑÙ7k]@˜8ó螢T¯è© þÑS {Yö½Ò.P„BI4çi]´9B=€î&\˜t²ÖU@ôpû- 3„z€Îê:C¨è ¡ 3„z€Îê:C¨è ¡ 3„z Ò­ ⡈0ƒÍ¤u €6$‹1:™6¡ˆ4IÒº@F“A‰JàF¨"L2ê¡’ŒBÑøþê€H38 ½ŠÖ—Ÿß1a’ɨu €6¢öå'Ô&-& wà¢Ý‘$!LQzJ ¡ˆ°€ÑfI$s@»c¶K²Éuñ "Ì/ÌÖT‹ÖUÑfϰø$B= [’Í,q.Úc‚9:¾„z -øÌIöT—vÄœ Ì Q[¡ˆ<¿°Ú2­ZWDORŽÕgˆ^¨gê–?ÌYWìñ¹²?jk€(óúÝI¶4«9¡ÂY¬u- æêýµ_m àÓº V¬I–D··NÖº Í-’°'´é½·Ù›hϲš“m©’Á`*­ÚRç®BQzà.DŸÇçªuW׺«UmŠfÕ€¸# C¹s‡ÇW+„°š“´.ˆ^cbRnmå6—Ö…m.9ßê1¥´é*Ü^G]}y]}y½'U’ÁnM ¾áòÔ¶éŠ@Cnoê•$„ð§&Å€x•™Ü98!+²ªMÚÄ·5#µÐ¦u@[IÉ·z¬ém½–}U¿+Êþá)³S»! …ÙCoï©ÜÜÖ@ôWnUšŒ ç¬/Ó¤¯ 2ú‡¦K+6hX kdað'¥%f›µ.ÿÏÞ}D]ÿßààXÇÞÈv°PDÀ½Wš–æÈ‘©M-G~˴̆eþ*s44Wæ6SÓLDPP!CöÞppóóûã£Oæqpèó¡¼ï3_ŸqŸã^÷ÐùøËH c©ýö.Tød±5÷"„°mÍŸ|ðd—$«;€®—]ÚÌÃ-¿<±ë#€g˜bR¯ ôž#膤l¾–™!_€V¸ðLáé±ul Ž.Ø—â'‹­™!„kcæÁfqè’soÊäRÃàÀ3%!ëzÓ‰øý:“‰‹Å¦ÛF¥å†Ž¥dlò=UU±›Û¸©‡ZÉ$êí_¿;q ù¶2™´Z\'×t,€«Í2ì¥WÇ5ê‚}ÉåÒôÜ0ºÌb±íÌ< !\—ß§×𤬫„zqmj~l?»Á] @×(¯-Ì-M¡Ë&võâšzQ!$¯!„Méï2™YèNÆÕ®‰ kÜÍ e:Ôóv™ä`éC—Ä5E74<ƒ<{M`ÊI™k0€n«k¤mm¬gþõ ãqõìõZ]”Ñ#O¦ôw™BØ„w‡Ñ\Ž6ý:þaxYMA—Å V©("é óÒÛe²—ó“?µ²ÿÑDPðÌêg7†éÎ()óBM]¡fãèžD}¶…¹‰ ŸÃ}öÃ3†Í!ÆŽ:Z¶¦ \A—í´ª6?éáEºÌåðÜÆ<*B´yú¾nÓn&'„È)ÙÕ{G^ZÕe‘¨Otê…Úú ºloámkæab`wš½A&—B’r¯L¸‘ÃÆ„Ð9øžS§ÍUyõjQºHZN—Mt½9,mÕ¶Ãå>ÝÜKYÚ2]K#׊†Ra]©DÓá(Eט÷à7ðLå¤KûqŠNØ#—?j±Þße ŸgH—=,Fú¼“zJ.—BbÓÿé5ÛÌж+ãètR™84áórŒß B_[ÐÛ>8)+„Ò ®‰N=Øw‘¦"€gÏp÷å÷þME¹›zÂß}±@ß­z†¾ýú÷í×_ÓQi«o¬o;9àg#7Ó//ÝÙïbÕßÖÔµËè,Õ²c[™Aoõ}ÙÑÊOqѾïì»ø:]Mü©¯Ý(sC—®Žž91iÇrËî5šv{›¥Ÿ¹‘›FBèA(±ô‰¾>!„c(Ñ—‹Ø21¡(J.—VÖ³9šŽž]ráñY,a³ål-GGD4ß÷zIEJØíüטÚ+.À¢¨'UÁ)Jþó¹¹™1ôK=m÷&}Îõ g©×ª¨2‹~i¤oýþËtxûùܼŒühºlkêõú˜ßÙ,ü™ª«¨ËÛuñE±TH¿4Ò·®¬- Ëz:¦ó&Fçz ¤ÊšœÃÿÌ6<~ÇÁÒçiG}i}j´‹=kÄV-.Ÿ~Y'ªÞuá½*aiׄ Ðq2¹ôÀÕO˜Œ‹Åž3ú»¦=BÈË#¾æiéÒå¼²ø‹··t]”ðÌK…Ç"Þc2zöÞK&íçrZ×Pvò¿7$ÒzÍ=†D*Ï09;”~™Wž £¥oo†ñΠÝä”ìhÄ{Y%º=âr´—LúÍÂØÕÁÒçnÚyºƒózQåýÌ¿luuL4,tk¥•iüójUm.ý’ÃÖzmÒo¶fžM—lœÔ#„Øš 2ÿ¥iI„±é—{™÷31°Rsت+¬|¸ëÂ{e5ù̔Ѿo뿤•Uì-¼sKî•V=¤_¦Fš:YÐß ´EÉOF®MÎ a¦Ì¹ÕÕv!ÄÄÐÞØÀöþÃ+ôt‘¤&!ý¬…¯¡¾fb€î-§èÖ±ËKêEôKa͹ÕÝqt³ 7“Ô#„X™ô68Ýx™îf^.—ÝIÿ¯º¾ÌÙª?—£ùžÉ)YhÂñ£á[$BfâøA︢Íu=œÆ>ȨÓ/“r®pØZæ~­¯@K…G#V*fô‚½°”yimÚÏÄÐþ~ÖäÑw+IbÆYaC…½å@ß­à‰Tx5æë+7¿’Ë%ô‹={Ô·>nÓZZå©2IÎ=|ù]±B¿:<½ñ>‹†ôÊ"Xº…òÚÂá_ä–¥2SX,öÔ!냼*¹…ÚúÒ¾T^“ËLà4mšÿg7Z'’Ôîy-¿ü>3ÅËy¼1ÛY,v£%3ÿ=ru•DÚÀLÑæ °r@ŸYß­žwÔ”cáqÛEâf’—?wôwîŽcZY­µ¤!¤¬:ë§³s«ëŠ'šÚMô{Í£WPC舌Â{—ïÊ(¼§8‘ÍæÌó£‡Ó¸vmª¢&ï—sóóz¦ÓÞȨ̈sb€g E¨˜´ãÿÆmcFÆ „ô±¶`ünfpŒFJ*3~>7¯FX¢8ÑTà2Ì÷=W»jº­´œ°;ß•We*N4ÔµXþÂa3Sëë¶‘Ô#„Ô‹«ÏE~›rªÑt=mC/Ç¡ýG8Zz > t™‚ŠŒ¸Ìл™!µÅf¹Ú¾4â+c}[6[×PqàŸåYE·™),Âòs}yŒ÷J>OСˆàÙR^›}&z3,-Økñ”!6­£§H(ª:{}ÓgM×Õ1éã0®¯ãD[ó­ož%Ï+¾“”u15ë_aCE£¹¾nÓ_ÚÀ×nû{hÛI=ZvQÜá++*kó›Îâ°¹v¦n6¦®f¶z:¾¶—"è89%“ÈÄõ¢šÚ†Êʺ’¼²Ù%É™¨é’|mÁÿ5ƒÝ_éHç2¹ô¯ˆO£“Ž*Nä°µ|gö]d¢o¯ò–àÙQ‘´'½ð†âD6‹3}觃ûÍQr# c_YÙ¨9ÃÖ²2õ°4u7Ò·×Õ1Ñáò´t ¾[ôh”\$©‰k„ å5ÙEå÷‹ÊîËwœ§ÈHßzÎèï­”íä]Ù¤!D&—Ĥœ ¹óS…B µfÙ›õÎ)Mm}€6YzWe·¾Œ®ŽÑP¯Åž tx²ÓøŒÎD|R[_Öhº­‰§g¯‰.VC,zwÊŽ G •[zï~î¿ñYjêK͵3÷ž5òkKc·vmS*ßJ>÷s³Õ&Y™z–%¶/bèN¬L= ËZ_ÆXßv„ÏûÌärxÊo¹I=EÉo%Ÿ¸—q!-ïEÉ›]ÆÑÂãa1>x £¬Œ +2[škoáíã6-À}‡ÍíÜýŠÄµEn¾rš¼.›goîceÔGWÛˆÏ3Ôá±ñû9À³B.—J呤¦A\#Uä”Ý-¬H’7÷Å‡Ãæõ^2Þ•ÊQ”üfò±»é2ò£[únek1 ¯8Nµí@w`ká“W|§ÙY,ÛÅ&ÀÛe’ßY*´ymwR!’ÔÝyp6«èvF~Temâ,WÛÀ´¼HÕ6 À°1sÏ/½¯8…ËÑv¶ñ·3ó ö^¬§c¬Ö½W¤ýw{ç½ô rJÖÊb—âªtµFÝŠÏ ÈsA°÷kºJtx¤ ‘¸ööƒ3ÙEqéùQUu…г\lÒó£:e/ .¶CÒóžê·ÁHßÚÙzp/KßÞÓµµôTÞ²êI=ER™857¼^TU/ªŠ*uµ5yß,<ç tÍDb!_G «-àk lÍ<Œômº8†ÒªÌ[É'cSO7«Žakê•WßÅQ€úpØ<™\Üt:‹°zYú ìû’_ïÞP€!•‰Ss®Õ‹ªëÅUBQŸgØf]èÎŒômêÅÕtK/¾Ž ·ÝÐvµ±mEç$õžy¹%÷’²B²‹ã2 b$ÒzfzÓ_] GÓç›ÕÖ—2/M ímÍ<í̽ÜçtÀ‰Yí IDATV¾‡¤@»å•&ŠÄµõâêzQ5‡Í©–¶½ô|m—ÃÓáêéÛ™{±Ù*v™ VHêô0± ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡AR ‡áj:€Ö”Ve–?6TÔ‹«kë˸m±¤NÓA´ÍÈÀV"òµú|3C=K{ o6‹ÓYGRºÂò”ØÔ?sKâ³ oËäÅYú|“ÚúrM <'ëA™·˜—,²4éí`éÓ×ad_ûlv‡|,Š¢:!@'H"…ßû­FXÒÒ2z<½:1jê@`kl—W‘Ûì,-®Ž·ó$ÿ~³­üTÛ8’z y5’и_¢“ŽJ¤õ­/©ËÓŠ…]@G˜X”Ô·¾Œ‹í1~ï:[û·wãHê€&É岿£¾ºžp¢äMçò¸ÚNæÎŽfÎzÚúº<>Ÿ§ËasÙ,V×Ç Ð^rJ^/®¯ ëÄuùyy9%ÕÅi&çlí?gÌ÷†ºÊoI=Иü²¤!ä—%5šnmdãmïãm?ÀÌÀ\#¨ƒHÒ”Ÿx7çNjA²T.UœÅÓÒ4x]€Ç\Qê÷K$õ@3"½¾Y±‚‹°<ì¼ÆxL°6²Ñ``êV/F>O ­—<Õ÷ˆ³ÍàÅ÷ð¸ü6·€¤t5Š’Ÿ¿ñeDü~ʼn½­úÎ<Ï@Ç@CAt5©\zõþåû—å ?sZ™ô^ã¢bFÏË~À¢¡K‘Ñ ù;ymØr6ëQ¾®¸2ýÀ¥åi¾B’zÐÊ«sއ®c^ºZöžð*‹ÅÒ`HÝ›UŸ™ƒf³È£¿‘2 b®ÝÝÓì’Hê€ÚQ„:ö?±DH¿´0´\¼„Ãæh6*€nh ÓàÑ㘗ÿÞú¾¸2½ébHê€ÚEß?’‘M—¹­Wƒ£Õ-@KÆxLp6w¡ËR™èxÈÚ¦Ë ©ê%‘6\‰ý‘y9Ös‚…¡•ãèæX,ÖËþsy\ý2§ø^âÃË–ARÔëfò±a ]¶6²Þg”fãèþLôMÇ{Mf^þ»£ÑˆHê€IeâÐ;OF¼ï5ƒc(#À5È/ Ëy¥‰ÉY!Šs‘Ô5ºÿðJµ°˜.ÛÛ÷µq×l<=—ÍÙo óòFâaŹHê€ÝM?Ï”GôÍ"¨¦ ¬× ]ž.]NË».U1³ÔuIêRr®Ñem®v?ÍÆг°YlO;oº,“K2/=™¥¡àÙ—’&‘6Ðew[O-Ž–fãèqú÷òeÊ O’z\MÏ…ìâ8¦ÌüÈ ÐÓ9¼RU]G¡*Îi:xö¹X¸ñµøõ’zBHNÉ]ŠPt&¨©ê’W’À”íM4 ´.xÂ,ã©,ã©Q÷5 <…ÅbÙšØÓeaCeEM]FRÔ‚¢äye²ú:]#ÍÆÐCÙÛ3åüÒDº€¤¨EM}©H\K—mŒl5 @ÏeclÇ”K*3é’z õ¢*¦l c ÁHz4}}¦Ìü‰…¤¨E½¨š)ëðøŒ Gãót™2“ÔÃè· rJjcê.5HD:ZÚš Óp¹¨]JGKGGKGG‹¯£cÎ×yÔO1’z õ UùÊàqt4 ¨ EQ.ǺåÓ…†ºÍ®ЕÔ€v+*® ¿6ãa!!¤¯›Ýı~½]msóJî'DDÝÏÊ)õÂú{×´¶4aV¡(jÖ¢¯/\Ž!„8Ø[|°r¦·³P(ºzíÞw»ÎÔ7ˆ9öÞWØZ›Bú¸Ù©¼#ÆÃìâ™ ¾:{1š0°OßÞvye‘ÑÉuÂBÈÚ ¿½2c˜‘@¯ÑZY9ÅãÖWBØlÖ/ç Áî5µÂÛwÓï%>\±î5œN€vCRÚG.§æ¼¾•N´mùd᪷§ki=úvIQÔÞC——®ü±´¬úŸ8°û}f­‹WbéŒ^7Û[W¿3Ð4„Îèáý§M4á©TöûñÐËnîàŽt•@Wgëûÿ7ÀË™ž˜ò oì‹çä•ÖÖ5ü²ÿŸVÎlths_ÿ–Î虚œ<ðáˆ`/fîå¸åïïÈÌ*êÐéè èÝÚçÌß7BÂïBV½=}Ý{/1‰6B‹Åz}Á¸Y/BŽœºV]#df»x“.|ú¿¹LFæï×ûåiA„+¡qUÕuÜ‘¢Á^ÑW¶1=BH7Û5ïΠˡñ–ÿëBTäÍ$Bˆ–7üâ׊=BÈØ‘â#wè颟PÐ<$õ }¾ß}–Â×ám^?¿ÙÎM‘H¤)ò˜‰%eUtÁ£o¯¦«xº;Ð…Ääìîˆal¤éÔg&ƦO7.äæ—5šµkﺰtÁ¸~½í›nSOW‡Ëå4 @WBRÚ¡²ªŽ®Ë6fÄ€–†¸ííbKRÓŸäÚœ,éƒôü¦«¤¦=šhfbØÁ1x<.×L¯SV–Æt!7¿Tqz}ƒ8üF"]~ÿ­éÍî ›@ŸzÐ IYôH²çþ¹É2žÚúŠÝÏ-xeÔ·?þIùú‡SSÆû+¦ÛRäüë:!ÄÕÙÚÍŦƒ;j“ž®Ç‹¥Âz‘âô´Œ|‘HBÑÑá9;Z)¿A€®‡šzÐ%¥UÊ/¬¯÷¤û9/wÇõ«gBnƦŸü¿+¡q•µyeû_9õ£:a—Ë9°û}‹ÕÁ)ƒÙ‹¢’ÒjºàêdÍf7³@÷šzÐr9E&ôÓwoµ¾°‘@_ñåæõóf>“2öŠг†z;¶.ôï×);R ]1‚^ó ûCRÚÁÂ\@däÛÙ˜µkݤÔÜsÿÜär9ï¿5írH\jZž¿«]Ðà~«ßyÑÔä©-:²#Õ ôèBN^Iì #Ô€vè×ÛžÅbQõ =¿ªºN`¨§äŠr95kÑ–êáÿÞ{é«O’Mêڑʘ¡<ÊÊkjjë ôùêÞ#€ÊЧ´ƒ™©á@WBEQÿ·óŒò+Þ¼š˜œM™0ÆO­;R™™©¡‹“5]>|"´ ö 2$õ }Þ]öh,Ú¯8•žY äZiùtA`¨«ÖuĬéÁtaÛŽ?%iÓŽœºVS+ì‚HZ‡¤´Ïœ™ÃùºBD"Ið„uWBã-”õêòÿ«­kPœhfjH¹JQ”úvÔo¼6‘¯Ã#„¤e,xã»:á“-K¥²uŸîŸûúVf BŸzðÈŽ_ÏŸù;ª¥¹Ãƒ<§Nð'„p¹œS? ¿6'¯´°¸bÜŒ#‚½ùº99X¦gÜK|x9$Ž¢¨¾½íÖ¯žÅ¬>,ÐÓÂ\P\Rõýî¿¢n%îgfjÈb±!,BLM --ŒúºÙ¹¹Ø0«¨¶£Žèeg¾uókï¬ý‰rôôµ+aqÁîý=ÊÊkþº•“Wj Ï·´0JËèŠjƒ­@R9v:¼õè¤!ÄÞÖìæÕÿ{uùÿ] £(*$ü^Hø=Å%û¸ÙöqµUœ¢Ë×>wdãˆ)Ö7ˆ£bR¢bRšÝ…¿_ïo6-ä©òŽ:èí×' …¢6”Je¥eÕgþŽbþ~½ìY»ýçs?üt¶÷ $õ@VÆÿžþ,$<þ“¡a×ò Êåeinäï×{ÆÔ!/O æp÷øŸA¢§«ÓßÓ)ãaaaqEÓÍÞŒM|HK@@@£Y­fnnî!CôôôfÏž-‘Hº*XeuóðžIÏÒ›¢%ÏÃ1´I½G @7øøã[_’^làÀ]Xg Y²dIPP‰‰‰@ pwwíµ×.\¸ —Ë5ZÀÜiiišŽ ;v숊Š …Ç¿pႦÃi¬ “J¥¬ö+--m´ö>*™‡ƒ"OOÏqãÆ½ùæ›.\Édê8dxÎ!©×ضmÛrrr4EgJKK›2eʨQ£~ûí·ÈÈÈŠŠŠêêꤤ¤}ûöMž<Ùßß?**JÓ1>§²³³éÀÉ“'5Kws¢###¦lll¬ÁHšÕÍãu⣲¢¢"11ñòåË?ýôÓäÉ“}||bbbÔü3 O€Ö¡O½Æ>úè£C‡i:Α™™9tèÐÂÂBú¥···««+‡ÃÉÌÌŒ¥(*66vذa{öìY°`fC}•——k:„nçD5+V¬ÈÍͽsçÎŒ3† ¦épë‚ðX,Öúõë›Nÿú믥R)!äÃ?d³ÿŽÅçóéBÇ•7n477'„H¥Ò²²²âââ;wîܺu‹?räÈÐÐP??¿N:Üçž­CRï)G&“ýþûï+W®ìq l›õÖ[oÑ_S}||öîÝëããÃÌ***úî»ï¾ûî;±XÌb±4ã󫬬LÓ!t;8'ªÑÕÕݱc‡¦£hQ„Çáp>ÿüó¦Ó¿ÿþ{:©÷ÙgŸq¹-~äuüQùꫯººº6šÿî»ï†……ÕÖÖ.Y²äÎ;xØ*O€Ö¡ùíS&L˜`ccCYµjEQš§£233ÿùçBˆ¾¾þ¹s翦B,--·lÙrýúõmÛ¶½ú꫊ñ¹†z(Máœ@×SߣÒËËëܹsôÇÊÝ»wccc;1ìgž­CRï)2™ì£>"„„‡‡ÿù矚§£nß¾M‚‚‚lmm›]fàÀ«V­ê à |em ç„Ãáh:„çŽZ•&L Ë¡¡¡*øœÂÓ 'J¯‰É„šŽày¤ÞSêêê^ýu{{{BÈ| ‰TØEQ§OŸž5k–½½½¶¶¶……ň#~øá‡ºººf—/--¥û?|ø0=åÖ­[ ,pqqÑÓÓóóó[ºtirr² ‘0í¼TâV.—?~ü…^°±±áñxÖÖÖS¦Lùý÷ßÛÌ1""bùòå½{÷ÖÓÓ>>>Ÿ~úiee¥â2çÏŸ§üõ×_ov#[¶l¡hÔp9cGŽ!„Èd²ýû÷ûùùikk³X¬FÙX•Aª]»´´4z­7ÞxƒžòòË/+I·Tí”99JžÀŽ_ ºoJ¹\~ìØ±‰'ZYYéê꺹¹½óÎ;NK{ÏIK´µµéB{ßDwîÜùøã¬­­y<ž­­í¬Y³ÂÃÛ]¸SÞ³b±x÷îÝÆ 355åóù}ûöýàƒÊËË •9Ò–BòôôìôPoܸ1oÞ<==½¦#½Òâââ4^ÇuüQÙ:///ºÀôÙ×”P(¤ß€&&&͆1yòdú\ýúë¯MçÆÄÄÐs×®]Ûh–Êo Òž‡O'^Jž*£Z? žC ²º°‚#Ó6\+<^#Áo3j‡¤ÞSjkkµµµ?þøcBHzzúÎ;Û»…ìììÀÀÀ™3gž8q"77W,—””„……½÷Þ{nnnÿþûo+ë–””444¬\¹ÒßßÿСCB¡ðöíÛ{öìñõõˆˆho0¾¾¾t!22277·½«çææÍž=ûܹs‰¤°°ðï¿ÿ~õÕWƒ‚‚Š‹‹›]«¼¼|Ú´iC‡ýå—_ öÿñŸ¦i‡öÆ<á–ñÔïwÿ¥Ö¨z¢žxõ»F¾g0PÆSjkk !‹-Ú²eKffææÍ›.\hjjªäê™™™t] >Ÿ?dȦ§§‡‡‡Lš4éÈ‘#/¿ür³«§¥¥Mœ8144”Åb;88dddDGGËd²úúúÕ«WGEE±ÚÓɺƒƒƒ‡‡Gbbb]]ݤI“N:åææ¦äº999ô÷[ŸqãÆ9::fdd\¼x1!!!::zòäÉ‘‘‘ZZZŠk¥§§BèZ9C† ÑÖÖ¾~ýúíÛ·ssswïÞ=vìØvE+ÊËË׬YsâÄ Bˆ———‰‰ÉÇœœ:rªi×µ377§óYGýï¿ÿ!Ë—/W˜…£³#‡ÐúÉQ~™Ž8tèЦM›êëë &OžìààŸŸáÂ…²²2±X¼lÙ2ssóéÓ§·ëœ´N"‘Lž<ù¿ÿþSòMãïïO§Z,--GíèèXVV‘˜˜HùøãÇßÒ°9ª½gSSS‡JÀápüüü nݺõðáÃ)S¦´ç+K…P)Šzíµ×NŸ>MéÝ»÷š5k<==ËÊÊÎ;·gϹ\njjzàÀº’”‹‹K‡×‰:ò¨TÆýû÷邵µu+‹3&$$„Ö¿ÅY111ôÇ!äêÕ«E5:tRËå7Úl{ß4•>¿”*< T8Æ®ü€xNÈ(iBÅ5楜’%WE¥Vßt5ôó5'à™k06 W:Bùeÿ?‹æ6þ!°{ê‰1wO8“Ï*$õžB·åñx_~ùåœ9s*++?ûì³~øA™u%ÉÌ™3錞‡‡ÇùóçéY"‘hÙ²e”Éd‹/îß¿ïÞ½›n®8`À€cÇŽ1 ü÷ßS¦Lihh¸yófdd$]•CI,kÿþý2™,>>ÞËËkùòå+W®tvvn}E™L6{öìÜÜ\6›½k×®¥K—2_¢¾øâ‹?üpÛ¶m111?ÿüó;ï¼Ã¬%—Ë_~ùe:£gjjzäÈ‘±cÇ2sÿþûï-[¶ìÛ·¯¿™Ÿ?þæÍ›‡ntfT;•µëÚ ºAkBBý•u̘1/½ôR£mvðZ99íZ¦#è¼Ø‚ ~üñG¦UiuuõÂ… Ïœ9CyçwÆÏçó•<'mЉ‰!íyùùù92;;{óæÍ³fÍbΰL&[±bÅ®]»![¶l9yòd³»Sá=+•JçÌ™CgôìììΞ=Ë Ë@QÔÞ½{׬YSUUÕÞo“ ¡ž>}úèÑ£„FDD0-§L™2|øðyóæÑÙϯ¾úJ#áu"••ʨ­­½té]6lX+KŽ;výúõ„°°°+V(΢“}Ó§O?sæLqqqbb¢bCf¹\N7·=âö,h~û¦*ÄìÙ³LÙµkWjjª2ë>|øÎ;„[[ÛÈÈH&£GÑÖÖÞ¿ÿ¼yó!uuu7nli#S¦L WLù=zΜ9tY…NÖxöìY###BˆH$Ú¾}»««ë /¼pùòåV‚8qâÆ„Í›7/_¾\±Z„––Ö–-[<<<!šOž8q‚þbÉçóoÞ¼©˜Ñ#„Lž<9<<œŽ¤³DGG]ºt©éWDÕ¡#:ýÚuðZ99íZ¦#ttt~ÿý÷(öghhxäÈKKKBH^^ÝëDíº,ëèÑ£÷ïßå•WÏ0‡ÃÙ¶m]K÷ôéÓÕÕÕ²;BÈÉ“'éa ¢¢¢Z¥»/TßX í õܹstaóæÍLF6wî\º*Y'(Ôéï vQíQÙ&©TúöÛogffBÜÝÝ[ªòIóõõ566&„„……5êVnrûÒK/Ñ5"µÀ½ÿ>=¦Ä¨Q£šÝr{Ïm>¹”íÚi×@<'Œx£læÏvþ°ÀŸÍzòt¥ˆüAuìñŒ-Wò–‹ 4¡’Øl–ž®NÓÿ:ÚÂzîlçõ}Ø,3"Tzõí“™ß\ÎÛW&Ê×`„mzqÊÚ¼MÿÿþËjM‡Ö6µf»ºµ&nèAÔkQPPÝùÝ_ýE7}jEIIIll,!„Çã-Y²¤Ùe\]]'L˜@¡(êÊ•+MÐÕÕeúSWdeeETþ.äàà°oß¾´´´Õ«W zbrròüùó}||¼ÍÆŒC˜<!$**ª¡¡ÁÊÊÊÑÑ‘Nê………)&›èõtttšn³½ç¶ƒ\Êví´ë? žO†Z¦Ã­^™ãüq?£@ëI§O¡2jîžÌÜz)ooiCçOÏIN§ÍÃT_wÌÝÜsrI½ÖlÙ²…þ¾ºzõj¦1”žž^Ó%é¾Ã!NNN|>¿¥ öë×.Ü»wOù0LLLèS‘–‘‘Úœ”””f·ãèèøí·ßææænß¾iïïïO7f¦ÐÍÍ:ÄjÓ½ý••’@¯åààÀ|V7kkëf϶j‡ -]»6uüZ:9í]FMìììèBç&õZ¢Ì…‰D'Ož|ÿý÷ÇŽkeeeaaqäÈzV{ÇÁliw)))‰„bkkK7´Ô¸VÎÌüùóé–-[µý÷ßé^Ì&Mš¤Ö?˜T~u„’Je‚7Þx#11qæÌ™Ê,ÏôZ Ø\”nlÈb±è¤^UU݈›BQÔ nÔJºu-[5=?5r)›Ýi÷ù€xèk³šõŠóÇÆÁ–bÛêaMü©‡ÛþÉýµ¤¡ù_O»§²òSç¹,ã©ô˜Œ˜;XÆSu­gæä=5àol\ÚÂ7¿ë=p¹©óÜq36ìøõ¼\ÞLϳ‹ßZ½{ð˜Õz6/Ùö[¸äÝíyeŠ 9¼Â2žz%4®ÑŠSfÆ2žúé–?!GO_cO9õ#BHbr6Ëx*ýÏÁ™å[åónBæâ·¿÷ |ÇÐ~ÖЉë>Üt ªº™lzõâ’*Š¢~ûýò Q«ôl^ê3è·×ì®6´tÒ¢cRXÆS¹fÓjëžZæÇ_αŒ§ò­gŠDÅé;÷üÍ2žúÊ’ošY™Ã$„ðx\Š¢ö¾¢dÊk×=Ðæ•%ÊÝ$ôI((*¯6lúúH_ÿ7t¬fôò\üÖêÝ…ÅJž™VÆxUë  ‚VÎÉú͇XÆSÆ6S‘¨ªºŽgñ"ËxjjZž’[{` ŒÖ8;;¯X±âÛo¿½sçÎÁƒ-ZD100hú„ùÎßz³Sf€ÈvåZúÎüË/¿|ýõ×M§/Y²dÏž=-mM__ÿÝwß}óÍ7÷îÝûÁTWWWVV.[¶,**Š®³Ð®Ø˜æNÌZêkË©<ÕATÎwtŸCPºO=BH^^žD"Q÷“­_ˆû÷ïÿú믤;&#„hkkûúú …ÂäääNÜÓ µsWíˆVÎÌàÁƒW¬X±}ûöË—/?þ“O>ñöö.//?yòä¦M›!æææt7 OÝÚ|T6²qãFsóGãú9:::99Y[[+9p3ÍÙÙÙÑÑñáÇ׮]c†¸¥“ztÇ— ªªêêÕ«þþþ„´´4º?‡–:ÔkIKçVM\ÊfwúÌ?]º!}-£`Ë—|MÇÆ•ý—TyCJ1*«61«6Ñ^¯ŸŸÙxK¾£ƒT’©‰Á^}sÕ®7˜1uˆž®=}ýç‡!ëÞ{ÉÞÖŒžBQÔöŸÏ­Ý¸O"‘òx\¡Þå8úÿ±}(öÎöëK«Öï¡^::¼üÂòß~¿|ú\dØß[¼=•M_ïâd]]#,)­ÒÒâö²{ô—‰¡n+kQõ;Ï|´ù X,¥ˆˆºuÿÈ©k¿ÿ²:8À½é*Y9Å+þ÷ó±ÓáôËÔ´¼Ô´¼;÷2®_ú¦Ù_¿®†ºÕ5Â7“ÇŽÀLH „44ˆ£cS†>ìZd!dd°wG“¢ÈüeÛþ8¦dÊSþhóÊ*“ÐNþuý‡ŸÎ¥g°X,Š¢ròJwÿváÏó7Â/~íêlÝmo€vióœÌz1øËÿ;“RPTnmi¢¸îÅ+±‰´¿§SoW[%·ÖÁh»ÔÔkÃúõëéÎò7lØ@wÕìŸøLOêmv™DU{éz\.wùòå¡¡¡tÍŽ˜˜¦‰1Û¼yó Úâçç×h­–Z3u%Õ¡[y¡u̯l6›ËÕä¯ Û¶móööþþûïËËË~þù礤¤ÚÚÚØØX%kW)é—MÝIÌÎòÝwßM›6råÊ•¡C‡ ''§µk×ÖÖÖÚÛÛŸ>}š©qù¬jåQÙÈ«¯¾úÎcóç϶µµmWFÂb±èÊzÅÅÅtB¹®®Žn+:bÄB‡Ã¡ ÌXt5=Òþ¤^Kžù‡Ï3€Ý–.Wh9cŽËFo“‘\öSߥsê’Îd}ÿwÎîa†¦ÂSÞÒã}û»ä”}ûã£î'ü{õŽÙÚ3˜ÅÎ^¼ùÞ‡¿ò´¸{\Q“s¢(õPòÍŸ|û»œ½ýó¾˜ÅùoÙ{;jë¦OˆÜQ—w2÷þþµ+fø puïcß®À¦Œ”vû—o6-&„ôv±I»ý ýÖ‹­ Œ°kï…5~‹¥kÞ}1;a_mî‰Ûa?ú÷ËÊ)žøÒ')šé7còìMg/DÿÕÒüäyI>^3›rãVòÕkÍ7Gãr9Ã<ÉãlM.§Â®Ç»:[BBÂã™éE…GÞ'„ŒêÕ‘Ã\÷ɾ?ÏßP>ÈvQæPæÊ*y“0V¬û¥¾^tð§UÅ~/Ï<òÇžµzº:…Åk6ìUþÌ4Ò7@»´yN¼=û¸ÙBÎ]¼ÙhÝ3GB·½g¸'BR¯ FFFŸ~ú)!$77—®þf``Ðt1¦‚FFFkŸCiiit©¦Ô[¶l¡šÓJ5½F|||æÎK—™Ä̱¤§§[µ…ÉMЩOÒB÷[­ëÈà’ÍRíº•nu~ˆÂ;ÅÌÌLƒµ±>¼fÍ™Lfmm}ëÖ­7n,[¶¬oß¾jÊ32ƒ`äää¨cûîÞ½{—/_ÖÕÕ]»v­»»»ŽŽŽÝ˜1c¶nÝš’’ü¼ŒœÕì£RM˜nõèl]dd¤D"ôpÃäqò.""‚þ‰^ÌÐа³ÒOÝêá£Ïütsº\ƒ!Óæºlìo2J‹ýTǹu)g³·ŸËÞ™/LÓTx´Sg#¹fÓýß¹çoz.‡ÃÞù후¯¿?™›_JQÔúÍ !ß|¶X—ÿ舄õ¢•ÿû…òÛŽ•¯ÍËãqY,V7Û“>äpØ[¾;I׊ª®®Z¿—2÷¥á§~äÙÏÍfÙZ›~³iñ¥SŸq¹j¯-QYU÷Ñg !¬œ¹õ³×ìmÍ8¶·óg?àå\[×ðágš®Åb‘Ðó_­|ãkK+“Íëçûöw!„\¸ÓÒŽFïO »þ$©—˜œUV^ó<7$üI2(ãa!]ËÍŦ#‡¦««ÝÞ ­ßD‰{@™+«äM¢hX g\øöWg43546ÒŸ3sØá_×Bþº”ªÊ÷‹.»”¤Ì9a±X³_JùëB´âº"‘ä¿1„—§+¿µÜ ©×¶åË—Ó}fõÕW Í&õè !b±¸¥M1½Ý5;š¤Fxz>ªçÌôÄ˽{÷èþ¿”Át˜‘‘Q__¯Ì*LonL¥­Î¢Ú!t+ÝáÔw!L³Ö´¾¤úPõÉ'ŸBØlvDDÄÀÕ½G¦ƒ¶ììlåGSÕ©TúÒK/ …ÂM›6}óÍ7‰‰‰õõõ999—/_^³f¦zcÔ”¦J55jæ¾uë!$""‚2lØ0¦4=Äm}}==:STT!døðᕉîµzæ Gàsô,^˜ë²ÑÇt,­£8+_øà\ö޳ÙÛóêR5!D&“7ú¯ø;wÀÀ>¯Í[ß þ賃—®Þ¾èßï•C™ŽÏÊ)öñv~yzâf,Gõ.,®ÈÈ*$„œ:Y^Q£­­õõ¦ElöS¿ss8]ñUýÔÙÈ꡾žÎº•OµPÑÑæÑÕ¯ÎüUZVÝh­u+_ò÷ë­8…n<Û´·8Ô‹ŽMi=ú²L×ÎäéëírãVr}ãé×" !#‡zuð‡‚TÔú @Úº”¹²JÞ$Š^œ`nöTÿõSÆ¢[ûÒù¬öê²@IJž“Ù3†B®„ÅÕÔ>É<„DÜ«©­àå̤ƒU8Ã=’zmÓÒÒÚºu+!$//ï×_m¶ù­•••··7!D$íß¿¿Ùídee]¸p.7N]á*H$ÌP›-IM}ôaiaaA˜c …»wïVr_¶¶¶}ûö%„Èd²;w*³ŠÍ£7[QQQ³ ¨<„‚j‡Ðõ˜´HCCã^E»Ã!¨ïQÅÜ$#GŽTœÕÊ9ét¥¥¥ééé„AƒµÞfg±¶¶¦Û« …¿þj¦‡ÚnåÚµkôùéšç•©ö¨T333òtRnrKsww§c///§묶·¤{<|hjztŸŽž¿ùä¹.ýÌÆó8Oý^X Ì8Ÿ³ëLÖ9uªtpÜA3_¤*Î5úÿÎÒ)ŠË|µq¡ÀPïб7Wí"„|ÿÕRÅ$ÝÎtÔ°þM3SÎŽV„ôÌò¸æÚ`¿>v6fj>¦æ…ßH$„ êkbܸæÊı~„Š¢®G'5šÕ(KE±0BŠŠ+[Ú‘Gß^–Fb±ôf죿©B#âõtu<úö ÔW,–F>Þ ÒˆàæÛÞ*O… ÊܤÕ{@™+«äMÒ:‡íãíBÉÊ)isᦺìP’’çĽ½g?±Xzé¿ÛÌtÛ[Åü]§œáîI=¥L:•N=|õÕW-5Æyûí·é—_~Ùt$ Š¢6mÚDW ˜1c“.QŠ¢–-[¼}ûö–ºðËÉÉ9uê]fÚ|…cùä“O”ïS|ùòåtáË/¿lv-¹\.•>©àjkû¨÷ʘ˜f€Æþýûþùg%wÝ”j‡ÐÅ˜Û 77·é\BÇ/PCCƒâgüý÷ßt‚ÇãÑãÏ0Z?'«õ®-«««é¾Ì:3ªæÖ­[› —Ë÷îÝÛé;U ÓDÚÐÐP³‘¨UG•jBï"11‘¹ ‡ÎÌe±Xt /<<üæÍG=‰tbRtƒ‡M}Oƒnr€@Óæè4›8Ïeã ³IÚœ§zô/ªÏ¼óÓŸÿ/»ö>!Ýk´J sÁº÷fBf/xeÔ ß§†A£«,mÛñ'3)óÿ—ýÿÇéüÂ2BHoWµ7l àhD—¯meaÌ,Ó:-.—´Úi‹Å5Ô›<®ˆ'—Sa×ùºq¹œ@ÿ¾„¦.f9´ùQ2:¢Í Û«•{@™+«äMÒ&K #BÈÃìæëa´®Ën%)NfÏxª®\N½p“(´½m×Öz4Œ~«‹µmÛ6??¿‚‚‚sçÎ5»Ì¢E‹vìØŸ••5lذ³gÏ29‰DòÎ;ïìÛ·Âçó7oÞÜ1‡††ÒuW®\yðàÁ7Ž?žîëBQÔÕ«WW¬XAÇ9|øðAƒ5=–ÊÊÊ€€€cÇŽ)Î%„\½zõÔ©S;vìPÌy/]ºôÇÌÈȨ¨¨ð÷÷?uê”bO)))K–,™8qâúõëé)†††ýû÷¿{÷nCCÃG}´sçNº}™X,Þºuë† ´´´Tn¥Ú!t1f4äÇ¿ÿþûÌÕ¡iü:~ÒÓÓ¸{÷î!C†0OŸ>=þ|º¼råÊFýK¶~N:—¥¥¥……Eqqqlllll¬âí9þ|u4´|ë­·víÚ%‹£¢¢fÍšuðàA]ÝG¼ÖÖÖ.Z´ˆI5Åœ u4ˆnŠé(óСC6lè‚=jDG•j2vìØo¾ùF&“8p ®®ÎÐаQ+õQ£F=z4""Â××—bnnδîøÐÔ÷4è&ÝEÈ“·¿œ’É)E(ŠP„PEE(B=žøèË,¥¸˜.×P±Ï¸ZI¥H.4Ô2UœX).ÉêL´m'–6äŠdÂæ÷H(Šz¼GB‡~²˜ƒ¾‡bRìam‚PZíf觸ñU1õ²ã¡Ö“o‚ ábY=E(ŠÈ)òøß£ã¢ ÷Nï<ÐòEÅíDŸiÕŽ²ž¯x6C S„zz"u1÷W…y²Gcže´ªNZ%§žtTRÜ}1÷s{_³ñŽúŠWGƒärêü?·èrQI%3l=Nnô÷tòìçÐìê}{Ñ!#žÖz†¬³’`£‡8rêZØõ„×ÌNHÊ*¯¨èAäE·Æ-(*OË(°µ6uqj&ÍÔÝ´r(se•¼IÚTSSOQ­Æ®¼”¡ü9™5=xÿŸ¿tS"‘jiqoÝN-(*Wl{Û®­õhHê)ËÇÇgáÂ…û÷ïo©*Ç;}út```IIÉíÛ·ûõëìëë›™™yíÚ5º¢›ÍÞ»w/Ó¡Z9ò·ß~[¶l™T*6mš@ ðöö¶¶¶®¨¨xðàÓvÒÆÆfß¾}ŠO÷çŸeff3fàÀVVVÉÉÉ111tSµéÓ§Ó5ÒôôôNž<9bĈêêꬬ¬€€Š¢¢££cbb¤Ré­[·,X`oÿh¸ŸU«V-\¸òóÏ?GDD ©Ý,§ä5’2żÌãTˆ\q½ì£:E(.›g¡ó䛆”’ä×=Ðæð-ùNÌD±¼!·.™Ï1´Ö}ÒƒD½´&§.™"rò(úÇéÅ=>NEQ„0 xfÎO~?¨‘”%WF›êØ(N,$WE[óœ ú3‹ê³Rª¢²?„Ù»BâIN5Ù»ƒ¾g?£'¿ùåÔ%ß-»ê&ðë#ÌLL¯¾_æa<ÔÍðÉoI•‘‰Tk{|t.íqùdw£@f;·Ëþ½Sve¨å˽OÒú‘E§ã+®³]¬xŒ× ¥T5cQãí–8ê?iBx³ôüƒª˜)½Þ¶Õ}R'ªølVm ÇÕæ:OÆ9½Q|Fµ‘"^rZ«x[Þ-»ZXŸa¯×G1©w·üj™(¿·ÀŸÃyrWß+©‘4n–¡ŒÁSßÕquÒÊQÖóónkâ)Bë§VÌ®½ßæÆÙ,¶œzòÍ«¤!çRîSm?³ñŽÞ,M§ö»y3é…‰ƒï&d^úïöÉ¿®¿<ýI!kKcBˆo—ßv¬le#–æFD¹6€ô i'wÊLÇ™Ù\ÏbÂzQAQ9!ÄÆÊ¤Sö5j˜7!$êV2=î-yœÎ³0xös¸y;UX/ºq3™2r¨wø]­•{@™+«äMÒ¦Ìì"¢êeêÊ@ùx”9'½]mx9ÇÅgDDÝ9ÔûìÅ›äé¶·íÚZ†¤^;|þùçÇŽkeWW×èèèY³fÅÄÄÔÔÔ\¼xñâÅ‹Ì\ ‹}ûöMš4©K‚%„Å‹þøã7n4ê³lÊ”)üñGÓª7mž“Îõå—_^»víÎ;µµµÛ·og¦;;;ÿöÛofff[жvíÚºººÍ›7SUPPpüøqfÖ‹/¾¸wïÞ^xîI­©Y³fÑísüñGgggµ&õÁŸþ9nÜ8:“Òt‡3~üøÝ»w÷êÕƒæêÈ£Rø|þСC¯\¹Bÿ¤Ø¡ÍÉÉ©W¯^ÙÙÙ¤³ÛÞÒ4þð!j~t‡8˜¶®rõ¸‚QÈp=• R\K‹­ýZﯧì°^k8ßu3E"ýžö‰Ïr¶ó‡ÌÄzYõÑŒ/TˆÓDÛúe§uO¶#­¹˜û‹ßišÃ“¯%5’òËyûíõúYë.g&VŠKB «°G}§“z·Ëþu3ôk”é‹/•K^Õâ’¤ÊHÒ~ZO}KJ«ó„©ü§*Se5Eõ žj…W/­-å«°G©ü©±ìä”L*ËÉÓ)ºZJãfž*&µD{œ„zz"«™‰¶Çæ§Y*ïñ©ê÷ØææX„°ÚlNËfqåTãë¤UÕ’2%å²49@yUuÝŸìãr9Û>_÷`Î’­ï}øë„1~úþ<p?t,$4"ž®FÔÒv÷ûãdXtLjqIÝ+YKÌL +«êÊÊYP[×øË)=ƒLÖZ?3 :Îè˜Ôʪ:#žâ¬Ë!q‚ôï§Ì¦Úää`éä`™™U”–‘=:IK‹0èÑŸ²#‡z'$eÝŒMŽM%„Œüöî< ¦ìø÷¾ö}GJ¢ˆRi‘ˆìkÙÙ·4ã7cg¬ceÄXÆš-ED”½‘"IR¡E{i£}}÷÷Ç5×óÞëõÖJ¾ŸñÇ{Ï=÷Üsîëu¿¥ãê t›’Àûà§eù|HxËÉ+z›L]‘ÚÓbþËÃgL™Ø?æuJÐçƒú[ß}ߎ½4·ïΩ'==½Õ«WóNÓ©S§ÈÈÈK—.M˜0¡}ûö222ZZZýû÷ß»woRRRSFô(¦¦¦·nÝŠ‰‰Ù¸qcŸ>}:tè ##£ªªÚ½{÷ „„„„††6ôšj``ðøñã   éÓ§ÊËË+))uéÒeΜ9ÿþûohh(×ah=zôˆ={öìØ±c©ÐÐа··ß¾}{jjêÂ… ÙºÞ¹sgçÎC‡ÕÖÖ¦R=zôéÓ§ÆÆÆšš¢þM@¸[hJÓ¦M»{÷îäÉ“»ví*//odd4eÊzà64÷-ˆØ@L&sÉ’%ñññ+W®ìÛ·¯‚‚B»ví&L˜pãÆëׯs]Hø¨1RTTŒˆˆØ»woïÞ½ÕÔÔ455ûöíëåå;`À Í}IÄ–-[¢¢¢æÏŸohh(''§££3|øð‹/^¹rECC£cGîýÃ`Ïž=Ó§O×ÖÖÖÒÒ✻S¼H’Œ‰‰ Þ½{síU__óæÍaÆ•••I´0’&ÊJI`¹uB= ATg=Š$‚zÐÜ?|(ýiÐn5½êúŠêúŠšúÊfU-³º–Y]Ǭ©#këÉ:&YÏ$™$09 œ1‚c'×xðn™7pÅo¯'lß–®Èž=pN™$Ö+r\ë…» °GÓ€Á™9סG·Ì%yEîñ;öcp¦o¯7ŽØ"ƒë‡¨QlqX9)E;çiF¿[jnÞˆlöôý˜ÿù§¹£Œ;ëN™ÐßÞÖ$;·è÷?¾†Ô'uPV’OMËÛ{è|&u““)¯¨Ú´Ó‡­ÞJJ+XÿW·­&<‰øfÉ‚­»ü¨XQó å~,æ'¬3yœƒ²’|IiÅž¿X÷WW×nÝå cFÚñŽ6 „Z7:6ùID‚uE…/à§¢x#â©e4øY%C Û”ÞÏ?-ËçCª¨˜ýWî{.ÕÔÔèëLpþÒ÷¹%?VÛ IDAT¨N\Ç÷€·Ÿed¼ŠKe{+hn߯V­õîڨ͛7oÞ¼™wƒáâââââÂ祵µµyÏ(Ù­[7§œ´´´´´´Üºu« 'áäääää$ÐYÒÒÒ3gΜ9s&?‰Ö¬Y³fÍ®‡¸Þx£5ÆJ¸[`ÓÐã!–¶6lï^Ý?•#P Ñ@4jƽ:PëGó¯Ñ:a#JCÈÊÊ._¾|ùò圇444„{ùiwkkkjì$§óçÏŸ?žë!uuu®‡*’(EݶmÛ¦M›tuuïÝ»gffÆz¨ººº°°044téÒ¥ùùùïÞ½{úô)&“Dñø$P´Qˆ•|~wê·ß~£Æh7äÔ©S§Nâ‘@,uËÿÉ5%Ÿ¢_T,_èû"dä‚ãAâŒñwãï‚ÿ»"³‘tBjðv8vŠëzüfÎ))B†j ˆ/T>µM_êËQ† ÒÊšrºlË2(Ëh¶Qè(Ïøf§º\ÛöŠ]øòߗ̉®ƒ €P’Ñ`ÍGWјAH)IózÜQÙLYFCQ꛿t«Y·QèÈrE½ýß}QìWWþöŠ=5‡˜¨ÙÉK+³î´Óq®aVÉ~[Žº®uÌZ–œ ¶+þwËÀ ¾|¸Ôê˜ÿc“ñíd²ájÎ̬.Û¿T Á€ÿš²°&;ºànzY[$RVJÁRcPMG¶b7—¸„´¿ÝPV’߸j*qàOÞCW8z}¶Ûàžæ@KSeû†™K×_·õìÇüOk–º´ÑQ#I25-oÿ?×G ±=ÌÚ¶Q_·ÜuÓNŸ¼oUTV¯_áÚŨ}vnÑåÀ'›=/ü{ý+‹/ãëGµ{úæ´oÈÀ~æÎ#{*Û{ðš×‘@“.zoßg±Ï´[ƒøô¹üØ™Û?ÍUYUSUUù¶)ESãK9wì½T_Ïüe¡³n[͸„´_Výý*YQAÎsó1VÝ–'ÎÞ½‘™]0kê׿JpèAÄÃ'qQ/ßèëtêØ–G&nSì}øiY>VÛvû¥e|\·Üµ«qû¬œÂÝ€?~Ÿ¥ /+DÍ4ñÐ(ꤳa»^Ö]žG¿ßwø¸Nè'tnÊÊ ‘UÐT7*NÔCIJ}½˜gý@M&%%…Šmmݺ•-¢rrríÛ·Ÿ6mZAAÁ’%K 11gCµ|ª²ÚÔìûT/-‚5ô_d%^CÅ-)Ž>AúJÝØ‚ Áè¤b¡øm¼Fš!ÛEÕö¿ðÓ×+²Äe¾^ñkHèÛ‰ù@VJÞV{”²Ì7C¤UìÛŒSýv«ŠŒv¿¶“ ‚AåÃr•/Wg‰×ü‚ ©o®¨)×ΩÃÏlÅh«`8®ãEéoÞ ;(uŸd¸’5.C_…ýŠ_‚O_öH3dYó1Rµ2T1g›»ÐL£Ÿ©F?¶ØhO­!=µ†€ÈLÕLÕØvšk8šk8²í´Ôd©9Hô+š¨Ù™¨ÙqììÍ™²›š½è—e.ywPêÆ¹SO±«X®¨*Ë¥_?Û£K‘—úf _auö‹‚Û©¥¯ÙÃy ysÍše"MË#¨+×Ã¥µÇqîWSU*HöùeÕ?õõÌU‹'Ñ=˜zYw™7cèÉs÷~^~øÉÝ ‹=Æäæ{z]Þw8pßáÀ¶mÔËË«ÊÊ« °¨”Ž&¬_áš[xÔûöY¿Ïúý« /[YUêÊY9…tPoáì‘^G®ç|ž:µGJŠqêà’OŸË—¯ÿæïÄzºZn“øø‡.Zqdý¶seåUK~³{뼆nv±Ç˜ªªšøxz]öôº,//[UUúíµÏ[ajÒ¡¡…0¸¿%\ €_g¹ÑÔP±ìÑé~h LÓ—ŸNǂަ@x<…)H’äçà§eù|Hh}zuó½òˆ57ذrŠÛ¤¯;Zò ×íÞíó—ü4¬“)ú?~ïuä:pŒ½¥ïŽŸÜ¬Ì;ß ‰þëÐµššº¿wypæÓ’aP!„»'OžP1ÙîÝyM¢‘žžNmHtv?„×N\:ž a”þB¶=R„ôp=öW&Y†üàö3@d² yíl;奔8#MŠÒ*f\Þj%'¥¨¯Äþƒ]NJ±ËJôN¶ÎnÂaR ‚séÆïaª|$šâêܨ‚Û©¥¯ØúiÊ0äzh8ZjË&®Cë뙯†=|×FGmùÿƳúcãì+×Ã#¢Þž8{gᜑ@ÄÎM³GÚ:/úUò»¤,}¦g¸;êkxWJŠqdï¢ñNö>—¾ŒMþþ±—u{ÛnëV¸Pã()ÚZªÏÿýkéÚãÏ^¼++¯²µ2Þ°rÊ þÞ>÷9ËyòïÅmÛ¨ß}ž•]ØËª‹~{^ LñÛÒÉÃYy |“”ž™ß×®»ƒ}÷uË]Ù&Y]5sSÃ×ñ¤¤ôp”ÁŽ1¯S`P‹Îf'Ðm ª¡ø|øiY>ÚÌ©ƒNü½xûn¿°§ñL&Ó¾W·…³GŒbÍ–¬Å>®uKwQ¨N\'ô_¹ñI’=Í;wÖåÈ•ßÜ–ÿoü‹WIO"²s…Y2¨y"ŽlB!6:::`ffÇ>Íú.ܼy““8mÚ´3gÎHKsù Ppp°‹‹Kee¥©©ill,Û ­!oRïž½»ˆÚe1f`w1t°BµŸj>¾(¸\ò’-œ'Í5Sï×Sk[o>„~dýF®~™°ßsáb1Í]ÔlJ«J·n¤¶M ‡Îñ`O=„Bœ†Ú£G¸¸¸ .¤¤¤¸»»;88´k×NZZ:33óÍ›7ÞÞÞÁÁÁ$I¶k×îòåËÑC!„Ÿ>×ä¿(¸“TÍ6)¤4CÖTÝ¡§Ö)å†ÎEèGÆd6Ûj¿¨Å B!v²²²¡¡¡cÇŽ ˆˆˆˆˆàL#''7kÖ¬M›6Ihmb„Bµ2%µ…ÑwÞ—D1ÉobR„Œ©zŸžZÃØ&mD!ÄõBq¡¥¥õøñãðððóçÏGGGçäääåå©««öìÙsÁ‚Ô8k„B!ÞJk‹¢ ï¾ûüœZ¬†&EHwS··Òƶ.0B!~`P!$fÚÚÚ8Ygë@„ƒƒƒƒûâ€!„B|*«ýô²ð^âç¶pƒ2Qëm­5œëò¸!„øA=„B!„BbV^÷ùeá½ÄOõdë~!ÕU­—µÖpÍæ*BµÔC!„B!$6u¥1…÷â?=­'kY÷3FU[kíª2ZÍU6„¾Goïjî"  ƒz!„B!„Ä ²¾,¦0$þÓ“:f ë~ƪÖ6Ú#ÔdqB^„ ê!„B!„Ud~Ð뢇l½ó :«ZÙjT—mÓ\C¡Ö ƒz!„šNll¬º:N‰-Y©©©222úúúÍ]„B?ʺRÖˆD'K[í‘ríš±T!ÔŠ1š»!„~555&L000ˆŠŠjî²´fgΜéÒ¥ËêÕ«›» !„~,ÖÚÄT,&uZ5LoFô$ô¹šÐãu$°¹ ‚P3àBâ”™™Ù§O%%¥)S¦ÔÖÖ6~Öùwäøñã))):::–––Í]–ÖlРA Ã××7&&F,â§ !„?Te´LÔì:*›M2\1\ož–\ûæ.BµrÔCHœ<QQQqéÒ¥›7o6wq~MVç<˜?¾ƒƒƒ¦¦¦ššš©©é¼yónÞ¼Éd2%wÑÖ¤¬¬lÛ¶m°aÙ†’ÕÕÕΛ7ÏÌÌLSSSIIÉÔÔtÖ¬Y÷ïß'I²¡³„n–Ù¬ÙÙÙk×®íÞ½»¢¢¢¶¶¶££ã‰'êêêø<ÝÀÀ`îܹ°víZ±”²!„âSÿv.#õݵåqþ„j ÔCüJOO'‚ ˆË—/7wYZ.Ö™Â444ØŽ¶Ì:”P©šìfy×¹X$%%9;;<øÔ©SáááÅÅÅ%%% ÞÞÞNNNvvv’¸n+süøñ¼¼<##£™3g6”æÞ½{ãÇ÷ööŽ/..®¨¨HHH8wîܰaÆ ’””ÄvŠÐ­Ób›5$$ÄÂÂÂÓÓ311±²²²°°0,,ÌÝÝ}ðàÁ|f²víZiiéÛ·o?{öLô"5Á§¬‰µÌŸÆ!Ô ø‚‰BMÊ@ü***jî"|/^œ™™ùòåˉ':::²m™u(¡R5ÙÍò®sÑ¥¦¦öïß?77—ú_ ccc))©ÔÔÔ/^$ùâÅ ª#Õ¬Y³Ä~õVƒ$ÉS§N€‡‡‡´4÷¯//¯eË–ÑÿÛ­[7…><{öŒÉd>xð wïÞ·oßîÕ«•FèÖi±Í?~üø²²21bÄðáÃKKKÏž=›’’æêêzçÎýi†††NNN§N²³³±T’þ”5½–ùÓ!„B!`Pñ«°°°¹‹ðPTTš““³iÓ¦ãÇ×ÕÕ)**Òû…nÛ¬‹-¢"zýõ]!+W®tvv }ðàÁ©S§<<<øÉÊÅÅ%00ÐÏÏoß¾} ¢”JÒŸ²¦×2#„BH ø8BÔCüÂ~ ¢k™uø½÷Ô“¨ÔÔÔÛ·o€²²ò7ôôôX¶mÛÖÓÓsòäÉ=â1¤ÀéÓ§ÀÖÖ¶S§NœGãââ–/_Nmÿþûï›7ofûMWW÷رcýúõkÓ¦ ìºuZl³†……=|ø†ºtéRz¿’’Ò¹sçºtéRUUµcÇŽ HII5šÛ˜1cäää>þ|íÚ5777 –û;Ô:~@!„B­Ø‡ô»ö_yñ*).>M]MiäP›­ë¦ëéj±¦‘••&Iòô…Ã'oÆ'¦ëëi`¹kë\%EyÖdùŸž¾tçùûäl’$­-æÏî6‰}ðA¿‘«ŸD&ä½;¯£­êísÿÈ©[<ò€ªêš=_½~+2.>­²ª†íhÎÛ³íÚ|™´äELÒ£7ž>O,,*µéi4vTïEó ŒH"1À â¾‰®eÖ!õxˆŽŽ¦6ØB?4[[[[[Û&,Ô÷‡$Ij沆ºéýöÛoÕÕÕ0mÚ´-[¶4”ÛHX¡[§Å6«ŸŸµ1wî\¶°¦¾¾þСCƒ‚‚222ž>}Ú¯_¿FsSUU1bÄõë×ýýý1¨Ç¦uü€B!„Z«ãgî,_¢¬¼ äåe³s‹N¿p#üa°§…™!Œ$aÆÂ½.?¤þ÷]RÖ»¤¬—±)Oîì¢~•"IrÛî‹»\¡³ªªª yø*äá«÷ÉÙ¿¯žÊyé´Œ‹×½ÖPž”¢âÒ>ÃW½KÊRWSêmk’–ñ15-:ulk ¯²2ÒT½±êwïÚÚ:YYi5U¥{b¨½WËËÉJ¤úÐç1e÷øñc®]»*))©©©YYYmÞ¼ùÓ§O¬i‚‚‚¨ ¶,XÀ5OOO*çx¥‚‚꯯/Ô×ן>}ÚÆÆFNNŽ ˆ«W¯ò™†Æd2/]º4vìØöíÛËÊÊêêê:;;Ÿ?¾¾¾¾¡KûøøP{ž?>kÖ,###%%%ww÷ÄÄD¶³’’’¨³~úé'j‹‹ Á‚Ÿ_¼x1cÆ kkkeee--­Þ½{oݺ•Ç;ÿ7ÅŠŸ¶šO ¶ëÑ£}"?uxìØ1j›Z³²!–––A())•——óHFá]í‚¶ìË—/7lØ`oo¯««+++«§§çêêÆvQA³®­Yq­sþë7ú›[èµP%÷0Kú‘ˆ·À*--ëÊu:¶øøxjAUEEE///>óZGôf•àà`’’5jçÑ1cÆPAAA|fØ¿ˆˆˆà±p0?$ú) I’®®®:t““kÓ¦ÍÀ÷ïßÏö£R,ßh!„’¨3¾! —,+¯ïdÿ:ü`yÖåÌøÓ«O´éiljÒ5åo›¼¯=õÚéžx&+á̆•SàéóÄÅR ‚HNÍQT”ûkÇ‚×áË2ý‹R}W-ž;ö^ÌÉãò»ŠÓ”-×oFòÈ“òóŠÃï’²;Z¤¾:ùàÆIÑÇ·­Ÿr²2w®l Ú©©¡×o=[ºö¸¬ŒôÉ¿—føç½;—øìkK£ë·"zß–Hõ¡ õ¾***7n\ÿþý;öþýûŠŠŠ’’’˜˜˜-[¶˜››ß½{W¼—+..®­­uss›;wntttMM XXX”&33ÓÁÁaÊ”)7nÜÈÉÉ©­­ÍÍÍ ž9s¦ƒƒÃǹ^:??¿ªªjÉ’%vvvçÎKII©¨¨ˆŽŽ>qℵµõãÇÅx›$Iþú믶¶¶>>>/_¾,///**zöìÙ¦M›ºtérèÐ!Î7(!nª¶ ÜÜÜ”””àÊ•+\Ó$''ÇÆÆÀرc©Ä ¢Úyxýúõøñã­­­wìØ™››[[[›íïïïèè¸cÇAnôÂ=Àü½¬­­©ðððÌÌLA Ð f±´µŒ,AæææœG/^¼HmL™2EGG‡ÿ Ý:"6++[[[‚o{öìá‘UqqqZZôíÛ—ë ³t¤/&&†ÏâõìÙrrr222»1¾‰ñ§ÐßMééé}ûö4i’¿¿fffMMM~~þÇ—.]Ú¥K±jB!$9%¥Ëן€i“\9»®G÷Ž ¡§«µkËÜ;W¶JK3‰¢¢\hÐÎ%?Õm«Ù¾æ¶õ3¬-àæ½(:Í_;$¿<±lѸÝ;JI14Ô•ÿÜ<Ǭ›AMMïåGœ h4ÏŠÊêËOàøþ_ÕÕ”€Á Ö-w575L|Ÿù$2N¶dÍ18upɼÃde¥ ‚0é¢wùÌZ))†ç¾Ë55ø×D$*~ûE^^žƒƒCrr2Púôé#''÷äÉ“èèèÌÌÌ#GŽ 6ŒßLœEEE+W®ô÷÷sssMMÍ>°Í6Å;MFFFß¾}©7R++«áǦ¤¤Üºu+...22ÒÉÉ)<<œsĤ¤¤Q£F…††ѯ_¿Ž;¦¤¤DFFÖ××WVV®X±"""‚¾SãÇ€ŸŸ_HHxxx°ŽJc0x…†9BõRUU]°`™™Y^^^TTTpppQQ‘ŸŸÛŒïBÜTËl;VüÔ¡ŠŠÊ´iÓŽ?^ZZÈu¬ÝjêT.ÅYñSí|¶lTT”ÕͧmÛ¶C† 144,,,|üøñ›7o`Æ #FŒ Oäÿú柠§Ž;š™™½y󦼼|ôèÑW®\éÒ¥ ŸWo³¸ÚèéӧеkWeeeΣÔ,r0~üx /tëˆÒ¬’óöí[jÃÀÀ€k===ƒÁd2øÌ“ êÀÓ§OÊVD¢Êh}7ÑRSSûöíKuUPPèÓ§­­mrrrXXØÇsrrFíëëëââ"£!„BHÒ®\/*.•““ùs˶Y礤ؿ¦[2ÙΦ+ëǾ=¢_%gå|]KKS…í,‚ ö3“˜N ˜"ÏØ7˜LR[Kµ³a;z'ƒAØÙtyÿ!á]Æ`G ¸––ñÑÊ¢³ËxÖ ;ul;¨¿ÅýИ”´Ün]ô® „‡A=&“éââB½Hkiiùúú6Œ>ìéééíí-Æi zöìYÇŽ}||MS__?eÊ”ÌÌLƒqøðawwwúUdÇŽk׮ݻwoTTÔÑ£Gùå¶l:={ö¼xñb×®_~`…„„8;;WUU={ö,<<œ¾œšš5¸/..Žz:thCcqÚµk())=þœ¾¤¦¦nÙ²eûöíÒÒ_B!nªÅ¶+>ëÐÝÝzÛ|ø0xzzR3¦ñ³¢<Àüèñ㊠ˆÓ§OÛÛÛ××׿~ýÚÜÜÜÃÃcÉ’%;wæ}b+x˜ÅØF/_¾KKKÎC$I>{öŒÚîÝ»·@…ºu„>‘“Oee%Ÿ‰Û·oÏã(Ý™NSS“kƒ¡¡¡QXX˜‘‘A’$?O‚¶¶¶¾¾~fffttô”)Sø,§@Dÿ”Ñún¢ÔÖÖNš4‰Šè™™™R‡ª««.\xöìÙúúú¹sçZZZvíÚUÄo4„BIÚÃ'qÐÛÆD¿½v£‰9ךh££yÙ§`€ŠÊê—±)±oR_¿I»ò2³ „Ë“š/¯¬¼ª¾žÉjü\RtÉ…ÇÀ`GKÎ_Û¨h`rjõˆð/ÒþþþÔÔ` Ïž=c}‘''§°°0uuuñ^422R]]ýÎ;<¢B<ÒøûûS_¶mÛæááÁÚ¹@FFÆÓÓ“Z ’ qrvv c}2dH ò®¾UPP@&sttd½têÔéôéÓúúßüâ¦ZlÛ ÁÖÖ–Šzܽ{7/ý¯F999ÔƉ'ÊÉÉñÈGÐjç ??¿øøø©S§²¶ˆ””ÔÞ½{µ´´  ¤¤„ÿ=}út(//ÿý÷ß* B!„šEvn!t5æõ§Pd¤¿,OÁº3.!í×ÕGÛw›ÝoäêE+Ž\¿Éd’P[Ë× Ñœyš›vlÛF½ªª&èÎszgaQé¿b ‚ †ëÕ¹oïÁ«„ƶÇN߆‚ ƒzôÔì+V¬¢§†Ð6nÜhbb"\šýû÷€¶¶öo¿ýÆyTZZšz“IHHàœÏ¨S§N×®]ãçääDmdeeñwPRR’••€wïÞñ3§¾7Õ’ÛNPAPãÔêëë©å X]»vú"itì­ ÕÞ(®ã+ååå‡$I¦§§ ”§(0ŸÄX£Gމ‰™3gŽ””$yãÆáÇ›ššúøøpͼ<Ìbl#jÁ555ÎC……_2p=Ê!ZGÄ%„^ÒGP>TZZÊg¶TÅJh±Wñþ´⻉^fÍš5ªªªlG ‚ؼy3Õ¾—.]¢:ô!„B¨%£Âmb›rðxe¿_Ÿ vìkvÍgCAò…ÌøÓs¦ %Oé#{À‚Å®\ÿ\Ró:eÜ´mEÅ¥Ëë ÷¥§´ìÑiºË@®ÿ̺IdvôCÁ FFFA+W®l²ëjjjÒ«ï š¦¨¨ˆ*ó¨Q£¨×NTO‡ÚÚZª+EEE®gµk÷eFqõ¨Å.“““]\\xÇ}„¸©–Üv™6mš¢¢"œ;wŽí5¡žŽŽÎàÁƒyg"Pµ‹‚ê~Eè*">À|o=tìØÑÛÛ;))iÅŠtø)11qÆŒVVVïß¿gMÜ f1¶I’TD‰k7CWe¥Ô:b9Qè¾<Öä¥güOýFU»„‚zâý” úÝ”ŸŸÿâÅ ••?>×<©ù H’¼ÿ¾(ÅC!„Ph«£É©9bÉ-æuÊâߎIIIœ[Ýwã¸Ñ½9§ØÎx'û= K&ÏÞ©Þqª•ã’'‘ ?͵}ÃL:n[ °¶4:l×½mÅÜMý€0¨qqqÔ[eÇŽ…î*"]]]áÒ¼~ýš*ó¹sçZf‘ž$(55•Ï"Ñ9ÑFDwòäIj©«W¯vîÜÙÅÅåÑ£G\_ã…¸©–ÜvÂQSS£æ½ŠŽŽŽ§÷?xð\\\ø™ ŠÿjHuuõåË——-[6lذvíÚµiÓ†îQ(ÐJµz€9‰½ ÷ìÙ“™™yàÀz ßëׯíìì¨1€Bß`K{˜ÅØFeeeTW>®÷Ew=ûôIÔÑ|¶ŽO/zIkº÷"'ú×%G¸¢‚z<ò‘„~Ú°j軉Z«:uêÄãgr÷îÝ© jõp„Bµd}{w€È¨wó?‹ž[À§$Id5n´`s77jïÁkŸÄyZzçÊÖ­ë¦Ý÷¿Ø'ùk‘‚¼,¦Ÿ½)„>~][‹«Ü"IÁ Þ×`„ØGSJŽ@z„•° IDATþßýÄ;?ÅÀÀ ""ÂÕÕêëë/_¾<`À33³þù‡mÈž7õ=¶]£.\Hm°vÖ ¢ª«Ñ±·þ«OñññË–-kß¾½‹‹‹——×ýû÷?}údmmÝ­[7!r“ÐÌIìõ@é×_}ÿþý?ÿüCøûôéÓÂ… é^T­àacÑ}ʸz”••©9"«««³³³)cƒ…áÝ:â=ñíÛ·1|ã]«t5òèUGÅæ¤¤¤äååyߪvÉ-ê*¡O«†¾›èúä=\ÝÈȈ-=B!„Z¬ÉcäädÊ+ª6íôaûí±¤´BÐܪªk@Uå›?þUTV?i@I’‡Okj¨Ìv<|°ÕÆUSÎinjÈ–lÒXe%ùÔ´¼½‡®‰r9„xÀ Þ×N 1kè2OŸ>=§1666Í[Ú:\¼x1&&fÑ¢EÔ[kBBÂÏ?ÿܳgÏwïÞÑÉ„¸©ï±íÕ»wosssðññ¡oZ÷V__Ÿÿ¥9ø¬v~ìÝ»×ÂÂÂËË«¨¨ÈÞÞþèÑ£ eee/^¼˜4i’@YQšòc=°‘––öðð ¥bRQQQToJán°¥=Ìbl#EEEjÚ5®}ñ‚ OŠŠWùy´ŽxOœ>}ºßΞ=Ë#+º“`C½êêëë©:444äÿo0Ô) ­¨+’û”ñFÿ¢Ï;dI¦xŒkF!„P Ѷúºå®ð÷­9‹¼Þ%e‘$™•S¸ÿŸëÍ罌M(7 3C¸~ëYø³¨ª®¹c;pÙÍ{¢þÚY^QõésÙíh´4U¨Ñ¸ë¶ž]¾þÕ÷$É”¹KÖ½ õ€eð—Ó'‰w„ÿttt¨äääváºÄAÓ³´´{„¾Nñ§2S“û=>¹½k°£¥ˆ…œ6y€¢‚œ~{me…ùŸó>~Êûø)þmÆÝ_.\zpÚ‚ÝÔßb ‚عiöãÛ»æÍÖÓ¼sii¥~{íÉã®ùl8wt¹ˆe@0¨zzzT¯‡úúúC‡ñs 5)8äååqMÐP? qi×®……TTT9rD¢×¢Ñ„ªª*³RWWß·oµM­]BÝ”mÍÚ||Ö¡††5A•¿¿}}ý7ÀØØXĨ\«w© ’““ W¯^¼g­âÄ#Ûfy€i ÕWµµµOŸ>å†`ئMj£if‰>Éâm#ªfZ$×ÆÆ†ê¬W^^ÞèÊ¿¬K%×:¢œ(iNNNÀd2oÞ¼Éy4((ˆÚpvvæ?OjEÚ¦¼ ðS&4ú)­®®>}ú4×4iiite>œÞ/Æo4„B‰A#‡Øœ;º<î顲,ÿg!øsa»6t‚Ç·w‘Å7–þ<ŽíÄ•¿N ‹o„í¤÷èh«óú%íõ©Šœ+Ñ÷/ö#--ejÒ,¾tñwÖsùÏ35-o ó:Ónñ‘‡?¾?Oß ‹oÔf'žÙ¹i6\ ŽHMûú+ºCïî'ÿ^üòÑþòìË ÏŽøŸ^3ntoIÌh~@ÔððøÒùö?þà:‘6“Édð[OOÚˆŠŠâœÑüôéÓG•LI¿úßÿþGmlÚ´©i&ÿ¦#™™™üŸÕPbºÛkÿ!nJжƒfm>þëZ.#77÷Ñ£GÔ›üÔ©Sùÿ¹/Pµó(ï)¨JJJ"##:Êûf›æ¨8‘$¹páÂ~ýú8p ¡ªÈÈȸrå µ=tèPz<Ì’~’ÅØFTÏW¯^5”ÀÓÓ“Z~æÌ™?ÿü³¡d÷îÝ322¢¦ÞºuDiVIsss£6Μ9Ã6ª:##ãßÿcccþûÌæåååææÂMÀ†$ɼ¼<‡o‹ø)ý”þñǜ붓$¹e˪«éĉéJ ì7B!„œÍd2—,YbggwýúuÖ!I2$$däȑԈÑôêõu8@<Ì’~’ÅØFöööœœ\RRÂ5AŸ>}6oÞLm¯Y³ÆÅÅ…2IÉÎÎ^ºtéˆ#òòò&L˜P]]-tëˆÒ¬’fkk;räH 9pཿ²²rΜ9T9ׯ_ÏÿÜš/_¾¤6z÷îÍv(''§GíÚµ322b«mþ‰þ)ý”¦¥¥9::feeчjkkúé'oooPPPضmë‰B|£!„BQ¢_%€‚¼,ç¡ôÌüÜÅòò²6–ÆM^.ô#"ZæZMïåË—¤^8¥¥¥íìììììH’ŒŒŒŒŠŠª««“••MJJêС•þìÙ³³gϦ¶ÍÌÌz÷î][[ûàÁƒÌÌ̶mÛ:tˆš%êï¿ÿþå—_X/TPP@Íímffǵ0ü¤€äädj䌌ÌСCmmmÛµk—˜˜E .»{÷î°aÃøÌ611‘ $ 2„3XSWWgllL  ³¶¶ž8qbMMÍ“'Oüüü¨9ÑÙ$Ù¿ÿ'Ož€ªªêĉíííµ´´²³³¯\¹òèÑ#èÖ­ÛóçϩՅ»)¼í@Øæ½íªC//¯eË–QÛæææ±±±\¯(zµó.ÕÒ¥K÷ïßÊÊÊóæÍ333+--}ðàÁ­[·˜LæÀCCCÀÛÛ{Μ9ݬmÍ ÷øqòöö^¸p!Ý?NMMÍÂÂBWW·¸¸øýû÷ôøÖöíÛ?~ü¸S§N¬ç6ÁÃ,ÑDÂÝW™™™T™=zÔ¿®iH’\»v-kÔÒÌÌÌØØXFF&--íÅ‹T¯:99¹€€€Ñ£Gƒ­#J³JZrr²­­-5Þøñã‡^ZZêí혘#FŒæ‰dOOϵk×vèЄËjýúõüñµ=~üø«W¯òÈG¢Ÿ2¿›’’’úö훟Ÿ***ýúõ³¶¶NMM}ôèõƒqþüyº$EÐo4$´7©wÏÞ]Dm²3°ûæ-B!$º­»ü6íô±²è|Ãïw=]-zì›nówÅ¿ÍØ¾aæú®ÍXBÔ*•V•nÜHm›=âÀ «¸¸8WWׄ„ÎCÊÊÊ{÷îuww§Ç?ÖÔÔ :4,,Œ-eÏž=ýýýôõõAÂA=HOOwss£ÖHåäèè¸gϺ›‰ˆ/NpáÂ…éÓ§³íô÷÷§ç¹gS\\¼jÕªÓ§OÓ}ˆXuëÖíòåËœ3— tSÚ„m>±´ÿuXXX¨§§Gu!Ù±cǺuë¸^‘“ÕΣTýúõ£ûûÐ:wî|êÔ)mmmj=Πïl©m!ÚšSCu.ÜãÇ)>>~ÅŠ·oßn(££ã™3g 9Iúa–è"¡o+ƒŒŒŒ-[¶üþûï<’ùùù­Zµª¡‘666Ç·²²¢÷Ý:¢4«¤=zôhòäÉT”ŠÕ Aƒ._¾,ÐhÖ‘#GÞ¹sgÊ”)~~~l‡¶lÙB÷ŽÔÐÐàÁÍJ¢Ÿ2Ñ¿›RSS]]]©qÙlÚ´iãííMEÙú†„ƒA=„B­OiY刉¿?}ž(%ÅàÐÃРmmmÝÛ¤¬g/ÞIKK­øeÂÎßgá”yHì¸õ¤›µH-K=bcc}}}/_¾•ŸŸ¯¬¬lbbâìììááÁö§{YYÙ;wîìß¿?$$$&&¦¾¾ÞÄÄdîܹ³fÍ’——ç%V<~üøæÍ›¾¾¾Ož<ÉÍÍ•’’jß¾½ƒƒÃ¬Y³(Þ%Ó¦MÓÑÑ9vìXlllzzºžžž­­-=±' 'N¬_¿þüùó·oßNJJúôé“¡¡a×®]œœ,X -Íå â¦j;hÖæã¿µ´´ú÷ïO½Á ´î­ÕΣTŠŠŠ¼téRbb¢””T·nÝ\]],X ¤¤T\ÌkªˆFoV¢°p'SSÓ[·n½zõêÊ•+÷ïßÏÌÌÌÍÍUPPÐÓÓspppss4hPCå”ôÃÜO²¸ÚÈÕÕuïÞ½—/_æÔ›:uêØ±c®]»“››KDûöímllÜÜÜFÅÖjB·Ž(Í*iŽŽŽ±±±ÿý÷Õ«W?|ø   `ff6gΜٳgóßGŠŠŠBBB€Zx‡Í¯¿þöèÑ£ÚÚÚÏŸ?3™LþGõÒÄõ)Q§N"##¯\¹âë뙟Ÿ¯ªªjjj:~üxwww®g ú†B!DQQV¹¾ÃïÊ£s$¥ä<Žˆ×ÑR3ꤻlѸ%?íØ¡I(C?8쩇P UWWצMjz5ëQ ô]xýú5µPéÛ·o»víÚÜÅù!x{{Ï›7++ËeΈˆˆèÓ§‘‘QRRRý °§B!„Xpí©‡ e ÔBRýàÜÝÝ›»,‰ÊÜÜÜÆÆ.]ºÔÜeùQøûûÀôéÓŠè5v›Š·"„B!„¾/ÔC¨%ª­­Ý¹s'hjjN›6­¹‹ƒÌ›7þù矪ªªæ.Kë—˜˜xçÎø¯Ú¹úøñãîÝ»`éÒ¥MW2„B!„˜`P¡§®®nÙ²e/^¼€•+W***6w‰ƒyóæéëëgee8q¢¹ËÒúmß¾ÉdN˜0ÁÒÒ’k‚÷ïß<8??âÄ‰ŽŽŽM\<„B!„èp¡ „Zа°°ÀÀ@yyù›7oR«ÍÚÛÛ¯Zµª¹Ë…xÈËËoÙ²eþüù;wî\°`¼¼|s—¨Õzûö­¯¯/ƒÁؾ};×ïÞ½ëÑ£GmmíàÁƒ}||š¸x!„B!±À B-ŵk×þúë/ú{õêuñâŦY;¡¦1k֬ݻwúô)!!ÁÊʪ¹‹Ój½|ùR^^~êÔ©¦¦¦\›››O:uÉ’%|ø@AöööÍ]$¤ÌÌÌ>}ú())M™2¥¶¶¶¹‹ÓúPŸš=z4c1Ž?ž’’¢££ciiÙŒÅøa 4ˆÁ`øúúÆÄÄ4wYD…_!Ôêqõ(y•ne»òaoji,†öBH\0¨‡ÐW={ö$ø0cÆŒæ.ió8xð`DDDEEÅ¥K—nÞ¼ÙÜÅiÝŽIIIÍ]–f––¶}ûöÞ½{·mÛVQQÑÔÔt̘1'Ož.[VV¶mÛ6ذaƒŒŒ ÔÕÕñó1aSPP@ç)ôM¸–o…ˆQvvöÚµk»wﮨ¨¨­­íèèxâĉºº:¶dsç΀µk×6G1B!°¿åTP•y7ë”ê®ä’—$†öBHdÔû¥§§S/Æ—/_nî²ðò½”³Õh´ÂY§TÓÐÐhªr!~ÕÔÔlذÁÄÄdãÆÏž=ûøñceeeBBBPPЂ LLL¼´´ôìÙ³)))aaa®®®wîÜ¡úER œœO:egg×Ä¥E!„øÇ êQ>Õäý›}>Jö¶µÖ°.ª¶ BJ¢C¡V ƒz?¢ÂÂÂæ._š±œË—/766n®«7—F+\QQñàÁƒMS$(%%%SSÓ°°°‘#Gžvúvs—!IÁ ž¤Pkøúú@}}ýéÓ§mllää䂸zõ*kb’$\]];tè ''צM›îß¿¿¼¼¼¡üƒ‚‚¨ü,XÀ5§§'•€/™””Díùé§Ÿ¨=...¬kMr®ºÈd2/]º4vìØöíÛËÊÊêêê:;;Ÿ?ž­ «ššš#GŽ8::jii)((tëÖmõêÕEEEªªª|T›0å¢öÄ‚ÉdöíÛ—*ÒÅ‹9œ={–::{ölΣ?öððèÚµ«’’’ššš••ÕæÍ›?}úÄõBü·ýà;wŽ:÷âÅ‹£Fj×®¢¢b—.]~ùå—ÄÄDÖSø¯p:ó=z4T-‚6§µçùóç³fÍ222RRR²±±qwwg+°„ðYϤ Ì6:’I’FFFA())qÞ¸+ÑUWWWVV€ŠŠŠšš?§¤¥¥åææ@«œ?Qˆ —àà`’’5jçÑ1cÆPAAAl‡ú÷ï$)Ør/_¾Ü°aƒ½½½®®®¬¬¬žžž««+5Û '±|$Eÿ"@!ô"~Ë©¢®$âcà…ä­/ ïÕ0«ÄR*$´_VýChŒièßäÙ;›»€PZVIhŒéÑ眇ڶQÿÅݹ‹Qûe‹Æ5}ÁjÔ“¸âââÚÚZ77·¹sçFGG×ÔÔ€…… ==½oß¾“&Mò÷÷ÏÌ̬©©ÉÏÏøðáÒ¥K»tér÷îÝæ*yff¦ƒƒÃ”)Snܸ‘““S[[›››}úðù'ôˆˆ ÂÜÜ\B¥jFUˆ­­-Á·={öðȪ¸¸8-- úöíËu i:ÒÃv¨gÏž“““‘‘Áçm¾~ýzüøñÖÖÖ;v숌ŒÌÍÍ­­­ÍÎÎö÷÷wttܱcs…þH6ýB¡–C¸á·œªêËŸå_HÞUp«º¾¢ñ$1„’¢<ç?y9Ùæ.*ãqôï]ºŒï×dåA¨‰áD¤WTT´råJjÀ”¹¹¹¦¦æ‡è ªRSSûöíKu‡QPPèÓ§­­mrrrXXØÇsrrFíëëëââ"zIttt¨PŽŸŸ_HHxxxØÚÚÒ X¬ÌÈÈèÛ·off&XYY >ÜÐÐ0%%åÖ­[qqq‘‘‘NNNááá¬ë3¾{÷®ÿþÔb RRR666ööö999ÏŸ?ÿðჳ³³ØËÙ”µÇUÏž=/^ìåå•‘‘ñçŸnÙ²…>tøðáôôtØ´i“®®.½?//ÏÁÁ!99¨.o}úô‘““{òäItttffæ‘#G† FE„hÚ¹sç¶lÙRYY©¢¢âääÔ±cÇììì›7oÖÔÔ,\¸PGGgüøñ àƒÁƒˆÍ‘””4jÔ¨ÐÐP‚ úõë×±cÇ”””ÈÈÈúúúÊÊÊ+VDDDð”@õÜ®]»Áƒß¿?//ïéÓ§œPS¦LúBb?gÎj›ë\QÃ?»víª¬¬,Þò4;á*D,Þ¾}KmpM §§Ç`0˜LfBBÛ!*¨OŸ>mètVQQQvvvT·¾¶mÛ2ÄÐа°°ðñãÇoÞ¼€ 6Œ1‚õÃÎJ¸¤¸¾B}§ÄûÛZu}Å‹‚;¯‹šiô³Ð$/¥Ôø9H&8÷¹|fms—‚;ÞA=„Z= êI\PPгgÏ:vìèããÃöþ_[[;iÒ$*bffdhhHª®®^¸páÙ³gëëëçÎkiiÙµkWK¢¦¦FÕ‹‹£b7C‡å:[V}}ý”)S233©ÎhîîîtXgÇŽk׮ݻwoTTÔÑ£Gùåj]]››õ"§¯¯ýúu+++êI’'Ož\¹råçÏŸÅXÎ&®½†lÙ²åâÅ‹999»víš;w.U†ÏŸ?S]`LLL~ýõW:1“Étqq¡"zZZZ¾¾¾Ã† £{zzz{{S¿ Ñ ¬¨—öY³fýý÷ßô·’’’Ù³gSíÿòË/#FŒPPPàÿÁàAôæ8tèôìÙóâÅ‹t‚gg窪ªgÏž…‡‡s ‰Hˆzvss»ÿ>\½z•GPOEE…u|¥ˆ *&“YPP•••––vþüù«W¯2™LiiéS§NõêÕ‹ÏL^¾| ––8ìò IDAT–"¦%±B|||¨±ºü`[”ƒ ÝÉNSS“kƒ¡¡¡QXX˜‘‘A’$ë«‘¶¶¶¾¾~ffftt4[¼˜+›Aƒ¥§§oÛ¶ÍÕÕ•~Þêëë/^|øðaðôô¤fNä$ÄGRŒ_!„¾S¢¿åTìzYxÿuñ#3u ÍÁŠÒ*b¿ú~aPýà0¨'q‘‘‘wîÜ111a;äããC½6ëéé…‡‡³N6$''wúôéúúzŸòòòßÿž[½ øûûSt¶mÛÆ6q˜ŒŒŒ§§çíÛ·ß¼ysüøq:úpùòåèèhPQQ‰ˆˆÐÓÓ£O¡&þ³µµ¥ßîÄB¢µ·}ûvuuuÎý 㯿þbÝ£ªªºoß¾©S§VUU­^½úÒ¥K°gÏjщÈÊ~í”îïïOÍc¥  ðìÙ³Î;³fåäääääÄšXÐV`%//âĉéÓ§³•Ö×××ÐÐ0///++ëÚµknnnüV Obiggg___Ö~aC† qssóöö€ÐÐPIõ„¨ç‰'þüóÏ555»wïfû‹ôû÷ïãââ`ܸq ¢\Hhl="ÇŽ»iÓ&kkkþ3ÉÏÏ}}} Ãÿ4‰X!œ?½…VVöå÷N--­†Òhkk’$YYY©¨¨Èzˆ êðs-‚ üüüÔÕÕÙú~JIIíÝ»÷âÅ‹………%%% Mu'èG²é¿B¨õ!$I& $½@2I&I’$ L’}ƒ=ý×ÿ’I2[ g@2’ɾIO2¡ž$¿–ŠJößuÉŠ:I-?UǬyUôàMñãnê}zj V’æò+j.ê§~.)¿wuÛÐ=Y÷;OÙ|÷ù¦ßÜ6¯™Fïì7rõ“È„¼wçu´U½}î9u+>1]_O{èË][ç*)ʳeþ!ýã®ýW^¼JŠ‹OSWS9ÔfëºézºZ~Üæï¦Ò¼IL'4¾LL||ÿ¯ f g½Ö¾?,ýù›iõ^Å¥z Œz™”–ñѲG§~ö¦k–MVSeï *hQ95Tx:A~Á磧oÝyþ>9›$IkK£ù3‡»Mj…SZ# Á ^Sظq#×wBz ‹5kÖp¾S±yóf??¿úúúK—.yyyµk×Nâe€ýû÷€¶¶öo¿ýÆyTZZzúôéëÖ­KHH¨««“––€#GŽPG—/_Îú"Gãúê. ‰ÖÞ™3g¸î—’’âŒ5¸ºº?~<$$„ŠÙuëÖÍËË Æ?|øpÖ”Ô~X±b[D“­ÀÊÈȈ-¢G‘——Ÿ;w.5ÍßÍ›7ÅÔ½9:uêtíÚ5ÎÅ1œœ¨BVV–XŠÊFˆzVWW5jT```jjjll,[_6z¶¾T"6¨(‚––ÎÏÏgëùŘ–è"}ÐÄH¸  záA=úPii)[PjþªÖÑÑáº_^^~øðá¾¾¾$I¦§§s]úFˆdÓ „ZšoÃCB¤¾ÄH&0y¤8#SߤØ2ä Hq½.K¶¬ ˜ ŸÈJû6Ãÿ6H&ï¾$C¼Ô‘µqÅ>…›¨õ¶Òª,Ãe‚Zô]HËø¸xÍÑ‹_Vîz—”õ.)ëelÊ“;»X=;~æÎòõ'ÊÊ«@^^6;·èÔù{7Â{*+)uÒ-)­È/ø,##m ÿå×UEÎËÑH’üëеuÛÎÖÔÔQy>Žˆï{åÑùc+úÙ› ]TN< oafH’ä¶Ýw¸B'¨ªª yø*äá«÷ÉÙ¿¯žÊw]¢õ$NSS“^T”U~~þ‹/@VVvþüù\Ï5669rdpp0I’÷ïߟ1c†dË EEE‘‘‘0jÔ(Î×9 5«¶¶6--ÍÈȨ¼¼œê‚K–,i‚B¶¨Ú#âСCæææµµµK—.0`@YY™œœÜÞ½{Y“RKÄÊ•+yç)D+ð_à±cÇRA½>ðbiEEE®wJ‡ÿ$ÔºžÝÜÜàêÕ«lA=jì­ºº:kHW¢ Ê©_¿~çÏŸÏÎÎÎÊÊzøðaLLL@@@@@Àüùó:$''×h$IR‘£Ö…½BÄ…ÛÐ*+@¯ƒÌ9%ÕüõBuä4Ôô#Ùô_‰¯žM"¤¸ž8#GL:C‘RìùsDÖ¸žéäÅâ¾¹Ûý(‚!+%/ÍhþUМ¦l)+«ôÚéî:¡I‘“7·ï¹øôyâ¿b‡ øòÛõß…KÀx'ûmëg˜šääíÿçzô«dS“f†Î#z¾2÷^]ÚÇ==ÄÏuŸ¼¹rã)Xùë„ÅcÛ·ÓŒ}óá—Uÿ„?K5ySÔ/“.ì˜ä§¨œx‚HNÍQT”ÛºnưA=»wíPRZ±sŸÿî;ö^tŸ=\·-÷ÙZb…A=‰ÓÕÕe‚G£¦<€N:qM@éÞ½{pp0ÄÆÆJ¨„l^¿~M’$œ;wîܹs¼§¦¦½}û¶¶¶ôôô¸®ç(v’®½÷ïßóŸÞÄÄdõêÕ;vìˆŽŽ¦FŸ­^½š­/^\\U±;vl´÷“­Àié•â êI´9è©Çè.Nb$t=3FII©¼¼< `óæÍtš¬¬,*x7qâDÖ‘×mPNíÚµ£ûi’$ùèÑ£uëÖ…‡‡ŸÄ¹D ÔãqnCª««oܸñäÉ“¸¸¸×¯_çååч]s¹¡dÓ Ô¨ÇyWÒËâ1 …Pk"MÈt×p°Ò¢€3ë}çBƒvÚÙ|™·wÛú7ïEE¿J¾y/ŠŠ”•”V,_¦Mpîè ƒ=]­][æÖ×3¥¤„YgùÓçòu[ÏÀê%“þÜ<‡ÚieÑ9äúö>ÃVżNY»õLÀ¹u‚•Ÿ…ÿkÇ‚C{~VVú2ŒWC]ùÏÍsnÞz“˜î{ùÑòÿâуz͆~â= “~·ô½Kh]ˆzç¤'xêÒ¥‹DÊÄ¡ÖÞÚµk½¼¼¨·\}}ý5kÖ°% ËÀÏü\B´ÿÚ¶mKmdeeÕÖÖŠ¾ÖªD›C¢£#…®gEEÅqãÆ]¸páõë×ÉÉÉô­Q‹ÇØ[‰6(oA 0àÞ½{½{÷Ž‹‹;{öìÂ… î#FÅ"[!*äíÛ·-”ѦM›†ŽÒË£·½t¬¼<ûD-Tsð¹ 5%>>þøñãgÏž¥¯(''gmm]QQ‘˜˜È>´†>’MÿE€P£ªêJKk‚#$4‚ `@ƒ‚ øfÿ·AA§ÿºAì9|I϶ñM†àÈ‚R_ hàºÜòÿzJƒ'þ·šs¡°:[Õ+EHwS··Ö¦(-Á¿8"®®\§g¬£íÜ4{ÍRÁÖÖcõÛ’Ét˜ŒâØ·Gô«ä¬œBú¢EÅ¥rr2n™CÅhÂEô¨}Zm‡5¸ ²œ4333…Œƒkh—Cvµ9Ͼ¾¾ÆÆÆÙÙÙ‚P/;;ûÊ•+Däïï/’–Öé•‘`¦×{÷îUÛ˜a“´´4AÜøÈuB…{r"U}óûË—/¹ŸêmÚ´ß*W¨wðàAî;ÓÒÒ2$$ÄÝݽF%˪þÿ!¨–O[[M_Ê€&y)A3É”,CŸdÈ•$T()ž$%nòR Q½N•bÃt†xŽF;› 0ÔPüŸKŠ~ôñ0ܾ2fFÆâ·ýïÔœowÑ`_ÏÆûv÷r151X±þÐÊ ‡P|0J\i,,,\]]‰¨´´tß¾}Û$%%9s†[žI“ˆ¬¬Þ¥þÂÏ;&eÁGÙ’’)…mß¾]Ú1üËÒÒ’›{¡¨¨ˆ›T!¤ÔY˳§XwîÜùí·ßˆhÆŒ­[·Þ´i—jÍœ9SøAòÖÖÖÜЛÊÊÊ_­fn¦\±,+Ø{ïÞ½…7IÿÆ¢A]¹Ôò<3†ˆX–å&9yò$YZZöèÑC±;’QQQ‘”­111Ü‚`¦é¸Ã%%%Õ¾0eQì Q.ëçóù‚ÿ#„:uŠ[2dˆøÖ—/_Ò¿—FºŒŒŒçÏŸ‘‡‡G=$zTgÿ€jQD¨Ç´2èàßꛬ& ÑS\xU^¡ÈÁeæM›ÑóÄTöiinLD‰Ii⛊ŠKSßd‘•…朕¥øØ{ ³îRSS þ}IÈáeê"þˆ=€j!ÔS¦Y³fq k×®ŸÙ“eÙ•+Wr“ Ž1Bâq¬­ßÍ´-þÀõ}ûöíܹ³ªý ºzõê•ô–/_.ãþýýß=$uÓ¦MâOLãóù{öì‘¥Ùë¬ÍÙS >Ÿ?sæL>ŸohhøÝwß‘Ýüùó‰èåË—ÜHiÓ¦ j–xbù|>7å(Õè*+))t%ìôéÓ·nÝ""MMÍI“& oªöCŠr9j 6ç¹gϞܽ´!!!åååÜ«O>ùDâ¥Z^ÐjÝ»wÏÉɉ»¸âÊÊÊ6oÞÌ-÷ë×O–¹»5ïÞ½«¨ ë™ÂOˆ¢pY0íß¿_ä®äääK—.‘ƒƒƒøÝ²oÞ¼IKK£/tÒŸ\™——ÇMÓ¬Xuñ¨–ÚÝ~Ë´Ôo;Òv¾¯õd-K…Õu›Y"3+Od}A¡¬S‰óîâLDQÑOÒßJ»q„›w¢²R¦gvw÷ráúÌÉýÀz9öÝ~=kP­YŠ>yƒeYßÞn"ð B=eš4iRûöí‰())ÉÇÇ'%%E°©¼¼|úôéD¤££óý÷ß‹¼×ÐаC‡DTRR²xñbÁÊËÊÊÖ¬Y3eÊ)÷÷ fê>>6l9@Ù¯‚°çÏŸ»»»ß¸qCxeppp@À»‘æÌ™#òl»j¿1¤h —£jsžÕÔÔ¸;mÏŸ?áÂîNUñ{ok¼#-­wš®öX>Ÿ?vìØW¯^uëÖmõêÕùùùÂ[322&NœxçÎ"222 s«âååEDÏŸ?ÏËýý¬á«‹¢(îîî ¢‹/nݺU°¾¸¸xÒ¤IÜÿzK–,ŸvFðäK—êó377çôݾ}[äGMDDDÇŽ/\¸P»ã .þ!ÕRã‘zÍõÚ ·ýj€ÍçfÚõ:‚ÂÒÜ„ˆÂ# ¯\µñ7_DÍøí¦¥¥QXT²|ÝA‘_Åóòÿûâ™1¥¥gË’ëùÜM_O;/¿è‡_‚…×—––¯Úx˜ˆüxr“`Ô’,Å—”–‘¡Á{e**.½u§ú'°à™zʤ©©ìííýöíÛ;wî8;;wïÞ½S§N‰‰‰W¯^åFKñx¼={öÈ%lÞ¼y'N$¢;w^¿~½K—.ååå—/_~õꕹ¹ù¯¿þ*4!Â××·eË–III÷ïß÷öö1bDYYYxxø‘#G¸XJSSóï¿ÿîÖ­Û›7o»uëÖ·o_www ‹ÇGGGsQѰaÃ#\¿ÿþû… ѱcÇ"""zôèáââòêÕ«ààବ,[[ÛÜÜÜììlÙÏô:kyö¤[·n±±´Ùµ¸ L322¾ýö["jÑ¢ÅìÙ³[õõõ·lÙâïï_YY9uêÔÈÈHnè–žž^PPP¯^½òòò’’’¼¼¼<=====Y–ŠŠŠŽŽ®¨¨¸uëÖ„ š7o^ƒ« âîÝ»ÞÞÞ]»võððPSS ¿yó&·©K—.âáZµßRÔéå¨1é×q„ ®®®µ<ÏcÆŒùùçŸ‹ŠŠ¾úê+"jÑ¢—…‰«ÁŽ òóó_½z5{öìY³f999IìœÇã-_¾|ìØ±åååË–-[¿~ý€ìííµ´´?~Ê=‹a˜]»vÉró&ýêÑÝ»wÅo(VÿG“÷Ü•Uø Q mÛ¶¹»»çääÌ;7,,Ì××7???00{ÞeÿþýÇ/þ®ØØX"jÞ¼¹`¤¶tÜ7gEEE¯^½¦L™Ò¶mÛüüüË—/Ÿ={–Ïç÷êÕ+,,L¡‡U'ÿ€ª‘;Ô³Òuôh:ÈB§U]Tõc@ßN×n<Øwøb¯îí‡ ðÈÎ)Ø¼íø–í'œ­ãŸ¦Tÿ~IÌ›5Y òïÚÖ–ˆBÎÞŒ¸ùÈÛÓ¹¤´ìú‡³îzôDœcúú:D”œ’QíJøÐ ÔS2‡¨¨¨€€€èèèüüü³gÏ ž’NDÍš5 4hÄ÷Ž=z÷îÝ×®]#¢|øÉ“'CBB $ÿñJ–o )”x9j©Æç™a˜Ñ£G ¾¬êÞÛïè‡~7nœ™™™©©©øÃ EtèÐ!""âÊ•+Ó¦MëÔ©“¹¹¹¶¶vÛ¶mG޹yóæ„„y,îfí   ¹ÞÕp(ü„(O\\ÜâÅ‹uttLLLzôè±gÏžÐÐP‰?½³²².^¼Hÿ^YèêêFFFnÞ¼¹K—.FFF&&&ÞÞÞ[¶l‰‹‹ëÙ³g=Ú².þ!•"ÓH½fÚ-5ŸþqË9Hô3SÃ[—~6ØËÊÂÄÐ@·kèßßO×·‰‘^mºUSãmß<ólЊOz·mÓ‚Çãytrürªßè߆ôÿïwæ=¿Ìž7k˜“£uyy…‡›£•´{Œ†Y8×?2ô‡ñ£z»85WWãy{:={Ľˆm=»)òïÕ¯¥¥q)dÍçû·°išSàâÔüçõSÃÏmìãÓA¼·y³†õëÝQWGëuZ–ô•ð¡aªz ¨¢ŒŒŒ¦M›‘«««êNq Ľ{÷¸ÁŒñññ­[·Vv9´ÀÀÀ)S¦˜šš¾~ýšûk€JxxþÀù™Üò@W¿^Î)·¨kçSö&æÇIi`¦mãn6°¥¾K nÔøå—ä¯>±Œ[v±í;±ÿÂH=€ÆJ0w @µoß¾sçÎD$|%(ÅÑ£G‰hܸqHô a«2ª3Ѳôµž<Òv~Ký¶Hô¡TiÊ”)D´cÇŽ’’e×òázüøñ?ÿüCÿ^€Kâì·M4›}d5Á¿Õ7­ : ÎP „zP¥)S¦ØØØ¤¤¤ìÞ]ó‡C-­^½šÏç>¼C ÏXh8˜÷'Ê0Ô0ëm9.Àî[ÃNó>¨ „zP%mmí•+WѺuë0XO)âãã>ÌãñV¯^­ìZª!Hîô5Œ},F²[ÔÚȃÁ§N€º¯ Í„ Ú´iÃçó=z¤ìZ>D111ÚÚÚ“&MrqqQv-Õ`ˆÑU7ênî?Ún‰s“® ø €ŠA¨ bꨄz*¡€ŠA¨ bꨄz*¡€òuìØ‘cbbÒ®];__ß3fœ9s¦²²Rz'—/_þì³Ïºuëfbbbddäââ2eÊ”3gÎðù|A›ŠŠ ñU+##C|wñññ‚7nÙZûI<'â>ýôÓœçgÏžÉþ.zýúõ¢E‹œuuuÍÌÌ|||vïÞ]QQ¡”b@¥!Ôh ²³³/^tuu]¿~ýãÇ‹‹‹333¯]»öùçŸ÷éÓGbl …º² €ÿ|÷ÝwM›6%¢ŠŠŠÌÌÌôôô˜˜˜[·nѽ{÷z÷îÖ¹sgá·$&&öèÑ#--ûÒÕÕÕÁÁAMM-11ñöíÛ,ËÞ¾}›6a†a–,Y"¾ß 6pãÅ-ZÄã‰fý:::âoႼ–-[&%%EGG¿xñÂÖÖV°U;š1c†‰‰‰øzN‡ªÚÔ <|øpذaDÔ¿__ßüüü$$$\»v- àŸþÑÐÐPv™ 2ê4 ãÇwppYyïÞ½/¿üòÊ•+Ÿ}öYLL Ã0‚­3gÎä=77·={ö¸¹¹ 6½yóæ§Ÿ~úé§ŸÊÊʸ·¨©©­^½Z|¿[¶lá²¶U«V©«WÿcáéÓ§wïÞ%¢7Ž3†Ïç-X°@Ð@Q;"¢yóæ‰Ÿ•3sæL.ÑûñÇ¿úê+nå‚ † vùòå½{÷N›6M©5€*Áí· ]ûöíOž<<|óæÍãÇW`Iܽ·:::C‡õòò¢÷ïÆ×®]»rå õíÛwîܹ‚õzzz¿ÿþ»¶¶6­Y³¦ÚÇ& ÔP à–ÃÂÂëïܹÃ-tëÖÍÚÚZâ{ÝÝÝçÍ›§Øz¸¯W¯^ÚÚÚ$¢¨¨¨—/_*v/Æ‘#G¸…É“' ²$"›¾}ûQrrò7”P¨&„zª¡}ûöÜ‚àñyD$Hˆ„§¸­k \˜Ø¿"¤ÇŽ«·TËéÓ§‰HMM @Eøùùq §Nª×²@•!ÔP jjjÜ˲‚•:uâ"""^½zU?•î´åâ¼N:q“{4¦9pÝÝÝ™ýðÃRºÊÎÎNJJ""ooocccñ‚¤/66¶.Ž%„zªááÇ܂¥¥¥`eË–-Û¶mKD………ƒ zúôi=TÂ…w¶¶¶­[·&"Ç Ù»qãF½‹*$>>ž[hÑ¢…ÄÖÖÖÜDÀ=ª¿²@Åaö[PPPðÏ?ÿpË>>>‚õ ÃìÛ·ÏËË«²²òÞ½{íÛ·Ÿ6mÚœ9sìììꨒ/^DGGQÿþý7ÿ8ð?þ ¢cÇŽÍ™3§Žv]Ÿ}úƒFŽ)½¥­­í?üðêÕ«­[·ÚÚÚr+ïÝ»çééSûJŽ;Æ-øùù‰l2d· ð9pŸ>}ÊJRQQ¡ØÕ===n!33³ª6‚MúúúõQ@x˜^\‘Ï›˜7(qc(¢=€:†Ûoï¾û®iÓ¦Ür“&Mlmm[µjeii)×.}}ý/¿ürÆŒ{öìùæ›oòòòrrr¦NYËûpÝÛ·owïÞ-¼‰eY--­ÒÒÒk×®¥¥¥YXXÔfGJ/×DÍš5«j« §ËÊʪª ê©©©ikkËS&@CÁ“yAøË„ü»‰ùq­ \;› 0ѲTbmB=€düøñ éJ]]}Ú´ižžž]»v---ŽŽ¾|ù²ðƒðäõêÕ«7npË+V¬¨ªwîÌ™3k¼£†`ܸq·oß–±ñ¦M›,XPÕVÁɪFêUVVæääp-1õ-¨(†˜OZ-ŒÍºø(;¢‚-çV"Ú¨S¸ý 1sss;v,·üàÁƒÚt%¸÷¶Z‚rˆZ·nÍ-¼xñBbƒ—/_²,KDmÚ´©·ªNWÝлÙð1öËÚ›ôTg4ë¹h/(qchÊ>Ü  @õ¹víÚq Ü„5&ˆêbcc%>䮤¤„›=ãÊ•+éééµ,[¹¢££%£DR†é‘““EEEI¬wöìYn¡S§Nuq,õé¿hÏØG,Ú‹E´µQT\º`ÙÞ6žÓõ­?éÒwþ‘à«Ê®¨ªUð„é?Z:MØw袲 9 ÔPaååå‚[b«òäÉnAÊsߪõúõëððp"²··wuu•ØFKK‹›.ƒÏçÿý÷ß5ÞWãÃM ÌçóÏœ9#¾õÔ©SÜ‚`²U§«nèm>BJ´wÑÈoÔä ›·ýÿ4ÅÄX?&.AS£¡?OL… ~“žóûŸ—ÓÒ³wí;§ìZ@õT˲S§NíÞ½ûÖ­[ù|¾Ä6ÉÉÉ‚Ûfkó@½àà`îÑ#FHyîÛˆ#¸…Ï+»+W®¬]»6..NYˆ3f ·°ÿ~î4 $''_ºt‰ˆÜÝÝ•P@ù7Ú[ÚN,Ú{þo´—]š¦Ä UÔ_ï`Œý„_6Ÿ´ñœ>dﻈҥ5è3¿ ˜1ök×u–«U”{_œúç<òÝËûùÉù ðTvQÒ4À‚¥\eófM¾ø|ˆ£½ÕW3?®ÿ Æê¨ª°°°}ûöñùü9sæxzz†„„”–– ¶²,{ñâÅdddQÏž==<}*˜™ÁÊÊ*00°Æ3«¦¥¥]»vˆ¬­­==¥ýqI__¿ÿþ!!!•••ÿý÷çŸ^³= [·n±±±”?üðƒ`Y>–••?~ÜÙÙ¹ö(ĶmÛÜÝÝsrræÎæë뛟Ÿøøñc"êß¿ÿøñã•]#@â¢=7Ób2/>ʹQ)4CîóüØ„ü»v†;›ö7Ö²Pn*d°¯{ÐþEÜ2˲o3òŽ_]¸b_܃³¿ÝydÏ7rõÖðC½¬œ|"216Pv!²j€7ü« òB¨ Â&OžÜ¥K—ùóçŸ;wŽˆrss¹ôM˜Ïþýûmmmk¼Á½·Ã‡¯v4Ùˆ#BBBˆ(((H!¡ÞÞ½{¥7õ,--ËVVVµß»¢ØÛÛŸ8qÂßßÿíÛ·Ç?~ü¸`SïÞ½:¤¦¦¦Äòê‡P´wáQNä{Ñ^^LB^,¢½ša¦YS£ÙÓüt´5§ÎÝ|òF~A±¾Žì=¨JÜSã‘ ÊÒ  V•« ²ÃÝ^ªÍÅÅåìÙ³±±±Ë–-ëÚµkóæÍ544 ÿïÿþïâÅ‹aaaµIôHhÞ[é÷Þrüüü¸|êâÅ‹'{­SóçÏïÛ·¯žžÞ¸qãÆŽ[Ï{—ÎÇÇ'..nñâÅÎÎÎ:::&&&=zôسgOhh¨‰‰‰²«¨?ºêFÝÌG޵_Úθ‡è ¹y1G7\x½7äÖÌ€¾‰¨¼¼"9彇áÜŽ}6qÆO­Ý§™Úõ±lÛÿNñùïžõ|$ø*cì×Ûo1=xüRðœ¾ÝÎs š´Íû]‹Ù×Q«c¿ë ¯ì>àÆØ/#3¯¸¤ìÛ•û­'2Æ~Ž\Þšþ6—eÙ½„zô™§gåïä1}Ö‚í…E%UTtÌSÆØoƼ߸áÊûâë²ì‘ˆîÞOœqåôúš]eyO ì¥‚¢`¤(‡žºQ7ó‘cì—¶•0jïÎÑÄ ^À¨=ÙºJD&Æ–æïKröæÜEÿÓÔPßóËìüä£ožüþøæŽNìCÎFí eoaÅ»i1^•®Í†›ë´”±ç{ÙWòbHRŸâƒ3ZthoÜSÆžß–$G¦‹Þ&yGD:êYM±g":“¼“O•$ÃÙ "‹ S{ŽÉ M-JP¤¤±*­<í :ÊØsJѱï=Égƒˆšh™wiê'cÏeü’°ÔCUoÝKo˱<-;¿ùöt^Ù[±.ßëÓFß)§ôM^Y&K|n í%äÅØº¹›õo¢i.ãî>4|>›”œ¾}ï™M[ƒ‰hÑWŸpßiEÅ¥s¾ÝED{·ÍÄ7NŽÖAû9vžºþ§ Sij*>8~:rû3§O(q+ÃPØ©u\4FDß/ùôLhô»ÏÏ„FÔ³ƒ¢ö˜“[¸xÕ"úfÎÈ +&q+Ý\í.†¬îÚïëØ{ ‹Víþ}±p',±WN¯wsµã¾Ü³m¶³çŒÜ¼Â„i×ήçFÿ5·6ûßÏ_vèþeRrú£'É"ƒëHµg,/¿hÞ’=D4Ö¿çï;çóx Y[šn\9¹²’¯¦V“á\58²” Š…P­‚ò,ÙÇø”ò‹d﹤²0³ôµŒ 4äx|j%¿ümI²ŒyŒ|Õ2KRòÊe}èm¿XöžóÊ2ÒŠell¢%Ç|V¥•E¯‹žÉØX_ÃXöž‰èuÑÓJ¶Ê'‡ˆ(ç—ÉÞóÛ’WÉ…dll¡c'{Ïå9Idll^)áÑWU᳕‰ùrŒ¦éi1JöƯ‹ž¾)~!cck½ÖiE ‚K#ˆöì Ý:#Úû×éóÑ6.“ˆˆÏg3²òÊËß®i“Ì™þ.Éý3øZRrº›«Ý'ú ¿·UKóÞ=\/„Å&$¥µq´Qxm:ØO›$ùÖT"Z8Ç_úp|¼Ûݹûœ{ú›¢öx,$"/¿H_O{áûCä´µ4—.å?qÝñÓ‘™yf¦†‚MßÌ)Hôˆ¨£y³&oÒs–,%Þ¹¶µ52ÔËÍ+LIͬŸP¯Ú3v,$"+;_KKcÃÊI\¢'P³Djte) ·ß@£Å²r4–e¬–PÏrt-WÏ`«ßÎBW4èd‰}ž{'3”ÏJ¾çñCSRR–’š™’š™ú&‹Kô† öº|ríŽgih¼¾s5â>õñé >DÔÎÖ‚ˆž'¦ÖEmcFö”ò5‘Ô‰ˆš55"¢7é9 Ü㵈ÈË£‰±Hãý:˲áQï%ï 3kRGË¥Ú®„ß'¢.l¬ÌµÓœ@YJÅÂH=h´Ôyâ·²$9cäùƒ7á ?ÿ‹$õ)Ø‘\=sW‘Н•/.”'ä”—\}×UÊ)o~ZÕ7(WÄ›ã‚;p9 ñŒ:u6ío¤YóÙ™‘C½ƒö/"¢ŠŠÊv޳⟦Xš›ôêÞ^¸ 7ΉNôx ¯µ‘G@«E½-Ç!Ñ“Ã0VN"¢³QÜãÕ8ݽ\ˆ(ìú=Á4Uá¦S¨¬ä‹oâfBÈÌÊY_P(Ç\:õ;ö¨è'9¹¢ÓÅ„^Žå¼=% z­kuq>½»8QTô“ô·¹RšI¹Êâì aõ ^å—g^IEœ§H>Þí†ô÷ ¢Ëör7cÑÈ¡Ýôõ´“Þlþõ¸ô·[43&¢´ôlñÄÇÒÜ„ˆÂ#ß›aÕÆ#Âéaäÿq7}=í¼ü¢~ ^_ZZ¾jãa"òàÉÍáPÏêâ|úí¦¥¥QXT²|ÝA‘§×ååÿ7±»”«,¡Ï†zAB=¨'ÿÅy¹â¼Q­#Ϋ±µßM`&:æé‘à«ÜSƒÕKÇÑâUæ-ÙÍ ãbY6áEÚœow ¼×¥MsÉÉ-ܵÿ˲EÅ¥YÙùܦ};ѾÃÿ ¾VXTòêuÆW‹w/_wÐÉѺ¾P&ÆïŽ}Íæ¿­ÜŸ’šÉç³q^ô¾ìÎÝçº:ZëWLRJauq>Í›5YûÞ ›<†çhèÑɬâ<…@¨ €8 >!Ô€ZbÃR<ɽÅâ<€z‚Pj‰)­,NôxŒÚ¿ÏÎ3UbYB=¨­Îf^< bçÔ„zP[fÚ6v®š<7³~ˆóêB=P€~Ö“ˆeWð¡à)»hèÔ„z*¡€ŠA¨ bꨄz*¡€ŠA¨ bꨄz*¡€ŠA¨ bꨄz*¡€ŠA¨ bꨄz*¡€ŠA¨ bꨄz ‡î¾aŒý¶l?¡ìB>hõT B=€ú–‘™§nö1cì×µße×u苯w0Æ~þ×Õ¸‡ü‚bÆØ¯]×Y ¬J¹ß) B=€úö÷©••|]­Èèø—¯Þ*»h¸²s ”]‚‚5¾#R„zõí¯ã×ÕÕÕV|;–ˆ‚N„+»h¸_ÖøŽHYêÔ«·¹—®ÞíÕ½ý§£zÑ_ǯ+»¢š`FÙ%|_ÖøŽHYêÔ«à“7ø|vè@OKs“.îNQÑñIÉéâÍÊË+~ÛsÆ«ßcÛÑÍÛNþéš?þºÌç³ÜÖë1Æ~cQq©®åHÆØïɳúw²Úô·¹,Ëîý#Ô£Ï<=+'é³l/,*‘Xá‹—é3çoïÒw¾ž•¿µóÄϾܚ’š)ÒFSSeÙÀƒ¤wÈí=#3¯¸¤ìÛ•û­'2Æ~Ž\4¸{?qò¬-í½¿0lÐcàÂE+÷çæŠ—Tƒ£¥ç&-G3Æ~ÂbEÖµŠ1ö[±þðJéWDv2ˑૌ±_o¿ÅDôàñKÆØ{í>p^Ðæv쳉3~jí>ÍÔn¬ïˆeÛþwJ¼)—@úÕ‘ýäpý¤¾É*,*Y¹ápÏéÚ#Z´›,GO\'¢¡»ÑǃºDEÇŸÿÅpá6,ËŽœ°îä¹›DÔ¦i~AññÓ‘ÇOG:zåô_ˆ™0ºÏÊ ‡oÇ>{úüµ£½•ð{/^¹[\RæÚÖ¶µƒµ`eRrúìowþ|ûòɳ”'ÏRbâÂÿÙ(2æîûÿ™·dwAa ikk¾NËÚûGhðɈ+§×»¶µª>ºùPЕj;$¢·™¹c?ßzù]<ÔÞÅ–;Æ=¾øûeeܾ®G>¼ùðð±«ìšßÝËEüÔÉx5è¹ZÕ^y;¬öXôõt­°ÞûIDATì[Yæå½ÍÈÕÐPoaÓ”kih ËÕ³uçɯ¿ ,/¯ÐÔT72Ô ½˽þ üF[KSdw/Aµ›ät"üç'Ÿ'¦2 òlrJÆö½gþ>uãÚÙ v–ÕÈ #õêOúÛÜË×â:´kÕ²y3"úxIº÷Ä™¨“çnšÄ\ý9éÞÞÌ„C÷"¶ êç>åÓ~\âcgkѳ[;":|Uä½!g£ˆÈÿãnÂ+Zr&j˺Ï_?ÞŸòhÿÒ£ˆèÆ­Ç—®Æ 7ÛøâÔ¹Û K† öº±­0%èÕÃ}_Ïѹ£ƒ‹Ssá– —þ}êFµr¯:péjÜò…cÝÜq~SÛ6-ˆè·=g,Û[VV±àËá/ï¼:zçÊÏÞžÎIÉéý—Ç?MïGÆ£¨AÏÕªöŠÈ«ÚcÒßãÙ]WN&¢ÖöVÏîìâ^ûQÈÙ›sýOSC}Ï/³ó“¾yòûã›;:u°9µ3ðœøî$^‚j7ÉeöÂ]ÅÅ¥vÌKúGVâáC»¿ÖÓÕNKÏ^°l,GòÂH=€zþ÷á5¬è¡¯«^ÃÊÓXÂN«m,V0[å!Ôúèªî™ml¤Ù”TVð©>Ÿå†é‘sk;Ë›·Ÿ¼x™nÛ¢™ YTt<}2¬[ÇövDÄ0L;ç–§ÿZ.ÜÕ¤±}¯„ß?rìêÒ£¹ŸÏž:w‹ˆF}/Ôc ;µÎ³skîËï—|z&4úÎÝçgB£?êÙ[™—_4oÉ"ëßó÷óy<†ˆ¬-M7®œ\YÉWS{o`®®ÖÉÃßIïPàøéÈí?Μ>y `MNnáâUˆè›9#7¬˜Ä­tsµ»²ºk¿¯cï%,Zµ?ø÷Å"ýÈr5ë¹Z²\¹Èr,U)*.óí."Ú»mŽ sr´ڿȱóÔõ?͘2HSó½ÌGüȲI.>Þí‚öÛÔ̈ûrÌH]­aãVŸ8õèI²sëæÒßòB¨PlæÅÔâç$)³ ¤%â«»”üBRüñþN¥%båI(¸&ÉN=žœZœRÎÉ‘²S…ÔÃð¦:ý¨ì*j¯‘ ˆaÆh·õ[‚Ž¿þõì‚fÖV¦Dy+¾¸¤LG[ôVJŽÿÇݾøzÇÃøä{“7ÆFÇö^tÛª¥yï®Âb’ÒÚ8Úo¿²l’Ëð!^‚D3¤¿Gsk³ä”Œ3ç£ê)B=h„2J_½,x¨ì* N°,Ÿ%>£š“z“žs%ü^Gá;ý?î¶~KÐ_ï‡z#ü¼×n>z÷~bçžsç1|\@Oñ§¤éëi2¬Û¾C»*õ$Þ{KD"!5kjÄ•$Xs%ü>uéìdceVí±ÈÒ¡À˜‘=EîQ½vãyy´116i<°_g"bY6<êÑǃºÈ»Óšõ\-Y®ˆ\ä:"®FÜ'¢>>Äïüµ³µ ¢ç‰©"¡žø%eS-©©ñÜ\í“S2’’ßÖEÿ8•ü!P:ùp ij¼e—PCܽ·É)ާ9tšÊ½&o ¢è˜§‰Io-­,L.†¬örwzô$ùÿfoµq™´`Ù^ñ¸gÒØ¾Dt$øª`ì-7“ƒx¨'NC]Þ´û:-“ˆZ;XUù9;PW͸}q ”]-‹fÆ‚6òîTQ=‹ñŠÔ†”(‚Í·yÛß‚ d¯]ûΑ¤dPüȲ©öÌ›5!¢/ßTÛä…‘z óÞ„×0¢kþý‚mùß6Ñp“‹;Å×Þ%Sãªw*SãÚ`‘o\åÛ…ÊlP'Gî3CÊ>9Š9:±÷ o*ç—f—¦å—g‰ÝòÌ”óKÄêQ ܽ·…E%ÏSÅ·=~ý¡;F[7ÿgÓ…°Ømÿ;uòÜÍÍÛþþßþïùzP?wA›]Û¶již˜ôææí']Ü’’Óã¼p´·jçܲåñù,Iú¨ Ò“+®Ò­zíY–+R?¸ú;´kUÕ…®ñd —Ÿ_LDêêjÊ.¤B¨PO‹QÝÍÿû`,!ÎK¤5VT²#–ÎHˆ`€(¯<óNÆù„ÂX>Ë^ÏcÔZyt2õ5Ð0QVmµ‘–ž}%ü¾‰±AúÓ?DQwêŸ[~£Wýõ~¨GD<ãÛÇÍ·Û½‡/,Û{þR̨ÉžÜÞiin"h0qÌG+Ö:v2¢‹»ÓÙ ·‰è“»×,˜3oÚ„ˆ$Ž ginLD‰Ii⛊ŠKSßd‘•EM.´\=s穼¢RÆÎ«½"õƒ;ÆNì÷n›Sw{‘÷äH”øò ÕôR‚t¸ý! ž–¶šžà¥¥¦+òÒäéüûÒyið´D^êê$>éD¯îí55ÕoÇ>Kx!!Š"¢ö.¶§Ž|ggkQPXr5üð¦‰c>"¢à“7X–=z›d»÷V"ï.ÎDý$ýmnÍz]w/n_9¹…"›B/Ǿ«ÇÓ¹®{æ¦ËÈÌÊiYPX,}/R®ˆbqß-••ïÜÜ1†]¿W^^Qw»®ñÉH}“÷œþýÖâH<"¨„z |\œw$aíãÜH>ûßÈ £ædÔe”Ýâž–£ 4L•Xaí=~ˆùJ¸US_OÛÇ»  ¥¥g¾w—±††z«–æDTT\*¼Þ¶E³Þ=\Ÿ'¦Þ¹ûüâ•»v¶Û·ªY…þC»iii•,_wPäÉnyùE5ë³Ê}}ÜM_O;/¿è‡_‚…×—––¯Úx˜ˆüxrGÔiÏÜ»ðÈGÂ-Wm<ÂÍ"Lö+¢XÜCÓÒ³…S°‘C»éëi'&½ÙüëñºÛµì'‡“•] ²fÍ••U´°i:|HWÁJ‰G5€P”)¿<ëJšÄ8ÇÅy½,ǪxœGD©o²®F<`¦ŸN ìÛ™ˆþ:~ˆÊË+FŽ_çÒeFЉp.HbY6ødÄåkqjj¼]ÛŠ¼wÒØˆè«Å» ‹J>VÃ{o‰È¼Y“ÅóˆhGàÙI3·åñD‡ŽJ<"ÃÖlg©$ž?p~&·<ÐÕ¯—óGÊ­ˆ‚òì;™¡ñ¹Qâ£ó ;w6ío¨‰÷5ñíÊý¶ÍÿbøßcÄÔ·î¾ zôóú©³§ù)»–Æ)¿$õ‰eܲ‹m߉ýwn¿€úQPž“yAäÁyôoœ×ÉÔ×H³©²jSu,Ë?}ƒˆÆ}ÒKÙµÀ‡‹ÏÇÄõ ¡Ô­‚òœ˜ÌPñ8!žƒQ§Î¦ýçÕÒñÓ‘ñOSº¸;)ö™wÐ!Ô€:¡­eèÔ¼GyijEeyM§a•ÇÅyñ¹Q•l…ðzÄy QZZ®©©~%üþÔ¹Ûˆhõ’O•]Ô >[Ùܤ…ºš†º¦……Ikn%B=¨,Ÿ|[lÕÔ^¹µ@ý+¬È‰É¼ð8'RBœgØ©“™oÍfʪ­Ñðüh^RòÛܼB"šÿÅð¾½:*»"¨¥å¥ÉY/‰ˆè¹î»¿… Ô€:¡£e$X..+Vb%PÿølåŸ ëÊù¥Â+â9ºu2ë8O!JKËù|¶¢¢²‹»ÓçúOù´¯²+€ºR\V$XüŠ…PêÄ{¡^y‘”–ÐøðµvÆ>1™¡Ü— ñì Ý:#ÎS(--{Û”]Ñõs•]B#Wô^¨gÈ- Ô€:a kÆ0<–åQzÞe—õ­ƒIïÙ×Êù¥ÿÆyæÊ®@U ÿ*e¨÷îÇ)B=¨êjZ͚ؿÉ~JDoóÒË*Ê4Õ5•]Ô-5ÝVºöºêFÕ·€ª¥d¿,[›µåxJ*?ë¦í¸>Ë“¢Üb þ9vB¢P{)ÙÉÜ‚OÃÂĉ[F¨uÅæßPˆž¤>Rb%**³ ##ÿ-·ln⨮öîÖ„zPWœšû–ï&Ç(±—+Xþå ¡Ô3£VVf.ÜrFþ[Ü ¯»/ï–;Ø,#Ô€:ÔÁ~°`9âé5%V r^d$¤æ¼æ–›6±³4m#Ø„Pê›ãÇ óîwÎ;/nef)·ráþ?‚åέ‡ oB¨uÈHÏ¢Ó¿¿€Vò+/? Un=ª"%;ùé›xnYGÓЫí8á­õ nõq›ÁcÔ¸å[ QÉ™IÊ­ á«äWÝúSð¥wû :š†Â ê@Ý23²íè8”[æ³ü¿nª¨¬PnI ÜåG^g¿â–µ5 zvø\¤B=¨sƒ½êj7á–ÓóÞœ‰ Qn= YJö«‹þ{šÞ®‹µ4ôDÚ Ô€:§¯c6¬û Á—áO®F> W^9 WVafàÕ]|–Ï}éÔÜǽ¿x3„zP:ØiÓ¢—àËwŽÅ§>R^9 QqYÑž+;òKò¸/µ5 >éµ!F¼%B=¨'c?ÚbiÚ†[æ³üá{ã’c•[@Ñ[”³ãÒ/ùo¹/Õxêã}5Ðm*±1òl=Ö´¼Â7¿÷Ï)Hå¾dfP‡¡>N½•[€Ò¥æ¼¼¶+·(‡û’!æ“Þ:·QU{„zP¯r R>æWT’#XÓÖÆÕßc”®¦èãŸ>,±QÏ"Nß )«(¬ôó^Ú½ý$)ïB¨õ-#7qï™Ï2ó^ Öèjê}â9ÆÅº«¨مه#$e$ Öðxjú¯èâçñÔdì¡(YyEÉ„Åî,,É–ÒLKC[WSGOK¿¬¢¼Þj¨1=-½ô¼7E¥…,U™¿ñµCú¹Ï65l)Wçõ A¨¨,|xøZÜÞœ‚×Ršéiê–Ö[U5fÙÄ*5§Ê_l†çj7h×Â&ú–5è¡4 ,±/ßÄÜ}v:.áL~Ñ[ñzZz…¥õ@´4k%<­-G]MÓѦ{û!.¶iièÕ¸s„zбÄfå½LyûàÕÛ{o²Ÿ–d—æ–déhg*»:€êÙ[y¥eÆëhêëšéYX›µ³iÚÎÊÌE§QûÎꨞ² ù ÔP1õT B=ƒP@Å ÔP1õT B=óÿéŦçà„ËIEND®B`‚trusted-firmware-a-2.2/docs/resources/diagrams/plantuml/000077500000000000000000000000001355360272700234765ustar00rootroot00000000000000trusted-firmware-a-2.2/docs/resources/diagrams/plantuml/io_arm_class_diagram.puml000066400000000000000000000032021355360272700305110ustar00rootroot00000000000000@startuml package arm_io_storage { class plat_io_policy { dev_handle : uintptr_t* image_spec : uintptr_t {abstract} check() : fctptr } class FIP_IMAGE_ID { memmap_dev_handle fip_block_spec open_memmap() } class BL2_IMAGE_ID{ fip_dev_handle bl2_uuid_spec open_fip() } class xxx_IMAGE_ID{ fip_dev_handle xxx_uuid_spec open_fip() } class arm_io_storage { fip_dev_con : io_dev_connector_t* fip_dev_handle : uintptr_t memmap_dev_con : io_dev_connector_t* memmap_dev_handle : uintptr_t fip_block_spec : io_block_spec_t policies : plat_io_policy[1..*] -open_fip() -open_memmap() +arm_io_setup() +plat_get_image_source() } FIP_IMAGE_ID -up-|> plat_io_policy BL2_IMAGE_ID -up-|> plat_io_policy xxx_IMAGE_ID -up-|> plat_io_policy arm_io_storage *-"1..*" plat_io_policy } package IO { class io_storage { io_dev_open() io_dev_init() io_dev_close() .. synchronous operations .. io_open() io_seek() io_size() io_read() io_write() io_close() io_register_device() } class io_fip { register_io_dev_fip() .. io_dev_funcs_t interface .. fip_dev_funcs : io_dev_funcs_t } class io_memmap { register_io_dev_memmap() .. io_dev_funcs_t interface .. memmap_dev_funcs : io_dev_funcs_t } interface io_driver { io_entity_t io_dev_info_t .. io_dev_connector_t interface .. dev_open() .. io_dev_funcs_t interface .. type() open() seek() size() read() write() close() dev_init() dev_close() io_register_device() } } arm_io_storage .. io_driver arm_io_storage .. io_fip arm_io_storage .. io_memmap arm_io_storage .. io_storage @enduml trusted-firmware-a-2.2/docs/resources/diagrams/plantuml/io_dev_init_and_check.puml000066400000000000000000000031561355360272700306510ustar00rootroot00000000000000@startuml participant arm_io_storage order 1 participant io_storage order 2 -> arm_io_storage : plat_get_image_source(image_id, &dev_handle, &image_spec) group init and check device (image_id) alt image_id = BL2_IMAGE_ID note over arm_io_storage get BL2_IMAGE_ID policy: - fip_dev_handle - open_fip() end note opt policy->check() arm_io_storage -> arm_io_storage : open_fip(spec) activate arm_io_storage arm_io_storage -> io_storage : io_dev_init(fip_dev_handle, FIP_IMAGE_ID) ref over io_storage : dev_init() on fip device arm_io_storage -> io_storage : io_open(fip_dev_handle, spec, &local_image_handle) ref over io_storage : io_open() on fip device arm_io_storage -> io_storage : io_close(local_image_handle) ref over io_storage : io_close() on fip device hnote over arm_io_storage fip_dev_handle ready end note end opt deactivate arm_io_storage else image_id = FIP_IMAGE_ID activate arm_io_storage note over arm_io_storage get FIP_IMAGE_ID policy: - memmap_dev_handle - open_memmap() end note opt policy->check() arm_io_storage -> arm_io_storage : open_memmap(spec) activate arm_io_storage arm_io_storage -> io_storage : io_dev_init(memmap_dev_handle, NULL) ref over io_storage : dev_init() on memmap device arm_io_storage -> io_storage : io_open(memmap_dev_handle, spec, &local_image_handle) ref over io_storage : io_open() on memmap device arm_io_storage -> io_storage : io_close(local_image_handle) ref over io_storage : io_close() on memmap device hnote over arm_io_storage memmap_dev_handle ready end note deactivate arm_io_storage end opt deactivate arm_io_storage end alt end group @enduml trusted-firmware-a-2.2/docs/resources/diagrams/plantuml/io_dev_registration.puml000066400000000000000000000025241355360272700304370ustar00rootroot00000000000000@startuml participant arm_io_storage order 1 participant io_storage order 2 participant io_fip order 3 participant io_memmap order 4 -> arm_io_storage : arm_io_setup() group io dev registration arm_io_storage -> io_fip : register_io_dev_fip(&fip_dev_con) io_fip -> io_storage : io_register_device(&dev_info_pool[]) note over io_storage devices[dev_count] = (fip_)dev_info_pool dev_count++ end note arm_io_storage -> io_memmap : register_io_dev_memmap(&memmap_dev_con) io_memmap -> io_storage : io_register_device(&memmap_dev_info) note over io_storage devices[dev_count] = memmap_dev_info dev_count++ end note arm_io_storage -> io_storage : io_dev_open(fip_dev_con, NULL, fip_dev_handle) io_storage -> io_storage : dev_open(dev_con, dev_spec, handle) activate io_storage opt dev_open() on fip device io_storage -> io_fip : fip_dev_open(dev_spec, dev_info) note over io_fip dev_info = one of the "fip_dev_info" from dev_info_pool[] end note end opt deactivate io_storage arm_io_storage -> io_storage : io_dev_open(memmap_dev_con, NULL, memmap_dev_handle) io_storage -> io_storage : dev_open(dev_con, dev_spec, handle) activate io_storage opt dev_open() on memmap device io_storage -> io_memmap : memmap_dev_open(dev_spec, dev_info) note over io_memmap dev_info = memmap_dev_info end note end opt deactivate io_storage end group @enduml trusted-firmware-a-2.2/docs/resources/diagrams/plantuml/io_framework_usage_overview.puml000066400000000000000000000037361355360272700322040ustar00rootroot00000000000000@startuml participant bl_common order 1 participant arm_io_storage order 2 participant io_storage order 3 == Platform Setup == bl1_main -> xxx_bl1_setup : bl1_platform_setup() xxx_bl1_setup -> arm_io_storage : plat_arm_io_setup() arm_io_storage -> arm_io_storage : arm_io_setup() ref over arm_io_storage, io_storage : io device registration == Get Image == bl1_main -> xxx_bl1_setup : bl1_plat_get_next_image_id() bl1_main <-- xxx_bl1_setup : BL2_IMAGE_ID bl1_main -> bl1_main : bl1_load_bl2() activate bl1_main bl1_main -> plat_bl1_common : bl1_plat_get_image_desc(BL2_IMAGE_ID) bl1_main <-- plat_bl1_common : BL2_IMAGE_DESC bl1_main -> plat_bl1_common : bl1_plat_handle_pre_image_load(BL2_IMAGE_ID) bl1_main -> bl_common : load_auth_image(BL2_IMAGE_ID, image_info) activate bl_common bl_common -> bl_common : load_auth_image_internal(BL2_IMAGE_ID, image_info, is_parent_image) activate bl_common bl_common -> bl_common : load_image(BL2_IMAGE_ID, image_info) activate bl_common bl_common -> arm_io_storage : plat_get_image_source(BL2_IMAGE_ID, &dev_handle, &image_spec) ref over arm_io_storage, io_storage : init and check device (BL2_IMAGE_ID) bl_common <-- arm_io_storage : dev_handle bl_common -> io_storage : io_open(dev_handle, image_spec, &image_handle) ref over io_storage : io_open() on fip device bl_common <-- io_storage : image_handle bl_common -> io_storage : io_size(image_handle, &image_size) ref over io_storage : io_size() on fip device bl_common -> io_storage : io_read(image_handle, image_base, image_size, &bytes_read) ref over io_storage : io_read() on fip device bl_common -> io_storage : io_close(image_handle) ref over io_storage : io_close() on fip device bl_common -> io_storage : io_dev_close(dev_handle) ref over io_storage : io_dev_close() on fip device deactivate bl_common deactivate bl_common deactivate bl_common == Prepare Next Image == bl1_main -> plat_bl1_common : bl1_plat_handle_post_image_load(BL2_IMAGE_ID) deactivate bl1_main == Jump to next Image == @enduml trusted-firmware-a-2.2/docs/resources/diagrams/plantuml/sdei_explicit_dispatch.puml000066400000000000000000000021411355360272700310770ustar00rootroot00000000000000/' ' Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. ' ' SPDX-License-Identifier: BSD-3-Clause '/ @startuml autonumber "[#]" participant "SDEI client" as EL2 participant EL3 participant SDEI participant "RAS Driver" as RAS activate EL2 EL2->EL3: **SDEI_EVENT_REGISTER**(ev, handler, ...) EL3->EL2: success EL2->EL3: **SDEI_EVENT_ENABLE**(ev) EL3->EL2: success EL2->EL3: **SDEI_PE_UNMASK**() EL3->EL2: 1 ... <> ... EL3<--]: **CRITICAL EVENT** activate EL3 #red note over EL3: Critical event triage EL3->RAS: dispatch to handle deactivate EL3 activate RAS #salmon note over RAS: Critical event handling RAS-->SDEI: sdei_dispatch_event(ev) deactivate RAS activate SDEI #salmon note over SDEI: Prepare SDEI dispatch SDEI->EL2: dispatch activate EL2 #salmon note over EL2: SDEI handler EL2->SDEI: **SDEI_EVENT_COMPLETE()** deactivate EL2 note over SDEI: Complete SDEI dispatch SDEI-->RAS: return deactivate SDEI activate RAS #salmon RAS->EL3: error handling done deactivate RAS EL3->EL2: resumes preempted execution ... <> ... @enduml trusted-firmware-a-2.2/docs/resources/diagrams/plantuml/sdei_general.puml000066400000000000000000000016361355360272700270240ustar00rootroot00000000000000/' ' Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. ' ' SPDX-License-Identifier: BSD-3-Clause '/ @startuml autonumber "[#]" participant "SDEI client" as EL2 participant EL3 participant "SDEI interrupt source" as SDEI activate EL2 EL2->EL3: **SDEI_INTERRUPT_BIND**(irq) EL3->EL2: event number: ev EL2->EL3: **SDEI_EVENT_REGISTER**(ev, handler, ...) EL3->EL2: success EL2->EL3: **SDEI_EVENT_ENABLE**(ev) EL3->EL2: success EL2->EL3: **SDEI_PE_UNMASK**() EL3->EL2: 1 ... <> ... SDEI-->EL3: SDEI interrupt activate SDEI #salmon activate EL3 #red note over EL3: Prepare SDEI dispatch EL3->EL2: dispatch activate EL2 #salmon note over EL2: SDEI handler EL2->EL3: **SDEI_EVENT_COMPLETE()** deactivate EL2 note over EL3: Complete SDEI dispatch EL3-->SDEI: EOI deactivate SDEI EL3->EL2: resumes preempted execution deactivate EL3 ... <> ... @enduml trusted-firmware-a-2.2/docs/resources/diagrams/psci-suspend-sequence.png000066400000000000000000015034301355360272700266010ustar00rootroot00000000000000‰PNG  IHDRÝ 2G4„˜sRGB®ÎégAMA± üa pHYs1616šçB ÿ¥IDATx^ìý;“%;r¥ Ÿ?sþÅZ¢ÐJµÔ6Â(u$J-”Q¢D³2ki¤’¨P(£Dá{kn=7NÍ çÖó3J-”µD¥Z¢T¥þVÅÂ^¯'G bÇν#k=––p8܀ܙùÝ1ÆcŒ1ÆcÌ=ð¹Œ1ÆcŒ1ÆcÌ}ð¹Œ1ÆcŒ1ÆcÌ}ð¹Œ1ÆcŒ1ÆcÌ}ð¹Œ1ÆcŒ1ÆcÌ}ð¹Œ1ÆcŒ1ÆcÌ}ð¹Œ1ÆcŒ1ÆcÌ}ð¹Œ1ÆcŒ1ÆcÌ}ð¹Œ1ÆcŒ1ÆcÌ}ð¹Œ1ÆcŒ1ÆcÌ}ð¹Œ1ÆcŒ1ÆcÌ}ð¹Œ1ÆcŒ1ÆcÌ}ð¹Œ1ÆcŒ1ÆcÌ}ð¹ÌˆW¯^}ÿý÷?üðC¹ÿ¶A(bRׯ_³iòæÍ›òÀ ”{c<7¾>þŒ~Dob¦-Ef#ˬy‡—ãn>}úD›ß½{WŠ¿žNÖiì,dZ)z`0 Ndí³á°óüLËüôÓOo/` žnˆâ u'^ê_¾|)Es`>úî»ïð½ÜÛ0ϼCsh4â­àä9B´o‹Åhß:á1ŸˆRdÎÆî¹^Þ% ?~,Ì@,3ë œZw¿ú·r——ã5¨Ó1KÑøúX(÷9Ïóz2‘÷ïß#ì`ëDÍÎ3={w0 Ndí³á°\ÏçÏŸ±kþºÖYÀ€*¦ÁŽ›cÕK‘yѬœË ¸à¨@áYR£B.lýÑ+z@ Ìåþö ¿–~ûÚ˜ÎðnÀ:Û?Ô€(1b`Çù):ošð˜7hñûþ¤ì˜o“‹sƒìˆçœÛŸk^ý[aC'  :ý¾ ¹W¯^Ñ °jÉ3¼žL…FzªÍÁΧxÅkYâIÄa¹†/_¾ðÃþŒ¡@ɦYJT±™Mz.ƒq¨‰• '@¹Y8Å*$.ζ®þYßËý· £qT§óùÇ徇2Ð?TŸDç2è,d~)½°süv #ñûþ¤°çS%¾MP‹”ûÍÜ ŒAvÁ)^èó\óêß :QÕé›v‡'\—Ò„[¿žL‹:hëÏÃ4á?Â+käùàpOŸÓZ4ÿ7ž9,/‰j­‹kRî· (ŸË|kôÏe0•@¸@Z ypÁ_åÓS WLÇxIÀìr? Ýô` ŒÆ!KO¤Í’>+Úÿð£ûíd&æxtÓ€óý`±Åïû³ÂÄ÷r¿å_½zÏX±[V&Ì«2Ç29Ÿ‘ݯþ­0O@u:¶^¥èÙ‰?EàÅx§zëדiùðá&m¼¸·"°³À#¼â™`ƒÌyεuÇ¡7‰Ïev£üÇE; )˜üiªcbŽŒm^ ýs™,¥"L¯—=\Wgóo F)Qî¯@‹Â±6Çÿ@fbΣ€cCN0u°!à÷ýIÙ:6«¡¬þÈÌ]˜œÍ‡P~ÇÍ!æ€Ði¯‚íGyÖ㦯's,õŠ_}[)ŸÁZµuÇ¡7És†å%¡çîAQõ ×téœË(i0‹}n~"²õýt¬ÎæßŒÆ!SÉäNàÀÍLÌñ7Jx*gë¼~ߟ”çF%Ãã¯S_$“³±pºW•:ý^ƒkKíõë׺Ï'œ(™sÌ­y¨Wüjv=ç„Úzü÷Ýs†å%¡äÏþ8°¦¥s.£Œü6æ*È6 i1>ÁpÌN¼¤Ñ4+fiyÿþ=…AÔ#øëWc¤Më4ju6ÐÌŠJT·å«“Á<¸ÆZ3>ŠØˆ 'ùòå jÅhàz&àŒÆ`é9cû"'ãVD y ²NÄ£Òê¦|S×W1LìMõäKQò|óg“ÌÎå¾vŽ-Ÿ‰9áë$&¼¼ÞêWª³uF Ê€I`‰z š³è ´Ba2–_¢²’‘¨«QRHÁ¦±/¢û`Ühå$g{$†Z ÍÌ“(ÐD)Z£MrÜÒH°š$VƒþÙÓ#4‚G¥ùý¨N™t–ÄÞ‡B-ãŽ`Iˆ±"·»ÛϺnE¹3““•%±¡ ´‹§m‹(AyŒö•ÝêËD³³¾† Ç–Æg2“Ó 4°Ó!VŠž2©g7ˆ3  rMƒ¶(3˜s”E–ÒÄ?Êk8Nl^;@@ƒŒƒÿ5]žzª¶f<ŠÈ"Ö6QSEÞ©Cuñ¨TÛ8û©Åqp+êmÅ[ÿGTUÖÂ6V» Ä d½ŒBèóæ ÛÂÅbH¡Mƒ*¥½…±‘UµrlC<¥©±.U : ÌÈTÀ~™4NR| ßnyؾLjDå«9VK”o¥¨Ð_І0žå¦®ÑT0:óàÔç2èT¦Ë ¥Æ 3˜”˜¦»¿‡l£ÓSUU³Œì¶ùj†¿Î18+%¸…fdK.°)+Æžî¡dSòTý+f†µ´½[˜!å­‘äÊAÔ¶«y´9µ¬X±ã%È@¡J¹¿Àr|Çuwzß:ÑÑ**l™ìk8H=­Áb Óí&”pÀV¨Ú§°¶«g~xÎÀ€È ¤Ê&OPU‰t}‡|÷¥€Bd`×ÇAëûèflö¶êæ €†n'*çÓîtõÚdÄ ÆGÝñÕŽÀª¼[qrDˆè&d(Oº‘$•dEl+ºÙ]Ç)+‚ts TU4r»àŠèݾé¾ »ÝÔö>Ò‰%¨Â’Éd½YÁñÈ*fÕQÞº(é&½€®áH¬Ûvk7¶(Ay‘X)ÁZƒ)°¡îkm€¿ÐÀ§Ön}™‡¢>—ÑDÖæë ª¢-'ÄEô‚r.NñU-\·sTé)*ÖªÒå+÷) ¼ÕàÇ÷"¨<­\¹ŸÂ¶X—tçĈ4ãTÍábðrªàŒ€*q†Â…®®[“(к¦Š_U¬Ù†G,ïÂ5Ä@Ú¨‡•o‹ÐÅ|×;¦Ò  aÃví¢´•¢€vÇ£Ö²¸(E½nÄÄu%¡A+<|'‹ìWvÌøì&(Q&ȤÕ̯ˆ¾Ð0 Ûj–¸]z€­3L|$a@y\¡!ênж`R½ÐuUb-\wW„»çÆMÀ0êܤоà;²W–EÙWð´H?ekV>BÁÖä™OËŒX UoÕÑm»`k¸ÀLÖ1\R^=Åu{¬&EvåECØ:•û ,Ç÷jz¼­_X Ë}`S_ã–åqZŽ(£*óTQMµŠÜõQõžº~šš=ÅV¢alßË} è ([›Û·0r’(/XPw~‡<ªŠÒЖn«V¸0#”$¥(™a(€ºÕP¼í^}>b² SŠ.(UÀÒàWxK…¼n+n„O£›¢Õ/ZáHÌ=¹©•À…®Ak˜Ò@rñãÿsÄ*èîø¨&³®Šž(E{'d\·t{ŸµºòdüƬ€f™ Á’@€e?(¢O½h³^àQl‹TúcppMT%&Ì ¥¨A=ý¥(G•˜Q2˜%ø^„Ì ©ÏeЯìæAJeĹ>®*=q*©†rNù¤ºñ Z½“”‘08.àØVµ¦S/÷ Ñý•8—i\‘¶b\»Ä©–ÈÓv Ë`  øŽêí4Ú‚ºUà`)z:IMN@Þɹ€ )Ä …äËý…Å´YÛP¯µ† nE”j‘· 6qe¾Ñ<ÖE!¾Ã…"rf‘ýê›Æ›X~áB*†jX2Fëì¶e*èj“%qC"“Êý\̉y bHÛýÏD†µbž«¡Ê€1zߣºÐqô:j»iz오°rj» îHB„c‹@)åê/"wðˆß (a!h P¯Msã&`žlˆá]EÁdݘ¨qa]uØ‘‡ÐÉ£†Æi™¡^CE½+—”ó‘¸r¡¿K@ÁÎr!ædÌ:‚GÂ1Éq­ ·¤p•û *_ê=ÉŸè×üDGUm·ö5‚ÌÂlN³Ñ6užÆà@Fò±û€ú¨ÊE¥hb“ÓÔ 28ÆDùP™*d[¹_€¿ þêRP v:@£zU¥ô ä´E7I6#¬<Uà¶ÂxD%?.C¾29Õ¨.ôGÍì;>«²êFSÛÞí}5”_­”û!jj•Et*%J€ØA×z„*ÒCèµá‚uáz3ÆP±…@Ô0˜E»HÚ-E ±GJQŽ„+…êˆÊ*ÜÂàrcNH}.ÃÄq΀Š>2MÍÐõQ]ø—¢§(\å~A œ¥GD¹×u1¡a`FÛ€Mo+@×@› ŠX È`\TC ­èiL¿MÓW%°ÊÛ¬ƒ…rTÕ‰U9ÑÓÌM°£kXßË}CœÉÛÜ8›£.k“YÚpQŠæÐHÇ÷nô”Þ•f9À£*¶ƒe€LÍ äŸ™C¤¿;äÑh,—æ¶“TM«ÕUl»Ù,ÚEf úW3m7†ê¾J!MšÑ`ÎÅaç2š+l)GR–¢sxÚ¾À€²<š¤‘Ö}UPC›¾´§-'ñ\¿-hVÊæÌ66f&¬y2ï2d^6Ũ++;iV«Kf›:}¬mÐâõù/xZºs«žvmS„»u[¤-Ú X./*O•‡Uy´™˜Ë’®åjq ¡B¯Ò*Ôj(ê1êñ™!ÓôØ1Hm¶å¸™TuœÚ…³ó³+`pð½Ü?%›Ç("0 úáÞ 2;ë_unìÄÝY¡æ®¡;’̤eÆê°…y]ëž¶Y·ê uâ{¹Ÿ@Qî/ŒËÁQm®ä÷õ5¦¶ÁEyu_–r¶ÛG1*¼Ñ4Eºã‚¨ë«­#éöf7†]â¶¶;óÊhì¬ZÐqä›:±RH¢ZŠr'öò|Ä€„‘¥hAötÛU¨A¬¸oDiË*ŽQ¿—ûµ›õûª†ViûTmá¢Íq£ ¨7«^Îz¿Û ÑôÕ>jèi‘‘Ù‚AÙµ¥hA^ ¢•1zIWýHá6h31{P¯j¨ÈŒaC 2~€‚Ð]²WPÜ"=öÍ2){ñ_ƒZ¬R(+ÝÙu÷Ü8j!/Ø«ËÈ8Qú(:®F·f”°° #¢•=ݺ/yT8žµºtC‘òª»w‡K ³»ášæS"ˇ­åí~mþê‰n__k—ŽØ–¢ 2;Îc_€²7š‘õ·˜¦ˆÆEÛ¿Ýt]OåÊq]J{ +ÔõƒxÎÀ0âûÌÛJézMðˆ2•ñl(KTÕŠ½<1 ä©$å`¹o`gU÷°ÚܘÕê™›b‡¬ÒvÚª†Þ*TŸU«r? ‹ú±zÅ£ÏR”³i¬Mj¦ ˆ!’ƒñµoíÒÍü–wHÖ}jhǪÀ<2ŸËŒ“L™Ó+Ë9¡Z•IšJÐ(òr0Uu‡\×˜Š®S ˜›P·Es$Kj« ÷Pˆ®w`áb]ÚÅÙt9i?­"™mx´´°¢mÐ"µš#ò¥h"ßÈ8ª]ÍbÒ;¡€GyÌþ,ÄS®Û`L\äe`yÛôŒUc¯A¦¼Ë`Ɔ¬*Ekdþv™Þ2~Ó €rÌ]«o÷U °–hËVÊã<ê– YÉR´–ÞdSwtA‹õPU´aÌj¢jC»`Ææ®ïŽÐ}ɳÚÔb^)-‚ÝáZµv¬yÕ`‚§‚UZ…[Ë-¬2 +ÏVÀ¦¾Ô†ï1´3É„‹Ò­”p]êä}„[–ƒC¦©\îSÝÈ3žmÅÉ¥ \«\®˜7Ï&%ÊtJ)jPu{¿.õòüâYA‹¶eÆDºN©p߈47fµ;ÐôÒlÚ´|  ºÈlV[¸(Es¬zºÊaL[Q-H–¢…¬\sQeL÷0CVÍtë¤0» Dƒ3/"rÂ]º³hÙ08Ýv‘ïUÓš-½ÝIºyfÒs™M}¬eë8ÉU‹C+Ë9¡Zí Ò 9]³)VÙ&µY» ;rªFD7µU…ó`*ÄK J¨§…EnA<›¨t²°kÿVÛÔéãhP[+sÓ|#¨™Lÿ8y&½‹ÐÓØ(,Ñ®[½"€EKUµMÏX5ödÊ[`!…[ ƒ$ŒÈømâÖé!ãW©ÅÝ»ÀÓñ›» ’\EQ 2{Õ!v„ A`ëø^î÷‚©Cñ¬Â5€U­Ëqé¼&+@ëï¾*gW‰̤e†ZŒ]icn:ˆÚ`Fo}ÑPÕ|¹ þèÔ˜®¼Y¥ª¨‰"θfaµÈaÓ3ÄîôÑ!ÓT†F ú±=Eî KÑƳÛkU¨»KÁÉ• ÈÆË*Šm×Ô–™3¬[åôòLÄ*R Ú&µY»@úcŪѕ汛«°zºH×Í-ïjÀöC•DZ›ÕÖ8+n:!gîgå€ñèVQÂD]Šr¤¼zEvÑìׯ3"«¢§/D·ïºDÍ]º6T¨GƽI݇1-Ç5æÕ™à›G¦>—QJeoÍ.“I¦á‡Ö çˆjuòR6¼`ʳ ¨l“Ú¬]ÀŒ¯*ª9\Œ©~ÖDm(/÷[ˆÃ€M–ã{]cOÒÕÉB´Xî/ì°M™RÔƒÕ[™›æAÈdúÇÉ3é]„{< µ}׋·Êm½¥ª«AX5ödÊ[¸†<,DÓlÀ_–”j  üLÓ8v§‡ŒÇضwP‚È0Œb«î F•@ `C€…•Ù«î(Ñ‚@ð½Ü_bÂæ€ò ý´.Ç!Y•Œm–ïªHŽ¡ê)\Œ‰WûqT±nìâH+pM¸V­e¬2Í™Á;^4x´©\P!ÄÊý]y¶Âò1U’hDàQ)ÊmfӀ̌ëõqÁ€k¦©šÁ ¼ Ÿ‚v P™rÿ¤„#ÑÓñ ’ »ýUlÑb)2Ó¢tVî³nÖju]^жÍ8(ͱ¢ q1¦c7Waõ*t‘®›4ÝÕ ÷ÀS°˜ÿ⢈^P[ã<¬PÌ["RÛUݬÅÌý¬ yøHo@L/° %­Ë]¤<³*"á±r…=êx!h9€†Õ,ÚeÆ/õt–¢œq÷Á RàZ«sFêst0»v&]„$¾—¢Ý|çP­Á Â$.ËA÷}\ÙÖ5¦¢ëµ=]¨mS`‰ViÖVóB×»«ñÌz³kÿ>ÛÔéãht[7Í72ŽjW³˜ô.¢02uå ¦×Êžy¬Ø6=cÕ@-É”·Pržñd'{œÜ:=%áR´XˆõœB4ã@nPTËÖÌìUw„è‹ A˜‰ð< Å ÅÈj¢jÕ¨\½&+ÀQ#”å`Sò¬öã€Õ¥\±7DcÍ]ƒ÷½h¶– Z2¦+ÏV@ùTˆïôT?-¯Ö6@’å~ŽÕ>hzÇ45@I5CÛÜj¯äI¶TùÀe@ ¯qvrì ƒAž¨¿ªcÝ,Qgzy1€Š,¶eÆDºÉß-œaìæ*«ÝÑu3BË+ ª…òv'œÙ¬ZƒNi™Lª®rõWÖ¢jUîg夲G?НåDûŽ0)ÌnÑà±d&¶“¨¹v®rg #V» ìrTKDs"ês™¸úÙÔ¯Jk.#ºhöãv5çfÁ4ÄÁ2Y«!§Id00äT¹_PêoÍ{jO+]`![ìÎw]ï¬ÆS9P™ÚµŸmêôq4ã#|?<ßHf9Q »J&½«G¸æ¬½Sº2ë(ÜM]>j›ž±jì5È”·PÕ<Ýü‰°ém ß"=äÚÖ ¶IÕªûã1gf¯º£L†d)ºbnÜâ0{„òƒÖõc̨P6oÍ ]Þ=B÷%ÏLZfŒ§h å°­-ÈßÑ4—û§(D1'÷½h¶– ZXd@Wž­€…˜þê‰GÁ¦¾t™Ï¨MÓÔT§ô&ÚÍ G ŠÛj¯ T”-¡™%HZ–´ÀÙ}ñ¬Ø¤Dám;Wd96T%ž˜ïånÄ€‚ãøeDäT¬¨Â­#bìæ*¬>°¶ëf„–W¤¶[‹O[›ÕÖj§T¨¹Ã'äÌýqXÔó¶¢²j¦[%<ÖÏÕ®PlËý̘:Xf´HáLÂHs»ö0g¡>—][ûUµ¯¥~œVVsnfP -_¢pw¾X<Á¥hAö ­R4µÍÌA²¿;w½ û³€k`Wvíßg›V?•¶Š 5ƒÃód–“q ÕÄØ» …Õ¹ ‰ÕµB§h‰Öõ= ÚLÌÇ^ƒU ÍÁ‘ 6àKJµœX¥åÌÓ|ßšêý­3@ –§T5ÎF Ã'¥(™½êŽ|‰] ZY&@@Ñ+E×Am`rã§þÍÖ÷Rvg9d„îKžÕ~ »™´[Žî€Û "Õ*÷OQ»ÐSŠ.…Ý~zZî/l-xˆ•û5ºòûúš(¨“ú»Ó°i¯»)£æ§©125îšZ4ЪŒeõA¯Es*QÉ‹…l°L"OcGÈÔA£œp@¥°›xbS/·ÊáX”Ýñ(PUÜ="Æn®"kË}Cæ¦èæÞX-Ÿ¶6ëí°u4Í$•LÚ4!gîâ…äDslzÓ¶±kmƪ°æLÈ”¢…ÕΊí¦Y4cÕÔUÈj÷UPùîÁbîNç\F³¼'¾èx-£³µÐبÆíî)£K÷ÕÂ!‡d-÷˜¾ æP]O«Šš€ðýË—/¥tÖÚ1Zh?hW3²³2r€â ZÇå¨f¨®ý»m<ÝÉíòЯÌ<)ï*Q™m]4îÃt¼Z»(b\¶f¶Q¬Û´4”û†±×` |l V¥h í¬uè%wÓôØ=´he3ÎF ú릨ô¬º£8TAÁ¦¹1nÖê,hˆE”?¨RY>|ø §¥hawVCFè¾äYíÇqµÚ†WN*,·DŠ@¹Š:7ö¬ 7½hXk¾\PaæxKWþʉBF*Ÿ»ë1õ`7i36eT6M¡%Õ:!#F£%¨¹Jrµ×"z_Ä,¢¹]Šè# ´N!ÎóÎnz[ÅÚ¦7ÈhpÖʦ^îF ÛB€dcy7'ÙS$VÜ="Æn®"{ºá™›‚ªøË—rШlmV§l°àvræþjXIÂñòlõKõ&%Ș]㔨Ü\õì›E3Ʀª'ÛZí¾ vJ–$æñéœËe@ïV¯"Ü"Ûø4& ³ z5ç*A¥mß”&`CµÊŒ“~|ÄÁÂrAšñ(*‡…ÒÃïåÁ¹Í• ƒ¼Ô¶c´dƒ\v‚ÖÈ yMbØÑkŒhíìÚ¿Û6=­ò!ÒmQHñùF‡®å@1ì*Q™åô(‹ ³O)0K÷),æc¯Á¸éy؈ãnŒF7h“ £6 ß"=ØíÎÌÐ3Ú°kø¬®fâÚ½ šŒ•Ù«î œ•N•WÍÁVß˃!ˆ$ag»,Ž}Quëå€fl\˃ÅeÚÚÕžmÊ ÁêRR‰±#ð”0²ŠÓZ5åBLa„ÎRzAáªZÏ ÍX6ÔMoÔŠå fx; ø ËýSº½¼/b­U,1’ £l®*¢i–C¬²tGÄØÍUÞ‡8¡en 9Uîäc•KqnlmޝrÙÐ E‹Z„GNÈ™û«aÑ ¦aU|VAÜXÀþRº€GÐÆ”kçåUkê„] Úô#í,šMmý*æ¦MÐí>Âà*ñ€z$óÂ<>ýs ‰Œp„R´Æu¶~ªðIƒžX¥M£nÎEºƒJ³$ôC ÕP5x$\ ˆ–à‚)ÞVÄ„XU¤ ×|ÔÖb9Êý4qË_uPÖ\ê²¢ÄdUJ¤š˜½|:P>‰)÷[@Ì£ ãî·H±i¨,Áõd+(Ѥ}aßU wÏ®"†:¬Š¼'ã®Q’ ¢¨ËõoaL7&ª¾˜¬è5Ø=BÌžLž­iÙj»³4`ò lÞ®Ukù4kn09d.d/ú5_.øtŠUùù¾ŽÈ/PІTÝÐh·}T)ÁuÖð—C¸Ü稹ùwbÛGm A iI±xñº;<[¤ÆU ÌUSÛúÚVÚ˜˜gÚ6:Ö¥ÈÜ_ €›z﹓a0ç€6{Çò3^DªØØ6Ð? ö2åÝ 0è>”Dý;É< ëç2æ…áÍiÔGªÆ˜3‚%È• AcŒ™S'cZ´¡xófô>cÌ$>—ùæð¹Œ1æÔø\Æó—ùæð¹Œ1æÔø\Æó—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1_ùé§Ÿ>þ\n:A¹y‰¼x_ ÈmôÔ§OŸÊ½1÷ÓƋ]yø{Ócž¬ˆ¾.aϹ4,êèT¹™`«üÝyØmɬÜtñ¹Œùã«W¯¾ûî»ï¿ÿþÀ‘óöí[è/u4¾x_?üðz ^î¹HB§âËàïMcŒ¹5˜²¸(˜Íʳ“-ê¶®Ì!FyT,EÏc.h³ÈŸ1Â÷兟˼yó¹ Þ½{WŠLƒ&èɉl†lñâ|Iø\Æ<HB§âËàïÍ[€ÅÞVïß¿ÿ¸•bûN>|˜©N™y ¶ÔÜ‹B±Ã/ÕEèJQÎd¾|ù2#(ÊýA|þüMcOŽdhåãÇE"iÏ€"zAÌ8ð£g•SP^eûª1ã*BM+‘kZDw”ÒœùOO Î| \ðQ*O ¦ýåþB±x6;-CŒò¨XŠžÌ÷ç­/Yó}•rYäÏáûòÂÏe:LˆÓM:Ï 98p}¹ur</ÞÁ—Ä}_cƾ’œŠ/€[¼7»;Ù.tO´’Þ·pÒº d§jbž}ƈ*›´©¯Éêx& îbZlø¡4 mÑÎ ¸<8CÝ"—ÇÅ8É!Û6(ÉœŠÑ8Þò¥fÛ7oŠÐ0©®iq¦î|ôd0³°?Æc SÀ!ÙöËÖ•¹&¢CÒïyÈ|0õ1\ ŠXù3Fø¾¼ðs½M1•"Ó (MNdñD­Á*aëäøh`‘Aö3œ³;øM~DOÝå5f“Õ~#¸Âv*¾8«€ß›‡£÷R.ÂBòúõë"}A+iX[ЦÁÈb]’9‹õ}1å)¥Zc0¸2n …XýTX©paÜã“ ±ƒJÑSâÙͤÁ«ÀBé¸þ:.Är­œ!IÈgÄÓ«,#× Ä.†BzpÍBPri°†2 Ü?…[ð¨T[ÈÎ쨤¢ÔYk×12=„ªžùÝw,ò¢Ü_PLNËšë”Oæû!¬¾¤Ð.#VMGYäÏáûòÂÏe0ï`¶ÂK¨Ü›ä`r"™ƒyaëäøh¬Æäì~SÜô5fÎÈŽIïVgNsnñÞ<½§ª51–Ô¯_¿æ#P=…G,‡¥h,èYw‡³×´»ŠB! 'z(G&{|k¤¶ê¢njÏö™Ðt»<þðáƒLÝõód(D–‡°ªC ÿ“üÝíΠP`笎XýÈ@ôh¦ÇwD@Ÿ¯iíÑÊŒ©“Ð<0²œí6=ŠÈ8AM ì¥è)«ddð½ÜOÀ.FôÔŽê“Uvh@m·bÏ 3°‰Ò`235çÜ.3'óýv'[ù3Fø¾ø\ÆÜd}¹ur|4Vcrv¿)nú3gdǤw»=æÑ¸Å{ópôžÊÖÄ4 ÄŸÂ#ÂÇR4ǻ˟6Àëy%»Û!†âÍåOlda’„;3=¾/úˆMu¦ òU;'QÐï_¾|)¥=ðT¹Ñ~d&‘üRt4×ÇjÇðdö¯b‚~çÓU&[ÜaØ€hóya´Û˜(Ó&3SsÎí2óp2ßaw²e‘?c„ïKç\±ú%I\# @œšõ׿Ë}^NxÚþ”€åúsbŸ?†ZêǬšý‘þj}¹_~ÂyV„†ì œ¸ŠÉn…OQ—ÂòÔ&ŠÜ´°(ZÀmÖú¾è‰(Ô;¸æ°YÈO ]Þ’ø6Âm¥ͱ]Ð&FKd¬WVÐÆ6tãüÕ“ð§ãbçF³qKçqpieT®RµˆºãìUEz±p —¡\ɉºªÕ3ä5âp±1(Ü$Aô”Þ4°gÓÀ×qàd­í¡µÜ€§™LÕÊjï´TÓÜT÷u[Ü”¤ª"µíŒJv¿)ÄV#!mEº'¿˜³>À#РHH¢•ò,}§*1Ç4sòv’M¯‰1°du­v ž öL]MãîûWáÂÅLæÃ¼UGÛÒä»f¦-Ä9z¤†pÍ:𽩲n2,ÐO#qQŠžÍ­€VÒxZŠæ 6¥·üÌÕÝíÎC{d[yœ@1Ú£X z|_!”êe$KŒ†ZÑŒ4@“;b&‘üRt42iwê¬r¿zŠ-rNÀwÞb¨R`•É·ÖEïbiã-èNžíKbYo]{ti[ÄmÖ"žvc‚*(“™©9GÆ·TSq×*…W/š½º23­<…ÁY> -'õDd[› ¾zèiÛ­(\YG~&Â&Ò9—a¯0‚èT”(Ü*ÏR_][î/°"¾ãMP,ÂGêW\ {*«ôt_3«‰²U!À­5»bf&Br·í’¬uÊ3DóÑ#™<" 3ª(µ`ùKÉ.xZäžFCºm%ƒæ² Óà"4Mf6š@CEhWžõ€|‘{v)ŒFq­þ"“ÉZŒ½&~]aYH«ð×x+P˜Ðl w•£°›öh®r™@~æ}Xò¸î¶N³[º£† ¼Š%ñ=³ S ëVÍA>KÑnïdÀÖˆ–ãº]Ø1ĺѠ<àmU—‘o˶摭Ffy«€Ïp‚¡-"¬¦ŽH•ÿ]‰Å+ÍkÊØñšÈ@Ä2_ªŒ©¾VTbÂGU¬¤hºkbX¤¶N æ,ÔíšA[ƒœ—Ù¸.Ò Ùè&íß1ýfÀ~V¤û-ò" ¨ƒð´M ùMñT´³Ö+öµ;I uJÜrT #(ƒ”Ãíj_IÊw57°p2ÙUІ`l*Q·”.¬†¢¢ þ-P»“‡ÎN0… ÏùSáš×0)¿UmuYK«9›² Ù}ñiäâÐ`2cöîÝP«\i3JшQ¾›™ó ½û4ö[²9gë2#ót;’ˆp‘HÈzœài‘Ûùq„MKz.ƒlP¢ „… ·e©Oy|/÷Xßõ‚ nYNbõ«dªÅ[Ò¾½Ve«B=ˆáúñ=VÁ5h+¶¨.VU;`Êñ}Sô€âT…má;/@Ö›z¢<à-ÁÓ"ZŒ‹í²•R! 02 VK„Ð+~m~A6€1tŧ¼%Qò™¤N´ÅX¸Úk@ ¾š¸Àê Ê¹ S¤ŸúÕf8ðßcr² ¡§#í.®¿Å Aû¦ y4ÁÂßmC•hÛW—.ÁU€f ÃòØ4Ëã†V^pß"ߣ@\ûâ‚­à» Ñt]Ck_‡ï¢-Èq”ã%¨+>€0ÀoáU="YOIC¹¨.žÎ‰œÔ#É£Sp $Ã[JÞ’*0¡¥¨0&®‹h@iP‹è–uñ½H¯¡¶pA§bn€Õõ–P-XXùRõ ñ½Ü?EiwJѲ™Æ€¾W’Ò0~ÿvëAI9cžM ¨ý”iÛ‚’"@ayÜXˆï¼Yn è‰ò€·¤jºÛ(Àµ gDÚªV4S NJYQ×È<ŒP–Àf–ŒÙ×î$U(tæRúƒ#㫬ǯ‰€ml“µó¶¢Yz>¼2©J¹ÕPT¬æáõÀB60ut—^cèìjO ÊÇ`j"jg¡.“-n5¬ lƒª"¼Ñ…­kf¢‘»ºöèVÇÅäk&¡¼U®L›ÌLYÞfæ¦ÀÌHgÅJ`Ç2#ó]é'= #®‹P IaÂ[«oü ¦Kz.£ïšŽãÀ`Ç€,õU½Ü_PE€§q) ×$¨ÞêWª…m‡â$‚ ŠÕDÙ¤P;(”ÇI_Uð4–0FQå)À \ïÌ}2  údôâÆ£´”.åQ!Èz³… ñ½Ü7(ò$Î,h¥kQÅ*È@«Š62qžRií|¡Èd1yfp~ïŽÊ åF¬H` aI¹º¸‰ b V)½ÀG´¨nlQÊ!VX·Ò¬˜TÆ_õi†ÌÐU§£g«V4ÞAT%ïb<#r0*Tжo_Mm~vÁ”gC0ƒ á{tmGBu‚U·*PU¹PLÊý…F2’PUµ#Ûa¸jSH’R´ ¯A•3q¬Å±©ô&­¿„_U+@¹Q!CA‹KÚqDS3#•fB)ZÈjÁø*¥U ' ®•ã¸e9*V§·¨œß£N…±­“X<Û{S‚ª§b»  fÕ$úO9³.Óõ®«?c_»“´¡Á1ý„6Zš™ÿ¬Ç¯Œ€)ª°¾wmÛ‡²½3är•?«¡¨çáQÈA€ÐUóö*Šy¹¢©>ŽSNNË“-n2ljˆ_£¨rOù ª~ÔÈ•rÖÅ÷jï‚Z[_sÌÀ6&Ê´ÉÌ”åmfÒ0¹è 冿²µÐõ½¯4Ïìíi+¶F~aÓ%=—¸È2[é’ d]«Š]åÙkCý ÚœCúfÍ­& ˜W¨Y©?ƪµÔ´R®2wöEOå­§@OA«3#³P(ò  —f(xTŠ.Hsµ#zgÌ,òÔ)™¶¸ *EV3ü™d-€‹ùn"ò¥;5£¡X.²9TÚªTW9ÈF”wß[ i¬NµmmB¶u£—  R¥4—¢v¾·õÖŒ+ 鉅"…¥h\£6P‘Îù Ü=‡(òYÒfî0’UŽGV S6vBÖqRÛ8¢§­¿;^]Øô¤ðX³Ò,†Z…3[> ƒnF©«§*ŸŸ@Ý0¸M'uJ¥swÎÈÁ­ÓoÆ8åEìJÐíâ1U¸Ýò.;Ú§ …ÜG‰¡àw{ü¨ Ò5l7R>¯6«¢r,u–jâBuÊ#Eâ)Õ‚g7AcmÞÙÕáa \y*%ƒ©[L¶H1€F»Ì´%¨ µÊ}@9 ™î›ÓŽJÑzå «yÌŽ×Zé–+Ó`R)"Ë«<‘žnþ(Pq àtGz÷åµ£Ðõ]ªæ`ºd[#ŸEØdŒÎe/~v ÈR?ëZU즎úb¥h!+™=«‰²Ia¦ Ha5~öÁÖŠž:4{óI õ+#ë_¡XeËô®gdµ4ñÍŒp̓ƒLÎ|ï&@ä™”_ºè8 ²¤ËŒ°,¬ÒLËVŸxõÒ‹ª¢PëQ@xÍËF¶m8cº¾h)ßvzœâ)žäã«:"÷gƦm™ü¾ ¤³`ë¢Ègö°"¾—û…kŒÄ÷bŸa‘V@žÕBôÆ›  “ª6£±‘J³˜üÝÁ›ÑÕ‰ÛƒR´wr§»ú×LžM¹[s~€,)÷O‘ý™È¦ßŒÌ;´¥”Õü³ÚA-šÊªpÍ8%v´;Oбmì¬h ®)ßíñC"€áIa0#¿ Ù_%À,¤*£êAéÉ8ÐY´Å¾¸mßÈ-¬5c‰æ" ¢RtAÃêÀ)6`~ ÔVu™1^ÆÄF5rñt“1«0ÓÚeåÊ´I3dy•át³Õ/Zñ ûh Oº]ßõjÈVM“¬š´5òY„MFz.Ó´‚²ÔϺ6ëQ’-¼VûUoÄʞ݉ÒU˜iRˆŠ¥è ²(íˆÞx¦ T Z¿2VubEº²~›â¬&„RÔ «LXÉ3;Hm±g'‘3“µföAx³ŒRrf»bm¶«PGZÍ2 …ÙáÅ*²­Ü?%›vÆt«h?Ùª¢|eC·0¢î‹§9JžA_ïÈÀkæ¬\t5ï&ZS¢ÑÁ'cÃfR‚ ¦¶”áíb]tý݇ (÷C6£±‘ ~ÖƒÙƒHæ©`ßX˜ueWí59?`¬óšé7Cä#,$íÜ’uñêÄ÷rP VoG»ó(±£3ÛÔ18ã?$šúHÛ5× 3#¨BöTU¤*EtAÁÏèÆíÐ"{D ¦e2èÁŠnzÍ'UºL¶(18Õ¥ÈÍAm]óÔÐàÚM Ü+Z˜i0©Ü_ÈÊaÕbÈì´,Ë£;û@‹*1”1>»[éú®ó_€ü,¥Û¡I•òH·uE¾a3à±Îe@·õÕ~Íbw¢t+æbÉïohÄÑ“§UH#T ª( È,ðb¬³ë‹,ÁE†JœU#ì¬^'j(³ÿ™¤/Uá ð‹ ap)Ê‘Scán`iù ÚR™¯~ö@©³ r€×^;úV¡†mxˆ•û¼ó°¤† "«ÂrjªWfµ4”0ôt‘Z,ur4ØÂÐIêï"V‘Z•´¨V5²rAñ½Ü/D2$Pê„UÀ–ƒ]4t “Ëг´ÖAmIÂÎ’AüY ßËý4ó¯‰ Ø¼X÷•ñ8kVp °-T?êÇÌ—’i€¥¨6€6¼x´ô@ ° ¡*<-÷Oé“ùQs²pZR™'äà ,`¬¤B:[ iÐ#3îGº»¡…S5ûµlmwÝðÊòÊ6vnäAôŨż(ÏŽ@ö,’UQ9G4Zª±¯à#>Eâ)ñuy hWÁƒO@É™˜wÓC¨ÅU§&[œ›„ÚàB¹Ì4»²ÍMé3\¿B•ÅÙi¹k¹ ¡ u¡a 6”Í'¸eyL‰Ý­ œµÊýô…döΰÅV¹ÈZÏ"/7c„ÍŸËlP¨u?¾Çr\«<[‰vÁBž²n ʋ܅Ñ“§UH#T ¢ScØÐÀ’,ò¢ë‹,Ye~…70ÈÎ*>«1yfðÊÈÔâêOꀄ³qAh ˆ¾wý(b«´JôV#[X±j=ê† ñi—¶Š^qբªš+f^±ÊùApÔÅ«(¥¶"µÕpÈÊ#PuÍ# Z©êâ¶û›;cÃäò Zi)Ãñïú;fëkbÀä8©àÀªRt«Òh'®Ñb»9‘†™DU)¼«T–Ó¤ÖZÒ5fà£h-\…–Tæ )„P ˜iWACGàZ §k•÷#Ê«î. —Ù¦P/6Ø # m™¶.R¨ Õ â{½™n¹`Eˆ•ûài,¬ ZP9; ³PÀ‹±Î®/²“ C‘±zþ%ÇF¨¢^¥¥ha5&ªø<2à¨^î§Q‹·8—™|Uèd-„zq1¥k* QQMƒùh¬Ú–…W®£åY-ÚbsŽ%DåEiÂäÏ=”ó¨RŠäÑ|Jmë¬Új8d墙FF°…ÒîCƆÉåÕ®‰Ûܲ.JQC×ß;^cfÆÑXój>È6‚ëjS' ,E mA˜%['“YÛ5fÕGÐZ¸Ê8°R-iQl«ý@¨¢ðXgÅŒû™´J• [ÛÝD 1•#ÁXRExÐã×Gå ïÈaÞBóêjgE`>¼Y² BÑ% þ³!ƒÛw ³ø^îðV¢ªUVUM¶8)6 µµ9 Ñ7nH]‰aRŠ’YtžwC¨²¨™ÍÌ®å1‹)ípÖì¡Gú¸\µÛÝJæ;Átxâ)•\OF°b¦l|7Âf€Ïe6(ŒoJ^”lú̘ÞÁ¨X-"A¥Ñ“§UH#T ª( `CK²È‹®/;,°j$U&¬ZòÌÒT/÷Óh Q9ØeR¸Ø®¿‘,Ô›À+Õi¬±"«¶Qa^­PÞ®Œ»U›\ËjÞh­¥’a›@R±¡A„eÛ|Jm×Y’©]m®F¶ øqµ×]Ù€n3.·Ìdø¦ß÷š˜a<ŽÆFN+ÈPG4¬ hC8Þ.T•YÛ5fÆGyáR´Æ8°×L¿û‚6ÙÅD»ŽÆ 7µ»•,q]‡[$*#ÜÚõø!`£@#]ÓWÜ_ƒÂ;™6„~,E ;2ðš9dß›âÀy@}QõTf0É’| ¬e­nVÕHFdä¦×Ä<Ù8kVš ÜJþ˜“Ò%j7åvO T•YÛ5æ.ïÍk¦ß éÌBÝeS+ÈTì‘g0×A’ªfÚÝÊ rS´¦¬vòÉzüú¨Ñ˜ÛJB°c‘ÙE g¦VÍÃíˆËB‘±/D RKTî{Ä]7{¶‹æ½ñd5Ó"˜›„Úºqà#°uÍ —Y¸£•K‡ì†ÔÑ0© éZ¾o FÖÕ(ngõÝ­d¾·Ä_â› H4¾ËÖÈ_“ß&;ÏeÔÝ@c¸òiÛs«ùÔm}µ_³„ÈÊ÷)¤m[…]ÆqÈžî‹ A÷Õ%PEiÀª%YäEWÃ[w ÷GÖ˘³è{ëÈê~ò™¤UÏÎóØbëcËÌ{B‘ÁE)ZXM‰+_u«ÍEV…ñUx»…bð´ÚÔÅëŠîg7êë,áÁ¾ ¤ `ë¢aÒ5){S;жª§V8káû`Y±šáƒ7c—qÞŽŸNÒUÂBÐ :…O«v鿤 3 J€(°{|¥*Òµ°x¶÷æ5ÓoÆxf¬v¨æºô sKQÃ|»;„"æÛÀ¹{üú ß¥¡šmdóQÑàE[ã¿:M²$Û9°Šûòð@äø`à¨Ê}鿲u|3Ö6Ó"˜›„Úºµ{ͬ‘»£™K™wÙÓ¬\™6™™™års~ b’hné&̾VÆ«ØUå[#Mn|›ì<—Ñú²Ó@Ûs«]Þm}µ_³„Ø(ÝŠò OQðB-Ï6Â8€¨Ÿ Öîû¢§9¢=¯Eër ´Æd ì'YäEæ íÁ÷yc2b$»³ž"ƒ‹RtAöoÊȱ²VÕ³“°.èú‚×FL õlwù›eÒÌ߈”–æÙ“å~ȪmÔV…wЄ2§ª"´¾Ñ[¹O­Þ2=›@ïP[–´D~Ígàî9d÷›b‡‘Ý1ŽBªª XàÚ·“ôÂZ­Z…´þv‘¶6ƒ×D—Mãhfb1¤ÙOvÆ€À‚61´ô¨^Jù P[Û‘1U—íÎùƒ%Ø:ýf¨¿Ú„ ˜dAÒ?ØîÍ„óíî` Í¢ëN·û®€^] 2lSfDOaF6lãä<Šƒàü‚IÝ\ Ð=f%”Á÷rßcF†¨Åj‹Lj›otj«’Ä×Jw†É^ ¹;úwKƒ×kµåÊ´ÉÌÌ,GÚ³¼} ®¢u†vf'Ù×JWgöŠW—MdÐdkä³›Œç2€b½®É]CÚžç(è¶¾Ú¯YBìN”nEÍL`3ÆXöž«ÐPA­XEíè,¥öE/¾‰ãà‡;,×Ó*Jd¿bRˆ/¼,ò"óEñ¨}ŸAZ¬ÀV¨-¾³¹€GíH} |ŠïQÃ3;aT™w<“ ×rýÅaT ) `IŒŒ´kµÌ߈^W–”Ò H!BC|ÁàFVk)½ÌÚ-S—UÛèW^ÖJr€ÑªÌU¡ü¡f½5µ(‡ªÊMÀ>štÉCUml#ÊØ6™H9£S‚´Ã!VœSl5%DaÌX4§ðV1QA «à{à¨-jn¡u«©ñQt‡ß˃!h—µÐÐük¢ ÄŠÉqÔ§pYöˆ¡‰*ÈÈyú bÓJT=ŠêÙlƒÔ€Í[Ì(€[Rî²8€6cöåá<íkT”¢‰¤¢0¾—ûu_µûí2“«-ŠtVµeÑ€Ù±9\CßUˆ‹¶Ó5rwôï±»!eÚdf,ß· ñÝ0½” ;ZÁS —û²|Qðä­1“±dõ%…k>*÷²È_“ß&ûÏe2·ìþ¬ç²rÑm}µ_³„Ø(ÝŠp…x;b*Á#w*]3¡¨¥*%lý¨èèäS[.` KpAáÚÞ×Rd‘c_Zk QY‘›=…7V« %(o7$¢]»ÄÀ>³ƒŽl¥í/€XR$ÚzUdò`ìoÞQ¸¥Õßö†ùt]µM´áí¶Ž´ARQg[Eh knðeù N×M޳4¢œõQdk‚¶ nÙ£º²ãMA6™e8X$ž2à‘ýAÝl›„ò"tÂÌxÄ[J®‚x*¶%ƒ×D—ã¨u\ÂTU… òm(‰ïÉ?h¨Ë¦ t­јR@aå”—1óø\ÆcŒ1¦Âç2³¼ ¿ ÜýXšþ¦Ààw1æåás3ÏeŒ1Æc*|.³í=¾_þêä›7o°¬¸Ö_–Áu‘6ƘoŸË˜y|.cvðyùkë[ya9ö²ƒà.6Æ|ãø\fxgtÿJ9A¹?)cŒùÁâ˜Ó ÏeÌ*>—1;PÚlSS©ÿ"xÙApc¾q|.³™Ï—¿RþêÕ+¼ð×Ù?ž0Ƙχ0¾~ýÚr߬‚$Aª avÿ·ó âS^¦ÅǻƘƒÏeŒ1ÆcŒ1ÆcîƒÏeŒ1ÆcŒ1ÆcîƒÏeŒ1ÆcŒ1ÆcîƒÏeŒ1ÆcŒ1ÆcîƒÏeŒ1ÆcŒ1ÆcîƒÏeŒ1ÆcŒ1ÆcîƒÏeŒ1ÆcŒ1ÆcîƒÏeŒ1ÆcŒ1ÆcîƒÏeŒ1ÆcŒ1ÆcîƒÏeŒ1ÆcŒ1ÆcîƒÏeŒ1ÆcŒ1ÆcîCç\æÝ»woß¾ýðáC¹?0|úô©ÜŸD¾ ʽ¹š—”Æ<>Ÿ?æ{à·åÁ£ò’f]†ýù§»?²i€ëRjŒ¹^.žLÈœËý4x{¢Öû÷ïËý»2Æ<s™ï¿ÿþ»ï¾ûá‡ÊýÃóÓO?Á`ð2f"D¾ ʽ¹Ž–æ[É ÊÍ£‚$_"âñß&»gÝGëØ?ótÇF*,‡€ œòù¾Ùis£³i/Ï&ä}£¦ÖÉŠ»2Æ<ßî¹ ^“oÞ¼›ðW¼~ýú×çÇ¡yú€®á Œá­¹’}éaÌ£ñêÕ+f2&®Rôx`꣑“f3~/•}³î»wïèéã8x—éN™©ÇõËÛÐ/pëOeë üÕ›cƒe L¬¸º°ÉVD]gÑãÄ÷ro>}úÄœA0KÑ¡ n§ÜˆÏeŒ13|£ç2\¸°VÊç?1˜¡™qïí±ìHcMY<9cj¥‘ñðèñ?b°oÖç¥èÞ<ÿt‡ý<3ßµùy*Q`Á­c«XÄ93ƒŽ}Ñ‚òÁÂfPÀžjGa|/÷&=Å‚*†‡àåâYP&lMÍ“w7dŒy¾ÅsM[ðnb#Á±\ù±>@a ØnÅ£}^† 5pööÖô0f̆ƪZž@à‘ÿšÌ£‘åþàÁüx߬‹Ž@T|œ;Ýͤ:vûl¥腾Gã˜àëÊ @Ö-Eú‚>½ Œ ¸Va}ŠšÀ-º) µˆ‹"½ÀòªÐ´ Un+ö;âñÁHü:|.cŒòížË`YS}²WëKp‹u¶¦Ë±ò¢Ýú2xX¶¦‡1cn44fÔb•_ÍZÆM7!ûÐ 0x©ížuÑ·Þ¥oâØén&''ßk/ƒc‡|Fv$›>ªÏ¿pèµåàãÇXÒtW5j ÕÛd‹xJÑnY¥Ü›!·K›Ý—yf4OnM†™I8²»!cÌ#ð-žË`}F‹ž[¼ç4]Ží|íÖ—Áò5=Œs£¡ñ2Fܾ>4 ¬bð_ÀöæØén&'õ^;uÞ>ã°k•óy&É[ÔwÈüA÷áQu¦ÃaþÆËÙy1׋g÷<93 Gt-ê8T¤µ¼%h½È>~üˆr¶%ÞäÿÂP¥?FP9ˆdXýã>ïÞ½‹UjµÞ&3é±I!w•×СƒøÎ[ýý ý5¢ ¡/ð¨´ü%ÈùLÀZÿ«?üÀ^k½Ë*V½kµýØ Ú Î_¾|æ"º0–¯r  ¹,F+æ1˜ õz OýÌ(Þ4Tä.tÇEkϼZåIæÊ™ol‹@C6 ªt‚®Kµ¹‘(”çtÕy ÚÈ€M#®JNƵºÊÅÀ*ÿ·àm•Hm¯õ]wä¢0Ædzº nÔ\åLÕxº;0'Ç2mæ@þšäŒÃS®g­6£ÔÌ$]h¿LŽ#m i¶ÚJ6°uY²Šª@[)š†l­Xu€µD¸ˆªx‚AH¡?ê™È‘j áº;”ÀLŠD“ZÚç3ÂƒŽ€ž*toÝabƒîBó‚.Õ(,. „å¼€f^ã"v=-§šXböu+ÅZEô‚Iž.@´¡…­Sá#*ľC¾ò×EzËг(Ç5A4pËrh(¢»ÔB[)º …5@ Ip]JŸúB €r´+—UM³O»ëà ØIƒU‹· ºË£›l ¨X^¤/ A/¨ßAê1° Ä!€[ ð&Á0hÀõR{d$KÑ2娢ldŒ ް]EßaLe.²\™„[–Ã\G“XUEt.'Ç21gŽJNjF *RFÎÂ$^@«aÞà-¾3†±évfÈ€rÈCI¹¿Ðšº{Õ‚ƒ¥è)r§Ía–#æ¥4‡JâSЦ‘å~ 4Á¶PaY²oôÒ$ê&<‚G¬… Õb*F Iy^@rf YP·h ßÕ§¨^5¨eù EÛmE>D“ àš…¸.¢9†žrAå°D¡‹Aˆ–ã{å#A¡JÑÂ!Äk\ bêU‹ÊÎ’Ræ¨*¥uPLu˜k1øÂmà#\”¢§   ¿-¨bUdÀõW#žN¼h+vQCÒ€n¢Nõh»fÇí/EƘ 6œËhpâ¢]Ðx޵ðÖaa6,ÙPõTƒ9ÖM7•˜;XR´µÞÎY×#ûÇvÊ€ë8ãšAm|v„n€´e/í=`R+3˜ÊUÄ£RtA[/bdæÓcŸB½Ûâ;¨J&ß]v OgRNýHÚŽ&òkÇ "•1ðTѨtª-è)qU× (>Q³¦”6,ÐVípà …Û~ìNMDØðåË—òàin· ¹Üu O¡°J¢ºíÓUµê»J@ámËP=é ÕSÙÓFu-i£M:ᔼȒ“ñiìµ UϬ2 à:F8V…H𫹅ÚP«5oþ@‚*?ÑãY$3“n”“ KKrHr‚¶.³¤Û €T1DÜøå¥h uk¹¿MÅÓÊÔ¬§ŒÃ®æ*K4ב¬»I\žµSÜ* iŠ Ãæ*“à UµÁQn ¥èúQTÆ+t×1€j ´é¤Ší#¼2r&Em½PLº¾£V•Ï]h6„Ëý(‡Ú¶g„ªŠŒ™_¥\ßAxÚÍð.Jï¶9YÚŒ)÷ ²¤L•¬Ó³Þ‘ÚÊ5U¬Êã°­Þˆvy°0«˜–ð¢JK¸£GY×´™,m¬2¤­ »1fÌì¹ p·\h´Ç÷.«€ö'EšŒâ8×ôš ~*¬Æ9f+ÖÊ&ÊIÔ:ô·3ûõhjÛ©é¬êl~ܺ2#{H ÛièM_m­Ç*Ó@L9Ø­”Q“é±[!ÍëÖ¢k•¼ôŒ«Ì¤œzdYtå Ý•´ñ)ºµ-Ð~Ç~Dua[) tçyººÝ75ÖÝ@){[›åòä:)¢nÛ}«j“J@¶gXD«©¡hÍòÌ /® J¿T=k(ø]ªJi®zs„y¨tóSÁÌbU™4àšœ NWæúä™/r´ãT!mÚhÞ¨8€Ñhåe*µAØ1ŽaG ÍmX0[ê)ª62@¡›·*ÂVæëR¾êb’EUåÝ7£:wÓêB=U)iëŽ5Ðõw&EA×÷Õ[ά@½zµÅìR–vã¦V¢UÝB±ÚA z#¯ÂH¶Îj’!UÂ+Ôqy]A6lÕéYËÁjðªbU®îè*Ôä ªŠj–w«È¸ÒÛ7p.ÙÌoŒé2{.£Ù!ŽäˆFuœ\0 YØŽLͤqjÖ ÕžãÕŠÓ ®Y˜M”“h¶ºRO†¦Ë±~š^èAÎV´/t®¼Ì€¥¨!{óÉÁÌ’î‹JöT/ÝSĤ’©UØw+daå‘ÎÊ5VÁ÷jƒÛ¶¥P\aT\9ˆ²·²70¸-ÈåAVËýrßÐ ¬®ľ© Œ­R¨[¿²^ž!ËF°ªV&Ur$[Ê+Í*g¥0 ]·ÖVéæ³Ü=„ñ´ýÊ*ªÞµŠÐ6èß4몼êMzïUOmBJÊ}@l%3iÀ ŠºlàH––D^ìNÎÁ\'Ë»³DÔÜM›n»”$åþ‚L=j)ì)ðQ`EU JE¯ ‰W‰ m|4oUd«G”ïÚ,gaR)JöÒun¥“ÚðhÓ@Þ÷ÒœIQеs°6Þ„ü-÷d–vâ{5T»¡¾²ƒÌ(EÓ¨ª7RÚW&i…kÉŒ­/#E/³_š«ðn »Èf¨¡l:R@b×ìƘÙ=—Ñ ÍÆ$Ê)çDMÍø^Š.tË3aÑqÔt6QΠI§rü@düØN΃ 0J•ûB7€f€nKÛxUѵjÕA)G§”¢ Ö:1ÂYzìVÈŠÝ<É\SvUá’þÉNQd²aVý’’­ƒHšãbµ7µ€ëFŒP К@S@ô²% Ø75êϬÂRŒµÚ€ÈÚA/d ⼪¶ÛûR8/è*ï*Œ°Ö s[Q壱¶MCx’™­zÚõ+3L^ Ö`Ý?¦Ûb„6ƒØÄŽX ª¨ È”¢ÔÊd¤yàè¶2P+¤?s–1̺uÆ»å[m«¦f3dXŠh&LL›tŸàº›'óVE¨y¾.å»fwƒ£­cÖ³ kÃj¨»–tUEÔÅñ¥9“¢ Û"í\­»Êª¿-™Ù›V)·ë Hà¥Í'+C-0ðÊî*Wa\Etm«è¾Œ½Ìñ¬g»a—ñK2…݆"(§@lt5 RÓÀs8³ç2šð4ƒYÅxä¬=Oœ^”Pa Ä9Q³L6Q®¢w ôg§Å×£yml'#KÊ}ƒPÅY‘ÁE&£¤ŽëNîÝ7V Å÷M;y¥GôQªÊ}E8æU–»ªbõ3X%´:³·o&Ÿ!{²7. N€‹ Ä€Ì ¢nJ¬ö¦4¶ÞR?Õ¬E€Ì«µ¿ŽAU](Ó °¼*ƒ€tãÐýŽêHT¬»C-ª´ÝÁÒ"åqoÖUa-ªÜO0ˆ*µÉ¤™!<‰ªB´êiׯaTHPw‡åÝ#ÝIx5VÇæ$@­Læ¦É Ve ³nñ.BùVÛª©YÅ V x£4†§3¥òR]/b…nÞªjmª+ùÉ—¦BŠò ”: «¡fEˆ•û…¨-ƒ1ÓfR°nÖâdîe¬ú‹1;ñö„$ÉšÞ´J¹]¡ÚX«w–Ȫ¸T`´[îZ=-Ò_F*ÄE)z UxU1–ãš…•y‘LaF·¡Hwб„…È7ÆÂæs™Uâtä˵V¨A4òW‰KMmû拸ý[ýc× érl'CP”û†ní Ý€ñË@OǾȪ¨dÕAu¨|TÉ P„cpºéqB¥4 µÌE&Ó/Љž*çµ ª>Ç1@öÄxVìË„n”*äBl…3½¹ ”(žãQÜV§3•À€jjb P½Ü?eµ8è96l‡Únï«0s„Hyl·«0ÂZã1R‘EUñk뺣ºÑøyT}¢UO»~ C¾±Áuõƒè1Ý#ŠUl}`Ò-rÈŒVF^µ ¨ãøÆßËýSf¼‹P¾Õ¶jjV1C†aІNQo$®p4jovh¶eëKS!]J…ÕPÓòª–B±J|iΤ(´8°s’¿ˆùدÖlj««”ÛuИAµ²%lEÖj¦Å¤ÇDƒ%޳pl†|Œ.¨¥è)ŠaÞn¶È’*J‘LaF·¡ &Ftœ*‘É„1f›Ïeª…BK©pap4KˆÊ‹®ÍÈ%_-Ë'ÊØø±.¸õt³:¡†º Ž`”ªÚºã—žŽ}‘Uq¿½ê Z\tÿ>ªdP (Âq®ºÑÔ+Ò/€ Â[Põ‹h(õãîùÄ“=°¡5Ð|‡Ì€ƒ¨››zókÃ9Õ¡Œ@|°öŠAŽ“U[§&*Ìú òTÛ¤‡,¡€04È6=Ú¡¶Ûû*Ì!RC×Ua­Aç¶dQEKS;G ۠͠ꃭzÚõkÕ0¤4†9ë’ Y$…b[ÏLºQN™ÑÊèÑØkµ²)9Q¦µœ0†Y·Îx¡|«mÕÔ¬bÆVÃV‘…ÑÄ-ë$¬;ïQs¸ ¼ð·È]Á>¨; T¸°j¶[µÈB|/Jª—æLŠ‚q‹Ù[o’Ì_ÌŸ_-[áí S?.ÿöháÑš=¿J¹]‘…h—%Œ$쉷ÒÏ8à6ÆV}U±f†|Œ/#ªÅ :*ßU1–Ë’*="™ÂŒnCU”€JPkÀü³Íç2™¥hpóÝZjbíd1L¢Âl¢Ì@E¶ª·Î-XÐ C=B·ƒö…nÀ¸Ç'}éZµê ”Ç×ጃ]«²ôØ­öã; ‚몉–U‹Õí ²g0 w¨3ƒHšã‡Ñ4'Í,E»@£šIbs4 bÒ…îdV ²Ú"5ƒvV¹Fm·÷¥pÞ®òÕtb­Aç¶ ¢ÊGcm2)ÆG>¶A›a&D«žvýš7 Û j˜&Ý#´Ä4ËLRëÇæ$@­LFš^€n+µBú³Òk|/÷O™ñ.BùVÛª©YÅŒ­†­¢@E4â¢M3l =ÂwÀº×ݾSH³žÍ`CÃØ:ÄÊý µº¬ö;é¶H;Wë®ÒõWAy«`öü*åv4F2žJlùRÄdögå‘®«Žg=«Š±\öÓ.™ÂŒnC5ÝŸ ˆ1æ˜=—ádvühE1Üfs5€Vâi°éPV³L6QvA-5÷ ‡2`uB'œ…óc·ƒö…nÀøe ŸZTfD´8¨dVÔz1&›Ì^6@6ódé±O¡œbœ‘èfÂ.¿ ò¼ŽgO«¬¾qÁ¾L€BÖjOK‰ ®:nµ7Û¥Þ5(†ŠÀVUÉ)v´*+º½ Š]ͻՂnïgýRÑí‚ÕtZíÜ–ATùdÍafO¢ê]«Èª§]¿6¦©c`FdI¢xÆ‘Þ5i €L)jdÑM“ ,']ÍbÆ»å[m«¦f3¶¶ŠmРÄá6Ã8°;^š²më™Ñj¨i9ÄÊý ÁÀ¤–™Ý»‹œtý•aÝq16{r•r»ZEHü8OÔ¦dC`eö3`0è;6âè€< ³•’jUš³°Ó’A@2…«i©Õ{ì;dÓ0ÆÎì¹ÌîY˜hêùòåKW?Ñ«û:ÉÐD9_ U4 eÓëáhºÛÉYæ•û†n÷…n€¬í®Øâf×¥ô)Ù†Y¯™öe”! ¾!¤­[ @X&•¢…,=ö)‡eŒZäzlÒ£Öohùµ)%8ÛU.ƒ«`5]z|GÐ*Ú잚عÕ8YÚ€q¨bwbÑ/NnU Zß E)zJw2…b¦s+QÝ7âÀ /&XEV=íjØjت ƒn·*‘*›»&©ððœ’éfÑØ °;9ÁjüÙz"ÁNƒ&"Y’¬šºš][ Ù[˜ÈÂ*÷ÔPUÞR½ÄÇ­Pëóó\`”¢9VCMµ•¿û^š«ýNº-*íW#?¦ë¯ ÃÐ.E½Ê»fO®Rn×A«È;˜JmÕÔAÃP(Éö¬áú—Q·ãâF¨Â›e [ÝRÝÆi&ÔP–Zˆ â Þ7Œ1‡3{.ÆÓYÝ¢ë¢zÍL…|жsPÕŠ&ÊÉ E.È&å.xK¡"è¾íVÑt9¶sõ½…G¨:h_èÈÚîRhr¯^ŠD¯“Ö:HÚø+C*±2`9èÆ_j«ðfé±O¡jÁ/D Ñ h_ÿì;|×Ey0ÚZ½¡¯D ­ˆ[ ª%£4vdÇùÓÍUe]´P¶mššX+3IAÌKÑõBwh¨b«9†q«Zõ¾Ê¡¼u36Zõ]¦PÌtnÅ ªûFPH«òyhÕÀ‘UO»~u ûòåK7å~78-l‘´ «*[º&©°mÔP^”ðQ–“@2PUŠzŠVŽMN ¿ZË •ã{¹Šb8h"BùVÛª©YÅŒ­†(ÇÜØ3¡„qU"Åm$í¾¿Ð/´'C…“)ó!?ÿÒÔT?X¤µþ®†š–C¬Ü/ì{i®ö;é¶U,íbö@úË}N×_Ö[$Ìl†ïº(žr£ZEU´°  š´¥œ›^F€‚jÊBlõTáͲEåh±]ˆÆi&¤@gõФ³ ˾!0Q…*0xwcZ6œËÄW8&â8tq¹UP·=%N‚bÙðÆ– tÆw6”à)Ê+ÛÐ:«@¾ Ñë„M (.@ž¡¡m Y½ÕwA[å¾f´´#tÔe¨…©AÆ÷8ÃB?-P‹§l’:[(§¼ ƒ‚uQ«ªX½ó@| K B4ŠêÒÙ:1>jþOa¬Õ‚˜Ä(UTu’]”B45j)6Ÿ Šû”^  ,mæ3P(÷ 1žP¨á Ü",Ð;b(A¹Œ‡¤üªŒß75Ñ©J•@E*lÓfuhP3€1¥h9œR9Ø¡U($ð‚P QßQ¥k ($T å~6—E6, ~… †Âk†ð$RÎôh=Î0«žvýêÆBH©RtY¤R8–<å0Êñ]î@¦ZvwMÒvlN‚É,Pr`r<¢Lk9¡~|/÷O‘aƒ&"”oµMF 3£e«a@ž¢.ƒ Ð},<*Òð)€$fx¸CÐѪ â{DÍ•û5b+-ÐS%À„¯ÖaU­°>¢UˆVCMm(`ÀÒÔ׺ð}æ¥ 1V©l¨Xm >heé´¯« Vþ"šÓõWà P,Œ/P’™]uVÛ5äF4ƒÚ%±³š.àNyð”è&|¤P5~U„k±T(Ù¢*h.¦ yÑV좆¨6©G Í.¥ªàéÌ€Þ—¶RdŒ™`ù ¨¦uH’r?Q #¶”öÐx&K _)÷MuL7,o'š.QÕh.uTq~nŠhNÛÉYm•ûšÑµakèÆÐ’T•g xEå ºíî@ä Þ•¼èV•IUõnLÆé±O!Å𽂵@·"À«®H,Të‰U”BUf¶ìDãU]ÑuŠ„ærŸOc¨i )EOêm(rI\´îø4ë©Mi¢~do)m,Áb‹×;Ôz%j‚T·h·ˆVÓi²s#l7‹*¨|¬ììV÷Å ±GDÔ¶êiׯ®aqŒ£)÷ù&¡…µÐb•ÛÝLàÓ*V7ÊI€Z,ϲåj‹T·û’dÎ 6T,äÚ ‰H–$«¦f3¶CVÉ€Î"Ú0x<­ÞÈ”Ÿ÷ލJÅÒÂWZ Ñh <(÷ Õ;t5Ô¬ÞÆÖ—æLŠj˜i1‚Z3˃Ìߘ_}Xàµæ“Ìì8ƒ·è â”تªìF4FT–w» Ä© –eÅ [º¯'‚~„<¯Çi&Ø,„|fg•Ébë Ø¢z)2ÆLÐ?—ÙðÇGà#¬‚V‘kÀ„E1ÐýÜ`óF5$K ¸E!&"t³hu¡æ*w8Ñ |Õþ.\ý€¸ÿlaxA¹oàÓ¬ƒ6…n ^o±¯qÑ. +‚[f¯C…׬ÎZOÇá…¨ J…ÜfÞ­¦Ç&…0˜’°³â2%ëeººÆÈÔ™7ôÖAD>bC,¸n»ž°÷A¹R©%(I°¶]@‹•0nѺ H‹*Q»ÅÊÜvcÆ}1 --ÍÅDZõ”O+¿2ÃØû(/-´bcXzp]¥Á’î@Äê9 Xe¸Er‚ÕÄàSưEÞdK–$«¦f3$?ð½%›A˜ÙA±:oá]6y‚r?á…$v;¶ñ)h_š2Œ%p¶]c¬†šO!VîŸc`$J3 ¸Ea›c3) (“µH%¥¥ÜÂå6æ]þVšq aô» ̆¿¬Õí²Èá4ÔR À΢”؉¤%¨‹Ý ¸m»;‚Ò‘R!Ì¥ZçC†Âdœ-ðH1'RùAÅ5„ëvâÅõصMC`Í@]ªc&èœËL‚9BL¾B¶µ¥…RzWª©öa90tR5îeÊR”Àצìr¿D•çÃ<¤S&âCã³hàUúõ=–/hô£žññÜQD¿@)mÀ#Z_½¬ÊýA¨»I)MˆÂ¥h"½0NÚ+Ql³Vdü¦]U;&Fì¦î_‰Ü›âs ¥½£S:£4¶ËA.jã4Rt]×­wÉIq–ä<5%¾ [ƒ¬Ž¥èj®i‚bÓ­§‹PJoI¥è ŠÒ™°c•RšY¸uNìñyãUë(•Ç0zWŠÖ8d@Éé2Á˜»³ÿ\Ƙ}´ç2'¢Ý,UඬgRj,Rï‚ÌÞô#cÌXjŒ9׿4Í3ó˜«cŒyñø\Æ<7X{ñ•_îO…Ö+å¾áíå·ˆ»?hzùEâGûl§ÏeŒy(8Õx§jÎΕ/MóÌ<ì*Åc^<>—1ÏÍ©Ïeh—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1ÆcŒ1ÆcŒ¹>—1æ ?þøÏvo~üñÇb1ÆcŒ1ƘÏeŒyÂÏ~ö³?þñÿÞ÷k±ÁcŒ1ÆcÌËÇç2Æ<Áç2ÆcŒ1Æcž ŸËó„åLä·÷ýò¹Œ1ÆcŒ1Æ|#ø\Ƙ',g"ÿç¾_>—1ÆcŒ1ƘoŸËóŸËcŒ1ÆcŒy6|.cÌ–3‘ÿ}ß/ŸËcŒ1ÆcÌ7‚ÏeŒyÂr&ò¿îûåscŒ1ÆcŒùFð¹Œ1Oð¹Œ1ÆcŒ1ƘgÃç2Æþüþýû·p]˜‡Äç2ÆcŒ1ÆcžcÎe¾ÿþûï¾ûßËý~øÂcÞ¾} ÉÏŸ?K3®Y}@”/Eüãû÷ï•#*Ëúé'–ÃÔR´‹?¾zõŠ&EPBͲœ‰üû~ù\ÆcŒ1Æc¾îp.ÓžS´èØB‡8oÞ¼aÉ€wïÞQøõë×¥è„*¨,?ä\S A•ãÑHó8,g"wß/ŸËcŒ1ÆcÌ7ÂÝÎeð}ùU¡>E4|ÚeF¹q>~üXŠÂ¹Ì›7oŠö†ê÷•PÂ*לËИÍvQÂ_h¢û$Úi„åLä¿ß÷Ëç2ÆcŒ1ÆópÏs™r¿†2Æí¥ûKL@ç2ó¿:tȹ̫W¯ºŸñry™RjŸËcŒ1ÆcŒy6Np.óêÕ«åcåW™º¿Äîu.3Rÿ|̳±œ‰ü·û~ù\ÆcŒ1Æc¾Np.3ù«LÝ_bx.#“æƒ`žåLä¿Þ÷Ëç2ÆcŒ1Æóp‚sÀ* ûU¦ì—˜€ÏeÌ&|.cŒ1ÆcŒ1æÙ8ǹŒ~ñ'ûU&ýS+ð€ç2rçFúÍ5,g"ïûåscŒ1ÆcŒùF8ǹÌÇ—sŒ´–~‰©ý@ÍžË0àÝ»w¥È< ˙ȹï—ÏeŒ1ÆcŒ1æážç2oŠÜSt–Ñž¼ ~‰ @!+¾zõŠú+>|øPD/Üô\&þ¹X^JÍÃàscŒ1ÆcŒ1ÏÆÝÎeüôÓOE40øU&ýÓÛÞ™ ù4£=|¹é¹Œ>Ú3þ÷Ræ^,g"{ß/ŸËcŒ1ÆcÌ7Â=Ïe~Hè~ŠäÓ§O¬Õ¶‚*,ïVÔ¹ ¨¿¢=¹Ý¹ Ú¢æÉX™çg9ùÏ÷ýò¹Œ1ÆcŒ1Æ|#œãïËVñ?aë—˜²3Ët?MÓåFç2>| ZPý3oó8,g"ÿé¾_>—1ÆcŒ1Ƙo„3ËèÃ&¯_¿.Eá—˜²¿¡û ç2ÐIÇÿÜï#ãscŒ1ÆcŒ1ÏÆ™Îeº¿ÊôÃð—˜À#œËÄC™x¨dåLä?Þ÷Ëç2ÆcŒ1Æóp¦sÀS ß¢¶W¯^ñ¶åÎed¶eŸåLä?Ü÷Ëç2ÆcŒ1Æóp²sýÖ8ô?§qA–»ŸËøPæ\ø\ÆcŒ1Æc̳q²sý•_VõêÕªªûžËøPæt,g"ÿþ¾_>—1ÆcŒ1Ƙo„“Ët|øðª¿Äîx.#S¯?ß1ÏÆr&ò›û~ù\ÆcŒ1Æc¾>—ù)¡È-\y.£_eÒ©Çà—˜À•ç2´¿¥ˆæð³—™9Ù!ˆF©cŸËcŒ1ÆcŒy6Ž9—ùøñãÛ!>|(¢Â@ÿ»Ë§OŸŠÜÛ·¸.¥9ïÞ½+Ò9EôÂû÷ï˃„Õvg+ÌcàscŒ1ÆcŒ1ÏÆ1ç2Ƽ–3‘{ß/ŸËcŒ1ÆcÌ7‚ÏeŒyÂr&òoîûåscŒ1ÆcŒùFð¹Œ1OXÎDþõ}¿|.cŒ1ÆcŒ1ß>—1æ >—1ÆcŒ1Æólø\Ƙ',g"ÿê¾_>—1ÆcŒ1ƘoŸËó„åLäÃ}¿|.cŒ1ÆcŒ1ß>—1æ >—1ÆcŒ1Æólø\Ƙ',g"ÿÏ}¿|.cŒ1ÆcŒ1ß>—1æ Ë™Èÿï¾_>—1ÆcŒ1ƘoŸËó„Ÿÿüç?»7°¡XcŒ1ÆcŒ1æEãscŽäW¿úU9\ùÙÏ~ýë_—RcŒ1ÆcŒ1¦‡ÏeŒ9ŸËcŒ1ÆcŒ™Çç2ƉÏeŒ1ÆcŒ1ÆÌãscŽÄç2ÆcŒ1Æcæñ¹Œ1GâscŒ1ÆcŒ1óø\Ƙ#ñ¹Œù–yÿþýÛ·o?}úTîŒÏŸ?Ã<YîÍu|øðñ|÷î]¹?3pÜ7uOÏ—”ËÇ—Üü ®Ké É©­Ü›«Á@<1ʽ9Ž_Ts,>—1æH|.c¾Y~úé§ï~øá‡R´[¨õùóçrc`-D£¥èJÚB3†ñüþûïËýiA×31î»Y=]<_L<,š²ÄõÓ’ü(U†` žè¬roB3³ck¾|.cÌ‘ø\Æ<'Ÿ?~õê–,(|þ1m]BÁ<Ê?Û¾†±ÅjC‚p±üÍ›7¥ÈLÀxú\æ(NÏ“‰æ%D¡Æw\_˜âs™Ãaנʽ9ˆ­‹ cÎŽÏeŒ9ŸË˜çD+ì ¬ìŸítfë*ÿ<;n#Ûæ¸ª^üm‚ñ|Ûr¥®Ïe6ñbàùüù3ç%|×' ™Ì}.s8ì)¿>gë¢Â˜³ãscàþá>|øðñ?ÿùÏË©ÌÏ~ö‹_üâ׿þõo~ó›?üáEΘCÑ ëB,\—‰$.ëoÊÖ%ö´ßKÑa´°ÚðçÒ0ãùÿRÆ›7oÐ.xæ7­Âm!@pJQã ™rK0ÁÒž}´dŸËìãvϤßn¤ö¼ÿ~IÉÍâC§ÐÇrßð ç2;õí^ žˆ|¹7ásó­áscv¢³˜_üâå$&ç—¿ü¥ÏhÌáh…Ýî'±¬çb<Ï&dßê9÷ÜF‚¶Qì žçôªb`Ò}™éM4+÷·dꫬYÎîP~ ÏÏC¸Á3é·ƒ©½»žÓþ S¤9ÏÃê¨<Œùã'Õé8Ñ€5æ|.cÌ6ÅdøŒÆÅxí®Ÿ¸bÕø ‡¿„zÀÀÃnNfz“Æßb[Þ²{› Vƒ,gw(?çŒç!ÜÎà™ôÛÁÔÞ%|–´<#tÊnÍDz:*OcþøIu:N4`9ŸË³Â!g1>£1×°ºYåz<ÃÚ÷ñ—P¸xØÍÉLoÒø[lË[VS}Àjåìåòœñ<„Û<“~;¸‘Ú[ „Ï’6ƒsþ Svk>–ÕQy"óÇOªÓq¢kÌ!ø\ƘûÎb~þóŸÿùŸÿùßüÍßüýßÿ=¾ã:þ¹™U|Fc¶²ºY]]û~üøñÕ«WXV Ü¢°<îñùóçׯ_é¶¾c …¶ Üþ–c òúKK ™³âýû÷¨^¤ø' ²h !<Ù§ŠÚ(!]aHVÁ­0nÙ"žÒ$ÞȹÀÖž‚Ë•%cyî 4 yKâƒÀ-x[…= ™ €ÙTÛÚƒGE¨Ç|•ºL-TŒ¶A®Q2ckïtAC°uË}̨ZA•Õ?¸S¹2Û mÐYäî¯ܲš–óéæ Þ¤–Tù ºù9Ik'oí„þÅ¢~Ò2J“kÞ’˜$Hr p¬R7Ë4@g©°DruNc㨨Âîcs’™ 5ámå eù, «ÔŠ1¬€)÷ [’6Î:¨ÄÖë²E¹1!”džã{­(_ ¢] p#©0£j0£f×d£1†ÏeŒ)\yóûßÿ¾(z Ê}FcnÖ\µd ,S(PD¬„ø´ŠÐS°,“ÎCXéºH¯AU­<ËáÌÆÓEëM`µZ„PË¥ªŠ†Â¸)JÔY„.+Úò¬ÂQ¹Zìá"wakOeݺ[ÐHV‘ÄL£¿ÿòåK×ÂÊk²)P¸.º]F惬VPon²¶öN†âYîˆð8hÙu •mØ;e’ ëÈÀà.3i9°ÄôÛdð¼Z0HQ艣~d× u4·¬ã„¯ìŒtç=Á=<Ѹ@[º®È|ÌF@ù`0ЬE%Eî g@7-ÙUeÍesß@£…¨XîûŽsF@ìÝ»w¼Ž]\!V'¥.²Èg¡xT„ *;‡Ê‚ÙãEÅõÙhÌ£ásóMs£³˜ ŸÑ˜cÑ¢¥(€åŸbRŠZÇcŃ1Zè`ÛSD/`U§§¨…F–b,ŒJ…5X¥•gyÔ cØÖ׺«ÃJ€B?KdaµbƒL·H!êJ!.dX‘ J™%œ_ã[/¢k?4®"¿µ§ \æIÉ@=¸.r ÐF3Ý_•ð–Ä=$n%À †hÀ£"}aS ÌÆ#)dsd°óA†Ðl >€‘¥B`kï `ë•ûD†á)Ò¶g\ Ý"}A3€m­X……øŽNDE<¦HùZ÷·L¦%̃Úè/oIL?i›1x^-6ÒÔ `5ƒ7,Šô¨¨Zhˆ]`g,/ÒkI;ØWÃ$ʰà-‰£u ðB¹¡´Þ¶¥M2€ý¸…w1æ¨#Ùeì ‚\äЃ”20gZ/Ò €rè—aª+VmØÀ§¨ÖŠ] x]¤/ð)ê–ûÀ5 \ÀS€<Œªp-Ç)ŒïÝà£P¥( --| /ÐmŽ¡k§Ó׬d6h+î^T’Æ<>—1ßÏ|“á3s=XÁp ‚‹RtI®5M»Â"Ú厶%í²F+3\”¢¬‡âÚ«Õ™Á†ZyYÐL*ž6UæÅ…ZµqÒ*“Ààò`Aa¬Ê¥mUÐ4׎å~ÙBÀTT)÷§}ªG•~±£§älµÒI*ô¦Œ¸ŽÊqMÛ\(¥ û5HõU¤6s_ΰKÚŒÌw!Íi•g&É—,VÛ­`>€ÌA…:>r¤ ïØA ¦ãľ{ –WfìVHóð¨ÜºY¡.« ÒÖµ¡j© ì˜ A{êJô2=dQqx6ó ø\ƼXü,&Ãg4f­Òº`%T-‰C(EOÑ‚2.†V·yn¨–PÚVÈxQ%¯qQŠT+[€j‘W-Ö»‹]06c-v+ƒAfÙ×SÚÏÄ]ÇVdó 7i< èîðg4T •uú ã µ›åvWþÞ x–û9žÙÔãíñèN›è²ò.›ÒrGòD2ÃVÕj–ˌԆp&iènq 3Tݤ~Ï’6ƒ "Í™] ÚWw;PÿN¬àdò2#›Ï5¾*SWT/Ç4Ø=Ðͨ’j·BF¦rŠH'.JÑ‚âPÅj뤒ÙÜí5ÕêÚL4p¢%ꈬ¹lQqx6ó ø\Ƽ(Nz“á33F«4¬‡°p\„‘l»¨ÅPµ¶‹PO\fi%”í1´8«–PØJ+Ÿ•ýx0Ú¯Mr´¹ )S­ÕÆîZsÞ ©jž™Döõ”Ö²`PqÌŒû4~ðq?¶ ¥>ÚáÑ8È`Ð.Á®‰QþÞЧŒ¯hDÄPojzL×0•wÙ”–3é7 3lU­f¹ÕTÉf×ÈL(µª˜à–å™%«®jîFo^-ÆE)ÂV@× Åyœ]%«JytGª¶4ÀàT…»²b7Ôr­ÒÙ=ßÊ®ÉNQdÐP)zJw&”UUëm í^T´ª*¶f£1‚ÏeÌéyag1>£1-Z|ÄUVlZV«¢ZXÖdH ÔY[Fƒl 5€ µòY9é®gZÏ\P@by÷ç{3|úô ±PFEAUÑ`¢G•Id_O-Óá6û™sÆ|<«¦#4/Ó°)P Eûh©íÈÙL¹ZT73$Pê ¡•ðªñ@ö«nöQ‚ùpíkg\ÈTáѦ&æÓR¡‰R”3oðªZ”Su3(iˆPßË}e¢QŠº)7Ãj£«š„JÕ²<ƒÐ_ê Q¨»fd' R7ö3¡£µø^î×ì!xD™XP[eên…&íuB¸8Ù%hXU8@ödØmv¶X!cdüjˆdO[ª¸È Àd6ó ø\Æœ˜ßüæ7/û,&cßÍ_ýÕ_•ú楠ER»øÐЧ}¤Z«ÄÅÐî%Ô.žZù¬œ¨¡èÚLë™ H,WaÀŒx"Ö¥U•™DdÃ*­×¨«µ)Àõ«W¯æOgæã Íå¾!ëÇR(ÚG«¨­nœÍ”«õn†¬2ˆa¤Oubf<ýª«’ɦ öWj®¥2 t ƒ Å&pÝMËIû·¼ª–ÍP£´´ÒEYT™ÔM¹A£«š»ÝJµ3dŸ}¨P¨»fda©È—¢¹ÐµQ’ƒƒZxD™np*Sw+ütùEø®£Œ×t?«¥P :KtX3óÙ."{b<#ÝØv{¡¥ ˆ*f!’=YlW™ÌFcŸË˜³òûßÿ¾œ7 y1g1›Îhþñÿ±T3/-’Úõ–#||Dµ°«Áºg@©°°{ 5€««V>+'j(z=Ózæ‚ËU¸º# 8@C¨Ž(z &™ID6lê©È»ðÿ§«Uûèd•Õx¶ &ºý¸/P EûhEM”¢§ œ™rµ5¨pwïTtãÉ‚<¢Œê¶%«(J¨‚œ‡w_M_è²òUVÓòÄJQÃñˆU2µÒ©œÌ(r CUãø(‹ªy¦›r3 9Ô4ºª¹=©ýê|ÎäôjÔ*E™õ‰ýUŠæB×F‰%ãZxD™X°neêõ ®‰n»ÇëSP"a^bI ÎÙƒ–¢§tc«^Èjºíç=ÝØâ;Ìg£1‚ÏeÌYùë¿þërØÐðâÏb2VÏhþþïÿ¾ˆšIÝõ×. Z–keh Õ~¸š`Dj 5€¶òY9QCÑþ™Öå„Kт˷º“Et &™Id_OµÄϧLþìtÆ}ê„ã御ÛûuM(ÆAƒv‰Z®1©K7ž«ÆÙCÍ8z'"_ ¡ýÇ(]Ã@V>É -»Eö¼ªVö ¢=ÏLdY¤ò­–¬6ºª¹½_61õjO‘®’U¥<º3Óõ™U NU¸[áëås1ЉAAÍ×xÔý¿Eàsó«‹Õí ²§ÊFÑ­ ³Z¤µG!Úº¨Øáš1§Àç2æ¬üÕ_ýU9lXøfÏb2xFó«_ýªhÁç2/ŒñzHO«=öÃÝò1úá[¶öÊ–P¸ºjå³r’­W×jZÆ5%P b¹>>³øûž 2“Ⱦžê¢ÿÉ:ã{Dhü@![ŒvJ}Ô>Zed0h—¨õ¨áÀÞ!ÝxB9[8®±‰‹Rt >˜ù¡ñ8D]Ã@V>O––ê4QŠž²ÏàUµÜƒCþ\(]]#‰©¶¦Ý”›¡ÏȪænôäËQŸA÷àäôÛuVf»}}´$ŽÜÝ ÐŒ*©®¹Ê@ćðv€Z„ã `õ9¬1h…µ2›»É£xfà À¤VFîgÍÉžJ3CŽÊFcŸË˜³Ïe~ùË_–Ró”¿ÿû¿/1Zð¹Ì C‹¤î²F?@qùÒþ`míB³µÊÇ-4£•ÏÊI¶v”³í1€ìÕ·»ÖRøáÇRô}[&Uëu¢ÿDÓv“šîn!öõT;h^›ôæªÂVÃî@+ŽHyÛ.‘†˜!ÇöèÆsuÜšâ0×&-‹˜²Œ»2{:®5I¦„Ne^ï3ŒÕ{Ö¦SžloŒþ¢=­©Ý”›a°ª¹«A¾dcd+2#•Œ èÎç {¼¤9ëe:âéÛîX^Uܧpu. ÑY:òÈÂÛåú™0Î*åϦ˜«§*óјÁç2æ¬ø\fŸË¼l´HÊV'Ú›Uƒ¬<Ò.°´ˆŒK+¢õ,C+ºËY•“lí¨h´µþ#Õ†D«r-þº– ìäµLj%ñHqk»IMg›ç=Õö¡²y•Uy8; †“ÝT\e5ÈRÞ¶K¤’¥haß8ÊÈâ©°tíW–V»Så<ªWfƒ>Är6 Ú#Héo Ë î²5-³r²Ï`0V (ÀRÔ0Ù§úŒhíò¢M¼,åV‘ÎlC¾ª¹Û­ŸÂX&Íg»ÌÈF¥Ðb«6¨§*OUÀ—ê‡|T9¤pÓ@¬ˆ¶Êý…} U ð á/)B ¬‹ïº(æ€þ¥åý3aç¢Rtv‚M‹ŠÃ³Ñ˜Áç2æ¬ø\fŸË¼l´HÊVQÚTë!¬W´ÂB*®k±âÁ …íŠGÍ\ã)À’Këxêl—§™üXÅSÐzÍŠuá-Ôò—v– ò«*QB]„eÑ÷Äå"šFs¥hÙ¨´Çââßã"~GOá -­J! 1*‰æQ¸Peñû' hƒPG€X¹_`!Ø( <…1°dÒ—Õ £„ÝvÊ)ÉR´°oedñ„6à2ZA»êVÔB‹¥Âõ žÂ_˜b-&!)/bÚ€Ö°Õˆ@  !XÎ’qZÊønúí3ŒÕ}h P¦—™Áç2ÆcŒùF8õ¹ÌëËß þaùwZ¥ôÂûð·u»±åÕåOáf¿eŒyd|.cΊÏefð¹Œ1Æc¾N}.£?CpýÃ…XÞ=vù|ùW\ø^ŠŒ1§Âç2æ¬ø\fŸËcŒ1æáÔç2 û/¨ _ ÿU"ÅP½cN…ÏeÌ}øñÇ^Ž îÇ?þX¬y¹ø\ÆcŒ1ß_–”þ~‘‡ÿ‚êíÜY=fúüù3%˽1ælø\ÆÜ‡Ÿýìgüãÿ{߯ņóñã/¹œ±ÜØP¬1ÆcŒ1Æs>—1÷{û?þñÿÞ÷k±á||5û»ïîûuÒÐcŒ1ÆcÌ£áss–ýoïûås™Ý_>—1ÆcŒ1ƘC𹌹>—ÙÏeŒ1ÆcŒ1æÅàss–ýÿ¹ï—Ïevù\ÆcŒ1ÆcÁç2æ>,ûÿ}ß/ŸËìþò¹Œ1ÆcŒ1ÆÂ1ç2ü_n«ÿÂMPx@‘»HB¹_£k‰ 3ZýYù5ø?ØE–ýÿºï—Ïevù\ÆcŒ1Æcá˜s™ï¿ÿþ»ï¾Ã÷r?ä‡~€ð˜·oßBòóçÏÒŒkVåKÑÿøþýûEåˆÊòŸ~ú‰å0µ] <¢múKé7ŒÏevãscŒ1ÆcŒy1Üá\FÇx.tˆóæÍ– x÷î…_¿~]Š–¸é¹ÌÇ«£(ŸËŸËìÆç2ÆcŒ1Æób¸Û¹ ¾ÿ”SDç]f”ëøããÇ¥(œË¼yó¦ho¨~_ %¬rý¹ ¥*@Çô—Çß0ËÆþÞ÷Ëç2»¿|.cŒ1ÆcŒ1‡pÏs™r¿†Ž3Æí¥ûKL@ç2ú Î*GËÈr艟šñ¹ ð¹Ìn|.cŒ1ÆcŒ1/†œË¼zõj9ÍXùU¦î/1{ËP Ü„a,ñ¹LdÙØÿû~ù\f÷—ÏeŒ1Æ<'Xb…5a¹¿ðáÔƒ™?DøÍÂ(a…üåË—Rd® ËÆÓQ³Œž!¥Ès'Np.3ù«L˜S(‰ Üñó2h1¾ÿd¡ÏeÀ²±ÿ»û~ù\f÷—Ïe,¤0Ïèðטç z¼ÎD)=9ñ8–"ópÕ.µÌ;W—aÞ†åÏö?:³%(fŸjm"ËÆÓ|`b J‘1æNœà\° È~•)û%&€‰†uçgMRWžËTø\&âs™Ýø\Æ͇/î?~üå]^½z5h®íZ­¾yó¦Tþþûìgwœí7qå4«Pl 5„Kµï¿Ÿy¡ÌDà%R„†ÿ¬0Z^ŠŽ-ÊN¦aÉøU‹§=ä¡8*ùi[qf·HžøÃž×¯_/mn [· ‹Ä÷ß#ž¥´iS„¦)5ç¢}Íèmã.@»ò™‹(è)÷à&ûëD‹+$m†;ƒ!| ÙTåÕ‡Í͘,O‡¶<ã©Ûó œã\o‹eÒH•I¿ÄÔ è…=?ãh’´[ŠŽ {)~›,ûÿ~ß/ŸËìþò¹Ì#€ý§pøGf4sf`BëNe;fxÁº$›~5?ÏsåL^…FNî£ =«“ÿLˆ^(ƒÝöÔ9pÁL«œj@<ˈÈì1J«y®÷Ciì”ÎÈfì¯È:]½Ðz)mXvET5cí8ÍÆ¨wJâD)Ú ÝiõÈŒÕñõ8hÕ ²“»cQ2TQR‚]sB·󘽆Naƒ©>ËÆqM Æuñˆ pàk³sœË¬¾×õ¾i_ozaÏÏ8š¤Kd/Åo“ecÿßîûås™Ý_>—yøƒhÌ-‡ÿÄU3'šÀµ@[œÃ.Ú)—O³¹z€æy ™SÅ”À›Ë¾C­R|ðdhr^ ¤<ÒVOþóQ×¥4ðþò+À¾Èô3óv4 §ö™ñ t­Ò{u¿öM"º€[ÊWy¹~[+«pGèìç§cPŽV(‰\b£õo×)VlQ-’}äöEÖÅ÷r€|©9í+G‡¼ÈìWV ­R´ºƒËýhfèµRôð`hÃø‚ø”¢£d¨¢„Ü€àÊLØrãÑ:S CÐJQC–·àš@­ÖE9®¡Æ˜+¹ç¹Ì×A"÷Öí ¯·PÈŠ˜›¨¿¢}i’ÌÈ;È^Šß&>—ÙÏeÌ3€¹‘ó.JÑÌ`šÛMÅ`6Ã=?*jóß6q£I›(Ú¥OzGa˜49ùo€Äº^«Ñ£~ÍG=M—Ò§|\~íˆ2¸hÿÂèd(Ä b|€…œoY·:Ô¨:±Jd|/÷ ; ÛŠ:¨=䟮š:ÝiUɆ۹ùx†dØÊšD` ëf5ɲñ\¨Õºrövs¬1f’»Ë èÎZ»¼i~SIíÎ)zag´ÓîÌŒ¼ƒk&֗Dz±ÿ¯÷ýò¹Ìî/ŸË¼x4svçUm·@uV¾éuaEìNõ³Êy%7š´I …~öØý0HDo¼¡&'ÿ­ÐÏ$@uø"›7íöǨ­ìP†ÀÇäÖ÷à8‹Š+›Øñrgö/Ã…ïƒGU¨J¹OØaØh ¨’h¼Ò}1h%ÉMÝ<;Ï“ ›x@“ì¡a°°5dÙx ® Ôj]9{»9Ö3É=Ïe0Yté.MëTTay·¢^Ø þŠö gfFÞ´Q펉õå±lì±±¹ç—Ïevù\æ,`æÄ„ªÓ“U4sfk5Íäñ÷&ËÛ‰zŒN1¸µ“òI³á å´I …ì\=ïàŽ”q˜™ü÷E ¾àJÑÓÏní÷ ýüc&Â]«ÈÖ÷` ~):™´»‰­N©ƒxn¥;UCi€ú·Ü'l5lê£*7b–¢HÂBRŠzÐV› Wl5.žÅ¥h ʃru2P(÷9±7Ço5 ½Fµ“Ý·U^  «R:ÒÍÆMÍÝ.P‘Õº(§@œºr?ÁîhcÄ9þ¾ aEP‰¹ŒåÙì©öü’ Ó « fä\3±¾<–ý¹ï—Ïevù\æAÀæ (÷ìñ87 ÜÎOƒ«3§&´J€vMO1€>ÂО›w¹Ñ¤MªPÈÁÁJZ/&n¼g&ÿÝh;BûüÉèÍ V&Ïè>¨>X4ŠHü[ p±³v°Û)GŸ>ƒ ¬¢$,÷ [ ÛM·»ØAß½ÿFª:À5*vÝi½V<37ÛVn[àå ;x¥PîŸòáò?¶fÒ•’mC,ç@ד¼lÆí`ßûåËDOò@ª²dà›tÕ¢#Z…°¡×’˜pMO„Ñnõk€¨ÛŠ È¹â‰GEz·ƒ ï~ý1Ú±.oIôšñD!o«(µ^‹›JÌ×E>P€ñ t@®Q2ckïc2Ît.£ujœ#0ù²/žL ˜Ÿ#4Ig½­h¦Ë–ß>—ÙÏeŒà¬ÒN§˜$9Û<%¼œVgNMh•Â÷r?N1´EQɤžMÚ¤ …ÞDYd€âÏuüêäM°Œ^t•D-´¨Û"q2M”¢!Yz¬†¢¢ þ-Ð*Þí{;ouJÁ,÷—0ù£æVC—­†íFÝ´)!ÌZbD·­ÍtÊýµÞu3N†-ÐYÅœ6´­H²àçÚ*ª?† Á€råp Mðº…ÝéAªÇø³@^zj±TŸ‘SP¥×.4ÑU3 ìd9*îxý¡uHÆ$\Œ*¡…m|Ç-câ#4]*,@ ËT ÅVë HÆ @’%ÕK…ÀÖÞ1ÆŒ9Ó¹ Р÷%µ F¾¦\”¢54I¡¹Rt2úKÑ7̲±ÿÏ÷ýò¹Ìî/ŸË<œUªéT+<­“v0ž9±åÓv&ß1Ãw½ÐœMÚ¤ …&s½‰" ŽNFV'ÿ+#wPäØ8(ój³*«¡¨hƒ °Ka+Fn:ÕÚ䔆gL UNv÷ª° Ó.½¢ÈzŠé:¶0nžKQ@»âªÓéN«SMW©TiE ±¡Á¸Ón´f¨'÷¢l½€¬U¢ÍÕôçäê,éuV¡È¢§DíÎ?(Œnò8£Ü—1‚³J5ª°Zob0sb™Åi´?CÛ:Ãk3S­ítÖ0£êF“6iC¡WOwÖvÊxò?$ÚÊ’c—ŠÀ|x¢ªŠB‹.UF©i¡H—Ùýås™³J5j‹~ÍzH3'¦Y\ mu@w†ŒSô ²¶Ý¡iÎ\ÝçÜhÒ&ðšÊqQŠ‚›Õê°UÝÉÿhMZ«®D˜oÖ#ò(£’WÓó™6šcÏ ØÓöK…œZ}¹+=ªã'°iØ*ýÊ}‚ ƒd—ìÀbê,hæ÷ò aU€–WÝB v«ø¯¶$‡Œâ7¢Jiý€°êÄ̼ 6ZåþBVNä,.JÑ‚)÷ rªŠR7z;Ž2·Ê`™DTq0"ÚXmGj:ë@ãa@÷ÜjFCÅî@Y­«vÛI‰t5¨Ö¦Þ1ÆŒ9Ù¹ СOfŽ_Ù;l€¦›cg“ÕÉñ›bÙØÿÇû~ù\f÷—ÏeÎ*ÕtнçF€équWÙE3gF6ñnáòó{ƒMÚ¤ûÁb´-*;ºñäHÔ¹fOÒ¢̇7«";qÑ¥ÚHâS$ž²™ QvЍ>Û_3(¶úr囹~ì4fRrÞ°£ˆq«††ˆ£×]º–³°õZI…qÍBÔ*E=º ioÏ­Ø [§›•æná€L~¬G~ÅðÎ8‹G”‰ž‚nôT[ÙG×`’™Ddº]+|/uzýA35¬Æ36]1îÇ5º5PcVëÚ%ꈨa_ïcÆ|.SÆbC‘[¸r ê'škÆ?HÔÜ‘Í8-0˜UÐío)¢[¸fb}yø\f7>—1‚³J;ÆOOˆçÉÍœP^½å`± Ö*÷CôñìAÚÆÁ¤J=ð´G÷%‚Õ? £§ÚZWf &ÿC" ±¡<Ø·!é"ýóáͪ BÑ¥üçAMƒØË-óN©7ËýS¤gu´Žõˆ­Ñ¾m`›Fë ÑrºÓjV£QXs j•¢ Q<‚ÑèŽu)És@|Ç5,ѨTsóAb'¶æeåDÑ‹#B…Y-@ûAŒèF‚yw¢y4"T &™ID†­‚&J…ë_óñ¬šŽÐñ®†c5fµ®œmÛ%Ý ÙÝ;ƘGžË à›ŒHøë$”0þY¨ດ&hîX§Ä%¯&©Ùü)ª/”šO-éNÙßËÆþ?Ü÷Ëç2»¿|.ó pÉ…™¤Ü°-×Úš@lücÿˆfΙ¹.‚VØV¹¢p2l¡60ÞhÒF•RtY(ÐËu"Éj Éve|}ðò¢ ¾ãZ6 n‘¸…M”¢5äW´6]²à?qƒ7ÈÀI§¤mµ¯ã’©‹z¼Ü'@'NFûz”*hº5HÀ…•ºƒòrAIÝœ Q•`h…±-–0 Ô•éLxÈÄÅä*lÍËʉ¢ ž »²Pèå¢ugæ;» ´+ãë#О€Hçà(aÕÑO)"ªí BÑew…Â;H­I§ªâ€Õ8«;Ê}ÂÖh_ÏÌHœ‘éBwZ¯•$ÑM Ïq+ Q•¨êwž¼à)o1£âV#¢û›<ʪŒU)zqDÌ„TžÆ(nô”«“sˆ~ó Æó[”À]ƒIf‘amÅIv¿þdój<¡¼Ü7tûñ³ZwÐ.QGD ×÷Ž1¦å˜s¼±02Ä©pUT/È LµEîí[¾#Çà½R¤sŠè¼‰Ëƒ„£Ú=jÝ|:|.³ŸË±º4$_¾|™Ù^F0;Q¥h.FWM« ”ƒYW+KÈ—¢ã„BÎbm-wêòø‚¼¨VÆ×G@ÛÅð¨¶] =3אַUDîd›„ŠÝyx2–—¢†§´“Ç÷¯š0g©*÷ PHm“Ѿž™‘8#Ó…î´^«¢›“­d!Rs8s;›ŽÆ``.²é_NíÂNlÍËʉüŠ#B…mpDæi7z*Œ­dÄÜ®”ƒ®Á$3‰l²aÀŽ×ŸlÈÓøAÀÛ~¼Q Æ¬Ö´KÔQÃQ½cŒ‰s.cÌV–ýoîûås™Ý_>—yV—†­ËýÝ«®ùVô#ÙñA¼Ä{­,ã"ø(¡Ðrh'×Ï?E¶2¾>Òü>ùÍ©MÅ›662xþˆ*cw… €S¥¨aÆ©wÉ?ñ©Ø8Γ£lk´¯gr$ÎϺÓÖRE7ã¸5Œeâ#^Ç|Ž¢Oy=ó;Am ²r¢W#"ZÛ%K†nôt¶;îG"“ºc$3h¢¨L":›±a•ÕøDtÐ6hšñ(d‹QÃ5fµî ]ÒÍc{ÇC|.cîƒÏevãs#V—†‘MÂZŠekµ .FgZ™”œùô‡V–·X#B¡µ)}Ý7#ª•ñ•a­×ѰM{Å í`A{ÚÑÉäç¨2vçá<Õ‘V… |€eÆ)ÉŒ»#ž´Ñ’)÷ [£M`á‰Ú+Žƒ_AwZ¯•$•›r?K§tSZF~¸ü÷Ïh-BħP’6†:Û@eåD®œ;«sUPE©½˜‡Y2èƒð2©FM­aj:KÙ0 “lí#5]îVRCìÇÛjÀjÝ,£„4T™£]ß;Æâss–ý¿»ï—Ïevù\æAè. ±h?×Ù¥hˆ–bÙZ-c²­AÇ›|B õ‹heÁG1…l#ݵ/» Äuí•P‡ÆÂˆv•Ý£¢h `s»¿/ºáê†bÀî<œ„™«º1”;ã|^uJ{ø±¢Ž|²†]¿ªmk´zy_Ú0žM—¢ØÒS .d¶¡GªºÓz­$©Ta0²UÚ?,Ÿv7–P»•Jø”39¢êåþBVNájDDwª8ÄQ ª§Yô”‡°C»”. kP( ešf‰U Âj: ²±µA ‰rµ³Û±¼õõ$ßÍ “Æ ©AQ· Ô€Õº²ªm—HC•!;zÇ3Æç2æ>ø\f7>—1¢»4ärËS,‰°ïÞ½c!ÈÖ^ZŠMÊ 5„‹.\ÒrÐÝWh_±º²Œ‹à£‡BO¼+¥O‘³°³]•dûgmE@»)݇P°4G®ÕÈzªŠ /.JÑ¡(s“sñæ-.¢;ãÝŪSÚÀà¢åh‡JQm†‹Œª§PÂ*«Ê»ÌDåµ&+\(øU§Ó¶Ö0ˆ-š:ñ×áÀ5$!ƒï±|й4ƒ´íÊ23#TÞ*+'°i­3"bßÅÉB%a%ÈtË?}ú$÷qg©P¡‹ª\ P…ïU|P·H_Ðy% ~|j4Ó)*x©ÁZˆÛ"}‰)£v¼þ@tó«ÛK$cªÐ0h.÷ l4sÇ*cµ.làÓ¶]‚r @²];pv¦wŒ1c|.cîò±ÿ·÷ýò¹Ìî/ŸË<\UKC-•Z° +Bkh)–­Õ2¸ó¶þô«=ÖÍä±ò£@\nÅ8ñø#Ûu«G´B½2ñ6ûq.@wSìÀ° ò· žbQ^¤ÚPŒÙ‡ó ×áÑ`ßNV’þê ’GG—¢§PßË}‚ P)Q•Uå]6DågP'Ò¶Ö0%I7þÚ`·@Õ¸scÛѺåÙ®p¡ *¶Êʉ"ÜŽÎáù×Љ3ª¬Ðëªo¨ãº0‰…ÝvÁ C¶öŽ1fŒÏeÌ}X6öÿæ¾_>—Ùýås™?øÂª«Ü_À åX Ȭn/#X‘Cì±»` ÇŠØÞp1ÇëRm ØÏ*ÝE ùt^á< Eö©4JlÚ \ö/Wÿòå‹jMžÌ Jn]@Éj¶(“öìÎÃMÀ#V,û}ß/ŸËìþò¹Œ1ÆcŒ1Æ‚ÏeÌ}X6öÿê¾_>—ÙýåscŒ1ÆcŒ9ŸË˜ûàs™Ýø\Ƙ­ü´ìž—OŸ>ߦÉþ Àò²½3ÆcÌËÆç2æ>,û÷ýò¹Ìî/ŸË˜xùç[üAÇ“ò}ïÿ€ŒA•RùáyÙÞcŒ1æeãss–ýÿsß/ŸËìþò¹Œ9>—!>—©ð¹Œ1ÆcŸË˜ûàs™Ýø\Ƙ­,¿¶² ÿðï1cŒ1Æ<>—1÷áç?ÿ9öö÷6kN,¯NIžÿë« ÆcŒ1Æc®Æç2æ”üêW¿ZŽV¾òë_ÿº”~üüŸý³âùý€ ÅcŒ1ÆcŒ1WàssJ¾ås™Ýüæ7¿)![(¥ÆcŒ1Æcî‡ÏeÌ)ñ¹Ì|.cŒ1ÆcŒ1†ÏeÌ)ñ¹Ì|.cŒ1ÆcŒ1†ÏeÌ)ñ¹Ì|.cŒ1ÆcŒ1†ÏeÌ)ñ¹Ìªs™—÷o€1ÆcŒ1ætø\ÆœŸËì :—ùÃþPcŒ1ÆcŒ¹>—1§Äç2;ð¹Œ1ÆcŒ1Æ<>—1§Äç2;ø›¿ù›²…ßýîwå1ÆcŒ1Ƙ;ássJ|.3Éþð‡ßüæ7Ñ/~ñ‹¯À/ùK<úðáÃ?üÃ?” ÆcŒ1ÆcžŸË˜3ñ÷ÿ÷õWeJPާEîÛæË—/û·û/ÿå¿üÿâ_”Mð‹_üâÏÿüÏÿæoþæ÷¿ÿ}QdžW¯^}¿PîžÓ|:>|øðÃ?0Èן?.ÏöòîÝ;jûôéS)úæATçׯ_—"cŒ1Ƙ½ø\Æ<:ÙYLÆ·yFóOÿôO¿ýío±}úñÇK ®àOþäOþìÏþì¯ÿú¯}Ôõà`gøÝwßasXîžÓ|.Þ¿ðVüôÓOåñ^Þ¾}{”ªBÁ˜ ¥KÑ øôéôtA):xÑRž Ù*Ùý÷|Ê}Τ˜1Æs^|.c‘­g1/þŒ®ýå_þåŸþ韇'øùÏþ'ò'åf†ñ·¿ýí?ýÓ?•†Íc€ v†>—1]Î ¾{ýú5ö±ïß¿õêÕõrñ¹L BÁ˜ ¥KÑ @?²•[ Æ´'AʇÕÓ¢wïÞQyXŠ.È50Žá|sÆcÌyñ¹ŒyŽ:‹Éx1g4¿ûÝïþú¯ÿúÏþìÏŠcðó/ñw”pÛ?ÿó?ïþÝ™ú§Š¥ößýÝßuþižŸËD™Ø¹}øð¡ÜÄÔŽN Ú=ð¸áf¹oÐÆØç2âœË@'•g@ ÛãÊ\”¢I¶QâT ªæ›3Æc΋ÏeÌ=Ùwóã?òhàþávü!pÒ3šßÿþ÷›<¥›«ÿw aÄÆì׿þõ/ùËRsƒà£ ü/·ï…ÏeÄöÉϳý>„ÝÛWîÏ"Í>—Ï“Ÿ>}zýúõ«W¯nq,¨~‡/âýû÷h‘2ïæ3M’­”ð™I¿ÕæŒ1ƘóâsóÜ\y“}Lãÿñ÷ý±Ûßþö·EÅÃ3´?ýÓ?ýË¿üËÝ¿sô‡?üaßQ×/ùË¿ø‹¿ÀæÁÿÚé9áÞf°¥y4ng0¶”ËÞÍç2ßak]Šæà&|fcŒh”¢ož%FÆ ßែöƒTó%’l£¤©€ Ó6ßœ1Æs^|.cžƒÅdl:£ùÅ/~Qª=<Å⸹/Pc  :¡yÓ߯?ÿùÏù¯V?ªc®D{›rÿðÜÎ`ŸËhûºõô„;ðA§ìÖü‚9QbdŒû]¿BÕ:8P"ÉV JPŽÖ?~üH\wÿwØ|sÆcÌyñ¹Œ¹Ï|“1sFs–_Ã)æ.üò—¿üõ¯ ×à`y|Køÿžvt(ÿ´ *žî·ÆNö6å¾Ç§OŸ0¦°¥!Ø•C°Azÿþ=« úøoÇbJI2ؽÏÜEÆ€J?LE –½Û× nEz Ê‹®…®ØµŠÒ·oQ·»Ïœ'jY/,ýôæÍšŠvYŠDeШ…ï¼%qFÓÔŒr–Àšƹ!P·TؙŮ'A–¢!1«Á|- U%Œ ƒ%]0ÜXL½ŠÖëHìض)ªê÷rÿ¸œ9ˆ¶ø¥(A’­” œ­¿zõŠb¯{ÿt|¾9cŒ1æ¼ø\ÆɃœÅddg4g<—AœKé=@Góooý×N¨âÑHÜÛ´|øðïpâ˜íöÁ&°+ Ðnw396¸ Lm›€ÓõQĽ÷&ƒçÕ’n´ÑVw«¹J×k€&ª?5³Ë³˜Z‹\ +B=¢ÙÚ£-ÌÒÚE‹ñ_>*2 S~UñÁíàœÙ#Û®šñæÍ›¶!x¤°Ãµ"ú”n¢„öO¢VÚZð¨U\$Ö yø^`Rgë òaÕI¶Jd<|ÄÀT¬ÚÓ«ùæŒ1Ƙóâss-ûÎbþÅåOÆÞú,¦Ëo~ó›bÇ‚Ïe®aÇ¿vòß 9 îmº;+mfD)Ê÷Òq³Wê\já"þ@>–T±°:ÇTŽGå~ }Dú›Ð& %”é÷êÑ6µ±0<¯Ä3ŽV3®‹Ü•6Qоû.ó\&ž†T&e>Ö‚1ÒùÕ‚Þ‚êЊ`«/Ê–˜Ñý¤ Ê‹DÓ–2³ë‚*B×DuclÇdç2ñ CM°ß‹Ðcy¹µVùPYÕ"I˜WŠ. „à#nÕ\;/Í7gŒ1ÆœŸË˜üîw¿Û}ó<¿z3Àç27bò_;ýõ_ÿu©`®ƒ{›vg…^àNT›mr@û£u}šã®Q‹»8n¢JÅ=-®µãjwt™Á]´ùD­x€‹rhÖ‰naUüñ>neÈbï¬Áójm(AƒÍÚm¶¡ÈˆGQñô‡^óˆ4IQ‹% H$P ¡¾ó–‰å % ¹‰^à#ОÙÉŠ°Šå±ñ”…OUmá¶¢GÐPJ/D¯c²Å^mÅxd›‹Ÿp‰=;Ay9KdC¥·­=ô½@»ŠLì8¢ÈTVµH²µJ¡`²Ånй æ›3Æc΋ÏeÌ~÷»ß•ösñ¹Ì3€¨vk <¾ñg{›vg¥=O»Uؼñ)*Æ}#6`*o?Ȇ’W¯^UÛÚrõm±2ÃÚò.ÚóÏlbµƒmw€b‡Á3jåw˜zC—-éjÓ†¼µGÛ×nÅj±Ü7H3hQV÷Þ™/›"h'«T‡HN=­ÚRÄZË„U±J¬ÄÓ¨Êkõ` ðéÓ§ÁÓ˜·4RIP ¾—û]t• Å7áW·Ú£[ ¯¬jYÍ  þÊ„ç›3Æc΋ÏḛÙ.;ìy9é¹Lüc.ç:ÚÀ®)þ–“ÏeŽ‚{›jg…m$·1ƒ½Ÿ6EñàF;ØîiÎ&º†¬¼‹öc3öh;ðz@fتZfu·ý`“ê‚î~˜hÏ\ýš˜ÒFw*tŠ4g¿ûÖÕpld€o?Áô)¨-EOϹڣF¢ŠÑ;Ÿõ»jU*Ï™i ý-¿¥_t t¾Å‚%×Y¿¨ã*«Z$Ù†Qqˆé*bÓóÍcŒ1çÅç2f¿þõ¯ËûÂãŸÅDNz.9ètG§6þaáÞ›™r¿0s¼‚G”‰{QnŠð}òó º†¬¼‹6¥_=kp»œ!3lU­öáÝà ,E90€ÂƒM»~׬ê_m_WcUÁF²ª¹«áØÈ¶’u„R:îÞuF™(„š2Ñ~Ÿd‰‘%’P0³°DÔJe[Ù™× ŒgèLr! ŽdÛkr!&•ú+p¾9cŒ1æ¼ø\Æì!žËüøã§8‹‰ø\æù‰Æÿå_þe)5×ÑÝv7<Ý]%÷iƒ-åè]Ã@Vž¡3TÁtpZF)=CSIfÕ²"ÀNûÆíðg ƒÇ:©¥hAå°¹ͱÚèªænôŽ  ™°z šKÑô–¾€ŒÏ\ÎCª¾zØC)ëR'§ëÐÇy È>›3F¦¢%èRm‘k€1”YuA’­¶,Â*—òùæŒ1Ƙóâs³‡x.ó«_ýª”žŸË­KüM ì—ªMf×0•Ï€±O[üJu4“í“Å>ƒWÕ²"D{’É.ȶ©*ßjÉj£«š»Ñ;02„vf¡žŠaQÂT±ªh#°j¼š«ìiU]Cש–wïÞÉ`°éœ«kªâÆ“‘ åÛµ? $ÉÖþA„?]þk¾cP ”cŒ1/ŸË¼|~üñŸ—Ýð]ùñÇ‹A€Ïe¶òchú^À†b¹À½Mµ³Ò†gð“s<¢L<ÝìÓZô3íî_î²òy°ç¤ þ¹™lŸ,ö¼ª–Áäfx ]Ã÷êØ(¢=óãüÝßnôŽ  YG¨§âî]–wÏH÷8lœ- KŒVÕ5tÊPbTG–SÇ¿R§#ά/„ÂØÎEJnRŃ!t¯g‚`Œ1ÆœŸË¼|°¡ýãÿß»-fÃIÏN}´ºüî»û~}µÁ<…{›jïôæòçT{Ñî~I;¥™_…PÓÝ„®a +ß„Œ;:í®ÑD)zÊ>ƒWÕjç¿úÙhtíi‘%Ýî),÷ «š»Ñ;62€vfÑ=ÂÐ ÂÀ;mûãx‘ñÙ R­Êõà!§Q]§ŒCTAá,2r¤mZƒ Üüò勚hôw“JM໑'ƒ`Œ1ÆœŸË¼|–Ýìÿ½ûכꓞœÔlrjã_0ÜÛ`ëRîâϺã'JD¶YÕyG¶¯ƒ€öWÚVµM`£¥=U)ºÐ5x+Ýs5Jö ÆjãÑRº—l·/t^Ð~&BºÝƒÈUÍÝn=62€Ú²ÈÀ¶¯&6»wÖÝO¾èìÄ#†8ˆÚ3€Ê=šüÐʘ̩Œqˆ*(Œïåþ)r¤+ ƒÝA[úÌK7Ì%•²Žv‚É cŒ1gÄç2/Ÿe7ûÛ»¸©>éÁIÍ&§6þýM»qÒ® ªm6ŸÙ>GiP}LµØ–´©‰VRJZÃ2ƒ»  (¯vÅq·_=R»qƒ-ö ÆjöŸð®ÝÃlq«F¨9\gèÔ´Æh›mt3™˜±éUÍY·Þ"2PUîŸÛØV•Õ2ÕÑ\)]€I´ ¥ô‚媯  µG:3× aò3D]§Pˆ&*_€Î+'CÊx¶½&(Údûtù0ÆTxªèA¬{Þ§( ÒUMªg1Ƙ—„Ïe^>ËnöÉÉ]¾ÜTŸôŒà¤f“Sÿ‚áÞ¦ÝYéð‚O!†­Ð^t7oqÏÉŠ¤…T`'VŠ–=-¶L nÆøÂ‚ªÚò.–~ØLÍ ÝÙâ)Af±úëYÒ§$ö ÆjAüÌe¨P˜åEz>P 6x ;Õh÷äÍñé`£ÛÚX|uo±-–ÇWœËÊ£b¹J÷ƒÐ<%p !• «3& $!«h4á{©p¡ª¨d‹¶µºtR!TA'•ÓvÀZh ¾—ûe~LÓ@lT+º¹ dð ]«&bŒ1Ƙ†Ïe^>ËnöÿÜýëÀMõIÏNj69µñ/îmº;«OŸ>içSùöPC¼{÷®ÚYV[,ܶ’(áF‘×EôÂÀà–®~‚c ÄÓ(mÞa0XU ƒ½kyրꃀ·|øð¡m‘ ¼jZÐ0Øèf´©#¼ªyЭF†1A[åþ)Ý# ¡#†–î¡$ žÒë®=/Ÿ/ë Y'VdNeÊ¡y¾÷é¾—û0e2c7ñE´AÇÇ䉇¡ÆcÌ Ãç2/Ÿe7û¿ïþuà¦ú¤g'5›œÚø 6*ذU{¶öEü)½@•Õ§Cb¥Â?`k”m#!õãšÊ?}úÔ5lÕà ZJKÝ_‹Ñr\—Ò [ cµ¤öëׯ:6±TDõ¢hØ ­Ó…ê·Ÿ&rÅYa!«š ”û†C"Ã&²àÃ6  ­Rôvqi~&s d èuf¨z zf^—SUHWÓ£eµ×ÀŒLÛ¹3n~øðaU3™±ÁcŒ9;>—yù,»Ùú”äù¿ÜTŸôŒà¤f“SoŒ1ÆcŒ1‹Ïe^>ËnöÝýëÀMõIÏNj69µñÆcŒ1Æó°ø\æå³ìfëS’çÿ:pS}Ò3‚“šMNm¼1ÆcŒ1Æ<,ÇœË|^þÙ$x=÷߫߸îÂ_á–æWù_æ«àoÈGùËŸ¦óæéŸÜêј>ÀžïмõWÁw³ìfÿçÝ¿ÜTŸôŒà¤f“SoŒ1ÆcŒ1Ë1ç2ú—?LüëG ÑŸèÿþòßf2>^þ}@´×,PY¾É£1¯óq½ò–Ýl}Jòü_nªOzFpR³É©7ÆcŒ1Ƙ‡åžç2üØH†þåÎ5f>2#áø/ …ÔÜ¥ú¼ÌQç2²ÎâšÿS:lºRÿ ËnöÜýëÀMõIÏNj69µñÆcŒ1Æó°Üó\fòHâÓ§O”ÿþûïKQÏ;ð]Ç: Qš.Ekr.óþý{*=UÓ¸ÕÑÌ­¡iÙÍþÝÝ¿ÜTŸôŒà¤f“SoŒ1ÆcŒ1Ë ÎeÀäF÷—˜À½ÎeÔ. +E·oßòé5M̰ìfëS’çÿ:pS}Ò3‚“šMNm¼1ÆcŒ1Æ<,ç8—yóæ «Œ•©ûKL@ç#Ïy.3ó1ž7á{ütÏá,»Ùÿ~÷¯7Õ'=#8©ÙäÔÆcŒ1ÆcÌÃrŽs™É_eÒ1G¹¿p—s}¦úË5vÓ_eZv³ÿíî_nªOzFpR³É©7ÆcŒ1Ƙ‡åç2`õC¿ÄÔ~¦FuŸó\fPÃàÌEðyûöm)ºËn¶>%yþ¯7Õ'=#8©ÙäÔÆcŒ1ÆcÌÃršs™wïÞ±Vö«L:ãhÏAîr.3Ó¨>SãKÑ Xv³ÿõî_nªOzFpR³É©7ÆcŒ1Ƙ‡å4ç2Ÿ?Î~M‰ žÞå\†ö€™s™Ý­Ì°ìf?ÞýëÀMõIÏNj69µñÆcŒ1Æó°Üó\|ŸPDŸ¢ã•ö1ƒ_bªX´7T'u.ƒïƒ¿é›ý©cYv³õ)Éó¸©>éÁIÍ&§6ÞcŒ1Æc–;ŸËtù>9—yÿþ=ÚÃýS÷?Rë\&£ýó.žË”û×·2ò›ý/wÿ:pS}Ò3‚“šMNm¼1ÆcŒ1Æ<,wþ=&\·|úô©ˆ6dB‚è\æýû÷¥§¹ Y奜ËüíÝ¿ÜTŸôŒà¤f“SoŒ1ÆcŒ1Ëiþ¾ Ñ?9Š¿y¤ßÊþz®ÎeºG0]Ž:—ƒFõÇŒo.óŸïþuà¦ú¤g'5›œÚxcŒ1ÆcŒyXNv.£_eŠuÇ¿Ä LG;—Ñßý}óæM)ºËn¶>%yþ¯7Õ'=#8©ÙäÔÆcŒ1ÆcÌÃr²s ßÒ¯2©„·-w9—Q£ÙiйLûndÙÍþ§»¸©>éÁIÍ&§6ÞcŒ1Æc–óËèÓ1üU¦OŸ>ñvð‘“»œËÈÎÁ™ËÌÙÍõ,»Ùÿx÷¯7Õ'=#8©ÙäÔÆcŒ1ÆcÌÃr¾sý5Vóæ o-XÇÏy.3ó·cV?ésËn¶>%yþ¯7Õ'=#8©ÙäÔÆcŒ1ÆcÌÃr¾s ãŒÏŸ?ÏmÜå\&ÚVý÷(2ø·ßDzìfÿÃÝ¿ÜTŸôŒà¤f“SoŒ1ÆcŒ1Ë)Ïeô+BºÿÝÜ»œËý÷(ØYŠ.@?OmÀM‰ ,»Ù÷¯7Õ'=#8©ÙäÔÆcŒ1ÆcÌÃrð¹Ì÷ßÿC‚N¢ðÛœîgLˆ~•iüÖ)ÿæÍ›¢½!þãm°É£ Ù ^½z…[¨h‹–ƒöÈæp–Ýl}Jòü_nªOzFpR³É©7ÆcŒ1Ƙ‡åàs™o/þvFH¾‹Î5Àki@ÍÂ"½°É£úe¥.·þ &²ìfs÷¯7Õ'=#8©ÙäÔÆcŒ1ÆcÌÃr̹ øá‡¾?²* Þ¿_¤{¼}û¶È=ÕÜ% g´‡;›<ðñãÇW¯^A¾Æ,àvæXç–Ýl}Jòü_nªOzFpR³É©7ÆcŒ1Ƙ‡å°s3æóçÏ_…iað¯£nÁ²›ýwwÿ:pS}Ò3‚“šMNm¼1ÆcŒ1Æ<,>—yù,»Ùú”äù¿ÜTŸôŒà¤f“SoŒ1ÆcŒ1‹Ïe^>ËnößÞýëÀMõIÏNj69µñÆcŒ1Æó°ø\æå³ìfÿÍÝ¿ÜTŸôŒà¤f“SoŒ1ÆcŒ1‹Ïe^>Ën¶>%yþ¯7Õ'=#8©ÙäÔÆcŒ1ÆcÌÃâs™—ϲ›ý×wÿ:pS}Ò3‚“šMNm¼1ÆcŒ1Æ<,>—yù,»Ùu÷¯7Õ'=#8©ÙäÔÆcŒ1ÆcÌÃâs™—ϲ›­OIžÿëÀMõIÏNj69µñÆcŒ1Æó°ø\æå³ìf?ÜýëÀMõIÏNj69µñÆcŒ1Æó°ø\æå³ìfÿŸ»¸©>éÁIÍ&§6ÞcŒ1ÆcŸË¼|–Ýl}Jòü_nªOzFpR³É©7ÆcŒ1Ƙ‡Åç2/ŸŸÿüçØÐÞ˜Q ºh«vìÏÿõÕ†œÔlòóöÏP÷¾À†b1ÆcŒ1Ƽ|.cζèÕqÃó}µa#>Ú0ÆcŒ1ÆSáss>|ÀaŒ1ÆcŒ1æeàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1ƘûàscŒ1ÆcŒ1Ƙûàs³Âû÷ïß^x÷îÝçÏŸËcŒ1ÆcŒ1Æ\‡ÏeLÊÛ·o¿ÿþûïž‚’ׯ_‰ÓòÓO?ù€ÉcŒ1ÆcÌÝñ¹ŒéóÃ?”“˜å,†”ûï¾ÃÓ"w6>~üH×àÎO?ýTJ1ÆcŒ1Ƙ{àsÓáÍ›7<ùþûï?|øPJ—ßiÒéÌé>5óåËØLãÉ)Îe>~ü³¿žŠÞ¾}[Ÿ¸ðêÕ«búä˜?²dŒ1ÆcŒ1>—15Ø-cÛü]ò‰ì±y¨§'ÚWøðNEü\æÓ§O¯^½*¶6t{çÑ€ ñƒW§pÁcŒ1ÆcnŠÏeL>,ƒ‹RôœåS2øûå“&:)xðCÙ ³qîàgXp]D•èìGðA}JM-¢.ó†øÿdãHjºmÈ%L…Ÿ6d|ñO²‚ ‚ ‚ >&Q— ^àºÌøßo׃„|³àšŒ¿Çº 6;øwQ× Cdm.0 ñÃ2AAAQ— ^Àk¿Þœgê2|¦ó»â®ë26þŽþ²Ìããã/'°ßu%§YAAÁ»'ê2Á \—Ô\ü÷M¢.óÊÜÝo0õx||tu&J3AAA|d¢.”¸æÒûG9þg:ã¿As³Üi]ÆE™ÁÔÜ_¿~•;¿ÐAAÁ‡%ê2A‰Ë½·åOŸ>nœ{¬Ë<<<ÈæŸ~úéýª‰'"~d&‚ ‚ ‚KÔe‚’ÇÇÇÁÛò¯§¿;Ëgjº7î®.ãPzOEøeîLAAA¼c¢.4PåŠ?.ë¢ ðRZïûªË¼×¢ ¼›?—AAA°LÔe‚®ÀOÛ¿4.ÊpœD·_æÈ'âéé)µ¾œN©)‚ ‚ ‚àƒu™ Í—/_üÚ\pGÿ¡Y|úôi++%òê’¹ÁÒ@^”á8µÞØLä¿~ýšÎ_â–oß¾¥Ö ‚ ‚ ‚FÔe‚©n±ñððp¯Ð½S2IúfÈëG¿ôaŽR‡Ûl?FþzBõ]‚øa™ ‚ ‚ >2Q— Þ?ÅÏË4A&Iß¿þúkª[ìqƒ%ñíÛ·ÝŠØÝýìUAAÁe‰ºLÜ"ß¿ÿiŽŸoøoýàÅÃÃìL•˜ N¿âAAAðqˆºLWçû÷ïú%&‘Zƒ ‚ ‚ >Õe¼¹ŸÇ ƒû²UUË[¡÷Ö­[þa-«+kÎÝí6b{ÀL ž“ÏAÀ°$5×'ê2Á <"O‚  ‚÷Á¨.óýûwô5ÚR°¤óŒ[ûyý|úô)5Ý$úÖ7!íýµˆÉÝí6b{t žžž,\öZ@çn ž“ÏAàóçϺtÇïõâvã°ºÉñÞMÌHpƒ¼U&ódˆ<¹ô£pÙýá•Ô`,Ò)6A÷Îá¿/ãw†å·Ž×Ä?êûñ—½þ-ÿDÏ›pw»Ø]¿î^öar%µ0“ƒ'ääÃÓö×owWÍÃëÅíÆ!žr¼¸ÌHpƒ¼U&ï&Rð:øI{ÙGå•ÔˆGÁûà=×eô] là35wÅÝí6b{t ®ôút½·²™4]ï­l& OÈɇ§íG>5mhô‹;e<îõ†¸M˜P9^Üôf$¸MÞ*“w)xü¤½ì’}%µbãAð>x¥ºÌ÷ïß?þÌâ!èûåËIö@±Ôa ‡~ÓÇ6Ð75e|ÚþÕÔÓÓ“N±3n<Öããc.Ìñ`cW8ÒÆ Úá"¿Ê$óü»Í —ÆÞþAŒs ß9¸#Š.„ëÇ´CŸ š™>¦ó bËX²A ¼ûÇŠl”4ÓíÛ·o¹§Ð®Ž ž‡¡ÑJ‰ÚæzŽÜÅæ© \íÍŽ»çD˜Ý&8Ú4JàPk…¢¸ï4:íÛ}ü|#?Û·Q{1?Y‡ÔB|$O0P‹L:oQ²­°Y°ñêÅèØÛµ“R[S$$š.´hæáÀà£L ÄAoš(ßoq,1>SS†¯B38ìÕt5wM]˜VÌ(l % -Qd¦±ñŽ@Ü€ùÉ:¤ð½pÜô&Zòã4°èOM'—rt¯An0©BûÑm=\v:€Ó^Ü H]á!8`Êt,l†Xxp1b’xIó¹ã87É Ëg¤×«ùÜ€ ®zŠ ÔSPD¦7éP< Ÿ’÷ÐEÑnìxsâŽI¬ ¯^Œ%w(ÌXH6h>‘Ǽ±¿5 }}\Ó›/†èõmháfÁWIƒÔ”Á²¢«…1 ¹­p¶¶7h—Oßrè ˆicYÕŸ yù@»äu‰v!¹mu@컕çîçò´«m©é ¤Am-c-ù2ì]Ø>Ý«vÐã«EÄ<"Iú<¤–ÓyFmFn‰Úë`’Nº „¢îå.¨EúºçÙ[ïW¤§iðQl£ëµ2ØÅXKm[î;:Sk†Œç3o¨‘}•!€ƒs¶k6U¾Çý=É$tú®©†y&;VÌLÖ¤Z Ú–Aófæ³f$ÕÎAÍææ%ƒi`ˆÔtbp)Ƕ!ŸšV¹ìtÝ-ÆULN$µ'éôÒ%缆à’Ð҃˗,Œ‚dmFª‘R¢S‘ßJ8h9î”Ô7ÎeW=uq¨ùÜ,}¶¿¸ 6ÅÏÖ2ב˜»&¸ªK`׬Ç#Ò˜:lp*¢Ý`€0 58j$“¥K|ZÞŽ%Æ©²éøë—$#’ |8~ÓËÐíC_õ²ZŒ”NÇêùB¿ÇbtuôäíIz%j'z©é„c E/aóˆOjZÍm]²|2"p°»î ¶i}ˆÆÒ|Ñß%Ã%)”¤õ‹|Bmd|>ûj^í5ny>}€œÍµqÐô«Î^ð\󙚂 ‚ësõºŒ`yH6¼ªÕ}_â 5`9Ô¥ñГhÕ¬‹,“éÂi#®K…êÕ4 ß‹‹¢4 œ+$iÌ•X˜¸¥¦3°6Á’Ÿ.¼zÖP¸ïvâPl2ò â¥Öò^´$\*bË©ýª;zÒ{.;þlþèÞ G/²éq”ñD 5}ALµm6ê ò>¬0^¾äha? ª¤¶ÖSoFu¤¦—¬MÖ®Ú|oZߘNøz\‡+·ðüÖ£.åØþÚ¶£\v:@ ¡x€Ö*>õU;.üjn˜•÷îb(4f¤xn𸽀{t`ļALhé]ZXõä¬]n޳ضim¨EÌò‡<¨Š» m¾Ebì&L/° FúXçm=k»†m›O6OfØ<ÑK¤ø[Xòx*–¡_çC{Êò«ƒ|ót@=H!Ÿé|c-·­JW›9ÜÄ:ë>5‚ áÚÃ¥fz8ìußµkaé¡@‰b7Û›h¯_uì]Æ ‚àz¼F]¦ÞЀ×Ý|uçØ+qjz‰3–®Ô´Js­2Þ‚ –š2§fÖ*;ØûöNî¸7^ ‘šÎ ߯5·`›îƒíOçj„fü=;E¯e4\‘ N>óoÙ!·Ó[žË»ßˆˆIO¥Mƒ×Èï æÎÉÑfƒ•š&luèœb,÷â`wO<Ï¡@9Ÿ{É<`]µŽpó 6xXÍxçù­G\ʱýç?4.;~¶ôúŃqSÓFžóyVç,<¸¬öÌw Ü‘ž^ÀF¯ez^I8'W=iz÷¬|A ùuóˆùÑœüõ¸Ebì&L/° FºK:²kØB²ßx›jFè%Ríd f0z/߆M§Ày(П.løI›§Çrn«pphÝq¬f~Ø„`J¸gÞ˜^ vÕ^ï–o&ª3!7ճߴFÉ7o½ ‚àJ\½.ÓÛÐè¹ù>£÷rh¼Àô6Róh%˪/u¶Ð«é —¯y5ÞLäÑXÆÚzï6à½c¯áMòÆ«ç¾ "»ñ™DÚŠÚ»^j¯·ì0¹×Ð4 zí ìÞA½é |æ;* ·˜ò¡èÒç-ÇFÎ$¼g|í®×Xõ¤ìªµ‘é¼¢'Ð1Çó[>¸”cûgb8ÆŽ\d:|£on9ò¼²ã\í½Œ-<¸æŸÛcìW/JŽLoýjšqñUO£@ïžõÓ ·@8by;ò½iõ³¥°s>aòÀ®éÙï3g×°…dÏrñ,5»‰T`;{N9…òPx”£·¡*:J˜«:(æÅ6ä½Üس¼—ÛMÃf°BìLM}ˆ¿„ó¸Í£cj:?±«v9,=®ÚãxÎ$jóÎ ‚ ^×ø»¿©é%ÞÃåë„·AycŽÕööjóì.·Ç8D½€Û©ž€4`I:ß°ÚÍö6@2õ"ù°í”ò&H}&¦Õj‹éëµ›f`׌/¾À¥ÁËù®aù=$` ÎáAü›þ°yYÂg:Ÿ˜/°æü6„º¯Êdjq¯¼Ä©.…×ö”«=$PtTû †\Wô°öõJ±3“eP‹ãHÉg’8±«–v з‡z $?nîH{5Di+ƒ ‚WàFë2»ÛˆvW2[X¸ÀbæowTßX°#¹wšÑXfF›ÜŸÁ/0½€ä\vEoΑ-xÇ%ÉØ·Œó6‡Ý<íájjUMƒ×°Áƒh÷ÒLfØwP‹Ti‡ Þ­ºIn«Å\Уîbé×…!˜I¼…É«uüwaÐâÅo&hƒù™z°ýÅì/s‘é°ñtOM-¬$Ҍ㹅cŠÊËÌs{Lïv3»3" Ed¬v—ÉUO!¤ŸíÜ%W"µ…ñ9V[L_¯Ý4»f¤ ¯¬3õuuf×°\É'›sxÿ¦¿lç@¾˜›á–&Ö\Xë;Å+‚Z$æ÷y?\Ùïm„v)r[î b8æé驚Ӻ:33Y€›ƒL¨#¼«¶°mÀÅoù"Õm‰'Ú“ËŒ«%‚ x5n´.Ã.‡ö©Ã,¯d‚5¾xÉWÐÜ‘Ô4¤ef´Ér>·pvñj 〫Mçç!mÅ©0/5UpI2¶¤nƒãˆvfì8Ÿ#²¡KuòôÚ`”mðQ´f§¦ 蝹µ*‰yã匕Ù|ê4ç‚5áe©ØõÖcí&ÞÚdÕÒQWé(==ê÷½™ ÑQúëÑ—rl?ò©élΟ’ÔÔÂJòÇæŒã²O„䮜ñs{ ¡Pô§¦—ìΈ4‘±ÚK­zòn~¶“¹Nª;¤Ž|:¯°Úbúzí¦Ø5#sxX3`y‘»†Ùå4R‡\-§Ò9ˆÓß¶s _ÌŽÍpKk.îB§v‚¯éw Šáè®ÓâahOæ¶ôb8ƒ²J•(öcŒ«ö™ÉBn ºä .©KO­u¾þ-ïžh'3®–"VAÁ+p£u™ùi™Ý•,_;SS /càoÈôVÁÍh,3£Mî×[Š3N-¨М£™$á’dò¾‡lsi£ùÚÖ4 zí Ø…™h»a2V}µ«ÖÄ去#ÇôÕé!O/D…Ë»‰·6YcµÍšd&hƒù™z°ýȧ¦ËqÎt¨#Ÿé¼ESÉ¡œOç«4ŸÛc˜PÉ÷n§zÒP¿«ö( Ñ ýšÁße7ò=µ»Ã5#°Ûk&×ú‹Øb×åçð þGgÜvöä=hnêŒñ½xQÖoxÒrŠŒ–žÞXG=5ùèg‚…^ íWo Çú/‘Ë»Úë]µêGÃÒc7\±ØÍz¢íEqA¼&·U—Ñb¼¤¦«±»’Izßz5õæÆß…(6‚=šÑXfFÛ¼w† ®ºìíR‹zs޼Çr´küҥ„8äòØ‘¦aÐk_ÀwPîB^H idn?öpœ§¢ãƒçjóíô‚íÒK°úþ*È­é¹0V[oXçé˜3xB.åØþ‹<4jΜ†NÉäY7㸕Ï?¸zì:R`›{~YaO@ŠŒºøª·›~®ÛN.ObÞý"žžÖÞ£¬©yÍÈ&½¸›kÉÖ+g7’¶³ùˆ†æ~ÃÆF±%µf]B OB­¹G~80´W¢z~—s[ÆcC:?oòh83{gÊ!Jç'vÕ¾þ-/¨3Ù‘aN=•X˜.A¯ÈmÕe.¸ÛÅ Uñ áëP/º5µ³^ÞèÞû‡¯úF“hFc™mÞô&¨&SÍ7Ö9´4\‘iN’£»ï?z¯¹SÍ¡…wùõÕA¯£8©ÐÙœG×Vš7 6¨/Uù0ßU[2]{É=š¡9œCÑ›¸‘ƒÉÚU«È@ïu¨ÇLÐìΈ2ªðúâ«ÞnúåOòÔ4ÁxZqY:¡ˆ§ãÜ4)ÿJyÜÖŒìÑŒ¼ ÛÍäCÉæ84·žnèåIóª7§òò‡üx¾ w ŠÁÒ_ä§úÒhÉ|µ˹-å=°‘EÌÇÉñf|`pu¬öJ·<4SÎË}ÓTCžxSqtÉ ‚ .ÂmÕe`¼ÀˆfQà(ê±´âB¾cc­j.Wö%wÖê]ïŠ4æìEcml¡$CbE¨ÙF¨Wí-ºÍåÍQiž»æ~Ú–›ï?š.óz·k>벚g¶gXݾ–h¨ æTcA3'٠몧¬Ø4ÛTô6ˆôÈÒñö±Ρè™!#ù<4Y»jÞ@™ yôü¡!—r.õиøt¸#p[¥Ö :êjáàŒã .ìt’áŽãl,ß{·@Ï09Žåéü„.²êͤßàInŠ=­uä9µ PÇÓW‹‰Àß¼c¡vÁȼ0‘£QøLç 'ý½X­­’NƒZ­× 1Йc…€Îâ)çÇTáç ݆¾#¦è±Uw.ù ]x‰ú¡ÜV/4§ói¥y§8—Š˜k žñQ@o3š}ÇjApÁ[^Ô íEïÁek}.A¯ËÍÕeòïž±òåW9¦ã^dÙÐ d‹} Cðée ™|$›YàóÍ%›/fù:š;BK”ËÉçìEcImþÞöÐ%oÇA®Ò^Ìr¾ÕÓìÞô:¦çQJx' š8"¹%ô-*Ï,Öös*I·ÐÅÓÊœZÔ†õ ^K4Štæ“KjìL^‚Í–ŽÓ…Å”õv‡RrŒ\Cg>(±µÁµ1¾D¢Ò)cÞÓµÕÉ‚±Z°YkåpŠ0è«F34êîƒK9\•ò©i 'SÓyÓœJ”·4r?¢*©„ͤãG\ IÂÕÔÔn û6ìsÁZ>.]ž˜ùN÷t~"_,]ÞcÔÒ±îÕC~ÕáÍÉŸEdˆ'Á¡Âßh\RdžTY!-©Ã ç2(WǼQ4¦ Fr à9EÒfY ë]ÐÃ…ÌÑdVË%Äž½ÍüU©ÃÆ•¼Ôòéúpœ:œðˆ€©Æ·¡±"÷°!]بc+Ör[Clë!m dkÉOb­]’m€°3-¼óŒ‚Úx«…kÜòú”BeŸ¶„«õ÷-ò’˜š.A¯ËÍÕeÀ‹¨`9é¼³E ñ¢Î PØ–oDž ÚHç­·—žf‘Ë¢±À¼¶|{É¥Ì)’è‰b 7ôÂ#õå3IŸ‡´53­0I Ž›¾³Eó6¥&ˆ½—nºŸÑ)bR’Ë ÉÔí `ÿ6Úó&©˜&3HF •ZOÉœZ+.è‘!¶žÃº‘Î[¦B3ë<Åk“cµ€fuIõFjjý]mŽh<¿õrp)çR‹O‡Èã¹NhgÒq8ôà:úÜP8¨J×&fDÝó.æ‚«žzÓü¸σm¤ó r#Ioä7Z)aêéË+,ôÄí¨‘¾$1Ð)42“É «$f§kŒè<ïåIãC&×(š÷)ò¹Ù0N’<'é˜ZOäÏ È‹ ¹­«»9\“OÖ6È3>m&˜®æä œ°Ð¦äá ‰f쪅‹ßòèoæ3 ðÔú™)QLeq×A¯ÆáºŒvfPïErXÿ$V,E†v 4·&¬ñèçjZ(6$ÏÂão…ƒ”kágÅ*V_Fo.N6;‰nÂôí­yÒ\È£¼ØÄŒ£q”CÚØ@§4öæŽÝa.Ï1iRÔΧ$Ï=ÐË´:¶Àén† P÷ª%Š$´˜ÚkÃhl¶/ÀÜiP¨9U pŒ’ì¡.¢ÎO½)‰Á»kô殞SÌÝÓ……Écµ¢¾ anŸ$”!á¦*SÌoÎàRW%vþCãâÓ!·\ 8í©Åɇ\µ%’¬ï‹1Ešq߆¥7#ê éü%—ZõÔ¥—ð9è,æQ¨{óM›.…‘«4‰ûjiN_}‡:þZP ¹æ2²8ͧ© PÞÌä…UøšD7ì¯ó|òÎu`%_ÌqÏÁÕm´Òøq/Àu„‡ÖÏP(&"5u8šÛºD—t~„:[¤ª™] ø$ÑM¸¬NË?œ·Iî%»jáhXz¨‹nC=Ì“®=ß»pš‚ ‚Wçp]æ•a#bæW©X®ŠE( 31ItΪ\>5ݹ…Z‡$Ñ—PTùLç¯B²c#5M:üúëxËòVsÇpÛ6éÅKŽÌ€t~ÿ$öfÁŒ…—'K]Æ6pUb"µ¶¨Ÿ-5h¨çW .åpUbccñìØÆE¦Cä“2©vžC®\˜ãÔzë9GÉ)W¢ ¶13Gy$SS–ƒ¼uÇ…LPG±Û=Ém¤¦!’œÏdH­CP(áM}§7ã?&ïrŽ1g’,ØÀ¤ÔzyHMC’h_8]ž¸H}öz%¡‹„%éšÖæÞQq'‚ xn½.s=fÞ‚£¼I]æ]ÂŽjÛ&í¼œ7ÈýÖe‚`'d<².KÜéÁµñÎíªÅ² ‚`LÔe¢.sI¼º§ó`•¨ËÜ/3Ï–¨Ëï 'd<².KÜéÁUñ_ÃYûű ‚àRD]&ê2—$ê2—"ê2÷‹ïæN¤ ÛP‹n<¿*<õì’%œÿl9ÇjäªÄâm-¸ÈI%$©)¸lÜéÁ5ðRÒüsiAÁ«u™­Ë`ÞQnÁÌ ª|êÔïïfsÀv'¹tý ñí×e>øäÀMÍñ 7ij:QÏï·—ÿP˜® •Áu™+u™àz°ßК’¯2AÁ›u™Û­Ël;±ܲZ,ðÞPâÝlëë—ð´ù¾ýºÌŸÜOOOŸ>}böÇéÂ默æ9Çíâš\ŒãÔº‘ÿ(M¼!~ |„{ü5q`£.\ÿäæç½ÿðA\›[—Ñ/¼á?&ãßV˜çÞЈ'–Ûüô(ïæ/Ïñ~ž\:Bê¼½Ã3§?~üHç7ÆŸÜ  nü‘u§è_2„Ÿ4 ^VdÖåÈ® ‚[àãÖe‚ ‚ ‚ ‚ Þ–¨ËAAAA¼ Q— ‚ ‚ ‚ ‚ x¢.AAAAð6D]&‚ ‚ ‚ ‚àmˆºLAAAÁÛu™ ‚ ‚ ‚ ‚·!ê2AAAAoCÔe‚ ‚ ‚ ‚ Þ†¨ËAAAA¼ Q— ‚ ‚ ‚ ‚ xî¸.óÓÆ§OŸÒy0äéééçŸVЀãïß¿§k÷À·oßdùããcj:¡öÈ„+A`át~ó R%x+˜ M ³“šnü>,÷ÿàùå—_”Hâ}/»r3îš ‚à¸ïºÌo~ó›Ÿþ9}¾|ùB¬ ~ýõ×tùÀZ™Í¾05ˆL¸*–ðät~ó R%x+˜ MÊ=vÎy°|ýú—Í¥ÞëˆÞ!\|džµøójJxýþñãGj ΃å˜I’šî„ÏŸ?+‹Ì­ 0Gróè]A D]æC Xû*vì Ùgß×·€0[.ð‚‘šND&\íMïhÿ=H•à­X® ¼!k–§§'?osÎäÒ=éšÆÆ¯Åÿû÷ïö%~úìR8¤÷õÃ&N?ì'H$Râ}ÿ¼ŒÖ>¸£§VAp¿D]æýã×Ô»ÞBÙ‹¨Ë¼2Ú›ät~ó R%8“§§'¢ºðоVx[,rè.ÒùÖrŽûNìylüZüóºÌ—/_RkpéçÏŸSÓ=àú8ÏU­}0×,?!ƒ ‚ ê2ïŸ÷±ò;IíEdÂUÑÞ” §ó›g*Á™è^[H?…ÕÞ–£^Éä#ä/f_¿~õ Þ™)¢WàßQEsjÊ8ÿ÷˜pÍé<8òäÓ§OŸ?¾¯YuM¡ûeÁåå'dAD]æýãù]Ó‘¼ˆºÌ+£½ém4©œÉò[ÇG¨Ëø-®~ÒþøñCÚšWÏÁÙ>¶óãÜ^îë?œƒïèù»fù AQ—yÿ¼¹_?¢.óÊx;žÎožAªg²üÖñîë2_¿~•ƒ=yGà²O*gûXíûX‚7äî‚ó‘ˇîšå'dA®Ë°>±Ã_¾|™ùÎIþŸ)g~vµ(w©7Íîræ7$ŽA­j×Ç<&0vaH'™Í½^yôŽþûå?yÀXj$ñ’<ì0ã?Г›­ ñ9ÿŸ;ê{Ñf,yXj:qèõ °mù@œÊOŸÉ»@¯bлªB:¯©½îó¹QŒâ˜Ï8;³G¹BoeÃxı¿\Jc¬¦Š@¿”À@Ï.3ñ—GÎ+tµyË`˜gjæÉ¹œù@¤Ö—¨‹ß:t*fîw4kROM8èoÏßÝxî dh×0žýCÿ«,OM/Ár Œo¥£àŽÔŽíÄY‰9,Ø£ @3ÔBÁ8s ó1(÷¼Ã u'drKlaÓ $uUä 7•#ïÆYW0–\éd|rf›±¿z!ЩH/É'”ƒfØ…ë{õÊŸBWrª ïâ±är~× xÇÁ'd(˜45‚ x¯¨Ë<==y•2,?½¿]ÇóéÓ'­Rã?@‹Âº]ŠÕ]2ÚŒ²Š]8Í—öI‚’ЍêùÈRZ› XE¸’P+´8à4'z$cšÊi¡=I ñXMØ $¹ 9Þnà»8f¬¼ïx~³ƒûÍ›ËÀîÔîK‰2a…]ò¨ÍgA`o#‡&]’|¦ó—8Ùš¹Ê¤èjíÚ¡Üpè8à4÷·gXŽä{’“6Ü2x0â@æÐÃg*„´©çèŸÏ˜¿‡kN öëjq?—ê!H˜â1(æí"ð½èËi‘¶³Is °D´ ùà…Ú_›:x‡qÆú}O]Â4]Òùkn:(lü@æ(žÍ±yüy¸ÕѦ%‰¾ÄÁLçͬC¾™¢Mš€Ææ#Q^ÈÉûÚ~DAö¼€: r£y‹]Ô×Xl!ëj÷™!‰iŽE íIbÃÖ6) ›¿‘…‚Æ'ÇÌxn‰×p*‡9•9z&¸½ž©‚£OÈæ³ƦAï›ÙºL¾ê°r°¢€×?Ž“Ü Ö`]‚Zê.‚ö$±u>Íw†¦ÙŒX:?á‰à2BÚêGt“üÞJr{ê…¼@¯sI ¯dñãÎÝ9€mðY—×½£Yפw/œÒ™øNÕ^¹›¶¶I¥C7²@€K|ÒWbÆ._Ã)ÃQWI¡Su×qmyAþx©)†ÎCš†ÜHMý@AðËxébå`¯“Z·Ÿ/õjT,<,c4²ª[+º{ù©w]Þ¨Ñ1ˆeL½òÕ1_ÆÀ«8/-^M‘Qã Vˆ/~óá€S.ªò-Tîˆäu ŠÂ²P}iäÓöƒ•#–¿ƒ±²kuôjÐ Ö¦±D’xù²š;Èûã¦ÖÞ-I¦ ÍìûwmS_¦;Ÿeð›9:sKͺ”JØ€t¾‡b¨^{¿´Ð®F³0éö¨Öf…©5Ãsï}rÃÙqeŸu0kÜ+Ÿ8úX`85ö6M—>Pxgù">œ2t:Ùc!þ·pÜòÅ]pè1xN>HŸ@ƒG§=WH/pŠ$1D·<ò !ÀÍ’Z7ÜGRS&Ïgjz‰’k[È"Ð@ùèÆV ÏÈÌ}7 ñ”α¦rüŒ‚b @6~y¸J SëéIX+iB_” Ÿßï੃)/hä`Dçp>‘ä|æa—Zò$çX½ χµ¬ëá¹Èï…‹„t&>pô¡Ð%4ëò‰³ýPXkÑšNX§úâ©4c¡•_É)!ÀsϽs»`8]°¾ÿ„ô³p-µn8P€;©5‚ ø0LÕe¼v ŒðÕ|-„z ´oëNù–ÂZ«vTåûAK¾p‚Ö?É{‹)öÕ¦Í5^ «JòvoAølê÷Βद „Õ½¾V^ôl2W›Øµ±©ù6ÔÐEÃA1¡ùbÞÅ”ÛSìíºb+G‚¤TA½ßu~¢65m¬MzÞ+5ȵκãZn8t€@Óø Wn†p{S¡¯bsjjydz®-Œb‹TŒ>ÉZüóÇ‘kvžýbÿ}è1¸fOž\ÊC'hÔÕúÝ@ ùLçÓØßb{÷»ðÕüácóšÏ[˜û¥.4ÎgHWÓy‡”.©©s'±ú!¶Œ‡Û™?mêG½¯ÖJœt¾ÁdI¾·ÊÏÀ½PçžPäNM¹=óôFOsÆ¡g¹ï©ÂeÏ]³£»ô<ÊiÞ  éL|ì`S ÷Ѐf&˜…¤SÔi)®çÔ íQ˜ÛÖË¢ Ô‹Xm3PÄGWÑ0“KAÁ{b¿.ã÷„ÝU³¹Ì4i®‘ãu½FJ ¹;÷7O0/5 ±¶b#ØÄ¦¾§ÑT˜o{Û/[Þðº>c*x‚ê½…w3|Ö/Âö+«¥ï¤%38ߊ‰sèê • õÖª‡Ø›>Ï]>˓ޛ/µ»K¡ÖqÈÛ=‡rc&ëØÎt¾±öX¼Û ¦K¹üÚ(½TQ¨ G±@^í}ðqè1xf>`Csë_X›#³ëö]˱fX 탫ž”"D‹ƒÔTq=§ÜÈ#"5eø) EÇÁY4ð×V]éæ ‚ n–ýºŒ¼æÒ^q‘LM{hé*V&¯g“ß%h*1Þ»³¨§¦>ÞWõVÓ ½]°ÿL¾¸:V½7Ъ<°ÄÛ”ÞŒX¾Þ[ ö𦫽ìîÁ!*&®×ãL¨Ù°s>kyÒ¨Âr)¤Q…=~?Ïgm-7f²n@sеÇ ßcPN{‡gæCŸ›‘ÎOôÚw±%Œžš:ÅLj§éüe595LQÿÿôIDATpÂä¯gkYõÐ=¬a,ì "”£CçñÏé…´™c”öžÂsèYëöÁ¢cÛ.~›;DŽégu¯(PÐôî"!‰OÏ;c%Åý2è¸v#ƒuVÕë9%“½¤ægd¬Ó©2ð…K’ìÊ‚ ‚wÉ~]Æ++.k[w½ÅŠ[ÀÂf´tò»kdAS‰a”g›ævÀ»`fLe\éÌ ˜±ÊÊ‘iâ—:ŽSŸ!ˆIžÑSÓ _«jú;P{¶¹(~u/LâR³dÞäÜ’Èîäxc”ël¡ O¶rmÞÈrU{54çÛýæpnD“fn B7C3\j„£»;ë7íBxm”ž¿Ž9 ?ù•cã5zÍàÞ´¦ùÞè!Òù5{fòÁ¦"œš6™—ÃXµB7b'ÇMš#Ú¯b›ÂkYÒV46qH‹¡ <ƒ¦¦³ñÐc;QbÅ„E©¶¿×î)à™iK=5@.·I¹†Ú°_Ýý ¿@…IƒÐÉ<:¦ó=4½Òy…DzN· zcRã{Á›lÙì­¼Ný’é:EqOI Ð? ÈAèf@!} ÇÕÛ€# šï6ÓRÇVí“2ö—ÈvG8ž|ùY‹¿qzªêï‡×‰7fÍž™| —dNM‘Ït>}Ϻ…2µGmjm‰K~EÊÑ]íR5 y»ÑžÎ‡ÔöÔ j3dñ™Ùd2gšñÏ‘mµý½vÁc§„b»`IÞ—!8 &ÖîzH39XîQ8€4öit>“h†/ù†êeÝ€±ç„t&>rälú!F#½šañ¸\U÷ŤÐÒÓi®ä”ó„vµÔpI2ƒ¡ dIÏ#Û9PhÃÆa¹kþê¯þêßÿûÿþÁ?øí­òû¿ÿûéèö¸eÛnœÝ›ð§ú§ÿý¿ÿ÷tó{¨Ë̯L¯Óõ;§|9d±TãüRT+ÉñÚVìš`¡„+´™4ÕÈ ˜±êhv±%õ zO9ŽRÓ¤Ú]Ø©//¶³½ B'ófæN ‰ü Âu>œ3é€j×ÛÚ|k&õ,œ±¡f&ë4Q#,̾½ÐÙ?æP¿~¬2鯾Q/I˜y­Z‹¿ÀMwßlø{ô1xHØÌÄÇF‘_|kä ݸ™~vù&êÙ¶œ«RH÷t>DÂP—ÛÌŒÌQ<›c;›ñÏQ”zÑ«Ûs¸w<P'vGƒ¾E@zÖîzÈ ©ü@Äô 2—]aç@-òbŸ‚/ÖB:£yÁ`1‹ÇļÉLv]É)ç 6¤¦ ™ƒ¡ Æ–èêXáŒa÷ÎÓÓSzc ‚àð¯þÕ¿J7°ÇºÌÌ{‹ñâÔ\~tµXuÜ%ïÑTb¼¶ÍlŽ.„6µØÏåxS•ÿÈúŒUGã°Ë`[ãKX›š*zïŠ3»¥&~oúØ Ñ t2o~£”DØ›ï|,áè¤ wçXuŸ\Uñ2®÷â¹’yf²n@3\j„Cáð*Jõ™µQùë)›yóY‹¿@¿bKj¿Æy²Ëš=3ñéi^kóÅãÂ~ˇ”P_MœOëGÙr®ÊYº§ó!¥NcÑ{ž‰gslg3þ9²¿¶­×^Cxå ìžüÄk.==kw½áÔTá›±¾aàr1‰ÎºC <ã…8R˜ÑœÛˆAX<îÑy&»®äÔx"dìΔ[b…½§h{3KÒò—ù—éu-‚À?ûgÿ,ÝüÁûu™µw¼8é*KT:ߘY±ršJÌÌæ,Ç޺͌©M…3VYùÑ·ˆƒm·•Ø™š*zè™ÝR¡¹#ï…h:…º— 5»–ÂB`yÒ…ßÿqDo¹ÁÞ#r—y[V´–ƒÐÍ A‹ ñì/¼QÛYEÀAÓÕœµQŽú+òéè±(n¢§§'2tñÿé=ÄÌcpÍǧ·ïwÖ1LÖO%£§¦Ì’™à×䯸þª__—sUú'mC¹Fi>Ö`\‰Xf2†Íøç(—ê™íµ7qz£ÛÓÌóžµ»^€‚pjª°SÍå~ì²®™6Ⱥ3^˜ùÂŒfÛô!6‹cŽLjšcjq=§—.½4 ÀLð…u¦ó—ì>%ÀEÙ%àNq]æw¿ûã¿üËÿ÷¦¾þôOÿ‰lƒÇ¿ù7ÿòoü›úJ–ýö·þ·þVqéÍ¿þáÏ?˶ßý¿S\zó¯ÿçoÿmÙ¤_ð:üÉŸü‰bu™yöë2¬X^iŠWˆƒÅ©·é÷ŠÕ[ÚÈ—O ÑöFa°9ËñºÎ(©)ÇóuÔ;ìÞèÞIo>3V9>—únÉx[£0Bó;‡8nbÇ3³[jâ 4ôN·Ñ tãL¨ñ\Ó±6>gNMË“.<­$˜ .2M|*Åèb-7¡›Aá*ìY{,ët´›ûÔµQŽú«!fòg-þ¹~‚¡Aª Ç=ÏÌh†]³u}éЋ(øî(î8E޾%‚ŸÄÁN×2–sU½f\m¤—'(Ç¡«=åÙÍ^»x6Çvöâod^À^{gooc{p<5e8V…ž]/À©³×XÆt×¼÷\®ŸäãÈ×ÌxaæC 3š×0Î…ÝÈ3Ùu=§zaá$™à‹AjAþ”h = ¤¦÷/l§·5"Oloèë?ÿçÿO¶Áÿø_þ—ÿù›ßÜÔW²ì·¿ý/ÿëÿZ\zó¯ôü²íŸýïÿ{qéÍ¿þíÿö¿É6HY\Ÿóoþbu™yöë2àí/KNsïÈ¢X,l^¤¹”š6Ø„©ЖZ7¼{†Bk•V»|u”p¡Ä ¹iš}7óºÅN‘KŒé|C£K{±×Ï},ö(“Vyion€!Ø®¥“=ÆÛ_Å£b²˜[RowfvKMò­IÑ×™Eˆ¡Ó\ô2¡ÆN}ŸžžÒ…mÏla_:4éFÝ­¤“ï\•@Ï…Ü„nˆUéü„' ÉÇ‚q¸ä,ô‚¶0JÓ_ÑPd8øµ§gjÁBüíBnOþ¸Ë}?ú\°ÇñtÌ“ÙÖbFp¿Éä¾Ì;WÇÜxÈ3¡™4bRsêó'‰ê{VØ©ù,©¥K:ßÃÁ)F!>ž¦úAš÷JMGðlŽ»÷âod!.§óÍvl®'…SEŒÏfs<ï…ÙtÔˆ¢°v× p@ò-pÌ‹I'ÙäÔ¡0–ø’.ÌÑôâüÂL|À®s^Ô èeˆX»‘Ç:ÅõœÂ$u|ip*ø0:Ç©•§_þ„´Ê µyú ²÷u™å¯dYÔe~E]æMˆºÌSu¯°b±fŽu‰Ï$½Á%Éˤ…Õ¢.œ&é^ÚA‰Ôôò[=%‚O]75íê]£¨%Émøûü a–|V\ËCý8iU¾]@!j·øýÂ6‰ƒ$½¥ª··@•@ÃåAs¬]µò­ cÉ5 çAiL҃ЩË|@ä/½ì¸ŽÁ£sœ¤3Ö&ÝØk Kj=‘O:ôöú ¹±p/ä ¾µÁ ã÷ у…Qšþºa¥œ4¸q济Æß9“7 z5/z ž“ÖéQ$/š™Lcº¼uWM—ûØYFOM'òû…žÚmOÝKäsܛĵ\U;é|æ¥Eäµ…øjj:B>›©©žJ¬I™QÛÐlw£óÕ“Óçúձˣ­PâK…µÈ4Ûs„SSE~רç¡mHÒÅVaòÑaK}s/.Ҧ暅‡ØÂt^áÂ37ò®N@C³oÁšS…ÍBÂ|úQ<:g÷ ™¯} ÀDjN“ô;%ê2Ë_ɲ¨ËüŠºÌ›u™¦ê2ÀZ’/`¬.õ¾¥%]Î@’­@|&Ñ B/Z94ï k*ÖQudaNM4mF©fiš µµbÞ*6ù:]ÐÓß„±Ôk°·è9ù–"gF퀦wг¢Z„hºq&Ôhhzñ¶Öt| jaÒMþ¾Ýš9ìõæÆ|Ö5q¸ÒyÆÂcÁä. Äàè(={ACá>NÕN¯Ô”a=…©óA8'è[ÔÅÔcͼE0–„›¡f›þŠÞ#蘄öž ¹*“Æj ð®7´7ojËÈx6ÇÝÇñ™ËéüD³ôèÍ×L2,i*Ai©ãÂÚ]/À)î©‚¦ ´ÐK£.çØ<$gé‡Ü‹‹„´©¹Éчô2$çè<£óªNA󱀞oß¾9—v‡Î©m(fÍ=;1²~½?¢.³ü•,‹ºÌÁ¯™º ·9äß÷ çÀ\Z»úÉ–¨q@­_í¼é¤ó3Àö¥Ï«ãÛtaHÔe˜­Ëf‚5ƒŰްÔõ² y’èÏ?3©jçå–yõiÚ¸”úüü3«fs5Urô”ˆ˜ÌCòå>j˜®µÀ¶ÜÇžµâ¨U…rÀ¶£!¯AÇ7'Ž#“†Ù`¬â¹3©vÞ.•ÇM7áæ tjïeB Ãi¤S6ÍPÌËd/©Ð ¬î ˜ñ¥°z¹±|/M¤ó Ôz,å›HMCæGø[(™Ÿ¸š™øÛ’Þ„:µÀäcÐÌØ#X§õÀ¸já õÙz'Ë·ÌŒ<`Éæh÷q’Ü `"0x ©…]I(¹*µ½¹Ç¢9³€û›ÈNžé¼ÅnüqSéüD¯]ù™»I`\@Iêÿ2P´°v× ðM7ˆ¹À…<œÉx! k‚¼n¢ñ]Ù¤çÅù!‰OÎüCz™P€È$uƒyFçUù ËçÔ¹49´É:¯ 0‰K’D£)ùþˆºÌòW²,ê2¿vë2Þq'¦¦>ÜààW Ïh†¦<Ï45(ôóàR;©i ìA³TåÐ8Þu@Ôe8V— ‚w€1ãïÑÁ{¥®ËAp–XD‚`¨Ë,%Ë¢.sðë²u—<ä«ƒÖ ˆÅ§ÓOð}ÉŠþÍÊHAaùEê2ŸvÄäFÖD]f¨ËލË™¨ËÁ9øû™Ÿßûß ‚ku™å¯dYÔe~]©.óðð@Ç&ùOú§]f– Õ>Š7×GX}ÒÅOÛ]¤.#cýññ‘!hÑÏ“J3Œß¤¢.³@Ôe‚GÔe‚ ‹«Ô¨ËÁÞ"Ï|ó3‚‚¨Ë,%Ë¢.sðëJu™ÉM+…äwß;\ôÿôò¯qyÑQqd†£F6QE&dÐ(åÐQ—Y ê2Á‡#ê2ÁG&ê2A°Ì·ì¿³§¦ Žu™å¯dYÔe~½m]X/Ôe\Íoþ¼U]f€=*JH9Q—Y ê2Á‡#ê2ÁG&ê2A°Œ"ýáüßœ ¸Q—YþJ–E]æà×›×e&•IÅŽúõäë26i±¨Ë,u™àÃÁc‘§ÞÌÃ7Þß¾}#ÿaðÓ§A4ùôé“–ò¯s‚àâD]fù+Yu™ƒ_o^—™ùU¦Á_.säë2ñó2—%ê2AAA\¨Ë,%Ë¢.sðëÍë2ðÓÞ¯2ù—˜j¬ËØþ¨Ë,u™ ‚ ‚ ®NÔe–¿’eQ—9øu u™‡‡õêý*“*ͨ¹µºÌ÷ïß]—ÉÿóTAÔeˆºLAAW'ê2Ë_ɲ¨ËüºR]æÓ§O×<==%ÑŒñߌü¸.óððÆxI]¡Q]8HM—#¥|®¨Ë,u™ ‚ ‚ ®NÔe–¿’eQ—9øu¥ºLž—WêßTü¸cºør½ºLþÃ2Í ”‰ºÌQ— ‚ ‚ ‚àêD]fù+Yu™ƒ_WªËü´ý øšÞë{||TÇú‡bTéhþ(  S¥¿¦®\¯.ÃpÒ<ø‹¿"ê2 D]&‚ ‚ ‚«u™å¯dYÔe~ÝÂß—ÿ¤IQñ/1õ :.…¼ùß—ñ_ÉÁ…?~¤ÖQ—Y ê2AAA\¨Ë,%Ë¢.sðëFê2à Ë—/_RSöKL½¿¡{#u×~úé§K¢.³@Ôe‚ ‚ ‚ ¸:Q—YþJ–E]æà×íÔeü«Lù/é‡hCßB]ÆEÈ‹J¢.³@Ôe‚ ‚ ‚ ¸:Q—YþJ–E]æà×íÔeê_eúúõ«´=>>ª¥æÍë2Œ+³a²(Q—Y ê2AAA\¨Ë,%Ë¢.sðëvê2àßZRCÿsú§Ÿ~úþý»jÞ¶.³V”¨Ë,u™ ‚ ‚ ®NÔe–¿’eQ—9øuSuÿB~•I%ñ¸oX—É‹2ƒŸèiu™Þ .ÃÏ'VÐäû÷ïİ÷¢ÞxŠ¿ƒZr¬Aj}œûè‰ø¿y[x?ЪEûŠt¼5ïx›u™å¯dYÔe~ÝT]TéàóééIªÆ%·ªË0œ‹2õÿöÞ%ê2 ¼v]Æ©f[”»%¿wô\˜y\Á<þlñ8z"þ¯k®·t"ÿsƒA xÿ×:éq#¼ãm^Ôe–¿’eQ—9øu¨.Ãq“$z‰’‡•É·ùøÏ^Äs3ÆØÈ‡‡Ù_0SóÕ¢ EˆºÌQ—¹KŽ.ØÜ–ÃÑB»°ñ:Á%è-®÷r¿Üû}Ý‹ÿ+p~èî"ølõ°PA–µă4¨ñÞìý¥)ù_ÿgO¸y¸ÂFÝæÝQ—YþJ–E]æà×|]f·§„9P‹,=¥ÿ­_±[ ×Ó’êÅ£ÛFÀë$Ý‚½M’Ûó´Wµ‰ºÌQ—¹KŽ.ØH*ìÅ}{/Èþ;5>¸Y¼n£{¹_îý¾îÅÿ8?twü‡‡ɶO{D¶ƒwZÅ ®Ê{­Ë|ûöM~Áë?güˆ›ÇF2œòœÑé{"ê2Ë_ɲ¨ËüÚ­Ë䊾7ó‚Å€qÕÃ[ØýcºþùšųbÆÈ±…ó¯Þªu™¢.s—]°%lÓSÓÍÀÓóàéé)5Uèù…L:¿yx†bíÅ£}%µ¯:Å㈠«ýmCÍèX2øFÊØ¹L/þ¯Àù¡»‹àËHžŸãŸ‘‚÷Z—¿ÿ|ýú55½¼1zìI'/qÙÔ7¯NßQ—YþJ–E]æà×n]¾|ùÂVd@þwܧ©µOíÀ+O’›ØÿÌüäf×È$×'ÉíÑ{´F]f¨ËÜ%GlniîÏCÿÞìÕ vSO¸—ýâ•6¸ïxßüVôrïFî¥ýà6¿åûz†™{ÿJœº»þn xÇë oS>º œ¦ \b ›‡rýÉu<ú#èx±yó×Kin|mÑûüù³®îº¦XIXpÚëÂÕÞ‚Ýœ2OD:?1öh×f®ÒW€¼´™$×A³ÃpJ ÔK$¡âí",3?ŸŒ_îè»Ö# =ú}Qâ 0ûÙ“¾ Ìä¤U ÅÔ`óÑlÏÉ£Ç4 î8¨B~&ÚÄSŸ½;TynK8UÞòÙÌ$¥œØhPH9˜¸Þý‚–ºÔÖzt¥}1ݹ|ÏΜ"ó9nÆG`Ú.õÀÌ9ÿœÂ~$ÇAKö‚œÎ_‚üî 3ÁGã"Œ6§4äAËÛwÑêjê‘/i¤ Äzq.îÄ«y#ë9ÝÙ†£Wž®¹ÎcæG z:5wÎ+dj³{a6Áì%ÉE"è÷S º;fê2çä äãÖç7=ê;kݵ-´_ãq7†Aê<85˜ 7¯NÌ+¢Ä±æú͉ºÌòW²,ê2¿¢.ó&D]fº ë–ÖÖËÔ”Á#^W½r°H€å\-y]†eÆUƒõ{´Ñ,èõ’~>9fĺ¯.Mbã9À£¦ñ\’0K­'zF²-¨U‰±_\Mç'VGðn¼°ybÆ£Þt°Æs5Éul•. up΀ÒdÕ…f~ ²´^tâBšƒÍP꜇z<‡&}^­èM # ° ò½è5£"@~íÞ(ÐH)ÍUŽó´TIFê:Rëû‚ƒ$½qñûa"S›!ŠìíÅPp5ÉõíXÒ±— òHDyݽˆí ñkwn/ùó¸Á tÍø£3¢Â8ø46ùžä2¤«÷‚Ö«¦74HN/ßlÆ$ÀävÖÊk=úÆHŸ7÷´ ^D9.å|6ëö¨¹ä9bEB/]QH¯$tÂzžã~<òÐ|jfX¹âYsNžôž–\’ðü~‰Û$w<'W˜£¡¹šÎO¨]þ6ÕöBq&~tpšZäf7Ó{`YÚ›¯: _Ÿ¨Ë,%Ë¢.sð+ê2oBÔeØ©Ëðp×bP/iÀb¬=4—ú¯—j–a_euŠæ^ÊÃ!ÉÒÂ’ùÚS¯â¨¥O¯úN§0¿JÙx¯‘µñÿøñƒOŸ‚¯r—D~;qªØ«ï ýȤó —É :Õ^LÓŒGPOG>×6s ƒ=1Hò.& mpŠ€ “°ŽÕ.°!Igºtyë‚ 8÷€ã$º‡3Ízì2Ç–¡ÅÊA§"§Øôyµ€y–‘fÈë ìAz ïŽ(j\Užö¹°5@ó^Ãþæ(yG\HÒ'h¡RW2« }“ÐË›‚«…fŽuPè—r¸Ôýâ#è7³ŸDOo¹B ®&¹¾àK@¯ÍÆg8vcÏN>É‹mýþÚÔæ$öX‹?¬Ý¹6¶¡žq—Ür´©±2j§£­osÁ©$ëà_0¥‹Žp£¥}ðI÷Ú’Ðê=뻀UF’ÏzO$¡>Ȩ;z@ }c0y>ëtÍG©Ÿx Ž{ˆf±ÀQ’š2pPW‹¾«î ä…ågF¯“žÎ\ö¸¤'ÎÌ“ î—¬Sª,#ty—ºp†¤.¥ójç³ÎBí×ù`³”sšZÈ L:jž÷íÀ¢”ßehH¢oDÔe–¿’eQ—9øu™7!ê2 ìÿ}?ÊëÍM¾<ðÐO­'¼#gQIM<óN˪@ƒÑbyV£±6ìAIjÝð&˜ÏÔt"·«ìÒ…—ßcGCj’ï ødEÄf_R£¯òiµ¹ky4’¨ªmðb\/½ÒFÇtþÒ€zãè}@ºÂ#ÔÎL‡W}Úp®æícfö(v 8Îc•oYRS†;1Á{73û$¿„ëéCsñ"á¨qËÁ°£“>£ÖÁ,¦ü²Wkîá^c6JhÏÓI-@/g‘ðÐPϲ税­£E¬ì©º»/3•?©ìæåÉ5Ca••_ä~Z ¾1ýBajÊÐ(ÍK¢g'±R;ä=È3¿ÖìKÀÕ3˜`…‡âòæïÜ<˜u¶ÐHÇtÞ Ý¡Û¼|°ñµžÜñ^J‹¼/CXg½ÔP¯Üñœµ{¶wð9“ôbÜZÒ‘ájjÚÙ¨ÍÓ•©ôÕZá‚ãήZ¾è`FjÍ%\ÊÇòtsuòY}fäaºçI†“BÚtáÄB¸ °%v3Ïgðiògiq©#…y—< „.Ñ1ŸpàjÞqíq7‰§¾ˆXÁ²yž¯"zà}mþâ/þBok¿ÿûÿþèÿº©¯?üÃ?mðÿÝ¿ûG?ÿ|S_ɲßþöÿü{¯¸ôæ_?™öÛßÿ½ß+.½ù×üÞï%ã~ûÛ? ^‹?øƒt7ý“òOÒÍì±_—aØ{޳Tè°„¤Ö^òeÃK5Ôkk­tÖ+¨Wšæéu®X’½°¡¡Së [8¹Óo€q‹fëRíZ±ÃÈéEC~¹=–$[9¶­ÂÚtx+Ve7ë½QÛV'˜±wu`Á³\äÆX³M-ö¾M¬jæ{¹Ž*†¥¦Š…IŸQë¾u”À7Q¾)ïá_o¸|Šóôníœ)ür`{³à›´pG¨SWŒ]È·¶E†XùEîL·³· zÚLÏNOtá—ñ W}`žÿ¦ý½;ׯ7oRr>oo†Î3·yS¸ýœ”&8©õÄ8˜=”BÍ.Ë÷,þª#}=<ãt©Ó5w0tÙqNëFðI ?]Øðc¡ˆ•µÍ?«Ï‰|þtªcE‹®Öš/’'õÓ2ÏvF,4烦¦½üq—:2´4U©]—ê˜}ÜÍcß9HM-ÖÌsšÏâŒ6®ÖÑxMþìÏþLokA|þøÿ8ÝüÁûu¶zÊ«¶‰<ܵà X/›O/ÕõÚ)¼åëPogczFZ[sŸ½kLÁXÞ6`j½ˆB3 cdÝ¥h·›õn^xP¶kÎ;ö´öÞIjfö(]sOÖÓà^é¼bWÀxë9³EÛê˜brÍ®Z¿¹õŒ´ƒP¿ô’*Ç ‘š*mÈÓÆùëGN~[¥¦ Oú ÈÞ¹ö¬²@+/2|w 4wPtÐ œ:L³o/b9΄ÂÛ‘ærüw¯f¼Îi†Îa™¹Í{'Û`9¥{£×^ï¢.ÍùZ¾g\-|?¥ß¼ƒN×Þ3ʹˎ»cQy‘0Wu@V§ ~,çí=«Ï‰¼GÄÎÔôXdËùyÒL¿ü.hú"|¦ó Ô¥NiP«rz\äq7ïô|rkÖÌóCµÈRã m†ýuøwÿîߥ׵ >¿ûÝïÒÍì±_—æ©§?Ím‡Ýb൤· yQÉ× 1XÆšFöÖc±[î)Ø5¾iƒñ*;¿öìwûìÇw‰Rº\á}@1ôÚtô´{ÓÖÖ³ÆÓÔL™Éu›åžç3 ¶§ÂA =ÀV¥ó»j›“•shv½ÚŒ&DÒæyšz/¨R¹_N›Á6¸#¥¦—ôrÏíE$ÀBÞìNAMo,pTÓyE³¯ß¯³ì»£PÞË=qô)a8ÿµ;תfJ*Ð Ý¡Û|¬¡CáÈä}› sÔk¬¹@]š‘´¶C÷,`ž'C=Ï8ýjvå›Y±ì¸ï¬\›Ó•eÈšÓµ ¿çwÁîƒÂAÎïâs"ï{‰måE¶,‡Ë óÆœf¸Œ&z!ª‘Â:Û{y2ÎÏl­ðLœ–½Èˆ5óÔØë}°c¼6þû2¿ûÝÿå_þ¿7õõ§úOd<þÍ¿ù—ãoÜÔW²ì·¿ýó¿õ·ŠKoþõO¿fõ»¿ówŠKoþõÿüí¿-Û€ô ^‡?ù“?QÌãïËÌ3U—ñ¢›?ÇõôצAÇy Æ;˜âÑ¿»T{ÍÈc72‹P ¤>j,Q²±t>äÚû Z.¡ÜôÚ/ëD8]kÁU‰CïzÔìØ›\°üî[q—ž  8ô¦©é…¥&R EXš°–0Ðwà ‡F,5õ™Ÿô]µ´[ ‡RŸ>=3šÌãÚ6ø_¿TLÊfçß´¶ÁÜíZe%¤¦žr\È›«¸Dò )ß½œ·?ïëFRS‹¦r…z0¢zÍä4‡Èišê Ó‘šH3Øqßžc¯‡.Â>›75Øxú¦¦\•Ø¡”V¯AäzûŒ§í_‡ª{M­Ð~¹dÆqów¿E3ª°6ùö4oçØíȤÖ='ò%©é%u¬àœpíZ‹N®ö4 F¡ú6ÉmRUÔk7¥Vx&×x×ÌSã óß<»8Q—YþJ–E]æàWÔeÞ„¨Ë,0U—=ë½Bð@ÏO½ÌxO,ùúõow©¶ª|1v# 9PlÊ/»î^iŸáÚ Ð1ù=…¹_V;ðU’)†^›ÈëAŒ+d-ô´5ñƒ^ÒÌéü%M/ÜH_ÚÔ?õ3€í8¾ÛSà¸ÕžÁ°0é»ji—ïIW‡ÝªÙŒ &ujjÁ¸ócÁ-ãQìW¾tß"ø9½H+á 5mô”ÛÓBÞô:’c28À#ÏÑP{íȼýy_‡‹«©©…íÉ‹’ê;Q½ÆóeæíÏMuéHû€üε×ç×e`æ6ojpã8D¶öPJïÎN\¨ÉƒœšZؤKU`áÑ×c7 6Õ8Çqp»'N6»ì¢SGû&^–þe9zVŸyˆ’Ôô’:VpN¸v­U¬zš{»Ž3âs˜6Šàu©êµ›žÂ3ÁTÔ©©Åšyjäs I—7,Ê@Ôe–¿’eQ—9øu™7!ê2 ÌÖeŠ—z=`Ï¡«Úø»Fõ£w©¦]ùbìÆ^¯—]w¯±ÏðZÓ«~£èÙŸ·ûìƒw‡ͨÂÚtx~=®¡åèzï!z6€êMSÓ 7NNîQò7íbˆÝ¡×&}W­:B>YËȻڌ&3ÂõD;‘z‰¦_Ö6pvתÚ$ÑSî)(äM³#oV²껣7ÌÛŸ÷õ«`ÏHÑTÞË=£^ãù2Í!rlnªƒ<9Š˜ôÚ4CW3¸Í›®šÒê5ˆgÍ`¾vglRUOPÞ8ÉÚ£¯Ç®<·Û6Ú‹zÁ²ãà­ŽBêSû¢­‘•÷,T;ŒÓ¯àœÈïŽhårÍ,‡k×Ú±æ¦Á.êqµþî‚öƒTÕõÚMOá™4ÃU³fž½n¨Ë,%Ë¢.sðk¦.ãŠzÄ$ß#×£–ÝoˆÉ–¨q@­_íƒß¥X€ÅŽW½|7‰ºÌ³uo§ôæ¯G^È­7³äYKAòŠ…djÊvWhNMs\vÝÝ5>BŒÜ576ÿ|iÏþ¢Ý/ÐÔÓŒ*¬MG^•£1y£ÐQCpš*ÆÓÔôÂ;æÞtœ;O_ÛÓ3ؽMú®ZO¹[SÓ(æ|ά%†Á’V›gÆsÔ´Äi“G¾ÀVõdz¹×Snƒ yÓìèÆfÙ´7Øñt^1.-èݽÜ32©—†Ú5aS9HM«w®UM®ÍÐ5éÝæM «ql¼"Ãç¡”Þ Ôœ/]‚C÷,ØÇ|Ö&q$=úzìÊû5>7uÙq¡îT;“Üï”8`r%\çäÚ³úœÈ7C‘cåE¶,‡k×Ú<’5N•üvp—曆®öC/Ovó§§ðLjaçï\OÍÀøœAØkšÂ= 2.žÒ»³S#cšóµ|Ï:Ô½ŽÆ.uPòÐ{FÉ~ÈCºì¸ð½ÃüÊ€<¼y-Æä:ÖžÕçDÞ#â~jz‰¶p»×Ë“AÁ“›ÏºšÞU©ªêµ›ñpËÔÂx×Ìó|*ù½2Q—YþJ–E]æà×eë2¾…äw®nUèí rš·°žc Ë'Ÿ3“°‚Ø <—r¢.³ÀºŒ ­ßŬmÛd=oôuÐL…Ý¥Ú™”/Æà¤ìíÀšØæt^¡<+²¹Ç5öÍFá¢i­°é—oæÚ^Tw=jv”›ÀUÚað´]è.mƒYЈ=k(¼p*ž_§è9è½,6¤¦ \OœX›t« Ôšâ}<ÚØy§Ö¼~à…Ã’›Ý|—v Š¹p{or«b—ÙKéœÜªÚk†"szÊ9U{!ošÝX÷BLSµ#ƒ<=;ݱ(»ZO–:ÒžÎ+Ô±t>d9þkw®lƒ:Î@>ço¤ÍкÍ{Á¿^JïÎNÍ`¾–ïYÌS{3Îcì{ícnOjÚÃÚ &8ž…ÂeÇ…·:\Ux‹8xš´"÷ÜQ_>{Ó]sNäñT#Býn`—¡È–ëå‰#Î_ÒL•A›QØž‘t~¢×n4\­ðiûÃÕŒ¸¶óqfŽçqÍ<çgmöíu™å¯dYÔe~]©.Ã^…ŽMò‡Cï!ÙD÷uqãëi<ÓÅóyò9³ jýv)Ût.‰ºÌê2ù{Ÿuî:™6©öO½’:ºÚKg’©iË Ô}‹F†.U*¨çK“]ãtþßW¹kùf"uq VØôËß¶‚âæïEum:¼QËahm<ªê×°Þ/òéýb±É–@ošz^)žYœ2 :g*}ˆAa›3[žšNx\+Ç5°6é0V Ö€da-(†fÐt¾‡‡£‹§E—ò¬@FÂ\Ê0óì/—êYÈGÉï_F´ÎÚæffÖä<´5{è"szÊ{™fš}¿0\Þîüµ#Žj!>ÅDH èëŸÈúæ1ÇZWm–t^¡¾õtôX‹ÿÚëhÇùpÚUäf7C‡LÞæ½à3®GÛSZ} 3ÆÈ’z,ac›¿g1O—085Mcµ }èÑ×Äö òÙ¦z»õ~ÍqÃ%Ɉb¾\U”X^ ̱ˈM>«Ï‰<ä®ù1R¸Ìg1(¬…k×Z Çg:‰ÍÃëFÆMMÛãÂf@Ïþz ^»‘…µBµCnÆ<žúñ<.›ç—(.åë…Ðó°—–¯CÔe–¿’eQ—9øu¥ºÌ䣘›NòƒÛYx»XÜ¡z@þ<sÔÈ&Xž?îØÏèt×u™ÔeXt==0Øë@oÎv—jgR|ÞîúNäV½¸Jã Ô±t>d×xië 'c 72*Ïþd©K­°×î›ò­^/ª»õ:[ÏÚ‹.x¥n[GéÌ»«¯ÓùK^ø 6ÅaP{Ï÷ºH8× ¨wÕŽlC= { µI‡±Z¡îM÷3VcÝ#"ǧùFÜÏkÁ±u#Í”ð:$Ë­N“h†C1N3@bðlʆOé«Ó"†=åƒL½Ž¸ v†ãl†/ÕŽä·3òê‚|º< Bþ¢¢¾ù Ð|£1ˆ¥ó iÈm³X»së' ¤ó—u¨fèЯFzy8µ@q›‚¥”¦WÑ“Î'РÍá`힥EWëøï²üèkbyg;ÇB§ÐÌó凕(n®ÔzÂñõê`d¿@§"7#‰nœy(¶p b'CsÀgêpâJy¢î|¦ó—ÈÈ5Ïdd‰Nu@K’>A‹Òù‰^»é)T{óÒ ¾ÓÇó¸l^=ÑȈ3-¿Q—YþJ–E]æà×ÛÖeÀ·ûºÔÔÂ{˜báÀ*µ×OÚ FÖH £Ûl9§NÇD]fupfKuj=‘‡*ßçì.ÕΤfò±*ç6ä%µN H†X:²kü8_myá§µS´p(µÂ_ž®úµ¹Õ]šýÖÁö”!¸dݾp:ìA.(\ã”ÆžBÆU¯¦(ÏßÖrPÛܵ×0Da¡@CoÛ]š?Ž› iLº«hPÄ hdn¢$7AÓNô`Fý h¯‡îÉ\è…·7AÍÌl’¿áìÑÝ¡KEæô”sªöBÞ ¬ª'Ž¡¹_¬³éÒÂøÝâ‚Ayí8ÐØ³_³€@:¯BÄÒù ñkwn1 ¥¢:Ž{yXßæãà_#¥wg§F¡Ì×Â=‹y’iÎÚ.Í Ó²ûè«ÉÂ^pÚÛ‡Àòà ¼©5Ãj9HMp¹¶hÄ»âY}fä¿zÁçª.ñ)áœk䉴ñ™Î_b;‹Û¡žhÀ,ìÙ¯öz ^»Ñ@µB°6ÊóÝîËæ~†ÈvæÐ¸›á×&ê2Ë_ɲ¨Ëüzóº ÷£ºô6B÷l}×ëiÅópÀ‚‘5<(ØI¦“ž…M¢.³À±º +9½gº®B:o!üg˜sh—@:oÁUòÌ4={hkÓÕù%Jò=ãuµ§ÍÑKç/Ñ®Th“$š]Æ~é¤óaTÕ>?x¡Û²¹€ùÀ‚#À„2JjÝ mèyôE­ô äÓµi %ù45A>‰þòKÓøC“nvÕŠ\9°-¢:O>b=;\e¬$=!o%/JÒ…ƒ”n’›”MJŠÌ(W{/ÓÆVåa̽t¢ç°)7®ª¯'-ŽêjÀIÅ?á<+ùt­O>\ÓåAèŠ{› ~¡êÌ”FÛX FòyÀ›½g¥v0k»äO§<ÂÒœNö¨_\í]ÄQÇì„tþ”èênäE À¤žR{Nä¡|%ØÀæ£á[««½áÃtþ’Ü kP—Z¡üªUõÚ®Ö ßóÐEšÓI‡eóL1_pŽÍ$ê2Ë_ɲ¨Ëüzóº ·žº *Ü­’©k7oU—©ÑûÝÀ‹œ¨Ë,p¬.¾Õ üÂ$‚ æ©ë2AÜ>Q—YþJ–E]æà×›×e@ è½=}:ý€p-u™CÔe‚cÌÔeÝ·AAp”¨ËÁ=u™å¯dYÔe~ÝB]æaïM^¢.óqˆºLpŒÇÓ߯á1ÑüæÉߢ ‚ ‚e¢.÷HÔe–¿’eQ—9øu¥ºÌ§OŸ8®iþÇoß¾©WsÍü¸.óððÆxIýûŒ4ª ©éD]æÚD]&8ŒÜ™û1Á±îX˜y´AÁZ‰&7ˆAÜQ—YþJ–E]æàוê2=zJ´fAý ƒ_bwìIIô„¬/CÔe®MÔe‚Ã|ïükA{ü¤LApU¢.÷HÔe–¿’eQ—9øu¥º «ò5½è_8¨ß’ôJÕ[ÎЩŽÒ_Sÿ„NÔeË‹øOýúô‰‡‚~œ–t9‚ ®{\–žÁ?Ã‚à‰ºÌòW²,ê2¿náïËïMͺ†‰©·œa•âï˼{¢.AAÁÕ‰ºÌòW²,ê2¿n¤.®°ä߯ö/1õþí}Ôe>Q— ‚ ‚ ‚àêD]fù+Yu™ƒ_·S—ñ¯2}úô)5Šƒ¡£.óqˆºLAAW'ê2Ë_ɲ¨ËüººLý«L_¿~•¶ÇÇGµÔD]æãu™ ‚ ‚ ®NÔe–¿’eQ—9øu;uðo-éW™>þÌñO?ýôýûw ÔD]æãu™ ‚ ‚ ®NÔe–¿’eQ—9øuSuÿ•_ý*“*ãq£.óqˆºLAAW'ê2Ë_ɲ¨Ëüº©º ¸ºñôô$Uƒ_b‚¨Ë|¢.AAÁÕ‰ºÌòW²,ê2¿Õe8n’D/Qòð¯2©àòÓð—˜àœºÌÃÃì/èýï§1Q—¹6Q— ‚ ‚ ‚àêD]fù+Yu™ƒ_óu™®Â¸äñÓA©ÅëWäÿ›©‰ë2Iu d’ô†€×IºÃ·oß’ö©çKKR‡—D]f¨ËAAApu¢.³ü•,‹ºÌÁ¯ÝºÌ·oßR½¡ë2þ_×cÆUŸ²‡þðÿ|Í&é#wë23å*(JB&ê2 D]&‚ ‚ ‚«u™å¯dYÔe~íÖeàË—/¿ Éñçññ1µöI¢žžž’ÜÄ/C}ÿþ=‰ö©ÿBÍ®‘InH‚/Iú%Q—Y ê2AAA\¨Ë,%Ë¢.sðk¦.\œ¨Ë,0U—QU¯.ÅÝ2*öjx •ZwRîÚ0)ðãÇtA,q#Oõàøúõ+sÍg:‚{&ê2Ë_ɲ¨ËüŠºÌ›u™¦ê2þ{ÑéüÐoîõ~çí£á?µû˄׃m¥là 5Á4ß¾}#{Dz>>½§:÷-kÿjá5‰;zígîbviTygD]fù+Yu™ƒ_Q—y¢.³@ÔeJéEwóéÓ§{ÿ>UÔe‚»†}¹’‡û15ÁǦ÷TçQû-/[qGBszû±ºÆ´Fª¼?¢.³ü•,‹ºÌÁ¯¨Ë¼ Q—Y ê2 Ë¿wº5Ÿ?³~Ü+Q— î'¼aÁíÐ|ªs¬F¸å'mÜчÐ~æö÷`טÖH•÷GÔe–¿’eQ—9øu™7!ê2 D]æ¯ñ6—¾ì ÿçd½ÿÐ~ûD]æ®aúÈIHçoß¾á>Éó‘ƒð:<==m¹öÓãEÿ Ø•Ô~dzOu‚¬;…»&5½:ß¿ßfûù§MSÓKâŽ>ĽÄj0­ËO€w–*±šCÔe–¿’eQ—9øu™7!ê2 D]&ñùógä›]¾|ù¢Kè¼Óßpîíà_“¨Ë,£dþà;9ˆo–¾WºOãö¿8ƒ§ú›ß) ÛÆKpÜÑ“Ü×МÖ3Ÿï&Ub5‡¿ø‹¿ÐÛÚïÿþßÿ£?ú¿nêëÿðdüß÷ïþÑÏ?ßÔW²ì·¿ý?ÿÞß+.½ù×ßO¦ýö÷ï÷ŠKoþõ¿÷{ɸ­F¼üÇ옧›?Ø#ê2Ïè›{ò±ùß‚üS3wúÛLQ—¹kœœé<®Æ•îÓ¸ý/Î-<Õ{`’l›\‚ƒ1ï` ˆ'€ˆÕþå¿ü—z[ ‚à#u™y¢.óÌãããó~¡_vùúõ«ît5ºÌ];¹àÕ¸Ò}·ÿʼnºÌÇá,ñ±šÃ¿ý·ÿ6½®AðøOÿé?¥›?Øã2u™¯_¿~úô ÓüF4¢ ¿ ôððГùòå íi€ÏŸ?÷Tq›‘OçC{Þ/ ÿ…ò9ó«L†Nÿ=šÂòÙ¦ùo¡Ð“.w(¢‹þÄ€ìíàÅvL‘ ¨}zz¢}w[ÆpšýÔs3“"&ÓÏÔ&ѱ|Á™“;ï&qC 7Щ˜ù-}eÞé”ȧñ~ú©9 4"Ÿ$¶¹ëM–饟´C h´I«—ÃkÔ±n/¦#ŸÙ:¤GS¥vÖw(§½;ôhÎ8½@ Åd,cvÓ^ÚhW²q°™ðL=Úê4.ŠCjÅBö¨g¼Ž¶¡½v ùÝ A ˆ- ª7ÂŒ2™´½[ŒF…´xªË…:¶ÅÓ ˆ Ç7qd2á5:È6‰Y.‘¡å¹…€üà¹'…Zn€œIÝ6ÖR¨9³´4g¶xèñ™÷¥½÷|0…Ít×ðr¬`Jl†Ýû½ ž_äw ®©§U-(¬S‚KIhH­Óu³€¾¹æâ^ãjï\U§ôª 85OøïËüîw¿ãø¦øÓ?ýSÙÌKj½’e¿ýíŸÿùŸ§¦›áþÃ(ÛnpZ —lƒÔ¼<ýþê¯þ*ÝüÁ¨Ë°i™©áRÚ`½Tû`bб´ÝQß$›[é¡W:âAk°d`曓²V£Ûë´õôÐî±jÐÙ3²7¶:­]ˆíö(©óKÈvœ:nîhàu‘H9óé'Š$4äœÉ=äfS¹áj’룘3"ÇE d¿á¹Ù3làÎ åè¢Ó¢¯F‘I5îU˜êX·çÓ¡cSdÚÑTéA’˘&MU¹‘“9ã!ziÉÖ_3™°›öŽ|ܼqf2V’;¨Öò°GoÆQ•)Ý›9ƒ¼Bas±›OÚÁ-æŽEXÔŽL:?‘? zê:,p(á’{'I¡àÇEXrèØ|ñ–B† Íîͱz VF`¬:iÑUzéÔK¤žÍHªøLÒ{ ’¹~žX¬×& ¤Ê¡vLz É…NsÈÍ&й4O>™Í`t(&züÌœy†¿'xUÓò þvÃþÏÿY¶Áÿøÿ#µÞ ɲßþö¿ü—ÿ’šn†ôþ‘l»Ái%\² RSÜ$çÖe¼Ø Ô 8ðrÅ–.‰n˘ëõUX _ÒØ¢YÃ!£QòÍ¢¿Eft©7P„ùLç-À€ÔÔGÂ|êÍxÄ~1·™KI:¿rºº;" « ±@£ƒû¢?uØX‹mæ]]m²Áb…4¦'šÁ}!O c<ÝM?`©K|Z¯¥‡ã$7DQåS¨šœÜ£ny"t*fæåô’…¹Z4 eoø€$§„‚O÷B¾Þšû*p,_P®¢¡ƒ"ª Ÿéü%«zRÓ u¬Û5"Ÿ:@LÇð$t‘&ÓžSl°=lö>“g òÀHe‹µ‰ü¥hR-¬åa¼ÇÊOd ŸInƒ°H°JÂ;Eß$ÑðNí0“:æ ¶r°ru9žA!ÂA ¯Ú­Öžæ:ëZ ¤Ž» OJ<{’)ԩȧOjiLç4º; ed~³pPx ºŠa:pßÜTŽ“ôtTŒá˜áOsÛ’è t‰qu ¾'RP»lõ©ƒ$=äÐ2Ç©õÛZpÕž¤'P¯¼ ãrjmp*¸”„†Ô:á›=Ð)Í:@Žã~žl\JÒŒ¨«Àˆ ht‘'Ûù«ù{"ê2Ë$Ë¢.s¨Ë÷ÂYu–@/0©é„_øù¬·bE£ñ’ƶ/5e{ÓzGå}|m€ªÛk؆J ]RS XzSS ÇùcÙ0µžpÇÚÙ¼cqÕq€b÷Q›•µØö°y šš6pÓ—  wWPÄ9ÅU_ª-쥟£Qoƒ&·q°6¹Ën‚}IçÓjéµfajk¸TÊ}AX½ê9UǺ=ŸdšóèðÖÝ{©2%͇€wêc#9žÉ™Ýç’ÍNç}¥½g¼é#`.4sÉϓ⠻jÁQšÏÃÎOâSøÈ,£$Ûù zp4¸Z¤Vž;°|‹Iyî p «…/6©Ž0—š³6HxLê]2ØÐpܸÄí™Z78¥ÑWSë )ì%ò¾ùLMÞæx‡f!g؆⪽Å]çCj:á©)ÌÃ…ü=¿îØäÐýn_êyGØ!­¯öP—zvìc3—Æ4ur³‡ÝŽó޹ûÅͲüÄuä3H¢.³L²,ê2‰ºLp/œU—q{s£ãÅ)ßxk¦'5eÔ+–׿bI6VXìÆ½rX}¥!·Æ›€™]…"M¼A)ö:ŽXÏìüe#5mxëÖ´-ÿÆN¾íXŽm‚1©)#ßâFz”bk®ÂNµóéç.é| )fÜz“»ì&(t f['a7Ta°i޾–r0öÅ7c/u»§z‰*4̧Ê=ïldm?ôrƽj¿ü(èÍZŽÝOçClL/a¸–T»¹«v-{8?› ä?²|oz‚ê7Ca3 Í]¾ÅzÓm/¸TtgÔd„EoR7²QßBÀ«ŸÍ»Õ…T(Bçöf 9ždZjZÅÁ/¦Æ^Cs”žk=„ó±Ô4¤—5¾ézÓ´ò¥Vèôkæó˜¦Îy7HI­\Øæ"£–Ÿ _Î4ûÞ‰ºÌ2ɲ¨Ë$ê2Á½°^—ñœíNjz‰7XùÊäe¾^®šoGÞõ¶×îU,öõÐ=fvphWáˆå»ÓQ½`°q”_oàÔÈgs# ÖœoÇ—cÛdw×Ë´J 9SãH|¦¦Õôóvªçò k“k¹)zí»8i{QO\ÓpÐòä±I=wš)c_zÑu¬Û=P/K×Re S{çöC9ã;´x+OJóE®àPÚ;gfîúš^$wÕ®åa™QOD º7=kƒQü-¢|€Aw­²’" j¯­òôÒÀ#¦ó zc nd£á Yç¼q&oÅcûw3p{W¨r{Ïøæ”ùճܥ¨ž@Áüýn{Žn9H¾ž÷sâßÔ9ïæEý‡žÌ²‡ÏCO ÑkÿPD]f™dYÔeu™à^X¯Ëøa°Ê6W 5B±6÷ånÌ÷19^8‹—.RojzKoÁ¡]E3b9MóÔ8èuucwW²ò0.Ƕ‰ïíTšœ ~mÿZú===©ÌÌc“…É]vSÔŽL☠sv•[‰·¿Ë)ãáRǺ] ,Y~R-Ð3f×HPxw©Íý¡´÷tïJ6i:»jw=²†Ý×°ÉÛML kÁùl{zß3M¿¤màì9·XO¹ .äÍ®U5½.3Q¥W- …0¨ô¾»ÓThÜ«—óØ»BU¯ÝxùΧÀ¨A)J®MNÍüý>£¶÷ •½Y û!=9Mm5OD]f™dYÔeu™à^X¯Ëx•¥½‡RŸ /óÅvVòÅRçµmÓ×FEGµM¼ÊÒ%5µpcfÐŒXNÓ<5ŽÍpؽ‡›Ù%ÈÈ·ndÄh6æ3WØò<€½vMõ·õ–ÓÏßd.qÚ+$õ1…Ú {´ì¦ÂÁˆ=¥bk˜#åÀA xâ–S¤Ïtþ’fu¬Û5PO!,§Ê.LÊ1ÀHU­‡KcýêˆX:?áÇNž«q\È™O{‡ËÓÝ ¼RbÃæzB}9HB'vÕ*ÀA ìæøÔfÔ,ß›“ï«2›Ï<àÒFc:¯8çë)÷òfתù„Ÿ±_} NÕ±g$Xy1nS¡q¯Ýü)øöí]¸eÐlšªv‡ ]¹wnìõ‚^œ{LÞï3jmJRÓé$DéüÄŒ›=z:'Ý ©D ú­Vó÷DÔe–I–E]æ Q— î… Ôev)V¯æw½“.¾êµm—bÓP¯¦=XÈgVJ[ªœšú4#–S›×Ûk8ìîëŽgm|¾tã.3²Ý6·eµ;Mlªûºã.µfúÊZÁ1o¿óû93ðTÊóq—ÝR8±‡ÇÍç½@Êgðþr9å`ìË@³:ÖíhœsR¥ïäƒ¸ÕÆìÙóÎÆügÖ\¬áYšš&˜L{‡«HÂzÑ7×VP;²«v ­ xÏ©™qÁXx<ûšA°Îº¥‰ýªŸ½\JççÜb=åö´7«Ž&üŒýRXx”ž‘`åŸM…ƽf²B°Ö+&= U»C4§ÀÃäZáï´9˜Àqq¿÷ÂX`óS™£Aká7{ôt®›c4¿ƒÔCODš¡ðW #~¢.³L²,ê2‰ºLp/\ .ÃŽ~@êáËï¢XP-É^<©ë:œ¨WÓ3+¥-©Çª±;é¼¢6µ›ú3v×JÜqàlÓx7m“ÝÚò|›âÆñ›ª–sÒOïz$š~IÛÀÙ«j“DO¹ .äM³£{qu>ágì§W- …Ð3zÊ› {çËHïÕÐSµ;Ds ܨíPSÇy’Þý>£Öæõœ*ÎzŽêÉéé,xß«ù{"ê2Ë$Ë¢.s¨Ë÷Âz]Ư“ë_Ž 1Òé2M½*ÞIæ‘þñÂiü¦ÑÛ1°ÞK`Ra3b9MóÔÅBž#Í€I©ib¥w¯\órl›4‡Èin˾MüyK¨<'ý Žþ·‹…É]vSôÚwqÌ%å0ù F±kR/ÆÑCX½òè X·ÂSz~‰ž1»Fö¼'®êa…|ñ£…Gé¥}ó>Íiö2ºZ;2©åa“ÉÛM,ß›^¶š³&z §4±@J`òÛ}4;öF½±7²‘ƒ…ÀîZ GþD±IÍflOÕîÍ)˜Ù]ȵ:Îó4ïwµ@nOVI&ßr ÎÚû>ÿ‚žÎšw¼š¿'¢.³L²,ê2‰ºLp/¬×eŠÚÊQ¤XäKãò;•lËWÓ¥'´„1ðH4Íó(ÍoD±RÇB³¡.l½ƒ|ûuÙ÷Õ±ñŒk#‹mÙØxðûOnç™éW°;_9k“«F8ä¦8d^Nó5 Àwh»oba> Êe3óvÉ›¦ 5¹r"ðìÀÄS½§_šò¦ÙѽhŸOx°y¼þ¼˜ZÈ;ÄÒù ⯎@_º0›À¥ož¢§P`€úâQj"mÏ;¶¹ U»Cô¦×ÔWîooN› ŒEÐÔ’ÏWîpªv`‚dò¾S Ò& Ýë¢K€mr°0¦GS糓i5O\°.ä=CHÓ…U®Q—aŠ¡þNÆɲ³ë2ÊUS?N¸T]¦°íü9…¨Ë÷ÂYu`ñö"‹t¾Ñ»áw7vÆ+™ÐÎ[Ýuµ^Mä”lHr "&橯ÉÝ„žGLD’¨À/s:æ u8±ÛLtÞ1³ý;©éBؤsÒõ|d¤ó9RŸÕ˜¤Î©éuyåàk,8”{M’¢Ô4$¿é®êìe‡6‘š^gÌÏš{¥óÄ™u‚ì7ö¼P˧jG`~.r.R—Ék¬>xóº É&K>}úô¥ó[·Íä$gÖe( È¿Ÿy$Sëq¢.Ü —¬ËAˆ™ºL0û<ÅóÐwƒƒ ‚à¦8³.ã:Bs5ôO©¬­•ç×elÀOÙ/!›×e¾m¿ùÕü)μ4³\0=³.STd ɲ3~d&ê2Á½u™ .OÔe.‹ã¹¼g ‚ ‚7ç̺Œ~€¢÷Ó~_ûñŠóë2Œ þã ·S—ÿÒòoÕ]êïþÖxÿ³èË÷BÔe‚ ¸iºùôßQ^#ê2Á½u™ ‚ ‚ ®Îùu>Óy Þê·"CÔe¦ÈXæœß•>¿.cKr˜Ä§§§$±JÔe‚{!ê2AAA\¨Ë,“,»\]&ÿË2gZx~]æëׯcd•øôéÓ9¿Êu™à^ˆºLAAWç"¿Ç4xK÷_ŠºÌ.þ ¦ÁÿŸäâ_æ×_}xxðŒs@Kºv¨Ë÷BÔe‚ ‚ ‚ ¸:×þû2.…,Ô>T]æóçϲm¡€Us¿û ß¿wñhÙΨË÷BÔe‚ ‚ ‚ ¸:çÔeüŠ>S—Y(…|œºŒ‹2çüJΕê2à€‚µÿòu™à^ˆºLAAWç"u™ÇÇÇÔTáŠÃ@¦Ç©Ëø_V]ª(׫ˀNj-ŒQ— î…¨ËAAApuΩ˸Ì1øÎ~‡_øK±¡.“ÿ¦Keàªu×ã¢.¼o¢.AAÁÕ9§.ã_iù©ó/™¾}û6óîë2W*ÊÀëü¼ÌÂÏ@AÔe‚{!ê2AAA\sê2àWôæŸñ/1­ÕAÞw]ÆEXûC-ΩË|ýúõû÷ïé¤"ÿ­«Ø€¨Ë÷BÔe‚ ‚ ‚ ¸:gÖe\éà-÷ùÔº‘ÿ-ÛÔtw\—ÉÿzîÚOŒ9§.óóÏ?3eL_ý«g.ÊÀà—ׯD]&¸¢.ŒxzzâY ×xˆ_žï÷k|ðAøôé)ºüß?ïø¦Æ#¹VlL¯ár<ƒ x+άˀÿÚp,x ¥¦ßü†½k=Èùu­é92)œXû¹dÙR]Ãd $#:¬ý(Í9uÔÒŒ¾œSN“ôq¢.Ü Q— F­ô³Ý×Ãô"ß8“_ýõñÁÂd1M‚wÅâÕôöyxx íÙ÷üøñ#5Í¡mŸéüú,›z ¼ã›äZñ;ÿ×p9žApã°r{šâCîšóë2WrXLωÕùu–×dÊâ9?I²l©.3io©ÏΩËíªg% ^BûòOʈ¨Ë÷BÔe‚<õXœ|LŸÿC¤$Þ=îf§¹Óx/÷ýûw»pôÔñÕî—sL½ÞñMGr­Ø¯_Ãåx6ÁÍ¢ïoéÍ¡qùÇ@nŠ‹Ôeàëׯì9 ‹àÅþü¿™r~]†9⹺K’>H²l©.STú¬ý,Ïù÷—qÙ–0iF·9¥eÍžœ¨Ë÷BÔeî=ë_ùUе!à 5 yͺŒ×˜t^ï7ĺ«9¤«$}ÃäÅŽ£ûBuä3_™sL}tSsw§ó—¼òMýšO]’kø˜š6Ö\Fn$ŒAÐäMv571ñ#š£¸Íçö!.U—¹ÿû2—%Y¶úw¯Êùu™ëu™à^ˆºÌÝ …™Ïtþ*°gÒV`rûÎkÀçÏŸ?}úÄÞ"5] ¿Ò¯1&Þ=nfÇ{MHZ¾opððð૽ù½)xµ !1;Oóú÷õ²©¯Àîç•oêלû^$ü‚Ë·Æ hòúO¿'¯›³&rêöü›^n¿S¢.³L²,ê2‰ºLp/D]ænx“Ìîþþ ‰ºÌ]ãéã ÷]}¥_o~ßor_ß,»œW¾©_svì{‘ð .ßZƒ I<ý \|á 5e|:ýE•æÕ;"ê2Ë$Ë¢.s¨Ë÷BÔeî†7ÙÁìîïߨËÜ/Î+òyü­¿^ÉæÝo&9»œW¾©_svì{ñ@[pùÖÂMâéW0ˆÿÏñ½G,ê2Ë$Ë¢.s¨Ë÷ÂT]†W#¶qùOT²™ƒÞ¯¹"À%É@±ËÌùñãWóW/ŽÕqð7Õé•«ErÜ%WËÁîË.’Ç ¾^5 ËózÆ«‹lŠÞT9ê/ #y°%kÀZv‘aé$£nw’ý}i©r]†îjÜSN%`ãg¢]€ÉÃxfwq–ÂxR6WvÒ»¾wäŸÍ¬˜]ã ®îÊì¢d,IMÇÁŒäÏÆØ¤Í³c÷]Žsr=…´m°†v"ù¾Öi4«#Œ“ðÙɽÌé™Ú|«;Œ]tOÒۈϦd$¡èGæááA‰Áz‰$´ !†PËÑ©d ËC¯‹Æ=ôÔm29pU®1DjÚàTí¤¦>¯FÈ]ã€Óta •*ÈMm2UØ\ÿk…¨×ë¨_yèΉCm…;ºÚKÑ|ˆ@=øØD@šÕåüû 袱 7ƒ1ùÜãt¡…¢mû9÷*”Ó7]˜ƒ¾º+?}ú”š*18ªü¦ˆºÌ2ɲ¨Ë$ê2Á½0U—Ñ 0Ÿ³rxa]ÉÔÏŸ?炾Í?8ÂÒÅUä9¦¯JÓб¹ühºsìŸüÅ®ˆÓZ-ÐØÛ?5]è­”øå¡{óMñErŠMs1Píoá]A=Ê‚¿l&ê.X‚¼&ê]ì`-ŸOiS8Îéx‡d¼wi‚ž$W3íœC3;€"á-†½¤’°Ì.À“ÈUNå/^äúsµó£““Î&32»x—•à»Ì(`¾šÏg‚¦ûP&4ÇÒÝ‘$6”*=š ¯ùU{¯ãÑ$”¶qæôLÍ3ªùLè¥+4í,ÜàΫ&\B@’žJùxþT…mEè &Ÿóà Å û —¼N\ªÓh,€æ½ÜË44ôâ#åºÚ»)Ä‚_(¬Ü)Mšhzdß›ÎÚ»bcÍ!™î½Ì—f™DnqJ‚IR³PÐ¥¦gg38šÜÂ6 ¥7¢”óÉqá×™[ß&DI½šö û;¹}¢.³L²,ê2‰ºLp/«Ë°2iI0ùÚÀ²çe‰ä!_¨êÍ(ÝiG†-`Þ×ÇÀq½A”Ýë>ΗR “ššðÕB¾ÎG¯å9Nr'РK¼-sUÇÈ» pìÝ3Ôæû‰‹­<Ç>åÀ£Onì`-/µù”mC=£S˜ÙÁÔI˜ƒ¿I.3†íí:.Fä8¶9:³=¸)Ôj=ÐT%qzs•S$iÉ‚uÝï$õ­*ØŒJ ØgÂN}{ÅÔ˜ÔԲ͙0ß o”¹ºïõ*2œv‰¥ó +„NñEÇ|&錅$ÔÕqæÐ‘ÓzÄfFqàchšß’Ï&n¤óŒ^RAñ*à’§ÆSyô¦vn22ï•›WG/‡«I®Ï¡á„âž)a—‹”«y…0–[ŒƒÂ5 ûÇI.Òyµ"8DD7RSç‘"ñM ~!à«…ü|j%`=E²ñS;ÅìøÝSÓ‰CA.„ {jå «y„ŸØÐ)äŽäCÔä’˜¯Ô¡5\± _•¤P àWí4êR>–ÈoÆ…­ozI~<¾rË,“,‹ºÌA¢.Ü ê2ϋضҰj²l+ RÊ•bYeÕWG>‹•ÏkŒÐÀò©Kùj4–—z°‡.ùbÌXƒâ›·ÐìÕ·pÍlørg¿$Ì(6ô]*ô`¤ÚeŸ^°Ñ`k‹ÍåìöOü&‰Áïôµ8¶br€I=yÛ_`¶ÇâªÇÈw÷"†j<Á8•€‡ž‰6,ÌlÙ€©ÅÎ,7 ¸ºd‰zè’§·æI #€So…GGçXtIM/±IŽpˆÜ¯Ô4 P_ìÏ-gÞ=5P¼i¬e‚o( fêSëi¬â“Sȧóèßt?SOŸ©;®%¡ –@3sz¦Ú$+ñ¸®ÇAá8H¾°“c·cÃn €˜ç—NEÞ—S XùÌTîp•ˆ–8˜\MMÚ£èT$‰!G‡Ç¿‚SµÏÜ/×£o ˜_ezä)—ßÎ+Ks—}G@ ë<Õ… –B@÷q3—\ð #Õ^܆h&nż÷ðL¡Rë668 8…ŠÙ±<¤¦ Û(Èçzf;`®ÐB>ú–’ë÷¶I'äÃ)ø4æ“•O.ÆçqÆ$_Ê»ÅÉÐWâT>¿Ž|‚©Ž|æƒö°žAzÙx_D]f™dYÔeu™à^8P—õ’,XÞÞÖW½Æ@Ý1_M‹­†Û!_ìsP(úE|5ï®ýÐ"ŠpsõÕ\’ÏCn PŒâ­½RS†\n^ þæ#ÖûHw|ë3ÀÖò²8(f“=Ÿ¯v$NË^—åh/Ìì€^~ú–©_~ èuÏïLJ­GG×ÐMïhÑÕÁp3Ø»ù¹6€Ïf_glaáZ&ø©Õ‹a޳"ŸÐ#°-5`\‡¢îh…‡’Ð ¡gvÏÔñÓØWéžš6œHõ-ïK3¥Ö&Ö¦xG*„ƒV?u©Ö¶ËÂpö½˜q»Ü‹IÍõÂè[l~•àP0bjÊàí—0¦“SÞBsh':nŠ¿íšÐQ¶÷” =šWóåÒññŒçÅ&aáù Óeí±ÃA=Š£W»©Ž|¦óiü\mf8Ó”ÇÁpš2ðÔöé!E³/8ñš^DzÝslF3øÂ ë`ÞQ—Y&Yu™ƒD]&¸ŽÕe+dXWz{”æìÍDOsoAõ6Xíš#oLó÷R{ZoÐ ¼sí`×ò}žŪü;ðÆÔ óØX𗽋ëÍœ°=½ý}G©åeôv‡º:9 b%Ö¢½6³k(&˜‘ÎO8Vƒô¶ï¦k“æèŒ(µµwޞ鸽ëM\ÛÖKW°ò<&k™ph¢¥ýéü„ì©ÛoDÛ¥Àrj8dNÏTëÌ9M_Ü«žM‡}`Lµqš^²6•cüð©»4]>“Þp½HÚå^Lj®Æq@¬¶—B9~¡=$Œa©©Â6/Ü ~y¸µÇ/8Šr€é áhÈàA}çPÏìä%cóøltøLçsä SSŸ\¸™êà‰(¢äø×5’Ayáš™7uFÒ©80éö‰ºÌ2ɲ¨Ë$ê2Á½pì÷˜û­(3«W:ßèíD7 …æÝÌw_árͶ‡ÆÞ.¼3Pjz‰—ÏÜ7ö¶Ël $Pdìòš¿šèÅßé\0p°=‡}^¯c]ã×¢½6³kôb2žká©™©4iŽÞ»ã@§Wo:‰Æ…ÞÄõpÇÁƒÈsš‡e-Ü‹qwMupÒùÆ ˜FN—“°©­ i*8£zÎ6•zÙÈâmg€µõfÊ:Må˜ 3ñ÷ëÅÆ‹H‘o»“¸æ—ƒLãx·Ð£w'Q?=löq]9ä3;ƒI—§PäöîÔ4ñDÏ|g*S,(’),ñ]|ëÛDªÆ’ž‚Áˆ·OÔe–I–E]æ Q— î…cu™t^á¥vM´ä@¾0Ó^7æôÖKi¬LÖÌb¼ß@JrÍì®l'Èô^A`ƒ"mÞâäF:P¤¦—Ð.: µµ9îxÈß±N ×¦uö•`à ÆêMÙndj<½äY‹öÚÌÎÃX¦“q¬–lVtÝo¢qÅxtÈ7£¾»ÛI¬RÓêÈg:oá°pšV3üV༠vçJ›Â¶¦1M§¤ Ž&¡´3§i* vSÙ—±õ»œßˆIM{X[¯ËòT0•“ãtùDsv˜®g9§jï¹\cU½.»:›Æ¸ñÐ*ÓÃI^øÛdFØNù/“ŠÆÌVÇ+ízX§†¨ñó‡ãÔç„ Ä4‹kA¾øc§çˆ#Îç@IS[“Iá¦% ÈÀ<§2èo"Ͱ;–,4®!¢}ûD]f™dYÔeu™à^¸p]f†|qbѪ ´V£«q°2Yó.…f,‘rÁ1Ûú•C1™!7Ò¼Ôô’A@dUa­Yów¬¬¶gpÁÀAÕ›²ÝÈÔx êX‰µh¯Íìò‡," BA­g+Ñ4¾ÉÑѽùæ 5e3ßwc3©raˆî©©…Ã’ûµ– =º$xÁhš-±Â6«í ŠFѱt@1}ÒV44M…AD³£ç¥Tò0xÍ(ØØ9S X¥(ÕÔ]$YÇj’CÃõ,ßu¹Æªz]vu6qã.3slgÊŽaœ;UŒ®¾u~še¿цÇÍÝB¼ï˜æ4åf£ªF Ñ»Zàv—"˜e&Â…#6/Ïa;gVAm+G–@ž`h`žSn†Aꊦ Ž$~¥¦;$ê2Ë$Ë¢.s¨Ë÷Âå^áÅ·t¼Æ Ö!­UÅèjDa:¯°æ]“š«5Âäï¨@GµKÉ€|—æ@5…A@šq0kþŽu‚Õö .8¨±0 ¿d725¨R—^ò¬EÛjŸƒ5drÿíŠHý³’è‰q¬DÓøš…ÑýX>SÓDªÌã¡‹{jŒgslƒÃ’ûµ– †Ý¿mõžX…mVÛšõpŒ)’PÚhOç-¸ŠLÆq ×‘§º:"€`fe Ïü1¶ƒÔô’å©äTö ÌãTØÔÚq]ª]Þea¸åjï¹\cU½.»:›Æ¸1w§IOmΡØö‚–c§ ê‹Ué¼âL¿h´ybòÉæ^I{ž6ͪŠÍT5«Ÿ‚Ït>„±¤Mã8úر©E™gHÚÉ`,Üœ;#K ש¾óò”CxÀÌc1iøÕ‹ä}u™e’eQ—9HÔe‚{áÂu$SÓ^czëPóÔ8î"«ïcþf äªfVЪgÕ Í8˜5Ç:á¨Úƒã)ÛLÍî¬E{mf{xܯ¿¹×‹É8V¢i|ÁÚèà hÿ퟉¸È÷èò×øÔ4AïQP`—9HMçÝw†PØr(B¡ˆ¶5)h:åøMBi¶i*ì¡Ù1Ÿ—­÷ e`7bËSió0©xƒ8n×Òù4 ÃõÚw]®±ª^—]McvÕÂ!*üm2#l§ŠüWßÁMq¿»…2ŒÏt~’ÊÝ·Ûg_ ²nðIá2ˆ°ŸœEXìB:Ÿ£§­É¤pÓ’æ/§—rk8þƒ?¢dw2·OÔe–I–E]æ Q— î…[¯Ëð.$B³ÑÁpÖ|è{òMüGæòx-¾q4Æêm‘˽YXóW:¡ù­6°ÚžÁÇS¶™OA/yÖ¢½6³=gmtA¶HÀJz[g ú.«ó°¡ÈX媮æÓç±è^¼9äNÚÖ2!°¡HNeŸù%\Pc:?aÍ\Ê•c¡õè3]8±–„Ò6Μ]S{Õìè—.à’@Rpµ˜‹1ùë·ç7wm*˜”š6ÐL‹.AíøîS·ÉÚp½øïº\s¥0‚]Cssfuç63¶ÆÑà ï±ò?7ÏsÁÐ…U¾› öH—й(Xð Éz¬Þn¡‡#PßËÊçª"ùèæö ²•ÂfðØtÌW äÓ…V eíþÛYϪhÄŒtž%3íÅRˆŽƤÖºD¯tÞbmëÛ#7µð+w95Ý-ÿí¿ý·ôŠ¯ËŸÿùŸ§, ‚›äbuðŠ³ŠÐp ´sš¤78•¼—FÄ8É«¥~!ÔUÄÒy¯ú€0«ãfÑ/´[¾ÃS#Ÿ6>×P¬¬ì¬„ô« Ø~>“ôÆònòý ú5D±“8ê/xDÒ¬ö:F,u2pPzPžÎ_²™¶;¶S–ó éòÑ^˜Ùt‘pR¡D-RUǤמcÍ…ñ9–ùÑÄÀ_‹ ®ÉÓÐcRÓÖ˜ßþ~í.1"Iž§7;oXË Íèß"—e’,^–,œÎ3Ü…Ä„Z8@.%ékI¨vÒy ^÷Eóó`ýŒêu$,êØƒ&Ñ 4 0ÇÀs`m*A‘>1›M_ªŸyê6Y™fû®ËMW½n3ü2a„ü¶EíÌ*Ó1w±àÆüE·~àRà@Ài’ÎP/ÄÒy‡£~©‘Oµ¤Ä`ò=œwïÔaS…©btÇ!·ÜÀÚz5/ ò9>}°ð̳¢æÔ,ß_+÷ˆ2 %…0WóÇI4C½I玔ÂÎ8Ú9MÒ{ä¦r,¤DL¦Öó_ÿëýË[å?þÇÿøÏÿù?ç3ßññgögÿá?ü‡t~cüëý¯ÿÅ¿øéäöàÞ™)ûÁrɺ ø5¾ zŠ k•.±uhö¥¥¹Ã“$ ÓyVßIÅâÍ:š.¼ õ˰SDCª £'Ñ |Ñ¥Þ"$5eh"rê½Î!]Òå ”hù—¶É]ÅÀAééMÙndšÔ–3Jºv^´Îì€fR)¼šÐ:&ãX‰ñ9 £›<¼ƒy‘µPgã.¨u÷Ú™&"‰žÀòA—æ}º– ¨ê T{ª`"ŸÎ3Щ«R¢¡›’P3§gj39ÍŽ{P"†ƒñºÍ'O“z~9u¬M%ØÎfÁïÆMÇë¹›Éó…á–«½çr“+…QxMïÄü\Ñhª¢±Noöõtˆ¦¼~:¦ó>‡üb*Ó…— ¡ùêAzNA¡ÍæÑ+5eXO1­‡‚|Îc‡¾M_·L-?sAo,hf`o¾ —±Òwé¼ÏÑ­ï˜^ü¢9ïA»ðÌdA®O¥ó µä¤ jáQ–Î[òÁùLÕeXrXæ‹•~ò¬+,E†¾Í)¤]ë®’4¬©Oöw%j6s~ä á¤tóèÛ\)i,„‘DCºÜ‚•’J’ÞÀ öRu/î„Íð_z‹+íèÕtQëØ2hÓ°Cþ ÆíE^öL7e»‘é‘[ÎAÞýüh#09³cr#ÁAà݉Ñë˜Èª^¬Ä®ñæèèÍÚkò9p=$X½YŸ‡æqÆZ¬™.¹S@KºV±œ Ø€%¾ã;›÷bÒÎ+H*^&ª‡Öi óI(Uƒ9…ž©½ ˜fGeV¥ó—ð`ŸI¡$ír1³ËS)z³0èàÀ°yG ׳|×å× # œ«R.«Ì€<€žA±­¸#Æòr™t>ä_ »…D  >³ãYëù"{zgyðØ)ˆ© äiß#7ìÐý(ÏãF÷AÖó5–'DŠg:ßù<Â@ßµ·—Â/Ô¥t-8ì=½R’cÜ€dH: ´ÐC:n&ˆµðc-o,NÓ…¬<Íã(5üL0ÉT]æzšÝ÷ô” ‚÷[CÝž<ˆSSdxÙ¼3x‡|¼K´³e"¸ ”®Ÿç~,ëöÑkÔÛÞ},îØàW÷à6a‚€„—ËU}þ´ýŒjœÒÈ¥ç§Kú†îÃöÓôñÌ¿Q— ‚  Ýžñº ÉÌ\uvk?GÁÃÝÍ={ôà.Pº¾›oõkŽºÌ›ÃD?orý4ßÓ5ÿzÔ›#eŸé|£Ù(4ãñÌ¿Q— ‚  OpîÍÞs<üï}ïñËÒ‚àŽÐJ{ôà.àø=½qhŽºÌÛr~^a1¯g¡Fç3o4EÔe®GÔe‚ hà_Q‰7ê Ç÷ì_ä°Bó<ÿúõ+sà˜]BfðG‚ ¸kôˆ=z¼>zzÛ»_ }:ÿxœW˜GÌëY¨ÑùLçÍF!ã™ ¢.A¿Tû×Pƒ æ©ÿﱉ÷ xÇè {ô`™?~°Lø¯Œ9ýk¿^AŸm‰z¿dý}û›ý’)”èçezÑ|@n¤ hþÞŠü¸ÍãS¿á[D`”ôî>Ææ1(ÓM»|¯ñèÅt LrÒjkr ›)]¤=z ™|«N^"l³h6 y]d]pÞ¸.AAÁÇDo€zæ“7Þ¯Û çô,ôÊÍ%Þ —^ä9H—·7Xxÿä@Í·ôæÛæ˜ÂHNÑlÛ8иl¦=ÿ|„Zò÷ç§§'ða)DŒÏs¬Jç6RÆ8PÔ‰<º$mÇ\å“c놫M•íéüô ê˜Ð¢q“Ðé‡òŠº’ù,ê5jwØ¥\ŸÄË9.ŠcdÌÃY%§"ðãÇœu ë§”à2 –HmÈk‚¸¤î « Ñ™;)qK’8ýûTº£_2Œè!ijQ—¹y¢.AAÁ 7@à…35mèý3™¼[ïç\¥KQ}àeÕ-¼L"Ð|Ûc#›¯£—×ãt¾¡×õüõX£7Ý„e«r“ê—vQ“°¨¥¨k`¶[ŠRÔ#ê-}0/7>óСPí]Æç‘ô\ÃcV¹s…"ŸbEØç‘¬JçƒÔ¬-„:ªÂÂ?^þŽ›L²ãÊ´qþ ¤Ôhô¢{³QD]æzD]&‚ ‚ ‚7@o€õKã·íX øéƒ¢Ž`¤güº¨ÚæÛæYÎëqs\ÙO—â´Ö@ã9VåCKU]p!Ãõ…‚WzNR× U‰]dR^XúùbêZ†ŠJr!¯×¨B‘—`$SÏÎ<ÒP‡Ô€¼öD@/u‡zŽŠ”«½®aО…½H¿f£¿ç„4èu™ ‚ ‚ Þ€ÞK)è Ö¯ÄzME²ù’L;WÇ…É4ß6Ç Œ”U¼ó¾Z —abTJàT½r.eUQ * =E§ùªÌ€SÅuË<² éü„üÊuÖ*掰¡ƒåØÓSr422÷ZCÔÙ%I2áœ"—T·’°WµDØò½ð®Ù(0€KÍ{!8“¨ËAAAðô^J7Éüåð[öw¹T¼4μÏÈ4i“zèç}v5œo•^˜{¯ßÅ(Š-]tÚãqû£3›bˆñ c¤­¶¡®a?9Â%]•S*Äèg‚Ôn–c›óùô»f(¯kãà Æov%¤*÷º—nÂÕ$·i0Ÿ W—Ûh‡tò^„¨Ù(äommp>Q— ‚ ‚ ‚à Ð`ó57Éúå]½lªzÀÌøŒL“‘ÒÉË025X+1ŽÇHçÓ:Ç‚bŶ®‰ä¨ ’Ÿ·¿t ú•™|ˆñ cz6Ôu™¼E?„Ië7zêc³Û‚¯_¿ª¼"3<­0ˆÆèRžR’{M#-žG#Ib®ŽEñåû÷ï §.PÄvH'/Aò|¦óf£¿µµÁùD]&‚ ‚ ‚7@o€Í×<½dÖïíÀK©^¹yãU‹N_ÿ÷˜fÆU šïÆ—²jP 3òÓú+Œ•çt¶b<èÙPÏo3ÚÃ÷ïßuU•‘üW·È·›åØ6QíÃ#Š^ˆ­Ú i¡=olú ’ÌQi+:¢ ÒÉK$_„¨Ù(äommp>Q— ‚ ‚ ‚à Ð`ýÒè×Úâ×FLñ>¬å¿..¿¥ËȦòÁ¥[[»C㥬’ª¢6 ªKÅ ÊIÍX1‡ºežžµºù“/þ½*‡QJ0ƒP£izq&Q§½ô£è=I¿[ò«©½~MgŽ4z¢f£¿µµÁùD]&‚ ‚ ‚7@o€P¼‡ëÇüã0PT4žžžðÛ¦~tŠ÷|ÞäýC"õûê$2²ù.ê’G]_€ü‡M$Ö,7ÀE¬RÐj;õSy0‰ -˜”IÕndXQžü ¿W•˜Aá3ÿÉÕã ø9ŒUÈCjÍ\Ógj=!/bk\ÉL¨ p6úgvŠülæ IB#äa÷\¤ó¦½˜£‚ÂB×yB>[Ü™#ÙY„¨Ù(¢.s=¢.AAÁ 7@^õ²Ç)è5ürN#2¼„Ó›!ïœêB»@¯èÀÁ¦æ—âµ¼8‡.t콋êGuÀæñI#æ•)‘öÛ¼Ú‘Ij«\$¢‘«XÂ;¿G)^àÝŽ©Ë`ZTP±¤$ˆIp©h™GÃéSSfê ‹]ÄRkVÇlN­'d3šÓùAäÆ0_y ód—äÂÓӪ׮Ñ8P pª¾K¢O—xò9’,A€;Ë1bœJ@£Ð¨«‚Ó¢Å0"òEˆš‚!¸Äˆé<¸Q— ‚ ‚ ‚à Ð ¯y.µŽiIBÛ»«ÞQ ùû¹È_}™üZšo›cld:¯@ 7^ТWtƒÁéÚ ýª)«xm–ÂZêŸªØ iLÍ$‰KÔeòЍ‹2ÂbtIMÒÃgñ+ . ±5³ù×Ôæ©ëŠIÒX"“ˆ›dDê|²T…IN ÄÎ2e…W ý@:y‰²¨Q³QD]æzLÕe˜xæ ¾Ÿƒàõ)4ÁýÂ#%ž*AÜ#Ú‰ÔtWô,ïµ÷8* ܦÍy§­7@½æÞiiÉ+29D‰«€˜ßK £”Ô2\Z›ý?~б7¢ùúõ«Íë „ ’±zQ§E§ó ¬r `œW–lƼ¶¶Ž!§ã!z¨š mÝ@ž",ù™ÔìX[»J”Qó°M2EÍÈíÎFy¡«9hÞFh A⯫Œ DÔeî‚©ºŒž½é ‚Wƒ$ŒT|°>1•Ð|èAÜ,ŸNÿ-UÜÝ’¤ 7ï½öÚÃ=Æúøj|ä¶&å#¿æ-×eî=Hoíf|—êÞãE7`‘~ÍF¡'Ôe®AÔe‚{‚$ŒT|è‰͇þíàïä4¿Y‘ã^éüþ† ¤¦IbšâG©°S¤¦iÜ×ßp0?~Hf׉A:¿¸óùóg–Hóðð°ëã÷íß|ŽI¢'Àú.ÜE(œÂ£â›oþ®æ<©g‹$1üé9#ÎDûÐÝALôì‚;]’pYö¯C½öÚSÓÍsÔÇWCyõ1·7š"Î?šý;º.…¡·v3¾K5ê<Ú,»œêwëŠôÓ]É%¼:³žrÊ&áƒß°×#ê2Á=AF*¾¼9¾å/Ã2² ÆÞø9‰ªç­àõ8µ¾„u1ILsæ Z„â¶Ü#¼~‹™ûÅ¥gZï÷Õר;‡KƒÄ®Y½&ß9óP\ä>zzz*&ËÐn“z2rwr´¨M­çŒ8íÁÐ_O`’)V¹JeD]½|SóÒkï˜äï(G}|5”äk«Æ½£I™¿ /ÏݱÔáj0 Ð}t;V-ÀºœìÛCßKÐ2úú7£»].»mx[ò‹ŸØÍFáG%ø¹DLRÓ[ܰ¨Ë+°}~býüóùß„?„ž ‘Šï?ñ‹•`ïÞÊ:-節$årÔ(š…Éð™Î§Ék ÐÓÀ È¥šÔ­2ÎÜ^ä+´(~†¢‡ßcÍx6‘OPjzI®mÒà]°Ÿ$”N@¿ÒrË¡s$%€|¼zÕËÜÝÚ%Ÿ)Ê#àXK¿¶1_ Hç/é㸔ºmôÄγbbþîp!iP ¼}œQÅÍØkï˜ä阚nž£>^ ½l2M‰J6¦ó“rè6¼ÍKÍ+&Kô¿«à¶Jöí¡Pǽ'ÿõPÊÍ:Ü?¼¯áµðv(oÔ[ëtaC-¤h:ïü›àL¢.¬À ¹ml^{7FF*¾RÈïW¯¶ŸîÉjô9ûËùµ ˉꟌ˜_ùüŽD RÓåp(Ø ú ]"yÜ™œ¾£°Úf"yš?wsˆ?~Ø0êAÙ_:DÐ÷h&;øM/…­ªmf\Í`:oqÔ) Vêâúðäˆ † ¸¬¶·ÂUxÑkï˜ä¯š™—娗BIÎg:¯Pj ‚ ‚÷MÔe‚¼³yåÝØîÎ&¸Rèõ߈ÆFú¿NÈåDõÃV¿¾ óßó;JRÓåp(xs¶w»?¸äW!V“Ów4«íùšýÊÉ®©“¸æ‚Î#Î ¨¨ðh&/Ü,GqòàWjªÇð¨S (1"3ŧŽÓµ eÔ®Ø$ÎÏt~Ÿ8£Š˜ôÚ{ &ùëeæÅ9êã¥ØÍð÷‘ZAÁ2Q— VðÎæ•wc»;›à^XH¡Ë¾_Ͱk¤ŠŸéXKTÿø€~jਿ#¨Ôt9òPøW9vçÎ’ÄgfúÖ"àZIñƒnßµsz ˜ñ^OÇÑL΃Ÿš.Li9yŽ:š_èî»5“#.6@ÚæïÊÛÄUĤ×Þ1É_/3/ÎQ/ÅîÓì}¤VA°ÌJ]æû÷ïlši¶ž»¿eÍ6Ëò@ý e‹%4/®öd°ŠKiŒŸfƒ~ô׿ýß=tŠB}.8"ªˆ€ºRC¿cÉi³Ýø×ÓyÅQ#‘ÇÂ$Ý’×ø•ƒƒmüDz I@Ì^÷ gÜ%ϱÝM…QÚÄŒ M°ÄÓÇA31¢æ%ÁUhþižÝøC‘¨G˜ƒ™FÙuDÈ[‹…‡nÈ=rΣS)”;ÒãÙÛí7)Ô%jžåyL`2,è׈¤¦— ¹)°–¨ø%mºß ¯Ng‚ ~GªÔt9òP0ƒ“JLö8Vƒ×¡µ ¬À³Lµ\0d‘tršú`‰„±­xÚÌ„"g7ÏÇC,‡ë¨SŽna>u:[19âQÚhg¾NEÊГÜÏX ·•ÕM¤Ç»—ZviŽØ{è¡¿“^{Ä$OÇÔT X’lêXåð6—E3)øˆ7á’lnúˆm“z&gN †“€N×q›\jgBAÜ,‡ë2,üZ]rd«N-,h/EIòÙ[YÞÔ·Žå§9’“Û ðƒÈrœ„N,ŒÈf¢îB‹–[]"bœJ¬h7šhzÔH,éÉKÀSÐÃÛJÁžÀæ0 ¶%¡ ¿üä°/ñ_và3‰îAÌ›Jf6:†ˆõ|)2vl$zÔÑQ5»ñÖÀC7­¼Û4oa ±é— Í;ºvÄ r~7·_Øš -Éè…0µ™ù=æoÀB@Ô¶)záȦ{öW™©u>E(0I§ƒ}¿íg9u¬S°?4컇»à›‰Ì›×iyEÀÌ„"g7ÏÇɃÍk/¢GR y8>.>%°ËäˆG kâ)hRhî­¼ …,ÉeH^ókƒÅ®Ù,»¨íØ\ ìN¡¼×Þ1É73“9õƒ¢ ¸£¹¡Ô>˜}/Åæáè6càcÓZôŒ«Eczyä…"Ð\¦dÍ|¨ƒ ‚›åX]Æ{_ŽiT»¨ý^°%ÌÉrˆ/6äû?/*ÅÖ ¡)`3d!£@ÞX zØ`¿×ñi’ÐÆÂˆÞvjñŒžÔaƒS íÆƒÖ; _š42ßYžIá’ж}ÎIBle$Œ+…ypœD3ò½½„OÕ·h€Çâ@N;æùý–{aaáK|5ò™Î_â4ÃÔ´1°§ Ÿ[œ^ü;˜fx}!iGò˜“üIôjiç…’ñp:4$éŒqλ;¤ÐC/wŠbh´%¡lPàØ(LÒ{X[ÏH4K x(i8>ÓùWþ.a=ù£²G/µ.BЙЉ‚ã 8VõÃJœüÏñb›­˜w˜Òivñ-“{»¡(ØÍËàbÞ䢙sÔ) G¯tž=üë§P“ÉÖD[‡t*š;`h“š¶Žui†F.‘'–Ü?7îšwat’ò‹ôt©PÞkï˜ä阚NÙ`2|º “è†Û{¹gr…mºTøè‰³[Ëq:}Qb{@§"×,i<ºÔ uAp›¨ËôùˆwçP¼í°æ!ÌSì§Ù‘Xa®Ê›òÞ¢5†Ï\!Ë{{”ëRs%«ñC¡Pñ™»¶6¢]æRÞË °ÈiðXE»±Úb‡±`$§4â{¡ ÷YàÓɉ]Ã@a„b“B›]äŒÓ‰¾yÅ1kŽÓ…=įbpØë™jâ å+ˆ@ž S{F:ÍBjÚ˜/Q…§ Ç9U{=Š#\›íÉ®æÜþàŽ¸6Ÿó¬°0ÞØA(f*ϺÚÇãŽs I3zÊ&½Ôºu(ìþ88N6¿7}çGÀCˆ¦aË8óáíu±ÜD£¦xpYwY’xÉÌ7ƒß3Â<ž¢9v {RS £¿P®¨Û›LŽh1šzëFUX˜Î_"û¡ùŒÅN Sævf˜3ˆ•¬…B§3j²½b’§cjÚðm[,ñ‚Õ\þò™šö~'¶®æÙÚbtѳ¡é£/R‚iR»\àÉB¦Žo©]uAp›«Ë4W,/̈¥¦ ´T]¼ðÔoMÞ/²‘MMÙÛ]±P™æZÞÃŽ4E±6âÀ/aÂNïzö7w]kFzñn–r v ³¶t^Q °¹÷bß68„B7©Ê/ü3›¶±‘½ûŽvã¿{Çy£–Ûàðözy[\(Ppèö_Îù¶¤y{Ž·õ媧 BA/ÏË)õ;˜g3ïá{¶—Tƒ¦¦»‰qu(Æ—Ù¹%ãé»HHQIÂ|ð'qæÃÛ›‡¢G!ï¡{\ÐYbX˜‡òÞR’ã^ÍùÍñ³¨~“ômÕ{näLޏíâî#mÍ€ûñÒ|Cv°TÇçqæ!:ÚÞ±M}éŽïõ³Q8ù@B}§;ìyJò͹M¦ž»™T_c×Z'êÚR{(ÔAÁ røïþÖì¾ï5ivñûd­ª¹¤yAê­7^ÉLM}, Þ1šÍQUؼY÷ y8ØâŒ5;8(LMóñ·¼HMVU‡—KÛ 4°€ºµ9 ±t¾¡ÆA/Û3ð¢ÀÚ©œI…»†åXg HƒÞ¥·á~úíjë¥ÖEh†×/™Í'sað`ú.æÂb>H×.#0Þ^‡‚’D7¬çáÊ¿ÇT€y6ÆŽ[{RSIöfÇÓ·ëÔäˆó†Í00~f .IáÔ´!¯‹ÆÐÿøøHÂ—Š “¸t¨½‡Ý¡cjÚð$âQ äý(ÂëB^^1ñÐ'¥%w§ç#7—Ú¾¯Î4]Ëaб€4 –Î7ìã³Ã-,PÌQApk\½.ÃJàU¡¦îâ¥1ÿÖ¨‹· 6CñÚФ·ÃÈYQÐ…bè^»±=ùc9,()úrÚü‘Ú±aŽä Þ|ï: »‘¬Ñå÷’ð*ïq}›¦Žtp°*5˜Œ¿5 e=«ÅáÝ¥°\ª’¿…;ã ÀÌtÔNåøêX¡ ƒ¦’ÉÔslx_-Þœ vÝÏñ[ÇçÏŸ±ªÆ6J¥€¤Äй¸x-夦 {ꀸ>R|Ó{0}‰€oOfÇÇ…µçà"Ôä´‚ƒ6Š&½à¿¯Ña`À¤S®²!¿Ím‰ç.ß4™ñh´ÇH[3œ¥ƒ¸$™Bƒú¢<„¨7PS˜äŒšlïawŠÄXRP”?sT•`³XlÑ™®kvpêŽb7þ‡Õ‰°ZòÛ°Iñê+Uƒ@ÉßÂq€ž­zQP;•ã«c…2 òz#Å®û9¶|—úNÌÙM­sè…·˜Ûý^]Dx0}çGÀEùîÚS0óðŸÁáœV°_½—Ïf&×,çá¥ð,|ŸtŠUIb»ìÆyrÄ£Ñ#mMÛh܈K’)4¨/ÊÓùH~ÍJ¼ôûf,LâÒ¡öv‡Ž©iCöðùlDŸºR—hÕâ=!¾¨Eä‘Lê:äÛ  E›>ò¸`hÇ8žŒÆÇ$W RKHC‘$V+g{DQ&‚àö¹b]Æ;9Úëq³‹Ðp m½wØõŽÜ’Y5{;Œœµ½p¦ó F”Úbè^»iÚs‘°|Ï ôv6MÃI,IMì: »‘Ìñ«òE­¥IUä3FÊ(2slädpñ·†Ý@ßgÂÛd7P«pgX°G–@3±ý¾7V¸kXÎrÐæGñ[Ç c…k÷Ý$½PäN¹5ä{mCoú. ¾Ó}û¯sçP2Æò¾ Å8“k–óðR8µzñ‡I§“Æqžñh´ÇH[339’§¦ …¥hœÁwÔïÞΜ¤£í=ìN‘™2©¥]о~°›^$w™ô‘áØ…y©Ù‰òg ÍÌô ‚ î…+Öe¼Z4 ´ÙEø&¬Çœz{]oÑü½ bÁ^£·ÃÈYQÎB±;7Þ(Cû§g’¦òÆÃâ¹(fªg°ð‹ާ¦ °V½šY!œTé|ˆƒÓüU,]=da1oÚ3Ö|h7ÙŒÿn¢z§žÛ`UEi—Ý@i¬Â5Bž™9ãj"K ©Ó ïáG3sÁH!÷gFñ[øÕÃñÜÔˆIf&µŽ2…ç…çUï% zÓw~¬!Ïíü}u²Œ²‹]˜¹‰±z:z¡è±œ‡—;eÀ ¥gœòŠÆMú<©¼èã<Æ£Ñ#mÍ8x º>bzÏaå*Òù4Î î‚Ԕ᫅ïGÛ{ &ù"3åŸÜ†©io`tÛZ•®šµmÌûÈÞõ‚ÉÓsÄ RKHC‘$V»ê ‚সz]¦h4ƒ«Å[e~\°üªÙ¤·ÃÈYÑûŒžfE¸°IÍ@±/Qp ß4\6,¢0`·`äY›ß+ìn³\¸é (ª=áñÕIšJÔÍ“¢«EH{ ¼g8rå]¬Üôª-„åœà×ïf`gÌK©i¶I~ÞH¡˜Ì„Ú’ã;Å–ªN»‰qƒPäù6pÜ3^Lß™ðc°Ö`›/?‚`\ëñ*ó%ªËyx)ìø ’3NùéWÇ$Çë 1LM-&Ãx4Úc¤­i˜o„ÁMjcŠüQ¶p5OãÜÿ%¸Â÷£í=“|‘™~þ'º‰“lñS½¹™QÐøœßfÀ!dÀ sÄ®@3IÎ uApS¼ÆÏˤóŒÝWS¯4ÞèôÞ£<Êù«fo‡Q°0¢÷ôªzHáÅÐÞÜóYì<دä cŒlîll@1SŽUoýÕÜNõ°Gõ8†€I©uˆµÕAÈg$5 !Úéè%Žs:ßpz×¾{“EèæãïàCL] Ø¨9 ÜV©iõª¶–s~€£×ëbµÍÇq“©|6£]³;b”Î;øý³ˆ^M^uê¿{WžÃ ÎRÓŒ¿g'¿Ï€‹æ 6ìè ö°h®,"87ýj†bÀr΃Iå6xFfà”¦ƒÏtÞÇW<Är&Ãx4Úc¤­éB~#4«$ÍŠ¹PǺ}—Anà¯í)|w¯ÉöˆI¾}þ¾n"³ùôF¢(c‰µmFÓÇÞïÕ¼®­moz±•^§óŠf’œê ‚àv¸b]F½ _ºxCó:½…$©ÓAoÕô‹d½cýc¸É媷Ã(XÑÑàÀ/,¨nõÐ~ë@ÒA`\EÆñ©7 jŸ4’$iÌ_x˜,^æ (ŸÞ0ååÕB-pŠ0ÕòK¹;úL†0®z1P^°6˜T…¡(¶†Þr)5mxŸŽ.Û±„Õ(Ðãwºsêv5š¦a†ì¢3Š{M âõp¹%öË9¯^P[ÒÃéa…|æï?KŠ`Ò×#6_à›`›ºÌ)4Ÿtl¢\rJÌTÊÏž°ÉÔt9°YÊ9HMNTÀë<òÆöcgj:;N UK’ÈËèVµNìÏÝá˜ìÊš+W3ÆÁ¿²™OìÏmÖƒZ£s5µ¶ØuÊ“U<0›ôž®9“a´ Ù¤9MM¤­ ›@‘ÒžD¨«6Š?ÊÓù4ù-€#©u{J§È/™lï˜äëÌô3§Š¥hA 7¹~,ˆ^´×¶MäÓù†cXàq'vеuyd0€«=gAƒ"–ÎOœê ‚àv¸b]&GB€« I>uPtÉ‘€ˆW“\6XItÈ`‡Q€rIÂäˆE4„Né軚5U— uË:zXo¸ªK@—gû6܃$šùÞ”ä8Éex+HJ87#ßJÀjAíµ¿èHtJ”´£¢%Ia[æ¾xtµh IU=Ô{ú:8 cöˆ:FI’> Ëp |Z§8a îEG®Òˆ@:¯P_ÄÒù‰AÎsÀ(:ݽÝrr &]Ûð­ºZxç=ñ Ê78d$ä#6Q¸$Æg³QàCjáÄè œÃ8ùcª÷€UÈìÌ8ÎÅ«WŽÇ=4õœº†S‘Î7·¸•L3–óp›$’?™G­ÝuÊOÅâí· U 3njª˜ cáZ“Á(Ò6c fRSÇ} Ð7Á#¢„cðp¾T„È5ÙÞ1É×™™¯¿`Û 7/I¿$žËVºP±°ÍhúH5æÔõ”ùêd  ÞËqÀ@éòDjÕ]Ä9¡‚ n‡+Öe€Å,_-›3Vé,ù›í`Ï-Xhë€F†`åNrC;Œš…ó „Ñ«‚7 Í¡ë0rªŠ;67‡ŒDa-LKï-‹}³&Ñ œ®@&ŸÇ„{¯Iù«µ@X9 ëz–ÂH …Ò!UÍLTõ¶eµã–*N%)æãŸ'jþ35f`0ï$Ñ—0:“Ü s)W4ÝÍœÇ`½„ëR=â€z"êqI•zP ñÐX $£{6x›¡«É7ßu)Ž*<Än(ìrý#,àä<3u™¦ I(1hÆmî;SÍ4ƒÝL«C1f9ò¦G4â¬îÙ»NI9Ÿé|+ìm&ÃX/(5G­Ë7æ@ßbÙ5’G ¤^PHÜ|‹!rFM¶÷°þffn±yp?æ½Æ·-Wk÷J0 ÉhúȱÓ) ÍšÌã3ÏQ'†6rb7µÔ·™$ç„:‚ ¸¦ê2<ÐY´ò5¬@W{Ï}V5Ba6yƒ.Bj!ï¡—mø»[É Ç —Î÷X± ޵‚r –wd³•"›ÓI‹CFæÂÅ@M,?ÆM®JLŒ º$ÑÍàÔºm>vý­Éâ8µN„®á¤ecœ½{‘K;ªšáš‰?}‹lé98 ð…±zîÈZHçº:ˆF3çAço7c…yn Y2b2,5ËFªcÍl~<Ãä\Ì+<„”§“ ]PËZü4Øí.1Hç—)Ã6¸fFÙUäòð(Œ’œÙÜb»NéêàAQ°«p>Œ0oÕî=hòÇ2Œ‡Îy3jè›Fz9kÒœNNôVÒ^ûÉ2“iÊ—˜y{r'c‚Øä6càc¡¤g'îh ®‹>»à—‡(ô3zÏ0¡«ƒ€¬…:‚ ¸¦ê2ÁµaùÔ2ÏAj ‚ìÌ"[‚ ‚àõñ¶|¿N<‚ ø˜D]æ&ˆºL0OÔe‚ ‚àõñË<îý~}A"ê27AÔe‚y¢.A¯þ– Ÿé<‚ .DÔen‚¨ËóD]&Xàûö×ÖòþrŒªäÛ4 Eâ­xßÞÁÛòuûŸJñLAÁ5ˆºÌMu™`ž¨Ë 8mÁ{{êÿ^hþË’1tIož÷í]¼-ú›ÁQ” ‚ ®AÔen‚oß¾}þüùÓ§OñÇóƒ]ØF¶G‰Ÿ—ñó2ñó2AAoNÔe‚ ‚ ‚ ‚ Þ†¨ËAAAA¼ Q— ‚ ‚ ‚ ‚ x¢.AAAAð6D]&‚ ‚ ‚ ‚àmˆºLAAAÁÛu™ ‚ ‚ ‚ ‚·!ê2AAAAoCÔe‚ ‚ ‚ ‚ Þ†¨ËAAAA¼ Q— ‚ ‚ ‚ ‚ x¢.ó®xzzúå—_Óy¼._¾|!¿}û–Îïn%Üá¶JçÁð1'—áÝÜ}AA‡¨Ë¼+~þùçßüæ7?ýôS:‚Wä×_%ý€Q— ^_~ùEi6(@ÜÑÄ}ÿþý"ÅÓåºÌû»mƒ ‚ ˼+ô6u™@™Q—9‡¨ËÜ ï¬.s)¢.AAp¿D]æ]¡·ñ¨ËʈºÌ9D]扺L“¨ËAAÜ/³u™ïß¿?>>²oc¿k8ýòåK’x‰„ýûêìSŸŸ~ò®ñÛ·oÈÊ9}zzâX2Ÿ?–Œ˜Ÿ5žt6yxxØ•)ÀfäÓÀCÇidž$·po£\Déëׯy_ŽiÑ¥IÐÆöš¾:ÍC » ‘OÒO{ÌL}NÛ^¸Š„©­íuDŒ^Ì»OS‡Ÿ~ªr4?~üðscy.!D7®—Š„aæQ§y0¡ö=ÈK¿ßµ %¹Œ£þB/òk/xL«nɤkcœ«$º1ˆa“I ´çîìÆ¿…µk T»æÜv–Ћ«¾­ Ü»¯h‘SÅ”Ñ~ô¾6Ÿ«˜Ý‹¿,·_Eþsµ×±F·½”fp*ŠÈH†v.L\á#ªŽF¬pk{7EÜñ¦B Q…/^Ýj¥6ŸkaUb~ÆÝ±ÖAA¼çþÝ_ïbÓù o¡·{Î÷‘ÅkÞ$Íѯ7Ð3¸†—Féé {úÞÐ[sG‰!ŠKà×õk…ßš;l¿u@^5ð–½ù¾á^“»ö™©÷«C§¦—hÄÂñ8Ø{íõe®¹Ö^{¯Y§ª¶ù_¾m.A@3'šÑë2Çrá€öðñ¦ˆ7KsˆYg][XÅÚz³]ÞH½VÁ¦Ï劦‡›¨HoyGÜüM1@½eGÔú²h®œÔýtkoqœì—1ÆcŒ99ÇÆez¯zwL;äˆ^Q¼¹Í[¤Ùú ž‚·U^êí—"ãøÎ*zoÒJoFº€«uGzÈ!©!¡ IÜ,¶²ÊŒ™¡—1<Ñ)vD¦·…ë =Ýb¯œ é´¸¥lîœ#ª*Y8¶J®®û¥.÷f¸fPgP/zýÅŽÐzI:ª’U½~-²ªe.ç÷éù_¥z!íðSÍÍ‚šÕZ‘Ò,âÝ”J-Þ,‹3$¢Ú’ÁÍá4dl›7»jžŸ3ƒi/äÉr~ŸÅ+ç‹"òðÀNu?å‘ÓÊy güæß0ÆcŒ1æ´œ=.“^#½WÒyz­ë4ý”Ré½p@D™]˜¤çE/õ:Øc1¿ZÔ»»v}(Ë”šU~›zXˆ 3vÆ-èÌ„QÍqºè–mNÐîÀŸ±Å„âP=Ÿ¨k)˜Åú{VéUµCdm³ÅmýU/š?êÅ Úyš}WlW{fŒYUÃÿO:Aî„YÄÄhÃa°Dó-ÕÌD|–ó2£w³ÈÍ’Ðý8R7-aOSb„¥ÆîŠÈ˜^×À¸ÎæÀm»),vô†iPVÝOO·Í#®‚ƒŽcŒ1Ƙ³²..ƒÝÞùðö&øú[¿>êÝqðÒ¿ø™˜o½ùƒýÞ®¦3ƒAšàuvbK#A¯ªE/¡,®Ö챘><4øM'h 6)—ç\13ôª“õ7a†87djLLÐ ¶¾è–ÍN?ò`ÐÓf‰È*VÕ„4.„é)Q ÒôƒØÖßq@Õö î{÷,ö((zU逃ÉÐc¾ú¡¶¨¿±íù{¥ˆlˆ!•á9†ÃXKÁ*^*’"&MÛ"Hg†ÞhF´¥{›îÂgŒQÖ6'ÆN®‘åcÆu6£D€âMÊå9§-vô†Iºz=Qµ)Ü«JÈoÉxœcŒ1ÆsZfã2x/o¥‰úÕ³÷ Y|k[W&^R°&~c@]Ã"¨™¥z$o,ziæÍ>²˜¿~WÊ"¨6íšÌ ýØK‘¸k•©ƒ C€Øú¼[©ðúõk5JpšvS)ÀItŠ—óû ¢›£°­¿ã:ªí\ƒÊŸ={6˜ͪà¥XÇ)*±Èd ̳Êÿšÿc'È™iìØ">Ëù] ³iÓSÄ$}ƒ£i[DvöF3Ò³6ASA¬“ec,5vWD–Œ×ÙtŽAå3+ábÇAo˜0šì>5ÖhTñš¹#½ª„üG¨àücŒ1ƘÓ2—áû%À;"Þ ñz‡79Ò{õì½Fp‰yzï‘dCë€?dÚØ+óÌ+5@ÎUùõÆŒ"hvâ}švjï„ã’ûÀ¢—l²˜ üæ+xLÁñ€I?Ì ½|Ëš{¬Ýjz sIZé–Û†ûôœ€i–â 1¢$«X*êP ÜÁ Q¼œßùYmí¦„ ®êï¸N€tfèœÐæà·ÉË»0Æ}‡aÈ>Ù¨˜©alŒdÁèÍÿ±=¸Êlqž-\Ü« àã)V›CöoÞJ<MÛ"²“5‘µ½ÚˆŒ©§Mm¡`©±»"²|`̸Φs”ˆR8Ð[‹¨Ö}aމNkUù 9KÒœcŒ1ÆsZ–ã2z™ÃK[ý×y{¯ž½WÀÈâ{$ØÖ:Àn‡ùsE¼Åò¥–§3°r0è‚À&Š™ÑJ¿çE/ :Ød1¿ZÔ¾N£€²L9’ÅNŽÅ|¿ˆLE%©B5¯ÚžÊ hTûêØ Ÿ4awzV 2nq[U§~€ŸX[­|¥Ù÷]Ä/© &Æ€A ü?é93 ®‡ïï fà ^4‰)ZÖj6m‹°f h¢Ì½ÚH´M°§)1ÂR‹-fŒ×yÌÀͳØqÐ&FùQ÷ûBpŒKÍ?“¿yÄOÞqcŒ1Ƴ–å¸ _.Az™#½WÏÞ+`dñ=lkðu–WõýÿôÓéÚ4¢lIê£þ6ûÒóÆ¢—Æ¬YÌ_wJ[»ùVÆ,v °E¾3F†[Ö}› õeÑ-§u‚œ,p—fæR„VÁþr~9¤žuì2hŽÂ¶þÂí¬³9ÉìéœÛ0î{DQÑÉvkz5Œmhú¿7 ƒ¾ÇKhǘQ¼4 hHËZ)Ì 2sŸ 54ðpχìÂÀìï æ„,ïu Œël:çä+ábÇAo˜h‰– d#Öàæ€l#ƒN¤3r–¤;ÔktWÖŠø˜P†qwŒ1ÆcÌ6–ã2@ïd¯e@Ç|#ÇAÉzÇàPàóŒ_s7´.ôóO0È6 m"¨0Fh Á%ÂcíÕ“7½4ófa~|^ëÓæœ #µŸIIj}E¢ÉÌГäÛÒ^hJÖš0èBo\Ћ’;0鯵Nˆ6”|w9qPw_Ó€0?(ç- yµÙ) ‡4ï Ø’êß6èuµ¥`¯ö NÀµuhöž¢†º*äçUPrSq–|}ÖÖÀ«Ñ†ÈÀÿ¸kétl-ûNêœ3ËÚxn€ùûTÔ«J:E†’5À¾ô쬤çä&q±±#ã:ÎÙvS4Yì8X¢â æ8†µ%÷q#Žã¥H¬G>A£%ÉcŒ1ÆœŽ©¸ À{pz#DÊ»wïð†ŠcPòÝW:¦×¯€—˜§÷)Ö¶.âOž›ñˆØVBp Ò+AʉclÝñê p ’7½„âÌPΗ`~|âÆÀÀ»uýë`‘º§)(ØÜq5YìTÕ¢rd.À)QOÉt*d^JÖâƒÂœ‰Un\å„43NÑœ_rÜçææ†Æ”Üp š3Š—8 5ã;ˆWÕJÓ?«úKp+Å"¬™¿‹Ä{×$#ŽÙfUü6MÌTd†U5 ôº3ö?ÒœÇ  ©ïY.kd›m@MÌܧ¢/€S$ƯWD˜”ó ^íu¤Gò-¼Z.×9éœRõH™;±Øqг ±Åztàg^±ƒGŽxê2Žã"Æ[l~ŒcŒ1Ƙ³q‚÷9RΖÒöÊÖõ ÛÛ*O‚â¥ù%J¦>ª·ÙÌžï~ì)(©çŽ*(©¸Ä¡ŒåüD¬rÂüÜ%÷³ÎùvÜʆA/YOáù8JÒ%÷š‰(å¨a’èÛ³ŽõCRús $=4àL#¸á¦8 X߸Ðõb@ïîþ*6>KÒ‰(]muSw7³×cŒ1æÒX—yràÅš/¸é§©æ)‚ÝG³÷acŒyêèË2å¼Å™â2ÆcŒ1æQØy\æùÝŸ!˜ü‹æ’q\Ƴ{—é}?åæî¯z¯ýå/cŒ1Æs™ì<.£*ú Ø;ÀqcÌîÑ>øàƒú¯ö¼ }¹÷7}Œ1ÆcÌÓbÏq¼¿òåÕ?TÜŽËcvþ| ÁñwÄôù¿@lŒ1Æc.œ=Çeðë÷×=Ḍ1æhþ3/‚Ägýÿ~eŒ1Æcž"{ŽËàÍx¿¿î‰W¯^½|ù’ÿ’Ùcö ÿ'd«ŽËcŒ1Ƴ#vþ÷eŒ1ÆcŒ1Æc.ÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1Æc‡3Æe>:PN‰7oÞÀ†·oß–ó3s ]>9é@Û÷7Ã=j¯š§ æði—e®6xb–scO¼§Ë¿`s$˜® œ˜Ä Å<çŠË` Þ;ðᇖ¤Çàý÷߇ |ðA9?'è)»¼§ÛþÙ³gèÜèµìÁg/† $™£ÙåMj®s,ËxJ²Îrñà‰÷tá+Êü`s$~ý{,¼‘\ÅB\óx¯_¿fAxŸ7™ò(<äc=e—÷4óøÎTwêÅ‹ð-xùòeI2'EwÐã¾ôìl wy“šk£·,ëÄ^μ?pµyþüyI2Çqù ø%L<³ ŒÆîq_QÀ«W¯n·÷Á„ŸYonnp  +j+׆¼yó­”b|€'Zl~#ËMz÷î]I2àÉÃrõþ9¾@‡!¸}júõïÁÁ°ÚóóŒâ2ð ]9¼ŸÊâN`Ê£ð]Þó½Û‰ŽãÛ+DwÐãzxgí³Ù½eùX'î÷rþð§jnÆž¸üü&žÙg×ãN-l༠,ìíAPP N¥Ñ™qA\J1…s,×»$å9vŽ~ý{,| ¬b—ÁM‚U¦†þå<€%‰eá}æ9ÇÝ5L‚ óØØå=ß»”þâÅ‹’dNŠî ‡™½=N5ÐxËAUିbÊ|iªñƒÙìLòµÓxñÖ`xb–óÇF²_0¦$ÍbÇŸ4‹ë*.Ñ¥G.àçƒ>ØÄÛ÷|8!xÿ¿X| oÁ×<ä v½)Ø#JÒÚÂwïÞ)½%&–¬÷Á+DZ(I‡Äx?¢Z¦û­c¹ñææ¦$¿þ=¾V±úïËh„£KR es\æIÓ»ðÔyùòåä>Í&o´ssª~˜u™÷;>Ëy…Ìfl¸›o Ö9Èð0`©éý:À6;þ¤Yœ —ÿ¤~à‰·ïùpBô¬¼ÃÓ™ÁrþôÞ”Þ¼y£8/H‘¸çÏŸ3¥Òjƒ›‰Í‚K,'ÝV777h…Wãýˆœu¢i‚QÃ|;GPøõï±ð-° ÇeNÆ.ïyßNÅäöTx˜‰´øÎí³Ùî¦Å[ƒu2ÆÒX˜öPÛ¤ÏÇÀæUõ¤ YôL4L7 ÒQ¼îì­³úkŽœ¬»£fÞÈÚ†#bÐH³FÊkIín^Op€S¦÷€Ù±-5„ã4{Ì߬x›Ž“g@ò Ž;XCÃê9–Ò=9ßñ<¬¥x<²¸„zt³À?,cÒ<Äi¬Ìx&ÍØºÈ¡ËëªüPÎ[ æ8pãáFæÔŽKɹ;7R ž¦ŽÏT˜ìoºwf>œõ½kÆÈ´µmBn¸«B©Ã̺ý  C· %Ó:Mð=Zµ¾¦"õ§Ûg‘Å7%Ô™2¨ˆfÝ"°Š½éÑí²àârHsæàþoÒ› ó.Eý©—bs·^º[Ñno¦¥WP”‘±!øyM§'ï#‚‚ãH®kvG+Éx òl œr5Àç|¯‘3Î"”¸÷`õc¾±ðq •FE`ëÝÀC«E0‚zVk|l NVôS°6 NTU2ÐSfhZˆÄfm vî ]*I÷‘stÿDdÉàö‹ ¿*tµlNtwo]éy{à]ÁÖ™×1‰M4ûE^[˜qŒŽ0³ÀUT³ráÕI0|ÍŽc‚Á<7†{J¯M ¤—LÕ†ƒæýšÆôîSÙ€X’Z ,³‘fgñ5¨ç »ƒ¼6)Íž‚µ>Ð\‹@saY»‘zöÚI'$çk†4çëpP’ÛVKÚ€ñÅó ¤ô4¢×ëú 4Q››õ€žµÌO5Gd°b4›£Írõ¢ý½Kâ¼ehǸm›M3gÍ©n t‡¥ê9¶Ö“ó'Í.$6_Tè.ú$Ù#ã±¼£¡fµ`0ô½+³ç×UÃÄæT‰s)Ñë8+dîܚʼn7¨p~âõ²f>Ó{×¶»ã˜ Kê²¼´ˆœÐ#ö­°æ™»2²í¹V£E£×AKÌ ÿ4Y£;KÒ4êæªûbñP/Iwh]©A͸Ô,[#³lSë<©S½Î*QNMՃĒõ©«È©"L·F„õéña p ú5‘ŽD¬z(Gµx™Q„ypR)Ô£Óx¤w²Íÿ ë ¸#z ì>cÙ’õyCo{ø¼mï¾ñ«fµœXPm/ÎüØOIS8*A£±G8.™: +d €§$Ç13 r C²šRàŽ >ï!T@ñf%"o”":eßQCÉ}@3JÒ}Ð.3à $ݱyµD†x ßZ¹4y”E€J¥—˜Ž 0ƒ¶ÅÄɧÉIÖ€ Rõ”Ü$–Ë¡›,…O€ú®L ž˜ð”ĦQ?¯¢SÊÉvy â +NxkÈɵOXÛ¼'ç;P­ò ¸ âMToÞh>£»T9óð’ªU"@»ÌQ…™ k‚ùu-2C=U6¼–Vˆ<îÜ&(È"õÄ‹Ö÷骉‡KH×%ÀS¢n☗ê{yÛ{×¶»xÙŽ™8e:‰c –*'w”LpŠ ±3Àò’;°í¹ÖdþÉ»/g¢ESRû(ÿ¼a†±ìâr-T¤é€ÔßG| £f6Ó «aÂÔeåø%S¸‰Êy­*¸åÖÄÈÉ”™¹Íþ‚4JGm¨óЕѶEéXJÒ}Ÿ¢N5@ÌŸLª‘Ñ™¹òÄæpP¯r¼ŠÌê€JÔSrh*a‹*…O€ù[àš9{\† ³fnrœ*‰B£‹Ki9ÐÔœ¹‰fÀq¼‹bô±žg*˜žè…ŒO÷¤,¯gžj«o¼¸ÖÄ •ž¶@ÏlP;°9|–ó>ñ¥Õ–ÔûÝ$©S½Î"ÖþD65”Öë^O5@Ñ0¢ÖY§¼ŠšU9[Ä¥´ôÄéWû–òÙÔ»XJybqõé%i‰X$úÕ² RñàAu¦!@G˜ÎšQgt‹ü &gµFÖE˜Ì–÷R=ÝçÕºGhh浉°wø,ç±§ 6Ç ÃôzÊmðyž‘pc]ƒLš_ˆâÐD×!›šæg¹p@3¤žoD®;‰‘›BÞFÍq㘗¢yj™|šÐ*4óë >£Ô¤—¤;Ћ€UËòÙPÎ+bÍÈû¢Ò8‚Þš„½9¦ÏIO)ç¨JÅ“?q©WœîâU wEä›Ä;´$Ý/%WÃ'HD…åüN™¿7t Ôdü`à@mF¹p –Eª³¾s{¨ ÅãÄ‹Ö÷é¶‰Ç ñYÎõ½ŒñH£@š5o0ò˜ Ipuþþí¡®}(h Áq¬\½«M*˜îޏÄMš 1sP€*Œ>Á+G4Ö¦…=¡ÌõÄXDÔ÷`Wš3ºšÏ¬ .Ý|/« jž|°j˜X- ÒáøŒVÑTä)çw¬]›Èì4¬ŸåüŽè„øŠ®¥ AX Ÿ%逪Ú0@,«æ`L´§ ¯'öSyc¹f".SÏÝÞÄJOw;ÑCnqRÍX[W'}I: ôúF˜©¼šÖ•J3OéÍÅhºÇ j¥ösœèµµ~ͼ©ézŒ€®‚^§æo3­eÉ«ñr`OëKj4-'i=ßÒ˜æ%•ÈVw\eg&g¼êªÒ³¤7ý&¹ª-IP!K¦Çtg¥«½Ö$lMà”®üugZ™Á4iö=gNz:Ý;'ñy ÄÌí)kqP’=«äêú¡ɽ’ú.zÆl3R¥Àü@Ä»¦ywcþÄ»O™Oò49r=©mÐX †’t@ oóVÕUм›šÈå¼BÆ O]­Móö„·Ð$¬çë«<  Ð4¨ËMÔt7©EÐÛªõ& Pñäj¥Ÿd]²?ePzsà€Fü$wîucT÷B W£?7O¼^:Qµµý²ÔÅÕñxƒl3òÈ ‰Új7öîßj%©‚ö´>WŽk;­eþzȼī05Ý2ÙpŒ›>ÊÙ»ÑÈ“e9jƒÞ¢Ó3k›KU ¬º—é |Öƒ4£‘&Ð)B_¡ær~‡|8¹06QçQŽÅ¸È%) )‹¨é˜(f¨ù20¦÷Rs½‘å¥ù;ZËKÓH]nŸ+äìq™^6 p§æ³-ÒœñtóôÞ¼5 c•*çÍ º…ÒÌk6A:3¤ ›­hEÐÚ—ÖSݽæ"‹¶)CêT¯³4%ÒØ±‰æ<Ñ$Iæ©õñ$Ðk”éøl®hòFóE\#2ãMõ´ Mõd¤Æ·÷Ñ4CÎïyL+5úX’4º7ch(›ÎQgçß›høÊy…ºÓk¨YÃ6Ÿ7‘ëf¦îbwê ã7šgˆ\×¼{Íf†m¡yÒ|ü'Nþ4@kkשÍõdìR°vY KÊy…îÐæ nozœðÖj¥Ù¿Ê“`ÜqÝ/½iß»aå®™©X#ƒ£[N¾®‚fC€½½9Ö3F®ºs¨ éMF(C|ìnžx‹æ53hž¨Ú™÷® F?!WÝ¿÷”¯6¬oø,ç‹"½®Á$LQ^Í^À™”º;4 ¤é4ƒ†f²,ó7»/—Æ{,z¬™Aµ­º—·=X5L¨mà‡fß{kÑZÔßùA”ÙiþhLë[[]ˆ³§L,çÍ 2u–¤ÁæêjeƆ;ÄÕ/¢ óž¿fâïþ–¤ûè‰Ç©™QµÈY’†ô&Ÿà-twa:N–JsWS6?¹ 4g­ñÎ皈üÈÉRÈV®`â¸9¢ž2Ë?iDšƒœ,Ò¼¥›Þnú¨õ™y“^£c@ÏDV¥6ÑTOÏW!w%ch!>Ëy…̈/Ž=çGš5«¶Øe%öÌ5c×é6=‡Ì0 YÃ|µ½­E„µñ"¶m!Ò;SZ"Íîôæ›PqP’N½ZFšF²*ÐÛçDNþ4ÐsÂØ9¬¦KSß#òC¯k5“uö2ôz±ÚU·†F$:„4[MO’±…ƒ‚¢YƒÜÕü‰ñ"rKA%žj]͆Žy-iViºkÀxâ¦[[Q©4ñ žð½«™©<~B–óûÌ,Ô Ù¶hI¯Îf_6?2z`DÜ‚"‘’º´Âc 5èe›Óô¦ývg¾¬º_Îõ„›]ªÚVÝËÛ¬J/n;ËÎù…±ÉbkdvœÃ@±§´hicqümÞéôèÙ3¶s|Gã³$U°w`Þó×Ì£Åešwˆ=”¡”2žd@˱ì”å({h°«ÑøfTJ•¤¸Êlõ«ˆ«×DÞ,o- ãç™±M†ÅNfg¸„. 'Á’Ê"8.9Й±¢w 5jµ[àØƒÖ\w¼—NzÞ ¨–WqP’úŒ«Hg†d -dzeˆf¨¶m*MR§bbo(À0éõWudÞaðYÎ+šÝ‰ÐÎTƒÍš· T[LŒ  ®&#™8(Qæ[#:(C)3Ç©Öy5”¤‰²|Æ„–$FXç C³/Ldzeˆ}ìÑti¶. ⳜßùYhp2”2˜Þ«¶bMCsD/qϱ®¢ª:ƒÜ…â%©…*¯%Í #k=³˜_[ h-ò+±‰2$g2}ÐÜ ß»dMªQ)÷âRÉT¡ ,B˜ž#l ÙÊù²$902®SÓ,Ö ÄAY-èͱˆ*l‚Úbc@ŠÎÀ k¹†rƤlXU–f ÅúÅ@FÛ6»TCÜ3 qeËù&‚CÅm”¡”éL†–M-nX›,öàÒ̶Ð¥=Sã¬Sß‘ùàž¬ DÛÐh¸§øÆrÍ\h\f,O¥Ìñ$2CvÊòââØì‘ÇîRÇe¡ýø,çw)¸ùq¬%@-ª¹ø"ÕC=Ø&Ãb§@³³äÝ»wx;¡MRÕ‹ôNÃ7¡: ZO çÀ’ºãÌÜsHÏDV¥6WΠɘAw1´¡Ú¶5MjºZ9g¦Yì/ÀLˆ½Ã1†~Õ£YŸå¼¢ÙíL5D«ÆL†“ðÌŽuâ Z\L€†l•™„l:õQÍ¥ù&š5o33)±‡¦Ü"“O³iC“ÚuÌÜs©¼×ti¯P×zÞ«Ytëdhö…‰3ÌÜM‡fëb±`¯_š‡‹¤ÝE0ç1»hC“8‚Ö®«ê`Ì Äž?‰*^mV™ôŒX̯ÁÖ\šHÇæÕy˜²ö½‹¥f‘ªj‘Ô…E7Ò˜èÃ1²$Ž~b\§.Ö ÄÒ3±‰*„1hHÀ¥3ÅŠÊø\`OÁä#>¡š0cô“Œï?²-9|³Ká%&ö £åiR©;‹DÊH4Z’ZŒ[œ_› ú»vÛÐ;^Š!Öì?ß-‚J 0sNšƒ¨Ä^) ÜÜ‘«âBã2xò!ÀæO˜kÆ“  *¶ˆ¦Èr”=4Õ%Þ),{¤Ä±»Ôñ´è+÷*>yÊåI¦òu0Zz¨øÀ6;š8Õ*€Çbwë¬~àYß‚,bJ½3G ¼šZO fcµXF†ÜÂú‘X²ÞÑK'ª°Ù.ªåU”¤>ãªÒ™!C ñyèG—4‘T.•¤Š¦IÈ_'*çiã2“!=q<.‘sÊyE³;Ú™jPµ·ží³ö EX3Áq\R`¡ÒYX §,…ƒ’T¡î”ój.Í7Ѭy›‘),¸m ÊùM¹S=MT! Àññ뉼‡JÒÄ@YÒó^Í¢ëXç C³/ª–~è1yk4Bš­‹Å‚ø,ç÷A~Œ£Ù$­u‹î˜ól9QDSQïôqY'8Ẋ¶ê Jìù“¨ò8|Í #,5öLd1¿7ZKÇâóÖ›}ꉧ‚å¼…:~ä{×#qz¨ûô’ÆDŽAC–%½:å¨XƒÝ’=šÓã0¬êÑ@÷‚úÇ„‹¨,L-IK¨lÀ1 «IúÍ.E ö £¨¶œ`"Xõ`•‘H/I-Æ-Î/ŒMÐ4ëIýũ܋4·¸m0†—p«2E …RÈùhŒüÆNÅ%…ýEbÉzG/4Q‰½R@–lëȵq¡q™S Þx’½éÑ8ÙÁšftëŽkëu\Oº‘§è¯‚ÔAž¦E¡ÇLO{†5; ”¿~z©¹4%8°œÆGp©¹eêµÌ“êJØVÝñ^:éyƒÈªÔÁ&㪀ܕŒ¡…ø,çsôœ‘ÿù2Jš®<«z,ö7·4½á¨YtN³;Ú™jX¬ö°DÈ9hBsµ7ƨƒ‹º³Ø\³æmF‚m!GõJEVe^ä뉼·Ö¥ºÖôëdhöe±ÚU4Bš­‹Å‚= 5ë‚cÝ…I¦AÜxµGðëj³¡c^KšF=“X̯· øbCßη"f žê½k¦­„Ü;?È¢“Í‹ÌX2®3¤®A‰ó–Œ9y…€ýšäº7W&áЀÞ-“çe†@Uulb³ÔPÏ0Zžº¼¶;DF¦h¶¸aalÒë¯z4¿m! |ò•@v¦ðŠ*9ù xêo,×ÌeÅe¸E“‘òEÆ“ 0 yâS&iöH~×F3ð™î½Û± ôOìï=„Óp &½§ÊñY’*z·Ó¸³M‡ëjœòöëׯÙ\xŠÑ2°T²*¢®5†Wk;{é¤ç "«pP’úhÑìeî9SýJSeLÓù‘ÞdhºZ‰õc¬ÇØuM0pkK5»iv'ÂS ªv•ÏWQχm ‘z“ Ôr~ÓÓ|r,§]-#ÍÐ|˜YâNû4‘ÓN¸ž ï·öÝwé1Ëò€É:XCꋪ=É­Ñti¶. ⳜßG;ðù¥Œ,ºK3/ë%)МÿJ<áºÚlHîØäº8¸Í #‹žI,æo>+›¶Í ‚å¼…îAηÍï]jkÞÈóMÈØ£4ÐÑí‰qšf±†ÍŒje¾k‹°_@“\fƒµ èÝ2 ¶Îuã&üY^ñ~ o{°j˜ÐhIjÑlQv®½)Íþʰæü›­@ n[œràêQ8ß 1Oôåš¹¬¸ÌægRM—ælèÍ'%Î?MAïbm Žs“øÛ¤%)À Jpw±ªèÒøNÀåyʵ ƶ¡#Ê:Õì,Ž™Ø|ÕÕh?ëA+'qu„–÷fiïê¸Ç4Û•U±ƒ=4Õ{ûg½Œ&cŽ|(öº&{R†¦«UÜU’–Ðl0d53á ¬Z¬°YÃ6Ÿ¯B.“‡³ŸówÇâ€VŒ:ƒš+ç÷¡g@šÞ*uÚ[¸9*Õ»k"§}š°›éãRÍA,Ö.ËšþŒ,fhöå´·FÏ! Ùº÷kóó¢»4W›ÿJCWãªóÆ,®«Í†ý Ö¾–ô*‹žI0?èM!™[Ü<ñ&ÍS¶cÞ»6y¾ É^ [9_ã`Hãžã:5ŸS ,…ÏUŒje¾kc`•,,I4š‹ ¥~qh@ï–‰¨;«&ö6—n»—·=X{“!ÑlQeSúZšýUåóÛ¡»fë¸é–3 ж؛«½«ãR=o°8áË5sYqÀñÃçIÆO³¡Y¡¶¾éFһΪu§×#µÒóÒ™¡¹˘ÞûˆgÆã’m(^’î@+òH6;‹c&6mP7ã”Ðû ®â–F ±Â=WGh<>Ëy`0"cª ÍveUì`=ûA½–ÉBŒÑÛRÏÈ&0˜¥@]P¯ž Mž«•¿ÙY<¹ÓŒ;´rtùafV€ñ^wkHÓf›Ï›4vt#Dÿl[ˆä„ÚÕj¤>‚ÞqB¦jO»ZŠæ@èÕ4ß`æ^9 ‹Àäü ªÊy@Ω§Kõ¦ ¬bÁäRU¸vY Y±Êá‘f_Nxk€žCÀ6O‚ÉŽƒ8sa©»4Ãk“`‰1Y¥ôºX»®eH &-‘[&ŸbÑ3 5ê•G›ÀTáæ‰§æzö““¼wm3RžvBìl‚þ¬שÒäÜöÈè1cgí‚Þ³—Xaº×4šmõ6Øè,Ü»ŒÌ,5žrDo†øÄí€"`q3ÿOa {kóÐTw¥"ã{Åë…±I³¿2¬94v=³e°¦MóÍäL4@cTÎ2µî2K5]zƒØ»eŠhìÀ†Ž\!—Q:Ʋ~H#3fÀ¸éˆ¦&?ãsN3 éi[·©È–ÖDœÂ0Øžš½i(Û Œ]*©÷ÑVD½(î` jbÕ³<Ú†ž–ÔÃþMÍñjo˜bz¬-Žº n‚4%â%‚Jîóúç=WGTmìFVãjŸ£Åf:QÍveUê`8µ”Ç1Ÿµ1ð 3àRý @ 2€r~³AAy-ª_u[=W+à•0­#1U…ùÀÌHgf|Ê$‚t¿ã*=€Ï’´„\§AÇÜ‹.êuGÀ \­[d§2Lú¼ @åø,ç`${ båÛ"¹ÄKqÈ@ÝGeÀ% ì‘Ox5ÚÕR,.Å ÃVÍ‹=Š™ š†Á(U·°r ©Ž\OtW&—ÂiÑ¥%ubY ;Uaº5ØAÔ\Î+z}шàÒ1·è9ôZ'ƒ‚‹Ç13€º82#­ã $Xt‹u"O&-k$ Ú*Æèn¢‘˜< VÎÌøÔÍ Taj(Î1”½C[ì/•Ô;z –x&¡¶60ê5’Úz±¡CjˆJè1PÎïXœ‰ÌF/ÕÝQ7¹ºï]ŒD"‹x»¤Þ±yBÒTd+çKh†àS–§Ut\gï®ÜöÈè¡Væ»&_¡õ8(Öâ%¢Ý5@qœ¢uSõ+v™Íä)IC4EªMÏ<ðSXq)M €Ú`Ê–óHd‘4‹-«ƒ²Ô\“fQ•\û‚û‹ÆžÙpiÉq ¶œœi€Èx4W’žÔË5sqq ù0œ8%Z”¬K°–KWYÂSд0¾<1¿lLO=Âìä%ÂÚTÀiÉÚ"æLp vr¦~‘ô¤!<…UXõxœ:Õël¬íÖ_X¡’ßtK«Ýšx«ƒ«FyjŽ–à“H)¹ï襤ßV×iWV¥öˆk8u O¹Lã 6¦.ˆ±4*nôº~íÛ&ÞÌ| ªl~ïÚfä9&$Ë"[9Ÿ žŠ8ˆíŽëDÎCÑÓ<2z¨•ž5ѽ€‚r~ ÷ÖǽG²§LïÝ25*Ò£îìC>…/d84u‹ÚJ¥“!‚ê²díÂXÓëoœì`å:˜=iÆ9hÀSc¹f.1.pUƒA"ÚÅ„+ù–`%´ó&Õ‰ÓÁ–ïÍ›7q!ˆ `½ƒ÷ó–3C¤YUBï+ Ž”ë;`<(=joã”ë‹Æ1ujÐÙ¦Ÿ‘¨ ‡CÐ-¸„ª"ðXìx©±«Š$KƯJl´vó÷ÜÈR ý¨ŠÈªÔÁ)$O‚¾ã*/5aØ»î@"ú˜,„£x¶¡l=±ÑJÓ™cW×c Òô@=ê*ggÈ?¸C›Ô&q&“qwÍ@ å<°Öç=³®)ÑΪ­Ç‹ Toõˆ÷Af®œlŸÌiZGßq‰§ÍÁ]kä‘Ñô!Š4 h«Î Ø+ÒääëÉØ¥µÙ8å$QÁž÷šŒo vÊyÅ /§º5´Æžwœ`Ð5([W»è.Rß(‚‡øxkƒAÓ 0XWŠ0±ÙІגq…`Ò3‚ùi3<“ú‚Óz°Ä¶‰73@\ByïÚfäÉ'$ ›š€aɆTÿ¸Îñ]‰Ê뻃 ÚÞô«Q+«º†»&u iX۸Š<ì{uÖSE õn™„&Œ„—PJÄ©[»h­K¼—Q¼é$¢`z°¢ ^mN1nqÕÂX3èo]3N‘ˆ›—éƒ&äsäìÅgÉÉhÌSc¹ZVÇe< Æó0¦u9¿Ò™¡œ·Àò‡‘˜d‹&R(^êªþQ|ÜHXgK™=›gz”j›´°fPÎ{­ Ê0ÄzXs9¹cÜÙ^m´3N =zBg¬&%iÎÕN¦%0&¡¸N«­Ó‰ü\Î+ÆW{ÄyýÀæzÆô"öô܈zèFäaJ¯ÑÄŒ«£ ƒªˆ2ד=Õ´‹UõˆÓ/U²ØÅ!ž÷ù€TI튚ä00’ HÉz¿ >;ñYÎ+УR,Ü2`ì0oäI"¶íl;àÔP®­!œEU0µ¶]ØÆ qIŒÄ>â Ì‚ådšXaš·‹çÕA_PytØpk°•Ú!L?‰'V¡æ!(ÒkqÑ]9Ku÷oÃÅâÑ™‹žTæØX¼Ñ,”s@ª!qü›`þ8·e bz o~>r~õôLFT^r8fBòj¯øØ©ÖSOëd†Þ] PVA¿\›†­lèZj½îàä”g·grÒÂr>õ¤Wµê?Áç]z’{9:ÀþžYÕ`2€™ã}4s‰qa¶ügM˜«²^8#qš!º M3‘sR§‚ÍÕé‚zÞèù°`91C¶ÄeŒ9|À –3ÜÉ«–<ÓDnÄrY’̵²—1Æc̃Ýŧ³Ÿà…~ºü²úª”1p\Æ<&|À b.úé¿g¶á¸Œ~«3Æc.ŸÌÛ»¿XäU^~¡2§Åqó˜pEÍHóÍÍ–¼ø8³ÇeŒðk„1ÆsièïÔmà5˜ðjâן͹ÑOŽã_Z0æ—1ÉËðOæ°QÄÒvû‹‰~ˆgwÄO #q\ÆÇeŒ1ƘKãÍ›7zõÅÁ|ÀWâ‡ÿ*«Kͨyx&3'Çqóȼ¬þC«Þü?L1=—1‚·>˹1Æc.€›ÎI#xpû-îBxs÷OÙü6eNˆã2æ"øèðø3€œþ*¸YŻÿê|¶ô Í5ðòåKÞbåÜcŒ1Þ~ñ¤Æk0_‰ñþ†c¿¿]#¼TÿðØœÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1Æc‡“Åe^¿~ýᇾ|ù²œ?)ÑøW¯^¡iòæÍ›’º#àUt .çfšÏ cÌÃń«J9$øÔóÊfÎÊ£¼{n¯K™Û|³½¹¹)çÆL Ç„—hcž“Åe>øàƒ÷Þ{ïý÷ß/çOŠG1þ£>B‹hWþ¼”9ÀëûàUõ`ÎÈ_’æ@ÁfÍw_¤³•Å7cŒ2sö~¶É ¥É0£™y³çQaÉÚ'uDfc¼Æ?[¸B•$`.mŽ `ÂðBU%éDœ¯æsÒòÍ^=­lOÎ{»çõë×õ»¸\Ÿ,)œ*°¤$­¥xš]ÔS‡%kpÆè1á%Ú˜‡Çq™[Þx¼ëÖ½÷ðT’õr´#þÝh\ÔÞxOõÀ¬èõ wDÉTR½Í?vûƒ‚ Þh`ÛæðÅ‹œÏ5H¯70rÂâ­­œµ[Pm¯QP¿voó¼2&u$6öäÀƒÞd˜‰Ê%4P¼$ˆóÕ|nô½8!χfÚx˜+ Ç¥æ±FJÓl˜±\XÒxÍíÞÓíÁÀ£ fÀ‹?0&¡ûÎA=cž©¸ Vv¬ï ím"|íFžrþ¤8­ñ¨íà­Qmzêýx|7Àèæc½Ø=].ç o¼§"œ¤~êë¾@6¬6è;ˆÑ¦7à«X-ŽÑ¿ Óãòµas¨oI”¢mÇJ,YïÐ¥ÅM…r¢Â’tàÍ›7êÐ)6о0Ÿ%ëÑžHtEíy9ÙJé-?Ö ’ñ”ežÚª„MˆT9RÞ½{WÊL€ñb ƒÇÖ6ÎWó¹Á|鸌¹G\xq|Xc>ÄA¼7KÖD«>KÒ¯_¿F"Dlqõ´–óIz?Ð܆÷JÒc€·Jšñ䨽ÂÇ(ç'â|Õrþì~{r™Ìì¸ÍŽ™ŠË̼HñN>ùñ0œÖxÔ³X›¾G|?~èÁÌ1M.ä o3½ŽGŽö ~ÇDo“˜3õ}œ¨³~ ç3Lë/­ Z<Þp5N™5-¡VzMÔÑžj”3 7-u$…ž„UåüŽ^£σ ôIô¹P1p…*)çì¢Í«lèrou$ç«ù¬`vÑ“‹ò|l›iæ|`)àˆàL§º»ëuïahÎUÍäÁó‘–Ÿpš 1¢¹ý¸Om=5¼¯¾ϸc8Gµz {ñâEI2‹–?"¯Çen9­ñ3kå“v×*è ¯/k¹7¼Íp†ƒæ+¬6ÛqbèU{Õ ÞAQÕàûØTÄÐÆÚ'ß¶'åØ åLÃ=³˜$Æ6=¶uPw·F¡7v«ûˆ±cP¿Ì<ºÅ'äùØ6ÓÌùнÙÜÆkÎ\Ôxɪ´`F´:•ó£,bDs{`Õ¹Ñ*+ªy`Î4"稖r/Έ‘WŽã2·œÖø™µòI»kô†×—µ\ÂÞ1p†ƒæ+ì›ðñÉD™ï²~¶Výlpí“OÛ€U3yì„H³ï2rÕB1n´éy°Ö!Dw·"U+V±’qõ#}°j MDÓxqBžm3Íœ‰¸ ”¤ Ý¡Í[ûQÐL<,hö §Ù`#šÛ«Îl¯¨æ!ÑTÎOÄÉ«ÕsÜÙGÄÈ+g!.óâîŸhp–àþç)‰_äÆ)3ð¯ÑHÁ)yþüùâO²XÇkŸm°¥ÛÂ'Ú-ÕèUˆ"Ñøúò¬ú'uU¯_¿>4^|xJøûʃJRžæÏ›M~¡™‘­àÞPY$2@ñØÖߨD©äCä\»^£»YΰŒ•“fHD60˜Eš«už4Á`B²­±kèU¬aµ½oÐB {*½á¥@NaÎidN{ÇÊQ§ÌK¸«ŠÓþÞ+,ªM`Sz^ªQ”¤9Ö>ù0¾«ò“E'åŒ &á«’4Áσµ!¬Šæa’°ðjd`U¬dÀڱƌE£ yKò†E£Çó›AͰ-¦£ÎÒÀÁSc0çÕ\—ˆK¥ðï6‡ôa= cKЪ- @ÎñTa÷·Í4’F Àá=3pûÜö§ó>€ôÅ%´GZq<˜<‹ä'ÓªdF……X¶Ö ã’ДhŽ;AÌ3®YïUÅ®õî_Ç(—¤Ös“)è)Mb—Iª™yÎSôôÖAw †,'³~”b£<%èTÉwЧvšZ5ô¦JÙ€²%)@ïÅ*6·Ø®b,j ë™yŽÉ@’W²õËC­Ä90?z¼{÷½+ÕH–hQ刞’ºk( SK]­¶smµ”jÆi=jHDm½!€‚hzÛ¼j®½"iU§+T„yrÖsµÙk‚âȬ¾§;1Bò縃`Òÿ4pX‘§=*ùó+ƼëÌã²—Á€q~4‰3ŒäÇR…1f†.Õï‚ó£×РTH8èÕ©I‘ñåüÌøža¥J¾¸ÍÊ…¸Š<ðX9o{ 7Òª&°ª¹¸ÐZ´‚ª’媜6°³Xx5‚K¼ÿ{ÝGú¡¦)XCò»+5¡ÌÍGaCì—àJIJ älv„õŒ}Xƒª˜‡ÐÕdžÐ ÔäD[,Kz“y°˜6ïAÒ,E8LÍ¡ƒî×Èí½Rê‘2èîÀ¥É¿ðªJzÏÚr/»¼ˆòƒù¶ ”N(IÔÁ”>`ƒçÁZ‡V…Ocê†c`U¬dêd ‹9‰zT»NÆ$š7oÍ föéÈÓl%¹ ÓÒ*V?¬*l®Ió6‡a¼šFA ¨WE”ê5Ô›-=Û_ãØ+Û:‹ªêǺ† ={Kh´U ßõ'¯‚Á:ŒüÍÇë§sR[i¾m—­öõ¸ õ"Ð €Ï’¯@óY9´d ^’OÐ4UŠ)ºoQüÐø7ÿï ²MŽ`([ÎÀrU…NqÐÑ"Úe:ˆkœ&IªGÈZô¢$b[©G·ãw9.^û°‰ò—ó€\ З’z‡ÞQbï`'ó#Qˆè¥æCTPDólÀ%ëlŸ<@NØŒ¶¢¯p©äž€õ4]’îÃjñ©¹$?¯•@ÍÌŒR%i•ï”z„æ&ß] ”>/IâÌ©G­Éb£µçÁ‡UÅSY‹È1°*U2€9›•Ô¨G=—â€+à<Ÿì{¯f@ Q³:…š‘-Ž#ŽKîòLo«ª8^˜,àm4AââÈÀKèBI:t‡M,’%õa_nuX«eví4¬“ªWv}óù/•KD U!PL/¹ï@)^‚Ùy€²<ÆAÌŒz¬—&Êâ%©BmÕ3*¡Úêg¥žÑ—Ô:‚Kø,ç˜ûoã”éÌS‚K%ÓU¨™Æ,öà¾cý¬ð”ľÀ‡Ê ƒÛ!_šrÛÞU6ÀÚÐkà“>‰ á .5dÂ#'œj2 9¡ÙtÑxγòkБ %Í–µ V(K°€Ó±h”yf6§¸J«àjV%Z;_-Ðá’jÆjnú-¬mí¼Ò€Â6Ë6œ2EJÖ;—P3ùñ©ÌʃdãSó$ÎÕzN²Q|òeÑXKáT 驃(Xê ¬ò?Ží³û<%Ñ{V \e:òð€õã”Læ8ñß—!8F‘ráP£ÎK˜=%õ¬/é¦ÅP’†ÈN§;ÀÍÙ3ƒ6ÔSÓM×(õ¨9›—D¯E¢;ÙÒp*á ¤Þ¡¦yUec%ò*@ÎxëÆ‘"ɇjËJIZBÆ”óX‘R8PßSÓ2¬^OÖ¾¸·QUõüA6^ÚæÃ&rN´D¯ÖÆÀ¼»<žÌêj.Iw¨¶ºkè‚z—fµŒ8FëåÂÒýÛCƪ„&a²?NN€n6‡›`2[í„EäÞÚK=4g¦\=Љ±"Ê ”¤2‚l‹C°Íóh›ªŠÖ&;V¥Jô¼ÔD=J™Ù\³›‹Jz5u`†ÄEC7&òÄ»OÓ¸^æ?¯FƒQ\ ÕóA tU£¯QÀÁ *5„Ïzà´ê¦‚JÇAI:€4‚ 9MTªvQ´?]Å%¦“ù%´‡¼{Òã3‰ œßîÚu±õÁRÜ, ¶KÖš ‘Øñ’ÔNfÎäm .4ZRïPRÍD “ê{P¨k`òf£¡éù éÌ@æ§œ.á $Ý¡ç΢ógø~P“PO*9Ä«§ JÄçüœ×AÙr~z:(»X­†¦ž5Û¦Üâxi¸{óaž±Ot¯![I: V-8§ Ûæ¼ ƒ©²UÛ»»´-yuMÔzÖ-VË‹ ÉÃDÃ}ÌÓаj^ ÐH£o1x¦¤N3˜“ôUóPA}jr&k·ù_}lZ¶­GºÎ<'ŽË`®4_Yz5hÅé½èhz¡†’ÔG­4— {2­2¾œO u¹6Œ7̸¶A‹ª¹× ·¤û™MƒÁó[õ§ ¢•¢9Ö‹ËAÍÚü Y¤7v ¹º5í•J+錛È9ÉBZ‚DZšíÍR‹“™SÄ(/õ–ÝÞ²6\jÞ‰2f~eüŒâcD@¯6x^+ƒ€Ò6O3yÞ*K¶•…a‰º@PIÓorš+I”3ÍFôÔ(N›/…ªj•ç‘—z lÉ`…éR³/W4+i²è¥ˆz3÷nÒU4k&ãÊ‘¿YPýª×œf…JDwJÒ}zÝ”µ‹©Â ‰f%‘:ƒÞÞÂ…IË h½$ Y4Ð Ð| ]µ„ö@ÍÌÄ«›ý¯>öÆeÛŠq¼ëÌÃpú¸L9¯hÎ?&JiIêÍ¿HïNލŏâ/_³y­$ƒy â½wD6ËÁâXÏô.2cR¢W)·–UžQz\OùhÍnõ4-š rNœ]´jÔškezÀ+½7™õN;¨õzæ(çèÔa©y·hPz,Vwi lˆC¬™ÍÈci-j¾Ø©õ^+DÝŒG»L„%ÊPÏ[¢Ö ©Mݳ½j'í3ÓC‹atì`˜Hs í!×õj‹(só%^4»F—ú»m\z̸wÕi'Lh¥·é™ÑÌ f†£W–ônÆòjoÂl›rºe«MëÃÆ>꣆O­J¦sN56ÏyÍ“žo·!Ëúß÷šÔ=šgÐ…qµ›ß7ÀzfF§÷\HhÖ%ã{éóôL¥…=WhšíʪXífÿ7k‹l[1Žwy.".Â=˜af&ÍL;Ú â„^4pÔ‰)ŽœD†Åz/ j¨¡—‡—@]³POS l5”óèË6ëWͽJfz›„ç/¼¬ ƒ8´ß(¢e.îE{vÕƒ«=˜!dzÝú zë‚©%é®B¾ ×•«HÚ"j z“¹9ŽJ¼í^e(eÐ])1‚óna…5¨—&ŸÍnÑCDÔÙy«Äâ<ŸsOï]KïgrBó^‹(go¸#ÈÃá é[3ª*1öü6‡Ð |–ó;êî(¥vE¯’Uï¯êQr)ÞÚÙ"ø¤G¯fÀš{>\,˜œ Å!Z¨ýd¯"_Ųh—‰º:ØéÉZÚ”ËaXU³Rªvl¿`+ø,ç-Ô¯øhx›¨TÏÔˆîô^m Ü8³º× :pÐ_õ [“ry¢kÊ<È©'ïÌi~Æ©Å5œÅ몟’šW·«±x¸W–,NZz¾Z¬SfÇT- îÁ ½¾ÌêõÔS÷˜çT“AŽ4(—ïû¶éð“€n²f€ÖÑ)X^®UÐ<|–ó>¨6£6x†¨kuÆÕªïÈÐCJ™­°*X[Î+ÆK"ÊHÇË.“f~Í„f=‰Uû ^ê¹BÎl¶+«bµ*rëèÊPÊhÖQ/XIfˆ5¬ryD.%.³ÈÌ«óÌ´Ó„Fæ’44wõØÈXaþfmbТš«kêiªe““Z,šõ«æ^%l¢iy“žIX1ñìáÕ&Í"uëzeL[5zx†ø*zÏ Ÿêè-D)ô6ßH¢ý´3¦ Do27ÇQ‰‹¤öÌkÝ î\X(Êå•Äð‡–½ ÌîKXv¾G=âûYšKrÂbÇ£»JÒTÈ© Û< ,µÊ!´¡ö¿Þ­q‰{Î+z•Ô0g³’õ¨¾ƒpWòN¨9- 5ÓžeOœMÏè”ÛRY´"gö:.kAUŠ, š¨Ú±ýD™“MŸ ¼MTªgjd±_‘¦ók4±N–ôWýZ$ŽK¦ 9ªŽ›4a± L¡7ôÈÖ>V{6ܘL,XO™4ðp¯,‘ÇcYœ‹uÊìXƒª]$=_60ö ¨«”A) ^¤¾³E|–óM“AŽ]•Ç9/ã{Cv ¯ÿ‰õœ6£3µjà fëQwa\­ú¾Èxdg %ƒzdLšpWòa"å_¼ÅæÀÚýÍXtf³]Y«U‘E’1ÍÚ"4u†¸bLºÎ<:—ò{Lhb@ý´n‚œ·V§&42—¤¾ñÚ ânrT‹Eä`Ñíkà¥XQ§Êy‹»XÔ5 \bžTË&''´X4ëWͽJØDÓò&M“0 LgUp&žIhš4‹z÷"O¦P¦3g©·C)pÇ õXŸ<¥·uª·Ú›™¿~ß‚aÌÙ›ÌÍqT"\zè\—R๱œWÐÎy·Èÿu[ÛÐÐã€)¨™)`r‰*»y #r{rà¼6¸ k‹€ØýmžßæΊæ´Ñxqn¬TAYÃbN¢õî 8¶±uR߆M5³¶ž± ð’¦·Æ7Y¥É6)9\K%PYX¢Ú*9²Uáx@\{MÎ cû‰2]ýоRÙÚÛ$z£$õiú³‡2÷š&œ-ø¬8èot ޤgb™ÚœDŽwGèÞg°„§8À©nd –üÀÓ/ÁÈr~ÇŒI½²DVMv ÈWìHÍb2;Ö j1µ> 8‚±O@íX¥ JØ‹’tà$“A¥ÐÊ­#ú¤9ßtøiAÑGšMê%¢Ù©ºÏ²ÈƒÚ`6ÜÅmÞk¨ïkß7@KVÍ+G1 ,.éÐ¥˜àR3=‚IE{&÷œÀ‹Îl¶‹jy5V«"kýìù“¦¹«G)p§,5p¹.ýïˬbfÚ©ÅÅ7!,‹‡ÊnÓÓüºåêKj¢œ·¸‹—@]³è›N‰‰å W³˜é]¤i’ÕiËA½ÐbpŠAdfžFPœ9nl2h}=_ùB3T› fÇÕ0ƒÐ@ô&ss•Ø+Õƒv¶r^±Ö-¬¬õu-Ú@«ÀÚþ.ÎóU¨¶ä@Ís¼”¤ÛÜ¥îÇRÛªÚæzM4Õñ‰ãUƒJ"z=­oö&êÑâÜPÍ€·í˜AÍìKχc“’ÒJ"&GªépÝDLTÇÑhý‡'J¨Ýž'×V›ÜÒDýŠŽUCMoƒä1Í&zLfnvôwÛ¸ôÐ4˜º8¦ =×0ÁpJoÄÅŽ§gb‚—êžÎx¸W–,Nù¡7a¶M¹ÅjOÈØ'@ÆèD”½^œd2LÚPÓtø9€åzÜÇÞ‘ØÇÜV*XÛ9è¸ZÄAI:´dÕ¼,•‰F<ßKh V-)´p›3eU¬v\d@³¶ˆœYO‰3®3—À¥üSüyïfd'5½Ÿ¸6ßTºZßìTª-1p—Ö”ÁÍ£÷éÔS6=&0°,ŽõLï"M“Æ•4‹ˆX6}ý$¢×ÍÅ-qbÜú"zÄò‘ÀÚ¢ ¨)´ŸcÍã„¢7 šã¨w É½«ˆV5YëVšÓlêo´A£<°¼Éâ<_…jKfÈæñpÄFIšƒ¥@tò6ÏosÈØl´dÕVÍô].õÍÞD=êÝAÔLæAÍ4²çñIr;ØsKï)–hW75 š-õÝ6-5Ð=OÊ “36Ù\£^ÄÀÁØÛ öÆ=kf–VeôQOŠ”‡}ø|órÑdÆÔ ÍÅ"ìQô›& &³ h}XOm›Æ®7¸ W–,Nvô&̶)§?¾'œ‰±O3½“³àxiÛdØ<ç›?èW³¹±ñ2²9m]W»ùmp´dÕ¼ÒÍÒ,¥«É'½ôÈØ-=S93{¥ÆcÔìËfÿ=¶­3®3—ÀT\ô¦²ÏiЬAÓë$EÓmḤôH÷IÓx݇ÍF;Øf,º òèfN¾ŠÐ™@kaú  P¿š.’{•°‰qï"M“v¾{÷nÜ‹¸{A4Ù¼&Ž[Ÿ5àSÿ6Sœ9ÌÙ´PÑ»5šã¸ùõeàIÂjçÝ Asš5ñå¨¼Ä £CÔ_€‰QR[`^ÅgØâìUÂ&z–×4MR%õ ®¼×3@sXOï}WAïeÔS«ið*0.l—¨°\8 +[|GÊÖ[C{ã¨j{nu¯éödjd­[X!hN³¾±õ^²uÇ!O2^o-]nn™àaå|bž'PŽm.D¨ WY[=Ó4ÈÓt…ÞhAZ1Pæ5—‘ªH½Öód­C;›Ð,µUãJàRf`Ì“ra õ(ÞApfÓŸ²³w»Eš5šÚóá  ‘+4mšý•µÈYÏI´Âz@ê¬ ÆQÐ0HMÎ ³Ô+›&'˜¬](:ûÕ™¼ºèí¦7¨¡ziÅýˆÄØ# JR .h%é¶R§G¶K™Z÷k0—ÆÈÂÞLfµ°ŸM/e+çwhpœˆ•dÿôIDATè•%‹Ó£F¦÷œÚ<åääUï*PC n ¾â¥ÔA™â«r’ɰmÎ÷~$p]s8ÔÁÔœ;~úÔóJ ¨»0®ÈžúÖ5¯Ð&ÖgTº•T*¥GXŸ«ö¼„Råü>£f»½¾lö¿ºPÎ+˜̯3®3—Àl\F³Ó £ pƒÅµ`<§§Q}3 žCÅ·e1]âzúqéu©&švl Ÿ(Nk1w™êE¿iŽÝ¥õ¥¶ ‘W{•°‰žå5M“Ô ¤£_LÄ;7ÝB½ˆÙÜR.Ü'î78oË…C7áÔSwdƇcâ£ÔóM>ä§<Ñ@ôÖÐÞ8¢6Ö Ðtt& ¦‘!•¢K‘^Î+Xç¼[4F©¡ê/‚…ð!R4[n®R  ¶Šc¬á‚cZÎK¥ÀÄ`~¡vk¨!`êê*pÊùŸº£VŽÑ@fV…üƒÞ%ÐÊ¡²[x# «™êumÈÆKÉ<ÑóFø@‰kê©{ó˜ÈtdæóùcwÎü‚=BÙrÞ!v•ÌŒKÜ ¬ ðÖ`¿t_€z.* êîÄUÔ~ ¬$:V¨~Î1®ÆåÚAY€"*^’–£P3 F øÄ„,—˜rÛÞU6 §´ÅáÆ§fò 6´¸:¿àSMـ䙙ó=‡ ‡-ê%6hÅU&Šx‰‡eªæ@:c…¤î¸Z=Ÿžzƒ·Á ¨29¯T*ÎXkKŠ:›éM'4­I²¸¿àU4]ÎÔlWV¥j7û_¦Â3¸ 0Ö±ø†éÌ?p¹fã2Xõ8¢‘8ºã9 8;Ó¬%º‹r’r~˜Ð%ëM;ÌàT§hÐ3Ó¥M<Ö‚ïoE‘Ú]tWlÜ6êÄqÝ.`žf…Ö—f òa¯6Ïr¾DÓ¤øÎŠÂSä<(¹+°œ13@Á’Ú"=ØØ(ç­â¼:h}†ØDý’'g¯! Do Œ#ZL}$åü€Þ'}Ž<异ÅçÝ Asš5Q‘ñáH÷K *–,ÎóÄLý%kÚZì&jÉHãXƒ«µ{ÕÖ¼ç2&ÍFš7˜6 ¾@€Úªq2ÀÿõVaŒzmNK)çýý@¢Y3am½É0(HpW2µåBªŠ–ƒtÚ¼Y‹†¦M2&ÅÙ{ë¯;JÒÒ÷b"(…¦y554&U[ͪ½=ðFô@I¤ùSß¿é´9ߨSä,ç¶KXRÊ´˜|KDóêÙ8ùgwšãÛ\“ãPÊ‚ÅéÑ$vŠDã™rÞU6À Ñ‹ÞLF†æí€Äh H§ÍGœd2l˜óîñâ+\±àÎÔm-n âd>Tv 5Rªiº­÷@9?Þ7À ×Ϋ¸ìŒº…§pÓ­„J˜apÛ¢;ªçPå-<……€%÷LGÎr~M¤f»²ª®v›ÿ› rjzíŠ1ã:s ÌÆeÆ2 yœLX§ngDIåÕÞ³JípŠÄù9”¦]mpïÉ10¾®™Ñqp(Ñ~†¥Ð,²¥§Å¢»+AžRËœ¢Š'UvLØ#д‰¼Úó¯‚r¾3×&ÁtB騡k8¦zŸFX›Jj‡›Ã—ŒbC§ éI^´>[$uÙr­šBAŸÔŒÇêÁA l‹qw"ƒËy¯Î»E6ÍëÑ[š6'z QmÉt‡îßù­ª¿FãUJÀé¸kƒqìM  VyÐócROKêÒj€›´äkå”Á ؃K¸Aê;h†ÞTŽÑîÊ’c‰Á½Ét˜]Îï3((â(Œ;ÎßA¶Ò8LHõ½ž¨—@]œKw eнd=d†µ ®qÄ{^êQÀiÏ™‹Þxc@ý\Æ1úÒ¼‹ëÇäÌÊù ãÒ£·¾õ¼·ˆÜ ê› s»\΄q†4ÿÑëráÀ¸ìÌÍX“°¡\;zÊõ† •mË`‚•ÓQœÉlàZG™³fÂ#N2«*Íß”¦c‡CÓÖÞ®CH±BÕp š]X¬À½µµ)hbðú1+‡%8^5¯Rf€SÎp s’ÉÛÍ¡Qd+•Ì`¦ã“9ÓA9¿&RsªkŒêjÁ6ÿ×ó¡öáªcÒuæÑY—!ZRÎO ¦Q©ý@IE8/ã´cU œo¢TñÑGi¢Á]ÄRå|+¬„”¤½G¼$Í¡¥¼·Ü×”f¬Ç'Méðy_=:Åâ%iÝw $”Rõµió;õ„Æñb‰ñÔWƒ87ÎÚ—Ø(©CJÖÓ݉qàñFˆf”¤!%ë’t:6ŒK qï*ÞZyéL·+'§m»2¼5qÿLJ3kŠóíLXä„sþ¢%iˆò—ó ^«»X-a‚"%õ9¯dÿi­BÓ¬”¤G¥˜r`²§%÷š‘}¬[ÒœŠÕq™K3ò°U÷×´vV4t| cŒ1Ƙ&õþÙ˜ãñ¼2æT8.cžÏï~·÷K@ÆcŒ1FxÿlÎç•1§Âqóôà3Ÿþž1ÆcÌ"Þ?›sàyeÌ©p\Æ<1^Ýý¡òæ_Ø2ÆcŒ1 ïŸ#úS¯«ðkàÏ+cN‚ã2扥Ÿ£¼öÿMcŒ1Æ\'Þ?Gô2¹ l4Jys‡ç•1§bWq€½úË—/ùÏ8Í.¹¹¹ùðÃOò¿ýŒ1Æc®¾>ö¿Þ<]^¿~ o¬¥6Ï+cNÅÞâ2ÆcŒ1ÆcŒ1OÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeŒ1ÆcŒ1ÆcÇeÚ|øá‡|ðÁ‹/ʹ1GàédŒy¢¼|ùËyþüù›7oÊ…'³gÏ`y½ü"é¸ZΗxýúõÁ¼}û¶$]<½¾?.=Ï_Ȭí£1ƘëÁq™6ï¿ÿþ{gÏr~Þ°ÇÆ{j97f‚Þt2æiñQàÉíÏ{”þì¨G'{H¬]<˵'—_t¤œßÁ®Í/ËèøÁïaª”¤‹§×÷‡oJpÚ«W¯Êù=Ï_Ȭíc Ôa¡º¥$cŒÙŽË´áÛLýìd:¨_5ŒéÑ›NÞqaa Þ#Ÿ?~ssSòÝoÞ̶a·ööí[–ƒZ/™¦9rƒýìÙ³RÑûï¯ýÁf,»è“IU;þÑ·²6vŒåŽ5sõHAzonôë`QŒoÉz 7#'ùñ8*áÔ*9€S$ªþ8@“À!,[ƒ±+™Þÿõë×%õ>G¶¸èm0wÀr Œ§ýîôÇ6£ õý…v­œ/Žœá¸ÌXè.ØnØžç¯aDÖö̬TÆcv€ã2møLÏN¼Îò‰ü•3Os:áOÆò­‹ï‹šN½oØ­á&bYÒÛÞ/Vsäk:ÇKàõ·\XBûXËË…“ØÆ3lëí«ãF¨$ f ÆÕè¹QrôI^šîã·a¯^½J£Á%Þz3ö'ƒ[ìe;¦ÅɲóÞ£ÁòÆ…½¨Ι†«å| ÇeðÃÀqqKKVÏó×0"kûÈ`(»YƒKO¨ïÆcÆ8.Ó†ÂúÙ‰- ñdõ)Ì<½éÔCÀ3½O7áû"À‹ ÞwIz)¬íA^ÂAIšF-’ÞÞž¿<˜UÑZQJnE•¯8å?”^¾IÅGš2 ÚN5Æò’vÑãá[ëM¨7ÿÚ&pÎÈÉh·÷]žø¡zl˜ÉgY"››0ô#Ò š€m·'…'Õúü-3Ùâ6Ãz¨6x£$=Mx×Ô>áLßt­uç›™'§×÷ãÙ¼òƒžç¯aDÖö9±bÔË‘–0óx2Æsù8.Ó†o3óÏNc¬N§Ý_MÂ÷EÐ|ÇÕpêÅæ·s/Þ¼y£ŸþÍ¿_Ž­=—¾ã03záž¾ D|h3èPÖG|ìdí3í6ÌdºœcdÉ‘Mlèàa õ=¤”kKL¶¸Í°ªmí­}iÐóµO8 æGAwĶió(ôú~<›W~Ðóü5ŒÈÚ>Ä\€¸$cŒyÊl‰ËàHŒ&È¿¶ ^aWaf€‚%i Y‹ð7ÿìlRW;†ùA9ߊzæ]ݤÔr¶?tM-IhV”ó ˜”óiÖ¶u’é„â‡×­ïÓl””¤•ð}4k@¿ô»¶ùí<úDß4™ÿÉüØÚ#‰¶©¡ñ¬΋/`Ç÷Í,¢Ã¯9á ºšù­¨^æIWDÎ:²DÖnkbC§4¾Œ»É€ñ¤“-n0l€j›¼µ‘ŸLvJ ÿ†R€ÍqYz»ö g®–ó%&£ì΢UGÂ&ÀøÑÜë»Ølíæ•ô<¦Ùöš±–IO®íãVãkŒ1æ ±".ƒg^úù˜'8Æó ÷^\|Mǃ û œª lÈœMðÄU~€ãA[HÇÕ˜àtüƬ¨„?mf">™S0/Ÿ8~÷î]rªíýÑÀ¯ÍÇü· ܧd‚ÂöŒùKEw~´ÞƒU•Z:õ`poëÿó¹«kô: Žë]%§ˆ§¥@§H¤é[¤p”x£ÂU@kÑYXXŠM´µa:ÕÈc¬ð”Ôf×8…©ã÷õu~(I÷Q+1ƒÞŒÇ÷Zf³¦SX9>yºÈ¢µÇÁÜfCãÑÇUá€E`d¹\±ÙÚá#'–¤ E•];è=dÞ¢=D¡ÔåW$Î:²„î½ʘ ÂMŠür¦Ü¥Ñ3ÙâÚÀNÂÚÊÉú.XûðMK:=CÆ·˜À-¹ªEæ¬}‚,çKh­ëÍLvyHÓ*¯@z¤;§ðÒK‡&Pao&3gÝwÀÇ7+!8íù0‚lD¥"%Ó¦ /åüŽžçO>"õäÄ1˜¼J—‚Þ› àà‚ÚÕ“ãNÖöq«8(IÆcž2³q<ŠôàÁá)h¾N1N±l‰½÷=ojê¶R®µ@UÍVzV½¯à³ä¾£÷Le:>ñ~Ы¶~œ$–Ë-ÇŠÁ yýúu,X×Ól½‡üÏz€NKŽz+¿‚€ôÚ4èuªŠMà*¶ ñ >‚V¸AMhóØ(ç-‡hWƒƒÞ¤B[%÷}P[¬<2˜N5½JHzkÄi¹ÐU­ŠÇõKȶ˜aq4‘{5±•2x3Ž,Z{ i¼Òi"#Üh"õf 8Æê;ŠàT÷Ū!£{‡M,¢.'/͸"qÖ‘%òÚj.cÖv*M˜2˜T‘É7x» mk’jÖ¤m‚Ìõ“+.éÈÀœdÑlùà˜”óá«H]9[ÇÕr¾„Öºzf"%öå`Ô7­JMËi½¨\ozħÌmx Võ=ë<­{Á€2[8â¬sÞó½ôƒñ…á¶{t‹è…¤6U°,>1:%i帓µ} ¦O¸òcŒyD¦â2xÐêaƒ€Kñ õƒE”ÏÈ››<Æâ»Åà¹Å«ÈŒ",Åôô<ÓëÒa3Z‰¯w¸JÃðä µš6¥à”–£N^âÕøDñõ ù•¨N¡,:¢KõàUí2ýÃÄEX@Y̪R%ʉƒ’tõ]&õ:8Ä©*õ‹Uá)¨ à€õmx„bȈt•Âè”Ô¨“é2]V[LõËôæéT‡ -íŠQ§¢d:€N1€nd:ŠÇ·ä1*…JJR ÎÕ’tV±T2oL]ÜÅz`FI2¶öH’yº‰zw¢œÀ 0‰§ƒ¾ãåDqÍóI¿M"÷N†É{â”›qEBMŸcd‰`öªð%XÛ)Qœ?ê&Œ)I}&[Üàí&0SZ«Ö1œ’8¸º/àC\BëÇš µ%¸Ê"\q€†ˆÓziM rAÓò–&ÖIjÒ˜Ú®–ó%Ô Ì(Iw°*Ãä"è€&‚xÿ–¤ûhÂD‡ 6vÀ=š'_ÃÊù€tYK7"Ý»§GìNIZ.š­\w¿—Þ-ÞZÐMNÔ§J|¶2‘ÐT|ʱx‰¥R_h0˜w²¶h3¨ç¼1Ƙ§ÈT\FϘz[‚g˜žg%é=3Ÿ%õ¢ºª‡ALOÏ?‚§~l(¾ßÔæØJ2 >³KÒzÒƒØé=Sõx¨¼¤Þ¡«é­E¯µcéóº¡ÜÏ—“û †¯ Öl:ýlY¾ê5­ŽÇÑÑ'o4‰ÃÚÒlÑé’zQO øŠEÒ;r2 `Ú­ÁZ]*IwlžN=dI]¡`AsXåùú½°Gs°D¯‹s F mÃØ#|6ߌckD–ð4nc˜’Hù‡ïxh8ÄÚàÂZæÝÛ,²èŠš³Ž¬ÐÚKp›L.`m§Ø#M¢õ¤~^ÔL¶³á¸&-’cŸµ5oíÍß´$Öeྀ»šw‡ª­ýIKj×5Çe€šH6šlÄͳœÓ‰WÏñÅ×°Ôw­«æCB½ÆAIªh¶zžï¥÷èÈxÅÖ½-—Oš¯%*¯nw°¶=ÔúñUcŒ¹–ã2xrsõïmðôÄJ¯ |$ƒæs®÷ÔÃlf›¡7•f@ûŸôè¢mø¿áÕ¼Þ3Uf7ŸÐ2#ùpð„– é¡¾µßBÈ9弌ìÕ,·Ä×&•ªß/k”ö4ã@s nq1˜86 uÆ #Y éÍÝ=Òë,ÓSm"v¡$-!K`gIºêlÎ7ßÔ›VÕ4‹ÈŸ ݘ²¤çêYm˜Ö„8”=Ö\WÎûCêûkqøŽ÷€Æ—¤…åxTù¼{›Eä \…7š$' …ExµffzÌ€Y}PùÌ¢´8¾=@Ó­ªÄgIê3Ù¢²õ˜iK¨¶æ­­…wíÃW+8a0Qþ¬]ÔKG Òç}"Ëá™’t€õ÷êQŒ N½5Õ“¹Ù‘#_ÃRßÕñtë­BÞhNÒlô<ßKïÑMÎÞë ‹ C9u~ÐLÍqkû؃­ƒÿ1Æ<-–ã2zòõ^XõøI>6š9 jc©U¯ª`&³òèdæ·Wsôfì ×b¯6ÐôÏ6Ư×5´ ,nQTUñµiü”P½7x½ýÇÚäØÞ{§Þb£arToã×ìŽJ ºK¡9ÐMë”%½÷N <‹ãH”݇ۅÒAzÅÈÀK8(IKÐu×41f%«âXœŠz¼ÔÍÚueqøNâVBz3v3ª|޽͑+¤&TOžW7€!ÀFO hoÝ ‹ãÑRSߪêéâ:Ùbô6:Õ¤d@µ5omTÅVÊy å‰þÔ­t¦I[»¨—Nÿ»‘åqÆÊKõÊ jg©[W<¼ÔôI^Ã4'6/"“R‹‘µž?Ɉ¶;¨§ÙJ¥Û¿Û6î`m› ÑCã ßcŒyº,Çeøx!À£¨¦¹1Íg’@A–Šu%Î]4½1(¥7'™½™¦«Ä/Gàñ?آȓ½škç¥ã`¼'Q=?¨wÑô6>qµ‰Ü-Gzi£Ä Ó©‡,IFÌT(ÃzÝIhPš ­f×¶¢å¢ùcvö âM¤7µNBí^Üu"Pzó•½9|'ñ@¼IJÕ_ä9™1ïÞf¹Wá&i…A ‹ðjÍàFÛ ÀB'ûŽëÞx|¬Ÿå< ™'O“ÉW¶ˆj«oíɆp•Ù¿$M,雡«k“zé4¯94Mš–+ÓéMšs@ÎIwº¬Š3P™1gJ¥÷Ñ\JÝlökÓæÞâbÛD¯§‡h¶ÔÇr~G/½GsDpÌDÔvðM6p\Š…—®´Â(N.IGû|k4Ö¨­”TcŒ1OŸq™E³”9ÀgRJxœ°T|¨k³±øž z/" Ù¯]ÐüûDýìdmóé¢é =ïÓíÝ»w=ÆàMU¡Œ°•Aúi @ñÞ«Û¢'åüôö W‚cÔÐÜ©‰Áû«Âg9¿K™!ZÞœ“‘¦1J앵…cdIš0Žš©P†ÍÜM@ƒ…j#HÇDímSgºa+¨¶Y¡îˆÁ!Ioj˜‡šñYÎÀl1¾ëN‰7ÈxøNâY(«&GyÖæÝÛ,2vE“³Žì G\÷þœïfsöFSãØ»¿Èd‹¼=@µÕ·öæ‡/ЊqÌøÂ ê‡ë«­Mâ¥:æáj9_¢i¹I ém'Î LZ›¦Ÿ<¹Hêf¯ïA‚ qY›A¯§‡Xëù^zæˆhÞÎ ö¾ÄÄ^¤ÄÍã¾¶ L{ÀÚ!3ÆsᬈËàa0&=ž‘‚Rõ#™èÙKéQ—ªj¢Ì½&ˆìW3­Ðx|–ó;zÏÔ^ºhzCñcà€g­lÆ&­d5¨6€cÁ”Ak¢§égò‹žT èWIºƒ» Ùp\×£&ê+Ág9¿Kaâ˜ævº×¦1Jì•hðYΗ%iÂ]W(Ú•Ô kÀL÷…vÍ5áÕE_)ç*k'iŽ—v2hº$ur†ï$H±Ux¿Ö!3f†¨_ó®è¡¦Ï1²‹ÄÐLï+HóRmp 2×hìRh>1ÙâoPmõ˜\[p•Ùb *»m|1Éå4‚SÂÓÚ$^ªÓi®–ó%š–+ñ`ˆjiÞ2ª-m¹åÉCM#¢«RPªî;À³&±Z‚ÌókˆLM-Fz­÷<’Ѽ¨j@mYP÷~/´ª¦YÕ€fˆ éå| è ²Ýd1Ƙ°".³ö-ŠÏúÉGôìŒuý)=Éš(s¯ "ûµŸŸ¨Ÿ½gj/]4½¿N\3ã¡­*Ä1Ü‹×>^jºz¾ºÉH¨Z°èI9¿7yPÊF'¤P”šL?Çg9ïߘEG5Qb¯Xk,I†ô~¬—a“ѽÅÁj2Ó}¡Ì3Œ¸ÍÚIzãÅtÀ·vEjRßÃw¼´hà“ÍJu6gË6P˜|ûo­Àx&79ëÈΠQîMéùN©ªEÆUM¶¸ÁÛT[í‡Í_ éºa|_ßý+=€™‰jµôvmR/æáj9_¢i¹{³e€Â"òM­M’'×:­×w“ÌF&C33ïµÞóüIFDóvÐëªPM­„qƒ™î7YÛGŒ7¹,cŒyZ\V\fÕu2sm¿¨ƒg¯Ÿ¬m>]4½Á×2$Â$|"ÁñxSšˆ?y«‡©éêUàÕÑiz;ïÕ¬RµU ºÐ ýôjPïÐVIêߘEG5Qâ†éÔ£Ù©ÈL… Õõº“˜¬ˆº?Ó Íh«‡òŒã’ÈÉl«¬¤ç^¹”cM-ÎX0¾ã= ½\t8JՉǠ8Kí„&²*grúrŽ‘aÑ™“Š>DÎÌbˆ!1ÙâoPmµ&Rï¿$M,éTaóùȧ6©—ÎÚ&g8hZ®ÄÞl Âõ€§õßôä ½¾'°ç‡ lb13™éøZÏ÷Ò{4GÇLœìH$¾J1%ŠÍã¾¶‚ÁàMÃcÌ“f9.³vw'ø<ë=õìŒÕÖÅ3™›yÛƒ?ïÒ{¦.>kYalQ¶­ Á4Q𹦫×"kcTsïEnÈY’úè½0fÖÛOÏKi«LVµ+%cbµ*=L§zAïÕÉ Aú!^Dyû½È6§É'‹³k±SDÙÆîÚfí$½ñŠë‰~t_OþÞ”8ÞÚÈ¥d ŠÀÈ’zê)ÿŠ À$dκõÅ»£æ¬#;ƒ èu|²SŠU nRÐ iE&[Üàíª­¾µãP’*zyš«è$ãFyµî{/)ƒÚjš–kòoóy쑞eõ„9ÓkX"³ÈâOe@¯õžçO2"`UG´`ÖàÖ÷ææq_ÛG"«”1Ƙ³—Ùüøá£±Wª÷ÎÇR ÷N÷çzVõÞ š›v Vê  jëg'/ͧ ¶½!ÿ W5óþ4à ÍŽë ¤×¦&Íw,%¢‰f%´ ĉ¡R«|«îôÕ´ȆµÓiëìÑÄnFâ€6êq¼ÆÈΙÁòIÏiB6/îó›cšØfí$çÇÑäA=èšHÉùÇ{`àmïOõâŽzX!8ùÝ»wòIÝtÏÎ:²àíÛ·Íû”Ä€6f%õ>“b=ø,ç0”¬ms²Å Þ Ú𷶆©wã÷¾½Ut†KQ¯Ö}拾 ·'z–˪”œA·-VlÕS®Îô–XåMÁ‚Ók½×Ð*@oDäÕÁ¤‡Þ—0µ6—öŸ«Æ}m‹€Ú“`Õ†[ÌcÌ#²—z*ôÀxÔÏ?>´z=ÔÓ[´(ž*hÛø<‹o´õ/EÇ«éÁ©Çm2/î1@l‹ðê|ºÀ%dHÍ1‘q À0x€Ì?SåÌÚ9 Î’Úï°¡~ÏP=) .¤­¦SYœÊ‡ußy©NG Òqµœ/ѳ\7&*¬oÒ[‡cÀ…½ ³˜~®[iös»žiºß'¢é1Èßl°/uÁ^zÞˆ`B2U¥KhF[ÍÆ§Ê…ûl÷µ}d~¶R’&ÐÊ<ß1ƘGg*.ƒ§—x>ð,Ä£Žà)¸Z¯þ,Ò{– ,+D %é=‡P^ à]„¦†™3Óª˜^?ã–ƒ=xʪ 4ǃRàÚ6Ÿ.XsòLez\­_y›Èi8À jÆ'{!ÐÇ’»Çí¢,ëò Hïs¨“éE޼LÑ*)îLÅ'¶.¬¤œ¸’ï€ê—šqˆk/i_SmÁ~tG6”Üp•ùQyIºÒ™9KÒÍÓi€z§ qg2R˜0º†n¢-ƒã’{TÂR©wcdí¶1Z)%ûÄŽKê}¶Y;‰Z/ç÷áU‡—Ô€&Rì쑈‹pº§˜ibt$vǺûâ48nDÓcÎ:²@3Àlܧ캦ᠷg3R/zƒÑÀõnØI7*ìGÎ3&Õ甤ûĘEèÉ’Úzø"/!sIšFŽBQ3jññÐÁ’û^­Ó‘‚t\-çK ,gUµÁx˜¶a}мªK‘h<èÎ _ØÃäCØÉD€ÚJ¾%T„£Ïk\±›­¤ WËù½ôƒ‰SÇê)pJÃz= Bƒ*œ÷U}„µ‡êoAÁÉHy$Œ1Æ\,Sq è{<JÖ;˜¿N'xT°`ýÌÃûJñjuâAUòÝ‘¢‘f~‚ôfÐ4lãS Jî;hØ|º`[ÉhHéè>ÓÉLhFU%¨W®Áë…І°IÓ™°¶\ ˜­—ƒøf€×&Ö ª’éÕ€7½i%zCŒ²ƒ¾XR²ÌIÒìÙ6 ¿¬!’¢O¸«ä›CãX÷n€|2jìRzȘÞXl³veo¼Ô—^˜Ä q>é­rƒa7ïd+‹ VcÛâf,ÒtŘ³Ž,<2 7½Ø) Do†$t³¯šQ5Ê6¦wO%TÛ ÿ†‡¯VŒ±“{hz$ÀAí"ŽEÎü“c–/Þ&h¥wheccNõ60u°¼ÔÈ!‘Ðl¶h@ÝÙ^zñ\ŠŽ­A+½7+ÌÛ’i8p`ø¯êcÓÃM’“cÁ8"Æc.™Ù¸ ÁZÕO”~Í×/zy>Ï@oÿ€t\-mÀ‹Wï Ð\ÉwÇ ? ©:ÈKlWy*ÐUé—!z¶¡E<5‘^’îƒÌ|¬ö2$P!а#§ô[ŸÜª¡ßqK-PUïçx~+ù¨]¼÷ ÀSQò4ÍÓë_¼P9K™ÃOïVÚ'5 ƒuÁÉ9 š/:¦ÓX+Äqýeiä©;8¬ô^ïzÀÃ0Œ{pt\JÑÌU%é>²v²ÂU°G½ñB‹lºg[3Ñ“ÇŹD4W’NAsš±•ñL“+æíÑÈ®š‡kiöNn>Ë‹@+I/CÍx|[ès˜\Ô‹ñƒcíÃw¼ŠÎ7h=âÌ©g}[§ÓW¸ZΗX´<=žê;P~3Ó÷x©ýô¥Y¶×wö¥>€œ3­'R—SCk=ßKï±8"˜¨­wòǽùIh9˜¹…Wûª>ƹ1F/„aÆüdŒ1æÑY—1'gFoÉx¬">Ëùõ· ziÛW1ÆcŒ1ƘKÆq™Gド¯³:.㸌1ÆcŒ1Ƙã¸Ì£Á¸ è}_æåšÿè±W—1ÆcŒ1Ƴc—y4qxÿð‡HbÜá&ü[\ÿ"ô¾q\Ælf-¥äŽ([C)ù(¯¡”4ÆcŒ1æ’p\æ1yvÿŸY¼G9?¤\ù^Âq³M›UŒÿ<ç“cßNðcŒ1ƘÝà¸Ì#ó*ü3 îxüÁô¿OÚ7Ü}Á!ŽË˜y¼iŽËÔxQ5ÆcŒ1ˆã2Äí÷ì?úèšk©É›7oì³ÞM«(%wDéØJɧ@±x ¥¤1ÆcŒ1—„ã2ÆcŒ1ÆcŒ1ƒã2ÆcŒ1ÆcŒ1Ãm\æÿý?þ÷ÿÏÿþ¿³,ëq…;‘·åÿïÿó?üÿ_ÿ˲,˲,˲,kßÂîï6.ƒ áÿý¿û ˲W¸—ÁÍù?þîÿŲ,˲,˲,ËÚ·°ûs\Ʋ.EŽËX–eY–eY–e]•—±¬ ’ã2–eY–eY–eYW%Çe,ë‚丌eY–eY–eYÖUÉq˺ 9.cY–eY–eY–uUr\Ʋ.HŽËX–eY–eY–e]•—±¬ ’ã2–eY–eY–eYW%Çe,ë‚丌eY–eY–eYÖUÉq˺ 9.cY–eY–eY–uUr\Ʋ.HŽËX–eY–eY–e]•—±¬ ’ã2–eY–eY–eYW¥q™Ÿý»ŸûäŸÿs–µýØÿ•¯½¹I“üÑ希eY–eY–eYÖUi6.ó/ÿÕW>f̾ø/þËŸIóüÑ希eY–eY–eYÖUi6.óÏëW¸•ý¢1OŸïùžïÁdþ¹_x™æù£Ëq™Uúo?úÊoþ£_´¬}(Mo˲,˲,ëJ´:.ÃM£1Oš¿ô—þ’ã2O]ÿôË?ÏEɘ}ð¿úÓß•&¹eY–eY–u r\Æ\#ŽËì@ÿéç>ä¢dÌnH“ܲ,˲,˺9.c®Çev Æe~â'~‚3æéò{¿÷{‡¬ã2–eY–eY×(ÇeÌ5â¸Ì丌٠ŽËX–eY–e]³—1׈ã2;ã2f78.cY–eY–uÍr\Æ\#ŽËì@ŽË˜ÝฌeY–eYÖ5Ëqs8.³9.cvƒã2–eY–eY×,ÇeÌ5â¸Ì丌٠ŽËX–eY–e]³—1׈ã2;ã2f78.cY–eY–uÍr\Æ\#ŽËì@ŽË˜ÝฌeY–eYÖ5Ëqs8.³9.cvƒã2–eY–eY×,ÇeÌ5â¸Ì丌٠ŽËX–eY–e]³—1׈ã2;ã2f78.cY–eY–uÍr\Æ\#ŽËì@ŽË˜ÝฌeY–eYÖ5Ëqs8.³9.cvƒã2–eY–eY×,ÇeÌ5â¸Ì丌٠ŽËX–eY–e]³—1׈ã2;ã2f78.cY–eY–uÍr\Æ\#ŽËì@ŽË˜ÝฌeY–eYÖ5Ëqs8.³9.cvƒã2–eY–eY×,ÇeÌ5â¸Ì丌٠ŽËX–eY–e]³—1׈ã2;ã2f78.cY–eY–uÍr\Æ\#ŽËì@ŽË˜ÝฌeY–eYÖ5Ëqs8.³9.cvƒã2–eY–eY×,ÇeÌ5â¸Ì丌٠ŽËX–eY–e]³v—ù获oß–¤9J±>zóæMI:'¥±kM}¢¼|ùòÃ?|õêU9l—Ù—1»Áq˲,˲¬kÖÅe>øàƒ÷[ »ú’©ÅÍÍͳgÏó½;XðÃ?,9:ÔNŸ?ŽK%ÓÌ >ú裒´ô‚},-`hñaBBœ©Î^HÊq™èªâ2 ã–“‡…Mƒ+ "? ŽËX–eY–e]³.%.ƒ—~nÝ{`Kßü¶ÅóçÏKŽ|ðAÉW1.¡d=€ª˜SKÒ4¯_¿†ý,> µ¸^¾|YzøÞ{~r\fºž¸Œ–ÇÅXóiÁ’.Cäf3ŽËX–eY–e]³...ƒWì=Dú>K ͼ~ýº\85nnnPà7Sˆ²%ë}d8FC¨à ^BU¥Àq™‚=8…y3?‚ÁƒwÃÛ·oÑGô£Y’Çev '—á:“àšPrTà×ä,Iç'®®¸yÒ€«Âq˲,˲¬kÖÅÅe°/Iw¼{÷N‘ ì Jê¥7Š‹ýO3€D–BmÍ‚üý&dˆ;%µµ*tòâÅ –ÏŸ?G_Ê…û4[4çÃq™è)ÆeÞ¼yÃÕ  V¤fàãQâ2Zñ°ˆ1+*V*›Ó⸌eY–eYÖ5ë ÄeÀ»wïøÓZ#)LLÁš1ØZ°0Þc ¡FÙ—Aý,f~Géõë×åÈœÇev §—ÑB°p‰’t ^O—yóæ šã‡V᳜›s⸌eY–eYÖ5ëiÄe€~H_Q‘U;ÔÏRú!ð$*8—Q‘™ Ì ØP¡u°á¯´¬-øöí[%i¹ÁBÀæ@9?ŽËì@O:.“:Ü/ñ»ué‹~*u’¸ *Y¬­g§9ŽËX–eY–e]³žL\F{ exûö­~¢;ùBô–ù"BA–ɨÁ1mÕ ûì¬Àio[…M®rk÷îÝ»çϟDzèÈøçä¯^½BžXǨ¤Ù xÊ߯"1Åæ‰_áuÓƒ™QlÃ)ò³T¬œÍi¹Ã%,¬m¥…‹ ¯"[¬ç ḌeY–eYÖ5ëiÄeðæÍ]:H¯ÝÈÏt€<ã÷ò^%3¨!˜Z’†¨­c¾ñÍ +A¿JR@& |RÔÕ´sC%LG†’Ð> &•¤² Ë=çÐuÍ=cWëô“à¸Ìä¸ @Š–šDº±• ¸RõjÉfT®û7JšÑöWqœ¾(+§ ì,V0f±òf÷›«å…㸌eY–eYÖ5ë Äe¸?ï]õ‹{úé«Ð|Ü®L"fÊ*„Ï’xýú5j«Ù%ǃJ€")i‚ªšéDÛ¡ÔN™Þ Z5áF‹ þl ˰r~` :+ŽËì@ûŽËÄÛS¥ªJÇý… _¾ª†»ž·Ó±•܇Ûèjd1êg€›)ʃ։A²°wÈóòåKæÁ1‹ lÉt·\ð[0Ìs¨û›•ãýÒÊÏ º ÎÏ=ŽËX–eY–e]³...ƒwk¼»‹´Çè}÷›…DÜEU5[IཾlìNI  _¼Z+W%Íð a`[9?@Sq)þŸo¡jS)VÕ4˜¨Úr~@}©½iÚ©mÕÃo¢—Ùöý÷eâM¡R¸ÝJÒ¤ãÎÂ}ƒ/ þ±§úæÒ=›j‹ôZ¼£A½:é¾)È«¦Y\e±°ÇµWµhÀ¦Ç~)Oì šFzIz"8.cY–eY–uͺ¸¸LøvÞ£ŽÎ T¹v€¯ò`±ªífÊbÁÌÍíAý}™¦aÚüxñéMX0µ‚ ëÄK![9¿¿]dÍ5¬à¸ FÆÄšºEЬðap\fÚ_\æeøI µ¨T%I1ø2šîÙº61h¨†ô;¡øHÊ ‚ è. 6^ýÈV/*=—ã2–eY–eY׬KŒËàÅ:‚7ûÁ’¬Á‹»6ü î+PÓOqgXDP[3ù›•Ç=Ì´UÊ`m)1BÛâž'ú‘¦‘ãnÖ-¹èáwPŽËì@{ŠË¼ ]ÄU ¨TJÓ¼é€îÙAmãïÜ^`ZM×VEX?>›Q'µÞüžBóãéÒp\Ʋ,˲,ëšuqq™ñûú<¨‡ÆWmoˆÊN¾î7‰fåÚàª1é‡Ò¬ éå¼—ÙÊùý¸Ì¡Ê.±‘c·  ò¤²LÄg9@—Ùžt\ÜÞN’Úú"‰J­Z¸Xgºé€îÙAmƒÇ_êQ\ÔôàoQžå鬤¹æÌôîq\Ʋ,˲,ëšµÛ¸ÌÛð/œôú®¥nhe¼¨é}“¿I³òÍ Ö6Ø5ÕÛžÍþ—‘c·47Z _Fr\f^O=.Sƒ¤ùÝ@•,¸‰nÿ…Z4o:€K‹µ Zœ\+p•Ùâ—Õô†åB¨æf%3½»@—±,˲,˺fí6.´í×ë»þ.õþ.Cñf &þ„Å_›jV¾yƒÁÚÐÇr^Qo{6ûÿ˜V³×ƒã2;ГŽËàŽÀ½#^¾|9ˆNªr–¤y5©ïhäç¥fmdТŠ× Ýݱ•ݰ\ˆñº¡&jË/Çe,˲,˲®YW—‰%þêd“ñf ‰Š,vªY¹";k}ÂÚÐÓr^ÑÜö0qPªÉ1-}¥hü¿œÎã2;Ðþþîo•ªc ¼Ùn1?{ö yHó¦¸Ä"8(IƒU|Ü‘Se7,B57+™éÝ⸌eY–eYÖ5ë Çennnßy‰_)IôÖÆNøÅ‹ñ Œ7MPœEÀ8 Ô«œû|®úvkK4·=ú%¯Ueù˜VoŒÄ›åä¤8.³9.£È&j«—ˆæMf"½Ád¼W™-® Ç,¢Y³˜éÝ⸌eY–eYÖ5ë Çe¯ïxù®7$Ø9ðÍÔoçz­Íoj¼zõŠÅcÙñf ‡6N54CÑÚT¹þE ʾ{÷®¤Þ§®“¦¢Îr^Áæ­œP W{}„©)P¢]ÐØ-Í:^Ç­^¾|‰«gÚ\9.³9.ÃÛŸÍÅ¡wÓéžÜ\½.¡þ’ÔB¶ÅõYMo[.Ò•Ìôîq\Ʋ,˲,ëšõ´ã2,‚—xã-œ(4kC[|ï',.â¥#¿/Cbh°¹/^ÐÔØ¨+W»È‰R777È^¾|ùìÙ3O¥X—ÊyK![9¿C¦"Ž_½zŶp€S–‚Ù%÷œ²H²!Ñk5³8@º¨×8.YOŠã2;ã2½ÛŠô®ê /ƒ›«×"aÍU•¤û(È›ZGmLß¶\¤*QƒÞ] ŽËX–eY–e]³žp\Eô‚ÞdðÞ½{§_Ûi‚A Ê€ñf` ª› ÐbóË;oÞ¼—EÁô!æGz9¯l{R)Q»åø–j¨iæ? ŽËì@ŽËð¶jÞ麑ë†flèµH•¤3Cú6ßñËPåÍJÔDÓò‹Åq˲,˲¬kÖ¥ÄeÞ¾}‹·m€7þ’4Þûùµ‘*éý 7‚<ȉFK±¨-í%È‹/háæ¿xÂæJ3w B$6[Œ r–2wÀÔø75;5KáÛ-ç÷µK‘ûœúWÆ`.±[[LžAþEŸƒã2;ã2¨„éñÎz÷îN™ê†pãÃ%|jL·Û8.£@º÷Q¡¬ª›VÐÄq™„ã2–eY–eY׬K‰Ëó8.³9.£_ïßý>¦b.:PÎÍÇq™Èq³—±,˲,˺f9.3Åûï¿ÿÞ{ï᳜›'Žã2;ã2f78.cY–eY–uÍr\f Çev†ã2;ã2f78.cY–eY–uÍr\f Çev†ã2;Ð5Çe^¿~ýÁ—/_–$ó”q\Ʋ,˲,ëšå¸ÌŽËì Çev kŽË|øá‡X‘J’yÊ8.cY–eY–uÍr\f Çev†ã2;ã2ŽËìÇe,˲,˲®YŽËL±!.óöíÛW¯^a×DpŒ”r-ÀóÔ¼$yR+ÈV.T¼{÷Wß¼ySÎÿ÷_¾|‰"øÄ¥’t58.³9.ã¸Ìnp\Ʋ,˲,ëšå¸Ì«â2¯^½úàƒX$‚”/^”L“—¿$U(ÏóçÏKÒwïÞ!¥nU½~ýºd p#Ç.|ôÑG±à³gϘçzp\fr\8.³—±,˲,˺f9.3£ jŒyùò%÷Kùoÿ2çýM ¯¨æÞWfž={Æ‚777%é÷ÿÍ›7ª³ÙÊ«W¯JÖ;—IA€²%ÓÕà¸Ìä¸ p\f8.cY–eY–uÍr\f 2ðYÎûp¿ôìÙ³FŠ× ’‚yþü9ÓÓWiD³é>ø€¥R”çõë×ÊŸ=ŠË0j€…}ô «ƒ8»Çq™Èq0—Áj€;Ñ[ÓúÞÇÚ…tЋ,V½Ø]ô6! Á`ƒT’Û&6+oþSï7›ˆ@éª6rà ·= Çev ÇeÀL\æÅ‹\Áš¤…âÙÝôâ2•è­‡Zâjš‹ëAê/ñ!¥dº—±,˲,˺f9.3Eo² …`ÒVJ’øGy‰öHñÒ‡/Ë TïÚMkµ‘CzÝеá¸Ìä¸ ˜‰ËhAxþüù«W¯>úè#¬E1†ÒŒ÷¢·½¸°+D…hà€­ƒú+¼„zd!Ê\Û希eY–eYÖ5Ëq™)´m(ç›À.åvwRm¥°]azÚç¼}û¶Ù.±{)ç¸T—ÒFnðcðëÁq™Èq0—Á‚Ð̆¥€•¤Å„+ hG‰_ T°¦^—Þ½{§u,…’•΂úÇpWøâ—±,˲,˺f9.3…öå|ìCøsc ­KÚ#õâ/Ú5Åü¨‡‰ÈŒô&¬ s)6r1ñjq\fr\à $m¢¹ò(R\Ã4‹(ÜüŸ–¾T!«8¸ÂXLÄq˲,˲¬k–ã2S4·"°Ñß°äÆ#Ro¥¸«ñGÐÍ­Žâ238.ÓÃq™Èqpd\F‹L9?ðæÍVžÒA3¢üXôJÒ}zFs%逖Ǹî]'ŽËX–eY–e]³—™‚û‡z—ÒDßó(°!L¬·RÚíèW™z;ÅebµMÒoE9.q\fr\œ#.˜RÄDéñWœšßìKp5K 5—¸ëÄq˲,˲¬k–ã2S47Mâ¿L[…Tš»—Ô„¶:éÏÁ¨’µ›Çe"ŽËì@ŽË€Uq™W¯^!?–Ñ[Ù´þÄðn/X,cpµ‡2”2˜žj»N—±,˲,˺f9.3÷iSQ3øþ?Çe°ÿáUìpн Žëz—9 ŽËì@ŽË€æbRóbø¯²ëuF!˜x©,–1‹¤U‹M8.—±,˲,˺f9.3E½Ei¢ Iú"2ŽËÜÜý{ÚgÏžiSÔü{ “Æ$—‰8.³9.fâ2 ò,XšP‹éžúÇH1Pf,PL!2æÅ‹¥Þ¥À\Ê—ŽËX–eY–e]³—™‚û‡æî%‚Ça{ÒŽ§è1½­”ZÑ>G;¢Èb=MTg½;ºB—Ù—‹‹€r~þµÄeôG¯¸š ‚ÅóÆ$X¡ã2Àq˲,˲¬k–ã2S(brø¡of‹¿Ç¤D¢` èí^^Üý{Z5W.Ü­0H¿P@°ƒBU¯_¿.ç´wJ†]'ŽËì@ŽË€ÅP#/ yãâ2 .Dú%¦:Xœ"8ó°~Çe€ã2–eY–eY×,Çe¦P¤‡6$8` мxñ»&ýeUÒÛJé'Ò¤ùËPD»2€"üÝ€œ²œ–ÜpÊüŽËÇev Çe@ºÍkÆ‘—ñUE“_½z5È©…«WO–r\8.cY–eY–uÍr\f îÄ­70 $~ôÑG¬g°•ŠeÓ¿sJ¼|ùr`ê‰ÿÈ8.q\fr\LÆe@úPØ¥OÑQ W›^°Xñè^þ* `¨¼œ_1ŽËX–eY–e]³—™âææûŸiÏóêÕ+lT°ß8Ð7ÿ_¾|‰Ìƒ€ êáö¦·SJ B5DP3ò¢.Ôcâ q\fr\† E¹óïƒewzÌ©•çÍ›7Ф€ÁjƒªJ¦½µ+~×5Çlh‹Ë2¤¥‰EÐD9¿b—±,˲,˺f9.sYhõâÅ‹’d΀ã2;ã2c‰±•÷è˜_™ÁsÖèÏÊ€A6ðêÕ+Õ pLÊùô%>^u\8.cY–eY–uÍr\æ²àFŸõwþÍ q\fºæ¸ÌÍÍÍmÌcH ‚\*çWŒã2–eY–eY×,Çe.ì[¸ñÏã2;Ð5Çe¶ñÑå|}Ý&}Ûe@iæÀ|©kÆq˲,˲¬k–ã2„þâÃËÖ¿6'Äq™Èq™àMøÓ¿%ÉœÇe,˲,˲®YŽË\ ú}|–$s6—Ù—yøh€ƒÅgÅq˲,˲¬k–ã2—‚þ`„ÿâïà¸Ìä¸Ì€‰ÁbÿÅ«³â¸ŒeY–eYÖ5Ëqs8.³9.sn^½zÅ/ËøOóžÇe,˲,˲®YŽË˜kÄq™Èq™s£¿øûêÕ«’d΃ã2–eY–eY×,ÇeÌ5â¸Ìä¸Ì¹¹¹¹ùðÃëÿomNŽã2–eY–eY×,ÇeÌ5â¸Ì丌٠ŽËX–eY–e]³—1׈ã2;ã2f78.cY–eY–uÍr\Æ\#ŽËì@ŽË˜ÝฌeY–eYÖ5Ëqs8.³9.cvƒã2–eY–eY×,ÇeÌ5â¸Ì丌٠ŽËX–eY–e]³—1׈ã2;ã2f78.cY–eY–uÍr\Æ\#ŽËì@ŽË˜ÝฌeY–eYÖ5Ëqs8.³9.cvƒã2–eY–eY×,ÇeÌ5â¸Ì丌٠ŽËX–eY–e]³—1׈ã2;ã2f78.cY–eY–uÍr\Æ\#ŽËì@ŽË˜ÝฌeY–eYÖ5Ëqs8.³9.cvƒã2–eY–eY×,ÇeÌ5â¸Ì丌٠ŽËX–eY–e]³—1׈ã2;ã2f78.cY–eY–uÍr\Æ\#ŽËì@ŽË˜ÝฌeY–eYÖ5Ëqs8.³9.cvƒã2–eY–eY×,ÇeÌ5â¸Ì丌٠ŽËX–eY–e]³—1׈ã2;ã2f78.cY–eY–uÍZ—Á†Ö˜§Îw|Çw`2;.ó¤å¸ŒÙ ŽËX–eY–e]³fã2_{sóÇÿø¿ÃGcöÁñ_þLšç.Çeæå¸ŒÙ ŽËX–eY–e]³fã2ÐëøŸýÔçܲö¡Ÿû…—¿ýßüWi’?º—™ã2Ÿþô§˘'Î?þÇÿØq˲,˲¬«ÕЏŒeYç–ã2ób\Ƙ=‘&¹eY–eY–u r\æ²ôÏëW>ùçÿÜ—þÁϦtëJä¸Ì¼þ¯ÿøKßñ'þݲ5æéóâ?üdšä–eY–eYÖ5Èq™ËÒüŸüGx;ÿáùTJ·®DŽËX—¦üçX”¾üó?Ò-˲,˲,Ë:‰—¹,ýÔçÜq™k–ã2Ö¥Éq˲,˲,Ë:«—¹,9.sår\ƺ49.cY–eY–eYg•ã2—%Çe®\ŽËX—&Çe,˲,˲,ë¬r\æ²ä¸Ì•ËqëÒ丌eY–eY–eUŽË\–—¹r9.c]š—±,˲,˲¬³Êq™Ë’ã2W.Çe¬K“ã2–eY–eY–uV9.sYr\æÊ希uir\Ʋ,˲,˲Î*Çe.KŽË\¹—±.MŽËX–eY–eYÖYå¸ÌeÉq™+—ã2Ö¥Éq˲,˲,Ë:«—¹,9.sår\ƺ49.cY–eY–eYg•ã2—%Çe®\ŽËX—&Çe,˲,˲,ë¬r\æ²ä¸Ì•ËqëÒ丌eY–eY–eUŽË\–—¹r9.c]š—±,˲,˲¬³Êq™Ë’ã2W.Çe¬K“ã2–eY–u™úg_þ¹ßýÍ_­SŠeY—/Çe.K_ú?‹-ÐO~öÇRºu%r\ƺ4ýŸÿÚÿ‹Ò×ÿÉë”nYÖñúø·}ìüáㇾÿϤôéK_ø,º ÕÈmb…Ÿøîãë_M—,ëz„ä½÷Þû×þà¨qƒÄÄü>}x}íæ—Ñ}è+¿ø31=b×Ðǘþ…¾à‘Áî@»|\•—¹8}íÍMJ±®GŽËX¨ßû¯=¥X–uaCµmõ´ô×þò_@7Aýc|\‚Ò&jQðX¯B˺aÎwPLÿâßü ïÄôE îÓ§"u!ù=j¦?9¡#ôˆ—ÁÝÈq˺ 9.cY–õ´ô‰ïþ8^”Wék7¿Ì²8Æ[õÕÆe~èûÿ Óᇘ¾(Çe, +ïúë-\X>þmKéc9.sùÒÒ‡ô…O/ƒ»‘ã2–•õúW¾øÿâË)1껾ç;ÿÍ?ü¯ÿÂßû[JùÚoÿú·~û…Æ希eYÖÓ’^”çÑkô•Çeø àqã2ØÖ¢ˬ+Ô™æÀY§Ö ø¢ˆçª¦{÷é’ºâ/èQ3ýi £É^ìþ‘qµr\Ʋîé[¿ýbÉûŸüÁ?ðúW¾˜.Q?ö×?Åe1Æe Aâw}ÏwÆÄµr\Ʋ,ëiéK_ø,Þõ“¸eØ ¥KÊ^y\®ƒ µ"á´qŽ>Sºu=:Ó8ßÔÿ²’6ð«î¬Þ}ú„¤.ÄeÚG\æsŸùôza ôâ2ÿæþ×±ã…~í«¿”.YÖÉ…ùÆU¯—a|¦ôïúžïD:&jJ_%Çe,˲v ÉÀ·mW—Ù,Çe¬ÓêLsà|S‹·À æ MŸü>}x© )r±¸Œz÷¹Ï|:]²ö¡KËüÚW‰S|êÓ?®ZÖÉ5ŽËüÂßû[¼úÙÏÿhïÒ1Õq˲¬Èq™¨“ï÷—±N«3ÍóM-Ö}x© )þ²³¸ÌÓ k¬'ð}þzH¿6bYçÐ8.£ßrJéçê1_™q\Ʋ,kڗᤀê¿åÙ“ŠŒÛ:‡°å›iúÈíDÝÄŒ{'mƒÖnžUóüŽ÷9%æKV›§%Ý{BßÎX²j¨¶A…ÔÚ©¥jÇ£¦_bDfò$5ïS™¤”±”¾ˆÄRóC_7¤.¤^#O3=éQ&­Z\l´9@Öžôâ2¿öÕ_úÔ§ÀAëa4ˆËüÆ¿ø2#/ßúí4]¢¾ï“ß˲›çÎq˲¬hC\ïôÿ¶1à§ã}l½PVEŽ?ñÝŸÜŠë?I ¾óÄ?cñ•_ü–-­ÀiÏàÞv™YyÓ€o|ý«©å¸wÞ6u­d:d“š˜ƒEJî8EbʶYè[§©_úÂgãøâ`qJ4;…Jê¿B¢œMçc ñ*ZL—(ø‡ê!X5-eOÑ\)óÞ{(¢lÛ„ÉдDšî’Ò@¿`^Ì pZÛ¹ªZžI“ÇÍQ£P³ þÁ<æ ó žt©'˜Í"Sö‚)ÇH‰ù£æC13gW}§ÃfLþ˜?©¶^U’©èQ3]zøI‹±ëy,5ªuR™u õ&‰õõâ2צþ[¿’R¬‡Ô .óÙÏÿ(/Õ¿ÄD¡3|ß'¿7]š”ã2Öêw~ã¦˲ÆÂ+>õ®5ŠïÙÜ€ñ8ÄÞ>1%bæH/⛋ ]wMZRtgÕK ;›ìÇÁ9&­î¯&¨9†¥d|“f¬'*Çe.K_ú?û±}ì'?ûc)Ýz0 â2ú%¦Á?Ã>òW™—±.MþÕX”~óýbJ·,k ½¬×ïôQ|û×ÛìˆP$nÕš/úØéªv騤i[‚âÊ< hnðš?rg×ð‰­…bF°é)3¥ý^ò†öõÖBµÁ6x9!õZ¤ WÙ† h’xJ©8¥`ƒ.á@;º´ÙÞ&9$6Ǿ§Ý{*Å>ÊcPtŽcu<&Rq§ZoÑq^Šþ„ÔÒ'§%\Ít¶ˆdF"Nq2¯’z·¸è lCý<ŸÌ«Pƒn–8(ÑÚùjq¬pI5ó«RJW~JÕ¦ô$Õ[ 14»žEõ7Y˜Ò9mCæÁ)ò£¡x·âR½.Ź$ópÀzø ’Ó§™=ü¤EOß‚ÖÙé±ïqÔP9ëçU6G)µ5â2_ûí_ÿÔ§ þíÒÏ~þG¿ë{¾ûUã_)Bfl_™?ö×?•2D¡ªïûä÷23„Fëïßþ;?‰ôq=4Ó4E: à)2àTE&![,˜ÄßÌ‚êßvù©Ïÿ8¶@?ü#«;;ãvvg›Ù05º Çõ48ræP0orþ°;qtd! ö¾Ò"ÅüÂ1W½:.3sañqìf Çe¬KÓþÀs,J_þùŸNé–e ¤×k¼m§KQÚE€ô†‚ºš¶UØ<0­ÄtJÛ‰™WvíIš¿Ì¢ªâU$bÿ Sé_ÿ* ÆgÚMÁÖ“¼S¦'Sµo©«Âž0:-U¸Á6H—Rº$ûá®t ÒXkS·Yr€=i¬^€4^²°9%â>0©m^í45-]Eë¼ÍØ6-e9@£i@7K]nNìZì/>Sº„¡oޝzÝ,»Xí`0Q›Å±°HÓÏQš™“^c²iÙÑZQχ Αm ¾­t5 Ÿ|ÒÝkcišõ–šG™´êBs±R/j?«ÝSÝ&Ö¥©—Ñïbà{KmS#Øc+¿„üÍ̽=*6Ï%G™±[ŽÙ´Ñ‰GjUÓøÄ1öíÈÀœ)u¬AdÁZŸúô0C aPâ2ón§ýøŒ‰ÒÀl¸…—É]ª«fÕô0@b3ÈÂúi-ŸØ‹Bq+[o°uõ[¿ýbß !ÓÒîW•ÇúõååÄ%¥©µMãáUQ~¤¯½ÈÈÓ%x†p.mˆËÈ’E·3Ÿ1Qê™-kQðû>ù½lyꜛg¤prª#1|V‡9dC=:<¨!•‚Ô#,Ä'@ò:ÅtéI°“ÙRÐjRŽËX—&Çe,kƒ´ë¿@óý»·¿Ò[xÚK4· Ql}!Jµ¥=À⦱VoÛÐKïm–&;æ÷'= qs2²·‚XCo祶°£N—¨æÞX¡Ê“ºY×ÑWHÔÆ>íZY*5׬*ª9-5.½.oÓŒO¢¨Ù/j\­úÞ ©ñÑ$YìšêÅRþ^¬aƒ—zÎQú7¾þÕt êõ‘¥@šR¯Ëª0¥/ö¨i¿ZÙ0i»)Ošj݉éÖn4ŠËpƒŠ-küÚEÜÓÆ¯Šh×ãФ/nh#*Ç1/Å­/·Ù0F)ÇhCÓÄ®ýÚWIWÓæ¿àäÃØµ6.³ÊíО'{f÷Jaô“ýÛf„S¦£`ІàRÏ€Áè(8R[0‰‚:Az¬$K9ª]µ8úc9.c]𗱬 Ò‹õøš»dNéTs/w,8nj²uJ{ï´ÇPúä7 Þ¶¡—ŽS¦÷:¨Ä¤U¤[šñÞLá”mj\üPÛŠIb[@_‘…ƒRPÓHy2~ц‰øTl.Î  b¢,G)¹%©9jƒq9Rj‹sø˜dCͲãje!Ì“—¢Î È©RòXLljrbH‹c1èiO½"‹UÑu©L”êu=ªÓ•ˆVèðZ´àX5Ðb ^/Ži×zÅeÀwµ¾Ú o1Ä«ÜÓÖ›çZÚã3¨¿ýw~2~e¾æEmkšùÓ.ŠÑ„XÛâÎü„q™UÎQßS:Õ4[‰3ßþØ6sbzŠ¡PrW ˆŒG‡Q6,WzÓB]©N5W·¥_wš”$Çe¬K“ã2–µAÍ·ùZͽ‡„²¬¤¹—˜aæõ]{ï´UïP ÛrXŽ Q¬*µÛÛNŒ;Øs 4vï*Û ^ÂgJ§dü"½æÕtHRÝ÷OÜýŽÒ $ÄÌçîþRL,Ëœüí¹Ú9j.Ö#ËgˆC ÷Öãr¤P¡º pŒ¶Ò—¤º›M}åð_ØÓÔRý)3Ä«ÍK†räT)y,&6¥œqpZ ÜëÎ*猫‚X6õ‘‰ƒR½.k~Æt%Î}²è¨žšßw«¥ú{¿Æµ¶]ë©h—é…bDΞ'›f+ÊÐëKÔ¶™£`Y¯TÏœ2½Ù÷ž1l Ä\”2 †˜®æRz-Öû8/Çe¬K“ã2–µAÜu€ñ tsï!iÛÐÛK ø@½jk!3+ÔN[߉hþòŽvæ$6Ê”ÔëÞvbÜÁý÷®µ â%|¦tJÆ«žžæá«§¦C’ê¾+eP ‚…Ì= ¢¼­¡çd ?‘G æÇ'O)Ypi 4¬½¹qÁfØFÙÀqÓK̃ϔ.Áò3AfJ§©Ä«ÍK*d=E›JKž¬%ߎ'†´84ö¤ô ÎéU%±lê#¥z]ÖüŒé?iÕ"êL—¢Tÿ©ÚµžŠFq™:j Õ;O…<ØüÖƒ¤ýí8›ÄüÛv¹I'oZ–ø¥ŒÅðÄ ã2ón‡‡9S:µÈX fm›9ú£U¥ ñè4Ã=ñ SJLbµ Å_X°N¯µØÄ@ŽËX—&Çe,kƒ´K¿@ãíyÒË·¤—øæ^¢Wjƒôº¯ßLQt»te£Ô5`‹;ØÛ6ôÒ7wP6¤ 7Øqz;%ŒFžIM‡$Õ}×ß.[Øë¦ÒyÁˆÙô«4üú và<¿ÄÉòÁ¨55—S ýB+ì&IÆCrBJ§½ð6íHW9"Ͳãj로Ѽ«åÛñÄÇ¢ÙÓmÎ8b©L”êuYN‹éóžLZtTOº}]€Tš¨›ÛµžŠŽŠË€¸GÕ†|kÿ÷ö½=·ß«tò¦S@N%Ê11ê„qH·CãxAÏì¿ýw~’ée¿ï“ßÛü0H5¬š9ò.¡é¦”Aõ@Lïub[Ȧ”šԜ,¤jË{bÎa9.c]𗱬 ⮌_ ›{é´{‰´³Òn!JÍ?x!õ¶ ½ôqëÖ¥¦{·Ùõ:K©`4òLj:$©¶VÖᆨ^7ˆp NéÛøÝdv²|í´ŒËÉ¥¶Ð#¡¤žs(…)q.AôX³ì¸Úæ4^Ô¼«°cLmQ‹cÑìé6ç œFÑu©LÄg>I]ÀAL—Óbú¼'“5ºÒ£tK¦^Ó®õ$´1.ÓÛ»ê×j¶¦u%kw­‹Ûïy¼éæ>¿™¥HDíœ qhÆíиû³?ûùeY‚c´Xÿж™#o,’,_Ú¼jh ÚBJH鵘s`Ø@ŽËX—&Çe,kƒ¸ëãèæÞCjî% ™7ûµ’Á_»ùeý&K½Ïׯ ¹Óëmzé›;Øtï6Û qsòÆÚÍÛÉ!Í-.$c¢µã€¥<1àBégø¸¤c4½Íãq 6/ 4—sHA„ÔÜØxÍ7ø*]‚6û¤·ý«Ž¢ö$³'}»8ÍžnsÎÀiûˆl1QmÕßã£z.Õ•ÒÙÊÀŒ¦Ž™´lôº)Oré1íZOB'ŽË@¿ð÷þ6íÚÄ‚´^»ke[Ûv¹I'oº¹Ïo&F)Q{x[\Zt;4îþŒÙ±~§ïæl›9òìÇñ@éµXU¯;­ÝYì#T[8N¯Åv† 丌uir\Ʋ6Hû‡ñ tsï!õöú1xÜ<)}í]ë–6ͦ{›ÞÞv¢×Ay/¥SjÄ ·Ù±9ŒEï‡ð¦A†SIã^à ¦k#×ÛìÉ¥ÍjÕA\åAì©æÆ—¾ðYæL­SÛ¦eonœI½æÆs`|•>ÁgJ‡Æ7‡ü-F)Ûä¼] u§™¸Ê9ͪ¢X0yFa—:¼qö’´tèÎJé?iÇ]€p—1C=+Ži×zÚ—áÎôþxêoü‹/£¸²Å?M2¿¿¥˜Û.7éäMëÏ»|køWÙr Š+1 ža†ÚÛã2ÔÀíÓ{ÝY4›ú…¿÷·äFT§iÛÌxc¬ÅÑa[±;3}TïÒ$é¥×b»Ãr\ƺ49.cYÄ]¿@7÷Ro/¡wïÕ-_óÇ×Ñ|ê e€´1¨wæ €dUo;Ñë öWuc+ ^Ýf¤ÁêíÍ´•BÎo|ý«é*µj_דBÒâ¶3 ®:Õ㮫½™3à3 =*äÕñ&vÛ´ìÍ#…5ÔX'3Æs@WÓˆ`2èRó~W ) N—¨ßýÍ_­ËªÔØi0 yš†5µ8l7U(cV9§YUG¶˜o0$·à”é$-)º³RúÃOÚØ,,é**ìu:ÓÍb]޶Äefþx*…ªêœÚßþJóoÛå&¼éïºû·ÊÉWì5ŠÇDi‰82.C5Ý»£qï™Õìø¶™³öŸdI‹£Ã¶bwf¦.«èN3}ü÷•W¹±–ã2Ö¥ÉqËÚ mHÆ/Ðͽ‡„²¬$í% ¸ç™!à”ÕÖ¥ÆÒ®›4‹ÇMR£Úeñc©Þv§L¯Û’Q'v/È)Q’Xá6Û }DmÁ¨!æIö`«ÆúQ™Yy]óZ¡µÂ´Ë¾Ã¦€z;‡=°Šà™aŒŒNCzÏBäd’ú©r€ãtU’‘´afZâ”EŽ÷^{OøA6ÈõWÆseyà+DöHŸªMW aÃÏâ€cÍÊ!#WëšQ‹ þtIB ÌSw¶'´È"(›.Qt`²g›sšUE± ²¥tÍ1€c´¡JaA$ÆRòFJ‡T! âø&­Š:n@xLͧRБíZ—¯Q\¦·±ÔFzfçÉÝlÜ+*¿c2P]Ãfmk ËéÅM>H{øñæ_Õž).5¦v“µ”B-È–.ÕÒ$iÆez54gŽþ öÚ!nö1Š£Œa"h†WÐeH^Òä©G-jÑ c9.c]𗱬 ⮌_ {{ eYIÚPÚN4AÍ_úÂgS‘±âþ Å·ó»1[½Ð.4õº·t—´E‰ ‘'ž¦ 7ØFÕm¥Ý,öÏÓ&Í+:DNK47lÊ,„yÍŽKÑØ%¦«q²÷ùk§eon)E.jz·Ûxôú…•¢}8hî¿ë{¾3ÆA·ßóÚÖ4©¿b£zm[ÓE”Âàø¸Ì¼Û!5ƒ˜©/ :†[ÇQè3Ç.l›9üÜ‹5µ81Ø\²DN¨cs1(R\F]®½%OÖƒ;#Çe¬K“ã2–µAxíÆæïÕ±oAžÞ[8cPog…íjÀ¶! ùñú¾-F@{ îpzªÛån²xúÚ?ìo¦;ø¯ž‰­à”ýRÁT!´Ö6 Wc[ÈVÇ& /¾s¡lš›ßúŽ•v©/hÄüµèja©ó4cÑbºÉáÐb¼oÕ´ìÍã_%3ÐÊÀ‹s >Ž9pŽ›~ƒ&§œ+§P°7⸊y‚Ï”.¡6Î¥yÇ.ŽìÁÕfO×:gP…KÈ€l)‚»Ô„Ìò* ¦ÖîM€‡Ÿ´h1N )ÍéA¤]ë’µ—ØÖþí¿ó“¼ôÿâËÚB§í.6´Øè¦`Ç÷}ò{™9íqÊt”Š[t³þ¸§eÊ`û½Jšñ_Dë« Ž&hsŽVä=8G}áÕzëþÿ'ÿѪ¸ ªšw;²1¨iô(†ŠŒTdCÉÎ_ûê/© ±ém3j&¡9š‘‚PrfLŒ¢‘©9ý*ˆL¦ëjŠË(¨WÛ%g¦A™”ã2Ö¥Éq˲¬‡Ñø§ú–%}üî7wz[tlòqŸ)ݲ¬‹Õ(.ƒ¦ö¨8 tšv­ñ6®PLI;êøÕ €cªœ¿÷žöóÐâö{•¶5­Ív?îí£bžXŠéÔ1ˆù¯¾òðûå+ÿyJï)V»èvHa)€ aQ‰òÃÂCÞoÖ›H}ß6s(Å’òÔmTW‘ˆ 11Še‘-¥§¶(ž"³‚DµÌ†Ï”5“g Çe¬KÓ¯ÿý/þÿwñ÷þë_Oé–eYÖi希5©/ÞýÊ^ó«mºê‰dYOH£¸ öä_ûí_;y‚½k½eÕ× ÍÌk®‹ ŒŒ@HAúæn­mM×Ä)vø1zÍâ´‹Ö£‡S©µZëvh0 ¬ §)ÝD³ï±_ó3G‚ók4WûŠ™q)¥KÍîP¨-uJ=R/jSÕ£Þwaôeœf£3r\Ʋ,˲®SŽËXó|#†ß¦Á¥úwp,˺X-Äe˜‚](Ž©ñog ¬rBõ÷5’°ý±¿þ©q~$¢Úz“|¤fš®wþ*‚Ô ôž¢ëb§íÑZ·#ƒ2Ç¥«ë~!峟ÿQÁqÊ@¡ìæ™#¥¾ÀϽîÐZ(¥K¼Ú+'@Í^µè8;Ø‹Ç-fX”ã2–eY–õ¤õÏîþ¥Î¼ToŽËP_»ùåè¥]ÏŸÞÀ$álI‘äwïþ1Yï³X–u™šŠË\­¿‘aE]ÃÌá×azSB_¨éƒ希eY–e=]i·¼ þ9Òæ¸Ì}1¾°Šæ÷Gö*úçã÷ÿzn/^cYÖ…Ëq™‘—Y¥k˜9úKCÍÈ £6›‰ r\Ʋ,˲ž®ŽŒËp§í¸ å¸ÌXü/H).Ãu4þ—j–e] —Éq™Uº†™ó ¯üUàú7•ôKL½ßóš‘ã2–eY–õ¤¥ß©™—Êþîoþªÿ ®äßc²,ëzôôâ2¿qøËkµ­/(?œ;.ó=:«®$¢Ç_Vªg¥™¾JŽËX–eY–eY–e]•ž^\Fæ­{æTÏŒN²Ó^ÔCö謺’¸Œ¾2¿ók_ý%&ÙwÇe,˲,˲,˲®J¸Ì×~û׿ë{¾ó[¿ýNþÖC~»äÇþú§PvóÿÖ™Ôn¾/sá3ç„â¿‚Bc"R ˜²AŽËX–eY–eY–e]•qëõµ77?õù¿ù§?¥[W"Çe¬KÓ×ÿÉëÿìoýŸþ‡ßù”nY–eY–eYÖIä¸Ìeégÿîç>ö±ýØÿ•”n]‰—±.M/þÃObQúG¿ô…”nY–eY–eYÖIä¸Ìeé§>ÿãØýð|*¥[W"Çe¬KÓþÀs,J_þùŸNé–eY–eY–eDŽË\–—¹r9.c]š—±,˲,˲¬³Êq™Ë’ã2W.Çe¬K“ã2–eY–eY–uV9.sYr\æÊ希uir\fßúÆÿíŸ|þoüFùbõá_}ñ;¿ñ“Ù–eY–eY{’ã2—%Çe®\ŽËX—&lŒ—Ù±>ÿ7~ã{áüÀó?›Ì¶,˲,ËÚ“—¹,9.sår\ƺ49.³oq|/œïþ“Ï’Ù–eY–eY{’ã2—%Çe®\ŽËX—&Çeö-ÅeþƒÿàßÿâÿÆEé¯þÕ¿HÛö—ùø·}ì_ûƒJé–e]‚x‡þ‘?üo¤ôcÄ[5§ôGÑÿægNÞAëÄi ýîoþjºdmÓÕÅe~î^â%ïýgÿô—þÁϦK— Çe®\ŽËX—&Çeö-Åe~â'þòïÿþG¥_ýÕŸ¦mûŽË`;ôÞ{ïáÕ6¥[=}íæ—á4è¯ýå¿.]‰°ŸG÷?ñÝOéÖ9„{óäw(뼄PvÔ4æ‹ó3é’eÅ™þÙ—.]²¶éêâ2¿ò•ÿœïyà£3ŽË\¹—±.MŽËì[ŽË<º—Y«O|÷ǹ¸N§aÿÌÝürºj\Ü|žv²±ÎKˆË|üÛ>v!–XONœÆÀq™Séêâ2пüW_ùð'~øÿñ‡/|q\æÊ希uir\fßr\æÑuڸ̗¾ðÙ¿ö—ÿÂç>ó锾'9.£îû×@Ü|®šl¸qâfLéë|ôhì6Ø÷î[?ôýÓÆ{é‡ÑÚ{êŸ}ùç Â.¬óÑã2×°\ÖŒþ|é Ÿ­»Ðs¶ üï0dNöËÕðOL?Rh¥i*LjîaÐ:3à}¯-‡—š»ÔV;õ`Τœ=ÑNGR³ó¿k@ÃXóªÆ€"sÝô _ó~X5‹`^Ó hkð‰°ÃLEpÊ Æt|ÆüMÕ݉DkY'òãéuÓÍ®QÛ:X‹kT—bGhÞªi@õ®¦…̉ϔNé¶j:SˆWijªÍF+i1‘hGy˜Ÿ4oÿy-Îóß½ûºMp)Æ\àÔVç*g¹Öùcfh~^qÆÎ¯*Ö¼—i+Egþô¿ÿ§~î^¦<çÐoÿ7ÿÕ—þÁÏ¢õ”n]‰—±.MÿíG_ùG¿ô…”híFŽËœJ |åFoáxy¥x ê023ò¤tmH®"[z•´‘Hô¶"󢑸ä9ŽñIZ¸WS)¼Íó²Ñ~ˆEêÌp jcÍSb~¹úTql{P?ë©i€ãz?©¸Lm9¯ÆRq†ƒè|Æœ1íCõ"Õ ’=±|®hÌêr­Õ4¨gà¼VÍ"ìy)æW ˆw„ m¹|(EñT;U|¦RµÐK5‰M³Nä×ËF™Nê)mëàZ±#ø\5 ¨¸©T,˜ÂZèšßLQÁf@/­«É†ä¥¦å¼Š›:–%“÷NS3ó<æ©Á%d`ÎU7Æ®¤¶HNx˜ye-Êq™‘RtæOþÉg±®VŽËX–õr\æTR°€ï²øÔ‹,Þªµ÷@º^²)¼þ2=&2‰xÏN?­Õ¶!y‰§T̶M2òÐòíÛÜ*ÄtT*Ù€ÍO½ËjVŽœâ¤œ¨9O—¡qs˜Blià—á%|Ʋ± TÒð¥}NSÎÔbLÔ6,Œ·Ó,ê‰f³~V53ÐtZ‰Þƒ´¬½7ï™43‹˜$ ¿t÷›ÚØÌ" † 4¾u©'Ô #50§RÌIc„f2jPš-nèàÉ燦f§¤òÄ‘Eq8ˆ!'M’º68—*LW!y#NïÈ‹’ß᥺-vJbDÐ:Ч(ÒZ©Åñ<‡ýhNÞÃç »¶öFc êUµi’(OòÌi畵(Çe–õµ77?õùÿâÛù‚èèŒu>9.cYÖCÊq™S oº|¯xÇ­_aõâ›^ô™Ž·Þ˜á…¸÷ÌePo¶õÒ”ŒØ¤«ÚˆÆvaë-P-íë6߯t¹Z»Ùc$ãÑÇt‰RßSGd3¨ûˆ±Ó0ÅMÔIˆ•$ƒá"Ö|ÌöiÃ@Cë´Q”´/MµMúaÕ,’yÍ̽ý?ýV§Cè틦JšŸ½Åj“ë¾ñõ¯ê*ªŠ—¶upƒ¶MÍy|&Ë)Æ‚Ñ3±”©x‹ºÎfAß³AWÓmª:/£¦…=©¿½•mÃi4›l^Y‹r\fVŽÎX Çe,ËzH9.s*á•—/¯õ?ÕÛÌhŸÇÒU'7*ÇKoö½Ÿ³] -Ò µ$©xiª¥šO—Q×âÏð£°b†äUm¢PCL—´SŠû™“ +Iíª#3>ìiÃ@%ï¥ÁšôêYDãQg/2ÕltlIüòEºÔ“lîM ˆ‚æ6[7xrÚ¶nжi  ß+©`œ¥j.M]õ—WSµšZ1]‰½ ‚nÛ¿P+§>°Z|¦ô¦d[÷õn4Hî­ŸÔƒÍ+kQŽË¬“£3ÖY希eY)ÇeN¥™`AóíVïÄ1q,½¾×ïÙgz^4²¹“¤1`¼‡ÇfŒÙ&Ížqõ¤°™ñ˜:÷ƒQ ´S‚÷”¨=Ò1Û?Ú«…dÒ“u¬m=Po°æý ç/F‚šn‰ª{×£$V;ðI’º¼Xg/ƒ¾¡œ¶¡ƒÛ´XÏø~Dõí¤ÑÔmö‰¡ÐAæOƒ5³ˆ}oJþÑ!‘)8PUI,5ðI’,¸ˆuö2¨†hÕ¶nÓ¶iÀÖ¥ É‚8P¢î”X›f®2ƒšã”n6GËI¹%J‹gr>kK‰ÇkÕýó˜éRS37$Ÿ4gy ‹jÑ9 YƒuB9.³]ŽÎX'—ã2–e=¤—9•ôv‹·ØtIj¾31í.$ìA¯Å‰ú-™9{µmÖØHHÝGΘ®Ÿi\?'§à1^ù‘24ãêIÍD vÄev= Rs8°ƒb:Á1öŠ«b(,^Û KRÍpi/Ñ{Š‚)]ê 4„~}üÛ>†²ÑQÖ¼ff‘ ›AC¦AÌ%‰Ï”ÞÓÀEëìeP Ѫmܦ Ó …¬%‡§¾×Nf…) :hÜÕ\Z4hù MRâI4?Ïgf#´öF“Oš³â!畵(ÇeŽ•£3Ö å¸ŒeY)ÇeN%½Ý^©›ïÇLĶR(äQ~€ 8¥ô:^¿%óR]Û‘ê)©ûÈ™.}åðÿ€d3@žhùänDR[“ùRÓµÙQì>ˆ-ªl= Ro8°+Ã~2úÇØn¥l=±`Ïfkئ<=±§µÁRo 1ÄL(!ÅÄæ`ÍûaqɰØtSq'¯AlšG±Q|¦ôžz.Šb½ ª!Zµ­ƒÛ„JØPJ—ê>Fó”­–®‚£0@£O©/<Åà©"ª)ìHËÆJY?Òcâ©49Ïgfã†M—0FéôóÊZÔm\æ÷~ï÷~úg>ÿSŸÿñë/þà÷òÏÿ¹óéû¾ÿÿÞŸ|öoÿ/þm¾Dþ±?öÇþÈÿìßú·þ§èõÇ¿íþ¥×_H[}ë Éq˲RŽËœJz»¼Rë½<¾ã})¸¤J™ñ6üµû¯A¯ïõ{6KÕµ©ž‘ö‹ºìL°õR§bU‹e“f\=©É¦Ù}> ]^l/U9˜ün «ÛŒ®Å-ܤ¯hÌÀà¦ÇÔS&kÒƒY¤†ÆnIÒ ÌcsŸ$ÍXÂ:{šNÛÖÁmâX º\Oƒ™ÙõŽg:#/ª 1C2©g!ÓÜ•.ÅæÔ3i<Ïgã¶m쓇œWÖ¢nã2ŸùÌgøêcNÈ·|Ë·p¢?0ÿÞŸú_¦­¾õ„丌uiúO?÷áwü‰÷ëÿäuJ·ö!ÇeN¥Ák±ÄWÿ´—àKsJÔOƒ›?¢Ôë{ýžÝlâx5ŒÒ»݇°ÝÒ&}dâÚÁŒ«'¥ªÆ£WA FÒVs±_eæä¦tQ´gÆ]šH“SbÃ@eÕ`Múá$³ˆ’-ÒÛ“„f,a½ M§mëà6ѽ«¦$Ga€”˜¤!ÖÀI*ŽcÆ}bU)Æ#˜¹5Z®lób…à[¨7ϵ¤4o–Í7š|‚<éôóÊZÔm\æw~çwvÿ}™sëG?óé?ý§ÿß Á·|Ë·ü¡?ô‡~ôaA»¸¯—yÒr\ƺ4qßþåŸÿé”níCŽËœJz»ímðš_4€øÒœ^µõ‚®GéjýžÍÝEóÅýé;·Ûa»ƒ ’¢qÿ ³;:i°٠Ŧ{Û!BÏ í¾°‰M—jьɭѪÌÍ ÖÓ†Öp ¿Ê&­¬É®g‘R%óz¥amµ˜H,2èÅ8CÏik-Ù¬ ÓR©æªE© õí¦ûÝÇ*Šƒè݆¸›´–Ö é®œ¹é¢hØ`ÈN«fsêWófѬX{£EǦK”%¥[¯Û¸ 6þû2›uóOÿþ}ê/ðÝüð|êþ7óûŸø7ØÆþè¢]Çež´—±.MŽËì[ŽËœJz-Í÷fmZÒ{3ÓÓ;±võO•!UU¿gëRüfÇñRµ°³nôK_ø¬®¦Kµš;jÕßÜM}ãë_.ì@6ˆ;@Ð5HRs#Pïµ9½Ím3Ã)½©U™éÛ™¡6 ´†£‘Ôžpr°&»ÖœEkÛ¢Ø"¨]ÓÕØåE±Ô 3ôºÙ›áÛ:¸A¦¤¯´ôú³™¡9U•À"@ÿ¤Õ€‰ø¤Rë”î;|®úoñ,µ8ñN¥fsã[ió&·7Ÿ&ЃÍ+kQŽËlW‘ùç¿õ+HÿÁzŽÉí¸ŒµAŽËX—&Çeö-ÇeN%½4¼éÆ]^|ñ:ž~PÌ-Òcbo‡ƒ²ÌOê-S3ˆ°jÒTl¦bc¦K°{ ÷Q0ÆÔ! Y·ÁÚ’´yÀ%Ôý#WŸd¡>¨£BqàÒ%ívHr¸<G–ã´Þÿ£]fFséRStx¬™‰µC´…N™{’ÙÎ tü>Qšòˆ¶Íû¥æg,‘…Í-(n4;i“ýh”µéS—%3jË)fè Ì`ñ4 Û:¸A¦¥K ´ìhMc·¨’”Ó W™¡ç=Í:dH‹-…9Sßhã:·i~žSñV’÷Ô… 7%ÏcP”=ó`óÊZ”ã2[Ô‹ÈPŽËX›å¸Œuir\fßr\æTÒVJ[¼éâÒ+/¨ßÑ™yRºJ!^µ!¼|3Q—ÒÛ9„úy ¨õø:¾M2’:fýLÁq,¢í.Òi?Þì{™¡¸µ¨+ÇrÊÕ¨S‰ÇHÛ$À¦‘’Z¯];È–M±çQYŽt4A·ÄâÍmd-Ö‚u">áIÖ¬à˜ÜSÑT­Â1ÄúAjRCÈÃ~i¬U ‰Ê?ï¤3W™M53Qu¦üÙä Þ;,ˆÓTJâuRLÁZä¥Tj MfUˆƒ¸ãe‹HWJÔ`†oëàZ±û¨:fG˜Ò4ÓŒW‹À{˜*ê5PŠ3EÒÕ¯„*hF o|ý«jŽ6ÐEì¯+gz³S›µá~WqLƒµ†¬½Ñ(´¢«8`P̃RÌpéLóÊZ”ã2ë4ŽÈPŽËX›å¸Œuir\fßr\æTŠ[)ý¤=‚”憄/⸚ÒQa] À‹²ö'È“JAz³(’ò¬•ŒÄžµ±Ú2¤"ñg°‰:3Õ¬ ìitµªXÛô3Š0®b‹XGJ]ž¬ifî‰m%7ö¼‡ÌƒpÍC‘ù¦šýB":EkÓ`5óƒä‡ ³¨9¥b¤ŒB‹M{xãp Qg,2VÜ ‹8 ¼Úëìa‘æ ßÐÁµ¢7ÐÊÚi}é Ÿí™‡ôñTD×JÖNªƒ &.ÅOe¨óMŸA¿¶‰ž¬AsÍû½ö^êi³B$ön4 ýeNÌ)ÏÌ+kQŽËÌ*Ed>ý¿ÿßÖÊqk³—±.MŽËì[ŽËœJõV x—¥ðZÜÛEàm9›/Ó®ªlôÅ~ÑwÝ“°ùÁ¶d±éy¡tM¯ò0Cõã`°×Â%˜ÍœPìBSxõ‡Áãüè5»?®j­à%x[ýêµ.ÁŽ8÷W({Šªbæ(Ôû8v`Sì~ݼ‡tÕ !ϪÑG‘m ÅY3Ææ`Íûé«f”†‚ Ͱ„"Ê›À®œ“Šâ8^b…)Qš™á:8/Ô¶yPiÈ&KAì8ÔŒ|é ŸåÕžë¢`vœ`L‚Í;b¾ÚµJf,ºæ)33RšÃãÑ…ÞœAºFdpu^Y‹r\fY)"ƒc¤¤"C9.cm–ã2Ö¥Éq™}Ëq™SéÂã22oØž±ø…ïÓhÞZŽŒ§` ORÏEÉr ò4ˆÒ¾ŠË|X.Çenuªˆ 希µYŽËX—&Çeö-ÇeN¥¯þ¡/tŽÿèq¼dÞ*}âîlã§ Ó\š>þm‹fOêÈhc YOóÇu°öü9æXsm¬ñ=kïpàìœ.såë¿m÷y²É]ºA—¹ñÛ_øý‡ÿàÅg¿Êa;øçïÿ§öâ;ßù÷ôGÿÁ¬¸ýö[Í·tüÇ‚ÛÛÄÎé2×öç;ß±&EÆ@—nÐe`“¼ç'Ž›ö1g»õïnl;§Ëltè]6É?yÏO,ÄÛm·ÞÜØ&Ðe¦]ºA—€MòÏïZ|ŽégöŸ\¼ø/fÅG?úAóíÿøÿÜØ&Ðe¦]ºA—€MÂ÷þ8è2Óƒ.Ý ËÀ&A—8pÐe¦]ºA—€M‚.pà ËLº tƒ.›]àÀA—™tè]6 º À&¹öØÃÿÅ:µ\ß»l£…r˜»ÐtÅ…òs§O©üÒ…³¡|3ð°M ËLº tƒ.sã/ž¿öäãB!l è2ãmo}³îÓRûöÕ¯†6cQ>6ÕPPC×—]h¹ò¦7¾^庺Cùfà`›@—™tè]æÆƒ¾O‰ñ·®>Êa;@—Ø Çn;ºŸ=½NYœR8Ëå¶F—¹öØÃZTÎýwÝqñ³§Cã€ú*8 ˆ£ŽçNŸ Ír^zî ¯Æiß;ßs,I-ÍÕ†ª6ê¨.éø¶(•‡–œÅÚ5kY{fʤó×%º#¯C—œ°w[ç+l$¥ $ T5[qaݺŒBšFc)аu”?æºÌ€.3=è2Ð º Ì ËÛ¯>úP(‡í]`(;µäM?=Smg¶™IV¦DÑÜ(šVg³†ËU¹©W#DÊK-¤E“?i@<©V¹.¥1…ÊsÕðô\xË<,¶±®\Wꋼ¤ma!©cíH6BÑX™ Qå6ŒG,§­¨6OGj>ÝLÞ`Ðe¦]ºA—¹.³Ý ËÀ<¹tᬲyfh(ÙÞO^ç¿åˆ²/‹C(wf’•y®ƒKYÍrMA%V¥fÇn;ªµˆT És`C#[™ë¥zÙÞWÞÞó^5ðÂ6ÚxÖE¦^æ›ð©ó¡¼jé¹ð–a×÷.§þkQ6©–få颌ԟG–GÞ¢f¡cJxÚ%SœOQ_k“‡ÂI'ap•¼òÂÓ¡ïâËWmžËáP>ÅÙãb3Ï‘¿“Èk¶t×ÁüA—™tè]æºÌvƒ.óÄ“Fîwˆè^Ž¥|úÊ™deJ‹n(átñE–>crí±‡­P«ËWKYTå|.uÌãi3ª* š'Õêë…mÔݺäÏÅÈóc·¡¼„oüטVž+)¾®P^›´yÑa1ñÈäÎ8Pø ¡\\ß»œú<Ê·uãË·œ­hrož£™¼À$ ËLº tƒ.s]f»A—yâÉFžFºs§FkÌ$+käá“í4ÃtÏG=C体ƒU•ê&zi½&ÏcÛí ¤x˰½—žîœö¤ÅÈ‹¾š{êâúQíÜ5¼ZºÆ‹É'¹rñë ðˆ…S&<,¡|Ež£™¼À$ ËLº tƒ.s]f»A—yâÉFžFºs§¥IìL²²F.®ï]¶Z-䥛ñ.£N±gì£z Lqê¨d»„”âÚÝÉÆéÎiOZŒ¼¯.é³Né°NÃ+¤½Æ‹7?÷'+~ÛñæñˆåÏÃÊWdà9ò½ZÜp¸@—™tè]æºÌvƒ.3Êt÷,,K±è~Ýi¤‘j|îô)õMÛëeþ C#«ÖSNr½ n•S©öŽÝv4 ®ymÃ[G ÔÌ»ˆ¢'šÈšíç¯æoæ•(þò<øiíkÎXœ}œt ”“Ÿ/™O*ßÌs5°åØK£‘p^ºpÖÚX/™÷é§{BV¦1åIêUccàyi£R7r4lh ߬døó2Z¸uÑh¡ªÍÀ×ñ‰¶7–Áñ–é®K5/\JGäÅØ€6”¹§Mb#è mc4¼JiàÛC¡ªM¸Dm?«exëh4öˆåoê¥òQ‘ÂÀs4“w˜t™éA—nÐe`n Ël7è2Sá÷Ð:°ï¬µ—©éÞ7¿ÙURZllÖÈyìfݎݬY¨]Š!_‹|ðSœ×ú¼Å“ÕÀ×ÊtEj–ï.«Ê]ê;/5|¢âÝɰp:äIC«R•5Ó ©Ä0ßÛÃWäA0«]M)í ¤xKE -OSe™š-Ý¢}‘ïˆ0ß|¨ÔÛÚÆË½ ƒ4¨E©ˆŸ/&ÕnÑÖJg\åí1wÆV4*’CxŽÒ‹HžÔ;LºÌô Ë@7è207Ðe¶t™©ð{hYñ·ë~œ+5ìv?M' ¿Õ–-Ís\ñ Fº„<TÉ¢®´„T%)–×îï=,a!žlÔR2ïXL\kó¦9LmäÚZ<™ÉO™Ï2Æ¥£šâ#«M>xÍ¥îóRÃ÷dîƒJl.YóôŒ˜ÕfߟhÔð¾µõ¹”} QÝ‹ûÍh!à-ó€\Ï>Z"òfNcÒFä= 2µ)’¶7Thí½ÄOŸÜðBÑð*¤F#J9Ú6Ö¸øö+’_ÊÒ·ÇÜ[QˆÀêøŒí‘ýÈ<Ú{€I@—™tè]æºÌvƒ.3~­ÛÙPe¤¿íU5,-ÉÛJWrj F{ ©ò’>)ãxmZèIN-Yr±#8ãÉFmÅéRŠ |Øáê˜ãaodæ6©,$3>ož8µYºL¹áâÝç¥F­ÑI?QË+OªÝ´ Ã6ÓhVÕˆF ï[󡆶½<ñ%˜ib’ïAÐt¡*à-káUy˜T/‹*ñ¡FE^ ¬ªfÅ Û€¡ª¸–F(ŠƒY¥”áöñÈ„Ikå¦΃¼">c{dùcÍö&]fzÐe t˜è2Û ºÌT4îÚ¿?V²ªŠXZî§åéH< ÷?”žDi/ô|;-LñIƒPâÉFѹ‹û“¦Ð>lÍŸíåJ†müàv÷¼K']:rq·tŸ—íš5Δ‘«3ò9=wîRûñ¾KÝ(’«3:Îå9B-ªŽ·,noGµé¤²\3í‹|ç…'s&Äßø´¼Šâ EFIhkY\ì(|¨0i­\ØŠVŸ:0pQòÇšå¡6,Œ!à“¿À$ ËLº tƒ.s]f»A—™ŠÆ]»ãiFñVXéúªSK`lœ!‰P~¥a•Î¥#ï{1"ñ0jþ>lº:/T¯Ö@-½—V^tÆ]•…ÑœEõkýña‹§ ©Ÿ¡<ÅÇùs÷¼K']:²‚0B÷y©áÓ8ªÊ%ŒAIg÷“®1½p ÞwàrŠ˜:cãÈäFX=Kϲ·,nï€Úøé…§f|¨`íÈ÷ÄÜÈãŸ/ÇKòPÔÉñAjÏt8® ZŽ˜äíÑV4vê¥ l8KñÛa÷ñµðbùØyÛ1KG.î–îóRÃT†,OœÐl ©üáʂΣEC6vdµ·Žá¼tà€,ǃ°Ô½4\¡ªˆôµ‡%ôE^ ¬×¨€Ôv£Þjl4UÙåÖEmkY$àWBU ßÍÏQ‘ÂÀs4“w˜t™éA—nÐe`nœüÐÝJŒŸ|üB(‡í]f*wíŽß §7Ð^¨ûfÝ«»jâý´wÉËSÒìQí5¬§m^\UU±Ü±ô£6o{u!iÌñ.†|°ŽEgÔÞj5~:HNx¢Á‡UUZ¾µ·Ží°ûø!™éž·s±täâné>/5Šgü©™ôc ÙÒ(òÊ:ÊÏPÕǼÕ¥Aè—k²ôCF}‘ï Hc7úù²ßðª1HŠÖh#,m)j×]ißmE£"9„çÈמ‡Ú°sÂè'hªw˜t™éA—nÐe`n¼ðÌ•ßþÂo|ïÅgC9lè2S¡û×ý»Üª¨!/5Šg¿rïP’"ÇlÀ°}"¤å9iÂéÛii/£í›Ç<Œ–ª mY|+Å??ïøç˜Â©ìˆ¼ÃVWÛòß—ï§/÷ª=ˆÐ8¾¨áîùÔÅ¿&.üœúÚ§z{´©GErÏÑLÞ`Ðe¦]ºA—€M‚.3~-Óp¸EÖKOÒ„ÍÓ<—p ÜO‹â}vJã†>õdxâaXÇÚ¼¾–°vŸ®ñ{ï< n,ÁPÖÝnPdiÓÀcY1÷óäìž×ǬåùKG¶ò³Öw^j¸ŸhVMtó¤Qm‚ž6Ë4©ÆIk ÅÊüqgtà]¼YÍ«|µ¸| ÕëjS …ï[Y8§ê+÷Š':•*‚,èå#oŒ ˆa ×ÏPîønt˽j¢ZkS<¿Eü ³¸"9æ36Ö®*Ÿ=\ÅÞ+” ë’fkµ}Þfà9šÉ;LºÌô ËLέ·¿ý o|½åÛº lt™©ð{h»Ùµ{qŠ4Ó¿œô[j5ð|L©ˆgw2Uy{£vŸâ3¦YœrB/— O< ë[›×¼’…ô M¤åLZ«cÍ¥ŽÅ1ÝUµQKŧ–‘ê@AöBz©Æ!¬E/­Kpr žûÉìüªPçKӥΤ]Œîy5‹uÔ°Š€ºë$¦‹Z:²9–G¸û¼ñå\ šY{M¡Ý®ªDè ÝüÅ„6= Ö]Þj¯’E]òý¸>]ñìäØ ú©ö ¸ùf;ÐÇ/¥½ç t ö¾4ãQ’åKóZu´Ýe¤‹ÒAH•½—Z¦åmÔØzi@^N˜ËÜÐÏ´0®Q–{僤iêhUf:µ¢4òÊÏš_›ªõÆÞR'È »ß­—f åŠtêáøŒùÈ)òÇšÕ•/ߘö&]fzÐe&ç-oý!- ]f8ºÑû©ÈÿÿpÐe¦Âï¡•`¤‰ejÅÛk»i6ÓM°ÝâÛ±åŸù±uiß1+ÙæU³a…½ôÜrxâaX/ý å†/$O«23gl4³â˜¶ü`éàö?Ý¢"6Y¹–·Ks˜¥¤3ÊÒ¹dª íîyÓlÓ-eéÈæ° å¢ï¼ñ° _`ˆdniÎ)tnªÕ%àíå••×NP ¸÷RkŒ£¹–.M‘½„^º¨<¼‘¶…·sO?ÓÂ@šíËr¯Úk”©âßþTWMÝ<ÝNÓ¾=Zû|Kø©QƒP5Ÿ±±ÙÄLÞ`Ðe¦]frÐeÆâ·¼¥@t™©wíúînÓ¬ à™€™5VZbɧíÝv´XP–≙^ªPUÖ=O<ŠåŽÕÖ’÷ÊRH¹öØÃÖ`áʾY{-6üZÞ ‘)NBm¦5N3󴱨å0CðA“í›^Öâ&V™7œG ’ŠMKGnï–¾ó’㳌Z N––Ï®ÑäXho¶=ÒîöR1 žkOZ•FNËÔ"SÜW9µMÒ^š/jÑᦩ¤¶»ú"/,òmÂJ½<-ÌQ¶ßhé䪴·‡ïºèpÖläü”Møöhåš7”{Š2ÜRnZßiû“€.3=è2“3­.óů|êS÷<øÉBù@—€M‚.3º'¶wÝô®]…†—4Õx8º¹·a‹rÉæñeŠ7ýÖ¸í¿/Óµë@Îûtˆ­/0”O…¯El>KgUKIOD¨š\ŒL꛵ Òý¼Ýµ}xôÚ§Ì㼦 kö±{æ ðˆ‰Ãâóö.3=è2“3­.£q&mZ¦ÒeôÌï9vì¶£¦ýA—™ ÝËêYí×Ú5Ðe¦]frÐeЧ¾vñ—áƒßýÎS¡¶t™©@—€nÐe¦]frÐe ¥IÅÃ(,o¿úèC¡¶t™©@—€nÐe¦]¦Æõ?êÊ7.~óéǽDÇ~òNÝ#~÷÷¿à奺L:Nc(Í.\—±—†| Çbã¤%rÃü‘oÏþÉÕ´*Çô×N9sfoo¯­Ë\ß»|nÿ/eŠ‹ÉMQ’ Báêh.ÍhSÛì¡AŠ}p7uO/½ïÒOóª7®-³§I¨3«€.³Ýüó÷ÿSÓ>Þùοÿ£?úfÅí·ßj¾ýÄñê7æÎÃÑûU¨hƒ.3=è258u<4yåúŸ?uëíoõ6±·¼õ‡‚´a4ti:K0žýÜÇÒ–ïþÉw-êJ¦Ú´qæ†üѱ¦^éåûï~_ÚÞùâW>•/áMÿó‹RÂõý¯š_4ºiö­éi³ud6uøÎvY>»cßu¯Ÿ:–Kö25 XüSˆš+o¬‰F}§ýK¯ýó¢¨3} Ël7?ùÜ´9Ûm·¾3¸=CÐe t™éA—©áºÌ•›­ØËT•°Úб¦Ë¤ÊŽjÕL¤£¥ÒÌÆtŸH%†½”å³|ñ+Ÿ²*5“ó?ü#o½å–[Ž9¢“3RtßïBƒ+IÛOž!\{ìáÆÔ2Íž?ÏbÚŠ "Ö¸Ø1ôJõ¨°ý —¢©Í 3s&´è2Û ºÌ„è½åÜéSE­ ºÌô ËÔ0]FfRÅ[ÞúCþ#˜øbåÞŰ*õÊËUøîŸ|WúÙ(‘*#i¹}ÔÈf×O{i¤Íúða÷g^<8c¼ÿî÷Y¡,<ÅãK3üûe>ñ«>vÛÑp¹ºZqç{޹¢½TUªYL«Ë¤BI:µpÁE–+,&ˆû*{I˽‹ÐK+Š),iÉp¬¯ +CºÌvóÏïZ|ŽéÇü]÷ÝwbVüôO¿Û|û‰?Ÿcè]fzÐej¸.#ËŸyöO®º¨¾ ¦¦Ë|ñ+Ÿª}o‹$¯ÊG[ŸQÁáRQª:É7+ôh¸.“¿ÌÇñÖ8×kÄ·¯~5-ŸV—q¡$(FúO;R)äÜéSi•Pc«R÷´ÜF …“€:ÓºÌvcçWÆ÷þè2Óƒ.SÃu™T›Hqñ"¨65]¦?¢’? ³n]æ‹_ùT¨®:é§kIòͺÜzûÛ­¤¡Ë¸ö±ôërÅ„ºŒ?,£Ÿµçóï¿ë›.hF.‚Ծƕê#>—L êÌ(Ðe¶t€]fzÐej¸.SûÜÐïþþ¬An:t™Æ\®„ò±ak’“°UÈR—¬—Ì>ßTÓe®ï]¶fÕŠ u™‹7Ÿj)>§cÔÜ3ù£á³ :©Ÿ.šÏ™Šk=¬ÙD²µÎu¨A—ÙnÐet™éA—©±T—ñÏõÑd .£îÙ8¨çeºŒK±âà…™üÛ¯ÿ¾Í Ë¸Îò¶a_°2¡.£† U|Èe©.sîô©ý±_³®k=l…2•×f¹žüí”üS ü#Z»ƒ Ël7è2ºÌô ËÔXªËˆ¢hÒÖeüäj`s›.ãËOuáŸÞ2»å–[Ο?t™ßG>Ö1¡.ã•´‡2]F¦©½p©.SÓ›.&_',ÓñýwÝ‘~ß°ð˜kL—¢î>…VÔ¶‚.³Ý Ë8è2Óƒ.Scr]FãX•™è¥aãÈæ¯Ëˆßýý/ÜzûÛÝgÙßþáÿ=8\ƒ(L¨Ë˜¶²t(×8&ÑeÄK7ÿΔ5é8}væÒ…³ê•Óø¼•Ãê@/ƒâ)è2Û º Àƒ.3=è25–ê2é—ã¦å&¾äJŠ ïÎþTvc®â«cÃ6t.&×e -ÿƒ÷Þ}äÈk–Êþ%/oÛøç˜ü“>Ct™Ôg!oó”!ë:wú”cví±‡CƒäBŠÌÐe¶t€]fzÐej,ÕeF}ï|À‡?ÞdÌP—±UÈj˺_~ùå[n¹ÅZúW¥4ž+)2¡.£l¨;ë¡z)ù›MiùR]¦ø½¿E\j?S$Wd4H·¾³k Ël7è2ºÌô ËÔp­¤öÀˆ?Qòþ»ß—–uÍþ’Qà tý¼þçO…*Q{( +Q§rooïU×_«V¸ð1ä uÿÞ†¼â_ß´Î¥&‚¸V2D%±Æ•)EfuÐe¶t€]fzÐej¸V"ËÅW.d¿ûû_H«ÚºÌƒŸ| -7§xUøèÓŠ¸ó?T ÿûP·ÞþöP•ÒÐe\ã¸ÿ®;¼Ðyå…§SMdB]F¸®QüSGšº&¯¸Ïj —Ò*qéÂY¯ UEl–Ẍ?Åc†"ÓºÌvƒ.pà ËLºLT—‘é¥W]ÿó§\.Éu « ºŒŽ)´öO®úP²\—)þ½êâC.£p]F&RÑçìç^=5f_üʧ¼\È™T„2]æøñãÖ8ýš[ÿ*YÐGTõ¦7¾>U7¦Õe4ˆ¦)R—ÄKÏ=áâKþ #¯’©ï¥ g½Jºh’*M*W¯0‹ðO<…GrxPdVáÌGO*1~îÉÇB9lè2ë@ï9zòl#Ìý£S–â§Oÿ†ªë{—½£aÿŠâ/N`üËþË•e;‡-qPØû0ñ‡CºÌô ËÔp]Æu“7Üü J.jè ŒÅÚ]Fx/5ÐàâÝ?ù.+ôª\—IUŸ½ýË|^?°ÁÅþT¯Zø*œ4 æú½¿úï$\®wÞüŽÙ›Þøz»AquCÞrZ]Fh"P¦‰ô¿ÝÅúì¹·Âz™«ÖÌŽÝs5Ðòßîl¼pø ™Z¢ÈL‹Ï~=”ÀÖ€.39öF­7ŸPsÆÿKrÓFV¥S¹(ºiù¬éÿ\¡ªÆ¥ g5Nñ)Ô™|äUœÐcAöSc\ß»¬*17½Æ6Õð-Óbñ7™‡ ímív#TµÑµÐ×t™éA—©á2Ä•o\|ð“˜~‘šJrE˜´¡ÚP®Æù ²wÿä»ü+„¦VüòàQ˜'9<°ã–Oñͧ/ú/ûÛ?ü¿‡kÕH¥™ÔôOúæ«c+׊®HmjY-1=Eÿ5ÚǬ¬qjÅÿ/]… ¦qø`ZÐe¦EY¨½_¡.<…³L&ý¿FÿY‰?µšÿǪZ«ž„ÛŒ²üùЙ|äUœÐ™š.ã÷ ºÍHË[»~†òY¡¨ÊÃ"ºµkœµs§OY³¥¢›±–ù Jg¿¿ù`Ëðé5Vü‹÷™›¡[¹¤P´ÿ°¾ûûzaz9äw>é¢Û~G͘ÇíúÞekÉoæºÌô ËÔHu½|öO®¾û'ßõ–›•¿&ÆP•=NÊ Õú ¦ÈX¹u©}@éìç>vëío·^ï¿û}r&4‹ë2öRãÛà"õ*G-=?ü#o=qâÄÞÞž®Ìp­:z'Õÿ^z“5ŠoîºÔ[³˜67°ßJùÔBž¨04sÔ@1Ñ›¾½”3z÷·ŽíÿïÕ2]c»1tƒ.3!þe[z× U;ˆi¡puÖ4ì§yÕF¦ÿC•þϲª§^ÿoZ{Ùðo‡3|Û8Þ%=Y¶1†ß©»-px<†®Aûšr—òU ¿Æ½e¾.›ÝwOŠŸÎ±ø‡I-Vk½¦œvlý­Cæþ´ƒP$•´4f¨mà'7„t™éA—©ñÀ¼uwo”©—uŸ¹.ãïõ£¬øÉplÒü¿s˜ è2SáÏË俱Ô¶ÞýP ¬¥,ÿtÀµýïG÷ûu™ŽU¢òÐÒÑ=}è¢÷^k¦^ðå:Ö\©$aÓyix3¡ÂFÖX¦ã0 °ÏS„fŽÚ§ å**]íZÞb-‹C9žÆ¤)“=,“ŸÇ¥Ø)¡\h/¥žËôrxžV9l{¹˜ 9E> —,:¿öŒ¤{µ±L5SÜTµbßôR]Ši³Ü³6áÎÄÂ%Ò^–ô6(N1vÛˆÆÕg…ú™¶/2<ž†ü©….oÜFÞZ÷ÚýžÍ¢Ÿ¡ÜOGmÛ8Þ2¿¾ÒÙå¹k®<àçsÌs›Tæ§)¼Ïèì«PË´uèÕ‡;|óñ+©™'Ãʈ¼»,Í,]¬k^EóÙý·¨+¹ZÈ@ÔÞ:æç t™éA—nÖ§Ëôñéÿ’ãž¹Êa;@—Ù–QèîÙ²()U¡^êÀ›¥wäA•ð;ïðËpO$dº·V­nµõÓÓK Ô&íÕ‡çEÊL\²¿¾wY/Óñå­-Íë@/4½´ÑÔQðtÂF³ŽÁgÁk4Â/½} ˆÊau±òb4läv~âiŒ& UO§Áªu KÎÛÚæ]µ“®A¬Ü¨Dc š,ÄSäªú¦!ÕKÇ›‰š3V®ŸÚ¾R-ßÊ­ÊÙªBå9òD-õÓ÷°Ñ±mTk£É¬—ÐOßüfyÇœáñT¬|RMd“æóQ xˆžác*>¡JŽYUð0Ç[æç4Ì®UØK­Ñw…1|:Ç•‡K?}^™^z_oúf•âc†ò"íØúþ £¹Ã:XºXìCÕR¼o~^à @—™tè]æ†åíW}(”Ãv€.³<£éî¹x.ìv¼Ø@i›uWÚ–§ÉdZ.¤¡¶w/”‹Ž¿¡k‰h(4<5ÊsËvž#<¯+fž÷æSÛêÚù‰§15ÏGak ñô’ÒQG~Rdj¦ð©Ãµ‡äuµ¾:Eí@{ÉÎ…~éÄýg¿Vžã-ƒÊзm&¿ú†ÄӝްÃ]>© Yˆž¶‡Ï¥Ñ:®qÇ[æëÊg¯íÃáÓ9¶‘Ìò^>u:‘ö¤Oï“ü)R‹­QÛ?þno¦ÚšH$±]Êý]fzÐe t˜è2Û ºÌð[g™î¹C­¡;okPË:ì?$«–x„BÇçUƒPÕÏÊ‹øÔµå4ðÔ(ïkAóá™dú;ð”Ú*¬¼ŸxÓ±¨?¡ÅÂâ Hqdá'¥¸ÌÚoïEmÀ!y]­oÏWÃYvÿ–Ò•¡oÛxáTWßÒxº.ÐÓ¼’ |dÆNLŽ"ÓË¢Jè ÔA¨ xK ªTbU~îü4ÉÒÓ1|:ÇÇ)v©Ózég~Z}gÖöI _ãoø²ü?ïΛéeqØ.eé~ƒÍƒ.3=è2Ð º Ì t™í]fø­óýɧ–v_L ÿ¥½ß⹫ö#”wà9Æ|Ï—\Ì%Úøºò¾îCžçK×ëqåÖ±IÑp¬ƒ¢'~–•¦å£¨­ÑOJM´ äkÙµ¾ ÜÏp–Ç–\|É—_[¸“¯bÈÚ—X:¦oÆ;ÉØ-dK+šic3ø¤¡¼†{R‹g-2)>ÈÀyíÉÒ1%/Ï•,cH o™¯«8»pÍ» ŸÎ±på“:Ú{Å1=Îé¸üy«â§ºŠøê4`ŠÊ5u[Úøòe!/o,³ÆÒý›]fzÐe t˜è2Û ºÌð[çF6¥[mkã÷î5\ ñaCR‘¢ö6f(ïæâgO{²a¦—y¢2Ä7U™{f¶:ÃJò¾>u1’žfÈÒÑrò‚g yßvž³Jšakiwl8Ö­¥qj®ßüä6©l 4SÙOJ1z¢Ö±V>$àí1­¯’ÌÔ¥šŸcË ÍjkNYEŽOªƒP娹Ë×^c©'6 ¬¸RcìrÔÌÚçcú‹C ‰€ÑhÙ˜ÝOœpøtŽ…« cê½(œ;×Dri©Acu}¸Âè‹Ò»„•ÈÆÎ2v«À@—™tè]æºÌvƒ.³<£hÜ7‡4`>l#Uèv8J <ñPÂVµ“¨4íÉcâÙB޷笒f˜?íŽ Ç:°µ,=5¯¼ðtžŒµ©ì'¥=QëX+ðb_Ïr‹k~Ž-é_Ý®}üdÈ*r|Ò°óS|êP^c©'LYíóƒÂ ¸3ž°%ÈòèµObŠoàüy¥öìþÔ˜¢í×AhVÜo¸ç³çñô©­Ê^jÀQ>j¯®Bº(?G­X¤oçÃZA—™tè]æºÌvƒ.³üfºqwÞq¿ô®:MJCÕT¸Â|ð¯‡(&Qî¹²P%¼6ïëÉR-JÝë-®"Ðp¬;ã]µ®ÚÈK÷a­c­ÜW߈[±¯{Rü`QÍϱåµ U)rOmò6ðÍP[{ÇÕ·4ž¾œ†ÛAŠØ ’w…–çüî­ØV+,²\ÜiÏî“FðÇgÚ§2Åæ­SXƒ¢ÿ®:Ù—U¤½º|«§ïœ^X\Hƒ¥{6ºÌô Ë@7è207Ðe¶t™ ÐÈo“ç? ,[îYš…ª )f,~Ç_\N»¶¡éx””5…*Ã…›ZƒCò.w;w¬;;OÍ$—îÃZÇÆì*¬Užíó¨]aµÁÏšÿµòáOŽôm[»l«¯ÏT§xå…§C­pT?¦èîgqW¤3†*á}ïZ~vŠg¡=»ðÍà-5`hSÃB!+ºçÊKÑ1á‘ô–¥.géêrÚ;Ð žøJkk1t6SAG^ é›]fz¶X—¹ò‹"®Â7Ÿ~\„Â]]f¹tá¬þS ÷ ºóPáðûõ.³Ý Ël€Zޘ⠕¬vk~}ïrø†‘4iIË•³©Äªd9­í@Sk®Æo•ÓÛ}áwüÅ©µ> ,ôH-‘~'E-ÚJNòßÛ[ðÛù‰»=É;³ …1OòÓd;T)Ž,–îÃZÇZ¹pÇj*@±oã<ú––?kþ×ÊmjYÒ@ß¶YÇÕ70ž²pʼntÞÚ’ã]Ú»B–«7YqF?5²ðÞe,=}c4Ó˜¡M´cpOÓymMmñóë'%4XÊÒÕÔLÕ«¸cSB•kÙ²bw{WmÚצ³.^ ºÌôl«.óÀ©{ö¯ß×M%Í<øÉl@ªvt™ÄþË÷XöutªªÝœm t™í]fÔòÆ@zo­7½T{¡›l½!Ø-~¸N“Ui"¡ÆVèU:H{u`wðG7÷òÇó‰dy&àUZ‹y%ý Í–#Ó ¨Ÿžx˜å ˜²‹EÝ~¢¥úb⃘·?{Ú¼Õ^šWùÈV† hýר˘Š˜»­m`…²óGênãhØPeÔ:ÖÊ…\Ýò¿n?ÈyoPì›î[[©zyc« ~Öü/–k4+Ôh6GÒ‹Žm³ôê³1uöj³4žºL¬L#k:ÕŠôbTo¿5¶^!ªŽ¿/‡õ¸Éä€]ìƒf¦—¡£±tv¡Ñ¬™^†5ÌŸÂÂ¥îc•†Z¦¥…K²º5³ö2y¨ ƒ™î'=2µ×ìFÚ7]¯O—ÂÁ‚.3=»¦Ë|ñ+ŸzÃ_/Þý“ïJË—â¢Ë8è2»†þµ« d5~爴|ó Ël7®Ëüø¿ë¾ûNÌŠŸþéw›o;¢ËµLï¡sËßôRì¢[íë{—­J?C¯±¤)hnÅ<ÁWš?q PT¡+ÁGs”§L«ËÀÌñÛ0” Ø è2ÓcºÌí·ß¾·Y»óÎ;5ï|¿ÌÙÏ}ìÁO>ðìŸ\ åm¦ÕeÞ°S5ö™¹.³ kÊ@Ö—ØèúW/€Ê³Á¦^‡$4œ'¿ ¬ø»ßy*”ÃvðÊŸ=ó›çÎÜ{ωÙòéÿÒ_<-¸ YßÛ×–aB—GovÉ_«?0!è2ÓcºÌAÙ!úÞ_t™t™UXS²¾ÄféÈvO°Ž©`XßÛ×–aB—ßhæý6ºÌô\}ò«ÿÃÿðßÛżaûoþ›ÿǧ>óÑàÏT Ëlt™UXS²¦aý¿üÆó±ºû·6ûQ&8¤äo_ßÞÿ+3£ð¾[Œêmû_¸ üëô>ì…ûïÇè2Û?Ñ\ü¤9À:@—9ô|ñ+ŸzàÔ=â›O?ªUÛ<û'Wüä·Þþö·¼õ‡Œ÷ßý¾ßýý/¤mu·w¨\—Yê€fI§°O<ù€:H}ó¥¹.c/ÚZÒ‘u —¡ÁŠØì¹a_cÓýÜǼeÀu™ßúâçõ_‚ß ê¸øå+/<­DQû2¶s§O©¶ñmaÖ½8øÅý?é>¨Yþµa†º§³Ø·Ö©‹~Nòð§ixr}ï²­Âo¬í¥‘; ¾rÕ<4ôŸnÞlì°F:²Ú‘u÷gj!E‘µÑòCÀRüíË^úÛÎ(k¼Gm zÇ^¬ö¦¹ •WíB@vó¬ÝúLºÌ¡G ¿Ý(4þLõ­7ÿd’ëß|úqš–‘[q¨*ºŒ^Z¹¤å†ýmk঒³Ÿû˜:ŽòÍ—V4զŃŸ| 8²¹wcSغä°M‘Ú[ÞúCůãÑ•øÈ#9rdÑ»Ãð«Ë¥YÚÿ+2µ U¢& \{ìáüNT¦ÑŠ¿7°qÌÿš43“¶ìàXöWQešË¥¨b7ÕúP ‚^zL‚ícø°†bXY…ŧ]|üö¯£mLý åK o è25L¯W|ŒtÉ®Ñ5Q¶ÝaÚ»_~³°>Ðe=ß|úq{ïxCý#<&¤ ÞòÖò^·ÞþööŸïðBÙûï~Ÿ76\F®ËüîïÁªdšÈ1gd>]è8Ê7U©™)³—FÙ5,UùÈ©²3•4£ñ5š=#c#ëÀ°—2‡^⣿¶ø›|2ÝI¿íævom…á¦Ðo»sE_-­—Lw“¡V˜øúúÿF25°;Ñ;÷ÿ¾ æÏn¨ÊÕ@÷²ÖFÇÖ^#„Æ£pñÂ=¹ÿ®;ld[øtföÒðfÂÖk 4² è…²Tu>¬PGoã#»ó²\šQK•ëg( lP$(¿z9–´;À.p}ïrñ7šë]fðl¿ø±³Ÿ{õïgËÒ'ML#Èeoü†Låy`¼.ãŽÝzûÛ¯ÿùS^! ;|&…« ‰Ô&,AUK»ÂG³ŸéyI Oe¬ÏúLz¡¾ôÜ©¦VÝyó°ù¯4],õ‘bÎo…² %¤>mèã7k}]¸Yñ5õµas%H¾åÝ*.'Eþ‹\"Q‰MTì»tX׿Ô&ä0ªªu_:¬á1';ØJÐe¶?ù€enÅÏùó ©:Ðø›Ö.¦ñb¬.ã2ŠLË ¯•…޾ AB¹SŒƒã«›ä»f\y‘é eø\Á[÷ðÌ™3º2õ*Wx°Ó{Ér ¥¶öí9¥JGþH‘Ó?–ëÏŹÊðU¤gM³Xa~Ö>x.'À€.³ <û'WªD£ªHM©•×t(¦¦txƒÐ±AÍÑ^¦‡¨( ÿ8X­Á(Üÿê߀5ywàÈ‘#º$‹ºŒJ($óEáà¥çž°òZbïÚ¤´,Õ Š \zXª2ŒÂ×›*G –:ßÀ—0V—ñ8×ÖîOý¤ †ë2î˜Blè2óâú½Ï|î{ßúZ(_Š?j>þã¥äßSc*]&—>`èØ æƒp)$”‡Æ\íFaC5$ðÇÞñ‡žNœ8QÓe\Añy {F-¿}õ«Ö+<ä’µTbª²^é³'® |°e ®hÈòOiåä+N·.ã5t“|ï5]æ…g®üö~ã{/>Ê ºÜt¡þ@ŸÞ½p•[¬ºÌ¼øòo;zô胟øp(_Šë·¾ö/¹^SGÄ•o\|ð“<°ÿ%¸Â»L¢Ë4d0tLè›hOçs©Á[n~oÀ„¾˜33”;ù³Bîá™3gjºŒ(jžä§Ÿ!²Ça¬¥?6Š_Ýâq¨¥g,s@–ê QcEÂWä´Õó-]f¹ªÑä¹áÚÖX]Æ×®i R¼AÞKµ^XÄ[ê Tm†“º[oJO>~!”ìÔ(\ž¶—â/.]f^|æsŸP ô+¿Úó'Ea¢!|³ùç¨e¨ËŒõM´§ó¹–ZÃáá˜3 ]&_» CCtY¬\?C‰}ÈÕ ïåÙ~úˆj­pˆ¥¿aöÑrQcu伯Z¦ã;ßs앞ÍD„¹­Ä,0X·.³ÔÒ¼×üu™{ï9¡7¥«>Ê ¦Ëßìú:¨‹ À@—™«è2þ,‰”É?“Ëڸꡃ·¼õ‡Þ÷û˜Çó2¾‰öt>—F°¡j¿x,æÌZu™ðà½?”aåþ8ŒÉ..¸øµø/í¥áÍT®D¥ÁÅ×~UJ¬ã:tñÒsOÜ™ü¡n™ŽÇ (Bnû :P[ÑêÏËhªF*éØz¡ËÀvc2èÏ!ÖPwÞñF.3]f^¬¢Ëø_Y¾õæG™,ÕÃ_þ‘ ®,—l\28]¦Ï7Ñž®8×ú0gºŒ L¾Æ÷ßý>+éø“ð¯ÈµÃ^¦Í¬£«öÒé7\—Y*\;X“.ã¤ÂJî¤U¥«NñoÏ‘åYbc ía½ã¨Ônx¨ýY§QãOº ¬‚i"«ì^»Wyo1Š#Øõ{P€.3/VÑeDªM¸Àá2ã"EñË€kÚG­¼­ËÈr ÅðÓŽ^8Ê7‘®=Ç*þ)ñÉ1gºL_ÚñãÇkºŒ?“ká+{íé4ç÷¯›QKÿ>šðØKcü6–ÛÈ֭ˈW^xÚ²¬|:‹@ÍywÒJi,¡=¬+bé7õ,E³X¯ôñŦÛltXÛÀ«v®òÞb>G° ÷V]f^¬¨Ëø·ÉžýÜÇ\‰ð59.|ñ+Ÿ U¢¦}ÔÊõÒÊÕ -÷GBB¹ãŸÜIø,£|þpP(7ü¯P×L‹É.ú™û)ŠÎxaãïdû£EeÁrå0¯¼ð´e2i²‘j1¦Ú…먟éŸ[ZJCÔXµé<i¡ã½Š4ª±„ö°Ýb–‡:”lvÙfb›ƒ.3Î>¥Í`zÙ‡ƒDº™ýã~†·ºv¬wö.¡Žjß÷Y!à£iW{mLÚ>×±HŸÑ»öØÃ©ÃB/Ów5VÛÿÖ]„w?M§Ât„ü˧lt˜-è2óbE]&ý(SC§pu#WL®|ã¢i ² )Ô4½´ò0ÚÙ›"J^ÿó§Ò*ᢌ,íØç›ðó*Ãäš÷S¹?®X…‡wÜÓ'O溌’ eªÕÏ¢h’ª6vòën)™”«¤µ†÷Uzª4DU¨e‰ò­8e_y¹áNæ9˜ÇV–÷m+¼Aþñ¨í³éx³P¾1Ðef‚m`]¡¶ßlcøf¾tᬕ¨Ö°—AÅ𭮟ÞF”YÛá ô~â£Ù€Â«l|kàX­ö*ïk/­°öÞÌH•|v{®)U©¼¸:‹jþž°IÐeæÅŠºŒpEÀ,ÿ“H“T5øâW>•v‚ÂX]F¸Ð ÿŽ›ßýý/X¹Ï•vìóMø³B.v|óéÇÓ/ñuÑJ–»ªÆ*Ô:U¤®ê8U‚ÜÏ|.­Ñªdÿô§Þ›¦“ïU ‰–“>¸a?CKN|œ¢ˆàÏÚÈÂï®…^Úo§C_Ëmdy]˵ü×ï†çŸù]¯qQI1ñÿh«UÇÔOÐ,_B{Xá_â+Ë<5V¡¦2“¥”²+¿õ¹ž¹’V9 ¸ù¦8„ª.3ì*³ý` v”?’–ÚÉV˜îU{ÐOïèÛ[6öú•ê¥YÒGT›ƒÍ˜_j¦K õÍw{Á sß, ?}›²å¤Ú0Š«³Ar÷`¶h×iKˆ°O5è2óbu]Æ¿>Ö,&R\1yÃþ<.%xÕêºL*4h|Ã_ª£½ ;|©ì¢öÖEíÓ6ip|ðt|Y>r>»°aÍ¥t¢üóe⎟þÉEõ~¶#”QXZbæÒ@‘´eÈL„e fj4'Õ)t 䃹áå!ñ‘Çæum,›’¥>X‰,è5"ÕGÜ[õò½*_ÂÒa…?g$óÁÓñead%V~ôoÿ°®ú{ï9ñÜ“¥ „kI51n ËÌ¿ÊòtÔªòKÞ¶¥¿iØNÖž ×~÷õkû3\ ÕªMxǨa‡…ØE”ûf婲#LYk4Š«³µt¯¹!5¾ÞJ´1ì p‹ÕyÔ)[ëYØ<è2óbu]Æ¿¦Dö†æw©ø§iÜÔþÁO>à:KP(:tžs1ÓÔöøŒUåÇúf¼ÿî÷…¹ò/–?®•Sßâ:074‘Žs¯ô²(Ê]‰çÏŸ?räÈ¢ibÊ4–Þ†¦¿úΓ7ûå¶Y;•RK¥F‹¦¯5¹‘kCrÌjÇæum4š%TÁäC.ÊÊëT»h·oAÑÈ×¥öŠ•ßë—°tXqéÂÙ¢·2õÍÏŸŽÿ×ÿü]õfAñz€¹ºÌL°«¬xåÚÆ«)•Þ¥1‚mï±×¯?/ÓØŸæÛÒ÷.£èaÑ7[šªÒBÃfLÛç%ŽÍ8нQ˜6aÎS¡Þˆjob[€¯:× WGçÑ_ÇY8(ÐeæÅ꺌øæÓ_ùÆEáªaÞ1R¥ÀºûKãúŸ?U,Vž‰Œ£Á}¢ôÃ;Ž£|s´ä?ù€õª=+$4‚.Ô%õjuR]FÈ+Ÿ«¦Èºu=ÊþÃÞºét†§åºg5B¹¡<Êjkˤ¨ñ¹Ó§R7jþòÂÓIW$¸±4Zš·/6Ö€>Zšµ—°tXC#øàB]4]hãXö¢Ÿñüµ3=¹¯Ì¼j®Îxƒ´×†A—™ ÚNÚ A³0lŸ¨*'Ý?öRãxGÇF踄]è¬ I ]Mv±M]ÒEßÔX…ª²e¦XûtFæ#6NÚxuô^áa1“K΢hßÚÏ?^|™ëX Î£ >íY8XÐeæÅ$º 8A—Žë2º2õ ÛÇý7?ýd mPg~ú½?aµëøópÐef‚)o«ë2žù|ÿ˜eS\cÑ·F4ṙâêlœÜ½>ìÛm4 LiºöM å°tØJÐeæºÌv€.9¶ÿy‡<=û‹ç¯ý÷ÿÝÿSUå¯ü½'ø'›6ºÌLh(¦œ[öçiìù¬Æ«è2ÆÙŸC2M$O¡mÆðpMqEß.îåp~áÙ˜.c˗ɱ!Áôçh`8è2°• ËÌ t™™`_<ÿFt™eƒÊ‹F‘æuÛ͵›ì)ä^þ®Ûÿ¾ÞÌDA—™ EÍÂÈÕ"®e¤ÖZ¸š°º.“;©c•ä)tQm)*GÅ–þ¬Yã™Ç|(®ÎÎÝëàzòÅêC¼ZŠ‘cF{@--]‚3ä˰RÒ¯ñj+–ª4—+J:°^ésO"¸”“Ψ¾Ã%* kAVÇP夡«-ÇMú­«†rØ0Êâ´%‚fa¸Hqçk¿fÕræ4c´fÄ¥edc/ºûïºCãûKi»2a/t©Åfôô;wØh½PؘÞÒG0Ï5NH‰õR“¦%6Bqu6iºŠn<’«ËÊòÇⓚJŠ~j]ÖÀ¨µ‡¾Z~ãÌ^¯üõ=U ¦£‹Ÿ=ÎåçÝOeqÞâŒ'Ý |½y4tê5r:Y8)~ÉègZžÒh³Ê ²š5f€]]f^üùùw—þðËÿñ?_ å°aV|^æýw¿O/üäèçžx^Æ÷Ð[î×C£ÔE%ž‚ŠƒRg4ï“_…°y,×ÕÕÊ ÏõÓ."XIú ƒŽ_Mo6³ʇí lÂ¥XvmCùh:HÛ(UV¡53¬¼è‰ì§wžä[÷´ÖÚ[•Ž…ãm¼Yqu6x1‹M- :ÑXòE </´.«Ò¼i_ï"Óqúfâ¤ÂŠÂ\:ȃfSè§ŸA7£Ÿ²¼»JÒñ+Ѱ¡}ޝ7œ5½gZ¹L†µÈÂà® ¥Hʹӧ¬AQæ“ù,éDO™z…ư³ Ë̈­Ôe`BöÙ8@”%*© )bŠòRSXežyÎiÉ¡5Љ:V–˜gÑKQn죉¢ÀqéÂYo“úŸ–ë@/_zî ä™­†µf"¬ÈÂâµ:ÖAƒPamu¦ Ý…‹ò!TBÎÛ8ò9]…Æ·UÈB<í×ÔöÓèäZ¡,»5¾×¦8 ‹L“¦åÂÜPGë«“%„<—“ÖÆ»ç1÷ÕѨߺ޲†¯7œ5+—{!>iÒ*[a¾FÃî뫜 k gÔ@…ú¹úÆ€­]`F ËÀPg`Z,qͳèíÀòáâêLAX==öÜ{ˆ²PÃ…9ª„2ÿb­O-SU*ˆkÉóJi¹¸ó毂(cxmP,˜fj“V95]ÆË‹ODªq±<àëÍÏZpÕQ¹u ã[<õ3MÏÅê'H BL t€.ÃA©°|r[3F“Š«›J—ñϼ3öcû_z’û³5}Á"KŸàð´_†ot6¼Wˆ€Ú[¯´Ðñaƒ–á£WjÔt›Q–ú?wlÔY³©ƒÏ eÊOhZµâ ’Õ: ËÌt ê ¬Že­–E+¥ÔÁRÒî3DzeýJ­­ðØmGõÒ¾º.ãJ„Æ UÂÈ-h"Ö,¦ø,öé3Cç k«ÐJ­AzÖü9HNQËp'ÚŠû™Î¨öVØXà–®·Hq-„P.|™é£4^è%ö ª=^ Ðefº ô:«`Y«eÑv¼ÔFeÅËýû¢Èð§?¼D?È3 ÿ¤Lžá‹KÎ*\)šTõ3mæ…¡±ã ‹Ž½×RBåÖ UI¼Pcê¸HÑÉ¥Ú„Pßý±_3£ûY Ñp–®×QKÇÖ’Omå²Tfr Éw‹áñúN€@—˜è2° ¨3Їe•éñRÒ'Àsï¶`áx†Ÿ1Åß{-MûUn Ô2/\jÁÉn]Æ W|l¤½^mK/÷ŠÁÌuÿhRú܆­ét€.«ƒ:°yþãØ>ü/ø(oO—(RÌð×”öU/L?¿3„n]Æý\“.ãÑK'u¬¶8µ F&¨ùC7ù'õ|ŠPÞ¦æ0@ ºÌ¼øÌç>¡ôéW~õ´ð[ÿáß~ãÚïÀ.ðÌ¿¿ö§ûöü¿ûæsO>ÐÇ·ÿèwÎ~â—ßõüCSd޾ýí?øƒ?ø‘|do³öæ7¿šÂ]øW ÿñl%–·Ë–JÅ ?<¸1¥iÿ´*‰9ÙÖ&Š3 _õRݪAm½Å:V[[lÚ·1ΚN€@—™E]v¾_Vä{/>û{_úŒ‚Izùw~øSVpñâEÛ]39 yÑe`GðGfdÇn;úÊ O‡N1ù÷7òOÐ4Xšö·UÙ(•a]ÆuâC: ×€uè2K?B¥y­ŸÁ¢'k:AŽf«ˆVpxA—™è2;º tSTdT¨*t€Íà¾ìMûP9¤Ù×÷.{›\Dp墦P(o¢F·.ã„Ü(J3*”ÁÿUt×5dš=TiÌö°F[—‘i¨´Ü—)«é2Z©5ðAÒ?›²Žd»ù7¶kNÀvƒ.3/Ðevtè ¡Èè2ÿ ÄÌä%ÛÂÓ~3½ }] ©V¹º’y¡1½{ÈÛ»uáZ€LÃj›Nåîjè¥f*Ì=OiÌt+æë²’Ð>§¶^ŸT¦Yl!æ­Ì¦ÐË´KŠû k¸±Žd¤®†*ØÐeæºÌŽƒ.£XªÈè2›DÙ{*m䦪;ßs¬øP†úzŠž›:†çA–¦ý*·¹J"î¿ëކŸZEho¾µµƒöŒ©4“šF.¶4Ö[Y®^ºpÖÜÖÏÐÅIÕ´¶€2ù 2|̆“°Å ËÌ t™]2P‘1Ðe6ÏKÏ=qîô©c·U¦í(9WbZæ(·¿ó=ÇÒŽ÷ßuG±ã+/<­1êÜÔ¾ïF~ª6K>Ëó¢l¤r-”§,Q#Û&†V:$&F{½*Lã&o­üÒ…³êâ/s4¬éSú9ä^&BÛ ºÌ¼@—ÙqÐe`)£] Áµ›Pz«ÀA€.3/ÐevthСÈè2 î¼ù¨ð)$€Í€.3/Ðevt(Ò­Èè2 üCL¡`3 ËÌ t™]+*2º @s7ÿ–vþ=Ç›]f^ Ëì8è2àL¢Èè25Þvóo!µ¿š`} ËÌ t™]Ä„ŠŒ.P䕞~Û[ßü¦7¾ž‡eàA—™è2;ºÌŽ3¹"c ËÌt™y.³ã Ëì,kRd t€Ù‚.3/Ðevt™d­ŠŒ.0[ÐeæÅÞ·¾öÎw¾ãË¿u.”ÃŽ€.³ƒœùèÉõ)2º ÀlA—˜è2;Èož;sï='Ö¤Èè2³]`F ËÀ:@—˜-è23]Öº ÀlA—˜è2°Ðef º ÀŒ@—u€.0[Ðefº ¬t€Ù‚.0#Ðe` ËÌt€.ë]`¶ ËÌŽo\ûë7öB!ìè2°Ðef ºÌ¼ø½?xX™Ì™_ÿ•P;º ¬t€Ù‚.3/>ó¹O(“ù•_} ”÷qé¿üÓ?ó^ øk¿ª`ž ËÀ:@—˜-è2ób*]ÆÙ;ßùŽk{‡0OÐe` ËÌt™y±º.™3¿þ+ÿñ?_ m`¶ ËÀ:@—˜-è2ób]Ef @—u€.0[ÐeæEŸ.ƒ"³5 ËÀ:@—˜-è2ób¬.ƒ"³e ËÀ:@—˜-è2ób¸.ƒ"³• ËÀ:@—˜-è2óbˆ.ƒ"³Å ËÀ:@—˜-è2ó¢­Ë Èl=è2°Ðef ºÌ¼¨é2(2;º ¬t€Ù‚.3/r]Ef§@—u€.0[ÐeæEªË Èì è2°Ðef ºÌ¼0]æžœ@‘ÙMÐe` ËÌt™yñ‹¹×äŠÌ‚.ë]`¶ ËÌ…ôSKïïý=™Ý]Öº ÀlA—9xREæï|ÇOßùO¾võbh;º ¬t€Ù‚.süÁÿçËÿàÞnŠÌßý»÷ø;ñþŸ¹ûçþYO}ðÏÿË¿ ƒ8_þ­s¡}ƒÞ{×¥?ürÁ¹~cïW~õÐ¥ÿ‡?ýFÄùƵßÑt¡KƒýoþeÁÑò„оÁ©üüÞ·¾qT¥¡Kƒvü¿ú»çCûµø›.óýïÿ_œþµ{ï913=ùÏ_ ×¶óÜ“üÐÝ¡KƒßþÂo„R~óܙоÁ/ÿÂ5{Áyá™+~ø¾Ð¥Á§?þK¯üÙ3açꣅö §¾v1Œàhͺ4XÅ!ti°Žø›.ó7þÆß°w›ÙüÀ Ë´A—9HÞýž´H_Û•¯ÿvÄøóÿòï-ÛOÿÌ{à ΗëÜ¢Ñ`{øÂ¿ ƒ8'~ö§Ûõ{acï[_[´l§>òóaç̯ÿÊ¢Ñ`«Å_üÛÛ@;vì]aaºÌ•+WÛï}é3áÚvî9ñ3‹Fƒ­&¼øì×-Û/ÿÂà Îçþů. ¶†˜ò£ÿð, ³ãÇÞFp4Ë¢Ñ`{èÓ§Ã Ž"°h4Øç0ˆÑÿ»õÕçVÊ~ÿKŸNW)è2É7Ÿùƒ÷¾÷/ò§£Guü±Ó§>ó¹OÔøòok<¯qé¿Ú·i´oÓxç?þçkÿúßüËоA;þ߸ö;¡}µ#^æñ¯þæož;3ßûÒg’¼ð̕оMCûW}(´oÓxä»ßyê·¿ð¡}ƒË?ÿ½Ÿ ƒ8Ï=ùXhߦñ fÑ\¡}­Bk ƒ8Š@hßF#¤ôÅÿÆ·þíGï{ÿð¯Ï|äÿwãß§K€t™ƒgï[_»ÿ,´™£GuÜPL`»1]FÆ÷Ëìè2suº ÀN.3/Pgvt€]fŽ Îì,è2;ºÌ|AÙAÐev t™yñÿóµÞ{Wú—zPgv t˜O}íâ/ÿÂp V]f^üëó/=ú+¿ú@(GÙÐe`nÜ{Ï ½ç´ÿz7tƒ.3/>ó¹O(ÊuufëA—¹.°VÐeæE[—1Pg¶t˜è2k]f^ Ñe Ô™­]æº ÀZA—™ÃuufË@—¹.°VÐeæÅX]Æ@ÙÐe`n Ë¬t™yѧ˨3[º Ì t€µ‚.3/VÑe Ô™C º Ì t€µ‚.3/V×eŒ Î|ãÚï„0OÐe`n Ë¬t™y1•.c˜:óÎw¾ãÚÞã¡ æ º Ì t€µ‚.3/¦ÕeàÐ.s]`­ ËÌ t™]æº ÀZA—™è2;º Ì t€µ‚.3/Ðevt˜è2k]f^ Ëì8è207ÐeÖ ºÌ¼¸ô‡_V ô©³†rØÐe`nœùèI½)=÷äc¡&]fvü‡?ýF(Ý]fÈ‹Ï~=”ÀT ËÌt€]`F Ëìè23]`§@—˜è2;º ÀŒ@—Ø)Ðefº ÀN.0#Ðev t™ÙqýÆ^(Ý]fÈw¿óT(€©@—™—þðËGýÔÙC9ìè207>ýñ_Ò›Ò Ï\ å0 è2óâ3Ÿû„R _ùÕB9ìè207î½ç„Þ”®>úP(€I@—™è2;º Ì t€µ‚.3/Ðevt˜è2k]f^ Ëì8è207ÐeÖ ºÌ¼@—ÙqÐe`n Ë¬t™y.³ã ËÀÜ@—X+è2ó]fÇA—¹.°VÐeæºÌŽƒ.s]`­ ËLÏÿõÿèïýá¿õ#ÿïÞô¦7þÀüÀÿô?½>”çwÿ Á8D ËÀÜ@—X+è2Óó‹ù¹×œý£üà.s]`­ ËLϽ÷ŸxÝë^wûí·ïmÖî¼óNt™Ãº Ì t™-æ·¿ðǽKçwž&ßúôéàór}ïòÇñ"”o˜s§OɇKΆòCĵÇÖô3”oÁÒ†3ùvzé¹'4ÚÅÏr©În#M{¢aG°m¬Ÿ¡6ºÌô˜.sçwZ‚½1ûØÇ>†.sØA—¹.³­üÅó×Lþ˜¹=÷äcÁó]C·ÈúÏ]öí«_ U›äMo|½|xÛ[ßʶý,–ê¥ §±TұǷڀ»Æ¬6Ò±ÛŽÊ™;ßs,”´±m,ãŠÞ<è2Óƒ.Ý ËÀÜ@—ÙVž{ò1>fn[³÷”&)aÎýwÝaÑe¦Â– ŸÅòC½´áÔ¶Ó¹Ó§¬|lÔÞ:’ÅÍg#ÙÙ”?/=÷D¨hcÛXƽyÐe¦]ºA—¹.³­¤ºÌÅ7¼an,<Û–½§ÜýÝæÙºÌTØô³X~¨—6œÚv²Ç+dy|Ú Ë83ÙH/=÷„yÂÃ2ÐmýDÔÛ<è2Óƒ.Ý ËÀÜ@—ÙVR]æ/_÷º¹±ðl[öžnp•­åèm™î€C¹ày™Éñ|£X~¨—6œÆó2‡c·MË—¢¸ìC£Éü8—.œ5Çß»a<ðä[þUJ°y†ìœô„ {}ïr¨Z…‹Ÿ=m›gìûLºÌô Ë@7è207ž|üÂÉÝýÝï<Êá°ƒ.sà(Ý¿^’È¡ËL…-A?‹å‡ziÃil§—ž{¢#ÇSÜjvP;GŽÇM¡Ê™ÃFºöØÃæ'yõL²s:˜öºsLÔÓNæa™]fzÐe tØ è2ºÌ†©åü[°´áL¾¦ÍkçèÀ’]Ïa#ÝùžcKý„M2dçt0íug¸¨7í£=0t™éA—nÐe`3 Ë8è2¦–óoÁÒ†3ùvš6?¬£gHv=‡ä§cZº²s:˜öº3ìaž´:@Ðe¦]ºA—€Í€.sàôé2×{X÷ÍÊ /ý‰‹Ÿ=­)¼‹¸ó=ÇÆ>¦®^©«ò*°rÈC͘¶5®ï]Ö,Âjõ3í«r-'mŸ|S÷W^xZå:Öô3mìå¾´œQÔQãKÎêXkñ“Õ_Ü×jà‹¨ªØFî¥[Âæª‘°-§í@‚f´=©°8 1Ð7_š %³—Fñ·÷áBzÙ¸ämØ„íöŽšÉµ7ÇtàŽ©*mimTn/Ã>¬'lu¡¡–îö€º˜Ÿùt\µþÅUù ] ˆ´‹õ*zhA ñqä›jEû"’á\·Eíb ï$¶Ç¼KÚ² (?Ý 6õÄV¡r;#:0D™o’zi#¨Ö†õ1Eq]êFVËü¬És2Ì›]fzÐe tØ è2N‡.ãÇÁjÉ›e&‹F¯5Ý×zQ{õÒhµ1‹«h8 Ó˜y2ïaÑ<´yƒÓ¡.Åél"J?C/+ë¿zh£éLùŒn* e¼Ö¦–Ê ÷D^YI->fÅ¥Û)-×K+Wƒ´ÜWV›šEÀ½ Žò­8¾[m€E]fŽÑpƃYÄÃR³tÕ6…–6ê1öš‡^9Jª5TQÉ2—l´Z‹g_h™í³’yo\ ¯×ºH”b,œÊ±£Ÿ;¨ÖŽÍÔ>4K-€>òðÓX—LzKá×oÑòu ßWrC‡(•°>Ðe¦]ºA—€Í€.sàø{¸?ø¸ß»+MU¡ðÝyçùÏ+/<íwäê¢ÌD3 ûCV^{8"Ǻè§hùæ'yJœ:¯csÀ~ënå'tñ°h|;°¾"ÍÞ™§ÌÝóÅÚO;½¬J}Cy_­J¡°ýÔÈBÅÕPZëíC•Ql`ëU‰ÜS@r÷Tî ?#j™–륕«AZ.Â)¶s‘†Ú€£|k?/‚¬ŽÞÆGÖ¬YÒöi輽Φ£ã´qŽši"\îXºá³øÔæ’oVn¦—^Œm, 6'ßcKwNÇ›dZUÛÃÛW0!è2Óƒ.Ý ËÀf@—9pN1«ô“(Ë7gšo¢§Ÿ¡ÜiÇÁc˜ªWÞÅK:ð¸ã`˜ó²Q׈o¤ân_º‡cq¨ åÉÒ»<¤5joA6Z(¾^³°jMmåéUÐw1ú––¥£­NÛ™ÀS£ö&)ülÖ®»í+˜t™éA—nÐe`3 Ë8ž6´ïŒý¶^÷è¡Ê(æ?~C_ëåéÖÀl¡8‹Ó‘{øòC//&·¢˜x:Wó0}˜"TYy8 Ý´Ñd¯”š‡I”Ÿ‘¶ÕÊk§Ã]’i¹S<mj>ˆZŒbÒžR ”'¨µS9÷9Ä'¥í|m„v/±´Á@ìLiœÚ™rå(õÐÏo1½7ÌCYºçkº€5V­„Sé×]Ú«ïbô-­‰V|@&`žëç=_;ïCð%ä}—^wîd(w–6€Íƒ.3=è2Ð º ÌŸýúï}é3ß{ñÙP‡t™Çï¹Ó2Çoëk÷ßžn¥…žbÕzùì“l7ñ5WýwæÃsw t©•;þ±”tiž¹ÕÔQËCŠKë`;Pmj ÂÒ¼4§¶mj徜4ìKÕ.aÛOV TNÍQ;G†Ç¡¶7D>Â¥ g­—¬Ñ±û¼têQ׈G¸±a<ÂjªFaãÔb+|éE”Ç3Ç/Éti®•¤£ùz¢?^˜ê€}cqKO‚¯W~6ä*ãÚáFc ¾+Š1Ù侂 A—™tè]æÆÉÝ­ÜøÉÇ/„r8ì Ë8~Ïݸu~[_¼ÿžÉä…V^ôgw¬}­ñÒH·þªR†¦œb—¥Câ…µ^– ŸÅò°4wOµ5¬Aèhå¡p žºÑȵ‡VÔQ WRª–†»¶M1z¢v/ þ¤˜o²0 3Ü7aUúÊ w^ jxƒ´£ ^2Uée-’5|ê4>›½«v„eæ΢ºáؙҀ¡Ü)n?s ÑKxpR Fä}MY³ï¥y½u 14Ïeª­a ÒŽÅ€O…»$Óì)|™KÝþ&)¼ª¸+6¹¯`BÐe¦]ºA—¹qï='¶;7ÞYÐe¿uÖv¨JñÛúÚݳݠë>;/b!•ªa÷ñ5W}-yþ ¤«íLèÒÊ(Ä k½„-!ÊËÃÒºØÔRÜIü³9áÁC‰®ÕÖ,l›bôD1ì^ØXŽ* (Æú&|ù¡Üpç—Zî°ú¦ÎèXñ®ÎøÔi|6~-Ví/5 >VK Ø™ªÅVä§ÛK½„'¬]¶r"ÃJ¬™?Óá_äÂPx.Ì<béÅX ø„h.;ãf:N¿ÕȲsƾI o¯e†*±É}‚.3=è2Ð º Ì t™m]æÀɳ "~[_¼ÿvƒ'¿k¿xóϸÖH{5° ¤æªÆ±éBþàŸe©¯jݯ ]jC9Å€xa­—°%„@yyXZwÛZŠ’=›×SSÿЄ<ñf†7Ö¤Êxµv%xæ•÷ £'ôÒÊÓzac9¨0`‡o¢§Ÿ¡Üpç5‚ U#ttUwX¦‰~ˆÃ§Nã0çk±’Wù^¨^î|‘Õ“g[x-¶B³¸3¡¤ÑKxpRYD(ÚVî‚……È#`/}pÛ3zë§lÔŨ—Ö«qÊVD~ji¶ ³üì{pjnø;¡LÝÕÌ—éUy_IXµákW3ª¢Ì¬@—™tè]æºÌ¶‚.sàèžxÿιp+Ÿâ·õjª »A÷Ü&-lô‹å5W}-!ðŒ%×j]jåN1 ^è`Ž9ååaiÝlj)þPsÛ.PUîd1Jr½´ò4ì^ØXN1P}¾‰Úb ï˜:ÙAúx±a߯4djs¾«îO…-¹[ákLå•ö1jÁQΟÆÄëç=1µ¹üdå¦A1àk"}4,LW Žã‡¿IŠvL¼ãöLºÌô Ë@7è207Ðe¶t™gà­³ßÖï¿…Ý ‡dÆŸVŸèÆ’‡š«Åü¡½Àb—F¹S ˆ `ÚB ¼ßDq3;Óf›í¹Ÿâf6Ì·Q׈07dù)žŸ(×ø„ U²ô³]~á{ 5nœß Ú*æ@¸ ¬¯ ½e:»Ñw1Ö¾>Š ½sÚµµ7Iááªm›í+˜t™éA—nÐe`n Ël+è2Žß‘‡ûø€ß«}¨2ìþ;OŠ,I3j£(a)¦N1j,PUî^H9ŠC¥Ô¢œÍÊóÒsKY-P¹“}lj®>h;ÐÏÐFxòŒ®&—ˆZôja÷öùŠÒYdé€}¾ ÍbUµd²q–pRjY4b›ãñiœY?k¡Ü¨EXîYycäIðØÊ×HpC'ÂÊeE•͇ ë2ü)5³ø„ÓaÝUåi­c}eÃ/ÆZÀW䕞.úà lïœF­ª|Õù—˜±±}‚.3=è2Ð º Ì t™m]æÀi߯;~ÿ­ö¡ÊPwÕæùŒÿ®U¦¤+í®c «Žµ,(Ç2„𫾖?x^‘æJ¼\ºÔ†rjIH[¯P¡gòµ@Õ–ÖÀÚh£0WÝÒè9éz=×Ujª—º§.¹h%Ó™U¯º¾wYU¨éÈz)4ˆçíj9Dß ø¼JãkêÐ×ÔN½ºx÷På1Ôr~÷Sz©YÌo߇ÏbfsÉ+ágS–†ÔHku‚,¶Š¡º§ž§]RW(øàb©WiãP5 aM;Ùn„ÚU°Ì_ ¹—ø\Ã×¢“è¾­)CpÄ^ŒîÃÀP´wœág¤Üµ0Ðe¦]ºA—¹.³­ Ëì¹.³]fzÐe t˜è2Û º Àî€.0sÐe¦]ºA—¹.³­ Ëìè23]fzÐe t˜è2Û º Àî€.“b_>¾(Ö ºÌô Ë@7è207~ù>¨Üø©¯] åpØA—ØÐeR>~óƲÉÿ´@ ºÌô Ë@7è207þâùk—/~þ{/>Êá°ƒ.°;\ß»üñ_ü@ø#â;‹Ec,ø·Ÿ`@—™tè]6º ÀL@—™tè]6º ÀL@—™tè]6º ÀL@—™tè]6º ÀL@—™tè]6º ÀL@—™tè]6CªËüè-·Ì…gè2° ËLº tƒ.›á/e¡|ÌÛ¾ü¹<Ø2Ðe¦]ºA—€ÍðïÿèwÊǼí±/}&x°e ËLº tƒ.sãòÅÏ?ö®¿xþZ(‡ÃNú9¦‹oxÃÜXxÆç˜`@—™tè]æÆ½÷œ 7ÞJøÞ_€™€.3=è2Ð º Ì t™m]`& ËLº tƒ.s]f[A—Ùq®ï]>vÛQqí±‡CÕnréÂÙ·½õÍâ¥çžU»ÆýwÝ¡8ho„rXè2Óƒ.Ý ËÀÜ@—ÙVÐevœÿâtÏ ÓA¨ÚM< ß¾úÕPµk¼í­oVÞôÆ×‡ò]æÒ…³Ú!çNŸ åS.3=è2Ð º Ì t™m]fÇA—  Ë8è29Іm‹Ÿ=ª&]fzÐe t˜è2Û ºÌŽƒ.˜\—Ñ8ó”x®ï]–ck¡Ë1Û2™9Ԭ骜íŇ t™éA—nÐe`n Ël+è2;ºL`Z]æØmG'mB\bxÛ[ߪt™PD‘áë‡/kº*g{±Ã¡]fzÐe t˜è2Û ºÌŽƒ.˜V—1icªÑ&Dþ˜cè2°k¬éªœíŇt™éA—nÐe`n Ël+è2;ºL]ÆA—­]fºÌô Ë@7è207Ðe¶t™G7ñN¨ZŠõº¾w9”×È'šD—yé¹'lØáîð.£z9Þ7”¯Î]f¸ócS5ûÎ1ðœŽm廓96V—;]«PÕ¯:”"k tDX¦—ùý²Õ¡Ê°qD(7ä†Õæ#㦒t#9áÝî&ë%Ò–èL=ñ |ÔU©ÆaÃËô2Ð[Ú‹FÍa°ezYÛ™°ƒ ËLº tƒ.s]f[A—9t³¾7þªùüâu%E±.úi¹µ V“6ÒéRS¹R#;˜hvk¯ïLî³2%N5OÌŠ9vºðZw%K¡—–cUµuùP6-÷Ž¡ÜRS«’…S&Kƒ¯L{QZ2uô–"¬+Œ¬ª´±¡@-ª³ýÜÎIÏ-•±Ì+µoD¾¡¦-ZdÚ€¡} ;êòÊ O§c¦&ßT:Ž ‘VaU¹©Wš‡{L¼dÌ%­Q¸{Áj8]`nò3È6~Ñsµ´^²â õ¹Âu¾hdcñº4”"oU:þŽ–àSO k3üª ïléh2§[hÝ;ì è2Óƒ.Ý ËÀÜ@—ÙVÐe»Wž©ÔÅ!ŸæfJ ¼±á ¡µÑKµ×]¾2%¿ÑWUþ0‚çªUާ.B6Žý”ÕÒ¿€úZ{ŸTù•™ú¯ƒÐQxwÞH34{i@<í›v þëe±Üqg4NZî‹åòAñô*eƒîCX²Ú óY¦^V"ÂCò\Z.CÕIgÜÊÕÑÛë¼ÛtÁíÍ®–aW8iKwÌVá‘_ºå<&j晼š¥“zã6rÉÚÛŒæ­|:0Çd«„H±Æ2ynƒ ÛøiXÜ /Y߃©UÈsMFXæ1tÒ]çiL4BÚÅÌGK•j…Ví½T®‘–»a.yhå¾·5|ÖÏpÇâjv/Ôì*Oã ¹ÒÕ®J‹•~j4ß?éIILJ>‚–<äb‡Ý]fzÐe t˜è2Û ºÌ ›ò<;*Ü¿9/$~~C/Ës'¯MÓ¡\Ô³…!(HÇT ‘ÖÖðÌJ¦‘د¼ð´O<ÑøVRCyÕÊBdÚ ÷aCļ¼¶.V+J˽c(×JkCyN•f§Fmǧ˗&¼{µ´BÏë:ðóX<F;ò^N´ïáâÈ.ÍÔ‚ðøÈ4`X²Ï%K«F…¨¶¡ËGµi¹5Î/Ï>üb‘å©åêé»D¾¯TâæcjV˜ŸJŸH–/M1´ªà†ÍRôAK±‹ï:³üzéÃßåÂtFþ,•ŸñÜsC»´è›¿¿é§& µK‡í¸Øa7A—™tè]æºÌ¶‚.37ü¾?”û]{ñžÞu™´3TFÉÓÂ"ifUÌ|F9œ–ûºj©²çÒÁU_x1龄Ôw£¶®ZåkÉUŽ?Ÿ«6‹ãa å†gàiLlLuÉ3Ãáøy §)ŵåôÒÊkée{É?jŸ'ØÂ§S.í…ÃCänÄ!ÅGå}X(dÅ]ê¾…é|ɹdø©I;ºx‘;ïåû¢˜å§ •*\å)z.Ч }÷HÏ׊ø°Åšã{ø5îøÛTÞwé°µøÅ‹vt™éA—nÐe`n<ôéÓ·¾ó/WmÃ;621 f7äd•üͧnœ‘väk#˜Ãá$¦ø°¡¼ˆŸŽðd–ãD_ˆ|óÔ4ŽÀ(ç—b± L±²tÿXaÛo“Ê"æ¼,U^ü<ºÔ.íâ’½°¦|ù)H=²ëúðõ¦ÓÕð8 ih¼?´‡õµºØa7A—™tè]6ºÌÜð„g`¹S¼§·ÂF/O3rM¡ˆgö6©ÌÓ¿³½]ºp<}pcéŒ6¬,$QÞ±˜\iĤ6‹ás)‰Uƒ"yLU+”iÉ5Å­F¶†IYys#!Ö—hÇ$°ôt¨Üô…h”3biLF‘0àî¹läëmôÅu¹V’ŠPa[QÑŸF¡~jü">WzQ¨ÏO(Çü”¥ŒÖh…i_kiš¦}BJ^ùS0>]:Žð¸-µô¢ðí‘N…/Y&÷ôžS;§Þ²½Õýþ»îPc–RëÛÖOåRÓ¡/ìè2Óƒ.Ý ËÀf@—9tÇŸf²pÓŸßš[ûÆ-»õU³¼°Ñ+OüÚ É¬òüÄKÚ³˜·²4±Yºpw)]ûÒuåNÞ1”[•{(Ó±c%ù\µY Ÿ+ªHú(qmÿoÍXw35«}Ø'§´ÀÒÈ«*ŒàÃÊÌóyS§ÃÑh6](¢ZßKc2 ›½ _¾o-/iÐü”yG#_¯•˜ìâ*ŒkX¦¨ªMø¼’õ²ª6éÃJ¾=‚WS¡a5£Ma&ÿCáÁil*—’ÍÒYIÞ·=¬Ÿ¸t¨"ùÅ»ºÌô Ë@7è2°Ðe62Ý|ïߢ¿úkj¥@é}¼ÝÜ«—´ËSÍòÂF/ÏfJC2«6îüŠ~—.œ5'eþøQ Ž¡ÆV[ŒpcC¶‡êb‡]]fzÐe tØ è2›Çoß‹¿¢Oó¢!åŽ%!!—ð¹Â¯Íüòm<³*ŠJ¿ÔÕvªcx›ð¿/¼&-ùÓìk©ŸÞ+$QżËG+~ÄÀkóúƒBaÃcÕËpl4vHЧܩ=ò¡Ü±Ã£ÜXŠŸŽZ;¾k':%÷ÍÅš\z(²4&£X+oà›?•½Y Ý&­²ã4téþ÷ØæïTYqc×h\)ëÀßRÂtí«Ò#¾RÇHãª6y±Ãvƒ.3=è2Ð º lt™Íã©]QhH³¦”¥ ¡u 7ýžYÏ[d3%ϬdÅTÙÝ'›{²šBä™^ÖËÃÒ eŒ±4žîg1bž\ÉBUÌ»|´bòßx6ÇG«É EçûXºC>u(w–h#„óâÙimÉ£ðj®p¦ óA6dº|EêeÝkËÔKU‰±Anãη÷Uˆ°ù Ë÷›ÑÖªüù%iè\°Ó Åúy)NQçÓR›Î/î™v­Ökµùnlwmý\ýb‡í]fzÐe tØ è2›ÇÓªðûØW^xÚ«ò\¨‘#vÓ¯fi¡ÿæ\²½´r³™’§:fa é˜áwìžÏÈŸP•Öÿ…ÇD¦ãÒxm.<ùƒ“>—Yȯ<¹JË}ÕyüÓ%ç1ôÑjé«§ÐZˆ6@¨5‰ÓJsmËOtîa o_Ë-¶m5K •í«Ð:湫!ÿó=PÄ(Ó€aáé¦JËG…È eù9ÒÎQmzZ—Æd>µ,Ì®Ðymí*Sƒüë„ÒÚâ™õ¾–ÐÌæU­·®Sö§£SÜóë(¿RVAñ)èÛ#°}U6j}@Y¾·ÛÃŠŽ‹vt™éA—nÐe`n¼ògÏü§?¾ a @—Ù<žÉt+¯û{a Jügèµ4!´ŽjÊÓ\BÇšQøïÌUbU:ñÌÊzÉ4£™N¤ $tTâ]t ÆZ²’gu´¥Yyží¤µöÓW‘Vå)¨X­,ïâaFïÊÓŽr[µú™.Y¦¾iáOÈÌýÔiY«PÜlp¡øè4ÙªSg¬DUÚHÞÒ e¹5|Èõ:HÓBsL#{IÀ& Ë5бû©½´^ýT3Êä¶yëþËBþo†Hm¬\¦6:6¾Ÿ—´ýÒ˜ŒÂ\rÇ|výôÂ<¼"]»DkÔÏ´<=•\¦ãPë§Ï,W¸ …tÑbß½´P«½ü·@çUkíÓ®ŽFÓ˜=÷!Ý„¡}ûªL%'•Û€ ¦Ÿz«R¡h¬ãb‡Ý]fzÐe t˜~ø>åÆßºúh(‡ÃºÌ ûõWïÍ3Ó­¹nÖuçž„rÇîéC`x2Ls©Ö:Ì””3X_µ·t(7­.ô2Ô·æ‰Ln_x­{­£¨µWï·¾µr½´@S¡çüŦ©²™§ ”Î5Â"SûTuj4®E¾ˆrÂE·Ä´“ävÿÿôIDAToà‘÷’€­ZÍB¹¨íp3uÌô(â§#Í´ƒåÄØÕv²,¬niLFáT4ì8X1¶F¾¯Ü4TC”i|ìM %U¡6Eq+ºí×EdåÅ+¥EφÍMîßÚWeÔ7W£:†c/vØMÐe¦]ºA—¹qï='¶/7.sPØ/`unèØR)å:Öý}ÚX(Ÿ,–;ªRƒZfn”£ÆJt­Ê:¦ yƒYiu÷a} 4‘šyëÕ˜]µšNÍìeXˆÖÛNcjí-Î"t7÷„2¨´\¨¥ºGkÇ0ø`¡ „ý`hØâ˜y ÕriäsÂéÓqúñ ­N³¨ÐKªR5 åFÜP{-¿}ÊRÔØö›¥Á!Jß·q`lˆ4N8¹ÅöKc2 Í¢¥i@绫¸ORä^áûïºcix}ó‹|Ÿ kµ¹jÈÝÖ1?5¦JˆÚ•ÒM~úD;í«2ß½Ö@ÚŠqía° M7yXà‚.3=è2Ð º Ì t™m]F±¦ßx7P£é”·„rØ´Íl¿O8ìhWkiÚá¡vt™éA—nÐe`n Ël+è20 tØ$è2°k ËLº tƒ.s]f[A—Q ËÀ&A—€]]fzÐe t˜è2Û º Œ]6Éüu96ÿt™”—ž{"ja€-]fzÐe t˜è2Û º ŒB‰Ð«Y2º l„™ë2~9Œ2ÿÚ`t™»ÒÇZíûw/è2Óƒ.Ý ËÀÜ@—ÙVÐe`JD-™Ü˜.£$VÓ¡Ëì&¦Ëèìo±.ã/wt]fzÐe t˜è2ÛJªËüè-·Ì…gì½9ñÒsOl8šgN›A›­ñ׎mα¤Œ\/ýxÇásLºÌô Ë@7è207Ðe¶•?¾ü>fn_þÜ¿ žlè2Óƒ.Ý ËÀÜ@—ÙVþýýŽ 3·Ç¾ô™à9À–.3=è2Ð º Ì t™m%ýÓÅ7¼an,õ²î—.œ UNͱ+>F”Îxñ³§Cm›´¯Bjs´pkÜ †²f@ -|Èhh]Ó¯)C-]£{^#¸:ät§íWÁæòåhurF…i•¤S/¥y?;"T¥x›¤[bi´ÅŠWÇ®.3=è2Ð º lt™ƒB÷©–ºëž5TÁœÑùÒY“µ?ˆ¤ŒKmÚºÌæŸ—Ñ®³©e¯±¨>s&7Í¢Úb®È[ùª–¢­¯LS„|Øñs4ÜV¼C(îOľ6Z‚½“˜ 9;iû†¤*kÓ”pÏWŒ@ЦӰ©ŸÁtêjQ££YˆRcºMòÁÃ;ßs¬è› Ó3¾Ôÿ`a9)vÍšiöPkø5ÜÒKoˆ·î]]fzÐe tØ è2…§¸„gGPB¢h(5 å+²¦a=cïÖe< ûXÄ$x•KK#ÖXT6 ™b…fy”VÑe”šZ_³Úƒ*.Ö+g†à¡0Ó€¡A µEŸ}[ÚÑÕ³öâ{µÖìÒ…³Ö`¸ÃK‘‡͆•éXÁ1ÒrYªe¤x3ÔHÛ{ðC›”ÕŸøð`Ê4`¾"KñIS*Nú,)5;û%A΢[iÆt?èe­™³âÕ±k ËLº tƒ.›]æ@ðÔ¨ö ÌBwí …~†òYÓ°+ê2ž)µóáõ¡LK(>‡²4bµEuãùp¦.¯’oWÑe|#ø©_Ç/ÿ}½ž½Lem-êîK >þöþXŸ¬¸gÜí\>ë#} IƒçÃ^ºpÖ'•ç Çl_Ô«àïùò*DR/í¤´g»(¡-´?çâ\ËŠ'±Èð«¬Ã1hƒ.3=è2Ð º Ìo]}ôÁß÷Ýï<Êá°ƒ.s l 8D¬é¶~Mî¨ËØó*ŸásRK#V[T7í Ákƒ†5;. jú£CmÈ›åþx@Æžˆ~^Úcz¸Ô>¿”†„"ÅG[ß²O¡3ªŒ¥ûp좄Mª.¾O†ËÁï²Ç  ºÌô Ë@7è207N~ènåÆO>~!”Ãa]æ@°YÙúÒ€CÄšnë×4ì*ºŒgÅó|ªiÄŠ‹ZOV‹ÁôG'ÂŒÃ3Æ€=•`£ùÇjŸ…ÉÙŒ.£ÕùñÒ§üŒ¼òÂÓúiÇ¡MŠ?@¡‘=¼í0úȲtߦåßÂhã¶…Ú”töü Z•~†òiðCÕT¸·ÝSŒ]Ôõ›_&eñÛ}øU6vdX ºÌô Ë@7è207î½çÄöåÆ Ðe»‘•å÷èÊL„ÿîTǺ-µìQ™’²Mk£ƒ! ÿÅÏž¾ó=Ǭ‹<§R_M×þÛ+£ÐÈ>‘Ðàéo¶µF[¬ßÖÛK#ÏôÔ7]¬PLòfc‡5†‡QƒìŸº%ù•ƱÙÓB{ô@ã§…mÌíš?ZŽ5åŽÓ´»Îo(±°(ZíA€6 ¬Ls)4ž1l4‹¿g­¾œ¥(ÖE¡juÒPøÓ Ú0¡YŠ/ÁšÙêÚ˱Y¼wÉ9IÑnyuš×n›YÖvrælÈ^òÓ‘zeøºBy¥ûpu|iÝSŒ]”®M›QûD/µííåÀëtøU6Ö1X ºÌô Ë@7è207Ðe¶t™A…nv‹ùŒÝãZâçÙ‚Y¸¡W²dƒ©°vç­ô0¦™îàUkUKïÂâi@jòÍuŸb7Kž ¹­—ÅÅÊB‡kŒ £gƒíüÊ‚©AÒBÍ.Ú9pÀ|ÓÏb/?›©Îâxf•®:wlxÄҾŸÝ<î-˜>EÚÀ×5j:ü´úì5µ.à§Þ.Ïi ¡°…§§)Ç•K¼—v :Žð–®Èݳ÷ åÓµlŽ»×^µ£+Â|Y÷--l°t®ŽOQ|ÛÂØE…öÚöûóÞ‹ ¿ÊÆ:KA—™tè]æºÌ¶‚.37ì×CÐL%V˜æ þ»PUé>[i•Hì\SHŸüׯ^¢lÁf\z>÷D£™orØæò P*qdöÒðf³¾X/”Y®h Vt„Q ¬ªÂ™{6”Å3ç¢H¤ñ­¶xÖ|uißܱáó¾î•ŽUhåfŠž·_Šw¬Sã[ƒ4ñž1¦¸ó^âJÍÀTÙO}“©¡ð7ÂãA°—é¾\‡.…¨‹·|iÿXÛË Cá§cøiµ%Ë‚²¶4üuà›GÖ´Q‹òó•¾7úC¤ááWÙ(Ç`è2Óƒ.Ý ËÀÜ@—ÙVÐeæ†ßãÚOÏ7Ò¥9RH$Tå}Ór‘æÒi–|žÕðd/Ow/~ötþ9©šÃŽ\¹0¡›¨Øwé°}aôüªÂY¦×˜} ¾Æ\ïpÿeʼn܇4 k8¦ÂZ•a}ÍÔ,• ÜO™óò6>`1˜µó;‹LÇÃ/cÔ¢<˜éiõ†Øç ¿ÊÆF–‚.3=è2Ð º Ì t™m]fnØ=®Lµ$ÁY]¼³÷ì1½ùNSÐ|X•ø¼Kï—â üªw,”;ßî6ª¥Ãv„1-¯ÃkÌ>œÚBüñ³° ?ãá„6«Mäx´Õ&_þ*yu1˜^«‘Ór5¶ò°´+W1 Ÿ"”ñS¯ƒPµ:y(¼¤¸?­6=YíÓ§Aö‹ÁôÈ„òßQnEǺñõo­‹‡BÁ,’6>޶Ahi4Þ‚†£q|"3½²ñŒöù XcŸúåEäíÀÆ6—µ,2Iôv t™éA—nÐe`n Ël+è2sÃïqk¿Ò¬åÛNñ7íºû·Âü± Ãý^v8>ÔÀüÜ–£Ÿ¡| •¤=l_EcÆõR›¾Ejú‘ù¯Z;yµŸñ°‘ŽÙ8 Ÿ­¯¬¨¸ Oä0Sã{•ü ß`Ò1Qmi¾Wk×EŠŸúáÂÁpòP¸o¹bâ vz‰µOŸ±.á¹ß絎).âȆDláá­ EÃB{ŸºfÃwÚRt"‚{|ˆÂÕ>¿)µk_øÔaä ¿Ê–F;\ݰt™éA—nÐe`n Ël+è2sÃîq·Â~ÏÝÈ^ò;xÏÊò;u£#׭ᙞ¬6]Jîíp<1ËoýÛÃö…Q4fLQó¾}x~ž&á®+i!E?]Í Xñâ8)íE-•ºrl@3Å e:ÎãøððúÛZèb‹mXhŸ®«hj¶_Å-Wg–ªØ3(nÃ#¶tºáW™;¦¨ ía)è2Óƒ.Ý ËÀÜ@—ÙVÐeæ†Ýã6n…u›«2µT³"ÞÀ{yaMM›ë¶I¯®ÛêŒßÖ‡ò"òS£ù¿«ùºÚÃö…1íX‹¤aÝ.ªMQ;0]I%ªõh§LÞÅh8Vëâ,]” f¡¼†97 ¥²˜ùÝ«ž‹ußBK5D?õ:U«ã¡H÷•{žúæûAž{¡°ÂâÙq²˜»ð ¤—Œ´ÛÅ#0<¼µ. ³HÚXø8 Thi÷áŠhÌ ÎLò>éÛ£xu¸F¹t­ÚZÇIè ]fzÐe t˜è2Û ºÌÜhÜRž-µôFÙÝm{aÊð»ð(´µ˜éXIHñOêZ³ÔÛ¥JÓƒåëjÛÆ´c-’†¼½¨áøhžZÆn'Ë?ÕâÙ©ŸÍ<o8¦ÂZ•±tQ6‚y5P&?å¼Ó~pcì^õu©cަ8š·ÔA¨Z…\òB?³©o.Ã]|íW“ø2ÓBõ§¢îpéÂÙF_Ãÿš›~ª‹Ë–>b3¡tªjxІ‡¢H1ø›! fÛá‹r•Ma´óð馺Ê:ÃA—™tè]æºÌ¶‚.37ì·q+ìÉ¡r-7Ho»—&ÃÿBXǹKoë•tù :‡žÆ{Â9vXõµŽ£Â˜v¬EÒ°€75 ŸÔ£n«sÙÅ^ú¹óÔ=|ˆI4³A>/]Tpc)6 ¬ÌÀ¨½êÒÆR“óíÇ"ü,è T­N-R™ïC+ÉÏB­\ø K-Ž‹&¶å<ÃÏõR:Æôu…}ÞE‘¾}8šÔR‹¿¸(_ËRkë_ﲱц¥ ËLº tƒ.s]f[A—™vÛ¸îK—&ÃïÂ;H…•|üöm½?–/ËŸó÷häëjÛFј1Å^›},þ鋞¿ô\Ýô)Ÿ®1{£J…µ*cé¢lsr6 ¬ÌÀ¨½êÊÝs«H÷žB->©eѺ”ìeîjíôùC¬R×¶ÒÁÝᩢ᧵±ÁRŠ^µPÔèÛ‡2$˜Cåï C¬=Ôð«ll´a)è2Óƒ.Ý ËÀÜ@—ÙVÐeæ†Ýã6n…ÓÇÔCUÿuw.m£rÝ^yáéZòÓ¾­÷¼´˜3{mžPµ‡í £h̘b‹­ÍÞAºs>ÜÓu¸’U\ZñtŠ"Ke# ßBµ-ÑfÔ^õE©W ß ¥ ?õä¹›Z(ülšo~ òG{Òf)>²öFºê”ô£LùÈ>Búîá[N]ŠŸOìÀ|iðP•ãŠ[¾Ï}-¡¼F-øÃhl­!‹òåtžßÀ8«™µ‘o¡*06Ú°t™éA—nÐe`n Ël+è2sÃîq·ÂþÑQ÷Ážy*™ U† 7Kﻩ)–“Ԗ㽊›¹6¦hÛFј1¥={žq]{ìa<=S©ãçÚŸ¦Ii8¶Ôç¥ Ì‡Ô±66 ¬ÌÀðŒÑµƒ¥ê›y.ÓÆUŽŸz„ªÕi„" ì xÛÂÙ ²Nw _„o§<Ú e¤_ ¼mk=z7ð–Ã%ª}ûpBÌaYñš5†,ÊÛä1Iñ7“ÚbøU6Ä1ºÌô Ë@7è207Ðe¶t™¹a÷¸í[áZÕÀÓ3Y~ëïélé]øRj™­Ï’ŸvRÔH†ÕÞ•÷m+:Â(J—ñOm(Œ¶êŸÑ²åÚÔ ÇF¬±(sLÍBy¥3Qcëµt"é®1DbhlÅÕi„ÂÕ%·âr,øáì¸ÏÅÇÍRŠú‹ݯ,F}OÊ–Fxé۔ܨI3þt¬¸®b(ôíÃáè jƒÕÞ=òm‡—.ÊOÇÒë"U¥k Îð«l©c0t™éA—nÐe`n<øáû”ë꣡;è2sÃîqÛ·Âi:”§ˆºçV¡Æ i@ú»hO¢tSžŠ2²¥wáKÑ"Ô¡Ù—\kìWY-ÈŽ;¦.5¦ú¤ÛŽ€.3=è2Ð º Ìï½øì Ï\ …° ËÌ »Ç]z+ìI¸L]ÔÞ°îfºN»¤¿‹–騰cpéÔKÑ6”†Í½ zHõw)u£1 W…ÅŠ¥ÃŠŽ0zržÏ˜bŽiœP¾ i —,uû–ÇÙh86ðD4•wicÊÚÁ „•M§ÉCPÜÂEÌy™âª ?õíü¹v(ÒZ›ÝüOÏŽÒ~ëÒ8e)Çn>4¤éôÒ÷ƒº×dô]¥¶åÆ¢q|L3½4¯÷­¡YKý å5úöápüSWfÅå,Ý¥Kå tRBUNññ¨¿Ê–^Îa!E›J¶ÛÐe¦]ºA—€Í€.37ìw魰н¾§Á4H1ySr•wQ‰Ê‡ß…/EC“WµÌMy`¸¹·ÌÐñŒÑMí•Z¸ÛÅ„jé°bl=9/ÎèØ˜!”¯‚¢gSËŠyŽ/¶1oÛ±vÄ–.ÊúªY(¯á‘o3Æ¢é4ùà5%à²W-‡ôS_¼¸V¤ŠôÙŸZÖí ¼Äη}ß`6ˆ_tmÉ@ƒ[³têÑ;’f·å¦Xµ5 <múöá(´ k+Zº£½(yª"éET݆èÑkXíš‚"è2Óƒ.Ý ËÀf@—™ºµßN稱²/çÜéSKû*Cðöž²Ž½­_ŠÜ3ùD5”'xûbc 裥iŒEÌ_–k £j-PI…å*Ã3ÃØbkSk±VÛØªjŒ [Ú×j³ÜáP¾ïXCm–z›cí5x(wÆ8œ¥¡°å4b›7xå…§ÛcæX{ÄÒÝš i9í@ÛŠ†.üFœážÝûp,šHKHW4d9†-ªÑÞ–ÐØ½¥Q> µlÀç˜F.3=è2Ð º l†T—¹ïÍož ÏvI—9(tëüªØ0.³­(•²@)b¡*eMº l7è2Óƒ.Ý ËÀfHu™9ºÌºA—º ¬t™éA—nÐe`3¼ògÏÜúÎw,ÄÛ‹Ï~=xÓ‚.3×e.~ö´‚&Òçü­D Ë@è2Óƒ.Ý ËÀÆxîÉÇ~óÜ™9ÃhßßÎt™ûïºCǣ؅/wt]ÆM ·ªë7ÿüºÌî`_ =–¥ß»t¸xé¹'‡ k*Œ3O8ŰÐe¦]ºA—€M’ë2:°’Q¦q|Ì­Ä2Ï7ÝüK·ÂÿتÒò´ ¶ž\°b‡E’ˆ¿Œ2Ï™9œbØ è2Óƒ.Ý ËÀ†±dÎ>•¾ v¦å…÷ßu‡78(Ðe¦]ºA—¹.‡—ÿâôßâ›Þøzà Ï>e/­Êè2Óƒ.Ý ËÀÜ@—Ëé2úÊT¬8@Ðe¦]ºA—¹.}\ß»¼¢ðqì¶£ê~îô©P>t8 ËLº tƒ.s]úøöկ꿤U„·½õÍ Ueè2p(@—™tè]æº ô.sH¹tá¬"–?¦t}ï²ÊGk¯Ž¡|¶ÔÖ°nÐe¦]ºA—¹.sàØºó=Çt|ÿ]w˜šþÐÅÏžV«jüÊ O§ åœÞæØmG5r:øXÔ×>jdh—ž{ÂÊ5¦©*2;Jz­£šÉ•x_sí±‡­Vh(«Uwý´îþ• ¢f>B:¾£õjý å†u … HZØC¹Söí«_ UEL˜“Õâ?CjkX7è2Óƒ.Ý ËÀÜ@—9p,¿UÆxç{ŽYÒ(ôÒ»í¨•«PèÀ^šJâXw«ò6çNŸÒA:Ú@®=ö° b“Ú¼–ËaŸBfÇÂCWV¥ŸÞÑZº4crêÀ±ZqéÂYkή—A®B—é@Á´°‡rt€õ.3=è2Ð º Ì t™Çó[Ùû¶¼ôÜ×o~6IJeå“© cLú€ÉÅÏžÞàu:°Vdêî-bbPú‰¹”>óbnç)®=Mãn6Zê°°$¹˜Õ›çéì&©0õÁ‚SÓÔ>wjÚ„S†.09è2Óƒ.Ý ËÀÜ@—9p<¿5Q&‹â•ž6ÑÁÅK8ÃÖLåªMˇ`)º¹­f¡¼ˆüÏ×t‚ˆ#î¿ë•§k´–5]@Ó tï`±'ŒD¾äu€.s(vlè2Óƒ.Ý ËÀܸ|ñó?õÞw÷;O…rØ.pä_S”3 Ë0=…V›ô¥cÉv‡.cO¸¥"ÃÝåEŠkºŒ•‡'n„E#]‹­®¦ hºî,œ°´õaáÍ#cÁ”廨ˆ»]‹ÿ ©­`Ý ËLº tƒ.†Àa©²ª”OT¨*K‰—Ž ö¡|)×n~ J?ï¿ëŽôSTFcRC 4»aº„ÆòJ…¶„›×Wš±Õå#jÙpo>¸À¡†ªu‡Ñ°`ÊäO¨*ân×â?CjkX7è2Óƒ.Ý Ë@ !pxªlCεýÏ7-¡/á·¿Ç´?ÿ«ƒ‡gg“^üìi•[­“7¶$9Ïê½q‘ôÃ>¶ºš.`íCá q]fÝ ËÀA.3=è2Ð º VWUV¡Áõ½Ëwîÿ½j“j"µIíÓF2MíOÙ[’œgõ6—º„ò[]>‚¡qr÷6€V}îô)­Î0ô2ÿd–ý5q‹ƒÌš9þÝÏm†Og¨Êæ åLÙÈ ;§²Züå˜íœ¶W„üï ;ªªµÑ~Ó¶LgÑKÓ+s4‚V›P.^yáiy’Ž£ÆµŒ]fzÐe tÔ¡´°VPµÌ3jK¶•a†ò±hd›ÂÅ‚šÛöˆRÜ´°ØØ’ä<«·‰Ò?ÆTÃVWÓ4NîÞº±Ü^^-¨â( ·šÂŸ,ÐAÚ×òv•äk´ïsµf!…Ö >¸¡î!Õ·Õ]À±^¡ðÑJåmîÒšt™Útµr—'VÔe4² ‘/6¨õ*ê8Ú*‘å;Ê(öŵ»ˆžÏ˜t™éA—nÐe`n¼øì×ïKŸùދφrØ,ÙÙéÖ€.Ó 6]­|]Æ“ÆZÌ™ yŸ² ‹ó1¥å^X;õB Tƒ°ÌâÚ]Ä‘Éâ8+‚.3=è2Ð º Ì“ºûèÑ£O>~!”Ãv`Év#I>ÔØêjɹ’ío’‹Ÿ=-ÇyÇ’ÿÜ¥It™áÓ©ªXnÁ”­¢Ëx¡LSYT¿v"ÿP›ÜóBáÞ¦r‰»šðÞKÔÖîÌÈT{¬þ—¶ú@—™tè]æÆ½÷œ8zôèÕG å°Xë¹®2ᥤO1Ì[i-Ð?ÒbŸªeàÀ>M¦Ù‹–»¤˜[•Ÿ¦QŒ®™Éu™¶ÉðdŠ­"-÷'YÂç•ÜÕ¥BÚØ¶m¬—™^¢ÎÀT ËLº tƒ.s]f»Iu™Ùl1k'ö—ž+Ô2½$¤åÀs{Í~ç{ŽÉ™oß¼¬Êýt\Ëèð¶cºZ¹oõ UEÜmuÌ 5‹¹Q#ÿ¸PþQ¦û÷ÿb—¬ø½B25ÃÒ^¢¶vGÛÿj$_¦è]fzÐe t˜è2Û͵ÇVkhÆŽ‡ŽÃQèösùWU ÿ3áNMøv¯.Ó7]­ÜGËåŒ"îvºaº×"òï¦1}¤áj:õjk¼´ÿwâmŠ¥†€.3=è2Ð º Ì t€©°´_V”6j¢@·–Ñ7]­|]Æ?yÔ'gx_ã2ÍÙŸIò¯ƒ ŸoZJmíE\š€è2Óƒ.Ý ËÀÜ@—˜ŠvÚߨ5=B By›¾éjå“è2ÂÆ—u|9‹péÜéS~œÓ­þ´#€è2Óƒ.Ý ËÀÜ@—˜ —$ìƒc)þå)EQ`•A6jºuë2þG¬5QZ>\Ô·˜%šÆÑh¡¤¸ö‹Ÿ=·ÅçeÔXÝÅýwÝá…KA—™tè]æº ÀT¸´¡¼ÝŸò¸¾wÙ3|YQhp…åÎ÷ûöþÖ*í_ú¼IßtëÖe„/G©ê¡½Ô5{ÞËð¾f5Ùř֛ÆJ8wú” Õ ¬¥¸vªD©£•hpZGµÞR¸{a€6è2Óƒ.Ý ËÀÜ@—˜TVPê.üX™¿„.¿0%µšr‘Ò1uÉË'Ôe®ï]Î3EÉ] øã6f®•䨣+‹vÉ,‹×ûº×d¬t•«JËÚ ËLº tƒ.s]`ZìyýäýUÓ±J^yáés§O鸖Ï|ÿÏ{/úì÷jH)c§³Iòrs@ ×e¬}M? +2SÉÛö¢ {ÆPËPPã°|3•„‡hŒÚÚóAl„üÜ×6Ÿc€Q ËLº tƒ.s]`|{ÿãH5§¯—èî¸n®ï]vßÖç^:Å@=+'u5T¥¼ôÜ"´A—™tè]æº ÀZA—™tè]æº ÀZA—™tè]æº ÀZA—™tè]æº ÀZA—™tè]æÆ/ÿÂ=úÔ×.†r˜t™éA—nÐe`nüÅó×._üü÷^|6”À$ ËLº tƒ.°S ËLº tƒ.°S ËLº tƒ.°S ËLº tƒ.°S ËLº tƒ.°S ËLº tƒ.°S ËLº tƒ.°S ËLº tƒ.°S ËLº tƒ.sãòÅÏÿÔ{ßýÝï<Ê`Ðe¦]ºA—¹qï='Ž=zõчB9LºÌô Ë@7è207ÐeÖ ºÌô Ë@7è207ÐeÖ ºÌô Ë@7è207ÐeÖ ºÌô Ë@7è207ÐeÖ ºÌô Ë@7è207ÐeÖ ºÌô Ë@7è207ÐeÖ ºÌô Ë@7è207ÐeÖ ºÌô Ë@7è207ÐeÖ ºÌô Ë@7è207ÐeÖ ºÌô Ë@7è207ÐeÖ ºÌô Ë@7è207ÐeÖ ºÌô Ë@7è207ÐeÖ ºÌô Ë@7è207ÐeÖ ºÌô Ë@7è207ÐeÖ ºÌô Ë@7è207úôé[ßùŽž¹Ê`Ðe¦]ºA—Ø)Ðe¦]ºA—Ø)Ðe¦]ºA—Ø)Ðe¦]ºA—Ø)Ðe¦]ºA—Ø)Ðe¦]ºA—Ø)Ðe¦]ºA—Ø)Ðe¦]ºA—Ø)Ðe¦]ºA—¹ñ½Ÿ}á™+¡¦]fzÐe t˜~ø¾£G~ë꣡&]fzÐe t˜÷ÞsâèÑ£W}(”À$ ËLº tƒ.s]`­ ËLº tƒ.s]`­ ËLº tƒ.s]`­ ËLº tƒ.s]`­ ËLº tƒ.s]`­ ËLº tƒ.s]`­ ËLº tƒ.s]`­ ËLº tƒ.s]`­ ËLº tƒ.s]`­ ËLº tƒ.s]`­ ËLº tƒ.s]`­ ËLº tƒ.s]`­ ËLº tƒ.s]`­ ËLº tƒ.sãä‡î>zôè“_å0 è2Óƒ.Ý ËÀÜøÖÕGüð}ßýÎS¡&]fzÐe t€]fzÐe t€]fzÐe t€]fzÐe t€]fzÐe t€]fzÐe t€]fzÐe t€]fzÐe t€]fzÐe t˜ߺú胾ï»ßy*”À$ ËLº tƒ.sãä‡î>zôè“_å0 è2Óƒ.Ý ËÀܸ÷žG½úèC¡&]fzÐe t˜è2k]fzÐe t˜è2k]fzÐe t˜è2k]fzÐe t˜è2k]fzÐe t˜è2k]fzÐe t˜è2k]fzÐe t˜è2k]fzÐe t˜è2k]fzÐe t˜è2k]fzÐe t˜è2k]fzÐe t˜è2›ä{/>{òCw+à¶Iû»‹±ÚO½÷Ý/>ûõð&óä»ßyêž?³8s³´ãÇÞõäã‚Ûpˆ@—™tè]æºÌ&¹|ñóv‡aØ.؃¾/¼ ÀzrqÎæmÁm8D ËLº tƒ.sãÁß§[½o]}4”Ã:p]ægßò–?ý˜çŽ1ßdüWÿj¨=pž=ú¥üÁPuàüÄüˆù6ÃÓú‘¿ù7Í7ÙŸb›²S§NYÌÑe ®Ëœ:uÏŸþéã³âK_ú¯Ïò·à.3=è2Ð º ÌWþì™ÿôÇ—B!¬ ×eî{ó›ÿòu¯›ð?þæ›ì»ÿíjœ…gG>ñ×þZ¨:pÞ÷·þ–ù6ÃÓú©ÿå1ßdö¿¶ûõ_ÿu‹9ºÌaÁu™_ÿõ_üË¿|~V<ñÄCæ›,¸ ‡t™éA—nÐevt™nž¡ËŒ]æ@ ]æÐ.ë]fzÐe t€]]¦›…gè2#A—9C—9t ËÀºA—™tè]`—A—éfáºÌH†è2ÏïÛ7¯›¦fÖ¾fé8VòòË//^/3k<±Â†åã[ù÷¿ÿýÅëLΜ?þÌMÛÛÛ[T4 ]æÐ.ë]fzÐe t€]]¦›…gè2#YªË<ÿüóºµÝrË-‹¢º=òÈ#Ö¸aGŽ ‡Œ,+¶?qâÕ;®¶…ñÏœ9cå:Xu™üÑÈ6Tj*¼råÊ¢QÅÐeè2°nÐe¦]ºA—ØeÐeºYx†.3’iu—<溌LÇV8ä1“ãÇ[ãGydQô—YTF‚­C— óúBÜR'sC—9t ËÀºA—™tè]`—A—éfáºÌH֤˜}ë;ßñÂ3WB9¬t™nž¡ËŒäÀu™e2±#¬f†ºŒ»ÔˆºÌ¡]Ö ºÌô Ë@7è207”6èVïꣅrXè2Ý,Êäbʵ›9ë2]&}X¦¨@¹¡Ë:Ðe`Ý ËLº tƒ.s]f“ Ët³ð ]f$kÒeŽ9¢ö¹²>]FÓÙÈoü5C—9t ËÀºA—™tè]æºÌ&A—éfáºÌHæðý22Ò$è/þ!¦š ãRÈ¿ŒKŽ–ðýïQZ1t™Cº ¬t™éA—nÐe`n Ëlt™nž¡ËŒd&ºŒÌ–GydQ”|ˆ©öº3Ñe\?:räÈOÐeè2°nÐe¦]ºA—¹.³IÐeºYx†.3’ùè2þQ¦ôC@öMcê9è2.ÊÈRQ©aè2‡tX7è2Óƒ.Ý ËÀÜ@—Ù$è2Ý,õñؽ5†a»`ÿä=?Þ`žÜ÷Ÿ]œ³y[pè2Óƒ.Ý ËÀܸ÷žºÕ»úèC¡Ö¿ÌϾå-ú?0+Î9b¾Éþø¯þÕP{à,<;zôK?øƒ¡êÀù‰ùóm†§õ#óošo²?Å6e§N²˜óý2‡ÿ~™S§îùÓ?}|V|éK§Í7Ypè2Óƒ.Ý ËÀÜ@—Ù$|ïo7 ÏøÞß‘ð½¿b|ïïý€uƒ.3=è2Ð º Ì t™M‚.ÓÍÂ3t™‘ Ëˆ¡Ë:Ðe`Ý ËLº tƒ.s]f“ Ët³ð ]f$è2bè2‡tX7è2Óƒ.Ý ËÀÜ@—Ù$è2Ý,Ä$s]æäÉ“‹9^kéŸå6S¡uÑÁ¢h C—ÙnÐe`Ý ËLº tƒ.sãÅg¿þ{_úÌ÷^|6”Ã:@—éfáºÌHÖ¤ËÔ¬6ˆË+ù'•b’yÇšåâ º t€.ë]fzÐe t€]]¦›…gè2#Y“.säȵÏíäÉ“‹¦¯µóçÏ[Çü¡˜¶Þ¡1­£Ÿ[þ„º t€.ë]fzÐe t€]]¦›…gè2#™Ã÷ËÈ^~ù墮ábª :òÊðý2°VÐe`Ý ËLº tƒ.°Ë Ët³ð ]f$3Ñed®°<òÈ#‹¢äCLù×Ę¡ËÀf@—€uƒ.3=è2Ð º À.ƒ.ÓÍÂ3t™‘ÌG—ñ2?~|QtSìhL.›]Ö ºÌô Ë@7è2» ºL7 ÏÐeF2]&ÿ(ÓÞÞžvþüy+É ]6º ¬t™éA—nÐevt™nž¡ËŒd>ºŒÌ?µde:qâÕ»©#G޼üòËÖ 7tØ è2°nÐe¦]ºA—ØeÐeºYx†.3’Yé2þ-¿öQ&S:Úó¢ËÀf@—€uƒ.3=è2Ð º À.ƒ.ÓÍÂ3t™‘ÌJ—‘¹ºqåʪñ!&º ltX7è2Óƒ.Ý ËÀÜxòñ '?t÷w¿óT(‡u€.ÓÍÂ3t™‘ŒÒet\´EÓ)$ÿ(“ .Gšb’­¢ËœúP(‡u€.ÓÍÂ3t™‘ ×eæ*ŒKGšÖZü»~ÍÒ¿ÍT4×eC—Lm­÷Íl˜V½h]±7n,F¿i‹ž¯õääÉ“‹¯5t™Cº ¬t™éA—nÐe`n Ëlt™nž¡ËŒd©.sãÆ}µ¡e®Ëøßºn[[õ8’höÀ óçk¦­÷mˆ“Ku™!r•,HBnè2‡tX7è2Óƒ.Ý ËÀÜ@—Ù$è2Ý,ú¿þ¯æ›,¸ ‡t™éA—nÐe`n Ël¥jvo}ß}÷Ù[Á|ìþàÌ7Ùw¿ûÝEélláÙÑ£O<ñÄ¢h6ö¾÷½Ï|›áiU¸Ì7YØàü×ïýý#|yöóÄ_ûkæ›,¸ ‡t™éA—nÐe`n Ëlt™n[x†.3ÒÐe†€.ë]fzÐe t˜Ÿþø/éVï…g®„rXè2ݶð ]f¤¡Ë ]Ö ºÌô Ë@7è20C¾û§B ¬ t™n[x†.3ÒÐe†€.ë]fzÐe t€]]¦Ûž¡ËŒ4t€! ËÀºA—™tè]`—A—é¶…gè2# ]`è2°nÐe¦]ºA—ØeÐeºmáºÌHC—º ¬t™éA—nÐevt™n[x†.3ÒÐe†€.ë]fzÐe t€]]¦Ûž¡ËŒ4t€! ËÀºA—™tè]`—A—é¶…gè2# ]`è2°nÐe¦]ºA—ØeÐeºmáºÌHC—º ¬t™éA—nÐe`n|ïÅg_xæJ(„5.Óm ÏÐeFº ÀÐe`Ý ËLº tƒ.sãÁß§[½o]}4”Ã:@—é¶…gè2# ]`è2°nÐe¦]ºA—¹qï='t«wõчB9¬ƒ u™7nœIloooQÑkëÐeÎïÛ÷¿ÿýÅëláÙʺÌóÏ?¿Ù¾)Œ‹Šl*]&ø¶ú9•¡Ë ]Ö ºÌô Ë@7è207Ðe6É$ºÌ7n¹åýwL…W®\Y4oÓê2òäÈ‘#æØ™3g¥+ØÂ³t¹á.¥vüøñÕ™Õu™šo*|ä‘Gº ]`è2°nÐe¦]ºA—¹.³IV×eR½CnV"ëNã§Òe^~ùåãÇ/¼Ù·×eäR"YþrifE]&UÙ^=—û¶x½o«H3è2C@—€uƒ.3=è2Ð º Ì t™M²¢.“ê 'NœÐK/×K+W/e“è2çÏŸwýàÀu™çŸÞ<9~üø#‚tþüùEéH›ê{só8uÇ]`è2°nÐe¦]ºA—¹.³IVÑeyä‘ý ½õ‰—žþùEÑ`[]—9þ|úÈÉ¡Ðed´n?Ñe;è2°nÐe¦]ºA—¹.³IVÑeNž<¹Ÿ¡·RôUÒø©¾÷×M>t;“Û³uê23|^Æ}ãsLk]Ö ºÌô Ë@7è207Ðe6É*ºŒk.gaV‘BvS—I?ÇÔñ‘Ùšt™?˜f†.0tX7è2Óƒ.Ý ËÀÜ@—Ù$ÓeÔxQ4ØvS—ñO‡­¢}¬C—ÑYvÁh•¢Ë ]Ö ºÌô Ë@7è207Ðe6É*ºÌÇ:Ο?omÐeš«]}ÄÊl]F§ÕLá:~ü¸nýôïQî3t€! ËÀºA—™tè]æºÌ&Y]—ÑÏÅë’)«WºÌK–yùå—¥ãmu]Æ=IM'ñÊ•+‹½†.0tX7è2Óƒ.Ý ËÀÜ@—Ù$è2ݶðl:]&ýf™=\]—ÙÛÛ“3næ•ÙñãÇÓ¿r5ÖÐe†€.ë]fzÐe t˜è2›d’Ï15²tÿ¦Xt™¥æŸ`jüÝñ6ù÷Ë<ÿüó'Ožô3®•,êFº ÀÐe`Ý ËLº tƒ.sãä‡îÖ­Þ“_å°Öýý2.…th ;¥Ëœ8ñêÿã²+·u|ï¯ìå—_vñ¨ÛOt€! ËÀºA—™tè]æÆ·®>úà‡ïûîwž å°VÑed»ued}_ÔÒ°Ut™½½½—_~yñ"³ôSWf C—º ¬t™éA—nÐev™uW:”¥+Ÿ_”î[ú]¶‹¢‘¶ÅºLúí¹}O´m]æ–[nÑ)ÓéË?z梌¬ñáµ¶¡Ë Áu™™[pè2Óƒ.Ý Ëì2+ê22ÿ¶™ŽÍü9Ù•+WMGÚêºÌñãÇåIjæÒâÅMë{îcáY—.#ÇÌÙ‰Šõ=J³Š.゚L,ÎèkÏ©^.Z7t€! ËÀºA—™tè]`—Y]—‘¥*CjÊäÃC4£lu]æ–D3jXßw»,<ëÒe:&ë{´g]æÆ¦g-~!”Ã:@—é¶…gè2# ]` ËLº tƒ.sãÞ{N(a»úèC¡ÖºL·-6O¾ýG¿ó{_úL(œ—¾ò¹?¾ü•P8þ¿_ø£ßy8Ξ‰8XÐe¦]ºA—Ø)Ðe¦]ºA—Ø)Ðe¦]ºA—Ø)Ðe¦]ºA—Ø)Ðe¦]ºA—Ø)Ðe¦]þÿìýïÏmÇuß ê4Üó"È-@‚•™¼@FL'ŠgôL#!éŒÕ7FgDuÌìhD1‚¬ñ5)zb[y%9ÝrS¼êDmƾ‰¢–/Ò°š#Q¸#¸ŠGs$Æ ô+¿á+ç˜/Ÿïs¿^Zõc×ÞgŸóìç9ßÂ{W­ZµjUí}ªÖÙçœÅ8.cŒ1ÆcŒ1G…ã2ë㸌YŒã2fkü«ëŸû™¿óÓ¯÷)ßcŒ1Ƴ ŽË¬ã2f1ŽË˜­ñ‰G>|rròâW¿œò1ÆcŒ1«à¸Ìú8.c㸌ÙŽËcŒ1ƳW—YÇeÌb—1[ÃqcŒ1æ˜yò“̹uóå<ÿìS’4Æ,Æq™õq\Æ,Æq³5—1ÆcŽ–'?ù1ì/˜Þõηw21»à¸Ìú8.c㸌ÙŽËcŒ1G C0W~ð{/~(Ÿ§ïzçÛ—1f—YÇeÌb—1[ÃqcŒ1‡äÊ}'ï»ç=o¼öRÊß û6õùgŸ‚þ«?˜òÇA]hØå«FŒËà5åÇeŒY ÇeÖÇq³ÇeÌÖp\ÆcÌ!Á> ÚøhÆfÙ·©Œ‰¼ïž÷¤üqPZQ•—1æ08.³>ŽË˜Å8.c¶†ã2Æc‰ã2ÂqcŽÇeÖÇq³ÇeÌÖp\ÆcÌaÀæ0Øqõáy¿ƒóÆk/]¿ö8¿=zàÊ­›Ï¨”@µÞ|ý6Ž!@±(pãékÒÀ&ÈW^ˆbh‹_G­XÊ*SÇÁe+üÃ#ä@?Z¡~ Z”‘…zb)ý@ ¡‡Õ“ ˆÞ€¶ò;Y¨ ©iý ecà¸Ìú8.c㸌ÙŽËcŒ9 "¤ô¾»O‹Üxú ðÕÿùÈ#óÖÍgxÀ¤GZ˜™40Ř…"QòÊ}'Hu™dê o¼öRi# Œ†”)uIy¬ÀJì¾X î¼òBÙ:^Ëò—1fß8.³>ŽË˜Å8.c¶†ã2ÆcÃ÷îþÅ´7ž¾ÆÓh1jpõáJˆOy(Ö€×'?ù1hÀ«ŸA&xª¼BŒ9àùgŸ¢=ÿ¢Šb@´­eê j]9ׯ=Îð,„BvMS? Ð4*êŸ[7Ÿ¡1Ò†"ˆÉlVϱòòšFôÄŽ8.cÌap\f}—1‹q\Æl ÇeŒ1ÆÆƒÕ¨…c°†á†”IDˆzpÌLåjHÕï¼òB)‰SH–¦2Y1Ø“òAé  áj_ʨ …KÍ ÅG—1æ08.³>ŽË˜Å8.c¶†ã2Æcɬ`Gw`N|ETƒ)í¢z)™ +sfÑ šÆDÊèI•ªå­&˜_ý¹™Ô"mh‰æª¾2ÆÌÅq™õq\Æ,Æq³5—1ÆsH&ƒo¼öJIwhE"ƒýçe†@ÈDQŒe0§cjA®ÜwRþ€1@£(Q’¹bÖó2´üêÝ_,üæTT‚̪ÉÔ¢1fŽË¬ã2f1ŽË˜­á¸Œ1ƘCÂA5Øñäip„1ŨA'.Ã/é@€¡¼R8>\Ã0D'Ýßoê˜:Èõk«;0&*4ù1“Üyå…+÷”®@Nky£¬Sl‘6Tý  'µhŒY†ã2ë㸌YŒã2fküÎo~ág¯|àG¯~3åcŒ1û€!ƒ2Ø¡G9ô+¶ Œ;´"€!$FØPŠzP™j"7´LËõÓ¿Ê~˲Úo»$ óAѕӿ֦m ž—QÝD”¤ ¥=©EcÌ2—YÇeÌb—1ÆcÌ1ÃAŠè G)¿Œ;´"Ô€Ò[7Ÿyè+8`P#‰é?‰R~•ª©‹QÓ|œ0&S%CøàOú ˜QZÞò-/»_BJ zR‹Æ˜e8.³>ŽË˜Å8.cŒ1»À¿†Õß¾ž üƒÛô¹ºÙÏ?û¶š„?íSNü ‚-Kq LøZ0d‚Õ (ã­H5¤XF Æ‘ )8Ò¡jê.$…èN˸LµUµ¼qå¾äOzІRAs©EcÌ2—YÇeÌb—1Æn,SæÅ¥µ 9$ÜÆ”[)³)¸fâ„á¶V)m¶9µ˜4¸ÕL³#št+\Ç…˜$aJy ¤+÷ T”?¸Ë˜ô”ÞçŸ}*žVM'…ÿÐ5(ÊÑW“’%eT廿•«>Yù˜ Ðkä#•Ì (ƤÐ;ˆµú˜ 6Æ,Æq™õq\Æ,ÆqcÌ!ÑF4m..­-Ù!á6Æ»ôÃý$. M/O9‹p aÀLþ‡Áö§Ü<{Äׂ¡º(¦À!À¨]=ý!Æ&pŠ×xÉS¬zÀŽò)!3\0¾Ã+Œ*µ8-SGÀ̉M Sl4þ¾ &3ñJ8÷`í[­Þ1±®$Upr"ÑB ¢h<ûˆ*‰ïÈG^•a»)Ó³ÇeÖÇq³ÇeŒ1‡„‹~>¾¸`ƒÑÙBncâþçØÀtB÷ãör.¨ {–ý$gQ5.“2 7ØÇ<â«såî? á5N$å³èúµÇj‰—Ì`8 ¨.aÔ†’i–Ò{*å1exC+ #¬’21 p\f}—1‹q\Æcv›çÖâ0psÌ»ôÝ=p€qìì'Ùz ÁT3 2|Ä÷ŸER"åW¢ã/ÕÐ fBgp'›k™:ÈÓ_Åê7Ñ`þHÓÓs^ ¹´ª‡—sëbt\Ƙµp\f}—1‹q\ÆcváûùIvJ\tv÷ÀÆÑq™cƒ#X}‹q™VØâÈáåܺ—1f-—YÇeÌb—1ƀ맿ÅËß¼¸ñôµ+÷`G×ꎂÏáC\}øÁêžPH(ÂX„†ÔÖ,Ð.*âÇ8 ò´±‘ñÛ€ÌCG¨0z`PÒÚB@g4† •ÀH”&{"è”^ú uØ€Ò”?êÊøè–èX¸%Š ŽjUóÕÕ…N:¤T5IËKl jáìÖØVÒÕÉ`=÷ÉÐÃêe§F¦V”)5tö“GëŽË\20Q9Lq¶àXùÊ4\€ð/F]G¸{ðÚì\GƘY8.³>ŽË˜Å8.c¶ÆŸ~ÿÖ 7þ§?ÿÑ«)ßìî±}Õþà [ˆ(‰)ó%“–ÈØ1ª®â„™ÕÝf.ÖñÊ] NYŠU;{ý„Çeƒb,åd˜¹À*V”ž”rƒ”œ Ð4K«bèT,•@ô' gRæ T‹Ž³#jrv’ÌÁ Ù3UiC&†„GxþÙ§X—ªxÌÁbßˤ¡¤1HªÈcm•%X §V¼v(ƒœ(Àü˜#¨?M¿j&A&Š òͦH3Ç<àØ¥«i1˜fTÛ'ÍÆ-ƒ[\ÄË™¯tecvÁq™õq\Æ,Æq³5~ù?~rròòïÞHùf¯ÄÍ–¿Ø²êC]$=5Ãý9ÐÓ ØZ”›OTA&wx¥m/)PÝmöẜա°|—%ìòõÌ ÷×À0f²S¨ÎŠL ¬buئtYFÒ 0@›Š(‰Ö™©ç/Ã] Œc¼ª ŠãÄ •ÃåŒCmxÔ ›5Ô.sj!¬‹ÄnÆüX—bÌDèct©uh†ÇØ(†£Æp!ÄpL(‰4ªhö “9(‚›€V=bQj¡_4@9˜`j‚Ð1G° ™ÝÉ$Èds)ßlÌ \Ô,‚Y/ÞÝB)ïfãÆáeH˜Ã+è*3Æì‚ã2ë㸌YŒã2fk|⑟œœ¼øÕ/§|³W°jÇý›F-‚ £xå©6ŸH´ñûPܧ†F r¤rƒÑ2 ’ÈÇf›§ØlŸ*xëÉ ÉŠ!-°Š®‹†ä4AûãΜ’Õ­µZnú :3_¡>$#g"Åî—cAUx]à^€=ê‚”éx ÜÂѤuSGÈàÔâiY=Òé[Oþ©fdV­2Æcq\f}—1‹q\Æl ÇeÎîµÉiËÝ Nã>B=“»SÈ,Ø¢sï]ÝÙ²Ýô4H›êÖî]aˆV•]¦ªú!©hY£e/Zý6ÄÀa A:…°øÌH)`ØD9:ã$¿•Ìò€¦qÌD]dÆqŒùƒS« ÆEÐbjT°•4ª™„]PëÆcÌ\—YÇeÌb—1[Ãq™s;ÀrSÊí’¾ÖAIl/!\>‰Àýsu')FdªtöÞÔyõá!áSÚ óù”2ü[•\G©ÅDîK–@ž°SÑP˜rÆiuœ:£y”¼q÷Y4‡=Ì¢É@±ø= æ”MŒÃXôà j#S´‘Ä¡‰ÐøÉ©E?й(Ô¨`ëÉEÕL‚L¶•ò1ƘA—YÇeÌb—1[Ãq™s¡µ)Ümjsˆý'£H(Â>9Fg’p•™*0«{Qêl%Uïæ8I'7ÌÐ&HîKŠçŸ} µÊªS ã™IZ¿uúÛ7Ñ<GðÊS±”óÁˆò±ÐjbW~zÐbzv¦ã˜yÕUJFÆ¡‰”cŠ-Â$*AB­ªªÔ¨`Åä¢j&á䉭cŒ1³p\f}—1‹q\Æl ÇeÎîË$·ÙHé!lA±?ç–¯éY‰þ|D¦JgïM7ž¾µ%ku,¶*鄜B›"Q¸/Ižö)È ÁÛð9»s˜çeø5¥h^ŒÔð–à˜Ÿ\9ý -a¾h51L³‰ß½jy@±ÀŽË˜Å8.c¶†ã2çBkS·â%Øô²b|†§ØšJ¦„2ÕÝfŸNôa¤]À'>AH,¶*¹NŒÄLjD´“[ë–$¡òôã&¥:ž™¤Õñ2ú(Œ>²Ó™Œ}Ó`æ‹V‹á8Žx€’šŸDž™´\ã(hüäÔJÀeEä¤F[O.ªfv¡ì¯1Æ3ˆã2ë㸌YŒã2fk8.s.pX,Ê p"í‡ù¤@Ú'¸_]°KïDFÚå3 ›gä#-°Š®‹ûyv°Üá+È¥@ %Ë=¿~V¹ê«ÒÏLÒ²–ùéÉú™h ʧŒˆù„ªø¶£±¡–hXê]YT%ÁàÔ*)VC(œ\TÍ$ìR¾1Æ3ˆã2ë㸌YŒã2fk8.s.pøÖ[ÉWÀÞ;jžö©ô(7Ú½+Àc ¨ýÚ^Rgu·Ù§µ÷ y •1)Â'; ·Ù²iUt]Ü~óY4µ¡iJƦé½$ {ÃcZŸ—aì™ÑÏLBmH± `Éu„¾BC(ŠÍ±Ëe ›Xà[rç•Ò°Ò¼h CCéŸÂʨŠÂÊ ÈÇL08µ`Rò{ ™˜“4)¹¨šI‰¢ècŒ1fŽË¬ã2f1ŽË˜­á¸Ì¹À ö«8ÜXƽŸÄ°‡ÜôB,îH™I1ÂSýB Õ.Ø¥÷£ÜWS€æ!‡mŸ#ƒÍÃëb«¨Í•™Ð‰:ŠúqÅôÿÜ”:¥€¬…©ìKñU¡(åŒ#mÔL3pŒ¤p[„òH±Ë 0•ñ VYà[ÂÞA ì‘âïË`²v¯œoú êBŠ$©ê€‘$z¨H-"Jh•hjQ-[¤¼”H&æÊ'U3 žôcŒ1ã8.³>ŽË˜Å8.c¶†ã2çw€ØObwÊ '°ÿŒbØë*Ä@œ*à"¸û• ”Ç-4r@Yk˜ÇS¾À&™ÊÕ4H]Ô#œ"“9 btH ýmÝ™p\ s¼qúÿV’ÄArir&Na$Å$3é™T©!º¥„Ö‚4‚Ì1“Tåg‘œ™fISW±Â”O÷â¨.‰H!É©{P% ”µR&ᘦ_5“ EÉHcŒ1fÇeÖÇq³ÇeÌÖp\æ\àP[qìúª»AAôÅĈÌ>@‹ãæé”;꘳ leDm_lPÉRÇ÷×Ðîж~|§e?óGfc§‰É©%”O—1Ƴ—YÇeÌb—1[Ãq™s!ÅeŽ=Åe¶ÏÑvüð8.cŒ1f;8.³>ŽË˜Å8.c¶†ã2ç‚ã2ŽË¤|³:ŒËà*z$‡§ÕQàUyõôWuô½-à™(r\ÆcÌb—YÇeÌb—1[Ãq™sá¼â2ú±’>Ë~9ehàÆ86Ý¡üM™- O™„¡¨ã‡d;C0иš‰×Ü~v~šÒ( ïg!ÃK•é29ÇcÌq\f}—1‹q\ÆlÇ~þ£'''ß~îÙ”oöÊC§ÿLTþ–ê¾a»“”?¡º:Øâ¢!þn'Ùl\&ÙÙ‚q™ØñC²¡?úõÿžè šHYŠeJÌcŒ™‹ã2ë㸌YŒã2fküèÕoþÎo~áÏôjÊ7ÆcŒ1Ƭ‚ã2ë㸌YŒã2ÆcŒ1ÆsT8.³>ŽË˜Å8.cŒ1ÆcŒ1G…ã2ë㸌YŒã2ÆcŒ1ÆsT8.³>ŽË˜Å8.cŒ1ÆcŒ1G…ã2ë㸌YŒã2ÆcŒ1ÆsT8.³>ŽË˜Å8.cŒ1ÆcŒ1G…ã2ë㸌YŒã2ÆcŒ1ÆsT8.³>ŽË˜Å8.cŒ1ÆcŒ1G…ã2ë㸌YŒã2fk|û¹gûùþÙ¿œò1ÆcŒ1«à¸Ìú0.sÿý÷¿rØôÐC9.sÑq\ÆlO<òá“““¿úå”oŒ1ÆcŒYÇeÖ‡q™óJŽË\h—1[ÃqcŒ1ÆcöŠã2ëóâ·¿ò_üÿ›³0ÉaÓöŸý¯>ÿ…_Mö˜ „ã2fk8.cŒ1ÆcÌ^q\f[|ዟÁèW>õhÊ7G‚ã2fk8.cŒ1ÆcÌ^q\f[8.sä8.c¶†ã2ÆcŒ1ÆìÇe¶…ã2GŽã2fk8.cŒ1ÆcÌ^q\f[8.sä8.c¶†ã2ÆcŒ1ÆìÇe¶…ã2GŽã2fk8.cŒ1ÆcÌ^q\f[8.sä8.c¶†ã2ÆcŒ1ÆìÇe¶…ã2GŽã2fk8.cŒ1ÆcÌ^q\f[8.sä8.c¶†ã2ÆcŒ1ÆìÇe¶…ã2GŽã2fk8.cŒ1ÆcÌ^q\f[8.sä8.c¶†ã2ÆcŒ1ÆìÇe¶…ã2GŽã2fk8.cŒ1ÆcÌ^q\f[8.sä8.c¶†ã2ÆcŒ1ÆìÇe¶Åó¿÷[Ø}þ©'R¾9—1[ãןü'¸)½þÝo¤|cŒ1ÆcÌ*8.³9îüÉ+)ǎ˘ ògürÊ1ÆcŒ1Ƭ…ã2ÆlÇeŒ1ÆcŒ1æ¨p\Ƙ Ḍ1ÆcŒ1Ǝ˳!—1ÆcŒ1Ƙ£Âqc6„ã2ƘAžüäÇÀW^HùçÌ€17ž¾–òÍ–áÏ?ûÔH‘@&KS¾— 8~Óá¹ê«ðVàYa..Û¿ÊÌeÅqc6„ã2Ƙ¾÷âWÞvš¶°ÿyóõÛïzçÛaŒã2 §Òûîy‹4»”0¾ª( ÏÒñIÍ e-ò³<ßgSW} ØF#=ÐfìïNr!®2sYq\Ƙ Ḍ1GÅC\Á–lœ+÷°â¦ÖŽè,y)ßlퟯ>ü ŽAõyFÜV‰Ë\¿ö8å=Uˆ®âA‡\ˆ#l£‘{Ú6rëæ3ðj fûdøø×^Â= s^°"ò“dƒp¬ U0&IÜÌ!©[ú –ï ±9šZmñÒ§qŽ¡§©hw—1çˆã2ÆlÇeŒ9*°Œæp0Až·³vÄfž–øa™‹ÅàþÛ<ÈhâEX„48ôÚMUµ!ºŠáÉTTåBì7—Ñä¬&ÌÀ–±ÕoÝ–‘ß™êŠH°'9„Âx™ƒ0êDÍ­T¶xiŸ/œY\ˆ«Ì\V—ÙðGßJ9æxp\Æl½úÍ”cÖ‚™&¸(DJù@®ngí¸Ëîâ’‚VwÅžÔîŸÑzu|ßxí%dV‹Z\¿ö8«ìòŒÀeBW1œœŠªláªgô´~}cp^íÎ[$D8™zàJª¥Gº Œ¾+3U!@B8…£x{W‹8ˆU˜Ÿ2G€f*dBèíÔã3,Z üBÀ/z‡ñJE»³÷ÖÃÀ;9ðmy 8.³-žÿ½ß:99ùüSO¤|s$8.c¶Æç~õ1Ü”^ûöÍ”oöWÕý%õFÖŽh} fl„‘[ÀžÔjìúûgn8ËÖU½ú“À-°ð¯i ]Åpr*ª²…«žó©5mçÕ¾iÙ‰øÐé÷.™Òó/¼ÖÊ|pëæ3ظV÷®j ÕË¡a‹(JÛJ™“DãaLõjjµx™@ÇÑÍ”¹ [¸Ê‰ú;x2{Åq™mñ…/~[ _ùÔ£)ß ŽË˜­ñ‰G>Œ›Ò‹_ýrÊ7ûcd½¾‘µ#ME:ß=ØF¸ìIíàþ™{βuZ…í_Ê7ãÌÝmáªoÅ;Äà¼Ú7};݈žŸ;DýÅÑé2ŠRLgÁu­/"M^zŒÎ¤L3‰¦Áù¾·ŒeÓÞì Çe¶…ã2GŽã2fk8.sxFÖëY;ÒT¤Î†äxX°ÑaOj÷ÏÜߦÖY™o¾~;æ›YÌÝmáªç|@jM›ÁyµoúvÞyå–bë± Y>kƒÊËiî °bº²ú¨-\öÇ®²C¢þΚöfO8.³-—9r—1[Ãq™Ã3²^OkÇøà:Àkò§XùX¾ªœÎýÔ¢åæÚ`¿ä‚]Úª.þ“º ´ŒF>Z¹ºÒ_u¼ùúmý¦IîE‘è $ž’ô 09Èï($³Ô(AQÔ WhÛ™Ð.´ºqP¨Š™8Eæ¬o0XBã«‘™æ@Çø„|Õ2 #HRáäø&Vœ«swD骇å­K@¨ãÁšôÐØ¡ÚÀS3$™æUrפ¯À¬iÜ¢%P›ôã2¨+±>ªm©h0^nYÜVɸ“q÷†$`išÌÈï\,dÖ%åЩ»wlKU4c[³¢lq| ¥«,oðšŠÊËî -Zˆ¢˜Ÿ@iKfñÑ9ª%º9°¿ç)Ú$`Ur,$«oFfŽËl ÇeŽÇeÌÖp\æð`­ÃERÊĵ#Öa¬’RgM†¢3¡"õWr ,Fa@u]N“P S“yi§´À´Xí2Öˆ(Å«Žw¤4^I‹Q¬Sϲj)®¹¹ÿ?+(Rêì¸ZÀ¥ùYÙ'´X ´nAµP3[ƒÞ'NÚTÔš©ÝêK©™È9©³#ãYw®âòÑqªU%:°uÕ'U ¤ ‘sª;1"WS&IÂÚV­ÖäY0[HOq!ïI@îEJÛìjEq„qh@t]µÕšäƒÌu²Ü‚ƒÖdnM~0÷’¡mxÕ±’:çs"­«½+QK?÷ïÉI¹Õº¬tùïx3OÄc&È'áHu(•R÷ß|ývË*$¨¼dLÇe¶…ã2GŽã2fk8.sx¸Zꯨ´ÓR XH¸v¬î-%€*€*€­Òì1J¨ KduÍÄuêcP]¥êµb+Ž&mr‚šˆsƒ îÃÕ—ª{›@Š5¾[˜«r S2["áXù²¡ºsÖÜ+P¥êɈÆ ‰–U/çê²iÜ¢o§ŒL[ 1ÁuȉÌŠ•ã>‚æLʯ¢¡”o±ÀÉýY'…¥aË. Jû×JÕ…²"Z©¥‘%êoº™`¸a[šÏDNˆÎ‰ÓC™ä—¥» ÆŠåµDÕËa² 2I'N5d fÇe¶…ã2GŽã2fk8.sxªËµ„ÖRHÕ•¢”TW½e>ÑJzp“Ö á µ:\`L\ìVÕ®¸FÔê0:À.ã5åЩÛW ×Q Õ_-©Ó³µ·IhŒRþZž¾ý#¨/I³Ð¬ˆ5¾òÃ9ÎÕxÕWƒ,ëjmçH¿_%²¹5mäUè,eâÎ9æ/žÆ-:v"‡m!•“A¥LPU½Çj8R_a+ƒuûƒ›Ñ‘’4±—9YÝD:À{©5ÖèÒàöC—dÊ)QÑJ*j¡+=9V});¢…Ï•¹û¥øïªÞjTVµ†77 µ†Ì â¸Ì¶p\æÈq\Æl ÇeÖ@)?¢µT\ÕE´"Œ+W-[«·Éuá8“ µeÆèãýVDZ¡Àî]ÐΡÕVbdàZp¼ªuûjåÖVD½HÛŒÖÞ&Ñ1l.š´Éu°oIõ¥µ•b/bã㻑¹*¶ÊÎ4^òpÚV-¸Þ«žŒh,ZRÆÄÌÅÓ¸…ìDE˜*®†o^´z ·ÀÃc‚0ÜÅ E©/ƒTýÐB^­Ú¬Î¦””/s²ºÙšuj’Ê\ü^#m–7b‹`–K[¨¿ƒ3Tû"‡—®C‹âûãŽZtPõd¼·[¨;»¢sä8.³-—9r—1[Ãq™Ã3²¸œ\;byD¸rÕ²¯³âi}êi-õÀ2c°Êg-¬P•™\eŽ£ÖiO[RZ;w#Õº}µrH舒6HZm·*’Žas‘%iÄ5WÑJkXû¨/­¹Ä^ ÅÎŽïFæjË™»ÓÚ5Éó­}`IÕ“EK :£Oã²³•&}Âoô'ŽãPʤԗA¨y°®¼Z5>ž…qĘ?ËÉÊlͺußkªÓ#Qc²srdûLö· û’šÖ¦ìN5OÔgÒo¤Î³0(¢ÌŽÎ7ŽËl ÇeŽÇeÌÖp\æð´Vr‘É¥XuåªL(o!ÕZUuViËŒÑ1ö+2¹Êœ…>ŸD‚X wÖ¦48ZÛjÑ}X(:uûjQ÷-ãNZP’±bu†”P?”¤üt&­z„¶J>êK«¢ô§ÎޝôÓŸU$ Z­FÅܹÚq %±ÑÉçhbfŸÉNÉW-jHJ-ò[P`ÐWR˜ô ¨)+atæ¬òiu¼4È”ü8ìÑ`ݹmU•/s²šnͺêˆ/»dL™‰j‹º–£ñ ˜ì/&Àõk_½û£¹„Uʦj‰SN¦¦8©ôÈE%ˆ MÜGÕK㉬ŠÞNH ,LEfŽËl ÇeŽÇeÌÖp\æðpíÕ_ßL.Ū+WeN¦Ömö¢£g™1“kDyf÷.çOÿ‰:™pZݽ ⫦jݾÚd['a{+VgH õ÷;5HÒ–Ï&¤MKõ¥ªÈKegGÆw#sµï@ÒjTùú2Îä7MªLvJ¾j PCšQR;™Ò4n!…ØÃ‘ÄÑFIèi¤šY7ù¡EŒ¬)0Ô¡ª|™“Ñ5f¶f]uÄ—]2 :=ý[vÒé/<‹…¾­¦Ô ™¯2kt1’= PU/'êoôvBJúg&q\f[8.sä8.c¶†ã2‡‡Ë þúfr)¦Ej\K);^äwP•Ű­¥XfŒV®)_ Ÿ¦€åuZ‘#'ÉLœŒ‡ Öð€úÈ¢jݾZéLûÏ’T±:CJ:†Í ±E4ж=)n58ˆêKK³¼Ôêl|¥ÿ|çªä[Ý­Fõ½íèÐæ”3¹Ãd§ä«–5¤%µs§q‹I;ç¢~EË5aÆ¿&X7ù¡ƒÚ¯ªòeNÆ)kµf]uÄ•9÷½¦:=ýcÌbÐI=©¿wÂÞãý «,‚ñ± a^PSŽdÈž¨ªW´)µ‘’²SfŽËl ÇeŽÇeÌÖp\æð´m‘É¥Xåºl7 ö¢µÔËŒÑʵµF”g:M/†Ÿ—R9@ýSaXùëŒìWµn_í¤CZÈž~ÅŽasÑÐLŽ86<ìõˆ0P_Zƒ^jï¤þ*j´õÝ·¹suÄš-Úœªˆ9étIOÊW-ꌠqVW(çGË5[p ÌAæúÿ¡»_§™-UåË|¢Ž·f]uĕٙ«UªÓ#QmQvŽø§C«¿ëj܇¯6­cðîÆÝ'hJÏìi€úLúmĪI%fÇe¶…ã2GŽã2fk8.sxªKêÄäR¬ºrÕŠpÁ.b.u*YfŒ>äouü D-ÐÓ:µ?pýÕ-K«uûjÓ¢œê )é6 ÍÈþáÖœ’”fLTDúÎO”㻑¹:éÀøm—TÔ/øV’s.˜ôä伪ΨÅӸŬAΖkb µ¢o- µÆ¯,]H“^ª*_æäÉYWñÅï5Õ鑨¶ØŸüã´ú[u©`iõB–a,åeù9{ >ª^5è¾Ñѯ{]ëlq\f[üóùÏ—9f—1[Ãq™ÃÓ_ÿ‘É¥XuåZ~f¾?ØPk©–£å~K3òû»Sõ-`Ó­î,.íW\¼ÿiõ"Ño}““6F! R~‰4W…õwÔHýÎ’Ò3™«ê&̨vD–W'ƒìÁöOû¨¹Ñ5Ѫ89¯ØëäÉÅÓ¸…|;2â¤Ü'GÔ¯4Xヘ6Û f”vȨÕ¸ªòeNÖ¬ƒR©Žøâ÷šêôH´æ[DÂ%óEˆI«¿T^å7_¿Ý)ꔾ U•ÜÓMÒ7~ò>¨ LEfŽËl‹?ü÷·>þ‰‡¿uëNùæHp\Æl—÷Æ/ÿâÇÿì_Nùfp‰ƒ×”Y¶VZÙw>'Y¼NÒ_ê‘eÆh X~¨Èå/S¿é°­ºBf'ߪõê–I¥åžA“V½¯È!08‰²#­’`ëýÙ8HuÒbKS5¥ðà8Ê ÉKP®"¤ØÙYã»…¹*"As8œ¶œ (€W$I4mZŒOΫ֌¢IH³¦q ¹·eF À(W›ˆ¾MæÅ¨­îK1´'C…¥:À6™¯£ˆÄJåª>îdØÌ*­æZ#¾ì’iMH«EÝH¡$æÔê«%­þÊ¥­o¡"UÛ¸ü%Àƒ–ÿ÷1@“¨k)_ȪêU/·cÄS‘™‹ã2ÆlÇeŒ1“‹$°x­WöXEÅývX>"©ÖØJkJ–£®!ᥫX.y¥°ßôÐmXtj¯ƒõ A©?¡/° ]ÐÉlèTO¡}d>Š˜é«qgk£»p IvD™DöDùÔ…LÕ°¹ !¶g&Z‰ûô-R¸³?‰ho€ŠðÔ‚˜ÉƒØYºep|÷4W©3µÕuO5u¯°V:™‰KRE!‡0¡z˜g]4‡FÙtÔ39¯Ô÷”¿l·`+H-3Jè@¼¢®¦ú cX„T©èUHÂÿ°–À3ª‹¤™ÔœrF€IQ!ŽÑ:¢©8à¢6°ì’áÀ•–GFZŒƒ¯¸(_òÔú k™Uhˆ™ð'53áXò‘hRÇŒ} Ð$ê[˜·q¼àI AEèÀÜ«âô6Ëp\Ƙ Ḍ1† ¸ÎÒ L.ÅZ+W·pH8&gç§i÷¶Ö©b™1q)ò¡PÇ©Ö\´âDJ†á tlZ|3E3¢ÙI»<°˜T °Œ>+8MTk•š;3$B›Ëê ¨NZ .3‘J³áIö©z‰ Ωvvîø®;WÙKÓh¶±j©E>\‘*Šèm¤e—yÙ4ú¢ÒÉyÅ걊X0[ÈÈ–%¼; :Sk´³L(Åü‰U(?Þ#ñS·• ¹zùÌu²f]¼l#_pÉt¦‡è´Cºe¹Ÿ´ú ;¥™½Ð)l¦Ù‡ Ç©4²úM¢7͘’¶tu”&•caฌ1Âq™ý÷Ôr Š7’ÎÖ˜s+ò#˜º”i-ÅOêj ÓË,”ž­ªî&ä`É?([ [ï/@É2c°xUpŒäk‘ÚY"SF«ZÚôñ)„±a‹I!Ž‘óæë·¹¯QXLªüè2*G¢N4QÞè0C(Ó_O³Ý–a³hMZöù´‡©›ƒ’<µPŽ"¹7 ÜÜñ]k®rÐQDƒñå[È4×ø™Ò»j£|M$¤¢A’ŸS»ý;`]òÉÜiÜB­ô§w¢Õ:|•¢*%š±:Oá“Òr”?Lesg-ÝMȵ˜r_Írrë²ý—[Κ¹›ÊKF—ò#ýËûŽGFtú[ÕL1æã5ÊGp#:«Óþš¡Xw€F KÏZ:m«¼¶nÔ¥If1ŽËLð¿ýù÷Þóî~èw~ør*2fu—ù“?ù“¿û3?›òä½Û ‚·¾…Äw¬Ôù¦âws´`I'ÊuØY`Œäc/öÅÛÎS6ÔAò)_ÌÒ&&Õ)››îŠ}…p#dpŸLùû@fï2Ñå¹JæŽ/<lHò)GæªÅŽã^†öf!?ïé TýÚ_vi]ž©hÄÙ;·ÅXqßNŽmír£æÖíÚâñeDcÖ½T }P[)?!±II3— —yâ³>úø#O}ñÓ)¼÷žwó ìߺ‘ŠŒYÆe>÷¹ÏqÖ•Áoä€ÇkðŽK;ð.2ßÓG0ù ?*oŒÙ8X)žÞ>׌Ë\Jp‹¦£úkëCÆeÌÐæp;oÐÆ\zøA ’œ¦ÃÅ‹Ë|íë_âÌ~Ç;ßþê^L¥«ã¸Œ9$ý¸Œ>æÚø™ëx¤¼ý諳åS¬WN¿ñë-‡1—Çeq\æÑ»aç ƘÕÑÂø0Ï ™ ÊÅ‹Ë<ñÙG9³‘¾sû¹Tº:1.S÷aížÔšH?.à Òù.‘ù gç­æÑάü:Á—[wÿZbÇ'º1Áq™A—¹zú³¸€?Å¢RÂû¹ã2—­"kó;ZjúFjú\¼¸Ì«?xñ½÷¼ûï|û½÷¿?íƒ —[öaðžÔšD?.ƒE3îéËè˜`&—é0vÆUþy1ùe%–z gÌå ŒËðv4‹c¸!è¹z%õZ>T‚OTÑ\PônèÑ4æ`ýÉiZÕ“ðïþNpà¸Ìþû[ŸûïåÖ+ËŸÚ“Áñ¹¡‹H?.³.ÖÂ>¤3[?ÊÃ÷KtÇ_¶¯òÚ·oþú“ÿäÏôjÊ7f›Tã2ÌOG²q½úðƒð’ˆÏP\¹ïDù8ÞBÝ숾 í_¸0æhÙìu¦éã¸ÌŽG<óìÿxrrò+Ÿz4åã¸Ì…Æq™ÕÁ¦¢o­¾oï¯2Uyìç?Š›Ò·Ÿ{6å³YnÝ|7O}×—6Ngỹ|`Oˆ¹ío0s`pÑáÒó/˘I–Çe°?')¿Š„G~©÷;·Ÿ^Ù©œÁxLUÝ]ÌþÂ?ÓËL¶2+€2nöܸLÔœŠÖE þØf×\ÃTknEY˜òET»b\+°ïþ‰Ý`xo”©(±b\F-.x»RÝ”AßiíûÚßJ‘9f>ñȇqSzñ«_NùÆcŒ1ƘUŠËÜ{ÿûãï¹|ðCÀé[»ÆÓ„ãGD‰|ôç’0vø¿ñÛŸObzJáòÿ°‘Vü}™;?|¹ìÔŸ}+82 Í©nÕì:q™¾'¿öõ/•fHJxõ/R8“.’Yj :ŽüTîíÇ}Pm¨5Ñzb$œb¡I8‚RÎÿ³:§ §­až 0NG­tW9á?þ‰vâ2w^yá]§¿}P~–ó!v徯p€ÓVàãÖÍgzàŠ„™ªU` ò£$OIüɘÁÌV£7ž¾ö¾{Þ3E§ §­8”šŽ§gÕºõ[kѼj“~q\ÆcŒ1Ƙ½2—Á~›¼bÏÉã2U£$æNU[P$IÐÒŒ„=p”¤ÈÇÌÅ`ÿ,ÃRB»²ªŒË`[Þ±)™=B+.3éÉø7Ue’øßþ¼ª#EmL1¢4®–`œ•ÕLmŶßRm™Ê‰ÁèÒYq-µ¢9“Ý/#Œè#KqŒ„|”lMžŸú©Ÿzì±ÇxœÂ ß»û» e‚‘äßxúZŒY(!³Œ’èÛæL‰uqŸF¹r÷ª ¥’„̬>Ì¢ß?«¦÷ÝóžÒN*„=o¾~›ßK*Sõ óê`ÿÉméì?}sœ8.cŒ1ÆcÌ^™—Á®’›[œbëŽmgÚy¦Í-N™=YðÛÏá4mPö¨Q9ˆ@f’—1s1jj«ýbBf«b´9ÕÅqªÕ§—ô$ăô‘þs@ ृ€:Em¬uj˜T ¤ÑC(0U˜Ÿ4/&*„t;la¾úbÜOÇ”òHAU!È9+;õ³C&M%ÒŸÚ5ÀqcŒ1Æcöʼ¸LÚ‚ m2c ‚™åv·DúÓµ5W÷ÿsQÓÕý³b H) Þ¥Ç%„6üÕp@‹¹q™õ¨@é pR=™T«ðG+5«âÁA**ÑvÚ¥aHq(î־н—iYØQŽ+ñ?ý§ÿ´øy¤êŠ\Œ?¢*ee2Ø¡0Gª«oBµÌ¸q÷¯‘’r),¥úáÞÒ¤IS‰FUýGŽã2ÆcŒ1Æì•yßc*ŸÎ ŠAÄý|?ä!âþ6µ <ô§üL6]Gh·ß±a$"PRË z’T D1…q™AOÎòF6„ÔŠˆEF‚8’‰Qõ·fÕq‘QªÌDG9®D\­ßýŒË´Â Šk”[¨ÊŠq™‘(‰dâs:RX~S‰´4·òr¬ã2%ŽËcŒ1ƳWæÅeR¾Ðçÿñšø›©ØñÆg "#ûØwæãò-fm¡cTB;‘Fžì Õ¸ ñ$©\òê^„ç! mÖ]—I}ÃúÀ“TSSQõ¨Ó¨Œ—ÎÁg¸—‰SWÚ.P\æÎ+/\}øAÔ…’«”¡á5å‹jEßQêÇ>aAŠßur\æq\ÆcŒ1Ƙ½²ß¸ x*üy NcœB›Û~Œ#ÂmmÙÖ\:f 7öÊìÛL;‘bÝ>­¸ ˜ô$©œ€Ù² Ç‚9e¿újåI¤¨­zRÝY¨¡A=h‘òoH'„[9U4u£1ªÛ™´ªªüðq™øFHÐ#˜S†BX„×”/ªaeÆe¢©U…‘j\æÎ+/°VÇT"ÿ8.S⸌1ÆcŒ1{e¸Œ~K¥µ[†À½÷¿ŸÛQ$èË8ñy˜ÊÌ‘¸LÇo%¸ éx’T ŽèçTPÇ“†NL¡¯Vw”>{}^Fƶ¢¸LüñšŽ­ª*?p\FA\¿öx5ŒR†B–Åe Ÿ™ý؇LºuóevŒ!¬Uš4i*‘ú¶'ŽËcŒ1ƳWVþ}™Î¯«lwµ½ÿàÝßX]°¥ç¶v÷€šîtMÇý`;Ûï“qRõ$©,â7tJ9d³q0Ë«2»õµ/P*Ž´¢WtWLJBÊSL 2.ÓÿbQ'2ì¨ÖŒ}0‚ëvŒ!¬Uš4i*Q̨ü§m㸌Ù\Y¸ '¯Ä‹ {çˆéƒ÷N•;¯¼Š¶É…3ØìŒ>§Ð½+ÉTtõáUQh" ä°hPÃöñÅbvg^\¦ÜFí~'ÿ0Hqíc¤@b}’†]˜lZ]‹ñt“™$3þŒË€Ò“DÏòô(U«:1…¾Z0éɵ`CHP‹Ðïòt"h’yâ³áö‘V$¿MÖñ¡Ð¤*•3.óØcQ Å_ÚHùïÈŸ—Q°CN(„má5å‹jÝοY‹–LÇÒË õß&¥©È8.cv§u…^x«iÝìÜà‡¸’ò™É÷²­qá 6û@Ó7:RËP¦zä[’„«qÊŒßH±´ƒ0ØÂâÍ‹Ùq¤j›RíÉ[›…£*íoãÆ8’Â=¥†Å¨kÕ]tüµÝÍ­}»4Oƪ"ãqPõ:ÒiWQƒô” ÑwÊJoôÕnfõw”jÀoüöçu¬gaà«ê¿¼Ç°`œ½z¦VC+Hþ‰Ët”ãJü·ÿöß²)½Óà^_Í|?k½™U+ê-oŠÊúÝ™ò †ï¯h1þ•u¤õæÄŠH¥ýäêÃR -å[ …Lªæw*u¶êŠ#Çq³;­+ôÒп!¸—žÞSßJþôXL¾—m g°ÙƒÓ s| ˜{#Õâm o.¾XÌîÌ‹Ë á8_T7™ß¹ý¶Íe˜›öRX{~ìSø ‰ü˜ÉtÚ/Cö”MÇ  R«ãã©t®‘¿õ¯¯c ôÄg~I9³< äLÔŠùDQƒäR …H¸LU-Pœ¢ô¤øÚ׿Túj. µ •1 †<¢ÕùIîüðe•¦~ÁáœfHå³6ЯÒdƒ<܉ËDå©ú3¿ùEæ3á./WÜë«ù ÿfV­¨·òóL½Õ!•o0|EjE1ZoNZ©ÃÚçŸ}*¥Òñi)­·|UŒ/Q¼(yâ—~7¥ßñ«)ߘqZWè2p÷À]}ÐoO 9й?ôïÀGHç~~Ìè-©õ^¶5.œÁ…=ÝÄ jËõÕŽ NƒÎmpð-`îôq™É!óÅbvg^\†›I¼b‹m'ˆE1vÀÝ)%±‘Æ)ÀþVÛÑô˜IÔƒý3•£.åñ…™‰*1s1±iX˜ú¥G`¬…-=Í@ÂL}â³¢SÉ'©Ö$?üÿîùßû­?ü÷·”3ד߹û›µH&¼F_É<P!^!ÃL&Ô’<™T ¤„Ö>õÅOÓZà”—š †`t‚è4*aôŽ™H€ìQ>u„@'K‘Ø Ta”Õ$§ZhšEýžÆ.à˜]ÀÌg·?üáwýä;q€»|¼\q¯§@Êý7³jE}i ïmXLëí“Eå Þ–X™«?Wî;‰ÁΛ$Y„„cHB†ÎrkណBÒzË¿uóVÔ3·UØÙ²ºúý[ß~îÙ”iÌ,åƒø‚Õý©HФñíÄ1€w8äá³í3ù^¶5.œÁ…}ÜÄ0F¬ÕoDƒÓ s| ˜{#½óÊ X|b·z(ªdrÈ|±˜Ý™÷û2Øsò8%Å*ñ‰€2¥g¶ýUÍHГ䩹º—^,¯šÊvµÍNdÅ–ÍH¨^VYÀ\Omï• A¥þ>ñÙGYT)ôÕ’n(äã—Œv¡ÓP+—ª]fêL$E媩lhÂôã2 5y{ì1\’ˆË}¤™ô(øR}ƒas1ÅÀGÿÍ)†`R‚Ú2(&ßí:où4µZDäœ~ìÆ³˜ÁEù “õºèþSÞxMßN˜ãdò½lk\8ƒ/ û¸‰i1³úhptnƒƒo[¾‘N™/³;óâ2<ņÇ»Óø¤Œ@&¶µ¨›„Óó‘'>ûh’‡†Rù½÷¿bÕ]ñ2îüðeh‹íªS ÖpJ›qŠÌ$¶ <™Æ(Å °Õ_ú¶e_-UPÅtB¸Ê]xꋟN u|Rõ!ªW[(L¾†4aFæ@ò'ìù_¾ùu\H÷g~ïLé“FýÂYù ä•î/,v*Þºù êâFpïñÆk/±JõÑ}”¢-UXü[k´Ò© n<}-5 ®>ü`ëq÷I…0¥ÕÀ òùNÙª«·ÒÒ9ƘUàeˆË<å/zVÔ6‰n¼7V¡IèfÊ7&rávnÎà‹Â>nbŽËì•É!óÅbvgI\Ƴ'p%2.ƒ+3]«f×ï>øÓ »h¹àA0çÅ›¯ßÆJ.†qŒ‹uˆAÏÐ@yÒ Dǵ#&ÿ§¯±bõ™5±T1FQZ6=¹(ý­.³u­yJàÃ$LP$µèڬ˜ݹz÷÷Èq æ@”¤Iq;1âÏHô°ã,‚°ZŸtT´MÄF½7Ëá’ÏѶޙ*“Ý!-w¥¦wš9—: ÓLÀqh!Ÿ€¾ÁÑ9}a”N .ßãÐD¿/b|È¢—ªwàþ«N䤮™Ëã2ÆlÇeößñö÷QD«ºÎ®É˜}Ãõ¦(ÖsZ™á@ÇH,MA\5²JªX‡EØêhu^VÄÕ‘*J¸µ¢eu¼¦üÖ¢<®\Q 1mˆæøú8 —šq…«àv-I Eñ~BI¨U»È!âUƒ‹^3)ì:ÐRÅSÅä%J¢ò0&‹âd z‹A•8ܘÒôÒ.“Ó\ .C\†æÍM­ßñ݆?]Oëþ~ðvøÆÝ?-š•î½ÿýIÏåÃq™=Á•7Þ,c&Þ29µÒ;º1Fë9¤rMŒ…šÖ‘q%­|®•/´ÎNË\3)-‰Ö‚qÓó«ÍÙ“òY±ÌÇ&¡lPR¹Ýjµ"Ô\ÕN•¶šNht:7 Y‹ƒ8F•&{´*h)_--Y6‹˜‰Wå´Ð ÂqçIƒÛlt)5ÃÛÊÙÔÚ¢,÷Ø©r¦é BZåmBc”,TCÕ±†°ºŸú®ü4ë®_\b:mùMs¯©¨eð28LåîT—C2C}L“˜ÏTPuÄãe²ÖäºZ[NN´. –Òé—|RЪÇÀà4 aÕÖ¥9å':ª¨ËiôãÜ€¶ÔxÕÇü>´­S%N­òBViê´ÚkÌù¹>1𡏠öØŽËì‚ã2ÇeZ8.³'ø±ˆ ;,¤3ø‰1û£µbÕm›2Sô$Â%RœùZ³¢4-XIkƒó˜ßZ³¹T °b™ßA!–mµZ!ZsW·¸@Þ.w†U$ƒT$hRk{ÌÒ¤An©Žè÷4±l7¡êƒ~£æ–1s¡6¤Ö°.w Më"ÒœïŒþ8²!ÎjmÌðZ¼ˆìŒoXºNwk]¡Uƒ#g¶¼­QŽQ õ=M<æ£ k•3­š¯¡4zv¡:»:Ð6¼¦üZƒ¥{é ²øÞ88 ª'-› UÔeXX͇Âê5E{Æ'6mëtA^j]U šÞ­HœL]qºšÍ2—ØH§œíp™¾Çô¿õëÿåù×þéò4i¸L¨Ëãø{LÆžuýs?ów~úõï~#å›™\õj=¬\ä!u–kX R&®³[kÙHu9¹–­Ö¬Xæwèø¤Õ Ñ2·"ê~ks˜%“ó«úµÀ,¿uŒ›Ò‹_ýrÊ7+2¹ž«îʪ‹¼„4ÇåéäšP9R4‰+È”i™4¸(G7¡™h Q¶Õj…ÈHh@K¤ypõ*”ÇA*4©¥](5(uiX Õ"•N(|_¸:‹¬A‚ý>‰uûP~ÐÉ“LjCÑ[}˜9î“BEÖÂA*Z€´Å1l¢4U]™%¨%¨ªôCÕàÅ´ZŠ`Æ1eß•‰* ÁÄÙ«Ç»RØzÝE´Õ‡ah=µ›¨ö¨ƒF ´Üˆ¢Óö›— +"ͽ7¢ˆùh"æ'Ø©jë-› UÔeX8’/{¡m.Lê¬:AjQ½ŠæŽcEs)q\f[8.sä8.c¶†ã2ë-.¼:kÄ´(¬î±K¤9®t'׬€+H¤hR53’ŒÕõ¨ÀÎ ¬[¦²­V+DFN&H¦ºUäÃŽ»hRKaÕáÊI-‡GdgG¸ê:ìf™Ï„clÏÒC1²6Õí@ƒNždRÛ²q§ÚN§FFœê î»h*’êÊøÁ'˜$1¸¨"m1!3ÉLªq8Fe+BÓ, ´‚,zd€ñDö°;ð¤ª0gß=J¤I{ZΖy‘¹ƒÕòžHæuRÒ0è4ÚYmM÷û :ª¨ËéÚiå‹Ó€¶uº0©³êªI­¾˜Ë„ã2ÛÂq™#Çq³5—9#kÄ´(Ôº³³LÒWº“kVÀ$R4©šIFŠêz@t"A§„ªÊ¶Z­)”ªƒ…ˇwÑ$èLù¤êpeÆ^W™ü†‘­Ñ-×aˆVXʄ㸥”µ°G™}¨m\¾Ï¤68oÜ©¯ÊIŒŒþ8Õ1‚IÌì7AS‘TwÒøD ÀáÈ'-U#“jö´lE´¦™žêÒµÀHT%Í [_-¾«¸nJàd££E¢åp±`°ZÞ2LªZ¤{ã Óhª§|€L•6':ª¨ËéÚiå‹Ó åv1©³êªEBiÌ"Ü¥cEs)q\f[8.sä8.c¶†ã2`r=§„µ¤+sªHs\žN®Y‹Ñ$¬ËÌHË$V,óÕ vYã_7hµB&œKÕ‡ š„¦S>©:\™­ZséxŒŒÌ>»D=HÚž ηHß's™Ô&³gûd§FFœê1Ä€Ôo¢4•9H#]Vh ¥=½Wú¡jðbZ­ˆw¿‘Ttê>O¦ÑphgÇìu{ÔÞÖ°"•¡™ÔIJÁBX¥ôaE¤¹}t;Um½es¢£¡Šº GòÅ‚i@Û:]˜ÔYu¤ZsT8.³-—9r—1[Ãq™0¹žÓ2=.XµžK«öˆöñG.'׬ ºX”¶–ÕZ ºÕoIhséø¤Õ a[HŠ)ìˆ,™tWk;Qu¸2[µæÒñ©Î¢*è‘/†´èûd.“ÚPô–Å3Ç]j]D#£?NuŒ”Y½H5.6«ËJ Ç[ ª¨œLNªY´Z ¯”Þ–ýw^yAÞÐ#]é™NCëö¨Æ…v"¥¸3ó[®X6X“·VDš{ot;Um½3"‘ކ*êrš0­|±`жN&uV0©ÖŽËl ÇeŽÇeÌÖp\æh=×ZDjŸË×"[›“­ùâ¶SkÖòS\ÒúÔZvVw PÛZbV×£ÒVµ¿³ÆmµBT±ü Ã2äÖèšÔÚNÈáIC¿#sQÇ[vVgQ‹²G#ó-Ò÷É\&µ-÷ÉNÉiÑGFÆY­xYg&Tƒ˜èi™Ù‚=EÕ”JS~ÕàÅÈÛ­¸G¹*/Cz#Y˺hBQ›ª[ÖíÑ$£Ô-L]ËK‡@*"êû¬k :­ÓzËæDßþØó–YÅåÙÊ ¦mëtaRgÕ ÌDš,3—Çe¶…ã2GŽã2fk8.s´žC*÷‡Zm#Å¥›¶j­U¬Ô¦ø‹Ö¬HÕ­‹VŠiQ«Ë€ŒT­råZ]ʼj”GÚÊ5®ŠÒGÐDîÂ뛯ßN¥ »Za,ÀaXÊ'Òü¹§=?Òø,jQöH;ÌV7!€VtÚ÷É\&µ-÷þE¤BZwŒÒ¬¦åHÕkÝ‘@;3¥ÑóÓàùgŸâ1:Háòª1r]*j¼ Ù€†J…0U¥©h|¡„“¤!ã`AF6Wçùº=š¤—é X6X S–]#`ÐiTžÆ…°G-ÃDGCØó–YÅåÙÊ ¦AÈÀ¤Îªp켿˜ãÁq™má¸Ì‘㸌ÙŽË­ç˜âR«g-ËÕ*W±HXÒ¥u¶6œHi¢5+ö3±®ö¢Pž6{ZÖ#Å $ô+)­;Au=ÚÚ£u©\ãrW†”¥cuzR–ÂI™-° §6دV’Zv¿ ÒÚ$@³üVÝ£ìë´µî³`Á0œ–Am&£—âè'ïaP¬¾Oæ2¢mÙ¸·:%mLiì–¡1J³Zù0& :Bß"•;7¥.ã˜öËl]5©›ñâÅA,-ƒ—!k‘ÐVœØÐ/30ý”QuJ&1ío)Vö…¬Û#÷±iÖᔦâ5õobË ¨4Ýó…fuš0¢z :­CsÊýA U`Ï[f—g+_,˜ý!“:[N`>Réy‚w‡ÖEa.ŽËl ÇeŽÇeÌÖp\æh=§õ–n8\§2§ü˜NŸ0#± VoX>ªR¹ëÖšµÓRYhYÄ*R¢c(IµZùjp€~fª¨\ãj†ÄF!Œ^KkeUÇ” 3_ò“ VÔF%q8¨ùʉt6 Èa” û´“~ Ú²V©ªZ«œh¶ C>f›ŽÕÓÎ-û¤\òHã>™Ëˆ¶eãŽRVAb­(ŒcA,U\€Ú*gµBB»˜ÏY‚„ãT@h-Q¦â}ب3 Êém5)Wi&ƒÃØ t Æqª%âôC*CR‚o‘u{$Ô5ùV·2¤rSÝ¿‰-, û3J¥6Æ|w¼FúNcuèIù™(*5':ªÀž·Ì*.ÏV¾ìQdò}gRgË q¸©ª@¼ŒûÄ\h—ÙŽË9ŽË˜­á¸Ìˆë9¬¡¹‹ 9­¥ÞóÏ>UÊ3!¿[‰kV¬«ÍU+..SÂ~@E¨å;ù°¤l Ú´T­v¼´ˆ7^{IÛ˜2¡Ñr§Ô¡t2NcÌ‚¥­¥stx*ÕW‚Î2WeÙ,*=ÉT-k‘™æ ÅZ>™Ë ¶eãŽÌ3‰Ð< ¯VÇn.qŒRЦºLqû—¨^ÂHeg1@¥$r` Ãq”}ƒçÂɆVÞ|ývµ³ýñÅ…p&W3P?Së¶nDÕ·LéÖ$¢µLQrÁ`Ìÿ²VrÅ‚kdÐilº:ˆú”Ÿèh¨{Þ2ë qвI'à*.•+¡Jk>›K†ã2ÛÂq™#Çq³5—9i=‡u3V{X¥‘øig ,Úb,»;˸rÍŠÕÅ¢ñȇONN^üê—S¾1ÆcŒ1f—YŸO\ýðÛÞö¶÷¼ç=Ÿ>lÂÞ íþ7ÿ×ÿK²Ç\ —1[ÃqcŒ1ÆcöŠã2ëøÌC=Ä öÁÒ§?ýiÇe.:ŽË˜­á¸Ì¥á×^úÞ‹_¹óÊ )ߘ‹&sÊ1f `fnjrú¶oFà¼X0Œ .0@Ê7³p\f}—1‹q\Æl Çe. ï»ç=xx×;ßžò¹p`{2› ‚})f&Ò“ŸüX*:xÛ߈1f³Üºù ç­f‹î¼òÂYÖÝT½ñr¦!]¿öx*2ã8.³>ŽË˜Å8.c¶†ã2—ÇeÌ¥¡—Á$G&ðÇÀ¯½„M ]\}øÁê‡ùsÚ'?ù±q´ÝT\6T/cœ*HñRRé•ûN˜Ùºñ”RÃfþÅÅq™õq\Æ,Æq³5—¹4pÙä5º¹T·ñs]ï .=ׯ=Îi2ã–rUͤ©¸¸ .öÂׂ™Dq™þ‘:«Åeü¼Ì.8.³>ŽË˜Å8.c¶†ã2—ÇeÌ¥Îr23éÖÍgRѹsãék¸Á*t9ÚF"aÐéX>ÒC\IUfU%gªO[,aÅíÄetÃ/çØ=zµYî¼ò§ÄóÏ>•ŠÜ àꔿ#{R»{\™,òým—YÇeÌb—1[Ãq™KCgEeÌÅB{€”ý6 Ê^€Hý™$þƧ¯Å¢ë×?+ØCl®5ë"‰ËÀ-4£ŒOÉBLÈTtiP”áGad¶,`OjwŒËh¾ï´¿8.³>ŽË˜Å8.c¶†ã2—ÇeÌ¥aO›“½â¸ÌZ\¹ï„ž¬~câ¡®°tõg FfÝFâ2Éæ¸ÌaØÓ=jOjwŒË0ÿϨƒá¸Ìú8.c㸌ÙŽË\Z+*c.{Úœì^€HŽË쯽ÔýIÅŒ¨ÝH\†¦"9.“ŠÆ9NÂì—áÃ2Èô¯­ïŽã2ë㸌YŒã2fk8.sH°£ÀòKrõáûâc=ôÐW$ãŽ<ÊxþÙ§Ðhgýzýô¯IʦYKK14-c`yú’9NùÅø¾ÈOmᘵ@õãñA Y´’,Œ mñWêvÉ8V-ɤ®á”úñZõFܾÁJ&å“ vÖö›ü¢ZÐЪõæë·! ”ƒNÍj.v Qù­Í 'sì Aòõch­—j[À ÉvJ”Í%(F›‘ j²njqÄÈè/Ú’6h†þ$Is¯sÁ‚ä[ÔU­êø&å¨;9 "hŽn„’T$äê~7çÒšu‘2.ƒþΚó}TLN°y n³yuÀA§W«$I9 ;–PIÿ(b1ެ+ªwÚ4‡Q«zE@3Ä œ}ÄÔ‚$¼ ¸¥3y‡š-<%å„,ï¨8-'É\µ`Ðc’§[—a&4ÄL³ ÇeÖÇq³ÇeÌÖp\æ``ýÊ%WJXY&I€VU ‹¤êÒªº¢R>RkAƆʊÌçj k¾S‘PªU d(ª°4ÂÕ!ÛÂ.¢¬…œþÂ±Š–é1AUuÏÐ$è)w/€òt…üÉ$kc×à–2¡ eÙI SË`Ðê vË$Ú€VhvLÈél½ª­ µ Cß)€ì+ÊN¡bg«PN*$-ÇkªÂ&Zùôsu6²¨J«×1Uw’þ<ª¥ÒTøªt„;îjq˜ ˜†ŒW„X0±KÔÄÈDMì=ƒ×”ÑœGÓØ—ýEõÎ ¢SUÿ÷k• u4î±UÍJÑŸÕk„ ùÕi@y:<õ:Êw&˜R93[s Eå¸ Ï ©sR½À6Ýiû·‹Ø5T©^HP˜†{\-ô˜ÀÀQ Z*h04+‡“¼únnà¸Ìú8.c㸌َˆ¸ŸÁ*‡h]•V]ZB!A¦”ÇAùXTÍGj-Ȩ¶¬È|¬ÿ¤¹4‹6u*E*wVìd´›e­¤¶iºªHUQ[²!.% β­S›\A1fʫծQµ¤ ‹u–"!µ|HI¤r,›%¯E9Ž£$N‘™l@- ýHå]† KU%Õ*÷è;‹Ð%«ÍU?ì­„N¥-Õ¢L+¯i62Ÿ©´Hôm POªaüKUxJR£1X†Z”‰”Æ´ú‹TjK­sz0U[ÇAëÆ‚×è[V‰¦.˜ØUØRg©ŽàBHE»@Sñšò#šóê^a3PO‘ªsÖ²’º(^³B3%PÍÑ ž™¤. fê4R8(è`iÿ¨9€|(d%Ä*È”Z–µ£-ÔT‘Ø24hf”wZ°-J"ñ”H Hì—´1)ÖÆÕ‚Y#`iç²T )߬…ã2ë㸌YŒã2fk8.s°Ú~kAtºÜIëu®Æ°R(Œ”b ñãÙråÔZQ©JkA†*ÕŠÊÇ+”¨zÚÃó5šŠ•¢J•I´:d‚¤Š ŸÚ°~U~µ“â^B#´¨LµŽ†Ò@àT­§Ý,`‘^U7-¬OkŸ‰©kX"§}ÅÒ,n´ u™}E !:îŨÉW°Aù$nHÒ–L!¤èL€!c>;ëÆI‚U!ñŠˆ]ˆ£€TÚI­|&”ÆÙ¨¶Ò «(ùVS±œ dCëBê]9š¤dg‹èÆT#…ÌèyPiÙ…ª›Z”¬Šù­‰ÝBz:nÔ<Ü6]z ¢9Ïç¼üý©k(izYØrÐæ[ºÒ£ýi†YÈW e¼~Y¥©ƒšÛåˆC b‘î<åe¨Z鎴 ³î´@®HùE°¼ì²¼Q½½LªÝÑcihÁ”oÖÂq™õq\Æ,Æq³5ûùžœœ|û¹gS¾Y-v˵Àr0æcEEáÖŠSÚÒÒ¹µ¢’|kAÖZ2 R‘öH+5«n I­‘Òþ hŸY¶Xû ŸöŽ­ÆDʵ2àv…Élåã åÆØµreO$S\y5®ªU¥:y}÷u$–ª]”¦…>Ñr1®`>RÙå8:©¨5‡Aܶ*v¢¨ m„R¼×ª”“’¬’fBÙ09Cªû1Ðß°•¨ÅÜX˜Êñ"êZUyub·ÀpP¸ãù¹7ŠAØt9»"‹ç¼ü_½ùÈ-# ;ΩÞ-Fª¬«qÁAu†c¼(P½û±z9ä®êGNK“¡?ß–!#wZ ËS¾h9têNª•À2µîN„{§u³#ŽË¬ã2f1ŽË˜­ñúw¿ño¾ô?üù^Mùf-´ZYëŒk“œ–έó‘Z 2T©VT~u}ÉR¤êFB«ÃÔ¨V‡­'bZÆT‘+ª;„„˽Ùi¹ßï,Q×Ê-˜ì]) ³Gž!’ -‡(Ü ^wz'ÄÅ13[]®Î½ÎÞ•à*h LNòꞪegK';>IT;a§Ò–I¬~¯»ßX:W»ÖQ>) F$''Þ2Viº: 4ç[µ4@»÷hGç´ìd>RëŠP»éæIª¾U|­usÓœL:uyVÛZ†Ú¹Ó‚já$©Öí«ÝÝcqZ–t 3«à¸Ìú8.c㸌1džÖC#«=-ª:[ Ö¶¶µ¢b>RkAVÕ¦ürNúj[ëæÉÕa˘*²¡útBчêƒ$¤õ9|ßD]k}Ü:¹7ìÄ Ó† ©µ#“îE>¢ ò¹-Á„dÅ8 Ò–FY¨V´GNîÈdRÊ—óIËóZòdg¶$¨ ©êüÁ0 íDj …»±T?ŸË&v‹ª ‰ê4ÞYM/›ó­Z`¤õvtÍ(ë¶òEß3ÕÞU}‘Î4o5ù;þœË¬;-¨öh])ôÕîî±VEÒ1̬‚ã2ë㸌YŒã2ÆØ5½µ[A.7«K·ÖŠŠùH­YU›ò[ ñ¾ÚVG”ß2fÖºp²k‘aQ&õºï 2Ù5)‡6¨ªÂ†¢M!$Ètö “6T÷ÞeN‰4Ç(€z”FYTíQf«h™„îÏÊT±˜ÉPŠÊ`¢xØ­¥¢´©ê|ù*Ù’ÉPã¹ßX„ºW¡f¤ªs"#’­øéްéNO:Ûò¤\íWfÇEP­eÈBèLE%˜Þ˜i0OÐ eÝV¾P\#E€¾•B±ê5ZH V”?qówdüN è‘ñÂíƒ"ƒNݾÚèˆÑ(ó;—`õ‘N™e8.³>ŽË˜Å8.c̱¡uÒÈ3Æ**E¸tCŠk¬ÖŠJ:[ ²ÖBù¨žòI_­V©#“«ÃV/ª´,¯Ba¤ÎÂE”I:Y·å 2Ù5)I)€ ƒìGÂ16?åó “6êQ[]NHst‚ê¦QU{”Ùª’‘¢5=&§ ¦|þîßÇ ?:sÙ¶Ÿ6 U_u`‰”tœC$y^7¡i0’&ã\UrfØ6Ýé)Pg[ž”mÑ~eN¦~ë#ÈÂþLƒIru™ÊºîëÔ4‹O™áʪæåO¦Б?[£°˜Á;- ^S~wô1*Œ©Z·¯vwu.+@ýýN™]p\f}—1‹q\ƘcC ©}lŸâ&§µ¢’ÎÖ‚¬µd>ª§|ÒWÛZ7O®[½¨Ò²¼ …‘: SQ&édÝ–+Èd×¢rwH»òÆé?L©H8Nm¡.‹:}¤¼ò´Õå„4Çå¾ê¢T™‘ª=ÊlÕÉHÑš“Ó† ËdEÖÅ1 $ÓÈ5+¤ªê|õº´!"%“ߤäyÝXDœBÐß¡:±2µêFU”ÁA*Úv¿ÓS°ãœÇåƒã³¦\YO¦"!'£³8ŽVÑ eÝV~DM$HVDJ‘€R]=ý¯îé‰6ä°"bþ*ŒÜiðšò”°:ÄÐYu§S·¯vwu.+@ý­ÖÍî8.³>ŽË˜Å8.c̱¡G£±0JE%ƒÂÕ¥[kE¥•\kAVÕ¦|TOù¤¯V«ÀÔ‘ÉÕá¬uád×"#Â(¢Lêußd²k-åsÁæ‡ö”ª&mÐw ¢‡©­ïóꀪG13Rµ§ª*Ñ2‰ƒ8ž/¨°å.–Æɹ;dÚ€Tu>´±4Ùè+‰œûEhô»6vïÔÖ1U2#žqªÝOìoίÅäp(^´{tBY·•‘ßÒr0“0€6 LÎöÄaüÙ¹Óu6å…¨ PÞIØñjݾÚÝ=Ö¯Ø1̬‚ã2ë㸌YŒã2ÆZa5œŠJ$\~´(ª[kÐZQiKÖZµ‚Ì/×£¤¿@l­›'W‡³Ö…²ad{&áΓ(¢L¬¾+Èd×Z·€øÕ€ØÜ¤ Ú-ľ°wHñ)‰Du'ŒV˜™FYTí©Ú I¥£Øëñ|A…©EfrLj½¬%-ïõ¡ HÕêòUÇH@“ðZn˜òíyÝXÄŠŒ˜:î¥YHmÊ,›ó­Ë>…i¶ u³óõœ²n+_°T‹)S¸àzo ÓâøšœÜ…µhÝiÜ3…jUž¥Õº}µ»{,õ"Ñ1̬‚ã2ë㸌YŒã2ÆZ%¬uFv8г¤O [+ªþV›ä²"rµ)ŸhÝY]çµ\ÎZJ[g '´5ê«Séξ+Èd×õàu÷ýdµ9e¶¶ZÖC²ŸÁæD–Ç|ÍíVŪ‘““¼3'[ÓcrÚ qeüÜN‹Á(RëIœø{7©¨Döwz-öqc‰°kxÝ}bOš:øäÑÔ‹”ÙÓœ_v¤åŸe¥ýZEs;¸8\¥9Ð…©(è÷wqi¿âbµz‘X0ˆfŽË¬ã2f1ŽËs„`•óÖ‚¨±ˆÄJ+F ¸0BJ»#‚Eµá5mZ+*ír!а”meE•µˆì¬®ó´ L]ž\¶zQE»¤ê^‹W¸—Çp—:[ý SKÞ²Ë}W‘…¯¶¾ã«jô1åh ªØœl@*›Ðf݉“'ÆAªûjµ•t¢iæ§Q-Ÿhò”e R9 ZÓcrÚ q5ðŠFa!¨vu¶å ¹±5‘ä–ÁPíGª¶¸ïKdÁÄî S«ýêx ­£T—ü\ä”Ù}Î/6oœ~G:¥)ÊZe¾P]ðjJ¨"cF„„ÙVÇž¹ÌºÓ hÕòNi¼ß¦"ÐW –y¬5-l½j˜YÇeÖÇq³ÇeÌÖxùwoüò/~üÏþøå”oVDK"$kÛƒ}2Uˆ‹K}fŽ„aÜ#a=Ç5R¹¹ê¬¨T õìz´ ©¬ÈZѶHù(å8¨æ·V‡s×…zÖUâ> ÇT ÐîÂiw½QFmú® “]zð) .À)ÍŽ¶áÄ®Ôðóc/àm60ÙbÓªBè+$ÈÄîÃ$mKP” FOYiùÝa>Rì¬ä«½´s<_P!Äb¦º¦1áY[hu é(¼&gÒ ÊÄ} F‡]`‘òûÄáÆ±Fç`7±`bwˆÓ#N-x¬ã¥8y’ƒ° ýž.žóŠŠ"•uÑ5d¢éVt` 9­Ë'òa¼`ãåPº—:Ë|ËÕ®rô—½‹£†qO¥ð!j•¢/g-t™eõY ”´î´@î’Ñ;£RèÔ{.P‘J ¯,ó˜j¥i™@EjNùf-—YÇeÌb—1[ã|øäääů~9å›uQø ‹rv^ì…´2C¢$VKQ^+¶HgE•Ö‚„§\Ã1?Õ¢L¹Â#¬…T]ç©ETó[«ÃN/ªÄ !ŽÉÙyd‘ÙHŽòÕÅ=Z® ƒ _-ô‘Ø4Ô3?:MGIæ %kef”Ä¢f$hˆUHÚSá8™„ƒ²_ÈaieÑñ‰ú…ĆÔæ$+"§Zk<_PyÙ÷hF5•U:¨ 8QãE&”B?^ÏÎg6Î÷Æ™;±û”¦J Ž;;|¤þ5Ø‚Mà5åGv™óŠ #¡ú‡.:Ë]jy"ºÊ©_ÇÌ Œ„‘#m¤•‰Q ¼– ùå :ÏŠƒ=@Jpª€ræã`ïÉ Ù J³c M K9biRˆcæK›è«%¬Î$å@úKÍi¡æ²ºY ÇeÖÇq³ÇeÌÖp\æ`Ä­²rªëûë×/…‘Zò ¿¢*[Ç)ך­Š”GiÊ'¬…Tn€VÉÚÉÕá‚uá›¯ßÆ=õ ªRP†T©%ú® “]ðXÜTÄ„†ÒÞÚäê˜ Yn¢ ÕŠh7UØHT݈äWGMP&²èû$î½™Ð?ágEœFyÀç A   €'ÑA:ÄIRVTÕbJ-ì»ÊqABÅñ†"ç{c‰ÌšØ“ÀžÒTä ‰ø‚@×$“Šasýê˜l¥å.N]$H¦"€;Luô‘ÐnKçʈÏ\” Up yå¼¥|™/Ð_É@¯#‚æddPšêVÇ ™ÐV½-c²ÑT%'™YÀΤ jË;-)/=䨴ª9N’–Á}µd®ÇúÓRÐà–afw—YÇeÌb—1[Ãq™ƒVH$.”«` %áIym,S¾Àj[ªŠ M®¡Ë7µ•ùd²¹j)6TýZ“j[ÄÞ–Ù‚‹ãAyšÔ—™ìZÚ¢Á S7 ·fŠÞZz‡Åwœo“>pc¬‚FËMT„]®î“ÁÈp«­8'[!?+_°4zÍÑWhZ™Èsç3w—"Æ%`IÐŽä jøÆ’H]ãuKb¿&g#:2)Ó=“¤ ½±xΔªSì×d£ €N5QÕ}+xæ•òìTÇNmé[žQýME$Ý“aÞäPªÊ.ãA¡J6L^JhTòUáØ©(@ê41©–Då ã1”ÒùFã2ûÆq™õq\Æ,Æq³5—1æÒ0¸ø6`d²,.c̱Îé§òd‡ÐÝ ©ÈìÇe6‚ã2ë㸌YŒã2fk8.cÌ¥Áq™q&w oÜý…H¦"cLd$.£çe:€˜=á¸ÌFp\f}—1‹q\Æl ÇeŒ¹48.3Ž~ð¢ú»'oÜý¡ ¤;ÉȘËÍW^àÅ‚-}5ìrýî¯ÿ8Êy.è­w3¼;€ø'æÇeöã2ë㸌YŒã2fk8.cÌ¥Áq™q°“äã0H8À†ÞW~Ç*Zö[¼Æz WNyA] ¿&Žƒ}ßšÐZŸÅ1\ãzkPBÇY¤˜š†Iͺ8.³>ŽË˜Å8.c¶†ã2Æ\´øv\f„[¿FbÂæþLUŒ1-®6þê ùWë¶.-:éÂ|=úÆ¿°Y-2«ã¸Ìú8.c㸌ÙŽËsi¸uól~zàJë/QL‰þEžãØ?aÌ2píà ÂuÄ Ç¸¾â·föŠŸ—1[Æq™õq\Æ,Æq³5—1ÆcŒ1f¯8.³>ŽË˜Å8.c¶†ã2ÆcŒ1ÆìÇeÖÇq³ÇeÌÖp\ÆcŒ1Ƙ½â¸Ìú8.c㸌ÙŽËcŒ1ƳW—YÇeÌb—1[ÃqcŒ1ÆcöŠã2ë㸌YŒã2fk8.cŒ1ÆcÌ^q\f}—1‹q\ÆlÏýêc'''¯}ûfÊ7ÆcŒ1Ƭ‚ã2ë㸌YŒã2fƒüèÕo¦cŒ1ÆcÌZ8.³>ŽË˜Å8.cŒ1ÆcŒ1G…ã2ë㸌YŒã2ÆcŒ1ÆsT8.³>ŽË˜Å8.cŒ1ÆcŒ1G…ã2ë㸌YŒã2ÆSrýÚãO~òcÏ?ûTÊ7fG0µÀ›¯ßNùæBà;Ãa¸uóø¯)ÿ˜yãµ—à“O_KùÆ,Æq™õq\Æ,ÆqcŽ“ï½ø2x×;ߎ7¸÷Ýóž”oÌ.`[…y…„ƒTd.¾3ú¯)ÿ×^Â;×W^HùÇfÝéÍãm~ï6ká¸Ìú8.c㸌1GÈ•ûNNWwo»úðƒ©Èï¾Ì>p\æ¢ã;ÃahÅe˜t„Ò8.cVÇq™õq\Æ,ÆqcŽ-m½»háÝ—ÙŽË\t|g8 ô3^cæ÷^üÊéÕóV:Â+Èq³:ŽË¬ã2f1ŽË˜ ò£W¿™r̺ðy,y¯_{<Ï?ûúÞï>wÞ}™uY—¹úðƒœ®Ûü—ò/"o¼öû‚;d*(õáÐÏå¼Rþ9^#ï û`q™‘™¿€=©5+â¸Ìú8.c㸌ÙŸûÕÇNNN^ûöÍ”oÖ‹Z¬™Ræ‘0²7ÆRÞ}™uY—Ùßflx¥à5å_Dô8FçÂ÷á0tæÕ¹_ ®âUØß­`dæ/`OjÍŠ8.³>ŽË˜Å8.c¶Æ'ùðÉÉÉ‹_ýrÊ7f-FVÕÞ}™}°`G·¿ÍØ*töÏŽ‘m¤ï ‡aËójÁU¼ û»8.s´8.³>ŽË˜Å8.c¶†ã2fߌ¬ª½û2û`ÁŽn›±UØòþy.ŽËl‡-Ï«Wñ*ìïVà¸ÌÑâ¸Ìú8.c㸌ÙŽË€çŸ} ë$P~•éÍ×oë÷,Än<}-‰õü•ûN’’ÖöúµÇQªïŸßºùL¬‹ãÉÿݨ6Wýæ?ÄPÓµâ[‹~œ@(ƒ|žÂxj&“ËñÔ ÐéÈC\ACúo,œªÖàŽ@,Ö"È©~UíÎ+/°Ë,ådP‰[58ÜPÅvÑb*š™2)©ævŸä(‚@”oùV¤ ;áνÉ)ý´ÕY…§$Ž”@öZíH΢Ȥ‹äÚ†ÄSR½úƯSaÐo˜´ª‹Ì(F’ÃNÇ;®Ù¾°ÊEì,OçÞ0FñRPÕ™{}ÒÌÄqÇx#5 ÐñþL{¸ä@Xˆ¹‡|s ¢0àHAgÊGE䣔§É3(ítFR­äAuþ°k(=&½wFÍ8žœ$Éxhæ D&ÛË bôÔ¯ñ™àC¾_G…8-'ð,µ$õôGͬ‚ã2ë㸌YŒã2fk8.s°.<],ååN±bQJUxK«–$¬º’< 1¨…c,æ(™R¹ì#XÁCç™P‘ 3.@õÙ]+Eo°\AV›¨ö…`5y&T$%a@ýT˜Úš\Á·ÌcB/ʼü€8–ÇL2bÕ¬áÆb~kÔPuáÑn¹Hª’pÚ²¹œä÷BIkZ¶¦1FÒl!ÉjŠ#EúcQx-F\„A<˪¥4ij®SAà‡Òž4¦s¯¸’Žëâ`QÝYpg€žVCZ-Z.EÉ? ã"È·nï{8W•Ó~VÄ«ä «´òñŠãêä¤ÚX…ôgr¼ÆQý,·‘’þçOø¬ìÇSËÐ2–È]­º‰Î=A7Ø–Sœù¸­u„Ó…6®,»ÍšUp\f}—1‹q\Æl ÇeVE§kž¼¼ÓÚ+0,»±ÞÂÚ(-¤ZP䱸ÄZŸJâz.mØ€vA&=(­nÔ£Za­Øb¡Ub)NI2Œ2xÕõÇíMZ‰èa)tÊ8 $èIU Iy@’Ç8hí—L:ÕúVu«9ªB‚’T,‚%<`‹xÂÔ€WP†b²JEèµ:ýßòjõSPdJ •¨ã8HE„¶!Á¤j>ì¤Á­IŽM)íABG°=(;ȇ"ð‹P :f…*¶Ìð†Î*<%iUí"U§kèg•Ž‹úÏË$·H  “¶E7â­Ä*€¥l—2TŽƒx7PQ¤IˆÖBJ¾ª*gµEât•1:``çiÕ·RÕÕa)«ÐÎ¸ÙÆAªÒAµdˆ®ˆÂ² Â8¦0$x,V!ÕVp€Så/¸R¹4ó•’µZùlˆìi´E©Œgd ‰yÎA‰NšlP"…8`‹EPE$XBÍ¼Ž˜‰ºåmP¥H´@9sÔnéó’x;Õu¡®IzMûOÿX@uæÃ0Þ cwâW»ì6kÖÂq™õq\Æ,Æq³5—9Xê®v~ly§u$ÖCÊ$XEUÃ"%XWa¡V.7ÑVu©HÆ ¡˲Xª…ÔÆ| !d°¶‹Eñc^Ä" qŠ„V„HèTÔ ™™ÔS•jõYÖ’©H(ƒ2 –Â0c—òÔ¦Règ>퉎ݱjîpCž «›@d²´œ%“ƒ(û£å³&¹&X9÷¤§hv)5¹¡"¤ÎÜKT;åÒœ. 9‰T––̽T:²ø:•f–ªnT²ìŠk¡K£Ô&¨“iüΠ1Âk9Žº.FhòG· 2£ýѪ²iNió^N]HíBFÞ@B©ŠÛmå3á8öÇ4)yóÂU·«ûå…0yó²§T®ê鯢K)E"`ÃYÁi*DZDUÊ FY9†Ù©H ¨Ú_ݷ˺#jåçä й͚µp\f}—1‹q\Æl Çe€Ö…q}¦Ì=}6¥ÕvZª],Ëõ¢Vfi!÷9i;A°¾×ZJb‘Z¬®2‰ê–‹EÐÚGaùˆÌ–IÚ ¥…>k1%SwAËåÔM­•‘БXÙѪêp÷×Ù}ï%&Qö/›äš`US¶Ñ9òyÕ±°Dóª3÷ÕŽDdI¹$êu«/‘qö¯)Ÿìr*qKéÏ™Ö×B—FÇQ²jÖAcTîÒÁädKP¯­pyô†æOk@esôÒ¾®U—È]KEñj>RÕ‡šÕÕQ«ß²J©PÚZW±&^«9v?õBQU«{ RëVi9ªÊÈÌïPí˜T;9ó5ªóÄìŽã2ë㸌YŒã2fk8.s´¬ŒË»É¥äŽTùXwÆ|Q]ó©VÇZ-éÒ®Luqó#­…&©jÐ:¾º'­5(ÐH{ 5qR«|ÓÚ5­’‹Òp˱i³7¹@OHË<Ù¿l’kÔš–R hm˦"ƽZíH¤åR!ßâ5•̽ô5k˜\§ÔŒÔÚ’-¾âZèÒèÈö7o¿˜ðÆi CŠ{*ñ¨ð0ײJAŸR€—C'¿«ÙÚPVi²Ð} j ëâE­.·.dö1Õj¡&Zw°È2ÿ9?åOª]v›5+â¸Ìú8.c㸌ÙŽË-+ãòN{$,éZKÃÅTíä‹êšO+ÔÎÇh­ ŒZì,õèŠÖjRš£-1'ÕVû’2wGkâdO+?±£UPÎVÒ°¶ör XŒì"€ô·z¡ ŸäÚYµ¦¥Üƒß–æI³Kª2£5WI_Idî}@]NùDí.¸N©¹Ó¯ÅW\‹gö­ªÞ†è¨EeZ;y1k I8]n‰ÒK²g¯‡ –ŠDi¡aãùbÒª’V•É!`ÅŽ1Ò ÛÝd¬ °H“W1xþÙ§(Œ49Uo#-ZΟT»ì6kVÄq™õq\Æ,Æq³5—9Z¦Å>›B +¡Î¢¼*¢hÀ‚Œp©Š”m#ªk>fvj-éR]µØY­ÒZ´’ò‰4G R‹º-$ Z ÚÁ¹`Y°Ï6ÁæR7«Æ—̲j|¸[ÛÊ;AÞnõBÝO NrU‡L @Rµ˜‰Wå$&Í.iu„´öÆ )A÷SQɬû@¿Ë}ã‰&dRBÍ~É™l!T·Š,é4J-iˆã«L$–8+î:Š(²92…îì Ó¼* w˜ëX%“R> Ï}«Ðñëׇ» _­2i?ÛBÂA HƒœY6'dÒä$!š*Hh±fi]àþ³!)ؼ&ÉIµÈ§}R…- fG—YÇeÌb—1[Ãq™ ee¹¼{þôoVXÊ„Óή¬«[­¥ª)5Ú1†Ð茙j¢U hQ˜êªE­‰K¨¿µ”æ¨Aj'SR[íà8jh¥Ôͪñ%ƒVÍn kõh€‚5W†?•·[½P+¥#“< tRüÌŸ®è8mÒì’NG€B,E¤d°Ýñû@¿ËšUã‰&dRº~©ï“©ï!K:ò}«¤!úY™“ Ê'PBÓî¸TH¸?îå0•9%ê„c~ßE@×±ŠJ’fÀç‹–Up8n;,­¦²Ê¤ým))N*gvüÆ>" =…Ñ£³åi\ ÿ‘T&%ùIµêÑdŠ·Y³"ŽË¬ã2f1ŽË˜­á¸Ìв²µ¼Ãb1-UG>fú€Žë?4„½Zúä65:i —niÍ'ÛZµŠ(“êªEÄüõ·V“Ò5H-z ªBª$>Ú=°9lEE©›(ªæ'F¬Z0Ü üƒ„§·[½ ýH¥mu&¹ªËŸ-TP[Çi“f—ô;"…KE‘ØTÔ¡ï"Òï²êV'(¢LRº~©ïs¯¸¤ÂN£}«¤!ŽoTK{ZLeÀ¬¡”p¾±Sx•ÌA‚UK ˆ2Žù} \Ç*™”òÙ£ñ|QµêÎ+/0Ÿu1‘pwÒpT«€IûY¯RUEi€Sêìø}D‚p*êƒN©. ‹MƒY­£:nÝè;{X„üTeR­tκ͚q\f}—1‹q\Æl Çe€–•ýå?H¤d¹ä*Áž\Â¥æV£“ÆT×|ZÏuº€"ʤE¡ZÄAÌ ¹²¢æ¨aDm•j¡Hå&­jd'?1iÕ²á˜W4[ÊÓé“Þ™! 5É«'&;2ivIßd²b©(²¬;¤èwy¤ÝV¨¹Ó¯Îì3â̾UÒMQ;ά^ —ƒSYq¯wµý«7¥I„†ç‹ªUšØÕÇ1ªUÀ¤WY±cLÉÈ$a‘:ƒÒwli@ÇcÑdëê2Ê_‹§Ú²¿“jeϲ™Ýq\f}—1‹q\Æl Çe€ÖX#‹!­\'…û«ÕV£“ÆT×|²ªÚÑSiõß·“´V䦖nÜ}>%-y'i-j'‘U;«Fvò“VõݨÒê°jø°UЗ˜ª[£êEkkGû‘ª$ÊI®G®ý1™l´ï´*}ò^þp>/˜c¢uèkÞå:¥æêÜ&‹¯¸èví[% ±¿e rô¸ÙH¯%Ü鑬Qf¯Wm1ÑòªÌÊU«Z­j0y³"Rz,¥OßÀ>"µn/“´þèjræ÷›fiiù¤Úe·Y³"ŽË¬ã2f1ŽË˜­á¸Ìвrdy7.,ÉçŸ}*-ⓞIýÕ5Ÿ¶d­à©õÌvÚNDX·¥\âº|ñ¨¤ßýG4T/™´jÙp Öå’Än-‰uP/ªc¤¾#U H”“pÙž_ÛŒjŒ Ê9CúÎȶ–¤6§"2k'ߢtéÏ“]®Sæw*®ï “ö4-ÓøÒKH³&y•‰kýÏ=<£¹H™‰êÞø`WµJ&A Ñ“ãù‚-&«ª™D!Œ²T£Üz‘ýã—9`sHÕ Y#‚”®ÁY´ÕqhÕ"Ò¾Zuj­Ðª™‹ã2ë㸌YŒã2fk¼ü»7~ù?þgürÊ7+RÝba…T]"ëƒÓɵ Ô–«ÕΚ²µßýu$Ruq¬•q¹àCC,j-A5) iÙ-_U·å¤trgQÛ§ÓÉ?ÉÈ–ñ‰I«– · yxÕA˜„‘Ò^­«)0k’K j)3‘´éAÔMÇi´ªïüHÇÏDÐ_ö.¶;˜å"Ày‚46š{²bë$Ë®¸l¯)_ô­‚sNÍÉã;òÜÊ8òyÙë7_¿ÌØŠ\TzèR-»Ìž"xऩ´Š}ÏU«˜‰×ÖwsÊ*@£\‘;K×K$ÍL]È¥Z SG§h=¢.æy£ŒÂk¼ªuûjÆo³óaÕ¬«Û”8.³>ŽË˜Å8.cÌ¢õ_\Þa‰ƒ…ÖXúð+¬È)ÙZ€F´)EÒ¢0*aJkʪ1®Ë…¶:H0­£-€-úQ+}–K´DëhUÒö€­^£ŠªÇ|´.Ͱ!îTa æj2õ´ÕÁÔ\´ ))Ù2>1iÕ²áZÍ3U÷~}¤FÂ4b&¢èò!32ÉãC7¨õàÞ£6e’8÷°Ó U¦=¬‚ƒ¾ó#ò³â5¹‹ƒEº™±]$t!Vi1ËE ÁT4 bïpJ$¨… ô¯SZ^¶upüŠë OrÄ:Õö­‚<«—ã+Í8ÀÂræã§hšgEœ™è`ušI~‹Ø4] y4Ê|$ä« ÙëÀA 5 ÉÕQ3ÝU©âÜ|Qµ*6§{©)U!Ô†ŸÓrô" 躀$d¢— ŒRä—š¥E£[4L² ™©b T±iõ 6¨¿ÉZ åŽ8󡇥Щ̨ EÌôÕ‚·YäŸUð vÆq™õq\Æ,ÆqcŽ­±â(-°ˆN£d­ ‘¢¼jšTU‰pa )ÄæÔŽ[:SE¦(L=hZ9H² ŒOEØÞ$ÈÙùiJ;™N'AsÔ‰”ÚByœŒì±jÁp 8LÉ'#`¿ÁæÊ„ÖW™äêSª‚„ãT‰1Á¥úrDßù ŽEL©]XžM§©(ßa®‹ª£.œe×)e’ª’W\‡xA)ÅÁê[…Ž”Ulˆã(;£©ã›Ì43SJA–ä"¤tšäÅ^.)WBuØÃëÇ©}8ž/ªVÅ«„§¤ÎT…TOÞˆ—RÒ(ªÓ -jvUÝžPCe»ÕU›ŽÓ˜Þ`Š q@oà@ÂbR-˜{›•Ê ÍÌÂq™õq\Æ,ÆqcŽ,e¸îIË;¬®âb §X;ÎÚ3SùYý +`m#P)Ÿð³M”žµwšpоèsÂ*©³i©ÊËu3©¨. ÑnéI$*Œ’~'IŸî"á™(¢Úddßx1hÕÜáŽÈìäüqÐ í¤$õ[\™Xeî$Çx¥&¨¹5Ç™ªàXÞfݾó©›8@ÓI†_`‘ NáÖ®»Å\¥á2¾°à:E)ÛMù%s¯¸>唎Ç)Õ*'2yq%åLÈY0L¥KqÜêošBLy±×ãEz¦ô®=ô6¢<`/ÆóKK«JÏà˜ÃÇü² IS^JcZõ2[3ÃÒ3ÑÓ„SÞÓ4»:7UÑq˜$Ešœ8Ž3¤.Sî<ºÙFa1©̺Íâ”’xmMB3ˆã2ë㸌YŒã2ƘÖLXö‘T4Ž4lÙ¤A*ê@ùr™¸ ²gMÚ¾ª¢nÎn}L:þ˜@4:·ïrHE-$Fº)«@*Z†ö[]±³Å\I>å'¤sRrQùød¨"=)¢owlbî4“ð ¼X\q©ÝeºîÈ\7 VéO¶¨¤Ò*š!;Nc vA*ª2)<)Pe°–Ä@>Lª2#8.³>ŽË˜Å8.cŒ1æ\ðgžÆcÌyá¸Ìú8.c㸌1Ƙãßh}MÀcŒ1ûÃq™õq\Æ,ÆqcŒ1‡çÊÝÅœû³ÆcŒÙÇeÖÇq³ÇeŒ1Ƙ7Â7¦"cŒ1ÆÇeÖÇq³ÇeÌÖxý»ßø7_úþüG¯¦|cÌ¥A¿øÛùscŒ1ÆìÇeÖÇq³ÇeÌÖxìç?zrròíçžMùƘKï½ôä'?æo0cŒ1ç…ã2ë㸌YŒã2fk|⑟œœ¼øÕ/§|cŒ1ÆcÌ*8.³>ŽË˜Å8.c¶†ã2ÆcŒ1ÆìÇeÖÇq³ÇeÌÖp\ÆcŒ1Ƙ½â¸Ìú8.c㸌ÙŽËcŒ1ƳW—YÇeÌb—1[ÃqcŒ1ÆcöŠã2ë㸌YŒã2fk8.cŒ1ÆcÌ^q\f}—1‹q\Æl ÇeŒ1ÆcŒÙ+ŽË¬ã2f1ŽË˜­á¸Œ1ÆcŒ1{Åq™õq\Æ,Æq³5—1ÆcŒ1f¯8.³>ŽË˜Å8.c¶†ã2ÆcŒ1ÆìÇeÖÇq³ÇeÌÖp\ÆcŒ1Ƙ½â¸Ìú8.c㸌ÙŽËcfqõáßõηƒ;¯¼ŠŒ1Ûç×^zß=ïÁ%üÐWRQ\òWî;áåOžö©$sHhLJù›åúµÇióE¼yÂf^¤"3ˆã2ë㸌YŒã2fk8.sH°¾ñôµ'?ù1rëæ3I€`õƒE3€L*2æÜÁÌÄjé{/~%æcnsÞ¶&öF¸úðƒ0{¹7_¿Š6lƒ…s÷Ìf³lm@qåò†U©¨·å¬¨t¾oR´gV/θ‹~K7ϰ~¸~íq.î·I`ßhÚœï _h—YÇeÌb—1[Ãq™Ã€åå¢9åb9*MEÆœ;Øq~¦­…¦÷–?¾Æ•(;·ù©/¶[4é"~¨nÐeq\׬…ƒ[7Ÿx«:ß‹ˆ×ò¥Ë¼ùúíÖúá!ÇevÇq™õq\Æ,Æq³5žø¥_899ùý¿šòÍŠÄ­ ŽÉÙy±=Ú¸ ? \ýÁø=©=Z&ã2e¨ñ` 1Ü­íb¼ÿóÚÆÃNX›J/ýá868 Ëâ2¼pðšòÏšt¹ã2“뇵î·w^yæ”/—ÙÇeÖÇq³ÇeÌÖøÓïßúösϦL³.ú˜ËÇø³(-+±<ÂJ EGJX¶U˜dOjx’.M[ LWLZLÝó}(€;¼¦|qýÚãèÂÕ‡LùÛß´º±ŒÉá8¶6  îŠÛ¼‘rvmʤ> â2è«à ÞZ¥ i•³jÙ¦9à¸Ìb—YÇeÌb—1æØÀBêt%óÖΤú{·n>ãG9ÀžÖýÛÜN\h&—ïç‹›ÂñAÜUå|Ÿ†Kpv] {ûܸŒ¶ªöQÚVñÀä]sÀq™Å8.³>ŽË˜Å8.c̱Ñ_W±`«0žÔ3“Ë÷óÅ€MááØ îŠÛÜ“_ú¸Œn¶ñIÛ=€´ûÝxòƾÍ9p±p\f}—1‹q\ƘccÙ'ZXU×Feþ»ð4ø$3ªS´–zâÿ©ªIƒtô äÄNE”È—¶R!Y  HjQw—߃ˆÞ»~íñÉo÷ĦÁø·0Žª…†:6¿ùúm´5CžµZsI³ju–ïÈ)3Aʇ…lLNB€º2T›lEž’Ø;NŒ¾{ãØ'TAat»üÖŽ¥ÂJ£a³ôÓ1GÝì÷128ߨÖäp´˜;WaF2ÔMUª#U6M8.e¾@)(Še>åu*cZôÐ 4¸c‰@£ª¢!F£§WðлG]V¹úðƒ4´Æqp†€¹£œàìê÷"Ór,»Ó±ôeFZ(¥¡*• -]>©Hè[ÒÐœŠÆa×tcÇX3Ä¡Á)ÔVœ]^G „ò õ}~ùp\f}—1‹q\Ƙc‹•Ó•ÌŒOŒËÕà*ùXñT §Zy—<ÿìSZx)¡JÙ Àšø¡Ú@@ÃÜo]AU|¥U1Åa Wµ Jà7I‚qµ¤åŸeÏíWíĺº•ªº öô½]m9†(€c¸+ÖE•(‰y[zƒ®P~r8•—ùšÏÌǾ.Ù …© ™5Ü<+«%ZNh?P¿Áe£È‰J"TˆW—~CEt9ÊOÂÖ©0Û’r¤Yú©™—üܨrÊù6>-Æçê²›UµûôLl:Bù2Ÿhž—ÇŠ­|6š<–üÉiyVRéùHy­á>é˜Z’4Ä”ŒÏ2>ÊU(ßê”W¡Ãæ<‹:ÞL9u[!ì/Rº}UÑâ¡c˜Ž eu­šÐIjÚ°kãwr²î;ìÅq™õq\Æ,ÆqcŽ }äõÖÇØú#­~"T…|-â‘CxŠT݊ĵWY%íë°€V)°–Q¾¿y‹@3«HT©wÈ¡L5Ŷ¢UR3ãÒ\-?‘JÍ8ŽÂ“Ħ¡„è4}B˜šNòHÕ]7”tZAÂq9¸ˆGQÚ!Å>¢âYn¡bj7-Á©¼Ì×|Ž1‹¨ ÇÉ-@fÓ13wtc™â¥GP]9Fý‚9H¨[ÚI…xÕUVV¬b V„˜ï$8@)`^£dÊ/¸ÌoãÃÑbp®.»Y龄aÂSئ¦S-Ê”ùDó<šGX±•‡C)^Dè%‘púˆƒtÅÈP 2„§ê~iR‰j•)†NözGjÁ*UI5‘f óñZ^Ý=eEÜ"bþ¬Vû‹T²„„qŠDgÖ ¢»V5Eµj óù—›iU$UiY‰Uµ h­_#¡<ƇґÍ×ïþ; NÑe­!ŒS¡ZÚº[ÇqÕàqµ C@y~Ï¢äŠZÁ£Å¨ fÓ±uÍ Å $]Ä"¤r?£.§Vp¬"茎°ù´„uaÆ"¶ÎR$ôE  |¦äF*/óqÊ|VÇ«ÚBë±-U!(ƒÃ ÐP+<%QŒÕ!34³.4ÇFcßQ]ùD )ëÆA¬>/P…ªRCRG à´4©5ËTø–ùÑ«(•¼P)ç=¯5@2çªZO“¡s³‚VA¨|M`UTiåØvZ»2CX±“Zï­á€˜­‚ñCÒ=“ÈàRsìK¼ÓÆ ‰TV,Á¼…Uð9«À6œ’(¦^à`p†€ÁQn¡Z)_÷UÅÑõË-É á5fÎmh\’÷ªH?j¥"=”I¶Í‚£mfˆýÂ)ä õ£ÆL¤òN¾î;ì…Æq™õq\Æ,ÆqcŽ­x˜pÚYtjõS®Æ´ôIë€%ŽJ¡!)RP]ÞÁ’¸ À)…«ë$,[;¥ w:+Ôk8'‰–¬Ùw¼¦¢µÔM~#*M;Š*”ÓÖÞ’¡(‚œéˆfW›Öš5¯1juŠ6#¥aÒ®©UW2¥ –f¤d³*¦| ª'7FÅ|°`¸A§ˆ° ¥€¼]Ûè5#%âOÊ}]ÿê«Â†’ÿ'û5‚º€ƒñÈâù›=2WeXuÈZ7+HY >‰.J¥ý¾hž—Ö²b+Ÿ©5Ûa$ª!•¦êÒ\ª•[ZŽ-QïªÓxñ åUÇêþPU¨¬b©îBÕ*Õi¶ кIVA] wnhˆ2h.ÍE͵lÓ@‚ðøœš‘_Õ¬Ò¤ðRâ¸Ìú8.c㸌1GËÕÚ—±Ëç @g, iOEª¯õ7±%“‹¤qmZƒVw õ¤¢dvÊŸT«Õd¹I#³zÑßD%$ãb z ëoe²³HÕùZKdõùQaDÊ«sLÓ )-²¥<åkP±ŒUµ˜*vh 7 yÕ"R­/“ª‘@×Wú@XöÇëNh, –ŠZÐ’$/óbæ\¨iüÔÁ¹ó ,6{|®B`Öͪš)âgû©¨_±s«aÅV>RëæsrrÊi [%j¨:É9Hû¸#u sR/Ô»V¨KÖÆåçr.)å—µ¢þŽÜ뤡/,ËSþ\&›Ó@[ãwr ý*ï°ÇeÖÇq³ÇeÌÖøßüÂÏ^ùÀ^ýfÊ7û >,M¸ŠR*+Zý”+`ÖÅê'å}+*³³ôô›\{¬ã2®µÔî4Ý¡eÕ¤Z-¯«;U LE%ô^[Å…‘:m ´f‰•T•¬€'•ÓÕHiL[[9°œÏD}L;t&á ýI@‰§˜Kž¤LªÛ1¨Vk–° Iž­ ^ÈUªšEõ²Ë|S~¿n•ñ¹Úq,[ŸŒY€–Í­|¢y^jfÅV~K!µ›O©\÷´Ö×1µEç*Þ÷©CÙw€SdvŒQ£ñžËŠ™e«½[ÖŠ2GîulbR¸jÞ&›ëÌR½“¯û{Ñq\f}—1‹q\ÆlO<òá“““¿úå”oöGI[ÁÎꇵÒ2TT+j!ØZKE¤ A¾Š,k¯Z¨¡zöl5Ýê] ªˆÖ*yR­£X¦ž-+G £sJ3ªŒÃ€ÓÆÿbø&{DÔ/È+SÚbfdDyU3h)—Nu!1iA©  U×MzµZW6´Œ$Uåcku\š¨Êk‹Ž„¢Ö§ô}ú–À±Ô Ì¾ý(¥äc>[ì8§Åä¬aPá*lIJÉHU¢es+ŸtÅŠãùBÖâFÊ•”VµÆBtLm¡*h±UÔ×Vµ ÚÊÌqª”C䢄ޕp¬Z­¨«"¶)j°¬3s¤¿òX?h%KRþ\ªÑ@ÇEª½“ÚUÞa/:ŽË¬ã2 ¸ó×ï½ÿýï½çÝùèÏ¥¢£Âq³5—9/ÞøñŸêˆ»¬Îê‡+°Öò¥ZQ­Œlä¤a$ŵW‡ØM$¬V«–¨éþâ ~Ã2~ +R*צ“j“yÔ7 ¨­‘%rkÀPRL­ë¡†¾=êWœ ÒÖ»‘Q椤¥\:£%‘ŽUs‡P²ãUÚŸª›¨™M­*Œ°VÇ¥‰–<.€„c8.Jbú–TGj—ùØ"^cæYAdíH’©í tËæ~_dOé(Vϲv2E«4“®ë4P•Òo{½#õ©:™#)õEãç¼3 (]hËZ™ÕߪÇØ“Šæ¢æZ¶uæ©öNj'SÇK‰ã2ëã¸Ì¾ñ­§ÝÛÞñη§¢£Âq³5—9_´d‰+’Îê‡kÁÖò¥ZQM´[i@C¨ØaÖ—)°ŸDjfÂb7ɨiH¦"÷¥8ˆF2¯©Ê¤ZäK Oë1l1Ò]Š"ZéJg™S¥‹“AuѺ2##]椤¥\:£%‘VÅà :E„ö'uªe$¡r¤hjUa„µ –ò[tä±9LOÛá¸è¬Ò·¤:R¾ýtRr [ÄkÌ¡5+„¬…r´Þ!Þ¬¤6ÙiÙÜï‹ìA‹©ˆÇó…¬…$ûÒ"v§¬5é:H¦¢ªRúMFöµÉª¨Au[¦ö©:™Ìï€÷ jу8`úcÇ¢©•Yý•pôXbÁP¶€ªjÙÖ™¤Ú;©¥C:L¾Ã^—YÇeภq\Æl ÇeÎ}7‹l™Ó£j¿¤­ÕÙIw–ÇZÊ¥S]HT+.n0éÕjÝÁˤª¼c a­ŽK#òׯ=Îv™·4}ÍÕ‘Úe¾¶ØqN‹ê¬ˆÈÚ¾a ©í tËæ~_:ö°âx¾±¶¤5bëT¥´d¯w¤>Uö‡©CyOÖ£@8YÖʬþJ¸üCÈù™AƧMk6V{7©ö¨p\f}—Y€ã2Äq³5—9_´Ð‰Ë»Îê‡kÁÖò·ZQK%}ØAZMì6ìR|\|²i¬;)P.‘å*yR-+" îlû°k¥U$œ‚Å Ôkõ¨ß •#E'W×Í‘‘oWÉcIIK¹ .ç3©V\6Ü€Ÿ´? ȆølE¢JëCX b)¿Å¸¼¦Ç஬¯¹:RÊìtP3RœoÊï×­ÒšNB†;h§Ýè–Íý¾tìaÅñ|!'ŒÜ½EÿÚ \§*qn¤¢–g;‹4ëŽÔ§ê@föiU§æœÉS¨*oÑËZ™ÕßÇ–o‹Qß[¶Éžrjï¤v•wØ‹Žã2ëã¸Ìö—yõ/¾÷žwƒ{ï*Ú&ƒq¼àFvwÀÛ<[iý¯áå½f÷g-w.ŽËœ/z( .¼:«®1oS>©V¬6ÑM /MŠ«7mz[½C>J!Sb¨4åOªÕRr•[Í@ùjɈ0O½®fFZá•êº91©œ¥’–òê´ŒT+.n ûS¾¨Ö¹LZ[úŽ1„&A,å·˜%¿¢pk¤X ¯sçPÝ”?ɬ¹šò;¨­Zh©å@#¥ØÑô(ÝK…ãùBÖvdJäºVì©cj‹ÖÜ òØ>îHªÄ)u.È3x;@_¨¿º_ÖÊÜþN:vR`…xZ¶õç¨öN™G¾Ø&ŽË¬ã2 ØS\æÂ=†3—ѽ·ÚT´"zSiÝa/7z«_—\J—Ù7X‹tÖmú`3. ;«.ÂZ“¶U‘µªAXÔŠ &-Îöwg@sl"®Þ€–˜1Sè–UnŠ §S·¯V‹o¼¾ùúíT:u­5FÐzrw¤ÛTÚT§MDi¥0y>ÒW®Q@JJZÊqÊüÖŒªV\<ÜŠ„e]êD¸¤"€¹!tE· V„XÊo1K~EáÖH-žo€ÎAj G‹ÖtŠ,»YÑ HeÉàu±¦ï¬ !€ƒÁ…&°ÌÃÁd]ˆ±ûðC*:*—Ù7¸pâª:%L¿òÁL~–b–¦"®`Z“¶SW„.ù”`^¸ÙV5AU .´À¢¥¤ºØ…‘¥<”H ª9¼ðy,a1©–2aBõêÚ·EË{ÈLíL€ª0RU^ Ë­Š L†$è%¤ji¤ê Ž»¦YRÒR.yÄ|Ѫ¸l¸A9Õã|ci«nÜ¥T½R@_!`/ –ò[TåËN1A8ù­Cß’þH!“ÕË…JË;{]Ñš% nVÐYõ'/sjÃk¬BP±l 9°¥,*Ý;7¿†•í*UgfçòA)»?Ò4éÏ ²`†Œr•ޱd« ;·ÖØ èI¥‘¹­,ëokô‘ɉW"«:Ý,AC¬¥„&T:9:½[÷öââ¸Ìúg\FG„9ùèϽãÇo8Uib2€‚ŠISUçwn?‡|r&w*IUv¤ì,Rl¼÷žw§Z¤Úµwýä;Ëû–¸7‘3¹Ó»U$UYîŒTuÖ@ÑDir&RUX° ^yߺ™ÖI¼e§Vpš¨.æð¾X­‹Ìò • 8r&úã ¡Vªr¹q\æ0`ÂãbÁU 0™[ ¾7_¿ aP 0¿µëT$ÈG»²+¡rÇAC¸"$ |Ö‚—vR2Ò¨„ËžB!4HÇÈA>= ¢p¤¯–À?Q9€»°®e³`Ç¥è¯Q‡fRž”îíÌ+€"z)~µ¡ æh¦YRÒR>2-«ÁâáŽÆ«ÇúuË«:“vR!K[³®¤%GÁY58I"}K&Gjî|áhÑ™U’auû7+T‘pì—x•d"VŒÝA>-CíìJó« «]€þ¢ngf¢ Ì“|iê`Ó`rnè‡Îñ2w”¬Ûé&^¼¯8¡ß€œÔoeqÓPئÑ,™œÃ-`¡ú’ÆnrLö©hÞëtä’á¸Ìú8.ƒã÷Þónž–éƒú@ª :q™¯}ýKeØ"¥¤SÚZ©lebg¡¹emÙèwn?—õ“?ùγ£Ó„[R¼\Šn¥wØ4z¦®‘pK•0¹wè]7è²Ñ¸ZÂqlÇ­Fñf¯ZÖž•¦²nZ¶&ù2¥A¹ô8.cŒ1Æ®"ðšò¹h¡×óf 8.³>G—ùà‡> ÀĽ÷¿ÿ©/~úk_ÿRzœ™­êeðâÑÇaÑ{ïy7ƒ>JbP­¤Zí²j™#¢ð. jBý‚yðƒòÙâoüöçU‹È~ÖýÎíçp%þÉŸüÉç>÷¹wÝ Ð¤(î¡àêÝ' ±,`ŽˆÂËÐçŠ_\¹ûXá8¥ ìÄñ÷^ü ¹ñôµj©ÆÎµ²~Š¡ #åÈŒŸðÈIÔh[ú\fPé¡®(Öƒºj)~xÅBÐ:sÈøÇG—ÇeŒ1Æ¡ÕKÊ7æBÀ Œ•sÊ7çŽã2ësäq¦w¼óí)Pd²ô½Å7zT2©è‰Ï> ù¤M(´qïýïOE £v¾sû9éG[©T!›jHtáÎ_f&®DŽæ¼ò¿wèß»ûàÌ^—Šz<Ù÷\?}X·vÒP>ÆÔA¦V¼ù(ßBÞlÿ/)x#üfDUùCáàS@¯;¥Çƒã2ÆcŒàÒb¯ 0cö?°Äìí|ÁÍœŽË¬ã2Õ xê‹oYÈTFm˜?7€òÄgíTÜw\æÑ»ÏòT¿œ…>²´ŒC½úƒaK£+—Á•Ù‰ l'.ÓG!•ª\Ù0]mÿ —Ì(ãS@•v©F…ˆlУ4Âq⸌1Æ#¸rØë̘=ÁEõâ…½Ù+ŽË¬Ï‘ÇeZA¢`ÄG>ús1q¥_qßq™þ1 ¾”­+œ”B61.sç•(S¾÷_”¸LßN®lú‰•¡ o*•JT±õ8З•Ê>:.CþÕõÏýÌßùé׿û”oŒ1Æ!\]T6Ælþ4oëùtsî8.³>ŽË¤¢ˆ¾v”â—2.¿å”ŠT1ŧb\×§" éiÃK—éÄM€Äªq™Ö·œ:Q­ˆ‚/å35ŽËcŒ1&–^cÖÅq™õq\&EôC¼‹ã2¯þàE }7ê\â2ýï1ɶò{LŠOÝ{ÿû¡Düê?}üs§é3Ÿú¥'Ã/ï¦Äfã2o¼ölz˜¥jg«w ™Qý“¾¬”Œ¼u󿣵Ðó2å ¥­"cŒ1ÆcŒY ÇeÖÇq™TQ #‰MVÿÚ׿Äz”L©Zqßq™øM%´‹îüðe_ÐëXZ½h¥¹À)ó7—¹u󙇸cjI©j§„ûq™øM¥7_¿‹PQJÒC7Šª &ÇeŒ1ÆcŒ1ç‚ã2ëã¸L*Š,‹Ëè)&ÈD”™j}Çe@ü?lØùµ¯ ¢›}Ãbé{ïy·øë㞟:Mó¯ÿµ÷ÝóR~ÅfSqýò.LŠ(3Õ*íÇe@Ôc ëæ3hWùo!!É“ʇq—1ÆcŒ1ÆÇeÖÇq™TQ\æ½ÃßcŠA™~è³þÈéqt„MTÚ… © @>Ò£4é÷eZl'.ƒ2=p%=´Ò·SQ•~\æÎ+/H²šªq“þ_Aฌ1ÆcŒ1æ8.³>ŽË¤¢ˆ¢ƒq™øÒO|öÑXDÎ7.£0l»÷þ÷ËT€s‰Èýßým±‘¸Ì¯½¤ˆIõ×ÝW‰Ëð'` |ãék0Iµp€Óê΀Ý]丌1ÆcŒ1æ8.³>ŽË¤¢ˆ")ѪÞÿY_p¾qv'*ÿÎíçШN[èÛO)>u±â2úå—–»Çeô·J=pE™ïT!1f4)\ÅqcŒ1ÆcÌp\f}Ž<.ƒTýs"ð¿ýù3‰·½mðëH­ï=‰­Åe‰ñ¦Wð¢ò/V\f2rÑ·s$n" 1.3ˆô/¨ —1ÆcŒ1ÆÇeÖÇq¤jhF_Þ)­Jÿy™øŸGUïÜ~Ž¥Hh"•î¥r˜ñÄgE‘$œPÝè«Á¸Œž"AZö0Èÿ&ýçeÞ|ý¶";‹ã2±§=p-B8’ä# ¬ ¡¾d•Ý¡ærð§ß¿õíçžM™ÆcŒ1Ƙµp\f}—aº÷þ÷çös,ýÚ׿¤ RùK1ªžÂ+ñ÷eR¬:U„”* ÉÀ€;?|™™ÕŸªY€ÂFÕ„¦ü"°áL.ø*Æeî¼òÿr¨úÓ- j¼/ü{tUr1 L ég\nÝ|F?î¿+”žIŒŠª¡ ôƒ&ÐL±j‚“*‚ª:ýºrßIÕ¼b&Z‘+Ž„'~éNNN~ÿů¦|cŒ1ÆcÌ*8.³>þ}ýx cg'§©ú(M+.âÿ1¡ô½§ÿ'-ñȇONN^üê—S¾1ÆcŒ1f—YÇepƒ)1¥Ÿû¸ Hñ %†xúq@˜ÖŠËįYýÆo½ ÈôñGÐYäS©úÔ Ä¢L™®Üwrç•ÒuKbÔ€©_XŒ¾©Sеžgá3&4²j2)9ø¼ TAR\¿ö8,A©ôT[÷úaÔªF¾Z‘r%ÇeŒ1ÆcŒ1+â¸Ìú8.ܯ}ýKüÐø< øÈGN_kªòèã€Ö7Œ’6+Ì*Š¥ª{ïýïÿßþ|X€¾c…Wt?•’ø 8Œ"Uy° ’z^æ¿ûÿíõk·"22ï»ûÈ•ûNžö©$°;·n>óÐWÔÊÕ‡L ÉàXßubô¤ú"µb"=¢÷ 6‰=i}ÉöÀrYHдìlñÆk/ÅŠèÚä \2—90 ;¦L³epO਑Ýoƒ Yš2 ¹žAªßÏÝ&‰jŒà]Kì>ÃG"“¥)ߘ­á¸Ìú8.“Š.+ÞýS'à$öÞÆ_JEâïˤkõ8yßÝg‚ú¿ê"±~”Ç,Àq™CÂ/^¹ï$å›-“žª«>¸7‹ò1½rÇ‹{‹<[JèÀÝâácžèÂ…ØLò-Øï¿¦Ï­›Ï¼uÏ 3'ÉÌ7Æ3EwSõª×±ú¡1ÛÁq™õq\&]Vô Ì£?’Š"úJ×½÷¿?•8.“Ðþ¤¿6õ›îþp\æ`hÍ:ù—Ù¸5qÔp³Â´%ØB¤§öZ÷+=~ع*.±TTåÓß £‘©èòA¿á5å_ 0LßíÇe8/´·Íaˆw-‚[b’!xŒOaã¦ÚúpE”é\õ(e»šã¸Ìú8.“Š.+÷Þÿ~v¹ó¼Ì¾Ìï:!Uú7á¸L‚o´H€‹v³¾@O}_—9\;úñ‡‹…â2ý?Ÿ„*îZ‡µéÄe' n¡”GÚþVG:;´‹‚v’¬;¯¼@o{Çk&éÜÐVq¸§Q,%\мdªW½®&tg6Žã2ëã¸L*º¬Ä?Éþà‡>PþzôLÍÈ—˜€ã2‰‡Â ã=…]pŠL. ‘ KÍ*8.s´oïeŒë†Y÷¤û\g_ªmnV´èÆ…ÔôÎ6F:'LŒ_§¢Ë}»VOájŒWëƒý=9^ãq>5§[ Ú W——Õ¹øíÜyåtìã§ýÙÓ ïIíd\æÍ×oëÆˆºÄÌòKbHù€ÕñºîÍߘÕq\f}—IE›å‰Ï> k—Á‡_vaB>reÎrOóáŸØt‹Uâ2ׯ=Ž·ŸelmOˆ7QXuæÇÓ·U ÷éX„œTw¯°õØÎÝq\æhž_¸é±à^Ôã;Òö¤Ú¨¶—ÑVCœšVÜE1_´¶1š0³6N·n>…­]Íe‚Îiyuß_› ¦ëн Y~(r^~;$º<[×þØÓ ïImë†&pC£¦Í›¯ßV>îxº"Z7= ”6k–žã03ˆã2ëã¸L*Ú,ú"Ò‚¤ß”ÁA Á¤„¢~èw~ø²í³J\Fol Òß·ð~Œ5W Õ„¢›ÍYÛóÓê }ã¸Ì¸z÷a/Á‚é{R«ýgkìxïÂkµ]YU­ŽL–¦º è@'n1ßù<å/@ã‹‘JE{eÁt]±×ƒtŒÇ—vÿèzƒ|íë_âã-s¹÷þ÷§o-}ã[7ØýÈà32‘Uâ2xÇÂ;ЮÜw²åRùaoäúÀ_‰ï ì‹’÷ÙIÕÆq\æ`bàîtá¦Ç>7Æw¤#ìI­öŸÕ±ÓGµ­Ïx%óR€N–F›µ?ño%´XqW©ñ­ÐþX0]Wìõ l±jäyùíèò<Çûöž}Oj«74¡ç[w6 T¿ÇK&ÙÌ,2á9As p\f}Ž6.cvg•¸Œ1+â¸ÌЬ\ßc…ŠLý~V™X¡VŸ•€@ ¢îä#·n>Ã_WÂß^0ºâæ+c5pœ>öDs€[$0§jú…LÜQHf©%Q3:NÐþÚR@]–Ê« YÒv‚@'«Çm 7'ЬœAÐ (lý,ìr ÙÒŒq§@Ú½ùúmæ+'Î^TG3ÉÃf9¹ãR@{X‹à´¼LÐäc¶œŽÀ[Úh-‰_²P‚"©…m­q¨‚&TEnÇ1Û­î`#r¯zÍSÒòat5ñv [LFÎõÚèÏ=*ÑDÂ1kAƒdôhJ£ƒ¬+Òl$ƒ#ÈK ÊÙGH-HÂˈs@mœ¢s}pÎ/˜K³æ<$OVŸÕj´4Œ@3«£¡TÉêe&Ú™ÆlÇeÖÇq³ÇeÌÖp\æ`'ƒå#÷åVËJ.C±äűRZkbÑLá”°N­nZHÒÉKPÄ5tZæ.Fû´”d¶:gYµÍ€—`!rÎÊ~<¡G’ãj%_ÕŒÌê~£—‘ªrd…dʽJuƒ¾ƒÖÖ¥â\Š@yk挴"”š‰z‘\¤Š8@CUÒhFZSW?Š×T…%S‚p_*i%Ì“( 0“«UÐb¾RV¡¼ìlÕè2%« ¥IÝlu­cjØ*iŒÆýVí>ò«–PžI.bŠò>*•žA\ËgԹةŽ)lSès|ÐgÍùqµdîœÇÀQ ,Å€ªðšŠ„<_•a7cï*{ˆ1[Ãq™õq\Æ,Æq³5—9_¸ÖäâHXwrýÊÍ Á⛥HF@J"UצqŽZD§Œ¤TWÀsÑrÚ –æ±-¼RæÖÍgÔ5&ž’¸%‘ÌژЄ„ÇÕv™2Ò½T†f°Á`$S€á5åGdyùq4t²¨ºÉ™ ‘ÃS>’º¬™3Ò®Á­)@"‰=JE`R-Œ¡ª'™è“˜´(;2ò 0a¥†Î6f4ÍÅLÌ(6Q>‚ÖËq‰<4 õ"uPeXlNµæN]¦ÒíÈÁ¦7iØU² JSÑdï€L…LúžŽÜ›4kn aŸó¡„ùLãCO…e¯…f8RîØnGÃ8“~ƒ‚çÓƒeI9'ÕG¾j(ã4`u”&×i”Ë °`Akbï‚ µ©Ó>v“È)_ hjwôX9«uQ·& ¡aHG›ÿôIDAT¥{Ê7æá¸Ìú8.c㸌ÙýüGONN¾ýܳ)ß®5™Ê] éo´K«di.ÕÆ­ÑîË\íÐâþ³ƒš.WÞ$mä"º“já ”{ ''w©w¥óUÔ÷¡6H¥5Ú²yÜÒÀ1“nÙe”ÕͤY¨©ƒªˆTîBF$•j(çNÝÎÌ¡sÊ*“½ª›6¨D½ˆhЫW)ÒøÐ·º dI9ÓHDZsñ[k8tË*ë²H8¨z¦׬žî„ÊÇëø‚ÖÄÞé,C0UdyÊ æ<˜T+e+ÇNEåèDØ.R©³·c³1ÛÇq™õq\Æ,Æq³5^ûöÍ_òŸüù^Mùæ0h§TÝf-‘S¾(°Xï×Âzº/0ŽvJZD]ß‘ŠÎº¿¯ViÙê´1¿Ü›©¨ßqÙ\jètgÕj5¸,™ìf«ƒ“µ?“pOS6T«L©Ïù[aÇëwˆÝ§…Hiã*$0>ôý^k·€LmuvœI¿õa_ʺrK+r¤vË« T]´lAkbï‚ÚŒbW{4Hk΃¾ÚÝ=VÎêAgÒf¤RC§;Æ\—YÇeÌb—1ÆD´Ö¬~, & @JôÙ©Ö'©v•e.U!u¢K¢³òž¤³îï«•C:»‚ªC ­UQE¡ I§;  ýÉí PZ}Ph’Én¶:Øq(}¾§©ËéQV™ìžmi‘4hòO†–íAj©-éëÔ@w®ÁÙô[šQÖmå µ[TÕÞ-AҚػ ð†,•–T{4çXµn_íî++:³s]tºcÌEÁq™õq\Æ,ÆqcLdr­©0d \…‹l$­eGÁ¬µÊ2÷ùð³ÄPxõá!*Á”,WÞ%Áî½ zú£µj¯9¤ãF ÄŠÐÆüÒ“*êûP›œRƒ¬ªÚ<˜UèHÊW×àÀÅ÷ôQ7KÍD½Hì¸NÐf$y ¥-ÂZ·cúA!4ˆV•ÉÞÉ{8h!V™Ô TKŸ¤ßkô‘ qŠ"}%ãŒôQÜyå…[§?5%hFY·•/×H Ç¯RDO®ÆA ÄŠ°“ù8ˆù;‚Û#Õ"¡Å~tf|¼Æç<è«i!X2¿œÕ*JU4 ©ÔÀF[6s!p\f}—1‹q\Æ™\kjÿ3’ô¥ -‚q U‰þÒ|.ØíkI„cìŽdODkúrå-Pգ”Z«öjC&Srˆü_zR[ľeX‘UWŒCw¡¹”Ïb‚dgb$äªf ^$׉rÔZÚ"ìiÕíÏŸþm0ÊTV™ì,œL LêeÇ'éôHaÇo@žo·ÊHŒiRY—Â}êi¼ â¥ Mù“)tF¦â2®þø_&áø¡®T™¤^S~dîœ}µ»{¬œ]zž ÊSQD†•‘}ZÕ²Ù˜ ã2ë㸌YŒã2ƘÈäZSûÈ`ÕÛ!îFpÊZ8PfB+à”¿ hŽj™p\#´èoí QEJpylcØGÅʺ}µr4PU‹ôeùE1ŸÐN¼¦üHÇ0èl-€Æ ¹”OÐ/ô]ŽEjI&ä–¼z‘\Ôw)ÓÒi¹]&!¡Ê¡„´ªLöNj¶ÐNrR'(;>I« D aI*ŠP R5f:ά>¢QÇKf”u[ùÜNµ¾• IÔ¯)(eÑøä°"bþ* -LW™„ãr2P¯)_,˜ó ¯vw•™0 c­jÙlÌ…Àq™õq\Æ,ÆqcLdr­9¸œMh}ŒƒT$:+à¹uó­ì¡?­ÝUT®Ý„iRù„gÝßW;â*òµ¢L­6JäçäÐéÎØPžÀ4*³Ë/ƒ”È-Í-ßö]GdÉîzi»Žü\œ© ˜ì]^U™Ô ¨­öZ` M…¿¾’q&û¨xÊ™O3ʺ­üˆºð–ö'$a°ÀÕdd*îN C·‚×”O–ÍyÐW»»ÇÊŠ#Oöe:Ý1æ¢à¸Ìú8.c㸌1&2¹Öü²LBëõòÓc…sÕÎB³´«é/úµ²¯n±:ëþ¾Z=E?‰ˆ@+V÷fj´õ#ýáëtgP˜”òKÐܬÑïkV/’‹ú®ŠÁE34u;©¯±¨þóKS #[Íá ¢ KE-ªýJÈÚñ¡ïëÔ(t.ùe7“*“~“µ¯ç”u[ù‚2Õ¢;8EÇF§Œþ#HäÒÖ^‹ø%¬4äÆ˜)TkÖœ}µ»{¬:«Ù(.‘þ]ºÓc. ŽË¬ã2f1ŽË,oðÕ÷xd¶ÖaÆ\FÖšZCOøÉ ˜v¿û[æâ eiW£ö«×µVöÕFgÝßW»xGÚêÑF¢µ–UsÃL à<ÁŒJùUfmr¨¹%LUHÉEr]Ë$y/ ,žºýuJ‘‰¢I#gEô¨©|ŠÀ3ú~Gfx6Î¥ï·e¥ýZ ï„*ËF`ìX±zí¯KëVÐïïâÒ~ÅÅëßÐîiù“V!U¯š¾ÍÆ\—YÇeÌb—™‹Þæ±Pˆù|ƒÇ;´C3æB3²ÖÔnjÖ*YkÜr¬-ÒîËÜêçá@­$tQWWçÒþn¶¯È!éfÒ ±VU­žŒ@*÷2¯Õ;•l®ncæÂ¶Ð͘ÙúhZ†¥ü*F*??ÇœdRr‘\‡”¬˜6-µË¦®j•ÎT­jiFµˆH`|˜ä–2`§YÁ4®³ÓA"jØEíâu•÷MiKù¤S*申‚µÊ|¡º8@H’)‘1#ÂÂl«cÏ\Z×£ú•,ìz§´?çûjÁ2õohѤò]C¥-oÓæjw:À$T\%iÌî8.³>ŽË˜Å8.3-R¾Þ±šIEf/ÿî_þÅÿÙ¿œòÍaYkÆ,&|ÚSá—ô¤pƒ®¤X¤¥3ÓÜen BIÚBcû!›SÀ"®¿Ù¼êé•¢z\ÜC@ ‘:ûªZ O¿‘’µ³#iㄆZUˆ6T¨ ” ní  “³6?-غŸ2¯Üw’†@‘¾Öc> Ù mr)tjö²4¹H®c‚°êbhX—ùªB&§.[īЀ ã®OµR"ûÕºÆ)Db»qˆ º‰¦S/P]j㛪3_¥ãC¯J!æjY¸—H‰]P»HkíQ¥°ê7oì>ÆE½@*‡ž:Ë|o,JÈП.a°`¯òsY}h$%ºWà5æ¹KnŒƒ®Rèœ5çûjÁ2©VkV£ p›Ãb>’î Ö­v§Ì N¤ΘUp\f}—1‹q\fx=}?ý±…h­cÌ,>ñȇONN^üê—S¾9 ƒkM-Ü) Pð˜ùX§ZTÎDI ãšâ1^S­¹Ä<­¢aÌì\¼H8*•ÙÈLÚTT]÷KŒ IP< ETõ#%ÍZÙ—î² Iížw7™“Û˜Y°ÑÔœ,ÁAê,Êl ÕBÂqT¢=Ur‘\§É†Äºñ´Ú÷ŽK¡~CN¬C!8H¥ÂT…h À*©/É*úKÍi²ž¢"6¥<zUA’6¨Š2p(Dª^Ëèû-‰h†,‘p2´ò#1Š×2!¿Ü„CçYq°H R ¯Þ A€Â»\­2C6ȤÒìþ /žó#s‰Õ™¤H©YS¢å"ä«:ŽÉÙyw~Òž²ÑhŽj‘Òm̹à¸Ìú8.cã¸Ì,´,¨n´êõÛí.8.s¾Œ¯5qÄMBL¨ÞZÎÆ}„ù$Wó–¹-`µÅ„œÖ'óØ~$yø! ”=…<öÿZgW×ý“jú®KJ¨[ÞLÔbÿ>?§¦‘Ó6ar3 º\ú„ b³…pé7 Ó›¯ßn¹(æC¬Ó¾ Õ©ËG3è7œFyP59Ø…¶ªÒ6TI2ÐPõ$2ѯ©DY§œrNÇ%¨›– .jÙ {’ðŽôýV{¨òÆÝ§¥ð*aBù2_À]’œ 4'{ ƒÒTwÁâ®KS• œdf;“B&¨…ýI˜ô½ª9“s~d.Íõ[D‚U©H´ÞÈ ³åÂn¶ºSmQ9RyEsx—YÇeÌb—á®”o±kÍl¢ºŽY ¼‰ž¾™6—hzÇõ>mŽËœ/˜ÆÜT¤üǾ Ë_1YU$¾\p¯uù`åÕ†ZH¾*Ü2{Ò]}µ¤À¥h.ÉHò>±T”€âÐtZ£òÉAž©v$õ·ÕÙI¸Ù+•°i*“½ƒ0sbõ‘mRk0T¶HZ­tª€ØVÇ?Q9€Uåþ?g¢pßžQaLJÐL™IÉ™ô›®Ç(€^ÀÂRž>éøëÌ(ܵâ×v" çÁK©ˆÌA *iƒjÁäèLzìT ?ušœKQ9èx ¥t~§QDÖ…†>å÷aCeÌ!q\f}—1‹9@\ï@o½+v?qÚ¾;"¡­T´"Z]uZáÆÉoº‹q\æhY7.sYÁƒ7™}Üît»žÜÆ\Döê:s„hFu>vÒ5åYwxözC[—1fS8.³>ŽË˜Å8.3ÎHÌ‹3ÊtVi¦ã2G‹ã2#8.³Çe̺ŒÄeô‰ÎÈ#f]özCs\Æ\—YÆeþò_þËØÌ2½ãï@»ŽË\h—D˯þ{0^#b¦ƒã2G‹ã2#Ä­ ŽÁîOçAU)²Œã$s @§Ø;ÇeÌ*àÂáŒÂ]«v¹~÷'¨÷·þ1´þ¼ñô5ÞâvÿÚõÇeÌ%Àq™õùâ—þâŸþ»ÿÛÉž#á;·ŸûÆ·n¤Ì¯}ýK>þ(‹+¾úƒS~ PUfFÍxâ³ÂžR’ì—ÁЄ߯+Þ¢R©X—6}ÇÇ“ï£ â2Щ¯(ã`² ˆ±‰+S㪽åîoÿljã2G‹®ž^½û»QãL^ž—ÜOoE‘vßÐó1uné¹nü˜>ñ× q Â)׸é²ÂÁ¾/(4ï„#ÀÔ¤äò¡•›:ždf¡HœÒî·_cÎÇeöÂ×¾þ¥e|ìçÿÑ{ÞóžÿáSþ8ôúÿ+s |ã[7xG~ôñG˜ó‘þÜ;~|i‹S• UDi+VòÁ}€2÷ÞÿþT$ÔV ß@9Ò,=LO|öQIŠeqþ”ï™Þ» oNq±{ýô/șĩŒ(wP·n>—2J.?¦p”穨.¾«­à™ÕÏ»ˆú[Õ‘$<ŠÌŽË-¼*ñÊÓò&3’.e@!¡[Ùq§ !*„þ$p9p\Æìƒ«Å )ñj*W/«Ó2 “P%)¹|¼qúO[è©À`%™Y@aÔ¶»BcÎÇe¶Å¾øl~åS•»éã28~ï=ïæi™>ø¡¤º ©T%@8HEä;·Ÿ« È ˜”‚2He,ˆË¤ÏøÎtv6EI¬Li/µËYA#¡•´¸™Ü¶•‹ï¾ñH7Y"±É]Ÿ:r FíÇeŽ–ë×ÇE­e®Ÿ—1ëòæë·q[Æ$é„àY&˜`¼á7´ƒ=6‹Y­Ûà ^¢c—ÙŽË,Cq™~è £Ü{ÿûŸúâ§¿öõ/¥ggë*bòÞ{Þó‰b.Lñqñèã°4iP\†Î Á ƒS¬ò¼L|†ËJn<}ñ­wQ 8Å»N`éq>ðŠµ‚¾ pÊêHiÓõü³OQ•‚&~ßPK1$¨U„b2©ü³mõ ã ëžTdFp\ÆcŒ1Ƙ½â¸Ì¶p\fŠË0½ãoÿÚ׿”šIÑH21Ÿ<ñÙGYÊô‘þ\Š¿¤P‹ò™ÊGuJæÆe®ÞýUÈê'-ÕgIãïj?zýî/ç!¥Gf4³m¥"Á§O)Vý†‘@¥·æüš¯¢?#¦ÄqcŒ1ÆcöŠã2ÛÂq™eĸÌ;ÞùöêS-O}ñ­ÿgJQ…lÒ£4@º0¥˜au¼¦Žq™jÅ’¹qE@ʇJZ¬òüˆB*ÕïÄevIÝDÔJ 0© #¡Ô6%ŽËcŒ1ƳW—ÙŽË,Cq™VP†(þ’{Qð¥õë3ï½çÝ­à‹Â=eäEq™²V‹Åq™Ö³-%«Äeú‘—‘¸Œb.éËM}›)é™ÕÅeª™>ŽËcŒ1ƳW—ÙŽË,#ÆeRQD’CQl%U—ÚGD?C“¾¬¤üò+Nj®úí§*sã2ñ+EÕo•l!. &Edjz¦¦ó§µ…ä¸Ì—1ÆcŒ1f¯8.³-—YÆ`\æ#ý9Š¥¸Ì«?xYÿ-[?è ýŠÝÜûãÿ–]­H—©þõR•¹q  Ž«_,Š,‹Ë|ïîïþ’~ä¥_ âÄ@¦…ž—I¦Jÿ`ôl,OEfÇeŒ1ÆcŒÙ+ŽËl‹çï·°úüSO¤|Óg0.£8K)V}¶…™f&ÖmýC69L\&FI˜Þuú'J­?*zrN\æúéå*®Q&hKU€ì©–Ù0˜’©Ò?Òà¸Ì.|îWÃMéµoßLùÆcŒ1ƘUp\fsüÁ}+å˜IvËè—â£4 ÄèÅYô³Áz§ú_K‡‰Ë'ÿS3á´úͦÁ¸L5Ü#βֈË@x’ôЬï1¡#Fr\f?zõ›)ÇcŒ1ƳŽË˜ËÀܸL ¾øä £WÿŸ­”Qu=SSFj"‡ŒË[7ŸÑw˜ÊÐÌH\&þ‰5Ä $ý62Yº,.…@+©h„‘.ÇeŒ1ÆcŒ1[ÆqsŒË(PRÆeŸŽAâ¿eë}õÃ1é[KúUšV£‡Ë[7ŸQd¤ |Œ5&HéG^ú¥@±’ã2#ÕwlËcŒ1ÆcöŠã2æ20—Qä¥úIúR¿¸T¹(óÕ¼¨_®~‰ œW\Ä^ÒC"#qÕ­~ ì—é˜7§¯±îH¨e–°1ÆcŒ1ÆÇeÌe@q¤V”ä7~ûóg¯ÅàŽž…IÚôÍŸ}ôÞûßÏc>_SrŽq°J\æÖÍgRÙ1.ÔÄC\IE“è¤ô«’‘þcŒ1ÆcÌyḌ¹ ĸ R54£(Iz&ÂX ’â/)æÿ-›ÂmˆË<ÿìS)‡¼ùúm>Räbä·]T÷êæ" 'Pª‘—Öÿ[G.A[ ™‘…­È‘18HEÆcŒ1Æsî8.c.).ƒtïýï×ïÂ|íë_RˆI¿ã[¢p Ó;îþpD±&ý[Sɾã2w^yÊßWü]ѯ½¤'VÊÈk1éYT‰Jôû2ïzçÛSàCELÕ¸ŒB?HR =I•ŒD+Õ/L¡î•ûNPšòêvÉ!Šà´¾“eŒ1ÆcŒ1çˆã2æ2¿‚c+8Ma”ê£4BÃ0½·öóÀ1ăԉò&.Ãô®w¾ý}wÿUZ‘¤êã$ j A˜ Sñ÷_JÍW~Õ°HªNý8HÂß{ñ+I,6¤"ÄZdò—‰…ôL~ãÉcŒ1Æcã2›ãΟ¼’rÌ$1.ƒSý‚oJÕŸûMÄ8NUþ‰Ï>zVÜx Fì;.®>ü â)!¿õ-§aJÔ­j¦ZýÂKëq•ø]'¥RøÎ+/¤?öN ÍU›¸uó ¤¢È ˜éógürÊ1ÆcŒ1Ƭ…ã2Ûâùßû­“““Ï?õDÊ7}R\|íë_úà‡>ðÞ{ÞM>òÑŸÓךúüÆoþÑÇ!­˜‹:Ë©lÌË€7^{éúµÇõ¤ ¸rßIúfS j]}øAUyè+ÕÇI’f}èÍ×o?ùÉÎC(·n>µª[ý©Éh òêÃ>Ba£ÎÏÓ豤"3ȯ?ùOpSzý»ßHùÆcŒ1ƘUp\f[|ዟÁèW>ÕÛí›’2.sAY—9Zô M'â£ØM?Äc:|â‘ã¦ôâW¿œò1ÆcŒ1«à¸Ì¶p\fŽË!“ßQÒïïøKL»à¸Œ1ÆcŒ1{Åq™má¸Ì2—9Nô8LõëTWïþ8qç3‰ã2ÆcŒ1ÆìÇe¶…ã2Ëp\æ8yò“ã¸W>†Q¼¾ñÚK©èÒðÅ_ûî¿ü‹ßßï¿8.cŒ1ÆcÌ^q\f[8.³Œ —¹÷þ÷ÃàÈOþä;ÿÊiz×O¾ó]wÿÁºÊ%Ž5Ì®`ð%åë¡.÷/þ~û¹gqÇ`ÚStÆqcŒ1ÆcöŠã2ÛÂq™e\и ¬¥Ù RçOˆŽ =2£ÿŠ"üUàc`ýé÷o}îW;̼•VÎ8.cŒ1ÆcÌ^q\f[8.³˜‘?®Þ0XÿäMþú߸ç§NÓßüë-ýotÄÿúùÞ‹_)£To¼ö2ç©¢?ýþ­'~éN#3o¥_þÅÿèÕo&™e8.cŒ1ÆcÌ^q\f[8.säø÷eÌ.¼þÝoüò/~ü42óVúܯ>ö§ß¿•dæâ¸Œ1ÆcŒ1{Åq™má¸Ì‘㸌Ùu£3ŽËcŒ1ƳW—ÙŽË9ŽË˜µX+:㸌1ÆcŒ1{Åq™má¸Ì‘㸌Y—׿û V˜~ýÉògür’é㸌1ÆcŒ1{Åq™má¸Ì‘㸌Ù¯}û¦¢3÷þí¿õÅ_ûÔxtÆqcŒ1ÆcöŠã2ÛÂq™#Çq³?–Eg—1ÆcŒ1f¯8.³-—9r—1ûfntÆqcŒ1ÆcöŠã2ÛâŸÿˆ-ã2G‹ã2æ0¼ü»7>üÿþipæägþÎOÿ«ëŸ{ó?|7ÉÇeŒ1ÆcŒÙ+ŽËl‹?ø£o}ôÿ£çï·R¾9—1‡d$:óíçž}ìç?:÷ׂ1ÆcŒ1ƒ8.c̆p\ÆžñggŒ1ÆcŒ1«ã¸Ì¶xå÷÷Ê•pƒ47¡âGÿñ?:$Wýؾø™CòÏÿå?ûÖ­ÿùÀ¤1Ú+ŽË˜óâåß½ñþÛòfÂèÌŸÿèÕ$cŒ1ÆcŒYÇe¶Å7¾ùo¸/r:æô±}ìÿþñü‰G>|0¾økŸÂ>ü|û¹g_ûöÍCò§ß¿•n¦äů~ù¿÷³œ‡?{å¿ó›_ptÆcŒ1Ƙ½â¸Ìæøƒ?úVz^c¾ñÍ“ž=9 é›Ãð·ÿößâÆÒÉéÓÏ^ù@Ší›_þŧøùïÿécÿÍÏÜû_ßÿ_ òSãžÿí_y×;NÓ»Þõ“ÿÕÿñoüê/|dÏþŸNï:ÆcŒ1Ƙˆã2ƬíWžK±°|÷ÿ}ëNÓ÷ÿÝwÒãU~ç7¿và›ÿ8?»ôû}NHé/ý¥·_ú_þÍÿ”ÞxŒ1ÆcŒ1Âqc6„_fSüèÕo¦@Øxñ«_N°Ýùß½ëo{ÛÛþê_ý«gqšC¥Ÿø‰Ÿ@»~dÆcŒ1ƘŽË³!—1ûàÿô×ÿo{ÛÛnܸÁÙu°trr⸌1ÆcŒ1}—1fC8.cöã2ÆcŒ1ÆlÇe¶Åÿã¿ûçÿòŸýÁ}+å›#Áq³—1ÆcŒ1f³8.³-~ë__ÇNæ‰ÏüRÊ7G‚ã2f8.cŒ1ÆcÌfq\f[|ዟÁNæW>õhÊ7G‚ã2f8.cŒ1ÆcÌfq\f[8.sä8.cöã2ÆcŒ1ÆlÇe¶…ã2GŽã2f8.cŒ1ÆcÌfq\f[8.sä8.cöÁ{þ÷ÕqcŒ1Æc¶‰ã2ÛÂq™#Çq³./~õËþ‡ÿ'~â'—1ÆcŒ1f›8.³-—9r—1kñâW¿üÀßûYÜOþ×ÿù1ÆcŒ1ÛÄq™má¸Ì‘㸌Ù‘¹÷oÿ­/þÚ§Þ÷Þ÷8.cŒ1ÆcÌ6q\f[8.sä8.cv¡ŒÈüÙ¿Œ|ÿî¯1ÆcŒ1›Åq™má¸Ì‘㸌YÀŸÿèÕßùÍ/("ó3ç§ÿÕõÏ1"C—1ÆcŒ1f³8.³-—9r—1³`Dæg¯|à4 s‘yó?|7‰9.cŒ1Æ\Þxí¥'?ù±O_‹™·n>ƒL¼ÆLcÌÅÂq™má¸Ì‘㸌™Åc?ÿÑÓ€L3"C—1¦69ïzçÛßwÏ{Rþ \¹ï$åcÌîà6…7Öt³zè+ÈÄ'f&xko¼öR*2— ¼q¬Sþ!yþÙ§hÃõk§"ÓÂq™má¸Ì‘㸌™Å/ÿâÇû⸌1°KÁÚñ­käÇ?‚^U­â1Ƙȭ›ÏàöRÞ¬”ßÙóÖ„ô½¿’ŠÁ­uÁW^HEU(œH2%lÀ¸ß‚ÕÚŸæ}›1Ðñ”HžüäÇ8ßpŠL Çe¶…ã2GŽã2f8.cL‡+÷½5Q±MùËp\Ƴ'x³ªî·¹ïÜyvËHÒd¨‚ð” J@k¯Û(6~ •U«?¥¸?Íû†“ö§üCâ¸Ì—ÙŽË9ŽË˜}ฌ1-®_{ütéØûœy\ʯ—UXÔ>ÿìS)ÿ¢°?û¡Œ¨~á@×ØÇ”oÖÓî]ëÂû›óz²ï¡®¤"€vOïdõˆ‰ê.ޫ둦ª †: –”¢]â2“&Íeš÷ã2Çe¶ÅoýëëØÉ<ñ™_JùæHp\ÆìÇeŒiÁ•÷ŠëW*\%.³`‹²)ögÿ1¬ø¹³B*÷®fV¿öÁ^¯YMû~ä¥D¸úðƒ¬»8µÔÀ4é7MàO_ƒ[,‡Ú‰„˜k-pàóÏ>u徨]=J»?Íû†Î_wnÏÅq™8.³-~øÿÝW¾ö/þðßßJùæHp\ÆìÇeŒ©¢O˜±iIE‹á–c•]Ù^÷x`ö;.cv‡—êº{×½^³œƒ;ìì.ßÇ‘€¤þru&0r¨ )E‘öêÀãarªÇeฌ1Âq³—1¦Šv+.¹ßXeSqÑ·(û³ßq³;¼T×Ý»îoÎëq˜NlEŤjx½ zz8eœO_£fè¸åéO`)Iþ¿è7½@ç¯;·çr wéÕq\ÆüÿÙû×_K¯ë¼äŸàoíÓÝÂ1aº‘Ò°€HAŽ:ˆËIT„Õ:Ð¥˜±Ó&iÂVT¦TrLó˜,Z‘"§È¢u£]‘Ë&h™tŠ‚¢PPX(I-BÕ¶¡T† Ý_„F×'ýé§ö³ëÉИ—÷]ïºÔÜ{=?,¼k^Æó²Þ=dz.Û „u³ ¬ËSE‘Cyp¼vù%D1ŒÁST#µ3vêѨ-èù ]` OEª¼ô‚.èÆ¹3§c Âaìü ¶ªNÅöüçº(þÄEßr#Àuk\ QÃêQSf³­H•jÆV©”Ђ6'ÜÙÎÆ› '0NžÊ¥ª}6)_ôK¹b…ׯàiì‹; (Ræ:ÄE/}£?|©â‘OIÕäËZÕ X¶çQ$³ý͉ɡeÔLE;Šuðºˆù),ÄÌ•àgdçkêT¡D¸5|IpÍL4Wæ$hÕêô7CŸ–å”…ãÕ×õä‹”¯”Jã@p*D8ù­ê{‚¢ØKgO ŒNM4|\s)q¡š¦ucºŒÙÖeŒ©‚è'WPþH'ϵŒ pNUŒ¡„@¥Â1Ø(ƒ œnã+Ä„Êé”\vSÿD>“–3JåpøÖWbBfŒ±Á–üÇv|FQ !Ð Ü(ë#'E­KÀ \‹84‰5±[úD*Ljà¤êL ZÐð°¬–’'  çxÄõÌ­:Õ€SzAúBŠà¨£ç ؘX ½«Ú2ªóŒ!h‹ÂÏÃÜZŠ£Øêk¶º‹ÐWkåvê7¢,+]#s‰•YÁÅ/½×²F×rX+àš™q}¸ÊŽ&7CŸ–e9É|þaºHMT¡¥ÆÎjÆûà·rZ»E¦R>¼’R§[uO¸ªÍ ÄÖìá"µ2-¬Ë3ÖeÌ6°.c̪ðxŠGF5¸Æ#Á5JS+À e‘Ò*€˜C1¿š:±ÐLd¿ôD ™±‰æ©l…‹‡ ˆùÕ´ØŇՄ"Å3 Jo‘ÊHC±§ä?ªœ?Ì=˜"rø<¤4FÕ‘3@þDg¢ý2¡•j.ƒžàQ ŠGrÐÃÍ”zÑdVõ,D‚…T°«Yul¨£D¦5ifaа ‡8ª)®…|Ã… ÆÌůÙèCi×±2a)S~bfµ•ÐÐ(ðaNÕU¢ I …Ðxc½ ;–-õdÎfèÓ²,'ã½–5"$\GyEΔw¢WJ8ºYvA˜ƒ„úIÇô Õbf¼–n,ؓ醌k=Å… Μm¬Ë3ÖeÌ6°.c̪è\{ó\ypŠ1ÌW¢ò‹|€j‘ÞV„‰áÄ…°À"®*Àdâ1Æœ†àd²2ù”¨ ‡ð6N;®µ4q–æðŸE¨Ó2{ñüYÖñ¸‹à³^ƒÑ2‘·)?!ßR§ë@›©kù''Ò÷gi2‹ÊÌGó˜ßA{,v¯è!ìô7C‡ªe '5 Ú·º E-RþàQ™Ý%¢oj…·ãT£G•sU]2­H¹»–íI}R&¶Â…:bÂ4ª‰éc]Ƙ°.c¶ucV%ž,ËC¼¢¯tð<+—åVÀÙ9¯/QæÐê´œ×ѼϨ4qKþÅK­ÿµË/Åè"Ò‹¼EÂ<¤HŒhÝË~U”&Aë[øÙ*EνMØ@f‘æol:‰””—8iHå´°;4!¥–©:-ËÀph3-A *4Ò²³ækVsR]ÙêŒÍ1KØ©µÿWEª\T€^G­× <©S!}2;¤BÛ)v´êf¨Rµ ä$üŒ+0ó,JÛ£¿4ÚQÑš&Êpƒ­Ò0ÙWt@½WM©~)Qiô-³då9Rk‡˜ë2Æ „u³ ¬Ë³*:Åžjü íÖ˜ùh3ûèÔ›òuú_ÉÚ$åIŠ4ؤôÈÏõC¬™(^ZpâW8‘ÚÊ[¤V,׊Ӏš§°Goƒ·lrΑRl£ü²¯uÙ•6võÍ|å£ [• ]Í×4¢´Œè#³¥ÞT…¾á1åÏÓX¶ÜóÚ~ÕðTG1iV¨9.RÑ2´ôIMˆayÌœ"¤´ãG0Ê 0¤BCŽ­ºªT-9 ÿã‡qDuì’ŠÊ¥¯Š_¸ Ã>2[½­Nº÷Ò-&¼ºë–íIu eF4 ›ÚŠû€ucºŒÙÖeŒY•t®-Ñ©4:y’žT€V_ B”9t<¤'H1XÒ©½uþU›[ò(NXpâ—W©­ò[Á P¿1Ü"jÞJd3ŽZ‹²¯u˜ô§º±5º´”´†!\ÀlTô.4>^¤!¯3—ÈI¸1gÒ¸i;SÑ¡5­‰šÞ´ÜBâËM¯Á–Y¡¹Ms¾˜Î,±©*®qŠpQ+¤R¬œœÀ 9.ºì »˜¿UË@Æ[“Ì—RlueíŠ8!zù¤[JD‚N²‰ÙSf_”Ëö$»@jMïÆ·â>`]f,.ý ïyÏ»Ÿûü§R¾Ù¬Ë˜m`]ƘU‰çÚ*zó3Å­Í&:@ ŸjÔÚWtXkTúß)Ú XwE¼He4ž†“ØÒkvÙ²NššÛÎ6ž‰vœTNï¶G*æl§ÉÍP¥eYN¶&¹ã’ÜÀô2§µU³¿”Õæœ|fÂÖAR§‘e+Uí7¢Ièûo"ÖeÆÂºÌžc]Ælë2ƬJ<×VQš<­¦ B2Aõ‡N[}éôŸ¬­ƒ”þ&Žþ0àaÕ7 ãuùÁ‡>ÛðŸôOüú¤FuùäUjÛÊ0R‚Ytjœ:€™IêàlW=é³î¬,MB³ZhcøÚHŠôÒd:Á2knvhU°.ô Æ"æ·¦bK¯Y-kkÃT™4+d¿¯„f Š%«¢ÝRN…Ž%V2R‰¨Ç|N¾2õUä”×J­´''gRþ·fÉ”X— ë2{Žu³ ¬Ë³*“GUJSæ§ B§äô®;Igh¡3w²¶< Ãl믖,ˆ”È6ü'ˆ9éRõÄ/‡«ñL+¦šŒµ‡Ó “J¸¸H+Å<€Rڭä?cµBœvm¤XAË­¥¯Îšß´²é¡µvº£‡i‚…Ò;f5vªWóé{+´¾ëÏíÌY ))AËçÜ¢Žœ¯N”JK¶A+ï¼*Á–^³šC<Î×FA߬˜YmíÛÉ…¦7ípMàJ«ŒÊl•¶V‡•¶ÓºŒnA˜äþz±©zˆ¿“^hœüdV+’ÖtÙžÔŸ’êJiŒH­Y2%ÖeÆÂºÌžc]Ælë2Æ¬ŠŽ°H8­Æ_]ÁQ[§áò F¥£*ƒX¤t ÆaZ¦p‹ˆJWDZ莄 o üÄiuR+ÁQ¹ê 21´²¡úÚ”ÿ¡2; õKS\Ô‰&c-   Ɖf¥Õa¢ˆMÒê Lo¹‘4ç1Ü-gxUä œŸ¿±‰š³fª¦`žÕP'–Š~ÔºLT¹ ñ”®â1éUW\Ûi{¯YmBÌRuA1åVÑÌ÷'MƒMù«¢î&_¹­žépB/C4OE-ªÛiÕÍP¥µQådë^ÑßáñÅ‹ÖËMvP»"ÁÍp¼E¡UÌ„3ê·—X´lOÊZ*’5¦Ö,™ë2ca]fϱ.c¶ucVEçZ}y tÅujXšŠÛ° ÎÐ8§~l‚ÇØ„è€{OGêUATÀ[ ¥)ò n Ð(d­ B¶á?©Ò²>Úç–®â×Ìa2e LÆZ$…eBשI\}ôŽ œ:¸D·‘‹ÔJ1$[±&HÕVvd0§}æà:µR‹˜Ê ]FÊ© ;+T£ÖÅhhša,–ü)C_©HHšù¼½×lü˜ëÐ8`eæ«>A)›à" ù RÑJDý"UÛì7S™+­²^†hžŠZhfbGìþÏÜ Uª–œl­E«¡'H¸îˆDšF$'Þ7ª¥á§|½~Q}[sO"±•*#¡/^£ZjhZX— ë2{Žu³ ¬Ë³*:×âÀZ ÅQ!5!<‰–¥u`UBϾ¼NM@ ΕJÑd%4œ›Ù;‘rÁT†Ü©BJ h#ÛðŸ\<6YÆÓÞpSB&¢6ÄULÆZ@ma£ÐÔ _þ”SɬúĆÕ9Á„Ö¸•P3ÕYº;«nl¢·ú‘ªÎÄa¶ÓÅ ­¨uèNKRK§(%Ö¬DWœ×ª,æìyÔÁ&9,+š—Âögõ…F´aZ3?Eï­yK¨~Ü<šÛ•VYÃìïÃHu;-Ø %­*'Q!æ‹VC_Ú“#­¾N™Z›“_ÝŸ²–JìIPÞ£P™Äã´fÉ”X— ë2{Žu³ ¬Ë³*é\‹¸gVd\tœA•”pðÅ)–F®©# Öe«X9kjUµ<ô‚q!µìèÔ^^à0,È€Ù€)}P¥ÊýÄù¬. rª«0Š$<ݸ~…«P R‚a¬¥|‚ŒðÈ•MÀÌ*ý!ð¿Ó@©šà¢_y°Cù«SÔ³âw „63HE²æ<­ ¦îiD3Üßœq“è%)â‹6òšÅ€è—»«è"ræ«Û¯\cŽ(ÖeÆÂºÌžc]Ælë2ƬÊñÖe:‘B>T@B˜Šöœ'¦¾›´mÖüÀÂö°.sté¿6çè†Æ˜‘±.3Öeöë2fX—1fUŽ·.ƒÇª¸pãúÉ>OH—i)Vˆ‡Yádû@n;ÖeŽ4åóÊsÔ±.3Öeöë2fX—1fUrôÛ +†§nýL#†vß='Ï9ý—Ÿ~ú™,Ýö‡eøs «r{?„¢ï‰ a{ÀŸK/<ËÙÃ57 ê¬ô ЄÌG*ÛøÑ»~c>ñ'-Ž7ÒþÒ‡b°å˜xÌ7Æ!¬ËŒ…u™=ǺŒÙÖeŒY•ÁÃW©+%~Fæ¾ö÷@ÂwÚ!–>ìo•„VÉÎŽ)ÿ TJXNòö€ýÃÎVIpŒÍÇ×eú3\M#gãpµ „/jÌð_ 3ÆLb]f,.ý o{Û[?÷'çR¾Ù¬Ë˜m`]ƘUá‡GRð3'þ+óª(f‹ÿ݃E¼>wæônâ:t$¯æ3Ègð³Eš:€käìæ›_X;õ;¸ÇæƒolÝžÉÈÃÙ8ú¬YÌ䇌ªÿ!ËsT°.cÌ@X—1ÛÀºŒ1ÆcŒ1Ãb]Ƙ°.c¶ucŒ1Æc†ÅºŒ1a]Ælë2ÆcŒ1Æ ‹ucºŒÙÖeŒ1ÆcŒë2Æ „u³ ¬ËcŒ1Æ3,ÖeŒë2fX—1ÆcŒ1fX¬Ë3ÖeÌ6°.cŒ1Æc̰X—1f ¬Ë˜m`]ÆcŒ1Ƙa±.3_ºôg×þîrÊ4{‚u³ ¬ËcŒ1Æ3,ÖeÆâÏÿó³ˆd>úñGS¾Ù¬Ë˜m`]ÆcŒ1Ƙa±.3O=ó$"™G{$å›=ÁºŒÙÖeŒ1ÆcŒë2ca]fϱ.c¶ucŒÙ¯_}å/?wíòK)ߘAÀþ$Ø«©h@ðR:*®³m¬ËŒ…u™=ǺŒÙÖeŒ1f#¼åÍoÄmí®;ßò¹í\xú v&ö'®Ï9êŒÆË*峇X— ë2{Žu³ ¬ËcÌF°.cÆäâù³Ø™LØŸÔ;žøðéÚhX—1FX— ë2{Žu³ ¬ËcÌF°.cÆ„;éÔ÷2çÂÓg.½ð¬*Œ‰uc„u™±°.³çX—1ÛÀºŒ1-à $8y÷‰”oF%Vììç'°Ð"Û”â¶vÛu™ÝÏÌîÙÍksrÅ—±%³(p ¥^»üwéÅógS‘°.cŒ°.3Öeöë2fX—1¦Å€ÁŒˆÖ°:Hßxù¹T´ Ð »ëD‰té¶o˜ÏÌma¯Í9+¾€-™í°ûçðć¦W¯Sq•‡rÛ˜Û…u™±°.³çX—1ÛÀºŒ1-vû™ÅìX}˜ÜÒ¥Û¾av<3·…¼6·$gì^%Q»ü„Î$ÖeŒY ë2ca]fϱ.c¶ucZì ö3‹Ù±ú0'œ¦K·}Ãìxfn ;xmnI@Ù’Ùêq¨úµ.cÌJX— ë2{Žu³ ¬Ë“¸vù%„ @±Ÿ’êe¾~õ•sgNóg#È©î…Tm>è…¿ AÐoç·BVíQôuß='Õ0u„§òÕZ¿ `S?VxÊV óyéLë7&´q8Ìáê Á=æ€VGž>£1ÔìÌg¾¡>zawi?ܸ~E5a™ø4NV>¨f‹´î¸nMxº4sfà^¹mZÝa˜´Ã§h«ù,-§QȲÎi?pŒi-æÏjvúš¿â„^ÉZi¬jÀŠd>ÏÙESæêk­îªs•®¿iQv´šxʽ„ǪqA¯P­ô Äš\eØäS˜Õªá¢ß A_ôŠŽµö^z»àÎ&ÊíVåöœ–MN8Hù‚®V›¯´‘Ø‹n¹jˆ½¡:f÷X— ë2{Žu³ ¬Ë“PÀPM(MõqZeüP&T®†[}ª ‹ê±xAï¬Ó6®q@ge%”êÈŽ:¥q4ai§vá× ÊVÈ)ã¨ÉÏÀV ·Æ™SMèEm :¥o)¡æÌ0£KL1 bGô¡: ­aN­Wn¹*ógl¶ÆU]_­.@l-ƒÖ(bRÈGæ¯QßøÌ‰ªA_н[3ÃWMªž#ÁH }ç›%­—6zĤÊU:=¦­ƒóBøÚD)®Q•™’ñ–þ°R#ŽAÿi­¼S!U÷*©¾‘ZÃiÁi¡U›Èé(D­‹Våý‡ÆñXUm´@åVz…–¯‚U7+ó–«N™fn<³ ¬ËŒ…u™=ǺŒÙÖeŒIPŒˆY>%HF &F&Ê$jˆ”ZáܯÒäÌ]FÈf'Tà(R¬‚ùTó4u-&]²‰”&ÔzTĈNEšórZLÎ *€2ö““åújøœR4çþÄ£†£æihËVÕ²5b«ÒÏ>ØŠ4XÎ3z ˜³âpƒ*ÝÓª•CžcVÛu’®*¤:™UÔck i :Û) SN²¹Úb’ËP¿DÍ;[Ž!á:: ǯL‚j*ÂØSm–­Zh"¡ÕÌ;@‹P‡/¡EDŠÃ×+¨´¦A!U§'(Š}i’WÚHš">jÚÓ Äìë2ca]fϱ.c¶ucZè`šò+ Å€A(Eš¨à<­Ó9žàXí,î]ù8¬Ç|Nÿ)ª-›ŠOª­d¥qh¨ÉüÒÒ ÞÔcÙé´rif|;é*èO‚"ÉøQÐ÷Ñ穨ÅäÌTwiµÕð‘Z3À@4-1Ñ›ùiÛ,^£U焨»9æœïÌdËÃ9fÕ6ÅÒ„óŒ4ç®Ôcu’5'­‚ömª †Heæ£æU¯ç sUN…ö*öIÌ×ü¤|¢~£ÂÒA½À™ô¢Ú¢(›!æWQ²*Ä|9e½‚˜ÒÐÐ5¦M%k+m$¶BÂE9ds»°.3ŸüÌǬËì3ÖeÌ6°.cL jS>é¼ß(tðíÄBç9ëô®qU£J–"UãÙLçuE/éSB¢Ùɵ¼É`+rè/˜¬™tÈ¥jØß² ¸·F‚Öœ·˜œ™šðÔVÎcºZfÙou>e6mªÉ%hU˜lXE¯š$UÑ;+Þ¡5“fõ¡‰–“Eù¢¨¢«õ9“H-•ù¬Æ¢5]6?jÞ…V¹z§ªZh)BÙé6×i¥;›^³iÃG4óñ¥†énÀÊ(åEú¡=»[¼‘äXÇy³{¬ËŒÅ·¾{é£ôÒåS¾Ù¬Ë˜m`]Ƙ<žâ1å [çu “ñœ@çûV|Y§wŽ«å’ܨ†ß­hŠ­ZsÔ0 “1j«;Ð÷s2<ò¹õ%&]2˜òIË%f¶ZMBg­#t©:3}ÔWj«áwÎð«CXg&'­Šbr¤É˜sΊwhÍÆ¤Yét­å“…™ŸRQýòEÔÒ\œm¤è’ÖtÙ×[Ô¼ôJ°ßÖDéþ-T34Û²h­£Ð@âKC]tî-Zè誴’hM¯ŒN–U ôç Šk‹7»X¶íÍö°.cÌ@X—1ÛÀºŒ1-ª'`Áó:RëÔ tðsÆcP¬Ó{ÿØÝ·¬ $…=lÕš+ x)ö;9?­î@ßOY†K¨Y…ó€Tµ˜t :“Py¹A¯JT¡œ„*hÂú3Ç…P–‰¼ÔVÃïøÀ¶ð¶ŒE«q£l¢IoDcOþ01swi ö;êŒÜCµTT‚!£¾¦´<œ4‹|Uh¡ ©mõX®ÝÌ1ªÇ(Ã3aD™óQóÒ+Á9lùV—Ì¢-VQµêÀúÊÕ;=ïw!W«LlË.ƒRmàøRªv§‘rÔUT!6¤µ”in;ÖeŒë2fX—1¦Eõ°+XŠÔ K9´ŒDúÝ%Öém[ÇnÖ«–[Ñ[uœ—3±ßjf¤Õèû)ËsRŒpZLº &'¡:óÌœ“f~­ ?3C>ÙþWÙH©­†_.„¸xë?+Áø{ÕÀ¬³Fô¼3ÕÙÆãú¾{N–?À1gÅF ­™,=œ4‹|V˜LXÁÔ¶JgíôúêQ.E j ûÊœš—^ ÎjË·ê¸dv2•KS…cïT.T9ý.äj z”¾ÉO¾°Ú¥[¿\£Q«»¨ïÚ™“ÒFêO»¹]X—1f ¬Ë˜m`]Ƙ<ž¶ÎÖ,Eê„%3è¤ß]bÞÙ¶uìÖi¾jY±DŒ…[uœ—3±ßjf¤ÕèûÇŽ¶.ÌûrФ«`rª3ÏÌI?gŠ2 ?3Cf§H¸@}DtìElIm5|Ô‰ù uM³@!¥/è­³F4‹Ç”?D¼ˆu£o¸n £ˆù}U PS>·<œ4‹|VТ´PÜÞ§³vÈaQgŒ@.ÅM¨¶iÞf¢æ¥W‚sØò­:.™ÅNÆu‡9_{¹Ž¢\PåtZøÀjIQ¾f›ó Ù%M òªgíR«¶êFêO»¹]X—1f ¬Ë˜m`]Ƙ<ž¶ÎÖ:õvÂ’òÈÞaŽA±Nïýcwß2ñ,ÅEÌg«Ö\ÄlƒÉùiuú~NZ^•9''¡:óÌì´Z•þÌ cH¥Ö£ Om5ür!„Úʾ\*ÃàuÖhS“%ªäƤ{ú,”£ã*”NšeC¤´‹é¬>|Ñr†T]jm•™¨ygGqiZ¾UÇ5ÇìJpìV½³ÑóN+ÐrõÚÿ2±žjQ<•ñ–‡ÕU›oM»¹]X—1f ¬Ë˜m`]Ƙý³µN½ep+tdO?¬XEç|‚cÞûÇnY®žæ[±[µæ è“©aß™Vw ï§‚™ŽK+¡ °å*˜œ„ê`™‰Ç™˜¤?3šR½ýQij«á— !8šE ‰š¤êXg4i)7®_©Î˜†ÜZqµªþð-KK'Í2êFšs˜CgíTÔŸIÍvÜ¢°Æ¶qÒæ£æ¥W‚ý¶&ª:®•n¹sh­£¨ÞÙè9Rú K¤³Ðšp\sDÑ ‚¸ÌZŽwñF¢ÁÖ´›Û…ucºŒÙÖeŒiÑ?‘+ˆo“&h©|;½DJÇ X§÷þ±[­ªáV+šR+8ó;EJf™ßšd™MÝ}z¿Êò¦ôlÍ ·­±€ª…ÅáS‹þÌh«j‚JS[ÀfüwNÚÒH¥MÐ7 â‹"y °è¦üýµC¿ò6£t¯£"å9™¶ÊLÔ/µpi°¬Ðik\°Æ|¤rÈ 2a¹%Ò%4Lóïljˆ¾â} ͵sP×=±+¥IŽ7<¶nZ#T›¿‘h³5íæva]f,¾õÝK>öÈ¥Ë/¦üpùë_8õÈÈ”Þÿ¯þ·TjFÀºŒÙÖeŒiÏ÷8ªVO«ñÔÎ:ªÉTž†;Ä0©´Ï÷`Yï¬Ð:vËf5ÜÒA?e|bM+D­¥ððšùUËU4v$YˆÍ5 ÊI° ª¥ü#áš~ÒUf–­:¨.„JaJ¥e/¼H«ßŠjÞJ¨š,[£9¯Í¹{aRùbé¯x\µÒ ûÂSY}³„Í™d<Ú¯Z®2¹v8+0±;u„„§© Ð(ª7Š9HŽDBwì1ZcNµwЗd $‡ÄAÍt­P W½³]»üR¬ƒk: L\t|PwH¨™J5v¦Î_úÏDHt#5aê¤|s{±.3ŸüÌÇÉ<úØ#)M¾téÏ~ý27Ó©Gþú7ÿKªcFÀºŒÙÖeŒé€ó½Î¯LÈ™¬Ã„sm’Qæpãú„+¥Á–µ½÷Ýȧ…êûÉ Æªa$,ãABr OËyˆ1Ô©&SÑ ½@ÙQ9(Œ"†1¡mK*jQšÒ[ý NBz[: 0X8“†Ã„Lô;óí}293å@PÿܙӚð1ö‚(’DïðMDÜ¥åœ/[£rçwö'åNC‚VdÛ_ñªAä _)°¬Ê‘¾Y i€LÈDóï-p’ ;k‡Þ[3Óš öSÑL°î©Ó4]>êÄLÑæ§:"$˜íLE‚FèØªw¶×¯¾‚…NMƒüþ+}Ön|Ffq‘Š«n$VnM»¹]X—‹§žy‘Ìu™/]ú³í—Ô˜›éÔ#_þúR3ÖeÌ6°.cLœ­¯âh ÊØI0+EÑ%±Ó9ÖVêñ hÕA>+¤|Q-Ñ ‘ÿ¸Àp”ß"!úÖw €a«Vh `0Î'èÛìS2’æpæÔ¥VL”†C:[n’þÌÄÄ ­!0?~a' ØH°–ŠÚ2Þ‹›$V]£™¯ÍDêh²aœ¨êÚÅ­­qÆô41i–Dãó<çÕ” '­µifªÛFP6í p& ºNC£ýÎä°Bg\(ÕpØEÇZ•õïléE=³àè@Ê'0ÂÒ™#š¿‘V2kv†u™±Ø .cEæ(b]Ælë2Ƙõ)£³WÌÙ}]ƘñÍ ‚u™±Øˆ.óÅ¿úS+2Gë2fX—1Ƭ£—=gr¼~ë×XP33,¾³™A°.3kê2ÿòs¿øKï?Pcn&Øùæ·¿”ꘑ±.c¶ucÌú8zÙsôƒ)ÕŸ#yýê+Ü!HýoÇ3¾³™A°.3‹u+2Çë2fX—1Ƭ£—=çZøï3¸À~àÏXœzà^\«¨õ#²ÆŒ‰ïlf¬ËŒÅ]ÆŠÌqºŒÙÖeŒ1ëãèÅ\jüO&ì'fÿcÁw63ÖeÆb%]æ¹ÏJŠÌÛÞöÖÇŸüˆ™£Žu³ ¬ËcÖçÜ™Ó`NMý£bsì¹vëú`?€ûî9‰ëø_ŠŒ9BøÎfÁºÌXÌÔežûü§Þóžw27™~üÑo}÷RªcŽ"ÖeÌ6°.cŒ1Æc̰X—‹I]ÆŠÌñƺŒÙÖeŒ1ÆcŒë2cÑÑe¬ÈìÖeÌ6°.cŒ1Æc̰X—‹R—ùÞ¾öìùÿxòä»™ï|ç;PÇŠÌqźŒÙÖeŒ1ÆcŒë2cu™ª"síï.Çúæ˜a]Ælë2ÆcŒ1Æ ‹u™± .óï=eEf?±.c¶ucŒ1Æc†ÅºÌXüǧž@$óÏÿùÿã@9q÷;ÞþàCÿæ?üÇß}ê™'¿øWú¥KV’,$Rå>ßûÁ×Rs³c¬Ë˜m`]ÆcŒ1Ƙa±.3ü͇©ÈÌOŸ8ûx2"NÿÖ¿=¬4/½óïhýrÍ÷~ð5ýêðÌôÑ?šŒˆ‹ù9}(¦·½í­þÚ/—üúøæ·¿”ŒˆO~æc©~Ÿç>ÿ©dAð»cO=óäLÐuç·~à3*¤&]$EŒ\þú:ºÌ¿óêÕ/¿0“ë_ýbjnöë2ÆcŒ1Æ ‹u™±¸úí/ý‹ñŠH'ÿŸïºÿW)É ‰K—_LFÄçþäÜ;ßù?¬M¦÷¼çÝ­oK-ÐeNÿÖ¿MFÄ'?ó±ÃJ³ÓÿêO“±ªc˜“dA\üËÏVš:òVç°Òìtíú7Ð&]æÆß~õío{ëa¥yéñ|0Zˆ|ýåç+ÍKÿòÿâê—_HFÄ3ÿþ±Ãz?žÞ}ò]xèþ’ßâß% â‡ßyn§úP¹£@}ÿµ¿úOç>:Ÿ—Ÿÿl²Á¤¥úäË/žŠ˜ÀX’…ÜNõ;ôMÍÁºŒ1ÆcŒ1Ãb]fD.þåç~ñ—ÞÏàö¸þKìË_ÿBú´H‡Žö¾ùí/¥¤ôÁdA¬úy€$#â‹õ§¿þ¢ˆÖçôoýÛÿïÿï hËÏË|è7ä–˜™žù÷% bU] M’ñ¯ßÿÞÃJóÒÛßöÖûÕd„\ýò ‡•f§Î0û7ý°ÒìÔRy~ôý×VÕźÿ—’ñÒ…?8¬4;uæÿñ|ð°R;ýÄOüÄ·/Y—1ÆcŒ1¦ƒu™qÙuÆ$:ßc–}ÿµøáŽIþþ¯/% ‘W¿p!} ¥ÃŸ~ú?t>K²êçe` cIF*¤Oëôùó?z*Yÿí¿^¼g•yõ?¯4G—ùÉŸüÉCäv¤K/<›|6ÆcŒ1Æë2£cuf¯8ŠºŒ9\záÙ9¼ô¹§>û‰ÿ=ñü§?žªÍç;ÿõ?'OŒ9B<ñá‡ßòæ7žzàÞ”oŽ(ÏŸÅ‚ÞwÏÉׯ¤¢£ËÉ»O­]úúÕWà0Àr¤¢#¦Á¤üÝp{{7Ælë2Gƒ?ÿÏÏêWT¬Îc¬ËcÌ8Üuçî¸ã<¦ü£âá'>üð¹3§Sþ±A,?Ç÷—ŸKEGîR -å &Ÿ«€M˜ŠæóúÕWFXD¼ú0ü OŸIù+±¸÷ñʳ ë2G‰ç>ÿ)©3ï|ç;žzæÉÖÏôš#ŠucŒ‡ãªËp\Hû€Y—õu™SÜËQßöŠ,SF.½ðìÁÜløúÕWRé|6«ËlÊ+cÌ2¬Ë=¬Îc¬ËcÌ80öÛTØ3×.¿Äè iß>23².—–yÅ]º'º ¿‰ÆæH·}ÔË”¼îè?^©t>Ëzo±)¯L„ìp>‡ulŸ±.sT±:s,±.cŒ1ãp,upò}{W\!ý2d{($^ Up—Þv…b>Ët™ׯÜwÏI6ä‘nû¨—)#xÝ¡!Z­ùyŸe½·Ø”W&½º©5Ú Ã:¶ÏX—Žùò ÿ©óÉ“ï²:sl°.c¤óO¯Ì6¸úåºÿ—xc3=þ‘îÉ®ðÉõ˜Á8i4]æ‰?LǬËT¹xþ,‡‰tòîž>ÃëÛ>êÍ*#«r{{7sà¾p†ulŸ±.3ÿòs8ò~âìã)¿C©Îà)2S5s$°.cFã÷Ÿøw¸±\ÿêS¾Ù÷ÿâ¿âý|äôÙßß‹ß%ñÉõ˜a]fè2 ø‹H²pÛG}{•‘ÛÛ»™_ž®Ñ°Ží3ÖeÆâ©gžÄy÷ÑÇIù“$uVgŽ"ÖeÌh|à¡ûqKyùùϦ|³=x<}ôw>”Ü>êðËö ~ß~æÉMؤ¢IÔoÊ,ù…#V&©h1[2¸ÒïÈŠ:”MÇ"õí¨áÌiï Sýñî@—‘'몃zIù”®:ØSÜ ôTÆÔe8ùåš)Ÿl»÷ÝëÖ±O ËŒ¬ÚPÏÙöºƒTTeNý™D„îØl±R«U‹ƒÝê=dŸ±.3‹uBuæï|ÏÍVgŽÖeÌhX—Ù=¼#ýÎïüú… ÿ~(~åW?Ësœtœƒù{+8¤2!Ú¹ô³(êŸ\q6½ïž“±!žÂ›— ð×vS¿¸€5Õä¯iÄRTnE#ž>“†€” FX¤|ÄÉ1ŸOÍ\U5`GxÄuæùâù³±~ÓØW'0(;Â5çœq,R5z)×h²à¿V¡;4Œ¦ð´œ@dÕ‰¤ÊUP Ñ]Ê'3…jìÄü+”}•+…käT_˜|ÖYu; YhºÕ—æ„¥-Ǹ¦ æÀ åÌßá´Ã—FIu>Ëm¿¸÷hª^aKGãHxºÒ ÎQÎYp÷€ÙX×hÒz-#?ù†ër¨Z_Ø{ª ¢ÈHÊ×)žbøÕ )ÞÙ¸uÕªå6XÕ1PmÒ™L³ë2c±¦.C®ýÝeر:s±.cFúÌîá­é•W>ûßÿû_ÅÇ?þaúvlt™xœMIqS+€³r«!S5Ø`µúÅaÕvVK‘Y¸Ñä°8œ°Ÿ7W6Aµ”ǘ((š)Æ“Ð[#Bjî1ÿ‡5j ÖªQâíVGð\ƒ*u™Ø>Eš?j,PlØ7os©¥ÄEhCKù`¥A©¨Â+¤†ˆå˜TöR®ïmÔeäjµkÄÀ,…ÿ©hec§ÜQȇKÚ])UwxiJhžË„VqK,î½EË+¬8­!¡áÓò¥T²Ò‹BpDxD±rL­Ñµf©ìK뎔|ÃE9À¸@©¾öU´Y&ŠMbý¿&¬¦ÔY”•ÃÂuf©ºpf1ÖeÆb#º )Õ™ç>ÿ©TÇŒ†u3ÖevoÚHÖe¶MŒpúÄáÇY<¦“+꤆1øGe6,Û–1[餋C-ÛÆÈת (Åcì®jù¨†136)ߥ¨òqÄg¾* ‡C‹Ùü7áe‡ÎhD5‹X*·ª± ]Ó€üذ”-b)ûÑy&dÆVqA1dùƒ‘Ê`54*eT†5..3asˤ|pîÌiiÛàO ß Ÿ„žÃÏ”¿ê pÍLx®ÌˆœLþ3“óÕ{¬8EH±÷•…rÔ}ú å0.Ê=©‘F·5“l‹§3w¸ê§|¬[!Åk6ÙHï-ª^ÁM!_¯8niÔGwªÙuЕg¾(‡€VòjæèTª&2+Ã%UŽ¾éžœêúƒÇx'¤}­& ל"VæSo\ñuŠ—| Ã¸Ð+ öÕ„°UºuÀm¸ÑYñùŽÎ.4“@“†„ëØÄ¬ƒu™±Ø .C’:óž÷¼ÛêÌÈX—1£a]f÷ðvd]fÛÄy* •EH8¹¦R…«GR™-ò(Ì”¢îØ#R²Œ3:óK›¨©p"ÒiÂÓv™}@tF׸0ü˜ßAÇz¤r®TZ š¨2j˜ãëbÍ^úßi‡Qó÷Þ¢ê,ÓNº!Ìž/xQ,ni•1F=ÕM²ZYÒLܨ²?sVµßR¾Ð¾*Ç4ù¥Zfª¶í3阖¦:9š¤ê ³ë2c±q]†\û»ËŸ8ûøÛÞöVž§ßóžw_þúR3ÖeÌhX—Ù=¼Q#Y—Ù6:˜ö†tríè‚–‘RH¬üê™^¥Õs°â2nAƒ¥Ÿ4Uæ÷☥–Áò¹6èdŸâöN¨F¢'qíÔ]šv¢…CŠs¨€<¹!žUÍÎGn—Ó«!ã"MRµ¹lPšÀ2ÐÒb¡¡2±™Ùr›Ó2Ý^]FnZM…©œ7m¹˜©[i‡ƒêªõe‚’Ž·¨zÅ^Ò"nŠÎ‹bÙèÔ*~˜¥Ú²rKY oxTŽ^ªiÿ´(-D6òפœº9ôªÐÒãôRª.Y€u™±Ø’.C¾õÝKýø£Tgò#©ÔŒ€u3ÖevÏMÙã Y—Ù*sB»êÉUm Pª“¬4ØêQEUy©Ò}h0ùßÉWÈÑ iªÒAݸ~%ÖhZÁP8“î©UœáÉ@K±ÓbAÐÃ4^ tQµ¹lPÒ&Ê@Klùi8Њصiã„kÝÏgkçÌA¯ÆóxÔ b©Z¥W½*¯´ÃAuÕèÎü,ÆâÞ[T½jÝÍ6EµS°`tRyð¨Ì“•åƒr´J‡«ô»Ðܦ}iÍ¿,/ÓËúŽÍ¦ê´Œ˜U±.3[ÕeÈ·¾{铟ùص¿»œòÍX—1£a]f÷è7“u™­¢Àµs ®ž\yRGB`ó#­ˆˆ['ݾe9.RevTæ«‹ÖÐZ [LÖ§“¨¦œ™ïxËU}꡽DèR 2'SÇr 6ø†&ˆhÙé/nšM6JŸ‹‰§DœäžF4™bC­Ô‚Á’9kÝAcÔ6Ák—_ÒWÀâÇ8R<*‡pžË|Q]V>3‘ZßI,î½E«¾6*LêUVzQ ù¨òÛÆ†ÒÔt[è EŸ“´UØPn#á;¹õ¡ÖlBv¢ý„üLFضœ·™ôÓG·ú/Rù?sÇš>ÖeÆÂºÌžc]ÆŒ†u™Ýs {ÜLÖe¶ Ž›`ý2_]´†ÖjØb²>D5å´¦.!WÕV £µýAŠT&zìÓÙ*‘ôÃH²À§¥‡­ÅÍ&›‹¥3;Ö‹{oÑ©”žÅ„Ês~Ã…,xQ,ÝJ¯#í"$9S¥ô [›E‡í,T;e<¦|" ñŽ”ŸÉÛVk}Ç8ùHý™œã¿™u™±°.³çX—1£a]f÷è7“u™­2ç_=¹Î9‰ê$ÍlÛ:Ië(\µ\uX#¢&œ±- &ÿ;ùê¢5´VÓõé<ª)GŸVè÷"WZ·ædæ`]f,¬Ëì9ÖeÌhX—Ù=ºÇÍd]fÛð`ŠTÿ ¥“«¢VäWÿkŒ ªï¶Nºê±åJ4‰Ñ,›”¹‘òÕ*å«‹V˜ÝjØb²>=Dµ˜)M¡uÜ××"RCv‡T øÞ Ŷގ^GT2:­Ž—E.ô>½Õ¢jsÍAi×ný/žêZhìä¶[]¦9ÈÂâ%øhãâÆÀ0cä3S›­úY8Àj)_pöJ?«ù t[áv"÷Þb¥ú“½ š­Öì¼(–Ž™HIÅq¹ÊHÕÅ]‰ÖÍS£¨Þ¢·÷×d’¾c€ö‘ª- ­?{†X—‹O~æc8ïZ—Ù[¬Ë˜Ñ°.³{t›ÉºÌ¶Q žŽ¶8ëĉ„ãi,*-ƒÕض Vû'i5L'{¢sŒfÕ$!Ñ–ÿe~+´­†-&ëW'D¡Rù6²9¤İ6 AkÍTZú\š{зÒèv/KY„:©hš-m®3(Ic2R­WªeêÚå—ÒOh°·Q—ô¼H³¤ÔH ©†¯œ”¦|A㥟ý|¤rÕàJË—ÿ‚Þ[TëcÊÈ\Kßé]¨æJ/Še£ÓM¬ì>c,Ñ D·²²ÀØ£†u©nuz‹+ÇüÖ D6û×d’IÇÐ#+ £4¨XºØSb]f,¾ùí/=øk¿|ñ/?—òÍž`]ƌƗ_<ÿ¡ßxð‡ßy5å›íAáɺ̶‰Q%—8ÐD¤ÌÄ#ž¸H õ&'JÑG[ ¶HÕÓ*K[Y”«‚☡Sf"! ã7äèQõ ;*óÕE+Di5l1YŸ–"OPЧ˜sŒ +Â&He Ø#ªa9Ð(SrC ¢™ewœIÀæ(±I‹Ì`uh$n $L­€* ܈ù?ÃH„àXÌ,£ÇÚ L):7$¥ù(íÌ”Í[ùñ:p³Äõbfœ´Å½·¨Ög&WûYw¤9‹¸ìE±xtlȶ|5Ý:’Áè®å.Ô¤œs{©¦þƈ´Œt^Ì_0:¼jZÝ¡ î©~ëÊ„&ñ_ûRé ¡Ÿ1%ùfMæ0é^#­™DBóòFjÖÁºŒ1a]ÆCáɺÌnÀ!‡Q1…¢;c8•¦£ªxýê+ *b[T.Ïý¥¨ß fßéNˆAAÑ \Ó6) ¶:âxAKè{X2YE¨ÐšK/<‹"‹ ù©fäÆÁ?‹IMøÁlbéQÛ²ygM«ÀN´€aÒgnŒ•EZÇVµDÁ²AÑÒš.é…ÁÔb¼åbiZbG‰6Ÿò¥Ñ‡Sàg*qZ\¨Qº`‡÷W­Üù¨_®×âÞ[´êóÎ0éOŸU_kŽ®ôµÖžÀZ¬ Ð>—M0ðT5;›9½:P¹|Q çAÕzéLrøs˜ã(gOç¿xÍ|¬Ë3ÖeŒ1>¬ËcŒ1ÆìÖeŒë2Æ HÖeŒ1Æcöë2Æ „uc …$ë2ÆcŒ1û€ucºŒ1†Â’ucŒ1Ƙ}ÀºŒ1a]ÆCáɺŒ1ÆcÌ>`]Ƙ°.cŒ¡ðd]ÆcŒ1f°.3ßûÁ×>ù™}óÛ_JùfO°.cFãû¯ýÕŸÿÑS?úþk)ßl HÖeŒ1Æcöë2cñ¹?9‡óîãO~$å›=ÁºŒýƃ¸)}ùÅó)ßlÝãf².cŒ1ƳX—‹§žyçÝG{$å›=ÁºŒ`]f,¬Ëì9ÖeÌhX—Ù=ºÇÍd]ÆcŒ1f°.3Öeöë2f4¬ËìžÝãf².cŒ1ƳX— ë2{Žu3ÖevÏîq3Y—1ÆcŒÙ¬ËŒ…u™=ǺŒ ë2»ç@÷=ýï§ÿmrÛcŒ1Æ,úÌXX—Ùs¬Ë˜Ñ°.³{~þçþ@ú:ý›{ߟÜ6fLNÞ}â®;ßð–7¿1åßà €K)ߘUyýê+ØÕØN÷Ýs2™Ä~˜/½£ò·1º@lsÇwà1åßè̪"Ñ…§Ï  Àj¦"³·àe…½´`;í÷Ýs’¥4ÈÝ îÕt«œŠúœzà^쇓wŸ¸qýJ*2ãc]f,¬Ëì9ÖeÌhX—Ù=ºÇÍô;ÿð^ø©ŸŠ_yÓ›è›_f|.ž?K %Ù×WIª–;é6BtuHŒÎ¬Hk¶ýA#¬ËÌ÷:Î^DO|øaLÚ¹3§Ç-Óe^¿úŠîf*5ãc]f,¬Ëì9ÖeÌhX—Ù=ºÇÍôÊOþä¿ãŽ¡øø?øôͺÌàœzà^žÎ‘pR'‡ÏrV}6­ÍI¨Ÿ,ì ºº&?”Dgë2þÆÊ˜`Źô)«l[—™ÜÌ ØýD¡/ÎÒ.;äâù³ð§#Èíź̅§Ï¤R3>ÖeÆâsrçÝÇŸüHÊ7{‚u3¿ý›¿Ž›Ò«_¸òÍö8Ð=n&ë2f8ôóhŽþ—^x!ó׌å_!`HHIù`³ÑÝJÈ«”¿qæD€tfÕÉÇ‚ž¼ûÄ}÷œ¼Óh:èe…­žŠ¶úb§ÛÐeælæì~¢nËÒL2ySZ¦ËÜð1äSÜ›òÍ‘ÀºÌX|ï_{îóŸúÖw/¥|³'X—1£ñ÷}é¥ ð£ï¿–òÍö ðd]Æ,C¡Hù–éëWTK×d2ظ-ìÌ«íé2fpnKðo]f쯻ׯ¾’Šn#“7¥ÅºŒ9ÒX—1f ¬Ëc(| Y—1 ¸ô³<з¢5ø7ÎM·…y5'”¥3Û¤Ímd÷r°.3öxänJšë2{…ucºŒ1†Â’u™]‚ã/ŽÂdò¿Þ¼~õ• OŸQýþOø•½[‹‹~«d|Õs¹þùHëÇ à+lG}£¹*w`<¦ü]Bjŷ˘Ó5ÀÉ$Ô'‡ÏrfF_Ëtز°¦P©ˆÁ›²>Óœ e¥P–51|Ehì1Z(ǃ´˜šÌGsn .bͰSXC§Ñ=¤dO™_º£M!Ï‘P“ð)Úâ…Æë4^uÔÚ·4‚ǔԥô¨ÓÒÉ9sÛ—TM•ÕlÆœê P‡P‡ð©¶}ê¨Eܨ¸ˆ౬S&i3Ÿ;sú0·°Æ§t¥‰ÚÈ0¾´Ë¥“e7V@[½•Z›”•cŠ3&¯¢âœKóF‰"T«æ³(MiÇa³c¬Ë3ÖeŒ1>¬Ël…H8Ç|¾?¾1bÁ:Û1âŠMĨÀ:h‹s0@XÃVcećlˆÇØi UNùõG½>sºê˜jåãZE3 â"F-†[H¥WQHóÛ&m® Ö‘ ª&\b—pŠ”Ô/Ç®úDþÀ`ÌgÔOù¨¿þÛàìÆé3 !PŒ±F qÉ0p¨ ¤5ðS­ô:Riu¼e¾Pó”¿ÀIæÃTnQ ¢æ€Ø®5¨ô)9-.ŒÄüX„¶jS)¼/VQ«4R<fnfú†©ˆ/a ½>Ç …ɉª³æ0öˆ&ê.ŽbñM€žÈUT†eLEY3A4>%±Z\z<¢#ͳf)í% ñÆLÌ6ë§)…M¬`œs{±.cÌ@X—1ÆPø@².³mp$åi5È Î²ñ­¨&m‰ŽÚH)ìÑÙ©Ú´ÎÍDñVs7X3Ëý/†3ÐïZ#Å´¤"¢éš,ÑXÊúˆ:´(¥Wꨌm€üDÃ9A P(Õ™ÕèO ho„•Õ Òb>¢)fΜ¨UQ§H­ÅÂÌÐçjxX-•å² j]Ò<¨(å v‡Ç˜¹ÀÉUçvÒ1Øa…êfSiºuб2Äà¼:®’êä´˜Ü̘¢´Eg°“µ©;¡`­QËŸUoZ¤ru&™\‹øê+ÛyUÇË›d9 3ÖeŒë2Æ HÖe¶Š¢µÎáXÄÊñ×#z‡‡à˜¯£y†:L·ÎÍ3]E´sÐÕD¨6t-cŽ“š‹o*!Øc…ÉÁ’~§z?gVéLË[õ˜,ÈrŠf5Q-ÅaÔigŠ&·¥ŒD ¦º"šEJãm勪åuœDš3·}Ç´KOµ¿äÂî`G9-‘NÌ|± 99玧9iõÞAŽ•mûÊyHÐBg5úëÜèç|7“Í5ÿ+muP¯¬¡´õ¾‚ë2cqùë_øÅ_zÿsŸÿTÊ7{‚u3/]øƒýþ÷þð;¯¦|³=(| Y—Ù*+3+WÏÊ“„ÂÔý*´ŒÔ:¦“h*E&C¾eÐÉ9#Åœ¤¢g ©?XÿY³3ªWsº˜é­˜ïLË zLd9y«|$ÄQVXŸV§Í-*WW4‚k6™3«­Õ™\µêZ/pàš™H“sÛwL¦`‡=–”žOvÎLF$!¡I_o‚K¬‰‹TTåõ[ÿÂHÅ.Ûö¥u‹…TµPÂãÄŠÉr)M2ÝH™óaóªW#=è¶é[k\ÕüøI\ÀxëãHæöb]f,žzæIœw}ì‘”oöë2f4>ðÐý¸)½üügS¾ÙºÇÍd]f«èP>çýðjäV¢³o@&»kÍ0ˆ.Å|¶…ñ˜96¯zE4ÿ-ßZãêŒÀ,»Vê|·Îìë2ca]fϱ.cFúÌî9Ð=n&ë2[Eo†w1³rõ´Ý?(ýŸò#:vOþœM¿ÎªÃè ý‘rÆ:ñQôÒY—ªWš9!ÙÌu™ïLË zLd¹ã-âm„XWïætÊîVêkά¶6À䯍ú³ÀÉÄäÜö›³1J&;g&;œ;sZ] ¥NLú,QFR[9V¶íjÍUaÕÕׂ¶f´\bÛÅ~²yÕ+¢ùoùÖWg¼‚Ÿr:03­´-ÍV±.3Öeöë2f4¬ËìžÝãf².³Utðó†¡*wÞ§EðV=mO”7°;¤ò=pÒòs}&Íj¤ý®iiR6Ò£f¤"Qõjr–€T¤Žñˆ6I'Ρ3­…Öü$ ²Ü ÒWC[ó Ms:­Îm¬)ÍvZi©kÉ£-—ªþ,p²Jgn[ÍäJŸMPäÜZGôÅ ­í4MiÚäò9mEÒ_D9V¶íOÔFF”`U?åÌ‚›7Õb?'÷ä䫯5®ÎxºyΩlvƒu™±°.³çX—1£a]f÷è7“u™­réÖ¯`Î9•Ω¬cnÒnæ”Q:Yg&ˆý¼hJH-?×gÎ(TQn*"sâv¡@®UÔcÌŸœ% À¸¶EÂUCYBgZᜆ“,LiíÕŽs˜Ó)÷6RúÄD­Hk°RêZ.U¥ŠÖZ/s²Jkn¥nTç ™,m­{ vò…¼’ÙNZ2ÒßÌQÕ7•–mûª+¸\ýªÁunÕI›Ïä0µú­‰j«3Þ’•*›`]f,¬Ëì9ÖeÌhX—Ù=ºÇÍd]fÛðpŒtñüÙTp Žïo«r5&Œÿð"…sξ WªQÐJD]£÷Ò¤2LEì&?¥Ò‚3ЩâœV,¤ 3§BÓ^ª'XA•&¯â,UÇ«¼?œˆÂÑôÖz„þ` R>‘…4öÉ -ÒÒ°SݽUætªè½3ä’þÐþDJ]K‰(»‹fIK¶ÌÉ*­¹Õ\µ¦—ëŽT¾èZô_ÈRk;ͤº'û›¹_Ú¹›MNÔï„„»"m ²ÎM :ióÑ^­ö 4Q­W_k\ñ–¬TÙìë2ca]fϱ.cFúÌî9Ð=n&ë2ÛF1¦)^±™ñØ­ƒ2ò“cÂ2P™söÅéh¡± ‹SÜ[ÕJàM¡ëÑݸ~¥ã§‚Þ¾«8„~s…:HQö"qERQ‹¸.1†AGò‡*"š¥Ô¨-Òüø0†y˜jf¦ˆšf㾊(ÜMjŒÑOdbiß+íR-ýÌU;-‘٪Ȱ¯ÒBÇ=Œ¯#¦Ô5*h]âË$®®UDVurÕ¹Õk”—>¾¸J³™ð-íuÿµ£€¬1¡TE-0“¨–Ü5¤™éoæXšÖH/a¤r§MNÔfï„€K_n ¢.7U9Í™ù*ê7ZŽK<ùêk«š§å0‡=,…Ù8ÖeÆÂºÌžc]ÆŒ†u™Ýs {ÜLÖevO±L8¼â)à™)ee”"Bˆõqë¶B”ŸÐA •Þ àOÙEy¶®c\À3S¢­` íã1å' "ѽ4¸XÉØPƒe³(µÂ ¤†˜j ¶HxšZõQ[y‚ ,‡*°Gä+'‚Q³yZh-Mœe®Fª•] ‡EÉx‹j§%_Y ½ãE!g8|ä—Î(.EB)aeÚNÆÆUp掦0FŒ4Õ‰` ¨¿øíSŽ)¿ ¼4ÒI÷úÀZÕ.úó ¸Ú˜Z¦L4”5Œ.…=ô¤5E7®_a…4Bü¦ý¸u;sÈH² äZt:­’<˜‡–3$îÏ8Wxʸ±µícÃ8dl]8ÜÙ+9™*wæ– Tõ[•±=à¡l wn qG\ks¢a¼ ¸M•û3ÑßÌ .D¬@ÇZÓ5g¢ŒÈ8ÍUï„ô¤üDš€†šçÚœ?óUâì¡÷Øüa­W_k\­üòÏV€æ¶`]f,¬Ëì9ÖeÌhX—Ù=ºÇÍd]Ƴ’Qé(¶AÐHo—É‘Æs±.3Öeöë2f4¬ËìžÝãf².cŒÙü°Ì[ÖøÚÅ.±.cŒÙC¬ËŒ…u™=ǺŒ ë2»ç@÷¸™¬ËcÖçÂÁŒÞÕøgÀb]Ƴ‡X— ë2{Žu3ÖevÏîq3Y—1ƬeŽ#ñ &b]Ƴ‡X— ë2{Žu3ÖevÏîq3Y—1Ƭ KxÍ(Ý1ÖeŒ1{ˆu™±¸tùEœw?ù™¥|³'X—1£ñÙß?óö·½õúW¿˜òÍö ðd]Ƴ‡œ:øÒGè‹WƳ>ÖeŒë2Æ HÖeŒ1Æcöë2Æ „uc …$ë2ÆcŒ1û€ucºŒ1†Â’ucŒ1Ƙ}ÀºŒ1a]ÆCáɺŒ1ÆcÌ>`]Ƙ°.cŒ¡ðd]ÆcŒ1f°.cÌ@X—1ÆPø@zÇ?ûgÿòŸþÓ¡xÛÏý}{â·N%·1ÆcÌ2¬Ë3ÖeŒ1>OÿæÞ÷'·1ÆcÌ2¬Ë3ÖeŒ1‡ÊÇØéÁ_þ×ÉmcŒ1Ƴ ë2Ãñ¥Kvíï.§L³'X—1£qão¿úßþëÅ”i¶Ê¡òqâÄïüÃxá§~j(~åMo¢oþ}cŒ1ƘMa]f,þü??{ó¼ûñGS¾Ù¬Ë˜Ñxü#ÄMéë/?ŸòÍö8Ð=n&ÿî¯1ÆcÌ>`]f,žzæIœw}ì‘”oöë2f4>ðÐý¸)½üügS¾ÙºÇÍd]ÆcŒ1f°.3Öeöë2f4¬ËìžÝãf².³‡\»üH™›åõ«¯|ãåç¶ÝËfiù¼¥±À&H™f?9Н—oicÆÇºÌXX—Ùs¬Ë˜Ñ°.³{t›ÉºÌ¾qîÌé;Ò~8m·¼ùèâ®;ßòG¦åó6Ƃɿ¹wÜá8Ö€£øzI`'sKoõÆbŒYë2ca]fϱ.cFúÌî9Ð=n&ë2û†ë2 ë2f1¯_};`·¤¢9,ÛckvºY¬Ës$°.3Öeöë2f4¬ËìžÝãf².³oX—iÑòyc±.sÌÐÇЬé²=¶f§›ÅºŒ1Gë2ca]fϱ.cFúÌî9Ð=n&ë2û†u™ÔeN=p/Z¼ûDÊÖeŽ—^x– ZÝ'Ø ØØ)_,{½ô;Ý,ž>'ÁëW_IEĺŒ1Gë2ca]fϱ.cFúÌî9Ð=n&ë2û†u™-ŸŒ•ûM¬Ë?.½ð,–µüí^ ØH©H,~½´:Ý8ô©µc­Ës$°.3Öeöë2f4¬ËìžÝãf².³oHØjø´8μ´|^0Tî7Ñ*X—9ölU—ÙôɺŒ1Gë2ca]fϱ.cFúÌî9Ð=n&ë2û†u™-ŸŒ•ûM¬ËìÖeŒ1ã`]f,¬Ëì9ÖeÌhX—Ù=ºÇÍd]fÛð‹çΜV®ä˜ßâõ«¯ ¢‚œzàÞ9ß\ˆ¡ bŽ.»ÃÅ'hˆ.g¢ktGƒ jÒD• t²N³ûxÚú ”FŸ'óKØ@e6áS‚ šxŠ HŠr1(99g€°†5U\Gû«‚µâ÷ÝsòÂÓgR…H9«hÞšÕׯpø|Šj°¯Vª&VœY6ôª5Õ0Ý.AÃÔœ9ÏŸU®‘—¸Öi?`fTž³Ÿb–4(¬Kg9ÊN »Ð]ÃÑ´ãbæšâ–F‚cÌqø¥.·µ©ÐªµC* -ëÓÏþ>¬BÇâÀgΤˆM:­´±ËÉ'åI°yu-’¸n-Ùª¯/c¬ËŒ…u™=ǺŒ ë2»ç@÷¸™¬Ëlœ˜«0â ^árZoAœÈË&Lbhiu„ƒþ é(ÁQ¾Úۦʰ®«6‘“FÍ:xlÅoˆµØÆSQ f€>” ]TÇ}ž“_‚9衞PªšZL".Ž=&ä´væ§ÕQìb&˜Š²w$Œºê@«kÁ^M•Œ°.@ì ×±æ‚q¡ÇÃ?žªž$è «ûM›§ÜjPÑ1DÔÓJÑrÜcÕ×K4);ù|#P?°ñc ™±~ 8sØ –è0Ñœ SL©&P •;÷Öv`9Uî09plÝaÐQé6Sé¼nGq"ŽD¢ˆîiƒ­ú*дãÄ9l9föë2ca]fϱ.cFúÌî9Ð=n&ë2Û†ço‘áà§ 34.ª K< ³ 9Ìj4DœX\ëKͺDå¢2ºF}˜/ͰØQhTz‚‹±¨fé‘{)’©{eØL_ù.·|ž™_‚^P-ö§$Ž ×¬缜Ÿrq¶Å hž† ©I,([!ÁBé@¬ gPª"VŽõ‘ÊÐQq£ < U[0.Í¡êzXV.Ñ~«îêN¿Ý±4¶e“X³L™BâS?A·‘Y¾^ø©œ[€j(*d>ü”Zc>¦+µ*¡h[ñ)‰.i¡1ÖÇcÙiõsr5ùjÕR2³*mTa_åÀõ שˆò(.ÔJ™HiÆX„ÇRè‰7áê<ÓŸÔvÁ«`æëËa]f,¬Ëì9ÖeÌhX—Ù=ºÇÍd]fÛà`Ís3¢Å·7qøV>QCÔIÁL !Êh'~ÅÀ^!SŠHÀ2KEì1¿ƒ|@B«¨¤ÄQGç£ʌȇ2 *A5Oó4 ­y+{oåw«)_,Þp›E± ÑÐÒʶˆA`’ºãaÔÉu¢´Ò‘RïŠÙ—Úâ1®Î‚qÑ`rÀìœÀi¶Ü ÚŠH¥} -çATÑ ”E‚™`'.‡üD*÷s«Sæë16Ô|"_™“ÈÃts&êkr¢¢Wºª×Š’©}U®Q‹ÎÀã§Ë¢¢ÎDªÎdzù¼rY„TÈØ¹àU0óõeŒ°.3Öeöë2f4¬ËìžÝãf².³mu Åw׉‚®òì®8¡z¼Æq\â›Éƒ Æxé|¯ ÚFQF UÐ;ëÃÉ2C*-#[¤òíqä°hf„Í&Ø S>}žŸß¡Õ…X¶+4oÕI@L;ÙoD‘^©þ¸ÖqÉRðLB§Þc¸^Ý“`Á¸d¶åüJ³$ÕHé­Å†i8ÕL W[Ã(b)_/•juÊ|•ë¥îÒÐ:¨Ié‰ ]Ê š4<¦"åW÷•îK3?2Ó¸^wÉ å·n/Z‚XAû¶œMR9d½Àã‚.x€8í¥Æ”X—‹O~æc8ïZ—Ù[¬Ë˜ÑøÐo<ˆ›Ò—_<ŸòÍö8Ð=n&ë2ÛF'þVY=mÏy£X ºP¦â‡–€¢ ±U+Ô’Efý–”¢Q…è§âár®TÔ28v&|A~Nf§É²]¡µk…ÓÚ­à9¢.:–åÖ¾4ˆ{W܈ҖW Ƶꆬ"³©_¥¼€{±TAuš V.ýÑ t\åC*¿^:Z2ÕÅÕö‹7>ò°µˆ“ìZ¨*Ý gºª·tV@Šª™í7ÔŒùê.fêvª –îZÚð±»e¯nM;zl-1ë2cñ­ï^zô±G.]~1å›=ÁºŒ¯¿üüãùà¿ójÊ7ۃ’u™m£¨uh®žì[úˆBšÑR+À¨†d2Õ ~ª~¶` Ö©,7b<Ö ~ÀJ½÷iù¶j~‡Io—íŠùf;Û†(œ‹›§ƒºîˆ8 ,ã.RG­À,[!%Ýd>Šù£o ªÑWÕ1½6ÓKŒ•Ëùœ3Õý=&—J «æ“9¯÷=DjíX ³eSÛ#Z¨fFdvæ*÷4ÉÛN„–‘¢«Ú QLáô¢>j²ª©03uWÍŒT_šŸÎë˘ˆucºŒ1†Â’u™m£Ãt+ð`œŽã“QЉ<!ó÷1|R&ÂZUP«¬ß©¬5c¾:Šq®™¹ GL‹‰ÂEkŠZ>OŽ¥¤Õ…Є¯´+h ¥UTöcÃM)Z¥¢*“#T µK;.-×Åóg™‰„ è´£U‘ÞÇ¥ ¥°y`¾òÙŠØ$æÃÛ”_}&P„ ¥MÑ2¾j>™³( zˆÔÚ±“6µ=¢™ÅE UP«ý)AòsÎyRJ0HñÖÄ.¸šlÅk"(ÝÍè9šTQ…8à –Òì9ÖeŒë2Æ HÖe¶M5‰àÀÒxp:‚·ZÈc[6LÖ"ò'žã•9™:–#ÕAEZ±ôš2ÎAŠÑ$üWÙœ2•¾µ|žK ;í4YsWL¦ô›90çmöêN+‘͸¦j÷[bñ¸Ƕ¸>y÷‰ô1–>šgi:Ül‚Ô+9¯á”óFOâØIk«GäFÊ-ã«æ“9‹’ ‡Hh›ŠÈ¤MmhAf'SúÈI‹þÀÜŸÊé´r5 =â1åp‡HÚÓ¨Õ]º›±Õœ_ –Òì9ÖeŒë2Æ HÖe¶Ná­x†Çýx¬:£·ZÈË Y‹ÈŸxŽW&‚\w˜©ŒT‘óe,TarP%’rнh-k-Ÿ'ÇRÒêBÀ T@Z°+ð¨±T™eªô¿]&†Ðj‹Re&ÖŠh ×ñ‹}Ж­dœ¦4-|ª]ª0»TRMÑÙêbrµŒ¯šOæ,J‚"µvì¤MMu´ ³˜XTè0óÃPý˜b¸H9V@®¦}¨|n }†·JM‹vë—kMÏñÈñ¶H½/XJ³çX—1f ¬Ëc(| Y—Ù68.óÜÜŠgªÇtõ[­€N䨬Lî•“?ñ_Í\‡Vì!]°Çòmp䰈ѵ>³>ößA_.€¥ÔòmÕü¨Üo²lWLšf¥¢*sº®î¢9qãFÆ…qÒhjf¯(šó‚jÀÝ(ß:›£(ç³ú:MtÌ’–ñUóÉœEIÐC¤ÖŽ´©í-Lš]•þÀn/8f¾Z®êVÆói\Ê䟖÷=æÇ†s˜œvcÖeŒë2Æ HÖe¶M5‰ð¸ŸŽãŠÒ»£ÅQ°àá©Õü‰çøª©u¨*¢Ï³”á„Â$†.ªY~B¡…f¯úßmZ¾­šß«Ði²lWÈìLÑ¡ƒÂ¹Ž“vÔY…$¨‘9qãÇÕÙW-Ô;®Ë Z.à+W_&,ÂÂ¥|Í@Y$&÷XËøªùd΢$è!RkÇNÚ¬îùêžY‡þÀ+ É yŽ"U+aC<¦]ª]ÁN9¢è÷$Æí¤ ¤e¿Ïä´“°.cÌ@X—1ÆPø@².³mªÑH„Žã1SBIù¶ªP¤¤÷öâœÖ1]­b}L ¹±õÒ ·„ U§E!ÊëWtêt¨N©h•®šßa²É²]±Ù ÆimŽà5¹¯Z+5'nÜค©új’>qƒG•F-F¯ÊøŠ¬ÛŠN©.w¤eaÕ|²Î,µvì¤Mä³B´°qE˜ÇcÕÏÖŽ­ª+ ô#ÓÕ)ÕòéU'!j1Üê©w²ìU°`)Ížc]Ƙ°.cŒ¡ðd]fÛT£‘ˆÎô1SÑ RõCŠgRœ €AB,ì‹)ãUË1±£2ÌóÕø(\ðñ ÞË9ó“ŠØj~~‡ŽdÙ®Ð'‰Pó—¡8©P¤ÐÓ8oÕ÷óµR)Àž7.W¹·‰üœ¿aÔ;<ÇèʶZ‹NP ض:µu‘òEËøªùd΢$´c[M&mÊBÚót­×ÂJÐZË ö|Ú¥Ú½­ã!•w3 ûUK½¢WèÕ^–½º'§Ý˜„ucºŒ1†Â’u™mÓŠFOü8¯§|ñQ”´ÙD*U…¸PÍ0™ Ò9^QRyÄ¿vù%d¢íœÏVùÀ„±È‰2H- Hok3¡ßªÐ"FY1€óVN¸ægf~9 ð# «‚P<€„ â0«ñæ­>r”šànðiyŽWü‰„:è¨9Rk zŽÇ >EjÅ·„˜pJûÄ( h”CËxšZ­šßÔÍž²kØQ…Å»" רI”;ê#7˜`ði²U$\³Seâ¢rXÚW—<¯ÖÄ®SÍ9h—"ÁH*Õ˜ª/:ÀÞ£“"Î3ª±fœ´b‘r-ã«æ“™‹’ M$\•NÚÔ$”›„Ãg‚M<%¸VfjÒ‚MØ\m Ÿ"UWPÂêGð45‰Äšå-mìöT,xu/[J³ÏX—‹O~æc8ï>úØ#)ßì ÖeÌh|è7ÄMéË/žOùf{è7“u™mÓ‰FÎÙ(ű;å“SÜOêJhUý~AQÙ ÑãUÏñhHÊ„Vóþ4ÂâÜ™ÓÉ<Ÿbý´:¬ÝŽ„;`¶Ë çÒ ÏrEàCjÂúóóû” ‡¼Î®¸qýÊ}·¾q“2±Êé³}0·¥)äT¥ ìدÖoõ;?n\u\-O&·VIŒÉa6•u„‹T$X —ò ÌÒ‚Rü@Ääk_5Ÿ, æË­íOÚìïy”&ãLÈD/{]"¼| âiçf‚AÃê!¡Õ¤Ò¥½òã0ú@ RkQȪ¯‚eKiöë2cñÔ3Oâ¼k]fo±.cFãÝ›ÒËÏ6å›íq {ÜLÖe¶ ÎÙ8:WC‚sv¿ š ªp "jv¿à“@©„3{T|[Fd­õvq‚Á Sþ|â¼Å0˜3 §¤µ­üI0L:öÖß0×·ìb%âDuW’ºž\P¤³ß"++Užô¼lM8:biç…0YEr5U›\î–ñUó+Ì\”ˆ&¼œí¾ÍÉ=â>dý­U›†´4ÖT­&M/Ûù­G× –xÎˆÒÆWÍ.XJ³ŸX— ë2{Žu3ÖevÏîq3Y—1c‚°äàmà‰¯;cŒHºŒ1&a]f,¬Ëì9ÖeÌhX—Ù=ºÇÍd]ÆŒ‰¾÷±ÎÇ@Œ1{…ucúX— ë2{Žu3ÖevÏîq3Y—1òú­ß¿\çKLƘ}úŒ1}¬ËŒ…u™=ǺŒ ë2»ç@÷¸™¬Ë˜9uë?CMþܦ1Æë2Æô±.3Öeöë2f4¬ËìžÝãf².c„ÁRç‡K1&a]Ƙ>ÖeÆÂºÌžc]ÆŒ†u™Ýs {ÜL¿øÿñßøÆ¡ø_ßòúf]fo¹ïž“ˆ¬ÎÿnÖc:œzà^ß:Œé`]f,¬Ëì9ÖeÌhX—Ù=ºÇèɺŒ1Æc̦°.3Öeöë2f4¬ËìžßþÍ_?>†NþGO%·1ÆcÌ2¬ËŒ…u™=ǺŒ ë2»çÆß~õÏÿè©ÿtî£Ãâý`Œ1ƳA¬ËŒ…u™=ǺŒ ë2ÆcŒ1Ælë2ca]fϱ.cFúŒ1ÆcŒ1[źÌXX—Ùs¬Ë˜Ñ°.cŒ1ÆcÌV±.3Öeöë2f4¬ËcŒ1ƳU¬ËŒÅÅ¿üB Oœ}<å›=ÁºŒÇ?òAÜ”¾þòó)ßcŒ1Ƴ¬Ë Ç¥Ë/~ï_K™fO°.cFãGßíúW¿˜21ÆcŒ1›ÂºŒ1a]ÆcŒ1Æcö ë2Æ „ucŒ1ÆcŒÙ+¬Ë3ÖeŒ1fžøðÃoyóO=poÊ7ûÃ}÷œÄ8wætÊ7ãp<Öèâù³Ærãú•Ttyýê+ð À½T´noïÛY0´“wŸHùfo±.cÌ@X—1Ƙq¸ëÎ7ÜqÇxLùG9O|øak “|ãåç°>¥"³q°!±-/<}&å÷96kÿ9Œ(ÝF4½XšTÔçÚå—м~õ•T4ŸÅ½·ØˆW›‚+¾àï ‡pé…gS¾9êX—1f ¬ËcÌ8W]†ãBZ5Þ7¬Ëì ™œjlΕbfë2[e±2¢áÜwÏÉT4Ÿë2ñjSЙUÿ¾œzà^áøýa2ÖeŒë2Æ3Ô/ŽÙñ÷Úå—x¬GòGfú,‹ùÑj¨ÐúH€­È©FÂM¥–­Ñ€H2jóhzWUFxóDZç{:‹{o±¯f‚m ÿ;"ã2]žsÇì“ÖeŒë2Æ3<Ä¿ã/Nö¢‚>Ì?2 b~é ›Š$÷lEL2¶åªó‚5FéHQ*º,VFN=p/V¬óÓ0‹{o±¯æ ù»³-¹âp&å÷çÆ’ŠÌQǺŒ1a]ÆcÆgßçfslXó#€dë2»ÁºÌVÙ¸2²··÷u˜³-—é2æc]f,.]~ñĉŸüÌÇR¾Ù¬Ë˜ÑøìïŸyûÛÞzý«_LùÆìÖeöœ1¿u™³`ÆÄºLÉíí}ælKë2&a]f,žzæÉ'N<úØ#)ßì ÖeÌh|à¡ûqSzùùϦ|cޝ_}'iÛb¦.Ãß ©hõ›òKg~ሕI*ZÌ– ®ú"«ú E™ß‘šh¶q}[mW—a§$- Eu½ÒеMùU¬HÉ:kĆ å÷™|…‚–Ë&GH—Ñ*(g1´Ó2…ü­öÞ‡½,ë­èùªº {\ç5h̼ ˜A°.3Öeöë2f4¬Ë˜cNÀü½£‘p\æ¿ íë28òÞwÏÉØ Oa­õLQ øk»©_\Ärãú•h¨Ü:¬_xúLR2aeòüÄ|>=4w`p¾Ö@ØqF„„yîÿʦ1‹Öúÿ 6¹„§}Ïᆢb$ö€œ9àJ a=%©2(G‡„§˜¥eÑT¹^p»õ/·Ò²÷ÖDÑ8ˆO›uløX©Z™€»¥dñ­´‹`nðµÆŸ#a«Òþ‚ýY¾ pÍ‚Fb“•Ð2ÑfÓÅR8™Šˆ~~E>hz¹^å*´n2\tP½k•7O\—S·¸÷-¯4oñéa7Ñ9pK¤æ"cA&Ÿ¦ AiõöÏiªºÄqÇ"áºeÇ ˆu™±°.³çX—1£a]ÆoÆSlL<Áã©ÀñºÕ©zŽgµúÅÕf…„Ì2bO 9|ÞVÙÕR>c>¢Çh6¦•!ÁckDH-áÆaÚ¸ª­ÐKt;5AQªO0¢Ã?žÐ{€×­¶Ák¶RŠe¹šÐõª¡TxJå’µ†ÌSe,½xoľ¸"€O±^±&ó«S½xVÝEp‘:EÃXsÁþdD}XãÇúÒ¬¦iY Ü—h¤:š+¸QÕþè•£ ÁˆCŽ©Ú7 R9ä´æ)NÝâÞ[´¼Z¼½K:CC¨&;B}8Óê´³Eás*’Ø$zšjš1±.3Öeöë2f4¬Ë˜c ß=æÉ'Z„48òâñä­DÊTjc|Å÷xѰl[©ÙJ§gôÙ6†¸V5X@)cwU›ÈG5ÅZ± ª2¡¨òœ¨r8´£Î— d‡ÎhD5‹XZ†ˆ1€D“˜OSH0¢|"›ðVÊ.´(åìa,,BB+=ÊsáijXß0]±/<%1°Ï:Hê4ö‹„®Kq¤…Zá‚3œF+k)‘¯õ¸îŒ¥l"›jÛÙX#棕†ƒåf_h«š€½—]/^£»–™¯uDðqó,° è0[q qö˜™®ÀcÊRt›`XgR¢qi ¸%˜Ê›ŒJÓpâ]þ`–dùé½EË+æ£m*ä°£¸@sn}¨ƒ¶p‰MhJÄšq?àO¹+0'±(ÝQEÉž2« ÖOaDÕÌÈX— ë2{Žu3ÖeÌ1Fî q‘ÊCmŒÙRÙ²!ÏßL)V="%ËŠoK›¨YF€ ÓD±GÊ> NÒ4® öQtTΕJÓTNSø¥'7bXó‰úJs¥ü2´Óx‘P-•¶¸HE‚£C*cc —fÎ3Œ°~ÕI*zwE9·È‘oÉÿe{Cù©~v]ŽB²êÑ`u¤­]¤ —©º@`e-Z¥HMh©´¹è—vJçc/åî’Ø_qBЮª¨ Šb>ІIÃÑ’á"ædFÇ÷Þ¢åÕ²íÝAž—ÛRhc#•³¡Ò¸@–Ó+”‹[Šׯ¤3&ÖeÆÂºÌžc]ÆŒ†usŒÑA6…ID'õtÒíè‚–‘Rh¤ütÔ&*­åuLOE,ý¤©2_C®: 7ºË†-äs5S¤š¢…[)ðò?.\ß7­ZôDN«•BÜê„TѶœW…꜀8ÏÕ™Ð$§¨µŠFTÝ Ê1ÙÞ¨®T ZHö¯Ñ²]¤îZŸÂXf™™H¥\´?‘æ¿À«hÓ»vëã0œçr>û‚üªc´†”´ m˜ÔJ½Ï ÷Þ¢åÕ²íÝAžW m‰•n²œ¶ßªš±.3Öeöë2f4¬Ë˜ãÊœssõ¤«¨·Â6 :éÀMƒ­uL¯F ²YëªÐ`yRoå+8iEøÕ é Žª1Xk ÔªÌk*4Q2Õ;}i¼­¥œ³I²™¢&ÁÑ!¥OîDTgr­WçTV8ÿËöFë…P…ÒT/^#ÎaE¤ÜE`Ί/³\ŸͦV˨öÅ™D¦ÜK;­ÒÀ5!­ùo¹­…‹ù-­¡ÅâÞ[T½Šù›ºõÉó4Ÿ:›+Ý•Ÿc¾¦bþ3ÖeÆÂºÌžc]ÆŒ†us\ÑA¼uâÕ³øœH u¤¦Á”)ú–åp:Žw Á2–hå«‹ÖÐZ [LÖ¯N3ñ7ª(°ÔTÄÕL•…̪#º‡Ô’HЊ’‡&—©t£dÒˆXÉÙ•5-¨¯L¹3#l•Æu­ø%¦Xš`Í䛜Yu4ϨP¥ÜEùefbed2'9ÑHQ9­ŠLÅO‘0úàL¼õazËL Ï[ÒÚÕ|e¶¬%÷Þ¢UÒg‹žò[Ès4LEbÒ&wZ²Ðš}Œ é¾¥ÿÓÍÜ^¬ËŒ…u™=ǺŒ ë2渢ƒx:ÝF€•™HH@GçjÛÖIÇt¤ªå¾Ã«p‡t!X©r+P­¡µ¶˜¬O'Q­Ìœ“4ò|2EgèRk¼ZÇäa‡þ2Íüx‹ŒL~¬@ÁØœ èÓ ýáhZâwäÒª{C2¡Zëý|ÎLòMάºF´6'Å•’µêò‘–çl¤É‘ΧúM+ºÍ5å5UŠ»ÇA‹ü… É A>+$·«ùإ̌[«ÃâÞ[¬äm„«g¬<Ÿ\ñŽM.S²Ð™-"ÚN*¡f4¬ËŒ…u™=ǺŒ ë2f— $ÀY“èà® šëk<¿vÌòXœÎÍÌDêD::WÛ¶Nê<¦#U-·Ƥ©!z!zëƒV< .ZCk5l1YŸN¢Z™É†}uÈóT¡$êš·ÖxµŽÉíe"­‘‘É~ûÝ%fšÕ´D›j»`o`™3¡Zù…d¢(ù&gV]#ZCÂEŸ»ÊZg>Ñ„u¢‘*²Ür229ÒùHþSwð„Æ)»0€G}ª‚õñȧbrBZ£š¿ê÷Þb%o#ô¼œŸò|rÅ;6¹(ÉBN.„ÿ鯄§Ik3Ãb]f,¬Ëì9ÖeÌhX—1»$(uåÙ”©u:_€â›ì:›åO'hÊ«çl¡áW-WV†„ЇòØ–“ÿ|uÑZ«a‹ÉútÕÊÌù½€9«YB÷Zãm­c‡¾'XÚŒ¤/•”è“Qoj¡ÊýáhZ¢`!—ï Œý¾ƒÙK;HIšaQòMάºF´ÖŸçYël¤–çl¤É‘®„œ¤ò¯VÉg}ˆ‰ò·¶e¹ß&'¤µ1ªù’çüy0i“‹˜,LÎ  ÊæH¸gFƺÌXX—Ùs¬Ë˜Ñ°.cv Ï©ô.ð”qEç$º*:ˆ#VLE‚çÚtn¦“H1jMèÝét¤®ž³…,Wc9'A\¯Ž‚“ÿ|uQu´¶˜¬_fÎïT'gº‡ÔúfB äa‡IO挎»½cD¬äáÌÊš–¸ 4®5÷ÆëW´i“œ™”)gV]£9ó\"k™_`Yf;­4ÒÖ ¯„¶çÆ£xÇQ0G‚]yO›œÖƨæ+³3½‘Ž·hÕŸ´Ã œ¿èòþVª_\À+΃¶_œ·Å½·hÕŸ´ÃejÍR•8"ظˆ¯¬I›œ¨8! :'Ìä|꾇E HÈTe3,ÖeŒë2ÆìlRÒA‡æàXCx´Á+°‹”É:ªÀ$:œ©uzÓy1%Øg…™èÐ{aHI¥:F³!¯‘âaQ™1Å ˜·Ò*h=©óO¢óÜrn°STH­@«!S{DOù„ÃGêÌRšíÕ”pÑKÿÙQ™¯.Z»«Õ°Ådý΄À–¶F—šèÕÔJ0Xª« D) V=l¡iŒ)mu½« .ÅÊ“tŽ!ÇP(b,Sµ>X¶7:ËQŽ‘Ë]êÅk´ê.Â蘆1¿dÁþ„ñjdbÎÕu9Ãj•vÑ$±»22³Ê™,™œÖÆhåý9(òcýŽ·Xà-©nï>Ic:Þ˜´ÉYJ»:'ñ=†2U_Ñf@¬Ë3ÖeŒÙ8Üà°‚# ‚D¥ÈÄ9UYzɤOBx°†ú:*ñȥؘÃwV™«éÝ|'@"õÅ¡réêxhÎ÷:ˆãé :¢}â‘þŒ9¨¬Ó›(“OUŸ½£(ž# Såú€¶1“ m²°)8ðP¨¬\jE,¦ b[TÖ´” õµ+Èït‡`¥ ü zŒnàš>°Ii°ÕÇ Zá_ßÃ’Éú(B…Ö„`†Q¤qit˜ö2Èi6:ŠQ‚¥Ê¸Ö"r-[$ªÍ1„rtÈé ­—/ZÃDée˜€‡˜“X¹_ñÞ(½BMo¤¿¯ÑJ»£Cèì±`â~žšà)ç\]§F)ª•wË9ÀÚ,רGPÞUÈä„´6FÃ`Pð-ÎCµ‹Å½·Xæ-À2¡´:° ÐDcÄuüêÖ¤M¡ªÅÌÖœpJ‘¯îÚ.¾Ÿ˜Ýc]Ƙ°.cÌ.AüÃ.Î.)ð œrxЉExJ IJ¨ZF‘ÎÖeÁY ù8c)‡ªDYs&­Ž"(E™Â=LçEÎF©ªT+Ö§Fú°c]Æc†…÷O¤ª˜eŒ96X—1f ¬Ë³K:ºL•Rw`NùV-'¤Ì¤ Q6/e”5u4¾Y— 33…ª?åüÄüò}HƱGúPZìq¦{Æs àû¸õ­úI c̑úŒ1a]Ƙ]"µ"åG®|LJ”ºCK‰@Ni¹T[ØüÔ­€ÈIÍ‘™Ú® %Ø„©òÓ@€Pšò#œ@“?ÕÙÐTphD(Šñ}Hê£)ßcŽ+ú[P½icŽÖeŒë2ÆìI)ŸÜwð+¨RT ªJ¡Ä /ï\záYVŽŸE¯ÚWŠªU‰¤ƒ¬ŽõÔAÐ/K}:\>ôËl®”ü©Î'¹“4E€>TçÓºŒ1fßàMµüL¥1æøa]Ƙ°.cÌ.¡d€ƒoÊðˆ1ª‘Rw¨*$Š ¬†5Àü ·~(7k®¯ËK·~jÖð¥¹>.ž?‹|$4Dsú¶àó2lX+Ó‡”I¬Ëcö â¸Ù¦|c̱ĺŒ1a]Ƙ]‚øŸ’AÊçŽÊüRw¨*€pžÆÅÉ[ÿR¡ü·l?AÓbSº yýÖ?‡*?«R ÌOoØVý©ÎƵË/!Es>‡Ï¾¬ËcŒ1f¯°.3ßûÁמûü§¾õÝK)ßì ÖeÌhüý__zéÂüèû¯¥üãAK—i‰ ¥îPU"-L .üLMúM•–K‹) R)…ê«þ´fƒùsä'úPZì±tÏcŒ1æ¨c]f,>÷'çNœ8ñø“IùfO°.cFã·ó×qSzõ Rþñàõ[ÿê"}’åÜ™ÓÈDQ̼ïÖ?+£ËÈZ=~é6ÕD¿&+šŠâLP;ÿP©ÃÅógÓ9œø yæÄ_á%cü¼ L1³ªË”Ò rÒr¢ÒÀ­ËcŒ1f±.3O=ó$B G{$å›=ÁºŒZ!S>ÐH«Y—1ÆcÌ^a]f,¬Ëì9ÖeÌh{]æ/?G-é®;ßpñüÙ2 ×—^x–RBÒe@)‘ðƒ04ˆúäÂÓgh3 àܙӴsÐÕÍVà¾âËMhëDIex(„Íñ´tûÔ÷ª\­æãO1Q¢^X-E#H¸IgáüÄÖeŒ1Æs\±.3Öeöë2f4޽.C®]~©ª0¿Ô/&¡¾ •GÀ%‰”^¿ú JA_pa”9Ÿ™]T‡<³k¤Õ§´eǺŒ1Æcöë2ca]fϱ.cFcOt™Ãƒ¤L ÏѤ|C¬ËcŒ1f±.3Öeöë2f4¬Ë,㮃/ì¤ï"]záYêé >Fh~žøðÃú´Ñ¹3§ñôäÁoâX—1ÆcÌñúÌXX—Ùs¬Ë˜Ñ°.³ ý ?8ó–ƒ_êÅS¤ò7YCã“Äߊ/L˜4fb‡YÖeŒ1Æs±.3Öeöë2f4¬Ë,æõ«¯œ;sú-·þ·8õÀ½—~üŸU¯ÉÉ»ODû-Ž.øë3@¿q£ jÆcŒ1Çë2ca]fϱ.cFúŒ1ÆcŒ1[źÌXX—Ùs¬Ë˜Ñ°.cŒ1ÆcÌV±.3Öeöë2f4¬ËcŒ1ƳU¬ËŒ…u™=ǺŒ ë2Æc.ž?{ä~G|ámð×å÷ Lç0峬ˌ…u™=ǺŒ ë2ƳŒK/<ûćú)ë£ü÷ÿDkqîÌipãú•”¿ ؉?v>µ½ëà¿×½åÖ?³3«‚©ÃnV—9õÀ½0{òî›Ú!æ¸b]f,¬Ëì9ÖeÌhX—1ƘUá§KtŒKˆÍލ:c]¦J\èMÍ 6 ÎO’f¬Ë¬ÉÆu™×¯¾¢âÏš™>ÖeÆÂºÌžc]ÆŒ†ucŒY‰SÜË0 !9|~?àpT°.“@¼”MÍ ¥•’u™MÑÑeÎ9%¾xþlÊïu™ OŸI¥ÆD¬ËŒÅçþäB ÇŸüHÊ7{‚u3úqSúò‹çS¾1Ƙ„mŒÁâÛã—^xVñöQ ›­ËD°² ¶u±©™A$Ïo'E´yÛ§" ¶ÖeÖ¤¥Ë`’¦ÉÜb· Õ©îMùÆ$¬ËŒÅ÷~ðµO~æcßüö—R¾Ù¬Ë˜ÑøþkõçôÔ¾ÿZÊ7ÆSãçTtãú•£ûιu¡É`5±Ž»™í«¨Â”X—YÎófucfb]Ƙ°.cŒ1ÆQ.½ðl?xS ä¢;ë2A;ÐǬË'8ÏÖeÌmÁºŒ1a]Æcn 8v#¬"ˆ®SiäÚå—øCs*¾©Núaˆöq±ÎÏÄÆAN×襯_}…OqÁ&­ulÐIÿoÑJó&k—ãºïž“ ÞÐ6d…2ðë³x)¦^Åü° Ž4½¸¦ç¸PÍ™ÄYÅÌOú÷Cßgþ뢸Lì­ÿ}÷7O =ÂÎâ™™Ïb]F7ŸÖžO`¶Õô»«²ƒE™ô£@~Çy¸—œ$¥.CSèñ`úoÎ--Uë@ e_bÍ 7Çë2Æ „ucŒÙ1ÏŸUÌ£„s9ŽÈ©&rö¤„ÌVÌSm‚îªgtdVÿ˪ÿÄaÀ}÷œ¬ºÊ "Õœ<âc‰mMÅš›r’´æ§úãšÕ•B‚…r±ÈŽÇ%÷:Á•|˜€­¹”qåLjÿκ+'0˜a>mMu•ê¬Â *Õ$ÕÁ"§µ ô pÙˆmÑ$ÖÕ͆œ•FT²lfVEëØß6 W?mx$Uœ’•É3B… Çø'æ+ÊEÃøé}~"}X#†Ä©ˆARt¦L4„YeƸ· xXƬ€x rÐx7뤚ÀfŒmpMg⊠’de¤˜d©”v<.ÚÁcÊÐ%¤4*ô5,¥*¨-®™‰T :RÑVß%)?q3ÇmRõxÊq©&P/¸Pï :€&qˆÖpÁ¶X_¬cÜT €Q!ZÀ$Èø|Ý!¡M2f ?1ºTá<(É%Œ:N£ê •¦…—mâ1M~‹-- êÈàäUZÓ¥A¥|6Œù°#ðäÀÞÍÞñT¨Z‡Ò&Xi8fO°.cÌ@X—1Ƙ¡@´Pá ã|Ä'81ëi„Çk¤ëâ`ÍÌ9ñâ¬\=Ž«tŽ)Ъ¦H E@a R ÌÄfԤŠ\`æã»úr¯Ú5zd)l¦5Ú帤±f9½‘þ®K¬¹”åˆZ½c˜ƒ¥d£I@šã6`pŽ„SÀ\Å|­ œWfDƒJ‹¨^Zm5WÕ l§tòaæÌ,C3Ð×8$\¤W‚•&#šÿêk»¨SZ²¥E‘“¯D09]´Ç”φe¾^Ý­u¨Ú\i8fO°.cÌ@X—1ƘÝЉlWEoüÆ@ÁI5ÚOô=QHP qW¢u(ŒéDtRqàJ•;¾Éÿ4Û»×ÌÈmSa<‡ÖYʪ}é/ÉIíá¨EFúfK8«H¥ÊS"ãկ؀(Å|M&ò[ih­X½ÏqµdS ÚGNÆ›L‰¦½%w²4¹Jãh›dMA³iò[liQdvÎurºZ#ÒT¤ü™¯î*U›+ Çì ÖeŒë2ƳôvåÌ7;è„cãqï‡RŠ9[!1`± $H´¢å·â¨Í:yòÖ§6æ¼W¬kt­fROv9®™‘›v .RÑJhh3ó æá óì$[!µöêJn«—–‘™ )ë Å¥”W½ÑŸ #U-c’•ff1“ D8Kiq…^&ÉÕ~+09‡‘--Êü;*˜œ.¹t å˜zïÌR‹ªÍ•†cöë2cqùë_øÅ_zÿsŸÿTÊ7{‚u3/]øƒýþ÷þð;¯¦|cŽ:kFSq˜&zï7¯¥>àä}_ñÃ4Bž >®«Àí¤¶sŸ u´ò|¸é↜dwHiƪ̩Œ"ÖA嘿Ëqɇ~MíXNE“  ÑÚä9œ4QÌì´‚·¨€4ÇmMEê¥ÊÌÊê+S^ÅÌ„††ÊUô:Åuj;´Z§ùLªÃ/©.®ÐTGW•Ù™"šEê÷NP²ò²EQ&vî¨`rºä@ÊgÃ2_³ÔšÛ-›ó‡cöë2cñÔ3Ož8qâÑÇIùfO°.cFãÝ›ÒËÏ6åsÔÑÁ}ÎG6Ĺ3§Ñgú2•1€zaÂA¼ìÇañT*Oö-^¿ú âÔ¯ºZÚiEb³NÒ+<¶¾7ae¤N˜§¨)õ¾Ëqµ|HhKt>MÙøRÒª•™Vš¨'·På9FÓ‡8’K Í[t@uö‡6'ÍZ‰|XÖ|&~g¤ º¸B[4ºªÌ9©ß;Ùê¢h˜ªwT09]­ φe¾f©5·Z6ÁÌá˜=ÁºÌXX—Ùs¬Ë˜Ñ°.cŽ+“÷ªÅ34ÙxJxÄGªšÂ9;6DÂá;VPmV™ø¡G¹„‹ÒU<¦&(ªæ‹Í:Ùr£ +#uVJQS² ÊÌÈîÇSìqÎÆÛÆR²!ª•™Vš¨9ó°¬rr)Áq!E›jÛ™L :àU9G%,Yi°‹‡ì¥¿mª‹+ô2‰®Æ×Žf£Ê• l{Q&ï¨@Z>Ð<¦|6,ó5K¨Š&iÙ$s†cöë2ca]fϱ.cFúŒ9® Æà!xf4¥@¢üÀùœ8äÒ ÏªG¤xòVó™žôѦ Á`ŠjZB?r›uR“Ù™11§r+jº]ãê|%aN²¥¥¤i¢˜ÙiµÒD!ÔdåÔK•™•9.¤¸ äUgoLmMVš™ÅT‡_R]\¡—ItµõÚYÌn¥sG“ÓÕr€ Ëüuf©e3Ҏ٬ˌ…u™=ǺŒ ë2渢à¡óƒ¯B_µÀÑ99qÁá›ñ’Âò•<™zZ«~M¦!LF›u’Ý!aBRQ‰*#€OEB±}5<Ûý¸Z®¾¾ÊÛÒRÒT+3‘Zj‘& ©¨d¥ V•ûsRõP^u^zlØ7¾+ÍÌb´µú7¶5íšêèêJ‹5‡].JõŽ ¤q´|h9Ày.ó×™¥–Í’ÖpÌž`]f,¬Ëì9ÖeÌhX—1Çœ€yüs\V¤Q·çÄ!ñª¼Î‰¿D1@õK­a2rج“š„ªÎ•˜SYFZ ÑÆÕør~³K‰"THãe+¤–¢¤@w¦úÀ^ZÎ'&+#F=èÌœ™eh‘ÎdZ\¡Ýž\ÕüÇÌÅìxQÊ;*UM5[C¦ce¾ÕÖÜvhÙ¬RŽÙ¬ËŒ…u™=ǺŒ ë2æÃs6ÒÅógSÀ±Gd^÷OùŠ1朤«Çny²~”"gÊ·[D#‘ :E±j(~áé3Z”“WßCŽÖRÑŽÇ]íˆ)HsúÚÒR²!ªÅL F)ŸH”Aš©>Èy½ˆ"7®_‰Ê”dµ–\¥ ©÷9öë¤ÏRm ùП¬8*,ÞcšÏþM¦º¸mi$¹ºªèÖG²›E©ÞQµŸKûxaj2Wzùpn«E}:6K¬Ëì3ÖeÆÂºÌžc]ÆŒ†usŒQ4‚sŠ—Z SáM+jG|¤x’F<û)8ÇSîc‘ì—žd–Öª(‚M!.,°k$\Ä"0'rØ “@󆋨×\—"jPè:…+q\eT¹ûqÉÕ4®ׯhÈe¬XeKKɶ¨VÍGJÝq9”f†î ¼‘0é}E1¢Ãª5G”ƒš#Í|š€‡Uýhò¡33ìª{l ¡?ÒÖâ´¥‘ä*ÜÓê§Å"ØÉ˜Ÿª~]²¥EÁË5ÓËOé9c‘ò‘âˆâk ×*"ôªÌj¸ê Vm®4³'X— ë2{Žu3ÖeÌñF±ŽÂx tþŽñ³2QÀ©ZghÅ8DgqIõ‘Ê PA8Ú¢[!¿j¿E qÕµŒËáÔJÞ¦üĦœ¨¦&¸€5¢ÌMÅ(‹•1™ÌDÂSÕ¬€&)?±ÁqÅ—®’˜93âÚÒR²!ª¥|¿i÷ ¡NrËÁkTK [`EØ©4ˆ‹XsÎ|$VFNª_.|î¯NœIØÑdÆ.p‘Zµà®ˆÈr$®2Üc¤ù{lÞ)úEÖXäFéƒf F°vœ"\p8ÈŸé¹LmvQ8±&};0ГóЖħ¸@óÔª•d¥´€‹ªŒ•¨ÚTæÌá˜}ÀºÌXX—Ùs¬Ë˜Ñ°.cŽ7ˆx>.ŽË±&b šcÂaZFŒCø¡æ§„&ªÁY¼Õ)ùÓ¡Ú5rxúçujRªlÊI€y«šBf–\»üRk¥ªõÉm¶AËUä¯ô6ø6–’Q-åLÂÍ~<¡>?(Á†è76écã˜Ð{´Ã2»(Sµ>à$ UK#Ølœ™jB¿˜êÔ¤EÇNLÑ%\æv¾ºƒ:í´³¸@nTQÒ[5Áfù}º*[Z”êk©uG­geÁ`¬ßÉQVš³šU› †cŽ=ÖeÆÂºÌžc]ÆŒ†u³ <ÀQ§g‚è´ tQ54ACæ#7®_QM€s<ê#¤W“Že‚&°£úÍadfD$`}É®)À]•º¨æWÙ”“ñIœ"Ø¡«U0áq\“õÇWÜ-+¯6»”,Eµ”OÒk!VcÃUG?£ÿýyÀÐÐãüyC½J/½X”8:ßVÑÅógÙiŸÔŠãjMû$ê4å'X§Õ f‰:CNóPRa‰loQÊíšý—g|ƽÄù,' 9t>å TPïeó*-› †cŽ7ÖeÆÂºÌžc]ÆŒ†ucŒ1Æc¶Šu™±°.³çX—1£a]ÆcŒ1Ƙ­b]f,¬Ëì9ÖeÌhX—1ÆcŒ1f«X— ë2{Žu3ÖeŒ1ÆcŒÙ*ÖeÆÂºÌžc]ÆŒ†ucŒ1Æc¶Šu™±¸tùE„@ŸüÌÇR¾Ù¬Ë˜ÑøìïŸyûÛÞzý«_LùÆcŒ1Ƙ`]Ƙ°.cŒ1ÆcŒ1{…ucºŒ1ÆcŒ1ÆìÖeŒë2ÆcŒ1ƳWX—1f ¬ËcŒ1ÆcÌ^a]Ƙ°.cŒ1ÆcŒ1{…ucºŒ1ÆcŒ1ÆìÖeŒë2ÆcŒ1ƳWX—1f ¬ËcŒ1ÆcÌ^a]f8.]~ñ{?øZÊ4{‚u3?úþk׿úÅ”iŒ1ÆcŒÙÖeÆââ_~îĉŸ8ûxÊ7{‚u3䃸)}ýåçS¾1ÆcŒ1f#X—‹§žy!У=’òÍž`]ƌƺ7¥—ŸÿlÊ7ÆcŒ1Ælë2ca]fϱ.cFúŒ1»ä/?÷úÕWRæÑþc)s(®]~ipÍp'GR…U¹qýʃ,:ê÷c̪X— ë2{Žu3ÖeŒÙ'ï>qÇwÜuçZÛø\»üüÇ(0–T4ÏŸå$§|coyó±UbZó…ÉxLçΜNuЋ¼EÙ7¬ËŒ…u™=ǺŒ ë2Æì ÅGW—QT‰±¤¢*ÏŸEü î»çd*Ú7®_¡lôćNEÆ$¸UðˆÍLúŸa¹ðôÔÁNÆ6KE»N¦^%•}h]Ƙ½ÅºÌXX—Ùs¬Ë˜Ñ°.cÌÎP´¶?ºŒ>A°›(1óÎú2Gê2svòëW_‰Ÿ…™|ýêeb]Æ#¬ËŒ…u™=ǺŒ ë2ÆìŒÍê2§¸wü}¢Uu8¹Rýuà7˜ÊÏæð“àÿ¨ÇmÙ‘k—_â$c!RÑ:lÉ,˜©Ë<ñá‡YSi]9,ÚÍ'ÈŒ1ã`]f,¬Ëì9ÖeÌhX—1fg dH¶]†±âŽßu_U—ž>sîÌé"œ^LHÙ×fg~LnË~ˆHq(ňuØ’YÀëìäK/<«ƒÊ¬´Ž.£ej}Ês\±.3Öeöë2f4¬Ë³36«(ÀKù[e.³BwÛìÌÉmÙ‘c¦Ë¼~õMé©îEÎü]ÔÒe.<}†ùÿì1f|¬ËŒÅ^é2ÿÞ#œ~èÿø)Ÿ±.cFúŒ1;c³êÀm‰Ã‡Õe½WÛìÌÉmÙ‘- ([2 8c­Ì­~òî×.¿Äœù»H/“ä3-øLÆì'ÖeÆbt™/~éÿ&ýÔoHEûŒu3ÖeÌ1æâù³ˆ‹:áܹ3§QZþ/[æë=íׯ¾‚§ˆ©HY?úü±T×üËXëÐ 5ª!Œ\záÙT Q"¥8œOIYŸD˸˜¸ðô5A$IË 8‘+w c n[ù°^Rwó©ªcì…s…„)e('aæäG#xʆx,› ¦dV>Ör` 4'lSeûa%8-r.Á±X¥è ç$ã"úk’4®Ò YÕ,˜3c‚3†j)_¤×)jÒ“eº |C:õ7˜ŒÙO¬ËŒ…u™=ǺŒ ë2æ3G)”MùlÈ€ Á!«Å„œVÄ‹H¬¬Sð¡åBkÄœe+&Ä™±²ÂÔjBi¬ ªþ#!³ ø#Wc:õÀ½ 899“TTB¯˜1²ZLià}8‡ð*~Cc?´UKp@5WZÏQD# ¹•Òäô—Œ Ä&Ø]Õ%@wX…XsÕý°*ZuZ4Fx~˜ÕHqh˜ÉÖ$§I[É,˜?c‚ž¤~;È~ë~"ªÛžÂÜF”2cÌQĺÌXX—Ùs¬Ë˜Ñ°.cŽ1“q3<¦|6Ä£ôÔÁSÀ&ÌI‘!`¬Î”šàQm“?¨Ã|T@ #@™H1°DQ4…ħ$Æ UG–c$_J37®_Ae–â"I^á"5¬2©Ë0XeÔRÙj%ÃZ4ȧ$jòùœ(e"•±=* õ¥þÐ,.ÐPÕd4µ 6‰õÁÅ[ÿX ©Ú*êD(¢!ñ)A©j.(›è”ž`~h\Õø¨rDÕÐV4.Zc~šY`©ž’Xs¥,Mv@MZ[¦Ëcöë2ca]f}9ýxü÷Žävt#p¼KùDé/c‰}£æð㻩ƺŒ9ÆLÆQ ÌRŒÔ ¥ñÎŒ;‰Jc`^¿õC¡H1ŒG~4ˆTê2 ”Hô)ŒÒCÐr^Ä :õHÁ¢Ú¬ZÅ?és7pXE:ªàcüAôA™ë ùoí„K€©Šü1iš75OºÜ`«´…‹’?q#Åé"lUú¹p6Ó¼Á“–P…T®5A>L•¥š ¤¸åȤY æ f R~ ™jí" ¬ÙñÙ³oX— ë2krÔ?†ÓÒeô'§„˜¿Yt¤ØÏƒ‚Îvóaû€usŒ™Œ£˜•7^5DQÙ6êü”/5!áD¥HÉf4’è ¡å¼`PTF¤@·Ä¨:Á™-{DK‘fÞHÑ„õË¿;ÑTù‹xÕùUéL#Y°š@¤êŠé¥ýS·>Ê””™-g hï•‚Ž.å¯mÎ\ë¾ç}4eÛI³ý “36st`r‰Î¶7Æì-ÖeÆâ“Ÿù˜u™u°.³:RìçAAG·ù‡°}àC¿ñ nJ_~ñ|Ê7æ0GµBY5,?@AT!Š´†T¾çOTa2®ºq•MZÎ),­;œ<0ücôùŽ2ˆ%/+´Ì&:ªü¯j"øFþ`i½æÏ¼h-ò;SÁ~«k¤æq MKÌŒ´*L6\€lÎù©Úu–¬³O&ÍN¼Uù3w2˜¿‹:Ã1Æì-ÖeÆâ[ß½ôèc\ºübÊ?~X—©b]æ6¢³ÝüCØ>ðõ—Ÿü#üáw^MùÆ&ã¨VÀƆ²î'ú6Gü¤‰ª%æÇuB•MúÝIaéÜðK úPO „þZͼ‘ª~é{oÙ™ãÿ|̼h-ò;ßíl$5Úߤšd3éYlXík1úÈ:­ÊghÁ’uöIßìú3Öi˜ ¤É]ÔŽ1fo±.c6Ï¿t¤ÌÄJ ¾ö7/§ü’•Ìnx59Ø_¹ò"ÚâQ9GQ—o`ò@Öm[o T˜¬Ó‚î¥Ì*:ÛÍ?„cŽ4“q³òÆË†²TÝOÐEÊ)™ô èÜÁ¿& ŒË&-ç‰îx¨€~«¨‚Z)³åáœaFTþ¤"úß²Ói¸€ÉqEPgΠ¨ša[Œ´ü*³ñÏŸFÝY5ÎRê—ùxŒ™k"Õƒ–ïëþÿrM.RQ œÇ‹ˆ3 iýC…˜Ù5«vJäUÕgcÌ~b]Æ,ä+W^ü©;ßô »øÇŸxÓ›9ücƒ‹·¿ãç>ÿŸV“Ȥ€‚†ï}߻؅j¶l¾ö7/£kÂÊHÊh•š¬  ›r±GÿS+ÿÙ–~"ášãJº N<:7V=8"œÛâëy8îÐZ<]© P¾/ŠƒŽ_¨›øÓ9“± ùŒ~ÕEå©ý² ë° º$Zgä³~l[­|ñüYšŠ•e´~ÀsÔÁ œ¯úVÅÛS>–ùBqj¶rJ:þ 8ÇÍS·©2•MZÎÜÙp2E “36g˜Õ/ïÏô¿e§Óp“ã«.f¸cSÿ'į•ºѨç¤ô~F?,.iö˜ð´ú!MHgÉ0 <]°f™Ê¶}³ëÏXZ‚š‡ÎŠyÕ™ c̾a]Æ,DÂÊ#§ÂÓ÷¾ï]|Z¦³ÏünlH:ºÌkóòÛßñs,m¥dSÖZ©ìe:ƒ©Úi¿í½¿ø¾¨ËLž'6rÀJ'ª2ÅsÃëW_ÁÁô° ‘⇮#ñP¨Ã+¥s̤WLåéÒ­#RM(JéH×JóÏdƘ£ÅdïZ6,ó…îÞº”9%-pSÕm ¨vê{qïº!—Ch9Ot냚jÕö–‡bÎ0#ªŽRýoÙé4\Àä¸,Šªù uM³@!¥·:4jÔaï-Ê?Ä4‹Ç”¿ÐÂT¾¥¯X„‹TD0:0#ÎF>/CS-Z37R~ Í@żB¿©È³·X—1 ‘ò«þ›n}Jå§î|Ã{ß÷®˜ÃT~Â¥£Ë–ù·ÍÃÿã÷q‰¡­ª%ªþàvª»SùéEÝ“Ë!´œ'jˆ‹TÔarÆæ 3¢ú¥ô¿e§Ópýq-[‚V~Dud_ .%QhÔ3§7Òß[õ÷))lkÉ´ åŸÝÎr÷Í®?cóÊÿΊ“ÎpŒ1{‹u³(¬ð⑃Έ³Ïü.ó‘JY¤¯Ë Qy!h¥îÞ[û–PÇìF€Kr ü¤™?üãO¤"€±J¡*N×åË—©Ëý ßê‰JGŠÎAEð¥ò'yˆAªj*eB}l;bp’cÔO‡uÇŽôƒT:€¾4Àªž…A±tÁéÍsÑ›ðéV#tÃIù¼™”ùBÑ©n§Ší;­ªqnMðV™B¥åúÝI9ªÞ®[”ãJÀ V˜y#UýÒ ýoÙé4\@uæÅ²%håG8Fš½ô³hBZM®Ýú'Y]Ô¢¿6ˆ¶VZ;M.b>Ñ‚VW\¥eÛ¾ÙõglæNý]é dz·X—1 ‘ÂTý²’”¤øë¶ / ”ŠŒÐÇUÞôæŸME`ÛºÌã¿÷íW?€#m¥ê›ý"OBŸ¦y÷»ß=¬.ª‚QS=ÇðˆÃÔù¤>^u£ ‡E­ST|Ï3}L67Æ3ôª¯Þm¢FœŠt·,?=At«‰š2ËÏAÔ¬¶’“ýßìˆM,'ËâU…Ü­{¸nÑ3o¤úëV.g£e§Óp}…nÙt–†hå7h:pZðØù[\¥¿6Kuí°ío޶±dšªø¥Ò²mß,XhŒ9êX—1 ™©€è«=é#$GT—ÑpªºŒ¾åTö.A§úõ+ñÓ?}'êüÌÏüÌÿç{ߎ/Tý Ç)!æo–ιg&}?yÄAê¿7¨jÕ“M+ŽŠÜιVåò|¦¢ù‡0cÌQG7ܤënÀ„:ªOt·dBà§ÛŽ´c¤¤wè6…oA¸­éöÅÒx÷ÓM¥1?*GHå ]°H}!®‹bŠ>h€TÞöQ™è"}ºPfQ$kZÌÇãÌ©þj”ôít. þeáRâQÑï²%Ð.*—FhÒ”`PÀ™R2Ã.U§h®GðÞVª/\0'í‡UÁ¸àIòîµ>ôŠjôêÞ¦R$e8‰á0©\î¾Y°xÆØ E)_À7L‚Ÿ0¨ÌÔA>k®´{eŽ¥"cÌ1ÀºÌX|ë»—>úñG/]þ±¯üŒÉLDzÄñÐeôͬò7}ÁçÿâÓ,-¿Ç$A ád ê2Hß¼ücÈõ'|«Œõ'ñ1·ï§F¨–Š"r£z^Ô_é£Î±k\·Póò¤¥3tY´Ï\ýò ¿ÿÄ¿ûÑ÷_KùÆôÂGÂ݃ð)B8ÞŽ“Z)_±nj‹¤è7¢[Rj›¸éñ7«ØŠÝ!¡2®AlÅ‹ÔÈ’:BýX'ùCãÑ>R²ãg$ZVC\\¤ŽZÀ8–wh³e§Óp‚FTÊA±×ÌQQš(m­ri"jÞJ¨š¤sE—”_NËœý°Z9@˜Yµ,ÉI>h~ânLuQ]î¾Y°lÆX„j)_¨m'¡Nj4u+í^xÂVU›Æ˜£Žu™±øäg>vâĉG«ÿþÈP|qž"!#U›Óüì3¿ûöwü*$: gzµ)/°í{¯¦Rý[¥òC1r{f_—Áá'!ø“ \¤ú@¥ñ´T‚ÞY öSQ|×+¾Ôjf*OZ²Ð9„í!úqSúò‹çS¾1ÇDƒº±0á)ï0¼+–7´˜šesØŒõ#¸Õ´êëV_Þ$cäÉ„VçΜî4åÐJÇ²êæŸÚVÿ¤00!‡b:‹ð›´ÿeGô¼e§Ópå:¦®W]ýM©. ‘®‡ÞÓ‡/âÚ•*—þ0¡UUsöÃJ”‘Sþù&åÎAåX¡4ˆ§ÈÔ_ÿ™2™eUgŒ=vv2+ôSé Àú²t¥Ý+ÿ[ÓkŒ9ÒX—‹§žyÒº øÃ?þĤQm¸m]H|yÓ›Vÿw ý*]—¿[¬áà¢ÃOÿô?sFþSúäv5UýT+ '%T‡UŽÁCyNÒ  Í')£²Ð9„í!xè~Ü”^~þ³)ߘãÄëW_A€›ˆš/òq BD§Â{î$ÊQs\T¿¹‰Ý¥úè®u‡„l¢“& öUý"hRŽ:kª-£!¬M6ôw5¿c§Õp0±Qœa±ÒÀ±j¾€þѵTDÐ{,í´üÑâ’Nwdæ~X‰¸Ò~®¢úÕÊÑÃXûª³Ü}³d¥ãäwŽt©ê¤Vù+¿²ªˆ=SݙƘc€u™±8ƺÌüï1é'r‘Pú«þÂçÿâÓ¨Oú? ;Ó«uÐ7³˜Ð8|rª¿‚¬:Õ¦x%âõˆ„Wf|¡êOxëp¶¤zt :G"Á™SÜ‹“Î*­úÉ#j¦¢„j2áiÌÁui>«4ÍD¬ËD¬ËSRê2Ƭʜ]Ä¿}Þi·Nþ6Ž8ÃÀ2ÒªºŒ1æc]f,ŽŸ.?]ó;Í%aT"·ßï¶u©Bü‚¯™ð™Ÿÿ‹O§&D¿/sÔuSªúíû©¶}]FŸëÆ…š0á)2«ïƒ­?EÖeªX—1¦ÄºŒYŸÉ]„?vü#è¿J·…íM¾ucL‰u™±8~ºŒÄ‹$²´šÇp‰ùâöê2”WdÝ=þ{ÖgL þÊðŸaSño®wö^ÆcFÀºÌXÑߗᯮèà‚9HÕoý´tÅ\?rú!ðÞ÷½‹6ñ¨‹ÔÄæt†þ¤j‹IÒL5¡; 05ðä°ÆAÐI}ô£-u™¨zè`t×Fß­² vß‹nàE‡H "xÔ…š!õu{i%ø–Z}g Ý¡'9Éá°(5$òIïv´?X—1ÆcŒ1f«X—‹#ªË\ûÞ«Qqˆ ù©!éè2¯ýÍËkhÈÒ²!ùÊ•%p(µ*¯ z—ñ_}𤪼÷}ï‚WÑmT«þp”ªég~ægªŸ—¹¾ˆ®ÔÒsß­¯Åu™øK„)!ÿ/?ÇÒªcò¿¯Ë\xú kâ‘’ 9y÷ %4‚TULÔ¼“`*µ"QÖQªö²?X—1ÆcŒ1f«X—‹#ªË0ç‘ÓáZ¼éÍ?ÛúF øÞþŽŸKE$YÈaEVCð•+/¢4¶-¿Hµ )/­Ÿ:þü_|ݱN«SÔIîd~â?þ^H¥.®]~éäÝ'î _êÙÆ§èŸøðñ‹·Ô¾”êä°ˆK© V@çÚ’ŸðØ’oô37H­RÃt$÷r0cýO_óݱUüNÓb]ÆcŒ1Ƙ­b]f,Ž´.sìÑow$! /:½iõÛ„WbG—ÙNÞú“„ž*o¹õ™~5³>ÖeŒ1ÆcŒÙ*ÖeÆÂºÌȼýÖWôÉ*(e5ë2 ¸ëÖ§úßu².³3¬ËcŒ1ƳU¬ËŒ…u™‘Ñ—˜úߊRµÎ׸ZX—‘.sñüÙT$âÿ]*¿ce6‹ucŒ1Æc¶Šu™±°.32úRUsyío^ÖÇ´T÷·u}é®;ßPý!dêÃ2¸H¥fãX—1ÆcŒ1f«X—‹?ÿÏÏ"úèÇMùru™?üãO¼éÖÎ^•Ïÿŧaƒå¨‘p|þW&þq,mý0pŸeº ªvýÁÝ=ðçpÒ]?ÖûÄ­ÿÇ¤É áz—–ѯÊ}÷œL¦Ž䃸)}ýåçS¾1ÆcŒ1f#X—Ž/]ú³kw9eÈQÔeô1 S†ÿéé0«‘$â,`™.£Ï˜,Hþ> e¦Cÿjé®;߀!wþ©Óƹvù¥Ã¾WOð6Y;ZÜøÛ¯þ·ÿz1ecŒ1Æc6…u³Ét= ÿÞ#?Uüwê™üáBv¾råÅGN?ÄáG‰"U[À2]æÜ™Óþ—Ñù—ÛË¥ž=õÀ½ñƒ'àäÝ'0Ø]*2½§©› |N¦Œ1ÆcŒ1FX—1f –é2ÆcŒ1ÆcŽ(ÖeŒë2ÆcŒ1ƳWX—1f ¬ËcŒ1ÆcÌ^a]Ƙ°.cŒ1ÆcŒ1{…ucºŒ1ÆcŒ1ÆìÖeŒë2ÆcŒ1ƳWX—1f ¬ËcŒ1ÆcÌ^a]f,.]~ñĉŸüÌÇR¾Ù¬Ë˜ÑøìïŸyûÛÞzý«_LùÆcŒ1Ƙ`]f,žzæÉ'N<úØ#)ßì ÖeÌh|à¡ûqSzùùϦ|cŒ1ÆcÌF°.3Öeöë2f4¬ËcŒ1ƳU¬ËŒ…u™=ǺŒ ë2ÆcŒ1Ælë2ca]fϱ.cFúŒ1ÆcŒ1[źÌXX—Ùs¬Ë˜Ñ°.cŒ1ÆcÌV±.3Öeöë2“\<ö®;ß.<}&æßwÏId¾åÍoŒ™f}¬ËcŒ1ƳU¬ËŒ…u™=ǺÌ$oyóï¸ãŽ»î|ÃëW_‰ùO|øaä#á"æ›5±.cŒ1ÆcÌV±.3Öeöë2}.½ð,Å—“wŸHEà®;߀"<¦|³ÖeŒ1ÆcŒÙ*ÖeÆÂºÌžc]¦ÏÉ»OP—¹ô³©ÜwÏI–¦¯8™u°.cŒ1ÆcÌV±.3Öeöœmè2×.¿ôćÏŸME›–ÙúJEäõ«¯ô?£OÓøWf6ˆucŒ1Æc¶Šu™±°.³çlC—yâÖ¯lO­ào¾ ¡¯T´AN=p/{ÁE*nүϘÅX—1ÆcŒ1f«X— ë2{Žu™Ô\ª_b"ú*Ó¹3§S‘Y†ucŒ1Æc¶Šu™±°.³çX—iqíòKì¢õ%&ráé3¬¶½ÁîÖeŒ1ÆcŒÙ*ÖeÆÂºÌú|ñK@ʼ|åÊ‹óýYU—¹vù¥o¼ü\ÿW]–é2´ R~•źÌü.Î9Í.ú£˜ü ³*ÖeŒ1ÆcŒÙ*ÖeÆÂºÌL¾råÅŸºó àñß;œ«?üãO¼éÍ?‹Fï¸xû;~îóñi5!jˆÊ¯ýÍË©”&ÓJoùñžP+9,«¥T ç°¬‘J åÒ ÏvzAQëã3jÕùq"¯:?læóÒ…?x÷Éwýý__JùÆcŒ1Ƙ`]ÆI¤Ëüꃿe”÷¾ï]1‡)}jæíïø9æã"æi.Lñã0âñß{„¥I¸Q¿ð¨€L܈.£ïé ¼ûĹ3§¿ñòs—^xVŸÑ?Ã^õó2±Šž8ø¿×5™”š¬úy¸ªš(…qx`'Z(¿–GÝÿÒ€YÖD©ÈcŒ1ÆcFúŒ9’H—‘†’Tøq•¤¿¨(©*$}ÎEß“ŠHÙI_tŠ ñT²NUß)™Ôeô3+'ï>‘ŠÀ~¸üÿÐ3u J*ÕO£Üw럡Ni !+ ¯T‘¶’ôpãú)‡ö—Ÿc,¤¢MÑœÊÆcŒ1Æs{±.cŽ$Òe˜ªßHzäôC‡Å?þ±—ø‰˜òhÒW¢ÞôæŸM€š'µEº ê\ûÞ«±t“ºŒÄ‹ù?ž2S—éE’JU¸™£ËLºÑùPŒÚΑZVqŒ1ÆcŒ1æöb]ÆI¢.Seˆ”ôi (å/û² u‘*|þ/>}³e­(ê2¥â3‡ùºLë'uKfê2}úÊË]FšKGQjn¥!H—AšüÒ“1ÆcŒ1ÆÜ^¬Ë˜#IüS*ŠH(I{iý@ÌW®¼Èü_}ðôe¥¤ûè·cÞû¾wÅ| îÊ¢™Lê2§¸—]ÜÕþ‰ÜĺŒ> ƒÇê7¡ˆ\-Ȇù«ê23§ÈcŒ1ÆcnÖeÌ‘d¦.£/%%]Fú šÇ¨$½æóñi]'‘M˜_~"FºÌœŸø­2©ËÄ/ûàâÔ÷vd2‚.¿[„ë-ýEögAS›©ÈcŒ1Æc†ÂºŒ9’ÌÔeô3e5É+ñ—}ùVŽÿ [ª™bº ¸ðôéH¸>y÷‰Î—ƒVÒe®]~éÔÁY‚Ù- -ÓeäÃÌ”\•ý9CrغŒ1ÆcŒ1fp¬Ë˜#ÉúºŒ¾Ž?JCÍE9|Фß÷Õ‡hªÿc{7º ¸vù¥“wŸˆr Ò[Þüƪ 1_—Ñÿ]ê¤õui=N=polŽÁ²í]“ÃÊHÖeŒ1ÆcŒ1ƒc]f,¾÷ƒ¯=÷ùO}ë»—R¾I¬ªËDñ…””#UEÚr¤¼Tlxgº yýê+§¸÷® ÎàºüI3ui+0ròîçΜþFø†Q_y™¯ËÀx*šÃÌ!xËÊH¸N¥fUþþ¯/½tá~ôý×R¾1ÆcŒ1f#X—‹Ïýɹ'N<þäGR¾IÌÔeôÛ½¥.ôqþRŒTgýë%5g“V§;ÖeÄ~XêL©\Ì5¢nRÕ2ÖÔe¤•¬©ËÌiûšüñ3Éoÿæ¯ã¦ôê.¤|cŒ1ÆcÌF°.3O=ó$B Gû¿xbªÌÔe¤¼TÿA’~˜¥TU’Á(ÄH¦©~‰ Ü.]\záYv”þ9ô]FÂJú‘XS—Yó»EçΜfÛ9ºŒ¦b™dxè~Ü”^~þ³)ßcŒ1Ƴ¬ËŒ…u™™H—Aª~¥èŸ.!UëHgù©;ßpí{¯R‚Iš‹>q ÒqâOGn£.îº%B%ácŽ.Ój+ÖÔe€ºèÔi±ÒG`4^ë2ÁºŒ1ÆcŒ1[źÌXX—™IÔeª²‹$•ô˜µ$ý oÒ\”ÿÞ÷½‹•ñÿµvdºÌëWRŽ˜Ôe::E_4Á~é2'ï>‘Š„~T¦:£hÑ]‰:êèPf>ÖeŒ1ÆcŒÙ*ÖeÆÂºÌL’.ƒ”¤}¶éWü…X‰Ú /ô¯—HüÇØ¬ð¦ÚOÕmë2¯_}å®;ßpß='ËÏŒDÕ#éÃ&Hñßiǯ;Åx”D“ôo¹«ºL”~¢nMÑyVC/éËVu`ª*î¨mÕÈœï˜ùX—1ÆcŒ1f«X— ë23‰¿/#5„×@ RGFú8 ¦ @ö™:š‹jnI—‘Âr×Á¿LzâÃ)HçΜN­@VP ªžE§¸7YÖ2ÕJÄŸ¡ev‘*_xúÌa¥[ÕÔÑ}÷œdÅVDÊQç#9„F&?Ycæ`]ÆcŒ1Ƙ­b]f,¬ËÌ$ê2×¾÷j’N”ú¢ ÐÇa˜øÀ ýŸ&¦ôšÈ¶u }¤šZ¿Ú%˜ŠuÐö° H(’$TÕe€>°SY9}ú¦šªÊ‹†PUmD”®R‘Y†ucŒ1Æc¶Šu™±°.3“¨Ë0ç‘ÓáZ¼éÍ?ÛúuÞį>ø ¨Lø³¯ýÍ˪ÐúOLD¦þð?‘Šf2©Ë€ OŸ9y÷‰»î|Cä¾{N^záÙT3rñüY~ EÀNª É2žÒìµË/¡9€Ø$òÄÁ¿ë¨\ý²@Íä ëŸzàÞÖ(â× ZfÔ¥ÉÕ˜™X—1ÆcŒ1f«X— ë23)u™ãÁ]&²àt.o¹õY¡êwµˆê”ª“Y†ucŒ1Æc¶Šu™±°.3ë2{ˆ¾Êô–Æ?ZÒgjð˜ŠÌb¬ËcŒ1ƳU¬ËŒ…u™™X—ÙO$»”ÿ‘ œ;sš»â¾{N¦"³ë2ÆcŒ1Ælë2ca]f&Öeöýºpõç‡õ%¦þO형°.cŒ1ÆcÌV±.3ÖefrDu™øÃUþÉÿòæzþïÿä¿åàwv‰Å–t¾©téÖ¿úö\më2ÆcŒ1Ælë2ca]f>—·t{AúÆËÏ¥Wï~¢Ì¤_ö=y÷ æïÕ‡eþþ¯/ýé§ÿÿójÊß ÖeŒ1ÆcŒÙ*ÖeÆÂºÌLô¿«ûÿ¸z4Þû¾wýTøgÞ%?ýÓwþÌAºë§ï¼ëÇÿ‡tõUö“'>ü0Hÿ-ûâù³ÈÜ·ÃôøG>ˆ;ÆÛßöÖgþýc[Rg¬ËcŒ1ƳU¬ËŒÅçþäB ÇŸüHÊ7{‚_ƬÄõ¯~ñþ_üW¸i mIùÐo<ã_~ñ|Ê7ÆcŒ1Ælë2cñ½|퓟ùØ7¿ý¥”oöë2f¯~áÂöÔ™ï¿öWþGOýèû¯¥|cŒ1ÆcÌF°.cÌ@X—1‹ùò‹çïyÏ»¥Îü§s½ñ·_MuŒ1ÆcŒ1£a]Ƙ°.cÖäåç?+uæ_¾ó_X1ÆcŒ1fp¬Ë3ÖeÌF°:cŒ1ÆcÌQÁºŒ1a]Æl«3ÆcŒ1ÆŒucºŒÙ,?úþkþGO½û仨ÎàÂ?âkŒ1ÆcÌPX—1f ¬Ë˜m`uÆcŒ1Ƙa±.cÌ@X—1ÛÃêŒ1ÆcŒ1b]Ƙ°.c¶ Õ™ùÎÕ™TÇcŒ1Ƴ3¬ËŒÅ7¿ý¥í—/þåçR¾Ù¬Ë˜Ýpão¿úŸÎ}TêÌ=ïy÷ËÏ6Õ!_~ñü‡~ãÁ~çÕ”oŒ1ÆcŒÙÖeÆâ“Ÿùb¤G{$å›=ÁºŒÙ%sÔ™qöñ§žyrÇ|ñ¯þ4ia øêÿëÒ·Ò_í+W¿üÂ$ˆ¨ÓKÚ˜e`/}ö÷ϼýmoå+÷ž÷¼ûÕ/\@¾ucŒ1Æc¶Šu™±øØx !ÐÉ“ïJBƒ@ÑAÐäätÛÒý¿ø¯«ï˜ßâßý§sÝ1_~ñ|ÂvÀßÿõ¥t›Þ%?üΫÏüûǤÎ`­éÞ‡ ë2ÆcÌ|ãåç^¿úJ™™rŒ1G ë2cñÔÁ÷˜Fû}™o~ûKéc;à¹Ï*~e7<þäG’¶Þÿ¯þ·ƒØÉé¶¥{Þó=ü+÷½ç=ùó?ÿó‡Å'NüÙ³gÓcŽiÞòæ7ž¼ûDÊ_ŒÀÔ©îMùƳ>¸ÃÜqÇwÝù†2wž˜™à­i#w¹½7öÛ>‡×.¿À¥žMEæ¨c]f,žR—1;cg¿/são¿š>¦±^ýÂ…ô”ðÙß?‡A9ãØ¤>ö¡´…Œ9Nਨæ‰?œò€xi2@2Ƙ¼~õÞaÒÍêÂÓg‰„‹˜aC¤™Ÿ¬Aü^@ùÙœ5ÙžåmÿIÛ1˜7®#.R‘9êX— ë2{ÎÎts,IBØ2þëKü؇?ðÖ·þs*2¼ð÷˜Ì1æÔ÷nð¨m]Ƴ%î»ç$oV¥¢Á;O磬€4S—¡„NSÑšlÏò¶±.c¶Šu™±°.³çX—1·‘ôã2üÇLüìus\¹ô³<ãnê›G›Õe®]~©ú[G…íù³3ÃË£Ë>Œñ6‚m‰éÅMùk²Õ×lG|¡¾ŒÔÛÎ×Xiã_ÛÙžåmstußLŽÖeÆÂºÌžc]ÆÜþþ¯/}ôw>t ÆÜL÷ÿâ¿â?cÖeÌñFçìMÅQ 96¢Ë ¾:8~ÕOßlÏÿsgNÓò1~Ç!+ÇèhjKð¥ºÙ{«¯Ùþ—•ÔuUbÖKf¾š˜pñü†`n{–·þ^¤ü]²@—ñÍä¨`]f,¬Ëì9ÖeÌ6ø/úÿìŸü£*ÿäýìÿó~âVúŸ~òÿðÆøb…ÿóÿñBþÿíÿú‰™óyï»Þþ÷ÿï/'ŒÅ9ü8=Žì0¸‘¨ ghºwDu™íù¿ìã£#@$‡R[‚/ÕÍÆØ[}ÍrKtm·áÕ^1¹;`ÁÝn#ùf28ÖeÆÂºÌžc]Ælƒ·ÿÜÿÂ?É·%=÷É&Œ½‹¸Áðž¡ÑFâë2-¬Ë˜õ騋ÙêkvòÞÂ_ŸAJ_e’íÿà³&|UZ—1[ºÌXX—Ùs¬Ë˜mðÏþÉ?Âßãßú­ßº¼ÛôÆ7Þ< œÿ¿›ü1ftZyÀÅ¡–¤üÈ]Fvú¦PJ÷úÖÖ?±R וç´Úžÿ+E&#XéÛjj˜ò…̦ü>3[í2”šéÒöàŽZiö‰‹žŠÄJºŒ¬u ”rÕæïy™íoNi+=ߪý4ÿL3™3É룻MÊß q ýUàL.ÖefÞ9#rL9+ÝýÈ‚›‰úÝà«ÒLb]f,¬Ëì9ÖeÌ6 .sáÂî®%ÜÍЯu3,ú¼Ì¹3§Ë"¾ñȧ÷Ýs’Q®[gbV«Feˆšh–F˜ð´ü«Åš|J6ò¦7œ“­.€ÆÁ¨QtØà ái9Ûó_FJ³ ÖD|¥Ÿ±`e$\cÔÕ_µ@ÂÊŒCØ–­ÒjÂr¹å‘“V×ÈI5ñ”+ý¸ñê¾Z ú Å³±µšÕ ‰¥­W·Pw‘r`ÿ°ûM|£XnìhV½ÿø 'ñb{¯Ùê.‚çè1Õ$pŒÕJS Ä:qŸÀ`Ê™ îŠt¾\÷ÉIîÓ²œ^ƒx¢—Ã]pAyZñrn«›¡³ ôuR>ШzÂŽØž"3U‹¤&¸ææD>súÍÁ‚› žV O'û2ÁºÌXX—Ùs¬Ë˜m`]Ƙ­÷yþÆ#*ðºL8ˆ§V€'ÚòÈðXϾ©~,*S'™ ‚™C[·œ9|2c“4©ÕnüWØÙJZJDtчä-Rwa€,ÂEœ$´ÕdŠf“e¦4FÕHe«è æÖZ©æ2¸ˆxœ¿±å|56Ce–V}{ýê+iÜ! ,‘ãú•äC¬¶Ìä¡¡bžå¼®¦8öè[²†”\EeJû~ª~i¹*pÐTë ƒvð3±ÖñéL¸LH©ùœIîÓ²Œ§ÊO¯A¥4ír¦³s4'qêp×·LýU¨æ#•n`,±£8]He}›Ä„üþë1²êͤ5çLèºú·Òlë2ca]fϱ.c6Îõ¯~ñ~Ãÿ S­Ë3‹u†ÆS8a§€¡<«~5Qì(<ˆáß %ÏŸ…e¿QO…ª-#F2zïo€3D/émùXªÓ9.寀v{þ#Ò€…Ø©ÌÆÐOÙ/|À’1ÞjíP¤ÊÕX$ãœ<Æ¡iP¤Lv‡Ä‘¦ \ÑJ1ù19,г @Es@õ“>+AÿaœöñtrckfPY™B~⢔ 4öh׬ϩÆLj§¸PµÐ<ƉÂá¹À6À5Pe>%1òdx |Í¢ Y@‘,ÃBuw6ÁcÊOÈBÈ2àMéDäIg’û´,ÇÆ ìId5AJ›Dþ”Û`Ø 6c¾ºÀ…^ ¾ p›¨UZ5I]u„jZ\è>o/$í"Í€FÊÒ9³:jˆËÌéf¢QÄNc¿HÕš b]f,.þåçÉ|âìã)ßì Öe̹úå>ôâ–ò?ñøƒj]Ƙùè0TžÎqTe¬©ˆGØòü #Ié Èl™Â™˜E›= shè.…17®_¡óeœ ñ–S4Wi€[òÈ\¤" 9e…CÆb¾¼eJ¥D‹ÕÙå*sVñˆ.Rüd«rÎ5«e«uY¤ùH{FA/S¤€f;Êê©:-ËÀ’ÑféF *å‹-½f[;`z«^µÄ…’ n-S4µê$W©Zš=$Ì@¤ñ¥ÉÁ21¿ê’4ŽX*ªó©1"¥ Àé¨÷ª)uT¾Ö€+ö¢=€”fÛ@M`<–vP«Ö®ˆ[º¬ƒ¹4¿S³ë2Ãqíï.§³?X—1áê—_øÀC÷Ÿ¸•üycVEÙ2`&:§¦ƒ;ó«gôl‚Ç”¯(e%k“t<ä¨KOZéSì±%ÿ¢A‚‚®ÔVÞ"¥7ä…ú­†.,JmL¶\Õœ'ɃùHe_ë ³+mlŸIJÐè˜J›Õ£iDJ‘ç:Èl©wT©ú6“VÛÉ=/…¥5ÿÒâ(&Í 5oí·ùTwûª“\¥jh˜˜ØTD8íHQæÓý§:9Õ•Rf´цO÷4¾|dMi­KµwQ½sÊfêšH=GBÍTÚ‚n#UgH+¬j[@·ÍÖXÌF°.cÌ@X—1k’™ßþÍ_¿þÕ/ú÷eŒY¿qNED÷t8桹uL¯’ÎúBQÊJÖ&éxHOâñ]nTãRµ¹%ÿB—ù‘‰W©íoÕoœÒjÎ)Åü$ÙE(N6Ù°Ì_ù³ÒÆV™ÔZÃ£ÌÆRµJZ•¦1å¯I?>/á¦M>Ϥ:^0¹‹4ö–®ñÿgïom½Î2_Ð@눧¥‰PAªO@KIw+]»Ï8Em¥›‡ŠO•>Ø&¤Ù8qºQœmr(Bmg» İ1©lz;”EmQÞrˆbÅ ¤ÐfW'Š„Ì—Ê¢þ€Ó—×µöU·ïñò¼¬9çk=×ÐOKÏ/÷¸ÇËó¬q_kι4Š8ÿ“f…ìÇæë©¸—Nr•ªe a¶6§)5ÔR¶ÞÏ÷íœ!¨NZb:ÀLI-;΢'§Æ”Y±Ä²™æMhS~DuZ2sr¬Ë3ÖeÌj¾ùüKE†EÖeŒYJ<WÑá8Eª<¼¶NêUZ}éX¿ÈÚ$«žh¤–àRÚL ‘φ»õ¬ˆL„¼Jm[ùõ‹Ê©¨NÍ šT‘.“r-P'æŸêG4ÆêÆN ™‰&zãL &5´av¦ñ„hÒp1ù†ŽêˆfÒšFŒè¨ÿæž—‡p Qö5c-³B5q‘Š–ÒZ& ““\¥e/™ßr¾ÕP; Õüè§Œ´z!ÕíÁ±#S¾³"ênÀá*e/Õ~#3ýhÉÐc*Èdig, oÄìë2Æ „u³‚¿üôýÿâŸSŽAúÔ¯}øïÿòF¬`]Ƙ¥èüòEë,ËSu뀋õ¾{.¢Õíà"Užy\^І–Ž×RRw &Sžü3#“W_yáSšmPm+o;65EåÀõA€¤A¨»É”úå2!¥e:!Zý”/Z«¦ÊÕ¼uó9½1!Î Ç^ö¥åÛíÐ Æ Ç5újýy¿å^b·÷¬–u2E š±–Y¡ši;­ µL‹&¹JÇ2ó[ηjû¥¡Ÿ)«ÉÊ­^ˆÆ?ëÄåC‘JËG·“)zHË1'!³}ÿ#ÚuiÞHU ,‘‘ÖgÌɱ.cÌ@X—1‹xåëÏôb]Ƙ¥èüò…Bˆt–婺<àâp¯s-j½LMZ]œ‰ èQ´ÇQ[ž¤¯üP@o;¤wXìÉ0'2A\b5¤è'sR[yÛ± $O ãÔ1ngf9Ru¨’ítóOÍ¢»”/Z«¦àMoIà›d ñ%u攫–o·C#è=²k&\W×49\²{VeªEôyλ3ˆæ¶¿çÐY¦ù“\¥eY³×2ÕqIÎHFу.í@-AßaŒ}±-Š© ­7 É[Ô쟜xÉ&ÊIÈlßÿˆ†\ÎÁþîš9oæ$X—1f ¬Ë˜EüO?ÿž¾"C¬Ë³¿S¾Ð¡?eyªN™ŠQ‘p§¢ÒV_¨Ã&ÉÚ Q€]MŠºÅŠ0€ìÉ0é%$Ì*®á‰þž/¯RÛV~‚‹UM(ŠZ'\÷rq'QGp,šíøÓÚØÚÃjKS )%Nq$%$½ hùv;´¼E/t˜©ÜØi8‰=ݳlˆ´hì“f…æ¶¿ç0¹Ls&¹J˲†Ùr¾ã’Šäƒ6dÚ’V[½êöˆë®)^V§H.õ;JTû¬0Ûßu3U?)ïh³+¬Ë3ÖeÌ"^üòÓpõSE†X—1f)ñü]E‡ãŠðT¸ŠÒ_nI«/E)ýãòRè!<¸WªîuÑØ“ÿ ïRTÊ8D^¥¶­üû…YD2ç àºÕ ¥l’ò'á®@*‡ph¶ãLjTÆØj‹ÆK SÁR :Ìaô[íH]ìvhUÔ—Üô¿ê!ØÓ=»nY'Í ‰Z—ÕÌ_¦Î$WiYÖ0Q!拎Kñ®gNz)d¤¯"U›§u×&©®‹:j §ŠúmÍä ³ý]§iï﮾³¬Ë3ÖeÌ>°.cÌRtþnŽuHMobç©:pU¹|?P_)•Ù*Y; üog\%Š·—º±ÿ‰þÀ[Lf FME@¥©m+?ÂÅ­ê-´ôKƒØ»‚´Ù–nl iÇEu#q~¸Ü¼®.ËÝ­…‚çÔ=ÄϘ)4»½g/Ýy'×ü `’ûÞ ¹}ò¹]´L­I®Ò²Œ—ÌoMNߥ¸dzj•â‹ÞçÒZ# :i—ë®NËǺ'§ VUr°b õ&sv×ühN‚u™áøöw¾–rÌv°.cöuc–¢ÃqõHs¿©)¾e~jEkee"S)tŠÖ¡ÀfÑŸÓåFÕÿ;÷Ÿ(~«J$ýÒ–¦3«Ùú'Ó%šðª3Ô°ÔGNÂêÍR¶E˜Ç8<­,Ã?d^¿vå¨bÝy ­%îœVwý»rO÷ìj•³oV¨ÚÒ[µdÑ2í¤2^2b¾è÷¢[ûÒ÷r"aÓ¦j€³„ÔÒ>t›¤ ¬]¡Ý2H¥Û+–C²KUÓ”`„Ôš¥Í[ëa¢ñ¶lÊ«¥Ï1³ë2cqý+O!’ùô•GS¾ÙÖeÌ>°.cÌRtNEÂu:U«´<:ó Ž 1Sõ“‚ð^Eñ¬/Vëû(´FB×gnÇÜ«†1:”£rK’¨žøwî?QüV´Ni'ª™Œ þì Ëœ:äpê@5ÆÃÀ9 H­ sž¾kÀ [í6‚Ï4‹„ëù›p,øÉ‹ä›cNêT×]C«F׫3ÕÖ ÒÞV~¿ÕÎïY5o­,–.©UÒÔ{Ê_Au™–Nr•Ö˜¼'wŽ†ßŸŒâÈÌëJ‡UŠA¥"3™Å„°>Rz¬xrvž±#¤Ö,•hÞZ[N–Ñuù,Š¥­]mv‚u™±xü‰ÇÉ|ìã§|³¬Ë˜}`]Ƙ¥(Ìà?q¢ÅéÄ¢òÊúé@ÏÓ°€  Þ“qþŒMˆ„Tïé°¾4g­„.ÊX%ŽÁÂNÒ`,íâ!  ˜…K°¬å·¸ «ø©p‹ ­d  N5?¡U¼*›K­@Bs¼äÔÁ%º|üL­°l‚Ľ‡Ÿeµ¥hf8ø9scÅ™Li)cH‰Ôò}±B¹aNýÇOÍ0ÜÓ 0ó©¾Ö>c\ð u0,E[–"¡ˆÑDóÆŸ²&´Cе&6NVV³Ä:4X¥¥eÍ<|HEX§ì à ­Á¬29Ÿø9s’«T-ù 1_´ M>SËÎk·_Òà‹Žáà~D}ùe/,-WÔ*é/Ñ qΓSÖt{jhÈa«ÖèJæ >ý™Ëz[ âe,eþþH¾Í!Y807Â÷¹ÞwÏÅè®/=p/cf¤òÍîMÈ|$ïË`O&ç'öÝI;Gâ`úÜ¿Ü~Ø™1ßs†°.3Öe6Žu³¬Ë³”ÁÃWº·4!|Eü–ÚbŒäøõAD…—‹ÒÒï¹Ü9—ÞøÏhÊ©Ãõ¾ßgô­ð‘æ'}*m|]&ÎçÌ4òpvç'}̰¥×cÎÖeÆÂºÌƱ.cöuc–¢¤üAX­Ë°yü/$,â5F}˜/Q] î½ïÎð9vëÎìæ¿–œP—|cƒ8±3ÓÈÃÙ9¸Cqó&]†ÿ'¨ú½3Ƙ³‚u™±°.³q¬Ë˜}`]Ƙ N9ã°úsL%¢½"¯æ“,œ:üÄÍá?Dçd&ñë„ðR×ÂY]Äá—ÀcvŽu™±°.³q¬Ë˜}`]ÆcŒ1Ƙa±.3Öe6Žu³¬ËcŒ1Æ3,ÖeÆÂºÌƱ.cöucŒ1Æc†ÅºÌXX—Ù8ÖeÌ>°.cŒ1Æc̰X—‹ßþÝß°.³e¬Ë˜}`]ÆcŒ1Ƙa±.3ý·7>ð¡¾vãS¾ÙÖeÌ>°.cŒ1Æc̰X—1f ¬Ë˜}`]ÆcŒ1Ƙa±.cÌ@X—1ûÀºŒ1ÆcŒ1Ãb]Ƙ°.cöucŒ1Æc†ÅºŒ1a]Æìë2ÆcŒ1Æ ‹ucºŒÙÖeŒ1ÆcŒë2Æ „u³¬ËcÎW/?ò–7¿ ܺù\*2æÔ¹ïž‹ÜŸäÒ÷¦ £qñî t5åcƒucºŒÙÖeŒ1çO~äýx }ëù/¤"cN—·¿í'¸9•“êŒ}¶.cÌia]Ƙ°.cöucÌùúŒ“«—áÎ|Ë›ßôôg.c^zàÞûª†ucNë2cñ×{ãSÿúc7n>›òÍF°.cöucÌÉùäGÞö¡!tÄS¾G—9ðÌžÉµØ {êåúµ+°yõò#)èÍ27žy2"˜Ìf#å ë2Æœ.ÖeÆâ·÷7É|ìã§|³¬Ë˜}`]ÆsBѽhÞu×ÎÃæ n[²‹\:]]æð3sx&×b'ì©—·¼ùM°yH¹áð=N‚)=šÚÞÇ©¬ËsºX—‹ÇŸx̺̖±.cöucÌ ±.Óº̮°.³?¬Ë3>ÖeÆÂºÌƱ.cöucÌ ±.Óº̮8gºLG9<ÖeŒë2ca]fãX—1ûÀºŒ1“ nA\M&¿âÕW^xú3—UשBäÖÍç`M”û†ú–«—‰­°Ã×èRÇ:ƒŸ)_Ðlì—M.=pïëQÝ]wá‚uˆª%4F°ô[6hYQ:†£î¢ç°Ì ÈgަtÆA[5AG /Y13qZ°¾'“5¬N&jÊ,*°­H•Et¦jÐÂäZLÒïki/Èä·¥´ Z.#›àµÛ/¥Ê$Zî/P 6K—Qw-;(Ò(@¿;šÒKÌÒœVô •¦ö ^Ek€óu­ZÿYé/ô$XxG„k­ÈLƒ±I§ª•“é—j¹S>‰>ô7ÝÐôâ‚­°dªc6‚u™±°.³q¬Ë˜}`]Ƙׯ]Q@¨„à'ãTà }ñî Œ»bBNëÿ­Ð8~âBê uþƉÆ ŽJí³4‚s<+0*@äR4a5üLùDfé-€KÉrL(R8!0oeäTç³Dd5EÏa™pá\š:$ä¨rIkÝgþßœE3ƒu¯n¤–“¬ÌIƒK¬Ìc¼ê(R*wÂÌ5š¿àaµ/yµ¨—ªçHÑ I“–R¹Ê¼µ‹CBf'¨Žt"´#Õ¯æM·|ì«4éo8i¬Ikè%5D~õY$fnª>¨ÌV¸®ÞÔðŠ3P¥u;TÝPͪpsõÎ?Õj=8XºYº‘è~âËA³Lð!Ö4çë2ca]fãX—1ûÀºŒ1-bLˆ19~}ôˆXÇw•ªr¬³u©SèØ­¾R+$XF°¡ÌT¡Œ(¤E¡‡­bÃòXÏRüLùDf$€¥ºLt×DæHqEÊ$ÇC8$ S]àB×H±~$írU [­"ógÁØqn­/¤jw¬€1–ú‚âÒ8W4 Ž_‡„j2 TGÎù×hþZ´@œÌÊe_j>¿—îÊ ùÍùƺÌXX—Ù8ÖeÌ>°.cLD8G§ß×S<#Ÿ ÎÊÊŒq8ÂŒ¨GijxlBxì.ÛâdÏ"$\°.Ð;*xCs„‚4¶ÂOÅW0®ðùÑO ú1SÈlüD>Bá/Iúó¯ê yì7Ž4Æ-h<6QѬÂ0*N".¤RœŠbš€×n¿¤9ŸIΜ¼D)ÜKcG×ô©œ Š0XØAô’ê¤QÈ,~&OÀÒ5âpbs@ÚZUØžÄ| '´48Ù *À–& ªu§ÐBœ «¡ ÖAJ»E{ ]Çü*°Cã´†&ê.ŽBK€jqªQGAJïšækJ9KøŸ]%ô ÕÔœ.‘X“–•àŒÜŽŽ¥ÉK7U‡ÎM YÃ…šÝÔHiBd)Þ>p™èK™‚0•C–͸a0vµš¿‘8(4d[L5—®–ýšóu™±°.³q¬Ë˜}`]Ƙ*Ò/Ò9ž ˆ‡xE&¸P¦À1Z'ò(–@JEñTZVÛÔÝ1 ub,DÔ0°;üŒ™BfÑ<)®¨ÎÐXʶF§´Š†¯R‘KHåÔÍ „ª–UZÎj•É™­ ùl›þê8]LÕæj[ö«¢ÔpõqNZkQEqoõ–)™ì±wkQ4]e(Ë"üLùB·v)á•VW¡Jg’µøY¦ºKÍQ™ùH­¶Ô¼êÑü#•SÑzZîöÆ×Ý„Tnõ…µH ç«‹¨;Íã’µ´mâl#•·»KÖÖm¤8íåͦ°.3Öe6Žu³¬ËS¤TT+·¾1T4N1¶ŽÝÕ¸]¥¸HE@QJj«°!"Æ!1_£ˆ™¢¼µ<~+|ÕHËȹŠê·BP¹TФ:X„slÕ d¶\•LÎL:YN8ó‘&ý,çGë˜Ú®^£Éµ¨"7Z ”X× ÑÐʶÕméWX: @ƒåšçI0°9R\¹ÔZ¾j^õŠhþ«;Y7N²°Û_»ºå§&0îm=îæŒ.Þ×r>ÝìÌÇB´–²šÏLüŒ™¢µ‘äXÇy³¬ËŒ…u™c]Æìë2Æ”à ~tžõ'Jû;±¢ÖIçr»[‡õ~Tß:Ê+¿ÚŠTƒ„j¦èo}?A˜@Òº[(\W©ˆÈ`«Bu°ŠÄZnh:‘sdrfúÐÉr«ÎG:Ã×ªà›­7#´¦ºG4GJXÝ èÌF&%7t–›Ê5jÑ©¯ éˆX5Ö‰bÖtÎóªDÍ;£àü·&JÏ·d¡ß ´6U•Î:­WtCbMGKÕ?Þ­iá P“kÑEù[¿à­2Wo$MàÝÊœo¬ËŒ…u™c]Æìë2Æ”(ˆgë3+óØB»c¦è[n… ÊïøCgb„SõP´º“3 ˨PEÑ&®SÛ*œ7¤èvúª3/³Ÿä[DÂM9 UЄõq‘ŠZÀaÁy+ûjå õ[†»Õ¸¬^#MZkª[À"Áx?2_Ú âXM£V­l«Q§|"á'¡¤o¡„õ«k7Çz|Ý¡7®ÆUfÎGÍ;;Šóßñ­:.ˆsU²èÆGV.בTåï9;§5ò¿Ì¼zùÝJQX” •y¾t#MN»ÙÖeÆÂºÌƱ.cöucJt”Ÿó—ü™¡ÝH1<è»aMª–[±„ò;þh€Ñ™j` ZݾŸ@cŸLŸ#Uÿ#r©U¡:ó2;™ÊI¨293äÆ3O"œƒ3Õ‰*ûbµŽ­÷/1ý~õÉ`kª;(ˆe‚©Ö›fö‚æ¨ÙKÙ–5ñ3å-ßdjY(ap2åW5…¹-`\Ììo³j^z%8ÿߪãbæœ4Çs½³ØcôS>tZibC ý)Ñï|AµW_yAŸ`ů5aN²³z#MN»ÙÖeÆÂºÌƱ.cöucJxFêå…*÷C ž×‘¢Íþ±[§ùªeÅ)R~ÇŸêéaË™Vw ï'ÐØÑ¶›êâ” 2 Fÿ#r©UÒ`e–þt迹CLΠл9àP/ÌÄEjÂù,ó# )Q ½t¤…@iª¯"vÝ¢\#d²akªû`&aS½#Á`ij²ä«RœF/Û²?S>ÑòEkU:ë›`h’òá›úJE¹-¨í|7"j^z%P„ ߪãb&ó;̼ñ5ör{Œ~ʇN«ÖäS…AÒýÂÛJÕà||)q ÷sÈê„¶Š™f›X— ë2ǺŒÙÖeŒ)QL;'ΙYgkÔI'ìþ±[§ùªåV4¥üŽ?t)Æ*UE«;Ð÷ô-¯€ó†ýÈ¥V…êÌOš]Êą̈<)ßœÅy+'¼•/ô—|þL©e€ê§üIv2ip8ÊF¥“½¨-F—Þ ÔÙ ýQO.ß Øc¹vqÉRQ¤êÆUfÎGÍ;;Šóßñ­:®9#šÆÞÚÕ9dN§èÌ@2È—ºƒÒGäZVWm“Ón¶ƒu™±°.³q¬Ë˜}`]Ƙ£ÓŸ=«¨r5Ü%­ «ìîŸæ[±„ò;1@Õ™j¦è„.}?Aßò 8oH)þr©U¡:ó2;óí0“ÌŸ™ªŸ,-'¼•/¨¢Ú­›Ï¡kÔ$ØÏ­¡É“”? Ì¢!RkªçƒÛDÖÒšú½è{[«÷`g3ôG­†sž3aNÊróŠW)ÎÆÅÌÖ6ë£æU¯ç¿5Q :.(f®¦³ŽDoo‰nÐs¤Î‡RõM1ñI9,­¤Ç¸L¥7È´fiõFšœv³¬ËŒÅŸü¿ŸD$ó©ý±”o6‚u³¬ËS¢óýœñœÊ­¸±ìÖi¾nµ¢)å—1Q’Ò¤ôv¢!¤V@[a¡,ïJïPtÚŠÐ&C8º”f~uøÔbrfàJ[€¥å„·ò+TEŠ«×hr-¡»)ÍX¿-œæHg3ôçõÙ°3ÕK鬖 : "‡£v#?[Û¬ä†Î0é[k¢@Õ‚F´“_ëØ¦6I¼qÍÌÎí ñ¥œùx ó˜&A×4–­ÞH“Ón¶ƒu™áøÚ?¾õ½›)Ólë2fX—1¦ OØHׯ]IEçìxôWåøGlñÚí—T!Å'ýcw?iõ•T EØ)R2«à¤ìnkeh¡'• V…¥hfªT¾¥"RyEVø‰U‹E똜u—ò&­œp¶*ó…Ì·W¯ÑäZ,¢¥Ëô{é—j×›AEU-p&‘v¢,€ÎÚÁyöÕZY 3­‘¶Yš´ùhä|Á‰êT¨Žk·7¾†Ë©T7/R\,½¥¥ÕUÖ–«Ž.ŠV/bŠA¨#÷ª[¥êÛ$“Ón¶ƒucºŒÙÖeŒ©¢?½âLœNÒ8#3žÎu"G~ p¬çÙ© NúÇn™ÅE* ÆRœ |& $J q\ðMù@AT²ÂE¦Ôˆ‘úJÆ5 U© —ùïR‘KqJcšº2'­™×ü BÁ,µ†P293Èg…´m✗ÎVe¾Ð{P™ >Ai58D›,Z£Éµ¨‚BýÒ †¾H­ ©ö¢Ò4'¨ A!•›AÝÅ[,Þ/²Œ ¬N21]“ãýµc)KÊ ‘P¿åUD5Ç-ï$XP©¦.Å9¢3óp;FP)¡ ºNM:LÎLuÛ ÒÉrÂi°ºDëˆ:˜ŬˆA`¹-×­Q-ª x–)µÆÕ梁u‘0½’ª›¡o¢£ë–·H­»» ítÖ®Ü0JȯÎ?ÆÅ XßT4“¨\(ž8K¨£œDg\»ºñ1:6ÁxñD*FNu‰ö[Ë´êßÑh{\µ1Ñr,K7Òä´›í`]Ƙ°.cöucú ¨@œ†ó1ÁÁºü{¬@‚Už¬è‚ÑrÊ'蚥Ià,E 3Ë ÑŸ–5¯ªõémêN *³ŒV|‚ü8Ÿ­0ÒTmqi~Ç"NNú0ˆèÏ<€ G]ÀùÉÙ+™œ™8ߘ©†‡z)èy™/ûÁTÊ'Ø!¬€ŸÕá¬X£8„´RG“ '{ÁœT­qÆZ›n`]Ø #­Î 2aAÆš »ÎÝ]eríHš™Î 0.š9í-âì%ñ’]ÄÌK;ãZ±©°ô`;Ö×°"Ñàä”t‡NÕ„­ªËÐð«O?>öI**Y´‘ÔoÊ7ĺŒ1a]Æìë2Æœ3J]Æl ÄrÜHÑ ë´Þ_`ÌhàæMk6‹ucºŒÙÖeŒ9gX—Ù8sÂWê2­÷Ë3 ÖeÌ–±.sÎùÚ?~òÚ¿ùîßýEÊ7cb]Æìë2Æœ3¬Ël…¯÷5¾Êôéþ÷bcƒu³e¬Ëœ[¾vãü¥_@\„ô…/ýN*5cb]Æìë2Æœ3¬ËlœWÃw¸¾ýèŸÝxæIì €k}‚ u–~7Š1§ˆu³e¬ËŒÅÍo~ù§ú§žúüÕ”¿ˆ7Ÿ•"ƒôÈÿëÿé÷Ëœ¬Ë˜}`]Ƙs†uÓùŸ>LoÛO8¸5g ë2fËX—‹ÇŸx ‘ÌÇ>þpÊŸÉÍo~ùÒÃï?Rc^O¸FNªcFƺŒÙÖeŒ9gÜ:úÄàêŒPbÎ1ú8Ü×È9áí1æTÀÛØïó2ĺÌX¬Öe¬Èœ¬Ë˜}`]ÆcŒ1Ƙa±.3+t+2ç ë2fX—1ÆcŒ1fX¬ËŒÅ"]æ›ßþ÷VdÎÖeÌ>°.cŒ1Æc̰X—‹™ºÌ·¿ó5Ô9Rc^OVdÎ ÖeÌ>°.cŒ1Æc̰X—‹I]&)2þÒ/|íÆ§:æìb]Æìë2ÆcŒ1Æ ‹u™±èè2Vd¶€u³¬ËcŒ1Æ3,ÖeÆ¢ªËX‘ÙÖeÌ>°.cŒ1Æc̰X—‹¤ËüõßÞøÔ¿þØOÿôO 2VdÎ?ÖeÌ>°.cŒ1Æc̰X— é2Vd¶‰u³¬ËcŒ1Æ3,ÖeÆ‚ºÌ?ß=Rdîÿ_þ…™í`]Æìë2ÆcŒ1Æ ‹u™øë¿½ñ ÿË¿ ƒô/þåÏ_ÿÊS©Ž9ßX—1ûÀºŒ1ÆcŒ1Ãb]fn}ïæãO<¦÷Èü³Ÿý+2ÛdkºÌ÷_þ³W¾þÌLþþ/o¤æ‘×þÓ7Rý>?ø›“…Èן½öW?5“?ùýÇÑ{² nã«©~Ÿçžþ·ÉB>ôÐý3ùðüæó_D+ê2ÿøÿc>a–~è‡~ȺŒ9ÓÜxæÉO~äýø™òÍåÕW^À‚>ý™Ë)ÿLsõò#ÔõkWRþÈÀapëæs)ÿÌiÇ@°)ÿ0œnïÆ˜Ýb]攡"ó3?óN†1/¾ ?Óÿc:|íÆÏçÛßùZj¹ùÍ/§úäÉkÿ3™øíßý¿þÛÉ‚@QµU TþîßýE2"®å©TŸ`5ü¥_(ù—~'YÔe~ðƒ|ì£N1vŸï¿ügéÞòû¿ãŽä7'=tÿ¿ü‡ï¿œŒäßósï>®7/}î·šÇß?úìoWš¨2Ty÷ѽ3?¡~² ^üòÓÇ•f§?¸ú©dDüê¯|à¸Òìtû_MFVù¸Æìôá>ˆ†ïy×;î:½ôïÿ¨§432oyó›°‡ñ3åŸu^}å…o=ÿ…s/åíoû >—0üTtvá.ÅÐRþ°`ò¹ ŸüÈûSÑ™ƒ;jÅ#wæwbÊ_ÄêÞ[ìÄ+cÌ:¬Ëœ&OüÎÿúßÿÿ=ç»ßùŽ÷Ý{ÏϽ/¾+Åðäz £2 MÍL>öÑdA|õÏþHoÞ™™žúüÕdD,u ]ßúÞÍd„|óÛÿþ¸ÒìÔ¹Pt\ivê¼IâÚÌ„µNu™^xá¸ÒìÔy“ÅC÷ÿËãJóÒ;~ú§ZïþøÁß¼x\ivêè2Ïñs‹£{~îÝ-ÁüÖ'ÿUÒªút” óÑþrªßáWå]앯?Ã7Â̤ÿ~LZªßá>û›|“Ñ÷¾ùïûèÿã×~ùWðzëÿá‡ø‡þÿöÏRþLüfs¦9¯º Ç…´µ·Y—ÕºÌÕË`˜¯¸x÷…ÓÝÃ딑[7Ÿã ,m˜Ø­.³+¯Œ1ë°.sšüóþžãˆsvúZã;€¿ûw±TøÀ‡HFÄR]]£I2"?ú2ãù©ã†yéá÷K¨šCkÆÀ›Ï.²†¬x¿L‹›ßür²¨Ëü—ÿò_þ?Ï|!ÅØ$~'’nìÈÒøt>’c6ÈŸüþãï¾ø®ŽðdÌ9ñÉù‹R#ƒ7,,ºÌ¬ÐeP“ì¦ûêŒuʆCÏ‘N²w«ËìÊ+cÌ:¬Ëœ&·¾wócÿ•»ßùê/¾ë7ÿÍ'ôÁœ’o~ûß' XKõ;ܸùljnF€º ÒF¾_ÆcF†¡à®Âžqи¶öQ¦au™ë×®`9ÀŠï ájžc]Fõ‘0Ø‹w_@CŒ—gšijç¬SFpßÑù¥ »Õev啉p£8¥Ã:¶e¬Ëœ>é+f~îçÞ]ý泬ËcÌ8àÌz^£”mþ=œq,ÒhÃ×[Vè Ü¥ZÊ–uºLù‘%äsìH§u“žD9ù&M!ÊÍìC™Ïéönæ0ì/‘aÛ2ÖeÆâ»÷O^û7ü¯LH¸èÿ sΰ.cŒ1ãà“ë9ú̬Ðe:pø»²¶ë2¦÷ç€k4¬c[ƺ̈XÙ,ÖeŒ1æð ¢ÃñTÜwÏÅ×n¿„|\÷O®OæòÅ»/¨!@¤ÔùŠTF…ë×®ðeìùéMx‰LU脯¾òBù¯jJƒâÒ÷¢Τ|QþgžŒ£ÃõÒ·$`&aÝñeJ'ÿ#oõ_ð´Æ%RGhÂoÒA&©¥Ë¤†`Ž“%莓MU'™¬FÇp—E©r¶Eý”/æ /çtJo«u°?c/¸níØSÔe¸!AuM±:,Õš(o¼D×ð/çïpΤn’r>Ëm¿º÷¯°¥aPÆ*/z Ì¿)KÎ,̸ê÷› ?}•.ð Žuêc !íÍ×_’êï4O·j.÷*æVm‘«%V8†™L“0ü¥»ËLb]f\¬Îlë2ÆsH"ƪÎ(ÂO^§VçòjC&4©4ˆˆ«Õ/Ž¿¬‰CöqVHh"S‚áÁq"É`„]—ã‚cʇÙ#9ub•vD·«#B_-‰Dó_M°ÙŠ Z1®ã˲S6*M‰mSýU”¢)¸qœÛH­É‰p–8ɉEƒÒl£UÌØÒ¬€Æ|Dzj›òË!hÔ»ÕeZá}·+WãO•V'°/üT§9x ¨yLÕ4UíõYZ¦Tuï-Z^a«´\jí–Äü›BpttféÓ£:HhRö…}Ø]9 ³@ÚWýñ¦;èä¿M’?E_ähÍ$:íÈFfÖeFÇê̦°.cŒ1‡D§a1/=p/θ’9tÒÅEjʆ±-óËÃ1KqÒå…ÚÆC9ÿž‰ ”¢&JãÉõ«6Y!:åŸ7Y©<:Ë~ÊG_ÌWsÓ9´8Þ™‘`+üL#Š…¢Ô ÄHè@ó~Ã8pöØ;’Ú¦¥A\¤" ™Ó¢Ÿü»ô$hÅúhˆæX äÀ` ‡â"î©\à%)c¤*l‹ú)é 4uå#ª#[‰5H¨Àñƈ¾’‚¦)ÂÒÄüÈTÙKy[[M .RÀ¨YçÓÎúºà®‹“\. `iY„½rÇ='Mêbfï-ª^ab™Ÿx˜piKã:V®— ¾MÞ„ƒÂÏ¥£‹{M.Ø ?ce©2,ktì©ìBEªÏ  °Æ:ý·¥¤‡‰ªÑ:‡‰ ô›–ÆqÑ8.:èEŽUgÄæ–fvˆu™³AU¹õ½›©š9ëX—1Ƙƒó%O–8tÆ m Pª"¢Ó*ާ¨‹â_>q‹L± FbQ<ã'ÚÆƒ8ξ*U&AM $e5)Ý ‡¥)MJcø Ø )yÞAMpG„kÍFêtúŠ S©¢n¤` È9.8J)ÈÑä—ÝÉ&\JEU¡f9" ^àL*ÒÌW—²g£toé à93ËAØQ*ÕJ•CÖ ’˜|æ¯lBcœ¹: : õ©ŽúÂì)SÃGÂõü΢Òm=yÊUƒ´Š“¶º÷U¯tï¤{ Ä;¬»)ÖN{’{Xbt‡ü˜C;ee µˆ]È~é0¬•‚ˆì§|÷ðŠß&üÛ&#-&è_ï¸19r¥ñ·§9 ÖeÆâ»÷׿òÔ_ÿí”OPúÔç¯þÜϽ›êÌÏüÌ;â1«3ç ë2f4þþ/o|ýÙk)Ó˜ó¦H1ÐñÜóãQ¾zű¸eYù0óÌ"á¢<[«´<"·`üLù<ë—ù ¤QTöžTÔ¢T€VÜ®x Ú ´aP<Ð ¶é R)+àg5²ué5­Q+bÇü¤¢¥ÐÃ4^ ™_ÑEÕæºAée UÝ~ ̪ë Ô*Nø®t‡©¨ƒŽæ1ŸcÁ4r“`Vc©©•*/Úá ºjù¯²º÷U¯4Ï­½tBª‚u££5üŒ™-&+—Zû§E¿ Ýøkšÿêo¤ù¿"}Ç4½­ @S1ƒ™>ÖeÆâñ'Cô±?œò«X9X—1£ñ¡‡îÇæù/~.åsÖQàÚ9WO®Œ:§a±N5fhbegâTV„î4X¬[ùê¢êh5l1Y¿:!Ìì÷¢V³¡È¹Óþ ÅJ\hZ!Ê¢ø¿Ju¼`Å⊪ÍuƒŠ½W&©æ·* +†ôêzÅ`…î_ô^Û[´ÆÈLì+m­8ubQe‚u;¼•OkH­UK¬î½EµþõkW^÷é(dÉZ´œ\1:m­9CÖ£S™> iiÿ áwGK¬Ü…ìïü·É$}Ç´áûa߈YŠu™±X¤Ë«3ç ë2f4¬Ë˜óŠÎH£zèÔIº;)Ñð;+.?“Zž3Ò*}ǤNöoRY·LºÌX¬ÐeHRg>õ¯?Öú’32ÖeÌhX—1ç•9‘põäÊL¤Ÿ¤ûgôŽÃ8CË«2%;*óÕEkh­†-&ëÓí8!­©KÈUµUÃh-Aâ•9™’*Ñ! B5­šJ;‹;I9‡`õ ªï#SXžÞ™ÒcJQ=ÑJ­,@sõ¥“ùhŒ¸ˆ9Úrå”2§|ÃçY KJS|fv¬%V÷Þ¢S‹ÅR&\c6æGã+nŠ£[tiN&t”FzýÎÍSÂ˪:C'[£`)R|"%äg2¶å¼Í¤ï˜FןÉ9þ›ùX—‹Õº ù—~ççÿùÿx$Î\øéŸþ)«3gë2f4¬Ë˜óÊœ|õä:ç$ºî$­£pÕrËaµ‚qÄÏ(Es¢䃚”ùê¢êh5l1YE¨€jÊAׯ{0Õ‹\•| †ÑZ‚þ Å*óé;ÿIº…št¸þÏ1..=p/b~Y(ÇKZ‹;‡ªÍÕƒBüIƒø©Ì2'å'›‰¤æ çuÏV Vî!%Ei>zwŒ&Ó¥—>†ŽëýQ]"lXÎŒ ·²ÜÏg¦úduï-&ëc3³S&ÔO‹[eÝM±btåc¡ƒö!,È™*­åÀ~HbS¹CXÚ…Ú¢—T$PÄ:ÉÛ–ó6“¾cœ|¤þM*#3w¬éc]f,N¨Ëë_yê_üËŸ?gŽÕ™ïþÝ_¤:fL¬Ë˜Ñ°.s¾ÿòŸÝsç c¦Ÿý™úÜÓÿ6¹}ÖÑ ¾ó'÷êÉUÖ9'éth¦ÁÖIºoYǃ²2Ѷü—4˜üïäËZkh­†-&ëW'„™ý^ÊÙhÍy„þ ÅV3WéVÇ Êá̧jó$ƒÒø÷©å2g¥J´R+«q­eHòœ/åObЮQ§ >éOgh¹\ñjþÒU[Ý{‹™õ±1ä*vK*-YwS¬¶ÖäÀ¢Ê°+4ÀÒ[:ÙLjÔYñ–ŸåðÑwlæ©oÄ,źÌXìD—!QùíßýTjÆÄºŒ ë2à‰ÿõã|VœÞ}ñ]Éí³B ž;;çÚê¡SGðÎ,ë¤P–[=öÏèÕƒr¿ KËCs+_]´‚„VÓõ«ÂL¤N¬BËHñ³lØéN­¢eFÝHúTËIèûÀÒ4^P]Ü™TmždPR%Esã—R•`×HsÞ4!0ùlµt°Z¾jx¿Ý¡¬qE‡Öªº„ )_´ÚVóõl™¹j«{o1¿~ëßÕUé×luºbtz'T§•À~¦…9•'ÑÚ¥§V¿‹ýý6™¤ïvàQŸ=ûs~‡šEX—‹ê2äúWž‚Íoçk)ߌ‰u3ÖeÀ§~íÃGÒÇè)¹}Ö‰‡ò2àŠlÓÉUQkç0JËH)^e~«!òÙªªGTCw6IŠVi+_]´‘~w%“õQ„ ¨35ó­ð[‹H–™‰Ä·9$´pHq€Êg~Bª#" eËRI)ôšCÕæ E›øÙñh¥),ì¢Vp€­ªž,E>`Œ{1ÌXÝ!SÁgU+Qµ”/Z³WÍŸ GV÷ÞbQýÉÞEÇlgƒMÚ¯6d&ÒõkWb¾ˆO{våÝu´žýQìï·É$}Ç&?Ýþ+Ä_SźÌXì\—1g ë2f4¬Ëé2üØ}ç‡~h(~ÿG~„¾!%·Ïú[eÿëĉTž\y`EªFÑj[†ÄlØ:I󠌔NöDçþͪI„ÈÒÿÖ‰¼ZˆþQ¾d²~uB #Uƒ+:öò?Q”AJ¤H¨ó#­à$ASøÙúXRéžd‚²h’ê*iÅ ´ytQ ½âÛZ{¤^4Ø´|:S·­§»U{IO‰¶…‘”/ØKkuR¾‚a¤rÂáêÇI[Ý{‹jýVÔÍÊÞ…j.º)ÖN;¶40{ÑàR! ànªÞ5Ú'éFà(ZÒG´Ûß&“L:¦•]=Q; d–b]f,¬Ëlë2f4¬Ëé2ÿúÿãÿí®»†â…ÿö¿¥oHÉís@ŒÿqüÅy SçQž\Ës§NóHhˆ&8©ƒØ­Ê@®’ÖA¹â*PŒ™2aYÇkô+7Jÿ[ã’µª Õ°Åd}¡B9!ŠF®ÐŒ Á€f©lh¥˜®i Õx‘xýÚæ#q'¨ט4œ9ê¸y¿¥ÿÞ‚kÕòÝ¡S8OR*­9<É ÐûqË£„jÕXðÍ&¬›qÏÃJ‘Ÿ|Cïl‚ú1¿ª±>LÁ ^¶h9Y%î1¤¤>` ÌG§üK—µU ؼ\V¾æ Æ=Ì&¦*¯î½Eµ>2AœÞø„™³K×Ý,]::Øg>‹°¬œ@=:’Af²rÔ\p—œö4çÈA¾¶:jjÕPªš$q5áR4¸§ß&“L:†Ùë`6èw#ó‘¯&æ„X— ë2ǺŒ ë2ÀºÌ)Ï—1á<Šã&©¼N­@jˆ::Â"á‡×Ô°Në$|6¯¶¥3Hñè Ô )º :‰‹X_MÊ|uQu´¶˜¬"T@µ”â¸XS©Ú`ÕŽk ³qñº`Œ‡‘Ð9~={Ô1˜IFà3Uu¾º[ ¡ýªÍ“ *VC|˜J#Š™Ê^Rs­BÚÉ-8isÒLƒ±èq³#Ÿ‹8Ìd*%ô 5S¾ ‘ruZù ÍgLhãóÕ½·¨Ög&._"Í´¼î¦`>j¦|A#eÃë×®È~™p£ÅÊð1Ñ7rœõFÍ.®Nª‰‹ò†Å¾Š¦˜’Ïûøm2ÉÇð8MuÒK‹2»ÅºÌXX—Ù8ÖeÌhX—9ÖeNœ¹ãY×8y3øA˜‡— Öü{o:§â%ÙeŒGh-…©ù¬PmN?A zDþ±w|xíöKj’ê«£”¯ñ¶ä€VÓõYÚšùs<°£„—ýðñv ´ð‹…"Œ‹«ä¨Ëî@gMK°y’\Ógæ·Æ›ÖqfÄ…&›«uéè­.„³×áYõ^@f¹XZ…þ:ŠèIŸ¥Q¢V§:öÕç¤|ÁÒruZù„;ÿx^–뵺÷Õúå~FÂKø«õYqS0¤|ÁÒ²!¨v‡Unír‘ZMÒ}Š„—讵IÒ;ƒP¹|†ïü·Éæ8ÖZ}dâÙ’*›b]f,¬Ëlë2f4¬Ëë2#€X‘Ì¿…Ú‚TtHFða`E4´VäS‚šK›uVìÝNE}Ød…Û}ä X=¨>qÈ •š¥h2™rfµ?«oŠÕ¨»9{>N8H¥‰¥«£ú)?!›“5wŰŽmë2ca]fãX—1£a]æX—1ÆcŒÙ2ÖeÆÂºÌƱ.cFṵ́.cŒ1Ƴe¬ËŒÅSŸ¿Š³ï£}4å›`]ƌƇ?ø J_öZÊ7;ĺŒ1ÆcÌ–±.3·¾wóñ'»ùÍ/§|³¬Ë˜Ñ¸ý¯þÑgó¾ÿrÊ7;ĺŒ1ÆcÌ–±.cÌ@X—1fƒX—1ÆcŒÙ2ÖeŒë2Ælë2ÆcŒ1[ƺŒ1a]Ƙ b]ÆcŒ1fËX—1f ¬Ë³A¬ËcŒ1Ælë2Æ „uc6ˆucŒ1Ƙ-c]Ƙ°.c̱.cŒ1Ƴe¬Ë3ÖeŒÙ ÖeŒ1Æc¶ŒucºŒ1ĺŒ1ÆcÌ–±.3ßþÎ×ü¥_¸þ•§R¾ÙÖeÌh|ýÙkþàƒ?ø›S¾Ù!ÖeŒ1Æc¶Œu™±øíßý œ}?öñ‡S¾ÙÖeÌh|è¡ûñPzþ‹ŸKùf‡X—1ÆcŒÙ2ÖeÆâñ'ÃÙ׺Ìf±.cFṵ́.cŒ1Ƴe¬ËŒ…u™c]ÆŒ†u™`]ÆcŒ1fËX— ë2ǺŒ ë2ÀºŒ1ÆcÌ–±.3Öe6Žu3Öe€ucöÇ'?òþ·¿í'.=poÊ?.Þ}agNÎõkW0ðê+/¤"cÄP÷àÈà>Â,ñž:3‡é*©È¬ÀºÌXX—Ù8ÖeÌhX—9ÖeÌ^ùÖó_©h ¼åÍoºë®»ð3åŸ taLÊïsëæsˆlÁhò\Âp¶¹µÌL†º‡7'*¦Áï,¸G?ñ(HE}†}¦.ÖeÆÂºÌƱ.cFṵ́.cöλï¾úx¹ô]åíoû ˜ZD²p0Ð5žòO:³T—Aý£Õ»ë¾{.¦¢ÓźŒ™ÃP÷à°è6Çî,Ü옱óªË ûL;]¬ËŒ…u™c]ÆŒ†u™`]Æìœ§?s™±P5-ÕJ:Æ«éC2ºz¥ôã(:³tþ5Ûï>èmøê+/`8·n>—ò…u™3ÇäÝ{½±?1¢¿íbOf[ ;ÞJ'8ï–þ†AÝ^ªËœÖ3mp¬ËŒ…u™c]ÆŒ†u™`]Æìñuê½ïž‹7žy’gkwu¾zùXK(úJùõ“…ƒ!¯RþÎÁ¦¶¢Ð™¥¡×¥îECpà/q˜œ:ŒôhÄÖeÎs¶è>˜ÜH«Ù“œqx•ä´–¦Ï¤W«u™Óz¦ Žu™±°.³q¬Ë˜Ñ°.s¬Ë˜Ýrñî <+—oÇ1š1ÒgžL¥'dÑ×I8˜W):! íOâ-&§NC¶.s&˜³E÷ÁþîA黽§öd¶ƒ–æ%ì’É ³Z—1U¬ËŒ…u™c]ÆŒ†u™`]Æìý¥·ÝwÏEVØùÈ÷}„ƒy5Ã:c]Æœ s¶è>Øß=xþt™¡n¥É c]f·X— ë2ǺŒ ë2ÀºÌ àˆIR~~õYú“­¢ñT4É¥îåA¹õ?Va“v&­‹¾4Ò[íï1™‰æ-ššéšÈ“T4“ÉЙìÉ祻(qBç«LN†û]ቚœpĤ+zÔIùûC=μ5X´5g‹&d3å·Ð~^q–LΊ8¢™ ­‘TYjÌ1Û¡z+uPw3÷†à”Îl5¹a`ª¬ USÎ:häävÎÖeÆÂºÌƱ.cFṵ́.sº à¾àù ×ï¾Ðú˜ ¨êãøþôg.§š¦h×8b¢¦Z•Mƒ É8Ü›=Ê~ç8+ûKÏô}h?S~•r¤HxÙ ú` œçcCGW°ïU¹úHxÙÙ%¨OÔ<’j¢|ÃuòxY]‘«—¡©²þ§wì̤ºÃEÔûP“¸ÙØ9H¸î¯fõÖÃä´n¥hø´•A\¤g]å¸4 ¸é³'Z¯ÖgR¸d µL©G$¼ìL&¿­ã¸êAÅoî@Q…ˆª lþê¾êÜi?#ͼ«pi‡ /ã h‹ß8¨ä'Ö7ù†„—Ø ±Xd¬˜¨&MÆÕ\”Û9˜UUfÂËÖÞàF| ÇŽÛLý#$¶¬¬—DÕpã³À–ƒ{ÌABÍV/ºGóL;+X— ë2ǺŒ ë2ÀºÌ)‚ce<ÿ¥”ŽÅ8/ÆCg™ªgP6Áϲ¯t˜Ž‡fÔ$zÙÑY"l‚Ÿ)?¢QÌ´9“9]L¨&¸·èŽeb×eRtWõ ±S«!S+Ú‰ÀÕãÚÇÂî0À–ÏÈ,Ç7XšÖ 5e„/ÑE¬¹ˆ¸Ë„RÕ”cŒNyR+0‹3œGê 6„3°ÉæJqÆÖõ¨›%%ä¿vû%u›hZR¾ÍòDNì19Y]VÕgeÕÇ+,Ú¢@ï¹CJ6‘0±2iíg¤þ=X%>Ø»ŒkÆ”SMQ+ç3¶MS:ß,X1Q ç¸v-¥ý³â±É­¯°Wã< ¥GæoùŽâlÄTíH÷Hº`Ys˜¦´ãð¹ÁºÌXX—Ù8ÖeÌhX—9ÖeN‹W_yAg>D•ˆ-qF822?u®ÅÎܬ âq¹ŒîØ ?eö.â´eùú[+<ÔaÍU¹{éW¦KH)Ì8!sº)jb4šv$x˜Zµˆ‹È©ƒ©R&(½Š@\ýÔvNp…i„ój… .1H3ÌË~cX[ŽvX„š1_=Æ^èÿü ,ÁÌÐyyË—D!ÀK:krãMQþË•8ùh‚Ed~ü{;òU¿M¥ùÇS²¼®Çx÷¡”CÃM¡!/RC¼LiÐ\…Í9iëúg0MQ¼ã`D•ç›]1QUhYs…®«Ý­{l¢”Mh´—qÔ%«nn8À ò~Ê1æ •}©5c¾zŒ½p/•£;X—‹ë_y gßO_y4å›`]ÆŒÆo}ò_á¡ôÿÃõ”ovˆu™ÓB']\¤"€LœõRçÈêéçr–"¥³8ê4Ú‚Ф"€C-KáC*JÄSr*ŠÈ¥Iƒ‹àѼߵFŠjéD£óýLß´ˆåÔiÉJ¯´VŸ¥ýáDÔ]Çs)U‹cW8Jd9Θ‚á¸KÅk·_J9+ ýÎ ÄÆü'·5‡¥‡šüЫÓo‚õ™ª« Vô¨|¤$-a¤º‰ÒRjZR¾PÛt ¨aujŸ0UÏI¹&2XÞž˜6O ª…^zV‘µ´ªÀIV.»0˜žÉ$>‹Rѳ+&ªƒ&ª´V?6ÓüWwPódVÀ + Á~ºM¢tóAu¼x¦ Žu™áøöw¾–rÌv°.cäû/ÿYÊ1»åWþÀ±ò1vJnŸxÄÏ9>UnE 'RL¥h mqîŒEBAc5~ê=å'tJî„`ò´½Ž9Nj¤ñÏ¡)\“ƒ%ê´:·i²Ö É-#•‘|•9³*›Õák ¥RYŽ1ŒÖ:í·Bo;S$Ǫû­¥wàb«VÔ*!ræÌkV[Û~]]u†ñÐP¿iÅÕ0å =â‚‚êt mÚèO¿IbÒ1Ò}ÏÑ]¼Ýäâ{°Eµ‹3Ÿx-äyÊŸ4»n¢:h–Ò– «›2‹”D“9¨yk˜š(ô[õœ3Œ”~oVÇ+kû{¦ ŽucºŒ1äþù¾cåcàô=wºŒ²­P-¢ˆ¨súo…ú< #uŽÅ<¼¦†òS~BçÚŽŸ`ò´½ŽÉQ€Eu&Cš9ã­ö¨8¼|ƒ½P™AœY¥3-o[”Ÿ" -åïŠêÔEäXkoW-¨UKvÑ­”æ¡…zim˜u=êÎE©2#2›ülå YŽ §ÍÜÙoiÜ?2ÕZd¦c™ÔM!Ïåvô*¡JùUÝwszï ñ¦üI³+&ª–¦ZΪNtIf;º“FղωBJãjW£˜9oç ë2Æ „uc6Èú…cñcì”Ü>ëLž8#3+ëL3[G¡£-jâºJët›@)«uº‹Æ>Ÿêð#rÃIE‘™ƒH'ê¨z5§‹™ÞŠ9³JgZÕc² ËÉ[®Ì‡ÙN§«©N]¤å˜à<·&ÿéð%Mi¦3g¾?«`]ó‡ßZ¯Ö¢Èt­LµÂf޾EJ—ôÆ $쇾”9é˜ì§~…äYˆnËN¢t»Ã­â‹ŸR…\bÍ™[%Á…(›4«ifåDõÑ4¢m*B‹úcìoªÒìÔ¼5 ùÖªÐr •¿ïgÚàX—1f ¬Ë³Aôý2üØ}ç‡~h(~ÿG~„¾!%·Ï:“ï è°Ø?)*œˆïÙný…޶sRÿx-Sî€Nð»=ørø®gÆÛrorit¸ï ¤ê3‘:ó9s2Å|gZÃWÉ‚,—Þj®`5}^à$ÐÛÎð;Žº—,DŸû©5Q‰þ¬‚u=Î~k½R¾?qÞÔj2%—ôtBBQG˘tŒCž“daÒ&˜œÉ„L˜.ä¤:D·Lgõ æ…jpC°m騤YµLi‰hË[é$ÍŽÙ9L.®&ªU¡å@Ç1  ó¼ÛgÚàX—1f ¬Ë³Aü½¿§‚s¬ªÜ:}Ö£M¶-þBG[$TëS©m ªÑNÊ,û|&»ÖY¼?™³ d°S³ê3‘:3 uéŒ(2ß™ÖðÕc² ËUoQªá0!’IuÖA³á÷\ÊdAë‹ü>™Œ &¬u6Õºñ’M”“Ð𓟭|!⼩•œiQ~ô¡»l2áeÍN:㬻«"égÒ&@}ÚLù`_Ò9š——Ó-ÓY}ÌCš^ñej2i6¶íÓ¿Ð4–·’Š:cc\ˆŽÙ9¨y´ÑDµ*´è;†RL+0íê™68ÖeŒë2Ælë2§Â¢÷˨rëôIx”ÄϘÉãrÊŒèhÛ?vÏD>t>Ñ üºÃz‹êð#úÌÅÌc2¤Ñá¾³.U¯˜‰Ô™¥ë2ß™–Aõ˜,ÈrÇÛ™Ïô¹Ouê"“ŽÑ¥dA~v†³ˆþ¬‚u=Î~k½R¾¨ú3Ùjjt é!0ÙÅäK渽Â,¹uç~³ ¤$Í`™ßZ}Ì€šcrp›Ä9çB”ŽMš]=¢šÆr‹žä±Ù1;‡ÉÅÕDµ*´˜ãØ>žiƒc]Ƙ°.c̱.s*Lž8#ªÜùP=¬ódÙ9Áëh»“sgõtžØyPA&ÍΩ†Ð9²­K篩U¯æÌŠXgæºÌÙQt¦ePó“,Èòä„ jeHˆjRéRªS™tŒóÜšüÉá̤?«`]ó‡ŸÖKtÊUZÖ–ß’î‹É.&‡\"›KïÁù¼vû%g/i•1Õ|¡†U÷8Q¥c“fO8¢Mc¹E'! RuS•fç0¹aä[«BËùŽíö™68ÖeŒë2Ælë2§Nx<êõ»dNeÕ¹øÆOð¸Ü?Áïð”¯8¤%!µü<9“£Ðß®OXG(*h­‹þ™q²69K@uæ¼£ LFã€Î´¼m9óc õí¸1“É…˜t¬ºù—~%ê$ýYëz¤óH-ñ®eVëXÕ€,Çy[ªvÐM”L­Œúh°-·[÷àRªFnÝùè­Þ5¢òS]€¥¥cóÍΟ¨>[é$ÍŽÙ9Ln­~«BËEŽíð™68Öe†ãÛßùZÊ1ÛÁºŒï¿üg)Çìë2§B<ÈVì ¾gž•‘ZAšNê8D–ù鸜Ðç¤RÛ(ºkõØé s²îøN4Ÿ)?¢Yj°ë¶bÚD]Ô]ò*ÎâÆXDâöÀu*­¢¥ã9m«”OZA΢¦e„E­­^E[·5“ŽU7ÿÒŸU°®GmŪ‚©X)Mµ– œhÒÒ¼q ŸOuNäXk‹Ê·™wa_H‹îÁ¥ÐNi„½·Œ«UuJ;mûf×MT‡þ­¤9L;M´›}³“LnUh9Ör`‘c“½œ¬ËŒÅõ¯<…³ï§¯<šòÍF°.cFƒ’Á+_&å›b]æ´BSo Î` (SVÆI½ nU›©[ç{rýÚ6GµÖ9.Í ªÙ#Ry˜îø©·‹÷]í0§¹¢YT‹²WY:34m ªy@*½RiuǶå¶PðЙ¡B9ù¤~Tc˜«—©F)šô6íö”ßA“Ð’ 'ƒ+ZèL~kz±ú­NKú³JVôˆZFJEÚ¨LåB¨ašm­Sš7E×ð¶*‚è 0XÞ)r/ííÉ-Ú²@§éÎÕ ÒLÞƒUàs©ïȱ҈òËyr -Dô­êXß캉êп•´ ètÑcsòí3¹aT¡ú,-ªùKŸiçë2cñøáìû±?œòÍF°.cFãC݇Òó_ü\Ê7;ĺÌis³ÎÖ¸Àá‡BõUÆ9>UÆñêÇó}yüe)ŠR~BGOÇQ¦.ð’]WϬ%8¸Ózç ¢ŸHeäƒ Çekñtrr¤š^$\£_t‡Ÿ1¿ê”ÄIƒE|+g8±¥W˜£F¯'”¢ :j‹ƒ©U5ä¸` b¤Ä -³˜6GÛ˜—ÌëÂLzŽ|€Å]¤šD«ŸŒwÀgö‚†ºP…ªcvZ:o=Ôà9(-[µ ©Ö¬’u=j>‘pš@U‘™"‡EHjˆ^˜£ ôžªÆ1çXS:‰µ@¿ìQ­pÁšèB5ã.osµ¶¨ uð’faŠ•‘ŸªV߃UØ ]ëd–S}-‡ºÆ… ¸`)Š’Aý”5Ñ7 VLTا)XHEDþ ášcÁϘÝ#“f'Ñ̳Ӵa`–¥(R“HËj>3Ñ#zA>Àdê¬.Ó9úÌXX—Ù8ÖeÌhX—9ÖeN‘ëá;SB~:Jâ%OÛÕTÖ'l2çL©h5ÁÂü¿¾â€ÞWÕŽÊHbSéØãœ‘ÆX"%4/£‹>­Ábæ±":ë§V 3KHóc*çP)N&»kY†·l;1_fã‹ê[Jè¥ÜŠÚº SQ‡r~°v*­:élþέÇ4þû³*Öõ¨y‹ v0~Z/Òj7:ó†ÝRm¨ ŠŠ£ R¦ê}¤®cJ÷;êô' as¬V߃%áã ™*„îÇÅ!ÅMÞz®b'c ¸¨:6i¬˜¨-!V<6ç˜í# 1iÃÀ,sPMM"-ªùKŸiçë2ca]fãX—1£a]æX—9]ÛàôŒcŸ@`Љ]Q„ óë#*@…Ív@0€šÑ8íã«`l&¨®“)Œ´e‡!뤢™Àóù#EQŽ´ã^8Ÿ¬)Nàzµ¼âêsà•«AÎÐ0ZK‘$,£´^.HÛ‰C)~æ“ÕiÍ!ŠÞ,šaTŽ]ÀtªÒ–cmQÚš|€eBÙ'hµhþû³šXÑ#šÄÊèŽãE>ƒFm¶Djˆ^8ùˆ?áh­EÚEý–ÏX(70:ŠË”èoQ’Ö újY^}–°~4…¶JM\§O¥!ãšÖ¸-Ç&Í‚UeòV"p;ºDZ·<˜i¶OgÃÀ,í—;“´håcÒÊùì ðœa]f,¬Ëlë2f4¬Ëë2Ƙ½‚ÈŠ B57ë˜ÔeŒ1f>ÖeÆÂºÌƱ.cFṵ́.cŒÙ+o¿óy¢òþf5ÖeŒ1;ĺÌXX—Ù8ÖeÌhX—9ÖeŒ1ûãÆoʸ>ûû‰Ì¬Ëcvˆu™±°.³q¬Ë˜Ñ°.s¬ËcöÇÅ£¯ õ'˜vŽuc̱.3Öe6Žu3Öe€ucÌžxõ•Þ¾ä+WÍ|¬Ëcvˆu™±°.³q¬Ë˜Ñ°.s¬ËcÌ™ãêåGÞrô_®¬ËcNŽu™±°.³q¬Ë˜Ñ°.s¬ËcÌYäÕW^8É 6Æa]f,¬Ëlë2f4¬Ëë2ÆcŒ1[ƺÌXX—Ù8ÖeÌhX—9ÖeŒ1Æc¶Œu™±°.³q¬Ë˜Ñ°.s¬ËcŒ1Ælë2ca]fãX—1£a]æX—1ÆcŒÙ2ÖeÆâ·÷7pöµ.³Y¬Ë˜Ñ°.s¬ËcŒ1Ælë2cñ×{ãzàk7þ8å›`]ƌƋ_~úWå?ø›S¾Ù!ÖeŒ1Æc¶ŒucºŒ1ĺŒ1ÆcÌ–±.cÌ@X—1fƒX—1ÆcŒÙ2ÖeŒë2Ælë2ÆcŒ1[ƺŒ1a]Ƙ b]ÆcŒ1fËX—1f ¬Ë³A¬ËcŒ1Ælë2Æ „uc6ˆuC®_»ò–7¿ \½üH*Ú!ï¾À^RþÈ´|ÞÇX0ù´yëæs©Èl³x¿$°“9„½>XŒ1'ĺŒ1a]Ƙ b]ÆO~äýw%\¤¢òö·ýº8[qfËç}ŒE«ð­ç¿ŠÌåâݰUî»çbÊŸÃê=v’Nw v2·ô^,Ƙb]Ƙ°.c̱.cˆu™-Ÿ÷1ë2猧?s™ Š´â=PëöØ ;Ý-ÖeŒ9X—‹[ß»ùøÝüæ—S¾ÙÖeÌhÜþÆWÿ賿ùß9å›b]Æë2-v¨Ë\¿vÓÛù@‡u™s†$ì“W_y!•b'`ű+R¾8¡.Sít·Üºù†ÐyhX—1æL`]f,žúüUœ}}ì£)ßlë2f4>üÁñPúú³×R¾Ù!Öe ‘"°×ði㺠*÷›h¬Ëœ.=p/¶J)ÆI°@i*«ï—V§;‡"µv¬ucÎÖeÆâñ'ÃÙ÷c8å›`]ƌƇº¥ç¿ø¹”ovˆuC¬Ë´hù¼b,¨Üob]f;ìU—9ôɺŒ1gë2ca]fãX—1£a]æüÚ‡?x¤{Œž’ÛfçX—iÑòyÅXP¹ßĺÌv°.cŒë2ca]fãX—1£a]æüÏ÷þü‘î1zJnŸ^»ý"–ø­œú¦0óÛ:Q_QAn<ódªP%v¤&¸ž Ÿbw¸˜éd¤Œ31 4ªQ!MT J'ë$b¿/SÑŠÅÌ*³ _ìUƒ'¨€„|æ`Prr汦j2sK´@Zñ§?syòËJය}‡9|½„ý~«¥ãZ7ôªåoÛèv SsæÄ©Ã5rô-0ØH´IT ”{LƒÂºt–£ì””]hÚqó'¡)zˆ„æÌqøxÉ è‚9ðJ›jæºÀëtÔx :sfÎd$î¨N+öÕ*-wH‚Íãc!}èÏí襺ӵÙ2ÖeÆÂºÌƱ.cFúÌøàC¿p¤{Œž’Û眫0â þâݽ(!'ÖO\¿vEQL0Ë©²¨v;8©Ó¤jsT("!sÑ)?Æ™hX!£2òchš˜SG ò}÷\dý”àL cDôyN~ z<ꡞâ?3Ö*00+ç<ÍOÍË¡!§³%ZTW¦Zÿz¹Ú5f©ú½¶ +pÎãN(§té¸Ðcµþé ñ3åÍIÕ&¥Ž2i0æÄÁ–)ZfM:ƒ‰J ‘é{U9Rvó9oW/?—Jx9gŠª·©%ØQM-4;…éS8É=P¥ú ƒ…¥ÿœÒ8Ÿ|ÀËÖL’êC9Øé¨ñ–“Oh?ñ,JE‹ÂæåÞFNÕ‡²&œÛ8‡hkC¬ËŒ…u™c]ÆŒ†u™ ï—yäÇ~ì;?ôCCñû?ò#ô )¹}ÀašGdœ›uÚÆ…®‘Z'{¶eb“Ô°½K¿`ŠMp!í <åÇ0ð ÄœNX•`x€&Š ñ“{=¥Q÷#a H¦YuÄN˱”2“|ž™_¢¹­¦ajecÌŒ ]#¥ùô •qMÔpQ[îIœÒ8À²>R¹4Šo<ó¤.Råí·ê›ÔoõÓVÄ…2Ë®qÍjÕ÷9kÂBç~©n{V(ÇË|l3-Yi°ª£%úºLìW ?5ðÔ#®«"EÚWhÔ°]¶ê¼ÜKŽÉm¤²®ÓŒ±?c&Ñl ÅM"´ýÒƒ(NçÈÒóù÷—1ĺÌXX—Ù8ÖeÌhX—9þÞßÓB8ÏÖ8:+Tt‡TžÝv"% E6‘ÊhM'~ô¨¾ÊS{²՜䌺ƒ…˜ß!õ…pBñXu 3¶z‘ÍRR)ÁX'ýc §¿¸âB™µJ1^Õ ¡Ók õÒrƒÝ!EEQSGÊ)‹–BßÊ‘.ÍïÀÑuš¬ÛZÜ–ê¤i/%¹v1³²–¦µ  j0Æ-·WŒk醬Қ.­8KÓT§|ÖGÛ˜ äjY$äI©¼õXZhu*çKmh«ÝU‘‡­È_ÃD×Õï²­Z¨*Ý)3o| ¼ú)­(ÆE¡G¾U[ù‰†1_Öb¦òe6­‚æ?毸 €¦©ÕИˆu™±°.³q¬Ë˜Ñ°.s¬ËœŠ+ZñLõdßQ(„¤ŠšN†Oò'†dŠ:R¨Q¤‘ò«Ð2\ÕÈPn”½ÈàÌ?›whù¶4¿*÷›¬Û“žÈlŠKÚ±fÇZ„þ % #‚}È:qÓ*nlÞ`ݸäÒêpTfã&´ŒL^$Çto¦µceŒ%fÍ@Y$ú3 Å*-´:må=:ÒÀ;ÐC¤ÖŽÕ0[6µ=¢…ªB‘ÙΣ)Ò8(ÅU+a¤x T§EÏ1ìL^¤Í_펦:>h»Æ¹Òütî/c"ÖeÆÂºÌƱ.cFṵ́.sZè0î‘êq¼zÜOèDŽÊʬžø#ò'†OÊDì„ë*“–#ócŒè<`/H1øQ\ºú͘+Ñòmi~Ž¢ÓDÇ?©ˆT;•Y-JB¡/®cÃôËšiþ[LŽ SÚŒ½«£ŽKëÆ…kf"¡Â¤URÕ;T£” ‹j`k*˜_Î眩®.w¤e|i>™³( zˆÔÚ±“6µ^Ñ‚Ì^zà^T(‘pÓK¢?pPî¥9 ª3 …+ÊFô™«IxM$¥§™jÆáGªwÁä´“°.3Öe6Žu3Öe€u™ÓÇež›ãi>Âã~<¸žÑ;­€Nä±­÷ÊIÈŸxŽWædêXŽT‘ó)RVÆ9H‹Þø áç$¥Ò·–Ï“c)a&'Ü“).n90çÏìÒ/ú“ ›qMµÐ—VKo]aB¿÷—Ua×q\1¨ÖûdVSQÎMű“ÖVT—;Ò2¾4ŸÌY”=DjíØI›ÚÑ‚ÌN¦ÖXý¹!?¥­ô»«q€Yb[ÖäÑÅÎa©ºKO3Ú™“¢+–Òlë2ca]fãX—1£a]æX—9-´ââq(™:£·ZÈc[6LÖ"ò'žã•‰†ð§ÃÌÓ?jÒZÊr5c~õ3eÎ$ˆyØŠ †Ð²Öò¹•ߡՅ8á®à@Z\¼ûB|G•ê6hQÝi%² ”©¶ŽN2®Ï<‰|Y@BÍÖ¬–”’MIváK½µAAuùöÖDï)¿µÕ#(BXHù¢e|i>™³( zˆÔšÛI›ÚÑ‚Ìâ¢ÏÌ÷Cõä†üTN§@)«¥2ýrsê Æ¥·_IÚãÛ^P‡/[!Á`‡t¬XJ³q¬ËŒ…u™c]ÆŒ†u™`]æ´Ð¡¿Ïà¨ÒtL×½Õ èD ÊdÃòÐ/äO<ÇW3OBuP½!:O؉‘˜Þ¡ ØxÅBHQ æ[¾-Íï€Êý&šð»b‘'-:ó_¢P³ßuu͉O>.xÈ÷F±¯ù¦´U¸»RP ÒBt6–óY½O³¤e|i>™³( zˆÔÚ±“6µ=¢…I³Kéè ,òsæ½ÐrUÒ•Zƒzì$—úK†Ÿ)¿Ïä´“°.3Öe6Žu3Öe€u™Ó¢DxÜOÇqÅŠKNDÁ‚‡{$½m>!â9^™ˆ1”yªƒŠ(˜)à ‹ïYPÍ™0ü‹4’þFiù¶4¿W¡ÓdÝ®˜4;…sè(UQ×IäŠ(âÓ>'nÜÕ¸àç ©ºôUbïeP ;GöŽ·+W%B•ó9gª«Ëi_šOæ,J‚"µvì¤Íêž—ÙùwwŸþÀA9yÞ™@ËHéÑš„cÞÑGÌ‘XîOÚïûP29íÆ$¬ËŒÅSŸ¿Š³ï£}4å›`]ƌƣýe<”¾ùüS¾Ù!ÖeN‹j4aœŽã#ôyŠ©Q»QÔÑtÊ?î;ñÌ"4¨þ¨‘ªñX QâõLÔ{UDPé ó; r¿Éº]ÁL¤±r²#µuÝÚW jpNܸÃq)î¦êŽ€«¼§àJuã–”bX?¶%˜V‘à  ZÊ- KóÉœEIÄYJEdÒfuÏ+sWŠ0ŽŸÕÿÕ­µÀϘ¯ÌÖ½ m’h“×q8QÚ“jSvÄ=Àj©¨ÃŠ¥4ǺÌX|÷ïþâúWžú뿽‘òÍF°.cFãïÿòÆ×Ÿ½–2Ín±.sZT£‘H5$‹a@úó,Qü™*¨†d ®Ò9žáÒÉcc fË·œòSÃANªÓA½—Sg8Ò²ëêBtò;t ëv…têû5–"'«!1ÂÚ8çý}4¢äÛœ¸q‡ãÒÖêt—Pï˜î4!ÌÄOÕ±T°Zu~d!å‹êrGZÆ—æ“9‹’Ðú–oô “6e!îù(”T•”¥ÐRuìXY–¦F=©õœQ…êèÊçU|ŠjŒ¨ÖY—uwÁŠ¥4ǺŒ1a]Ƙ b]æ´¨F#œÑQŠózÊW$€¢Ô‡~…åq\E)ÆPðÀ”*¢@óª4ƒLXhý=9ÁA1ÁàõkWT„±Èê"]«fKà¨Òвâ¼á"ÖB´ò;T£¸v®ÞšØ44ulÍjBq R ¶Q„®SïxÉÊ] ¡µyÒæ™7.¬Ár£jæ1„TÔCÓ“YÞ8œ\ÀÕX*:¥-Ë¢µÜ¢e|i>™¹(-1fX™ñi0i³µç9½Hð¶úxÁR¶vE‰¦ ãs#nøøDX—ã‚ÚCI¶HÍÙ{YMù¼hÝ¡pøu+KîîKi6ŽucºŒ1ĺÌiÑŠFÏâåQ^ee)ªá°tvGªßÕ#™ÂÉž×å9^1-š @€|5o"A'Ù5–žà:µŠ¨®SiŸeÁy‚9´\Ú¤«óó;ÄP£Ž-üaéÒ]‡F›‹½ ©U œHh+W•+#”e>+£Ó¸7J5dfܸt\(bedª¦<‰5ç ½#©4ú†„;(U ¥“BóŒ:¨pí ‡¥ÊI´Œ/Í'+‚ùòq„Ÿ@&mjÉÒžíöKÉ2°æÇ&T_0B^ïà(U›Ø?ÇÅwZŽÇÌÖÝ T ­Ri4ŽÔR™WÜÝ+–Òlë2Æ „uc6ˆu™ÓÇež›[gzœ³QŠ3wÊ8¾³´L¨Ãzª/RÀ„&ü+1Ï÷Õs<²´š'¤ú-è6Cˆü+¡¨ÿÖ›8„!ÇÓáÿd+!¦¸"¸NMZ ÑÊïÃV1Åhð$»Á[i\ MJq¤CuuÐEéöì×xcjõ;?n\4.Ü-O`DÕf¢7ƒ U›«/\´ö-ëT›GQC)‡Gå$ZÆ—æ“uÁ|ùT‰OÚììyÌO”ÆRB/g]B‡MÎjJUQ†ÀC6/L•nG¢ÿå $Á%•F–ÞÝë–Òlë2Æ „uc6ˆu™Óçlœ˜AëÛ²Bʰ€°‡u&}Q "ØDEì”e”ª!@Èæ‹>IÄAéÃè FdmŽp ¿¢ãçä`« Uœ7\Óˆ•Ak!Zù“`˜µz''ß0×—]´Ö´&$NÌöí¤®û Šr 3}[4®TyÒótT÷9v2K±.©HLV@‘\MÕ&—»e|i>Yº(õ5ái¶'m"ŸZ{.½ñA‡.°Ä‹n>4Ж/ÑÜÞçR—Q¨ƒ´Ã¿BŸKÎMÌ?>ØŠœj¤EÂĹY£s¦ËHü=ɺ¬î½ÅN¼Ú\ñ¥¿_$-³_LX—1f ¬Ë³Mþã¸þW?5,›}Ãñçïø«qù£L}VÄüׯ]ÁÄmÄ"°µ-SQë2{eµ2Bùà„7ÂÎu™x5‡W_y½ô˜ŠÄ:]ž£ v,›3ŠucºŒ1ÆŒ¿KÏÍg‚¡b¿aYóë}»Š$7ÅŠm¹bÆäœé2àÖÍç–~[Pâ$½·8¹Ws˜³-×é2þ[R?—X—1f ¬ËcÌ8œc]ÆÌaEÌo]æÀ¬X£19ºÌÉ9ÝÞOœm¹Z—1çë2Æ „ucŒë2gEÌo]æÀ¬X£1±.Srº½Ÿ„9ÛÒºŒIX—1f ¬ËcÌáÁ¡‡cqß=_»ýòqÝ?7?ý™Ëï¾ †GíÎ7 2*\¿v…/c¿È‡5Õx‰LUèD&¯¾ò:•AiP\zà^”–_O@#Ê¿ñÌ“qt¸^úÿ›0“0¨}’F„ÒÉ`Ô± ®'#´ä6˜ônÀ™Ø„½,ŠùÑ ]e\à%AQªLÊUCÍÖªMR¼3ÃÈç6Hõ[u’½qëæsiz«õ‘‰.Zÿ(ç$k4ÁU”ÎnU5Dï±&™oY¤»£ægRÉ`D±þ"¸L@™D’éÐÇd’2’V5[Û•SZ;0ͮ˩[Ý{‹–W;|ôñ¶ôœ~Šøù#ÖA¾L‚‘V§™4U]bdFÏ;vÌ€X—1f ¬ËcÌ!Á¹Ÿ‡ã”pœE~ò:µ¯Ý~©Ú MªçxDŒÑêW±ÎÖÇY!¡‰L „4[M2a×å¸à˜òaöÈ@N‹!vD·«#B_˜ŠØD Àh«Ó ã=®T¤êTŒ¨ÚÜÆ"ê:µJÀÖl¥ä0^¶F‡„î–†R­£—rÉZCfªNÔê½Ñé+ƨ€ÕªS½z–î"­#.Ð)¯™P?Ö\·?[wú‚ÿ|Ùj;ùŒŽRPi‹ (ÕöÓ„`´†ÜÙ0HÕáh°)¥©[Ý{‹–W«·wIÕI%t¤ššmü6©Þ¿i6Hœ“TÔy¤šfL¬Ë3ÖeŒ1æ(<ÀÉÇqœt%sð'/R+P6Œm™_©YŠÓ3/Ô6F)?t^GM”ÆÓ6êWm²2"tŠH56¹Z¼GöS>úb¾š#ºãÐâxS8Ý­ð3(NŠR+ ` Mð2 ÍKåBA/lbÔhp¡¾ÊÙÃX¢',zafßÉzG55Á^’$ë²ÓØ/óc“>qZp]Ž"VÆ„°2’ÖhöÐ66¨€|Úgµ…«ÌAiÚX#ù Á.e_¸Ž•Y³øê5Z±‹PEØ*¼@XÆO j+,•"ẜ=^¤iY íDoEtÞ¦R-VœIMˆüÄ=¦|È ‹ÊáÄ!ó­í¤÷-¯˜4Es¶wŒMb+¾$qW°+ð‚»¢ÿxÔœ fÌ—è†&üE03x k±¦ë2Æ „ucŒ9<‹#áØ˯Ý~)úËC­Îî8òòO"¾¦ÌVHÉój‚„ë8"\k6RG@ Ë"9™ÜˆaIÌXö…Ÿ)ZÖBã"æÃ½ä|,í ÷ª‹Bd¹œÉ8-3çYÆ,Œ ?æÈ~9·šC¤TºnoHݸ^|æ"¹ èX9Õ«×H¥åH[»6™Ogbi¼ÓWXŽRNš ÍS93‹o¥ò¢¥GJî­>üQ¦&„)a>,Ç| yHÃQ>üLO8ŒL œÕ½·˜ô Öfnïò<'!³H¸Ž.áZ‹•œ‘eøói ­Ò¬‚òî3cb]f,¾ûwqý+OýõßÞHùf#X—1£ñ÷yãëÏ^K™Æœtð-Ð:ô+²ÅÏä©HɲòËó} ˜qQž­Uš"Šl‚Ÿ)_'ø”¯àEe/ ,ˆ-xà"u—fCña+ ªŽKƒª.J5æ¼uó9f¢U9á ï *EMBž´l.gÉ­w Ä?òkW§WÈÿäÞº½¡E‰™-P •S¿«×hÝ.RЋ”d ±Î²–©º1¤¢"Í¿Á«ÈTZâø„AJîy7Lœ \ùBƒM÷6LŽê·Þ{í¬î½EË«uÛ»ƒŒh*Ai5[±´‚ÒØ—"ØÖRb!X!yØAs˜¢&Á9AªÆ™„®"ÍYëE‹¢Ê­8V• ®ÛZ©V«-¤©^½F+vО„3U¬³¬ùiͼ6Flµ‚Ö r&‘)÷’ÿÕVšÖü·ÜÖ†‰ù8ÒbµXÝ{‹ªW1Ñöî Ï;#¥ó°YÝH- ÊOOy8s*Ì€X—‹ÇŸx !ÐÇ>þpÊ7ÁºŒ=t?JÏñs)ߘ³Îd¼ªgqE˜¹~Ð`ë¤.ËÕƒµ"‡tï@ƒÉÿN~+h­†-&ëW'„™Ve¥ÕìLNiVvK"i…F&—irtàÒ¶t†Cy8³2W )nkÑÞh‚49ÎLòmõMγFCqYëx»Â²tÃN«ê´¯CF ˆ3‰^ôtŠcÔÀÓóprB´W“Ûš„˜¯Ì–µÄêÞ[T½êä‹êöî ÏÓ¶ŒLÚä:& ­9ÑT UGó5#c]f,¬Ëlë2f4¬Ë˜óŠâ­?à±8›y˜FêD::§¶Õs¶è[žtgqÁˆ¨úØQ™¯.ZCk5l1YŸ¢Z™É†-XAS!ÏSµˆ*¨#º‡Ô¯Ö1yØAžÈ·=‰n”ÈHG4$XtÖœãáÌw+hZbt'—–î ‘PŠ—­7Œpf’orféÑ.Z°B\)Yk-PÃh*Á 22g#MŽt> Ñ£äD¯P¤ë茚$¹yrBZ£š¯ÍЙÞÈêÞ[,ò6ÂÕÁ¼¥üò|rÅ;6Ëe9¡A&´mMšë2ca]fãX—1£a]ÆœWtï^y,Nçff"u"«m['uª«–;#¦’WeJ>€V< .ZCk5l1YŸn§ aæœ$á@žO¦ØÝCjWë˜<ìÐY&ÐÚ ™ì·ß]b¦YMK´©¶+öÚÆ5ÅõÅ»/”ê ë$ßäÌÒ5Š=öS”Ÿd­3Ÿ+,·œŒLŽt>z{æ9åÐ8ß;ƒ°°÷˜C&'¤µ1ªùKǸº÷‹¼´æ§…<Ÿ\ñŽMî´d¡?'÷…ÿ醄k*qæL`]f,¬Ëlë2f4¬Ë˜óŠâÕÓ-á7›uêíD::WÛ¶Nê<¦#U-·V+Ç¡¥hNZçþV¾º¨:Z [LÖG* Z™‰ŸH•ø¥ òAHª–P@÷R¾@>+$;´–‰È`e šŠókUîGÓ²“÷ˈ«Gÿ²—FP3}­×=ù¦&K׈Öð:$CkÕå#+,ã%Í&'#“#]„œäK.Ÿ^ês\b}%M¹‹äykBZ£š¯1Æ­Õauï-y¡çšÀIäùäŠwlrQ’…É9Áj&¥¾ãƒ ë2ca]fãX—1£a]ÆœWtïü9‘GÛtnæa© ´åÕs¶è[–Ãñ8®L´-¿¦”“ÿ|Yk ­Õ°Ådýê„0s~/ :9“Ð=¤ÖWµÖ±Ã¤'sF78‹<œYYÓ·\:áÞÀT˾ÞÍA83É7U^ºFsæ¹DÖ:3¿Âòœ™×H[3¼ˆûî|bˆóFãê= 1Oßù4\)—LNHkcTó•Ù™ÞÈêÞ[´êOÚáÎ_ty>¹â›\£darNÄÕËМÊf¬ËŒ…u™c]ÆŒ†us^A¸ÂkçÜÌCm:7ó#H“î¥;_ÖDŸê9[ð˜ŽT 9Ä~ûMXšüïä«‹]'“õ«ÂL¤ô^† ,S¨ßGËÔZÊ9ÁU¢ºL®5É€ó†Ô#¦ˆ5ç,ÊÌÊô0ÕÙáÞhý§3f¦©^½F´†4YkuÖY®9¢EïlŒùèùF兽ǯ›‰ëU~¬ILNHkcTóõ>™÷éêÞ[,ò62{yž¶edÒ&W-Y˜œ“Èœ_sf¬ËŒ…u™c]ÆŒ†us^Ñ_Œñ³üª  ?8§s³$€ÎI—–‘RäV=g Ó‘ª±"‡xg“ä¡h•¶òwœLÖG* ZÌÔÌÏ *À«8“&J‘ŸZaþi Ã×l4Ç’!ÒÐ4d$\s ‘ç´YzØAnÐ ŠPÕR>Pô΄šäøu-ÎÄ’Å e¤B“81¡!æ¥U[T7UšÒÔirrQw `e‚?±2X·7J¯ð½Çj„Í[S½zí"ŒE`Î*¬ØŸØ(=®z”ðO©ër†Ù~¦üI´( |ªD5¼|ªÉ imŒV>)ž¸†·é]Ý{‹uÞÍdÊïC³Ç#<cÔ…'m²4mìÖœ´~¥jfd¬ËŒ…u™c]ÆŒÆ9ÖepHy’;up’Û·«°Ï‹+€…–1œqˆl y M™»þ“£P[ŠÉ>ìÞªKG›ÌÜÛªŸòW3§÷8ºÞƒDÖæìd>[æ×_z©h«¬ÛEsXaYÓ>gÅùlì<Ï.qêRÑyâÀcTw;yž˜Cb]f,¬Ëlë2f4α.Ã?Zž‰“.ÿ¶¿S,ÃþI„F˜Ò”?Zh-ÇtcŒ>ÿOòt5Æœ ¬ËŒ…u™c]ÆŒ†u™°.c]ƳA®ÞùŠñÖGðŒ1çë2cñÔç¯"zô±¦|³¬Ë˜ÑøðÄCéëÏ^Kùç€I]Fo±žófàj5YHù%ýŽv¥Ë´zA&ì÷…¶)ŸÌÑeÐï¤ë2Æ#ø{êRíÿñcÎÖeÆâÖ÷n>þÄc7¿ùå”o6‚u3·¿ñÕ?úìoþÃ÷_Nùg~Ù»H øSØÿÉ;_È:H8ó«SüüÖї𱚾:ñÖ¿í’ÖHü¿òÛ7ÑQü»(›°ˆ× } àøý¯´ƒ¤^輊x ZAÂuüÎÎ4W¼Qýá÷²JË0vP„Ÿ)ŸÐfÊ4ƘsÌÓGÿ_ Ï”oŒ9—X—1f ¬Ësî»ç"Nº8ïR#À5ØÁ÷#Õ>ù‘÷j Èy5|/&uª*4‚Ÿ”P ×,MpÁ:àµÛ/±3êã%’¤xŶH¸ KÿvŠÃ=š£/4D/ü·&tãÖÍçh3u!ªô9¸`LJ™‰Ÿ² ¹B+±w€Rä$u‰Õð3f 4)ÓcŒ1æ|`]Ƙ°.cÌÁ :P ׯ])3ËÊÔÞRügMÊ+R.••² Yt3Ñ™­OMBçÓû}øÿe ,£BUø€{é{ ¤òÄ̪Û@ÎK‚)eÒBœá¤LcŒ1ƘóucºŒ1£¥ËT)uæ •_ÇHËIFI™U¥†P³ˆŸbÎj]†ÍK?EG—©RúSΩjO€õã[f˜ƒŸÊ‰ ÇùîcŒ1Æœ-¬Ë3ÖeŒ9;ÑeJ%$ ¦šÉwtšG¥ÔAAqf[ÒÌþtÖLoÕð$Õ§…ÖrÀÎ|÷Œ1ÆcÎÖeŒë2Æ Ê-!àÆ3O^zà^Ô!ÔJ!æˆòM"ߺóõºzw ›#1?Âüè3Wë2è~Ò,.⧇H_—Aó«—á7Ýšš¯Ëp\ æ«&-ÄQGØ$ecŒ1Æœ¬Ë˜=òŽwþä¿ùMo}Û§|ÓâTt~ (ˆŸ›0æÜC}¡*°7e€käàBuZJÀ­Äúï¾€j¼ÅðªÃ汋ÆÏ7±ùj]† GÚABÑZG—yúè‚°TîÙX Ë¨a­T“bNvªîcŒ1Æœμ.ƒÈaÿ{Þû®”oFà‡Näø™òM‹SÑea™Nõs¶àÎ/…}ê'*#¥îPæˆKÜ‹¢‹oü?Ù©£NóÚÙÉúôg.sà±ë–.ƒ`×ú·Ù¤ô§5œùžÓBš%;¥{ÆcŒ1烳­Ë\yâ8Æ1ýùKϦRsêX—YŠucw~)T¥„Rwh) аS½³ø+3µ†ªK«Ñ¿C’A\Ti±ô§U³5É%´Ðª‰K÷Œ1ÆcÎçD—Aäÿò_=ŸJÏ"ý·7>ð¡¾vãSþeçºÌÃ<αg]ƌƋ_~úWå?ø›Sþ9€;?~¶ˆ”¢Лh”ÓR"E„òËnì(½¥ k¶¾µw4¨..ÒeP™Íçè2YJ°&~¦|‚K÷Œ1ÆcÎg[—¿øàûÞú¶ô×Nùg”ßþÝ߸páÂÇ>~N†³[]æáG‚5$\¤¢sƒu3zè~<”žÿâçRþ9€B¢ýë×®`óëÛpyGà'?Ç„Ÿï¾pt‹¼A_è(q¨&ä¿vû%U£$\è3SðäÒÑ÷ «K(“ŠO„_v»(5&€:ÈDìßxæIJ6|S’Ä#\°&j2àš™¨€ëøÕ¬î¤+ÁTÀ¬Æjœ üTNF@Ê4ÆcŒ9œy]æœñøY—ia]fO0äCŠQ–1äë2¯Þùò&…ý¸˜O-€ð+c¢–A!©äé£ïÊ(x{!4Ë|—ᆱ]¿v…ùLÕN[h˜± üL÷»’4&\À78€‹d™J*Å…Šh„vð3¾ȺŒ1Æc6‹u™±°.ÓÁºÌžPÈ”¢,cÀ9ÖeÀ«¯¼À7§\¼ûB|Šò.ð™ŸüÈûãgŽn<ó$rÊ·®Pé†Ò·º¤.ݺùì°/€ë¨VdÞwÏETÀO}þh>è”z H¾‡0äj>~ò.5üŒïý!°Üê é?À*pV brð3f ë2ÆcŒ9Ç,Öen}÷ů~íéø¸~ô×F¨ ¾ô§ŸU~•—ÿêyUÆEÿ‹BPùÊŸèWF&üÙí—ËÀ&;p jöûe…”)4.«I—9á<XP/­ä-j.í+®”:Ú•.ÃUþÅß÷ºxp×]¸ ÃÉí<§KÉ«]Qî=¼Tqí›t|~ñ¥¯ýå_þeK—AƒH/{ˆ‹ð2iˆvØàg2F’D­&qb;º ºFX¥¶ŒÍJèOÇKS<é77‡ç|ë2û7î¦ûòï5THùpÞZ“c]ÆcŒ1ç˜Åº Nœœißúî‹ïxçOâeLo}Û·ÂÎ÷¼÷] Ôc‚…T´*§p—uÐiÌ\ ŒÃûRB¿øàûb5 E­~9KH¸(‹ÊqÁÇ%]æ$ó ~ï?]HõŠk84ˆÁ&û}=úë§úxÉ3?cý¥¼üWÏ'û1¡¨\ª›9åþ9 œaüÄ5æ§œpt‡µ+› UÕ.Ì$Kï¿ÿþª.Ã?¶Çà„‘ s¾uçÃLßø9ˆÏ<)ýE‰¡c_—¹uó9˜Š–™SFžô)ý½ÀKÑc*"èˆ,ÍŒƒu™¥ð.H7 Ðûeªo‡1ÖeŒ1crýÚœ[pæ©þÅëÌ_ONõœfæà 4{b½.ƒ@T¡/.bÌÒÔP)Jq Ô¤S‰ÆU1g>ê+g51þÇEt?cM8Ìj­~9KH”'„Þñ!ûê‚5K]fé<ƒ÷¼÷]Ç5BGjˆëT_ÃùÒŸ~¥¼.û*å !±‰ZIÁÏÔj‹t\kH(%ǯr~ï?­ú'áç•'>Á.ÊîÒlKyIJ‘ç?ú£?Zê25b¼']&‰2HQûˆ_NÁðF•Q ðºTC@ª¦* mã›_úÊ‹T$½['BËø™òÍ)b]f)ñVÅžÇmõôg.ãÇí]ê5ë@/0>Iùy¢a·˜>aô€ÿ|É"U6æüg…HE;‡o¿M™»åÃÙ7cÒ$xVk:o>$|¢VÏifû˜@~:ø ýÊ6û`¥.ƒÄà‘¤þò£úŽ"pe~z¿š”oaÐ{C¢q€®Ùi#ä†rV#9ÞÆ|¼Lö×é2ÒÐ*¾ùè;®“.ƒ´hžÁïýá§Y„†qöУ˜VAÃa_ø©€f"a]ÔD¥,BŠBƒœg‚­;NJÂ^’´yâÌÄáÇIƒ?QÊY j~0«2ßCgÞ2³:'j‚ôŸþ¿‘îU-Hñ©#\à—ÄgžÄï~Ô‰5b)bB PAùLéÀšªpß=ãy"¶M¿™˜ŸåùC'¤òwzgÑ®W³¬Ë¬€oOK÷^â†M5W£B?¡ÓÔpX½`ÒˆxP(³úÑ0cÎ:ø]‰ ¿×ÇEbç2qO¿çàùäcR,«æY /aªüV²À¬-Bmq g`A9fû˜@ÚDj}Q€Ùëu¤ÞIH1*¦Ô‚¢ÉxX¡>*§Ï€~¢'aw¥<±šÂÏ”_"!£ÕoU—Ñ{%’î)u¤ùó $ÀɘOTçPÃAB…´FqEb>‚VzˆVò°l¸Žê¬F$ÿµÖ…ÃG*^¬!QV‹È™4|MKR”â* =öñ¦{•Ç<¸£Þc³ÖoÕ)+ÀÍ2¥¢ æWÃ!T®þQ«RyQ}¤Òœ`XäßICa]f5¸¿p›êÄN‚¾Ëi’ÔÐ3åHbjýZ_ ?sl}ö/Þù0r5í¼»ƒ¡I›ùDí/+ÒÉÏ9}ûeBýÔöì.ǩә@¾=*Ôç€VG«ôz*Ïf;¬×eZ¡/"^Vˆ¡¯"Ø‹–¨yèVa”Ûrf45GDX§Ë(³3´R—Y4ÏÒPbf¤êƒ†ƒ±—ZÐò%­§?cñ;©hÕYÈÏÖ'•:Ó Ô]õCI€óƒ•8½ë'mæÿ£ôæýÑÅÅÿåÿüL÷jõ×€4”¶?'ªßj_´ŒÊÇÏÖª¥¤Ä¿¹¡—23æËl,ô³Ì7§‹ucŒÙø­Í_ˆH÷Ýs¿%©¥â7»òwõ–ü×_Md|·‘9<§YØG_/9Bªæ !“:è<ÓZV\, ݘ^LÐ>~¦|£}VÛíêoŠÖJ^Y1·|—žpc˜3Íz]&…èB¡o¢ÊPü…BýÉwÖÖ}­FavKÔët™(´f¯Ôeͳb~”*3"¢” ÌèmDÎTHh5Sþ:ª³*ô¢~w¬ƒ4)N ÓéNËQÝiÞhígßõÎw¿ûݸxË?zs|4?ý™ËGò—bâ%ó;úº~O§|ÁR`°ói£Vh-Z ‚¸ýž÷¾«”æë2Õyflô‹¾J¤DÏ5TPfù¬Qf«Xºš}ú=N. ѵ&v>4ÕÝ£w>¹–\ªN 3?ýo~ýßý»wÔ¨þá ô¦i­³Âœ_Õ‡,WÏX¢zÐY3ž&Ù Š$ÁÄ“¨Ž‰~çhX—1ƘÓúÆÐï}üÞLEKáï_tÄsÅþ¢Ç–æ¢7Ì"ųÍY¡zLZ‡–u瓪G²VÛ‡¡5û»³ÌFؽ.ªa'ê3Ÿ ×ïyï»ÒÛ:Z§¶h³ŠÏçʬÄë_|ð}¥„4)téLïxçOFh¾.èjœ«d¼“¢çNUïUg:c¥‡'¡ßcKIhŠ:nÏ„¦:£kíì|ækÿS„©ÿß÷þê?ÿçÿÌ2Å£Xëwíþti+st¤ØV"Küskò@V‡Ý!ç,þ%í|c]Æl<ÇHÊ/AP=¿2À“mQ}ÙOZü Ô/HE}ؤóLÞ¡“€¦@ʯ²tþ#lµÃq­›}¸õ¾ d…ø»rè"ö"ˇŒù{©¨hÁ^:ÉdiCõ¥œê1i:¶ícòËÃUV‹è5ÿ ¶ô™6ɤK{ܹ‡¢œ@‚Ž^_Úý,îºçŒ9[N—!hÎR¥êjú¡u„Öæ×Ÿäå£ÿŽÄuzï̤Ÿ}ÖÒ+½ãο:Ú•.ƒ‹>QÓpªÞ‚ª3ý1’ÒÓÐïQ¥]*Š ”Õ:nÏ„¦:£kí½3KŸ˜£RS¸q?þ“òOðR¿Yñ>ª^9½íO—Qæ ]Fù•¼äo\GõÛ…õ÷ñ›Ìœë2æÜƒçÒ}÷\ÔÓ ×ï¾P~~9©&+·ÎÊh‚'[2ß-˜À#·´¿"”ÅS^•¦Z]³2~âÏsý @fù‡]9 0?ÉO\ÃÉjxV®^ÂB¹Xd¯ãºzôÜ«¥~ýˆHIŽËͯԉmaªó¿Êú¸æ{xç,ÖLtþ¡“»…ÎãgÊO°W[‹“väÔëmñ²¿ßpã¤EÁuëžmWjòÆ\Úã̧.2IÊ'˜––+…LØä‡ùL|IZO§ˆ,¤|p’çŒ9[ì^—™ó5Wžø„>у¤yæW„DX¿НãÑ_X1*ñ5=¬ø‡Ù#Íã;~Æ¿Ò#l@Í!ÙÁ£Röq¡°ªÜ‡ý¢>úÒŸ”c Æ_.öŽŸ8<¸ˆÎïÐI˜e$XãÌ\Ó‡8EèBΣ ­.Ô5ƨ&dOãB¿ÌGCÕÇTÃ2:‚cªÙ‚þàgÊÈ«9qÝ|àÍÂ~*Úš®þx#tõ±"hÎLÎ0M!)_pÆÐŠÓ‹—ØÜ'šLé¦H YÊ&]3S ™©á"dpO3ÏQãgÊO¨Ú‘/ÿõ†Šˆª‡Ñÿ¸(:ÅMv-8áøÉqQ½1WôHƒø9ùÔU͘)0!G=T¦‚ c>ú‚ñè‡CT­¬±aÌÄi¥ëž3æl±^—©ÆÆ@BFü€R‹2²•²€U™ÐFmbçT»`fô<¢IhÍRDÑûW¿öôõ¯<…èÓW]7Ïj5gòÅ:]fRA…þ,-Eo?iù©î^n|«tõË’W£½ÚRÁèOµB .ºD]é-ÿèÍÈăÏ_þÀ/§t÷<š_·Ò=+°9~– Ɉ~ T™ ‰/¥or›¿KXM¿S»¨óÚí—X³Ó‘9E>õkÆC镯?“ò9èÐ_}À"3Fã8s—a?ˆ±ø˜EeŸTëa^õ„Gv¤øí#Õš»º@Âu*%»uRõËùÁ4¢4æKi­K6.õ¨`i ùú¿øÔ5\Ñ㢧nº:· –ù'¹³Ð “3'|Θ3Çz]©”Nô—¤9oÙ(u‰-©bÔÍîNK—A*‡©7’ µ„HÔeðòÛßù~®›gåãgÿÿ‘GÖé2@>”J”AÂE*]‡ül½CGoByOã?«Âœu™Dº ˜füÞ~Z¥©h¥`„^qƒI—ùŸÿ§ŸG&Ð:TOº*íüŽïgù›€)á/¤ê¯7…"HUßXª!à"–êw'JY¿bc3ßùÏRŽ1ç=¦ð@KE‹Ðé9>Eõ|ÆãN™-äIÊ'ŠOªñE´:ÒïUƒa°C'ûWB•[]ú†”f{OãRÕ²Ùgfü¦-„‹TtN=®@ˆ„ëTºÌ9—¬ô_Ë]Ý„:x$yH­ª·jô¿sÖ*“ä¸ñцÙëQ‡}ágÊOÈ¥êéNO³TªÃdkgöN4ç¨ßº‰Vô¸Ã§nç6aÃ2ÿ$w'$9£ÌuÏsæ8‘.ƒãÛ[ß}Q‘j©b”‘°×X9*)ºþÒŸ~–öc ¬àV9ë€M)õ‰&ɽ]­¢N¤|¦8j„ß(•ATRbѺy-ÇƘÆ"½£\#"g’ú |8‹°Rªè$Äw»HuŠcD¿¬€T¾cH3³+´ H°‰ý¬"ÌÇŽTzBÔœ5YMºÌçïß²´ú¤ú Ô9+Ä#EüE…§¼Œ³4‘qTH¿áÔ)o„þ”Aû¨Kã¹ê¨ÖnŽkÆ3“V¶‚ê£XÏÞôô+Ñi¾£hT¤+à#ÖªùHñÍÿ‘Ý:ÙŠýªè·I'¦UäÞžÆÕên&ê´?WÚW¸HE'afï»BK°n®ª´vûBiUim œÖð3fF4XHE-tÈI ™˜‡=…Ù“!¬VÎiíºIãšü”_ESÚº1ÁŠç?uAß~ç6aÃ2ÿ$wV9pÂçŒ9s¬×ebT‰k @éË;X„Ÿˆaè H1 ñý&2®î¢qZF©rÖ!m!ÓIuŠÌ–žÂRz¨©90¢&´†:;íc6bÕ(e~ô!õ‚‹4ÏàÖw_ŒPŸ}µÅÏØdµ.R_„9¸à<¤îN‚Œ«;\ÄIÐÌ#±rXM™å(ÖAgØ‹Œã:v‡ëÔJÄ}ŽÄ÷=I—ÁÉç>S+l¨%ú›ýD¿p,fQi„¿'˜PvðKBm‘pš}|‰©)'!ÇŽ||îS&ZqD%‹f‰•;®Â­-íQ™¸è¿k¦?]°);©¨5&“ÐíäÌ Ÿ3æÌ±^—Ap‹ÀRñ§R5îÕ[RBåò-* j©¬Ïjèw>Š®SªŽÀ“ÒIä ÀF}¾ŒJGµ>Sz X7Ïäå¿z>Ê^)¡aÒ€ªÞF:º rªóƱ!zŒMNÂïýá§ÓTàe’ÌÐiª£W[“¶}Ýúî‹ÕÞß–zû’¦(ê2|F3µ~µèÐ'U‰ÒŒºà¹/«Ft¨*l¦Ê ý:A*ã|\æ?cŽžŠsÞ²!ðÌij O<ß"4•tx©"$\ã¡]þ©\OòÉ ©mâñhM®¶ìT£‚Èn”'˜ÏTT¢ÊÕ_RE¬“zß߸ô~+&tÔ#-ot N¦¢“ Þa?íM†ÙY»>0‚[®Âˆ ÙÒÎ*¤|Á¶±áœÙ Y¤Õ£ Øí2Õqr5ݤår"š¸ë”9'Í™%ÎCÇÕÕ=âšdÂ5R}ƒ«µ|åD±a™ßi2IkBNòœ1gŽé2x‰)âOòè¯?+G…¢­j²rЍ#(BU~Ç;²ªàÀ&èô»ˆ/ýégùöŠ~§NÆúÑ :–ÞÏÂAÁ¬š yùž€¶ëæY¤±XÀpÊ9¿õÝé-ß²Q‚|VЧ‡q¥Ð‹ì¨¡jžœ8ç­*ç9zµ+` $IöÕãäÎ!p’ó£·ŒE]¿¿ñ»„¤ûVàØÍ s¾A‡€ =ÙѶo„ž°!AX2ç0Í/¨­°‡¥`Ž5cŒÙ!x”ñ÷l<Ó÷I:5ÎЂ9¥)Äh¥ H¸ÆC/ÖÁKõ™TÃI ÿ˜dA/SÖ/óÅnDµ~wVFꬔ"¢ds¯ã¯`d²9ªu>—AMÖOù‘[tš+ØOE;$Æ“ë"IÌ$gI / _–þO.7ÛÆ†sfƒf‘N¾ñóMé9prh¹3|RNBDÝS&šwèLc„SŠú)_œ¤Ç9O]À ø™òIgc°a™ßi2IgBNòœ1g‹“ê2fOxžÇ'é2;!ê2é^5ƳCtÒù~ž›‘p&8‚«H±}ÌŒ N@žæ™.…vªy9¬ ~#BâèUëô߉ Èn”‡sDyUnM/hED†‚À9!ëã'Ö+ :Ôø ZsµCI² ¤Õ¢Ìqû£wÔÂ`Ü*œ½ÒÿÉå.Ι šEÚÉBèÉÓéqÚT)?Ñš=¢ ‰wÄÎ÷ §´ãêÉ{ì?uAº:´&ð$>ONȺçŒ9[X—ÏóøX—1Ƙ³Ë¢€\ü¯¸e çòT”PM¯/òdœÝi ©´Nÿ“QÁndwH“3TÁy*Òl\¯Ý~I3Ÿ|¨2gPŒÁ:ίãäoاçHëD ù©Z ýÒ¶êÌXÙP³Ñi%gæl×I´åJÿOG×)'!¢ ‰wÄÎ÷ §´ãê{Ô„£»(ƒö§«ã@kOâóä„¥Ïs¶°.3(žçñ±.cŒ1g—¾Ô’Ðɾúæ•â\žŠJtªVå–¦°žï‘ªoEiþ[ùb·NjÒ_°«Ì©¬:i<.l“Á˜”öçÅy^›Ï#Þç$ ­e@&YZú?¹ÜÕ†ý¾Í"͹Á'9‹ï—3Ïdr¥À{,Ÿº@>Tß³¦wl•EÇÊ|@¯›;*¥A\À‡T­ÕÐ –c&;:ásÆœ!ë2f¯H—Iùf#X—1£a]Æœoô7ê2!ç`ÕÄÉø¸à çiEb±¾b¹2UôˆŠy4o%ø3óo° fRÂùž^ÁTjR Jvè$@\qܬHåaþaü¸¸HÕ){W§2&_Õ&é ùØœ©>ÀS…TÔ¢3Ï1¥0oiGý Œif<Ù2ˆ=Ì"ü¬6é8ÌÙ.b°,J ™ ‰ù2Þà-°OZž3Ñfjâ2%l&~¦ü«•“@4Øê2µž-L°\Ý´%“+%õ¸ô©Ûzª£Ó×î|”©lØ™À¨ +áDªVRfVÓ¢çŒ9+X— ë2ǺŒ ë2æÜƒ8 §yˆNÃÕ“4ÎÜÞ=!º0)šÂ¡?ÕoYh‚:± €‘9'ûH²ƒk†‚|ë ÆÊ§üj~•]9 0¥è:Ù¡«%\©Ôu§>Øß¸¹È“Tš€a"?Õ$èbi`ÆEŸ$EÔK;âìÍaÎûeî¯8-˜a¶å6(›\nUÄáÈÝá%W²˜/—”ÀBça/¨†Ñ¥¢™ptá“Î$ ¶åjù¨ÅjmÚô>ÇU²¨GìÃT¹3Œ£²îbäãe¹ÌoM`2ˆëÖ§##­ ÙÕsÆœ ¬ËŒ…u™c]ÆŒ†ucŒiwý]}~ ¼ŽƒudŒ1X— ë2ǺŒ ë2Æ3zKõ3&;ä`cŒ!ÖeÆÂºÌƱ.cFúŒ1Æ ߟ)ç¬#cŒ1ĺÌXX—Ù8ÖeÌhX—1Ƙ¸qô•¢oyó›æËÉ:Ö‘1Æa]f,¬Ëlë2f4¬ËcÌðËnð•ŸëÈcŒ°.3Öe6Žu3ÖeŒ1ÆcŒÙ+ÖeÆÂºÌƱ.cFúŒ1ÆcŒ1{źÌXX—Ù8ÖeÌhX—1ÆcŒ1f¯X— ë2ǺŒ ë2ÆcŒ1Æìë2ca]f¯üÞ~ú­oûñ÷¼÷]1óáGB&~ÆÌÓºŒ ë2ÆcŒ1Æìë2ca]f¯üð›ßt×]w½ã?3ñÁ÷!E/ÿÕó1ÿT°.cFúŒ1ÆcŒ1{źÌXüöïþ†u™=qå‰OÜu”¾ô§Ÿù/ÿÕóÔk~ñÁ÷ÅüSÁºŒ ë2ÆcŒ1Æìë2cñíï|íÁ_ú…ë_y*囓óÖ·ýø]Gï‹IùàïüÉVѱ.cFãëÏ^ûðüÁß¼˜ò1ÆcŒ1;ÁºŒÙWžøÄ[ßöãàT> ôŽwþ$ºî¿ÛåÏ_zöõ·Ê4Þ£·Òà"ë2ÆcŒ1Ƴ)¬Ë˜À·¢ }õkO§¢}ƒÙ5|HE‘÷¼÷]¬öç/=›ŠHõ«gucŒ1ÆcŒÙÖeÌ_—¡ìÒù¤‡pêe².cŒ1ÆcŒ1›ÂºŒÙƒë2úSúÙ‘‡yˆuN÷£LÖeŒ1ÆcŒ1fSX—9K|éO?ûð#=úëÿõ¿5áú­G_ìbþ®xù¯ž]¼ç½ïJ²ü|7 Ò/>ø>æ$?šÃHÇ ¸õÝi‡/á‰Òòïýá§QÊÿrXŸ 9¼dÎIßéh7ÀºŒ1ÆcŒ1Æl ë2g ê ü¬Íïýá§¥†(!g‡ïX¹òÄ'Ê.Þzç)þúÃÇYµD?Å{Þû®ª5$ŒH(Áˆmi¹e)J0üwKHýÉ¡A?-¬ËcÌf¹ôÀ½oyó›À­›Ï¥¢³Â«¯¼ðö·ý†pß=SÑ `n9Ép5¹x÷nqÂ7E2xýÚ•TGû÷Q*2Æœo¬Ëœ%¤ËHÁ5ßB"‘ñ­"«ùÒŸ~VßóÞwñM(ïxçOâ%P¾dM$¾$ñ;tõŽäÃÛhù¥4#]FòÍT3¬†¤RßdŠuðS9UfVÛ+ÖeŒ1f³ ;úmv×·žÿB*:+ÀsafT‰(5Á'?òþT´'8ÉÃÊFfÞrç„I¡Tu™W_yáéÏ\Æ&¸NDÔeh¹ÜöºƒP'cÎ7ÖeÎR7˜â'nâ;Júÿ1z&| l¦÷˜¼üWÏ—öß:õý2ð¦ð3åG·ÓJ’.à è‚ÿ„?£æ¢j¥²#h?S~brÀºŒ1Æl– ê2ˆTYÿ0Q(Â`öå7˘I¨žtvògžä{j޶ðMÈ)—ˆnë2Æa]f,n}ïæãORCR~•“(ú‚˜¤ÚHpAê¸1©ËÌn¥(¤ÖWÞë2f4nã«ôÙßü‡ï¿œò1;g·ºÌõkWõ]½üHÊß+#ë2ü„úB,]a®ú±ôYçTöC‚“\}×ÉIØ“Yî–ÖN¾ôÀ½G;÷8¡2ë+uÞ“ÕÑežþÌe•»Ôs¾±.3O}þê… }ì£)ŸH—i½#fæCæ Ss>u]FºIK—³“²Ëd¡éMžë2f4>üÁñPúú³×R¾1fçìV—a”ˆŸ)¯,ÕeK#|EZ~ÑÆÎA/ôíÆ3O¦¢ÝÎü˜œÊ~ˆ|òèÍJH¥qödpÆZ;™{u.=p/· ?ÐÄVLåN#]Ffw.3cǺÌX<þÄc>öñú¿ ’pÐÒ)v¨ËèÍ#o½ó¢{ÕeúËš”]æ¿ÈºŒ1%zè~<”žÿâçR¾1fçìV`|ˆŸ)¯,Õe¢ÜŽc»ù19•ý9gºÌÅ»/\zàÞ” °…Ø©õž—–.sã™'«ùƘ-`]f,N¨ËPÙ‰.óò_=O•‡ßóÞwÅouI,ÒePçÊŸÀXÈäç˜R~bR—Aó~¡šý÷Šu3ÖeŒ9Öeö‡¢wë2)ÿ`ìI@Ù“YÀ[±“'?×Òeø–®ÑîcÌa°.3ãè2½HpaÂËßûÃO§j@ÕZŽ[ß}±ó¯²‘’b]&ݫƜ ÖeÌ9æÕW^@€Ô ÅoÝ|¥å ˜¿;/b‘9@¸ñÌ“eýIu5¯^~D ;Ÿ’ŠÃù’¼vû¥T™D˸˜3 _Mô?hЇ0?¶¤c)”ùú¯7yÓ­ªŽ±Í<,3T'aæLu2†øY]…¸%äi-?8[¥ „F퇥ÀC¹—â­ÁRô¥/dáD¬IÒ¸Jƒd©Y0sÆgl…JËt RA¿¬€šÊä›eФµÜƘóu™±J—!Wžø„d¦ø È¤.ƒüøîÔ×ÿÞÞ÷ûeô¿[„¦·ßã^±.cFúŒ9ÇLê eS>2`C[ÙQºx÷…Vċ諬ϯíøƒøÎ¤„LÄ™±¦þV_Måw‘"ԯĄÌN|ˆ8ùƒ—ׯ]QÀÉÉ™¤ ÚgþÕ˔ݥ÷ohà¹2aáØ\-¡²j‚ùK@PŸ¥¸Æ0cÛôñ––e%”&a» KY¶Â´§oêYº–‚MRîg8¦y†çÑ¥¡a&a­¬ ’EfÁü¬fø™òÙPq°[Æ|5!*Bœ¯&QaJþ0†„µô…(ùh.-?ù’Äj1²…Û±ˆšRXªmÕ ¦ä S+"MÀ%Ö/TùŸ* /-JUœÄZ0hÀÒ%œ(äs°pã™'a“&€]aiìN öIòÈ[ôóùž äãglÂᨈ/‰ê¬CÃOº^ÂI½Ä¤¡/iv¸q>9c2¦E™@³‘Æ5Ó,X:c„Eq 3aC¤t[ xÈ å¶7Ælë2c1¸.øq¤¤qè&UǤŒTÿ³’J×é2 êR„&§EºLkz€u3ÖeÌ9FѤTD³¥|5D*C/¥,J v"•‘bÂh3ùƒè± ‰"Àˆª¨t^(¨®F­[=¦| øif4Û PÕ.R þÚí—TÚZ»ELî„K åFj͆&9 PE0žúÕîJÑ”¥ô?SþIXdSÒ#0å<MT¹W'ÍžpÆfîdoÿÖžél{cÌf±.3ãè2Õÿ­Ò”D9VÕP¤°T¥©!'Ôe:£V…þ?üž´s¬Ë˜Ñ°.cÎ1“Ñx+ìTÃKµ” Ø)ŠjU >©Õ|­Ao(›´œý /†/CçÌl«ògf4Û P5ÕéRG;‰l'wB‡ÖH/À@JÕŒ°ßê¨yÒ¿Ô¤¯•6[ù'a‘MhÅ’iã•m'ÍžpÆfîd¡½Ôz8€Î¶7Ælë2c1ˆ.û0òž÷¾+ ·¾ûâ;Þù“t i%Wžøóá›à§þs“Ô¤øÅ4þÒ³eN¨Ë =úëÇóö¥?ýlô\nw> $'«âÑÁ°.cFúŒ9Ç(‚jEã­€M‘^ÊUÕ eMLúS¢ ´lÒïNn'z¤…—Nª! 8c«µì=¢·9ì$²]1ó¢µÊ/ßâ!ØouZÍûÓZ6Ù°Ú×j4oÕ·¢$4¢KÖÙ'“fO8c†%ºAúóÜŽ1f³X—‹qtvS°I$T• •âB¨TtBJu±Z—Ñ´ ±_\ÄVúZœŽ)IKÕ[ ë2f4¬Ë˜sŒ¢ÊV4ÎÀ¬ ±Zœj  N‘X'Ì›ô‡Ü:úZ ¢8°lÒrž(š½x÷\W)-Lzˆ|Vè 3¢úè.±÷–NÃÌœy1g àX5?Â~«k¤OîÄæ¸f&špJ8oH©_æWûZÔ=$Œ%½µ'ßX©¨Ê«wþ=ЇƒÊ¶}³'Ÿ±™;\ßê]}“—Wè=c6‹u™±çsL¿øàû(pÄ„œw¼ó'SMrå‰O¤úp&V( â%2o}÷Eæ'Ñd¾.ôŽ¥øÖ˜?éYf&—"úoS§ø¥¿ÀºŒ ë2æ3·BÙN8Mw)¨+sJúþ\½ü*(†L©lÒrž dÃÉ-ô=s†Qý2@¥ÿ-;†+˜Y´šáŽMéwéý&hR]>zNJýV žœ§ßø­Õ¸¾ôÀ½ÕO iBúKƒï¾;ѬRÙ¶oöä36'Ëáô§yÕŸ c̦°.3}]æÖw_üêמn‰2àÏ_z¶_a)_úÓÏ>üÈCäÑ_8~8¨Ê•'>ÁÊñóJÍa¤´F·1:Õ$K™_Fhà:•RúÁÏ”/&+ë2f4¬Ë˜sÌd4Î@ ?S>–ùBq—‚º2§¤å^ª ýâ%Q(X¡å–ùB»PP§H¬æµü‰!_ëŸþ”Ch9OúÑl‹É›3̈ê—nÐÿ–NÃLŽkÅ´ò#ñ“/)¡ÇrhõÌéô÷ÃNàû‰è!Rú,&¤µde`$µí,wßìÉglNCzŽ(:Ã1Ælë2ca]fOèk}«Ê‹T›Óý°.cFúŒ9Ç ˆâÿ9·BY†a·ü~\óÌé´Rtýi}Ô…((-‡Ðrž¨!\ME9·>©±4 î¨ô¿e§Ópՙ떠³4‚ýÂìgžÄBà%AÛêG4jÔIE“ô÷ÃÑm…Ýó5!Õ%ëß åî›=ùŒM6DvQÝU:Ã1Ælë2cñÔç¯"zô±¦|srø4ÕO*Q²é|ûÌÁ°.cFãÑþ2Jß|þ‹)ߘs€"ºªÊ€Ø©Ê*k}»'¦ ²Öÿ½HèZ™r²ü`PilBÔ]Ê'ëâUu× A%aÌ4Û PéËN§á $%”ÓÖ-A+_H‰¨šmÑ_Ö«® ºvzYuÉ´ Õ­ÕYî¾YpÂëïd”u¾@”ác6‹u™±øîßýÅõ¯<õ×{#å¯ã÷þðÓo½óÏæsêïÙ >üÆ/V¾þÍö)b]ÆŒÆßÿå¯?{-es>ˆþ°^}åE\eD‹Ê¨[NI õf“j'›HѦÂûªx¤V¥*JŸ» ;‘ZêRI|SC©.)BFBï©´J'@¥{-;»lû“¼n Ôª\¢É„…–TW" iéÀ'÷é®–¬¼Ý@¿´3ê~C°zÆú;hJ;uªÈç¥.a‚ù»Ås†°.sžy8üéù)Éç‰ê[f:ï£9<ÖeŒ1æ` ¼‘6CîÏ<©|$\«ˆ(CBéõkWT„ˆKmÓG„`–ùHñ-Ò€ÔFT ǘ™b?µbŠMˆd û½vû%]Ë2ú­J3ÈDL›‚@™EïUkLÉÛ•³Ñ²³:²­"çcl¯¯[8Vͨ9+I`¡ÔPÙA‚c©À+l¼¸'Éä~X Æ'Ë7ûèC|IŒ¢žúÕ$ÇÒ4cVÊåî›e…u3ÆVcÊ'­aëvoì1cÎÖeÎ3~¿LIùÿªøß &ÿÕÔa°.cŒ1‡$†|ˆvH|‰ „g©•òU™×@ ®S+ È ‰õÕ?ÿ§¸4ÚD à¶Z±¨ þÓ»WØQÔ@òÑ)í#¿e9ªK¨#ËÌcx‰ üŒ­ZtTÚlÙYÙ¶@d®!pPø TA¥(âM.êTóœ®NJêe$ôO¢Kô/S«9ûaZØÑÎÑpÅKåí;Ú“v£ â'®™Ã¢r\ o + ¡hæŒ1ÖR>„D -ªÍ×íÞ8ÌTdŒ9X—1f ¬ËcÌQ´6•Qò_»ýjµxCªc$J!J¨HOÑZŠäñ}±(&t-•$5!åÐ8®ˆBßjªÆíˆðË&ÈaÉN;3é¨ì¢e§Óp˜T‚*]±p¬š‘V;W/?‚&"®^¦†¨\õ‡ m£*!¢M¦r?,¢4Èߪ£¾~íJr/£|S5ˆLÍ9`Ò,X1c¬¢”àN&ImšW‡ÓB“SuÉsÖ±.cÌ@X—1ƘÃðøâÝíFÚÌG¼‡À©üì$E\¨¯æ¸€5Õ¬»‹õ_»ýºÕEÀ 6ÑÉNûºôÀ½å[2aAÆš »jlOÐÖT?ZFCX+'­Š†¬áæ·ìt®¦0±Qœa±h PZͨÀ0¦RÁÚ±B5¶ðG‹KÐ]GsöÃ"0Џâ~®wNµrô0Và¾*…Lš%‹f¬£Ëú3 ª¥†`.ƒû[tnLcÌÙźŒ1a]ÆcÆ¡bªV´lÌ.½s »¨#ŽPðN;úºÌIX§ËcÎ7ÖeŒë2Æ3>ÖeÌÉ™³‹¬Ëœ"ÖeŒ1‡ÄºŒ1a]ÆcÆÇºŒ99ÜEHÕº€ûÖþƒg³¬Ëc‰ucºŒ1ÆŒusr®_»ÂàéâÝ¢#\üÆŠHûÐ"·n>‡®—rò/¦-.È ¿Øå¾;ÿþ Ð2f2Õ1Ælë2cqó›_þ¹Ÿ{÷¾ô;)ßlë2f4þä÷÷Åw}ÿå?KùÆlë2f' ,Wˆ^MOð¬gŽ;[’¶ (ð €b:¡.“ bé¯_»’êc6‹u™±xü‰Ç.\¸ð±?œòÍF°.cFãC݇Òó_ü\Ê7fËðïÞû~#ƒÙ¯¾ò‚þI6Áõ¥î=Ì¿ÝAïêw>ýºtnÀðML`'Ë!k c6Žu™±°.³q¬Ë˜Ñ°.cŒ1ÆcÌ^±.3Öe6Žu3ÖeŒ1ÆcŒÙ+ÖeÆÂºÌƱ.cFúŒ1ÆcŒ1{źÌXX—Ù8ÖeÌhX—1ÆcŒ1f¯X— ë2ǺŒ ë2ÆcŒ1Æìë2ca]fãX—1£a]ÆcŒ1Ƙ½b]f,¬Ëlë2f4¬ËcŒ1ƳW¬ËŒ…u™c]ÆŒ†ucŒ1ÆcöŠu™±°.³q¬Ë˜Ñ°.cŒ1ÆcÌ^±.3Öe6Žu3ÖeŒ1ÆcŒÙ+ÖeÆÂºÌƱ.cFúŒ1ÆcŒ1{źÌXX—Ù8ÖeÌhX—1ÆcŒ1f¯X— ë2ǺŒ ë2ÆcŒ1Æìë2ca]fãX—1£a]ÆcŒ1Ƙ½b]f÷<ÿõ/üwÿÝÿþ®ÓHÿÍó¿ûôã¿–ü1gë2f4þàê§~ögþéío|5åcŒ1Æcv‚u™Ýó¡K÷Ë$§‘þïÿã?Kþ˜3„ucŒ1ÆcŒÙÖevu™w¾ó7›î»ï>ë2gë2ÆcŒ1Ƴ)¬Ëìê2÷Ýw샥O|âÖeÎ:ÖeŒ1ÆcŒ1fSX—Ù=ÖeÌj¬ËcŒ1Æc̦°.³{¬Ë˜ÕX—1ÆcŒ1ƘMa]f÷X—1«±.cŒ1ÆcŒ1›ÂºÌî±.cVc]ÆcŒ1Æc6…u™Ýc]ƬƺŒ1ÆcŒ1Æl ë2»ÇºŒYu3¯ý§oüÇÿp=ecŒ1Æcv…u™Ýc]ƬƺŒG?úË.\øæó_LùÆcŒ1Ƙ`]f÷X—1«±.cFãCÝáÂ…ç¿ø¹”oŒ1ÆcŒÙ Öevu³ë2f4¬ËcŒ1ƳW¬Ëìë2f5ÖeÌhX—1ÆcŒ1f¯X—Ù=ÖeÌj¬Ë˜Ñ°.cŒ1ÆcÌ^±.³{¬Ë˜ÕX—1£a]ÆcŒ1Ƙ½b]f÷X—1«±.cFúŒ1ÆcŒ1{źÌî±.cVc]ÆŒ†ucŒ1ÆcöŠu™Ýc]ƬƺŒ ë2ÆcŒ1Æìë2»ÇºŒYu3ÖeŒ1ÆcŒÙ+Öevu³ë2f4¬ËcŒ1ƳW¬Ëìë2f5ÖeÌhX—1ÆcŒ1f¯X—Ù=ÖeÌj¬Ë˜Ñ°.cŒ1ÆcÌ^±.³{¬Ë˜ÕX—1£a]ÆcŒ1Ƙ½b]f÷X—1«±.cFúŒ1ÆcŒ1{źÌî±.cVc]ƌƇ?øà… ¾þìµ”oŒ1ÆcŒÙ Öevu³ë2f4^ùú3¿õÉõß9åcŒ1Æcv‚u™Ýc]ƬƺŒ1ÆcŒ1Æl ë2»ÇºŒYucŒ1ÆcŒÙÖevu³ë2ÆcŒ1Ƴ)¬Ëìë2f5ÖeŒ1ÆcŒ1fSX—Ù=ÖeÌj¬ËcŒ1Æc̦°.³{¬Ë˜ÕX—1ÆcŒ1ƘMa]f÷X—1«±.cŒ1ÆcŒ1›ÂºÌî±.cVc]ÆcŒ1Æc6…u™Ýc]ƬƺŒ¿üô¯þÊ~ð7/¦|cŒ1ÆcÌN°.³{¬Ë˜ÕX—1£ñá>xáÂ…¯?{-åcŒ1Æcv‚u™Ýc]ƬƺŒ=tÿ… žÿâçR¾1ÆcŒ1f'X—Ù=ÖeÌj¬Ë˜Ñ°.cŒ1ÆcÌ^±.³{¬Ë˜ÕX—1£a]ÆcŒ1Ƙ½b]f÷X—1«±.cFúÌιzù‘O~äýׯ]Iùf·<ý™Ë˜ç[7ŸKù[æÆ3ObNð3åcŒ1æt±.³{¬Ë˜ÕX—1£a]fç¼åÍo³úíoû‰”ovÈ·žÿ&¹:Ï·n>‡ÒW_y!åoî=üLùÆcŒ9]¬Ëìë2f5ÖeÌhX—©rß=ðÏçâÝÔÖºÌhé2·n>ÇümjÖeŒ1Ƙ1±.³{¬Ë˜ÕX—1£a]¦ ãÛù)FÂlk]f¯´t™O~äýÌGBX´¬ËcŒ1cb]f÷X—1«±.cFúL•‹w_@ÀŸx=Ö?J)øý2¦ó~™´‰ë×®Àpõò#©h¯Œ0vcŒ1Æ”X—Ù=ÖeÌj¬Ë˜Ñ°.3Ÿ™A/«Y—Ù+-]†œú;eô¶\¤¢½b]ÆcŒë2»ÇºŒYu3Öeæc]fúºÌ©c]ÆcŒ1ë2»ÇºŒYu3Öeæc]f¬ËT±.cŒ1ÆŒ‰u™Ýc]ƬƺŒ ë2óY§Ë 2GŽ˜ Ô_}å…ûî¹›ÀÔÓŸ¹œªÍ Ñ<šê8pã™'S×àÒ÷NþÏiôrñî ±:ê|µ ¿¾çúµ+¸¾uó9µEf¬ÊÙ ÿ]†ÆávÊçÿØR~š”v†Y™jöŽRº‡ ¼$(J•ÁºåN› ^»ýòqÍNcecŒ1Æœ:Öevu³ë2f4¬ËÌgfÐËjˆ®oÝ|?q2SÁxû¸ÞS§U‹jïHè¢üÄöÇÅEBý–ÈòÚí—Z½ ¡ágžLMLjÁÂ4ÞèØÓŸ¹œJ™Ð#ÌêZõ ›”ùô“ùï¾pÔú Ëii-"Sj‚ëã‚FJöW,7,Tý¡'´†Ÿ©•1Æl„ûîÝ8Õœn‚É+c€u™Ýc]ƬƺŒ ë2ó™ôªš..=p/"ð(|à:µ¨ÃR6A˜ ø¶æ·bõ*j%€ôˆdJ¾¡2®YD  *ÍT{Á^*?‰€¥èˆø ;·n>Ç:úÏJH(¢åØDE2KXTæ#‡ù¼@5Ž4z[¶Báš‹‚© $´õç¿_F–Qgþr«”­¢ÿ±ÓÔÊc6Ž4ÿÛ]w.ð!ye °.³{¬Ë˜ÕX—1£ñèGˆo>ÿÅ”oJý¦ü„Âc$„âü€ AÔÍ|ÔIÁKÙ/… é)“Ÿp!QMˆ€Ï<‰ÌóG¯Ê®£d“|VQÙK|Mì‹h¤,UÛhDCNr<”e¤–ñ2?µŠ#Å5[!¥¾zù8P}× –¥š\¤"²n¹£”×ó¦&H(U‘1Æl ë2fX¬Ëìë2f5ÖeÌhüÃ÷_¾ý¯¦LSEtÊO°Ò}µ7Å´BniUåEa|)7T‘«zûI"FõÒø…/%òùRøÒ–¨,DkâµÛ/±RR.”‹¨Å¸Ý¯ ŸË ¡ñ2¿ÓHò¨®Z•«—a“R|™ÔeÖ-·æ­ªÉ&ª¥"cŒÙÖḛX—Ù=ÖeÌj¬ËsvaT<ôö«µ"öIã“‚ö£f‰8ߺó•(ËOßyCM4¨t„ )QÐ RU_’QåN´4v9À$x¥j ±Nš´þyÕ2.Ë¥‘–qÚLžDª õÝ:H(Â,!½•S‡œVˆÎÓT‹¸Ü}›„CèŒÑcÎ7ÖḛX—Ù=ÖeÌj¬Ësv™ôVÃ{`¥H1ºVf«Õ"æðbfårìp• á¼2­qõ§ÈxëËk:3Ö2N›q‰jCf"•"Wu)IV×-·lv¾ ˆÞvÆhŒ1çë2fX¬Ëìë2f5ÖeŒ9»Ì zY­rWƒùWÃÿœVæjô±ïž>ªrG#¨~}¯¾š·*=}yMõÿ1uzœüÖ›Ãè2}eµ.³n¹[_¢YaÖcÎÖḛX—Ù=ÖeÌj¬Ë˜ùÁß¼˜rL•™A/«µ‚çV0OÕ©õ‘ùèßýÀ“×n¿”J‰> 5‚ø©™ˆ¾HøêåG”©OñLÊHéHõ§L×t•ZÆÙ¥)_” µXÕ·¨èu—âK¿!ÿó—{r¥´L1cÌùƺŒë2»ÇºŒYu3¿õÉ…Äío|5å›EÅ)?Áj¥.@ZºÌœ÷­ÌGaù?•_»ýÿ©rôΗêûk$‘”çH‘ªêƒd‚ÒlŠˆŒG1ˆhtH¥‘–q¶*G!ʆZ¬ÒŠäaG—)’uË­•*—U³Ô£1%¸±AÒO«Ü8úì>z ÈòõkWd¡ª±~¼ëù¼ê“”ÊE#êO`÷”ÀmxrõÜìë2fX¬Ëìë2f5ÖeÌh|è¡ûq€xþ‹ŸKù¦'ò9A/«á(ŸòIK—hÂ"\<ý™ËŠ4p—N`¹lUEoå@Bæè yéBf2•Ì ~Œö‘¯&Dâj"V«R`¹ úSDà*- ášþÃÎ,´Œ´òÕ0å‹jCf"a€ÊÄÀ•T]U ó˜“hÐ$\`\s–FØ 8'q¶'ÇhL‰¶"¶S**QåNBV^ª?ʸž6p‰9ý”<_4¢¸ûâmžRºÍ8X—1Ãb]f÷X—1«±.cFúÌ|xFŸ zY­‡(Ì(ƒù[7ŸS8;â8«öæ‘—î|EK5%‘/c/Héeª/œ×8JÉ[\Wã"Ö™ ÕâlÄD³,-´Œ³>JS¾¨6ÄÀ‘É„ „/)ࢪˤ™aг±n¹«f‘Ð ®Â^§VÆtÐ>œ£b¨2.Zèý2¯ÞùðR©Ï&T9n`=0‘™z‰HÖ$Èa«9#ª¢~‘ÐõÅ»/àæ‚Y ©zã›SǺŒë2»ÇºŒYu3Öeæƒ9Iù ÖÁ9>å÷Y¡u¦G>JŽýÿ5!!AKiÁDk¸†c7joÂGÔ„¢Ôu§¾({AÂËû‚%RZNù%ð¢ešå—æÐÛÒHË8냔/Z 9ÀcŽ^"ElÒZJ 7Lh•*€ËÞ­ƒkøÌ —Ö@¬oLmïEºÌLÉ›“õ%ִЛkpã(SúHõöi±ÔÉö çÓÓùºû|£‰u3,Öevu³ë2f4¬ËŒ Âl"•.âÕW^XdG•gÖ«N²'³‹ÐŠLþÙ?1§ÕŠåVå–øeÌLöªËèg“*†,G)½0óÀº h £R_³6§‚u3,Öevu³ë2f4¬ËcÌ–Ù«.ô“Ž:Yý8E]¦ƒFÔz¯œ9E¬Ë˜a±.³{¬Ë˜ÕX—1£a]Æc¶Ì¾u™9eÒ‡˜Rë2f)ÖḛX—Ù=ÖeÌj¬Ë˜Ñ°.cŒ1[fߺÌ;ÿG,½&"³é=5ƒë2þÓ€X—1Ãb]f÷X—1«±.cFúŒ1Æl™}ë2@BFõ£L­1u¹oýíNb]Æ ‹u™Ýc]ƬƺŒ ë2Ƴe Ëèÿ»W?ÊÔúP—ÑX¹d†u3,Öevu³ë2f4¬ËcÌ–Y§Ë¼åè?²—\½üHjúe’ÍòÝ4Òeb/‘ÔìO—Ñ[{Zÿ°Éœ.ÖḛX—Ù=ÖeÌj¬Ë˜Ñ°.cŒ1[f.ÓJ­¯Â•œ‘Ä)°óIÔeªéÀºŒÞ,sñnÞƒb]Æ ‹u™Ýc]ƬƺŒ ë2ƳeÖé2Oæ2ê—¤úâÒ÷²á}÷\ŒùúSõ60ÈRô{Õ/¬Ù“.#Wßòæ7Uû5#`]Æ ‹u™Ýc]ƬƺŒ ë2ƳeÖé2K%[7ŸcÃôDfõ;tÑ [¡Z*ê°]¦ø¾$‚id¬Ë˜a±.³{¬Ë˜ÕX—1£a]Æc¶Ìat ]Cÿ^ºÿ!&0ˆ.E™êW›q°.c†ÅºÌî±.cVc]ÆŒ†ucŒÙ2ÓeÊ2é“A­w Œ ËÄïúMÂ2b]Æ ‹u™Ýc]ƬƺŒ¯?{íÃ|ðóbÊ7Ƴ¦ËHàÀOæ\¼ûB|Y2‚.#keÎÖḛX—Ù=ÖeÌj¬ËcŒ1f¦Ë5çG™(Ótþ·Ñ©ë22eQæ¬`]Æ ‹u™Ýc]ƬƺŒ1ÆcÆa‘ŠqBÉC\ºïž‹Oæ2¯;_£{ººŒì,êÝœ.ÖḛX—Ù=ÖeÌj¬ËcŒ1f©'”<âG™&?ÄNQ—‘‘E]›SǺŒë2»ÇºŒYucŒ1ÆŒC ªÄðà%+_zàÞO~äýU®^~DõK(Ç(õ?$]æ-o~Sê%’þǶœÔ“J‚MZ@¿‘‚Ôµ9u¬Ë˜a±.³{¬Ë˜ÕX—1ÆcÌ8¼ýŽŠÑJñ--“•‘úoÑÇ—˜ô?³«H—é§O~äý±Õ¢U™3L¦Ôµ9u¬Ë˜a±.³{¬Ë˜ÕX—1æ,‚ØÇôΗSC°I°UDÜ3÷Ýs±U$^}å–^zàÞTdŸõ™¹uó9¬;è‹û–7¿©Ï¢ÊX&Õ¯+§¢X‹õ«¤o¨Y4¢*Øf©~‹Î—ã˜SÁºŒë2»ÇºŒYucÎ" üwQ3 ¢n쓘¶©×ǹwRùåñS©¨ÅÕË`gn!8äΟ™ÁJq}ý01fOX—1Ãb]f÷X—1«±.cÌ™ãÒ÷âÙ{¦£As¤ª`ÏàܺùœJqÍLî($\«” ‡E3÷ÛgžTýsÿ=ÖeŒ1“X—1Ãb]f÷X—1«±.cFãû/ÿÙŸüþãÿðý—S¾!Š{ËOO N÷ùƒRÂéüp Ô/NÎ>Ì wK?êVp^: ý6ùI¢ÿ:Œt¾·"Ø­.s*{ÛºŒ1ûƺŒë2»ÇºŒYu3þàƒ8@|ýÙk)ß~‚©úf„sð×û>\1@¤™Á>¸xç_·ìVCٓٓë2rìúµ+©¨ ¶%¿} SÑùc‡wÜiímë2Æìë2fX¬Ëìë2f5ÖeÌh|è¡ûq€xþ‹ŸKùèÿ†Tÿ©ê¹×e¤2œ¢.C] i·ʞ̞P—yõ•¸©&ÿ‰ï6ÙáwZ{ÛºŒ1ûƺŒë2»ÇºŒYu3Öe:èÍ Õ ÊºÌØ”.sß=‘‰õÚí—b¾!ÖeŒ1“X—1Ãb]f÷X—1«±.cFúLEï'×eøe$õaCüLùäÕ£ï¸éT¨"gú­PÃß_ìJ7@ëk> (šŽA²T—‰–SQ¥4»B—AÜQ3?Á4Ÿ™Ë½où  õçÜqlERQ¥G+°`oËlkEÔD9ÖeŒÙ7ÖḛX—Ù=ÖeÌj¬Ë˜Ñ°.ÓAï—¹zùe" BdÈ‘‰/IúzàÏt)­ (7‰œŸÙëãgÊ'lÙ5b˜˜|ušRuŠ:õ¥1•þ”;9ÉÞŽþ”–["Zô'&äë™Ðß!ƘÕX—1Ãb]f÷X—1«±.cFúÌRnÝ|1`„†Ÿ|I¢ˆÃð ?ì)ÿÆ3O*lÃ…*X@>lRÀ9dâ%ÿÞ+µ~½¹þ¼Í"\D“ô—ÿX*gp!é!*Jׯ]ÅiŒª¶X Yx¢wÀ¼DG±@+sH|·^¢”%¹ÖØ0Ú´0iÈBœg¾7‡ùÉ2Tk©(‚RV['Ä$8–´—à0»@¾–ΣkÔ?Œ.£-‡­P?îR¤´Eá"¡ššh‹2•þ°ªáÖÐŽŠ’ –L•çïmÌ›, H–aA£HM@²Œ!\ÐT4˜cvÂÏÞýœjN7Á‡ä•1ÀºÌî±.cVc]ÆŒ†u™Õ(ÐJù‚Ô ^»ý’Ú*Ø#ˆÖÏ„RDt±”0&,ÛÊlTXˆÌÞWû ¿‚Ì'£wæ£BÌ?!{Êå÷ÝÊ·êT†Ù)“(ž/WaÒ,¦‚ªcWìºÖŒõ£n-G«÷Ep>“Ÿ•$ʬ ³R ³=Ø©œ ­KÚ¨Q‹ù@3†Túƒ†ië-bÙ¤ã¼èìIHɲò‘’̇…@_,BêïcÌ©€³…¦¿ÿË©‚1'ÁºÌî±.cVc]ÆŒ†u™ÕT³™(M‘yŒ?S\'Øo5ždàWºÔwUákRmæÄ®+è;“P(»BÂ@8Ͷe kÒZþT‘Í”ßqžÜºù+$ñHH›‹ªœL·‘rŠÔß!ƘSÁºŒÙ+Öevu³ë2f4¬ËüÿÛû¿XÉ®ëÌÔC?ýÐý"À‚U@=4`m6ªØÕVVMª kB ¢]¦mV±M±Ø¶Ú4%ªlIc2)•l©“LJ–E;KN[Vɤ+)[EH²]LPÖˆ0ËJHÓAÀ çE _FÓóÒèùxWæ7[kï³Ï‰s#2wDü6~¸ˆØÖ^{íqÏú«™Jù–0•™»^Y_Y_ó6óÉÈÆUJ³NA›¹bд9›»®ÃN6o&J4W´û_çÀ³fg77,¤K¦vͽ³jÐÙôYúAðbÓÔ¢éRItPq:ÖLߟ&Ím³Óy¦N©Õ¥r¯c:•)9Ïfû'n è2°SÐe¶º ¬]F]f5+²D3•™O՗ļÍ|²™…Ú¦ru™mÒ\‹êcàTòËwï™øÇFƉ®œIM³Øÿ:î›-®ÇMšô8*ûY÷’]^Nó<”ßröäë]ÊÖ…4O…ñbÓÔ¢éR‰£çïÙ-O©»%úþ4‰‰ê!ç{xé‰sê\ã»±J ³z™ý·tØ)è2Û]Vƒ.£.³š…Y¢2d¥šJÞÔ³ää¬ÊÌ—dìN5Sÿ?¥š¶9[d³(ûQŸ žž{n|ŒKE“v„ƒX¬J' âµ—ŸW†?ä:î›õ—”Ò‚ö³î%»¼œXf½G¢¨Ã’”J²~¦úÀ‹­§žrÉ8T]SÓ÷GGHçJ“ªƒ ›õŽóê£Ãl)-ÄŒõtfÉ2àV.;]fû ËÀjÐe`4ÐeV3›ƒ‰R€PQg5)3wÚÖÉØ­¿Èˆÿ˜áÆVI_Lc›žzŠôU³¹ëiç)õÕÓúKjݧ-PÎG7•rEQSçÀ}³^¸Ji­&EÆûY÷’]^ŽÜ©äI £â/ʉ¢ÎSß[T–õ3Õ^l=uÇ¥Àp êšš)ÒWꪨOà§iHÇùÀmjŠÒa=!®I,Y&Ü*Ðe`§ ËltX º ŒºÌjfs0§vzpáÜÃeîô,eæSõ%é>ˆTê¬Ngs×ÓÂADREÒÇš逸‹T46>¨e ö¿^xßìê…wf,Y²Ëˉèu\½vãǤ* ¥™¢Ÿ©>èDiÖ%ïšå˜tB×ôGÛõ*:K¡Tº56º^ÂìÇ@•ö¨éaÉ’eÀ­]v ºÌöA—Õ ËÀh Ë¬¦ŸƒY=i&~NÏRÖ7U_ó*ÓŽdÛL}hu*8›»n‹ò~-ªlê§ÇÎÉõ³î`ÿë…÷Í®^xgÆ’%»¼œˆÀ¬«¯¿ò¢ïÞZ¸.Ç6Õ(ͺ¤¦ë똤PÒôÇ‹jŒ‰ê%Ìn±=Ühìa’—Ù?!pK@—‚.³}Ðe`5è20¿ü‹?§‹¾t)ÕÃ,Í,Ñ8ó7›–LeæSõ&äžNâWãÏ=uòä&×nü«àM®À KšËÃiÄÙµº¥&áÖ:î›ýÍ¢3cÉì.oD3nSl´®Ð&Ô¹yØ._<ÿÆZSÏÎâ¶ìÐM-Äÿd:™ 'UêÁ /!ÕÏžíúŽž%Ø™¦B*Ö™€›º ìt™íƒ.«A—ÑÐedz—>õÝW_Jõ0‹S¾fÖêÜûRëËVýGþ”™ÏfìîД{¦pB»\Í <0Õ+åÉý0:™oÞ+¡Ek÷Í 7SšØŸzÆÏ>µËÑŒÛ>´©¾‰U†:VITê©ÝÔß—4Уš¢†IÎ{Eͳ6Ó Ó$Ö©™–]šB¡Â­*ý7ŸW_úÊ'ý¥ë’ÌIùýßzi¶ºÌöA—Õ Ë N›©»sï:5µ(£²©.ã¿ó«È@Ù  e¼Í»œ.ª³2êÔ4WáÜuSAg ¹§å×Öœ²¦„¶Fa¤Î®û9p߬ðÍ ²<µJÝS´íO=c‰gŸ²¼±GÚÙ²Ra¬Õ …Ýššš”Jyläv؉’¦ekŠp96i‹~]$ƒšZ5Ѥ’œwS²VŽj®7ÜÐÏ©³íáS‡DÓ«ÆVIMåT韸9¼úÒWž½ô©G>ø ï:ûÎëbLUîz÷»>öá÷?÷…Ï¢ÑÀ)A—Ù>è2°t€ƒÁY«2±PF” ;…+34U*ÊÍ"ÙsSÊÌ—dì2âáÍ¢)ju¦ÌQå­’öpI«Ûa°žTM1JÃå›Ðƒ”pn„¦5M§˜Øùã%5¡Ô¡4Dè§|p¯K ~ªOTFÑ(÷fÍ  oµêðVô4N–ÕCêKÔÝÔ?5­ ñ8•zH é¦ú+V7uH£¦¶I[üàÉbõ±älOùïÒ\ˆ*¯7o‘3j ƒýÛå4ZÌTA£MA—Ù>è2°t€Câµ—Ÿ?€ÊÇÒízªäÐDäc¨Î"ÝØ¢´°Yoüùšfvf£C$ å½êPú#äaGjIKÐã©OB-DNʷ䆖“BW¢ •SN›vAè©*Õ$o5ÑÔêúfƒz…lªsLQrKt™Xc}â,•n«gSùê“" ›6S×'MÝ´:5éq½;ýàèä§€»¬H­îlÒÁ¶“z½L  ϶(ZT'˜Rv–eo=–µÎ+¶Â:-F5äý?ÿÞ;~䇯W-(h4°t™íƒ.«A—€Ó ŒN¿”é¥zci@=Sìš[¢Ë ˆÎ§VÇ €›Ìi´ ÔðÒÚú—÷3¿†FÛ]fû ËÀjÐeà4Ìf¼–¦î€Ý. ËÀMc»ZÌh4pzÐe¶º ¬]NCd¼ú9õa¢{n|ׯŠO¬À)A— Ðe`§Ü-f 4XºÌöA—Õ ËÀi8[ü™KOœó×мvò/{ËVÙß¼ñ¿i–“,ZcÄÿ­'_q"Ê»–î9ù—O"d •C º l[«ÅLFËA—Ù>è2°t ]¬üÔO¼ç;ßz!ÕØ¼V|³oåÀÁõç7%ö•ƒÿ®SíN¹*zêÖÔ¤2õíÎûN¬]NɘZÌh4Ð]fû ËÀjÐe`4Þwÿ½º,ÐAª‡‘)ÿÕÎùý uæìª¸³t™)®]}VÁ1å?ÒÖã²éPEÇ’o8€ì—3 Ô ËltX º ŒºÌ¾s«>"ónD² Û Ë9 -f 4Ðe¶º ¬]F]n>_{æâ¡j1S¬Öh4*™‚½]fû ËÀjÐe`4Ðeà&óä¿þHˆ³eßµ˜)6Õh¸TÛwÐe¶º ¬]F]n&ß}õ¥ûÑrC³ª3Åæc~ûºÌöA—Õ ËÀh ËÀÍäïþìJh e96-fŠ)]fßA—Ù>è2°t t¸™$]æ“þÒ‘k1SÜïÏ\ºÌþƒ.³}Ðe`5è20è2p3Iº !SÄEZt™}]fû ËÀjÐe`4Ðeàf‚.³t™C]fû ËÀjÐe`4Ðeàf‚.³t™C]fû ËÀjÐe`4Ðeàf‚.³t™C]fû ËÀjÐe`4Ðeàf‚.³t™C]fû ËÀjÐe`4Ðeàf‚.³t™C]fû ËÀjÐe`4Ðeö‘³wžyë[Þ,RýÍäÚÕgÇ çNMc²w0Ú ŸáàòÅó©Ï¦°¿{ºÌBÐe t™íƒ.«A—Ñ@—ÙGn¿ímúu 4ÕßL¾ùÜçåƒÊ£x 5ÉÞ9|¨„€{árúMaöt™… Ëè2Û]Vƒ.£ñÙOž»ãG~ø•¯9ÕÃȠˬ€¼}ÎÞy&6B®<ý”¸ç®³§¿É…ýØ#Ðe‚.sH ËltX º À~qùây¥y7ù“šN“v>Ù.³‚:|íê³2»uË;2{k‰›eVœÞ…b’êt€=]f!è2‡ºÌöA—Õ Ëì«sÈÕ8½¼ý¶·¥&ƒ.³‚:;¢¢YRÓiØ‘Ù[È’ãÝD»§¶oï$À^sï»ßu]-¸uE>$¯t™C]fû ËÀjÐeö t™)ö. Þ©Ãè2 ñ.Üs×ÙÔÔ]`(Μ9ó¾éM·ù¼ô¬c]fû ËÀjÐeö t™)ö. Þ©Ãè2 Y½ ê߸w`¯QzŸT’›|H^q;fÐe¶º ¬]`_Pš'¬ËÄÓàõW^Lƒ×^~þÒç”zœ:ôÑpר7’Ë]¦œ´ìYë2Wž~*&½pîaÙq}zœZg‘Kᧆ§¦’r–å¾É¸Gõ}»võÙø:žÙÎ ®é*vÇж/jDó›PêCҌɦfE²¬ž©CBý:=˜2;ËÂ-P7¹$cEÞw·W4õ‚ b ú×…»éqtQS.°ŠL¹–ÓÄààA_Xq;fÐe¶º ¬]`/¸ç®³')^»ÔÁPþvöÎ3!â”E5Ë?¯á$¼Y”Цž¡Ë(MU¯ÜÕk”s6]U}êÙ¡NƒZxsª“î^¾x¾ŽCÓ·æ*TTYÆÊÌ:\#gšK°}« Í¢ž6µ´¦Á´_™¯¿òb3ÚšnêÛ£›ýµ5©[Ÿæf©Èräz:—μ¯½ü|g š¬j¥ýUHÓ@¹ª>ѹ&^Â×»¥\Žô…u·c]fû ËÀjÐeöe­'IY»$©åÊÓO9Ô5*J=vh¦¸.¥Ö=5Å…sÇDõ¤SÒŒgQg=<0-­CGæÐb=‹Jí›7õ‚R¨G•+*ShõI«P)ÃlªËÈÃèoûžB¢O_@q7¡º^;ápùåfŵ«ÏÚNÓr uˆ¦ºG¹H(Œ1DEÃÍõªJm)›RÙ®.£sR.°^ö/QˆÜMRLô`yXŽô…u·c]fû ËÀjÐeöeb"r³HÌLÙ­Ì•Z—Y_™ì)Ísý+ãÎÉ5djR§QÊyõøzí›ÞTÿ_)k4ÉBéªzÚfÆ7‘KÑ¿–9lJÊÏè±›™Òh&•Ò¦êC…ÑXWê±,h±i^¾ZËzÑq¸I¸*;)ø^ê±;^—¢5¢\`¨XDX¯IYhV¸Ö^ÖûfŸdÙ,õ8/¼7Ä¢•JŠg¬4J)¥É²œ÷ìjòŠÜ§I ôÑ-–Þêitðª}’µ´¨T©5 Ç­ÚŽ²ÉkQËz@_Xq;fÐe¶º ¬]Fãõ¿þúú—S%çx©ÞXHYn \Ñ)Ÿ³Ä>N/;© Sq•”IŠP1TRÂìü³iY)n§µÆ~¦YœxOÙ±ó)bSn2[&ù—/žOò„qÀ“Ä0åpÎÍm­ñ¢4Kj d0)2ÆG¨ÞÊY³ŽvÓO‹>ekÄYQš àìXí³°Wõ,íB‰ú÷Ú²ŠÜKó*øÑ$—Êzщ¿pëÂ×/À‘€¾°âvÌ ËltX º ŒÆ#üý†þÆs_HõD’_çr•ýœúîRÿ¿þC}§—Ê-S“qVÜÌQ‚& öd*ô٤h4™J°m¤ùI%ÑÌËHºr^fÒ26RÜyá®yÕiÒ%8 µc³f£ƒ‚6%²ÔQÝh—›Xv‘©Ôdè2°t÷ݯ~C?÷…Ϧzú9›ÔNÎ¦Ä úLI8TšŒš:=c²Ð%œú*õJM5Í{¡¼}Tœ55ïìX‡W‘Òï¦Ãìä’%"¶*iÒ%t›5N¦.©7ÝñQSÿ!MÑ¿Á$ð†¦—Æ¦»`ìöÔÀYËò$:”Á´(f)¡f6ÈûÎì1+qçNq¬| FÏÆý¢ó¶öKò|£Í¢·5Ÿy•…k9xÐÖAÜŽt™íƒ.«A—Ñ@—é)Y™Ö–ÌæŠAßHÂyHçê?²ŽŽÁ˜1Y°ò¶‰W=.6±Ÿeç%΋ð_ÅY“ŒDÍ’©k®|I ;LÙx §Q¿p »¤¢ÈôµªzE}”é…·Âê^íX߬*£µ³§±é*¶ðú+/º2NÝk3Å’ÅÚ·t\¯yËúYÔ¿?pÖ²-”n»R[¬ÇM"\úéQÆF§×õ` ‹\jUfo]iªºÞVU¦YJÒVMŒZ²¢>n|·º‹Œ§>Ç úÂ:ˆÛ1ƒ.³}Ðe`5è20è2}ê<¡d¡áËú%I‚óÎÕdS^‰˜1Y°³¥¿œÀ~–þy<üWñX×,¹9Åh: œZWŠvÓá>åÉU4—fL}ûßßb­NgF7}®ë›õŠ–”Ò‚—è±Vºä&©Àc;‹µoêܬ_¾ ú÷ÎZ¶…ÒmWΖ´Cbáé 6ê,ü&Ù¹#)ð»GyÓœ·Uóºr–Mlr­ø×éÚ} ¾yrÀ /¬ƒ¸3è2Û]Vƒ.£.Ó'RЩ”ÌWÿS©`FT–$ Kò˜·“(ƌɂÝP}¥"Kn °ŸåÚåÊŽ+kÔÝ<Ö5 ó(uó-MOƒ©h7žåÊÉ)²MMQ;ig:þ;ÇS‘ÁÒ稬ë›õŠJSMÊD×hºr]*³™sàQÅ–¾5ë7Ú¡þý³–m¡tÛ•³1œ2{hu„Άš: ß–NB-—¡·U­®œeS'›ø«—Ï민¸Î“}aÄí˜A—Ù>è2°t t™>‘‚Ne¾Ÿ¢Ÿ³õ$–\ýGÖÑ13& ¹1‹ý,×º„ÿ*ΚFÒÄZT40}>™vJÉš/äµ—Ÿð¾»=iÃzE çxê™îLé8Ö7ëýh÷‰[xÂŽÊ’à8S‹S¾uÛÇÛ:5pÖ²-”nÏš=fOoÉF˜ÎG™šbÞÖù 'kôº¿Z×yrÀ /¬ƒ¸3è2Û]Vƒ.£.Ó§™*'uÍû‚©|cŠ%Wÿ‘ut ÆŒÉÂFnÌb?˄֕ýYÂçiŽä’[6šŸw06•R²¦Ã¡­ŒÈ«¤4¹>Mh™ÑÚ KDZ¾YL½‡tÉñ°WY¡Sr[Ö¯ÞoëÔÀY˶PÓ• ï:HúÇ,±QçÀÂ_'È>©·u£C¾ÂÉYÖyrÀ /¬ƒ¸3è2Û]Vƒ.£.Ó'„©dõJë_>'ú"BuœÎÕdI›œ«¤û5Öá,%¥Á1µ~j!e½iŠK"iœK7ufú-¦Þû™Œø~Ÿfè©›g ãX߬p´Sý f•Qæ|âTïH;O{´z,ôL œµ¬úèPÓ£:/·ƒÇï SǬd£ÎÁ’W·Í¦{jÖmÐ 'gá¨$ÐÖAÜŽt™íƒ.«A—Ñ@—é3•-˜HŒUÒ Aù¿o–«!1d6‡ét )˜º…aÎRRì„|*iw‡4к|ñ|Yh:ÿ!Ý v3æS)Ù”Ã1¥Ëô]òÔÍÈ[|©ë›±›2{¨L©¬5_<|õ.ôc(f-;˜êYÖûà-…S/™&u6róÀtn*ô¶¦w³>ëœì³Î“}aÄí˜A—Ù>è2°t t™>MáõW^ôc'{Ê(Ò­åÇ^¦’É&³‰b˜­sêüÁþL‰&Êÿ~ ÃYJJƒ“«Ô¦¬#ÔΗMiášB•^ŽœŒžieÀURJ6åpõÑ–Õñ÷yH{m—ÊöC¥‘¼òªUjÇúf…,Ç^«4µuÖ.”R—úשC©ÏLÇ¡^‘‚f—ê‰6Ú…’2†~–¡˜µ¬úève¹ùŠS¥¶©œëÀð«&E¦ÉFÏyóíÅ[P·z[žÌ`“}ÖyrÀ /¬ƒ¸3è2Û]Vƒ.£.ÓÇ÷˜¨èr\(y+“dá@%Z•]DϨÜô:¾T(rUɪ(®G5q–R§Á²M*²)ƒ) zÐÌ—Ô':¨ÄÀrTvWªC,AA‹J7¥):רOt¶}-¡œ4õWÒîV=·…;”B†L•ã§JíØ¬YaWUÔ¤8„áúÒrÔ”=í›Jóf¥šÚ1Yz•*zšF‰v!aã1cDÃ÷_ÌZV}t¨Ï^™ ŠÈx™õ¨ƒÁ]²Ærš4õA¿ó¨Cj¶YßMãmU)g)ICÄF+Zˆ=‘ñÔtœ /¬ƒ¸3è2Û]Vƒ.£.3‹/ñ]ê„S5×ÛªRª )“^—òp©™1¼™?(AªWä¢éN)œ¥4Ó`UÖKˆ¢Ù§’%-|Ê·FYhÚ×F8L³ôN”÷¡¤ÒŒªP2½Ç" e‡æÒ"1WÓ±Y³B™ð”·*š¢Lw§Îª,,Üú@6§6K¦ävêl´ ‰Ëϧeê©ÎL´ÎZV}tH#°LÖ,+^Å{„÷±™ÄÔ¦»LÅßáMâ‹ßîd¹¬¼­SEcӱъbOš~!è ë nÇ ºÌöA—Õ ËÀh Ë,Aùª3]Ž åoNK”l(!‰>î™2P²mSéOÐzª¹¦ò­Í?\Z‘òsÛòöÊ&߯ñú+/Æ,S£%9ฉMR·õ)}넱 Qi<+?n&f®IQšõ¿ô¼Ù¹è2°t t€cf.³©äqmâ¿Å‡AU6å¼ujÈj'; Ë$ÐÖAÜŽt™íƒ.«A—Ñ@—8f6R1N#yø£L¾§éµî‡˜ºÌ° /¬ƒ¸3è2Û]Vƒ.£ñþŸ¯~C홋©ŽTŒÓHõG™ü!¦ò#i%è2¾°âvÌ ËltX º ŒÆË_{ú“þÒw_})ÕÀ1pÓtßã2=ùOX~Zƒ.3,è ë nÇ ºÌöA—Õ ËÀ8Ü4]Fxx|”)dš³Óÿî ]fXÐÖAÜŽt™íƒ.«A—€qØHÅ8¥äá.Ýs×ÙKOœ‹ÇSbè2¾°âvÌ ËltX º ŒÃÍÔeÊ2Í~ˆI Ë úÂ:ˆÛ1ƒ.³}Ðe`5è20V1ô ‰¿¦·ìüà}w?úš\8÷°ûׄãR¯±òÖ·¼9ÍR’þǶôýIƒkWŸ-§ð—'OÒ¨ã}aÄí˜A—Ù>è2°t‡Ûo¨S¥¼¥e¶³Jÿ|)Šÿgvë2ý’ô‘V4…l^ïÝ-G+Í /¬ƒ¸3è2Û]Vƒ.ãðèxë[ÞÜg£Î·Ï}ҧ윚jd­ìß$}CÍF+šâ¹‡Ó&ý›ƒô…u·c]fû ËÀjÐe`¯A_Xq;fÐe¶º ¬]öô…u·c]fû ËÀjÐe`4¾ñÜùà/|ç[/¤z€&è ë nÇ ºÌöA—Õ ËÀh¼ÿçß«ßÐ_{æbªh‚¾°âvÌ ËltX º ŒÆûî¿W¿¡ŸûÂgS=@ô…u·c]fû ËÀjÐe`4Ðe`#ÐÖAÜŽt™íƒ.«A—Ñ@—€@_Xq;fÐe¶º ¬]F]ö…o>÷y‘*á”\»ú¬H•‡Ç` /¬ƒ¸3è2Û]Vƒ.£.{Á£x@¿Uȱ·È…sGTÞÔtplvúÂ:ˆÛ1ƒ.³}Ðe`5è20è2{Äí·½í­oy³8ìš`ïG]6}aÄí˜A—Ù>è2°t t™}áÚÕgOÌ7Ê¡fÑH°wº ¬}aÄí˜A—Ù>è2°t t™=â­oyóIŽù¦+O?•š¦xð¾»o¿ímgïÜû‹0ì]€.ë@_Xq;fÐe¶º ¬]F]f¸võYå™ËERŽ~¦ú½ƒ{ ËÀ:ÐÖAÜŽt™íƒ.«A—Ñ@—9lÐe º ¬}aÄí˜A—Ù>è2°t t™Ã]: ËÀ:~ìÎ;tñpk‹|H^q;fÐe¶º ¬]F]¦Ã•§ŸR^wáÜîÑã³wž¹ý¶·‰ï»ûµ—ŸwSÍ¥'ι³”vj4W|L ykã—/žOþLŸxÖeâiÐü$”¦+W'äOç?©³LÉ¥xªázê±KœLKÖÔŠXêcdüôº›`odД«¾ç®³"ˆÅŠr`"v§ß§$öÈÞ =:QÍ£èK¢]öW”b"ÙŒ¨.wÛÈ`·N¨Õ¤ž½ßYž<-Ücõ yt;x>6¥ÛŽC‡t°ûÎÀtÉA”¿û³+©4¹¯“òo.|,µÂø ËltX º ŒºL‡Hêâf%„¡q”E5Í”XI R¸ëŠ¢þÍG¥úè©P|ÊÙÝÙD«bßÒ*˽µ2™d°)ÍØõ¬Oˆ*;w“@t™u\×IA—ÙGÐe¶º ¬]Fã‘þ‚~Áã¹/¤zNê¢(7s“àRp½pæ\J* ¦ûelDù^Ù¤ÇѤ!®Œœ0M×'’ÏίQ}”×M¥ÞQË NPUÔ­\¬òU·Öm³Œgàh¨$gìg­Ë¬3è`&ƒ’úÇ,úÙ¼ãÉ£:7_QX’}a#uÐ:GQþ;~ï V¢ÜˆRµ)#£R³Z»çJÇ[ ×\julêim¹t¸–6¢É?Ë(ÙgÕ»²O'nІƒSô@õIj—_àõ6ÀÐeÖq=^']fA—Ù>è2°tï¾úÒ+_ÿrª„ Lêšùvd©Õ ¿k¦p–«ŸÍlÿòÅóeâºÜ²±ýTo¢ƒJ-ˆN ]æ´µV"kn-—æNå´SÚ„¦¹ÖÔZ¢²LÔM,9´Zn1D?S}“æ^SvúGQ5ѤMYR¸UEöSk¡€‚fpj|÷J=oD@E>×·ÿøÔ5kM?n²ïéR«7¢öAèlĨZW€YÐeÖq=^']fA—Ù>è2°t€=ÂI]3{N/ËÞ9[ýi”„ÿð>e?Ii´wpz™êƒ%ù÷rR í ¹Nww(sõðGe*¡µb’|ö^$]fA‰ÊZa39`¥Ië*ë˦…ûØaj‹½ü)A¤és_KîÐŒCgéHKKèÄ¿?…ã°Ða÷ßè%lŪ#?E‡…n@ ºÌ:®Ç뤠Ëì#è2Û]Vƒ.°G8©«ï œ^–¹ºs6å–ý¿ê[¹XøÇÿ©¤½ƒ³ÜTXs™ÒV„sÔ¤GÌ:ãè9¹Ò\á³Jöæ^¬6èkæÕÑ¿¶i;Irîc‡©¨ÎŦÏS›mÆ!á ¥“°‚NüÃç©)|—8,fãÖ\”åªÙQ§WâŽt™u\×IA—ÙGÐe¶º ¬]`˜Mê^+>ˆTÖGvEIûì%SöÑ?ÍÕ§éžYâ€SÐ2q³ÎԂΔ©„½*eŽæ^¬6hA§Î«Õ'šÊ(ß[‘n£è¹ƒÎ– ¥™)SÍå—ÄÓÀYÇlVRS#Óv¹­ókŽd=oø<5…w|‰ÃBÝ¢ÿTÜšÒžŒLá A—YÇõxt™}]fû„.ó_ýWÿÕõWÆÍ*ß÷}ß§yÑeöt€=b6©S©¯ï¡ˆ¢S)h=vŠÈ—÷ý)¢U¥³@gÂÉȬ3èÜÕñìg³aY¥ŒXs/NcЕ¥jV~l­¦5sxËOSŸyirùä_e;þ©ÔQm.¿$ÜNÃ~mÍØl™)ÜyùJÏ{¦ÿU¶J=otÖrR}àCµÄaaŸ§â&ê(ù Ì–Z¼€YÐe6â;ßzákÏ\ü䣿t=^'å®w¿K5Š$ÑÛ#Ðe¶Ï“Ÿ¹~vKÊ?ÿŸîJþÀ.°G¬KêÌ•§ŸRÚ¢¤l³3¶I3÷îÓŸ"ZU: t&œŒÌ:ã^µã™âË*å·¢4÷â4­§¨¨Cà€LåÛ6å[o,ÀM}V¨Æ“QÑŒ²©…á@ÕæòK±4pÊš±Y=HM5î¼P—‘«á€ŠÈC-\FÄ8÷ˈ:JÞeùOqÊïÙ8BþÓ¸ÿÒåß\øÿ ñÝW_záK—žü×¹÷§ÿÙõ0M—»Þý®}øýÏ^úÔ«/}%Ù¡@—Ù _üƒÏÜ*þò•ÿ-9{º À¡¼+Ò³©¤®yEB™›ìDî§R~pÆé_'i,iæÞ}ꜳd‰΄Sª<댿gÇÇÂÂ4½jîÅi :2Ñ䢚ŽîàEyÃBßëAhqÇ„«jJõ³G±90|«­›ÕƒÔT³0ÚÆa/Ï|àCUÏ>OMÑØd6nýÏ1M€øOÿáòï~æ×Þÿóï½ãG~øº–P•ûÑúË¿øs¿ÿ[³Fóç¾ðÙOž»ÿÞŸ¹”Í˻ξ“0 º À@ Ëì³IsìÙLUê$Ùé_ý‘™&Ñ¿“f×Ô“–ØòF’D­D³Î¨ t í¤º¿û\ÞŒÐÜ‹ÕcQªyý••™ë©ì mÄ춦Ç>&óæ¿ëšŠêìQl W;£lVRSÍÂhî,ÇR“pk=oøÜ%:›ÌÆ­ùö=P _˜P³D‹™*G¥ÑD Þwÿ½×¿½¢0*þ2®)Ò¤pK@—t€=ÂI]ýÿÀùÛ’,±ÎœmêS3‰fîݧ?ÄšKǰ ’nîpý”$ ¶J™»²¾U$¸|ñ|tý²~*Á^g°–>ÞtÍegùçYúSOµÎê ͳç3Fu:$d?úÏ~hËJóæ#·ÖóÆr,ÕM·©—p­ ¿.¦F@“Óh1S%4š^ùú—ÿ·׺–*âðì¥O­¾§æ}÷ßûo.|ìå¯=œ›ºÌX\¹úŒ^Ÿþ§z8Ðe`4ôÛ]—ÜïÚÄIJ¡ùcÊ$Ë´|*e„³Ìœý •¦¬ IKÕ£ŸÒ7qâÝÌçåvx¥Ò¼}à j'Û²J}[C—¼u<•xÛl²iƒi!ë z”È`àÖ>Þ÷³7¾<¨£jÕØŸzFß»QoñÔòM˜MKƒ¯¿òbÙ$ì‰J©Jt°ÐÓ\²"ã]ŸÑÓ5%žºž7BÚ%lv¡ÃŽ›Šö:µÊZL§ŸIYsýTÀ X§ÅüÔO¼ç“þÒ#ü…w}çõªESìõ ¯¾ô•–ìõN]¤½üµ§ÿÍ…½ïþ{7 ¾Êý÷þŒ.ÿ¾ñÜ^ÿë¯'›°;ÐeÆâñ'Ó‹áCy(ÕÑ€.£·Î>÷…ϦzeR§¢\Ôš‹RÐÈÜTR¾§zõL:‹¿è4%´Nt5ªô8r×2ÿŒõtÍ,¥5ZB雓ÙtçK¹üZµqjEvœÙZÍQI6K%HJ +²z7¹>°3)O^gPÝ<ÊE5Fá*M%ÒØrãfñŽÈ¥R+)£-û®O­S2A¬´XFÀäÈx!å1ë Ñ_¥ ‘,Ǻì@¹/e|4Ä.©ÔóÆ(õIõÁit•…/aáêSï¯ÜÐ)'žÖi1_{æâw¾õBiíÕ—¾òì¥O­ÓhöH Ñ2†kÝ-!ýò/þÜýè?½nhY¹÷§ÿÙ“ÿú#/|éRÚØ:è2c.sä ËÀh Ëtpnöà}w;…Ó?V©s³²§ZEY“²}eæ¥5=®?ÿ^AD¦T£V×ÌR&Ò¶œ|³Q¢{FiêvÆBC=°Nw…¬]o>)ê_†H%¹x/jabA6ú”=Ë¢úæÂ…Å,uK­}JÁBä[é­G}ÕY~05ÐãRQkà§²Oe? œÂžDI6ËP—QŠeŠèéõ¼îêƒuºŒl–Z¡žÆ,Qô¸¾™Hȇë=Nú„ÿö<*ӀƷfœäòKË”3Å f_þ Ñï~æ×®{Ü*÷þô?‹X¾ûêKià ^ùú—WH]*±_üûí.3è2Gº ŒºL§ ÊE™§EI7¿JæË¬ÏEÛIµrBÙ©‡¨ºK%Ø4,E¥(ª™í¥öÁ”ÎÔKÖÓzSÞÉRjJ9¢Ü‹Ô$65(#á°F½öòó±¿ÖRÞÄä{LJ®@›r¸ƒf©½UVa! é/_„Áz °U­1–M²_éÓ<᪩CQŸ+=U¥åÈzÞ¨×rR} åŸ˜ÙX—Ñãæ!Qš¢L áÉÿ(ª”©©—ÀÁps´˜)þîÏ®èâäc~ÿ]ï~×uÓ­ò»Ÿùµ4pLÉëß(¨¾ti§&r5Ýõ‰—þýöÖA— t™#]F]¦C$u*N†•‘ª2Hw¾$4Ä=g; %ÉnüW ©þª”٩̼Ci\Ùij5¡ ˜¾Ïµà)ô )g$d¿\²b›:”(yž]ûrƒv~*'¿çÆM@2˜šgøxö)£]i.svù³gcêèÆ¨Ž61Eé'ÔåÙ+F8\Ïþ”&6r8âVZ[þ6éu! KŽ7Àžrkµ˜):¼MǤÔeÞuö·äCCšT{ôä¿þȽ?ýÏ®»²¬ÈáøYÜGsÐeÆ]æÈA—Ñ@—é ,ro¥v© j]f_ÐnƶvîèñÖëAjJËã6Š}\>@bL-fŠ¿û³+×=8)û¨ËÜõîw¥Ö›ÏëýõÿÚéŽùaíx2 A— t™#]F]¦ºL‡ÃÖe|¿LóvŒŽ€‘yõ¥¯ì‘“¸îÍIA—Ù Öæf¿œøþ{&…… ËŒºÌ‘ƒ.£.Ó]¦Ãþê2×n|;ŒœoÊ.¦ÿ;x7˨,ü ÀPô¿ƒ6•A´˜’ëžt™­3û¯RXºÌX Ë9è20è2Ðe:ì¯.#|;ŒŠ¢§ÚkQ~³4÷ýÊq5¥ÚŒÌw¾õÂì=j1%×½<)è2;%þµSú¬Sê A— t™#]F]¦ºL‡½Öeăÿ‚JEõgï<3u/Œÿ[ÓÔWŒÌË_{ú$¹Îep-¦äºÇ'eu™;~ä‡Sëà”Ϋ¤VXºÌX Ë9è20è2®<ý”’ð{î:»â¿Õ<Î=|ûmoÛ÷/X‰µ£-ÖZ„—ÿ3¨‰úÀÂàhIºÌ#ü…½ÐbJ®»~RöQ—QI­ƒƒ.³ÐeÆ]æÈA—Ñ@—8’.£§©Ãø\wý¤ ËÜÐe¶ºÌX Ë9è20è2ǺÌ-]ÐeÆ]æÈA—Ñ@—8Ðen è2€.3è2Gº Œº Àñ€.sK@—t™±@—9rÐe`4Ðe†åÞw¿ë$¾•E>$¯n-×Ý:)7G—Ùë]à ºÌX\ýÆ—~úg~âó_üõTGº ŒÆ³—>õS?ñžýúG G‚rÚÿóMoºµÈ‡äÕiØG™@CRLn>ò!yµ½vþ@—tXÈá%Õû¸¢½Þ…½vþ@—tXÈá%Õû¸¢½Þ…½vþ@—tXÈá%Õû¸¢½Þ…½vþ@—tXÈá%Õû¸¢½Þ…½vþ@—tXÈá%Õû¸¢½Þ…½vþ@—t€½àÑ÷y‘꧈Îd0z^»úlÔxlŸ¦'®ìPö/‡¤úÕ\zâÜ£x ¸pîa/ð&pxIõ>®h¯wa¯?$ÐeÆâÛû'Ÿþÿé_~5ÕÑ€.£ñêK_ùýßzü»¯¾”êÆa»ùÕBÐeàxÐÁÐñPYòB»ç®³Ñ¹S|Òâà©\zâœ-t¨=yíåçm¤S’筨ϣx v@5ŠCê¹#/©ÞÇíõ.ìµó‡ºÌX|îw.è\>òØS= è20ïÿù÷êMékÏ\LõƒpöÎ3‘Ýdi&21ýLõ{J,]šl¤b¸s§ø¤=xßÝ©¦Ãµ«ÏFçòu'—¢²_v¤Ë”‹•WÁõç7ëuxIõ>®h¯wa¯?$ÐeÆâñ'Ó¹üÐGJõp$ ËÀh¼ïþ{õ¦ôÜ>›êa[ùÕ¦DöUæ‡{M,çæ¤‘°wlô*sçKOœSÿ&þ˜ïvÑÏÙÏþXÄ)¿ ZÖ¢Ró–S$Ü?ØÊû†ý‘ó—/žw½‹R¹ wÍ^R½+Úë]Økç t™±@—9rÐe`4Ðe`p¶’_­ÀÉdªßSb9 fª½Ê6}Iºÿ…s§¦„ÅŽkWŸu¥f‰ÊNï¦NÖ”ŠRmäÊÓO…}µÎêM§äð’ê}\Ñ^ïÂ^;H ËŒºÌ‘ƒ.£.³ñ–eÎP£AªŸE÷1p£«üY—lV¤¦&›öD?,5 ×»i~µ©ÿÂCÊ%8%sÍrìÀ˜¬Ž¡ñŒSÁŒå”™íÂø'<ÑjW·Â:ç›ØÔ:k1ðÖFãôlô*Ûô%yáÜÃÑ¿<~5ŠatK/:Íõýá‰M¬iÞ¼SâX>úRÓv9¼¤zW´×»°×Îè2c.sä ËÀh Ëtˆ¯{t’à«p•úÞõ+O?¥‘ýFÑcÕ¨>õJÂr¤s—/žW@ªŠ†üIDATá±1°™émäÒ¥'ΕfUôXݦ’O¹Ú쟺™úë0õt*EQ“ˆ?˜kie¬ô ^¯œ‰!ÑG%žÍ mÓõŠä‰Š,Ä–E¥~–ýûhuÉ=í¤m²Qÿ%¥=–åg.‚èq[ÿD[=­]õÙ–ÍÔ„‘êy­¥å¨Y~x¢)Âr˜RÑc¹§Å¦žAÌëzý•u´Ê±Í°ï r>V±DÅØ¨³Ð 0¥Ÿ£ut¨4KÔkÞ²¾Ï¦NÖxs§N×B½éô^R½+Úë]Økç t™±@—9rÐe`4Ðe:(=Ð5·®Î•ƒù*?JºwF¡¢þÁõç­DâLCʱe‘…ZÓYî’²Çë •KzPç*r2ZURÿ”& /g/;«$O‚è Sš¨ìì¢Ê2ÿqÎÓ,êìžÁ¦ëSž¨X.ÑÏ4ª‰3Ï(z\>ñ%ª¼Þ\ i:\ã]HÃõ õŒ&õ_ÿ’ÒϺÈfök„zÆ(•úu!®h¯wa¯?$ÐeÆ]æÈA—Ñ@—éàKs¥©ÉÄÕ3üwàòÂݙƔå©Ìv‰KÍ%öÙ5 ÿ8,ìy35 ÂdªYi¼.=HMá­ÊTæ³b½^Eg½³f—¦Ò\>Höqd–«iSëŠÿ’ ¸Où°oeŠî°+‘ŽéǨzº˜bSç›,9êî“<±{õíHbÉ¡–XšÊÔ«¬Ä§Js#¬[ÕñÑ!‰¦¦¤åÀN•úÀˆVT³ðPr–…^R½+Úë]Økç t™±@—9rÐe`4Ðe:øÒ¼sÍ£~ªO§ßåõ½êëÊDXV)3ÛY—lY C8PÓÌ%\©<ßh]¥ÍǤ•2^V:±ÚHÓ[ãê³×ÔÊUØT¢¹Šu4×®mz¥£S7ût°º¡rO÷ßN‰ñwåÔ¨ ¯ð±/ïeˆ°GH›þL9¹Âù)¼õýÎ1c¸jb¥©²¤ïçÈÄÒTÊMœÂõ ÉÔ­|Žj:«>-Íwﯦ‰‚¦š£úµdE5 ÏÉ)gYÈá%Õû¸¢½Þ…½vþ@— t™#]F]¦ƒ/Í;×Ü‘i,)åõ½3ÎEóŠÖ%[^RJ#z\®E5WêÛÙ" åÀ0®E••Æn×ég>ëÖëUÔÓ™p8­b%–Ê峚˜«^»ï ˆ¢E¬É=7>q£¢‰:úN¸±QüíÞÔ¨@­Ñ­”`|D96zF­Ÿz,¯|Æ<]ý±”ÎOáˆõ;{×JU4üW“k}?G&–¦Ò|•%6ê\âà'=4â6XïïF]ídà·ˆ¦ècN9ËB/©ÞÇíõ.ìµó‡ºÌX Ë9è20è2|iÞ¹ævþ¦}ʄٙF'9l^ñϺdË*ÉDä(CV⤦ëãO,$í€íL‘òÕhÔTfÕ H?óY·^¯¢žÎhHØLõS\¾x>†¸Ä¼®l®]§" õŸºÝ É¥“ÿ™u}ðIÑÓRM¦¢GijTàÙS0cFýL5!»X…±I»úÔjà 秘ò63ª”§.Æ–+Jôý‡¥ù*KlÔ¹¤ù1KxS ˆ÷w£À®v2Xxø}NêWÜ9¼¤zW´×»°×Îè2c.sä ËÀh Ëtð¥yçÊ>®Ë;©Zgä°™W̺dËå0%ÊŠ5‹ó •òÛv ãy“08åU' ýüjÝz—¬b£½|ão©Üsò¯²Ë<­¿v¡ÎIÛHš¡ïØ‚$u£ïC3þþœT?¶Þ Ry¾9"”çä¹.9ïx¸Âù)¬‚õ;ÇŒúYVÆJSeIßÏ‘ñ&6_e‰:'"D*~ô?Ä$Ö½ÆOã¤X8ióœlÃKª÷qE{½ {íü!.3è2Gº ŒºLgï+ûu×å¾èßT˜uia:±Ï%œä»²ãy“XΔW€ôó«uëõ*î™ûöâÿ)ìd3·ì¯Ý¼þÊ‹Ö26ZŽQ®kOÒÒVÄal=cÚ 1áI¤ßeòØS= è20¿ü‹?§7¥¾t)Õƒp ×¹²_wõï‹þ)]À9mºâ_âÒS'QžÎŽm”#‰ðjj”R§Ö¾ÁajÉ+Öëé¦üyý•72Ûï­ #¶Ñ¼5ÎÓt}šñ_’vöû”Mñ¸<ðåaöM¾¢$Æ®8<5þüTg;Ü'}²FCTÙ\iÐ÷sdbi*S¯²’:',ÀE}~¦Þ …÷w£ÀžÆÉ ÓO9™š‚©s²u/©ÞÇíõ.ìµó‡ºÌX|ûoÿäÓ¿ññ?ý˯¦z8Ðe`4^}é+¿ÿ[÷Õ—R=ˆ%"ˆûtòŠg*Í;,,ˆ$³K\²Ñ´¼ÍéfÓ•&1j*³r@êÔÚ>L-gÝzÕôé›ÀIº¥¦&ŽIªZZ퉘zá¼MšÓõ}˜Š¿ãPïK`=¥yþ½5þòrÊ{dú«^çüaM¥¹õ«N'ªï¤èû92^rùJŸb£Î5Ž¿€?+7µÂû»Q`O餰…í¾ó¬àð’ê}\Ñ^ïÂ^;H Ë º ÀaE seï¿÷ªL]+ýH_âL#Jú4²s½¡º}`‰Kþ®96ÕMYPiYIuÓyg&eg§âj}ý•]_R[맬HZ{ÉSÊ׊õ +_É%­È«V‘ͲuŠX]퀞F“JšHI]‹öo?)Ñr´„Zóá‘ý²>Ìn[Óðú+oÊÖ¦HçÒº›½ŠS[ìn©>èž&Þz™M§¢l­§ó*R½éû92±4•©WPÉFkü2«ÇÞß{J'Eÿû•d6¶»ïüV8¼¤zW´×»°×Îè2.°G,A„/ßU” ë©ú eÝN<Ò•½Z£\Ù«¨ƒ¦N U4¼%ºTfžz¬ô8\Ò=IË$ÖNÚyõŒJ•”ỿŠLÉI­4Fi¸:‡}=-‡D¥–•FOì5RkeÎѤ"ç#DÉΦ률&kjZKT†xPŽš¢tÀ³ÛZ”äs4)\î¯è¹‡„ú«›úkjÇ¿œ1‰>Q¿"þò0šTôXÔY?Ëz-!2öGES«ã¥ª‚ÕÎ7ñ‡ÔTô@>(òšZÃ5…ëe6 ŒÖz¦ïçÈxá>‰RPsgÕ»r9~E+\1mAêS¢Y¢ÿFÝhES„{*ÉC wÓÂSw/©ÞÇíõ.ìµó‡º À@ ËìºàŽ+o]…§¦„zú2½Y’Â"ƒQ¯ž%•f®²Ü¥”ñ¦"oËÛäÞõ†ª4s!eVN{šEö§îŒ(+MÔ$J Ь¥>­7PÂ^¥"'åO„ºžhŠ©€(¶Ñ”Ö>Õ_¥Ÿ¦¥®T—Z(‰Îɳiü]d¶#ʈr™éU 4öz[7Ô§q¾‰†tâ¯éÔ! 1dµŸ#Ó‰F”rÕî¬Ê)úAHÓÕw-•xUÒ,%én´¢)Òù”Í@£RÓ]pxIõ>®h¯wa¯?$Ðe]`¸pîá¸ ï§ òd¥Ó‘!U.Zß2IuPê[ŽšÊu7r)™µqMZÿ­X3¦Îê©éR· QŸrˆ‘æ(Õ«ó”âBOgFù\ÎÒÌÀ7Zo yÓ[ŽP«ÕgINjll}H3õÚcŠ4djëk´¨°\ZÐ,õy²Üô!˜}<„fŸ ¬¹|ñ|XÍCމZµ1§t~Š:þ}#r@äLª7}?GFžÇ;ÒTQp–wV)û×(È×û-ÐG´¿×»vKzOØhEtòÕóú˜ï-7m£/©ÞÇíõ.ìµó‡º À@ Ë€Xñ~€ñÚËÏ뽨C)WÍv³™{Ö7²Õ\zâœûO‘$ÂV4‹:ß~C^ÞwwSd܇—TïãŠözöÚùC]` Ðe@ ËÀ/©ÞÇíõ.ìµó‡º À@ Ë€@—€%^R½+Úë]Økç t€@—.K8¼¤zW´×»°×Îè2cqõ_úéŸù‰Ïñ×S= è20Ï^úÔOýÄ{¾ó­R=ìtXÂá%Õû¸¢½Þ…½vþ@—‹ÇŸ|LçòCy(ÕÑ€.£ñ¾ûïÕ›Òs_ølª‡òÍç>ÿã]:^R½+Úë]Økç t™±@—9rÐe`4Ðen¯½üüÍü°^R½+Úë]Økç t™±@—9rÐe`4Ðe†åð’ê}\Ñ^ïÂ^;H ËŒºÌ‘ƒ.£.0,‡—TïãŠözöÚùC]f,ÐeŽt t€a9¼¤zW´×»°×Îè2c.sä ËÀh Ë Ëá%Õû¸¢½Þ…½vþ@— t™#]F]`X/©ÞÇíõ.ìµó‡ºÌX Ë9è20è2ÃòcwÞ¡_Ó·¶È‡äÕiÁ”´ß|äCòªÏ^ïÂá¡=]f,ÐeŽt t¸i Àq‚.3è2Gº Œº ÀNA— t™#]F]`§ ËŒºÌ‘ƒ.£.°SÐeÆ]æÈA—Ñ@—Ø)è2c.sä ËÀh Ëœ’ ç~ë[Þ,®]}650gï<«NõPƒ.3è2Gº ŒºÌ)yô¼é¤|ó¹Ï§¦Ñxð¾»o¿ímgï<óú+/¦¦M‘-]` è2cqåê3J>ýOõp$ ËÀh|ö“çîø‘~åë_Nõ°}Ñe^{ùù·¾åÍáê…s§ÖMA—Xº À@ Ëì—/žôt„Œ}Ôe.=q.µnÊitELÕǾàÈA—t€ý"´ŒŽ±/ºŒ¸pîáÛo{Ûƒ÷ÝêW°Z—q¸ô 5*è2.°_’.³EÐe–ƒ.0è2ûºLt€å Ë º À¾ðÍç>/¬ËÄÓ üFµ.sí곪 ~‹ŠÆzÈ¥'νöòó©Ã,ᘟ^yú©°¦®”Yõ鸤¦ ç¶aÓ”=k]Æ3ÊBÓ—‘ï»;Â¥SÆ t€@—Ø î¹ëlÈÍ¢V÷|´Ðe^åųwž‰§.ªqçšËχÆQ–·¾åÍåKýHÎèqrÞBLç&õ©=O¥t©4¥…§%¨>}‹Mù­ÃuQÓ ) `_@—t€½`….sáÜÖô ”!n¿ímî_R΢þê&{b]à ÐeÆ]fSÐeV©”ÊÔÇ ºLŸ)aÂÌê2M #*U¼ïnY¨±pSKMÂÏ~ç¦'ÈŸcªÍ6M•L ÔÒÞ˜ ]Ž t™±@—Ù”­ë22(RåMã&è2þKµ ·ÌÀ,è2}B_èÖé2³¥–6šLé %MO„ט–àoð­ßI¦L™)Ðen—/ž?{ç½½'ó;€[ºÌX ËlÊvu™G>úЭ­àæÜ/¿†õÛwá7†Â1ƒ.ÓG/%½cègª7§Ôeô ÏÔá§ú§úµªO½]¦ŸøòF“ï߉Î*M›S¦Ì”?è27 ëui¾«ï º²ÕÒ´þô{ºÌX ËlÊvuÙ¢µÜ]`9è2}B_è§Ôe¦FmÊ”RÒô¤¬áï-jjþë)SfÊt€]cQFoÅz¬÷[¡~Ÿ¯ßœ÷‚ çÞÇ%è}lAÐü­:2¯½üü¥'ÎÙí÷]ºÌX Ël º ¬C×ܬ»t™>q ¨Ÿ©Þè%ÞUÖé2 o‡™%üì_§6=‰›eT)ÿu±uöÎ3ê&ú¯ ¦©’).=HMpzÊ[ Ó/&=7g•ýºFºvõÙø½ãRÿ~ý¦sÀË¢_µ{¡ÎÈɸÿºß7ŠjTŸ:Ã,è2c.“ˆo{ùãŸIõf‰.óÒŸ?v„§Ö’›©ËhQáRY9¥ËèO¿,Å·éè,RýMÀS¯˜ýµ—ŸK„vw^1‘ˆßßú‰:Ó]¦O\Žègª7ëtª¿mwágÿ:µé‰.­fÖ4M•Lùã„]`Äû³JS÷÷oŸMßöo!¥ºáÕ î¿.bís”úéàÒÌå‹çí³˜¨QÙ£#4è2cq̺Ì÷½åÍ⑾±ö?~ñ™;Þñv=½þÊ~Ó›~ð¶øÍßþDÙ?øò´.óÒŸ?÷³ïýÉ0}Tô¸i*º¹§Ÿ©ó¦È·ÒN<‰Tôø=?þÎhªu™òžÌ(z:•±èWlÒ­õøž»Î&™#úˆ²ò”ÔS«4g”£†ñ[Goîzûöp=µ©_Hš«ì¬¢Çš(uëÙfYC™]¦Oœ¢©ãêkÜt_±éç민X6­#¬i®T_Òôį”>«ß4U2å¢t2Û-LMFïŠj3£€úUï±³ïÏúÙ¼~ ]þÅŠô E¿üK¤ÿûî–Sþ²Ó%h\B¨ÒËQéü¸¼Ñ9Ñ=(—0•°@t™±8r]F/à‡¾ÿü“¿RÊe©Å—)]æ7ûIûH65‹;ÿñ‹Ï\¯(v– ßdD\ûö w¼ãía3•¼íÔšt™ò­Mo|A<­s<ÿ¹.U&³)Ó¦(a‹‰šE]¾x> ñ/$=ðüMEëÔ«\¦:ñtÓw¹¡ˆ¢Ç¨35è2},[”ǯTRâÂE¥~ÍS¯ÇòZ³yq¬ãª>©rŠx™ÈTª/iz¢ï‰o”x¹ õ ä@óUÓ4U¢&uP·T_æ c¹|wPAšØÿJêÜŒoà*{qQ$oõû¿‚}yYÿ~ ý.“‡ÍßbåÅyõ>ºŠž:E¾4ê\@ ºÌX Ëüàm?¯ä;Þñö/þÁg¾üÕKúéJ=-GMé2–B~ö½?éÏ ýñ‹Ï¼çÇßýÕäÎâ‘>¤!Mô@Oƒ¸…ç4Ø™Xˆ¨F^ =ˆ…«hÒR—Ñ›uÔëÛïËÊOô»Gos)Ç+s'½¡«5ÐãÈʤ1~ãnë½²JÊ©U©h®ô«E¢É}M*ÿñÏ_´.ãß‹KÄrg2õ;¸ÞßÕZÖGçm½Wú—Gów¼Kwc–É•,¤jÊŒ´ôÜ9ðÖQɲ]UÑãÎ%ËQ.3Kyr¢èÅëV]×F妺ŒÐ‹××ÐuÑåß>/(Í•êK¦_EO]äCt™±@—éè2þ–™ò _öK—)¥»ôýßÿë2ʈü¾¬7¸%ÂÇ·ïè_ê«ñ/øT_ÒLÛü‹³“Ëyùå'¹¼X=HE/ÑMQ“ºu(?L±ÑÀ]æ˜ÑÉ—@çuj¹óz€XrÙæwþ}”6öÚù`ßo6ñ_‹åÿÔÂÐ]f,>ýG—Iõ¦)šôu™—þü¹G>úlÊxÉÔæ§Çf§t^•ºŒ^Ÿ~kŽ2¥DX>XòM4"¤Ó¿Ý7oi©±.s¶øŠ™%ù^ø©RÊ"zìõªè±,Ôö)û”¥3]‰ºÙ‚tþ¬tð¼ÿçß«7¥¯=s1ÕÃ1P^à6¯®üzÔÏÔ£±ä»|çOMã³×ξú½_~üwPe(Þww0­B•©3ôA—‹¿ø«+úÈCW®žê¿2ï)!LlQ—Q%•Pd‚¨i™j: 6»©.#ÒgjTô–—¾%wÉoÙ’xÇ_Þ ÿò뛲.SþŽôØMuñÚËÏëwU¬:Š';ªiÒÿ¨W²¬zzÌ¢ŒøÆs_x䃿ðo½êáHðËP/]réÂK¯G_òâKS2€¡ð›vº²*ÑÛ{ô)/Ûö_^î£ó‘ÕNíÅõ§O”K\-p§Ì Ðe`B˜èè2?ûÞŸŒ|)šLé2î,³ñ¯²_úó碩/åL5›]¡Ë×®>›”ˆRšqýM¾_FÓż}SÖeÊO™úç ]&Я+-cRÚß”ZëA‘z™û•Ø,zÕ Êì¾Îéè2Í˶}a¯u]vzƒ:—ÇC¡ Âó(zº/Kt…Y]FMñRÿâ|Æ•M‘å¥?.¬ég-… ¨ËØ¥ò{ÓkU¼þÊ‹÷ÜøÐfùû¦¯_ÔD½c¦úÄ»pß”~¯Ÿx÷=¿c–è2KŒ _@¨ç %¥Vdúßæp„衲Þ:ôJ ôX¯€=ÂWŒë_Víc^½×ºŒwG¿^SÓ^pí곺*ó± ]`§>Ð]FÁJJª7îà;_DSdqåïx»+MG—yä£M5ë2çŸü•Ôøîž»úÇ;ºL ‚~ºÆbÍ¿lÄû~ia5áŒJç¼û”·óøçÔ[¶ F‡%~: •©EŽ_/u4—%ÚͰì¯.ã­ÙGE)á©ð÷›å ËÀ(„ì¢òžgjVLÒ 5}]¦oª_úWc]FkÔ©UxíOýÖ“³ºL­ª”Fueɵ«Ï–šÈuß 3%í_¾x>:¤_3þÅ©Ò|Ëöï'=HM5þÛÎr]FCPdàxXòÝ1qu´•«Ä›Ïžê2¾èUØ7úã°ø®™ýÚˆ[ º Œ‚µ •$‹|ù«—ÜZþ“ìhŠú¦.£Q® Î?ù+ѤÒÑeê§ÁºŒŠ,—ŸÃZ¬›ôJ´.ÓT üÑÓôû2*UjC¿ƒÕZþad‹ºLùQØúnýjqk_J]FEN–­VšTJEI«kŠ8±¢Ô¹‡ ÈÀ1P^Fêqj¾›ú{Ûàì£.c±L›r¢ŒðAÒ¢RL.£ÊKüŒ?ûÞŸ|èáûõÓ•õ·Ï4uá/£Ñƒ/þÁgÔM?­€D©uá¹îxÇÛcvY(?9µë2ɸЃ¨QùÍßþD©ËÄ/Ný^Ô[›Þ¦E(,Ñ9Ý€Z êóà}w«ƒ°ú°#]FÈrL¡"Ëzzåé§äê=ÅG„jµÈ¿8Ý'Æ ÿÑ@%i=á¹~Ê~ÄD J•®!ÔEŽ ]üÄUSóÚÌWe{zäËK]¦¦1)õ 9ŸZ÷oĶÒc]F!4‹¼í~ó·?aý¢,µ(#¦tÕ7¨ò‘>MiH` ¥,üâ©þs¹mÖÚK|õL©ËXn¨Ký«T”úH*é—SXÞâ¥?ÍÔ,Moý~ZL•ø•.ÉDùÇ¿æ•Û^àË˽¸,Þt A—‹ÇŸ| ]&Õè25è2ûÂûî¿WoJÏ}ᳩà–ci©CrËñ%³eØëd9VJ0©h—/žOC ºÌX Ë «Ëüñ‹Ï|ù«—6Âß<¾.“~{-!YØYˆ˜ Ë º À¹võY]/¡ùïÌÇáÊÓO=xßݾYFèéÔ—KBt™±@—V— ÷6*c×eô¦îmTNùiXt™}]`§ ËŒºÌïx{ª„Óë2zŠ.c¾ùÜçãîGt™ÁA—Ø)è2cq̺Œ˜•-n!§ùS ÑÝç–è2">š´É ^{ùy¾¤}|Ðev ºÌX¹.·J—˜]`§ ËŒºÌ‘ƒ.£.°SÐeÆ]æÈA—Ñ@—Ø)è2c.sä ËÀh Ëìt™±@—9rÐe`4Ðev ºÌX Ë9è20è2;]f,ÐeŽt t€‚.3è2Gº Œº ÀNA— t™#]F]`§ ËŒÅïÿ»§”}ìW?”êáH@—Ñx䃿 7¥o<÷…T[]f8¾zåß^û›«©Žt˜âÊÓO=úô³¬¼ôÄ9U¾öòóeåvyý¯¿þŸþÃåT Û]“ßüíO|ß[Þ,ùè>}( ]æ8¹|ñü[ßòfqáÜé)xíåçÕú¦7½éž»Î–õQyöÎ3e%ìè2p˜<ôðýÊWUô 5̬.síê³·ßö6ñèHM°¿h7ã¸Nmktxë[Þœnñ@Œ²öt8LU—¹ç®³±.¥è© ö—Y]f꾘©ûh`_@—Ã]öˆ¾.sé‰sѪ©Iœ½óŒš8{ º &‡ªË\»úì=wU*~ùâùÔûK_—é+/}Õ]“CÕeà éë2Sb2³`XÐeà0A—=¢£Ëøv˜©Õ$n¿ímêÀG™öt™CæË_½$üô¥?îü“¿òÐÃ÷ =p}I QÏTüñ‹Ï¨U?S½‰á×¾ýBªñS;Ð1²)26Åÿà3Q©Ç‘Íê{Ö¨¿Ç>òч¦.´¨´vÏÛ¨ÕG‡ÙÅzk>ü{øcûØïýÞïý?¾ý—éµj¾ùÜçEªu½RzåùbwŸpñ¢éÕµ«Ïª¾óß‚Âíôo†ŒÚ¾æjv eÍ•§ŸŠ!Î=DiN±/ýùsåBôØOõà=?þÎx\ë2˜¢r¬Šÿæo"².£E¹ss¥hÇc•Zš±’¥¢žøÿÑmÿïÿýëU­~¼D—)ÿgSOU¶õmÁÊÿàŒß~ÛÛ;PöŒJý,+Í”.óÚÿ¬â)¦LE}áu$E)âèA9KÔÔ·¨¨ƒšôÓRˆºñT¥)Ž”+R)‡è=OÑó(ÍXÖ'®]}6†÷»­ã}÷ß«7¥ç¾ðÙT[]f,v¡Ë„4 Ÿ¾;¦¼ÝCõzêQ®O·Òˆ&¢4ïþðD®±!U„ªÔÏZ.Ù”r þøR-Õ¹ƒx HVáåÇ2Õ3ä'u³¤¦°+¥øRN'¦âúø~™_ÿõ_þÊÉÓGcfugûî ¡&¨¨ÕýWSН¿òbYÏ]g/|ï× Ø«²ÒLé2Ö)Ò=>zZKž"†”‘±~¤’Ly*ÉgYˆúz®ˆ¤ÊOo}V©ïµñ2ëOÕwܤmŠOƒêOº ÀNA—‹]è2*?xÛ$•AXƒ(?€sþÉ_‰ÊZyq•ï«îvùâ|&šÞóãïte郆詛N‰§“ÙúcGJT’.ãj9e½ñ2Ë…ë2*©I”ÁÑãmû“Êó¤Ô„.£òÏê'bH’ fu•2ó^åE·Ö÷€lŠ\ SIéhÒ× ¦t‡þ¨„—¦õ¬X.IS¸>E8˜†J¥hñ%펼ŠzyXK6¥ “Z!ª·;±QÄ6]`§ ËŒÅŽî—©Ea…"‰,zZWºÞD~ö½?Y×—ºŒïÙ ž®•JìgÒe\_R)(Ÿ²ÞºLó^!·jT­9š=5%¬Ëüñs—cHJÈ—è2µ6!|çÈl†?‹Å‚¦¢‘èëÛÕešŸÒò}1úé{[D ;vö{ÿù´u™f­¿¤å8øÍ8‰)³õì®ÙÂéu·º ÀNA—‹]è2I˜(iJ0V.ÊÛ[¬VXÍI·~4MÙ‡ú“SÒt²ÄBI¹ü—n|%Mò3}TJ…Å›3z¥SÊË’y…u™?½ú|L ù¬.“ã›\f3üYìƒfœUÊÉm« ÷´¾&Ñ_¸¨5 (SB‰hš SSË™úž—ÚÄ”þ²\M›b5è2;]f,n‰.£Rj þ>”òV”¸?%d…Zb°Þ‘î%YâÃ:jM]fV= š¢ÏMÐeÆ^ü꟔ßùÍO…Á”[Ȩõ¾<Ѹ‚òÛRî¹ëlýÙ^M ö*¹mÝDEMýLõ.êéAÔ¨I›4=ùcj9¢éLÓT‰¦S=(ëcºº¾Æ=Ñeö t™±¸ÉºLS€°ÈRJ Ñ3n{ñ·¥øvK9éÃJK|XÇ:]Æ~N©'ÃR޵Á­ë2 Úïx»š¢O*)!D—¢œ½óLS=éKSºŒµE¼ïîòƒH¦¿p¡%‡¯Ý5³%y«žZŽh:•Qµ‡ƒœêkÜ]`¿@—‹t×ß/¦±R²‹?ÓôÈÿ–}ÇÉ¿FªE‡ÑtWŽ£ËD袨õû¿ÿ-ÿø¤üwÿð¿Ê”£ËˆK'ÿ)ÌFI߯"ú’DG—¯üƒ§°Ekõ§¿p¡%Çp¯Ý5«R¸T£ÊÊ’¦3QÙU{ø+S}M8¦‚.°_ ËŒÅŸcþVÝP^â;eÔ9d­A¤§f4]Æ_޳P—)ò ]Æ¢ŒFÅ÷%ïîûev¡ËWž~ªüBIšéK}]Æ\8÷°u•ôÅÆý…‹ZÝЃT³p££°4éALù³ÜOÇ]`¿@—‹¾÷Wüñ‹ÏÄØø¾˜øàRÙ­¼A¦¾}ÆìZ—Q©ÿùQÐÔeìO½ä’¦ñ­ë2rY¹ºLpåé§Â•òëfú’ÄB]&°¼Ò”~:jÍÂzGç{›„©©åˆ¦3Q©2õE<ö'íÎT}ML¡ŸÍzt€‚.3»ÐeB[©éß”wÓ˜Ýé2"æUI K)ʨ¤©½.•Úç2,©iëºLycŽm†.sï½÷F“Ê€ºÌÙ;ÏÜs×Ùôy™ò¶”²éÒçb^Õ— ˆ¥Š(¥ÛrUOë[K¬°hö²>æ¢å9ž]åòÅó®v 9fTY/SöcHYYÎÔ»`'“ó¥(£2µ­…\áÉøV@—Ø)è2c± ]Æ÷Å(ÿ×cA”©Ï‰²[-7ø»£4¿çe§ºŒ…•zi|ô¡x\O]zUSŽÕƒZ|Ùº.#|oŽê僦ø¹÷½÷ïÿý¿¯š·~ÿ[¢i@]ÆÚÄÙ;ÏÈš¸§ø¯Iõ7¶Dÿ(z,ÜÙK·íªšd-¦°U&­$,è§Ä,¢Ò,|/Š:{.Õ‡)9S ›j-+Kb º¥z™=±÷F±‡žå¹‡ã±º¥1£Jò¤ÄŠÕÔç¤Nº ÀNA—‹}ïïÿà3\TÓe„U•ZÝ(o£!Aj ùèCÑ:H͵o¿Êï¦Ù.²üž§×%—ÜÔŸZËWç;Þñv•ŽŸj ƒåÇÁÌìJ#V¥{æü“¿b7~ìïø½ßû=½$õÊT®œ<}ÄæõW^Te]/¢~*{ï \òMtöÎ3·ß¸3åÁûîžúgCú—­ Ä2Ó‡Œ„üT7Ñ\S7ƒ$)DÝ<êž»ÎήWžÈšK^M}Qq„1Õ›hU·Tȹä‰Ên1°övÉwÇDô3Õo…g/}ê§~â=ßùÖ ©¶ºÌÁ²ë{U`Ä÷Ë„.“^«0EÒe¾ìâïÐypÃÿù #€.s° Ëì#è2+8x]æÑejÞ1töä[r„]|ˆ v ºÌÁ‚.³ Ë¬ààu™×nü¯«úûnD§ Æ]æ`_—)¿¿f9³_‹³×ÜL]Æ_•²œ©¯M¹µ¼.#î9ùwÚõM1Ú‘“Wù›f¿FÆ]æ`_—‘cááFeØål…›©Ë„œ±QÑddŽA—ñ-3éKd´êƒ_;Àaƒ.s°üñ‹Ï|ß[Þ,šÿhäXx¸ýÿí½ïÜd]fSÆÌÿå•|ëü3ìÃàòÅóõ-KqSÿ?aÀÈ Ë ÄÍÔeà–ƒ.0è2°OþëüØþÓsác¯ÿõ×Sìè2cñí¿ý“Ïñ×ÿ⯮¤z8Ðe`#ùà/œ9)»SgþîÏ®<{éSß}õ¥T[]f,>÷;”b=òØS= è2°)Ï}á³w½û]»Sg~ùN–_øÒ¥T[]f,ò1¥@úÈ ßÔ »]Ö±;uæ}÷ß+›²Ÿê`+ ËŒºÌ‘ƒ.§aê º ÀNA— t™#]NÏvÕt8^{ùùG?ðÀ¥'ÎÍVlt™±@—9rÐe`[lKA—¹%œ½óÌ[ßòf‘ꦈ£““ê÷å<·ßö6-ុΦ¦—&'›®-ñ–¥Lõ2{\Õô¦7½)u¸ôÄ9Uª\yú©²¾Ä¿»/_<ŸšfA— t™#]¶ËéÕt™ÓóÍç>_“ú$â¢P×v©¦¸võYM<úRÓ‘ Ó¢3“‰=B/Š“”§±„Ñ–¦ŒKþÈ«×^~>5-±G‡÷–õà}wëà)Ù~ý•Sì/ýãzåé§ÔªRß;±NKŒ]ø›HShˆèh=p< ËŒºÌ‘ƒ.»à4ê ºÌ)ñUZ*º¼SÓÔÑ1êð’œÝqÏ]gØÔt$D ““ê÷…}Ñe”Ÿ‡?Ü,S19°Wßk/?ëR¹pîáÔ ûKÿ¸ž½óÌTkü¢QÓ”&¿»Uê2>`­Žt™±@—9rÐe`w¬SgÐeN‰¯º¦J3ÛŒk»©«ÆM¹|ñ¼®;¯@—‰“6ˆx±‚}Ñe|Ò®]}653±Göê+u¾UäèWozSxÕ«þä8¼éÁûîNMÌÂ÷÷Gç.3è2Gº ìšMÕt™Sâë¿øøR Küø‹\”:áÜ®.cRý!¡‹`]×*ªGû©þØet™â8ðÇíÄ¡¾É\8÷°ÞT{Jç¸>úN^â“_"Óë÷‡å"‹~aéÍDýÑyA ËŒºÌ‘ƒ.7‡åê ºÌ)é\Ã]ºñ%‚*é±è2°)±Ëè2;År*_‘àMöˆÎqýåûà}w¿ñк#&Þ4–o#‚u ËŒºÌ‘ƒ.7“%ê ºÌ)é\ÿ‰{n|&"圳—†Ñ÷ƒØåÄ‹uì….ž¨ÈÛÔtäð&{ÄÔqõ‡˜:7Äù¦˜t•ëùOL°t™±@—9rÐeàæÓWgÐeNI?]ñ•\ê0«Ë(-|ô˜©,QõÂ>ÄÓàôÐ ;e–þ\8÷ðÔ×"wzœZšh¶síÏVÐB.=qγ÷¿fâÚÕgåC¹öÒóÙ;ÕÕÁ5Ñl Kb—KñÂn÷}4µvͳ÷w$…Z~zììVв¿}“Á7^ ku™2ÎýÐ%ç¥ÙÝá‰Ji!X±õáÉÔ¼z…F‡TobÆrxòAbö%`9ŽXù2÷›Œ»ÕÈ·L-3ÍöjÉ Lž”%4¯ZëcwRðm°¿´ÕhižbÝÛ`,§ÓÁaÍnZšê½ïBO=dá—,$HÞ–Ç`ÉF‹Ž«úœ¼¾g¾µ7†§w¤¸YfÅ×Ĥ5&–Ç t™±@—9rÐeàV1¥Î Ëœ’~º¢«±7®«SºŒ.+uÙ6SÑtmç›qšeÅåc"܈ëW]û&¯ô4ý9Ñ\¾x¾^‚jd$õêÑ(‹:§ëfG2ÕŸåºÔnº:½p5®×åRí¹ 61ÍÕ\æT kÂϘº¹Íð E,uŽ25Ä¡Žó&ÓpùŽbIÝ_OµË6K(‰þu}0uBš{”œ/jHÙ³Iœ*óÒ L…“2^»To}¬kjÞHóTš» ­1cPú΀Nw[Œ”6Uô4^qýµL1¹Ú¼¹ mS}fw®½’Ù˜Øèý3ˆÖëÒŠ\/³Þ,—ÒÃÓ³ð=3¼R‰M©‰å¨Ô‹mî‘ú'©%,è§ˈ ºÔ缤9‹jšË~to7}«Yq\ýK³cVÔÃuôTþtÖÞDþL͸pÓá@— t™#]n-µ:ó?ÿì?×ct™ÕÔp%¾îLâb·Ö¢I¨›(+Ëkh_b6Ë”²°œ˜W—•ž(¼²?*õ,ºÖŒ&u ÿ½=HuUjã¥fáH6¯ïWpåé§<—§.g—·äÜYqs`×ôѪê ¢F?Sç)¢¿v¶£ÎË|R=Ë©£Ô9€C­©sVäžçŠR/9lÖõeꢩ]¯„Ü6õÀõÂÎGLÂyUêç)OŽ ž˜_´õÖV’“Â~ªhlj1J¹qö!¦“YÙz=ÖŠÃF”/ÆRFñžF©]-þòx§}OŠ¡— ÑOwpÐTœ{ïÊXú¨I¨³·F”/z#ÒT_fýT7ŸÀÒCŸóÓ`–²^>¤W™½r@^iiJð*J1+ö(-ÁΜ˜YtΟY(㯓i¯Ê"êc°ð­fõqõD©>1çåØTÚ\ÇyvÓá@—‹GÎ}0r! …B§<öË¥_°Îuž®€£UeêÚ·¬é²ÕøÂº9Q§é4„Ù°ìœÄ8éÒZ\©K𨬯Úk꤫D¡(/¸}ú eaç›~j.¯=íˆ •:%SçhJ{ÖR妨%=HÛQž´t•¯t·Ì‘J<$¥ôµŠÖ›†;#ª—cƒõ1V¬¢I¥<0A ¬ë#ÚjM‹ ÜZzX:?5p1]”…[ßyÙ:[‹RûÙXú°ä%¶¿k³e†œü)Ø µ_hisËmRSºóÅ£Td9ö©WY4¥š ³>E©¾Ü :&nMëZÁFwêmÐ'¤Ü¿ú¦âSb *Ëßâáf@´Æfk:å YtÞjÖWO×t²Äq®µ¿M±©rG6Út8$ÐeÆâ/þêû—ÿó½ýø‡Òmp$p¿ ŒÀ'ýW?õï¹.Éœ9óžw¿ëõ¿þ“ôË—€õ…£.¼|[_FS=ªCgÈ”§$̪¤¿ueªãëi_øÎþů“)5±å©„d9åÔ)!4þÛoZˆ÷têz=,«”)ÐF+–SšØáåññ2aõT|„r “¨ú´ž®îKKõ68•º8á)³G;¯²$ ]κ­÷¨$~E½‡$›^{ª·µ«ÓžègªÊ—ÊzmMÔOÅDxeúglvûÞ6qÀÖûtM½•­ð¡‰;ûž)ìÕÔËÜ'¤|m6_)SØÂFç\ëÊ›]~ Ds9¢ü©ãêéd¶¬¯YÞs¿\‚í/Ùt8$Ðe‚ï—[Ë+_ÿò/ÿâÏ]×cΜù؇ßÿwv%õðEª.àJ\¯éšR¨C4¥ú!1×FÖ–f5oª7á’J¹À¥ÒÏŠý'Ü…0ô…ìTB²9¦:×Äþ{fŠêìÆ9?)ýt Nó×Ñþv8žËãÓLÄl¨·èPl.¼Äfë%4—fƒMJØ`™@ºrëˆ^·õr K,Y•ñ ™µÞQFX؇¤òœ’YMM4ýŒJ•Ž?>-Mùlê´4§3•åq˜Ú¾©zo\ÚÓ÷p#”Jÿ=SL'ãÈ”n;Úšhj9f* ¦ó×eÏË—óì1h¾Õ¬>®Kvl¶ç,^xŠ|x¨2»épH Ë º Ü*Pdv„¯®šE—•ÍÌaö*6Еœé f­mJ˜í\˜ú¢¹¼ªöe¨Š:L%Õî6uEžP6êßaáÔͨÎnœõ‘2nÎTT¿îB¼¿ ã£ÓèåüJË>³¦Àr`D&U–Øl½„æÒlP~jÆû_œu~5áϦ[¯€×•>j FfËqD@ê¹f}X‡bõ†7Ý 5]šò³¤i|v›ú–#*S‡-P«™ ÝT½Ýžšb‹{á¹T:Ì’©Èø½ZëÈuô¬Ùu5ϹúÇ(9Ö¤ùËBNÖ•%ªår\95JØŸ²ÒKϛرٞ³4—PÖ«ô7 t€@—›ŠÌN‰ë?]À•èªkݵ¯Ò3%œj²å²4‡DÏfÓi³r5Õ_YêAYï¿öG‘…òOåAD@e¡H1{¿œf†Pãø—×Ó ¦.èµLTÑcír™ŠÏÒߎ~| ,(KJfC­úèPG&U–Øl½„æÒlp¶”g_Mø#WS½™Z`¬®ŠRÔè`œ úÿßNb)§¾ågÖ‡uxC;A«Wa?ûþØøFÛTOWqP©Û¦ïŸS!µÛõÁv÷bÉ{¦˜Ý©NdÜEoƒÍ÷ÞÙu5Ïy3ÚÍRz>{ š»0þ¤Ux`éy“æ×Ñ\B°pÓá@—tØ_ÿÃß¾òôS‰ßûõß÷Ïᆴǜ9ó¾÷þówñ|êsJþæÿ>yrl4¯ÿf™ºö-³w=êD}=DtšNC˜ÕÔ©Þt®u6tÝ¢ÈNyaª§Q__­6ñ…rçZ|!žºoÊÎ×nwBm?ë¸)cÔ…x=^(K‰X› ¦â£z¯WEFô4°'åcHÔOÅGõÑ¡èY’5c³ê™ššK³A=è£ÃæQ³Î¯Fɬ\Mõfj¾¯Ç{ëµìOõz‰§ÊÍNº7>À5ëÃ:¼¡ …“åÔ^oß/Ã2»Mõt%Ù)ëW¼†©ºÞn§)ÌÔÀÕ̾gŠÙ ¯Tšn+>îŧÎÌ®Ë{§ž®´Ûªì éJ1Ú¦¦–ÓÜ…Ù ˆð'­BËò¤¬¯i®qÍ%˜%›‡º À@ ËÀ.øÙŸü¯ÿJ¿Qþ‹ÿâ¿ø¯ÿëÿúºsæÌ?øÿàïý½¿w½mÛåO¿úo“?GEóúo]{Õ£t‰vÑ7Š.æÒÍÍ!Á:f ³ Sÿ¹oêúØ»Žn¥‡³c³WðËY8u3ª]–\úÇÝ+ÑM¥N¿›„?Sf§â£T´êt—zFSJfCÝè%kÆfë%4—6k°É¬ó« Vl½_בëEëUÿè,w&šõaÞÐNÐÂçrj/¤ïOÓøì6õ-GTʳ±îýsªÞnO¿íEç=S4ƒYÒŒLBò{ J’ff×Õ<çáð¦Ñ˜=Í]˜ ‚húãéJÏ›,ï9Ks ‰þ¦Ã!.0è2° ~èþ7ñë\åf*2Q.þ¯¿’ü9*š×³4¯}u}|ÑöÍè\.¯óa–0Û¹0 —T:WœBîé¥ùjU×£îÙÁÊkñ…xj%'©ÉLåœ]|sĬŸNR^4E;šññÍ•:iûfCÝØ?½Âfë%4—æ3³P· f_Íi¶>c#­Õc Þ¦XitnžŠYÖa:G±\B]éµÔøœ—cv›šÓŸå'p*tSõÍC^²£½šï™ÂšÈTÜš‘i¢ÃAV)ÛÙu5Ïy˜Ú4³Ç ¹ ««§ÓËúÏÛù±æšLm:è2.» t™óçÏøÃ¾®Çœ9ó«¿ú«ßùÎwâ¼í¨hÍ‹.£ lz=Ú¼öue3Éé\.¯óa›mþS9¹|^ÿ)Û×ß®Yèöìür–LíKÿt]îëæH¡k"&%ÑY6S}“~çf|œøÖŒ’©„a6ÔÍ®œÊdÒz Í¥ÙàBå.Øâ9Iœfë­MȽÊÅú‹Z´R'ÞÍ- 4Qª?%Ú”euˆÕ¥ŽIÓÛÀË·µÙmjNg<¯ì¤Ê4‘™ ÝT}ó—L Ü~›*Cä¸MIò':L¹]b…¥£ÊFç|vT/gê4wÁ£¦‚¯ádÝaª>áy§[Ns S47 t€@—]ðCÿè¶ò™› ÈDÑ\º€@—Qf¯óÍkz_ڦϛˆÎ…¦è < 1£Šì§&ákúÎ-MórÓö/_<ïJ£%— ¹¯Å·rÁê©›–|ý•Ý!¥µ:Ô×ÙZˆ[SS“˜¥Þš~çf|œ4—鵤…̆ÚfËäg[nP©—Ð\Z)ü5•Á&³Î¯Æá’?)b¢¿õ^¾Žt,ª<ÛÂ+ §iD„S­§!P©-Ö­iêŽÖø¨¤w‰ÙmЧVê½(7•½N…´yÈKv·Aó=³|•¹ÒXþS™r»¤¯ËhŠÚÈÔ9÷ _òëÀÈ~Œš:S» Ù£~£ã*¢©®O„xª²‘ÌÔdö • Ë<è2cñ§ùÕ÷þËqù>—êáH@—í’þ×ÒMSd¢hF]@ Ë(³×y‰æ5½¯ÓºV‹YTšy`y1·<•“ªÈá2Û)ÓìRU‘r¦¾–µ‡åe´³M”†ÈŽ*5©kf¯à7BFšfIWö¯7“Ëí²I¸IEc˵—ù@R”4ªÎœ¥íž"Œ—1)iÆg*m.ר’†ÙP;zi wYÆËãg7¢ÔK˜ZšOˆšš7A(ª)z³Î¯¦ŒØÂ­/‰î–|¬T­Ñ¡E>¨Oª?=å+¢ÜV¿ùø§›‚¨WÑî§÷œrßÓzg·ijºÀ{Qºêã—Ž„— Rœ éÔ!7ÛÚ M$ÏS|„—“Þ:¼ör™é­’"£Î餧ý,›J;jZ~Î›Ž•è<¤Q³Ç`j\/ʦÙãj'“ÁDtÓðæÛÎF4—°é¦ÃÁ€.3Ÿþ+“ùÐGJõp$ ËÀ¶HŠÌ?øÿàÓŸþtœ®›V4¯. Ðe„úú¯/ûÊJ]¥½qEvRt}¦K·¸z‹šÎDº†‹>*²,ÔMS·MñŒ~ÆÃù(éÜ× êþëB<†GeÙY”¦lßýË%Ì^ÁoJšZsÉÕrv=NCDŒ W£[ívhÏÕASDXÊá /ýÃ~2n¦âSzSkË¢ÒM)E™ µê£CX`׌³hÞXu½„èS×—7.…ÁX‚°eý,‡Ì:¿šp>܈)â±=QÑã4Êø…¬’|eèT”Á¦}Hõ[Á«ðºb:=ÐѦ4Ê7P¨Ä@õÔbmM¥N2g·)†×Óv¬<ëÞ?ÃT]¯±'ã&ø©›â‰d0|î¿g–ïöê¦"úë§^eÑTºmW¿ ¨h:÷,;Ç?ö,*z\ ÒËßsɾǦ³Ç@õÑ¡Þ;c÷DÔèÁÔqµÁ©ƒ0^_As ®”«z,ú›ºÌX<þäcÊdÐeŽt8=I‘ù؇ßÿCÿè6ý.¿téRœ®›V4»æE—Q6½€‹+Èz”®¹}q梚¸t‹ÇiHàKR—¤˜¬ <‘åת?ÆF©§¸võÙÚÿ(ÍkÍ)Ë*º¬/{Î^Á¯À9L]Òì&¼Õ_åÅæðæ2§Ö(;u¾1…·#ÕSñQ}sGä¼ó¨äÃl¨ã(ªÔÎw°Z#õ:KÓ qj] LYå¬ó« ç5ãF[oÊ›Gš=7=˜’êìCªß ]ØO%^æ±éÍ©/_Ù@—9ZÆßú[òŠ€à”o¶ãp$oq±ÌôÛ­£×lt™±@—9rÐe` Ë@“ çÖåõ¦ø’T׬z:ìÇìKŸ’®ÂW hlÅìão½Ïùr8ÉÛâ”o¶ãp$oqÍ\ÿ;‰›È`w ËŒºÌ‘ƒ.»]`XÐeÆ]æÈA—]€.0,è2c.sä ËÀ.@—t™±@—9rÐe` Ë ºÌX Ë9è2° Ðe†]f,ÐeŽtØè2Â.3—ÿèsÊd>qþ‘TGº ìt€aA—Žks5ÕÀñ€.»]`XÐe]vº À° Ë º ìt€aA—tØè2Â.0è2° Ðe`ß|îó"UÞd^{ùù[îÃ:n~ô"V×®>›êoòdO÷n&qnKÜGÈLíh•T°_ Ë º ìtØ”G?ð€öNE Ojºi( {ë[Þ,ÎÞy&5 Î-‰Þí·½M3*b©þ–pùâùqœ‘‰s[¿jâå_–ZšQçhâ°À¾ƒ.0è2° ÐenÊN•-ˆ{î:›šg]Æ—2·Ôtxð¾»cï.œ{85ÍräºÌ민(7äŒâšqTôS8ð/zÛŒšè£R¿ Ðeà`@—tØè2·Š³w¾•½ËÐeœ ®˜ýÈu¥Óƒxã/´þ«¬ó‚B—€ƒ]f8®\}æÛû'©ŽtØè2·Šï»û$e¸5ÊÂi@— ™CE›˜š.=qN­bê+-v½³wžÑŒµ3&¾åÙi|‚I¥¾GLÎËɽûTÚFÌnÓ®™=œëØ‘YqJ]ÆM{wO"@]f,.ÿÑç”É|âü#©ŽtØè2·å3Î=¼wßI‰.£-ÓÆiûR½?áØTp¶½%¡¯n¹.c7ê3ø-÷pwÜÚÌÎuìȬ8¥.ãCõú+/¦&€ý]f,ò1e2úÈC©ŽtØè2°)è2fsÔ£Õe®<ýTÇO§Ð©þ`áÄÎÎuìȬˆSÑØÔ êÒç¢þòÅóe=À>‚.3è2Gº ìtØt™³9êÑê2^xÓOt™›Àìá\ÇŽÌŠÓè2áŸ`€Ã]f,ÐeŽtØè2·e¢þ÷®©þÊÓOùŸèžºg ž1¤ÿ—áNÙŒ/øÎÞy¦ù!@FÞHƒZiØk/?ß÷Df½¡ž³ãÒøbáåo”å^8÷px•êû\oD µ¤á¸kDÔD&©¢xF(ÿm“žFGO­±:Qöœ%ÓDaPS{FQ~vC–£C<Õ’½Ýý½6é„èq}ûÈ¥ðSÃ]éHFÜÒê)ä¹BäóÐ÷Dõ2âêi ÔÏzHy2Õ¡tCLçÒ=hnßòmZM„%ÜZHÚÓ˜+‚¬"gì@Óçô:­ ›šɲzvÞ²º¥úYˆÙË·#Í¢ çLp ËŒºÌ‘ƒ.»]æVaeAyEjŠl$ê•ÃD·²¨²ì¯$3ê5°¬/Qš}”;•õrCiO4¥"kSÉXt(!¡§á¹JšEÈÉæDRw”´7‡¨¿£×ÏÙ%Ìѹ¹Y‹VuKMA,ªŒm‡·Y¦Æ*&Ž˜‹jR`§¨Ç–¥LŒ#Œá†êë0*mvS™ŠXí¦úk¢R㘲¥´ç–œ^A„:V‰ºK¹^E;âÓ)a¤¤FU¦c6ås”r›Ö¡éšSx˧P$§N‡d#³bÅ;@x’æM4ߎdP£jõ `OA— t™#]vºÌ­BYÄI61©ËDj}ô@”ùRå&¥¯e½±©²C© èAÌÒŸH4¡×_yÑ£ê$Y©x4©È¾,ˆ2¬‡”í›kôØÒÀçäÍìݦd<5 …(Z˱u"’vO%ž¥¾à±ÖƒÔ!­N–ü?t R‰§A™”ÆU©U¸gLOUJ'Ík/?¯žÑAä³ü×OWÊB²²&S¶¦Oµº§]U½\U“(ý—WêÕß B˜Õ»].Ðfõ jTbH N¹wÍQ¥4£ú0r½í†Íà”ÚϧLisíIwŸx=UâiP.McÝA!*­E}¹ÝËÍŠï"ZËIkìsùvp` ËŒºÌ‘ƒ.»]æV1«Ëøg™¹•yµ+…Å:;N>Ó¨¨T©“"O¤’RÇf"¤Ü)*;ù•Jº•@Žy`š¥\i©%¥ûú9[0µü ´–|léy'ôr¦²DR†KCìLs›ø uBa¯T4Ey†E+•zùÊ®£©sB꼂ÎZ‚HçGØÿz¬Cƽ'Ÿ(¯¢Œ‰°Ùz#¥h’Ù´ËjšZÈ’mZAlPí‰Î|í¹Aêl1™ª7Týc]*µò;kVxxÚÁÎ;€ˆQýˆy—;³ì;è2c.sä ËÀ.@—¹U(‹8É&&u%$õ}Í4FÉRTj¬+ï(çr>“þ²mœ²¦u"d—êì]¸½Rá,·œ¥TRêtK5eˆRk{˜¬yö(u*k7ÊÊ:fj"ã±*•aẄ&šb¯šñôF§å7·Æø†¦œuÌšÒ‘H5f*æe¨›'Stæ ³uSH!*µŽ V!¯ÊvÕ¡ÛHê?ÕtÆ‘å&Çú„ÛPÌÚlZ°ÆWïéÖé{è 5¿6e*¤³¡ŽštùÉܵʰ-šsõ§*£µyæÝª ¥¦Ù3Îlç`IÄfwà@—‹¿ø«+úÈCW®>“êáH@—]€.s«èä9ýl¤30pä|©©¼ÌJª)-o&B®Ô¼é^»±üåo± •Úy{®ÒÏÙjœX]nWû©f'tÓÔîtÆá˜4W™Ÿ(GuV»1•ùöŠ4¤ü “|K™¤ž*=Ö”åzkiFËzý¬Ýëc'£¤Z‰ãúY¶šN*X¦ú±Rý,ïòèŒ 4P­SS7 oUC-¤Œó¬Í°P³ÜSï‚Q:ˆT¿o«D¤gtTåg7ÖkWI! µˆÈ”E–Vß¡ãC¢’ÎÛªÔØ:áWeŒšÚ¦MѺd3½¦ôró®%÷ú‡Sí¡zF¥ÐBÊ(ÕKž=óëÞDŒRSª/Y²Ë5¥?© `@Ðe]vºÌ­BYÄI^ÐÈsúÙHg`Pæ*¶>•8¡Š¢y5©3•¦S‰Pʾʦ2Öƒ˜(ær}ZN™%ªDO×D"§M;¤%w’g•©œ­Ÿ Ú‚}ní±®rÈ,¶©ÓéAÏY›1¤f½ 긾µ‚òÐÊrí»µv ¤Î†Zx¶V—úøûSº¤RO:»M›¢)l­öASáÖp pk¹®dКG“J Ê+ÞD4©[ª/Y²Ë5ž´o`Ðe]vºÌ­Â9Õ¦ÙHg qÖ¡RK%ʇ5Ñõ®E‘…ª„j<õ¥ïýô“ÜðŸñS™š+ý¡>Šjä³Z£i*JS”Bƒ¤VQ:ÕôSA-ÜSD)œM#c]Mß:Ô±-Ÿµ7ƒùú+/jwÒŠ¢¨RóöØr¼ïî4K’ë5ªÿ…sû‘B:jáȨO‰¢§UÇp•t˜Åå“Â\oþÞ"kS¯Íþ6­ šŠj4Qêô§¨ ê©*­º6—6kV¬x›Íci–ìr½Ú)€¡@—tØè2·È•ð4ë;éîÔ@óÚËÏÏ)Q7å·JQ‚: -Ѽa<Õ2Õo-'S=Ww.“ؘháKì¡¢”š‚h©Þô#(†ás æìØ~;h •Â2k3ZÓ¨ÅÊ+ N)(4Ñ,>MûåËÀ6W7j+/Sk‘3ÑaJæqû#Ô¿à\Âlç…”¯ù0u°ÍÔá Ê](­É[­·ó¶Ó7Ȉ Ú.kÜÅØè2.»]Ž“Ù´_©þÿœ4;bwº À~.0è2° Ðeà8™Mû/Ýø6¢§¿¤ vº @€.0è2° Ðeà8‰´_åBë?^_yú©è Ÿ³Ÿ ‚]`]æ›'ŸG+•—øP•x°û/ít€@—]€.ÇÉ…_£òÖ“ïÊo“êáH@—]€.GË…s×¾Ëí·½íòÅóiÈÖñ'q6*•ìžüs¨߸¤­)ë§¾˜à0@—‹OÿÆÇ•É|è#¥z8Ðe` ËÀ‘óÍ“«ôà}wÇ­(z §ÛúgI³p¿ ôA—‹ÇŸ| ]æ˜A—]€.0,è2c.sä ËÀ.@—t™±@—9rÐe` Ë ºÌX Ë9è2° Ðe†]f,ÐeŽtØè2Â.3è2Gº ìt€aA— t™#]vº À° ËŒºÌ‘ƒ.»]`XÐeÆ]æÈA—]€.0,è2c.sä ËÀ.@—t™±@—9rÐe` Ë ºÌX Ë9è2° Ðe†]f,ÐeŽtØè2Â.3è2Gº ìt€aA—‹ßÿwO)“ùد~(ÕÑ€.»]`XÐe†ã«Wþíµ¿¹š*áH@—]€.0,è2.»]`XÐe]vº À° Ë º ìt€aA—tØè2Â.0è2° Ðe†]` Ðe` Ë º À@ ËÀ.@—t€@—]€.0,è2cqõ_ú‘ùáÏýÎ…TGº ìt€aA—‹ÇŸ|L™Ì‡>òPª‡#]vº À° ËŒºÌ‘ƒ.»]`XÐeÆ]æÈA—]€.0,è2c.sä ËÀ.@—t™±@—9rÐe` Ë ºÌX Ë9è2° Ðe†]f,ÐeŽtØè2Â.3è2Gº ìt€aA— t™#]vº À° ËŒºÌ‘ƒ.»]`XÐeÆ]æÈA—]€.0,è2c.sä ËÀ.@—t™±@—9rÐe` Ë ºÌX Ë9è2° Ðe†]f,ÐeŽtØè2Â.3W¿ñ¥w¿û]Ÿÿ⯧z8Ðe` Ë º À@ ËÀ.@—t€@—]€.0,è2.»]`XÐe]vº À° Ë º ìt€aA—tØè2Â.0è2° Ðe†]` Ðe` Ë ºÌX|ûoÿäó_üõ¿ø«+©~‹Èþ{ÿå¿ÐÏT#€.»]`XÐeÆâs¿sA™Ì#}0Õo…Ïñ×ßýîwɾʃ=ZaÐe` Ë ºÌX<þäcÊd>ô‘‡Rý))™ýÑwh–ks5õ@—]€.0,è2c±u]Ef¿@—]€.0,è2c±E]EfA—]€.#pé‰s~à×^~¾¬¼pîaQÖè2c±]EfA—]€.³_œ½óÌ[ßòf‘êö%Wq€¯]}650—/ž¿ý¶·ÅÂ…§´ó2µ#zõäà "³;.=qNo\“¿«ŒNqÓEªkn ºPNŠå™¶:ë ;Pn³| zª¿ÇÊNê`Â%…:Õo„,”Ómäêþòà}w똽óÌ)£×DaÔVéìÝáT³,±|'…Z(,å›ÉÔŽèiÔïÎ71­ýž»Î¦úÁ¹ ‘9=rR̾_©CôLõ5Ñ-é‰>EÙYDeÇ+ ¶þ7Up< ËŒÅj]Eæ0@—]€.só‰KÌŠ/pGÐeü×˺¨^«»òôSiˆQŽKHE•—/žOK¦jFåu)[pª¹.q’5Ùì¬ñÁûîN3 åæîâv€)à€qŠ]GæôøU<{®¾ØÕÝJ­)8¦RšuÜôNîʃèPÖséAj8ÐeÆb….ƒ"sH ËÀ.@—¹ù4õ…~qÊcoa'|yÝ)åå»y𾻯7Ÿ,Á\¯šNÏj%«¥¢§åX§š+'%µñàúó“’f<J]f)·ÆGú°ñ‹Eg85 t­}¿TÎ]Gf+,y_yú©è£Ò<ŸÆïÀ¥5ŸœN)Cä¸Mé2ñr˜:±¢©±ºÌXl¤Ë Èè2° Ðen>ºèÔjÂb.|S“ðØ¡t9S:yáÜÃ^…ʃ÷Ý]Ž*s]¬ûÊ[ô4®¹eÄýMiSéì„ ’f,' eåœ'«È% /]êÌxHÄÓöm oMs¯þQÔIÖ‘Ó©îß,¶S¦vDO£~wç<>1§ó–êç&DæôXoJäAÊSkI¼?ëg©˜øäÈŽbÒÄ…žFmzYob–©Ö¾jpð ËŒÅB]EæPA—]€.3ÎöÓµl"ºõ¯¡wMÿòÚÒFº€ö_\§’™fzVZ›Ê]/=qN­¥Y' %N¥ÒIf„fÔÚ72ƒÜ?çƒ×Û¹máÖ2µ#~™sÎ{ëà_þ¥eê%yíÆÇ‹Ò¾OÎÂ88nÍ_vxJ§›ípؠˌŬ.ƒ"sØ ËÀ.@—_"O]Ñmd]FȽèP^¯»²¿À’ò›þ ¯½ü|ù%µ›& B¹‡=ì‹2p¼5ËÁ^3þz§<ôË|ù‹èHØ—ÈÄš~NÝ`â'«Éw8š 7¾\&uðÉYÇ­ù‹Ã|çó¡áêÔï€Ã]f,:º ŠÌ1€.»]fVë2Wž~J—ÅBWÏKnðVŸKOœ‹!¢?]“þåµðíñe_ý/ŸÑ·Øl*”h]1PRÓžKRÓ –9þ9W™Šè±vR”Ÿ¡Ç©µDs•ÎØÉr"9Ÿ\ª)g쬮Fý#ÎS£4¯N²7—ÎÎÛésš ÷ô³ÿÿªbv¿4]Ôˆº[Y¤z9ì°ô·8XÆ@­áaíXÔ«CY)úgC­³}‚è©¥ÍÖû¼iQuqzÇÔSSêYGÆôgY~ð̦ýßÓ´Ô$R·Æƒ©÷ó©ßMò'êõ ¬ŸÂqkNd‘(Õ—„'ý>‡ ºÌX4u™ã]vºÌ L]û&Ê Sõô¨(ªWXö/QyOëß ÉÈF_oÑ¿¼¾^/;ØÕ…ñJ`ìê’D´dÓ„á4s%6 r¸ªþz,7œJ¹ôu" ¯çRMsáÞ¸8cÞ•p ˆú²¦¤9ãÔêjb½*õ9oZVQ¥RÓ²§ÿ´Þ9íî“Æžfƒäs9°³5u³8Ov·´_®(i™ÉayM5ËÃLíHí›_&úén‰%}LôÔZR}œÀ¨×ë1žºhTÚ÷S:61ÍÛ<udŒO]=ËŠ·ß¦cêßÑŒJ,¸4ªb¨&Ù—c1Kís0Õê“SÇ¡‰ã;[âÝ©›JÞS¾Kì#è2c‘t™c]vºÌ èzôä‚s©.£kn_.'£ß(ÍdU—ò#ÊQÍœ­Içò:ðõzÙ¡ÌX–\UË÷OM³lš0ÌþÅx!+‚®ª¢ZŽ-GMy¥úè Î1W9žú{ãš¹®»ESYc¼‰*ê\>÷Y³À[“Îy)HÉfZ‹J:ù•êàÊDŒM¶µAQ46u6u³,×eÊÒì¥z¬l¶%6 c0µ#Mßl¿¶ø¥Ô‘ÌL8V‡1–¬ŸšåÄØõµ— IöcˆÊ¦Ž5tg"1µkêõž‚¹âà•Ö¢¿‡¤y§èËU²¦&ýÔc¡vË­ÅŸœ…þØTLZ⮣]âM\8#À!.3ÖePdŽtØè2ƒWÉ*é‚>ánQt=íܬL0ê?¨z º•õÊ¥}í^§yM:—ד·òêÙIB”þõ·pZ25K‡M;<ëUŸA¶«ÑA,Z9 Qq&oÊø”6µõv#eYåÆé§fTUêg(·º&(]--ëq YmIç\dVqKG×§:ù£§QßÔø,ܤdÒ‘ÙtƒTdAÆå¼v$…7¡>ÂÛ¡Ê>ÑšBçz{å¹4{TªÔ©ò¦aS;ÒôMnD¥&re‰#\¿ÕÄBjSaÄË”óÞ/D¥œÂŽÕ1 šŽyw4W¹›š®œ( ŽýÈÈTФðì2[ÖO<=Žz |½ø¸\8V¿LFTj—¢)ÞñüzIî 2>©©ŒCÇ­Þñ…¦:t™±øÜï\P&sÇ?r"Èœ¹ów|è#¿ø‡ÿþÒW¯üÛ)’…’ks5uîó?ý÷ÉB‰ZSÿ>}!)uîsåê3ixÉ_üÕ•Ô¿ÏŸþåW“…’«ßøRêßçÛû'É‚QSêÜGSwt™W_úÊË_{z9¯ÿõד…’Ô¹Ïú—Óð’ï|ë…Ô¿ÏßýÙ•d¡ä•¯9õïóÝW_JŒšRç>š:Y(‘Û©…%Y(Iûœ>þ?tûû_þ—ÿåAì…êëíöÉIƧpÜ:;ÞÜÓ±pð ËŒÅŸúh(2ËË'Î?’Œ˜‡ÿÕÿr½Óâ2%Í\û›«?ò#?|½Ó²rïÿôÓɈ‘Ï×;-._þÊï&#æìÙw^ï´¬¨²`4ËõN‹Ëvãí•?mê2¯ÿõ×ïØ0þ÷ßû3¥…’g/}êz§ÅEC’£‰®wZV´)ÍèÏ}áz§Å峟œ¼ y䃿p½ÓâòêK_IF‚CŠÿýÐýgÿÙ×=©üçÿù®·ß~ûõç[*è2fá…©»5/…}µ.[cTóÚ:˜º(oÒ¹8öŸUšIˆÆz QÔ_=Ë¿ ý•öÙ4a°ÏuðCãh’dˆuA¶«SçoŽ*ïÂ(ë£W&áÞ8•N¾ç…”•Î-§ü\ˆ×Û?ç%^l9¤Lª]išM§Ü Õ'Ec ýõzGÒAu½&­_Âû{Ê0Š)§|³ZQ+&Vê¦&p­%Õ{uiê`ê]ÎzM}¶›Žy!ŠŒ+á¡JóuîéitÓÏÃ`ÅÁó¦,ŒäS±Šµ—3:æé‡oix`'Õgв¿ãV[óì͖Ȧº%ËǺÌXüßÿã¿¿óÎ;"}úþ/ÿÃÿøîwýì}÷¼÷_þ‹{I~ÿß=•:÷yø_ý/»?>ô‘‡Rÿ>Ÿû É‚‘Ï©sŸŸ{ß}ñWW’óø“¥þ}:JŠfyð¡Rÿ>_¾eéò}.uÿŸÿ¯¿mê2âc~ÿûî¿w9LþÕ—¾’:÷yÿÏ¿wJ°¿ÿ[§þ}>ùè/% æ;ßzá—ñçRÿ>/íédļð¥K©sMݹûFn§þ}–dÁÜüøÿä]ÿã™úÿ÷ÿÝýÃÿfŠ·ÿÐ?~û?¾=Už†ÿëgþî?~-ù|´,¼0nSW¥º¤#éÂ7®eë«aÓ7›ðåµúk ‰Y¢èiU¢ÄI®w=)Û”9Tš¹Y' ÇÚó:ø^l]’ñ0ÒYx¬HÝÊJ»:µïa6jš*±Yÿ=\x-MÉÌ4w’Þ˜]oÍÔŸä’%¤´Ìˆäê Z—!÷×ëQ·%õÆÛqú0NÕOù0•ê pJ€HLíHs#ÌÔ»œ÷½–›ŽÅì*¹Íq.w¿ŒŒ‡ýL4Ñ¡^¦©×ë):fb÷êÊÒ%ƒr¥Þët™*iR/ªED@ev±Íåè2#—Ë-Ï1À¾³ð´¾‚OÔÜå%¾®¤›Ä(•%9€ 6‹LõÓ~S«3¥ˆà&¹çÊ…hÈFc½üÒ!2NÕôØ}VYõueIsÇÃTg®¾“eeMsFoÇ”Ÿ ÑÔKì(UV‡`êF©<ÜkojR ETUʉT_W.§?Ü^©Û’z³Ð«%aœ2¥§Q_ûà@•І咴ÂŽŽVªožÀ’©Q¯Ÿ¥þ¢ÇÍþî\V&œ2ŽŒÞèl$Eϸ³úÈH“0¢Rñ1V«&êˆG}ê—ƒRÞ(d?Ë(ùÌ4g—çѪ)Êå˜$e6§šh=õ3Õ<è2ã‚:s„ Ë0‘ŠÌ^˜F·ÎUi\¶–¾¾^Rf/‹… j.Mdtu® ñ…*7ÖTJ·õ8*ª<%J b¬¤¦&žkIÿ¦ñÕA¶µ©È‡oiÇc——”¦“ýevfÔÏM÷7Ñ_¯ƒfŸZ]=Ä^ÍVzíKJ9Ñìõé·WiG¦êÍÃ8eªãƒÓõ2±weº}©Cx(WS}ó–L Ô{Å|ïM~‡)³ŠÔ™E88å\ŽŒ%•t»Ÿqç%%mAÄÁEÓ-­ñò½Y4“ Q-Òß§>!MŠzãbj•šÚI€#]ftPgŽ t€Æ—àý Óþ…²ˆËÖòÂ×WÃjR}‡… HçòzÎTœ*43¢…lš08¥\2WÓøê ÛÚÔ¾kH˜-+c—UJË5JäJÅNöâêÓœ1U®`j½zóFÑD^…[‡Èy¸óUŸ¥R2^{i¹É¦Ô§?Ü^¥™ª7[ cÇTÔ×>ø† ýte]3K ‘o©>–Ð155PïªOMMk^]ßa§4XFÆd§ySI9‘Œth¾ýê<«),DÑ‹:õéSoV¼jê…[fò›p l:&¼öú„4q(´¢Ô©¨OjJ¤µè2ûêÌ‘€.pÀøâ»aÝ:W¥qÙZ^øv®†×±uƒÂË÷%¾ì—à›& Nç4×ìý Mã«cbkSû‘IAˆ]Þ42v²–ÎŒ*S~.dj½¶¯$0å·Õy¸sËdÄkßúõé·WiG¦êÍ”Ùaœªïû‡D%rxß~²‘jÞÖ;Ò<%SE4ég¼§kJK5N„™9Tšþ¸s³u! ²gQÙTšI1‰§µ?IÓôS=(»™fp:tB¡šhJ‡°fÉ®$è2ûêÌÁƒ.pÀ,¼0n«Òúš{+‰AÉÖ /¿¼Äµ¤Ê%lš0Ï5õÇaÓ4¾:&¶6µï™´ãámªœÅNöÃÒœÑä¿¥¯£¹^Ô¢ü~ˆŠ~ι» êÓn¯ÒŽLÕ›¦Ùuaœªïûà¤=æòg©ÍjžÀ’©ÂžÄG™ü´ˆ~v¤X«!a-¨#«Ô‘wçM^b>«$Ñ­O Rõ¶º)\µ«¦ìSâ“ÓýáS;2Uošf]¹Q§êg}(ã¹.¶1ª~ižÀ’©Â7ÈDkDZ˜E¥®ÀÃKí¦ŽŒj¢§Jm­ãæø´§Íê£w‰¥¯_#M åzãq3ÈOÎÔ I8nµM¯«oªcààA—ÙWPgt€ÆIBÿ‚;ºu.ñ›Ó8^@÷Yqq¬Ä 3µÓ†È\ïÜ@EsMI3ꦖ÷öoš0ÞMÚIÕ¦Œ¯ ²­Mí{sÇ\mô‰o\ßÃæŒS{däR_Ï šëueSOñ¾4CT&ІLy¸£ êÓ>µ#Sõ¦iÖ•…qÊÃYOMT“úôñÆ¥úæ ,™x¸¤¨4³ÛSv™ô*kFÆÖ4oŠäºƒ×d.#"búÎèAê”úH éøìø,\—ãVÜÑ“©©¤ÓM/y¹ÑyߨwÐeÆâOÿò«ïý—ÿâò}.ÕO:s` ËÀh|홋ïÿù÷~ç[/¤zXAä*ý n§©ÞÄÅtºð½võÙ¨WÑ¥mÙè¢VWºKòjѹ¼ž"®àÕ_³§œYWÒö­NŸ|鯢né²[ë’Ûõ’7M­Ëž¨(«ïF)½MÆ×Ù®NíûÔŽG½ÊT2,Röâë‡evF=(7Q#Ù[íæznɲ+…,{R•~ˆ\¦´ªmPŸþ𩙪7[ 㔇³>”R]10y+ÂÛúš©ã`Çêrà:3Iöµ•4|*2Ö_’c+žü‘5Õ»FèiØÑÏÔ4‹ †aa*tí©OÎÔ I8nõì¦E)ºÕú‹NozºÌX|ú7>~æÌ™}ä¡Tßuæ`@—Ñxßý÷êå¹/|6Õà t=—•);JD7]ƒ¦z3uÙíkhõÑE¿j„èiŒ:ýåõe’£¹40ˆy£LYóµx”ð6¸^uRÊ+u/vኌ–&7bl”˜(\M3Ö)–çUQç%Aö©}46Õ;ƒRQ«ò®˜Kár`SH½qɇÄÔŒf£UÝW6sÎÄÔzmDc!4Õ¸i*DÚúè¥ÎÙŒgW‘Ù­lPŸþpUFkštªÞL™u¬–‡qÊÔ¬Â6Uô8µÎÃåjªWMßàÔÀÀúE”ŽßP£¢n2¨—^Jåðú8u"ž«(ìe½ƒ¬"ã³ÏðëÚû¨²Bz(ßUʹžEESk‰ŒD·ŽµÇ­¹q1oF‡¥–¥ìvÓ8À€.3?ù˜R Mu™uæ@—Ñ@—Ù"¾ OÙQ¦©ÞÄåióÚT—æ¾x­‹†,üswÿòz ]»OÍ®ú”Æ$”>9>uQSúƒö¦ C¢ãjÍ8¥Ald»:µï±pÙLõB«î„ECRJÙÉ'Kú36W§Ê…¹âÔzõ´iYà ÔTˆ„Ç6Ý.ÙúõéWe´¦™ª7[ cÇTÔOù JÍ´ÓmŠpU1OõL 4a!Jÿdê½eê<¨¾©ñu"SÆ?µntð4ïTçþ[åI«J{]R†®?—OέwÜšçy;¿†b ú™ê…W·.>ãƒ.3§ÑeÔ™½]F]f‹(=ÐÕíì®.îûÝ¢uJ5j:{ç]õï\¦7™e åºn.g—‘…÷ä+±Ô¤In^Ä«2<ÔÔ´UFçé„<—·´Á,r,JL}{ŽLE‡ToêÊíæÂ5E˜ê‡eÉŒåê–ï è¯W¦lV‹²Ÿ!–¼QV¶Å êÓ>µ#Sõ¦ov£0N™šõA¨SåågÀ„}y›êUM©ÞL 4~è)I/" Õ¤>¦¿“ëAjËžâ™:ë/yó™ÂQíÄM”¡ëOçž’ˆþMT/auHMf‰Í׸¢­X)D©à`@—‹Óë2êÌž‚.£.# ”,r¶å)"œ§Ê·orë@ïè™:K÷Üøú^ãpœ ËŒÅ¶t™ufï@—Ñ@—€[Ž3:ýLM°Sœ*wî.XH¨«S÷^ñ‡#]f,¶«Ë¨3{º Œº Ür¼ñ!&>Åp“!U†-réÆx×tòYSŸr8xÐeÆbºLÔ=M`Ðe`4Ðeà–ê€Êi¾}6Å_rvâ“lÊí'ßþ[”É·Ò¤z€ã]f,v§ËVg|èÔ#€.£.·ÿ¯8¹ÉD ­Â÷}À¶ð˹òPª‡#]Fã}÷ß«7¥ç¾ðÙT[]f,ÐeŽt t€‚.3è2Gº Œº ÀNA— t™#]F]`§ ËŒºÌ‘ƒ.£.°SÐeÆ]æÈA—Ñ@—Ø)è2c.sä ËÀh Ëìt™±@—9rÐe`4Ðev ºÌX Ë9è20è2;]f,ÐeŽt t€‚.3è2Gº Œº ÀNA— t™#]F]`§ ËŒºÌ‘ƒ.£.°SÐeÆ]æÈA—Ñ@—Ø)è2cñéßø8ºÌ1ƒ.£.°SÐeÆâ/þêÊϽᆵ^ù·©Žt¾té—ñç¾ó­R=lt€@—8*Ðe]à¨@—t€£]` ÐeŽ t€@—8*Ðe]à¨@—t€£]` ÐeŽ t™±¸ö7Wò±«ßøRª‡#]F㕯ùw?ókß}õ¥T[]f,>÷;Μ9óÈcLõp$ ËÀh¼ÿçß«7¥¯=s1ÕÀV@—‹ÇŸ|L)Ї>òPª‡#]Fã}÷ß«7¥ç¾ðÙT[]f,ÐeŽt t€‚.3è2Gº Œº ÀNA— t™#]F]`§ ËŒºÌ‘ƒ.£.°SÐeÆ]æÈA—Ñ@—Ø)è2c.sä ËÀh Ëìt™±@—9rÐe`4Ðev ºÌX Ë9è20è2;]f,ÐeŽt t€‚.3è2Gº Œº ÀNA— t™#]F]`§ ËŒºÌ‘ƒ.£.°SÐeÆ]æÈA—Ñ@—Ø)è2cñ¹ß¹ è‘Ç>˜êáH@—Ñx䃿 7¥o<÷…T[]f,¾ý·rù>÷u%ÕÑ€.£ñwvåkÏ\L•°-Ðe]à¨@—t€£]` ÐeŽ t€@—8*®ë2ÿŸÿïÿ[ !ÜZôJ ]æÿøß¿«'6ÿÇÿþÝÿ·á é ”Ú5IEND®B`‚trusted-firmware-a-2.2/docs/resources/diagrams/reset_code_flow.dia000066400000000000000000000104571355360272700254730ustar00rootroot00000000000000‹í]]o㸒}ϯ02¯›Ÿ"y}{Ó½˜] p˜܇‹E ØJ¢AV:}Øß~‹’“øCŠeQTÛÝ•AwZ%Êä©SÅSäßú2›>'Ù*]Ìß_2B/É|¼˜¤ó»÷—þñË•¹üéÇ‹¿OÒøoðç.‹gøÄ|å^½¿¼ÏóåßÞ½{||$Ó§Uœ/22MÈ*y÷ÿñt¿ƒFï.¼ 6/0‰óؽ·~7Îó,½yÈ“Á<ž%ï/oâñ_wÙâa>¹,[­ÛÓE6øOß_þp»þ¹|·¾Ð»­+½qõe|—ÜdIüWýÅ)üXÛîâË$Û½ðl¹X¥Ð$Zî5©¹Žû{£ÍºÕ Íï~üágùCyKë7^¯Uu£µFòYœÝ¥ó};ðt¦å£àÄpÎáq(k,ÕR³çgr¼¹›~ÍMû5—õk.]]/YžÅi¾oòf±˜&ñ¼´šgI{;«q<…!öV·Ÿ3¸‡ ï`æw¾€ùÍ^࢘ö|ßuî\´|»D‘:XùeºxßÇY¸òañ¥V˜/¬\±>p努 CÚŠ*^ѶV“i2ƒ9—Í÷Cï.;W˜90®"Kß'éÝ}^í–Óîf‘M’ìð„`´üaÒRÆ"ƽ̆À&Pp#Ž·\Wä«Ó•c¬,ãÉd;ï óäK~y êÙiS÷$ŠTÔV»¬ÕÇÅt°´È/>eé,Ξ?ýY“Èzƒ?Ö¥ó¼Êº{p Aùô n2ž¯.«üi ÅåGM¦Ÿ“<Ç›$âø;Ø›œ•_”¡Û?ÒÏè6Z×q$J„ÒÖÏÒîLªÍœÒ­ÙÔÆ„kwóYRý…¾’ ÖÐJePŽî¸ÙòuT†ãåõ›&×ãûdüWƒ`ƒWÿ|D€ði1}ª ¸¯7WÄ(NOm¥‘=ºç¡ŒÅˆ()-qIe¶ XK»„gs}0J¨íeuS%ì9¶\¼U¸t®*[Ju¨¥#±VÚQ+|F ßXÔÀ×QƒÜŽXÔSØ ¼³0¯¬(H<Œ4`Š®M ¦F†Xåæ?—­m7‹ ºég“0Âa‰V›l㊆q…H6Œ+üŒ`\Ñ&®ø=ü›`dÑSdñÌ«€ÁYk$†LJíܱôuÇ ÜPWJèuí܃¦†Ì:Þ«F\0*km´™î wM<°…¾mÎ7~Ƙ?÷ÁÊçÝVh·õiç¨é|_,§q~»ÈfW«e2NoÓ18“8OЋϽÄñÂX…N¬'vx…[y;1ºŸ|é܃ërV˜áz~Eh aÄP‰ÀkÛUÝ«õu>Ï!Ü"w_nSKþ Òf;µ´Ÿ%­ø,«NKéN²Rò‡s¹õ5‚DþB ž¨eX¼6äU#¦ˆ°ºxm¬>}š‚1u¯l¤zH~\„à"u‚Ôâ–Ú»ƒnJû¯ÏIÅ•rIXdyÐõ¹µ%A”–|¤‰åŠÂkEgg€SkMÁ¢T/™¿šq‰@u‚@µ™Pü4ž- íònI”ìË.— ¦uuQ…>ȧ¦“µ- aí÷ÞÄ„„ýBàãÎõ±¡«~É€Á®CŠöå›)?’l–Îãi…FAx×?]±á%àÎ zb#ÜR…¡s/±ºí E³$?“tœ=ÄûÑ5Ò1ó€IN˜ª oND_¸ÛÛäm?®9ÆÈm:60r»þ9åDñ¼Š ºÞëìƒèÆ –ù`;Á5;ýLÈÙÃ*O&ƒ_ÒlögÉE–¬’õêé—O{:Ë”i­´˜i/^râú6ÍóŠ9ZyCG¡ç4]^ß/²ôÿ`¬sy Ønãé*ñ0¤Èô`FV7+¸|rÙ ; I½kO%±Ö2à]F ­,«”KZ‹È¸˜”ZæbT«X:?U×Íê–‘Q~A:F¥•‘XˆÔ° ;ÊTy¥fgª„6…ÚS'Nka‡ Âàí)Sµ×Éê–R‰!£7À@Dè,OeŽš˜àí5Jïê< 3:l;+æfqžÓ¹ýsÚîgѰh½u‡¾zº"ÎF€Íq·æoLšñ+°—ˆ¤ó4O!Î\Å.®?ý¹ÿæ§iœß.²Ùþo~ÎÆ÷p{ãü!ƒ°ýkÌi„Ïi0' —¸ásŠïOµv?:p,m¸3P^²ff†|_¤y¿U8EžŒ<¹uäüÕ=L”MíbpPš,©?Mæ‰Th¦ F”*©²€¿Âòd–N¯5›ðC RåoŒ*dó<%Èn{g·ÜÅ‘ÛöÅm%óç¶\žØ‚öÂjÝ^\ÂgµÛ=«láÜ&eÈk‘×ËkŸ™©¤_iEHrÿ¹/h3ßû<ó…è'žôíyßv#OœòÊVLyÑy8ú†XzW0¹3 †A«„Ä¡’˜‘ p5 ç«þõyV¶:½ZcTù¢Ê÷ûPù¾Ô;_ °·çÚçaDæ PÖû½Èz¥ìâH™¡ ÉÚ,.`Ó¯Ipð.`cŒ0Muà€m·k5-œ„PjÌÖ`èÖ>t;¡ÛQûBÉhûÓ¼¯Têä<*Á†Li5 Œ"V)gIX]‰“ék¢9µ=Ie7뎥RîÆ”Õ˜BPi*‘´Aꯤ–þ§ÜI_¯Ü R$Ñ…̸”’õƒ±†‰ᄀÖµÁµ{â_L_ô’¾`œX¦¦0º‘:4ðVºo¥Ý‹lho­Y%x+E(×…Ámߨayv¯™Ã":´óXׂ¬½ûôûÇÿ¬’üa¹YµòüÆv±Êó»ÿ™ÀLHǯ+®‘Ç`vÃ|Hæñ|œ #ìÃ2¾ÐfQõןêÏt‘r߸%ÙÚ-5MIJ­³$ÀR‘â¢î+±\ÙÏš¦\ºÃ$3惼òAÚ[thûÁ¿}ñØvðð©ˆÒÿTD‡œ‘5skŽŽ8ÑÏfÄðÓg=ÿúðûŸ¯HPÌ>C¹ú°˜Nú )Q™”ÒJEœZ…? qo$#(1åô–âˆaŽjUÞÕxnkRæö•3ÌFakòJ;Â¥¬™;VÚ½²¢­U§oœjF$"Ôy"”ÿÁs #EAñim…¹%wCwvƒ6ˆNˆN‡G#bÓyb“w½˜K2(·&2¨{1R„u`Kðâ%†uˆMG#BÓyB“ð‡&fФ²Ø­íDÄ”v;§ #;ħFC!ê]{xÑA´€Fm D[hÑA´€Fm D[hÑA´€Fm D[hÑahxgYѲöª£šaÑÞ%h £¶Ð¢-4‚h Ú@#ˆ¶Ð¢-4‚h Ú@#ˆ¶Ð¢-4‚h Ú@#ˆ¶Ð¢-4‚h Ú@#ˆ¶ÐC[îìì7g¿XòEæžÌ:{]X\X¿»ûûÙ8¿@?wÛ/³øŽ©w ž4¸Q{ö¡ìew-{%ë•Fí¸÷§vœAÚ=tÔ£î˜vÇõ•úêí¯¦ÍL»ùÁ›¯ïéh{mm~øÏÿ9õ'©^ž`‰²äŸÉßþÖöìÃÙñC㽸—q³ÆÝõÜ]Ž:ÇɯN¾ý÷m7Ùú¤öñbÿðYmmõε¿\{ÛoûÞÜï©-Ñý¢YúˆÓé‘ÒK¥ëf¯;ýõi½QŸrOÊ}/ÞçÐx(·8»øÃg>Ìü6Óe¹íñÛÜîIA§3èúŽëÙ32çXŽmÝí¢Ùöu³×åfä®›½nËzŽì9åÍ)­ô²À‹Úh®mαœâ‹ÅCÒ¨]QYùèJ½Q?wßÜŸoùyÖÁ¬õ¿Zß´‡w{'$*d~Æü§>zjÇ;;<ïÎQë8¾åxÁÙ×°»]4ÛþÐo²õ±=ôÛ‡~}ð×äZ€Ž¢¢myA¹ˆ„t iúPÞ©¼Ì=™þæAS©Kd—{~uÏžö8ë¶9¿ïüýóï7šŒÖë˜gƸÛÑ‹¿˜:óç]¾ü¡å#~4¢Ç-=<ì¢%»@GÑFÑ6(Tœ]ìè§n "aqaµöڊŠFÛ†ZÕ»=#ÜíhÜÏÇ-½¼ôµ‚׿|3çä—'7¾¼ÑÃ.Z²ktmm»ÝÔÍeÙûÑÞFíN§Óm©©¬Q‡uEäòùË“Áfn¸YHTHUIU½N½[v©ÌóîÒµw×þßëø³Ã"ânv­è”:`´¹6жŠN™øêÄíomÿü7ŸfÖÙërç®ùÅšÌ=™=#âÇ­a½½Â^–_¶ñåC'm”,»öõ[E¤Î^·mÅ6·{rJ}]½£Æ‘›‘{ðÓƒQÉQ"ânvœw2¯U_x—¢®Q ZV´¬Uwvö›³_ü÷Ì=™ŽGX|Ø-o¹ý©ÛýüJrJÖ=·îô×§õ}Ê=)÷¿t¿ºØmÃum/_¸üá3VUýIiI›–mò°®­¢S‚#‚“Ò’&ÌŸh w»p×~jÇ©ÿù¿å剷'þhÕZãÕ˜aÑÝtZmmÑÑÀ»¸Ð.4‚h Ú@#ˆ¶Ð¢-4‚h 0x·;×ʲ&³©ÛMÝîyážÞ·÷nºYÃkÛÞÙoÎ~±ä‹Ì=™uöº°¸°~w÷÷³q~~—<ïž_Ý3ôûCÕ§××ÕÏŠœõôÿ=Ýë¶^íR?šåýQÛq³Æ-É[2ïмø[ãßšòVÅ劆:NG­cÌ3czÜÒË;U»mÉ–‡??üÆ„7¢úEÍüûÌ'ü`ÅÊó˳g·¤xø2/ÚŠˆ(¢3è-£§ÞòÆ–¼“yñ·Æ/ºpà„§¶Ÿ*Ë/{äµG6ÿ~óSïˆè!" ‡.ž>üÐÆCö_ˆóØ;íùß=[ÿ¸ÕYï÷³q©?I‘­onÝñÎŽÒÜRs¨yxúðq³Æ©»jØm·¾Ýг‹gýc–úPæžÌ?>ôÇùÇç«WS9ëk¹ö¶ßö½¹ßS[¢ûE?²ô‘+×­h®xï¿Dh­mÿeߺ}z£>ðfÊÝ)aqa!Q!S×N Í>”½âᑽ#Ü; Q·•Å•óúÎË=žkK²©}z`PÃ\+"9ÇrŠ/ydH£Eñ\<|Ÿ÷£í¶?nÛõî.{…ÝjžòÇ)ÁÁjûÈl6׊Ȩ'G©ytðÃ×ürÍÝÏ߭蔞#zFöŠÌ:”6h u˘þ1Cÿsè‰m'\ÑÖÕm %pàýw½·k‚ 5•5û×ïŸöñ´F;*/(‘n!×Z<|Ÿ÷£íðôái3ÒLf“ÉljØÞÅÖÅÝSBlßeM¿@¿.‘]âºk/³‹È¡‡¶¼¹åòùËŠ¢T—U'Þ‘Øl·Ã¾ò±•÷λ÷ÀúÖhkÜà¸F; ‘’œõF ‹×õŽº+yëjëÔF÷¯Ú÷£­O›¶7ýп…J/•þùñ??õÑS½oï­(ʆ—6äŸÎo¶Û„á f‹ùÈߎìz×°kÚU·›ºY¢,{?ÚݰÝétªý4[|hlhÃ=œ)‘С×w8h%`][{¹]D¢’£E)É-ùví·6ž>üo¯þíÜ·çš]YLÑ)_¸ý­íŸÿæóÂÌÂ:{]îñÜ5¿X“¹'ÓCŸCÿsè®÷velͨ©ª)Ì,üdî'‰w$ºFšà#ZñkdÞÑ3â?žýew- ì3ºOUq•»‡L²aþ†~ãû¹›rÐï®~?Yÿ“¿/þû—úÒQã‹»eâ-qúŸCk«kÿòü_ 3 Í¡æ>£ûÜ;ïÞ=*x›reÝ+‘eEËÚ±¯¨wÔÏë;ïûo|ÿ¦±7µw-W1Ã:£½KД0!ášìúŸ]þ]ü“Æ$µw!hk`BBË͉Ÿãè÷è?êZc‡¦¢íoÎþ¦½K@»ÑÚ„tZD[hÑA´€Fm D[hÑA´€Fm D[hÑA´€Fm D[hÑ¡8Îö®¡ËŠ–µRÏ3¬3Z©g´/Fm D[hÑA´€FÚ»€vУµ¾¢†fœãk{ ­0j Ú@#ˆ¶Ð¢-4‚h Ú@#ˆ¶Ð¢-4‚h Ú@#ˆ¶Ð¢-4‚h Ú@#ˆ¶Ð¢-4‚h ÚzŸýìŽü?Ý“õ|è…gÍ9¿M)Þø‚³¦ÂÃö¹‹Wì}¯i{Mö Ï5m¿ô‡Ôó3•ó3•ó³Œô*Û¶ôºKÍ}u`徯ûé>ÅÐÞhMÕáÿ+øó¤àÔY– K –˜ÚüSåÛߨÉ>hŠáŽt÷¼å®ŽÚê“[ Þ~ÀhKöï3΋ýtDD[¯rÖ_^ûÓ Û~jùÞBµÁ/z@è#§SD¥9Eëž©>½MÑû¦L°Ü÷ŠâبGñ…Ÿ¨ÉüFo‰ ºmšû=)¢3(:C@ß» ‘‰µ9‡ýûŒs׿»ö¢uÓks^^7½xÃs¦žw„MYÕ:/ @aB‚7Õævg™‡ü°ñŠ""+½1jîiÛÏ÷Ödí+Z?«iùïôºÑÖ7ô¡×£~I®@´õ&Gy¾ˆB¢›>T›—aÏÜúà2)XßÅrÏ‚Š=«ÄYßh›šó»-÷ÿN1ú¬±]Æ<ënG¥_¼|~¦ráç~yËÇxʯǭîúoÉ~´hëMú ©+Énú£8Kñ3ë‚"Ô»†°gmµ£¢ Ñ6ºÀ0] õ»m"z»ÛQ—q¿Š]êŒ}ÍÑmαꓛ‹7¾à®ÿ–ì@ˆ¶ÞdìÖOo‰©lºÜÓ©·Ä8k*êËóÕ†ºË™ŠÁ¤7‡7ÜJ]_U쬳«wëËr¯²?EgìšØÿªÃŸ¸ëÿ*ûU8€vl¼JÑ…N|£lû%Ÿÿº®ðŒ³Î^›{äòšŸØ3w#MqÊÖÏrÚËe—J6¾`šÞ(Y»&ùÅ *Ûúšˆ8ëìeÛ–¹ß“Sê뜎šÚÜ£•?ö‹êï®ÏûÕÛjó2ZñhCD[/ èw_äOþQs~oîïnÉz>´`Õ¬±~ÑEQ´ÖYS™ýR|ŒQý­–4}zøckªOlÊýÝÍyoŒ1õãn/¥_,¨>ÚeÜó±Kj£ç7ÅÌëþúŠÂÖ,À›µmž£ä¢£øBð3õ]º‰ˆ_ô@¿èêCõեşή:²ÁY[ퟘ:ñ:s¸ˆÔWox¾úèÆúÊ"CD¯°G?0Föq”æ­{¦úô6Eï˜2Árß+Š_ ˆä,L ¼y²ýÔ6Gy¾bôûþ;Æn)"â(¾Pøá5™ßè-1A·MsÕS¶uIÙŽŽÒ‹zsXÐðÿ×eÜój{ΤÀWŸÚê(ËóëÖ¯®8Ë6ëõ!{æÎü?ŽžŸ£ø™¯˜³þòÚŸÝöSË÷ª ~ÑBù“\¹r‡":ƒ.Ð<ú¥[׿7Ålµ—À›ˆ¶ÍÓ‡D"/45ø¶ŸøÅ 7Xc]þÏEoìöËýŠŸ¹è/3 ß,âÿm‘‚wÿSQt]gîÔw±ÕæÑ™‚E¤`åCúи¨¹§öŠ‚•­Ÿ:i¹ÚOÕ‘‘?ùB`)ÝôÛËk~Úõ™/E$ÿ‡ýlÉó?q”çåÿéžõÄDNý«!4®&û@þŠ» ‘}<¤>Tyh}×§·êÌaõ•EÙó¢ksmÉ"R±ëíÀAü[®©Í9ì(Î2ùaãV”F •û>PôFCx//¼šm‚ n(º®3¾2Å(ÝôÊÅù=/.è]¹ïC©+<[utcè¤:s¸b °Ü÷jÕ±Ïê«Kê ÏTûkè#ÿ­‰Egì–¢‰ªÍ˰gî }p™Î¬ïb ¹gAÅžUâ¬W÷4ò)]€EDúÝWsa¯ˆÔæeÔœßm¹ÿwŠÑß`í2æYW9ƒ&ÂâEQüb™‡¦WŸØäz(häT9LDtÖÀËw­gMEåþÌÃ~Üè°åù"b‰vwÜeÛ–fϵ]x6¨lÛÒ°)ïꃻzéhuŒÚº¥Š´|ï7ò½ß8íåå;ÿTð?SºuKv”ˆ(¹K†¸6Óù‡8гe¹Š_ >$ªaŽâ,ÅϬ ŠPՎŠ}P¤ˆèÍáj»b pÖVI}£8K¦ ´~·}DoWWU‡Ö—nYRw9SQ”úêRÿıWêìre§Aß,X9Ñrï¢ÊkôÖaM*BDêJ²ýþUU#Aßì’6[g RLA®FEol8‘×YW£6^åh[DÛ«SLAÁ©³Š?›[sñŸ¦ÃDQlÏÔù‡üÛ6“³¦ÒQš£ÎÍUé-1ΚŠúò|5ÝÖ]ÎT &W¢mJ]_U쬳+“ˆÔ—åªíŽÒœ‚?OŠxêsÿÞcDQŠ7Ì©Ë?ye× æ˜FéÌ¡UG6”ïZÔdÈVDŒÝúé-1•{ßsMþŽÓ©ÎIPüÌú.¶FÏ2„Æ5Üc]Á)1„Æ»;€vÁ„„æ9Js‹ÿï—5Yû5õ•—KÿñqÔšb‡Â{ô¹óòO8JsD¤¾<¿òàZ1„÷ôOºóòÿþ?GiŽ8µ9‡¥9ƈDSܰ¢õ³œörGÙ¥’/˜‡¦‹âö57vMò‹T¶õ5qÖÙ˶-SÛö2ñ‹ê/Šâ(¹Xùíj• ²ôo/ÕœûÆ<¸É„ZQt¡ß(ÛþFÉç¿®+<ã¬³×æ¹¼æ'öÌú4}¬|×ÛÕ_8k*ë Ï}ò ÿı†¨Ú£¶ÍSüë«J V=â(ÎR &£-9üÇë ‰"–þAÉg¿¾´t„:µ  ß½&ŠHø£:;wñgu©!¢wxúÒ¥[øÖ­{&û¥xEo H™`½ÿUÏû lÍ埨<ð‘b ðOúûù="bˆH ùy¹ËFêƒ"taþ}*r׃yHzñ†çúÝ«s3å  ß}‘?ùGéß_.ûòu§£ÆÖÓ|Ë÷â6êshº³¶ªè/?«+<£3‡ô¹Ór¾†mLq^Yõɇ,+ZÖJ=ϰÎèÑZ}û†zGö¼èÐï¿pÓ]í]ŠˆÈ¹í]è4˜ 5å»ÞRüC’Æ·w!m š’5Ǫø™Ã]íaF/€Vm5%æ7nçàhc{Т-4‚h Ú@#ˆ¶Ð¢-4‚h Ú@#ˆ¶Ð¢-4‚h Ú@#ˆ¶Ð¢-4‚h 0´wíàÜŒö®à_z,k­ž}çÚ £¶Ð¢-4‚h èŒsm@g´Ziï ´èûÎö®àß0j Ú@#ˆ¶Ð¢-4‚h Ú@#ˆ¶Ð¢-4‚h Ú@#ˆ¶Ð¢-4‚h Ú@#ˆ¶Ð¢-4‚h Ú@#ˆ¶Ð¢-4‚h Ú@#ˆ¶Ð¢-4‚h Ú\ÝâϤßì+wç­eŠËþîî¡ ¢L‘‹E­X@êQ¦ˆ2EŒJ¯Y²ô¯×ßÕÀ9òáNïUæKˆ¶W—–,G²$¯ô»»›KrŒl>úÝÝÍG$)J¢¬-êÊé”ZÇõÔðüýRû®”¾%¿Tf _ºžN´h pub%"[ŽJZ¿ï¶É)–I¿—yɹerî÷2u¬4'UšvzítŠ$EɃ哽""1¡Ra¿ 3 Äd”ð`·í"¢ÓnÔî‘xÛ˜¾²èSÞ[ü ""w$Éö Ùžqe¢mY•ˆHÿî¢(r±HVïðæÞN©sHMÍ–÷HÿX‘D› ë%³Þ—òj¹T"/|$é£D§¸m[ˆdäx³0ßA´h©´~’[,cþ5­6¢‹Ä†‹½VF%}×’ØMæ=(#_”‘/ÊÔ•rgoî}á'b|T“± å–xy=]DDQdíL©´KüLô¼ô•%?ðÔ."³ï•÷wˆõI™¸Ì›åùÅéôÅéÄËŠZ땞aÑJ=_‡­v>ó¡£À7¬öÊtü»ïûV’dÔA´€Fm D[hÑA´€Fm D[hÑA´€Fm D[hÑA´€Fm D[hÑA´€Fm D[hÑA´€Fm D[hÑA´€FÚ»€6ñ}g{î}µÒZ=·ïqùFm D[hÑA´€Fm D[hÑA´€Fm D[hÑA´€Fm D[hÑA´€Fm D[hÑA´€Fm D[hÑA´€Fm D[hÑA´€Fm ŠÓélõ}(JkïЧ"ífu«Å¡ïó ô CktJ–ÅuhtÚtÀµòf´%Ñ‹\§´¢-‰­ŠŒ Zèú£mË-‰-qÕ3ŠŒ <»žhÛ’PKøÀµjxÎx>ÇÔG9Ç@#×m=¢¼¥%1—€ ii´õjÉhU®¬Ù“€ \ZtÉw¹Öét)Ðf<œo|—HK¢m³¡P‹öâîÜ#ÝOÑVQ”¦qÁ—CmuuµÒœ^½zÝ`Ïüðïé) jÚžššÚ°¶'žxBDüÞ{ïÝ`‘J³ça³g,è<Üεu7XÛšÅÜ(ÿ²²2õö<зoß—_~YDtºKðN§³®®Îh4¶C‰""òì³ÏÎ;W½­–ñì³Ï8°ÑfmVg»¿ ×Íét6=Q¥-. |Pó£¶k°¶¡ ÑëõF£Q½("IIIsçÎ5jTRRÒŽ;l6ÛöíÛÕgíÝ»×5ÂúÚk¯ÅÅÅY,–¨¨¨ ˆÈôéÓ=:}úô¸¸¸ôôt)--6mZ÷îÝ#""&Ož\PP >÷Â… ãÇ·X,ýúõÛ±c‡»"]…™L&yå•WvïÞ­>ڨΤ¤¤Å‹5* `äÈ‘ÙÙÙ‹-êÚµkDDÄ’%K>ú裨O|æ™gŒF£îW¯^=tèPY²dIŸ>}‚ƒƒãââ.\ذŒF;rwP>ÎÝðm»ÚW‹¾FÖ!BmK¬_¿~ýúõ©©©Ínpâĉ_ÿú×ÿøÇ?Š‹‹;v÷Ýw‹È믿޷oß×_=33sÕªU"2eÊ”K—.íß¿ÿüùó!!!=ö˜úô‡~8&&&77÷³Ï>[¾|¹·ê|ûí·—/_žŸŸ’ššZVVvæÌ™uëÖ=÷Üs=zô8|øp~~¾ˆlÚ´)..nÛ¶mêí´´4‰‰‰ùë_ÿZZZú—¿üå÷¿ÿýºuëÜíÈÝAuš9EÀh&Ú6ñÒRh˜:ujXX˜‡ ƒÃáØ¿YYYHHÈÍ7ßÜt›³gÏnܸqÅŠáá᯾úêgŸ}VRR’‘‘±{÷îßýîwþþþ±±±Ï>û¬»½,Y²$ü_¾ýöÛ«ÖùôÓO'''M™2%??þüùf³ùöÛoïÓ§OVVVJJÊæÍ›srrŠŠŠ¦M›¶iÓ&im'Mš¯(Ê AƒÒÓÓÕG›îÈÝA]åõ%NTnè„ϵÕp®‘¨¨(Ï$$$¼ûî»o¼ñÆc=vË-·ÌŸ?ÿŽ;îh´Mfž,11 IDATf¦¢(C† qµ„„„dggçää„……Y­Vµ±wïÞîöòä“Oþò—¿ToGFF^µN×]³Ùl³Ù\S‡ÍfsYYÙØ±cÿñÔÖÖŽ3fìØ±S¦L9uêTnnîÈ‘#EdýúõK–,Qk.--;vl³=»;¨wGáƒM½eÒ-§K6h/4Ì=ÁÁÁÕÕÕêí†óJ'Nœ8qâĪªª¥K—>ðÀ………Š¢4ü"Zll¬¢(lût:]qq±ÝnW§Ïæææº+#888&&¦…u^UZZÚOúÓººº±cǦ¤¤äåå­^½zĈ999“&MúüóÏÇŒ£(Êœ9sNž<ÙìŽÜT‡ÓìË@'ño:U&¸å–[>ýôS©®®^¶l™ÚxüøñÍ›7Ûíö€€€ˆˆ×¢6›-##C½Ý³gÏ;ï¼ó‰'žÈÉÉ‘üüüµk׊HRRÒ Aƒ^{í5±Ûí®>[Ûí·ßž••õñǧ¥¥)Š2zôèÅ‹«³Ô¯”õïß_Q”‹/®^½Ú]'ëT§4pû52í Ù6²hÑ¢ýû÷§¤¤¤¥¥¹fTUUÍ™3'22244ô­·ÞZ»v­šfÏžýþûï[­Ö‰'ŠÈ|5bĈàààaƹVZX³fͦM›n¾ùæ1cÆŒ3¦mÄl66Ìf³uïÞ]DÒÒÒJKKÕ½'&&Λ7oäÈ‘#GŽœ:uêwÞé¡wÕáhþÔîüÛdĆC\ät\œÉŸ³ºÕ>Hü>¿é®¸2jK€f¸ûƒ h[‹Öµ|ÑA´€Fm D[hDóÑ–/•7kàÀ~ø¡¯uÕBƒ~ï½÷=...==½ÑîÜõŸ””ô_ÿõ_£GîׯßàÁƒ:ÔlW «Ø¿ÿåË—‹ÈàÁƒgΜùƒü åUuPš9‡šÂÕÈÚ„ÁÃcŠÒ8øv,S§NUsíÙ³g7nÜxéÒ¥ððpyõÕW-KII‰Á`p8û÷ïïÚµkHHˆškÝmânGžŸòÔSOY,¹ï¾û^|ñÅ«VkµZ'Nœ¸råÊÅ‹WTT|ôÑGÿûß›}Š«çG}ôùçŸßºuk\\ÜÎ;?ùä“àààààà ÜsÏ=o¾ù¦N×xx¾…Uu8 ÙЙ5N<q;œ¨¨(õFff¦¢(C† ‰‹‹‹‹‹ëß¿HHHvvvBB»ï¾ûæ›oÚl¶Ûo¿}Û¶m6ö°#ÏOQó®ˆTUUÕÕÕy®VDž|òÉ÷Þ{¯¶¶vÍš5Ý»w6lX³O±Ùl oggggee™Í戈µ1!!¡ººÚ5;¢¡VÕ±4:];ôfà:xµUuܱ[WЉUåàÁƒMG^'Nœ8qâĪªª¥K—>ðÀ………6n:öyÕþÝiÚUÃX6jÔ¨ÐÐÐ 6¬\¹òÇ?þ±»NNŸ>­Þ¨««;wî\tttLLLEEE~~¾šn333M&“+Å^GUH‡þ3 xE3Q¦iíè¡¡gÏžwÞyçO<‘““#"ùùùk×®‘ãÇoÞ¼Ùn·DDDF‹ˆÍfËÈÈhyÿ¸ëÊåÉ'Ÿ|饗¾ùæ›þð‡î¶Y±bÅ‘#GjkkçÏŸššš˜˜8lذY³f•——_ºté…^HOOoy`½jU>«é)ÚAÿ7¢ùУ½tûÁDEE1"88xذaÛ·o‘ªªª9sæDFF†††¾õÖ[k×®U³ÙEdöìÙï¿ÿ¾:¶%ý{à¡+Uzzú±cÇî½÷^×삦¦M›öøã‡……ýíoûôÓOM&“¢(k×®­¬¬Œ4hPÿþý—,YÒòWéªUù&r-PyšlÐlœ%4´ ‡ÃýÎ;ïÜu×]Ín””´hÑ¢ &´qa>…SÐa°BB›ðôQu³AQ”Ž>‚Û!¼õÖ[!!!ãÇoïB|”»ó\ @gv•¯‘©A¡i†P[ˆ­ÄjµšÍæÕ«WwèïuµwYq6€«¯ "N§³Ù|¸Édj¥vïÞ~ƒýìÝ»766622Ò+U€Æ\5Ô¶×,O4äámjÕ€K´½6mh=ôOÆõÌjµž>}º¦¦ÆÏÏODŠŠŠÌfsQQ‘mÕ-ϵN§“!ð)þ[&Îúš†ïH³o\+\¢m‹´K¢õ°G2n³‚‚‚ŒFcqqqdd¤Ãá(//OLL,((ˆŽŽ‘ââb«ÕªnyáÂ…œœ»Ýn4»uëÖ£Gµ}÷îÝÅÅŵµµ‰‰‰'NœèÖ­[AAAYYYpppß¾}/]º”••åt:ccc»wïÞ´†ÊÊÊ}ûöUVVöéÓÇl6‹HMMÍÉ“'‹‹‹u:]xxxBB‚^¯w×~òäÉŠŠŠ“'Ož9sÆb±$%%µÑ˾Í]®%Ôú>õ=rp½ûm=ñ‘Dë¡2n#‹E¶%%%ÁÁÁ¡¡¡§N§ÓY\\ܧOu3“ÉÔ¿ÿòòòþóŸêC4êÝœœœäädÿ#GŽ8p 22òÖ[o-++;xð`xxx@@@£.^¼˜’’xîܹC‡ :T§Ó>|Øßßذa‡ãðáçOŸNLL‘fÛ{÷î]RR„p!Ôjƒ»€ëÝtK´m†Ï&Ú¦ÜeÜ­[}´àÖfµZ/\¸ "EEE‹Åh4úùù•——;N‡Ãáµu¥Æ   ›ÍVTT䊶QQQ®\+"ÑÑÑêÈk×®]Ož<§(ŠÅb ,//om£¢¢Ôí{ôèqñâÅââbÿÒÒÒ””½^¯×ëããã:Ô»w着ªfÛ™ 5û¿"¡¶ãj6àzqrÑöЦ‰¶¥Ã¦×u£ųZ­'Nœ°ÛíÅÅŽzõ‹ÅRTTät:ƒ‚‚ †ïNø‚‚‚ .TWW+ŠRWW犼"Òh2®ë®^¯÷óósý(êõz‡ÃÑ´õ†¢(&“Én·+Š¢×ë]q9  ¾¾¾¶¶Ön·7Û®NHs¹–P« îî¿¿DÛŽh›êä7 Àd2åççWVV‹ˆÅbÉÉÉQo¨ÛÔÔÔ9r¤ÿþj¢=sæLUU•· ¨®®Vo8N»Ýn2™L&“Ãᨭ­USluuµN§3îÚ½U ttäZÍkúíO·7Új,Ñ6Õi3®Õj=þ|—.]t:ˆX,–ãÇ‹HLLŒºA]]ˆ‰ˆÝnÏËËSC°W\¼xQƒ{þüyuê‚N§ëҥ˩S§ÇÙ³gm6›¢(Ͷ‹ˆŸŸ_ee¥·J€Žˆ\ÛIx}=¢Nm5Ÿh›êl×jµæææº‚¬Ñhô÷÷¯¬¬ Q[ãââöíÛçççg0¬V«v½"**êøñãf³9%%E×ÉÉɧNÚµk—¢(ááá={öT7v×›‘‘‘••eµZ“““½Ut\äZ k”nopàÖË .x˲¢eÞípÀÁZÚ+Õ5|óÚëÅï„ù‚zfr6¢%8[´­Ñ0žofx—·ÞtÚúN¢õ)mÐk;'oÝj3Ú’h[ˆŒ ðeäÚNÅ+ón5mI´×Œ ð¬í —ë¸ÕB´%Ñzà#²í„n|à¶G[m«"ãÚ˜/|Ó>å:nu­TJëpp€úÏÕ’ú/íW”–5}y·þK»Õ´­œ={¶möµwïÞ¼¼¼¶Ù€k²xñâ~ýú¹îΛ7OQ”cÇŽ©w:¤(ÊÅ‹[¯€ÔÔTEQE1½zõZºtéuw5pàÀ?üЋµyQg¹dc´íŽq\@«¼¾d:p|ÿ$LKKûÅ/~‘——)"›6mJNNÞ¼yóM7Ý$"›7oNJJŠŠŠjIWN§³®®î:®@ùüóÏ¿øâ‹µµµ[¶lyà’““Çw­t,×:pë룶ŒÑú ÆqÑ™}ýõ×%%%êí²²²¯¾úJ½½{÷î .ìß¿ÿË/¿Ü¿¿Ýn?þü×_½cÇŽ .¸¶9sæÌ¾ýöÛýû÷WTT4êüäÉ“'OžÜµk—z=õºÐ;vìØ¹sçÉ“'G£§äååíÝ»×õômÛ¶©Û\ºtéÛo¿‘ .ìÞ½û«¯¾Úµk×¹sç\Oܽ{÷Ù³g÷ïß¿{÷î’’’–Ô´ßœ0`À€ðððÍ›7‹HEEÅÁƒŸ{î9õ®ˆlÞ¼y̘1êí%K–ôéÓ'888..náÂ…®’’’æÎ;jÔ¨¤¤¤;v$%%-^¼xÔ¨Q#GŽÌÎÎ^´hQ×®]#""–,YÒl Š¢ †€€€»ï¾;11ñðáÃj{NNÎÃ?óôÓO».iÙlûôéÓ=:}úô¸¸¸ôôôÖyµnÈœ>:jËm‡àaWxËÐùäää$''ûûû9räÀ‘‘‘·ÞzkYYÙÁƒÕË/‹HAAÁÍ7ßl0rss:4tèPõ’uªÞ½{—””ÄÆÆªcB"røðaÿaÆ9ŽÃ‡Ÿ>}:11±áN­Vë±cÇjkkFcqq±¿¿qqqXXXqq±Õj“ÉÔ¿ÿòòòþóŸês è7jIý@+ñý![Q%55uË–-“'Oþꫯn¹å–ñãÇÿìg?s:N§óË/¿|ûí·Õ-cbbþú׿ÆÅÅ8pà®»îêÓ§ÏC=¤>´~ýú­[·†……©wß~ûí5kÖôèÑcÒ¤I©©©“&M:sæÌ·ß~;vìØ &$$$4[‰:j{úôé#F¨-=ôP\\ÜéÓ§+**|ðÁY³f-_¾Ü]û믿þÕW_=÷Üs“'OnÝ—ÌK®iàÖ·Fm›þ1FÛ!4û61”‹Î&::Úl6ëõú®]»ÖÖÖÆÅÅéõz‹ÅX^^®ne0DÄf³9ÎââbVVV–––öîÝ[¯×ûùùÅÇÇçææ6úÿÝh4šÍ梢¢šššÚÚÚ¨¨¨¢¢")**R£mdd¤¿¿¿ˆÙl6õQW1 ?mIý@ðÍ![UZZš:L«ŽÑFDDtíÚõÀûöí+--=z´ºÙ¤I“âããE4hPzzú¦M›\=L:Õ•kEäé§ŸNNN š2eJ~~þüùóÍfóí·ßÞ§OŸýû÷7-àå—_VÅÏÏoüøñO=õÔ­·Þ*";wî\¶lYpp°Íf[°`ÁªU«êëëݵ·îkä%ûjd\÷U3šŽã SrÑi˜L&õ†šD]£Pz½Þ5‘ÀÏÏϵ½ŸŸŸÝn÷СÝn×ëõ®ôP___[[Û°±Z­EEEN§Ójµªƒ¸UUU555!!!"RPPpáÂ…êêjEQêêêÔ¼Û¨à–×\“­[·jìþ´´´iÓ¦]¸paÓ¦Mê·¸RSS7mÚT__?pà@×Ï×úõë—,Y’™™©(Jii騱c]=4šŒëºk6›m6›ëc³Ù\VVÖ´€_ýêW ,¨¯¯?qâÄ#<ò /,X° ++Ël6»>IHH¨®®.((p×îú\H“Ú3Ú’h5ŒŒ‹¦´ñKN¯×»Æ???ƒÁ`µZÕ° ´ w?ûëJ iii«V­š1c†z7"""66öĉ£FR[çÍ›7räȈˆˆ°°°;ï¼³á÷´páÂ… êtº®]»Ž?~ñâÅ"¢(ÊÚµkŸyæ™øøx£Ñ8a„W_}ÕC»ˆÌž=ûÉ'Ÿ\ºtiZZÚÚµk½Užw5\—°åß$»ž‹ó^“Ž’h]8çt:‹ŠŠŽ9’’’ÒpvZË5m[︮®.++Ëf³ †ãÇ×ÔÔÜ|óÍ^ìßëšý†™Ÿ¸W}Ç}6òîÝ»×f³]÷_¹.»wïNHHP? Ä òÙ³ yø&qÃ÷®cE[´¥ë87ZkÔ¶Ã%ÚFÔ«}„……TTT¨Ñ¶¦¦æäÉ“ÅÅÅ:.<<PêëëKJJ***ºtéÒÞµšâã?û踼m;z¢mHµ­ªªrýJs·Àd³íM×§ljذa"RWW§.8§ÆÖœœœÈÈH54‹›U0;¦(ÊàÁƒõzý©S§Ž?ž’’âê¶°°0;;»áÅ}>»HÜñãÇKJJââ∶Ϟ‡Æk¯óN´ÕR¢‘sçι®Ù£þJS˜LIIÑëõz½>>>þСC½{÷®ªªj¶½å_4 ¹¹¹={öt8yyy\¹bEÃU0Ïž=[\\XXX8räHõ‹Ò Û·o¯««S7+//?vìX¿~ýÔu:Ïh{}ûöõboC‡õboþЄàƒ¼mSSSýÿÒ¡?hèÑ£G||¼Ó鬪ª:zôèÙ³gãããÝ-0ÙÂ…'=‹ŠŠ:räHBBB~~¾¿¿Ãñ¡¦«`êt:EQÔKhª ƒÝnW£íåË—CBBš~íºáw€vÑAgù2ÏÿŸó‚£5xmB‚ö>SV%000<<>ÞÝ“-\xÒ³ƒÁPXX˜““c³Ù>ÔtLõKЃV³l#f³ùZ÷î#46ö¦®úKŽ¿jp­ø_¢ƒâCëñþ×È´‘qÕëAWUUåçç«KBº[`ÒÓ ×§¼ªnݺeffVVV6š#ÛtLNgµZ322z÷îíççW[[[\\ìºÖH‡ûn)‰¼ã@çÁÏ;Z[+®kÛq3®:×VQ£ÑêZHÒÝ“îÚ­OÙtGÛ·ow=¤N¥ k4æÚì*˜}ûöÍÌÌÜ·oŸ:ó!,,Ìm‹‹‹+++»uëÖ:¯×h!¾ú¦{k‰./®lÝ6‹dûí·111]»vm÷J I¾ùóÞøÜsÏMž<¹Íö8xðà™3gþà?ð©ªÚL[\²¡ceܺ{Èd25›Pݵ[,õ*|îÜvÛm®ÛƒÁ`04¤M—§5 ½zõêÕ«WÓ>›mô$Z¨xß½¥á’æ7¨{÷îê‡T€wñóÞ,õºb­1‡ðÙgŸõf4¯Õ/ÙЬμV¿»Å‡/^¼˜••5dȆhfw-¤ß.õ‘¯ŸîÞ½Ûf³TVVöéÓG]˜ïZW¶¾xñ¢Á`ÐëõMW¶nvijuב‘‘ÅÅŵµµê5âÍfsÓ®vïÞ¡nf6›ívû5-Œíî@ŽÚ¶°’¶}gþœ-ðŠFžùò̺ÒÒÒÙ³goذ¡ºº:--íøƒëwtRRÒäÉ“·mÛ¦~#üwÞIII™>}úŠ+BBBÌfówܱjÕª¤¤¤‡~xëÖ­yyyýúõËÊÊúæ›oÔvîÜ9~üøœœœFMJJzàvíÚU^^îçç·bÅ uîbNNÎ3Ï<³mÛ6??¿ &¼òÊ+ò-¬ªM_Ä»¾ky´Ý…vêXã¸m`ûöíz½þ¦›nòÖè‹/èÌÀ YèÝ¿xñbJJŠ:Çݵž´W¶ö°4uaaဠÃùóçOœ81hРf»*((8p Ñh¬««ûú믯ialwÒH +nœ?|hmS¦L1û÷ï7›Í3gÎ|ì±Ç6lØàztãÆ_|ñ…ÅbùíoûÓŸþôË/¿|ýõ׿úê«Fý¯_¿~ëÖ­aaaEEEÑÑÑGŽQ?û}ûí·yä‘F¹VõÉ'Ÿ|ýõ׋åÝwß½çž{Nœ8a2™z衸¸8uiü|pÖ¬YË—/oúÜV¥/_ÞÆRp5ný—v+«ÍÝvÛmÇoºb×СC;Üm³o_ÓwðeQQQf³YQ”=zÔ×׫SØKKK{÷î­×ëýüüâããsssN§»vWWWöéÓÇh4êtº„„„ºº:×®ÕÅOÂÃÃËÊZ\š IDATÊúè£ÿøÇÍ>ÅÕó£>êp8¶nÝš‘‘±sçÎeË–Ûl¶ ¬Zµª¾¾ÞÃs=W¥í3jÛ¬¦C¹y·ÃaŒZâïï¯ÞPÅd2ÙívEQ¼µ²uuuµ‡¥©]]étºúúzw£Yê"€ªkZÛÝ4-¸…•Gff¦¢(C† qµ„„„dgg»®‘ä ¨ªªr]M©‘¨¨(×í'Ÿ|râĉ‹-Z³fM÷îÝÕË”6ÕpaP›Í–m0Ìf³ëKä ÕÕÕM?TiaUšá‹Ç–ššº¬h™ˆ 8øÝE¹È¸>‹D Mª®®Vo8N»Ý®®'í­•­=/M}®uaì_ŠhUŠÒ>_ºªØØXEQñÄ999"’ŸŸ¿víÚ«>Ëf³eddxØàÉ'Ÿ|饗¾ùæ›þð‡î¶Y±bÅ‘#GjkkçÏŸššš˜˜8lذY³f•——_ºté…^HOOoy`½jU>åšNŸŽ¶.d\A¢E'uüøñíÛ·ºÖ“NNN®¯¯ßµk×Þ½{ÍfsÕ­›m½téÒöíÛ9Ò¨ÿ¾}ûšL¦}ûö}õÕWûöík8W¯YºRÙl¶ÊÊJw coß¾ýòåËW=–¸j%€¶}ðÁQQQ#FŒ6lØöíÛ¯ú”Ù³g¿ÿþûê´Úf7HOO?vìØ½÷Þëš]ÐÔ´iÓüñ°°°¿ýíoŸ~ú©ÉdReíÚµ•••ñññƒ êß¿ÿ’%KZ~ W­ªãòÑ1uB‚®¹ .%Z]ßJí‹Yh,çtÝœNçÎ;“’’BCC]šY=°Yœ-ÚÓ–ó.‡ÃýÎ;ïÜu×]Ín””´hÑ¢ &´qaíèFÂ’/εm ×.óq[‰è(rrr ƒÕjmïB€ë×i¿ªøÖ[o…„„Œ?¾½ шŽm]ȸ^G¢:M.Œ øì—ɼËjµšÍæÕ«Wûþ÷ºÚÌ þWÖᣭ ÷‘hªá%»:thWÜ F·!Ý]u›ãÇ·A%>âÆç¥h'Úºq¯ ‰à;:í´4u}Øh0Úºq= Ñ|_g¸…‹WþªÑr´u!ãºh>®NK€xo‰ŒNm]88Ã:CÚðZ¾žÿþhúh+ýô’hé¶³ñâÒo+Úº¸R]kgÜö3D¢héVü›”:i´ui³ŒÛÞú¡%Ñ:º¦cC¤[Mòú'Ø=Úº´^Æm³Û¦‰–8 è¸H·š×33‰¶µ×8îu¿—MmúÁÔs3n´Ú]³éV:ÓexµªÙQ?¯¼­D[·¼˜q[cà¶ÙDëÝ]ÐîšýÊðm‡Öz¹Vˆ¶-Ñã¸-;I´€ÎFý-Éð­´j¨Um¯Ádܸ%Ñ:9w÷®GÛ¼"´”‡äõ7Žh{=¼;ŽëáM%ÑàÒìð­ŠŒëƒ<êµÒ;E´½!×”q[>pK¢ÀÏ¿OÛq9y´\ëýB´õŽëÇmøÖ’hq³034äaø>®µ‡Õ‰¶^æ9ã6û‡&‰€ëà Id\ß×fEˆ¶­ÅCÆuÙ²eKÃF-:9.2àú4ŒMÄ\ßÑ.󞉶­®QÆÝ²eËèÑ£n@¢À[|÷kd«[”¹•)Wn;ßoYÏß÷ÕCnDÛ¶£f܆M¶M¨-))9þ|ÉÿgïÞ£šºþáïƒP !MÀiŒ@!£\EZ0KÄâck­¢#PÚ´µb‘ʲZ-¢ÏHÕÑ¡,]¡ ÒxÁqVµ­eÆ¡Tð‚@¹ƒ¹#—¼œ·g2! áÇïgùGrÎ>ûì}Í׳?V*•Ó§O …ÖÖÖÓ¦MÓVþÇ”H$VVVjÛÛÚÚ Å¢E‹Æ¸½Ã„hËrMMM·nÝ’H$öööÆÆÆÕÕÕmmm|>¢›0ÊmÙL©TÞ½{wæÌ™vvvôSSSGGGúñ“'OîÞ½ÛÜÜl``  íììåvww—––¶´´‹Åâqm=ÀLt` µ··wwwœZ@+..¦(ÊËËËÃãµµõþýûËܼyÓØØxáÂ…ÎÎÎ555cÜ^€A´e³žžBˆ±±ñÀ]---sæÌ™6mÚ3Ïyòd¬ 0ˆ¶lFQÔœ9sª««gÎ.—;gÎ///äZ˜œmÙO,s¹\Š¢lllúûû››› !---sæÌ™6mÚ3Ï&³vuuiÛ>!-D[ö«©©éèèP*••••E Bˆ‰‰É³Ï>{ïÞ½¾¾¾'Ož…5ÆI¦¨«W¯®X±ÂÜÜœËå:;;GGG···B|}})Š¢(ŠÇãy{{çççÓå%ÉñãÇ™Ã{{{)Šº|ù²ZµCúÈÉǽžå5b÷'þd¶#¤T*{zz&¼ò­[·>ÿüóÃ.£ÏáÃ+<õL6gΜñóósuu-((hhh8qâDCCÃ7è½;vìèé马¬”Ëåþþþ>Ô¿æ‘|âõ“ŸøMíhçèèÈãñ¤RéÞ½{™í2™lç΋-’ÉdW¯^ýå—_^zé%@àäätõêUºÌßþö7WWWúñŸþô'##£ÖÖVBÈ©S§èXÏÊ[ZZ6mÚ4kÖ, ‹uëÖ555 lç®]»Æ¾{÷î%K–899-X° ¨¨H­LDDÄ­[·"""¤RiHHˆÚáÚZ¥ñ\‡’J¥@,ÇÆÆê¨A÷Ikkk---%ÉæÍ›;::t÷`Òêïïß»w¯££#—ËuuuMNNööö¦ Pehhhff¶eË–¶¶¶’’ý+g>=u|DÒeFøqOð‰¯ÅÔŽ¶‰äÂ… ---ÙÙÙŸ}öÙ×_ÍìÊÉÉÉÉÉ)--õõõ ”H$uuuçÏŸÿüóÏéK–,)..nll$„äååI¥Ò+W®Ðýüüô¯<88¸¾¾^¡PTVVòùüÐÐÐA››››]\\®¶711qîܹ‰‰‰åååiiiúwYÍ;wbbb.^¼ØÜÜ|ûöíW^yEG ºOºvíZ##£û÷ïþôÓOQQQzö`²)..®ªªzã7Ô¶S¥¶%##ÃÈÈhöìÙÃ;Ñø|Ü|âÿ·)mãââ„*jkk™]AAA¶¶¶E¹»»‡„„äåå1»ÂÂÂf̘A)--½víÚ'Ÿ|2}útkkë­[·Ò,,,œóóókkk=z´iÓ&úp&ÚêSùƒrss“’’„B!‡Ã9xðàùóç?~¬»G7n„U«Véjèh•CCþ¾>…BÑÚÚÊçóçÏŸ?Ôh¥¥¥ <O$ÅÆÆ¦¥¥õ÷÷¼/ãÕš9s¦¶ñññ"‘ÈÔÔ4>>>==ÝÊÊjx'Ÿ{‚Oüÿ6¢í† ®«°´´dvåääøøøX[[ÛØØ$''ÓoVšX,¦TUU͘1ÃÌÌŒ~:gΦÌÒ¥K/^¼˜——÷â‹/ÒïÝ»WWW'—Ëõ¬¼¼¼œ¢(OOO©T*•J]\\ø|~uuµî …Bú‡ÃéìììííÕÿjèh•;;»ôôô#GŽˆD"zLzH5Ъªª¸\®……SmWW3ïb$}ô'šŽk:xÔÕÕUTT¬[·ŽÞhdd¤ú›'OžÐuœh|>î >ñÿ›áD7`p<O"‘0O§M›F?¨­­ úûßÿþâ‹/Rµ}ûö»wï2Ř¯fΜÙÜÜÜÝÝmllL©««cÊøùù…‡‡÷öö.]ºÔÙÙ¹¡¡áÔ©S .äp8zVnmmMQÔ7ø|þ(vÙÀ@ó9t·j €€€€€€ÎÎÎøøø5kÖ<|ø°®®N[ ÚN*‘HÚÛÛé÷zyy¹±±1óþ˜Zœœœè»-¹¹¹©nW*•ôç;—ˉDjGI¥RÕÏÜ{÷îBlmmGÒ’Ñú¸'øÄW1Fmµ¡õåââBQTMMÍ©S§4“Édîîî‡"„tww'$$0»|||ªªªþßÿû~~~E-Y²äÓO?¥g#èY¹½½ý²eËÞyçzšDcccVVÖÈ»&‰JKKn׳U´’’’üüüîîn‡caaAÿÏRG ÚNêàààååÕÖÖV__¢íoÀ$g``pøðáÇÇÄÄ”••uwwß¼yó½÷Þ+((ÐqThhhjjê7ß|ÓÑÑQVV¶eË–¥K—2ßâϨ|Ü|âÿ·)Ö\U»ví’Ëår¹<,,lÙ²eÚJ~õÕWyyyóçÏñÅ_|ñEf;—Ëõòò‰D³fÍ"„øùùµ´´Ðô¯<##C,/\¸Çãyyy}ÿý÷#ïÚ¶mÛNžî >ñÿ¥T*G¡•ŽJ…ï+¶À¿ç04¾¯¦ð¨-€*D[` D[` D[` D[` D[`‰§"Ú^½zuÅŠæææ\.×ÙÙ9::º½½âëëKQEQ<ÏÛÛ;??Ÿ./‘HŽ?ÎÞÛÛKQÔåË—Õª]°`Á‰'tŸZµŒ››[ffæ°×§¼FÃ8/ÀTÄþh{æÌ???WWׂ‚‚†††'N444ܸqƒÞ»cÇŽžžžÊÊJ¹\îïïÿðáCýkÞºuëóÏ??ì2ú>’òc]ÀdÃòhÛßß¾wï^GGG.—ëêêšœœìííM (ÊÐÐÐÌÌlË–-mmm%%%úW~àÀk×®Ñe2ÙîÝ»—,Yâää´`Á‚¢¢"µ2·nÝŠˆˆJ¥!!!j‡ÇÅÅ9::òx<©TºwïÞAOwèÐ!©T*Äbqll¬ŽJtœ·¶¶600ÐÒÒR"‘lÞ¼¹££ƒ9—¶îLf,¶ÅÅÅUUUo¼ñ†ÚvÕå+hFFF³gÏö¹rss³³³‹‹‹ÃÃÃÕö&&&Î;711±¼¼<--Mm¯D"¹páBKKKvvögŸ}öõ×_ë8Ñ;wbbb.^¼ØÜÜ|ûöíW^yEG%:λvíZ##£û÷ïþôÓOQQQúw`by´mll$„Ìœ9S[øøx‘HdjjŸžžnee5ìsmܸQ BV­ZUXX8¤cƒ‚‚lmm)Šrww ÉËËÓQØÐа¯¯O¡P´¶¶òùüùó磒ÒÒÒ‚‚‚„„'‰bccÓÒÒúûûG¥;‚ ÑöøñãÔoÔvYXXBª««µ»aÆëׯ×ÕÕUTT¬[·ŽÞhddÔÓÓÔyòä ½Qw3„B!ý€Ãátvvöööêß…œœkkk›ääd:‘kcgg—žž~äÈ‘HäããsåÊ•aTRUUÅåréëC×ÙÕÕÕÔÔ4*ݘlˆ¶¡¡¡Êߨírrr’H$oÀ”är¹ô¨­ê^©Tz÷î]æé½{÷!¶¶¶#l§æ«][[´k×®ŠŠŠŠŠŠ°°°QpéÒ¥¦¦¦åË—¯Y³F©Tê¨Dãy%I{{;ËËË™8 0±!Úê```pøðáÇÇÄÄ”••uwwß¼yó½÷Þ+((ÐqThhhjjê7ß|ÓÑÑQVV¶eË–¥K—ŠÅâ6F$•––ÜÞÚÚJqqq¡(ª¦¦æÔ©Sºë)))ÉÏÏïîîæp8ôp²ŽJ4ž×ÁÁÁËË+**ª­­­¾¾>:::$$D[ø˜ØeV­ZuñâÅÂÂBssóõë×[[[»¹¹é8$$$äã?~ÿý÷…BáâÅ‹gÍš5hÜÔǶmÛNž|8¼zRSS]]]NŸ>­Oy¥RÙÓÓ3Ô³lݺõùçŸ^}ŽIù±®`|LáhKQ”¡¡¡™™Ù–-[ÚÚÚJJJÔ ÄÅÅ9::òx<©Tºwï^zcDDÄ­[·"""¤RiHHÈÛo¿}ìØ±3gÎH¥Ò/¾ø‚R[[hii)‘H6oÞÜÑÑA(“ÉvîܹhÑ"™LvõêU™Löé§Ÿ.Z´ˆÃáÈåòêêêýû÷[YYYXXh\ÖëÀ×®]cªÚ½{÷’%Kœœœ,XPTT¤ZF­…jÇj씎s:tH*• ±X«ÿ•Q«GÇeÑØ€ñg8Ñ FFF³gÏVÛ.‘H.\¸ •J¯_¿¾|ùrGGǵk×&&&~÷Ýw~øáºuëèbE ‚O>ù„~ºvíZ©Tzÿþýööößÿþ÷QQQŸþ9½+''çòåË3fÌ Ÿ¦¦¦~õÕW666AAA¾¾¾AAAeee?þøãÒ¥KW¯^mgg§£Í¹¹¹ß|ó@ øë_ÿþí·ß2»¶pÐNi;Ë;wbbb ÅìÙ³?~|ÿþý!]U:.‹Ž¾Œ§)…BÑÚÚÊçóçÏŸ?ŒJÈ`—eØ}]“7Ú?~œúÆ6l¸~ýz]]]EE…ÆÆœœkkk›ää䯯ÆAOZUUÅår-,,è§vvv]]]MMMôS±X¬Z˜yÊårE"‘ó´µµU÷‰„B!ý€ÃátvvöööÚ¶atÊÎÎ.==ýÈ‘#"‘ÈÇÇçÊ•+è„ vY†Ýx Q£DãlòFÛÐÐPåo4 ¥©©©Æ½µµµAAA»víª¨¨¨¨¨ cêa2è@‰¤½½‰zåå寯ÆLtÓvG¶êè”6—.]jjjZ¾|ùš5k”Jå0®ŒîË0ILÞh;Bô¸©‹‹ EQ555§Nbv‰D¢ÒÒRG988xyyEEEµµµÕ××GGG‡„„èˆÂcD[ utJ£’’’üüüîîn‡caaadd¤»mç$—@7Ö¦‡]»vÉår¹\¶lÙ2f×¶mÛNž"ÿƒµ£¶ð´A´–@´–@´–@´–@´–˜ŒÑöƒ> (êüùóC=P&“åää ܾ`Á‚'NÐÝÜÜ233‡×°‘«»Uúl×X@­Iƒ«VFŸò ã¼cmÒEÛ'Ož¤¥¥¹ºº¦¤¤h, T*{zz†TçÖ­[ŸþùÑhÝÐ £©DÖê(0ÔžŽÖ•™¨+  jÒEÛÓ§O+•Ê£Gž={¶®®ŽÙ.“ÉvîܹhÑ"™LvõêÕæææ÷Þ{ÏÆÆæÙgŸ?>³<ìƒ/^lbbâááQTTDoôòò W«<11qîܹ‰‰‰åååiii„àààúúz…BQYYÉçóCCCé’ëx¬ªM•H$.\hiiÉÎÎþì³Ï¾þúký¯Fnnnvvvqqq`` >ÝQ5¤óÞ¹s'&&æâÅ‹ÍÍÍ·oß~å•WtT¢û¼k×®522ºÿ~aaáO?ý¥gwFhrEÛ²²²¼¼¼×_òú믧¤¤¨.¯6cÆ ºØ… Ž=*‹ œÅb1]&""ÂÍÍÃálÚ´©°°P÷é>>W®\^㫪ª¸\®……SmWW3Íc$ÝÔxGÛÐÐPåoÔvõöö;vì—_~ …B¡8÷Üsžžž|>?$$„aúضmÛÉ“'ÍÌÌ!b±xáÂ…<ÏËË‹¹ãÆúÕŽÝ¿¿B¡pvvöóó[¼x±ÆÓ988ìÚµK.—Ëåò°°°eË– ãÊèßaŸ·³³sûöí–––æææ)))YYYEé¨DÛy)ŠÊÊÊêèè°µµuwwwqq‰‹‹Åþè@Ê÷ãªgG÷ wxšá}ìqJ‚ÿóXyR¿šÿ€Èÿ˜D£¶#h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,h ,a8ê5R5êu £¶Àˆ¶Àˆ¶À£3×V©TŽJ=Œ„G £[!ãÏf£šõ¤:Ù:~”¯£b‚{ ƒ£‚‡¶WyrìÚµ˜ˆª£Ñ` @Ö¢-À„A`]ˆ¶“°žm&bë(B´˜Ô}õ‡h 0Á^G ¢-Àä…Ô;$ˆ¶vT ÚLRÈ»C…h 0) ÈŽ¢-Àd„¤; ˆ¶“âìNt€µ(Ššè&LaT°~å‚q‘ÿ£¶Àˆ¶Àˆ¶À˜k ãA©TNt€T§tcÔXÑXÑXÑXÑXÑXÑXÑXÑXÑXÑXÑXÑXÑXÑXÑXÑXÑXÑ`|}})Š¢(ŠÇãy{{çççÓÛoݺµråJ¡Phbb"“ɶmÛÆrõêÕ+V˜››s¹\ggçèèèöövºªèèè¶ÇÍÍ-33s„•°¢-ÀÐìØ±£§§§²²R.—ûûû?|ø°¿¿ÿå—_‹ÅEEEMMM™™™vvvtá3gÎøùù¹ºº444œ8q¢¡¡áÆÛ¶B´Š¢ ÍÌ̶lÙÒÖÖVRRRSSóË/¿DFF>÷Üs&&&nnn7n$„ô÷÷‡‡‡‡‡‡ïÝ»×ÑÑ‘Ë庺º&''{{{ë¨ÿСCR©T ˆÅâØØXzcKK˦M›fÍšeaa±nݺ¦¦&BHDDÄ­[·"""¤RiHH!D$}ÿý÷ô!………¦¦¦ôc™L¶}ûö%K–xzzÊåòâââ±»>Ñ`˜222ŒŒŒfÏž-‹¾üòËÊÊJ¦@qqqUUÕo¼¡v EQÚê¼sçNLLÌÅ‹›››oß¾ýÊ+¯ÐÛƒƒƒëëë Eee%ŸÏ %„$&&Î;711±¼¼<--MwkOŸ>ýïÿ{ãÆ+V¬èîî^¯'3D[€¡‰‰D¦¦¦ñññéééVVVß}÷ÝÂ… 8`oo?gÎzþkcc#!dæÌ™úWnhhØ××§P(Z[[ù|þüùó !<ÈÍÍMJJ …çàÁƒçÏŸüøñš½qãF@@yóÍ7ûúú._¾<¤Ã§D[€¡Ù°aÃõë×ëêê***Ö­[Go´´´Ü·oß?þøèÑ£M›6YXXBª««õ¯ÜÎÎ.==ýÈ‘#"‘ÈÇÇçÊ•+„òòrŠ¢<==¥R©T*uqqáóùCª–"‰Tõð)Ñ`h¸\.=j«q¯©©iTTÔôéÓþùg'''‰DrâÄ µ2J¥RGý—.]jjjZ¾|ùš5k”J¥µµ5EQ7nÜ(ÿÍ£GæÎK10ø¯8ÇãñºººèÇô|\Æýû÷é½½½CKž*mFª®®îƒ>P(ííí¿þúë¾}ûzzz<== >|øðᘘ˜²²²îîî›7o¾÷Þ{Úª*))ÉÏÏïîîæp8FFF„{{ûeË–½óÎ;µµµ„ÆÆÆ¬¬,º¼H$*--e÷ðð8{ö,!¤««+!!Aµæ¤¤¤›7oöôôìÙ³‡ÃáøúúŽÁ•˜`ˆ¶#ebbòøñã×^{ÍÂÂÂÞÞ>777''ÇÁÁ²jÕª‹/zxx˜››¯_¿ÞÚÚÚÍÍM[UÛ·o·´´477OIIÉÊÊ¢s–‘‘!‹.\Èãñ¼¼¼˜Û lÛ¶íäÉ“fff„ýû÷+ ggg??¿Å‹«Ö¼iÓ¦·ÞzkÆŒÿøÇ?Ξ=kll<†Wd‚PºÇÃ'J£„Á ËŸÍþùäúéÚµk¥Réýû÷ÛÛÛÿûßGEE}þùçô®œœœË—/Ϙ1ƒ~šššúÕW_ÙØØùúú•••ýøãK—.]½zµÓ’;wîÄÄÄ(ŠÙ³g?~üøþýûôöàà`###…BÁår###CCCÏ;7°…:œ>}ú‡~ééé+V¬¸sçÎ$_ž£¶ÄÇÇ‹D"SSÓøøøôôt+++µAAA¶¶¶E¹»»‡„„äåå ZgiiiAAABBljD±±±iiiýýýôÞ°°0&×B6oÞêáãÑžF¡¡¡Êßh,@Jf⩚ÚÚÚ   ]»vUTTTTT„……1õ0t ‰DÒÞÞ΄àòòrccc¡PH?Õ²õpéÒ¥¦¦¦åË—¯Y³F©TZ[[SuãÆòߌrëÖ­•+W …B™L¶mÛ¶qnÀõë×µÝÐ{„®^½ºbÅ sss.—ëììÝÞÞNñõõ¥ß<ÏÛÛ;??Ÿ./‘HŽ?ÎÞÛÛKQÔä_`´ Úê2ÔD;m@ÆÕ­¿¿ÿå—_‹ÅEEEMMM™™™vvvÝ(]”JeOO>%Ïœ9ãçççêêZPPÐÐÐpâĉ†††7nÐ{wìØÑÓÓSYY)—Ëýýý>|8–­`•>ø€¢¨óçÏõ@™L–““3pû‚ Nœ8A?vssËÌÌ^ÃFr¬îV Ûè6i Új0í°OGܧgFZMMÍ/¿üùÜsÏ™˜˜¸¹¹mܸ‘ÞÕÒÒ²iÓ¦Y³fYXX¬[·ŽY9°¹¹ù½÷Þ³±±yöÙgçÏŸO/ÇR[[hii)‘H6oÞÜÑÑA–Éd»wï^²d‰““Ó‚ ŠŠŠèí¿üòËK/½$œœœ®^½Ê´'..ÎÑÑ‘ÇãI¥Ò½{÷2Ûe2ÙÎ;-Z$“ÉÖ­[÷ /0» ž}öYz8–Ñßß¾wï^GGG.—ëêêšœœìííM (ÊÐÐÐÌÌlË–-mmmSq¦?À„xòäIZZš««kJJŠÆúA0¶nÝúüóÏFë†fMe=DÛÿ˜œ‰vØ Ð³;SX,vpp ûòË/+++Uw×××+ŠÊÊJ>ŸJo_¿~}EEEAAAsssZZÇ#„¬]»ÖÈÈèþýû………?ýôSTTSOnnnvvvqqq```xx8½100P"‘ÔÕÕ?þóÏ?g K$’ .´´´dggöÙg_ý5³+'''''§´´4%%¥¨¨èæÍ›ôöÔÔÔ×^{Ëåª6¾¸¸¸ªªê7ÞPëïÀ4##ÃÈÈhöìÙC¾vO¥Ó§O+•Ê£Gž={¶®®ŽÙ®:qõêUã „,^¼ØÄÄÄÃÃï8pàÀµk×!·nÝŠˆˆJ¥!!!d(ã,‰DÌúa………Ìä7µ¦jUÑæÐ¡CR©T ˆÅâØØXz£Æv©IÛ·o_²d‰§§§\./..æË3bˆ¶S&Ñ„ŒK100øî»ï.\xàÀ{{û9sæÐß›ùdúôéÖÖÖ[·neÚdkkKQ”»»{HHH^^³+,,lÆŒ„zaÃ/¾ø‚ÒÞÞþ·¿ýíí·ßVëWcc#!dæÌ™Ú:/‰LMMãããÓÓÓ­¬¬F銰\rròk¯½æéééàà úû¢2áëë«q„’”””ððáC///f¼ƒ‘˜˜8wîÜÄÄÄòòò´´42”q–Çê ÚT£*ݹs'&&æâÅ‹ÍÍÍ·oß~å•WèíÛ9¤&>}:;;ûßÿþ÷ÆW¬XÑÝÝ­»üyzï0¼›ÑNNzÞZÙ;%:¥?KKË}ûöíÛ·¯­­-99988xÞ¼yMMMEyzz2Åø|~uuu]]‰‰‰X,V­¡ªªŠËåZXXÐOíì캺ºššš,-- !B¡ÞÎáp:;;{{{«ªªf̘affFoŸ3gSUNNN\\\yy9EQ---K—.ev©žtÆ û÷ïÿꫯfÍšååå¥Ö)º1ÕÕÕL«ÔlذaÛ¶m¦¦¦ª¿`322RýfêÉ“'ôÆA® ÀS£¬¬,//oÏž=„×_=%%eÛ¶mÌç#3AƒTWWÓÿt;;;35DDD¸¹¹B6mÚ4è$zœ¥¾¾žþ(9xð @ xüøñǵկ'¦©„   ú3ª²víZmöõõ) +++>Ÿ?þ|íäóùú7‰ zóÍ7wìØqùòå—^zi¨ý¹§kÔ6Ò}úÏ?ÿlmmMQÔ7ÊóèÑ£¹sçÚØØtttÔÖÖª(‘HÚÛÛéRBHyy¹±±1“hš9sfss3óÿQæû¬ÚÚÚ   ]»vUTTTTT„……©¾ªW{Ñ¢EæææçÎûâ‹/ÙBœœœ$ÉÀéÿL…\.—µUÝ+•JïÞ½Ë<½wï!ÄÖÖV[GØçøñã:>ãRSSíììè…ààಲ²K—.1{™1ˆòòòã 4æû4SSSz¼CGcè‘OOO©T*•J]\\èqõëIõØœœkkk›äädæãL#;;»ôôô#GŽˆD"Ÿ+W®èhçš$‰TõðÑòTDÛHóHúîb£uë®É@ÿ¾LõŒ[WW÷Á(Šööö_ýuß¾}===žžžöööË–-{çwèÛØØ˜••E¡·¿ûµµJ¥²¸¸¸¶¶ÖÁÁÁËË+**ª­­­¾¾>:::$$ÄÀ@ëß™Læîî~èÐ!BHwwwBB½½µµ•âââBQTMMÍ©S§t´|Æ ùË_þõ¯ œPK1008|øðáÇcbbÊÊʺ»»oÞ¼ùÞ{ïè¨344455õ›o¾éèè(++Û²eËÒ¥KGòO'À”ªí°··÷رc¿üò‹P( …ô€åÑ£G™̧¡Æq=©~| iœEíXBÇëêê¢3“tÕšª{TE£€€€K—.555-_¾|Íš5J¥R[;‡Ô¤û÷ïÓz{{+**tÌ©Sl޶CM´ãÓªñÇîŒkbbòøñã×^{ÍÂÂÂÞÞ>777''ÇÁÁ’‘‘!‹.\Èãñ¼¼¼˜iï™™™Ï=÷œ§§'ŸÏ imm¥(*++«££ÃÖÖÖÝÝÝÅÅ%..N÷y¿ú꫼¼¼ùóç¿øâ‹/¾ø"½ÑÁÁa×®]r¹\.—‡……-[¶LG !!!·oß^¹r¥¶)«V­ºxñbaa¡‡‡‡¹¹ùúõë­­­éoÁtÔùñÇ¿ÿþûB¡pñâųfÍÒ¯ž*çÎkhh(((¸þ›äääììì÷OÔ8¢çYD"ó›³!³¨Kñðð8{ö,!¤««‹FQ3¤QBHIII~~~ww7‡Ã±°° '­ikçš”””tóæÍžžž={öp8___=¯Øè¢&g¤Kx¤ùõÓÇ Y–69;>>Ø4Ïxêêëë›9sæ±cÇ–/_>Ñm™Tß–xïFx“LE“êU[±b…©©é—_~Éléííµ··ŒŒ|ÿý÷e2ÙþýûW¯^MïzôèѶmÛΟ?ßÒÒ2gΜŒŒ Õ2ååå¶¶¶===††† ,ˆŒŒ|ýõ× !W®\Ù°aCcc£ŸŸ_VVÖãÇcbbΜ9Cÿ„cåÊ•ñññÚêW;¶¼¼üÍ7ß|ôèѳÏ>»råÊØØØ¶¶6BˆZS?þøã´´4 ‹3fXYY=zôˆ¦ª­b(а°°’’’iÓ¦988ë³ÓëÒéXu]c{ŒŒŒzzz˜2Ož<¡7êîšP(¤p8œÎÎÎÞÞ^}ºðt:}ú´ŸŸŸ““Ó÷ßßÔÔtáÂ''§±û]¦R©ìééÁüøa4é < IDAT›˜h‹DË>ȸ0¨)÷Òs¹\z”Tã^më¶k\^Çúì '''‰D2ðó’ùk¥±=R©ôîÝ»ÌÓ{÷îBlmm‡Ùg]x õ÷÷oÞ¼yóæÍûöíûÝï~Çår¥Rixxxll,]@Û4zm“Úu”ß¹sç¢E‹d2ÙÕ«WUçÇkœ¾¯êСCR©T ˆÅbÝ ‹ˆˆ¸uëVDD„T* !„ˆD"f!úÂÂBæ_™L¶}ûö%K–xzzÊåòâââ1¸ºcb\£-íÓtcÍë®mÝvKÃëXŸa``pøðáÇÇÄÄ”••uwwß¼yó½÷Þ+((ÐÑŒÐÐÐÔÔÔo¾ù¦£££¬¬lË–-K—.U3­®<…ŠŠŠªªª‚ƒƒµ®¯¯W(•••|>?44”Ù•›››]\\>hùœœœœœœÒÒR___ÕS¬_¿¾¢¢¢   ¹¹9--ž¾Ï¸sçNLLÌÅ‹›››oß¾ýÊ+¯è8QbbâܹsËËËÓÒÒt÷ýôéÓÙÙÙÿþ÷¿7nܸbÅŠîîîA/×d0æÑ–R¡»ädK´ctwɱ˜ãòäÉ“÷ßßÆÆÆÄÄD.—kü½óøÃ-rA¼â»ví’Ëår¹<,,lÙ²eÌ®ÌÌÌçž{ÎÓÓ“Ï燄„ÐI1##C,/\¸Çãyyy1Ã$ªV­ZuñâÅÂÂBssóõë×[[[»¹¹éhFHHÈÇüþûï …ÂŋϚ5käITGמ6ô`'3 >>>žÎôï8uO£8©]wù°°°3f¨5@ãô}Õ†††}}} …¢µµ•ÏçÏŸ?Ðé‰iÿ›o¾Ù××70ÒLNcu‡„©~£ƒ3gÎEEEÅÅÅI$’{÷î>|øÆ .$„ìØ±ãÿ÷[[[?þøcÿòòòïÅñÔÙÙÉçó¿ýö[>ŸÿÖ[omܸñ‡~˜Àö¨Q}•qkPE¿â“óåÖö¸ê®>úè£>úh`33³äädµ|>?!!!!!A÷yårùùóçõo!$,,,,,LwµªÍVýù‹T*Õøï°¶®°ÒñãÇÿøÇ?ÒÕþFÐÓ«««éÙð‘‘‘‘‘‘)))û÷ï'*Óè™òô4z>ŸO4Mj×]^ã÷-§ï«²³³KOO?|øphh¨‡‡Çž={/^¬ûDz‰Dªuü`RåQÛ):@«fìî.©6Ç%11ñ…^`ö<ûì³ôذ¶9.§ÎðùüÝ»wÛØØ77·þþþѼ£ Ó` ¼Ö0±BCCµ}<9;;K$m_†è3^ÿòã“Æéûj.]ºÔÔÔ´|ùò5kÖ(•J'20ø¯ìÇãñºººèÇj÷Û¾ÿ>ý ···¢¢BÇý[&åhÏszí…B¡qïâÅ‹?úè#úq\\œ‘‘Q]]R©œ9sæ±cǘbôo–/]º¤v¸««kFFýø×_åp8ÅÅÅôÓ·ß~ûwÞ¡;::þîw¿{ôè‘R©LKK³¶¶îêêR*•¯¾úêš5k;::Þ}÷Ý+V¨Vž››knnþí·ßޤûãl ßÜ0eMô»&)¼I¦"¼j999Ó§Oß¹sçÝ»w»ºº***Þzë­Ù³gÓ{—/_PSS£T*¾úê+z»££cvv6ýøÁƒ„žž=Ë+•Jÿû¿ÿ£/[¶ìÕW_­©©éïï/**¢eܾ};// Gµ´´ìïï×q¢åË—ïÞ½›9üµ×^ûÓŸþ¤T*;;;_~ùe.—Ë´ÇÚÚº¸¸øÉ“'111³fÍ¢O19©¾ÍF4jËŽ1ÚÆíî’fff_|ñ!¤½½ýoûÛÛo¿Íì8ÇE÷Ô…Bñ‡?ü!;;{Ñ¢EÃkÏ„˜roxªøûûçåå)Š^xÁÔÔÔÛÛ»¿¿ÿÌ™3ô^}¦Ñ«jy¢eú>£³³sûöí–––æææ)))YYYt0Óv¢mÛ¶m&ó+žššêêêúóÏ?ëY^©Töööi«†dëÖ­ôÿÆUûR^^¾{÷î nÀX…vÙ1Ž;vRRRø|þK/½4Ñ eC£ŸVÁd0F¯¸>+žÇÅÅ9::òx<©Tºwï^z£Ú §ß~ûícÇŽ9sF*•Ò70©­­ ´´´”H$›7oîèè`Ψºæ»L&ûôÓO-ZÄápäryuuõþýû­¬¬,,,âââ4¶YãÊïCº­5Ѳ¾<½½j_¤Ré /¼ mu/L?°mWŸ×çzêh9À¨ÃQÛ¦ú8îX033ãr¹§NRûyÙÔ…1ZÐa¬_÷Ó§Oÿðà ==}ÅŠwîÜQ»[D"¹pá‚T*½~ýúòåË×®]›˜˜øÝwß}øá‡ëÖ­£‹Q%>ùäúéÚµk¥Réýû÷ÛÛÛÿûßGEE}þùçô®œœœË—/3릦¦~õÕW666AAA¾¾¾AAAeee?þøãÒ¥KW¯^mgg§Úzåw…B1{öìÇ3¿ÕÖ‘àà`###…BÁår###CCCÏ;GY¿~½AAAH$ºyó¦êúò©©©ª}9wî\dd$³WÇÛ6ðBéy=µµ`ÔMLœÂ8.ãÑ£GUUU>>>jۧ܌тnãóººâyPP­­-EQîîî!!!yyyƒÖYZZZPPÀãñD"QlllZZ³æŸÚšï›7ož7ož©©ipppccãž={¸\®£££B¡P«YãÊïÚ:¢í¶Öƒ®/¯îu´m¨×sTÖ²ÐÁ××—þâñxÞÞÞùùùôö[·n­\¹R(š˜˜Èd²mÛ¶1‡\½zuÅŠæææ\.×ÙÙ9::š¾e§¯¯ott´>'ÕBùxN=ÆO Øg‚G ‘q§:$ZÐǸ½ôƒ®xž““ãããcmmmcc“œœL¯Ï¢[UU—Ëe~åigg×ÕÕÅ|¥®–#™§ô-™oc¸\nkkëñãÇUÿÊÐ+¿9rD$ùøø\¹rEGG˜áé©...ôŠðƒ®/¯îu´M•>×S[ˇÚ`vìØÑÓÓSYY)—Ëýýý>|ØßßÿòË/‹Å⢢¢¦¦¦ÌÌLæk“3gÎøùù¹ºº444œ8q¢¡¡¾¥ýT·uëÖçŸ~¢[1Á&Ë—àC͸ˆ¹HÿW‰Æ™îÏkkkƒ‚‚víÚUQQQQQÆü›£cFD"ioogB[yy¹±±±P(¤ŸéߢëÔ\ù][G´­¯Ïúò z Æ¶©^(=¯§ŽµìF EQ†††fff[¶likk+))©©©ùå—_"##Ÿ{î977·7BúûûÃÃÃÃÃÃ÷îÝëèèÈår]]]“““½½½uÔ¯6õ\ÏyçdXSÏõ™µ¯ítô${¦žÝ»w/Y²ÄÉÉiÁ‚EEECjÆÃuŸ]Û!§õÝüÉmô?úñ¿þcdÜq¦ÿG¢…‰’””tóæÍžžž={öÐwƒVÝK¯NéââBQTMMêíùÞpšáàààååÕÖÖV__2*“ãKJJòóó»»»9Ž………ê vÄÞÞž¾­5Fé›ýÑÛß}÷ÝÚÚZ¥RY\\¬gÌÕ} ¶¶©^(=¯§¶–Œ…ŒŒ ##£Ù³g‹Åb‡°°°/¿ü²²²’)P\\\UUõÆo¨¨ãÓžz~ñâÅæææÛ·o¿òÊ+‰‰‰sçÎMLL,//OKK#¿Í;oiiÉÎÎþì³Ï˜Õ,\__¯P(*++ù|~hhèÀ3¦¦¦~þùç|>ß××·µµµ¬¬ì믿þðÃËÊÊtœNMnnnvvvqqq```xxøPÛ3ðpšŽ³kú裪Ýp:%%EuïÌ™35Š”””h{ºzõjÕ_‚þóŸÿx¸»»ûÀÖê舶ÛZ›™™%''«mdz­Ú—W_}õÕW_Õ} î¶©](=¯§ŽrèãøñãüãéÇ?â7lذmÛ6SSSSSSf£¥¥å¾}ûöíÛ×ÖÖ–œœêáá±gϞŋ«•ÉÉɉ‹‹£g–·´´,]ºTcUÌÔsf =õœÏç«Ó=k_ÿÓ1S§8Ngggoo¯¡á?ÝíÑv¸Ž³|8pÞùßÿþ÷_|‘¢þ¿öî>¶Êònàø}ݶC^  u”Èû6 †…q‹ˆ(!˜ld 0:Ãd…e*3.2é²p“ ˜‰±qÓ™ ™KFš64“ çÖQŠcò&X¥Ï}žc(§§íy¹Ïu>Ÿ¿úrŸë¾ÎÊ×mâþûïûí·“ŸmóèyW.õíÚÕÅýtôîÉcýW\qEWøHHÍY…ÌòÏÂÉ»ï¾ûÝï~wÏž=§OŸþÏþóÃþ°©©iÒ¤Iݺu«­­­­­]¹reCCùsçöîÝ»dÉ’úúúK-ÕæÑó4ÏGY8zžúvíêâ~:z÷6õgõ~Mm/fŽÛiF¿H¤úœ– Ž®`žäÑg?ûÙ>øà¶Ûn;tèÐe—]6räȺººáÇGQ4{öì;v<úè£ëׯÿ裮ºêª;î¸ã‚!nk-GÏ÷íÛ÷™Ï|føðá-GÏW¬X±hÑ¢µk×Θ1cûöí-çÎËËËûöí;sæÌãÇ'~Á•Û¶m[¹råu×]wìØ±þýûßtÓMñO-y̽ÍÛµ«‹ûéÄÝŸyæ™+VLš4éĉŸÿüç·mÛvÅWtýu¸”D<«eÝñÎÉJݸIñ|⹡h‰¡Ö¿,ýÚ£M~‘"ÿÕÈÖ¿Ì ~j{±ŽÎq£âøÍ–þ©Œbx5€ ˜¶I­OâíqZ x„œ¶­Û‘\E ¡bIÛ¤dÌ¥Ž¿m\E ³¢KÛ¤WÑDÅœ¶I…Û¸Š 5iû©Bi\E Ð&iÛ†Ž6n”ýŽô­»Ú%mSi‰yåФOÚ¦+—Ç-@'HÛË^ã*Z€®¶—©ÆU´pô—@kÒ6:׸Š ³¤m&uâ[+´»i’¶Y‘fã¦x %m³+ÍÆU´PT¿ †®kÿšƒ÷|úEcÈÚt_œwwnG¶9ÒfãÕŸåÙÖ-߀̶ |ËjrÀÔ€@H[!m„³¶@¶ø6—ŸÚšÖQãÄüOßn~:½•ïð"ÊÔ€@HÛ8š>}z"‘H$eeeS¦LÙ¹sg›—Mœ8qË–-9Þ@lIÛ˜zàššš}:‡O “ü3²¸Û¶m[=®¾úê–wëêê^}õÕ¾}û^|å¦M›ž}öÙ¡C‡Î;wúôésçÎmhhøóŸÿ|à 7|ík_»òÊ++++_~ù媪ª×_}Ö¬YÕÕÕ·ÜrËË?~|РA{÷î9rdËš·Ýv[IIIΞ/@§™ÚÆÔÚµk+**JKK×®]»yóæ´||ñâÅmvmEË–-9rdiiéüùó~øá’’’iÓ¦UWWïÙ³'Š¢¹sç6,‘HŒ?~áÂ…¯¼òJò±Ée{÷î=gΜ'Ÿ|2Š¢Ó§OÿêW¿úÆ7¾‘õg Ò6¦-Zôú믿û7o^òã¼ÔC’Ÿ*))©¨¨èÖ­[òÝ“'OFQTWW7mÚ´!C† :tÆ m.»hÑ¢-[¶455=û쳃ž=‘H$‰²²²)S¦ìܹ³åúÊÊÊ_þò—ɇüñljDâÕW_ÍÇÞòCÚÆÑ /¼0cÆŒ±cÇÖ××=ztË–-G}ã7Z>ûÀ455ú¨åƒYÞ,@Œ8;£Fª¬¬Ü²eËonnny£¤¤¤¢¢¢u×FQTUUõöÛo'ßýç?ÿEѰaò¼Y€‘¶±Ó­[·ÚÚÚÚÚÚ•+W644œ;wnïÞ½K–,©¯¯Oñ¨;ï¼sÓ¦M¿ûÝïΜ9ÓÐа|ùòn¸aàÀ9Û6@ÞIÛ8š={öŽ;vïÞ=a„>}úÜ~ûíC† 7n\Ї,\¸ðÑGýÎw¾Ó¯_¿ë¯¿~ðàÁ[·nÍÙ†âÀYÛ˜ª©©y饗.þxŠŸÂ°xñâÅ‹gqOñfj @ ¤-¶BÚi @ ¤-¶BÚi @ ¤-¶BÚi @ ¤-¶¢{¾7@tðžD‡>;dms6·P¨LmòOªd„©mv%©&1¶¹Ùo@;t0À¥˜ÚÄ‚`è:i›]šÂÙíRÀ)H[€¸­]$m³.ÍY¬‘-Ð.í š´ˆñ ÐÒ6ÚÈÙíR½í’¶ñ"a:MÚæH鬑-Ð.½ i ;B sü4²ÜinnöãÇ€NPºªÄüŽ}¶ùéìí%¦¶q$g¡HÕŒ“¶9uÁŒÖÈh—ÆZèàtH[€˜µP kfeæ¬íÅGHcëžèž|oáSôºå 7ÅIÝ-pšLmòI¶f´ˆ5í›>i gâ5S2ÿ}m‰$SœEÕÛ!¦¶ù'a3BÚÄ”Þí(i  B¶ë¤-@)ÝN¶q!g»HÚÄŽÆíi #¢¶+¤-@¼¨ÛN“¶BÚi @ ¤-¶BÚi @ ¤-¶BÚi @ ¤-¶BÚi @ ¤-¶"îi»k×®o¼±OŸ>%%%£G~ðÁOŸ>Ù[Œ7î™gžI¾;qâÄ-[¶döé¬ÙúšNl©õ5~ 9x)²'Öiû /̘1cìØ±õõõGݲeËÑ£GßxãK]ßÜÜÜÔÔÔÅ›Þwß}×^{méÄš)®éè–2õ²ñRdO|ÓöüùóK—.]ºtéêÕ««««KJJÆŽ»aÆ)S¦\påˆ#zè¡©S§Ž1b×®]üã[>µ{÷îÒÒÒäeßÿþ÷¿ô¥/5jâĉýë_£(ºë®»þö·¿Ýu×]UUU .Œ¢èñÇíµ×’yâ‰'¦NÚ³gÏšššÃ‡?öØc (//_³fMË5'Nœøö·¿=xðàòòòyóæ;vìâçrÁšo£õ5©·´fÍšêêê²²²ªªªÕ«W·ùÒµ¾þÇ?þqUUÕå—_>pàÀGy$Å"©ï{äÈ‘[o½µÿþ•••Ë–-;sæLê§{ñMÛ7ß|óСC ,¸àã‰Dââ‹ëêêêêêÞzë­éÓ§§XóÅ_|þùçß|óÍ[o½uéÒ¥Q­_¿þšk®Y¿~ýþýûŸzê©‹²iÓ¦Ÿýìg½zõš>}úÉ“'ž{î¹ï}ï{ QÍŸ?ÿ½÷ÞÛ³gÏÁƒ{õêuçw¶ûÔ.ÞFk©·TYYùòË/Ÿ8qâùçŸÿÉO~òÜsÏ¥¸Ñ?þñ•+WîØ±ã¿ÿýïßÿþ÷¯~õ«)I}ß[n¹¥Gÿú׿vïÞý—¿üåÞ{ïMóéäL|Ó¶±±1Š¢Aƒ¥sñâÅ‹ûöíÛîeßúÖ·.¿üò(ŠfÏž½{÷îtV^¶lÙÈ‘#KKKçÏŸßØØøð×””L›6­ººzÏž=ÿþ÷¿_|ñÅŸÿüçýúõëÙ³ç~ô£—^zéƒ>Èø6’æÎ;lذD"1~üø… ¾òÊ+).îÞ½û'Ÿ|²gÏž“'OöêÕë _øB'‰¢è­·Þª¯¯_·n]YYYEEÅ#<òÔSO?¾ëO ƒâ›¶åååQ>|8‹˜Îeýúõky£gÏž~øáÇœþÊ%%%ݺuK¾{òäÉýû÷'‰I“&UUUUUU3¦W¯^íî¹ÛHª««›6mÚ!C†ºaÆ–ÿ¸”+¯¼róæÍ?ýéO+**¦M›ö‡?ü¡‹DQtèС’’’–ÿ"-Ëž={6yô¢+O ƒâ›¶£Fª¬¬¼ø_è777_|qëS eeegÏžmy»Í“¯HÖj' 2$‘H¼ñÆûÿÏñãǯ¹æšN/˜zKGŽ™;wîªU«8pàÀÅ‹·ùj´6gΜßÿþ÷ÇŽ›5kÖ׿þõæææ‹\꾕••§OŸNðþýû/»ì²dÑÄD|Ó¶[·nµµµµµµ+W®lhh8wîÜÞ½{—,YR__Ÿú&Løõ¯EÑÙ³g×­[×î***Þzë­Îmòª«®š9sæ7¿ùÍ#GŽDQÔØØ¸}ûöÎ-•ΖNž<Eј1c‰Ä;ï¼³uëÖÔëìÛ·oçÎçÎëÙ³gyyì#^7IDATy=R/r©û>|òäÉ÷Þ{ï©S§Þ{ï½|páÂ…]ù_€lˆuÌž={ÇŽ»wïž0aBŸ>}n¿ýö!C†Œ7.õ£{ì±={öŒ=zÆŒ×_}»wY±bÅÓO?Ý»wï9sætb“Û¶m8pàu×]WVV6yòää7gèŠKmiøðá«V­ª©©©©©Y¼xñÌ™3S¯óá‡Þÿýýû÷ïÓ§ÏÆ·oßžH$R,r©û&‰íÛ·Ÿ9sfذaãÇ3fLòDÄG¢Ý¿ÑNk•Vç2² D~]®¡íÿ}R'¸;[+]µµoñ”wø#òS±žÚ@ú¤-¶BÚi @ ¤-¶BÚi @ ¤-¶BÚi @ ¤-¶BÚi @ ¤-¶BÚi @ ¤-¶BÚi @ ¤-¶¢{ÆWL$_Úej @ ¤-¶"3gm›››3²NÒºãë2»`ÒݽïÎÒÊij}9ã¯@13µ Ò€@H[!m„´ Ò€@H[!m„´ Ò€@H[!m„´ Ò€@H[!m„´ Ò€@H[!m„´ Ò€@H[!m„´ Ò€@H[!m„´ Ò€@H[!m„´ Ò€@H[!m„´ Ò€@H[!m„´ Ò€@H[Ñ=ß\"‘èÐg›››³¹€™Úi›]šÂÙt…´ Ò6ëÒœÅÙt‘´ Ò6ÚÈÙt´ Ò6GRÌel2BÚi›;mNgl2EÚi›SÌhl2HÚi›kÉI­‘-@fI[Ñ=ß(FæµÙ`j @ ¤-¶BÚi @ ¤-¶BÚi @ ¤-¶BÚi @ ¤-¶BÚi @ ÍÍÍ9»Ùºãërv¯®»»÷ÝùÞPH†ÒW¸è€¯p[ùÞAGÜ‘»êËS[€¢£k!cŠ  KNÓ¶€æ ´U &ô"kÅQᦶÅE‚C†G2Š\§mALC b“@ ©F ¦Š¦¿MmŠˆø†¬(špŒ¿<¤mÌg¢1ßsÚˆb*oS[€b!»!‹Š)ã,?iÛÉhl7 ÄH‘5·©-@QÜuE‘ñ”·´á|4†[ ”Žb¡øjÛÔ |Rr¤øR2nò™¶±š’Æj3@Ô$gEÙÙ¦¶ÙSE”ñ‘ç´É¬4&Û£)¼)ÖÂ6µ™¼†<(Ö¬Œƒü§mÞ'¦yß0e äA·uþÓ€,Ö7E—ù‹´ÍãÜÔÈÈ6} äTqWu,Ò€Œ“ÔgŘù—´ÍËôÔÈÈ • äHÑ÷t\Ò€ Ó Eš¹£´Íñ ÕÈÈ%­ d’ŽUÚ2bDnæV¼Ò6g“T#[ ÷'E:Š¢¸¥-]$ !vDgÅ.ms0O5²òEwY¡žÿOìÒ€N“ÎSÒ3W☶YªÙù¥> ÓÍ­Ä1mèÑ ±&@s"¦i›¥Ùª‘-ÈÅüÿÅ4mè¹ @†f_|Ó6ãV#[ >”(Zù"ñM[Ò$”¡`ˆÑ,‹uÚfpÎjd ĺD%·%Öi @»$2IšMqOÛŒL[lxR¥@'éãKˆ{Ú‚8†‚$L³¦Ò¶‹3W#[ δ)ÐaÊøÒ mh“,†&O³£0Ò¶Ó“W#[ þ*К8¥ÂH[. ˆ¡à‰Ô,(˜´íÄüÕÈ(:H‹nOÁ¤-IR!U3­Ò¶CSX#[ °¨U :8 …”¶D"#X3ªÀÒ6ÍY¬‘-Pˆ4+pI 8=–¶ENþB€dkæ^Ú¶;‘5² —rÚ }ÓVxi P´„/K¼fHA¦m鬑-Pèô+ðÿ¨ÞŽ(È´(B’'a3¡PÓ¶Í鬑- ü/½ÛA…š¶EEìBQ²]VÀi{ÁŒÖȉ–”n'pÚ ™ EDÎvMa§mrRkd „GÑBQÓ¸RØi < EGÔvA¢¹ÙË@þ3‚CšHDô–IEND®B`‚trusted-firmware-a-2.2/docs/resources/diagrams/reset_code_no_checks.png000066400000000000000000001155111355360272700265040ustar00rootroot00000000000000‰PNG  IHDRžÜ¦}ó×bKGDÿÿÿ ½§“ IDATxœìÝ{\”u¢øñï3¹8!–j^"MC±|U§¶‹º¾Ö-:m½ÒSVdz'«ÕÚ6·ãÖjºÝ£{º¬½Êú•¶î)«ÝÒ¬4ÌËzAAAÀ¸_†ÛüþxÚ‰f`f¾|Þ/ÿžyæy¾Ã ·/Ï<£8 ~šà¤-$AÚ@¤-$AÚ@¤-$AÚ@¤-$AÚ@¤-$AÚ@¤-$AÚ@¤-$¡ëüņª 5Ž¡éó#=y0k I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶i Ièü¼¿Â¯ ?Y÷IÑ7Emö¶Hkäø›Æ_ÿï×…¹Z휵×-¹nÊÂ)]–—-Ùpã†ç‹Ÿï²ü¿oùBN3|Ôð™÷ͼnéu}ê ³^Èz4ëª;®êÛÍàg~MÛcûÓ½Êü·ÌÛ~}›)ÖTq¦bÏË{JŽ•$LKðâ^®_~ýߨÞÖžÿeþ+w½b¹Ò’’™âÅí 0ù/mŽ­ÿ¹õÚŸ]û/«þE]2rüȯÿ±ÃáBÔ^¬Ý¶bÛé¯NkõÚ´›Ón}æÖ ®S¹Õ%Õo?üvÑ·E¦XÓµ÷^ërOŠÐè4fÜõãbÆÄ”ž,MÉLqµ}WË·­ØV–W¶mŶžù`ÌŒ1‹ÿ°ØGßx‹ÿ޵-=YZ}¡zê§vY®(ŠâÕ»_Õ굫®úÏþ£øHñö_lï¾…×îy-"6âÙ¼gx罯íu¿»öÖöÜÏr+ +Õ)aWÛwµüÎßÜiI±Üù›;Ÿ:ò] 0(ø/më+ë…WDt¿ª¼ ¼è›¢;þëC˜aX̰›qó7o}ãèptYçÜÁs?zöGzƒÞgžóðW;údí'ô?FüÇÆ;7Nÿ×é£'vµ}Oö €ÁÂ$„E… !jJkÔ U—T…9—GZ#[í­ —¢Ã:¯:<4Ôª~=&ÚÕŽ®ÿëoþÅÍŽGùéòÍ÷nÞñëI×&õ¸}Oö €Á³¶W\y…)Ötà]–;ÓHSKc‹:­+„øîÜw:ƒÎiì¼ZDlDSMS›½Mý²îbûÝ)eDÒˆôI?öá1WÛw¿_E£ôãîÀßü—¶ŠF™ÿÂü=/ïùè¿>ºTt©ÍÞV–[öîÏß-ú¦(zL´uŠuûÊíö{]EÝŽ_hZ—²‘4".-n÷ÿìB´ÙÛ>ßô¹Ë=9DG[G{K{Y^Ù‘÷Ħƺھûý†Ç„—ç—ûð;¯RÔ¨6Tmðõþ ¿.üÛÚ¿}SÔÞÒ™9yþäYÌ ª)­Ùöø¶Ó_Öê´i7§ýèW?ROvÛù¼¶ßÿîí‡ßn¬jÔëmY¶vº9¯­¢Q£ÃmY¶Ûž½-Ôêjû®– ! öü¿Gÿ_}e}ò¬äÝü¯¾ønh’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Åáp ôz°¡jƒ¶üˆùm‹Y[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$t=¿Ø¢ ôdôÇ@àŸ0k I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶—·öC1~Å_>½M(‹ÅÉ’ï¿!ÞÞ网Òàò²RÅñbQ^ûý—;‰Ô8±ëÄ÷_î:.l±"ÖìѦÑÚÞ—1<ù#Ñúº¨}Yüîn±â-ñÉѾlDn¤-ÀåMˆQáb×q!„h°‹#çÄã·|ÿ¥b×q1'õûËë>)?á?ÖGÄsùa ¶Ÿ‹U¿¶ÿ{O ÛÏÅÚÅÌ_‰{ÄŒgDI•XóbÄR½D¬û°ç1(ŠÐiEH¸i¢H¶ˆcÅß//­ 6ˆ˜¥"î!ñПDc‹»åË6‹%bÙfa}Ddoôî7ià‘¶—§("óJñÙ !„ø2WLNóÒŹÂáñE®ÈúGÚÆ ¯µ/‹?ÿ»øÝ_Ŷœ6²ý€Ø¾\äýVd^)„¯ìïEDˆÈ|VÔ5‹3ëŶGÅão‹3å.GÒÚ.þvTœ.Ó“¾_rçz¡×‰Ó/Š«ÅÁ"±ü wË_ÊãFŠ—²Eѱy‰w¿I´ðHÖøï§iwsƉèabD„8|V,µMbö¸ïW[˜!¢…¢ˆIV‘=Sì<þÖ̑a?|ùÐõ"5N„‹Å3DExv0Ä,›H¹B*êa¿Þ.”Å"èn1ox`ޏz¬B䕊}ùbÃ]"Eüå€BÄ  öº¨Rô"*Üår!„FÞ”÷žxÛœqbÍûâš$¤BˆëlbOžØ“÷öuMB‘>J(ЏP%¶ìõæÞÑÖ.ZÚĉñÞ7"=^!’-"c¬Xþ¦¨okÄÊwDöL¡Q\.BX"D^©78H[OeeÕbÎ?«&⣄½UÌ´}¿$ù ñôbÆ3bÆ3bÉ«â†toîý¹¿ýÝ"ä1÷919A¼”-„Š"¶>*í"áQ1éI‘/ÖýÔÝr!ÄŠ[Ä›{…ù~1ƒ7‡‡#'ÞPå«ïô#æG|´eжxåpü³ŸVI2k I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶i I¶„n à?q äÞ·(¾ÚòÀޯì-$AÚ@¤-$AÚ@¤-$AÚ@¤-$AÚ@¤-$AÚ@¤-$AÚ@¤-$AÚ@¤-$AÚ@¤-$AÚ@¤-$AÚ@¤-$AÚ@¤-$AÚ@¤-$AÚ@¤-$AÚ@¤-$¡8ŸïCQ|½ HÀOEÌŸåÐOxýÎ¥eÑ]ž6”.è-o¦-E /r>h\à!/¤-E Ÿ¢q€‡úž¶ž-EO\öEã÷ú’¶žD-ñÞêüœqÿS¯å9ºè]ÚºRÞâI渠 OÓÖMÔÒð)ç¬Ç'! œ<úÈW]ëp8H ø›çïe“´í1ˆZ WÏ=ê¸K[EQºçB Gmss³Ò“±cÇösË'N|ûí·{u“LJ……u_ž™™Ùyl÷ÝwŸbÊ”)o¼ñF?9¤ôø<ìñ †—ÇÚºš¬õå`ú+88¸®®N½|ûí·7î׿þµB£ù§‚w8mmmz½~†(„â±Ç[µj•zYÆc=6qâÄ.«ùmœþ é3‡ÃÑý‰ª(þøøh€zžµ\“µ…ýƒV«ÕëõêåÐÐP!„Íf[µjÕÌ™3m6ÛÞ½{-Ëž={Ô[8pÀ9Ãúâ‹/Z­V“É»zõj!IJeËNœ8±lÙ2«Õš-„¨­­]ºté¨Q£¢££-ZTYY©ÞöüùóóæÍ3™LãÇß»w¯«A:f0„Ï?ÿ|NNŽzm—qÚl¶µk×Μ93$$dÆŒ%%%kÖ¬1bDttôºuëÞyç &¨7|øá‡õz½÷[¶l™6mšbݺu)))áááV«õ¹çžë<Œ.;ru§œ«éÛ X½lPD­'¶oß¾}ûö¼¼¼ÌÌÌW8uêÔSO=õé§ŸVWWŸüðÃ7zkœ¯¼òÊÆ+**"""233ëêêΜ9³mÛ¶Ç|ôèÑÇŽ«¨¨BìܹÓjµ~þùçê嬬,!D\\ÜÇ\[[ûç?ÿùw¿ûݶmÛ\íÈÕ¤yŠ€þè!m»ÌxÉ K–,‰ŒŒt³‚N§koo?tèP]]]DDÄUW]Õ}ÂÂÂ;vlÚ´)***$$ä…^øðÃkjjòòòrrr~ûÛßÇÇÇ?öØc®ö²nݺ¨øöÛo/;·z(555,,lñâÅÏ>û¬Ñhœ5kVJJJqqqZZÚ®]»JKK«ªª–.]ºsçNÑ)m.\˜ (ʤI“²³³Õk»ïÈÕºÌ74ty¢2q ÀÔõX[‰»Vë~…ÄÄÄ×_ý÷¿ÿý=÷Ü3yòägŸ}öºë®ë²NQQ‘¢(S§Nu.‰ˆˆ()))--ŒŒ4›Íꤤ$W{¹ÿþûÿó?ÿS½sÙq:¿4‹Åyè°Ñh¬««›;wî§Ÿ~ÚÚÚ:gΜ¹sç.^¼¸   ¬¬lÆŒBˆíÛ·¯[·Nsmmíܹs{ܲ«;áê^ .‡ÞrÐ-C»l/ :wOxxxss³z¹óq¥óçÏŸ?~SSÓúõëo¿ýöK—.)ŠÒùhñññŠ¢9r¤Köi4šêêj»Ý®>[VVæjáááqqqŽó²²²²|ðÁ¶¶¶¹s禥¥•——oÙ²eúôé!!!¥¥¥ .üè£æÌ™£(ÊO<‘ŸŸßãŽ\Ý©A§Ç7–€!âŸHRM0yòä÷ß_ÑÜܼaÃuannî®]»ìv{HHHtt´ó¤‹%//O½ûCâOx¥ûÁ³¶Ô¤áê6 7Îk >Ò’ m Ò’ m ‰žÓ–7•÷hâĉo¿ýv mÊCS¦Lyã7ܯãÿQùO`†¦ÒVÖ~9ŽÖÖÖ…§|7ÚÇ{lÚ´i¾Ør€“õ‰ ºsy@Â`Ÿ÷²Ùl«V­š9s¦ÍfÛ»wommíÒ¥KG½hÑ¢ÊÊJuµ_|ÑjµšL¦ØØØÕ«W« {\yÙ²e'NœX¶l™ÕjÍÎÎî²;WÛ·Ùl¿üå/gÏž=~üø)S¦=z´ÇMuí¢E‹®¾újç–÷íÛ7lذ†††îwð‰'ž˜={öÔ©Sg̘qìØ1uyiié‚ bbbâââzè¡ÆÆFuùóÏ?Ÿ““Ó«Q Rƒý© úLé2§%Í7Øl6½^¿{÷îÈÈH!Ä-·Ü¢×ëÿøÇ?ÆG}´¤¤äƒ>8uêÔäÉ“:4vìØšššÓ§O_uÕU®VBLœ8ññÇ_´hQ÷ݹº‰Íf ÿä“OL&Óo~ó›;v|ñÅÝ7Õy´UUU#GŽüæ›oRSS…÷ÝwŸ¢(ÿû¿ÿÛýj4š¯¾úÊd2½þúë«V­:uê”Á`˜>}ºÕjÝ´iSCCÃwÜ‘žž¾qãF!Ä”)S}ôÑŸþô§žj’æ9 ŸFæ:7×)J×ð\–,Y¢vmaaáŽ;.^¼%„xá…L&SMMN§koo?tèЈ#"""Ô®uµrDD„«¹¿É<`2™„·Þzë3Ï÷yÙí»Ò}S³læÌ™Ã‡ÿàƒ^}õÕŸýìg®6rúôiõB[[ÛÙ³gGŽ×ÐÐPQQ¡ÖmQQ‘Á`pVlF5ˆ ê_ÀWô2ÝCv°GØ1cn¸á†û´´TQQQ±uëV!Dnnî®]»ìv{HHHtt´^¯w³²Âb±äååy¾}7\mÊéþûïÿÕ¯~õõ×_ßu×]®ÖÙ´iÓñãÇ[[[Ÿ}öÙÌÌÌää䌌ŒåË—×××_¼xqåÊ•ÙÙÙžëeG°º?Eéïc ?zŽùêö­·ÞŠ>}zxxxFFÆž={„MMMO<ñDLLÌðáÃ_~ùå­[·ªw³Ç•…+V¬xóÍ7Õca=Ù¾n6¥ÊÎÎ>yòä-·Üâ<º »¥K—Þ{q‘‘ýë_ßÿ}ƒÁ (ÊÖ­[&Mš”žž¾nÝ:Ï¿K—U`¢k€ÊÝÁ=æ,Ñàííí#GŽ|íµ×n¼ñÆW°ÙlkÖ¬¹í¶Ûü<°€ÂS0hp†¿p÷§êAQ”Á>ƒ;(¼üòËóæÍè(WÏCº€¡ì2o#SC¡{C¨KÈ1›ÍF£qË–-ƒú}]>âê7+žàògHB8Ž{‚Àõ‘ªªªË®“››ë‡‘7.àI„‡i+\Oßv^H^ÀÜó8yš¶*7+h\xÕeéæiºè]ÚªÜn÷«HxÂó·'òŒ=êKÚª.¸NüAªþŸ[ƒg p£ïi«r¦FŸ«…S‰á²(Zà‰þ¦­Sçø VÑä,è-¯¥mg]¢„Ò…'hYÐO>IÛ.Ü' á;t¯À§ü‘¶îõ˜;ª6øhw˜ñÑ–=Ô9åI=/âs\ Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’ m Ò’Ð ô$§(J¯®u8¾€Ì˜µõ­^¥*] Ф-$AÚúœ‡s±LÙôi I¶þpÙY¦lú´€$H[?q3/Ë”-€W¶ië?=ÎÎ2e à-¤-$AÚúU—9Z¦l¼ˆ´€$H[¿Ú½{÷gŸ}¦^þì³ÏvïÞ= ÃŠn 0$tNØÙ³g;/t®ÛÌÌL @.¤­]vR633Ó¹ €W(Š2ÐCð¯Åxê E¤­÷õX´®‚Õ¹œÆ8D½Åÿ“P ¹– º<(~+]ÒÖkzU´nÖ¤qðQ;X¨”—´í¯~­›ÛÒ¸šxžÃÌñƒ¨Œü¸¤my½hÝlÆõÐùóçËÊʦNª~YTTTTT4mÚ´ÐÐP!DCCÃ7ß|sÍ5×  '''111**ªŸÛ9pà@|||LLŒWF’¹lÔrÚø@àæaòià’¶½ã‡¢u³}×=³Ù|úôé–––   !DUU•Ñh¬ªªRÓV½ày×:¦  ¸ùo™œ 4‘8.ië‘)Z7{¤q{¦×ë«««cbbÚÛÛëëë“““+++GŽ)„¨®®6›ÍêšçÏŸ/--µÛíz½þŠ+®=z´º<'''::ººººµµ599ùÔ©SW\qEeee]]]xxø¸qã.^¼X\\ìp8âããGÕ} lll MII1Bˆ–––üüüêêjF•˜˜¨Õj]-ÏÏÏohhÈÏÏ?sæŒÉd²Ùl~úö@`sÕµDmàS#WëÝG´u'@ŠÖÍhÜ.L&“š¶555áááÇ/((B8Žêêê””u5ƒÁžž\__ÿ÷¿ÿ=444::Z½ª²²râĉz½^ý²´´455588øøñã‡މ‰¹úê«ëêêŽ9Òe.\HKK ={öìÑ£G§M›¦ÑhŽ;œ‘‘ÑÞÞ~ìØ±Ó§O''' !z\ž””TSSà àDÔÊÁUàz·nIÛlÑvGãva6›ÏŸ?/„¨ªª2™Lz½>((¨¾¾Þáp´··;gmÕf±XªªªœiëìZ!ÄÈ‘#Õ™×#Fäçç[­VEQL&Shhh}}}÷´U×=zô… ª««ƒƒƒkkkÓÒÒ´Z­V«MHH8zôhRRRSSSË9 :ëñE¢vðê1p½xpiûƒîE;ˆêÆU™ÍæS§NÙíöêêê±cÇ !L&SUU•Ãá Óé¾ÂWVVž?¾¹¹YQ”¶¶6gò !ºŒëüR«Õ9µZm{{{÷«E1 å‘SÇ IDATv»]Q­VëÌ厎ŽÖÖV»ÝÞãrõ@a€è©k‰Z9¸ Üþ?¾¤íà.Úî†xㆄ„ †ŠŠŠÆÆÆððp!„Éd*--U/¨ë´´´?~<==]-Ú3gÎ455ykÍÍÍê‡Ãa·Û ƒÁ`hooommU+¶¹¹Y£ÑèõzW˽5ìèZéuÇvÿëv覭dEÛÝm\³Ù|îܹaÆi4!„ÉdÊÍÍBÄÅÅ©+´µµ !„v»½¼¼\`¯¸pá‚z î¹sçÔC4Ͱaà ’““ÛÛÛ -‹¢(¡¡¡=.B566zkH0ѵC„×ÏG4äÒVú¢ín¨5®Ùl.++s†¬^¯nllŒˆˆP—„††Z­Öƒét:³Ù¬Æ®WÄÆÆæææ644Æ´´45¯SSS öï߯(JTTÔ˜1cÔ•]-ÏËË+..6›Í©©©Þ ^t­ÄºÔm?'n½|ÂoÙPµÁ»œpdB—%Uu¼úæÁ¾Ç  >3y6Â<[äÖe/0[Þå­]òYÛÀ)Ú€2Ôæqƒ];4ykîVδ¥h=Dã];¤xå¸[©Ò–¢í38·7œú6q+CÚR´^DãS¶CPÿ'nqÚR´>Eãü,Þi€Ò‡‰[†â;ŽLPÿ9—dþÃÀ JfÝ¿½»ÿaÀÆø×áÇ ý³¯”——ûg_zeíÚµãÇw~ùôÓO+ŠròäIõË£G*ŠráÂß 33SQEQôzýرcׯ_ßçMMœ8ñí·ßöâØ¼h¨|ds´Žy\@V^?e:Ðÿ$ÌÊÊúùÏ^^^#„عsgjjê®]»®¼òJ!Ä®]»l6[ll¬'›r8mmm}øÊ'Ÿ|ò™gžimmýì³Ïn¿ýöÔÔÔ믿¾·\z;qè³¶ÌÑ æq1”}õÕW555ê庺º/¿üR½œ““sþüùC‡}ñŇ²ÛíçÎûꫯöîÝ{þüyç:gΜ9|øð·ß~{èС†††.ÏÏÏohhÈÏÏß¿¿ú)zêçBïÝ»wß¾}ùùùííí]nR^^~àÀçÍ?ÿüsu‹/~ûí·BˆóçÏçää|ùå—û÷ï?{ö¬ó†999………‡ÊÉÉ©©©ñdü€ßæÑ&LˆŠŠÚµk—¢¡¡áÈ‘#?þ¸ú¥b×®]sæÌQ/¯[·.%%%<<Üjµ>÷ÜsÎ-Øl¶U«VÍœ9Óf³íÝ»×f³­]»væÌ™!!!3fÌ())Y³f͈#¢££×­[×ãEÑét!!!7ÝtSrrò±cÇÔ奥¥ ,ˆ‰‰‰‹‹{衇œiÙãòeË–8qbÙ²eV«5;;Û7ß­~éÏ @gm™£ÜÌã 2 =¥¥¥©©©ÁÁÁÇ?|øpLLÌÕW_]WWwäÈõã—…•••W]u•N§+++;zôè´iÓÔ¬S%%%ÕÔÔÄÇÇ«sBBˆcÇŽgdd´··;vìôéÓÉÉÉwj6›Ož<ÙÚÚª×ë«««ƒƒƒ«««###«««Íf³Â`0¤§§×××ÿýï ŽŽVo[YY9qâD缑'ã|$ð§l…Š¢dff~öÙg‹-úòË/'Ožþøc«Õzøðáo¼1%%åÎ;ïT¯Ú¾}ûîÝ»###Õ/_yå•wß}wôèÑ .ÌÌÌ\¸pá™3g¾ýöÛ¹sçÞvÛm‰‰‰=ŽDµ=}úôôéÓÕ%wÞy§Õj=}útCCÃwܱ|ùò7ºZþÒK/}ùå—?þø¢E‹|û-ó’^MÜÖ¬m÷É?æh…&¦r1ÔŒ9Òh4jµÚ#F´¶¶Z­V­Vk2™BCCëëëÕubccu:Âb±8Žêêj7lll¬­­MJJÒjµAAA eee]þ×ëõF£±ªªª¥¥¥µµ566¶ªªJQUU¥¦mLLLpp°",,Ìb±¨×:ÓùŒðƒÀœ²Ueee©Ó´êmttôˆ#>|ðàÁÚÚÚÙ³g««-\¸0!!AQ”I“&eggïܹӹ…%K–8»VñÐC¥¦¦†……-^¼¸¢¢âÙgŸ5³fÍJII9tèP÷üú׿V%((hÞ¼y<ðÀÕW_-„ÈËËÛ·o߆ ÂÃÃ-ËêÕ«7oÞÜÑÑáj¹o¿G^2¸?ŒÏ}•F÷y\Á!¹2 ƒzA-Qç,”V«uHä\?((Èn·»Ù Ýn×jµÎú éèèhmmí¼!„Ùl®ªªr8f³YÄmjjjii‰ˆˆBTVVž?¾¹¹YQ”¶¶6µw» Øóñ½²{÷nÉþçÏÊÊZºtéùóçwîÜ©¾‹+33sçÎ'Ntþ|mß¾}ݺuEEEŠ¢ÔÖÖÎ;×¹….ã:¿4‹Åùg£ÑXWW×}¿øÅ/V¯^ÝÑÑqêÔ©ÿøÇ+W®\½zuqq±ÑhtþA&11±¹¹¹²²ÒÕrçß…¤4iKÑJŒÆEwr¼ÈiµZçœGkkkooÞÔÔ¤^p8ÍÍÍ]â² ƒÁÐÞÞ®l „hnnÖh4Ýßwb6›O:¥¦mXXXkkëÅ‹‡ ¦ÑhÔCuÓÓÓÕWÜ3gÎ8ø‡ú?¿?ûª¤¤¤Q£F½÷Þ{§NRgL333_}õU‡Ã‘••¥®SZZºpáÂ>úhΜ9Š¢<ñÄùùùÎ-xåÐ Fc³Ùn¿ýömÛ¶­^½:..®¡¡¡¢¢B­Ø¢¢"ƒÁåj¹º…þ#0 @ÚR´C ‹Î$x‘ ¿té’Ùlîèè(..îíÍKKK£¢¢BCCÏž=«ÑhL&S—‚‚‚œïÿ 6lXAAArrr{{{aa¡Åbéþºa·Û+++„&“©¸¸xÔ¨QBˆ¶¶6!DXX˜Ân·———‡‡‡÷þNý%ÁϾӜ9sÖ¬YsÍ5ר?¹îºëî½÷^‡Ãñ裪+¨³­éééê¹À¶lÙ2uêToí]=µBGGGAAÁ{ï½—žž.„HNNÎÈÈX¾|ùÿüÏÿ444¬\¹2;;[£Ñ¸Z.„°X,yyyÞU@ñ_Ú–¢=|ø°zô›¢(ÁÁÁ#GŽŒ‹‹ëÛ¦8Ðùí ¾ÖÑÑqæÌ™ÊÊÊ–––ðððääd£ÑèŸ]{‚Æ…Ó ~‘KLLqŸ——W\\l6›SSSSSS öï߯(JTTÔ˜1cºoS«Õ6¬µµU6›Íåååê4mhh¨Õj=xð`PPN§3›ÍjìÂÕÏþàú¤†¬¬¬Í›7?òÈ#ê—ÑÑÑñññ§Nš9s¦º$99ùé§Ÿž1cFtttddä 7ÜÐù÷~zî¹çž{î9F3bĈyóæ­]»V¡(ÊÖ­[~øá„„½^Ûm·½ð n– !V¬Xqÿý÷¯_¿>++këÖ­Þžwu>/¡çï$ëˇóöÊ`)Z§Ã‡GDDX­V‡ÃQUUuüøñ´´´ÎG§y®Ç´õÝp[[[qq±ÅbÑét¹¹¹---W]u•·ïu=¾Ã,ÀŸèË>⛼°X,}þ-×)'''11Qýk ú)`Ÿ-èÌÍ;‰;?vƒ+máO}xnøjÖvÐmê§}DFF†„„444¨iÛÒÒ’ŸŸ_]]­Ñh¢¢¢µZ­«åÎóSž9sÆd2Ùl¶î{Ù¿¿Éd ¿xñ¢3Ckkk92}út­V›““U[[ÛÞÞ®þeAˆmkk;sæÌ¥K—:::ÌfsRR’^¯×étV«UÝHXXØwß}çŸïUŸ1 ðÒÑÑQSSÓÐÐ0lذ •ÿÙÇàåå´ìEÛ™:kÛÔÔä|Isu‚É—w??ewBˆ¶¶6õ„sj¶–––ÆÄĨÑ,\œóäɓТL™2E«Õäææ¦¥¥97{éÒ¥’’’Îàh\ìIârsskjj¬V+i;ìóPb|ÏáuÞI[™ŠVqöìYçgöÄÅÅ©/iê &ÓÒÒ´Z­V«MHH8zôhRRRSSSË= ¤N§‹ŽŽ.++3fL{{{yyù„ ?|bEç³`VWW‡††^ºtiÆŒê¥÷ìÙÓÖÖ¦®V__òäÉñãÇ«çý\Ü7.àãÆóâÖ¦M›æÅ­Aðÿƒu0 y'm333»üÿ2¨ÿÐ0zôè„„‡ÃÑÔÔtâĉ„„W'˜ôðÄ“îÅÆÆ?~<11±¢¢"88¸óüP÷³`j4EQÔÐTét:»Ý®¦íwß}Ñým׃¯UÄ }Í dîÿ?ç_ðÚ òýMYQ”ÐÐШ¨¨ŠŠŠ„„W'˜ôðÄ“îEDDètºK—.•––Z,–ÎWu? ¦ú&è)S¦¨-Û…ÑhìíÞ„dsÿèî²/rüVƒÞâ‰Aоãý·‘ÉѸêçA755UTT¨§„tu‚I7'žì|~Ê˺âŠ+ŠŠŠ»#Ûý,˜Æl6çåå%%%µ¶¶VWW;?kdн·”¢80tðó_óáymoãªÇÚ*Š¢×ë‡î<‘¤«LºZÞåü”Ýw´gÏçUê¡´‘‘‘]æ\{< æ¸q㊊Š<¨ùéLÛêêêÆÆÆ+®¸Â7߯¡h!õA÷Ö)º¼xfkÿœ$ûÛo¿‹‹1bÄ€R ÌŸw?˜8qâã?¾hÑ"¿íqÊ”)>úèOúÓ€•ßøã#WãNœ8ÑÕUƒ¡ÇBuµÜd2©ŸÂçʵ×^뼬Óét:]÷$ í~zZN7vìØ±cÇvßf E »·t>¥y?5Jý#à]ü¼÷Hý\1_CøØc¹‰éùü#z4”ÏÕïêäÃ.\(..ž:ujç¤9Á;E áÁ»Käí§999‹¥²²²±±1444%%E=1_oÏl}áÂN§Õj»ŸÙºÇSS«»Ž‰‰©®®nmmU?#Þh4vßTNNNtt´ºšÑh´Ûí½:1¶«;ÒyÖÖÑø÷‘ù'òlWtùõ,¬«­­]±bÅ|ÐÜÜœ••õßÿýßÎ×h›Í¶hÑ¢Ï?ÿ\}Gøk¯½–––¶lÙ²M›6EDDÆë®»nóæÍ6›mÁ‚»wï.//?~|qqñ×_­naß¾}óæÍ+--íòa¢6›íöÛoß¿}}}PPЦM›ÔcKKK~øáÏ?ÿ<((è¶Ûn{þùçCCCÅ?ÏÚz8*¿~=Ö·Ïòðßív6¸æqý`Ïž=Z­öÊ+¯ôÖìK Ê¿À GƒèÑ¿páBZZšzŒ»ó|Ò^<³µ›SS_ºti„ :îܹs§Nš4iR›ª¬¬œ8q¢^¯okkûꫯzublWw¤ GôŸÿøàk‹/Öëõ‡2>úè=÷ÜóÁ8¯Ý±cÇ'Ÿ|b2™~ó›ß<øàƒ_|ñÅK/½ôå—_vùÓÿöíÛwïÞYUU5räÈãÇ«û}å•W~üãwéZÕ_þò—¯¾úÊd2½þúë7ß|ó©S§ ÃwÞiµZÕSãßqÇË—/߸qc÷Ûz8*itýør?ËìĹp÷? ذüîÚk¯½æškºŸ±kÚ´iƒnʶLJ¯û£ ²ØØX£Ñ¨(ÊèÑ£;::ÔCØkkk“’’´ZmPPPBBBYY™ÃápµÜÍÆ›››/]º”’’¢×ë5Mbbâ¥K—ÚÚÚœ»VO~UWWçf„êD¯óÄØBõÄØkê|bl‡ÃáæŽô¸ OF ………;vìØ´iSTTTHHÈ /¼ðá‡ÖÔÔ8WxàÔ—ò[o½õÀ®¶³dÉ’ÈÈH!„Ùlž?þ«¯¾*„hhhxçw~ö³Ÿõxç–ï¾ûîöööÝ»wçååíÛ·oÆ ááá‹eõêÕ›7oîèèps[÷£’ÆÀÌÚö¨ûTîPžÇt˜£…L‚ƒƒÕ Š¢ »Ý®(Š·ÎlÝÜÜìæÔÔÎMi4šŽŽW³YêIU½:1¶«;Ò}ÀŽ:ŠŠŠE™:uªsIDDDII‰ó3’œ³Q!!!MMMÎOSê"66ÖyùþûïŸ?þš5kÞ}÷ÝQ£F©SÚ]çƒZ,–’’Ng4o"OLLlnn®¬¬ìþGG%@¼o™™™ª6!&ùþC¹hÜ€EÑBJÍÍÍê‡Ãa·ÛÕóI{ëÌÖîOMݽ=1vÿOÅ ø”¢ Ì.+>>^Q”#GŽôêó>ÕSuÖù·Ä™3g>üƒ>xõÕW]MÙ !NŸ>­^hkk;{öìÈ‘#ãââ***Ôº-**2 žÿ¥·û¨MŸ—è;vdÂõŸsÉ}zxxxFFÆž={.{“+V¼ùæ›êaµ=®}òäÉ[n¹ÅytAwK—.½÷Þ{###ÿú׿¾ÿþûƒAQ”­[·666&$$Lš4)==}ݺužß‘ËŽjð Ð9õ€7œÇ*8 –´êÛ™,GÀ?8SŸ9Ž}ûöÙl¶áÇ;JsöÀñl‘Ï :˜wµ··9òµ×^»ñÆ{\Áf³­Y³æ¶ÛnóóÀPb)µõ„s—ãq}‡¢‹ÒÒRNg6›z @ß Ù·*¾üòËóæÍèHb°¦­ëu-0¸Hybl `ßLæ]f³Ùh4nÙ²%ðß×å7ýü¯lЧ­ÛO-0HuþÈîΦM›æç‘ýÔeâv(ÔmUUÕe×ÉÍÍõÃHDÿK‘'mhÜ^¡hcÈ–€îúö‹„iëDãºAÑßP˜¸…“W~«‘9mh\'Šà†àa Þ;EÆH[§#Žz¤HÛ~éUãz>qKÑàŠû×Ó<<<ç»ß@H[ïèópFøüv H€ž;cCÕmùó#>Ú²+]ÊuöìÙÎËŸ}öYç«(Zú‰Ì ™ÌÚú\—yÜÏ>û¬sÝ Šï Ì9;!„ØâQs+‹¸ìxÓ³-ÿ$Pïò@ mýGMØÎ¿Mú'jkjjÎ;WSSãp8‚ƒƒ£¢¢âããµZ­«õ¿ýöÛ¸¸¸#FtY^__èС™3gúx¼}DÚJ®²²òĉqqqcÆŒ1 MMM%%%õõõ=4/#meæp8òóóGŽ™˜˜¨. KIIQ/·´´äççWWWk4š¨¨¨ÄÄÄîS¹v»=//¯¶¶Ö`0ÄÆÆúuô½¤èÀ‡ìv{÷C TÇŽS%##còäÉuuu§OŸî¾ÎñãÇ ÃôéÓÓÒÒ.\¸àãñô i+³ÖÖV!„Á`è~UcccmmmRR’V« JHH(++ër轺Θ1c4Mppp||¼ŸÆ Ð'¤­Ìôz½Ân·w¿Ên·kµZu!DHHHGG‡šÂ×Ñëõ:ιŽÇ Ð/¤­ÌŒF£Á`¸xñb÷« C{{»³e›››5³të´µµutt¨_¶´´øzÀýAÚÊLQ”¤¤¤’’’¦¦¦ŽŽŽ†††S§NÕÔÔ„††6¬   ½½½¥¥¥°°Ðb±t9ÍuhhhXXXqq±¢££C½°8C‚䢢¢&L˜pöìÙ’’õ¼¶#FŒ B¤¦¦ìß¿_Q”¨¨¨1cÆt¿yjjj^^^yy¹V«>|x]]ßH[ùEDD¤§§w_n0RSS»/Ÿ}ÚÍò¤¤$£Ñ˜”””‘‘A×€ÀDÚÊ/66Öh4*Š2zô莎Žêêj!DcccmmmRR’V« JHH(++s8®–ô¸<ÒV~ÁÁÁêEQ ƒÝnBØív­V«×ëÕ«BBB:::Z[[]-‘ô i+¿ææfõ‚Ãá°ÛíƒAa0ÚÛÛÍÚÜܬÑhôz½«å2r€^!måwáÂ…ÆÆF‡ÃqîÜ9EQL&“"44tذaííí---………‹EQWË…AAA}o\â ò‹ÍÍÍmhh0iiiÍ÷¿Ï¤¦¦ìß¿_Q”¨¨¨1cƸ_Ÿ——W\\l6›SSSæÎ¸FÚJnÚ´iBˆøøøîW † ÕÕr“ÉtõÕW{}„Þ i I¶i I¶i I¶i I¶i I¶i I¶i I¶„n  9EQzu­ÃáðåpdƬ­o‘ª~CÚ: ?8 Áç‡ûÃÀФ,îݵŽ7}7I0k(˜²`¨éUªÒµž mýlðÒ6 о MÎÅ2eë!ÒÖOˆW_#mÕ ÀPvÙY¦l=GÚú àS¤í£w€›yY¦l{…´õ+BÀwHÛDéU³³LÙöiëoä,€(^)->H¾Æ¯€Ám‹G±ÔùÃu=²ý /‘? m18¶0xÑ ð5g'p@$AÚ@:¯o‘?Ã[øèï§-€+LÁ[zœã€H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H‚´€$H[H"ÐÓ633såÊ•—ÄÅŽñÆ}ÞàáÇÃÂÂú=®Þ™2eÊeÇÜy‰'¾ýöÛ}»¹'+÷¨;`Ú»wïÍ7ß<|øp£Ñ˜––¶råʆ†!Dff¦¢(Š¢„‡‡_sÍ5»víR׋‹ûÓŸþä¼y[[›¢(»wïî²Ù^½d÷çåÞÃõ{$÷+~ §m?9ŽÖÖÖßøc=6mÚ´>¯ãÉÍû¶²¶@ ù¿ÿû¿¬¬¬ &ìÛ·¯¼¼ü7Þ(//?räˆzí“O>ÙÚÚzîܹ3füèG?ºté’ç[îÏ+~o_yyÅïÑàNÛuëÖ¥¤¤„‡‡[­Öçž{ιÜf³­ZµjæÌ™6›mïÞ½çÏŸŸ7ožÉd?~üÞ½{ÕuÞyç &¨—~øa½^_WW'„زe‹ú{¸ñÚÚÚ¥K—Ž5*::zÑ¢E•••ÝÇùüóÏçää8oþË_þröìÙãÇŸ2eÊÑ£G»¬³lÙ²'N,[¶Ìjµfggw¹¹«Qõ¸¯_|ÑjµšÙ ‹ IDATL¦ØØØÕ«W»Ù‚û–––.X° &&&..jllt_X>øàƒ>øÜsÏ¥¤¤Æ &üñ¼æškÔEÑétf³ùç?ÿy}}}nn®çw¾zºy‰T×éç˽àß…Á¶qqqüqmmíŸÿüçßýîwÛ¶ms^µ}ûöíÛ·çååeff.X° ..®¬¬ìÃ?ܸq£ºÂìÙ³;VQQ!„عs§ÕjýüóÏÕËYYYžo|ñâÅ/^üðÚš÷÷è0™LBˆ[o½õÀ½ún¸U:®½½ýСCuuuW]uUo· ÊËËÛ·o߆ ÂÃÃ-ËêÕ«7oÞÜÑÑÑÿû€ÿ©³Z#GŽtµÂúõë-KXXØúõë_ýõ#FômGþy¹¼âÿ³A¶÷ßÿáNbbbœWmß¾}Ö¬Yñññ£Gþãÿ¨>YU±±±ê…âââÈÈH³Ù¬~™””ä\gîܹŸ~úéÎ;çÌ™£^.(((++›1c†‡/**ReêÔ©V«Õjµ¦§§GDD”””¸¿GQQQê…¦¦¦¶¶6Ï¿nFÕEbbâ믿þ‡?üÁb±Ìš5K“îÕTÅÅÅF£1::Ú¹Ùææfçqý¹/øŸúŠææÅZ ²²²³gÏ.Z´H]¨×ë;¿Á¦¥¥E]èfGþy¹¼âÿ3Ý@àòÂÃÃãââœ_jµZõBiiéÂ… ?úè£9sæ(ŠòÄOäçç;WsþYaäÈ‘ÕÕÕv»Ý`0!ÊÊÊœëdee=øàƒmmmsçÎMKK+//ß²eËôéÓCBB<Üx||¼¢(Gމˆˆðâ]Öhzþ•Ãý¨º›?þüù󛚚֯_ûí·_ºt©¬¬ÌÕ\í4..®¡¡¡¢¢B}® çó€ÁeüøñêÙ–&NœØy¹ÃáP_ßF£Åbér+«ÕÚù5·  @‘П‘xëå^ðŠßÉ ˜µuE}×Wzzº¢(.\زeK«Ùl¶I“&½øâ‹B»Ý¾aÃçU³fÍ*..~ï½÷²²²E™={öÚµkÕ£<Üø˜1cn¸á†ûî»O=L¢¢¢bëÖ­ý¿k‹%//¯ûrG¥ÊÍÍݵk—Ýn ‰ŽŽV³t³W;MNNÎÈÈX¾|y}}ýÅ‹W®\™íê§€§Ñh~ÿûßÿþ÷¿ꩧΜ9c·Û?þoÿöoûöýöî<ª©+ñø}IX²–Bd  €ˆì8 U±ö8c{ªu¤Tt Ói+V9µ[jV;GG;£XöŒV§Êq›3ôˆµvœS×QËüü¡Hd0,AY!Ûïwúš !„=Äïç¯ä½ûî½ïáËÍ}÷å[8*==ýèÑ£ßÿ½J¥ª®®Þ´iÓ /¼À|‹;2còëžà7þšbÝ5´mÛ¶ÄÄÄÄÄÄŒŒŒ%K– VòïÿûåË—£££Ÿþù矞ÙÎçóããã¥R©!dñâÅtë+?}ú´L&›7ožP(Œ¿yóæèO-++ëäÉ“®®®ÉÉÉ#;eBHooïæÍ›=<<ÜÜÜŽ9’››KQ”…k”¢¨ÜÜ\•Jåïï¾wïÞÑŸ#ÀdY¶lÙ¥K— bbbÜÜÜV¯^íëëk2ˆk"--íøÃûï¿/‹.\èãã3dâÒ˜üº'øÿŸ(ƒÁ0µÝT8&|®ì~žÃx0û¹šÂ£¶ÆmÀN Ú€@´;h vÑìÄ3moݺõÒK/¹¹¹ñùü9sælÙ²¥§§‡’””DQEQB¡0!!áÊ•+tyooïcÇŽ1‡kµZŠ¢®]»fRmllì‰',7m\&22òÌ™3#>Üšòf ]€©Èþ£í7ß|³xñ∈ˆüüü–––'N´´´Ñ{?þøcFóèÑ£ÄÄÄåË—·µµY_ó‡~8wîÜ—±æðÑ”ïzlG[½^¿nݺuëÖíܹ388˜ÏçGDD>|8!!.@Q‡ÃquuÝ´iSwwwYY™õ•ïÙ³çöíÛôëO?ýtÑ¢Eaaa±±±÷ïß7)“™™YZZš™™)—ËÓÒÒLß»wopp°P(”Ëå;wî²¹}ûöÉår™L¶cÇ •XhW¡P¼úê«ÞÞÞëׯW©TL[ƒ€-³óh[\\ÜÐÐð›ßüÆd»ñã+h§OŸvpp˜1cƈۺpáÂÙ³g‹‹‹_}õÕuëÖ™ì=pà@hhèjkk?n²×ÛÛûâÅ‹gÏžýüóÏ¿þúk UTTlݺõÒ¥Kííí}ú`²³³¥R©@ ÈÎÎÎÉÉñôôq[kÖ¬qqq!„,[¶¬  `XǦ¤¤øûûS•––vùòe …9ŽN§+,,ìêê‰DÑÑÑ#¨¤¼¼L'òÁäää|ñÅR©tÁ‚ׯ_A% |>Ÿ¾>t}}}J¥rLN`RØC´MOO7üÄdWXX˜··÷À˜’|>Ÿµ5Þ+—Ë>|ȼ­¬¬$„øûû²Ÿ,–ù«­P(RRR¶mÛVWWWWW—‘‘1ðDL$''_½zU©T.]ºtÅŠƒÁB%fÛõööîééaâomm­““g¦"{ˆ¶°X¬ƒuê”åzÊÊÊ®\¹¢V«¹\®D"¡‡“-Tb¶Ý   øøø7vww777oÙ²%--m°ð 0%Ø”Y¶lÙ¥K— bbbÜÜÜV¯^íëëiá´´´?üáï¿ÿ¾X,^¸p¡ÏqÓYYY'OžtuuMNN6Þ´mÛ¶ÄÄÄÄÄÄŒŒŒ%K–X®§··wóæÍnnnGŽÉÍÍ¥(ÊB%fÛ¥(*77W¥RùûûGEE…‡‡ïÝ»wôç0‰¨!¿û¶ª£I®cR!Áç À^àç9Œ³Ÿ+ûµ€g¢-Ø D[°ˆ¶`'mÀN Ú€˜ªÑ6))‰~²®P(LHH¸rå ½=66và³ÇLDFFž9s†y[TTîáá±|ùòñë°5cʘôpXÇZYÞ¬´ `;¦j´%„|üñÇæÑ£G‰‰‰Ë—/okkY=Gˆˆhii9wîœ5å ƒF£n+~øáܹsGVÆšcGS~¼ë˜S8ÚRÅáp\]]7mÚÔÝÝ]VVfR`ïÞ½ÁÁÁB¡P.—ïܹ“Þ˜™™YZZš™™)—ËÓÒÒ~÷»ß}õÕWß|ó\.ÿë_ÿJQ(¯¾úª‡‡‡··÷úõëU*}`HHÈ'Ÿ|2þü[·n…„„üùÏž?>—ËMLLlllܽ{·§§§D"1ûX¯={öܾ}›©êÓO?]´hQXXXllìýû÷˘ôÐäX³'e¡­}ûöÉår™L¶cÇ믌I=.‹Ùs˜xœÉîÀ8}ú´ƒƒÃŒ3L¶{{{_¼xQ.—ß»woéÒ¥ÁÁÁ+W®úè£U«VÑÅ(ŠrqqùÓŸþD¿]¹r¥\.¯ªªêééùõ¯½qãÆ¿üå/ô®¼¼¼k×®¹»»Óo=ú÷¿ÿÝÏÏ/%%%)))%%¥ººúÎ;/¼ðÂ+¯¼`¡Ï.\øþûï]\\þøÇ?®[·î_ÿú³k`‡<©ÁZ©¨¨ØºukaaáŒ3:::ªªª†ueŒY¸,Î`"MáQÛììl©T*²³³srr<==M ¤¤¤øûûS•––vùòå!ë,//ÏÏÏß¿¿P(”J¥;vì8~ü¸^¯§÷fdd0¹–²~ýúÙ³g ‚ÔÔÔÖÖÖíÛ·óùü ZnhÍš5...„eË–XÖÃ:)‡£Óé »ººD"Qttô*!C]–Ÿ ÀزÝh{ìØ1ê'f ¼ýöÛ÷îÝkjjª««3;И——·`Á___??¿Ã‡·¶¶ÙhCCŸÏ—H$ôÛ€€€¾¾>¥RI¿•ÉdÆ…™·|>_*•²X,æmWW—å†Äb1ý‚ËåöööjµÚ!û6‚“ ÈÉÉùâ‹/¤Ré‚ ®_¿>‚JÈP—eÄçÏ `Œ˜ý€Ùn´MOO7üÄl:P ³{ EJJʶmÛêêêêêê222˜z˜ :··wOOõjkkœœ˜è6ØEsƒõÐÂI &99ùêÕ«J¥réÒ¥+V¬0 #¸2–/ €°Ýh;Jô¸ixx8EQ?>uê³K*•–——›=*(((>>~ãÆÝÝÝÍÍÍ[¶lIKK³…ÇÉ`=´pRf•••]¹rE­Vs¹\‰Dâàà`¹’ÁÚµ‘Ë`™Ý¦“   mÛ¶%&&&&&fdd,Y²„Ù•••uòäIWW×ääd“£(ŠÊÍÍU©TþþþQQQáááf—;oƒõÐÂI™ÕÛÛ»yóf77·#GŽäææR5‚+c#—À2jÈo´­ªÅè›ú1©€àsöä”UÓ©ÔŸ_NZWóáWäÏìvÔž5ˆ¶`'mÀN Ú€@´;h v£í|@QÔwß}7ÜCBBòòòn=qâý:22òÌ™3#ëØh޵Ü+k¶›-`Ò¥!5)cMy³FÐ.Àx³¹hÛßßüøñˆˆˆ#GŽ˜-`04ͰêüðÃçÎ;½žt•XÑ[ †{¦cue&ë ³¹h{îÜ9ƒÁðå—_ž?¾©©‰ÙòÉ'ŸÌŸ??$$äÖ­[íííï¾û®ŸŸß´iÓ¢££™ÇÃÖÔÔ,\¸ÇãÅÄÄÜ¿ŸÞ¸gÏžÛ·oB233KKK333åryZZ!¤³³síÚµ>>>‰dÕªUJ¥’>d`ý•J¥7oޤ˳]Ý»wopp°P(”Ëå;wîò 0½ ùôÓO-ZkÍé0»!Ö´k\~ß¾}r¹ÜÅÅE&“íØ±ÃB%–ÛU(¯¾úª‡‡‡··÷úõëU*sYÌžÀX±¹h{øðá×^{-...((èØ±cÆ»òòòòòòÊËË“’’V¯^]WW—ŸŸßÞÞ~üøq¡PH—9tèÐþýûÛÚÚâãã×­[gRùBCC8P[[{üøqBHjjjsssaaá£GD"Qzz:]r`ýµÀ¸«ÞÞÞ/^ììì<{öìçŸþõ×_[5.\¸pöìÙâââW_}ÕšÓ16¬v+**¶nÝzéÒ¥ööö¼øâ‹*±ÜîÊ•+ªªª îÞ½»qãF+O`”l+ÚVWW_¾|ùõ×_'„¼þúëGŽ1~¼jFF†»»;]ìâÅ‹_~ù¥L&c±XsæÌ‘Édt™ÌÌÌÈÈH.—»víÚ‚‚ËÍÕÔÔ\¸páСCb±˜Ëå~öÙgß}÷]GG‡…ú­Ät•’’’âïïOQTTTTZZÚåË—­¯gÍš5...„eË– y:&†Õ.‡ÃÑét………]]]"‘(::zd///ÏÏÏß¿¿P(”J¥;vì8~ü¸^¯ýé i¢£í±cǨŸ Ü{ôèÑ€€€øøxBHjjjuuõÕ«W™½L¾¬­­åñxfãæôéÓé ··W«ÕZèLmm-EQqqqr¹\.—‡‡‡‹D¢ÆÆF õ[ÉøØ¼¼¼ øúúúùù>|¸µµÕúzÄb1ý‚Ëåy:&†Õn@@@NNÎ_|!•J,Xpýúõ‘u¾¡¡ÏçK$¦Ú¾¾>fšÇhN`HmÓÓÓ ?1Ù¥Õj¿úê«úúz±X,‹éÃ/¿ü’)À¤a???•J¥P(FÐëçSöõõ¥(ª¨¨¨ö'OŸ> ¬~ãc !B¡°¯¯~ͤ7“®*Š”””mÛ¶ÕÕÕÕÕÕedd <ñÑ0écí&''_½zU©T.]ºtÅŠƒÁB%ƒµëííÝÓÓÃ$àÚÚZ'''&ÑŒ+šðí·ß¶´´äççßûÉáÇϞ=ÛÖÖfR200pÉ’%ï¼óŽB¡0 ÅÅÅÖÇ\©TÊÜsF×óÖ[oч·¶¶æææZ¨ßøXBHLLÌùóç !}}}û÷ï7Û\WW!$<<œ¢¨ÇŸ:ujX×dX§3švËÊÊ®\¹¢V«¹\®D"qpp°\É`íÅÇÇoܸ±»»»¹¹yË–-iiiƒå`€±eC™ãË/¿\¹rett´÷OÒÓÓ===srr>s挗—W\\œH$JKK£C˜5²²²Nž<éêêšœœL9}ú´L&›7ožP(ŒgV<0[¿É±»wï.,,œ3gÎâÅ‹.\h¶¹   mÛ¶%&&&&&fdd,Y²dWÆúÓq»½½½›7oöððpss;räHnn.EQ*¬]Š¢rssU*•¿¿TTTxxøÞ½{Çð|, Æäûq㉳cû…;<Ëð¹ûqÊÌ]FQ©?¿6œ´®æÿ¯ȟÙШ-Àh Ú€@´;h vÑì¢-Ø D[°ˆ¶`'mÀN Ú€@´;h vÑì¢-Ø D[°ˆ¶`'mÀN Ú€@´;h vÑì¢-Ø D[°ˆ¶`'mÀN Ú€@´;Áó)Šó:†„Q[°ˆ¶`'mÀNŒÍ\[ƒÁ0&õ0ö?Ý?¶2Þs}oœj¶’ñ\ä1¿n0…P©ÃÛk89~}±µ˜ˆªcÑ` @¶¢-À¤A`[ˆ¶¶ ØJˆ¶“ ±u !ÚØ4d_ë!ÚL2„×±‚h `»z‡Ñ`ò!ÂŽ D[…¼;\ˆ¶6Avôml’î ÚØ ÄÙQâLvÀnQ5Ù]˜Â¨TëÊ¥â"ÿ £¶`'mÀN Ú€À\[˜ƒa²»öÉxJ7FmÀN Ú€@´;h vÑì¢-Ø D[°ˆ¶`'mÀN Ú€@´;h vÑì¢-Ø D[°ˆ¶`'mÀN Ú€@´†¤¤$Š¢(Š … W®\¡·—––¾üòËb±˜Çã…„„dee1‡Üºu륗^rssãóùsæÌÙ²eKOO]Õ–-[FÙŸÈÈÈ3gÎŒ²»h 0<ü±F£yôèQbbâòåËÛÚÚôzý¯~õ+™Lvÿþ}¥RyæÌ™€€ºð7ß|³xñ∈ˆüüü–––'N´´´Mî)Ø+D[€á¡(ŠÃḺºnÚ´©»»»¬¬ìñãÇõõõ6lðòòâñx‘‘‘kÖ¬!„èõúuëÖ­[·nçÎÁÁÁ|>?""âðáà êß·oŸ\.wqq‘Éd;vì 7vvv®]»ÖÇÇG"‘¬ZµJ©TB233KKK333åryZZ!D*•Þ¼y“>¤  @ ЯCBB6oÞ¼hÑ¢¸¸¸ÄÄÄâââñ»>“Ñ`„NŸ>íàà0cÆ ™L”‘‘ñ·¿ýíÑ£GLââↆ†ßüæ7&R5X[·n½téR{{ûƒ^|ñEz{jjjsssaaá£GD"Qzz:!äÀ¡¡¡¨­­=~ü¸åÞž;wîìÙ³ÿ÷ÿ·fÍš—^zI­Vì¬m¢-ÀðdggK¥R@““ãééÉb±nܸ1oÞ¼={öΜ9“žÿÚÚÚJ™>}ºõ•s8NWXXØÕÕ%‰¢££ !555.\8tèX,ær¹Ÿ}öÙwß}×ÑÑ1¬n¯Y³ÆÅÅ…òÆoètºk×® ëð)Ñ`xÞ~ûí{÷î555ÕÕÕ­ZµŠÞèáá±k×®;wî<}útíÚµ©©©÷ïß—H$„ÆÆFë+ÈÉÉùâ‹/¤Ré‚ ®_¿N©­­¥(*..N.—Ëåòððp‘H4¬j !R©ÔøõpŸm†‡ÏçÓ£¶f÷ ‚7:;;ÿøãaaaÞÞÞ'Nœ0)c0,ÔŸœœ|õêU¥R¹téÒ+V ___Š¢ŠŠŠjòôéÓÐÐPB‹õqN(öõõѯéù¸Œªª*ú…V«­««ÖXòTh 0ZMMM|ðAaaaOOÏ“'OvíÚ¥ÑhâââX,ÖÁƒ<¸uëÖêêjµZ]RRòî»ïæççVUYYÙ•+WÔj5—Ë•H$„ÀÀÀ%K–¼õÖ[ …‚ÒÚÚš››K——J¥åååÌá111çÏŸ'„ôõõí߿߸æC‡•””h4šíÛ·s¹Ü¤¤¤q¸“ Ñ`´x<^GGÇk¯½&‘H/\¸——DY¶lÙ¥K— bbbÜÜÜV¯^íëë9XU½½½›7oöððpss;räHnn.}ÏÙéÓ§e2Ù¼yó„Ba||<³ BVVÖÉ“']]]“““ !»wï.,,œ3gÎâÅ‹.\h\óÚµkß|óMww÷þóŸçÏŸwrrÇ+2I(Ëãá“eÿÓýC‘÷\ß§š­d|G¤m^|€±‚ßz¶#$$d÷îݯ¼òÊdwdìÌ0j v‚3Ù°sV­3»ÑŒ¢-€ý+++›ì.LLH_Ã…Å-Àh Ú€@´wVŽÅbÈ`”mL%%%QEQ”P(LHH¸rå ½=66và£ÅLDFFž9s†y[TTîáá±|ùòqìñp˜ôО ÚN„!Gd1d `k>þøcFóèÑ£ÄÄÄåË—·µµ¬ž£GFDD´´´œ;wΚòƒA£ÑŒ¬-@´0ƒ¢(‡ãêêºiÓ¦îîî+ ìÝ»788X(Êåò;wÒ333KKK333åryZZÚï~÷»¯¾úê›o¾‘Ëåýë_ ! …âÕW_õðððöö^¿~½J¥¢ ùä“OæÏŸrëÖ­?ÿùÏóçÏçr¹‰‰‰»wïöôô”H${÷îØÛ}ûöÉår™L¶cÇzcggçÚµk}||$ɪU«”JåÀB¤R)ól³‚‚@ÀtióæÍ‹-Š‹‹KLL,..Û+<°ø×1 ƒ­q‹![[vúôi‡3f˜l÷öö¾xñ¢\.¿wïÞÒ¥KƒƒƒW®\yàÀ7n|ôÑG«V­¢‹Qåââò§?ý‰~»råJ¹\^UUÕÓÓóë_ÿzãÆùË_è]yyy×®]sww§ß=zôïÿ»ŸŸ_JJJRRRJJJuuõ;w^xá…W^y% €éIEEÅÖ­[ g̘ÑÑÑQUUEoOMMupp(,,äóù6lHOOÿöÛoöЂsçÎýðÃ...999/½ôREE…?ž£¶fdggK¥R@““ãééiR %%Åßߟ¢¨¨¨¨´´´Ë—/Ygø9ϲ IDATyyy~~þþýû…B¡T*ݱcÇñãÇõz=½7##ƒÉµ„õë×Ïž=[ ¤¦¦¶¶¶nß¾Ïç/X° 88¸°°Ð¸Z‡£Óé »ººD"Qtt4!¤¦¦æÂ… ‡‹Å\.÷³Ï>ûî»ï:::†uÖ¬YãââByã7t:ݵk׆uøÄC´8fGg1d 0)Ž;FýÄl·ß~ûÞ½{MMMuuuf8óòò,XàëëëççwøðáÖÖÖ!mhhàóù‰„~Ð××GÏ „Èd2ãÂÌ[>Ÿ/•JY,󶫫˸d@@@NNÎ_|!•J,XpýúuBHmm-EQqqqr¹\.—‡‡‡‹D¢ÆÆÆ!;iL*•¿îáÑžEéé醟˜-@Jfâ© …B‘’’²mÛ¶ººººººŒŒ ¦&ƒäííÝÓÓÄàÚÚZ'''±XL¿,d[#99ùêÕ«J¥réÒ¥+V¬0 ¾¾¾EÕþäéÓ§¡¡¡{( ûúúè×LΦ1s´Zm]]ÝôéÓGÜÉh;¡Lþó`È`Š¢ÇMÃÃÃ)Šzüøñ©S§˜]R©´¼¼ÜìQAAAñññ7nìîînnnÞ²eKZZš…(l¥²²²+W®¨Õj.—+‘H!K–,yë­· !¤µµ577×lcbbΟ?OéëëÛ¿¿q͇*))Ñh4Û·oçr¹III£ìêxC´¶   mÛ¶%&&&&&fdd,Y²„Ù•••uòäIWW×ääd“£(ŠÊÍÍU©TþþþQQQáááf—;®ÞÞÞÍ›7{xx¸¹¹9r$77—>}ú´L&›7ožP(Œg–A0éáîÝ» çÌ™³xñâ… ×¼víÚ7ß|ÓÝÝýŸÿüçùóçmü2Be›‡ûŸîºÐˆ¼çúÞ8Õl3ízÑ¢EÌÆ«W¯Ò/lÿo €0þ†Ý6#X²{÷îW^ye²;2ãÿ_VÞHÈCÆ…g™íßx 6?*`0ˆ¶ãÂìoè?‹é-Æ…‘qF Ñv,Y™h+€Œ @ð™‹0´0‘>€Íö!ÚŽ?jGö»Ùø(¦Nd\+!ÚŽÜX%Z³å"ãX†h;lãšhBÆROOOuuugg§N§svv‹ÅÆÕžÝÝÝ………óçÏóš;::=zÔÑÑa0èSóõõe³Ù÷îÝkoo'„°Ùl>ŸïïïïêêJÉÏÏ÷÷÷gžc0®_¿I?#Àîa][«\3ÂlLúÉÄôa`sf{õ¬1 ?þø£““S\\\bbbhh¨³³ódwjV.£T*‹ŠŠø|~ttô¼yófÍšÕßßßÝÝMïõóó[¸paBB‚H$*..Öh4ãÙe»òÁPõÝwß ÷À¼¼¼ÛcccOœ8A¿ŽŒŒŸ¯V«£££é]EEEóæÍ£[¤ †‡NŸ>ÁÁÁÆçNQ‡Ãñññ©¯¯W©T"‘h|®1€]éïï?~üxDDÄ‘#G^|ñÅ ƒV«¥eXéÃ?ŒŒŒ»>Zk]µ{µ5ÃìPèÑZÃl—žµq\GGGWQQÑÒÒÂ<ÿšöàÁƒþþþØØØ„„‡ÃÜæYZZªV«£¢¢ž{î¹Y³fѲ¸¸˜¢¨øøø˜˜˜®®.æ‘Ù„¶¶¶°°°¸¸8‰DRQQAo,))qrrš7oÞœ9s?~Ìvrr Ÿ?~XXXcc#ó”pBˆR© ›;wnpppwwwOO½]¡PxxxçZBHOOZ­öôôò ´´´PÅår‡uÝžYçÎ3 _~ùåùó盚š˜í!!!Ÿ|òÉüùóCBBnݺÕÞÞþî»ïúùùM›6-::šy,mMMÍÂ… y<^LLÌýû÷é{öì¹}û6!$33³´´433S.—§¥¥B:;;×®]ëãã#‘HV­Z¥T*éCÖ?ðX©TÊ<<œÅb9;;ûúú2‘×ÃÃ~!¤RéÓ§O% ½E&“Ñáp8‰¤©©)00P§Óµ´´DDD˜œ=ÁÀÂó  …N§spp˜5k=h C:|øðk¯½tìØ±>úˆÙ•——wíÚ5wwwBÈÒ¥KY,V~~¾T*-)) …t™C‡9s&88xÓ¦MëÖ­û׿þe\ùnܸñÑG­ZµŠÞ’ššêààPXXÈçó7lØžžþí·ßBV¯^mRÿÀc-0îjKKËÅ‹årù½{÷–.]¼råÊÁ¬¨¨ØºukaaáŒ3:::˜¡³ýV—Î;÷Ã?¸¸¸äää¼ôÒK“òT^DÛ‰¾-l\=›Ë‡9::ÒßÚëtºÇ?xð€Ïçk4Š¢îܹÃãp8jµº¿¿ŸÍf›ügS«Õl6›ùB‡ËåêõzFCçEf;‹ÅÒëõƒžo@ç]º>>µµµÝÝÝtXŒe(Åbétºþþ~ãaN'''N§ÑhèÙ××Çb±,L]rrrÒjµz½žÅbBúûûéíýýý%%%ááát¢­®®îíí5[ƒH$âp8mmm …‚YÐÀŸÏwrrjnnf¾ëx²GjU*ó–nÝöï«CÇŽûíoK¿xÛîÑ£Gâãã !©©©ÿýßÿ}õêÕ矞ÞËÜ;Q[[ËãñŒo¥`LŸ>~!z{{µZ­É/cµµµEÅÅÅ1[D"QcccSSÓ`õ[ÉøØ¼¼¼½{÷Òmuvv¾ð  ÈÉÉ9xð`zzzLLÌöíÛ.\8X?‡mI¥ÒÆÆÆáœÐ˜y梭Ý'Úì;ãö÷÷×××{zzÒC­ …B¯× …B.—ëêêZ^^>sæLGGGFÓÞÞ.‘H¸\®››[yyypp°££cOOƒƒÇ›6mZeeePPN§«©©‘J¥;y<ž@ hhhðõõÕëõ ôv­VK¡Ã¨Z­niia¾ÀÈËË«¶¶V¥R……… ÜKQÔÌ™3KKKY,–T*urrêíímll¤ÿȬN©TZUUåææ6mÚ´þþþªª*WW×Iù>`²¤§§§§§›Ý¥Õj¿úê«¶¶6zl’öå—_2Ñ–ùÉïçç§R© …——×p;@zÐ|}})Š***2ùÑíääd¶~ãc !B¡¹„™¤kÒU…B‘’’òüãù矧(jóæÍ>´ÜÃääääääÞÞÞììì+V´µµ ÖÏau‰™Û Õjëê꘿&Ø3m#ŠL'2»HuÃe!ã’){AX,–V«-))Q«Õ,‹Ï燅…ñxØð°X,Žˆˆ¨««kll¤×µõôôl—©S¯×WVVööö:88¸¹¹Mð¿¶ìÛo¿mii¡—¾¡·\¼xqýúõmmmÌ—û´ÀÀÀ%K–¼óÎ;‡¦çº»»[s¥R)sÏ]Ï[o½õùçŸ{yyµ¶¶^¿~=99y°ú%„ÄÄÄœ?þ…^èëëÛ¿¿Ùæè_@áááE=~üøÔ©Sƃ¯•••=~ü811‘ËåJ$úwÐ`ý49Ë]:tèÐòå˃‚‚vìØÁår'+WØs´E¢Œ=ÝvÆápL–Ä2Þ5cÆŒ3fXsˆ““ÓìÙ³Vb<ÊÙÙ™¹8ÎÎÎÆ÷~1‹|ùùù1¯«‡é‡Ã±üƒR$…‡‡Üna‰™L6šo¸ìØ—_~¹råJfíEBHzzúöíÛsrrÞÿ}“ÂgΜÉÊÊŠ‹‹ëììœ9sæéÓ§­Œ¶YYYo¿ývvvöâÅ‹sssOŸ>½uëÖyóæ)•J—_~™ŽŒfë79v÷îÝo¼ñÆœ9s¦M›öòË/߸qc`sAAAÛ¶mKLL”H$îîîK–,yúô©…îõöönÞ¼¹¬¬ŒÍfåææÒÀƒõÓú.­]»öÍ7ß|ðàAhhèùóç'ë;CÊÊÕã'Øþ§æÿ4±†'Z㯹mçâOÝÕ!¦®Ç744ÄÅÅá6/ý9Ä,À‡dʱÍßz0æBBBvïÞýÊ+¯LJëÆ3ûµµñDkãìiwJ¸yó&›Íž5kr-ÀšòÑv`¢Egsù°‰÷ÜsÏMvìÐT¶H´À¾—V°ìÞ½{ííí„6›Íçóýýýé5Ýîܹãíím̓âF¦££ãÑ£Gô½ƒb±˜^Àx°þäççûûû3kî †ëׯGFFÒ«K2Æ»ÛðŒcù9é¦X´E¢ȸðlòóó“Ëå:®®®®¸¸8>>~¼Ô®T*KKK½½½™ߺ»»éåxFÓËËk؇)m1‰ÖvØåòaPÅáp|||êëëU*•ÉŠõõõ …‚~hœ——³8†V«­®®~òä‰F£ár¹¡¡¡<ÞØÖÖ¦×ë]]]gΜiL ÃǧOŸÎ,Ù&LVó°Ü êëë½½½éuñè•ÚÛÛ5 ‹Å ¡Ÿ8mÍ©Ø8Û¶H´¶ ·Á3¥¥¥…¢(ã'*ÓœœœÂÃû»»üñGG¯\ZZJQTTT”£££J¥¢†üàÁŠ¢bccÙlveeeYY™É£5{zzÔjµ5sëõÚÚÚ"""8ΣG***¢¢¢¬<5gsÑ–ŽGä?r-¢’ÍBÆ;ÖÐРP(t:ƒƒýh“̪ï@*•>}úT"‘ôöö>yò$!!^Ó‘íëëkkkKLL¤GjnÞ¼iò|NFC±°äý±žL&£›‹Åµµµ ˜=µ70Õýðûvíúá‡T*•ŸŸß¢E‹Þ{ï½ñk166vÆ ¯¿þú˜×ùÑG­ZµjÌk¶¶m±®êT‡Œ öÇËË‹¾…‹vH©TÖ××÷õõQ¥ÕjéûºúúúØl¶IB¥Ëܹs‡ÙÂápÔjµq´¥S/=ÀúþPÔ,O®×ëÉ.ñhÓ‹ÅÒëõƒÁä³§ðl:wîܪU«6lذgÏ__ßÖÖÖ .œ8qbÇŽãÑœÁ`Ðjµ~ø¡…§ó€¬¡‹Œ§k?1Þ˜ô“É錎Ù>³ÿÐ6ŽÍf;::–kûûûKJJäryBBB||<ó8gggN×ßßo\˜Nº±±±ñ?yî¹çLf¸òù|''§æææaõÇÙÙY¥R1o{{{éÃ;UëN à¤×ëׯ_¿~ýú]»vÍš5‹ÏçËåòuëÖ1¹¶³³síÚµ>>>‰dÕªUJ¥’Þòé§Ÿ.Z´(,,,66öþýûC–ÿä“OæÏŸrëÖ­={öܾ}›ÞÕÞÞþî»ïúùùM›6-::Úø±·´}ûöÉår™Lf¹c™™™¥¥¥™™™r¹<--"•JoÞ¼IRPPÀÜo²yóæE‹ÅÅÅ%&&ÃÕ“3j;0â ÈÚ,‘ &ìì9RZ­–BÿP«Õ---B¡ÂårÝÜÜÊË˃ƒƒ{zz¸\®««kyyùÌ™35M{{»ÉWüEÍœ9³´´”ÅbI¥Rf…OOO ·‹I¥Òªª*77·iÓ¦õ÷÷WUU¹ººŽòù–ƒÀ3èþýû ©©©ƒHMMupp(,,äóù6lHOOÿöÛoé].\øþûï]\\þøÇ?®[·î_ÿú—åòyyy×®]sww7ibõêÕ,+??_*•–””˜ü¬¨¨ØºukaaáŒ3:::ªªª,tìÀ7nܰrB¹sç~øá—œœœ—^z©¢¢b²ž;,m§V¢§Õ%ǃ^¯¯®®V*•ýýýB¡0((hàýΓ ˇÃn.Ç“ËåwïÞuttäp8®®®t"$„„††VUUݹsG«Õòx!$00°²²²¦¦æÂ… ÍÍÍb±˜òÙgŸ¹¸¸tttÐŽ®Y³†ÎË–-ûýïO±\>##c`®­®®¾xñbcc#ýý‰Éí§„‡£Óé é?ƒ£££‡lÈJLÿßxã?þøÚµk¿üå/‡{'ÞDDÛ©•hiã·ºäxÐëõ'22’Ãᔕ••——ÓŸl„Œ 4Û¸ƒÍr‹‰‰a^ûùù™]‹Ãá˜,ÚEoœ1cÆŒ3,·+‰ÂÃíï!D&“ 9gÀ¸ÛsçÎe^;;;›ýWìÔìÒ±cÇ~ûÛßÒ¯'¯BèhØØØHÿ-ºaÆ 69rd÷îÝ„ÚÚZŠ¢âââ˜ò"‘¨±±‘N ô±„.—ÛÛÛ«Õj-—7û¹¶¶–ÇãYø?““sðàÁôôô˜˜˜íÛ·/\¸ÐrCVbFëè×Ö;‰Æ+ÚNéÛÂÆouɇ¿mlllnnfbhgggQQѼyóØlöíÛ·Åbqgg§N§c±XÌ@¬Ù¥19Ž\.gºúäÉ“Ñ]€‰€%rL…€ Ï‚ôôôôôt³»æÌ™ãíí}êÔ)³^úúúRUTTde °\Þì  ~~~*•J¡Pxyy VmrrrrrrooovvöŠ+ÚÚÚ,4ÄbýÇ}VB¡°¯¯~ÍLü¥1s´Zm]]3tmãÆø62û¸-lüV—œ9s¦ñ[OOÏîîîžžú­B¡ððð`îQ*•aaa111^^^÷ïß§o|~ðàAlllBB=Fk\a[[[ccc`` •ý±¸í ðo 6‹ÅbýÏÿü϶nÝZYY©V«=z”ŸŸOÇÐÀÀÀ%K–¼õÖ[ …‚ÒÚÚš››k¡¶á–gyçw …Á`(..¦e”••]¹rE­Vs¹\‰DBl¡!©Tj|#ZLLÌùóç !}}}û÷ï7®ùСC%%%fûöí\.wª¹±µÒc´MØê’G"‘455êtº–––ˆˆŸôež”J¥555ííí<ÏÂÒ˜ÝÝÝ< Ö× ¶Ãòòa`÷ðo ¶iùòå—/_Þµk×Áƒ;;;=<<–,YòÍ7ßÐ{OŸ>½uëÖyóæ)•J—_~999ÙBmÃ-O9sæLVVV\\\ggçÌ™3OŸ>m<‚ÛÛÛ»yóæ²²26›”››KÇîÁÊÊÊzûí·³³³/^œ››»{÷î7ÞxcΜ9Ó¦M{ùå—oܸÁÔ¼víÚ7ß|óÁƒ¡¡¡çÏŸŸ÷B(“9%#cgѶ»»»   66ÖìÝ÷îÝW—ü÷¿ÿíççÇ|Út:Ý7¢¢¢L‚¦ñ× ƒ¡£££¤¤$!!¡¹¹¹¾¾ž™sûöm¹\άš~çΙLÆår‹ŠŠŒ?[Z­6**Šž«@ßô6p‚ù”ƒˆóŒ›º?:``Ë”cò[o{ò{÷îW^ye²;bãÙØŒÚÚÙ2OÌꒃݘL¯.i²qd«KŠD"‡ÓÖÖ¦P(Œçk35B C__Ÿ““³4¦ñ2ïÆÝžÜ»ÙFi*ÞnÃbù–¤¤$üU£4ö·‘ÙÁ-𼺤——Wmm­J¥ 3Þ®P(Äb1Ç«««c±X...,ËÂÒ˜Sô¯a$ZÀ¿8Œ•q\ükJg܉\]’žJëîîn2æ*“ÉÊËË{zzø|þœ9sè[-,ÙÞÞ®R©,ÜAiShLÔ?ú;w¼½½-ßZPPàëëËL¢g®÷÷÷‹D"“¿9§ æ¬ÏÅËË«²²ò¿øÅˆ«5¹P£,6Ëä>õ)d"Öµ¢Ë<Óê’q8‡30’òx¼ËÓZXsÈõ2'ÍɆѰñw…B!fÍšeý!ƒÁìÂ=“ÅÇLJþkÜø\úúú˜…ìÒ„>Ìò-ð6þ«nü( úy?“Ý‘ñ‚D ÆÆïŸ~°Õ Õ××+ µZíàààååE?•àáÇ===>¬®®vqq¡(Š^×¹7´¿¿ÿáÇííí,K,з޾}["‘´··k4š   ŠŠ ///¥RÙÕÕ% CCC››› ƒ¯¯¯ÏÀ>744444hµZ‹5}útº?ÃZÖšÙþäÉFÃårCCCy<^}}½··w}}=s.„½^Ïf³™l³Zè›É… ±æz†„„ Ös€17¡Ñ–ŒË¸yó&›Íž5k–M÷Œ $Z01ÿúJ¥2::šÃá455Ý¿îܹ&‹“;99…‡‡;;;wwwÿøã<O"‘Ìœ9³££Ãä t‡Ã,]\\ììì¯Ó銋‹«ªª‚‚‚˜###™ ¦P(fÏžíìì\RRrïÞ=_üâ]]]EEEb±Ød l•JUSSËårµZ-sçè`'òàÁŠ¢bccÙlveeeYY½"Jii)EQQQQŽŽŽ*•ÊxåúY3̹´µµUVV2{-h¶o/”•×s°žŒ¹1~dÃpa¹þçž{.!!~F³±¹sç2è›Zìã±0E¯m0ÚÛÛM xxxÐë–©TúôéÓ!ëT©TôZ’ôÒ(þþþMMMÌ]›2™Ìxrúôé|>ŸÕh4r¹œÍf»¸¸ðx¼îîn“š)Š2 ÝÝÝ:ŽÃá…B 'Ò×××ÖÖìààÀb±ÚÚÚèÐùäÉ“   '''Š¢è^¬¹V–´Ð·á^ÏÁznM'¬‘””DQEQB¡0!!áÊ•+ôöÒÒÒ—_~™¾!;$$$++‹9äÖ­[/½ô’››}7Ë–-[èÇ'%%%mٲŚF###Ïœ93¶%G/66öĉ¶ÓŸI19£¶ÙÙòaÏ Ü¶ÀxU>GGGµZmR@©TÖ××÷õõQ¥Õj­™¤V«Ùl6“_¹\®^¯§ïã$ží¼¥s0óm ›ÍÖétMMMÌIII\.wÖ¬YeeeÀßߟù+wà‰°X,Š¢îܹÃlçp8jµº¿¿ŸÍf`)õ¾¾> Zè›1k®'½w`ÏÍ.b02üñïÿû®®®?üáË—/¯­­uuuýÕ¯~µtéÒû÷ï‹D¢ŠŠŠÿýßÿ¥ óÍ7)))7nÜ»w¯··weeåÁƒéÝOîYŒÞ‡~hᎠgÄ$Úš•””TQTQÄly¦Æq§–ÿ4 …I4p5hã½ýýý%%%r¹>ÞÊ›>œœt:ýBBH__‹ÅÙTQ©TjòD"‘DFF&&&º»»[8fYëøŸ<÷Üs|>ßÙÙY§Óõ÷÷·3C8XßV^ÏÁz>ÜX@Q}×ʦM›º»»ËÊÊ?~\__¿aÃ///¹fÍBˆ^¯_·nݺuëvîÜÌçó#"">œ`¡þ}ûöÉår™L¶cÇŽÌÌÌÒÒÒÌÌL¹\ž––FÙ»wopp°P(”Ëå;wîdX²³³síÚµ>>>‰dÕªUJ¥Ò¤­?ÿùÏóçÏçr¹‰‰‰»wïöôô”ƒë^‘ÎIDATH${÷î¥Ë ÖÜž={nß¾ÍÔóé§Ÿ.Z´(,,,66öþýûÃêÙÃ-·>Ø!íííï¾û®ŸŸß´iÓ¢££éÇüyFÌ£-ƒ¸È¸6‰l“B¡èéé1 ÌjÐÆ{é/ÁéuÔjuKK ³‹žlj¶N7mÚ´ÊÊJ:ÖÔÔH¥Ò1™¯R©ž>}ª×ëé¬l<-xà‰p¹\zYk:Œj4šÖÖVB—Ëussc¶÷ôôXs-8Xߌ/”•×s°žŒ‡Ó§O;88̘1C&“eddüío{ôèS ¸¸¸¡¡á7¿ùÉþSWTTlݺõÒ¥Kíííú¨ººÚBs&.\¸pöìÙâââW_}uݺuÃíÏÀÃiZ7{ÈêÕ«ëêêòóóÛÛÛ?NOp²æ:ŒÌÔø>ˆI·Eô‹)±|˜Áma`ûÌ®Íàñxr¹üîÝ»ŽŽŽô3ãÓ××·¼¼¼¡¡ÁÕÕuöìÙ&ÕΞ=»²²òßÿþ7EQb±˜¹½l”ôz}MM y<žq»ÃZÖ:44´ªªêÎ;Z­–ÇãÍš5kàãͲpà`}3¹PV^O rŒ‰ììì#GŽtww»»»çääÐˀܸqcß¾}{öìùñÇårùöíÛW­ZEÿe5}útë+çp8:®°°~rÓÀu9 !)))ô‹¨¨¨´´´Ë—/¯\¹r`±ššš .477Ó·Ó|öÙg...&„Z¿~=ýŸ.55uݺuÛ·og±X ,.,, °²¹5kÖÐá/[¶ì÷¿ÿýpû3ØáZxHuuõÅ‹é/vè[H­¼#35¢-c`Æ%˜’;Îha 1»tLL óÚÏÏ^ Ê„‹‹‹ñƒ è…NNNó.!dîܹƒ½‹ÅÆw‚šý](ÌnìD[ÖšÃá˜t˜µñ.wwwwwwËZî›É…²òzZXÀÇŽûíoK¿6ûèÍ·ß~;++K ?\ÉÃÃc×®]»víêîî>|øpjjêìÙ³é?«­ÿû* ''çàÁƒééé111Û·o_¸p¡I™¼¼¼½{÷ÖÖÖRÕÙÙù /˜­Š.Çl‰D&‘Ž™ÞÃçó¥R)óW:ŸÏïêê²¾9æ§—ËíííÕjµ&sÜ-÷g°Ã-´>ðÚÚZg2aÉÊë02S,Ú2qÇ-؈ôôtË_XÓp°½`ãÆŸ|òÉ?þ¸zõjooï'N˜Üneù©+ÉÉÉÉÉɽ½½ÙÙÙ+V¬hkk3™A”’’òüãù矧(jóæÍ>dö—ôõõ¥(ª¨¨h4ÎrsCe†ÛºŸŸŸJ¥R(Ʀ“ë0›žkkóq ¦äŽ–î;ÐÔÔôÁöôôuê”ñáÆ%—,YòÖ[o) BHkkknnîpOÍrsCe†Û:ÝÄ;ï¼£P( Cqq±B¡“ë0˜)mȸ£D v`ê®mÂnN`ñx¼ŽŽŽ×^{M"‘^¸p!//~ØÊ²eË.]ºTPPãææ¶zõj___ kfõöönÞ¼ÙÃÃÃÍÍíÈ‘#¹¹¹Eeeeܸ$!äôéÓ2™lÞ¼yB¡0>>þæÍ›Ã=5ËÍ i”ýAëgΜñòòŠ‹‹‰Diiit8ýu evÎʤÛÿtÿ˜Ôc<]6éAÍøûŽI¿øXŒl ýć,À‡dʱ©ßz`¯Œ?fSu®­•,,­ð,ÿdD¢»dçÑ–1Y×òâ—÷Žë_´H´`ßž•hË`ÂÜÀÇù’qˆz–ï¸Xxl['Xèž%Ï\´e ̸Ϧ+ ÑÀ3èÙ¶ŒñθVÜŽÉ--<Ëm6uÇq‘h¢­YÆ¡pà”ÜDÆ!nG6d‹ÛÂŒ!ÚÁÂmg“•#‘hÌB´µÖ(3®…[+‡l‘h,C´¶‰\> “h¬‡h;rýíÌìÀ­Ù![$Z€@´cµ´-Àh ÚŽ¥!3®ÉÀ-=d‹D `Ììÿk ÚŽ Ëw°-ˆ³£AÉC°ÆÜþ§ûÇ©æ÷\ß§š‡ÄÙE‹B®^½J¿E¢³èøSÚÀï*ÆœñÇ £¶‡þýÄ\ýE‹á?9ÀbMvÆ¢-Ø D[°˜k a°ÎŒ!ŒÚ€@´;h vsm`¼`÷Ÿ²jª1•úókÃIëjþ/\äŸaÔìFmmѽ{÷ÚÛÛ !l6›Ïçûûû»ºº,vçÎoooOOÏ ï €-B´µQ~~~r¹\§ÓÕÕÕÇÇÇ;880 >>>`lÛ5 Xœ¦(D[ÛEQ‡Ãñññ©¯¯W©T"‘èöíÛ‰¤½½]£ÑÕ××{{{óx>>„úúz…B¡V«¼¼¼üüü膌«åóùjµ:::šÞÕÙÙYTT4oÞ<6›=Y×ÀJˆ¶¶®¥¥…¢(.—K¿U*•‘‘‘&#¸4…B1{ölggç’’’{÷îyxxüâ¿èêê***‹Å\.×ÉÉ)<<ÜÙÙ¹»»ûÇäñx‰Ä¤Z­VûÃ?ôôôðù|ºNäZ˜mmTCCƒB¡Ðét³fÍrtt¤·Ëd2³¹–2}út:zzz>|øP.—SåââÂãñº»»¹\®‡‡]R H¥Ò§OŸ2Ñ–©–ÃáH$’¦¦¦ÀÀ@N×ÒÒ1îg 0mm”———¯¯/›Í61urrìf›Ívttd¦Ì²ÙlNGQ*•õõõ}}}EiµZã[ÓŒ«•Éd%%%­­­ÎÎÎÓ¦MÃó?ˆ¶6ŠŽ§cXaIIIxx8h«««{{{Í–‰D§­­M¡PH¥Ò1ìÀ¸Âº¶Ï ­VK¡WTP«Õ--- {yyÕÖÖvuu!ÚÀ‚QÛgÇ“ËåwïÞuttäp8®®®tØ5K*•ÖÔÔ¸»»6¯À!ÚÚ¢ÈÈH³ÛçÎkü6&&Æì.±X,‹™·ÌJ^~~~Ì‚_ª%„p8‡ãåå5ÌŽL&LH3 =²;ٌڂ©›7o²ÙìY³fá±d0µ Ú‚©çž{n²»0˜vÑì¢-Ø ÌµµQ=êèè0 ÎÎÎb±˜~îî½{÷ÚÛÛ !l6›ÏçûûûÓëäççûûû3OX0 ׯ_ŒŒtqq™ÌÓ˜@ˆ¶¶H©T–––z{{:99õöö666vww‹D"BˆŸŸŸ\.×étuuuÅÅÅñññx°Á„d0>|8}úô€€Çf³App0kiEq8N§R©&±·¶ÑÖæôôô¨ÕjOOÏ!K¶´´PÅår' W¶lŽF£!„899 V ¡¡A¡Pèt:‡Y³f9::N`ïl¢­Í¡'ΪÕêÁfÐzyyÑ·”±Ùlf#EQƒy«×ëéãÜY‚ 6‡Ïç;99577V€Íf;::çZBˆ³³³ñ¤ÛÞÞ^zãøõÀÖ ÚÚŠ¢fÎœÙØØXSSÓÛÛ«×ë{zz***:::,%•J›ššž>}ªÓéz{{«ªª\]]-Ìj°?˜`‹ÄbqDDD]]]cc#½®­§§§@ °pˆT*Õëõ•••½½½nnnÖa[€hk£D"QxxøÀí‘‘‘ƒ"“Éd2Ùxv À¦aBØ D[°ˆ¶`'mÀN Ú€@´;h vÑì¢-Ø D[°ˆ¶`'mÀN Ú€@´;h vÑì¢-Ø ÎdwÀÎQ5¬½ƒa<»`Ïmlŵk׬٘””4þ}˜’0!a| kC¶Ï8k2+r-€ˆ¶`'mÇ•c±²2Ô ,†l,C´;h;†‘Å-0šÅ-ÀmÀN ÚN ã²²h1d ` D[°xdÃÄ1 xüX)))‰yX†lì•:¼½†“ã×;Q[€É¨:æm'”É-†lÀz°C¶@C¶¢-À¤A`[Ô˜ œB 0¶0 SÛ©AÃ’å·4K ø¿ð+ògµ˜L¸Cˆ¶ÿßÎÝ…HY÷¿F”XÖeÕ\[l³µ@Å|L K4C*"•º%ì ÈR <èLƒD¤ÈØÄ(©ìE)Œ¬’…XZ${0ÈÖÐDW°Ü|¢rî¹÷¿fwgfg®ùÎëu¤yù›ßlAo?M jÚ·ï¤-@™‰×b)þ÷µõ™HŠÅg¸@õö‹Õ ü$lQH[€”Ò»ý%mRAÈNÚ¤‘Ò̓´H 9[ i :7?Ò EDm!¤-@º¨Û¼I[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚H{Úîß¿ÿ¡‡1bDmmíäɓ׬YsöìÙâ¾Ä´iÓ>úè£îŸÎœ9sûöíÅ}‰¾œÙó™<®Ôó™¼ßB ¾'ÕiûñÇÏŸ?êÔ©­­­'OžÜ¾}ûÉ“'8p½ç³Ùìßÿ]à‹>÷Üswß}w‡äqfŽgú{¥b½…øR œô¦í¥K—V¬X±bÅŠ 6Œ?¾¶¶vêÔ©[·n½çž{®xr„ /½ôÒœ9s&L˜°ÿþÆÆÆ¯¿þúò/µµµ :´û±—_~ùþûïŸ4iÒÌ™3¿ûî»$IV­ZõÃ?¬Zµª¹¹yÙ²eI’¼úê«ß|óM÷oyýõ×çÌ™SSS3{öìcÇŽmܸñ¦›njhhØ´iÓågΜ9óôÓOßrË- >úè©S§®~/Wœyõ5z>“ûJ›6m?~|]]]ssó† ®ù¥ëùüo¼ÑÜÜÇ!¹_÷øñã‹/5jTSSÓÊ•+Ï;—ûí”^zÓöàÁƒG}üñǯøë™Læê‡÷ìÙ³gÏžC‡Í›7/Ç™{÷îݽ{÷Áƒ/^¼bÅŠ$I6oÞøàƒ9Éýº<òÈ!C~ùå—¶¶¶o¿ývõêÕ}|;%“Þ´íììL’äæ›oîËÃË—/¿ñÆ{}ì©§ž6lX’$ .lkkëËÉ+W®¼ãŽ;†ºtéÒÎÎÎW^y¥¶¶vîܹãÇoooÿõ×_÷îÝûÎ;ïŒ9²¦¦æµ×^ûôÓOÿüóÏ¢_£Û’%KÆŽ›Éd¦OŸ¾lÙ²Ï?ÿ<ÇÃþ÷ßÛÛÛ»ººêëëï¼óÎ<I’äСC­­­---uuuëׯ߶mÛ¥K— ;E”Þ´mhhH’䨱c}yxôèÑ}yläÈ‘—PSSsþüùþù§ï'×ÖÖ6664¨û§]]]™Læ®»îjnnnnnž2eJ}}}¯wÎãÝöìÙ3wîÜ1cÆÜzë­[·n½ü€ë¹í¶ÛÞÿý·Þz«±±qîܹ_}õU‡$IrôèÑÚÚÚËG.{áÂ…î^òvŠ(½i;iÒ¤¦¦¦«ÿýl6{õÃ=?¥PWWwáÂ…Ë?¾æ'_¯Ð]«y3fL&“9pà@Çÿœ>}zâĉy˜ûJÇ_²dɺuëŽ9räÈ‘åË—_ó«ÑÓ¢E‹¾üòËS§N=ðÀ?üp6›ÍqÈõ^·©©éìÙ³ÝÜÑÑqà 7t-@J¤7m ´eË–-[¶¬]»öðáÃ/^üþûïŸyæ™ÖÖÖÜ¿qÆŒŸ|òI’$.\hiiéõ…:”ß%o¿ýö <ùä“ÇO’¤³³sçÎùÕ—+uuu%I2eÊ”L&óûï¿ïر#÷9?ýôÓ_|qñâÅššš†††!C†ä>äz¯;nܸY³f­^½ú¯¿þ:qâÄš5k–-[VÈ BªëdáÂ…ûöíkkk›1cƈ#{ì±1cÆL›6-÷ïÚ¸qc{{ûäÉ“çÏŸß}÷õú*Ï?ÿü|0|øðE‹åqÉ?üpôèÑ÷Þ{o]]ݬY³º¿9C!®w¥qãÆ­[·nöìÙ³gÏ^¾|ù‚ rŸsþüù_|qÔ¨Q#FŒx÷ÝwwîÜ™Édrr½×Íd2;wîeÊ”îo™^ÿ‹vŸNéñy€¢‰®ˆdÇ5¾ÅSqüÇ¿"ÿOªW[è;i @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ýÄL&Sô3 WV[‚¶!m¢8ŸµÍf³E9§[Ëé–âØíÙáÏÐÉ}Ôó³ÈEÿºT3«-AH[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚¶1¸Ü.“ÉôëW³Ùì@^ 2«-AHÛÕ¯Öd Pi @ÒvÀõq‹5ÙHÚ„´-…^Y“-@á¤-AHÛɱ˚lŠBÚ„´-k®³&[€b‘¶!mKêŠÖd PDÒ€ ¤m©u/µ&[€â’¶1¸Ü¨FöZ€`µ i @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚¶!mBÚ„´ ˆL6›-Ù‹µœn)ÙkîÙáÏ–û @ºíÈ”ûýñŸÒU_¹XmòU±XYJš¶´ƒVÐUzWnµ(@u$c¥(uÚVÄZ—諪éo«-@aª&Ó¯ i›òM4å×èŸj*o«-@Áª)Ó¬4K/Ei[â Õd „¢¤S•¶ÑÈÍÒJWÚ–lI5Ù¡hè$IÒ–¶ÑˆÎJ]Ú–`O5Ù¡¨çÿI]ÚD#=K%i; «ªÉE7÷Æ´ˆF€–DJÓv€¶U“-ŠbþÿRš¶ÑÈЗ޴-úÂj²BÑÊWIoÚD#FXªÓ¶ˆ;«ÉE%_KªÓ I:Òž¶EY[M¶@(úø:Òž¶ÑÓSi[àæj²BQÆ×Wi <•‘¶y/¯&[ MœSe¤-@4"uTLÚæ±¿šl€PÔpo*&m¢‘ªÅVIiÛ¯Öd „¢ƒû ’Ò ÁZT–¶}ÜbM¶@( ¸o*,m¢‘­ÅSyiÛë"k²BѾ}Vyi x-’ŠLÛ»¬ÉEõöGE¦-@4¶*5m¯¹Îšl€Pôn?UjÚD#d VÁi{ÅFk²BQºýWÁi œ-Le§m÷Rk²BѸy©ì´ˆFÔ “ÍúòÁ³yˆi>çIEND®B`‚trusted-firmware-a-2.2/docs/resources/diagrams/reset_code_no_cpu_check.png000066400000000000000000001132461355360272700271730ustar00rootroot00000000000000‰PNG  IHDRžÜ¦}ó×bKGDÿÿÿ ½§“ IDATxœìÝ\TeÂÿÿë „4?œ…K™Ò åLånå-º¶~ ·tÕUªåîöG‹Ù®d~jE‘»½Õµt+ú)MÚÒu7Amõ擱šñ¥† @©(òc¾œš˜q€˜¹x=þqæ:×\ç:3çÌysyæÅh4 Àù¹ôvÛ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$áÚúAæ•ÌÞêGßô¬Ï³½Ýy0j Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h I¸öðö¾úô«3>.ù¬¤©¡i ~`ø#áýî¡;î¼Ã\ýµ kÇ/?fƘ6åe'Ë2Î|µôÕ6åÿõ‹ÿ:wäœÂÅÕÅ7Ø7vnìø…ã»ÖÕ×â^K|.ñ¾¿¯kO@ëÑh[ô·¢·Ÿz;þ·ñ¿ü¸w wÕ…ªÃ[—•…>jí<”úÐÃËnnjþòŸ_¾1û í½Ú°ø0¶ÇÔsÑÖØbÜùŸ;ÿíéûùŠŸ«%AáA¿\ÿK£Ñ(„¨¹\³ké®óÿ{¾Ÿ[¿‘SF>ú‡Gïðh;”{µìêŽgv”ü«Ä;Ðûßžú7³[R„‹«‹‹«Ëð‡†ÜP~¦<,>Ì\ûæÊw-ÝUQ\±ké®þðÑÝ1wÏúó,;½,°•ž»×¶üLùÕo®ÞÿËûÛ”+Š"„xóÉ7û¹õ[qlÅøÒ¥¹¿ÏmßÂ[sÞò ôZU¼jþ»ó¼uÄòæš›Ï8[ýUµ:$l®}såÓþÏ4m˜vÚÿ™öâ‰ɵN¡ç¢íêB¯Ÿyµ_Uy®²ä³’åßݸßp×”ßOùlûgÆc›:_ûú±U¹¹»ùè|žI0·¡×~üœïsÿ1è?6NÛ8î×ãl®}k¶ gÑs7$ 𠄸V~M]híjÙÕ;î¼ÃT>P?°±¡±öÛÚþZ×¹Ó÷Î;½ïTúßíonCýÇCS~?ÅØb¬<_™ýTöž—÷ ý·¡¶oÍvà,znÔög÷þÌ;лðÝÂ6åF£Ñ;ÈûVÝ-uXWñÝ×ß¹º»jjZWó ôºyífSC“úðúåë–7§¸(ƒ†ŠøyDÑÞ"sí[Þ®â¢tcwÐÓz.Ú*.JÒkI‡·þÛ+û¶äÛ¦†¦Š³ï=ÿ^Ég%þwûëÇèsÓrj®W]ßóòžf>Ð&Y:H7Rwð¿ !ššm:dvKFÑÒÔÒ|«¹¢¸âć'Gškßòv=<+¿¬´ã+›RÔ T™W2í½½¯>ýêkÿQòYIó­æ¡G'Ž›w‡Ç×ʯíZ¶ëüÿžïçÚo䔑ýñ1u²ÛÖóÚ~wé»Ï쨻RçÖßÍhÈË̳0¯­â¢xú{ ¯züNŸ;͵o®\qîȹÿûÜÿ½Q}cXܰ_gÿگƳ>ÏÚ£Y€¾©§£-Z#ÚØ?´ Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im Åh4öv:y%ÓN-?ëó¬Z@ïbÔ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$áÚÛ@ÊQz»2ú•±·{¾Ç¨-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´…µÖîáK|¸r—Pf‰3eß?9+ˆ¶:_±o©¨Ù"vÿNlø»ØuôÇFr Enª(þ“ˆ¿W!Þ8(6>%ª6 /¿J\¯Ö‹]ωe;Ä…J³=ilÿ8)ÎWŠqC¿/™¶^¸¹ŠóëDaº8V"R·Z*ÏJÃDV²(ÉÙ lû"€ÞD´E'$†?L›Z$ þw‰A^âó‹âØW¢æ¦˜0üûj3¢E¨¿P¥ɱ"ïÔ-,˜(øñáâ‡ÄÐ_ÌŠU×ŪéBã.â "ìgâxIx9W(³ÄOŠÉkÄüñà=BQ\. ¾™³…g¡õéÓEö'¢Åh¶ÈŠh‹NH!Î]—¾yEbÂ!„ˆ¿Wäù§Eä`á£ù¾Zn¡ˆû£yF ~FlÎU5?¶Ðæf\ÓC»Ðz 凇ýÅõú:ðûÇ…q›hÞ*μ&òO‹´÷„¢ô;¡qþw}_gH€¨oÕ×Í–YmÑ Cµ"x xÿ3ñE…xðn!„ˆ.òO‰§Ebø÷uʯŠÄÊiâb¦¸¸A,˜(Z“*íí<EÅÔ1âƒB!„ÐùŠÚ†tIµpw~žfË….øÈˆ+<:'a¸Xó¡;TÜá*„ã âp±8\üã¶×o !DD°PñÍ‘sÄ–[7ES³¸Õ$N—‰÷?!B1L+¢ï©ÛÄzqùšH{W$Ç Ål¹Bë%ŠËmÙ1àˆ¶èœÄpQqU$üp[­ÿ]"ÄO44ŠXÃ÷%Ã~&Vþ»ˆùƒˆùƒXð¦˜aË­¯þ@¸=)<戉«ÅèP‘•,„Š"v>'êDès"ê"2þ?KåBˆ¥¿ÛŽŸy")ӖݽK1ñk5™Wì•8žõyÖN-;›Ü€Ÿú•#žAôMŒÚ@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[Hµ·;€ô+con=G±W˽»_Àa0j Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶„b4í¾ E±÷& ã¶®>óWv?†€SpµG£dYt2ë'»žt@_eËhK¢… ™’.XÉÑ–D »"ã+u=ÚZŸh{àv^Hà¶GXÖ•¯‘Yj‰³è«Ž1SÀåkd@ÑÙhk9pga·9ê¶mÀ÷¬¶â‰=ƒƒXfU´5)ÈèyÀœÛGÛ“1½‹Ã´gé‡vEi ŒF£Ãˆúúz¥#÷ÜsO7[ŽŒŒÜ±cG§žòùçŸ0 }y|||ë¾Í;W1f̘­[·v³“}J‡Ça‡G,è;ÌNþ匣býû÷¿~ýºº}útNWQQ±wïÞ7ÚªŸo¼ñÆÆ«ªª¼¼¼âãã¯_¿~áÂ…]»v-[¶lðàÁEEEUUUBˆ¼¼<½^èÐ!u911Q¡ÓéöíÛWSS³{÷î 6ìÚµË܆Ìí”SæÝÑA´m3â%ShX°`ÁÀ-Tpuumnn>~üøõë×½¼¼î»ï¾öu¾úê«={ölÚ´ÉÏÏÏÃÃãµ×^Û»wïµk׊‹‹=ú§?ý©ÿþ!!!K–,1·•ŒŒ ¿üë_ÿºm?/^¨í½¶çZ!D`` å C† yçw^ýõ9sæŒ=zÕªUãÇoS§¤¤DQ”ûï¿ßTâååUVVV^^>pà@µpèСæ¶2oÞ¼ÿüÏÿT—nÛOÓCF£ÕjM·k4šëׯOœ8qÿþý 'Nœ5kÖ¹sç***bbb„¹¹¹jŸkjj&NœØaËævÊËËËÜ^8 6·ÞrÓ-}Ù¯‘ ér­øip÷ôô¬¯¯W—[ßWš”””””tóæÍõë×O:õÛo¿U¥õÑBBBE9qâD›ØçâârõêÕ††õöÙŠŠ sÝðôôÔétVöó¶-ZÔÔÔ4qâÄ‘#GVVVæääŒ7ÎÃã¼¼|ÆŒûÛßEY¾|ù—_~Ùá†Ìí”Óéð‹e øÉ }*Œ=úÃ?BÔ××gffª…gÏžÍÏÏohhðððð÷÷7M Õj‹‹‹Õå»ï¾{Ò¤IsçÎ-//BTUUíܹSa0¢¢¢Ö­['„hhh0µioqqq¥¥¥ï¿ÿ~bb¢¢(&LX»v­z7‚ú•²ˆˆEQ¾ù曜œs˜Û)g×§i`ökdò Ù¶±fÍšãÇ9211Ñt×ÁÍ›7—/_àëë»eË–;wªÙhéÒ¥Û¶móññIJJBlß¾=00pܸqžžžÑÑѦ™Þ{ï½¼¼¼ûî»/!!!!!¡gvD£ÑDGGkµÚàà`!DbbbMMºõaÆ­\¹2&&&&&fÁ‚“&M²Ð޹r:ÒºÀœŸÜŒØzˆ‹|çÅ‘ @ßôã¨-iÒ0÷›UóÚŽh Im ¢-$A´€$:޶|©¼C‘‘‘;vìp´¦¬4f̘­[·Z®Óó½²`ú¦£­¬~ÆÆÆÆÞî…µì×Û%K–<ðÀöhÙÁÉz`€öÌÞàìã^ƒaÅŠ±±±ƒáÈ‘#555 . ö÷÷Ÿ9sfuuµZmݺuz½ÞÛÛ;000==]-ì°rJJÊéÓ§SRRôz}rrr›Í™kß`0¼ôÒK&L3fÌÉ“';lªuogΜùàƒšZ.((¸ë®»jkkÛïàòåË'L˜pÿý÷ÇÄÄ©ååååÓ§OÐét‹/®««SË_}õÕ£GvªWNÊÙ]ÐuÆŸ²°Ê¹„………‡‡WWW«þóŸO:µªªª®®î7¿ùÍ”)SŒFcqqñ€¾üòK£ÑxõêÕýë_*ÆQ£Fmß¾½ÃÍ™{JXXؘ1c®\¹b4׬YÛaS­{ûÝwßyxx©«ž~úé¹sçv¸ƒ÷Þ{¯ÚrvvvHHH}}½Ñh;vìOvìØùóç«õGý?ÿó?ê•“’æe)Ú:u2 û¯ÿú/uùÂ… Š¢TVVª¯]»¦(ÊÕ«WÏŸ?ïááñî»ïÖÔÔ˜žh®²Ñ|ò³ð”°°°¿üå/jùéÓ§=<<ÔåöÑÖÔ[£Ñ8{öìÔÔT£ÑxãÆ OOÏ‚‚‚wpýúõ¦‡AAAûöí;{ö¬ÂÔ“¼¼¼þýû777ÛE[kz匤9€@´½!ÁøÓpàÔÿ·¨.”””(Šrÿý÷ëõz½^áååUVV6dÈwÞyçÏþ³V«‹‹;tè…Ê6dù)~~~ꂇ‡ÇÍ›7›šš,÷V1oÞ¼­[·666¾÷Þ{ÁÁÁÑÑÑ>E«Õ¶^.+++--Õh4þþþjá!CêëëMwG´fe¯œK›ÃÕÈ]¶ô1®·­¡(Š“FSÐ Qåĉ^^^mê$%%%%%ݼysýúõS§NýöÛo-TvqéøÖd O1§}S­cYll¬¯¯ïG}ôæ›o>ýôÓæ9þ¼ºÐÔÔtñâÅ   NW[[[UU¥¦Û’’wwwSŠíB¯œˆSÿl¢ƒ(Ó>È:{h¸ûî»'Mš4wîÜòòr!DUUÕÎ;…gÏžÍÏÏohhðððð÷÷wss³PY¡Õj‹‹‹­oßsM™Ì›7ïüã§Ÿ~:{ölsu6mÚtêÔ©ÆÆÆU«VyxxÄÇÇ6,:::55õÆ—/_NKKKNN¶>°Þ¶W«ý!꤀îè8ôÈ—n·oß8nÜ8OOÏèèèÇ !nÞ¼¹|ùò€€__ß-[¶ìܹSÝÍ+ !–.]ºmÛ6Ÿ¤¤$kÚ·ÀBSªäää3gÎüâ¿0Ý]ÐÞÂ… Ÿzê©þýïÿðÃÝÝÝEÙ¹sg]]]hhhTTTDDDFF†õ¯Òm{å˜Èµ@eéfƒã,¡¡g477½õÖ[?üp‡ Ú5küñî˜Cá­Yú¯ê#‚¢(Î>‚ë¶lÙâåå5yòäÞ2w’kèËnó525(´Ïj 1ÂN|||4MNNŽS¯ËNÌýeÅѬýÀÂH-‘=ƒƒXfí  : n‡«”Ø®WÀ,`ÆmäZð½ÛÏkÛš¹ûT¦r¢ºï¶,·õLG€Óè\´UY¸íW‘ta ëþ µ C]‰¶ªÛ\Ëu¾}G÷ïZ!Ô ºmU¦`ÚåÔÂMº¸--°Fw£­IëÁWÒ*º8 :ËfѶµ6÷ta ²,è&»DÛ6,ßMKðí;¯À®z"ÚZÖaðͼ’i§Í=ëó¬Z¶Rë(ß·¾B—Ãß0À¾øWH‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$áÚÛœ¢(Zk4íÙ™1jk_ŠªäZ€î Ú@D[»³r,–![€n"Ú@DÛžpÛY†lºh Im{ˆ…qY†ll‚h Im{N‡£³ ÙØ Ñ’ Úö¨6c´ ÙØѶG)Šbá!ºÃµ·;Ð'Xˆ°¦UŒàtÑÖŽ:5(KÆè&¢­íuó62.ú&îÏA×ðQ‰öøBÑËn{ìí#F£1ÆÖÇÅ÷ˆ¶VéDÛµÖȸ­%&&ž:uª²²R}˜——7bĈüü|õa~~¾Á` ´¦)£ÑØØØh¯ŽºÄÂ%ÏÊP…sÛwÄN†hkI¯$Ú®µOÆBŒ5ÊÏÏOͲµµµ'NœX¶lYëh› .gdd„……yzzêõúÕ«W›Z0 +V¬ˆ5 GŽ1 k×®õððˆ‰‰)++[³fÍ Aƒüýý322:ìÙ3g|ðA//¯qãÆ©…åååÓ§OÐét‹/®««³Pž’’rúôé””½^ŸœœlŸ— œåPÛÃA§X¸¶ÝѶ’h»¶Å¾œqE‰?pà€âŸÿüçèÑ£'OžüÉ'ŸÆ–––O>ù$11Q­©ÓéöíÛWSS³{÷î 6ìÚµËÔHnnnnnnqqq||¼â7ÞØ¸qcUU•——W||üõë×/\¸°k×®eË–]¸p¡}6mÚôÖ[oUWWOžôÍŒ›˜˜¨Óªc´þþþƒ úüóÏ;VSS3aµڌ3BCCE‰ŠŠJNNÎËË3µ°`Á‚š.^¼xĈ ˜5kVUUÕªU«4M\\\XXØñãÇÛw`á…ÇwssKKK«¯¯?xð`qqqAAAff¦§§§V«MOOÏÎÎnii1WnçWœ ¡V2¾w6L,D[gJ´í‘qÛHLL>>III6ì8/9.ÍèP›7·›±DqÌc%óJ¦MÚ¹m–U9æ‹`sÖ+v|)rì Õ'Þ>éµ>>ûÈ)‰.ãh‘^› ïr_`«7]ÎÚ%ÑvÈ´¿2. @ï"×öMF£±õ[¯(]~•*Ú’h­dMÆm½ÖÑ_1ûp||HÍÑ/@°©6é¶kdˆ¶$Ú.“-㜜2«·{‡Ñµ['޶Ö$Z¢˜•ȸGõ¦êþÀ­óE[­]‘q½¥õ-׈. Ü:Íä_ÖÌÞ%ÓÔ]½ÎÊSÊéÀ6âããÓÒÒzf[‘‘‘;vìè™m蔵k׆‡‡›®\¹RQ”3gΨOž<©N—n¿ÄÇÇ«×\77·{î¹gýúõ]nÊ‘?jºä=Ú’h{›Ñhlllìí^Np—mbbâ©S§*++Õ‡yyy#FŒÈÏÏWæçç †6¿ÖnN—Ï»^x¡±±±¦¦fÆ K—.ýøã»Ðˆsél´pÐhK¢u@d\@¡Õj>¬.0@]6 k×®õððˆ‰‰)++[³fÍ AƒüýýM?Æa0–/_>a„ûï¿?&&¦¨¨¨Mã)))§OŸNIIÑëõÉÉÉBˆòòòéÓ§ètºÅ‹×ÕÕµyÊ»ï¾;jÔ(uù™gžqssSo/''çBddd„……yzzêõúÕ«W›žh0V¬Xk0Ž9bMÿã˜÷Q£Fùùù©Y¶¶¶öĉË–-kmM¿d¿óNQWWWGydذa¦sŸ–·ÿ¨q4Ý9+ÚZ“ŠH´½ŽŒ tè7ÞØ¸qcUU•——W||üõë×/\¸°k×®eË–]¸pA­óÁìÞ½û³Ï>›?þ”)SZ·••5|øð¬¬¬’’’ììl!Ä´iÓÜÜÜΟ?_XXxìØ±ÔÔÔ60aBQQQUU•"//O¯×:tH]V\Z§ÓíÛ·¯¦¦f÷îÝ6lصk—é¹¹¹¹¹¹¹ÅÅÅñññVö°Ç²B(ŠàÀ!Ä?ÿùÏÑ£GOž<ù“O>1---Ÿ|ò‰éÝí}Þ566þãÿ8þü¸qãÔsŸ–·ÿ¨qpÊmI´Nªs×>¶€îX¼xñˆ# 0kÖ¬ªªªU«Vi4š¸¸¸°°°ãÇ«uæÏŸïíí-„xòÉ'›››(ÌVXóâ°º|ôf´%ÑJÃÚŒ;ëûèkúÈûnºÇN£ÑhµZÓCõ&!„V«5Õ×jµeee,--Õh4þþþêÃ!C†Ô××WWW·©6qâÄýû÷çåå%$$¨ËçΫ¨¨ˆ‰‰BäææÆÅÅ…„„ =¹_=@ŽßdèСÁÁÁï¿ÿþ_|¡Ž˜ÆÇÇççç8pÀt7Bœw...ƒaêÔ©|ð0ÿYaá3¤õGdznÇH´} æ8û;>zôè?üPQ__Ÿ™™ÙÙ§oÚ´éÔ©S«V­òððPo¶kM«Õ«ËÆ ‹ŽŽNMM½qãÆåË—ÓÒÒ’““Û_âââJKKßÿýÄÄDEQ&L˜°víZõ*«ŽúDDD¨såäät~pö¿µ„„„5kÖŒ;öŽ;îBŒ?þðáÇ6E[»žwF£±©©éÖ­[§OŸ~ÿý÷#""„ùÏ Ÿ!­?j$c÷hët‰¶g&³Ç|r·nÝúÝï~7xðà;ï¼3&&æäÉ“¶m¿kȸèӽݦ±5kÖ?~|äÈ‘‰‰‰ãÇïl; .|ê©§ø÷¿ÿýÃ?twwoSaéÒ¥Û¶móññIJJReçÎuuu¡¡¡QQQ~iZ£ÑDGGkµÚàà`!DbbbMMúMíaÆ­\¹2&&&&&fÁ‚“&Mêôž¶cîÄw®_jHLL¬¨¨0M†àïïÒÐЫ–Øõ¼[½zµ›››‡‡ÇĉG••%„0÷Yaá3¤õG »g[]íîÊóZÕ®=pÌÃ7>>>&&æøCccã¦NúÑG=ôÐC]h*22rÙ²e3gÎìÔª.»víÚºuë~ýë_{yy=õÔSÿû¿ÿkÃömÅÊ£Ó¸ÍÞAϱœbÕ÷Ú‘¯m‘‘‘¿þõ¯Ÿ}öÙn¶c0Ö¬YóøãÛ¤W}Yë>+–5'~ûšŽvú£wýäd·îذ娭Ҋ…j5FÛ!{O×fUVV–z¿Žª  à®»îª­­ægÁ¬©©Y¸papp°¿¿ÿÌ™3Õþ¼¼¼^zé¥Áƒ{{{GFF:ìW ÇEŽüFߺu+??¿¨¨(::º·ûHÅ‘O|87c·õ؆zÆøñãÕ¯Þºuëïÿ»‡‡ÇÿûÿO]5vìØ'žx¢¦¦¦¼¼|ìØ±óçÏ·\>jÔ¨íÛ·w¸•Ö«¾ûî;¢¢"õáÓO?=wî\u9,,ìÞ{ï½råŠÑhÌÎÎ ©¯¯7?ÿùϧNZUUUWW÷›ßüfÊ”)­ß³g¯¯¯:ÓžS°ëgÔÛ‡äfΜ˜žžn“ÖÂÂÂvïÞm“¦ú¸Þ>BaG½}pÁ±táØèú1$ë1Úææ¹çž{N-?{ö¬¢²²R}˜——׿ÿææfsåF«£­Ñhœ={vjjªÑh¼qㆧ§gAAZ¶~ýzSµ   }ûö]¸pAQÓ¯]»¦(ÊÕ«WՇǎóòò:tè^e£F8½Þ>áèzû…õöÁÇÒ…c£ë7$´ßd‡œñ÷¨z~Ò¸yóæmݺµ±±ñ½÷Þ ný_ŸígÁ,))Qåþûï×ëõz½>""ÂËËË4;æ¾}ûââââââºó ôzóÍ7Ÿ~úéÖ«ÚÏ‚¢(ʉ'¼¼¼Ú·õ¿˜ÜÜÜlÒÚ’%K"##mÒ`'¾‰mÏßÖúø¹Ü?´+Á8nزe‹——×äÉ“{»#6Ã-ÌqüwüÌ™3>ø ——׸qãl>³µ035µÂ`0¼ôÒK&L3fŒú›‚í›2 +V¬ˆ5 3gÎììÄØæväÕW_=zôh§zXÏÊßÁc€¹“WØúüm­ÏžË]ø½Ñ3ÑÖ„ŒkŽÏªU«þò—¿Xøæ™³ ÑÂgyÓ7mÚôÖ[oUWWOžTN^aëó·5ÎeëõN"ã¶qåÊ•ÒÒÒö3v={ÖY~““D Ëœë}_¸páðáÃÝÜÜÒÒÒêëëZXXh®‘  8P¡Þ²ÿæ›o !jkkß}÷ÝÖ÷5™Z{òÉ'›››-ìHûMXÙÀç:ñoËòÉ+l}þ¶Æ¹l=;Þkk '½&ÖÞGk4ŠùÿD9NwmÓëõêB¿~ý‚ƒƒËÊÊ\]];5³µ…9øLSS›JÔ©©ÕéüÔ©…7oÞljjruíàƒ:00дy…­ÏßÖ8—­ç(ûFÆu.H´€ºxñ¢ºÐÜÜ|éÒ¥   Îlmyjêµoªõ9Ø©‰±-t¸k=lNQǼ|táäÝ8[ëƒçr—ÿÓÞávL½Qaýw·ùšß¹WÁ¡X{×u7œkãÆgÏžmjjzå•WÜÝÝãããM3X߸qãòåËíg¶nS.ÌÏl}÷Ýw«SS——— !ªªªn;aŸ…I²UêÄØŸ~úéìÙ³[—oÚ´éÔ©S«V­R'ƶÐakܶ'@×8ÅoN^Ñó·µ>~.w*Q8\´5YÿÝzõŸåjdÜ@¢E_3oÞ¼äädu(EOÚ¶3[[˜šºCšRY?1¶…[ã¶=äÖÙ“WtãümsÙz:æŸy¥ƒ[Ÿó}Κç:æ9#ßuÀ½¶°¨õqwVsssPPÐ[o½õðÛ Ú5kœå«¨ò“)œa´Öhóëe}çs Ãó·5‰Ïesº6í—ÊQîµµ†i×rÆå~Ün²×}´¿âí€E³øã§ëä›»øl‘…ñWŽ>©­ôéóל)Úšqío†NÊÇÇG£Ñäää8þ÷Bë9ì—Él‹ó·½nþ…ã ÇM‡7$XfÍí Ž¹³½‹D Ñÿ~B_ÃÑ"±6W%Þß¾¦û€SŽÚvÈš¡\ÆqMH´d4ûæm h¯k!DžhkBƵ€D p"}䶨lòW„ÑÖ„ŒkB¢8‹6·¤Û>ÂV÷¢ÈmMúlÆ%Ñœ鶯±á=Ö}ëëxë¿[Ûßà7 ø…€dœúº Ëlûæö‰QÛöLyΫét㸌ѤÑþûdŒÝJ©}zéæ»ÜG£­‰—D éVz6ϵ‚hkât—D ^‡éVpus~Æ›¼­DÛ¶<ã’h}J‡3Ý2|ëÔì—kÑևʸ$Z@Ÿ¥^ݾ•€]C­Šh{{½˜qI´¨Ì ßšÖöx`- yÆæoѶ:•qE7Þ--íu8|«"ã: ËyÆNïѶ+¬É¸¢ó§‰P1% :¾5áÄ)Ø/Ìm»Å&—D @§X¾…ƒ³wž!ÚÚFg3nZ­Yyñ…#è±¢mÏiŸ_íšhUýë_GUPPPYY¹uëÖÊÊÊ'NØu£½‚h+³–––E‹-Z´hõêÕaaafÔ¨Q›7o;v¬¢¼¼|úôé:nñâÅuuuí[¸téÒäÉ“½½½ÃÃÃ9Òã{Ð D[™•––Ξ=»M¹zûï´iÓÜÜÜΟ?_XXxìØ±ÔÔÔö-LŸ>]§ÓUTTìÝ»wãÆ=Ñi€®"ÚʬªªJÔ~UqqqAAAff¦§§§V«MOOÏÎÎniiiSçèÑ£úÓŸú÷ï²dÉ’ê7@—meæïï/„(++k¿ª´´T£Ñ¨„C† ©¯¯¯®®nSgàÀ>>>êáC‡Ú¹¿ÝB´•Yxx¸N§k?ÝÑhÔétµµµê°®¢¤¤ÄÝÝÝÏϯuµ   «W¯644¨+**z Ï]F´•™‹‹Ë믿þú믿øâ‹.\hhh8uêÔoûÛ‚‚‚aÆEGG§¦¦Þ¸qãòåËiiiÉÉÉ..?9 CTTÔºuë„ ™™™½´V!ÚJîÑGÝ¿aaáèÑ£}}}Ÿxâ‰ÈÈHEQvîÜYWW‘‘‘Ñþéï½÷^^^Þ}÷Ý—Ðóý°žâ˜?Ú‘yÅ^„Ïú= @§Ó-^¼¸®®ÎByJJÊéÓ§SRRôz}rrrïì €ED[ùmÚ´é­·Þª®®ž|¸››[ZZZ}}ýÁƒ…ÅÅÅ™™™žžžZ­6===;;»¥¥Å\yoïÀímå§×ëÕ…~ýú—•• !JKK5¿¿¿ºjÈ!õõõÕÕÕæÊ{£ãC´•ßÅ‹Õ…æææK—. !t:]mmmUU•ºª¤¤ÄÝÝÝÏÏÏ\¹ÂÅ…£84Šü6nÜxöìÙ¦¦¦W^yÅÝÝ=>>^1lذèèèÔÔÔ7n\¾|9---99ÙÅÅÅ\¹B«Õ÷òΘG´•ß¼yó’““}}}?úè£?üÐÝÝ]¡(ÊÎ;ëêêBCC£¢¢"""222,” !–.]ºmÛ6Ÿ¤¤¤ÞÜ3£ÑØÛ}è@æ•L;µü¬Ï³vjÙJŠ¢˜–óŶ—£Ü¾Žʬ—Û¬kùWĉ1j Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@®½ÝÉ)ŠÒ©µF£ÑžÝ£¶öETè1D[BènH°;£Ñhù¶Ð7)³:·Ö¸Í~}‘£¶Ž‚![úšNEUr­5ˆ¶=Ø Ðˆ¶ì @ßdåX,C¶V"ÚöÂ+€½m{©€¾ì¶#² ÙZhÛsˆ°vE´íeä]`a\–!ÛN!Úö(‚,€ým{I¨:eȶ³ˆ¶=8 `'ŠM’?$ {ãO€s˱*,µþq]k‡lÅ%òGD[8¢-8/rìÍ”¸!’ Ú@®6o‘ÿ8†­ðX SlmÌa ¶Òá7$@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@D[H‚h Im ¢-$A´€$ˆ¶Ñ’ Ú@ŽmãããÓÒÒZ—ètº­[·v¹ÁÏ?ÿ|À€ÝîWçŒ3æ¶}n]'22rÇŽ]{º5•;Ô…ऎ92eÊ___F3räÈ´´´ÚÚZ!D||¼¢(Š¢xzzŽ;6??_­¯ÓéÞ~ûmÓÓ›ššE9xð`›f;uÉîÎåÞÊú’ûŠïèѶ›ŒFcccc¯7¾dÉ’x Ëu¬yz×*÷@;8š¿þõ¯‰‰‰£F*((¨¬¬Üºukeeå‰'Ôµ/¼ðBccã×_óØc}ûí·Ö·Ü+~g¯¼\ñ;äÜÑ6###,,ÌÓÓS¯×¯^½ÚTn0V¬Xk0Ž9réҥɓ'{{{‡‡‡9rD­óî»ïŽ5J]~æ™gÜÜÜ®_¿.„ÈÉÉQß`+¯©©Y¸papp°¿¿ÿÌ™3«««Û÷óÕW_=zô¨éé/½ôÒ„ ÂÃÃÇŒsòäÉ6uRRRNŸ>’’¢×ë“““Û<Ý\¯:ÜÖºuëôz½··w```zzº…,o´¼¼|úôé:nñâÅuuu–÷‡ÕÒÒ²hÑ¢E‹­^½:,,L£ÑŒ5jóæÍcÇŽU+(ŠâêêêããóüóÏ߸qãìÙ³Ö7nºzZ¸Dªuºy¹\ñÍpîh«ÓéöíÛWSS³{÷î 6ìڵ˴*77777·¸¸8>>~úôé:®¢¢bïÞ½7nT+L˜0¡¨¨¨ªªJ‘——§×ë:¤.'&&Zßø¬Y³._¾|üøñ¯¿þÚËËkΜ9·íöž={vïÞ]TT4}úôE‹µY›••5|øð¬¬¬’’’ììlëw¹/¾øâÅ_Ü¿ÿÕ«WÏœ9óÈ#XhÁòF§M›ææævþüùÂÂÂcÇŽ¥¦¦Z¹/8𢢢ÒÒÒÙ³g·)W¥MÉöíÛÝÜÜî¹çž®m¨g.÷‚+þO9A´ÍÈÈðk¥¼¼Ü´jÆŒ¡¡¡Š¢DEE%''çåå™V-X°`àÀBˆâââ£GþéOêß¿HHÈ’%KÔ þþþ#GŽÌÏÏ///¿råÊÂ… Õ§›¢­5õÕW{öìÙ´i“ŸŸŸ‡‡Çk¯½¶wïÞk×®YÞ£ùóç{{{ !}ôÑÂÂÂN½zÕ†««kssóñãǯ_¿îååuß}÷u¶UqqqAAAff¦§§§V«MOOÏÎÎniiéþ¾ÐóÔQ­   sÖ¯_¯Õj °~ýúwÞygРA]ÛPÏ\îWüŸr‚h;oÞ¼Ï[ 0­ÊÍÍ‹‹ wî\EEELLŒ•—””(Šrÿý÷ëõz½^áååUVVfyüüüÔ›7o655YÿjXèUC† yçwþüç?kµÚ¸¸8uLºS-¨JKK5¿¿¿©ÙúúzÓ}ÝÙzžzE³p±VƒGEEÅÅ‹gΜ©º¹¹µþ‚Í­[·ÔB ê™Ë½àŠÿS®½ÝÛóôôÔét¦‡ýúõSÊËËg̘ñ·¿ý-!!AQ”åË—ùå—¦j¦ÿV ºzõjCCƒ»»»¢¢¢ÂT'11qÑ¢EMMM'N9rdeeeNNθqã<<<¬l<$$DQ”'NxyyÙp—]\:þ“Ãr¯ÚKJJJJJºyóæúõë§Núí·ßVTT˜kÁÜFu:]mmmUU•z¬—””¸»»›ŽoœKxx¸:ÛRdddër£Ñ¨^ß5V«mó,½^ßúš{îÜ9!Dhhhwzb«Ë½àŠßŠŒÚš£~ë+""BQ”o¾ù&''§Ãjƒ!**jݺuBˆ†††ÌÌLÓª¸¸¸ÒÒÒ÷ß?11QQ” &¬]»V½ÁÊÆï¾ûîI“&Í;W½M¢ªªjçÎÝß5­V[\\ܾÜÊ^©Îž=›ŸŸßÐÐàáááïï¯þei¡s6lXtttjjê7 î°Š IDAT._¾œ–––œœlî¬ÀÁ¹¸¸¼þú믿þú‹/¾xáÂ…†††S§Nýö·¿-((°ð¬9sæ¼ñÆüq]]Ý… žþù‰'šþ·klr¹\ñÊɺÛÚ°aÃV®\³`Á‚I“&™«ùÞ{ïåååÝwß} ¦rF­Õjƒƒƒ…‰‰‰555jëß¾}{``à¸qã<==£££>Üý][ºté¶mÛ|||’’’º¶ËBˆ›7o._¾< À××wË–-;wîTÅB æ6ª(ÊÎ;ëêêBCC£¢¢"""222º¿ô–G}tÿþý………£Göõõ}â‰'BBBÚ â¶‘œœüòË/ÿîw¿óóó?~|ppðmçmÙär/¸âÿ”b4mÐJ«/Ú¤A@p\€,ø<‡=tx\9ñ¨-ÐÑ’ Ú@D[H‚h Im ‰>m92eÊ___F3räÈ´´´ÚÚZ!D||¼¢(Š¢xzzŽ;6??_­¯ÓéÞ~ûmÓÓ›ššE9xð`›fÇŒ³uëVË›n]'22rÇŽ]~º5õ;Ô…í8#ù£í_ÿú×ÄÄÄQ£FTVVnݺµ²²òĉêÚ^x¡±±ñë¯¿Ž‰‰yì±Ç¾ýö[ë[^²dÉ<Ðå:Ö<½;õíÝ€£‘<Ú¶´´,Z´hÑ¢E«W¯ Óh4£FÚ¼yóرcÕ Š¢¸ººúøø<ÿüó7nÜ8{ö¬õ¿úê«GU— ÃK/½4a„ððð1cÆœ}ú¢E‹Ú¬ÍÊÊ>|xVVVIIIvvv›µ:nß¾}555»wïÞ°aî]»,lè‹/¾xñÅ÷ïßõêÕ3gÎ<òÈ#±°ÝiÓ¦¹¹¹?¾°°ðرc©©©Ö<ÚVUU !‚‚‚ÌUX¿~½V«0`ÀúõëßyçAƒuy[óçÏ÷ööB<ú装……zîŒ3BCCE‰ŠŠJNNÎË˳PÙÕÕµ¹¹ùøñãׯ_÷òòºï¾ûºÐHqqqAAAff¦§§§V«MOOÏÎÎnii±Éîô ¢íÛo¿­ü Í*!DYY™¹çΛ7ïóÏ?¯¨¨¸xñâÌ™3ÕB77·ÆÆFS[·n©…–»áçç§.xxxܼy³©©Éú]ÈÍÍ‹‹ ·¦æ½÷Þ{î¹çd2Ù(;#•J+++-·wwwB¢¢¢(ŠzôèÑ©S§l×SQQqéÒ%FÃår% =œl£«í†……%%%­_¿¾§§§¥¥eÓ¦M™™™ƒ…o€)Áù£ÌÒ¥K¿ÿþû¢¢¢øøx//¯•+WÆÄÄØØ%33óüãïÿ{±X¼pက€!ã¦=6lØpòäIOOÏ´´4Óíaaa[¶lIIIIIIÉÎÎ^¼x±ízÔjõÆ}||¼¼¼Ž9’——GQ”J¬¶KQT^^^___ppplllTTÔž={FŒ“ˆò»o»j1™ä:&¼¯œþžÃx°ú¾rþQ[xJ Ú€“@´'h NÑœ¢-8‰©mSSSé;ë …ÂäääK—.ÑÛ,ï=f&&&æÌ™3ÌÓ’’’¨¨(ŸeË–_‡íéSƬ‡ÃÚ×ÎòV ]Ç1U£-!ä£>Òjµ>LIIY¶lY{{ûÈê9zôhtttkkë¹sçì)o4µZíp[ùàƒæÎ;²2öì;šòã]ÀĘÂÑ–¢(‡ãééùÞ{ïõôôTTT˜سgOxx¸P(”ËåÛ·o§7æää”——çääÈåòÌÌÌÿþïÿþꫯ¾ùæ¹\þ—¿ü…¢T*_yåÿµk×öõõÑ;*Š?þxþüù …âÆ …âÓO??>—ËMIIijjÚ¹s§¯¯¯D"±z[¯]»vݼy“©ê“O>Y´hQdddBBÂÝ»wM˘õÐl_«e£­½{÷Êår™L¶mÛ6ûÏŒY=6N‹Õc˜xœÉîÀ8}ú´‹‹ËŒ3̶ûûû_¸pA.—ß¹sgÉ’%áááË—/?pàÀµk×>üðÃ+VÐÅ(ŠòððøóŸÿL?]¾|¹\.¯®®îííýÍo~³~ýú/¾ø‚~)??ÿÊ•+ÞÞÞôÓ£Gþío JOOOMMMOO¯©©¹uëÖsÏ=÷ÒK/…„„ØèsAAÁ?ÿùO?ýéOkÖ¬ù׿þżdÙÃ!j°Vªªª6oÞ\\\Ÿ¿`Á‚ðððââbÛ ­ZµÊÃòtéÒ¢¢"ûzXÅápôz}qqqww·H$Š‹‹A%d¨Ó2âc[Žm;FýÄj·ÞzëÎ;ÍÍÍõõõVóóó,Xtøðá¶¶¶!mlläóù‰„~Òß߯R©è§2™Ì´0ó”ÏçK¥R‹Å<íîî¶ÝX,¦p¹\µZ­Óé†ìÛ*$$$77÷óÏ?—J¥ ,¸zõê*!C– <…(€1bõ æ¸Ñ6++Ëø«è@)¬¾ªT*ÓÓÓ·lÙR_____ŸÍÔÃdPKþþþ½½½LÔ«««sssc¢Û`'qÌ ÖC5˜´´´Ë—/«Tª%K–¼üòËF£qgÆöipŽmG‰7ŠŠ¢(êÑ£G§Nb^’J¥•••V÷ KJJZ¿~}OOOKK˦M›233mDáq2Xm”U—.]Òh4\.W"‘¸¸¸Ø®d°vä´Øæ´é$,,lË–-))))))ÙÙÙ‹/f^Ú°aÃÉ“'===ÓÒÒÌö¢(*//¯¯¯/888666**Êêrãm°Ú8(«ÔjõÆ}||¼¼¼Ž9’——GQÔÎŒƒœÛ¨!¿Ñ¶«“oêǤB‚÷8“SvMk¤2~~lEQß}÷ÝpwT(ùùù–ÛNœ8A?މ‰9sæÌÈ:6š}m÷ÊžíV ˜uiÈ}ÍÊØSÞª´ 0Þ.Ú ?~<::úÈ‘#V F­V;¬:?øàƒ¹sçŽEï†g]%vôÖFáéX™É:æ.Úž;wÎh4~ùå—çÏŸonnf¶+Š?þxþüù …âÆï¼óNPPдiÓâââ˜ÛÃÖÖÖ.\¸ÇãÅÇÇß½{—Þ¸k×®›7oBrrrÊËËsrräryff&!¤««kõêÕ‰dÅŠ*•ŠÞŲ~Ë}¥Réõë×éòEEEÀjW÷ìÙ. årùöíÛ‡<Lo Å'Ÿ|²hÑ¢ÈÈÈ„„{‡y‰bO»¦å÷îÝ+—Ë=<|øìÙ³íííf%CCC/^üöÛo+•J£ÑXZZjÌ•J¥Ì5gt=o¾ù&½{[[[^^žúM÷%„ÄÇÇŸ?žÒßß¿ÿ~«ÍuwwB¢¢¢(ŠzôèÑ©S§†uN†u8£i·¢¢âÒ¥K†ËåJ$Û• ÖnXXXRRÒúõë{zzZZZ6mÚ”™™9X[”9¾üòËåË—ÇÅÅùÿ$++Ë××777ײð™3güüüE"Qff&Âì±aÆ“'Ozzz¦¥¥BNŸ>-“ÉæÍ›' “’’˜¬Öo¶ïÎ;‹‹‹çÌ™óì³Ï.\¸Ðjsaaa[¶lIIIIIIÉÎÎ^¼xñÎŒý‡3âvÕjõÆ}||¼¼¼Ž9’——GQ”Jk—¢¨¼¼¼¾¾¾àààØØØ¨¨¨={öŒáñØ@É÷ã¦gÇö wxšá}Î㔕«Œ,Q??6ž´¯æÿ¿ȟ9Ш-Àh Ú€“@´'h NÑœ¢-8 D[pˆ¶à$mÀI Ú€“@´'h NÑœ¢-8 D[pˆ¶à$mÀI Ú€“@´'h NÑœ¢-8 D[pˆ¶à$mÀI Ú€“@´'Áó)Šó:†„Q[pˆ¶à$mÀIŒÍ\[£Ñ8&õ0ö?Ù?¶2Þõ|wœj¶“é\ä1?o0…PÃ{Õxrüúâ$0j 09UÇ¢-À€lD[€IƒÀ:¶m°m&bëB´phȾöC´˜d¯cÑÀq!õ ¢-ÀäC„ˆ¶ yw¸m‚ìè!Ú8"$Ý@´pˆ³£Ä™ì€Ó¢(j²»0…Qö•ËÀIþFmÀI Ú€“@´'¹¶0ŒFãdwœ“é”nŒÚ€“@´'h NÑœ¢-8 D[pˆ¶à$mÀI Ú€“@´'h NÑœ¢-8 D[pˆ¶à$mÀI Ú€“@´'h 0 ©©©EQ% “““/]ºDo///ñÅÅb1ÇS(6l`v¹qãÆ /¼àååÅçóçÌ™³iÓ¦ÞÞ^ºªM›6²?111gΜe%NÑ`x>úè#­VûðáÔ””eË–µ·· †_ÿú×2™ìîÝ»*•êÌ™3!!!táo¾ùæÙgŸŽŽ.,,lmm=qâDkkkIIÉ䂳B´Š¢8ާ§ç{ï½×ÓÓSQQñèÑ£†††uëÖùùùñx¼˜˜˜U«VB Ú5kÖ¬Y³}ûöððp>Ÿ}øðáäädõïÝ»W.—{xxÈd²mÛ¶Ñ»ººV¯^ ‘HV¬X¡R©!999ååå999r¹<33“"•J¯_¿NïRTT$èÇ …bãÆ‹-JLLLII)--¿ó3‰mFèôéÓ...3fÌÉdaaaÙÙÙýë_>|È(--mllüíok¶#EQƒÕYUUµyóæï¿ÿ¾££ãÞ½{Ï?ÿ<½=##£¥¥¥¸¸øáÇ"‘(++‹ràÀˆˆˆÔÕÕ?~ÜvoÏ;wöìÙÿû¿ÿ[µjÕ /¼ ÑhFvÔŽ Ñ`xöíÛ'•JÁ¾}ûrss}}}Y,Öµk×æÍ›·k×®ÐÐЙ3gÒó_ÛÚÚ!Ó§O·¿r‡£×ë‹‹‹»»»E"Q\\!¤¶¶¶  àСCb±˜ËåîÞ½û»ï¾ëììV·W­ZåááAyýõ×õzý•+W†µû”€h 0²zŽ=ÝÚÚzîÜ9{ÊF­V;²¶ÑÀ Š¢8ާ§ç{ï½×ÓÓc¹ÂÀž={ÂÃÃ…B¡\.ß¾};½1''§¼¼<''G.—gffþ÷ÿ÷W_}õÍ7ßÈåò¿üå/„¥RùÊ+¯øøøøûû¯]»¶¯¯ÞQ¡P|üñÇóçÏW(7nÜP(Ÿ~úéüùó¹\nJJJSSÓÎ;}}}%Éž={,{»wï^¹\îáá!“ɶmÛFoìêêZ½zu@@€D"Y±b…J¥²ì!!D*•2÷6+**L—6nܸhÑ¢ÄÄÄ”””ÒÒÒ±=Ãã‹M£Ñ8Ø·²pd§OŸvqq™1c†Ùvÿ .Èåò;wî,Y²$<<|ùòå¸víÚ‡~¸bÅ ºEQþóŸé§Ë—/—ËåÕÕÕ½½½¿ùÍoÖ¯_ÿÅ_Ð/åçç_¹rÅÛÛ›~zôèÑ¿ýíoAAAééé©©©ééé555·nÝzî¹ç^z饦'UUU›7o...ž1cFggguu5½=##ÃÅÅ¥¸¸˜Ïç¯[·.++ëÛo¿µì¡ çÎûá‡<<âN DÛ eö˃![€)Š7ŠŠ¢(êÑ£G§Nb^’J¥•••V÷ KJJZ¿~}OOOKK˦M›233mDa;UTT\ºtI£Ñp¹\‰DâââB ]¼xñ›o¾©T* !mmmyyyV{þüyBHÿþýûMk>tèPYY™V«Ýºu+—ËMMMeWÇ¢-À°………mÙ²%%%%%%%;;{ñâÅÌK6l8yò¤§§gZZšÙ^EåååõõõÇÆÆFEEY]î`¸ÔjõÆ}||¼¼¼Ž9’——GŸ>}Z&“Í›7O(&%%1Ë ˜õpçÎÅÅÅsæÌyöÙg.\hZóêÕ«ßxã ooïüãçÏŸwðkÈ!”cî²èB#ò®ç»ãT³mÌ´ëE‹1/_¾L?püÏ@#`ú »cF°A¡Pìܹó¥—^šìŽ Áôm†Å¿Æ—2ÅqáiæøÞ‚ƒÀŸJ ¢í¸°úÚòo1½Å´02.Àˆ!ÚŽ%;í`qÞó`†ö&’å Ø¢í°üS;²ÿͦ{1u"ãØ ÑväÆ*ÑZe9”‹Œ `¢í°k¢µ„Œ;¤ÞÞÞššš®®.½^ïîî.‹Mo«=zzzŠ‹‹çÏŸ?æ5wvv>|ø°³³Óh4Ò‡Èf³ïܹÓÑÑAa³Ù|>?88ØÓÓ“RXXÌÜ9Æh4^½z5&&†¾G"€Óú¶v¹b‚Ù˜ú“‰éƒesV{õ´1?þø£››[bbbJJJDD„»»ûdwjv.£R©JJJø|~\\ܼyófÍš500ÐÓÓC¿´páÂääd‘HTZZªÕjdzËNåý÷ß§(ê»ï¾îŽ …"??ßr{BB‰'èÇ111gΜYÇF³¯ƒþßM IDATí^ØØvi`ÔÖ–‘]6ÞpÙ™©FãïïïêêJÌu:]MMM{{»Á`ðôôœ9s&}wzûãǵZ-—ˈˆàñx÷ïßïèè`±Xô¸/›Í&„ܼyÓÇǧ££C«Õ²X,…BÁçó !¦²²²««ËÍÍÍô–ß J¥R£Ñ¸¸¸øùùÑÛoÞ¼)‘Hèzø|¾F£‰‹‹£_êêê*))™7oÝ"Íh4Þ¿úôéÌ´@ 7=vŠ¢8N@@@CCC__ŸH$Ÿs àTŽ?}äÈ‘çŸÞ²€ÑhÔétô¿ ;}ðÁ111c×G{ «N£¶VX à1Z{XíÒÓ6ŽëêêÊãñªªªZ[[™û_ÓîÝ»700œœÌáp˜Ë<ËËË5Mllì3Ï<3kÖ,:P–––R•””ßÝÝÍÜ2›ÒÞÞ™˜˜(‘HªªªèeeennnóæÍ›3gΣG˜ÂnnnQQQóçÏŒŒljjbîNQ©T‘‘‘sçÎ ïéééíí¥·+•JÓ\KéííÕh4¾¾¾CžÖÖVŠ¢¸\î°ÎÀSëܹsF£ñË/¿<þ|ss3³]¡P|üñÇóçÏW(7nÜèèèxçw‚‚‚¦M›ÇÜ–¶¶¶váÂ…</>>þîÝ»ôÆ]»vݼy“’““S^^ž““#—Ë333 !]]]«W¯H$+V¬P©Tô.–õ[î+•J™û‡1c7f]ݳgOxx¸P(”ËåÛ·oò ìÝ»W.—{xxÈd²mÛ¶Ñ­ösX]Ú¸qã¢E‹è/QKKKGøã5ŒÚþÌ1Çhíñ4ãRÓØØØÐÐÐÓÓãîîìããÓßßßÞÞž’’B– ¹~ýºN§Ójµ?NNN¦oHÁöõõuuuÍ™3‡Íf³Ùìààà»wïΜ9“¾»‰L&ãp8„±X\WWÇ”ŠŠb±XîîîLäõññ¡©TúäɉDBo‘Édtg8ŽD"inn Õëõ­­­ÑÑÑfÇEO0°q?ÃÆÆF¥R©×ë]\\fÍšEZÀ>üꫯ&&&†……;vìÃ?d^ÊÏÏ¿r劷·7!dÉ’%,«°°P*•–•• …BºÌ¡C‡Îœ9þÞ{ï­Y³æ_ÿú—iå¸víÚ‡~¸bÅ zKFF†‹‹Kqq1ŸÏ_·n]VVÖ·ß~KY¹r¥Yý–ûÚ`ÚÕÖÖÖ .Èåò;wî,Y²$<<|ùòåƒíXUUµyóæâââ3ftvv2C9Vû9¬.;wî‡~ðððÈÍÍ}á…ªªª&宼ˆ¶}Yظz:—suu¥¿µ×ëõ=ºwïŸÏ×jµEݺu‹)Æáp4ÍÀÀ›Í6ûeÓh4l6›ùB‡Ëå ­VKçEf;‹Å2 F£‘žo@ç]ººråʯ~õ«á×è=½ÑÖ™­UOáÒ l6;  ®®®§§‡‹ L¥±X,½^?00`:Ìéææ¦×ëµZ-#ûûûY,–©Knnn:Î`0°X,BÈÀÀ½}`` ¬¬,**ŠN´555jµÚj "‘ˆÃá´··+•JfAS|>ßÍÍ­¥¥…ù®Çò`-GjÝÝÝûúú˜§tëŽ]À:vìØï~÷;ú±åe»G IJJ"„dddü¿ÿ÷ÿ._¾üË_þ’~•¹v¢®®ŽÇã™^JÁ˜>}:ý@ ¨ÕjNgöÆT]]EQ‰‰‰Ì‘HÔÔÔÔÜÜ|˜ž ëíímgÌ•J¥Ì5gt=o¾ùægŸ}æçç×ÖÖvõêÕ´´´Áê7Ý—þüùçž{®¿¿ÿþýV›£ÿEEEQõèÑ£S§N™¾Zª¨¨xôèQJJ —Ë•H$ôÿ Áúiv8¶»tèСeË–………mÛ¶ËåNV®pæh‹D;gºìŒÃá˜-‰eúÒŒ3f̘aÏ.nnn³g϶¬Ät•»»;srÜÝÝM¯ýbù bVÓ ‡cû¥H$ŠŠŠ²Ünc‰™L6šo¸œØ—_~¹|ùrfíEBHVVÖÖ­[sssÿûß›>sæÌ† »ººfΜyúôi;£í† Þzë­}ûö=ûì³yyy§OŸÞ¼yó¼yóT*•Ï‹/¾HGF«õ›í»sçÎ×_}Μ9Ó¦M{ñů]»fÙ\XXØ–-[RRR$‰··÷âÅ‹Ÿlâ=óÌ3“Ý'4U£-ípî¥l»sçNGG!„Ífóùüàà`zM·[·nùûûÛs£¸‘éìì|øðagg'}í X,¦0¬?………ÁÁÁÌš;F£ñêÕ«111ôê’Œñî6<å˜[~Nº)m‘h'2.<‚‚‚är¹^¯¯¯¯/--MJJﵫTªòòrÿÐÐPfÅ·žžz9žÑô' ÀöòÎa D[L¢uN¹|€ Eq8œ€€€†††¾¾>³”J%}Ó8???fq NWSSóøñc­VËår#""x<½±½½Ý`0xzzΜ9Ó,˜Æû÷ïOŸ>Y²M ˜­æa»?6444øûûÓëâÑ+utthµZ‹¥P(è;NÛshÎq£-­#ÃegðTimm¥(ÊôŽÊ477·¨¨(ww÷žžžü‘ÇãÑk'———SëêêÚ××Gß ùÞ½{E%$$°ÙìTTT˜ÝZ³··W£ÑØ3g`°þد½½=::šÃá<|ø°ªª*66ÖÎCppméxMþ#×"*9,d\pbJ¥R¯×»¸¸Ð·ö0+À¬ú.¤Ré“'O$‰Z­~üøqrr2½¦#= ÚßßßÞÞž’’BÔ†„„\¿~ÝìþœZ­–bc%È!ûc?™LF7-‹ëêê, X=´70ÕýðÃ;vìøá‡úúú‚‚‚-Zôî»ï*Šñk1!!aݺu¯½öÚ˜×óᇮX±bÌkvŽm±®êT‡Œ ÎÇÏϾ„‹vµ¤R©úûû)ŠÒétôu]ýýýl6Û,¡ÒenݺÅláp8Æ4ÚÒ©—ž`(ê?–'7 ä?—x´Ši‚Åb £Ñh¶‹ÕCx:;wnÅŠëÖ­ÛµkW```[[[AAÁ‰'¶mÛ6ÍFN÷Áظ;ØÀºÈxºòÓ©?™œ>ÁèXýñYýA886›íêê:X®(++“ËåÉÉÉIIIÌMàÜÝÝõzýÀÀ€ia:é&$$$ýä™gž1›áÊçóÝÜÜZZZ†Õww÷¾¾>æ©Z­¦7ïPí;4€§Á`X»víÚµkwìØ1kÖ,>Ÿ/—Ë׬YÃäÚ®®®Õ«WH$’+V¨T*z»B¡øä“O-Z™p÷îÝ!ËüñÇóçÏW(7nÜØµk×Í›7é—:::Þyç   iÓ¦ÅÅÅ™Þö–¶wï^¹\îáá!“Élw,''§¼¼<''G.—gffB¤Réõë×é]ŠŠŠ˜ëM ÅÆ-Z”˜˜˜’’RZZ:gw\LΨ­eÄAu>X"Ì8Ù}¤t:!„þ7 ÑhZ[[…B!!„ËåzyyUVV†‡‡»ººöööº¸¸p¹\OOÏÊÊÊ™3gºººjµÚŽŽ³¯ø)Šš9sfyy9‹Å’J¥Ì ¾¾¾6.“J¥ÕÕÕ^^^Ó¦M¨®®öôôåý-;4€§ÐÝ»w322+‘‘áââR\\Ìçó×­[—••õí·ßÒ/üóŸÿôððøÓŸþ´fÍšýë_¶Ëççç_¹rÅÛÛÛ¬‰•+W²X¬ÂÂB©TZVVföûXUUµyóæâââ3ftvvVWWÛèØ®]»fç„„sçÎýðù¹¹/¼ðBUUÕdÝ;wX&4ÚN­D;N«KŽƒÁPSS£R©„BaXX˜åõΓ ˇÃi.Ç“Ëå·oßvuuåp8žžžt"$„DDDTWWߺuK§Óñxxð ¶¶¶   ¥¥E,BvïÞíááÑÙÙI]µj–.]ú‡?üb»|vv¶e®­©©¹páBSSýý‰Ùå§„‡£×ë‹‹‹éÁqqqC6d'¦ÿ¯¿þúG}tåÊ•_ýêWÃ=o"¢íÔJ´´ñ[]r< ‡Ãáp****++éw¶BÆšãÜÁf¹ÅÇÇ3ƒ‚‚¬®ŠÅápÌí¢7Θ1cÆŒ¶Û‰DQQQö÷‡"“Ɇœ3`Úí¹sç2ÝÝÝ­þ;4§tìØ±ßýîwôcÓÉë„:655ÑŸE×­[·nݺ#GŽìܹ“RWWGQTbb"S^$555ÑiÞ—ÂårÕjµN§³]Þê/r]]dzñ;’››{ðàÁ¬¬¬øøø­[·.\¸ÐvCvbFëèÇMMMöï;‰Æ+ÚNéËÂÆouÉû÷ï›>mjjjiiabhWWWIIɼyóØlöÍ›7ÅbqWW—^¯g±XÌ@¬Õ¥19Ž\.gºúøñãÑ€‰€%rL…€ Oƒ¬¬¬¬¬,«/Í™3ÇßßÿÔ©SV?^RURRbg °]Þê AAA}}}J¥ÒÏÏo°jÓÒÒÒÒÒÔjõ¾}û^~ùåööv ±Xÿq•P(ìïï§3iÌÜNW__Ï ];¸1¾ŒÌ9. ¿Õ%gΜiúÔ××·§§§··—~ªT*}||˜kDT*Uddd||¼ŸŸßÝ»wé ŸïÝ»700œœLÑšVØÞÞÞÔÔjg.;ü¬Àa±X¬ÿùŸÿ9pàÀæÍ›|XXXHÇÐÐÐÐÅ‹¿ùæ›J¥’ÒÖÖ–——g£¶á–gvyûí·•J¥Ñh,--¥÷eTTT\ºtI£Ñp¹\‰DBl£!©Tjz!Z||üùóç !ýýýû÷ï7­ùСCeeeZ­vëÖ­\.wª¹±µÒc´–&luI‡#‘Hš››CCCõz}kkktôÏ ú2 OJ¥ÒÚÚÚŽŽgciÌžžž{÷îEFFëëÇa{ù0pzøY€cZ¶lÙÅ‹wìØqðàÁ®®.ŸÅ‹óÍ7ô«§OŸÞ¼yó¼yóT*•Ï‹/¾˜––f£¶á–'„œ9sfÆ ‰‰‰]]]3gÎ<}ú´é®Z­Þ¸qcEE›Í ËËË£c÷` mذ᭷ÞÚ·oß³Ï>›——·sçÎ×_}Μ9Ó¦M{ñů]»ÆÔ¼zõê7ÞxãÞ½{çÏŸŸ×B(³9%#ãdѶ§§§¨¨(!!ÁêÕwîÜ–«Kþûßÿ bÞmz½þÚµk±±±fAÓôë£ÑØÙÙYVV–œœÜÒÒÒÐÐÀL‹¹yó¦\.gVM¿uë–L&ãr¹%%%¦ï-NKÏU /z³œ`>å â<å¦îŸ˜˜Ä2å˜ýכĞÀ°(Š;w¾ôÒK“Ý»˜¾ÍÆfÔÖÉ–ybV—ìÂdzuI³#[]R$q8œööv¥Ri:_›©b4ûûûÝÜܘ¥1M—y7íöä^Í6JSñrCÛZRSSñ©Fiì/#s‚Kà'xuI??¿ººº¾¾¾ÈÈHÓíJ¥R,óx¼úúz‹åááÁb±l,9E? #Ñ~â0VÆqñ¯)q'ruIz*­···Ù˜«L&«¬¬ìííåóùsæÌ¡/i´±4fGGG__Ÿ+( -‰ú¡ßºuËßßßö…¡EEEÌ zæúÀÀ€H$2ûÌ9U0Gmz,~~~<øÅ/~1âjÍNÔ(‹€Ã2»N} ™ˆum§è2Oã´º¤%‡Ãáp,#)dz\žÖÆÒ˜C®—9éœlN6Œ†ƒÿÜ•J¥@ ˜5k–ý»F« ÷L–€€úÓ¸é±ô÷÷3 8¥ ½™íKàü_ÝøQ*•ôý~&»#ã‰Lß~°Õ M544(•JFãâââççGß•àþýû½½½÷ï߯©©ñðð (Š^×¹6t``àþýû,K,‡„„З޼yS"‘ttthµÚ°°°ªª*???•JÕÝÝ- #""ZZZFc```@@€eŸu:‹Åš>}:ÝŸa-kÍlüø±V«år¹<¯¡¡Áßß¿¡¡9BˆÁ``³Ù̶ÕmôÍìD) {ΧB¡¬çcnB£-—qýúu6›=kÖ,‡ïH´`f~ú*•*..ŽÃá477ß½{wîܹf‹“»¹¹EEE¹»»÷ôôüøã<O"‘Ìœ9³³³Óì t‡Ã,]ZZêîîž””¤×ëKKK«««Ã˜cbb˜ ¦T*gÏžíîî^VVvçΟ_üâÝÝÝ%%%b±Øl ì¾¾¾ÚÚÚ„„.—«Óé˜+G;{÷îQ•Àf³ë9À˜ã[6 –ëæ™g’““é{4›š;w.sƒ¾©Å9nÛS”éjÐF£±££Ã¬€½n‰@ J¥Ož<²Î¾¾>z-Izi”àààææfæªM™Lf:9}út>ŸOŒjµZ¹\Îf³=<éW-{nuC€‘ùè£þð‡?twwÿñ\¶lY]]§§ç¯ýë%K–ܽ{W$UUUýïÿþ/]ø›o¾IOO_¿~ýž={üýýýôÓùóçs¹Ü”””¦¦¦;wúúúJ$’={öÐekn×®]7oÞdêùä“O-Z™p÷îÝaõÇêî¶[l—ŽŽŽwÞy'((hÚ´iqqqôm~‡<#æˆÑ–A\d\„D ŽI©TöööFf5hÓWé/Áéu4Mkk+ó=ÙÔj<oÚ´i< ƒ`mm­T*“Éñ}}}Ož<1 tV6ly \.—^Öš£Z­¶­­Âår½¼¼˜í½½½vÆ\Û;Ö7Óeçù¬çãáôéÓ...3fÌÉdaaaÙÙÙýë_>|È(--mllüíok¶£_ꪪªÍ›7ÿý÷÷îÝ{þùç8qàÀºººãÇBüýý/\¸ÐÕÕuöìÙÏ>ûì믿¦÷µ,™‘‘ÑÒÒR\\üðáC‘H”••eÙâÑ£G¿øâ‹¶¶6‘H”ššÚÝÝ]SSóõ×_øá‡5556š3SPPpöìÙÒÒÒW^yeÍš5Ãíåî4­[ÝeåÊ•õõõ………ǧ'8ÙsFfj|ĤÛè’húÁ”X>ÌÉà²0p|VWƒfðx<¹\~ûömWWWz€‡™ñXYYÙØØèéé9{öl³jgÏžýàÁƒÿûßE‰Åbæò²Q2 µµµtäñx¦íkY눈ˆêêê[·nét:7kÖ,ËÛ%ZecÇÁúfv¢ì<Ÿ6äûöí;räHOO··wnn.½ ȵk×öîÝ»k×®üQ.—oݺuÅŠô'«éÓ§Û_9‡ÃÑëõÅÅÅô›,×å$„¤§§Óbcc333/^¼¸|ùrËbµµµ---ôå4»wïöððèìì4»!ÔÚµké_ºŒŒŒ5kÖlݺ•Åb-X° <<¼¸¸8$$ÄÎæV­ZEÂ_ºtéþð‡áög°Ým´n¹KMMÍ… šššè/vèKHí<#35¢-Ã2ãLÉgH´0…X] :>>žyD/PeÆÃÃÃôFô 777˼K™;wî`OÅb±é• Vÿ «Û;Á–µæp8f&&Gmú’······ím÷ÍìDÙy>m,È `cÇŽýîw¿£[½õæ[o½µaÃ@`zs%Ÿ;vìØ±£§§çðáógϦ?V555Ùÿù*$$$77÷àÁƒYYYñññ[·n]¸p¡Y™üüü={öÔÕÕQÕÕÕõÜsÏY­Š.˜˜Èl‰DMMMf‘Ž™ÞÃçó¥R)ó)ÏçwwwÛßóWˆËåªÕjNg6ÇÝvÛÝFë–»ÔÕÕñx<³ Kvž‡‘™bÑ–Œ;ÞhÀAdeeÙþÂšŽ€ƒ½*Ö¯_ÿñÇÿøã+W®ô÷÷?qâ„ÙåV¶ïº’–––––¦V«÷íÛ÷òË/···›Í JOOÿûßÿþË_þ’¢¨7Þ¿ŸyÕ´d`` EQ%%%£Ép¶›Ò(û3ÜÖƒ‚‚úúú”J¥é­©Æä< <ÇÐ+IDATÆ¡çÚÚÃr>.Á”ÜQÀÒ]àš››ßÿýâââÞÞÞÇïØ±C«Õ&&&²X¬ƒ}Z&“Í›7O(&%%]¿~}¸‡f»¹!²?#hýÌ™3~~~‰‰‰"‘(33“Ç£?ƒ¡¬ÎY™tûŸì“zL§+Ð&=¨™~ß1é'‹Ñ‚C¡ßx‚ x“L9õ_œ•éÛlªÎµµ“¥žæ¿ŒH´à”œ<Ú2&+ãÚ^üÒòÕqýD‹D Îíi‰¶ &ÌYÞΗŒCÔ³}Å¥eá±m`¡xš “hì‡h;rýìÌêÀ­Õ![$Z€@´cµ´-Àh ÚŽ¥!3®ÙÀ-=d‹D `Êêo€=mÇ…íŒ;ØÄY€Ñ Æä&Xcnÿ“ýãTó»žïŽSÍCb‚ì¢E‹!—/_¦Ÿ"Ñ€Uô ü‰€)Íò»J€1gú6èíÄ¡ÿ?1gÑ¢Eø%C¬ÉîÀØ@´'h Nsm`" vÃy€1„Q[pˆ¶à$mÀI`®-Œ¬àþ³SvM5¦2~~l‘HtóæM‰DÒÑÑ¡ÕjÃÂÂüýýy<!äæÍ›~~~*•ª»»[(FDD´´´466ÆÀÀÀ€€BHCCƒR©Ôh4...~~~AAAtC¦Õòù|FG¿ÔÕÕURR2oÞ<6›=YçÀNˆ¶Ž®µµ•¢(.—K?U©T111f#¸4¥R9{ölww÷²²²;wîøøøüâ¿èîî.))‹Å\.×ÍÍ-**ÊÝݽ§§çÇäñx‰Ä¬ZN÷Ã?ôööòù|ºNäZ˜mTcc£R©Ôëõ...³fÍruu¥·Ëd2«¹–2}út:úúúÞ¿_.—SåááÁãñzzz¸\®]R H¥Ò'Ož0Ñ–©–ÃáH$’æææÐÐP½^ßÚÚ=îG 0m”ŸŸ_`` ›Í61usslæ%6›íêêÊL™e³Ùz½ž¢R©úûû)ŠÒét¦—¦™V+“ÉÊÊÊBBBÚÚÚÜÝݧM›6†Ç0~mOǰ²²²¨¨(:ÑÖÔÔ¨Õj«%E"‡ÃiooW*•R©t û0®°®íÓB§ÓBè4Mkk«Â~~~uuuÝÝ݈¶0…`ÔöiÁãñärùíÛ·]]]9ާ§'v­’J¥µµµÞÞÞƒÍëp@ˆ¶Ž(&&Æêö¹sçš>·ú’X,‹ÅÌSf%¯   fÁ/ÕB8‡ÃñóófÇ&&$€J¥’ÙìŽ FmÁÜõë×Ùlö¬Y³p[2˜ZmÁÜ3Ï<3Ù] LH'h NÑœæÚ:¨ÎηvvvFwww±XLßw÷Î;„6›Íç󃃃éu ƒƒƒ™;,Æ«W¯ÆÄÄxxxLæaL D[G¤R©ÊËËýýýCCCÝÜÜÔjuSSSOOH$"„Éår½^____ZZš””„+LHp@F£ñþýûÓ§O áñxl6[ „‡‡Ó¹–FQ‡Ã Ðëõ}}}“Ø[Çhëpz{{5¯¯ï%[[[)Šâr¹Ð+LJ G«ÕBÜÜÜ+ÐØØ¨T*õz½‹‹Ë¬Y³\]]'°wŽ ÑÖáÐg5Í`3hýüüèKÊØl6³‘¢(£ÑÈ<5 ôÆqî,€Á„‡ÃçóÝÜÜZZZ+Àf³]]]Ms-!ÄÝÝÝtÒ­Z­¦7Ž_? ¢­Ã¡(jæÌ™MMMµµµjµÚ`0ôööVUUuvvÚØK*•677?yòD¯×«ÕêêêjOOO³œ&$8"±X]__ßÔÔD¯këëë+lì"•J ÃÔjµ‹‹‹——WHHÈ„uÀ Ú:(‘He¹=&&f°]d2™L&ÏN84LH'h NÑœ¢-8 D[pˆ¶à$mÀI Ú€“@´'h NÑœ¢-8 D[pˆ¶à$mÀI Ú€“@´'Á™ì89Š¢†õªÑhÏî83D[GqåÊ{6¦¦¦Ž_¦$LH_Ã…Å-ÀSΞ̊\ `¢-8 DÛqgçX,†l€ 5(‹![ÛmÀI ÚN„!Gd1d ŒÁ†f1d 0$D[pˆ¶ÄƸ,†lÀŒå-†lìh N·l˜8F£·;¥¦¦27kÀ-€³¢2†÷ªñäøõÅI`Ô`r ªŽ9DÛ e6F‹![°¬Å-Ѓíh 0iXÇ5&‡–SHÆF¸`j;5hX²=ã–f+ÿþEþ £¶“ ·cÑÀ¡!ûÚÑ`’!¼Ž•±_×s"a¬`7Rï°`Ô`ò!ÂŽ D[…¼;\ˆ¶Avôm’î Ú8 ÄÙQB´p8ȸ#ƒh à@jGÑÀ± ÝŽ¢-8 D[pˆ¶à$mÀI Ú€“@´'h NÑœ¢-8 D[pˆ¶à$mÀI Ú€“@´'h NÑœ¢-8 G¶7nÜxá…¼¼¼ø|þœ9s6mÚÔÛÛ;¶MÄÄÄœ9s†yšpâĉ±mž:MËŒ K¦eF|p*ÆCGÛo¾ùæÙgŸŽŽ.,,lmm=qâDkkkIIÉ`åF£V«e£|ðÁܹsGYÉê´Qf¸]«CS0~7Ú †5kÖ¬Y³fûöíááá|>?::úðáÃÉÉÉf% ÅÇ<þ|…BqãÆ ©Tzýúuú¥¢¢"@Àûä“O-Z™p÷î]BHNNNyyyNNŽ\.ÏÌÌ$„ìÚµëæÍ›Ì.Ÿ~úéüùó¹\nJJJSSÓÎ;}}}%Éž={è2]]]«W¯H$+V¬P©T–ÇbV§e7LËØîÒž={ÂÃÃ…B¡\.ß¾}»ÕSgZ~ïÞ½r¹ÜÃÃC&“mÛ¶ÍF%¶ÛU*•¯¼òŠ¿¿ÿÚµkûúúlÀÄsÜh[ZZÚØØøÛßþÖl;EQ–…óóóóóó+++SSSmÔYPPpöìÙÒÒÒW^yeÍš5„DDD8p ®®îøñã–»=zô‹/¾hkk‰D©©©ÝÝÝ555_ýõ‡~XSSCÉÈÈhii)..~øð¡H$ÊÊÊòÐ,»aÊv—üýý/\¸ÐÕÕuöìÙÏ>ûì믿¶ÑPUUÕæÍ›¿ÿþûŽŽŽ{÷î=ÿüó6*±ÝîòåË]\\ª««‹ŠŠnß¾½~ýz;`Â8n´mkk#„LŸ>ÝžÂÙÙÙÞÞÞC[µj•‡‡!déÒ¥EEEöÔ¼víÚÙ³g ‚ŒŒŒ¶¶¶­[·òùü „‡‡×ÖÖ:tH,s¹ÜÝ»w÷ÝwcÞ Fzzzpp0EQ±±±™™™/^´Q˜Ãáèõúâââîîn‘H7‚J!•••………û÷ï …R©tÛ¶mÇ7 £?€1ä¸ÑV"‘Bšššì),“Éì)&‹é\.W­Vët:ûkæóùR©”Åb1O»»»ëêê(ŠJLL”Ëår¹<**J$ Ùçtƒ‘ŸŸ¿`Á‚ÀÀÀ   Ã‡Ó’››ûùçŸK¥Ò \½zu•Bù|>ý¡«íïïg¦^ŒæpÆãFÛÈÈÈÿßÎýƒDýÇq¿oÑà PDˆC.’CC ´µ´4H‹ÐAäÚêàÖš-·µF-A4µ„.I8ôO§ïoˆßýü™Þwßû~?ß÷=SP~ï={y911ñ÷ÿÐÏóüï_¼û] £££ÛÛÛ~¼ï;_÷hÕj&''³,{÷îÝú¿¶¶¶Î;×óÛŸ´¹¹yãÆåååÅÅÅ}?»-,,¼zõêÛ·oW¯^½~ýzžçmrÐëNLLüüù³UÀëëëÇŽk-@"ÒMÛ#Gެ®®®®®>zôèÓ§O;;;ïß¿¿{÷îëׯÛàÌÌÌóçÏÆöööÊÊJÇ:uêÔÇ{;òìÙ³óóówîÜÙÜÜl4_¿~m6›½=ª›“¾ÿÞh4¦§§³,ûüùóÚÚZûç|øðáåË—;;;Ç?qâÄÑ£GÛ?ä ×ššš½wïÞ?¾|ùòðáÃÛ·o÷óO€AHºN®]»öâÅ‹7oÞÌÌ̌߼ysrròÂ… í?êñãÇoß¾=þü•+W._¾ÜñUîß¿ÿôéÓ±±±………Ž|öìÙéÓ§/]º4:::;;Ûúæ ý8褩©©ååå¹¹¹¹¹¹ÅÅÅùùùöÏùýû÷ƒNž<9>>þäÉ“f³™eY›‡ôºY–5›Í_¿~9sæâÅ‹ÓÓÓ­oެãW´»zÊ®÷ò@høs@$kû|‹§bÜòWä’^m {Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AŒþÄ,Ë &tdµ i @Ò€ Šy¯mžç…<§eek¥Ø¶,- èÉ]Úý^äÂ?oÃÌj @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AŒT}@pY–êgó<ä9‘YmBÚÖ¡VX“-@?¤-AHÛër‹5ÙôIÚ„´-CÇEÖd Ð?i @Ò¶$mvY“-@!¤-AHÛòì»ÎšlŠ"mBÚ–jÏFk²(´ i[¶ÖRk²(–´ ˆ‘ªFöZ€A°Ú„´ i @Ò€ ¤-AH[‚¶!mBÚ„´ i @Ò€ ¤-AH[‚¶!mb¤êjk-«ú‚ÃÜp+äIÈò¼¼ßäÊÖJi¯Õ¿¥±¥ªOÒ–BÚvoÒÖzU£X¬Ñ©}(5mk´ƒÖèTþ°Úô¡kh-Ž,BÙi[‹5´G°‡Õ ?‰o¢‰ŸW¨ Ò6ñM4ñó8ˆÕ oÉ.£É6Õ¤m²Ëh²‡БÕ  î£ ž4`•¥m‚ûh‚'Ð=«-@A’ZI“:¦,U¦mR+iRÇЫ-@qÙJ9£t§m"[i"gЫ-@¡*_L+? :Õ§må‹iåPˆêÓ š wÓ!žl‰¤m…»©É Œ$Ò šJÖÓážlé¤m%ë©É ’TÒ š’7Ô¡ŸlI¥mÉªÉ ˜„Ò šÒ–T“m£ÑH-mK[RM¶ñ¤•¶Ñ”°§šlÿ•\Ú–°§šlBJ.m¢èªj²Ý%Å´èªj²ˆ*Å´ˆf@ÛªÉöÿMÛm«&[€ÀM[€h _XM¶I7m _XM¶±¥›¶Ñ¸³šl÷“tÚ¸³šlÂK:m¢)dm5Ù õ´-dm5Ù ƒÔÓ š>7W“íÁj¶}n®&[€!Qƒ´ˆ¦çåÕdÛV=Ò¶çåÕd 0<ê‘¶Ñô°¿šl;©MÚö°¿šl†JmÒ šC­°&Û.Ô)mµÂšl†MÒ š.·X“mwj–¶]n±&[€!T³´ˆ¦ã"k²íZýÒ¶ã"k²NõK[€hÚì²&ÛèeÚ¶ÙeM¶C«–i ;ë¬Éöêš¶û®³&[€aV×´ˆfÏFk²=¼§ížÖd 0äjœ¶Ñ´–Z“mOê¶­¥Öd ÀHÕ°‹½¶YžûôÁ?7µ¹zVx¬êIEND®B`‚trusted-firmware-a-2.2/docs/resources/diagrams/romlib_design.dia000066400000000000000000000056511355360272700251450ustar00rootroot00000000000000‹í][oÛ8~ï¯0Ü—YÀÃðœÃk=é`ú°Øº`wöe‹@ŽUÇ3ŽmÈÊíeû’’rq"'Ž%*U@£i#—ægJ¿sáí§Ÿ¯ÏƒË4ÛÌWËã!0>¤ËÓÕt¾œÿýÛ_4ß?øi:O>¹ŸY–œÜ'–u<<Ëóõ§££««+¶¸Ù$ù*c‹ùÛ¤GÿK‹äÈ:~þ0<¬`šä‰¯z7Éól>¹ÈÓÁ29O‡“äôÏY¶ºXN‡e©ªÜéj±Ê—Éâxøñ[ñUÕmÕóLÝëd–N²4ùswÕܽ¬=¤êuš=®ö|½ÚÌ]‘üfý¤ÈŽzüßÊT¥6®Ðröùã/âcù•ª7îëªû¢;Aòó$›Í—OqܽY”7™ADw3¤5–k¡áöž¼nÒ-Ü¢[¸¬[¸ùæd½Êò,™çO!'«Õ"M–%jž]¤‡ãlN“…£ØsÍjЊoó<_½ðý¿%‹Í> (ß¾ëm¯í¹³l>}¾ãn•ØQËÕ|šŸ\º]eí7j¿œoæ“EZ÷íç˼µêoÚ©þñÓ)Ôûþã ÙPÖ¶Ó[ž§õO4]^œWwsO”Z÷àuÝâ²øJ;ÆýW¡vU©ÞoÀ¦¢d™EIzdÁCæµ®JÖéP „Š‹1h(Å8Óïç;´ÑÄ}¼×"a¼Œ é=0’EÄ;2µÔØÔrÆ=»4S*(«ï¸’ŽÕÀ¸¿4S­Ksûå+DsÜÜî c´·ß³½Ý!M¢¹Á5…5rR!I¶¸%wáº7¹Îf€7¹À”‘¢ÁÀ׿‰Z vR2*Tÿ"Ù\ ô-¬ (}‹äÜ¥1ºQÐÇN¡c‚¹WJ]T`,HiõW+þ^A ª,X«À(4Ö õ2(¨çµjÊk”L¡Ô#ÅxÐô›Ïëê‡Ë1Y†•\d`LHJ·Ð¾½MLnGžasä`Ð*©µrÁ5XŒ9òï9p×;©*»Kƒtõ~ôaŒ.2£âÂÊ>äȉ9òà>ñ"F¸±iA”¤ç‚3}Ε3aeIè ‰¬“ñYrç=p&­Å îCÜËpQæVž\‡õˆ¹´äœI×òY[Û±­04ÁÈp–Ø%1m¤cAlã‘%ŠÜm¦ü:ÝŒn=£ÙíŸÙ…ÆsÚœ_ε#°Œ´ jwVH¨œÝuÔFÈýر jwÛhä~ÃÓ(ŒrýKH+Aµ»LX£57ζßQ&  …ái¥µõ:§mØñi…%’RhÇ`œƒé¯%ÓêPäýˆÝJ#÷#¶ÞJHQÈyðŽxŒmðXùG¬˜Æà<†IéŠÇ²{ø:<72ò8 Û˜.¤¬¦Byp‹IɊDz#— ÏãÆŒ<9üñäN;ùgŒ r!š€Â±pÂ<ö¬BP™v,º è'ƒµû%ÿ£úàóßv‘ò=DõП¨þîF-—®/;åÙ<éj·ÿ38sZUQ4_•1Ïàþ¿‡æéJ»Gµ¶$‰² IÔXXXä¡%Q*k ÛÎKI”ZL²'’x‘o¢ v!ˆµ”Œ‚ØA¤7DÕ† ,BgÄà‚èWCø +A”~²f¤{#ˆ§Q»ÄZJFAì â ¢na˜ ‹\ ³6ð S…#8ÉÏ<&éÇ}@˜ï_ ÿ8_ç‰ßØd’lÒ(‰Á‡ÂëI¿çðßç³ß“Ù×ù2­*ÓÖx8r¨0¤çfY¤lŒ€b†,`…¬FÎò³“¢95²¦(2m\'yEÑšë‰3R¤äuÄoë*›ow†ç:Âs^ÃîϽæ;%ù*[]äÛBP¾{WÆ~9=I²luµ»Íˆ «>Y¤ËÙó³øeSˆ× ÈŽßv¤è j> o–ÚÆà4`1÷ ‰ë°cp%ù¡ û9‰Š„G {–n}±è†u°v¿ž•Ñëáf9¼ ‘â\û Í‚ =Q@–HF)3vÿ*Ivä°Bž(м‘ûLp± '°‘w¹dÐ¥„ QKA* zWæ`+S±|èRszJ¢Gr_KSìPge¬‘÷ RÎ`«h};°¾õ¤ŒÖ·‡Ö·•é¦Ì‰‰Ð»z)*Èïêåè'´»”L†Ýæ¶îgy (®„Š´äÔòrí ½ûCBj–Þ“åmgò)¡÷ì,AàÀ÷‰Hioy•ñ×ĸ9¹SË{‘o¢ÝíÆîÖR2ÚÝÚ]Ñ‚BI #T~Îz`’XqÔÞî a­ßŠë°›ç´ÑÄ= /KF ‹.âÔa÷ˆÕŠ;Ï­RR ÖïÉðÊV’9Jû‡ŽVÈÀçI:]µÒ^ %²sÁd/ ïi4¼Ý¤›k) o÷ŠEÕ†D rñ f~Ýv`‰*3¡Ø,V—ÈŠEîZ¢>E…êB¡jª ¥[P(+Éy΂!="V"ùa{°^¡¤*‘I*ÛìET¨.ªž‘Q¡ú¨P¦­1{Æ)è&gwHœ 'IE~Kd0}Øä¬ÙŒÕMœWÇɨQ½Yð‚»çij‰¶…€Ú[è’¤ ‰¯[$Îü—~ àJxdâÔƒÄc,ªaËÿêùÕ°‡5Ÿe)7~ÜG0!ÂêÓ-1#J}RV ,mÔ§¨OÏó1êS¼µ7ZžLІ·FÖÅ †AØãîtq2¹WC=2öâÀ¸¨†ykµ|ŒjØ¿ÉA„-œ!`Š­²ýN¬V‡=CÀ`…„VI2C@þp .5>£y#ã’˜NϦ6–ÛæPÞ}¾r,CcB¦¤-ÇÞ>òì-VÄ ~¸Ê’õ:ÍþÍp„Ô²3Zá>æLÏÑuš! €Ÿ++EÐqx‡@†”÷ÿ¬ëͰÔ~Ë”U½ØÕmk/£ÿðÿFµ ­V;éwxë£\É|+ðs4 ÓAg^ßã€ûu²¸0VÆÑø(NÏ“1zR=Ìg¨6ÎDUŒi:¡J ”zL¨˜úZÎf4nâ>É Ã%i«„2‚ƒÀ°«Œ‰ƒ¶Tå24¾§“>©ƒµïfÏÊ »>?@âR[Ô§{%Ýxv}þòõ:®uêæ°ÏZFF»ÛÇ ÝM•4Ò/’DÀÀùÖÉÏò0jLœ-׃µ=çœ,ªÃ‹>øßâ™ÝÄõìŒjÕÃ(Á¶16deqÜ™–‡D…Ä|ºÕ*Ðþ¬cBMܸ‘q;¢.ÑÊ¡ÛFÇD"…&v$˜"åÏC.èË^DƒÖI~zÇ;;ï¬ãe´¿=Œ´ S¢°M>‹*¬NÝ"¡RÊ"÷×~T\wêyFF…zS…*¯ÉMš}þP^¸ŸY–œþðBns´trusted-firmware-a-2.2/docs/resources/diagrams/romlib_design.png000066400000000000000000000415341355360272700251740ustar00rootroot00000000000000‰PNG  IHDReÊ/ sBITÛáOà pHYsÐй‹çŸ IDATxœíÝ\TeÞÿñ3,†hÊ"¸ŒŒ 2,ù³n‘uo­¯ÞDnÊf®¨-Ä¢æ®)*"”@*öcUÄT~øXuKÍVmïÚJ­53Ô-ÓŠ¥Q„TQðwÈ-óýã܆3Ìpfàõüc×9së| ½=3לK¥×ëÐ*¥ À —Ès¦¼TýÈÛÛû‰'ž8wîœá«ÅÅŽzõêÕ«WDDDQQ‘áC‡5|çY¯×2D¥Ru\õgæLy)‚^¯×ëõ¥¥¥!!!3gΔö—••=úè£=öعsçÎ;7~üøððð²²2©C=þùÏJ›ûöíëÙ³g‡–pf*'šï£Rý»Ú;wîøøøÜ½{WÜüÃþôÒK/I_|ñÅòòò;wоóÎ;ÙÙÙŸ}ö™øêèÑ£Ÿ{î¹éÓ§;Ñåäd÷—¢ëׯ¯]»vøðáÒžC‡ÅÆÆö™1cÆ¡C‡¤Í©S§^½zõóÏ?!//ïÚµk‘‘‘V0àÔZÿ(äÕW_uuu}õÕWáCt2N–—â­——×¶mÛÞ~ûmimm­F£1ìéëë[[[+mº¸¸<ÿüó‚ ¬Y³fÉ’%..Nv퀂Ì}ÒÜܼyóæÌÌÌ-[¶477‡ èdœ,3ôz}sssYY™V«ýú믥ý^^^:ΰgUU•···áž™3g~õÕWÿûß g̘ÑAˆ——×’%K¾ùæiÏ<==ããã½¼¼>þøcÃÎÉÉÉâ¿PE)))W+`kN–—‚ ¨T*­V»{÷îùóçß¹sGÜ.~T)ùÛßþn¸ÇÍÍmÑ¢E3fÌHHHpss븊΢åG!›6mZ¸p¡ óçÏÿË_þbØ™AÐÙè‡QµÓ¦MÛ²e‹Ø>s挷·÷† ._¾|ùòå 6x{{—––š<ÐÜ€L2ü/F¿~ý***ÄýçÏŸïÛ·o}}½^¯¯¯¯ïÛ·oyy¹tˆ^¯ÿë_ÿúä“OêõúÇüµ×^ÓóGgæ|÷—’9sæ¼öÚkbû8|øð'Ÿ|tðàÁC‡+[!ÐièM}²yóæššwww•Jåîî^SS³yófãø‰3}Ÿ€" ¿ÊuñâÅ_ÿú×gÏžíÖ­›¿¿ÿ—_~ ¾TQQñë_ÿúâŋݻw—Y³fMZZÚÊ•+Å/ ‡œ ¿»d…ÜôéÓ{ì177·÷Þ{ïÃ?4ìñûßÿ~æÌ™ær‘¼„órâ÷c(Bü(ä/ùËüùó^Š‹‹3šõtü[yÜ_ ÏuÇ¥KÐ=&ôï¯t@ ÞœØG 'Z|Ô­[‚Áó"È8Pp[Ï<£l%,–›+TVZyìßþ&,ZdÓj€NíÖ-ÁU•Jؾ]éZXè·¿µ>/EBß¾6ªè¤ÊËq)W¥+ ˜™3…ìl¥‹ÛÏ.ܺ%Ì -ÈKä‘—È#/G^ ¼@y €<òyä%òÈKä‘—È#/G^ ¼@y €<òyä%òÈKä‘—È#/G^ ÏŽy©ú‘‹‹‹Z­ŽŽŽ®¬¬”^jýûU€ì{©×ëõz}SSSAAF£‰ŽŽnK»–€\;à...¾¾¾iiiýúõë€Ó`s‘—ÍÍÍW¯^ÍÊÊ5jTœ›³o^~éééùé§ŸÚõtØIG|~©×ë¯^½:þüE‹ÙõtØIG¼+Bß¾}SRR|||:ætØVååµkײ³³z衎9¶ÕAŸ_öéÓç‘GÙµkWË—Dâ×H¤bƒï–„󲕴3÷ pL<yä%òÈKä‘—È#/G^ ¼@y €<òyä%òlü<¼êêêÆÆFÛŽ ûquuíׯŸÒU€°q^†……9sƶcÂ~üüü.^¼¨tàìò¼õ~ýúuëÖÍ#ÃVšššªªª”®œ†]òòþçxà{Œ [¹té’¿¿¿ÒU€Ó`¾òÈKä‘—È#/G^ ¼@y €<òyä%òÈKä‘—È#/G^ ¼@y €<òyä%òÈKä‘—È#/G^ ¼@y €<òyä%òÈKä‘—È#/G^ ¼@y €<òyä%òÈKä‘—È#/G^ ¼@y €<òyä%òÈKä‘—ÈsµÇ ÅÅÅßÿ½=F†­\¹rEéÀ™Ø%/§M›faPŠórذa÷ß¿mÇ„ý¨Õj¥Kç`ã¼üÇ?þaÛpÌ÷@y €<òyä%òÈK䑗ȳq^ª~äííýÄOœ;wÎðÕââ∈ˆ^½zõêÕ+""¢¨¨ÈðÀ¡C‡êõzi^¯2dˆJ¥’:˜<]ËS»¸¸¨ÕêèèèÊÊJÛ^ Ë²ýý¥^¯×ëõ¥¥¥!!!3gΔö—••=úè£=öعsçÎ;7~üøððð²²2©C=þùÏJ›ûöíëÙ³§§njj*((Ðh4ÑÑÑí¿û½ëååµdÉ’o¾ùFÚóÒK/ÍŸ??))I­V«ÕêÄÄĸ¸¸—_~Yꜜœ‘‘!mfdd¤¤¤Xqj__ß´´´ýë_í¹$öÊËëׯ¯]»vøðáÒžC‡ÅÆÆö™1cÆ¡C‡¤Í©S§^½zõóÏ?!//ïÚµk‘‘‘Vœº¹¹¹ºº:==}Ô¨QÖ–ÀOØþyëÒgŠýúõÃOT[[«Ñh {úúúÖÖÖJ›...Ï?ÿ|FFƾ}ûÖ¬Y³dÉËâÜðãLOOÏO?ýÔš  »|~ÙÜÜ\VV¦Õj¿þúki¿———N§3ìYUUåíím¸gæÌ™_}õÕßÿþ÷ÂÂÂ3fXqjÑÕ«WçÏŸ¿hÑ"«¯Cvy?V¥RiµÚÝ»wÏŸ?ÿÎ;âÎððð;wvûÛßþn¸ÇÍÍmÑ¢E3fÌHHHpss³º€¾}û¦¤¤œ8qÂê0d—õ/Eþþþ<òÈ[o½5wî\A^|ñÅGyÄÃÃCœ¶ú÷¿ÿ}Ó¦MÇ7:*55555µ§¾víZvvöC=ÔÎqÙ÷ysæÌyíµ×Äöù$(((((èàÁƒ‡ nûhªŸj¥Cppð·ß~»k×.Û\ Ë³ñý¥áAøÍo~ó›ßüFÚ|ðÁ8Ж[î7ÙÁèù–V @ñ<<ä‘—È#/G^ ¼@y €<|Ÿä«¯¾ª««kÿ8€£ñöö6l˜ÒUp6ÈËY³f>}ºýãŽfÊ”)ï¿ÿ¾ÒUp6{^Á¨Q£,]ÞpX555ÅÅÅJWÀØ,/wìØ1xð`[(kïÞ½S¦LQº „ù>È#/G^ ¼@y €<òyä%òÈKä‘—È#/G^ ¼@y €<òyä%òÈKä‘—È#/G^ ¼@y €<òyä%òÈKä‘—È#/G^ ÏUé8üãÛ·oWº Àb»wïîÓ§O;!/´UEEÅǬt€ÅîÝ»×þAÈK–yê©§fÏž­t@›ÄÄÄ\»vÍ&C‘—,3pàÀÇ\é*€6qss³ÕPÌ÷@^WÏK•JeÑ~@×äpyIPÃå¥^¯·É8ä.À†./p@——†÷…*•jóæÍnnnÆ ûì³ÏvìØìîî>zôè3gΈ}Ö®]ëãããååµpᆆi•J%vöìÙiÓ¦yyyyxxDFFÖÖÖJgiy¸‘æææ•+W8°OŸ>³gÏ®««³ëOà€./ìß¿?77÷úõëO?ýtDDÄž={>þøãÚÚÚI“&Í›7Oì“››[PPPXXXZZšžž.üø¦®^¯—ÞÝ>}ú‚ *++/^¼¨Ñh^xáé-7’•••——wäÈ‘óçÏ766®X±Âî— 8'Õ\\\Ôjutttee¥ô’²µí§W©ôí1dÈANŸ>Ý®Q~$ü˜sb»ªªJl‹wu—/_–6ÝÝÝÅ>§NwkµÚ–ã¹uëVÿþý¥n²‡4èÌ™3b»ººzÀ€í¹@8…={ö‚0eÊ¥ iMD„^ô}dͱ99zAÐ/ZdÙQ‚ ¤¤¤˜ë ýáüðÃ:î¹çž{ä‘GŒ^:’¯¯¯a”XÁÃC/ú[·ôŽ~Ù¯_?±Ñ£GAÔjµ´Y__/¶ņV«Õét&ÇÉÏÏïÓ§J¥òðð¸|ù²ô’ìá.\4hø¯fµZ}éÒ%\Щ¹¸¸øúú¦¥¥ýë_ÿ2×'..î7Þ6·oß×!ÕÖpô¼l‹òòr©¡ÑhĶћ?QQQ3gÎ,++kjjºvíÚ?üÐúá†üýý+**¤k À¤æææêêêôôôQ£F™ë“½cÇŽwÞyG„·ß~ûÍ7ßÌÉÉéÀËt†¼LLLÔét:.111&&FÜéíí]RR"õ©««ëÝ»wÏž=/\¸ðì³ÏÊn(..nΜ9%%% EEEQQQv½À©‰ïÄüìg?ëׯßk¯½ö—¿üÅ\Ïûî»ïwÞIMM}á…^xá…wÞy§[·nY*`‘Ηááá!!!Ç×jµK—.w¦¦¦Ž3FºËܶm[jjj¯^½ÂÂÂÆ'{¸¡øøø'Ÿ|222²wïÞ111ÑÑÑö¾"ÀyIïÄ\½zuþüù‹-j¥³Ollìš5k,XàããÓaEÖq ù>MMM®®®"0‰vÀ|“Ú>ßGtûömq^^Ë—Dß|óMÿþýßÿ}FsîÜ9˪ÚÀ†ó}k}’¯¿þÚä'ˆœÎµkײ³³zè!sêêêbccwïÞ=vìXWW×§žzêøñãîîîY$ÐvŽõ~lXXXJJŠÒU°žôÌààào¿ýv×®]-_ÍŸ??>>~ìØ±‚ Lš4)66vÁ‚ÊÈp¬ûË;wîXzˆÞFÏ›Ð~­ü=Êþ©&&&ÚºÀ–ëþÇD^ ¼@y €<%çûäååݾ}[Á`sîîîãÇWº °=%ó2!!¡°°PÁ`sþþþ.\Pº àÿ¬^½úóÏ?ÿç?ÿi§ñU*•Éy¿cÇŽMMMµÓy¡å¿OÖ»wo¥«h;}û&Ož¬ÔhŸ}ö™V«•ÖiqXõõõŸ|ò‰ÒUÿVWW—™™ùùçŸwü©7lØ0vìØ„„¿Ð™(Ÿ—ÙÙÙÇWºŠÖ¨Tª½{÷väé ÿÅêááqìØ177·+À:—.]ò÷÷Wº 8+s7jíñþûï3æ—¿üeÇ—4hРÐÐÐ}ûö±ùùù£G–-éìÙ³Ó¦MóòòòððˆŒŒ¬­­5YRSSÓŠ+ àéé¹~ýziØ–Å¢‡~øË/¿´ðLJF^¶InnnAAAaaaiiizzºE}Ž=úÅ_477·<äàÁƒyyyµµµ'Nœ7ožðã3Ãćâ·ÜœH[þjD-Ïccc—-[vóæÍcÇŽ‚ |÷ÝwF=¥ÆåË—Åv]]¹e'Y°ìâÅ‹‚ øûû+]ˆm°ž—I²ëyIZù‹0êfr¿ŸŸ_NNÎÅ‹Í(_TTdò¯²{÷îuuu²%ºuëVÿþýM–TTTÔò2Mþëõúï¿ÿÞpJ±áz^Ü_¶I`` ØÐjµ:΢>­Ì‚Q«Õb£Gõõõ¶©p mù«1gïÞ½GŽ1bDppðZv¨ªª’Æ 29~¿~ýŒîðL–”ŸŸÞ§O•Jåááqùòe“%UVVµÜoªªÊñ§µÃ"äe›”——K s+tšëcéG|T‰ÎÁä_D÷îÝïÞ½+¶«««¥ÎF¿ö!!!{öì©©©ÉÌÌœ={vËÁ}}}¥ñËÊÊLþU†††?~\¶¤¨¨¨™3g–••555]»ví‡~0Y’ŸŸ_YY™ìUKŽ?>jÔ¨¶÷‡ã#/Û$11Q§ÓétºÄÄĘ˜«û´…··wII‰Õ‡Âä_ÄÈ‘#×­[WWWWQQ1wî\©³Ñ¯}ttôéÓ§AæÊ PYYYYY™ݲ€I“&½û%ÕÕÕõîÝ»gÏž.\xöÙgÍ•4kÖ¬øøøòòò7n´eé±wß}wÒ¤I²ÝàDÈË6  >|¸V«]ºt©Õ}Ú"55u̘1ÜeÂÙ™ü‹Ø²e˼½½ÃÂÂ&L˜ u6úµŸÏÁçûXS–­­^½:""BlwdIééév:´Â†ó}”¾؉øåŽ·ÿ~EÎ »âýXä‘—¶¡çy€ü‹pÀ’à\ÈKä‘—È#/G^ OÉï“ÔÕÕ ‚ß»woË€MˆOμyóæ¹sç¬^¡–’y)þöèÑ£ ÖÛº}ûöwß}G^vYßÿ}ZZšÒUÀ±xxx¼ôÒKJWaJæåàÁƒ«ªªþßÿûO>ù¤‚eXdÉ’%¯¾úªÒU8¨×_ÝðÙcè‚îÞ½›••¥tp,¾¾¾äe{=ùä“â*êÏ?ÿ¼‚eXdÉ’%6¯V¥RuŽo†åææ’—¡W¯^þ󟕮ʻ}ûöŠ+”®Âfx”QVVV\\ü»ßýNéB`{=zôHHHPº (ïòåË)/™k±µk×úøøxyy-\¸°¡¡¡e•Je²Ñ’#â¦ô¿Ò«â=·»»{@@ÀÖ­[í{1J(**š>}úƒ>ªt-ÐVä¥Årss KKKÓÓÓ­î#Ò,› î‰]¶lÙÍ›7;vòäI›×¯ 1)ÿã?þãÝwß}æ™gú÷ï¯tEÐVä¥Å²³³5F£ÉÊÊÚ¹s§Õ}Ìquu­ªªºzõª¿¿§¹¿4LÊææf777¥Žë— Z­V§ÓYÝÇœ½{÷9rdĈÁÁÁhO©ŽÀ()Åüã¹¹à\ÈK‹•——K FÓö>Ý»w¿{÷®Ø®®®–:}®²gÏžšššÌÌÌÙ³gÛ¶øŽd2)Aàæ€3b~¬Å·oß.6bbbÚÞgäÈ‘ëÖ­{î¹ç®^½ºxñb©³··wIIÉàÁƒÅÍèèè´´´   A\\œò4EEE¯¼òÊûï¿o“’x`ýúõ_•EΟ?/Baaabb¢¥ÇöèÑcÕªUv( €’ÈK‹…‡‡‡„„466FEE-]º´í}¶lÙ2gΜôôtŸ”””>ø@ÜŸšš:f̘›7oŠS~&OžyáÂ…ÁƒïÚµ«c.ʆª««'MštïÞ=s ;²$«?ÞŠoß{zz’—@çC^ZFŒ´äääÖ»%''·ì3lذ'NH›qqqb#)))))IÚe›r• V«/\¸ðꫯnÞ¼YzÿÙÐÈ‘#ccc;¾0‹mÛ¶íÁ´è-ñúúzÞj:+ò¶çãã³nÝ:ñÙ-Só›o¾Ùµk× Aƒ”*¯-öîÝ»mÛ6­VkÑ÷îoÞ¼I^•S~<§ ¦fyyùsÏ=×£Giÿ?ü°råJ +—¶×9k+&Só¿ÿû¿Ïœ9£la`òÁ(5¹ÅD}Û Py‰Žc˜š|𷘜y‰Ž&¦æ¥K—¾ûî;¥kAG³Ój܆¢—P†‡‡Ç„ ”® `58)žO¢×뫪ªAÈËË[¸p¡ReÀ†JJJ”.N@\@„¬¬¬É“'¿øâ‹m?ÖÜjL²CP,/›šš222AøöÛo¿ýö[¥ÊÐÁÚ¹ÁŸÿüç—_~¹OŸ>ÙÙÙ'N´C€i ?¯@¥R™{d¹ª¬¬dU sêëë¯]»öÐC9øƒ ¸òòò!C†¦V#¿q$»^¯ÿè£fÏž}ùòå,]ÂyÙ­[·K—.)[CÛ©T*›W«R©:Ç[I{÷î2eJ`` ŸŸŸÒµÀ¡Ùc5‚NówGÆ|J\`øðáZ­Öp5‚x{{‡……NW#î2ÅÕ<<<ÒÒÒœq585òÒ2&§Âjçtù¦¦¦+V 0ÀÓÓÓñ½¬œœ|åÊ•ëׯoÚ´ÉÍÍMÜ)®FP__ÿÝwßÅÅÅI7‹III7nÜ6£¢¢Îœ9S___PP&ÉÍ%:yi™¶L…oÏtùŒŒŒO?ýôÈ‘#ååå•••6¯`òÒ2âTxF“••µsçN«û˜³cÇŽ7jµZOOÏÌÌL[” °òÒ2m™ ßžéò•••â\ SâS8/òÒ2åååRÃÜ7aLö§Ë‹íV¦Ëûùù•••Ù¶f@û‘—–ILLÔét:Îp*|[úˆÓåëêê***æÎ+u§ËK›³fÍŠ///¿qãFbb¢]¯Ðvä¥eLN…oKŸ6N—_²dɘ1cƧÕjýýýí}9€6RøyÎEüè%99¹õnÉÉÉ-ûˆÓå¥Í¸¸8±‘”””””$íïÖ­ÛªU«V­Ze›Š6Âý%òÈKä‘—6Ætyè”ÈKä‘—È#/G^ Oáï_êõú“'O*[lâìÙ³J—v¤p^666Ž=ZÙ¥X^ªT*’²ó Vº(¯¹¹ùÖ­[JWåݹsGélI±¼tuuýüóÏ•:;û©©©ùùÏ®t€ñüX6ãââBRÂHïÞ½•.Á6ÈK6ãíí}ãÆ ¥«ì‚ï“ ¼@y €<òyä%òÈKä‘—È#/G^ ¼@y  SQ©Tí·n4tAä%û"rÐ9—ìK¯×ÛdrÊ"/G^°/ÃûB•JµyóæÀÀ@77·aÆ}öÙg;vìvww=zô™3gÄ>k×®õñññòòZ¸paCCƒ4ˆJ¥’F;{öì´iÓ¼¼¼<<<"##kkk¥³´<ÜHssóÊ•+اOŸÙ³g×ÕÕµR¿ÉÑÌýðáÃ!!!îîî[·nµô\pdä%€µÿþÜÜÜëׯ?ýôÓ{öìùøãkkk'Mš4oÞ<±OnnnAAAaaaiiizzºð㛺z½^zwwúôé ,¨¬¬¼xñ¢F£yá…¤S´<ÜHVVV^^Þ‘#GΟ?ßØØ¸bÅŠV 69š¹³ÇÆÆ.[¶ìæÍ›ÇŽ;yò¤¥ç‚ƒÓ«Túö2dˆ §OŸn×(€#Ù³g S¦L±è(q©dOOO;Ue$"B/ú>²æØœ½ è-²ì¨ŒŒ ARRR,:Jø1çÄvUU•Øï´._¾,mº»»‹}N:%î,..Öjµ-Ç1rëÖ­þýûKÝd4hЙ3gÄvuuõ€Z)ÞähæÎîçç—““sñâE+Î{ðõõ5ü­³‚‡‡^ô·n鹿Сúõë'6zôè!‚Z­–6ëëëÅv`` ØÐjµ:Îä8ùùùááá}úôQ©T—/_–^’=üÂ… ƒ ßÝU«Õ—.]j¥`“£™;ûÞ½{92bĈàààXz.82ò€Ã)//—FlÍŠŠš9sfYYYSSÓµk×~øá‡Ö7äïï_Å] IDATQQ!Ý@ÛÆbÌ=$$dÏž=555™™™³g϶ô\pdä%‡“˜˜¨Óét:]bbbLLŒ¸ÓÛÛ»¤¤DêSWW×»wïž={^¸páÙgŸ•=ÜP\\Üœ9sJJJŠŠŠ¢¢¢,-ÆÜÙ£££OŸ>ÝØØ(‚‹‹‹¥ç‚##/8œðððáÇkµÚ¥K—Š;SSSÇŒ#ÝenÛ¶-55µW¯^aaaãÆ“=ÜP||ü“O>Ù»w˜èèhK‹1wöÉ“'GFFzxx¤¥¥íÚµËÒsÁÁ1ß0Æ|“¬˜ïÓÔÔäêêjÑYóózK1ßGÞ‰'‚ƒƒy  ¬¯¿þÚä'ˆ€Óq޼´"ö’““322ô6zë„……¥¤¤(]…<•)JÇâªtmÒ–ØS©T†Ý #""ìYywîܱôEþ™Ë¿­!Ë9î/­pûöm777¥«t ç¥ÉEŠû333ýüüÄ ÙFϟܲeK@@€øÀÉââb¡Å³%[>jRrï޽ŋ«ÕjµZ½xñâ{÷îuÈ…œ›òïÇŠÏfaÖ¬Yééé/¾ø¢¸ÿèÑ£_|ñ…8µÉÈÁƒóòòúöí»~ýúyóæ}öÙgz½ÞðýX£MC«V­:uêT~~¾ 3fÌX½zõË/¿l¯kº˜ššš .(],öË_þÒÃÃCé*œ€’ß'Ì?éñ»ï¾3ìfØnùÀI}‹9è‚™)éÒ‹ŠŠL> àû$&É~ŸdóæÍJý‡ íñ‘u¿FÎÀ†ß'QþþÒÜ“ýýýÍbò“mTUU%1((ÈÜ£)Xí¿øÅ€”®mröìÙ[·n)]…sP>/ËËËÅ;T£'=Z:™»ý}}}¥3–••ñÍ0Àæ¦NºiÓ&¥«@›üö·¿ý裔®Â9(??VöImdôlI#RšFGG'$$TVVVVV&$$ðl*@[(Ÿ—²Ozl#£gKš³|ùòÁƒ‡†††††:tÙ²eVŸÐu(Ÿ—ÉÉÉW®\¹~ýú¦M›¤oLê:µÕpÓÜKIII7nÜÐL‘5Ù­{÷î999ÕÕÕÕÕÕ999Ý»w·éÕ:'åóÇG^ Oá¼ÔóÌF€3àþyJ~ÿ²´´477WÁà°ÆÿÀ(]ü›’yùå—_ÆÇÇ+XÖ®]»ÈKEùçû 4hüøñJWGñÉ'Ÿ”––*]S>/G•““£tp±±±ä%¤|^LSSÓ±cÇ:àDׯ ‚  ={Z|ìùó‚ :`Q¥‚ \ºtÉÜž;wÎâR'A^6vçÎqãÆuØé’“­?ö½÷„÷Þ³ø¨·Þzë­·Þ²þ¬€s"/›quuíȤ,*®_†úô±øXN(+4!(È‚£.]ºT^^îçç'-Šg¤ªªŠ[LtVä%`3÷ß^^^‡î·¿>úHÈÈ&N´øØ…E‹„©S…ìl ŽZ»vmJJÊÓO?½fÍ“¶lÙgq5€3àyÈ#/G^ ¼@y €¼Nž—'NœV©TJpnΔ—VÄ^rrrFF«lÚÉ™ò²-±g”©………v«ÐU8S^ZáöíÛnnnJWpz‘—*•jíÚµ>>>^^^ .lhhögffúùù¹¸¸?½wT©T[¶l pww=ztqq±ÔA¥RI ÃMÁªwt$/AÈÍÍ-(((,,,--MOO—ö=zô‹/¾hnnnyÈÁƒóòòjkk'Nœ8oÞ<áÇ7lõz½Ô0ÜÀjŽòüØììlF#BVVÖäÉ“_|ñEi¿¯¯¯ÉC6oÞ¬V«AxþùçÍ=ÍÒÁ t€‹/~üñÇJW6©©©Qº§á(y)-w Õju:´ßßßßÜ!bX ‚УGúúz»– íöïß¿ÿ~¥«lÌQò²¼¼|È!bC¼ÑYú‰#ŸP ò÷÷ŸhÅj)PZß¾}•.Á 8J^&&&nß¾]lÄÄÄX=Ž··wIIÉàÁƒM¾ªR©xK°Ÿˆˆ¾Á…ÎÊQæû„‡‡‡„„ >\«Õ.]ºÔêqRSSÇŒÃ]&À¶%/“““¯\¹rýúõM›6Iߘ4º4Ü4÷RRRÒ7¤ÍVFPœÑ×cL¶ÂQòGF^*ÆÜí²CÝD‘—$ÀÁ9D^ààÈKä‘—È#/G^ ¼@y €<òyä%òÈKä‘—È#/G^ ¼@y €<òyä%ò\•.@xë­·Þ{ï=¥«€£¸wïžÒ%€ ÊçeSSSSS“ÒUÐ%ó2:::22RÁà°ÜÜÜ”.~BɼtuuuuUþYÌ÷@y €<òyä%òœ//U*•Ò%ºçËK:žòy©R©Ö®]ëãããååµpᆆi¿Q7Ãÿ•^=|øpHHˆ»»{@@ÀÖ­[[Žï޽ŋ«ÕjµZ½xñb°‚òy)BnnnAAAaaaiiizzz+=õz½ø¿bC„ØØØe˖ݼyóرc'OžlyȪU«N:•ŸŸŸŸŸ_XX¸zõj{\ ssˆ¼ÌÎÎÖh4&++kçÎëêêZUUuõêU“÷—»wïÎÎÎîß¿ÿþýsrrvïÞm£ª]ˆCäe`` ØÐjµ:΢c÷îÝ{äÈ‘#F8p e‡ªª*iü   KÇ@p¼,//—FlwïÞýîÝ»b»ººZêlô¹fHHÈž={jjj233gÏžÝrp___iü²²2i|ÚÎ!ò211Q§ÓétºÄÄĘ˜qçÈ‘#×­[WWWWQQ1wî\©³··wII‰´}úô鯯FA\\þ}9R¬FGG'$$TVVVVV&$$DGGwÄ%:‡ÈËðððáÇkµÚ¥K—Š;·lÙràÀooï°°° &HSSSÇŒ#ÅáäÉ“###=<<ÒÒÒvíÚÕrðåË—<844444tèС˖-ë€+t2±‹ «9è|Ÿäääääd£Ã† ;qâ„´)-Åž”””””$íŠŠŠŠŠj9&ó}VsÐûK y €zôèââb©ƒJ¥’†›@+ÈKÊÈÍÍ-(((,,,--MOO·ºÿÑ£G¿øâ‹æææ–‡|¸V«]ºt©Íû›“šš:fÌî2a)W¥ ЉóQ“““Mî7)99Y¶+ áI›IIIIIIm9#`ˆûKä‘—È#/8Þ5…â”ÿüòóÏ?¿}û¶ÒU@yµµµJ—f)Ÿ—Ë—/WºM¥R™¼e4·Pœ’yùðÃ÷îÝ[Áà€¼½½•.LP2/_yåÏ ã>6Ç|ä‘—”a«õ/º ¦Vµ<|øpHHˆ»»{@@ÀÖ­[m1èÈKʰÕú—-µ\Õ266vÙ²e7oÞ÷‹3ßnÞ¼)Æá’%KêêêÆWWW—––ÖrðåË—'''‡†† ‚ðÔSO-[¶¬£. èf̘¡t €Ý9J^&'''''íg¾I›qqqb#)))))IÚß­[·U«V­ZµÊèpij\÷îÝsrrrrrl_7 kp”ù±82òy‘—,ƒpp‘—88òyÊÌõññ©««SäÔpXï¿ÿþo~ó¥«Ó”ÉË»wï’—0òÃ?(]˜¥ä÷/kjjÄgÝ¡‹‹ŒŒ>>^^^ .lhhögffúùù¹¸¸?ýW¯J¥Ú²eK@@€»»ûèÑ£‹‹‹¥*•JjnºwïÞâÅ‹ÕjµZ­^¼xñ½{÷Œ:äçç=Zl:uJl¿ùæ›bãÔ©SAAA†õ–zöìÙiÓ¦yyyyxxDFFÖÖÖÊ^©ÉýÍÍÍ+W®8p`Ÿ>}fÏž-=³Åèt‚ <üðÃ_~ù¥¥?yØ›Cäe+¿vFÝS6MMM+V¬0`€§§çúõëúè`¹¹¹………¥¥¥éééÒþ£G~ñÅÍÍÍ-9xð`^^^mmíĉçÍ›'üø†­^¯—†›†V­ZuêÔ©üüüüüüÂÂÂÕ«Wu¨®®îׯŸØ~üñÇ;&Beee||ü;wÄÂ&L˜`xˆa©Ó§O_°`AeeåÅ‹5Í /¼ {¥&÷geeååå9räüùó+V¬0÷“ñõõ­ªª’ù)C z•JßC† áôéÓm?äþûïáûï¿—~û{ì±ÊÊÊÊÊÊÇ{쥗^2ü#‘?ý㑬\¹ò¿þë¿ÊÊÊ®_¿¾xñâ–ýáàÄ¥>úè#¥ ù·={ö‚0eÊ¥ iMD„^ôÖýØrrô‚ _´È²£222AHIIi¥ §NÛÅÅÅZ­VÚÿÝwßv3l_¾|Yl×ÕÕ¹»»·ìÓrS(±¨¨H:£¤{÷îuuub{ß¾}¿ÿýïõzýš5kúöíûúë¯ëõzñýOÖjèÖ­[ýû÷—½R“û tæÌ±]]]=`Às§ûþûï¥ÚÉ××W„ªª*«GððÐ ‚þÖ-½CÜ_ ‚­Ñh4MVVÖÎ;-:vÇŽ7nÔjµžžž†Sàô,« (!00PlhµZN'í÷÷÷7wˆZ­=zô°tjhUU•tÆ   Ã3Šúõë'Ý®=úè£'Nœa÷îÝo¼ñÆo¼!ÂÉ“'}ôQÃC KÍÏÏïÓ§J¥òðð¸|ù²ì•šÜáÂ…Aƒ‰ï©ÕêK—.™88òyä%òÈKe>BÚ\à8ÈKä‘—Ê0|¤‘¹6Àq—œÌ‰'‚ƒƒùðŒ¼ $+b/999##ƒ7cÐÁÈKJjKìejaa¡¸Æ8БÈKNæöíÛnnnJW.‡¼`*•jíÚµ>>>^^^ .lhhögffúùù¹¸¸-¾OµeË–€€ww÷Ñ£GKT*•Ô0Üø: y À^rss KKKÓÓÓ¥ýGýâ‹/š››[rðàÁ¼¼¼ÚÚÚ‰'Λ7Oøñ [½^/5 7C^°—ììlF£Ñh²²²vîÜi¸ß×××ä!›7oèÙ³çóÏ?_PPЖ³œèä%{ Z­V§ÓIûýýýÍ¢V«ÅF=êëëíZ`ò€½”——K F#í·ôG>¡„# /ØKbb¢N§Óét‰‰‰111Vãíí]RRbîUÒƒ¼`/ááá!!!Ç×jµK—.µzœÔÔÔ1cÆ‹Py À^’““¯\¹rýúõM›6Iߘ4šžÓÊó“¥Í¤¤¤7nH›­ŒØy €<òyä%»àmRt2® žû¥—^êÖ­›‚ÀA”––*]ÈP2/×­[§àÙt*•ÊÑîtÍ•d]©x•2yùòË/K_D<ð€Ò% ‹"rÌ‘¾ÃÓúϧݜ2y™””¤Èy %[ýW¾Sæ®Ñ~RSS_{í5•J5wîÜÕ«W‹I)öéô_UòýX€yíµ×:$>Ú´iZ­öOú“ÒEuæÇèäL.ÃiÈh ÎÍ›7º¹¹ 6ì³Ï>Û±cGpp°¸$ç™3g3K{¶\˜óìÙ³Ó¦MóòòòððˆŒŒ¬­­m{IÍÍÍ+W®8p`Ÿ>}fÏž]WWgéš;ûáÇCBBÜÝݶnÝjÑéÞ|óM±ÛÀW®\¹cÇŽVªê|ÈKœ¹e8ÍÙ¿nnîõëן~ú鈈ˆ={ö|üñǵµµ“&M—ä49fË…9§OŸ¾`Á‚ÊÊÊ‹/j4š^x¡í%eeeååå9räüùó+V¬°ôÍ=66vÙ²e7oÞä%€NÎVËpÊŽi´Ng]]]ïÞ½{öìyáÂ…gŸ}Ö¢’âââæÌ™SRRÒÐÐPTTei1æÎ}úô鯯FA\\\,:ÝŒ3–/_^QQQQQ±|ùòY³fÉýœ:ò@'g«e8eÇ4Z§sÛ¶m©©©½zõ 7nœE%ÅÇÇ?ùä“‘‘‘½{÷މ‰‰ŽŽ¶´sgŸwè4X€ÄyÙ¥Ö?`ÒÆ7nܨtprjócØ@§üï#`ˆ¼Ð.ññññññJWØß'@y €<òyä%òÈKä‘—È#/Ç÷/X¦¦¦¦¨¨Hé*€6ill´ÕPä%Ëlß¾}ûöíJWt4ò@[õíÛ÷ÁTº Àbݺukÿ ä%€¶zæ™gžy楫”Á|ä‘—È#/G^ ¼@y €<òyä%òÈKä‘—Èãyx@×õí·ÂÆJ8¶††ÿk—@×uô¨pô¨ÒEN‚¼º¢‡-RºÀyÜwy tIcÇ cÇ*]àT˜ï€<òy®‚ èõBjªÒ…°Pi©Ò]Éÿ}~™‘¡l84W’pj< t@×ðÿß}“½°÷þIEND®B`‚trusted-firmware-a-2.2/docs/resources/diagrams/romlib_wrapper.dia000066400000000000000000000047571355360272700253620ustar00rootroot00000000000000‹í]Moã8½çWîË,aXüfg’ÁÎa±‡ö°³§Å"mÅÑŒ,’’t.ûÛ—¤äŽãHŽc‰N+ ÑÝi* ŸH=½ªâGå—_¿­ÒÉC\”Iž]Máé$Îæù"É–WÓÿþ·ŸÕô×ë³_IôÕü]Ñjb~"+méjzWUë¯(}*£*/PšÜ£2¾ø_”¦Ñ…©t1½>›L¶XDUd¯5W£ª*’Ù}O²h_MgÑüÏe‘ßg‹i]«©7ÏÓ¼˜YÄå4{Y§£¥»¦ÚÅ[£¾[ïЩ/ík‘FOqÑ4ÿÛ³™ž4¸QœI4¯’‡MikLòÙñ¼j:û¯*ÊQ±˜ü<ù-ÿ6}öAŒ’,®¦ÿÄ/k·{¦1£ƒ¯Fk§ÁH !Ï",°Øˆ×2Ò3›í¢¦Q¶Lãg$h‹KÂ0[ˆÃ±Èq¯næy‘½ö†î¤ƒróº£yaˆ½õÒë.N–wU7E oVÞå7-åÛÖ²ý;x¦ñ¼þ=þVmbÃÄÖŽ^Ä<{ßÄÞ “—„"ª¤²Eͤ:¸²£ò†¤ïÔézºÎ~QoÇ]þcµ®f)J:œæ=–¦Ëmɳª Ð^ŸÜF«$}2÷eåtRVOVœÕ?ú÷8}ˆ«dm+÷ûïàÕ«Óòú`¤ðËëú’ïâä1p/mðž@ ã~@ÆÃ]f«¸ý™ÆÙýªÏQZ-ìûÞŽwK»ïÇó­Ð“Hé-Q€ˆ¶t`À¯DmŒÍÐF¢ Åô8Rz µ6_ªÛ³".ãâ!^œ­ï«y+ïrÕÅÏ W?²\µG ´·ZiDµ6lÀç>ÕÊ ± KÎ/©FÒ•5ÂÜkœ0D‰ íz—R’ñ-,9Æ8¡Õ¬/«©y\sÞöÉj‹„$ÀŽÕ€ZueTù¤õ }<„Ö iLAc`Ô¾À’ƒGZDˆä .€R`Ÿ(ü娵ÖÔH™±á‚H¿j]#a$„”—Ô<¡2ƒc‘Oï\¢<8”ÞÊ.R‡r|¥Âô‚æ6 Õœúµ¼D4@˜Zà Z±sPˆJíÛðöíáavW¥©qó41f÷hÕ=ÐîR)0ck!8#R~"»+‡ 5æ`9ÑLùö'-CBkeí.…™16†Iûj¬®«ÛIÉ`uÇguU_RH*ÂìL0(åsÎÙш*qi—y0C„*¯Ë½Ctñ³+‘äÛo2Í.|žI=‡¥}ÀÜ:rž9L ÖpØ D˜w÷îbà°?€ÄB:=é›ÄБ†ÄظÄ;‰{w1Øç.›ÞÛl€ Á¥3¶Â¯?a番7qijxLMÔ+ˆ-«£ŠSÆ;³I=Ó"ßO')?CÄã‰x¾T–™wÙ(OùêUÛ|grg´ª¡h•»@gòü]cJ^oÑÝit E$C("«!}+¢ Z[$¬jEŒ¹²"#QÄûª zx =l¥dÐÃÑè¡ 8>Fé ‚XBûD+€&jÆ ríÊŠFÃÎÆÓb%ƒ ŽFõéaÿ-gF°v¬"ÌëÂ7Aˆ ‘ Ñô’Ú ZÒ•µ<ù´zh§Dö\ä,*ãÿàÿmô¾\ØEÏ #<¤|¹š>H$•â~åŠkE,hÊ­\IM]YÓc‘?R®H«SÈU;=ƒ\ýÈrõ$‹Û–ÕÄÚA ;×!½:W ãÜâPN/Ýsib)Ž”*ë±ÞÄÙÂõæ˜>¶:v±O(Ws+cÏûîËp`¾Þ½¶¤ïZkË7QQäÝ”#¤gÓ7iœ-÷-bÄûB¼±4y0ÂQ1P÷œP÷ÏÂGO(õÞc©Môbg3 b‚úœOÚR®œSÃìtA覓Êj‘ä(Ÿü´qKþüßþH9ÃfË1FOj€sXRœkÄýO eؘ؉#‹`®Ž"tª¥*šüôXDëu\¥:Åi¬Vj¥£RéN®m'‹J2¿'W6HXæN®º¬è±È§>¹ò5Ô ®´32(ÔÓ%á! \-¹ç£u UجãÜyÂG“-)ÔIªAŸF8õLú§œäÆŸ©óeùN9iwHÆs’—Æ•g\B7lþã{ú¹«Ÿí•˜æõÎCaþùSÏ?³÷Ì?SÏÓÏíç¶énK?7¡ 0éõÔüœ#-˜¼e¾r»ÆÉ©à~lõíÝ—ÿÌ’ ¦ 0ÃJ~¢üg„ö_Lᄲs‰˜ÖÊëZ “5ÓÊšIá¦'¥¹ì“Ñt0ä>;å¡DÂúsZpmž8pâ•ÑE Î@ÒŽd“ñ,Dˆ{™ÂÃñå]!|Ck  q}4'Ì«.9ƒg0aÎÔR‚Q„ø6µ½»x`¾30'cLPB%ÇÔ«­ÅÒ˜vó‡2›ýCÓÏdkÅ´VÌeÿd ƒ_Z[ ”â` .—5® Çâžxͨ ÷·ÁèŽÐè°UPPæf*#Ô¿:Ù YM¨5º¨pKÚBQ¿F·C’Ñ“]ÕŸÖRbV'~ðëJÖ8Ôˆ©¶6W*ܤðc!Áh0¹{Ù,îwièþÚ¤°t9¯‰Ò«8Õ@ n ŽÑ˜!Ã.² N{ùäi„òDñòdÜJ{¦Grî×wÚñd<ñº¬1‡÷Ty:…<µò1ÈÓå †ˆì=Wˆ î9°30)ç8 í0ð°»5(Ó^*]£. °ëM ÍÎ9^õçw,¬.a`¶ ðxN0]ò­KíT º4F]êŸ\”"A€ŸÛß6#|†sÏ@ÀÀ„șÔ3%¥Ä‚9„P&ïYE;¸¤iŒÒĆ&MÜo]¦ }úP}ªËiô×guÁü]Ñêúìÿ‹¸ Œ›trusted-firmware-a-2.2/docs/resources/diagrams/romlib_wrapper.png000066400000000000000000000274651355360272700254120ustar00rootroot00000000000000‰PNG  IHDRotÍ4îsBITÛáOà pHYsÐй‹çŸ IDATxœíÝ}XSWžð“D¥¼T"DB(²»F:­tæñ¡Ø©etpX­DÖÑem•U–5"/vª„мtGmÕ©³êl·O·Ðº.:” Z;h'ÒÙ".BÑ„ßß%¼dÿ¸Ó»iÞLroHH¾Ÿ?:'7çžó»Ì/÷žsïáhµZ pÙjˆÃá°ÕÀäÂZ6¥!­€»±"›Z˜&qéÜ ûç¦îÆx6mll …>>>‡"ߟ˜r8ú U£Ñlܸ100Çã½ûî»ô¾t…ááa±XÌãñx<žX,6ìèêÕ«Ë—/ ôóóKKK»}û6»‡0ŒgÓÕ«WÜ¿ÿìÙ³çÏŸ'ß_¿Õjµô…Ü’’’«W¯* ¹\^__oØHqqq[[›\.—Ëå …¢¤¤Ä°ÎŠ+6nܨT*¯_¿Îçó·oßÎÚ‘LŽÑaÎððð­[·.[¶,,,ìÿ«r~P9**êóÏ?î¹ç!­­­ñññÔ»t5@pâÄ ºÂ²eË:;;Í„òðáø¸¸7n°thÄø¹i]]L&›7o^tt´ÑóNBˆJ¥ŠŒŒ¤ÊQQQ†z{{u+¨T*Ã:r¹<999 €ÃáøùùõõõÙre<› …ÂÚÚÚ[·nUVVfffRõæôòùü®®.ª|íÚ5ÃFBBBè |>ß°Nzzúš5k:;;GGGïܹ366fó‘8Šñl*‰._¾<22BárÿZ'((¨½½®³jÕ*‰D¢R©T*•X,6ÚHNNŽR©T*•999"‘ˆ~‹NÌjµzÆŒ¾¾¾===o¾ù&[G0‘ŒgÓÔÔÔ´´4??¿¢¢¢cÇŽQóòòéDXPP/ ö³Ÿ6RXX›WPP`XçðáÃyyyÓ§OOJJZ¸p!K0¡ŒÏBËáé L!›0…l À²)SȦLq¼¼¼¸‹Ó§Oã>(pIF—v°‡ññqG‡`„.—;44äèHÀ•-^¼øü£££°ê¦L™âØ8ÀµÑϧpIøŽ` Ù€)dS¦M˜B6` Ù€)dS¦M˜B6`ÊÙ³issstt4‡Ãqt &Mh6µ!)J¥Ò²²2­VkxX1¡ÙÔ’¤¨—q EJJŠÝ"`³_é}øð!V`'ÇN6åp8åååÁÁÁ›6mÒh4ôöÊÊʰ°0j ÝóN‡sàÀˆˆŸ ´¶¶Ò8]Ð}©kxxX,óx<'‹±J+8kç¦ --- …¢£££´´”Þ~æÌ™ .]&úôéÓMMM·oß~íµ×6lØ@¾¿¬Õjé‚îK]ÅÅÅmmmr¹\.—+Š’’¶ÀZB—ËcÔ ‡ÓÖÖöÜsÏBÚÚÚRSS;;;©íß~ûíìÙ³éjt^äp8}}}<288488¨WÇð%M œ8q‚ê±µµuÙ²eTàœ-ZÔØØ(“É’’’ ûX;7ŒŒ¤ @¥RÑÛÃÃÃMíB¥RBÈÔ©S‡††¬ê®··—î1**J·G€ ÆZ6íêê¢ |>ŸÞní]1Ö ¡{ìììÔí`‚±–M%‰J¥R©T‰$##Ãæv‚‚‚ÚÛÛ¾¥›hE"QNNŽR©T*•999"‘Èæb-›&'' …Âøøx@ŸŸos;yyy‰‰‰OûÌÑ8#dS‡9qâÄŠ+…^ýõÏ?ÿÜÑQ8#dSp/B¡ÐÇÇ'""âСCäûS‡CŸ¡j4š7òx¼wß}—Þ—®0<<,‹y<Ç‹ÅÃÃÆ]½zuùòå~~~iii·oß6¬#—Ë,X@•£¢¢ÚÚÚ¨òï~÷;ªÐÖÖE÷^YYÆårÍ´ÏápÊË˃ƒƒ7mÚ¤ÑhÌoçwæÌ™™™©V«vGy饗¾þúk‹?l7‚l îeõêÕ÷ïß?{öìùóçÉ÷×oµZ-}!·¤¤äêÕ« …B.—×××6R\\ÜÖÖ&—Ëår¹B¡())1¬³bÅŠ7*•ÊëׯóùüíÛ·ÖéïïŸ5kU~õÕWÏž=KQ*•ÙÙÙ="„œ9sfñâÅtý3gÎ\¸pa||Ü|û --- …¢£££´´Ôüöªªª¦¦&™LvíÚµ‘‘‘;víŽÒÛÛkþv_\.Wk¥BH__Ÿµ;‚«¢þeæçç}799™"“É&8*Caaa555ׯ_×ÝH¾Ï¦@ÐÖÖF•/]ºDtr-UˆŒŒÔ­ ÌwúàÁƒÐÐPÃíÞÞÞjµš*öÙg+W®Ôjµ»wï~æ™g<¨Õj©+«tïß~ûíÛ'„бµ¶¶Ò±™ÚsåʪÜßß?{öl3Ý=~üØÇÇÇüÁº'œ›€{©««“ÉdóæÍ‹ŽŽ6zÞIQ©T‘‘‘T™¾Ðª«··W·‚J¥2¬#—Ë“““8ŽŸŸ___ŸaY³fѧz/¿ürss3!äøñã~øá‡~H9þüË/¿L×·¤}:6@ ›Ñí===111Ô…nwãÆ £ÝÑNŸLƒ.dSp/B¡°¶¶öÖ­[•••™™™ÔF½9½|>¿««‹*_»vͰ‘ºBgg'ŸÏ7¬“žž¾fÍšÎÎÎÑÑÑ;wîŒÖIHHøê«¯¨ò´iÓ"##?þøcŸŸÿü磣£Ÿ}ö™@ ðõõ¥ëëÆi¦}:¶®®.ÝØŒnïîî¦Ï±tÛ1œêüÕW_ýøÇ?6<@6÷"‰._¾<22B¡ç×µ··ÓuV­Z%‘HT*•J¥‹ÅFÉÉÉQ*•J¥2''G$ÑoÑH­VϘ1Ã××·§§çÍ7ß4ÌÒ¥K?ùäúåâÅ‹sssÿáþ’‘‘±iÓ&ÝAS=fÚ§ƒ—H$æ·gee½ñÆíííæÒ¥Kééé¦z$„|òÉ'K—.5SÁ­aܘø)Lÿþïÿþ£ýÈÛÛ{Þ¼yôßdEEÅÓO?M¾ýî»ï6lØàïï?sæÌòòrb0n:44”œ=44D·O×9yòä~ô#OOÏðððššòáYŠZ­ êèè ^~óÍ77oÞÔjµùË_ [6ß>!¤¬¬læÌ™þþþYYYß}÷ùíccc555111^^^ñññuuuF»ÓjµW®\yæ™g-ùœÝ ‡Ê¦F/A˜Áçó{{{ûúúx<kY&³Ý»woß¾=??¿¸¸ØðÝE‹566Êd²¤¤¤‰ À™•––ž;wîäÉ“l5Èáp´Æž2aj»å~þóŸÿô§?ÍËËcÒˆ«òptnÍè3ΉŔïzeÓ°°0¶â€ÉN÷Ž4wÃ(›ŽŽŽ²°ÂÔå\†—yÁ<³©î I4».\à´l̦ºmpsHŠL!›0…l ÀÔDßoÊüöa€'´ö¡4¶ñòòš2e žÞ.háÂ…r¹ÜÑQ€[(//ߺu+ÓlÊápÊÊÊ***FGGE"ÑÞ½{§L™B ÎA©—ô÷äû;Ÿ·nÝÚÞÞ\XX¸nÝ:½ö‡‡‡·mÛöÑGBÒÓÓËÊʼ¼¼Æ nbÚ´i¸ìgxxxxx˜*³pnJ-æNY»vmiié[o½eª&•Pu³ìêÕ«ß{ï½%K– ìܹÓ0›Ò ÜB~õ«_•””¼ýöÛÌcwpæÌ¡Pèè(Àeååå•••Qe~µUWWóù|>Ÿ_UUuôèQ«öõððèíí½yófxxø¡C‡ +?~¼ºº:44444´¦¦æøñãÌ` ÙÔÔ"ï–¨««“ÉdóæÍ‹ŽŽ®¯¯7¬`É÷ŽÅB65º˜»··÷àà Uîïï§+ë=yN(ÖÖÖÞºu«²²233Ó°qK¸p,²©ÑÅÜçÏŸ¿gϵZÝÝݽ~ýzº²Þ÷"‘èòåË###ä‡O+¤“®™îœ Ù499Y(ÆÇÇ ‚üü|jãêë냂‚’’’/^LWÎËËKLL¤“ejjjZZšŸŸ_QQѱcÇ /,,ŒMHHHHHˆ‹‹+((`0»8„.—kómÎxXbÑ¢E2™,))Éѱ€[xþùçårùÅ‹1§쇚ÓKÝoŠ;±˜B6`Ši6Åe^œ›0…l `ÍÍÍÑÑÑz7Ùƒ«B6x2’¢T*-++Ãp˜›@6x2K’¢^ÆU()))v‹œ‹íkÈ=xð€ÅP`²‹ˆˆÈÍÍutÎâáÇXAÒ}ØžM>Ü××Çb(0Ù½øâ‹È¦0é˜Y¤yïÞ½{÷îU©TãããºOªáp8û÷ïß½{÷ÀÀÀßýÝß>>‡Ò«À.-žJl°Ë¹)õ`…BÑÑÑQZZj¦¦VçgjËêÕ« îß¿öìÙóçÏÛ#<vÙ%›VWWóù|>Ÿ_UUuôèQ«öõððèíí½yófxx¸î¹)~?€Ó²K65õ`KÔÕÕÉd²yóæEGG×××Û!:–Ù%›}°ˆ··÷àà Uîïï§+ë ˆ …ÂÚÚÚ[·nUVVfffÚ#<vÙ%›}°Èüùó÷ìÙ£V«»»»×¯_OWÖ{zˆH$º|ùòÈÈ!„Ëýÿð0 œ–]²©Ñ‹8p ¾¾>((())iñâÅte½§‡¤¦¦¦¥¥ùùù;vÌá°‹éú¦FI¥R©Tª·qîܹÍÍÍôˬ¬,ª››«»Ätzzzzzºa›˜…N Oo` Ù€)ö³).É€»Á¹)SȦ6Ò½cÇTÜ„]æôLR}ôÑÕ«W8@@?>Á(dS™ZÃÆ“Úïÿû'N8: p:¯¾ú*²)€uV­Zíè(À)\»vÍ’å[MlÇápŒ^0µ& ‘H´dÉGGN¡¡¡Á’lŠYHàœdv˜“„¬C6·ÀÖ™"ÃtˆVW…l À²)¸½{‚÷ïßéåå5wîÜsçÎ9r$::ÚÇÇgÁ‚W®\¡ê”——nÚ´I£ÑÐp8ÝÖ «Y!¤¹¹9::.ÙÜÑÉ“'îÞ½»jÕª”””ÚÚÚS§Nݾ}{éÒ¥6l ê444´´´(ŠŽŽŽÒÒRòýuZ­V«{ÁÖ°¸-’¢T*-++À @6wtðàA@àëë+‹=zôþûïGFFR/¿þúkªNuu5ŸÏçóùUUUffôYX Ü%IQ/ã*Š””»EÙÜѬY³¨ÂÔ©S !<~944D•###©‚@ P©T¦š²°€Q>ôòòrtÀdS㺺ºèŸÏ§Ê†—òŒVctÚ^YYÆår‰Áðü"""¨ñøÖÖVb0ôn8ÔÉ ÙÀ8‰D¢R©T*•D"¡Ÿ(ÔÞÞþÄjzðéL Ÿ9sæÂ… ããㆻœ>}º©©éöíÛ¯½ö5¯7ônt$&)dSã’““…Ba||¼@ ÈÏϧ6æåå%&&êfG£ÕÀõ˜ ¯®® 1ºËþýû#""|}}·lÙÒÒÒbI/H«“ž,®ollÌÃãÿÿÔõ¾°L½”J¥R©T¯©ÜÜÜÜÜ\½Ê†ÕLµ‰ïÊÉËÔyxx¸©]ŒŽÇƒ«Â¹)¸¾o¾ù#šÀ©rk/ã㲿«B6×—””´mÛ6GG“›%ä–0z×…\;y1½ÒÛÝÝýøñcVBÉK©T::s=zdí.¸$ z¨ò‘‘‘ôôt&äÔÐûýû÷ñ7æb˜fÓ °‹ÊÊÊ…㥦¦.\¸ÐÑQ¸£ãèfÆàM½etèÝÔK˜DlϦ‘‘‘Ó¦Mc1˜ìÂÂÂÂ_ýÛ¿ýÛåË—…ã…††"›L Û³é¹sçXŒ€uùùù3gÎttŽñÙgŸýñttnwÈ€ËZ½zuLLŒ££pŒ7n ›²`á‰0§€)dS¦MœšÞ„j*$ÛBu´ÆM&=‡ƒÁ]Ctž6ÿáXXÍ<œ›Lzl¥R×8MÔ¥»DV«Ý¶m›¿¿@@ÀöíÛu·3ÿqn náƒ>øâ‹/¨õ|–/_.Ö­[ÇVã87pvF×*×¥·Pùþýû###½¼¼æÎ{îܹ#GŽDGGSë–_¹r…˜XÿÜpõò«W¯._¾<00ÐÏÏ/--íöíÛ–‡4>>þÎ;ïÌ™3' 33S­V[{€¦zoll …>>>‡²¼¯ßýîwTµ9sæ¼óÎ;GŽ1’µMœ©µÊM9yòdCCÃÝ»wW­Z•’’R[[{êÔ©Û·o/]º”Z·Üh›†«—¯X±bãÆJ¥òúõë|>ûöí–‡TUUÕÔÔ$“É®]»622²cÇkÐTï«W¯.((¸ÿþÙ³gÏŸ?oy_mmmÏ?ÿK¾ÿbšx›7o&„TTT8*‡KHH „\¼xÑÚ—.]J9qâ„=¢² •¨rkk«@ 0ZG·ÜÛÛK•©³´¾¾>ú¥™6ÍüÑ>xð 44Ô|Hº»ÇÄÄ\¹r…*÷÷÷Ïž=›ÉêöVSSsýúõ'ö¥w8\.W£ÑPeFóÔSOé…a4¼?üá„W_}Õð-jqªòòr­VëÈsS×î—dêT*-++ÓbŽ%°ÄÔZå¦Ìš5‹*L:•˜X·Ü’6åryrrr@@‡Ãñóóëëë³<¤žžž˜˜êº1Ç»qㆵhª÷ºº:™L6oÞ¼èèèúúzËûš6mÚƒ¨òýû÷§OŸn&$káJ/ÀX’õ2®B¡HII±[DàvL­UÎz›zÉééékÖ¬éìì½sçÎØØ˜å!…‡‡wwwÓ§qºûZŒ©Þ…Bammí­[·*++333-ï+..îÏþ3U–ËåqqqfB²›ÙÔè°61ø¿‡è&?îݱcÇìÙ³ýýý+** Û‹Å<Çã‰Åâááaƒ`Ñǽ¼¼¸¶Ö*b›z‹™«Õê3føúúöôô¼ùæ›V…”••õÆo´··k4šK—.¥§§[Œ©ÞE"ÑåË—GFF!\.×ò¾~õ«_vwwwww®]»Ö‚ÏÉR,Ÿ›Z>T®5î.++ûòË/e2YWW—ÑÕ§‹‹‹ÛÚÚär¹\.W(%%%ìîÆÌï¿ÊÊʰ°0êªÞlÉDDDPÓ#[[[‰ÁOCÃ_Š Qk•ÇÇÇ &k•?±Mj1súO÷ðáÃyyyÓ§OOJJÒ[Ýï‰!eggÿâ¿HKK›1cFFF†H$²6S½§¦¦¦¥¥ùùù;vÌò¾Ö¯_Ou$ _yå•ú§²ôò[³ˆeÃÚD'‰ênŠŠºté’™ö###éö/]ºdt¤œ“sÎB"„,Z´H©T*•ÊE‹ýú׿¦·§¦¦ªT*ú¥î.Ë–-ëîî~üøñÛo¿ýÒK/Ö1|9ñ0 É•f!=Ñè訇‡‡U»8üOtbXu˜¦*;f’µC应JeTT”™ ½½½tûQQQÖ¶`¨ººšÏçóùüªªª£Gên 1ºËþýû#""|}}·lÙBÝàXß|ó [ƒ©®Ç’«D¬\Ib9›Iööö¤Êýýýte½èÃÂÂ:;;Í4B·ßÙÙ‰¿`ÎÔï¿ððpS» à@IIIÔI’óãc¿îtÏ;™W3åljt$yþüù{öìQ«ÕÝÝÝëׯ§+ë w¯]»6;;»««ëÞ½{‰„ÞNÖ"‘(''‡º.—““cþ*<€%LÍK´ö_8†HÁ=z”••eÕ. 3‡ÍL]bu,gS£#ɨ¯¯ JJJZ¼x1]Yo¸{ëÖ­‰‰‰ .FÏ cccâââ Ø Ü[S%õ~€»aù©÷R©T*•êmœ;wnss3ý’þ •›››››Ko÷ôô,.....ÖÛþåâíí]SSSSSÃnÌàΨß###éééL¦JR? ïß¿ï2?´À*xz¸5©T:00p÷îÝ}ûöÑwˆêeDÝ—¦ÞÊÍͽwïý9ÀÝ ›0Åf6ÅïqpOX-Ü~ÿM.7oÞ ðð˜ˆo­»wïâŽv è®êj£¿ËÑÑÑññq&-€ëñðð È q8ä{]3fÌxñÅÓÒÒþùŸÿùé§Ÿ¶k_kÖ¬±kûàzeÓ•+W~úé§l…®¡±±ñå—_vtà‚¼½½³²²Ö­[W^^ž••%‹ƒƒƒYï%(((44”õfa² 2_…k&žžžO=õóv`²Óh4¸VvµfÍšwß}·££c÷îÝÕÕÕ™™™[¶l‰ˆˆ`±‹ßþö·,¶lúñÇ/[¶Œy;0Ù½òÊ+_|ñ…££Wæáá±k×®×_244ô›ßüæý÷߉DyyyÔRŽ‚ñ-p_z+¯¿óÎ;sæÌ ÈÌÌT«ÕTµÆÆF¡PèããqèÐ!35u¼{÷î3Ï>þ—¿üå×_íÀÀÀÍ!›‚[;sæÌ… ¨ ÔUUUMMM2™ìÚµk###;vì ê¬^½º  àþýûgÏž=þ¼™šº ,_¾üƒ> ßúàƒV­Zåïïoj÷’’’«W¯* ¹\^__?qŸ‚SQ«Õ÷ïß¿uë–J¥úöÛoÿ÷ÿ·­­íþç §×ÕÕ½ð ‹-jlltHÀàæp‡ Lœ¯¾úJ­Vsíæ©§ž¢ –‡¤»òÚÁƒëêêæÌ™CÙ³gÏ /¼PQQAñððèíí½yófxx8unjª¦^ƒ999¯¾úêæÍ›=<wËŒŽŽŽŒŒh4š‘‘¶ 6ï;::jÛ|æÆÆÆÆÆÆ¸¸8oooÖ?"3MaâMLGT¢²„îú ===111ôK:+×ÕÕíÚµëí·ß¨®®~íµ×LÕÔk0&&&..î?ÿó?W®\ùÉ'Ÿ$&&RïšÚ]¥Ré®àká!˜qøðá?üá–$°ááaæÝ±ËËËËÓÓsÊ”)žžžz…§žzê/ùËÈȈá^3gÎܾ}{VVÖO~ò“‰Ü²)LœŸüä'ã,3õ–åë£éÖ ?uê”áQ¡PX[[«Õjÿû¿ÿ;33³¯¯ÏTMb°4›X,þõ¯½råÊêêê}ûö™ïˆÏçwuuQ³i®]»fá!˜qùòåË—/[R“Ãáx~ÏhÓ-<±ó‚ùG4ÔÔÔüùÏÖÛèçç·yóf±X<}útÛ?2[!›ÂÄÙ¹sgRRÒtgÃ^YYYo¼ñFMM@ èèè(..þè£!"‘¨¨¨ˆ:Y¤Î#MÕ4ô³Ÿý,77÷_ÿõ_§M›6oÞ<ó­ZµJ"‘PwhˆÅb›ýÖ­[÷úë¯[˜À˜w714Íž={t·øøølܸ1///00ÐQQ88›âi/à<²³³¹\nZZZwwwttô®]»¨í©©©iii===±±±ÇŽ3SÓ(±X¼~ýzÝYE¦v/((‹Åñññžžž[¶la~»Qllì+¯¼Â°gsüøñ7nPeOOÏÌÌÌ¢¢"Ý•Þ'¾Ç€8<›8Þ7 —ËÍÎÎÎÎÎÖ«–žžžžžnIM£_©ëÖ­[·n%»{yyíß¿ÿþýÔË­[·Z|(îb||¼¬¬ŒÂårW®\¹sçNV˜˜cù‡S^^¸iÓ&FCo׫¦û_úÝÑÑÑ;vÌž=Ûßߟž$i¸;¸§O?ý´££cÉ’%---¿ÿýïí”Jíô=F‹Å<Çã‰Åb'œ6`ÿ~Ó†††––…BÑÑÑQZZj¦&õC^«ÕÒ¿èËÊʾüòK™LÖÕÕ¥T*Y &µ?ýéOçÎ;qâÄßþíßÚµ#»~·µµÉår¹\®P(JJJìq0ÁØÏ¦ÕÕÕ|>ŸÏçWUU=zÔª}9òÞ{ï ÿÊÊJz;Æ$@«ÕîÝ»÷¥—^š€¾ìñ=F;~üxuuuhhhhhhMMÍñãÇYЉýlJß0'¬] P©TbŒšÈ»~õööêÞXŒ…T]ûÙ´««‹.Ðí¼½½©r?]YïŸGXXXgg'ë!XÅ®ßc!!!tûŽ la?›J$•J¥R©$IFFµqþüù{öìQ«ÕÝÝÝëׯ§+µ··Ó/×®]›ÝÕÕuïÞ=‰DBoÇ,$˜Hvý‰D999J¥R©TæääˆD¢ 9&°/ö³irr²P(ŒùùùÔÆÔ××%%%-^¼˜®œ———˜˜Hÿ‘mݺ511qáÂ…@÷ mοê܇]¿Ç cccâââ &àˆ`"p¹\­MÒÒÒ!ÔC×è)m¶5.`Ñ¢E„ÆÆF÷’““ !2™lb"¡Î×ÞÞÎn³“èÏ{óæÍ„ŠŠ Gâ0 „‹/Ú°ï$ú?kÛ¶m„òòr­V‹ÙÀ}Ùû¶BpȦàÖp{4°‚ålªÅ¡0©Øõ¶B˜¤ð=6À¹)¸5Ü ¬@6·†Û£€ȦàÖìq[!¸!dSpk¸=XõMÁ­I¥R©Tª·qîܹÍÍÍôˬ¬,ª›››››Ko÷ôô,.....ž€8ÀÉáÜ€)dS¦MÑäiª N ·[0n ðWï½÷Þ®]»8—‚‚‚œœœ'VC6eD÷äÆT&‹ÁÁÁ[·n9: p.ôÝçæ!›ü€X,.,,ttàxÅÅÅ–?4Ùà|||8žå•1 €)dS¦M˜B6° ÜwîVM˜B6°‡Ã)// Ü´i“F£¡·ëUÓý/ýîèèèŽ;fÏžíïï_QQ¡W&;Ü!.kùòåÞÞÞŽŽÂ1”J¥£CpM ---„µk×–––¾õÖ[¦jjµZ‡£û —²²²/¿üR&“ìܹs"Â… „l .«­­ÍÑ!€«©®®æóù„ªªªÔÔT3ÙÔБ#Gjkk!D÷™xtšk@6ôÉ'Ÿ|÷ÝwŽŽÂñ¨ï}`Qdd$U*•ʪ}•JeTT”‚§€l .(66ÖÑ!€kêêêzî¹ç¨ýcÅÛÛ{pppêÔ©„þþ~º²Þ€hXXXggçܹs'0^˜8˜…`)‰D¢R©T*•D"ÉÈÈ 6Ο?Ïž=jµº»»{ýúõtå   öövúåÚµk³³³»ººîÝ»'‘Hè혅äM,•œœ, ãããA~~>µñÀõõõAAAIII‹/¦+çåå%&&ÒÉrëÖ­‰‰‰ .áááˆì Wz,%•J¥R©Þƹsç677Ó/³²²¨Bnnnnn.½ÝÓÓ³¸¸¸¸¸XowÌBr ,dÓòòòãÇ3o&;…Bá胅lªû£ À 1ʦR©”‡ ÄÇÇ;:»À%Y0ƒQ6}á…ØŠ`òœ^¦M˜B6` Ù€)dS¦M˜B6pRNø@|S!Ùª Íðœ^€IŒÃáెè>>!!!ëÖ­»sçŽa†<¨æðØz°+Ý%”&ØÞ½{·lÙòÓŸþtpppÇŽkÖ¬ù¯ÿú/G`+™L¦˜ „‹/Zµ×îÝ» !Û·o·STÖ"„”••Íœ93 `ãÆÃÃÃFëè–÷íÛ7gΜ)S¦ÄÅÅ}ùå—~øá³Ï>ëííýâ‹/¶··›jS÷ß)ÕTGGÇßÿýß̘1ã—¿üå­[·Ì‡¤ÆØØØ®]»"""üýýÿñÿññãÇÖ ©Þ¿øâ‹yóæy{{Ïž=ûàÁƒfúÒGÏÇ}}}M}†º¨%lKJJL5µmÛ6BHyy¹V«õX½zõ~‚[ãñxŽ`’ihhhii!„¬]»¶´´ô­·Þ2_ÿäÉ“ <¯ºº:%%%))éÔ©SÁÁÁÕÕÕ6lhjj2Ú¦V«Õ]±bEUUÕÑ£G5MaaáöíÛýôÓÿøÇfâ±²)€ó’H$*•J¥RI$’ŒŒ ûµÔÞÞN×Q«Õ3fÌðõõíééyóÍ7­ )++ë7Þhoo×h4—.]JOO·6S½‹D¢Ë—/ŒŒB¸\®å}íÝ»W*•666Ο?ß’ÈȦÎ+99Y(ÆÇÇ jÏNmæåå%&&Òg¨‡ÎËË›>}zRRÒÂ… ­ );;û¿øEZZÚŒ3222D"‘µÁ˜ê=555--ÍÏϯ¨¨èرc–÷µyóæë×¯ÇÆÆr¾÷øñcK?/ ™\˜¼\cÒŽŽzxxXµ‹›|í[u˜¦*[w‡ ËÉ&Ê7ß|ÃÖ`ªë¡Î³µ–=Y9dS€É*))©¼¼ÜÑQXÄhÞ2Ÿê˜°°e@6˜¬=zdí.öK`ÎÙï„Á,$¦M˜B6` Ù€)dS¦0§à¨XÀÍ577[^Ùàär¹\.wt0É ›üÕ¢E‹jjj8—ÄÄDKª!›üÕüùóí·Æ¸6ÌB` Ù€)dS¦M˜B6` Ù€)dS¦M˜B6` ÏB—uåÊG‡®l``€.#›€ËÊÈÈptà.MÀÅÆÆ::p<òf8™bI^IEND®B`‚trusted-firmware-a-2.2/docs/resources/diagrams/rt-svc-descs-layout.png000066400000000000000000002301061355360272700262020ustar00rootroot00000000000000‰PNG  IHDR;?¼{eàsRGB®ÎégAMA± üa cHRMz&€„ú€èu0ê`:˜pœºQ<ÿŽIDATx^ìý_ÌÇuß« š8Mà¨-ë71c‰Z í1a³©£ŽêSÇf§_j"uQ!júg·†°lâj4šÂ‚K8¼p`ƒ¾!ìraëÂû†Õ…¡è`àç ]äR¿7õVOŽföÏìîÌîÌîûƒ>Ï~fÏÌž=Ÿ×sfÎ9íå—_¾O/i@¤i@¤š5bÓK¤i@¤i f ÜWóà46i@¤i@¤{+¢Ò‚4 HÒ€4 HÒ@å±U~ƒ4l ”¤i@ØP"¶ •?¿ëy,2¿¿)gÖ3¶gŸ}voybÃé2åê“ÚÆ G¿*÷¾yó&Ž¥]½zr è‹ã÷ÄË´fÁG}Ç;•ïæÙ³gƒã8bÞ>vg è`³1`ä€9óØMš‰zS3i@¤m5 bÛVÿ©½ãë.ü¦†oRÖìè}á _ÿd  PšÃ†èÀ×Å‹S†èO ü=2á+ò‹z¾# $síûFèÁ… Äeš*ŒG:þxߪ¨o!æú Ž{'Y§ò=xqähFiñ ˜Õà¸ùÛp"ç†]‘ˆ-eÒª4 Hmi@ÄÖÆý"gà{‹b‰_Éþ‹[ÚÁ" àûžè×áw?! B†uD.¡ƒÇ¸Š§pœ3à·ˆ¥q½Ï»míÏÆìñÑ·[@l6nö2B娸埒;÷±ùSüüqÜ œŽÕÌ€¢¼ò;ÉŒW›¿:^Ža¹¿ñò‹§éÓ£©¯QJÒ€4 ¼¢[ÁcAúW2¿ãm± _öö}ïjøÊ'£$Gìð»Ý;•PIÂÄ;ϸûŠ4\‘ Ò“šÙ^´¾öéÄæc5lÁ‘ë‰Þ•Õéc#ûü„±ÅÇÍ9 ü>2 6² §gꙣ NLú6¦¾F) HÒ€4 bkhÌûJæ~vúçðï7Ñ{Ô0ä¢ói’Z‚T8ׄό*ȶ¹žž!| xÂ` % é‚aôµO'6¿^‰÷„Ônì#b%Ïò}à3úäìÅKF›åO%6ºô‚ñ{Çõn6Û¤9¬ÆÒ€4 4¡ùØš¸MázÙ¤¯d¸g¸p‰/uïg"qÓ/ƒNÒȱÑc‡1Zÿ2pD’)‡Ž."ÁH:Û¯Clæ† º³pà­Y§ò'¡0ðtz)û²åãN tOÕX¤i B ˆØ*¼)CšçcâpO_ÁþtÐ^ÛÝã@d4ñ›¹è|/|£ ȃ;ÆÀm–-oÐ’§ ‡××~!±Å«¢>BÓûØï#F }Æè …s…w@ùéÄFÔŽ3Œx>±µñ k”Ò€4 ,Ó€ˆm™þÖ:»“ØFÓñs«“5 ð¢¼ÿÆ;oR~1®ór¹s‹½p‹½ÁJÀ§ýy^²ïÈKC3bå@û…ĆÓý%sI7Ž<à ¯m#ã*$~yÑüŸÊO$¶`'œ¿Òà#îr³û8É»ÖV?Ò€4 H‹4 b[¤¾ÕN¾ã¹à˜‚Sä'ÛŸ,®q9Ò_…%Íç‰æ~¾Rë§øÈòPç˜QÌfäOa®–´ï[+Ú¹ ç—ìSŸx °ˆ «=`Wjãé»öDbC3Þeÿ²« Ûî@á!b[íÁTGÒ€4 ¬¦Ûjª^Ô¨"ð¨1e먛D‚¯p€Eœ××Ðôãc„f¼7p <…teŸlß7Œ£ÂYA{Šïq }çÀ|]Ñ@Wø(Hu†‘0œeÎM¹¯ü>b ºc²ßàåï87öaØÁxDl‹6, HÒ@•±Uy[4¨]k Å9ºD"¶%ÚÓ¹Ò€4 Ô©[÷%uTôlu¾F3ß&ö§N_£[Ü»˜ÝŒ{ÿ;_“„³0ïD®rÚ‚ï¶êo‘( HÒ€4 H‡×€ˆíðS@ ¤i@¤ê5 b«þi€Ò€4 HÒ€4px ˆØ?¤i@¤i@¨^"¶êo‘( HÒ€4 H‡×€ˆíðS@ ¤i@¤ê5 b«þi€Ò€4 HÒ€4px ˆØ?¤i@¤i@¨^"¶êo‘( HÒ€4 H‡×€ˆíðS@ ¤i@¤ê5 b«þi€Ò€4 HÒ€4px ˆØ?¤i@¤i@¨^"¶êo‘( HÒ€4 H‡×€ˆíðS@ ¤i@¤ê5 b«þi€Ò€4 HÒ€4px ˆØ?¤i@¤i@¨^"¶êo‘( HÒ€4 H‡×€ˆíðS@ ¤i@¤ê5 b«þi€Ò€4 HÒ€4px ˆØ?¤i@¤i@¨^"¶êoQ™>ÿüóŸÒ«€ Ø2wLR¥i@­ÛAoÿÿûÿžÿ'ï}ÿÅ}B?5•B±Rºli@¤’±•ÔnŲÿåêûÿþÿþR?5•ŠØ*žõš4 H k@ÄÖðÍ[2t[FP3Q"¶%sRçJÒ€4 h@ÄvÐé!b±têë²¥i@hS"¶6ïÛâQ‹ØDl‹'‘HÒ€4 ¬§Ûzº®ª'›ˆ­ª ©ÁHÒ€4 k@ÄvÐ"b±têë²¥i@hS"¶6ïÛâQ‹ØDl‹'‘HÒ€4 ¬§Ûzº®ª'›ˆ­ª ©ÁHÒ€4 hUTs C"6› i@¤†4 [C7+çPEl"¶œóI²¤i@ k@ÄVXÁµŠ±‰Øj›—4 HÒ@‡Dl"6ÛA§¾.[¤65 bkó¾-u‹Äö­;/~ç»ß/AZ¹dªJÕâ‰)Ò€4 Hݱtf´Hlo;ýöò©\tUBŽˆí “.[¤ò±•×q•=´Elð®×î»ï>[•³Iƒ’¤i@(®[q×ÙACÄJ{óƒ½ç}Ào[ÓI£’¤i@(­Û= ß¾};P´yá•—ÿô¥W^<œx÷îÝ«W¯^¾|ùÙgŸõ§@‚Âãþ„¯ q‰Iб=þ‘óW?óY,bŠØJÌÉ”¤i@hB"¶{ÔuòäI·ü‘3gÎàS ˜5áE\ó'^¼xž={–op¢ñÞó{Ù´Ábþô/`_éÙÓ±Ù†3[éY!ùÒ€4 HÕj@Ä–Dlà°abcÒ¼Ëí‰'ž0ž&¶€×™+"6E¬3ÓÔ‹4 HÒ@ ˆØÆ‰>3ó{uúØÐàúõëÁ-±³Dl‰x„䨩f?ÁYò±eyæ%D¤i E ˆØÆ‰ ˆvóæM[‰ k¦ÁÊ)§ÜltÎ[°m…™T§íëßü6bBùƒPÛ 3A]HÒ€4 4¡[±yüЉ-Þ Ç{–`µQb‹÷±±%fRÄ6슓­ÄLLi@¤&4 bK%6Äor•³oU4Æ,8Øàf%6ícK\3±5aS4Hi@¤±½¯i"7GgÐ×Faq¬(àÌ¢Aq:^$<¦ùÀ)D7{ùXQ›ˆ­Ä³-™Ò€4 H{Ò€ˆíÞÝ?QàüŸÁ4F€ÆÄ2Ãâ&£‚€6ÌôÁ¹BÔ³$m ,eƾÕÒ“¬ÅUѯ~íª+ZzbH¾4 HÒ@±Ý»/XÐ]³ï á¹N±•;[®ù)9Ò€4 HDl"6ÛA§¾.[¤65 bkó¾-µˆMĶxI€4 HÒÀz±­§ëªz±‰ØªšŒ4 HÒÀ°Dl!"6ÛA§¾.[¤65 bkó¾-µˆMĶxI€4 HÒÀz± éš…Añ²ðOAÚÿ²LAÈEã¸3‰ø”oëÝmדˆMĶÉÄS§Ò€4 Hó4 bëÕkL!Þ²<(^xsñâÅÎÂíÌ©æ ãt!hÈñB˜w ç%b±Í›9:K¤i` ˆØºÕðZÙg`/æ¼ J ø“™5רŽbóð‡Vù`ý{/b±­?ëÔ£4 HÒÀl ˆØºU>óìeµD‡‰e,knLl&‡½‚زäìqûEl"¶ÓF§HÒ€4 l¥[·æA]žØð'9Œµ§ü>6+HJüby®ÆÄ_ç²é:SAÄ&b[g¦©i@¤,±M&¶`›m\3‡öDl%¨¨f™ªR•Å*Iˆ4 HÒ@¬[÷¬àú¦}fq Ã«¢¶ÄÉf1±æ|¥Q­ŠÖŒ_3Æ&b“‘•¤i@(¤[·bË œB (?Æ{0ÝfAqw;ßã×Fc óÛãØE¡û:*V«¢3€lôÛèÄSi@¤y±õê©×à6ã¶ÃúÛü‹`ðÜi÷Ýw_XÀLlôá¡Í¼Û¶ü¬w¿û×ò'ßðSo|£~2j*…b—ßI¤i@ ˆØ†¦’q€ÏðÛá}€kø“Äfo¬q|¡1@ b™.d«×ã?þ¯Ÿ¼øÅ/E?5•B±[ÝSõ+ HÒ€4°c ˆØv|s‡.M«¢£Kœ3hUô “.[¤ò±•×q•=ˆØfÙè)"¶*'»% HÒÀ4 bÛÃ]œq "¶QüšÑ@Ä6c*êi@¤ ˆØR´´Ã6"¶@6zŠˆm‡Š.I¤:4 b«ã>¬> Û(~Íh b[}"«Ci@Ž¢ÛQîtp"¶@6zŠˆí “.[¤ò±•×q•=ˆØFñkF[•“]ƒ’¤i`±íá.θÛ =EÄ6c*êi@¤ ˆØR´´Ã6"¶QüšÑ@ĶÃGE—$ HÒ@±ÕqV…ˆmž"b[}"«Ci@Ž¢ÛQîtp"¶QüšÑ@ÄvÐÇI—- HÒ@y ˆØÊë¸ÊDl3€lô[•“]ƒ’¤i`±íá.膉ísŸÿª¶bÓ† Dl3¦¢N‘¤i@HÑ€ˆ-EK;lÓ±}õkßxóƒ}ü“Omd£]‹Øvø¨è’¤i@¨C"¶:îÃê£h‹Øà]®Ýwß}"¶ÕgŠ:”¤i@¨B"¶*nÃúƒhˆØÿÈyàÚï}ôIùØÖŸ'êQ¤i  ˆØ^~饗._¾ìï‡?rõ•—ÿôÙW^8Ÿxýúõ³gÏž9sæâÅ‹wïÞµ³ §ÄG($xKÌ•†ˆ ~µoÝy+’"¶3A2¥i@šÐ€ˆíåÛ·oŸšš-[ ÆÊ+SÄVhºJ¬4 HÒ€ˆíÕ9ÀmjLäás§®‚ ºð–ñ¸Ê{Î.ÀP Á{O~ÀA4ÆzéŒÉð†‰ÜüËP¯Ü±åe5J±•›±’, HÒÀÁ5 b+;V¨^0ïDl"¶y3GgIÒ€4 l¢Û&jß¾S›ˆmûY¨HÒ€4 $k@Ä–¬ª}5±‰Øö5£u5Ò€4 ì\"¶ßà¾Ë±‰Ø:õuÙÒ€4 ´©[›÷mñ¨El"¶Å“H¤i@ÖÓ€ˆm=]WÕ“ˆMÄVÕ„Ô`¤i@†5 bëÕ²£1ãòq IÛY†æéà‹ùlÖ8.„ÀX;aÃÙ)b±m8ýÔµ4 HÒÀT ˆØz5V#¨ù²q½);ĆäºHŸkGи“Ø‚TmSïY–ö"6[–‰$!Ò€4 Hëh@ÄÖ­ç xØ‹Ys‡‰Å J—B;‰ ^:4“­0m.St×1[êE¤j@ÄÖ}ÓÁgà-ûÌk˜ØÀy²bC=+|jåä·šsò±•À;ÛVóYýJÒ€4°{ ˆØºo1‹VÙgXÜÖæ_V¨ŠåAY`”k£}«¢"¶´TƒLÛî-¦.P¤­4 b›Ll}$6ˆƒŽk£"¶(jÍ1ˆØ¶2dêW¤Ýk@ÄÖ}‹(jŸÙbèèª(OáÚ¨ˆmMZª¡/Ûî-¦.P¤­4 bëÕ¼ùÌà-Ãû^x £>64ãÚ¨IˆûÐ>¶+ûDl[2õ+ HÒÀî5 bë½Å€* b@i>˜™§Í^„¹€Ï°6Šd}ùØ6'¶w½ë]ž^Ù5ÅîÞjè¥i@Ö×€ˆmHç@1 Œ/¼„/~ÃY®¡1üv–dý»Ž+šÝÁò±m2™Õ©4 HGЀˆíw¹ãEl"¶ƒN}]¶4 Hmj@ÄÖæ}[Vûø'Ÿ´á}ýÐ&b+=o%_¤Ãj@ÄvïÖcAtEÌò¤…¼ó Òs>1y_|VãÜÂ)öÞX`)‰-xùd"…¦fýÄöž÷}¸f>0zÚòºÄ²K±š®+ HÒ€4 b{͈‹̘"¶¡ gK¥”ƒâÒ],?¥~bƒS n6ƒ*xÚp$;cå(b[>3%A¤i S"¶ƒNŒÊ‰í«_ûV™ñÛˆêêg>+b;èdÕeKÒ€4 ¼ü²ˆí ³ ~b øŒ ‡X„¼^±¼Òäc;èã¤Ë–¤i ¼Dlåu\e"¶¼¬Fi ¶|äwª¼á”4 HÒ@Û±µ}ÿf¾~b VE:Z³2ÊüÃÿø'?þã?~åÊ•¿üË¿œ}kt¢4 HÒ€4k@ÄvÐYQ9±!‘øÌïck%òà·~ëñK—.8qâ™gž9èÜÒeKÒ€4 ЀˆmH©, Š—…âÒvø—eâò€@.Ç…ï§b ÜÙ‘•ü^A:ü‰|ýa%DÙ>¶ï}ï{çÏŸ?uêÔ­[·Ö¿¹êQ¤i`±õÞSÖ˜B6$¼eyP¼ðæâÅ‹…Û™SÍ#éBXMIÚ˜¡m«)U?±}îó_ÀÂ(\kð´!\n•‡pk÷ôùçŸôÑGyä¼ÙêF«_i@¤}h@ÄÖ}^§À^ÌyWµó™5רŽbüøü)Y2À͘‹õˆ=ð›ÏÍVÂ=–Efg¬(0ζsçνøâ‹3î”N‘¤i@ [÷4Ÿyö²Z¢ÃÄÆ²–57&6ßë™ÆË¦ëÌË&ˆ- E­)d »Ç7~øá'Ÿ|ò?øÁ:·X½HÒ€4 ìI"¶î» êòĆ?Éa¬=å÷±YAR‡ÃŒëžä°abóÕKןR"¶$7œ ¤O?ý4‚ð[Á¤ëÏyõ( HÒ@Ó±M&¶`›9ÉHl‡¤½b ÖOןC"¶õ‰w>6xÚàoƒ×mýû®¥i@Õ€ˆ­ûÆq}Ó>³8ÐáUQÛ”ÆfÄÂÛֻƋ±mElÔ?ö´agö·a¦5j;4li@¤55 bëÖ67™!P”ã=¿Y‰k£æu³> }ðÁš7Û÷%bÛ–Øx/CŠHRÄ“*˜t«AýJÒ€4ЊDl½wŠ©×à6ã¶c*5nk³Á.à3`’S¡ …fñ¹ëO[ ÄÆûŽœmp¶!²¸­?Ô£4 HÒ@± Ý&$ãŸá·5Âû×ð'‰ÍÞXãøH|º¹ñVž."¶zˆ·5”€z &]ùYPwÒ€4 4¡[·)ÿ Elµî1HQ“TÁ¤ù§»$JÒ€4оDlíßÃYW b«Øx'L:kFë$i@v®ÛÎopß剨ª%6Þ2“ž>}ZÁ¤}DuÙÒ€4 ¼V"¶ƒÎ[åÄÆyùÜsÏ!˜ô±Ç»sçÎAgª.[¤ià ˆØ:DlMgç—¾ô%dܽpá‚‚Iú¸ê²¥i@±vˆØ"6ÎÒk×®!(áSŸú”‚IûØêÂ¥iàÈí w_ÄÖ±a¦"˜Ä*“tâê²¥i@8ªDl½ó"¶‰“k£¨L VK:}uÙÒ€4 O"¶ãÝóW®øÃ>÷¯Ÿ¼øÅ/E?5•B±ëL)“""AÁ¤ëh[½HÒ€4°¹Dl›ß‚mðÎwþÚOþä~êoÔOF @¥PìšwTÁ¤kj[}IÒ€4°¡Dl*Ë®µ*Úîªh¶Mj& HÒÀ ±•Uò Õ æ]@åÄö­;/b1Þ5#ªò)É XÙ¥í†Ø8©L:ïáÒYÒ€4 ”Ѐˆ­„VY9±Õ° ê‰ K¢"¶M&ƒIárS…«Mô¯N¥i@ Dl õ[Àg1Ãe÷-¸3›6°­ ›Û°ÅMÁ¤5ºli@ØZ"¶­ïÀFý·Hl`8¬–.çªrþÓ§ÿó;Þqf¯–¸.„‘‚ÛRº×kÜèqT·Ò€4 Œk@Ä6®£]¶¨ŸØ‚UQ„ŽÖ¿* b{衇xà$6ÛkBZøØpuHÞ†n»|4tQÒ€4 Ô©[÷¥ø¨*'6¸ÁÀg>âFë'6®Š‚i˜Ø 5 öŠ5àQ”IÀþ¶jckŠ?Bê@¤u5 bëÕ7²£1ãòq IÛY†æéà‹ùlÖ8.„À¬ës|¬{ÓïõV?±é<€kÈÊVnA3‹ä`ê¬kàrÃbâ.·í#˜eI¦ªLºþ#¬¥iàh±õÞq@AÍ—%ˆëMÙùà0,ä!}®Aã€Ø˜ž—…Þ‘õ-(„°æä«ŸØ¾þÍoƒÒÀmÈëÜlxÿï~? W•ÒyVÆ}pè ·æ]^§/\”‚I×Qµz‘¤#k@ÄÖ}÷ƒâQ`/fÍ&63 ±q@lÈ—kH·U}*Ž­~bWÚàWc*Ýúq ŽÅ )ÜQØvíÚµýE\*˜ôÈ_$ºvi@XA"¶n%ƒÏÀ[ö À n3«X› ä’+Ä®p;»h‚ØÊ9à INÉîqçÎ .Àå† g;[LôÁ¤[Mlõ+ HÒÀ^5 bë¾³,ZeŸ±¸;‰Íï`cÉ)6cyP¥#­Ø¬ð¨m[z‰ØJ@[ ±ñ^nà”ÂbâéÓ§ñfOÉ2LŠÀ‹/}éKëOlõ( HÒÀ^5 b›Ll¾ê¨?™Ä†#ðÏqmtÀdžf\]¡è»|l%à¬Sf:±ÙMyî¹çàlÛ_B“>öØcàQ“îõËC×% H+k@ÄÖ­p®ZÚg¶}mx›íZãÚhç>6ÛåF'ÜVn6ùØJ`Ü bãÛkBð(‚InX ^Ù´©;i@v¦[ï 5ŸËœa‰ÄƵQ“`}`ãš­¢²|l%Èi+™³‰Ífˆ%ùÔ§>µ›„ XE¼vïíæŠvö5 Ë‘¤&4 bë½MXýQ±@i>˜€ÙÔü‹ÔðÖF‘ì#ÎÇÆLlnbן+ò±• ºåÄÆ™²±í,!"d±¹ ×µ¿8ÙõŸ_õ( HÔ€ˆmè¦Å€VÞ †÷€°àE1œÅGØ;{Às[y×8[ÍÄf“’ A:ûH‚ üm¨ q@k«K–¤i`‰DlK´×ð¹"¶&ˆ3 »ø-!v†5<í^:<ˆ &mý&jüÒ€4°¾Dlë뼊El g ‚ úr A,˜t ZÅ#­AHÒÀÞ5 bÛûî¹>[sÄfwÒ‚ÀñîizãZ &mýBš¾ ¼4 4¡[·)ÿ Elígöïs/?6ºa»[þ)²¢D“âB°Tª`Òµ®®¤i 1 ˆØ»a¹†+bkØl&XBÔ›ošxŽ€ „&ì©D®Vr¤i@±tˆØvClœÁ`µ+W®´žŽCccúdê²¥i@èÑ€ˆí SCĶ3b³yl Aà²j4óè[ôàoSeÒƒš']¶4 ti@ÄvÐy!bÛ+±qBc#?¶…Á冢¥c¢°"PäªÑñԲ貥i ˜DlÅT[·àw¿û׿M'N½å­úɨ¨Š­çÎ[BS§N!3H‹ûÃnZÁ¤õÌ(D6Ô€ˆmCåoÙõ‡>ôáßøà‡ÿàò§õ“QP)»å}íéûù矇³ .7¬6¶X”Ý‚I]ç­pJhHÒ€4МDlÍݲ<Öªè¾WE;g ‚`X£ A°3A °hÑY˜ç¹•i@8°Dl½ù"¶›Íõv‚:‘Ä܆EÞƒ>ººli@8ªDl½ó"¶#'}» A0r,òbsÐó °.»¼^zåU¾ŸÉ=\½zõìÙ³“O›{ /¼pæ•WÜ)Žð#´™+^çMЀˆm‚²öÔTÄ&b³ùl A°àØÐF1lÎÃò.‚IñfOϦ®¥ ANžŠ{¡ÇNÄVϬ±ÿ;±g²“Øìÿ'ÿÀÛÿX£Ä¶þ„±‰Ø&Í:ü·½bØå†½nõï³`ÒÄ%§IªPã]j€î¨©ÄFƒ…*ËŽ$! $Hñ=ÞŒ®´z Çî:/™^1ÿ¿Éç7W{½@’þ8ýj<5"¶z&¼ˆmœØè"¶ÿŠ:‰~²à¾r÷ŠØJàQ…2ÿËÕÿ®çñÎ>&A:4Ð[ý™5C × âILš}&ìOàñMe4Ð(±ñ_.ÿZa~ˆØDl˧‚Àåzî¹ç– ,'q¯'F«`ÒrJnZòüˆÄÆ³ì•ø /™õÛÇ?ù@ 6pÕÕÏ|öÞ&ŒÏ|6;cåxpbã„´„ §OŸ®–аž‹à ìoS0é3¢s [=wYÄöê½`ÊD"—7‧À¦ÛpXàͦ’ÿ òÿ ±|oM—BDl19×®üñÓvþ¶·~{^ÀÊ.MÄæMv¶UžDÁ¤õ|i$Õj€ÄÆÕÒ`\?­¶œWµ*=0ÛlÕ%¸B.ܤqD*÷±}ý›ß† ƒ?t¹eg¬¼Elñl´„ =öX ALŠ•\“Î3&û>‹Ë }¯\×>ÐÅp$i® ÈñšÙ°7ä z¨¡ [ waƒ1TNl`5¸Íˆ GDlL”|]~éK_Bj4lüÇöÿ Ù1Û§>õ)“æ»ç’$ H95 b˩͆dÕOlŸ‘á¼×-¯{,‹4ùØFš‚ €Ć “Ž^ˆHÒ€4°²Dl++¼–îš 6ŸÔ£ ÛþÇ?yã߈ïûj#%+™ABªÜZðÿ!˜þ68+Q—†! HÒ4 b;è4¨ŸØ¢šXýõ_”É#äye,YŽÔ6Ý™xT[Bø±ñá® &­mÎh<ÒÀa5 bºõÈ4ˆ •>¿Þõ lÇ%ÞqÃŦ¶ÝªY9±a|æÓy4+ W òì#XòþûïÇ?²íW^`C#è‚@iŽ$è· •InršÖsS4ià°±õÞzf£fB_C—Itíeù;|²i E›>,c~Ý §]ýÄFDûÎw¿zã’(ÂE³ì6+'¤o¾ø±ÝÜzÃ×?6¹Ã…³áݯ¶k( ŽI¸'¸õ¨Ë£pš*˜´Úi£IÑ€ˆ­÷Fƒ¨È[ÌËÂ#AB]2ãœ}†¶>bcRÛ(9Øjüýž÷}`´ýæ F#àLÂ×?×X?ÅŸª˜<„–±¥õ$Q0éA¾u™Ò@µ±ußš x”Ú0±Ñsf‹¡}ÄÆZo"¶ÀÂÂ(\k_üòWRoÞf”ØülÃBbàr{Ýë^4 ]«µ› ¸VUB &½m¢u* HGÖ€ˆ­ûî•@Y“€>6¬ú­lÆgôɱp…väpUĶ9`eÀ$bó3h‚u@äqµx… 3–me(™„š©a/ n ¼¤p‘*˜t«)¡~¥cj@Ä6™Ø‚}lV<ÔVQ½C.ØÇךñœˆ-;0m.p6±Ù,´x Nñ þùDPö•àâÚ<.RøG—PDóÛKW- M"¶î;ŽõMC+´`‘xºÍ‚Z¢v¾W<á{‹}l8Âêl\uÝ0\´þȃÍñkÆ–›ŸŽX$e¼–M¯`š©*!vÜ Üzâ$Žö¦ë•Ž£[÷½Ž÷±á‰„Ç`Ò€ÉXjA¦È7†÷Ã@ÊMDÛ =%/±ÙÝÇö)‹W`ê2Å+ A¶ÞÀíÀ}A‰Ö²Ë™,I–¤[ï€ þ0|LzK‰õ|“ xÑ´*: @Í5(Dl~ŽÂ—ƒ5AÆ+`INñ L`Ú!ȆðüØ€ &ÝëW¦®KØP"¶åo¸Õ¬è´Ðªè2ë;web³^A9,æže¼B=iÌŠNãX8.H0¼[ñ«‚IW¾éêN8ˆDl¹ÑáeŠØöDlþî2^i̯p̲ô–®Ç­b9LzP۪˖Ši@ÄVLµu ±í•ØlÞ1^eé-^aó¤+?p=n›„Á¤G“®|ëÕ4°? ˆØöwO“®HĶ{bóóÀâX–N¸­B¼à î.À®亦!@0)Q½Aä5u«¾¤k@Ķã›;ti"6[çüÀ‚0Ââ ™}ï¾Âõbuxý„ ˆê," 2ÞÔ é²¥i`ŠDlS´µ£¶"6ÛètF¼ï@3ŒW@nØÇ+ø„ ðUN®è Î6“æÒ§äH;Ö€ˆmÇ7wèÒÞñŽw ˆ–^Ù5ÅîrJÕ@l¯€-ü{MWŸ"ü^ØØ‡k\͹¨`ÒBO ÜdÆ%p üâ/ž*4I+bkèfåª|lò±Í›OŒW@š ,#Z¼Âþ‚-!Ö…×IbÁ¤ØD¸?}ΛlËÏ¿?ö‰»d®¬`âòùк© õ;8sü"¶æf«*U3'ÁâÓâx…mÉ9a]xÍ„ bn"\9bñ\¨T€ˆ­„¡ÛD¦ˆ Ϙˆ­RCSzX"¶FçhÄæg)ã°% Y3ö¯°rB¬8cg”¹æŽºÒ6gù"¶†n™"6Û&6¤ŠNEl%ŒÎ‘‰Í¦5RWX¼ËÒï&^aå„ pXbGâIwæ¹\ÓŠØJºMdŠØDlkšŽºú±•0:"¶`–³,=âX–~7ñ Lo"®„ZôÙF__¸-KwTô*¶.b+aè6‘)b±meF¶ïWÄVÂèˆØúf6ËÒ[¼ÞàÏÖ÷סàA·ÞJçÂ…Û¡ènµðÕíTŽˆØJºMdŠØDl¯š„Û·oÆÁ޼ðÊËúÒ+/ N¼{÷îÕ«W/_¾ì>;…'ú#¼‚Æ9 W(CÄVÂèˆØRæ*âàlƒËõà¦j}ÕQ¸Ò A¸,Ò `Ò”iÆ6"¶†n™"6Û«ÔuòäIoÀOväÌ™3x³2¼ˆkþÄ‹/âϳgÏò N4žÃ{žb/;‚6˜ˆøÓ¿€}é&i^K[ £#b›:áš‚ßÈâàIjwíÏ')Ç  &4ÇDl% Ý&2El"¶Tb‡  ”æ]nO<ñ„Ǿb xq’=šÝXÄVÂèˆØfOHÆ+°@;ã “dB\vïáM¡•_“¢‹Fµ4{žL=QÄVÂÐm"SÄ&bK"6úÌÌïÕécCƒëׯÖÄÎö±‰Ø6yþKt*b›ú…ÚÙžñ “´x…urØf¼ ±„ HzR¨>º€–°¾Ü¢~òj»Ošˆ­„¡ÛD¦ˆMÄ–Dl@´›7oÚÚhLlX3 VNi>àf£sn”Ø‚}l+Ø2ùØJ[Þ©kñ Ø"†ý[-Æ+`ÛÎ0xlt+”1ДÓî‚rÞi㥉ØJºMdŠØDl©Äæñ+&¶`C›_?«[¼-ˆu(aÎDl%ŒŽˆ­Ä\¥L¸©,^«ÍÅ+XB0D ´‚rÀ…®`R[ ã¶¹L›ˆm±!~“«œ}«¢1fÁÁ7Û(±iUts[k"¶rÄæ%c5ñ ÷ß?¶s5¯VTJ—$„Ã߯Þ:7¢þ^äcËeÜ6—#b±Ý38ñš&6óv pmÇŠÎ,¶§ãEÂã¾`œBt³—±õÙ‚¯óÛäüÛN¿¿¿uçÅÍMÆèDl+…³,½Å+`ÇXé¼h¹. Aàƒo,¯W P=@2VKs¶]9"¶Q«ÕJ›ˆíUC~2¢Àù?ƒ-hŒ‰ d†ùÄè„   3}°¢žEu1°”CúVTK›ÈúWE¿øå¯¼ùÁ‡ÀjÿäS€6¼¯ÚDl¥çí€|Ä+À· bš7¼¯?>–z±ÿŒ•XóÖò‚dD$(˜TÄÖ ŽSÄ&b{ÕþcAtEÌò¤…½ó ÒsÖ™ @Æäm|ñ=X}àûo,°”ļ|2‘B_õÛ{Þ÷àš=Æô´>ÕÛ6±š®“Äbqeé-^­¼~¬IãmÌ„  «ì AL*bÛÖ$fì]Ä&b mi\ü`ÔÚÆ lC.HÆ|2ÞÂsR?±Á©7›=ðð´áHÆç¿„([®ù™Kã°× ;ޯו•kœ”c Aàx˘äÈÁ¤"¶†n™"6[^{Û’´Ê‰í«_ûžOü6Ópõ3Ÿ±µ4Ãê+ãÀm¯‘Š2^.Ü üÌ›2átÁJê›QE‰Ø6¡«ŠØDl-Cc¢ê'¶€ÏÈpˆE(a rÉ”­‰ÇÀâ@E€˜jã²'Á…ƒ`îÐÄZ>H[.ã¶¹›ˆm¹AhU‚ˆ­„±5÷< :ñ ø>¨3^!{BĪ+PõÁ¤"¶†n™"6[sß/Ù\?±«¢ ÝÄR¤wúÿù÷ðC?ôCˆUDí ì·ö¼c;ã¡Ö¡²ÍÑÕY¼ƒ7k‹W°„ @Ìå@U“b¢Ö¼±où±¥›¯Ê[ŠØDlË B«*'6$òŸù}l E€Ï@iø~Å·¸õ1…q =*,Koñ ØýVÖ`ï–qs%ÁDÅÆ> [[ú–Ï[å–><›ˆmÄ ‚=­°úøï-ãå¢1²} ßG|îrÃ4UBåĆÇ8Hç?‘ï#ýñÞ¤åÀª¨0nê­¤=X ¦ŒWÙ`X pc APøp¹Ð‰‹åQln–(Ÿµí}±mb Kt*b± “‹/"§ Í º£5Ž0C[L]Ì©æ ãt!8h¯ò®õ]aýÄö¹Ï(\kð´!\n•‡ÀHMÝÇÖ‰q ¸å°*‡/|•ÿlûýwäÞ±‰Û`¯€?¢Òr}"o0K>`` 3c±uÁ¤"¶ð´‰L›ˆ­×`²t•á—U,J øóIl¾U'±¡M )Ùê'6fôÀl>7Û&ö"¥Ó©ÄÖ9ÿ@ 48NðeÃF0U¸åp“QãpwX_aó²ôLÞZ˜dÁ¤"¶ÃÕD›ˆ­×†³€}l•†‰Õ¨¬ÎALlÈ ‹p¼ÁEWŽÏø2*ª bkÂŽøAf!6aÜèì­ªâX–Þâ6\[´„ Òìa0˜WÔJ‘Öù bkΊö XÄ&bë}ÒATžØl¿Z¼*j»Üˆb¬Jç\Ll,?ŠãXr r+ ‰ØJ²rÄ–Žqà¸åð‹ï*|ãÖ³e~å¾~w¯€[ÜÙ0^#ÛÃ@ðÄlêÂz+6#<–(Ýj—’ˆ­„ÑY™Ø:§/¾­1©°F†ï*|ãbË<,0.$Êå0^˦Æ+,O‚¹úùÕo‘¨|ßLÄVÂÐm"SÄ&bëµ8ð>6+„¯Š2΀{à°6Ú¹Íw9 m†mštŠˆ­„ѩ؄q“„Òš`ñ Y€ïsýx…å A@~,±<\i…òEl% Ý&2El"¶^ëÁ gö1ƒF‰ ͸6C}mx´¡Øõ_"¶F§ZbKÇ8PÂðÝŒ¯:øWš^[ÿ±î‘eé¯%¯¯` AÀ^3‚àt[`z`Ø›GȦßY[ C·‰L›ˆmèÁoqq“øÅ¦Ü‚_šñ#îc3‰XÅ ²{04+¡Ì’nzò¶±•0:m[çŒU`~â»_u  ¬ˆa ãò>}%[¼ÖP³¦Ž ®³‚Àdžac>`ÀSûݤ½ˆ­„¡ÛD¦ˆMÄ6dC°¸ ê`á·Åu‚á|B5¾ç§¾þÄéö‘ï†ë­»aš[ £³bÆ­ 5¬9¡¯0;V`ÒÈ-!¸˜t.ÆŒ7L*b+aè6‘)b±M2S»j,b+atöJlé‡7°kgp#-Ì麫G.áb¯€xÆ+ÀÓ¹‚q›àä/â®M /h"˜TÄVÂÐm"SÄ&bK0¢;m"b+atElOìÀ×?Ð ;+Œ›jE¯€Ý„PÅ+ÝõÏ„ èkjB“Âå¶Úªî$eŠØJºMdŠØDl“žý]5±•0:"6a\v3añ ¨{t!¥ã,!:JgDlkíÓÓOÉ®¨N"¶†n™"6Û:F£Æ^Dl%ŒŽˆ-}®wzãà­gß²X„ófÒ"]z×í¶D>dÆ+€ÞŠÆ+@óèˆU“0Ã/H/î]=Á¤"¶†n™"6[»¦{éÈEl%ŒŽˆmá¼ÄÖ(€¾e± tÃ×?Ì´0.Ö*\Y¯ÀLi%â|Bä%Iá0 Œ‹¹S£Μ¾ÓçÛW¿öö¡Oæ·î¼øõo~{Í[ìKÄ&b+d%+b+a³Dl%¦¾0nX«,KÏxü.¯€.û.7üN †€‹.@ öV5]Lc“ˆísŸÿÂÛN¿ýÍ>8Ào¼ÿâ—¿b†â=ïûú4¸ú™ÏZƒàSüùøG΃ÆLÍÇ?ùÏbèÂÚÇÒìH”<ô‚68ø{}28Ž.ðÃֻI®ÈŸKÍÄdÙ9N\¸Ë‘zC×S-°ˆMÄVâû¥ ™"¶©ö"¥½ˆmµÙ߉qØædÁ—4B`…:÷—S|`ð´Y¼4áèʸ±Ì‚@Ï).4Ü#8JqG6ÌÜNl@%2?`5"š1 ‘¨a?h Œ0ø rÙ§ %bJŸÿ ´ÇÓÙ#þ$&N™¨@òw¾û}3GWþøiöâÙŸB „ãå¡Ç!ßw\ÆSÛ<þøãÿúÉ‹xlô“QP)»ÏÓìU ã € ¸ñ p@f é°„ H7º‹n«`Ò©ÄæÝWô-y›y§Œrˆ&}Ćãð5:Ýl² Æ0@lKº"ù^ÈIôÛùµÑQbcweš¼ÁyÈ‹9Ÿû8žNbÃqº0Óÿ%±‰ØšýZ<ðw¿û×ò'ßðSo|£~2j*…bß (®NŒƒ[ðïxàU3®'¿ž´¯$B:,^!%ž`X{+b±­`1*íBÄ–Îaé-El•N÷Ã:Æ1^»Í˜€mI¼BbBàÜ™X¨-L:‰ØìIçöy™íµ¢ç‰ÄàLÀ.ñÆ,.\ŽnØ‚:Ìð{ø:‰®/0Ÿ.ø=pž‡7@¶K!6¿^I×£-ÀŸÞ™Ç%TFð‚Õ>2ãzqz"›ˆm!oüT[:‡¥·±5þX¤?Æ8dÖ€7»Ä€ 4X¾Ú˜:š|í°¦iñ ,K?;^!%!„Ó…™’1dÞU¦[ç2¿ìع*:º£‹N©N.‰2R!Þ-×Ilq¶nÀI¶6šBlAzƒ»ð`lä0¿×­Ø§à¨™±‰Øæ=œ%b53ˆØöðl̺ð( ¬D·DÀpMcËÒ3^P5/^Á' vªË£ØT‡Ýu%²±¤[à:âãï×ç›g>oRè{‹ÃB;{éÜ+†ƒAi‰.º˜“¼w0¾:j&™.4?rJö9Mb¥ØbÉÃ&WÄ&b›e›wq’ˆmž"bÛÅÑí"öq .@•Å+à þœêA„; ë­Xu…ß®3RDˆÍm¬¼éÄF´ò×àñêÛÖi b®"Bõ-‰r™5ðìÇXrg¢ ŒÊN9‰k£Œuè#6  Ä»ÖxÜ·é£I륓ؘʮ3ÂCûØ Ð}ÙŒ“5¥Û(~Íh bkê!Øf°?Ür`x¨ôî®ÙWŽåK \n¬¯0µ,½%Á¹qBh—Ê6Ìapb:±D,æ€P‚[»Lñ±q]ÒÎ7uÎ*vaÞ¯Î%QrX€}}*séur×F=±ñO?f4Ðç dî_òV犭GUŽ$ègÅþEùØF§½ˆmTEûl b›d£§ˆØöù´”¿*8–@iX7a€‡@oø’«ã€\,KÏx >}Yçö%ŒÁ¤“ˆ 80û«U¯9GƒàË!à=§¤®@3€zÄï>ˆ4ó/8b## á7ÛÄ©Ý80s¡cœ^¾q|±ôGö„’Ñ€#ñ?SY]kUT«¢å-q­=4DléÁD£DUºˆ­ÖùÞä¸ZÁ8Æ+pÑ“ñ ‰>B&!ð!L:;ô·|*±•6’?["6[“v<Ë [!¶©9{f›ƒ,'ŠØ²LN Ð@'Æzà–Ã3 ÜW )g‰þ¯ÀÀ Æ+¤Äøâ€õP´÷ûØp!89³‹4ˆØ²X¶„ˆØDlKLSÛç¶Bl°ò±µ=Õ4úò€— n-à« |½m‹qØ”ÆxpB R☄=çAb©´oÕu BÄVleƒˆMÄVÞ”ÖÚCCÄ–åi_Gˆ|lµÎ÷#Ž«Œƒ‡Ìâ@“Ãñ AB£1„#þ@`ŸáOï+Ø b[Çô­Ð‹ˆMÄvD;Îk±•01"¶ã>Q\y'ÆÁƒ…uL8±À7ðÕ-,W5¬ ,t2^eéâ˜c³„ €9ŒGÀì ÞûÞ÷2J£såTÄVÂÐm"SÄ&bkÄʦˆ­„ѱ˜ªY\`€œXà p ߎ¥1Žeé-^¼çûÀ•û„ ,EŠ#\líýÈü†ÊC›ˆ­„¡ÛD¦ˆMÄVÜVÛˆ­„ѱU;á5°©XãàÕ/bãð>ŽWÏá#`UmhðþÁ?0\ã`\€WÄVÂÐm"SÄ&b›jÄöÓ^ÄVÂèˆØöó„èJº4Љqà$xæ°v –‚¯.%8´O»ŒW€¿Í₲ô–+ª¯ýëbßpzh›AlÈIÆ”l}™Æ`:Ò¬³’ÁÀ)A 2·A&’À!+[J"7¤4CK–`÷U˜ ­óÇr³ÅŸBš¥ŽC–µ¾" S©u&{ .ÁX¨´sHÃùí-b±×*‹ØDlÇýºò¬¢Ô€k€6 `‹î®…Çxö¨1^Ág-ùýßÿý×x¾:‹N˜Dl@–+°ý0ŠmË=Å™`; ðôI¾øßûzY~¬ûé‹+`$@LkÃOã º -X…^N_e*öË6qÒ%VÍ J>X¬µ)¨X:l“El"¶¬v«)a"6[SVƒmLy1Žñ ,KÏx…·¼å-}ÄFh£¾&AÍ*`9¦À焃,ßiåž<-õ9¨ˆ¼Eb1õNÅÊQ¾˜p ƒ4OÛ@G}ìÈ ªÖ#¯.èþ0kkRy‡Y °¯ ê$#,b±5f3WÄ6ÉX$6ÖªhÆ)*QûÓ@'ÆaÞ8 ¶¯ÁW7œ,—ñ gÏžÀ5~„˜†IÄF" VñàžWtú¢æùØâ³ ãé,oŠñ˜Ão±q-J£W ó¢ÇÊ€Ø: —`žB[®gYuEsi²19"¶D›ÔLÄÖØc áV „Ô@lؾtCl·£ `ZŽ0_ÉÅ}"å)-ôN!~q0&•yÄÆ®ƒšž}c¦m 4絈­±Ç@íUÃCÜè(´ý¿ówþÑ?úG‰ÄÐIÙVåýO1ˆÌ#6@NäN/V .!¼cc†G®8 ‰wúû¥Û p-Ø xƒ%`OltÎuº­G**R"¤RŽVEµ*Z«¹*?.ÛTKi/b+?sÕÃq5à1ÚF‰ uº~û·;Øüþý¾çÝûÕè‹òû·æûbø§¡[ß~86¶€V¶÷ÛθÁß‚'øÆÃ(ØN÷‹ª640p .3 ¶x 5Щ.þT¬èÔ‡Y>¶©ÛI{[ Mm#bÛÉã¡Ëxùå«W¯ž9sæ…^ 2øçåË—cÝt¶DcÿÂγëׯçòľ»~饗p.Úܽ{ןþË¿üËÃÄöÃ?üÃüà?ô¡%[ʪ(÷®yòàŸÞ}5#ò °3ðWÑéÕ.êÛªÈC†›“VEqzoAùFiŒ´ðzb£N†«?kU4—E±åÒdcrDlSi,¥½ˆ­±Ç@Ãí×à ßÄ·oßfþyòäIc8;µ³eÀa8§ƒ½|‡Êä‰"¶\–FÄ–K“ɱM¥±”ö"¶Æ w"±1­F°6Úéc ˆýÀO¿—­o'ß žK±À> %­†FQ>!=V8×"ñ›k|L±Aj!Öø­]fèœã–/¼× §û[dìûˆ½Ø§Öogü½zèÍØK°„Ú94³n,H÷aà½#ÆÛÔb#Õ¡%k'àO.ÔÚî:[ þ™bWÙõ¼J"¶tK‘ÞRÄvÐÇi—ÝÇa$'¿6šNlظvÏŸtõ*6‰ØÀjè—[ë~ú§z˜Õð)âIÑÅ$b3oNçÆ|pŒALßF7ò T¶ß¿1b‹? °ôÛ+0ÀƘßñÖ9OiÄÆÅÍ`}–ïÌcp«ç-(̇ŽÊŸeÐÀ¨™±a>‹Øöhk®IÄ6j f4±%L=5iC}`"9õ-np¨ ß»XâœAlFx请¾õ­І\n,T5•ØøÔƒ?€#Ã)6f؇ÑSØïh36Àð6äðð¦zÎ/V>6>2"¶6¬göQ¶Bl};mÓŸó5[ŠØ²OT ÜJž3~d;ÒÒ}l$6£=‹f „ùW£`JÀ¹d>dúè#6„|ï{ßã)óˆmM£¡¾5 ›ˆm+c¸}¿"¶D31©™ˆmû™­dÒÀ0‡‘œP«À\_ÑT'±üÐWð²•S5 Ø=øàƒýèG_ÿú×wBG%b›d»êo,b±e²m Ši…Øê·#~„"¶ ¹[ÃÄæ×F§úØúœsÃwѦ`µ‡zIqñåbVÃýÐЧš—#[[&t`´"6Ûqµˆ­„!±÷‰ÚÝ•r˜­Ž¶4Ý0ÆÓRéNŠ<`˜êßû{!¿ó;¿ƒ÷?û³?ûŽw¼Ã¶¯÷AÄVÂÐm"SÄ&bÛ•M¾ [ £#bKž€jX»R8Œk£d©ÑUQ:Éð²+O'¶ñ/þº@¶_|§_¹råÇ~ìÇpä+_ùÊÞð ÞûíkZ-aß¶•)b±Õn4ËOÄVÂúˆØÊÍXI^Y)ÄÆµQz¹†‰ -‰w>—[ ±!Âu pâ[ÞòhàÎ;§OŸ¾téXA 2ÀA”}î¹çbÉÇVÂÐm"SÄ&b[ÙVÔˆ­„ѱU4Å5”eH!6ôÀf1±ùÚSFu–׃C®RõøãŸ?þ~áXo Ì×Ú©S§ŒÌ¸ÆJ™ô½%¶Î¼¸ÞŒ Emg’Ø --²r Ó,R $òhw›2/9h ¦sÀ:piÕ˜#7è‘IIüO\Gk¹½±‰Ø–™´–ϱ-· ±[ËÏ„Æþ tÖw‹ŠâVjjÆÕBgñ¹}•àáEÃ~µÿñæ™g€eõGôGt­1Ëš½Øug}¶Éåcc–ÿŠóÜ2Ñüòœ,Í¬å’ Ê½ƒ‡‚68݌ÈóÐúÌ·AA¦´ FÎô¶ñEY3_瀕àýOh# FÅ?ƒÒ[ M®ˆMÄv\-b[h>:O±÷‰Ò•çЀìé§ŸF(Üig×®]ó®µIýä%6 ˆy’ðžœÌçÔW‹ÉNl`5: ÎLˉB¬oã{ hŒVˆ<­$TLlAu,Vµ"NùËáA;Bá8Bá6H &i60®Á<š^9Ëí­ˆMÄ6éÙßUcÛr "Û® ]ÌÖ¸qãb  úƒü€cÁµG}ôÂ… k-}¤y‰-XÇde§ zæ€a‰É†¬ü¼/Qjr|/Ć–¾úgLlq™©¸ U§äàmH¬ReÞY¿‹íÒ–Û[›ˆ-ýÁß[KÛr "bÛÛS¡ëÙHÈy /Ú¹sçüv4,‰ànݺµdPE‰ €ŒES@Ú€aárç@ñ+A^Žyér[ÌX}Þ»¾û ï$6¸ Í“—ÅØŠØDlKLAÛçŠØ²‘@ˆVEÛ~*4úÕ5€PPxÑG o¬sºÖv`ζÙã*Ml\‘$Qõ­Šb­“†‚5㹤ˆÆÇŸBTìóF†\å×.àOõ±q¡3ð~u³ÓTú '±ùÈàšwûe1¶"6Ûl;Ðü‰"¶,FDÄÖü“  ØHÀ20\k-‹kÍ®©4±yÐ!9ÅaÂà`î2Ò 9õùÏbbë‹$`˘ØÈˆüa¿~ZçY<Øé<‹Û3ò ní屉Ø6²Ut+b±U0 5„#jž3D}"¼pæ¯Çs¹ÖV#6Rš÷±¥øº€5æî⦱I>6zõ‚SbbC/hc?!œS}ltÔñ½Þ5üäÅ5ô"b±Ñ\òšElé†5½¥VEûDéÊ4Ð Êóài[¾k-Bi[ú>6¬‚™l…Ô¬Š÷cõícC/>‡_N%2z]í4h÷±YÄkºåLi)b±%ؘ6±¥Øˆ©mDl;}\tY4‡‚R(\kX…w 뤺y­ˆ¢ÄF4IŒís¡yb#ÿTç{éäª FFbë‹冼XQd`aýwª h/b±e·Í±e4%&JÄÖÌ ®¨ÎPPïZ –G3­±Yls}mÀ°p#¿ßòÏýû¶¬IBššüdYm3®…«Ÿž½páÜ«gdÙ¹ÝYß,±Ür{+b±e´ ‰±-· ±[c†[X ú§ú§¨^€¨s°‚kÍ.+/±YTƒ‚Íõ}‘>Ü’×|tBàˆo%†9€üÚh^b#´Yˆ+p>GI'±e_±‰Ø ›«ŠÅ‹ØDlOO ­y øPP”þÄ×-ëV¡B(^ÿý¿ÿwìZ+çZËNlŒÁô?qZµ¾º¢q0P_N#3 Ä>ª@šÙ1÷iÛüñxó\ßV¶«ˆ‘`

—íè“#Ûì ©w£ ôæÍ›ø®µðßøÆ7î¿ÿþ7¼á %v­Å:Ìåc+m:$T"6ÛnŒää i…ØRr>ê«5±Mžˆ:aGè ÅJ(œj¼Êçž{ ØÞùÎwâÛ·³¨|veˆØV³~¥;±‰Ø²Û‡f¶Bl\Œ(m rɱ5óh ¹5Ð \Ãb(`9ØNŸ>}çÎÛ·oßKHñ7´åÈk䉨r·ÍåˆØDlEmEÕÂ"¶Í-EúDlUOz ®ŒBAïÞ½ bC)w¸Ö®\¹ÂþyðòåËe†#b»W®`?"6Û £Ò.Dl%,šˆ­Òé®a•Ñ@gUPßv­á‹ö§ú§áZóÇéx+3(Ûq æZÄ&b[ÁbTÚ…ˆMÄVéÔÔ°ZÐ@_UP?vðÜÏýÜÏá‹6v§‰ØJØŸ}˱‰ØZ0eÆ(b+aÝäc+3[%µ" ôU †ˆ5PìZûó?ÿó>b³èѢצ}l% Ý&2El"¶¢¶¢já"¶FGÄVõ¤×à–i` *¨ŒP°â ÐÇáN àŒ‘-îcC62+-à Z%äúÛ 3™/ŽŽ6Vâ‰rÝ GXo ¿‘V7H¢æ»°®ýxØEüÓ9`“€,k,Å~}=´•‰öEß;G»ÐäŠØDlË XËg‹ØšÎÓEl-?ûúBAcׂ ÅÃŽÇ  ×¯_Ç·/~¯ ñ¼>6¤õ Ìà UšbÅ‚¸’ZØ{P$€EpYsq.ʇÉû.¬_?&BšDl¬@eýÝð§É•ÉZ þžÛ9Ú…&WÄ&b[ÁbTÚ…ˆm¡ù±U:³5¬Üp­ÙGp°Ú|ö5Ÿ¡-÷`Cy[[PR3È+鉭³Ú:lô·uBá±¥çBb±öÀÕ‡Ó=´¦Ã$±áeÀ*b+:¥ï+*]«ՀˆMÄVíäÔÀ*ÑÀh(¨»Öך}Ä\ˆ ùa=”«ÖYÅ6!6stΪN=[±9b}w[¦Lô±¥[g1P ƒŽ7VÇJ!6 Œ—à UÉÇVè±RlíbEl"¶Úç¨Æ·RBA9:´|ä‘Gl×Zçj 6:c@o( ¿Ú•mElä-[ð±‘x:Í‘‡ªìÄ6U6òDb£GÐ¯ŠØ Íp[!ÅÖ.VÄ&b«}Žj|[h 1”CC)wt‡ó,e¤Xº¥´ÌØf+bƒyáŠa§³jÅhüÂh"±ÅûØ:q(wÚ0)öíc3™¶‘—é×FElç°%b+¤ØÚÅŠØDlµÏQo] $†‚škíÑG=þ<oÝaNëmCb#rÑó4ìc 6™išAlðê1|Á~‚ðO çxH“ñO0ì™>ô\±M›¦É­ElɪÚWC›ˆm_3ZW³H‰¡ ÞµvëÖ­E]®rò¶Äfk£û^õˆIB±šÝ"¶BŠ­]¬ˆMÄVûÕøVÑ@b(h[®5Ó\^bcDwzëÁ`Ose;º¸6ŠOû²{‘ØF7U ¶s»›?wtÏY`ñú"C:)òÀ$sm”ζ>Çálëì˜Õ"¶UŒb}ˆØfŽ•­¾™®õj©n{ì1Ä &4EMôÃ5áZ+Dl¤¨€EÈd)“7ûˆ-Èî`"œÙ=g>­.Þãˆ%ÈJl$³ oc1£2ãuØ™ïc¹½±‰ØRÌÔ>ۈؖ[X‚ˆmŸOËî® ž.\~}éK_J¹8lVÖµsçÎU¾k-¾–¼>6<ò ' 8‰Åø§ßÝ×Fûˆ 2}]€ጞ932Â(NvM¤3R$]Å{ÎÐ2(Ÿ`2™Èƒõ à£oÌ×0•Ù™R˜9„åcKy²¦¶‘mªÆvÒ^Ä&bÛÉTÖeLÑ sâĉk×®%ž§Øa¡‰í«j–ØX¤%òMqW Â),£«¾*U”I,E+¡¬demðÞ¯ÏöU”òýÆF b³k 0kTfgÙ.ÈD§K¬®|lò±Ue[VŒˆm‰íè;W>¶U'±:›¨§Ÿ~ìˆaÅÏÑ]kˆ …On´q J[ ÓÑ)@–{V|öŽDl"¶:Ì£j…ØX5%=‘wv31I ˆm¹«>¦k«Ÿð«=ùä“éìÕ´kÍ4Ô4±M2>»o,b±M·|{9£bÃŒ}µ)Û^žý\BAOŸ>ƒ_|1ñªvàZ±Õf—GÄ&bK´`;lÖ ±-Î×” bÛá£Òì%Y(èsÏ=—~hŒ ¡îZ‹/S>¶5 `ѾDl"¶t;¶·–"¶ÆEĶ·ç¤Íë™ Ê«Äæ6”…C.ÝW¿zDl% Ý&2El"¶ú N©ŠØJ[©ù*¹i˜ JÁt­]¹r%­ŸfZ‰ØJºMdŠØDlÍØì±•0:"¶ìUÓ5054p­a5½¯VZŠØJºMdŠØDl­˜ü㱕0:"¶ü3U40#tß®5ÓY bC8¢×ƒŸ>{‚f–†Í·Áñ Ú>¥äX"ͿŢp$ ŽôeÍ힌Ͼb!¸–Î+ÊhfEl"¶[¸Ó&"¶Œ¦ÄD‰Øvú¸Ô{Y3BAíb¸km—®µ¢ÄƲT–ÉÖ§½ ¬ ‹>á'¶6<pU\B€Gì‡% <·±À@üJ)9ÀŠXã÷Ãfa˵ë¹ÍçõµªYÙ ¬ˆMÄV¯!.=2[vƒ"¶ÒóVòMóBAy:Ϋío×Z<=JøØb®b5 EPÿ¥ X!N„Ë:T¾¼ H ™2={±œ€ÕýÄ)ü3v³úØ‚z¦Œ!õqK¼ÛU°ì)M(ÇL€cúÌ Vi.K+b±×þ‹ØrÙ/GÄvÜ'jÅ+Ÿ j¨!È`RÊ/.sWë`%ð0_<ߘ¹`…+P]vÐ!)F(54ŒË˜&Z6VÁòDáºü¥a ø“Pˆ7Ñ©‰c˜ÔLÄ&bËl'b›d,‹ØzZêìPPïZÃbhb•ªUŒyebó>3"à?xƒ?½¡C‹5=Íæ‰K–ǯHŽ[[^`°+n@”¹ á™ëÜ–gbºK´¢}ÍDl"¶X¤™— b[h>:O±ÍœŽ:-AóBAéZ³«.GlÁB$W0=–]ÌÛ„7±û |,MzbE1š ¾UQ3Pð¥¥'%_«ºÞ#ˆÈ—hÆuXoYœ† †‘n¶á±‰ØÌäN›ˆØfŽEl;}\6¾¬Ù¡ ‡u­•&¶`§?—8ýú&I •¸éƒCmÓ>²µQOl”iÖ†Hd?&™K«>€€ïÓÃ?Ñ÷Ÿ›ê¬kúírðgL“vÐ¯Øæµ±"6ÛÆ†xÃîEly­ ¥‰Ø6œÒ»ìzI((‚zS28È®µx¬àcãòe€kD4lê"cáM°)Íoó·µÑ›!C¼÷ná¾1Æx\Ãà ñià„¡ë\ç¥ Ä•lšËÒŠØDl»4òI%bËeG¼[ÒäS£ , ¥x(<úè£çÏŸÇî·„÷Ù¤±ù?^ 4®¢;Šú}ižØ ‰÷±yWââiŸ¹ÃZg²ÊP þЙçGKQñ¿„š²;Õ‹ØDlû4R)W%b›j/RÚ‹ØRæžÚ k`a(¨¹Ö~øá[·n\Ûë‘Ë|]tA{ÂÈFv0 ®ìhjúbEmï›-!6)…®'¯—›öŒê8~Ô·.ÅŠöµ±‰ØŽkÍDlKlGß¹"¶ã>Q9®|a(¨\kk®ŠF€ÈÅd}až@‹?ˆ}TøˆÛÅL²åc³ p`A49£ÄÆ`ÕØd)Ö†í¡Oº\ ,,Üu Äu¡É±‰ØrXÙ6eˆØšÎÓElm> UŒza(¨\kwq­×Fã]_f+ü¯˜Ø: $Ä5‚û"F‘ÎÑG- T, ŠÙòna¤ï£ŒfVÄ&b«ÂRo2[FSb¢Dl›LæÖ;] Êˇî±Ç;ø®µu|l}Õ?yÜ~wZ«øÙYú“EBãq¡ñ§}uEͯÖçcëÅ:W<á±ëû(—¥±‰ØZ7õóÇß ±1¦}´âJ.£°PŽˆmþŒ<ä™ËCA©6ìWî5ß!µ8tÑ%|l ­„NŸ§›ˆí¸ö­bc¢ I¹…晃,g‰ØŽûDM¼òå¡ æZƒ_ 1¡ˆW˜8„C4±e±l5±‰Øa³:/²b«ÁR¤AÄvÜ'*ùʳ„‚z×2®%w~¸†"¶tóUyK›ˆípöË.XÄVÂ<‰ØŽûD%\y–PP¹Ö4ýWMDl% Ý&2El"¶IÏþ®‹ØJÛ®’¬“%T®µ©÷DÄVÂÐm"SÄ&b›úøï§½ˆ­„ѱíç Éw%YBA9œ¿üË¿¼té’v­¥ß[ C·‰L›ˆ-ýÁß[K[ £#bÛÛs²ìzr…‚r¨ zêÔ©+W®,Աα•0t›È±‰ØŽe¼üÕŠØJÛqŸ¨×^y®PPïZCAwˆ•†'i@ÄVÂÐm"SÄ&b›ôì缾ˆ­„ѱíê!™u1CAåZ›u^s’ˆ­„¡ÛD¦ˆMÄ¶Ü ´*AÄVÂèˆØZ}rŒ;c(¨\k9nÈ="¶†n™"6[.³Ðž[ £#bkïIÈ4⌡ @µkmùͱ•0t›È±‰Ø–„V%ˆØJ[«ÏÂqg µQ ¼¸¦]k nË«§ŠØJºMdŠØDlË B«Dl%ŒŽˆ­Õçaָ󆂚k HáD³¥“^£[ C·‰L›ˆí¸ÖMÄVÂèˆØòDå  \kÈâq5®p™"¶†n™"6Û £Ò.Dl%ŒŽˆ­ÒéžoXÙCAåZËws:$‰ØJºMdŠØDlEmEÕÂEl%ŒŽˆ­êI¿lpÙCAåZ[vC’α•0t›È±‰Ø’žù]6±•0:"¶]>,¸¨ì¡ TåBA©ì‡Ó®µõ§‡ˆ­ Ë™2H›ˆm}RK­[Ê“\O[-ó{â8®]»œÂ·{‰J`AlY{ì±Ç´kmâmÉÐ\ÄVy\8›ˆ-ƒEhT„ˆm¡ùè<]ÄÖÜã@××… °Zbð…|„…–.™£±•0t›È±‰ØFŸ÷Ý6±•0:"¶†ƒzä‘Gàú*Tp®5¤[+Ä‚ ©zÃ¡ŠØJºMdŠØDlZ’»±•0:"¶§uZ÷/¾ø"@ ב¿#íŒÉ­äZ›¬²2'ˆØJºMdŠØDleŒD REl%ŒŽˆ­ò¹wדO>yâÄ ,†ª\k…;O¬ˆ­„¡ÛD¦ˆMÄ6Ïìá,[ £#b«öÙ@H¾¼±¥ õ¦Ê +­pÝi×Z9 O•,b+aè6‘)b±M}ü÷Ó^ÄVÂèˆØê|B ¿¾¼ËEk‚Q¸VhW\Š­T"¶†n™"6[ý§ÔEl%ŒŽˆ­Ô|+·t((Ç×Ú©S§®\¹2w˜:¯”Dl% Ý&2El"¶Rf¢~¹"¶FGÄVÏÌ/ Ê+•k­ž;Þ9[ C·‰L›ˆ­rkSpx"¶FGÄVpÊ&‹^!T®µä»±qC[ C·‰L›ˆmck²a÷"¶FGĶá”F×+„‚Ú´kmÛÛÒ»ˆ­„¡ÛD¦ˆMÄ–òÈﳈ­„ѱmõ´¬ Ê«ClX (°ÕŪßt ˆØJºMdŠØDléþÞZŠØJÛ&ÏÉ ¡ v]/@6Émr¥êtªDl% Ý&2El"¶©ÿ~Ú‹ØJÛÊOÈ:¡ Þµ†%ªÅ¯¬·ãt'b+aè6‘)b±Çp…W*b+atDl«=Q넂ʵ¶Ú -Ô‘ˆ­„¡ÛD¦ˆMÄVÈJ4 VÄVÂèˆØV˜ú«…‚òZÐv­Éµ¶Â-Ñ…ˆ­„¡ÛD¦ˆMÄVÂD´!SÄVÂèˆØŠÎþ5CAy!¨7¥]kEïiiá ¶w¾ëÝpùÓúi]"6[isQ¯üVˆí;ßýþÇ?ù~—¬ì2El…füš¡ ¼Ðá£>zþüùr…­ éJb½þÕ¿úW<ðÿœzË[õÓº~ôGÿ¦æö}RÁ15Ð ±}õkßxóƒáwvº*!PÄVâiZ3Ô\k¨ëÖ­—#™kj@«¢% Ý&2åc“mMÓQW_­Û&¦av§"¶¼³|ÍPP¹ÖòÞ»J¤‰Øf[³ÚN±‰Ø*±* CÄV‰ØrMå•CAåZËuãj“#b+aè6‘)b±Õf^Öˆ­„ѱ-ŸÁ+‡‚rÀجvîÜ9íZ[~ûj“ b+aè6‘)b±Õf^Öˆ­„ѱ-™Á뇂r´Ø¯†]k7nÜX2x[§Dl% Ý&2El"¶:Ì£±•0:"¶yswýPPs­Á¯†˜PÀ⼑ë¬Ê5 b+aè6‘)b±Unm OÄVÂèˆØfLÙõCA½k ×fŒY§´¢[ C·‰L›ˆ­³“œ"¶FGÄ6i¦® *×Ú¤´ƒÆ"¶†n™"6Û,ÒÌK±•0:"¶Äé¸I((Çöì³Ïbך\k‰wªõf"¶†n™"6[ëæhþøEl%ŒŽˆmtFn ÊQa·ʃ>òÈ#Úµ6z›vÓ@ÄVÂÐm"SÄ&bÛ]š|!"¶FGÄ60· åàÕC…Ð+W®L~TtB˱•0t›È±‰ØZ6EËÆ.b+atDl³r«PPïZ;}úô;w–=4:»= ˆØJºMdŠØDlí \#±•0:"¶x~n *×Z.[Ñ´[ C·‰L›ˆ­i[´hð"¶FGÄæ'åV¡ r­-2 û:YÄVÂÐm"SÄ&bÛ—qšr5"¶FGÄfž-lðì±Ç¶ZˆD¿XÕ®µ)&aŸmEl% Ý&2El"¶}©”«±•0:"¶ CAmÚÔdðüóϧ<j³o ˆØJºMdŠØDlû6VCW'b+atŽLlÛ†‚r®Óµ†ˆu8î³­+w±•0t›È±‰ØŽkÛDl%ŒÎ1‰mÛPÐÀµ†,Ç}ªuå‘Dl% Ý&2El"¶ãZ8[ £s@bÛ6T®µãš°´+±•0t›È±‰ØÒú=¶j…ؾúµo¼ùÁ‡ð{1µÓCÛ¶¡ öP>ýôÓØµ&×Ú­T†k±M5bÕ¶±‰Ø2X„FE´Blßùî÷?þɧð»Z;âvbÛ°*¨ܰsîÑG}òÉ'µk­Q+´Â°ElMXΔAŠØDl+XŒJ»h…ØRžäzÚìžØjå…Rî(è~ëÖ­J0 « ˆØê1 G"b±ÕaT¶…ˆm¡ùè<}ÇÄVC((ºÖΟ?ÿƒü`‹GG}¶¤[ C·‰L›ˆ­%Ó“w¬"¶Fg—ÄVI(¨\ky-ÀA¤‰ØJºMdŠØDl±Z—)b+atöGl5„‚ʵv\;µøÊEl% Ý&2El"¶Åö Y"¶FgOÄVI((Ÿ0ìWÓ®µfÍ–±•0t›È±‰Ø¶4%Ûö-b+atöAl•„‚òÁf5lYÃÆ5íZÛÖb4Ú»ˆ­„¡ÛD¦ˆMÄÖ¨Ê0l[ £Ó:±Õ ê]k Í0ã%ⱕ0t›È±‰ØiÃ^¹h[ £Ó.±Áƒ…Äf'NœÀbh O…¹ÖZÃx4†F5 b+aè6‘)b±5j…2 [ÄVÂè´Hl½rå X Å2L¬"¸kM®µº<º [ C·‰L›ˆí¸æLÄVÂè4Gl "°Ú¥K—*Ù%|ä®5¹ÖŽk›²^¹ˆ­„¡ÛD¦ˆMÄ–Õ64%LÄVÂè4Dlðc¡'ð¨6BĆ$×ZS†¤öÁŠØJºMdŠØDlµ››r㱕0:MÛóÏ?ÿÈ#À…7å&Ø$Ép­ÁÏwúôé;wîL:Q¥a ˆØJºMdŠØDlÇ5w"¶F§rbC(è¹sçàÇzöÙgë™út­a/]=CÒHv£[ C·‰L›ˆm7viò…ˆØJj‰¡ ØÎãÆÉs¥Ø r­S­¿ª[ C·‰L›ˆí¸vMÄVÂèTHl>ïë™ñr­Õs/v<[ C·‰L›ˆmÇ–jäÒDl%ŒNmÄV[(¨MJ¬b/v­×­uå‰ÄöÅ/åãŸ|ê«_ûF`¾þÍoã ÿ Ÿ~ë΋Æ%H ±X´ì…®üñÓW?óÙ M0˜a{É3DA`< k†:/mø”aUà\èšUåˆØDlk™úú±í›Ø* åCJC„â ªrøÕ÷€jDy40Jl¿÷Ñ'ßüàCþaÆám§ßPð/´|ü#ç­þ >Å)ŸûüúÌK,§CH€PO,ˆ 6Zœ‹?Ém `¨ög§(œTzÏû>à¯Òbϱ£+q¼Ú8˜>žƒÀ@ç^¥}ª±‰Øò…¥´Bl´Pÿn–¯Ù2kð±U ê]k2Àzh‹ŒÆÜ¢†‰ pÜKöÈàpÄ Æ‡c?hŒF œbŸB ÈKŒI,0ö±A ±ÌŒr ™S Ý¡™±” ƒŒ…ßv$¶ißùî÷y.„ðSˆe¿Ó yQ±Ko±ÔK€ÃU^›ˆ­E”gÌ"¶ÙX6pâ¶ÄVg(¨\kyžXI™¥abƒ;-ö?Pø˜°‚Gž~)Äï“8kô#ï·¾ ã®ãîˆ;é,e½@~ g`µ§x‹Áž°GÚÔ8Ûè¿o´…ìRïÿ:ùsoÇ?ÔOF @¥Pìú¦ÎPP¹ÖÖŸ ê1ÐÀ0±Á‰P0'SL ÄÆ…Ôb£‹«sM°S ï—n?~ð&[€S}ˆ3¼(i#ï\‹ àÏ.–ºò=NÅ2žËëŠÝ‡£ÿBËÇ&ÛqíÛ{ÞóÞòÞ÷_üØ'ô“QP)»æ¬ª6”J@AíZ[s>¨¯IÄF/7iMbt‹ ˜p1'\§mJ:WE=¬pÝÓrÖ9@Oßv‘Qbãcï`ŒM¶^Ig›'­yĆ.@м ¼Á)ò ý±•-]W»jÙʪèè?^U5XyU´ÚPP>*2Ài×Ú® Gk3y áþ-b„ßPÅãÄ,þp˼¡R'±õ­– Rˆýxoœ§"ºµ Vr ‘öÑÌŽÛhŠ2‡ÿô4‰?gÑ“‹Ë £Ü&›|l­™Ÿ|㱕@½Õˆ­ÚPPs­¡ Š–VR`>ßs#Ii …ØÌ†|` ¾(û –ó:‰(Ó¹ð7¼*JD2²;†Aôy€8ÆšS÷±Ña6êc#TÙµ3þÀ<‘KˆÍtŽ‘sá5Þ´˜h›ˆ­1ë“q¸"¶F‰­æPPïZSfœ®% ÌÓÀhäA¼ê·©n;ëä®]v.Y ìsé™Ç+f,†|ÇS\h}[âÀ¬”FªóþEÏv¿Í#6Pf̲ˆlèÛùg†ZÄ&b›göp–ˆ­9b«9T®µ=…=^Ã0±ùif|éHË7l“El"¶ ,H%]ŠØš ¶ÊCA9™”ز¦]k•<Ú†×Àè>¶ æaÂŒCŠÍÇ0`¸æA߆­¾eJŽL Hbp«ï4pË Çx»Kƒp†A«bÉøˆk£ÖKEAíæ:?¢³ÐbØÆú0Ë"6Û½Gû…^8{ö¬Èý‘'^yùO¯¾òŠO¼{÷.Zž|åuæÌ™ëׯÛY8ÎSâ#è ƒWи„ ±ÕOl•‡‚rZb¿B1Ô³T2¥…%6nØb]Ñ8_ó¢ Ø _ïG«³ ÄéÁ¥õ|„?1Tåì6¸ÎÆhÉØ/ #é“@W"E—ï50ð‘Ë~‡*b±Ý³·oßcy»à€¥îý«áxëò+¯àDà„€Ì@`ø¸Æ?)BxнìûÂoÿz饗Ú©ÑÓEl5[å¡ œ]t­!&I×Fç›H›h …ØJ˜ÉÌ®›ˆ-‰Ø@W€*0-N'±ÁK¸âˆbÏ>ûl ±­oËDlÙ .ÏîQ((çª\kë?³êq†Dl% Ý&2El"¶$b¢Ælå´“Øè' PïâÅ‹"¶MïM:]Blõ‡‚ʵ6ƒtʶ±mb Kt*b±¥–)Ád\‰-^W5o m”Ø0ƒ}l\Z-ú’­„M™GlM„‚r6¢€v­}0%<¯Dl% Ý&2El"¶TbC»›7orm4&6V°ŽF¶b‹÷±åµYÒDl%ŒÎTbk"”óC½t銄j×Ú §ºÈ¥[ C·‰L›ˆm±¡)×FûVE¹eÍ¿€ktËFä2OérZ!6Æ%–œÛÄ‚ÄN"¶&BA9£àZ;uêÔ•+WÒ'˜ZJ5h@ÄV‰m\> ›ˆíU“/\hf_Àdô°ÅµÑ Ì“Íü)p­ìÀj¯à?EcÊaú¾ÕÒÆ® b³‚Ǭµ·ü™/-!‘Øšå 4×Ú;wJÏIÉ—²k@ÄVÚè­&_Ä&b{Õ>€¨€P -`fÀî1ǧqv¥±1ù Í,z”ˆfþ9îZcß$6že/åcƒ`­¦êñ¥ZV33:%¶VBA99åZ˸²6'6V—·<±AIM|îäŸÖŒ¯üN±Ä¶Ž:³²Á~2™-2À¡M(Xå¼¶|bá¶qù)"6Û_Y¬ir۰ɯož‚åN; ²¬QÉ (†7>7/Ndd"b‹Ÿg˜oÝhÚ–?öE% [+¡ r­­Œꮨ¶%6«ÈÄT±D· ¦B\mÝÛótþ°æ­9ôUJ°u‰¸–Yß v¾¼Û‹ØŠNËÙÂï›}¦NLÑÀ ¹pS†·©|U”E‘}.l_ž¹(u-ÞIl …‚rž`ô‘GÑ®µyO–ΪJÛ[\žËæÓJ©‚Ó%_”5¬‚$EúÕbcû Ì@b}÷%¶qù¹ò±ÉÇV•mYu0•­Œ÷äãHl˜–[¼bk(Ô&@ AX]u:ª3i Œ¶%¶N óõ æ$Ø?´üç6(êI1 ¶Î=Áí²µÑ”*òyÍf¢4›ˆ­Œ‘hAjýÄðYµvÄ›Ol …‚šk É; ÙÂÖ¥q lKlD+x°úJgÎ#6.kšå`“>5†ó–“¾·á:žÕZZ›ˆmüßk‹&ˆÍ'õhÈÇÖP(¨\k{}Àu]ÔÀ¶Ä¨â*$hƒûÕ‚ÈéÜÇfË ²`ËxÄ;ÕðÞºðzãÞ’ádI}ûØÀ‰Î°BÍDl"¶ãšµú‰-ø_00C…ŒÂB±ÿéÓÿù@qtÄ„¶2·°kM®µVn–Æ9U›M œ[†n`/c&›,àûï|÷û<ÑßCNŒ\>N 2=]Í#6ôŒ*`Í…¦rÆé"6[÷ã0Ï H(øC Pí ¨(…ã}ѱXHàA+3?ÕÍn_9±ÑTùÿ#›ˆý“§ÿë{ÞóÞÙ7eý¯]»¦]k뫽‰™óÈ,!ÿ´ŒEþ:[¢qð¹mä‰}/ë!üh§(ÇfMÐg%Äf€tóá¢SWE"§ó0óÈmmÁ`ûïw`ÅÓNѪhͧbEûëÀ¬–ÿ†#.ýiÅ ¬YE/T‹em+æû°„º«Í•ú‰6ˆÿkrI4Ž™šñZÑSFó±­vG;B±)ø/\¸ ]k£º:f˜2Ø=OløÓçª4µt¶dzK¾˜8 çÆÖ}KŸçÈðަ/|LrŒïÔ†ÄF«Ó•§´©ÄóE·œ9á̇ÇåNøÆ‚,H)‘ü™CDl5?ï"¶×ÜØ û'ÒÞ”%à?þŸ¼Nbc†6öùìÂdÑÒ5'JýÄf¶‰jóü)¨× ±!*ݱßnÍ)§¾ÚÒ@'‡uBRgË`™׎ÿrÁgµôP8 žë=|ƒ#±ã-²!±ƒbõÄÇÆVF3 v’ÛÔ‚åË€Àè¥Sv¶F­ˆí57ÆâQx¨ þA„³¤¸ÄÖIc 4û—qýZUMLF}0| 6mئ~b£kíüùóÈרÍÒ°×Ñ@Ÿç, ' &‘Øøo*N·$Á‰Ã×ÅsiŸybÀ¼óôm‰Ù×è¾²ü·øÓ– ûö±uu®-@Ä~îó_ð¶Ž;}}Ì?}f씵pVgÝx›ß]·‰Õ>6ÌpÛks¿o´ˆSÁ>6žÆ ôq/ZLl<`‡WçFÖ˜_dz—VˆmÓ0»ÓʉM®µ5±Öûêã° Žß$boyÒšDl¶ J!‰s[b£KÌêA‘“|Ü@_•*s¡áÜÎ-ÿ8¸Ù (×_î¬RÅÚ $¼Ä*Uq©«ÙvrÞ‰"6[hTûˆ-ÞÇÆ­ê¨!W'±Ù¥0:8ôæ;æ>¶•ƒDló¬ÆðYÕ›\k­óÓúãï#¶xYº{‚ ¶x",í "ºxù,뜲}ÍÔµ9±•°3Ç”)b±¥[ß&3#6Z1¬öùج'Æ7ÙŸÀ5é4OEm´ˆ­„Õ«“ؘN»ÖŠ>Pû>Àa$§¼‚…x×+øß/ÕÅ.:_Ö&P,#:W*:oˆ­„¡ÛD¦ˆMÄ>ã3ö±Ù^ ®Â”Ä»+<¢ØÌáMŸa*ý b+atj#6lVÖ5l\ƒ­ôŒ’üi`ØsƵQîßêc ˆ-ÝÇÆŽ`NSbx;Dl% Ý&2El"¶ÐÆÂ™5± ÎáÈÏg\ߌ‰)<Ø™!#Þ·²ò"¶F§*bƒS ¡Ø»¶ÕS¿Mk`˜ÃlmÛ9Ò‰ ÿ¯ÎÞÇF; ›É7£y=Dl%L܆2El"¶‹ÊeJ¦OãÇf h&øâ§>Cþ¤ëŒ`BË@¬—Æ÷kÚw[ ÓS ±Éµ¶æ£´×¾F9ÌÖFG[šŠè™³”“"˜J‰HxbÊÚ¨|l% Ý&2El"¶nc‹ÿKÄ;ï CÄVÂèÔ@lr­Í{"tV #qoÙè>6s’YGéÄæay:“}XZ¥¾Û'b+aè6‘)b±×J‹ØJm‰ Õ ž|òIíZ;îSõÊSˆ«  6|´bKxæ¦[œ>ð0—&†Ã¶Dl% Ý&2El"¶¬®)a"¶FgCb{î¹çúôÓO75 5Øz5Bl=×Fcbó»>ØG,?9/Û" â-"¶ód`׳ ïÎHlHEëb‚ÊQAþé«|â,$NcêÚ ð€8Ð&î"‰—´Ó9` ÄⲸaäqzÈî%‹±±‰Øê5—¥G&bËbD!›\k—.]:}úô;wJOÉ?Ž°Û DeuY‚?½˜Õ(hɱѵvåÊ•ãNe]¹4Я¼Ä1gÞ³l€ùœXÖ3öZÕ±Õ†783 ðÒ¡Äú6¾—Î2íp×f¬Bgéw?*´D{┿´#4k,´åK519H³{q={ZðÊYnoEl"¶ãš:Ûr KX“ØäZ;îÓ«+OÖ@^b Ö AZ,k5b{þùçåZÛÝC© ʯ¢Äk@ÆJ$6.wÆûÀ̪x ò¦Æ¼t¹ˆ-f¬>ï]߀ý…wÜ„æÉËblEl"¶ü¢‰"¶,Fd“}lXÕ®µV4s[ ”&6®H’¨úVE±ÖICfÜÄAãÀc‡O!*ö‡y#C®òk— ð'ŽúظÐx¿:‰ˆÙi*ý…“ØüÂ+pÍ»ý²[›ˆm[c²eï"¶,FdebClX qXÝrö¨oi  ”&6:$§8,ÀCl¿÷Ñ'I3lläÔç?‹‰­/’ s}Ó‘\Å~ý.´UÑNçYÜž‘þÅU× .u¡É±‰Ø±:†ùîwÿúϼéÄ©·¼U?5•B±n×=‘p­a%¡…äK¬4°? ”&6Rš÷±¥s |]ÀswqÓØ$½zÁ)± ½ ýt†pNõ±ÑQÇ ÷>6z×ð“×ЋˆMĶ?•zE¿õ[ÿÆ?ü—?­ŸŒ€J¡ØÔ{ÜN®µdU©¡4ð ”&¶ô}lX3Ù ©÷cõícC/>‡_N%2z]ídÊŒûØ,â5^SZŠØDlǵnZM±SÛ”ˆGI'±e_±‰ØÖ4uõ%b«–ØàZC5÷óçÏÿà?¨kÒh4ÒÀ X…Ð2&Ÿš‹Ø`.‚bqZµ¾º¢q0P_N#3 Ä>ª@šÙ1÷iÛüñxó\ßV¶«ˆ‘`

{¿rPÚÕ«Wq•—/_±•°‡¹r[i´cù"6Ûa,et¡ò±•0mS‰ ûÕàZÃÞµãND]ù‘4 b+av"SÄ&b;’±|íµŠØJ˜¹tb£k 1¡Ø¾vÜY¨+?˜Dl%ÌÎAdŠØDl³—îrEl%Ì\"±ÉµvÜïØW.b5;ÓaŒöe ©d“~ÓGˆ–"6Ûqͧˆm’±HlÑ¢úf"6Ûqh+Äf©&g<áëŸ2LlÏ=÷Ü©S§´kí¸OÝ᯼u[ ±±bAdA‚ H :á7“ô"W-K#øúî)ÄÆrRL½ëú,!ûÅ)ìר1(±0 “µâZ¨"¶BÏú}…äJl娟ØðO*ÿé´ßëØÔûˆí/ÿò/QôôéÓ/¾øbåCÓÊià ÄF—•¯:@là³ 1ͫ›¯.‘ØÒ7}a+oèhoy¤³ð¼olÄfUá<‚SÍiÐ^>6ùØÊ™¦Ú%×Ol0°f8JüӶЂħw]kW®\©}Nh|Ò@a „Ø`¸Þ 6®¢ÆÆ„u9­êhvbc]Ô¸_$Ý{)Ä9¬gï×FK˜k›ˆ­°}ªX|ýĆgÞ/ ÀruÚµìÔµD`@læZ»sçNÅsAC“VÒòè¢þÁJ½ÒMƺ¢° ‰«¢ 6ò–!ѱy, Œ_<ÍKlpÝ @>¢Ï,‘ØÐ’ÜiLEl…&¹VE )¶v±•[l)ðo\[Ä&×ZíÏ€Æw lEl€øœl¹s˜Ø‚ÿ(úÊDb‹#:iO\fžÃ0Rd³™†°D@[±z¶Dl…[»Øú‰Íïáà{Á‘%ΰBçš»ÖäZ«ý1Ðøö® ‰ÍïE›Ml¶3$‘ذ.Á0ûùú7¿›;ŽÇ/b[ÙØ¯5ë“éŽ~mTÄVèÁ±Rlíb› 6oDFýó… l’XÛc«i×Zí€Æw lKl¶6:Lln0X¿®šHlé‘«±Ö×¨Õ –‰mmTÄVèñ±Rlíbë'6ü èÿ;¤m?­ßøÿãŸüí¿ý·±Zûí×ø¤chàÂ… ?ö‰\¦€»ò¯þôþª s×F™GÃpÊ·!ôXL(¤1ÈÔGp¥2;µ0JWú"è*ã5ŽÊ ˆk£”Ü·Ô;û^(ò¬ˆív+ºÊʉFÐÿ¿Ø·çwöó_âÄÑ ºmºli`u îçŸþÓúú׿>#±Ñïd²ÂBbãÚ(¬Y±Q&Î"´Ô¸}ÍL1ôÊï<ã?±6˜Qº ,l,éʸ÷n’ÌØ,øð±•˜ò"¶Zm@fåÄF+æŸyXo¿JðÖr™"¶¦¾†x üÙŸýÙþè‚þþßÿûýÆ—?Ú&{¿ § ­ü†°˜Ø¸6:@l€-Ë: 2cÞxÕ’Ç)?ÎRIb³Oý›Î­lt¡ñZ`]­_Ï££2;ÿ‘fú_[‰çLÄVB« ȬŸØh ø?% bï'£ Î(JÄÖÀÔ×w­$©þùŸÿyºyþÚ_ûk?üÃ?ü//|4ã3Qp†Á:‰:AA*8™|î\v ;†SÌ›ÕÙVŽI(ñí‰qÁ¿©ÖTÄ @x\í€G¼-VÃÿ‡q-Aôè¨L^W “úé D}/´*ªUÑ]›®Á‹«ŸØ¸š`åÙÿc›m8N±÷‰Ò•o­,ƒ>ùä“?ôC?D\Ãë¯ÿõ¿þwÿîßÍ»*ZÂn Èìs­<Œº±‰Ø¶¶1Ûõß±ñßÙôè§ÍÍŠˆm»­ž­/}éKëoý-c5{óÿñ?nšØ6·iõ @Ä&b;®k…Øê±)#±÷‰Ò•o¤d=|×»Þ³üîïþ®ˆ-ÅvÕßFÄ&bÛÈÆTЭˆ­„…±U0µ5„i©ª±S­×î¿ÿþ¼ùØJ ÉLÔ€ˆMÄv Ó\ªˆ-ÑLLj&b;î¥+ßB ¶>\ÃñÇ{LÄ6É‚ÕÜXÄ&bÛÂÆÔѧˆ­„m±Õ1»5Šià©§žBLh'·×Dl% Ý&2El"¶Ù5ùØV°2"¶ã>Qºòí4ðoÿí¿í$¶gŸ}VĶ‚Ý[§ ›ˆm;³uÏò±•°2"¶­çµú?œþÇÿø¸öº×½ù>&[œÏ 9Ï‚tk´ÌC§ÞèÌO†öùÉykãO¡M2\è¢/[çG¸^ u^uܵÕÔòá 5éS²aA9yþ™~9"6Ûᬛ]°ˆ-ÝR¤·±÷‰Ò•o¤÷¿ÿýozÓ›þÆßø·:u #šDl¾˜ÕÀÁ W- KgåªHfF|<¨àN`1_6”Å,¥“nŽ˜x¼“Šâ€hVGo⫎»Žsü‚AÑi\•Ñý/0ýrDl"¶lLÝŠØÒ-EzK[S[C82÷·~ë·ÎŸ?oû=î±>šAlA¦nx†ˆ/Þ°Þ9 }ÆÄ† tú<±Ymxßî(_–jj‘ÐØFÙHbbëü((Ô§ïô®YÕ,û”õ ­äËsÅüJ'e¬¥aK+b±È´i[:xÍn)b;î¥+_]×®];{öì#<‚ÕOtgÒy¼á o 3!§îrb3·™çÒ q$ <~Dœ_Žô-c¿ WHù>…Ø–I™twÍú>â⬙¾á€ÉˆbÁµÐwèígçÅRuÞ$K+b±­ncªéP>¶IÆ"±±ˆ­š ®ì\·nÝBâ\,}¢(.‚Õ@i?øÁ.\¸€o÷ï}ï{Yˆµò‡ýFñG$6¸šß’½P£ Ž£Ä6Ü€ìÕÙfà#\6í«‘7!÷¨õѧ‰"¿ö3Ö[б‰ØvnÔ.OÄ–b#¦¶±÷‰Ò•¯¨çŸþôéÓpªÑ‘ÛÉ“'ñц€|?uðÂÇ€- ÞÄå<¢ ßûýõ$6|/”_õ3bã)£;î [è7†ð5æ…t6%B XLZ±=&6*!( Ï5e!‰fVÄ&b[ÑÆTÖ•ˆ-ÑLLj&b«lšk8;ÔœjX ýwÿîß!}®aÙ<`”æ¯y*±[ãA-?ŒK}>$#64ðk£Fl„OQ¶¶Hú! ’¨xÄÿtî ë³QX6Ll\9í 2]ôdzé‚UãNÇd¢±‰ØvhÎ/IÄ–h&&5±%N?5“æiî4x×þôOÿÐF ¸Ÿú©ŸúÍßüÍNS‰Íƒ±“ø ò\錢ø§µñÄFgˈ-F%0i~ÛÙ¨,Å.Í 6ðbpÕv¤ÓëÖçccpC§#mÆ6^¬ˆMÄ6Ïhìá,[ŠÉ›ÚF͇gC×P±}ôÑ?û³?Ãö5nSÃëÝï~7v°ÙŸÁØgž}"—÷¨qÇ}°Ré£ <±ÙÚ(÷ã ö!‹¬Mˆ ׋K2Ã&±“ظM­s¯ž_Sžj]El"¶Š-Sᡉئڋ”ö"¶ÂÓVâ­$ìøô§? hC1*ûØ~øa`YŸ^–›!—ÁV§Ÿ‰«Ÿ´±ÙÚ¨_$ÐÄÛ˘õƒÇ×'6âÚ¤UWŒ3&¶¾«ëÓOŠ]•ͦ÷}‡6¾ø3gÎ0^¯¼€b<­téÒ@) <ýôÓ 6¼ð†}`…ô§_y1»Gçk!±raq°/Ì“¶èRŠ‰Žº`G—¥Ø'áž'‚Ž-Â’Ø “ üñ…®¯á­f“VEÉ^} @UœÝƒ‹¡^Ž8-èK>6ùØJ—úåÊÇ–þ¿]zKùØêŸùa‹€/í±Ção?èíW~åWžyæ™+ZNlD.8ÒrRX‹˜Øè¨ó«¢ÞÛD˜ãf¸ šðïÍ ×é¨óÆŠn³¾XQÿ[Æ?£á¨P‹)¥»1øñ @lSÓ°Ù‰ØDl-Ú®MlX-z="¶DÛU3›ˆmê㿟öÍÛÕÏ|OìÇ?ùTÍ–EĶŸ'DW²–nܸqîÜ9ô†lØÇ$ZÃA,†~ô£MÏè![ÍFröØDl"¶µlR}ý´Elð®áq±Õ74"i`‘,—–>ƒZíkög[zFÛl*ªùD›ˆm‘­iú䆈í=ïûÀÛN¿ý‹_þÊ›|H>¶¦g/ x —(Nµ Ö;›ÑýçÑMW£VEk†°Ic±‰ØÒü½µlˆØÀj|°El{›…ºžkÀW BýPT ”§\kÿëý/PÝl=‰Ø&QQÍEl"¶Ùv ù"63""¶æ§.@xE 1,w"M.Þǵީ$ÎÈèáu,b«Â&MÄ&b;®ù±M2‰ypÜ'JW>EXëÄŠ'Έk½S ò®Õ,(aŠì×´±%Ú®ú›‰ØDl³í@ó'ÖIl_ýÚ7àH³ŸÀˆÈÇÖü´ÓH¯dëÀ‹šèÛ£† Ñ¿ø‹¿˜—ÑC>¶úñkÆEl"¶ãšÏ:‰ 1 Í~DlÇ ºòjÀ»Í<ºùËå¶¶¸ü •ÈÇ6ƒê ³Ö;/q£ØÁưƒ, ±mBW%:±‰Ø²Ø„&…´Hl%¬@^™ò±5ù0hÐ…5 Z\ëý£q +§·nÝÊ2([^·¡4›ˆ-‹MhRˆˆ­„é±5ù0hÐ…5`¹<ÐOg­wöÏPƒ3†)b+aè6‘)b±Í°;9EÄVÂèˆØvòxè2òi£¼ÎZïü;ÛjÀÅS4ËÕ¿ˆ­„¡ÛD¦ˆMÄ–Ë,´'GÄVÂèˆØÚ{4â’@ " ØC_­w~ÊÄl(r€5ÓŒ#±•0t›È±‰Ø2Z†ÆD‰ØJ[c†[RØ‹c.¼:k½ó#®„Φˆ­„¡ÛD¦ˆMÄ6Û4¢ˆ­„ѱ5ÿ`è2i Xí¬õn¾·‡~øÅ_ì‹HX2"[ C·‰L›ˆm‰)hû\[ £#bkû©Ðè3iÞ2D}Â(¯¯Ö;?åF7v°™C.Ó@îUĺø±O”xØ%se ˆØDl¹ÌB{rDl%̈­½'A#έ —G_­wvk ÖW`táèDl% Ý&2El"¶…Ö áÓEl%ŒŽˆ­áGBCϤ€½†Qì‘GA¹ª¾ŠUËG$b+aè6‘)b±-7­J±•0:"¶VŸ;“|.ˆì«õÎÞ¬*<ÖC‘87Ó^#FÄVÂÐm"SÄ&b+a"Ú)b+atDlmÌ~²Œ‚ð‚aÏVKp€oA ˇ)b+aè6‘)b±-7­J±•0:"¶VŸ{±ËÕ¥L Â| ëÌÈPlzCâÜf Ç%b+aè6‘)b±-´ Ÿ.b+atDl ?ú `M;Òà6£ŒZïl`µÞƒUÔCè>UÄVÂÐm"SÄ&bËnš(b+atDlÍ<h> ¹< x4³7®±2UöŒþÊDl% Ý&2El"¶|F«5I"¶FGÄÖÚs ñ.Õx «Ÿ>n`´”»m\óâ—Ž£ç|[ C·‰L›ˆ­•h@ìó7ÿÉ{ßÜ’úɨ¨ŠmàökˆÒ@& `ïv°™°ÑD¸ð«!àë§¶0ši Ýb>ö±ýôϼéíïø‡úi]"6[Q[Qµð_ÿõG:ùs­?õ*…b«¾ñœ4OÁêçp­wvkÕEËeôð×÷»¿û»o?ó«ÿ+“¨­4 b±å3]­IÒªh ǾVE[{4Þù@¤'ˆÍŸ?PëÍ,ßÇèÊéüa½öL­Š–0t›È±‰Ør™…öäˆØJ[{O‚FtÝœׂ A¸hç™V~4U[^ÕËÇVÂÐm"SÄ&bËkZ’&b+atDl-=ët Äp6\ë=XœÁ:=äc+aÜ6—)b±Ý{´_zé¥Ë—/û‡Ü¹úÊËŠp'¼:O¼~ýúÙ³gÏœ9sñâÅ»wïÚYÀSâ#ì+x§ÛÕñ3Dl% ˆm|æ©E³¸pá’߯.·á òq)Þ¸¼ê‘­„¡ÛD¦ˆMÄvÏ8ܾ}ûäÉ“ÞLø#À/LP¤«øD´Ä‹pöÄO@&Žbq<€B;¾Dl›˜€ìŠØò~ÝJZ=ˆCAGk½sðV9tµŒ^i"¶ìVn+"6[±¨Xf:‰ N5ßk8‘ž¶Qb[ß.ËÇVÂîˆØÖŸÉêq İ5Z룲¨Ò¸˜Õ ÃF"¶†n™"6[±ѸÐIÓIl€³x)Ó@MĶɾ~§"¶u¾†ÕËšˆsy ÷Ĭ™Ò0Žfk+tE"¶õÍ`¡El"¶Tb{á…ŒÉbbã§±Å1ÇÛ(±«¢ØÜVÈ~™XùØJ˜[éy+ù+k sé3q}ó™gžA ¦Hí¼+^>¶Vn+™"6[*±ÑµÆuϘØâpæã)"¶­ò•û±­ÿ•¬Ëi¤…L¹(îî»­õÎÆžÒr%.D>¶•m`¹îDl"¶ ÄFð‚Û¬oUÜX[K%¶¦jX¦|l%,‹ˆmý™¬ i;ÏD Õ¨¼ü”Zïlo¥–;·Ð8‡ÅŠØJºMdŠØDl¯>ìXÓÄʦ=ù àŸ¶¸ú‰üq¬(‚Cñâ)D::Þ(œ‡³¼eÁGLÒçŸ+mÝš ¶ßûè“o~ð!þ|ü“Omb&&u*b+=o%5 Ĺ<Ðõh­wÏç]³Ü¹«Üw$b›dÁjn,b±½úh¶@fØ! ~"®Y2ŽÀ=†ã˜71±!&gA$ܼygñOv@Ô#ÆáÅÜüˆÄÆãöòøXÈÌÕOlä<@ísŸÿÂW¿ö«Ÿù,Þàj6(›ˆ­Ðt•Ø•5`5@}¿éѧNb]ÕÑ„mE/MÄV¹ÍLžˆMÄöW¶‚ÛÔ˜ÈÃçN]tá-ãp•÷œ!\€¡‚÷žü`¹ÐGè¥3&Ã&ró/C½r¶¬rbûÖh5{žéoK¼7i)b+7c%y5 t¤Ôzç=غ­6ø #Û&–°D§"6[q3²Bõ‚y×P9±á®}ç»ß·'«¢"¶y÷ZgIéè$³”Zïì¡ E{¼·XÑôÞ³·±•€§MdŠØDlÙíC3ë'¶À(¼íôÛßó¾lb)Ò;•­™@íÒ¢à#où—¥UUÛ¹sçnܸf¾8ÕèYåˆØÒÍWå-El"¶r†¢vÉm÷´}ý›ß®Ü¦ˆØjŸ÷_¿:sy yJ­wJE`)*‡ò}úYE­r›™><›ˆ­¨­¨ZxCÄF\ó{ÚÒò•[þ§Oÿç_üÅSX Âjø&ùB«žs\Å€K °ïâHð‰?0ùOœ8#›_±ˆmeX®;›ˆms{²ÙZ!6,†×.ZÎd”ü'Oÿ×·¾õ—«H<ðL Ö˜ð_¾Ã—èô’jÓ@gÚŽ¾EÒÎÁ{§Zb” bËhß¶%b±­`1*í¢ b®á§þÅP3dñª(  †¯K—.Ýp°;p?à=ò]á8’ª O©tîjX¹5ЙË#±Ö;ÇâÓäúdl¹G:Yžˆm[ÌÊØ»ˆMÄÖñü3+spðc¦L ^Ì‚6¬Ce/«ˆˆf6/ ¼Ì ÅîdË4ñ„ú‰¸–ñ_ATâ>6|½Ò®]»†¯,EÞ`Œ^÷º×á 6nã ×Uã ào²šKã@ f]ÜnRi)Lc«Ž€ÂV8ïx•"¶ìÞ:]ˆØDl¡Í@ú\ ±ƒ±âL¹Á hŒiÈ&6_ÁJ&0éîšYsýà+'6ìZƒb±JnãϾcEáÒ¥áëß1\W½ÿþû¡|ÿq]i®Ð (ò¸Ê·ž:Ù­0£[ñ†³>ŒëT„Ïß–X$~5…ŠØÖÁ©z±‰ØB»³|¹V?j ÚÓyf [>64Ÿ±3à Óçâ”À?·šCG•Û¿ü$`‹V° KºHô±MºÑpWp]> ’]Árá7Þã×UëqiLº45ÞV}ÛÔk½sð>‹ÞcfBì¶×å{±-1hU+b±…†…N/;ÊZRÃÄFD3öЉ§³æšÁGù<+¨gµš¥«œØª²éƒ)AlSß©˜Qðºq]~8˜3øäl]>­«®ö4µØQ_RÜôZï¼j¿xš^Æj5‰ØÒÍWå-El"¶TbÃ\ ö±쬤ËR‘Ã|‘+NgÝR”…ºñàœc¹*¸ßXØt5+†ŽDl%ÌÓjÄÖ9UðlëªØ™dëªxª³uÕª\ kÎyõeèËå–7E]2À \TõÕRÎ]§ˆ­„¡ÛD¦ˆMÄ–JlV¸=8ÁˆµÞñ}Ùçc³UQn•‹­N_¡¼õ+b+at¶%¶¾¯@LK¬œÚº*"Um]¬8ŽZW] *é¥˦:É|Á¤H…Õô b+aè6‘)b±…vƒž0MÜÇf5®rÂÓøØa`=y±¾û`A¶´E±•0:u[ç\âº*Ò:à+ N8®«"‡Þ#î±… jH‚ZúY8š|`:î{|ÕéµÞy®/ZUFi"¶†n™"6[hµÀ[X äQ€3nŒîc3)Ü”>õ Ö…ùçÐŽ·>7^¡¯[ £Ó±uÎ+,lÒðMŒï¹Ç{ ô†œ#0”xƒ?qIÐ@명žÊÄöUgO¯õÎAbª ¹ öÀôâ¯0þ©]ˆØJºMdŠØDláã@N†2”Ë”¶|ìŠÅÝxÐv¹­c¸Ñ‹ˆ­„ÑÙ+±uNK–s`º|+çÀuU–sàºêjSZ këàXûîLËŒ›…Wº±~ QÖì^-¯‹ØJºMdŠØDlé6jo-El%ŒÎ¡ˆ­ó‘àº*Ë9p]ÕÊ9p]•ål5moÏU­×3°è‰ÛÛ4iàѦ+Lêhyc[ C·‰L›ˆm¹AhU‚ˆ­„ѱu>,çÀuU–s€+ΗsສÊ9²&B'Õzçð<¢ùô¹…¿P¬ˆ­„¡ÛD¦ˆMĶÐ4|ºˆ­„ѱMz$¬œ×UYΛäl]II´®:I¥ûÂ&Õz§d8Gqƒ,‚¸ÎŒ^ "¶†n™"6Ûrcت[ £#b[þ<ÀëcëªHüËuU_Îëªû±–÷¾? }¹¶oÝyñÊ?ýž÷}àñœÇo¾óÝïÕ¯~æ³homX96&8ˆâã±@ÊSì׿ùíN3…1`¨pЃï,ÇÜ7 G_¿÷Ñ'ßvúíÍ(9ý2Ñr¸Ó@ç^¥}–YÄ&b›ø½±£æ"6Û¦3ÖU}9®«â7¤ƒ—s€fU>°IµÞ9O‚*ïA¸hµsiÔǰxóƒáÈ‚¾ÿê×¾Aû€7˜Q<è€8lÀÓcc‚ƒˆÓ'0h ƒ`Y dŒóÁð,þà¸yç`@„¼d^;~pJÜ)Æ@ Å`<}—ÉS:;ÅGŸûübãà°M±‰Øªµ3Å&b±ŸduÀrØ ïË9p]•åà^Úýºê@.©µÞyƒ 5gôH÷±Áuð~5øÀ1žØ àxLƒ³è›GlÀN,‡Å,ˆ®qƒ´SÐÌãåÀ†­Ûxÿ˜ ÒÒÂAâc,p±ANÀ…dMۨɼo´…ìR"6Û.'vßEq]•å°ËÖUñ†ëª{*ç€ø¬÷•¦˜±šøäf¬¨n5Ù†}l~,¬â8]>t‰€EG±¦±Q&°,æ¡NîÄÞ¯Qb§B~¼ð iøñæ‘G ¨"X½GlñY‹÷­s0ò±ÉǶ•Ù¾ßw¾ó×~æM'N½å­úɨ¨ŠÝþîjÉÆq]Õ—sàº*öìs]µÚô°W p­oÌóÒ§j¡%[E¸h+õˆ4Ö¹ÛÌxe€Øè™+AlÆ‘ô¨yx⑘Ïâÿ?G‰m´eOÙc ¸óˆ]k>¾"›ˆ-Ù®ï®á‡>ôáßøà‡ÿàò§õ“QP)»»Ér¸ âº*²Äq]+€ø¶`9®«²œCa’.´©µÞyã«\´2'ˆ °Õ¹žèY!&6ÛûÅÅÄyĆ¥L"à—eéÊ¢·©Ó­ÅÝfÜ|60 døÒ:—üâl|±óˆ ZåÆ8Ž—¯ÈƒÄJ«¢‰ŠÚ[3­ŠjUtosºðõ°œ×UYÎáu¯¼ð†å¸®º­ói aÇðRiŸò‚¹A>¶Â*Ï ~˜ØF÷NÅä órÍ#6ÛéÏ7~SW°]¬“«,º“ÜÓ+Bl²0` ½_þ6Ï—óˆÝ1âÕЭ/LÁÆ&›|l,B£"Dl"¶F§nUÃö帮ÊrpËq]•åÖYWÈå¥M­õN=#˜µª[0<˜b£k8€Ä¶Àûñ¦c± t ‚¡ÿÌÇ®ö¹ pœžÂ˜½F‰m´9ù<_¢/°„ØLp(2˜c8\TÄ&bkÈòdªˆMÄ–yJIœÓëª,çÀuU_Îëªu$K $‘ž‰ýâ*0rkü™(dÛfÄ{ŒÌ&ˆtîcó¦ƒû÷ccÒ‡2Ã)-È©f¢¸ oÏïd¯Q ‹7Éñ*Ð;Îe8*C8ýxšj[ÐfSߥkL>6ÿiUt[{²Yï"6Ûf“ï¨ûr\WÅ—×U¾ ¶`9‡ëª`)é«1 sw Øúf æyé¶½Ûñ¢@‡8cS~JF‰ üD'œ·'Ì‘ÑéHˆÁÄ4ã3_Ä{ÿÑï6Hæ¹øM¸dŠ žn<:üâY:çxo0$¿dlœ:ð{±­ßáø›ˆ­9û“mÀ"6[¶É$A4ç@ ÀÁuU–sàº*Ë9ÀsÆxÕ\3j½óRàçÃz¨yûæ%Ý- •É"Gk€N¬T£ üxF5ïu#úp=%t†±õ ì[¦$™ßËŠ4°/ÐOçö¯8­Z§Å£4Šb/¶êÚÇ|Ä\j‰g?ìhà£Xc¾ß>Ë,b±M~þws‚ˆMĶ›É|œ áº*Ë9 G×UìÇ~ÌÖUƒr3j½S™A„Á¼,n5Ü—Qb3;@Gѳ°\BzïpG¡»”¤)2a¥¥ôÈ6ì7±½ˆMÄVƒIÙf "¶D31©™*Áo3›Ú+Œå¸®êË9<øàƒo|ãqmРoÙ4V^P34ð·µ¥ìtb›ô¤«ñú±‰ØÚ2>9G+b+aqDl9ç¨d j`Øï…}o'Ož¼yó&`'VTñÇr\WÆùÀö/³ÎvÔÕpEl% Ý&2El"¶LÊ6c±•0:"¶mfóñzŽØvÆr\Wºa¾ï¿ÿ~+çðÏÿù?ÿà?hå…Š6uVwH¹í"¶†n™"6[Ê#¿Ï6"¶FGĶϧ¥²«¥¨©µÞ¹®ŠÜ"¿ÿû¿]q¿ú«¿Šœ#ø‚ƽá oøð‡?Ìréëªõ(LÄVÂÐm"SÄ&b«Ç°¬=[ £#b[{¯?`œ^9Û–D ¨÷GôG¿üË¿ èa9®«Z9®«®SÎaö}±•0t›È±‰ØfÛæOl‘ØÄn¹¶71£ŠØš0ê¾8Ã@N4¯Ö;/:^iœÅ}Y9®«²œrÈá=ÀYΡ’…TÛ¨Õj¥ˆMÄV·y.9ºæˆ‰‘F«ok}Dl%ç¬d¿ŒŒHÃÖ§ˆyµÞ) €… ¿î9\¥4º¥áË9`]•åð'r]uF9‡»}eì¬Jˆéy·µNqïR®ü +\šˆMÄvÜˆ Þ5¦y±wÊþÊáÁ÷ ¨aI)­7á8¬.,–s€ËÍÖUYÎëªVÎaöº*V‡39ܶ9± o‘*ÖC’%ï òÍš¡ëÌCëK2 APñ‰ð„6¬»'FI(KùKùqÒàáü·+ðYÜ…ˆMÄvÜ/†ˆÆ%Mäc;î|=ü•³¨ü€€&xÍÓHAQ~³hF®«b´,çÀuU–sàº*Ë9Œ^ ù±®ÕÉ—Û L °² WAõw_j=(ÅBUV¡³)pÖ’5CƒºXàEVJÀؘò·³0z †´ùË"6Û¨MØmƒ†ˆ –ÂjØmn5†ÿ¹Ôªèn˜M/l´¦çìZLÀ9ô?­¼å¸®j叮дÀ8ˆPV¿ Šá×ì…ÆÍ€Û¶%¶¸ÐSP}´úgç¿©ü÷•V±³ú'k›²A@lôêÁÍæM¡˜˜RJU>¶­ìÁ}[u¬~·Õ@CÄfÖA>¶mçŒzßD£Á³k½órP,Hä/mjrrjáº*Ë9 pè î4°ÖCÄÿ ¸­6b#0Í#67ÆÑgFwšýxÇ›'°ÎÆ< 8*[¹ù¼\²ˆm¹›” b+ño¢|lM> z4—ÇìZï¼hìCÀ÷KaÉË”«äÞÐ@±ø‡ØIl·mKlØ€‹ñ€Ÿ¸0ÛœÄê ΂ی[ÖøC,³uUO`\¥.å)b«yò‹Øj¾;ÇV'±á¿F£ÎÍò±œ]Ÿ€Sp&a“ÙÀÐFÆ/+ޯ֙ѣ>ݼŒ´sÄf܆ô¿?ö‰ÿž%Ê´q³†„ß +4Šx<ø1¨êŒÀYžºg¶ŠQqÍÔ†ç ŒaÃ#gû¸_Û9—xáÙ›iC[…¶h!ÕIlpËûí®Á3/b[cf¨:4çV'ry`˜ØÚ…µÂÙãÝi~ÃÜK/½tûömÎ?ñ;%û× /¼ÐwbÐÒþ´ö<œÖŒ‰iáàWÃB*CP·õ±y ®b•w€ñ¿SFø¿¨D«h1X1 16‹ÇãØOó«aéÓ–SûˆŠÄfq 6ªÍ³“ˆØDl³m]ó'ÖIlÃÿ–‰ØšŸvº€d ÅdÍãÏdÙ¯6 ÜiAFË—/ã;ÒP‰ž9s&eŒS87ˆå‰}/ëú‰'ž¸ÇW¯ú®À±ª‹@Ú¾ÜlÛ[¼þˆJªI[7uU”ÈìZó~µÀßìK#uæ!‡L2™VE§>Gk¶—mMmWÔ—ˆ-»Óµ­¢)ÞòPFsy¤,˜+ NtÚÇa8Hîlyýúuó–§.^¼xòäIà‚‡6žè[z›wïá\¼¼£îÏÿüÏq¤“ ýð6$6U©ñ”6•Ø ŠÁžÇ‹{×p~¸`ù2 04³tnÁÖ·Îl %ìä<™ò±ÉÇÖ²Q_6vÛ<«1|–ˆmÙ¬ÔÙ÷4oÆzYΉP¸¦|âÙ8£G'‡Å䄱u¶Œ×1Áj—.8qàöÇç‚Õ0˜»wïOš ‰.´€®˜ÏÖ˜i±YBµÀÔ¸ƒ-`Ä€Øgê½tpûqœ([ÍfH>¶šïNÁ±µHl%+¯L[Á){ Ñ£¹< †%µÞ©ÅxÉ5Ž`èóœÅž­DbC¿\ß47[:±á\xép.~›œ›7oŽNŠm‰|ÆePþø%QC:ûÔÞÒunáÚhœ’q q`AL`ΖtÈq„¶€ËöñpdÛ­lò±ÉÇ6ú¼ï¶ˆ-/«Qšˆm·Ì*–’Y-é† `Âö|ߦ3£G‡ñ¸_M'6ºÊìÜIĆïFh3t½-ÛÍ‹5£ð;p€á£¸´Ž˜ ï;·ñ¬ÀˆáBSƒƒ ç RæB&rIJ`W\þå‡)aBdŠØDl£ÏûnˆØJ˜Ûn˜ò–²5 k—XRîáÈ”òì,0?Àa\‘ ‚úþôšC¿0Ê.@`x¼‚8 Á>6n†ݾfÖ@l%LÍeŠØDlåÍp­=ˆØJ˜<[­ó½öq¤€M£Å4—Ôz§ ☆¾XÄFr2lJ÷±u÷Ư³gÏvÞ3[ß§ñ)"¶†n™"6[ív¼ÜøDl%ŒŽˆ­ÜŒÝ·dÔ‰BÀÁð5.©õNÉXuEÀ/Úércãa3÷ØhËØÇf¼5uU”Ûà¸6Ú鄱•0k•ȱ‰Øöý-0tu"¶fHÄvÜ'jÁ•§ Øh1ø”þãÓ †QÏÉ ~ÁÑ–66$ò˜½çÚ°·3dµSò±•0t›È±‰ØR¬Ü>ÛˆØJÛ>Ÿ–’W•’Ë#%"atŒ1ó ïŠå0[e(@Ê>6x×ÐÒÒª¥ûØ‚uXD‰&îf±•0t›È±‰ØF­ÜnˆØJÛn˜2¶¯ùeʸŸ…µÞ)0¨gÀƒqQQßû(±Ùz(÷–d~ Z:±™?ÏF˜1*b+aè6‘)b±•1Ã-H±•0:"¶æ~-cD™)„mú4¶#[Xë2/]º„˜/´ÈU ±A Y*&6«dÀeSzׂºÃ5ÌÇík>Ÿ/„]ge±•0t›È±‰Øj±ÝëCÄVÂèˆØÖŸÉöPCž,wa­w G. aàÉ­šHl–q#ð±ãìV´õàÙEß‹±¨ôÌu¦ó@ÜÐÖYŸž×ž‹Øâ,eqš4N®F›ƒ”lL]‹Æ}9i}90cÕ™,-I€-’Õ…ÌÔkA²7ŒG:SÊ1áÜ@/¹,­ˆMÄÖ¨µÏ0l[.;âåˆØ2L͈H\èuƒ%ª*Î 'ÑEƒ|¥©àOß·ôBãŠU<2û^Ä»@x0N~º±±ËøŸ— â6V蓦¬Þ =2Ùz‚¸A_xª³ ÛüÅ…Dƒ!¡SÉJ2°A0x•ÕH°² ¾FšY-_ÚÒâ¦K¬®ˆMÄ–hñvØLĶÄvô+bÛá£Rà’Rry¤$ÔMZ§—î½ ‰nЍÛäò±Åµž€_DsqØâ"QÞV =øÊÀ5H0ØÂ›¸R»ï¥³è'Á˸0&¶ÎzVA©ƒ¾r¢ì݃©Õ!µawVGå‰ [‰ØDl-š ¶mfs;½&ÒÒòZïTIµÐ4ÚŽþ&´4±¤Œ±F‰>¶ ´¨·'Ff}F¦Ø<úØÐd_’®È_x'±±2}gQÔy¶WÄ&b›üüïæÛ<«1|–ˆm7H‰ ¹uëbë£.ßÞ0Ô"pd=g˜_›ˆm¦ØÁiïz×»ðè•]P즇.!¯€Jȯ1šË.¯õΑw®«¦D<ä½ðÍ¥•&6úÕ˜€ctU4ÀœÅðR íÜsûØèÒÃ@Íï'ë\ß$ŸáûñéBLx'±q·“®dváÁª(Ï2Ÿß 8ë¶Í&tÅ'æòÀäZ² "à ÈÍÛ¹HZ±Úò ­4±ùXabÃ.~M;éq'Æ/šôbù8Ì¥ÇFžùâi£8°KŸñžþÂã}lô v¢álÃ+b±å1 -J±Í6'ŠØZ|J91ê3K­w^K§/ N>ì+}±µÉ/JlL«aá£>¶8sŒ‰ÇJ0š±”õÒç óË©)‘±K‰i°³ˆ‰vá1±1M‰%ÉblEl"¶ÚÌËzã±e1"Ûz3¸‘žÝfYj½S%Ùq3âàÅ÷¥Ò]"søÜ¼ÄŸ×±&o®7ÞòK|OCÁìkÜvÆãLZæm? >*ô8J±ÌµaÎò©¹UŽÅ‚¨‚ÎXQ.øfÜÍ&b±•3µK±‰ØjŸ£íïÚµkȯ1zé˦)¢p€(ßróŒ(ý‰2S,ÏrU£’«AFbã¶zÿ$#Êtþ˜µ±61ï÷â>06Ürä§À á;Ž'h“¾*Ú)™”Æ5PUpá¶hÕPÓæWÄ&bËeÚ“#b›a2FO‘­½'¡Øˆ‘ËãÑGMþüyäiKi9Ú€‚WÐ,Wv·ÑÞ;×ð] bƒó>6Öí¬:Oþ:>¶ÑgR8ÏÀUÃÛ¼¼sn’ðr1¤Œ5 ¦ŽSÄ&b+a"Ú)b›j/RÚ‹ØÚ˜ýåG‰mþˆú öþwv›˜S7eÈXZEÀA¼cóŒô®ùñ_½zß¾(ñžrQ Ûäò±¥<þjST"6ÛBkÐðé"¶ÆEÄÖð#‘oèé¹¶|7Yˆí‰'žð§ÁÓ†o_8Û&Ëš~‚ˆ­„¡ÛD¦ˆMÄ6Ýìå [ £#bÛËó1ÿ:àâBTfJuxà°ç,%I[Êh:c êÌèï¾}áiK¹®…mDl% Ý&2El"¶…Ö áÓEl%ŒŽˆ­áG"ÓÐsy ·ô–£Cë‹-ÈØÅèÒpôîÝ»é§Ìn)b+aè6‘)b±Í¶ÍŸ(b+atDlÍ?Ë. } 2o4@g¿•dô4ŠÒÕ6±¡k[ C·‰L›ˆm™ynùl[ £#bkù™X:ötCÔ$öœåªï‰¥O¬ÃÒÒg—^ö”óá]Ã÷îÅ‹§œ´¨­ˆ­„¡ÛD¦ˆMĶÈ4}²ˆ­„ѱ5ýP,|z.ŒµÞ9àÎbéø¸äªÓÏ}á…ˆk너ÚÀš#¶8×Z KÈd¶‘:ZÒ…ˆMÄ–npöÖRĶÄvô+bÛÛs’v=^®¾SsÕz§üÎä ˆi@š aÚð‹·Bp(6®áµ2®áÂò[_*Ÿ¥–Éfƒ\kAVÛ8å,Rà2߬eÖeûéL„ëÇÃ.†ó÷Ɔ+Èè‹ùŒk£2yzœ81mï$#,b±7UÕvÐ"±¡ÆKÆš'“ŒEbc[µ¾ÜÀì K ùL,Z•8Ú>w]úvºÄŽ–4ƒw¸¶~‰ªMˆ à¶Jj•£‚²N¬U…ßÌš VÃé÷Âi?óÙIĆS`$AQÁOŸùb¿8…ý5š¿ÃÉRTà3TÊåËD+Ú×LÄ&b[bˆÚ>·9bƒ5ÁTGYh²Ÿ.bkû©˜>úIÛŲ‡  a£îÌ£;ýʲÁÈÐMpm+b£«Ìÿ{9@là³ 1íkU™¯.ÅÇ9é‹›„-…ì×—–ê+o–Óˆ £±e{fúÝ·Bê¢B ´El¬ ,b«p"|HIk;u’±Ö;å?÷ÜsØÁ÷UUFÄXðÉ¥›Í¿ZÌ ›²*JÿYÀ[ÄÆUÔø¿GÖw‡éãGÙ‰ G ;"A’äRˆ rÀ¦8ůjU´a±Rlíb"6˜X@Ø‘V ¯›M>¶Úç}Öñuº¸:{ÈXëÝä#ûnœ§·ã²^÷a 6Yç M4·éúûØHlä-C¢bóX˜#¿xš—Øàº0§V~>‘Ø0lr§­–°ÕZÅC b›k ?¯!b³¸%¬€ˆ­ñ‰¼Ùð'cf¬õÎ îë½ã6ÓQoEl0,ð9Ùrç0±õmö𠔉ÄGt:Ò8ž ¸ÁŒ¡‘"› È4§#ÐÖFKØj›ˆ­‹²Ñ"¶á½·y‘k¡4ùØ6šÎkw;iGZÆZï¼Î¾âîÙ;Z[­úÛØü^´ÙÄxš´*ŠÕL†Øý4ûÆñÄ›Øl+ûµf}2ý2±_±˜Ë÷DÊÇVH±µ‹±-„³ÎÓElµÏûã›”Ë#o­wÿܹs7nÜ.¥¯PUŽ+nXƶÄfk£ÃÄÖéãÞ5û(ÑÇ–y0°k}¥¯ŠÒÚÚ¨ˆ­Ð3#b+¤ØÚÅÖIlAúŸ€ŠJX¼Ü&b«}Þ/°ß?1ÕYÞZï{_ª^  ^‹¯ooòwå^+üéýUAæ®2†á”oC7•Å„BƒL}C8c°óQ £tغ¾ˆºÊx£2ƒP ®Rrö¸~­ŠÊǶ7ó”~=um„ýˆØÒo¨Z® p n³Ä¾²‡m‘†jñúÖIǹãfy‰~¯ “E×F0ÛIl”‰³m5n_ãA³Å¿óŒÿßÚ`Fé*0§`2Ò•O¥¾œ$3ž%ð•ˆë±‰Øvl©F.­Zbpz•ø¿M>¶ã>¯´ƒ‹+ñ¼I¡ ‰2ûiÙ#ÇS³ìý_†S†V~CXLl\ 6ÀEá7ÈŒ9xãUK§|klM³Oý›Î­lü÷˜×n³~=’dv¦;aú_ùØJ<Z-¡ÕdŠØò²¥iU´©?wˆé¹<ÐRW ÂÜ®ºÏëÛ‡}up¼åík7Ò²s8À#ä€NP N¦¸4 |c8żYm€} %ærC{bœw³¡kk* â <®vÀ#AA‚Àôa0Ì „k ¢GGeòºÔO_ êlÃ+›|l»±K“/¤EbƒYQ•ªÉwZ'äÐÀ•+WP`*QRöZïì·/[oÞB¥‰×ØJ³Ä6›9fœØç›!ªõSDl"¶VÌNþq¶Hlõ[ùØòÏÔ $NÊåñ–@(‡"D4VÆÔ±U ÎU‡Ð:±ÕoôV¡ˆMĶªí¨ª3[ C#b«j’g ª€À°‰-QZ‰*ì}™;püá‡N,BŸ8þ5±•0t›È±‰Øvf&\Žˆ­„ѱM˜‚-4Z ´Ç«K7´p[&ŒQÄVÂÐm"SÄ&b›ðä﬩ˆ­„ѱíé1™šËc*Þ%êª/°»åà`à å³™ˆ­„¡ÛD¦ˆMÄvL#vïªEl%ŒŽˆm7O±Ó?½Z9Ú#U[\š}¹B +³±œ˯ËG[›[ C·‰L›ˆ­6ó²ÞxDl%ŒŽˆm½\¸§©Φ¶Oþµk×U$n<©RVb_»l&b+aè6‘)b±íÒF%]”ˆ­„ѱ%M¾êMÊå«)T‚} KHöj Õß“™\Øx(Î4‹´dA¶6šæ]‹?b&ÛÎ|iÁA$có¥‚Ülƒa¦·»‡1¡.ƤU R¾­™nIÄ&b›ivpšˆ-ÅrMm#bÛÁ£Ñ—G£ïÒʹ»úüv…âvpïâKXؘýß «Wùš¡´',¾ÙYÁ…¥P*Ê[ž¸®Y òÙ;ò¹vq°³VA ±Yõ*JöãaU¦)§ZѾö"6Û.mTÒE‰ØrÙ/GÄ–4ù*n„kؾ–žË£D­wª{×°ƒ­SU¨pPbÃ\Å·eþÐV&¶Àª° Tà6ƒ_Šñ;hO’ïRë¬[‰RJ`ÙxóxuJ´xïKÎÓÈsY¡+QNöf"6Û|CÐú™"¶ìElM?3‚= ­NÄ1(£Ç¤9¶-±Á&Þ/áê$=mÁj&=g¾;Ú{ü¢—«³d']n4k£ÄÖY]ŠçõæÁ޶zËÚ\%,gŠL›ˆmÒ³¿«Æ"¶1µˆ­Ý‡d†·¬<õIîK¥Û®ÚK|[b \_æ ãæ0nóF†K¥p•ùµH_£(–Hl}rè¥%16V8µrÀôºá'X½j-§¶±‰ØJ›‹z勨¦Ú‹”ö"¶zgüàȦæò€°µÞ9Fœ8q¢seV=¦N°5‰-Þ:;ØèBó‹Œ>þÀ6·qé“k£ž®üé©oÛh ø ýZax`™gG®Øb=×¶¸uzûRLåŒ6"6ÛÔÇ?íEl3LÆè)"¶FŸ”ìDÀAúà ÕzçúVZH.}äGk¹±‘Õb/”ßÖ v¹±qÍ”ûú‡‰Í¶¾ñ÷±qø3üŒ QÏÇø}l>_™>GÍfb›ˆíhæë¯®WÄ–h&&5±µøDáK¯I#/Që¸uëB:ShÏܤ o®ñšÄæwåsy1XôÄR#°Ã3ÿ4#cĆ#¶6:¼*ŠŽøãCOcã9’kà®5;+n<ÉZNm,b±5g² XÄ6Õ^¤´±e› k š‘J­ÜÒä@e÷ÐѵTÕd?[›!—_7äö/c,¼!ÃYü'6HàÚ¨G1Ft.nÎØî–BlÄ2[ *b[ÿ‘¸oý.Õc øð‡Ïýë'/âÿ'ýdÔT ÅÖp5† LÍå™Es¡]ºt É{;G®Œ)74n³!±rw:ƒCqÜïu ˆÍ2·y?\gvÈñk”³}l_5^$,úàV­ŠÎ›“Kα-Ñ^Ãç¾ó¿ö“?ù†Ÿzãõ“QP)Ûð´8ÒÐïܹƒ„g“*©ÏHÿ‘®QŒXÖp05©oz§»o¹-±¹˜£3·©™+ 6sÔybÃAfкù ºþ\[¼Í~ðÒ+¶æo£Û-áBãØŒÒˆhø3þ(e ba­ŠjUt÷öª÷µ*ºÐ|tž®UÑVž¨¹<ÊÕz§ÒúöÆ)£Ç’Iµ±õ1s˜Á‘ϼ±ÝÕ¡Y mâOœÓUP¥ 8ècNûªT™œbÃ00A(Œƒ'È‚}q%ŒªÉ±‰Ø–˜‚¶Ï±•0."¶&ž 0ð;Ã&¶P­wŽaÀ‹6µÈ餋Ú}ãÕˆ­„=‘L¯›ˆm÷öJ>¶{Y¼Wû±5ñDͺœ ® 8ü~øa$ïˆOQFt5v¶±­fýJw$b±-´ Ÿ.[ û"b«ÿ‘ØÝß7xxãà“K/6:U Á§.\¸víÚTjo±•0t›È±‰ØŽkÙDl%ŒŽˆ­ò' ôš4È;Þ&ÉGMwtž2ðѤ.ŽÜXÄVÂÐm"SÄ&b;®)±•0:"¶šŸ($§ÅzèTWÙŒ%ÔIJHÛQ.Oï¤6ÝXÄVÂÐm"SÄ&b»g‹^zé¥Ë—/{«ä\}åå?E'¼:O¼~ýúÙ³gÏœ9sñâÅ»wïÚYÀSâ#ì+xKXL[ £#b+1W³Èœ‘Ëý–Þõ?àó+šø-‹J›"b+aè6‘)b±Ý³9·oß>yò¤·>þð Å#é*>-ñ"œ=ñÄ €£X Ðް/Û&& {§"¶:¿Å±©×MmÒðÊÕzç00*t&„ƒ#¾7P椫q¬[v+·•@›ˆ-‰Ø@T,³Ä§šoƒÆÀ5œHOÛ(±­ojåc+awDlëÏäÑçåQ+ZëcHòôÓO#aôÒÔ`T"¶†n™"6[±ѸÐIëÐIl€³x)Ó@MĶɾ~§"¶ÑoÐõÌØˆÈC9ö¢›x+Àâúwa«Elë›ÁB=ŠØDl©Äö /“ÅÄÆOc“dŽ·Qb VE±¹­´“­„Y±•ž·SåÏ«Ú>ï¬ô± »ýJ÷ž>䱕0t›È±‰ØR‰®5®{ÆÄï„3oO±mò„¯ß©ˆ­ªïø¹<0þ¶ü4 T­J·­ F;,Ô£ˆMÄ6Ø^p›õ­Š‚Û+fk©£Ä¶¾ù“­„Y±­?“ûzD.¬lNOÑZïÌpƒk¸S¯ñPíEl% Ý&2El"¶WmÖ4±²i†ŒAüÓÃW?‘¿#ŽEp(^æZC:Þ(œ‡³¼¡ÄGLÒçŸ+mU› 6”7Þªêð<“$b+=oå#÷,’™u†aHX'Bs€ÉæQf¢NŽÙLÄ6Ï”Ux–ˆMÄöªl̰üD\³d{ Ç1obbCL(΂H¸yó&ÎâŸì€¨GŒÃ‹¹?ø‰Çíåñ±­ŸØˆkŸûü¾úµo<þ‘óxÿõo~»B;â‡$b+4]'‰…Ÿ ¸65—º(Zë—0¼ä:Mw’ÔØ4 b«Üf¦OÄ&bû+ËÆmjLäás§®‚ ºð–ñ¸Ê{Î.ÀP Á{O~ÀA4ÆzéŒÉð†‰ÜüËP¯œå­ŸØ€hW?óY{žñçÇ?ùTúã½IK[¹›(y^./ZëƒÇØNœ8ÑYñŸÎÛu—¨–Ã6±mb Kt*b±·cE,}ýÄ<ó"¶%·û8çbïÖ§^oéZïÏ@úa˜›z9j/[ fÚV¦ˆMÄv\ËÖ ±}ç»ß·UÑoÝyq[“1Ú»|lÛ>Qóòb”®õN`kê.ôU5€¹mUÚzïò±Z­VˆØDl­›£ùão…ذÊàle«ß²ˆØæÏÈÅgή°Nxæ@Y÷áèÑÅŠ9´[ýf3q„"6ÛqmY+ÄÆ‡1€¶÷¼ï‰ÏöVÍþäéÿúÎwþZßF¥ãζòW>;ʲt­w^úð&¹u±üM¨±ÛVÆ0{¿"6[&f1µElxø…h«|aô?}ú?ÿìÏþì<€ ?¬sÍØPµÎÝßY/à Ž[ºÖ;»Æª+*¾÷q<Ù²³;RÏåˆØ²“ÓVEl"¶z ËÚ#©œØ°} 5Ïg_üòWðÄVžàÃVEñ5 ç vÁ¿îu¯Ão,Ø!—ýÚ÷øý!‹ö‡Íðk®V¾óÂ… ˆí»ÊèQtžŠØ¶¬ìýŠØDl¶‚Y9˜ƒƒ3eZðb´a*{YE„@4s°y±hÀƒä×-jÂ(¼rb«Á¡¸·~{v+W`¼ ;ÍáiÃŽxxYÙ¿nܸ15³ë ó¡Ñ. IìOÿ µÞ9¤aÚ ±¦jfgíElyM܆ÒDl"¶Ð:!}.ø‰…ØSq¦Üà4Æ4ä ›¯ˆ`%ÔÍ÷µB6?øÊ‰Ë Ð-|\À!htC{‘Òõpä¼AØÏtîܹû￟˦Õ&iåk{^.\ݼ¨Òjp¡)£Ç }N=EÄ–b¸šh#b±…?ÊòåZý¨BRhO?™}õvúØÐEØpésÑÒPÏÊÌOµG³Û×Ol0"X ±Áµ†ú•ï`£ÉKå²)üCX6ÅÆs-›Î˜ÉëWól ‡¯În¡«Ãž"bk‚ÆR)b±…vŒ£ì(kI ÍÖFcbãé¬y€fpãQ>KWáO|ä¯c[› ¶”Ǹª6éÄfwŽ„–M§NûÙ1ž+Ôzçµ`Ÿ–ÂûVÀ•ÑcêŸ×^ÄV•…\2›ˆ-•Ø0W‚}l;+iŲTôœù"W>œÎº¥(9 9æÆó•©V¨%ê¯VĶÄvô;ƒØüMñ˦ØMeSäâŸ÷Eµï³f;ÉÖ©õNåcù{ûnÄlá¾ïlö«±•0t›È±‰ØR‰Í ·'±Ña&ëó±Ùª(·ÊAŽmhÃ{îiËn­ŠØJ…ÄæïX n$p—Ml¨hSêgIE©j½sÃyC”Ñc5['b+aè6‘)b±…vƒž0MÜÇf5®ÂÓøØÀjøLl¼»¦›MÄVÂèd$6›š\6…K†Ñ¦xsähÓÙ¹< ÏÕJ­zòfL¬:»éHÄVÂÐm"SÄ&b íxËb6^Lº1ºÍ¤€ØÀa±áSÐ`]˜Žÿ‘÷¹ñ ™N[ £S‚Øü¯;mzÀeSì ÃUÏó5.ñÌM}‡÷ØÍ^Ò: µ‡Dl% Ý&2El"¶Ð¦!“៌¥ÓË6¢ùmg;O]ø“k£1±‘ùL,WHí 3ÀYDÂ:vVÄVÂè”&6?7lÙôÆeSðÜ:“g“^à¸ÂeÎ+#±N­wªwÞоŠï8蜑@nï S[ C·‰L›ˆ­Û"ž~]/Â~3y›½â#öQ,ñ ír[ÍDŠØJ5‰Í¦ p„˦X3å²)þÜ_’Þ%[ÐÖ,Ü9¼â©Œ«™8v$b+aè6‘)b±­l=*êNÄVÂèlBl~VqÙ€ÂeS|]í#Útv.~gãµÎ³7¼â9\`t­[ C·‰L›ˆíhæë¯®WÄVÂèlNl~BƒÕðunk}Ù‘غ7ïY]§Ö;Ç6ZÃ`µB ótµË³Dl% Ý&2El"¶]Ú¨¤‹±•0:UÛð²ißF«¤Ù³b£%«Õz§>† ¨XÕŠÚW¼Ãe»±•0t›È±‰ØÊ‹š¥‹ØJ:‰­sÙiÞà~ÃjcÍ˦Kê€Plµ«C0ô9dkÙò¬<6[ C·‰L›ˆmeëQQw"¶F§~b –MQV˦Xv¬-ÚtI.QWöGj Ã5g³_ZÓEl% Ý&2El"¶¦mÑ¢Á‹ØJ¶ˆÍ/›b¯£M‘™‚Ѧۮߡw]Z:ë©s}åœgÏ<ó BY‰õPeô˜z³´±•0t›È±‰Ø²Ø„&…ˆØJF‰ÍÏ`l·b´©-›n‚ÃE9‡9\<^«å7Ý-7ÊsMZF-b+aè6‘)b±5bu SÄVÂèì€ØâeSø‡¸l òX'Iï’|£¢²?LÃ5ÝGH³G½Dl% Ý&2El"¶ã·w¿û׿M'N½å­úɨ¨ŠÝ߬‚¿ ˦Xøã²)‚"Ë-›.ÉåÍ/I´;ãÆaïüy'.¡ÏãÑ)~÷w÷þŸŒÏ¸Dm¥›ˆí¸öíCúðo|ðÃpùÓúɨ¨ŠÝ÷¬Âš#÷sÙÁ˜ˆ6͸lŠkؾ6{ ÝjµÞíoPÂ)wöåì{"­suûØÇÞù®wg|Æ%j+ ˆØDlë{Ѫh ÇþÎVEG'. Ѧ~ÙŒ2zV_ƒ%¹< sIæ¶yc-9µd7Þ¼!é¬@Z-aè6‘)b±×¾‰ØJ£›=?¶lúÀpÙ%Û'ù–k_xú C0ê?ƒë,;C²Nɨ[ C·‰L›ˆ-£ehL”ˆ­„Ñ9,±ùÙÏeS,nbÙ¿S–M—g»]??í¨ÿl8C[cö¢ÙáŠØJºMdŠØDlÍڡű•0:"¶`bÂÓÆeSøÞmÚ¹l:J?Ãó}ýÝý¸.ÀèÀ¨VN·ØìV€ˆ­„¡ÛD¦ˆMĶ[;5za"¶FGÄÖ7ñjŒ6—MtðÃÎØ¾ë—M ‚X^'Êl½äD[ C·‰L›ˆí V«ã2[!¶¯óÛo;ývüÞÄFLíTÄ–òDùeÓŸÿùŸÿ•_ù•ÙѦ£ÙkSÆ3µÍ¨Ko4"ajj?["¶©F¬Úö"6Ûl;Ðü‰"¶†IÄ6éÁ€{ì—ù—?úÑrÙ”©ÔÒ£M—ï~›4Z6nb´A?l«U\˜q ‡:EÄVÂÐm"SÄ&b;”ízÍŶBl›˜†ÙŠØÒŸ¨ –@‡Õœ€n@"F›KCx³Ò{ÌÒÛ׆¶É¨²\Ú.…ˆØf[³ÚN±‰Øvi£’.JÄV‰ؒ&ßË/ƒÏJÙ·Ó ‹¤Œ6…Æo¼—M7ÙÚ?ZA='ÀjÍDl% Ý&2El"¶ÕìFu‰ØJ[ÊDŸ´š ‡¼V¶l fí.M¦ cj›” ¡ë'™zGk/b+aè6‘)b±Í|ýÕõŠØJ[Ê5k¸lŠ< oxÃ~ôGô_þË9ºlš2˜ô6£Ë›¸ýÒÇÌ–"¶†n™"6Û1ؽ«±•0:"¶Ñ'ja.ÈÇ^·§žz A,I/–MáuízIƒ”åÎá£Kz×¹³5 b+aè6‘)b±Í¶ÍŸ(b+atDlÃÆòJíAâ ¬TrÙᙌ6å²iöçs´€2zd×y"¶†n™"6[›Ð¤[ £#bxFëŒ>HõÞmٔѦpæ!{Ȩ̔£ ‰\@Ƥ˜2<µЀˆ­„¡ÛD¦ˆMÄv\['b+atDl}OVyä‘%YÊ&ÕzGwX6E¨mŠmsK–MS’ôŽnq;®¡ÙúÊEl% Ý&2El"¶­ÍÉvý‹ØJ[çŒÎ呸Œ&B딃eSpÙôĉ\6ŽÌë;0Hä(𜺉¨f%4 b+aè6‘)b±•0mȱ•0:"¶xöe° lv* - •òÔ­mzÿý÷'.›bƒ>/ô5eÀj³\"¶†n™"6ÛrƒÐª[ £#b‹Ÿ‡å@S¢Ö{°lŠjq´i k¦ ]«6b㱕0t›È±‰Øva“f]„ˆ­„ѱ“qù/8Æàå*·©ŸË¦.\à²)ÞØ²iJø§2zÌ2?ë$b+aè6‘)b±­g8jëIÄVÂèˆØüyÜì[6Í ÑžáhmÄ"¶†n™"6[kæ'ßxEl%ŒŽˆ 3k‹H„†ßKfë&µÞ9` ö´uŽß–M_ÿú×ÿÈüÈ'>ñ D,¹L[Z"¶†n™"6[isQ¯|[ £#bK‰¯}* ;úK— íFŠó IÚ>ùÉO¢%\‰ØôÆeÓ…:ª5˜¡[ C·‰L›ˆm†ØÉ) ÛW¿öM ÄŒNElóòÜÕhÒÚraŠo/¨ |¼Œ6E¨)£Mñç¤$½å.G’El3ìX§ˆØDlÇ5h­p j+Ðvpb¬ÀÕ´ð¡ZaºdXÏ­F:І˦p¹Áñ÷pA˦KnÇòsEluâ׌Q‰ØDlË B«Z!6<Ø­à†zdbËBZõÞK?l)Ù:Òã!p-¶lŠŒ!Z6-}û:å§Û¿ü•ßûè“o;ýöò)¼7˜¸òÇOãHço†öhƒÆ1…àøç>ÿ…à8ÎÅqä{ÿ3`î8ž¸—xœ8òõo~ÛZ~ç»ßz Æß9òøÂãkì»pÄð)´ Ý^ýÌg­‹ø’­£NÚ‰"6Û&6¤ŠN"¶ÿmuÊa‰-cfÿ¤ZïÙŸ"ôŽ€ƒáT½ó6ØA2X˦è‚˦ i³_þ^ŽâÍ>„ßü¼ç} Á|ÄÇËþôäáGߺób`yØÞÃñÙï½Xv„atr?õôC!Á%ðO´|ü#çÙ€+6x{‹²ñÇqÄ4c¸Ùwá 4^¨aꇗïkïù2El"¶½š©ñ뱕 ºc[–\˜²YöÀOýž)¹ß–û±OŽË¦Hó†eÓ+W®hÙtö-K9q˜Ø€,ÀGp‰ bgÉ£ÓhŒ%À”˜Ø.þx@lFo†A”ˆâPÙWðQçØÐ]ã½%€'6ès¶¡¯NžïºïÂ!§{òH d^£YÄ&bKyä÷ÙFÄ6j f48 ±åª"•¡YîQ ‚ :;‚û ²Œ!`µK—.1ÚT˦…nî0±u@ļSfˆtÒ)Š˜Ôðô3Ll\OŒ rðC^€Yc#¥±ß¾ÝÀÅKN!¶¾ ïì#±-Ÿä÷-! -j@Ä6ÈFO9±_° ¸³ð(Që}ÒRʃ¦8á&ujƒeSt¤eÓyšŒÏõ±8Õ÷Œ÷]_ð!Ѭ3’{à{ók££ÄÆ…NïKóÂéióãìFbl×GlXç%ÛÀ…s´d¼Lô%ÛÔy.b›ª±´±â׌‡"6ìÄÂêÊ,|$à¥0eô]M–)±·lø¬\+¿£cò)Ö^¹l Ʋér ítÇ F÷±qq­@0}«„}Ćã~ß[°diÜãOO!6ŒÊ³”G«˜r¸ŠêØÞÓGl¤º¾=s¸® ø ÀÄ 'Ïñ×Ò·aNÄ6õѱMÕØNÚ‹ØfÙè)‡"¶,¹b#óÙ_Ó½p*c`ô‡‡ÍŠØ¦ÎgÛTí¤½ˆm¿f48±Á÷˜Xþ0”[jL[J¶Þ,UíÇÓٌ˦*£Mµlš®ÌbóO:C‰»ûƒˆH’“_²ôk‹¶6šBl>ø€\åá)ˆfüôÏy<ê#6ޤsírxUtôÂã‰Kà}‰ØÒg2[ŠØ¦jl'íEl3€lô”ƒ[–\xRòŸ}Þ÷Ï¥ìr+:N/\˦“T=Llðuæ‹wwu®Š¢Y°tH—’Š€{($…ؼS2ƒEO-À£>b FëíÛ0± _xgèF_8BßFºØØ*VTÄ6éÙßUcÛ(~ÍhpbË•ä6¥TÑG.±jÊ.·¢ãn˦<ð—M‡óÉm5Î û&¶NëÜ·ì ÛäA£À€{,s›aJ§“ §{ ë„'2mT<6F›ZƒNZÂÁ,øhô©ÀÀÆ´)Á ¬|lS ùئjl'íEl3€lô”Ý[®(y©hó>{) »'"ëÇ ŒË¦@7.›b%WIz1a†‰âÁb(`?LigV‹©¨ÏAå[ÆÜÃõÄ€ØØ5{g$„-­‚Þ:.¹ôI*êäN^Ù‘Äf׈ƒAhBlÙˆmôÂ¹Ë ?èˆ×Õ·Ö,b›jÓDlS5¶“ö"¶QüšÑ`ßĆÝTHߨòg!Ær9³%q€b£L³ù6»ÈeS¤#F´)~<Útt ÍbÈR™c™Íl¡$;4 cÑ™Ô)ÍïQ#²øâ£uÔIcŒ–0áÁØü¹DCºÓ‚ŸÎËì[ÏzážÅP«qŠ» cÔÞjUT«¢3ìáNN±ˆ vLl€|ýVIOy<–WHée¸MJìg"Õ-L9 ð´1Úô°Ë¦£Äf9°&atŠ×}lYt"b±•3•µK±e1"[JLeʤϵ .¥¯¾6‰‘)T·dkžë—Mp\6]s[õ•Nl% ‚dfÔ€ˆMĶ•Ù¾_[FSb¢öJl)[¾Ræô¶µÞ9B8 ±Ók4±YJݪ”K®° .˦ø Äo¼ßq’^[ C·‰L›ˆ­BsºÒDl%ŒÎ.‰-c$ñϲ®ºä!Á*!tTBU=FG;»9È £±åz^U >—&“#b±S.1zϵ¤•q'Ü’G ŽŒ^T=|¹äb+<Š 3ÚôĉŒ6½/$ظ®7j@3hÉ}c±/j±Ù¢$g4˜ œÂP¹0x† —€ Q)åóª­/OlÄ»á@ [®)-bË¥ÉÆäˆØFMóŒíúØ2æòHwk­ðÌ$‚c¢n…ï¸ $ya´©-›¢ÈléëDl±£+6žÒ¸é=póˆÍ¼P8Ápø‹Œ~$ÃáÜcÿxaü)ˆÍSIí‹9àOl)4F^Üé°/0P¾VEµ*ZÚ\Ô+_Ä6ÈFOi”Øò&ਡÖ;¼Ä´½ðÃaßÕhâzæGÆeSøt¹lŠ0ÞBIz'Ûhè"Wý¶}Ò•‡¡> u}AäÃeÅmañΰØþ¹˜‹Ç`„aài¡ <=FU^)eú÷1±Á//¡C%ÕùX¾ ÒøbEl"¶M]¦!‹ØFñkFƒF‰-Ñ•2õÀ=ø­³ž"ja›ô…ÎJò,¼ÞFOç²)’ªpÙo&-›Žr^:±u õùŠ–¨%^RdúŒNø‹3<–tGÑ0h@äŠÃ6ͯøÛýmÁV?*ÄySüp£öVÄ&bkÔÊe¶ˆmÔ@ÌhÐ"±%VFOœs)e E-l–Xº ž€Ö…×»ƒÓúp¶qÙÜ™9ºlŠ–Ø7°1.Ø€¶AÍ?û>" ?yÅÐjƪh_¿¢°Ë͇…úUËÙÄ!ôê[èlïZ<’ V4p4rT>"AÄ–ëñÔ>¶\šlLŽˆmžÒ±á ^\s7c"·…CÂw?|6)ì±$ÏÂîtzv €Õ‚eÓØq‹6À¼P†¡/-K:±á馧Êg£µägt¶u:“˜³Æa±‘lÀL~‰ýZÂoyâqtÈÙâìT›ÑUxQ@]ÞK‡kñj±åz@Dl¹4Ù˜Û(~ÍhбáK¼’‚5)“ÒÏ,¥å m9,q£Û V}°eS¬™rÙ„M§hŒÄÆW§³m±}ÈmX Äoˆ5êKÿAºâ² Î5Vü˜Onà#z³Ø/|¿!òƒdc¿$Ú963¢êD:®ë°¼äx{_@lè--fÂöáÙ.‘ή.VNŠ±Õª¨VEk'El)6bj›†ˆ-o.Jj½óyNϬ–˜Y÷¸f¢²+ç²)pœË¦8OlζIÄf»¯ ñÛ³€}9úñâ7qzœÖßhà#z¹Ð€ý;·…ys„‘0¥-~®¸ÎŽpÐïÆë”Ï}/X'Å‘8á\h8Ä @&1×Ó!¥á£¾Q¥ÛX›ˆ­2ƒ´âpDlé–"½e+Ä–7> o¨é‡ƒÁyJàgÞá…ÃÖéS5ð?ÿçÿ p­ÓÙ6ƒØÒŸwµ\S"6ÛT+±Ÿö"¶¶¦ bËXUÅZ&&ìöóÌïëJàIí#6ïl±•0t›È±‰Øöeæ\ˆ­„Ñi‚Ø÷x%ΦŒuH{h†,_X,KÙ™—7BvùÈ%aª°km€ØlgÛÇ>ö±‹ûD‰‡]2WÖ€ˆMÄ6ÕJì§½ˆ­„¹©ŸØ]P‰½¶ÔÀµÑ|¸4¬™bå4ìõ fëk ØÄ†L¼È,c/ð#—ßûÞ÷ŠØJغõeŠØDlëÛ™Zz±•°8•[Þ[é)j×™ôéÞ¾Œƒ×¹´MzA íåË—_zé%öÎ?ñ;LgK4ö¯«W¯Þ½{78—'ö½Ø5~³A|.f`çG¾¥VEKºMdŠØDl›XÂ*:mˆØ†k ob;ú:­™Ø²gßÈ»ººð©H¯4…•S„ˆ.ìðyûöm^,ÿJlvÀX’Á[1Ûq9Õ_xçuQ`‹£&t ˆMÄ–òÈﳈm‰íè;·*bËîRÊmºüÑJÏÓ‘^—¾r †%Q®2aÇjÄÆík„¼Dí•&6€”1Ö(±ÑÇ”õÆÄȬÏÂô›'°Db ê»wJ¸"áÄFOÞhÔt;,b±%>õ;l&bK·é-ë!¶ìtUU­w>éרŒ3LØ0‡qm”»Ê¦›ùϦ®Šrû=|}N¸àJK¹„«¥ä›x#¿§À ·‹áMy@fê+6O+Ä6 %ß Ø YŠ>öÃqHfÄl17ÇNbó®»À ú g3?$ò\¼TšnKã–"6Û ;¶“SDlKlGå>¶ôbM‰³9{)ÒÄ~šMÊß›}3ßòñ×/a”ÃHNÈÖ1ÚÒ.y L"6F-0£[gÈj§JKhÌÞaø3€0œ !å ½mÏ'3 ;¥‚Â$ø³F#:=y}ÄÖG]¾½a¨E0ÄW½ÜÞŠØDlõ›ÍR#±-· ±„|lp†!8Û¶2N —ÓwÔ)£Ç¼™0Êa¶6JtÍîAÒ²µÔIÄæ]z8‘Ë£^Tß5–&6úÕ˜€ctU4°8‹á¥.øÃb p@Íï'ëó±A>N´Ÿ.ĺè$6.ãvšJ`¨]x°*ʳÌç—ËÒŠØDlóLÙαå²#^ÎæÄ†¹ˆå̘Ës=½úÓj¨ôá‡N) š=¹Éj׸yG£Ä†¤¸·l”ØâÕÌD›%cóu®è®ã²ìÀ«4±ùXabÃ.~M;éq'Æ/šôbù8Ì¥ÇFžùFWE'íãÒgg¼§¿ðx=ˆh8ÛðŠØDl›[ÅÍ b›m8Nܜز/ÿÕVëLúef¿Øì‰]½ãbàÈa1±a“E?ñ†®5´ "Ø…µd{{Ùâiß(pÍÖI7ñ±1­†íõ±Å™;`L<îPB3Ü÷Òç óË©)‘£Þ;kй˜hÓ”Á M®ˆMĶº¬¦CÛBóÑyú¶Ä–^©)qÂc‡V@[bûušÝ¸q!¢)}aüpÅå] Néwm@NÀ,ï9óÚ5ÚÚhÐ2( êòõ©x:»è{Ñžc´A¬Uëz •n^|N\[Äš`¼¹ÞxË/Aò=ͳ¯qÛ3i™_@´]ü€ø¨Ðã@(Å2׆m8ËKläEçV9?0®3V” ¾Ã“Œ°ˆMĶÓ:ç*Dl“ŒEbã ‰­„3©ªZïœå“êT¸ýnγªsh #±q[½ÿ ’e:Ì€X €uâý^ÜÆ[Žü8á œ`ÇñmF÷ÆÙî·Nɤ4®Ú¨‚ ·EÛÀN„š&ZTßLÄ&b[` ?UÄ6ÃdŒž²±•Ø\_—?4é–¾×mù¨$¡Z ä"¶ÑgR8ÏÀUÃÛ¼¼sn’ðr1¤Œ5 ¦ŽSÄ&b«ÖΘˆmª½Hi¿ ±•¨Ë^Bæò9=)­Z…Âå„©¨“ØRŒ‰Ú±‰Ø¦>þûi/b+a×'¶¹<°ñ µÕ+Üþ…Mu@É”‡Ë3›ÒRmö­[ C·‰L›ˆm߯jèêDl%ŒÎÊÄV(2 ¶ZïœÇ×®]ChEâ âÌ›â$±_5«M"¶†n™"6[mæe½ñˆØJ5‰ {ð±ð‡JMy'MzfÚ¼ýK›äö«0ÜšºR_^"¶†n™"6Ûq›ˆ­„ÑY“زçòÀÃP"‚!Ë3vþüypXЍIÁ¤)Õ¦i ˆØJºMdŠØDlMÛ¢Eƒo…Øú¢Ù71£®FlW®\¹téÒ¢\a­wŽ{×°ƒ-ñbëô&^Ͳk@Ä6jµZi b±e·Íl…ع𻠳²±¥§MŸŽÖzçà'•™Ââé‰'RªW¥kF-›Ö@ b›‘á‚ép‡Xœem’Ñ[xú¤¾¬qçuÁ\^ìŒîDl"¶¦mÑ¢Á·Bl3ì OYØ åÝ(±Æºh‚þß“'¥…K_<Í26 I×J‚^å5PŸ ]ZzËìĆÔÿV] N–‹\²¬ `?A:\+úùi;sêŽ.2 /ÕòtˆêJ5¶ùu‡Sï\pÍT”Ñ‹ØDléþÞZŠØ2šUšØ -\V»U’ÏlR¶¶½=Ïu_+Mñ…ïÝÎ’S…® ;±EP`€< ‹öƒO}‰ObÕ¶bÁ4‹Þ¢ n•uÑYHÔN·²WL·Kš„ÀÚP*ŠÄfbMÂäò†eÀdžŽR¶‹ù^‚5Y.ìeÝSL‡¯‹èMÌhfEl"¶Œv©1Q"¶Œ¦¤ô>¶B+&mê_y~Oºäš/de½Õßè ¶³gÏ®3ÔŒ>¶`I4ÞÇF6 V .øadÚXä»÷Æõ™£abKÙ+d@QóˆÍ€¬óºx-p鉨²Oòû²K”À&4 bk…ØJäòÀ-sšeòOÚZ‡èxã°¼›¥k )§leƒw ಮáZ2[ì4"мø ëLlƒ>nPáÍïW›Glñ¸@)ë¤ Mà:¬?˜Mlì¨óºFwàͳ½ò±ÉÇVÎ:Õ.YÄ6Ïj Ÿ•}U ìåÊž`lRѧõ§2.9½úÖ“O> ÛúƒTS5Pãz(^G˜zú¼ö¥‰­oI†XçHã²)Ïê[7ĉ€*RÝ€­ÏEÇ-k´Tƈ$ECÌ”¥Ï>˜½.Û¼¹šr–|l)ZÚa[ýÄV(—fsµÞù˜Mò)"£BD³íøš. Î6øKnÞ¼¹Â 6$6æÔˆ]nFBŒ ˆ3nøˆ„bë“o׸ñͼ­ÃŸ>ÿÈ Ûèu‰ØÊMl[9ÝV-YÄV9±a™ïÔ©S‰[ï'MµI[Ä&I^ÞW%N¸EU9‘8þc6CÝÕ²²e$6nÌò6€;\1Dx¹|É–`]’>0ÚI'œ-wçc㚬åûð¸Žp±¥\$ÇÛþš\­ŠjUô˜óÞU‹ØšÎÓs­Š–«UyŒIKœ•_ËqËk¯  qV,Œb…te$6ò§«ab3jñ{Ý€>ƒ.Ú0é.sa0ÿ­&6âOáé^¾'?o¯‚èÑ`+žÁb¼KÏ>" _zI eM·Ã"6Û £Ò.Dlé–"½e.b+”Ë£Ü2k–Y>µh|8%K×RN1œ¡V¾}×ÙÊ–—Ø€,ž·àÊ jRŶ)4É„ªÎö ò š‹¤)…•±LIùbòybgwXÅGÌ6â 6Ø{^ÅÀGô _x.^ðM·¥qK›ˆ­œ™ª]²ˆm‰íè;7 ±]ºtéÊd>Òv0*IDAT•+Ù'P9¿]®¡N"0eôÈ¥öÒrPÞàÞn­«WÙ³{àõÒK/•îòó[öŒ%¬P 2K(JÄ&b[ÁbTÚ…ˆ­„][NlåJ|V^%ýÚµk¨FŸø´€>Oœ8‘¾Ý-Q¬šÒC ¬®(ÖC‘V·P_ؼÄ£?Ö@|h «Ò¢L& Î;r›ˆm£Qc/"¶¼Ö„Ò[¡\˜å@0ËäžšSmÒv·,#”…@´–A;÷´-”<|zvbÃj`ÞíY% Ѷ2‘þm4QÜŒŠØDlEmEÕÂEl3LÆè)Kˆ ic‘¨¢D&ØI i7™µ“ü؇xReôØäN5×ivb5jPH"6[sö'Û€El%ÌÊlbƒ“ ¸V"—G¹,!¹æ"<‹È—.M=Òu¥–"¶†n™"6Ûq Ú?ûg|èäϽýÿ°ò,@üÌ›Nàwåãäð R(vê¬*P9ßàÚªé!Ÿ(®…öS5¬ö‡Õ€ˆmº*Ñ©ˆMÄvX;öò{ÞóÞòÞ÷_üØ'ô“QP);uV•ƒªú*‹ØØtMŠ'M«–{Õ€ˆ­½ÒZ`-!Ÿé;Ò&°J‚Zí\y‰ I+:E}æ3ÄHÆa’AZµÎ6È^Æ,¸yÔ:úñ°‹á$jFϲÁY’6k6*3E!¹,­ˆMĶsk5py"¶\vÄË™Jl“RZLš¬•×zçµLr.*£Ç¤  ÆÔ@^bë«Ýî‹°ð@mAé‚ ˆ;>µjü‚pËÎú ~<ìÂW|·÷}¶Î—Là‚’ £21€¸Šº­1ÃüŠØDlÇ5k"¶&cô”IÄvëÖ- Kº‡iÒd­¹Ö;/dj©©ë§“Ô¥Æ{ÕÀVÄT &¶¸<(3Ðú4"‰Ä†ŽF͠滈˞Z]‡áYBbà =|¿"¶B”*ÁRlíbEl‰vmR³tbÃ^{@U‰\˜yåVZsMkp*2t¤ÇÆN]?Í5NÉi]›ýUÞI6@lô“ùjî´9` {µ">óYþ™ØX„>¶o„0Ö°J!6^)~{ò±zpDl…[»XÛ$KlœHlåryÌð]m2S§2处m›\‘:­S[yËÖFˆ­¯^;)Í×e·ÐÅ«¢é>6Ƕ¹NËf¼•Hlt×ùŠ«"¶Bƒˆ­bk+bK„°IÍRˆmj>‹I3©òZï¼–©}§VˆŸ¤15Þ·¶"6Ø Œ9φ‰­¯ì•ßî–èc„ÁÕ¢8ž¾BR¶ Ëf2 !Ê¯ŠØ =V"¶—QµS¼~ý0¶Ælƒ<¼ð&>ñúõëgÏžEÕ<?¾{÷®É„ž¡à4.qïEl“P,±q ±MÚn?éÖÍë6i$çÚ>ãP%ªu lHlX%4'Ùlb³…ËDb#äùïú2;6ì<3Rd³™ÞÉç×FEl…Û˨IŒÅ^¿þð SÖ#é íƒÑ/Â*C&Žbq<€B;B!"¶D$ª¼Ù(±-ˆÙÄÒáÔ §S J‰mT›íEƒÿi˜ØúV'gøØWE±mnªl‰3qU”f™2 ˆ"¶BÏ‹ˆmœØ@T,»Ä§šoƒÆÀ5œHOÛ(±º»båc+ÃÄV4ŸíTZÊ¡GDZ àÛø{‡×)s±ŠšØ^ͤ@y‰ ìÕ¹[ßJ¹ƒk£ÜÖf8åÛôE{ æ:·áSÏ(]¯oÿ6¥YÄÃ¨Ì Ý ×F-!b+ô$ŠØÆ‰ ˆÆ…NÞƒNbœÅK™j"¶xT¡ÌbC.G}´ÐcC®â§¯ yø-eÄ ß9`gÎRâ:ƒÉ˜Ð +Ú0Е§›’û6çͶÛÊdžÇPÄ–Dl/¼ð‚1YLlü46jæx%¶`U›ÛJ›HùØfŽûˆ {çQ ³Pêµúk½s2O h" péçTòj /±ÐG@3ø!`ùÄiÍÖF¨pÆ<´£ç,ˆ  —ÜÂc×<Ë‹t…ñðSÿÓg²…Vê’‰ké2ã”Â\±-œ·}§‹Ø’ˆ®5®{ÆÄï„3oO±•À£ evâ7±w>=÷ØÔG½\(ÃÔ‘ ·ŸZ´èž¿¼—&iÕj ;±Y(3ÇY-èd ÊØ)¶*·i‘–øƒ÷tªùpN€”U&`@€÷A¸¼ØÜFäâ…p”™ØÌÇ6,³³׎åc+ñPˆØR‰à·Yߪ(¸-¸C¶–:Jl%ní°LùØJ_LlEsyà·²n8uœE½’ë?nêq+ ” 6£™Ämþé¦*È´lºÀ¸þØÆsUºü¾––ýZ–* UQ­Š¾jF°¦‰•M³) àŸ¶¸ú‰üq¬(‚Cñ2×ÐñF±à<œåm>bÒ>ÿ\i×±±`Köç¿„À˜Ø°w ;Ø ÝÍúk½ó±¾‰€ƒIZqº³›K刭„‘Ì ˆØDl¯šÀÈ ßà'âš%ãÜc8ŽybBqä@ÂÍ›7qÿdD=b^ÌýÁHl¿”¼»<—4 ɧ‡½Ð¥Ç«ð%JXT/SÄ&b{Õj1ókXÞ fâð/æò`µ åGg]QJg™„À>mc%狚T[ ûRŽØJG3äl3¶£)£GÞ[ iÔÀ†ÄF ÃÒOÞÚ€{€A,H¬-’ä|µPœøØbÖ‘¡Õ’h­ ÀkÒ[ÞeWP-aTM¦ˆMÄvï‘fò[Ö˜‡YŠ5;Ø>´ÄÔÁ§8Ñ>ê#¶ +›1œOÕæÀ÷¸ÒWÄV¸"¶Vj½sÒ΀ËK¨¥É߇j ¶Àgf®)¼ ÖLIK\y´µQ_t°ÅË©°fÞ6Jl} ò) ¿  Ê¡®¼0*b±Ý3Jp€ùD¸VZj€Ø˜78+6ph€\¸;->Jó)sã"¤%LgCÄ󔽨p \ƒÌBÄÖÖ/„Ê>÷Üsé“vÆjºpµ<¸V&¶`!’«¢°X%ö‡‹ŒÞ‘ØÀI†<]¢¥õ­ŠöUÖ˜ñe齃 Gä¯ì`ÃE‰ØDl÷¬™Õ ¥i0Ñß6Ll¨pà×F;}ltÂYåxÊïþÀ›­ÆûØ:=[3OcˆUQ€‘OðfG¸`êw¶Áåf›ÞJ˜Ó@¦ˆMÄöª»Ë‡gÚbèðª(í ­.$6P pm…ðf¾El%LL^bk¥Ö;'ö®aÛ$>PFIêRãØØˆ\Þ oÕ¶¬ÅqšÀúÏÌ^n9;ž…Ø8ïccL+z!ºyX±Í˜ O¹oáù;8 OÆ[þ} ±áò¹6ºØ€kë$õ±•5“™‘ØZ©õn3jFzŽG}ôÖ­[;°!º„j5°!±Á,p[wqÁ1vù­i±á,|Êefd,›‰f×ÒWEûê(°G0"cðÛo¼óÄÉ´*ºò̱ÝS8V6ÉL~×?Þ3C›½|>6ŸàlH)‚gÒw${+1'äc+n¹ˆ­¹l3Â#𻯡d–ÖÀ¶ÄFâbb4@DOÝZ1±ÑéD°æA[€%WŸ¤3ò éèÕ³ßf*yà?ê,ŸU´jŸÛ«Þ5p’O±†•ÊøÅÖñþ¶ÎolŒ•S¼Ãäâ}ÐQÜ>»]±•0+Yˆ­¡Z3¢Ú*šýé“ÀÕ4°±õy­xœ¿û"+í#¶ LÓ@Røðà]‹Ó³õÕ5Àð±GvJ¦³°ï£FÕdj›ˆm5»Q]G"¶Æe9±µˆ2çλqãÆ¤)>Ã'7I¾KÔÀjÄVžH¦×€ˆMÄv\³&b+a —[CµÞùð`#¶£Mzš‹tuj\•Dl% Ý&2El"¶ªl˪ƒ±•0: ‰mFúÙU'MÔ<‚8¸sçΤa4T1éêÔ¸* ˆØJºMdŠØDlUÙ–U#b+at–ÛŒrœ«Î˜®Îðuˆ×¤aïy@½Ig©±40O"¶†n™"6Û<#°‡³Dl%ŒÎlbk«Ö;DH<üðÃSÙ«­©{xÔ} "¶†n™"6Ûq™ˆ­„Ñ™Ml-rÌŒljmÝ:®uØÑ•‹ØJºMdŠØDl;²L/EÄVÂèÌ#¶'çeS›‘ewâ¼Vsià5±•0t›È±‰ØŽkÝDl%ŒÎ bkÑí„•Ð'N äsÒóÓ\\Ť«Sã:5 b+aè6‘)b±ÕidÖÕ;ßùk?ó¦§ÞòVýdÔT Ŧ߿Fó\ÌöœyéšTKi S"¶MèªD§"6Ûq­Ü‡>ôáßøà‡ÿàò§õ“QP)›8«1Ø [bûJšÍ+ß~éÒ¥+W®Tr Æq4 b+O›È±‰ØŽc¸Â+Õªh £3iUt†§ª†ùzúôéçž{nÒHf”±š$_¥> ˆØJºMdŠØDlÇ5t"¶F'ØæíÜß|¾^»víÂ… S‡1£ŒÕÔ.Ô^Ъh ›VL›ˆí¸VNÄVÂ%[sµÞùœÌÛu7oõ¸O¦®<«äc+aè6‘)b±eµ M ±•0:)Ä6¯²S “k^ÍÓ«¨5\¬Æ° ˆØJºMdŠØDlû0Js®BÄVÂè¤Û<î™s³žƒ½k`¯©"]üz™j_­Dl% Ý&2El"¶üvæ…^¸}ûv~¹¹%ŠØJQbk4'ü‚À5¬oNš†8 e¬°<é,5–2j@ÄVÂÐm"SÄ&b»gX'Ožô6Â9{öì™3gü§—_yÅ'Þ¼y-!Š¿Ÿxâ ; BxJ|„}¯ qFûe¢Dl%ŒÎ0±ÁMõÈ#L-ÄYâîO•9¯*ü³¦ŽMí¥ ˆØJºMdŠØDlãÄüÂD¹xñ¢…NbCV-4»zõ*›Ý½{'êáMav$æÅu쯈­„Ñ ¶k½s*ÎËÍ1ï¬u&¿z9ŽDl% Ý&2El"¶$bƒ· >0ËtÚIl1“½ôÒK8ëúõëèCĶɾ~§ÄÖb­w~¯Ïy£Ù掃2¹RÛúf°P"6[±ÑÌaÖIl€3ì` Œ C¹6*b+ô ×&¶ØîIÿ[ü޼uë 3L¹2zLÕ˜ÚÒ€ˆ­6#9{<"6[*±‘º¸6[ßʦqÞ0±a"ûØVˆ]ЪèlÃ1pb'±µXë_Ÿ³Cæ¹å }gKì‘5 b+aè6‘)b±M 6¸Ð¸6v­á#ü,#lp³ÉǶÉã½I§1±ÍË:[ÉW,¾íðš:eô˜ª1µ/§Û&–°D§"6Û=CAó&Ãû̼{Œ>3xÚâXQç–5¼°ƒol¸ÍÇ.x†SäAʳýñO>•Òló6±5Zë³÷Î;§NšÙг¦æ)÷…-É×€ˆms«˜k"6Û«Ö heaž8d¾±Ø=ÆÌ1±×pœ«™øï}ZÇ#9RCDl£Ïóã9ÿæmVCƒ€ØšÞ}íkØÄ6õû^=¦jLí‹j@ÄVƒaÌ2›ˆíU[TjÌ£F óaÁ4:ä:ó±Ô¼@›QÞûO-[ˆ ‘gÙËçr+dΚØÇöï~¸ý´HlM/Þ¸qåÛ§Î=d0AÊ\,O=Qí¥B±e¡¥„ˆØDl¯±Ü£ìú¢u±µ?‡@6;ÁD•¢qðŠÃN³›³ú‰íëßü6@ím§ßÞ¢­ÑZïœfX =qâÄ ðjÚ§˜ý“À4 b«¶²ŒAÄ&b«Á¤l3†&ˆíêg>‹G›ØÚò±µ[ësqxRá`›±ïm›@½C"¶,´Tƒ›ˆíF«ë*ë'6³Í[£µÞ9Mf§RSFãZ“Н\ÄVleƒˆMÄV±¥)<4[#AäÁ;ÞqÄVøî?/Ò%SQ*¾à°$Z˜¥[ C·‰L›ˆm– ØÅI"¶FçSO]yàÚ]¼víÚ… fLðyœ7£#" LÒ‚—ægÞtæþª~Z×ÀOÜÿ¤[¿ËÆ÷íòªtQ£±• 6øØ>ò‘ßU~ j€hˆ÷œ:¼gžy¦i·âÔëUû¶4€h0½v ì”mkâ•­ˆíU­"<›¾nÁ@g":\W*ˆ6e—qj0€÷ÛdŠØ [ôÆ•>oûÝìÀÒr"ÉÒ€4 ìR"¶{·ùÏ ¿‘2 ¹Ùx§-}Z&Ô‚AÕ?WàƒùÛ²k#\hÚ‰ØDl~jÍ.~:¯’U¡Y-±Ò€4 ìX"¶—ñ]e¼…÷`&#¶Nω /-°Æñ,ßÎ×H`ƒø ³òÒåÖW¢4û±‰ØlRÁO†¸¥¥°ŠÌmíîÛËþXI 4 Hå4 b»WTÊ×°bSö&Ð>ëJÁfl‡>6x×2×*ÇSNçAK™ në,*Ÿ}4Dl%Ъ̸|öWBà•+W.]º4Cò¼…Ôéi@¤ÛËA*üI×ë¸ûÝltƒY%P¿‚9°*ç\ßA­Šb©uĶHl³ýd³3·ÉìJÒ€4 ÌЀˆmˆØ‚rŸ¬oÄÆÕL®.'6à ½}Þu7ãŽ&ž"[ †k‘Øfg¾}ä‘Güƀĉ§fÒ€4 Hó4 b»·Lé#¼­o›ñND{.eöÝ€t%tF*Ì»»g‰ØDl˜³ËÕÏ>1ûL–@i@¢[Ç>6î*ÞÇfóÂLg‹ÇÛéØ!ç÷Õšˆ"6"€mF–£Ù'šÌ+ HÒÀ4 b»¼iprJ‰õ5ž¾ÄÇæÀXQìŸ+=ùDl"6D æ`ÆLCyT‹Ÿq¢N‘¤i@˜­Û=ÕaáÒ²¯ÙJ(9,x¡±íc3¥óôÙ>6œDã…:ûv¦Ÿ(b;8±Ý¹s¥¥f$æ˜]!}rª¥4 HÒ@¬Û_éÄRll5Q† '䕈íàÄ6;nÞ5øØòÎFI“¤i@Õ€ˆmTEûl b;2±Ý¸qãܹs3f62z ×î ÏÜŒ¾tŠ4 HÒ€×€ˆí óAÄvXbC­w`qsÆÔŸ dF_:E¤i@Ħ9ð²ˆí°ÄváÂ…k×®Íxnݺõè£Î8Q§HÒ€4 ,×€|lËuؤÛ1‰mI¡D*̨=Úäã¡AKÒ€4PŸDlõÝ“UF$b;&±Í¦.eôXå¹T'Ò€4 ôj@ÄvÐÉ!b; ±Í¦.„œ8qbÞÖ·ƒ>`ºli@rk@Ä–[£È±Ø–äQSFFk Sö¬ÛžïîÀµ‰ØŽFlHç¤3¦;P6eô˜¡:" HÒ@F ˆØ2*³%Qïz×»îÓ«€ Ø çj×"eî¼)£Ç<½é,i@òj@Ä–WŸÍH“í8>6¸Çp€²T3fç’ØÒÝéi@¤> ˆØ:7DlÇ!6”{GÑ÷y}vlé¼ît–4 HÒ€ˆMsà5±„Ø^|ñET8˜· mv1+=lÒ€4 HÙ5 [v•¶!PÄvb›½ M=Úx’5Ji@8ŒDl‡¹Õ¯½PÛˆíK_úˆmÞ_²–:¯G% HÒ€40 ÛA§‡ˆíÿßÞÙ¼ÖuœqØ@Ö)Ô.þ(úÒˆ4­õ36éB˜,ÙxSÐÂP¹u1ni% **^T‹,´«H7¢YÄ«æ.íFda´0dã…ùÜŸ}Ìéé¹ú¸wÞ™9óÎy„¶|æã<ï{ÅÜ3ïTol–E2*zŒô÷· Lc+88)§†±UolÚm u²°$ >->l8ZA€À…0¶ ÕyÆV·±©*Çòòr؆*zÔù™ç® ç06ç >ÆV·±©^®ªæ†e‡¥m؈´‚ `l"ªóŒ­bcÛÛÛ[__K\Ëf…°i@óÀØæ¡Tá5[­Æ¦M*{«ïYk9!`8š@€Àü0¶ùYUu%ÆV«±Y6 looollT•èÜ  Z`lµDrÁûÀت4¶étª  æÂ«Ë-‹sa#Ò €æ'€±ÍϪª+1¶*Ír ¨V×´ÆVU–s3€*"€±UÌEnc«ÏØ,Ï4ŽŽd{aÕ@É;®… @[ 8ïÍ0¶ÊŒÍxJAðñ£Þ?Ì€€›—HEž'ÆV™±­­­íïï‡eÉáááêêjX[ZA€@[ÎÅ‚±ÕdlFå²¼ýV\f3!@•ÀØ* ìE·…±UclÆ"j»»»*rQ¾ðÿ€ 00Œmà 5<ÆV±Ýù–H²½ÉdVn7lDZA€@Œ-Œ›ûV[Æv||¼´´¼ÇsssskkË}6s€F@cAO»EŒ­cÓŽ½Ä–ÄÆí¥aƒÒ €Â`laÜÜ·ÂØ*06ã©í–í¥î?Ü o06o‹4_ŒÍ»±_Aûꫯ´E4R6Ñ  $'€±%G\æ^Œí³Ï¿¸rõ𾧬è}>Üy$°y"nNu–ëL€@0¶*¸øMx1¶^•®ÏlÆ&]›N§‹‡ýE ããÔ°Ai@F› ×æ[ oËclÆš·–㽦;ó† àŸÆæ?†Aw€±956•äÐ+hÁ5o©èôq¡ á `lÃÇ``lNm}}}oo/8gŒû‚Ç¥!  `lF€^›clMï®é ¶àœ£¢G0:BœÆ6x†™ÆæÎØ´c@º&ë ÎË ÁƒÒ€¢ÀØ¢`ô× ÆæÎØŒ;¨èáïSÊŒ!t`l#MŒÍ—±w Ø×çFú9á¶!Cc+&y'‚±ù2¶7nh‘,8GŒësÁãÒ€bÀØb‘tÖÆæÈØõ Zp†œœ,-- —†€ ‘Ʀ§®06/Ʀšò­ãããàô¢¢G0:B(‡ÆVN,²Îcóbl÷_~'ÇÑÑ‘*îŸ@<. !@ .Œ-.O7½al.ŒÍî[ÆàÜ$4… P;Œ­öŸq› c3VP{üøñÊÊÊHSœÛ† PŒ­®xÎ}7[ùƶ¿¿¿¶¶6wHO¹PÏC-w-CÓ€âÀØâòtÓÆV¸±éͳÉdbÙà©ãGu©›Œd¢€ p.Œm¤ ‚±nlÆ žváéƒÛ† P*Œ­ÔÈ$ž—c{òôÙÝ{ô=…`EïóáÎ#µ‡Î~d»q‡©ýè€âÀØâòtÓ›cûìó/®\½¦ïÑí*E‡±ŒÍøþ™ñH+7IÌD!Œ‰Æ6¦hwîÕ‹±¥ðªt}F1¶ÝÝÝÛ·o[òRû´kÁÒm!@ 4[iÉ4Œ-…·ÙMËc:á@çJçý‰jðÐ4„ t0¶tl‹îc+ÓØ´»S{<-©³¼¼ Œ@À ŒÍI bOcKaloÿùÆ›ÆXi‡éd2±kŸq4‡ ¢`lE…#ßd0¶ÆÖ« N*z„q£ º `luÇ÷Ì»ÃØÊ46mÕÆ…‘&%· @gÀØFš[™ÆeŸéHsšÛ† P5Œ­êðž}sŽŒM¥tž+ºhnè‘袭¸€Æ@cC”O¹GGÆ–b1,QŸ–÷بè1Ò"· @`>Û|œª» cK!mcÛÚÚÚÜܬ.Ѹ!@ˆCc‹ÃÑ]/[QÆFEwŸ & @ 3Œ-3ðR†ÃØŠ2¶('Ç—’[Ì€ÀØ@õÐ%ÆVޱQÑÃÃ'†9B˜Æ6p†c+ÇØVWW‡ÊÆ… 06aŠ?IŒ­c£¢Güä¦G@5ÀØjŒê÷„±•`lªè¡’¹GGGsDŒK @`Ô0¶‘†c+Áض··766Fš‚Ü6 ,Bc[„VE×blƒ›*zhMß+J+n€RÀØR‘-¼_ŒmpcÓêšÖØ Ï¦@…ÀØ Dîi`lÛÞ]Ó›ÞcËxƃ Ÿ06Ÿq3ÏcÖØtâ»v‰šÃH€ 0ÛX"Ý»OŒm@c{üøñÊÊÊH3Û† [6ÿ0¶MÏCuÎÿ$â @ Œ-ë¢Fz÷Ý÷^ý;ß½|™? ©ÀžèÝÝ]"ZT20@(ŸÆV~Œ’ÌðÖ­[¿Ü¸ó·¿ÿƒ? ©Àž0m5˜L&TôH’Ót @ j[Õá=ûæx*:ÈSÑÍÍÍ­­­‘æ· @›žç¦[~cÓÒšبèáùsÃÜ! Fc ý°clùmmmmظ3: 8%€±9 œuÚ[fcÓæPmµ†ö€ 0VÛH#±e6¶åååét:Òlã¶!@ÀLc3#üÿ¾þúë/¿ü2r§ ºÃØr›Ž7Ð! ÂH—€ 0Ûs Öõë×»ïþäæÍ›ï¼óN÷ÿðòK?é5üôÓOu¥ºj¾ôÑGm+uÒ4™ýIÓIï«wqŠdÄØ²=R$0}BŒíc“~]ºtéÎ;mfœjl:wH—íìì4—}óÍ7jتžþÒ“°ö'³¾˜'1¶lƶ½½½±±‘'¬Œ@µÀØ.66­–i LNÖ$Á©Æ6ëdß~û­Z}òÉ'j‚±¥Ð£û|¸óH*ÜýeAEZur_€2ÀØ.6¶FÑÚ³SMr¦7ØzÁÓÃÐæÙ(ÆV ]¥˜Ò¬±iuMkl™?Õ @õÀØæ2¶Æºšg£³ÆvÖ“ÍÖóÎ76=Ní½Ç–aïOE3=êûÉAŠÆ6¯±i ­y6:klzkMÿ¥ï½(jMËl¬±¥p£2ûì­±i¨v‰õÙf\@¨‰Æö¼Q±nP»kfÝå±fÍL+m³{Eõóæ•5}é ¶æ/í{lò¶îÞ…®Ã±ó`÷º{ïÁ<— ~Mר¨èQÓ/Jî€Àà0¶WjÕnóÔ¿Ûµ±Ù屦rǬ±I×ôóæi¦þWï–QçúIkr¥5[0¶ 5ëÖ‡ëW®^»ð².hM=T2WOEÿ„3@¨ƒÆö"Ž*¥ÖÔQk„¬» ÷ Z³ wj=¶FÔºHÚZKÓß»ÿÛVk“±é=¶¦UûÕ­å–(Ï\¼Çöäé3éšø¸36*z$Ê[º… 0ZÛÿBß¼£Ö{ë_ŠÖZWsi÷'³[Ô‰VÔÚŶæ=¶¶¡þK«q½]¥º¸÷5»í4z‚–olÿü×$jo-¿íníäädiiIu=¢G!@`´0¶‘†Þ…±íüå¯zÖ©—Ø|­±QÑc¤*n€@J[Jº÷]¾±µï¥ù2¶>ø…Øô[ÁÁgj€ àÆæ/fQfŒ±¥Ø© o¼ñ=¢¤(@€@—Æ6Ò|ÀØRÛ¯û»Ë—/4¥¸m@HIcKI·à¾1¶Æ6{JUÁ)ÀÔ @ÀŒíU´´‹SEÛ*¸úis¶A÷«©Ù¦­£úa¦ÞÇ©_ÚøÙž"¯ ԰鳭מ£ÐŽÕ-—(›06Œ-QjÑ- ¤ €±½ ªBh*&]ëV_Sù´æxƒžH5Ôºe;ÔCïÔ„6Tò³nŸÍyVêVàÚ»ò³n16uÞ; !Eà16Œ-E^Ñ' $"€±=oD­áÛUó÷ö ƒúÆØô¿Ý•°S­9¡wÎU·:îìíáñ‰âÝv‹±al©sŒþ!@ "Œí¹´ºkZ­EclÍ¡ÝÓßO56u«G¢íÉñMغõx{C4¾˜¡|®¦áÈØR¨U¢>y-âï&º‚ .ŒíÅ#Ñî[húgsbÁìSÑÞI ÝãGÏz*ª~zÆÖÒWóvm¯ù¡~’á|ªf,Œ-…´alüz… D0¶pcÓjYûltQc“™õ–Óš¶Þ††DQÇØRèšúÄØÒe,=C9ŒíÅÊVwmΧ¢MÞ4GÈ7Çß•I³klÍêZOÎôV\o7CÒÔd-…´alI“–Î!Œ™Æö¼§JíB×ùï±µIÓ<ߨäj§š™~ž¡¨G;mŒ có/>;Û«ý¡M%¶Þ«iú¡Þië~éý³ëgͳÑ9MëmºRïõ}¶s– &J)Œ cK”Zt @)`l/¨J¡´Ä%gê¾øßÔKë~5kczÚ[$kŠ«­œµ‹gÍóÐîW»34ç#QMcÃØRüB¡O@HDcK¶ôn16Œ­ôe~€ Ð!€±406Œm¤©ÏmCðIcó7ó¬16ŒÍœDt@ù`lùX5Ɔ±•L€Î'€±4C06Œm¤©ÏmCðIcó7ó¬16ŒÍœDt@ù`lùX5Ɔ±•L€x*JœBcÃØø`@€€#¬±9 VÌ©bl[Ì|¢/@HLcK ¸Ôîïß¿‰¯¶Ô˜3/@pLà¿9u³ù/‚ IEND®B`‚trusted-firmware-a-2.2/docs/resources/diagrams/sec-int-handling.png000066400000000000000000005224031355360272700255020ustar00rootroot00000000000000‰PNG  IHDR"Ò:`hsBITÛáOà pHYsÐй‹çŸ IDATxœìÝw\SWð“MÂÞS@@¢8qá½ëÞÕªUë¶­ÛÚ¾ÚZm먫î]ÅYNAÅ…ì=!ûýãÒ˜B@v¿ïÇ?Î=÷Ü{Ÿ“Ö˜<9ƒ¦T* @ ç&fD&gE'eFˆ²ŠÅ‘XàhÝ!&!HÛ¡@mr³÷OÄårÙúz<3;so;sO{ }ž¹¶C€©í ±Ê$E½»ü4öRjö‹²gÅâ¢ú ê”X\T,)(–äBrÈë¤{T½¥q«¶ÎC¼›9i5@RP”¥$J¥R¡Ý0ÅañXLn=<‹†ÑLPUo’ïß|ü{\ÚÃ ÚØ›µKÌ~Ro!@=haæ“”YAËvþ>sÝûÒ­®ƒ),ÎMÈx’’õ,%ûYf^¬°8W,²™\BˆD&ªë§4"nöþ/oÓM—kjÀ3··ô±5ólaÑÖÚÔ­ÖŸ…4TAljh`ð×鹯Êk@#4.LjË6°4j-(Ê¨ÏØ ®ð,3ò_K ŠŠó”¤Üï’f†-‡tý²Cߺˆ¡°8ïYÜ?Q±—ߥ†)”ò² XL®i&5-,;&ehø…ØHÏÚËiP[ç¡v^µ•®4“’(“3£‹%‚"1¿X"`28BQNÍo åár ˜t6—cÈÓ1naîM§3êú‰EÅùçƒ7F¾½Xö”KÏËa¨½y;ã6¦Žõðë%h—’(s Óò^$f=‰Ï|˜ÁS¶M‡¾£{~S‹Ë6å ’n>þýÉ›sr…¬‚f,¦ŽTV\[h¬Í¼Ò²£+h`aìÒÏw¡·Ó`^ÃgU?ͤPÈcƒÒ¿K KÉ~®P¼Ï"»Øv}›ò †‘@t¹&…¢\Õ¡‰¾­¹§¹W—6“tØúµþ¸WIwO-/,ÎS¯dÒپεwmeTû£m ˆ2C^ˆx{B*«×ë°õÇúïÙr@ ïŸ'L¹öpkä›@×!,&OŸg¡Ã6àp ˜ ~ôPÇaëç$K ŠÅùåO80ÔµÜå —a5yVuÒL/âoD¿»÷Oy-<â3Ÿ×$,¨ƒÎÔø;Ðì-Ûupãë:†A¯}n>úízįêãõt̺¹Íìà2Ž]/ë@£ “‹ŸÄý}ïÅ~Qºz}ï‡tù²z£$”DöâøåÐïÅÒÂR§XLžOë±–&m,MÜM  RK• “‹S2Ÿ¤f?K NÉŒ$ef¿ºÙûéù?]ËêÝ¿ i&%QÆ$Ýx´=%ëYÅ-[˜¹&e—»lÔ.ÛÀÏsjwïyÃjßD®ý}oÝ×§T54½s«IýÚ.a1tj#Lhjd Ég;ïÇìUyäå4hBŸÍL§J·føgn©o 4½më±®ö-,;Ô|‚@s&–sv^YÕô·ÓL2¹øzįwŸî-õ†É`¹ÚvjÛ²W+ëö.CÇúÿÈd°+Ÿ¤™„¢ì]¦dæ½U¯ÔÕ1ì;«½s:(4<±éOoEŸx“úH½’NcŒìñUg÷ •¼É­';¯†oVzØÝå;&½ ÿÀ(”ò 7=~wFUÓ³íì!]¾¬øª˜„ ¿®ÎU[’ÖÑcz¯vK1E ®å þ¾½(‡ÿNUãdÓù“!+¿±5cãÆåKÈx¼óü„|aªª†É`õk;eZï v¦­i4L‹hˆLô¬Ú;÷mïÜ/576¿°dœ9µ¾žDZØÊ®ÛßÀß$Ÿ¼ý¹ê°M‹€q~›kkAqh>h4º›moAQzZ^É, ­LZY·*ï’䬨W>‘+¤Ô!›¥;ª÷¶v­Çã(@=àrŒ<œ†eäÄä K&Ðå¤ð Ó=ûUò妙^&ÞÞe–úEûns¾w³ë„AL £ïëÒ_Ÿkü.=Zµ']BÆ“¤Ì§^Nƒ*ø9B,î½üq±¤€:´7k7¡Ç6UA@SÔÚ¦gJî³\a"u›æë:šÍâ•m™+HÚ}qªH" u¹fþ²5o[±4{ Û½åàø«ØÔPªÌeÌîwD‡¥WO@SD£Ñ=í>O¼Z$É'„He¢\AR[ç!¥š)ò=—gäð¨C[BÀ~3£ª-. 5G£Ñ]úå âU™¦w©aV¾¦ö¼Vø¤Ôœ˜Ãת~úæqô? ø¡‹ké·hŒõ,—ÜíjÛQUó4öÒå°56NÊ|s‚*Óí#¿Ÿx£úˆš49ªË·ª™1Ïâþy•t§T›ÛOw¥d=û·=kd¯­È1hm°ß7v–¾Ô’(ÏÜY-–?xYé4SAQÖî STså x¦+Fîmi‰½«16“;³ï×^=T5wŸîy{±lËëÛTåvN£]¬ºÕG|Ð Ø™zwu®:¼ñh»úÙôÜW7"Þ×ôéø¥½U¥fè@a0Ø£ü·qÿýÕ9O˜r)ôû^U:ÍtúÎ*‘˜O•9,î̾_ëê`ïj€FF£MêµÊÕ¶ƒªæÔí/³òß©·IΊRý®Èaêø,¯× ©ëíµPWÇ„*'fD¾I¾¯:üµjÙGë®>­Çj!>ø/¶ÁîßR²ÚFx̉´œ—_òŸ4SÄ«3/o—œ 1¦õÞ`câ\q€ÐiŒ)þk­¨C©¬øÔí/J¹ªAГªr§Ö“¸lƒúš4ƒÓÝm–ê0èɪ—¡Z’ÍÒØu“êk-hWK›n^.£¨²’(¯El­¸ýû4SAQÖùûU‡}¼'ºX·«ý@{ØLîÔÞëÙLê0!ãIpô_TY$æ¿L¸õo3žŸÚ˜v€ÚÒÁeœ.ǘ*Ç¥†ç Ó!7½Ÿ¶ßÉc¦¾®•v‚Mz¶[Âb–ì35'¦‚ÆïÓL7ÿ.‘‰¨²‰sï‰u"h‹©¾õ ßU‡7ÿN­ä÷<þ†j¤º‡ý¬ü uÍä¶m9œ*+‰2úÝ•´œ—oSB¨¶A{·IÚ‹4àéû´O••Dy'rwKÒL‚ÂŒ‡/OQe¡ë¾‚AgÖi” -]݆ۙ¶¦Ê"1?øùABHTì%UOûÚ‰ šOûAªòÓØ‹^ŸU¶w›Ìaéi#(¨HgÏYL‡*¿ˆ¿¡¥TVIšévän™\L•Û¶ì¥Z¹š¡ í8Gux/j_‘˜¯ZÇ1v²ì¢¥Ð é³1ñ0Ö³£ÊəѪߺh4ºw«1Ú‹ ÊÅå¹´èC•%2QLBPy-é„©¬øáË“Ô1Fëë=¹B-jiéådéM•‹ŠóïGí“É%%§,:Òi í…MМ-»Re%Qò 3¨²y[}ž¥ö ¸9P•ÕgB”B'„¼L¼¥ïÔ¦…Ÿ…‘}]MU¿‘4® ë²då7·´rèBãºX94Ž÷C"fºªGß ævõͽÝÚLýxùß×d2ù‡/h¨z{OP•£Þ]U•mL<´4#?o¸9`Ú>@ÃådÓƒÍҥʱ©aJ¢ÔØŒNyª–…jïÔ§‚ƒ&ï÷‡^¿‰Óvµ .>yä¸y=úNØ{àÔýˆìœ<¡°èÕëw‡=~¾wÇÁ7‚‚µ#@5¹X·Óç–ìó’ͧªGš êšµq›²•öVë?¨$ƒmcîC•Eb~® Ic3ºTVü"þuÀaq]í:ÖS€Ð¤Édò•«¿×v5•˜”ڽϸóJþ‚xz´5<`ܘÁ;¶e0„˜—±Cgü¼mŸVè&:îåЃ*+•ï‹0ÕwÔN@Ðl˜8–ªa1¹¦†-µ T–•ÉûqJÖ3mèi9/å uàfÛ‰õïÊáÕF¥`/Þ ºý@Û±ÔÈÂ¥SÓ2 !mZ…ß?qùì‰?NÞz÷LFbØWëëêr•J¥B¡Ðv¤Õ¤J3©ã² ê?hVØLƒÎR¯±0v¥ÑèÚŠ*ÃÊô}š)5'FczJöûü“½¹{Í@ßÞ]ìm !˾øV.o¬«%%§]¸DÑÑá\<ûgG_oõ³¦&FëW|nãÚEËÏÒRŒ5egÖšþßÏs :“Íäi+h>tØúê‡Fú-´ T’‘þûµ¼…¢lmèÉYѪ[ÓVu4‰týê…„§Q1Õv8ÕôøÉsªÐ©ƒ·£ƒÆ6n®ÎÖ,¢Ñhõ@mb3uÌ K>ÒÑÍÎÔËÖÄK»!@3aeäjaè¢:ÔÁxj€£–‰ÛгòK–}¥šÒLP EÓ&vqv „¬ÝøsAAa5n¢T*/\ š8m‰CëžCws»ŽÝûŒÿñçÝù|Íÿ+B„Â"jŸ»½NQ5‘Q1³æ­jíÕgâÙ¶ÓП|þ8òy%P%”š—ϯl/þ¼6zü|;çnl7+‡.ý‡Lÿsß ©TVÁU¡á‘óopk oî­oîíÝqȪu›32K§Š¯^»KõwÊÌåï³gÿIªÁÚ?«×«^¨ýOB ÅѺæ{и.{öŸ¬y ±1q¦ J¢LΉÎ.ˆ×j8Ð\ä¦fòߪ9H34xêé`‘Dówsf‘˜O•Ø,.f‚Z!,,d2×.š2syzFÖ÷›wþï+Íyò¤¤fL˜ºø~H„ª&;'/ûÁ£à~ܲ{çoß|4ª¢½N32³%éš [¶üºWµ°qTô˨藇ÿûÄŽaC>¼£bûv%›m…G€ÍÒ53r¦ÓYlÛHÏZc¦j˜—¿ÕP;„Â"BÈ„±C¿ýqÇ‹˜·?oÛ7wöDû6•¼2vô j…õZ‘““¿zý*Çäåéjiaöêõ;÷VÕî4F\Žþ‡Ô™ŒÜ„‚…(ƒìüw„( !å`éYш¢X*ä°ð]jGa¡ˆÂ`0~øæóacæ‹¿\ûÓÑ¿~©Ìµ2™|Ì„TŽÉÍÕùâÙ?JÖ“ËåË¿üî×ßB>[öU;ÎÛj¼ÉCg!ž­OÙîæZ’Šx0dF^>?!1åìùÆ\q$4íÀŸ?vê>J*•½|Û¶ÓY3Æ-^0]uà Èåòq“?£4¿n^·`ÞUnè_-û~ó®5¶¼MøaË®¯7,¥ê ŸɟQ9&c#ÃÃû· 诺áýˆUë6Ÿ8¼­sL„®ß}ýÒÆÚâÈ_ü{v®a ‘b3¹4Bã²õŠ$ÚŽ7zrÖ³Q®T&a31cj‡°°d1¦!ƒz÷ííG9vòBhxde®=rüü£'Ï!æ¦!·OªrL„ƒ±õ§µKÎ$„Èdò/ÖüPÁ} ètR=%Ô¡½×œY¨òí»a• ÆÇÛýâÙ=&ÆF„©T¶óÏ£î>†Î8áFÅ;è:{%$ô1!dݪ…‹LWÏ ÑéôU+çu÷ë@Ù½÷¸jNß™sÿPQ±Ù¬Û'ÕsL„î~îÝRåY®ß¼?rÜ<'÷Þ;v‘H¤¯¢†\è­[µ°ìY6mò(BHfVNvNUù˶}Tá³O§UfÀTmùbù\o/·²õÕè4RôÿüCÍ‚Ÿ¿׈ûÁ?CÊ»ðyLe·Ô „$§$ÿôóO½ú÷rtu4¶2nÛ±í¨q£vþ¹³¸¸¸V»Ú‡oP·Úz»Ïš1–yâô%U½Æu¬³²s©¡Lt:}ohnf2aìPªüÏ{Ûèèp4.½diQ²Ôqrrzå»ÐÂÎzß®ïc_}¾l5²‰’˜”:ñ·¶ýËn]—“›öð)!d@¿,Sã=[·jI^¿‰S¿„òùò9•­† ôÍŸ^¶¾](K*•~ýÝ×^¾^ë7­ž‘‘Q\\üúÍë«×®.]¹Ô£ÇÅ+µ#Ô&Í_ jÑ×–;y¡°PôÅšG íÇåêB¨I¥<{þšñÔÂκ‚…¥ÝÝ\¨Bô³WUŠÄĤ$IT$ªòϧö¶?üïók?uqóÖ=/bÞBââ“»÷áÌnjn **ª§Î^¡q]*¾m\|r·®¾Ïž¿V(„K 3 óúÛöËÜÌD__·l}5ºP'ñ@ûxúÇææåÎÈvtp¬ÉÍ‹DE£ÆŽº{ÿ.!„Ãáô ðmçËãñÞÆ¾=uöT^^^jZêÄ©o\¾Ñ¹Sé¹ÛMXXHȱÇ߾yýæÕ+±XlmmÓÎ×wȈf2ñ ýÃúuïöôÉ“6óëÑãüÕÊ^u÷a„{›6U}hQaáуÿØökRb"ƒÁH`ʼnráb¨sV–æ«V~ºvãωI©[;°jå#j½¨ *›¦êˆ›«S #¬Õè4FóçÍ÷p÷¨£›su¸m<îÞ¿ÛǿϮßwÙÙÚ©NmZ¿i줱÷‚ïÉd²5Öܸr£ŽbhPãã×~ñù•‹ÿÈùöÍë·o^Ÿ:~¬µ«Û·[6÷êÝG[áAY¢¢¢=»vÞ»uûAHp±H¤íp¤™ >,[ôñ®=Ç’’Ó¾ûiÇœYLMŒ4¢Q-ÞTq>HuV¡ÐÎâÓt:}â¸a}½}ýFÂø„ä“g.OŸ2úߨTaÌÈ[7¯­øVf¦Æê—Ðé bk5ºP FÛüýæÞþ½‡ Rê8CCÃ}»÷µòhE ~,(èh)L€z’œ”4¤_ßô´’UbÝÛ´qrqa²Xɉ‰‘Ëåòׯ^Ž6ì«o¿ûtÑ"í†ÚXL9ÓÌÜ¢¼³Ž5DvVÖ¦µøB¥ ÍõËÕùþ›•“g,+((ܲuÏ·›Vèkͤš/ö..©‚»ÅÆ%RÕZKZáâì0wÖÄŸ~ù“òìùkU½¹™ Uˆ}—`gkU™[©25oÞÆW#’Zßë­](‹N§YU©êÅó˜7ÅÅbÎï£Zm*9%Ï/04Ô¯ÌÓU¯¿¶'W£ U¢T*ù|>!„N§ÛØØh;€º•’œüÏåË„ŽŽÎÑ3g[8üg ‰‰ÉŠU«GŒsîôéù‹k)FÐÀÄÄdó¶íªÃc‡KÄb-ÆÓ(4ˆ:ÐÐéôŸ\M ‹6ÿ²Gã¤9K ³vmÛB ÅŸûNh¼On^þ±“¨ò€þ=ë,^"•ÊBBWÜF5øÈBm\••¥y[owêÛþø«2ϲ±¶pws¦Ê•¼„ºŠ*dddklðîßa_UU.TIXxX>?ŸÒÖ»-WGóKMFTd$Uhß¡C©“J«Ö®+W¯©ùz²Ú…4ÔŸn]}ÇŽDùmçÁâbÍ9àó¦R…¶ì„e|ÿÓ®‚‚Bênm½Üê(T¥R9ï³u=úNØòë^¹\®±MNnþ¡£ç¨rÿ¾ÝÔO-ü·_÷[JjFež8oö$ªðÓ/¦¦ej I"‘ª×¨ÒL‘Q/22KgšÎœ»úýæ]•y´FÕè@%Å'ÄOž1™*oZ¿I»ÁÔUò¨Úë](•ÊK3&Nðnåbcdئ¥ãGC‡Ú¿_*•V|aDxøçKwõñq´´p´´èÙ©ã7ë×geþçGÐõëæºp VzÒLP¯~øßl6«°Ptäx ÆÓ&¢ÆÑ¤¥gvë3.>áýd4¹\þåÚŸ¨µ Æÿû¼î2ýwî…ïûë”B¡Xñåw¾~#ÏžÿG$*Voúxà°™ ‰)„6î.Cýg?ˆi“Gùx»B„¢®½>ºQêþž̚·J=5{æ8gBHAAa§î£BÃ#ÕÛ'$¦ 9kù—ߪWòxÜí½!2™üóÕ?H¥2ª^&“ÿ²}ÿø)‹ÙlVµ_jt < …";;;êYÔ¥«—f|2ÃË×+5-•F£mݼµ_Ÿ~ÚŽ ÎyûøP…ÇI U½<=-mX@ÿ'\ LKM•J¥Y™™wn-[¸ O×.I‰š'1ðùü™“' êí¿ÿÏ?ß¾y]( …1ÏŸÿºeswßöŸ:U»k¼æææÊåòÏæÌ™7sæ“GÄÅÅ„/¯ö¬Íõª¥£Ý’…3üywy §±X̳Çÿðó›‘™ýìùkOßAݺúvhï•”œv/8B•uúåÇ5ݺúj¼C­ðïÙyÿî>™¿Z&“?Š3ažÏÇ»µ_Pð66!ö]É› ‘‘ÁÑ¿°Xÿù«Äf³ÎžØÑ­÷¸´ô̤ä4ÿ€É}ü»vhïÙÂÎúõ›øÇ‘ÏîÞHéãßeò„Ô%<÷̱ß{öŸÈ礤ftï3¾£¯W§Žm™ FxDÔÃGQb±„2kÆ8*ûCY¾dÖÄiK!üý ìIçŽm•Jr/øabRª‘‘Á±¿¶¡ù爪F ÑÙºm«©©æý4Ö­^§ËÓ0ýz®^»:fÂõšþ}û¯ùbMçNkë ™µ‡—×óèh‰X<~äÈǵv­ìÌŒ´ÔÔA½ýS’“ !îmÚôéàè䔜˜xçVPäãÇ/cbÆ r+ä®Þ6YÊÉÎÚ¯ßÛ7%[yxyuìÜ™ÇÓ}–››»ÏŸÃGf0µÕǼœÜÿmØpòØQBˆ»‡‡……åÛ7¯ÝÜÝkÒ hŒf‚ú¶úóO÷ýu*;'¯¼N-[„ß?;~Ê¢ÐðÈÂBѵ÷¯Ý¸¯:kdd°cÛ¦ c‡Öuœ3¦ŽéÜÑgåêï/]¹E ‹ÊŽèiïãqhßÕ‚ÙêZ:Ú…ß?;iúÒ{Áårùõ›÷¯ß¼¯ÞÀ·§µÕvßôör ½szìäÏž=-—ËCÃ#ÕÇ4éèp6®]äíéª~ɘ‘ûøw ºý€òæm¼j­(×ÖN§ŽlwmíTíîW¯ и>v¸¼S+—®¬Å4SYL&33+S¡PÐé\MFûm÷Ÿ={H¥Ò7¯_ùwî§:|ñpã7ƒn^ œ4mÒùÓçñ»4½ûö»öÃ7ßœŒÈ*,Òø§¼ÉtPf-hçÓŽ*<ñ\»‘h…—;qê´»îÚ€š)V,-™?¿X$¢ädeWþnºÿ®s—•EZ¹Ößt¹ T¯Ðxam&ÐŽUÈήÂ7€&†N§7®¯oßnÝ I çΞ™0y !„”D:räÿ~ü©âû˜þ;~GuÖ †•T¯Ðx!Íu¢HTÄãòÊ;U²‰­m}EÐ@µtvž>kÖo[!„¼|þ‚ª45/Y ;þÝ;ÛʾUš˜•djÞÅVyû#jv[íª^/ ñjÙMhbžÇ<÷jïªñ¬B¡Ø²u UîÛ§o=ÆÐ@¹y´¡ ªõ‰TË6½Š‰Wò>­]ݨBjJŠ@ ¨Ì%\.—*üJ>¥òª× h¼f€Z¦P(¦<=5-µÿþ›¾ÝÄçÿç{ _À_´lÑí»· !l6{ά9Ú‰ ¾H¥Ò‡¡šÓî*ïÞÆRó×í¶°´ôðò¢.ß½ãJ>ËÊÚZ•iúóß+y UÈÊÌÔØ !.®’O/«z½€Æ “æš©­Û¶V¼ Æê/VèTõÂáC‡ûuñ[·zÝ´YÓ$Éw?~·uÛÖþýú;;9s¹Ü7oßܺsKµÓßþèìä\ÃŽ4dJ¥rÅ¢EÇÚð¿ÿÍ]°Á`”m“››{êØQªÜKmŒçìyŸ.]0Ÿ²åûï??ÁÚÆ¦2Oœ1{öê•+!¿ý²uòôª,’zHR©”ÍfS‡ªÏ¢¢²23Í-,Ô_v¸âK?[ª1ÍTñ…ö~]üF |;xá’…aáa¢bQàÅÀRÍôtõ~þéç©“¦V5l€Æ%äþ½£ÿ"„lXµêäÑ£+V­î óï<5BÈÃÐÐÕ+W$%&B\ÝÜ R7iÒÞ];ŸEE …ƒzûïÚ ³ŸŸú͆…>pàçß~SÏ^M™1ãÏ;âbc…‚€ž=ö9Ú¡S'ÕÙ¤ÄÄ‹>srvþnËÏT —Çóiß>òñc™LöÕš5¿üñ‹Å"„Èd²=;vl\³šÅfKÄâj¿Õë4RH3@ðlãt5(4<ôÄ©=LMKÍÏÏo騲u«Ö};Θ:ÃÌÌLÛ1Ô¹n=znßµké‚2™ìytôÌIuõô<½½­¬­|~Ü»wñïÞQ- w8@¥x(l6û¯cÇ÷í“‘žž’œ?Au—Ç;pôذþýAZjêÐ~}Ûùú¶ëÐÉd>Žˆxòè‘D,º~}òôžÞÞÔ%ó-ž3c:!äÄÑ#ÃÃ|;tT*•¡!ÁÉII†††»ÿ:8~äˆj¿ÕëÅý±u«I…crW¬^¥_æÇ’Нzt߀:]ó&]6¶¶ÿ\»uãÆÙ“'C„d¤§Óh4 KËŽ:;¶ÿÀ4­ìU­Z»Þ <{6ðï³#"²³²¸\nKgç~Θ=»TN‡Åbÿûï?wî¸s3(:ê©T"qnÕj섉“¦MãéêBôôô…‚š¼Õë4:´Ïw–¬¹ØÂÌmá_µ Ô³Go¯Ÿ ~¿¦#cüŨ{ZŒš‰m—†ä$¨{wXÙÁ}šã€Êøé7!JBH Ζm 9W P%H3A3òèÉ3×ÅÊ¡‹B¡Ðv,Õ×4zMÒLPMüFÒ¸.üã0©¼ Ÿ=]¥'fdf¯ß´ÕÓwž™—‰µo×^ý¶ãX,©ü/Þ$„ ÒG}Îsõ:Rí^P EÛÿ8èèÚ‹Æuaê¹VéÚZìEµ;’˜”ºñ›mº¶hÑIǨ£k¯É3–Ý~P¥Ž@ƒ%À¡q¸{ÿáØI 3³r¨ÃB" ÜðôùÓ»ìl+µ%AàÅ„áCúÕa **ý¶óÐÍ[!÷‚#D¢âêÝD»½Ëå[~Ý»î«_$©ª2!1%!1åè‰ÀIã‡ïÙñ-—«£•Ø@»f‚šúäãñæ¦åm騢æxý&nøGsøüBHï^]ô/.=ó2öqäóácæÜ:Áãq+¾IbRjdTŒŽ§oï®ÔCG2³r¾XócMî Ý^ˆÅ’ SŸ»pÂf³F ðòtÍËãG<޾s/œrôD ƒA?¸wó‡îMÒLPS‹æO÷ôh]§˜¿x•cÚ´~ÉÚ/Pû\~¾lÎØÉ /Þ|òôÅ–_÷®[µ°â›\¸Déß·[y ©z舾¾ÞÜÙU‡î;QÕõ•´Û‹­¿í§rLƒôÚ»ó;k+ Õ©¿¯Mýxya¡èÐÑs³gŽïÙ½cÅ ÒLÐÐ…„>¾y+„â×¥ýš/æS9&B›ÍÚ¿û—6}óòù?oÛ·ô³õôxÜ'ð’–gÌBLMŒvnÿZuxàЙ*­-E´Ý‹e‹f=Œˆ62ÒßýûÿÔW†"„ŒðÅò¹ë7m%„ìÞ{i&€fK€CCwüÔEª0sÚG¥R&ÆF#†õ#„äç ®Ý¼WÁMá­;¡„!ƒüë*к§õ^°XÌã‡~ÝõÛ7¥þCP~:•*܉¨ß¸ A@š º‹—ƒ!4mèàÞeÏÒ‡*P³ÉÊóÏ{R©¬S‡¶êó¼†Ð &“Á`04ž262473!„¤¦e(•Êú ´i&hÐòù‚¸ødBH{+Kó² úö FÖD>}QÁ}JvgÚ·n¬' ¿Ôsåå¡ iCš ´W¯ã¨‚ƒ½­Æzz<cCBÈ«7qå-§-“É/]¹M>¤á&h>¨á÷B*•¥¥gBl¬-TKh@ó44hIÉiTÁÔÔ¨¼6¦¦Æ„‘¨8;'Ocƒàòòùö¶u½‘\jø½¸üP*•BºuõÕv, ØijjóÖ=f¦ÆO}µn‰®.·&7 ©‚©‰æGBÌL_•4.²07-Û@5׬â!6uÚ‘škø½øëðYª0|¨6·ómAš jJ•\(ëË•ójœf*¢ Žf*9UP ,{V©T^ºI*1׬N;RC ¿#Ÿ:zŽÒÆÝeÔðþuôhÈ0i4jyoBHyë.BärE©Æê^¾z÷66A__·g÷Nuaýhà½P*•Ë¿ø–Ú]îë K±8@ó„ÑLPSÑ—ënµ ==UÈÉÉ/¯MοK2éëë–=xé!dP@/6›Uñ³ê´#5ÔÀ{qþâÛwÃ!í}„ÐðÈï~Ú©ª—Je³æ}™Ÿ/ „¬\öIÙÑ4—nB†iˆ»³U^CëEq±xô„ù'N_"„8µltõ°µ…¶ƒ€©í ÑÛ¼u™©q Ö¯þÌÀ@¯ªŽÞ¿»_ª¼ýçõBçäæ¯Ýøóýˆ¡ƒú‹Åüý’Ò¹cÛÅ f”º\¡P\¸D>´² šêu¤ò½ÈÌÊ9xäoõ³2™œ uóÖ=ªJg‡‘Ãú×s/*Ù‘‚‚ÂcçÞºJ¡Óé3¦Ž9x/(„r¹¼Ô%˗̲¶B  Aš jê¯Ãg+n°bélyŠ/tt°S%hì.œýsÌ„ié™W¯Ý½zí®ªYG_ï³'vp8ìR—?zò,-=ÓÌÔ¸K'ŸJu£º©|/RÓ2W®ú¾l¥R©^?bX?Uš©ÞzñÁ ©Ž¬ß´•Ê1B ÅúM[+¸dÆÔ1H34+H3Aãеs»§/þ¾óð™sWãâ“X,–[k§©“FÍž9ŽÍf•mOíÎ6dPoƒQïÁÖš†Ö Qq±¶C€† i&¨¦ˆsõ|¡¹™ÉƵ‹6®]T™Æ%KUb®Yõâ©ÆU>ÞîJÑÛ*]R×½¨ê…;·½sû×Õ{4yXš ø„ä¨è—l6+ omÇR}M£Ð| ÍMµlvÿ®zzã ë#hxfø00˜´²õ++P$Tÿ)+üšBgÐt è‰ÒŒDiø5áÔÕæÝ†|ð,6M×AQ*•EuytpQ‹ÖœÅ¿Zë1ªO5(Ê;5q¥y]?2¤™>ÌÇÿÃc”*#öiqÄ a+îð¹ÆŽî:,M#?ñsö£ ᑲÝ;ñL,?ðO³g7ž*¥’äÉ#® Ïþž“ôZ|êל™,jdÅŠ妙 ™ÃÚLõÇ«oÍÁË~·iåÃeqh„SÆÌ<=ºB®|û´¸Jw£Ñˆ £ÏxÃñËÌ!n %ÅÊ:‰[MQ¼®F3Ô+[gv©&‹fhÎ,JDÂjòèÊ#„ȤʼL™¥=‹ª\Ú?N$T,ÞfãÞ‘«Þø÷iÑÁECgmBÕü47%6ªø§ËŽzFŒ‹‚;géñc ¦{'Þè¦l’‰×…{ÖgPåä7’y]c©òôµ]‡è«î3v‰Y_µå™T7×5 ß8Îä¦ËL­™þöcH£¹Lyó?8PŸ%·qf÷kØ)@¯l_ŠƒNòß=+.äËíÝ8m{èömHÃïe ÒLµïíÓâÍóR!Ãç˜ ži¬ípjMµûµ|`<õµpõ~»:‹ ËL’¦'H!.Þ:Õ»ƒjO¿úy—œ4ÙñÍÙ‚„ÔaF¢4#‘ŸôZ¼b§-F!ÝÜ–%*Tóå &M5¿O‡÷á‡æ¤Éþ/7:¸ˆ:LOß’-•({Ž2س.CU÷¬8îY±D¤è>âý2UJ%¹u’æ·¹LÉâиzô˜pQL¸èE¸è“o,Yìª-ui&­‘I•‘w ÿþ#G© }ÆÚº”èTI¯Bô5Y|û²4I±bÂr3ß~zJ¹}šy^lTñëÇ"W_.!īϫ›ýý@Ááﲬ[²Jí4W±ßW¤I%Ê ËÍÚù늄ŠCßeÅF_9÷øVaF¼dâJsŸžº…ùÁÿeÆ¿_>ç7TŸÎ(ÉEÝ+<¹5›Ã¥OYeÞy€AËL’îYŸu¯ðÞßllÐp ÍÕDÍ• ÑÉÚƒ-ÊNQ™ß-V¡ úéÍþÚ²£k2“¤ëÇ%BÚtæ-Új]¶Az¼dãÄ$BˆßPýik4,ëûê‘è—…©„‰+Í{þðUPmOnÎï[ªrâJó#«ùWïìo9oægÉdR¥)cÂr³^cªœ.Q*HNºôîß‚ëGò !§Ój0²‡N'ËwØ:ºs¨ÃaŸ˜<½W˜òVòüA•fª ,ßaÓ¢‡bhF¦®¶Ø8!±¨@‘—.[±ËÖÆ‰M14cLùÒâ›iI¹é²´8)•t“+Oü’M™¶ÆÜ·oÉd:‹¬¹ßZ­›xõP^ÏÑL44H3A(ääÖì%ÛljòŦÙ2·cñôèEBEÒ+±RIʾ†¯‰JJI|%¦ ª¯…PweÖMRÖ`¹íŒ$ivª”*suéÔÝ*ó^ú,¸èËá „¥R)ÌWÈe%Aôeà?¦FéæSÔßLh4Òʇ›òV’Ÿ%«Ém)SŒ¨ÅÊe`ÂäÊÍ0¢rL»Vl®]$Täeɨ4SÄ anº¬EkNû>ÿY°ÉÔšéÚ^'æ¡(;UfåÀªy„PsH3AM½Š=½[èÓKWÛ4>4qôÐyVT/çgËŒÌKÿ}|õ¸dÏ©œ4YvªÔ̦ô÷¨¤×bB“E«öD¨¤v½uç~kU‹7üäËü,Y~–<ê^áýó‚ã[²Ÿ…ÍûÁêƒs¤e©¼OOÝ>ã [·¯ñ€#zéGë3!yµ°µœÆ› råëEB…ê¡o"E„·ܲ983[y(ÊJ–"ÍÐ@ Í5¢oÄ(È—ŸÞ–ãÑ•‡EX«¡¥çEX!$ñ•¸TšI© ¯‹!.],R¼z$Ò”f’Bì\ؘ0Ðè0Y43–™ Ë¥­Nïq†ßÍL~ö (è?`ŠQŪ^ ¹ò«II‰RC3FÍsL1˜4R³A[ݼœ7®’7´JåԮͿ~4_cûZÉ‚@­À>ÀP#}Æ2˜´ìTéÍãš?ýCÅÛ”ì*E%ŒÔ¥ÅK„ùrž½}]BÈ«ˆÒóæ$ÅJjk*‡6ÕÜšªÞÐñNP!c æ !wÏ *A5ß”rïœ #QZWÁi’BìZ±; ÐÓøÇ¦üõ ža4Ôˆž£ÇHƒÛ§ùWäwl`hVåŽ òä·Oó£îe¥Hr¥‰«Mg®ÿC‹f@¼}Z¼y^ !dûm'‡–™$=¿+÷Õ#‘0_Þc¤Áä/ÌU ~ jÉáÒó³d×ò£îægÊŒ-™ž~¼ÓŒ LJ‚ÌN‘^=”ÿ"¬¨¨@a׊íÚž0ňÃÕœ‘J”o £î%¾çgɘ,š•#»ó½ž£ T{!Uƒc›’•J’þ]eI…Z©¥§Ž“§ÎƒK/‰J­Û’+V*)a¦Ú}m+ÓŒDiÐIþóТüLWîì­3`ŠQKOà *f׊CÉI•J%ÊÊmÛS·¥§Nܳ⳿ç|úCé9}Ô]òºŒT_ ̘„{WŽÆ@åõcÑÏ R?جu;î²?l¨r|ŒøÆÑü”XIvŠ”g@·wåt ïÛWößOCÇ·dß>ÍWÒèÄЄihΰwåødXj+˜R9\º¾1ÃÁãÙ×±¿Æ_4F äí ¤™ FŠ‹ƒg‡\ˆEŠs;r¦¯«Úw€ð„G~È‹Þ/«›/I—Ü>-:ËxÐŒr·Lòå9i²íKÓT×–ñ¦yê IDATz*È•¿z':°)³HXÒ 3It‚ÿ,¤hå.[}cFØ•‚Ã?dIÅ%ß¾ÞF¿,~þ hÅ.ÛR€ä2åƒË—öååe¼_ E*VÆ=+Ž{VüäNáÂÍÖ,N5?3é3L­™9i²ÄrÒLN^:ŽBˆ Gž‘ ±r|ßMÕ(Mi¦º{mËsû4ÿô¶™´ä%-È“GÞ)|z¯pÀc&&Tü«¼u¾ùÙ2BOŸ^¥ï`4½Àd˧©Oï¾,vñùÏØF]#F‘PQÈ/½t¹¸¨F‰':FQÔWêØÅ['ìJÁ›'Å ¹²&i}€&F'¥Þ@¨”é šú°bÆ¿?6Þ–sãØûÑèülytvQtpÑãùs¿µ2¶,ý5Ŧé2¨ÛòsdùÙ²„ñ½s‚.ƒô§®6§æØ–j¬T*‹ Ù©ÒìTé£ áÅ=¹³6Y:y6ôQØPJƒz{†i&¨q‘ÂÀ”ÑgœÑÕƒy.ôc¨žóAÁ‡¾Í¢Êž~¼V>\›Uüô^¡Lª Ü[T øh‘©ÆkÓâ${ÖfˆE {7NK¼ ™£Ç>²äß:Í'JâÓS×Þ“*}xM(•(3“¤÷æY¶`ÜšÍdÑ:Ô·´g¥ÆIÝ*$>Füðš°ë}õ[= *<ü]!„«G÷î®ëàÎÑáѓߊî ¯"DwÏ úޝò6ä*ŽmtrÒ„¹²B¾œz{%„(äÍ!¤¥ÇÖ‰ÍÖ¡IŠ•/#DÿM3‰ !.]½²^[îœß’M•.è$_×1ÿ'+g¯’I?ÎIQ*ɽ¿ù 1³a}ö‹µ¥}IÊݧ‡îžõ„ üRï•úéÝý›ïâÍ ˜jÄÓS}£Òï5Úð‡YÉEBÅ£ù½FT{¸cΣ›BBHâk‰{Ç’O])±’B‚ÚŠŽÎ 9¸é¼‰½z$òÿè}>‹šggïÊ)µòQ]¿¶ee$JOmÍ&ÔÀŠ…¦ý&¾ÿþ,ȑۜõävaU^€&+?Kvç¬@&UÆFšnlïÆ¡ÑHvª4pWî‹°" œ^R#?5}RÿBü覰C¿÷%.¼·‘Å!— Z·çzúñŠ ׿à[Ú³j²–“›F#…|ù½ó‚# ¤b¥T¢Ô5¨«„“®!cÄ\““[³ÿþ=G#0ÕHߘ¡T’œTiÐI~›.<Ï®ÞÊ bÁBH‘–›Q5- -=tºÑ¿Xà?Æ âËétbÝ’=n©!$è$ÿö~©ì¹:c ¦ÿG†¾ýô¶/IK|%Þ·!sãñ:ºX¸ iªÏ·h˜f‚).RBxzôásLŽþ˜÷¬øá5¡úÏæå¹´/i9b®‰*BqöÒùø+Ë_§Bwåzúñʾ­äeÈFÌ3é>¢Ü7©RY$BHKO6yÏC‹ bïÊY¸ÅšúAžâÛOïž܌Dir¬¸Ô¼ :,ÿCCîÌÒžÕuˆþÍü¼LYÒkqËJ ùÑHuaÒk±*Íô걈bç¡[­Ú•¤™TcreJ¬„¨­î¤RׯmY×çSOì;Á¨ÿ¤ÿ|I60eÌýÎjù€¸BAéi;Ë“[…ó»Å–­çêÑ·üÓ²2-Ç-5óÿÈpÁë›2žÞ-|z·Î 1YDR\2ì|ÌB“Öíªó ¿­3»Ë`ý— ÎíÈõ饫Êz÷atœ_/ÿsmUC§“ik, ò3Ûsªñ Љ%Ó·Ÿ^ÄuáѳÎíÈ‹”}ÆŽ)óËd-ê=ÎP+»z0ÿƱüÇò Lb‘’šØ[T @š  ª”J’øZLQ}ðPápéU£íÛW/è$?7]&*xúeŽôŸ|cùÕ¤¤ülYðAß žÐiåíüׂ¡¾Bº×·uaBÎþž£¾Fb‘‚Þ¢gÄè9ZC:í#—š·ŸôFœú®ôl„c f©tF)~CõÕsLUF¦ïCõ!„F#nBˆRAø9¥W)/}ÞòßÅÔ—mª*Õp$õUÀ©…™Zµ/¹?5¶¼¨@‘ü¶¤Mz‚T*Q’2 3ÕÃk[Š\¦Œ¸!$„p¸ôÓʹ?@@“ PhþSÉ–÷ŽÜÇìÇ.1söÖÑ3¤+ÄÆ‰Ýyþú#-jò¥kØ'&L-;UzçÌûu4õŒ«öÛùôÔ52cêèÒ];po³ñª¯kPåíJ™±Î¢ßD#K{–\FÝ9Ææuû«FF~jºr—­ßPý­þÏÞ}Ç7U~?7I›†îA¡-{Zö^"¸A†Èܸá²AD”% "|QA¦¢ ‚Šˆ‚" "d‹ìÙAK÷JWîï`H¥#4mòy¿òGzïͽç&Üœœç:ë—•ñ¾âwc E¹1µ•óÇÒÍÅ/¡­ ùÎì¦(Òì^÷óÇ"rê@ZÞÔíºycše޹|yúÝøï“íXÐÔdSø¹ŒðóÿìM5/‰-AšÉÕM ©­¿r&ÝÒÜd’³‡ÒDÄR×P«‘›V§dg©ÿîO«ZO/V9©\ÕL¥ÿÜ^9aN,ÖkáæéSÒï®@4pL€¥êÛ&[<4 ð.FO·öïWI—«iÂå•uƒóÌ@ס‡g‡9F[’ïn»>ëÓ5¿ô±ÎEé7Ü?o‹·|÷s«O\^%ß哾ªšïòÚMÜj7¡s0`­ôظ$öׯâ=}µûz~‚Ë\"/eŠˆ¢ßB]ÔoaØ»)éê™ôô4Ó­¦÷P®Ùëíeoî°™ú- Íïu‘_¿Œ‰¸‘vq3äó¶{íFOŠUrYþ·*ß NñÞ­\Ý úïêvcŸê-&ÿ޼”ù킘‰]ýÐ…ÙƒÃV½}ø-‡,U]ÅcžK.êJ¦y?ç3ÌäÕýoÒ(W7¥fC½ˆœ=j4/¹z6CDܽµæŸ ,Jÿ¹¼qÄÀªL8 @ùÐõYŸm+¨&Y7?fRÿËÛÖ$X&ç-×p´Òn-~•ø€òAç¢ û0¨ï0m\TÖ7]ŸÐóâW³¢¯‡Ý~~€¬L5&"ëðŸ)s†„Ÿ=lT4òèË~·}”Y@ðߺhÚ8*{½½ ì`Ðl) ÄåÁ'¼7ÿ÷¶ä‹ÿøÔh 7¸kòÎfoø/÷”{˲®ßXUÁÓÎÉ‹ Ç ÏÌPÝÜ5]ŸõmßÍÓ;àFH§ÿ.Ѥà–.àWϤ×ÕŸ?f‘º9;×oaøyy\blvld–îVý¿Kÿ¹µÔˆ%Çs½@¹¡ÑÈCOùÜÛÏ{ÿ–äík®œNß±>qç†ÄGùöxÑOÉóCá¡í)ƒÛçžßÀË_;`T@f…Ðjú¯f<ïþ8 »¼½ ì Íëúœï®Ÿ’c²7|;ü£ }…|."|+Ýø‡vËTHôÙnß@{¦™TU¾˜™¡VðÔŒZlî‹ds•k¸ê šô4SØÙ›ÕLõ[äH3Õläf®»pÂèj0$ÆdKžþßbçÖó¿ÁÒ±QT¿Pθè•=<Ûw÷üwÚwÇ\9nž²¶÷ÿån¾æâª˜ë¬øèüƒuµ»u|ÔËE_„ñ,×Ão\-¸3oàèJùíei&ؘ[Mï!þŸO‹úgoê™Ãinòyk¨Ý俆ÖR33Ô|GÛÛy£»výVÅ™ÞÛV®]ÎŒ¸!"­ô¸C9&Ñh¤ú]úÓ‡ÒÂÎf$ÅgG_Í‘:Ísdî]Ý” õg/7zü×i»Fhîì~é?·ÕêÝhÉtîˆÑd ”7Š"¡m [UùvAÌo«ã·¬J¸ÿqKù¶Y£»+¼:#÷”Eu=>*`õÑFuфȦÜë6sÓ¹jÎ7þ½-Ùœ•¸¯¿w³Îî¥xnî^š ôÿI?}(í“ñzxUðÔD]ÉÜùcâÅÒýƒt1ù4$òò¿ñ?ëÐöäê¡úfn–fÞû~M‘zÍóéuWë¿öL¶$K~ý¿ÍîÜs{«ój÷ˆçΉgc²gkõ G͆n­œ:và·dñôÕÚ°ò ”Ä•3éóGDtyÆç>¹~s:´=Å|©P³‘ÛîÆGg-~3Ò”­»´éâaÛ(#ìòö‚²†4î”Þÿçè”ÊX:÷ñrÕ+«gGgÕä˜Ý2ÓhÄ< A©DzƒÞ|ïÅ0cªéØÎTKW#E‘ûú{?6ÄïÍ>—“ãs'Pü*ë‚k¹†ŸÏˆ¼”¹øÍkó¶Õ4gî à¨óò×&Æd›k¦ê6˧šÉE¯ÔlèvæpšÉ$"R=Oc&‹;ôÜÞê¼ ™´`LÄ…ãÆ £ºkcÒ®Iæ‡øê^šZiϦ¤ëóÁJß¾ÍÉIqÙëæÇÚžÒ¹Ÿw­Fú žÚ¸¨¬¿·%ÿúU¼ˆtìåe™â£„TUb#³þÞžüËÊøäølW7åÅwõFTŽ©4ß^Pf‘fÂâ[I×õYßǰMûîž ÚVø}]±])ÑW³L&Õ¯’®AÛ ÷öó®T­¬4†¬\Ãõ5U\wæpZLD–—Ÿ¶^ Cç¾^5º‰ˆw€6ošIQäåi•¾|/úÊét/?]bLv¾­r=¤fC·#¦ˆH¥j.y›.™Õkávæpšùþ­͙݉綀ór÷ÒŒ[²û§Ä½›’ÃÎ¥§§©Áºæ÷y<8ÐÛÝ[{úï´âØ\Ÿaþž~ÚKbÏ3šç·µÖ¨C…£Jxˆc¥Žï~QU%-Ù”•yãGÇŠU\^z·RÁ0ʵRx{AÙGš Å´pwíÛnÓýßî/ø¼w€¶×`¿^ƒ U\S§©[ÁÇ-xƒöÝ=Ûߺ@¯Wýz½šÞº§ß¨˜ïª·WVÍwyPM×q‹B 5¯!³n?½BÏ—ýz¾\ØB$Û>·fœ—F#w÷ôº»§WÞU ò}dÐmþ%Nhù»Q'÷¥öâ_À[Øœ¢ÈÃOù´íâ±ë§¤£;R¯‡eSM!.•ª¹têíÕ m…’"+S5wNpÑ+~•tÕCõMîqo󰇹}$GU o/(ûH3`‰±Ù{7%‰ÈŽõ‰¤™Ü 3¾¯^ÀZïÝ#Ïù>òÜí8&`à˜Â icå”]Þ^P^fÀ–¾žsý÷u ·ZÛü>÷WgT/?mç>^'ö¤Ý?À»£î ÒLØž¢H¾cC¬>1.ÿѸ@9Eš Ûkvïª%Ày0™(l€j&ìãƒWÃÎ5öðÀí™ÌKfoª¡7h~\»wsRÂõìç'¶íêi^õÁÏ5ܽ4¿}°sCbld–îÞ~Þûz+Šdg©[×$ìÜ\Ûõ¾þÞmö°ë 㬗Â4™û[M½áæL[¿Ž_;/FoÐ|øk ë}ÛÖ$|óÑõ6]<^˜Rɼ$).ûïïJ‰º’©(R­¾¾CO¯ÖÝ<ÄmOÁ¼ÁåÓ·}“pþ¸1%!»Ú]ú¦÷¸wîã­ð³€C Í@Ù’Ÿ½tÒµ“ûÓÌV©«·¬Š‰Èúbz챩æ?#/e~=çzf†Ú©·×’·¯Y–_8n¼pܘ‘fêØË˼¤ú]z7w1ÅtþXzhƒe‡§þ6ŠHzšéâÉôÚÝ,ËÏN‘ú- "¢ªòÓ²¸-_ŧ§™DÄÅUÉÌPOîO;¹?-êJf÷ò™G&ßSPUÙþM· b²³T½bðМܗvr_Ú?ûÒ^žVÉÅ•iÎÊ=ÒL”-ß}{êoc¯WýZ=è‘’dª\ÝŲêã±™êÀ1ÍïuOK6­œ}î¨qÓŠ¸¿·§\»˜ñĸŠÍ:¹§$f1=êâ?é?¯ˆëÐÃS£UDD£Uê57ý+åÌá4KšÉd’³‡Ò*Vq‰¾šyú`š%ͤªröˆQDê·0ˆˆ¢Èõ°L½AyôÿÐ6*×p5¦˜6}·å«øM+âîéååå¯-Ì)Ý‘òÍG×õÍÓoTlÛÅC£U¢®d.™tí莔ß'2〠H€²å莔'Ç<2È·b—¡zë±lŠ"c> ¾·Ÿ·w€®r ×g&ŠHj’).2kì¢Î}¼¼´Áµ\Ÿž("±‘Y2-½«•ADNJ³, ;›žšlº¯¿·ÎE9uðæò¨+™IqÙ¾•tþÁ72\ýGøO]Wí>Áµ\5©à©é3Ô?¸–kV¦ºïפœB†Q]3÷ºˆ<ûfÅöÝn$¿«º¼:£²F«l^—•©ÚôY€PÍ€íÚž2¸ý¹\ ûóè)ŸÛ>¶F¨þîž^ù®zøiŸªVcè*WwñòÓ&Æf?2È'¸–«ey•º®MZ²).:+¤Îåwµ6ˆÈÅ陪y„š9µT¯¹¡j}ý¹£Æ¬LU碈șCi"R¿…Aù/Áåî»^IQ¤^ CøùŒëáY…9…¿%ÇFfU­§oqŽvNþAºú-ÜNîO»že]·€òˆj&lOQDç¢äºirçjò×òAå}ŠMîž¾Ú–'Åe[–ÕtõòÓfeªÿ1š—œþÛ¨7h‚k¹Ôjä–™¡ž?~cù™#F©× ydÕsG|—¸úƒèã»RE$>*Ÿ4SÞS07{º«•!ï©„¸ˆHôÕÌÜ+PÞPÍ€í5»×ýÕ•‹÷Xó€²BҺ俱¹.I¬¢)ŠÔoiØ¿%ùÌ!cÝf“IÎN«ª×h•Úõ[¿–ÓÓê57ˆÈY«þßáç3þü>qïæ¤´d“ˆøTÔ™³fÙÙù vË{ ñÑY"²eUü–Uñùl@9Eš gqWksš)Mž÷½z&=-ÙT·™›ˆÔmn‘S=^’¸kY1Y~•uþA7/~_—`î¬Ô¤£ûÝ=Íí Ji&€=y5yåîßí`z»½ClL•›ýò!Í ð¬'ýdÆ>çBš `OZ«Wy¨þ'D5€âÉÙ)˜4“s!Í€#ÛrùåˆÔ}¢ªª¨OÕ߯ÓÐ,@aQÍ ˜HR;1ÒL82“˜TÕòE‘‰üªš,÷EkÇH”/Ì{îÌH+àÈrÖ©sÍ T±J31ì@X¿{vp.¼Þ8¶›ß ùi@‘äL3QÍ °¬/94çlx½pd9 H3(ëAsÂE…§ÒÜyñi€c»ùYO’ @‘Ð@ñ0äÖ™ñi€#S«k;ë¸=«a/|qPT39/>-pôfP$&Õªš‰As MUéÍä¼x½plôfPL´P\T39/ÒL82Z€(>«‘¶9Fà@èÍäÌH3àØn^Û‘dP$&ª™ÕL΋4Ž,ÇOˆ*‰&EA5€b¡7“3ÓÙ;ÀA´ÞO5Xi¾¯Óèí X±®f"Í Býžªíó¨IÍQÝ´~ö@9Â%‡ó"Í؆¢h<\íä‘£þ€k>E ÓTÐi*Ø; å‹Ö³síåªjW·½ÃA©"Í€#£8(eÅ%À½•½£€}0HÇÆ 9”ÒL82…Ïz”.=plVÕLV“F6Go&™NcpÕz)¢ˆ(Ì( €;Š4ެcðt{‡gÁ¯š°ª™€›.‡…ggeÙ; ññööõñ¶w‡ÎwŽ IDAT i&à¦7§½Ÿ`ï(䉾=Õ¯·½£ h4 Í`ЫšVšGLKÒF×—æ°-ÒL@>\ÜLMº&–æ£.èI3Ê5ÍÀH3ÀH3ÀH3Àh „¾’ô‡¢(Šh{×ÞhÐU´wD€²Ž4€|d«™Ùjº¨æ¿û I0žÙwyœˆ¢ˆ¦ªo÷ú_°wD(=¤™äCUM–ûŠ¢µc$Ê—l“1ÑxÎ|¿bfkûƒRFo&ùPÅ*ÍD5€"Píì†4€|ä¨fª™VÎ$5içÂë ªd[î+ _šj]ÍD-¤s¡7ŽÌ˜—‘(""ª»KVÑÛ9 å‡j5ì…z…—ã݃$µ“!Í€#;ýÉ¿q«Í÷{Ô\ãïÖоñ(GT•j&ÅCo&çŧÎBåš@ÑPÍ 8èÍäÌx½plV TÒLŠ g5-Àšõ%µN†×G¦(Ö}7I3(‚œõ4ñPX9;»ñîá\H3àØn^Û‘dP$ªz#ͤˆ†¹¢…Éê>ïÎ…4Ž,çOˆ$š¥š‰þߊDU©fr^|`àØ¬«™H3(‚›i&¾5(z39/^oœi&E`iN5€"¡7“3ãG¦0Ó€â²ú¢È·EbÕ›‰<µ“áõÀ¡) šPL–j& ß½™œ82:ª(6Ko&Š‘õ/[¤™œ‹ÎÞ€;ʺšÉTÀv‹NSA§© bÒ)nöŽ@yBo&gFš G–óÊŽAsŠ g͵ö@ù¤Ò›Éy‘fÀ±Ñ”ªÊ^÷ôhð‡*&U§q·w8(U¤™ph9Z€ÜqÅU¯ó³w°ª×pd9"hÀDš Çf]ÍDš wi&ÕL(%ôfÀ‘y¸U44UD#Šâªñ´w8pd¤™pdu}úÖõékï(à4 Í Í Í Í Í Í Í Í ÍÐÙ;eŽ*¦äŒ0EÑ*¢è4½ÖÇÞÊÒLrËÌNùîÜ#æûÁîw?Tm‘}ã” ¤™ä¦J¶å¾¢Ðj@œ½þÕÑð÷EQQZW{¯Šw{G„ÒCš @nª¨–ûÑÚ1åŽ*&UL7ÞGTõ¶ÛÑð»€ÜTõf5“(ŠýP©¦›÷)‡t2¼ÞrSåæ·D…j&Ea]©yjçBš @nªjfâ[€"±(GšÉ¹Ð› G–œ—~JTQEõwkàîRÙÞ(rT31æ@Qä¨fâ ÄÉfÀ‘]MþcoätóýŽÁ3k{÷´o<Ê‹œƒæø– (¬{3QÍädøÀÀ‘ålˆÀT/ ˺8ÅŠ$go&Þ@œ ¯7Ž4€âá["€bã’Ãyñ€c»™fâŠ@ᙨfP\9æà ÄÉðzàÈŪšI%Ñ °röfÒÚ1å3Í9/ÒL82%G5“©€- ëb¾%(ŠœyjÞ@œ i&½™‡Éú[¢B5€¢P©fr^¤™pl¤™u1ßAŽj&z39^o™B pÅ¢Ò€mPÍä\øÀÀ±QÍ 8T«w ª™ ½™œ84«™æTfšPh9ª™øÖ H¬/9ÒLÎEgïÀ”óÊŽ4€ÂÒi*šˆjR%»‚Ke{‡ ½QD_}]{‡GFš G`h`hlï(à4 Í Í Í Í Í Í Í Í ÍÐÙ;eNRæÕ„ôóŠhE㫯oÐùÛ;"@9@š @nW’¶í¿ö¾ù~ç95¼ºØ7åHZfT–)U(âî¢(Z{G„ÒCš @nªšm¹¯(´ÚPGÃg]MøÕ|ÿ‘Ð_+¸Ù7”&>0䦊Ér_á[€¢à Ä™ñzÈMU­¾%RÍ ø{€RÅ€Ü(FPl9óÔ¤™œ rË™f¢}/€"Q-÷ÈS;Z€àÈ’3Ã/&nREDÔŠ†¦•+´¶wDʇœ-À)FPÖyjÍ9ÒL8²äÌ«£æšï7ö‘4€B¢š @±©*ÕL΋×Çvó'Dµ€­ §œÕL|kP$V39>0pdJŽ‹;M K¥µ €âÊ9hŽ7çÂë €c³®f"Í °rT3ñ­@q)”39>0p¤™VŽÄ4ƒæ…ªÒÜyñ€#Ëñ¢Jš @a©r³šI÷Ec5ê–©* 84…AsŠ#G1ÕLŠ‚ÞLÎŒ×ÇÆOˆŠÃú[¢"Z;F \£7“³!Í€#c¦9ÅcÝœAsŠ$g9$i&çÂŽAsŠƒàJÀª7ÕLN† ™õµ]Îi_  Ö-À¾5( z393½w’ 9ÅQÉÐRTQ%Û¤š\µžö@¹¢ZW3‘fr.¤™pdTª(ž:>½ëøô¶wÊ%oC=QU5‰¨\‰8ÒL86z3€RÕ<äm{‡»¡z ÇÆ 9”ÒL8²œ…ꤙp‘fÀ±YÏ4Gš wP¹L3í?xtà3#¶èjðm\³C>/½v£ÉTØIš‡š¢êÜêÖï‰ay7ε0_ªªž;ùÝÿ«X¥µb¨³þÇ-…¦0ûÏWRRŠb¨Ó¬mÏâ=¼lrÈ“{Q4€ÒRþZ€y}Ƈó—YþŒˆŒúiSÔO›¶Ï¿|ÝêU«r?Š¢¸ººä]îâRœç$99µa‹®—¯„ã±%ŸPÊG,yR`/—ÀVcEQQ|õõìY9K3-ÿb9Ç4tðÓ/=? j• ³ç.í?ptöGKö8ò¿O¾xÆë…ÜUŸ^]Ö­^`«ÀEiÞ¬Aóf DäçÍ¿gffÙjÏ‹‹sÀŒŒCžØ‹›Ö·¡ÿ {Ga/~qëö­S'O}æÉgì €S(gi¦%Ë¿‘W_zbÁÜ)æ%þ~>m[7ôLß%+Ö }Õn‘îî†õß,4ßi_:Ç‹O,•&‡<)@)‹ŠŠZõõ*Yºb)i&€ÒQžz3©ªzèÈ?"òàýwçZåáQaä°ç‹7Þ­ êxÿÅP'*:FUÕ¥+Ö¶êð˜»ãúM6jJjjšy›¯×nT uîëò”ˆ9zÒÒ[jÅÊo­wuðÐñç^W¯ñƒþÁ­î1hÁ§+ó6±2îzL\Zšñõ7ß®ÙA1Ôùrõ¯ò©Ü\1ÔùmÛÎ\{ëÑçeÅPgÊ´ùy•’’öÎôùw5}ØÍ§Aµº÷ü߈ɑע-›ò¤ ¼5n”ÁÇp«ÛÏ>‘kKë%·òãO?>Öÿ±êõªûVömں頗9zĆ‘”YIÉICÛŽms- |åÅWjT¯1lp1  ¨ÊS^FQ”ÕCNþ{îÀÁcýzwµw8wÜÅKW‡œ²ö»Mæ?OŸ¹púÌ…ÃGNîØúµ¢(îjת–t=&ÎÅEW­j°y3OOwóUUçüù¸‰ïeff nÞ^ž[¶þµeë_[¶ýµfå|77}®ÃEGÇ>1æ]KÚ¨iã» ³ªHÖ}·yÞÇ+ο¬(ŠªªW®F|úÙWßÿðë_ÛÖÔ®UMDn{RàHEquuÍ»ÜÅ%ŸÖHHH1vÄšµkDD§Óùúúž>súô™ÓkÖ®ùôŸzfP©Ebññ·¬ ž7g^iF€òTÍ$"úu‘æ.þpþ2£1ÝÞáÜYÝz½¸qÓös§D]ÙyiÏ[†ŠÈÎÝÿs¯ˆôèvÿÙÛfN'" Bëž=±Í|ëûØ܆[GŽ›¦×»®Xü~bÔ‘ˆ‹»Oû­eóF6n]´duÞÃMxûýßÿÜ3mÊè3Ç·îûë»»ê×.̪">æÝ´4ãÊes¢®ì‹8¸êó¹îî†ÈkÑc'Ì4opÛ“GÒ«g¯økñyo_,ý¢HûÙ¹{çºïÖuìÐqËÏ[¢®F]>sùâ©‹}ë#"¯zíÊÕ+¥‰]ÄÅÇÙ;ÜPÎÒLoŒòðƒM&Ó˜×gÔmôÀ¼+âŠÙÇçÛõ›uõsÝòͿ؋V«ýc˪¡ƒŸ®àW)0àÝI#›4¾KD6ýòÇm›šš6bìTYºð½çžî£ÓiE¤nëV/Ðé´ïÍ^”‘‘™ë!6nýtþÔ7_ÿ¿:µ«·nÙÄzb«Š¤SÇÖ‡÷m|ú‰^þ¾¾>ÞO<Þó«åsE䇿ü÷\ñö èÖµÛž{~ÙøKÇ n©T©Ò²EË|¼}²²²víÞeïשׁ™PÊÊYšÉÕÕåçõK?˜9!Àß÷jXäÈqÓBjÝ=øµ·Ï_¸ýOµye硪ªÍc.¶×ǾںeËŸŠ¢têØZD¯Ýö±kÖýtérXó¦ ú÷yÄzyêUîíÔ.òZôù —s=¤uË&/êŸïÞ XU$½{=\1ÀÏzIn÷U­¤ªêO›·—|ÿà´5h¤ÑäøL×ëõAAA"’XÒé;cccƒk| æŽÚÿ>hð1øUö»vÕ²ðÒåK#ÆŒ¸ç{üƒük‡ÖòڈȈ\;Ígb٣Ǿò¯´jß*°Jà]xû·ó>Qæ‡GGG«ªºbåŠ÷vðòoҪɨq£RÓR‹ü<8r–f­V;väK—ÏìXºpfó¦ RSÓ-Y]¯ñƒ“§ÎËÛܺ}몦Íuüò“w.ò¢Òh”\K+ú‹HTtÌmûç_ûEäþ{Û+JîÔªYUDÎÏfп{Þo»ª„´Zmóf DäÒå°;±pZgÏ=uú”ˆ´o×¾„»òóó{çíwDä­)o¥¤¦X–Ož:YDÆŽ[%¤Šyɲϗµjßê³¥Ÿ8xÀ¤šÂ#ÂW¬\Ñ¢]‹c'Ž™7PUuÁÂêüÕ×_………¹ººnݾuôøÑž`4s÷»¾ksw›iïM;söLzzúÕ°«Ÿ-ý¬m§¶ç/œ7oàîî^«f-qqq©U³–ùæéáYÀ騪:oÁ¼{î¿g媕'NžÈÌÊܵg×ì¹³ÛÜÝf÷žÝy·¿tùÒÓÏ?=äµ!‡JMK=söÌÂÅ {ôîQ¦~š(#Ê_šÉÌ`p{á¹þwÿðëÆÍ›6ÈÎÎ~wÆÿ&NšcÙ ÷ãC:Þ?Àúfμ”kæÑj…¹®5W<Í™·Ô2Y›åöÙÒ¯EäZÔõ\Ñjoù¡€U%W)0@H3€íddd¬ûn]Þ=L&ÓÐÁC7l\ò}¾ðÜ Íš6‹ˆŒøpÞ‡æ%ìøcëö­UBªŒ>Ò¼äËÕ_149%¹g÷žvˆ 9wòܨᣚ7mZ?Ô¼ÍÆMÇM§wÕ/þtqÔÕ¨‹§.;x¬y³æ7m\²bI®ƒŽy}LZZÚ²EË®œ½q1âó%Ÿ»Wp¿víÚ„·&˜7èÖµÛ‰C'¦Nž*"¡õCO:a¾=öècœË¢%‹&¼5!##cäk#Ïœ8s=ìúž?÷´mÓöò•Ëö}ôì¹³¹¶ïտצ͛æ~0÷ÊÙ+—N_š0n‚ˆìÞ³ûÏ¿þ,Ñs àˆÊÓLsy)Šòи¯Ã¸7Þûpþ²9ó–Œö\På@Ùðh®Áe±qNÔ»ÁœŠjÚ$´QƒzùnиQýÒè–’’RDD§-ßÿ ÖoXïáï‘káG³?zéù—Š·Ã‰“&~ÿÃ÷‘ééé•*Uúðý¿<Ø&‘hµÚy³çu~¨óÜysŸöùàs)ÓÌ©3+*ˆHbRâø‰ãEd@ÿË-3à  žñîŒììl­V+"©i©c_+" ,ìÛ»¯yÏuj×YýÅêF-Íž;û•^±žð®c‡Ž«¿X`þóñ~*òñ?oü÷Ô¿wÕ/δ§ “ß,"£GŒžþÎtó¦MšnÚ°©ó86éÝI«>Ï16P«ÕnùyKË-ÍNš8é§Ÿ:vâØ/[~é|OçbÄàÀỽF£™:yÔG Vdee>rÒœfºzn§½ã²§ ÊE¤eóFKμC‡0£ËÊÊ.á~Ì}µ‚ƒm”7ÙÙ¹ßEK2ëìÙ³/]4ß÷öòVÅd2™S<%¤Më6Ï=ýÜç_~>éÝIûÜ»oo‡v,Ù¢õÖÇÅÅéõúéïLÏÕ%ÊÀºïÖ]¾r¹i“¦æYð,ªW«Þ©c§m¿o»pñBýz7éÕ³—%ÇdÖ­K·*!U®†]Ýüëæâ¥™¾ßð}bR¢‡»ÇØ‘c­—Ü oŒãÉçž\¿a}||¼eÕØ‘c-9&Q¥ãÝ8^Œ[94g4¦ç»ÜÅÅE¯w‘Ì̬ÒÈÎÌÃÙò~7èØ¡•ˆü±coÉÓ@·àï+"1±¹§‘NNNÉoóü…GD>úˆÜÝþæü­N Ìc>–Ÿ–ëöò /{‡+—¯ÜiÇÎý+V~{o§¶Ý»ÞŸ0û£%ó¬¨W·æé3ò}ÈÔ™ .^º:qüzuk†GD½ÿágŸ~ö•ˆÌœ:ÖÍMÛ“*aÀàTB‚C&ŽŸ8rìÈ%Ë—Œ1Ú&û4™L?ÿò³ù~Tt”ªª–º$óOKjÎË4iÔ¤AƒùnШA£ÛÆ”œ$"Z]¡FÞ*†[1ÇOþ0SåÆ~J¹úe@Ypðê$cf´ˆ\*w ÝbïpPªÊSšéƒ™*U ˜2mþ®=ïÚów®µÝºÞ;ΤÂïíÛõ›uù´ÁööòŒ ?PÈçÍ~{èà§E¤õݽ¯\½ñãgLl¼ˆ zy¼›^/"U«íßù}á+’jUƒôëþõÚC†Oš8iNrJʈ¡ƒ>˜9AD†}.òÚõ÷f/üpþ²ç/«’ššœœ*"ññ‰%O3½òâÀþ·<úz쀧‡›—hµÚe‹Þ‹K;!ÿ†PíÛ6ÿzíÆ•«Ö næê3ykÂÐý{ò¤…פQ¹xé¢Ñhtss+ùW­Yµgïžô8züè¦_6mظ¡WÏ^æUæ"£‚G½U®\YDš7k¾pÁÂbÇpáâ  .ÞÃÍ1X:XYKMKŒŒ‘ ÊAÅp$ªz£ƒ¢fPDÿýd£HA?AÁ!•§Ï EQÆzùÌñ­ÓßÓ¶uÓŠ~nnú¡uz?úðæ Ëú~‰uELadçË”K |·µüà}=öZÔuóͼ$!!ÉügôõØ’œõm­Xüþèá/Ô¯W+3+³uË&UB*›—+Š2sêØ¿¶­yá¹þÍš„&%§T ê×»ëk­Xü~Éàï»ç÷õ|(8(ÐËËãþ{ÛoùéóçŸíççë}«‡<óäc‡÷n|âñžþ~>ÁA}zuÙ¼aùÔÉ£ò¶½¸ÕIòºUõMäµHñññÑë‹öù˜¯„Ä„‰“&êtº÷¦¿7mÊ4óúsm‘ˆ´kÓNDöØ_@Ç¢í:ˆÈŽ;²²ŠÙH1"2âè±£"Ò¾m{ËBs‹ñBvô3ǰÿÀþ„„Ü㸷nÛ*"Š¢˜Ï€úß×Dª™•¥R ¬t†C*OÕLfÁAÇ™8~H±÷°`î”s§Øvã‹§þ°a0mË¿Ïℱƒ'ŒÍ=5µ^ï:gÖÄ9³&æû»Û·´î®¯[®àU"R½ZÈ÷ß|škáóÏö{þÙ~ùnŸ™™Õ ´ÎªÏçÜî¤ÖÆOT9hÔðQÖcÖTU]þÅriÙ¼eÁcÙ iÚÌiÑÑÑC^R»VíZ5k-X¸`ßþ}ÓfN›5}–ˆôéÕgÂ[RRS¦Îœ:oÎ<ë#&&%zyz‰HïG{OxsÂù çÿ÷ÉÿF uÛ#ÆÆåþæ½ÞËÈȨZ¥ê£=µ,¬XID"®E˜L¦¼¿[äÒ§WŸ oNHLJœû¿¹SÞšbYžžž>}ÖtéÑ­‡ŸŸßmcœÕLJ€Q·Î‹—¥Ç¤ÒÒl,<"ü³¥Ÿ½9ùÍO 8pð€¹Òöü…óƒ^´eëF3~Ìø’åÄÉŸ~ö©‡»ÇãÞEQ>œõ¡¢(/üøèñ£"8~ôxY¼lñËC^>söŒªªáá >]P¿Q}ó6~~~“ßž,"oN~óõ7_7×=©ªzáâ…±Æþ²å—\ùþÌ¿xêô)“É6æõ1Ÿ-ýLD¦Nžj=°AhEQbcc—®XªªjjZj\\îYP-|}}Í1Ìš=ëíwÞ7™LGíÖ«Û‘£GÜ+¸O<µäOà¬z3³§e)‡Í9ŸòWÍ€cX¿a½‡¿GÞå^^^á ³åì÷f~yð÷ß|ÿâàüùÇþQ§Ó¹º¸¦¦¥ŠˆN§›ñí›ï KUÄäçÖ ß3EDUÕQcGegg>ªbÅŠæU-[´|îéçV¬\1|ôðm›·i4š×Ǿ¶ìóe_}ýÕW_ep3¤ÓDÄÇÇ',,ÌÜ(jè«C¯]»6{îìùÏŸÿñüÀÀÀÔ”Ôä”d‰ïòP룷mÓví·kW}½Ê²+™0nBÿ¾ý­7«Z¥j¿>ýÖ~»vøèá“Þ”’’2tðЙSóïhŽ!ݘþÎôwfÏ={îl777£Ñ("UBª,_¼¼~½|Z1ÎIU-i&¾%(¢ÿFôÛ¤¤å ÕLØÍ-šæSûY@‹Àûï½ÿð¾ÃÌü }»ö~~~&ÕÔ0´á“Ÿ<°ëÀkÿ÷Z¶Éx6aý¹„Î%ü™º¯‘¬ûnÝŽ;*V¬8|Øp뇼;é]oŸ½ûö®X¹BD´Z킬_»~àãCï Õh4-[´:xè὇éòˆù!Š¢LÓYñ IDATx àlnV3)T3(*ª™œÕL”¶¹ÌûÁíÕ~Ko/ïaC† 2,¿•V—wyz…fÿýûöÏU@dV±bňK9ޤ(]ê’«()¯öíÚ·o×¾àmD$333ô®ÐÏ—|~Û-õzý¬é³Ì]¢¬mÛ¼íViÖ´ÙÒ…K Þí­>vÔØ±£ÆÞ6* ü£µ €bRyqb¼ä8²œ£]òŸ“®lºÕ zJ‡¥«&-À”ÕLN‡j&”†‚g¬ÜAÖÓÏ•«4{£@1ÝlîFo&çÃgެüV3°/UÍ6ß!Í èèÍä¼øÌÀ±YW3åÓ\òe¢8€â¢7“3ã%¿Sþ>|bçîƒv àÔéó¿mÛiÇe3‘(.Ë·DÞFÑÍúiÞ@œ½™îUU‡œrúÌ…ËgvT¨`°K ƒ_{ûä¿çÎý³ÝÝÝ>Ê«j¦rÒT»€â”«Ö*T3(š›ÕLôfr>T3Ý?oþ}÷ÞC£G¼h¯“ˆL?äZÔõy¯°W€2A¡7€âP©fP|7.94ç„xÉïˆé³>ñññ6øË’a£¦(†:·ºõ{b˜õf–?ó:wþò¸7ÞkÔòÏŠM¼›6nÕmÂ[\º–wËï¿»uË&Ì]œ–f´ù Ê‹œßI3(¬›ÕLB5€¢±jIžÚéf²½Óg.ìÞ{èñ¾Ý¼¼Ö5ïª>½º¬[½ x»û¿å£ÇO‘Î÷´7êåV-«ªºwß‘÷f/ܳïð+Cß4™L¯¾ô„õC{ô¡!Ã'}þåwû÷(ÞAå]ÎÑ.¤™V«À1ª˜TÕdÐU´w,Ê.9œi&ÛûæÛŸ}|¼îëÜΆûP–‘f²±ýŠHÓ&wÙpŸ{öÎÊÊ‘AÏô¹Õ6Ï?ÛODŒÆô·^Þ¬I¨ˆì?x̆ñÊ‘Ý{ˆHØÙŒØkYVÓ¾Üuðïƒ"Ò£›í»øÅÅÇÙ|Ÿ(ËH3ÙXDd´ˆÔ¨n˨GŽ?_Ÿú+…WrsÓ‹Èá#ÿX/¯^-DD""¢l€²ã…W'x4NOϰw ŽàÅÁ/Ö¨_c媕öÄÆš4j중ã»Ró®ýå·_D¤ahÃÚµjÛüÐT38ÒL6— "Þ^žù®ývýfÅP'×möGK ÞgLL¼ˆT¯\À6Š¢˜3J1±9®éõzW77}lú€2™L?mÚþð÷èõ®öŽ¥Ü‹ŠŠZõõªk×®-]±Ôޱؘ¢hšur‘c;SÔ<ƒæ6ý²IDzöèi½ðÐáC/ ~©qËÆÁ5ƒ{ôîñégŸšL¹Ë Ì.]¾4b̈{¸Ç?È¿vhí!¯ ‰ˆŒ‘µß®5øºôè""G5øÌ·\Y¼£Ç¾ò¯´jß*°Jà]xû·râþ®÷| 111iÆ´7'¿Yó®šÃê5«Kô¤àÎ Ídcqñ "âíšIQ½Þ5×M«Õ¼ÏŒÌLñóó)x3?É[ÔàãíŸXÈøá`†š’7³i¹õ{b˜õf–?s9wþò¸7ÞkÔòÏŠM¼›6nÕmÂ[\ºf« ¯ÇÄé<ê+†:÷<0°ä[æ=eÏŠMîjúpϾ¯üðãoÙÙÙ·Úó´÷>n{O߀V߆¡ÍºŒ{ã½ËWÂóÝù­ž¨ääTó=™wmjjÚŒ÷?mÖ¶§»cŸÊÍï¾ïñ/Wÿ æ×ÙlöGKÌ{[ÿã–[msàïcQÑ1ݹÏzáú·t{ìÅÊÕÛ|ÞÕôá§>”³ÈQDTU]³î§»=XµMçö£¾|?lçÆ¸¬ÌÛÏB6jÜ(K¾ ïí‰gŸ¸íìîVM©_yñ•Õk œÿë[~ií‹¿-"§d5òÌqv[·m«ÆLªª.X¸ óC¿úú«°°0WW×­Û·Ž?zÀSŒFc®=/û|Y«ö­>[úÙƒLª)<"|ÅÊ-Úµ8v☻»{­šµüýýEÄÅÅ¥VÍZæ›§‡§å@óÌ»çþ{V®Zyâä‰Ì¬Ì]{vÍž;»ÍÝmvïÙ÷,¢¯G÷ØïÃyFFFŠHãÆmü4Àl9D$##SDtºü3G}zuY·zAQ÷Y­j°ˆ„…_+x³«a‘’_Ñ“‹‹.!1©¨…#QÅÕÕ%ïòÂ̇8oÁŠ×ßzß:}yüÄéã'NÏÿäóy³ß~ù…%ïû~ÍÎÎ6Üvî>~-$¸RÉ·tsÓ›¯&“ŸpêôùS§Ïoüy[ó¦ ~ýéó_ëW­Ùð#&'$Üüoòï©sÿž:·pɪşÌØß k.]{°Û³gÏ]N›‘‘±kÏß»öüýóæß¿Zñ¡¢(¹¶?söâÛï̽ín7þ¼]Dºuílþ3>!qèˆ)«Öl0ÅÏ×Ç|â«ÖlXòéÌõ·löij#7ÿú§ˆT¨`ÈÈÈ ?Ÿ~ÞxrÒ“cC*èo:Š¢¸ºæS?åâ’Ï?³²¦€a\óæÌ+ÍHJ‘Ò³ó«þþ3cbbŽï©ÚåæŠ]{v%&%V ©Ò´ISó’›6Ž›0ÎÃÝã“ùŸ ì?P§Ó=wöٟݸiã’K¬sp_®þr舡"Ò³{ÏÉoM­y-rÁ§ 9Z?´qÃÆÝºv[þÅòÿþ¡õC÷þµ7WL‹–,šðÖùÚÈ¡ƒ‡U:~âøˆ±#öîÛûhßGwÿ¹»Ní:ÖÛ¿=åí?ÿúsÊ[Súõé_¿ný;ó\ D¨f²1sû¤ÄÄdî³Fõ¹|%¼€Â‡¬¬ls*o[¨„Ä$?ß[6u‚3èÓ«‹1þŸ¼·Õ_|TðçþoùÈqÓÒÓ3:ßÓfãw‹#/퉸¸{ý7 Ûµi––f|e蛋–Ø`ÜÊ7ßþ¬Ói'M¦ªê·ßo¶É–Ý»ÞwõÜΫçv†_Ø•{<òÒž>xK¯w=täŸQã¦Yo¹dù7O Ô´Iè—Ëç\:ýgÄÅÝ?¬]ôô½’“S'½û‘9w\Fcz×G_8{îRÓ&¡;·“}4)úèö_¾jѬa·®÷æÍ1™L¦—†¼a4¦×®U­à=oüy[Ëæ‚*šÿükç5ë~êÔ±õ[V'F¹vyoÄÅÝýû<""ƒ_{Ë\œ¥ªjïLJlþõÏV-ïþc]òõ£;ö}Ôÿµ ]ìµÌíëb sF½zöŠ¿Ÿ÷öÅÒ/Šüì”:çlJ­Óéz<ÒCþ"gaþóÑšÿ¦¦¥Ž}}¬ˆ,\°ðé'žÖét"R§vÕ_¬Öét³çÎÎȸ‘qNLJ?q¼ˆ è?àë•_7 m¨Ñh‚ƒ‚g¼;ãÇï~4?° “ß,"£GŒž9uf•*Z­¶i“¦›6ljܰqrJò¤w'åzÈÆMç8ÿõ±¯×®U»e‹–å"§ à„H3Ù˜¯¯·ˆØ¶z¨fª"’ššVÀ0¥S§Ï›GÕ¬‘#Í”˜˜ìKš Ewìø©×ßœ%"ƒ_~rÛæ/»?r_¥À€Ê•*öêùàŽ­kž~¢—ˆŒ7íô™ %9JôõØm¿ï¾·S»gžì-"ß|ûsÉ·ÌEQ”J#† š?g’ˆ¬ýnSjjšyՉΠ5EDžyò±;×?5°WµªÁ•+U|´Ç+—ÍYóåüß-η¬Hæþoù¿§ÎµnÙd×öo:´káæ¦wsÓßÛ©í]ëÍOc. ¯þó¯ýúuoZ'ïZ‹°ðk‡ŽüÓ£Ûý–%=ºÝhφí¿|Õ©ckƒÁMD*Wª¸rÙ¯¬¬ì¿v0?ïNùÄã=ÿuU»6ÍEqqÑÕlX¡û @9±7)-%«„ç[Æ9mSjs÷¥M¿l²þÅbó¯›E¤g÷™Ö}·îò•ËM›4íóXމM«W«Þ©c§k×®]¸xãÿûú ëãââôzýôw¦k49®%n;\D¾ßð}bR¢‡»ÇØ‘c­—Ü oŒüÿ\¯TË-=3¨°g ;!Ídc溡èèXî³Qƒzæ1>Ÿ~¶êVÛ|òÙ—"Ò ´Nýzµ¬—_‰³DÉôYŸdffU ©<Τ\_#u:í¢Óü}ÆôYs>+ÉQ¾[ÿ‹ÉdêÕãÁàJÿÏÞ}‡5u½qo{oP7ˆˆâ–ªµuâĽWmµZë¢X­ÚÖ=ª?­«j[µ­ÖYëD­¸܈T†ì½’Iîï‹1$²„ïçÉóxsî¹çœ{‰¼9ç½mZ5¿vã·üó}j¥g÷ND”››§<ð‡essóœí¶o^¦¹Öuè Þº”üœ Q(Ûvì%¢%‹g¨îÒœÇDDQѱþß­ Ëœ›••SLË'O_ ¢>½ %fjæÞX퇥§'rt°%"åªÀ:¶Þ»{½‘Q¡Á87100âQbŒzþ’JMMutq407Øûw¡_YwîÞ107°´·|óZYXTiUïLGÍ¥ˆŽÏç,[¹¬yëæævæ ›6üzÎ× o—¿3)5×Φ­Z–6ëž©:))‰eÙ]ìêÐ¥ƒ•ƒ•G+Y~³Ä-·x«`]»t524zóúáã‡\ÉËW/Ÿ‡=777ïØ¾#WrõÚU"êÒIË$;—º.Ü!ÜÓ+W¯Qk¯ÖNŽN¥̵ë׈¨Më6j»ztïAD,ËÞ.”¡iˆï­ÿe JA˜©Œ5soLD¡ž•a›B¡`ü˜ADô˯û´.ÇKJNý}Ïa"š;ó3µwᡟ‘G³&e8¨ Ò32 ¢Ù_OÒšÂÉÐÐ`Æ´qD´wÿ1åä R8xä4õõéJDúu#¢¢VÃé^³(Êqš››QJjúá£gˆhÑü¯ôõuÈHT*!¡O£¢c6¨ÛýSïwVfYö‹éßeg‹¿›7­žK휜â.ì‰Óv¶Ö-=›ßfXxÄÓg/‰¨c{¯âkêñˆ(W¢=Kºî,--Xø}÷ýw9â·‘²ÅKÑÜYsk9Lº,&4W¡Dé¨ü{¤MÇ6KW. ËÍÍ}ózû¯ÛÛvj«ŒŒ¼3)µV%ÍT9zÂè©_M½wÿžX" Û¶c[Ÿ}ŠYõ\1 ô º}ڈΜ=ÕpS™|zú( ÅÆÅцM4ó»s7àKLJäjrÑÀ† –n0Üá\èJ¡¡²Ž’.“¤ Ò!ÌTÆÚ¶nND!ž–m³óý§ÚX[fddš0[*ÍUÝ•“#6z†D"­åd?rX?µCBŸQÛÖže;¨ö‚‚ïËdr"?Æ·¨:Æ&"©4÷ö݇¥ë%1)åÂ¥ OWç:NDԿϧTÄj8ÝkcßDdkcecmID—¯Þä&ÅhþÇ)C·ï„‘›k†aB>›;oÅÐQ_}÷ýº³ÿ]Õ¬¼ç¯Î^néÙô[¿©DTÔ-ä‰H"‘þxݧ×Çjs—Tåååï?t²{Ÿñ …bÆ´qқ󤊴¤|"²«mPL5M7ѳ¹g\|ܺ 븒KW.¿p¾–S­™3fr%\éìœì¾>}o߸›òâÉ‹Y3fµhÞµ±+W‡KG­'ÒÛ±uGâëĈg¡wB[x¶àÒQ«u:ÇŽD"ùí—ߢãã"âvïÜmdh”Àå™&¢Þ={?º÷hÉâ%DäÚØõѽGÜc@¿Åœ —©://oæW3Ã…%Ç$]jÛ¦mTtT¿AýÂ_„«Õï?¤ÿé€Óë׬Ž|9Ïoݺqùêå÷º¦e¡ŸO?z]"¢3çÎQ¿>o_ÿ\,ÌÃÝcøÐáZînî\MîÅYêéEÅݸf+=0¥€;Í•±† êš››Þ¾Z¶ÍZ˜›Ú·¹›Ïا½:ô÷›5¹µ—ݾ·zÝö°ðCCƒ#û·èé©ßû‰ûˆË¿tú„ˆ,-̹¬öZ99ÚéëëI¥¹÷Cwòn]Š^¸upýú|Ê=umR¿aƒº×ƒîF¿Ž«]Ë¡t55)ŠÈ¨Øm;ö®Y¿ƒˆ¾ýf ÷!öÑã0"²·³166,Ѱ ` ŠËš¤Š»»œ‹sí‹Z±f›ò“ó²U[Fè¿cËråDªø„¤Y~ËD"áîkÞyÀ —‚$©O¯.Z÷~3Õ¡NÇÆ%æææÙÛÙü¼nñ´)£‹o0."—X20æ›Zh¹…œš£ÇŽ[«þoíÿ>›ð·Íçó7¬Ýй[çõÖO;ÁÉщ›Ê´bÉ CC*œ@ú·_~ã‚e\i¹\ÎÍ[QMG=hà ®e.µ{K÷µë×~>ñsÕÞywðÞ·gŸµµ5÷tèࡆCG=qêÄÓgO›4.ͤNÕLÕË~XÆr™ª;Ò9ôQè¢íÝ]hm ŸÏ?wêœWË‚¹c‹æ/:yêdè£Ð3çÎtþ¨s)ÆP†zõè%‚n¥§§‹ôD—®\Ò××ÿ¤ë'Ê öööDÔ³ŶMÛŠoÊÖÖ–TÖЕ×QDd„æ.±DODöïø¯ Uf3•1׳[§gÏ_¾g^dMÜÝ£ê¹Ô~ü$|Âçþî^½Ü½zMþr~Xx„›kƒëp'Uyyù§Ï^jPß¹A}ç² |X¸°ˆÚcíÿÔ'ƒ¨JII'"ç:ŽÅÔa†›[”’ZÊœÊÜt¤¡ƒz+4 'ÒX §{MÎÉ€ µêw¬U¿££K}s·z®]V¯Ûβì”É#§}1Fõßy7·÷”™•MD‡þ9ýÓ†_—ÿ8'æåõ„¨àÝ;ט˜ý¹ïߟ·¾½5Û´¯¿OKÏøaá×îM½³Ù§/…‚n]µ/Ä{þêUÄëÜÜ<"233a¦˜‰QDD,N#"ÏLuœž"× 6÷¤Më6ãF“H%‹~\tîü¹à›ÁÚuPF‹tI ­{:jNÿ¾ý•1&Nï½k9ÕbYV9§¤tÌT-‘¥°Tp…çΜ«Œ1Ã0Þ½éÍz´ÊennÞÉ»“\.?áü¥Ë—rss?ýøS#C#e…í:Ñ•kWd²wd‚oצݺ}+))©˜jÜO“»C…*®£[·oed¨§¸:xžˆ†áº€ ÂLeoì¨DÄå|QÚ´þ{V~hŸ–̲ºWkׯóiȹ¿ÿØÀ¥j"¢O>îðÏ­nlîáªY?ð⌌¬q£}‘6µ†cFOO¤ö(>ÑI^~>YZšß²•¥9qጒJHL¾t妛kƒ¦noÓ»øèND,]M%©47&6!&6!.>1?_FDúv»p毭TNb‰¥b¦e`¿îùYÏ4iñw5+s'9%-0àÏys§8:ØÚÚX5p÷Î5D´lÕn졎ü{¦mëæsgN~çX–=q*°K§v&&FZ+ìÿcãË'¯œÿÛoÖä„Ääé³¾ï;èób~Lar"ŸIô ymº½ã'ÎÐo€$]¢ö˜|ý:Χg—¢*èé‰\êÖòîÐjõrÿÐÛ§ìl­OŸ¹´aó.­•ÓÓ²$Q =òü£`cc3gæ"ŠŒŠ;j¬gó·IâtI ­{:êbpk»¢¢JfÒ%SõËס¯2N‹e YyÑD”(¹¯`óUkr ¶«H¦¡¾>}‰èÌgNž>Éãñz÷è­º×ÒÒrñÂÅD´`ñÿþ\hŒeÙW¯æÎ›ËE¦8¶¶¶ßÌþ†ˆvü¶còÔÉaáa,ËÆÆÅnÚº©±{ãpÕÜ\݆IMMýuׯ,ËŠ%â´´4"²°°à:ZµvÕÂÆÆÅ*Šôîß;äAˆ‘¡—B >83•=€ÿå£B>;p±üzY½ÜßÁÞ6,<¢EÛ~»þ8œš–βlZzFl\Áç®¨èØ½û ì×½®s­òTWuˆ(*:¶˜ÏÆ2™œ‹C•î5Æ­ƒ‹%‘Q1ʇ2f¤ºN÷ššþŠ%s‰hû¯?{^hòK“Æõ‰(!1¹øº½'.`Ÿ¬VÎãñ¸õz/^FnÝþWbRŠTšëêÙCuaã{‰hàЩŒA.¬Æ9p‘ˆ|z}¬Ëj9Ù/šÿý²sŸæ^©4wîÌ_2Rd ›yuÕi*“î Å©3iÚ“U_Kº$Ö=u1²²³ˆˆ¯Cð®˜1…tÖEåŠ9"ŠÈ<óÏ‹>aéGì;ÖU GÇV^­’’’^Ç¼îØ¾#wß=UÓ¾˜6wÖ\–e7nÞX§açFζµlÝ<Ý6oÛ|ððAÕšþsý'Ž›HDýý—G++«ú®õý¾õ#†bbb¸:µkÕì;˜ˆfÌžáèâh_Ç~õºÕÊŽ–~¿T(®]¿¶¾k}+G«¶Þm¯]¯åTëè¡£5.÷kå)ÀËÅÌé6nÞýãòM½{jYîQ&œë8]9ÿw¯þÃÂ#&|îOD"‘0//¿ßOØFD«×m—ÉäKÏ*Þ¡Ús©[›ÞDvŠŠ"={þ’K¹âR·Äa¦ø„¤KWnÚX[ÆG©-2:q*°ï Ï:9{ÆÄÕ,Ê€¾ÝÚµñ ºyßÿ»ÕÜÿŽ2mùŸûŽ~ñÙˆ’ž‚ޏ0Ó“§ê÷#SellÈM¹Rù:77ÏÑÁÖÄÄØÑÑVY~âT`ãFõtϹÖÜ£ ½Šx-•æ*3Ž˲“¦|{ÿn¸¥Ðg‚m™ÿ®Ú»oPpPŸ^}<|púÌéc'Žõï[0¹R—Òº§£.—¿ÉÑ¡4îH·LÕMëv5Õ»šžûöGœs=nQhòv›©õMû”®ëòÓϧßí;·©ð=攆Y²xIï½wÿ¹û^ȽðððÚµk»¹º>Ò§§jM>Ÿ¿é›úõé÷÷Á¿C„DEEyµôjצß,?nžgÇ–ögbcc½Zz999);š3sÎ'òóÖŸïݿݮm»ömÛûÏñ73+òÎPa²ócB’¶2 !žƒQ»º¦=+{Dða@˜©\˜š/üvzè£g‰Ôа î®UýzuÝ øëïÿúûXXxDBbrS·†v¶pì¦M­šË@wîn¬­,’SÒ¶nß»jÙ7ZëlÙþ'¹¹6Ð")Þáΰ,Û³{'ÍD6]:µ‰„Á·B"£bœë8é^³¨¾†YµÌ¿s·ÿÿïʵ[u,ˆ.ÙÙZ÷éÝõÄ©Àe«¶L;X$–ô,táÙÜ•Çã…„> ©bY–» ]S·F}zw9]ËÆVܹ÷pó†ôí¦,LNI»|OkdeY­qí¸ø$"²07S½¥B¡˜í¿|ïþc––&¾_ZˆôËxrkFfÆüEóÁÊe+ïÞ»;vÒØ9þsº~ÜÕÄØ„ˆÚµi·ÿà~.´Ö:´ë°÷ï½\:j 4­ââã„> ¢ömÛ+ ‹JJ]̸LÕj±e¦jŸN--çDe_ÏK$UVÈÊ}-vAhòö©})_~üfûùÍö+¾NûvíÛ·k_|"b¦G·=ºõ(¦ŽžžÞªe«V-[¥u¯gˆdà IDATsÏ_·ýZ|/ï ”9©,5<ã(·ÍcD3€îòåÙ/Sþ&b†g¢WÏÁ´’o¶  ‹æÊË×ÓÇïܺ¢übL¡P0~Ì s'wG<»$I{ôðÎé_6-åvÍÿfêÏë—kïPq/-"úå×}™™Ùš’’Sßs˜ˆæÎü¬Sö9ED½zhù“cllÈE‚¸Õpº×,F'ïÖ}zw%¢¹óVª.ƒZøí4>Ÿý:nÚÌÅšq‡c'Î=#//ŸÞƒ­uÏîX–]ÿóoªå'O_HLJq°·-if«Óg.±,ËŽšÙß,çn¨§ZȲìÎß÷Q+/wåOJ&“Ošòí†M»l¬-·ý:ËÒ®ìClKW,MJJšñòÕ[<¯û§i­Ð³{'":pè”î5ßÙéòæ0 sóv—é‰Ó¦Us.sÓÎßtè2ôÐ?1± ié7o‡Lùjaÿ!_8|êø©ó%=A5+~œËçó·üò×ʵ۸۽…>|6uÆ""Z¹ÔOs–VñNœ 455îØÞK­<&6aËö?ý¬8lêÍÛ!r¹œeÙ/£FŸ}æÜ7ÿ›/¹šRiî‘ÓwýqØÚÊ"0àÏz Þó5=zòhëö­ÆFÆßú}KD ì[µŽa˜ÍÛ6sÉ¡uI ­{:jΊÕ+&M™ôìù3…B3ÇÎö_·Ñ’ÅKôõõ•ÕŠJJ­U)2U»[Mèä´ÆLO}Š_znø±—#2l€˾ýö…ÁG( ¼Û©áð7´³07;´o³H$¯câÇö-é óóeç.÷ìÖI(T_DæähwòŸö¶ÿÿ¯íGƒôÍÝŒ­=4íºïÀq€¿vå·?jÃÕ0tÊÑãç¸í>¾“»´Ÿ½æËÊÇ“î\º^ü0Ž;jle¬ùptq$"–egÍ%—Ëg͘¥\çÕÒkÜèqr¹|ÆìÜ4"]H랎šˆÚ¶i{ððAÏ6žÖŽÖ Ülùe Íó›7dÐÕjÅ$¥Öª¤™ª⹘öê_ïèGŽ«LE…òg¥ç¾¸3÷ØKßȬ³DUâÆsEaUM1øÈ% fBœºÂŠÔÉ»õ¥sûê¹Ô~ü$|Âçþî^½Ü½zMþr~Xx„›kƒë´öò(E³Ü|"­ëà8MÝ:9ÚÑO~Õ±æÁ#§ßÙï ¿ÖÓ½Šx½eû_ªåÓ§Žyöàœÿœ/š¹765560ÐoØ îW_Ž}pëä×ÓÇëzVÅ;j`ÐåC¾ý{$$&wíÒ~÷Î5¿o_UÒ©LW¯ßÎÌÌ.êsŸvíøäþ™õktlïeei¡P(Ü›63r@èíS³¾z›û)èæ}n#9%-2*&;[Â*HùP(t ȵQÈDtèÈ¡+×®ØØØÌ˜>Cõýhnf|3x×»èMé£:ܵ‰+Çójé5mÊ´ûÁ÷{õèÅÂ¥£ 7zœG3ì¬l''§ýÜwpÇÖjC9ldð•ࡃ‡ZZZ:Ø;ôïÛÿØác‹,Ö¼È;¶ì˜1mF£†dù2Õ¤ÔZq™ª/ÿwyäð‘®M\|A»¶íf͘uûúmïÞEE¼zf>ê÷v\®'(”Ô)=7üâëÙÇ^ ŽÊ:`TY,½ÍÄÃG(Õ78åsG,¨Ê˜o¶Õç¶j[7™î³¡rGP¹ÆL‘–žAD¦òO§&Ud׉¯ô‚XpÛ# 5x`Eö^¼ü|Ù‘Ïœ½¼ëÃDôÉǦOÓ·wW.•2T¤9þË×ÿü{BT°µeYµy'üÜkk•O õ,ü^)«Æ+Fמ]oÝX»rí´)Ó*{,Z°¬üEÆñÉÛ²òÕçÜYê»zÚ|YÛ¸ Þ@Õ—|6j·ÝÌzrK›¯+wëËm×±èÛºöòÊ”­5xp¡ÄÚ¶ÓѬ€;ÍÀ;…‚aƒ}† ö‹%ŸŠŠŽíäÝ1¦Jqâô…vm<Ë0ÆT¨¥¯:†ßÀ|@=³>/2Ž>HÞž«Ü•*}ý••~Ó6ÓŒµ' +ç¢&ç)²‰e …ö×ú_ùuÕ†êl&†ðGJäí»2ߥÕ<3€®V/÷¿rívXxD‹¶ý~Xøu¿>ŸX˜›¥gdJ$¹Ž¶{þúçñ“ðw62}ê˜ZNUëþîаðˆça¯–~?»²¥Ác Í×7ë–þOhÊöœüxå®é£ÿ¢§Zx´°™æhԱΕg‘©"«<Ú€ê‡eUS«àS"”€ê/$ê©f]9×qºrþï^ý'†…GLøÜŸˆD"a^^~ÿ¾Ÿ=°íÈ¿gþ=þß;ìÛa¦Ò9qúõ)"1|xŒ°±ÅÐæÂÒ‡&ïË•»’%ÎE}akàéi3ÝÁ¨]Y÷\ð‘E6(Ðj_ƒÙLPJ r3Õ<3}XbYVAIJ¤`Y–û«Ï²ŠâÊIA,«¶Ár‡°,±ô¦‘75‰%ÅÛrfI³‘‚rÕ –kDul*•Ê ª#Õ¾”u¸ò‚¦HãØB‡³…O­ÈSÐÒ,±l»ñ©r{v“­4‹n³mEþ”å²·Û’ް1Äp óâ1ß#2 1oÊßlÃ0ÔØ²G3›·éœ^¦_ I<ÔÔºO#Ënʰ´À§)§›ÙøÖ5k¯,|šð2ãJA;Äp_XôH\ÛÊr†!†á3›Ž~rþø‹iQ¯’“›º5´³µO»8û'×_wûYÔWéñ|’ø¹»uS=Geá³ÔsÁ±7†¡72ÌÛÞæMwo· N¼Ådž·‹Å"2nää'7´øXÄ7V-Ì•gÕ7ï,àé) #3‚d¬”Þž#1 ¾›UïýM–B†!žƒq3Õ7Ö‰âg,+·3rSýÁ%KÂâ[¸¨”±iÒ(Íñ´]X"bx _o¢ÚN¾BÊOy.µœì—~?Ëݽ!K,¾Xþ ñQ‹ Í}Ÿ§ MÙ)‘½Í—(¹6ê3;C/O›iö†mÊ®Oå a&Ð Í@©©Æ©‘€²B˜©ìeç'¼\ø&–AêñeD%˜¢Á!•¸ ©ìªAz$±,I³+mzg¾\œ“Ÿ]¢CÄù©ªO%²ôDñSYÕÂ켄Øìõ-º¨¦çFGgÞ.éëu¡IcçªÆ°®¾Þô$åTÓ6ªa¦èÌÛai.fUÃL/Ó/GeÞ,iDdoÜT5Ìô0éhLö}'“ªa¦;ñ&KÂ똶V 3]Ù–™WŠ'4ûGÄ7T>=óêI~ê瞪uþ ›ÍgDã›R–(Xù§Ÿ—¢;#¡õè¦oo—'ÿêk¡ï<´Év®dˆo¯ì¼Ä|ìšöo¸NY3EòêÈóéTÊb˜B5†ˆ÷&d¨P#"žƒ‘û§uç+ÛÑ3 Ûº”Ÿ#VU¢øîøMºyڼͮ›sýnâm¡4ÕÞ õÈ=­mܵ±ÅPe;ñ9ÁOÒöÖ5íébÚKY“}õEÆñúf}TsEe¾Î¾ø&VÈ ß6ž÷šˆ¢²ÎßJ«ŒŠÇÕ6ùÄÆÀCeä7’$!Î&Ÿšë5Pí1-÷¹³iwa-•Â+YùÑÜ#†xêPåÕž:¶Õ¼}¡&IB¤²T;£Ö"ÞÛj²äAž"Ëΰ•«å¨FƒŸ¥í˜ò«D–¢¬ ¾s&r¢½akO›év†^‡ï½p¥Ð ¯¤²óE,kCD # –2»ª­ý"¿Õï3 ø€JxÇ`Í ”r3Õh3•=+K‘¼ªìQ@i1dU;/%ZTÙã(¡Â“Qß| VÈ’Æ/ú÷XA£åF«Õ,eLáuÝZO‡´õXêsÔ˜â«Ð¼!+K,£ýâ¿?Ý^ +SÖÐ]®¼Pš†!¡ˆä¹…šÈWˆÓsÃm < ˜ž"}T‚žÞ0ÖQ}š•uÞ\¯¡jaFÞËW™'­ š:ÑÛ0SŠôqXº–ÛXp¦mÕ' {œ¦¶ËHèX8ÌtíQÊ.SQÕ0SdÖ¹°ôÃzTÃLáÿDdž-áùõpþÝ^%Ìô yûëìK}]Yê7QÞJ\›(¾;¨ÁYc¡#ŸÑs³ÛÈ|è‘=%²dÕ¦âÅ·"Ç9µMH«ŸKï…¡‚Él6•²)ÓjÕÙL<¤V€’(”› qêša¦²Çà/qÃÃÍ}PÛ`Y¹ŒÍ+œ Žˆ¨QkÅ ‰UI{aI‘WðQÀÓ3˜•b¨ùŠÜ-X]Â+('†Ãeáy{O%[²NÁSeæ†xô¶BA‰Jn½ aÔʹUo 1TžJæMSʳPÙ~Zèâ½M÷£­•òB>„¡·C-tÅHeªWŒÞ–¨a#3‚oÇïI–¼PÛa¦çäe?ºAó.Ì¿ËÒþx8œÛ®kÖ¾‡Ë÷%~é”wëþîÖýÕ [Ø on;˜Çú_߯a¼—ý¨‚ø)—m*·éM+õr…j;-íFºYõ1ÊíÝÚ~œ»Í@K}gÕÂvŽ“ ?ÕlÕ{’±R"R‹1šë5 7S„z,ëÐÅÔy|¼¨‰ çfÂï(äfªáf*{ÆB›IÇ*{ ]tæ­[ñ{’ÄÏÕÊME-íG5´èZï¥Âcøšg'àé HOký1Z ­Õ MõMÉQ­ÐRß…ÊB-/ÍBsoÍÂÆ*9¤Þ‡—ýhÍÂŽN_ª•ðA—:³ß¿;ß°Oý•j…FBkÕ¬Ls½Ú¾6½¹bŠ|D†z…fÍ8{j¬žKËÅÔÇÅÔGù´àÄÛ–¢à½‰Ü#j`>°™ÕgîþCT°f°íÐT Ç|ª@ló¥ø„ P½ý”ˆ0”jn&ü©qf‚š"&ëÞ­øÝ 9OÔÊE¶-íF6¶ì¦6utôæöy…¿«Òá‹+O_ÀÓW+ñMD…î¸GD¤/°TÍ«]jf"3‘z ÓJßÕJßU­ÐÎPK³êšv×,lhîËm¤H‡$oκ¨6]‹Ïè54÷mfý™¡À®L†PR •¬êÓNŠU87f3Õ8ø\ Õ_löƒÛñ{â²CÕÊ„Ö-솻ZõB€ *X²$4$yÛëìËš¦FCÜ­& l+klTxÍ £-$@Ñp§¹ Ÿ®¡:‹Ïyt;nOLö}µrC¡E Û®Ö½øgÊU’$$$ykLöUµrO¿‘ùPw«‰õõ§•³™ ôT¿EC˜©ÆA˜ ª§DñÓÛq{¢³î¨•Ì=m‡ºY÷ðÊ !‘*=¾Qw—Eܶ¡°Ä7ª€j/Q|7$yklÎ µrϰ±Å0wË e²0 L8µÿ¤öf–U°¤°ÔoRÙÀ‰ê¢9äfªf‚ê&Y~;nOdf°Z¹¾À´¹íà¦Öý„<ƒòè—ψ\Ì:–GËð¡Kß¾Ÿ¼5>Gý÷’gÔÄb¸›Õx}¾…Ö*‹‘ÐÞHhÿîzŒDµ<¿áîwlaàVÙʆ0T)’W·ã÷DdÜPËu¢Ç7ö°än=@Ä7,êX€òŸ|?yk‚ø¶Z¹gìj9ÒÍr¬Ú=õ>túB›†Öc*{Pif‚ê My;þWéWÙÂ&ß°™Í@_߸²Æ5SlÎä­‰â»jå"¾‰«Å(7˱"¾i¥  ü ̶ôÜ×wâÿ|‘vQ-À$ä¸Ûôkn;DOãÎèå*&ûjHòÖ$IˆZ¹ˆoêf9ÖÕb”¿— šB˜ >T™¹qwþ K TÍ0GDž^Së~ž¶Côf•56¨‘Ø×ÙWB’·&KBÕvèñÍÝ,ǺZŽò0³ª3„™àƒt9úOSÏh˜\­z{Ú 3 ™.T$6:ûbHÒ¶é#µú| 7«ñM,† yF•22€Š„0|¨TcL|FØÄªgK»†B«JÔsz줱»u~óZ³}}}}GGGG ‹ø„ø»÷îîü}gë­?›òY~~¾ÖÊööör¹<"2âÈÑ#“§Nöhå|3¸\/'==½z©HÕïŒÊ ÂLeÀ»ƒwzBºê£Ní:D´eãÕÂÿœ ¢=íÙ¸y#M™<%øJpÌ˘Ëÿ]^·z]Úunß¹½å—-ší÷ìÞóÅ“/ž¼xýâuVrÖÝ »Ó¦L#¢¿þþëç-?k­üêé«ÔøÔðÇáëV¯³··ŒŠìÑ·Çå«—ËûR¤¥§•w¬ú@9A˜  ¢ý¾çw"úlÂgë׬÷hæaiiÙºU멟O½tgÍŠ5?,ü¡øÃù|¾k×µ+×r‘¦_vþ²lQ•¦~>õÖÕ[žÍ=sssÇ6>3+³lOGMõ›ûSýΠœ ÌP¡X– !¢®]ºªí262ž>uºP(Ô±©AQTtTFFFñ5­­­ÿüýO==½¸ø¸Ýì.阻öìj`n””IJì®?vuèÒÁÊÁÊ£•Ç,¿Yb‰XYíàáƒæ=úô ¢(SDý±÷ÕÖîÝ¿÷ٔϚy5stqì3°ÏÖí[Õ2RqÝ¥¤¤H¤’‹¸4q107Ø·ß;÷Ú×±707¼¨6~ßa¾æKW.Õì%>>>Gœ³l岿­››Û™7lÚðë9_'$$”茀ƒ0@…bÆÙÙ™ˆîÜ»óžMÙÛÛsÙ9Ùï¬\¿^ýAÑÞý{K×]dTäè £§~5õÞý{b‰8,œç7ˆnÝPæ{êݳ÷£{–,^BD®]Ý{Ä=ôÀU8qú„ߟîÔ¹)“§X[[ÛÚÚ.š¿¨YÓfDtæÜ]zKÄsýçѶMÛF-ˆ¨AýûöìkׯÍËËS­âô‰ë6úÏõ¯_¯¾WK/µµ„ÅïÕwï›WoŽ6ÂÊÊÊÜÜ|èà¡¿ïüˆNœ:ñôÙÓÒµ Pc!ÌP6ä¬,.ç!÷H“FUöp J‰DG]±d…••ULlŒß<¿zMê}5ë«W¯ÞylnnndTäñ“Ç»ùt»vãÇ[´`‘Žýra&ÒáÖi¹òŒDɽñ™B¢,œ;s®WK/åS†a¼;zQl\¬.½:r(*:ª¹Gsß¾ªåÎuœ;ywJHHP;}¯–^ãÇŒ/ªµâ÷ê®ßþÖÖ…æ‚õîÑ»–S-–eμû5MŠøþ­èù·¢çߎþ.1;¨²‡ a&€JÀçóg~53ìQضMÛš{4KÄ;ßÙْ̫KÔòasŽ;Ê%Ÿ6·3oâÑd訡AÁAvvv{~ÝÓ±}G;•ÉdÜÑõƒÃð•Û<žúQ6Ö6D”””¤KSW¯]%¢.º0 £¶Ë¥® q锆øѬ©ãÞ÷Áçó==<‰(*ß”XN^LTÚñ¨´ã‘iÿfI_¾û¨^•=€šË@ß`ÜèqcG ¼¸`ñ‚!ËW-ÏÍÍ]úýRµšúúú––DÄãñê:×mצ݄q ô tï."2‚Û077×ñ†Š åpKÕ”)À‹ÇMzÚ°iÆM´VHLJT}ÊçóµVÓeï{²µµ%¢¨(„™JŽU ”ëцja&€JÆ0Ì'òqç¿]øíÆÍ7lÚ0}Êtå]ä8=»÷Ü·gß{vÄ…™„B¡rõœc+³hòp÷pssÓZÁÝͽ¬úzOYÙYDÄ”c$  &(>N ÕÂLUÇ[üÝâM[7Éd²Ðµ0S™8á<µðl¡cÊp"bÊ.ÏwF-<[lÛ´­¬ÚTÃ-£S® ,5.K”£ƒcŒ  †aIuÙ/ÂL5&°T4©Tªµ\(ê‰ôˆ(_–_æ>|üðøÉãD4fäÝ*E˜‰[Î&—ËÕÊ;´ë@DW®]yÿ0PQ¬¬¬ˆ(55U­<;;[÷Fââã„> ¢ömÛs%Ehóv-f3Õ@3T¨¡5k´qóFÍTßG•H%DÔ¶UÛ²í46.vôøÑ2™¬®sÝÃFè~`)ÍÙÙÚQ\BœÚ ì7ÐØÈøå«—?où¹¤mêÈÞΞˆnßP-\¶rÙ•kWŠ:$5M=&µrÍʼ¼¼Úµj÷ëÓ+)êŒ@‹ÜL5~äjïþ½IIIþ ü?éõÉþƒû#"#ÒÓÓ>~¸dÅ’/¦}ADÇM´±±)“¾X–ŒŠÜ°iCï6Ïž?340ܽs·‘¡‘î-”b2‚›«Ã0©©©¿îú•eY±Dœ––FD–––‹.&¢‹ø/ðçîODz쫈WsçÍ=sîLI;ÒÔýÓîDôÇ_þçpŽ8'&6ÆožßÒ•K6hXÔ!+V¯˜4eÒ³çÏ ELlÌÿ9ÛÝNDK/Q.-,ꌠx˜ÍTn¡-… IDAT!7@…Z±d…­ÝÒKƒ‚ƒ‚‚ƒÔööìÞó§U?½g§N97rfY6###//+¬_¯þž_÷´lѲDM•b6SíZµû>xøàŒÙ3ý¸(''gÚ”i+–¬ ¢i_LKHHX»~íÆÍ7nÞhkk+ÎgçdQzzzn=JÚ—šIã'ý¼õçäääÑFs%|>ÿ—Í¿¤¥¥ÍûnžÖCÚ¶i{ððÁ½ï5Ð7঒Ñ<¿yC ÑåŒ@ r3Õp˜ÍP¡†™5cÖÃ{XøCëV­­­­õõõ]›¸öëÓïØácÿøG÷üÜEÉËËKLLLJJâóøµkÕîß·ÿŽ­;îß+iŒ‰J;aÇ–3¦ÍhÔ°‘,_æÕÒËÉÉ© 5†Y²xI`@à¸Ñã<šydge;99 ì?ðྃ;¶î(EGj¬¬¬®]¸Ö×§¯ƒ½ƒ©‰i—N]N=9vÔX ‹¢9ldð•ࡃ‡ZZZ:Ø;ôïÛÿØác‹,æñ }V*êŒ@«’›‰A˜©Æa¾ÙVŸÛªmÝdºÏ†Ê À‡K,Kûãápn»®Yû.ßWêptu'üÜkk•O õ,ü™½*Åï{·œ<{„Ûö“báXöY‹°Á6_Ê#"GûÚWþ^‘]@% Œž}‘ÛÖð²¾À²R‡S^ºöìz#èÆÚ•k§M™VÙc©‰6žôIÉŠT>ý¸•_+×±•8(+/Söß‹YÊm·ª½ÌÙ¢_åŽÊÖš?<¸,ïµm=¦<¢Y³™ Õ5/Õ~2«2óÊr3Õ@3@!…ÂLTâÜLP“!7S ‡0¢z?r÷#€’À/?r(„%¹r›ÁG(=Ìfªqð7 )<‹æ  ¯ºE˜©ÆTö j©!©U+{Õ’JZýê~ЄÙLPˆêl&R€@Iš‰˜CÍSî³™X–äù …Œäù,Ë« Ü–apÓP(/,Ëè1 †øB†' ¾W1t}¾é°&;¸m!ß°Üû(7]j­“)$,±,+Ç¢9x˜ÍTã”W˜I!ge¹¬4K!ÉTä‰T‚ •“Zè©È€10ãé›ðz _^¿æx ß\¿N95P‘ 6•=øP9™u3Õo@IJ¬ÂÂЭ²‡­ì'°ÉóØìdyÜ“¼„°üŒx9bLPéò$lF¼$ò|6éE¾±ßÄÓšÊÀû†™dR6%J–'A²ø e§ÈssVuB=DšÞË{}´Î—*_æ#Æ´|)›.Ë—bù@¹àñð}@MQúßøùREbx¾<1&øàÉelBX~ž‘&¨)’’’–­\öÑ'9ÔuptqôàsàÐÍjÜýà’’’X–ÝõÇ®]:X9Xy´ò˜å7K,kmùü…ó£Æª×¤^·ÃÇ ¾lbbR¢±Ý»ï³)Ÿ5ójæèâØg`Ÿ­Û·ª%ÔäF•’’"‘J,^àÒÄÅÀÜ`ßþ}%êÊC)ÍÉrÙ¤—2dû†jƒUPò+™m=¡@Ÿ©ì±@M‘žÎgD&¢:Ù)˲ËW-ÿßÏÿËÎÉ&"}}}©Tx10ðbà‹—/¾ýæ[ÍC"£"gúÍzüèìg‰èuÌkÍjš·Šã"GIIIÊ’'OŸQË-t¶ª«×®Q—N]Ô¢TDäR×…ˆ^¾zÙ¸ÑÛ•qC|‡hÖ€ÊU²0SnŽB–‡årPÍÉòØÜ…¡9¿²5Ô›`SÛæÖ_Úz½û"'hyoÏhKóøéã¿íÜû÷ÞŒÌ "rtpä—ÉtúRY(—ê›óôùS"ªçRO—õâæFmØ´aæ Z+$&%ª>åóñn  Ê)A˜IžÏ¦Ça¹Ôé±r=C_„ïÇ ÒÄåÇåÛµõÔ9ؤ£m;¶ÍñŸCD>=}ÆŽÛ±]G ‹¥+—.[¹¬Ômæçç‘€_Ê;YÓ› •‡»‡›››Ö înî¥n*F þ ä‰rLe‚šAžÏæJ†"|E•,>'8 'ØÞ°§Í—v†­Þ¿Á¡f3[(îݳק§Ïû7È©ë\—ˆbbcJÝ‚½½=µðl±mÓ¶²T0]S€³ ÊNÆT&¨A²“ä,R@Õ/¾9þLä„ñí÷lêèñ£,Ë~ÚõÓ2Œ1Ñ›0ÓÝûw%RIéZèЮ]¹vEÇ…{Péf’å)¤Ù˜Ê5Hn+ËEœ ªxñ-.Ø/¾UêF¤R)ºÓœX"¾s÷ÎûŒ­g÷ž"‘(--mמ]ªå9â.¹ø; ì7ÐØÈøå«—?oùù}F•H×0S¾1&¨qJô²—ÈÒw?Â=#W—ߨ Ú(ÝÒâÅ·ÎDNˆ/¾YŠÃ›5mFD'O ""©Tx1°Cçg”uþ~î½ïyû¿ŸwL—†ëØl-§ZÆN "¿oý¶íØ–žž.•J/^¾ØµG×sçÏiÖ762&¢è×ÑÊKKËÅ тŠüøs·±cYöUÄ«¹óæž9w¦' L×0“$Ó: Æg”àeÏ+•er|…¸üF@D âÛg"'DŽç'”è@ß¾nMÜrÄ9÷ø¸^“zöÎö>|ÌÌÌÖ¯Y¯¬“¯ÈΓgåÊ3X*AÞŒïæ}פq¹\>Ëo–C]»:v½úõJJJZ³bfefD´qóƹóæ* §}1m,Ënܼ±NÃ:ΜmkÙºyºmÞ¶ùàáƒ%:M¨,Ï’~ ~!|ä…ð‘Y¹¯*{8PÑt 3)dl.VÌAÍ“'f2¼ò êJ߉Ê$¢\yªŽ‡èéé˜8nbíZµÓÓÓ›4nòÓªŸÎŸ>ïÝÑ[Y‡-UŠJkkëKÿ]šï?ß»ƒ·‰±‰•¥Õ䉓ƒ¯4T³òÌé3»véjh`«,dfÉâ%ãFóhæ‘•íää4°ÿÀƒûîØº£C€Š'΋M“Çzøk¢˜€ÈqÍ­¿t0j«º×ØÈX’®ž“ÛÆÆfó†Íj…înîÊš,„™–îêìSw¯f§sgÍ;k®f¹©‰éÂoÒ·êåšc°¶¶>yô¤Ö3jß®}ûvíµîâ³*›jô 4Kƒáƒ¦Ûl&9bLPCa6”§²ü– ¾s6jÒéȱq9AïÓŽ2ÆDD >"@ ©N‡,]:ø éfÂmÝ¡Æbe€J¢øîÙ¨ÏNGŒ‰Í¹Qº Dä—Ѹ æÀl¦M§å@3AÅ*g(ì›´ýšeµîÕ,Ôr,Ëjî-¾5õNßÕ«^Iû€‹o´ìÕù;ê+÷¾cäÚÆ«q¬Ö‹£¥¾ê®¢ÏºðñÅž—–³.vÀï¹ú±ï¹n}iùéÚ—¶‘«ɦJŸjk³ $Jl)hÎÆ|d¡×°DÇ*XYLœ·%’^‰=ÿþãiÚ¤¹¥…õû·UŸêofFçÛŽAµ¡S˜)7q&¨¡rsX³ÊÀ×÷ZVð—‚ YA™y>mIï ýhû^|`ÊOlÚÃs»Jvº7”o€R/ÒŠ÷ɼ™Kf¨10›©FÓ)ÌÄÃTY¨©ðâ€*E!¯Ä÷j¬œÍ«¼ÞàÀÜL5&°@YÁl¦ ·j¨Ò¬,mêÖ®ÿ>-äÈâsåܶ©ÈYÀè—èp–™yQÆæBKý&D¤|¿Xøm#£¶ñöîT…¾ÆÔ0@¥+œ› ³™j„™ja&€ê&¨rTÍ!7S „0@5Wè®X,ÂLÕ„©ÈÙÃú‹z¦> ï챼…ÙL5ÂLÕžj p„™ªÒ}ü2ÕinýE=Ó>0@•„ÜL5ÂLÕr3T&¢:Ö_ÔG€ ª0Ìfªáf(†‹/<ÏTö(´Âl&€ž‰¨¶‡õ˜à€ÜL5ÂL5 ÂLU‰ÀL„µ<¬§Ô7ë‹|ZÖú¡¹bK,‘BoYÙʆ0@5Wh¾:R€|8L„µ<¬¿¨gÖ—ÇàM;|0ôD•= ¨4ø‹PÝ1X4ð1:yXQ߬LðaÁß-€jiª,õÿžÆB'ëÏë›õG€ >D¸¹à‡äEä«:íšÖi×tÊ·3+{,eæ}NjýÎÍܱg./±T¸ÓÀÁXèÔÁá‡õO64„| ð  š3ØZê7áÖÎ x†•=Pg,tò°ž\ßl¢Kð¡«*ÉZöšBDÿû~¥oϾEUÛ²gçÊ-ë‰hÿ–]í[¶®¸ñ|°\-G»ZŽ®ìQ€z|³öß74ˆ»È@õPåÍ-ûymvNve ÜYè5jd>1&¨6ª\˜))%yÝÎÍ•= (™ªf²¶´"¢ß÷ÿõìEXeJ j…™ôðq²w”+ä ×.cYÜ ÞÏÇ s€ª¢ª¤çÈd2¿)3f~?/èÞ­cçN÷ïÞ»¤-H¤Ò¿ ¸øßó—/2²3­-¬Z6kÞ¯[ïž?áñ´ÄÔ^D¾úxX":þÛþænî™YY›÷ì8x62&Z$=½pK (ëüûë¾M=$Ré¾:uìEäKc×¾5Á»u{®A…Bqú¹=‡÷= {j¨oèÖ°qÏ.Ÿí3PkïD$WÈ/\¿òß• ·CïÇ'%äææ9ØÚun×qÊèINö%=}¥ìœìfÝ:Èòzuê^ñîllh¤ûá×ïÜœ±ø›Ää$eI|R©À³§϶hê±eÙºb7i™é± ñ#¦O|É•4iÐP-’œšòôÅó©óg¿ˆ|Å•H¤ÒÄä¤KA×VÍÿaD¿Á©éi³œxý2·73++>)!ðúåO-ÿf‘Zr…üTàÙõ;·„G¼T-xq(êàÉ£»×mkÛ¢•î§¯ÊØÈ¸e³æ·BŠHHN´³¶UÝ|ï¶L.'¢Ü¼ÜÛ!÷:¶n§º7#+óÑó'D¤Œ)•ú ëry‹ræÒùÙKdeg)KB? yüðð©Û·l£K PªZ˜)‡ÇãÍ›6{ܬ) ɉÛ6ú ¼~ù3¿é\ô¤ESïÖíëÖ®óðéãÿ®]ŠŽ}}ïу~“†ÿm¿£½ÖÓ“VlúéUt¤£}§¶óòòê9×U«óß•‹'/œÉÌÊòpmúqûÄIàõË\ÈiñO+<š¸µÈ/<⥳SíÞ]» ø‚k·ƒî> !¢?ì7hDãú U[»qçæ´ïæ‘žH¯K{ï6ž^6–ÖÑq¯Ï\:ÿàÉ#±D2{É‚KO J».¬s»Ž·BîÑõ;7ö裺ëê­DÄ0 ˲—o^W 3߻ͭXônS(Ìô>WX—Ë«ÕÙË_|;S¡PQ}g—.í?jX·^xäËwn>xòèÁ“G%¹$PŽªX˜I"&¢.í¼;µíp9øúÎ}»‡öØ n½w˜œøÕ¢o¸ȬϾüzâTnן~Sf|ýý¼sW.$¥$¹`ö?;þbF³…u;6Å&Ä8tñL}=}­½ì;vˆÏã/ûfáèøFf>}äôI÷=æJûN*“Ë?1vÁWsù<>ÍVL›»tááSÿÑο÷¬Y°Dµ5ïÖí{ÜÍÚÒú« Ÿ«Î6š2jâ”ù³Î]¹ûúß3'õî¯óõ+¤SÛŽkù™ˆnh„™®Ý "¢1¾Ã÷Þwåæo§:ðÆÝ[DÄ0L¯·s…Þó ëry5%¥$Ï^2Ÿ‹1è7x©ßwB¡Û¥P(öý{hùæuª³œ U­à9b11 óÃìù@&—/üI§\à›wïà C|Ìúlšj’ c#ãí«6Ôwv!¢»C.×ÚBlB|÷N]—ù-,&blh´kÝÖ1¾Ã•a#éc&qÛ –]öÍÂE_ûs1&"âóø³&}Ém?|öX³Á­Ë×/õûNmE›P(ô›2ƒÛ>{9ðç^”fMÜÌM͈èú`Õò”´Ô'áÏ Æø#¢GÏŸ¤¦§©V¸q'˜ˆ<\›š™˜* ßó ëry5íØ·;3+‹ˆ:·ë¸òÛï•1&"âñx£4l´î­@¹ªZa&‰TÂmÔwv™Ï-®¡ÑÎü‰¨‘§w 7w3S–e5óPI)ÉO_¾ wfúðÖfxóaYöЙãÜö¬o':VE ”¿Š•fÒœ¸4ñ«qÜ4ŸÅkVfÊóÒO…¦={ÂM´©[«¶³ƒc¡-wiÛžÛ¸yï6wV>mšûulñ,Ì,ŠOvXYXQbrRNNNñM)rO_¾8vþ4w³EDG– $5uRìÖ½;êÂëwý‰¨±gCר³]»}K½W½0Sk4Ó‡p †÷UHP\B<¹»¸Õ­é¡Ó±zÁ›¥Lá^ŠÜL}‡PÞ*VšI“¡Ô`þ÷Ó‰(*6fíŽÍy…kªs1.ÎEµ&K¸¥©3åò¤ÔäB*ˆD%‹SÀç Âb*H%y·‰©ØBÒ[D»io—a}kµmÜeXßïL_·ów.³–•U²¨8mšå¥™nÞÏ›¯Ä²,—fjâÙ€ˆšz7"¢«wnª|\BJ,7òôV·óá#\‚á Ó©›“‹®Çê…\™¼ëñ@îõwèOú ¼UÜ4õìØµEÃ&D´eïÎסÁD$3”¬–’šÊmØZYÜ«fg÷´ä””ҳģ"FNû¶Y¯+6¬zúòEíê5‡ôðÔÙnØQÔñtbgmSÃ͈nÝ»Ã%’B#Ãã"Aƒz^DÔªq3"ŠˆŽ å¹yÿ5õn$‰Õíèe„SÓò:µ·±ûðÖ üýrè±ÇÍŽ=n~ò¿¶úŽô b=i.†aOûéðþJ¥råÆÕ¿ÿ¸Æ¨°4“±‘·WLkÑq±Ü·0¶Þ½ ~ÝwÌД´T÷õ/?ïÙK qŠŸ!¥½¶Í[½ŠˆŽ wqpº~ç5ªïÍͱªS£¶©±Irjʵ;7Ýœ\’Ÿ¿ $"Ÿ&Í5ÑËHóf®å[¡*¬\U¶R•ID,«Ôw, z6Õr¯ñåÀ¡DtæòÅO ͤžíZT;ÙŠìȘ("’J$¦&"Í4cù‚”´TŸïûÓúy§kæ˜J‘ú¾¹{þ%"ÿw‰¨e£f\!ÇkÕ¤9ݺ—ˆî?zÈ•·nÚB³½Œ°…™9·Á5 •Á›åbðȦ*©¢§™ˆhÊèo-Í-ˆhåÆÕ²ÂÖfòò¨'30$¢'/žEñh6¿ëW¸»ÆZ4jÆçñË2^­Ä%Äÿð€ˆš6hÜÁ§ g6ón,ŠˆèáY–½ýཹWŽÃ-õÍ­üÍ¥¢LMêÔ¨­Ùˆ^FØ£zMŸODÿ>Ç„&€J¥¼•Bš©*ªi&#™ÑÜ S‰èæ½;÷¬ zwéNDJ¥rÝ›ÅÂ5åªrݺžÛЭWY«­äÔ¼Õ‹œì îÍgffÉK¥#©DÒ¬Ac"zøß£ÐÈð踉Xâ]·¾º‚O“DŸ˜ð:4øÁã‡DÔªIsï†^FX"–´lÜŒˆ²²³vÜ[h§Ï_¿,•¾ ”¨Ÿ _ Pê*ÇO½ï§=Õ÷&¢µ…å8ˆè»/ÇrÓmö?´a×VõsÓˆ(Cž9~îÔÀ WDäéQ·[»Îåò{¸:: "ºyï÷P9µ»ïwÖ7.!¾àQ|~Þ,¡,…Bû¾Ú4kIDŸ?åfjâÕ›ßÄqvpt²w$¢ÿø?|ú˜ÞÌoʧìF¸˜“ùÙ0ncãnßS~ç4w%¥$1iÜéKçuê  jÊȉŠÊð̸™qC®,ä߀Ң¾ZdpÓ\•T¡—WãñxK§ÏëþåÀB“/Ddoc»æ‡•_Ïü>W•»rÓo¯_nÝ´…³½Ó“Àg¯ýFD¦æ›—¯Î7OG_„Ba›f­.ݸ>ðÛ#?jokŸáÚßÇΟæóùvÖ6Q±1ù޲¶°â6î>¼¿ÿ䑞»r+y¯móVËÖý¢ÈQlûs7½{ǧu“æ{ܱÿ.áåSXš©ìF¸˜“jߪM÷]NùËVd3wJçsí{6°±²~öòÅÁÓÇââm­l¢ãòä’vánÌOÜv[‡_]»è7ø¨½Y› 7;'òF IDATÍUI•#ÍDDukz ëûùîCûŠªÐ©u»Ý¿mþ~áÌø¤Ä{þå–R«_»îï+V;v‡š¾¬œ½¨ÛˆÏââž>™¼xŽº¼Q}8xúØæÿmÏwˆTÚºiËkwn¦¥§M[:ÏÝÅ›äU¼ZÕjX[ZÅÆÇ½ "¢–ÒL>M[ì=vÛëdïèìàXh;e4ÂÅœÃ0«,ÏÉÉ9õ¿z‰Û "7q主tÚWת6öýUJ k3Uq•&ÍDDÓÆ~wâ♤”ä¢*´nÚòÚásûŽrš pj>Ãá7ʵ–ëž½{J«Aø(¨ÿØÀMsUÒL=Í?òJ'Í»÷Ͻ111¾;}K¥Aø8h¬Í„„CU„Ÿ:@Ùš<}²ÔTZÔkðƒóÕÔ,)ʉS'ú|ÖÇ¥¦‹™­™W¯/Ç|ù0à¡6Á”ÖÚLÖÖÖ_úÚÕÅu¸ ê´ô4©©´™OþgM@Âb6S•V™–¨¼†‰DË…B¡Ní¤¤¤|?íû¿üEDÀÌÌìEà‹/þ:ðצu›¾þe!]—Ál&"Zókþ%““ËuÙ¨€XRqš·íCÕÙLå¡wÏÞÉ1É_»}wëÔÎ[7>èÓÒçÂé ±á±¡¡ÁσûõéGDßMþ.,<¬°ƒÊ$ÍTP’v@€f3UiH3T&Ý>íæÍÿÜÉs>-}¤)ÙØØlÿ}»©‰©R©¼yëfai,^–±a6¨Ÿ7‚µ™ª&üÔ*™zuêñxïü .‹íììˆ(%5¥`ýw¦¬³ìƒŒ7º~£úönö=úöØ´e“J¥RïOLL´w³—šJ÷þ¹W³‘{÷ïIM¥æ¶æáá\IûOÛKM¥ë7­'¢‡HM¥]zt!¢€Çê•§ð:€ªçÍ·Z¸i®JBš  tðˆo*qæ^†BK}‡UËËW/Ÿ¿xND-š·(lÞy,KÿÛ~¦m§¶üùGDD„H$òûÛoÊŒ)Ÿý<++‹«cnnþÃüˆhÞ¢y™ê&.YHDÓ&Ostp,Ø¡¡a5·jD$ «¹Uã^F2£R=Q¨èޮ̈́›æª$¤™J‡D`üyí­ÜËÇqÂû( …âàáƒ=úöP©Tãǯ_·~Á:ê?ñ®e¬\¼[,oÝ´56<6øyð£{x78yæä¶ÛÔõ¿ñ•·—wTtÔª5«¸’+×®øýíçèà8iâ¤BÃèöi·'ž,Y¸„ˆOÂç‰yŒˆÇèöœø8 ÍPŽ?*³å{mÛ±íýGa΂9^ÖNÖÿž•µê§U?¯ø¹ˆº )²Ø¿VÇÑæõ›‡ &ˆ¨º{õ}»÷ ‚_Vÿ¢P(¸Ú|>Í/kˆhõšÕáá,ËrS™V,Ya 5(qÀPt­}®O½úÖ¿×¹Ö }Çz€4@9É-@½Ff ¼|ù28$8;;›ˆLŒM†Ñ\bI·ç?Ó£•µëºp¥SsqviãÓ&&&&(8H]Ø´IÓÃFȳä /¸àwáöÛ-›·ìß·‰£€ªi&€òЧWy²<ßkÌWcJÜàž{ž>|êwÖoòÄɱ±±“§Oî?¨?—u*€!¢ÀåDÔ´e¦Àzœn®nDô:èµfá’…KLŒMöýµo┉ ÃüºòׂhBš  R‹Å®.®-›·\¾xù?·þ±¶¶>wá܆Í ©Ê0D”§$¢Ý[Ϩ§~ùîô%¢Ø¸X̓¬¬¬¦NšJD!¡!_ ýÂÛË»N *5¾€å`ï0gÆœIÓ&mÛ±mÊ÷Sòí}óœ9"¢šN ë·*´‘zuêi¾U©T§Ïæ¶cãbY–Ål&(^…H3½xýòÛySã">ïÑoє٥øWlÙµ ú²zÛ†ÕÛ6ÑÖ•k»´í ïp* ÏzžDœ••%‘H4wÉ„ŽnÆÝìí.<¥g^^õvlÞ¡Mƒ{ÿÚëÛ¿G×Μ;süäñÞ={—Ièð±¨7Ímûs÷‹×/3åòþx\)ZЋ¢V މ&"SSS±Xœo—A£6?õm?ˆîÝ~®T*ßÛKJjÊœsÁË~\ºh)M95-=­ø£ø|>åææjqù©Ø÷G\…H3¹88q2CKs‹ Þrt\ÌêmVoÛ˜œT* Vj €r6cÎŒUkVåK6±,»c÷"jÔ QQSwûöê+3”½z½nãº÷ö²tÅÒ¸¸¸1_q¯æ> ß€¦MšFDF,]±´ø£l¬mˆ(*&ª¨gÞ*#'êVÔ¢“AŸ±¤ÃQPUˆ›æÆildÞ§Kw#ã ÞòËà×ÜM[½:u375+•6+/Œ@yŠŒŠÜâ»E¡PøßöŸ1uFï</(8è‡e?\ð»ÀãñfLQÔ±æææ ç/œ>kúÜ…s£c¢§MšfeeŲlpHð†Í:uèÔ¥S®æ“§O6mÙ$3”Íž>›ˆ†YµrUë­7lÞ0tðPîî¼BÕñ¨Ã0Lbb¢ïNßÑ#G˳äÙYÙffEþ멌 ˆß˜|XÅæQPÊéj&=J>: o"Í$†÷TYZÆ´M -=~Tf!+Xnll©MÍ_~üeܘqGö5nÔ‰Ó'Nœ>!DBQ¦<“ˆÁòÅË[·j]L ãÇŽ‰‰ùeõ/k7¬]»a­µµufFfzF:%''si&–e'O›œ››;yâd+++îÀF 6bçž§L¼töWølh'G§ý8t`┉ /ÈÈÈ?nüŠ%+ ÖÌTÆ>Šß˜|(—U¨ Æor3îÊ0übN*² ‘fª\’RRôB‚ÑÐ^¡‹©r ¹S¬ÐšÜrí?iÿï÷ü±çð±Ã¯^¿JMM­ëQ×ËËkÆ”µjÖ*>†a–,\Ò­K·]ÿÛõàთ/_:99Õñ¨3dÐîŸvçê<|ðÚkVVV'LÔïADÝÚuÚ¼â·|{Y–õ»qeß±ƒ¯CƒÃ"#ŒŒj»×ìÖ®Óç=û …Â’µ¬.?滯A]Ï\Uîñ gþ:qøÅ«@…2§NõÚÍ6þzèH™¡úç¯; í£Ù8×§}«¶;ݨ¹7S.ÿãèþӗο ~-Ïʲ±²nѰɈƒë×®[Lœ'¶ÿåU§^jZÚ†Ý[O_:&Šžý}W hSçÀ©£S—Ì%¢¹ßM;tdÁŽÚ}ÞãUHH(zyíAÁÞlý£Q}ïÔ´´=‡ÿ xúdÏá?÷ü¶¥†›{ š-Áhœ»â7eÉ\Í'g?üïñÃÿ:}¬Eæ%ˆô";7éqÂÎgIû”ªLÍr†x.Ƽ,¿5—ä_¨˜*zšé‡Õ+¹ScÏ_ôìhgúàIÀþ“G‚ÃC³sr>°}¿ë—çý¼$*6ÆÝÅ­C«¶2CÙÏÎ^¾HDO^<ÝòÈ—Ÿ áj:Ú;ì]·ˆÖnÿÝÿÁ]"úyî[;n¯™ÉÛÇè\¿{kÄ”orrrø<þ Þý›y7651yþ*p÷¡?Ã"Ã×îØlaf6rà°Bã‰[±þ× °{Û6ÍZ)Šj.®%¨S2?ü¶2:.†ˆZ7mÙ®Ek¡Pøï®ÜºŸ”=ø»Q~ûŽsì+ÓÑ8õÒØÙ“¸‡a»»¸}Ò¢u ×j/C^ߺw‡Ëy•ÊÉ@™ÊÎMy’¸óYâÞUÆ»{£Ž^Vßš‰kè'2(3:ͤÌÍ=pê(Õ©Që¯ ;¸[ä{6н÷øcüïßéúIÇìbﱃ ÃÌ?eìБêçæüyüÐŒå ˆhë¾]# ææÚJ |š´ ¢}ÇqÕ{6pwÉ?É?!)qü¼i999–æÿ[³µN¼ÕX?iî3´ïÀQÓÆßºwå¦ßúwímldT0žU[×GÆDí;pᤙ±¤Ð˜µ©S2Ñq1V–«æ/oÛ¼W2‚'§¦ û~LÀÓ'±ñq¿ùnZ8i&•åhÄ%ÄOY2‡Ë1 î5`éôyê[#U*Õ¾c—oX¥9Ë *Enê“ÄÝOÿ—£JwãlÔÎÛr¼™ä=K•@%Uø‰+ˆÐˆ°¬ì,"jìÙ0ß2Lö6¶ýºöúð. ¥ÛÞðÍðQšÏfØ£¯“½#…E†syÖÞ¦=¾I)ÉD´zÁ uV…#30\ ôN¡Jÿ7ná—â7¿›cbœdízºíoç¸9&€X…N39Û;rK#]ö¿–œšR]´mÞªƒOþÕx<ž—G=n;*6FûÖrU¹ûO!¢†õ¼ò%k8µÜkTsv%¢À W…¶ àó|?S3çU²:%SÍÙÅÜÔ¬`yýÚu==êQjZÚËà×Z¶V‚Ñ`YöЙãÜö¬o'º‚UQËZéŠUFe<æ^IY¡ú \å¨Òâ7zÙùaü&Å»“˜emz¸ýÙÞi¹ÄC_á@ù¨Ði&@ðY÷>DÞmÄg;ìÕunQ‰Y™[p1ñ±ÚõøÙS.VhV…ãêèLDêÕ»óiÓÜÇÙÁ±ø^´©SêÖóâ6B##´<¤£ñ*$ˆ[}ÜÝÅ­nÍJv5’•›v]z éýYýÚuÊtV‹D’w?Z®J¥ýQaQáÜÆêmWoÛXLͨ˜¨Âû‰Þ›uJ¥5·®å!%ðèHnÃÍÉ¥$Q@9Rª2Ÿ%í{œ°3;7)ß.{ÃÞV¬¤^z ô%W•}æYnÛJÖ´M5_ýÆ寢§™|þo W|Þ³ßÚ›oÜõÏ”Ë÷=°÷èVMšÏŸ8#ßr?z—’š÷-.Ã0<¦¸™b¦Æ&åQ©áî^$"n­%m”`4RÓò±·±+I”P.”ª¬çI>NðÍ*`²5lÖÀr¼µAC½UËËý/K*–X"6ï±oö²BžLû3r¢U¤$–}Û8±,±,«Êkœë…eYbE.žTË–“³_É•ñD,K*"–eß6ž÷_–}s ¬±ÈÍTì®eËiŠÐèÌ;o‚¥¼¡P¿Ík6%åí£Ó¯îjÙ~©H¾¿|\Xz;Qƒ¡ ºà ”©Šžfâ´hؤEÃ&áQ;ìÝ{ô@zfÆ»þ½¾´wݶ¦ÞôÝ[F²¼?h&úvòèoõLéRß+gfbªå!% ©·‘˜œÿº ÊR*•¹ª\}GA ‘H$Îe³Ÿ'ýõ8ÁW®LÈWÁZê]Çb„•Ô‹ˆÍȉæ®r …¶ŒÖwè§*‚sTò¼ ò¼ëdR_-«¯Æ¹ÿšŠªKæZ¶œœý2EñšåÒo/ø5'öM¢Be"rÕ>M–‘”zFj¾ ¹$EÞ.bE<£º#µl™ˆü£—²¬R}ø›qàRª7]äímb3C*°Ò²åqkãåØ7iq 7‰·‘×5éjÜYË–_& HøýÍ8FnE#YC,˪X"Y«Öö?jÙrröËc¯ûR^&å=øŒxXí{Z¶LD§ƒ‡d*µ]'¡«Ëní?!¶¿J9¦eeOËq ¬&hY9NþèfÔ¢÷VËJãå}0Òâÿý]È“ŽJ•æ/j¤™ª¢Ê‘fâ8Ú9Ì›8ýû¯Æ­Û¹eóÿ¶+r£¦Oð?îgø&7¡w¶öÜÆÃÿé%þ›uÁuzœ6BÂóÖ´æžÁ§Œ†…YÞCd7TA{öo9uþ°¾£ {[Çoft|”à+WÆZ!Vþolø¿ù ×¼%âk{Y{5bFBÖZVnëð««q-+¿N9ñ(AÛIû5LûkŸDHË »»JËÊ2¡½Ni¦ÉXVÛ £·Õx)i›fJÈz™qKËÊY¹ùSŠÅP¨ÒÒaZVÎÉÕuÍM­rLeÕ% ¿É×¥åŠúP¨âÞLÛ$"bн©>V•ï§n$3š3ajß.=ˆ(%-õο:|UU*øü¼AËÍÍÿ—Ÿ—G=™!ýóèAjZZ9FD–æ–ÜFBR!³X–Uää” Ù¤”dÿûw¹ífïN+ÝÑð¨^SÀçÑÏ1¡  BIË »óc¾“÷%é”(« ò Ò²æ}Ú5­Sã#÷Qf1—å±,×-TvPn0›©ª«è³™X–-ô»ïºõœ;ID9%Ê›|+u*§@D ôîÒý#ûSÓÒ–¯ÿåÇÙ?”slvÖ6ÜÆ£gO î]³}³ö xkÚºoWzfµoÕÖÜÔLsW鎆D,iÙ¸ÙÕÛ7³²³vÜ;yôø|rU¹Ï_¿,Á)Àð xŒ@Å*5 sTEÕç”]îC·–uù6µ cfË2÷¡[ãÚ·Ìè6Ÿ'óÍâ&Û0D¼7CÄ0 CÄ2 1Ä0ÚßåGDžÔRZŸˆû»ðM;y?Ù¼·ofø0ZúæA{DôÇ‘ý›÷øÇ›8rl¾CJ}4F~6ìêí›D´q·oM·êÝ;¼½!")%yÂüé×îÜÔb$>N&¶9BQ¹Þ7”.bUDDR¾e_÷Íñ[_¥S±êïx¸`•±ØUÄ3Êw¡ËctøKß“…´®F šWøÄC ïM’‚LEÕ´oÙÁÐGÄ3~“ø ¼k~F£å79 †ÈXä¦}˦b÷vŽ¿½½ÂÏKRðÞ†­qýÏ牵o™ˆº»îãÒ1oÆkŠˆìml×.þiÌŒ‰¹ªÜU[ן»rñÓO:Õ©Q‹a˜—Á¯oüãÅÿFóMþÚ¸£,J$Ãû}¾i/ ›ôõ€n½«»VKLN:éw64"¼A]ÏnîûO)êpEŽâ7ßMNíÒ¶cµââoÞ»£NëL=¾a½ü_²•úh´oÕ¦{‡.§üÎe+²¿™;¥ó¹ö=ØXY?{ùâàécq ñ¶V6Ñq1¥>t•BýN©föå:÷ì뜬¼¿eB‡–v‹<-¿~œ°íeòÑ\Vñ¦›©Œ•+ã:xYŽ3“”pÎB=‹Q¥r!¬ –ÑÃïÄ|³2J"‘¹¤vµ,àIÞ_ ª0õdí—ð༻6f3UE7ÍÄ0ÌšVÎýiÉõ»·< xð$ _…–›­˜µ¨ü³¶´=è‹M{|Y–ݺo×Ö}»ˆH"–|õù0±HLD}>ùcݶïÎŒ‰}òâÙ“Ï4çñxvÖ6™Yò2Z¹|ÌàÇ/œŽˆŽR*•?¤.ÿô“Ž¿Î[º}ÿÅÛÑçS“ƒ§Žmÿkf¹€ÏŸ6v"—9ʧÔGƒa˜Õ –çä䜿z‰ˆÎ_½ÄmPÞtªq=:vé<´o FJ…LhßÜvA}‹¯'ø&Îeó:Á’*$íBHÚEg£ö^–ãÌ%úJL½ö<–ïÝi.Dˆ4SUTqÓLDäæä²wݶ‡ÿ=>váÔÍnGDGe+.ŽNÕœ\>ïÕ¿]‹ÖúJŽÎüf’‹ƒÓ™Ëž¿z™’–âhçÐÄ«aFf&—X!¢–š^;tæÀ©£ç®øýø<9%ÙÀÀÀÉΡE£¦_ôìêè\v±Yš[œØþ׆ÝÛ<~øüU T*­WÓcX¿Ï;µnÇ0Œ™‰I1ÇËŒVÍ_>¨gÿ¿N¾ÿøaXd„­µu›f­¾8¬ºk‘÷&”úhHÄ’­+×^¸ö÷þ“G< HJI¶2·hÖ ñÈÃÔõÌg~ø(À2Ú6³[ßrÌ£ømɇÔÉ&"64Í/4í’“ì/«q’ºúŒJ(o2f3€®4—8ÄÚLUS…H3¹»¸…ú²d5Ç«N=¯:õJ·åâ{$¢Ùã§Ì?¥¨½<oHŸÏ†ôù¬˜$bÉð~ƒ†÷ô!qêZ‡cin±pÒÌBw}Ñðýu ÷º¦Þš¾û8¹â•úhÃ0Û´ïܦ}Á]†R-ÇÊšÀº™íOË1¶¿H> Te½ÙÆ¥ÿ–~ÙQÖÚËòKiy/¤B…ÙLPbšŽÀï* ?uxK¥ÊÕwPùHVMlfös?W×|„€'̠ͯ§_=<øbظ8ùC½Å:Ãl&(!ÌfüË¥@*°hl3½¿û¹z_ xï¬?‘~ýtðÐ ¡cb3ïë+<ÐÞÛµ™p±:ÃÚLUþå€R#˜7²ž2 ú¹ú£…tTLæ=}…Úxû¤9†¯ßH ÒÑi6Óïë×[tïØ¡d}efdÌŸ5³¹·—‹µU—¶mïßODãG®[ÍíÏÿíyïáeäOê#€4”21߬¡õ¤þÕÏyZŽòdš»¢2nŸ q.ddtæ}…Å{›fÂÅèª×fýÅðÍëÖ½ 422zøàH$Š‹Ý¿oolLÌîíÛË´k(þå€2!æ›6°ún@õó^–ãD|#Í]Ñ™wÏ…|u6dDT†¿¾Â€¢°¬z6.*“×®Z¼÷ÕûÓ.êCÜ»7fÄ>9Z˜×s¯6¤¿#¨Tª|-Ïš2Y³#YýêîZûL›øÝÓ'ï< ©ÜÖfzúäÉ…³g‰hÏþ_½މíÜ­›•µõÈ1cœ]]¿þ7ÝÝÎ IDATv|Ùu Å«Oš€•ˆoìm5¡Žùˆ§Iü—¸[‘›ªÞ“yï|èhk©·—Õ7ö†­ô$hÂl&€JŠÇðDb±f‰";›ˆÿöX‘PÄm,˜=kÓÚµêò˜èè gÏ^8{vóúuÛÿØëà蘯}±DbnnNDÙÙÙ1ÑÑÑQQÿÞ¿¿Ë×÷ó!CWoÜ( ‰¨ÜÖfzñì99;Ú½;I¤y!ùé·5e×)hi& w·Pÿ'ï¯Å0B7“¼k$kÃZú  ¢ñ¼,ÇÕ1ö4q³s“Õ»båÿ^k%õô²üÖAæ£Ç €ãlÔA‘›ÊR®˜oªïX@-||"“4KzÔ ]½aàaÃóUÞ·g7—c5vì°/GÚ;:½zõàÞ½k~»ÿÏ?Û6mZ¸lY¾C:}úéŽ?örÛ¹¹¹/_ìòõݺqã_{ÿ¨UÇã»ÉS¨g3%%%‘™¹yÙu%ƒ4@éñeÝè; € MÈ“yZ~ía>ôYÒŸOvfç¾ýS8Np1웾î'E.zŒˆ¨¹í|}‡enÏÎD4bÔ¨W­æJÌÍÍ5i2xذÿíÜùÕØ±ÅÎçókÕöXþó/D´uãÆ[¶L˜4™a#4“Öá&EˆìßÛÈžÃT¸‡Ù}øIUv˜ åJÈ3¬o1j@õs­§Jo¿„t2ú9&€rÀ²ì£‡‰¨m»öùvÊdc'LxsÜûõéןˆÂBCSRRˆÈ@h×¾Æ_jèPã@]Û‰š5/_ò5|Xýêî^5kŒ2øîíÛ2#Yá=|ð`˜1ͼÿä±c§OœhÖ²e¡•·nܸhœ‰Tjll|ù’ßåK~W.ùmÛ½G,‘4jÒ$666,$Dj`P§n]"rryÿ7U¡!!3§L>~ø0÷öU`à«ÀÀG'/\TÏŠzoï%;©*³™@oúÑúßVoZ»6;+«Äí¾xAD<ÏÒÒ²¨:GøiÙ2–e?2ôÖ¿ÿ†'&]ûçÞÀ!Co]¿^°òÙS§æÎ˜.‹×mÙóäuÐí‡^ œ=uj—¯/Õ¬Uûìå+§L%¢šµj½|åìå+㿟ôÞP÷ísþÌ™W­~ú_Pð”™³ˆèέ[7®]Õ¾÷’T•‚4踛ôÖwUÈ÷Ó¦·ëÐQ¥R-˜=«©gý-6pw½éD©T®ùõ"jÑÊGs¦¦,¹|ñüyD4hØðu[¶T¯QS ÔöðX÷ûÏÈWYž™9wú4"Z³qÓ ¡ÃU«^}Ç{Áš_Q(º©ÆãóŸ;?jìX KK+këYóçשWˆüÎ×µwNªªÑ*ͤR–u>üðñ‰DûŽY´|¹¹…EdDÄÜÓëWwŸ6ñ»  ÷«ÈÎ 9}âD¯.ýoÜàñx³æùè¿ "ÂÃE"Ñì ò­Ø]pÔÑCÃBCë{yõê×O³ÜÉÅ¥Uë6±11!Áï¯(§LmШ‘ú-Ã0-}|ˆ(*2R×Þu:©ªF«4“X†IOPE‰eîÉŽÏçÿ~ÒÃç/ÖlÚTßËKž™¹Ë×·™—çÊ¥K ]ñúäÑ£ÜzÛæf ëxŒôù]k›-;w5oÕª¨^^<{JD^ Ú;8¼7¤›×oQë¶Ÿ|„œ‹›+¿.yš‰ÇËŸÙ°´²"¢ø¸8]{×餪­–ge‚ªŠá!Í-‰T:䋃‡qåïK‹çÍ{ôðá/+–+²³ç/Y’¯¦X"177'"gkgçìêÚ´Yóa_~)‘J‹iÿųçDäæVM›`¢##‰hãÚ5×®)´B\lŒ6íhI ·†·N½ëtRU ÒLÅ)ÅøØ0 óIûm®·[4wΦµk7®]óõøñê§Èq:}úéŽ?öêÚrŽ2‡ˆø­’\ƧnýúuêZÁ£n=]Оö½ëtRUVƒÂããRª(ž~¨x<Þìù ~_¿^©T>È—f*W"ŠŠˆÐ¦2×£Wƒ†k6múð®u¥}ï:TU£Õ<%¾€øB\lC•Ã2<¤§࣓•Uh¹@(‰ÅD”““S*9»ºÑÃ÷³äò÷VnÖ²%ݼ~M©ÔÃØ´ï]§“ªj´J3ñ B†*HdÀð1› >.¼k×Ú´vmÁ¥¾O=Ê¥N7mZ*}uìÒE$%%%ýo×.ÍòÌŒ ¿ çóUîѧ¡LüúõæõëJ¥whß»N'UÕh»ê’Ôë3A•c`‚=|lìÛ·`ö¬:ÚÿWhpprròÓ'OV.]:ñ›qD4|äHî)lÎÁÑqØ—_ѼÓ}ÿ=999;+ëÚ•ËÝ;vøûâÅ|•ÍÍÍç,XHD‹çÍ[0{÷ 8–eC‚‚æLŸæw¾l38Ú÷®ÓIU5ÚÞ$”`NT9øØÀÇgÑòåV6Ö?-[v×ßÿ®¿¾½»tYñ˯¥ØÝŒ¹ó®_¹úâù³YS&Ïš2Y$) [;»¥+š7sF¾Êc¾ý66&fͯ¿lZ»vÓÚµVÖÖ™™™ééD”šœÒ¡sçR ¬ í{×餪m'kD< ªDlÈĘ͆a&Lš|'àÑÜE‹5ibai)–HjÕöèÞ«×þcÇ÷>"–HJ±; K˳W.O›=§…LfdnañåèÑßòï7p`¡±Í[¼øÔE¿!_Œ¨ç陞žnoïгoß=û¬Û²¥£*”ö½ëtRU 3c³;·ådY{B÷5ÅT•§äÆëa.½°p˜ðõ@™»÷òÂþ¿¨ßˆÍfö½¦Çx  {7ž:˜Ûöž`f_:ëqjéìëœ,ÙÛ:­ýqGyv ·µ§º'¤…¨ß¶k<½±ÇzŒ´ñóO"–ˆœ¬='ô=\°‚“5D<|cSC(’"×UËj¬ÁÊàO}ЕƷ˜ÍT%}ÐO](áYWФøç*1¡„±ª.Jð³™àƒ¼»6.²ª¢ý© $Œ…«@f‰ R’Yð-ÝB1~ý½»8nx)S“§O–šJ‹z þbp15­¬¼šxõÔÿÄé¹¹ù®MËW¯_-¦ŽúÕ¹{çrø°ï¯¢?ãG®[ÍíÏÿíÑw 3A)4!â™Úñ Lx ¡ÊÜœ ý‘Pã sgÈÇCŠ àwf31ø.¹Ì1 #‰ – …Â|%‰ÄÜÌœˆT¬*99ùEà‹/NŸ=íåéuêÈ) Zæñxb±X³<;;›ˆŸÿöç^h ÅxwFdź֊‹Ý¿o/íÞ¾}аáúç£U i&"bx$–ñ¬« ²RU)ѹªüùt€ „Ç'[¾Ä˜'U¬ßzz÷î%"f3•¹Þ={ïÛ½O›šŸvþT]“eÙ¸¸¸ý‡÷Ï[8ïaÀÃés¦oÿ}»N-û´ôIŽIÖ,©U¿VhXèÆµ‡Áå7ä—žžæfcS·~ýËþ·ßS•Õ|Ò\Åúbem=rÌ¿ ¾þv|ÉZÐaª°ÒI3åµ%âÉ,yRc¾äpíÇ¡*+Í4‡/bd–|3ž2›ÍJSÉST 9î¤}I© ObĈž &€"Uä^  Î;QvvvDDDê5ô|´R’µO¯|Ì—ÿºŒCÕUúi&ψ ‘ÏÈšrsT*%åæ°,K¬Š²3X†ù˜?y _,ˈ †G C|!Ã0x°uãÆ»wn'%$x5hØ¥{÷¯¾þZóùGÝ;v¸sëÖÓà K˽»wíØºõÅóçöŸ´o¿pé2©AÞ=˜GøúËÜö“G¬ óÊ×ýþ;·Š6×ÎóÐ0ƒŸ–-Û÷ÇŽøØ¤‘ ­ãÂsÆùŽkÔÄ÷ìå+ùbËÌȨáä¨Èξûè±kµjƒçÚ|ü굑‘ц5¿Þ 44ÄÊʪs×®Ófϱ¶±)xÈ“G6¯_ÿðþ½°Ð°ºžõ›·h9qÚ4ccãB[^ºò§±&è4ïP+ó4T,–/WG•YÈòþöËo£GŽ.æ(•JºuûÖÕkWÑŒ)3 ÎÞ/YËð`YvëÆ‹æÎÉÉÉ‘H¥ÆÆÆ—/ù]¾äwå’ß¶Ý{ĉfåЙS&?|˜{û*0ðU`ࣀ€“.r*C™ÌµZµÔ””Ä„¡PèàäÄՔɌ4Û‰›3uÚ•¿/qokˆÝëKNú&Ý»{748ØÙÕU³òåK—ÙÙõ½¼ Í1©8rä÷‚_¿f†eÙˆðð[·ž:~üÔE?ÍY–Ý´ní²…  ‰%’Û7oÞ¾yóðý›·ïhÚ¢…–ãVüPh9@„Û­à a ðò–[˲ÆÈÙógÝ=ÜÝ=ÜÝj»™Ú˜zxy¬Z³ŠeÙ1_;z쇴 ™³§NÍ1]$¯Û²%(:æÉë Û¼48{êÔ._ß|•÷ísþÌ™W­~ú_Pð”™³ˆèέ[7®]å*tîÚõî£Çó/!¢šµkß}ô˜{õèÓG³%óç߸vuÎÂ…Çn¬ŸµÝÑÖEhé lм&9t0_§çNŸ&¢^}û"³§MÍ’Ë7úú> Œˆü}ÇNCÃØ˜˜…sfkVÛ¾eËÂÙ³ Åøï'ýûüEHlÜ¥›·š4k:°Oï×/_j9nÅ…–ã„4hÀl¦rÕ§Wy²<ßkÌWc ÖÌÊÊŠŒŠŒŒŠŒŽŽÎÉÉ!¢žÝ{ž;yníªµB¡ðCZ†‰<3sîôiD´fã¦AC‡ "ªV½úŽ?ö ‚5¿þÂMùQãñùÇÏ5v¬…¥¥•µõ¬ùóëÔ«GD~çÎëÔïÙS§~^³vòŒ™Ž.Ö®b¾€!¢[Ñ‘4kªTª gÏÑ{4-||.ûßþlÐ`s SSÓ~nÞ¾ƒˆÎœ<ùâù3®NJJʲ… ‰è»ÉS-_îàèÈçóë{y>uºN½zééK-ÔòJk(i&ÈÃjÞ4Ç`… D6J‹O«Y£&ÙÙÚµñi£ï¸ b9zè`Xhh}/¯^ýúi–;¹¸´jÝ&6&&$8H³|┩ 5R¿e¦¥EEFêÔoƒF†Žà–.z;c®C×&††O=Rg…ˆèÁ½{q±±uëV¯Q³ø6»÷ìeñî¢c»vuptdYöÂÙ³\ÉÉ£GÒÒR e²ï¦NÕ¬)‘J§ÍšMD'MÖîñp¥5€4@éò$ ls¯j¦ø÷*%c‘K«ï¼­Æ{Z޳1hôþ Ü ‚% —‘ïNß/ôT,7¯ß ¢Öm?)¸\—‹›+¿~'ͤ¹(8ÇÒÊŠˆâãâtê·Ï€\¬FšIj(îÕ·9ðö¾9-ï˜+7S‰ˆÂCC¹ÿ7‰¨q“¦fffù*wìÒ…ˆX–½ëï¯Mã¥5€/(J‡'mj÷¥¾£ø F"gOËÂúŠ£g÷žM›4½s÷μ…óöïݯïp ‰ŽŒ$¢k×l\»¦Ð q±1Å·  ‰H×e¼ø¼¼¥Ü EŽÎf=XVEÄÊÄ.C†ÿó{Ž<0cî\.uîô)"êѧ$i&"²²¶&¢°7i¦è¨(z“AËGj``mcÃÕ)’  ÍP™0 ³ì‡eºu:qúÄ[7Zµh¥ïˆ ¢àr"uë×÷¨S·Ð uë•i–† - ¾}ÛRåìêú*0ðÑÇžÞÞáaaÿ=~\½FÍZµk—¬ýôôt"âÖœ¢÷å€ò&X!OT¾f¨d|Zútû´Ûé³§gÍ›uõâÕ‚wHAÕdckKD^ ®Ù´Iß±ñx¼ÁÆ­\ºôÄ‘#žÞÞÏ#¢^ýú•øDD¶vvÜ[î|CƒC Ö”gfÆDGkV†òµ™*ŸüÀ0Ì?÷þ9tä¾cŠ¢YË–Dtóú5¥RYŠÍòù<"Råæ–àØÏ‡#¢Ç޲,{éÂy*éÂLDõ8 €ˆš6oÁ•pç{ïîÝ”””|•ÿöó#"†a7kV²î úq¨:fУÇÊ,d_önöï=¶^zÃ#¢ù?ÌÏÎÎ.Å–¡òêѧ¡LüúõæõëJ±Yk["ЉŽV©Tï­œ“³së¶Ÿ¼ |põòe7w÷:õ´ºq/)))_ɪ•?* G'§î½zq%=ûö5”ÉÒÒR7üö›fMEvö/+–Q×=ÌÍÍu¹(2UÒLz“[U®V±óçÌ‹ÅÁ!Á[|·”nËPñ)Uò‚…æææs,$¢Åóæ-˜=‹{J˲!AAs¦Oó;¾d}Õòð`&11q÷öí,ËÊ33 怊1hø0"š;czFzz¯>}µ¼cî×WŒ=:ðÅs•J1{ÚÔ[·ѼŋÅ WÇÌÌŒ;ßÕ?­\º`ATd¤J¥zòèQ¿Ý=|h`h8oñb϶h8UÒLåmõÏ«åÉò¢^Ñ¡ÑùjîÛ½¯`#NŽNÉ1Éòdùwß~W‚–5=ô\ž,>dx©Ÿ)”«¼ø¢ÿíi©Y¯òíóí·ßOƲ즵k=\]긹ºÙÚ4®WwëÆG(YwŽNN} ¢éßO¬éèàno·æçŸµ?¼G¯Þ2™Ñ­ë׉¨GŸ>ZÕ¤Y³#´lÐÀÅÚÊ«fm›6Ñ”™³úøL³Ú˜o¿¿d‰P(\óë/ž5ª;[Y~Ò¼Ùí›7ÿ<|¤FÍZÚÇù^8UÒL•IhÒñ EXxʹ‹/úÝ®™lbfÞâŧ.ú ùbD=OÏôôt{{‡ž}ûîÙ`Ý–Bf½iiýï[¾™8±zš9J¥w£FöÚk`hØ»"rrvöjÐ@Ë£><äoÿ~š››ÛÚÙõèÝ{ÿ±ã³,àñÞÉc0 3qÊÔ³—¯ <¤Vm@Фyó “&_¹s·…öAjéCÆ¡ŠÀ“æ* «|û;·Í’*<ùlDòyÓÎÖãŒ%î\yÓ-š¶hQL#§.úZþýÔißOV°\$/^ñãâ?jÙN>fffDÔSë;æˆH™“S«¶Çï;vjSÙÓÛ{ömï­Vh´: EQãj˜ÍPi¨Øl{ãv[Ýr(Ÿ«Ë+l²éÄ‘#!AAš4©ïå¥ïX Ì!ÍPÉH„V^ö³>­}ÆÝrHÅL6eÉå,Ë^¾ä7ýû‰D4{áB=åk3TJ¡•·ýìÚV£ŸÅm N8”ËfsåE­ÙTž:·mœ™‘ADßNü¾m»öå”?¤™*±÷&›M»Ô¶[žÉ&Ev6«RQ£&M†9ä‹åÖ5èÒL•—lªe5êyœo¾dSXò™ðäså™l‰Å×þ¹W²cµ|zTLX› à#!Z{ÛÏîRûtÁ5›Â’Ï\|ÑïNèŒ µ@8|dfø¨ Ùú‚4ÀGèm²Éb0’MP>°6@éÈQÉïFíâ¶Í%®µ->Õo<%ž~%<ý C|"¦–Ùç¦b=< J—Thíí0§–õèç±Û‚ºf“‡Í8#q5ýÆ ¤™JGŽ*ëQÜnÛÕ¤ÒLPÅË?OÚÏm;ÊÚ ÍðÑ(ŸdSbf@bfÃcgü‰È¾4b‡Êi&€J#ê¹$%FXž=ªrœ½2MŒcŸ'ý©±‡yï±Bža5“ê·¹löËäcb¾©«qgu¡B•”rÚ@hå$k§.ÌÊM M»¨K˜yÁ ld>êR¹2>,ý²‘ÐÉΰ™º0#'*2ㆉ¨šµACuaª"$&ón1-ÅT\ÃJê©~›¢ŠÍ|`!ñ0—x¨ “²_ÄË[I=MÅÕÕ… YO’²^hwvïcmàm,rUÅË%g¿²5l*¾ý;>6ó~jN˜½a µº0:ãvº2ºÈv‹æ`ØZ"0W¿ÊðÏTÆ:ÉÚ‰øFêˆôëY¹‰.F<‰º0,ío…*M›Ê»Á0.ÆùŒH]šæ§TÉ«™t×l*8õëjüΗ:¯SN½§ñÂbá3bg£Žê·,©‚SÏy2GY[ua.›šæ'æ›Ú¶Tæ¨ÒÃÓ¯¾ \kR¾¹­ÆgR‘›™qÓ@`­ù™”+b2ïÊ„ö–°LeLlæ¿Zô?#‘£…¤ŽúmFNTœü‘‰ØÍL\C]˜¦KÌ~j*®Á«ÙcHÚùbZ.й¸–‘ÈYý69ûeª"Ø\RG󃚘õ,='ÜJê%X© ²ždäþA-à`¬¥ÞšÔxù£Leœ­AcßX]+­L¶3l&ਠc2ÿQä¦Ýp‘ì [jÞ‚y'G•éhØšaøêÂÈŒ[*V¡ùY"¢ˆôk,©´êC#†xš¿ßˆ(<ý*Ÿkþ~S±Ê¨Œ[žA#ua.›q§øÆ %äˬ¥Þê·J•<&óžX`j)©§.Tä¦ÅÉJ–æ’ÚêÂìܤ„¬ÿ´85HåR·9lœæÞleb²ü™ÈÎHì¦.”çĦe¿29ŠœÔ…™ŠÈtEHÑýyš2‘³f$S™®3»J…6êÂtEh¦"ÊDR],°P¦eÉsb¿‘±¤†X`¦~›šõ*[™`*õjüFMÉ T(“Ì êi~P“åÏrTï~PßUT0fÒz|ßÌÉò§JU†§ýtm’M!Á/³²äºžcHÒ±àÄ£Üv};ÖÜÀ³øúïebjfkëø@yBš  Òxuǰü;å ÙúS‰Rý£—êt Lh¯™fRª2ý£›Iji¦™²•‰þÑ‹m k¦™2r"oEýP‚Pd>š—a©Š[Q‹ÜŒ»j^†%f?¿µ¨–Ù@ÍKú8yÀͨE%豎ùši¦ØÌ{7£y[MÐL3E¦ßø'öצ6³5ÓL!iÅo-A-íi¦™‚RÏü—¸»­Ã*Í«÷À”Ã/“vrÞª™fzš´74­$χîê²[óêýIâΈô뽫ÕL3=Œß'°«ÑL3Ít/vUŠ"¨=:ÈZñùoÓLwcV¦çDºwÕ¼z¿µPEªwÓLìµÈ™%èNÂ7ÓL3åªW#f‹\4SÙ¹)W#fXJêÙ»½M3eäÄ\˜Q‚m }ªñ™LË ¿1ÍIÖ®½Æg29û啈iî&½|4>`qò€+SKÐcMÓÏZØ-T¿É¼-rf=‹Q¬'« #2®¢2Kg IDATߎ^ÖÐz2K¹êÂXù×ɇKÐcS›YæÃÔoƒROÄoñ±_&3é­. L>ô,i_{ÇuNFoÿïÿ_âî÷¦ ÕÉy‹½àíOçQ‚ohÚÅî®û,¥õÕ…âÖGgÜîë~ÊXä¢.¼³2!ëi zPý‚¡ÐNýÖ?ziJöë!µü…ŒL]x=rN–2á ÍÿŸ¤¾°×ž€'Zël¸_Ø·ëÏj\R—(Uò‹aß˜Š«÷®vT](W&\ ûF×îˆÈBR·‡Û_ê·9QÃÆÙ6ïì¼M]˜¢º6ÎŨó'Ž«Ô…ñò'ÃÆiÓ…¡iþ«–¢zç2Ü ™än9ÄÛ~¶º06ýæ?aó=¬ÇÖ± .ŒHõ ˆüIûSS«gû}-ëÑ귡ɧžD¯mà0¯šÅçê „/âv6uþÉÉ´«º00nWPâ¡ôØÂu½q{õÛçqÛB“N¶qßneØD]ø$zMTê•5˜Jß&ïþ\žñ =v®u\3Ow?|Q’ü¿îuþÖœÙô*áOz“_ÖL6Ú–\‚N‰òþÕ¸I;Ktø;Z·í2êëiÞ”,JaßÉ: Ê˾hS‚ÉPŰﯗl2ÙkÎx¢7ɦ”¬@}•ÒL¥£Ðë-¶Ðb×f PÜÇïÝû¹0ÈÅ(tp0bPÉĤÝÈʉËUeå+ , „¶z *;Ü4P¡µnÑ¡šK÷×+CªôŒ{"¡¸škÁ0Š»XÕ\T‚ˆ<ÃVöËÄ뤑D`ÞÊ~™”o¡Y(Ú·²Óí=.Õ4ˆÈXäÚÊn‰Lô΂æâZÿgï¾ãšºÚ8€?7 ̰·\8p¡âª«*EÄ][µÕ:ªÖQ±8Z[µŽªÕºªÕÖYíÐ:_·µ¶u/\¸ª‚²‘½!É}ÿ¸C! Áü¾Ÿüqïɹç<7 „ûpι\Ø”\ßÔIÒ¼ƒëík$•xMœÍ[wpo'n¢ZènÑQäjí¨²Ä Õ²~ÛJ衪‰u’´RݯcÝÛFT×^ÒXµÐÛ¦Ÿ£¤¹´ä96´}×Í¢£öÆ5–Z©,€BDlß÷´ì¦º˜5±ÿ¨@–*äY©6wœ \òFs®­ žêj-ÔÂqR±"O-©ÔÚ9´TÀL;—/Êmœ-•àðDª»|Ƭ­óçªS‰Hȳjë<[,(ñA•Ú:Ï.Ѹn§i.(ñAµ¸´qž©ö:[ kµqž©¶ü¶­¨Ag¦é©Eb'j¨ºk/nìçŒf¨þ’ò®sÿQ/e–[j2ûj p+lT/:&˜*i&€šË…€Ž^Í»a¤™ª‰¤ì ÷“Ö§åÝQ+ ì:ö²{ &0¤™ª?•um°ò4hÃF3T+‰Ùç$ý€¼6H3Ô/ÒLz­T 5‚}u§9†á›0¨ $˜À$f¨þ^M™+ïÞIP㩤™0š  jB‚ Li&€€Áh&Ð Ë"ÍP…••` 8}„¼H3ÔX› tªŽfÂàULð†@š  úÃЖ¨r´&˜F{Ù A‚ ^'¤™jå¤9…özPñª+¸a4À›-1û܃¤ H0Ái&€êK€€Ž0š  J@‚ ÞXH3ÔXt£º8á›0(K‘<órôt¹¢@µ &xC Í`"¾E÷Ú³¸mK3Ó †QÏ ESûêڼò –"¾ÔÔá€B¾·ý{R¶s»/Lïòy"“Æ@„4€±ða}Û ,¸ÓèÄAâë@¾¦ŽÊÑÀñ£'©»< $˜àMƒ4@M€IsÕ‡H`ç_{•“¥?ƒÉ­ð†Aš  úc0š  zq¶êhê4ÀÍ#jwš€Jƒ4@M€ÑLPéf¨þwš€J‡µ™ª¿^µ6+XÃgÌL T[H3TÖÂ:¦ª?Lš#@š Œi&0¤™Àf#@š Œi&0¤™Àf#@š Œ@`ꪉByÎé¨o¸mg‹Æ­]F˜6œ‰›^ KgžˆoÛÅ}…©Ã€*i&ã³Åϲ¯sÛ|žÐ´Á&%?<·8‘ˆÌN¦ŽªLš€XVñr“1eP5!Í/°ô"ÍÄcø¦ª"¤™àeš £™ÀH3À ÊIs F3€þf€”£™ŒfýáNsÕß©˜ñé…ÿ±¬‚axïÖ?cêpàÍ…ÑLPH3T…òŒ|Y*1È Z±$ç6ðë €/€ê“_@G¯F3áJô‡/€€yñ¯r) ^­Í„Is ?¤™ª¿’c™XEU–€Š@š  &xu¹È"ÍeÃàPH3T•ºa•ñ{ €4@M r¹Èb4h¦ÊDD a4è i&€€Á¤9(Ÿ‚äÊm†Á•è _Õ_ÉÉ/H3@Y^ý~`p¥ú×@Í‚ÑLP–Åh&¨|yÔÕy4Ó˜ cê4¬³ó·¦ ÊcIum&\)€Þ¦ šó­6XÇm‹ø–¦ @M5¾cTrròo»~#¢-Û·|0ìS‡Pµ xæý½±¤`I!`ĦªüÀ8xŒÀѼ>÷°¹š:x#„Ì‘H%e=Þÿð}µšª%e9|ôpÿ!ýk7¨mëbÛ¼MóQãFÝ¿]~(*“_تy§¹ìœl‰TÒ®S;µr''§Ç|\§vÉ&›$0€ê„!žÈK*ªg+j`%¬eêp êÁh&€ÊÅ0ŒP(,]nff¦W;™™™Ÿ†~º{Ïn"¶¶¶?zôøÑî=»7|¿aÔ£´ÅPbOQF­7ZFFFYO­ùnÍëŒÊ‚ÑL•«_ß~I¥;¶ìЫ —.ìÝ¿·S‡N§ŽJŽMŽyõ0j`ÿD4%dʳØgZ~•hª¢K€§g¤›:(ÒLUC`@àås—O9Ù©C'‰XBDÎÎÎ[Ü*µ‘Êd²‹—.j9–©úK€kÍo¤™ªŒ¦›òx%¾»E"‘««+efej=”!¢˜ÿ ·/HnÙ¦[]· A~Ú P¼š@—––æV×M"•p+j+]¿q]"•عØÅÆÅ* £c¢?ýìÓÎ=:Û»Ú{ûxOœ21!1A­Ë›·nŽ0¶Yëf»#¢îÝ%RIbbbn^î⥋›·i.u–ÖoRÿÓÏ>MJJRVÛ³oD*éÔ›ˆÂï†+·RÞZŽkg݆u¥O;ünøÇŸ|ì×ÞÏÉéG@¯¾þªô Åž’’²ìöÛ;tí`ïjïëç2#$/?Oë« % ÍP…EDF<|ôˆÚû·×Re™¿wg.wùxv|\¼P(<ýÏéé3§>´  €«cgg÷õW_Ñ—ó¿ÌÍËU;oá<" õp÷àJ¶þ¼Õ¯½ßO[~ »¦`ñ ñÛwnoåßêν;/»c×m\×¥g—_wý§±;¥ýÿÛß¶cÛEK=Žx\XXûÓ–ŸÚ½ÕîÉÓ'\ ¯º^öööDdffæU׋{XYZi=evͺ5»wÞùÛÎ{îËŠ/^¾¸bÕŠ¶Û^º|©týè˜è˜8eâÍ[7óòóG<Þ¸icЀ *ºb:€I ÍP%íÝ¿7h@B¡˜4aR³&Í´T.¼×çÕÏ%"‹M6%ǦD=ŒºsýNË-?²yûfeµÑ#G·hÞ"!1aåš•\É™sgNÿsÚÃÝcÚÔi\É/¿ÿ2éÓI9¹9}ûô »–Ÿù 2djHËæ-}úpuŽ?2cö ‘P´iæäØä²ºã|6ë³üüü­?n}ñ,!*áçÍ?[˜[$%%Íþr6W!0 ðÞÍ{ ç-$"Ÿ†>÷nÞãýƒûk9å7ÿ8ûËÙEEEÓ¦L{|ïñó¸ç—Ï^n×¶]̳˜àAÁ‘jõû éwüÄñUËW=‹xý(zöŒÙDtéò¥³çÏj}ङ*×ÁC-í-Õ›·©g[t÷ÅÜ/|šû8y:}0úƒ‚‚•ß®\¾d¹–úyùy¡³fÑÆuG¼?B Q=ïz¿ïø] ¬Xµ¢¨¨ˆ«Éçó׬XCD«Ö¬Š‹eY–Ê´dás‰9eegÍüb& 2t×Î]M|šðx<7W·o|sxÿa®å¼ü¼ÐY¡ºtÇéÔ¡ÓÕóWßú¾½½½T*}wð»Û6o#¢#ÇŽü÷ð?Ã^¢ÌÌÌy æÑôO§/Y¸ÄÃ݃Ïç7÷m~üÐñfMšåäæÌ]0Wí>ŸêØ© ã&888899Íýb.—¹;yê¤a1Ô@H3T:y)™ŠUXXHD6Ö6 è­y¤fïþ½1Ïbšû6çnK§T»Ví·:½•””ô4ꩲ°m›¶#GŒÌ/ÈŸ»`î©Ó§®\½ÒÁ¿Ã ƒ¸g:˜žž.‰½Xm•(>Ÿo@wDÔ¯o?Õ’ÀÞî,Ëžøó„ޝ‰š‡degYZX†N U-—ˆ%ŸÏüœ;µ5ÅC§…¶nÕZ¹Ë0L§Žˆ(>!Þ°j ¤™*Wÿàþùùjq£ÇÜàÎm;Ü~púÄé©!ÉÉÉ!3B½7ˆË:itþÂy"êúVW†aÔžª[§.)WAâ,œ·ÐÆÚæ÷Ý¿O>•a˜ï–}§<ðÜùsDÔ¦uw7wcuWŸÏoáÛ‚ˆbžÅh¯Y– /QÛ6mmmmÕžêÝ«7±,{éJ‰šÔ²fDäèàHD)))†ÅP!ÍPňD¢:µëtðïðÍ‚oÂ.…999ñ÷È#}›ùæd縻»è7`Ïï{6mØÄÕÙ»ï¹ ç§Nžªz삹 ¤6Ò+W¯lß¹ˆø|þºÕëî9øÞ»ïù4òáñx­[µž4aÒ­+·ÞéýŽîÝ) :ìʹ+ï~×ÎÎÎÕŵ_ß~‡öš7g§þWʦ6M4µAý²bYëV­ÝÝݵŸògÓ>;û×Ùaï óiä#à üÛù‡L »Ö©C'í/†™¹Ñ›Ûòth4¹ÏÓFPuÈ2÷=šÌm{XµêâbÚxtt=âÔV(wÍE¶³œ3a}½ƒvËwú±Däéä;yÀþÒ¯=$€êIAŠœ¢dn»@¦~c#(KYwЀ×OÁÈ_¬zV¬È5m0PaÒ±$Wn3¸RýáˈJŽ.d¾ #€* i& Âh&¨0|yT+ݺ[Ú[F>‰Ô÷@–}uLŒfx3zÿ=G ó°«WM€fH3T2E~¡<³PžQ(OgIQþ¯Åß'þÎÏÈŸp@µÐÉÒÂÛÕ¥w—·V,ù&==½¬˜CfÎ"¢…s¿ªøéTÜi ú»œ¸ 2ó0·=Àû¨µ°ü« ÐEfffðàà«×^ +HIIùçÌ?ÿœùgÓÖM÷nÞ+}Èþÿí4`r÷üÅóÉÉÉ¥«)Ši¡Ó6mݤ,)** »v=,1)qÕòUãQ(ó¾žÇ0̬Ïfp:ª÷}ÌÉ*êñ^½NMCZZÚù‹çÏ_<¿}Çö‡OØÙÙŒaŽž8JDB¡ðvøí„ÄWײjÞ½÷ÊÕ+íÚ¶Ó¥Ù„Ą„Ä„Ïþ»|åòM7õ ìk´ ucÜ øèšPRbb¿€Þ¦Ž‚ˆèÁ½{×®\iÓN§¾X–ÍÊʺv#,lÛ¦M{õiܸtµæ-[vïÙóïS§Nÿùg^½*#€ŠÀh&€š€QÙfˬz?yüÕkWm¬m–.ZúàöƒÌäÌèGÑ{~ß3°ÿ@>_䳺uêž8y"/?OY²ÿà~†aêÔ®£Vóó¯>ß´uÃ0ù8ìRXFRƳˆg¿ïø½sÇÎZâ9uúÔýÿî·kÛΧ‘O‰8ÇŒU}X˜[Ñ¢ù‹T þ½NyÈÂÙ;õ:µà àôÄôôÄô¤gIþ¹0tÈP"ºsïÎä×7bQ&“:}J,8üC":vâ˜öú[¶o)·M>ŸŸž˜ž“xûÚí ßohØ afVæû¼ÿÏ™*mŸ€>jo ÷Øò“zT•ƒ¾]½è~jº³°´|«k·ÐÏ¿øîûuå×ÖÙŠµkÆ<ãB‘ˆˆ¾^²DYb«)CºcëV- Žùx¼òpîanaAD_-\¨ZxáÆMÕ£î?ŠMM‹NN¹xóæœùó%ææÉIIc†—Ëå{1rmüþ{CÏ a4@Mð*ÍÄ"Í`$Ñ1Ñÿ;ü?"ÚúÓÖÀ€@®ÐÉÉ)è  w‚žÅ>+}Hÿàþ«Ö®:ùçÉý‘B¡8xø`»¶í†‰ŠŽRV»qóÆº ëˆhÁÜ¡!¡\¡H$êÜ¿pÿ'OŸ”Ò¶ÛˆhÈÀ!jå±D"–”®onnnoo¯ÜÍ2“P.Qj‚ìï“7õ:5'‹‰H,·jÙjû¦íEEEþwàࡃÉÉÉNNNeÅlD—®\ÊÈÈèÞµû;½ßÙ¼móñÇÇŒ£±¦µ•µÀL°ïÀ¾åK—ÛXÛhoV,‹Åbk›õ 4$°_àÕkW?™úÉÝw+’‘1𩾸¯3>ºzÑëÔtáâêŸÀéãGز…¥¥…e‰‰™ææveoeemf&øßþ}‹—/·¶¶ÖXG,‘ˆ%ÖÊl–ˆ„"‘H,&¢ú N›1ÓÖÎ>tê”Ç^<®s—®¥ë÷ °´´:ûï?±Ïžyxz–}~&€ÑLÕ£:š‰Eš À8nݾEDæ½J?ëé¡áÚ¯Ï;}Äbñ¾ƒ/–gºpéBRRÒ þƒÔª­ÿq½B¡ðªë25¤t#^u½4Æ“––Æß)Ý ŽØ—¿b’ž§VÚ„q¸6oܺaX<úâN¿G·ou~ËÌÌìŸ3ÿ”µ8”ÀL0ü½áyùy¿ïþ]¯.,Ì-¾[úEEG>^ßUýû|þÕçe5 ß€œÜœ¿ílÕ²U-ÏZÆ &55•ˆl¥¶· œ4GDbs‰^§vèÈ![[[[gOç];pKk7nÔxýêõÇCD|>?1:Qí1yâdµjYÙYç/ž§—ƒ˜¸»tîBDÇŽ+«q±X<|èðܼÜ]ìÒ+*nÀT½TúÔ£ÕÖꪤ ûèꨂ§ö†‰ÅC† ËËÍÝ»kw%u1~òäË·n7oÙR{5©­”ˆÒRS+) à ÍP 1 Ó·O_z5a¤Äh&®›X§êæ­›c'ŒmÖº™[]· A~Ú P(¨”è˜èO?û´sÎö®öÞ>Þ§LLHL ¢=ûöH¤’ÞA½‰(ün¸r–ÄÎßvª~7üãO>ökïçäáÔ# ÇW_•™•Yº—îÝ%RIjjj~Aþœysê6ª+‘j¸E4À› Ní:ŸMûìÈ# Ñ ýóíîoÑêïW>vXcý¾}ÍÌÌ …Æ[ÂYYYq9¹9z…QXTHDB‘P¿èU(—'"†x¤ÿ©Ç“J¥ü;|ûÍ·çÿ=_‘ÑU›RD¥†xüuú¯ââbo/oÕ´]·®Ýèå᲌5šˆ¶þ¬ß¨¼¼5³—Ë?¿† xuQÁS{ó}!ðûO£bSÓ"âþ8t¨^ý?®[·~Íêr‰ÅDTŸo¬0Œi&€ê©_ß~DôÏ™òòóTÿé]\\túïÓTra&–e×m\×¥g—_wý' OÿszúÌéC‡U»øÖŸ·úµ÷ûiËOa×ì">!~ûÎí­ü[ݹwÇ«®—½½=™™™yÕõâV–VÊ^Ö¬[Ó¹{ç¿í¼÷à^±¬øâå‹+V­hÛ±í¥Ë—4žEÊó”Áï ^¹fe"&@U :wìü¿½ÿãVïÞ±s‡ÆjR©tá¼…ÆM2hHég•K2)iÒ‘­­-efhÈÛêìÕjÐLÉ+…rO­pÿüŒüüŒüÜ´Ü„¨„Ó'NOùdŠDüš²ÃÜŒ¹'OŸXÚ[*¡³C‰èúë)))eèÓȧ½ûÛá·¹©Ä:Š‹#"WW× n8ãÆ ãG8 ù´mßþÎíÛ7¯ëñ±ÑB(‰Äb›n=ÞÞuà€X"ùvñâ+/j?*#=ˆlí팀± ÍP=ù·õ···/((8söŒêh¦+Wneegy¸{p7câ9~dÆì"¡hÓ†MɱÉQ£î\¿Ó²EË#ÇlÞ¾YYí—ß™ô餜ܜ¾}ú†] KO|25¤eó–> }ïݼ·pÞB"òièsïæ=%ñãæg9»¨¨hÚ”iï=~÷üòÙËíÚ¶‹y<(8"2¢ôY|5ÿ«³çÏÎÿrþÝwÏÿ}¾²^,£âñx\÷qäã²ê|:ùÓUËWyzx–~ªAýæDv=L¯~ìˆ(-#M¿pU¨Nšc W ºœÚë§P¼˜ ̲¬\7S¡Pœ8uBËá,~çî"jáÛ¢BqWLeÄðf¾¿o¦— ë½~|¹j×­;þ“I,ËΟó…öš™Ddgooô*i&ã0HÇøâo×™cêpH ½D/æÍ½J3þë+‡8ååç…Î %¢ë6Žx„@ ¢zÞõ~ßñ»@ X±jEQQeegÍüb& 2t×Î]M|šðx<7W·o|sxÿaî(-233ç-˜GDÓ?¾dáw>ŸßÜ·ùñCÇ›5i–“›3wÁÜÒG9~díʵ³Bgy{yWä6í¯Yaa! øåü\hÄçóûö!¢½û÷Êåòrë+5hЀˆ¢£¢ è”ãc7b¤ÏÝ}Â?ht³Žuou*rj•äZصçÏŸ ‚”¸nD•ò1nô8z9Ö©,û”J¥{öíÉÎÑi9íë7®ÇÆÅQ¯ž½Œ¿*/†7ðý}3õ0P*•Ø»7'[¿É­º˜0eŠP$ »zõŸ¿þ*«N\l¬L&#¢ú =€Š@š ÀXOÄ=øL5™vU·úÒñ“ljUI3:GDÜÊMœ½û÷Æ<‹iîÛ|`ÿª‡×®Uû­No%%%=zJDLOO‰D‹¿^Ìã•ø‚Ïç—ÌC²²³,-,C§…ª–KÄ’ÐÐ)\û¥—oݪõ¨Fét¶¯]jjê™sgJ—øß"jØÐÀË¿Iã'1 ù$rͺ5¥Ÿå~$Këà߈®ßªè,†xéiYgÏ+ýTÅO­2=q”ˆZ·j]úÞ|Ü*à§ÿ>Í¥Ë5’ˆ%ÆËÉÍùcïåö•—Ÿ7ã‹DT˳V@Ï€ Åm¨ŠÇPyÝšC,‘ ~ÿýÜœœý{ÊÿØèËÁÑqàw‰hå·ËʪÃÍ×s÷ðððÔ0(À„f¨¶ºwínanûäQ2W’W-•J;¶ï¨¬vþÂy"êúV×Ò÷-ª[§.=yú„ˆÎ?GDmZ·qws7 ˜ /QÛ6m¹åc89Åñ—¾Î®»‚ˆX–½tE}…¦!‡åŽN•!#3# o@ÏÀž;~Ýñäé“ÂÂÂçÏŸÿõ÷_ýïÞ¿KD'IÛ¶i;~ìx"úrþ—!3Bü÷ ¨¨(--íÈñ#￳výZGqi¦Û·oë5J£Ê;µÊpüÄqz™QRÓ¥s†a²s²Ï]Ð5Sâ/k1¬‚‚‚¬ì¬ˆÈˆŸù¹S·N—._âñx?¬ýAã(N–eSË –ê*.*ÖX-==½‚1”«²ß_½Ne)?GžŸ#ÏÊÈIKMU}¨¾b™™™\¡rõ±ÌÌŒ%™†¯G–›óªS®$//WY²¬–c?=†ˆb¢¢ î]‹ “'Ñå .×Ï_<þ¢†ëÀÙ3f÷ìÑÓàÆW,]‘——·ã×7mܸi£êS6ÒxHË-½½¼#ŸDž9w¦{×îwM•|jÆõ,ö—јfrpphܨñ½÷ŽŸ<Þ£[²iâÓ¤]ÛvW®^)ý”\.·u±U-±¶²þ釟Êj-%%ÅÃÛCãS;¶ìP]ôý艣kÚÙÙÅ=‰«H åªì÷W÷S#¢¼lù÷¡QDô=…•îúÓöŸ yñŠõèþ߃ªÏöx1’«‘Ϲ0ñ…Nºw÷.Õ’yŸ>ïóϹí‡1Ï´¬|äÓ¸q›ví®]Ñ𱩸&ÍšuèÜùâ¹s+—-ÛÓ©Sé '#¢þƒWFï4@uÜ'øà¡ƒ—ÏF´bF/ÓLÁAÁªu¸ÿÖú6õmܸ±ÆFš6nJDÜbº-RþO8·8!üùO\‚Iù,×j±<ϰÆL¢Ní:·¯ÝÞ³oÏ™sgþ{ô_zzº@ psuóoç?vÔØöþí+Ò8ŸÏÿqýC‡ ÝúóÖËW.§šÿ‡ ÕÕõˆS\xõg·¹ÈvÖmÓ  ÊÉÈÈð¬ç©`å+Ž×˜1Ó{=åóÌâžÆs÷±âŒ™0æ·]¿1rãºZš5nÔî=»»¾Õõø¡ãZªm۱퓩Ÿø6õ½r¾Ä_Þ\/­;Ô¿R¬š`"¢âfJ·"Ú·k_`@ WØ= û¥Ë—–/Y>yâd}Ï ÆJLLlèÛÐÜÜ<êa”H$2u8Ú¬=Ú'5ûÕŠõÝüføù|hÂxª% ¬\¶ôÓÏB¿\° òzY0wò“ȇÜvßY‰•×QiÙÏÿnqà¶;wé=æãPíõáuZ¾Ó—ˆ%"O'ßÉö—®€µ™ª3©TúV§·r6ê†El¸µ¬˜íÒµ½jމ^®çrîÂ9îž5eñoëOD×®¥¤¤h©ÆÍÅP[&·8ÁÅ'ˆîÝŽÉÉ.T–3Äó¶ék3ˆ†áºƒ¹¸¸Œ=.##ãç_~6u,P)òrs·oÞdeeýɧŸš: f¨æ¸)ri·[dÞiGDƒû W«0 x€¥…å“§O¾ÿá{-í ì7P$åæå.\²PmUÔ¬ì,å¶³“3%$%p“ìr‹.'.ØèîÿP$áä*NýšA/Lý½·±Ÿ¿ê»MDdggg”S¨Éf‡Î¶´°\¹f¥öÄ1TQ;¶nMKM2M˺Q&„4@5×·O_":ù×É£Çòx¼ÀÞjìììæ}5ˆæÌ›3kÎ,n°˲O£ž†Î=yê$WÍÉÉiæô™D´ië¦qÇ=Žx̲l|Büº ë6m~7œ«Öا1Ã0iii¶¬¼”°`×½€Ñ»l±…5¯ßx;":¾=ýß­víÌ7wpYõ(3°_àíðÛæ ç-|]/ @uæàà°åÇ-#†ˆ‹W_kªs ‹™sæL˜<ÅÔh†%Àª97W7¿Ö~a×ȨsÇÎöšþù9iü¤¤¤¤«V¬]¿víúµNNNy¹y9¹9D”‘‘Ñ»ç‹Fg…Ί‹ÛúóÖ_wýúë®_%bI~A>I¥Ò¸¸8ߦ¾DäéáٿЇCg|e¾€W˜Ïvj3h²=u×Öš×èçï/ïÚtmצ.b±¸  €ˆ<Ü=¶mÚÖ°AÃ×õ’TsÁAÁj+ý@µñáèѦ@¤™ª¿à>Á\š©¬+O†aÎ[Ø;ðç_~¾yûfDD„§§gcŸÆÃÞÖ' ²ŸÏ_·z]pPð®=»n‡ßމ‰iݪµ[ÿ!3œ‰(·8áNꦞÓe‹¥w.äf¤Èëøˆl ñ¼lúø:L9·ö˜~·¾ßðýÍ[7Ÿ={æßο}»ö³>›eccóz^ 0©³TÇš‹æ/ÂÚÿúª¤—·j½kîvºÞ}oî‚…ã'ã3P)f¨þfLŸ1cúŒr«µ÷o_î}¬†éݳ·r|“RnqâÔM3ö+Øbž€Oµ<ÕžˆâÕµ lî0ÑZX›«Ù¢y‹-·”Ìß'þ.·T!I¦¡:«¤—·j½kqié¦f€ŠáLäl‘jyéToH3€ÊK0M°Ö1Qh`H3€Þ`€Òf= ÁeAš àö×™cWo\0udoë0bøûwR7Gdì×”`z§¹ÃDka[ü׳‰æÇ® ” å™çâgЩ¥™›¿Ë\ån¾ìùùø9¶¢z~ί–3Ï.йœ¸ØQÒ¬…ã«{¥< Kþ®ŒVY-=:›ûù:ŒWî>Ï¿s#e‡e—Æv( s¯„§nªkP_:XYø,çŸi¿è×Õ³ ö¶é§ÜÊ:ù0}w#»÷j[õRFdˆÌ<ÔÔ~Œ»e'eჴ_c²ÿ*ÙW¹½ÛÂá‹vÊý»©[csÎø9…:Hš) o¦|Ÿ”æï2W*òV^KZ–Zp_¾Øu:¹-¶ÖR_N\^ð¸«Ç*‰ÀAYx.~VNQ\ÏZ›<‰²ðïgS åé:ž—êN@í<æÕ_¹§bÆÉÙâ€ÚÛUë‹&âK{xþ ,‘)òOÆèp›pV=s3çnk”»…òŒS1ã¥"¯NnK”…9ÅñÿƆ8Hšú»|¥,Ì(Œ8ÿ…îç¥ädÞº­ólånjÁ½‹ ó=,;·tœª,LÌ»z-iy]뀦öc”…Ïrþ¹•²¾Œž´½Îõlú5¶ûP¹•u2üù>vÃëK) gìö‹¯ÃÇu¬”…÷ÓvDdЫ/NKÇ)µ¬z(wï¤n~’y¤­ólW eáäUÏrþíèºÐAâ«,¼œ¸()ïš^}qïé[îËíÄ”e¾JɻգÖ+3e῱ÓÓ ½Sg§˜ÿêŽf§b>Î)ŽÑ›>‚êî6ãY*wGX Kà}TµÎ¡'y ?¨î•`åžôÕ©¯’ŸU±À.°ÎoÊ]™"ïГVBÏžµ6) ódÉÇ£>°ûtóX­,Ì,zúWÌ„r;+]ä(iñ–û·ÊÝ´‚ÿþŽânѱ½ëüWQYS-ÊÍ¤ÔøW&d¹·H¯¾8µmƒ›¸¼ú)ˆÍü3<~Y=‡ ?RF¥í¿Ÿ´¾‘Óx/ûw•…Ÿïx”²]Ÿ®^hê:µ¶måîÉ›"ŸÿÖÂ}Ž»ÍÛÊÂ; ßE§n[k‰“å«›l܈ý:>ëý:#"býk¯v°h¥Ü¿ö실ìó½6Ùˆ* /FMIͻգÞns¡›²ðLäGY…ztElF¾ˆˆÇíœ\ë¤Ë1ÆÂ*˜×ÙÒLo´gqQ7n_1udçhn¹S-ÁDÄð³~^û•#˜XRÄåœSÍ)‘‚-ŠË9o@§¶¢úª»r¶0>÷‚œ-P-,VäÆç^à3fª……ŠÌøÜ‹ô(ä[—hGž‘{Yõ"“ˆòåÏr/Û‹«æ'%äò69KZ©îæÊó®zZuS-Ì.ŽMÌ»æ-í¯Z˜U•¨r-­»|yšZ;Iy× å™ª…™…O’ò®+rU Ó %å]7 G™"¿D;’óo©}–Ò þË(ŒT\µ0µà^ž,Ù€Õ.¡R îËÙBµÏóïªæ¹ˆˆ%ùóü;tf¥(ñê)XyjÁ=µlQjÁ=!ßRµP¦ÈSfîô"”¸Þ+V䥨9ÅqYEQ,+S-Ì.ŽÍ.Š1 G¶d(§(.O–¤V'»8–ÇðÕ êNVòYb³‹cy~º 4€JÄhþ†Õ½Àøf0Ž#R™ÈÕðÄê…Œ™€'ÖØ—V S²>O(à™«™ñ,Ô ù<±ÏB÷¾˜W%^U3ž¹g©öR›ñ,„|+*YSȳò­të«d¦Ä®o¥6Z“ˆD|©HD*SöÊîKˆo£ŒX`'â•,dxbÚ¸Nñ%{={#"ñJ¶Ã$G!ßJµeI^LŠÃnˆÏˆÅfŽeô¤íuV‹\À“HÌœÍJö(à™KÌœ×ôwÇ}©.J4è¿Co<É&€ê§Äh&W  Üi&¨’MÃl¨*T×ÃÂHЋß!€7*ìe²éO?çj7$JÉç’Mq9çMèˆU½D,û.x•ÍÄ`]¼ i&0OÜÄnä@ï““M=›€dÀ®äh&\"€¾T×fÂï i&0&$›ª®£™ŒqcA¨aT×fBš©†Bš ŒÉ&€ªK€@E°X› f€ÊSn²é(’Mo7#cÁÚL5¾< r)“Mmœgª%›ž#Ùð&aYŒfÃa}7 ¤™àõðÄí>Ô’lÚ/K1Ux@D„ÑLP!øxãà5Ò’lb¾˜ogªÀÞ(gÏŸ•H%å>zõé¥<äúëŒþ •+[Ûºê:pϾ= …B­å!ª-XØYx5òêØ­ã”)wïß-9š‰¯VÙÑÝѧ¹ÏðQÃùý—¢¢"ÝOGߨ9TVS#ÇŽäêœ=¶ô³©©©K—/íÜ£³»—»­‹m‹¶->ÿêóg±Ït*Bum&Lš«±f€×­d²É+ôuÏ0¸³Ç•Ä• ÕB¡PȕϚ3«S÷N{÷ï}ð߃‚‚‚ÄÄÄã'8æÃ.=»ÄÆÅ–n_,»¹º¹¹ºÙÚÚ&&%Þ¸ycó¶Ím:´YûÕ5¹ìÅ`å„®²‹‹‹\.ŠŽÚpÿ¸‰ã|ý|¯\½¢Ë¹èíÚ³KcyNnΑ£GÊêh÷žÝMZ6ùzñ×a×ÃÒÒÒ >z¸úûÕ­ÚµÚ³o.¡@a}7 ¤™ÀT^&›N´qžédÞÊ˺©#·ëö< IDATxStêÐ)#)CõQ˳ý°öÕÂ#ŽÑŽ_w¬]¿–ˆ&Œ›påÜ•¸'qgÿ:»òÛ•µvâXfVfé§Ž;š—Ÿ'‹K?µmǶQãFefeú6õÝöÓ¶GwE=ŒÚóûž÷‡¾Ÿ“›³à›z ¿C±åWêN`ê Fã’Mí>4u UÕ¶ÛˆhìGcW-_Å•ØÙÙµñkóÁð¶ïØ>~ìxí‡óù|ŸF>+–® ¢õ×ÿ»/³çp)§ù¿Ñînî?ž8dྃúÞº}kÔØQ·®Ý²¶²6bl½ÞîuèÈ¡CG}0ìµ§vïÝÍçó»wí~ìÄ1ÕòûÿÝ™BDÃÞö㺂×8Aï½Ô' o3_åÈ/¨<ª“æ0š©ÆÂPU±,{ûöm"êÞµ»ÚS––“'N633Ó±©AýQZ¢,?G¡ýúÐÁÁá—m¿ˆD¢„Ä„ŸwþlÜØz÷ìMD»þPŸ7—ššzêô©î]»—>jñÒÅ………n®nëW¯Wæ˜^×€AõëÕ×r:`<*£™°6SM…4€qðˆg)tâb©Ã€a˜ÚµkÑõ›×+Ø”‹‹ ·a&sµzh¯ìíå=hÀ "úm÷oÆÍVjëßÎÿß³ÿ&&&ª–ïÿß~™L6dМœÕò´´´ƒ‡Ñ³¾Ð8Ÿ^¬Í„4€±ˆ6Ãïä]zHD<oD«£ý½Ê¼×›Ò[Þ"¢;wïääæ”UÇ€Ørrs† ¢P(öØ«Z¾{Ïn¡PÜ'8+;KµüüÅóÜM놪KûP™T×fÂh¦ i&€*lÆôow[¡PÌš3«i«¦ë6®ËÌÔ°~¶v2™lŪDÔ©C'ÇÕ©]‡ˆärù³gÏŒ[vvöàƒù|¾êýæžÅ>»péB@¯›ììlÕú÷Ü'"gggK K]€ÊãbÕyïA¾á}o7rþØÔá€i ÍP… …ƒ{.Y¸ÄÞÞ>.>nÆì^¼¦„Lyõ´Üc £c¢=ܳOÏ —.ðx¼¹sæêØ/—f"¢ôŒt#ÆVTTäääôv÷·¯ß¸ÁîÙ·‡ˆ† ÆUP­Ÿš–JD^u½t *Óæj,¼ñUŸÏŸ6eÚã{7®ÛØÜ·y^~Þæm››µn¶pÉBnB™šƒ‡J¤‰T"u–6òmôîðw/_¹ììì¼cËŽŽí;êØ©L&ã6xŒ¶k }cã¼ÿîûD´{Ïnnw÷žÝ6Ö6ÜêàêX""-MÀë„4@u KFŽyéÌ¥#Ž4÷m.—Ë¿YöÍÜF'‰Åb7W77W7w6~m† òݲïÜ~À­ê­£¨è(nC*•16NPŸ s‹½ö²,ù$2ünø ƒ4Îæ³³³#"]†nÀk€4@õÁ0Ln=.þ{qꤩD´fݵ[¶Q@¯€È‘‘"ß{|ö¯³;¶ìødü'±D¯Ž¸4“™™™röœQbãX˜[ôîÿßÃÿîÿwÿБCDôþÐ÷5ÖlØ !%''çæåê?T¤™ª7ïËy<O&“ݾs»2º8ýÏi"jÙ¢¥ŽK†ë—WÚ»ïÁÃ==<;øwÐX­S‡NÜÆï»×+ ¨ H3TaËÍf"¡ˆˆŠeÅFïôîý»‡&¢†}PI±u}««‹‹Ë–í[®^»:tÈPOó•‹““S`@ -[±Lmupxýf¨ªÂï„7hÖ`íúµ¥×À>xè`~A>µókgÜNãâGŒ!“ÉêÔ®SÖ\¶ŠÇÆç󇚒’BDï½ûž–x>Ÿñ9ŸÏ‹:M.—«={äø‘@ àõ@š  ªúm÷o)))³æÌêñNÝ{vGEGeddܽwá’…ã''¢Ñ#G;::¥/–e£c¢×¬[Ó¶SÛ‡šKÌÞü³…¹EåÅ6lè0"òmæÛħ‰–j~­ýÎ[HDÛvlëÚ«ëÿˆOˆÏÈÈ»6%dÊ÷‡ì;°ï؉cž6èC`êÀ@K.qvr^´dÑå+—/_¹¬öl@¯€ï–}WÁ.Ž8V»Am–e333•c‚¼½¼wlÙѪe«J­YÓfWÎ_±³µ+7È©!b±ø‹¹_„]6r˜êSB¡pñ‚Åýƒû—ÛTÒLUÃ0!SCÞ{÷½¿î¸–ÿàÚŸÂô%ŸÏü\­~tLô´ÓöÜÏí>Žxü8âñí;·O?ͨ¬ÃÂ5»xÙb–e‰èÿìÝwxTUþÇñï’Þ;„:¡„"RUdí ýYÐÅÕÕU±¡(ö²ººöµ°¢ØU,¨  ‚JS”ŽtH(I …ô2Édîýýqa˜L ÉdÂM2ï×ÃãssæÌ¹ß¹‰Iæ“sÎ5›Í_ûõ·‹¾9|dà ›ñöŒ‡{Øn·†…‡-ûiÙ²Ÿ–-ÿiùœæ¸õÏÉ͹ï¦û–ÿ¼Ü³ëÀ;\&E 7¬ôU|â¥(JÚþ´ à ž}á—ß¾öS×W~H:wR„ˆüû¥gee¹õwå¸ïÿꋯÚ{èÀîÞÿ ˆüúÛ¯+V­pí6ÿ‹ùÏüûMÓ&]=ió› ² Öÿ¶~ÒÕ“V­YÕÀÂ~¿ðþï÷÷óŸõÖ¬ìôìý»öo]¿uÐÀA ¿_øî‡ïÖìÿØ“­XµâÉGŸüsß«–7ô,¼Ëõ†•ÌfòYÌfÚŽß,hÔª±ž}ÁÏß/$8¤¨rÿŽ}jº|Jôžµæý{~öùgwM¹Ëµ³Ùl^úÝÒ!ƒ‡è>þð㋾[´uÛÖ%K—œuÆYz£¾xMD®¿öú·g¼­ÏrJîüÎßi×®Ý /¿pÒ’ÊÊ˦MŸ&"3ßœ9qÂD½±{·îs?šÛop¿—^}é–oñóós}ÊÂïþ÷õÿþí¯kø Ð \î4GÌ䫘Íø®¨¨¨àQ5‡Þ¢(’rzGÙ`¿[çi÷LsfL"¢(ÊèQ£E$óp¦³qéKÓ3Òýüüžxô ¥úÍccbRÒç_~~ðÐÁ”)—¿Üµ½s§ÎgŽ>3+++mšÛS† rÃõ74dpͧÚl&…˜ÉG1› h;.»ä²?ü¸f{iiiBç„zžXV^¶o‹-}oe澊]¿çŠHzFº[Ÿš·ŠÓ“£œœgËŽ;Ddð Á‰í=z²jõ*s昚oS“º$‰HjZj¯ž½\Û¯¼üJÞÓÆsÝ›‰I-¾Š˜ 0F¥£ØÏܸ›¯”Éd²Xjù%ßl1×õ”í;·¿ûþ»:§¨¨DD"b-þÖ ©ªª:éé¬V«ˆè[}ëvîÞ)"]“º6¾öcô¹Q¯½ùÚko¾Vk‡ìœl·³¹ÎWà”ao&1`”¬òu›rf¤ÄÜÖ)t¬Qû˜Ìœ5ó¾é÷‰È¹çÙmìÎn)Áa¦_?n?ûÍ•ž h·ÛEÄböü†Z è7 99¹Öý’ûy<8€fTm61“"f¼Ã¬X;†¦Çv7¶ÐJ(y¶?¥ßÐ+%æÖΡçœâ7f[¶n¹÷{­Vë'}ræØë²_Q5MÝd>êñ˜]:w‘ŒÌ GHHH‘AÍ|s¦Çƒ8õØ› BÌx‹¿9䢮ÿ2º Ð*åÛvýœ>5Ò¿gJì­BÏQNÕž& ¾] iÚ9cϹø‚‹EäìÿÑÛ×>#²À³1õ˜iæ å¶òÀ€FÜóÎiäð‘Ÿ|úÉÊÕ+«ªªj] eò·D…úwÑ4Q-¦ £Ë1Ø” 0†ÛÞ%ù»N¿÷ÛÔ‰û‹~ÐD­ëY^d³ÙD$$$ĵ±¬¼lý†õyÁyøùùåççøÑ‡®í¥e¥?üøCCF˜pÙ„àÔ´Ô7þû†Çe8õºÇL:¯××çõúæü^ £‚RŒ.Æ fZüŠ=¿dÜûMêåû‹–4wØÔ¿oYôÝ¢ßÖþ&"6›mùÏËGž5rñ‹=³Cb‡¿ýõo"rÿC÷Ïœ5³  Àf³ý¼âç±ç]ºliÍþ!Á!"r(ý³%**ê‰Çž‘Gžxdú#ÓõÛØiš–¶?mÚƒÓ–,]âqm€æF̥νK *öþ’qß7©—§}ß|aÓåã/Oî\ZVzöùgwíÝ5¡sÂÅã/õÅW›2ì£>Ú»Wo‡Ã1õþ©íº´‹ïáeæää¼øÜ‹5;è?@D^Ÿñú´§9§ücÊ´©Ó4M{}Æëztêܳs\‡¸äÉ3fΘÿÅü¦ÔhVÄL@ UP±wEÆýߤNH+ú®9Â&ÿÅß.¾qò;t,((èÝ«÷ËÏ¿¼ìûe£Gnʰ111¿üøËÃÓ=rthHhtTôÍ7Þ¼våÚÿ›ø5;ßsÇ=cÇŒ Ê<œélTåé'ž^¾xùäë&è? ¤¸$11q¸ óçΟõÖ¬¦ÔhVì¨CiØ}å *ö­Èx`sîÌ”˜t »°® Â_}ñÕzf!…‡””×lñÚ ·Æ~ÉýÜ:/_¼¼Öa§M6mê´šía¡a=ô˜<äÞ^³†˜˜˜E Õ:øˆá#F QëC'- `f3­@aEꊌé_ï—Z¸èÔl@c3FiÐl&W…•i+3§/ØwYjáBÂ&@KCÌ´2E•ûWf>¸`ߥû ¿Ñ4‡Ñåp 1Ð*UX•ùð‚ÔËö~MØh ˆ™€V¬¨òÀªÌG¾J½t/aÀhÄL€1¥Ñ{3Õ¥¸òàêÌG¾J½doÁU«òÖ°4 1ÐFWZ}øÑû.ÙSð%aàÔ#fŒâµÙL®Šíék?þÕ¾‹÷|AØ8•,F*;Õ¿4ÿ”þìVÇÞÛÕ’}…ߊh"¢ÿW?͵åÄqµ>ú±VóÑã×Ñ­ú€r¢¥Ž>®§Óûœ¬$çÍàk<Ýup­Ž§»®Õ|E5ÊÓêx9'Zj^:J:vÒšƒÔ㚈8´Ji6%öŒå»ÿùÈÛo)bRƒÿºüÀO Nfl €S€˜ €Vc÷ê£N]^•³*ó!£ÎÀcªCDTõ¤=›· Íà§‹æàÌf@+¥ˆˆâº½‘âÚâ~|¼‹kKÍþ'Æ©c÷nÕ;Ô(Io©c@‡VQ^•ÛÈWí!«¿qJ÷iª(5ÛJø«6øb&À;ªÔŠ´ÂÕúq°5¦}ÈcëÐfŒzfB|¢‘hjVù†À@ÿ”„nµ¼Vj¼?¯ë¾rò>.÷v¯ëM¾k·zßá×ѧ1¡Cõ×U_îàhH^þ)š*"R\‘VQ•§ˆID"‚’ÍŠ¿ÑÁÄL@‘túÀØ)ñACŒ.€/Ú™õöÁ‚Eúñù½…øu2¶‚˜ 0†ç2% ;%>è4ï £‰æxds×MQm6‹æ|1¾À%fÒˆ™€V#6p@JÌí‰!£.Àuo&Íù*b&|@µ¿(3-GoÃbûŒ™BÀ ÑäD̤°hÎW3ÐöU_˜CÌ´h1ýÆNI 9ÃèB )˜Í䣈™ðìÍ´Ñ}ÆNér¦Ñ…€'4—EsìÍ䳈™ð5ÄL@‹|<`â€ÖËõw ¾›ù(b&Ú>Í-“"Jt@Ÿ”ØÛ;†Œá-€Ö®ÚæØ›ÉW3à \ï4g`ª‰ H¾$i¾ÑU€·0› 䋸…;Í-’Å`t à5ìÍ!fÀ7°8hnÌf‹æ/±šúÇ^®Gv1´¨1ð>öf‚3Þb5ŽLü‡ÑU@íªÿªG̼/&xˆŸ9LÓTMQÌF—c3à \·'fÞ—»Ñ%ÀxLc íS„-ÀÐ숙ð [€ Ù3ÐöU¿× 1š1¾€ÙLhvl@Ûg1nÿ¬ˆ¢ˆd3º´MÄL´}fů[øeFW€6ŽEsðb&x1¼€˜ ^@Ì/ f€3À ˆ™àÄLðb&xÅè€6®–oÌúT?Ž èÜ#r¬±õpŠ3ÞaWmΘ©Køb&>å`Á"‡Z.¢XL#.2ºƒ˜ 4Õö#o”Vfˆˆ¿%Š˜Ég±7h*M4ý@!jða|î@“iÚñ#ÅÈ2`(b&ÐTš¨ú¢3ù.b&ÐtÌf[€à–ºC•* µv–ðˆÑ倶FÓØ› ÄLø†ôÒ•šæ‘è€d£kmsÑœ°h·1à”Ó×µúúxÈ9›‰˜Éw3à#ŽýÂGȚÉÙLD >ŒÏ=>ÙL yÿƒÙL¾Œ˜ áœÍDÌš{3˜ _£3ïÓØ› ÄLøEqþÐ'fÍÁù;Qƒïâs€`ÑhFÚñÓ ‹æ|1>-À@3sÞiŽ˜Éw3à#˜Íš{3Aˆ™ð'~Ýc pÐ4öf‚XŒ.h#üLAgv¼[?õ‹7¶¨…Âl&ÐŒNÌfbo&FÌx‡Åäß'ú"£«€z°7hF½ãþ®jvM´@K¬ÑµÀ0ÄLøvIͪOümF—ã±`Á¢94/b&|‹æÐ¼ˆ™ð Üi͘ Ÿ (Ç~è³hÍ„-Àð çtœ©‰*¢˜?£k@ÛDÌ€Oˆ èct hãX4/ f€3À ˆ™àÄLðb&x1¼€˜ ^@Ì/ f€XŒ.h#*%?|E?Ž î50î*cëà#f¼£J³§®Ö5Q-N%»£d{Ö›"Š"¦ðÀž#Ç]ŒA̚ġ–ïÍýX?nþb&ŸÅÞL I4ќNJ(Vc3€&rÝ9„˜Éw3€&©>›‰¨Áwñ¹M£ˆ™Da6“ïb p|‡n-¬HÑLŠß„n .´)®·Ûfo&_FÌ€O(³g—Ø3DÄb 0ºÐö¸Ìf"fòa,šÀ7Ÿ¾®¹Îi÷ÔM·ÞÔ¥W—9ŸÌiúP  pýCQˆ|Ÿ{|‚Ëôõ¦ÆLÙÙÙŸ|úIVVÖ{¾×Ä¡@[Ál&ˆ3Ь¦Þ?50"°®×üõ·ž®-uùvÑ·ã¯ß¹gçȄȔ¡)7Ü|Ãæ-›PËñÙLMŽ™ââân¹é–.»ÜqëÎÆâ’âÀˆÀa£‡5qpб7tìÍ@³SÅÏϯf»ÕjmÔ8………wO»û³ùŸ‰ˆÅb‰ŒŒÜ½g÷î=»?›ÿÙ[o¼uÃõ7ÔWÉC/,š{íå×ÜZ š>,hµ˜Íf3p Œ»t\AVAͽ÷Q£ÆYýëêÏ¿ü|ôÈÑK¿[šž}pÏÁý»ö_>þr¹sê‡ÒÕûl¯ÍfªU~A~s Zöf‚ŽÏ=­ÆE\ôÛÊß–,\2zäèÀ€@‰ÿí÷#Â#ªªªÖüº¦Þgÿ»¢7¶¯‰ÙLø6f3A„˜ €Ö¥_r?“©ÚoÿvíÚ‰HaQa=OÔwI8¸³âƒfõÒ¿}RûK&\òÖ;o©ê‰òòòÚ'µŒüäÓO\Ÿ»~ÃúÀˆÀ¨„¨ôŒt½eìc#ß|ëM™ÿÅüÀˆÀó/9_D¶ü¹Å¹ó÷¡Àw°7tÄL´n{÷íݵ{—ˆŒ>¢žnš(Ë?+|þæŒß¾/ÊÈÈðóó[öÓ²{¸÷ªIWÙl6½OTTÔS=%">ùhiY©ó¹O<ý„ˆL›:­Cb‡š#wMê-"V«µkRWý_hH¨÷^%há˜Íb&Z¯ÊÊÊÏ¿üü’ —¨ª:åÖ)ýûö¯§óº_ŽÌûO®ÅªL~,.;={ÿ®ý[×o4pÐÂï¾ûá»În7N¾q`ÊÀÃG¿òÚ+zË/+YöÓ²‰î¹ëžZG¾è‚‹¶mÜöôO‹HŸ^}¶mܦÿÙxï½VТ±7t|îhv ¾YâöïÝÞ=ù3ëððã÷Ié×1îú¯·UØ^yᕟ{±žþeåeï?¿EDþúH숋B-³ˆtïÖ}îGs-ËK¯¾TYY©÷4›Í¯½ôšˆ¼úÚ«é隦éS™ž{ú¹ À m³™ "b1º 0‡^ÖãåãÇaÆ r8n-Z¶âÞ»wïþûõãð°pEQTU5›ÍuõÿüËÏs—uìé?xlˆˆh¢é›&GzDÌ IDATtîÔùÌÑg.ÿyyÚþ´^={éOzúäë&ÏþßìÇÿùøÕW^½ö÷µ#‡œ8a¢ÇÕ€6½™ #f¼Ã¤XÚ÷3º -ÔøËÆÏýh®œóÁœÃGgÎ\øÝÂf0õþ©‹XüÙÿ>ó÷÷¯µÿªÕ«D¤÷iŠþ[Ÿ¦9ýKê’$"©i©Î˜IDž~âéß,˜ûÙÜ5¿®Qååç_V~_u öK<½Ó󚦊h!þ]Œ.†!f õñ÷÷ïÒ¹K—Î]F9åÖ)#ÇŒ\²tÉŒ™3î½ûÞZûgΑ¥Ÿ,ý¤@Dn•·Ù9Ù®ÆÆÆÞwÏ}ÿóñL¾nòÀ”Íó:@ágŽèq‘ÑUÀxÄL´n‰í~àá{¦ÝóîïÖ3é ô:ôðkßÕOD’Â.rÛ›³_rµù˜ªª~·ä;ý8;'[Ó4f3ई™hõô "ûì·Ùl5;$$$ˆH§^þ}$ND®ë=ˬøÕ3à'Ÿ}òÛÚß.¹ð’-nù~É÷ß,üfܥ㚧v´Üi€V£®]Ãd‘ˆˆˆºöf9|¤ˆìÙhSúõí>^XTøðã[,–ÿëßÏ<ùŒˆÜ7ý¾â’âúkÓ7 ¯¹Ó9|1­Æ?ðÊk¯¸…Mš¦}ðÑ"2dк–¶M¸lB@%'Ãþã§…'=Ë3Ï=“““só7wëÚíŠË¯8}èé™Ï<÷LýÏŠ‹‘ÃY‡UU­¿g<¿ïZb&Z‡ÌÙï¼÷Î#O©}{Μ5³}»ö_Íû*!!áÛï¾=ã/gDÄGÄ´é;¨ï¼ÏçY,–?óï3FQO wÞv÷´©Ó4M{ã¿3:õèÔ¹gç¸qÉ“gÌœ1ÿ‹ùzMÓ¦N›êp8¦Þ5566Vo2xÈäë&;Ž»î½«ž™J;t¼âò+Dä®{ïjŸÔ>¡S ¯¼Pÿe©TK6çÎübï¹›rfµmßWøíI¯$Z2b&NGmTG-©M­=õ…rcÇŒÝôû¦Ÿ{qÄðQQQª¦öíÓ÷Ú«¯]·fÝ·ßYŠ¢<ýÄÓË/Ÿ|Ýäý”—$&&N7aþÜù³Þš¥÷ùüËÏW®^{×w¹>÷Ÿÿ3"Úñös”ÅÐÀ‘+E•jq=£¹²š‚Ì‘ Ù¡U”Ù³êÍ•I±„X8²ˆUî¯eL­ö³„úu4)ÖŽ\bϬRËêéàzÞ K¬¿9¢#ÛùåöìzFse5‡„Zú‡‡VQP‘Z×Ʊóœ`ŠèÓÀ‘E$϶Óåk¯æhÕZ#ü»YMÁ ¹¸ò`¹#¯îÇ«%Ø’lm×À‘mŽüŠԓv+(/rW–›Žòkàø^QV`>•§`¬Šª£YÅkôãØaÆ3Т}úÕ‡‹~øÒè*¤]Bâ-ÓFoË›]á(¨µCvù¦ìôMn×ô\ãgkà)–ºí¨m{;Ÿ•ør—°óØùÏ£ïo=ún;÷ˆ˜8²ÝS ìœS¾yÉØ9ØÚîŠîKØYD¤ŽÓ4G;Oè¶0̯K;ÿvä錒• ì<,á‘Þ‘×4°sjáÂ?²žo`çŽ!cÆv|³‹+-L»²ÍŠÿu½×7°³ˆ,;t»3=© :Ïnø|½-¹ïì-\ÐÀÎbþ1(öÎv>\ºfEÆô“v³›Ebõ㣇üÖ|ÕÀñ ±4QÇŠÒÐ?2¡í!f'WRyhCÎkn~¦ÐZg µr'™”tÊ(¢´ŒRZF¢]@KÃи̷mø\f´=|îÀÉYÍ!fÅß­±R-ñêIxÛ @kU}‰4?Ó}³™h5¢;VZNéÔ’ì}þª*"`ŽžØý½­GßÛ?ß¡U\/F ²Ä†ûwµšBÜžnRñ›F»àáúÖEJ}¿š{,ØšÐð‘#z%…]X×Pnb4|ä@sL×ð‹ëMD”ã5|‡#]×ðK5MumQê>KÍ‹_ÄàQ–˜ºG«Öá×­á#Gú÷ìqE=£¹Š èÕð‘ýÍa½"¯ªk4·×Ò¨/<é1¡Òqb^žRß— d‰køÈíCF6|Ýh\à †î—Ô7ú×ÂjíVì(³×j ‰:ÙfU™%«ò*vëÇÝ#&4|‡²JˆkÄÆdZ£j‹æˆ™|1­FŸ1Å‘íí'ïç=‹_‹SmÇæ>ZbO°ôM}Wþ<×°©¬*»¼*·Sè9)±·Fú÷ôì\Câ¦z£äZ$…]X[Ìäáþ]ÏhßЭˆkT»§›iä>Q×5ÓÈ킇µ n–m_-±ÃkŽ‘E¤á;"5VRØEIa5ÇÈQ}NšéFÞРW>¸·à؆Vãº^áßÝÓÒø*×›TÔû'#´m,šh‰?}b÷ÅÉQ×».£ÓD=Pü÷©Wüœ>5ÿøœ­…ëÔ9Eáq<ÀÞL!f¨7lZúMêDÂ& µq]íÂ{¦µ”[FÀ`ü:6-IŽúkõ Â5Â& uQ5b&MÄ·ˆ3€& ´Ä  ž°é§ô{òm» «@ƒ°h@“hìÍ!f^á6YL.h‹ü&í Â& %ÓÄá<æQ<ÂÞL!f^¤‡M—w[LØ´.*[€höf‚Ž˜ xaÐ ¹nªÂl&W-­&jð]|î@³86Õ³Œîî<ÛNÃêàB«¶8³™4ZõÙLD ¾‹Ï=hF–èºÃ¦eߦ]IØ´Zµ-À™ÍÀ®{3ñmÄw3€fç ›úFM&lZ j1³™4žë·!fòaÄLà ´DŸ=a“Í‘oXq€oÓØT@i.‹æ˜éÃ,F´–ˆÉýæëÇ&…ÿ³ NzØÔ7úÆmGßßUðY•jÓÛ;‡ž`Ž4¶6ÀgÓñ-Uª4MÕÄa5]€ÖG«¶hŽ´ÚwñfðE”K˜ÑU@«Q=lšW¥ÚRbo3º(Àw)ŠÙ,f–¹ðXLj‹b‚k¢‰¦ûw0º†˜ F›RboK-\éßÓèr€‡ü-‘þf%ƒ™lÀhVSH¯È«Œ®MEÌ/ f€3À ˆ™àÄLðb&x1¼€˜ ^@Ì/ f€3À ˆ™àÄLðb&xÅèÌ®–(bV“"f“Â{€‡øxGYUþœ?¯Ö»„8?éICËh„/öž_á(‘0¿Îº-2º@kEÌø:MÔ㇊‘uhµvdÍLËûBQL"2¼ó«‘ÉFWc3¾NÓŽÅL&Åll%Z©JGa¹ýˆ~¬ivc‹Øðuš8ô…7<¤¹óÄwñ¹|¦¨ð€'´j1|?E_çœÍdâ ÏhÎ-ÞD!°öa|î_§xÈž¨>›‰› ø.~оÎy§9…-ÀxèDÌÄ.o¾ŒÏ=àÓœ“ˆ(ÌAàöf‚Ž˜ ðiZµU˜ÍÀ#ìÍ!f|œsÿoa© O±7tü|𦱣 €¦ã; Dˆ™Wm6K]xÄ5°†/ã§àÓ4æ ðöf‚1àã4ÙLšŠÀ:>÷€s™ƒÀb pˆ3>Nu½ ¹˜ ¬@륹~'Qˆ™|1àÓØ€70› ""£ ÚE”K¸~l5[ @Ã)b µvÐDÓÄáoŽ4º­{3AGÌxG %br¿yFWÐh–˜Ë»/6º ­œ¦¼|@Ë™T‡VxÄÁŠNè4M O°˜Ì|A@‹3´Ó¿OÓþ%¢i¢šMF—ô”˜IÓ¤ªBuØÅQ©ÙJÔªJMsˆ£Š4'TÛ³Xü”€“ÙO1[Åâo"ˆÙ‹(-%a€ þ"ÐT©ªPí6­(×a/#TB}T‡&"•eZYÁ±[X”ÐX³5P±ú›Ø­c3iªØmjQ¶£¼P=yo 6v›–w¨JDÃLaqfk ¢˜˜Ý€1Œˆ™4©(W‹Ž8lÅLðŽò"µ¼Hõ5…'˜ýMÜ=€SïTÇL»VVà(8ìVÈÁÛ*ŠÕì5¢9(Âl¶5pJÒýlª*ÕœT{A&š&™Ž#»+í6æÊÁËî˜ú¤ؽ®W\sG==CcôN9ïÒ‰·|ýí‡Ãƒ‘^±¶ž>Îcλö”^pqêf3U”©¹©vÕýíà}j•dïµÇ$YýƒÙ^¦(ŠŸŸµf»Õêþí4 À?:*BDTUË/(ܵ;u×îÔ…ß-”’üâÙ1Ñ‘Ùd2ùûû¹¶WTTŠˆÅb6›ÍÎF???ƒœ¢˜ÉVâÈM­Ò˜Ä„SEuHÎ>{L’% Ô|òÞ@ƒ]>îüÏç¾Ùž_p¶³§¦iÙ9G?·pú£/lܼ}êýÏÌyÿåF|æè¡¶‚í®-]zuà`Ƭÿ>{Ãõù" YœŠ¹¥*N=M“Ü´ªŠVÏÁxŠ¢ÄÇÅÜ}Ç ¯¿ü¸ˆÌÿòû²²r£‹/kö˜É^®æ¦Ùɘ`M“Üýv{9IZŠ Î;SD***Ó3Ž] xYóÆLŽJ-'­Šý˜` Õ!9iUU•$hœ“˜""ÂŒ­¼®c&M•â\‡ÃÎÛ{Ìa׊s*SšÐÌ·PDâb£cc¢Œ®¼¬c¦Ê2µ8‡‰LhJr•¥äLð‚/,¶„ôrû÷ö»së–ªªiûÓ§?òÂÓϽ)"=p«¢(^ZŽæºÓœ£J;z°ª™yMÆÌ2{žëC»ó~4ª*d±˜Ÿ{zšˆ¼óÞ§»v§]î*E¹å[Ú¶åÙvتòNþêàýEsš&¥ùLeB Ušçð1ÕØ|Ù lŽ¢ÏvÞ¬w q~Ò“Þ?GƒÙÕòm¹ßlÎþÂVUèöPL`÷! “º„0¤0Ÿ5þÒs‡Ÿ>ð·ß7Mô…óf]Õ)[÷Sú]úñษý£o2¶­‘Cµi¢)¢ˆ¢˜£Ëa¼39*Õòné…ª¼PuTjÿ6»x¥£ôÏܯ·æ|e«*r{(6¨ç„IƉ´Ù—ßb)Šòü¿¦Ÿuî5_ûãÊÕœ1j¨ÑàêÄoï ¿'ðÈŠÔóʶêÇl5¶Èû1“½B¸3Z,M{EÛŒ™*%[s¾ú3gA…£Äí¡øà>Câ'u #Ú0Ò™£‡^rÑØ…ß-Ÿöà¿[ñ¹Òsêðˆª¹ÄLŠÞ/@ir,Pšgs´Í3٘ʄÍ^®†µ©o|¶ª¢­9_ý™ûu¥£Ôí¡vÁý'Lê:ØÂàæÙ§î[ôýO¿¯Û<ï‹ï®ºâb£ËÀ‰ÙLšÌ9ß„ï"¾ÍË1“¦‰­˜˜ -Zy±'mc*‰­ªpsÎÛr¾±«ånµ0$áºö!)†Ö†}±`±%¤WÍöð°Ð£™ëênÿ~½&_wù‡s¾xè±Ç_z®¿¿Ÿ·F )49±³ª"Ìfà íx`Íl&çå˜I­R+ËX2‡Í^¦9ìªÅ¯uï+¯Êßœýù¶Ü…UªÍí¡ÄÐAC®kÜÏÂ|ÃQË]jƒn}ðÔcwÏ÷mÚþôÿ¾óñÔ;ÿæÅ‘ð˜æ²ç…¢´îß‘Çù¤MüIžòv̤*“™Ð²išhj+þÆWf?º){þŽ£ßU©nu ;mHü¤øàdC kóÞ|õÉ7_}²‰=;ulo+ØîñÈ®öïú¥±O VÕg33ð„3°æÛˆóöÞL*S™Ð hšÖ#öR{îÆ¬Ïvæ-v¨•ÕQ:‡>8aR\P-K®ê§±8/`o&ˆ4ÇÞL@Ë×êæÜ•TfoÌþt×Ñš½ú#J—ðC&Åv7¤0Ðhl ÉØ› :/ÇLe­íí;|Ry¡êÜ:¾÷WÙ˜õ鮼¥ªVåÚ®ˆ’1zpüµÑ]ª ´ Õc&f3ð {3AÄë1“‰ŸJh êúBÍ/(TU£R›£Ày\Yi?š—ïÙ8"PT‘¹!kîžüå5¦®gN¸6* ‹ˆˆ´Ê€ å¨¾hŽß+xâÄÞLÜIÀ·y{o& 5»ë¡Çò ={®°zÞÇŽ7lÙúö—÷x\ÆUWI˜³¯àgUs¿ÅX€%l\÷—#:éæÛÎÛys‡Ð!w{ÖÙ'«lç½t8ãìN÷;Ó‹7,;ðoEEQD}"«¢˜QäD£¢ˆ"ŠI96ÓUQ¥sØð¡í&;ÇÉ,Ùüûá»EœÕ?v¼³ñPÑ›s¾èunÈ¿8÷®Ù•÷ƒóD¢©?‹(ŠbRDDLŠ¢¸–‘>ªCè`ç8ůKŠ8#>¨÷‰3¯Ï*ÝÞ-âÌȀήeäÙöWÙõ¥9k8Vâ|´}È€`kŒsœœ²Ý¥öÜ„à~–0—Æ=Ž¢øàd«)ÐÙx´<Õ®–×x]úIQN\F—Ë«(¢[cLʉo¿¶ª"MÔK¸ë:ý‚S€ë€&k^Çl&ÞÀ:!f¼ES¥à°U?.Í÷ðÿ,³UK¹°°¬óg{òÝ¿G›‹ªU…û·wfLrü—B·ÔAÓUj…C­¶‹“C³Ûª:ï«>›‰÷‡$å²/goüãÈl×eYUªmUúŒMYó%\Ó;êü0ÿöã{¼æ6TlP+{ÏtkL tMò‡M¯³[Ę®)gº…½£Îï9ÖmÊL¿˜q=£ÎMÕDÓDgt¥ °4QõFÍ¥QD ¶F» ž:Èu‰™ˆ$Ç\Ò1lhtõ}ýbÆu ®‰û‰D´Z4gÖé²QDºGŽ êêïÚØ#rl\P¯@KDõÆ¿$÷už®æÈn5kñsYB%"íC„úÅ»]À„¾eö|·„".¸—Ýa«íu ]N$š~:­æl¦K¨Ÿ9ĵEÑó‹ê†g©–Ô™¶4´Ñ#µN«­ÑmöŸç¯ÑmèZ‚­úò5hIªïÍDÌÀ3,šƒ1Ð’%†J t¨xݺÃe—ír¶—ØsVz}SÖgƒã¯íuNÍ¡YÕü#§I±Ô¬Áb pÛ¾Ú3!~q!~qnþÝæp‰HlPØ M?c—ð"#Ü{FS³g¿Øq5=0ªÃí5ÿÒù¡š—t{Þ+g¼¾ï§n-ª*i[ED‚üO4[þÚg‹Ëb\§Âiz^¦Çˆ.ùþ¡æ¶à"ÄÚ~B·EfÅϵ1¯û¥Ió­¦jiWL@¿ ;t<°;DŠKfçl×O§·[\ljòï=ªÝ3áþIÕì?,á‘è€dׯ¸ ACâ¦V{-ÇÖ¨ºæƒnçÕ4Qcû»Žéß«GÄÄ¿jÑgd@擄‹B­‰n=;†œ}<¬ë’êᬪ7ÆD•¶«²ÄYMÕ—:6R¥Z\\yH?²ÄZbêïï&&ÆýÿDm[€h:—¿2ɧ3-]ÇÐÓ:†9PôûºÃå–ïu¶WfýrèÕYŸN˜Ô#rlÕm€¸Þ+ÐÙÔX&Åæ×Ù­Ñb pÝ#Içg ,Mlm×=b¼[c¸_R¸_’[ct@²[ðä™Äщ!£Ý“Â.L »Ð­±WäU½"¯jÔàwiJi'¤—¬XvèX¦9(öš1·zg\­_µ©lÀ3Ç'Æ3›ÉÇ3­‚Ò9lXç°Ó÷þºîÈœ£å©ÎŠ*ÿ|ð¥Ys‡$\×=b û)¨‹ëL6xà*Ô¯c‡35Q5ÍhŽ2º­{3AGÌ´"J—ð‘“Ñ¡§ IDAT]ÂG¤¬Zäy¶ýÎ +2–x~CÖ'§%\×5â¬Z·|àó\¿348¡ÖÙ—Ð(AÖE1‰¦ù[›zn´jÄL@«£t8#)btjÁ/ëŽ|\`;è| ÀvèÇýÏE|rZÂõI£ ›ÔÅã½Ïj5¦û£K@‹@Ì´JŠ(Ý"Æt ?soÁÏëü¯°"ÃùP¾íÀÒýÏD& I¸>)|$“VèªßÙLð>b& SSȱÝ"ÎÚ›¿|}ÖÇE‡-Oû!íŸ1ÝOkw}ç°a„M„½™Ð̈™€VϤ˜{FÛ=òìÝy?nÈú¤¸2ËùPnùÞÅ©OÄõšð׎aC ,€áªßö…  ÞÇM©€6¤XzG_puŸ÷Ïìxwˆ5Öõ¡œ²Ýߥ>º`Ï=éÅŒ*@ à:›‰½™à}ÌfÚ“bé}QϨsw]¼1ëÓR{®ó¡¬Ò‹ö=”Üwh»ÉíCR ,€!‚­ }¢®SDQâ]Ú f3µ\û¤uÞ·Óð¾w?1ÝèZ¼¬)/í™×_ÔŸûë†?𣶶Á¬XûÆ\zMò#o ²Fº>t¤tÛ·{Xqè?FÕÀ(a~Ophüô¡ñ$†œat9hƒˆ™€6ˬøõMŸÙ#Úßh‰p}(1tQUÚ*cb¦”óGéR¾Yú]=Ýž›ñŠÞmÛ¶Ö(ýp†~¡þrÍeuõ9oÒ„NÃûv5 ´¼¬Ö>÷„>HÚ¡ÍV) `1ùˆ›xmòìaío °„‰HT@—®g] ­1x6ÓÓ¯½XWê†KLh-"û¤••—×ìp4?oç¾Ý"Råp¬Ý¸®ÖA¶ìÜ."aá]:tjÎba ‹)``ÜÿMJžsz»¿ÞþFÅe'`¼Âà˜)+7ûõ÷g[C (Êà~)"¢ªêö=µÌüZ½î7çñª?~­Ù¡Ò^©çP“û+ D›e1 Š¿ºsØ0£ ´AFÆLúœYsgï;f`mƒ3‰ÈÖÛj>ºúµ"$"«~ÿ­f‡]ûöTUU‰ÈÀ¾ý›±JÐv3]yñøø˜¸ªªª'_}NÓ4+i9c¦]Ûk>ºjÝo"2ùÊkEdç¾Ý¹yGÝ:lݵC?Øw@3Vé f³Ùè@-,ž»ªªêÞ[¦Lö‰_~[ýÊåçŸõ—ÆŽPV^>÷ëùK~Y¾;moqiILdÔþƒ&\pÉ9£ÇÔºòkß´³¯ºDD¾ÿèó¾=ûä¼ñáÛK~Y~(3=,4të¿*Šâì³èÃyý{÷ÕOñùwߤL  ïÛ«÷í×ÿ}hÊ`}@‡êøfé÷s¾øtç¾=á¡a}{öþÅ=¿®ugªª._³âÇ•?­Ûºépv–ÝnoŸ0fÄ·]c|L\c_¾«}úšL&UU·ît™e¦ÊL‘ÉW\;kîl»Ý¾ò_'œ‰k稔ä~5oÔunÈEnÈ+ÊÍ;úþ¼ÿý¸òç-kϤnW^<þêË&†‡4ì’€SÊȘ©´¼ìÊ‹'¼óñ‡û¤=õŸçÏ>*À? áO_³níßï:1çpvÖÂe‹.[|úÀ!ÿ}æå¸˜Øºž[XTt(3ýê;nÒóéÛ£·[üq´ ÛîS½/õà~½¥Üf;’“µ|õŠ7Ÿ~ñÒs.Ì9š{ÇcÓ~Ýð‡þhIiIÆ‘ÌV,Ÿú÷}Sÿ>Å팪ª~ÿÓÒWßûïîÔ½®í©÷§Üÿùw >~íÝZ#ž  êÝ­Çö=»ö¤í+·ÙN\ÉÕëÖŠHRÇÎíââû÷JÞðçæU¿×3uJìå6²Ç×¹!¹.ßÿüã}O?RRZr¼Á¶~ë¦õ[7}¹øÛ~½’28Å ™ÊJ-fóôÛî¹åÁ»Óg¼5罚éL]–¯þå¦ûït¨IIî7z舎í;lݹmÙª_Žädý¾iý¸¿_óíûŸéÛ?Õ”u4çÑ—ž9”™Þ..~ôÐ¶ŠŠþ½ÝË¥+~újÉÂ’Ò’”ä~gœ>²´´t骟ÓghšöÐóOõLê~ÓwÌHïÖ9éÜ3ÎVUuÅÚ5ú.Úo|øÎµã¯t›´zÝo·=r¯ˆøYýÎ>jhÊàØ¨è‡ÿ¼lç¾ÝEÅÅ<ûØâ9_6eûíAýR¶ïÙ¥ï>¤ÿ@×S‹Èié}6ü¹yÕ¿jšæ<—Ýnß±WßÿÛ}Å\S®sC.r­¾ÿùÇ[ºG_GÙ­sÒ™ÃFuëÜeOÚ¾ÕëÖþ¾iýï›Ö{pq@s32f*)+‘óÏú˰A§­Ý¸nÆìw¯¸h\ÇöNúÄ#9Yw>1]Ï>¦þýö»o¼Íd2‰ˆŒ»¢à¶ÂÛ¹oÕ¿f9|×Ó?~}V­ÁÍ o½–q$ó¯¯yô®iuM¡šóå§³ùù‡ŸºúÒ‰ú ÷ÞrÇÿÝ6yÇÞÝEÅÅN¾¢ªªê®¿ÝzïÍSô³WÚ+ÿ~ÿ?ÿ¶ªªªêÃùŸL¿í×ÑFqÎè1 qñwýí ±ñÎöÛ®ÿû÷OYýÇo;öî^¶ú—sFièå«ap¿”¿š'"[wnwÆLš¦é³™ô–!ýSÞûTgg¥Üß­s’ÞgwÚ^»Ý."ƒªïÿÝÄëÜ‹\SvnδgÕ3¦kÇ]ñô´G­V«þP•ÃñÁ¼ÿ½ôöëå6[ã/h^Fn^ZZ&"Š¢üó¾GL&S¥½ò©ÿ<ß'Θ=«¸¤XD®¾lâÔ¿Kytaá¾òßÄ„v"²ê_Wýñk­#dɼhìyÿ¼ïázâàþóö5—]á PÂCÃn¹ö†ckÚK>3íw:Ïîgõ»û¦ÛôãmÇwÔvRå½ß|öÇ]3& ˜vËúñ’_–5àÕ×Éy³¹?]vߺW_ï6|ðP>h¨Þ¾ê÷›snçä¶ÿw¯sC.rM³æÎÖO:vÔYÏ=ø¤3c‹Ù|ó5“¯›pUÃGÀI.]»¯ðëÔÂ…iE‹Z…ÑåZ1#c¦2[™~Ч{Ïɯ‘V,ÿéוõ?«ÊáørñB±˜ÍwÞpKÍ~V¿;oø‡~<Ñ‚Z±Z­Ýõ€knRÓ¹£ÇŒ:­ÑyC·>=zÿß%ÜMéÓOϤçdÕ°®q)ÉýõJ2Ž®§ž“JêØ9,4T\öó–ã+æâcâ’:v‘˜¨èž]»‹ˆk0¤ÇL³¹oÏÞÎÆ¦_ç†\d7š¦}ñý7"¢(ÊôÛî©õŠ5e]!jÚ‘÷¿U™¬Ì|pEÆôJGÉÉŸî´¼²­ùåÛòË·—T0ºÉȘIÓNß{ËúæÓO¼ül¥½Ro¬5PزãO}¶KÿÞ}ëZawÑØóôƒU¿×>›éœQgé3q+.:¦žG-KTx¤ˆdådŸt¨ŠÊŠm»w~µdáËï¼a6›E$ãH¦%9™L¦A}ˆÈîÔ}¶ŠcËÊôYK#‡œî¼˜£† ‘ÕëÖV9z‹KõîÞËuÚQÓ¯³yß4}îU÷.]ûtïÙ¨çÀ3š8œÇ&ÅÈ7Z)MSÚ{íò=W/ßsÕºôÇŒ.Fj)?EÂCÜ2UDö§œõÉl½1$(¸fOgÓ¥C§ºF‹  ‘Üü†\çèÈ(ý ‰»¡ á4×=S[Ø­ƒË·…-Þ|[‹ûô?pûÝa¡¡ªª¾øö롵-šKéÓOß³iëÎíGj»¡›ˆ,]¹\?¨y«8CÉÉÚðçf9äô±£ÎjÖs ê7@DvìÙ¥ªêú­›ô“ºõÑ·g:”™žs4wûž]"’’ÜÏí–p†\ç>Ý{ZÌfÙ¶{Gáñt¯(¯:º1ç9¯oÈyí`ñ2£ËЂ¸Îfâý!°7œZÜO‘舨i·Ü%"K~Y¶gjÍV«õ²s/‘J{å›Ϊ١ªªê?ï½¥O¼è²æ,¶¡ò í[Ô¡]bÍG‹KŠ+*+½u®Á}SD¤´¼lÓö­©÷‹È—™tCSëiÎú­›ôåun3‰A×9À?`øàÓE¤¬¼|ΟÖzÒ½µ}UNªÂ‘¿%÷í-¹ïlÍ•^ò‹ÑåhA\ß²© °7Ži‰Ÿþë.¿J¿™ý¾]k‡;ÿvkp`ˆÌùòÓ™ÿ{ßu–oIiÉ-Þ} ㈠tÚÙ#Î8%%ŸDRÇNf“YDÖ¬[ëv;¹5ë?ïº Å%Å5ŸåܰIߢ»œ»€Ïùò3éœØ±}¼ûvÚÁAû‘ŸÖ¬<œ%.›:¹j¾ë\ÏKûÛÿMÒÞøðíV,w}(7ïèÕwܸ|ÍŠF PràJӘ͠Iª¯½eo&ŸÖ‚¶w²˜Íÿ¼ï‘+o›œs4·Ö‰ íþóä¿ÿñÐ=ªª>ûæËKWþ4zèðíÿܵcéÊŸÒgˆHBlü›O¿è¶'‘QüF ¶bíšý鯺ý†þoR»¸„ìÜœ%¿,[¸l±ÕjMˆ¯¹0-.:V?X³þ÷y ¿þÅ~V¿“ž«W·å6ÛW‹¿•ê÷˜s5ê´aë¶lœ·ð+ýÃZc¦æ»Îõ¼´sF¹pÌ9ßÿüc¹Ívóô».sÎàþc¢¢·ïÞùùw_çäÇÅÄf×»+9 ®ß«‰™œà=+LCàöfÂ1-1f‘aƒNûöî;<Šªmàð™ÝÍ&›ÞBB‡„Ò‹R”&‚(Š+öН”ïµà«XQEšŠ€Šô 4é5zB Bz/›ÝïeIBÉ&›d÷åuyæÌ™™gv‡Íγçœ=døï›ÖÞ¬Á~wýôé·/¿ÿvjFÚˆÃ"[®íÖá›ÿû´¾¯_ÕGZ^O›5üÑûSÒÓŽž<þòûo›ë»uèüÑÔ?­\¾è·åÅ6qÖézwíñï=Y™¯Ï~·u³a­ÚÞò@µº}ë°½G˜L&!D3)zvéþùßMF!DÃúþ~¾õJmVE¯s§&IÒÜ÷?*z÷µ-ÿn“eyýÖðõ[ÕUj•úÍg^êѹÛè'ºÝ#$Ë4Y&̽™$ú ¨ÇÞòIb×jhšI1í…×6ïø'7?ïf úuïµsõÆåü¶iûßQÎgçæøxzwk?jÈð!ýîª!ý˜ÌÖ÷ÿç×µ_þøÝÎý{.ÄǺº¸„µl3fèÈáwÝ­R©n–©ùäÝÙoðŸƒÇ:ët7ëÛURÇÐv{PÊ=:w-µM§ÐvŽZGeÌZ‡3Yª¢×¹ŒSÓ99-œóÕ¦íÿ¶î£'§gføùøöè|Çã'†¶lSþ×p‹OlͰ$_›TE’Ô¶@­e²(׬›qT3éÍo›*¥@ßVÏû¼’»ËºbÈL4Þº`Sþj÷ú¥äX~öÅôŒL!„ÎÝ8ðÙjš—ã¸o…—Rž0fÔCcGWçÑaÏE…¯Øõ‰yÑÙÑë­Ñ;mªN–þÂïÑÕrS‘½þ×¶ñ¨9ÖÄŒI/8#„PKŽ[²u8°_¬–š}Ѽ8 Ë]Z?bÃxP…†ôµ'û*åîýz6ùʶñ êÌYÒNéè×îùÑ«K6`Ì$v‚¹™”îú 9fTPA|µÀUü!Àî0hÀ®~&0ÿ7€Š‘-ÍñIbçxû° ½™Ü„‰ÞL*Ëò«s3Ù5þ`',¦'ËàôfP)²Åw ÖvŽ·»pãw>òL®»>7w*ˆ¯¸ª”‡m€ºÈ¢7Ó O`ïZxÝ_`H“…I­r²u,j%æf‚i&ì?9¸.Ôç [‡ vSKŽþn}”d“‡®•­Ã-‘fÀ.08¨"Žï^Áߨ: ÔtfÀN08ªi&ì‚$Ñ› U‹4vÂr pÒL°>ÒLØ!ÒL°>¦À.hUîÝýß“$IÉÕ!ÀÖá "Í€]ШœZz³u¨Ë4+ Í+¨•ƒæÚ镞™Q¬Rë õó­Wß·^óঌӱm»ŸÜ €*Twz3é‹ôñ—?úËšU£&?xÏ#cÎDŸ³uPö¢VöfRh´ßÏùR)˲œ•–‘vìôÉ [7çåçŸóõö7|´¹ýûŸ}¨¤]º¶ïôÐèq ëûÇÄ]ÿèS‡##J€¼Â–¬þE£V4mÆ#Æ(Œ^}êùqÏN:u6+;ûžIc Ë=óê“ST*•B_¤ŸüÆ Ûöþk0ý¶ü­g_¶Ü[ ?YÔSÁÑ”¯UB%IjmHˆÇp[G¨ÅêÈà²,§gfœŠ:ûÓÊŸ=4jçþÝB?ßz/>ö´¹Í¼% 3²2…Ÿ¿ÿ¡9í¢ðpsÿÕ©BˆÌì¬ð[•Ê ñ±ú"½¢[‡ÎÅf&jÒ¨ñ}w°î)¸º¸.žûÝ„‘cÍÙ<ÜÜŸzðQó~òîìן~AÉ1 !´Ú—žxV)Ÿ8sªØÞjøÉ †0Êù'R<žºðXÊü˜¬õ¶@­ThHMÿ+6ý¯ØŒuù§ml©÷fÊËÏoܽíÍÖ6n:ÿÃÏ]]\•E£É¸bíïBˆ®í;•:ÇP‡6a ëû_º’x.&Z© jè¨u,ÔnÛ³3kòw7·*8‰ëõî_2°Ž¡í•Bëæ­,¸)Ú·•$I–åËÉW,ëkþÉ †eÙ\–O}PÙ…ÄMSÊ-ê=ê©keÛx`Cu¤7“¥ömBg¼6mÍ¿4 6WFž>•™%„è×½×Í6lÒ¨±"&¨uÐŽ:Rq>öÂðÇÆ-û}En~^Õ†^‚Ÿok5·‡—âJr’e}-=YT?Y\Ÿ‚³Œç@da2—¥º˜g@ùÕâÞLZíwÌ5/ÎþrNôÅ!ÄÔ)¯õìÜ­Xã¸ËñJá“ï¾üä»/ËØí¥+—¯ïóõw³srþÚ²áB|ìÔfü÷ëOÇÜ3â‘c‹ C«:NNº[5pBM&ËÊZz²¨~7ÞÒ› @…Xô‹$¬í[-Î2j4ê»z÷3ÿ7ýÅ7”úŸ}`4,ZfV–R$I­R—ñŸ‡»‡Å!4_ÏþdÙ îèØE‘“½è·åw?|ߤWž17«ìêdP²l‘fâæ@…ÈÂrøm-Î3 òjqo¦bôìÛ§[ÏûwŸŠ:ûó+'Þ7Þr­›ëÕIš^ú…}º´ÜTŸn=ûtëy>öÂ+–®Xû{~AÁÖ=;÷9ðë7‹:´ ³Ú X],*ƒÞL¬A¾u؇º“e”$iúKo(b›óÝÊäDfþ •ÂÑÇ+¶ÿÆMf½þî¾5ÿ<6n¢"¿ à‰7žWžÎ¦P_{\¡¾°b‡°–j8Y@­# Ó¶øW¶Æ¿¼5þ¥ÃIŸÙ:5…eo¦ºtw :ÝÐ/’OûV§ÞþVM[<0rŒ"=3ãÓ_[®jת­‹ÎYq âpvNv…áéî1ãÕ©C B$§¦Xæq|½¯NךžVrC“Éd0Uø¸·¥NP]ÌÍÞ›ý÷•¼C¶Ž@MaÙ›I%Õ©»Õˆ¹™pU]ûCòúS/¸:»!¯üÙrF!‡{Bdde~4ïórîÍòñ®–:´m§ŠŠ®gŽüëù)…c§O”ÜäÃo>K)-ýTªádµšLÏv×0h@å17ÌêÚÛïëíóÂcO !Œ&㌹Z¦N^xìi¥Ï’Õ¿|µh¾ÁX|šðCÇ^ˆ5/F_Œ¹ólZW,ÿb47ïøG!IR»ÖmÍõ )®Ý÷ˆ8l®7 ÿùôƒo—þ`ÅÓ¼¥ª>Y@­# ËŸI3¸J–-¾(Ò@YöfªkyÜ–º3¸Ùãã'.Yýküå„ûvÿ½kûÀÞý•úÿ†ŸÏøèé·_6šŒûù†m[†ô»³MóV²,G_ŒÙ±o÷¿ö ìÝÿ‡O¾BȲüòŒ·£/ƼøŸ7Z¹|ôÝÃÛ4o¥srº·è·åBL¸w¬›«›ù¸:'§‡FûnÙBˆ Ï?1vèÈ àÔô´5áë/wïØµ~½zn^_=/BUŸ, º~÷H’ €½™TÞs3‘°¶ku0Íä¨uœöü«Ï½óšbæÜúÞÑSë UV î{çÒÏç¿øþ[É©)ÇOŸ8~ãè6Zíãå]TTäàà IÒ3>žöñÌ]ö:~ôÐñ£ÅŽ2 GŸ¯N-Vùä„IkÂ×_Nº¢/Ò/ÿs¥¹þÞÁC?œ:㋾µþÙÞ\UŸ, ’®¥˜H4¸Š›CÖ`ùÕ‚O»VÓLBˆawéÒnéÁcG.ÄÇ.üeɳ?a^Õ«k÷WmZ±ö÷Í;þ9uÃÅÙ¥q@`¯.wL;ÁüŒ6!Dp`ÐÏ_.¸7áÊ墢¢ €Æ!ƒ=®O·ž%ëç[ï¯~ýzñ÷G"#ÎÆD¹º¸†¶lóȘôè#I’§»Guœ¼…*=Y@­# I™:áÆK°k7ôf’èÍ "nœ›‰4“]«•i¦ˆM»Ên IÒêùKo¶Vçä4iì„Ic'”çXÚ„uhVþØü|ëݬãϳ?a™ðR4 ŽÝ[Ê”á Z]ÆZ!Äž?ÂËŽ§JOPËHÒµ/ôfpÕƒæ¸9P!–¿`17“}ãíÀ^XÜ@’fpÕ ƒæèÍ BèÍ3ÒLØ«_ûH20»±7w*†¹™pH°ôfP’,Íe‰¡.p^ IDAT*„ÞL0ã öÃÜ›‰4€«nìÍÄ 9ÂÜL¸¦VN*E&Íà*mp¯³ea”…ìíØÂÖᨕèÍ3ÒLØ ‰'Í(A§ñmæ9ÊÖQ¨Ý܃›×›$d“,dO]+[‡["Í€ý`а>O]+²KP0fûA'vT!ÒLØ ‹G•Ó› ÖGš {aîË$[>°ÒLØ ‰¹™P…˜{qWà7J?&ÊÙÖ± ²ršIæÇQÔ\¨ì“Ÿ®£­C@]fåAs:Fá¡йs¡`eV¾Ù–$ž”ŒZ@"Ë€µY;ͤb0jÒ¡X•ÓLjµäàÄÏ…Do&dÙ/’;/»VµHœTÞ«j\PNÞ5Z'¾3”ÂdÙ›‰4€ ¹¡7Mì[ÿ!‘„Î]íÀ`%ØŒgCµÎ]M> T7Þ’fP!7<ÿ‹O»Vå]$•põÖ ENŠñÖ­«rõU»úhø¾Š-qÏæ]’e“ƒÚuX“Ÿm€A–½™øy@E07̪cD›¤þj£ÈH Ó„êãÙPíâ­&ÇfÙú¸,ý!„VífëXÔ²Ez3¨ z3‘f²kÕ4q’J-¹zk¥”ƒ,ߺ=PI>A;9&¸Áõ_ùc à™)ÀTÚ Ÿ$܆ٷê{û%•prU×oá u&µ‰*¤u–ü[:8{c€®MÉI’ €™l98ߟX·üv­z' 'U½`‡œ4cf¢‘/¹°2Ixø«]½Õ* ŸkP ‹¹ø ÀÌrFÒL*âÆ~‘ÜŽÙµêM3 !„Pi$w?³‡:?˘™h¼a'P!’J¸×Wë<ÔŽ|¢@̽™H3¸ÊdÙ›‰4€Š±/qSf×lfºz`GÉ­žÆÉUeÐËYÉF}.ßwQZÉ­žZ£•´:¾@ùñg€™Eo&ͨfyƒ™ÍÒL ÊA'œÜÕF½ÉP( sMÙ&}?²âæ$áà$éÜTŽ.*£PkUäÊ œ4 $YЛ €uq‡f×lœfRH’Ð8ª4ŽÂÉ]åî/ŒE&Ù$ YÎË4‘A€B–…ÎC%I’¤’Õ¤– b® šãIs®1ɖχRÛ0µ—,37®ªi&K’$4ZåWɃaP(ŸYPQ$锂¡.*¹™pH° šPÒ}¸;PÌÍ3Þ~ì…týIs<çÀU7Ü28+ 7“]«qƒæ@•1§™èÍàªöõžké5^&Y6¹84°u8j%æf‚i&ìǵ¯}Là7‡Fnl€Ú­±×0O]+YÈB69kll‰4ö‚_@UðvnïíÜÞÖQ F`ô5vCbЪi&ìOš@"͸ÊÙÑK£r°u¨B7™#Ó°%IR»8zÛ: VÆÜL€«ò Ó%!™d£JRÛ:T Gµ§NSO™¡I2S5l('?© (Ǽhù¨2µi&Àu² ôÙÎŽž¶Uâ®ÀolBa’M…E¹JÙÙÉ;¯ ½ÈoÛܒѨBvtpÕ9ºûy6+µ ƒæ7È-Lµu ŽË+L3?"¯ MYoȳmHn©@Ÿ%„(,ÊÉȹ”W˜QjMPýNFC¶Ñdtuò¨Þð€š«0G½m¡ouÑ gè lÃ$Lþ^MÔ’:!-Z©IL?]Ͻ©m£u[búéb5……Y6‰@ùê³ÍeÖ½Ô6šËi§õEyB£ÉPMq5žÉ$²SR » /*HL¿`Y“v",h˜ÂváRúÉb59ù)6‰@ùåä'›Ëº›ôUR™óOùúœR[ê°|‹_$ i‘6‰ØøÔãÅj’ÒNÙ$åwÅâßéÍæfÒè=2si&@'GG'''[G!4t¤Bõ)ùáŸr4§ ÅÕ©ZÇû¡7äOÜ­”U’Ú$…9ùɹùÉ.ºz6 @Y®¤]ï‡Ø¨^ÛRÛh\u>JÉ`Ôgæ¥x8s_ûµ`î[‡T·Ô¬KÅjL²éd\x·æl¨óÎ$l-2*e äŒóJùRʱæwÙ..·ŸtX)¨Uï–¥¶Q5ôim^HHªŽ¸5F|ê9¥à Ñ™+]\g£p@Ýwìâzs¹M“ëy¥³Ãm€rIJ;›¨”ú¶Ñ¨Km¦ ¨j^ˆO=[¡j†ìü´ìü4¥Ü¨^¨‡‹¿RŽK9›|Øvq€:+)3êÜåJY§uï×þ)ÍÕi+¢â·®õrPÓœº°Á\ ¹çfÍT¾×GÓOŒ¨Ú 5IÔ壿r€oÛ;Ú\(·íÄ<[Dê¸í'¾•e“RîÜrŒ‹“WËÀ~Ê¢¾(7*n«íBpS²l:uáj?DIHíB†Þ¬¥Ê×3ØÝÙOY¸t"+§H€½8va»¹Ü, g¯ÐGÌNÜŸzÌFq€º))3êDì&¥¬Q;öïð”¢C³áæû" !Û&87w2fyÄ\#¿v^n7k©’„Ô®é0eA–åcvVG€[+Ðçž½tH)ë´îÍõvÒºõ ›dn°zïÔ"c¢uÑdX½wª|-‹Ô­õx7çzBˆ6Mzº6P*“ÒOGÅm³U„J%˦½Çç›{…>RFc•¸1y¼÷ÌZ™ä1ØÃç·ŒEJ¹Mð Z+„èÝî1G­«R™š}q˱Ïm¨[þ=õýåôSJÙAãtgÇg•²ZåпÃ3æf;Ž|nU &ˆŒþ3-ë‚RöõhÒÞ"‰T’Jè×ÞË­‘²œœââ®*Ž`ccѶã+Ì‹›T :­û¸þ›ë÷žYr:)@e%¤ß~â;óâÈ^ï)]™][uw©¯”S3£÷F.¨îøÜDN^ÒÖCsÌ‹wvzN%©Ëh¯Rþ7 ãõäñ–ˆeth€ºí`Ô¦Ìk“ñø¶mÖ¨§yUhðàöM¯ÿ@±r÷LÒ*#)3jñö§Œ¦«Ý¨[öéÚê~˵㮯˜÷û.9Ç 5¦½3 õÙJ¹O«N-F—Ýþjš©KË1ž® •òåôóÎm¬º¶•W˜~t‰yñ®ÎÏKB²lpoïÿ˜ç/2,ÞúdJVLµ†ꊌÜK?ü=©àÚmªV£Ûïƒbß=„[ŽiØG)MEn¥@ŸU­(a_äÂó ;”²Z¥×ÿã’ÿx‹Q]kí`Ù¡iíù¹IU%À¶þØ÷uNA†Rö÷nѦÉÀb \œ¼žõ«9ÓThÈý~Ëċɇª5JPû]N?õý–‡òõ™Ê¢ƒF÷Ôˆe.þ%[JBÓ÷¿NZ7e1=;võÖç ÆÂê‹ÀN]ذãÈõ©Zûw|¦¡o›[n¥2—º¶àÛV)åý¶ë €ºçLˆ˜mJY’T£ûÌ,õ‰ú^Í2O­rPóõ™?m}âTüßÕ'¨í¢w/Ü21;?YYTIêÎ ôkw³öž® ¸óæo& IGþÜþªI6VG¬ntáòîuÿ¾-®å…‚êwÔùÅòl¨~ÿý÷•’JRùw:pú7eVÿ´œÄ|}NË€®U0ÀâSÏþ¸eºÑdP{‡=zGënÖØË­Q _ûcÑë•¿ ²lŠŒÝ˜’ì×ÕA£«¦ˆ@-TX”³îÐÿm:2Ç(_ýÖ¡R©ôeÛ&ƒÊÞ°žg°J­‰NØ£,¦g_Œ¿r°YàµcÕF ÀÂñ¨ß×þû–|-ÉëëÑäÉáK´ÎåÙözšIáªó•T*ó?鸔Ó:­kãz­­0ÀÒrl~+_Ÿ£,úzOô…¹¿R©|<‚š5êyò–"CR“”u ê­Fà&I·˜ ì,äç~Y¾cJ\j„¹ÒQëúèù­ƒ”gÁ ºfå]IH9¡,få^:qþ¯fúë=«$bdÙ´/òû~¨üÒ,„pqò~zäÒRǺ–ê†4“"È¿SBrdJæeñÜåC^®õz7µZÈ[HËIœ¿éMóÓåµ®“‡ýXž¿ž® :6¿÷ÔÅò ¯Nçd4¢.°ÆQëæçÑL%©ÊÞ°&Ù»aÅ®W#.üe0éÍõž® Ÿµ²Q½ÐòïªU`ÿÄô³ÉÑÊb‘!ïXÔ*S_~åªPJFÔê­SNƬ5׸ê|ž±ÔÏó6’B’,Ÿ€IoÈÿn̓ñÉÇÍ5}ÛŽÚùIþ=@-u1éäOÿü'·ðêãZÔ*ÍãChгü{(2äoÜÿ¿]‘‹Í?k(tZ÷Ö…6¾;¸~7•¤¶fР60ɦØäѱNÆmÎ-L·\% ©këqûOuÔºÞîne!ÿ}è«-¿°œ2¸¡o»¡½þëåd…¸X(2äïŠøúà©%–ßöë{5|èBO׆·µ«RÒLBˆ¼‚Œ/VJÏŽ7×4oØéÁ¾ÓœÝ*4 úÉBÞrtéßÇ–Y~Ú¿ó“NÍGU`o—SO/ !%3¦ä*µJÓÀ«MCï¶õÜCœ=´îN®‰'êY6åè³s ÓR²/\N;y)í„eß%3/×€‡}è×¾2‡;rîÏÛÞ4™n˜<°~×aO5è^™=Päæ§:½ìðéeE†|Ëúf=½û» LÉZzšI‘—üã†Éæ±BgG·‘Ýžërçí`i9‰+w}x}fÚqü€9íš­ð>M²1"jÝ߇¿JÎ8_vËŸ°„Ôãe·µK€whBZdÙm¼Ýt|¶s‹ûÔ*M嘚uñ·moÅ\>X¬ÞEçÛºÉ=-›ÜÝÐ7L”öØ\eHËŒ‰K:xúÂÆ¸+‹WptpÖcj·ÖãK} õ-Ý4Í$„Ðå- áLÜvËÊ&~mux¸YƒŽ8 zdç§o‹üuß™õEÆBs¥³£Ç#C¾ nÐ¥òû—…|ðôÊȘMgãvÞì1ÃA~].&ÿFjµ z/&*u•$©šô ¹§[«q’U§n”…~`î¶£ó¦¢R[ß»u€_G£—“ÖÝIë®RiTÖÈpu†,› ôY…ú¬¼‚ô”Œ¨¸+‹ y¥¶l×tè¨Þï»8yWøXe¥™„²wF,ܰoN±»ˆ ¿6=ZŽ ê­Qk+|l€uÉBŽM>}ìÂöݧÖûÜöólúè= |Ü[÷ˆzC~DÔÚó—öÅ\>ž“`¹ªE`Ÿ³q;­{8`[Íõ>ÿ¯e‡‹HÃnMü»vl>ÒÑÁ¥ê] ÏÞ}bÉÎc?äd”ÝR£q2\{H.!D}ï6WÒN–Ñ@RËÆýv~¡’]Å-ÓLŠøäc+¶¾u%ý\±z•¤nØ=ȯuHýv>͘ül"-ûrBZT|ÊÙ½g×ès‹­Õ¨w}¹O»Ç«úSÚ`ÔŸ‰Ý–¯ÏÊ/ÌÊ+ÌtvôHËŠ«Ò#€jæíÖ(¯0Sçè®sôÐ9z´jÜO£v¬ÎL&㡳«]uáò!ËÙÁ-9htÅf™ì\#¿NñI‡K]¥sôèØüÞ®-Ç6ômc•c•+Í$„eÓžK7ø´PŸSúŽ„äéêçâä¡Óºz»úçé³­ $“Éh4 ô¹ùúœ¬¼Ôü›2· |w·×êy†Ts„UªPŸ³çä²øäÈK)'R³bÍõj•F­rГf,´hÔçlüõqµ6Я}PýN-û7ìV±9˜n¦¼i&…Þ¿çÄÒßç䧖Ѭq½V±É§+ ‚$IÕ.äž_ðójfëXª–ÉdŒM:šW˜‘_˜Y¨Ï1˜ŠL&ƒ­ƒj7çz£^§u×9z8iÝýÚUݱn/ͤ0šŠÎÅZ{ââ–R;7׋¹ÂÓ…  i5Nú“HBj\¿cûfÃÂBîqwö³I`ìVEÒLf²c¯½r$>ùxBʉœüÔüÂL!Dó€žçv[/H@q.õ3s¯8ht®:_&ê…ø†ùw"»ÀV*•f*U¾>ËPT`”é£UH¥Ò¸9׳î8j¨ ë§™`‡T¶ui&Xi&Xi&Xi&Xi&Xi&Xi&Xi&Xi&Xi&Xi&Xi&Xi&Xi&Xi&Xi&Xi&XÆÖÔ>²lº’•™|"· -¿0+_ŸéåÚèJúY[‡p ž. s ÓtŽ:­»³“WŸV|Cø´V©Ô•Ü3i&€ò*ÔçDÆl>|îè„=²‹­•e914¨éŠ …©Y‹UJB òïÔ¡ÙˆvM‡¹8yUlÏ’,ÿ†€bR2/l>ðÙ±ódÙt³6^Òã«3*€ ðvñIËM½ÙZIHm‚uo=¡E`ŸÛÝ3i&€²\¼rdË¡/ÎÆí¼eËFÞIYWª!$€ÊðÐy$g'ß²Y _»_lÕ¸ù÷Lš  tù…™kvÏ>|ö÷’«œµ.Á~My5 ð ôtörursvt–„TýATLž>¯@ŸŸ]u!%&!=.&ù|V~fÉf-ûé÷.þåÙ'i&€RœŽÝ¶jû´¬¼$ËJGcX`‡v;6¯ßB%ñÄ^PwÈB¾s,îHDìáÜÂ\ËU:­ûðžïti9æ–;!ÍpYÈ›öºõÈ<ËJ'§^ÍûönÙßYël«ÀªÞ ß½{ûé² ²,ë;6¿÷þþ©Ue=MŽ4ÀuFSÑoÛÞ>rîOs$¤¡wßÙfÝ—€ýey×¹ëŽþi²xþI³€žþÚIëv³­H3\e2¬{äü¥}æoŸ±Ýhê×܆QØÊ¥Œ„ßö-¿”‘`®ñ÷nùüè•]©íI3!„,›–myñøùæš¿föžìèàdèlËh2þºoiDìsMÿΓ‡ýä )å;i&!„X»ç¿;ý`^ìÔ¤ëØ®¨Uj†PÈBÞtlÝÖS[Ì5¡ÁC&úR*1¥S ˆ£QY昺…tÇC䘄’în7üîvÃÌ5‘1›¶ú²dKÒLÀÞeæ&þ¾ó=ób«mFwgÃxj ­ÝÑ´§yqë‘y )'е!Íìš,äUÛ§賕Åúþ÷~œ‡Ê”4ºóý!õš*e£É°bë›FS‘e¾B»µöLÜ¥¬V©'tD£ÒØ6$€šI’¤ =Ñi•ÅÄ´3;"¾·l@š Ø/“l´œVà®6ƒx6´a<5œ»ÎcdÇÑæÅßêsÌ‹¤™€ý:½!9ã¼Röu«wgÛÁ¶ æëÔ¤kðµ¡sy…™»O,1¯"Íì×߇¿2—ïl=H’ ƒ¨-‡Þc.o=ú]‘!_)“fv*.éXRz”Rövõ騤‹mã¨-Büš™;4êsN]ܪ”I3;u,z¹Ü³Yž.P~}Zô3—#¢×*¾N{$ ùØùõJY’¤vl@íÒ²AG'¥|&nGaQ® ÍìSbꙌœËJ9È'ØÃÙÓ¶ñ€U¸Ü/yÐøÞkë@Ô}µ¦MÃP¥\d(ˆJØ-H3ûŸ|Ü\nÕ° #P¶îƒ^—¼FH^#ön¾NצgR¾\‘fö(óÚÄLnNîÎZÛPIBªïsòSŒ¦"ÒLÀåë³”‚‹#9&€ r¶ø*•_˜Iš ØƒQ_d(PÊN:ÛV¤Ñ¨mû¢Ó^ÿ*•_˜¥±a(6¡7äµ `È/2y»úØ:UB–åõáÿòÏî}§¯$gxz¸´ix߈žON¢sÒÞl«#ÇÎñÝšÈS±gÎÅgçä—ÚfÞ§Ï=óØ=;PA¡^ç?F1÷ƒ'_zf¤âÄ騝æ¯Ýúï±Ø¸äà úÂBžœ4¤ï°2NÍ`0.ùuëò•Û#"c2³rø ¾³ã[/ ªïá•[þW *ÉÕɽ±OƒZëà`4‘fvÇh,:}q«Rvqrµm0ªBRræƒOÎù{{„¹&9%s{Jæö]‘Ÿ}óÇÚ_ÿÓ¶Uãb›ää<ùâ—¿¬ÞQÕ273Œ3>úùƒÏ~3MJåÉ3q'ÏÄ-_¹}Áç/L~dp©FÇ\¾ïáÿ;qÁ\sñÊw?n\úë¶9³sws¾­ø ’Œ&ClêE!„çîêô!eÛ¿Çwí;u!6éΑӎýûU}?Oó&²,yä¿›ÿ9"„hÒØïÍ—Ætl×4''ÿïퟻ&¿@¯Ñ¨üú%?/!D«*| ³˜‹Wî}pöúðƒBˆ][µlp9u×ÞSyù…Bˆ×Þ]8ntï’9£ ±I½î~óJR†B¥’:¶kÚëŽÖ™Yy‡#¢Ÿ¼ðÜkóªàå€Û@š @Ýa2É&ÏQR?þgÒ«SF98\½ë‘eyþ¢MϼúuRræ´Y‹~ù¢y«¿6îWrL­š7:°õ3W—«ÏçؿèaÝ{ßó–Á`\¶bû†•ïWò@fËWnB4oÚð·Eo· V*O4jzÂåÔ¬ì¼ïo~uÊ(ËMŒFÓ„'>VrL¾>î«OíÛ3Ô¼vÓ߇Ÿ~åë‹qI•zù r˜@ÝñǺ=[wB¼:eÔ[/5§~„’$=ýØÝ÷è)„XºbkNnyÕ_÷+…ÿ¼=ÁœcRÜÑ¥åý÷öBlÞzØr“ŠÈRÿÞa{Ã?1瘄­[šSKÛþ=^âÔöî=xF¡ÕjvmüØ2Ç$„rW§È=_;::”ùò@Õ"Í î˜;oBç¤õÎÄRLšp§B¯7œ‹¾d®LNÉT ¥N¥Ú&Ha2É'OÇVò@f^ž®›VÍôör+V?lpW¥)¥Øªy?¬W O?zO‹f%÷éêâ¤Qó¤9¶Dš @‘‘™»{ÿ)!ÄÀþœuŽ¥¶1'hÎF%˜+Cšø+…RSBg£®Vúú¸Wò@fZ­F«-eÿúW'rŠ¿”jYŸ_ ÿwïI¥üÊs÷–zD°9æfPGDžº¨<µí¯û%¯e7މ½b.Ošp×gßü)„øèóUÇt³L>¿òÏ]BˆVÍÕ¯änÉÝÍY¥’L&9/¯Ð²þ\ô¥ÂÂ"!„‹³S“Æ~åß!T'z3¨#ÌcßÊÃr¦ö¡ÁÓ^'„ØèlÿáSÿÞ‘‘™›p9õ‡¥á†OËÍ+ppÐüøÍË’$Uò@·$I’ù(–RR³”Bó¦ Km5½™Ô&“¬†é:ïÓçÊnìåéj¹8û݉ã’–ý¶mÏÓG½k¹ÊÓÃå›ÿ=×½KK«¨b”ÎSB†Ù—Ô\¤™Ô~õ<”¹ó—5ô½­mOÿkã~FýÊs÷nþçȹèKnnºVÍõîÞæµçGKUæ@ãéá¢â’«ápP1¤™Ùþޏ IDATÔ­[J’$ËòÙ¨KÙ9ùn®ºrnh2Éãý0+;oê+÷ÿ÷½G>žñX¨ÂÌÓB]IÊÈÍ+pq¾xPm˜› @áëãÞ¥c3!„,ËŸ~ýGù7Üøì‰Ó±Bˆ!wuªÒU˜¯{ÓàJyùoÛ«áˆP¤™Ô/aÃwBh4êU‹§õòF\BJbRúÀQïèÖ¥cóà úQç/;³e[„,Ëm[5~ë屿Íûõ ­ç둜’ùÙ7î=p¦ç­}¼Ý$IBHBøx»×÷ólÕ¼Qó¦ Í›Tì@•ѸQ½9³þo…ËWnß¼õHïîmÚ‡§¤f­Ù°/.!ÅÃÝÅ×Ç=:æ²U@š @-ðóªe¬ÕhÔJšIà»ÿŸO~úÓ-ێʲüÏŽcźµnØ¢Y€e³ÎqÍÏÓŒ˜VP ßsàôž§K=Ê]ZΙùXŸm+| Jš2yX^^á´Y‹ cJjÖëöþ±n¯²ª{—–?/|ó_ýþÕ‚µV<"ÜÒLê?¯Í«gnÝy|ùÊmÛwE^ºœf’åúõ<ïèÒb̈^cFöT«o˜?D–å#Ç¢eYvqvj|þBbbRzÉÝî;xfèýïï ÿ$´uPÅTyo¼xß°!]¿š¿6|Û‘„K©NNÚ¶­?<~Àc tpÐúY÷pp[$Æî{“—<{I¥Ü& tRïɶ€Í}4wåÛ3~òñvÛðÛ eÆ%³¢"CFfî#çÞ|ïGåitï½ùÀŒ©Ù(R¨YÖY½ëìÕÞ¦SF­¤7»Ÿ<ý¿Ë„ï¼6¾XŽIáà ©çë1tPg§þç !NŸ‹·A”Pð¤9vm÷þSEE!D›–e4‹OV -›5ªŽ° "ÍÀ®ùx¹+…o®×ë ¥¶‰ˆŒyë?‹„.ÎN“\m±@í 9vm@Ÿ°a!GŸ_³a_÷A¯=9iH¿^aþ~ž:cÂ¥Ô¨˜KËVl_ñÇN½Þàèè°lÁëÕ³uÈPC‘f`×4õÖ¿þ;æ‘ÿþ³ãØ‘cçŸ{m^É6’$Ý;ôŽÿ¼õ`Çv!Õ!Ô¤™Ø;O—-Ì>pøÜÒÛ>›˜”ž˜”á¬slÒØ/(Яu‹ÀÇ'lÜÀÖa@MGš „$IÝ:·èÖ¹…­€ZŒ)À`¤™`¤™`¤™`¤™`¤™`¤™`¤™PqF£qòäÉnnnÍ›7ÿûï¿m*®C‡’$I’´råJ[Çb}¾¾¾ÊÙíÝ»·Øª2N¼v]Þµ+ZûQ·ÿe@í²åÒOg2÷›d“­€:Ž4*nýúõ .ÌÉÉ‰ŠŠš2eŠ­Ã¬©v]Þµ+ZªÙ¥¼sÑYG¶]^þëùÿ;¹×$mŠ{ä™O´|dÑòÚôkÙíÆÜûî7%¯sçýY¥QÕFµñݯµôš!Ít ùùù_|ñŃ>عsg777ooï°°°Ç{lÍš5z½¾2{~ýõ×¥rKII)uÛ±cÇV8€³gÏN™2ÅÙÙY’¤fÍšUæ\Øs±Û2qâÄbû©ØìÍ><}}}ðu€·–“/yèÐçÅ’«êûy>ûøÐà ú/=3²ú«˜›Å\ÆiVF¾lþî+¯m­x k ­¨¡dY~æ™g,X`®ñññ 2 ±±±Bˆ¨¨¨±cÇ>÷ÜssçÎupp¨ð±z÷î]v­V[áýóæ›oFDDXeWjµzÁ‚óçÏ—$É*;,©X7.”×ʺªáò¶¢jŽvôèÑÙÙÙÅ*“’’¶nÝ*„$iܸq%·êÞ½»R°ÖlÓ¦M‡®”õz}JJJrròéÓ§…ÉÉÉO?ýôùóç?üðÃÊž0 6ÓH4ŸuôpêæôÂDs}NQÆ¿WVI oïsWkÏ©âßç«$IZm)wpšZp[—žQVGãoþ÷lµEb-¥Æ\öiVR]½jã»2Ô‚ËÑ&–-[f¾9räÌ™3Û·o¯,šL¦ƒΛ7oñâÅ&“iË–-ÙÙÙÞÞÞ>V÷îÝùå+]>]ºtñôôTÊÉÉÉ'Ož¬ä«ô¶655µêv^ÇðZU…Z‘c2«¶h-3DfÛ¶mSÒLZ­¶ìÏ4k}ÀvèÐaîܹÅ*Fã–-[>úè#%˜>úhàÀ¼ÍSÔ)’P5sïÔÔ½ãùìˆÃ)›,;7å2w_Y}4uK{ï;ÛxöÔ¨¬öãnU¸oD•?MµuT¥ù—š£JO“ µƒæJ!ËòG}¤”‡¾zõjó-B¥RuëÖíÇÜ·o_÷îÝ7lØP™Sõûþûï·]3cÆ [‡S–¢¢¢¬¬,[GQ;ðZ¡¶¨êXµZ=dÈM›6õíÛW©ùì³Ï¬< V“„ÔÔ­ÃýÁoxÜÇ)ÀrUž!kOÒË£gF¤ýSd*´U„u›dnyšµëWL+²“ ‚4S©ÒÒÒ"##•ò+¯¼¢V«KmÖ¥K—={ö„„„Tchö%--ÍÖ!ÔÖz­êäŸ=+Ž9EåUϬƒƒÃ‹/^ù^É'6T^ü—µ–ìÖnl“×ïn4¹žS åŠ|cÎÞ¤5Ë£gI ×› l_Ť¦eû„<(yXòëVËú‡ÏI^#œŒ‰K¸a‚…CG£&=ûY‹.Oû„<8ø¾é_-Xk2•2¡á…ؤç^›wÇÀ×\ŽmÔæÑÉ/~q)ñ†¯žAH^#¶l;ZlÃáãgJ^#Þÿp¹â—Õ;$¯FLBDDƘg²|²ØÍž¨󨔹a=Ÿw×çž·¦Îø)3+·dœÊæIÉ™²,/\ÞeÀ+. ǶìúÌóo|›—Ӽᾃg$¯ß{srox»?ûæOÉk„kÀýEE7LÝõù·k$¯Ÿú_©1—ç4…Z­æ¶‚,¿ÛºnùΊr\$Ê+pùJZn^ÁŒ~nÕí'ÿû‡>öÜkó“ÒÍÍnùÊ”ñ<µò\{÷+ ìäYK$¯½ï~³ä†™Y¹Z¿Ñ’׈ó˹·Z4S),”Ñ:tPžñ´råÊ›­ SeYÞ¸qã˜1cBBBýýýÇŒ³cÇŽb[edd(ûô÷÷Wj.^¼hù<)''§’ÇJIIùðÃ{ôèáëëëääÔ¸qã±cÇ®X±Âd2•¼¹'EnnîìÙ³ÃÂÂ$IúþûïËßÌsÉÇš­]»ViЪU«›Ó¶m[e1''gÞ¼yýúõóóósvvnÖ¬ÙO<±k×.«¼VePÚ—ó*&//ï×_}ôÑGÃÂÂ|||œœœ‚‚‚&Nœ¸sçÎ2¶ªØERRTTÔ›o¾êêêêááÑ¡C‡éÓ§§§§ !ÜÝÝË{þ¥ÅfÝË»“É´lÙ²x 44T¹¢JUžgJ–­µ^d«¨¶Ø:(…¢¢¢¤¤¤2ZšL&ó³ó6lØPj›Áƒ+ üñRüõ×_JƒR祪̿,Q‰Ï·ò¦@$¹†Þ×äÕ{=å§ ²\Q`ÌÝŸ¼nyôÌÃ)›õ¦Š?-§šùx»ýßô‡…o¿¿(7ïzÒäÙ‹…o¿r`€¯R#Ëòçß®é1øÅ¿üŸ¢uЄo=ú›ߞø…7ü0³à§Ma=§ÌûaýþCgM²œp9uá’ðÐSޏp[±¹ºèš7ðõqB88hš7PþssÕ•±•,Ëÿûê÷nw½ºhùß‘§.Œÿî=ùáÜ•í{¿¸kß©R7¹{eüãO~ñ‹CG£òò ÏF%|ýýºÁ£§ßì‘ ;4sws6M{öŸ¶¬ßöïq!Dn^Á#ç,ëwì>!„Ч]eNÓd’'LžSþ ˯ü×À-ßÙò_$Bˆ•îjßûÅ÷?\~6êRaaQ\BʼÖwìóRtÌåÛzeŠ¹Ý àvßýÛRždÜèÞBˆÝûO'%gÛ|}ø¡¢"CçÍBšø—soµi¦Røûû›yæ[xå%'' !ââ↠rÏ=÷¬^½:&&F¯×_¹reõêÕýúõ+9»Êíúþûï›5k6uêÔ½{÷¦¦¦ÆÅÅ­Zµjüøñ½zõRæ¾%שS§éÓ§GFF !DÇŽ+Ь’.]º$„ذaCÛ¶mŸ{î¹;v$''çççGGGÿðý{÷~úé§•ãVGGÇ ¼SùùùsçÎ yà~úé§ÈÈÈ´´´ÂÂÂØØØeË–õíÛ÷õ×_/ûó½2‰,˳fÍjÛ¶íœ9sNœ8‘›››••1{öì¶mÛ®Y³¦Âi¦ò¨LäGíÕ«×ĉýõ×'NTé;[ÉP­¨Ú>`4h`.—œ°Ü’J¥4hRVft*¦  Àœ- /õbÞ¶m›R(u¨ŠýËRTæó­†¼éPƒI]ÛŒzehà3þº`Ë…Ƽ)ë—EÏ<˜²¡Ð˜g«ønË“ éÔ¾é¥Ä´?¿ú´Ö­;…o=àûú £ÍÍÖlØÿòÔŽZÍ¢o^Ί[qùÌ⳿ëܡٚ û¾ûñúåúùï§^þ*'·`Ô°îÇw•›°2þä¢7^¼¯Sû¦mZ?v™†éuxþïMB´iux¾òߘ‘=ËØê›…ë_Ÿþƒ^oxý…ѱ‘?æÄÿvxûç=º¶º—t÷˜÷ÎE_*¹ÉÐqï¯Ý¸ÿ«9Ï$[šxfÉ»¯BìÚwJI•¤Ñ¨ûõ BìØi®4M;vG6 i „غóú†²,ÿ»WI3…Uæ4ß|ïÇ5ë÷•?ÈÛRžk <ïl9/Å‹oÍÏÏ/\òÝ«Iç–¦Åü¼üû7\œ“Ò_ŸþÃm½2ÅÜîp»ïþm)Ï Ò®m“–ÍdYþkãþb›ÿ±nbܨÞåß[­Fš©îîîýúõSÊo½õÖñãV¸.íYJJʾ}û:wî.„hÒ¤I÷îÝ}}}Í Þx㸸8ó¢££ã;ï¼óÎ;ï<øàƒJ»»û;Þ~ûmËýO›6íÉ'ŸÌÌÌB4kÖìÁ|å•W† âææ&„Ø»woß¾}˸ÉLKKËÎÎ0`ÀÙ³g…nnn>>>jµÚܱ趚URFFÆøñ㇫Õjûõë7~üøÞ½{›ÍŸ?ÿÉ'Ÿ4·¿Ý×ê–Nž<Ù¥K—r¾SŠœœœ–-[¾òÊ+W®\Bx{{<øá‡îÝ»·³³³Òæÿûß¼yóÊ8îí^$f²,?õÔSï½÷žyTTHHÈèÑ£Ûµk§V«/_¾|ï½÷=Z¼·U8òÈÈÈþýûïÝ»WÑ¢E‹™3g._¾|Ö¬YÍ›7Wh4šÏ?ÿ|Á‚ ,xæ™glªuUÛìéÓ×–¬_¿~Ù¬JM3íÙ³§ àêO‚ñññgΜ)ÙÆ¼a©i¦ üËRTò󭆼éPóº´º7è¥áŸkàÜÔ²^oÌ?”²iyôÌýÉë Œ¥ŒÕªf«ÖìÖøÞ[ì?ó}©Z­úú“g…s¾X—"Ëò;³–!æÌ|ÜY稴ÉË/|éíùBˆ…_¾4iÂ]ZѼiÕ?MÕhÔ~¶R¯7!²²ó^}g¡âÁ±ýV-žÚ:H¥’ø|<ã±M«f*[U©ŒÌÜi3 !Þ|iÌœ™øªÕªŽíBþ^óíÚ6ÉÉ-˜6kqÉ­ÔjÕöuN™<¬ž¯G}?Ï™Ój×¶‰bÖC7;Ð]ýÚ !¶ïºžf:vâBFfî OÐj5[w3ןº””œàt‹ïesuuºÝ ÍʾD9®ò¼³å¼HÌúö =ºó‹‰ãøú¸{yºNÓwÙ‚×…®ßwêl¿fTà¨À»_Nå|A$I?º¸–T2+(Ô¯ß|P1öÞ^åß[­Fš©t_}õ•2Æ!==½[·nï½÷ñª0£ÑØ·oßäää¾}û>|8&&fÏž=IIIK—.U^dƒÁ`ù‹ºN§›={öìÙ³{ì1¥ÆËËk¶…÷ßßÜxÉ’%|ðÂÝÝ}þüùgΜY¶lÙ§Ÿ~ºqãÆS§N)=Î;7uêMŸÈ››;eÊ”èèèV­ZmÞ¼9###99911±Øp³r6«¼+V!^xá…K—.mÛ¶í—_~Ù¹sgllìÝwß­4X´h‘y\Ïm½VåñÒK/%%%•óR¸ººÞwß}Bˆž={nÚ´)))iÓ¦M‹/Þ¹sg\\\ÿþý•fÓ§O/,¼éÐèÛ½H̾ûî;óðÆŽ;ž;w.::zõêÕ™™™Ó¦MÓh4EEE·õ"Ü–ŠE.ËòäÉ“•ÜÁرc=:}úô &¼ûGV6¼páÂäÉ“'Ožl•¥UøE¶ºêù€=pà€Rðòò*»±¹7ÓáÇ•÷ÅÒ–-[„]»vÕh4B%ec)==]Éf—:ŸTþe k|¾Õœ7j…ç#¿0²ñ ÎÍ-ëõ¦‚#©áË£gîMZ“o´ñ4ÆF£©Ø²¸ÞͶ{—–O”_ Ÿ6sñ¦ï9pºw÷6ÊXů«w^ŒKêØ.äþQ½,wÛ¤±_ÿÞa‰Iéç/& !V­Ù–žíèèðÑŒGUªfT««ãrÕšÝYÙy®.No½4Ʋ^ç¤þÆJƒ’SJ¿õÒØ®®¿w’$õí*„H¸tÓoJšiß¡3æÁJJj©_¯ÐNíšîÚwª°ðê7I¥ÇÓ€>í*9åb‚´Tö nu ”ç-çEb6zx÷z¾–5Çt ð•eyݦƒå9©’*pTò…-Cù_ñ÷õB„o;j9Û×?;ŽåätéØ\1w»/omDš©tmÛ¶]¸p¡£££¢  `Ö¬Y5zôÑG÷íÛg•±–þý÷ßá7wèPe“¯5^¯ê©§ÂÃÃÍCÌþŸ½ûŽk"yþlèE:ÒAQA=QDDTÄãÎvVN°÷vÖS~ŠŠž¾ØÛ©§D¬'gÅŽ]±S, ¨€ HïU ”dß?Æ[CB >ßósŸÍf2;»3Y؇)EM˜0é£qöìY ²-,,dfù=sæÌ¬Y³X¬¯MÚÄÄ$00LZäïï/â9öĉVVV>ìß¿?‹Å¢(Š÷¯ýuMVOAAA{öìÑÕÕev_¸p¡S§Nä%yòl ÔÔÚµk¯_¿þøñãðÎ謣£¨¢¢yyy‚ç¼$h$………Ë—/'Ûýúõ{üøqÛ¶m™wÕÔÔ6nÜøòåKR€†#AÉ_¼x :::¾¾¾¼%TQQñõõÕÒÒ€={ö0hdUÔ†Ð7ØììlækâææV믃¦¦¦¤g"—ËÊw÷î]6lX·nÝ@X˜éáǤä"‚4o©ÜßšH¥#„Ð7ÄHµÍPóù#,šªYóî¯ä–GæÝ HX÷,ëRi•¨áØ Çmx/:ÿ ß¿9Ó~áM³ùÿ¦hj¨ýsæþÜÅû(ŠÚ½å7ÞŸƒ$Vò“sÁŽä˜Ì§Cz÷ôèfmj,ý_wÅñèÙpìÞ^G»ß[ƒØMÓOÃø'èá‹›@K}MÈÊáÿã‡öæ-µ**ªÂ^Ä‘=Á£ÔT•hoÞÓ¡=›]ò<–·H?: 1'> ɧ€È6 NÍŠÙHD“cuíÜ>%‹šS @}.¬hâ_ŽÖf:X”—WÞ¼û’IsñZŒÑ»®¹}»0ÌT£ñãÇ?{öŒ™?•Íf;vÌÑÑÑÎÎÎ××·´Tj#´333¯ÕŒÌ¬ñ­[±bÅüšÉkkk1‚l jTŸCûùù€œœœ3F—ÐýR$AÉ™‰~œuttø>¨¯¯ß»woàp8Ì¢l²*ji¸,›Íö÷÷wttüôéhjjŠèìë¦qs………¤c”“““““óu‘=1Htå¥uk:•ŽBßCË!fs]-þg®Þ‘w·âuÞýÖ=Í ,­ªïãkCh©¯¹Üà “²¦Mèg×¥Ú0ÀÔô\ØásYí‹ùwðè ÈÌ*€´Œ\°jk,ƒ` @žºù¨ª(¶Ô€´ôÚ—ZVPÇ¢(ê§>á¿é½9îçoºÛµ“——ëåÐþëÜÿ>jšÿ»>j-d]‰hâÔ¬˜D4ƒ–ZP0“T€´.l.Ș‘}àRPyÉápɶûa&©\Þ&N^ÖhÒºvíqùòå;v<~ü˜ìŒˆˆ˜3gŽ··÷²eË,X€k¥‹ÃÎÎNh ¢U«VdƒÃádff×í'Y`` Ù`f&zh²6vìX¡iÆ×¹sí?0ÄLVO5­ïN °`Á2ô,44ÔÜÜ\êGoˆšbÆ‘Ç~)úÊ•+dcÒ¤IÖÖÖ‚Ÿm”œYŽ·û/fbb¢½½½ ‹Úpꃈˆððð ÛUUUiii±±±yy_~çPVV>sæ ³£h øë¯¿àÞ½{¼ûƒƒƒ¹\®œœœƒƒCaaáŽ;Š‹‹ÃÂÂH(`"S?ýô“ÐÌ%¸òÒº¿5©JG¡¦†šÞ›$]Å­$Ch h-E}£ 9ì”ȼû)%±ðßè¤*º2*ÿáÛ‚gíµzØêôSWÐ’Eñ…ãré«7¾ŒÏÌ* iš÷yâîÒ©u§B?nÓ±Éê9:¬>DGHÁ¤—ù¹¯í¿ç>x½ÊsLdôÇ¢ç^?ruÿQÔ/HNÍILʲ0kÙʼ¥TÚ D´qjVÌF"ZqqH_Wýèä鯖 ûŽæÍçQÆÙЬþ&Ó”ä¾ö8¾z¤¤ªp¸ùï¼×ÿrÒßd•7žó8â—‹Ì{D˜Òno{¿ŠEÉMj»–·fýb—h(èŽk³šÙYÆ)9þ~ˆCW¾ÉSb¥é`§ÛŸ·vdèÄé{OÃÞ ÿ¥GdôÇk·Â/\}6rØ×õ¼Œ ´ ›m[ÿ¿ŠÈÄ@_ ļCâUÒîKÊùQØ$5¥eåé™y`l¤+ø®~rî !á1\.M4õím-õ5hoò<†]^ñ,,j^c®©ÑÄ©Y1‰hd‚!cCþnûbjÌ faļ VmMlm,#¢><yëÒ§3YuŽ1W×ܾQfW§N|||¶ñšþ IDATlÙrèС;v¤¤¤À“'O\\\"##É$#Ë<úòqppèØ±£Ð·¾[E)**’眺F£ÓÓÓÉG***zõµ&QVV&¢âQ†Ïa“0S~~~cWœšªªªºyóæ‘#G._¾,tÖmɦâ®éй¹¹L†VVVäÜÐD\4ggg²ñøñã’’555Þw‹‹‹Ÿ>} ÊÊÊRìÊ$YQ‡˜7XÑttt,,,,,,Ú´i3räÈž={Öé;«ªªÚ§OŸ;wîÐ4ýàÁ2±=üf"A%}}}kkëØØØÛ·o3óë?xð Ö‰™jRÓ•—âý­®‡F²’ÍN®à–} ¿Múü6¹ä]rILJIljI\jéû´Ò÷é¥ é¥ e2Ê>f–%f–%f±“H"‡BúÎ|ÍœæTd•Tòíü\YÀæ”VßÉ-ç”–sJ+¸ì .»’[^Å­¨¢+9t%—æpi ® ©Œê×/C3øS ¯!¥?GQÂ~?ÿ¯i¥rÄ:d.áI°O nõ]TÍ)%9&æb×l­*¹ü‹ç²(¹Z½ºé ”mŒ Ölù7+»pδ_ÚZùµ£½uJZΚ-L·á½ÕÕ”>¦ÿµÿ¶ÀË}xo%%…’R¶÷æ“|M½¨¸ÚwÍÈ@ž„T›ŒyíÖÉTÓ¼ ´ =3ŒÛÍ}Dou5å¢âÒíòî//¯\·í_1¸‡®ÿäÐ#ëͽˆLxúÎÁ®ªÊ—?q‘ ¿‡¼%„‹3ÿwN³!ˆnâÔ¬˜„‘—Ï¿ä߆?OWTT™›êÿ:Ô‘ÙÙ”€hu½ £]àʰ¤”ìèwŸì»¶kma qnß" 3IB]]}ïÞ½Ì᧐ ô¨‘ij~‰¾ËËË—••ѵñóó“m¥âãÇd£!¹“ MÓ“&MòððÈÈÈPVVž?~xxxLLÌÉ“'½¼¼†j``P{.uÇÛè[œ)ßÏÏL'¿oß¾FEE]¸p¡ÿþ ‹ 6Ô–M3$Ã,3Ó63=Ù`±XL4Kâp8Lt‰l(**’ Â¥âû¼¿!ÉôÅ ¾ìæßÉÿ;½„ÃBú¾ñgN ÁHžš9ï½±zÞÂò§XGÖ£Pxøƒ–Ö9Š_–RZ1¡-¡™Ë³äYŠò,E–’"KYQNEINUYNMYNMEN]E¾…ª¼†ª¼¦š¼–º‚–º‚v  ] =¾Ìµ• µ•øFaS-U,ô”MywÉQòƪíLT­LÔ¬LÕ¬ÍÔÚ›©u0Wïh¡þƒ©šU ÁÈ¢ä:hõg¹ÊÉÀ]M^Æ34E¿ûô÷Á+êjÊdÅwŠ¢ölMQÔî—#£¿ü©«ÓbêI°|ÍÑ%«ü³² €¦é‰‹¼^¿óe‘kƒ–Z+€G®O·+.>•¦éÔôÜ]û/YØLgr€AýìàhÀ3—”²SÒrȳxw޶\!ØD'´ñiøÕâ|{( w*°”†™ÏçÛYZUô*÷λ‚gœêýY«F÷nzx6´ó—ŸÊëܯ©¡–“prÁÒwéB7f0Tw»vÓ'öó?q{îâ}ol#+¾/œ=,#3Ë®s;÷^ܹ÷¢AK­’öç6–üÒïËÀÌ?–ŒNIËñ;vóø©{ÇOÝSQV,cW€¶–zJZN—N_ÚíoSíÚ9;§pÌô­dœë°Ï¢¼übÏÕ‡y inª?æ×>§Î]¼oåºãŸKØ‹æ ûsÝôšNváìalvÅêM'·ì:·e×9eeE6»ÌLôþ9¸¤};Óš>(Ÿút€3á%BOWæc+2JKœ®LP÷Ó¬ ÷CMÓâ´qjVÌFBôìÞþTࣧï3YÀ*Ï1cG:×çÊ4f€š¯íî-¿ÍŸ9¤NÆüÚ'üåû]û/Ïs¼§&fn¶6–7ï¾Ü¹÷bUg÷–ߤ{Ê ÃL’cžó«ªª ¾ÛÂF ô¯|ZZZ:u"˽?}úT¶aòòò$À”-æÊVuõâÅ f¬Ó·‚OãϱràÀ²±yóæF‹1€ººz›6màõë×2Ÿ ½®Þ¿?{öl˜6mé“••eiiicc3räÈQ£F5…¹ÀdH&7XŠ¢ pâÄ xþüyÿþý>|Õ×ÓÖÖ¶·· #¨ÐÐP²_Š#æ ‰ÝßPã°Òt0Q³&æP°˜m¨ö<ÿE ¾ìW–«6c…½Þ/Ü2ùêQ'÷*ºŠïžÒÏx i(èNk·™o§®’1ïÔ΄¡Jë±–Ô”øZªX 6›Í·ÓHµ‘j¾¦jÖ¦jRXöÔ@¥µJk¾Fª–Fª–âCÚJ†ÚJü¿ºh) éŒÌ;£S}ð5QBæÃÍ•UGäÝ}›ÿ„o *¬všÝºéÔP”Aïr¡SÛp8ÜÓ=xÝR_sñüj¿mZ=åüå§ÏÂcüOÜš5e PµÙ{ÊÐA‡ÿ¹ý22!.>ÕÜT¿SG‹Ic\† r`>('Çòýkþ¯C{ž<üêu§äìîvízvo¿bñ(²œ<¡§«~o§Ç ¿°qŸKØö]Û®òãÒ§ó‘“wËytŸ‡±‘ε[á©i¹Ý»¶35u)ŠZîáÞߥë®ý—^DÄ'¥d÷rèÐÛ±ÃÊÅ£ù&ë©¿–úš6[E½M”“cõêÑ÷-—>6Qo¡.ó×é4몦b¶qjVÌFBLërèï…þ<õèÙ[.—ëØ½ýoSüYÈ߀›l „^[òxU§ £íã¹ú0MÓ|#æ˜S3·%ó]_DÄ? }—–‘'½mpf‚ÃálݺuΜ9::¢&ÆgÖÏRSSk:#˜šæú ïN9|øpò¶mÛ¶iÓ¦ñvoid,ËØØ8)) ’““mløÑ4}ñ¢$Ó‚òZ¿~=ÙhݺuûöÕf¼«õZ5œ˜˜/³o4þroNNN$ÌtàÀåË—×4QtœÞ˜¦éqãÆ¥¤¤ØÛÛûûûW¥&~ƒ8p 3…‡‡ÛØØ¼ÿª‡™ _¿~aaa¯_¿ÎÏÏ'“µƒ´ÃLДîo¨qðNö\­[™žÖB½“àNsué,K",A ®·%C¨)csJ"rï¾)x\Å­6&¬¶]»é ’VÄM|>Îñù³–1|Gˆ–úšù‰§÷÷îÑ¡wõxРТ~é×M°§ ³–þáêN›ÐoÚþŽJJ ;6ÌØ±a†`&olš¹]—6Ç,]÷òp÷òp¯õãðúÉßB÷ïÞò[M½Hj:hM§YŸBŠÙÄlbÖ¬8*+9­Í-­5e]¯ ˆ×êYûâ\[BÌ f&ztþ•ú禯§yûÂzqŽØ¤àÜLühšž7oÞüáààðèÑ£š’¥§§3Ó¦Œ1‚ÅÂ+)}Lw†üüü¬¬,Á .$£T233=<gœ‡ vñâEÞµ¢+**Ž=êääD–ÜVRRòö–ΠqÄG__Ÿ™=zýúõ‚ÁƒÍ›¿ôœ?~üx¿~ýyÐ4äììÌ·¿!03Ÿ>}úÈ‘#ÌþÄÄÄQ£FmÚ´IÌ™°7lØÐ§OŸˆˆf—Ë=uêÔˆ_† ÛÚÚΜ9“ïSµ^«†ckkK6Ö¬YÃf]Ü·ªªjÇŽݺu‹ŠŠj C÷íÛ—<¸xñâ}ûöq8_—Fþøñã°aÃD¬Sd#55µ )SÎ7n4Á(XÃiú7XÒ¤ÃÂÂȈ9GGGÞùæ gÏž***pÿþ}2hî§Ÿ~’““òz´Mêþ†B߃ nYxNP@ºW¹wª¯%GµnÑŽõ²~ÆS„Ž%D!Ä ÍñkÓ¦MHHÈðáÃãââàêÕ«W¯^UTT433Ó××ÏÈÈHNNfåääŽ?neeUŸ#>}ú´Öie&Mšäææ&Ág;wî¼nÝ:æå¢E‹ÊË¿þÔ$Ž ++‹wær•¿þúKœÂ7(‹µhÑ¢•+W€OXX˜ƒƒCZZZHHHTTqóûï¿'$$ìÙ³î߿߾}ûÎ;ÛÚÚjjjÆÅÅEEE‘9³W¬Xñï¿ÿ6higÍšµ~ýúªªªéÓ§{{{[[[çææ¾~ýšÃáÛØØ0“+ÕDNNîÉ“']»vmÓ¦]IIÉÓ§O È»†††§OŸ&εj ,¸rå ·nÝzøðáúúú©©©×¯_ÏÌÌTPP˜1c†˜=¹êŠ¢¨#GŽôèÑ#''‡ÃáÌŸ?ßËË«{÷îñññ?¦iZOOÏ‚tÔªU+ÒceãÆ±±±{÷îmœ¾E–––]»v}õêULLŒ™™™³³³¡¡!S­rrr$nØ¡CggçæÔY²ño°8p`DDDZZé™È7b”””œoÞ¼yøðᢢ"h€sDÓ¹¿!„PóVÁeGå=x\Á)«þÕJý{ý_t•šÊÒ+!Ôôa˜IkkëÈÈHŸ7’ÇûŠŠŠ„„&(CXYY:t¨OŸ>õ<\zzú¥K—D§©iþ×Z?ûùógÞ—þþþ%%%‚ÉŠ‹‹yÇijj6…0Ì›7/ €LPÆL×rïÞ=www (j÷îÝ:uZ¾|y~~~yyyxxxxx8o&]ºt¤“. ½{÷Nš4‰ô$JNNNNN&o999ݺ5ÿ´ D­×ª 0ÀÛÛ{íÚµ‘‘qðàAæ­^½zùùù™šš6P˜ ,-->|øë¯¿ÆÆÆ@qq1³=8;;9rÄßß¿¦0ÓŒ3ÈD<ÙÙÙû÷ï_µj•±±q•EQ×®]0`@tttiié7jJinn¾bÅŠÙ³g7›±u|ƒ•À€¶nÝ ¤£™`˜ ú÷ïóæMc‚ 35ûB5W•Üòèü‡‘y÷Ë9¥|o™«w´×ûE¿úª|!„j…a&ᔕ•===çÎ{ëÖ­K—.EFF¦§§çææª««;::ºººÌÍÍÕ××·±±™9s¦«««¼¼<èééÕfÒÒÒ:|øðŒ3||||066NOOoœ0¤¤¤(p·nÝØlvbb¢ÐpRRÒܹsUUU'OžÜ8kMüÛ»woUUÕÒÒRRT¡Q~Þ¸’™™Y»ví®ÿ"2>úí'm-õAýìÖ­œhl¨Ã—LQQž¦éÃÿÜÙ8è]l²©‰^ÿm·­›¦ª¢Ä›,+»pÿá  ÛÏß'¤Qe×¥Íô‰ýǹ9óåFV¯ËŒûG_O£Ö< Œ]ñçžÀ+7¢ß}b³+øÞÍŽ?©§«A¶_DÄïñ½ò,<&7¯¸›m›á¿ô˜7c‹…12T/fB!„B!„jáwìæâ?}.a€²²bjz®ÿ‰ÛWž_ÝÜù‡V¼)¹\zÜÌ?O>"/ãâSãâS#¢><º¾•tt¢izݶSÛÿdrc³+îGÜ Žˆÿ¶zéXÁ£'&e.XvàìÅÇ5åIäå;ö÷|Ÿ¦£ÝÂɱãÇO™ ÓÀ¬¥©±.ÈËË‘ìñ½²ôÿŽTVV©(+jj¨Ý¾Aþ>²LYIQú—}7pÐB!„B!$ʱïþæáó¹„í:Ä1ê©OIê¹”·G—.i×¥MGk3¾ÄËþïÈå PŸ?çd½ÿ'#öÄ*Ï1ð$ô]ðã(’€¢¨‰jjÊ;7ÎŒzêó9ålÞÇ=ÿ6l?‘•/X€Á£×\½&"ObÎâ}ïÒú»Ø~ˆð»}a}Üsßu+'€ºšò½Ë›ߨ¦¥©—¯‡y¬ðSR”?ºÏ£(ùLzìñ¸ç¾ÝlÛ^¾ê{ä†ô/úž`˜ !„B!„ªQQqéâ?ü`¼{ßóÇWvê`ÁbQ&FºÛÖN»y~éÄK]]ùÁµ-ógÑ×Ó4h©µnåÒÝéúLšgÆ¿ôûß¼:XÈɱ´µÔ·­öC{󊊪€³Ë 'Ǫ5ÏÒ²òó—Ÿ€ßîß55ԀŢþX2¦S‹71IÏÂc˜d‹¼€ÿß‹¦Œû™”¿]ãsÇVÈËËmùë\EE•ô.úî`˜ !„B!„ªÑùËOóò‹•”¶®Ê7u‘œœgêå‹Ü»Ûµc^RåÜ«¤¦å2;uuZ¨«)ó~Š¢¨làã§LÉò|ý&‘Ë¥ [j[˜µdv²XT{+ˆ‰K!{N>ú”œÕµ³å(×Þ¼‡heÞòG'›Œ¬üŸ2j¼ÕÃL}Û8ÎÌ™3[´hÑ®]»»wïʺ8+!„B¨yyð$zt³65Ö'½à,Ú-õ5 +§P0qiYù“ÐwûÍ[²?èösHIË‘,OEy(þ\ÆåÒ¼) ‹JÀØèËTåŸFÀOÎ]Wijled:'„$ƒS€#ôm ò÷÷€øøøùóçÇÄÄȺD+!„B¨YIËÈ«¶Æç   4]-úó&&éÀáë'Nß/,*#]2~­²’#Yž6- Zjefܸûbp{²37¯øÞÃ×d%;²'5=vø\ØásAhΙYuÒ9H°ïO}ì=tmár_6ÈaúÄþNŽu´[¬Ù°vë¿ç©  `çü_'nœ:o×óúýhÿ!}ÁÒyùŋ绚 Ö°E IDATé’d$0Õ¥SëN,„æcÓ±•Äe@ÃLHöÂÃÃ-,,e]–oÏàÁƒgΜyòäI##£ýû÷ MÓô¯pƒ–°ñO_œJ‘¢²²²¥K—ž:uª¡$[\.÷àÁƒëÖ­KO¯Ö‹;???::úèÑ£m۶ݲe‹›››¬JˆB¡æÊ@_ ¤:”,"êÃïË|äÎ[1lƒ´²€ƒ{ôíÝéÁ“h·É›™³¦ ܰjóÒÈ@ºÙ¶õÿ{¡s3!ÙËÉ2ö‰INNÎÏϯ¤¤$!!ÁÅÅEh𦅴„úâTŠt>}úÁ!+’44MÏ™3gîܹLŒIWW×ÎήsçÎZZZdO||¼»»ûüùó+++eWR„B5C½zt€ÐçqYÙB&W’@à•g4Mpé*Ýìð¹øàIôÑ}7έõ^>nïö¹öܵ@Eùk§o'ÇŽðàItU•X£óª 3!ÙËÍÍ­=ItÞ¦…´„²:}év«®ÕÂ… «ªšíÒ³'Ožôóó#ÛLjˆÈÉÉyñâEdddnnnhhèÔ©SY,ܹs§¸¸X¦…E!„Psã>¼·’’BI)Û{óI¾ù•ŠŠK%È]^-ÔUxw––•‡¿|_ŸrÒ4½Ïÿš¾žæä±? üÙn×øy3wéÔš/™ÛðÞêjÊ ÓÿÚw©>‡CH( 3!«¬¬,**’u)𳦅´„MÿôëoôèÑðúõëƒʺ, ‚¦i2± :400°K—.Ì»,ËÁÁáÈ‘#¡¡¡ŽŽŽ×¯_×ÑÑ‘QIB!Ô<´ÔZ¹x48r}ê¼]qñ©4M§¦çîÚÉÂfzdôǺfØù‡VpùzØÓ°wÀ.¯¸Ñ­¯Yi®>JJÙyùÅ·î½â ‡ñÒÕiAÆÐ-_stÉ*ÒE‹¦é‰‹¼^¿ó¢že@ß9œ› ÉX^^ž¬‹ÐÌ5ý+Ü %lú§_sçνsçN^^ÞªU«ÆŒ£««+ëIY^^^tt4Ùþßÿþ''''4™½½ý³gϱ\!„úŽü±dtJZŽß±›ÇOÝ;~꞊²b»´µÔSÒr{ ‰6j„Ó–¿Î½‰Iê=p™±¡Nn~qyy¥£½µÏŸs,= q!)Šš;}ðÚ­ÿr÷VVVÔh¡Bú×ëj·05ÑsÞ{ÒXe%EX8{XFfþ–]çvsïEƒ–Z%%ìÏ%l((,ù¥_7‰Ë€öf’²òòòcÇŽ¹»»·jÕJEEEWW×ÞÞ~Íš5YYY¼É ¨ÿÔ4qÌÕ«WI‚öíÛ ¾kkkKQó'ý’’’ 6ØØØ(((PuèÐ! R999[¶léÙ³§žžž²²²¹¹¹»»û™3g¸\®Ðr’ümllÈKš¦oÜ¸áææfii©¤¤dhhèææöðáC¾O1WÀÐÐìùôéÅCYYYèá•””lÛ¶mðàÁíÚµSRR2110`Àž={JJJD|ª®§É³Š¡k™$£(êܹs‚G}…˜d¢‡\¹¹¹‘”‚mF8•"A(--=}úôÔ©Smlltuu•••-,,&NœøèÑ#¾”70‰¡•R§ë#>‹µbÅ ÈÏÏ_½zµ90òóówîÜéââbdd¤¨¨hllÜ¿ÿ={öˆî&ÙM@|¼ÃMLL$Χ9}ëëR!„ª99–ï_óƒÎ®™0êÇŽÖf,«»]»…³‡½ Ý7d@÷ºæ¦¤¤pïò¦YSš›êç|îhm¶gëo®ouîõC=Ë9Þ½¯ªŠ’©±^ u•¬ìÂ̬‚̬‚·±É·î½úÍÃgüÌí¤—EQ›½§<¾±múÄþ¶6–ÅÅe¦Æzî#z_ XutŸG=Ë€¾s”ˆ®t¨®®\¹²`Á‚¤¤$Á·tuu÷ìÙ3nÜ8N.((ÐÖÖ&oeggëéé ~äêիÆ kk똘¾wmmm###ÍÌÌ’’’’““ûõëǼûüùónݺÕ5%:tÈÓÓ³°PÈÌvŽŽŽ.\`ÚùJb``‘‘‘œœoå)ÂØØxãÆ“&Mìû ÁiâW14b-“dpöìYwwwÁ£ E®0›Í611!]~®_¿>hÐ ¡‰KKKõôôÊÊÊ222DJ³RêÔÊÊÊ|}}·lÙ’™™)4ñ’%KþüóO¡¿ÖÌ7 AB+…¬Ñ òôôܱc\»vÍÅÅ¥mÛ¶iii,ëÅ‹¶¶¶|‰½¼¼È¸3ooï5kÖÍðСCK—.-((|KOOo×®]&Lq²u½ ˆ¯¨¨HKK‹ü´:xðà¬Y³$Ȥ™}ëëyRŠK³7œèI¶;štšâ4S¶åA!„êïã§ÌÞ—™ëÞ»¼‘™ø‰Ãáff ¸óÇúðÊϲþ†€¤éò«À'q_þ¨<ßõš“šíÛ·/]º”yÙµk×:dgg‡††åææÎ›7¯oß¾õùS¼ ¼¼¼ââb—„„hÑ¢…¢¢bAAÁ?ðGÁÅI¹råÊÍ›¿,{Ù¶m[ƒ·oß>}ú´¸¸8$$ÄÙÙùÅ‹-Z´,INNNhhè°aò³³ U«V†††ñññÌßó—.]êææfffF^*))ýñÇðñãÇ€€ÐÐÐøý÷ß™ ååkoœqqq£G&Óýš››<ØÀÀ &&&<<üÇiii+W®xð ®/]ºtûöíd[YYÙÙÙÙÈÈ(--íÁƒ999'NŒ÷öö®)‡ºÞħ¡¡Ñ·oßàà`X¾|¹££#ÓsJLÍò[ß8-!„Bßÿ·Ò3óöïœÇ;¹¸œËØPgåâÑ>¯¥gæedåc˜ 5( 3IÇÙ³g™G‘ž={úúú2OA\.÷À^^^R)))™?~BBBûöí÷ìÙóóÏ?S•››+8 ¨Ö”'Nœ O,Û·oŸ1cY¶ RSS§M›vûöí÷ï߯X±ÂÇÇG°$ÇÙÙ¹¢¢ÂÙÙy×®]]»vš¦fΜÉf³«ªªvíÚE:_€ŠŠÊ† àÎ;$  ­­MöˆoÍš5äqý×_ý÷ß•””È~š¦/\¸°råJ???¾Çu‰OSVU u©e^â_áY³f‘0Ó… ŠŠŠ444Ó\¸plŒ7NtiůñK¨®®>räÈÝ»w÷êÕËÛÛûçŸf:ûäåå¹¹¹‘ÄêÕ«g̘AŽX×VÏö/> m­>þ Ó¦MÛµk×»wï=ztúôé±cÇŠŸƒŸŸcš:uêÎ;™.9¹¹¹ .$×pÍš5íÛ·3fŒÐLêz¨{{{6›ŸŸïàà°téÒE‹‰9 U³üÖ7Z‹E!„Ð7äed¨ª( ¾•œš“‘•¯¬¬Ø­KÛF/ú¾àÜLRP\\Ìô¡èÓ§ÏÝ»wyÿÒÎb±æÍ›—’’2xðà†8ú‰'¬¬¬>|Ø¿‹EQ”Ða¢S.\¸lŸ9sfÖ¬YÌ ˜˜˜’Áþþþ5-_QQñÛo¿Ý¾}›<^EQ&L˜3gyyöìYiœñWÌt¿6l`×ÉqGŽùîÝ»>}úð¦—ø4e[ÅP—Z–@‡È…b³ÙçÏŸLPYYyåÊPQQ!ƒ}D¨k¥ˆiíڵׯ_üøñ€x”éè誨¨@^^žÐ±Zµ’JûSC\·RPPؽ{7Ùãéé)þ4OyyyK–,!ÛÓ¦M;|ø0ïxC]]Ýþùgüøñäåï¿ÿ."熻 üðÃþþþ䊱Ùìõë×›ššN:544TôÐïfù­oÌ‹B¡oH{kðZ{4=³Ú28Ñï> µ†¦éUžc””dT:ô½À0“ìÛ·Œ a±X{÷î%O¼|„ö‘ Š¢Îž=«¯¯_Ÿ”û÷ï'²Ì;wàÀ‚ ÔÕÕ—-[l6»¦'ù+V8p@QQ‘oÿäÉ“ÉFZZ‡Ã©µœâ#cs ¢¢Bð]ÁACŸ¦l«êRË’a&»9~ü¸à»ÁÁÁäº >\]]]tVu­1ijj4HèǵµµGŒA¶ccc%È\*í_L q}H˜ ú÷ïïêê ©©©ÌpªZùøøTTT6mÚ$XŠ¢¶nÝJ¾ÚÙÙÙ~~~5eÕ 7ñãÇ?{öŒ‰õ°ÙìcÇŽ9::ÚÙÙùúú’±“‚šå·¾1[,B!„¾!ÿ›7ÂÑÞúed‚…ÍŒAîÞ³ÿ·wú‚ݽ,µéµ 6>ÕËÃ}åâQ².#jþ0Ì$Ìx¢É“'×uÆú7n\çÎë™200l0}ÙÙÙ‘°°°š}HnÕªÙàp85Íß,™=z OOOÑ+aŸ¦l«êRË’qww×ÒÒ€àààOŸ>ñ½Ë\·ZGÌAÝ+E*,--Ɇ`áÅ!•ö/¦†¸>¼KîØ±ƒtùÙ¾}û‡Äùø¥K—ÈÆo¿ýVӌѦ¦¦Ó§OçK/¨¡o]»vˆˆ¸pá‚““³3""bΜ9–––;wî Þ5Ëo}c¶X„B}C4Z¨Þ½¼Ñÿï…½{tx“t4àέ{¯äÿ7oDü˃›½§HüG_„ćs3Õ×çÏŸ™_âúé§Æ/é¼PŸ”ÅÅÅÏŸ?EEE999²-ˆy$®ëS¢–––‚‚Bee%dgg×éã"ìܹÓÙÙ¹¨¨èîÝ»–––3gΜ={vëÖ­…&–ø4e^ÅP—Z–ŒŠŠÊäÉ“÷ìÙÿüó™<›àr¹/^„ÿúÕšU*Ebeee111oÞ¼yóæMtt4SAÌ4áâkèöϧ¡¯¥¥åÒ¥K7lØP^^¾xñbRw ØÃˆ(**zùò%ÙæÝêÓ§ÏàÉ“'UUUâLÒÏâM€Åb¹ºººººFGG8pàĉ¤j233—,YxöìY###’¸Y~ë¹Å"„BèÛ¢ª¢4}bÿéû˺ èû…a¦úJOOgfiß¾}ã@ü€tM)™S¨¨¨èÕ«W­ùÇÄGQ”¢¢"yÂ=‹J]uéÒ%((hܸqÉÉɹ¹¹[·nݶmÛ AƒfÍš5tèP…j£Ž%>M™W1Ôc¬™øfÍšEÂL'NœX¹r%sÄŒŒ 9r$ï\B5©S¥ÔUUUÕÍ›79rùòeÒ¢øÝ)ZC·> z}//¯£G¦¤¤\ºtéÖ­[ €š–#•K´iÓFD¶mÛ~™-²²²2''§¦~OBÕtˆe&«âãààбcGyvêÔÉÇÇgË–-‡Ú±cGJJ |8Ù¹uëÖþù‡lK|šõ¯bhµ,ŽÑ£G“§ë³gÏ’åÀÞ½{—@ÞªÓ\M ªšL-×é 3ãæÈ°#f277—8¸Ã¨©RÄ)aLL ÙèÛ·o]+Îé˰ý3D\‰­_¿^[[6oÞ,¢ó׈#ÈÆþýûsss…¦ÉÌ̇³iÓ¦Z'„bÖ†SSScú[5Ëo}Sh±!„B …a&)X¸p!Yª¼¼ÜÃÃŒ6âS^^Î÷ Â̧KFñ¢izÕªUþþþ S^!.\¨ªª ™™™\.·ÑÍt@ÈÏÏÏÊʪÓgoß¾““#ô-Ò—ÚµkÇì”ø4%«bhµ\§+Ü¥K—=zÀùóç322È*`cÇŽ%ïÄQ×J§„ÌÆB'ŠŽŽ>~üxMåçô³ýKp}$¦««»~ýzÈÉÉñõõ­)Ùï¿ÿNN¿¸¸ØËËKðô9βeËJKK@[[{Μ9R)ž˜hšž7oÞüáààðèÑ£š’¥§§oذl1‚i±Íò[/Ã;6B!„B¢a˜I ,,,V®\I¶/^¼èêêš””Ä›àÑ£G¶¶¶C† )//gv2³Õž>}šÌÑK$&&Ž5jÓ¦Mõ™Õ¸® 6oÞL¶?Þ¯_¿ÄÄDÞ4M9;;óí¯?}}}æLׯ_/þй°°°¡C‡ZYYùúúò=æçç3ó(;991û%>MɪšF-×õ “M999‹-"¯â˜“ RÄ)¡­­-ÙX³f ›ÍföWUUíØ±£[·nQQQ5IœÓo´ö/Ùõ©Ù³gÛØØÀ©S§jJÃ{ú‡9rdQQoÁ†ÎòvîÜÉ;kx#øðáé[—àììéÇ^^^Lt£Ö“å#ú& ZllìðáÃy§âVTT433Ó××ÏÈÈHNNfbvrrr£Gæ;»æ÷­—z‹ý—fo8ñe8pG“NSœfʶ<¡EMÓ\%'ë‚ „P3tùUà“¸‡d{¾ë¹:/…„b±X?üðæM›Øl6—Ë}ôèïøeee///fâÐÐÐØ»wï¤I“H¤/99™™ÈÃÉÉéäÉ“æææººº¢——"Š¢vïÞÝ©S§åË—ççç———‡‡‡‡‡‡ó¦éÒ¥‹›››Ô=oÞ¼€€€èèh c&X¹w§¬#GŽ888lÚ´)---==·×áààpüøq¾Çu‰OS‚*†&SËuºÂêêê&L`fÝ7nœøkºIV)µ–pÀ€ÞÞÞk×®€ŒŒ f’ èÕ«—ŸŸŸ©©©ˆHâœ~ã´‰¯O}üøã£G&‚jBQÔßÿݾ}û•+W—””0³¿ÚÚÚÛ·oŸ>}º &>kkëÈÈHŸ7’`\EEEBBßÒxVVV‡êÓ§ßÇ›å·^†wl„úqiα÷tÔêÕYç'UyiþœE!ÄÃLRÃb±V¯^=sæÌÇ_¿~ýýû÷yyyZZZVVV¿üòËÌ™3y'&L˜`eeµ}ûö‡æææêëëÛØØÌœ9ÓÕÕ•¬U¤§§×ha&bÖ¬Y£G>vìXPPPTTTvv¶ŠŠŠ¡¡aÏž=ÝÝ݇ "­Uäyijj>yòd×®]?ŽŽŽ&}zõêÕªU+Ÿ"S&Ïœ9óÂ… ×®] ÍÈÈ (ªmÛ¶íÚµ5jÔÈ‘#k*­d§)ACÓ¨åº^áY³f1a¦:­1'q¥ÔZÂ5kÖ 2dË–-QQQIIIvvv&L9r$™…§E‹5Mò-þé7tû¯O£­?ÿüóÊ•+¼ÍQµ`Á‚qãÆùûû_½z5&&&??_GG§cÇŽC‡1c†–––Ô &>eeeOOϹsçÞºuëÒ¥K‘‘‘ééé¹¹¹êêêÆÆÆŽŽŽ®®®ƒ–“«ñÏÔÍò[/“;6B}‹( *¹å‘y÷ßä?n¯ÕÓV÷g5ùFŽBß4‡âÕ¹sgèÚµëË—/e]„’>4‡Ðw…ú`Ìÿ˜—r”¼µf®ºýÔ´eX*„jpÐB¨Ì‚ë'N”mIB!„ê‚j½;9tÕÛ‚'1…!VÝ»êöÓPÔ“UÁB¨ùÁ0B¨šªª*___PSS“Õ\<!„BÒEECµa\šSWÖFÃÎNw€–bKY• !„š 3!„ªÙ¶m[jj*L™2E¶Óñ „BI E±hš#¸ŸKsß>/|a©ak§;@GɨñˆBÍ †™B_Ð4}øðáÿû¿ÿ?þøCÖ%B!„’¾qs|h Š^%E´nac§;@OÙ´Ñ †BÍ †™úÞ½~ýÚÃÃÃÜÜüÅ‹ÑÑÑdçÁƒe[0„B!ifúý±øõÇâ(sõvº T,¼X!Ôì`˜ ¡ïݽ{÷î߿ϼTQQÙµk—››› ‹„B!$]ÅqWئ“>¿MúüÖTÍÚNw ‘ªeƒ !„š 3!ô½ãr¹:tøðჶ¶vß¾}ÿïÿþ¯cÇŽ².B!„4‰×›©š”’Ø”’X#Õ6Ýôš¨Z5D©B¨ùaɺ![¼xñÛ·oÙlvzzú©S§0Æ„B¡æ‡¢$|ðI/M¸š´ïâ§]É%ï¤[$ôÝšøÆÝ‹æ —UÙjPfB!„B5s,IÍ Ê-O»zT[ɰ«nÿ¶]) ";E)* y¤U—ýsn~ÁçšÞÚ·cnc–¡F&û¯B!„B50)÷<Ê/ϸ—vâEήºýÚiس(9éæÄ1rXO™÷Zª‰ˆ0B͆ÞB!„BÍ\ p+¬ÈNÿ÷Ô‡Mï žqiNC}£0Ì„¾[Ø› !„B¡¦¦¦iò. |4 \š¦h.p$.]mƒï%ÏÍ¥ ¹4€æ ÂÓ3GòA¸5•ÉùK1„Ÿ—®–€¦ @siDž2ozÞ  ¿\ î—|¸ W7Å•¹3N¿Ì½i«ó³µ–£<¥ÐpÇBu¢e1¶°¨äö…õý~´åÝ?t̺k·Â½—[ã5žÙé4hÙ“Ðw™qÿèëi·’p IDATþçÎþÃAïb“MMôúÿh»mÝ4U%¾Ì“²¶í>ÿ"2>úí'm-õAýìÖ­œhl¨s*ðḒ4‘Ñ)íadûÈ^©ãfôצ™sGðåýq×þKÏ_ÅJÎêÒ©µ“cG¯ÿ¹kj¨ñ%«kQÕTx&AVváþÃAA·Ÿ¿OH£(Ê®K›éûss®5g„0Ì$}Ÿ?3fÌäÉ“ÝÜÜä›À¨àf,//Ï××7;;{çβ. B!„D¨%DÀåÖ"ü ðIõ„Ð Ñ8DRC¬„/À!FT¨Z HXˆ„÷d]‰¨Ÿ+ gžϹ>Îr•’œª¬‹ƒ$”˜”¹`Ù³“—qñ©qñ©Q]ßJQ_ûÄù»¹øCŸKØ ¬¬˜šžëâvà•gÁW7««©´imTXT’“[¤  onªO>ÒB]EÄqišÞ¹÷âÊõÇ+*ªHžCÞ>yûïù‡'ý<{÷è qQ‰(|çZÑ4½nÛ©í2 ØìŠ;Áw‚#â?¤­^:Vìk‰¾S‘¾íÛ·…††<¸E‹².Ns¹råJ˜8q¢¬‹#ezzz¹¹¹ðìÙ3GGÇZÓs8œÙ³gŸ>}ÚÐÐðÀ?ÿüs׉R×Dß(üê! |®Ì/¬ÌŒtT ‘ðG"jŒ}Ô"šË­%D"x ‰C$ÂrÀ úΰ(9kM;Ýcú¦ ½¦´´ÜçÏ9£]¸\ÚÇïê†í§Ÿ„¾ ~åÒ§3Isìß»¿yø€ëÇõLìhmžž™·ûÀå—‘ ­Í:ÿÐjèÀߚµèïŽÖf|+ÍÕdŸçêÃàùû¯ g76Ôyý&q¾çþgá1ƒÜþïåƒÝíÚKPTA¢ E}HÌPSS^·rbÛVfEÅ¥›vžÙþ÷… ÛOÏš2а¥¶D—}/0Ì$eÛ·o///Œ154—ü188ØÓÓóîÝ»¢cöÍ^PP¿¿?ÄÇÇÏŸ??&&FÖ%B軀_=$÷EÏòk\‡!$ Å¢(ŠEQPÅ¢@äFõ—yå麪 Ç¢Xí4ìíôj(è6Ð!P£‘“c=¸¶¥»];òrÝÊ —¯‡¾~“xýÎ »)*.]ü‡?Œwï{Âw ‹E€‰‘î¶µÓ8®œœ$Ó–¬\w–-rÛºf*ÙÙµ³åÝËû-yý&qåúãgzÕµ¨‚Ä,üÎ3•”ÔÕ”ÉKm-õmk§]¿ýâMLRÀÙ‹ç»JpŽèûa&)óöö.))100˜7ožˆd………×®]»råÊëׯ322JKKÍÍÍÛ·o?vìØ#F¨ªÖø²²2??¿ØØØ¸¸8{{û_ýuРAŠŠŠ"ZŸÏ6²¸¸¸Ý»w9r¤¬¬¬M›6ñññ5¥\»vmß¾}ïß¿4dÈÆ,$B͉§§çŽ;ÄLœ­§§× åA¨yÃåÏ¿?!’B!ÌÅ"Åy _P°¾nðeÈäðßyÒ³„|¼Z>‚Ùòmðä\Ãq…~·üdƒ'‡ÚÂFE.H=ëàô‡Í™R©N^Pm4ììõi*êK=sT«ó—Ÿ231þ\7Ýó÷_%Îsù"w&pE9÷êôúMbjZ.sмüb%%…­k§’0 C²ɳ¨¸T]Myù"7Þý*ÊŠ«—Ž5uËùËOó >kk©×©¨B$Náuuø;LPõ£“Í›˜¤Ÿ¤ÿ=BÍ †™¤)++ëðáðbÅŠšBEûöí[¿~}^^ïþ¸¸¸¸¸¸Ë—/ÿ?{wsþ?ü5Ý÷M•ˆ¤H’$ùZG% ‹µ¹Ïu,9²,9*Ö"WëZGIŽÜä.Å9JQIºï¦Ò53¿?Þ~Ÿ™¦¹jÂëùØÇc?ó™÷çýyÍû]£yÍû02Ú³g§§'Ç…L&óСC7nÌËËc?_VVöúõëcÇŽuéÒ%00ûB1¯mM·nݺvíÚýû÷“’’¼ÄÅÅeÈ!ÑÑÑþþþßyšiäÈ‘³fÍ:uꔡ¡aHHˆ´Ã‘>‡gÏž™šš~øðAÚ±á+ ûÖlà¯Á×6ü¶é Ìï ßÔ†€)^©Þ9Þ)’ÿ¤6øf4šM‘°]ØJ)$¾ø½£™«÷´×ûQ[Ñ@Ò5#AÑh4δ"çzŽä ´o§ …Åäი×ЯO·FûÖíÑ“7àØ×RG›3¿3r¸=°X¬Ø§)£†÷*TnÂ_ó¹îùËŒ—o2_½ÉºŸr‹¹}Ï0Í$I'Nœhll”——÷ööæY ´´tìØ±>¤Î¨©©™˜˜¨©©}úô)77rss½¼¼V¬X(#óå-’ÅbÍ›7ïðáÃÔ…ººº¦¦¦?~,//€÷ïß{yy-X° ((H^þßí-Ŷ•­\¹RðeöìÙÑÑѱ±±)))Ý»óXï;!++{øðáC‡}mŸ^ZJqñWùO ÔÃ666vvvæ_¦M ~liÍöþê!´W2í­;¬Éa#œ S$22ͤH¨ ù ¨Á úFÐ$ù“L3UëÑ·ÝºŠÆ’«‰bœ[ÿˆã¾-}yy9`±¾¬1—›_]»p®”$R§¹”¥Š²¢A{íü²ܼRîgù‡ÚÔ þÍÛþº~2ì^Ee5êÊÉÉ@C£ÙkÑwÓLÃb±ÈP¦#Fhiiq¨¬¬8p`rr2y8lذ•+W4ˆJ뤤¤ìÝ»÷àÁƒL&óáÇuuuÊÊ_6#8uê•'rww߸qc¯^½ÈC&“ùÏ?ÿ„„„œ8q‚ÉdÞ¹s‡N§ëèü»¥8×¶2{{{ªéŠŠŠ¨¶âoôèÑ***555¡¡¡da¬ï~Х巿:RÛÑÑñìÙ³Ò¡M°GðW ÅP¥³¡JgiGÐ÷ERi¦ŽªÝû¶û±’‰DjC_#&“’þ§¿é¼P÷â“<œ€Áï;ruñªƒà6ÂaÆÏÜ­t´Õ7žöÛzFüÐ7ÓL—’’'Nä~–ÅbÍž=›äMh4ZHHÈœ9s8~½»wï¾ÿþÉ“'ûøøDEEQ9&‹µuëVrÖ¿¯¥h³$øÈ¨',køàÞ˜cB¢Á4“ÄÄÆÆ@Ÿ>}ÔÕ9—mc±XäxذaóæÍã_GŠ}ʆ±±p3ÀŹö+2hÐ r@zAX555aaaÓ¦M³±±ÑÕÕURR255ýùçŸ=zÔÔ%¶¶¶4ÍÆÆ†|øž={ª«9ÿ=kö.ÔÔËêêêÍ›7ÛØØÈËËÓh4ö!iDYYÙÎ;lhh¨  `dd4lذ={öð$R^^NûM­ŒsåÊRÀÒÒ’ûBƒ/3Û³²²hl”””¸«*.. ìß¿¿žžž’’’‰‰‰——Wxx8“ÙüŸéAÑ¡a%ËÃÄ7fÌžÂÂÂH333ž?cuuuÇ÷òò233SVVÖÕÕµ··ß°aCaaaS7¶³Èk=ÈꪪAƒµoß^EE¥K—.3gÎŒ‰‰á¸JØiöWDí/I½Õ „-ÍÔ^ÙtTÇùcL©X4_µ=†ú:—Â~Òoë²¶h¼Ü(*ÊW×Ô®8Å1‘­’^Cèk@^A)™§ÖLc¨©*UÒk¶ïd?_W×°qÛ3²÷îo-|m]=¨«)³?[ó¹îYâ;ñ@ßœ4'µµµ‰‰‰Ð»woîgãããÉñºuë„Çk``@£ÑÈ»ÀÇ»uëÖ:×6%>>žcÇ:þTTT†.þ}ùÐÑÑ155ÍÊÊ6ÍôùóçƒügcÎ?ž:uêÔ©SË—/ÿóÏ?›ê²¢¢"ÈÎΞ9sæíÛ·©ó‘‘‘‘‘‘»víZºt)ÏkY,ÖæÍ›7oÞ\__OLJJJJJ =pà€i&þnܸ1cÆ ö¾ËÍÍÍÍͽ}ûöÖ­[·lÙ2uêԦƻq#™”ììì¡C‡¦¥¥Qç9~Ž9²bÅ ²Ò<‘—————wçÎM›6M™2E¬W%¶#GŽøøøTTüû}Nvvvvvöùóç/\¸@%8´~r„-õ†Ý»wotttUUÕåË—¯^½Ê±Õc]]ÝêÕ«ÉñîÝ»UUU9.ŠŠúõ×_?~üH©­­---MHHÞ³gϤI“8~õDî,²ÁÂõë×çÍ›Ç~Çôôôôôô¿þúkΜ9ûöí““k©Åì/qÞjBÂNšÓSê`¯÷£©ZеŽCí=ysìôÿ9ÛŒrµ/+¯Ú¾÷Âî—»v1N{Ÿ#ZúíµÖ,›°>àÔ£×k>×ý¾|‚Eg£ÜüÒsûm=sÿJ@/ëNÐÃÒ„F£•”Ò¿1wڈϵõµµõÜÉ:Úê›×N]ê{xËŽpƒùëœÑ†ú:¯’?üºâÀó—ª*Jëyï1ÕÁ÷ìa—¯?}šâäн¶®þñ“äE+¾}÷‰»B55eÈÎ)æs}o0Í$‰‰‰ä£¦÷³wîÜ!;wnv 'nƒ ºÿ>¬ZµÊÑÑ‘úf»E¯mJ@@À¥K—/ß:[³ÛÙÙeeeÅÅÅ1 s%UUUVVVÙÙÙä¡ŽŽŽ½½½¾¾~fffbbbMM ìØ±ÃÜÜ|Á‚qâD2sYAA¡ÿþ999Ožœ¿lÿš'ªªk—Ìsûs㌦ê\<×­¶¶~ÿ©À ˆÀ %%…ÚÚzèh¬÷÷¡å–DŽVØàÇqÜñæíÇ®+ tJÊèuu ŽöÝ‚ÿœ÷늵ÙژߌNܹïbc#cwàžgÐ÷ÓL’ñôéSrÀ3ÍtïÞ=ràââ"Ú–ÁÁÁöööµµµeee+V¬X²d‰®®@‹À‰síWÄÎÎîÂ… •••©©©VVV‚\¢¦¦6nܸݻw;99­_¿~È!T~ª´´ÔÓÓ“¤çÖ­[7sæLEEEî †‹‹K}}½‹‹KPPÈÃb±NŸ>=kÖ¬ÚÚÚÆÆÆ   ;vp\xðàA*CÑ»wïððð.]º‡ÕÕÕþþþÛ¶mkhh¥!š°aÃ’c;vì™3g¨—Ãb±.\¸°f͚Ç žc"q.\¸0==ÝÒÒrÏž=C† ¡Ñh%%%Ôd¢Ã‡S­§M›¶sçNmmmò°¤¤dñâÅäÓû† ,--y.œ/eeåÍ›7À;wHýÚÚÚä ·“'O’´…††ÆöíÛgΜ)#óå{ΜœœéÓ§ß¾}ûÝ»w¾¾¾ÁÁÁ×J¶… [* Û”… žuÒh´UK½† îr)áÅûŸŠœºpì¾fÙ-MÎQá-¼¢¢üÝËþk·œ¼XT\aÕ­ãô)CçÏ™’–Í]Ûò… /ÞÇÆ§äæ—6u}ohÙ­ZµjÛ¶mPQQÁ=SÆÒÒ255‚‚‚–,Y"Ú-NŸ>=cÆŒºº:òPIIiâĉóçÏwpphö_Mq®•j§¹Î;¿ÿ¾ÙògΜ™~ü˜}Åz¢´´ÔÌÌŒ$¶¦OŸÊQ?‹ÅúùçŸÉìvíÚeff²Oª*//§>Šééñø'ùÊ•+nnnЭ[··oßr<{çÎaÆAÓƒé***ÌÌÌÈ$¦7n¸ººr¨ªª²°°ÈÏÏWRRúôé{f¶åz°Ù°ÅlX>|||H’B__ßÞÞ¾©b~~~}úôa?“˜˜Ø·o_&“©¨¨˜œœLvX¾|ùÎ;`ãÆëÖ­c/O§ÓÍÍÍÉ0œÞ¼y“} QYYÉþF*NgQ?®úúúG%Y$vµµµ}ûö%[% 8c£f{„ã.¿zâ÷—8o5ˆ?zMÑæ“ýɱ•±µ·ó,éÆƒjiQƒskšü“RC^¯ž«…f®]‹BBºü<2&íË_Ñ ="ðmT2ÈJÛ222<çkPóÄC4yòä'OžPßù×ÖÖ?~ÜÑÑÑÎÎîàÁƒd†WK\ûµ` øUššš#FŒà™aÑÖÖ¦6&YBž|}}8À½§Ø/¿üBrssÿÝBõðáÃ$C!++Ì¡žçEFæÚûBBѲ4íܹsÜ9&&­•••ýýý¹ë§Ñh[·n%íVTTtøðaGHHI[ÌŸ?Ÿ;mjjj+W®€ÚÚZöÕp@J=H´BÃ\mõƒD±³³#Ù󺺺eË–@VVRÔ¥Kö™qÄþýûÉ[¢ŒŒÌ¾}û¸sLÀµzº8EÙ½{7wŽ ”””¨ìÿ£G$›©‘`‰ðVƒBˆ]S”Ôäµü4ÑÜ·«f_Ì1!„øðT2Ȧ×ZZZ©‡çì6ê×ê‡~¤rq:K@ªªª;v$“s“““…½¼)­Ó_M½Õ „âÀ>šIYN½·îP+­²4ü4„B†o¬’AòGMÍ‘ÑÓÓ#i&jöœø¬­­ƒƒƒ9²cÇŽOŸ>@LLÌàÁƒ“’’x®W-‘kÛ,ªñEÈå566Þ¼yóèÑ£—/_æ¹l³«qÓh4r!û h%%%Tm]»v¶Z‘õêÕëÚµk“&MÊÎÎ.))Ùºuë¶mÛFŒ1{öìÑ£G‹¶«]SSíH–èܹ3Ÿ¨e³Š‹‹›î!qyyy¤Sêë뜜š-O–X"¤ÕƒÐ¶ÖÍÍÍÓÓóüùóyyy ¢¢²k×.îbTË€¥¥¥ 5‹ÓY‚322"i&ò^-­Ó_M½Õ „âB%YU[Ý!=´œåd8§!#„’L3I™±EÖààfbbòîÝ;xñâ…d﫦¦¶téÒY³f­\¹2$$RSSÙÈ\äkcccsssREEeäÈ‘‚— 5–š='&“¹wïÞÀÀ@êa×®]ííímll¬­­ÜÆû !„¾7J²ª}Û´Ñ$/óU~¥ŠB_ L3I†ŽŽ°­ÁÄÁÅÅ%::?~,Ô–^"3V È &ááႤ™D¾vÛ¶mB-øÂ‡&I¡Ÿô… X,ÖÔ©SÉOJJJ3gΜ6mZŸ>}¨âÞ¿L|ìësµržBEEeݺu¾¾¾W¯^ ºÿ>¤§§{zz®Zµ*00P"waŸ=š——ÇspêYêX¨ü ˜¨åääèt:÷úA|H±ÛrÃ>þ|Ïž=ÔË/ÆÄÄ 0€£ûÚÞ¹¹¹íÛ·o¶fq:Kp™™™ä€ç¶†¢iËý…Bß¡ÁFSšZ!„áà’ARt:Édr?K-A’‘‘ÓÐh´éÓ§“ã´´4¡¾çÚ¶ƒ8 øX†#GŽ“®®îÝ»wƒƒƒííí%žä@­!ÒÚ}\NNn̘1÷îÝKHH ëéÀÖ­[ÿþûo‰ÔÏ>#==OI2M dddšúxߨØ(‘¨ØQ666 ;ÆPŠ=(Ù†• ƒ1gÎ&“©  °eË`±X³fͪ««ã(©¯¯O§¥¥ R¹8% ƒA¥™Œ%Um›í/„ú>aŽ !„Z¦™$ƒ¤™X,ÏMNNNVVVäØßß¿…–Ï >56665®J"×^¼x‘%ŒVÊ"¥™Èš»пÿ ‹‹ššµJËË—/[ç¦M±³³»páµ!:™;)>---kkkrǧ$õlÿþýÙwj×ÐРVA.**'ž¿nìÆÆÆ Uaëô`³a‹Ö°-dÿþýdeîß~ûÍ××—$Öß¾}»yófŽ’:::ÔÞ|æÜÅé,%$$PéužeDxßn³ý…B!„PËÁ4“dP‹Œðœf%##³bÅ r|ýúõ£Gò¯­°°}ñ#ƒáïïϾ¦ OÔþMªªªÔ÷áâ\ûuIII!&&&^BuV+ïFí9uàÀîá”ÖYÍWFFfáÂ…ä˜Ð!¾1cƃ¦öþ+((8tè9vss㈊Ú0‹ç6,ëâÅ‹| æN6µb5ŒkÛ¶m®þÓr=ØlØb6lKÈÉÉùý÷ß }ûökÖ¬¡Ñh{öì‘••€ÀÀ@îLܨQ£ô|›å IDATÈÁÁƒ³²²¹…8%ˆM›6‘ƒN:q,LÞlð×û !„B¡…i&Éptt$ÔöÕ¦NJM›3g™«ÅSrr²““Ó°aÃÈg‹µ`Á‚ßÿÝÁÁáÑ£GM]•——G 3fŒŒŒŒ˜×~uH˘™™ x 5î‰}aÊëׯOœ8!¡èþcÚ´iÔ}<È]€Åbùúú6›ÊíÛ·›Úè¿faa!©Û-Z´ˆ¬©L§ÓW¯^Í=™”Á`¬\¹²¦¦´µµçÍ›ÇQ€Z™û—…Åb­]»644”OÔ½²²²ÂÂBî‹/&,]º”çtצ´\6¶ø +q‹/&)˜Í›7“¥—zôè±xñbhllœ5kƒÁà(Ov6¬««[ºt)dzD]]{JœÎ¢$%%ñLüݽ{÷Ê•+äxùòåÓf›íþÚ`!„B!Ô¢¾Ê„Bdmm­¦¦M§™deeO:E>±0Œ)S¦Œ7îñãÇìŸ:RSSW¬Xakk›žžžœœLR?ááážžîâââæævñâEö»ëëë;æììüéÓ'PTT¤ÖðçÚ¯ ‹Å"-ß¿ÁW²µµ%6l¨­­¥Î766îØ±£OŸ>¯^½’x¨0hÐ jbβeËöïßÏþI;33ÓÍÍMR«qOŸ>=zt×®]<Èñ©¾¬¬Ì××—Sƒtħ¯¯@Ž92nÜ8j+@rSwww*‹·sçNöÅ’‰qãÆ‘ƒ°°0ö€>|?~¼¿¿?û*?ÜÚµkGØ´iw~=Â'N :”cv'‹Åºvíš‹‹ ÷¬Ï–ëA¡Â­a%+**ŠìгgÏ3fPçýüüH¢ðÙ³g»wïf¿ÄÔÔtÍš5äøâÅ‹K\=zôÈÖÖvÔ¨QÔH1q:‹²y󿲝îÄd2Ïž=K 8²µµ5kÇUÍöm­¿B!„ji´Ö™˜ó=:thttt¯^½ø,RûñãÇ‘#G¾yó†:£¥¥ebb¢¨¨˜““Ã>QÎÝÝ=,,Œì©”ššêîîξ\®‚‚BÇŽÛµk—ŸŸŸM}Ä•••=}úô„ ¨’â\ÛÊ–,YÂ>ÿ(==ýÎ; ®®>yòdê¼²²ò®]»8®ÍÉÉ!ŸiÿüóOïxëÖ-WWWrl``àîîÞ®]»œœœëׯÈËËÿòË/dĘ̀Q£¨ñ„­­mRRœ;wÎËË‹gýjjjÕÕÕðüùs*¥Edddôë×^¤®®Þ·o_SSÓ÷ïß“íõôôLMMàÉ“'Ôp9þšŠÊÛÛ›ú(khh8bÄsss99¹ôôôˆˆ2šÉÒÒòéÓ§êêê"ß…‹ÅZ´hѾ}ûÈCUUÕ~øA__?//ïÞ½{dø¬^½šúή²²ÒÄĤ¢¢‚<ìØ±c·nÝJJJ^¾|É`0 ïß¿occS__ß­[7ž“U¨t†ƒƒƒƒƒCnnn\\Ü«W¯¨ÅÔ–.]Jí¦¨¨Ø³gO[[[MMÍ´´´W¯^‘Y„?ýôÓ™3g8*o¡0lq¶)>>>;vìCCCþ…§NêééYUUeeeEf5Þ¹sgÈ!ìe.^¼8vìXPQQyõꕹ¹9õ“ÉœùeU>+ckogÎ$#B!„Äåç‘1iÉñB9éFó-qvvŽŽŽ~ùòe~~>ûCìLLLbcc‚‚‚Èð™òòrŽ%·µ´´üýýçÌ™C7€nݺ%%%oÙ²…®¯¯OOOçØº¨k×®GŽ8p ûIq®me¡¡¡ä“:Î>/ISS“;ÍtóæMr Ôxœáǯ_¿ÞÏÏòóó©åQÀÉÉéðáÃ:tà?3Kdæææ>;vljj*Ðéô»wïRϺ¸¸=z444”$)ÄwôèQÿÜÜܼ¼<îÕÁNœ8!HŽIp4mïÞ½–––kÖ¬¡ÓéÕÕÕQQQì´µµ·oßÎ>†††Æ¾}û¦NJRáÙÙÙÔ"MÎÎΧN211ÑÕÕå9á‘X°`ÁéÓ§_¿~ OŸ>¥ »{÷.ù¸N£ÑvïÞmmm½jÕª²²²ºººgÏž={öŒ½’^½zyzzrWÞr=(HØâ4l³òòò.]ºÄ¿ Éš­_¿žtŠ››GŽ <<<ÆŒséÒ¥ššš¹sçÞºu‹i(##súôé=zøûû×ÖÖ2™ÌG±OìURRZ½zõìÙ³©3âtqüøñèèè£Gr¿öíÛ7,,¬S§NEFFz{{ÛÚÚêëëËÉÉiiiYYY͘1ãòåËÉÉÉ<óDâ\ûµ Ã":wîÜì( 6lxúôé¸qã,,,MLL<<<Î;÷èÑ#+++ Éf^ØuïÞýåË—‡>|¸¼¼|‡ÆŽ{éÒ¥û÷ï››› ¾–y³È:ßgΜùùçŸ-,,ÔÕÕ544ììì&NœGíÿ%A4í×_ÍÌÌܺuëÀÛµk'''×¾}ûÿýïÛ·oÏÈÈàÿÑzÊ”)ñññ&L ícddäêêzîܹ{÷î‘Æá¿\½¦¦fLLŒŸŸß°aà UUU»wï>sæLŽÕ»fÏž™™¹{÷nWWW###yyy ®]»z{{GEE=þ¼©TB õ  a‹Ù°ñüùó   ““ûóÏ?y–Ù»w¯ªª*ܹsçØ±cìOÉÈȬ[·.##cóæÍ hß¾½œœœžžž““Ó¦M›233ׯ_Ïñ6bthiiýõ×_?þé§Ÿ ÉO”»»ûÙ³gãââšÊ1À?H|´…þB!„B¨uà¤9Irvvމ‰qvvæ³Þ6’¸¢¢"CCC²§µÌBÛ¤³ .xxxH;Ô†à¤9„B!‰à˜4‡£™$iæÌ™ðøñc²¢6jçÏŸg0222ÞÞÞÒŽ!ÔF566J;„B!„¾}˜f’¤ñãÇ“9VÔj¯¨¥1™LÒÚ£F222’v8!„B!„Ð÷ ÓL’¤¦¦¶|ùrسgOAA´Ãù.„‡‡“¥yÿøãiÇ‚B!„B}×0Í$aË—/××ׯ©©j+q$ƒ±aØGC]%áÅ{ù¶¾:ÍWpAaùɰ{ù…e‡ŽÝv,H ˜fBß52ØÇËËKÚ±´!QQQ¿üò‹•••¦¦¦––VŸ>}ÆöìYƒ!rµëׯ¯®®Ö××_°`uROO&¼Ÿþ™½fªQ\\ÌóZ~Z¨¡ZBZZÚÂ… UTTh4Z—.]ø”ôóó€{÷î]»v­µ¢C!„Z•Ž¢á0ãéM&›26a²Id¿®8@ÓvcÿO½ÃxK‡yn?m¼t-žÁ`ŠP'½ê3MÛÍvàb‰G+)¯’?\½õ .^›ûö8ýÓ9·ÒŠŸ60Ÿ^Öo¯5ÆÈN¦úKæ¹·~`Hm7g‰’Š»wï.Y²äõë×ì'#""Ö¯_¿wïÞáÇ [maaá_ý¾¾¾*** WzZ¨¡$ëÖ­[×®]»ÿ~RR’€—¸¸¸ 2$::ÚßßÔ¨Q-B!$E$ÙTZ——P|#“þ’E-άUz?¥<ÖJËÉVgˆ²Áš’’‚®¶:0™¬²ŠªÔw9©ïr®Ü|Ö»§ù­ÈMzºÂ­¹^V^Õ2aJLJê'0íØÞýÇ~ ¬¤ 툚ÑæßËûwÌoµHø0Í„ú‚ÅbmÚ´iÆ d¶”²²ò!CÌÍÍ«««ß¼yiii£G¾}ûö Aƒ„ªüĉòòòÞÞÞìçÇŽK§s~[XXXxïÞ= Ñh&Là®ÍÑÑ‘ç]ŒùG¢  î¿£-ÚP’µråJÁL”Ù³gGGGÇÆÆ¦¤¤tïÞ½%C!„Ú’l*©ËM(¾™I lɦ—¥÷“1Ù$’QÃí#Žû’c‹UXTq6ò᪠Ǟ¿ÌømÍ‘“…Ûl¤í§™JËé «óÕü´Á€Û~/#Áaš !ô¯ÒÒR‹%++»jÕ*___555ê©Gyyy644Ì;7%%…F£ñ©Š‹Å"C™FŒ¡¥¥ÅþÔáǹËß¿Ÿ¤™Ξ=+xüŽŽŽB•Y 5”ÄÙÛÛS ^TT”œœ,ÈU£GVQQ©©© %Ëi!„Bß6]E£á˜lj4M¿½Ö’yîÊJ sÛwîÒãƒA U”¯ákI@HñO>Ñ´©€¿–^F‚Àµ™B_Ðh´;w®^½:66vË–-ì©8pàÑ£GÉqjjªP;‘ÅÅÅ¥¤¤Àĉ%°´´\CIÜ‘#Gîÿ?²è’ TUUÝÜÜàøñãõõõ- B!Ô†d“W§Ô{ûšMÌú—¥÷OglzRxé3®Ù$ªCû@]]çœÿ,”™ðâ½÷ü]]íçêšO>n]ðá+Læ—4ßÙȇ4m·Ánk éu&µÞµã˜–éO4m·;÷_pÜkôÄ4m· §ÙO:XIÓv+.©ü\[¿jÃ1#Koš¶Ûßá÷¨§ ‹*X,VèÉÛöƒS5òêÖwÞ¯+Ô|®ãó¢þyþަí6Ù~òBHx¿®8Àÿv”¤×™ÓÙ8ýªÑqÂÀWùú¯¨¬æ¸[c#ãÏ=‘ÝúÎS6ôìî0?øð2²¾¡¡‘œWï0¾ÿ0ŸÓD X´ö¼Ñ>|,\°<¤ßÐåªF^¬¦ÍZ¼'7¿èeê^A!—8ê¤E‰ G3!„þ%##ÐÔ³®®®d ¼{÷®OŸ>VŠŠŠîîßȺ}-ÔPmÇĉÊ‹‹çÅ«ŒG×·65ðGUU©Ÿ}·‚² U”mz˜€™‰~³·c±X;÷]\³éD}}#())<ŽK~—|æüÃS‡}ôã\µàÃÇ‚™‹v_¹ùŒ<|ûîÓ¢•ëêæÍøqâômd=oˆû'5îŸÔêêÚÙÞ®¢,,íðñ›Ë~?RU]K^lN^IèÉÛ‘QOî_ ­—…m@ÁCEâÃÑL‰®¸¸800°ÿþzzzJJJ&&&^^^áááL&ç&Ç'Û™s?ËîÇ$%CCCE¾] ‘••ÕÐø²d£ººZÅÆÆ@Ÿ>}„ºêë%rCµÔ’R¤ïB¡ï®¢Ñpã^VtRïÉ5²éÞ—‘M œæ#„3 };Ívz_þLº|ýéRßÊ rÇö/­ÌÏK=‘öÏÁ>¶]._?xôŒvíû>ñPÀÞ`Õ­ãûÄCä?Ow'‘ÃX½áøýǯ6¯ú.áÐÓè–¨§FNØpåÆÓà?ç¾û;?õäZŸ‰Ÿrÿñ«¦jëÞµcÜíí«–z@÷nãno»½ÝgÑØfo·?ôšÏº¿êë}ýøúhÕ§s‰v÷ïk™•]8Âówé¹7r›´ñaì›½Ûææ¤OŽßOÒ([v„³6&>yÿŽù¹o¿Š vèÓ•œolä½ëq³ KF;~&zÎÒàªêZQޝbƒ«s">%[±xœ]¯ÎVÝ:ŠÖËÂ6 €¡"‰ÀÑL‰èÈ‘#>>>Ô™ììììììóçÏ;::^¸pÁÀÀ€zjìØ±óæÍ«­­ÍÍÍïß¿?Ï:ËÊÊîܹ ãÆùv-$'''??Ÿ÷èÑCÀ«jkkÉı޽{·TdmŒ° Ÿ——'xý***-½‡ŽŽŽ©©iVV¦™j9åõU åÍ#»­«Ékk*´°æZFuI]îÿ_ÞD­ÿO^F¡’‰€5³€•_“Á]k_ÓÚ+™ÈÐd¬¼´.¯É>yG¥Ô) ]%Y5î<Õ4VT7V4U'%Yuy]kndÖW4ñz†Çd@F[Qˆ¬Ëêò©½ÏhÍE®¡ 'KôûêÆŠÿ6õ¿¸o¤$«ª(+è±õÌÚZ™Þ])KSPx@“Ŭi¬à[ä?wQ“×jª·ÏtðüÒŽ¦,«æ¬ïÕCË9©ô^võ[î‘M=´ôÒ¢,ðOãwˆÉdee8zýÏ=‘àûÛx2r¤æsÝ’Õ‡ tï’ c¿lábÑÙ(ⸯEŸ9»"æÏ©  ù«—¯ÇÞ½hÖ/<þ”’••yp5°¯y¸qÍ”Ë×ã_¾ùpýNÂà=%x»òŠê5OÀÊ%ž[7L#'{÷4¾¼Åqèò—o>¬ÙtâܱÕì—Ðh´WlmÌÀÈ@çÈÞÅÝæ—•W}üTôèúVëî¦`¨¯s(èWÛ‹³² “S³{ö0-f¡4Ûh•ôše¿‡Àd¯A'.—‘¡€±¡î6¿é SVV”/"4  ¡"IÁ4B¢X³f 5gªK—.úúúÉÉɱ±±t:=..ÎÅÅ%!!É¢¡¡1f̘°°0ˆˆˆh*Íté񴮮F9r¤¶¶¶È·k L&séÒ¥äØÕÕÕÔÔTÀ Éú>vvv-\["BC\ºÄ9ÕœSSÓ>ˆžàììì²²²âââ †¬¬ ŸB‚{]öøMÙ# Ûè rj/è·ÍŸ3o|:"`amEƒ 8ÿo “Ÿüq¯€…`j?9M ?.8—W“!`áÿNî¦é `á·åñÏŠ¯ X¸‹FŸ!FS,\Z—w!k—€…•dÕ¼-6 X.fÕ3k,ìi棧ԡùrS™ItRÇöî½t~°pzåó‡ùa6Ví:ºã W7–Nß$`a˜c¹«ÙÜåâÇÝ•õÅÍ—ãÒȬO*½÷“M\®Þú§ƒÕ4`2YÅ¥• äü¼é?.œ5ЇE>ÊÊ.ìÝÓ|¼ÇökÍLÚÿÏÙæÎýYùìC$¥¯ÅÌ©¼XµÄ‹ÊAFsq²~ùæCNn‰dowþrl%½FMUiÕOöóÊJ ëVü4~Zàù˱eåUÚZÿþD­\ìIrL„¥EýöZ…å¿ûL$9&¢—u'M ÕŠÊꜼ’ÖI35Ûhç/Ç––Ñå·úM#9&Šh9&© I NšCHh'Ož$I C‡¥¦¦ž:ujçÎ7nÜHII! Ù¼{÷Î××—ýª)S¦ƒóçÏ“åú¸‘5Œ`òäÉbÞN²’’’&MšDÂÓÑÑ |óÓ§OÉÁ÷f§¡ÚÒ_•••©©©ÒŽ!‚ ÃiÔà©<ƒÐ¢ÚJs´±£¾mƒ 'µÿï@’l:ýÞ/®ðrÛù‘®ÚÚúœ¼’œ¼’¼‚R’còåx/Ê?dçyù/ƾ€\zqÿôš›@z¦c½7qìÀ¦~_8’ о&óI'ôí=yŽ}-u´9¿$9ÜX,VìÓ”fbÓÓâsQó£e%¢ÙF{óúõéÖÁHOR7¡ I ŽfBH8‹/&Çááá®®ÿY]ÏØØ822ÒÂÂ"???44ÔÏÏOW÷ËÀ{WWWÒÒÒ¬¬¬„„{{{îšoݺjjj£Góvâ;qâDJJJnnnjjj||<9Ù½{÷‹/víÚUðz¨é`æææüKŠïñãÇTÓqóóók‰Õ¸Åo¨‹/J<*ñuîÜ™äååYYYI7„B_‰¶’di¹¬[&=‰š”Êv;™Nê=-µÛHTê<Ý"Žû@c#ÃÚiaê»C}ÿ9Û°—ÉÉ+€Áv_àYIAa‹$J„AC’bM}C,òíróKàÿ³iT” Úkç–åæ•ò¯¹©… _b:TIáh4òb»v1’à-$Ҁܡ"IÁ4B )//€ùóçs$}55µ•+W.[¶¬¶¶ööíÛ?ýô9¯  0qâĈˆˆàN3]¾|¹¡¡Æ§¬¬,æíÄçïïÏ>ŒE^^þÀÞÞÞÂΟ*))™VX »  àêÕ«M=û믿¶ÄM%ÕPm 5m“ô BHâLT»+Êrm£Ãëo]° U„ÈÔk*´ë­;´éúþsZEVˆ7gé¥óÏZyÞHNFQðÊÍÕ{ë)uüo¥MÞHKQˆ}‘Ú)›ôÐÈv5߯T*rjݵx.RËãFò´XhÚ3˜l5ò ^QFÐå“ÀX¥‹¼ŒBSÏrÜH[Aˆõ¤4ÚuÑàþF‡w?ê* ^³œŒbgu[~5ò9ÝœŽª–5Š•MÔH-ÆÔPQ_XÕPö±*™½ dºhô¶ÓsÕRh/ÚÝ¿mrr²x›êèø%óÜ»YSO‘ßï^ÖØç|±³±2k•¥€ZƒŒ~úfrL& $=âò»jÀ¯¦™Ndd$9`Ÿ×ÆšöôéSö¼Ï”)SHšéüùóﶽ̭Í6 "p p„„——G†_Ö××;99õm‚»û—oz?þÏ;2Fc_œý©+W®ÔÕÕÀĉåää$r;1)++›››0ÀËËëØ±c999‹-€’’? XOUU¨¨1˜ÿë"©†jk¨.#=ˆB}?ªÊæ‡ŸÉØœRËžc¢Œ…†ýóÕ?ýŒ9&Á¹8Yví >ëþ¢¦2yºPSUJÏÌÛµ¿™ýv ôµ ¯ ”L¿bg¨¯1qÿYìÙoë²ì\7¶ IDATt›å5f€šªR%½fûÞHöóuu ·€1#ûéê´ørÜZ¢=½Ü(*ÊW×Ô®8Å1‘­’^Cóéeu¶ÕD¦™BYY™På¹ä¦ÒLƒn¨‡“&M’àí$HGGgÏž=dî^uuõÒ¥K¼Ì½¢Ó9¿ùV‰ÐP±±±¸vMÐm¹ÅA’£fÏ!„Bß<þ ¦‰æ¾˜`ÿ¿Ðh´§ iá“3º:ê›×N€UŽ-_ZXT,+ãCþ’Õ‡®ßI ®íaiB£ÑJJ野ß`±X5ŸëJ˾üa9b¨;}'üÂãêšÚO¹ÅK}o<ݵ‹1gm‰Žö—×¾eG¸¯ßñœ¼&“•ô:s¨ÇÚç/3TU”Ö{K%°–hOýöZk–M€G¯O[”ö>‡Åbåä•…\2µ™‘ô:“ãÓËÜÚl"'Í!$jæ—œœNWRR¶†îÝ»ÛÙÙ%&&¦¤¤$''“ ¼ªªª®_¿¦¦¦ýû÷—àí$næÌ™§OŸ€7n0 AV¹ÖÑѲù÷C¨†Ú¶mÛ¥KÍ|ÇÎÔÔôÇbFØ,ªËH"„Bß¶ª†²Ä’[©OyL‘Ó´ë£ëª©ÐNZ±}l¬Ì¼'ýpìt´ïÆã£å`ñ\·ü‚²À ˆû.îÜwQ¿½VuumUu-”WTÿ8ôËrò&ÚM;ðläÃùËö¯Ùx¢ªºvÉ<·?7΀9Þ#‚B.WLœ±•–••ù+xIiÝgÝ_Rz­Y<×­¶¶~ÿ©À ˆÀ %%…ÚÚzèh¬÷÷¡å–¤U µçïË'|Ê->|ü扳wOœ½«¬¤ð¹¶´µÔ>å÷²î|{™§¶Ù€ˆÀÑL ÁÀàËf+/^¼­j@Ó… _vo½yófmm-Lž<™}l‰ÜN²úôùòïýçÏŸß½{'È%$IA§Ó™LæZDh¨¶†L×¢£äB!©«j({˜v&csJùÎLšöÍ}0üsLâóó¢¨(Ÿ™U°?ô˸l°Þûñm3~fkcN§î`¤ç5fÀ¥ÓkíÿÏxðcû—.[èÑ͸¡¡±oo‹Fz伞®Æ³»;=F9èh¨«üàÒóö…MÓ§ ÕÑnë¦h4Úª¥^q··O8ت[G9Y'‡î+{ìâd-­¨Z¨=eeeîZxí܆)ãÿgÕ­£ŒŒL_;‹ÅsÝ’ã÷Þ—*ÖT/óÔ64Üç}Ï|||vìØÂ,mccóúõkرcDzeËD¸innn‡X,VŸ>}ȪÞS§Nýûï¿àåË—666¼­­mRRœ;wÎËKÖäåå‘ã„„j“;>Ö¬Y%%%Ž‹¹ÿþàÁƒ@QQ‘$àø¡%r-"4TK‹ˆˆ?~<tîÜùýû÷Í–?yòä/¿ü÷ïß4hP‹Ç‡Pë¢×m>ùeô¨•±µ·ó,éÆƒ’ zCéó’ÛÜ#˜dh2]4úØéÇìB5ëòóȘ´‡äx¡GŽfBH8ÔzÛÛ¶mví$ÂÈȈì%—ðñãdž††«W¯€ GŽI"·Jzz:ÿÔs|||óæ 0€ç˜1ogfföèÑ#زeKjjê¾}û¸S”ÐÐPWW×?¦¦¦zzzjkkÛÙÙuèСºº:55õÕ«WTɵk×6ŒOs±“••íׯ_ttt+¤™šíG˜:uª§§§×R?-ÔP·dÉöñVéééä °°pÞ¼yÔyeeå]»vq\›››[TTNNNÜ5ß»wÁøò×yLLLuuµªªªdƒG!„$ˆÞP’Xr;­âÏ5˜úèºj(ð[l!„à0Í„@^^ÿ嫪ª¨c¶{÷nkkëU«V•••ÕÕÕ={öìÙ³gìå{õêÅ3—A™2eJxx8“É$æyΘÿv3gί%4ÛÀ6‰OØk©Ÿ–k(É ­®®æ>O§Ó}ú´wï^WWWKKKMMMuuõ>}úLš4i÷îÝYYYsæÌá3$ЧI“&‹Å’àVnÒÕB Õv„……@çθŸ>|øªU«455»vízêÔ©¯÷e"„úÈÐd­µ²=”é¦é0±ÓšÁ†S0Ç„BGã¿YBI„³³sLLŒ³³3™Ä‡Ú²¢¢"CCCƒáïïïëë+ípjôš¢Í'û“c+ckoçYÒ!Ô¢jÕ§Ó72X övºÃ1»„BtùydLÚCr¼Ð#'Í!„ZÃÌ™3cbb?~üéÓ§:H;ÄÏùóç †ŒŒŒ···´cA!„$@IVÕÅ`¢±jWeY5iÇ‚Bß8œ4‡j ãÇWWW€}ûöI;Ä“É$}4jÔ(>+y!„B_—.v˜cB¡V€i&„PkPSS[¾|9ìÙ³§  @Úá &…‡‡¿~ýþøãiÇ‚B!„úÊ`š !ÔJ–/_®¯¯_SS íXo cÆ 0yòd{{{i‡ƒB!„úÊ`š !ÔJÔÔÔüüüàСCeeeÒñ•ššª  °eËiÇ‚B!„úúàà¡Ö3sæÌÌÌÌéÓ§kkkK;ÄØ1c®_¿þáÃ333iÇ‚B!„úú`š !Ôzäää¥jF1b„´£@!„B}­pÒB!„B!„’L3!„B!„B! À4B!„B!„’L3!„B!„B! À4B!„B!„’L3!„B!„B! À4B!„B!„’L3!„B!„B! À4B!„B!„’L3!„B!„B! À4B!„B!„’L3!„B!„B! À4B!„B!„’L3!„B!„B! À4B!„B!„’L3!„B!„B! À4B!„B¡o„óˆ•4m· Kҡ蓮B!„B!„`š !„B!„пŠK*åôÆÐ´Ýþ¸JÚ± ôëŠ4m7/ïÑ.§W}¦i»Ù\,Ù¨¤ë›|Q­ ÓL!„B!„þuáʃ©¬¤Ÿ’“W"ípPUV^%í$ï›|Q­ ÓL!„B!„þ~ñ±œœì«&±X¬ó—c¥j£¾ÉŒÌ7ù¢Z¦™B!„B}QT\q÷aÒÿœm¦N áI;"QÐh4i‡ðíû&32ßä‹je˜fB!„B!ôEdÔ&“5fd?cC]‡>]câS>åskhhÜzÍq˜¶ÙO{Lûó–¿Ãï1™,òì†ÀÓ4m7Ça>ÜV×Ô*Œ£i»¥gæÁÿo WXTÁb±BOÞ¶ü›ª‘W·¾ó~]q æsÏ?|,\°<¤ßÐåªF^¬¦ÍZ¼'7¿”£Œ‚‚œ ’»—T~®­_µá˜‘¥7MÛíïð{T¤×™ÓÙ8ýªÑqÂÀWùú¯¨¬æIØW!`µZ¦?Ñ´ÝîÜÁq~ôÄ4m· §ÙOòïÁ òZÎF>¤i» v[C^ MÛüwìt4{U /Þ{ÏßÕÕ~®®ùäáã־Ÿ.àó”P-CêÉ+(­®©õÛzÆÒaž’Á8ëé –‡ä–QÅ|Q¨YrÒ!„B!„P[qîÒcpᣟ&¤¿»dž;{&“5nªÿ•›ÏÀ¤C;zÕç‹Wã.^;}îÁÕðõ4í—Ÿ~ðÛz&þŸÔ̬‚N¦úì×Þ¾÷¢®®¡wOóÎ ©“>üºòÀ¹‹Éô÷9iïs^¼Êxt}+Ǹ¤ÃÇo.ûýHUu-())ää•„ž¼õäþ•€ž=ÌØ#œ4ëϰÈGÍVE%“fýIå,zYw‹µsßÅ5›NÔ×7’{=ŽK~—|æüÃS‡}ôëÎÝt‚¼ ªD³="l…ü_‹šªrçN†•ÕÅ%•òòr&Ú‘bêjÊÔËÜs0jÅG••45Toß{Aþ ;ºRIQãv<» Ù§„q)f÷¨ôÌ<Æb±²sŠCþºváÊ“Ç7¶’Åf_ŽfB!„B!PXTqïÑK[sÓŽí`ÌHG¿ð˜£Ø¥kqWn>ÓÑVñhOÖ«¿J2N¿Š 9Ì~ÆÏÃHFÃÜÌ`Ðkãšsuã)xÀ~rä„ Wn< þs^ỿóSO®õ™1ñ)÷¿b/vüLôœ¥ÁUÕµ£_ÅWçD|J>¶bñ8»^­ºud/¹ò£—¯Å7[!±zÃñû_m^;õ]¡§Ñ;--:ÀþÐk>ëþª¯oôY4öãë£UŸÎ%>ØÝ¿¯eVváÏ?Þ¥çr×#È«¡ZA4Û#ÂâÿZF»ö}Ÿx(ào°êÖñ}â!òŸ§»¹üòõ§K}+*ÈÛ¿´2;%”Å«}þ\wòà²Âw—fž9}d…ªŠR~a™Ïº¿Hf_ŽfB!„jUŸéÕÔCpÏh`ýçÀâ:óïa“O±XÜ…¹oÚtÍ,Þáñ ˜%La.çWøß-ôêš~ŠÅ]X€€E{uÿÞL˜ÂMÜQÌWǦWµT›ß <ï(¹gƒÕ¨$«ê¬ïÅUì«y%–Éd¹ÿè@vïÚÁ¢³QìÓ”ìœâŽÆzT±ø„4ï1€ -¡ÑhÖÝM¯†¯g¯jú”¡b^Ÿ=ÿpõÒ„Éd]½õ <Ýþ“f’••yp5°¯y¸qÍ”Ë×ã_¾ùpýNÂà=ÉÉJzͲßC`²× “—ËÈÐÀØPw›ßtƒ)+ûŸ!jjJWήç_!åòõøÃ»Íúe8u¦¼¢zÍÆ°r‰çÖ ÓÈÉÞ=Í£/oqºüå›k68wl5G=; Ѫ„ ="Az¤)5Ÿë–¬>¡{—LëLNZt6Š8îkÑgNஈù3F*(ü'ÁÝ‚<%'ëˆã«Ûéi’‡“<]T”=¦l¾t->%-»{׎ü/G‚Ã4B!„P«J­x_%í(B-BAVù«N3‘KÆ$i4š§›S`PDÄ¥˜ßŒ¡Š‘”SܳԚÏu*ÊŠ<«òt°Ðç@ÒëLöÏðÏÓ Ëm¬ÌºY³^µÄ‹Êhûº8Y¿|ó!'·„:yþrli]QQ~«ß4’c¢p䘬Ò×ÎbæÔaìgÎ_Ž­¤×¨©*­ZâÉ~^YIaÝŠŸÆO <9¶¬¼J[KM¨›ŠV­ é¡Õ€Â"eeöîi>Þã?ÉD3“öÿs¶¹sÿEFV>Ç $î.ä)¡ŒíH嘈Ѯ};ëeç_ý¿öî;<Šzßãøw¶$KB „„ 5„P@" G!  TQì ÷ËÁ«<€Ç«¢ØÎ9E,< ˆ8D)A"A‘¦‘Jênv“ûÇx–°)l YHÞ¯'ÏÃÔß|gx6Ÿßo¶ fjDtš€Æa«°XífwWQOç²ÎïL8Õ#¼WdGÇÂÉãK•÷ÍMw]h»€CI§cÿòøòU[ÍkÕÖ|¼MZʰæ³]Ž…Õö˜§ØHD‚Û¶‘¬œ Ï~îLH‘Aý{„…É¥¸Ò ÃÔI×;õ,ÛýÃQ‰àßÚiã±£ˆˆªª{ú­®­_³®påŽÔI. “]{“Ddø°¾UûëuîÔND´Ñß+«z \YÕ@z½.¦O9óGÖåh¿Å"f€Æ¡Šz$o×¥·»"i=æRÎfuêó_ŽŸ)Óæ‹È~?›šíز}HÀöM/Ç èñû‰´g. ‹š>çÙ•ç²Î;5xÿÝñ"²fÃnGwE-fre°£Ñ ÷sLÏÌ‘î]CëwvUt¨ú0”v,-qâÕʳ]°¿ˆ¤g8¿Þî’m¬f«rñŽ4D-ÐIZF®ˆ¼¶ôsÇËÚ?﾿EDªVõ¸²ªáB‚ý„˜©±Ñi Iš:Dù]ø&¿º/i•‹þ¨vÉ…½\ØX.:„⾕æ§5J5Û8ÿàÊ^•Ž^¥Áz\“\¹ פ¶³«²{­5_¼»Ò„gWóîµmܳ«z3k+¸ÆMpv…¶Ü_óþ(ùÍi´&½bèâÓÓ/N®NZ¹RsYµ¿u¯ß”0kÆDÇlÏîá [nÿþ—¥Ë¿ø÷–Ÿ^[úùòU[?YñÄØ‘Û ëuMDÈñ“i'Çöír65ûðÑ”Ý:8 ×í"»]•êÿh|µg)Z ®.MӬƕ;Ò4´3è}Mtψj7èÕ©)ë©EQ‘YD ½» iVˆ™šT¸wd¸w¤»«Pç­Y‰9[Ot]¯{úÅÅÆ{ÚÔ´ï.3+gBRÛ 6™¿¯vê0õÅÖýãîxqíÆ=•c&Ñé”QÃcF 9òkÊœgW~³ãàÔû_9žøNûÇÓ7ÿ£õ›bûvùjÛ¹mÂÐúEE!mý¤ºþV—Cû9}&³êªRsYƹ< mx¹›Õ®SyE…‹í_òŽ4 í4û÷ëºâÇ.Ó!êzej’|&SDBÛ5éõiöè4—pÞšõmúêµÉ N&VΘôб—ÿõwv™;$äÖ«7c‘Ï6ïUUuôˆØªƒòÜ0´·‡‡aßßkê[Ô;ªÓkžëÔ1¸¸Ä²+áhåUÓî."Ÿý{¯ªª[¶'Ju3¹hð ž"²ïÀñ¬ìKÔ@C㢴c/(qZõÍŽƒ"¢(Êuëü…A]› ô‘ܼ"§‹K.1þW-w¤iÝÙ**œßA©æÎ„¤òò†Æ@5©÷•©,=3ï—#É"2$.ʱ°¦“‚눙 Fç­Y;ª˜ ZÀ44äVï«9`Ò¬Û¸GDÆT×ÁÊÇÛtýu½Ddý¦mIfV~q‰¥ò6F£!"Þ¦S§3þ¹lÓe:´ëWÆ!/¿ØiÉË ?µZË;†µtË…Ž®5\GÌÕ(°fïHÿpmò‚ÕLC›MÀ$"çòví=ªÓ)£nŒ©vƒÑ#ú‹ÈÚ{DÄf+¿õÞùQƒY¿)A‹6TUýlóÞÝ?ÕëuZ UÙô»âEdæSË‹K,SÆ©÷àJ!Á~OϺ]DÞ~ïëé[rüdšªªi¹KÞÚÑûCI§ë×lµü[¿<÷^ùÇkkŸzaUZF®Ý®J:?qîÁÃÉÞ^¦ùó¦5A³£ãcEäý·¯ý|OI©%5=gæSËŸ_ðq÷®*oV×;ÒXzEvT%7¯èÝU[TU-5—åå‰H`ÀŸ§ùäóïÏž»B{úLUÕä”ÌÇÿ÷ݯ·'6üÐ.^™Ê^Z¸æ¾‡;‘j·«©é9=ùî[+¿‘ùó¦™<=.yRpc3ÀE ¬Ù‰¹[Oü\e &C¤_\L`¼·ÁÏ]µ]Z¹¸‘5=¡3:>ö‰çVþ”x<ålVP oLŸÎ?8vÛôŠ¢tïZTdNÏÌ‘óîëÚ¹½Ó¾“Ç]7cN+í%÷®¼c®Ï̾=5=gùª­¬ÙñÁš­Lf‹UDüý|RÓsúF_ÓÆ<öÐ8‹Åúìÿ}´`ÉúKÖ›L‹UDÂ;}øîìÈnaMÐìƒÓF/yksvNÁÔ^Ñ–èõº•KÏË/šóìJÇfeÖò:Ý‘ÆÒ1¬íÔIׯٰë‘YËž~ñƒâËã[øâÚifžË_°dýâ77.~scH°_I‰E‹ÀΔŒ‰ïßÀC»xe*»n`äš »Wú㯈Ì3õŽÉÃ\<)¸ˆ§™àOÖìï2>ú4yþ‰‚NO0Eù ¹£óÜ¡!SšYÆ$ÿyÇܘ‘5þòß+²c‡ö"²nãoÓÒ…'~¿dú]#:†µ=}æœÁ ßÇæ<9sJÕ}½½L·O*"áÁýûumHz½îÎøjÝówßvCTpN70¶Ûcûuß²›G lHËU)ŠòäÌ)?n[tïÔ£z„ôºÁ×ö|â±É‡–Ý4Íúîß±xâÍq¡í|[{ ÖgÛç/Ýw|€ÿEi`]ïH#zÙÌY3&öèÖÁf+Ó-,4ÈqšóçMÛ³åÕîÙ¯wç¢"sXhД C6}<÷ýe3~\¯Le÷Þqã/»_¿óÖa¾¡í&¼eý /=sOÕÁÈj:)¸H©÷ë®RE¥Ù/¯¾N›Žê=mè»·W‚BkNbîÖ“…‰võ¢'˜tŠ>²M\LàHcsK—šÌßç½·ðõ ³´è%ž AS:úï û~ûׂ{hœ»kiž6Üp|—6=câz:ÍhÑ ­9?ç~s¢ð@Õ€©G›A±#}Œþ°ÛÕÏ6ï‘»o»Áݵ å²Ûyy\!f-šÓo•Z”B[ÎÏ95LׯŽ"`j¸õ›’S2 èÓ§³»kÐøœþÿ$f-ŽÑØ* u¸¹,×b5—W”»»nPhËý9ç›…û ˜.³Åjò4nÿþÐ#³—‰ÈËÏÜãîŠ\å"b2¶je ðôð&f-ާÁ+¿8MUí"Rf³¸»MÊf/K8·áxÁ~§·ÈiSLàÈÖÆwÕÖœ 1;9%³¤Ô""³C?wWರØ,"b±™-¶4£¡1hqEg2ú˜­…"b¶™Ý]€&eÐydYÎTΘtо{›±£˜KY™M gЀ½ï¦î‰wwE.³õÂG©Vž¾ÄL %jej£ÅL…æUTEœßg  ¹RDéxÓöôU¢L¾cƒF¶6º»®fÅÓÓ˜ôÛî®Ù³åUw—ÐÌZ ´ ¢7y´&f-Q°_—¼Â?DÄZnÍ)ÊnÛ:ØÝh:}ûæmò ‹ åKÀõe«°ffiÓA~×(¢3€–¨CÛècg¿×¦ÓòS‰™€EerÄ,¢ww!puK?Ÿîx‘BXP´ˆèÜZ€{hŸ„4grN»±nAÆ w6'Å1Ö¶·3€–)¢]¬c<¦¤Ôꪺ·€«Î‘ÔCŽéŽ!1BÌZ&oS@§ö´éBsA 4ÔÅùÒ|ÇÓLþ>‚yš ´`}»Üâ˜>xf¿+¸ê<“¨ÊŸÏƒ÷î2F{Nœ˜ ´P}ºŒq Î’xz¡¹À½õ\-lÖ=Çw:fûv¹Y› f-”·) O—±Út¹½ü»ß¶»·€«Å¾S{‹-EÚtDHŒ6þ·3€–lDì EùóãÐþä‹ËŠÝ[À•ÏZnýî× ßÏèÿ?Žib&ÐrûwíÝy´6m«°}”𯜨Ýç‰ë_Î…÷é>Ì±Š˜ ´h£¯£×µéäìS?œÜãÞz®d¿î —ZªIDAT¥ý9åÏw§(¢Œü\åµÄL E ôí8úÚÙŽÙ/m>“›â¾r®\¹Å9ë~úØ1×뮎!ý*o@ÌZº¡}î‰Ñ¦Ë+l«v/Ï)ÊvoIWš’²â;ß.)+Ñf|ÃÇzÒib&ÐÒéýÃ{½´Ù’²’»Þ.µ–º·*€+‡­Âºbç;¹Å9Ú¬^g¸;þuÇÇ'b& ð `ÌJƒÞS›Í+Î]üõ‚´ü?Ü[À• ¯8÷_[9>)Šnêð×ÂÚö®º¥ÂëT4‡O}õñ·3UÕ®Ít†»OêíÞªÜ(%'yåÎwÊÊËKÆÆ=ù—¾­vcb&€ ŸújÍŽYörÇ’~ý'ÄNöòðvcUMÏVaÝrøË„»Ù‘"Ê-ƒŸÚûþšv!f¸È‰Ô„ÕÛf”Y‹KZ›|GFØyNaÀÐü©¢ùãЖÃ_8c½Î8å†ù±Ý&Ö²#1€³ÂÒ¬·7Ý™[x¦òBSë±}ÇÇDô'lÍ•ªªI©‡¾<´9¿$¯òr£¡Õýc–w «}wb&€jØÊÍ_ï[´÷èjÇPMƒÎÕ¿Óµ‘¡QäM y°«ö“玦֭<¼LÏ&. TQ­å6³­Ôl5—–•$gŸÌ-ÊQ¥š€ÈÃè5õÆEÑ׌r±eb&€Ú¨ªýhʶí‰odä«}Ëö~2Χ5MUõæïàÔ'®ªßðá1‹í>I¯3¸Þ21€K~=óíáS_%þÆVn®vƒ°€ðÔ¼?š¸*€º ð Ì+έv•^gŒŒ¸1¦ëøèÎ7)¢Ôµeb&€:°Û+öÿ¾.#÷XZNRZvR…½Ü±ªcHÌÙsÝX€+‚|;å¦8fuо}`d‡¶Ñ¡=FÞnÐ{Ô»eb&€zREÍÈ=f.+°”š­…z±´ì¼»‹¸O»½Â˳ɣµ—§_û žõxp©ZÄLh¼…€˜ €˜ €˜ €˜ €˜ €˜ àÿxýÛeÐJ¯IEND®B`‚trusted-firmware-a-2.2/docs/resources/diagrams/secure_sw_stack_sp.png000066400000000000000000001041351355360272700262420ustar00rootroot00000000000000‰PNG  IHDR¾ÊÔ4R¢sRGB®Îé pHYsgŸÒR@IDATxìÝ ¼UãúÀñG'§A]I*E)Rݤ Eˆ®2U„›9„EHfn‘)JW”kè®ü•™®rÔ QQІ[R)ý÷³êÝ­=ž=¬µ÷Úûý­Ïg·×^Ã;|ßÝ:Ïyϻ޵ñݻÏ_¿aCaA²¨\©Òׯ½òJÓ,’ÈÉ©\órÂL&µ@¯w]ºvB'žKþÍûº¢½?ø`òÃØ‹”#pÁÅÄ—k^9 Én(W  ×»‚¸—‹ëïM*ø›>©#€ €  ß`´¥@@ðY€À×g`’G@†o0ÚR € €ø,@àë30É#€ €C€À7í@)@@| ðõ˜ä@@‚!@àŒv  € €> øú Lò € €Á ð F;P @@Ÿ|}&y@@`ø£( € €€Ï¾>“< € €@0|ƒÑ”@@Àg_ŸI@@ ¾ÁhJ € ೯ÏÀ$ €  ß`´¥@@ðY€À×g`’G@†o0ÚR € €ø,@àë30É#€ €C€À7í@)@@| ðõ˜ä@@‚!@àŒv  € €> øú Lò € €Á ð F;P @@Ÿ|}&y@@`ø£( € €€Ï¾>“< € €@0|ƒÑ”@@Àg_ŸI@@ ¾ÁhJ € ೯ÏÀ$ €  ß`´¥@@ðY€À×g`’G@†o0ÚR € €ø,@àë30É#€ €C€À7í@)@@| ðõ˜ä@@‚!@àŒv  € €> øú Lò € €Á ð F;P @@Ÿ|}&y@@`ø£( € €€Ï¾>“< € €@0|ƒÑ”@@Àg_ŸI@@ ¾ÁhJ € ೯ÏÀ$ €  ß`´¥@@ðY€À×g`’G@†o0ÚR € €ø,@àë30É#€ €C€À7í@)@@| ðõ˜ä@@‚!@àŒv  € €> øú Lò € €Á ð F;P @@Ÿ|}&y@@`ø£( € €€Ï¾>“< € €@0|ƒÑ”@@Àg_ŸI@@ ¾ÁhJ € à³@E?Òß°aƒÜsß}²pÑ¢¤É_uÅÒdï½#ŽùÏ'ŸÈãcÇ:Ûâí8ØãS^yE^yõÕpªýúö•NþlëJ´‹Û!×mäλÖ}¯m/¤ºQV®yÅõ-àš—}{&º¶%Úž}ޤ€@j¾¾©e-r÷½÷JÍš5å¦nwÜ1ÕÓ|9î¡1cä³Ï?÷%íBM4mC]‚ÒŽ…jM¹íàšìvæšìö¡tx!÷¡+V¬o¾Y~ÿýw/ê“Qú¨ zµ—÷át^¶öö.øî;¹øÒKÃ&© ¡S)'Ç o ü_ášù-àšéÁ'ŠYÀ÷ßD=î?wè‚¡à3_æ'3g:m¬emß®]1·w¹uÓÚ+µyóæð±‰ÚPHö'Áp¬ `‘@¢ÿ/\ó‚ù%àšÌv¡Tø%à{à›¨àÞ`šñ¼?þøc¢C³Þþî{ïI‡ƒŠ;œBÇæ­\¹ÒÉãÀÖ­ã“u $5kÖÈ}£F…ƒÞD?ÀÝÕéѽ»èKϽ÷osï Ìz²öL!)HÑ pÍ ^sÍ ^›P"üÈëP‡æÍšIii©¯uÔÉ×þýï„ylܸQ–þôSÂý6í˜þÎ;¢º¤ôºmªW¯.7¸_ÊkwXGÀo®y~ §—>×¼ô¼8bÈkà;wÞ¼p å&†O]U{>¦¾ù¦sB•*UäŠË. \›zm¶Iû§+Æñ~ pÍó[8õô¹æ¥nÅ‘“@Þ†:¸Ç»)¨3(o‰ÈyÄÒûä“cNuß«cˆ^~yÄ1—^|±¼øòËS®ýß[o‰¾ößo?¹à¼ó¤B…í¿$š®(Þ±&#÷Ø135š»Þî^U÷v"¬n:r}h¶ Ó«Áèõ×^+µjÕr’׋v²ý¦ ©¾» w MáfòIõüòŽóÊÏÝ®šg¦ío¦aK§L3©‹97“w÷wÜŸè{—I}Lš¼û+ÝŽ\ó"§®äš'ïÿ/×¼­ÿ/¹æù{}²)ußßxAg4°~¡÷jÜ8zsøstÞZÑ@õÓ²²ˆ)Ñ¢/îã3Yp›t>ÿâ ¹hà@1­Ùï=:µyôñÇ Û}ü?_xA¾]°À½I~ûí7zãN>zž{¾a=Ðì7]ÄÉ)|p÷Hår I†‰®wxGh%U¿ÿýïré Aá_L^·tYÝm¤¿Eï7åÐ÷Tëâ>'Ùz¢ÛWyí]Þèú$ËŸ}™ ¨qô/ÚÑ)qÍ;/‚„k^‡ók^¤‰¹¾rÍ‹táSú¾¾åI{=œ{nDïj¢sÜ=¤zŒù¡®?hܳB\xþùN&Ž>ϤߢE ç¦,Ós¯÷Ðä¡çDÿÆéÈÇ?ý´“l¢™)Þÿ}YµzµÜºLç,ÖsGÞq‡œÒ«WLÝ5èuÒî^“»¬îýO<ùdÄ/¦®å½/^¼Ø9D{–kì¼sy‡§¼ß+¿—B½óÑíhÒÖö×Þ{ÓóŸjûGW¢¼62ùéyÙ|¢ó÷9:èu_ìÝû|衈¿¸Ó*¯>îcYÏ×<®yú—}bŽ=ºkWiØ SòÏ>ûLþøãOk¡åëÛnŒÓ@ó¢ .ˆRõ†®¿‡žPwÀþû;ùN~þyùùçŸã–aÉÒ¥ãfõÜÛFŒˆ;¤@ƒ÷Űq£FÒí˜cÂéê~äéF÷~íù] °ƒ°x駦~_Ü:q·¿öúg;t²6ò².©´ön˜'ºƒ^=·R¥Jre¨÷[¿ûÚÞÓÞ~;n’Éê÷6ú*À5k^:?3¸æmª+×<_/MÖ%î{૽ÚËi aÞï»ûî¸A_¼Ћ…™ (Þ~¿¶iЫóÙjNìÙ3a6”–””$ B²7[¯nÝ„ùëŽV-[†Ë =Ëé.õë×wNÑ@*“óãåç¥ßñK‡æ§ÃýB±.^üÉÚÈ˺8.ç3·´þð‹7 È]÷DA²ú”“=»³àš·/Ûï×<®yîÿ†\óܬg#÷¡™ÞýçýLÓHvžþiÅÌï[=œ 2Ññ»ï¶›ì±ûîNÝòåËžg÷qzÞî¡ý¹Z~Z¶Lšì½ý·åTòuÿÑ@*Ýó£óðÚ/:}?>'j£\׺ז¬¾&è¾!1Q}’¥Å¾à pÍKÜ6\óÛ$Û“èá¾yñó/YtŸ;?®yåi±?[‚ |õ?Ç=¡¡æOÀÙV>Ùùîù}k×®ÓÛè>WÝe—]œr-þá§—8:ðuÄu3¿¨Öûƒ?”.‡žr|¼ú“_®ëâÎ/ž-Ûìàšç_[sÍKlë¾åâçŸ;¿Ä¥bÞLà=޹íyüñ¾Âú` íÕ ;Q/®i÷o«åývlÎ Ú»'Ù·ysùìóÏaÏMž3¥[:e.&¿\×Å_ôMté´Ç¶×<Ûk^b_÷5(?ÿÜùqÍKÜ.ìñFÀ÷1¾^Sg@?a‚“”þ§}ÿý7wy‘Gt¦W·›^ÜècÌg÷o«åývlÎ â{ß3Î?IOÿܤӧ¥sÃØ¸ñãÃ7÷“_®ë’N~AüQ¦ì¸æeo˜J \óâ+¥s òâç_:ùÅ/1[H]  ߟùÅ> Õ:ú¨£’;pWÝܰåޖκ¹iÍL—•èܧÿñðü²^Ï›(O?¶kˆÎža3éu¡G' €µWê‚ÐÃ@ôõihf ÷’o¿lÛ?Ÿui×¶­“}yß==èÙI“¶»¬Ž×¼Ü´×¼Äι¾~sÍKÜìñV  _w•ߘ:5;¢&6®ûýñ±c#ŽuÈ·_¶íŸÏºh;˜iòâ}÷´læ—žÂR¼\óüm[®yñ}s}ýæš¿Øê½@AŒñuÏšèŽOÝ>誫œàÓ0é°ëTÇéêdáfÂpݯS¥²ôèÞÝ9LŸ”–(o=ÀýÀ‰TÒ ò1zÒ?̃=R-ëÅ^sC\>ý¼hwÝs]—sú÷aOöÝs—‘õâàš—Ûväšß›k^|¶¶@Aôøêø3a¿á6c}ݽ“î§™éqzÞu×^î93çê{÷㎋x‚{_ôºþçuï½á‡e¸÷›r¸8áÞ_¨ëú'@}8‡Î»lzãÕÅÔ_KÔÛ/?¯Úß]ï\ÖÅ”ÿšÁƒãN§gæ‹Mõ!0îz°l®y¹o®yñ͹æÅwaká ìÐ¥k×-´° €Ùè˜io¾¹C6iäâ\®y¹P&Š[ ˆ×;½¶·º7µ+ˆ_oªJ* € €6 øÚÜúÔ@°H€ÀעƦª € €€Í¾6·>uG@, 𵨱©* € `³¯Í­OÝ@@‹|-jlªŠ €Ø,@àksëSw@@À"_‹›ª"€ €6 øÚÜúÔ@°H€ÀעƦª € €€Í¾6·>uG@, 𵨱©* € `³¯Í­OÝ@@‹|-jlªŠ €Ø,@àksëSw@@À"_‹›ª"€ €6 øÚÜúÔ@°H€ÀעƦª € €€Í¾6·>uG@, 𵨱©* € `³¯Í­OÝ@@‹|-jlªŠ €Ø,@àksëSw@@À"_‹›ª"€ €6 øÚÜúÔ@°H€ÀעƦª € €€Í¾6·>uG@, 𵨱©* € `³¯Í­OÝ@@‹|-jlªŠ €Ø,@àksëSw@@À"_‹›ª"€ €6 øÚÜúÔ@°H€ÀעƦª € €€Í¾6·>uG@, 𵨱©* € `³¯Í­OÝ@@‹|-jlªŠ €Ø,@àksëSw@@À"_‹›ª"€ €6 øÚÜúÔ@°H€ÀעƦª € €€Í¾6·>uG@, 𵨱©* € `³¯Í­OÝ@@‹|-jlªŠ €Ø,@àksëSw@@À"_‹›ª"€ €6 øÚÜúÔ@°H€ÀעƦª € €€Í¾6·>uG@, 𵨱©* € `³¯Í­OÝ@@‹|-jlªŠ €Ø,@àksëSw@@À"_‹›ª"€ €6 øÚÜúÔ@°H€ÀעƦª € €€Í¾6·>uG@, 𵨱©* € `³¯Í­OÝ@@‹|-jlªŠ €Ø,@àksëSw@@À"_‹›ª"€ €6 T¬P¡ÂÚ .¾¸šÍÔ²ÐkIö©øŸ×<ÿÉb(”ë]±·C&õÛ!““8@@ 8]ºvݜҷ$ unÛP2@@|=Ä$)@@à ø·m( € €€‡¾b’ € €@p|ƒÛ6” @@ÀC_1I @@ ¸¾ÁmJ† € ࡯‡˜$… € \ßà¶ %C@ðP€À×CL’B@®opÛ†’!€ €x(@àë!&I!€ €W€À7¸mCÉ@@< ðõ“¤@@‚+@àܶ¡d € € øzˆIR € €Á ð nÛP2@@|=Ä$)@@à ø·m( € €€‡¾b’ € €@p|ƒÛ6” @@ÀC_1I @@ ¸¾ÁmJ† € ࡯‡˜$… € \ßà¶ %C@ðP€À×CL’B@®opÛ†’!€ €x(@àë!&I!€ €W€À7¸mCÉ@@< ðõ“¤@@‚+@àܶ¡d € € øzˆIR € €Á ð nÛP2@@|=Ä$)@@à ø·m( € €€‡¾b’ € €@p|ƒÛ6” @@ÀC_1I @@ ¸¾ÁmJ† € ࡯‡˜$… € \ßà¶ %C@ðP bµjÕæ¯]»¶‰‡i’ ±@çÎcÎ>}zÌ66 €ùÅN_‡b§¦ùÊŸ|3¨¨AïâË3O3@}ò˜Ôž;)f@| Ôo\›Ã|ág™/C²ät@@ ð-Œv¢” € €Y øf Èé € €…!@à[íD)@@² ðÍÓ@@ C€À·0Ú‰R"€ €d)@à›% §#€ €†oa´¥D@ÈR€À7K@NG@( ßÂh'J‰ € ¥€'ï?_ž,ýœ.÷Þ—lþcsÜ"}8ãç˜éïM»¿6nذA†Ý2D.¿f üþûïåýoÞ“´î&=5L–¦qžðÜøróL瓲¼Mzß,øZú_ÐO¼.ƒIŸwüøßšÿÉ_/éïü_Ôÿkæeëw™ë’_ß4ÒE xøš ~úù,ùúÛ¯ÍGÞ· ô烵YŸþ'î/‹\$‹~XìóÛúßd媕1vœ~úÙLg{»6ícö³ è/_q¾èÿ£èåõ©¯:Að¼¯çEï*êÏ\—Šºy©$ð4ðÕ<zô”zA”§(7·Ü·•TªTI.^(lþ#¦ŽŸ}Q&›7o’.‡!ëÖý*sæÍ‰9fÃÆ ²ä§%²kÍZ²×ž{ÅìgÄпR¼üêKÎÎ¡× —ñ>ñjÛº³Ï¶k×¥øß¶"€@q xø6Ý»©ü²âgyŭ–fí*•V’ÝêîæØ|ûý·g›ž\ h{’ Çëþò«ÙNoÕŸÛ¶—wÜ1" > PLm[·—èW6õ3¿Xž{ÖùÒ¬I³˜¤.¿øÊP~íâþÿŒ9¸ˆ6p]*¢Æ¤* ²@Å”LáÀ“Ž?Ù zßyÿm9ªË1R§vÎÑñ¿£½?âX홉þ!¥®Ô´‡^s£\{ÃUN XµêN2ìêdÌÉšµkå®÷ʃü]f–}â¤×í¨ã¤Ï)ýœcGÜ9\¾[ø]Ävw¦„º1û4(Õt3 8µ·÷ÀÚ:y/Yº$¢^¦'·ËaGJõª;²þÉõ—_~‰ð[²ôG§8{ìÞÀ+üî…_81×ŠŽ‰¼bÈ¥á?«e‡mÃ6\‡±Š€§mBo® ~-Úc|Ë79•1ÇÄ»>™}:vÖ\t›Üélv;ïzÌWÿýJn:2âÿ¹Éë¨#Žv®[zp¢ëžû\sžþåÈ,ÉʨÇp]2R¼#€€Mžöø–V®,ÇÓÃùsýÓŸŠ;žÕ«¦Þ$ôê1#îžðªÇÇ=Æ48® LÍrïƒwGüÐÑñ{_Ìþ,& ÕíîíôÇù—ý5›ôô]{±/¹êBY¶|™{sZëì×ZJJ*Jto®éÉÕ€Öü Šî`z…5ÈoѬE8_?üLâêqéà‹Ãκ]ÍÞzûMsï„€ù¿÷øSc^SUDÔá#‡E½zl¼ë“ùÿèzõXÍ×}­Ñm™,Ñ×½]wÝÕI&2Fçkl¸.EËðŠUÀÓ_E:¸}Gùø?:Á综ÓÓá†|åßSœ@Sºx½hi@èî-Ñ To»gä¨pO‰þÀÑE÷éòÄèqNï¬é ½sÔíràþmdøõ#¤¤BI¸‡Y/ö‡v<ÔÙ6%4P{K¢{gL¯§ FSíÅv âú§~¨ ö¨ç«åÐE­Ü­þ Òñˆ?„nx3‹énѬ¥˜vºÏk¿p~!Ï'Ÿ~Üñ0=æºÏxšãxG önÜDzw‚¼0åyç—7½®˜E¯ —]|…s 0ÛÌ»~ß5ˆþ‹^oô/CšŽÞhjþ2eþ?º7=±ÏLzÚù¥5ÓëG¼ëž–3Ý2šº™w®KF‚w°EÀÓ_ƒvΙœÞËC?hM÷¥?'zå§Ÿ–:Cº’ýÔ [_Ù.îÿÿšVºet_CÝeáºäÖ`Š]À—ÀWѺ‡Æúj®ùs`¦f^ÛTþDX¥r•´\S.?]“¶y7=Ífƒ¹a-úšùA¤½I4r~koq&Ó˜¥ãgÊiÞãÝHgöñŽ€_3} |£Ë«½±O>¼õa0z™þ¢þÊk/K“ÐÐÈFŸýÙüb½=ŸÓ-c¢À—ëR.Z‹<@ (¾¾Ú»Ò¿ï¹ÎÝÐúä}»ƒ2ªs6Ál:>ôØ7¶™žMÃüPL'½xÇšhÆÐó¸_ â´æ‘ö&}¿è{çáz—w&³Jdãgôxua… `ÆèëøøDcyµ]»-¯¾ñ¯ð|óÕÌSÞÿ=ý3×KºeLT>“×¥DBlGbðeŒ¯Ò•Ö¡›µt]ôlæbk¦î2ç˜w3δaý†R¡Ä×bŠk«cZŸó´3Ö×ܰ¢=Áæ‰i¦l™¾ë/:­™þüâËÏ€6Þ¼¼:T¤Õ¾û9?„µWXÿý´6?ý´w]ÇW›?ãºëkæDuoc  ˜ÿ'å=UrùÏËdÓ¦Íb®7fÈ‘{L~²:š|â]ÏtHE¼Ç|ë0Š•«#ŸÒ˜Îÿ¯t˘¨ü\—ɰŠQÀ߈2$fnt›ÿÍü?s±Õ‹ÿ°×ELæ{羡+">DÿÐÒ€øâ+Ïè Î6[#«Áô›Óþ7 5éëpý¡ûXh*¤è±ËzŒŸ~î_X&Nþ‡)’h»˜'`…7²‚@€ôÿ‰N±¨K¼)Èt{¢ëþÔEÏÓkƒ{Ñ¿õpzxz4÷ÿÇ‘wß¾1Uÿ¯›RÜ¿¼6l°§“œþ5ló›õLþ¥SFwù£×¹.E‹ðŠUÀ·¡L{/Ï=ó¼¸sõê  CÊ×¾âÝ@¢=°:ݘߋéaMT“¿ú¯]«ŽT¬X"ú‹@¼a&/Ó몽½Úûlf}0ûõÝO¿¡éŸÊBRÖ1ÚîéŸët¸¼ÿÑûîb°Ž@ t6ýËI¼éÌÜשûܳº¸§fÔà7zÑÿ¿§œtZx³¹¯AoL=ç¢3ÃÛuE¯eMöjÞfn5³J˜éþÿJ·Œ&Ÿèw®KÑ"|Fbð½ÇWáÚ„þ¼=ÕiÄ.0Ð| ¿ëÛ+Ž™U |€Ç+æ±¥ÑÉ꼾ï»%áŸþ£/ï³ ²õ8ógÕxç˜Y-t_²^o¿ü´×w̨Ç"ÚMƒ#ﯸlC ÐúKb¼éÌ´Ðú<Þì3‰þéÿ…¿Ýqĸ{íõÕY#ôñÇîE¾–éÿ/3e£9V¯5™üÿJ§Œ&¯èw®KÑ"|FbØ!T±-‹,/ÖúQ/(0GŸ| ¦Äú_³  €@¾ê7®­Yk ˜¥K×®[S˜$'=¾®?EC@°D€À×’†¦š € €€í¾¶¨? € `‰¯% M5@@Û|mÿP@@À_Kšj"€ €¶ øÚþ  þ € €€%¾?¹ÍGª‰ ´mÝÞ£”H@HßH>!€@žÚøæ¹È(^†:oÛR3@@—¯ ƒU@@â ð-Þ¶¥f € €.Æøº0XEü Ì*›SÆýư@ ß Ð8ü˜Iàë.)#€– 0ÔÁò/ÕG@l ðµ¥¥©' € `¹¯å_ª €Ø"@àkKKSO@@Àr_Ë¿T@°E€À×––¦ž € €€å¾LgvÝ-CdÑÂï,§µ³úU«U—ukרYyËkÝ a#9ì¶À+\Ë5²páÂÀ—“z/°SõªòëšuÞ'LŠhذ¡Ü:ìŽÀ—“ú/àKà«Aïˆç^ñ¿ôä8¡§t§í×*¹)¶}!,ôÞ5õöB(*eôX`ðQ×Òö›JrÚö,¨Cø € €X!@àkE3SI@@_¾ € €VøZÑÌT@@€À—ï € €€¾Ìê`…•D_Ú¶nïKº$Š €/ß”@ß@µ…AŠI€¡ÅÔšÔ@@ ¡oBv € €“o1µ&uA@H(È1¾Ÿ¿ÿ¶<7ê΄…vï8ñÂˤ]—£M‹¾ž'ÝpµtÌñrÜY܇%]ÎoçZµeШG¤âŽ¥IÏc§÷Ñm‘,Ú>™Náî›U6#¦ðA÷»vÕZ¹­ß²qýƈòzò!Òó‚ã#¶•÷¡lÚg2aä3åæìï}e/iß­³¾pî"=èaéxÂÁiå_:5äš±WIÅÒ@þHHÉ…ƒ@T¬ïñp×-1AöꟗËíçõ“•?-MÅc T€¶fÃÍ ¾Ñ¯ •ôqoÊM½GĽZÎwŸOu­,˜ý]Њí”çÉÇÅÙ«–­’›O½UV,YÈ2S(@À+@ÿzïîÑóªÂît´‡ø¿Ÿ~"•wª&ß>Jv©[ÏÙ­ÑWÿùHþõäésÕP©PRâ>õÐö9@&‹Œ´—õ­g¦9ç^tßÒ¸U£ˆt4°üòƒ9òÛ&¦Ý‹êîÍHÔ£Zö¹3æI•jUäòÑ¥æn5”M™_=EÎÞ/tͳ¾O$%qzýSbâ %`õÕ힓͛6I¿kn½Ú:½/,»7Þ[¾Ÿ;G´÷—¥øhûâkÓ\ÕHÇÍ›6‹©ÑA¯–¡ÿMgJËŽ-D{Qýwq®Š•R>°kÙϾå¬pЫ'ž1ä4Ù£ÉîN/µ–›¥|zýË7â‚(è_?Á6nXïµ:žw½›FdUZ©²4kwL›ôùfÎçÒn[OpÄA|(XÚ¾`›®` ®ÁoЋ¬A­Žçm°Oýˆâ•V.•·©ãß”¯?ûVÚoë Ž8ˆazýì PpÖöøþ¾~½,ÿñ©·gc©P!v(CíÝ·þ`X¶ðû‚kT œ\€¶OîÃÞäÍÛ7“’Š%2éžÉòòÃÿJ~p€öjà»|ñϲû^»ÅÊP§Am§´K¿ãÞ†òš^ÿò„Ø@pÝãûâC£D_‰–lf_X±ü'ùcó¦DI;CJ*š'aÙ‹am_ ­Xœuhؼqz§wTodÓ—YZtØ7«1²Lë+Ñ’Íì +–®t†9$J[Çûj@Ïâ½þÞ8’ ^ XÛãë5$é!€€=GŸÙUnr³3.Ö]ë9}%×t».г:¸ËËzfôúgæÆYA Ð]š~ßÙ„  ñhûø.l ހދ½ü¡KÃ2sêêÍcºèüºfÖ‡èysÍIf¿ùì÷¬&Þ³ ×?;?ÎF ŸÖöøÖ¬]74Î-qܯsøêŒ,Å'@Û_›¡F ÝþÚ­r×ÔÛå¨~]"MöíЪ?‚P<©Yo—¤Ct_´¢À/½þo Ї@Ä‘_‚ŠeóŽ•+KíÝ÷¥ß/?þØ3Wïò;U­ÓpÏb©2õØ&@ÛóUÈTÀÌÛÚ¤õÞIÇòvìÙAÞžôŽüøí'ðmÝåÑW>í¡®]¿V¸LÑsõ.[´uêÆz¶ÎgžÏ²JÞôúJKQN¶ XÛã«S–éÍq:OïßÌß.ZÓ鮿}ò±ó`‹½[ì±…/@Û~æ«&xÔ±¼ßµ0a1Ìd‰fPHx¢;´ìzs\¼ù…uƇ9ÎqlÑ䀽|,Eq'M¯q·/µ+k_m¾ý:æ´âø;nŽx<ñ¤¿ß%?.øFölÞÂ Ž‹£©©…[€¶wk°žª€O9Ü9\ÇðÆ›ÎÌ=Ö·e§–q§K5?¯kÝyk¯óØaOE<žXŸ2÷Ã×?:äÐà˜%±€öú_ßãQÃdÃX´×_¿/î^ýŠ÷”Ĺg·ÇüâfʽþÑ"|.F@u(oJ+mfmÛÇ2>â1Æð¡(hû¢hƼT"ÑMZ ‡Œ»Zz^p|^ÊV^¦:¿lŸëN8L{yoxöúˆÇGÀ‡°½þa V(HB¥Þ²xÁÖ›¼ªA¿§Ëˆç^ñ*9Ò) ¡§t§í ¨½¼,ª¶ýøGŸÉ:ÉYe3bÒhÓº}̶L7èõIÿÜÌbŸÀ࣮õ¬íß÷¦ÓëŸLQ{ýSý(Ñ”wñÒw÷ú»‡ÖÄ;Öl3½þúùÉÇ9½þfŸy×_Ú.=°(Ò¶÷âúd¬ê7vžt¨1T`–.]»n La\@u°ECŸ¼ r}*"É" Úëßù”Üùšuè€{ z©½þÑv6Ot×u‚.@àô¢| €ÐadSÈL§¼33I¤›w¦ù¥›Ç#4ëÇø­A( € €€?¾þ¸’* € €@Àê°¡8Ø.à÷Ím¶ûR@Àf_›[Ÿº#@™>ÏêÀ*S$@ 0Ô!GÐdƒ € _ßüú“; € €@Ž|sM6 € €ù ðͯ?¹#€ €äH€À7GÐdƒ € _ßüú“; € €@Ž|sM6 € €ù ðͯ?¹#€ €äH€À7GÐdƒ € _ßüú“; € €@Ž|sM6 € €ù ðͯ?¹#€ €äH€À7GÐdƒ € _ŠùÍ>X¹oܰ^»ájùqÁ7Ò±û‰rÜY‚U@Jã›mïmÚ ·mÝ>ís8@T|]J?-ú^ô¥Ë¬éoÊÁÝzÈ.u빎`µXhûà´lßà4%AŠL€¡®}ç…çdó¦MΖõ¿®•oæ|îÚËj1 ÐöÅÜºÔ @­¾Û¾ ¿®^%_^ñ½˜6é²é÷ÛøP|´}ñµ)5B@ žï6•ÞxE~ñÕ¥á>û:ï«^.eïMwÖù§xhûâm[j† €€[€À7¤¡76ÍûäcÇeçZµå”˯‘+Uv>5ãCùcóf·ëE$@Û¯1g•ÍèWðJI‰@ Q€À7ÔjsCA¯Îä K—ÞgHPðÛdÿÖÎçy3gÈ¢ùsuþ)>Ú>xm:3øF¿‚WJJ„ PˆÌêjµ/>xÇi»Ê;U“½[ìï¬vÒ)òßO?qnvûòãdÏæ-ã¶ï¢¯ç9S ™›â¢ÒäA£‘Š;–Fï’lÎIŒ  Ðö±q €)`}¯Ÿàê²gó¢ª.uìé¼t]§6[ùÓR]M{ÑqÂÃûœ$ãï¸)í!Ùœ›vA-<¶·°Ñ©2 €@Î_y¥¼5uªó}ÿýR±bE©^­šL?>b[Î ÊÈúÀ×ôê*úa'ô’ %%ŽihŒo³v9ë:µÙ‡¯OqÖ“ýs⅗Ɉç^‰xíûçÎ):dbÂÝ#¿Ùœ›¬LìK,@Û'¶a €™ Ü¡ƒL}ýu9¶[·˜$Ö¬]+<ø lÝ?Õ¼ysépÐÖX+æ@Ÿ6Xøê4Vï½üO‡V{z÷Ø»is‡£»‡orûòã÷3šÚ¬ÏàaθaMXƒßYïü_DÉ>dsn²tÙ'BÛó-@@À{:uêÈÆIɶŽÄx9Ìž=[–-_îìê|øáññm›Õï7³? Oa¦7µEÃÝiçá›Ü²™ÚìО'Ëî÷v1ÝY"²9×·oM$LÛA#R@À \?dˆ”–n½¯é©qãäˆ£Ž’/B®{Ñ^ß²²­ÏNØ}·Ýœ!îý~®[{s›NcõÞËχm_|h”è+Ù¢Ak›ÃŽ ‡Hv¬{Ÿ›Ðe9bé÷ ä?6§œF6çºËÀúvÚ~»k €x% ãwkÕªå$§AïS¡±¼å-õ¶¾›¶=9·¼ã³ÝomàûÓ¢ïE_é,fj³D3<$K«^£½ä«ÿ|”ì„û²97a¢ï í-nü€U}íªµr[¿;eãúíOˆì}e/iß­]ÀJJq¼ Ý½Ô$­ T©ZUv­YS6lØ |”YÌãw}¬êðÎ Ï9S•¥ ¬S›e²,ýîÛLNsÎÉæÜŒ3-âiû"nܪZÙ´Ïä¦Þ#"‚^-þ¤{&ËËÿ«€jBQÓ ÝÓÑâØb¨_¿~^ªge¯ÞØôõç[Ç–4kÛ^ú\54éÐ=þîKÎuÆëÔfwë!»Ô­—rƒ¹ó«·gc©PaëÌ©$͹©¤oÛ1nOÚÞ¶ÖN}µ‡wúso;Šîá}cÜ›²~ÝÖǧ§Ä”Ä ÚÝ EÒ²ÀoëÖÉ/+VÈnõêÉ©½{ˈ‘#ãWg}h±ï¾Î¾Y³fÉúõ¹»æYÙãûѯ„ojsOa·uBõ&·CzþÅÙêÔfî´^|äþ´òóê\w:¬o íù&A@ å‹–ujH›#¶>%Ò”ëè3»JÏ Ž7y/"Ú½ˆ“ªÄpß´vD—.2ôºëbŽëÝ«—ÜzË-áY¦¿½µ æ@Ÿ6XøêMóB(Ö%Þf‰œS™ÚlÚ¤DLy¦y¾æÒðØÞŽÝOLø¸lÎMTf¶G Ðö‘|Ê¿À†uä¿ü/ÿ¡9 ÝsÊMf9xxÌY²tëC¿4øÕXìת•3gﯽ&ž~¸DsçΕ>Þ“…7ú¼bÝP‡¹¡ WgWÐ%Þf‰¼M¯¯¨fj³v]ŽŽ8ÜVOr©xòÆqNÞÑùêøÓ #Ÿ‘CO>$ÜëlÒ2ç›s«T«"—(5w«.“9ÖlHVFsŒMï´»M­mo]µ×wPè‰mãÆŽ OkOCƒÞK ’\Íæ`Ê`U¯{«Ê;U“½[ìoRzw÷úF÷Ðj ÷Ù:^ŘæsåýK¿knL:Ž8›sÝù±_€¶ïÂÖü œ1ä4Ù£ÉîNFzXnís»lÚ¸)¦@úçñ¿]ø÷ˆ WZµl• é>TÌþ.|N¢cõ šã¥>9…ôê¡¿­ýM^=%ô4Ê?œôR-c Ùõ!´{Q7/•Û&°lÙ2éÖ½»<êý^tƇó/ºH.80çA¯–%¶« º„EôYçĽ莿g\#íõ½qüö¹£jsäÑrÞˆ»£7§ô9›sSÊÀòƒhûÂù´mݾp ›EIK+—Êå]*&˜4¬éY5IOîùáë¥E‡}å¬áýB¿@oí¯0½³ÓŸ}[öÜ·¡³ÝÝ«ñ3·?k’Ìè}Æk3¤a(Ÿ»¦Þå>¼÷a[óz3ʼˆN¢Ý‹¨1©J\}r›öö>3q¢|ºqM`¤ÅªÀ7Hð”â ´±$ð5µïÓ™âž×U§3ÓEçòÕíoOzǹ ®ß°>á W÷·îr€”MÿL¾ý|Óû[Z¥Ô96:èÕc5ØÒ 9›e§?í$Ç8.œ„–[—tÊèNÈÒÚÝÒ†· ÚæÉmg¹õñå—_ªÖ¾j ƒ6 èØÏ[§ÜîýÕa :ÛÊ¥+CóokHd³:tƒ\IÅçØ&­÷våDÇfº}×=v¼M:锑Àרm}§Ý#=øTøÚÛÛlŸ}œŠ¼5mZJOnËu­ |s-N~ €@^ƒþ"óg}íº‹þ»Ø fõÐèañN_8wQ¼Ížm«×(ùÜ婔ѳÂYB´{‘5¨ÅÕqÏã»h‘¿×¤L™­º¹-S$ÎC¼Ðáÿ~jjL’:$¡vý­Ï¹×õÕu^s>úJ¾ÿjaÌñî 5ëíâÊ©ë>/Ûõtʘm^…~>í^è-HùË03:lܸQjß^*V ^ÿ*oy­È~È©À¬²ýÊir”Ù;“ß•±ÃžrfE0Yš›Ót°ûÔwÆæ¶8¸…³[g~pÏà õ¦µ1W?*+–¬ý³¹Þl¦K¼cÛþÙ}ï­³Ièq:+ƒ.Úc<ñÎç¶‘ú›ë©–1õT‹÷HÚ½xÛ–šm03:ü¾i“LyñEiÚ´i h‚ŠŠ‡Â €@®f†ßè¥XoxÓÞÙkºÅ>Ùè¨~]Ãóóv>å0™óágf h£½™Í,ÉŽußôÖ¼}3yë™iÿž-Ê÷s’÷,›¼ÜïÉòÕãÜetŸgëz´»q Ýï…*`ft(-- WaÌèÑáõx+«V¯–3úöÍÙc‹éñ× ilkФ™Üô—dÄs¯Hô-ÊK&›sËK›ýþ dÓ~ÙœëÍÈÁosSSËŽ[{sÝùéC%tF³˜é¯4(Š^´gø†g¯?DÂÛçºÓ£øÜ°yç¡zCœY4ßCNìd>¦õnòM¥Œi%\dÓîEÖ T§ v•zËâË=-|¿§; §‰’XA =¥;m_-å}!µíÇ?úLÖ ?úä1i èI̶L7èõÉÌE›iœW˜ƒº–¶/̦˺ÔÚö^\ŸLAê7®­«CféÒµë–|&^oyeÊu/CÊkö#€ €”+`Æ÷–{``¨CñÉ@@ w¾¹³&'@@À¨ûî“·¦N•C:evoA¦ˆ¾™Êq € €@FC‡ “%K—ʧ–Óù~ã›Qsq € €@*7]/ Ç×KMÒB@,¨RµªìZ³¦S{wOî{ï¿/M›6•–yýõ×eÅÊ•rjïÞám¹X!ðÍ…2y € €– Ìž=[–-_.×âÀÊЪU+©S»¶´iÓF*W®œ3†:䌚Œ@À6²iŸÉ„‘ñãܢþrÖð~R¡„þ‡bû^ÐîÅÖ¢Ô'UßÖ­“_V¬ÝêÕ“ „O[³v­”••ɱݺɘѣÃÛó±Â7êä‰ Ú¶n/ѯ„ðŽ9}%Ã{Ý"+–¬ÈY-Þ÷¦ >êZ™ñú')å™îñ)%jùA´»å_€"¯¾¸/†nVÓ¥SÇŽáÞ]ýüð˜1μ½ºî^fÍšÅÍmnÖ@À.6¡À·Ø–èÞÝë7ÊèAË_ÿ(ï½ôô¼àxO«¬é/úïbÙ{ÿ½RJ7ÝãSJ”ƒ„vçK`£À¤É“§±íÊ ½»7 .:ÆWƒâ .¼P~è!§GXmÞš6MFŒ™S&†:ä”›Ì@‘ÒÊ¥ò—ËNr‚ß/Þ-ÇÓM*–zw9žþÜ;R£N˜À÷è3»Š¾¢—t>ŸÏ© Ðî©9qTá \š½!Þ¢ÁoŸ~ýâíÊÙ6†:䌚Œ@í:Äaó¦ÍÛ7x´¦ãK§Ž3åÔÒ=>å„90®í—…E" Ol›8aBNoVK—λ.†tsæx@ÀRµ«Öʤ{Ÿwj¿ß¡­œÞÞ袴Çöš±WEôë˜[ j{_ÙKÚwk'OÞ8N¾ü`ŽT©VE.=PÖ®þU&Þùœ“î¤{&‹¾t1ÇGŸ¿pŽwÛöOtyuóE÷] [5ÚvÄÖ7SÆ¿Ž<[^{âßÎðݯ~'áÚÝÎv/¯rÒ*Õ¨QC^2E6lØàÌÛ;þü¤Ççz'o®ÅÉ’ Ì*›³¿ÐÇýê M×t».¦^°rBGq æ UËVÉgßüšý& ÔÏ¿­ýMž½{’¬[ó[ʽÈ:®÷Ÿ£^Hùx“¯{|²ÙfÞuÜrô¸V³ï±ëÆšUç½¼úE\ hwÛ½@¿®ž»R¥JÎß À¾ž75 "€@63‹0ðçqèɇ„ojÓžÚÃ{*ÇžÛÍ9Ô\êMjѽ¨3^›! ÷m(wM½Ý9^ƒàÃ{ægzbM/o¼¼u›Ž7½ü¡K%ÕãM::XoÊ3½Ì5wÛ:Y½ïøj°÷ÉÔYN´9GßÝ=¼îúÍz«,æX÷yŶN»o½©Ó¶v/¶ïq¢ú,[¶Lºuï.ú¤6ߢLê@IDATºL— À¾‰Zí €€G‰zAMò ›7}™EƒR 5ÀŒ·ìô§äøÇ…wõ¿éÌðºŸ+ú§ú·'½ôjžZ~ê Á¯ÇhsDëˆag 9-üYë×ù”Ã9Ž—~·ÔÏ"ç5mÚ]ÄÆvÏë—. ™ßuÏ=¢¯x°ÑÌôârs[>ÔÉH  Áåõ=npÆî&8DvÝc×¼<øbÅÒ•ÎÐíÖÀ\â¦Þ#䯷#-;¶HxF½FõîcGa Ðî…Õ^”63ÛWàë‡ “Í›·Ïf£ð?Cûxdqf®œ…¤€¹¹Íý§qR´¥f½]¤¤b‰,˜ýèÍif|¯)çÒï~}U¯Y]þ´ëŸÌfÞÐî `Ø\TÕ«U‹xh…»rsçÎuf~Ø´i“{³¯ëôøúÊKâ €@ùsgÌs†´ìÔÒ³! _¾ÿ¥ü±ùò3ßvD*ÇW«Q͹‰Ng‘øÛE÷G dÅ |Ù, @(,*¡±Ô»Ö¬èBøºy( € PX•*U’ºuê$-týúõ¥¤¤$é1~ì$ðõC•4@@Ë~[·N~Y±Â©õƒIåÊ• Ò©“³oé’%²iÓ¦„Çy½ƒÀ×kQÒC@,X³v­”••95¯±óÎòÂäÉÒ´iÓ J”œ/Ûéñõ…•D@@»ªT­*»Ö¬éTÚÝ“ûÞûïKÓ¦M¥ÃA…A^ýuY±r¥œÚ»wx[.V|s¡L € €€¥³gÏ–eË—ËõC†8°2´jÕJêÔ®-mÚ´‘Ê•+çL†¡9£&#@@ x~[·N~Y±Bv«WO4h®èšµk¥¬¬LŽíÖMƌޞz|ó¡Nž € €@‘ h€ûbèf5]:uìîÝÕÏãÌÛ«ëîeÖ¬Y9½¹À×­Ï:ä] mëöýÊ{¡( €@J“&O–/BC*Uªäôîš'³iP|Á…F¿oM›&#FŽL)]¯Ú!”ЖŠ–{•é € €E-P¿qm­ŸÆPYºtíº%0… pAèñ pãP4@@ï|½³$%@@ 0«C€‡¢!€ €A¨S§ŽŒ;Ö³G»t‘‹zøæB™<@ eYe3bŽmºá@l|³ä|ðT`&¯§ž$† °]€Àw»k € €I–-[&ݺwOr„Hï^½äÂóÏw޹aøpÑGeñ%ð½öæ!òâï‚RGÊ9Ø£A#¹ý†ÛrSvY 6H~^º4»D8 J VèIb÷Ýr_A•™Âú#àKà«Aïq¼àO‰I)ðêy'²\Ñ…Ò wZ'_.}ÑYñ"Ðå}~Ù HSä½Lg–÷&  € €¹ ðÍ…2y € €ä]€À7ïM@@@r!@à› eò@@È»oÞ›€ € €äB€À7Êä € wß¼7@@È…o.”É@@ ïÌâž÷&  € €@aÔ©SGÆ+¥¥¥)øæáÓ·jõj9£o_Y¿~}Òã¼ÚI¯W’¤ƒ € hz|Ý<ûÚ¶no_¥©1 €@Nøþ8ã]){ìÞ” ö;ëiÐéHçØU æË‡w^'{v9NZœrvJçGôß)eñûoIç[ ;¦ÖŸ@ }6ø6ܹŽÌø¨T®y}˜8ûm9}òíiUüŠƒÿ"÷3 ¥s†OZnš>Á9¶G³ƒäŸ§“ÉsÞK;O“Ùã' ’û$Gõ—_7ææO&oÞ@ ð–-[&ݺw/¼‚o+1Câ4Ü_Oy6Î6!€",~?詘 WmNku¸lþšœØüàÀSiÀ}ÎG¾œðJ Ð=¾¦’îÞ\³Í¯wíé%èõK—t(|íe=ó€­]:iâÍòâÜ#*õî9wË! [Ê#=.“©ß~šV/ª»77"Q>hðNÐë,I"€@ èñÝÖ<:<âµ {;AoÍ}ZJõ=ö tÃQ8ÈÀ‰Í;JÅ %¢AjtЫ%:ô‰«ä½…_Jív–£ö:0?…L’«î¿ßð/'èýrÙ÷²hõò$G³ (.‚èñÍù7¯M–-›7‰ö.ïÞ®“|x×õ¹È–<@ J`VÙŒ¨-"…2î×\ƒß .WwêÜÿþñK2ó¼ûƒZTÊ…x.@à»´íEC¸›7pƒGƒr,03àï‹s?p†: ïÜWš×jñMe9f gçÊw©R-¼@À‚|¿xêÑW¢¥rÍÚ̾‡í à©À”y˸ÏþÏ* 7²éË,3~˜ç uØúëQ&‹ÓúJ´,ÿu5³/$Âa; ‚c|S@â@À-pîK÷IÍ;zË‚•KÝ›¥ýÍdð)3«CDáù€X P=¾¹œÕÁ‚6§Š àÀÊßÖÊ^£¶ÏnæÔÕßtyá´ÄÌúhž^³ß'—³:˜#€¶ÐãkKKSOðL ÑtfšÁºß7HÛ1 îÁžá `@÷øîÞþPÑWºKÆM娇&¥{Zøø’J•å¡÷„?³‚D DOg½?Ï™Þüff’H'/÷±^ÖÁ.ë €@Pèñ jËP.@@O|=å$1@@  øµe( € €€§ãëiMI  B mëöQN ‰ Px¾…×f”¢hCà[ÔíKå@| 0Ô!Ÿúä € 3ßœQ“ € €@>|ó©OÞ € €9`ŒoΨÉR˜U6#æ0Æýư@ ß Ð8ü˜Iàë.)#€– 0ÔÁò/ÕG@l ðµ¥¥©' € `¹¯å_ª €Ø"@àkKKSO@@Àr_Ë¿T@°E€À×––¦ž € €€å¾–¨> € `‹¯--M=@@Ë|-ÿP}@@ÀžÜfKKgQÏ™£o“Ÿâ§rÍÚÒù–¤ÂŽ¥ám¬ €@a ìR¥šÌ<ï~i¼K=™8ûm9}òí)UàÝsî–C¶LxìðéOËMÓ'$ܯ;Üyëç“&Þ,/ÎýPWSZz4;Hþyê0©X¡D–ÿºZê/¿n\sîã' ’s<:f{ªÖý¾A}â*™µäkç”òênÒñÃ<ç¼›7™M¼#€@†ôøfWì§i€úÞˆ+åÕóNJôªÁO=àóÉ·Ê–?6'eùqÆ»òï§G½zÂúËåõ‹O•Eïÿ_ÒóÙ‰ÁÐàµÁεölÖAÚìÖÄ“ÂïÜW¶ MNl~pÊéM8ùš”óo¸sy®÷uNЛrˆ+@à[°Mç_Á¨Ér\öù'2õгdÝòŸâ¶jÁ|ùlìßãî35ˆ^ñõWæ#ï P@Wwê«îXI´ÕË%`Vó½ïÙ©´rÒ"hOñôþwHåŠüµ));("†:QczQ zË»7"©:û·“¶]+;„þ è^¢‡-lZ÷«L¿þépõH©Ùd_÷¡òÍk“e˶?Ó5êÚSZœrvxÿÆ5«eÚuçËæ ÂÛXAÂÐ^Óv»7(ðÅî!wð|Ü!nû= @7»‡ h0;¸S¯”‡PÔÞigyë¬Û“xùôáÎÐŒx剷íÜ—î}Å[Üà Òj¯îñò`d/@oö†E“‚ _Œ0\{ÛíÁg¥Ý%×ǽzPI¥ÊrÈÐ{¤ë=O†Ö+…Ï+{ì>ùã÷áÏ ÿ¶âgç³Ñûö:3¼OWJ«ï,ÇÜ?Qšô85b;ìhÛº½D¿ì”(œZߨ¹O¸×ôë?:×ÀóªŽ'gU‰)ó>–½G#ë7m½žÙ¸u¹½¸D.Y³ÂÉ·ýÍä©“®Š[ TÍØb÷9qf#oÑ4eöùbüèp¯«¨]F>”Ò g¸v½ûIùSýœBè˜Ý¹/$¿%^i÷éqZLOq¼ãØVÜmBoô«¸k\صÓá]íïTBo ;á™›ÂêqMÿ,¥%ÙýaqÍÆuá@6)½)­ë¸!á2œÖêpÑÀܽhOò™l½)Wƒ^w™ÝDZŽÅ'@à[|mšQ´·÷ç¯>sέXu'iqê_ãöò&J\{[õ¹@vØöCné¬ý¾º¯JÍZΩ:ø«Éã%Ãv(0³[.ðà¦Èœå å“ç;µÐW ~³Yª—V•ݪ×L+‰ïW/“S&”MÛn¸ÕäÌÍqÑ7³õyþ™¹dkyÓÊ„ƒ@  | ²Ù¼/ôÏ_}îí­ßñH©Z»nÚ™ÔhÜTêìׯ9O{}W}ÿM8½íŠ¿{óeyëÚóÂqø V@ àNÚ·£Sfí9Õ¡ ºÜùþ¤pÐyj¨Ç5ÓE{f¿¹ì‰ð0Šÿ[P–ò˜a-Ë5SŸg­7ÇuÝëÀˆ›Ùtª´t¦= 'Æ ¬@vƒ*ØjSðhµ?ýÞT¯M‡ðzº+»µ;$<ýÙ¯?ýº Añg_¾qÎLa–î<Àé–‡ã@À? L;Ôoîd0{Ùw¢/]Þ[ø¥,Z½Üé 6S›™¹kâü£7¯Í<ÿþ8{¶nÒa}ùo ÷ÇÛqï‡ÿ”–uötæÞÕô§ž92|˜Î{ۻφ?çs¥¼º3o>[‡¼‹M€ßbkÑ ë³fÑçLæPyçôþ¬èβjízážÝ5?,tï’ÝÛ*‡ÜÞ¯;u 3z#˜¬ÿ0+ô°”è—õ(8±yÇðfDš,¬üm­Lûîs§Ôf6†lª _ý{û¦ÜÛëÎKgaÐ@ܽh}ÄS׆ËëÞÇ:·oq·oàj§=¿Ç>4Iê†n`2‹öþ¾9øœ„s›ãx·C`f(ð~ÙQ󪥎•=c¿ÎN¡5œúí§Ч­¥3CÄÉQÜAuÔ®”>ö|f¸,X¹Ô9V‡dt{zhFAtJ™qZ€À7ÐÍ“ûÂé\¼ëWo (“Ü×-_ž¯·ú &Ñö¢!Òú¯W„÷k¾Ý3Œq¿aV¶@¯‡„ÇÞêMmÑø]ºÁÌÜä–ÊÔf¶3Pv~¬ór÷Ò¾pÚ á›Ó2QÑèÎO^ãâz3[yÃ.2É#›s¢ën ÌûA^Nït6Àœ‹€K€À×…aóªŽÍ5‹ŽÍÍtYòÉ{áSwª»{x=ÞŠ}pÏœé4hñÒfø' S˜]Ò¾G8óXa}´°ûeæÉÕÓÚìÐ'®’'>}#œÇ#=.+wßðÁqV4¯2ânf‹cÃ&l 𵩵“ÔÕ=6wþ”g3êyÕÇ/ûb–“Kªc…uà.#Ç„€áž-IqÙ…yЀ¶ÁεÓ*A&S›éø\üj¯ñc=/O+OF¢|£E,ý=Ù¬1wÉ–ms`¦B¢Og›=ááð0‡t¦DÓà·Ö¾8ÙlZ¿NÖ¯Z™J–ƒy¸ºSïðMmé!“©Í®zãÑðø\}…™7|90Lgf$xkW{l·lÞ$ú ‰i×](oy Ü§·éÃ/¦]w~x`}Ôqó“¶?)Iƒâ²'þ&†ÆôVرi(`½©­ÝîM¤2Í–?oà£ÎxàT§6sóèøÜË^Xþyê0'ØÖ!z#]ô˜b÷9¬#€‰èñM$cáv3×®©º™k÷“nÛû«ï¿ž&o^Ù?ôê¹­ÿ:(&Àýí—åòúŧJ¼´þ;ebxîßšMö•*»n}Ê›)ï }üoåŠ[Me¶[û/¦;Ètj3}ÅG‹ç:i¤r£\p´( M€ß µHžË£7œéRöؽá’hïïkô N´¢ãz¹þž¤O}+/­ºvHëQɉÊÂvð^@ojëÒh'áxS˜%ÊQ§6Ó©Ï4`>²qkç&µt{lû<g¸çX‡Zh0´ÙÕŸí z|ƒÓ)Iôl ©¬Îþíä¨{ŸJô–—N£®=¥A§#Ë;Œý '³[í“Æ€þ—ÄlËtƒ^Ÿ¦u¢§0S?ÎC º¼¿É“ë“©{ýÆÎt~CféÒµë–À&À¡Ç7ÀCÑ@@¼ ðõÎ’”@@,@ààÆ¡h € €Þ 0ÐÍ;KRBÚ¶nïA*$ €@¬o¬ [@ m|ó¨OÖ €@q 0Ô¡¸Û—Ú!€ €l ðå«€ € `…¯ÍL%@@ãËw%0«lFLy÷CÂ@ |3@ãðO`&¯¸¤ŒX.ÀPË¿T@°E€À×––¦ž € €€å¾–¨> € `‹¯--M=@@Ë|-ÿP}@@À_[Zšz"€ €– øZþ ú € €€-¾¶´4õD@, ðµü @õ@@[|miiê‰ €X.@àkù€ê#€ €¶øÚÒÒÔ@°\€À×ò/ÕG@l¨hKE©'†@ÛÖí £ ”@ à| ®É(0Å-ІÀ·¸˜Ú!€y`¨CñÉ@@ w¾¹³&'@@< øæŸ¬@@r'ÀßÜY“¤ 0«lFÌQŒû!a €@¾ q ø'0“À×?\RF,`¨ƒå_ª €Ø"@àkKKSO@@Àr_Ë¿T@°E€À×––¦ž € €€å¾–¨> € `‹¯--M=@@Ë|-ÿP}@@À_[Zšz"€ €– øZþ ú € €€-¾¶´4õD@, ðµü @õ@@[|miiê‰ €X.@àkù€ê#€ €¶T´¥¢Ô C mëö…QPJ‰ Pp¾×dâhCà[Ü Lí@< øøV©º“¼zÞIy¬Y#€@®ôÿ}!,•*W–.ï¯/„¢RFðH@ÿß³  ;„^[/XŽ € €@ õ×Ö£4† ÌÒ¥k×-)L€ ÂÍmnІ € à€/C¼+)!€€m³ÊfÄT™q¿1$l@È@€À74NAÿføú‡KÊ €€å u°ü @õ@@[|miiê‰ €X.@àkù€ê#€ €¶øÚÒÒÔ@°\€À×ò/ÕG@l ðµ¥¥©' € `¹¯å_ª €Ø"@àkKKSO@@Àr_Ë¿T@°E€À×––¦ž € €€å¾–¨> € `‹¯--M=@@Ë|-ÿP}@@ÀжT”z"€@a´mݾ0 J)@ N€À·àšŒ#PÜm|‹»© G†:䟬@@r'@à›;krB@È£oñÉ@@ wŒñÍ59!€@ ³ÊfÄŸß6 €d @à›§ €€3 |ýÃ%e@Àr†:Xþ ú € €€-¾¶´4õD@, ðµü @õ@@[|miiê‰ €X.@àkù€ê#€ €¶øÚÒÒÔ@°\€À×ò/ÕG@l ðµ¥¥©' € `¹¯å_ª €Ø"@àkKKSO@@Àr_Ë¿T@°E€À×––¦ž € €€å¾–¨> € `‹@E[*J=@ 0Ú¶n_¥” €'@à[pMF(n6¾ÅÝÀÔÈ£CòˆOÖ € €¹ ðÍ59!€ €äQÀ—¡W ½R–ÿôc«EÖ kÚuw—{GÜ“ëlÓÎoаAòóÒ¥iŸÇ  P¸µêÕ“ûn¹¯p+@É=ð%ðÕ wfÓC<+$ !€@ðÚÎÏ“BÎ*›“Ž—ã~5èÖÉ—K_L¹Ù€Áèò>¿ì£%ò_ ®þùoJ€.™>¾®¬XE°L€1¾–58ÕE@l ðµµå©7 € `™¯e Nu@@[|mmyê €X&@àkYƒS]@@ÀV_[[žz#€ €– øZÖàT@°U€À×Ö–§Þ € €€e¾–58ÕE@lô“Û.9ò`¹õä£Sj›Û^™.·¿ò¶sì±ûí#OŸª¼4kŽœóÄó)¯=з§ôëx`Äñît#vð¬¸âà¿È=Ç H©îç?-7MŸàÛ£ÙAòÏS‡Éä9ïÉé“oOé|=èñÉ9n¿.ÿuµ4Õ_~ݸ>å48@`«=¾Û¾ ¯_yvLЫ»†tï,o]ýW)­X²íHÞ@ÿv©RM¾½llDЫ¹ÖÞigY{Ý rbóƒý/9 €E&è_cíw¯«ö,¼wCùmãïrÌ=cå³EKœ¬MÏqÛF{ÈÇîQ6åâìp÷æú¡pv룥ñ.õ$º‡×ô?Òã2™úí§ôüúOš P´Ö÷øÖ¨ZYÎëÜ>&èÕí‹ÿJß1Ïʦ?þ£[6¥×·hÿP1‚% ½½—´ï!ë~ß ÝžÜžûÒ}òÞÂ/e§ÒÊÒl×úÁ*8¥A.P=¾~V«\Iêþ©š¬Ý°QæÿôsLV_üð“lÚüGÌv6 €€?m[·÷'áJuåoke¯QgÇ-±Å{Tß5î>6"€$°>ð]¼bµÔ½ìÖ„JûíQW*–Tï~^)7mNx;@À6¾I!_>}¸3bâì·eÖ’¯“ËN@H‚|õ3}%Z~^»Nöú7Y£ëå¢Ã î8åXYµn½\òôË^&MZ PàÃ;÷}%Z¢Çæ&:.•ífFˆŠ¶Þdë÷øâTÊÄ1 €@! X?Æ7Y£M¼ðtÙs×rÙ„)žÕÉòe L@îüMJK ¢ï"YU؇äT  ®š~Ïê-®=½ï 9ß zû„nnû×gs£á3X.Ë^×)ó>–o>>,þî9wË! [ÊS']•ÖœÀáXA,(ˆÀ7—mc¦0û=4ž÷°Û Om–Ë26 Ì*›S}ÆýF’ôyþN™7ðQ9²qkgvféÃ'@ ‘¯KÆ<)næw?H·{Çr3›Ë†Ur%0“À·\ê5×É’5+¤Zi•rå@íŒñÝf¡+ÖÇ#?ÿÉl9âÎÇz·GXC 4ܹŽü6ô%Y6x¢Ó£}õÒª²[õš²`ÕRù}ó¦èÝ|FH @à‚ÑžÞ~t‚Þsžx>›@Ü,\½L>ùq¾óxâÇz^‘©Îã;½ÿR¹b©¼:ÿ?²‘À7‡ €@2‚êPÞtfZÁxÃNn×Jô•hÑ×ÊB'ÖóçdÇÇK?QºlGâ(o:3˜ñÃ<9ô‰«"‚ÓÓZ.úJ´œ4ñfùÿöîNŠâ^àxE®D¼P‰TV6 ˆcŒ"ϛɋ(DQÄ'Šâ ‚D#> x_øIF%AP¼P#Š "ˆœšù×Zšžž™î™ÙÝž©_>ËÌtWWW}kbþûßêêGÞ^ úÎ¥ª.™¬Ë•—u|oœ÷@ºjØ  à|Æ÷§Se Š"þ>v!€@© ˜§·ÍX<7¥‹÷ÿóM)ûÙ Y Öß”¿,Pòu{zé;ªùàÑ¡OËå¡+§ ””À„s”üDÝüK’…=ÿÞ®ä‡ @ ç3¾ùR € €@1øÃ(ÑF@@¼|ó&¤@@b ð-†Q¢ € €y øæMH € €Å @à[ £D@@ò ðÍ› @@ŠA€À·F‰6"€ €ä-ëXäÝ;*@¢¨(¯,º6Ó`@â ð-Žq¢•8#ЉÀ×™±¦£ €@m 0Õ¡¶Å¹ € €@øÖ ;E@¨mßÚçz € €u"Àß:aç¢ N`Ñ’…)‡˜÷›BÂ@|s@ã¨9*ߚåf@Àq¦:8þ û € €€+¾®Œ4ýD@ ðuü @÷@@W|]iú‰ €8.ÀÍmúìÞ¤L=?bjÝ|wõéÆMêˆë&ªM[·e­½åMUÕ ƒUYƒúªêƒUê” ¿W[·ïÈz@8 4k¼‹ªºd²jÓl_õÇ×ç«þ¾)Tóþ>àVuL«öiËŽš7SÝ8ï´Çå€}mù|ÆÿW=òöyjëÓîÇjN¿‘ªþNõÔº¯¿Pm&]¤¾Þº9åÜ{NÿбWÊþ°;6mÛ¢Ž1L-Zóž>%[ßM½ W-ÓçmݱÝìâr ã›#§Õ®ÀOŽø‘Z?e¤úxâµêÈZÔîŹdàõ€¦{ér}Û­:µh›õœ0Fu?O}7êiõÓCº„)®ËMÏa]Ï [E`¹Ç—ýS4i€Ú¼}«>~b›ò¬Y\ "×|õ™._¹;ußÃë–@ÕÌ-¶Ï ,ÌN(ß’J:‚Ô¾€Lèq`}a¹1ìôY7zjïƒ;«†õòûÃâW[7yl˜ÞÉMi=ÿ0ÂkÃ9‡¯$0·7É$_pä‰z—½v›ír¼GÒ ð-½1¥G €@­ \\ÞË›.pçË«7×­P¯¬~W__2®üæ³íÚ°‰j±ë‘ªøð‹µêì‡ÆªíßV¯#7È™›ãü7³;{¼ªZSÝÞH¡0¥@~¿Še—ãßh{i´oK¢|Ûïÿ¼/+ÌÔOßôe–B;ñЃ¼}A= »ÔÚ໨ߞ™¼l¹†¹5»ãžœ§nzr¾²Ï·¯ùÌ•«.µRaû5û•×Õ€³“ê;wêŸÔ‰9¿f³—„3ûìkš}ö«mlïO×G)¥Ÿv¼G ”Î8´«îždNej‚l7¿ø:º¥ÜZOõKd\£,-¦+øþ{ޝìúËò%¡ç K[†?7CÝvò@]›Ü'™Ý»û\îMË¥Ò¤m’µfC7|k`œ÷Ü¥‰Z“Xv+×íóM›ÕðŸÖ¬¬b0䤮:øó×7¤W7ôÊþ Ͼjý_Ó¶t^º€P®QqàþjÝ×)à)ÇìmÊy}Õù];z»äšO ½P¯QúbΛ¥ÍÌÚµr61íñ ÌQí÷n­×Þ•úŸ»`¬WLÖÆ÷÷?yŸëòM¶¾³Žo]Ž×.5ß˜Ž¨ÜÌõòò•:;Ú»C;½v­}S—d9;¶ÚO·^‚عo¤þ©.(x3W ðž¹ââ¤føƒ^;h´M¿øgi³Ðý*;¨Ý—©‰›ÐäÒο'ìñ›YOêÀ|Á¿V¨U¾Ôú8þª&‰ÀÞ~Ї²Û´Ôýzêµe™n{ÈLðogí¶Úe彬úƒ;s<âÔîúTÉ^mÙútû T”W†+H©:øé!]½%Ì$ˆ4XØðÍFõ·^ÓoÔÕ‚:•Oà'«0ü¨ùþÞlR¿Ñ'Üw×Þ k²JS€9¾1WÉŽnÿö[/;j7õšÞÇ맽ɾ°Ù^){JbÚÄý/-–·:ƒ{ÅÉÇè÷òÏy]:ê€TÞÛA¯|–,ôq㦪ר)#[‹¦»ªŸMžé³+?K<骛½Vê¹{ÞB]V2¤—'²ÙöfÖë “íµÏû:d¿ûɧz—\£ÃÈIêfϵ‹è© ²$šl2…â„›§'eÉ¥­û ù­’à\¶¡'uKû°ŒlýÔðON¯ÿ'§Š8©Fd®ìÑ]_CÉçÞ¯þ¨¿l¹žÆ”­•k„ÉÒÎ\°X]Ò½R_àñ•êŽÄt“6ýzsõZõÖšµv³ß¿÷Éz— z阡IŠžò—äG–šì°ŒÏà™Ö';ÃLÇÓÏ´à% ðóÃŽñæÊÊMmþGü®HÜ`&7¹É’afi³L–€4Ýã|>çúÈ!¶‰%ÝýÞájÙeÓ”ÜÌ–mÚ…}nm¼÷÷½6®É5pU€À7æ#ÿÄ’·u`gÏõµ³½2Å!ê|R `W^=Ý õžÍô<á&M¨ývßMk˜y®™hvNLQ8xŸ=½L®)ûÎ÷YWó9èÕd}åæ9 XOHÜ'7«Ùý ›Å¶ƒx©KæVû§0Hdúƒé߇ŸnЙô ¶É>{:Æ Ÿ†õ륇égºúÙ@± ÈÍ`ƒ+ûxÝUä'Ó&«;DÉÜJl?âî>CtVÙ`gº¦}LñÆcN·wñ`ªCÌ]²£2½@6™ëÛ'‘•5YQÉ\J¶4—M2¥ö¶KY#µÏnµwgó#‹ßT›·m×Méí½‡×¯tg»½æ½™Ö`¦oÈ~¸Ÿ–x̱Ùìþ}|3ý²`~1sÍ/¦^@@é,îM÷ŠD‘ËÒf2?wÆâê)K’5žÞwh¤kRð ñõ‹Ä쳕¬ïÌKúy-œ6¡7—ÖÛòMÛ}š'•ܸy‹úäËzúAPÆ4©p>È|Ú‡^^ª§MH :þ¬Ÿä4gÙ4E¦.Hö÷ùÄt­›ï®wÛ7áÙýK—Å5uEÉ›sx-œÀ¢%ÕsÀíeÎ/[|®îv–wS[”Vå²´Ù°¹Ó”< £M³}•<ŒâO¯ÏÏyy´(m¥,”¦oŒ«='Ö47Ÿl¯Ì6+B˜?ûoÚ´-eúÃVU½ø»¹f¡_ozj¾Îò–5¨¯NjßVW/ýúë[ÿÊéR&ûkÖ–_nïª^¹Âdq%(6YÜtý‹’Ω¡œ”Q ŠÀ7£O]”›ÚŽÚï`ÝŒ0«-Hy™[[V¿¡ »´™ÝG™Ÿ;ä™ÿSsúÔÁv¾Sìºyî 0Õ¡ÆÜd}í¦æ“í•L¨›²Ùsie>±l2WV–ýʴͼäl½Y¦2ÙŽIÖwñŠÕIÅ¢ôK2³÷ 8SÏÁµ+‘›ÚÌÊ &È•ãf•Œlý³}æT½aWÍ{œÇÿJ+[˜9»2·öÿ—ÎÓåÍÒfúC„äaÿXYýß's£\„Ó)Šx¾E¼ßØs}Ãf{eÅY'×l(¾6zˆ¾YNöÉ’^öÐì€ñÌ£W½ú—)A¥dS¿øÝ ªKÛÖ¦Ú¼^M0*•„í—}AYóWªqÍ©Ç{»íµ€MF[Ê*³þñª.Ô¿l>Þxƒ€£rS›L;-h ³t,…XÚìÜÙ7{Ë£ÉT‹N-ªÿJ”îšìG‚˜ê¤Ã}ö»óß~?ÔÜ^³ÊAPwdï¯þðHÊ¡sîšåÍ“57‰¥*à{ɶ°ý º¼³Œ™jç†eQN×eåF7ó Y%â¾3†E®ƒ@Àm$ºÿÝÊåë ªpþÀþªêàÿ<¬ •;X™¹YKº.Ó̘VAþÌ?sP?½6/YË´L¨Šw_P÷O›•wÍÓî’RÇÀ‹§ìËu‡ü÷éoÝøcW®~œ‡@1 ôxq{AþûdúÞ²^ÎOb¨Øl=zöü.6‰qCÈøÆxpLÓÌÕ¢d{͹¼"€ €T øÆü›`ߨÅcrc>X4@b-@àëáQjH¯nzÚÙÞ˜ÍC@Ø øÆxˆÈöÆxph €oŒ‡Ìd{¥‰ € àŠ¯+#M?@@Ç|ÿÐ}@@À_WFš~"€ €Ž ø:þ û € €€+¾®Œ4ýD@ ðuü @÷@@W|]iú‰ €8.@àëø€î#€ €®Ôw¥£ôŠC ¢¼²8J+@ŠN€À·è†Œ#PÚ|K{€é P‡Lu¨C|. € P{¾µgÍ•@@êP€À·ñ¹4 € €@í 0Ç·ö¬¹„X´daJ)æý¦°@ ßÐ8jN ŠÀ·æp©p\€©Žè> € àŠ¯+#M?@@Ç|ÿÐ}@@À_WFš~"€ €Ž ø:þ û € €€+¾®Œ4ýD@ ðuü @÷@@W|]iú‰ €8.@àëø€î#€ €®øº2Òô@p\€À×ñ/ÝG@\¨_mTÖXU¼ûBMTM Sùß}1lÊÊT7CSi#H@þwφ€ÔHà;}ò t@X LŸüûX¶‹F!€Ô¼@¾5ßl®€¥*PQ^Yª]£_ €u,@à[ÇÀå@ Y o2Ÿ@ &ÀÍm£¤"@@8 øÆyth € €@Á| FIE € €q`ŽoœG‡¶!à À¢% Szͼßv €ä @à›§ €@Í TøÖ.5#€Ž 0ÕÁñ/ÝG@\ ðue¤é' € ฯã_º €¸"@àëÊHÓO@@Àq_Ç¿t@pE à«:lÙ²E¹y”ú`Åêºá£T»¶íjÍÒ\û«Õ-c&¨ ¨ _R¿›6YýâÂAªû1Ýk¥-ÒŽ _TÝ=Á»^]´Ã»¸õÆ´ÃÚ•ò¶c‡NjÈ¥W¨z;ÕK9Æ@@ X žñ]¹ú#õѪ•ÚãɧS;¾ÝQ¬69µû_ËßSƒ†üR­Z³*§óãpÒâש+G UÛ¶m‹Csh € P‚g|êQÕ¨Q#Õt·½Õ²÷–©õë׫½÷Ú» Í¥’.•]•üÔõ—v‡tp“5—ŒýƒÿQ{öùæ^@@¢(hÆ÷˯¾T¯¿µTOoèÛûtµiÓ×êÍeo5k—_Z®:BÿòòrÕB²¾®}è/ €%,PÐŒïo½®$cØ©cgÕáðr<=òølÕíÇÝô|[ãh²Šf.îwß¡ª–¼¢7ßcOo~®ìˆRÖÔo¿š9­AΉwÞæ]WÎ *#ûM$ joþ¶ÎyìÏêáDe{æ¹§ô©3S;Ì1»î ùÑÒÞ·ÞyK¼úz5uÆ]zµ9'¨¼9õµQÃFªÅ>-”ŒÙ¤oÏ¿8?1oûuÍõôI“&;«Ñ×õ2úaûaê ë/åe Éèñ7ª;¶›ÓÓÎ!j‡ïäïßD)+§•÷Û‡±ò·ƒÏ € PóÍøþóåJ‚¡ÃÚ¦vÛu7uø¡G¨õŸ}ªÞÿðý´=™ýèCIÁ§”<ì¿ÕÚukSΉR6ådk‡²#GHº®¾ç¾©jÞ ó¬’Õ—ÌÙõ½R(S[“*IóÁ´Cn¾óocÆRY£Zµl¥vª—ü¹çÓtÐ+Õȋ͛7Yâ•êIDATןÅ3l?L¿Í/;¦IAþrLäQcG&½²?ÈH‚ΠvHÝbdÏ9RÖ´9¨î vHû‚¬d? €Ô@Á2¾’‘[²t‰êоƒ†¤;?îÜE—r“[Û€U$p|òÙÇ“2w& øÜßžMš_¥l6J¹¦²vÆÖdg=4Sîf^²ÌY–,£?c(Ó:®q¹7CÊÿ¬ïÏÕ‘G”ëÌäI'ôJjP›L;ü™SÓÉï¿ß)«QØå% 3«høÍ‚®™mŸé—Ô+™{{eƒo6£n;ÉËòJ}>û°ö´Û%ûÓõÃô;Œ¿dX%@¶ËJݦßbtT§J„KÛŸšû„þåËÎD›²öœó(eåz¦Íaû˜ÎJêbC@ºHNçåцWA¯ˆv°ÔþÐÃõtpU/¥½äÙ€ ¦_¥lеdŸA‹_­ÒÁѵÃFzS0jÓVÍKzé•êþi³R‚OÉh÷îuZºËdÝo·ÃÒäDiËÈÄ”‚zõê«E‹_NÊRÊñþgçž2'·÷É}dw¤M2 çìŸòs郴‘š2EÅ¿Ù×–cQûa—ãoþŠ`—•ëÚs‘_Y´Pv¥Ý¤ìè‘ãÔÔIÓ=·t…ƒÊÚmŽ2V~«t×d? €ÔŽ@A2¾&0&K@%?ÉÛ}“›É¢šc’=“iöf¦HÈ\Ö ŸoH¬ÑTŽRÖ®ÏÿÞüÿ°ví½Ì´)#[ùÉ´I_M†5S¹lÇ2µCÎm™Èô°Kµbå õíŽo½Ìkƒ¸J\¨ÍŸÝ¶ëm±o û£ŠÚLåýþb-™S¹IòÊk‡$]×þðÉ'ë_ÌwG2Ävù þD)›©ÍÒÿX™¶ù­Ì~^3 T”Wf.ÀQ@r(H´´(‘A šk·)è&7û¸ý¾Õ­õŸ·7|ñŸÀ×>n¿RÖ>/ìûBºa¯ç/'S äÿ/ þrQ?ƒQëˆRÞô£¬¬,ôi&àÌv‚ýËdèÍtsžùeÌ?]"JYSW¦WÓÇLe8–] ov$J €ä$PÀWþ-[P0eŽr“›=­!]‹W|ô¡žŠÐ¬i³tE¼ýQÊz'Exs×ô)IA½}¿ÜeVqˆPe¤¢Ë«f»gwˆTi6ýà0ìf¯.ažÄæ\ he³¿{òY²Çþµ‰£”•:2m¦™Êp @êN ï9¾r“¬Ý›nN¨Ì™ìxd…î¡.fÐ:¿¦>¥l&NLÍ;–›±.úÕùÞj ¦-òß{§ÎÔs}Mà.A•ÌÎuËÔ©Ó</he…\¯YçEíG¦ò~ùîÈ÷JÖL+ƒ¤ë—™¯+s´ïœ0UÏ 6Ó"üçd*›©ÍRO±Œ•¿Ï|F@À5¼_³voçŠJïF1?bϽtÐ!ëÀú—)“UÌ> &o™8Ngê‚ê‹RÖßóÙâH½u´÷€¹ö½3ïÑ7èÉ*öæ’% ¾ôÊAI™`»|˜÷v;F޹Ö3sÍjþ›ÃÔ[Ûe¢öÃ.Æ_V‘M– “q°7É¸Ë zfÙ78~™7®¦¼ùžšÏQÊÚm.æ±2}ç@Wòšê ÁâS‰¥Á䆫“zœœÖо‘HžäÖåû`FΓ›×쑤Éò}Æ9IõE)›tbÀ‡S« H¶Væ%øõI%$»Ûö‡mõ>»Ýþ6Ú'­Zý‘ýQ¿÷?À"¥@b‡ÜÌ%S5ü7c™²Ò–c»k>Æö5j?ÂúK‡åQÏ2•FŒ$øõoöwEVÃ(O,''eýã*çÉwè¼s.Ô7 F)+çFí£œÃ–›À¢%©«t0ï77KÎBHÈ+ãkþÄkd\uò§>‰G-Ï5ìò᪢ü(¯°{·›˜=ŽRÖ«0àdðdy+ûºR씓z«+.»Ê[AAöÉP9Ù/ó™G];Z÷Éþó¹YMÊÈW©þWêÿõÀËì]ú½Ì%ö·%¥PŒvDéGébººe¼&ŽŸœô]IWV¾W¿»}jÒM‚QÊfjG±UŒ¾6M©J¾þŸÀ‚ìD@ ¢Àå¿[¹|]ÄÓò+.™bYlí§ë’yTk”²A糊K`Ú½SR<ð¢Á)ûØÔ•@Ë6{É¥%†ŠÍÖ£gÏïbÓ˜7$¯ŒoŒûEÓ@@H ðMâà € €@© ø–êÈÒ/@@$¼VuHª)ÂssS˜S¢” Se@@Ü ãëæ¸Ók@@À9_熜#€ €n øº9îô@pN€À×¹!§Ã € €€›¾nŽ;½F@œ ðunÈé0 € য›ãN¯@@ç|r:Œ €¸)P'°p“š^#€@ŠòÊ0Å(ƒ ,°1ñq—ä]|ò lüAýúõ¿Ú¾};P>>"€ €A‰Øic"vÚ5èû@@@@@@ 6þ ©kn(ì+ÅÀIEND®B`‚trusted-firmware-a-2.2/docs/resources/diagrams/secure_sw_stack_tos.png000066400000000000000000001026321355360272700264250ustar00rootroot00000000000000‰PNG  IHDR¿É½bK2sRGB®Îé pHYsgŸÒR@IDATxìÝœEúðñGI‰d ˆº·‚áÅpþÅ,Êé)fÅpŠ‚bÂ8D=Q0á œ§wø Äãd] QN$ƒï<ÕöÌôÌNꙞ©_>ËÌt¨®ú>Kï³µÕÕÛÞ¯ßÜuë×w@ :µkÏ{ýµ×:fQDÞ店7jN„@É „ñš×«wï¹prºäßuójjâûЃ&ß­ €@5ç^pAÑ\p¹îUL6#€@µ!½æÍu¸ZààvèP#¸²)@@p ü†+Ô@@ @’ßq)@@ \$¿áеA@P€ä7@\ŠF@—Éo¸âAm@@ ù —¢@@Â%@ò®xP@@H~Ä¥h@@p ü†+Ô@@ @’ßq)@@ \$¿áеA@P€ä7@\ŠF@—Éo¸âAm@@ ù —¢@@Â%@ò®xP@@H~Ä¥h@@p ü†+Ô@@ @’ßq)@@ \$¿áеA@P€ä7@\ŠF@—Éo¸âAm@@ ù —¢@@Â%@ò®xP@@H~Ä¥h@@p ü†+Ô@@ @’ßq)@@ \$¿áеA@P€ä7@\ŠF@—Éo¸âAm@@ ù —¢@@Â%@ò®xP@@H~Ä¥h@@p ü†+Ô@@ @’ßq)@@ \$¿áеA@P€ä7@\ŠF@—Éo¸âAm@@ ù —¢@@Â%@ò®xP@@H~Ä¥h@@p ü†+Ô@@ @’ßq)@@ \$¿áеA@P€ä7@\ŠF@—Éo¸âAm@@ ù —¢@@Â%@ò®xP@@H~Ä¥h@@p ü†+Ô@@ @’ßq)@@ \$¿áеA@P€ä7@\ŠF@—Éo¸âAm@@ ù —¢@@Â%@ò®xP@@H~Ä¥h@@p ü†+Ô@@ @’ßq)@@ \$¿áеA@P€ä7@\ŠF@—Éo¸âAm@@ ù —¢@@Â%@ò®xP@@jUöúõëåî{ï•ù $=Å—]&vÙ%jŸÿ~ø¡üuìXgßö¨süaÂk¯Ékÿü§[ê€ÓN“zôp?Ûú&ÖÅëïyÏ]Lï}_'Z_Lm³½®\ïJë;€ë]öñLt]K´>û3R© –ü¦Z…»î¹G5j$7\wl»í¶©È~£ÇŒ‘HÙÅZh*&C]ÂÇbµ¦Þ¥/Àõ.Ü1æzîøP;r%Ša+V¬ëo¼Q6nܘ«v¥]Žþ6j_íí}èÁ/[{}¿úúk¹àâ‹]“T@ÃÇTêÉ>R ÿO¸ÞEp½‹öà¥.—žßD=‚Þ?è„i‘´PÉæ‡Ó§;±ÖºVtëVêqOÚ>ýA =T›7ov÷KCÝ!ÙŸÝxƒ€%‰þ¯p½ ç7×»pÆ…Z!¤@^’ßD øí/I¦ß»hÑ¢D»f½þÝ÷Þ“îûíç;´BÇëýðÃÎ9ö-/÷Ý'ë I?þø£Ü;r¤›ø&úAîmÎQýú‰~é±÷ÜwŸwShÞ'‹h*IEJZ€ë]øÂËõ.|1¡FäC àÃvßm7©U«V mÕžÉ×ÿõ¯„çØ°aƒ,Yº4áv›6L~çQ]RI|½6 4ë‡ Ý/ÕÅßÛÞ#¤×» uÓ/›ë]úf@)<ùóÙgn²(’O]U{A&¾ù¦s@ݺuå²K. ]"›zk¶îIüÓcÿ ¸Þ©›^Ù\ïÒóboJI  Ã¼càU‡T·ø%3¿?ä9þ¸ãâõÞ¹«cŠ/ºôÒ¨}.¾àyùÕW£¦cûo½%úµ÷^{ɹçœ#5jüúûA¢éŒüö5'òŽ'3Ó¦yÛíí]õ®×éÚ7k&×FfÁ0=±š^{õÕÒ¤I§x½x'Ûnêê«÷óþ‘éÝÌyR=¾ºýrå竞3Óø›)ÚÒ‰‘ic&m1ÇfòêýÞ0Ç'ú¾Ë¤=¦L^ƒˆ!×»è)-¹Þ‰øýßåz·õÿ$×»à®M6–œ—ä×/ñŒÅÖoìÛ·]í~ŽMôÜ ‘7š¬~TU5]Zìû&ïý’nSÎÇ3gÊù]$&¹5ëý^cËQ›GþúW'Ñöîÿ÷—^’/¿úÊ»JÖ®]+C¯¿Þ9çXw4ÛMRup ¼C?RùÁœB‘î.±ív7DÞ¤ê÷¿ÿýO.<ØýeÀ”‘ëøÇÖÕ#ýe(v»©‡¾¦Úï1ÉÞ'J²½çª.Þ±õmO²ó³-}õýE;¶®wçD‘p½‹âp>p½‹61×V®wÑ.|ÊL /ÉouUÓÞϳÏ:+ª—5Ñ1ÞžRÝÇü`×8ÞÙ"Î4È)Â$Á±Ç™ò;uêäܨezPýzÍ9ô˜Øß>½Iùø'ŸtŠM4cÅ”)SdåªUrä¦0ÓXqûírBÿþqm×Ä×›L{{Ìy¼uõnìñÇ£~0m­îuáÂ…Î.ÚÃÜpûí«Û=åí¹ò{%ÒKGS¶Æ_{ñÍ_Rl#ª‹‘9Ÿ—Í÷Bìyý>Ç&¾Þ‹¾wÛƒ£GGýEÀ[VuíñîËûüp½ãz§Í3×ñD?/¸Þýú,®wù¹6Ùt–_ÿ¦_€Vk’uó 7Ȉ›nJilé€SOÛ÷ÐÞ½¥m›6Níg̘![¶lÉiK4©|ã—›å4Ù<ÿÜs£U½Éë/‘'Ùí³÷ÞÎy_xñEùî»ï|ë°xÉ’¨q´zì­7ßì;¼@ïE±}»vÒ÷°ÃÜru»Iôt¥w»ö¯Š$ÙaXré§É¦~¿x†â¿öþg;Wt²å²-©ÄF{:̽‰¯[»vm¹<Ò ®ßûïIo¿í[d²öøÀÊÀ¸Þq½Kçç×»_ŸüÊõ.°Ë’µç%ùÕžíí4Ž0¯÷Þu—oâç ½h˜©‚ü¶µN_ïVÛð‡£NxMLËÊÊ’&"ÙŽ£mѼyÂóë†Î{îéÖA{˜Ó]Z·ní¢ÉT&Çû/—~ûì³OÔ/z>½(îIŠuÉEÒŸ,F¹l‹Sájþ1sOëA¿!AÞ¶'Jü“µ§šÓ³9C®w[á²ýÞãzÇõÎû_ëWƒ÷Ù „bØC¦ðþ©?Ó2’§j1óÿ¶ÞqG'±L´«–-eÇV­œžºåË—;=ÐÞ›åô¸V‘íùZ–.[&vùõ7çTÎëýa£ÉTºÇÇž#×~±åñ9QŒòÝïùÌX·dí5‰ìMŠ‰Ú“¬,¶…S€ë]â¸p½Kl“lK¢ëƒ÷ú“‹Ÿ}Éê Û¼çãzWÛs!Ptɯþ'¹;2ÌÀü98‰ÊðÎÿÛ´iÓ¸^Gïqú[é;ìàÔká·ß:½Å±É¯wÿ0¾7sj»ßŸ:Uz|pÊ=ó~í)%¿|·Å{>?[ÖÙ!Àõ.¸8s½Klë½þäãgŸ÷|‰kÅr'PTÉoìTA:÷è# ,Ö‡oho¨&Ú‰zsM(¼¿¹V÷›²9&l¯:´dÝw—ì !xî…â¦{K§Î¥ä—ï¶xÏ{c]:1`ßâàzlì¸Þ%öõ^òñ³Ï{>®w‰ãÂ–Ü äeÌo.ª«3#Œê)§(ýÏ1êþû£nøÊÅ9bË0½¹ºÞôæÆîc>{s­î7esL_O;å÷‰{úç'Z-›ÈÆïÞðWJ~ùnK:ç ã÷uÊN€ë]v~©ÍõÎ_*ëO.~ö¥s>ÿ³ôŠ&ùýîûï¡Ú¼CûôI:ÁK`nâò®Kç½¹‘ÍL¥•èØ'Ÿ~Ú6×sä&:gëµ7DgÕ0‹™³ôšÈc‹%ÁÚCunä!úõQdÆ ïRh¿lã_ȶtëÚÕ9}uß{ºÓßž>a|¼mà}qp½ËOœ¸Þ%vÎ÷µ›ë]âX°%÷E“üz›þï‰Ý)ͼÓAé>:üà½È|ºf17qi¡ó›E÷{èᇫM¼SˆéÃF=ô{n-KËqÛmÎPý¬C1²½QLË)䢳jœõÇ?FUÁ$Á&Éõ¾þuìØ¨}½ í—mü Ùƒ™BÏï{Oëf~ñС*,¥)Àõ.ظr½ó÷Í÷µ›ëXŒ@ÑŒùõΦènP]?øŠ+œÔpé UÇíê¤âfbqÝ®S¥²Õ¯Ÿ³›>Q-ѹuïC)R)7Ìûè…Ho1ÿHµ®œw^ÜMr…ôËEü½mÏw[Î8ÐÓžì{Ï[GÞ¿×»üÆë¿7×;Ö¿@Ñôüê˜ 3©¿a7c½½”Þ§žé~zÜ5W_íö ™cõµßGD=0Á»-ö½^FÞsû@ ïvSïC)¼Û‹õ½þIPà¡ó2›H¿¶˜öë~‰z½ å—«ø{Û϶˜ú_u啾Sí™9eS}PŒ·¼¯×»üdžë¿9×;Ö·À6½z÷þY“@  3éÍ7·É¦Œ|Ëu/_ÒœÒã5O¯m¥+ž»–MÏoîšLI € €¶ üÚyÚ €X(@òkaÐi2 € `«É¯­‘§Ý € €€…$¿&#€ €¶ üÚyÚ €X(@òkaÐi2 € `«É¯­‘§Ý € €€…$¿&#€ €¶ üÚyÚ €X(@òkaÐi2 € `«É¯­‘§Ý € €€…$¿&#€ €¶ üÚyÚ €X(@òkaÐi2 € `«É¯­‘§Ý € €€…$¿&#€ €¶ üÚyÚ €X(@òkaÐi2 € `«É¯­‘§Ý € €€…$¿&#€ €¶ üÚyÚ €X(@òkaÐi2 € `«É¯­‘§Ý € €€…$¿&#€ €¶ üÚyÚ €X(@òkaÐi2 € `«É¯­‘§Ý € €€…$¿&#€ €¶ üÚyÚ €X(@òkaÐi2 € `«É¯­‘§Ý € €€…$¿&#€ €¶ üÚyÚ €X(@òkaÐi2 € `«É¯­‘§Ý € €€…$¿&#€ €¶ üÚyÚ €X(@òkaÐi2 € `«É¯­‘§Ý € €€…$¿&#€ €¶ üÚyÚ €X(@òkaÐi2 € `«É¯­‘§Ý € €€…$¿&#€ €¶ üÚyÚ €X(@òkaÐi2 € `«É¯­‘§Ý € €€…$¿&#€ €¶ üÚyÚ €X(@òkaÐi2 € `«É¯­‘§Ý € €€…$¿&#€ €¶ üÚyÚ €X(@òkaÐi2 € `«É¯­‘§Ý € €€…$¿&#€ €¶ üÚyÚ €X(@òkaÐi2 € `«É¯­‘§Ý € €€…$¿&#€ €¶ üÚyÚ €X(@òkaÐi2 € `«É¯­‘§Ý € €€…5kÔ¨±úÜ .¨oaÛi2äP@¯%9,.Т¸îÊKáX!PL×<+’F#·Ic_vE@©@¯Þ½iÕBU-†=„*T@@ H’ß u)@@ T$¿¡ •A@R€ä7H]ÊF@•Éo¨ÂAe@@‚ ù R—²@@B%@òªpP@@ H~ƒÔ¥l@@P ü†*T@@ H’ß u)@@ T$¿¡ •A@R€ä7H]ÊF@•Éo¨ÂAe@@‚ ù R—²@@B%@òªpP@@ H~ƒÔ¥l@@P ü†*T@@ H’ß u)@@ T$¿¡ •A@R€ä7H]ÊF@•Éo¨ÂAe@@‚ ù R—²@@B%@òªpP@@ H~ƒÔ¥l@@P ü†*T@@ H’ß u)@@ T$¿¡ •A@R€ä7H]ÊF@•Éo¨ÂAe@@‚ ù R—²@@B%@òªpP@@ H~ƒÔ¥l@@P ü†*T@@ H’ß u)@@ T$¿¡ •A@R€ä7H]ÊF@•Éo¨ÂAe@@‚ ù R—²@@B%@òªpP@@ H~ƒÔ¥l@@P ü†*T@@ Hšõëן»zõêAž„²@tzöì·ûäÉ“ãÖ±(”@$šÉŸ:êüœ7sššø.üjyæ%p$ cG ®Ä'Ç>·Ž €@¡Z·oJÇa¡ð³GÈ©' pö½ùŽáòõü¯ó˜õ·_þÑDÔ»Ù¦‰i6½ÙÚë»ï>]s/^²8ê°éÑíõ»ßKƒí8I²þùõûï¿ò[¼d‘S[µ1Õr_sáçæy£c$/r±û§b5ëþËÏn¼E è4N´hÏñM·ßàüuÆìãw}2ÛLO²ù¬IwÏ{šÎ«î3ûóÙrÓÐQÿÏ͹úr¨sÝÒ]÷¼Çšãô/HfIVG݇뒑âlÈyÏo­:uäˆÃŽ’5k~’'Ÿ}Âw|«X“M½q,6ñÕ}n¾}x›ªþ:î7!Ó?a6Š$§f¹çÁ»ÜÄW×éx¾™³fÄ%µºÞ{óþðtÉŸÜ䨔§¯Ú›}áçɲå˼«Óz¿Ï^åRVVSb{uM®&µæ‡‘úéг˜ÞaMô;íÖɬv ríg W‹¯¼ÀuÖõjöÖÛoš]xE (Ìÿ½¿>1&á5%QC4I>bXTâ«ûú]ŸÌõL‡Px=¯÷ZãÝ–ÎûØë^ãÆÃÓ©cìùŒ ×¥X>#€@© ä¼çW¡zTì/ÿùïT'}÷ýwãz<¼˜¯ýk‚“ljRç׋¡É–&…Þ^MDõ¦°»GŒt{Lô‡Ž.ºM—ÇFs†˜Ñ;FÞ&ûîÝE†_{³3ÞÖ¬× þAû䬛¨½&±½4¦÷Ó$¤±cq¦ðOëH;ÚìØ:nܯZy“Zýa¤ã¿ÜgÓ;Üi·=ÅüÀÓm¹ösÏñ|üÉ¿:ÞrãföãbØ¥}9úˆcä¥ /:¿ÀéuÅ,z]¸ä‚ËâÆáëvý~×D6ö/?z½Ñ¿i9zó©Clþ?z÷7=²Ï<ÿ¤ó‹k¦×¿ë^&u4í6¯\—Œ¯ `‹@Î{~ Ü™§Ÿíôb¾ùa“h*0oo¦7ñÕ2ô‡Õ°ÈпžRÝ~òñ§¹‰¯~ö.ç}¡;&ÖÜСÉåi'áþ€3ëÍ hz¼þÙsü#ÏD%Úºþ7 ~#Gz¤¾ÍjÑ^]ý¡¨?Ä̸_M¬gÍžéüð4I­ùaôßéÓ\;Ó;ÜeßߺmÊOifŸÐÄà¤þ§¸íÖ_lŽ=ê8÷3oB ²jšÄ~e{žÿ;º¿<úÀãÒ®m»¨¢t†šƒNóíÁübzÍÃÜkЬÿ—¯¼tˆóúaå4§<ïÿGïþ&ñ6¿Õ-H?½)GÇ[›?ézÛiæLõ®ã=a0ÿOª{úäòï–ɦM›Å\oÌð#ïýdm4çñ»žéð ¿G‚ëŠVE?Í1ÿ_éÖ1Qý¹.%’a=”¢@°å/bææ·¹_Ì24\ý0ìæk¢¦óŽÅóÞäU@bpiR|Á僢z„³=­Ž™Õ„úÍIÿòMjMù:ôAð>™&)v,³î¤Ÿ÷—–g_xÚTI4.æIYîJÞ bý¢Ó/êâ7=™®Ot½1Ãô¸Ø¡[ú× "õÔs㵈¨ÿ#îºÉ½YUÿ¯›™S¼¿À¶m³“sœf¡2ùÿ•N&ø‡ëRV#€@É :ìÁhi/æY§Ÿã;—¯Þ2?òg}½ Ìï¦í‰Õ©È‚^LOk¢z˜óçb@Ó&ͤfÍ2Ñ_ü†<˜s™ÞWíõÕ^h3„Ù®¯Aú™ª*òØe³íêw,S>˜â­ïµ€ÎR¢Añ›êÌ[qÖÏ;­¢wÚFM€cýÿ{±'¹«õ>ý+‘Þ+pæù§»ëõ^Ë:ìÜÁ]gn5³M˜ éþÿJ·Žæ<±¯\—bEøŒ¥*—ž_ÅëùSìCU§;ÿì‹ÌG÷UÇÜ^vÑ•q³ ¸;äøyÄil±:ïïðknJ8 vÿê>›D[÷3bõ;ÆÌv¡Û’õ~å§½¿cF>7M9¸·_uY‡@¨ôE¿©Î´Òú—7ÜoVšDÿ¿ôÿÂ}·ß5_{™u6 }T²wÑ}c¯eúÿËLçhöÕkM&ÿ¿Ò©£9Wì+×¥X>#€@© liØÏ ¿Z^ªí£] P„<þ@\­ÏxaÜ:V €…hݾ©žZó¨Ð,½z÷þ94• qEòÖóbª† € `‰É¯%¦™ € €"$¿| € €X#@òkM¨i( € €É/ß € €ÖüZjŠ € —‡\ÀŒ¤#е¼"ÝÙ@”H~S¦bGÈ—@’ß|Qs@À:†=XrŒ €Ø+@òkoìi9 € `ɯu!§Á € €€½Œùµ7ö´Ð TVM‹«ã€ãHX Éoh‚Á L'ù ˜Ò@‹ö`qði: € `›É¯m§½ € €€Å$¿Ÿ¦#€ €¶ üÚqÚ‹ €X,@òkqði: € `›É¯m§½ € €€Å$¿Ÿ¦#€ €¶ 6Ïï57 ‘ó¿¶Í“öFêÕo kVÿˆ…emÚ¶“Ãn-ŠV_{ÓU2þü¢¨+•Ì­Àv êÉO?®Ém¡”VmÛ¶•[†Ý^u¥’Á –üjâ{ós¯[{J¥ÀÐúûPF&ØJiÜ‹eÑÄ÷Ή·Ku©g®ìs5±Ï¡g1¥±gA@öÀ÷ € €€5$¿Ö„š†"€ €üò=€ € `ɯ5¡¦¡ € €Ýð- ©@×òŠLå8@’ ü&åa#B  Éo!Ø9' `…ì3D@P’_¾@@¬ ùµ&Ô4@@€1¿| €@è*«¦ÅÕ‰qÀq$¬@È@ ´ÉïÇSÞ–çFÞ‘R“þpÞ%ҭסξ æ}&^÷gÙï°#åˆ3ÎNéxÝ)ö|Û7i*ƒG>,5·­•rì˜ØX$+•Ø'Ó)ÞmÓ‹$ù]½rµÜ:àÙ°nCöAÇ(GŸ{dÔºê>TMš!Ox¦ºÝœíÇ_Þ_*úvsÞÏŸ³@F ~Hö?¦GZçŒ=_Ãf 媱WHÍZ¡ý±’ ;!€Õ 0ì!"ôÔ7Å%Ú«¾[.·3@~Xº¤:C¶±±/âà¸êÿ÷¦ÜpüÍq‰¯VëÝß“+û\-_ÍúºÀµô?ýã׋K´W.[)7žx‹¬X¼Âÿ Ö"€%"ú_ñ½={A˜kOñç}(u¶«/Ü6RvhÞÂ9&E³ÿûüãñ1rêC¥FYY§§Ì$Ä> › * ½­o=3É©Ãù÷ž+í;·‹ª&—Ÿ¼ÿ©<}ë³i÷¦z{u£ ÍÑ­ûœiŸIÝúuåÒQI£–œ’M_5AÎ> rÍ£o$rzÿSQbÂ%`ýÕí—ž“Í›6É€«®s_ Ññ_)­Úï"ßÌùT´˜¥ôˆ}éÅ4_-Òäqó¦Í¢‰jlâ«uxÃé²çþD{S|¾0_ÕJé<š´kÝÿxÓn⫞2ä$Ù±C+§·ZëÍR½½ÿÕ±a}ÏohÖ¯s[ß»ã.£NU«vÙ­Û~2éù§å‹O?–n¿ôGí㢠öEº¢©¸&Àa[tl²&¶:¾·Í®­£ªW«N-éÔ£“Lÿ¦Ì›ñ¥TüÒ#µ\zÿ] Þ PtV÷ün\·N–/úVZìÔ^jÔˆÖдÕÖËæSt¥ÂɈ}r¶&ؽb7)«Y&Ïßý‚¼úÐ?’šü._ø´Ú¹¥ï°†fmš:µ]ò5÷:T6zÿ«b;á}ÏïË£GŠ~%Z²™•aÅò¥²eó¦DE;à Êj†ž(aý‹}±/ö–nýÛîÞF9¹—ÓKª7·é—Y:uß#«1³šPëW¢%›YV,ùÁò¨lÿ«I=KnèýÏ#¥ k«{~sIy `À¡§÷–[&Ü茓õ¶úÓfËU}¯ õlÞúò>3zÿ3sã( únÍ ïøC¨ƒ¿±÷wamxtœì¥£/v+dæÜÕÊtÑùwÍl±óꚃÌvó9èÙÌyxÍN€Þÿìü8B XÝóÛ¨ióȸ·Äù¿Îñ«3A°”ž±/½˜†¡EšÝöú-rçÄۤπÞN•&ÿííÈðª-a¨ž4j±CÒa :ǯIÜCQáW‚Þÿˆê!@ qæ—à€RZ½m:Ò´ÕŽ²ä›¯dË–Íqsù._´Ðin³¶;•R³iKD€Øóm©€™×µCù.IÇöîtwyûùwdÑ—‹ä·¼×>¢_…\´§ºië&nbçò]¶`ë´Ž-Úmï¼u-–sÓû_,‘¢žü*`uϯNg¦7Ìé<¾ß~1÷W•È; ë³ÿã<üb—N{GmãCñ ûâa¡Z`HÛûÍìù «an.K4³BÂÜ u׿üæÖ™ >ú©óð‹ûì`-J»hzÿK;¾´®4¬N~5„{íÿ;'’ão¿1êQÆÏÿåNYôÕ²Ó4ÂM+¼ÄÞ«ÁûT4ìyÂÁÎî:¦×oª3ïØß=ØÓwZ±TÏ—ëýÊ{ní};쉨GëÓè¾·Èyh‡&È,‰´÷ÿÚ£®5L6¤E{ÿõûÅÛû¯Cbb¿ü”’øìÙm1¿¼™:Å–FײַKQ ôê›îJƒ²[׊¸G¿ÿÚË¢_‰–³o¼#’Øî){p°Ì|ÿçQÆw_tVÔîúÈã#е öÑRp–:|A“} DìTgÞ¢:î@©èÛÍ»ªÚ÷ÕMu¦øM§–¬zŒ¹±Në^5y†óøå[O¿C7¹‹>òø˜ó U²îV.DoLizÿ%¯aîý×_tôéƒÞºÓû¢o2ª¨€õ=¿ª{ê•Ãä„Kþ­Ã!®~x|Ô#£vàCIûp†±ky…Ä~…­¦‰nvÒzj9dÜŸåès [µúèü³§^srTÝ´·÷º¿]õÈã¨øà ÐûïRð¢Ø&RëŸ~µõ&‡\¶`ÀÙ'ËÍϽ–Ë")«H†žÐØI¬rYMûøGžÉe‘•¥×'ýÓ3‹}Wö¹:g±ÿ÷¸7ÞÿdŠÚûŸê/A‰¦Ãó+ßÛûïfã·¯Ygzÿõóã×szÿÍ6󪿸]:ꢒü%HcŸËkTëöÎ5 ÍÒ«wïŸCS™W„žß‡ª!€„W€ÞÿðÆ†š!L ôc~“Užm €R@‡@xt’M]2ÏÌ0‘î¹3=_ºçaÂ&@ÏoØ"B}@@ ç70Z FL*«¦ÅÚ%r  €Ù üf+Èñ sé$¿97¥@@­ {à;@@À’_kBMC@@H~ù@@°F€äךPÓP@@’_¾@@¬ ùµ&Ô4@@€ä—ï@@kH~­ 5 E@ ùå{@@À’_kBMC@@H~ù@@°F€äךPÓP@@’_¾@@¬¨iMKi(@×òŠ¢©+E(.’ߘxmX¿N½îϲè«/dÿ~#Î8;f>–ª±Od»üúcú 2jðCòí¼ErÐqÊÑçé»+KO€Ø—^LiQáöc¿tÁ7¢_ºTN~S~Xº$f>–ª±/ÕÈ–N»–|½TôK—ÿ5]V,^Q:£%Iˆ}R6"–Éo ×;/='›7mrÖ®ûiµ|ñéÇ1{ð±Tˆ}©F¶tÚõÖ3“"×§ÍNƒÖ®^+óf|Y:£%Iˆ}R6"–ɯ‡ë§U+eÞÇUž5"“žZ6mܵޥ'@ìK/¦¥Ö¢Õ+WËÜÊyQÍš8þMÙ´aë/ëQøPRľ¤ÂIcB @òë Âÿ~M6FÆüêÒv×=œ×Uß-—ª÷&;ïù§tˆ}¸b[Y5Mb¿ÂUÃü׿ýW?÷©ËNÚ:¯+—­”Ê·¢aw6ðOI û’ ' Éï/AЛ>ûð?Χí›4•.½J¶­]Çù<{ÚTÙ²yëŸC3ªcbŸcÐ7=’üÆ~å Ø¢-B“ÞO§~êÔ¿a³†rêµ§H­:µœÏŸLù$r}ÚR´m£âɈ}r¶"‰Éï/js"‰¯Îð K¯ãO‘†‘¸ÃÞåÎçϦO“sç8ïù§ôˆ}éÅ´ÔZôéÔÙÎ Ú®>zË‘¸c—N3?ý`¶|3{~©5™öü"@ìùV@ ÷Luö‹éÌ÷ßqÞÕÙ®¾ìÒioçýïŽ=A>ÿèCç¸Oþó¾ì´ûž¾X0ï3gz4s£\ìNÚ“sn€›ùÞ,iß¹oeæÏYàLfn”‹ÝI{’¯{…Ô¬ÿã ›ccÏÃç̈}fn…@2z~#:š€j’«ËN»wMVuiÞf'çKßg3홎~ê±2þöÒ>‘ͱZo–äÄ>¹[ /  ¨&¹ºh‚«Éª.-Ú5w¾ô}6Óžé¸á!ý†ÊØaO¤=|"›cµÞ,Ɉ}r¶‡À•—_.oMœè|ºÿ~©Y³¦4¨__ž?>j]>[ÿ«~>Ï’s™Þ]­ÎïŽé/5ÊÊœšÕŠŒùÝ­Û~Îpölêª}èÅλDºõ:4ªeOÝy“Ìþï¢Ã'žºëf9õŠ¡î9¼;fs¬·Þ§.@ìS·bϘÞ]={ÏŽ\;¶öYè˜ßN=:9Ã!tÚ³÷^y¿Ú‡^y©èÛ-ª!_?N>yÿSÑáO /g àžÃ»c6ÇzËá}êÄ>u+ö Ÿ@îÝåÆáå엜Ê[ÃW¯–|ÐÙ¾ûî»K÷ýö“÷¦Lñîè{ë{~uŠ«÷^ý»ƒ¬=¾;îÒ1 ¼û¡ýÜß>ùÏ”Œ¦=;õÊaÎ8b-XàÊwþ_Ô9’}ÈæØdå²M„Øó]vâêíçßqª©=¾mvmUåýîîÞø6óÝYM{6ð†ÓqÄZ°&ÀN¬Œ:G²Ù›¬\¶‰{¾ ŠY Y³frý°a¾‰¯i׬Y³dÙòåÎÇžlVçåÕúä÷‹Y3ÜéÍôF·Øq¹Ûmßнñ-›iÏ:ú8iÕ~'¨éΑͱyù.*Ò“û" œEÕž÷Ñîôfz£[ì¸Üú ë»7¾e3íYÏ~';vhåȦ;{D6ÇZÊ´›JìÓ&〠\;dˆÔªµõ>§'Æ“Cúô‘™‘d×»hïoUÕÖ©[µlé ‡ðnò½ÕÃtŠ«÷^}Ñõ}yôHѯd‹&®]~÷{ßa ÉŽÓ!Ú³¬3J,ùæ+Ù²esÊedsl²:Ù¼ØÛýâh»Nq5ù¹·ÝÊ>÷ ¢_ÉM\»õéâ;l!Ùq:„B{–¿·H}¹Øûk†W$;N·eslueÛºØÛùÒh·ŽçmÒ¤‰ÓM|ŸˆŒí­niñKò»é—'ìV·¶Û­îù]ºàѯt–l¦=kÑnçtNµo6ÇFÄG€Øóv%_/ýJgÉfÚ³V»líùMç|fßlŽ5eðú«±ÿÕ‚wÅ'P·^=iܨ‘¬_¿^ÞÿàƒP6Àêä÷—žs¦1K72:íY&Ë’¯¿Ìä0ç˜lŽÍø¤%| ±/áà–HÓÞzf’3YºÍÑiÏ2Y}±(“Üc²96ã“–ðľ„ƒKÓ¢Z·Ž¾!jc€¬ö 7;ÍûxëX“ݺV$œÁØëþw]x–3>X§=ëÑ÷(Ù¡y ³¹ÚWïùZìÔ^jÔØ:£DµFvÈæØTÊ·m¯'±·-úÅÑ^½Ùinå<§²ºï‘pÓÝÿÖw8ãƒuÚ³Ù_µld6Wûê=_«[¦5l"›c«­˜…;x=‰½…ß%ÐäµkÖÈ÷+VHË-äÄã—›GŒðm•ÎÑi=œm•••²nÝ:ßý‚XimÏïÿ~ͽÑÍ;½Y"d½ñíÀ£ÿÏÙl¦=K´¯ßú—¾?­óyËÈæXo9¼ß*@ìùN»Àû¯~àÞèæÞ,Q½õÆ·ƒÿ³ÙL{–h_¿õ/Üû÷´Îç-#›c½åð~«±ç;¡Ø¼7²Ò«— ½æš¸&ß¿¿ÜrÓMîl“ßþõþ†¸Xaeò«7;}yœ±.~Ó›%rNeÚ³IÏ?5šžkÔU;óüj¹û÷ûCÂ'Åesl¢:³>Z€ØG{ð)|z³Ó§S?u*æ7½Y¢§2íÙÄñoFM‡¦çºï¼¿8óüj¹w`Â'Åesl¢:³>Z€ØG{ð©x3F/Yâ4@`}ÈÅ^;‹Îéûï×_—ó r7gÎùà?[s2weÀo¬ö0'’øê¬ ºøMo–ÈÜôþj’j¦=‹} …y"›_ú'ö¾§é·ÉY—ͱ eC”±âàC>:Û™uA«æ7½Y¢*›Þ_MRÍ´g±´0Odó+CÿÄ~äÙGømrÖeslÂBÙ%@ì£8øPÄÚû;8òd·qcǺSžù5Gß‹–|Íò`ê`]òëâªÎvõe—N{‹”^µ÷Wб1Ò£«Ipù=£Žk»ë2ÿóÙQëô<Ü6²Ú1ÂÙuB>ø {_–P®ìZ^Êz])ïWuëוûìœÖ)µ÷WŠ¡åhÜåò¨ãwêÔV¾ùt~Ô:=Ï¥£.ªvŒp6ÇF¾ÄÞ—…•E,°lÙ2éÛ¯ŸèoO¯6Ig‚Фwîܹi¡uɯΙ{þíÉ[{¯ÿëÜÀ±uùý¡rÎÍwÅ®Nés6ǦtËw"öÅó ÐÅÒäWç̽tôÅJ{o™pcÂã+¯ GžŸp{² Ù›¬\¶m ö|'”’€>áM{}ŸyöYù0r3›>ä"L‹uÉo˜ð©  € Pjæ ogœ~ºÓ´O>ù$TM¬ªÚP@@¢Ð^ßÝvÝÕ©ÿ[“&¥ô„·|7–ä7ßâœ@(Q3ϯ6oÁ‚¡l%Éo(ÃB¥°[ ²jšÄ~Ù-Bë@â03=lذAö«¨š5Ã7–ä·8¾—¨%V L$¿±_VÐX@ ˆÌL7m’ /¿,;v UkÂ—Ž‡Š‡Ê € €¤*`fz¨U«–{ȘQ£Ü÷~oV®Z%§œvZÞqLòë…4׵鰛Üðô+iµu÷lŽÍè„”Slâ—ͱ9m…•´@ÛÝÛÈm¯ß’Q³96£rPN²‰_6Çæ´†@ {•"@@Â)@Ïo8ãB­@@¢0ã}Ã\qz~Ãê† € S’ßœrR € €@*#ï½WÞš8Q<à€TvÏÙ>$¿9£¤ @@T†&‹—,‘SN:)¯ó3æ7Õ± € €@J~Sž%:°nݺNò»)2/p>z~ó¡Ì9@@Kztï.O'Þ¹~ÃÔt’ß0Eƒº € €E.pÒ‰'JYYYÊ­xå•Wòö€ ­ÃR ;"€ €$hP¿¾4iÒÄÙÅûä¶+/¿\Ú·k',fxÃñýûË™Êû|¬Èœo£ç7礈 €Ø)P·^=iܨ‘Óxoî{S¦HÇŽ¥û~û¹0o¼ñ†¬øá9ñøãÝuùxCò›eÎ €X,0kÖ,Y¶|¹\;dˆ“+EçÎ¥YÓ¦Ò¥K©S§NÞtö7jN„© t-¯HuWöC‘ÀÚ5käû+¤e‹Ò¦M·f?®^-UUUrxß¾2fÔ(w}!ÞüBs"€@R.$¿I}؈„U@“Ü—#7°7h°ÿþN/ïܹsê>4fŒ”——;‰±·þ•••y½áa^}Þ#€ €d%ðü /ÈÌÈ0‡Úµk;½¼æ nšŸ{Þy΃-Ì Þš4In1Â|ÌË+=¿yaæ$ € €€=—Dfuð[4>uÀ¿My[GÏoÞ¨9 € PÚúd·gŸz*¯7°¥+JÏoºbì TVM‹;ã€ãHX„R aÆòÏ dýúõμ¾fÌoX*Kò–HPp¦“üº¼AŠUÀŒù [̰‡býŽ¢Þ € €@È–-[&}ûõ“×#°0‹I‚_ÿÇ?Ü9~ͶB¼’üBs"€ €%,pçÝwË!}úø&ÁoMœ(fˆBüBs"€ €˜$xtdŽ_ïrãðáR¨$˜ä× Þ#€ €ä\@çþÕžàk‡ “Í›7»åkü÷È6oì’ð@@ ˜Ô¯/÷d7mÓœ9sœ!6mÚ”·&2ÛCÞ¨9 € `À•—_.‡÷íëÛàë"=¾ïM™â»-è•$¿A S> € `‰€>äbÜØ±R«V­¸âQÆq•ˆ¬ ùõSa € €@Öa›ãWDò›uX)@@ÀOÀÌñ«ÛÂÒóËl~‘b € €@Úæ!±süjA‡ôêåLoV¨)ÎLcH~¯ € €90süsì±²xÉ’¨rÍ<¿ùžæL+Aò > € €äRàÇÕ«åÔ|çùm¸ýöòô“O2Ïo.Á) @@ °Ç÷ï/ç W‰BLyÆ oqa`Z kyE¡«Àù@r h®ßB$½¦9$¿F‚W@’ßÐĂР€™ø%½a™öŒä7“ˆr  € €@œ€ßC.Â’ôšÊ’ü ^@@r&¶¤×4Œä×HðŠ € µÀÊ•+eàYgɺuë².+ˆH~ƒP¥LÈJ ²jZÜñŒŽ#a :}ÈÅI§žºzy+DòëÕà=„B`:Éo(â@%@R ù-ŨÒ&@@ ¿›Ú²9ÕÊU«ä”ÓNËÛ0‰À’ßzõ¶“¡'ôËÆ‚c‹T ¬¬&±/ÒØeSmý?_,K½zõäÊ>WÙè¥ò@IDATKu©gÊj–ûzSQúÿž,ù3òQ„@P Œù×PÖ‹J!€/Xò|Õ9 € €@¾ô¦¶¾ýÿuä½÷Ê^;ËãÆÉãÇ'¬^îÝåÆáÃnjC  ¦\@@»Ô¯/Mš4ã÷ý>eãI~C*… €Ÿ@ÝÈØêÆ…ºâ$¿¡•C@ŠO víÚÒ¼Y³¤oݺµ”••%Ý'ˆ$¿A¨R& € `¡ÀÚ5käû+œ–_6x°Ô©S'¡Âàl[²x±lÚ´)á~¹Þ@ò›kQÊC@,øqõj©ªªrZßpûíå¥^Ž;Fiè¸à§"7ÂéMqºügÚ´¼&¿Ìö> € €d#ðИ1R^^.-[´þ0fÔ¨„ÅÍ™3Gžz晄ۃØ@Ïoª”‰ €X* ½¿çžwž,^²$©€>Ùí²+¯Ìk¯¯Vˆä7iX؈ € ®€&À§ £#½À~Ëu‘ù}ÿ¯ÿ¼=ÒØ[†=x5x € 3ç#c~õ+L Éo˜¢A]@ÀèZ^ €@‘ 4‹Lq6nìXyæÙgåÃÊJùä“OBÕ’ßP…ƒÊ €€ t!ùå(Zk‡ ‘ZµjɧŸî´!lÉ/c~‹ö[‹Š#€ €áÐ^ßÝvÝÕ©Ô[“&É‘)Ͷü†-"Ô@(RïC.,XÊVü†2,T @(>åaðå—ˆ d¿Š ©Y3|#lI~‹ïûŠ#Pò•UÓ$ö«äM@X¶l™ôí×O6FY<áå—ãžðVèf†//´çG‚ L$¿± 7ÁŊ🀙éAox3K²'¼é>ú°‹SN;-osþÒók"Ã+ € €@É ü–|ˆi  € €€`؃‘à@@ +3Þ7«B>˜žß€)@@ <$¿á‰5A@¬yï½òÖĉràäµÍ$¿yåæd € €*0tØ0Y¼d‰œrÒIy˜1¿|ÿ!€ €äTÀoʳD'¨[·®“ünŠÌ œ…žß|(s@@ÀÝ»ËSãÆ‰w®ß05ä7LÑ . € €@‘ œtâ‰RVV–r+^y啼=àB+ۇ”CÃŽ € €ÉÔ¯/Mš4qvñ>¹íÊË/—öíÚÉŃ‹Þp|ÿþræÀòþ$+2çÛèùÍ9)"€ €v Ô­WO7jä4ÞÛ£ûÞ”)Ò±cGé¾ß~.Ìo¼!+~øAN<þxw]>ÞüæC™s € € Ìš5K–-_.×â$ÁJѹsgiÖ´©téÒEêÔ©“7†=äš!€ €¥-°vÍù~Å iÙ¢…´iÓÆmì«WKUU•Þ·¯Œ5Ê]_ˆ7$¿…Pçœ T kyEÒílD§€&¹/Gn`;oÐ 9`ÿý^Þ¹sç:•}hÌ)//wcoí+++ózÃÛ6‘“ÿ¼ð«åÞ:ð@@ ‰@ëöMu«æQ¡YzõîýsX*£OoÛ+2¬A—ë†ó«‹Þ÷ÐèÑnüÖ¤Iróˆζ|ýCò›/i΃ €%#@ò[¼¡ä†·â5G@HS€ä7M0vG@(^nx+ÞØQsJV ²jZ\Ûºp\œ +@B4kÖLÆ›³Ç{†‘öüæC™s €@ZÓI~Óòbg@Ôöº{"€ €¹=¿E@ª €äS`Ù²eÒ·_¿¤§<¾g®_ÝÉ;ÕYÒƒò´1°ä÷ê‡È· ¾ÎS38 Z`Ç6íä¶ën-t5R:ÿU7ýYÍ_Ҿ섥!Ъm¹}Ø¥ÑZ‘•@`ɯ&¾G<üRV•ã`(žslÑTVߊ‰Ã‹¦¾T²˜Ögxö…PBI0æ·$ÂH#@@R ùME‰}@@JB€ä·$ÂH#@@R ùME‰}@@JB€ä·$ÂH#@@R ùME‰}@@JB€ä·$ÂH#@@R ùME‰}@@JB °‡\”„@@ˆhÖ¬™Œ;VjÕªµ>ч‡O´ÉY¿rÕ*9å´ÓdݺuI÷ËÕF’ß\IRäL kyEÎÊ¢ @¼¡O~M{Wª½Ç[ç„ï÷:ãBisÀïí+¿š+Sï¸Fvêu„t:á I¶áó ÏÊÂ)oIϛۦöÛM²ò؆© t)’äwãÊŸdÆ€ûd˺Q k~\ÙéÜâÖU÷áûI3å‹/V·›³½ÝåÇH³¾û:ïWÏY(³•fÇT¤}Ns²…ã&ËwÿúHö{‘Ô¨ú ¦Ú¼"€ p•KÀ¦I÷¼ “:š&؃Õ `³€&Œ‹ÆOö%XúâTѯ=î=Stnë»OXVjÒ­í¨Õlû°T‰z €@È–-[&}ûõ y-W¯h’_o¯nâæäf‹öøjâË‚ø hoëâgÞu6ù%¸Ÿ_ÿŒ¬|ÿ3ùâÖÓîMõöêú;—ë’%ð¹<e!€a(šä7hf¨ÄÏ›7I£]÷”?­–k×äãÔœŠH`å´yòó¦Í¢‰ª_Ïî®7œ,&þéóE¾û²¹f¨„¶¡ÁÞ;ɦ×ÉæŸòs£I!Û͹@ ùõ||ñú ¢‰¯ö2·êv€L½óZÏVÞ"€@¾*«¦ÅªXÆ›ŠkÖeQ¤×Ú$ï{î3üXX«J½@œ üzH»ž?Äý´y=½ .oȳÀô'¿ +:8þ¾ûYûõ²Œo4Ë3«{:ob¾yÝw=o@Š&ùùÄ¢_‰½1Yé°r)P÷ÖÒò䃜ÅÌÍm¦ü†Ýw•ŽÃO’mÊ2{†&Ôú•hÑÓ˜•!‘ë@ê2»:W_.{ €%-ÐúôžÒuÂ5R¯C‹¨v®üàsùoßeZŸáòã¬ùQÛø€ Px¢éùÍçl… 5@b(«SK:>×­ª÷F2]©ciÍl‰æñ5ÛM!ùœíÁœ“W@À&z~mŠ6mE@t8Äo_&‡K«=s-þÛ{‘i·z^ GH] hz~So{"€Á ˜§ºý¦¼}Ò±½Íþ­,y~Ьùr©“ü6îµ—è  €@aèù-¬?gG"¨Qg[©Óº±èØÞÕ³&¬ýú%?D¦Û"õvnžñÍo g €@Æ$¿Óq Ø( ã|[žp€ÓtÓûÍCÿŠcðŽýmxÀ$¿qB¬@ 'P4ê›êL ›íÝMºžµlS£ÌýúÍWE¿-Ýÿ#€¶ÐókK¤i'äT ÑTgz’²úudŸq—ÝÃ/r Da €@HBßóÛªâ ѯt—†í;ÊᣟO÷0wÿ²ÚuäÀ¡w»ŸyƒÄ ÄNu»=Ï™Þgf˜Hç\Þ}sÙo¹¼GÂ*@ÏoX#C½@@r.@ò›sR D@«ÉoX#C½@@r.ú1¿9o1"€@躖W„¾ŽT@ 8H~‹3nÔ’èBò[Òñ¥q €@!öPH}Î € W’ß¼rs2@@B üRŸs#€ €äU€1¿yåæd Š@eÕ´¸ÝG @ H~3@ãV`:Éo°À”ŽX,À°‹ƒOÓ@@ÛH~m‹8íE@, ùµ8ø4@°M€ä×¶ˆÓ^@@Àb’_‹ƒOÓ@@ÛH~m‹8íE@, ùµ8ø4@°M€ä×¶ˆÓ^@@Àb’_‹ƒOÓ@@ÛH~m‹8íE@,àñÆ?¦Ou«,õy䬖±×J›~Ÿrq›×¯“©w^+ÿ›ÿ¥{LFM¥çMHmk¹ëxƒÙ ,7YŸœqAeõëHçQƒ¤vË2.£Ôü~ÒLùbÄ‹N³ö¸÷LiйmÖMüüúgdåûŸù–Óîòc¤Yß}}·ù­Ü¼nƒÌü˜¬™·ÄÝ\«Ùö²÷Ø‹¤F-~ì»(¼±V€ÿÖ†¾ú†û%©~GÍ|âѯf{w“®ç_-ÛÔ(óÛÍY·hÚ»Rõè=qÛ×­X.o\pbÚ‰t\A¬@ŠDÀ/Iõ«ú×w¿"úÕ°û®ÒqøI²MYâ?ÚzsoY–­’ûÝ,é&ÒÞ2x@©$þT*-¤ h’ú¯‹NŽê­® e(/;CÖ,_ê»ëʯæÊŒ±ñÝfVj½bÞló‘W@ $4I~Ôˆ¨ÞÙêºòƒÏ¥²ÿ²~ñ¾»®ž³P¾¼ãeßmf¥&Ñ?Κo>òŠ€•ôüZöäöëMÔ«Û;¼iÍO2ùÚs¥ûŸGH£{Dè‹×_Ÿ7orÖµë}´t:áîö ?®’I× ’Íë×»ëxc¯@×ò {Ÿã–·>½§è—ßâ‘«?ßû‡uÑ~½³‰zuc{‡7¯^'3N)~ñZôÌ»òó¦ÍÎÉš×Cv:÷0÷ÄWþ$3Ü'[Ömt×ñ[H~m|‚vk:süƒîÖêÆâ–Õ®#½[b“תGïëIòÚß9åj"½GÿÓÝsè›Z ¶—ÃîV>ŸðlÔz>Ø)Ð…ä×ÎÀ§Ùêe¯M—&}ö)ªq¬š„~uÏ«nK«‹[V§–t}®Ä&¯_ÜúbÔ^M’uhƒ.šH·=»{}³mÃí¤Û„kEáaAÀv†=ØþÓþ™ãG¹½¯š¤ö1:¥›Ð4yí}×ãò›¶;;%êÞ9/=Szõw=ꤸãêb°MÀéµ~ú¢köW÷¾êö¾j’ºÏ¸KRJÞ5yÝ÷ù+¥^‡N›5Ñ]ðØÿK»ýúW€\Ü —ö‰9 ü†(…®ŠöÞ~7{†Sšõ¶“N'þ)éÍk±õÕ^àΧž¹cë–TN•-78»é¶ºš8ïulðìÆÅÎg@ %ïp”ÉNÚ{û¿Ê­³Üè,;xÒ›×b«­½Àí.9R¶©¹õ¦âÞýT¶lØ:”L·i/².:6xþ#cç3ü"À°¾\ïfìöú¶Þÿ÷R¯isw[ªo¶ï(ÍöêâL‹¦½¿+¿ùÂíÉÝåðþ²lf¥3î÷ë7_MŽ™Þ,UYöC ÿzÕìÁcq¤f–ïxUïŸìýö­±IZý¦O‹ý³¾ë-ß”åÌÌ``¶é«ßXXo;‰ÆØšíú;ÞÖ»-“÷ÿûèK·×·Éaûf4}\ýÝ[ËöœiÑ´ý?}¾ÈíÉmuòA²jÚ<'^K_œ*š3½Y&‘â˜R ç·Ô#œFûV/ýÖÝ»E—îîûtß´ìv {ÈOK¹ï51Þ统Íôf ¦¤ÿ§;·Þ”¤@edN騝’lh‘5J“W3¿­V]“¯y7=ù…vKV-ÑĹêä{ÜÄÐf’[3;7ñ5û${ÕäuÖyEÕÙ쯽£ÿí{c™´­éÎÆ`ÊNôºvÁ÷î¦FFßìnHáMãžÝ½Ö.üµLMŒwþóÜmÆoÙ¹ëxƒ"ôüò]à ü¸à+ç½y¨³}#w}ºoê5má }Й~üv~Ôá­*Šô(·©w\ãÎü Ó›Íð7z£¤ìþ0Ýç*ÜWØï‰ï^¯” ßýOº½6Ô£ª=µŸœ?&í?ÝûµÂÌRàíöëuÝõ†“ÃMì×3lÊ=ÞÛ#ìÝöù°§ãâaz¨µ,oLÙÞíf]*¯k¾Xìì¦eÖjÜ •C|÷ÑŽèÐÙaí×Ë¢öiÜk/§GÙôØëFÞLtB/p, ç×âàªéÚ|øè祹çŽ~í~óÊ3Î\¨ºr^Ø*°vþrÙã®îÍYzVùÓ—eô§ûD¦eõj˶¿$…f–ƒ]®9.ÑîIׯœú™;‡®7ñÕƒ´l]§7éÔaK^™æ–¥Iý’ç§8Ÿ5¹Þ÷oWĵ±n›Æîþa|£=À¿}}˜4Ü7·zÚ üщw%œ#ØÝ‘7X @òkAÓm¢ÎÕ»nÕŠts÷_³|‰Û«Û`ÇÄýìzþ)ÿÓeîqzÞîæÞ$çnà \ Ó1ª©T¼Þ.-Ý4Aûø÷»7qéJíÉÌdv‚ï'ÏrÊÔ±½õ÷hí¼÷þ£ pû;«¼7ŽyÇåî2ä87Ù÷›í{M¸7|ÿcÆÅèC.Ì|¾uÛ5KXŽö”{yÐóξâñ(ß„³`ØC 7ݦéXÝ¥¿ü¹YÇêÆ>¤"Õòøž»ëvÍ[¹ïýÞè0ˆ&{ìí>àÂL‘æ}†ßq¬Cü $K²²­IËö—•Sç8=µfœj*7¤%:¯kÐrt1c{í«ë7¯Y/#ɨ'0I³öún·kòëW²2ý¶éXÝ•ïælÒ±º™$õz°©£¾¯Û:y/´þòð›}wvp¡.:Eš÷Z 6 ÐókS´«i«««»é\3MY5‡EmÖG댺¤:vXçî5bŒ”Õ®íç"ÍYÁ? PÒfˆC«=Ývš¤ÕÜìænHá>ÅlçF°ÉË.f¬®žLÇàšiÊÒ9¹Þ¨3:è’êØa¢²ÏøK¥Fmã¼=ÝÎ þAÀ2z~- x²æÆNSV9æNézþÕ)Ïõ«Oq›õÔCî‡t¦KÓ¸Éû8=ϛ֭‘u+Èhªµdíc„[@À ½À³?æŽ×õ»!­ºVh’W'Ò#ºfÞçig‡Ÿ”Ö|ºÕ•ŸéöØiÊt¦Œtê¦=Ú_ü‡;ä!¡(šÿ¦ËÎNϳ·§;Ó¶pÅ,@Ïo1G/€ºë\¼æ!ú0ŠIל—R°> ãÍ+ÊÿæoÀ]‹¼û±§º5ÔÄxúèÛR*Ë=ˆ7 `€é6cUuœê7£^Ok:5-C‡-è²æË¥ik¦3 b® sñš‡ThïöŒÓG¦Ô¬7â}tüî/Ú¾6gþÞ­ž&Æs‡?›RYîA¼AÀR’_KŸ¨Ù‰æâýð[äç-›ãÓ¤÷_$o^>Ð}@†îTþ§ÁqE^ûýryã‚ů¬Ï'<ëŽ7Ö±Æuo}\Ü Y¡¨ÝB§ßÚú#eå”Ù¾ §™êËÛMÚ<:1n«jf+ˆM`Í rÞrbß›$ÖŒqÝîý¬Éµ‚ ãcµç8vïþÙ¼O4¯öpûÍ—¬Iï‡GÝâ$¾:œÃ,~7ã­_ºR>ìw³ø•¥Ó³™ñÆ:ÖØür`Êã›ö`S´Sl«Þ„¦KÕ£÷¸Gh/ðëçöw?'z£ã|¼öî¤Cª+«ù¾ÝSj‘¨¬Gü xÿ¬®=š«g/toèÒ×;”!¶f«¦!‹ÿ6EÌSät»wlk½›G [0SibûÝ[3¥Yß}"õ<_Þö÷È ýY"ôÆ0Møôigë¿ý>nˆyò›Ó‹ú§>NÚŽÇàŒÉÕãtÉõÍašØëâ}`ˆãìlHò߼ñ»WWVÃöˆòŒ=žÏ”ºÉo©G8ÃöÅÎÂJ1Íöî–Öa¿2Ûõ>ZÚðëŸòüöa„SÀûx]Mv½‹&m{u–ï'm‚̻ͼׇ1è—wÑãv:ÿð¨d­aÝœ9zuLoì1ÞMí5Iwu ¡÷œ:öX{©Mâl’`ï>Ù¾…!•ò²™Ôßü¸î/ f¯Ø&@òk[ÄÓh¯Þ„vØýÏ:GLu«;,!¶ˆ½Î¸°Ú„µ¬v9pèÝ¢Ã$&]3(jˆ„–—JqìyùŒáÐ?éwyé*7á4µÓ„K{OõOﱋãkza½Û%{æó¤7ï1:cDZ[´™ý´ÙûÄ3³¿&ʉžz¦säêƒî‹{ì²9>ÛWíeî6áZ§¿¶˜ò½=âf]ì«ik¢:§Òc[&Ÿ(Um" ûyáWËsÞ¾gŸ,G<üRÎË¥@§À?Ï9VÆ?òLN*÷ÈãÄ•söÀ ãÖeºB¯O‡gz8Ç!€@ Lë3MG@l ùµ-â´@°X€ä×âàÓt@@À6’_Û"N{@@‹H~->MG@l ùµ-â´@°X€ä×âàÓt@@À6’_Û"N{@@‹H~->MG@l ùµ-â´@°X€ä×âàÓt@@À6š¶5˜ö"€@øº–W„¿’Ô@ (H~‹2lTÒèBò[Ú¦u €@öP@|N € _’ßüzs6@@ üŸS#€ €äW€1¿ùõæl ‚@eÕ´¸½G @ H~3@ãV`:Éo°À”ŽX,À°‹ƒOÓ@@ÛH~m‹8íE@, ùµ8ø4@°M€ä×¶ˆÓ^@@Àb’_‹ƒOÓ@@ÛH~m‹8íE@, ùµ8ø4@°M€ä×¶ˆÓ^@@Àb’_‹ƒOÓ@@ÛH~m‹8íE@, ùµ8ø4@°M€ä×¶ˆÓ^@@Àb’_‹ƒOÓ@@ÛjÚÖ`Ú‹áèZ^þJRC@¢ ù-ʰQiJ[  Éoi˜Ö!€`ØCñ95 € €@~ëù­[o;ùç9Çæ·5œ  & ÿç‹e©[¯žLë3¼XªK=@ úÿžØ&òõó¯–£ € ¢@ëöMuOÍ£B³ôêÝûçÐT&Ä ¬ç7Äm¦j rʪiq5dp +@2 ùÍC@ Xé$¿ÁS: `±7¼Y|šŽ €Ø&@òk[Äi/ € `±É¯ÅÁ§é € €€m$¿¶Eœö"€ € üZ|šŽ €Ø&@òk[Äi/ € `±É¯ÅÁ§é € €€m$¿¶Eœö"€ € üZ|šŽ €Ø&@òk[Äi/ € `±É¯ÅÁ§é € €€m$¿¶Eœö"€ € üZ|šŽ €Ø&PÓ¶Ó^¿@×òŠðW’"€¥ÉoQ†J#PÚ]H~K;À´( Ã ˆÏ©@@ò+@ò›_oΆ € P@’ßâsj@@ü 0æ7¿Þœ R¨¬š·ã€ãHX Éoh‚Á L'ù ˜Ò@‹ö`qði: € `›É¯m§½ € €€Å$¿Ÿ¦#€ €¶ üÚqÚ‹ €X,@òkqði: € `›É¯m§½ € €€Å$¿Ÿ¦#€ €¶ üÚqÚ‹ €X,@òkqði: € `›É¯m§½ € €€Å$¿Ÿ¦#€ €¶ üÚqÚ‹ €X,@òkqði: € `›@MÛL{@ ü]Ë+Â_Ijˆ P”$¿E6*@i t!ù-íÓ:@ € {( >§F@ȯÉo~½9 € €@öpÙÐËeùÒEl§F| 4mÞJî¹ùî|ž2ãs 6X¾[²$ãã9ŠO I‹rïM÷_Å©qÎK~5ñÞñÀœW˜@ œ]ç¾—³ŠUVM‹++—ã€5ñt@`—¿¸º³ /Ðk ¿ð> á¨WÿpÄZ €€G`zÀɯçT¼E°L€1¿–œæ"€ €6 üÚ}ÚŽ €X&@òkYÀi. € `³É¯Íѧí € €€e$¿–œæ"€ €6 üÚ}ÚŽ €X&@òkYÀi. € `³É¯Íѧí € €€e$¿–œæ"€ €6 üÚ}ÚŽ €X&úÇ_øûrËq‡¦–[_›,·½ö¶³ïá{í*O:Q^©üTÎ|ìÅ”Ž×8íh°ÿ¾Qû{ËÚÀ°Rà²ÿ'wvvJm>ùI¹aòSξGí¶ŸüýÄaò§ïÉÉ/Ü–ÒñºÓ_,gîûëupùO«¤ýÈòÓ†u)—ÁŽ €[èùõ|'¼qùã_Ý<¤_OyëÏ’Z5Ë<{óV`‡ºõåËKÆF%¾zƦÛm/«¯yIþ°{`+@é €@ „¾çטÝûª=Ì=vi+k7l”Ãî+3,vNmz»¶ÛQ.;ì@·gÙÔ‹W°WÀÛ«„ÂË•ö;´Øž^ÓüðQ—ÈÄ/?¢8|ÊD’ ç7Ú†õêÈ9=+â_úë3?—ÓÆüM6mÙ"‡îÙ‘Þß’ý¯@ÃÂ$е¼Bb¿ÂT¿|ÔE{}/¬8JÖl\/}Ÿ•àžõʽòÞüOd»Zud·Æ­óQΔŒ@Ñôü)^¿Nmiþ›ú²zý™»ô»¸SÍüv©lÚ¼%n=+@ .‘ä×ö凵«eç‘ôeÐÄxÇ}·±@ ¹ÉoÄgáŠUÒü’[Jíµcs©YVC¾þîÙ°isÂýØ€äCàÕ“‡;Ã!žõ¶T.ž—Sr@ dŠ&ùÕ›Îô+ÑòÝê5²×ÐûdMdÌn.qû ‡ËÊ5ëäÂ'_ÍeÑ”…E.0¼çi¢_‰–رº‰öKe½™)¢f­7Þ=Þ8•:± PŒŒù­&jÏžw²ìÔ¸¡\òÔ„œ'ÖÕœšÍ €@BMºÿsö}R«¬hú0¶…  €@>Šæªôl±èÚãûÎANâ{j䆷̘» Ÿ@ ʪiq%‡qp>{_'|öÙöÆ#]—wϼKl»§ëÀ¹°Y`z‘$¿…ŒÑ©/Þ!Ÿ]ôˆü¾}¹3ë¼(d487“ÉoL´Ìå¦ý­ô½g,7¸ÅøðÂ!ðã†5²øÇR¿VÝpTˆZ €E"À˜_O ôÑÆú(å?œ%‡Üñ(‰¯Ç†· _¶Û7“µC_‘eW>ëôìÆž½A­zÒ²A#ùjåÙ¸ySìf>#€$ ùýF{|쿯“øžùØ‹ ¸XäG`þªeòᢹΣŒ=úÒ¨“ê<¿“Þ.ujÖ’Îý¯l ùòá L h†=T7Õ™6Òo¨ÂqÝ:‹~%Zôf¶ªÈ£Œ‡}ˆ³K²ýýÊOT.ë@ ôª›êL¦}û™ôØQ êIýJ´ûìòòœ©rô3Ãeú9÷;ûúí¯óüÞ0ù©DŰ@ÀG€žßÊöí$u¶-šß|ÂÈ*(Eó”·Ç>úw\ó4A>ù…ÛâÖ³@ ¹@è3¾þßTѯt—×g~./¼)åÃ29GÊ…³#””À=Sÿ.ú•î;]YªÇŸõʽ¢_, €Ù Ðó›½!% € €‰Éo‘Šj"€ €d/@ò›½!% € €‰Éo‘Šj"€ €d/@ò›½!% € €‰Éo‘Šj"€ €d/@ò›½!% € €‰@èçù-Gª‰9èZ^‘ÃÒ( @_H~µà„D  ÉoH"A5@Ò`ØCéÅ”!€ €$ ùMÃj@@Ò ù-½˜Ò"@@ŒùMÃj(œ@eÕ´¸“38Ž„ €üf€Æ! ¬Àt’ß`)°X€aŸ¦#€ €¶ üÚqÚ‹ €X,@òkqði: € `›É¯m§½ € €€Å$¿Ÿ¦#€ €¶ 0ÛC#Þ°^ygÈ Ù©qCùnõÙkè}²fÃÆjÏкÑö2ýú ¥Î¶5eú×ßJß{ÆÊ†M›«=Ž@°ìP·¾L?ç~i¿C yvÖÛrò ·¥TµwϼKl»gÂ}‡O~Rn˜üTÂíºÁ{ný|ì³7ÊËs¦êÛ”–£vÛOþ~â0©Y£L–ÿ´JÚ(?mXwì_,gî{hÜúTW¬Ù¸^zì ©\<Ï9¤º¶›r§}ûÿÛ;0©Šk—a1ŠÑ !bpÅd"`PQLŒûs'!äEž¢ˆO”|÷í!êÓH/úp¿¸$. ÊâÜPDPq!*Šòú_c]«oßî¹·§g¦{oè{랪:çWsúÌ©s—Øq_|µÁuñ Ôƒ‘ßzÀchã8x™5WO0ï^~žÙs‡Ž»8«A ÈÝ¡]+sX÷½M¯ŽÝ ÊÇ}8qÀ fãÄûÍÏvîwˆùÓãb¯ß¹Ý6涣γŽoì„*šÎoEo_º”?dÏ3ÿõ³iëVæà?J—ñX 2'pNÿ£²m«6FÑÔR¶$­Öà„Éf³ÖUUPÄøÑS¦™ª–­ Êñh^H{h^ûÙ¬­™óì?Íq{ïi¾Ì¤„ÜÿÜ+ÍÚVŒƒ@%Pôt¯ívÊRù´>ÃÌžœ™>%øÍM8%@Ý~:‚Ú³û;¢ÃfíÌÃ'ÿ¾`ºÀ=ÇM´iQúDõýâîËŒ~¢šŸ‘4í"Êö¨5èƒJC€Èoi82K#¸ÿùWLûQ“Ì÷ÇL1Ͼ½²Vd @  DO_û`…"çsl¿#â Ï+sï’˜¯n>ßð…•9 kuÑ\9’+?ùÀÊ×lßÝÜrøØÈù嬺\cL¤0€@³"€óÛ¬¶c 4.¥ üA»¨‹ýtÖoguèN}Lëõûã'_|8³q,ÓAµAèpìîû9ç~SDù¤=°]r|}}9®!æIç·yî+VAh§V R®yú^óÒêe景ڵy•\Ÿ¶y붦ãæßK4Å[­2Gß>Åløº¶jŽ͹sánÇÏžf¬¬Õ7Ñ"CK ~_É+ÖìòWÜ/›öY¦\Ú—üwäŸúUaæÈcìA0W&í€]v ú¢,[†mÔ}ÍïŽÈ.ëãÖ—bóõ˜:çQóû9¼¿ægjúîØÙĵkö3/˜á7ÍΚïøé6÷er€]óËŹ>M×çúŒýþ|6J&‰þœ\C ¹8|—~Ö4EP•¦ vÑ·›½;é€j sL&òš¤ì˜à›üœ_uýeéâØ9ÄÒeÜC7™KagÓ9Ex¯vF¢¡2jÒMÑk 8¿ ´×[·­Y™)ÉUlûðÓÏ͸Ûî·N¬ªŒÜÏ:€áùFéo_õ_úàã±ê;Ýò9yùœB­ÑûÛ›ÕWžoÂΧžùíê3'öëtiÍûÆœlk_1ï Ógd'[µ¡.»ä _ñГÁA…_¼,sèLßTNÌ•=+ôšb9¥ù^ý{ç±$~e±W‘è73KNŸatÀ­® lc\‡moŒ5Yi&€ó[»ßâZçÎÏýõ£¾JwHš_*'vҵ©]¶ÞÊæ ·mÛÊl·å–ˆË{-„g³LºÂNÛnDtì+ßD_Ý}Ô§‹þê@œÖý3‡ôt€Í·+n4Ûwä5—r­Ãé ÒA©ξ·Þ_k#êQº©ÏOÍøA†Oë–-rDZ3ßüôC ’ è€Ø¨ša ª¦ ŸBMU’Dpåû/ޏ~Øh];Ù…ÖôŸÉßtòOý.®!” í¡6^QR¥¨)÷wX&:뢣Š`*jZLSÄÔoß­jc¶Ý¢ñN=ßµè%óù—¬ J½Øq›ïvå‹<ûúºk—âàR9Ôïœ÷C3¯DvÍ·ïÍŒó[è ƒûr ±îË›‡Ï†'°pñ|þiøUY!.Eswh×!®¸•+¦ì™òuoZT›º¤èñ ‡I´&€¢ù¢Rf}~”TÑß™¿:&ÐpÆcóƒÜÚ 3æE·mÛgI®û|½yïãu6!*rš%\‚å×Þþôó6…BÎê´£.*‡Ù©¢4Eÿš9\×¥ý–¶Û?˜çÛ—/šëæJ%vcø,ç7Ü8&Òt÷çô?*8è–D‹bÊž7Ãè%]·ú¾Ñ +þüÂcE—NK¢+²€@ó%@ä·BöÖþ:•ëõUΰ«áRš"Úùû¹ÑßÁ»u³¦É®‡_~Ý™™èÓEÝA7}Y¸ì¸ClÚBû’D‰)ˆ0*œ€ºíµÝNÖ Uah3i˜ÙdâÁyº\vrpðÍ•=K‚@ùº£ø¯à…JجuU’)… Eç7 Gù޸误a}¢¾ŠˆVµª üû¹µÊ/VSî¬J‚j3u´-SVH¦®gŠþ.Z¶"K,‰]ŠÐÞ8üëÜú“è ›«Øà§-¸êuÙçó¹cÁ‹þÔ\C Õôªàª–­-ƒ89¼ÊµýŸçµò®ìYR€zaÅß—×þ·ÉžK:ò€œ_G¢>ýèoܨ¯*)¨Ž®krŸ›4Ú SŸÊ}ùoJóÆ#öÚÝ<|Î/sK½¹í£k/4}»uqÓÖëÓ9¤š$®]þ‚ª ¬oœ{È~A·_+ØE¶õPÕ3fýýY+e_]|‚¸€@ è ›RԢʛåCRвgÇϾ(ˆ +í¢WÇÚ¿å[“~@ùó›Löû5xûç±r}]õƒ(s”×ûë?Þ•óèØëfy³îàXŽP ;ürnqíŠZ^/¥p/¦pÏU+ؽ\Ãõ¹gz]!û¢^âæài$pjõ›{+ۣʛåc⢿Ã{‰Uö,jE¯;t”-æ^¬5†>@QˆüFQ)Ã>E$UW-ÉËÞXýAŽ5¿ïÔës^ðà]Þ¬œ`½`#ÜÕÛÛv<çâXxx|Ô½¢¿ŸdÜÕõ*ãðX§«ËñõŸË¹ïnn1«$³Î¸ùêœyFœ2*§¯Øý÷é‘þüá«X~Œƒ@%øÄ†’ý7JöwêjËýÉ*›6pРe£L+Bä·Œ7ÇWͽy-IÔ×Ï5 @€€18¿ð[àÞ╺°a¨@€@ÙÀù-Û­ùV±ÑCúÛ¢¾ß2á € Cç·j8†¨o#Âf)@€š=œß2ßbõ•š¼l¡Ì7 õ @({8¿e¼E~ÔWe»æ½øjk‹j€ @ ü Pë§Œ÷H/h?jRb ‹—x!@€ #€ó[a†ºHÞÕµ/tIƒ­Ø@Kç·qy³ ƒ@/œß” bó[ 5Æ@€ T$œßŠÜ6”† @(†Îo1Ô@€ P‘Èù­ÈmCi4o ÏÏ1<à$t@€@p~‹€Æ@ a ,ÀùmXÀÌ@ ÅH{Hñæc: @Hœß´í8öB€ ÀùMñæc: @Hœß´í8öB€ ÀùMñæc: @Hœß´í8öB€ ÀùMñæc: @Hœß´í8öB€ ÀùMñæc: @Hœß´í8öB€ ÀùMñæc: @Hœß´í8öB€ ÀùMñæc: @H–i3{!ò'лº¦ü•DC@¨H8¿¹m( æM ÎoóÞ`¬ƒ ЄH{hBø, @€ иp~—7«A€ 4!œß&„ÏÒ€ @K€œßÆåÍj€@  ÏÏ‘"8 € Pœß" 1hX p~0³CH1ÒR¼ù˜@€ÒFç7m;޽€ @ Åp~S¼ù˜@€ÒFç7m;޽€ @ Åp~S¼ù˜@€ÒFç7m;޽€ @ Åp~S¼ù˜@€ÒFç7m;޽€ @ Åp~S¼ù˜@€ÒFç7m;޽€ @ Åp~S¼ù˜@€ÒFç7m;޽€ @ ÅZ6”ímª65½_}¼¡¦g^@ Ìèó•ÒÚTU™O|^)ê¢' Púß= "°Iægãò¥«¡@ l,\”‡ @HBç7 -d!@€*šÎoEoÊC€ $!€ó›„²€ @M AJ­_¿ÞL¾h¢ysÙ›æüqM÷nÝ ’[û“uëÌÅ“/5­Zµ2OÍÒ\;ã*ó‹“Gšû h]¤ÇSóŸ0~²°^Sè,î]8=¼®œËž=z™Ñ§iZ|§EÎ3: @€@¥hÈïòo›·ßYn™Ì¹ÿóÕ×_U*Ÿ¢ô~}ékfäè_šwV¾SÔør´è¹…æ¬ñcÌ—_~Yê  @( ‰üÞ;÷nÓ¦MÓn‹mÌ’×–˜5kÖ˜m:lS…‹™¤oM?£Ÿ¦n墇ã/î¢çŠÜßvçÿšã>Ñ á€ T4’G~?þäcóÂËÏÛT‡Ã†þÔ|úé¿ÌKK^ªhHiS^_\Î3Þ~yzÁ|¢¿iûÀ^@€@3&PòÈï‹/¿`9ìÕ³é±{µu îºw¶éÿãþ6ÿÖ±tÑE—›{ÍõWš‹Ÿ±Ûoë _WIdÝüþ§ËqŠt^~Í%Áº%£~§ƒ¢¡~ ëzÇ=ÿgîÌØ«öÀCs훳î™?wT¾´ô}ù•—Í„s.0ÓoºÎæU»1QòîYÒÏ6­Û˜ŽÛv4Ú×dÛ_Ÿx,“Ç}¡9÷‚±–IÛ¶›™IçO "ûqípsÆå/y¥“Lšö[óÕWÜð¼9åQz¸}s‘DVC¢äÃìã° ëÁ= @ O ä‘ß<ý”‘C´k÷]Í›oavße³æƒ÷Ío½‘ךÙwßžå€J~ÔØ7«V¯Ê“D6g°×!gv¤ñYëêñ·L7>þ¨'Yët)‡7ìøJ¨®Y“ä¹qzè@^¸Mž6Ñüé¶[ÃÝ6š>~â¸}.½êâHf9ÄèXÿÅz³ò½•¦s§Îæ;-²Mnüã ëøjflß¾½½ϸv8»Ý§R=““;œÝqø+Ò*'Ù—ÕÜÎn1Ú«WuÄ¥ûÜy÷Ù/`~DÚÉú9èIdµžÓ9®ùXi. @MC ;¤WOžÍ8¾r}‡i·]v·©ÎéˆZBN¥_møI#òæ›&‘ZK}r„=»À:Hç¤cìØµ›‰ÊSsÚYæÖ³rPE¶‡94ß2uöûzøŽšJ— ™ô‚-Zš…‹žÎŠVêùqG8ŸÊÑzà0u'jŠ„ž8⸜ŸÓÎiÉÙTºJ¸ùkëYR;|ù8üÝ_|Y­ëç&?³p¾ºò6ÉNš0ÕL¿â†€[>á(Y_ç${f•oMú³ ô®®1áŸl î @Å(Yä×9RCN•~²Ûz{ðÍESÝ3EÑ”"á7—.¡ÜÖµ®ÍThg'‘õç _»?éïÚ}· Bíd¹ÕO¡&[]¤µ\]Ï é¡±2ß¶ïd–-_f¾þêë ÅA\å(—ª…£Üþ¼¿ßÑ¿5Ií($æ/ÖŠ êàäYçÎZ׿yï½wí÷»£H±/eOÙB:Kð¼¢6©'IDAT^9ݬ\?Ÿ… ôÊ8¿4@€@C(™·´0Iʉõ•Ž:øæ?÷¯;ïÐÅþ©{íGß:¿þsÿ:‰¬?.îu©œÝ¸ë…å”f /á/a¹¤÷QaÒ9’È;;ªªªbsNg]ü/ŠÔ»Ô7Î}! §N$‘usút6’á @MG dίþ4­åPùΣ¾ù)ùL_öö[6-a«v[å ú“ȃ\\wÃÕY޽²_¦\u‡S&Ý´jS³Õ–usH4i;;ä Æm~Õ ÷ƾ8cåÔªù¿{ºW9\»8‰¬æ(Ôœ…dx@€@Ó(Iί©¶o¾QåPöܳ·µ2œ›UØÍv$’ÈBꪨ_ï°Žþ wV¼íßÚëðK.r2:ॴð-'+]~Òï'î¶l?“Ú—¿ Ök¡•V#Fr€ÃÍÿ]Q•ŒêL©9Ɇ÷Uãô;t±'ÛÃId56©C+ŽÀ‚Œón‚ ည!Pïȯûs¯{ÙA!%†e^wUºkìã2eö †Êá»dêå‘Qä$²Á„Šä©ô•¿®Ä<ÔœyúÙAeõ)'4,§~å7Oíª¬ß•|²ú½ºö²éY“ÈÒ£ÒöªŒ~mP€ Ш6ɬ¶qùÒÕº¨SÄXåÂV½¿:ëõ¸QŠ$‘O PYfÜ|uŽÂ#N•ÓG ¦"Щk--?ªlÚÀAƒ6–2e¬H½#¿elªA€ @ ‹Îon @€š3œßæ¼»Ø@€ E ÞÕ²fKpã<Å’D6Î|È@€ ¤“‘ßtî;VC€ TÀùMå¶c4 @H'œßtî;VC€ TÀùMå¶c4 @H'œßtî;VC€ TÀùMå¶c4 @H'œßtî;VC€ Th²:¿©¤Ñ€@,½«kbÉ!@HJ e¦­ëÔµÃw“D€ ¤•€ü§ 6”›ùë2 áÓÞ1¢A€ @€ @€@³"ðÿÿy6pºœ6IEND®B`‚trusted-firmware-a-2.2/docs/resources/diagrams/xlat_align.dia000066400000000000000000000044521355360272700244500ustar00rootroot00000000000000‹í]s›F†ïó+åÖ–Ø⣩“IfúqÑi;Ó´·$°Lƒ@ØŽnúÛ»ÙB_Æ{6&~•±&’W»,bßg÷õ9ì¾Îã6Ê‹8K/bhŒ(faœÎ.þùÜ|xÿæÇ0~?³<˜òiQ½º\—åâ‡Ñèîîn˜,‹ Ìòaß ‹hô_$ÁH Þ¿1ŒfaPÕ{ëwƒ²ÌãÉMi0.“`úe–g7i8¨K­ËM³$ËÛ ¹¼½Z=£u5£­z©{Ì¢I_ŽWmʇïŸRõ"Êw«/²"–EÊåb¯È‘zªçF™u©BJgïß~´ßÖ‡´~cSס=ÚH9òYœî·#ÏMRŸzD$OÆØ÷|Óµ]qNžßÜDos‰Þær½ÍÅÅå"ËË<ˆËý&'Y–DAZ·Zæ7ÑéíÓ ‘—ØcÝêЋ«¸,³–ã¿ ’â)¨ß~mϹ³<¸[%ŽÔr‡åõåW¦ÓU×¾dªý6.âI:ú8-•U¿TSýî·³RïÍÇ;^ umGñzÑ8?³›8ŒŠ–Ël»Ì‘š®×ÅFmg}·ÜSOLýÖ¬WM$Á2Êï5}60Ö_ìZi½Ï&ÿFÓrÝ­Ÿ“ìnzä¥qn|ʾ6Ó 9وËÁæöyÙ퉬MJÞÞ‰YdWyfîös_%ŽU=™ì֜˃ÒYÕµŸ›Cs|¶z~'¨ú¿-ŸNk0J¢ùå4ËÓý™€Šþ¬ª_‰Å~Ÿ„‚:Ô}ųëòxåöiuO²<Œò¶#7‡Â¬ÂöM!œS»§òü_nõƒsA_DÁiM×ÙÝå¹l;¨ŸÓÊ"ÃmHï²/Ô2úZZ”w§Ì±3±šªn•Û™Õ™Ó>‚c³Š,-5T½o\ó8YÊã Òb`å²R.)AõG’Û¨Œ§ASXŸ{ããàwâ™Û»[£ÛâxHPœ3 Ü­™ÝñrtýdšÝ’ÏY:—Qz3?0gxlÖp|Çà=Úðët ‰î@³Ùf ý{žyì<³Á3ð <ÏTñÌÏôñŒºóÌcç™»áÙê™h€ hš*  DÓG4«;ÑNÕ¶g MˆÓv¦u ¨j€Ú6Ôl@MÔlPsø¡6Þ@L~¨9€ ¨jÊ æjú 6î5â~jüá!„ø@ PÔÔŇ @D#ÔPã¡FˆñLj‚D5@ PS5D‰h„š«jüa"Ôˆ±øãD"€ ¨)ƒš…@PóºBkr™gëä4ËÒ‘œvz‡À4•Lsì0.˜¦õiä"=M'Ó|L³Ù™¶2k¤yüHƒ÷¤i@š:¤Á{Ô™qm*`šÇÎ4wÃ4öµÓ;¨j€ vjÈRÓJ5¡€j¬yj5Öê<µ5×~®!Q `Ø6•`C¦šN°‘ °9ü`oÀÆž«Ö¡KÀ°l‡À†l5`³€øFê|µ5Ø4DŒ a `Ø6•!#ˆÑ 6[Øø£F¨6BâF´°l›J°!rD'ØÆ*ÀÆ:BØKCì×6€ `S6d®©Û_’a‡’kŸ«1ÐØÄõlo2✠F®™C×’- ]Ï¿b(¯sya¾|±ø'ÎË9”>†a…ñ×"˜FßPA¼} 9ÿ”%!¿Ž9ñ,Ë"ŸÓ²}rùó_ϤMAŽí ¹:¤Ýa²9«eì)¦Î7Ѝ”‚S™H -WЃ8Éù¶C^_äéÏëe!%úô-ôiçÒ„@õQ :'ýŸ[¼;ÒZ•9ßU’Dgrbíö`•e¿ÄŸ^¥™C_¸D$<Ç'Ë$—Áµ} ~Bd¾:!ò‘Í+DÖÐ’Ú³Ö!»:$ CZuȆõZ‡ÈT C¯¹Mòú¡CÒªCt¨ß:$èï¾}V• ÙP"Aý" R¤UŠšW!´¨ZD*´ÈaÖ¢ñ–9ýÐ"Z¤W‹hQ¿µÈR EÄìX ¿©EÔËz -ÒªEϺçZd«Ð"fÓš¶\kê‰mí@‹ôj|ëžkÑX…1×´å\SO¬kZ¤W‹à]÷\‹Zd1{×Ö–wmõÄ»ö EZµÈ‚wýR´¨~Ë(_½|xu? sy¡&A)¥H^¯·qO’hîeÓ2¾½uz%uŽçæÝ"©±CR½í÷ýnx7HÈ|Zî¤g†ÞÕr'¹ñû›0>%Ùô‹ñSZæËW—I©ÀÎp|FC"Ëó‘h ç&Ô«mé;Ø”{"å¦Ó«+ßå´ÄŒŸ+)‹B£ÌŒßXÇžNØé‡ß}=Çú¼ÆÞêûÞ˜ïóØaI÷²–td|&IÀiYÌ9àÀ7M|³TìHü›OP½ùÄŠp–†Í'Èâ°ž{5ë¹Õrî÷¬4,éô/é< ã^pfÉr–¥‡¨×9wN«…¹ÚDpma’èfa.äi¸\úÓ;Ôfq¶m°þÑ”ÄiôÒÀ™Õ¿&uƒ‚ V¯£•Ùa¹îz\T“A‡,æ¡Av˵ONKËl§†VbxèX&YÝm@‡ÛoL@a²›€X Á„ˆƒèáo\Z=@Ûñ[€ PhpÁ7€0;  x§Ý+ð:v«c…¼Úç耼'»mFÛïE›Ç!Lx/×ãpº{Âã69„Ûu"v—Cx˜Âæ€ÍyC¨“‰¿ûê´9\¡Nü‰+Âߤ!s…º§ã•9È\ùaNÜiv9<.ë’®¶9ª5Ý&¢£bD‡ðÚ":Ú¨-Þ‰nÇËu;$v±Þ=¿ž ŠFL‡Ãïv¦‚p;p¯Ì¹<ac¨Ñó°U¤w þØÑî ÁÑð“%îM =×ñ¹Mj‹àp:¹"UL ¦ÇÖ½Nëòg–ó÷oþ¹½#ŸÉütrusted-firmware-a-2.2/docs/resources/diagrams/xlat_align.png000066400000000000000000001331701355360272700244770ustar00rootroot00000000000000‰PNG  IHDRZ˜Æw‚sBIT|dˆ pHYsììu85tEXtSoftwarewww.inkscape.org›î< IDATxœìÝwxÕþÇñ÷ ¤J€Ðk(R¥+RDPQQ° êEõwUìŠ^±bE¯íª¨ M±bÅ‚¢ Uz¯¡—ÐI9¿?Îl2é;ˆÀçõ<ûdgæÌ™³³ÙÙïž6ÆZ‹ˆˆˆˆH¸" »""""rl)ZØ8^cb Þâ&kíþÂ,ONŒ1b@еvÝ>VQ š·¸ÓZ»3´%€rÞâFkí#Y6cL HµÖ®=JÇŒ*y‹[¬µ{sþ¨é-&Yk·Îüs8^PÆ[\o­MÎ#mè;è¨o9|@†ÉóаÀõY cÌéÀ=Þâp øÐ[>ø.ŒcÔêz‹Bà4è ¬'#¸Ë“1æV ‹·˜\m­=Æ®µÅÞóÇGóH{0Ä{ÞNÙþ Œ1Õpÿ­€Š@îüÎþg­ÝZˆÅ9ácúçgY,>¶Ö.ð­è l"#¨;Ò:’ñýГŒïÃ¥°Ò{þ_àÎüvð‚Îá@IoÕ4kíÓaï6à)ïyS`^ißÎv’tŒ1q¯µ.îGÇ` ð‹µöÝÂ,ÛÑ¢2|[€îÞóoÉpBnñmhV€c\<ì=¯ÑZÁ Œ1E€GÈ|a|\8%úg1ÆTf‘Q{Ò ¸øP)rt5#ãڜՌ1÷Yk_<š:œ\ã[îlŒyÅZ»§° ôObŒéŒÊaSàlà„ Õ2|¡ªøký¼&×Þâ4kí"kík­ñ¹Ö>c¢Œ1ÕwaSÖSÛSê0e{.ÁchôÕ¿ò(CŒ1&>œŒ1e¼fÿ°c¢1UsX_ÒkŠÊkßRÞ¹‰÷~mç”&ÎKS6Ì"ÝFFðøÐèä­ÿWc›W™*yAzNÛŒ1¦œWžùÄSÜ“`Œ)–Gš2á¾?"lj§€€7€ƒ¸ïÀg1µrÛÁû\Fýƒc"1Õ¼G¦¼¬µßû¾+r¬}4Æ”7ÆTÍéúàå]ÉSóï–ÓçºPñ¼¿ÅKsKì]G£ÃÉØSÙ(öðòË%¯\¿7Œ1Ƙ Þµ°xiBç/Üï P ÚV\­q+à\ëÚÂ|^KQ¯é>·íQƘ*Ƙ^ׯ÷–!#ýwíüÃÛï4/͹¾ü¯òÖ¦ûÖï~Çý}ÖKS÷ó“÷¹GF0´(ë¥ @ú+D.Ʊ¡ëm _ºh`•/íz¯<þëw/mÃ,çq¥ïuY2/úÒù¯õÏyÇ\è;§ßúòJZ{yø¿Ÿ&{çg<.x{ÐKsž/Í/ÍÏ^™nÍç}âÛw ®Fò, 2KºX_º}ÞëXí[—”÷ÒÖ÷Ò| Ä$#Ø\ Äzé"ÉÚýÿ;€§¼4¥Éü÷_‘ñÝ·8é°|¶ ûÃ},=pµ7[½7a·®2¿ü5=ùɸ¦ÍR@‚·ý ßöjYŽ$€¬œeßRdüí[$€ìç;Ö…¸à/ôA˜éKOFÍãÜ@’h\€Ðþ¡Ò_+ù1ƒ¹¾À·>§rÐ($à~i…Þƒ|eyÃw®«à>Ì¡²õËòúNòþ–'#óÿR5@Ý|ÎQ .гY)¸@´”/í·¾íxù7&ã";7÷³"ÞW}ÿ‡¡}× |é[z[øŽù²o{èb¸ï"¥‡Ç˃ÌäçÀ[ÀŸ¾u;€r^Úq¾õÏyŸéK}ëîñÒ•ñ>/þëÙ©¾tzë†xË1¾2Uâ¼ç97ùÖ}”ñÖǼ瑡rûòíîÛïo]Ðò'/í.ܵ»µoÅÉ ¾õozå©NFàbÉ ‡úÖõöÖuò¿¾|ýäl\` Tŵ܅¶]ê¥/JFpô‹·®§·|¨âË»Þw+p3A\¼/M ÿ>¹œ£¸Zæ¬×úø‚O2q×x<è[ÿ_Ùâ²ÇŽ;zënñ­”öíßÐ{þ”/Íé¾× H?9Ÿ-õ ÀZ{44Æ´Âý£†ú Ý/ÖÚ×­µIÖÚUöËuJŸúƘïŒ1‰Æ˜dÜ… Ô¯N€cù]çýÝ|oÝäo] cÌÉÞóz¸ ÀwÖÚMÖÒΩoOcß󬵬µ›qñ¼üd­}ÛZ»Ç;wÍÈxšc&c&â.Pà.0-­µûpÀÿŒ1›Œ1?câ¾ °ÖnÁÕàŒöÎá8`î<æÊ+kÜÈñ¯pµxe»÷K>ÛnÀ{Ö™­ îÿ+t[c&xåMÁÕèÆxÛBïgs2Å}`­]ä+×ÌP>¾ãvò§æÞºXàdDŽ_=p?>[zˉ¸Š9 n{Ùº™0fúÖ•°ÖîÀý¨¸Áëv¥·¼‘ŒkXh€ak`§1f¦1fÐÌZ›×õä”,åØá÷€Í5ž\cŒ™mŒÙnŒ±¸nV!¯õ^ü3½ÅÏ­µ­µÓp5«¹Ï»ÿú=ÚZ›lÝT<rÈ:”6ý»ÀZ;ך’—ÁÖÚ ^9Ö“ñ¾Üî]¿~"ã;ç¯å7¸Š†(`1f‰1f îûz³—v,î–6ccFãþG6“kí¯¸©‘þWipÈÛTxÝs^»MµÖÎ÷¾;ý±BhÀm2p›1æ/cÌNïýôÆ ½Ÿþÿ—¬7#Œµv¿µ6Ôÿ2t­OžôÎÓ׸šopÿ›Fa÷>îŸÜ(µNÞóm¸Úptjÿ{–mêcL}\¿’hÜ…ì\ s ®v0p'kcL=Üè2pÁÐ/Þ¸ÿà’ëpÍ:þAÛsyâï°¼-Ÿ´~?eYö*‰Ï’ïjïo¨öÀ|à2\°{Ž÷¸œŒ‹\? —¦6®OdWÜT íò)ÖÚñÀxïK¥®¡(®¯SVɸ_À!¡×^ˆ6Æ´À5³Á5‹À²7â:¶‡ÞÏ’¾<6äR4ÿyª€»Ø…„ÎS¸†DŽEÿÃ-¡i|~±9ÏÑ»ÅZúå6‡ï+¸`´®9ôroýpkmhÀÜOd\K:ã¾Ø[7c:Yk'å’w8Ÿç»€¼ç¡.K±düØ/È€škÉ\ÛÑ3Õ{º~Ö7Æœf­ýƒ‚]ë÷â‚HÚy”'·k½%cnËP¾¡ù3K[k·c.ò^Ow\_Í“€+¼ýµÖn2Æt®Æµª5ð=q×ÇÁy” ïÿæu\ÀX׌}‡·ùl²W„ø¿ãváZº"È87ãj&ÁÕXÏÀµˆ]á­+èµ>Á÷|‡÷HËe¿@Tµv®‰Ü—x¨öæ›Ç„©9Èé¢tÈ÷¼d–m¡é"1å½çYç67§Xh´Õ ÖÚá:%gÍ/ˆë|ÏK§y“|ë¯ö¦U¾ugd)WV+sÙ~FÖ„Yds±ïù‡ÖÚÿ××h€µv•µv€µ¶>®I$4mR#¯FkíkíýÖÚ:¸&™g¼4m›«3GƘË1mCËÖÚT\7М¡»sØ- ך&©½·>Ѻ)3Î&£võ2kíõ¸/®¬£çûž_•¥\¡ýýçéµÎS›ÇŒ"Ç‘ÖÚg¬µoX7ú9·àÐÿksJൄ*^"#zÏ—&ÍZûžµö|\Ö××²Ìæ‘…ÿóÜÓ¿Á÷y>×û»w»×÷ûïð_ëȸÖûgkÕB®ò­;#—ç!¡k}Y¼VcLi\·®¼äv­7Àµ¹\öƒû!o­í«5nLF0š~Þ­µßZk¯öÊÕ ×—ÐÿsdŒ¹Ç?ˆWCü½/IN×ú޾÷®=ñ×Rïoèý\ ´µÖþ®lVA®õÀy9œ§¶ª,˜÷q£©üQ~æëܬò=cŒ™…k®Aæ/ÿoŒ1ëqs f5Õ÷üVoº€>ì×(^s@è·÷kÍïràV\¼ÎÖÚï}ÍÇgc&à~ñ÷Ê!û±¸_eñÀCÞTUȹ¦./¡A3›½¦ß‰¸_‘íKŒ11ÖZkŒY€ë̾Äû›uS½iofâj —à~-û/r©äî, Ÿ1f)îýJÂõ‹ Míós.û}lŒŽ«¡ýÒæýõ¿Ÿý1?áúÀdšzÈZ;ßó®¦ôTcÌB\ís)\“G'ïøs½×s¿÷CäwÜ9ï„«e®œÇë‘Ì^Á]¯B?,³Ö¦_«1Oµ€_qÍå dL˜×µd(®†±,ð¸1æ \°z2.Àxwm8×’ð€1fpwA_ˆ1¦ ®Uܵãí,I^ÃbWcúãõ ÄÕD6Æ4ÇÝl£9Ù½‹k×:3 7@'h%Ö»¸~%€aƘa¸3êâšž×—cºáÎÅ7¸óê/ÞcLO 7®Ån-î<†~äõÞÜ ò¾£Wà~ПîÛ>1‡}Êó¼kx(P·¸xÜûÙWiq—qw(êŸË9¸Ó+ï cÌ™¸k{S`î=yÃ;F$ð‰1æ}ï<ÔÃ}gOÆ}oÿ=‡£#å‰öÀ}áú‡Ú/È!M~ƒhúç°O nD—¿SîkÞ¶’džZ&xÈ·ìDóy–<> c`Ê,_º|Ñà.Ž¡|^ÊaûI¾í£½uõÈ<ò;xÚ·ìŸÆ§™§¨Ù„ëZÎiMßÊQÌ£*ýu¾trIó¶ï=HËa{ðb>ÿ÷}ºÐc"PÒ—64ˆf ™G­‡ÒúÜLʲýdtÿÉ—®.8Îzlÿ(ìú¸ 1§2ÎÊëõé¡Ç±ø —Qع¤MŸÆÇ·®¢oÿg²¤ ó´Y7dÙ>8—ÏÚZ –—&Û o}ÜѬû†Fa× ó€•d\3hhy€—.¬A4Þu%”®}Ûðm Ðù™§(Z…«L -û§ññ¿W#ø›÷<·A4es(ÇùdÉì¿F¿â¥é–Ëyßt÷ÒôÊ%ͼï<ÎÕϸïà¬ûÄ5‡ÒùÑ|NæYGÒ€‡}iO&óÀœýdþÞìçKÛ Ws™õøOùÒ\…ëÆ–5M*Þ”T÷a¼I@ƘÖd4#&Z߯No{y2úÔ͵®OFq\À2›Ãý§ë\xnÂîܽD—zÛbq#—KãæN\BFÓïkí_>õ½m‘ñ˦°ÛZû§—¦)îWÑAkí”\^gMÜ/hpr¶ÎÅÆ˜ö¸_:¬µS½uq¸à3TÖõ¸¦€UÖ7pÈë¸}î3ÁË«¾·y¶µv§q“¡‡:P/¶Ö&æRÞ@#\­ß&¯Ìs}ÛCMð ¸ |;0ÃZû—/Mi\m\ ïœmþÈúçrü(\_-\ÿ•­À"ëº>øÓ}‹ë7µÙZ[ÑsŠ·ß àg›¥;„1¦ .ˆžm­æÕÄà.¼s²¤mŠ»UÀš¿f=_ƘÓpç¸ ®fd®õ ¼9^cNÂuW7cDRi›àÍ$a­ýÝ[IF×’5ÖÚYöy×wm/PÉúîÖâµàœŒ«<M»³ø!ô÷úÏ…RdºÆzדv¸ï„(\ Ó¯Ö  å6®Rc2îóºÎ®°Ö®ñš5;xëÖYk—åòÚOÁ]ï,®o¨Í²½4µ‹k­µË½õuqß5Ûð~üâúŽL·¾{{{×–¸ÀøWÜô>eq³‹üæ¥ u˜l3ú“úËã;/Epß/Xk7úÒÔÄ}ßVĵ¶n~´¾{cjã®»pß·‰¸÷&ϓ޾ñ^þÕp±ÀzÜ@™õ¾4±dôÍ|WÉÐ×sŠÿ»ÉK_׊矸IÊ–ØŒ~¹¡ÿöÞ9ˆÄ”¿Z_· ãn:ÑWC›æ•qеÖß³À@Š‚¬da—GD‚ñšlëáj̪­µn©äŸ$ki­½­0Ës¸©¤ˆˆHp¯’Ñïm>0¨Ë"rÔ)€)ƒq·3Ìm¨ˆü³½‡ëw=˜˜µÛ‰®ËÂõÞó㮋š°EDDD$Í)""""(€‘@@ŠˆˆˆH a¢1ÆTÃÝ“±n§­µùÝ=4‡VÜ\X5psE-¾²ÖnñÒ¼…›Lu”µv€7WŸ–ôTÜ|zYksºµˆˆˆˆ%aƘ¸ÛΕõ­~ÈÓÝZ;9ýÚànÉÔ ‡Í[p“w‚›Ì¸nÒÐrŽS"xóç]dÝ}†EDDDä( · ûU\ðø=îÞÁßz˯{wNÉÆ›]ÿS\𸸠7{àÜ]TBúâî 2 ‡¬îÂÍÿš·|>3³‹ˆˆˆÈQ–oéÝÚ)t›¥—­µ³—½å¦¸€2'·án¯”t³Ö¾c­g­ýÝZûеÖãñ¡¸[=—C>+½[ï}ë[w ¿r‹ˆˆˆÈ‘Nv‚ïyèš«²lŸ™Ã~M½¿K¬µ³ ý¾“5|iæXkwäsü—Œ1OÑ þFÖûGŠˆˆˆÈÑNvœïyèãI¹l÷+ïýõˆ·?ûá4EGÑ@¨©¼¾1¦|éEDDDä '€\ë{žàý­‘Ëv¿Ðm{êy#±ÆýÂ.óÖÚz¸A6IÀÙdÜHDDDD޲pÈù¸û9‚›Š2š“órÙoœ÷7xÀZ;¼˜€«ÉÜã=o\ÀÂڮ⭛09LÂH¼?.ؼ¸HÆ‘wå³_/àWà^ ¹÷7âúC œÁ0¡ÑÚ»qµoXkß³ÜÙc¾ÃMZ.""""ÙÕ²Ö®Ê+±Ö†›×—±°ÖZ{(HI¼»ËT6Zkwå—þHI k·†ˆ°oēݲ߉.^’ÊZ¶²‰‹VMŸDll,Mš4)ì¢È fóæÍ¬\¹’øJ¥¨Y¿Bþ;ˆ§¶mLbõâÍÄÕ*Jl…‚ߥzçòöoMƒ0È@”µ6X^BYk“ÈãÞW.¡x©~ùò/Ö¯ÜFÏ;:øX×G¯ýJ儲tèÖøˆcõâÍDF¥JBîç4qõv¶&&QçäʙާH iã:Þ¹²-·ÿ°”²5êfÛþåÃ72gìpÒÒR©Ò¸7}<-ÏüæŒÎÄ×Rºj6-]×R¹QK.y~$eªÕ`ÍÌ߈*Vü°}û!'ŸeXdèµ–©^›"E#Ó×ÇU®ÁµïýÖñ¾x誷hGËËo,p™Eäø‘´}×´z «¶aè?¸G¾ÁVJr*ï>ùߟ@Íú¨X­4«—lfÇæ=ÜüØy\uû,›·ºM«°uÃ.®oû2UkÇS4²[“(S¾}våükN \î‡z¾ÏœßVòöÄÿ£eÇŒkÿ}‡øúýiÜþÜE/›ÖídõâÍó?œfL\FƒÕr /k8ˆç>¹žÚ+øÿ½÷ *V/Ãý¯_–mÛìÉ+¸÷’÷صm/ii–w'ßA³öµ |¬cH K³îÿ¢ý÷±è§±,øþ“°ö)W§!ý>w5}÷îfÄ ]øý½¸à?¯ç¹Ÿµ6Ó/ႦÉÏ5ï|VÀ™“=Û6qpOR®ÛGùDäØ],’þw9N©Á­ßkŸ÷žþ‘ÏÞžÂIÿ¦Ñ©5Ò×/žµŽiã—¤/?÷é Ùö}u\?jÔ+OZjÞÏ«÷Å9W´ 2ªHØe^½x3 ¦¯á¬KšòåÐi™Ȭ.¿õô׎kÝáº^&®ÞNò¡”#vŒ* eyîÓ¨Û¤2g–yðoåu¡ð]¼$U›œÊæ¥åšf˲ ½¶#O5epÇjL|m i©©éÛ·¯YÆè~ÝtJO·(λ=ÛshÿÞlù¤¦$óå#7ñåÃ7’š|¨@å}íü†,™ø5C.oÍ SâøúÑ~$mZÀ¤×gõ´IL~çY^;¯#oì ÀO/>Àä!Ï2öÞ®=åE~üh½Z<Ÿ¾ý¥»Ç2òÅŸØ{4ãà–³_Ïüúõ|®lò,íbî¡GÝ'ùväŒLÛG¼0.¦KŇyùž/°i6×òÝqÁÛ:½—¼Ç¥ žæ­Gǰ51‰»{¼KǸè\~ƒnù˜û ö½P¡ZiZt¨}B7[û©RŽ˜ƒ»w±è§±X›ÆÆ…³Y4~,ç>08Ç´Éö3âÆs©Õæ,.~v8ëfMá»Aý‰.GÛÞýI>°÷¯;‹*'ŸÊuÃÆS¡^ÖÌø•ˆˆÌ¿¶ìÞŘ_B±¸²\òÜŠDFåZ¾¥¿!±\FSGéj TkÖ€­+1á¿pvÿ§‰O8‰/¾‰é£^ç컞¦]Ÿ{Yóçdj¶îHë^·aЏ2ìÞ’ÈÔáÿ¥ÓmrÎ}ÏQ¤Ö¦1mÔkÔíà‚ÌÔ”d¦ÿ/>þöß:·"rl[1#‡$Ó¦Ký|ÓnXµ=;÷gZ÷ÇO‹Y±`#›×íä«aÓ¸è†Ó(W9¼>—i©i|3|:÷½z)MÛÕ¢\åRüøÑ,º÷i“cú]Ûö²yÝÎô}ïîñ.õ[TåÙ{³|þFž¿ýS6¯Û•ž~Ëú]|úæïÜþì…ÜöôŒ}g*OÞ4†/W<ÀÜßWrÿeCyäÝž´?¿!3~^ÆÀëFQ­N9š¶M`âØy¼ûäÜÿúåœvN}Þyü;&3Ÿ†­ªçX¾A^Gç 3ðý«9©i¢¢]xsßeC‰-Ͱ)ýÙ²a/ÜñƒïËCo^ö¹’œ)€”#fߎ­ÌøðM6-™G¹Zõ©Ø YŽi—Nú†=[9ï¡ÿSª4¥«ÔdÃ_3˜ñá›´íÝŸE?e÷æD.|âmbKÇP»]çLyìJ\Ã×o¡Îé]èrß ù6WÌûæ"£‹¥/×nNz pÊ•7sÒçÐꊛøý½8û®§‰©€P† IDATŒ)FDd$‘Ñň)U:Sžåj7àô¾dÊãÕsë±+q q•k°èÇÏ)R4’zºåwúDä8¶qÍÊW‰K_7é‹y|9Ôõ//]®8¼sU®ûÿðáLbb£Ø¾y[“¸aÀ9ŽÿÛ¸…ÜŸÌé^Ân×µæË¡ä@úÍù}«mâÕïn¦BµÒT¨Vš®½Z1ü¹ ™Ò5n]ƒ+þ¯×Þs&CŸþ‘5K¶P£^yF¾ø3ç\Ù‚ó®nÀY—4eâØyŒ9ƒ¦mûÎÚ×(}û/öà‹÷þȵL±%£1Š—Œ¦diw]_:ws_ɈwS»q%j7®D¯þxö¶O¸ïÕK)~s¿d§RŽ˜25êpÍ;Í·_ÈðÞéÿóêliw¬]A¥†-2d5[wä¯`­eëÊÅTkÞ&=xÌÉ×ö£Z³6œ{ÿ‹a•ï’çGæÙ²æ)gd¼–êuرvE¾y&´î”i¹tÕêœÞ…™¿Ã™·?Ο½M‹ËúQD.‘Y…jîZ·mcRúó„9÷ªÌž¼‚‰_äÞÝà‘wzR£^yÀÕf^ÙäYÞûýš´Iëø_¾÷ O©Î¼)«¨X½4s~[™àåeóºÄWÊ<ú»yûÚ 'sÙ¢Côç1±QÄW*Åú•Û¨Q¯<›MDð‡¿F3äÔž·2ëÓ÷غb«¦M¢åe¹-r¢«Ý¨‘QE˜>aiúºšõ+Ð媖œf˜žWãJT¯[Žß¾]Vú[öðë×óÙ¶q7/Þù9/Þù9£_šD\|q¾–{-_HérÅÙ±y7I;ö¥¯[>?1[ºˆ"¹·•*K÷NãûÄÇÓ?ïÄ‹cûP²t16¬ÚžiŸ +·…õúüÇØ›t[2ú†®÷ò(U66P^’H9*RS’™ûÕ(Фd…*Ù¶'´îÈÝ;Yþ››F'åÐAÿ‚Zm\GòZmÎfÿÎm,øáÓô}¬µX›Ñ©ºlõ:\?êW~ÿ)㞺#Ӷí|í†ìX—$@Ý])Å'w÷¤n‡®ÄUιˆœ8J—+Î5wŸÉë¾aÉœõ™¶å5X$'s~[Éš¥[¨\³LúºoGÎ`í²­9¦ÿvÄ *Õ(Øy÷3zö½éþ/vç›áÓIKÍý‡:@“6 ”*Ë'ÿû´Ô4¶mLâûf*óé4â›3HÚ¾/Óú½IhÙ±SXœ>àå¯?V§7ûç¦Vʬ_‘dÖo^•’¥‹ñý–fÿÉê·¨–ÞÌ-§&lÉdDŸs3ÍX¹q+.}a“‡<Ëìφ²×vîÝÍkç5 DùÊôþs®ym[¹˜7{¸‰¹·¯^F‘È(.zê]ŠÅeŸ 5>¡gÞñ£ûu£Nû.l\4‡È˜Xº?õ.åë4¤ó=ÏòéݽømȳT¬ß”Õ3~å¦ÿÈ”_\åê\?ê†__?z3ݾ™kMâÈ»fz­‘Åb¹ù³ð.‚õÏîÎÇw\Nâü™”«Ó0½œ91´ºòf~zñκãɰò‘cOŸÓÿËέ{I\µ¡OÿÈ'ÿûKonG¯þrLÓ£]9t0…Þm^¦~óªTN(Ëîû˜?} —ÞÜ.ÏcÝÕý¢¢‹²s«ëyÁ¿NåÂÞ­Ó·?yã‡<ònOª×-—mß/Þ›J—«Zd[Ö%ÍtËÇLýq1õšUÍõر%£8ìj¼rc‡L!iÇ>zÜØ6Ð<‘½îìÄüik8·ò#´=·%JÇ2Új®ü÷\qÛé\{ÏYüúÕ|.ªýÍO¯ÍâYëhܺFžyvíÕŠgný˜ß˜LÇîM¸êö3xàËØ{4>ÃöÍ{صm//Ý7Ï|¾ýg¶ãÏ}r=¥Ë§o§×Ò× è5œèb‘ÜûÊ%´éÒ ì×~¼0G²–æŸÈóp.Ï,…bqù¦ÏÕ¨Öì4n3õ°•­0¥<Àº9Ù_Kt‰8*7jÁö5ËIÚ¸6Ó¶¢Ñ1™øíJ\“ÑgÐbKÇS¶FÝLw¹Ùºr1EŠdš¸|ó²ù¬Ÿ;âe˓кQ±%2å»}ÍrÖÍžBZj U›´¦|ÝF¬õ;åë6&¦¤{O÷'í`Ó¢9TjÐ<Û@—Ü^«‰(BÍS\‡ïUÓ'QµÉ©DƸfŽƒ{w³iÑj´Ê˜ ͦ¥±iñ\R“Qµik¶®XD‘¨èô‰Òýæ~5ŠñƒâÎñ+ Ô4þO6°a 4`ܸq…]9ÁŒ5ŠнO›<œ-s_Iò¡ÔLë*×,C•Zy÷µK\½¥sÙ¶1‰ªµâiвZ¦&Ö…®¥BÕ8â+•âÐdæMÍèGEµ:ñÄÅgL´bþFúvz•/Wü‡Ø’™§œIMIcöäÔmR9Ó>!‹f®£T™b”¯Zš¹¿¯¤YûZ,BâêíìÛ}:'WNO»ï!Ö,ÙLÍú5x"?Œ™Å˜y÷»2,ØH±âQ™úIΛºŠšõ+PªLæ×¶tî"£ŠR¯Y•lùOýai©–SÏ:‰­‰IÄ–Œ¦RŒšÖ¬îOfñ¬u”.W"½/ç†UÛ™=y1Å"iÙ±nžS--ÿ+‘[³O‡Ô°UuŠFIï3êWçäÊaOßt¤|5l]?šöO”¢a¯‚×®Nº7‰¥Ÿí¨e­]•WZÕ@ à‚Á¬@üÊÖ¨CÙurÝžU\åÄUÎû×b¹ZÙ§¯¨P·1êæ~›ªÜÊQ½Eæ_ëÅJ•Éõõä÷ZNÍ|‰èâ%3àjý·>,W;û/дÔTölIä×7Ÿ¢Ó¿wÁ£ˆdhÚ®`w%©\³lž·#ôO]I«N¹Oø ®ŸßíÏ^”-x(R4"ÏýýNüé²–oæ¤e”(]ŒªµË1qì<ƾ3•K|µ¦µe¿LN|¶ªžëÔ<ÅŠGqæÅMÓ—Ãé·],2ÛûP%¡lž·&ôó°9ÉïÜŸH@ŠA³>}—‰¯¤Þ™ÒüâÞ…]9É{E‡l^¿‹çþý)Û7í&¾R)º÷9kï9óˆWþ9@ŠA­®èK«+òîo#"r¬éÚ«]{µ*ìbH!R{šˆˆˆˆ¢RDDDDQ)""""(€‘@@ŠˆˆˆH EDDD$""""ˆH D¤ˆˆˆˆ¢RDDDDQ)""""(€‘@@ŠˆˆˆH EDDD$""""ˆH D¤ˆˆˆˆR´° `Œ)v[k·vyDDDD$waƘÆÀE@+ b­íæ¾uþÀÉ@ `°øÔZû…—ìm ðÐÏSîË&Ø ü ·Ön çØ""""rø…[yp†köNg'cÌMÀk@”·j;Pˆž„ÈY@1`¾·\ 8×{¾Ï;n oùcLSkíž0Ë.""""‡Q¸} GÍkÂÍØÓxÏ­µ pàoýÕ¹í`Œi¼Š ''Ykãq5˜Í€w}É'À)9duµµ¶$ÐÛ[®… @EDDD¤„@ZkŸõMôþþámÚ‘Çn½qµ–û«¬µË¼ýÓ¬µs­µ÷ûÒÞ |ܘC>Å1ñ@ߺåá”[þÙlZI×qhÿÞ#vŒ53cÃü?sݾsÃjþøÙ;¾ˆœ8Hf󺤥ÙlÛÆ2‡MkwB©Ž¼=»ðÕ°ié¯{Áô5Ìž¼¢PË4õ‡E¬Z¤ÞnGRàQØÆ˜Ö@g\³òÐ<’6öþ.õY4ÆœcŒè{Ôã#qýŸö–oµÖ® Zn9úžm]–Eã¿ÈqÛg÷]Ë3§–æå³kñt‹Œê{>{·mÎ1í7ÝÊ“Mcr}ÌøðÍ\Ë0ë“w™?î£\·oøk?>_°&"'„Ô”4ž¸ñCz6{Žö±÷òÞÓ?æ˜nÒó¸¢ñ3œ^â~.k8ˆÓcïåŽ ÞfÞÔUéißõ9‹g¯`ÁŒµ´‹¹'ýqI½§tËǬX°1ì²¥¥YÚÅÜÃùÕ²oÏÁôõIÛ÷Ñ.æVÌ/¯™¿,Ïõu…kˆ]È…½[°7éo üŽó7Ò°U5ι¢ß8“?s!c^ý…Ú+³zñf~ûv-:Ô¦{Ÿ6ÄÅg¼žuË·2â…ŸY»t Õê–£÷©’P6}û´ñKøäÉ)Z„î}NËóœ½1ÀÕ}½ñð·Ä–Œ¦í¹ 8ó⦤$§2jðDþœ´Œ¥bèÚ«g\T°úª¦mhÚ6[\­ÂV ¤1æ>\SrÐjŒ‰1Æäõ_>HÆ šæ‘;€5,kM ôß’ó­³¶®\L¥Í °ß"ÊÕn@‡¾R»Ý9L:˜I¯?–)ͼ¯G³à»iyY’÷ïãÝ^íÙ³-ç¾13ƼŗúP¾n#Z^Ö‡S~âÃÿ»¸@¯IDŽoó§¯aÏ®t»®uŽÛ#Šd|Å~;r‰«3سë»wîgñ¬u|ò¿ßhÙ±N à uçú4:¥:ï=õCŽÛ×.ÛÊ¿N}‘}»Ò£OÍ\Ç5­^doÒââ‹S÷äJ”,]Œv]Ò®kCŠ—Ìþc9ùP*‰«wÐãÆ¶ô¼£#»wìã†v/s`ß¡9ç÷•LŸÑ||Ço3sÒ2º÷9ƒR¸ÿò¡|3|zúöß¾]È“7}ÈìÉ+8·gK¦þ¸˜¯|?}ûªE›¸¦Õ DD®üwlšåšV/¤g³'¯ ÿ…C(W%Ž3/iʾaÙ¼ ¹ž³–븿gÔ¡]׆ԬW€‡®zŸÏ‡LáÌ‹›R¾jõÎWæåšÏ‰.ÜÈA€Á5]û;”­ÅÍ혵vŽ1æà9 °Ù³–ŒéxÂ5Ôó6PÞ[NƧ媰>}ŠDå“Tކ%¿fþ¸èûéŒÀû6<ç’ôçµÚœEñø üøü}œyûãéëSäê!ã0ÆÐ s^;¯ÓG½ž) @jJ2?½ø]î{–—õ æ©g0¸c56-žKÅúM ø Eäx´vÙVbKFSªllúº9¿­dþtWOR¶B ºöÊ}Ò˸®ýɇR©R«,ïüz{Êñƒ.ä¦3^¡WÿNÙÐáϧÎÉ•4æ::_Þœ³Ë àó!S¸æî3©ß¢‹g¯§S&¹æ],’»_Îø!ÝþüF\˜ðÓ',¥C·Æ¹î®åìÉ+øjÕ¨\³,ç\Ñ‚¤íû˜úâLéâ+–äÉQ×pòi5¹¼Ñ öï=D±âQ¼ùŸq´>»÷¿~»7añìõ|>d ×?Ø™aÏüDÇîMқ͛¶M [ÍÌ ~mº4ðþÖ§J-,›—È„Ïæ2|Ú]4:Õ…5QÑEòØwé5©Ç‚ec÷³u^r÷ß43ýGAl^é ür9×Væ9ÄÉZ;Ø3¸ 7‘x\Ðùð¡—/¸ ÂËK¼å¾màzìÆ5a±ÖÎ ³Ü9I`úÇ# 9\Öü9™OïîEAC©X/÷ Xn’6­gÊÐY1e<ÛW/%¢HQ’ìË”&á´31Ƥ/×j{6[–/Ì–×Îõ«8´“ßÂ’Ÿ¿J__4º[–/T)"™”ˆ‹áàþdÒRÓÒk·oÞͪE›X6/‘ûå@~—ø8¥ÊIJcË>2…Ë â‹ådjº GãÖ5hw^CÞüÏ8îÜ#Ó¶å%ÒöÜéËE"hÕ©.ËÿJ tŒÏ‡LaâØyÌž¼c`ÿÞCa*_½x3UÊR¹fFssëÎõ²§ûÑjuÊÉŠùiܺKf¯'¦xw÷Șýo÷Ž}飬W.Üĵ÷œ•¾­R2T«S.Ðë[þW"qñÅiЪº¯œõ:è§ÀÝ Ó¦?“ÙôgÁHŸ²ù%+€´Öž•ª\÷\—OšG²,o:ô˜ùX”ãâÇ!²XÁsùèÞÃV Õº90º_7º>ô2Mºõ*P“ßÄÁ=Iô|ã âªÔdåÔ ¿¾s¦4i)ÉÙ–³ö‘̗҃\O\•šéëOïû ekÔ)PùDäøX³ì¯Dê5« À™7åÌ‹›2úåI|ý~xÍŸeÊ—àºûÎfÄó˜ôÅ_\tCÞ}ørrëSЫùóÙö5†”äÔLëRSÒ0†p­\¸‰Wîû’×¾¿…:'W"&6ŠË ÊÔÇ37Ñ1EÙ“t€´4K„wÌÝ;öeK›¹E0"„i UǺœÛ³e¦4¡šßˆCjJöׄ‰0îõXëéyF8W…­ÎE1T:µà­«K?ÛÏæYÉ÷4À?ä^ØG™›ý´žP,.Ÿ¤yPù·¬›ó#oêÊ9÷>O‹Ko(p> üœÏ £tÕýôy¶4+ÿø™´ÔÔô qÅï?ÑòòìSŽ–©V›âñز|!Ï»¢Àe‘C£SªÓòŒ:¼zÿW¼øÅDEü+5qõvöì:ØYkI\½ƒøŠ%‰.™ïþµU¢k¯VéDB´¬ÎoãrÛÓÝHINåÏIËø¿AnK¹Ê¥òè1é‹y´èP›Æ­]ÓîêÅ›Y¹0¼9Zƒ=;÷ó׫iÚ6k-¿~lÔw“6 Ìù}e¦ft¿“šVáω˸òßg®kAâêí¹æW42‚¸øâìØ²7½ »~óªìÙu€ySWÓ¬}-þøq 5ëWÈÜþ“U:5І½ ^9¶yVr(€Ìwôω@ÊQ4ãÃ7Y>ùûôå¢1Å8»ÿSŒèÓ…b¥Ê8ÿO¾~ÔMô]$2Šó~%Pþº\Ê„—´q+§N`ëŠEÙÒ”ˆ¯ÈË[Óꊛ˜óÅRäÔžÙ§ 2tø&c¸Ž-ËæsR§ 8¸{‹þŠKŸEñø _½ˆëÞztÛ6ífÍÒ-Øwˆ-veª {äÝžÜÝã®iù.nB¥eرyß ŸNýÕòÌûõ‡¾!*º([“˜>a õšW¥óåÍ8°/™‹j=ÎK_Ý”o?þ»riý§2­»îþ³ùþƒ?éÛñUμ¤)Ÿ™Bù*qôðF*·8£‰«¶ót¿¨’P–7¶Í6šû¬Kšñöcßóî“?]”oGLÏÔ$—„éÕ¿ýÎ|®½Zñ×´ÕT¨Z:P­ÞmOwãºÖƒésú9çŠÄÄF1÷÷•´9·]®lAŸ‡»pc‡W¸ÿò¡4?½6Ÿ¾ù;«—Î5?c §u®Çà»>§]׆4?½6­:Õ¥Çm¸»Ç;\uû¬]¶•ÇÌâéól@å·q Ù¹-s¬ÕïñóIMIeÈãßsè@ Cÿž’eŠÑëÎŽ$4¨ökÿ'S)GL‡~²5ŠÁ˜ÚöîŸ-}DÑüeÇU®A§ÿ{”"‘îáÙwbá÷Ÿ²jÚDª4nÅ9÷<›i: úgw§I·^¤:À¢ñ_P½E;.ü!1¥ÜÅ¥|FœvmFÇõ†ç\L|ÂIÌýjË~ýŽñiÝë¶ôéƒDäÄR¦| Œ1\Ò·]úºâ¥2F*W¯[ŽQ3ïåÛÓY6/‘Y¿,§Zr<<äJZv¬›žîêþH¨ï~„–¯GßG»¦o«P-Žó¯=…öç5LïK¹nùVŠ—Š¡iÛ„Ëe ô}´+•kfLJR%¡,íÅš%[([±¤Ë»j̹ߘÌÂk9ïêS¸òÿ:ã®·±%¢ùbÅ#Lûi ëWlËqþÈõÊ3dÒ¿7jQ1‘<1òZ–ÎYOÍúÓÏQßG»R¤ˆ ÛžÛ€ý{3FhhrQ® IDATßùBwÚt©ÏŠùéÖ»5s_IÒöŒ ë¼kN¡ZÌרÞt¦bµÒé¯á£ùð雿±`úbb£8ù´š´9ÇÍ«Y¿E5Þùõvƾ3•õ+¶ñøˆkX¹`#µæ¨=:´³'¯`þ´5éÍݽuÍÚ×bæ¤å”*Ë›n£i»Z¹æqáõ§±quö–Þ¢EÝ{X®’›~Îÿ^ÿZêcíq8»eŒ1ßçòÌҿׄ}Gª5;ÇL=le9 lAà 7.ç;2ˆ)£FbÀ€tïÓ†GÞ¹ª°‹sX~i"{’d >ŽU›Öî¤Bµ8Œ1lX¹»º¿C»® ¹ý¹‹ »hǯ†Mã±ëGÓþ‰R« {Ò½I,ýl?@-kíª¼Ò?¡°ˆˆÈq¢WÿN…]„ÃæƒÿNâÛÓ‰¯TŠeói~Cz?Ø9ÿåM¤ˆˆˆ1w¾ÐÞtfÇ–=”¯G‰8ÝÙëx RDDDލÒåŠçz«E96…u+C‘""""ˆH D¤ˆˆˆˆ¢RDDDDQ)""""(€‘@@ŠˆˆˆH EDDD$""""ˆH D¤ˆˆˆˆ¢RDDDDQ)""""(€‘@@ŠˆˆˆH EDDD$""""ˆH D¤ˆˆˆˆ¢RDDDDQ)""""(€‘@@ŠˆˆˆH EDDD$""""HÑÂ.À±lÝÜi<Ñ4¦°‹!R¸¬eÑ¢EÔ«W¯°K"'˜ÔÔT¾úߎœQÈ¥)•|‰H_`TÉ÷=ÉU=E‚ã•R4þ6§ÖÞ(dŒ9ø¨±ö¬ÂN.,ý“¹}Á#Á í#¹y¦"§¯ßÓˆI©Zž~ôoÙ%"DÄÍÑq*¥”zrš@*¥ž*6lÈ’%K˜7oµk×FDJ?‰È)ùÌúÉVJ)¥^Pš@*¥ž™²eË2yòdÖ®]K‡ðððÈ ‘Ó"2YDŠ8:F¥”RöÓR)õÌåÉ“‡Áƒ ýúõ#K–,n@`¯ˆ,‘ZŽŽQ)¥Tâi©”znÒ¤IC·nÝØ¸q£|ûí·øúú PøKDv‹H'Ñå´J)•Äi©”zî\\\hР‹-bþüùÔ©S''§W€©Ö>ÉA"’ÉÑq*¥”Š›&J)‡*S¦ “&MbíÚµtìØŒÀk"ù£ˆstŒJ)¥bÓR)•$äΛÏ?ÿœ­[·Ê€È–-›àì‘"RÛÑ1*¥”²ÐR)•¤¤Nš®]»²~ýz?~<¾¾¾u€•"²GD:‹ˆ»ƒÃTJ©—š&J©$ÉÅÅ…úõë³hÑ",XÀ›o¾‰““S1`Šõs·‹HfGÇ©”R/#M •RI^éÒ¥™0aëׯ§S§N¤L™2#ð¹µOrªˆ¼âè•Rêe¢ ¤Rê…‘3gN ÄÖ­[åÓO?%{öìn@'`·ˆ¬‘7DD§RJ%wš@*¥^8©R¥Âßߟõë×óý÷ßSªT)€ÚÀr,‹nºhŸ¤RJ=;š@*¥^XÎÎÎÔ«W… òûï¿S¯^=œœœŠ“­·‡ˆHGÇ©”RÉ&J©d¡dÉ’|ÿý÷lذ<==3ƒ¬ n¦‰HqGǨ”RÉ…&J©d%GŽ|úé§lݺU DΜ9]ŽÀ"²JDêjŸ¤RJ=M •RÉ’§§':ubíÚµòÃ?Pºti€×eÀ^é*"ŽR)¥^Lš@*¥’5gggêÖ­Ë‚ X´hõë×ÇÙÙ¹00ÉÚ'9LD²::N¥”z‘h©”ziøúú2~üx6lØ ]»vÅÓÓ3=ð©µOrºˆø::F¥”zh©”zédÏž°uëVùüóÏÉ•+—+ÐØ)"ÿˆH=í“TJ©øi©”ziyzzÒ±cGÖ®]ˤI“(S¦ @ `)°_DºiŸ¤RJ=LH¥ÔKÏÉɉ:uê0þ|/^Lƒ pvvö~‘Ó"ò…ˆdstœJ)•Th©”R1”(Q‚o¿ý–7J·nÝH•*U:` ˆœ‘"òª£cTJ)GÓR)¥â-[6úõëÇÖ­[eÈ!äÎÛh‰Èj©¯}’J©—•&J)õ)S¦¤}ûö¬Y³†ü‘²eËT–Á"ò®ˆ¤tl”J)õ|i©”R‰àääD­Zµ˜7oK–,¡Q£F¸¸¸&Xû$¿‘쎎S)¥žM •Ä^¿ÂWŸÊ\7Î""üîS™K©„/^œ±cDzqãFy÷ÝwI:uZ ¿µOr¦ˆ”ttŒJ)õ,¹8:•4ܼtŽEý;Òð«i¤ÎüpåÄö ݼŠóÁ»H›#/uŽ{ä|{—Ï#hÁ4ÄɉÌ>Åñ®ð:Þ~5'Ë·¬ý1nžÔýôÛ'ŽR“R´ÿ;¹KWJplô{}PêÌÙiøÕ´DÝïèæ¿I9;™ µ;V•|dÍš•O>ù„=zÈ‚ ˜:uªËñãÇÛmDdð °ÔåàP•Rê©Ò ¤àÞPo\ɽ°Ð8Ïïü}:WO&ân§wnIp¾k§Žrùh0¯6î@‰mÀæõhÊžå¿>íÐíý^ T~ƒWw°}©Ý4Ñsl™ñ?oXñ £T/’”)SÒ¶m[[Ÿ¤ŸŸ@U`‘ˆ‘÷EÄÓÁa*¥ÔS£H•( ¿œ À¦©£Ù·b~¢®q÷JÇ+õZP¼þÛÜ »Ãö_~ x½Öñ^slëNï À3]& Õh€g†Ì±ÎŸÙý/'7FöW^ûüëĵöòÑ`.ÜMáš qvu‹ó^«Õ#Cž‚qžÛ³ìW V©ËÉÀ\>L±º-H“5'g÷róâYÎíbÏŸsqóLOµzœÞµWwœ\\9²é/2|…;ׯϯ)ÓeŒÛó§È_¡Ö£ê…#"ÔªU‹Zµj±wï^¦NÊâÅ‹óGDDŒ·î%9oŒ9ãèX•RêIhR=÷Âîp~éãIØVŽèÍì.u¹zü[¦ÄŹtxŸíüßcú1µUyŽüCø­›¬?„°kÍsxãJ¦·­†³‹k¼ÉcB~ëÝŠßú´fí÷C8·oãëfïòy\?}Œ°ëÜ8{‚Ó»¸p`ÿþ2e_ô`fçÚ\9~;7®8o2[g}kîe_ôàÄ¿ë+.õâ(V¬ß|ó ›6m’÷ߟ4iÒxýD丈̑ҎŽQ)¥—V Õ3såØ&6zÅåc(Pù êôû&αüGÀŒ±tž»™œ¾~˜¨(æt«ÏßcúÑú‡ÅœÛĦ)£h÷Óßäó«ï=wü6•5ߢՄEäô-÷Èøfù¿³‹«íµOõ·¨ýñhÛk¯l¹ygÒŸ¬ÿá ö­übu[P´N3‚þ„·_MÊwìû}ï¢Ï†³¸º[vuqrvfù=©úÞ œœ¹zò0Ç·®±UtUò—%KúöíK÷îÝeÁ‚L›6ÍåèÑ£ïïˆÈz,}’K´OR)õ"ÑR=3i²ä¤þ‰\8°›ís`ý„aÔþäë‡ÆžÚ¹Ïô™ÉQÂ’ô‰“>Õê³æÛAœøw©3g'o¹êñÞoã#¸rì g­'}îü ÆW½çPÒdÉa{í™!K¬óÑßr—®Ä¶YãœÓ»B-[òP¨F–Ñ“Cëþ¤PÎû‘ü•êà•-w‚s©äÅÃÃ6mÚðÎ;ï°zõj¦NÊæÍ›«UD䈈Œ~2ÆÜvt¬J)•M Õ3ãšÒ“œ¾~äôõ#mŽ<Ìù¿úTî6¯ô±ÆÞ½Bê,Ùcõ3¦Îœ»·obŒ!ìæ ¼²å޳ß1Zdx8‘÷9&¦%ÊÆÛ *FBé’ƒˆð°ç|p>'gJ5ïÂö_'Q òìü}: ¾˜’¨øTò$"Ô¬Y“š5k²ÿ~¦L™ÂâÅ‹½ïÝ»÷µOrð1æ´£cUJ©øh¤zn"ïY¼[—Î?t.C^Îï"ôÚeÛ±ãÛÖ’!OAD„Ì‹qú¿­ÜºüðµÑª¾?ˆ’M;ñS›*\>üLÞC4·”©â]±þ Ò-ºplË?ü<gW7 Vy󙯦^EŠa̘1lÞ¼Yºw—Wàcจ̑ףRJÅE+*–ƒk–’*cVÛë”é3á]¾&ç÷ïäòÑ`ÎïßÉWÙóç\\SzR¨ú[ñÎu÷æ ‚ÿþ€KGö±ó÷äô-GFïÂ-XõMÒç.Àý;Põ½AœÙ½]‹fR«ï( ÕlH†<ù­wk*têC–B%8ñïzŠÔnë‘qÕ÷>ÃÍÓém«ÑvÚ_d)T"Þø­ý“s1Þ«“‹ Eë4KÔï)oÙj-˜FŽeñÌ…¬…}ã›:sv|ªÕçŸoúSåÝÏprvNÔ=ÔË#S¦L|ôÑGtïÞ].\ÈÔ©S9Òh-"±ôI.Ò>I¥TR¡ ¤ÀÕ݃¼eªÚ¾h™}Šã]¾&§‚6ÛV!§É’“ís'â™1K¼ ¤WöÜxeËMÀŒ± BÊ´(Ù´eZ¿kÛH<£wa\ÜRàìâJû«Y9¢7ó>hŽgúLÔüðKJ5ël;ßaÖ:þþº+¾êETD9J”µ%|¹KU$Ej/Êwì›gjÖŽÂ[Ã&“2m†D½WwÛ|yËVÃÕã~bš"UšX›”¯×šÈð»ü;gnž©i2j&½ ã™.Sœ¿ ÚüÏ”jîßÿJáîîÎÛo¿MëÖ­Y»v-S§NeãÆ•€J"rÌÚ'9ÍsËѱ*¥^nbŒqt Ï•ˆ¬ê0âxx=þDd&§o9ü xj±©äëÏ¡ïsçúš}3×Ñ¡‘ÔS)•Ìi©”R/ ¡jժ̜9“•+WÒ¢E \]]ócEä´ˆ|-"ºc½Rê™ÐR)¥^p… bÔ¨QlÙ²EzõêEúôéS}€£"ò«ˆ<ús=•RÊNš@*¥T2‘!CzõêÅæÍ›eäÈ‘øøø8-€Ù,"Í´OR)õ4h©”RÉLŠ)hÙ²%ýõ3gΤJ•*åùÖÏÝþPû$•ROBH¥”JÆ*W®ÌÏ?ÿ̪U«hÕª®®®¹oD䌈ŒÝ@)e7M •Rê%P°`AFŒA@@€|øá‡¤OŸ>Ð8""óD¤¼£cTJ½84TJ©—Húôéùàƒزe‹Œ=šB… 9ÍÍ"²EDškŸ¤R*!š@*¥ÔKÈÍÍæÍ›³råJfÍšEµjÕ?`žˆ‘Þ"’ÆÑq*¥’&M •Rê%W©R%¦OŸÎªU«xûí·qssËŒ±öIþODò9:F¥TÒ¢ ¤RJ) (ÀW_}Å–-[¤OŸ>dÈÁè‘ßD¤‚£cTJ% š@*¥”Š%}úôôèу-[¶È˜1c(\¸°3ÐØ$"[E¤¥ˆ¸8:N¥”ãh©”R*N®®®4mÚ”+V0{öljÔ¨ˆ”æZû$?/GÇ©”zþ4TJ)• Š+2mÚ4þùçÞyçÜÜÜr£­}’cEÄÛÑ1*¥žM •RJ%š··7_~ù%Ò·o_2f̘øKŸä©äè•RÏž&J)¥ì–.]:Þÿ}6oÞ,cÆŒ¡hÑ¢N@`ƒˆl‘VÚ'©Tò¥ ¤RJ©ÇÝ'¹lÙ2~ùå^ýuD¤ ð‹ˆ‘¾"’ÖÑq*¥ž.M •RJ=åË—gÊ”)¬^½š¶mÛ’"EŠÀ(9-"ߊH~GǨ”z:ìN E¤°ˆøY¿õxBD²ˆHui/"õl¶‘"2]DÚ[_»Å¸‡Ÿˆ”‘|"âfo¼J)¥ž¯|ùò1lØ0äã?&S¦L)ÀAù]D*;:F¥Ô“±+‘Â@°Åúõȹ‘L"28¬¦K€#"²)ÆÐ@{ ¼õu¶÷ØlŽD¤¯=1+¥”rŒ´iÓòÞ{ï±yófùßÿþÇ+¯¼â4Ö‹È¿"ò¶öI*õbJt)"ÎXÀÄVÅ@'À³žÀ@àw 棌O°$#ã˜jð°H‹åqHáÄÆ­”Rʱ\\\hܸ1K—.å×_¥V­ZˆÈkÀl9."ŸˆH:GÇ©”J<{*}€rÄäÅ¥3àgý¹1¦1æ;cÌWƘ&€oŒ±=±$§íã˜g‰1f ðYŒcìˆ[)¥TQ®\9~üñGÖ¬YC»vípwwÏŒ°öI~'"£R*a‰J E¤0˜¬LäÜÑ£Oc~yð¤1æBŒ—9€B@Ö8æé,"ß­¯±<ÒVJ)õ‚Ê›7/C‡% @>ùä²dÉâtˆÈ"RÕÑ1*¥â—`ãÑõY,’+z¡Ì©sãëõDÌSË_*Ñ­WQvÄ¡”R*‰òòòâÝwßeãÆ2nÜ8J”(á4ÖŠH ˆ¼#"®ŽŽS)[b*oe±$‘¯%cœ«("9ã¹î¸õ{ŽǶcé…´G'ëM€`ÐÁÎ9”RJ%a...4lØÅ‹3oÞÐÁfWà÷c:xã™Ç™ÂâöUÜS{‘Ó×/á±J%c‡7®${öìüöÛodÏžÝÑá¨d,""‚åË—3eÊvíÚe;.N ÎOð÷¹RÉ„K pr}ü? ÷n"à @cÌöG}œÒ‹û}1‰¸Æ(dÎû1cœ/dÎcŠH î¯âË>’7±¬è¾dWÀÇr Èø$s(¥æììlêÖ­+]ºtÁ××7á ”zÛ·ogÔ¨QlÛ¦›r(õ T6Æl|ԻȈ¬^çóà‘úñ'ºòÔbRê…öeyˆ? \^(]º4þþþÔ®]gggÇÆ§’­Ù³g3pà@Þlû}¿ëA—R/‡sùþoø LO3ÇžgÓ Ž, ÈoŒ9ú¨±/ãGHE–äÑÃëñgy’k•J~.c^‘Z@ïÀÀÀ:’3gNÓ©S'iÙ²%žžžŽŽQ%S®n.¤Nûøÿh*õ¢sO逳»à–æñaÇxüàv‰v}¶RJ=Š1f•1¦.–JägΜ :t(eË–5_~ù%gΜqtˆJ)¥žM •RO1fŸ1¦«1&ðyhhè¥ü‘Ê•+Ó½{w‚‚‚¢RJ©'  ¤Rê™1Æ\2Æ 5Æä:EEEí^ºt)7¦I“&,[¶ŒÈÈHG‡©”RÊNš@*¥ž9cÌ]cÌOƘ@-`ùŽ;Ì{ï½G•*UÌÔ©S¹uë–£ÃTJ)•Hš@*¥ž+cÌ߯˜7±lí5ùìÙ³w‡ F¹rå̰aÃ8}ú´£CTJ)•M •RaŒÙoŒù?kŸä ÐÐЋS§N¥J•*¼ÿþûìØ±ÃÑ!*¥”Ї&J)‡2Æ\6Æ ³öIvŒŠŠúïÏ?ÿ¤I“&4nܘ¥K—jŸ¤RJ%1š@*¥’cL¸1fº1ÆxXdºwïN•*UÌ”)S´OR)¥’M •RIŽ1æcL= (0éìÙ³w¿øâ Ê•+g†Ê©S§¢RJ½Ô4TJ%YƘ`cL7cLNà³ÐÐЋӦM£jÕª¼ûî»::D¥”z)i©”JòŒ1WŒ1_Xû$;DEEíZ¾|9M›6¥aÆ,]º”ˆˆG‡©”R/ M •R/ kŸä cÌ«@MàÏ]»vÙú$'OžÌÍ›7¦RJ%{š@*¥^HÆ˜ÕÆ˜ú@`â¹sçî~õÕW¶>É“'O::D¥”J¶4TJ½ÐŒ1Œ1ïZû$?½sçÎ…è>Énݺñï¿ÿ::D¥”Jv4TJ% Ö>É/1y€öƘ+V¬ yóæ4lØ%K–hŸ¤RJ=%š@*¥’kŸäÏÆ˜’@ `é®]»L=¨\¹²™4i!!!ŽS)¥^hš@*¥’-cÌcÌ[@aà‡óçχ >???3xð`Nœ8áè•Rê…¤ ¤R*Ù3Æ4Ƽgí“pçÎóÓ§O§ZµjtíÚ•mÛ¶9:D¥”z¡h©”zic®c†[û$Ûc‚þúë/Z´hAƒ X´h‘öI*¥T"h©”zécîcfcJÕ%ÿý÷Ÿùàƒ¨T©’™8q"7nÜpt˜J)•di©”z©cÖc…€ .\1b~~~æóÏ?çøñãŽP)¥’M •R 0Æ2ž¦ IDATƼoí“ìv~ÆŒT¯^.]ºhŸ¤RJÅ  ¤RJÅ`í“aí“lkŒÙ±jÕ*Z´hAýúõùã?´OR)õÒÓR)¥â`퓜eŒ) TïÙ³'ªW¯^T¬XÑüðÃÚ'©”zii©”R 0Ƭ3Æ4IJŸä÷/^¼3räHüüüÌgŸ}ƱcÇ¢RJ=Wš@*¥T"Yû$»[û$û………›9s&5jÔ K—.8:D¥”z.4TJ);c®cFcòmŒ1«V­¢U«VÔ«Wßÿ]û$ÕSsù\¡·î>×{FEFqöøU¢¢ ·n„qõâ­çî]ºÅ­aAݧ ¤RJ=&kŸälcÌk@U`ÑÞ½{£>üðC*T¨`&L˜Àõëצzî…G²tÆ6F¾ÿ=ëNbݢ݉ºîÚ¥[|ÓûºTù–†ù‡Ñ­Æ÷L¶’+çï^{¯ú“ù{ÞN®œ¡Çm_C:ÎaÙ¬íܸrû±âžùõjzÖÄõ˱¯¿zñ ò µŸûí:¾ðÿå±îñ´ w>óÆoˆ÷ü²YÛ ¹úD÷˜s*¦|ÀÎ GoŒá«nó([Ӈῶ·/R:uZ—âüÉk¼¾Ò›EÉí“ €WÊå¥kÕï¸xæ™sx%:æµì&UZÚô©Îï“7óv¯ª‰¾`ËÊ`‚wœ¦@ñløVÈÇ¿«Q³™/ÿm9Nª4°eÅ~м–›’•½c]ÅÚ?vs<ø"Yó¤ãõf¾¸¹»ÚÎ_¿|›¿çï$*2ŠJõ‹=2–ÍË÷Å–•Áœ8p‘œ2Qôµ\ì<Åö5‡HááFźEÈáÁ®÷­lMÊÖô!2"ŠYcÖ<ÖɉV •Rê0Æ\7ÆŒ²öI¾cŒÙþÏ?ÿкukÞ|óM,XÀ½{÷¦r.²ïß“´í[#ÎóYs§³ý<¾ÿR¶¯9ç8c »·#•—;²¤¶+†ÅÓ¶òf›×x£u)Ž_ xÇéxÇ®^¸‹™£ÿ±½þá³eôi8…³Ç®0íËU|Òü'>o?Ûv~î¸uŒê±€^õ'slÿ¾ý3ý[ΰ §s¥oß)×.ÝâçQÿжÌ7ܹÀÕ 7iWf ¿Œ[Çñà ü_µñœ:t)Þøî:CT”áðîsì8Á™£—˜?a#üþÇÞm'Y1'V%F²uÕ»~O*nZ|\»—;:¥’†¨€ "âbŒÑ•#°þNæsD¤2Ð{ß¾} úôéã4bÄÓ¾}{yçwH—.]3©ääÄ‹ä-”ÙvìÚ¥[\:cÙ[ÔÅÍï¢Yã½¾wÃ)¸¥páâ™ë8»83imwœ]_ºpê:Ûþ>ÀÇã›’&}J*¿õ ‹ÚJáR9¼öüÉkLñ7ß.û?ÊÕ*À€Ö??4îè¾ó,;5WgNºD«â# Ç=¥?ZMȵP€ˆÐÚw¿ý°‘¶Õ`úÈH›Ñ“éâäìDËiZø+jµ(gLú½ÎCWÒö£ê*iy!WCùöãÅ šÚšzíÊ0ºçBFõXÀ‚à‰þ]©¸iù¸¦´OxŒR/œ"""ÿ[¢¿Œ1W’bŒÙl‘üÀ—/_îôõ×_{~÷Ýw¦Y³fÒ¹sg¼½½šF%Ñ«›ÅIlÇ6,ÝËŒ‘ÿp;$ 'g'–ïõ݆Ö%K®´\»x‹Uó‚ÜaW¿Ošt)uÿ%Ó·R¬lr´<¯ß¾,ƒ;̦×× qKñèÔààÎ38»8S²J~Û±Joaýâ=±ÆÕhRWgrÌDª´ìÝv’ÒÕ °}Í!²çMÏ/ãÖÛÆ§Ë”Š}ÿž`OÀqÊÔôÁÉÙ’ç)”ÙîGÏwáî{TŽñø»jÃWøõ»õܸr¯ žvͧbÓò xeËE™Öï9: ¥êïoú“*U*²dÉâqôèÑ*Ƙ*Ñ眜œŽcl %°K«”`Œ9ô‘A@—ðððž³gÏÎ9gΪW¯Ž¿¿?*Tpt˜êÊãc©<ž:t ŸWsРc9t,DzYÛßé#¯÷ñÍaë¬P·us|Κ…ÿѰ³_‚÷6ưø§mDÜ‹¤kµñDFDr5”u‹vÇ[å‹~7÷”®¸º9ÛŽ¥JûpâšþGê)Ü] ¿kùãóú¾9˜5f Cg¶y¢¹¢¢ ‘Q .¼‰¸ö0—Î\çË9íl>€,¹‚XòÓ¶È|E²r5”C»ÎÚ’_{û ½‹eåÒÙÚ÷Êîœù3²sÃÛž°Ðpön;A…7ŠÄ;gÊT) ½ßWœ§Pfn‡„±gÛIJ”Ï Àö5‡psw%k®´vÅ«¦ ¤Rê©ñòò¢jÕªT­jùK?**J>lK(wìØáqäÈ‘«”Ç1›¹ŸTî|Ùª”Ö÷û ð‹ˆTzïß¿¿aŸ>}œ†në“LŸ>½ƒ#U²öÝ„‡Ý#äZ(‚Îð×Üä+š•‚%²?4ÖÉÙ‰“[ò~í ôo9ƒÊ‘=ozB®…²aÉ^\ègÜú÷Žî;ϵK·X¿xwÃîÅJüšN·¡uy½ù«]»xÚV*Ô-J¦¾±ŽgË“Ž¶e¾áâ™8Åx´þ ü¯d£Z£âôk9Ÿ¼ÎáÝgÙö·} d§µhûÚÆõ]LÖ¥HÖƒ½ÛN:]JÊ×)L‹î•éÓp ³Æ¬¡|ÂLýâ/\ݲ”®V€“6eÈ’Ó‹¼…³P¾NaÆôZH÷áoqå|3¿^C«•c%Î:uø2ÍÝë˜_í¤ðpeÝ¢ÝDFZÚ¶ýs §®ñj%o2ç|ùRM •RÏŒ““>>>øøøÐªU+BBBlUÊÀÀ@vîÜ™çæÍ›y¹_¥ { —2ÀóÒìØkŒÙloàƒ+W®t3fŒçøñãMÓ¦M¥sçÎäÏŸ?¡i”üùó¿Ü¸Jö|8{ü*¿MÜLÝwJÇ™@+››y{ú1ñóå|?`)WÎß${¾ô¼ZÉ›Æ5¶+R:³Y纹»RªjVY7wOéJî‚™˜9¢ÞÅ,‹nBoÞåäÁ‹d‰£ÊÅõ+·iÙ½òCç •ÌÉëÍ|Ù³õ¥«æ§TÕ¶ÇÔÙò¤'<ìþ×}5·=ÓGüÍÚE»)P<í>®ÉÄAËlçóÍJ¶<±†÷˃WzË£îü¯dã§-½˜8h95žŠ«›3}sÐi@-À²eNÿ‰-˜9z5‹ÚÊ[Ê’§Pf²æ‰±Ù»ÃÞdÅœ@¦ [Iù:…m{kŽûx1_vý•®Ôo_†ÎkÇ;GþW²±kóq~›¸ù¡ßMšô)mÇKU-À¿«ñïêCdÌîõR&bŒqt Ï•ˆ¬ê0âxØ×OË™Éé[ÿ_õ³oÕËmp'Š.Ìòå·31†C‡d«T>|˜˜7‰È k•2f/åK±Žˆx]DäcLN¡ZµjtîÜ™J•*9:<‡š={6¤ag?>›ÒÊÑá$–îå·61îÏ®ÏìÆÛêi€­fpçv8ÿ[Òå™ÝSÅoÉôm é8‡ŠÃÒPämÇžg]ß-¼ÏsüQcµ©”r(±U)[¶l Ä®RZ{)s‡„„äZ[¯ ‘íÄ®RžsØ›x†Œ17€¯Ed,ÐÌóáš5kÊ®Y³†B… áïïOÆ qssst¨*‰ðñÍÁ ©Ï6¡žôù ï>Kö¼éÙøç>n^¿Ãø•Ýžé=UÒ¢ ¤R*ÉI“& UªT¡JK«¤1&V/ePPû¡C‡*cl%8''§“T)w&§*¥µOr.0WD*½8аoß¾ÎÑûI¶iÓFû$Uœ®Ÿ¶–=*´á(W/ܤG•ü”®Z€4é·…J4TJ%y"BÁ‚)X° ­JyóæMvîÜI```t•2WHHH+ •õš»T)·$—*¥1f°IDò\½zµó7ß|“*ºO²S§N,XÐÑaªd,]¦TÔhRÂÑa(ÒR)õBJ:5•+W¦reËbcŒ9r$æŠï‡®U1úk•2æ¾”A/r•Òs è%"Ÿþ÷îÝûà—_~É5wî\ªT©‚¿¿¿í÷£”RO“&J©dAD(P   E‹Àý*eŒGß¹BBBr-­×DW)cîKyÖaoâ1Yû$ÇXû$›cz¯[·®ÜºuëðññÁßߟFiŸ¤Rê©ÑR)•lÅW¥Œ±â;Å¡C‡¬Ržz`_Ê cL¸cÞ}Œ1‘À<`žˆT>>>Ž R)õÂÒR)õRK•*ÕCUÊ£GF?òfÇŽn¬eûpj''§Ó¬øN²UJë^nÆì“œ;wnî˜}’ѫݕR*±4TJ©D„üùó“?þXUÊè^JkR™ãÆ-€ÖkÂE$Ø+¾“T•Ò|#"ã€&@ïõë×û­_¿:wîL£FH‘"…ƒ#UJ½4TJ©¤J•ŠJ•*Ù>ùÅ#ÇŽ‹¹âÛíàÁƒå£¢¢ÊG_ãäät&Ž*å]Ǽƒû¬}’óù"RKŸd“O>ùÄyäÈ‘¦]»vÒ¶m[2dÈààH•RI™&J)e'ÁÛÛoooš5kÀíÛ·c­øÞ±cGö7n4š[¯ ‘Ä®RžvØ›¢·4²öIö¼víšÿرcSÿý÷¦qãÆÒ¹sg *äÈ•RI”&J)õxzzR±bE*V´-è¶U)­›»˜7o^žyóæQ¹re[ŸdÌÏ>VJ½Ü4TJ©g$_¾|äË—¦M›–*å®]»bU)¯_¿Þ h "÷¬½”1÷¥<õ¼âµöIþOD¾½7lØP~Æ ,XN:ѤIí“TJi©”RÏ‹§§'*T BÛ‚î{)]8]¥ìàäätö})Ÿu•ÒÚ'ùð›ˆø:t¨iÿþýGmÚ¶m+mÛ¶%cÆŒÏ2 ¥T¦ ¤RJ9P|UÊûRf»víÚƒUʘ½”Ƙ“Ï*>cLÐRDò`é“ì2nܸÔ&L05’Î;S¸págu{¥T¥ ¤RJ%! U)ƒ‚‚\ƒƒƒËEEE•ã~•òÜ+¾wcžf\Ƙ@Ÿ˜}’óçÏÏ;þ|*Uª„¿¿?U«VÕ>I¥^š@*¥TW•ò¿ÿþ‹ùè;ëµkךMÁV¥ "öŠï§R¥4ÆÜÆŠÈw@# ÷Æ+lܸ‘ Øú$ÝÝÝŸÆí”RI”&J)õ‚ñôô¤|ùò”/oÛvRŽ?«—288¸lTTTYà''§óT)Ÿ¤Jií“\,‘rÀ‡‡n6`ÀçÑ£G›6mÚH»víÈ”)Ó½W¥TÒ¤ ¤RJ%yóæ%oÞ¼4iÒ€ÐÐЫ”Y®^½Ú˧ÐDÄQ¥<ñ8÷6ÆlZ‰Hn çõë×»|÷Ýwi&Nœh4h ]ºtÑ>I¥’M •R*J™2%~~~øùùE’'NÄL(]öïß_&**ª ÐlUʘûRcî$öžÖÇä‰È SDDD¯ ä]°`+V¤sçÎT¯^]û$•J•@ŠÈ[@±8NýcŒù7k]±ôɼä®û€%ƘKÖ1“€:ÀlcÌ@I¼cšHà2°'¡û)¥”Š[žÉM›6UÜ´iÞÞÞøûûkŸ¤R/¸ÄV [oÇq¼oBgÝ?ì' ®g—€ÌÖŸÓY41^gÎe@kÿRJ©Ç”2eJÊ•+G¹rå¢Ùª”Öm„\öïß_&22² ÐÀÉÉéÂûRn¯JiŒ‰ E¤,ðáÑ£G›0ÀyÔ¨Q¶>ÉÌ™3Çu¹R* ³÷öH,iDÛß@I‡¥Á:;pøØ ¤^ZÄÞË#”Ð8¦ê ¬:Ý7ÒÀ6;cWJ)•€«”wîÜy°—2sUÊX÷¤ÄR¥<öà¼Æ˜m@kùèyãÆ®ãÇO3iÒ$Ó Aéܹ3E‹}>oR)õÄìM ÃÀ)à_c̽GŒ}KòÔ7ÆÅ8·ø6ÆëŸ°<æ˜t{`žcƘ@ÉŒ%xªû›)¥”Š›‡‡ÇCUÊ“'OÆÜ—Òeß¾}¯EFF¾Æý*åÅV|Ûª”Öfìû@Ÿd¾ P¾|yüýý©Q£†öI*•ÄÙ›@~ãçC"ÒÔ_²„õûÁèäQD¼±ôAFÛeŒ¹–À=ÿ'"øÿ|‚1æ?;ãV°ù§1ªþòúŹpÀþ΄Ày“Y÷ýPÒåòæò±¸¸¹Óêûßc=Ò¾qößÕñ!Eª4\8ð¥šûóÖÐÉqÎwãÜ)æ÷jÁ¥Ã{I“5'!ÎÐxÄ ¿Þ(ÎñJ©Äqww³Ji]í]¥,aûÃkŒ¹ 쎈ˆÈ±páÂô .ÄÏÏjÖ¬é÷¡”²HLÒ8 "+€]Xa¿a=÷{|…eŒY,"󰬶$" ¬×{ÙcyËÊëìÖc«íœC%awo…°cþJ·ü?»¯-\³¥šù#NNcXñåü5ò#Úϸÿ‘½+æÓiör•¬Àùà]Lk]Ÿjõ)T£ÁCó-þÔŸt9óÑáç5¸¤pgÏŸsùc@Gz•­†{š´Oô>•R±EW)4°üY —Ý»wÛ’ÊÀÀÀ .\Èã äÍ›—|ùò9&p¥T¢È(`–GÇoZES±ìù(o€¾À«Ö/€sÀ\,+RÉúý&–mƒ&cf$âºøX÷ô/ôS¨§%*2‚½CªLÙ(ß±·Ý×{fÈÌkߺ–‹w~ç6çöíˆ5&{±Òä*Y€¬…}ÉS¦ Ö,y( ½~…#›þ¢ÉèY\> @†|–þÍ3{þ%…Zó•R‰äææFéÒ¥)]ºtô!9wî\ÌÇÞ²{÷n!Ççøñ㬘Ȇ¥{¶Rw÷ŽeSœÍƒBØüyüëbŒíÇlÀñGM0´nØý†ˆ¸Y'tN&°…OÌkÇã­Ÿ.“ 8ÿ`Ϥ1¦ñ¯OpÑÌÓfùõxe§'¸ÅU]xñ¤¢"#YðÑ;ܼx†öÓWÛÅØcϲ_Y9¢7ù+Ô"ƒw!R¦Í@ØÍØ-¹Y‹¼ûuáW¹xhÏCsݼp€¿OÇÉùþœ¾~È3û¿£RêQ²eËF½zõ¨W¯`©RîÙ³‡uëÖ1}útnܸAxX÷n;8R¥ÇDYR!E:§Çž'ìZ¡¢s¥GHô6>ƘpàÄãeŒ ?-~zvÙé·<ì}šÃúÉ O"*2’ß?iÇ•ch?cõc?Þ4euú}Ã+o¶`Ûìïsæ¿Ø{Οٽô¹ <4Î+{ʵíI¡êo=V~šªT"„ݼέËçm_·¯\ÄDEñû'í8´™&_Ï&ò^¸åü• vÏïâ–¶ Ï•‡Z0õ¡1üÇþU¿pdó*NîØD±º-çžÚ‹bo4gÓ#¹txŸíøÉ›¸ׇ$)¥’÷”ö?½PJ={7WÊ.‹tŠõ:Eª4|¸ú»—Î`BýWlç\R¸óé®8?R7^U»ΟCÞcëÏßrïÎmªvÿœsû‚byµq6LúŠ?¿Ëík—¨Òm ùüjÄ9_ý¡“øsÈ{LhP¯l¹¹{+¯l¹è0s®îv…¦”RJ%[š@ªgfàÎø«vƒƒl¯ˆSîRc][ R>Xu„çN’&k.D„rmzØÎ7üjšíç gH‘* )®^¸ùX×'WZTJ)¥ž“àÀÓܼ~Ç–=ÈÉùþ?Ë+fröØÕXçoÝãæõ;:Íü yµR>»’Ǩ(ÃÒۨ߮ µZ¼Ê¹WÙp<Þñÿm>Æö5‡m¯{ÖHІ£4ì\Ž;·Ãù¤ùt–ÍÚn;¿aé^†ùÏe÷–cÔi]Š-+ö3 õ϶óG÷§ík_ãì,´ìQ™ÈˆHÚ”c{½cýz7œB¦i©Ö¨8ãû/娾øÓ—®Z€RU Pá"äöÉ@¿ÓY<-€M}ɘ݋þ-§óçÏ®¶*ûhò „œ?ÍÚñƒ†RŽe ·nÝâÈ‘#x{{#"ŽŽH©$ëä¡Kxxº‘6£§íØ›±gÛIÒeJEÝwJÇ{}ó¢Ã¸I¶¼é™²¡§]÷ßö÷B®…RµaqRx¸R­Qq–ü´â~y¼6píaþÛrœ?O&K®´ÔjQ’Wn³}íáXã2e÷bج¶}-7­|GŽ{J7&ZN¹Z…øx|3ª6,Π3,š@»k2}øßTo\‚¾ßZ›¿R. ¼‡Å“_íB¶ïÑŨ»Î°öÝÌ üˆÂ¥ràâêÌä!+¨×®Œ]¿/?M Ÿ@È…3¬?ÄÑa(åp§N¢fÍš¤I“Æ”,YRJ•*E©R¥xõÕWI:µ£ÃS*ÉHååÎÝ0K¿³‹¥ÚxíÒ-Ž_àÈžs„Þ¼ûÈrù™!xeðäúåÛüñÿíÝwxTUþÇñ÷Iƒ„PBBo „@èI( -(XW+ö²«»®e]Ûê.ëÏUwW·Yׂ•UÁ @± R¤‡Ð…z'!!$”äüþ˜›a†Ô¡8„|^ÏsŸdæÞsæ\1áËçÞsîëó¹ªç“|’ùg"Z„×êó?s!£®èGƒÐ`.ºi _5ûŸ½Ôý^U6¬ÛI»Î‘´êÐÌýÞÀQq Èa½TÜ1®Æ}É{]úf›†rÿ˜7ÜÇæ“óÓr~ÚÁ-åÞ×6&’¶1‘µ:·rY+·Ñ"œn G/ýÇÛÿœé.dåÄ©€<^·¿ï^½ÊJwßž5kVô¬Y³ 66–ò‚211‘.]º(¥”z+º{+ÊJËÈ\±ÕŽ¥^Ò›ÔKzóþó³ùìÚÍxnÕˆ<›·ÿõ³>[Ř[«¿W\÷_þðéJ<Âço-ôÚ7sòr.¼¾µíCQTP‚µÖý3\W\ḆaÞ…¨ 0®ÙE€1†¤±œ;6Á똦‘ÜÇ;™¥ôHiçæ)00€ÒÒ2l™Å§2Œ1èwÏÉ¢òxÅŸí¡¬t«µö:cL+ H)++KÉÌÌ‘‘úþû®t5nÜØR&%%)¥”z¥{b{úŸÕ•žÊ3So#¤Áñÿ5¼}c…yÅ”ÿ{ÌZ˶ yD¶j\iš8cbQmš01ýA¯÷ßøë×L}kadÙ·ç«m¤× N”•YæN[íÓ˜û¤D³r~.÷==¦Òýq}Û²äûL®¼c(àJ=wlʯ²¿àA4‰#w‘ûv\¿væ³jÑFú¤D°ðÛuÄÄ·"¤aõ)«Ôž H9©¬µ;€Ïœ cLÐH’ SfÏžÝyöìÙ8û+¤”±±±J)¥Îzõ±ìÞVÀ†u;)*(aÏŽB‡wáük]—¦ÿüÚXîó×%ü‹³.ëCëŽäíÜÏôwÛ»mµ}¿8n: ³{[‹¿Ë kŸ¶œã¤y‡atÌãüçÓ_‘zIï m?{s!çŒM q³P¯÷/¾y Ÿþ­¹{+´ñÔ¹Gk®ù}*¿N}ó¯MbÕ ´lß̧Tïο_ÄMƒžæÖaÏsÎUýhŠy9 ¾ žQWöãÖGÎãÖaÏóðUè38†)ãçѲ}³*û3Æ0`dWþóûO|~<ý†Æ˜ËÅ· äþK^çêß gCÆ.¾ý0§>¼¹Ú±ýøÅòví÷zþ‚Cðú_q°ø0¯=6ƒðf¡\ßYîI;õ‘ H9¥¬µG€4gû/€1¦%®‚2ÅZ›’••5 333ôƒ>\)e¿~ýLRR’û^Ê&MšøëD|Ò,*,\z[Šû½FMº¿oß%ŠwÓà‹w“µré³³i×9ŠqãÇ’4"Ö}Ü5¿O%º{KZ´m¯=ß½¯E»¦\xC†\ïž¹½)k7aá è;¤s…1"õ’^ü↊“HºôjÃ=ÿ;=E´îÁ¯=ßuÙH9?Þ]8Ü÷ôRÎëNΚí\|Ë Òçd³ßÑËØ¿¸¡?ºµòêÿ–?žC‹vM×rE®~˜)ãç±zÑF†…Ð+¹GÅ®„öõ9¿ã³7°-w/O¼{=Ù«¶Ñ¹g›*ÿ{?þöõ¤ÏÉfõ¢q.?òúÕL°ˆôÙÙ4mÆøîªv¢Ð%¿L®ô©?†  ¢Z»~ÿxþ…VÙ_}`ÊWT_cfçñT&„6õ÷pDê¾ûÛÑCË­µýŽ· '¥ìƒST:[gýtéÒ¥BJ •È곉'2nÜ8.ùU2¼~µ¿‡ãwï=7‹}{pû㜲Ïؾ1VšaŒaËú=ÜwÉë »¨§{Hñ©ñØ-“òD⯠­¹Af=X@æ”b€kmnuÇ*¿sRÊ¥Îö"¸SÊdœ”2;;{`VVVè‡~M)=g|7mªJýuÍ=©§ü3&=ó3Þ[Jd«Æd­Üư‹zpÓCU/D.g."rZ²Öî>w¶ )eaaaòœ9sºÌ™3g?]ºt!!!ÁRvíÚU)¥ÈItß3—òËqç’·k?-Û5õº4/õ‹ H©|I)?úè#ÂÃýRÊ„„¥”"'¨YT#¯…Ð¥~R)"uV)eoœ”rÿþý)sçÎí2wî\œýtîÜÙ+¥Œ‹‹SJ)"â#"rÆpRÊtg{ ÀÓ‚£3¾“ׯ_?0;;;ìã? Q£F6!!Á”• 4kVõ²!""¢RDÎpÖÚ]x§”xÜKYTTT!¥Œ‰‰!!!òe„”RŠˆxS)"õе¶”ÊSJ÷½”999ׯ_6yòdÀ•Röë×Ï+¥Œˆˆð×)ˆˆø H©÷œ”rª³›R&¥üøã±?þø£»MLLŒ×º”qqqÖï……E¤þP)"rŒšRJ %77w`NNŽ;¥ sÏøNHH !!æÍ›ûé DDN-""µPEJéžñ}àÀ”yóæÅΛ7ÏÝ&::š¤¤$÷¬ïnݺ)¥‘3‚ H‘ãऔ˜íecL)å† åææz¥”}ûöu§”‰‰‰J)E¤NR)"r’XkwÓœ­²”2yþüù]çÏŸïnçBçÝ»wWJ)"§=""§H-Sʹ¹¹¦L™@hh¨WJ™””¤”RDN;* ED~FU¤”½p Êâââ” t]°`»M§N*¤”AAúõ-"þ£ß@""~䤔Ëí¨R&oܸqІ }òÉ'4lØÐR–o‘‘‘~:©T@ŠˆœfjJ)KJJR.\ØuáÂ…î6;vôZ—R)¥ˆœJúí""rš«"¥ŒÄã^ÊM›6 Ú¸qc£O?ýp¥”}úô1åcLHH **ÊOg "g""uµv0ÝÙýV0ÆŒííÀtkí¢ÚcpýÒêìÖSGƒaŒœL´ÖŽ3Æ4îðè¦Ø ¬²Ö.öeÌ""âb­-V8›gJ9§¨Ü²eË Í›7‡þùç€+¥ìӧ׌o¥”"R«ÒÓx ¸ÆyËHFWÓ.Ùi×½’Ý»€–Î÷@k ‰Çë'«èó `´s¹FDDN€“R~ál•¥”É‹/Ž[¼x±)oÓ®];¯”²gÏžJ)Eê™ÚþÄÿWñ¸x×åH GU Œ1Àd -°xX4úWyþkàwÀJºº˜ Ü Ü\$Õ&Ÿ""â»*RÊæxÜK¹uëÖA[¶l Ÿ:u*àJ){÷îí•R¶lÙ²ŠO‘3Am ȇœ¯/«®À:kí×Õ´¹WñX\d­M÷Ø7xÞãõ[¸.sn?¦Ÿkmš1¦%® ¤–ã‘d­ÝKÅ”²'÷R.Y²$nÉ’%mÛ¶îb2))‰=zì—ñ‹ÈÉWcénÎË{€:ßï2ÆÜb­^EÓ>Î׌òâÑÓ×}å–[kójÂ3Ƙ'8zü%k튚Æ-""§†“R®t¶W¡BJ™¼mÛ¶äiÓ¦…O›6 p¥”½zõòJ)[µjå§3‘U›Òó'<×%åós‰Æ˜hkm~%íÊï²ö,‹ëx¹s€okøü` ®{.ºcZ”OÀÿ«MJ™––—––ViJY~/¥RJ‘º¡6äVïß¶Ö>cŒ™dMDà»JÚ­FqƘ`kíaà çI µt—µöSçÙ°ÙÀHàŽ&¡""rš©&¥tÏøÞ¶mÛ iÓ¦5.O)CBBlïÞ½MBB‚»¨lݺµŸÎ@DªSci­ÝcŒÙ´«âÊÒG€/qÝÏ üxÔZ»Äó¾åò€ý¸fj÷<Žö""âGNJù¥³y¦”É@Ê¡C‡RÒÒÒºy¦”mÚ´ñJ){õ꥔Rä4PÛI4ÿÀ5éåFcÌ`”óþj\ÿº¬ÀZû¹1æC\³­ÿÏ3ךú8Æû1×âšyÝÖy¯²Ä³¶ÈÛ ÅÇßKIá Aä b-¸n5ñÉ1)åkà^ÁÃ=ã{ûö탦OŸÞxút×íö!!!¶W¯^&!!ü|W~qøÐ ó‹ýq "§…’‡8˜_Æþ-eÇÝÏ‘î¶5k¬ë—õc€?9[˜óö\àWÖÚŒjÚâºïñA¼'ÏlÞž²Öî4Æ|‚3 ÛZ{»1¦{Lw…Î{/Yk'Á,Ó. êxÛ‹HEƬµ³À|`¾µv‡Ÿ‡%g'¥ìSP:[7ŽÞ/"'ß0kíÜê¨Uy&1Æd±ô'°ðíÊ„6‰ Ó€á'ml"uÑÚ™Ÿ@YY…õæà*&Ë‹ÊåνÐ"'ÄI)ÏÝ‚B !áª'EÂÛYcxX¥Ý«P´­ ¿µ6­ºcëc98§2!Ô׫éîiIû¾ƒ¸õƒ'ml"uÑ_âˆïÞwÞy‡ôôt–.]JZZ+V¬°%%%î¿Õ1%ΣHÝE¥µv»ß.už1ævàåáÿlBÜå¡þŽH7ëÁ2§ÄXks«;VÏž‘“"**ŠsÎ9‡sÎ9€#GŽ˜µkײtéÒò­áƇÃÊÛcrq.yã**—)¥9ý©€‘S"((ˆ^½zÑ«W/n¼ñFöìÙãYP²|ùòN%%%Ѹ•Š1¦Ä³¢ÒZ»Í_ç ""•S)"?›ÈÈÈJSÊòKßK—.m¸aÆ¡ÀÐò6Ƙ -(磔RDÄïT@Šˆßx¦”7Üp{÷î%--Í]T._¾¼cqqq'àjcÌÁcRÊùJ)ED~^* Eä´Ò¼ys¯”²´´ôØ”²Annî`Hy'¥t/!„+¥<äñ‹ˆÔ* Eä´HÏž=éÙ³'×_=àJ)—.]ê•R8p 0¼RJÏu)·Vù!""â"Rç4oÞœQ£F1j”ë¡X¥¥¥fݺužEeƒœœœcSÊx¯K™®”RDäø¨€‘:/00=zУG¯”2==ÝR.[¶¬Ã:⤔À!{)Ë×¥ÜâŸ3©[T@ŠÈ©yóæŒ9’‘#G®”2##Ãs¡œœœÁÀàò6ƘMx¯K¹T)¥ˆHE* E¤^ $>>žøøx®»î:òòòÜ ezz:Ë–-k_TTtp€1æ1& ïßJ)E¤ÞS)"õVDDgŸ}6gŸ}6eee•¥”)ÖÚ”ò6ƘÍx¯K™n­=è—ñ""Ž€€ºwïN÷îݹöÚkÈÏÏ÷J)ÓÓÓÛ] \ î”r)Þ)åf¿„ˆÈÏ@¤ˆH5š5kÆYgÅYgTL)ÓÓÓCÖ¯_Ÿl­MîwJé¹.åR¥”"r&Q)"âƒÊRÊ}ûöy.tβeËÚíß¿ÿ à §Ùaç^JÏu)7ùç DDNœ H‘Ô´iSFŒÁˆ#WJ™™™é™Rggg—§”¿0ÆlÁ{]Ê4¥”"RW¨€9ÉèÖ­ݺuãšk®\)å²eËœáÇ`­­Rfee ´Öî0ÆlÃ{]J¥”"rÊ©€9McèÚµ+]»veìX×#¼ Y¶liiiå÷R¶.((¸ ¸Ìivس ï”rƒÎ@DÎT* EDêÆ3lØ0† ¸RÊìììcSÊeee€ß;¥ô\—2ÍZ[ì¯s‘ºO¤ˆHfŒ!66–ØØX®ºê*àhJ鱌Pë‚‚‚KKfå)¥çº”¹~9©“T@Šˆœa*K)ׯ_ï•Rfff–§”wc¶ã½.奔"R""g8c ]ºt¡K—.\yå•ìß¿ß+¥\ºti«JRÊåx¯K™ãŸ3‘Ó H‘z(<<œ¡C‡2tèPàhJéñHÆàŒŒŒþeeeýqRÊ€€€ÖÚy-*+¥©ŸT@ŠˆˆWJyÅ®‡ã›R¶Ø·oß`ŒÓìˆGJ9X`­]ïŸ3‘Ÿ“ H©T£F2dC† \)eNNéééåËedd$•••%w;¥ô\—r‰µö€ßNBDN rÊlY¹˜æb mQaŸµ–m«Óؽ~-¡M›ÓiÀpBÂÂ+í'oÓzŠöî¬òsšµ!<²U¥ûÒ'¿IHX8=/¸ªÒý[W-aõŒ8çÔâŒDê7c ;w¦sçÎ\~¹ëá8å)¥Ç¥ïùùù——8ÍŽcVà½.¥RJ‘:N¤œ2nHå²M$þœK+ì{nd G–Ð"¶ÛZF@p0×¾2v½T86}Ê[¬™ñ‡KŠÙ·m#‘Ñqc~Ç#ô¹øºJǰ1m.aÍ[TY@æoÝÀO_OV)rœŽM)“““ãyÙ;hݺu‰eee‰ÀƘ]x?=g±RJ‘ºE¤øÅ~ž¸a(=r˜ 7Œà«'ïå—“æV8öì{žàì{ž`ãÒyóÚ¡üfJšWbi­u”U©Í1'r¼ˆ¸ÄÄÄã•R._¾Ü3¥ŒÊËË Œvš”§”žëRfûgô"R* Å/º=Úý}`P0ÝGañ¤—|î'kÎ ¾ù÷CìÉYGPƒ†Ä;Ÿ Æ=O£È–îcŽ,aÊn ãû©„4j̨ûž¤Ïèë+íïÈ¡ƒ|ÿüÿ±âów)Þ·—ýR¸è±WˆŒŽóý$Ep¥”ƒfðàÁåo¹SJ§¨ Z»vmyJy@@@ÀngÆwyQ¹ØZ[äŸ3‘c©€¿³Ö’ñýTb‡žçsÛ°ˆ(®xú}"£ãس–¯þ~/_=u—ýë]÷1KÞ…wÿ… Æ=ÇŠ©ùìO¿¤e\oZwï[¡¿¯ÿñ[V,äÊg?¤y§X排I·_ÌÓV|Bç)"G›R8p€åË—»‹Ê´´´ÈcRÊR{)Ë‹Jñâw³^|œ=¹™Œ}aŠÏmÛöêÀü=çí¡ós˜ÿÖÓ^Ç4mÓ‘a¿þ#ƒ®¿›•S'‘>ùM.÷œ×q‡Š‹XòþË\;~:]÷s¼ïï¤O~“-+¹ß‘“/,,Œ””RRRÊß2¹¹¹ž)eàO?ý”PVV–€“RcŠ­µ¬|í›gòÛØENÝÆ†ÒnHÈÏòY* ů¼ý ßyž›ßù°ˆ(ŸÛoY¹˜éù-ÅûöÒ¼SWlY)E{vxÓiÀpï×ý‡±'7£B_ù›s(+-åÓ‡n{mYû¶mT@Šüœ¢££‰ŽŽæ²Ë.\)åŠ+ÜEåâÅ‹CóóóÉËÂÂÂHNN&99€‰'2nÜ8ΛÀÝO]ìçщøÏÌ—ñ܃Ÿÿ¬Ÿ©Rübñ{/3ó™?qã›ßЦGâq÷³+k5ý.½ €²ÒRVLXá˜ÍËæS°c MZµã@þr|ǹý»Âq[´¡M½û_Fÿí 8\r€Ààõã"r: o@Ûèæþ†ˆß4‹ª|åSI#Ê)õå_ïfæÓt¿iÔ˜›&Ìä‹Çï¤Aã¦Lyðèlè  ¹ýÓe>õ?ðú»™ú¿aíÌÏØ°hV…ËÕûãµ+ÐiÀp2g}A»>é{É•öwé?Þæ½;.áéÔöÄ;Ÿƒû÷‘»hw}¹–FÍ[ø46‘3• H9e®ý+lY©×{A‡†qÓÿ¾«p¼ ¬±ÏVq½¹ùíï j @ò÷Ð}ä%lX<›”›î%2&Ž„+~å>~ÈmLPƒ†ä,üž>£o ËÐsÝébô×bçåZvíÅSW²aÉò·äÙŠ‹Ÿx0çò¶ˆˆˆ¨€”S¨SÿaUî‹8â¸úlÞ¤BÛfí¢iÖ.úhßRÝßGÅts_ÙÓjÂ"¢*LÞ nv\K ‰ˆˆÔþ€ˆˆˆˆÔ-* EDDDÄ'* EDDDÄ'* EDDDÄ'* EDDDÄ'* EDDDÄ'* EDDDÄ'* EDDDÄ'* EDDDÄ'* EDDDÄ'* EDDDÄ'* EDDDÄ'* EDDDÄ'* EDDDÄ'* EDDDÄ'* EDDDÄ'* EDDDÄ'* EDDDÄ'* EDDDÄ'Aþ€1¦Ð(´Öîñ÷xDDDD¤j5Ƙ¶À›ÕrµÖVÓ>¸ètök€ÉÖÚÏœÃ^ÆãÛ1-·=º)v«€·­µ;j·ˆˆˆˆœµI çU±ïPu 1·ÿBœ·öm€$àB ¼€LBÕÎëPÏ<”áÎëßcúXk÷×bì""""r’ÕæÈl â˜m™³oRUé£1¦ð®âñ «µ6úoxþ0˜_IW×Yk7;¯cp """"â5ÖÚ2km~ùôúøW5MoÅÀÕÖÚ,þVXkò8ö~à=àÖJúidŒ‰Úz¼—]Ó¸EDDN;7çs°ø°¿‡qJ9\ÊÖܽî×yÈß]äÇÁÞ…(<è×1œéŽgÍÎ×éÖÚ5Õ×Óùº®üžEcÌ9ÀcÞ¶Ö®¯áóÞ=æõÖÚ͵­ˆˆÈq(+³Ì˜”ÆšÅÙ˜¹‹ ®ëÏ×U¼¶cS>žú–u˶°wG!mcš“|nwÆü*™&Íøeð³<ôâ• ¿¸'Öíäß÷Lq·oÝ1‚#ãrA<š4¬õØî¹p<-Âyìíë0Æp ð ]ù|å*ÚF7¯±Ÿ™»Øœµ›ÁÄ×ês+³)k7Wöx’ùÿCpH oüõkòvñøÛ×wŸ'êÏ׽ÈKûpÕC+ì++³L{1#¯èKXxƒãþŒçüœÎ=[sñÍ+ìÛµußM^ÎêÅ›ÈÛYÈŸÆ_E›N5ÿyÔ%>ƘnÀÅÎËêÒG8šn–y¼w.G P€¹@MäWÀF`®äóQcÌkíªZ ZDDä89t„÷Ÿ›E|ÿŽä®ÝÉæìÝŽIû!‹{G¿Fêè^ÜòÇQD¶nBîOÛ™þζ¬ßÃ_¾€‡^¼’ø¤öìßWÂü¯ÖòÈëWÚ(„-9{yå‘/Xôí:þüÚÕµßü¯Ö`H9?Þ]Ø9\Êü¯ÖÖ:}KŸÍço-<¡òX¿¸a‡9iýl¥GÊxì–I$¥v9¡rÕÂ\‚C+Ý·zÑFfO]ML|+¾xg1Åû«2R'ùš@Þ`¡Ò{b¹IDATµvv Ǯκc"åyþ¼ÅÑÉ2µñеöScL tnª¶•ˆˆÈ iÌÛ‹ïàש/TØøP)ûÍüâ†<ôâî÷{ôïÀ…7 `ûƼjû?ë²>4‰p%”ÑÝ[2îš·¹ÿÙËmRm;Oç_›ÄË|Á¨+ûUYÌ,>ÌÌÉËÙ¾!˜­H½¤7†½; Y½h#ù»‹øúý¥ ¾ áM+¦ ëÒ7³tv6E%tîÑšczXû¥¤g¾ŠìÕÛ‰OjO\¿ö¬œŸCê%½X:+‹¨6M))>Ä¢o3HÖ…ž;zµ?|¨”ï?YÁ¦Ì]tˆâìËû|ô|wo+`æÇË døè^ÕŽeÎTWþ4{êjš· ':¾q}Û°rA.é³³iÔ¤!CÑ“VšÕú=Ó›cz“¿»ˆ÷Ÿ¯©\ª›jý§oŒiÜ輬)}x8ŒkÒ̧ˆÌÕ&N@yþqœ}ˆˆˆœ«n`cÆ.nxðìJ÷·îxô¯ªÜù?¥U~÷UY™eå‚ DµiâSñ0ú—ƒ à“WçUºÿ¾nèÿþûÇilß”Ç_nžÄ]ç½LY™eA ›×ïæ@áAV.ØÀÊ(9P1)+.:Äc·¼ÇÎÍû(È+濚ÆoG½DU+øMg1¾8×ýúŸwOæO׼͎My¼ðð4Æ]ó?žüíGîýžšÉSw~Ä.‹ ëvrïè×øûo>tï/È;ÀMŸæõÇ¿bßž"Æÿe·{ž#‡KØš»—ë“þÍ'¯Í'sÅV~ú;6çWùßlmºëÏ!cÙV.ØÀöùÎ8¾åÖaÏ“±|+Ÿ¾¾€±½ŸbÅüÜ*û©ï|I ïÂ5)&ø¤¦ƒ­µË1ÿ.vc6qt9žÚzËó*ÐÂy}Wqz¼0w„Ôî^“ªÜ_@î¢N¨‘:ÏRå_$"g² ëvÒ0˜6ŽŠ»·°wG! ÃBè×¢ªæÜ6üضa/Mš‡ñâ7wø<†À @nâBþý»É\Tɽxïüû;:ÂgÙÈoŸ¸ Û?ÊŒIi\x}λ:‘ÏßZÈýÏ^Zåg„6 aÒ²ݯýèù\ØþQÒgg“˜[íøÖ¯ÙÎG/Îå ï¥ÇWªø» ÇW8n[î^¦dŒ# Àpém)ÜuÞ+<üÒðÚc_èýOatÌL°ˆKoKáõÇ¿"&¾/}{ÆV-ÜÀÍÉÏT9¦Ûþï|ÞüÛ7Üúȹ´‰\“œÆ?ú%ÿüøw2úèMyúÞO˜°àÞjÏñt²uÞ!Jÿïãü,÷D¯¯íת€4®»s{³p]R.«¡ ÖÚ§13ûp-$ÞØ| ¼ïô®Â#€ çu‰Ç>pÍø.Äu û5kíÊÚ|~â˜ö·èÂeWöOL¸ñ¬îG¤®[»v-III611Ñ$&&’””DïÞ½ õ÷ÐDN™²²2ŒÁ=`Ƥ4>ym>…yˆjÛ”IéVÙþ¾§ÇÖ¸»¶ìã‹w—ð—›'òòÌ; iàÛÝeç\Õ O}Ëħ`ì]üö­˜—CÊùñîËÛ-ÂéÊy9\x}ÿZFÖÊmÌ›ñé³³)*“¶1‘LzöhYТ]SÖ,ÞÈ¥·¥°rA.¿¸q€ûÏ¡çÀŽ4‹jTësX³d& €”óº»ßKÝ‹‡¯šÀáC¥UÞpºÉù²„œ/KNFW-€uÕP«ÿKµ/?žXk—7ÕpÌ#ǼÞŒ8žÏ«…í@#~A¾]*ð’Uùå‘zgÃR°öðž={v}óÍ7m¿ùæm||¼ILL¤|ëØ±c ‰ÔÑÝZr°ø0;7çÓ²½ë^¹ëï?‹ëï?‹IÏÎbÚÿUÛ>¾÷=ƒÎéÆymþ_­­ñ¾cc¸ëïñðØ œ;6Ák_QA -Û5õz¯e»¦Ô¾ÈÈß]Ä/?Ë­œË•w%ªuþ|Ý;*©yY¢CKiÔ¸¡W‘]Ù=–Í[5v` ä Óa~1†ÃsRG÷"º{Kì?Hdë&î}Æ¢Ú}]E%4‹ #¤a°û½¨¶M)+³$8$̧þü¥ý°Dö8þ§Toüþ yGÀÚUë´xöÏl Ћó€Ð¦5,"5¸¿=9´ÆZÛÏÓHRJKKSV­Z•°jÕª·ßv=™422ÒR&&&Ò§O¥”Rgõ؉¶ÑÍy÷é¸ïé1'ÔWiie¥e5N¼©Êà âéÖ¯oüí¯÷;ƵdÑ·Üüð(÷{K¾ÏäòÛ]+ê…†7 ä@õ…à´ÿ-"1µ 7þa${wî'wmíž(ݽ%Û6ìekÎ÷åâßdÔÐÊ[çž­9r¤Œ›Yéþö]¢HŸ“í^N'o×~²Wm¯²¿À B{wǸìܲœŸvß pͰoÕÈ]ä×Îm@üµÇÿ;õÀ®²òr_MÇÖÇRDNkí&\·©|`Œi$â•{öìIùæ›oÚ›R&$$¸SÊN:ùkø"üøÅŠ JÈÛµŸ¬•[ùúý¥tèÚ‚ø¤4 æOã¯âKߤ¨ „ó®N¤uÇöî,dÁ×k ª~žê_üDh£÷ â¡Áîôñ`ña®ˆ’GÞ¸š#ãj5Ö»ž¼˜Û†?ïõÞ5÷¤rë°çÿè—œuY>~ùGŠ J¸ô¶’R»ðèïòõûKiÝœ¸¾íhìÕGþ˜ðÔ·,›»žA¼þׯ ­åò7ý†v¦ÿY]¹wôëÜøàÙ¬\˪…¹µj[î¶ÿ;ߌø//ýy:ç\•@ðVÌË¡M§Sc{÷pÿå$º'v ßÐ^yä‹j'#†uæƒÿÎá‚ë’hÝ1‚ÞÉÑôNŽæÉÛ?ä·ý›²vñÑ‹s¸öÞÕŽmýšíîìå†^Ô“²R˼/×Pä,§ôã—kÈZ¹•þguõJ[ë2"rÊXkâzD©û1¥NJ™ÌÑ”2qÕªU!ï¼ãš×¼ys›””ä.*ûôéCXXÝIäÌòÕûélߘGDËÆäí*âãWæ1â’^Ä'¹îéK>·;“–=Èëų|Fþîý´ïEÿ³»rõÝÃÝýôI‰¡Y¤ëÿãFM˜Ë'¯¹~,ÂÂCè–Оq¯ŽuÏÜÞ»³›òhÝ¡êEGSciÜìhÚÔwH WüvY«¶î* zìÈ>»•7þú5Ÿ½¹Î=Zóúœß¹/ñF¶nÂïÞÀ¼/bóú=üå­kÜI¡ççÜø‡‘üãÎ iÄ¿JÇ®-há\mBbj,åW©Ûw‰¢YÔÑù²ÏL½7ÿö53'/'>©Wß=œÉãÞÛ§-­Ú{/—Óohg÷¢ê½“£yåû»xí±Lûßb†Ó=±·>r.g_Ö‡¼…|ðÂ>yu—ß>„][T¸tïéÞÿŒáë÷—òêc3uE?.ûÍ`žvÏ>ðÞ4‘ð& ¹úwùþÊgØtKhOÆò­|üŠ÷-mý†væÈáR÷û‰©±Ì™æzîJǸ–gLiêÛìIcÌ à<žÊÔ%l‘“Áu {¹µ¶ßñ4÷H)“q’J }ùþ€€âããñL)£££OÆÈ¥Ž›8q"ãÆã’_%óÈëµ_€».øü­…¤ýÅcÿóßÓ\Nk­ûHk-÷\ø*Í¢ñø;×ûydgŽ©ñØ-“òD“º„=ëÁ2§ÄXks«;V ¤ˆøÕ1)å3Ƙö¸ Éä²²²”5kÖ$­^½:äÝw]O6ˆˆ¨R6jäÛ¬K‘ÓYRj,©>N¦9]=sß§ìØœO‹¶M™ýù**å•ïîô÷°ä©€‘ÓŽó¼ûœ cLGï¥LÎËËKùöÛo;|ûí·€+¥ìÞ½;‰‰‰î¤2&&Æ_Ã9aí:GÖ|PqãF²üÇòvígàÈ8’FÄÖú™ßrúR)"§=kí!`³`Œi‡wJÙÍš5^)ebb¢;¥ìÛ·¯RJ?ˆjÓ„‘Wôõ÷0ä$S)"u’µv 𱳕§” x¤”3gÎì8sæLÀ•RvëÖ Ïu)•RŠˆ"rFpRʅ΀1¦-ÎÄœ²²²äµk×öÿé§ŸLœ8€fÍš¹×¥LHH _¿~J)EDjA¤ˆœ±¬µ[ÉÎVžRöÃ)*óóó“¿ûî»Nß}÷àJ)ãââ*¤”žOÑ"R8)å"g{ÀÓ†£)eʺuëú¯]»¶Á¤I“hÚ´©WJ™ ”RDê="R¯Yk·Sœ cL0)å¾}ûR¾ÿþûNßÿ=P1¥LHH sçÎJ)E¤^Q)"âÁZ{XìlÏcZS1¥lXžR6iÒÄëßýúõ#<<¼ª©óT@ŠˆÔÀZ»øÄÙÊSʾ8EeAAAÊ?üýÃ?®”²k×®^)e—.]”RŠÈC¤ˆˆœ”r‰³½î”2'¥ÌÈȰnݺ†ï½÷àJ)¼RÊÆÏŒgâŠHý£RDä$pRÊO cLǤ”³fÍŠ™5kÎ~¯”211Q)¥ˆÔ* EDNkí ÍÙþ `Œi…“RZkS233ddd„¾ÿþû4nÜØR&%%)¥‘Ó– H‘Ÿ‰µvð™³y¦”É@JaaaÊìÙ³;Ïž=g?±±±^)ell¬RJñ;""~rLJù"€1¦%Îã­µ)YYY333C?øàÀ•Röë×Ï$%%¹ï¥lÒ¤‰¿NADê)""§kíN*¦”}pŠÊ”9sæt™3gÎ~ºtéR!¥ ð×)ˆH= RDä4椔K­<¥l39ÇZ›œ=0+++ìÃ?ަ”ž3¾›6mê¯S‘3 H‘:ÆZ» øÜÙ0ÆR1¥ŒõL);wîì•RvíÚU)¥ˆ7""uœµ¶Hw¶—ÀR–ÏøN^¿~ý ììì°>ú€ððp¯”2!!A)¥ˆÔš H‘3“RNu¶ò”²7Î¥ïýû÷'Ï;·ëܹsqöÓ¹sgÜ)e\\œRJ©” H‘zÀI)—9ÛËÆ˜(<Ö¥\¿~ýÀìììFü15ªR6kÖÌ_§ "§""õ”µv70ÍÙÊSÊ^8)eQQQÊ?þØõÇÄÙOLL ”/#¤”R¤~R)""€;¥\îl¯c"ñH)srr­_¿¾ÑäÉ“£)eù¥ï„„"""üu "ò3Q)""U²Öî¦;Ƙ*¦”qå)%@LLŒ×Œï¸¸8ý1|9ET@ŠˆH­YkË€Î6ÀÓ'¥Rrssåää„—§”aaaRÊæÍ›ûé DädP)""'ÄZ»øÂÙÊSÊž8åRæÍ›7oÞ<÷C¼£££IJJrÏúîÖ­›RJ‘:D¤ˆˆœTNJ¹ÒÙ^wJ9§¨Ü°aàÜÜÜÆå)ehh¨{ÆwyQ©”Räô¥RDDN9'¥üÒÙ5´3ƘŒ1«@.PhŒÙhŒù§Ç¡¿ÞnrÚu4Æ”xlEƘ Æ˜éÆ˜TßOSDDDDN–Ú^ÂþHÖ?ƒ€wkh÷ð6ÐØL¾¿ô8îàÀ'ÎkãÓX|„_cZ×rÜ""""r’Õövçë¿­µoc¶ã*ÛVÕÀs>ð+çå³ÀƒÖÚ#ξ`àÃ[ÑÀÆJºzÒZû©1æl`& ÄÛk9v9‰j[@þø=ð+cÌaަ‡oUÓæbçë^àáòâÀZ{øÜãØó€1Î÷“Žég1&¸Úy½H«å¸EDDDä$«my?®I.—Cœ÷&UÓ¦»ó5ÃZ{Às;G A€û­µ5ƒ;kmA­F-""""']mïü Wñø%0Öy}9ðE5mòœ¯M=ÞkÄ©ÎQ‹Ï~¸xÞyýª1æ¼ZŽ[DDDDN² HcL'`”óòÖÚ9š<žgŒi_EÓ•Î×8cLkíßqM¨ñÅkí$kí=@†3æË|ìCDDDDN’Ú$G<¾ê|RÅ~O/»€@àscÌcL4¾í1=Œ1·±Î{E>ö!""""'I÷@Zk·c>ÀuéúecÌß9zéy’µ¶ÒÙÐÖÚ]Ƙ±¸&àtáè=åû+4¬è…c^ož©E»êÍÁ O¸‘z¯¬Ôß#znËœC*°þ†H—ŸUU&X‘±¶æ:gô\÷-¶v³)ÖÚ²Ú†á*>{áZög;®u$§Xkw;njŵ4Ïkí4cLSà^n,Pˆk!òéå“rއ1f®Yß"rò,·Ööó÷ ¤~q&f¾ìïqˆœb¬µ¹ÕP«òLâ<ɦMŠˆ/ò¬µ_ù{R¿cºü=‘3ÐTkmµ· Ö»RDDDDNLm—ñàÿ™!ËÎÌ ‡IEND®B`‚trusted-firmware-a-2.2/docs/security_advisories/000077500000000000000000000000001355360272700221405ustar00rootroot00000000000000trusted-firmware-a-2.2/docs/security_advisories/index.rst000066400000000000000000000005431355360272700240030ustar00rootroot00000000000000Security Advisories =================== .. toctree:: :maxdepth: 1 :caption: Contents :numbered: security-advisory-tfv-1.rst security-advisory-tfv-2.rst security-advisory-tfv-3.rst security-advisory-tfv-4.rst security-advisory-tfv-5.rst security-advisory-tfv-6.rst security-advisory-tfv-7.rst security-advisory-tfv-8.rst trusted-firmware-a-2.2/docs/security_advisories/security-advisory-tfv-1.rst000066400000000000000000000166421355360272700273430ustar00rootroot00000000000000Advisory TFV-1 (CVE-2016-10319) =============================== +----------------+-------------------------------------------------------------+ | Title | Malformed Firmware Update SMC can result in copy of | | | unexpectedly large data into secure memory | +================+=============================================================+ | CVE ID | `CVE-2016-10319`_ | +----------------+-------------------------------------------------------------+ | Date | 18 Oct 2016 | +----------------+-------------------------------------------------------------+ | Versions | v1.2 and v1.3 (since commit `48bfb88`_) | | Affected | | +----------------+-------------------------------------------------------------+ | Configurations | Platforms that use AArch64 BL1 plus untrusted normal world | | Affected | firmware update code executing before BL31 | +----------------+-------------------------------------------------------------+ | Impact | Copy of unexpectedly large data into the free secure memory | | | reported by BL1 platform code | +----------------+-------------------------------------------------------------+ | Fix Version | `Pull Request #783`_ | +----------------+-------------------------------------------------------------+ | Credit | IOActive | +----------------+-------------------------------------------------------------+ Generic Trusted Firmware (TF) BL1 code contains an SMC interface that is briefly available after cold reset to support the Firmware Update (FWU) feature (also known as recovery mode). This allows most FWU functionality to be implemented in the normal world, while retaining the essential image authentication functionality in BL1. When cold boot reaches the EL3 Runtime Software (for example, BL31 on AArch64 systems), the FWU SMC interface is replaced by the EL3 Runtime SMC interface. Platforms may choose how much of this FWU functionality to use, if any. The BL1 FWU SMC handling code, currently only supported on AArch64, contains several vulnerabilities that may be exploited when *all* the following conditions apply: 1. Platform code uses TF BL1 with the ``TRUSTED_BOARD_BOOT`` build option enabled. 2. Platform code arranges for untrusted normal world FWU code to be executed in the cold boot path, before BL31 starts. Untrusted in this sense means code that is not in ROM or has not been authenticated or has otherwise been executed by an attacker. 3. Platform code copies the insecure pattern described below from the ARM platform version of ``bl1_plat_mem_check()``. The vulnerabilities consist of potential integer overflows in the input validation checks while handling the ``FWU_SMC_IMAGE_COPY`` SMC. The SMC implementation is designed to copy an image into secure memory for subsequent authentication, but the vulnerabilities may allow an attacker to copy unexpectedly large data into secure memory. Note that a separate vulnerability is required to leverage these vulnerabilities; for example a way to get the system to change its behaviour based on the unexpected secure memory contents. Two of the vulnerabilities are in the function ``bl1_fwu_image_copy()`` in ``bl1/bl1_fwu.c``. These are listed below, referring to the v1.3 tagged version of the code: - Line 155: .. code:: c /* * If last block is more than expected then * clip the block to the required image size. */ if (image_desc->copied_size + block_size > image_desc->image_info.image_size) { block_size = image_desc->image_info.image_size - image_desc->copied_size; WARN("BL1-FWU: Copy argument block_size > remaining image size." " Clipping block_size\n"); } /* Make sure the image src/size is mapped. */ if (bl1_plat_mem_check(image_src, block_size, flags)) { WARN("BL1-FWU: Copy arguments source/size not mapped\n"); return -ENOMEM; } INFO("BL1-FWU: Continuing image copy in blocks\n"); /* Copy image for given block size. */ base_addr += image_desc->copied_size; image_desc->copied_size += block_size; memcpy((void *)base_addr, (const void *)image_src, block_size); ... This code fragment is executed when the image copy operation is performed in blocks over multiple SMCs. ``block_size`` is an SMC argument and therefore potentially controllable by an attacker. A very large value may result in an integer overflow in the 1st ``if`` statement, which would bypass the check, allowing an unclipped ``block_size`` to be passed into ``bl1_plat_mem_check()``. If ``bl1_plat_mem_check()`` also passes, this may result in an unexpectedly large copy of data into secure memory. - Line 206: .. code:: c /* Make sure the image src/size is mapped. */ if (bl1_plat_mem_check(image_src, block_size, flags)) { WARN("BL1-FWU: Copy arguments source/size not mapped\n"); return -ENOMEM; } /* Find out how much free trusted ram remains after BL1 load */ mem_layout = bl1_plat_sec_mem_layout(); if ((image_desc->image_info.image_base < mem_layout->free_base) || (image_desc->image_info.image_base + image_size > mem_layout->free_base + mem_layout->free_size)) { WARN("BL1-FWU: Memory not available to copy\n"); return -ENOMEM; } /* Update the image size. */ image_desc->image_info.image_size = image_size; /* Copy image for given size. */ memcpy((void *)base_addr, (const void *)image_src, block_size); ... This code fragment is executed during the 1st invocation of the image copy operation. Both ``block_size`` and ``image_size`` are SMC arguments. A very large value of ``image_size`` may result in an integer overflow in the 2nd ``if`` statement, which would bypass the check, allowing execution to proceed. If ``bl1_plat_mem_check()`` also passes, this may result in an unexpectedly large copy of data into secure memory. If the platform's implementation of ``bl1_plat_mem_check()`` is correct then it may help prevent the above 2 vulnerabilities from being exploited. However, the ARM platform version of this function contains a similar vulnerability: - Line 88 of ``plat/arm/common/arm_bl1_fwu.c`` in function of ``bl1_plat_mem_check()``: .. code:: c while (mmap[index].mem_size) { if ((mem_base >= mmap[index].mem_base) && ((mem_base + mem_size) <= (mmap[index].mem_base + mmap[index].mem_size))) return 0; index++; } ... This function checks that the passed memory region is within one of the regions mapped in by ARM platforms. Here, ``mem_size`` may be the ``block_size`` passed from ``bl1_fwu_image_copy()``. A very large value of ``mem_size`` may result in an integer overflow and the function to incorrectly return success. Platforms that copy this insecure pattern will have the same vulnerability. .. _CVE-2016-10319: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-10319 .. _48bfb88: https://github.com/ARM-software/arm-trusted-firmware/commit/48bfb88 .. _Pull Request #783: https://github.com/ARM-software/arm-trusted-firmware/pull/783 trusted-firmware-a-2.2/docs/security_advisories/security-advisory-tfv-2.rst000066400000000000000000000077301355360272700273420ustar00rootroot00000000000000Advisory TFV-2 (CVE-2017-7564) ============================== +----------------+-------------------------------------------------------------+ | Title | Enabled secure self-hosted invasive debug interface can | | | allow normal world to panic secure world | +================+=============================================================+ | CVE ID | `CVE-2017-7564`_ | +----------------+-------------------------------------------------------------+ | Date | 02 Feb 2017 | +----------------+-------------------------------------------------------------+ | Versions | All versions up to v1.3 | | Affected | | +----------------+-------------------------------------------------------------+ | Configurations | All | | Affected | | +----------------+-------------------------------------------------------------+ | Impact | Denial of Service (secure world panic) | +----------------+-------------------------------------------------------------+ | Fix Version | 15 Feb 2017 `Pull Request #841`_ | +----------------+-------------------------------------------------------------+ | Credit | ARM | +----------------+-------------------------------------------------------------+ The ``MDCR_EL3.SDD`` bit controls AArch64 secure self-hosted invasive debug enablement. By default, the BL1 and BL31 images of the current version of ARM Trusted Firmware (TF) unconditionally assign this bit to ``0`` in the early entrypoint code, which enables debug exceptions from the secure world. This can be seen in the implementation of the ``el3_arch_init_common`` `AArch64 macro`_ . Given that TF does not currently contain support for this feature (for example, by saving and restoring the appropriate debug registers), this may allow a normal world attacker to induce a panic in the secure world. The ``MDCR_EL3.SDD`` bit should be assigned to ``1`` to disable debug exceptions from the secure world. Earlier versions of TF (prior to `commit 495f3d3`_) did not assign this bit. Since the bit has an architecturally ``UNKNOWN`` reset value, earlier versions may or may not have the same problem, depending on the platform. A similar issue applies to the ``MDCR_EL3.SPD32`` bits, which control AArch32 secure self-hosted invasive debug enablement. TF assigns these bits to ``00`` meaning that debug exceptions from Secure EL1 are enabled by the authentication interface. Therefore this issue only exists for AArch32 Secure EL1 code when secure privileged invasive debug is enabled by the authentication interface, at which point the device is vulnerable to other, more serious attacks anyway. However, given that TF contains no support for handling debug exceptions, the ``MDCR_EL3.SPD32`` bits should be assigned to ``10`` to disable debug exceptions from AArch32 Secure EL1. Finally, this also issue applies to AArch32 platforms that use the TF SP_MIN image or integrate the `AArch32 equivalent`_ of the ``el3_arch_init_common`` macro. Here the affected bits are ``SDCR.SPD``, which should also be assigned to ``10`` instead of ``00`` .. _CVE-2017-7564: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7564 .. _commit 495f3d3: https://github.com/ARM-software/arm-trusted-firmware/commit/495f3d3 .. _AArch64 macro: https://github.com/ARM-software/arm-trusted-firmware/blob/bcc2bf0/include/common/aarch64/el3_common_macros.S#L85 .. _AArch32 equivalent: https://github.com/ARM-software/arm-trusted-firmware/blob/bcc2bf0/include/common/aarch32/el3_common_macros.S#L41 .. _Pull Request #841: https://github.com/ARM-software/arm-trusted-firmware/pull/841 trusted-firmware-a-2.2/docs/security_advisories/security-advisory-tfv-3.rst000066400000000000000000000120361355360272700273360ustar00rootroot00000000000000Advisory TFV-3 (CVE-2017-7563) ============================== +----------------+-------------------------------------------------------------+ | Title | RO memory is always executable at AArch64 Secure EL1 | +================+=============================================================+ | CVE ID | `CVE-2017-7563`_ | +----------------+-------------------------------------------------------------+ | Date | 06 Apr 2017 | +----------------+-------------------------------------------------------------+ | Versions | v1.3 (since `Pull Request #662`_) | | Affected | | +----------------+-------------------------------------------------------------+ | Configurations | AArch64 BL2, TSP or other users of xlat_tables library | | Affected | executing at AArch64 Secure EL1 | +----------------+-------------------------------------------------------------+ | Impact | Unexpected Privilege Escalation | +----------------+-------------------------------------------------------------+ | Fix Version | `Pull Request #924`_ | +----------------+-------------------------------------------------------------+ | Credit | ARM | +----------------+-------------------------------------------------------------+ The translation table library in ARM Trusted Firmware (TF) (under ``lib/xlat_tables`` and ``lib/xlat_tables_v2``) provides APIs to help program translation tables in the MMU. The xlat\_tables client specifies its required memory mappings in the form of ``mmap_region`` structures. Each ``mmap_region`` has memory attributes represented by the ``mmap_attr_t`` enumeration type. This contains flags to control data access permissions (``MT_RO``/``MT_RW``) and instruction execution permissions (``MT_EXECUTE``/``MT_EXECUTE_NEVER``). Thus a mapping specifying both ``MT_RO`` and ``MT_EXECUTE_NEVER`` should result in a Read-Only (RO), non-executable memory region. This feature does not work correctly for AArch64 images executing at Secure EL1. Any memory region mapped as RO will always be executable, regardless of whether the client specified ``MT_EXECUTE`` or ``MT_EXECUTE_NEVER``. The vulnerability is known to affect the BL2 and Test Secure Payload (TSP) images on platforms that enable the ``SEPARATE_CODE_AND_RODATA`` build option, which includes all ARM standard platforms, and the upstream Xilinx and NVidia platforms. The RO data section for these images on these platforms is unexpectedly executable instead of non-executable. Other platforms or ``xlat_tables`` clients may also be affected. The vulnerability primarily manifests itself after `Pull Request #662`_. Before that, ``xlat_tables`` clients could not specify instruction execution permissions separately to data access permissions. All RO normal memory regions were implicitly executable. Before `Pull Request #662`_. the vulnerability would only manifest itself for device memory mapped as RO; use of this mapping is considered rare, although the upstream QEMU platform uses this mapping when the ``DEVICE2_BASE`` build option is used. Note that one or more separate vulnerabilities are also required to exploit this vulnerability. The vulnerability is due to incorrect handling of the execute-never bits in the translation tables. The EL3 translation regime uses a single ``XN`` bit to determine whether a region is executable. The Secure EL1&0 translation regime handles 2 Virtual Address (VA) ranges and so uses 2 bits, ``UXN`` and ``PXN``. The ``xlat_tables`` library only handles the ``XN`` bit, which maps to ``UXN`` in the Secure EL1&0 regime. As a result, this programs the Secure EL0 execution permissions but always leaves the memory as executable at Secure EL1. The vulnerability is mitigated by the following factors: - The xlat\_tables library ensures that all Read-Write (RW) memory regions are non-executable by setting the ``SCTLR_ELx.WXN`` bit. This overrides any value of the ``XN``, ``UXN`` or ``PXN`` bits in the translation tables. See the ``enable_mmu()`` function: :: sctlr = read_sctlr_el##_el(); \ sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT; \ - AArch32 configurations are unaffected. Here the ``XN`` bit controls execution privileges of the currently executing translation regime, which is the desired behaviour. - ARM TF EL3 code (for example BL1 and BL31) ensures that all non-secure memory mapped into the secure world is non-executable by setting the ``SCR_EL3.SIF`` bit. See the ``el3_arch_init_common`` macro in ``el3_common_macros.S``. .. _CVE-2017-7563: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-7563 .. _Pull Request #662: https://github.com/ARM-software/arm-trusted-firmware/pull/662 .. _Pull Request #924: https://github.com/ARM-software/arm-trusted-firmware/pull/924 trusted-firmware-a-2.2/docs/security_advisories/security-advisory-tfv-4.rst000066400000000000000000000150221355360272700273350ustar00rootroot00000000000000Advisory TFV-4 (CVE-2017-9607) ============================== +----------------+-------------------------------------------------------------+ | Title | Malformed Firmware Update SMC can result in copy or | | | authentication of unexpected data in secure memory in | | | AArch32 state | +================+=============================================================+ | CVE ID | `CVE-2017-9607`_ | +----------------+-------------------------------------------------------------+ | Date | 20 Jun 2017 | +----------------+-------------------------------------------------------------+ | Versions | None (only between 22 May 2017 and 14 June 2017) | | Affected | | +----------------+-------------------------------------------------------------+ | Configurations | Platforms that use AArch32 BL1 plus untrusted normal world | | Affected | firmware update code executing before BL31 | +----------------+-------------------------------------------------------------+ | Impact | Copy or authentication of unexpected data in the secure | | | memory | +----------------+-------------------------------------------------------------+ | Fix Version | `Pull Request #979`_ (merged on 14 June 2017) | +----------------+-------------------------------------------------------------+ | Credit | ARM | +----------------+-------------------------------------------------------------+ The ``include/lib/utils_def.h`` header file provides the ``check_uptr_overflow()`` macro, which aims at detecting arithmetic overflows that may occur when computing the sum of a base pointer and an offset. This macro evaluates to 1 if the sum of the given base pointer and offset would result in a value large enough to wrap around, which may lead to unpredictable behaviour. The macro code is at line 52, referring to the version of the code as of `commit c396b73`_: .. code:: c /* * Evaluates to 1 if (ptr + inc) overflows, 0 otherwise. * Both arguments must be unsigned pointer values (i.e. uintptr_t). */ #define check_uptr_overflow(ptr, inc) \ (((ptr) > UINTPTR_MAX - (inc)) ? 1 : 0) This macro does not work correctly for AArch32 images. It fails to detect overflows when the sum of its two parameters fall into the ``[2^32, 2^64 - 1]`` range. Therefore, any AArch32 code relying on this macro to detect such integer overflows is actually not protected. The buggy code has been present in ARM Trusted Firmware (TF) since `Pull Request #678`_ was merged (on 18 August 2016). However, the upstream code was not vulnerable until `Pull Request #939`_ was merged (on 22 May 2017), which introduced AArch32 support for the Trusted Board Boot (TBB) feature. Before then, the ``check_uptr_overflow()`` macro was not used in AArch32 code. The vulnerability resides in the BL1 FWU SMC handling code and it may be exploited when *all* the following conditions apply: - Platform code uses TF BL1 with the ``TRUSTED_BOARD_BOOT`` build option. - Platform code uses the Firmware Update (FWU) code provided in ``bl1/bl1_fwu.c``, which is part of the TBB support. - TF BL1 is compiled with the ``ARCH=aarch32`` build option. In this context, the AArch32 BL1 image might fail to detect potential integer overflows in the input validation checks while handling the ``FWU_SMC_IMAGE_COPY`` and ``FWU_SMC_IMAGE_AUTH`` SMCs. The ``FWU_SMC_IMAGE_COPY`` SMC handler is designed to copy an image into secure memory for subsequent authentication. This is implemented by the ``bl1_fwu_image_copy()`` function, which has the following function prototype: .. code:: c static int bl1_fwu_image_copy(unsigned int image_id, uintptr_t image_src, unsigned int block_size, unsigned int image_size, unsigned int flags) ``image_src`` is an SMC argument and therefore potentially controllable by an attacker. A very large 32-bit value, for example ``2^32 -1``, may result in the sum of ``image_src`` and ``block_size`` overflowing a 32-bit type, which ``check_uptr_overflow()`` will fail to detect. Depending on its implementation, the platform-specific function ``bl1_plat_mem_check()`` might get defeated by these unsanitized values and allow the following memory copy operation, that would wrap around. This may allow an attacker to copy unexpected data into secure memory if the memory is mapped in BL1's address space, or cause a fatal exception if it's not. The ``FWU_SMC_IMAGE_AUTH`` SMC handler is designed to authenticate an image resident in secure memory. This is implemented by the ``bl1_fwu_image_auth()`` function, which has the following function prototype: .. code:: c static int bl1_fwu_image_auth(unsigned int image_id, uintptr_t image_src, unsigned int image_size, unsigned int flags) Similarly, if an attacker has control over the ``image_src`` or ``image_size`` arguments through the SMC interface and injects high values whose sum overflows, they might defeat the ``bl1_plat_mem_check()`` function and make the authentication module read data outside of what's normally allowed by the platform code or crash the platform. Note that in both cases, a separate vulnerability is required to leverage this vulnerability; for example a way to get the system to change its behaviour based on the unexpected secure memory accesses. Moreover, the normal world FWU code would need to be compromised in order to send a malformed FWU SMC that triggers an integer overflow. The vulnerability is known to affect all ARM standard platforms when enabling the ``TRUSTED_BOARD_BOOT`` and ``ARCH=aarch32`` build options. Other platforms may also be affected if they fulfil the above conditions. .. _CVE-2017-9607: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-9607 .. _commit c396b73: https://github.com/ARM-software/arm-trusted-firmware/commit/c396b73 .. _Pull Request #678: https://github.com/ARM-software/arm-trusted-firmware/pull/678 .. _Pull Request #939: https://github.com/ARM-software/arm-trusted-firmware/pull/939 .. _Pull Request #979: https://github.com/ARM-software/arm-trusted-firmware/pull/979 trusted-firmware-a-2.2/docs/security_advisories/security-advisory-tfv-5.rst000066400000000000000000000056571355360272700273530ustar00rootroot00000000000000Advisory TFV-5 (CVE-2017-15031) =============================== +----------------+-------------------------------------------------------------+ | Title | Not initializing or saving/restoring ``PMCR_EL0`` can leak | | | secure world timing information | +================+=============================================================+ | CVE ID | `CVE-2017-15031`_ | +----------------+-------------------------------------------------------------+ | Date | 02 Oct 2017 | +----------------+-------------------------------------------------------------+ | Versions | All, up to and including v1.4 | | Affected | | +----------------+-------------------------------------------------------------+ | Configurations | All | | Affected | | +----------------+-------------------------------------------------------------+ | Impact | Leakage of sensitive secure world timing information | +----------------+-------------------------------------------------------------+ | Fix Version | `Pull Request #1127`_ (merged on 18 October 2017) | +----------------+-------------------------------------------------------------+ | Credit | Arm | +----------------+-------------------------------------------------------------+ The ``PMCR_EL0`` (Performance Monitors Control Register) provides details of the Performance Monitors implementation, including the number of counters implemented, and configures and controls the counters. If the ``PMCR_EL0.DP`` bit is set to zero, the cycle counter (when enabled) counts during secure world execution, even when prohibited by the debug signals. Since Arm TF does not save and restore ``PMCR_EL0`` when switching between the normal and secure worlds, normal world code can set ``PMCR_EL0.DP`` to zero to cause leakage of secure world timing information. This register should be added to the list of saved/restored registers. Furthermore, ``PMCR_EL0.DP`` has an architecturally ``UNKNOWN`` reset value. Since Arm TF does not initialize this register, it's possible that on at least some implementations, ``PMCR_EL0.DP`` is set to zero by default. This and other bits with an architecturally UNKNOWN reset value should be initialized to sensible default values in the secure context. The same issue exists for the equivalent AArch32 register, ``PMCR``, except that here ``PMCR_EL0.DP`` architecturally resets to zero. .. _CVE-2017-15031: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-15031 .. _Pull Request #1127: https://github.com/ARM-software/arm-trusted-firmware/pull/1127 trusted-firmware-a-2.2/docs/security_advisories/security-advisory-tfv-6.rst000066400000000000000000000217221355360272700273430ustar00rootroot00000000000000Advisory TFV-6 (CVE-2017-5753, CVE-2017-5715, CVE-2017-5754) ============================================================ +----------------+-------------------------------------------------------------+ | Title | Trusted Firmware-A exposure to speculative processor | | | vulnerabilities using cache timing side-channels | +================+=============================================================+ | CVE ID | `CVE-2017-5753`_ / `CVE-2017-5715`_ / `CVE-2017-5754`_ | +----------------+-------------------------------------------------------------+ | Date | 03 Jan 2018 (Updated 11 Jan, 18 Jan, 26 Jan, 30 Jan and 07 | | | June 2018) | +----------------+-------------------------------------------------------------+ | Versions | All, up to and including v1.4 | | Affected | | +----------------+-------------------------------------------------------------+ | Configurations | All | | Affected | | +----------------+-------------------------------------------------------------+ | Impact | Leakage of secure world data to normal world | +----------------+-------------------------------------------------------------+ | Fix Version | `Pull Request #1214`_, `Pull Request #1228`_, | | | `Pull Request #1240`_ and `Pull Request #1405`_ | +----------------+-------------------------------------------------------------+ | Credit | Google / Arm | +----------------+-------------------------------------------------------------+ This security advisory describes the current understanding of the Trusted Firmware-A exposure to the speculative processor vulnerabilities identified by `Google Project Zero`_. To understand the background and wider impact of these vulnerabilities on Arm systems, please refer to the `Arm Processor Security Update`_. Variant 1 (`CVE-2017-5753`_) ---------------------------- At the time of writing, no vulnerable patterns have been observed in upstream TF code, therefore no workarounds have been applied or are planned. Variant 2 (`CVE-2017-5715`_) ---------------------------- Where possible on vulnerable CPUs, Arm recommends invalidating the branch predictor as early as possible on entry into the secure world, before any branch instruction is executed. There are a number of implementation defined ways to achieve this. For Cortex-A57 and Cortex-A72 CPUs, the Pull Requests (PRs) in this advisory invalidate the branch predictor when entering EL3 by disabling and re-enabling the MMU. For Cortex-A73 and Cortex-A75 CPUs, the PRs in this advisory invalidate the branch predictor when entering EL3 by temporarily dropping into AArch32 Secure-EL1 and executing the ``BPIALL`` instruction. This workaround is significantly more complex than the "MMU disable/enable" workaround. The latter is not effective at invalidating the branch predictor on Cortex-A73/Cortex-A75. Note that if other privileged software, for example a Rich OS kernel, implements its own branch predictor invalidation during context switch by issuing an SMC (to execute firmware branch predictor invalidation), then there is a dependency on the PRs in this advisory being deployed in order for those workarounds to work. If that other privileged software is able to workaround the vulnerability locally (for example by implementing "MMU disable/enable" itself), there is no such dependency. `Pull Request #1240`_ and `Pull Request #1405`_ optimise the earlier fixes by implementing a specified `CVE-2017-5715`_ workaround SMC (``SMCCC_ARCH_WORKAROUND_1``) for use by normal world privileged software. This is more efficient than calling an arbitrary SMC (for example ``PSCI_VERSION``). Details of ``SMCCC_ARCH_WORKAROUND_1`` can be found in the `CVE-2017-5715 mitigation specification`_. The specification and implementation also enable the normal world to discover the presence of this firmware service. On Juno R1 we measured the round trip latency for both the ``PSCI_VERSION`` and ``SMCCC_ARCH_WORKAROUND_1`` SMCs on Cortex-A57, using both the "MMU disable/enable" and "BPIALL at AArch32 Secure-EL1" workarounds described above. This includes the time spent in test code conforming to the SMC Calling Convention (SMCCC) from AArch64. For the ``SMCCC_ARCH_WORKAROUND_1`` cases, the test code uses SMCCC v1.1, which reduces the number of general purpose registers it needs to save/restore. Although the ``BPIALL`` instruction is not effective at invalidating the branch predictor on Cortex-A57, the drop into Secure-EL1 with MMU disabled that this workaround entails effectively does invalidate the branch predictor. Hence this is a reasonable comparison. The results were as follows: +------------------------------------------------------------------+-----------+ | Test | Time (ns) | +==================================================================+===========+ | ``PSCI_VERSION`` baseline (without PRs in this advisory) | 515 | +------------------------------------------------------------------+-----------+ | ``PSCI_VERSION`` baseline (with PRs in this advisory) | 527 | +------------------------------------------------------------------+-----------+ | ``PSCI_VERSION`` with "MMU disable/enable" | 930 | +------------------------------------------------------------------+-----------+ | ``SMCCC_ARCH_WORKAROUND_1`` with "MMU disable/enable" | 386 | +------------------------------------------------------------------+-----------+ | ``PSCI_VERSION`` with "BPIALL at AArch32 Secure-EL1" | 1276 | +------------------------------------------------------------------+-----------+ | ``SMCCC_ARCH_WORKAROUND_1`` with "BPIALL at AArch32 Secure-EL1" | 770 | +------------------------------------------------------------------+-----------+ Due to the high severity and wide applicability of this issue, the above workarounds are enabled by default (on vulnerable CPUs only), despite some performance and code size overhead. Platforms can choose to disable them at compile time if they do not require them. `Pull Request #1240`_ disables the workarounds for unaffected upstream platforms. For vulnerable AArch32-only CPUs (for example Cortex-A8, Cortex-A9 and Cortex-A17), the ``BPIALL`` instruction should be used as early as possible on entry into the secure world. For Cortex-A8, also set ``ACTLR[6]`` to 1 during early processor initialization. Note that the ``BPIALL`` instruction is not effective at invalidating the branch predictor on Cortex-A15. For that CPU, set ``ACTLR[0]`` to 1 during early processor initialization, and invalidate the branch predictor by performing an ``ICIALLU`` instruction. On AArch32 EL3 systems, the monitor and secure-SVC code is typically tightly integrated, for example as part of a Trusted OS. Therefore any Variant 2 workaround should be provided by vendors of that software and is outside the scope of TF. However, an example implementation in the minimal AArch32 Secure Payload, ``SP_MIN`` is provided in `Pull Request #1228`_. Other Arm CPUs are not vulnerable to this or other variants. This includes Cortex-A76, Cortex-A53, Cortex-A55, Cortex-A32, Cortex-A7 and Cortex-A5. For more information about non-Arm CPUs, please contact the CPU vendor. Variant 3 (`CVE-2017-5754`_) ---------------------------- This variant is only exploitable between Exception Levels within the same translation regime, for example between EL0 and EL1, therefore this variant cannot be used to access secure memory from the non-secure world, and is not applicable for TF. However, Secure Payloads (for example, Trusted OS) should provide mitigations on vulnerable CPUs to protect themselves from exploited Secure-EL0 applications. The only Arm CPU vulnerable to this variant is Cortex-A75. .. _Google Project Zero: https://googleprojectzero.blogspot.co.uk/2018/01/reading-privileged-memory-with-side.html .. _Arm Processor Security Update: http://www.arm.com/security-update .. _CVE-2017-5753: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5753 .. _CVE-2017-5715: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5715 .. _CVE-2017-5754: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5754 .. _Pull Request #1214: https://github.com/ARM-software/arm-trusted-firmware/pull/1214 .. _Pull Request #1228: https://github.com/ARM-software/arm-trusted-firmware/pull/1228 .. _Pull Request #1240: https://github.com/ARM-software/arm-trusted-firmware/pull/1240 .. _Pull Request #1405: https://github.com/ARM-software/arm-trusted-firmware/pull/1405 .. _CVE-2017-5715 mitigation specification: https://developer.arm.com/cache-speculation-vulnerability-firmware-specification trusted-firmware-a-2.2/docs/security_advisories/security-advisory-tfv-7.rst000066400000000000000000000143141355360272700273430ustar00rootroot00000000000000Advisory TFV-7 (CVE-2018-3639) ============================== +----------------+-------------------------------------------------------------+ | Title | Trusted Firmware-A exposure to cache speculation | | | vulnerability Variant 4 | +================+=============================================================+ | CVE ID | `CVE-2018-3639`_ | +----------------+-------------------------------------------------------------+ | Date | 21 May 2018 (Updated 7 June 2018) | +----------------+-------------------------------------------------------------+ | Versions | All, up to and including v1.5 | | Affected | | +----------------+-------------------------------------------------------------+ | Configurations | All | | Affected | | +----------------+-------------------------------------------------------------+ | Impact | Leakage of secure world data to normal world | +----------------+-------------------------------------------------------------+ | Fix Version | `Pull Request #1392`_, `Pull Request #1397`_ | +----------------+-------------------------------------------------------------+ | Credit | Google | +----------------+-------------------------------------------------------------+ This security advisory describes the current understanding of the Trusted Firmware-A (TF-A) exposure to Variant 4 of the cache speculation vulnerabilities identified by `Google Project Zero`_. To understand the background and wider impact of these vulnerabilities on Arm systems, please refer to the `Arm Processor Security Update`_. At the time of writing, the TF-A project is not aware of a Variant 4 exploit that could be used against TF-A. It is likely to be very difficult to achieve an exploit against current standard configurations of TF-A, due to the limited interfaces into the secure world with attacker-controlled inputs. However, this is becoming increasingly difficult to guarantee with the introduction of complex new firmware interfaces, for example the `Software Delegated Exception Interface (SDEI)`_. Also, the TF-A project does not have visibility of all vendor-supplied interfaces. Therefore, the TF-A project takes a conservative approach by mitigating Variant 4 in hardware wherever possible during secure world execution. The mitigation is enabled by setting an implementation defined control bit to prevent the re-ordering of stores and loads. For each affected CPU type, TF-A implements one of the two following mitigation approaches in `Pull Request #1392`_ and `Pull Request #1397`_. Both approaches have a system performance impact, which varies for each CPU type and use-case. The mitigation code is enabled by default, but can be disabled at compile time for platforms that are unaffected or where the risk is deemed low enough. Arm CPUs not mentioned below are unaffected. Static mitigation ----------------- For affected CPUs, this approach enables the mitigation during EL3 initialization, following every PE reset. No mechanism is provided to disable the mitigation at runtime. This approach permanently mitigates the entire software stack and no additional mitigation code is required in other software components. TF-A implements this approach for the following affected CPUs: - Cortex-A57 and Cortex-A72, by setting bit 55 (Disable load pass store) of ``CPUACTLR_EL1`` (``S3_1_C15_C2_0``). - Cortex-A73, by setting bit 3 of ``S3_0_C15_C0_0`` (not documented in the Technical Reference Manual (TRM)). - Cortex-A75, by setting bit 35 (reserved in TRM) of ``CPUACTLR_EL1`` (``S3_0_C15_C1_0``). Dynamic mitigation ------------------ For affected CPUs, this approach also enables the mitigation during EL3 initialization, following every PE reset. In addition, this approach implements ``SMCCC_ARCH_WORKAROUND_2`` in the Arm architectural range to allow callers at lower exception levels to temporarily disable the mitigation in their execution context, where the risk is deemed low enough. This approach enables mitigation on entry to EL3, and restores the mitigation state of the lower exception level on exit from EL3. For more information on this approach, see `Firmware interfaces for mitigating cache speculation vulnerabilities`_. This approach may be complemented by additional mitigation code in other software components, for example code that calls ``SMCCC_ARCH_WORKAROUND_2``. However, even without any mitigation code in other software components, this approach will effectively permanently mitigate the entire software stack, since the default mitigation state for firmware-managed execution contexts is enabled. Since the expectation in this approach is that more software executes with the mitigation disabled, this may result in better system performance than the static approach for some systems or use-cases. However, for other systems or use-cases, this performance saving may be outweighed by the additional overhead of ``SMCCC_ARCH_WORKAROUND_2`` calls and TF-A exception handling. TF-A implements this approach for the following affected CPU: - Cortex-A76, by setting and clearing bit 16 (reserved in TRM) of ``CPUACTLR2_EL1`` (``S3_0_C15_C1_1``). .. _Google Project Zero: https://bugs.chromium.org/p/project-zero/issues/detail?id=1528 .. _Arm Processor Security Update: http://www.arm.com/security-update .. _CVE-2018-3639: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3639 .. _Software Delegated Exception Interface (SDEI): http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf .. _Firmware interfaces for mitigating cache speculation vulnerabilities: https://developer.arm.com/cache-speculation-vulnerability-firmware-specification .. _Pull Request #1392: https://github.com/ARM-software/arm-trusted-firmware/pull/1392 .. _Pull Request #1397: https://github.com/ARM-software/arm-trusted-firmware/pull/1397 trusted-firmware-a-2.2/docs/security_advisories/security-advisory-tfv-8.rst000066400000000000000000000135511355360272700273460ustar00rootroot00000000000000Advisory TFV-8 (CVE-2018-19440) =============================== +----------------+-------------------------------------------------------------+ | Title | Not saving x0 to x3 registers can leak information from one | | | Normal World SMC client to another | +================+=============================================================+ | CVE ID | `CVE-2018-19440`_ | +----------------+-------------------------------------------------------------+ | Date | 27 Nov 2018 | +----------------+-------------------------------------------------------------+ | Versions | All | | Affected | | +----------------+-------------------------------------------------------------+ | Configurations | Multiple normal world SMC clients calling into AArch64 BL31 | | Affected | | +----------------+-------------------------------------------------------------+ | Impact | Leakage of SMC return values from one normal world SMC | | | client to another | +----------------+-------------------------------------------------------------+ | Fix Version | `Pull Request #1710`_ | +----------------+-------------------------------------------------------------+ | Credit | Secmation | +----------------+-------------------------------------------------------------+ When taking an exception to EL3, BL31 saves the CPU context. The aim is to restore it before returning into the lower exception level software that called into the firmware. However, for an SMC exception, the general purpose registers ``x0`` to ``x3`` are not part of the CPU context saved on the stack. As per the `SMC Calling Convention`_, up to 4 values may be returned to the caller in registers ``x0`` to ``x3``. In TF-A, these return values are written into the CPU context, typically using one of the ``SMC_RETx()`` macros provided in the ``include/lib/aarch64/smccc_helpers.h`` header file. Before returning to the caller, the ``restore_gp_registers()`` function is called. It restores the values of all general purpose registers taken from the CPU context stored on the stack. This includes registers ``x0`` to ``x3``, as can be seen in the ``lib/el3_runtime/aarch64/context.S`` file at line 339 (referring to the version of the code as of `commit c385955`_): :: /* * This function restores all general purpose registers except x30 from the * CPU context. x30 register must be explicitly restored by the caller. */ func restore_gp_registers ldp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] In the case of an SMC handler that does not use all 4 return values, the remaining ones are left unchanged in the CPU context. As a result, ``restore_gp_registers()`` restores the stale values saved by a previous SMC request (or asynchronous exception to EL3) that used these return values. In the presence of multiple normal world SMC clients, this behaviour might leak some of the return values from one client to another. For example, if a victim client first sends an SMC that returns 4 values, a malicious client may then send a second SMC expecting no return values (for example, a ``SDEI_EVENT_COMPLETE`` SMC) to get the 4 return values of the victim client. In general, the responsibility for mitigating threats due to the presence of multiple normal world SMC clients lies with EL2 software. When present, EL2 software must trap SMC calls from EL1 software to ensure secure behaviour. For this reason, TF-A does not save ``x0`` to ``x3`` in the CPU context on an SMC synchronous exception. It has behaved this way since the first version. We can confirm that at least upstream KVM-based systems mitigate this threat, and are therefore unaffected by this issue. Other EL2 software should be audited to assess the impact of this threat. EL2 software might find mitigating this threat somewhat onerous, because for all SMCs it would need to be aware of which return registers contain valid data, so it can sanitise any unused return registers. On the other hand, mitigating this in EL3 is relatively easy and cheap. Therefore, TF-A will now ensure that no information is leaked through registers ``x0`` to ``x3``, by preserving the register state over the call. Note that AArch32 TF-A is not affected by this issue. The SMC handling code in ``SP_MIN`` already saves all general purpose registers - including ``r0`` to ``r3``, as can be seen in the ``include/lib/aarch32/smccc_macros.S`` file at line 19 (referring to the version of the code as of `commit c385955`_): .. code:: c /* * Macro to save the General purpose registers (r0 - r12), the banked * spsr, lr, sp registers and the `scr` register to the SMC context on entry * due a SMC call. The `lr` of the current mode (monitor) is expected to be * already saved. The `sp` must point to the `smc_ctx_t` to save to. * Additionally, also save the 'pmcr' register as this is updated whilst * executing in the secure world. */ .macro smccc_save_gp_mode_regs /* Save r0 - r12 in the SMC context */ stm sp, {r0-r12} .. _CVE-2018-19440: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-19440 .. _commit c385955: https://github.com/ARM-software/arm-trusted-firmware/commit/c385955 .. _SMC Calling Convention: http://arminfo.emea.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf .. _Pull Request #1710: https://github.com/ARM-software/arm-trusted-firmware/pull/1710 trusted-firmware-a-2.2/drivers/000077500000000000000000000000001355360272700165675ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/allwinner/000077500000000000000000000000001355360272700205625ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/allwinner/sunxi_rsb.c000066400000000000000000000063241355360272700227470ustar00rootroot00000000000000/* * Copyright (c) 2017-2018 ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #define RSB_CTRL 0x00 #define RSB_CCR 0x04 #define RSB_INTE 0x08 #define RSB_STAT 0x0c #define RSB_DADDR0 0x10 #define RSB_DLEN 0x18 #define RSB_DATA0 0x1c #define RSB_LCR 0x24 #define RSB_PMCR 0x28 #define RSB_CMD 0x2c #define RSB_SADDR 0x30 #define RSBCMD_SRTA 0xE8 #define RSBCMD_RD8 0x8B #define RSBCMD_RD16 0x9C #define RSBCMD_RD32 0xA6 #define RSBCMD_WR8 0x4E #define RSBCMD_WR16 0x59 #define RSBCMD_WR32 0x63 #define MAX_TRIES 100000 static int rsb_wait_bit(const char *desc, unsigned int offset, uint32_t mask) { uint32_t reg, tries = MAX_TRIES; do reg = mmio_read_32(SUNXI_R_RSB_BASE + offset); while ((reg & mask) && --tries); /* transaction in progress */ if (reg & mask) { ERROR("%s: timed out\n", desc); return -ETIMEDOUT; } return 0; } static int rsb_wait_stat(const char *desc) { uint32_t reg; int ret = rsb_wait_bit(desc, RSB_CTRL, BIT(7)); if (ret) return ret; reg = mmio_read_32(SUNXI_R_RSB_BASE + RSB_STAT); if (reg == 0x01) return 0; ERROR("%s: 0x%x\n", desc, reg); return -reg; } /* Initialize the RSB controller. */ int rsb_init_controller(void) { mmio_write_32(SUNXI_R_RSB_BASE + RSB_CTRL, 0x01); /* soft reset */ return rsb_wait_bit("RSB: reset controller", RSB_CTRL, BIT(0)); } int rsb_read(uint8_t rt_addr, uint8_t reg_addr) { int ret; mmio_write_32(SUNXI_R_RSB_BASE + RSB_CMD, RSBCMD_RD8); /* read a byte */ mmio_write_32(SUNXI_R_RSB_BASE + RSB_SADDR, rt_addr << 16); mmio_write_32(SUNXI_R_RSB_BASE + RSB_DADDR0, reg_addr); mmio_write_32(SUNXI_R_RSB_BASE + RSB_CTRL, 0x80);/* start transaction */ ret = rsb_wait_stat("RSB: read command"); if (ret) return ret; return mmio_read_32(SUNXI_R_RSB_BASE + RSB_DATA0) & 0xff; /* result */ } int rsb_write(uint8_t rt_addr, uint8_t reg_addr, uint8_t value) { mmio_write_32(SUNXI_R_RSB_BASE + RSB_CMD, RSBCMD_WR8); /* byte write */ mmio_write_32(SUNXI_R_RSB_BASE + RSB_SADDR, rt_addr << 16); mmio_write_32(SUNXI_R_RSB_BASE + RSB_DADDR0, reg_addr); mmio_write_32(SUNXI_R_RSB_BASE + RSB_DATA0, value); mmio_write_32(SUNXI_R_RSB_BASE + RSB_CTRL, 0x80);/* start transaction */ return rsb_wait_stat("RSB: write command"); } int rsb_set_device_mode(uint32_t device_mode) { mmio_write_32(SUNXI_R_RSB_BASE + RSB_PMCR, (device_mode & 0x00ffffff) | BIT(31)); return rsb_wait_bit("RSB: set device to RSB", RSB_PMCR, BIT(31)); } int rsb_set_bus_speed(uint32_t source_freq, uint32_t bus_freq) { uint32_t reg; if (bus_freq == 0) return -EINVAL; reg = source_freq / bus_freq; if (reg < 2) return -EINVAL; reg = reg / 2 - 1; reg |= (1U << 8); /* one cycle of CD output delay */ mmio_write_32(SUNXI_R_RSB_BASE + RSB_CCR, reg); return 0; } /* Initialize the RSB PMIC connection. */ int rsb_assign_runtime_address(uint16_t hw_addr, uint8_t rt_addr) { mmio_write_32(SUNXI_R_RSB_BASE + RSB_SADDR, hw_addr | (rt_addr << 16)); mmio_write_32(SUNXI_R_RSB_BASE + RSB_CMD, RSBCMD_SRTA); mmio_write_32(SUNXI_R_RSB_BASE + RSB_CTRL, 0x80); return rsb_wait_stat("RSB: set run-time address"); } trusted-firmware-a-2.2/drivers/amlogic/000077500000000000000000000000001355360272700202025ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/amlogic/console/000077500000000000000000000000001355360272700216445ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/amlogic/console/aarch64/000077500000000000000000000000001355360272700230745ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/amlogic/console/aarch64/meson_console.S000066400000000000000000000175311355360272700260720ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl console_meson_register .globl console_meson_init .globl console_meson_putc .globl console_meson_getc .globl console_meson_flush .globl console_meson_core_putc .globl console_meson_core_getc .globl console_meson_core_flush /* ----------------------------------------------- * Hardware definitions * ----------------------------------------------- */ #define MESON_WFIFO_OFFSET 0x0 #define MESON_RFIFO_OFFSET 0x4 #define MESON_CONTROL_OFFSET 0x8 #define MESON_STATUS_OFFSET 0xC #define MESON_MISC_OFFSET 0x10 #define MESON_REG5_OFFSET 0x14 #define MESON_CONTROL_CLR_ERROR_BIT 24 #define MESON_CONTROL_RX_RESET_BIT 23 #define MESON_CONTROL_TX_RESET_BIT 22 #define MESON_CONTROL_RX_ENABLE_BIT 13 #define MESON_CONTROL_TX_ENABLE_BIT 12 #define MESON_STATUS_RX_EMPTY_BIT 20 #define MESON_STATUS_TX_FULL_BIT 21 #define MESON_STATUS_TX_EMPTY_BIT 22 #define MESON_REG5_USE_XTAL_CLK_BIT 24 #define MESON_REG5_USE_NEW_RATE_BIT 23 #define MESON_REG5_NEW_BAUD_RATE_MASK 0x7FFFFF /* ----------------------------------------------- * int console_meson_register(uintptr_t base, * uint32_t clk, uint32_t baud, * console_meson_t *console); * Function to initialize and register a new MESON * console. Storage passed in for the console struct * *must* be persistent (i.e. not from the stack). * In: x0 - UART register base address * w1 - UART clock in Hz * w2 - Baud rate * x3 - pointer to empty console_meson_t struct * Out: return 1 on success, 0 on error * Clobber list : x0, x1, x2, x6, x7, x14 * ----------------------------------------------- */ func console_meson_register mov x7, x30 mov x6, x3 cbz x6, register_fail str x0, [x6, #CONSOLE_T_MESON_BASE] bl console_meson_init cbz x0, register_fail mov x0, x6 mov x30, x7 finish_console_register meson putc=1, getc=1, flush=1 register_fail: ret x7 endfunc console_meson_register /* ----------------------------------------------- * int console_meson_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. This * function will be accessed by console_init and * crash reporting. * In: x0 - console base address * w1 - Uart clock in Hz * w2 - Baud rate * Out: return 1 on success else 0 on error * Clobber list : x0-x3 * ----------------------------------------------- */ func console_meson_init cmp w0, #0 beq init_fail mov_imm w3, 24000000 /* TODO: This only works with a 24 MHz clock. */ cmp w1, w3 bne init_fail cmp w2, #0 beq init_fail /* Set baud rate: value = ((clock / 3) / baudrate) - 1 */ mov w3, #3 udiv w3, w1, w3 udiv w3, w3, w2 sub w3, w3, #1 orr w3, w3, #((1 << MESON_REG5_USE_XTAL_CLK_BIT) | \ (1 << MESON_REG5_USE_NEW_RATE_BIT)) str w3, [x0, #MESON_REG5_OFFSET] /* Reset UART and clear error flag */ ldr w3, [x0, #MESON_CONTROL_OFFSET] orr w3, w3, #((1 << MESON_CONTROL_CLR_ERROR_BIT) | \ (1 << MESON_CONTROL_RX_RESET_BIT) | \ (1 << MESON_CONTROL_TX_RESET_BIT)) str w3, [x0, #MESON_CONTROL_OFFSET] bic w3, w3, #((1 << MESON_CONTROL_CLR_ERROR_BIT) | \ (1 << MESON_CONTROL_RX_RESET_BIT) | \ (1 << MESON_CONTROL_TX_RESET_BIT)) str w3, [x0, #MESON_CONTROL_OFFSET] /* Enable transfer and receive FIFO */ orr w3, w3, #((1 << MESON_CONTROL_RX_ENABLE_BIT) | \ (1 << MESON_CONTROL_TX_ENABLE_BIT)) str w3, [x0, #MESON_CONTROL_OFFSET] /* Success */ mov w0, #1 ret init_fail: mov w0, wzr ret endfunc console_meson_init /* -------------------------------------------------------- * int console_meson_putc(int c, console_meson_t *console) * Function to output a character over the console. It * returns the character printed on success or -1 on error. * In : w0 - character to be printed * x1 - pointer to console_t structure * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_meson_putc #if ENABLE_ASSERTIONS cmp x1, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr x1, [x1, #CONSOLE_T_MESON_BASE] b console_meson_core_putc endfunc console_meson_putc /* -------------------------------------------------------- * int console_meson_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. * In : w0 - character to be printed * x1 - console base address * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_meson_core_putc #if ENABLE_ASSERTIONS cmp x1, #0 ASM_ASSERT(ne) #endif /* Prepend '\r' to '\n' */ cmp w0, #0xA b.ne 2f /* Wait until the transmit FIFO isn't full */ 1: ldr w2, [x1, #MESON_STATUS_OFFSET] tbnz w2, #MESON_STATUS_TX_FULL_BIT, 1b /* Write '\r' if needed */ mov w2, #0xD str w2, [x1, #MESON_WFIFO_OFFSET] /* Wait until the transmit FIFO isn't full */ 2: ldr w2, [x1, #MESON_STATUS_OFFSET] tbnz w2, #MESON_STATUS_TX_FULL_BIT, 2b /* Write input character */ str w0, [x1, #MESON_WFIFO_OFFSET] ret endfunc console_meson_core_putc /* --------------------------------------------- * int console_meson_getc(console_meson_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 : x0 - pointer to console_t structure * Out: w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ func console_meson_getc #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr x0, [x0, #CONSOLE_T_MESON_BASE] b console_meson_core_getc endfunc console_meson_getc /* --------------------------------------------- * int console_meson_core_getc(uintptr_t base_addr) * Function to get a character from the console. * It returns the character grabbed on success * or -1 if no character is available. * In : x0 - console base address * Out: w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ func console_meson_core_getc #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* Is the receive FIFO empty? */ ldr w1, [x0, #MESON_STATUS_OFFSET] tbnz w1, #MESON_STATUS_RX_EMPTY_BIT, 1f /* Read one character from the RX FIFO */ ldr w0, [x0, #MESON_RFIFO_OFFSET] ret 1: mov w0, #ERROR_NO_PENDING_CHAR ret endfunc console_meson_core_getc /* --------------------------------------------- * int console_meson_flush(console_meson_t *console) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - pointer to console_t structure * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func console_meson_flush #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr x0, [x0, #CONSOLE_T_MESON_BASE] b console_meson_core_flush endfunc console_meson_flush /* --------------------------------------------- * int console_meson_core_flush(uintptr_t base_addr) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - console base address * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func console_meson_core_flush #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* Wait until the transmit FIFO is empty */ 1: ldr w1, [x0, #MESON_STATUS_OFFSET] tbz w1, #MESON_STATUS_TX_EMPTY_BIT, 1b mov w0, #0 ret endfunc console_meson_core_flush trusted-firmware-a-2.2/drivers/amlogic/crypto/000077500000000000000000000000001355360272700215225ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/amlogic/crypto/sha_dma.c000066400000000000000000000127311355360272700232660ustar00rootroot00000000000000/* * Copyright (c) 2019, Remi Pommarel * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "aml_private.h" #define ASD_MODE_SHA224 0x7 #define ASD_MODE_SHA256 0x6 /* SHA DMA descriptor */ struct asd_desc { uint32_t cfg; uint32_t src; uint32_t dst; }; #define ASD_DESC_GET(x, msk, off) (((x) >> (off)) & (msk)) #define ASD_DESC_SET(x, v, msk, off) \ ((x) = ((x) & ~((msk) << (off))) | (((v) & (msk)) << (off))) #define ASD_DESC_LEN_OFF 0 #define ASD_DESC_LEN_MASK 0x1ffff #define ASD_DESC_LEN(d) \ (ASD_DESC_GET((d)->cfg, ASD_DESC_LEN_MASK, ASD_DESC_LEN_OFF)) #define ASD_DESC_LEN_SET(d, v) \ (ASD_DESC_SET((d)->cfg, v, ASD_DESC_LEN_MASK, ASD_DESC_LEN_OFF)) #define ASD_DESC_IRQ_OFF 17 #define ASD_DESC_IRQ_MASK 0x1 #define ASD_DESC_IRQ(d) \ (ASD_DESC_GET((d)->cfg, ASD_DESC_IRQ_MASK, ASD_DESC_IRQ_OFF)) #define ASD_DESC_IRQ_SET(d, v) \ (ASD_DESC_SET((d)->cfg, v, ASD_DESC_IRQ_MASK, ASD_DESC_IRQ_OFF)) #define ASD_DESC_EOD_OFF 18 #define ASD_DESC_EOD_MASK 0x1 #define ASD_DESC_EOD(d) \ (ASD_DESC_GET((d)->cfg, ASD_DESC_EOD_MASK, ASD_DESC_EOD_OFF)) #define ASD_DESC_EOD_SET(d, v) \ (ASD_DESC_SET((d)->cfg, v, ASD_DESC_EOD_MASK, ASD_DESC_EOD_OFF)) #define ASD_DESC_LOOP_OFF 19 #define ASD_DESC_LOOP_MASK 0x1 #define ASD_DESC_LOOP(d) \ (ASD_DESC_GET((d)->cfg, ASD_DESC_LOOP_MASK, ASD_DESC_LOOP_OFF)) #define ASD_DESC_LOOP_SET(d, v) \ (ASD_DESC_SET((d)->cfg, v, ASD_DESC_LOOP_MASK, ASD_DESC_LOOP_OFF)) #define ASD_DESC_MODE_OFF 20 #define ASD_DESC_MODE_MASK 0xf #define ASD_DESC_MODE(d) \ (ASD_DESC_GET((d)->cfg, ASD_DESC_MODE_MASK, ASD_DESC_MODE_OFF)) #define ASD_DESC_MODE_SET(d, v) \ (ASD_DESC_SET((d)->cfg, v, ASD_DESC_MODE_MASK, ASD_DESC_MODE_OFF)) #define ASD_DESC_BEGIN_OFF 24 #define ASD_DESC_BEGIN_MASK 0x1 #define ASD_DESC_BEGIN(d) \ (ASD_DESC_GET((d)->cfg, ASD_DESC_BEGIN_MASK, ASD_DESC_BEGIN_OFF)) #define ASD_DESC_BEGIN_SET(d, v) \ (ASD_DESC_SET((d)->cfg, v, ASD_DESC_BEGIN_MASK, ASD_DESC_BEGIN_OFF)) #define ASD_DESC_END_OFF 25 #define ASD_DESC_END_MASK 0x1 #define ASD_DESC_END(d) \ (ASD_DESC_GET((d)->cfg, ASD_DESC_END_MASK, ASD_DESC_END_OFF)) #define ASD_DESC_END_SET(d, v) \ (ASD_DESC_SET((d)->cfg, v, ASD_DESC_END_MASK, ASD_DESC_END_OFF)) #define ASD_DESC_OP_OFF 26 #define ASD_DESC_OP_MASK 0x2 #define ASD_DESC_OP(d) \ (ASD_DESC_GET((d)->cfg, ASD_DESC_OP_MASK, ASD_DESC_OP_OFF)) #define ASD_DESC_OP_SET(d, v) \ (ASD_DESC_SET((d)->cfg, v, ASD_DESC_OP_MASK, ASD_DESC_OP_OFF)) #define ASD_DESC_ENCONLY_OFF 28 #define ASD_DESC_ENCONLY_MASK 0x1 #define ASD_DESC_ENCONLY(d) \ (ASD_DESC_GET((d)->cfg, ASD_DESC_ENCONLY_MASK, ASD_DESC_ENCONLY_OFF)) #define ASD_DESC_ENCONLY_SET(d, v) \ (ASD_DESC_SET((d)->cfg, v, ASD_DESC_ENCONLY_MASK, ASD_DESC_ENCONLY_OFF)) #define ASD_DESC_BLOCK_OFF 29 #define ASD_DESC_BLOCK_MASK 0x1 #define ASD_DESC_BLOCK(d) \ (ASD_DESC_GET((d)->cfg, ASD_DESC_BLOCK_MASK, ASD_DESC_BLOCK_OFF)) #define ASD_DESC_BLOCK_SET(d, v) \ (ASD_DESC_SET((d)->cfg, v, ASD_DESC_BLOCK_MASK, ASD_DESC_BLOCK_OFF)) #define ASD_DESC_ERR_OFF 30 #define ASD_DESC_ERR_MASK 0x1 #define ASD_DESC_ERR(d) \ (ASD_DESC_GET((d)->cfg, ASD_DESC_ERR_MASK, ASD_DESC_ERR_OFF)) #define ASD_DESC_ERR_SET(d, v) \ (ASD_DESC_SET((d)->cfg, v, ASD_DESC_ERR_MASK, ASD_DESC_ERR_OFF)) #define ASD_DESC_OWNER_OFF 31u #define ASD_DESC_OWNER_MASK 0x1u #define ASD_DESC_OWNER(d) \ (ASD_DESC_GET((d)->cfg, ASD_DESC_OWNER_MASK, ASD_DESC_OWNER_OFF)) #define ASD_DESC_OWNER_SET(d, v) \ (ASD_DESC_SET((d)->cfg, v, ASD_DESC_OWNER_MASK, ASD_DESC_OWNER_OFF)) static void asd_compute_sha(struct asd_ctx *ctx, void *data, size_t len, int finalize) { /* Make it cache line size aligned ? */ struct asd_desc desc = { .src = (uint32_t)(uintptr_t)data, .dst = (uint32_t)(uintptr_t)ctx->digest, }; /* Check data address is 32bit compatible */ assert((uintptr_t)data == (uintptr_t)desc.src); assert((uintptr_t)ctx->digest == (uintptr_t)desc.dst); assert((uintptr_t)&desc == (uintptr_t)&desc); ASD_DESC_LEN_SET(&desc, len); ASD_DESC_OWNER_SET(&desc, 1u); ASD_DESC_ENCONLY_SET(&desc, 1); ASD_DESC_EOD_SET(&desc, 1); if (ctx->started == 0) { ASD_DESC_BEGIN_SET(&desc, 1); ctx->started = 1; } if (finalize) { ASD_DESC_END_SET(&desc, 1); ctx->started = 0; } if (ctx->mode == ASM_SHA224) ASD_DESC_MODE_SET(&desc, ASD_MODE_SHA224); else ASD_DESC_MODE_SET(&desc, ASD_MODE_SHA256); flush_dcache_range((uintptr_t)&desc, sizeof(desc)); flush_dcache_range((uintptr_t)data, len); mmio_write_32(AML_SHA_DMA_STATUS, 0xf); mmio_write_32(AML_SHA_DMA_DESC, ((uintptr_t)&desc) | 2); while (mmio_read_32(AML_SHA_DMA_STATUS) == 0) continue; flush_dcache_range((uintptr_t)ctx->digest, SHA256_HASHSZ); } void asd_sha_update(struct asd_ctx *ctx, void *data, size_t len) { size_t nr; if (ctx->blocksz) { nr = MIN(len, SHA256_BLOCKSZ - ctx->blocksz); memcpy(ctx->block + ctx->blocksz, data, nr); ctx->blocksz += nr; len -= nr; data += nr; } if (ctx->blocksz == SHA256_BLOCKSZ) { asd_compute_sha(ctx, ctx->block, SHA256_BLOCKSZ, 0); ctx->blocksz = 0; } asd_compute_sha(ctx, data, len & ~(SHA256_BLOCKSZ - 1), 0); data += len & ~(SHA256_BLOCKSZ - 1); if (len & (SHA256_BLOCKSZ - 1)) { nr = len & (SHA256_BLOCKSZ - 1); memcpy(ctx->block + ctx->blocksz, data, nr); ctx->blocksz += nr; } } void asd_sha_finalize(struct asd_ctx *ctx) { asd_compute_sha(ctx, ctx->block, ctx->blocksz, 1); } trusted-firmware-a-2.2/drivers/arm/000077500000000000000000000000001355360272700173465ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/cci/000077500000000000000000000000001355360272700201045ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/cci/cci.c000066400000000000000000000103641355360272700210120ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #define MAKE_CCI_PART_NUMBER(hi, lo) (((hi) << 8) | (lo)) #define CCI_PART_LO_MASK U(0xff) #define CCI_PART_HI_MASK U(0xf) /* CCI part number codes read from Peripheral ID registers 0 and 1 */ #define CCI400_PART_NUM 0x420 #define CCI500_PART_NUM 0x422 #define CCI550_PART_NUM 0x423 #define CCI400_SLAVE_PORTS 5 #define CCI500_SLAVE_PORTS 7 #define CCI550_SLAVE_PORTS 7 static uintptr_t cci_base; static const int *cci_slave_if_map; #if ENABLE_ASSERTIONS static unsigned int max_master_id; static int cci_num_slave_ports; static bool validate_cci_map(const int *map) { unsigned int valid_cci_map = 0U; int slave_if_id; unsigned int i; /* Validate the map */ for (i = 0U; i <= max_master_id; i++) { slave_if_id = map[i]; if (slave_if_id < 0) continue; if (slave_if_id >= cci_num_slave_ports) { ERROR("Slave interface ID is invalid\n"); return false; } if ((valid_cci_map & (1U << slave_if_id)) != 0U) { ERROR("Multiple masters are assigned same slave interface ID\n"); return false; } valid_cci_map |= 1U << slave_if_id; } if (valid_cci_map == 0U) { ERROR("No master is assigned a valid slave interface\n"); return false; } return true; } /* * Read CCI part number from Peripheral ID registers */ static unsigned int read_cci_part_number(uintptr_t base) { unsigned int part_lo, part_hi; part_lo = mmio_read_32(base + PERIPHERAL_ID0) & CCI_PART_LO_MASK; part_hi = mmio_read_32(base + PERIPHERAL_ID1) & CCI_PART_HI_MASK; return MAKE_CCI_PART_NUMBER(part_hi, part_lo); } /* * Identify a CCI device, and return the number of slaves. Return -1 for an * unidentified device. */ static int get_slave_ports(unsigned int part_num) { int num_slave_ports = -1; switch (part_num) { case CCI400_PART_NUM: num_slave_ports = CCI400_SLAVE_PORTS; break; case CCI500_PART_NUM: num_slave_ports = CCI500_SLAVE_PORTS; break; case CCI550_PART_NUM: num_slave_ports = CCI550_SLAVE_PORTS; break; default: /* Do nothing in default case */ break; } return num_slave_ports; } #endif /* ENABLE_ASSERTIONS */ void __init cci_init(uintptr_t base, const int *map, unsigned int num_cci_masters) { assert(map != NULL); assert(base != 0U); cci_base = base; cci_slave_if_map = map; #if ENABLE_ASSERTIONS /* * Master Id's are assigned from zero, So in an array of size n * the max master id is (n - 1). */ max_master_id = num_cci_masters - 1U; cci_num_slave_ports = get_slave_ports(read_cci_part_number(base)); #endif assert(cci_num_slave_ports >= 0); assert(validate_cci_map(map)); } void cci_enable_snoop_dvm_reqs(unsigned int master_id) { int slave_if_id = cci_slave_if_map[master_id]; assert(master_id <= max_master_id); assert((slave_if_id < cci_num_slave_ports) && (slave_if_id >= 0)); assert(cci_base != 0U); /* * Enable Snoops and DVM messages, no need for Read/Modify/Write as * rest of bits are write ignore */ mmio_write_32(cci_base + SLAVE_IFACE_OFFSET(slave_if_id) + SNOOP_CTRL_REG, DVM_EN_BIT | SNOOP_EN_BIT); /* * Wait for the completion of the write to the Snoop Control Register * before testing the change_pending bit */ dsbish(); /* Wait for the dust to settle down */ while ((mmio_read_32(cci_base + STATUS_REG) & CHANGE_PENDING_BIT) != 0U) ; } void cci_disable_snoop_dvm_reqs(unsigned int master_id) { int slave_if_id = cci_slave_if_map[master_id]; assert(master_id <= max_master_id); assert((slave_if_id < cci_num_slave_ports) && (slave_if_id >= 0)); assert(cci_base != 0U); /* * Disable Snoops and DVM messages, no need for Read/Modify/Write as * rest of bits are write ignore. */ mmio_write_32(cci_base + SLAVE_IFACE_OFFSET(slave_if_id) + SNOOP_CTRL_REG, ~(DVM_EN_BIT | SNOOP_EN_BIT)); /* * Wait for the completion of the write to the Snoop Control Register * before testing the change_pending bit */ dsbish(); /* Wait for the dust to settle down */ while ((mmio_read_32(cci_base + STATUS_REG) & CHANGE_PENDING_BIT) != 0U) ; } trusted-firmware-a-2.2/drivers/arm/ccn/000077500000000000000000000000001355360272700201115ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/ccn/ccn.c000066400000000000000000000530071355360272700210250ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include "ccn_private.h" static const ccn_desc_t *ccn_plat_desc; #if defined(IMAGE_BL31) || (!defined(__aarch64__) && defined(IMAGE_BL32)) DEFINE_BAKERY_LOCK(ccn_lock); #endif /******************************************************************************* * This function takes the base address of the CCN's programmer's view (PV), a * region ID of one of the 256 regions (0-255) and a register offset within the * region. It converts the first two parameters into a base address and uses it * to read the register at the offset. ******************************************************************************/ static inline unsigned long long ccn_reg_read(uintptr_t periphbase, unsigned int region_id, unsigned int register_offset) { uintptr_t region_base; assert(periphbase); assert(region_id < REGION_ID_LIMIT); region_base = periphbase + region_id_to_base(region_id); return mmio_read_64(region_base + register_offset); } /******************************************************************************* * This function takes the base address of the CCN's programmer's view (PV), a * region ID of one of the 256 regions (0-255), a register offset within the * region and a value. It converts the first two parameters into a base address * and uses it to write the value in the register at the offset. ******************************************************************************/ static inline void ccn_reg_write(uintptr_t periphbase, unsigned int region_id, unsigned int register_offset, unsigned long long value) { uintptr_t region_base; assert(periphbase); assert(region_id < REGION_ID_LIMIT); region_base = periphbase + region_id_to_base(region_id); mmio_write_64(region_base + register_offset, value); } #if ENABLE_ASSERTIONS typedef struct rn_info { unsigned char node_desc[MAX_RN_NODES]; } rn_info_t; /******************************************************************************* * This function takes the base address of the CCN's programmer's view (PV) and * the node ID of a Request Node (RN-D or RN-I). It returns the maximum number * of master interfaces resident on that node. This number is equal to the least * significant two bits of the node type ID + 1. ******************************************************************************/ static unsigned int ccn_get_rni_mcount(uintptr_t periphbase, unsigned int rn_id) { unsigned int rn_type_id; /* Use the node id to find the type of RN-I/D node */ rn_type_id = get_node_type(ccn_reg_read(periphbase, rn_id + RNI_REGION_ID_START, REGION_ID_OFFSET)); /* Return the number master interfaces based on node type */ return rn_type_id_to_master_cnt(rn_type_id); } /******************************************************************************* * This function reads the CCN registers to find the following information about * the ACE/ACELite/ACELite+DVM/CHI interfaces resident on the various types of * Request Nodes (RN-Fs, RN-Is and RN-Ds) in the system: * * 1. The total number of such interfaces that this CCN IP supports. This is the * cumulative number of interfaces across all Request node types. It is * passed back as the return value of this function. * * 2. The maximum number of interfaces of a type resident on a Request node of * one of the three types. This information is populated in the 'info' * array provided by the caller as described next. * * The array has 64 entries. Each entry corresponds to a Request node. The * Miscellaneous node's programmer's view has RN-F, RN-I and RN-D ID * registers. For each RN-I and RN-D ID indicated as being present in these * registers, its identification register (offset 0xFF00) is read. This * register specifies the maximum number of master interfaces the node * supports. For RN-Fs it is assumed that there can be only a single fully * coherent master resident on each node. The counts for each type of node * are use to populate the array entry at the index corresponding to the node * ID i.e. rn_info[node ID] = ******************************************************************************/ static unsigned int ccn_get_rn_master_info(uintptr_t periphbase, rn_info_t *info) { unsigned int num_masters = 0; rn_types_t rn_type; assert (info); for (rn_type = RN_TYPE_RNF; rn_type < NUM_RN_TYPES; rn_type++) { unsigned int mn_reg_off, node_id; unsigned long long rn_bitmap; /* * RN-F, RN-I, RN-D node registers in the MN region occupy * contiguous 16 byte apart offsets. */ mn_reg_off = MN_RNF_NODEID_OFFSET + (rn_type << 4); rn_bitmap = ccn_reg_read(periphbase, MN_REGION_ID, mn_reg_off); FOR_EACH_PRESENT_NODE_ID(node_id, rn_bitmap) { unsigned int node_mcount; /* * A RN-F does not have a node type since it does not * export a programmer's interface. It can only have a * single fully coherent master residing on it. If the * offset of the MN(Miscellaneous Node) register points * to a RN-I/D node then the master count is set to the * maximum number of master interfaces that can possibly * reside on the node. */ node_mcount = (mn_reg_off == MN_RNF_NODEID_OFFSET ? 1 : ccn_get_rni_mcount(periphbase, node_id)); /* * Use this value to increment the maximum possible * master interfaces in the system. */ num_masters += node_mcount; /* * Update the entry in 'info' for this node ID with * the maximum number of masters than can sit on * it. This information will be used to validate the * node information passed by the platform later. */ info->node_desc[node_id] = node_mcount; } } return num_masters; } /******************************************************************************* * This function validates parameters passed by the platform (in a debug build). * It collects information about the maximum number of master interfaces that: * a) the CCN IP can accommodate and * b) can exist on each Request node. * It compares this with the information provided by the platform to determine * the validity of the latter. ******************************************************************************/ static void __init ccn_validate_plat_params(const ccn_desc_t *plat_desc) { unsigned int master_id, num_rn_masters; rn_info_t info = { {0} }; assert(plat_desc); assert(plat_desc->periphbase); assert(plat_desc->master_to_rn_id_map); assert(plat_desc->num_masters); assert(plat_desc->num_masters < CCN_MAX_RN_MASTERS); /* * Find the number and properties of fully coherent, IO coherent and IO * coherent + DVM master interfaces */ num_rn_masters = ccn_get_rn_master_info(plat_desc->periphbase, &info); assert(plat_desc->num_masters < num_rn_masters); /* * Iterate through the Request nodes specified by the platform. * Decrement the count of the masters in the 'info' array for each * Request node encountered. If the count would drop below 0 then the * platform's view of this aspect of CCN configuration is incorrect. */ for (master_id = 0; master_id < plat_desc->num_masters; master_id++) { unsigned int node_id; node_id = plat_desc->master_to_rn_id_map[master_id]; assert(node_id < MAX_RN_NODES); assert(info.node_desc[node_id]); info.node_desc[node_id]--; } } #endif /* ENABLE_ASSERTIONS */ /******************************************************************************* * This function validates parameters passed by the platform (in a debug build) * and initialises its internal data structures. A lock is required to prevent * simultaneous CCN operations at runtime (only BL31) to add and remove Request * nodes from coherency. ******************************************************************************/ void __init ccn_init(const ccn_desc_t *plat_desc) { #if ENABLE_ASSERTIONS ccn_validate_plat_params(plat_desc); #endif ccn_plat_desc = plat_desc; } /******************************************************************************* * This function converts a bit map of master interface IDs to a bit map of the * Request node IDs that they reside on. ******************************************************************************/ static unsigned long long ccn_master_to_rn_id_map(unsigned long long master_map) { unsigned long long rn_id_map = 0; unsigned int node_id, iface_id; assert(master_map); assert(ccn_plat_desc); FOR_EACH_PRESENT_MASTER_INTERFACE(iface_id, master_map) { assert(iface_id < ccn_plat_desc->num_masters); /* Convert the master ID into the node ID */ node_id = ccn_plat_desc->master_to_rn_id_map[iface_id]; /* Set the bit corresponding to this node ID */ rn_id_map |= (1ULL << node_id); } return rn_id_map; } /******************************************************************************* * This function executes the necessary operations to add or remove Request node * IDs specified in the 'rn_id_map' bitmap from the snoop/DVM domains specified * in the 'hn_id_map'. The 'region_id' specifies the ID of the first HN-F/MN * on which the operation should be performed. 'op_reg_offset' specifies the * type of operation (add/remove). 'stat_reg_offset' specifies the register * which should be polled to determine if the operation has completed or not. ******************************************************************************/ static void ccn_snoop_dvm_do_op(unsigned long long rn_id_map, unsigned long long hn_id_map, unsigned int region_id, unsigned int op_reg_offset, unsigned int stat_reg_offset) { unsigned int start_region_id; assert(ccn_plat_desc); assert(ccn_plat_desc->periphbase); #if defined(IMAGE_BL31) || (!defined(__aarch64__) && defined(IMAGE_BL32)) bakery_lock_get(&ccn_lock); #endif start_region_id = region_id; FOR_EACH_PRESENT_REGION_ID(start_region_id, hn_id_map) { ccn_reg_write(ccn_plat_desc->periphbase, start_region_id, op_reg_offset, rn_id_map); } start_region_id = region_id; FOR_EACH_PRESENT_REGION_ID(start_region_id, hn_id_map) { WAIT_FOR_DOMAIN_CTRL_OP_COMPLETION(start_region_id, stat_reg_offset, op_reg_offset, rn_id_map); } #if defined(IMAGE_BL31) || (!defined(__aarch64__) && defined(IMAGE_BL32)) bakery_lock_release(&ccn_lock); #endif } /******************************************************************************* * The following functions provide the boot and runtime API to the platform for * adding and removing master interfaces from the snoop/DVM domains. A bitmap of * master interfaces IDs is passed as a parameter. It is converted into a bitmap * of Request node IDs using the mapping provided by the platform while * initialising the driver. * For example, consider a dual cluster system where the clusters have values 0 * & 1 in the affinity level 1 field of their respective MPIDRs. While * initialising this driver, the platform provides the mapping between each * cluster and the corresponding Request node. To add or remove a cluster from * the snoop and dvm domain, the bit position corresponding to the cluster ID * should be set in the 'master_iface_map' i.e. to remove both clusters the * bitmap would equal 0x11. ******************************************************************************/ void ccn_enter_snoop_dvm_domain(unsigned long long master_iface_map) { unsigned long long rn_id_map; rn_id_map = ccn_master_to_rn_id_map(master_iface_map); ccn_snoop_dvm_do_op(rn_id_map, CCN_GET_HN_NODEID_MAP(ccn_plat_desc->periphbase, MN_HNF_NODEID_OFFSET), HNF_REGION_ID_START, HNF_SDC_SET_OFFSET, HNF_SDC_STAT_OFFSET); ccn_snoop_dvm_do_op(rn_id_map, CCN_GET_MN_NODEID_MAP(ccn_plat_desc->periphbase), MN_REGION_ID, MN_DDC_SET_OFFSET, MN_DDC_STAT_OFFSET); } void ccn_exit_snoop_dvm_domain(unsigned long long master_iface_map) { unsigned long long rn_id_map; rn_id_map = ccn_master_to_rn_id_map(master_iface_map); ccn_snoop_dvm_do_op(rn_id_map, CCN_GET_HN_NODEID_MAP(ccn_plat_desc->periphbase, MN_HNF_NODEID_OFFSET), HNF_REGION_ID_START, HNF_SDC_CLR_OFFSET, HNF_SDC_STAT_OFFSET); ccn_snoop_dvm_do_op(rn_id_map, CCN_GET_MN_NODEID_MAP(ccn_plat_desc->periphbase), MN_REGION_ID, MN_DDC_CLR_OFFSET, MN_DDC_STAT_OFFSET); } void ccn_enter_dvm_domain(unsigned long long master_iface_map) { unsigned long long rn_id_map; rn_id_map = ccn_master_to_rn_id_map(master_iface_map); ccn_snoop_dvm_do_op(rn_id_map, CCN_GET_MN_NODEID_MAP(ccn_plat_desc->periphbase), MN_REGION_ID, MN_DDC_SET_OFFSET, MN_DDC_STAT_OFFSET); } void ccn_exit_dvm_domain(unsigned long long master_iface_map) { unsigned long long rn_id_map; rn_id_map = ccn_master_to_rn_id_map(master_iface_map); ccn_snoop_dvm_do_op(rn_id_map, CCN_GET_MN_NODEID_MAP(ccn_plat_desc->periphbase), MN_REGION_ID, MN_DDC_CLR_OFFSET, MN_DDC_STAT_OFFSET); } /******************************************************************************* * This function returns the run mode of all the L3 cache partitions in the * system. The state is expected to be one of NO_L3, SF_ONLY, L3_HAM or * L3_FAM. Instead of comparing the states reported by all HN-Fs, the state of * the first present HN-F node is reported. Since the driver does not export an * interface to program them separately, there is no reason to perform this * check. An HN-F could report that the L3 cache is transitioning from one mode * to another e.g. HNF_PM_NOL3_2_SFONLY. In this case, the function waits for * the transition to complete and reports the final state. ******************************************************************************/ unsigned int ccn_get_l3_run_mode(void) { unsigned long long hnf_pstate_stat; assert(ccn_plat_desc); assert(ccn_plat_desc->periphbase); /* * Wait for a L3 cache partition to enter any run mode. The pstate * parameter is read from an HN-F P-state status register. A non-zero * value in bits[1:0] means that the cache is transitioning to a run * mode. */ do { hnf_pstate_stat = ccn_reg_read(ccn_plat_desc->periphbase, HNF_REGION_ID_START, HNF_PSTATE_STAT_OFFSET); } while (hnf_pstate_stat & 0x3); return PSTATE_TO_RUN_MODE(hnf_pstate_stat); } /******************************************************************************* * This function sets the run mode of all the L3 cache partitions in the * system to one of NO_L3, SF_ONLY, L3_HAM or L3_FAM depending upon the state * specified by the 'mode' argument. ******************************************************************************/ void ccn_set_l3_run_mode(unsigned int mode) { unsigned long long mn_hnf_id_map, hnf_pstate_stat; unsigned int region_id; assert(ccn_plat_desc); assert(ccn_plat_desc->periphbase); assert(mode <= CCN_L3_RUN_MODE_FAM); mn_hnf_id_map = ccn_reg_read(ccn_plat_desc->periphbase, MN_REGION_ID, MN_HNF_NODEID_OFFSET); region_id = HNF_REGION_ID_START; /* Program the desired run mode */ FOR_EACH_PRESENT_REGION_ID(region_id, mn_hnf_id_map) { ccn_reg_write(ccn_plat_desc->periphbase, region_id, HNF_PSTATE_REQ_OFFSET, mode); } /* Wait for the caches to transition to the run mode */ region_id = HNF_REGION_ID_START; FOR_EACH_PRESENT_REGION_ID(region_id, mn_hnf_id_map) { /* * Wait for a L3 cache partition to enter a target run * mode. The pstate parameter is read from an HN-F P-state * status register. */ do { hnf_pstate_stat = ccn_reg_read(ccn_plat_desc->periphbase, region_id, HNF_PSTATE_STAT_OFFSET); } while (((hnf_pstate_stat & HNF_PSTATE_MASK) >> 2) != mode); } } /******************************************************************************* * This function configures system address map and provides option to enable the * 3SN striping mode of Slave node operation. The Slave node IDs and the Top * Address bit1 and bit0 are provided as parameters to this function. This * configuration is needed only if network contains a single SN-F or 3 SN-F and * must be completed before the first request by the system to normal memory. ******************************************************************************/ void ccn_program_sys_addrmap(unsigned int sn0_id, unsigned int sn1_id, unsigned int sn2_id, unsigned int top_addr_bit0, unsigned int top_addr_bit1, unsigned char three_sn_en) { unsigned long long mn_hnf_id_map, hnf_sam_ctrl_value; unsigned int region_id; assert(ccn_plat_desc); assert(ccn_plat_desc->periphbase); mn_hnf_id_map = ccn_reg_read(ccn_plat_desc->periphbase, MN_REGION_ID, MN_HNF_NODEID_OFFSET); region_id = HNF_REGION_ID_START; hnf_sam_ctrl_value = MAKE_HNF_SAM_CTRL_VALUE(sn0_id, sn1_id, sn2_id, top_addr_bit0, top_addr_bit1, three_sn_en); FOR_EACH_PRESENT_REGION_ID(region_id, mn_hnf_id_map) { /* Program the SAM control register */ ccn_reg_write(ccn_plat_desc->periphbase, region_id, HNF_SAM_CTRL_OFFSET, hnf_sam_ctrl_value); } } /******************************************************************************* * This function returns the part0 id from the peripheralID 0 register * in CCN. This id can be used to distinguish the CCN variant present in the * system. ******************************************************************************/ int ccn_get_part0_id(uintptr_t periphbase) { assert(periphbase); return (int)(mmio_read_64(periphbase + MN_PERIPH_ID_0_1_OFFSET) & 0xFF); } /******************************************************************************* * This function returns the region id corresponding to a node_id of node_type. ******************************************************************************/ static unsigned int get_region_id_for_node(node_types_t node_type, unsigned int node_id) { unsigned int mn_reg_off, region_id; unsigned long long node_bitmap; unsigned int loc_node_id, node_pos_in_map = 0; assert(node_type < NUM_NODE_TYPES); assert(node_id < MAX_RN_NODES); switch (node_type) { case NODE_TYPE_RNI: region_id = RNI_REGION_ID_START; break; case NODE_TYPE_HNF: region_id = HNF_REGION_ID_START; break; case NODE_TYPE_HNI: region_id = HNI_REGION_ID_START; break; case NODE_TYPE_SN: region_id = SBSX_REGION_ID_START; break; default: ERROR("Un-supported Node Type = %d.\n", node_type); assert(false); return REGION_ID_LIMIT; } /* * RN-I, HN-F, HN-I, SN node registers in the MN region * occupy contiguous 16 byte apart offsets. * * RN-F and RN-D node are not supported as * none of them exposes any memory map to * configure any of their offset registers. */ mn_reg_off = MN_RNF_NODEID_OFFSET + (node_type << 4); node_bitmap = ccn_reg_read(ccn_plat_desc->periphbase, MN_REGION_ID, mn_reg_off); assert((node_bitmap & (1ULL << (node_id))) != 0U); FOR_EACH_PRESENT_NODE_ID(loc_node_id, node_bitmap) { INFO("Index = %u with loc_nod=%u and input nod=%u\n", node_pos_in_map, loc_node_id, node_id); if (loc_node_id == node_id) break; node_pos_in_map++; } if (node_pos_in_map == CCN_MAX_RN_MASTERS) { ERROR("Node Id = %d, is not found.\n", node_id); assert(false); return REGION_ID_LIMIT; } /* * According to section 3.1.1 in CCN specification, region offset for * the RN-I components is calculated as (128 + NodeID of RN-I). */ if (node_type == NODE_TYPE_RNI) region_id += node_id; else region_id += node_pos_in_map; return region_id; } /******************************************************************************* * This function sets the value 'val' to the register at register_offset from * the base address pointed to by the region_id. * where, region id is mapped to a node_id of node_type. ******************************************************************************/ void ccn_write_node_reg(node_types_t node_type, unsigned int node_id, unsigned int reg_offset, unsigned long long val) { unsigned int region_id = get_region_id_for_node(node_type, node_id); if (reg_offset > REGION_ID_OFFSET) { ERROR("Invalid Register offset 0x%x is provided.\n", reg_offset); assert(false); return; } /* Setting the value of Auxiliary Control Register of the Node */ ccn_reg_write(ccn_plat_desc->periphbase, region_id, reg_offset, val); VERBOSE("Value is successfully written at address 0x%lx.\n", (ccn_plat_desc->periphbase + region_id_to_base(region_id)) + reg_offset); } /******************************************************************************* * This function read the value 'val' stored in the register at register_offset * from the base address pointed to by the region_id. * where, region id is mapped to a node_id of node_type. ******************************************************************************/ unsigned long long ccn_read_node_reg(node_types_t node_type, unsigned int node_id, unsigned int reg_offset) { unsigned long long val; unsigned int region_id = get_region_id_for_node(node_type, node_id); if (reg_offset > REGION_ID_OFFSET) { ERROR("Invalid Register offset 0x%x is provided.\n", reg_offset); assert(false); return ULL(0); } /* Setting the value of Auxiliary Control Register of the Node */ val = ccn_reg_read(ccn_plat_desc->periphbase, region_id, reg_offset); VERBOSE("Value is successfully read from address 0x%lx.\n", (ccn_plat_desc->periphbase + region_id_to_base(region_id)) + reg_offset); return val; } trusted-firmware-a-2.2/drivers/arm/ccn/ccn_private.h000066400000000000000000000200451355360272700225600ustar00rootroot00000000000000/* * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CCN_PRIVATE_H #define CCN_PRIVATE_H /* * A CCN implementation can have a maximum of 64 Request nodes with node IDs * from 0-63. These IDs are split across the three types of Request nodes * i.e. RN-F, RN-D and RN-I. */ #define MAX_RN_NODES 64 /* Enum used to loop through the 3 types of Request nodes */ typedef enum rn_types { RN_TYPE_RNF = 0, RN_TYPE_RNI, RN_TYPE_RND, NUM_RN_TYPES } rn_types_t; /* Macro to convert a region id to its base address */ #define region_id_to_base(id) ((id) << 16) /* * Macro to calculate the number of master interfaces resident on a RN-I/RN-D. * Value of first two bits of the RN-I/D node type + 1 == Maximum number of * ACE-Lite or ACE-Lite+DVM interfaces supported on this node. E.g. * * 0x14 : RN-I with 1 ACE-Lite interface * 0x15 : RN-I with 2 ACE-Lite interfaces * 0x16 : RN-I with 3 ACE-Lite interfaces */ #define rn_type_id_to_master_cnt(id) (((id) & 0x3) + 1) /* * Constants used to identify a region in the programmer's view. These are * common for all regions. */ #define REGION_ID_LIMIT 256 #define REGION_ID_OFFSET 0xFF00 #define REGION_NODE_ID_SHIFT 8 #define REGION_NODE_ID_MASK 0x7f #define get_node_id(id_reg) (((id_reg) >> REGION_NODE_ID_SHIFT) \ & REGION_NODE_ID_MASK) #define REGION_NODE_TYPE_SHIFT 0 #define REGION_NODE_TYPE_MASK 0x1f #define get_node_type(id_reg) (((id_reg) >> REGION_NODE_TYPE_SHIFT) \ & REGION_NODE_TYPE_MASK) /* Common offsets of registers to enter or exit a snoop/dvm domain */ #define DOMAIN_CTRL_STAT_OFFSET 0x0200 #define DOMAIN_CTRL_SET_OFFSET 0x0210 #define DOMAIN_CTRL_CLR_OFFSET 0x0220 /* * Thess macros are used to determine if an operation to add or remove a Request * node from the snoop/dvm domain has completed. 'rn_id_map' is a bit map of * nodes. It was used to program the SET or CLEAR control register. The type of * register is specified by 'op_reg_offset'. 'status_reg' is the bit map of * nodes currently present in the snoop/dvm domain. 'rn_id_map' and 'status_reg' * are logically ANDed and the result it stored back in the 'status_reg'. There * are two outcomes of this operation: * * 1. If the DOMAIN_CTRL_SET_OFFSET register was programmed, then the set bits in * 'rn_id_map' should appear in 'status_reg' when the operation completes. So * after the AND operation, at some point of time 'status_reg' should equal * 'rn_id_map'. * * 2. If the DOMAIN_CTRL_CLR_OFFSET register was programmed, then the set bits in * 'rn_id_map' should disappear in 'status_reg' when the operation * completes. So after the AND operation, at some point of time 'status_reg' * should equal 0. */ #define WAIT_FOR_DOMAIN_CTRL_OP_COMPLETION(region_id, stat_reg_offset, \ op_reg_offset, rn_id_map) \ { \ unsigned long long status_reg; \ do { \ status_reg = ccn_reg_read((ccn_plat_desc->periphbase), \ (region_id), \ (stat_reg_offset)); \ status_reg &= (rn_id_map); \ } while ((op_reg_offset) == DOMAIN_CTRL_SET_OFFSET ? \ (rn_id_map) != status_reg : status_reg); \ } /* * Region ID of the Miscellaneous Node is always 0 as its located at the base of * the programmer's view. */ #define MN_REGION_ID 0 #define MN_REGION_ID_START 0 #define DEBUG_REGION_ID_START 1 #define HNI_REGION_ID_START 8 #define SBSX_REGION_ID_START 16 #define HNF_REGION_ID_START 32 #define XP_REGION_ID_START 64 #define RNI_REGION_ID_START 128 /* Selected register offsets from the base of a HNF region */ #define HNF_CFG_CTRL_OFFSET 0x0000 #define HNF_SAM_CTRL_OFFSET 0x0008 #define HNF_PSTATE_REQ_OFFSET 0x0010 #define HNF_PSTATE_STAT_OFFSET 0x0018 #define HNF_SDC_STAT_OFFSET DOMAIN_CTRL_STAT_OFFSET #define HNF_SDC_SET_OFFSET DOMAIN_CTRL_SET_OFFSET #define HNF_SDC_CLR_OFFSET DOMAIN_CTRL_CLR_OFFSET #define HNF_AUX_CTRL_OFFSET 0x0500 /* Selected register offsets from the base of a MN region */ #define MN_SAR_OFFSET 0x0000 #define MN_RNF_NODEID_OFFSET 0x0180 #define MN_RNI_NODEID_OFFSET 0x0190 #define MN_RND_NODEID_OFFSET 0x01A0 #define MN_HNF_NODEID_OFFSET 0x01B0 #define MN_HNI_NODEID_OFFSET 0x01C0 #define MN_SN_NODEID_OFFSET 0x01D0 #define MN_DDC_STAT_OFFSET DOMAIN_CTRL_STAT_OFFSET #define MN_DDC_SET_OFFSET DOMAIN_CTRL_SET_OFFSET #define MN_DDC_CLR_OFFSET DOMAIN_CTRL_CLR_OFFSET #define MN_PERIPH_ID_0_1_OFFSET 0xFE0 #define MN_ID_OFFSET REGION_ID_OFFSET /* HNF System Address Map register bit masks and shifts */ #define HNF_SAM_CTRL_SN_ID_MASK 0x7f #define HNF_SAM_CTRL_SN0_ID_SHIFT 0 #define HNF_SAM_CTRL_SN1_ID_SHIFT 8 #define HNF_SAM_CTRL_SN2_ID_SHIFT 16 #define HNF_SAM_CTRL_TAB0_MASK ULL(0x3f) #define HNF_SAM_CTRL_TAB0_SHIFT 48 #define HNF_SAM_CTRL_TAB1_MASK ULL(0x3f) #define HNF_SAM_CTRL_TAB1_SHIFT 56 #define HNF_SAM_CTRL_3SN_ENB_SHIFT 32 #define HNF_SAM_CTRL_3SN_ENB_MASK ULL(0x01) /* * Macro to create a value suitable for programming into a HNF SAM Control * register for enabling 3SN striping. */ #define MAKE_HNF_SAM_CTRL_VALUE(sn0, sn1, sn2, tab0, tab1, three_sn_en) \ ((((sn0) & HNF_SAM_CTRL_SN_ID_MASK) << HNF_SAM_CTRL_SN0_ID_SHIFT) | \ (((sn1) & HNF_SAM_CTRL_SN_ID_MASK) << HNF_SAM_CTRL_SN1_ID_SHIFT) | \ (((sn2) & HNF_SAM_CTRL_SN_ID_MASK) << HNF_SAM_CTRL_SN2_ID_SHIFT) | \ (((tab0) & HNF_SAM_CTRL_TAB0_MASK) << HNF_SAM_CTRL_TAB0_SHIFT) | \ (((tab1) & HNF_SAM_CTRL_TAB1_MASK) << HNF_SAM_CTRL_TAB1_SHIFT) | \ (((three_sn_en) & HNF_SAM_CTRL_3SN_ENB_MASK) << HNF_SAM_CTRL_3SN_ENB_SHIFT)) /* Mask to read the power state value from an HN-F P-state register */ #define HNF_PSTATE_MASK 0xf /* Macro to extract the run mode from a p-state value */ #define PSTATE_TO_RUN_MODE(pstate) (((pstate) & HNF_PSTATE_MASK) >> 2) /* * Helper macro that iterates through a given bit map. In each iteration, * it returns the position of the set bit. * It can be used by other utility macros to iterates through all nodes * or masters given a bit map of them. */ #define FOR_EACH_BIT(bit_pos, bit_map) \ for (bit_pos = __builtin_ctzll(bit_map); \ bit_map; \ bit_map &= ~(1ULL << (bit_pos)), \ bit_pos = __builtin_ctzll(bit_map)) /* * Utility macro that iterates through a bit map of node IDs. In each * iteration, it returns the ID of the next present node in the bit map. Node * ID of a present node == Position of set bit == Number of zeroes trailing the * bit. */ #define FOR_EACH_PRESENT_NODE_ID(node_id, bit_map) \ FOR_EACH_BIT(node_id, bit_map) /* * Helper function to return number of set bits in bitmap */ static inline unsigned int count_set_bits(unsigned long long bitmap) { unsigned int count = 0; for (; bitmap; bitmap &= bitmap - 1) ++count; return count; } /* * Utility macro that iterates through a bit map of node IDs. In each iteration, * it returns the ID of the next present region corresponding to a node present * in the bit map. Region ID of a present node is in between passed region id * and region id + number of set bits in the bitmap i.e. the number of present * nodes. */ #define FOR_EACH_PRESENT_REGION_ID(region_id, bit_map) \ for (unsigned long long region_id_limit = count_set_bits(bit_map) \ + region_id; \ region_id < region_id_limit; \ region_id++) /* * Same macro as FOR_EACH_PRESENT_NODE, but renamed to indicate it traverses * through a bit map of master interfaces. */ #define FOR_EACH_PRESENT_MASTER_INTERFACE(iface_id, bit_map) \ FOR_EACH_BIT(iface_id, bit_map) /* * Macro that returns the node id bit map for the Miscellaneous Node */ #define CCN_GET_MN_NODEID_MAP(periphbase) \ (1 << get_node_id(ccn_reg_read(periphbase, MN_REGION_ID, \ REGION_ID_OFFSET))) /* * This macro returns the bitmap of Home nodes on the basis of the * 'mn_hn_id_reg_offset' parameter from the Miscellaneous node's (MN) * programmer's view. The MN has a register which carries the bitmap of present * Home nodes of each type i.e. HN-Fs, HN-Is & HN-Ds. */ #define CCN_GET_HN_NODEID_MAP(periphbase, mn_hn_id_reg_offset) \ ccn_reg_read(periphbase, MN_REGION_ID, mn_hn_id_reg_offset) #endif /* CCN_PRIVATE_H */ trusted-firmware-a-2.2/drivers/arm/css/000077500000000000000000000000001355360272700201365ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/css/mhu/000077500000000000000000000000001355360272700207275ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/css/mhu/css_mhu.c000066400000000000000000000044011355360272700225330ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* SCP MHU secure channel registers */ #define SCP_INTR_S_STAT 0x200 #define SCP_INTR_S_SET 0x208 #define SCP_INTR_S_CLEAR 0x210 /* CPU MHU secure channel registers */ #define CPU_INTR_S_STAT 0x300 #define CPU_INTR_S_SET 0x308 #define CPU_INTR_S_CLEAR 0x310 ARM_INSTANTIATE_LOCK; /* Weak definition may be overridden in specific CSS based platform */ #pragma weak plat_arm_pwrc_setup /* * Slot 31 is reserved because the MHU hardware uses this register bit to * indicate a non-secure access attempt. The total number of available slots is * therefore 31 [30:0]. */ #define MHU_MAX_SLOT_ID 30 void mhu_secure_message_start(unsigned int slot_id) { assert(slot_id <= MHU_MAX_SLOT_ID); arm_lock_get(); /* Make sure any previous command has finished */ while (mmio_read_32(PLAT_CSS_MHU_BASE + CPU_INTR_S_STAT) & (1 << slot_id)) ; } void mhu_secure_message_send(unsigned int slot_id) { assert(slot_id <= MHU_MAX_SLOT_ID); assert(!(mmio_read_32(PLAT_CSS_MHU_BASE + CPU_INTR_S_STAT) & (1 << slot_id))); /* Send command to SCP */ mmio_write_32(PLAT_CSS_MHU_BASE + CPU_INTR_S_SET, 1 << slot_id); } uint32_t mhu_secure_message_wait(void) { /* Wait for response from SCP */ uint32_t response; while (!(response = mmio_read_32(PLAT_CSS_MHU_BASE + SCP_INTR_S_STAT))) ; return response; } void mhu_secure_message_end(unsigned int slot_id) { assert(slot_id <= MHU_MAX_SLOT_ID); /* * Clear any response we got by writing one in the relevant slot bit to * the CLEAR register */ mmio_write_32(PLAT_CSS_MHU_BASE + SCP_INTR_S_CLEAR, 1 << slot_id); arm_lock_release(); } void __init mhu_secure_init(void) { arm_lock_init(); /* * The STAT register resets to zero. Ensure it is in the expected state, * as a stale or garbage value would make us think it's a message we've * already sent. */ assert(mmio_read_32(PLAT_CSS_MHU_BASE + CPU_INTR_S_STAT) == 0); } void __init plat_arm_pwrc_setup(void) { mhu_secure_init(); } trusted-firmware-a-2.2/drivers/arm/css/mhu/css_mhu_doorbell.c000066400000000000000000000016031355360272700244160ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include void mhu_ring_doorbell(struct scmi_channel_plat_info *plat_info) { MHU_RING_DOORBELL(plat_info->db_reg_addr, plat_info->db_modify_mask, plat_info->db_preserve_mask); return; } void mhuv2_ring_doorbell(struct scmi_channel_plat_info *plat_info) { /* wake receiver */ MHU_V2_ACCESS_REQUEST(MHUV2_BASE_ADDR); /* wait for receiver to acknowledge its ready */ while (MHU_V2_IS_ACCESS_READY(MHUV2_BASE_ADDR) == 0) ; MHU_RING_DOORBELL(plat_info->db_reg_addr, plat_info->db_modify_mask, plat_info->db_preserve_mask); /* clear the access request for the receiver */ MHU_V2_CLEAR_REQUEST(MHUV2_BASE_ADDR); return; } trusted-firmware-a-2.2/drivers/arm/css/scmi/000077500000000000000000000000001355360272700210715ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/css/scmi/scmi_ap_core_proto.c000066400000000000000000000040751355360272700251110ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "scmi_private.h" /* * API to set the SCMI AP core reset address and attributes */ int scmi_ap_core_set_reset_addr(void *p, uint64_t reset_addr, uint32_t attr) { mailbox_mem_t *mbx_mem; unsigned int token = 0; int ret; scmi_channel_t *ch = (scmi_channel_t *)p; validate_scmi_channel(ch); scmi_get_channel(ch); mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_AP_CORE_PROTO_ID, SCMI_AP_CORE_RESET_ADDR_SET_MSG, token); mbx_mem->len = SCMI_AP_CORE_RESET_ADDR_SET_MSG_LEN; mbx_mem->flags = SCMI_FLAG_RESP_POLL; SCMI_PAYLOAD_ARG3(mbx_mem->payload, reset_addr & 0xffffffff, reset_addr >> 32, attr); scmi_send_sync_command(ch); /* Get the return values */ SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret); assert(mbx_mem->len == SCMI_AP_CORE_RESET_ADDR_SET_RESP_LEN); assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header)); scmi_put_channel(ch); return ret; } /* * API to get the SCMI AP core reset address and attributes */ int scmi_ap_core_get_reset_addr(void *p, uint64_t *reset_addr, uint32_t *attr) { mailbox_mem_t *mbx_mem; unsigned int token = 0; int ret; scmi_channel_t *ch = (scmi_channel_t *)p; uint32_t lo_addr, hi_addr; validate_scmi_channel(ch); scmi_get_channel(ch); mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_AP_CORE_PROTO_ID, SCMI_AP_CORE_RESET_ADDR_GET_MSG, token); mbx_mem->len = SCMI_AP_CORE_RESET_ADDR_GET_MSG_LEN; mbx_mem->flags = SCMI_FLAG_RESP_POLL; scmi_send_sync_command(ch); /* Get the return values */ SCMI_PAYLOAD_RET_VAL4(mbx_mem->payload, ret, lo_addr, hi_addr, *attr); *reset_addr = lo_addr | (uint64_t)hi_addr << 32; assert(mbx_mem->len == SCMI_AP_CORE_RESET_ADDR_GET_RESP_LEN); assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header)); scmi_put_channel(ch); return ret; } trusted-firmware-a-2.2/drivers/arm/css/scmi/scmi_common.c000066400000000000000000000122531355360272700235430ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "scmi_private.h" #if HW_ASSISTED_COHERENCY #define scmi_lock_init(lock) #define scmi_lock_get(lock) spin_lock(lock) #define scmi_lock_release(lock) spin_unlock(lock) #else #define scmi_lock_init(lock) bakery_lock_init(lock) #define scmi_lock_get(lock) bakery_lock_get(lock) #define scmi_lock_release(lock) bakery_lock_release(lock) #endif /* * Private helper function to get exclusive access to SCMI channel. */ void scmi_get_channel(scmi_channel_t *ch) { assert(ch->lock); scmi_lock_get(ch->lock); /* Make sure any previous command has finished */ assert(SCMI_IS_CHANNEL_FREE( ((mailbox_mem_t *)(ch->info->scmi_mbx_mem))->status)); } /* * Private helper function to transfer ownership of channel from AP to SCP. */ void scmi_send_sync_command(scmi_channel_t *ch) { mailbox_mem_t *mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); SCMI_MARK_CHANNEL_BUSY(mbx_mem->status); /* * Ensure that any write to the SCMI payload area is seen by SCP before * we write to the doorbell register. If these 2 writes were reordered * by the CPU then SCP would read stale payload data */ dmbst(); ch->info->ring_doorbell(ch->info); /* * Ensure that the write to the doorbell register is ordered prior to * checking whether the channel is free. */ dmbsy(); /* Wait for channel to be free */ while (!SCMI_IS_CHANNEL_FREE(mbx_mem->status)) ; /* * Ensure that any read to the SCMI payload area is done after reading * mailbox status. If these 2 reads were reordered then the CPU would * read invalid payload data */ dmbld(); } /* * Private helper function to release exclusive access to SCMI channel. */ void scmi_put_channel(scmi_channel_t *ch) { /* Make sure any previous command has finished */ assert(SCMI_IS_CHANNEL_FREE( ((mailbox_mem_t *)(ch->info->scmi_mbx_mem))->status)); assert(ch->lock); scmi_lock_release(ch->lock); } /* * API to query the SCMI protocol version. */ int scmi_proto_version(void *p, uint32_t proto_id, uint32_t *version) { mailbox_mem_t *mbx_mem; unsigned int token = 0; int ret; scmi_channel_t *ch = (scmi_channel_t *)p; validate_scmi_channel(ch); scmi_get_channel(ch); mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); mbx_mem->msg_header = SCMI_MSG_CREATE(proto_id, SCMI_PROTO_VERSION_MSG, token); mbx_mem->len = SCMI_PROTO_VERSION_MSG_LEN; mbx_mem->flags = SCMI_FLAG_RESP_POLL; scmi_send_sync_command(ch); /* Get the return values */ SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *version); assert(mbx_mem->len == SCMI_PROTO_VERSION_RESP_LEN); assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header)); scmi_put_channel(ch); return ret; } /* * API to query the protocol message attributes for a SCMI protocol. */ int scmi_proto_msg_attr(void *p, uint32_t proto_id, uint32_t command_id, uint32_t *attr) { mailbox_mem_t *mbx_mem; unsigned int token = 0; int ret; scmi_channel_t *ch = (scmi_channel_t *)p; validate_scmi_channel(ch); scmi_get_channel(ch); mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); mbx_mem->msg_header = SCMI_MSG_CREATE(proto_id, SCMI_PROTO_MSG_ATTR_MSG, token); mbx_mem->len = SCMI_PROTO_MSG_ATTR_MSG_LEN; mbx_mem->flags = SCMI_FLAG_RESP_POLL; SCMI_PAYLOAD_ARG1(mbx_mem->payload, command_id); scmi_send_sync_command(ch); /* Get the return values */ SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *attr); assert(mbx_mem->len == SCMI_PROTO_MSG_ATTR_RESP_LEN); assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header)); scmi_put_channel(ch); return ret; } /* * SCMI Driver initialization API. Returns initialized channel on success * or NULL on error. The return type is an opaque void pointer. */ void *scmi_init(scmi_channel_t *ch) { uint32_t version; int ret; assert(ch && ch->info); assert(ch->info->db_reg_addr); assert(ch->info->db_modify_mask); assert(ch->info->db_preserve_mask); assert(ch->info->ring_doorbell != NULL); assert(ch->lock); scmi_lock_init(ch->lock); ch->is_initialized = 1; ret = scmi_proto_version(ch, SCMI_PWR_DMN_PROTO_ID, &version); if (ret != SCMI_E_SUCCESS) { WARN("SCMI power domain protocol version message failed"); goto error; } if (!is_scmi_version_compatible(SCMI_PWR_DMN_PROTO_VER, version)) { WARN("SCMI power domain protocol version 0x%x incompatible with driver version 0x%x", version, SCMI_PWR_DMN_PROTO_VER); goto error; } VERBOSE("SCMI power domain protocol version 0x%x detected\n", version); ret = scmi_proto_version(ch, SCMI_SYS_PWR_PROTO_ID, &version); if ((ret != SCMI_E_SUCCESS)) { WARN("SCMI system power protocol version message failed"); goto error; } if (!is_scmi_version_compatible(SCMI_SYS_PWR_PROTO_VER, version)) { WARN("SCMI system power management protocol version 0x%x incompatible with driver version 0x%x", version, SCMI_SYS_PWR_PROTO_VER); goto error; } VERBOSE("SCMI system power management protocol version 0x%x detected\n", version); INFO("SCMI driver initialized\n"); return (void *)ch; error: ch->is_initialized = 0; return NULL; } trusted-firmware-a-2.2/drivers/arm/css/scmi/scmi_private.h000066400000000000000000000116371355360272700237370ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SCMI_PRIVATE_H #define SCMI_PRIVATE_H #include /* * SCMI power domain management protocol message and response lengths. It is * calculated as sum of length in bytes of the message header (4) and payload * area (the number of bytes of parameters or return values in the payload). */ #define SCMI_PROTO_VERSION_MSG_LEN 4 #define SCMI_PROTO_VERSION_RESP_LEN 12 #define SCMI_PROTO_MSG_ATTR_MSG_LEN 8 #define SCMI_PROTO_MSG_ATTR_RESP_LEN 12 #define SCMI_AP_CORE_RESET_ADDR_SET_MSG_LEN 16 #define SCMI_AP_CORE_RESET_ADDR_SET_RESP_LEN 8 #define SCMI_AP_CORE_RESET_ADDR_GET_MSG_LEN 4 #define SCMI_AP_CORE_RESET_ADDR_GET_RESP_LEN 20 #define SCMI_PWR_STATE_SET_MSG_LEN 16 #define SCMI_PWR_STATE_SET_RESP_LEN 8 #define SCMI_PWR_STATE_GET_MSG_LEN 8 #define SCMI_PWR_STATE_GET_RESP_LEN 12 #define SCMI_SYS_PWR_STATE_SET_MSG_LEN 12 #define SCMI_SYS_PWR_STATE_SET_RESP_LEN 8 #define SCMI_SYS_PWR_STATE_GET_MSG_LEN 4 #define SCMI_SYS_PWR_STATE_GET_RESP_LEN 12 /* SCMI message header format bit field */ #define SCMI_MSG_ID_SHIFT 0 #define SCMI_MSG_ID_WIDTH 8 #define SCMI_MSG_ID_MASK ((1 << SCMI_MSG_ID_WIDTH) - 1) #define SCMI_MSG_TYPE_SHIFT 8 #define SCMI_MSG_TYPE_WIDTH 2 #define SCMI_MSG_TYPE_MASK ((1 << SCMI_MSG_TYPE_WIDTH) - 1) #define SCMI_MSG_PROTO_ID_SHIFT 10 #define SCMI_MSG_PROTO_ID_WIDTH 8 #define SCMI_MSG_PROTO_ID_MASK ((1 << SCMI_MSG_PROTO_ID_WIDTH) - 1) #define SCMI_MSG_TOKEN_SHIFT 18 #define SCMI_MSG_TOKEN_WIDTH 10 #define SCMI_MSG_TOKEN_MASK ((1 << SCMI_MSG_TOKEN_WIDTH) - 1) /* SCMI mailbox flags */ #define SCMI_FLAG_RESP_POLL 0 #define SCMI_FLAG_RESP_INT 1 /* SCMI power domain protocol `POWER_STATE_SET` message flags */ #define SCMI_PWR_STATE_SET_FLAG_SYNC 0 #define SCMI_PWR_STATE_SET_FLAG_ASYNC 1 /* * Helper macro to create an SCMI message header given protocol, message id * and token. */ #define SCMI_MSG_CREATE(_protocol, _msg_id, _token) \ ((((_protocol) & SCMI_MSG_PROTO_ID_MASK) << SCMI_MSG_PROTO_ID_SHIFT) | \ (((_msg_id) & SCMI_MSG_ID_MASK) << SCMI_MSG_ID_SHIFT) | \ (((_token) & SCMI_MSG_TOKEN_MASK) << SCMI_MSG_TOKEN_SHIFT)) /* Helper macro to get the token from a SCMI message header */ #define SCMI_MSG_GET_TOKEN(_msg) \ (((_msg) >> SCMI_MSG_TOKEN_SHIFT) & SCMI_MSG_TOKEN_MASK) /* SCMI Channel Status bit fields */ #define SCMI_CH_STATUS_RES0_MASK 0xFFFFFFFE #define SCMI_CH_STATUS_FREE_SHIFT 0 #define SCMI_CH_STATUS_FREE_WIDTH 1 #define SCMI_CH_STATUS_FREE_MASK ((1 << SCMI_CH_STATUS_FREE_WIDTH) - 1) /* Helper macros to check and write the channel status */ #define SCMI_IS_CHANNEL_FREE(status) \ (!!(((status) >> SCMI_CH_STATUS_FREE_SHIFT) & SCMI_CH_STATUS_FREE_MASK)) #define SCMI_MARK_CHANNEL_BUSY(status) do { \ assert(SCMI_IS_CHANNEL_FREE(status)); \ (status) &= ~(SCMI_CH_STATUS_FREE_MASK << \ SCMI_CH_STATUS_FREE_SHIFT); \ } while (0) /* Helper macros to copy arguments to the mailbox payload */ #define SCMI_PAYLOAD_ARG1(payld_arr, arg1) \ mmio_write_32((uintptr_t)&payld_arr[0], arg1) #define SCMI_PAYLOAD_ARG2(payld_arr, arg1, arg2) do { \ SCMI_PAYLOAD_ARG1(payld_arr, arg1); \ mmio_write_32((uintptr_t)&payld_arr[1], arg2); \ } while (0) #define SCMI_PAYLOAD_ARG3(payld_arr, arg1, arg2, arg3) do { \ SCMI_PAYLOAD_ARG2(payld_arr, arg1, arg2); \ mmio_write_32((uintptr_t)&payld_arr[2], arg3); \ } while (0) /* Helper macros to read return values from the mailbox payload */ #define SCMI_PAYLOAD_RET_VAL1(payld_arr, val1) \ (val1) = mmio_read_32((uintptr_t)&payld_arr[0]) #define SCMI_PAYLOAD_RET_VAL2(payld_arr, val1, val2) do { \ SCMI_PAYLOAD_RET_VAL1(payld_arr, val1); \ (val2) = mmio_read_32((uintptr_t)&payld_arr[1]); \ } while (0) #define SCMI_PAYLOAD_RET_VAL3(payld_arr, val1, val2, val3) do { \ SCMI_PAYLOAD_RET_VAL2(payld_arr, val1, val2); \ (val3) = mmio_read_32((uintptr_t)&payld_arr[2]); \ } while (0) #define SCMI_PAYLOAD_RET_VAL4(payld_arr, val1, val2, val3, val4) do { \ SCMI_PAYLOAD_RET_VAL3(payld_arr, val1, val2, val3); \ (val4) = mmio_read_32((uintptr_t)&payld_arr[3]); \ } while (0) /* * Private data structure for representing the mailbox memory layout. Refer * the SCMI specification for more details. */ typedef struct mailbox_mem { uint32_t res_a; /* Reserved */ volatile uint32_t status; uint64_t res_b; /* Reserved */ uint32_t flags; volatile uint32_t len; uint32_t msg_header; uint32_t payload[]; } mailbox_mem_t; /* Private APIs for use within SCMI driver */ void scmi_get_channel(scmi_channel_t *ch); void scmi_send_sync_command(scmi_channel_t *ch); void scmi_put_channel(scmi_channel_t *ch); static inline void validate_scmi_channel(scmi_channel_t *ch) { assert(ch && ch->is_initialized); assert(ch->info && ch->info->scmi_mbx_mem); } /* * SCMI vendor specific protocol */ #define SCMI_SYS_VENDOR_EXT_PROTO_ID 0x80 #endif /* SCMI_PRIVATE_H */ trusted-firmware-a-2.2/drivers/arm/css/scmi/scmi_pwr_dmn_proto.c000066400000000000000000000042111355360272700251370ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "scmi_private.h" /* * API to set the SCMI power domain power state. */ int scmi_pwr_state_set(void *p, uint32_t domain_id, uint32_t scmi_pwr_state) { mailbox_mem_t *mbx_mem; unsigned int token = 0; int ret; /* * Only asynchronous mode of `set power state` command is allowed on * application processors. */ uint32_t pwr_state_set_msg_flag = SCMI_PWR_STATE_SET_FLAG_ASYNC; scmi_channel_t *ch = (scmi_channel_t *)p; validate_scmi_channel(ch); scmi_get_channel(ch); mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_PWR_DMN_PROTO_ID, SCMI_PWR_STATE_SET_MSG, token); mbx_mem->len = SCMI_PWR_STATE_SET_MSG_LEN; mbx_mem->flags = SCMI_FLAG_RESP_POLL; SCMI_PAYLOAD_ARG3(mbx_mem->payload, pwr_state_set_msg_flag, domain_id, scmi_pwr_state); scmi_send_sync_command(ch); /* Get the return values */ SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret); assert(mbx_mem->len == SCMI_PWR_STATE_SET_RESP_LEN); assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header)); scmi_put_channel(ch); return ret; } /* * API to get the SCMI power domain power state. */ int scmi_pwr_state_get(void *p, uint32_t domain_id, uint32_t *scmi_pwr_state) { mailbox_mem_t *mbx_mem; unsigned int token = 0; int ret; scmi_channel_t *ch = (scmi_channel_t *)p; validate_scmi_channel(ch); scmi_get_channel(ch); mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_PWR_DMN_PROTO_ID, SCMI_PWR_STATE_GET_MSG, token); mbx_mem->len = SCMI_PWR_STATE_GET_MSG_LEN; mbx_mem->flags = SCMI_FLAG_RESP_POLL; SCMI_PAYLOAD_ARG1(mbx_mem->payload, domain_id); scmi_send_sync_command(ch); /* Get the return values */ SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *scmi_pwr_state); assert(mbx_mem->len == SCMI_PWR_STATE_GET_RESP_LEN); assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header)); scmi_put_channel(ch); return ret; } trusted-firmware-a-2.2/drivers/arm/css/scmi/scmi_sys_pwr_proto.c000066400000000000000000000035601355360272700252050ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "scmi_private.h" /* * API to set the SCMI system power state */ int scmi_sys_pwr_state_set(void *p, uint32_t flags, uint32_t system_state) { mailbox_mem_t *mbx_mem; unsigned int token = 0; int ret; scmi_channel_t *ch = (scmi_channel_t *)p; validate_scmi_channel(ch); scmi_get_channel(ch); mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_SYS_PWR_PROTO_ID, SCMI_SYS_PWR_STATE_SET_MSG, token); mbx_mem->len = SCMI_SYS_PWR_STATE_SET_MSG_LEN; mbx_mem->flags = SCMI_FLAG_RESP_POLL; SCMI_PAYLOAD_ARG2(mbx_mem->payload, flags, system_state); scmi_send_sync_command(ch); /* Get the return values */ SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret); assert(mbx_mem->len == SCMI_SYS_PWR_STATE_SET_RESP_LEN); assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header)); scmi_put_channel(ch); return ret; } /* * API to get the SCMI system power state */ int scmi_sys_pwr_state_get(void *p, uint32_t *system_state) { mailbox_mem_t *mbx_mem; unsigned int token = 0; int ret; scmi_channel_t *ch = (scmi_channel_t *)p; validate_scmi_channel(ch); scmi_get_channel(ch); mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_SYS_PWR_PROTO_ID, SCMI_SYS_PWR_STATE_GET_MSG, token); mbx_mem->len = SCMI_SYS_PWR_STATE_GET_MSG_LEN; mbx_mem->flags = SCMI_FLAG_RESP_POLL; scmi_send_sync_command(ch); /* Get the return values */ SCMI_PAYLOAD_RET_VAL2(mbx_mem->payload, ret, *system_state); assert(mbx_mem->len == SCMI_SYS_PWR_STATE_GET_RESP_LEN); assert(token == SCMI_MSG_GET_TOKEN(mbx_mem->msg_header)); scmi_put_channel(ch); return ret; } trusted-firmware-a-2.2/drivers/arm/css/scmi/vendor/000077500000000000000000000000001355360272700223665ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/css/scmi/vendor/scmi_sq.c000066400000000000000000000026171355360272700241760ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "scmi_private.h" #include "scmi_sq.h" #include /* SCMI messge ID to get the available DRAM region */ #define SCMI_VENDOR_EXT_MEMINFO_GET_MSG 0x3 #define SCMI_VENDOR_EXT_MEMINFO_GET_MSG_LEN 4 /* * API to get the available DRAM region */ int scmi_get_draminfo(void *p, struct draminfo *info) { mailbox_mem_t *mbx_mem; int token = 0, ret; scmi_channel_t *ch = (scmi_channel_t *)p; struct dram_info_resp response; validate_scmi_channel(ch); scmi_get_channel(ch); mbx_mem = (mailbox_mem_t *)(ch->info->scmi_mbx_mem); mbx_mem->msg_header = SCMI_MSG_CREATE(SCMI_SYS_VENDOR_EXT_PROTO_ID, SCMI_VENDOR_EXT_MEMINFO_GET_MSG, token); mbx_mem->len = SCMI_VENDOR_EXT_MEMINFO_GET_MSG_LEN; mbx_mem->flags = SCMI_FLAG_RESP_POLL; scmi_send_sync_command(ch); /* * Ensure that any read to the SCPI payload area is done after reading * the MHU register. If these 2 reads were reordered then the CPU would * read invalid payload data */ dmbld(); /* Get the return values */ SCMI_PAYLOAD_RET_VAL1(mbx_mem->payload, ret); memcpy(&response, (void *)mbx_mem->payload, sizeof(response)); scmi_put_channel(ch); *info = response.info; return ret; } trusted-firmware-a-2.2/drivers/arm/css/scmi/vendor/scmi_sq.h000066400000000000000000000007401355360272700241760ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SCMI_SQ_H #define SCMI_SQ_H #include #include #include /* Structure to represent available DRAM region */ struct dram_info_resp { int status; int reserved; struct draminfo info; }; /* API to get the available DRAM region */ int scmi_get_draminfo(void *p, struct draminfo *info); #endif /* SCMI_SQ_H */ trusted-firmware-a-2.2/drivers/arm/css/scp/000077500000000000000000000000001355360272700207235ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/css/scp/css_bom_bootloader.c000066400000000000000000000121771355360272700247360ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include /* ID of the MHU slot used for the BOM protocol */ #define BOM_MHU_SLOT_ID 0 /* Boot commands sent from AP -> SCP */ #define BOOT_CMD_INFO 0x00 #define BOOT_CMD_DATA 0x01 /* BOM command header */ typedef struct { uint32_t id : 8; uint32_t reserved : 24; } bom_cmd_t; typedef struct { uint32_t image_size; uint32_t checksum; } cmd_info_payload_t; /* * Unlike the SCPI protocol, the boot protocol uses the same memory region * for both AP -> SCP and SCP -> AP transfers; define the address of this... */ #define BOM_SHARED_MEM PLAT_CSS_SCP_COM_SHARED_MEM_BASE #define BOM_CMD_HEADER ((bom_cmd_t *) BOM_SHARED_MEM) #define BOM_CMD_PAYLOAD ((void *) (BOM_SHARED_MEM + sizeof(bom_cmd_t))) typedef struct { /* Offset from the base address of the Trusted RAM */ uint32_t offset; uint32_t block_size; } cmd_data_payload_t; /* * All CSS platforms load SCP_BL2/SCP_BL2U just below BL2 (this is where BL31 * usually resides except when ARM_BL31_IN_DRAM is * set). Ensure that SCP_BL2/SCP_BL2U do not overflow into shared RAM and * the tb_fw_config. */ CASSERT(SCP_BL2_LIMIT <= BL2_BASE, assert_scp_bl2_overwrite_bl2); CASSERT(SCP_BL2U_LIMIT <= BL2_BASE, assert_scp_bl2u_overwrite_bl2); CASSERT(SCP_BL2_BASE >= ARM_TB_FW_CONFIG_LIMIT, assert_scp_bl2_overflow); CASSERT(SCP_BL2U_BASE >= ARM_TB_FW_CONFIG_LIMIT, assert_scp_bl2u_overflow); static void scp_boot_message_start(void) { mhu_secure_message_start(BOM_MHU_SLOT_ID); } static void scp_boot_message_send(size_t payload_size) { /* Ensure that any write to the BOM payload area is seen by SCP before * we write to the MHU register. If these 2 writes were reordered by * the CPU then SCP would read stale payload data */ dmbst(); /* Send command to SCP */ mhu_secure_message_send(BOM_MHU_SLOT_ID); } static uint32_t scp_boot_message_wait(size_t size) { uint32_t mhu_status; mhu_status = mhu_secure_message_wait(); /* Expect an SCP Boot Protocol message, reject any other protocol */ if (mhu_status != (1 << BOM_MHU_SLOT_ID)) { ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n", mhu_status); panic(); } /* Ensure that any read to the BOM payload area is done after reading * the MHU register. If these 2 reads were reordered then the CPU would * read invalid payload data */ dmbld(); return *(uint32_t *) BOM_SHARED_MEM; } static void scp_boot_message_end(void) { mhu_secure_message_end(BOM_MHU_SLOT_ID); } int css_scp_boot_image_xfer(void *image, unsigned int image_size) { uint32_t response; uint32_t checksum; cmd_info_payload_t *cmd_info_payload; cmd_data_payload_t *cmd_data_payload; assert((uintptr_t) image == SCP_BL2_BASE); if ((image_size == 0) || (image_size % 4 != 0)) { ERROR("Invalid size for the SCP_BL2 image. Must be a multiple of " "4 bytes and not zero (current size = 0x%x)\n", image_size); return -1; } /* Extract the checksum from the image */ checksum = *(uint32_t *) image; image = (char *) image + sizeof(checksum); image_size -= sizeof(checksum); mhu_secure_init(); VERBOSE("Send info about the SCP_BL2 image to be transferred to SCP\n"); /* * Send information about the SCP firmware image about to be transferred * to SCP */ scp_boot_message_start(); BOM_CMD_HEADER->id = BOOT_CMD_INFO; cmd_info_payload = BOM_CMD_PAYLOAD; cmd_info_payload->image_size = image_size; cmd_info_payload->checksum = checksum; scp_boot_message_send(sizeof(*cmd_info_payload)); #if CSS_DETECT_PRE_1_7_0_SCP { const uint32_t deprecated_scp_nack_cmd = 0x404; uint32_t mhu_status; VERBOSE("Detecting SCP version incompatibility\n"); mhu_status = mhu_secure_message_wait(); if (mhu_status == deprecated_scp_nack_cmd) { ERROR("Detected an incompatible version of the SCP firmware.\n"); ERROR("Only versions from v1.7.0 onwards are supported.\n"); ERROR("Please update the SCP firmware.\n"); return -1; } VERBOSE("SCP version looks OK\n"); } #endif /* CSS_DETECT_PRE_1_7_0_SCP */ response = scp_boot_message_wait(sizeof(response)); scp_boot_message_end(); if (response != 0) { ERROR("SCP BOOT_CMD_INFO returned error %u\n", response); return -1; } VERBOSE("Transferring SCP_BL2 image to SCP\n"); /* Transfer SCP_BL2 image to SCP */ scp_boot_message_start(); BOM_CMD_HEADER->id = BOOT_CMD_DATA; cmd_data_payload = BOM_CMD_PAYLOAD; cmd_data_payload->offset = (uintptr_t) image - ARM_TRUSTED_SRAM_BASE; cmd_data_payload->block_size = image_size; scp_boot_message_send(sizeof(*cmd_data_payload)); response = scp_boot_message_wait(sizeof(response)); scp_boot_message_end(); if (response != 0) { ERROR("SCP BOOT_CMD_DATA returned error %u\n", response); return -1; } return 0; } int css_scp_boot_ready(void) { VERBOSE("Waiting for SCP to signal it is ready to go on\n"); /* Wait for SCP to signal it's ready */ return scpi_wait_ready(); } trusted-firmware-a-2.2/drivers/arm/css/scp/css_pm_scmi.c000066400000000000000000000267171355360272700234030ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include /* * This file implements the SCP helper functions using SCMI protocol. */ /* * SCMI power state parameter bit field encoding for ARM CSS platforms. * * 31 20 19 16 15 12 11 8 7 4 3 0 * +-------------------------------------------------------------+ * | SBZ | Max level | Level 3 | Level 2 | Level 1 | Level 0 | * | | | state | state | state | state | * +-------------------------------------------------------------+ * * `Max level` encodes the highest level that has a valid power state * encoded in the power state. */ #define SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT 16 #define SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH 4 #define SCMI_PWR_STATE_MAX_PWR_LVL_MASK \ ((1 << SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH) - 1) #define SCMI_SET_PWR_STATE_MAX_PWR_LVL(_power_state, _max_level) \ (_power_state) |= ((_max_level) & SCMI_PWR_STATE_MAX_PWR_LVL_MASK)\ << SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT #define SCMI_GET_PWR_STATE_MAX_PWR_LVL(_power_state) \ (((_power_state) >> SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT) \ & SCMI_PWR_STATE_MAX_PWR_LVL_MASK) #define SCMI_PWR_STATE_LVL_WIDTH 4 #define SCMI_PWR_STATE_LVL_MASK \ ((1 << SCMI_PWR_STATE_LVL_WIDTH) - 1) #define SCMI_SET_PWR_STATE_LVL(_power_state, _level, _level_state) \ (_power_state) |= ((_level_state) & SCMI_PWR_STATE_LVL_MASK) \ << (SCMI_PWR_STATE_LVL_WIDTH * (_level)) #define SCMI_GET_PWR_STATE_LVL(_power_state, _level) \ (((_power_state) >> (SCMI_PWR_STATE_LVL_WIDTH * (_level))) & \ SCMI_PWR_STATE_LVL_MASK) /* * The SCMI power state enumeration for a power domain level */ typedef enum { scmi_power_state_off = 0, scmi_power_state_on = 1, scmi_power_state_sleep = 2, } scmi_power_state_t; /* * The global handle for invoking the SCMI driver APIs after the driver * has been initialized. */ static void *scmi_handle; /* The SCMI channel global object */ static scmi_channel_t channel; ARM_SCMI_INSTANTIATE_LOCK; /* * Helper function to suspend a CPU power domain and its parent power domains * if applicable. */ void css_scp_suspend(const struct psci_power_state *target_state) { int ret; /* At least power domain level 0 should be specified to be suspended */ assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == ARM_LOCAL_STATE_OFF); /* Check if power down at system power domain level is requested */ if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF) { /* Issue SCMI command for SYSTEM_SUSPEND */ ret = scmi_sys_pwr_state_set(scmi_handle, SCMI_SYS_PWR_FORCEFUL_REQ, SCMI_SYS_PWR_SUSPEND); if (ret != SCMI_E_SUCCESS) { ERROR("SCMI system power domain suspend return 0x%x unexpected\n", ret); panic(); } return; } #if !HW_ASSISTED_COHERENCY unsigned int lvl; uint32_t scmi_pwr_state = 0; /* * If we reach here, then assert that power down at system power domain * level is running. */ assert(css_system_pwr_state(target_state) == ARM_LOCAL_STATE_RUN); /* For level 0, specify `scmi_power_state_sleep` as the power state */ SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, ARM_PWR_LVL0, scmi_power_state_sleep); for (lvl = ARM_PWR_LVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) { if (target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_RUN) break; assert(target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_OFF); /* * Specify `scmi_power_state_off` as power state for higher * levels. */ SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl, scmi_power_state_off); } SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1); ret = scmi_pwr_state_set(scmi_handle, plat_css_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()], scmi_pwr_state); if (ret != SCMI_E_SUCCESS) { ERROR("SCMI set power state command return 0x%x unexpected\n", ret); panic(); } #endif } /* * Helper function to turn off a CPU power domain and its parent power domains * if applicable. */ void css_scp_off(const struct psci_power_state *target_state) { unsigned int lvl = 0; int ret; uint32_t scmi_pwr_state = 0; /* At-least the CPU level should be specified to be OFF */ assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == ARM_LOCAL_STATE_OFF); /* PSCI CPU OFF cannot be used to turn OFF system power domain */ assert(css_system_pwr_state(target_state) == ARM_LOCAL_STATE_RUN); for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) { if (target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_RUN) break; assert(target_state->pwr_domain_state[lvl] == ARM_LOCAL_STATE_OFF); SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl, scmi_power_state_off); } SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1); ret = scmi_pwr_state_set(scmi_handle, plat_css_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()], scmi_pwr_state); if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) { ERROR("SCMI set power state command return 0x%x unexpected\n", ret); panic(); } } /* * Helper function to turn ON a CPU power domain and its parent power domains * if applicable. */ void css_scp_on(u_register_t mpidr) { unsigned int lvl = 0; int ret, core_pos; uint32_t scmi_pwr_state = 0; for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl, scmi_power_state_on); SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1); core_pos = plat_core_pos_by_mpidr(mpidr); assert(core_pos >= 0 && core_pos < PLATFORM_CORE_COUNT); ret = scmi_pwr_state_set(scmi_handle, plat_css_core_pos_to_scmi_dmn_id_map[core_pos], scmi_pwr_state); if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) { ERROR("SCMI set power state command return 0x%x unexpected\n", ret); panic(); } } /* * Helper function to get the power state of a power domain node as reported * by the SCP. */ int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level) { int ret, cpu_idx; uint32_t scmi_pwr_state = 0, lvl_state; /* We don't support get power state at the system power domain level */ if ((power_level > PLAT_MAX_PWR_LVL) || (power_level == CSS_SYSTEM_PWR_DMN_LVL)) { WARN("Invalid power level %u specified for SCMI get power state\n", power_level); return PSCI_E_INVALID_PARAMS; } cpu_idx = plat_core_pos_by_mpidr(mpidr); assert(cpu_idx > -1); ret = scmi_pwr_state_get(scmi_handle, plat_css_core_pos_to_scmi_dmn_id_map[cpu_idx], &scmi_pwr_state); if (ret != SCMI_E_SUCCESS) { WARN("SCMI get power state command return 0x%x unexpected\n", ret); return PSCI_E_INVALID_PARAMS; } /* * Find the maximum power level described in the get power state * command. If it is less than the requested power level, then assume * the requested power level is ON. */ if (SCMI_GET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state) < power_level) return HW_ON; lvl_state = SCMI_GET_PWR_STATE_LVL(scmi_pwr_state, power_level); if (lvl_state == scmi_power_state_on) return HW_ON; assert((lvl_state == scmi_power_state_off) || (lvl_state == scmi_power_state_sleep)); return HW_OFF; } void __dead2 css_scp_system_off(int state) { int ret; /* * Disable GIC CPU interface to prevent pending interrupt from waking * up the AP from WFI. */ plat_arm_gic_cpuif_disable(); /* * Issue SCMI command. First issue a graceful * request and if that fails force the request. */ ret = scmi_sys_pwr_state_set(scmi_handle, SCMI_SYS_PWR_FORCEFUL_REQ, state); if (ret != SCMI_E_SUCCESS) { ERROR("SCMI system power state set 0x%x returns unexpected 0x%x\n", state, ret); panic(); } wfi(); ERROR("CSS set power state: operation not handled.\n"); panic(); } /* * Helper function to shutdown the system via SCMI. */ void __dead2 css_scp_sys_shutdown(void) { css_scp_system_off(SCMI_SYS_PWR_SHUTDOWN); } /* * Helper function to reset the system via SCMI. */ void __dead2 css_scp_sys_reboot(void) { css_scp_system_off(SCMI_SYS_PWR_COLD_RESET); } static int scmi_ap_core_init(scmi_channel_t *ch) { #if PROGRAMMABLE_RESET_ADDRESS uint32_t version; int ret; ret = scmi_proto_version(ch, SCMI_AP_CORE_PROTO_ID, &version); if (ret != SCMI_E_SUCCESS) { WARN("SCMI AP core protocol version message failed\n"); return -1; } if (!is_scmi_version_compatible(SCMI_AP_CORE_PROTO_VER, version)) { WARN("SCMI AP core protocol version 0x%x incompatible with driver version 0x%x\n", version, SCMI_AP_CORE_PROTO_VER); return -1; } INFO("SCMI AP core protocol version 0x%x detected\n", version); #endif return 0; } void __init plat_arm_pwrc_setup(void) { channel.info = plat_css_get_scmi_info(); channel.lock = ARM_SCMI_LOCK_GET_INSTANCE; scmi_handle = scmi_init(&channel); if (scmi_handle == NULL) { ERROR("SCMI Initialization failed\n"); panic(); } if (scmi_ap_core_init(&channel) < 0) { ERROR("SCMI AP core protocol initialization failed\n"); panic(); } } /****************************************************************************** * This function overrides the default definition for ARM platforms. Initialize * the SCMI driver, query capability via SCMI and modify the PSCI capability * based on that. *****************************************************************************/ const plat_psci_ops_t *css_scmi_override_pm_ops(plat_psci_ops_t *ops) { uint32_t msg_attr; int ret; assert(scmi_handle); /* Check that power domain POWER_STATE_SET message is supported */ ret = scmi_proto_msg_attr(scmi_handle, SCMI_PWR_DMN_PROTO_ID, SCMI_PWR_STATE_SET_MSG, &msg_attr); if (ret != SCMI_E_SUCCESS) { ERROR("Set power state command is not supported by SCMI\n"); panic(); } /* * Don't support PSCI NODE_HW_STATE call if SCMI doesn't support * POWER_STATE_GET message. */ ret = scmi_proto_msg_attr(scmi_handle, SCMI_PWR_DMN_PROTO_ID, SCMI_PWR_STATE_GET_MSG, &msg_attr); if (ret != SCMI_E_SUCCESS) ops->get_node_hw_state = NULL; /* Check if the SCMI SYSTEM_POWER_STATE_SET message is supported */ ret = scmi_proto_msg_attr(scmi_handle, SCMI_SYS_PWR_PROTO_ID, SCMI_SYS_PWR_STATE_SET_MSG, &msg_attr); if (ret != SCMI_E_SUCCESS) { /* System power management operations are not supported */ ops->system_off = NULL; ops->system_reset = NULL; ops->get_sys_suspend_power_state = NULL; } else { if (!(msg_attr & SCMI_SYS_PWR_SUSPEND_SUPPORTED)) { /* * System power management protocol is available, but * it does not support SYSTEM SUSPEND. */ ops->get_sys_suspend_power_state = NULL; } if (!(msg_attr & SCMI_SYS_PWR_WARM_RESET_SUPPORTED)) { /* * WARM reset is not available. */ ops->system_reset2 = NULL; } } return ops; } int css_system_reset2(int is_vendor, int reset_type, u_register_t cookie) { if (is_vendor || (reset_type != PSCI_RESET2_SYSTEM_WARM_RESET)) return PSCI_E_INVALID_PARAMS; css_scp_system_off(SCMI_SYS_PWR_WARM_RESET); /* * css_scp_system_off cannot return (it is a __dead function), * but css_system_reset2 has to return some value, even in * this case. */ return 0; } #if PROGRAMMABLE_RESET_ADDRESS void plat_arm_program_trusted_mailbox(uintptr_t address) { int ret; assert(scmi_handle); ret = scmi_ap_core_set_reset_addr(scmi_handle, address, SCMI_AP_CORE_LOCK_ATTR); if (ret != SCMI_E_SUCCESS) { ERROR("CSS: Failed to program reset address: %d\n", ret); panic(); } } #endif trusted-firmware-a-2.2/drivers/arm/css/scp/css_pm_scpi.c000066400000000000000000000103041355360272700233670ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* * This file implements the SCP power management functions using SCPI protocol. */ /* * Helper function to inform power down state to SCP. */ void css_scp_suspend(const struct psci_power_state *target_state) { uint32_t cluster_state = scpi_power_on; uint32_t system_state = scpi_power_on; /* Check if power down at system power domain level is requested */ if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF) system_state = scpi_power_retention; /* Cluster is to be turned off, so disable coherency */ if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) cluster_state = scpi_power_off; /* * Ask the SCP to power down the appropriate components depending upon * their state. */ scpi_set_css_power_state(read_mpidr_el1(), scpi_power_off, cluster_state, system_state); } /* * Helper function to turn off a CPU power domain and its parent power domains * if applicable. Since SCPI doesn't differentiate between OFF and suspend, we * call the suspend helper here. */ void css_scp_off(const struct psci_power_state *target_state) { css_scp_suspend(target_state); } /* * Helper function to turn ON a CPU power domain and its parent power domains * if applicable. */ void css_scp_on(u_register_t mpidr) { /* * SCP takes care of powering up parent power domains so we * only need to care about level 0 */ scpi_set_css_power_state(mpidr, scpi_power_on, scpi_power_on, scpi_power_on); } /* * Helper function to get the power state of a power domain node as reported * by the SCP. */ int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level) { int rc, element; unsigned int cpu_state, cluster_state; /* * The format of 'power_level' is implementation-defined, but 0 must * mean a CPU. We also allow 1 to denote the cluster */ if (power_level != ARM_PWR_LVL0 && power_level != ARM_PWR_LVL1) return PSCI_E_INVALID_PARAMS; /* Query SCP */ rc = scpi_get_css_power_state(mpidr, &cpu_state, &cluster_state); if (rc != 0) return PSCI_E_INVALID_PARAMS; /* Map power states of CPU and cluster to expected PSCI return codes */ if (power_level == ARM_PWR_LVL0) { /* * The CPU state returned by SCP is an 8-bit bit mask * corresponding to each CPU in the cluster */ #if ARM_PLAT_MT /* * The current SCPI driver only caters for single-threaded * platforms. Hence we ignore the thread ID (which is always 0) * for such platforms. */ element = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; #else element = mpidr & MPIDR_AFFLVL_MASK; #endif /* ARM_PLAT_MT */ return CSS_CPU_PWR_STATE(cpu_state, element) == CSS_CPU_PWR_STATE_ON ? HW_ON : HW_OFF; } else { assert(cluster_state == CSS_CLUSTER_PWR_STATE_ON || cluster_state == CSS_CLUSTER_PWR_STATE_OFF); return cluster_state == CSS_CLUSTER_PWR_STATE_ON ? HW_ON : HW_OFF; } } /* * Helper function to shutdown the system via SCPI. */ void __dead2 css_scp_sys_shutdown(void) { uint32_t response; /* * Disable GIC CPU interface to prevent pending interrupt * from waking up the AP from WFI. */ plat_arm_gic_cpuif_disable(); /* Send the power down request to the SCP */ response = scpi_sys_power_state(scpi_system_shutdown); if (response != SCP_OK) { ERROR("CSS System Off: SCP error %u.\n", response); panic(); } wfi(); ERROR("CSS System Off: operation not handled.\n"); panic(); } /* * Helper function to reset the system via SCPI. */ void __dead2 css_scp_sys_reboot(void) { uint32_t response; /* * Disable GIC CPU interface to prevent pending interrupt * from waking up the AP from WFI. */ plat_arm_gic_cpuif_disable(); /* Send the system reset request to the SCP */ response = scpi_sys_power_state(scpi_system_reboot); if (response != SCP_OK) { ERROR("CSS System Reset: SCP error %u.\n", response); panic(); } wfi(); ERROR("CSS System Reset: operation not handled.\n"); panic(); } trusted-firmware-a-2.2/drivers/arm/css/scp/css_sds.c000066400000000000000000000044771355360272700225440ustar00rootroot00000000000000/* * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include int css_scp_boot_image_xfer(void *image, unsigned int image_size) { int ret; unsigned int image_offset, image_flags; ret = sds_init(); if (ret != SDS_OK) { ERROR("SCP SDS initialization failed\n"); panic(); } VERBOSE("Writing SCP image metadata\n"); image_offset = (uintptr_t) image - ARM_TRUSTED_SRAM_BASE; ret = sds_struct_write(SDS_SCP_IMG_STRUCT_ID, SDS_SCP_IMG_ADDR_OFFSET, &image_offset, SDS_SCP_IMG_ADDR_SIZE, SDS_ACCESS_MODE_NON_CACHED); if (ret != SDS_OK) goto sds_fail; ret = sds_struct_write(SDS_SCP_IMG_STRUCT_ID, SDS_SCP_IMG_SIZE_OFFSET, &image_size, SDS_SCP_IMG_SIZE_SIZE, SDS_ACCESS_MODE_NON_CACHED); if (ret != SDS_OK) goto sds_fail; VERBOSE("Marking SCP image metadata as valid\n"); image_flags = SDS_SCP_IMG_VALID_FLAG_BIT; ret = sds_struct_write(SDS_SCP_IMG_STRUCT_ID, SDS_SCP_IMG_FLAG_OFFSET, &image_flags, SDS_SCP_IMG_FLAG_SIZE, SDS_ACCESS_MODE_NON_CACHED); if (ret != SDS_OK) goto sds_fail; return 0; sds_fail: ERROR("SCP SDS write to SCP IMG struct failed\n"); panic(); } /* * API to wait for SCP to signal till it's ready after booting the transferred * image. */ int css_scp_boot_ready(void) { uint32_t scp_feature_availability_flags; int ret, retry = CSS_SCP_READY_10US_RETRIES; VERBOSE("Waiting for SCP RAM to complete its initialization process\n"); /* Wait for the SCP RAM Firmware to complete its initialization process */ while (retry > 0) { ret = sds_struct_read(SDS_FEATURE_AVAIL_STRUCT_ID, 0, &scp_feature_availability_flags, SDS_FEATURE_AVAIL_SIZE, SDS_ACCESS_MODE_NON_CACHED); if (ret == SDS_ERR_STRUCT_NOT_FINALIZED) continue; if (ret != SDS_OK) { ERROR(" sds_struct_read failed\n"); panic(); } if (scp_feature_availability_flags & SDS_FEATURE_AVAIL_SCP_RAM_READY_BIT) return 0; udelay(10); retry--; } ERROR("Timeout of %d ms expired waiting for SCP RAM Ready flag\n", CSS_SCP_READY_10US_RETRIES/100); plat_panic_handler(); } trusted-firmware-a-2.2/drivers/arm/css/scpi/000077500000000000000000000000001355360272700210745ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/css/scpi/css_scpi.c000066400000000000000000000160151355360272700230510ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #define SCPI_SHARED_MEM_SCP_TO_AP PLAT_CSS_SCP_COM_SHARED_MEM_BASE #define SCPI_SHARED_MEM_AP_TO_SCP (PLAT_CSS_SCP_COM_SHARED_MEM_BASE \ + 0x100) /* Header and payload addresses for commands from AP to SCP */ #define SCPI_CMD_HEADER_AP_TO_SCP \ ((scpi_cmd_t *) SCPI_SHARED_MEM_AP_TO_SCP) #define SCPI_CMD_PAYLOAD_AP_TO_SCP \ ((void *) (SCPI_SHARED_MEM_AP_TO_SCP + sizeof(scpi_cmd_t))) /* Header and payload addresses for responses from SCP to AP */ #define SCPI_RES_HEADER_SCP_TO_AP \ ((scpi_cmd_t *) SCPI_SHARED_MEM_SCP_TO_AP) #define SCPI_RES_PAYLOAD_SCP_TO_AP \ ((void *) (SCPI_SHARED_MEM_SCP_TO_AP + sizeof(scpi_cmd_t))) /* ID of the MHU slot used for the SCPI protocol */ #define SCPI_MHU_SLOT_ID 0 static void scpi_secure_message_start(void) { mhu_secure_message_start(SCPI_MHU_SLOT_ID); } static void scpi_secure_message_send(size_t payload_size) { /* * Ensure that any write to the SCPI payload area is seen by SCP before * we write to the MHU register. If these 2 writes were reordered by * the CPU then SCP would read stale payload data */ dmbst(); mhu_secure_message_send(SCPI_MHU_SLOT_ID); } static void scpi_secure_message_receive(scpi_cmd_t *cmd) { uint32_t mhu_status; assert(cmd != NULL); mhu_status = mhu_secure_message_wait(); /* Expect an SCPI message, reject any other protocol */ if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) { ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n", mhu_status); panic(); } /* * Ensure that any read to the SCPI payload area is done after reading * the MHU register. If these 2 reads were reordered then the CPU would * read invalid payload data */ dmbld(); memcpy(cmd, (void *) SCPI_SHARED_MEM_SCP_TO_AP, sizeof(*cmd)); } static void scpi_secure_message_end(void) { mhu_secure_message_end(SCPI_MHU_SLOT_ID); } int scpi_wait_ready(void) { scpi_cmd_t scpi_cmd; VERBOSE("Waiting for SCP_READY command...\n"); /* Get a message from the SCP */ scpi_secure_message_start(); scpi_secure_message_receive(&scpi_cmd); scpi_secure_message_end(); /* We are expecting 'SCP Ready', produce correct error if it's not */ scpi_status_t status = SCP_OK; if (scpi_cmd.id != SCPI_CMD_SCP_READY) { ERROR("Unexpected SCP command: expected command #%u, got command #%u\n", SCPI_CMD_SCP_READY, scpi_cmd.id); status = SCP_E_SUPPORT; } else if (scpi_cmd.size != 0) { ERROR("SCP_READY command has incorrect size: expected 0, got %u\n", scpi_cmd.size); status = SCP_E_SIZE; } VERBOSE("Sending response for SCP_READY command\n"); /* * Send our response back to SCP. * We are using the same SCPI header, just update the status field. */ scpi_cmd.status = status; scpi_secure_message_start(); memcpy((void *) SCPI_SHARED_MEM_AP_TO_SCP, &scpi_cmd, sizeof(scpi_cmd)); scpi_secure_message_send(0); scpi_secure_message_end(); return status == SCP_OK ? 0 : -1; } void scpi_set_css_power_state(unsigned int mpidr, scpi_power_state_t cpu_state, scpi_power_state_t cluster_state, scpi_power_state_t css_state) { scpi_cmd_t *cmd; uint32_t state = 0; uint32_t *payload_addr; #if ARM_PLAT_MT /* * The current SCPI driver only caters for single-threaded platforms. * Hence we ignore the thread ID (which is always 0) for such platforms. */ state |= (mpidr >> MPIDR_AFF1_SHIFT) & 0x0f; /* CPU ID */ state |= ((mpidr >> MPIDR_AFF2_SHIFT) & 0x0f) << 4; /* Cluster ID */ #else state |= mpidr & 0x0f; /* CPU ID */ state |= (mpidr & 0xf00) >> 4; /* Cluster ID */ #endif /* ARM_PLAT_MT */ state |= cpu_state << 8; state |= cluster_state << 12; state |= css_state << 16; scpi_secure_message_start(); /* Populate the command header */ cmd = SCPI_CMD_HEADER_AP_TO_SCP; cmd->id = SCPI_CMD_SET_CSS_POWER_STATE; cmd->set = SCPI_SET_NORMAL; cmd->sender = 0; cmd->size = sizeof(state); /* Populate the command payload */ payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP; *payload_addr = state; scpi_secure_message_send(sizeof(state)); /* * SCP does not reply to this command in order to avoid MHU interrupts * from the sender, which could interfere with its power state request. */ scpi_secure_message_end(); } /* * Query and obtain CSS power state from SCP. * * In response to the query, SCP returns power states of all CPUs in all * clusters of the system. The returned response is then filtered based on the * supplied MPIDR. Power states of requested cluster and CPUs within are updated * via supplied non-NULL pointer arguments. * * Returns 0 on success, or -1 on errors. */ int scpi_get_css_power_state(unsigned int mpidr, unsigned int *cpu_state_p, unsigned int *cluster_state_p) { scpi_cmd_t *cmd; scpi_cmd_t response; int power_state, cpu, cluster, rc = -1; /* * Extract CPU and cluster membership of the given MPIDR. SCPI caters * for only up to 0xf clusters, and 8 CPUs per cluster */ #if ARM_PLAT_MT /* * The current SCPI driver only caters for single-threaded platforms. * Hence we ignore the thread ID (which is always 0) for such platforms. */ cpu = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; cluster = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK; #else cpu = mpidr & MPIDR_AFFLVL_MASK; cluster = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; #endif /* ARM_PLAT_MT */ if (cpu >= 8 || cluster >= 0xf) return -1; scpi_secure_message_start(); /* Populate request headers */ zeromem(SCPI_CMD_HEADER_AP_TO_SCP, sizeof(*cmd)); cmd = SCPI_CMD_HEADER_AP_TO_SCP; cmd->id = SCPI_CMD_GET_CSS_POWER_STATE; /* * Send message and wait for SCP's response */ scpi_secure_message_send(0); scpi_secure_message_receive(&response); if (response.status != SCP_OK) goto exit; /* Validate SCP response */ if (!CHECK_RESPONSE(response, cluster)) goto exit; /* Extract power states for required cluster */ power_state = *(((uint16_t *) SCPI_RES_PAYLOAD_SCP_TO_AP) + cluster); if (CLUSTER_ID(power_state) != cluster) goto exit; /* Update power state via pointers */ if (cluster_state_p) *cluster_state_p = CLUSTER_POWER_STATE(power_state); if (cpu_state_p) *cpu_state_p = CPU_POWER_STATE(power_state); rc = 0; exit: scpi_secure_message_end(); return rc; } uint32_t scpi_sys_power_state(scpi_system_state_t system_state) { scpi_cmd_t *cmd; uint8_t *payload_addr; scpi_cmd_t response; scpi_secure_message_start(); /* Populate the command header */ cmd = SCPI_CMD_HEADER_AP_TO_SCP; cmd->id = SCPI_CMD_SYS_POWER_STATE; cmd->set = 0; cmd->sender = 0; cmd->size = sizeof(*payload_addr); /* Populate the command payload */ payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP; *payload_addr = system_state & 0xff; scpi_secure_message_send(sizeof(*payload_addr)); scpi_secure_message_receive(&response); scpi_secure_message_end(); return response.status; } trusted-firmware-a-2.2/drivers/arm/css/sds/000077500000000000000000000000001355360272700207275ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/css/sds/aarch32/000077500000000000000000000000001355360272700221525ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/css/sds/aarch32/sds_helpers.S000066400000000000000000000030571355360272700246160ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "../sds_private.h" .globl sds_get_primary_cpu_id /* * int sds_get_primary_cpu_id(void); * Return the primary CPU ID from SDS Structure * Returns CPUID on success or -1 on failure */ func sds_get_primary_cpu_id ldr r0, =PLAT_ARM_SDS_MEM_BASE ldr r2, =SDS_REGION_SIGNATURE ldr r1, [r0] ubfx r3, r1, #0, #16 /* Check if the SDS region signature found */ cmp r2, r3 bne 2f /* Get the structure count from region descriptor in r1 */ ubfx r1, r1, #SDS_REGION_STRUCT_COUNT_SHIFT, #SDS_REGION_STRUCT_COUNT_WIDTH cmp r1, #0 beq 2f add r0, r0, #SDS_REGION_DESC_SIZE /* Initialize the loop iterator count in r3 */ mov r3, #0 loop_begin: ldrh r2, [r0] cmp r2, #SDS_AP_CPU_INFO_STRUCT_ID bne continue_loop /* We have found the required structure */ ldr r0, [r0,#(SDS_HEADER_SIZE + SDS_AP_CPU_INFO_PRIMARY_CPUID_OFFSET)] bx lr continue_loop: /* Increment the loop counter and exit loop if counter == structure count */ add r3, r3, #0x1 cmp r1, r3 beq 2f /* Read the 2nd word in header */ ldr r2, [r0,#4] /* Get the structure size from header */ ubfx r2, r2, #SDS_HEADER_STRUCT_SIZE_SHIFT, #SDS_HEADER_STRUCT_SIZE_WIDTH /* Add the structure size and SDS HEADER SIZE to point to next header */ add r2, r2, #SDS_HEADER_SIZE add r0, r0, r2 b loop_begin 2: mov r0, #0xffffffff bx lr endfunc sds_get_primary_cpu_id trusted-firmware-a-2.2/drivers/arm/css/sds/aarch64/000077500000000000000000000000001355360272700221575ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/css/sds/aarch64/sds_helpers.S000066400000000000000000000030321355360272700246140ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "../sds_private.h" .globl sds_get_primary_cpu_id /* * int sds_get_primary_cpu_id(void); * Return the primary CPI ID from SDS Structure * Returns CPUID on success or -1 on failure */ func sds_get_primary_cpu_id mov_imm x0, PLAT_ARM_SDS_MEM_BASE mov w2, #SDS_REGION_SIGNATURE ldr w1, [x0] /* Check if the SDS region signature found */ cmp w2, w1, uxth b.ne 2f /* Get the structure count from region descriptor in `w1 */ ubfx w1, w1, #SDS_REGION_STRUCT_COUNT_SHIFT, #SDS_REGION_STRUCT_COUNT_WIDTH cbz w1, 2f add x0, x0, #SDS_REGION_DESC_SIZE /* Initialize the loop iterator count in w3 */ mov w3, #0 loop_begin: ldrh w2, [x0] cmp w2, #SDS_AP_CPU_INFO_STRUCT_ID b.ne continue_loop /* We have found the required structure */ ldr w0, [x0,#(SDS_HEADER_SIZE + SDS_AP_CPU_INFO_PRIMARY_CPUID_OFFSET)] ret continue_loop: /* Increment the loop counter and exit loop if counter == structure count */ add w3, w3, #0x1 cmp w1, w3 b.eq 2f /* Read the 2nd word in header */ ldr w2, [x0,#4] /* Get the structure size from header */ ubfx x2, x2, #SDS_HEADER_STRUCT_SIZE_SHIFT, #SDS_HEADER_STRUCT_SIZE_WIDTH /* Add the structure size and SDS HEADER SIZE to point to next header */ add x2, x2, #SDS_HEADER_SIZE add x0, x0, x2 b loop_begin 2: mov w0, #0xffffffff ret endfunc sds_get_primary_cpu_id trusted-firmware-a-2.2/drivers/arm/css/sds/sds.c000066400000000000000000000153641355360272700216750ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "sds_private.h" /* * Variables used to track and maintain the state of the memory region reserved * for usage by the SDS framework. */ /* Pointer to the base of the SDS memory region */ static uintptr_t sds_mem_base; /* Size of the SDS memory region in bytes */ static size_t sds_mem_size; /* * Perform some non-exhaustive tests to determine whether any of the fields * within a Structure Header contain obviously invalid data. * Returns SDS_OK on success, SDS_ERR_FAIL on error. */ static int sds_struct_is_valid(uintptr_t header) { size_t struct_size = GET_SDS_HEADER_STRUCT_SIZE(header); /* Zero is not a valid identifier */ if (GET_SDS_HEADER_ID(header) == 0) return SDS_ERR_FAIL; /* Check SDS Schema version */ if (GET_SDS_HEADER_VERSION(header) == SDS_REGION_SCH_VERSION) return SDS_ERR_FAIL; /* The SDS Structure sizes have to be multiple of 8 */ if ((struct_size == 0) || ((struct_size % 8) != 0)) return SDS_ERR_FAIL; if (struct_size > sds_mem_size) return SDS_ERR_FAIL; return SDS_OK; } /* * Validate the SDS structure headers. * Returns SDS_OK on success, SDS_ERR_FAIL on error. */ static int validate_sds_struct_headers(void) { unsigned int i, structure_count; uintptr_t header; structure_count = GET_SDS_REGION_STRUCTURE_COUNT(sds_mem_base); if (structure_count == 0) return SDS_ERR_FAIL; header = sds_mem_base + SDS_REGION_DESC_SIZE; /* Iterate over structure headers and validate each one */ for (i = 0; i < structure_count; i++) { if (sds_struct_is_valid(header) != SDS_OK) { WARN("SDS: Invalid structure header detected\n"); return SDS_ERR_FAIL; } header += GET_SDS_HEADER_STRUCT_SIZE(header) + SDS_HEADER_SIZE; } return SDS_OK; } /* * Get the structure header pointer corresponding to the structure ID. * Returns SDS_OK on success, SDS_ERR_STRUCT_NOT_FOUND on error. */ static int get_struct_header(uint32_t structure_id, struct_header_t **header) { unsigned int i, structure_count; uintptr_t current_header; assert(header); structure_count = GET_SDS_REGION_STRUCTURE_COUNT(sds_mem_base); if (structure_count == 0) return SDS_ERR_STRUCT_NOT_FOUND; current_header = ((uintptr_t)sds_mem_base) + SDS_REGION_DESC_SIZE; /* Iterate over structure headers to find one with a matching ID */ for (i = 0; i < structure_count; i++) { if (GET_SDS_HEADER_ID(current_header) == structure_id) { *header = (struct_header_t *)current_header; return SDS_OK; } current_header += GET_SDS_HEADER_STRUCT_SIZE(current_header) + SDS_HEADER_SIZE; } *header = NULL; return SDS_ERR_STRUCT_NOT_FOUND; } /* * Check if a structure header corresponding to the structure ID exists. * Returns SDS_OK if structure header exists else SDS_ERR_STRUCT_NOT_FOUND * if not found. */ int sds_struct_exists(unsigned int structure_id) { struct_header_t *header = NULL; int ret; ret = get_struct_header(structure_id, &header); if (ret == SDS_OK) { assert(header); } return ret; } /* * Read from field in the structure corresponding to `structure_id`. * `fld_off` is the offset to the field in the structure and `mode` * indicates whether cache maintenance need to performed prior to the read. * The `data` is the pointer to store the read data of size specified by `size`. * Returns SDS_OK on success or corresponding error codes on failure. */ int sds_struct_read(uint32_t structure_id, unsigned int fld_off, void *data, size_t size, sds_access_mode_t mode) { int status; uintptr_t field_base; struct_header_t *header = NULL; if (!data) return SDS_ERR_INVALID_PARAMS; /* Check if a structure with this ID exists */ status = get_struct_header(structure_id, &header); if (status != SDS_OK) return status; assert(header); if (mode == SDS_ACCESS_MODE_CACHED) inv_dcache_range((uintptr_t)header, SDS_HEADER_SIZE + size); if (!IS_SDS_HEADER_VALID(header)) { WARN("SDS: Reading from un-finalized structure 0x%x\n", structure_id); return SDS_ERR_STRUCT_NOT_FINALIZED; } if ((fld_off + size) > GET_SDS_HEADER_STRUCT_SIZE(header)) return SDS_ERR_FAIL; field_base = (uintptr_t)header + SDS_HEADER_SIZE + fld_off; if (check_uptr_overflow(field_base, size - 1)) return SDS_ERR_FAIL; /* Copy the required field in the struct */ memcpy(data, (void *)field_base, size); return SDS_OK; } /* * Write to the field in the structure corresponding to `structure_id`. * `fld_off` is the offset to the field in the structure and `mode` * indicates whether cache maintenance need to performed for the write. * The `data` is the pointer to data of size specified by `size`. * Returns SDS_OK on success or corresponding error codes on failure. */ int sds_struct_write(uint32_t structure_id, unsigned int fld_off, void *data, size_t size, sds_access_mode_t mode) { int status; uintptr_t field_base; struct_header_t *header = NULL; if (!data) return SDS_ERR_INVALID_PARAMS; /* Check if a structure with this ID exists */ status = get_struct_header(structure_id, &header); if (status != SDS_OK) return status; assert(header); if (mode == SDS_ACCESS_MODE_CACHED) inv_dcache_range((uintptr_t)header, SDS_HEADER_SIZE + size); if (!IS_SDS_HEADER_VALID(header)) { WARN("SDS: Writing to un-finalized structure 0x%x\n", structure_id); return SDS_ERR_STRUCT_NOT_FINALIZED; } if ((fld_off + size) > GET_SDS_HEADER_STRUCT_SIZE(header)) return SDS_ERR_FAIL; field_base = (uintptr_t)header + SDS_HEADER_SIZE + fld_off; if (check_uptr_overflow(field_base, size - 1)) return SDS_ERR_FAIL; /* Copy the required field in the struct */ memcpy((void *)field_base, data, size); if (mode == SDS_ACCESS_MODE_CACHED) flush_dcache_range((uintptr_t)field_base, size); return SDS_OK; } /* * Initialize the SDS driver. Also verifies the SDS version and sanity of * the SDS structure headers. * Returns SDS_OK on success, SDS_ERR_FAIL on error. */ int sds_init(void) { sds_mem_base = (uintptr_t)PLAT_ARM_SDS_MEM_BASE; if (!IS_SDS_REGION_VALID(sds_mem_base)) { WARN("SDS: No valid SDS Memory Region found\n"); return SDS_ERR_FAIL; } if (GET_SDS_REGION_SCHEMA_VERSION(sds_mem_base) != SDS_REGION_SCH_VERSION) { WARN("SDS: Unsupported SDS schema version\n"); return SDS_ERR_FAIL; } sds_mem_size = GET_SDS_REGION_SIZE(sds_mem_base); if (sds_mem_size > PLAT_ARM_SDS_MEM_SIZE_MAX) { WARN("SDS: SDS Memory Region exceeds size limit\n"); return SDS_ERR_FAIL; } INFO("SDS: Detected SDS Memory Region (%zu bytes)\n", sds_mem_size); if (validate_sds_struct_headers() != SDS_OK) return SDS_ERR_FAIL; return SDS_OK; } trusted-firmware-a-2.2/drivers/arm/css/sds/sds_private.h000066400000000000000000000072041355360272700234260ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SDS_PRIVATE_H #define SDS_PRIVATE_H /* SDS Header defines */ #define SDS_HEADER_ID_SHIFT 0 #define SDS_HEADER_ID_WIDTH 16 #define SDS_HEADER_ID_MASK ((1 << SDS_HEADER_ID_WIDTH) - 1) #define SDS_HEADER_MINOR_VERSION_WIDTH 8 #define SDS_HEADER_MINOR_VERSION_SHIFT 16 #define SDS_HEADER_MAJOR_VERSION_WIDTH 8 #define MAKE_SDS_HEADER_VERSION(major, minor) \ (((((major) & 0xff) << SDS_HEADER_MINOR_VERSION_WIDTH) | ((minor) & 0xff))) #define SDS_HEADER_VERSION_MASK \ ((1 << (SDS_HEADER_MINOR_VERSION_WIDTH + SDS_HEADER_MAJOR_VERSION_WIDTH)) - 1) #define SDS_HEADER_VERSION MAKE_SDS_HEADER_VERSION(1, 0) #define SDS_HEADER_STRUCT_SIZE_WIDTH 23 #define SDS_HEADER_STRUCT_SIZE_SHIFT 1 #define SDS_HEADER_STRUCT_SIZE_MASK ((1 << SDS_HEADER_STRUCT_SIZE_WIDTH) - 1) #define SDS_HEADER_VALID_MASK 0x1 #define SDS_HEADER_VALID_SHIFT 0 #define SDS_HEADER_SIZE 0x8 /* Arbitrary, 16 bit value that indicates a valid SDS Memory Region */ #define SDS_REGION_SIGNATURE 0xAA7A #define SDS_REGION_SIGNATURE_WIDTH 16 #define SDS_REGION_SIGNATURE_SHIFT 0 #define SDS_REGION_SIGNATURE_MASK ((1 << SDS_REGION_SIGNATURE_WIDTH) - 1) #define SDS_REGION_STRUCT_COUNT_SHIFT 16 #define SDS_REGION_STRUCT_COUNT_WIDTH 8 #define SDS_REGION_STRUCT_COUNT_MASK ((1 << SDS_REGION_STRUCT_COUNT_WIDTH) - 1) #define SDS_REGION_SCH_MINOR_SHIFT 24 #define SDS_REGION_SCH_MINOR_WIDTH 4 #define SDS_REGION_SCH_MINOR_MASK ((1 << SDS_REGION_SCH_MINOR_WIDTH) - 1) #define SDS_REGION_SCH_MAJOR_SHIFT 28 #define SDS_REGION_SCH_MAJOR_WIDTH 4 #define SDS_REGION_SCH_MAJOR_MASK ((1 << SDS_REGION_SCH_MAJOR_WIDTH) - 1) #define SDS_REGION_SCH_VERSION_MASK \ ((1 << (SDS_REGION_SCH_MINOR_WIDTH + SDS_REGION_SCH_MAJOR_WIDTH)) - 1) #define MAKE_SDS_REGION_SCH_VERSION(maj, min) \ ((((maj) & SDS_REGION_SCH_MAJOR_MASK) << SDS_REGION_SCH_MINOR_WIDTH) | \ ((min) & SDS_REGION_SCH_MINOR_MASK)) #define SDS_REGION_SCH_VERSION MAKE_SDS_REGION_SCH_VERSION(1, 0) #define SDS_REGION_REGIONSIZE_OFFSET 0x4 #define SDS_REGION_DESC_SIZE 0x8 #ifndef __ASSEMBLER__ #include #include /* Header containing Shared Data Structure metadata */ typedef struct structure_header { uint32_t reg[2]; } struct_header_t; #define GET_SDS_HEADER_ID(_header) \ ((((struct_header_t *)(_header))->reg[0]) & SDS_HEADER_ID_MASK) #define GET_SDS_HEADER_VERSION(_header) \ (((((struct_header_t *)(_header))->reg[0]) >> SDS_HEADER_MINOR_VERSION_SHIFT)\ & SDS_HEADER_VERSION_MASK) #define GET_SDS_HEADER_STRUCT_SIZE(_header) \ (((((struct_header_t *)(_header))->reg[1]) >> SDS_HEADER_STRUCT_SIZE_SHIFT)\ & SDS_HEADER_STRUCT_SIZE_MASK) #define IS_SDS_HEADER_VALID(_header) \ ((((struct_header_t *)(_header))->reg[1]) & SDS_HEADER_VALID_MASK) #define GET_SDS_STRUCT_FIELD(_header, _field_offset) \ ((((uint8_t *)(_header)) + sizeof(struct_header_t)) + (_field_offset)) /* Region Descriptor describing the SDS Memory Region */ typedef struct region_descriptor { uint32_t reg[2]; } region_desc_t; #define IS_SDS_REGION_VALID(region) \ (((((region_desc_t *)(region))->reg[0]) & SDS_REGION_SIGNATURE_MASK) == SDS_REGION_SIGNATURE) #define GET_SDS_REGION_STRUCTURE_COUNT(region) \ (((((region_desc_t *)(region))->reg[0]) >> SDS_REGION_STRUCT_COUNT_SHIFT)\ & SDS_REGION_STRUCT_COUNT_MASK) #define GET_SDS_REGION_SCHEMA_VERSION(region) \ (((((region_desc_t *)(region))->reg[0]) >> SDS_REGION_SCH_MINOR_SHIFT)\ & SDS_REGION_SCH_VERSION_MASK) #define GET_SDS_REGION_SIZE(region) ((((region_desc_t *)(region))->reg[1])) #endif /* __ASSEMBLER__ */ #endif /* SDS_PRIVATE_H */ trusted-firmware-a-2.2/drivers/arm/fvp/000077500000000000000000000000001355360272700201415ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/fvp/fvp_pwrc.c000066400000000000000000000032471355360272700221410ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* * TODO: Someday there will be a generic power controller api. At the moment * each platform has its own pwrc so just exporting functions is fine. */ ARM_INSTANTIATE_LOCK; unsigned int fvp_pwrc_get_cpu_wkr(u_register_t mpidr) { return PSYSR_WK(fvp_pwrc_read_psysr(mpidr)); } unsigned int fvp_pwrc_read_psysr(u_register_t mpidr) { unsigned int rc; arm_lock_get(); mmio_write_32(PWRC_BASE + PSYSR_OFF, (unsigned int) mpidr); rc = mmio_read_32(PWRC_BASE + PSYSR_OFF); arm_lock_release(); return rc; } void fvp_pwrc_write_pponr(u_register_t mpidr) { arm_lock_get(); mmio_write_32(PWRC_BASE + PPONR_OFF, (unsigned int) mpidr); arm_lock_release(); } void fvp_pwrc_write_ppoffr(u_register_t mpidr) { arm_lock_get(); mmio_write_32(PWRC_BASE + PPOFFR_OFF, (unsigned int) mpidr); arm_lock_release(); } void fvp_pwrc_set_wen(u_register_t mpidr) { arm_lock_get(); mmio_write_32(PWRC_BASE + PWKUPR_OFF, (unsigned int) (PWKUPR_WEN | mpidr)); arm_lock_release(); } void fvp_pwrc_clr_wen(u_register_t mpidr) { arm_lock_get(); mmio_write_32(PWRC_BASE + PWKUPR_OFF, (unsigned int) mpidr); arm_lock_release(); } void fvp_pwrc_write_pcoffr(u_register_t mpidr) { arm_lock_get(); mmio_write_32(PWRC_BASE + PCOFFR_OFF, (unsigned int) mpidr); arm_lock_release(); } /* Nothing else to do here apart from initializing the lock */ void __init plat_arm_pwrc_setup(void) { arm_lock_init(); } trusted-firmware-a-2.2/drivers/arm/gic/000077500000000000000000000000001355360272700201105ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/gic/common/000077500000000000000000000000001355360272700214005ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/gic/common/gic_common.c000066400000000000000000000225351355360272700236650ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "gic_common_private.h" /******************************************************************************* * GIC Distributor interface accessors for reading entire registers ******************************************************************************/ /* * Accessor to read the GIC Distributor IGROUPR corresponding to the interrupt * `id`, 32 interrupt ids at a time. */ unsigned int gicd_read_igroupr(uintptr_t base, unsigned int id) { unsigned int n = id >> IGROUPR_SHIFT; return mmio_read_32(base + GICD_IGROUPR + (n << 2)); } /* * Accessor to read the GIC Distributor ISENABLER corresponding to the * interrupt `id`, 32 interrupt ids at a time. */ unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id) { unsigned int n = id >> ISENABLER_SHIFT; return mmio_read_32(base + GICD_ISENABLER + (n << 2)); } /* * Accessor to read the GIC Distributor ICENABLER corresponding to the * interrupt `id`, 32 interrupt IDs at a time. */ unsigned int gicd_read_icenabler(uintptr_t base, unsigned int id) { unsigned int n = id >> ICENABLER_SHIFT; return mmio_read_32(base + GICD_ICENABLER + (n << 2)); } /* * Accessor to read the GIC Distributor ISPENDR corresponding to the * interrupt `id`, 32 interrupt IDs at a time. */ unsigned int gicd_read_ispendr(uintptr_t base, unsigned int id) { unsigned int n = id >> ISPENDR_SHIFT; return mmio_read_32(base + GICD_ISPENDR + (n << 2)); } /* * Accessor to read the GIC Distributor ICPENDR corresponding to the * interrupt `id`, 32 interrupt IDs at a time. */ unsigned int gicd_read_icpendr(uintptr_t base, unsigned int id) { unsigned int n = id >> ICPENDR_SHIFT; return mmio_read_32(base + GICD_ICPENDR + (n << 2)); } /* * Accessor to read the GIC Distributor ISACTIVER corresponding to the * interrupt `id`, 32 interrupt IDs at a time. */ unsigned int gicd_read_isactiver(uintptr_t base, unsigned int id) { unsigned int n = id >> ISACTIVER_SHIFT; return mmio_read_32(base + GICD_ISACTIVER + (n << 2)); } /* * Accessor to read the GIC Distributor ICACTIVER corresponding to the * interrupt `id`, 32 interrupt IDs at a time. */ unsigned int gicd_read_icactiver(uintptr_t base, unsigned int id) { unsigned int n = id >> ICACTIVER_SHIFT; return mmio_read_32(base + GICD_ICACTIVER + (n << 2)); } /* * Accessor to read the GIC Distributor IPRIORITYR corresponding to the * interrupt `id`, 4 interrupt IDs at a time. */ unsigned int gicd_read_ipriorityr(uintptr_t base, unsigned int id) { unsigned int n = id >> IPRIORITYR_SHIFT; return mmio_read_32(base + GICD_IPRIORITYR + (n << 2)); } /* * Accessor to read the GIC Distributor ICGFR corresponding to the * interrupt `id`, 16 interrupt IDs at a time. */ unsigned int gicd_read_icfgr(uintptr_t base, unsigned int id) { unsigned int n = id >> ICFGR_SHIFT; return mmio_read_32(base + GICD_ICFGR + (n << 2)); } /* * Accessor to read the GIC Distributor NSACR corresponding to the * interrupt `id`, 16 interrupt IDs at a time. */ unsigned int gicd_read_nsacr(uintptr_t base, unsigned int id) { unsigned int n = id >> NSACR_SHIFT; return mmio_read_32(base + GICD_NSACR + (n << 2)); } /******************************************************************************* * GIC Distributor interface accessors for writing entire registers ******************************************************************************/ /* * Accessor to write the GIC Distributor IGROUPR corresponding to the * interrupt `id`, 32 interrupt IDs at a time. */ void gicd_write_igroupr(uintptr_t base, unsigned int id, unsigned int val) { unsigned int n = id >> IGROUPR_SHIFT; mmio_write_32(base + GICD_IGROUPR + (n << 2), val); } /* * Accessor to write the GIC Distributor ISENABLER corresponding to the * interrupt `id`, 32 interrupt IDs at a time. */ void gicd_write_isenabler(uintptr_t base, unsigned int id, unsigned int val) { unsigned int n = id >> ISENABLER_SHIFT; mmio_write_32(base + GICD_ISENABLER + (n << 2), val); } /* * Accessor to write the GIC Distributor ICENABLER corresponding to the * interrupt `id`, 32 interrupt IDs at a time. */ void gicd_write_icenabler(uintptr_t base, unsigned int id, unsigned int val) { unsigned int n = id >> ICENABLER_SHIFT; mmio_write_32(base + GICD_ICENABLER + (n << 2), val); } /* * Accessor to write the GIC Distributor ISPENDR corresponding to the * interrupt `id`, 32 interrupt IDs at a time. */ void gicd_write_ispendr(uintptr_t base, unsigned int id, unsigned int val) { unsigned int n = id >> ISPENDR_SHIFT; mmio_write_32(base + GICD_ISPENDR + (n << 2), val); } /* * Accessor to write the GIC Distributor ICPENDR corresponding to the * interrupt `id`, 32 interrupt IDs at a time. */ void gicd_write_icpendr(uintptr_t base, unsigned int id, unsigned int val) { unsigned int n = id >> ICPENDR_SHIFT; mmio_write_32(base + GICD_ICPENDR + (n << 2), val); } /* * Accessor to write the GIC Distributor ISACTIVER corresponding to the * interrupt `id`, 32 interrupt IDs at a time. */ void gicd_write_isactiver(uintptr_t base, unsigned int id, unsigned int val) { unsigned int n = id >> ISACTIVER_SHIFT; mmio_write_32(base + GICD_ISACTIVER + (n << 2), val); } /* * Accessor to write the GIC Distributor ICACTIVER corresponding to the * interrupt `id`, 32 interrupt IDs at a time. */ void gicd_write_icactiver(uintptr_t base, unsigned int id, unsigned int val) { unsigned int n = id >> ICACTIVER_SHIFT; mmio_write_32(base + GICD_ICACTIVER + (n << 2), val); } /* * Accessor to write the GIC Distributor IPRIORITYR corresponding to the * interrupt `id`, 4 interrupt IDs at a time. */ void gicd_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val) { unsigned int n = id >> IPRIORITYR_SHIFT; mmio_write_32(base + GICD_IPRIORITYR + (n << 2), val); } /* * Accessor to write the GIC Distributor ICFGR corresponding to the * interrupt `id`, 16 interrupt IDs at a time. */ void gicd_write_icfgr(uintptr_t base, unsigned int id, unsigned int val) { unsigned int n = id >> ICFGR_SHIFT; mmio_write_32(base + GICD_ICFGR + (n << 2), val); } /* * Accessor to write the GIC Distributor NSACR corresponding to the * interrupt `id`, 16 interrupt IDs at a time. */ void gicd_write_nsacr(uintptr_t base, unsigned int id, unsigned int val) { unsigned int n = id >> NSACR_SHIFT; mmio_write_32(base + GICD_NSACR + (n << 2), val); } /******************************************************************************* * GIC Distributor functions for accessing the GIC registers * corresponding to a single interrupt ID. These functions use bitwise * operations or appropriate register accesses to modify or return * the bit-field corresponding the single interrupt ID. ******************************************************************************/ unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U); unsigned int reg_val = gicd_read_igroupr(base, id); return (reg_val >> bit_num) & 0x1U; } void gicd_set_igroupr(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U); unsigned int reg_val = gicd_read_igroupr(base, id); gicd_write_igroupr(base, id, reg_val | (1U << bit_num)); } void gicd_clr_igroupr(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U); unsigned int reg_val = gicd_read_igroupr(base, id); gicd_write_igroupr(base, id, reg_val & ~(1U << bit_num)); } void gicd_set_isenabler(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << ISENABLER_SHIFT) - 1U); gicd_write_isenabler(base, id, (1U << bit_num)); } void gicd_set_icenabler(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << ICENABLER_SHIFT) - 1U); gicd_write_icenabler(base, id, (1U << bit_num)); } void gicd_set_ispendr(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << ISPENDR_SHIFT) - 1U); gicd_write_ispendr(base, id, (1U << bit_num)); } void gicd_set_icpendr(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << ICPENDR_SHIFT) - 1U); gicd_write_icpendr(base, id, (1U << bit_num)); } unsigned int gicd_get_isactiver(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << ISACTIVER_SHIFT) - 1U); unsigned int reg_val = gicd_read_isactiver(base, id); return (reg_val >> bit_num) & 0x1U; } void gicd_set_isactiver(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << ISACTIVER_SHIFT) - 1U); gicd_write_isactiver(base, id, (1U << bit_num)); } void gicd_set_icactiver(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << ICACTIVER_SHIFT) - 1U); gicd_write_icactiver(base, id, (1U << bit_num)); } void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri) { uint8_t val = pri & GIC_PRI_MASK; mmio_write_8(base + GICD_IPRIORITYR + id, val); } void gicd_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg) { /* Interrupt configuration is a 2-bit field */ unsigned int bit_num = id & ((1U << ICFGR_SHIFT) - 1U); unsigned int bit_shift = bit_num << 1; uint32_t reg_val = gicd_read_icfgr(base, id); /* Clear the field, and insert required configuration */ reg_val &= ~(GIC_CFG_MASK << bit_shift); reg_val |= ((cfg & GIC_CFG_MASK) << bit_shift); gicd_write_icfgr(base, id, reg_val); } trusted-firmware-a-2.2/drivers/arm/gic/common/gic_common_private.h000066400000000000000000000104271355360272700254210ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef GIC_COMMON_PRIVATE_H #define GIC_COMMON_PRIVATE_H #include #include #include /******************************************************************************* * GIC Distributor interface register accessors that are common to GICv3 & GICv2 ******************************************************************************/ static inline unsigned int gicd_read_ctlr(uintptr_t base) { return mmio_read_32(base + GICD_CTLR); } static inline unsigned int gicd_read_typer(uintptr_t base) { return mmio_read_32(base + GICD_TYPER); } static inline unsigned int gicd_read_iidr(uintptr_t base) { return mmio_read_32(base + GICD_IIDR); } static inline void gicd_write_ctlr(uintptr_t base, unsigned int val) { mmio_write_32(base + GICD_CTLR, val); } /******************************************************************************* * GIC Distributor function prototypes for accessing entire registers. * Note: The raw register values correspond to multiple interrupt IDs and * the number of interrupt IDs involved depends on the register accessed. ******************************************************************************/ unsigned int gicd_read_igroupr(uintptr_t base, unsigned int id); unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id); unsigned int gicd_read_icenabler(uintptr_t base, unsigned int id); unsigned int gicd_read_ispendr(uintptr_t base, unsigned int id); unsigned int gicd_read_icpendr(uintptr_t base, unsigned int id); unsigned int gicd_read_isactiver(uintptr_t base, unsigned int id); unsigned int gicd_read_icactiver(uintptr_t base, unsigned int id); unsigned int gicd_read_ipriorityr(uintptr_t base, unsigned int id); unsigned int gicd_read_icfgr(uintptr_t base, unsigned int id); unsigned int gicd_read_nsacr(uintptr_t base, unsigned int id); unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id); unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id); unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id); void gicd_write_igroupr(uintptr_t base, unsigned int id, unsigned int val); void gicd_write_isenabler(uintptr_t base, unsigned int id, unsigned int val); void gicd_write_icenabler(uintptr_t base, unsigned int id, unsigned int val); void gicd_write_ispendr(uintptr_t base, unsigned int id, unsigned int val); void gicd_write_icpendr(uintptr_t base, unsigned int id, unsigned int val); void gicd_write_isactiver(uintptr_t base, unsigned int id, unsigned int val); void gicd_write_icactiver(uintptr_t base, unsigned int id, unsigned int val); void gicd_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val); void gicd_write_icfgr(uintptr_t base, unsigned int id, unsigned int val); void gicd_write_nsacr(uintptr_t base, unsigned int id, unsigned int val); void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val); void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val); void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val); /******************************************************************************* * GIC Distributor function prototypes for accessing the GIC registers * corresponding to a single interrupt ID. These functions use bitwise * operations or appropriate register accesses to modify or return * the bit-field corresponding the single interrupt ID. ******************************************************************************/ unsigned int gicd_get_igroupr(uintptr_t base, unsigned int id); void gicd_set_igroupr(uintptr_t base, unsigned int id); void gicd_clr_igroupr(uintptr_t base, unsigned int id); void gicd_set_isenabler(uintptr_t base, unsigned int id); void gicd_set_icenabler(uintptr_t base, unsigned int id); void gicd_set_ispendr(uintptr_t base, unsigned int id); void gicd_set_icpendr(uintptr_t base, unsigned int id); unsigned int gicd_get_isactiver(uintptr_t base, unsigned int id); void gicd_set_isactiver(uintptr_t base, unsigned int id); void gicd_set_icactiver(uintptr_t base, unsigned int id); void gicd_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri); void gicd_set_icfgr(uintptr_t base, unsigned int id, unsigned int cfg); #endif /* GIC_COMMON_PRIVATE_H */ trusted-firmware-a-2.2/drivers/arm/gic/v2/000077500000000000000000000000001355360272700204375ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/gic/v2/gicv2_helpers.c000066400000000000000000000152721355360272700233460ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "../common/gic_common_private.h" #include "gicv2_private.h" /* * Accessor to read the GIC Distributor ITARGETSR corresponding to the * interrupt `id`, 4 interrupt IDs at a time. */ unsigned int gicd_read_itargetsr(uintptr_t base, unsigned int id) { unsigned n = id >> ITARGETSR_SHIFT; return mmio_read_32(base + GICD_ITARGETSR + (n << 2)); } /* * Accessor to read the GIC Distributor CPENDSGIR corresponding to the * interrupt `id`, 4 interrupt IDs at a time. */ unsigned int gicd_read_cpendsgir(uintptr_t base, unsigned int id) { unsigned n = id >> CPENDSGIR_SHIFT; return mmio_read_32(base + GICD_CPENDSGIR + (n << 2)); } /* * Accessor to read the GIC Distributor SPENDSGIR corresponding to the * interrupt `id`, 4 interrupt IDs at a time. */ unsigned int gicd_read_spendsgir(uintptr_t base, unsigned int id) { unsigned n = id >> SPENDSGIR_SHIFT; return mmio_read_32(base + GICD_SPENDSGIR + (n << 2)); } /* * Accessor to write the GIC Distributor ITARGETSR corresponding to the * interrupt `id`, 4 interrupt IDs at a time. */ void gicd_write_itargetsr(uintptr_t base, unsigned int id, unsigned int val) { unsigned n = id >> ITARGETSR_SHIFT; mmio_write_32(base + GICD_ITARGETSR + (n << 2), val); } /* * Accessor to write the GIC Distributor CPENDSGIR corresponding to the * interrupt `id`, 4 interrupt IDs at a time. */ void gicd_write_cpendsgir(uintptr_t base, unsigned int id, unsigned int val) { unsigned n = id >> CPENDSGIR_SHIFT; mmio_write_32(base + GICD_CPENDSGIR + (n << 2), val); } /* * Accessor to write the GIC Distributor SPENDSGIR corresponding to the * interrupt `id`, 4 interrupt IDs at a time. */ void gicd_write_spendsgir(uintptr_t base, unsigned int id, unsigned int val) { unsigned n = id >> SPENDSGIR_SHIFT; mmio_write_32(base + GICD_SPENDSGIR + (n << 2), val); } /******************************************************************************* * Get the current CPU bit mask from GICD_ITARGETSR0 ******************************************************************************/ unsigned int gicv2_get_cpuif_id(uintptr_t base) { unsigned int val; val = gicd_read_itargetsr(base, 0); return val & GIC_TARGET_CPU_MASK; } /******************************************************************************* * Helper function to configure the default attributes of SPIs. ******************************************************************************/ void gicv2_spis_configure_defaults(uintptr_t gicd_base) { unsigned int index, num_ints; num_ints = gicd_read_typer(gicd_base); num_ints &= TYPER_IT_LINES_NO_MASK; num_ints = (num_ints + 1U) << 5; /* * Treat all SPIs as G1NS by default. The number of interrupts is * calculated as 32 * (IT_LINES + 1). We do 32 at a time. */ for (index = MIN_SPI_ID; index < num_ints; index += 32U) gicd_write_igroupr(gicd_base, index, ~0U); /* Setup the default SPI priorities doing four at a time */ for (index = MIN_SPI_ID; index < num_ints; index += 4U) gicd_write_ipriorityr(gicd_base, index, GICD_IPRIORITYR_DEF_VAL); /* Treat all SPIs as level triggered by default, 16 at a time */ for (index = MIN_SPI_ID; index < num_ints; index += 16U) gicd_write_icfgr(gicd_base, index, 0U); } /******************************************************************************* * Helper function to configure properties of secure G0 SPIs. ******************************************************************************/ void gicv2_secure_spis_configure_props(uintptr_t gicd_base, const interrupt_prop_t *interrupt_props, unsigned int interrupt_props_num) { unsigned int i; const interrupt_prop_t *prop_desc; /* Make sure there's a valid property array */ if (interrupt_props_num != 0U) assert(interrupt_props != NULL); for (i = 0; i < interrupt_props_num; i++) { prop_desc = &interrupt_props[i]; if (prop_desc->intr_num < MIN_SPI_ID) continue; /* Configure this interrupt as a secure interrupt */ assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); gicd_clr_igroupr(gicd_base, prop_desc->intr_num); /* Set the priority of this interrupt */ gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, prop_desc->intr_pri); /* Target the secure interrupts to primary CPU */ gicd_set_itargetsr(gicd_base, prop_desc->intr_num, gicv2_get_cpuif_id(gicd_base)); /* Set interrupt configuration */ gicd_set_icfgr(gicd_base, prop_desc->intr_num, prop_desc->intr_cfg); /* Enable this interrupt */ gicd_set_isenabler(gicd_base, prop_desc->intr_num); } } /******************************************************************************* * Helper function to configure properties of secure G0 SGIs and PPIs. ******************************************************************************/ void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base, const interrupt_prop_t *interrupt_props, unsigned int interrupt_props_num) { unsigned int i; uint32_t sec_ppi_sgi_mask = 0; const interrupt_prop_t *prop_desc; /* Make sure there's a valid property array */ if (interrupt_props_num != 0U) assert(interrupt_props != NULL); /* * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a * more scalable approach as it avoids clearing the enable bits in the * GICD_CTLR. */ gicd_write_icenabler(gicd_base, 0U, ~0U); /* Setup the default PPI/SGI priorities doing four at a time */ for (i = 0U; i < MIN_SPI_ID; i += 4U) gicd_write_ipriorityr(gicd_base, i, GICD_IPRIORITYR_DEF_VAL); for (i = 0U; i < interrupt_props_num; i++) { prop_desc = &interrupt_props[i]; if (prop_desc->intr_num >= MIN_SPI_ID) continue; /* Configure this interrupt as a secure interrupt */ assert(prop_desc->intr_grp == GICV2_INTR_GROUP0); /* * Set interrupt configuration for PPIs. Configuration for SGIs * are ignored. */ if ((prop_desc->intr_num >= MIN_PPI_ID) && (prop_desc->intr_num < MIN_SPI_ID)) { gicd_set_icfgr(gicd_base, prop_desc->intr_num, prop_desc->intr_cfg); } /* We have an SGI or a PPI. They are Group0 at reset */ sec_ppi_sgi_mask |= (1u << prop_desc->intr_num); /* Set the priority of this interrupt */ gicd_set_ipriorityr(gicd_base, prop_desc->intr_num, prop_desc->intr_pri); } /* * Invert the bitmask to create a mask for non-secure PPIs and SGIs. * Program the GICD_IGROUPR0 with this bit mask. */ gicd_write_igroupr(gicd_base, 0, ~sec_ppi_sgi_mask); /* Enable the Group 0 SGIs and PPIs */ gicd_write_isenabler(gicd_base, 0, sec_ppi_sgi_mask); } trusted-firmware-a-2.2/drivers/arm/gic/v2/gicv2_main.c000066400000000000000000000453571355360272700226370ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "../common/gic_common_private.h" #include "gicv2_private.h" static const gicv2_driver_data_t *driver_data; /* * Spinlock to guard registers needing read-modify-write. APIs protected by this * spinlock are used either at boot time (when only a single CPU is active), or * when the system is fully coherent. */ static spinlock_t gic_lock; /******************************************************************************* * Enable secure interrupts and use FIQs to route them. Disable legacy bypass * and set the priority mask register to allow all interrupts to trickle in. ******************************************************************************/ void gicv2_cpuif_enable(void) { unsigned int val; assert(driver_data != NULL); assert(driver_data->gicc_base != 0U); /* * Enable the Group 0 interrupts, FIQEn and disable Group 0/1 * bypass. */ val = CTLR_ENABLE_G0_BIT | FIQ_EN_BIT | FIQ_BYP_DIS_GRP0; val |= IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP1 | IRQ_BYP_DIS_GRP1; /* Program the idle priority in the PMR */ gicc_write_pmr(driver_data->gicc_base, GIC_PRI_MASK); gicc_write_ctlr(driver_data->gicc_base, val); } /******************************************************************************* * Place the cpu interface in a state where it can never make a cpu exit wfi as * as result of an asserted interrupt. This is critical for powering down a cpu ******************************************************************************/ void gicv2_cpuif_disable(void) { unsigned int val; assert(driver_data != NULL); assert(driver_data->gicc_base != 0U); /* Disable secure, non-secure interrupts and disable their bypass */ val = gicc_read_ctlr(driver_data->gicc_base); val &= ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT); val |= FIQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP0; val |= IRQ_BYP_DIS_GRP0 | IRQ_BYP_DIS_GRP1; gicc_write_ctlr(driver_data->gicc_base, val); } /******************************************************************************* * Per cpu gic distributor setup which will be done by all cpus after a cold * boot/hotplug. This marks out the secure SPIs and PPIs & enables them. ******************************************************************************/ void gicv2_pcpu_distif_init(void) { unsigned int ctlr; assert(driver_data != NULL); assert(driver_data->gicd_base != 0U); gicv2_secure_ppi_sgi_setup_props(driver_data->gicd_base, driver_data->interrupt_props, driver_data->interrupt_props_num); /* Enable G0 interrupts if not already */ ctlr = gicd_read_ctlr(driver_data->gicd_base); if ((ctlr & CTLR_ENABLE_G0_BIT) == 0U) { gicd_write_ctlr(driver_data->gicd_base, ctlr | CTLR_ENABLE_G0_BIT); } } /******************************************************************************* * Global gic distributor init which will be done by the primary cpu after a * cold boot. It marks out the secure SPIs, PPIs & SGIs and enables them. It * then enables the secure GIC distributor interface. ******************************************************************************/ void gicv2_distif_init(void) { unsigned int ctlr; assert(driver_data != NULL); assert(driver_data->gicd_base != 0U); /* Disable the distributor before going further */ ctlr = gicd_read_ctlr(driver_data->gicd_base); gicd_write_ctlr(driver_data->gicd_base, ctlr & ~(CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1_BIT)); /* Set the default attribute of all SPIs */ gicv2_spis_configure_defaults(driver_data->gicd_base); gicv2_secure_spis_configure_props(driver_data->gicd_base, driver_data->interrupt_props, driver_data->interrupt_props_num); /* Re-enable the secure SPIs now that they have been configured */ gicd_write_ctlr(driver_data->gicd_base, ctlr | CTLR_ENABLE_G0_BIT); } /******************************************************************************* * Initialize the ARM GICv2 driver with the provided platform inputs ******************************************************************************/ void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data) { unsigned int gic_version; assert(plat_driver_data != NULL); assert(plat_driver_data->gicd_base != 0U); assert(plat_driver_data->gicc_base != 0U); assert(plat_driver_data->interrupt_props_num > 0 ? plat_driver_data->interrupt_props != NULL : 1); /* Ensure that this is a GICv2 system */ gic_version = gicd_read_pidr2(plat_driver_data->gicd_base); gic_version = (gic_version >> PIDR2_ARCH_REV_SHIFT) & PIDR2_ARCH_REV_MASK; /* * GICv1 with security extension complies with trusted firmware * GICv2 driver as far as virtualization and few tricky power * features are not used. GICv2 features that are not supported * by GICv1 with Security Extensions are: * - virtual interrupt support. * - wake up events. * - writeable GIC state register (for power sequences) * - interrupt priority drop. * - interrupt signal bypass. */ assert((gic_version == ARCH_REV_GICV2) || (gic_version == ARCH_REV_GICV1)); driver_data = plat_driver_data; /* * The GIC driver data is initialized by the primary CPU with caches * enabled. When the secondary CPU boots up, it initializes the * GICC/GICR interface with the caches disabled. Hence flush the * driver_data to ensure coherency. This is not required if the * platform has HW_ASSISTED_COHERENCY or WARMBOOT_ENABLE_DCACHE_EARLY * enabled. */ #if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY) flush_dcache_range((uintptr_t) &driver_data, sizeof(driver_data)); flush_dcache_range((uintptr_t) driver_data, sizeof(*driver_data)); #endif INFO("ARM GICv2 driver initialized\n"); } /****************************************************************************** * This function returns whether FIQ is enabled in the GIC CPU interface. *****************************************************************************/ unsigned int gicv2_is_fiq_enabled(void) { unsigned int gicc_ctlr; assert(driver_data != NULL); assert(driver_data->gicc_base != 0U); gicc_ctlr = gicc_read_ctlr(driver_data->gicc_base); return (gicc_ctlr >> FIQ_EN_SHIFT) & 0x1U; } /******************************************************************************* * This function returns the type of the highest priority pending interrupt at * the GIC cpu interface. The return values can be one of the following : * PENDING_G1_INTID : The interrupt type is non secure Group 1. * 0 - 1019 : The interrupt type is secure Group 0. * GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with * sufficient priority to be signaled ******************************************************************************/ unsigned int gicv2_get_pending_interrupt_type(void) { assert(driver_data != NULL); assert(driver_data->gicc_base != 0U); return gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK; } /******************************************************************************* * This function returns the id of the highest priority pending interrupt at * the GIC cpu interface. GIC_SPURIOUS_INTERRUPT is returned when there is no * interrupt pending. ******************************************************************************/ unsigned int gicv2_get_pending_interrupt_id(void) { unsigned int id; assert(driver_data != NULL); assert(driver_data->gicc_base != 0U); id = gicc_read_hppir(driver_data->gicc_base) & INT_ID_MASK; /* * Find out which non-secure interrupt it is under the assumption that * the GICC_CTLR.AckCtl bit is 0. */ if (id == PENDING_G1_INTID) id = gicc_read_ahppir(driver_data->gicc_base) & INT_ID_MASK; return id; } /******************************************************************************* * This functions reads the GIC cpu interface Interrupt Acknowledge register * to start handling the pending secure 0 interrupt. It returns the * contents of the IAR. ******************************************************************************/ unsigned int gicv2_acknowledge_interrupt(void) { assert(driver_data != NULL); assert(driver_data->gicc_base != 0U); return gicc_read_IAR(driver_data->gicc_base); } /******************************************************************************* * This functions writes the GIC cpu interface End Of Interrupt register with * the passed value to finish handling the active secure group 0 interrupt. ******************************************************************************/ void gicv2_end_of_interrupt(unsigned int id) { assert(driver_data != NULL); assert(driver_data->gicc_base != 0U); gicc_write_EOIR(driver_data->gicc_base, id); } /******************************************************************************* * This function returns the type of the interrupt id depending upon the group * this interrupt has been configured under by the interrupt controller i.e. * group0 secure or group1 non secure. It returns zero for Group 0 secure and * one for Group 1 non secure interrupt. ******************************************************************************/ unsigned int gicv2_get_interrupt_group(unsigned int id) { assert(driver_data != NULL); assert(driver_data->gicd_base != 0U); return gicd_get_igroupr(driver_data->gicd_base, id); } /******************************************************************************* * This function returns the priority of the interrupt the processor is * currently servicing. ******************************************************************************/ unsigned int gicv2_get_running_priority(void) { assert(driver_data != NULL); assert(driver_data->gicc_base != 0U); return gicc_read_rpr(driver_data->gicc_base); } /******************************************************************************* * This function sets the GICv2 target mask pattern for the current PE. The PE * target mask is used to translate linear PE index (returned by platform core * position) to a bit mask used when targeting interrupts to a PE (for example * when raising SGIs and routing SPIs). ******************************************************************************/ void gicv2_set_pe_target_mask(unsigned int proc_num) { assert(driver_data != NULL); assert(driver_data->gicd_base != 0U); assert(driver_data->target_masks != NULL); assert((unsigned int)proc_num < GICV2_MAX_TARGET_PE); assert((unsigned int)proc_num < driver_data->target_masks_num); /* Return if the target mask is already populated */ if (driver_data->target_masks[proc_num] != 0U) return; /* * Update target register corresponding to this CPU and flush for it to * be visible to other CPUs. */ if (driver_data->target_masks[proc_num] == 0U) { driver_data->target_masks[proc_num] = gicv2_get_cpuif_id(driver_data->gicd_base); #if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY) /* * PEs only update their own masks. Primary updates it with * caches on. But because secondaries does it with caches off, * all updates go to memory directly, and there's no danger of * secondaries overwriting each others' mask, despite * target_masks[] not being cache line aligned. */ flush_dcache_range((uintptr_t) &driver_data->target_masks[proc_num], sizeof(driver_data->target_masks[proc_num])); #endif } } /******************************************************************************* * This function returns the active status of the interrupt (either because the * state is active, or active and pending). ******************************************************************************/ unsigned int gicv2_get_interrupt_active(unsigned int id) { assert(driver_data != NULL); assert(driver_data->gicd_base != 0U); assert(id <= MAX_SPI_ID); return gicd_get_isactiver(driver_data->gicd_base, id); } /******************************************************************************* * This function enables the interrupt identified by id. ******************************************************************************/ void gicv2_enable_interrupt(unsigned int id) { assert(driver_data != NULL); assert(driver_data->gicd_base != 0U); assert(id <= MAX_SPI_ID); /* * Ensure that any shared variable updates depending on out of band * interrupt trigger are observed before enabling interrupt. */ dsbishst(); gicd_set_isenabler(driver_data->gicd_base, id); } /******************************************************************************* * This function disables the interrupt identified by id. ******************************************************************************/ void gicv2_disable_interrupt(unsigned int id) { assert(driver_data != NULL); assert(driver_data->gicd_base != 0U); assert(id <= MAX_SPI_ID); /* * Disable interrupt, and ensure that any shared variable updates * depending on out of band interrupt trigger are observed afterwards. */ gicd_set_icenabler(driver_data->gicd_base, id); dsbishst(); } /******************************************************************************* * This function sets the interrupt priority as supplied for the given interrupt * id. ******************************************************************************/ void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority) { assert(driver_data != NULL); assert(driver_data->gicd_base != 0U); assert(id <= MAX_SPI_ID); gicd_set_ipriorityr(driver_data->gicd_base, id, priority); } /******************************************************************************* * This function assigns group for the interrupt identified by id. The group can * be any of GICV2_INTR_GROUP* ******************************************************************************/ void gicv2_set_interrupt_type(unsigned int id, unsigned int type) { assert(driver_data != NULL); assert(driver_data->gicd_base != 0U); assert(id <= MAX_SPI_ID); /* Serialize read-modify-write to Distributor registers */ spin_lock(&gic_lock); switch (type) { case GICV2_INTR_GROUP1: gicd_set_igroupr(driver_data->gicd_base, id); break; case GICV2_INTR_GROUP0: gicd_clr_igroupr(driver_data->gicd_base, id); break; default: assert(false); break; } spin_unlock(&gic_lock); } /******************************************************************************* * This function raises the specified SGI to requested targets. * * The proc_num parameter must be the linear index of the target PE in the * system. ******************************************************************************/ void gicv2_raise_sgi(int sgi_num, int proc_num) { unsigned int sgir_val, target; assert(driver_data != NULL); assert((unsigned int)proc_num < GICV2_MAX_TARGET_PE); assert(driver_data->gicd_base != 0U); /* * Target masks array must have been supplied, and the core position * should be valid. */ assert(driver_data->target_masks != NULL); assert((unsigned int)proc_num < driver_data->target_masks_num); /* Don't raise SGI if the mask hasn't been populated */ target = driver_data->target_masks[proc_num]; assert(target != 0U); sgir_val = GICV2_SGIR_VALUE(SGIR_TGT_SPECIFIC, target, sgi_num); /* * Ensure that any shared variable updates depending on out of band * interrupt trigger are observed before raising SGI. */ dsbishst(); gicd_write_sgir(driver_data->gicd_base, sgir_val); } /******************************************************************************* * This function sets the interrupt routing for the given SPI interrupt id. * The interrupt routing is specified in routing mode. The proc_num parameter is * linear index of the PE to target SPI. When proc_num < 0, the SPI may target * all PEs. ******************************************************************************/ void gicv2_set_spi_routing(unsigned int id, int proc_num) { unsigned int target; assert(driver_data != NULL); assert(driver_data->gicd_base != 0U); assert((id >= MIN_SPI_ID) && (id <= MAX_SPI_ID)); /* * Target masks array must have been supplied, and the core position * should be valid. */ assert(driver_data->target_masks != NULL); assert((unsigned int)proc_num < GICV2_MAX_TARGET_PE); assert((unsigned int)proc_num < driver_data->target_masks_num); if (proc_num < 0) { /* Target all PEs */ target = GIC_TARGET_CPU_MASK; } else { /* Don't route interrupt if the mask hasn't been populated */ target = driver_data->target_masks[proc_num]; assert(target != 0U); } gicd_set_itargetsr(driver_data->gicd_base, id, target); } /******************************************************************************* * This function clears the pending status of an interrupt identified by id. ******************************************************************************/ void gicv2_clear_interrupt_pending(unsigned int id) { assert(driver_data != NULL); assert(driver_data->gicd_base != 0U); /* SGIs can't be cleared pending */ assert(id >= MIN_PPI_ID); /* * Clear pending interrupt, and ensure that any shared variable updates * depending on out of band interrupt trigger are observed afterwards. */ gicd_set_icpendr(driver_data->gicd_base, id); dsbishst(); } /******************************************************************************* * This function sets the pending status of an interrupt identified by id. ******************************************************************************/ void gicv2_set_interrupt_pending(unsigned int id) { assert(driver_data != NULL); assert(driver_data->gicd_base != 0U); /* SGIs can't be cleared pending */ assert(id >= MIN_PPI_ID); /* * Ensure that any shared variable updates depending on out of band * interrupt trigger are observed before setting interrupt pending. */ dsbishst(); gicd_set_ispendr(driver_data->gicd_base, id); } /******************************************************************************* * This function sets the PMR register with the supplied value. Returns the * original PMR. ******************************************************************************/ unsigned int gicv2_set_pmr(unsigned int mask) { unsigned int old_mask; assert(driver_data != NULL); assert(driver_data->gicc_base != 0U); old_mask = gicc_read_pmr(driver_data->gicc_base); /* * Order memory updates w.r.t. PMR write, and ensure they're visible * before potential out of band interrupt trigger because of PMR update. */ dmbishst(); gicc_write_pmr(driver_data->gicc_base, mask); dsbishst(); return old_mask; } /******************************************************************************* * This function updates single interrupt configuration to be level/edge * triggered ******************************************************************************/ void gicv2_interrupt_set_cfg(unsigned int id, unsigned int cfg) { gicd_set_icfgr(driver_data->gicd_base, id, cfg); } trusted-firmware-a-2.2/drivers/arm/gic/v2/gicv2_private.h000066400000000000000000000100431355360272700233520ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef GICV2_PRIVATE_H #define GICV2_PRIVATE_H #include #include #include /******************************************************************************* * Private function prototypes ******************************************************************************/ void gicv2_spis_configure_defaults(uintptr_t gicd_base); void gicv2_secure_spis_configure_props(uintptr_t gicd_base, const interrupt_prop_t *interrupt_props, unsigned int interrupt_props_num); void gicv2_secure_ppi_sgi_setup_props(uintptr_t gicd_base, const interrupt_prop_t *interrupt_props, unsigned int interrupt_props_num); unsigned int gicv2_get_cpuif_id(uintptr_t base); /******************************************************************************* * GIC Distributor interface accessors for reading entire registers ******************************************************************************/ static inline unsigned int gicd_read_pidr2(uintptr_t base) { return mmio_read_32(base + GICD_PIDR2_GICV2); } /******************************************************************************* * GIC Distributor interface accessors for writing entire registers ******************************************************************************/ static inline unsigned int gicd_get_itargetsr(uintptr_t base, unsigned int id) { return mmio_read_8(base + GICD_ITARGETSR + id); } static inline void gicd_set_itargetsr(uintptr_t base, unsigned int id, unsigned int target) { uint8_t val = target & GIC_TARGET_CPU_MASK; mmio_write_8(base + GICD_ITARGETSR + id, val); } static inline void gicd_write_sgir(uintptr_t base, unsigned int val) { mmio_write_32(base + GICD_SGIR, val); } /******************************************************************************* * GIC CPU interface accessors for reading entire registers ******************************************************************************/ static inline unsigned int gicc_read_ctlr(uintptr_t base) { return mmio_read_32(base + GICC_CTLR); } static inline unsigned int gicc_read_pmr(uintptr_t base) { return mmio_read_32(base + GICC_PMR); } static inline unsigned int gicc_read_BPR(uintptr_t base) { return mmio_read_32(base + GICC_BPR); } static inline unsigned int gicc_read_IAR(uintptr_t base) { return mmio_read_32(base + GICC_IAR); } static inline unsigned int gicc_read_EOIR(uintptr_t base) { return mmio_read_32(base + GICC_EOIR); } static inline unsigned int gicc_read_hppir(uintptr_t base) { return mmio_read_32(base + GICC_HPPIR); } static inline unsigned int gicc_read_ahppir(uintptr_t base) { return mmio_read_32(base + GICC_AHPPIR); } static inline unsigned int gicc_read_dir(uintptr_t base) { return mmio_read_32(base + GICC_DIR); } static inline unsigned int gicc_read_iidr(uintptr_t base) { return mmio_read_32(base + GICC_IIDR); } static inline unsigned int gicc_read_rpr(uintptr_t base) { return mmio_read_32(base + GICC_RPR); } /******************************************************************************* * GIC CPU interface accessors for writing entire registers ******************************************************************************/ static inline void gicc_write_ctlr(uintptr_t base, unsigned int val) { mmio_write_32(base + GICC_CTLR, val); } static inline void gicc_write_pmr(uintptr_t base, unsigned int val) { mmio_write_32(base + GICC_PMR, val); } static inline void gicc_write_BPR(uintptr_t base, unsigned int val) { mmio_write_32(base + GICC_BPR, val); } static inline void gicc_write_IAR(uintptr_t base, unsigned int val) { mmio_write_32(base + GICC_IAR, val); } static inline void gicc_write_EOIR(uintptr_t base, unsigned int val) { mmio_write_32(base + GICC_EOIR, val); } static inline void gicc_write_hppir(uintptr_t base, unsigned int val) { mmio_write_32(base + GICC_HPPIR, val); } static inline void gicc_write_dir(uintptr_t base, unsigned int val) { mmio_write_32(base + GICC_DIR, val); } #endif /* GICV2_PRIVATE_H */ trusted-firmware-a-2.2/drivers/arm/gic/v3/000077500000000000000000000000001355360272700204405ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/gic/v3/arm_gicv3_common.c000066400000000000000000000070511355360272700240310ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * Driver for implementation defined features that are identical in ARM GICv3 * implementations (GIC-500 and GIC-600 for now). This driver only overrides * APIs that are different to those generic ones in GICv3 driver. */ #include #include #include #include #include "gicv3_private.h" /* * Flush the internal GIC cache of the LPIs pending tables to memory before * saving the state of the Redistributor. This is required before powering off * the GIC when the pending status must be preserved. * `rdist_proc_num` is the processor number corresponding to the Redistributor of the * current CPU. */ void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num) { uintptr_t gicr_base = 0; assert(gicv3_driver_data); assert(gicv3_driver_data->rdistif_base_addrs); /* * The GICR_WAKER.Sleep bit should be set only when both * GICR_WAKER.ChildrenAsleep and GICR_WAKER.ProcessorSleep are set on * all the Redistributors. */ for (unsigned int i = 0; i < gicv3_driver_data->rdistif_num; i++) { gicr_base = gicv3_driver_data->rdistif_base_addrs[i]; assert(gicr_base); assert(gicr_read_waker(gicr_base) & WAKER_CA_BIT); assert(gicr_read_waker(gicr_base) & WAKER_PS_BIT); } gicr_base = gicv3_driver_data->rdistif_base_addrs[rdist_proc_num]; /* * According to the TRM, there is only one instance of the * GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits that can be accessed * through any of the Redistributor. */ /* * Set GICR_WAKER.Sleep * After this point, the system must be configured so that the * wake_request signals for the right cores are asserted when a wakeup * interrupt is detected. The GIC will not be able to do that anymore * when the GICR_WAKER.Sleep bit is set to 1. */ gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) | WAKER_SL_BIT); /* Wait until the GICR_WAKER.Quiescent bit is set */ while (!(gicr_read_waker(gicr_base) & WAKER_QSC_BIT)) ; } /* * Allow the LPIs pending state to be read back from the tables in memory after * having restored the state of the GIC Redistributor. */ void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num) { uintptr_t gicr_base; assert(gicv3_driver_data); assert(gicv3_driver_data->rdistif_base_addrs); /* * According to the TRM, there is only one instance of the * GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits that can be accessed * through any of the Redistributor. */ gicr_base = gicv3_driver_data->rdistif_base_addrs[rdist_proc_num]; assert(gicr_base); /* * If the GIC had power removed, the GICR_WAKER state will be reset. * Since the GICR_WAKER.Sleep and GICR_WAKER.Quiescent bits are cleared, * we can exit early. This also prevents the following assert from * erroneously triggering. */ if (!(gicr_read_waker(gicr_base) & WAKER_SL_BIT)) return; /* * Writes to GICR_WAKER.Sleep bit are ignored if GICR_WAKER.Quiescent * bit is not set. We should be alright on power on path, therefore * coming out of sleep and Quiescent should be set, but we assert in * case. */ assert(gicr_read_waker(gicr_base) & WAKER_QSC_BIT); /* Clear GICR_WAKER.Sleep */ gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_SL_BIT); /* * We don't know if the effects of setting GICR_WAKER.Sleep bit is * instantaneous, so we wait until the interface is not Quiescent * anymore. */ while (gicr_read_waker(gicr_base) & WAKER_QSC_BIT) ; } trusted-firmware-a-2.2/drivers/arm/gic/v3/gic500.c000066400000000000000000000007501355360272700215750ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * Driver for GIC500-specific features. This driver only overrides APIs that are * different to those generic ones in GICv3 driver. */ #include "gicv3_private.h" void gicv3_distif_pre_save(unsigned int proc_num) { arm_gicv3_distif_pre_save(proc_num); } void gicv3_distif_post_restore(unsigned int proc_num) { arm_gicv3_distif_post_restore(proc_num); } trusted-firmware-a-2.2/drivers/arm/gic/v3/gic600.c000066400000000000000000000056421355360272700216030ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * Driver for GIC600-specific features. This driver only overrides APIs that are * different to those generic ones in GICv3 driver. * * GIC600 supports independently power-gating redistributor interface. */ #include #include #include #include "gicv3_private.h" /* GIC600-specific register offsets */ #define GICR_PWRR 0x24 /* GICR_PWRR fields */ #define PWRR_RDPD_SHIFT 0 #define PWRR_RDGPD_SHIFT 2 #define PWRR_RDGPO_SHIFT 3 #define PWRR_RDGPD (1 << PWRR_RDGPD_SHIFT) #define PWRR_RDGPO (1 << PWRR_RDGPO_SHIFT) /* Values to write to GICR_PWRR register to power redistributor */ #define PWRR_ON (0 << PWRR_RDPD_SHIFT) #define PWRR_OFF (1 << PWRR_RDPD_SHIFT) /* GIC600-specific accessor functions */ static void gicr_write_pwrr(uintptr_t base, unsigned int val) { mmio_write_32(base + GICR_PWRR, val); } static uint32_t gicr_read_pwrr(uintptr_t base) { return mmio_read_32(base + GICR_PWRR); } static int gicr_group_powering_down(uint32_t pwrr) { /* * Whether the redistributor group power down operation is in transit: * i.e. it's intending to, but not finished yet. */ return ((pwrr & PWRR_RDGPD) && !(pwrr & PWRR_RDGPO)); } static void gic600_pwr_on(uintptr_t base) { /* Power on redistributor */ gicr_write_pwrr(base, PWRR_ON); /* Wait until the power on state is reflected */ while (gicr_read_pwrr(base) & PWRR_RDGPO) ; } static void gic600_pwr_off(uintptr_t base) { /* Power off redistributor */ gicr_write_pwrr(base, PWRR_OFF); /* * If this is the last man, turning this redistributor frame off will * result in the group itself being powered off. In that case, wait as * long as it's in transition, or has aborted the transition altogether * for any reason. */ if (gicr_read_pwrr(base) & PWRR_RDGPD) { while (gicr_group_powering_down(gicr_read_pwrr(base))) ; } } void gicv3_distif_pre_save(unsigned int proc_num) { arm_gicv3_distif_pre_save(proc_num); } void gicv3_distif_post_restore(unsigned int proc_num) { arm_gicv3_distif_post_restore(proc_num); } /* * Power off GIC600 redistributor */ void gicv3_rdistif_off(unsigned int proc_num) { uintptr_t gicr_base; assert(gicv3_driver_data); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs); gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; assert(gicr_base); /* Attempt to power redistributor off */ gic600_pwr_off(gicr_base); } /* * Power on GIC600 redistributor */ void gicv3_rdistif_on(unsigned int proc_num) { uintptr_t gicr_base; assert(gicv3_driver_data); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs); gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; assert(gicr_base); /* Power redistributor on */ gic600_pwr_on(gicr_base); } trusted-firmware-a-2.2/drivers/arm/gic/v3/gicv3_helpers.c000066400000000000000000000363511355360272700233510ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "../common/gic_common_private.h" #include "gicv3_private.h" /* * Accessor to read the GIC Distributor IGRPMODR corresponding to the * interrupt `id`, 32 interrupt IDs at a time. */ unsigned int gicd_read_igrpmodr(uintptr_t base, unsigned int id) { unsigned int n = id >> IGRPMODR_SHIFT; return mmio_read_32(base + GICD_IGRPMODR + (n << 2)); } /* * Accessor to write the GIC Distributor IGRPMODR corresponding to the * interrupt `id`, 32 interrupt IDs at a time. */ void gicd_write_igrpmodr(uintptr_t base, unsigned int id, unsigned int val) { unsigned int n = id >> IGRPMODR_SHIFT; mmio_write_32(base + GICD_IGRPMODR + (n << 2), val); } /* * Accessor to get the bit corresponding to interrupt ID * in GIC Distributor IGRPMODR. */ unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U); unsigned int reg_val = gicd_read_igrpmodr(base, id); return (reg_val >> bit_num) & 0x1U; } /* * Accessor to set the bit corresponding to interrupt ID * in GIC Distributor IGRPMODR. */ void gicd_set_igrpmodr(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U); unsigned int reg_val = gicd_read_igrpmodr(base, id); gicd_write_igrpmodr(base, id, reg_val | (1U << bit_num)); } /* * Accessor to clear the bit corresponding to interrupt ID * in GIC Distributor IGRPMODR. */ void gicd_clr_igrpmodr(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U); unsigned int reg_val = gicd_read_igrpmodr(base, id); gicd_write_igrpmodr(base, id, reg_val & ~(1U << bit_num)); } /* * Accessor to read the GIC Re-distributor IPRIORITYR corresponding to the * interrupt `id`, 4 interrupts IDs at a time. */ unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int id) { unsigned int n = id >> IPRIORITYR_SHIFT; return mmio_read_32(base + GICR_IPRIORITYR + (n << 2)); } /* * Accessor to write the GIC Re-distributor IPRIORITYR corresponding to the * interrupt `id`, 4 interrupts IDs at a time. */ void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val) { unsigned int n = id >> IPRIORITYR_SHIFT; mmio_write_32(base + GICR_IPRIORITYR + (n << 2), val); } /* * Accessor to get the bit corresponding to interrupt ID * from GIC Re-distributor IGROUPR0. */ unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U); unsigned int reg_val = gicr_read_igroupr0(base); return (reg_val >> bit_num) & 0x1U; } /* * Accessor to set the bit corresponding to interrupt ID * in GIC Re-distributor IGROUPR0. */ void gicr_set_igroupr0(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U); unsigned int reg_val = gicr_read_igroupr0(base); gicr_write_igroupr0(base, reg_val | (1U << bit_num)); } /* * Accessor to clear the bit corresponding to interrupt ID * in GIC Re-distributor IGROUPR0. */ void gicr_clr_igroupr0(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << IGROUPR_SHIFT) - 1U); unsigned int reg_val = gicr_read_igroupr0(base); gicr_write_igroupr0(base, reg_val & ~(1U << bit_num)); } /* * Accessor to get the bit corresponding to interrupt ID * from GIC Re-distributor IGRPMODR0. */ unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U); unsigned int reg_val = gicr_read_igrpmodr0(base); return (reg_val >> bit_num) & 0x1U; } /* * Accessor to set the bit corresponding to interrupt ID * in GIC Re-distributor IGRPMODR0. */ void gicr_set_igrpmodr0(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U); unsigned int reg_val = gicr_read_igrpmodr0(base); gicr_write_igrpmodr0(base, reg_val | (1U << bit_num)); } /* * Accessor to clear the bit corresponding to interrupt ID * in GIC Re-distributor IGRPMODR0. */ void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << IGRPMODR_SHIFT) - 1U); unsigned int reg_val = gicr_read_igrpmodr0(base); gicr_write_igrpmodr0(base, reg_val & ~(1U << bit_num)); } /* * Accessor to set the bit corresponding to interrupt ID * in GIC Re-distributor ISENABLER0. */ void gicr_set_isenabler0(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << ISENABLER_SHIFT) - 1U); gicr_write_isenabler0(base, (1U << bit_num)); } /* * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor * ICENABLER0. */ void gicr_set_icenabler0(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << ICENABLER_SHIFT) - 1U); gicr_write_icenabler0(base, (1U << bit_num)); } /* * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor * ISACTIVER0. */ unsigned int gicr_get_isactiver0(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << ISACTIVER_SHIFT) - 1U); unsigned int reg_val = gicr_read_isactiver0(base); return (reg_val >> bit_num) & 0x1U; } /* * Accessor to clear the bit corresponding to interrupt ID in GIC Re-distributor * ICPENDRR0. */ void gicr_set_icpendr0(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << ICPENDR_SHIFT) - 1U); gicr_write_icpendr0(base, (1U << bit_num)); } /* * Accessor to set the bit corresponding to interrupt ID in GIC Re-distributor * ISPENDR0. */ void gicr_set_ispendr0(uintptr_t base, unsigned int id) { unsigned int bit_num = id & ((1U << ISPENDR_SHIFT) - 1U); gicr_write_ispendr0(base, (1U << bit_num)); } /* * Accessor to set the byte corresponding to interrupt ID * in GIC Re-distributor IPRIORITYR. */ void gicr_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri) { uint8_t val = pri & GIC_PRI_MASK; mmio_write_8(base + GICR_IPRIORITYR + id, val); } /* * Accessor to set the bit fields corresponding to interrupt ID * in GIC Re-distributor ICFGR0. */ void gicr_set_icfgr0(uintptr_t base, unsigned int id, unsigned int cfg) { /* Interrupt configuration is a 2-bit field */ unsigned int bit_num = id & ((1U << ICFGR_SHIFT) - 1U); unsigned int bit_shift = bit_num << 1U; uint32_t reg_val = gicr_read_icfgr0(base); /* Clear the field, and insert required configuration */ reg_val &= ~(GIC_CFG_MASK << bit_shift); reg_val |= ((cfg & GIC_CFG_MASK) << bit_shift); gicr_write_icfgr0(base, reg_val); } /* * Accessor to set the bit fields corresponding to interrupt ID * in GIC Re-distributor ICFGR1. */ void gicr_set_icfgr1(uintptr_t base, unsigned int id, unsigned int cfg) { /* Interrupt configuration is a 2-bit field */ unsigned int bit_num = id & ((1U << ICFGR_SHIFT) - 1U); unsigned int bit_shift = bit_num << 1U; uint32_t reg_val = gicr_read_icfgr1(base); /* Clear the field, and insert required configuration */ reg_val &= ~(GIC_CFG_MASK << bit_shift); reg_val |= ((cfg & GIC_CFG_MASK) << bit_shift); gicr_write_icfgr1(base, reg_val); } /****************************************************************************** * This function marks the core as awake in the re-distributor and * ensures that the interface is active. *****************************************************************************/ void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base) { /* * The WAKER_PS_BIT should be changed to 0 * only when WAKER_CA_BIT is 1. */ assert((gicr_read_waker(gicr_base) & WAKER_CA_BIT) != 0U); /* Mark the connected core as awake */ gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) & ~WAKER_PS_BIT); /* Wait till the WAKER_CA_BIT changes to 0 */ while ((gicr_read_waker(gicr_base) & WAKER_CA_BIT) != 0U) ; } /****************************************************************************** * This function marks the core as asleep in the re-distributor and ensures * that the interface is quiescent. *****************************************************************************/ void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base) { /* Mark the connected core as asleep */ gicr_write_waker(gicr_base, gicr_read_waker(gicr_base) | WAKER_PS_BIT); /* Wait till the WAKER_CA_BIT changes to 1 */ while ((gicr_read_waker(gicr_base) & WAKER_CA_BIT) == 0U) ; } /******************************************************************************* * This function probes the Redistributor frames when the driver is initialised * and saves their base addresses. These base addresses are used later to * initialise each Redistributor interface. ******************************************************************************/ void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs, unsigned int rdistif_num, uintptr_t gicr_base, mpidr_hash_fn mpidr_to_core_pos) { u_register_t mpidr; unsigned int proc_num; uint64_t typer_val; uintptr_t rdistif_base = gicr_base; assert(rdistif_base_addrs != NULL); /* * Iterate over the Redistributor frames. Store the base address of each * frame in the platform provided array. Use the "Processor Number" * field to index into the array if the platform has not provided a hash * function to convert an MPIDR (obtained from the "Affinity Value" * field into a linear index. */ do { typer_val = gicr_read_typer(rdistif_base); if (mpidr_to_core_pos != NULL) { mpidr = mpidr_from_gicr_typer(typer_val); proc_num = mpidr_to_core_pos(mpidr); } else { proc_num = (typer_val >> TYPER_PROC_NUM_SHIFT) & TYPER_PROC_NUM_MASK; } if (proc_num < rdistif_num) rdistif_base_addrs[proc_num] = rdistif_base; rdistif_base += (1U << GICR_PCPUBASE_SHIFT); } while ((typer_val & TYPER_LAST_BIT) == 0U); } /******************************************************************************* * Helper function to configure the default attributes of SPIs. ******************************************************************************/ void gicv3_spis_config_defaults(uintptr_t gicd_base) { unsigned int index, num_ints; num_ints = gicd_read_typer(gicd_base); num_ints &= TYPER_IT_LINES_NO_MASK; num_ints = (num_ints + 1U) << 5; /* * Treat all SPIs as G1NS by default. The number of interrupts is * calculated as 32 * (IT_LINES + 1). We do 32 at a time. */ for (index = MIN_SPI_ID; index < num_ints; index += 32U) gicd_write_igroupr(gicd_base, index, ~0U); /* Setup the default SPI priorities doing four at a time */ for (index = MIN_SPI_ID; index < num_ints; index += 4U) gicd_write_ipriorityr(gicd_base, index, GICD_IPRIORITYR_DEF_VAL); /* * Treat all SPIs as level triggered by default, write 16 at * a time */ for (index = MIN_SPI_ID; index < num_ints; index += 16U) gicd_write_icfgr(gicd_base, index, 0U); } /******************************************************************************* * Helper function to configure properties of secure SPIs ******************************************************************************/ unsigned int gicv3_secure_spis_config_props(uintptr_t gicd_base, const interrupt_prop_t *interrupt_props, unsigned int interrupt_props_num) { unsigned int i; const interrupt_prop_t *current_prop; unsigned long long gic_affinity_val; unsigned int ctlr_enable = 0U; /* Make sure there's a valid property array */ if (interrupt_props_num > 0U) assert(interrupt_props != NULL); for (i = 0U; i < interrupt_props_num; i++) { current_prop = &interrupt_props[i]; if (current_prop->intr_num < MIN_SPI_ID) continue; /* Configure this interrupt as a secure interrupt */ gicd_clr_igroupr(gicd_base, current_prop->intr_num); /* Configure this interrupt as G0 or a G1S interrupt */ assert((current_prop->intr_grp == INTR_GROUP0) || (current_prop->intr_grp == INTR_GROUP1S)); if (current_prop->intr_grp == INTR_GROUP1S) { gicd_set_igrpmodr(gicd_base, current_prop->intr_num); ctlr_enable |= CTLR_ENABLE_G1S_BIT; } else { gicd_clr_igrpmodr(gicd_base, current_prop->intr_num); ctlr_enable |= CTLR_ENABLE_G0_BIT; } /* Set interrupt configuration */ gicd_set_icfgr(gicd_base, current_prop->intr_num, current_prop->intr_cfg); /* Set the priority of this interrupt */ gicd_set_ipriorityr(gicd_base, current_prop->intr_num, current_prop->intr_pri); /* Target SPIs to the primary CPU */ gic_affinity_val = gicd_irouter_val_from_mpidr(read_mpidr(), 0U); gicd_write_irouter(gicd_base, current_prop->intr_num, gic_affinity_val); /* Enable this interrupt */ gicd_set_isenabler(gicd_base, current_prop->intr_num); } return ctlr_enable; } /******************************************************************************* * Helper function to configure the default attributes of SPIs. ******************************************************************************/ void gicv3_ppi_sgi_config_defaults(uintptr_t gicr_base) { unsigned int index; /* * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a * more scalable approach as it avoids clearing the enable bits in the * GICD_CTLR */ gicr_write_icenabler0(gicr_base, ~0U); gicr_wait_for_pending_write(gicr_base); /* Treat all SGIs/PPIs as G1NS by default. */ gicr_write_igroupr0(gicr_base, ~0U); /* Setup the default PPI/SGI priorities doing four at a time */ for (index = 0U; index < MIN_SPI_ID; index += 4U) gicr_write_ipriorityr(gicr_base, index, GICD_IPRIORITYR_DEF_VAL); /* Configure all PPIs as level triggered by default */ gicr_write_icfgr1(gicr_base, 0U); } /******************************************************************************* * Helper function to configure properties of secure G0 and G1S PPIs and SGIs. ******************************************************************************/ unsigned int gicv3_secure_ppi_sgi_config_props(uintptr_t gicr_base, const interrupt_prop_t *interrupt_props, unsigned int interrupt_props_num) { unsigned int i; const interrupt_prop_t *current_prop; unsigned int ctlr_enable = 0U; /* Make sure there's a valid property array */ if (interrupt_props_num > 0U) assert(interrupt_props != NULL); for (i = 0U; i < interrupt_props_num; i++) { current_prop = &interrupt_props[i]; if (current_prop->intr_num >= MIN_SPI_ID) continue; /* Configure this interrupt as a secure interrupt */ gicr_clr_igroupr0(gicr_base, current_prop->intr_num); /* Configure this interrupt as G0 or a G1S interrupt */ assert((current_prop->intr_grp == INTR_GROUP0) || (current_prop->intr_grp == INTR_GROUP1S)); if (current_prop->intr_grp == INTR_GROUP1S) { gicr_set_igrpmodr0(gicr_base, current_prop->intr_num); ctlr_enable |= CTLR_ENABLE_G1S_BIT; } else { gicr_clr_igrpmodr0(gicr_base, current_prop->intr_num); ctlr_enable |= CTLR_ENABLE_G0_BIT; } /* Set the priority of this interrupt */ gicr_set_ipriorityr(gicr_base, current_prop->intr_num, current_prop->intr_pri); /* * Set interrupt configuration for PPIs. Configuration for SGIs * are ignored. */ if ((current_prop->intr_num >= MIN_PPI_ID) && (current_prop->intr_num < MIN_SPI_ID)) { gicr_set_icfgr1(gicr_base, current_prop->intr_num, current_prop->intr_cfg); } /* Enable this interrupt */ gicr_set_isenabler0(gicr_base, current_prop->intr_num); } return ctlr_enable; } trusted-firmware-a-2.2/drivers/arm/gic/v3/gicv3_main.c000066400000000000000000001160201355360272700226230ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "gicv3_private.h" const gicv3_driver_data_t *gicv3_driver_data; /* * Spinlock to guard registers needing read-modify-write. APIs protected by this * spinlock are used either at boot time (when only a single CPU is active), or * when the system is fully coherent. */ static spinlock_t gic_lock; /* * Redistributor power operations are weakly bound so that they can be * overridden */ #pragma weak gicv3_rdistif_off #pragma weak gicv3_rdistif_on /* Helper macros to save and restore GICD registers to and from the context */ #define RESTORE_GICD_REGS(base, ctx, intr_num, reg, REG) \ do { \ for (unsigned int int_id = MIN_SPI_ID; int_id < (intr_num); \ int_id += (1U << REG##_SHIFT)) { \ gicd_write_##reg(base, int_id, \ ctx->gicd_##reg[(int_id - MIN_SPI_ID) >> REG##_SHIFT]); \ } \ } while (false) #define SAVE_GICD_REGS(base, ctx, intr_num, reg, REG) \ do { \ for (unsigned int int_id = MIN_SPI_ID; int_id < (intr_num); \ int_id += (1U << REG##_SHIFT)) { \ ctx->gicd_##reg[(int_id - MIN_SPI_ID) >> REG##_SHIFT] =\ gicd_read_##reg(base, int_id); \ } \ } while (false) /******************************************************************************* * This function initialises the ARM GICv3 driver in EL3 with provided platform * inputs. ******************************************************************************/ void __init gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data) { unsigned int gic_version; unsigned int gicv2_compat; assert(plat_driver_data != NULL); assert(plat_driver_data->gicd_base != 0U); assert(plat_driver_data->rdistif_num != 0U); assert(plat_driver_data->rdistif_base_addrs != NULL); assert(IS_IN_EL3()); assert((plat_driver_data->interrupt_props_num != 0U) ? (plat_driver_data->interrupt_props != NULL) : 1); /* Check for system register support */ #ifndef __aarch64__ assert((read_id_pfr1() & (ID_PFR1_GIC_MASK << ID_PFR1_GIC_SHIFT)) != 0U); #else assert((read_id_aa64pfr0_el1() & (ID_AA64PFR0_GIC_MASK << ID_AA64PFR0_GIC_SHIFT)) != 0U); #endif /* !__aarch64__ */ /* The GIC version should be 3.0 */ gic_version = gicd_read_pidr2(plat_driver_data->gicd_base); gic_version >>= PIDR2_ARCH_REV_SHIFT; gic_version &= PIDR2_ARCH_REV_MASK; assert(gic_version == ARCH_REV_GICV3); /* * Find out whether the GIC supports the GICv2 compatibility mode. * The ARE_S bit resets to 0 if supported */ gicv2_compat = gicd_read_ctlr(plat_driver_data->gicd_base); gicv2_compat >>= CTLR_ARE_S_SHIFT; gicv2_compat = gicv2_compat & CTLR_ARE_S_MASK; if (plat_driver_data->gicr_base != 0U) { /* * Find the base address of each implemented Redistributor interface. * The number of interfaces should be equal to the number of CPUs in the * system. The memory for saving these addresses has to be allocated by * the platform port */ gicv3_rdistif_base_addrs_probe(plat_driver_data->rdistif_base_addrs, plat_driver_data->rdistif_num, plat_driver_data->gicr_base, plat_driver_data->mpidr_to_core_pos); #if !HW_ASSISTED_COHERENCY /* * Flush the rdistif_base_addrs[] contents linked to the GICv3 driver. */ flush_dcache_range((uintptr_t)(plat_driver_data->rdistif_base_addrs), plat_driver_data->rdistif_num * sizeof(*(plat_driver_data->rdistif_base_addrs))); #endif } gicv3_driver_data = plat_driver_data; /* * The GIC driver data is initialized by the primary CPU with caches * enabled. When the secondary CPU boots up, it initializes the * GICC/GICR interface with the caches disabled. Hence flush the * driver data to ensure coherency. This is not required if the * platform has HW_ASSISTED_COHERENCY enabled. */ #if !HW_ASSISTED_COHERENCY flush_dcache_range((uintptr_t)&gicv3_driver_data, sizeof(gicv3_driver_data)); flush_dcache_range((uintptr_t)gicv3_driver_data, sizeof(*gicv3_driver_data)); #endif INFO("GICv3 with%s legacy support detected." " ARM GICv3 driver initialized in EL3\n", (gicv2_compat == 0U) ? "" : "out"); } /******************************************************************************* * This function initialises the GIC distributor interface based upon the data * provided by the platform while initialising the driver. ******************************************************************************/ void __init gicv3_distif_init(void) { unsigned int bitmap = 0; assert(gicv3_driver_data != NULL); assert(gicv3_driver_data->gicd_base != 0U); assert(IS_IN_EL3()); /* * Clear the "enable" bits for G0/G1S/G1NS interrupts before configuring * the ARE_S bit. The Distributor might generate a system error * otherwise. */ gicd_clr_ctlr(gicv3_driver_data->gicd_base, CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT | CTLR_ENABLE_G1NS_BIT, RWP_TRUE); /* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */ gicd_set_ctlr(gicv3_driver_data->gicd_base, CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE); /* Set the default attribute of all SPIs */ gicv3_spis_config_defaults(gicv3_driver_data->gicd_base); bitmap = gicv3_secure_spis_config_props( gicv3_driver_data->gicd_base, gicv3_driver_data->interrupt_props, gicv3_driver_data->interrupt_props_num); /* Enable the secure SPIs now that they have been configured */ gicd_set_ctlr(gicv3_driver_data->gicd_base, bitmap, RWP_TRUE); } /******************************************************************************* * This function initialises the GIC Redistributor interface of the calling CPU * (identified by the 'proc_num' parameter) based upon the data provided by the * platform while initialising the driver. ******************************************************************************/ void gicv3_rdistif_init(unsigned int proc_num) { uintptr_t gicr_base; unsigned int bitmap = 0U; uint32_t ctlr; assert(gicv3_driver_data != NULL); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs != NULL); assert(gicv3_driver_data->gicd_base != 0U); ctlr = gicd_read_ctlr(gicv3_driver_data->gicd_base); assert((ctlr & CTLR_ARE_S_BIT) != 0U); assert(IS_IN_EL3()); /* Power on redistributor */ gicv3_rdistif_on(proc_num); gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; assert(gicr_base != 0U); /* Set the default attribute of all SGIs and PPIs */ gicv3_ppi_sgi_config_defaults(gicr_base); bitmap = gicv3_secure_ppi_sgi_config_props(gicr_base, gicv3_driver_data->interrupt_props, gicv3_driver_data->interrupt_props_num); /* Enable interrupt groups as required, if not already */ if ((ctlr & bitmap) != bitmap) gicd_set_ctlr(gicv3_driver_data->gicd_base, bitmap, RWP_TRUE); } /******************************************************************************* * Functions to perform power operations on GIC Redistributor ******************************************************************************/ void gicv3_rdistif_off(unsigned int proc_num) { return; } void gicv3_rdistif_on(unsigned int proc_num) { return; } /******************************************************************************* * This function enables the GIC CPU interface of the calling CPU using only * system register accesses. ******************************************************************************/ void gicv3_cpuif_enable(unsigned int proc_num) { uintptr_t gicr_base; unsigned int scr_el3; unsigned int icc_sre_el3; assert(gicv3_driver_data != NULL); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs != NULL); assert(IS_IN_EL3()); /* Mark the connected core as awake */ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; gicv3_rdistif_mark_core_awake(gicr_base); /* Disable the legacy interrupt bypass */ icc_sre_el3 = ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT; /* * Enable system register access for EL3 and allow lower exception * levels to configure the same for themselves. If the legacy mode is * not supported, the SRE bit is RAO/WI */ icc_sre_el3 |= (ICC_SRE_EN_BIT | ICC_SRE_SRE_BIT); write_icc_sre_el3(read_icc_sre_el3() | icc_sre_el3); scr_el3 = (uint32_t) read_scr_el3(); /* * Switch to NS state to write Non secure ICC_SRE_EL1 and * ICC_SRE_EL2 registers. */ write_scr_el3(scr_el3 | SCR_NS_BIT); isb(); write_icc_sre_el2(read_icc_sre_el2() | icc_sre_el3); write_icc_sre_el1(ICC_SRE_SRE_BIT); isb(); /* Switch to secure state. */ write_scr_el3(scr_el3 & (~SCR_NS_BIT)); isb(); /* Write the secure ICC_SRE_EL1 register */ write_icc_sre_el1(ICC_SRE_SRE_BIT); isb(); /* Program the idle priority in the PMR */ write_icc_pmr_el1(GIC_PRI_MASK); /* Enable Group0 interrupts */ write_icc_igrpen0_el1(IGRPEN1_EL1_ENABLE_G0_BIT); /* Enable Group1 Secure interrupts */ write_icc_igrpen1_el3(read_icc_igrpen1_el3() | IGRPEN1_EL3_ENABLE_G1S_BIT); isb(); } /******************************************************************************* * This function disables the GIC CPU interface of the calling CPU using * only system register accesses. ******************************************************************************/ void gicv3_cpuif_disable(unsigned int proc_num) { uintptr_t gicr_base; assert(gicv3_driver_data != NULL); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs != NULL); assert(IS_IN_EL3()); /* Disable legacy interrupt bypass */ write_icc_sre_el3(read_icc_sre_el3() | (ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT)); /* Disable Group0 interrupts */ write_icc_igrpen0_el1(read_icc_igrpen0_el1() & ~IGRPEN1_EL1_ENABLE_G0_BIT); /* Disable Group1 Secure and Non-Secure interrupts */ write_icc_igrpen1_el3(read_icc_igrpen1_el3() & ~(IGRPEN1_EL3_ENABLE_G1NS_BIT | IGRPEN1_EL3_ENABLE_G1S_BIT)); /* Synchronise accesses to group enable registers */ isb(); /* Mark the connected core as asleep */ gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; assert(gicr_base != 0U); gicv3_rdistif_mark_core_asleep(gicr_base); } /******************************************************************************* * This function returns the id of the highest priority pending interrupt at * the GIC cpu interface. ******************************************************************************/ unsigned int gicv3_get_pending_interrupt_id(void) { unsigned int id; assert(IS_IN_EL3()); id = (uint32_t)read_icc_hppir0_el1() & HPPIR0_EL1_INTID_MASK; /* * If the ID is special identifier corresponding to G1S or G1NS * interrupt, then read the highest pending group 1 interrupt. */ if ((id == PENDING_G1S_INTID) || (id == PENDING_G1NS_INTID)) return (uint32_t)read_icc_hppir1_el1() & HPPIR1_EL1_INTID_MASK; return id; } /******************************************************************************* * This function returns the type of the highest priority pending interrupt at * the GIC cpu interface. The return values can be one of the following : * PENDING_G1S_INTID : The interrupt type is secure Group 1. * PENDING_G1NS_INTID : The interrupt type is non secure Group 1. * 0 - 1019 : The interrupt type is secure Group 0. * GIC_SPURIOUS_INTERRUPT : there is no pending interrupt with * sufficient priority to be signaled ******************************************************************************/ unsigned int gicv3_get_pending_interrupt_type(void) { assert(IS_IN_EL3()); return (uint32_t)read_icc_hppir0_el1() & HPPIR0_EL1_INTID_MASK; } /******************************************************************************* * This function returns the type of the interrupt id depending upon the group * this interrupt has been configured under by the interrupt controller i.e. * group0 or group1 Secure / Non Secure. The return value can be one of the * following : * INTR_GROUP0 : The interrupt type is a Secure Group 0 interrupt * INTR_GROUP1S : The interrupt type is a Secure Group 1 secure interrupt * INTR_GROUP1NS: The interrupt type is a Secure Group 1 non secure * interrupt. ******************************************************************************/ unsigned int gicv3_get_interrupt_type(unsigned int id, unsigned int proc_num) { unsigned int igroup, grpmodr; uintptr_t gicr_base; assert(IS_IN_EL3()); assert(gicv3_driver_data != NULL); /* Ensure the parameters are valid */ assert((id < PENDING_G1S_INTID) || (id >= MIN_LPI_ID)); assert(proc_num < gicv3_driver_data->rdistif_num); /* All LPI interrupts are Group 1 non secure */ if (id >= MIN_LPI_ID) return INTR_GROUP1NS; if (id < MIN_SPI_ID) { assert(gicv3_driver_data->rdistif_base_addrs != NULL); gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; igroup = gicr_get_igroupr0(gicr_base, id); grpmodr = gicr_get_igrpmodr0(gicr_base, id); } else { assert(gicv3_driver_data->gicd_base != 0U); igroup = gicd_get_igroupr(gicv3_driver_data->gicd_base, id); grpmodr = gicd_get_igrpmodr(gicv3_driver_data->gicd_base, id); } /* * If the IGROUP bit is set, then it is a Group 1 Non secure * interrupt */ if (igroup != 0U) return INTR_GROUP1NS; /* If the GRPMOD bit is set, then it is a Group 1 Secure interrupt */ if (grpmodr != 0U) return INTR_GROUP1S; /* Else it is a Group 0 Secure interrupt */ return INTR_GROUP0; } /***************************************************************************** * Function to save and disable the GIC ITS register context. The power * management of GIC ITS is implementation-defined and this function doesn't * save any memory structures required to support ITS. As the sequence to save * this state is implementation defined, it should be executed in platform * specific code. Calling this function alone and then powering down the GIC and * ITS without implementing the aforementioned platform specific code will * corrupt the ITS state. * * This function must be invoked after the GIC CPU interface is disabled. *****************************************************************************/ void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx) { unsigned int i; assert(gicv3_driver_data != NULL); assert(IS_IN_EL3()); assert(its_ctx != NULL); assert(gits_base != 0U); its_ctx->gits_ctlr = gits_read_ctlr(gits_base); /* Disable the ITS */ gits_write_ctlr(gits_base, its_ctx->gits_ctlr & (~GITS_CTLR_ENABLED_BIT)); /* Wait for quiescent state */ gits_wait_for_quiescent_bit(gits_base); its_ctx->gits_cbaser = gits_read_cbaser(gits_base); its_ctx->gits_cwriter = gits_read_cwriter(gits_base); for (i = 0; i < ARRAY_SIZE(its_ctx->gits_baser); i++) its_ctx->gits_baser[i] = gits_read_baser(gits_base, i); } /***************************************************************************** * Function to restore the GIC ITS register context. The power * management of GIC ITS is implementation defined and this function doesn't * restore any memory structures required to support ITS. The assumption is * that these structures are in memory and are retained during system suspend. * * This must be invoked before the GIC CPU interface is enabled. *****************************************************************************/ void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ctx) { unsigned int i; assert(gicv3_driver_data != NULL); assert(IS_IN_EL3()); assert(its_ctx != NULL); assert(gits_base != 0U); /* Assert that the GITS is disabled and quiescent */ assert((gits_read_ctlr(gits_base) & GITS_CTLR_ENABLED_BIT) == 0U); assert((gits_read_ctlr(gits_base) & GITS_CTLR_QUIESCENT_BIT) != 0U); gits_write_cbaser(gits_base, its_ctx->gits_cbaser); gits_write_cwriter(gits_base, its_ctx->gits_cwriter); for (i = 0; i < ARRAY_SIZE(its_ctx->gits_baser); i++) gits_write_baser(gits_base, i, its_ctx->gits_baser[i]); /* Restore the ITS CTLR but leave the ITS disabled */ gits_write_ctlr(gits_base, its_ctx->gits_ctlr & (~GITS_CTLR_ENABLED_BIT)); } /***************************************************************************** * Function to save the GIC Redistributor register context. This function * must be invoked after CPU interface disable and prior to Distributor save. *****************************************************************************/ void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_ctx) { uintptr_t gicr_base; unsigned int int_id; assert(gicv3_driver_data != NULL); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs != NULL); assert(IS_IN_EL3()); assert(rdist_ctx != NULL); gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; /* * Wait for any write to GICR_CTLR to complete before trying to save any * state. */ gicr_wait_for_pending_write(gicr_base); rdist_ctx->gicr_ctlr = gicr_read_ctlr(gicr_base); rdist_ctx->gicr_propbaser = gicr_read_propbaser(gicr_base); rdist_ctx->gicr_pendbaser = gicr_read_pendbaser(gicr_base); rdist_ctx->gicr_igroupr0 = gicr_read_igroupr0(gicr_base); rdist_ctx->gicr_isenabler0 = gicr_read_isenabler0(gicr_base); rdist_ctx->gicr_ispendr0 = gicr_read_ispendr0(gicr_base); rdist_ctx->gicr_isactiver0 = gicr_read_isactiver0(gicr_base); rdist_ctx->gicr_icfgr0 = gicr_read_icfgr0(gicr_base); rdist_ctx->gicr_icfgr1 = gicr_read_icfgr1(gicr_base); rdist_ctx->gicr_igrpmodr0 = gicr_read_igrpmodr0(gicr_base); rdist_ctx->gicr_nsacr = gicr_read_nsacr(gicr_base); for (int_id = MIN_SGI_ID; int_id < TOTAL_PCPU_INTR_NUM; int_id += (1U << IPRIORITYR_SHIFT)) { rdist_ctx->gicr_ipriorityr[(int_id - MIN_SGI_ID) >> IPRIORITYR_SHIFT] = gicr_read_ipriorityr(gicr_base, int_id); } /* * Call the pre-save hook that implements the IMP DEF sequence that may * be required on some GIC implementations. As this may need to access * the Redistributor registers, we pass it proc_num. */ gicv3_distif_pre_save(proc_num); } /***************************************************************************** * Function to restore the GIC Redistributor register context. We disable * LPI and per-cpu interrupts before we start restore of the Redistributor. * This function must be invoked after Distributor restore but prior to * CPU interface enable. The pending and active interrupts are restored * after the interrupts are fully configured and enabled. *****************************************************************************/ void gicv3_rdistif_init_restore(unsigned int proc_num, const gicv3_redist_ctx_t * const rdist_ctx) { uintptr_t gicr_base; unsigned int int_id; assert(gicv3_driver_data != NULL); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs != NULL); assert(IS_IN_EL3()); assert(rdist_ctx != NULL); gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; /* Power on redistributor */ gicv3_rdistif_on(proc_num); /* * Call the post-restore hook that implements the IMP DEF sequence that * may be required on some GIC implementations. As this may need to * access the Redistributor registers, we pass it proc_num. */ gicv3_distif_post_restore(proc_num); /* * Disable all SGIs (imp. def.)/PPIs before configuring them. This is a * more scalable approach as it avoids clearing the enable bits in the * GICD_CTLR */ gicr_write_icenabler0(gicr_base, ~0U); /* Wait for pending writes to GICR_ICENABLER */ gicr_wait_for_pending_write(gicr_base); /* * Disable the LPIs to avoid unpredictable behavior when writing to * GICR_PROPBASER and GICR_PENDBASER. */ gicr_write_ctlr(gicr_base, rdist_ctx->gicr_ctlr & ~(GICR_CTLR_EN_LPIS_BIT)); /* Restore registers' content */ gicr_write_propbaser(gicr_base, rdist_ctx->gicr_propbaser); gicr_write_pendbaser(gicr_base, rdist_ctx->gicr_pendbaser); gicr_write_igroupr0(gicr_base, rdist_ctx->gicr_igroupr0); for (int_id = MIN_SGI_ID; int_id < TOTAL_PCPU_INTR_NUM; int_id += (1U << IPRIORITYR_SHIFT)) { gicr_write_ipriorityr(gicr_base, int_id, rdist_ctx->gicr_ipriorityr[ (int_id - MIN_SGI_ID) >> IPRIORITYR_SHIFT]); } gicr_write_icfgr0(gicr_base, rdist_ctx->gicr_icfgr0); gicr_write_icfgr1(gicr_base, rdist_ctx->gicr_icfgr1); gicr_write_igrpmodr0(gicr_base, rdist_ctx->gicr_igrpmodr0); gicr_write_nsacr(gicr_base, rdist_ctx->gicr_nsacr); /* Restore after group and priorities are set */ gicr_write_ispendr0(gicr_base, rdist_ctx->gicr_ispendr0); gicr_write_isactiver0(gicr_base, rdist_ctx->gicr_isactiver0); /* * Wait for all writes to the Distributor to complete before enabling * the SGI and PPIs. */ gicr_wait_for_upstream_pending_write(gicr_base); gicr_write_isenabler0(gicr_base, rdist_ctx->gicr_isenabler0); /* * Restore GICR_CTLR.Enable_LPIs bit and wait for pending writes in case * the first write to GICR_CTLR was still in flight (this write only * restores GICR_CTLR.Enable_LPIs and no waiting is required for this * bit). */ gicr_write_ctlr(gicr_base, rdist_ctx->gicr_ctlr); gicr_wait_for_pending_write(gicr_base); } /***************************************************************************** * Function to save the GIC Distributor register context. This function * must be invoked after CPU interface disable and Redistributor save. *****************************************************************************/ void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx) { unsigned int num_ints; assert(gicv3_driver_data != NULL); assert(gicv3_driver_data->gicd_base != 0U); assert(IS_IN_EL3()); assert(dist_ctx != NULL); uintptr_t gicd_base = gicv3_driver_data->gicd_base; num_ints = gicd_read_typer(gicd_base); num_ints &= TYPER_IT_LINES_NO_MASK; num_ints = (num_ints + 1U) << 5; /* Filter out special INTIDs 1020-1023 */ if (num_ints > (MAX_SPI_ID + 1U)) num_ints = MAX_SPI_ID + 1U; /* Wait for pending write to complete */ gicd_wait_for_pending_write(gicd_base); /* Save the GICD_CTLR */ dist_ctx->gicd_ctlr = gicd_read_ctlr(gicd_base); /* Save GICD_IGROUPR for INTIDs 32 - 1019 */ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR); /* Save GICD_ISENABLER for INT_IDs 32 - 1019 */ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER); /* Save GICD_ISPENDR for INTIDs 32 - 1019 */ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR); /* Save GICD_ISACTIVER for INTIDs 32 - 1019 */ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER); /* Save GICD_IPRIORITYR for INTIDs 32 - 1019 */ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR); /* Save GICD_ICFGR for INTIDs 32 - 1019 */ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR); /* Save GICD_IGRPMODR for INTIDs 32 - 1019 */ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR); /* Save GICD_NSACR for INTIDs 32 - 1019 */ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR); /* Save GICD_IROUTER for INTIDs 32 - 1019 */ SAVE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER); /* * GICD_ITARGETSR and GICD_SPENDSGIR are RAZ/WI when * GICD_CTLR.ARE_(S|NS) bits are set which is the case for our GICv3 * driver. */ } /***************************************************************************** * Function to restore the GIC Distributor register context. We disable G0, G1S * and G1NS interrupt groups before we start restore of the Distributor. This * function must be invoked prior to Redistributor restore and CPU interface * enable. The pending and active interrupts are restored after the interrupts * are fully configured and enabled. *****************************************************************************/ void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx) { unsigned int num_ints = 0U; assert(gicv3_driver_data != NULL); assert(gicv3_driver_data->gicd_base != 0U); assert(IS_IN_EL3()); assert(dist_ctx != NULL); uintptr_t gicd_base = gicv3_driver_data->gicd_base; /* * Clear the "enable" bits for G0/G1S/G1NS interrupts before configuring * the ARE_S bit. The Distributor might generate a system error * otherwise. */ gicd_clr_ctlr(gicd_base, CTLR_ENABLE_G0_BIT | CTLR_ENABLE_G1S_BIT | CTLR_ENABLE_G1NS_BIT, RWP_TRUE); /* Set the ARE_S and ARE_NS bit now that interrupts have been disabled */ gicd_set_ctlr(gicd_base, CTLR_ARE_S_BIT | CTLR_ARE_NS_BIT, RWP_TRUE); num_ints = gicd_read_typer(gicd_base); num_ints &= TYPER_IT_LINES_NO_MASK; num_ints = (num_ints + 1U) << 5; /* Filter out special INTIDs 1020-1023 */ if (num_ints > (MAX_SPI_ID + 1U)) num_ints = MAX_SPI_ID + 1U; /* Restore GICD_IGROUPR for INTIDs 32 - 1019 */ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igroupr, IGROUPR); /* Restore GICD_IPRIORITYR for INTIDs 32 - 1019 */ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ipriorityr, IPRIORITYR); /* Restore GICD_ICFGR for INTIDs 32 - 1019 */ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, icfgr, ICFGR); /* Restore GICD_IGRPMODR for INTIDs 32 - 1019 */ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, igrpmodr, IGRPMODR); /* Restore GICD_NSACR for INTIDs 32 - 1019 */ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, nsacr, NSACR); /* Restore GICD_IROUTER for INTIDs 32 - 1019 */ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, irouter, IROUTER); /* * Restore ISENABLER, ISPENDR and ISACTIVER after the interrupts are * configured. */ /* Restore GICD_ISENABLER for INT_IDs 32 - 1019 */ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isenabler, ISENABLER); /* Restore GICD_ISPENDR for INTIDs 32 - 1019 */ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, ispendr, ISPENDR); /* Restore GICD_ISACTIVER for INTIDs 32 - 1019 */ RESTORE_GICD_REGS(gicd_base, dist_ctx, num_ints, isactiver, ISACTIVER); /* Restore the GICD_CTLR */ gicd_write_ctlr(gicd_base, dist_ctx->gicd_ctlr); gicd_wait_for_pending_write(gicd_base); } /******************************************************************************* * This function gets the priority of the interrupt the processor is currently * servicing. ******************************************************************************/ unsigned int gicv3_get_running_priority(void) { return (unsigned int)read_icc_rpr_el1(); } /******************************************************************************* * This function checks if the interrupt identified by id is active (whether the * state is either active, or active and pending). The proc_num is used if the * interrupt is SGI or PPI and programs the corresponding Redistributor * interface. ******************************************************************************/ unsigned int gicv3_get_interrupt_active(unsigned int id, unsigned int proc_num) { unsigned int value; assert(gicv3_driver_data != NULL); assert(gicv3_driver_data->gicd_base != 0U); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs != NULL); assert(id <= MAX_SPI_ID); if (id < MIN_SPI_ID) { /* For SGIs and PPIs */ value = gicr_get_isactiver0( gicv3_driver_data->rdistif_base_addrs[proc_num], id); } else { value = gicd_get_isactiver(gicv3_driver_data->gicd_base, id); } return value; } /******************************************************************************* * This function enables the interrupt identified by id. The proc_num * is used if the interrupt is SGI or PPI, and programs the corresponding * Redistributor interface. ******************************************************************************/ void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num) { assert(gicv3_driver_data != NULL); assert(gicv3_driver_data->gicd_base != 0U); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs != NULL); assert(id <= MAX_SPI_ID); /* * Ensure that any shared variable updates depending on out of band * interrupt trigger are observed before enabling interrupt. */ dsbishst(); if (id < MIN_SPI_ID) { /* For SGIs and PPIs */ gicr_set_isenabler0( gicv3_driver_data->rdistif_base_addrs[proc_num], id); } else { gicd_set_isenabler(gicv3_driver_data->gicd_base, id); } } /******************************************************************************* * This function disables the interrupt identified by id. The proc_num * is used if the interrupt is SGI or PPI, and programs the corresponding * Redistributor interface. ******************************************************************************/ void gicv3_disable_interrupt(unsigned int id, unsigned int proc_num) { assert(gicv3_driver_data != NULL); assert(gicv3_driver_data->gicd_base != 0U); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs != NULL); assert(id <= MAX_SPI_ID); /* * Disable interrupt, and ensure that any shared variable updates * depending on out of band interrupt trigger are observed afterwards. */ if (id < MIN_SPI_ID) { /* For SGIs and PPIs */ gicr_set_icenabler0( gicv3_driver_data->rdistif_base_addrs[proc_num], id); /* Write to clear enable requires waiting for pending writes */ gicr_wait_for_pending_write( gicv3_driver_data->rdistif_base_addrs[proc_num]); } else { gicd_set_icenabler(gicv3_driver_data->gicd_base, id); /* Write to clear enable requires waiting for pending writes */ gicd_wait_for_pending_write(gicv3_driver_data->gicd_base); } dsbishst(); } /******************************************************************************* * This function sets the interrupt priority as supplied for the given interrupt * id. ******************************************************************************/ void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num, unsigned int priority) { uintptr_t gicr_base; assert(gicv3_driver_data != NULL); assert(gicv3_driver_data->gicd_base != 0U); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs != NULL); assert(id <= MAX_SPI_ID); if (id < MIN_SPI_ID) { gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; gicr_set_ipriorityr(gicr_base, id, priority); } else { gicd_set_ipriorityr(gicv3_driver_data->gicd_base, id, priority); } } /******************************************************************************* * This function assigns group for the interrupt identified by id. The proc_num * is used if the interrupt is SGI or PPI, and programs the corresponding * Redistributor interface. The group can be any of GICV3_INTR_GROUP* ******************************************************************************/ void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num, unsigned int type) { bool igroup = false, grpmod = false; uintptr_t gicr_base; assert(gicv3_driver_data != NULL); assert(gicv3_driver_data->gicd_base != 0U); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs != NULL); switch (type) { case INTR_GROUP1S: igroup = false; grpmod = true; break; case INTR_GROUP0: igroup = false; grpmod = false; break; case INTR_GROUP1NS: igroup = true; grpmod = false; break; default: assert(false); break; } if (id < MIN_SPI_ID) { gicr_base = gicv3_driver_data->rdistif_base_addrs[proc_num]; if (igroup) gicr_set_igroupr0(gicr_base, id); else gicr_clr_igroupr0(gicr_base, id); if (grpmod) gicr_set_igrpmodr0(gicr_base, id); else gicr_clr_igrpmodr0(gicr_base, id); } else { /* Serialize read-modify-write to Distributor registers */ spin_lock(&gic_lock); if (igroup) gicd_set_igroupr(gicv3_driver_data->gicd_base, id); else gicd_clr_igroupr(gicv3_driver_data->gicd_base, id); if (grpmod) gicd_set_igrpmodr(gicv3_driver_data->gicd_base, id); else gicd_clr_igrpmodr(gicv3_driver_data->gicd_base, id); spin_unlock(&gic_lock); } } /******************************************************************************* * This function raises the specified Secure Group 0 SGI. * * The target parameter must be a valid MPIDR in the system. ******************************************************************************/ void gicv3_raise_secure_g0_sgi(unsigned int sgi_num, u_register_t target) { unsigned int tgt, aff3, aff2, aff1, aff0; uint64_t sgi_val; /* Verify interrupt number is in the SGI range */ assert((sgi_num >= MIN_SGI_ID) && (sgi_num < MIN_PPI_ID)); /* Extract affinity fields from target */ aff0 = MPIDR_AFFLVL0_VAL(target); aff1 = MPIDR_AFFLVL1_VAL(target); aff2 = MPIDR_AFFLVL2_VAL(target); aff3 = MPIDR_AFFLVL3_VAL(target); /* * Make target list from affinity 0, and ensure GICv3 SGI can target * this PE. */ assert(aff0 < GICV3_MAX_SGI_TARGETS); tgt = BIT_32(aff0); /* Raise SGI to PE specified by its affinity */ sgi_val = GICV3_SGIR_VALUE(aff3, aff2, aff1, sgi_num, SGIR_IRM_TO_AFF, tgt); /* * Ensure that any shared variable updates depending on out of band * interrupt trigger are observed before raising SGI. */ dsbishst(); write_icc_sgi0r_el1(sgi_val); isb(); } /******************************************************************************* * This function sets the interrupt routing for the given SPI interrupt id. * The interrupt routing is specified in routing mode and mpidr. * * The routing mode can be either of: * - GICV3_IRM_ANY * - GICV3_IRM_PE * * The mpidr is the affinity of the PE to which the interrupt will be routed, * and is ignored for routing mode GICV3_IRM_ANY. ******************************************************************************/ void gicv3_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr) { unsigned long long aff; uint64_t router; assert(gicv3_driver_data != NULL); assert(gicv3_driver_data->gicd_base != 0U); assert((irm == GICV3_IRM_ANY) || (irm == GICV3_IRM_PE)); assert((id >= MIN_SPI_ID) && (id <= MAX_SPI_ID)); aff = gicd_irouter_val_from_mpidr(mpidr, irm); gicd_write_irouter(gicv3_driver_data->gicd_base, id, aff); /* * In implementations that do not require 1 of N distribution of SPIs, * IRM might be RAZ/WI. Read back and verify IRM bit. */ if (irm == GICV3_IRM_ANY) { router = gicd_read_irouter(gicv3_driver_data->gicd_base, id); if (((router >> IROUTER_IRM_SHIFT) & IROUTER_IRM_MASK) == 0U) { ERROR("GICv3 implementation doesn't support routing ANY\n"); panic(); } } } /******************************************************************************* * This function clears the pending status of an interrupt identified by id. * The proc_num is used if the interrupt is SGI or PPI, and programs the * corresponding Redistributor interface. ******************************************************************************/ void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num) { assert(gicv3_driver_data != NULL); assert(gicv3_driver_data->gicd_base != 0U); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs != NULL); /* * Clear pending interrupt, and ensure that any shared variable updates * depending on out of band interrupt trigger are observed afterwards. */ if (id < MIN_SPI_ID) { /* For SGIs and PPIs */ gicr_set_icpendr0(gicv3_driver_data->rdistif_base_addrs[proc_num], id); } else { gicd_set_icpendr(gicv3_driver_data->gicd_base, id); } dsbishst(); } /******************************************************************************* * This function sets the pending status of an interrupt identified by id. * The proc_num is used if the interrupt is SGI or PPI and programs the * corresponding Redistributor interface. ******************************************************************************/ void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num) { assert(gicv3_driver_data != NULL); assert(gicv3_driver_data->gicd_base != 0U); assert(proc_num < gicv3_driver_data->rdistif_num); assert(gicv3_driver_data->rdistif_base_addrs != NULL); /* * Ensure that any shared variable updates depending on out of band * interrupt trigger are observed before setting interrupt pending. */ dsbishst(); if (id < MIN_SPI_ID) { /* For SGIs and PPIs */ gicr_set_ispendr0(gicv3_driver_data->rdistif_base_addrs[proc_num], id); } else { gicd_set_ispendr(gicv3_driver_data->gicd_base, id); } } /******************************************************************************* * This function sets the PMR register with the supplied value. Returns the * original PMR. ******************************************************************************/ unsigned int gicv3_set_pmr(unsigned int mask) { unsigned int old_mask; old_mask = (uint32_t) read_icc_pmr_el1(); /* * Order memory updates w.r.t. PMR write, and ensure they're visible * before potential out of band interrupt trigger because of PMR update. * PMR system register writes are self-synchronizing, so no ISB required * thereafter. */ dsbishst(); write_icc_pmr_el1(mask); return old_mask; } /******************************************************************************* * This function delegates the responsibility of discovering the corresponding * Redistributor frames to each CPU itself. It is a modified version of * gicv3_rdistif_base_addrs_probe() and is executed by each CPU in the platform * unlike the previous way in which only the Primary CPU did the discovery of * all the Redistributor frames for every CPU. It also handles the scenario in * which the frames of various CPUs are not contiguous in physical memory. ******************************************************************************/ int gicv3_rdistif_probe(const uintptr_t gicr_frame) { u_register_t mpidr; unsigned int proc_num, proc_self; uint64_t typer_val; uintptr_t rdistif_base; bool gicr_frame_found = false; assert(gicv3_driver_data->gicr_base == 0U); /* Ensure this function is called with Data Cache enabled */ #ifndef __aarch64__ assert((read_sctlr() & SCTLR_C_BIT) != 0U); #else assert((read_sctlr_el3() & SCTLR_C_BIT) != 0U); #endif /* !__aarch64__ */ proc_self = gicv3_driver_data->mpidr_to_core_pos(read_mpidr_el1()); rdistif_base = gicr_frame; do { typer_val = gicr_read_typer(rdistif_base); if (gicv3_driver_data->mpidr_to_core_pos != NULL) { mpidr = mpidr_from_gicr_typer(typer_val); proc_num = gicv3_driver_data->mpidr_to_core_pos(mpidr); } else { proc_num = (unsigned int)(typer_val >> TYPER_PROC_NUM_SHIFT) & TYPER_PROC_NUM_MASK; } if (proc_num == proc_self) { /* The base address doesn't need to be initialized on * every warm boot. */ if (gicv3_driver_data->rdistif_base_addrs[proc_num] != 0U) return 0; gicv3_driver_data->rdistif_base_addrs[proc_num] = rdistif_base; gicr_frame_found = true; break; } rdistif_base += (uintptr_t)(ULL(1) << GICR_PCPUBASE_SHIFT); } while ((typer_val & TYPER_LAST_BIT) == 0U); if (!gicr_frame_found) return -1; /* * Flush the driver data to ensure coherency. This is * not required if platform has HW_ASSISTED_COHERENCY * enabled. */ #if !HW_ASSISTED_COHERENCY /* * Flush the rdistif_base_addrs[] contents linked to the GICv3 driver. */ flush_dcache_range((uintptr_t)&(gicv3_driver_data->rdistif_base_addrs[proc_num]), sizeof(*(gicv3_driver_data->rdistif_base_addrs))); #endif return 0; /* Found matching GICR frame */ } trusted-firmware-a-2.2/drivers/arm/gic/v3/gicv3_private.h000066400000000000000000000275001355360272700233620ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef GICV3_PRIVATE_H #define GICV3_PRIVATE_H #include #include #include #include #include #include "../common/gic_common_private.h" /******************************************************************************* * GICv3 private macro definitions ******************************************************************************/ /* Constants to indicate the status of the RWP bit */ #define RWP_TRUE U(1) #define RWP_FALSE U(0) /* * Macro to convert an mpidr to a value suitable for programming into a * GICD_IROUTER. Bits[31:24] in the MPIDR are cleared as they are not relevant * to GICv3. */ static inline u_register_t gicd_irouter_val_from_mpidr(u_register_t mpidr, unsigned int irm) { return (mpidr & ~(U(0xff) << 24)) | ((irm & IROUTER_IRM_MASK) << IROUTER_IRM_SHIFT); } /* * Macro to convert a GICR_TYPER affinity value into a MPIDR value. Bits[31:24] * are zeroes. */ #ifdef __aarch64__ static inline u_register_t mpidr_from_gicr_typer(uint64_t typer_val) { return (((typer_val >> 56) & MPIDR_AFFLVL_MASK) << MPIDR_AFF3_SHIFT) | ((typer_val >> 32) & U(0xffffff)); } #else static inline u_register_t mpidr_from_gicr_typer(uint64_t typer_val) { return (((typer_val) >> 32) & U(0xffffff)); } #endif /******************************************************************************* * GICv3 private global variables declarations ******************************************************************************/ extern const gicv3_driver_data_t *gicv3_driver_data; /******************************************************************************* * Private GICv3 function prototypes for accessing entire registers. * Note: The raw register values correspond to multiple interrupt IDs and * the number of interrupt IDs involved depends on the register accessed. ******************************************************************************/ unsigned int gicd_read_igrpmodr(uintptr_t base, unsigned int id); unsigned int gicr_read_ipriorityr(uintptr_t base, unsigned int id); void gicd_write_igrpmodr(uintptr_t base, unsigned int id, unsigned int val); void gicr_write_ipriorityr(uintptr_t base, unsigned int id, unsigned int val); /******************************************************************************* * Private GICv3 function prototypes for accessing the GIC registers * corresponding to a single interrupt ID. These functions use bitwise * operations or appropriate register accesses to modify or return * the bit-field corresponding the single interrupt ID. ******************************************************************************/ unsigned int gicd_get_igrpmodr(uintptr_t base, unsigned int id); unsigned int gicr_get_igrpmodr0(uintptr_t base, unsigned int id); unsigned int gicr_get_igroupr0(uintptr_t base, unsigned int id); unsigned int gicr_get_isactiver0(uintptr_t base, unsigned int id); void gicd_set_igrpmodr(uintptr_t base, unsigned int id); void gicr_set_igrpmodr0(uintptr_t base, unsigned int id); void gicr_set_isenabler0(uintptr_t base, unsigned int id); void gicr_set_icenabler0(uintptr_t base, unsigned int id); void gicr_set_ispendr0(uintptr_t base, unsigned int id); void gicr_set_icpendr0(uintptr_t base, unsigned int id); void gicr_set_igroupr0(uintptr_t base, unsigned int id); void gicd_clr_igrpmodr(uintptr_t base, unsigned int id); void gicr_clr_igrpmodr0(uintptr_t base, unsigned int id); void gicr_clr_igroupr0(uintptr_t base, unsigned int id); void gicr_set_ipriorityr(uintptr_t base, unsigned int id, unsigned int pri); void gicr_set_icfgr0(uintptr_t base, unsigned int id, unsigned int cfg); void gicr_set_icfgr1(uintptr_t base, unsigned int id, unsigned int cfg); /******************************************************************************* * Private GICv3 helper function prototypes ******************************************************************************/ void gicv3_spis_config_defaults(uintptr_t gicd_base); void gicv3_ppi_sgi_config_defaults(uintptr_t gicr_base); unsigned int gicv3_secure_ppi_sgi_config_props(uintptr_t gicr_base, const interrupt_prop_t *interrupt_props, unsigned int interrupt_props_num); unsigned int gicv3_secure_spis_config_props(uintptr_t gicd_base, const interrupt_prop_t *interrupt_props, unsigned int interrupt_props_num); void gicv3_rdistif_base_addrs_probe(uintptr_t *rdistif_base_addrs, unsigned int rdistif_num, uintptr_t gicr_base, mpidr_hash_fn mpidr_to_core_pos); void gicv3_rdistif_mark_core_awake(uintptr_t gicr_base); void gicv3_rdistif_mark_core_asleep(uintptr_t gicr_base); /******************************************************************************* * GIC Distributor interface accessors ******************************************************************************/ /* * Wait for updates to : * GICD_CTLR[2:0] - the Group Enables * GICD_CTLR[5:4] - the ARE bits * GICD_ICENABLERn - the clearing of enable state for SPIs */ static inline void gicd_wait_for_pending_write(uintptr_t gicd_base) { while ((gicd_read_ctlr(gicd_base) & GICD_CTLR_RWP_BIT) != 0U) ; } static inline unsigned int gicd_read_pidr2(uintptr_t base) { return mmio_read_32(base + GICD_PIDR2_GICV3); } static inline unsigned long long gicd_read_irouter(uintptr_t base, unsigned int id) { assert(id >= MIN_SPI_ID); return mmio_read_64(base + GICD_IROUTER + (id << 3)); } static inline void gicd_write_irouter(uintptr_t base, unsigned int id, unsigned long long affinity) { assert(id >= MIN_SPI_ID); mmio_write_64(base + GICD_IROUTER + (id << 3), affinity); } static inline void gicd_clr_ctlr(uintptr_t base, unsigned int bitmap, unsigned int rwp) { gicd_write_ctlr(base, gicd_read_ctlr(base) & ~bitmap); if (rwp != 0U) gicd_wait_for_pending_write(base); } static inline void gicd_set_ctlr(uintptr_t base, unsigned int bitmap, unsigned int rwp) { gicd_write_ctlr(base, gicd_read_ctlr(base) | bitmap); if (rwp != 0U) gicd_wait_for_pending_write(base); } /******************************************************************************* * GIC Redistributor interface accessors ******************************************************************************/ static inline uint32_t gicr_read_ctlr(uintptr_t base) { return mmio_read_32(base + GICR_CTLR); } static inline void gicr_write_ctlr(uintptr_t base, uint32_t val) { mmio_write_32(base + GICR_CTLR, val); } static inline unsigned long long gicr_read_typer(uintptr_t base) { return mmio_read_64(base + GICR_TYPER); } static inline unsigned int gicr_read_waker(uintptr_t base) { return mmio_read_32(base + GICR_WAKER); } static inline void gicr_write_waker(uintptr_t base, unsigned int val) { mmio_write_32(base + GICR_WAKER, val); } /* * Wait for updates to : * GICR_ICENABLER0 * GICR_CTLR.DPG1S * GICR_CTLR.DPG1NS * GICR_CTLR.DPG0 */ static inline void gicr_wait_for_pending_write(uintptr_t gicr_base) { while ((gicr_read_ctlr(gicr_base) & GICR_CTLR_RWP_BIT) != 0U) ; } static inline void gicr_wait_for_upstream_pending_write(uintptr_t gicr_base) { while ((gicr_read_ctlr(gicr_base) & GICR_CTLR_UWP_BIT) != 0U) ; } /* Private implementation of Distributor power control hooks */ void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num); void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num); /******************************************************************************* * GIC Re-distributor functions for accessing entire registers. * Note: The raw register values correspond to multiple interrupt IDs and * the number of interrupt IDs involved depends on the register accessed. ******************************************************************************/ static inline unsigned int gicr_read_icenabler0(uintptr_t base) { return mmio_read_32(base + GICR_ICENABLER0); } static inline void gicr_write_icenabler0(uintptr_t base, unsigned int val) { mmio_write_32(base + GICR_ICENABLER0, val); } static inline unsigned int gicr_read_isenabler0(uintptr_t base) { return mmio_read_32(base + GICR_ISENABLER0); } static inline void gicr_write_icpendr0(uintptr_t base, unsigned int val) { mmio_write_32(base + GICR_ICPENDR0, val); } static inline void gicr_write_isenabler0(uintptr_t base, unsigned int val) { mmio_write_32(base + GICR_ISENABLER0, val); } static inline unsigned int gicr_read_igroupr0(uintptr_t base) { return mmio_read_32(base + GICR_IGROUPR0); } static inline unsigned int gicr_read_ispendr0(uintptr_t base) { return mmio_read_32(base + GICR_ISPENDR0); } static inline void gicr_write_ispendr0(uintptr_t base, unsigned int val) { mmio_write_32(base + GICR_ISPENDR0, val); } static inline void gicr_write_igroupr0(uintptr_t base, unsigned int val) { mmio_write_32(base + GICR_IGROUPR0, val); } static inline unsigned int gicr_read_igrpmodr0(uintptr_t base) { return mmio_read_32(base + GICR_IGRPMODR0); } static inline void gicr_write_igrpmodr0(uintptr_t base, unsigned int val) { mmio_write_32(base + GICR_IGRPMODR0, val); } static inline unsigned int gicr_read_nsacr(uintptr_t base) { return mmio_read_32(base + GICR_NSACR); } static inline void gicr_write_nsacr(uintptr_t base, unsigned int val) { mmio_write_32(base + GICR_NSACR, val); } static inline unsigned int gicr_read_isactiver0(uintptr_t base) { return mmio_read_32(base + GICR_ISACTIVER0); } static inline void gicr_write_isactiver0(uintptr_t base, unsigned int val) { mmio_write_32(base + GICR_ISACTIVER0, val); } static inline unsigned int gicr_read_icfgr0(uintptr_t base) { return mmio_read_32(base + GICR_ICFGR0); } static inline unsigned int gicr_read_icfgr1(uintptr_t base) { return mmio_read_32(base + GICR_ICFGR1); } static inline void gicr_write_icfgr0(uintptr_t base, unsigned int val) { mmio_write_32(base + GICR_ICFGR0, val); } static inline void gicr_write_icfgr1(uintptr_t base, unsigned int val) { mmio_write_32(base + GICR_ICFGR1, val); } static inline uint64_t gicr_read_propbaser(uintptr_t base) { return mmio_read_64(base + GICR_PROPBASER); } static inline void gicr_write_propbaser(uintptr_t base, uint64_t val) { mmio_write_64(base + GICR_PROPBASER, val); } static inline uint64_t gicr_read_pendbaser(uintptr_t base) { return mmio_read_64(base + GICR_PENDBASER); } static inline void gicr_write_pendbaser(uintptr_t base, uint64_t val) { mmio_write_64(base + GICR_PENDBASER, val); } /******************************************************************************* * GIC ITS functions to read and write entire ITS registers. ******************************************************************************/ static inline uint32_t gits_read_ctlr(uintptr_t base) { return mmio_read_32(base + GITS_CTLR); } static inline void gits_write_ctlr(uintptr_t base, unsigned int val) { mmio_write_32(base + GITS_CTLR, val); } static inline uint64_t gits_read_cbaser(uintptr_t base) { return mmio_read_64(base + GITS_CBASER); } static inline void gits_write_cbaser(uintptr_t base, uint64_t val) { mmio_write_64(base + GITS_CBASER, val); } static inline uint64_t gits_read_cwriter(uintptr_t base) { return mmio_read_64(base + GITS_CWRITER); } static inline void gits_write_cwriter(uintptr_t base, uint64_t val) { mmio_write_64(base + GITS_CWRITER, val); } static inline uint64_t gits_read_baser(uintptr_t base, unsigned int its_table_id) { assert(its_table_id < 8U); return mmio_read_64(base + GITS_BASER + (8U * its_table_id)); } static inline void gits_write_baser(uintptr_t base, unsigned int its_table_id, uint64_t val) { assert(its_table_id < 8U); mmio_write_64(base + GITS_BASER + (8U * its_table_id), val); } /* * Wait for Quiescent bit when GIC ITS is disabled */ static inline void gits_wait_for_quiescent_bit(uintptr_t gits_base) { assert((gits_read_ctlr(gits_base) & GITS_CTLR_ENABLED_BIT) == 0U); while ((gits_read_ctlr(gits_base) & GITS_CTLR_QUIESCENT_BIT) == 0U) ; } #endif /* GICV3_PRIVATE_H */ trusted-firmware-a-2.2/drivers/arm/pl011/000077500000000000000000000000001355360272700202035ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/pl011/aarch32/000077500000000000000000000000001355360272700214265ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/pl011/aarch32/pl011_console.S000066400000000000000000000160651355360272700241410ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* * "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 /* ----------------------------------------------- * int console_core_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. This * function will be accessed by console_init and * crash reporting. * 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, r2, r3 * ----------------------------------------------- */ func console_pl011_core_init /* Check the input base address */ cmp r0, #0 beq core_init_fail #if !PL011_GENERIC_UART /* Check baud rate and uart clock for sanity */ cmp r1, #0 beq core_init_fail cmp r2, #0 beq core_init_fail /* Disable the UART before initialization */ ldr r3, [r0, #UARTCR] bic r3, r3, #PL011_UARTCR_UARTEN str r3, [r0, #UARTCR] /* Program the baudrate */ /* Divisor = (Uart clock * 4) / baudrate */ lsl r1, r1, #2 #if (ARM_ARCH_MAJOR == 7) && !defined(ARMV7_SUPPORTS_VIRTUALIZATION) push {r0,r3} softudiv r0,r1,r2,r3 mov r2, r0 pop {r0,r3} #else udiv r2, r1, r2 #endif /* IBRD = Divisor >> 6 */ lsr r1, r2, #6 /* Write the IBRD */ str r1, [r0, #UARTIBRD] /* FBRD = Divisor & 0x3F */ and r1, r2, #0x3f /* Write the FBRD */ str r1, [r0, #UARTFBRD] mov r1, #PL011_LINE_CONTROL str r1, [r0, #UARTLCR_H] /* Clear any pending errors */ mov r1, #0 str r1, [r0, #UARTECR] /* Enable tx, rx, and uart overall */ ldr r1, =(PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN) str r1, [r0, #UARTCR] #endif mov r0, #1 bx lr core_init_fail: mov r0, #0 bx lr endfunc console_pl011_core_init .globl console_pl011_register /* ------------------------------------------------------- * int console_pl011_register(uintptr_t baseaddr, * uint32_t clock, uint32_t baud, * console_pl011_t *console); * 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 /* -------------------------------------------------------- * 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. * In : r0 - character to be printed * r1 - console base address * Out : return -1 on error else return character. * Clobber list : r2 * -------------------------------------------------------- */ func console_pl011_core_putc /* Check the input parameter */ cmp r1, #0 beq putc_error /* Prepend '\r' to '\n' */ cmp r0, #0xA bne 2f 1: /* Check if the transmit FIFO is full */ ldr r2, [r1, #UARTFR] tst r2, #PL011_UARTFR_TXFF bne 1b mov r2, #0xD str r2, [r1, #UARTDR] 2: /* Check if the transmit FIFO is full */ ldr r2, [r1, #UARTFR] tst r2, #PL011_UARTFR_TXFF bne 2b str r0, [r1, #UARTDR] bx lr putc_error: mov r0, #-1 bx lr 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) * Function to get a character from the console. * It returns the character grabbed on success * or -1 on error. * In : r0 - console base address * Clobber list : r0, r1 * --------------------------------------------- */ func console_pl011_core_getc cmp r0, #0 beq getc_error 1: /* Check if the receive FIFO is empty */ ldr r1, [r0, #UARTFR] tst r1, #PL011_UARTFR_RXFE bne 1b ldr r1, [r0, #UARTDR] mov r0, r1 bx lr getc_error: mov r0, #-1 bx lr 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) * Function to force a write of all buffered * data that hasn't been output. * In : r0 - console base address * Out : return -1 on error else return 0. * Clobber list : r0, r1 * --------------------------------------------- */ func console_pl011_core_flush cmp r0, #0 beq flush_error 1: /* Loop while the transmit FIFO is busy */ ldr r1, [r0, #UARTFR] tst r1, #PL011_UARTFR_BUSY bne 1b mov r0, #0 bx lr flush_error: mov r0, #-1 bx lr 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 trusted-firmware-a-2.2/drivers/arm/pl011/aarch64/000077500000000000000000000000001355360272700214335ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/pl011/aarch64/pl011_console.S000066400000000000000000000160221355360272700241370ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* * "core" functions are low-level implementations that don't require * writable 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 /* ----------------------------------------------- * int console_pl011_core_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. This * function will be accessed by console_init and * crash reporting. * In: x0 - console base address * w1 - Uart clock in Hz * w2 - Baud rate * Out: return 1 on success else 0 on error * Clobber list : x1, x2, x3, x4 * ----------------------------------------------- */ func console_pl011_core_init /* Check the input base address */ cbz x0, core_init_fail #if !PL011_GENERIC_UART /* Check baud rate and uart clock for sanity */ cbz w1, core_init_fail cbz w2, core_init_fail /* Disable uart before programming */ ldr w3, [x0, #UARTCR] mov w4, #PL011_UARTCR_UARTEN bic w3, w3, w4 str w3, [x0, #UARTCR] /* Program the baudrate */ /* Divisor = (Uart clock * 4) / baudrate */ lsl w1, w1, #2 udiv w2, w1, w2 /* IBRD = Divisor >> 6 */ lsr w1, w2, #6 /* Write the IBRD */ str w1, [x0, #UARTIBRD] /* FBRD = Divisor & 0x3F */ and w1, w2, #0x3f /* Write the FBRD */ str w1, [x0, #UARTFBRD] mov w1, #PL011_LINE_CONTROL str w1, [x0, #UARTLCR_H] /* Clear any pending errors */ str wzr, [x0, #UARTECR] /* Enable tx, rx, and uart overall */ mov w1, #(PL011_UARTCR_RXE | PL011_UARTCR_TXE | PL011_UARTCR_UARTEN) str w1, [x0, #UARTCR] #endif mov w0, #1 ret core_init_fail: mov w0, wzr ret endfunc console_pl011_core_init .globl console_pl011_register /* ----------------------------------------------- * int console_pl011_register(uintptr_t baseaddr, * uint32_t clock, uint32_t baud, * console_pl011_t *console); * 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: x0 - UART register base address * w1 - UART clock in Hz * w2 - Baud rate * x3 - pointer to empty console_pl011_t struct * Out: return 1 on success, 0 on error * Clobber list : x0, x1, x2, x6, x7, x14 * ----------------------------------------------- */ func console_pl011_register mov x7, x30 mov x6, x3 cbz x6, register_fail str x0, [x6, #CONSOLE_T_PL011_BASE] bl console_pl011_core_init cbz x0, register_fail mov x0, x6 mov x30, x7 finish_console_register pl011 putc=1, getc=1, flush=1 register_fail: ret x7 endfunc console_pl011_register /* -------------------------------------------------------- * int console_pl011_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. * In : w0 - character to be printed * x1 - console base address * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_pl011_core_putc #if ENABLE_ASSERTIONS cmp x1, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ /* Prepend '\r' to '\n' */ cmp w0, #0xA b.ne 2f 1: /* Check if the transmit FIFO is full */ ldr w2, [x1, #UARTFR] tbnz w2, #PL011_UARTFR_TXFF_BIT, 1b mov w2, #0xD str w2, [x1, #UARTDR] 2: /* Check if the transmit FIFO is full */ ldr w2, [x1, #UARTFR] tbnz w2, #PL011_UARTFR_TXFF_BIT, 2b str w0, [x1, #UARTDR] ret 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 : w0 - character to be printed * x1 - pointer to console_t structure * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_pl011_putc #if ENABLE_ASSERTIONS cmp x1, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr x1, [x1, #CONSOLE_T_PL011_BASE] b console_pl011_core_putc endfunc console_pl011_putc /* --------------------------------------------- * int console_pl011_core_getc(uintptr_t base_addr) * Function to get a character from the console. * It returns the character grabbed on success * or -1 if no character is available. * In : x0 - console base address * Out: w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ func console_pl011_core_getc #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ /* Check if the receive FIFO is empty */ ldr w1, [x0, #UARTFR] tbnz w1, #PL011_UARTFR_RXFE_BIT, no_char ldr w1, [x0, #UARTDR] mov w0, w1 ret no_char: mov w0, #ERROR_NO_PENDING_CHAR ret 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 : x0 - pointer to console_t structure * Out: w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ func console_pl011_getc #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr x0, [x0, #CONSOLE_T_PL011_BASE] b console_pl011_core_getc endfunc console_pl011_getc /* --------------------------------------------- * int console_pl011_core_flush(uintptr_t base_addr) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - console base address * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func console_pl011_core_flush #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ 1: /* Loop until the transmit FIFO is empty */ ldr w1, [x0, #UARTFR] tbnz w1, #PL011_UARTFR_BUSY_BIT, 1b mov w0, #0 ret 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 : x0 - pointer to console_t structure * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func console_pl011_flush #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr x0, [x0, #CONSOLE_T_PL011_BASE] b console_pl011_core_flush endfunc console_pl011_flush trusted-firmware-a-2.2/drivers/arm/pl061/000077500000000000000000000000001355360272700202105ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/pl061/pl061_gpio.c000066400000000000000000000073731355360272700222460ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * * ARM PL061 GPIO Driver. * Reference to ARM DDI 0190B document. * */ #include #include #include #include #include #include #include #include #if !PLAT_PL061_MAX_GPIOS # define PLAT_PL061_MAX_GPIOS 32 #endif /* PLAT_PL061_MAX_GPIOS */ CASSERT(PLAT_PL061_MAX_GPIOS > 0, assert_plat_pl061_max_gpios); #define MAX_GPIO_DEVICES ((PLAT_PL061_MAX_GPIOS + \ (GPIOS_PER_PL061 - 1)) / GPIOS_PER_PL061) #define PL061_GPIO_DIR 0x400 #define GPIOS_PER_PL061 8 static int pl061_get_direction(int gpio); static void pl061_set_direction(int gpio, int direction); static int pl061_get_value(int gpio); static void pl061_set_value(int gpio, int value); static uintptr_t pl061_reg_base[MAX_GPIO_DEVICES]; static const gpio_ops_t pl061_gpio_ops = { .get_direction = pl061_get_direction, .set_direction = pl061_set_direction, .get_value = pl061_get_value, .set_value = pl061_set_value, }; static int pl061_get_direction(int gpio) { uintptr_t base_addr; unsigned int data, offset; assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS)); base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061]; offset = gpio % GPIOS_PER_PL061; data = mmio_read_8(base_addr + PL061_GPIO_DIR); if (data & BIT(offset)) return GPIO_DIR_OUT; return GPIO_DIR_IN; } static void pl061_set_direction(int gpio, int direction) { uintptr_t base_addr; unsigned int data, offset; assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS)); base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061]; offset = gpio % GPIOS_PER_PL061; if (direction == GPIO_DIR_OUT) { data = mmio_read_8(base_addr + PL061_GPIO_DIR) | BIT(offset); mmio_write_8(base_addr + PL061_GPIO_DIR, data); } else { data = mmio_read_8(base_addr + PL061_GPIO_DIR) & ~BIT(offset); mmio_write_8(base_addr + PL061_GPIO_DIR, data); } } /* * The offset of GPIODATA register is 0. * The values read from GPIODATA are determined for each bit, by the mask bit * derived from the address used to access the data register, PADDR[9:2]. * Bits that are 1 in the address mask cause the corresponding bits in GPIODATA * to be read, and bits that are 0 in the address mask cause the corresponding * bits in GPIODATA to be read as 0, regardless of their value. */ static int pl061_get_value(int gpio) { uintptr_t base_addr; unsigned int offset; assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS)); base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061]; offset = gpio % GPIOS_PER_PL061; if (mmio_read_8(base_addr + BIT(offset + 2))) return GPIO_LEVEL_HIGH; return GPIO_LEVEL_LOW; } /* * In order to write GPIODATA, the corresponding bits in the mask, resulting * from the address bus, PADDR[9:2], must be HIGH. Otherwise the bit values * remain unchanged by the write. */ static void pl061_set_value(int gpio, int value) { uintptr_t base_addr; int offset; assert((gpio >= 0) && (gpio < PLAT_PL061_MAX_GPIOS)); base_addr = pl061_reg_base[gpio / GPIOS_PER_PL061]; offset = gpio % GPIOS_PER_PL061; if (value == GPIO_LEVEL_HIGH) mmio_write_8(base_addr + BIT(offset + 2), BIT(offset)); else mmio_write_8(base_addr + BIT(offset + 2), 0); } /* * Register the PL061 GPIO controller with a base address and the offset * of start pin in this GPIO controller. * This function is called after pl061_gpio_ops_init(). */ void pl061_gpio_register(uintptr_t base_addr, int gpio_dev) { assert((gpio_dev >= 0) && (gpio_dev < MAX_GPIO_DEVICES)); pl061_reg_base[gpio_dev] = base_addr; } /* * Initialize PL061 GPIO controller with the total GPIO numbers in SoC. */ void pl061_gpio_init(void) { gpio_init(&pl061_gpio_ops); } trusted-firmware-a-2.2/drivers/arm/sbsa/000077500000000000000000000000001355360272700202765ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/sbsa/sbsa.c000066400000000000000000000021311355360272700213670ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include void sbsa_watchdog_offset_reg_write(uintptr_t base, uint64_t value) { assert((value >> SBSA_WDOG_WOR_WIDTH) == 0); mmio_write_32(base + SBSA_WDOG_WOR_LOW_OFFSET, ((uint32_t)value & UINT32_MAX)); mmio_write_32(base + SBSA_WDOG_WOR_HIGH_OFFSET, (uint32_t)(value >> 32)); } /* * Start the watchdog timer at base address "base" for a * period of "ms" milliseconds.The watchdog has to be * refreshed within this time period. */ void sbsa_wdog_start(uintptr_t base, uint64_t ms) { uint64_t counter_freq; uint64_t offset_reg_value; counter_freq = (uint64_t)plat_get_syscnt_freq2(); offset_reg_value = ms * counter_freq / 1000; sbsa_watchdog_offset_reg_write(base, offset_reg_value); mmio_write_32(base + SBSA_WDOG_WCS_OFFSET, SBSA_WDOG_WCS_EN); } /* Stop the watchdog */ void sbsa_wdog_stop(uintptr_t base) { mmio_write_32(base + SBSA_WDOG_WCS_OFFSET, (0x0)); } trusted-firmware-a-2.2/drivers/arm/smmu/000077500000000000000000000000001355360272700203275ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/smmu/smmu_v3.c000066400000000000000000000050431355360272700220660ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /* SMMU poll number of retries */ #define SMMU_POLL_RETRY 1000000 static int __init smmuv3_poll(uintptr_t smmu_reg, uint32_t mask, uint32_t value) { uint32_t reg_val, retries = SMMU_POLL_RETRY; do { reg_val = mmio_read_32(smmu_reg); if ((reg_val & mask) == value) return 0; } while (--retries != 0U); ERROR("Failed to poll SMMUv3 register @%p\n", (void *)smmu_reg); ERROR("Read value 0x%x, expected 0x%x\n", reg_val, value == 0U ? reg_val & ~mask : reg_val | mask); return -1; } /* * Abort all incoming transactions in order to implement a default * deny policy on reset. */ int __init smmuv3_security_init(uintptr_t smmu_base) { /* Attribute update has completed when SMMU_(S)_GBPA.Update bit is 0 */ if (smmuv3_poll(smmu_base + SMMU_GBPA, SMMU_GBPA_UPDATE, 0U) != 0U) return -1; /* * SMMU_(S)_CR0 resets to zero with all streams bypassing the SMMU, * so just abort all incoming transactions. */ mmio_setbits_32(smmu_base + SMMU_GBPA, SMMU_GBPA_UPDATE | SMMU_GBPA_ABORT); if (smmuv3_poll(smmu_base + SMMU_GBPA, SMMU_GBPA_UPDATE, 0U) != 0U) return -1; /* Check if the SMMU supports secure state */ if ((mmio_read_32(smmu_base + SMMU_S_IDR1) & SMMU_S_IDR1_SECURE_IMPL) == 0U) return 0; /* Abort all incoming secure transactions */ if (smmuv3_poll(smmu_base + SMMU_S_GBPA, SMMU_S_GBPA_UPDATE, 0U) != 0U) return -1; mmio_setbits_32(smmu_base + SMMU_S_GBPA, SMMU_S_GBPA_UPDATE | SMMU_S_GBPA_ABORT); return smmuv3_poll(smmu_base + SMMU_S_GBPA, SMMU_S_GBPA_UPDATE, 0U); } /* * Initialize the SMMU by invalidating all secure caches and TLBs. * Abort all incoming transactions in order to implement a default * deny policy on reset */ int __init smmuv3_init(uintptr_t smmu_base) { /* Abort all incoming transactions */ if (smmuv3_security_init(smmu_base) != 0) return -1; /* Check if the SMMU supports secure state */ if ((mmio_read_32(smmu_base + SMMU_S_IDR1) & SMMU_S_IDR1_SECURE_IMPL) == 0U) return 0; /* * Initiate invalidation of secure caches and TLBs if the SMMU * supports secure state. If not, it's implementation defined * as to how SMMU_S_INIT register is accessed. */ mmio_write_32(smmu_base + SMMU_S_INIT, SMMU_S_INIT_INV_ALL); /* Wait for global invalidation operation to finish */ return smmuv3_poll(smmu_base + SMMU_S_INIT, SMMU_S_INIT_INV_ALL, 0U); } trusted-firmware-a-2.2/drivers/arm/sp804/000077500000000000000000000000001355360272700202245ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/sp804/sp804_delay_timer.c000066400000000000000000000033461355360272700236320ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include uintptr_t sp804_base_addr; #define SP804_TIMER1_LOAD (sp804_base_addr + 0x000) #define SP804_TIMER1_VALUE (sp804_base_addr + 0x004) #define SP804_TIMER1_CONTROL (sp804_base_addr + 0x008) #define SP804_TIMER1_BGLOAD (sp804_base_addr + 0x018) #define TIMER_CTRL_ONESHOT (1 << 0) #define TIMER_CTRL_32BIT (1 << 1) #define TIMER_CTRL_DIV1 (0 << 2) #define TIMER_CTRL_DIV16 (1 << 2) #define TIMER_CTRL_DIV256 (2 << 2) #define TIMER_CTRL_IE (1 << 5) #define TIMER_CTRL_PERIODIC (1 << 6) #define TIMER_CTRL_ENABLE (1 << 7) /******************************************************************** * The SP804 timer delay function ********************************************************************/ uint32_t sp804_get_timer_value(void) { return mmio_read_32(SP804_TIMER1_VALUE); } /******************************************************************** * Initialize the 1st timer in the SP804 dual timer with a base * address and a timer ops ********************************************************************/ void sp804_timer_ops_init(uintptr_t base_addr, const timer_ops_t *ops) { assert(base_addr != 0); assert(ops != 0 && ops->get_timer_value == sp804_get_timer_value); sp804_base_addr = base_addr; timer_init(ops); /* disable timer1 */ mmio_write_32(SP804_TIMER1_CONTROL, 0); mmio_write_32(SP804_TIMER1_LOAD, UINT32_MAX); mmio_write_32(SP804_TIMER1_VALUE, UINT32_MAX); /* enable as a free running 32-bit counter */ mmio_write_32(SP804_TIMER1_CONTROL, TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE); } trusted-firmware-a-2.2/drivers/arm/sp805/000077500000000000000000000000001355360272700202255ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/sp805/sp805.c000066400000000000000000000022401355360272700212460ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /* Inline register access functions */ static inline void sp805_write_wdog_load(uintptr_t base, uint32_t value) { mmio_write_32(base + SP805_WDOG_LOAD_OFF, value); } static inline void sp805_write_wdog_ctrl(uintptr_t base, uint32_t value) { mmio_write_32(base + SP805_WDOG_CTR_OFF, value); } static inline void sp805_write_wdog_lock(uintptr_t base, uint32_t value) { mmio_write_32(base + SP805_WDOG_LOCK_OFF, value); } /* Public API implementation */ void sp805_start(uintptr_t base, unsigned int ticks) { sp805_write_wdog_load(base, ticks); sp805_write_wdog_ctrl(base, SP805_CTR_RESEN | SP805_CTR_INTEN); /* Lock registers access */ sp805_write_wdog_lock(base, 0U); } void sp805_stop(uintptr_t base) { sp805_write_wdog_lock(base, WDOG_UNLOCK_KEY); sp805_write_wdog_ctrl(base, 0U); } void sp805_refresh(uintptr_t base, unsigned int ticks) { sp805_write_wdog_lock(base, WDOG_UNLOCK_KEY); sp805_write_wdog_load(base, ticks); sp805_write_wdog_lock(base, 0U); } trusted-firmware-a-2.2/drivers/arm/tzc/000077500000000000000000000000001355360272700201465ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/arm/tzc/tzc380.c000066400000000000000000000046171355360272700213550ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include struct tzc380_instance { uintptr_t base; uint8_t addr_width; uint8_t num_regions; }; struct tzc380_instance tzc380; static unsigned int tzc380_read_build_config(uintptr_t base) { return mmio_read_32(base + TZC380_CONFIGURATION_OFF); } static void tzc380_write_action(uintptr_t base, unsigned int action) { mmio_write_32(base + ACTION_OFF, action); } static void tzc380_write_region_base_low(uintptr_t base, unsigned int region, unsigned int val) { mmio_write_32(base + REGION_SETUP_LOW_OFF(region), val); } static void tzc380_write_region_base_high(uintptr_t base, unsigned int region, unsigned int val) { mmio_write_32(base + REGION_SETUP_HIGH_OFF(region), val); } static void tzc380_write_region_attributes(uintptr_t base, unsigned int region, unsigned int val) { mmio_write_32(base + REGION_ATTRIBUTES_OFF(region), val); } void tzc380_init(uintptr_t base) { unsigned int tzc_build; assert(base != 0U); tzc380.base = base; /* Save values we will use later. */ tzc_build = tzc380_read_build_config(tzc380.base); tzc380.addr_width = ((tzc_build >> BUILD_CONFIG_AW_SHIFT) & BUILD_CONFIG_AW_MASK) + 1; tzc380.num_regions = ((tzc_build >> BUILD_CONFIG_NR_SHIFT) & BUILD_CONFIG_NR_MASK) + 1; } static uint32_t addr_low(uintptr_t addr) { return (uint32_t)addr; } static uint32_t addr_high(uintptr_t addr __unused) { #if (UINTPTR_MAX == UINT64_MAX) return addr >> 32; #else return 0; #endif } /* * `tzc380_configure_region` is used to program regions into the TrustZone * controller. */ void tzc380_configure_region(uint8_t region, uintptr_t region_base, unsigned int attr) { assert(tzc380.base != 0U); assert(region < tzc380.num_regions); tzc380_write_region_base_low(tzc380.base, region, addr_low(region_base)); tzc380_write_region_base_high(tzc380.base, region, addr_high(region_base)); tzc380_write_region_attributes(tzc380.base, region, attr); } void tzc380_set_action(unsigned int action) { assert(tzc380.base != 0U); /* * - Currently no handler is provided to trap an error via interrupt * or exception. * - The interrupt action has not been tested. */ tzc380_write_action(tzc380.base, action); } trusted-firmware-a-2.2/drivers/arm/tzc/tzc400.c000066400000000000000000000150111355360272700213340ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "tzc_common_private.h" /* * Macros which will be used by common core functions. */ #define TZC_400_REGION_BASE_LOW_0_OFFSET U(0x100) #define TZC_400_REGION_BASE_HIGH_0_OFFSET U(0x104) #define TZC_400_REGION_TOP_LOW_0_OFFSET U(0x108) #define TZC_400_REGION_TOP_HIGH_0_OFFSET U(0x10c) #define TZC_400_REGION_ATTR_0_OFFSET U(0x110) #define TZC_400_REGION_ID_ACCESS_0_OFFSET U(0x114) /* * Implementation defined values used to validate inputs later. * Filters : max of 4 ; 0 to 3 * Regions : max of 9 ; 0 to 8 * Address width : Values between 32 to 64 */ typedef struct tzc400_instance { uintptr_t base; uint8_t addr_width; uint8_t num_filters; uint8_t num_regions; } tzc400_instance_t; static tzc400_instance_t tzc400; static inline unsigned int _tzc400_read_build_config(uintptr_t base) { return mmio_read_32(base + BUILD_CONFIG_OFF); } static inline unsigned int _tzc400_read_gate_keeper(uintptr_t base) { return mmio_read_32(base + GATE_KEEPER_OFF); } static inline void _tzc400_write_gate_keeper(uintptr_t base, unsigned int val) { mmio_write_32(base + GATE_KEEPER_OFF, val); } /* * Get the open status information for all filter units. */ #define get_gate_keeper_os(_base) ((_tzc400_read_gate_keeper(_base) >> \ GATE_KEEPER_OS_SHIFT) & \ GATE_KEEPER_OS_MASK) /* Define common core functions used across different TZC peripherals. */ DEFINE_TZC_COMMON_WRITE_ACTION(400, 400) DEFINE_TZC_COMMON_WRITE_REGION_BASE(400, 400) DEFINE_TZC_COMMON_WRITE_REGION_TOP(400, 400) DEFINE_TZC_COMMON_WRITE_REGION_ATTRIBUTES(400, 400) DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(400, 400) DEFINE_TZC_COMMON_CONFIGURE_REGION0(400) DEFINE_TZC_COMMON_CONFIGURE_REGION(400) static unsigned int _tzc400_get_gate_keeper(uintptr_t base, unsigned int filter) { unsigned int open_status; open_status = get_gate_keeper_os(base); return (open_status >> filter) & GATE_KEEPER_FILTER_MASK; } /* This function is not MP safe. */ static void _tzc400_set_gate_keeper(uintptr_t base, unsigned int filter, int val) { unsigned int open_status; /* Upper half is current state. Lower half is requested state. */ open_status = get_gate_keeper_os(base); if (val != 0) open_status |= (1U << filter); else open_status &= ~(1U << filter); _tzc400_write_gate_keeper(base, (open_status & GATE_KEEPER_OR_MASK) << GATE_KEEPER_OR_SHIFT); /* Wait here until we see the change reflected in the TZC status. */ while ((get_gate_keeper_os(base)) != open_status) ; } void tzc400_set_action(unsigned int action) { assert(tzc400.base != 0U); assert(action <= TZC_ACTION_ERR_INT); /* * - Currently no handler is provided to trap an error via interrupt * or exception. * - The interrupt action has not been tested. */ _tzc400_write_action(tzc400.base, action); } void tzc400_init(uintptr_t base) { #if DEBUG unsigned int tzc400_id; #endif unsigned int tzc400_build; assert(base != 0U); tzc400.base = base; #if DEBUG tzc400_id = _tzc_read_peripheral_id(base); if (tzc400_id != TZC_400_PERIPHERAL_ID) { ERROR("TZC-400 : Wrong device ID (0x%x).\n", tzc400_id); panic(); } #endif /* Save values we will use later. */ tzc400_build = _tzc400_read_build_config(tzc400.base); tzc400.num_filters = (uint8_t)((tzc400_build >> BUILD_CONFIG_NF_SHIFT) & BUILD_CONFIG_NF_MASK) + 1U; tzc400.addr_width = (uint8_t)((tzc400_build >> BUILD_CONFIG_AW_SHIFT) & BUILD_CONFIG_AW_MASK) + 1U; tzc400.num_regions = (uint8_t)((tzc400_build >> BUILD_CONFIG_NR_SHIFT) & BUILD_CONFIG_NR_MASK) + 1U; } /* * `tzc400_configure_region0` is used to program region 0 into the TrustZone * controller. Region 0 covers the whole address space that is not mapped * to any other region, and is enabled on all filters; this cannot be * changed. This function only changes the access permissions. */ void tzc400_configure_region0(unsigned int sec_attr, unsigned int ns_device_access) { assert(tzc400.base != 0U); assert(sec_attr <= TZC_REGION_S_RDWR); _tzc400_configure_region0(tzc400.base, sec_attr, ns_device_access); } /* * `tzc400_configure_region` is used to program regions into the TrustZone * controller. A region can be associated with more than one filter. The * associated filters are passed in as a bitmap (bit0 = filter0). * NOTE: * Region 0 is special; it is preferable to use tzc400_configure_region0 * for this region (see comment for that function). */ void tzc400_configure_region(unsigned int filters, unsigned int region, unsigned long long region_base, unsigned long long region_top, unsigned int sec_attr, unsigned int nsaid_permissions) { assert(tzc400.base != 0U); /* Do range checks on filters and regions. */ assert(((filters >> tzc400.num_filters) == 0U) && (region < tzc400.num_regions)); /* * Do address range check based on TZC configuration. A 64bit address is * the max and expected case. */ assert((region_top <= (UINT64_MAX >> (64U - tzc400.addr_width))) && (region_base < region_top)); /* region_base and (region_top + 1) must be 4KB aligned */ assert(((region_base | (region_top + 1U)) & (4096U - 1U)) == 0U); assert(sec_attr <= TZC_REGION_S_RDWR); _tzc400_configure_region(tzc400.base, filters, region, region_base, region_top, sec_attr, nsaid_permissions); } void tzc400_enable_filters(void) { unsigned int state; unsigned int filter; assert(tzc400.base != 0U); for (filter = 0U; filter < tzc400.num_filters; filter++) { state = _tzc400_get_gate_keeper(tzc400.base, filter); if (state != 0U) { /* * The TZC filter is already configured. Changing the * programmer's view in an active system can cause * unpredictable behavior therefore panic for now rather * than try to determine whether this is safe in this * instance. * * See the 'ARM (R) CoreLink TM TZC-400 TrustZone (R) * Address Space Controller' Technical Reference Manual. */ ERROR("TZC-400 : Filter %d Gatekeeper already" " enabled.\n", filter); panic(); } _tzc400_set_gate_keeper(tzc400.base, filter, 1); } } void tzc400_disable_filters(void) { unsigned int filter; assert(tzc400.base != 0U); /* * We don't do the same state check as above as the Gatekeepers are * disabled after reset. */ for (filter = 0; filter < tzc400.num_filters; filter++) _tzc400_set_gate_keeper(tzc400.base, filter, 0); } trusted-firmware-a-2.2/drivers/arm/tzc/tzc_common_private.h000066400000000000000000000133751355360272700242320ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TZC_COMMON_PRIVATE_H #define TZC_COMMON_PRIVATE_H #include #include #include #include #define DEFINE_TZC_COMMON_WRITE_ACTION(fn_name, macro_name) \ static inline void _tzc##fn_name##_write_action( \ uintptr_t base, \ unsigned int action) \ { \ mmio_write_32(base + TZC_##macro_name##_ACTION_OFF, \ action); \ } #define DEFINE_TZC_COMMON_WRITE_REGION_BASE(fn_name, macro_name) \ static inline void _tzc##fn_name##_write_region_base( \ uintptr_t base, \ unsigned int region_no, \ unsigned long long region_base) \ { \ mmio_write_32(base + \ TZC_REGION_OFFSET( \ TZC_##macro_name##_REGION_SIZE, \ region_no) + \ TZC_##macro_name##_REGION_BASE_LOW_0_OFFSET, \ (uint32_t)region_base); \ mmio_write_32(base + \ TZC_REGION_OFFSET( \ TZC_##macro_name##_REGION_SIZE, \ region_no) + \ TZC_##macro_name##_REGION_BASE_HIGH_0_OFFSET, \ (uint32_t)(region_base >> 32)); \ } #define DEFINE_TZC_COMMON_WRITE_REGION_TOP(fn_name, macro_name) \ static inline void _tzc##fn_name##_write_region_top( \ uintptr_t base, \ unsigned int region_no, \ unsigned long long region_top) \ { \ mmio_write_32(base + \ TZC_REGION_OFFSET \ (TZC_##macro_name##_REGION_SIZE, \ region_no) + \ TZC_##macro_name##_REGION_TOP_LOW_0_OFFSET, \ (uint32_t)region_top); \ mmio_write_32(base + \ TZC_REGION_OFFSET( \ TZC_##macro_name##_REGION_SIZE, \ region_no) + \ TZC_##macro_name##_REGION_TOP_HIGH_0_OFFSET, \ (uint32_t)(region_top >> 32)); \ } #define DEFINE_TZC_COMMON_WRITE_REGION_ATTRIBUTES(fn_name, macro_name) \ static inline void _tzc##fn_name##_write_region_attributes( \ uintptr_t base, \ unsigned int region_no, \ unsigned int attr) \ { \ mmio_write_32(base + \ TZC_REGION_OFFSET( \ TZC_##macro_name##_REGION_SIZE, \ region_no) + \ TZC_##macro_name##_REGION_ATTR_0_OFFSET, \ attr); \ } #define DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(fn_name, macro_name) \ static inline void _tzc##fn_name##_write_region_id_access( \ uintptr_t base, \ unsigned int region_no, \ unsigned int val) \ { \ mmio_write_32(base + \ TZC_REGION_OFFSET( \ TZC_##macro_name##_REGION_SIZE, \ region_no) + \ TZC_##macro_name##_REGION_ID_ACCESS_0_OFFSET, \ val); \ } /* * It is used to program region 0 ATTRIBUTES and ACCESS register. */ #define DEFINE_TZC_COMMON_CONFIGURE_REGION0(fn_name) \ static void _tzc##fn_name##_configure_region0(uintptr_t base, \ unsigned int sec_attr, \ unsigned int ns_device_access) \ { \ assert(base != 0U); \ VERBOSE("TrustZone : Configuring region 0 " \ "(TZC Interface Base=0x%lx sec_attr=0x%x," \ " ns_devs=0x%x)\n", base, \ sec_attr, ns_device_access); \ \ /* Set secure attributes on region 0 */ \ _tzc##fn_name##_write_region_attributes(base, 0, \ sec_attr << TZC_REGION_ATTR_SEC_SHIFT); \ \ /***************************************************/ \ /* Specify which non-secure devices have permission*/ \ /* to access region 0. */ \ /***************************************************/ \ _tzc##fn_name##_write_region_id_access(base, \ 0, \ ns_device_access); \ } /* * It is used to program a region from 1 to 8 in the TrustZone controller. * NOTE: * Region 0 is special; it is preferable to use * ##fn_name##_configure_region0 for this region (see comment for * that function). */ #define DEFINE_TZC_COMMON_CONFIGURE_REGION(fn_name) \ static void _tzc##fn_name##_configure_region(uintptr_t base, \ unsigned int filters, \ unsigned int region_no, \ unsigned long long region_base, \ unsigned long long region_top, \ unsigned int sec_attr, \ unsigned int nsaid_permissions) \ { \ assert(base != 0U); \ VERBOSE("TrustZone : Configuring region " \ "(TZC Interface Base: 0x%lx, region_no = %u)" \ "...\n", base, region_no); \ VERBOSE("TrustZone : ... base = %llx, top = %llx," \ "\n", region_base, region_top); \ VERBOSE("TrustZone : ... sec_attr = 0x%x," \ " ns_devs = 0x%x)\n", \ sec_attr, nsaid_permissions); \ \ /***************************************************/ \ /* Inputs look ok, start programming registers. */ \ /* All the address registers are 32 bits wide and */ \ /* have a LOW and HIGH */ \ /* component used to construct an address up to a */ \ /* 64bit. */ \ /***************************************************/ \ _tzc##fn_name##_write_region_base(base, \ region_no, region_base); \ _tzc##fn_name##_write_region_top(base, \ region_no, region_top); \ \ /* Enable filter to the region and set secure attributes */\ _tzc##fn_name##_write_region_attributes(base, \ region_no, \ (sec_attr << TZC_REGION_ATTR_SEC_SHIFT) |\ (filters << TZC_REGION_ATTR_F_EN_SHIFT));\ \ /***************************************************/ \ /* Specify which non-secure devices have permission*/ \ /* to access this region. */ \ /***************************************************/ \ _tzc##fn_name##_write_region_id_access(base, \ region_no, \ nsaid_permissions); \ } static inline unsigned int _tzc_read_peripheral_id(uintptr_t base) { unsigned int id; id = mmio_read_32(base + PID0_OFF); /* Masks DESC part in PID1 */ id |= ((mmio_read_32(base + PID1_OFF) & 0xFU) << 8U); return id; } #endif /* TZC_COMMON_PRIVATE_H */ trusted-firmware-a-2.2/drivers/arm/tzc/tzc_dmc500.c000066400000000000000000000210601355360272700221610ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "tzc_common_private.h" /* * Macros which will be used by common core functions. */ #define TZC_DMC500_REGION_BASE_LOW_0_OFFSET 0x054 #define TZC_DMC500_REGION_BASE_HIGH_0_OFFSET 0x058 #define TZC_DMC500_REGION_TOP_LOW_0_OFFSET 0x05C #define TZC_DMC500_REGION_TOP_HIGH_0_OFFSET 0x060 #define TZC_DMC500_REGION_ATTR_0_OFFSET 0x064 #define TZC_DMC500_REGION_ID_ACCESS_0_OFFSET 0x068 #define TZC_DMC500_ACTION_OFF 0x50 /* Pointer to the tzc_dmc500_driver_data structure populated by the platform */ static const tzc_dmc500_driver_data_t *g_driver_data; static unsigned int g_sys_if_count; #define verify_region_attr(region, attr) \ ((g_conf_regions[(region)].sec_attr == \ ((attr) >> TZC_REGION_ATTR_SEC_SHIFT)) \ && ((attr) & (0x1 << TZC_REGION_ATTR_F_EN_SHIFT))) /* * Structure for configured regions attributes in DMC500. */ typedef struct tzc_dmc500_regions { unsigned int sec_attr; int is_enabled; } tzc_dmc500_regions_t; /* * Array storing the attributes of the configured regions. This array * will be used by the `tzc_dmc500_verify_complete` to verify the flush * completion. */ static tzc_dmc500_regions_t g_conf_regions[MAX_REGION_VAL + 1]; /* Helper Macros for making the code readable */ #define DMC_INST_BASE_ADDR(instance) (g_driver_data->dmc_base[instance]) #define DMC_INST_SI_BASE(instance, interface) \ (DMC_INST_BASE_ADDR(instance) + IFACE_OFFSET(interface)) DEFINE_TZC_COMMON_WRITE_ACTION(_dmc500, DMC500) DEFINE_TZC_COMMON_WRITE_REGION_BASE(_dmc500, DMC500) DEFINE_TZC_COMMON_WRITE_REGION_TOP(_dmc500, DMC500) DEFINE_TZC_COMMON_WRITE_REGION_ATTRIBUTES(_dmc500, DMC500) DEFINE_TZC_COMMON_WRITE_REGION_ID_ACCESS(_dmc500, DMC500) DEFINE_TZC_COMMON_CONFIGURE_REGION0(_dmc500) DEFINE_TZC_COMMON_CONFIGURE_REGION(_dmc500) static inline unsigned int _tzc_dmc500_read_region_attr_0( uintptr_t dmc_si_base, unsigned int region_no) { return mmio_read_32(dmc_si_base + TZC_REGION_OFFSET(TZC_DMC500_REGION_SIZE, region_no) + TZC_DMC500_REGION_ATTR_0_OFFSET); } static inline void _tzc_dmc500_write_flush_control(uintptr_t dmc_si_base) { mmio_write_32(dmc_si_base + SI_FLUSH_CTRL_OFFSET, 1); } /* * Sets the Flush controls for all the DMC Instances and System Interfaces. * This initiates the flush of configuration settings from the shadow * registers to the actual configuration register. The caller should poll * changed register to confirm update. */ void tzc_dmc500_config_complete(void) { int dmc_inst, sys_if; assert(g_driver_data); for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) { assert(DMC_INST_BASE_ADDR(dmc_inst)); for (sys_if = 0; sys_if < g_sys_if_count; sys_if++) _tzc_dmc500_write_flush_control( DMC_INST_SI_BASE(dmc_inst, sys_if)); } } /* * This function reads back the secure attributes from the configuration * register for each DMC Instance and System Interface and compares it with * the configured value. The successful verification of the region attributes * confirms that the flush operation has completed. * If the verification fails, the caller is expected to invoke this API again * till it succeeds. * Returns 0 on success and 1 on failure. */ int tzc_dmc500_verify_complete(void) { int dmc_inst, sys_if, region_no; unsigned int attr; assert(g_driver_data); /* Region 0 must be configured */ assert(g_conf_regions[0].is_enabled); /* Iterate over all configured regions */ for (region_no = 0; region_no <= MAX_REGION_VAL; region_no++) { if (!g_conf_regions[region_no].is_enabled) continue; for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) { assert(DMC_INST_BASE_ADDR(dmc_inst)); for (sys_if = 0; sys_if < g_sys_if_count; sys_if++) { attr = _tzc_dmc500_read_region_attr_0( DMC_INST_SI_BASE(dmc_inst, sys_if), region_no); VERBOSE("Verifying DMC500 region:%d" " dmc_inst:%d sys_if:%d attr:%x\n", region_no, dmc_inst, sys_if, attr); if (!verify_region_attr(region_no, attr)) return 1; } } } return 0; } /* * `tzc_dmc500_configure_region0` is used to program region 0 in both the * system interfaces of all the DMC-500 instances. Region 0 covers the whole * address space that is not mapped to any other region for a system interface, * and is always enabled; this cannot be changed. This function only changes * the access permissions. */ void tzc_dmc500_configure_region0(unsigned int sec_attr, unsigned int nsaid_permissions) { int dmc_inst, sys_if; /* Assert if DMC-500 is not initialized */ assert(g_driver_data); /* Configure region_0 in all DMC instances */ for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) { assert(DMC_INST_BASE_ADDR(dmc_inst)); for (sys_if = 0; sys_if < g_sys_if_count; sys_if++) _tzc_dmc500_configure_region0( DMC_INST_SI_BASE(dmc_inst, sys_if), sec_attr, nsaid_permissions); } g_conf_regions[0].sec_attr = sec_attr; g_conf_regions[0].is_enabled = 1; } /* * `tzc_dmc500_configure_region` is used to program a region into all system * interfaces of all the DMC instances. * NOTE: * Region 0 is special; it is preferable to use tzc_dmc500_configure_region0 * for this region (see comment for that function). */ void tzc_dmc500_configure_region(unsigned int region_no, unsigned long long region_base, unsigned long long region_top, unsigned int sec_attr, unsigned int nsaid_permissions) { int dmc_inst, sys_if; assert(g_driver_data); /* Do range checks on regions. */ assert((region_no >= 0U) && (region_no <= MAX_REGION_VAL)); /* * Do address range check based on DMC-TZ configuration. A 43bit address * is the max and expected case. */ assert(((region_top <= (UINT64_MAX >> (64U - 43U))) && (region_base < region_top))); /* region_base and (region_top + 1) must be 4KB aligned */ assert(((region_base | (region_top + 1U)) & (4096U - 1U)) == 0U); for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) { assert(DMC_INST_BASE_ADDR(dmc_inst)); for (sys_if = 0; sys_if < g_sys_if_count; sys_if++) _tzc_dmc500_configure_region( DMC_INST_SI_BASE(dmc_inst, sys_if), TZC_DMC500_REGION_ATTR_F_EN_MASK, region_no, region_base, region_top, sec_attr, nsaid_permissions); } g_conf_regions[region_no].sec_attr = sec_attr; g_conf_regions[region_no].is_enabled = 1; } /* Sets the action value for all the DMC instances */ void tzc_dmc500_set_action(unsigned int action) { int dmc_inst; assert(g_driver_data); for (dmc_inst = 0; dmc_inst < g_driver_data->dmc_count; dmc_inst++) { assert(DMC_INST_BASE_ADDR(dmc_inst)); /* * - Currently no handler is provided to trap an error via * interrupt or exception. * - The interrupt action has not been tested. */ _tzc_dmc500_write_action(DMC_INST_BASE_ADDR(dmc_inst), action); } } /* * A DMC-500 instance must be present at each base address provided by the * platform. It also expects platform to pass at least one instance of * DMC-500. */ static void validate_plat_driver_data( const tzc_dmc500_driver_data_t *plat_driver_data) { #if ENABLE_ASSERTIONS int i; unsigned int dmc_id; uintptr_t dmc_base; assert(plat_driver_data); assert(plat_driver_data->dmc_count > 0 && (plat_driver_data->dmc_count <= MAX_DMC_COUNT)); for (i = 0; i < plat_driver_data->dmc_count; i++) { dmc_base = plat_driver_data->dmc_base[i]; assert(dmc_base); dmc_id = _tzc_read_peripheral_id(dmc_base); assert(dmc_id == DMC500_PERIPHERAL_ID); } #endif /* ENABLE_ASSERTIONS */ } /* * Initializes the base address and count of DMC instances. * * Note : Only pointer to plat_driver_data is saved, so it is caller's * responsibility to keep it valid until the driver is used. */ void tzc_dmc500_driver_init(const tzc_dmc500_driver_data_t *plat_driver_data) { /* Check valid pointer is passed */ assert(plat_driver_data); /* * NOTE: This driver expects the DMC-500 controller is already in * READY state. Hence, it uses the reconfiguration method for * programming TrustZone regions */ /* Validates the information passed by platform */ validate_plat_driver_data(plat_driver_data); g_driver_data = plat_driver_data; /* Check valid system interface count */ assert(g_driver_data->sys_if_count <= MAX_SYS_IF_COUNT); g_sys_if_count = g_driver_data->sys_if_count; /* If interface count is not present then assume max */ if (g_sys_if_count == 0U) g_sys_if_count = MAX_SYS_IF_COUNT; } trusted-firmware-a-2.2/drivers/arm/tzc/tzc_dmc620.c000066400000000000000000000125661355360272700221770ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /* Mask to extract bit 31 to 16 */ #define MASK_31_16 UINT64_C(0x0000ffff0000) /* Mask to extract bit 47 to 32 */ #define MASK_47_32 UINT64_C(0xffff00000000) /* Helper macro for getting dmc_base addr of a dmc_inst */ #define DMC_BASE(plat_data, dmc_inst) \ ((uintptr_t)(plat_data->dmc_base[dmc_inst])) /* Pointer to the tzc_dmc620_config_data structure populated by the platform */ static const tzc_dmc620_config_data_t *g_plat_config_data; #if ENABLE_ASSERTIONS /* * Helper function to check if the DMC-620 instance is present at the * base address provided by the platform and also check if at least * one dmc instance is present. */ static void tzc_dmc620_validate_plat_driver_data( const tzc_dmc620_driver_data_t *plat_driver_data) { uint8_t dmc_inst, dmc_count; unsigned int dmc_id; uintptr_t base; assert(plat_driver_data != NULL); dmc_count = plat_driver_data->dmc_count; assert(dmc_count > 0U); for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) { base = DMC_BASE(plat_driver_data, dmc_inst); dmc_id = mmio_read_32(base + DMC620_PERIPHERAL_ID_0); assert(dmc_id == DMC620_PERIPHERAL_ID_0_VALUE); } } #endif /* * Program a region with region base and region top addresses of all * DMC-620 instances. */ static void tzc_dmc620_configure_region(int region_no, unsigned long long region_base, unsigned long long region_top, unsigned int sec_attr) { uint32_t min_31_00, min_47_32; uint32_t max_31_00, max_47_32; uint8_t dmc_inst, dmc_count; uintptr_t base; const tzc_dmc620_driver_data_t *plat_driver_data; plat_driver_data = g_plat_config_data->plat_drv_data; assert(plat_driver_data != NULL); /* Do range checks on regions. */ assert((region_no >= 0U) && (region_no <= DMC620_ACC_ADDR_COUNT)); /* region_base and (region_top + 1) must be 4KB aligned */ assert(((region_base | (region_top + 1U)) & (4096U - 1U)) == 0U); dmc_count = plat_driver_data->dmc_count; for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) { min_31_00 = (region_base & MASK_31_16) | sec_attr; min_47_32 = (region_base & MASK_47_32) >> DMC620_ACC_ADDR_WIDTH; max_31_00 = (region_top & MASK_31_16); max_47_32 = (region_top & MASK_47_32) >> DMC620_ACC_ADDR_WIDTH; /* Extract the base address of the DMC-620 instance */ base = DMC_BASE(plat_driver_data, dmc_inst); /* Configure access address region registers */ mmio_write_32(base + DMC620_ACC_ADDR_MIN_31_00_NEXT(region_no), min_31_00); mmio_write_32(base + DMC620_ACC_ADDR_MIN_47_32_NEXT(region_no), min_47_32); mmio_write_32(base + DMC620_ACC_ADDR_MAX_31_00_NEXT(region_no), max_31_00); mmio_write_32(base + DMC620_ACC_ADDR_MAX_47_32_NEXT(region_no), max_47_32); } } /* * Set the action value for all the DMC-620 instances. */ static void tzc_dmc620_set_action(void) { uint8_t dmc_inst, dmc_count; uintptr_t base; const tzc_dmc620_driver_data_t *plat_driver_data; plat_driver_data = g_plat_config_data->plat_drv_data; dmc_count = plat_driver_data->dmc_count; for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) { /* Extract the base address of the DMC-620 instance */ base = DMC_BASE(plat_driver_data, dmc_inst); /* Switch to READY */ mmio_write_32(base + DMC620_MEMC_CMD, DMC620_MEMC_CMD_GO); mmio_write_32(base + DMC620_MEMC_CMD, DMC620_MEMC_CMD_EXECUTE); } } /* * Verify whether the DMC-620 configuration is complete by reading back * configuration registers and comparing it with the configured value. If * configuration is incomplete, loop till the configured value is reflected in * the register. */ static void tzc_dmc620_verify_complete(void) { uint8_t dmc_inst, dmc_count; uintptr_t base; const tzc_dmc620_driver_data_t *plat_driver_data; plat_driver_data = g_plat_config_data->plat_drv_data; dmc_count = plat_driver_data->dmc_count; for (dmc_inst = 0U; dmc_inst < dmc_count; dmc_inst++) { /* Extract the base address of the DMC-620 instance */ base = DMC_BASE(plat_driver_data, dmc_inst); while ((mmio_read_32(base + DMC620_MEMC_STATUS) & DMC620_MEMC_CMD_MASK) != DMC620_MEMC_CMD_GO) continue; } } /* * Initialize the DMC-620 TrustZone Controller using the region configuration * supplied by the platform. The DMC620 controller should be enabled elsewhere * before invoking this function. */ void arm_tzc_dmc620_setup(const tzc_dmc620_config_data_t *plat_config_data) { int i; /* Check if valid pointer is passed */ assert(plat_config_data != NULL); /* * Check if access address count passed by the platform is less than or * equal to DMC620's access address count */ assert(plat_config_data->acc_addr_count <= DMC620_ACC_ADDR_COUNT); #if ENABLE_ASSERTIONS /* Validates the information passed by platform */ tzc_dmc620_validate_plat_driver_data(plat_config_data->plat_drv_data); #endif g_plat_config_data = plat_config_data; INFO("Configuring DMC-620 TZC settings\n"); for (i = 0U; i < g_plat_config_data->acc_addr_count; i++) tzc_dmc620_configure_region(i, g_plat_config_data->plat_acc_addr_data[i].region_base, g_plat_config_data->plat_acc_addr_data[i].region_top, g_plat_config_data->plat_acc_addr_data[i].sec_attr); tzc_dmc620_set_action(); tzc_dmc620_verify_complete(); INFO("DMC-620 TZC setup completed\n"); } trusted-firmware-a-2.2/drivers/auth/000077500000000000000000000000001355360272700175305ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/auth/auth_mod.c000066400000000000000000000266061355360272700215060ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include /* ASN.1 tags */ #define ASN1_INTEGER 0x02 #define return_if_error(rc) \ do { \ if (rc != 0) { \ return rc; \ } \ } while (0) #pragma weak plat_set_nv_ctr2 /* Pointer to CoT */ extern const auth_img_desc_t *const *const cot_desc_ptr; extern unsigned int auth_img_flags[MAX_NUMBER_IDS]; static int cmp_auth_param_type_desc(const auth_param_type_desc_t *a, const auth_param_type_desc_t *b) { if ((a->type == b->type) && (a->cookie == b->cookie)) { return 0; } return 1; } /* * This function obtains the requested authentication parameter data from the * information extracted from the parent image after its authentication. */ static int auth_get_param(const auth_param_type_desc_t *param_type_desc, const auth_img_desc_t *img_desc, void **param, unsigned int *len) { int i; if (img_desc->authenticated_data == NULL) return 1; for (i = 0 ; i < COT_MAX_VERIFIED_PARAMS ; i++) { if (0 == cmp_auth_param_type_desc(param_type_desc, img_desc->authenticated_data[i].type_desc)) { *param = img_desc->authenticated_data[i].data.ptr; *len = img_desc->authenticated_data[i].data.len; return 0; } } return 1; } /* * Authenticate an image by matching the data hash * * This function implements 'AUTH_METHOD_HASH'. To authenticate an image using * this method, the image must contain: * * - The data to calculate the hash from * * The parent image must contain: * * - The hash to be matched with (including hash algorithm) * * For a successful authentication, both hashes must match. The function calls * the crypto-module to check this matching. * * Parameters: * param: parameters to perform the hash authentication * img_desc: pointer to image descriptor so we can know the image type * and parent image * img: pointer to image in memory * img_len: length of image (in bytes) * * Return: * 0 = success, Otherwise = error */ static int auth_hash(const auth_method_param_hash_t *param, const auth_img_desc_t *img_desc, void *img, unsigned int img_len) { void *data_ptr, *hash_der_ptr; unsigned int data_len, hash_der_len; int rc = 0; /* Get the hash from the parent image. This hash will be DER encoded * and contain the hash algorithm */ rc = auth_get_param(param->hash, img_desc->parent, &hash_der_ptr, &hash_der_len); return_if_error(rc); /* Get the data to be hashed from the current image */ rc = img_parser_get_auth_param(img_desc->img_type, param->data, img, img_len, &data_ptr, &data_len); return_if_error(rc); /* Ask the crypto module to verify this hash */ rc = crypto_mod_verify_hash(data_ptr, data_len, hash_der_ptr, hash_der_len); return rc; } /* * Authenticate by digital signature * * This function implements 'AUTH_METHOD_SIG'. To authenticate an image using * this method, the image must contain: * * - Data to be signed * - Signature * - Signature algorithm * * We rely on the image parser module to extract this data from the image. * The parent image must contain: * * - Public key (or a hash of it) * * If the parent image contains only a hash of the key, we will try to obtain * the public key from the image itself (i.e. self-signed certificates). In that * case, the signature verification is considered just an integrity check and * the authentication is established by calculating the hash of the key and * comparing it with the hash obtained from the parent. * * If the image has no parent (NULL), it means it has to be authenticated using * the ROTPK stored in the platform. Again, this ROTPK could be the key itself * or a hash of it. * * Return: 0 = success, Otherwise = error */ static int auth_signature(const auth_method_param_sig_t *param, const auth_img_desc_t *img_desc, void *img, unsigned int img_len) { void *data_ptr, *pk_ptr, *pk_hash_ptr, *sig_ptr, *sig_alg_ptr; unsigned int data_len, pk_len, pk_hash_len, sig_len, sig_alg_len; unsigned int flags = 0; int rc = 0; /* Get the data to be signed from current image */ rc = img_parser_get_auth_param(img_desc->img_type, param->data, img, img_len, &data_ptr, &data_len); return_if_error(rc); /* Get the signature from current image */ rc = img_parser_get_auth_param(img_desc->img_type, param->sig, img, img_len, &sig_ptr, &sig_len); return_if_error(rc); /* Get the signature algorithm from current image */ rc = img_parser_get_auth_param(img_desc->img_type, param->alg, img, img_len, &sig_alg_ptr, &sig_alg_len); return_if_error(rc); /* Get the public key from the parent. If there is no parent (NULL), * the certificate has been signed with the ROTPK, so we have to get * the PK from the platform */ if (img_desc->parent) { rc = auth_get_param(param->pk, img_desc->parent, &pk_ptr, &pk_len); } else { rc = plat_get_rotpk_info(param->pk->cookie, &pk_ptr, &pk_len, &flags); } return_if_error(rc); if (flags & (ROTPK_IS_HASH | ROTPK_NOT_DEPLOYED)) { /* If the PK is a hash of the key or if the ROTPK is not deployed on the platform, retrieve the key from the image */ pk_hash_ptr = pk_ptr; pk_hash_len = pk_len; rc = img_parser_get_auth_param(img_desc->img_type, param->pk, img, img_len, &pk_ptr, &pk_len); return_if_error(rc); /* Ask the crypto module to verify the signature */ rc = crypto_mod_verify_signature(data_ptr, data_len, sig_ptr, sig_len, sig_alg_ptr, sig_alg_len, pk_ptr, pk_len); return_if_error(rc); if (flags & ROTPK_NOT_DEPLOYED) { NOTICE("ROTPK is not deployed on platform. " "Skipping ROTPK verification.\n"); } else { /* Ask the crypto-module to verify the key hash */ rc = crypto_mod_verify_hash(pk_ptr, pk_len, pk_hash_ptr, pk_hash_len); } } else { /* Ask the crypto module to verify the signature */ rc = crypto_mod_verify_signature(data_ptr, data_len, sig_ptr, sig_len, sig_alg_ptr, sig_alg_len, pk_ptr, pk_len); } return rc; } /* * Authenticate by Non-Volatile counter * * To protect the system against rollback, the platform includes a non-volatile * counter whose value can only be increased. All certificates include a counter * value that should not be lower than the value stored in the platform. If the * value is larger, the counter in the platform must be updated to the new * value. * * Return: 0 = success, Otherwise = error */ static int auth_nvctr(const auth_method_param_nv_ctr_t *param, const auth_img_desc_t *img_desc, void *img, unsigned int img_len) { char *p; void *data_ptr = NULL; unsigned int data_len, len, i; unsigned int cert_nv_ctr, plat_nv_ctr; int rc = 0; /* Get the counter value from current image. The AM expects the IPM * to return the counter value as a DER encoded integer */ rc = img_parser_get_auth_param(img_desc->img_type, param->cert_nv_ctr, img, img_len, &data_ptr, &data_len); return_if_error(rc); /* Parse the DER encoded integer */ assert(data_ptr); p = (char *)data_ptr; if (*p != ASN1_INTEGER) { /* Invalid ASN.1 integer */ return 1; } p++; /* NV-counters are unsigned integers up to 32-bit */ len = (unsigned int)(*p & 0x7f); if ((*p & 0x80) || (len > 4)) { return 1; } p++; /* Check the number is not negative */ if (*p & 0x80) { return 1; } /* Convert to unsigned int. This code is for a little-endian CPU */ cert_nv_ctr = 0; for (i = 0; i < len; i++) { cert_nv_ctr = (cert_nv_ctr << 8) | *p++; } /* Get the counter from the platform */ rc = plat_get_nv_ctr(param->plat_nv_ctr->cookie, &plat_nv_ctr); return_if_error(rc); if (cert_nv_ctr < plat_nv_ctr) { /* Invalid NV-counter */ return 1; } else if (cert_nv_ctr > plat_nv_ctr) { rc = plat_set_nv_ctr2(param->plat_nv_ctr->cookie, img_desc, cert_nv_ctr); return_if_error(rc); } return 0; } int plat_set_nv_ctr2(void *cookie, const auth_img_desc_t *img_desc __unused, unsigned int nv_ctr) { return plat_set_nv_ctr(cookie, nv_ctr); } /* * Return the parent id in the output parameter '*parent_id' * * Return value: * 0 = Image has parent, 1 = Image has no parent or parent is authenticated */ int auth_mod_get_parent_id(unsigned int img_id, unsigned int *parent_id) { const auth_img_desc_t *img_desc = NULL; assert(parent_id != NULL); /* Get the image descriptor */ img_desc = cot_desc_ptr[img_id]; /* Check if the image has no parent (ROT) */ if (img_desc->parent == NULL) { *parent_id = 0; return 1; } /* Check if the parent has already been authenticated */ if (auth_img_flags[img_desc->parent->img_id] & IMG_FLAG_AUTHENTICATED) { *parent_id = 0; return 1; } *parent_id = img_desc->parent->img_id; return 0; } /* * Initialize the different modules in the authentication framework */ void auth_mod_init(void) { /* Check we have a valid CoT registered */ assert(cot_desc_ptr != NULL); /* Crypto module */ crypto_mod_init(); /* Image parser module */ img_parser_init(); } /* * Authenticate a certificate/image * * Return: 0 = success, Otherwise = error */ int auth_mod_verify_img(unsigned int img_id, void *img_ptr, unsigned int img_len) { const auth_img_desc_t *img_desc = NULL; const auth_method_desc_t *auth_method = NULL; void *param_ptr; unsigned int param_len; int rc, i; /* Get the image descriptor from the chain of trust */ img_desc = cot_desc_ptr[img_id]; /* Ask the parser to check the image integrity */ rc = img_parser_check_integrity(img_desc->img_type, img_ptr, img_len); return_if_error(rc); /* Authenticate the image using the methods indicated in the image * descriptor. */ if (img_desc->img_auth_methods == NULL) return 1; for (i = 0 ; i < AUTH_METHOD_NUM ; i++) { auth_method = &img_desc->img_auth_methods[i]; switch (auth_method->type) { case AUTH_METHOD_NONE: rc = 0; break; case AUTH_METHOD_HASH: rc = auth_hash(&auth_method->param.hash, img_desc, img_ptr, img_len); break; case AUTH_METHOD_SIG: rc = auth_signature(&auth_method->param.sig, img_desc, img_ptr, img_len); break; case AUTH_METHOD_NV_CTR: rc = auth_nvctr(&auth_method->param.nv_ctr, img_desc, img_ptr, img_len); break; default: /* Unknown authentication method */ rc = 1; break; } return_if_error(rc); } /* Extract the parameters indicated in the image descriptor to * authenticate the children images. */ if (img_desc->authenticated_data != NULL) { for (i = 0 ; i < COT_MAX_VERIFIED_PARAMS ; i++) { if (img_desc->authenticated_data[i].type_desc == NULL) { continue; } /* Get the parameter from the image parser module */ rc = img_parser_get_auth_param(img_desc->img_type, img_desc->authenticated_data[i].type_desc, img_ptr, img_len, ¶m_ptr, ¶m_len); return_if_error(rc); /* Check parameter size */ if (param_len > img_desc->authenticated_data[i].data.len) { return 1; } /* Copy the parameter for later use */ memcpy((void *)img_desc->authenticated_data[i].data.ptr, (void *)param_ptr, param_len); } } /* Mark image as authenticated */ auth_img_flags[img_desc->img_id] |= IMG_FLAG_AUTHENTICATED; return 0; } trusted-firmware-a-2.2/drivers/auth/crypto_mod.c000066400000000000000000000056061355360272700220620ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /* Variable exported by the crypto library through REGISTER_CRYPTO_LIB() */ /* * The crypto module is responsible for verifying digital signatures and hashes. * It relies on a crypto library to perform the cryptographic operations. * * The crypto module itself does not impose any specific format on signatures, * signature algorithm, keys or hashes, but most cryptographic libraries will * take the parameters as the following DER encoded ASN.1 structures: * * AlgorithmIdentifier ::= SEQUENCE { * algorithm OBJECT IDENTIFIER, * parameters ANY DEFINED BY algorithm OPTIONAL * } * * DigestInfo ::= SEQUENCE { * digestAlgorithm AlgorithmIdentifier, * digest OCTET STRING * } * * SubjectPublicKeyInfo ::= SEQUENCE { * algorithm AlgorithmIdentifier, * subjectPublicKey BIT STRING * } * * SignatureAlgorithm ::= AlgorithmIdentifier * * SignatureValue ::= BIT STRING */ /* * Perform some static checking and call the library initialization function */ void crypto_mod_init(void) { assert(crypto_lib_desc.name != NULL); assert(crypto_lib_desc.init != NULL); assert(crypto_lib_desc.verify_signature != NULL); assert(crypto_lib_desc.verify_hash != NULL); /* Initialize the cryptographic library */ crypto_lib_desc.init(); INFO("Using crypto library '%s'\n", crypto_lib_desc.name); } /* * Function to verify a digital signature * * Parameters: * * data_ptr, data_len: signed data * sig_ptr, sig_len: the digital signature * sig_alg_ptr, sig_alg_len: the digital signature algorithm * pk_ptr, pk_len: the public key */ int crypto_mod_verify_signature(void *data_ptr, unsigned int data_len, void *sig_ptr, unsigned int sig_len, void *sig_alg_ptr, unsigned int sig_alg_len, void *pk_ptr, unsigned int pk_len) { assert(data_ptr != NULL); assert(data_len != 0); assert(sig_ptr != NULL); assert(sig_len != 0); assert(sig_alg_ptr != NULL); assert(sig_alg_len != 0); assert(pk_ptr != NULL); assert(pk_len != 0); return crypto_lib_desc.verify_signature(data_ptr, data_len, sig_ptr, sig_len, sig_alg_ptr, sig_alg_len, pk_ptr, pk_len); } /* * Verify a hash by comparison * * Parameters: * * data_ptr, data_len: data to be hashed * digest_info_ptr, digest_info_len: hash to be compared */ int crypto_mod_verify_hash(void *data_ptr, unsigned int data_len, void *digest_info_ptr, unsigned int digest_info_len) { assert(data_ptr != NULL); assert(data_len != 0); assert(digest_info_ptr != NULL); assert(digest_info_len != 0); return crypto_lib_desc.verify_hash(data_ptr, data_len, digest_info_ptr, digest_info_len); } trusted-firmware-a-2.2/drivers/auth/cryptocell/000077500000000000000000000000001355360272700217105ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/auth/cryptocell/712/000077500000000000000000000000001355360272700222215ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/auth/cryptocell/712/cryptocell_crypto.c000066400000000000000000000200761355360272700261520ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define LIB_NAME "CryptoCell 712 SBROM" #define RSA_SALT_LEN 32 #define RSA_EXPONENT 65537 /* * AlgorithmIdentifier ::= SEQUENCE { * algorithm OBJECT IDENTIFIER, * parameters ANY DEFINED BY algorithm OPTIONAL * } * * SubjectPublicKeyInfo ::= SEQUENCE { * algorithm AlgorithmIdentifier, * subjectPublicKey BIT STRING * } * * DigestInfo ::= SEQUENCE { * digestAlgorithm AlgorithmIdentifier, * digest OCTET STRING * } * * RSASSA-PSS-params ::= SEQUENCE { * hashAlgorithm [0] HashAlgorithm, * maskGenAlgorithm [1] MaskGenAlgorithm, * saltLength [2] INTEGER, * trailerField [3] TrailerField DEFAULT trailerFieldBC * } */ /* * Initialize the library and export the descriptor */ static void init(void) { CCError_t ret; uint32_t lcs; /* Initialize CC SBROM */ ret = CC_BsvSbromInit((uintptr_t)PLAT_CRYPTOCELL_BASE); if (ret != CC_OK) { ERROR("CryptoCell CC_BsvSbromInit() error %x\n", ret); panic(); } /* Initialize lifecycle state */ ret = CC_BsvLcsGetAndInit((uintptr_t)PLAT_CRYPTOCELL_BASE, &lcs); if (ret != CC_OK) { ERROR("CryptoCell CC_BsvLcsGetAndInit() error %x\n", ret); panic(); } /* If the lifecyclestate is `SD`, then stop further execution */ if (lcs == CC_BSV_SECURITY_DISABLED_LCS) { ERROR("CryptoCell LCS is security-disabled\n"); panic(); } } /* * Verify a signature. * * Parameters are passed using the DER encoding format following the ASN.1 * structures detailed above. */ static int verify_signature(void *data_ptr, unsigned int data_len, void *sig_ptr, unsigned int sig_len, void *sig_alg, unsigned int sig_alg_len, void *pk_ptr, unsigned int pk_len) { CCError_t error; CCSbNParams_t pk; CCSbSignature_t signature; int rc, exp; mbedtls_asn1_buf sig_oid, alg_oid, params; mbedtls_md_type_t md_alg; mbedtls_pk_type_t pk_alg; mbedtls_pk_rsassa_pss_options pss_opts; size_t len; uint8_t *p, *end; /* Temp buf to store the public key modulo (N) in LE format */ uint32_t RevN[SB_RSA_MOD_SIZE_IN_WORDS]; /* Verify the signature algorithm */ /* Get pointers to signature OID and parameters */ p = sig_alg; end = p + sig_alg_len; rc = mbedtls_asn1_get_alg(&p, end, &sig_oid, ¶ms); if (rc != 0) return CRYPTO_ERR_SIGNATURE; /* Get the actual signature algorithm (MD + PK) */ rc = mbedtls_oid_get_sig_alg(&sig_oid, &md_alg, &pk_alg); if (rc != 0) return CRYPTO_ERR_SIGNATURE; /* The CryptoCell only supports RSASSA-PSS signature */ if (pk_alg != MBEDTLS_PK_RSASSA_PSS || md_alg != MBEDTLS_MD_NONE) return CRYPTO_ERR_SIGNATURE; /* Verify the RSASSA-PSS params */ /* The trailer field is verified to be 0xBC internally by this API */ rc = mbedtls_x509_get_rsassa_pss_params(¶ms, &md_alg, &pss_opts.mgf1_hash_id, &pss_opts.expected_salt_len); if (rc != 0) return CRYPTO_ERR_SIGNATURE; /* The CryptoCell only supports SHA256 as hash algorithm */ if (md_alg != MBEDTLS_MD_SHA256 || pss_opts.mgf1_hash_id != MBEDTLS_MD_SHA256) return CRYPTO_ERR_SIGNATURE; if (pss_opts.expected_salt_len != RSA_SALT_LEN) return CRYPTO_ERR_SIGNATURE; /* Parse the public key */ p = pk_ptr; end = p + pk_len; rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (rc != 0) return CRYPTO_ERR_SIGNATURE; end = p + len; rc = mbedtls_asn1_get_alg_null(&p, end, &alg_oid); if (rc != 0) return CRYPTO_ERR_SIGNATURE; if (mbedtls_oid_get_pk_alg(&alg_oid, &pk_alg) != 0) return CRYPTO_ERR_SIGNATURE; if (pk_alg != MBEDTLS_PK_RSA) return CRYPTO_ERR_SIGNATURE; rc = mbedtls_asn1_get_bitstring_null(&p, end, &len); if (rc != 0) return CRYPTO_ERR_SIGNATURE; rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (rc != 0) return CRYPTO_ERR_SIGNATURE; rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER); if (rc != 0) return CRYPTO_ERR_SIGNATURE; if (*p == 0) { p++; len--; } if (len != RSA_MOD_SIZE_IN_BYTES || ((p + len) > end)) return CRYPTO_ERR_SIGNATURE; /* * The CCSbVerifySignature() API expects N and Np in BE format and * the signature in LE format. Copy N from certificate. */ memcpy(pk.N, p, RSA_MOD_SIZE_IN_BYTES); /* Verify the RSA exponent */ p += len; rc = mbedtls_asn1_get_int(&p, end, &exp); if (rc != 0) return CRYPTO_ERR_SIGNATURE; if (exp != RSA_EXPONENT) return CRYPTO_ERR_SIGNATURE; /* * Calculate the Np (Barrett n' value). The RSA_CalcNp() API expects * N in LE format. Hence reverse N into a temporary buffer `RevN`. */ UTIL_ReverseMemCopy((uint8_t *)RevN, (uint8_t *)pk.N, sizeof(RevN)); RSA_CalcNp((uintptr_t)PLAT_CRYPTOCELL_BASE, RevN, pk.Np); /* Np is in LE format. Reverse it to BE */ UTIL_ReverseBuff((uint8_t *)pk.Np, sizeof(pk.Np)); /* Get the signature (bitstring) */ p = sig_ptr; end = p + sig_len; rc = mbedtls_asn1_get_bitstring_null(&p, end, &len); if (rc != 0) return CRYPTO_ERR_SIGNATURE; if (len != RSA_MOD_SIZE_IN_BYTES || ((p + len) > end)) return CRYPTO_ERR_SIGNATURE; /* * The signature is BE format. Convert it to LE before calling * CCSbVerifySignature(). */ UTIL_ReverseMemCopy((uint8_t *)signature.sig, p, RSA_MOD_SIZE_IN_BYTES); /* * CryptoCell utilises DMA internally to transfer data. Flush the data * from caches. */ flush_dcache_range((uintptr_t)data_ptr, data_len); /* Verify the signature */ error = CCSbVerifySignature((uintptr_t)PLAT_CRYPTOCELL_BASE, (uint32_t *)data_ptr, &pk, &signature, data_len, RSA_PSS_2048); if (error != CC_OK) return CRYPTO_ERR_SIGNATURE; /* Signature verification success */ return CRYPTO_SUCCESS; } /* * Match a hash * * Digest info is passed in DER format following the ASN.1 structure detailed * above. */ static int verify_hash(void *data_ptr, unsigned int data_len, void *digest_info_ptr, unsigned int digest_info_len) { mbedtls_asn1_buf hash_oid, params; mbedtls_md_type_t md_alg; uint8_t *p, *end, *hash; CCHashResult_t pubKeyHash; size_t len; int rc; CCError_t error; /* Digest info should be an MBEDTLS_ASN1_SEQUENCE */ p = digest_info_ptr; end = p + digest_info_len; rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (rc != 0) return CRYPTO_ERR_HASH; /* Get the hash algorithm */ rc = mbedtls_asn1_get_alg(&p, end, &hash_oid, ¶ms); if (rc != 0) return CRYPTO_ERR_HASH; rc = mbedtls_oid_get_md_alg(&hash_oid, &md_alg); if (rc != 0) return CRYPTO_ERR_HASH; /* Verify that hash algorithm is SHA256 */ if (md_alg != MBEDTLS_MD_SHA256) return CRYPTO_ERR_HASH; /* Hash should be octet string type */ rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); if (rc != 0) return CRYPTO_ERR_HASH; /* Length of hash must match the algorithm's size */ if (len != HASH_RESULT_SIZE_IN_BYTES) return CRYPTO_ERR_HASH; /* * CryptoCell utilises DMA internally to transfer data. Flush the data * from caches. */ flush_dcache_range((uintptr_t)data_ptr, data_len); hash = p; error = SBROM_CryptoHash((uintptr_t)PLAT_CRYPTOCELL_BASE, (uintptr_t)data_ptr, data_len, pubKeyHash); if (error != CC_OK) return CRYPTO_ERR_HASH; rc = memcmp(pubKeyHash, hash, HASH_RESULT_SIZE_IN_BYTES); if (rc != 0) return CRYPTO_ERR_HASH; return CRYPTO_SUCCESS; } /* * Register crypto library descriptor */ REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash); trusted-firmware-a-2.2/drivers/auth/cryptocell/712/cryptocell_plat_helpers.c000066400000000000000000000060621355360272700273130ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include /* * Return the ROTPK hash * * dst: buffer into which the ROTPK hash will be copied into * len: length of the provided buffer, which must be at least enough for a * SHA256 hash * flags: a pointer to integer that will be set to indicate the ROTPK status * * Return: 0 = success, Otherwise = error */ int cc_get_rotpk_hash(unsigned char *dst, unsigned int len, unsigned int *flags) { CCError_t error; uint32_t lcs; assert(dst != NULL); assert(len >= HASH_RESULT_SIZE_IN_WORDS); assert(flags != NULL); error = NVM_GetLCS(PLAT_CRYPTOCELL_BASE, &lcs); if (error != CC_OK) return 1; /* If the lifecycle state is `SD`, return failure */ if (lcs == CC_BSV_SECURITY_DISABLED_LCS) return 1; /* * If the lifecycle state is `CM` or `DM`, ROTPK shouldn't be verified. * Return success after setting ROTPK_NOT_DEPLOYED flag */ if ((lcs == CC_BSV_CHIP_MANUFACTURE_LCS) || (lcs == CC_BSV_DEVICE_MANUFACTURE_LCS)) { *flags = ROTPK_NOT_DEPLOYED; return 0; } /* Copy the DER header */ error = NVM_ReadHASHPubKey(PLAT_CRYPTOCELL_BASE, CC_SB_HASH_BOOT_KEY_256B, (uint32_t *)dst, HASH_RESULT_SIZE_IN_WORDS); if (error != CC_OK) return 1; *flags = ROTPK_IS_HASH; return 0; } /* * Return the non-volatile counter value stored in the platform. The cookie * specifies the OID of the counter in the certificate. * * Return: 0 = success, Otherwise = error */ int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr) { CCError_t error = CC_FAIL; if (strcmp(cookie, TRUSTED_FW_NVCOUNTER_OID) == 0) { error = NVM_GetSwVersion(PLAT_CRYPTOCELL_BASE, CC_SW_VERSION_COUNTER1, nv_ctr); } else if (strcmp(cookie, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) { error = NVM_GetSwVersion(PLAT_CRYPTOCELL_BASE, CC_SW_VERSION_COUNTER2, nv_ctr); } return (error != CC_OK); } /* * Store a new non-volatile counter value in the counter specified by the OID * in the cookie. This function is not expected to be called if the Lifecycle * state is RMA as the values in the certificate are expected to always match * the nvcounter values. But if called when the LCS is RMA, the underlying * helper functions will return success but without updating the counter. * * Return: 0 = success, Otherwise = error */ int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr) { CCError_t error = CC_FAIL; if (strcmp(cookie, TRUSTED_FW_NVCOUNTER_OID) == 0) { error = NVM_SetSwVersion(PLAT_CRYPTOCELL_BASE, CC_SW_VERSION_COUNTER1, nv_ctr); } else if (strcmp(cookie, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) { error = NVM_SetSwVersion(PLAT_CRYPTOCELL_BASE, CC_SW_VERSION_COUNTER2, nv_ctr); } return (error != CC_OK); } trusted-firmware-a-2.2/drivers/auth/cryptocell/cryptocell_crypto.mk000066400000000000000000000020211355360272700260140ustar00rootroot00000000000000# # Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # include drivers/auth/mbedtls/mbedtls_common.mk # The algorithm is RSA when using Cryptocell crypto driver TF_MBEDTLS_KEY_ALG_ID := TF_MBEDTLS_RSA # Needs to be set to drive mbed TLS configuration correctly $(eval $(call add_define,TF_MBEDTLS_KEY_ALG_ID)) # CCSBROM_LIB_PATH must be set to the Cryptocell SBROM library path ifeq (${CCSBROM_LIB_PATH},) $(error Error: CCSBROM_LIB_PATH not set) endif CRYPTOCELL_VERSION ?= 712 ifeq (${CRYPTOCELL_VERSION},712) CCSBROM_LIB_FILENAME := cc_712sbromx509 else $(error Error: CRYPTOCELL_VERSION set to invalid version) endif CRYPTOCELL_SRC_DIR := drivers/auth/cryptocell/${CRYPTOCELL_VERSION}/ CRYPTOCELL_SOURCES := ${CRYPTOCELL_SRC_DIR}/cryptocell_crypto.c \ ${CRYPTOCELL_SRC_DIR}/cryptocell_plat_helpers.c TF_LDFLAGS += -L$(CCSBROM_LIB_PATH) LDLIBS += -l$(CCSBROM_LIB_FILENAME) BL1_SOURCES += ${CRYPTOCELL_SOURCES} BL2_SOURCES += ${CRYPTOCELL_SOURCES} trusted-firmware-a-2.2/drivers/auth/img_parser_mod.c000066400000000000000000000067571355360272700227020ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include IMPORT_SYM(uintptr_t, __PARSER_LIB_DESCS_START__, PARSER_LIB_DESCS_START); IMPORT_SYM(uintptr_t, __PARSER_LIB_DESCS_END__, PARSER_LIB_DESCS_END); static unsigned int parser_lib_indices[IMG_MAX_TYPES]; static img_parser_lib_desc_t *parser_lib_descs; #define INVALID_IDX UINT_MAX static void validate_desc(img_parser_lib_desc_t *desc) { assert(desc != NULL); assert(desc->init != NULL); assert(desc->name != NULL); assert(desc->check_integrity != NULL); assert(desc->get_auth_param != NULL); } void img_parser_init(void) { unsigned int index, mod_num; /* Initialise internal variables to invalid state */ for (index = 0; index < IMG_MAX_TYPES; index++) { parser_lib_indices[index] = INVALID_IDX; } /* Calculate how many image parsers are registered. At least one parser * must be present */ mod_num = PARSER_LIB_DESCS_END - PARSER_LIB_DESCS_START; mod_num /= sizeof(img_parser_lib_desc_t); assert(mod_num > 0); parser_lib_descs = (img_parser_lib_desc_t *) PARSER_LIB_DESCS_START; for (index = 0; index < mod_num; index++) { /* Check that the image parser library descriptor is valid */ validate_desc(&parser_lib_descs[index]); /* Initialize image parser */ parser_lib_descs[index].init(); /* Ensure only one parser is registered for each image type */ assert(parser_lib_indices[parser_lib_descs[index].img_type] == INVALID_IDX); /* Keep the index of this hash calculator */ parser_lib_indices[parser_lib_descs[index].img_type] = index; } } int img_parser_check_integrity(img_type_t img_type, void *img_ptr, unsigned int img_len) { unsigned int idx; assert(img_ptr != NULL); assert(img_len != 0); /* No integrity checks on raw images */ if (img_type == IMG_RAW) { return IMG_PARSER_OK; } /* Find the index of the required image parser */ idx = parser_lib_indices[img_type]; assert(idx != INVALID_IDX); /* Call the function to check the image integrity */ return parser_lib_descs[idx].check_integrity(img_ptr, img_len); } /* * Extract an authentication parameter from an image * * Parameters: * img_type: image type (certificate, raw image, etc) * type_desc: provides info to obtain the parameter * img_ptr: pointer to image data * img_len: image length * param_ptr: [out] stores a pointer to the parameter * param_len: [out] stores the length of the parameter */ int img_parser_get_auth_param(img_type_t img_type, const auth_param_type_desc_t *type_desc, void *img_ptr, unsigned int img_len, void **param_ptr, unsigned int *param_len) { unsigned int idx; assert(type_desc != NULL); assert(img_ptr != NULL); assert(img_len != 0); assert(param_ptr != NULL); assert(param_len != NULL); /* In a raw image we can only get the data itself */ if (img_type == IMG_RAW) { assert(type_desc->type == AUTH_PARAM_RAW_DATA); *param_ptr = img_ptr; *param_len = img_len; return IMG_PARSER_OK; } /* Find the index of the required image parser library */ idx = parser_lib_indices[img_type]; assert(idx != INVALID_IDX); /* Call the function to obtain the parameter */ return parser_lib_descs[idx].get_auth_param(type_desc, img_ptr, img_len, param_ptr, param_len); } trusted-firmware-a-2.2/drivers/auth/mbedtls/000077500000000000000000000000001355360272700211625ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/auth/mbedtls/mbedtls_common.c000066400000000000000000000027371355360272700243410ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /* mbed TLS headers */ #include #include #include #include #include #include static void cleanup(void) { ERROR("EXIT from BL2\n"); panic(); } /* * mbed TLS initialization function */ void mbedtls_init(void) { static int ready; void *heap_addr; size_t heap_size = 0; int err; if (!ready) { if (atexit(cleanup)) panic(); err = plat_get_mbedtls_heap(&heap_addr, &heap_size); /* Ensure heap setup is proper */ if (err < 0) { ERROR("Mbed TLS failed to get a heap\n"); panic(); } assert(heap_size >= TF_MBEDTLS_HEAP_SIZE); /* Initialize the mbed TLS heap */ mbedtls_memory_buffer_alloc_init(heap_addr, heap_size); #ifdef MBEDTLS_PLATFORM_SNPRINTF_ALT mbedtls_platform_set_snprintf(snprintf); #endif ready = 1; } } /* * The following helper function simply returns the default allocated heap. * It can be used by platforms for their plat_get_mbedtls_heap() implementation. */ int get_mbedtls_heap_helper(void **heap_addr, size_t *heap_size) { static unsigned char heap[TF_MBEDTLS_HEAP_SIZE]; assert(heap_addr != NULL); assert(heap_size != NULL); *heap_addr = heap; *heap_size = sizeof(heap); return 0; } trusted-firmware-a-2.2/drivers/auth/mbedtls/mbedtls_common.mk000066400000000000000000000050721355360272700245210ustar00rootroot00000000000000# # Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ifneq (${MBEDTLS_COMMON_MK},1) MBEDTLS_COMMON_MK := 1 # MBEDTLS_DIR must be set to the mbed TLS main directory (it must contain # the 'include' and 'library' subdirectories). ifeq (${MBEDTLS_DIR},) $(error Error: MBEDTLS_DIR not set) endif MBEDTLS_INC = -I${MBEDTLS_DIR}/include # Specify mbed TLS configuration file MBEDTLS_CONFIG_FILE := "" $(eval $(call add_define,MBEDTLS_CONFIG_FILE)) MBEDTLS_SOURCES += drivers/auth/mbedtls/mbedtls_common.c LIBMBEDTLS_SRCS := $(addprefix ${MBEDTLS_DIR}/library/, \ asn1parse.c \ asn1write.c \ memory_buffer_alloc.c \ oid.c \ platform.c \ platform_util.c \ bignum.c \ md.c \ md_wrap.c \ pk.c \ pk_wrap.c \ pkparse.c \ pkwrite.c \ sha256.c \ sha512.c \ ecdsa.c \ ecp_curves.c \ ecp.c \ rsa.c \ rsa_internal.c \ x509.c \ x509_crt.c \ ) # The platform may define the variable 'TF_MBEDTLS_KEY_ALG' to select the key # algorithm to use. If the variable is not defined, select it based on # algorithm used for key generation `KEY_ALG`. If `KEY_ALG` is not defined, # then it is set to `rsa`. ifeq (${TF_MBEDTLS_KEY_ALG},) ifeq (${KEY_ALG}, ecdsa) TF_MBEDTLS_KEY_ALG := ecdsa else TF_MBEDTLS_KEY_ALG := rsa endif endif ifeq (${TF_MBEDTLS_KEY_SIZE},) ifneq ($(findstring rsa,${TF_MBEDTLS_KEY_ALG}),) ifeq (${KEY_SIZE},) TF_MBEDTLS_KEY_SIZE := 2048 else TF_MBEDTLS_KEY_SIZE := ${KEY_SIZE} endif endif endif ifeq (${HASH_ALG}, sha384) TF_MBEDTLS_HASH_ALG_ID := TF_MBEDTLS_SHA384 else ifeq (${HASH_ALG}, sha512) TF_MBEDTLS_HASH_ALG_ID := TF_MBEDTLS_SHA512 else TF_MBEDTLS_HASH_ALG_ID := TF_MBEDTLS_SHA256 endif ifeq (${TF_MBEDTLS_KEY_ALG},ecdsa) TF_MBEDTLS_KEY_ALG_ID := TF_MBEDTLS_ECDSA else ifeq (${TF_MBEDTLS_KEY_ALG},rsa) TF_MBEDTLS_KEY_ALG_ID := TF_MBEDTLS_RSA else ifeq (${TF_MBEDTLS_KEY_ALG},rsa+ecdsa) TF_MBEDTLS_KEY_ALG_ID := TF_MBEDTLS_RSA_AND_ECDSA else $(error "TF_MBEDTLS_KEY_ALG=${TF_MBEDTLS_KEY_ALG} not supported on mbed TLS") endif # Needs to be set to drive mbed TLS configuration correctly $(eval $(call add_define,TF_MBEDTLS_KEY_ALG_ID)) $(eval $(call add_define,TF_MBEDTLS_KEY_SIZE)) $(eval $(call add_define,TF_MBEDTLS_HASH_ALG_ID)) $(eval $(call MAKE_LIB,mbedtls)) endif trusted-firmware-a-2.2/drivers/auth/mbedtls/mbedtls_crypto.c000066400000000000000000000116371355360272700243700ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /* mbed TLS headers */ #include #include #include #include #include #include #include #include #define LIB_NAME "mbed TLS" /* * AlgorithmIdentifier ::= SEQUENCE { * algorithm OBJECT IDENTIFIER, * parameters ANY DEFINED BY algorithm OPTIONAL * } * * SubjectPublicKeyInfo ::= SEQUENCE { * algorithm AlgorithmIdentifier, * subjectPublicKey BIT STRING * } * * DigestInfo ::= SEQUENCE { * digestAlgorithm AlgorithmIdentifier, * digest OCTET STRING * } */ /* * Initialize the library and export the descriptor */ static void init(void) { /* Initialize mbed TLS */ mbedtls_init(); } /* * Verify a signature. * * Parameters are passed using the DER encoding format following the ASN.1 * structures detailed above. */ static int verify_signature(void *data_ptr, unsigned int data_len, void *sig_ptr, unsigned int sig_len, void *sig_alg, unsigned int sig_alg_len, void *pk_ptr, unsigned int pk_len) { mbedtls_asn1_buf sig_oid, sig_params; mbedtls_asn1_buf signature; mbedtls_md_type_t md_alg; mbedtls_pk_type_t pk_alg; mbedtls_pk_context pk = {0}; int rc; void *sig_opts = NULL; const mbedtls_md_info_t *md_info; unsigned char *p, *end; unsigned char hash[MBEDTLS_MD_MAX_SIZE]; /* Get pointers to signature OID and parameters */ p = (unsigned char *)sig_alg; end = (unsigned char *)(p + sig_alg_len); rc = mbedtls_asn1_get_alg(&p, end, &sig_oid, &sig_params); if (rc != 0) { return CRYPTO_ERR_SIGNATURE; } /* Get the actual signature algorithm (MD + PK) */ rc = mbedtls_x509_get_sig_alg(&sig_oid, &sig_params, &md_alg, &pk_alg, &sig_opts); if (rc != 0) { return CRYPTO_ERR_SIGNATURE; } /* Parse the public key */ mbedtls_pk_init(&pk); p = (unsigned char *)pk_ptr; end = (unsigned char *)(p + pk_len); rc = mbedtls_pk_parse_subpubkey(&p, end, &pk); if (rc != 0) { rc = CRYPTO_ERR_SIGNATURE; goto end2; } /* Get the signature (bitstring) */ p = (unsigned char *)sig_ptr; end = (unsigned char *)(p + sig_len); signature.tag = *p; rc = mbedtls_asn1_get_bitstring_null(&p, end, &signature.len); if (rc != 0) { rc = CRYPTO_ERR_SIGNATURE; goto end1; } signature.p = p; /* Calculate the hash of the data */ md_info = mbedtls_md_info_from_type(md_alg); if (md_info == NULL) { rc = CRYPTO_ERR_SIGNATURE; goto end1; } p = (unsigned char *)data_ptr; rc = mbedtls_md(md_info, p, data_len, hash); if (rc != 0) { rc = CRYPTO_ERR_SIGNATURE; goto end1; } /* Verify the signature */ rc = mbedtls_pk_verify_ext(pk_alg, sig_opts, &pk, md_alg, hash, mbedtls_md_get_size(md_info), signature.p, signature.len); if (rc != 0) { rc = CRYPTO_ERR_SIGNATURE; goto end1; } /* Signature verification success */ rc = CRYPTO_SUCCESS; end1: mbedtls_pk_free(&pk); end2: mbedtls_free(sig_opts); return rc; } /* * Match a hash * * Digest info is passed in DER format following the ASN.1 structure detailed * above. */ static int verify_hash(void *data_ptr, unsigned int data_len, void *digest_info_ptr, unsigned int digest_info_len) { mbedtls_asn1_buf hash_oid, params; mbedtls_md_type_t md_alg; const mbedtls_md_info_t *md_info; unsigned char *p, *end, *hash; unsigned char data_hash[MBEDTLS_MD_MAX_SIZE]; size_t len; int rc; /* Digest info should be an MBEDTLS_ASN1_SEQUENCE */ p = (unsigned char *)digest_info_ptr; end = p + digest_info_len; rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (rc != 0) { return CRYPTO_ERR_HASH; } /* Get the hash algorithm */ rc = mbedtls_asn1_get_alg(&p, end, &hash_oid, ¶ms); if (rc != 0) { return CRYPTO_ERR_HASH; } rc = mbedtls_oid_get_md_alg(&hash_oid, &md_alg); if (rc != 0) { return CRYPTO_ERR_HASH; } md_info = mbedtls_md_info_from_type(md_alg); if (md_info == NULL) { return CRYPTO_ERR_HASH; } /* Hash should be octet string type */ rc = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); if (rc != 0) { return CRYPTO_ERR_HASH; } /* Length of hash must match the algorithm's size */ if (len != mbedtls_md_get_size(md_info)) { return CRYPTO_ERR_HASH; } hash = p; /* Calculate the hash of the data */ p = (unsigned char *)data_ptr; rc = mbedtls_md(md_info, p, data_len, data_hash); if (rc != 0) { return CRYPTO_ERR_HASH; } /* Compare values */ rc = memcmp(data_hash, hash, mbedtls_md_get_size(md_info)); if (rc != 0) { return CRYPTO_ERR_HASH; } return CRYPTO_SUCCESS; } /* * Register crypto library descriptor */ REGISTER_CRYPTO_LIB(LIB_NAME, init, verify_signature, verify_hash); trusted-firmware-a-2.2/drivers/auth/mbedtls/mbedtls_crypto.mk000066400000000000000000000003511355360272700245440ustar00rootroot00000000000000# # Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # include drivers/auth/mbedtls/mbedtls_common.mk MBEDTLS_SOURCES += drivers/auth/mbedtls/mbedtls_crypto.c trusted-firmware-a-2.2/drivers/auth/mbedtls/mbedtls_x509.mk000066400000000000000000000003461355360272700237350ustar00rootroot00000000000000# # Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # include drivers/auth/mbedtls/mbedtls_common.mk MBEDTLS_SOURCES += drivers/auth/mbedtls/mbedtls_x509_parser.c trusted-firmware-a-2.2/drivers/auth/mbedtls/mbedtls_x509_parser.c000066400000000000000000000261051355360272700251250ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * X509 parser based on mbed TLS * * This module implements functions to check the integrity of a X509v3 * certificate ASN.1 structure and extract authentication parameters from the * extensions field, such as an image hash or a public key. */ #include #include #include #include /* mbed TLS headers */ #include #include #include #include #include #include #include /* Maximum OID string length ("a.b.c.d.e.f ...") */ #define MAX_OID_STR_LEN 64 #define LIB_NAME "mbed TLS X509v3" /* Temporary variables to speed up the authentication parameters search. These * variables are assigned once during the integrity check and used any time an * authentication parameter is requested, so we do not have to parse the image * again */ static mbedtls_asn1_buf tbs; static mbedtls_asn1_buf v3_ext; static mbedtls_asn1_buf pk; static mbedtls_asn1_buf sig_alg; static mbedtls_asn1_buf signature; /* * Clear all static temporary variables. */ static void clear_temp_vars(void) { #define ZERO_AND_CLEAN(x) \ do { \ zeromem(&x, sizeof(x)); \ clean_dcache_range((uintptr_t)&x, sizeof(x)); \ } while (0); ZERO_AND_CLEAN(tbs) ZERO_AND_CLEAN(v3_ext); ZERO_AND_CLEAN(pk); ZERO_AND_CLEAN(sig_alg); ZERO_AND_CLEAN(signature); #undef ZERO_AND_CLEAN } /* * Get X509v3 extension * * Global variable 'v3_ext' must point to the extensions region * in the certificate. No need to check for errors since the image has passed * the integrity check. */ static int get_ext(const char *oid, void **ext, unsigned int *ext_len) { int oid_len; size_t len; unsigned char *end_ext_data, *end_ext_octet; unsigned char *p; const unsigned char *end; char oid_str[MAX_OID_STR_LEN]; mbedtls_asn1_buf extn_oid; int is_critical; assert(oid != NULL); p = v3_ext.p; end = v3_ext.p + v3_ext.len; mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); while (p < end) { zeromem(&extn_oid, sizeof(extn_oid)); is_critical = 0; /* DEFAULT FALSE */ mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); end_ext_data = p + len; /* Get extension ID */ extn_oid.tag = *p; mbedtls_asn1_get_tag(&p, end, &extn_oid.len, MBEDTLS_ASN1_OID); extn_oid.p = p; p += extn_oid.len; /* Get optional critical */ mbedtls_asn1_get_bool(&p, end_ext_data, &is_critical); /* Extension data */ mbedtls_asn1_get_tag(&p, end_ext_data, &len, MBEDTLS_ASN1_OCTET_STRING); end_ext_octet = p + len; /* Detect requested extension */ oid_len = mbedtls_oid_get_numeric_string(oid_str, MAX_OID_STR_LEN, &extn_oid); if (oid_len == MBEDTLS_ERR_OID_BUF_TOO_SMALL) { return IMG_PARSER_ERR; } if ((oid_len == strlen(oid_str)) && !strcmp(oid, oid_str)) { *ext = (void *)p; *ext_len = (unsigned int)len; return IMG_PARSER_OK; } /* Next */ p = end_ext_octet; } return IMG_PARSER_ERR_NOT_FOUND; } /* * Check the integrity of the certificate ASN.1 structure. * * Extract the relevant data that will be used later during authentication. * * This function doesn't clear the static variables located on the top of this * file in case of an error. It is only called from check_integrity(), which * performs the cleanup if necessary. */ static int cert_parse(void *img, unsigned int img_len) { int ret, is_critical; size_t len; unsigned char *p, *end, *crt_end; mbedtls_asn1_buf sig_alg1, sig_alg2; p = (unsigned char *)img; len = img_len; end = p + len; /* * Certificate ::= SEQUENCE { * tbsCertificate TBSCertificate, * signatureAlgorithm AlgorithmIdentifier, * signatureValue BIT STRING } */ ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (ret != 0) { return IMG_PARSER_ERR_FORMAT; } if (len > (size_t)(end - p)) { return IMG_PARSER_ERR_FORMAT; } crt_end = p + len; /* * TBSCertificate ::= SEQUENCE { */ tbs.p = p; ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (ret != 0) { return IMG_PARSER_ERR_FORMAT; } end = p + len; tbs.len = end - tbs.p; /* * Version ::= INTEGER { v1(0), v2(1), v3(2) } */ ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0); if (ret != 0) { return IMG_PARSER_ERR_FORMAT; } p += len; /* * CertificateSerialNumber ::= INTEGER */ ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_INTEGER); if (ret != 0) { return IMG_PARSER_ERR_FORMAT; } p += len; /* * signature AlgorithmIdentifier */ sig_alg1.p = p; ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (ret != 0) { return IMG_PARSER_ERR_FORMAT; } if ((end - p) < 1) { return IMG_PARSER_ERR_FORMAT; } sig_alg1.len = (p + len) - sig_alg1.p; p += len; /* * issuer Name */ ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (ret != 0) { return IMG_PARSER_ERR_FORMAT; } p += len; /* * Validity ::= SEQUENCE { * notBefore Time, * notAfter Time } * */ ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (ret != 0) { return IMG_PARSER_ERR_FORMAT; } p += len; /* * subject Name */ ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (ret != 0) { return IMG_PARSER_ERR_FORMAT; } p += len; /* * SubjectPublicKeyInfo */ pk.p = p; ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (ret != 0) { return IMG_PARSER_ERR_FORMAT; } pk.len = (p + len) - pk.p; p += len; /* * issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, */ ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1); if (ret != 0) { if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { return IMG_PARSER_ERR_FORMAT; } } else { p += len; } /* * subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, */ ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 2); if (ret != 0) { if (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG) { return IMG_PARSER_ERR_FORMAT; } } else { p += len; } /* * extensions [3] EXPLICIT Extensions OPTIONAL */ ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 3); if (ret != 0) { return IMG_PARSER_ERR_FORMAT; } /* * Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension */ v3_ext.p = p; ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (ret != 0) { return IMG_PARSER_ERR_FORMAT; } v3_ext.len = (p + len) - v3_ext.p; /* * Check extensions integrity */ while (p < end) { ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (ret != 0) { return IMG_PARSER_ERR_FORMAT; } /* Get extension ID */ ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OID); if (ret != 0) { return IMG_PARSER_ERR_FORMAT; } p += len; /* Get optional critical */ ret = mbedtls_asn1_get_bool(&p, end, &is_critical); if ((ret != 0) && (ret != MBEDTLS_ERR_ASN1_UNEXPECTED_TAG)) { return IMG_PARSER_ERR_FORMAT; } /* Data should be octet string type */ ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_OCTET_STRING); if (ret != 0) { return IMG_PARSER_ERR_FORMAT; } p += len; } if (p != end) { return IMG_PARSER_ERR_FORMAT; } end = crt_end; /* * } * -- end of TBSCertificate * * signatureAlgorithm AlgorithmIdentifier */ sig_alg2.p = p; ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE); if (ret != 0) { return IMG_PARSER_ERR_FORMAT; } if ((end - p) < 1) { return IMG_PARSER_ERR_FORMAT; } sig_alg2.len = (p + len) - sig_alg2.p; p += len; /* Compare both signature algorithms */ if (sig_alg1.len != sig_alg2.len) { return IMG_PARSER_ERR_FORMAT; } if (0 != memcmp(sig_alg1.p, sig_alg2.p, sig_alg1.len)) { return IMG_PARSER_ERR_FORMAT; } memcpy(&sig_alg, &sig_alg1, sizeof(sig_alg)); /* * signatureValue BIT STRING */ signature.p = p; ret = mbedtls_asn1_get_tag(&p, end, &len, MBEDTLS_ASN1_BIT_STRING); if (ret != 0) { return IMG_PARSER_ERR_FORMAT; } signature.len = (p + len) - signature.p; p += len; /* Check certificate length */ if (p != end) { return IMG_PARSER_ERR_FORMAT; } return IMG_PARSER_OK; } /* Exported functions */ static void init(void) { mbedtls_init(); } /* * Wrapper for cert_parse() that clears the static variables used by it in case * of an error. */ static int check_integrity(void *img, unsigned int img_len) { int rc = cert_parse(img, img_len); if (rc != IMG_PARSER_OK) clear_temp_vars(); return rc; } /* * Extract an authentication parameter from an X509v3 certificate * * This function returns a pointer to the extracted data and its length. * Depending on the type of parameter, a pointer to the data stored in the * certificate may be returned (i.e. an octet string containing a hash). Other * data may need to be copied and formatted (i.e. integers). In the later case, * a buffer of the correct type needs to be statically allocated, filled and * returned. */ static int get_auth_param(const auth_param_type_desc_t *type_desc, void *img, unsigned int img_len, void **param, unsigned int *param_len) { int rc = IMG_PARSER_OK; /* We do not use img because the check_integrity function has already * extracted the relevant data (v3_ext, pk, sig_alg, etc) */ switch (type_desc->type) { case AUTH_PARAM_RAW_DATA: /* Data to be signed */ *param = (void *)tbs.p; *param_len = (unsigned int)tbs.len; break; case AUTH_PARAM_HASH: case AUTH_PARAM_NV_CTR: /* All these parameters are included as X509v3 extensions */ rc = get_ext(type_desc->cookie, param, param_len); break; case AUTH_PARAM_PUB_KEY: if (type_desc->cookie != 0) { /* Get public key from extension */ rc = get_ext(type_desc->cookie, param, param_len); } else { /* Get the subject public key */ *param = (void *)pk.p; *param_len = (unsigned int)pk.len; } break; case AUTH_PARAM_SIG_ALG: /* Get the certificate signature algorithm */ *param = (void *)sig_alg.p; *param_len = (unsigned int)sig_alg.len; break; case AUTH_PARAM_SIG: /* Get the certificate signature */ *param = (void *)signature.p; *param_len = (unsigned int)signature.len; break; default: rc = IMG_PARSER_ERR_NOT_FOUND; break; } return rc; } REGISTER_IMG_PARSER_LIB(IMG_CERT, LIB_NAME, init, \ check_integrity, get_auth_param); trusted-firmware-a-2.2/drivers/auth/tbbr/000077500000000000000000000000001355360272700204615ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/auth/tbbr/tbbr_cot.c000066400000000000000000000513421355360272700224300ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #if USE_TBBR_DEFS #include #else #include #endif /* * Maximum key and hash sizes (in DER format) */ #if TF_MBEDTLS_USE_RSA #if TF_MBEDTLS_KEY_SIZE == 1024 #define PK_DER_LEN 162 #elif TF_MBEDTLS_KEY_SIZE == 2048 #define PK_DER_LEN 294 #elif TF_MBEDTLS_KEY_SIZE == 3072 #define PK_DER_LEN 422 #elif TF_MBEDTLS_KEY_SIZE == 4096 #define PK_DER_LEN 550 #else #error "Invalid value for TF_MBEDTLS_KEY_SIZE" #endif #else #define PK_DER_LEN 294 #endif #define HASH_DER_LEN 83 /* * The platform must allocate buffers to store the authentication parameters * extracted from the certificates. In this case, because of the way the CoT is * established, we can reuse some of the buffers on different stages */ static unsigned char tb_fw_hash_buf[HASH_DER_LEN]; static unsigned char tb_fw_config_hash_buf[HASH_DER_LEN]; static unsigned char hw_config_hash_buf[HASH_DER_LEN]; static unsigned char scp_fw_hash_buf[HASH_DER_LEN]; static unsigned char nt_world_bl_hash_buf[HASH_DER_LEN]; #ifdef IMAGE_BL2 static unsigned char soc_fw_hash_buf[HASH_DER_LEN]; static unsigned char tos_fw_hash_buf[HASH_DER_LEN]; static unsigned char tos_fw_extra1_hash_buf[HASH_DER_LEN]; static unsigned char tos_fw_extra2_hash_buf[HASH_DER_LEN]; static unsigned char trusted_world_pk_buf[PK_DER_LEN]; static unsigned char non_trusted_world_pk_buf[PK_DER_LEN]; static unsigned char content_pk_buf[PK_DER_LEN]; static unsigned char soc_fw_config_hash_buf[HASH_DER_LEN]; static unsigned char tos_fw_config_hash_buf[HASH_DER_LEN]; static unsigned char nt_fw_config_hash_buf[HASH_DER_LEN]; #endif /* * Parameter type descriptors */ static auth_param_type_desc_t trusted_nv_ctr = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_NV_CTR, TRUSTED_FW_NVCOUNTER_OID); static auth_param_type_desc_t subject_pk = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_PUB_KEY, 0); static auth_param_type_desc_t sig = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_SIG, 0); static auth_param_type_desc_t sig_alg = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_SIG_ALG, 0); static auth_param_type_desc_t raw_data = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_RAW_DATA, 0); static auth_param_type_desc_t tb_fw_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, TRUSTED_BOOT_FW_HASH_OID); static auth_param_type_desc_t tb_fw_config_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, TRUSTED_BOOT_FW_CONFIG_HASH_OID); static auth_param_type_desc_t hw_config_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, HW_CONFIG_HASH_OID); #ifdef IMAGE_BL1 static auth_param_type_desc_t scp_bl2u_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, SCP_FWU_CFG_HASH_OID); static auth_param_type_desc_t bl2u_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, AP_FWU_CFG_HASH_OID); static auth_param_type_desc_t ns_bl2u_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, FWU_HASH_OID); #endif /* IMAGE_BL1 */ #ifdef IMAGE_BL2 static auth_param_type_desc_t non_trusted_nv_ctr = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_NV_CTR, NON_TRUSTED_FW_NVCOUNTER_OID); static auth_param_type_desc_t trusted_world_pk = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_PUB_KEY, TRUSTED_WORLD_PK_OID); static auth_param_type_desc_t non_trusted_world_pk = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_PUB_KEY, NON_TRUSTED_WORLD_PK_OID); static auth_param_type_desc_t scp_fw_content_pk = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_PUB_KEY, SCP_FW_CONTENT_CERT_PK_OID); static auth_param_type_desc_t soc_fw_content_pk = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_PUB_KEY, SOC_FW_CONTENT_CERT_PK_OID); static auth_param_type_desc_t tos_fw_content_pk = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_PUB_KEY, TRUSTED_OS_FW_CONTENT_CERT_PK_OID); static auth_param_type_desc_t nt_fw_content_pk = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_PUB_KEY, NON_TRUSTED_FW_CONTENT_CERT_PK_OID); static auth_param_type_desc_t scp_fw_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, SCP_FW_HASH_OID); static auth_param_type_desc_t soc_fw_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, SOC_AP_FW_HASH_OID); static auth_param_type_desc_t soc_fw_config_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, SOC_FW_CONFIG_HASH_OID); static auth_param_type_desc_t tos_fw_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, TRUSTED_OS_FW_HASH_OID); static auth_param_type_desc_t tos_fw_config_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, TRUSTED_OS_FW_CONFIG_HASH_OID); static auth_param_type_desc_t tos_fw_extra1_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, TRUSTED_OS_FW_EXTRA1_HASH_OID); static auth_param_type_desc_t tos_fw_extra2_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, TRUSTED_OS_FW_EXTRA2_HASH_OID); static auth_param_type_desc_t nt_world_bl_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID); static auth_param_type_desc_t nt_fw_config_hash = AUTH_PARAM_TYPE_DESC( AUTH_PARAM_HASH, NON_TRUSTED_FW_CONFIG_HASH_OID); #endif /* IMAGE_BL2 */ /* * BL2 */ static const auth_img_desc_t trusted_boot_fw_cert = { .img_id = TRUSTED_BOOT_FW_CERT_ID, .img_type = IMG_CERT, .parent = NULL, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &subject_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &trusted_nv_ctr, .plat_nv_ctr = &trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &tb_fw_hash, .data = { .ptr = (void *)tb_fw_hash_buf, .len = (unsigned int)HASH_DER_LEN } }, [1] = { .type_desc = &tb_fw_config_hash, .data = { .ptr = (void *)tb_fw_config_hash_buf, .len = (unsigned int)HASH_DER_LEN } }, [2] = { .type_desc = &hw_config_hash, .data = { .ptr = (void *)hw_config_hash_buf, .len = (unsigned int)HASH_DER_LEN } } } }; #ifdef IMAGE_BL1 static const auth_img_desc_t bl2_image = { .img_id = BL2_IMAGE_ID, .img_type = IMG_RAW, .parent = &trusted_boot_fw_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &tb_fw_hash } } } }; #endif /* IMAGE_BL1 */ /* HW Config */ static const auth_img_desc_t hw_config = { .img_id = HW_CONFIG_ID, .img_type = IMG_RAW, .parent = &trusted_boot_fw_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &hw_config_hash } } } }; /* TB FW Config */ #ifdef IMAGE_BL1 static const auth_img_desc_t tb_fw_config = { .img_id = TB_FW_CONFIG_ID, .img_type = IMG_RAW, .parent = &trusted_boot_fw_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &tb_fw_config_hash } } } }; #endif /* IMAGE_BL1 */ #ifdef IMAGE_BL2 /* * Trusted key certificate */ static const auth_img_desc_t trusted_key_cert = { .img_id = TRUSTED_KEY_CERT_ID, .img_type = IMG_CERT, .parent = NULL, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &subject_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &trusted_nv_ctr, .plat_nv_ctr = &trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &trusted_world_pk, .data = { .ptr = (void *)trusted_world_pk_buf, .len = (unsigned int)PK_DER_LEN } }, [1] = { .type_desc = &non_trusted_world_pk, .data = { .ptr = (void *)non_trusted_world_pk_buf, .len = (unsigned int)PK_DER_LEN } } } }; /* * SCP Firmware */ static const auth_img_desc_t scp_fw_key_cert = { .img_id = SCP_FW_KEY_CERT_ID, .img_type = IMG_CERT, .parent = &trusted_key_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &trusted_world_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &trusted_nv_ctr, .plat_nv_ctr = &trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &scp_fw_content_pk, .data = { .ptr = (void *)content_pk_buf, .len = (unsigned int)PK_DER_LEN } } } }; static const auth_img_desc_t scp_fw_content_cert = { .img_id = SCP_FW_CONTENT_CERT_ID, .img_type = IMG_CERT, .parent = &scp_fw_key_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &scp_fw_content_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &trusted_nv_ctr, .plat_nv_ctr = &trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &scp_fw_hash, .data = { .ptr = (void *)scp_fw_hash_buf, .len = (unsigned int)HASH_DER_LEN } } } }; static const auth_img_desc_t scp_bl2_image = { .img_id = SCP_BL2_IMAGE_ID, .img_type = IMG_RAW, .parent = &scp_fw_content_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &scp_fw_hash } } } }; /* * SoC Firmware */ static const auth_img_desc_t soc_fw_key_cert = { .img_id = SOC_FW_KEY_CERT_ID, .img_type = IMG_CERT, .parent = &trusted_key_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &trusted_world_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &trusted_nv_ctr, .plat_nv_ctr = &trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &soc_fw_content_pk, .data = { .ptr = (void *)content_pk_buf, .len = (unsigned int)PK_DER_LEN } } } }; static const auth_img_desc_t soc_fw_content_cert = { .img_id = SOC_FW_CONTENT_CERT_ID, .img_type = IMG_CERT, .parent = &soc_fw_key_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &soc_fw_content_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &trusted_nv_ctr, .plat_nv_ctr = &trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &soc_fw_hash, .data = { .ptr = (void *)soc_fw_hash_buf, .len = (unsigned int)HASH_DER_LEN } }, [1] = { .type_desc = &soc_fw_config_hash, .data = { .ptr = (void *)soc_fw_config_hash_buf, .len = (unsigned int)HASH_DER_LEN } } } }; static const auth_img_desc_t bl31_image = { .img_id = BL31_IMAGE_ID, .img_type = IMG_RAW, .parent = &soc_fw_content_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &soc_fw_hash } } } }; /* SOC FW Config */ static const auth_img_desc_t soc_fw_config = { .img_id = SOC_FW_CONFIG_ID, .img_type = IMG_RAW, .parent = &soc_fw_content_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &soc_fw_config_hash } } } }; /* * Trusted OS Firmware */ static const auth_img_desc_t trusted_os_fw_key_cert = { .img_id = TRUSTED_OS_FW_KEY_CERT_ID, .img_type = IMG_CERT, .parent = &trusted_key_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &trusted_world_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &trusted_nv_ctr, .plat_nv_ctr = &trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &tos_fw_content_pk, .data = { .ptr = (void *)content_pk_buf, .len = (unsigned int)PK_DER_LEN } } } }; static const auth_img_desc_t trusted_os_fw_content_cert = { .img_id = TRUSTED_OS_FW_CONTENT_CERT_ID, .img_type = IMG_CERT, .parent = &trusted_os_fw_key_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &tos_fw_content_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &trusted_nv_ctr, .plat_nv_ctr = &trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &tos_fw_hash, .data = { .ptr = (void *)tos_fw_hash_buf, .len = (unsigned int)HASH_DER_LEN } }, [1] = { .type_desc = &tos_fw_extra1_hash, .data = { .ptr = (void *)tos_fw_extra1_hash_buf, .len = (unsigned int)HASH_DER_LEN } }, [2] = { .type_desc = &tos_fw_extra2_hash, .data = { .ptr = (void *)tos_fw_extra2_hash_buf, .len = (unsigned int)HASH_DER_LEN } }, [3] = { .type_desc = &tos_fw_config_hash, .data = { .ptr = (void *)tos_fw_config_hash_buf, .len = (unsigned int)HASH_DER_LEN } } } }; static const auth_img_desc_t bl32_image = { .img_id = BL32_IMAGE_ID, .img_type = IMG_RAW, .parent = &trusted_os_fw_content_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &tos_fw_hash } } } }; static const auth_img_desc_t bl32_extra1_image = { .img_id = BL32_EXTRA1_IMAGE_ID, .img_type = IMG_RAW, .parent = &trusted_os_fw_content_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &tos_fw_extra1_hash } } } }; static const auth_img_desc_t bl32_extra2_image = { .img_id = BL32_EXTRA2_IMAGE_ID, .img_type = IMG_RAW, .parent = &trusted_os_fw_content_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &tos_fw_extra2_hash } } } }; /* TOS FW Config */ static const auth_img_desc_t tos_fw_config = { .img_id = TOS_FW_CONFIG_ID, .img_type = IMG_RAW, .parent = &trusted_os_fw_content_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &tos_fw_config_hash } } } }; /* * Non-Trusted Firmware */ static const auth_img_desc_t non_trusted_fw_key_cert = { .img_id = NON_TRUSTED_FW_KEY_CERT_ID, .img_type = IMG_CERT, .parent = &trusted_key_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &non_trusted_world_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &non_trusted_nv_ctr, .plat_nv_ctr = &non_trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &nt_fw_content_pk, .data = { .ptr = (void *)content_pk_buf, .len = (unsigned int)PK_DER_LEN } } } }; static const auth_img_desc_t non_trusted_fw_content_cert = { .img_id = NON_TRUSTED_FW_CONTENT_CERT_ID, .img_type = IMG_CERT, .parent = &non_trusted_fw_key_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &nt_fw_content_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } }, [1] = { .type = AUTH_METHOD_NV_CTR, .param.nv_ctr = { .cert_nv_ctr = &non_trusted_nv_ctr, .plat_nv_ctr = &non_trusted_nv_ctr } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &nt_world_bl_hash, .data = { .ptr = (void *)nt_world_bl_hash_buf, .len = (unsigned int)HASH_DER_LEN } }, [1] = { .type_desc = &nt_fw_config_hash, .data = { .ptr = (void *)nt_fw_config_hash_buf, .len = (unsigned int)HASH_DER_LEN } } } }; static const auth_img_desc_t bl33_image = { .img_id = BL33_IMAGE_ID, .img_type = IMG_RAW, .parent = &non_trusted_fw_content_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &nt_world_bl_hash } } } }; /* NT FW Config */ static const auth_img_desc_t nt_fw_config = { .img_id = NT_FW_CONFIG_ID, .img_type = IMG_RAW, .parent = &non_trusted_fw_content_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &nt_fw_config_hash } } } }; #else /* IMAGE_BL2 */ /* * FWU auth descriptor. */ static const auth_img_desc_t fwu_cert = { .img_id = FWU_CERT_ID, .img_type = IMG_CERT, .parent = NULL, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_SIG, .param.sig = { .pk = &subject_pk, .sig = &sig, .alg = &sig_alg, .data = &raw_data } } }, .authenticated_data = (const auth_param_desc_t[COT_MAX_VERIFIED_PARAMS]) { [0] = { .type_desc = &scp_bl2u_hash, .data = { .ptr = (void *)scp_fw_hash_buf, .len = (unsigned int)HASH_DER_LEN } }, [1] = { .type_desc = &bl2u_hash, .data = { .ptr = (void *)tb_fw_hash_buf, .len = (unsigned int)HASH_DER_LEN } }, [2] = { .type_desc = &ns_bl2u_hash, .data = { .ptr = (void *)nt_world_bl_hash_buf, .len = (unsigned int)HASH_DER_LEN } } } }; /* * SCP_BL2U */ static const auth_img_desc_t scp_bl2u_image = { .img_id = SCP_BL2U_IMAGE_ID, .img_type = IMG_RAW, .parent = &fwu_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &scp_bl2u_hash } } } }; /* * BL2U */ static const auth_img_desc_t bl2u_image = { .img_id = BL2U_IMAGE_ID, .img_type = IMG_RAW, .parent = &fwu_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &bl2u_hash } } } }; /* * NS_BL2U */ static const auth_img_desc_t ns_bl2u_image = { .img_id = NS_BL2U_IMAGE_ID, .img_type = IMG_RAW, .parent = &fwu_cert, .img_auth_methods = (const auth_method_desc_t[AUTH_METHOD_NUM]) { [0] = { .type = AUTH_METHOD_HASH, .param.hash = { .data = &raw_data, .hash = &ns_bl2u_hash } } } }; #endif /* IMAGE_BL2 */ /* * TBBR Chain of trust definition */ #ifdef IMAGE_BL1 static const auth_img_desc_t * const cot_desc[] = { [TRUSTED_BOOT_FW_CERT_ID] = &trusted_boot_fw_cert, [BL2_IMAGE_ID] = &bl2_image, [HW_CONFIG_ID] = &hw_config, [TB_FW_CONFIG_ID] = &tb_fw_config, [FWU_CERT_ID] = &fwu_cert, [SCP_BL2U_IMAGE_ID] = &scp_bl2u_image, [BL2U_IMAGE_ID] = &bl2u_image, [NS_BL2U_IMAGE_ID] = &ns_bl2u_image }; #else /* IMAGE_BL2 */ static const auth_img_desc_t * const cot_desc[] = { [TRUSTED_BOOT_FW_CERT_ID] = &trusted_boot_fw_cert, [HW_CONFIG_ID] = &hw_config, [TRUSTED_KEY_CERT_ID] = &trusted_key_cert, [SCP_FW_KEY_CERT_ID] = &scp_fw_key_cert, [SCP_FW_CONTENT_CERT_ID] = &scp_fw_content_cert, [SCP_BL2_IMAGE_ID] = &scp_bl2_image, [SOC_FW_KEY_CERT_ID] = &soc_fw_key_cert, [SOC_FW_CONTENT_CERT_ID] = &soc_fw_content_cert, [BL31_IMAGE_ID] = &bl31_image, [SOC_FW_CONFIG_ID] = &soc_fw_config, [TRUSTED_OS_FW_KEY_CERT_ID] = &trusted_os_fw_key_cert, [TRUSTED_OS_FW_CONTENT_CERT_ID] = &trusted_os_fw_content_cert, [BL32_IMAGE_ID] = &bl32_image, [BL32_EXTRA1_IMAGE_ID] = &bl32_extra1_image, [BL32_EXTRA2_IMAGE_ID] = &bl32_extra2_image, [TOS_FW_CONFIG_ID] = &tos_fw_config, [NON_TRUSTED_FW_KEY_CERT_ID] = &non_trusted_fw_key_cert, [NON_TRUSTED_FW_CONTENT_CERT_ID] = &non_trusted_fw_content_cert, [BL33_IMAGE_ID] = &bl33_image, [NT_FW_CONFIG_ID] = &nt_fw_config, }; #endif /* Register the CoT in the authentication module */ REGISTER_COT(cot_desc); trusted-firmware-a-2.2/drivers/cadence/000077500000000000000000000000001355360272700201515ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/cadence/uart/000077500000000000000000000000001355360272700211245ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/cadence/uart/aarch64/000077500000000000000000000000001355360272700223545ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/cadence/uart/aarch64/cdns_console.S000066400000000000000000000144541355360272700251610ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* * "core" functions are low-level implementations that don't require * writable memory and are thus safe to call in BL1 crash context. */ .globl console_cdns_core_init .globl console_cdns_core_putc .globl console_cdns_core_getc .globl console_cdns_core_flush .globl console_cdns_putc .globl console_cdns_getc .globl console_cdns_flush /* ----------------------------------------------- * int console_cdns_core_init(uintptr_t base_addr) * Function to initialize the console without a * C Runtime to print debug information. This * function will be accessed by console_init and * crash reporting. * We assume that the bootloader already set up * the HW (baud, ...) and only enable the trans- * mitter and receiver here. * In: x0 - console base address * Out: return 1 on success else 0 on error * Clobber list : x1, x2, x3 * ----------------------------------------------- */ func console_cdns_core_init /* Check the input base address */ cbz x0, core_init_fail /* RX/TX enabled & reset */ mov w3, #(R_UART_CR_TX_EN | R_UART_CR_RX_EN | R_UART_CR_TXRST | R_UART_CR_RXRST) str w3, [x0, #R_UART_CR] mov w0, #1 ret core_init_fail: mov w0, wzr ret endfunc console_cdns_core_init .globl console_cdns_register /* ----------------------------------------------- * int console_cdns_register(uintptr_t baseaddr, * uint32_t clock, uint32_t baud, * console_cdns_t *console); * Function to initialize and register a new CDNS * console. Storage passed in for the console struct * *must* be persistent (i.e. not from the stack). * In: x0 - UART register base address * w1 - UART clock in Hz * w2 - Baud rate * x3 - pointer to empty console_16550_t struct * Out: return 1 on success, 0 on error * Clobber list : x0, x1, x2, x6, x7, x14 * ----------------------------------------------- */ func console_cdns_register mov x7, x30 mov x6, x3 cbz x6, register_fail str x0, [x6, #CONSOLE_T_CDNS_BASE] bl console_cdns_core_init cbz x0, register_fail mov x0, x6 mov x30, x7 finish_console_register cdns putc=1, getc=1, flush=1 register_fail: ret x7 endfunc console_cdns_register /* -------------------------------------------------------- * int console_cdns_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. * In : w0 - character to be printed * x1 - console base address * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_cdns_core_putc #if ENABLE_ASSERTIONS cmp x1, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ /* Prepend '\r' to '\n' */ cmp w0, #0xA b.ne 2f 1: /* Check if the transmit FIFO is full */ ldr w2, [x1, #R_UART_SR] tbnz w2, #UART_SR_INTR_TFUL_BIT, 1b mov w2, #0xD str w2, [x1, #R_UART_TX] 2: /* Check if the transmit FIFO is full */ ldr w2, [x1, #R_UART_SR] tbnz w2, #UART_SR_INTR_TFUL_BIT, 2b str w0, [x1, #R_UART_TX] ret endfunc console_cdns_core_putc /* -------------------------------------------------------- * int console_cdns_putc(int c, console_cdns_t *cdns) * Function to output a character over the console. It * returns the character printed on success or -1 on error. * In : w0 - character to be printed * x1 - pointer to console_t structure * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_cdns_putc #if ENABLE_ASSERTIONS cmp x1, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr x1, [x1, #CONSOLE_T_CDNS_BASE] b console_cdns_core_putc endfunc console_cdns_putc /* --------------------------------------------- * int console_cdns_core_getc(uintptr_t base_addr) * Function to get a character from the console. * It returns the character grabbed on success * or -1 if no character is available. * In : x0 - console base address * Out: w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ func console_cdns_core_getc #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ /* Check if the receive FIFO is empty */ ldr w1, [x0, #R_UART_SR] tbnz w1, #UART_SR_INTR_REMPTY_BIT, no_char ldr w1, [x0, #R_UART_RX] mov w0, w1 ret no_char: mov w0, #ERROR_NO_PENDING_CHAR ret endfunc console_cdns_core_getc /* --------------------------------------------- * int console_cdns_getc(console_cdns_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 : x0 - pointer to console_t structure * Out: w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ func console_cdns_getc #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr x0, [x0, #CONSOLE_T_CDNS_BASE] b console_cdns_core_getc endfunc console_cdns_getc /* --------------------------------------------- * int console_cdns_core_flush(uintptr_t base_addr) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - console base address * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func console_cdns_core_flush #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ /* Placeholder */ mov w0, #0 ret endfunc console_cdns_core_flush /* --------------------------------------------- * int console_cdns_flush(console_pl011_t *console) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - pointer to console_t structure * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func console_cdns_flush #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr x0, [x0, #CONSOLE_T_CDNS_BASE] b console_cdns_core_flush endfunc console_cdns_flush trusted-firmware-a-2.2/drivers/cfi/000077500000000000000000000000001355360272700173305ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/cfi/v2m/000077500000000000000000000000001355360272700200345ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/cfi/v2m/v2m_flash.c000066400000000000000000000110561355360272700220640ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /* * This file supplies a low level interface to the vexpress NOR flash * memory of juno and fvp. This memory is organized as an interleaved * memory of two chips with a 16 bit word. It means that every 32 bit * access is going to access to two different chips. This is very * important when we send commands or read status of the chips. */ /* * DWS ready poll retries. The number of retries in this driver have been * obtained empirically from Juno. FVP implements a zero wait state NOR flash * model */ #define DWS_WORD_PROGRAM_RETRIES 1000 #define DWS_WORD_ERASE_RETRIES 3000000 #define DWS_WORD_LOCK_RETRIES 1000 /* Helper macro to detect end of command */ #define NOR_CMD_END (NOR_DWS | NOR_DWS << 16l) /* Helper macros to access two flash banks in parallel */ #define NOR_2X16(d) ((d << 16) | (d & 0xffff)) static unsigned int nor_status(uintptr_t base_addr) { unsigned long status; nor_send_cmd(base_addr, NOR_CMD_READ_STATUS_REG); status = mmio_read_32(base_addr); status |= status >> 16; /* merge status from both flash banks */ return status & 0xFFFF; } /* * Poll Write State Machine. * Return values: * 0 = WSM ready * -EBUSY = WSM busy after the number of retries */ static int nor_poll_dws(uintptr_t base_addr, unsigned long int retries) { unsigned long status; do { nor_send_cmd(base_addr, NOR_CMD_READ_STATUS_REG); status = mmio_read_32(base_addr); if ((status & NOR_CMD_END) == NOR_CMD_END) return 0; } while (retries-- > 0); return -EBUSY; } /* * Return values: * 0 = success * -EPERM = Device protected or Block locked * -EIO = General I/O error */ static int nor_full_status_check(uintptr_t base_addr) { unsigned long status; /* Full status check */ status = nor_status(base_addr); if (status & (NOR_PS | NOR_BLS | NOR_ESS | NOR_PSS)) return -EPERM; if (status & (NOR_VPPS | NOR_ES)) return -EIO; return 0; } void nor_send_cmd(uintptr_t base_addr, unsigned long cmd) { mmio_write_32(base_addr, NOR_2X16(cmd)); } /* * This function programs a word in the flash. Be aware that it only * can reset bits that were previously set. It cannot set bits that * were previously reset. The resulting bits = old_bits & new bits. * Return values: * 0 = success * otherwise it returns a negative value */ int nor_word_program(uintptr_t base_addr, unsigned long data) { uint32_t status; int ret; nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG); /* Set the device in write word mode */ nor_send_cmd(base_addr, NOR_CMD_WORD_PROGRAM); mmio_write_32(base_addr, data); ret = nor_poll_dws(base_addr, DWS_WORD_PROGRAM_RETRIES); if (ret == 0) { /* Full status check */ nor_send_cmd(base_addr, NOR_CMD_READ_STATUS_REG); status = mmio_read_32(base_addr); if (status & (NOR_PS | NOR_BLS)) { nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG); ret = -EPERM; } } if (ret == 0) ret = nor_full_status_check(base_addr); nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY); return ret; } /* * Erase a full 256K block * Return values: * 0 = success * otherwise it returns a negative value */ int nor_erase(uintptr_t base_addr) { int ret; nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG); nor_send_cmd(base_addr, NOR_CMD_BLOCK_ERASE); nor_send_cmd(base_addr, NOR_CMD_BLOCK_ERASE_ACK); ret = nor_poll_dws(base_addr, DWS_WORD_ERASE_RETRIES); if (ret == 0) ret = nor_full_status_check(base_addr); nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY); return ret; } /* * Lock a full 256 block * Return values: * 0 = success * otherwise it returns a negative value */ int nor_lock(uintptr_t base_addr) { int ret; nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG); nor_send_cmd(base_addr, NOR_CMD_LOCK_UNLOCK); nor_send_cmd(base_addr, NOR_LOCK_BLOCK); ret = nor_poll_dws(base_addr, DWS_WORD_LOCK_RETRIES); if (ret == 0) ret = nor_full_status_check(base_addr); nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY); return ret; } /* * unlock a full 256 block * Return values: * 0 = success * otherwise it returns a negative value */ int nor_unlock(uintptr_t base_addr) { int ret; nor_send_cmd(base_addr, NOR_CMD_CLEAR_STATUS_REG); nor_send_cmd(base_addr, NOR_CMD_LOCK_UNLOCK); nor_send_cmd(base_addr, NOR_UNLOCK_BLOCK); ret = nor_poll_dws(base_addr, DWS_WORD_LOCK_RETRIES); if (ret == 0) ret = nor_full_status_check(base_addr); nor_send_cmd(base_addr, NOR_CMD_READ_ARRAY); return ret; } trusted-firmware-a-2.2/drivers/console/000077500000000000000000000000001355360272700202315ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/console/aarch32/000077500000000000000000000000001355360272700214545ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/console/aarch32/skeleton_console.S000066400000000000000000000130161355360272700251470ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /* * This file contains a skeleton console driver that can be used as a * basis for a real console driver. Console drivers in Trusted Firmware * can be instantiated multiple times. Each instance is described by a * separate console_t structure which must be registered with the common * console framework via console_register(). Console drivers should * define a console_xxx_register() function that initializes a new * console_t structure passed in from the caller and registers it after * initializing the console hardware. Drivers may define their own * structures extending console_t to store private driver information. * Console drivers *MUST* ensure that the console callbacks they * implement only change registers allowed in the clobber lists defined * in this file. (Note that in addition to the explicit clobber lists, * any function may always clobber the intra-procedure-call register * r12, but may never depend on it retaining its value across any * function call.) */ .globl console_xxx_register .globl console_xxx_putc .globl console_xxx_getc .globl console_xxx_flush /* ----------------------------------------------- * int console_xxx_register(console_xxx_t *console, * ...additional parameters as desired...) * Function to initialize and register the console. * The caller needs to pass an empty console_xxx_t * structure in which *MUST* be allocated in * persistent memory (e.g. a global or static local * variable, *NOT* on the stack). * In : r0 - pointer to empty console_t structure * r1 through r7: additional parameters as desired * Out: r0 - 1 on success, 0 on error * Clobber list : r0 - r7 * ----------------------------------------------- */ func console_xxx_register /* * Store parameters (e.g. hardware base address) in driver-specific * console_xxx_t structure field if they will need to be retrieved * by later console callback (e.g. putc). * Example: */ str r1, [r0, #CONSOLE_T_XXX_BASE] str r2, [r0, #CONSOLE_T_XXX_SOME_OTHER_VALUE] /* * Initialize console hardware, using r1 - r7 parameters as needed. * Keep console_t pointer in r0 for later. */ /* * Macro to finish up registration and return (needs valid r0 + lr). * 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: mov r0, #0 bx lr endfunc console_xxx_register /* -------------------------------------------------------- * int console_xxx_putc(int c, console_xxx_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 struct * Out: r0 - printed character on success, < 0 on error. * Clobber list : r0, r1, r2 * -------------------------------------------------------- */ func console_xxx_putc /* * Retrieve values we need (e.g. hardware base address) from * console_xxx_t structure pointed to by r1. * Example: */ ldr r1, [r1, #CONSOLE_T_XXX_BASE] /* * Write r0 to hardware. */ bx lr /* Jump here if output fails for any reason. */ putc_error: mov r0, #-1 bx lr endfunc console_xxx_putc /* --------------------------------------------- * int console_xxx_getc(console_xxx_t *console) * Function to get a character from the console. * Even though console_getc() is blocking, this * callback has to be non-blocking and always * return immediately to allow polling multiple * drivers concurrently. * Returns the character grabbed on success, * ERROR_NO_PENDING_CHAR if no character was * available at this time, or any value * between -2 and -127 if there was an error. * In : r0 - pointer to console_t struct * Out: r0 - character on success, * ERROR_NO_PENDING_CHAR if no char, * < -1 on error * Clobber list : r0, r1 * --------------------------------------------- */ func console_xxx_getc /* * Retrieve values we need (e.g. hardware base address) from * console_xxx_t structure pointed to by r0. * Example: */ ldr r1, [r0, #CONSOLE_T_XXX_BASE] /* * Try to read character into r0 from hardware. */ bx lr /* Jump here if there is no character available at this time. */ getc_no_char: mov r0, #ERROR_NO_PENDING_CHAR bx lr /* Jump here if there was any hardware error. */ getc_error: mov r0, #-2 /* may pick error codes between -2 and -127 */ bx lr endfunc console_xxx_getc /* --------------------------------------------- * int console_xxx_flush(console_xxx_t *console) * Function to force a write of all buffered * data that hasn't been output. * In : r0 - pointer to console_xxx_t struct * Out: r0 - 0 on success, < 0 on error * Clobber list : r0, r1, r2, r3, r4, r5 * --------------------------------------------- */ func console_xxx_flush /* * Retrieve values we need (e.g. hardware base address) from * console_xxx_t structure pointed to by r0. * Example: */ ldr r1, [r0, #CONSOLE_T_XXX_BASE] /* * Flush all remaining output from hardware FIFOs. Do not return until * all data has been flushed or there was an unrecoverable error. */ mov r0, #0 bx lr /* Jump here if an unrecoverable error has been encountered. */ flush_error: mov r0, #-1 bx lr endfunc console_xxx_flush trusted-firmware-a-2.2/drivers/console/aarch64/000077500000000000000000000000001355360272700214615ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/console/aarch64/skeleton_console.S000066400000000000000000000130151355360272700251530ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /* * This file contains a skeleton console driver that can be used as a * basis for a real console driver. Console drivers in Trusted Firmware * can be instantiated multiple times. Each instance is described by a * separate console_t structure which must be registered with the common * console framework via console_register(). Console drivers should * define a console_xxx_register() function that initializes a new * console_t structure passed in from the caller and registers it after * initializing the console hardware. Drivers may define their own * structures extending console_t to store private driver information. * Console drivers *MUST* ensure that the console callbacks they * implement only change registers allowed in the clobber lists defined * in this file. (Note that in addition to the explicit clobber lists, * any function may always clobber the intra-procedure-call registers * X16 and X17, but may never depend on them retaining their values * across any function call.) */ .globl console_xxx_register .globl console_xxx_putc .globl console_xxx_getc .globl console_xxx_flush /* ----------------------------------------------- * int console_xxx_register(console_xxx_t *console, * ...additional parameters as desired...) * Function to initialize and register the console. * The caller needs to pass an empty console_xxx_t * structure in which *MUST* be allocated in * persistent memory (e.g. a global or static local * variable, *NOT* on the stack). * In : x0 - pointer to empty console_t structure * x1 through x7: additional parameters as desired * Out: x0 - 1 on success, 0 on error * Clobber list : x0 - x7 * ----------------------------------------------- */ func console_xxx_register /* * Store parameters (e.g. hardware base address) in driver-specific * console_xxx_t structure field if they will need to be retrieved * by later console callback (e.g. putc). * Example: */ str x1, [x0, #CONSOLE_T_XXX_BASE] str x2, [x0, #CONSOLE_T_XXX_SOME_OTHER_VALUE] /* * Initialize console hardware, using x1 - x7 parameters as needed. * Keep console_t pointer in x0 for later. */ /* * 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: mov w0, #0 ret endfunc console_xxx_register /* -------------------------------------------------------- * int console_xxx_putc(int c, console_xxx_t *console) * Function to output a character over the console. It * returns the character printed on success or -1 on error. * In : w0 - character to be printed * x1 - pointer to console_t struct * Out: w0 - printed character on success, < 0 on error. * Clobber list : x0, x1, x2 * -------------------------------------------------------- */ func console_xxx_putc /* * Retrieve values we need (e.g. hardware base address) from * console_xxx_t structure pointed to by x1. * Example: */ ldr x1, [x1, #CONSOLE_T_XXX_BASE] /* * Write w0 to hardware. */ ret /* Jump here if output fails for any reason. */ putc_error: mov w0, #-1 ret endfunc console_xxx_putc /* --------------------------------------------- * int console_xxx_getc(console_xxx_t *console) * Function to get a character from the console. * Even though console_getc() is blocking, this * callback has to be non-blocking and always * return immediately to allow polling multiple * drivers concurrently. * Returns the character grabbed on success, * ERROR_NO_PENDING_CHAR if no character was * available at this time, or any value * between -2 and -127 if there was an error. * In : x0 - pointer to console_t struct * Out: w0 - character on success, * ERROR_NO_PENDING_CHAR if no char, * < -1 on error * Clobber list : x0, x1 * --------------------------------------------- */ func console_xxx_getc /* * Retrieve values we need (e.g. hardware base address) from * console_xxx_t structure pointed to by x0. * Example: */ ldr x1, [x0, #CONSOLE_T_XXX_BASE] /* * Try to read character into w0 from hardware. */ ret /* Jump here if there is no character available at this time. */ getc_no_char: mov w0, #ERROR_NO_PENDING_CHAR ret /* Jump here if there was any hardware error. */ getc_error: mov w0, #-2 /* may pick error codes between -2 and -127 */ ret endfunc console_xxx_getc /* --------------------------------------------- * int console_xxx_flush(console_xxx_t *console) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - pointer to console_xxx_t struct * Out: w0 - 0 on success, < 0 on error * Clobber list : x0, x1, x2, x3, x4, x5 * --------------------------------------------- */ func console_xxx_flush /* * Retrieve values we need (e.g. hardware base address) from * console_xxx_t structure pointed to by x0. * Example: */ ldr x1, [x0, #CONSOLE_T_XXX_BASE] /* * Flush all remaining output from hardware FIFOs. Do not return until * all data has been flushed or there was an unrecoverable error. */ mov w0, #0 ret /* Jump here if an unrecoverable error has been encountered. */ flush_error: mov w0, #-1 ret endfunc console_xxx_flush trusted-firmware-a-2.2/drivers/console/multi_console.c000066400000000000000000000056031355360272700232550ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include console_t *console_list; uint8_t console_state = CONSOLE_FLAG_BOOT; IMPORT_SYM(console_t *, __STACKS_START__, stacks_start) IMPORT_SYM(console_t *, __STACKS_END__, stacks_end) int console_register(console_t *console) { /* Assert that the struct is not on the stack (common mistake). */ assert((console < stacks_start) || (console >= stacks_end)); /* Check that we won't make a circle in the list. */ if (console_is_registered(console) == 1) return 1; console->next = console_list; console_list = console; /* Return 1 for convenient tail-calling from console_xxx_register(). */ return 1; } console_t *console_unregister(console_t *to_be_deleted) { console_t **ptr; assert(to_be_deleted != NULL); for (ptr = &console_list; *ptr != NULL; ptr = &(*ptr)->next) if (*ptr == to_be_deleted) { *ptr = (*ptr)->next; return to_be_deleted; } return NULL; } int console_is_registered(console_t *to_find) { console_t *console; assert(to_find != NULL); for (console = console_list; console != NULL; console = console->next) if (console == to_find) return 1; return 0; } void console_switch_state(unsigned int new_state) { console_state = new_state; } void console_set_scope(console_t *console, unsigned int scope) { assert(console != NULL); console->flags = (console->flags & ~CONSOLE_FLAG_SCOPE_MASK) | scope; } static int do_putc(int c, console_t *console) { int ret; if ((c == '\n') && ((console->flags & CONSOLE_FLAG_TRANSLATE_CRLF) != 0)) { ret = console->putc('\r', console); if (ret < 0) return ret; } return console->putc(c, console); } int console_putc(int c) { int err = ERROR_NO_VALID_CONSOLE; console_t *console; for (console = console_list; console != NULL; console = console->next) if ((console->flags & console_state) && console->putc) { int ret = do_putc(c, console); if ((err == ERROR_NO_VALID_CONSOLE) || (ret < err)) err = ret; } return err; } int console_getc(void) { int err = ERROR_NO_VALID_CONSOLE; console_t *console; do { /* Keep polling while at least one console works correctly. */ for (console = console_list; console != NULL; console = console->next) if ((console->flags & console_state) && console->getc) { int ret = console->getc(console); if (ret >= 0) return ret; if (err != ERROR_NO_PENDING_CHAR) err = ret; } } while (err == ERROR_NO_PENDING_CHAR); return err; } int console_flush(void) { int err = ERROR_NO_VALID_CONSOLE; console_t *console; for (console = console_list; console != NULL; console = console->next) if ((console->flags & console_state) && console->flush) { int ret = console->flush(console); if ((err == ERROR_NO_VALID_CONSOLE) || (ret < err)) err = ret; } return err; } trusted-firmware-a-2.2/drivers/coreboot/000077500000000000000000000000001355360272700204035ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/coreboot/cbmem_console/000077500000000000000000000000001355360272700232105ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/coreboot/cbmem_console/aarch64/000077500000000000000000000000001355360272700244405ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/coreboot/cbmem_console/aarch64/cbmem_console.S000066400000000000000000000065631355360272700274030ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /* * This driver implements access to coreboot's in-memory console * (CBMEM console). For the original implementation, see * /src/lib/cbmem_console.c. */ .globl console_cbmc_register .globl console_cbmc_putc .globl console_cbmc_flush /* ----------------------------------------------- * int console_cbmc_register(uintptr_t base, * console_cbmc_t *console); * Registers a new CBMEM console instance. Reads * the size field from the buffer header structure * and stores it in our console_cbmc_t struct, so * that we keep the size in secure memory where we * can trust it. A malicious EL1 could manipulate * the console buffer (including the header), so we * must not trust its contents after boot. * In: x0 - CBMEM console base address * x1 - pointer to empty console_cbmc_t struct * Out: x0 - 1 to indicate success * Clobber list: x0, x1, x2, x7 * ----------------------------------------------- */ func console_cbmc_register str x0, [x1, #CONSOLE_T_CBMC_BASE] ldr w2, [x0] str w2, [x1, #CONSOLE_T_CBMC_SIZE] mov x0, x1 finish_console_register cbmc putc=1, flush=1 endfunc console_cbmc_register /* ----------------------------------------------- * int console_cbmc_puts(int c, console_cbmc_t *console) * Writes a character to the CBMEM console buffer, * including overflow handling of the cursor field. * The character must be preserved in x0. * In: x0 - character to be stored * x1 - pointer to console_cbmc_t struct * Clobber list: x1, x2, x16, x17 * ----------------------------------------------- */ func console_cbmc_putc ldr w2, [x1, #CONSOLE_T_CBMC_SIZE] ldr x1, [x1, #CONSOLE_T_CBMC_BASE] add x1, x1, #8 /* keep address of body in x1 */ ldr w16, [x1, #-4] /* load cursor (one u32 before body) */ and w17, w16, #0xf0000000 /* keep flags part in w17 */ and w16, w16, #0x0fffffff /* keep actual cursor part in w16 */ cmp w16, w2 /* sanity check that cursor < size */ b.lo putc_within_bounds mov w0, #-1 /* cursor >= size must be malicious */ ret /* so return error, don't write char */ putc_within_bounds: strb w0, [x1, w16, uxtw] /* body[cursor] = character */ add w16, w16, #1 /* cursor++ */ cmp w16, w2 /* if cursor < size... */ b.lo putc_write_back /* ...skip overflow handling */ mov w16, #0 /* on overflow, set cursor back to 0 */ orr w17, w17, #(1 << 31) /* and set overflow flag */ putc_write_back: orr w16, w16, w17 /* merge cursor and flags back */ str w16, [x1, #-4] /* write back cursor to memory */ ret endfunc console_cbmc_putc /* ----------------------------------------------- * int console_cbmc_flush(console_cbmc_t *console) * Flushes the CBMEM console by flushing the * console buffer from the CPU's data cache. * In: x0 - pointer to console_cbmc_t struct * Out: x0 - 0 for success * Clobber list: x0, x1, x2, x3, x5 * ----------------------------------------------- */ func console_cbmc_flush mov x5, x30 ldr x1, [x0, #CONSOLE_T_CBMC_SIZE] ldr x0, [x0, #CONSOLE_T_CBMC_BASE] add x1, x1, #8 /* add size of console header */ bl clean_dcache_range /* (clobbers x2 and x3) */ mov x0, #0 ret x5 endfunc console_cbmc_flush trusted-firmware-a-2.2/drivers/delay_timer/000077500000000000000000000000001355360272700210655ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/delay_timer/delay_timer.c000066400000000000000000000040201355360272700235230ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /*********************************************************** * The delay timer implementation ***********************************************************/ static const timer_ops_t *timer_ops; /*********************************************************** * Delay for the given number of microseconds. The driver must * be initialized before calling this function. ***********************************************************/ void udelay(uint32_t usec) { assert((timer_ops != NULL) && (timer_ops->clk_mult != 0U) && (timer_ops->clk_div != 0U) && (timer_ops->get_timer_value != NULL)); uint32_t start, delta, total_delta; assert(usec < (UINT32_MAX / timer_ops->clk_div)); start = timer_ops->get_timer_value(); /* Add an extra tick to avoid delaying less than requested. */ total_delta = div_round_up(usec * timer_ops->clk_div, timer_ops->clk_mult) + 1U; do { /* * If the timer value wraps around, the subtraction will * overflow and it will still give the correct result. */ delta = start - timer_ops->get_timer_value(); /* Decreasing counter */ } while (delta < total_delta); } /*********************************************************** * Delay for the given number of milliseconds. The driver must * be initialized before calling this function. ***********************************************************/ void mdelay(uint32_t msec) { udelay(msec * 1000U); } /*********************************************************** * Initialize the timer. The fields in the provided timer * ops pointer must be valid. ***********************************************************/ void timer_init(const timer_ops_t *ops_ptr) { assert((ops_ptr != NULL) && (ops_ptr->clk_mult != 0U) && (ops_ptr->clk_div != 0U) && (ops_ptr->get_timer_value != NULL)); timer_ops = ops_ptr; } trusted-firmware-a-2.2/drivers/delay_timer/generic_delay_timer.c000066400000000000000000000027411355360272700252270ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include /* Ticks elapsed in one second by a signal of 1 MHz */ #define MHZ_TICKS_PER_SEC 1000000 static timer_ops_t ops; static uint32_t get_timer_value(void) { /* * Generic delay timer implementation expects the timer to be a down * counter. We apply bitwise NOT operator to the tick values returned * by read_cntpct_el0() to simulate the down counter. The value is * clipped from 64 to 32 bits. */ return (uint32_t)(~read_cntpct_el0()); } void generic_delay_timer_init_args(uint32_t mult, uint32_t div) { ops.get_timer_value = get_timer_value; ops.clk_mult = mult; ops.clk_div = div; timer_init(&ops); VERBOSE("Generic delay timer configured with mult=%u and div=%u\n", mult, div); } void generic_delay_timer_init(void) { assert(is_armv7_gentimer_present()); /* Value in ticks */ unsigned int mult = MHZ_TICKS_PER_SEC; /* Value in ticks per second (Hz) */ unsigned int div = plat_get_syscnt_freq2(); /* Reduce multiplier and divider by dividing them repeatedly by 10 */ while (((mult % 10U) == 0U) && ((div % 10U) == 0U)) { mult /= 10U; div /= 10U; } generic_delay_timer_init_args(mult, div); } trusted-firmware-a-2.2/drivers/gpio/000077500000000000000000000000001355360272700175255ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/gpio/gpio.c000066400000000000000000000033551355360272700206350ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * * GPIO -- General Purpose Input/Output * * Defines a simple and generic interface to access GPIO device. * */ #include #include #include /* * The gpio implementation */ static const gpio_ops_t *ops; int gpio_get_direction(int gpio) { assert(ops); assert(ops->get_direction != 0); assert(gpio >= 0); return ops->get_direction(gpio); } void gpio_set_direction(int gpio, int direction) { assert(ops); assert(ops->set_direction != 0); assert((direction == GPIO_DIR_OUT) || (direction == GPIO_DIR_IN)); assert(gpio >= 0); ops->set_direction(gpio, direction); } int gpio_get_value(int gpio) { assert(ops); assert(ops->get_value != 0); assert(gpio >= 0); return ops->get_value(gpio); } void gpio_set_value(int gpio, int value) { assert(ops); assert(ops->set_value != 0); assert((value == GPIO_LEVEL_LOW) || (value == GPIO_LEVEL_HIGH)); assert(gpio >= 0); ops->set_value(gpio, value); } void gpio_set_pull(int gpio, int pull) { assert(ops); assert(ops->set_pull != 0); assert((pull == GPIO_PULL_NONE) || (pull == GPIO_PULL_UP) || (pull == GPIO_PULL_DOWN)); assert(gpio >= 0); ops->set_pull(gpio, pull); } int gpio_get_pull(int gpio) { assert(ops); assert(ops->get_pull != 0); assert(gpio >= 0); return ops->get_pull(gpio); } /* * Initialize the gpio. The fields in the provided gpio * ops pointer must be valid. */ void gpio_init(const gpio_ops_t *ops_ptr) { assert(ops_ptr != 0 && (ops_ptr->get_direction != 0) && (ops_ptr->set_direction != 0) && (ops_ptr->get_value != 0) && (ops_ptr->set_value != 0)); ops = ops_ptr; } trusted-firmware-a-2.2/drivers/imx/000077500000000000000000000000001355360272700173645ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/imx/timer/000077500000000000000000000000001355360272700205045ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/imx/timer/imx_gpt.c000066400000000000000000000026701355360272700223240ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #define GPTCR_SWR BIT(15) /* Software reset */ #define GPTCR_24MEN BIT(10) /* Enable 24MHz clock input */ #define GPTCR_CLKSOURCE_OSC (5 << 6) /* Clock source OSC */ #define GPTCR_CLKSOURCE_MASK (0x7 << 6) #define GPTCR_TEN 1 /* Timer enable */ #define GPTPR_PRESCL_24M_SHIFT 12 #define SYS_COUNTER_FREQ_IN_MHZ 3 #define GPTPR_TIMER_CTRL (imx_base_addr + 0x000) #define GPTPR_TIMER_PRESCL (imx_base_addr + 0x004) #define GPTPR_TIMER_CNTR (imx_base_addr + 0x024) static uintptr_t imx_base_addr; uint32_t imx_get_timer_value(void) { return ~mmio_read_32(GPTPR_TIMER_CNTR); } static const timer_ops_t imx_gpt_ops = { .get_timer_value = imx_get_timer_value, .clk_mult = 1, .clk_div = SYS_COUNTER_FREQ_IN_MHZ, }; void imx_gpt_ops_init(uintptr_t base_addr) { int val; assert(base_addr != 0); imx_base_addr = base_addr; /* setup GP Timer */ mmio_write_32(GPTPR_TIMER_CTRL, GPTCR_SWR); mmio_write_32(GPTPR_TIMER_CTRL, 0); /* get 3MHz from 24MHz */ mmio_write_32(GPTPR_TIMER_PRESCL, (7 << GPTPR_PRESCL_24M_SHIFT)); val = mmio_read_32(GPTPR_TIMER_CTRL); val &= ~GPTCR_CLKSOURCE_MASK; val |= GPTCR_24MEN | GPTCR_CLKSOURCE_OSC | GPTCR_TEN; mmio_write_32(GPTPR_TIMER_CTRL, val); timer_init(&imx_gpt_ops); } trusted-firmware-a-2.2/drivers/imx/timer/imx_gpt.h000066400000000000000000000003731355360272700223270ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX_GPT_H #define IMX_GPT_H #include void imx_gpt_ops_init(uintptr_t reg_base); #endif /* IMX_GPT_H */ trusted-firmware-a-2.2/drivers/imx/uart/000077500000000000000000000000001355360272700203375ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/imx/uart/imx_crash_uart.S000066400000000000000000000066771355360272700235130ustar00rootroot00000000000000/* * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include .globl imx_crash_uart_init .globl imx_crash_uart_putc /* ----------------------------------------------- * int imx_crash_uart_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. This * function will be accessed by console_init and * crash reporting. * 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, r2, r3, r4 * ----------------------------------------------- */ func imx_crash_uart_init /* Free up r1 as a scratch reg */ mov r4, r0 mov r0, r1 /* Reset UART via CR2 */ add r1, r4, #IMX_UART_CR2_OFFSET movs r3, #0 str r3, [r4, #IMX_UART_CR2_OFFSET] /* Wait for reset complete */ __wait_cr2_reset: ldr r3, [r1, #0] ands r3, #IMX_UART_CR2_SRST beq __wait_cr2_reset /* Enable UART */ movs r3, #IMX_UART_CR1_UARTEN mov r1, r2 str r3, [r4, #IMX_UART_CR1_OFFSET] /* * Ignore RTC/CTS - disable reset * Magic value #16423 => * IMX_UART_CR2_IRTS | IMX_UART_CR2_WS | IMX_UART_CR2_TXEN | IMX_UART_CR2_RXEN | IMX_UART_CR2_SRST */ movw r3, #16423 str r3, [r4, #IMX_UART_CR2_OFFSET] /* * No parity, autobaud detect-old, rxdmuxsel=1 (fixed i.mx7) * Magic value => #132 * IMX_UART_CR3_ADNIMP | IMX_UART_CR3_RXDMUXSEL */ movs r3, #132 str r3, [r4, #IMX_UART_CR3_OFFSET] /* * Set CTS FIFO trigger to 32 bytes bits 15:10 * Magic value => #32768 * FIFO trigger bitmask 100000 * */ mov r3, #32768 str r3, [r4, #IMX_UART_CR4_OFFSET] /* * TX/RX-thresh = 2 bytes, DCE (bit6 = 0), refclk @24MHz / 4 * Magic value #2562 * IMX_UART_FCR_TXTL(TX_RX_THRESH) | IMX_UART_FCR_RXTL(TX_RX_THRESH) | IMX_UART_FCR_RFDIV2 */ #ifdef IMX_UART_DTE movw r3, #2626 #else movw r3, #2562 #endif str r3, [r4, #IMX_UART_FCR_OFFSET] /* This BIR should be set to 0x0F prior to writing the BMR */ movs r3, #15 str r3, [r4, #IMX_UART_BIR_OFFSET] /* Hard-code to 115200 @ 24 MHz */ movs r0, #104 str r0, [r4, #IMX_UART_BMR_OFFSET] /* Indicate success */ movs r0, #1 bx lr endfunc imx_crash_uart_init /* -------------------------------------------------------- * int imx_crash_uart_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. * In : r0 - character to be printed * r1 - console base address * Out : return -1 on error else return character. * Clobber list : r2 * -------------------------------------------------------- */ func imx_crash_uart_putc /* Output specified character to UART shift-register */ str r0, [r1, #IMX_UART_TXD_OFFSET] /* Wait for transmit IMX_UART_STAT2_OFFSET.IMX_UART_STAT2_TXDC == 1 */ __putc_spin_ready: ldr r2, [r1, #IMX_UART_STAT2_OFFSET] ands r2, #IMX_UART_STAT2_TXDC beq __putc_spin_ready /* Transmit complete do we need to fixup \n to \n\r */ cmp r0, #10 beq __putc_fixup_lf /* No fixup necessary - exit here */ movs r0, #0 bx lr /* Fixup \n to \n\r */ __putc_fixup_lf: movs r0, #13 b imx_crash_uart_putc endfunc imx_crash_uart_putc trusted-firmware-a-2.2/drivers/imx/uart/imx_uart.c000066400000000000000000000102541355360272700223350ustar00rootroot00000000000000/* * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* TX/RX FIFO threshold */ #define TX_RX_THRESH 2 struct clk_div_factors { uint32_t fcr_div; uint32_t bmr_div; }; static struct clk_div_factors clk_div[] = { { .fcr_div = IMX_UART_FCR_RFDIV1, .bmr_div = 1, }, { .fcr_div = IMX_UART_FCR_RFDIV2, .bmr_div = 2, }, { .fcr_div = IMX_UART_FCR_RFDIV3, .bmr_div = 3, }, { .fcr_div = IMX_UART_FCR_RFDIV4, .bmr_div = 4, }, { .fcr_div = IMX_UART_FCR_RFDIV5, .bmr_div = 5, }, { .fcr_div = IMX_UART_FCR_RFDIV6, .bmr_div = 6, }, { .fcr_div = IMX_UART_FCR_RFDIV7, .bmr_div = 7, }, }; static void write_reg(uintptr_t base, uint32_t offset, uint32_t val) { mmio_write_32(base + offset, val); } static uint32_t read_reg(uintptr_t base, uint32_t offset) { return mmio_read_32(base + offset); } int console_imx_uart_core_init(uintptr_t base_addr, unsigned int uart_clk, unsigned int baud_rate) { uint32_t val; uint8_t clk_idx = 1; /* Reset UART */ write_reg(base_addr, IMX_UART_CR2_OFFSET, 0); do { val = read_reg(base_addr, IMX_UART_CR2_OFFSET); } while (!(val & IMX_UART_CR2_SRST)); /* Enable UART */ write_reg(base_addr, IMX_UART_CR1_OFFSET, IMX_UART_CR1_UARTEN); /* Ignore RTS, 8N1, enable tx/rx, disable reset */ val = (IMX_UART_CR2_IRTS | IMX_UART_CR2_WS | IMX_UART_CR2_TXEN | IMX_UART_CR2_RXEN | IMX_UART_CR2_SRST); write_reg(base_addr, IMX_UART_CR2_OFFSET, val); /* No parity, autobaud detect-old, rxdmuxsel=1 (fixed i.mx7) */ val = IMX_UART_CR3_ADNIMP | IMX_UART_CR3_RXDMUXSEL; write_reg(base_addr, IMX_UART_CR3_OFFSET, val); /* Set CTS FIFO trigger to 32 bytes bits 15:10 */ write_reg(base_addr, IMX_UART_CR4_OFFSET, 0x8000); /* TX/RX-thresh = 2 bytes, DTE (bit6 = 0), refclk @24MHz / 4 */ val = IMX_UART_FCR_TXTL(TX_RX_THRESH) | IMX_UART_FCR_RXTL(TX_RX_THRESH) | clk_div[clk_idx].fcr_div; #ifdef IMX_UART_DTE /* Set DTE (bit6 = 1) */ val |= IMX_UART_FCR_DCEDTE; #endif write_reg(base_addr, IMX_UART_FCR_OFFSET, val); /* * The equation for BAUD rate calculation is * RefClk = Supplied clock / FCR_DIVx * * BAUD = Refclk * ------------ * 16 x (UBMR + 1/ UBIR + 1) * * We write 0x0f into UBIR to remove the 16 mult * BAUD = 6000000 * ------------ * 16 x (UBMR + 1/ 15 + 1) */ write_reg(base_addr, IMX_UART_BIR_OFFSET, 0x0f); val = ((uart_clk / clk_div[clk_idx].bmr_div) / baud_rate) - 1; write_reg(base_addr, IMX_UART_BMR_OFFSET, val); return 0; } /* -------------------------------------------------------- * 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. * In : r0 - character to be printed * r1 - console base address * Out : return -1 on error else return character. * Clobber list : r2 * -------------------------------------------------------- */ int console_imx_uart_core_putc(int c, uintptr_t base_addr) { uint32_t val; if (c == '\n') console_imx_uart_core_putc('\r', base_addr); /* Write data */ write_reg(base_addr, IMX_UART_TXD_OFFSET, c); /* Wait for transmit */ do { val = read_reg(base_addr, IMX_UART_STAT2_OFFSET); } while (!(val & IMX_UART_STAT2_TXDC)); return 0; } /* * Function to get a character from the console. * It returns the character grabbed on success * or -1 on error. * In : r0 - console base address * Clobber list : r0, r1 * --------------------------------------------- */ int console_imx_uart_core_getc(uintptr_t base_addr) { uint32_t val; val = read_reg(base_addr, IMX_UART_TS_OFFSET); if (val & IMX_UART_TS_RXEMPTY) return -1; val = read_reg(base_addr, IMX_UART_RXD_OFFSET); return (int)(val & 0x000000FF); } /* * Function to force a write of all buffered * data that hasn't been output. * In : r0 - console base address * Out : return -1 on error else return 0. * Clobber list : r0, r1 * --------------------------------------------- */ int console_imx_uart_core_flush(uintptr_t base_addr) { return 0; } trusted-firmware-a-2.2/drivers/imx/uart/imx_uart.h000066400000000000000000000116601355360272700223440ustar00rootroot00000000000000/* * Copyright (c) Linaro 2018 Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX_UART_H #define IMX_UART_H #include #define IMX_UART_RXD_OFFSET 0x00 #define IMX_UART_RXD_CHARRDY BIT(15) #define IMX_UART_RXD_ERR BIT(14) #define IMX_UART_RXD_OVERRUN BIT(13) #define IMX_UART_RXD_FRMERR BIT(12) #define IMX_UART_RXD_BRK BIT(11) #define IMX_UART_RXD_PRERR BIT(10) #define IMX_UART_TXD_OFFSET 0x40 #define IMX_UART_CR1_OFFSET 0x80 #define IMX_UART_CR1_ADEN BIT(15) #define IMX_UART_CR1_ADBR BIT(14) #define IMX_UART_CR1_TRDYEN BIT(13) #define IMX_UART_CR1_IDEN BIT(12) #define IMX_UART_CR1_RRDYEN BIT(9) #define IMX_UART_CR1_RXDMAEN BIT(8) #define IMX_UART_CR1_IREN BIT(7) #define IMX_UART_CR1_TXMPTYEN BIT(6) #define IMX_UART_CR1_RTSDEN BIT(5) #define IMX_UART_CR1_SNDBRK BIT(4) #define IMX_UART_CR1_TXDMAEN BIT(3) #define IMX_UART_CR1_ATDMAEN BIT(2) #define IMX_UART_CR1_DOZE BIT(1) #define IMX_UART_CR1_UARTEN BIT(0) #define IMX_UART_CR2_OFFSET 0x84 #define IMX_UART_CR2_ESCI BIT(15) #define IMX_UART_CR2_IRTS BIT(14) #define IMX_UART_CR2_CTSC BIT(13) #define IMX_UART_CR2_CTS BIT(12) #define IMX_UART_CR2_ESCEN BIT(11) #define IMX_UART_CR2_PREN BIT(8) #define IMX_UART_CR2_PROE BIT(7) #define IMX_UART_CR2_STPB BIT(6) #define IMX_UART_CR2_WS BIT(5) #define IMX_UART_CR2_RTSEN BIT(4) #define IMX_UART_CR2_ATEN BIT(3) #define IMX_UART_CR2_TXEN BIT(2) #define IMX_UART_CR2_RXEN BIT(1) #define IMX_UART_CR2_SRST BIT(0) #define IMX_UART_CR3_OFFSET 0x88 #define IMX_UART_CR3_DTREN BIT(13) #define IMX_UART_CR3_PARERREN BIT(12) #define IMX_UART_CR3_FARERREN BIT(11) #define IMX_UART_CR3_DSD BIT(10) #define IMX_UART_CR3_DCD BIT(9) #define IMX_UART_CR3_RI BIT(8) #define IMX_UART_CR3_ADNIMP BIT(7) #define IMX_UART_CR3_RXDSEN BIT(6) #define IMX_UART_CR3_AIRINTEN BIT(5) #define IMX_UART_CR3_AWAKEN BIT(4) #define IMX_UART_CR3_DTRDEN BIT(3) #define IMX_UART_CR3_RXDMUXSEL BIT(2) #define IMX_UART_CR3_INVT BIT(1) #define IMX_UART_CR3_ACIEN BIT(0) #define IMX_UART_CR4_OFFSET 0x8c #define IMX_UART_CR4_INVR BIT(9) #define IMX_UART_CR4_ENIRI BIT(8) #define IMX_UART_CR4_WKEN BIT(7) #define IMX_UART_CR4_IDDMAEN BIT(6) #define IMX_UART_CR4_IRSC BIT(5) #define IMX_UART_CR4_LPBYP BIT(4) #define IMX_UART_CR4_TCEN BIT(3) #define IMX_UART_CR4_BKEN BIT(2) #define IMX_UART_CR4_OREN BIT(1) #define IMX_UART_CR4_DREN BIT(0) #define IMX_UART_FCR_OFFSET 0x90 #define IMX_UART_FCR_TXTL_MASK (BIT(15) | BIT(14) | BIT(13) | BIT(12) |\ BIT(11) | BIT(10)) #define IMX_UART_FCR_TXTL(x) ((x) << 10) #define IMX_UART_FCR_RFDIV_MASK (BIT(9) | BIT(8) | BIT(7)) #define IMX_UART_FCR_RFDIV7 (BIT(9) | BIT(8)) #define IMX_UART_FCR_RFDIV1 (BIT(9) | BIT(7)) #define IMX_UART_FCR_RFDIV2 BIT(9) #define IMX_UART_FCR_RFDIV3 (BIT(8) | BIT(7)) #define IMX_UART_FCR_RFDIV4 BIT(8) #define IMX_UART_FCR_RFDIV5 BIT(7) #define IMX_UART_FCR_RFDIV6 0 #define IMX_UART_FCR_DCEDTE BIT(6) #define IMX_UART_FCR_RXTL_MASK (BIT(5) | BIT(4) | BIT(3) | BIT(2) |\ BIT(1) | BIT(0)) #define IMX_UART_FCR_RXTL(x) x #define IMX_UART_STAT1_OFFSET 0x94 #define IMX_UART_STAT1_PARITYERR BIT(15) #define IMX_UART_STAT1_RTSS BIT(14) #define IMX_UART_STAT1_TRDY BIT(13) #define IMX_UART_STAT1_RTSD BIT(12) #define IMX_UART_STAT1_ESCF BIT(11) #define IMX_UART_STAT1_FRAMEERR BIT(10) #define IMX_UART_STAT1_RRDY BIT(9) #define IMX_UART_STAT1_AGTIM BIT(8) #define IMX_UART_STAT1_DTRD BIT(7) #define IMX_UART_STAT1_RXDS BIT(6) #define IMX_UART_STAT1_AIRINT BIT(5) #define IMX_UART_STAT1_AWAKE BIT(4) #define IMX_UART_STAT1_SAD BIT(3) #define IMX_UART_STAT2_OFFSET 0x98 #define IMX_UART_STAT2_ADET BIT(15) #define IMX_UART_STAT2_TXFE BIT(14) #define IMX_UART_STAT2_DTRF BIT(13) #define IMX_UART_STAT2_IDLE BIT(12) #define IMX_UART_STAT2_ACST BIT(11) #define IMX_UART_STAT2_RIDELT BIT(10) #define IMX_UART_STAT2_RIIN BIT(9) #define IMX_UART_STAT2_IRINT BIT(8) #define IMX_UART_STAT2_WAKE BIT(7) #define IMX_UART_STAT2_DCDDELT BIT(6) #define IMX_UART_STAT2_DCDIN BIT(5) #define IMX_UART_STAT2_RTSF BIT(4) #define IMX_UART_STAT2_TXDC BIT(3) #define IMX_UART_STAT2_BRCD BIT(2) #define IMX_UART_STAT2_ORE BIT(1) #define IMX_UART_STAT2_RCR BIT(0) #define IMX_UART_ESC_OFFSET 0x9c #define IMX_UART_TIM_OFFSET 0xa0 #define IMX_UART_BIR_OFFSET 0xa4 #define IMX_UART_BMR_OFFSET 0xa8 #define IMX_UART_BRC_OFFSET 0xac #define IMX_UART_ONEMS_OFFSET 0xb0 #define IMX_UART_TS_OFFSET 0xb4 #define IMX_UART_TS_FRCPERR BIT(13) #define IMX_UART_TS_LOOP BIT(12) #define IMX_UART_TS_DBGEN BIT(11) #define IMX_UART_TS_LOOPIR BIT(10) #define IMX_UART_TS_RXDBG BIT(9) #define IMX_UART_TS_TXEMPTY BIT(6) #define IMX_UART_TS_RXEMPTY BIT(5) #define IMX_UART_TS_TXFULL BIT(4) #define IMX_UART_TS_RXFULL BIT(3) #define IMX_UART_TS_SOFTRST BIT(0) #ifndef __ASSEMBLER__ typedef struct { console_t console; uintptr_t base; } console_imx_uart_t; int console_imx_uart_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, console_imx_uart_t *console); #endif /*__ASSEMBLER__*/ #endif /* IMX_UART_H */ trusted-firmware-a-2.2/drivers/imx/usdhc/000077500000000000000000000000001355360272700204725ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/imx/usdhc/imx_usdhc.c000066400000000000000000000171621355360272700226300ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include static void imx_usdhc_initialize(void); static int imx_usdhc_send_cmd(struct mmc_cmd *cmd); static int imx_usdhc_set_ios(unsigned int clk, unsigned int width); static int imx_usdhc_prepare(int lba, uintptr_t buf, size_t size); static int imx_usdhc_read(int lba, uintptr_t buf, size_t size); static int imx_usdhc_write(int lba, uintptr_t buf, size_t size); static const struct mmc_ops imx_usdhc_ops = { .init = imx_usdhc_initialize, .send_cmd = imx_usdhc_send_cmd, .set_ios = imx_usdhc_set_ios, .prepare = imx_usdhc_prepare, .read = imx_usdhc_read, .write = imx_usdhc_write, }; static imx_usdhc_params_t imx_usdhc_params; #define IMX7_MMC_SRC_CLK_RATE (200 * 1000 * 1000) static void imx_usdhc_set_clk(int clk) { int div = 1; int pre_div = 1; unsigned int sdhc_clk = IMX7_MMC_SRC_CLK_RATE; uintptr_t reg_base = imx_usdhc_params.reg_base; assert(clk > 0); while (sdhc_clk / (16 * pre_div) > clk && pre_div < 256) pre_div *= 2; while (sdhc_clk / div > clk && div < 16) div++; pre_div >>= 1; div -= 1; clk = (pre_div << 8) | (div << 4); mmio_clrbits32(reg_base + VENDSPEC, VENDSPEC_CARD_CLKEN); mmio_clrsetbits32(reg_base + SYSCTRL, SYSCTRL_CLOCK_MASK, clk); udelay(10000); mmio_setbits32(reg_base + VENDSPEC, VENDSPEC_PER_CLKEN | VENDSPEC_CARD_CLKEN); } static void imx_usdhc_initialize(void) { unsigned int timeout = 10000; uintptr_t reg_base = imx_usdhc_params.reg_base; assert((imx_usdhc_params.reg_base & MMC_BLOCK_MASK) == 0); /* reset the controller */ mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTA); /* wait for reset done */ while ((mmio_read_32(reg_base + SYSCTRL) & SYSCTRL_RSTA)) { if (!timeout) ERROR("IMX MMC reset timeout.\n"); timeout--; } mmio_write_32(reg_base + MMCBOOT, 0); mmio_write_32(reg_base + MIXCTRL, 0); mmio_write_32(reg_base + CLKTUNECTRLSTS, 0); mmio_write_32(reg_base + VENDSPEC, VENDSPEC_INIT); mmio_write_32(reg_base + DLLCTRL, 0); mmio_setbits32(reg_base + VENDSPEC, VENDSPEC_IPG_CLKEN | VENDSPEC_PER_CLKEN); /* Set the initial boot clock rate */ imx_usdhc_set_clk(MMC_BOOT_CLK_RATE); udelay(100); /* Clear read/write ready status */ mmio_clrbits32(reg_base + INTSTATEN, INTSTATEN_BRR | INTSTATEN_BWR); /* configure as little endian */ mmio_write_32(reg_base + PROTCTRL, PROTCTRL_LE); /* Set timeout to the maximum value */ mmio_clrsetbits32(reg_base + SYSCTRL, SYSCTRL_TIMEOUT_MASK, SYSCTRL_TIMEOUT(15)); /* set wartermark level as 16 for safe for MMC */ mmio_clrsetbits32(reg_base + WATERMARKLEV, WMKLV_MASK, 16 | (16 << 16)); } #define FSL_CMD_RETRIES 1000 static int imx_usdhc_send_cmd(struct mmc_cmd *cmd) { uintptr_t reg_base = imx_usdhc_params.reg_base; unsigned int xfertype = 0, mixctl = 0, multiple = 0, data = 0, err = 0; unsigned int state, flags = INTSTATEN_CC | INTSTATEN_CTOE; unsigned int cmd_retries = 0; assert(cmd); /* clear all irq status */ mmio_write_32(reg_base + INTSTAT, 0xffffffff); /* Wait for the bus to be idle */ do { state = mmio_read_32(reg_base + PSTATE); } while (state & (PSTATE_CDIHB | PSTATE_CIHB)); while (mmio_read_32(reg_base + PSTATE) & PSTATE_DLA) ; mmio_write_32(reg_base + INTSIGEN, 0); udelay(1000); switch (cmd->cmd_idx) { case MMC_CMD(12): xfertype |= XFERTYPE_CMDTYP_ABORT; break; case MMC_CMD(18): multiple = 1; /* fall thru for read op */ case MMC_CMD(17): case MMC_CMD(8): mixctl |= MIXCTRL_DTDSEL; data = 1; break; case MMC_CMD(25): multiple = 1; /* fall thru for data op flag */ case MMC_CMD(24): data = 1; break; default: break; } if (multiple) { mixctl |= MIXCTRL_MSBSEL; mixctl |= MIXCTRL_BCEN; } if (data) { xfertype |= XFERTYPE_DPSEL; mixctl |= MIXCTRL_DMAEN; } if (cmd->resp_type & MMC_RSP_48 && cmd->resp_type != MMC_RESPONSE_R2) xfertype |= XFERTYPE_RSPTYP_48; else if (cmd->resp_type & MMC_RSP_136) xfertype |= XFERTYPE_RSPTYP_136; else if (cmd->resp_type & MMC_RSP_BUSY) xfertype |= XFERTYPE_RSPTYP_48_BUSY; if (cmd->resp_type & MMC_RSP_CMD_IDX) xfertype |= XFERTYPE_CICEN; if (cmd->resp_type & MMC_RSP_CRC) xfertype |= XFERTYPE_CCCEN; xfertype |= XFERTYPE_CMD(cmd->cmd_idx); /* Send the command */ mmio_write_32(reg_base + CMDARG, cmd->cmd_arg); mmio_clrsetbits32(reg_base + MIXCTRL, MIXCTRL_DATMASK, mixctl); mmio_write_32(reg_base + XFERTYPE, xfertype); /* Wait for the command done */ do { state = mmio_read_32(reg_base + INTSTAT); if (cmd_retries) udelay(1); } while ((!(state & flags)) && ++cmd_retries < FSL_CMD_RETRIES); if ((state & (INTSTATEN_CTOE | CMD_ERR)) || cmd_retries == FSL_CMD_RETRIES) { if (cmd_retries == FSL_CMD_RETRIES) err = -ETIMEDOUT; else err = -EIO; ERROR("imx_usdhc mmc cmd %d state 0x%x errno=%d\n", cmd->cmd_idx, state, err); goto out; } /* Copy the response to the response buffer */ if (cmd->resp_type & MMC_RSP_136) { unsigned int cmdrsp3, cmdrsp2, cmdrsp1, cmdrsp0; cmdrsp3 = mmio_read_32(reg_base + CMDRSP3); cmdrsp2 = mmio_read_32(reg_base + CMDRSP2); cmdrsp1 = mmio_read_32(reg_base + CMDRSP1); cmdrsp0 = mmio_read_32(reg_base + CMDRSP0); cmd->resp_data[3] = (cmdrsp3 << 8) | (cmdrsp2 >> 24); cmd->resp_data[2] = (cmdrsp2 << 8) | (cmdrsp1 >> 24); cmd->resp_data[1] = (cmdrsp1 << 8) | (cmdrsp0 >> 24); cmd->resp_data[0] = (cmdrsp0 << 8); } else { cmd->resp_data[0] = mmio_read_32(reg_base + CMDRSP0); } /* Wait until all of the blocks are transferred */ if (data) { flags = DATA_COMPLETE; do { state = mmio_read_32(reg_base + INTSTAT); if (state & (INTSTATEN_DTOE | DATA_ERR)) { err = -EIO; ERROR("imx_usdhc mmc data state 0x%x\n", state); goto out; } } while ((state & flags) != flags); } out: /* Reset CMD and DATA on error */ if (err) { mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTC); while (mmio_read_32(reg_base + SYSCTRL) & SYSCTRL_RSTC) ; if (data) { mmio_setbits32(reg_base + SYSCTRL, SYSCTRL_RSTD); while (mmio_read_32(reg_base + SYSCTRL) & SYSCTRL_RSTD) ; } } /* clear all irq status */ mmio_write_32(reg_base + INTSTAT, 0xffffffff); return err; } static int imx_usdhc_set_ios(unsigned int clk, unsigned int width) { uintptr_t reg_base = imx_usdhc_params.reg_base; imx_usdhc_set_clk(clk); if (width == MMC_BUS_WIDTH_4) mmio_clrsetbits32(reg_base + PROTCTRL, PROTCTRL_WIDTH_MASK, PROTCTRL_WIDTH_4); else if (width == MMC_BUS_WIDTH_8) mmio_clrsetbits32(reg_base + PROTCTRL, PROTCTRL_WIDTH_MASK, PROTCTRL_WIDTH_8); return 0; } static int imx_usdhc_prepare(int lba, uintptr_t buf, size_t size) { uintptr_t reg_base = imx_usdhc_params.reg_base; mmio_write_32(reg_base + DSADDR, buf); mmio_write_32(reg_base + BLKATT, (size / MMC_BLOCK_SIZE) << 16 | MMC_BLOCK_SIZE); return 0; } static int imx_usdhc_read(int lba, uintptr_t buf, size_t size) { return 0; } static int imx_usdhc_write(int lba, uintptr_t buf, size_t size) { return 0; } void imx_usdhc_init(imx_usdhc_params_t *params, struct mmc_device_info *mmc_dev_info) { assert((params != 0) && ((params->reg_base & MMC_BLOCK_MASK) == 0) && (params->clk_rate > 0) && ((params->bus_width == MMC_BUS_WIDTH_1) || (params->bus_width == MMC_BUS_WIDTH_4) || (params->bus_width == MMC_BUS_WIDTH_8))); memcpy(&imx_usdhc_params, params, sizeof(imx_usdhc_params_t)); mmc_init(&imx_usdhc_ops, params->clk_rate, params->bus_width, params->flags, mmc_dev_info); } trusted-firmware-a-2.2/drivers/imx/usdhc/imx_usdhc.h000066400000000000000000000075611355360272700226370ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX_USDHC_H #define IMX_USDHC_H #include typedef struct imx_usdhc_params { uintptr_t reg_base; int clk_rate; int bus_width; unsigned int flags; } imx_usdhc_params_t; void imx_usdhc_init(imx_usdhc_params_t *params, struct mmc_device_info *mmc_dev_info); /* iMX MMC registers definition */ #define DSADDR 0x000 #define BLKATT 0x004 #define CMDARG 0x008 #define CMDRSP0 0x010 #define CMDRSP1 0x014 #define CMDRSP2 0x018 #define CMDRSP3 0x01c #define XFERTYPE 0x00c #define XFERTYPE_CMD(x) (((x) & 0x3f) << 24) #define XFERTYPE_CMDTYP_ABORT (3 << 22) #define XFERTYPE_DPSEL BIT(21) #define XFERTYPE_CICEN BIT(20) #define XFERTYPE_CCCEN BIT(19) #define XFERTYPE_RSPTYP_136 BIT(16) #define XFERTYPE_RSPTYP_48 BIT(17) #define XFERTYPE_RSPTYP_48_BUSY (BIT(16) | BIT(17)) #define PSTATE 0x024 #define PSTATE_DAT0 BIT(24) #define PSTATE_DLA BIT(2) #define PSTATE_CDIHB BIT(1) #define PSTATE_CIHB BIT(0) #define PROTCTRL 0x028 #define PROTCTRL_LE BIT(5) #define PROTCTRL_WIDTH_4 BIT(1) #define PROTCTRL_WIDTH_8 BIT(2) #define PROTCTRL_WIDTH_MASK 0x6 #define SYSCTRL 0x02c #define SYSCTRL_RSTD BIT(26) #define SYSCTRL_RSTC BIT(25) #define SYSCTRL_RSTA BIT(24) #define SYSCTRL_CLOCK_MASK 0x0000fff0 #define SYSCTRL_TIMEOUT_MASK 0x000f0000 #define SYSCTRL_TIMEOUT(x) ((0xf & (x)) << 16) #define INTSTAT 0x030 #define INTSTAT_DMAE BIT(28) #define INTSTAT_DEBE BIT(22) #define INTSTAT_DCE BIT(21) #define INTSTAT_DTOE BIT(20) #define INTSTAT_CIE BIT(19) #define INTSTAT_CEBE BIT(18) #define INTSTAT_CCE BIT(17) #define INTSTAT_DINT BIT(3) #define INTSTAT_BGE BIT(2) #define INTSTAT_TC BIT(1) #define INTSTAT_CC BIT(0) #define CMD_ERR (INTSTAT_CIE | INTSTAT_CEBE | INTSTAT_CCE) #define DATA_ERR (INTSTAT_DMAE | INTSTAT_DEBE | INTSTAT_DCE | \ INTSTAT_DTOE) #define DATA_COMPLETE (INTSTAT_DINT | INTSTAT_TC) #define INTSTATEN 0x034 #define INTSTATEN_DEBE BIT(22) #define INTSTATEN_DCE BIT(21) #define INTSTATEN_DTOE BIT(20) #define INTSTATEN_CIE BIT(19) #define INTSTATEN_CEBE BIT(18) #define INTSTATEN_CCE BIT(17) #define INTSTATEN_CTOE BIT(16) #define INTSTATEN_CINT BIT(8) #define INTSTATEN_BRR BIT(5) #define INTSTATEN_BWR BIT(4) #define INTSTATEN_DINT BIT(3) #define INTSTATEN_TC BIT(1) #define INTSTATEN_CC BIT(0) #define EMMC_INTSTATEN_BITS (INTSTATEN_CC | INTSTATEN_TC | INTSTATEN_DINT | \ INTSTATEN_BWR | INTSTATEN_BRR | INTSTATEN_CINT | \ INTSTATEN_CTOE | INTSTATEN_CCE | INTSTATEN_CEBE | \ INTSTATEN_CIE | INTSTATEN_DTOE | INTSTATEN_DCE | \ INTSTATEN_DEBE) #define INTSIGEN 0x038 #define WATERMARKLEV 0x044 #define WMKLV_RD_MASK 0xff #define WMKLV_WR_MASK 0x00ff0000 #define WMKLV_MASK (WMKLV_RD_MASK | WMKLV_WR_MASK) #define MIXCTRL 0x048 #define MIXCTRL_MSBSEL BIT(5) #define MIXCTRL_DTDSEL BIT(4) #define MIXCTRL_DDREN BIT(3) #define MIXCTRL_AC12EN BIT(2) #define MIXCTRL_BCEN BIT(1) #define MIXCTRL_DMAEN BIT(0) #define MIXCTRL_DATMASK 0x7f #define DLLCTRL 0x060 #define CLKTUNECTRLSTS 0x068 #define VENDSPEC 0x0c0 #define VENDSPEC_RSRV1 BIT(29) #define VENDSPEC_CARD_CLKEN BIT(14) #define VENDSPEC_PER_CLKEN BIT(13) #define VENDSPEC_AHB_CLKEN BIT(12) #define VENDSPEC_IPG_CLKEN BIT(11) #define VENDSPEC_AC12_CHKBUSY BIT(3) #define VENDSPEC_EXTDMA BIT(0) #define VENDSPEC_INIT (VENDSPEC_RSRV1 | VENDSPEC_CARD_CLKEN | \ VENDSPEC_PER_CLKEN | VENDSPEC_AHB_CLKEN | \ VENDSPEC_IPG_CLKEN | VENDSPEC_AC12_CHKBUSY | \ VENDSPEC_EXTDMA) #define MMCBOOT 0x0c4 #define mmio_clrsetbits32(addr, clear, set) mmio_write_32(addr, (mmio_read_32(addr) & ~(clear)) | (set)) #define mmio_clrbits32(addr, clear) mmio_write_32(addr, mmio_read_32(addr) & ~(clear)) #define mmio_setbits32(addr, set) mmio_write_32(addr, mmio_read_32(addr) | (set)) #endif /* IMX_USDHC_H */ trusted-firmware-a-2.2/drivers/intel/000077500000000000000000000000001355360272700177025ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/intel/soc/000077500000000000000000000000001355360272700204665ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/intel/soc/stratix10/000077500000000000000000000000001355360272700223255ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/intel/soc/stratix10/io/000077500000000000000000000000001355360272700227345ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/intel/soc/stratix10/io/s10_memmap_qspi.c000066400000000000000000000140601355360272700260740ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include "qspi/cadence_qspi.h" /* As we need to be able to keep state for seek, only one file can be open * at a time. Make this a structure and point to the entity->info. When we * can malloc memory we can change this to support more open files. */ typedef struct { /* Use the 'in_use' flag as any value for base and file_pos could be * valid. */ int in_use; uintptr_t base; size_t file_pos; size_t size; } file_state_t; static file_state_t current_file = {0}; /* Identify the device type as memmap */ static io_type_t device_type_memmap(void) { return IO_TYPE_MEMMAP; } /* Memmap device functions */ 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); 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); static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer, size_t length, size_t *length_written); static int memmap_block_close(io_entity_t *entity); static int memmap_dev_close(io_dev_info_t *dev_info); static const io_dev_connector_t memmap_dev_connector = { .dev_open = memmap_dev_open }; static const io_dev_funcs_t memmap_dev_funcs = { .type = device_type_memmap, .open = memmap_block_open, .seek = memmap_block_seek, .size = memmap_block_len, .read = memmap_block_read, .write = memmap_block_write, .close = memmap_block_close, .dev_init = NULL, .dev_close = memmap_dev_close, }; /* No state associated with this device so structure can be const */ static const io_dev_info_t memmap_dev_info = { .funcs = &memmap_dev_funcs, .info = (uintptr_t)NULL }; /* Open a connection to the memmap device */ static int memmap_dev_open(const uintptr_t dev_spec __unused, io_dev_info_t **dev_info) { assert(dev_info != NULL); *dev_info = (io_dev_info_t *)&memmap_dev_info; /* cast away const */ return 0; } /* Close a connection to the memmap device */ static int memmap_dev_close(io_dev_info_t *dev_info) { /* NOP */ /* TODO: Consider tracking open files and cleaning them up here */ return 0; } /* Open a file on the memmap device */ static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity) { int result = -ENOMEM; const io_block_spec_t *block_spec = (io_block_spec_t *)spec; /* Since we need to track open state for seek() we only allow one open * spec at a time. When we have dynamic memory we can malloc and set * entity->info. */ if (current_file.in_use == 0) { assert(block_spec != NULL); assert(entity != NULL); current_file.in_use = 1; current_file.base = block_spec->offset; /* File cursor offset for seek and incremental reads etc. */ current_file.file_pos = 0; current_file.size = block_spec->length; entity->info = (uintptr_t)¤t_file; result = 0; } else { WARN("A Memmap device is already active. Close first.\n"); } return result; } /* Seek to a particular file offset on the memmap device */ static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset) { int result = -ENOENT; file_state_t *fp; /* We only support IO_SEEK_SET for the moment. */ if (mode == IO_SEEK_SET) { assert(entity != NULL); fp = (file_state_t *) entity->info; /* Assert that new file position is valid */ assert((offset >= 0) && (offset < fp->size)); /* Reset file position */ fp->file_pos = offset; result = 0; } return result; } /* Return the size of a file on the memmap device */ static int memmap_block_len(io_entity_t *entity, size_t *length) { assert(entity != NULL); assert(length != NULL); *length = ((file_state_t *)entity->info)->size; return 0; } /* Read data from a file on the memmap device */ static int memmap_block_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read) { file_state_t *fp; size_t pos_after; assert(entity != NULL); assert(length_read != NULL); fp = (file_state_t *) entity->info; /* Assert that file position is valid for this read operation */ pos_after = fp->file_pos + length; assert((pos_after >= fp->file_pos) && (pos_after <= fp->size)); //memcpy((void *)buffer, (void *)(fp->base + fp->file_pos), length); cad_qspi_read((void *)buffer, fp->base + fp->file_pos, length); *length_read = length; /* Set file position after read */ fp->file_pos = pos_after; return 0; } /* Write data to a file on the memmap device */ static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer, size_t length, size_t *length_written) { file_state_t *fp; size_t pos_after; assert(entity != NULL); assert(length_written != NULL); fp = (file_state_t *) entity->info; /* Assert that file position is valid for this write operation */ pos_after = fp->file_pos + length; assert((pos_after >= fp->file_pos) && (pos_after <= fp->size)); memcpy((void *)(fp->base + fp->file_pos), (void *)buffer, length); *length_written = length; /* Set file position after write */ fp->file_pos = pos_after; return 0; } /* Close a file on the memmap device */ static int memmap_block_close(io_entity_t *entity) { assert(entity != NULL); entity->info = 0; /* This would be a mem free() if we had malloc.*/ zeromem((void *)¤t_file, sizeof(current_file)); return 0; } /* Exported functions */ /* Register the memmap driver with the IO abstraction */ int register_io_dev_memmap(const io_dev_connector_t **dev_con) { int result; assert(dev_con != NULL); result = io_register_device(&memmap_dev_info); if (result == 0) *dev_con = &memmap_dev_connector; return result; } trusted-firmware-a-2.2/drivers/io/000077500000000000000000000000001355360272700171765ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/io/io_block.c000066400000000000000000000400441355360272700211250ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include typedef struct { io_block_dev_spec_t *dev_spec; uintptr_t base; size_t file_pos; size_t size; } block_dev_state_t; #define is_power_of_2(x) ((x != 0) && ((x & (x - 1)) == 0)) 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_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, size_t length, size_t *length_written); static int block_close(io_entity_t *entity); static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); static int block_dev_close(io_dev_info_t *dev_info); static const io_dev_connector_t block_dev_connector = { .dev_open = block_dev_open }; static const io_dev_funcs_t block_dev_funcs = { .type = device_type_block, .open = block_open, .seek = block_seek, .size = NULL, .read = block_read, .write = block_write, .close = block_close, .dev_init = NULL, .dev_close = block_dev_close, }; static block_dev_state_t state_pool[MAX_IO_BLOCK_DEVICES]; static io_dev_info_t dev_info_pool[MAX_IO_BLOCK_DEVICES]; /* Track number of allocated block state */ static unsigned int block_dev_count; io_type_t device_type_block(void) { return IO_TYPE_BLOCK; } /* Locate a block state in the pool, specified by address */ 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 (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; *index_out = index; break; } } return result; } /* Allocate a device info from the pool and return a pointer to it */ static int allocate_dev_info(io_dev_info_t **dev_info) { int result = -ENOMEM; assert(dev_info != NULL); if (block_dev_count < MAX_IO_BLOCK_DEVICES) { unsigned int index = 0; result = find_first_block_state(NULL, &index); assert(result == 0); /* initialize dev_info */ dev_info_pool[index].funcs = &block_dev_funcs; dev_info_pool[index].info = (uintptr_t)&state_pool[index]; *dev_info = &dev_info_pool[index]; ++block_dev_count; } return result; } /* Release a device info to the pool */ static int free_dev_info(io_dev_info_t *dev_info) { int result; unsigned int index = 0; block_dev_state_t *state; assert(dev_info != NULL); state = (block_dev_state_t *)dev_info->info; result = find_first_block_state(state->dev_spec, &index); if (result == 0) { /* free if device info is valid */ zeromem(state, sizeof(block_dev_state_t)); zeromem(dev_info, sizeof(io_dev_info_t)); --block_dev_count; } return result; } static int block_open(io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity) { block_dev_state_t *cur; io_block_spec_t *region; assert((dev_info->info != (uintptr_t)NULL) && (spec != (uintptr_t)NULL) && (entity->info == (uintptr_t)NULL)); region = (io_block_spec_t *)spec; cur = (block_dev_state_t *)dev_info->info; assert(((region->offset % cur->dev_spec->block_size) == 0) && ((region->length % cur->dev_spec->block_size) == 0)); cur->base = region->offset; cur->size = region->length; cur->file_pos = 0; entity->info = (uintptr_t)cur; return 0; } /* parameter offset is relative address at here */ static int block_seek(io_entity_t *entity, int mode, ssize_t offset) { block_dev_state_t *cur; assert(entity->info != (uintptr_t)NULL); cur = (block_dev_state_t *)entity->info; assert((offset >= 0) && (offset < cur->size)); switch (mode) { case IO_SEEK_SET: cur->file_pos = offset; break; case IO_SEEK_CUR: cur->file_pos += offset; break; default: return -EINVAL; } assert(cur->file_pos < cur->size); return 0; } /* * This function allows the caller to read any number of bytes * from any position. It hides from the caller that the low level * driver only can read aligned blocks of data. For this reason * we need to handle the use case where the first byte to be read is not * aligned to start of the block, the last byte to be read is also not * aligned to the end of a block, and there are zero or more blocks-worth * of data in between. * * In such a case we need to read more bytes than requested (i.e. full * blocks) and strip-out the leading bytes (aka skip) and the trailing * bytes (aka padding). See diagram below * * cur->file_pos ------------ * | * cur->base | * | | * v v<---- length ----> * -------------------------------------------------------------- * | | block#1 | | block#n | * | block#0 | + | ... | + | * | | <- skip -> + | | + <- padding ->| * ------------------------+----------------------+-------------- * ^ ^ * | | * v iteration#1 iteration#n v * -------------------------------------------------- * | | | | * |<---- request ---->| ... |<----- request ---->| * | | | | * -------------------------------------------------- * / / | | * / / | | * / / | | * / / | | * / / | | * / / | | * / / | | * / / | | * / / | | * / / | | * <---- request ------> <------ request -----> * --------------------- ----------------------- * | | | | | | * |<-skip->|<-nbytes->| -------->|<-nbytes->|<-padding->| * | | | | | | | * --------------------- | ----------------------- * ^ \ \ | | | * | \ \ | | | * | \ \ | | | * buf->offset \ \ buf->offset | | * \ \ | | * \ \ | | * \ \ | | * \ \ | | * \ \ | | * \ \ | | * \ \ | | * -------------------------------- * | | | | * buffer-------------->| | ... | | * | | | | * -------------------------------- * <-count#1->| | * <---------- count#n --------> * <---------- length ----------> * * Additionally, the IO driver has an underlying buffer that is at least * one block-size and may be big enough to allow. */ static int block_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read) { block_dev_state_t *cur; io_block_spec_t *buf; io_block_ops_t *ops; int lba; size_t block_size, left; size_t nbytes; /* number of bytes read in one iteration */ size_t request; /* number of requested bytes in one iteration */ size_t count; /* number of bytes already read */ /* * number of leading bytes from start of the block * to the first byte to be read */ size_t skip; /* * number of trailing bytes between the last byte * to be read and the end of the block */ size_t padding; assert(entity->info != (uintptr_t)NULL); cur = (block_dev_state_t *)entity->info; ops = &(cur->dev_spec->ops); buf = &(cur->dev_spec->buffer); block_size = cur->dev_spec->block_size; assert((length <= cur->size) && (length > 0) && (ops->read != 0)); /* * We don't know the number of bytes that we are going * to read in every iteration, because it will depend * on the low level driver. */ count = 0; for (left = length; left > 0; left -= nbytes) { /* * We must only request operations aligned to the block * size. Therefore if file_pos is not block-aligned, * we have to request the operation to start at the * previous block boundary and skip the leading bytes. And * similarly, the number of bytes requested must be a * block size multiple */ skip = cur->file_pos & (block_size - 1); /* * Calculate the block number containing file_pos * - e.g. block 3. */ lba = (cur->file_pos + cur->base) / block_size; if (skip + left > buf->length) { /* * The underlying read buffer is too small to * read all the required data - limit to just * fill the buffer, and then read again. */ request = buf->length; } else { /* * The underlying read buffer is big enough to * read all the required data. Calculate the * number of bytes to read to align with the * block size. */ request = skip + left; request = (request + (block_size - 1)) & ~(block_size - 1); } request = ops->read(lba, buf->offset, request); if (request <= skip) { /* * We couldn't read enough bytes to jump over * the skip bytes, so we should have to read * again the same block, thus generating * the same error. */ return -EIO; } /* * Need to remove skip and padding bytes,if any, from * the read data when copying to the user buffer. */ nbytes = request - skip; padding = (nbytes > left) ? nbytes - left : 0; nbytes -= padding; memcpy((void *)(buffer + count), (void *)(buf->offset + skip), nbytes); cur->file_pos += nbytes; count += nbytes; } assert(count == length); *length_read = count; return 0; } /* * This function allows the caller to write any number of bytes * from any position. It hides from the caller that the low level * driver only can write aligned blocks of data. * See comments for block_read for more details. */ static int block_write(io_entity_t *entity, const uintptr_t buffer, size_t length, size_t *length_written) { block_dev_state_t *cur; io_block_spec_t *buf; io_block_ops_t *ops; int lba; size_t block_size, left; size_t nbytes; /* number of bytes read in one iteration */ size_t request; /* number of requested bytes in one iteration */ size_t count; /* number of bytes already read */ /* * number of leading bytes from start of the block * to the first byte to be read */ size_t skip; /* * number of trailing bytes between the last byte * to be read and the end of the block */ size_t padding; assert(entity->info != (uintptr_t)NULL); cur = (block_dev_state_t *)entity->info; ops = &(cur->dev_spec->ops); buf = &(cur->dev_spec->buffer); block_size = cur->dev_spec->block_size; assert((length <= cur->size) && (length > 0) && (ops->read != 0) && (ops->write != 0)); /* * We don't know the number of bytes that we are going * to write in every iteration, because it will depend * on the low level driver. */ count = 0; for (left = length; left > 0; left -= nbytes) { /* * We must only request operations aligned to the block * size. Therefore if file_pos is not block-aligned, * we have to request the operation to start at the * previous block boundary and skip the leading bytes. And * similarly, the number of bytes requested must be a * block size multiple */ skip = cur->file_pos & (block_size - 1); /* * Calculate the block number containing file_pos * - e.g. block 3. */ lba = (cur->file_pos + cur->base) / block_size; if (skip + left > buf->length) { /* * The underlying read buffer is too small to * read all the required data - limit to just * fill the buffer, and then read again. */ request = buf->length; } else { /* * The underlying read buffer is big enough to * read all the required data. Calculate the * number of bytes to read to align with the * block size. */ request = skip + left; request = (request + (block_size - 1)) & ~(block_size - 1); } /* * The number of bytes that we are going to write * from the user buffer will depend of the size * of the current request. */ nbytes = request - skip; padding = (nbytes > left) ? nbytes - left : 0; nbytes -= padding; /* * If we have skip or padding bytes then we have to preserve * some content and it means that we have to read before * writing */ if (skip > 0 || padding > 0) { request = ops->read(lba, buf->offset, request); /* * The read may return size less than * requested. Round down to the nearest block * boundary */ request &= ~(block_size-1); if (request <= skip) { /* * We couldn't read enough bytes to jump over * the skip bytes, so we should have to read * again the same block, thus generating * the same error. */ return -EIO; } nbytes = request - skip; padding = (nbytes > left) ? nbytes - left : 0; nbytes -= padding; } memcpy((void *)(buf->offset + skip), (void *)(buffer + count), nbytes); request = ops->write(lba, buf->offset, request); if (request <= skip) return -EIO; /* * And the previous write operation may modify the size * of the request, so again, we have to calculate the * number of bytes that we consumed from the user * buffer */ nbytes = request - skip; padding = (nbytes > left) ? nbytes - left : 0; nbytes -= padding; cur->file_pos += nbytes; count += nbytes; } assert(count == length); *length_written = count; return 0; } static int block_close(io_entity_t *entity) { entity->info = (uintptr_t)NULL; return 0; } static int block_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info) { block_dev_state_t *cur; io_block_spec_t *buffer; io_dev_info_t *info; size_t block_size; int result; assert(dev_info != NULL); result = allocate_dev_info(&info); if (result) return -ENOENT; cur = (block_dev_state_t *)info->info; /* dev_spec is type of io_block_dev_spec_t. */ cur->dev_spec = (io_block_dev_spec_t *)dev_spec; buffer = &(cur->dev_spec->buffer); block_size = cur->dev_spec->block_size; assert((block_size > 0) && (is_power_of_2(block_size) != 0) && ((buffer->offset % block_size) == 0) && ((buffer->length % block_size) == 0)); *dev_info = info; /* cast away const */ (void)block_size; (void)buffer; return 0; } static int block_dev_close(io_dev_info_t *dev_info) { return free_dev_info(dev_info); } /* Exported functions */ /* Register the Block driver with the IO abstraction */ int register_io_dev_block(const io_dev_connector_t **dev_con) { int result; assert(dev_con != NULL); /* * Since dev_info isn't really used in io_register_device, always * use the same device info at here instead. */ result = io_register_device(&dev_info_pool[0]); if (result == 0) *dev_con = &block_dev_connector; return result; } trusted-firmware-a-2.2/drivers/io/io_dummy.c000066400000000000000000000063761355360272700212000ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include struct file_state { int in_use; size_t size; }; static struct file_state current_file = {0}; /* Identify the device type as dummy */ static io_type_t device_type_dummy(void) { return IO_TYPE_DUMMY; } /* Dummy device functions */ static int dummy_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); static int dummy_block_open(io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity); static int dummy_block_len(io_entity_t *entity, size_t *length); static int dummy_block_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read); static int dummy_block_close(io_entity_t *entity); static int dummy_dev_close(io_dev_info_t *dev_info); static const io_dev_connector_t dummy_dev_connector = { .dev_open = dummy_dev_open }; static const io_dev_funcs_t dummy_dev_funcs = { .type = device_type_dummy, .open = dummy_block_open, .seek = NULL, .size = dummy_block_len, .read = dummy_block_read, .write = NULL, .close = dummy_block_close, .dev_init = NULL, .dev_close = dummy_dev_close, }; static const io_dev_info_t dummy_dev_info = { .funcs = &dummy_dev_funcs, .info = (uintptr_t)NULL }; /* Open a connection to the dummy device */ static int dummy_dev_open(const uintptr_t dev_spec __attribute__((unused)), io_dev_info_t **dev_info) { assert(dev_info != NULL); *dev_info = (io_dev_info_t *)&dummy_dev_info; return 0; } /* Close a connection to the dummy device */ static int dummy_dev_close(io_dev_info_t *dev_info) { return 0; } /* Open a file on the dummy device */ static int dummy_block_open(io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity) { int result; const io_block_spec_t *block_spec = (io_block_spec_t *)spec; if (current_file.in_use == 0) { assert(block_spec != NULL); assert(entity != NULL); current_file.in_use = 1; current_file.size = block_spec->length; entity->info = (uintptr_t)¤t_file; result = 0; } else { WARN("A Dummy device is already active. Close first.\n"); result = -ENOMEM; } return result; } /* Return the size of a file on the dummy device */ static int dummy_block_len(io_entity_t *entity, size_t *length) { assert(entity != NULL); assert(length != NULL); *length = ((struct file_state *)entity->info)->size; return 0; } /* Read data from a file on the dummy device */ static int dummy_block_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read) { assert(length_read != NULL); *length_read = length; return 0; } /* Close a file on the dummy device */ static int dummy_block_close(io_entity_t *entity) { assert(entity != NULL); entity->info = 0; current_file.in_use = 0; return 0; } /* Exported functions */ /* Register the dummy driver with the IO abstraction */ int register_io_dev_dummy(const io_dev_connector_t **dev_con) { int result; assert(dev_con != NULL); result = io_register_device(&dummy_dev_info); if (result == 0) *dev_con = &dummy_dev_connector; return result; } trusted-firmware-a-2.2/drivers/io/io_fip.c000066400000000000000000000260611355360272700206140ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef MAX_FIP_DEVICES #define MAX_FIP_DEVICES 1 #endif /* Useful for printing UUIDs when debugging.*/ #define PRINT_UUID2(x) \ "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", \ x.time_low, x.time_mid, x.time_hi_and_version, \ x.clock_seq_hi_and_reserved, x.clock_seq_low, \ x.node[0], x.node[1], x.node[2], x.node[3], \ x.node[4], x.node[5] typedef struct { unsigned int file_pos; fip_toc_entry_t entry; } file_state_t; /* * Maintain dev_spec per FIP Device * TODO - Add backend handles and file state * per FIP device here once backends like io_memmap * can support multiple open files */ typedef struct { uintptr_t dev_spec; } fip_dev_state_t; static const uuid_t uuid_null; /* * Only one file can be open across all FIP device * as backends like io_memmap don't support * multiple open files. The file state and * backend handle should be maintained per FIP device * if the same support is available in the backend */ static file_state_t current_file = {0}; static uintptr_t backend_dev_handle; static uintptr_t backend_image_spec; static fip_dev_state_t state_pool[MAX_FIP_DEVICES]; static io_dev_info_t dev_info_pool[MAX_FIP_DEVICES]; /* Track number of allocated fip devices */ static unsigned int fip_dev_count; /* Firmware Image Package driver functions */ static int fip_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info); static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity); static int fip_file_len(io_entity_t *entity, size_t *length); static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read); static int fip_file_close(io_entity_t *entity); static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params); static int fip_dev_close(io_dev_info_t *dev_info); /* Return 0 for equal uuids. */ static inline int compare_uuids(const uuid_t *uuid1, const uuid_t *uuid2) { return memcmp(uuid1, uuid2, sizeof(uuid_t)); } static inline int is_valid_header(fip_toc_header_t *header) { if ((header->name == TOC_HEADER_NAME) && (header->serial_number != 0)) { return 1; } else { return 0; } } /* Identify the device type as a virtual driver */ static io_type_t device_type_fip(void) { return IO_TYPE_FIRMWARE_IMAGE_PACKAGE; } static const io_dev_connector_t fip_dev_connector = { .dev_open = fip_dev_open }; static const io_dev_funcs_t fip_dev_funcs = { .type = device_type_fip, .open = fip_file_open, .seek = NULL, .size = fip_file_len, .read = fip_file_read, .write = NULL, .close = fip_file_close, .dev_init = fip_dev_init, .dev_close = fip_dev_close, }; /* Locate a file state in the pool, specified by address */ static int find_first_fip_state(const uintptr_t dev_spec, unsigned int *index_out) { int result = -ENOENT; unsigned int index; for (index = 0; index < (unsigned int)MAX_FIP_DEVICES; ++index) { /* dev_spec is used as identifier since it's unique */ if (state_pool[index].dev_spec == dev_spec) { result = 0; *index_out = index; break; } } return result; } /* Allocate a device info from the pool and return a pointer to it */ static int allocate_dev_info(io_dev_info_t **dev_info) { int result = -ENOMEM; assert(dev_info != NULL); if (fip_dev_count < (unsigned int)MAX_FIP_DEVICES) { unsigned int index = 0; result = find_first_fip_state(0, &index); assert(result == 0); /* initialize dev_info */ dev_info_pool[index].funcs = &fip_dev_funcs; dev_info_pool[index].info = (uintptr_t)&state_pool[index]; *dev_info = &dev_info_pool[index]; ++fip_dev_count; } return result; } /* Release a device info to the pool */ static int free_dev_info(io_dev_info_t *dev_info) { int result; unsigned int index = 0; fip_dev_state_t *state; assert(dev_info != NULL); state = (fip_dev_state_t *)dev_info->info; result = find_first_fip_state(state->dev_spec, &index); if (result == 0) { /* free if device info is valid */ zeromem(state, sizeof(fip_dev_state_t)); --fip_dev_count; } return result; } /* * Multiple FIP devices can be opened depending on the value of * MAX_FIP_DEVICES. Given that there is only one backend, only a * single file can be open at a time by any FIP device. */ static int fip_dev_open(const uintptr_t dev_spec, io_dev_info_t **dev_info) { int result; io_dev_info_t *info; fip_dev_state_t *state; assert(dev_info != NULL); #if MAX_FIP_DEVICES > 1 assert(dev_spec != (uintptr_t)NULL); #endif result = allocate_dev_info(&info); if (result != 0) return -ENOMEM; state = (fip_dev_state_t *)info->info; state->dev_spec = dev_spec; *dev_info = info; return 0; } /* Do some basic package checks. */ static int fip_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params) { int result; unsigned int image_id = (unsigned int)init_params; uintptr_t backend_handle; fip_toc_header_t header; size_t bytes_read; /* Obtain a reference to the image by querying the platform layer */ result = plat_get_image_source(image_id, &backend_dev_handle, &backend_image_spec); if (result != 0) { WARN("Failed to obtain reference to image id=%u (%i)\n", image_id, result); result = -ENOENT; goto fip_dev_init_exit; } /* Attempt to access the FIP image */ result = io_open(backend_dev_handle, backend_image_spec, &backend_handle); if (result != 0) { WARN("Failed to access image id=%u (%i)\n", image_id, result); result = -ENOENT; goto fip_dev_init_exit; } result = io_read(backend_handle, (uintptr_t)&header, sizeof(header), &bytes_read); if (result == 0) { if (!is_valid_header(&header)) { WARN("Firmware Image Package header check failed.\n"); result = -ENOENT; } else { VERBOSE("FIP header looks OK.\n"); } } io_close(backend_handle); fip_dev_init_exit: return result; } /* Close a connection to the FIP device */ static int fip_dev_close(io_dev_info_t *dev_info) { /* TODO: Consider tracking open files and cleaning them up here */ /* Clear the backend. */ backend_dev_handle = (uintptr_t)NULL; backend_image_spec = (uintptr_t)NULL; return free_dev_info(dev_info); } /* Open a file for access from package. */ static int fip_file_open(io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity) { int result; uintptr_t backend_handle; const io_uuid_spec_t *uuid_spec = (io_uuid_spec_t *)spec; size_t bytes_read; int found_file = 0; assert(uuid_spec != NULL); assert(entity != NULL); /* Can only have one file open at a time for the moment. We need to * track state like file cursor position. We know the header lives at * offset zero, so this entry should never be zero for an active file. * When the system supports dynamic memory allocation we can allow more * than one open file at a time if needed. */ if (current_file.entry.offset_address != 0) { WARN("fip_file_open : Only one open file at a time.\n"); return -ENOMEM; } /* Attempt to access the FIP image */ result = io_open(backend_dev_handle, backend_image_spec, &backend_handle); if (result != 0) { WARN("Failed to open Firmware Image Package (%i)\n", result); result = -ENOENT; goto fip_file_open_exit; } /* Seek past the FIP header into the Table of Contents */ result = io_seek(backend_handle, IO_SEEK_SET, sizeof(fip_toc_header_t)); if (result != 0) { WARN("fip_file_open: failed to seek\n"); result = -ENOENT; goto fip_file_open_close; } found_file = 0; do { result = io_read(backend_handle, (uintptr_t)¤t_file.entry, sizeof(current_file.entry), &bytes_read); if (result == 0) { if (compare_uuids(¤t_file.entry.uuid, &uuid_spec->uuid) == 0) { found_file = 1; break; } } else { WARN("Failed to read FIP (%i)\n", result); goto fip_file_open_close; } } while (compare_uuids(¤t_file.entry.uuid, &uuid_null) != 0); if (found_file == 1) { /* All fine. Update entity info with file state and return. Set * the file position to 0. The 'current_file.entry' holds the * base and size of the file. */ current_file.file_pos = 0; entity->info = (uintptr_t)¤t_file; } else { /* Did not find the file in the FIP. */ current_file.entry.offset_address = 0; result = -ENOENT; } fip_file_open_close: io_close(backend_handle); fip_file_open_exit: return result; } /* Return the size of a file in package */ static int fip_file_len(io_entity_t *entity, size_t *length) { assert(entity != NULL); assert(length != NULL); *length = ((file_state_t *)entity->info)->entry.size; return 0; } /* Read data from a file in package */ static int fip_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read) { int result; file_state_t *fp; size_t file_offset; size_t bytes_read; uintptr_t backend_handle; assert(entity != NULL); assert(length_read != NULL); assert(entity->info != (uintptr_t)NULL); /* Open the backend, attempt to access the blob image */ result = io_open(backend_dev_handle, backend_image_spec, &backend_handle); if (result != 0) { WARN("Failed to open FIP (%i)\n", result); result = -ENOENT; goto fip_file_read_exit; } fp = (file_state_t *)entity->info; /* Seek to the position in the FIP where the payload lives */ file_offset = fp->entry.offset_address + fp->file_pos; result = io_seek(backend_handle, IO_SEEK_SET, file_offset); if (result != 0) { WARN("fip_file_read: failed to seek\n"); result = -ENOENT; goto fip_file_read_close; } result = io_read(backend_handle, buffer, length, &bytes_read); if (result != 0) { /* We cannot read our data. Fail. */ WARN("Failed to read payload (%i)\n", result); result = -ENOENT; goto fip_file_read_close; } else { /* Set caller length and new file position. */ *length_read = bytes_read; fp->file_pos += bytes_read; } /* Close the backend. */ fip_file_read_close: io_close(backend_handle); fip_file_read_exit: return result; } /* Close a file in package */ static int fip_file_close(io_entity_t *entity) { /* Clear our current file pointer. * If we had malloc() we would free() here. */ if (current_file.entry.offset_address != 0) { zeromem(¤t_file, sizeof(current_file)); } /* Clear the Entity info. */ entity->info = 0; return 0; } /* Exported functions */ /* Register the Firmware Image Package driver with the IO abstraction */ int register_io_dev_fip(const io_dev_connector_t **dev_con) { int result; assert(dev_con != NULL); /* * Since dev_info isn't really used in io_register_device, always * use the same device info at here instead. */ result = io_register_device(&dev_info_pool[0]); if (result == 0) *dev_con = &fip_dev_connector; return result; } trusted-firmware-a-2.2/drivers/io/io_memmap.c000066400000000000000000000137221355360272700213120ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include /* As we need to be able to keep state for seek, only one file can be open * at a time. Make this a structure and point to the entity->info. When we * can malloc memory we can change this to support more open files. */ typedef struct { /* Use the 'in_use' flag as any value for base and file_pos could be * valid. */ int in_use; uintptr_t base; size_t file_pos; size_t size; } file_state_t; static file_state_t current_file = {0}; /* Identify the device type as memmap */ static io_type_t device_type_memmap(void) { return IO_TYPE_MEMMAP; } /* Memmap device functions */ 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); 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); static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer, size_t length, size_t *length_written); static int memmap_block_close(io_entity_t *entity); static int memmap_dev_close(io_dev_info_t *dev_info); static const io_dev_connector_t memmap_dev_connector = { .dev_open = memmap_dev_open }; static const io_dev_funcs_t memmap_dev_funcs = { .type = device_type_memmap, .open = memmap_block_open, .seek = memmap_block_seek, .size = memmap_block_len, .read = memmap_block_read, .write = memmap_block_write, .close = memmap_block_close, .dev_init = NULL, .dev_close = memmap_dev_close, }; /* No state associated with this device so structure can be const */ static const io_dev_info_t memmap_dev_info = { .funcs = &memmap_dev_funcs, .info = (uintptr_t)NULL }; /* Open a connection to the memmap device */ static int memmap_dev_open(const uintptr_t dev_spec __unused, io_dev_info_t **dev_info) { assert(dev_info != NULL); *dev_info = (io_dev_info_t *)&memmap_dev_info; /* cast away const */ return 0; } /* Close a connection to the memmap device */ static int memmap_dev_close(io_dev_info_t *dev_info) { /* NOP */ /* TODO: Consider tracking open files and cleaning them up here */ return 0; } /* Open a file on the memmap device */ static int memmap_block_open(io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity) { int result = -ENOMEM; const io_block_spec_t *block_spec = (io_block_spec_t *)spec; /* Since we need to track open state for seek() we only allow one open * spec at a time. When we have dynamic memory we can malloc and set * entity->info. */ if (current_file.in_use == 0) { assert(block_spec != NULL); assert(entity != NULL); current_file.in_use = 1; current_file.base = block_spec->offset; /* File cursor offset for seek and incremental reads etc. */ current_file.file_pos = 0; current_file.size = block_spec->length; entity->info = (uintptr_t)¤t_file; result = 0; } else { WARN("A Memmap device is already active. Close first.\n"); } return result; } /* Seek to a particular file offset on the memmap device */ static int memmap_block_seek(io_entity_t *entity, int mode, ssize_t offset) { int result = -ENOENT; file_state_t *fp; /* We only support IO_SEEK_SET for the moment. */ if (mode == IO_SEEK_SET) { assert(entity != NULL); fp = (file_state_t *) entity->info; /* Assert that new file position is valid */ assert((offset >= 0) && (offset < fp->size)); /* Reset file position */ fp->file_pos = offset; result = 0; } return result; } /* Return the size of a file on the memmap device */ static int memmap_block_len(io_entity_t *entity, size_t *length) { assert(entity != NULL); assert(length != NULL); *length = ((file_state_t *)entity->info)->size; return 0; } /* Read data from a file on the memmap device */ static int memmap_block_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read) { file_state_t *fp; size_t pos_after; assert(entity != NULL); assert(length_read != NULL); fp = (file_state_t *) entity->info; /* Assert that file position is valid for this read operation */ pos_after = fp->file_pos + length; assert((pos_after >= fp->file_pos) && (pos_after <= fp->size)); memcpy((void *)buffer, (void *)(fp->base + fp->file_pos), length); *length_read = length; /* Set file position after read */ fp->file_pos = pos_after; return 0; } /* Write data to a file on the memmap device */ static int memmap_block_write(io_entity_t *entity, const uintptr_t buffer, size_t length, size_t *length_written) { file_state_t *fp; size_t pos_after; assert(entity != NULL); assert(length_written != NULL); fp = (file_state_t *) entity->info; /* Assert that file position is valid for this write operation */ pos_after = fp->file_pos + length; assert((pos_after >= fp->file_pos) && (pos_after <= fp->size)); memcpy((void *)(fp->base + fp->file_pos), (void *)buffer, length); *length_written = length; /* Set file position after write */ fp->file_pos = pos_after; return 0; } /* Close a file on the memmap device */ static int memmap_block_close(io_entity_t *entity) { assert(entity != NULL); entity->info = 0; /* This would be a mem free() if we had malloc.*/ zeromem((void *)¤t_file, sizeof(current_file)); return 0; } /* Exported functions */ /* Register the memmap driver with the IO abstraction */ int register_io_dev_memmap(const io_dev_connector_t **dev_con) { int result; assert(dev_con != NULL); result = io_register_device(&memmap_dev_info); if (result == 0) *dev_con = &memmap_dev_connector; return result; } trusted-firmware-a-2.2/drivers/io/io_semihosting.c000066400000000000000000000107651355360272700223730ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* Identify the device type as semihosting */ static io_type_t device_type_sh(void) { return IO_TYPE_SEMIHOSTING; } /* Semi-hosting functions, device info and handle */ 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_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); static int sh_file_write(io_entity_t *entity, const uintptr_t buffer, size_t length, size_t *length_written); static int sh_file_close(io_entity_t *entity); static const io_dev_connector_t sh_dev_connector = { .dev_open = sh_dev_open }; static const io_dev_funcs_t sh_dev_funcs = { .type = device_type_sh, .open = sh_file_open, .seek = sh_file_seek, .size = sh_file_len, .read = sh_file_read, .write = sh_file_write, .close = sh_file_close, .dev_init = NULL, /* NOP */ .dev_close = NULL, /* NOP */ }; /* No state associated with this device so structure can be const */ static const io_dev_info_t sh_dev_info = { .funcs = &sh_dev_funcs, .info = (uintptr_t)NULL }; /* Open a connection to the semi-hosting device */ static int sh_dev_open(const uintptr_t dev_spec __unused, io_dev_info_t **dev_info) { assert(dev_info != NULL); *dev_info = (io_dev_info_t *)&sh_dev_info; /* cast away const */ return 0; } /* Open a file on the semi-hosting device */ static int sh_file_open(io_dev_info_t *dev_info __unused, const uintptr_t spec, io_entity_t *entity) { int result = -ENOENT; long sh_result; const io_file_spec_t *file_spec = (const io_file_spec_t *)spec; assert(file_spec != NULL); assert(entity != NULL); sh_result = semihosting_file_open(file_spec->path, file_spec->mode); if (sh_result > 0) { entity->info = (uintptr_t)sh_result; result = 0; } return result; } /* 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) { long file_handle, sh_result; assert(entity != NULL); file_handle = (long)entity->info; sh_result = semihosting_file_seek(file_handle, offset); return (sh_result == 0) ? 0 : -ENOENT; } /* Return the size of a file on the semi-hosting device */ static int sh_file_len(io_entity_t *entity, size_t *length) { int result = -ENOENT; assert(entity != NULL); assert(length != NULL); long sh_handle = (long)entity->info; long sh_result = semihosting_file_length(sh_handle); if (sh_result >= 0) { result = 0; *length = (size_t)sh_result; } return result; } /* Read data from a file on the semi-hosting device */ static int sh_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read) { int result = -ENOENT; long sh_result; size_t bytes = length; long file_handle; assert(entity != NULL); assert(length_read != NULL); file_handle = (long)entity->info; sh_result = semihosting_file_read(file_handle, &bytes, buffer); if (sh_result >= 0) { *length_read = (bytes != length) ? bytes : length; result = 0; } return result; } /* Write data to a file on the semi-hosting device */ static int sh_file_write(io_entity_t *entity, const uintptr_t buffer, size_t length, size_t *length_written) { long sh_result; long file_handle; size_t bytes = length; assert(entity != NULL); assert(length_written != NULL); file_handle = (long)entity->info; sh_result = semihosting_file_write(file_handle, &bytes, buffer); *length_written = length - bytes; return (sh_result == 0) ? 0 : -ENOENT; } /* Close a file on the semi-hosting device */ static int sh_file_close(io_entity_t *entity) { long sh_result; long file_handle; assert(entity != NULL); file_handle = (long)entity->info; sh_result = semihosting_file_close(file_handle); return (sh_result >= 0) ? 0 : -ENOENT; } /* Exported functions */ /* Register the semi-hosting driver with the IO abstraction */ int register_io_dev_sh(const io_dev_connector_t **dev_con) { int result; assert(dev_con != NULL); result = io_register_device(&sh_dev_info); if (result == 0) *dev_con = &sh_dev_connector; return result; } trusted-firmware-a-2.2/drivers/io/io_storage.c000066400000000000000000000165241355360272700215050ustar00rootroot00000000000000/* * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* Storage for a fixed maximum number of IO entities, definable by platform */ static io_entity_t entity_pool[MAX_IO_HANDLES]; /* Simple way of tracking used storage - each entry is NULL or a pointer to an * entity */ static io_entity_t *entity_map[MAX_IO_HANDLES]; /* Track number of allocated entities */ static unsigned int entity_count; /* Array of fixed maximum of registered devices, definable by platform */ static const io_dev_info_t *devices[MAX_IO_DEVICES]; /* Number of currently registered devices */ static unsigned int dev_count; /* Extra validation functions only used when asserts are enabled */ #if ENABLE_ASSERTIONS /* Return a boolean value indicating whether a device connector is valid */ static int is_valid_dev_connector(const io_dev_connector_t *dev_con) { int result = (dev_con != NULL) && (dev_con->dev_open != NULL); return result; } /* Return a boolean value indicating whether a device handle is valid */ static int is_valid_dev(const uintptr_t dev_handle) { const io_dev_info_t *dev = (io_dev_info_t *)dev_handle; int result = (dev != NULL) && (dev->funcs != NULL) && (dev->funcs->type != NULL) && (dev->funcs->type() < IO_TYPE_MAX); return result; } /* Return a boolean value indicating whether an IO entity is valid */ static int is_valid_entity(const uintptr_t handle) { const io_entity_t *entity = (io_entity_t *)handle; int result = (entity != NULL) && (is_valid_dev((uintptr_t)entity->dev_handle)); return result; } /* Return a boolean value indicating whether a seek mode is valid */ static int is_valid_seek_mode(io_seek_mode_t mode) { return ((mode != IO_SEEK_INVALID) && (mode < IO_SEEK_MAX)); } #endif /* ENABLE_ASSERTIONS */ /* End of extra validation functions only used when asserts are enabled */ /* Open a connection to a specific device */ static int dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec, io_dev_info_t **dev_info) { int result; assert(dev_info != NULL); assert(is_valid_dev_connector(dev_con)); result = dev_con->dev_open(dev_spec, dev_info); return result; } /* Set a handle to track an entity */ static void set_handle(uintptr_t *handle, io_entity_t *entity) { assert(handle != NULL); *handle = (uintptr_t)entity; } /* Locate an entity in the pool, specified by address */ static int find_first_entity(const io_entity_t *entity, unsigned int *index_out) { int result = -ENOENT; for (unsigned int index = 0; index < MAX_IO_HANDLES; ++index) { if (entity_map[index] == entity) { result = 0; *index_out = index; break; } } return result; } /* Allocate an entity from the pool and return a pointer to it */ static int allocate_entity(io_entity_t **entity) { int result = -ENOMEM; assert(entity != NULL); if (entity_count < MAX_IO_HANDLES) { unsigned int index = 0; result = find_first_entity(NULL, &index); assert(result == 0); *entity = entity_map[index] = &entity_pool[index]; ++entity_count; } return result; } /* Release an entity back to the pool */ static int free_entity(const io_entity_t *entity) { int result; unsigned int index = 0; assert(entity != NULL); result = find_first_entity(entity, &index); if (result == 0) { entity_map[index] = NULL; --entity_count; } return result; } /* Exported API */ /* Register a device driver */ int io_register_device(const io_dev_info_t *dev_info) { int result = -ENOMEM; assert(dev_info != NULL); if (dev_count < MAX_IO_DEVICES) { devices[dev_count] = dev_info; dev_count++; result = 0; } return result; } /* Open a connection to an IO device */ int io_dev_open(const io_dev_connector_t *dev_con, const uintptr_t dev_spec, uintptr_t *handle) { int result; assert(handle != NULL); result = dev_open(dev_con, dev_spec, (io_dev_info_t **)handle); return result; } /* Initialise an IO device explicitly - to permit lazy initialisation or * re-initialisation */ int io_dev_init(uintptr_t dev_handle, const uintptr_t init_params) { int result = 0; assert(dev_handle != (uintptr_t)NULL); assert(is_valid_dev(dev_handle)); io_dev_info_t *dev = (io_dev_info_t *)dev_handle; /* Absence of registered function implies NOP here */ if (dev->funcs->dev_init != NULL) { result = dev->funcs->dev_init(dev, init_params); } return result; } /* Close a connection to a device */ int io_dev_close(uintptr_t dev_handle) { int result = 0; assert(dev_handle != (uintptr_t)NULL); assert(is_valid_dev(dev_handle)); io_dev_info_t *dev = (io_dev_info_t *)dev_handle; /* Absence of registered function implies NOP here */ if (dev->funcs->dev_close != NULL) { result = dev->funcs->dev_close(dev); } return result; } /* Synchronous operations */ /* Open an IO entity */ int io_open(uintptr_t dev_handle, const uintptr_t spec, uintptr_t *handle) { int result; assert((spec != (uintptr_t)NULL) && (handle != NULL)); assert(is_valid_dev(dev_handle)); io_dev_info_t *dev = (io_dev_info_t *)dev_handle; io_entity_t *entity; result = allocate_entity(&entity); if (result == 0) { assert(dev->funcs->open != NULL); result = dev->funcs->open(dev, spec, entity); if (result == 0) { entity->dev_handle = dev; set_handle(handle, entity); } else free_entity(entity); } return result; } /* Seek to a specific position in an IO entity */ int io_seek(uintptr_t handle, io_seek_mode_t mode, ssize_t offset) { int result = -ENODEV; assert(is_valid_entity(handle) && is_valid_seek_mode(mode)); io_entity_t *entity = (io_entity_t *)handle; io_dev_info_t *dev = entity->dev_handle; if (dev->funcs->seek != NULL) result = dev->funcs->seek(entity, mode, offset); return result; } /* Determine the length of an IO entity */ int io_size(uintptr_t handle, size_t *length) { int result = -ENODEV; assert(is_valid_entity(handle) && (length != NULL)); io_entity_t *entity = (io_entity_t *)handle; io_dev_info_t *dev = entity->dev_handle; if (dev->funcs->size != NULL) result = dev->funcs->size(entity, length); return result; } /* Read data from an IO entity */ int io_read(uintptr_t handle, uintptr_t buffer, size_t length, size_t *length_read) { int result = -ENODEV; assert(is_valid_entity(handle)); io_entity_t *entity = (io_entity_t *)handle; io_dev_info_t *dev = entity->dev_handle; if (dev->funcs->read != NULL) result = dev->funcs->read(entity, buffer, length, length_read); return result; } /* Write data to an IO entity */ int io_write(uintptr_t handle, const uintptr_t buffer, size_t length, size_t *length_written) { int result = -ENODEV; assert(is_valid_entity(handle)); io_entity_t *entity = (io_entity_t *)handle; io_dev_info_t *dev = entity->dev_handle; if (dev->funcs->write != NULL) { result = dev->funcs->write(entity, buffer, length, length_written); } return result; } /* Close an IO entity */ int io_close(uintptr_t handle) { int result = 0; assert(is_valid_entity(handle)); io_entity_t *entity = (io_entity_t *)handle; io_dev_info_t *dev = entity->dev_handle; /* Absence of registered function implies NOP here */ if (dev->funcs->close != NULL) result = dev->funcs->close(entity); /* Ignore improbable free_entity failure */ (void)free_entity(entity); return result; } trusted-firmware-a-2.2/drivers/marvell/000077500000000000000000000000001355360272700202315ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/marvell/amb_adec.c000066400000000000000000000105331355360272700221120ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* AXI to M-Bridge decoding unit driver for Marvell Armada 8K and 8K+ SoCs */ #include #include #include #include #include #if LOG_LEVEL >= LOG_LEVEL_INFO #define DEBUG_ADDR_MAP #endif /* common defines */ #define WIN_ENABLE_BIT (0x1) #define MVEBU_AMB_ADEC_OFFSET (0x70ff00) #define AMB_WIN_CR_OFFSET(win) (amb_base + 0x0 + (0x8 * win)) #define AMB_ATTR_OFFSET 8 #define AMB_ATTR_MASK 0xFF #define AMB_SIZE_OFFSET 16 #define AMB_SIZE_MASK 0xFF #define AMB_WIN_BASE_OFFSET(win) (amb_base + 0x4 + (0x8 * win)) #define AMB_BASE_OFFSET 16 #define AMB_BASE_ADDR_MASK ((1 << (32 - AMB_BASE_OFFSET)) - 1) #define AMB_WIN_ALIGNMENT_64K (0x10000) #define AMB_WIN_ALIGNMENT_1M (0x100000) uintptr_t amb_base; static void amb_check_win(struct addr_map_win *win, uint32_t win_num) { uint32_t base_addr; /* make sure the base address is in 16-bit range */ if (win->base_addr > AMB_BASE_ADDR_MASK) { WARN("Window %d: base address is too big 0x%llx\n", win_num, win->base_addr); win->base_addr = AMB_BASE_ADDR_MASK; WARN("Set the base address to 0x%llx\n", win->base_addr); } base_addr = win->base_addr << AMB_BASE_OFFSET; /* for AMB The base is always 1M aligned */ /* check if address is aligned to 1M */ if (IS_NOT_ALIGN(base_addr, AMB_WIN_ALIGNMENT_1M)) { win->base_addr = ALIGN_UP(base_addr, AMB_WIN_ALIGNMENT_1M); WARN("Window %d: base address unaligned to 0x%x\n", win_num, AMB_WIN_ALIGNMENT_1M); WARN("Align up the base address to 0x%llx\n", win->base_addr); } /* size parameter validity check */ if (!IS_POWER_OF_2(win->win_size)) { WARN("Window %d: window size is not power of 2 (0x%llx)\n", win_num, win->win_size); win->win_size = ROUND_UP_TO_POW_OF_2(win->win_size); WARN("Rounding size to 0x%llx\n", win->win_size); } } static void amb_enable_win(struct addr_map_win *win, uint32_t win_num) { uint32_t ctrl, base, size; /* * size is 64KB granularity. * The number of ones specifies the size of the * window in 64 KB granularity. 0 is 64KB */ size = (win->win_size / AMB_WIN_ALIGNMENT_64K) - 1; ctrl = (size << AMB_SIZE_OFFSET) | (win->target_id << AMB_ATTR_OFFSET); base = win->base_addr << AMB_BASE_OFFSET; mmio_write_32(AMB_WIN_BASE_OFFSET(win_num), base); mmio_write_32(AMB_WIN_CR_OFFSET(win_num), ctrl); /* enable window after configuring window size (and attributes) */ ctrl |= WIN_ENABLE_BIT; mmio_write_32(AMB_WIN_CR_OFFSET(win_num), ctrl); } #ifdef DEBUG_ADDR_MAP static void dump_amb_adec(void) { uint32_t ctrl, base, win_id, attr; uint32_t size, size_count; /* Dump all AMB windows */ printf("bank attribute base size\n"); printf("--------------------------------------------\n"); for (win_id = 0; win_id < AMB_MAX_WIN_ID; win_id++) { ctrl = mmio_read_32(AMB_WIN_CR_OFFSET(win_id)); if (ctrl & WIN_ENABLE_BIT) { base = mmio_read_32(AMB_WIN_BASE_OFFSET(win_id)); attr = (ctrl >> AMB_ATTR_OFFSET) & AMB_ATTR_MASK; size_count = (ctrl >> AMB_SIZE_OFFSET) & AMB_SIZE_MASK; size = (size_count + 1) * AMB_WIN_ALIGNMENT_64K; printf("amb 0x%04x 0x%08x 0x%08x\n", attr, base, size); } } } #endif int init_amb_adec(uintptr_t base) { struct addr_map_win *win; uint32_t win_id, win_reg; uint32_t win_count; INFO("Initializing AXI to MBus Bridge Address decoding\n"); /* Get the base address of the AMB address decoding */ amb_base = base + MVEBU_AMB_ADEC_OFFSET; /* Get the array of the windows and its size */ marvell_get_amb_memory_map(&win, &win_count, base); if (win_count <= 0) INFO("no windows configurations found\n"); if (win_count > AMB_MAX_WIN_ID) { INFO("number of windows is bigger than %d\n", AMB_MAX_WIN_ID); return 0; } /* disable all AMB windows */ for (win_id = 0; win_id < AMB_MAX_WIN_ID; win_id++) { win_reg = mmio_read_32(AMB_WIN_CR_OFFSET(win_id)); win_reg &= ~WIN_ENABLE_BIT; mmio_write_32(AMB_WIN_CR_OFFSET(win_id), win_reg); } /* enable relevant windows */ for (win_id = 0; win_id < win_count; win_id++, win++) { amb_check_win(win, win_id); amb_enable_win(win, win_id); } #ifdef DEBUG_ADDR_MAP dump_amb_adec(); #endif INFO("Done AXI to MBus Bridge Address decoding Initializing\n"); return 0; } trusted-firmware-a-2.2/drivers/marvell/ap807_clocks_init.c000066400000000000000000000053671355360272700236300ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include /* Notify bootloader on DRAM setup */ #define AP807_CPU_ARO_CTRL(cluster) \ (MVEBU_RFU_BASE + 0x82A8 + (0xA58 * (cluster))) /* 0 - ARO clock is enabled, 1 - ARO clock is disabled */ #define AP807_CPU_ARO_CLK_EN_OFFSET 0 #define AP807_CPU_ARO_CLK_EN_MASK (0x1 << AP807_CPU_ARO_CLK_EN_OFFSET) /* 0 - ARO is the clock source, 1 - PLL is the clock source */ #define AP807_CPU_ARO_SEL_PLL_OFFSET 5 #define AP807_CPU_ARO_SEL_PLL_MASK (0x1 << AP807_CPU_ARO_SEL_PLL_OFFSET) /* AP807 clusters count */ #define AP807_CLUSTER_NUM 2 /* PLL frequency values */ #define PLL_FREQ_1200 0x2AE5F002 /* 1200 */ #define PLL_FREQ_2000 0x2FC9F002 /* 2000 */ #define PLL_FREQ_2200 0x2AC57001 /* 2200 */ #define PLL_FREQ_2400 0x2AE5F001 /* 2400 */ /* CPU PLL control registers */ #define AP807_CPU_PLL_CTRL(cluster) \ (MVEBU_RFU_BASE + 0x82E0 + (0x8 * (cluster))) #define AP807_CPU_PLL_PARAM(cluster) AP807_CPU_PLL_CTRL(cluster) #define AP807_CPU_PLL_CFG(cluster) (AP807_CPU_PLL_CTRL(cluster) + 0x4) #define AP807_CPU_PLL_CFG_BYPASS_MODE (0x1) #define AP807_CPU_PLL_CFG_USE_REG_FILE (0x1 << 9) static void pll_set_freq(unsigned int freq_val) { int i; for (i = 0 ; i < AP807_CLUSTER_NUM ; i++) { mmio_write_32(AP807_CPU_PLL_CFG(i), AP807_CPU_PLL_CFG_USE_REG_FILE); mmio_write_32(AP807_CPU_PLL_CFG(i), AP807_CPU_PLL_CFG_USE_REG_FILE | AP807_CPU_PLL_CFG_BYPASS_MODE); mmio_write_32(AP807_CPU_PLL_PARAM(i), freq_val); mmio_write_32(AP807_CPU_PLL_CFG(i), AP807_CPU_PLL_CFG_USE_REG_FILE); } } /* Switch to ARO from PLL in ap807 */ static void aro_to_pll(void) { unsigned int reg; int i; for (i = 0 ; i < AP807_CLUSTER_NUM ; i++) { /* switch from ARO to PLL */ reg = mmio_read_32(AP807_CPU_ARO_CTRL(i)); reg |= AP807_CPU_ARO_SEL_PLL_MASK; mmio_write_32(AP807_CPU_ARO_CTRL(i), reg); mdelay(100); /* disable ARO clk driver */ reg = mmio_read_32(AP807_CPU_ARO_CTRL(i)); reg |= (AP807_CPU_ARO_CLK_EN_MASK); mmio_write_32(AP807_CPU_ARO_CTRL(i), reg); } } /* switch from ARO to PLL * in case of default frequency option, configure PLL registers * to be aligned with new default frequency. */ void ap807_clocks_init(unsigned int freq_option) { /* Switch from ARO to PLL */ aro_to_pll(); /* Modifications in frequency table: * 0x0: 764x: change to 2000 MHz. * 0x2: 744x change to 1800 MHz, 764x change to 2200/2400. * 0x3: 3900/744x/764x change to 1200 MHz. */ switch (freq_option) { case CPU_2000_DDR_1200_RCLK_1200: pll_set_freq(PLL_FREQ_2000); break; default: break; } } trusted-firmware-a-2.2/drivers/marvell/cache_llc.c000066400000000000000000000042531355360272700222760ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* LLC driver is the Last Level Cache (L3C) driver * for Marvell SoCs in AP806, AP807, and AP810 */ #include #include #include #include #include #include #define CCU_HTC_CR(ap_index) (MVEBU_CCU_BASE(ap_index) + 0x200) #define CCU_SET_POC_OFFSET 5 extern void ca72_l2_enable_unique_clean(void); void llc_cache_sync(int ap_index) { mmio_write_32(LLC_SYNC(ap_index), 0); /* Atomic write, no need to wait */ } void llc_flush_all(int ap_index) { mmio_write_32(L2X0_CLEAN_INV_WAY(ap_index), LLC_WAY_MASK); llc_cache_sync(ap_index); } void llc_clean_all(int ap_index) { mmio_write_32(L2X0_CLEAN_WAY(ap_index), LLC_WAY_MASK); llc_cache_sync(ap_index); } void llc_inv_all(int ap_index) { mmio_write_32(L2X0_INV_WAY(ap_index), LLC_WAY_MASK); llc_cache_sync(ap_index); } void llc_disable(int ap_index) { llc_flush_all(ap_index); mmio_write_32(LLC_CTRL(ap_index), 0); dsbishst(); } void llc_enable(int ap_index, int excl_mode) { uint32_t val; dsbsy(); llc_inv_all(ap_index); dsbsy(); val = LLC_CTRL_EN; if (excl_mode) val |= LLC_EXCLUSIVE_EN; mmio_write_32(LLC_CTRL(ap_index), val); dsbsy(); } int llc_is_exclusive(int ap_index) { uint32_t reg; reg = mmio_read_32(LLC_CTRL(ap_index)); if ((reg & (LLC_CTRL_EN | LLC_EXCLUSIVE_EN)) == (LLC_CTRL_EN | LLC_EXCLUSIVE_EN)) return 1; return 0; } void llc_runtime_enable(int ap_index) { uint32_t reg; reg = mmio_read_32(LLC_CTRL(ap_index)); if (reg & LLC_CTRL_EN) return; INFO("Enabling LLC\n"); /* * Enable L2 UniqueClean evictions with data * Note: this configuration assumes that LLC is configured * in exclusive mode. * Later on in the code this assumption will be validated */ ca72_l2_enable_unique_clean(); llc_enable(ap_index, 1); /* Set point of coherency to DDR. * This is required by units which have SW cache coherency */ reg = mmio_read_32(CCU_HTC_CR(ap_index)); reg |= (0x1 << CCU_SET_POC_OFFSET); mmio_write_32(CCU_HTC_CR(ap_index), reg); } trusted-firmware-a-2.2/drivers/marvell/ccu.c000066400000000000000000000260511355360272700211530ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* CCU unit device driver for Marvell AP807, AP807 and AP810 SoCs */ #include #include #include #include #include #include #if LOG_LEVEL >= LOG_LEVEL_INFO #define DEBUG_ADDR_MAP #endif /* common defines */ #define WIN_ENABLE_BIT (0x1) /* Physical address of the base of the window = {AddrLow[19:0],20'h0} */ #define ADDRESS_SHIFT (20 - 4) #define ADDRESS_MASK (0xFFFFFFF0) #define CCU_WIN_ALIGNMENT (0x100000) #define IS_DRAM_TARGET(tgt) ((((tgt) == DRAM_0_TID) || \ ((tgt) == DRAM_1_TID) || \ ((tgt) == RAR_TID)) ? 1 : 0) /* For storage of CR, SCR, ALR, AHR abd GCR */ static uint32_t ccu_regs_save[MVEBU_CCU_MAX_WINS * 4 + 1]; #ifdef DEBUG_ADDR_MAP static void dump_ccu(int ap_index) { uint32_t win_id, win_cr, alr, ahr; uint8_t target_id; uint64_t start, end; /* Dump all AP windows */ printf("\tbank target start end\n"); printf("\t----------------------------------------------------\n"); for (win_id = 0; win_id < MVEBU_CCU_MAX_WINS; win_id++) { win_cr = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id)); if (win_cr & WIN_ENABLE_BIT) { target_id = (win_cr >> CCU_TARGET_ID_OFFSET) & CCU_TARGET_ID_MASK; alr = mmio_read_32(CCU_WIN_ALR_OFFSET(ap_index, win_id)); ahr = mmio_read_32(CCU_WIN_AHR_OFFSET(ap_index, win_id)); start = ((uint64_t)alr << ADDRESS_SHIFT); end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT); printf("\tccu %02x 0x%016llx 0x%016llx\n", target_id, start, end); } } win_cr = mmio_read_32(CCU_WIN_GCR_OFFSET(ap_index)); target_id = (win_cr >> CCU_GCR_TARGET_OFFSET) & CCU_GCR_TARGET_MASK; printf("\tccu GCR %d - all other transactions\n", target_id); } #endif void ccu_win_check(struct addr_map_win *win) { /* check if address is aligned to 1M */ if (IS_NOT_ALIGN(win->base_addr, CCU_WIN_ALIGNMENT)) { win->base_addr = ALIGN_UP(win->base_addr, CCU_WIN_ALIGNMENT); NOTICE("%s: Align up the base address to 0x%llx\n", __func__, win->base_addr); } /* size parameter validity check */ if (IS_NOT_ALIGN(win->win_size, CCU_WIN_ALIGNMENT)) { win->win_size = ALIGN_UP(win->win_size, CCU_WIN_ALIGNMENT); NOTICE("%s: Aligning size to 0x%llx\n", __func__, win->win_size); } } void ccu_enable_win(int ap_index, struct addr_map_win *win, uint32_t win_id) { uint32_t ccu_win_reg; uint32_t alr, ahr; uint64_t end_addr; if ((win_id == 0) || (win_id > MVEBU_CCU_MAX_WINS)) { ERROR("Enabling wrong CCU window %d!\n", win_id); return; } end_addr = (win->base_addr + win->win_size - 1); alr = (uint32_t)((win->base_addr >> ADDRESS_SHIFT) & ADDRESS_MASK); ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK); mmio_write_32(CCU_WIN_ALR_OFFSET(ap_index, win_id), alr); mmio_write_32(CCU_WIN_AHR_OFFSET(ap_index, win_id), ahr); ccu_win_reg = WIN_ENABLE_BIT; ccu_win_reg |= (win->target_id & CCU_TARGET_ID_MASK) << CCU_TARGET_ID_OFFSET; mmio_write_32(CCU_WIN_CR_OFFSET(ap_index, win_id), ccu_win_reg); } static void ccu_disable_win(int ap_index, uint32_t win_id) { uint32_t win_reg; if ((win_id == 0) || (win_id > MVEBU_CCU_MAX_WINS)) { ERROR("Disabling wrong CCU window %d!\n", win_id); return; } win_reg = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id)); win_reg &= ~WIN_ENABLE_BIT; mmio_write_32(CCU_WIN_CR_OFFSET(ap_index, win_id), win_reg); } /* Insert/Remove temporary window for using the out-of reset default * CPx base address to access the CP configuration space prior to * the further base address update in accordance with address mapping * design. * * NOTE: Use the same window array for insertion and removal of * temporary windows. */ void ccu_temp_win_insert(int ap_index, struct addr_map_win *win, int size) { uint32_t win_id; for (int i = 0; i < size; i++) { win_id = MVEBU_CCU_MAX_WINS - 1 - i; ccu_win_check(win); ccu_enable_win(ap_index, win, win_id); win++; } } /* * NOTE: Use the same window array for insertion and removal of * temporary windows. */ void ccu_temp_win_remove(int ap_index, struct addr_map_win *win, int size) { uint32_t win_id; for (int i = 0; i < size; i++) { uint64_t base; uint32_t target; win_id = MVEBU_CCU_MAX_WINS - 1 - i; target = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id)); target >>= CCU_TARGET_ID_OFFSET; target &= CCU_TARGET_ID_MASK; base = mmio_read_32(CCU_WIN_ALR_OFFSET(ap_index, win_id)); base <<= ADDRESS_SHIFT; if ((win->target_id != target) || (win->base_addr != base)) { ERROR("%s: Trying to remove bad window-%d!\n", __func__, win_id); continue; } ccu_disable_win(ap_index, win_id); win++; } } /* Returns current DRAM window target (DRAM_0_TID, DRAM_1_TID, RAR_TID) * NOTE: Call only once for each AP. * The AP0 DRAM window is located at index 2 only at the BL31 execution start. * Then it relocated to index 1 for matching the rest of APs DRAM settings. * Calling this function after relocation will produce wrong results on AP0 */ static uint32_t ccu_dram_target_get(int ap_index) { /* On BLE stage the AP0 DRAM window is opened by the BootROM at index 2. * All the rest of detected APs will use window at index 1. * The AP0 DRAM window is moved from index 2 to 1 during * init_ccu() execution. */ const uint32_t win_id = (ap_index == 0) ? 2 : 1; uint32_t target; target = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id)); target >>= CCU_TARGET_ID_OFFSET; target &= CCU_TARGET_ID_MASK; return target; } void ccu_dram_target_set(int ap_index, uint32_t target) { /* On BLE stage the AP0 DRAM window is opened by the BootROM at index 2. * All the rest of detected APs will use window at index 1. * The AP0 DRAM window is moved from index 2 to 1 * during init_ccu() execution. */ const uint32_t win_id = (ap_index == 0) ? 2 : 1; uint32_t dram_cr; dram_cr = mmio_read_32(CCU_WIN_CR_OFFSET(ap_index, win_id)); dram_cr &= ~(CCU_TARGET_ID_MASK << CCU_TARGET_ID_OFFSET); dram_cr |= (target & CCU_TARGET_ID_MASK) << CCU_TARGET_ID_OFFSET; mmio_write_32(CCU_WIN_CR_OFFSET(ap_index, win_id), dram_cr); } /* Setup CCU DRAM window and enable it */ void ccu_dram_win_config(int ap_index, struct addr_map_win *win) { #if IMAGE_BLE /* BLE */ /* On BLE stage the AP0 DRAM window is opened by the BootROM at index 2. * Since the BootROM is not accessing DRAM at BLE stage, * the DRAM window can be temporarely disabled. */ const uint32_t win_id = (ap_index == 0) ? 2 : 1; #else /* end of BLE */ /* At the ccu_init() execution stage, DRAM windows of all APs * are arranged at index 1. * The AP0 still has the old window BootROM DRAM at index 2, so * the window-1 can be safely disabled without breaking the DRAM access. */ const uint32_t win_id = 1; #endif ccu_disable_win(ap_index, win_id); /* enable write secure (and clear read secure) */ mmio_write_32(CCU_WIN_SCR_OFFSET(ap_index, win_id), CCU_WIN_ENA_WRITE_SECURE); ccu_win_check(win); ccu_enable_win(ap_index, win, win_id); } /* Save content of CCU window + GCR */ static void ccu_save_win_range(int ap_id, int win_first, int win_last, uint32_t *buffer) { int win_id, idx; /* Save CCU */ for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) { buffer[idx++] = mmio_read_32(CCU_WIN_CR_OFFSET(ap_id, win_id)); buffer[idx++] = mmio_read_32(CCU_WIN_SCR_OFFSET(ap_id, win_id)); buffer[idx++] = mmio_read_32(CCU_WIN_ALR_OFFSET(ap_id, win_id)); buffer[idx++] = mmio_read_32(CCU_WIN_AHR_OFFSET(ap_id, win_id)); } buffer[idx] = mmio_read_32(CCU_WIN_GCR_OFFSET(ap_id)); } /* Restore content of CCU window + GCR */ static void ccu_restore_win_range(int ap_id, int win_first, int win_last, uint32_t *buffer) { int win_id, idx; /* Restore CCU */ for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) { mmio_write_32(CCU_WIN_CR_OFFSET(ap_id, win_id), buffer[idx++]); mmio_write_32(CCU_WIN_SCR_OFFSET(ap_id, win_id), buffer[idx++]); mmio_write_32(CCU_WIN_ALR_OFFSET(ap_id, win_id), buffer[idx++]); mmio_write_32(CCU_WIN_AHR_OFFSET(ap_id, win_id), buffer[idx++]); } mmio_write_32(CCU_WIN_GCR_OFFSET(ap_id), buffer[idx]); } void ccu_save_win_all(int ap_id) { ccu_save_win_range(ap_id, 0, MVEBU_CCU_MAX_WINS - 1, ccu_regs_save); } void ccu_restore_win_all(int ap_id) { ccu_restore_win_range(ap_id, 0, MVEBU_CCU_MAX_WINS - 1, ccu_regs_save); } int init_ccu(int ap_index) { struct addr_map_win *win, *dram_win; uint32_t win_id, win_reg; uint32_t win_count, array_id; uint32_t dram_target; #if IMAGE_BLE /* In BootROM context CCU Window-1 * has SRAM_TID target and should not be disabled */ const uint32_t win_start = 2; #else const uint32_t win_start = 1; #endif INFO("Initializing CCU Address decoding\n"); /* Get the array of the windows and fill the map data */ marvell_get_ccu_memory_map(ap_index, &win, &win_count); if (win_count <= 0) { INFO("No windows configurations found\n"); } else if (win_count > (MVEBU_CCU_MAX_WINS - 1)) { ERROR("CCU mem map array > than max available windows (%d)\n", MVEBU_CCU_MAX_WINS); win_count = MVEBU_CCU_MAX_WINS; } /* Need to set GCR to DRAM before all CCU windows are disabled for * securing the normal access to DRAM location, which the ATF is running * from. Once all CCU windows are set, which have to include the * dedicated DRAM window as well, the GCR can be switched to the target * defined by the platform configuration. */ dram_target = ccu_dram_target_get(ap_index); win_reg = (dram_target & CCU_GCR_TARGET_MASK) << CCU_GCR_TARGET_OFFSET; mmio_write_32(CCU_WIN_GCR_OFFSET(ap_index), win_reg); /* If the DRAM window was already configured at the BLE stage, * only the window target considered valid, the address range should be * updated according to the platform configuration. */ for (dram_win = win, array_id = 0; array_id < win_count; array_id++, dram_win++) { if (IS_DRAM_TARGET(dram_win->target_id)) { dram_win->target_id = dram_target; break; } } /* Disable all AP CCU windows * Window-0 is always bypassed since it already contains * data allowing the internal configuration space access */ for (win_id = win_start; win_id < MVEBU_CCU_MAX_WINS; win_id++) { ccu_disable_win(ap_index, win_id); /* enable write secure (and clear read secure) */ mmio_write_32(CCU_WIN_SCR_OFFSET(ap_index, win_id), CCU_WIN_ENA_WRITE_SECURE); } /* win_id is the index of the current ccu window * array_id is the index of the current memory map window entry */ for (win_id = win_start, array_id = 0; ((win_id < MVEBU_CCU_MAX_WINS) && (array_id < win_count)); win_id++) { ccu_win_check(win); ccu_enable_win(ap_index, win, win_id); win++; array_id++; } /* Get & set the default target according to board topology */ win_reg = (marvell_get_ccu_gcr_target(ap_index) & CCU_GCR_TARGET_MASK) << CCU_GCR_TARGET_OFFSET; mmio_write_32(CCU_WIN_GCR_OFFSET(ap_index), win_reg); #ifdef DEBUG_ADDR_MAP dump_ccu(ap_index); #endif INFO("Done CCU Address decoding Initializing\n"); return 0; } trusted-firmware-a-2.2/drivers/marvell/comphy.h000066400000000000000000000432201355360272700217020ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* Driver for COMPHY unit that is part or Marvell A8K SoCs */ #ifndef COMPHY_H #define COMPHY_H /* COMPHY registers */ #define COMMON_PHY_CFG1_REG 0x0 #define COMMON_PHY_CFG1_PWR_UP_OFFSET 1 #define COMMON_PHY_CFG1_PWR_UP_MASK \ (0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET) #define COMMON_PHY_CFG1_PIPE_SELECT_OFFSET 2 #define COMMON_PHY_CFG1_PIPE_SELECT_MASK \ (0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET) #define COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET 13 #define COMMON_PHY_CFG1_PWR_ON_RESET_MASK \ (0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET) #define COMMON_PHY_CFG1_CORE_RSTN_OFFSET 14 #define COMMON_PHY_CFG1_CORE_RSTN_MASK \ (0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET) #define COMMON_PHY_PHY_MODE_OFFSET 15 #define COMMON_PHY_PHY_MODE_MASK \ (0x1 << COMMON_PHY_PHY_MODE_OFFSET) #define COMMON_SELECTOR_PHY_OFFSET 0x140 #define COMMON_SELECTOR_PIPE_OFFSET 0x144 #define COMMON_PHY_SD_CTRL1 0x148 #define COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_OFFSET 0 #define COMMON_PHY_SD_CTRL1_COMPHY_0_4_PORT_MASK 0xFFFF #define COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET 24 #define COMMON_PHY_SD_CTRL1_PCIE_X4_EN_MASK \ (0x1 << COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET) #define COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET 25 #define COMMON_PHY_SD_CTRL1_PCIE_X2_EN_MASK \ (0x1 << COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET) #define DFX_DEV_GEN_CTRL12 0x80 #define DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET 7 #define DFX_DEV_GEN_PCIE_CLK_SRC_MASK \ (0x3 << DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET) /* HPIPE register */ #define HPIPE_PWR_PLL_REG 0x4 #define HPIPE_PWR_PLL_REF_FREQ_OFFSET 0 #define HPIPE_PWR_PLL_REF_FREQ_MASK \ (0x1f << HPIPE_PWR_PLL_REF_FREQ_OFFSET) #define HPIPE_PWR_PLL_PHY_MODE_OFFSET 5 #define HPIPE_PWR_PLL_PHY_MODE_MASK \ (0x7 << HPIPE_PWR_PLL_PHY_MODE_OFFSET) #define HPIPE_DFE_REG0 0x01C #define HPIPE_DFE_RES_FORCE_OFFSET 15 #define HPIPE_DFE_RES_FORCE_MASK \ (0x1 << HPIPE_DFE_RES_FORCE_OFFSET) #define HPIPE_G2_SET_1_REG 0x040 #define HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET 0 #define HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK \ (0x7 << HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET) #define HPIPE_G2_SET_1_G2_RX_SELMUPP_OFFSET 3 #define HPIPE_G2_SET_1_G2_RX_SELMUPP_MASK \ (0x7 << HPIPE_G2_SET_1_G2_RX_SELMUPP_OFFSET) #define HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET 6 #define HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK \ (0x3 << HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET) #define HPIPE_G3_SETTINGS_1_REG 0x048 #define HPIPE_G3_RX_SELMUPI_OFFSET 0 #define HPIPE_G3_RX_SELMUPI_MASK \ (0x7 << HPIPE_G3_RX_SELMUPI_OFFSET) #define HPIPE_G3_RX_SELMUPF_OFFSET 3 #define HPIPE_G3_RX_SELMUPF_MASK \ (0x7 << HPIPE_G3_RX_SELMUPF_OFFSET) #define HPIPE_G3_SETTING_BIT_OFFSET 13 #define HPIPE_G3_SETTING_BIT_MASK \ (0x1 << HPIPE_G3_SETTING_BIT_OFFSET) #define HPIPE_INTERFACE_REG 0x94 #define HPIPE_INTERFACE_GEN_MAX_OFFSET 10 #define HPIPE_INTERFACE_GEN_MAX_MASK \ (0x3 << HPIPE_INTERFACE_GEN_MAX_OFFSET) #define HPIPE_INTERFACE_DET_BYPASS_OFFSET 12 #define HPIPE_INTERFACE_DET_BYPASS_MASK \ (0x1 << HPIPE_INTERFACE_DET_BYPASS_OFFSET) #define HPIPE_INTERFACE_LINK_TRAIN_OFFSET 14 #define HPIPE_INTERFACE_LINK_TRAIN_MASK \ (0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET) #define HPIPE_VDD_CAL_CTRL_REG 0x114 #define HPIPE_EXT_SELLV_RXSAMPL_OFFSET 5 #define HPIPE_EXT_SELLV_RXSAMPL_MASK \ (0x1f << HPIPE_EXT_SELLV_RXSAMPL_OFFSET) #define HPIPE_PCIE_REG0 0x120 #define HPIPE_PCIE_IDLE_SYNC_OFFSET 12 #define HPIPE_PCIE_IDLE_SYNC_MASK \ (0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET) #define HPIPE_PCIE_SEL_BITS_OFFSET 13 #define HPIPE_PCIE_SEL_BITS_MASK \ (0x3 << HPIPE_PCIE_SEL_BITS_OFFSET) #define HPIPE_LANE_ALIGN_REG 0x124 #define HPIPE_LANE_ALIGN_OFF_OFFSET 12 #define HPIPE_LANE_ALIGN_OFF_MASK \ (0x1 << HPIPE_LANE_ALIGN_OFF_OFFSET) #define HPIPE_MISC_REG 0x13C #define HPIPE_MISC_CLK100M_125M_OFFSET 4 #define HPIPE_MISC_CLK100M_125M_MASK \ (0x1 << HPIPE_MISC_CLK100M_125M_OFFSET) #define HPIPE_MISC_ICP_FORCE_OFFSET 5 #define HPIPE_MISC_ICP_FORCE_MASK \ (0x1 << HPIPE_MISC_ICP_FORCE_OFFSET) #define HPIPE_MISC_TXDCLK_2X_OFFSET 6 #define HPIPE_MISC_TXDCLK_2X_MASK \ (0x1 << HPIPE_MISC_TXDCLK_2X_OFFSET) #define HPIPE_MISC_CLK500_EN_OFFSET 7 #define HPIPE_MISC_CLK500_EN_MASK \ (0x1 << HPIPE_MISC_CLK500_EN_OFFSET) #define HPIPE_MISC_REFCLK_SEL_OFFSET 10 #define HPIPE_MISC_REFCLK_SEL_MASK \ (0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET) #define HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG 0x16C #define HPIPE_SMAPLER_OFFSET 12 #define HPIPE_SMAPLER_MASK (0x1 << HPIPE_SMAPLER_OFFSET) #define HPIPE_PWR_CTR_DTL_REG 0x184 #define HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET 2 #define HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK \ (0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET) #define HPIPE_FRAME_DET_CONTROL_REG 0x220 #define HPIPE_FRAME_DET_LOCK_LOST_TO_OFFSET 12 #define HPIPE_FRAME_DET_LOCK_LOST_TO_MASK \ (0x1 << HPIPE_FRAME_DET_LOCK_LOST_TO_OFFSET) #define HPIPE_TX_TRAIN_CTRL_0_REG 0x268 #define HPIPE_TX_TRAIN_P2P_HOLD_OFFSET 15 #define HPIPE_TX_TRAIN_P2P_HOLD_MASK \ (0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET) #define HPIPE_TX_TRAIN_CTRL_REG 0x26C #define HPIPE_TX_TRAIN_CTRL_G1_OFFSET 0 #define HPIPE_TX_TRAIN_CTRL_G1_MASK \ (0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET) #define HPIPE_TX_TRAIN_CTRL_GN1_OFFSET 1 #define HPIPE_TX_TRAIN_CTRL_GN1_MASK \ (0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET) #define HPIPE_TX_TRAIN_CTRL_G0_OFFSET 2 #define HPIPE_TX_TRAIN_CTRL_G0_MASK \ (0x1 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET) #define HPIPE_TX_TRAIN_CTRL_4_REG 0x278 #define HPIPE_TRX_TRAIN_TIMER_OFFSET 0 #define HPIPE_TRX_TRAIN_TIMER_MASK \ (0x3FF << HPIPE_TRX_TRAIN_TIMER_OFFSET) #define HPIPE_TX_TRAIN_CTRL_5_REG 0x2A4 #define HPIPE_TX_TRAIN_START_SQ_EN_OFFSET 11 #define HPIPE_TX_TRAIN_START_SQ_EN_MASK \ (0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET) #define HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET 12 #define HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK \ (0x1 << HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET) #define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET 13 #define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK \ (0x1 << HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET) #define HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET 14 #define HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK \ (0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET) #define HPIPE_TX_TRAIN_REG 0x31C #define HPIPE_TX_TRAIN_CHK_INIT_OFFSET 4 #define HPIPE_TX_TRAIN_CHK_INIT_MASK \ (0x1 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET) #define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET 7 #define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK \ (0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET) #define HPIPE_CDR_CONTROL_REG 0x418 #define HPIPE_CDR_RX_MAX_DFE_ADAPT_0_OFFSET 14 #define HPIPE_CDR_RX_MAX_DFE_ADAPT_0_MASK \ (0x3 << HPIPE_CDR_RX_MAX_DFE_ADAPT_0_OFFSET) #define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET 12 #define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_MASK \ (0x3 << HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET) #define HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET 9 #define HPIPE_CDR_MAX_DFE_ADAPT_0_MASK \ (0x7 << HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET) #define HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET 6 #define HPIPE_CDR_MAX_DFE_ADAPT_1_MASK \ (0x7 << HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET) #define HPIPE_TX_TRAIN_CTRL_11_REG 0x438 #define HPIPE_TX_STATUS_CHECK_MODE_OFFSET 6 #define HPIPE_TX_TX_STATUS_CHECK_MODE_MASK \ (0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET) #define HPIPE_TX_NUM_OF_PRESET_OFFSET 10 #define HPIPE_TX_NUM_OF_PRESET_MASK \ (0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET) #define HPIPE_TX_SWEEP_PRESET_EN_OFFSET 15 #define HPIPE_TX_SWEEP_PRESET_EN_MASK \ (0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET) #define HPIPE_G2_SETTINGS_4_REG 0x44C #define HPIPE_G2_DFE_RES_OFFSET 8 #define HPIPE_G2_DFE_RES_MASK (0x3 << HPIPE_G2_DFE_RES_OFFSET) #define HPIPE_G3_SETTING_3_REG 0x450 #define HPIPE_G3_FFE_CAP_SEL_OFFSET 0 #define HPIPE_G3_FFE_CAP_SEL_MASK \ (0xf << HPIPE_G3_FFE_CAP_SEL_OFFSET) #define HPIPE_G3_FFE_RES_SEL_OFFSET 4 #define HPIPE_G3_FFE_RES_SEL_MASK \ (0x7 << HPIPE_G3_FFE_RES_SEL_OFFSET) #define HPIPE_G3_FFE_SETTING_FORCE_OFFSET 7 #define HPIPE_G3_FFE_SETTING_FORCE_MASK \ (0x1 << HPIPE_G3_FFE_SETTING_FORCE_OFFSET) #define HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET 12 #define HPIPE_G3_FFE_DEG_RES_LEVEL_MASK \ (0x3 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET) #define HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET 14 #define HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK \ (0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET) #define HPIPE_G3_SETTING_4_REG 0x454 #define HPIPE_G3_DFE_RES_OFFSET 8 #define HPIPE_G3_DFE_RES_MASK (0x3 << HPIPE_G3_DFE_RES_OFFSET) #define HPIPE_DFE_CONTROL_REG 0x470 #define HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET 14 #define HPIPE_DFE_TX_MAX_DFE_ADAPT_MASK \ (0x3 << HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET) #define HPIPE_DFE_CTRL_28_REG 0x49C #define HPIPE_DFE_CTRL_28_PIPE4_OFFSET 7 #define HPIPE_DFE_CTRL_28_PIPE4_MASK \ (0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET) #define HPIPE_G3_SETTING_5_REG 0x548 #define HPIPE_G3_SETTING_5_G3_ICP_OFFSET 0 #define HPIPE_G3_SETTING_5_G3_ICP_MASK \ (0xf << HPIPE_G3_SETTING_5_G3_ICP_OFFSET) #define HPIPE_LANE_STATUS1_REG 0x60C #define HPIPE_LANE_STATUS1_PCLK_EN_OFFSET 0 #define HPIPE_LANE_STATUS1_PCLK_EN_MASK \ (0x1 << HPIPE_LANE_STATUS1_PCLK_EN_OFFSET) #define HPIPE_LANE_CFG4_REG 0x620 #define HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET 3 #define HPIPE_LANE_CFG4_DFE_EN_SEL_MASK \ (0x1 << HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET) #define HPIPE_LANE_EQU_CONFIG_0_REG 0x69C #define HPIPE_CFG_EQ_FS_OFFSET 0 #define HPIPE_CFG_EQ_FS_MASK (0x3f << HPIPE_CFG_EQ_FS_OFFSET) #define HPIPE_CFG_EQ_LF_OFFSET 6 #define HPIPE_CFG_EQ_LF_MASK (0x3f << HPIPE_CFG_EQ_LF_OFFSET) #define HPIPE_CFG_PHY_RC_EP_OFFSET 12 #define HPIPE_CFG_PHY_RC_EP_MASK \ (0x1 << HPIPE_CFG_PHY_RC_EP_OFFSET) #define HPIPE_LANE_EQ_CFG1_REG 0x6a0 #define HPIPE_CFG_UPDATE_POLARITY_OFFSET 12 #define HPIPE_CFG_UPDATE_POLARITY_MASK \ (0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET) #define HPIPE_LANE_EQ_CFG2_REG 0x6a4 #define HPIPE_CFG_EQ_BUNDLE_DIS_OFFSET 14 #define HPIPE_CFG_EQ_BUNDLE_DIS_MASK \ (0x1 << HPIPE_CFG_EQ_BUNDLE_DIS_OFFSET) #define HPIPE_LANE_PRESET_CFG0_REG 0x6a8 #define HPIPE_CFG_CURSOR_PRESET0_OFFSET 0 #define HPIPE_CFG_CURSOR_PRESET0_MASK \ (0x3f << HPIPE_CFG_CURSOR_PRESET0_OFFSET) #define HPIPE_CFG_CURSOR_PRESET1_OFFSET 6 #define HPIPE_CFG_CURSOR_PRESET1_MASK \ (0x3f << HPIPE_CFG_CURSOR_PRESET1_OFFSET) #define HPIPE_LANE_PRESET_CFG1_REG 0x6ac #define HPIPE_CFG_CURSOR_PRESET2_OFFSET 0 #define HPIPE_CFG_CURSOR_PRESET2_MASK \ (0x3f << HPIPE_CFG_CURSOR_PRESET2_OFFSET) #define HPIPE_CFG_CURSOR_PRESET3_OFFSET 6 #define HPIPE_CFG_CURSOR_PRESET3_MASK \ (0x3f << HPIPE_CFG_CURSOR_PRESET3_OFFSET) #define HPIPE_LANE_PRESET_CFG2_REG 0x6b0 #define HPIPE_CFG_CURSOR_PRESET4_OFFSET 0 #define HPIPE_CFG_CURSOR_PRESET4_MASK \ (0x3f << HPIPE_CFG_CURSOR_PRESET4_OFFSET) #define HPIPE_CFG_CURSOR_PRESET5_OFFSET 6 #define HPIPE_CFG_CURSOR_PRESET5_MASK \ (0x3f << HPIPE_CFG_CURSOR_PRESET5_OFFSET) #define HPIPE_LANE_PRESET_CFG3_REG 0x6b4 #define HPIPE_CFG_CURSOR_PRESET6_OFFSET 0 #define HPIPE_CFG_CURSOR_PRESET6_MASK \ (0x3f << HPIPE_CFG_CURSOR_PRESET6_OFFSET) #define HPIPE_CFG_CURSOR_PRESET7_OFFSET 6 #define HPIPE_CFG_CURSOR_PRESET7_MASK \ (0x3f << HPIPE_CFG_CURSOR_PRESET7_OFFSET) #define HPIPE_LANE_PRESET_CFG4_REG 0x6b8 #define HPIPE_CFG_CURSOR_PRESET8_OFFSET 0 #define HPIPE_CFG_CURSOR_PRESET8_MASK \ (0x3f << HPIPE_CFG_CURSOR_PRESET8_OFFSET) #define HPIPE_CFG_CURSOR_PRESET9_OFFSET 6 #define HPIPE_CFG_CURSOR_PRESET9_MASK \ (0x3f << HPIPE_CFG_CURSOR_PRESET9_OFFSET) #define HPIPE_LANE_PRESET_CFG5_REG 0x6bc #define HPIPE_CFG_CURSOR_PRESET10_OFFSET 0 #define HPIPE_CFG_CURSOR_PRESET10_MASK \ (0x3f << HPIPE_CFG_CURSOR_PRESET10_OFFSET) #define HPIPE_CFG_CURSOR_PRESET11_OFFSET 6 #define HPIPE_CFG_CURSOR_PRESET11_MASK \ (0x3f << HPIPE_CFG_CURSOR_PRESET11_OFFSET) #define HPIPE_LANE_PRESET_CFG6_REG 0x6c0 #define HPIPE_CFG_PRE_CURSOR_PRESET0_OFFSET 0 #define HPIPE_CFG_PRE_CURSOR_PRESET0_MASK \ (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET0_OFFSET) #define HPIPE_CFG_POST_CURSOR_PRESET0_OFFSET 6 #define HPIPE_CFG_POST_CURSOR_PRESET0_MASK \ (0x3f << HPIPE_CFG_POST_CURSOR_PRESET0_OFFSET) #define HPIPE_LANE_PRESET_CFG7_REG 0x6c4 #define HPIPE_CFG_PRE_CURSOR_PRESET1_OFFSET 0 #define HPIPE_CFG_PRE_CURSOR_PRESET1_MASK \ (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET1_OFFSET) #define HPIPE_CFG_POST_CURSOR_PRESET1_OFFSET 6 #define HPIPE_CFG_POST_CURSOR_PRESET1_MASK \ (0x3f << HPIPE_CFG_POST_CURSOR_PRESET1_OFFSET) #define HPIPE_LANE_PRESET_CFG8_REG 0x6c8 #define HPIPE_CFG_PRE_CURSOR_PRESET2_OFFSET 0 #define HPIPE_CFG_PRE_CURSOR_PRESET2_MASK \ (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET2_OFFSET) #define HPIPE_CFG_POST_CURSOR_PRESET2_OFFSET 6 #define HPIPE_CFG_POST_CURSOR_PRESET2_MASK \ (0x3f << HPIPE_CFG_POST_CURSOR_PRESET2_OFFSET) #define HPIPE_LANE_PRESET_CFG9_REG 0x6cc #define HPIPE_CFG_PRE_CURSOR_PRESET3_OFFSET 0 #define HPIPE_CFG_PRE_CURSOR_PRESET3_MASK \ (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET3_OFFSET) #define HPIPE_CFG_POST_CURSOR_PRESET3_OFFSET 6 #define HPIPE_CFG_POST_CURSOR_PRESET3_MASK \ (0x3f << HPIPE_CFG_POST_CURSOR_PRESET3_OFFSET) #define HPIPE_LANE_PRESET_CFG10_REG 0x6d0 #define HPIPE_CFG_PRE_CURSOR_PRESET4_OFFSET 0 #define HPIPE_CFG_PRE_CURSOR_PRESET4_MASK \ (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET4_OFFSET) #define HPIPE_CFG_POST_CURSOR_PRESET4_OFFSET 6 #define HPIPE_CFG_POST_CURSOR_PRESET4_MASK \ (0x3f << HPIPE_CFG_POST_CURSOR_PRESET4_OFFSET) #define HPIPE_LANE_PRESET_CFG11_REG 0x6d4 #define HPIPE_CFG_PRE_CURSOR_PRESET5_OFFSET 0 #define HPIPE_CFG_PRE_CURSOR_PRESET5_MASK \ (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET5_OFFSET) #define HPIPE_CFG_POST_CURSOR_PRESET5_OFFSET 6 #define HPIPE_CFG_POST_CURSOR_PRESET5_MASK \ (0x3f << HPIPE_CFG_POST_CURSOR_PRESET5_OFFSET) #define HPIPE_LANE_PRESET_CFG12_REG 0x6d8 #define HPIPE_CFG_PRE_CURSOR_PRESET6_OFFSET 0 #define HPIPE_CFG_PRE_CURSOR_PRESET6_MASK \ (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET6_OFFSET) #define HPIPE_CFG_POST_CURSOR_PRESET6_OFFSET 6 #define HPIPE_CFG_POST_CURSOR_PRESET6_MASK \ (0x3f << HPIPE_CFG_POST_CURSOR_PRESET6_OFFSET) #define HPIPE_LANE_PRESET_CFG13_REG 0x6dc #define HPIPE_CFG_PRE_CURSOR_PRESET7_OFFSET 0 #define HPIPE_CFG_PRE_CURSOR_PRESET7_MASK \ (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET7_OFFSET) #define HPIPE_CFG_POST_CURSOR_PRESET7_OFFSET 6 #define HPIPE_CFG_POST_CURSOR_PRESET7_MASK \ (0x3f << HPIPE_CFG_POST_CURSOR_PRESET7_OFFSET) #define HPIPE_LANE_PRESET_CFG14_REG 0x6e0 #define HPIPE_CFG_PRE_CURSOR_PRESET8_OFFSET 0 #define HPIPE_CFG_PRE_CURSOR_PRESET8_MASK \ (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET8_OFFSET) #define HPIPE_CFG_POST_CURSOR_PRESET8_OFFSET 6 #define HPIPE_CFG_POST_CURSOR_PRESET8_MASK \ (0x3f << HPIPE_CFG_POST_CURSOR_PRESET8_OFFSET) #define HPIPE_LANE_PRESET_CFG15_REG 0x6e4 #define HPIPE_CFG_PRE_CURSOR_PRESET9_OFFSET 0 #define HPIPE_CFG_PRE_CURSOR_PRESET9_MASK \ (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET9_OFFSET) #define HPIPE_CFG_POST_CURSOR_PRESET9_OFFSET 6 #define HPIPE_CFG_POST_CURSOR_PRESET9_MASK \ (0x3f << HPIPE_CFG_POST_CURSOR_PRESET9_OFFSET) #define HPIPE_LANE_PRESET_CFG16_REG 0x6e8 #define HPIPE_CFG_PRE_CURSOR_PRESET10_OFFSET 0 #define HPIPE_CFG_PRE_CURSOR_PRESET10_MASK \ (0x3f << HPIPE_CFG_PRE_CURSOR_PRESET10_OFFSET) #define HPIPE_CFG_POST_CURSOR_PRESET10_OFFSET 6 #define HPIPE_CFG_POST_CURSOR_PRESET10_MASK \ (0x3f << HPIPE_CFG_POST_CURSOR_PRESET10_OFFSET) #define HPIPE_LANE_EQ_REMOTE_SETTING_REG 0x6f8 #define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET 0 #define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_MASK \ (0x1 << HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET) #define HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET 1 #define HPIPE_LANE_CFG_FOM_ONLY_MODE_MASK \ (0x1 << HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET) #define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET 2 #define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_MASK \ (0xf << HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET) #define HPIPE_RST_CLK_CTRL_REG 0x704 #define HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET 0 #define HPIPE_RST_CLK_CTRL_PIPE_RST_MASK \ (0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET) #define HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET 2 #define HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK \ (0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET) #define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET 3 #define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK \ (0x1 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET) #define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET 9 #define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK \ (0x1 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET) #define HPIPE_CLK_SRC_LO_REG 0x70c #define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET 1 #define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_MASK \ (0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET) #define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET 2 #define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_MASK \ (0x3 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET) #define HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET 5 #define HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK \ (0x7 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET) #define HPIPE_CLK_SRC_HI_REG 0x710 #define HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET 0 #define HPIPE_CLK_SRC_HI_LANE_STRT_MASK \ (0x1 << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET) #define HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET 1 #define HPIPE_CLK_SRC_HI_LANE_BREAK_MASK \ (0x1 << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET) #define HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET 2 #define HPIPE_CLK_SRC_HI_LANE_MASTER_MASK \ (0x1 << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET) #define HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET 7 #define HPIPE_CLK_SRC_HI_MODE_PIPE_MASK \ (0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET) #define HPIPE_GLOBAL_PM_CTRL 0x740 #define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET 0 #define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK \ (0xFF << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET) #endif /* COMPHY_H */ trusted-firmware-a-2.2/drivers/marvell/comphy/000077500000000000000000000000001355360272700215305ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/marvell/comphy/comphy-cp110.h000066400000000000000000001024441355360272700240270ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* Marvell CP110 SoC COMPHY unit driver */ #ifndef COMPHY_CP110_H #define COMPHY_CP110_H #define SD_ADDR(base, lane) (base + 0x1000 * lane) #define HPIPE_ADDR(base, lane) (SD_ADDR(base, lane) + 0x800) #define COMPHY_ADDR(base, lane) (base + 0x28 * lane) #define MAX_NUM_OF_FFE 8 #define RX_TRAINING_TIMEOUT 500 /* Comphy registers */ #define COMMON_PHY_CFG1_REG 0x0 #define COMMON_PHY_CFG1_PWR_UP_OFFSET 1 #define COMMON_PHY_CFG1_PWR_UP_MASK \ (0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET) #define COMMON_PHY_CFG1_PIPE_SELECT_OFFSET 2 #define COMMON_PHY_CFG1_PIPE_SELECT_MASK \ (0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET) #define COMMON_PHY_CFG1_CORE_RSTN_OFFSET 13 #define COMMON_PHY_CFG1_CORE_RSTN_MASK \ (0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET) #define COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET 14 #define COMMON_PHY_CFG1_PWR_ON_RESET_MASK \ (0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET) #define COMMON_PHY_PHY_MODE_OFFSET 15 #define COMMON_PHY_PHY_MODE_MASK \ (0x1 << COMMON_PHY_PHY_MODE_OFFSET) #define COMMON_PHY_CFG6_REG 0x14 #define COMMON_PHY_CFG6_IF_40_SEL_OFFSET 18 #define COMMON_PHY_CFG6_IF_40_SEL_MASK \ (0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET) #define COMMON_PHY_CFG6_REG 0x14 #define COMMON_PHY_CFG6_IF_40_SEL_OFFSET 18 #define COMMON_PHY_CFG6_IF_40_SEL_MASK \ (0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET) #define COMMON_SELECTOR_PHY_REG_OFFSET 0x140 #define COMMON_SELECTOR_PIPE_REG_OFFSET 0x144 #define COMMON_SELECTOR_COMPHY_MASK 0xf #define COMMON_SELECTOR_COMPHYN_FIELD_WIDTH 4 #define COMMON_SELECTOR_COMPHYN_SATA 0x4 #define COMMON_SELECTOR_PIPE_COMPHY_PCIE 0x4 #define COMMON_SELECTOR_PIPE_COMPHY_USBH 0x1 #define COMMON_SELECTOR_PIPE_COMPHY_USBD 0x2 /* SGMII/HS-SGMII/SFI/RXAUI */ #define COMMON_SELECTOR_COMPHY0_1_2_NETWORK 0x1 #define COMMON_SELECTOR_COMPHY3_RXAUI 0x1 #define COMMON_SELECTOR_COMPHY3_SGMII 0x2 #define COMMON_SELECTOR_COMPHY4_PORT1 0x1 #define COMMON_SELECTOR_COMPHY4_ALL_OTHERS 0x2 #define COMMON_SELECTOR_COMPHY5_RXAUI 0x2 #define COMMON_SELECTOR_COMPHY5_SGMII 0x1 #define COMMON_PHY_SD_CTRL1 0x148 #define COMMON_PHY_SD_CTRL1_COMPHY_0_PORT_OFFSET 0 #define COMMON_PHY_SD_CTRL1_COMPHY_1_PORT_OFFSET 4 #define COMMON_PHY_SD_CTRL1_COMPHY_2_PORT_OFFSET 8 #define COMMON_PHY_SD_CTRL1_COMPHY_3_PORT_OFFSET 12 #define COMMON_PHY_SD_CTRL1_COMPHY_0_3_PORT_MASK 0xFFFF #define COMMON_PHY_SD_CTRL1_COMPHY_0_1_PORT_MASK 0xFF #define COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET 24 #define COMMON_PHY_SD_CTRL1_PCIE_X4_EN_MASK \ (0x1 << COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET) #define COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET 25 #define COMMON_PHY_SD_CTRL1_PCIE_X2_EN_MASK \ (0x1 << COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET) #define COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET 26 #define COMMON_PHY_SD_CTRL1_RXAUI1_MASK \ (0x1 << COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET) #define COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET 27 #define COMMON_PHY_SD_CTRL1_RXAUI0_MASK \ (0x1 << COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET) /* DFX register */ #define DFX_BASE (0x400000) #define DFX_DEV_GEN_CTRL12_REG (0x280) #define DFX_DEV_GEN_PCIE_CLK_SRC_MUX (0x3) #define DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET 7 #define DFX_DEV_GEN_PCIE_CLK_SRC_MASK \ (0x3 << DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET) /* SerDes IP registers */ #define SD_EXTERNAL_CONFIG0_REG 0 #define SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET 1 #define SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK \ (1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET) #define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET 3 #define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK \ (0xf << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET) #define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET 7 #define SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK \ (0xf << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET) #define SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET 11 #define SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK \ (1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET) #define SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET 12 #define SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK \ (1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET) #define SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET 14 #define SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK \ (1 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET) #define SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET 15 #define SD_EXTERNAL_CONFIG0_MEDIA_MODE_MASK \ (0x1 << SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET) #define SD_EXTERNAL_CONFIG1_REG 0x4 #define SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET 3 #define SD_EXTERNAL_CONFIG1_RESET_IN_MASK \ (0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET) #define SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET 4 #define SD_EXTERNAL_CONFIG1_RX_INIT_MASK \ (0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET) #define SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET 5 #define SD_EXTERNAL_CONFIG1_RESET_CORE_MASK \ (0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET) #define SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET 6 #define SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK \ (0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET) #define SD_EXTERNAL_CONFIG2_REG 0x8 #define SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET 4 #define SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK \ (0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET) #define SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET 7 #define SD_EXTERNAL_CONFIG2_SSC_ENABLE_MASK \ (0x1 << SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET) #define SD_EXTERNAL_STATUS_REG 0xc #define SD_EXTERNAL_STATUS_START_RX_TRAINING_OFFSET 7 #define SD_EXTERNAL_STATUS_START_RX_TRAINING_MASK \ (1 << SD_EXTERNAL_STATUS_START_RX_TRAINING_OFFSET) #define SD_EXTERNAL_STATUS0_REG 0x18 #define SD_EXTERNAL_STATUS0_PLL_TX_OFFSET 2 #define SD_EXTERNAL_STATUS0_PLL_TX_MASK \ (0x1 << SD_EXTERNAL_STATUS0_PLL_TX_OFFSET) #define SD_EXTERNAL_STATUS0_PLL_RX_OFFSET 3 #define SD_EXTERNAL_STATUS0_PLL_RX_MASK \ (0x1 << SD_EXTERNAL_STATUS0_PLL_RX_OFFSET) #define SD_EXTERNAL_STATUS0_RX_INIT_OFFSET 4 #define SD_EXTERNAL_STATUS0_RX_INIT_MASK \ (0x1 << SD_EXTERNAL_STATUS0_RX_INIT_OFFSET) #define SD_EXTERNAL_STATAUS1_REG 0x1c #define SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_COMP_OFFSET 0 #define SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_COMP_MASK \ (1 << SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_COMP_OFFSET) #define SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_FAILED_OFFSET 1 #define SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_FAILED_MASK \ (1 << SD_EXTERNAL_STATAUS1_REG_RX_TRAIN_FAILED_OFFSET) /* HPIPE registers */ #define HPIPE_PWR_PLL_REG 0x4 #define HPIPE_PWR_PLL_REF_FREQ_OFFSET 0 #define HPIPE_PWR_PLL_REF_FREQ_MASK \ (0x1f << HPIPE_PWR_PLL_REF_FREQ_OFFSET) #define HPIPE_PWR_PLL_PHY_MODE_OFFSET 5 #define HPIPE_PWR_PLL_PHY_MODE_MASK \ (0x7 << HPIPE_PWR_PLL_PHY_MODE_OFFSET) #define HPIPE_CAL_REG1_REG 0xc #define HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET 10 #define HPIPE_CAL_REG_1_EXT_TXIMP_MASK \ (0x1f << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET) #define HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET 15 #define HPIPE_CAL_REG_1_EXT_TXIMP_EN_MASK \ (0x1 << HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET) #define HPIPE_SQUELCH_FFE_SETTING_REG 0x18 #define HPIPE_SQUELCH_THRESH_IN_OFFSET 8 #define HPIPE_SQUELCH_THRESH_IN_MASK \ (0xf << HPIPE_SQUELCH_THRESH_IN_OFFSET) #define HPIPE_SQUELCH_DETECTED_OFFSET 14 #define HPIPE_SQUELCH_DETECTED_MASK \ (0x1 << HPIPE_SQUELCH_DETECTED_OFFSET) #define HPIPE_DFE_REG0 0x1c #define HPIPE_DFE_RES_FORCE_OFFSET 15 #define HPIPE_DFE_RES_FORCE_MASK \ (0x1 << HPIPE_DFE_RES_FORCE_OFFSET) #define HPIPE_DFE_F3_F5_REG 0x28 #define HPIPE_DFE_F3_F5_DFE_EN_OFFSET 14 #define HPIPE_DFE_F3_F5_DFE_EN_MASK \ (0x1 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET) #define HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET 15 #define HPIPE_DFE_F3_F5_DFE_CTRL_MASK \ (0x1 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET) #define HPIPE_ADAPTED_DFE_COEFFICIENT_1_REG 0x30 #define HPIPE_ADAPTED_DFE_RES_OFFSET 13 #define HPIPE_ADAPTED_DFE_RES_MASK \ (0x3 << HPIPE_ADAPTED_DFE_RES_OFFSET) #define HPIPE_G1_SET_0_REG 0x34 #define HPIPE_G1_SET_0_G1_TX_AMP_OFFSET 1 #define HPIPE_G1_SET_0_G1_TX_AMP_MASK \ (0x1f << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET) #define HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET 6 #define HPIPE_G1_SET_0_G1_TX_AMP_ADJ_MASK \ (0x1 << HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET) #define HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET 7 #define HPIPE_G1_SET_0_G1_TX_EMPH1_MASK \ (0xf << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET) #define HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET 11 #define HPIPE_G1_SET_0_G1_TX_EMPH1_EN_MASK \ (0x1 << HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET) #define HPIPE_G1_SET_1_REG 0x38 #define HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET 0 #define HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK \ (0x7 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET) #define HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET 3 #define HPIPE_G1_SET_1_G1_RX_SELMUPF_MASK \ (0x7 << HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET) #define HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET 6 #define HPIPE_G1_SET_1_G1_RX_SELMUFI_MASK \ (0x3 << HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET) #define HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET 8 #define HPIPE_G1_SET_1_G1_RX_SELMUFF_MASK \ (0x3 << HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET) #define HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET 10 #define HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK \ (0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET) #define HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET 11 #define HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_MASK \ (0x3 << HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET) #define HPIPE_G2_SET_0_REG 0x3c #define HPIPE_G2_SET_0_G2_TX_AMP_OFFSET 1 #define HPIPE_G2_SET_0_G2_TX_AMP_MASK \ (0x1f << HPIPE_G2_SET_0_G2_TX_AMP_OFFSET) #define HPIPE_G2_SET_0_G2_TX_AMP_ADJ_OFFSET 6 #define HPIPE_G2_SET_0_G2_TX_AMP_ADJ_MASK \ (0x1 << HPIPE_G2_SET_0_G2_TX_AMP_ADJ_OFFSET) #define HPIPE_G2_SET_0_G2_TX_EMPH1_OFFSET 7 #define HPIPE_G2_SET_0_G2_TX_EMPH1_MASK \ (0xf << HPIPE_G2_SET_0_G2_TX_EMPH1_OFFSET) #define HPIPE_G2_SET_0_G2_TX_EMPH1_EN_OFFSET 11 #define HPIPE_G2_SET_0_G2_TX_EMPH1_EN_MASK \ (0x1 << HPIPE_G2_SET_0_G2_TX_EMPH1_EN_OFFSET) #define HPIPE_G2_SET_1_REG 0x40 #define HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET 0 #define HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK \ (0x7 << HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET) #define HPIPE_G2_SET_1_G2_RX_SELMUPF_OFFSET 3 #define HPIPE_G2_SET_1_G2_RX_SELMUPF_MASK \ (0x7 << HPIPE_G2_SET_1_G2_RX_SELMUPF_OFFSET) #define HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET 6 #define HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK \ (0x3 << HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET) #define HPIPE_G2_SET_1_G2_RX_SELMUFF_OFFSET 8 #define HPIPE_G2_SET_1_G2_RX_SELMUFF_MASK \ (0x3 << HPIPE_G2_SET_1_G2_RX_SELMUFF_OFFSET) #define HPIPE_G2_SET_1_G2_RX_DFE_EN_OFFSET 10 #define HPIPE_G2_SET_1_G2_RX_DFE_EN_MASK \ (0x1 << HPIPE_G2_SET_1_G2_RX_DFE_EN_OFFSET) #define HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_OFFSET 11 #define HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_MASK \ (0x3 << HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_OFFSET) #define HPIPE_G3_SET_0_REG 0x44 #define HPIPE_G3_SET_0_G3_TX_AMP_OFFSET 1 #define HPIPE_G3_SET_0_G3_TX_AMP_MASK \ (0x1f << HPIPE_G3_SET_0_G3_TX_AMP_OFFSET) #define HPIPE_G3_SET_0_G3_TX_AMP_ADJ_OFFSET 6 #define HPIPE_G3_SET_0_G3_TX_AMP_ADJ_MASK \ (0x1 << HPIPE_G3_SET_0_G3_TX_AMP_ADJ_OFFSET) #define HPIPE_G3_SET_0_G3_TX_EMPH1_OFFSET 7 #define HPIPE_G3_SET_0_G3_TX_EMPH1_MASK \ (0xf << HPIPE_G3_SET_0_G3_TX_EMPH1_OFFSET) #define HPIPE_G3_SET_0_G3_TX_EMPH1_EN_OFFSET 11 #define HPIPE_G3_SET_0_G3_TX_EMPH1_EN_MASK \ (0x1 << HPIPE_G3_SET_0_G3_TX_EMPH1_EN_OFFSET) #define HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_OFFSET 12 #define HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_MASK \ (0x7 << HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_OFFSET) #define HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_OFFSET 15 #define HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_MASK \ (0x1 << HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_OFFSET) #define HPIPE_G3_SET_1_REG 0x48 #define HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET 0 #define HPIPE_G3_SET_1_G3_RX_SELMUPI_MASK \ (0x7 << HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET) #define HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET 3 #define HPIPE_G3_SET_1_G3_RX_SELMUPF_MASK \ (0x7 << HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET) #define HPIPE_G3_SET_1_G3_RX_SELMUFI_OFFSET 6 #define HPIPE_G3_SET_1_G3_RX_SELMUFI_MASK \ (0x3 << HPIPE_G3_SET_1_G3_RX_SELMUFI_OFFSET) #define HPIPE_G3_SET_1_G3_RX_SELMUFF_OFFSET 8 #define HPIPE_G3_SET_1_G3_RX_SELMUFF_MASK \ (0x3 << HPIPE_G3_SET_1_G3_RX_SELMUFF_OFFSET) #define HPIPE_G3_SET_1_G3_RX_DFE_EN_OFFSET 10 #define HPIPE_G3_SET_1_G3_RX_DFE_EN_MASK \ (0x1 << HPIPE_G3_SET_1_G3_RX_DFE_EN_OFFSET) #define HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_OFFSET 11 #define HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_MASK \ (0x3 << HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_OFFSET) #define HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET 13 #define HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_MASK \ (0x1 << HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET) #define HPIPE_PHY_TEST_CONTROL_REG 0x54 #define HPIPE_PHY_TEST_PATTERN_SEL_OFFSET 4 #define HPIPE_PHY_TEST_PATTERN_SEL_MASK \ (0xf << HPIPE_PHY_TEST_PATTERN_SEL_OFFSET) #define HPIPE_PHY_TEST_RESET_OFFSET 14 #define HPIPE_PHY_TEST_RESET_MASK \ (0x1 << HPIPE_PHY_TEST_RESET_OFFSET) #define HPIPE_PHY_TEST_EN_OFFSET 15 #define HPIPE_PHY_TEST_EN_MASK \ (0x1 << HPIPE_PHY_TEST_EN_OFFSET) #define HPIPE_PHY_TEST_DATA_REG 0x6c #define HPIPE_PHY_TEST_DATA_OFFSET 0 #define HPIPE_PHY_TEST_DATA_MASK \ (0xffff << HPIPE_PHY_TEST_DATA_OFFSET) #define HPIPE_PHY_TEST_PRBS_ERROR_COUNTER_1_REG 0x80 #define HPIPE_PHY_TEST_OOB_0_REGISTER 0x84 #define HPIPE_PHY_PT_OOB_EN_OFFSET 14 #define HPIPE_PHY_PT_OOB_EN_MASK \ (0x1 << HPIPE_PHY_PT_OOB_EN_OFFSET) #define HPIPE_PHY_TEST_PT_TESTMODE_OFFSET 12 #define HPIPE_PHY_TEST_PT_TESTMODE_MASK \ (0x3 << HPIPE_PHY_TEST_PT_TESTMODE_OFFSET) #define HPIPE_LOOPBACK_REG 0x8c #define HPIPE_LOOPBACK_SEL_OFFSET 1 #define HPIPE_LOOPBACK_SEL_MASK \ (0x7 << HPIPE_LOOPBACK_SEL_OFFSET) #define HPIPE_CDR_LOCK_OFFSET 7 #define HPIPE_CDR_LOCK_MASK \ (0x1 << HPIPE_CDR_LOCK_OFFSET) #define HPIPE_CDR_LOCK_DET_EN_OFFSET 8 #define HPIPE_CDR_LOCK_DET_EN_MASK \ (0x1 << HPIPE_CDR_LOCK_DET_EN_OFFSET) #define HPIPE_INTERFACE_REG 0x94 #define HPIPE_INTERFACE_GEN_MAX_OFFSET 10 #define HPIPE_INTERFACE_GEN_MAX_MASK \ (0x3 << HPIPE_INTERFACE_GEN_MAX_OFFSET) #define HPIPE_INTERFACE_DET_BYPASS_OFFSET 12 #define HPIPE_INTERFACE_DET_BYPASS_MASK \ (0x1 << HPIPE_INTERFACE_DET_BYPASS_OFFSET) #define HPIPE_INTERFACE_LINK_TRAIN_OFFSET 14 #define HPIPE_INTERFACE_LINK_TRAIN_MASK \ (0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET) #define HPIPE_G1_SET_2_REG 0xf4 #define HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET 0 #define HPIPE_G1_SET_2_G1_TX_EMPH0_MASK \ (0xf << HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET) #define HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET 4 #define HPIPE_G1_SET_2_G1_TX_EMPH0_EN_MASK \ (0x1 << HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET) #define HPIPE_G2_SET_2_REG 0xf8 #define HPIPE_G2_SET_2_G2_TX_EMPH0_OFFSET 0 #define HPIPE_G2_SET_2_G2_TX_EMPH0_MASK \ (0xf << HPIPE_G2_SET_2_G2_TX_EMPH0_OFFSET) #define HPIPE_G2_SET_2_G2_TX_EMPH0_EN_OFFSET 4 #define HPIPE_G2_SET_2_G2_TX_EMPH0_EN_MASK \ (0x1 << HPIPE_G2_SET_2_G2_TX_EMPH0_EN_OFFSET) #define HPIPE_G2_TX_SSC_AMP_OFFSET 9 #define HPIPE_G2_TX_SSC_AMP_MASK \ (0x7f << HPIPE_G2_TX_SSC_AMP_OFFSET) #define HPIPE_G3_SET_2_REG 0xfc #define HPIPE_G3_SET_2_G3_TX_EMPH0_OFFSET 0 #define HPIPE_G3_SET_2_G3_TX_EMPH0_MASK \ (0xf << HPIPE_G3_SET_2_G3_TX_EMPH0_OFFSET) #define HPIPE_G3_SET_2_G3_TX_EMPH0_EN_OFFSET 4 #define HPIPE_G3_SET_2_G3_TX_EMPH0_EN_MASK \ (0x1 << HPIPE_G3_SET_2_G3_TX_EMPH0_EN_OFFSET) #define HPIPE_G3_TX_SSC_AMP_OFFSET 9 #define HPIPE_G3_TX_SSC_AMP_MASK \ (0x7f << HPIPE_G3_TX_SSC_AMP_OFFSET) #define HPIPE_VDD_CAL_0_REG 0x108 #define HPIPE_CAL_VDD_CONT_MODE_OFFSET 15 #define HPIPE_CAL_VDD_CONT_MODE_MASK \ (0x1 << HPIPE_CAL_VDD_CONT_MODE_OFFSET) #define HPIPE_VDD_CAL_CTRL_REG 0x114 #define HPIPE_EXT_SELLV_RXSAMPL_OFFSET 5 #define HPIPE_EXT_SELLV_RXSAMPL_MASK \ (0x1f << HPIPE_EXT_SELLV_RXSAMPL_OFFSET) #define HPIPE_PCIE_REG0 0x120 #define HPIPE_PCIE_IDLE_SYNC_OFFSET 12 #define HPIPE_PCIE_IDLE_SYNC_MASK \ (0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET) #define HPIPE_PCIE_SEL_BITS_OFFSET 13 #define HPIPE_PCIE_SEL_BITS_MASK \ (0x3 << HPIPE_PCIE_SEL_BITS_OFFSET) #define HPIPE_LANE_ALIGN_REG 0x124 #define HPIPE_LANE_ALIGN_OFF_OFFSET 12 #define HPIPE_LANE_ALIGN_OFF_MASK \ (0x1 << HPIPE_LANE_ALIGN_OFF_OFFSET) #define HPIPE_MISC_REG 0x13C #define HPIPE_MISC_CLK100M_125M_OFFSET 4 #define HPIPE_MISC_CLK100M_125M_MASK \ (0x1 << HPIPE_MISC_CLK100M_125M_OFFSET) #define HPIPE_MISC_ICP_FORCE_OFFSET 5 #define HPIPE_MISC_ICP_FORCE_MASK \ (0x1 << HPIPE_MISC_ICP_FORCE_OFFSET) #define HPIPE_MISC_TXDCLK_2X_OFFSET 6 #define HPIPE_MISC_TXDCLK_2X_MASK \ (0x1 << HPIPE_MISC_TXDCLK_2X_OFFSET) #define HPIPE_MISC_CLK500_EN_OFFSET 7 #define HPIPE_MISC_CLK500_EN_MASK \ (0x1 << HPIPE_MISC_CLK500_EN_OFFSET) #define HPIPE_MISC_REFCLK_SEL_OFFSET 10 #define HPIPE_MISC_REFCLK_SEL_MASK \ (0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET) #define HPIPE_RX_CONTROL_1_REG 0x140 #define HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET 11 #define HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK \ (0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET) #define HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET 12 #define HPIPE_RX_CONTROL_1_CLK8T_EN_MASK \ (0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET) #define HPIPE_PWR_CTR_REG 0x148 #define HPIPE_PWR_CTR_RST_DFE_OFFSET 0 #define HPIPE_PWR_CTR_RST_DFE_MASK \ (0x1 << HPIPE_PWR_CTR_RST_DFE_OFFSET) #define HPIPE_PWR_CTR_SFT_RST_OFFSET 10 #define HPIPE_PWR_CTR_SFT_RST_MASK \ (0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET) #define HPIPE_SPD_DIV_FORCE_REG 0x154 #define HPIPE_TXDIGCK_DIV_FORCE_OFFSET 7 #define HPIPE_TXDIGCK_DIV_FORCE_MASK \ (0x1 << HPIPE_TXDIGCK_DIV_FORCE_OFFSET) #define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET 8 #define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_MASK \ (0x3 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET) #define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET 10 #define HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_MASK \ (0x1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET) #define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET 13 #define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_MASK \ (0x3 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET) #define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET 15 #define HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_MASK \ (0x1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET) /* HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIBRATION_CTRL_REG */ #define HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG 0x168 #define HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET 15 #define HPIPE_CAL_RXCLKALIGN_90_EXT_EN_MASK \ (0x1 << HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET) #define HPIPE_CAL_OS_PH_EXT_OFFSET 8 #define HPIPE_CAL_OS_PH_EXT_MASK \ (0x7f << HPIPE_CAL_OS_PH_EXT_OFFSET) #define HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG 0x16C #define HPIPE_RX_SAMPLER_OS_GAIN_OFFSET 6 #define HPIPE_RX_SAMPLER_OS_GAIN_MASK \ (0x3 << HPIPE_RX_SAMPLER_OS_GAIN_OFFSET) #define HPIPE_SMAPLER_OFFSET 12 #define HPIPE_SMAPLER_MASK \ (0x1 << HPIPE_SMAPLER_OFFSET) #define HPIPE_TX_REG1_REG 0x174 #define HPIPE_TX_REG1_TX_EMPH_RES_OFFSET 5 #define HPIPE_TX_REG1_TX_EMPH_RES_MASK \ (0x3 << HPIPE_TX_REG1_TX_EMPH_RES_OFFSET) #define HPIPE_TX_REG1_SLC_EN_OFFSET 10 #define HPIPE_TX_REG1_SLC_EN_MASK \ (0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET) #define HPIPE_PWR_CTR_DTL_REG 0x184 #define HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET 0 #define HPIPE_PWR_CTR_DTL_SQ_DET_EN_MASK \ (0x1 << HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET) #define HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET 1 #define HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_MASK \ (0x1 << HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET) #define HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET 2 #define HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK \ (0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET) #define HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET 4 #define HPIPE_PWR_CTR_DTL_CLAMPING_SEL_MASK \ (0x7 << HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET) #define HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET 10 #define HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_MASK \ (0x1 << HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET) #define HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET 12 #define HPIPE_PWR_CTR_DTL_CLK_MODE_MASK \ (0x3 << HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET) #define HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET 14 #define HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_MASK \ (1 << HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET) #define HPIPE_PHASE_CONTROL_REG 0x188 #define HPIPE_OS_PH_OFFSET_OFFSET 0 #define HPIPE_OS_PH_OFFSET_MASK \ (0x7f << HPIPE_OS_PH_OFFSET_OFFSET) #define HPIPE_OS_PH_OFFSET_FORCE_OFFSET 7 #define HPIPE_OS_PH_OFFSET_FORCE_MASK \ (0x1 << HPIPE_OS_PH_OFFSET_FORCE_OFFSET) #define HPIPE_OS_PH_VALID_OFFSET 8 #define HPIPE_OS_PH_VALID_MASK \ (0x1 << HPIPE_OS_PH_VALID_OFFSET) #define HPIPE_DATA_PHASE_OFF_CTRL_REG 0x1A0 #define HPIPE_DATA_PHASE_ADAPTED_OS_PH_OFFSET 9 #define HPIPE_DATA_PHASE_ADAPTED_OS_PH_MASK \ (0x7f << HPIPE_DATA_PHASE_ADAPTED_OS_PH_OFFSET) #define HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG 0x1A4 #define HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_OFFSET 12 #define HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_MASK \ (0x3 << HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_OFFSET) #define HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_OFFSET 8 #define HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_MASK \ (0xf << HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_OFFSET) #define HPIPE_SQ_GLITCH_FILTER_CTRL 0x1c8 #define HPIPE_SQ_DEGLITCH_WIDTH_P_OFFSET 0 #define HPIPE_SQ_DEGLITCH_WIDTH_P_MASK \ (0xf << HPIPE_SQ_DEGLITCH_WIDTH_P_OFFSET) #define HPIPE_SQ_DEGLITCH_WIDTH_N_OFFSET 4 #define HPIPE_SQ_DEGLITCH_WIDTH_N_MASK \ (0xf << HPIPE_SQ_DEGLITCH_WIDTH_N_OFFSET) #define HPIPE_SQ_DEGLITCH_EN_OFFSET 8 #define HPIPE_SQ_DEGLITCH_EN_MASK \ (0x1 << HPIPE_SQ_DEGLITCH_EN_OFFSET) #define HPIPE_FRAME_DETECT_CTRL_0_REG 0x214 #define HPIPE_TRAIN_PAT_NUM_OFFSET 0x7 #define HPIPE_TRAIN_PAT_NUM_MASK \ (0x1FF << HPIPE_TRAIN_PAT_NUM_OFFSET) #define HPIPE_FRAME_DETECT_CTRL_3_REG 0x220 #define HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET 12 #define HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK \ (0x1 << HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET) #define HPIPE_DME_REG 0x228 #define HPIPE_DME_ETHERNET_MODE_OFFSET 7 #define HPIPE_DME_ETHERNET_MODE_MASK \ (0x1 << HPIPE_DME_ETHERNET_MODE_OFFSET) #define HPIPE_TRX_TRAIN_CTRL_0_REG 0x22c #define HPIPE_TRX_TX_F0T_EO_BASED_OFFSET 14 #define HPIPE_TRX_TX_F0T_EO_BASED_MASK \ (1 << HPIPE_TRX_TX_F0T_EO_BASED_OFFSET) #define HPIPE_TRX_UPDATE_THEN_HOLD_OFFSET 6 #define HPIPE_TRX_UPDATE_THEN_HOLD_MASK \ (1 << HPIPE_TRX_UPDATE_THEN_HOLD_OFFSET) #define HPIPE_TRX_TX_CTRL_CLK_EN_OFFSET 5 #define HPIPE_TRX_TX_CTRL_CLK_EN_MASK \ (1 << HPIPE_TRX_TX_CTRL_CLK_EN_OFFSET) #define HPIPE_TRX_RX_ANA_IF_CLK_ENE_OFFSET 4 #define HPIPE_TRX_RX_ANA_IF_CLK_ENE_MASK \ (1 << HPIPE_TRX_RX_ANA_IF_CLK_ENE_OFFSET) #define HPIPE_TRX_TX_TRAIN_EN_OFFSET 1 #define HPIPE_TRX_TX_TRAIN_EN_MASK \ (1 << HPIPE_TRX_TX_TRAIN_EN_OFFSET) #define HPIPE_TRX_RX_TRAIN_EN_OFFSET 0 #define HPIPE_TRX_RX_TRAIN_EN_MASK \ (1 << HPIPE_TRX_RX_TRAIN_EN_OFFSET) #define HPIPE_TX_TRAIN_CTRL_0_REG 0x268 #define HPIPE_TX_TRAIN_P2P_HOLD_OFFSET 15 #define HPIPE_TX_TRAIN_P2P_HOLD_MASK \ (0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET) #define HPIPE_TX_TRAIN_CTRL_REG 0x26C #define HPIPE_TX_TRAIN_CTRL_G1_OFFSET 0 #define HPIPE_TX_TRAIN_CTRL_G1_MASK \ (0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET) #define HPIPE_TX_TRAIN_CTRL_GN1_OFFSET 1 #define HPIPE_TX_TRAIN_CTRL_GN1_MASK \ (0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET) #define HPIPE_TX_TRAIN_CTRL_G0_OFFSET 2 #define HPIPE_TX_TRAIN_CTRL_G0_MASK \ (0x1 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET) #define HPIPE_TX_TRAIN_CTRL_4_REG 0x278 #define HPIPE_TRX_TRAIN_TIMER_OFFSET 0 #define HPIPE_TRX_TRAIN_TIMER_MASK \ (0x3FF << HPIPE_TRX_TRAIN_TIMER_OFFSET) #define HPIPE_TX_TRAIN_CTRL_5_REG 0x2A4 #define HPIPE_RX_TRAIN_TIMER_OFFSET 0 #define HPIPE_RX_TRAIN_TIMER_MASK \ (0x3ff << HPIPE_RX_TRAIN_TIMER_OFFSET) #define HPIPE_TX_TRAIN_START_SQ_EN_OFFSET 11 #define HPIPE_TX_TRAIN_START_SQ_EN_MASK \ (0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET) #define HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET 12 #define HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK \ (0x1 << HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET) #define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET 13 #define HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK \ (0x1 << HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET) #define HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET 14 #define HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK \ (0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET) #define HPIPE_INTERRUPT_1_REGISTER 0x2AC #define HPIPE_TRX_TRAIN_FAILED_OFFSET 6 #define HPIPE_TRX_TRAIN_FAILED_MASK \ (1 << HPIPE_TRX_TRAIN_FAILED_OFFSET) #define HPIPE_TRX_TRAIN_TIME_OUT_INT_OFFSET 5 #define HPIPE_TRX_TRAIN_TIME_OUT_INT_MASK \ (1 << HPIPE_TRX_TRAIN_TIME_OUT_INT_OFFSET) #define HPIPE_INTERRUPT_TRX_TRAIN_DONE_OFFSET 4 #define HPIPE_INTERRUPT_TRX_TRAIN_DONE_MASK \ (1 << HPIPE_INTERRUPT_TRX_TRAIN_DONE_OFFSET) #define HPIPE_INTERRUPT_DFE_DONE_INT_OFFSET 3 #define HPIPE_INTERRUPT_DFE_DONE_INT_MASK \ (1 << HPIPE_INTERRUPT_DFE_DONE_INT_OFFSET) #define HPIPE_INTERRUPT_RX_TRAIN_COMPLETE_INT_OFFSET 1 #define HPIPE_INTERRUPT_RX_TRAIN_COMPLETE_INT_MASK \ (1 << HPIPE_INTERRUPT_RX_TRAIN_COMPLETE_INT_OFFSET) #define HPIPE_TX_TRAIN_REG 0x31C #define HPIPE_TX_TRAIN_CHK_INIT_OFFSET 4 #define HPIPE_TX_TRAIN_CHK_INIT_MASK \ (0x1 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET) #define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET 7 #define HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK \ (0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET) #define HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET 8 #define HPIPE_TX_TRAIN_16BIT_AUTO_EN_MASK \ (0x1 << HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET) #define HPIPE_TX_TRAIN_PAT_SEL_OFFSET 9 #define HPIPE_TX_TRAIN_PAT_SEL_MASK \ (0x1 << HPIPE_TX_TRAIN_PAT_SEL_OFFSET) #define HPIPE_SAVED_DFE_VALUES_REG 0x328 #define HPIPE_SAVED_DFE_VALUES_SAV_F0D_OFFSET 10 #define HPIPE_SAVED_DFE_VALUES_SAV_F0D_MASK \ (0x3f << HPIPE_SAVED_DFE_VALUES_SAV_F0D_OFFSET) #define HPIPE_CDR_CONTROL_REG 0x418 #define HPIPE_CDR_RX_MAX_DFE_ADAPT_0_OFFSET 14 #define HPIPE_CDR_RX_MAX_DFE_ADAPT_0_MASK \ (0x3 << HPIPE_CDR_RX_MAX_DFE_ADAPT_0_OFFSET) #define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET 12 #define HPIPE_CDR_RX_MAX_DFE_ADAPT_1_MASK \ (0x3 << HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET) #define HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET 9 #define HPIPE_CDR_MAX_DFE_ADAPT_0_MASK \ (0x7 << HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET) #define HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET 6 #define HPIPE_CDR_MAX_DFE_ADAPT_1_MASK \ (0x7 << HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET) #define HPIPE_TX_TRAIN_CTRL_11_REG 0x438 #define HPIPE_TX_STATUS_CHECK_MODE_OFFSET 6 #define HPIPE_TX_TX_STATUS_CHECK_MODE_MASK \ (0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET) #define HPIPE_TX_NUM_OF_PRESET_OFFSET 10 #define HPIPE_TX_NUM_OF_PRESET_MASK \ (0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET) #define HPIPE_TX_SWEEP_PRESET_EN_OFFSET 15 #define HPIPE_TX_SWEEP_PRESET_EN_MASK \ (0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET) #define HPIPE_G1_SETTINGS_3_REG 0x440 #define HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET 0 #define HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK \ (0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET) #define HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET 4 #define HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK \ (0x7 << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET) #define HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET 7 #define HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK \ (0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET) #define HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET 9 #define HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_MASK \ (0x1 << HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET) #define HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_OFFSET 12 #define HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_MASK \ (0x3 << HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_OFFSET) #define HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_OFFSET 14 #define HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_MASK \ (0x3 << HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_OFFSET) #define HPIPE_G1_SETTINGS_4_REG 0x444 #define HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET 8 #define HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK \ (0x3 << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET) #define HPIPE_G2_SETTINGS_4_REG 0x44c #define HPIPE_G2_DFE_RES_OFFSET 8 #define HPIPE_G2_DFE_RES_MASK \ (0x3 << HPIPE_G2_DFE_RES_OFFSET) #define HPIPE_G3_SETTING_3_REG 0x450 #define HPIPE_G3_FFE_CAP_SEL_OFFSET 0 #define HPIPE_G3_FFE_CAP_SEL_MASK \ (0xf << HPIPE_G3_FFE_CAP_SEL_OFFSET) #define HPIPE_G3_FFE_RES_SEL_OFFSET 4 #define HPIPE_G3_FFE_RES_SEL_MASK \ (0x7 << HPIPE_G3_FFE_RES_SEL_OFFSET) #define HPIPE_G3_FFE_SETTING_FORCE_OFFSET 7 #define HPIPE_G3_FFE_SETTING_FORCE_MASK \ (0x1 << HPIPE_G3_FFE_SETTING_FORCE_OFFSET) #define HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET 12 #define HPIPE_G3_FFE_DEG_RES_LEVEL_MASK \ (0x3 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET) #define HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET 14 #define HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK \ (0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET) #define HPIPE_G3_SETTING_4_REG 0x454 #define HPIPE_G3_DFE_RES_OFFSET 8 #define HPIPE_G3_DFE_RES_MASK (0x3 << HPIPE_G3_DFE_RES_OFFSET) #define HPIPE_TX_PRESET_INDEX_REG 0x468 #define HPIPE_TX_PRESET_INDEX_OFFSET 0 #define HPIPE_TX_PRESET_INDEX_MASK \ (0xf << HPIPE_TX_PRESET_INDEX_OFFSET) #define HPIPE_DFE_CONTROL_REG 0x470 #define HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET 14 #define HPIPE_DFE_TX_MAX_DFE_ADAPT_MASK \ (0x3 << HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET) #define HPIPE_DFE_CTRL_28_REG 0x49C #define HPIPE_DFE_CTRL_28_PIPE4_OFFSET 7 #define HPIPE_DFE_CTRL_28_PIPE4_MASK \ (0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET) #define HPIPE_G1_SETTING_5_REG 0x538 #define HPIPE_G1_SETTING_5_G1_ICP_OFFSET 0 #define HPIPE_G1_SETTING_5_G1_ICP_MASK \ (0xf << HPIPE_G1_SETTING_5_G1_ICP_OFFSET) #define HPIPE_G3_SETTING_5_REG 0x548 #define HPIPE_G3_SETTING_5_G3_ICP_OFFSET 0 #define HPIPE_G3_SETTING_5_G3_ICP_MASK \ (0xf << HPIPE_G3_SETTING_5_G3_ICP_OFFSET) #define HPIPE_LANE_CONFIG0_REG 0x600 #define HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET 0 #define HPIPE_LANE_CONFIG0_TXDEEMPH0_MASK \ (0x1 << HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET) #define HPIPE_LANE_STATUS1_REG 0x60C #define HPIPE_LANE_STATUS1_PCLK_EN_OFFSET 0 #define HPIPE_LANE_STATUS1_PCLK_EN_MASK \ (0x1 << HPIPE_LANE_STATUS1_PCLK_EN_OFFSET) #define HPIPE_LANE_CFG4_REG 0x620 #define HPIPE_LANE_CFG4_DFE_CTRL_OFFSET 0 #define HPIPE_LANE_CFG4_DFE_CTRL_MASK \ (0x7 << HPIPE_LANE_CFG4_DFE_CTRL_OFFSET) #define HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET 3 #define HPIPE_LANE_CFG4_DFE_EN_SEL_MASK \ (0x1 << HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET) #define HPIPE_LANE_CFG4_DFE_OVER_OFFSET 6 #define HPIPE_LANE_CFG4_DFE_OVER_MASK \ (0x1 << HPIPE_LANE_CFG4_DFE_OVER_OFFSET) #define HPIPE_LANE_CFG4_SSC_CTRL_OFFSET 7 #define HPIPE_LANE_CFG4_SSC_CTRL_MASK \ (0x1 << HPIPE_LANE_CFG4_SSC_CTRL_OFFSET) #define HPIPE_LANE_EQ_REMOTE_SETTING_REG 0x6f8 #define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET 0 #define HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_MASK \ (0x1 << HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET) #define HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET 1 #define HPIPE_LANE_CFG_FOM_ONLY_MODE_MASK \ (0x1 << HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET) #define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET 2 #define HPIPE_LANE_CFG_FOM_PRESET_VECTOR_MASK \ (0xf << HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET) #define HPIPE_LANE_EQU_CONFIG_0_REG 0x69C #define HPIPE_CFG_PHY_RC_EP_OFFSET 12 #define HPIPE_CFG_PHY_RC_EP_MASK \ (0x1 << HPIPE_CFG_PHY_RC_EP_OFFSET) #define HPIPE_LANE_EQ_CFG1_REG 0x6a0 #define HPIPE_CFG_UPDATE_POLARITY_OFFSET 12 #define HPIPE_CFG_UPDATE_POLARITY_MASK \ (0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET) #define HPIPE_LANE_EQ_CFG2_REG 0x6a4 #define HPIPE_CFG_EQ_BUNDLE_DIS_OFFSET 14 #define HPIPE_CFG_EQ_BUNDLE_DIS_MASK \ (0x1 << HPIPE_CFG_EQ_BUNDLE_DIS_OFFSET) #define HPIPE_RST_CLK_CTRL_REG 0x704 #define HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET 0 #define HPIPE_RST_CLK_CTRL_PIPE_RST_MASK \ (0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET) #define HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET 2 #define HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK \ (0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET) #define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET 3 #define HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK \ (0x1 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET) #define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET 9 #define HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK \ (0x1 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET) #define HPIPE_TST_MODE_CTRL_REG 0x708 #define HPIPE_TST_MODE_CTRL_MODE_MARGIN_OFFSET 2 #define HPIPE_TST_MODE_CTRL_MODE_MARGIN_MASK \ (0x1 << HPIPE_TST_MODE_CTRL_MODE_MARGIN_OFFSET) #define HPIPE_CLK_SRC_LO_REG 0x70c #define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET 1 #define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_MASK \ (0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET) #define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET 2 #define HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_MASK \ (0x3 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET) #define HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET 5 #define HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK \ (0x7 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET) #define HPIPE_CLK_SRC_HI_REG 0x710 #define HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET 0 #define HPIPE_CLK_SRC_HI_LANE_STRT_MASK \ (0x1 << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET) #define HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET 1 #define HPIPE_CLK_SRC_HI_LANE_BREAK_MASK \ (0x1 << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET) #define HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET 2 #define HPIPE_CLK_SRC_HI_LANE_MASTER_MASK \ (0x1 << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET) #define HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET 7 #define HPIPE_CLK_SRC_HI_MODE_PIPE_MASK \ (0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET) #define HPIPE_GLOBAL_MISC_CTRL 0x718 #define HPIPE_GLOBAL_PM_CTRL 0x740 #define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET 0 #define HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK \ (0xFF << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET) /* General defines */ #define PLL_LOCK_TIMEOUT 15000 #endif /* COMPHY_CP110_H */ trusted-firmware-a-2.2/drivers/marvell/comphy/phy-comphy-3700.c000066400000000000000000000755421355360272700243750ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #include "phy-comphy-3700.h" #include "phy-comphy-common.h" /* * COMPHY_INDIRECT_REG points to ahci address space but the ahci region used in * Linux is up to 0x178 so none will access it from Linux in runtime * concurrently. */ #define COMPHY_INDIRECT_REG (MVEBU_REGS_BASE + 0xE0178) /* The USB3_GBE1_PHY range is above USB3 registers used in dts */ #define USB3_GBE1_PHY (MVEBU_REGS_BASE + 0x5C000) #define COMPHY_SD_ADDR (MVEBU_REGS_BASE + 0x1F000) /* * Below address in used only for reading, therefore no problem with concurrent * Linux access. */ #define MVEBU_TEST_PIN_LATCH_N (MVEBU_NB_GPIO_REG_BASE + 0x8) #define MVEBU_XTAL_MODE_MASK BIT(9) #define MVEBU_XTAL_MODE_OFFS 9 #define MVEBU_XTAL_CLOCK_25MHZ 0x0 struct sgmii_phy_init_data_fix { uint16_t addr; uint16_t value; }; /* Changes to 40M1G25 mode data required for running 40M3G125 init mode */ static struct sgmii_phy_init_data_fix sgmii_phy_init_fix[] = { {0x005, 0x07CC}, {0x015, 0x0000}, {0x01B, 0x0000}, {0x01D, 0x0000}, {0x01E, 0x0000}, {0x01F, 0x0000}, {0x020, 0x0000}, {0x021, 0x0030}, {0x026, 0x0888}, {0x04D, 0x0152}, {0x04F, 0xA020}, {0x050, 0x07CC}, {0x053, 0xE9CA}, {0x055, 0xBD97}, {0x071, 0x3015}, {0x076, 0x03AA}, {0x07C, 0x0FDF}, {0x0C2, 0x3030}, {0x0C3, 0x8000}, {0x0E2, 0x5550}, {0x0E3, 0x12A4}, {0x0E4, 0x7D00}, {0x0E6, 0x0C83}, {0x101, 0xFCC0}, {0x104, 0x0C10} }; /* 40M1G25 mode init data */ static uint16_t sgmii_phy_init[512] = { /* 0 1 2 3 4 5 6 7 */ /*-----------------------------------------------------------*/ /* 8 9 A B C D E F */ 0x3110, 0xFD83, 0x6430, 0x412F, 0x82C0, 0x06FA, 0x4500, 0x6D26, /* 00 */ 0xAFC0, 0x8000, 0xC000, 0x0000, 0x2000, 0x49CC, 0x0BC9, 0x2A52, /* 08 */ 0x0BD2, 0x0CDE, 0x13D2, 0x0CE8, 0x1149, 0x10E0, 0x0000, 0x0000, /* 10 */ 0x0000, 0x0000, 0x0000, 0x0001, 0x0000, 0x4134, 0x0D2D, 0xFFFF, /* 18 */ 0xFFE0, 0x4030, 0x1016, 0x0030, 0x0000, 0x0800, 0x0866, 0x0000, /* 20 */ 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, /* 28 */ 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* 30 */ 0x0000, 0x0000, 0x000F, 0x6A62, 0x1988, 0x3100, 0x3100, 0x3100, /* 38 */ 0x3100, 0xA708, 0x2430, 0x0830, 0x1030, 0x4610, 0xFF00, 0xFF00, /* 40 */ 0x0060, 0x1000, 0x0400, 0x0040, 0x00F0, 0x0155, 0x1100, 0xA02A, /* 48 */ 0x06FA, 0x0080, 0xB008, 0xE3ED, 0x5002, 0xB592, 0x7A80, 0x0001, /* 50 */ 0x020A, 0x8820, 0x6014, 0x8054, 0xACAA, 0xFC88, 0x2A02, 0x45CF, /* 58 */ 0x000F, 0x1817, 0x2860, 0x064F, 0x0000, 0x0204, 0x1800, 0x6000, /* 60 */ 0x810F, 0x4F23, 0x4000, 0x4498, 0x0850, 0x0000, 0x000E, 0x1002, /* 68 */ 0x9D3A, 0x3009, 0xD066, 0x0491, 0x0001, 0x6AB0, 0x0399, 0x3780, /* 70 */ 0x0040, 0x5AC0, 0x4A80, 0x0000, 0x01DF, 0x0000, 0x0007, 0x0000, /* 78 */ 0x2D54, 0x00A1, 0x4000, 0x0100, 0xA20A, 0x0000, 0x0000, 0x0000, /* 80 */ 0x0000, 0x0000, 0x0000, 0x7400, 0x0E81, 0x1000, 0x1242, 0x0210, /* 88 */ 0x80DF, 0x0F1F, 0x2F3F, 0x4F5F, 0x6F7F, 0x0F1F, 0x2F3F, 0x4F5F, /* 90 */ 0x6F7F, 0x4BAD, 0x0000, 0x0000, 0x0800, 0x0000, 0x2400, 0xB651, /* 98 */ 0xC9E0, 0x4247, 0x0A24, 0x0000, 0xAF19, 0x1004, 0x0000, 0x0000, /* A0 */ 0x0000, 0x0013, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* A8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* B0 */ 0x0000, 0x0000, 0x0000, 0x0060, 0x0000, 0x0000, 0x0000, 0x0000, /* B8 */ 0x0000, 0x0000, 0x3010, 0xFA00, 0x0000, 0x0000, 0x0000, 0x0003, /* C0 */ 0x1618, 0x8200, 0x8000, 0x0400, 0x050F, 0x0000, 0x0000, 0x0000, /* C8 */ 0x4C93, 0x0000, 0x1000, 0x1120, 0x0010, 0x1242, 0x1242, 0x1E00, /* D0 */ 0x0000, 0x0000, 0x0000, 0x00F8, 0x0000, 0x0041, 0x0800, 0x0000, /* D8 */ 0x82A0, 0x572E, 0x2490, 0x14A9, 0x4E00, 0x0000, 0x0803, 0x0541, /* E0 */ 0x0C15, 0x0000, 0x0000, 0x0400, 0x2626, 0x0000, 0x0000, 0x4200, /* E8 */ 0x0000, 0xAA55, 0x1020, 0x0000, 0x0000, 0x5010, 0x0000, 0x0000, /* F0 */ 0x0000, 0x0000, 0x5000, 0x0000, 0x0000, 0x0000, 0x02F2, 0x0000, /* F8 */ 0x101F, 0xFDC0, 0x4000, 0x8010, 0x0110, 0x0006, 0x0000, 0x0000, /*100 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*108 */ 0x04CF, 0x0000, 0x04CF, 0x0000, 0x04CF, 0x0000, 0x04C6, 0x0000, /*110 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*118 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*120 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*128 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*130 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*138 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*140 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*148 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*150 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*158 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*160 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*168 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*170 */ 0x0000, 0x0000, 0x0000, 0x00F0, 0x08A2, 0x3112, 0x0A14, 0x0000, /*178 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*180 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*188 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*190 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*198 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1A0 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1A8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1B0 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1B8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1C0 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1C8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1D0 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1D8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1E0 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1E8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /*1F0 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 /*1F8 */ }; /* returns reference clock in MHz (25 or 40) */ static uint32_t get_ref_clk(void) { uint32_t val; val = (mmio_read_32(MVEBU_TEST_PIN_LATCH_N) & MVEBU_XTAL_MODE_MASK) >> MVEBU_XTAL_MODE_OFFS; if (val == MVEBU_XTAL_CLOCK_25MHZ) return 25; else return 40; } /* PHY selector configures with corresponding modes */ static void mvebu_a3700_comphy_set_phy_selector(uint8_t comphy_index, uint32_t comphy_mode) { uint32_t reg; int mode = COMPHY_GET_MODE(comphy_mode); reg = mmio_read_32(MVEBU_COMPHY_REG_BASE + COMPHY_SELECTOR_PHY_REG); switch (mode) { case (COMPHY_SATA_MODE): /* SATA must be in Lane2 */ if (comphy_index == COMPHY_LANE2) reg &= ~COMPHY_SELECTOR_USB3_PHY_SEL_BIT; else goto error; break; case (COMPHY_SGMII_MODE): case (COMPHY_HS_SGMII_MODE): if (comphy_index == COMPHY_LANE0) reg &= ~COMPHY_SELECTOR_USB3_GBE1_SEL_BIT; else if (comphy_index == COMPHY_LANE1) reg &= ~COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT; else goto error; break; case (COMPHY_USB3H_MODE): case (COMPHY_USB3D_MODE): case (COMPHY_USB3_MODE): if (comphy_index == COMPHY_LANE2) reg |= COMPHY_SELECTOR_USB3_PHY_SEL_BIT; else if (comphy_index == COMPHY_LANE0) reg |= COMPHY_SELECTOR_USB3_GBE1_SEL_BIT; else goto error; break; case (COMPHY_PCIE_MODE): /* PCIE must be in Lane1 */ if (comphy_index == COMPHY_LANE1) reg |= COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT; else goto error; break; default: goto error; } mmio_write_32(MVEBU_COMPHY_REG_BASE + COMPHY_SELECTOR_PHY_REG, reg); return; error: ERROR("COMPHY[%d] mode[%d] is invalid\n", comphy_index, mode); } /* It is only used for SATA and USB3 on comphy lane2. */ static void comphy_set_indirect(uintptr_t addr, uint32_t offset, uint16_t data, uint16_t mask, int mode) { /* * When Lane 2 PHY is for USB3, access the PHY registers * through indirect Address and Data registers: * INDIR_ACC_PHY_ADDR (RD00E0178h [31:0]), * INDIR_ACC_PHY_DATA (RD00E017Ch [31:0]), * within the SATA Host Controller registers, Lane 2 base register * offset is 0x200 */ if (mode == COMPHY_UNUSED) return; if (mode == COMPHY_SATA_MODE) mmio_write_32(addr + COMPHY_LANE2_INDIR_ADDR_OFFSET, offset); else mmio_write_32(addr + COMPHY_LANE2_INDIR_ADDR_OFFSET, offset + USB3PHY_LANE2_REG_BASE_OFFSET); reg_set(addr + COMPHY_LANE2_INDIR_DATA_OFFSET, data, mask); } /* It is only used USB3 direct access not on comphy lane2. */ static void comphy_usb3_set_direct(uintptr_t addr, uint32_t reg_offset, uint16_t data, uint16_t mask, int mode) { reg_set16((reg_offset * PHY_SHFT(USB3) + addr), data, mask); } static void comphy_sgmii_phy_init(uint32_t comphy_index, uint32_t mode, uintptr_t sd_ip_addr) { const int fix_arr_sz = ARRAY_SIZE(sgmii_phy_init_fix); int addr, fix_idx; uint16_t val; fix_idx = 0; for (addr = 0; addr < 512; addr++) { /* * All PHY register values are defined in full for 3.125Gbps * SERDES speed. The values required for 1.25 Gbps are almost * the same and only few registers should be "fixed" in * comparison to 3.125 Gbps values. These register values are * stored in "sgmii_phy_init_fix" array. */ if ((mode != COMPHY_SGMII_MODE) && (sgmii_phy_init_fix[fix_idx].addr == addr)) { /* Use new value */ val = sgmii_phy_init_fix[fix_idx].value; if (fix_idx < fix_arr_sz) fix_idx++; } else { val = sgmii_phy_init[addr]; } reg_set16(SGMIIPHY_ADDR(addr, sd_ip_addr), val, 0xFFFF); } } static int mvebu_a3700_comphy_sata_power_on(uint8_t comphy_index, uint32_t comphy_mode) { int ret = 0; uint32_t offset, data = 0, ref_clk; uintptr_t comphy_indir_regs = COMPHY_INDIRECT_REG; int mode = COMPHY_GET_MODE(comphy_mode); int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode); debug_enter(); /* Configure phy selector for SATA */ mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode); /* Clear phy isolation mode to make it work in normal mode */ offset = COMPHY_ISOLATION_CTRL_REG + SATAPHY_LANE2_REG_BASE_OFFSET; comphy_set_indirect(comphy_indir_regs, offset, 0, PHY_ISOLATE_MODE, mode); /* 0. Check the Polarity invert bits */ if (invert & COMPHY_POLARITY_TXD_INVERT) data |= TXD_INVERT_BIT; if (invert & COMPHY_POLARITY_RXD_INVERT) data |= RXD_INVERT_BIT; offset = COMPHY_SYNC_PATTERN_REG + SATAPHY_LANE2_REG_BASE_OFFSET; comphy_set_indirect(comphy_indir_regs, offset, data, TXD_INVERT_BIT | RXD_INVERT_BIT, mode); /* 1. Select 40-bit data width width */ offset = COMPHY_LOOPBACK_REG0 + SATAPHY_LANE2_REG_BASE_OFFSET; comphy_set_indirect(comphy_indir_regs, offset, DATA_WIDTH_40BIT, SEL_DATA_WIDTH_MASK, mode); /* 2. Select reference clock(25M) and PHY mode (SATA) */ offset = COMPHY_POWER_PLL_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET; if (get_ref_clk() == 40) ref_clk = REF_CLOCK_SPEED_40M; else ref_clk = REF_CLOCK_SPEED_25M; comphy_set_indirect(comphy_indir_regs, offset, ref_clk | PHY_MODE_SATA, REF_FREF_SEL_MASK | PHY_MODE_MASK, mode); /* 3. Use maximum PLL rate (no power save) */ offset = COMPHY_KVCO_CAL_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET; comphy_set_indirect(comphy_indir_regs, offset, USE_MAX_PLL_RATE_BIT, USE_MAX_PLL_RATE_BIT, mode); /* 4. Reset reserved bit */ comphy_set_indirect(comphy_indir_regs, COMPHY_RESERVED_REG, 0, PHYCTRL_FRM_PIN_BIT, mode); /* 5. Set vendor-specific configuration (It is done in sata driver) */ /* XXX: in U-Boot below sequence was executed in this place, in Linux * not. Now it is done only in U-Boot before this comphy * initialization - tests shows that it works ok, but in case of any * future problem it is left for reference. * reg_set(MVEBU_REGS_BASE + 0xe00a0, 0, 0xffffffff); * reg_set(MVEBU_REGS_BASE + 0xe00a4, BIT(6), BIT(6)); */ /* Wait for > 55 us to allow PLL be enabled */ udelay(PLL_SET_DELAY_US); /* Polling status */ mmio_write_32(comphy_indir_regs + COMPHY_LANE2_INDIR_ADDR_OFFSET, COMPHY_LOOPBACK_REG0 + SATAPHY_LANE2_REG_BASE_OFFSET); ret = polling_with_timeout(comphy_indir_regs + COMPHY_LANE2_INDIR_DATA_OFFSET, PLL_READY_TX_BIT, PLL_READY_TX_BIT, COMPHY_PLL_TIMEOUT, REG_32BIT); debug_exit(); return ret; } static int mvebu_a3700_comphy_sgmii_power_on(uint8_t comphy_index, uint32_t comphy_mode) { int ret = 0; uint32_t mask, data, offset; uintptr_t sd_ip_addr; int mode = COMPHY_GET_MODE(comphy_mode); int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode); debug_enter(); /* Set selector */ mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode); /* Serdes IP Base address * COMPHY Lane0 -- USB3/GBE1 * COMPHY Lane1 -- PCIe/GBE0 */ if (comphy_index == COMPHY_LANE0) { /* Get usb3 and gbe */ sd_ip_addr = USB3_GBE1_PHY; } else sd_ip_addr = COMPHY_SD_ADDR; /* * 1. Reset PHY by setting PHY input port PIN_RESET=1. * 2. Set PHY input port PIN_TX_IDLE=1, PIN_PU_IVREF=1 to keep * PHY TXP/TXN output to idle state during PHY initialization * 3. Set PHY input port PIN_PU_PLL=0, PIN_PU_RX=0, PIN_PU_TX=0. */ data = PIN_PU_IVEREF_BIT | PIN_TX_IDLE_BIT | PIN_RESET_COMPHY_BIT; mask = PIN_RESET_CORE_BIT | PIN_PU_PLL_BIT | PIN_PU_RX_BIT | PIN_PU_TX_BIT; offset = MVEBU_COMPHY_REG_BASE + COMPHY_PHY_CFG1_OFFSET(comphy_index); reg_set(offset, data, mask); /* 4. Release reset to the PHY by setting PIN_RESET=0. */ data = 0; mask = PIN_RESET_COMPHY_BIT; reg_set(offset, data, mask); /* * 5. Set PIN_PHY_GEN_TX[3:0] and PIN_PHY_GEN_RX[3:0] to decide COMPHY * bit rate */ if (mode == COMPHY_SGMII_MODE) { /* SGMII 1G, SerDes speed 1.25G */ data |= SD_SPEED_1_25_G << GEN_RX_SEL_OFFSET; data |= SD_SPEED_1_25_G << GEN_TX_SEL_OFFSET; } else if (mode == COMPHY_HS_SGMII_MODE) { /* HS SGMII (2.5G), SerDes speed 3.125G */ data |= SD_SPEED_2_5_G << GEN_RX_SEL_OFFSET; data |= SD_SPEED_2_5_G << GEN_TX_SEL_OFFSET; } else { /* Other rates are not supported */ ERROR("unsupported SGMII speed on comphy lane%d\n", comphy_index); return -EINVAL; } mask = GEN_RX_SEL_MASK | GEN_TX_SEL_MASK; reg_set(offset, data, mask); /* * 6. Wait 10mS for bandgap and reference clocks to stabilize; then * start SW programming. */ mdelay(10); /* 7. Program COMPHY register PHY_MODE */ data = PHY_MODE_SGMII; mask = PHY_MODE_MASK; reg_set16(SGMIIPHY_ADDR(COMPHY_POWER_PLL_CTRL, sd_ip_addr), data, mask); /* * 8. Set COMPHY register REFCLK_SEL to select the correct REFCLK * source */ data = 0; mask = PHY_REF_CLK_SEL; reg_set16(SGMIIPHY_ADDR(COMPHY_MISC_REG0_ADDR, sd_ip_addr), data, mask); /* * 9. Set correct reference clock frequency in COMPHY register * REF_FREF_SEL. */ if (get_ref_clk() == 40) data = REF_CLOCK_SPEED_50M; else data = REF_CLOCK_SPEED_25M; mask = REF_FREF_SEL_MASK; reg_set16(SGMIIPHY_ADDR(COMPHY_POWER_PLL_CTRL, sd_ip_addr), data, mask); /* 10. Program COMPHY register PHY_GEN_MAX[1:0] * This step is mentioned in the flow received from verification team. * However the PHY_GEN_MAX value is only meaningful for other interfaces * (not SGMII). For instance, it selects SATA speed 1.5/3/6 Gbps or PCIe * speed 2.5/5 Gbps */ /* * 11. Program COMPHY register SEL_BITS to set correct parallel data * bus width */ data = DATA_WIDTH_10BIT; mask = SEL_DATA_WIDTH_MASK; reg_set16(SGMIIPHY_ADDR(COMPHY_LOOPBACK_REG0, sd_ip_addr), data, mask); /* * 12. As long as DFE function needs to be enabled in any mode, * COMPHY register DFE_UPDATE_EN[5:0] shall be programmed to 0x3F * for real chip during COMPHY power on. * The step 14 exists (and empty) in the original initialization flow * obtained from the verification team. According to the functional * specification DFE_UPDATE_EN already has the default value 0x3F */ /* * 13. Program COMPHY GEN registers. * These registers should be programmed based on the lab testing result * to achieve optimal performance. Please contact the CEA group to get * the related GEN table during real chip bring-up. We only required to * run though the entire registers programming flow defined by * "comphy_sgmii_phy_init" when the REF clock is 40 MHz. For REF clock * 25 MHz the default values stored in PHY registers are OK. */ debug("Running C-DPI phy init %s mode\n", mode == COMPHY_HS_SGMII_MODE ? "2G5" : "1G"); if (get_ref_clk() == 40) comphy_sgmii_phy_init(comphy_index, mode, sd_ip_addr); /* * 14. [Simulation Only] should not be used for real chip. * By pass power up calibration by programming EXT_FORCE_CAL_DONE * (R02h[9]) to 1 to shorten COMPHY simulation time. */ /* * 15. [Simulation Only: should not be used for real chip] * Program COMPHY register FAST_DFE_TIMER_EN=1 to shorten RX training * simulation time. */ /* * 16. Check the PHY Polarity invert bit */ data = 0x0; if (invert & COMPHY_POLARITY_TXD_INVERT) data |= TXD_INVERT_BIT; if (invert & COMPHY_POLARITY_RXD_INVERT) data |= RXD_INVERT_BIT; reg_set16(SGMIIPHY_ADDR(COMPHY_SYNC_PATTERN_REG, sd_ip_addr), data, 0); /* * 17. Set PHY input ports PIN_PU_PLL, PIN_PU_TX and PIN_PU_RX to 1 to * start PHY power up sequence. All the PHY register programming should * be done before PIN_PU_PLL=1. There should be no register programming * for normal PHY operation from this point. */ reg_set(MVEBU_COMPHY_REG_BASE + COMPHY_PHY_CFG1_OFFSET(comphy_index), PIN_PU_PLL_BIT | PIN_PU_RX_BIT | PIN_PU_TX_BIT, PIN_PU_PLL_BIT | PIN_PU_RX_BIT | PIN_PU_TX_BIT); /* * 18. Wait for PHY power up sequence to finish by checking output ports * PIN_PLL_READY_TX=1 and PIN_PLL_READY_RX=1. */ ret = polling_with_timeout(MVEBU_COMPHY_REG_BASE + COMPHY_PHY_STATUS_OFFSET(comphy_index), PHY_PLL_READY_TX_BIT | PHY_PLL_READY_RX_BIT, PHY_PLL_READY_TX_BIT | PHY_PLL_READY_RX_BIT, COMPHY_PLL_TIMEOUT, REG_32BIT); if (ret) ERROR("Failed to lock PLL for SGMII PHY %d\n", comphy_index); /* * 19. Set COMPHY input port PIN_TX_IDLE=0 */ reg_set(MVEBU_COMPHY_REG_BASE + COMPHY_PHY_CFG1_OFFSET(comphy_index), 0x0, PIN_TX_IDLE_BIT); /* * 20. After valid data appear on PIN_RXDATA bus, set PIN_RX_INIT=1. To * start RX initialization. PIN_RX_INIT_DONE will be cleared to 0 by the * PHY After RX initialization is done, PIN_RX_INIT_DONE will be set to * 1 by COMPHY Set PIN_RX_INIT=0 after PIN_RX_INIT_DONE= 1. Please * refer to RX initialization part for details. */ reg_set(MVEBU_COMPHY_REG_BASE + COMPHY_PHY_CFG1_OFFSET(comphy_index), PHY_RX_INIT_BIT, 0x0); ret = polling_with_timeout(MVEBU_COMPHY_REG_BASE + COMPHY_PHY_STATUS_OFFSET(comphy_index), PHY_PLL_READY_TX_BIT | PHY_PLL_READY_RX_BIT, PHY_PLL_READY_TX_BIT | PHY_PLL_READY_RX_BIT, COMPHY_PLL_TIMEOUT, REG_32BIT); if (ret) ERROR("Failed to lock PLL for SGMII PHY %d\n", comphy_index); ret = polling_with_timeout(MVEBU_COMPHY_REG_BASE + COMPHY_PHY_STATUS_OFFSET(comphy_index), PHY_RX_INIT_DONE_BIT, PHY_RX_INIT_DONE_BIT, COMPHY_PLL_TIMEOUT, REG_32BIT); if (ret) ERROR("Failed to init RX of SGMII PHY %d\n", comphy_index); debug_exit(); return ret; } static int mvebu_a3700_comphy_usb3_power_on(uint8_t comphy_index, uint32_t comphy_mode) { int ret = 0; uintptr_t reg_base = 0; uint32_t mask, data, addr, cfg, ref_clk; void (*usb3_reg_set)(uintptr_t addr, uint32_t reg_offset, uint16_t data, uint16_t mask, int mode); int mode = COMPHY_GET_MODE(comphy_mode); int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode); debug_enter(); /* Set phy seclector */ mvebu_a3700_comphy_set_phy_selector(comphy_index, comphy_mode); /* Set usb3 reg access func, Lane2 is indirect access */ if (comphy_index == COMPHY_LANE2) { usb3_reg_set = &comphy_set_indirect; reg_base = COMPHY_INDIRECT_REG; } else { /* Get the direct access register resource and map */ usb3_reg_set = &comphy_usb3_set_direct; reg_base = USB3_GBE1_PHY; } /* * 0. Set PHY OTG Control(0x5d034), bit 4, Power up OTG module The * register belong to UTMI module, so it is set in UTMI phy driver. */ /* * 1. Set PRD_TXDEEMPH (3.5db de-emph) */ mask = PRD_TXDEEMPH0_MASK | PRD_TXMARGIN_MASK | PRD_TXSWING_MASK | CFG_TX_ALIGN_POS_MASK; usb3_reg_set(reg_base, COMPHY_REG_LANE_CFG0_ADDR, PRD_TXDEEMPH0_MASK, mask, mode); /* * 2. Set BIT0: enable transmitter in high impedance mode * Set BIT[3:4]: delay 2 clock cycles for HiZ off latency * Set BIT6: Tx detect Rx at HiZ mode * Unset BIT15: set to 0 to set USB3 De-emphasize level to -3.5db * together with bit 0 of COMPHY_REG_LANE_CFG0_ADDR register */ mask = PRD_TXDEEMPH1_MASK | TX_DET_RX_MODE | GEN2_TX_DATA_DLY_MASK | TX_ELEC_IDLE_MODE_EN; data = TX_DET_RX_MODE | GEN2_TX_DATA_DLY_DEFT | TX_ELEC_IDLE_MODE_EN; usb3_reg_set(reg_base, COMPHY_REG_LANE_CFG1_ADDR, data, mask, mode); /* * 3. Set Spread Spectrum Clock Enabled */ usb3_reg_set(reg_base, COMPHY_REG_LANE_CFG4_ADDR, SPREAD_SPECTRUM_CLK_EN, SPREAD_SPECTRUM_CLK_EN, mode); /* * 4. Set Override Margining Controls From the MAC: * Use margining signals from lane configuration */ usb3_reg_set(reg_base, COMPHY_REG_TEST_MODE_CTRL_ADDR, MODE_MARGIN_OVERRIDE, REG_16_BIT_MASK, mode); /* * 5. Set Lane-to-Lane Bundle Clock Sampling Period = per PCLK cycles * set Mode Clock Source = PCLK is generated from REFCLK */ usb3_reg_set(reg_base, COMPHY_REG_GLOB_CLK_SRC_LO_ADDR, 0x0, (MODE_CLK_SRC | BUNDLE_PERIOD_SEL | BUNDLE_PERIOD_SCALE | BUNDLE_SAMPLE_CTRL | PLL_READY_DLY), mode); /* * 6. Set G2 Spread Spectrum Clock Amplitude at 4K */ usb3_reg_set(reg_base, COMPHY_REG_GEN2_SET_2, G2_TX_SSC_AMP_VALUE_20, G2_TX_SSC_AMP_MASK, mode); /* * 7. Unset G3 Spread Spectrum Clock Amplitude * set G3 TX and RX Register Master Current Select */ mask = G3_TX_SSC_AMP_MASK | G3_VREG_RXTX_MAS_ISET_MASK | RSVD_PH03FH_6_0_MASK; usb3_reg_set(reg_base, COMPHY_REG_GEN2_SET_3, G3_VREG_RXTX_MAS_ISET_60U, mask, mode); /* * 8. Check crystal jumper setting and program the Power and PLL Control * accordingly Change RX wait */ if (get_ref_clk() == 40) { ref_clk = REF_CLOCK_SPEED_40M; cfg = CFG_PM_RXDLOZ_WAIT_12_UNIT; } else { /* 25 MHz */ ref_clk = USB3_REF_CLOCK_SPEED_25M; cfg = CFG_PM_RXDLOZ_WAIT_7_UNIT; } mask = PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT | PU_TX_INTP_BIT | PU_DFE_BIT | PLL_LOCK_BIT | PHY_MODE_MASK | REF_FREF_SEL_MASK; data = PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT | PU_TX_INTP_BIT | PU_DFE_BIT | PHY_MODE_USB3 | ref_clk; usb3_reg_set(reg_base, COMPHY_POWER_PLL_CTRL, data, mask, mode); mask = CFG_PM_OSCCLK_WAIT_MASK | CFG_PM_RXDEN_WAIT_MASK | CFG_PM_RXDLOZ_WAIT_MASK; data = CFG_PM_RXDEN_WAIT_1_UNIT | cfg; usb3_reg_set(reg_base, COMPHY_REG_PWR_MGM_TIM1_ADDR, data, mask, mode); /* * 9. Enable idle sync */ data = UNIT_CTRL_DEFAULT_VALUE | IDLE_SYNC_EN; usb3_reg_set(reg_base, COMPHY_REG_UNIT_CTRL_ADDR, data, REG_16_BIT_MASK, mode); /* * 10. Enable the output of 500M clock */ data = MISC_REG0_DEFAULT_VALUE | CLK500M_EN; usb3_reg_set(reg_base, COMPHY_MISC_REG0_ADDR, data, REG_16_BIT_MASK, mode); /* * 11. Set 20-bit data width */ usb3_reg_set(reg_base, COMPHY_LOOPBACK_REG0, DATA_WIDTH_20BIT, REG_16_BIT_MASK, mode); /* * 12. Override Speed_PLL value and use MAC PLL */ usb3_reg_set(reg_base, COMPHY_KVCO_CAL_CTRL, (SPEED_PLL_VALUE_16 | USE_MAX_PLL_RATE_BIT), REG_16_BIT_MASK, mode); /* * 13. Check the Polarity invert bit */ if (invert & COMPHY_POLARITY_TXD_INVERT) usb3_reg_set(reg_base, COMPHY_SYNC_PATTERN_REG, TXD_INVERT_BIT, TXD_INVERT_BIT, mode); if (invert & COMPHY_POLARITY_RXD_INVERT) usb3_reg_set(reg_base, COMPHY_SYNC_PATTERN_REG, RXD_INVERT_BIT, RXD_INVERT_BIT, mode); /* * 14. Set max speed generation to USB3.0 5Gbps */ usb3_reg_set(reg_base, COMPHY_SYNC_MASK_GEN_REG, PHY_GEN_USB3_5G, PHY_GEN_MAX_MASK, mode); /* * 15. Set capacitor value for FFE gain peaking to 0xF */ usb3_reg_set(reg_base, COMPHY_REG_GEN3_SETTINGS_3, COMPHY_GEN_FFE_CAP_SEL_VALUE, COMPHY_GEN_FFE_CAP_SEL_MASK, mode); /* * 16. Release SW reset */ data = MODE_CORE_CLK_FREQ_SEL | MODE_PIPE_WIDTH_32 | MODE_REFDIV_BY_4; usb3_reg_set(reg_base, COMPHY_REG_GLOB_PHY_CTRL0_ADDR, data, REG_16_BIT_MASK, mode); /* Wait for > 55 us to allow PCLK be enabled */ udelay(PLL_SET_DELAY_US); if (comphy_index == COMPHY_LANE2) { data = COMPHY_LOOPBACK_REG0 + USB3PHY_LANE2_REG_BASE_OFFSET; mmio_write_32(reg_base + COMPHY_LANE2_INDIR_ADDR_OFFSET, data); addr = COMPHY_LOOPBACK_REG0 + USB3PHY_LANE2_REG_BASE_OFFSET; ret = polling_with_timeout(addr, TXDCLK_PCLK_EN, TXDCLK_PCLK_EN, COMPHY_PLL_TIMEOUT, REG_32BIT); } else { ret = polling_with_timeout(LANE_STATUS1_ADDR(USB3) + reg_base, TXDCLK_PCLK_EN, TXDCLK_PCLK_EN, COMPHY_PLL_TIMEOUT, REG_16BIT); } if (ret) ERROR("Failed to lock USB3 PLL\n"); debug_exit(); return ret; } static int mvebu_a3700_comphy_pcie_power_on(uint8_t comphy_index, uint32_t comphy_mode) { int ret; uint32_t ref_clk; int invert = COMPHY_GET_POLARITY_INVERT(comphy_mode); debug_enter(); /* 1. Enable max PLL. */ reg_set16(LANE_CFG1_ADDR(PCIE) + COMPHY_SD_ADDR, USE_MAX_PLL_RATE_EN, 0x0); /* 2. Select 20 bit SERDES interface. */ reg_set16(GLOB_CLK_SRC_LO_ADDR(PCIE) + COMPHY_SD_ADDR, CFG_SEL_20B, 0); /* 3. Force to use reg setting for PCIe mode */ reg_set16(MISC_REG1_ADDR(PCIE) + COMPHY_SD_ADDR, SEL_BITS_PCIE_FORCE, 0); /* 4. Change RX wait */ reg_set16(PWR_MGM_TIM1_ADDR(PCIE) + COMPHY_SD_ADDR, CFG_PM_RXDEN_WAIT_1_UNIT | CFG_PM_RXDLOZ_WAIT_12_UNIT, (CFG_PM_OSCCLK_WAIT_MASK | CFG_PM_RXDEN_WAIT_MASK | CFG_PM_RXDLOZ_WAIT_MASK)); /* 5. Enable idle sync */ reg_set16(UNIT_CTRL_ADDR(PCIE) + COMPHY_SD_ADDR, UNIT_CTRL_DEFAULT_VALUE | IDLE_SYNC_EN, REG_16_BIT_MASK); /* 6. Enable the output of 100M/125M/500M clock */ reg_set16(MISC_REG0_ADDR(PCIE) + COMPHY_SD_ADDR, MISC_REG0_DEFAULT_VALUE | CLK500M_EN | CLK100M_125M_EN, REG_16_BIT_MASK); /* * 7. Enable TX, PCIE global register, 0xd0074814, it is done in * PCI-E driver */ /* * 8. Check crystal jumper setting and program the Power and PLL * Control accordingly */ if (get_ref_clk() == 40) ref_clk = REF_CLOCK_SPEED_40M; else ref_clk = PCIE_REF_CLOCK_SPEED_25M; reg_set16(PWR_PLL_CTRL_ADDR(PCIE) + COMPHY_SD_ADDR, (PU_IVREF_BIT | PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT | PU_TX_INTP_BIT | PU_DFE_BIT | ref_clk | PHY_MODE_PCIE), REG_16_BIT_MASK); /* 9. Override Speed_PLL value and use MAC PLL */ reg_set16(KVCO_CAL_CTRL_ADDR(PCIE) + COMPHY_SD_ADDR, SPEED_PLL_VALUE_16 | USE_MAX_PLL_RATE_BIT, REG_16_BIT_MASK); /* 10. Check the Polarity invert bit */ if (invert & COMPHY_POLARITY_TXD_INVERT) reg_set16(SYNC_PATTERN_REG_ADDR(PCIE) + COMPHY_SD_ADDR, TXD_INVERT_BIT, 0x0); if (invert & COMPHY_POLARITY_RXD_INVERT) reg_set16(SYNC_PATTERN_REG_ADDR(PCIE) + COMPHY_SD_ADDR, RXD_INVERT_BIT, 0x0); /* 11. Release SW reset */ reg_set16(GLOB_PHY_CTRL0_ADDR(PCIE) + COMPHY_SD_ADDR, MODE_CORE_CLK_FREQ_SEL | MODE_PIPE_WIDTH_32, SOFT_RESET | MODE_REFDIV); /* Wait for > 55 us to allow PCLK be enabled */ udelay(PLL_SET_DELAY_US); ret = polling_with_timeout(LANE_STATUS1_ADDR(PCIE) + COMPHY_SD_ADDR, TXDCLK_PCLK_EN, TXDCLK_PCLK_EN, COMPHY_PLL_TIMEOUT, REG_16BIT); if (ret) ERROR("Failed to lock PCIE PLL\n"); debug_exit(); return ret; } int mvebu_3700_comphy_power_on(uint8_t comphy_index, uint32_t comphy_mode) { int mode = COMPHY_GET_MODE(comphy_mode); int ret = 0; debug_enter(); switch (mode) { case(COMPHY_SATA_MODE): ret = mvebu_a3700_comphy_sata_power_on(comphy_index, comphy_mode); break; case(COMPHY_SGMII_MODE): case(COMPHY_HS_SGMII_MODE): ret = mvebu_a3700_comphy_sgmii_power_on(comphy_index, comphy_mode); break; case (COMPHY_USB3_MODE): case (COMPHY_USB3H_MODE): ret = mvebu_a3700_comphy_usb3_power_on(comphy_index, comphy_mode); break; case (COMPHY_PCIE_MODE): ret = mvebu_a3700_comphy_pcie_power_on(comphy_index, comphy_mode); break; default: ERROR("comphy%d: unsupported comphy mode\n", comphy_index); ret = -EINVAL; break; } debug_exit(); return ret; } static int mvebu_a3700_comphy_usb3_power_off(void) { /* * Currently the USB3 MAC will control the USB3 PHY to set it to low * state, thus do not need to power off USB3 PHY again. */ debug_enter(); debug_exit(); return 0; } static int mvebu_a3700_comphy_sata_power_off(uint32_t comphy_mode) { uintptr_t comphy_indir_regs = COMPHY_INDIRECT_REG; int mode = COMPHY_GET_MODE(comphy_mode); uint32_t offset; debug_enter(); /* Set phy isolation mode */ offset = COMPHY_ISOLATION_CTRL_REG + SATAPHY_LANE2_REG_BASE_OFFSET; comphy_set_indirect(comphy_indir_regs, offset, PHY_ISOLATE_MODE, PHY_ISOLATE_MODE, mode); /* Power off PLL, Tx, Rx */ offset = COMPHY_POWER_PLL_CTRL + SATAPHY_LANE2_REG_BASE_OFFSET; comphy_set_indirect(comphy_indir_regs, offset, 0, PU_PLL_BIT | PU_RX_BIT | PU_TX_BIT, mode); debug_exit(); return 0; } int mvebu_3700_comphy_power_off(uint8_t comphy_index, uint32_t comphy_mode) { int mode = COMPHY_GET_MODE(comphy_mode); int err = 0; debug_enter(); switch (mode) { case (COMPHY_USB3_MODE): case (COMPHY_USB3H_MODE): err = mvebu_a3700_comphy_usb3_power_off(); break; case (COMPHY_SATA_MODE): err = mvebu_a3700_comphy_sata_power_off(comphy_mode); break; default: debug("comphy%d: power off is not implemented for mode %d\n", comphy_index, mode); break; } debug_exit(); return err; } static int mvebu_a3700_comphy_sata_is_pll_locked(void) { uint32_t data, addr; uintptr_t comphy_indir_regs = COMPHY_INDIRECT_REG; int ret = 0; debug_enter(); /* Polling status */ mmio_write_32(comphy_indir_regs + COMPHY_LANE2_INDIR_ADDR_OFFSET, COMPHY_LOOPBACK_REG0 + SATAPHY_LANE2_REG_BASE_OFFSET); addr = comphy_indir_regs + COMPHY_LANE2_INDIR_DATA_OFFSET; data = polling_with_timeout(addr, PLL_READY_TX_BIT, PLL_READY_TX_BIT, COMPHY_PLL_TIMEOUT, REG_32BIT); if (data != 0) { ERROR("TX PLL is not locked\n"); ret = -ETIMEDOUT; } debug_exit(); return ret; } int mvebu_3700_comphy_is_pll_locked(uint8_t comphy_index, uint32_t comphy_mode) { int mode = COMPHY_GET_MODE(comphy_mode); int ret = 0; debug_enter(); switch (mode) { case(COMPHY_SATA_MODE): ret = mvebu_a3700_comphy_sata_is_pll_locked(); break; default: ERROR("comphy[%d] mode[%d] doesn't support PLL lock check\n", comphy_index, mode); ret = -EINVAL; break; } debug_exit(); return ret; } trusted-firmware-a-2.2/drivers/marvell/comphy/phy-comphy-3700.h000066400000000000000000000221241355360272700243660ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef PHY_COMPHY_3700_H #define PHY_COMPHY_3700_H #define PLL_SET_DELAY_US 600 #define COMPHY_PLL_TIMEOUT 1000 #define REG_16_BIT_MASK 0xFFFF #define COMPHY_SELECTOR_PHY_REG 0xFC /* bit0: 0: Lane0 is GBE0; 1: Lane1 is PCIE */ #define COMPHY_SELECTOR_PCIE_GBE0_SEL_BIT BIT(0) /* bit4: 0: Lane1 is GBE1; 1: Lane1 is USB3 */ #define COMPHY_SELECTOR_USB3_GBE1_SEL_BIT BIT(4) /* bit8: 0: Lane1 is USB, Lane2 is SATA; 1: Lane2 is USB3 */ #define COMPHY_SELECTOR_USB3_PHY_SEL_BIT BIT(8) /* SATA PHY register offset */ #define SATAPHY_LANE2_REG_BASE_OFFSET 0x200 /* USB3 PHY offset compared to SATA PHY */ #define USB3PHY_LANE2_REG_BASE_OFFSET 0x200 /* Comphy lane2 indirect access register offset */ #define COMPHY_LANE2_INDIR_ADDR_OFFSET 0x0 #define COMPHY_LANE2_INDIR_DATA_OFFSET 0x4 /* PHY shift to get related register address */ enum { PCIE = 1, USB3, }; #define PCIEPHY_SHFT 2 #define USB3PHY_SHFT 2 #define PHY_SHFT(unit) ((unit == PCIE) ? PCIEPHY_SHFT : USB3PHY_SHFT) /* PHY register */ #define COMPHY_POWER_PLL_CTRL 0x01 #define PWR_PLL_CTRL_ADDR(unit) (COMPHY_POWER_PLL_CTRL * PHY_SHFT(unit)) #define PU_IVREF_BIT BIT(15) #define PU_PLL_BIT BIT(14) #define PU_RX_BIT BIT(13) #define PU_TX_BIT BIT(12) #define PU_TX_INTP_BIT BIT(11) #define PU_DFE_BIT BIT(10) #define RESET_DTL_RX_BIT BIT(9) #define PLL_LOCK_BIT BIT(8) #define REF_FREF_SEL_OFFSET 0 #define REF_FREF_SEL_MASK (0x1F << REF_FREF_SEL_OFFSET) #define REF_CLOCK_SPEED_25M (0x1 << REF_FREF_SEL_OFFSET) #define REF_CLOCK_SPEED_30M (0x2 << REF_FREF_SEL_OFFSET) #define PCIE_REF_CLOCK_SPEED_25M REF_CLOCK_SPEED_30M #define USB3_REF_CLOCK_SPEED_25M REF_CLOCK_SPEED_30M #define REF_CLOCK_SPEED_40M (0x3 << REF_FREF_SEL_OFFSET) #define REF_CLOCK_SPEED_50M (0x4 << REF_FREF_SEL_OFFSET) #define PHY_MODE_OFFSET 5 #define PHY_MODE_MASK (7 << PHY_MODE_OFFSET) #define PHY_MODE_SATA (0x0 << PHY_MODE_OFFSET) #define PHY_MODE_PCIE (0x3 << PHY_MODE_OFFSET) #define PHY_MODE_SGMII (0x4 << PHY_MODE_OFFSET) #define PHY_MODE_USB3 (0x5 << PHY_MODE_OFFSET) #define COMPHY_KVCO_CAL_CTRL 0x02 #define KVCO_CAL_CTRL_ADDR(unit) (COMPHY_KVCO_CAL_CTRL * PHY_SHFT(unit)) #define USE_MAX_PLL_RATE_BIT BIT(12) #define SPEED_PLL_OFFSET 2 #define SPEED_PLL_MASK (0x3F << SPEED_PLL_OFFSET) #define SPEED_PLL_VALUE_16 (0x10 << SPEED_PLL_OFFSET) #define COMPHY_RESERVED_REG 0x0E #define PHYCTRL_FRM_PIN_BIT BIT(13) #define COMPHY_LOOPBACK_REG0 0x23 #define DIG_LB_EN_ADDR(unit) (COMPHY_LOOPBACK_REG0 * PHY_SHFT(unit)) #define SEL_DATA_WIDTH_OFFSET 10 #define SEL_DATA_WIDTH_MASK (0x3 << SEL_DATA_WIDTH_OFFSET) #define DATA_WIDTH_10BIT (0x0 << SEL_DATA_WIDTH_OFFSET) #define DATA_WIDTH_20BIT (0x1 << SEL_DATA_WIDTH_OFFSET) #define DATA_WIDTH_40BIT (0x2 << SEL_DATA_WIDTH_OFFSET) #define PLL_READY_TX_BIT BIT(4) #define COMPHY_SYNC_PATTERN_REG 0x24 #define SYNC_PATTERN_REG_ADDR(unit) (COMPHY_SYNC_PATTERN_REG * \ PHY_SHFT(unit)) #define TXD_INVERT_BIT BIT(10) #define RXD_INVERT_BIT BIT(11) #define COMPHY_SYNC_MASK_GEN_REG 0x25 #define PHY_GEN_MAX_OFFSET 10 #define PHY_GEN_MAX_MASK (3 << PHY_GEN_MAX_OFFSET) #define PHY_GEN_USB3_5G (1 << PHY_GEN_MAX_OFFSET) #define COMPHY_ISOLATION_CTRL_REG 0x26 #define ISOLATION_CTRL_REG_ADDR(unit) (COMPHY_ISOLATION_CTRL_REG * \ PHY_SHFT(unit)) #define PHY_ISOLATE_MODE BIT(15) #define COMPHY_MISC_REG0_ADDR 0x4F #define MISC_REG0_ADDR(unit) (COMPHY_MISC_REG0_ADDR * PHY_SHFT(unit)) #define CLK100M_125M_EN BIT(4) #define CLK500M_EN BIT(7) #define PHY_REF_CLK_SEL BIT(10) #define MISC_REG0_DEFAULT_VALUE 0xA00D #define COMPHY_REG_GEN2_SET_2 0x3e #define GEN2_SETTING_2_ADDR(unit) (COMPHY_REG_GEN2_SET_2 * PHY_SHFT(unit)) #define G2_TX_SSC_AMP_VALUE_20 BIT(14) #define G2_TX_SSC_AMP_OFF 9 #define G2_TX_SSC_AMP_LEN 7 #define G2_TX_SSC_AMP_MASK (((1 << G2_TX_SSC_AMP_LEN) - 1) << \ G2_TX_SSC_AMP_OFF) #define COMPHY_REG_GEN2_SET_3 0x3f #define GEN2_SETTING_3_ADDR(unit) (COMPHY_REG_GEN2_SET_3 * PHY_SHFT(unit)) #define G3_TX_SSC_AMP_OFF 9 #define G3_TX_SSC_AMP_LEN 7 #define G3_TX_SSC_AMP_MASK (((1 << G2_TX_SSC_AMP_LEN) - 1) << \ G2_TX_SSC_AMP_OFF) #define G3_VREG_RXTX_MAS_ISET_OFF 7 #define G3_VREG_RXTX_MAS_ISET_60U (0 << G3_VREG_RXTX_MAS_ISET_OFF) #define G3_VREG_RXTX_MAS_ISET_80U (1 << G3_VREG_RXTX_MAS_ISET_OFF) #define G3_VREG_RXTX_MAS_ISET_100U (2 << G3_VREG_RXTX_MAS_ISET_OFF) #define G3_VREG_RXTX_MAS_ISET_120U (3 << G3_VREG_RXTX_MAS_ISET_OFF) #define G3_VREG_RXTX_MAS_ISET_MASK (BIT(7) | BIT(8)) #define RSVD_PH03FH_6_0_OFF 0 #define RSVD_PH03FH_6_0_LEN 7 #define RSVD_PH03FH_6_0_MASK (((1 << RSVD_PH03FH_6_0_LEN) - 1) << \ RSVD_PH03FH_6_0_OFF) #define COMPHY_REG_UNIT_CTRL_ADDR 0x48 #define UNIT_CTRL_ADDR(unit) (COMPHY_REG_UNIT_CTRL_ADDR * \ PHY_SHFT(unit)) #define IDLE_SYNC_EN BIT(12) #define UNIT_CTRL_DEFAULT_VALUE 0x60 #define COMPHY_MISC_REG1_ADDR 0x73 #define MISC_REG1_ADDR(unit) (COMPHY_MISC_REG1_ADDR * PHY_SHFT(unit)) #define SEL_BITS_PCIE_FORCE BIT(15) #define COMPHY_REG_GEN3_SETTINGS_3 0x112 #define COMPHY_GEN_FFE_CAP_SEL_MASK 0xF #define COMPHY_GEN_FFE_CAP_SEL_VALUE 0xF #define COMPHY_REG_LANE_CFG0_ADDR 0x180 #define LANE_CFG0_ADDR(unit) (COMPHY_REG_LANE_CFG0_ADDR * \ PHY_SHFT(unit)) #define PRD_TXDEEMPH0_MASK BIT(0) #define PRD_TXMARGIN_MASK (BIT(1) | BIT(2) | BIT(3)) #define PRD_TXSWING_MASK BIT(4) #define CFG_TX_ALIGN_POS_MASK (BIT(5) | BIT(6) | BIT(7) | BIT(8)) #define COMPHY_REG_LANE_CFG1_ADDR 0x181 #define LANE_CFG1_ADDR(unit) (COMPHY_REG_LANE_CFG1_ADDR * \ PHY_SHFT(unit)) #define PRD_TXDEEMPH1_MASK BIT(15) #define USE_MAX_PLL_RATE_EN BIT(9) #define TX_DET_RX_MODE BIT(6) #define GEN2_TX_DATA_DLY_MASK (BIT(3) | BIT(4)) #define GEN2_TX_DATA_DLY_DEFT (2 << 3) #define TX_ELEC_IDLE_MODE_EN BIT(0) #define COMPHY_REG_LANE_STATUS1_ADDR 0x183 #define LANE_STATUS1_ADDR(unit) (COMPHY_REG_LANE_STATUS1_ADDR * \ PHY_SHFT(unit)) #define TXDCLK_PCLK_EN BIT(0) #define COMPHY_REG_LANE_CFG4_ADDR 0x188 #define LANE_CFG4_ADDR(unit) (COMPHY_REG_LANE_CFG4_ADDR * \ PHY_SHFT(unit)) #define SPREAD_SPECTRUM_CLK_EN BIT(7) #define COMPHY_REG_GLOB_PHY_CTRL0_ADDR 0x1C1 #define GLOB_PHY_CTRL0_ADDR(unit) (COMPHY_REG_GLOB_PHY_CTRL0_ADDR * \ PHY_SHFT(unit)) #define SOFT_RESET BIT(0) #define MODE_REFDIV 0x30 #define MODE_CORE_CLK_FREQ_SEL BIT(9) #define MODE_PIPE_WIDTH_32 BIT(3) #define MODE_REFDIV_OFFSET 4 #define MODE_REFDIV_LEN 2 #define MODE_REFDIV_MASK (0x3 << MODE_REFDIV_OFFSET) #define MODE_REFDIV_BY_4 (0x2 << MODE_REFDIV_OFFSET) #define COMPHY_REG_TEST_MODE_CTRL_ADDR 0x1C2 #define TEST_MODE_CTRL_ADDR(unit) (COMPHY_REG_TEST_MODE_CTRL_ADDR * \ PHY_SHFT(unit)) #define MODE_MARGIN_OVERRIDE BIT(2) #define COMPHY_REG_GLOB_CLK_SRC_LO_ADDR 0x1C3 #define GLOB_CLK_SRC_LO_ADDR(unit) (COMPHY_REG_GLOB_CLK_SRC_LO_ADDR * \ PHY_SHFT(unit)) #define MODE_CLK_SRC BIT(0) #define BUNDLE_PERIOD_SEL BIT(1) #define BUNDLE_PERIOD_SCALE (BIT(2) | BIT(3)) #define BUNDLE_SAMPLE_CTRL BIT(4) #define PLL_READY_DLY (BIT(5) | BIT(6) | BIT(7)) #define CFG_SEL_20B BIT(15) #define COMPHY_REG_PWR_MGM_TIM1_ADDR 0x1D0 #define PWR_MGM_TIM1_ADDR(unit) (COMPHY_REG_PWR_MGM_TIM1_ADDR * \ PHY_SHFT(unit)) #define CFG_PM_OSCCLK_WAIT_OFF 12 #define CFG_PM_OSCCLK_WAIT_LEN 4 #define CFG_PM_OSCCLK_WAIT_MASK (((1 << CFG_PM_OSCCLK_WAIT_LEN) - 1) \ << CFG_PM_OSCCLK_WAIT_OFF) #define CFG_PM_RXDEN_WAIT_OFF 8 #define CFG_PM_RXDEN_WAIT_LEN 4 #define CFG_PM_RXDEN_WAIT_MASK (((1 << CFG_PM_RXDEN_WAIT_LEN) - 1) \ << CFG_PM_RXDEN_WAIT_OFF) #define CFG_PM_RXDEN_WAIT_1_UNIT (1 << CFG_PM_RXDEN_WAIT_OFF) #define CFG_PM_RXDLOZ_WAIT_OFF 0 #define CFG_PM_RXDLOZ_WAIT_LEN 8 #define CFG_PM_RXDLOZ_WAIT_MASK (((1 << CFG_PM_RXDLOZ_WAIT_LEN) - 1) \ << CFG_PM_RXDLOZ_WAIT_OFF) #define CFG_PM_RXDLOZ_WAIT_7_UNIT (7 << CFG_PM_RXDLOZ_WAIT_OFF) #define CFG_PM_RXDLOZ_WAIT_12_UNIT (0xC << CFG_PM_RXDLOZ_WAIT_OFF) /* SGMII */ #define COMPHY_PHY_CFG1_OFFSET(lane) ((1 - (lane)) * 0x28) #define PIN_PU_IVEREF_BIT BIT(1) #define PIN_RESET_CORE_BIT BIT(11) #define PIN_RESET_COMPHY_BIT BIT(12) #define PIN_PU_PLL_BIT BIT(16) #define PIN_PU_RX_BIT BIT(17) #define PIN_PU_TX_BIT BIT(18) #define PIN_TX_IDLE_BIT BIT(19) #define GEN_RX_SEL_OFFSET 22 #define GEN_RX_SEL_MASK (0xF << GEN_RX_SEL_OFFSET) #define GEN_TX_SEL_OFFSET 26 #define GEN_TX_SEL_MASK (0xF << GEN_TX_SEL_OFFSET) #define PHY_RX_INIT_BIT BIT(30) #define SD_SPEED_1_25_G 0x6 #define SD_SPEED_2_5_G 0x8 /* COMPHY status reg: * lane0: PCIe/GbE0 PHY Status 1 * lane1: USB3/GbE1 PHY Status 1 */ #define COMPHY_PHY_STATUS_OFFSET(lane) (0x18 + (1 - (lane)) * 0x28) #define PHY_RX_INIT_DONE_BIT BIT(0) #define PHY_PLL_READY_RX_BIT BIT(2) #define PHY_PLL_READY_TX_BIT BIT(3) #define SGMIIPHY_ADDR(off, base) ((((off) & 0x00007FF) * 2) + (base)) #define MAX_LANE_NR 3 /* comphy API */ int mvebu_3700_comphy_is_pll_locked(uint8_t comphy_index, uint32_t comphy_mode); int mvebu_3700_comphy_power_off(uint8_t comphy_index, uint32_t comphy_mode); int mvebu_3700_comphy_power_on(uint8_t comphy_index, uint32_t comphy_mode); #endif /* PHY_COMPHY_3700_H */ trusted-firmware-a-2.2/drivers/marvell/comphy/phy-comphy-common.h000066400000000000000000000121221355360272700252620ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* Marvell CP110 ana A3700 common */ #ifndef PHY_COMPHY_COMMON_H #define PHY_COMPHY_COMMON_H /* #define DEBUG_COMPHY */ #ifdef DEBUG_COMPHY #define debug(format...) printf(format) #else #define debug(format, arg...) #endif /* A lane is described by 4 fields: * - bit 1~0 represent comphy polarity invert * - bit 7~2 represent comphy speed * - bit 11~8 represent unit index * - bit 16~12 represent mode * - bit 17 represent comphy indication of clock source * - bit 20~18 represents pcie width (in case of pcie comphy config.) * - bit 21 represents the source of the request (Linux/Bootloader), * (reguired only for PCIe!) * - bit 31~22 reserved */ #define COMPHY_INVERT_OFFSET 0 #define COMPHY_INVERT_LEN 2 #define COMPHY_INVERT_MASK COMPHY_MASK(COMPHY_INVERT_OFFSET, \ COMPHY_INVERT_LEN) #define COMPHY_SPEED_OFFSET (COMPHY_INVERT_OFFSET + COMPHY_INVERT_LEN) #define COMPHY_SPEED_LEN 6 #define COMPHY_SPEED_MASK COMPHY_MASK(COMPHY_SPEED_OFFSET, \ COMPHY_SPEED_LEN) #define COMPHY_UNIT_ID_OFFSET (COMPHY_SPEED_OFFSET + COMPHY_SPEED_LEN) #define COMPHY_UNIT_ID_LEN 4 #define COMPHY_UNIT_ID_MASK COMPHY_MASK(COMPHY_UNIT_ID_OFFSET, \ COMPHY_UNIT_ID_LEN) #define COMPHY_MODE_OFFSET (COMPHY_UNIT_ID_OFFSET + COMPHY_UNIT_ID_LEN) #define COMPHY_MODE_LEN 5 #define COMPHY_MODE_MASK COMPHY_MASK(COMPHY_MODE_OFFSET, COMPHY_MODE_LEN) #define COMPHY_CLK_SRC_OFFSET (COMPHY_MODE_OFFSET + COMPHY_MODE_LEN) #define COMPHY_CLK_SRC_LEN 1 #define COMPHY_CLK_SRC_MASK COMPHY_MASK(COMPHY_CLK_SRC_OFFSET, \ COMPHY_CLK_SRC_LEN) #define COMPHY_PCI_WIDTH_OFFSET (COMPHY_CLK_SRC_OFFSET + COMPHY_CLK_SRC_LEN) #define COMPHY_PCI_WIDTH_LEN 3 #define COMPHY_PCI_WIDTH_MASK COMPHY_MASK(COMPHY_PCI_WIDTH_OFFSET, \ COMPHY_PCI_WIDTH_LEN) #define COMPHY_PCI_CALLER_OFFSET \ (COMPHY_PCI_WIDTH_OFFSET + COMPHY_PCI_WIDTH_LEN) #define COMPHY_PCI_CALLER_LEN 1 #define COMPHY_PCI_CALLER_MASK COMPHY_MASK(COMPHY_PCI_CALLER_OFFSET, \ COMPHY_PCI_CALLER_LEN) #define COMPHY_MASK(offset, len) (((1 << (len)) - 1) << (offset)) /* Macro which extracts mode from lane description */ #define COMPHY_GET_MODE(x) (((x) & COMPHY_MODE_MASK) >> \ COMPHY_MODE_OFFSET) /* Macro which extracts unit index from lane description */ #define COMPHY_GET_ID(x) (((x) & COMPHY_UNIT_ID_MASK) >> \ COMPHY_UNIT_ID_OFFSET) /* Macro which extracts speed from lane description */ #define COMPHY_GET_SPEED(x) (((x) & COMPHY_SPEED_MASK) >> \ COMPHY_SPEED_OFFSET) /* Macro which extracts clock source indication from lane description */ #define COMPHY_GET_CLK_SRC(x) (((x) & COMPHY_CLK_SRC_MASK) >> \ COMPHY_CLK_SRC_OFFSET) /* Macro which extracts pcie width indication from lane description */ #define COMPHY_GET_PCIE_WIDTH(x) (((x) & COMPHY_PCI_WIDTH_MASK) >> \ COMPHY_PCI_WIDTH_OFFSET) /* Macro which extracts the caller for pcie power on from lane description */ #define COMPHY_GET_CALLER(x) (((x) & COMPHY_PCI_CALLER_MASK) >> \ COMPHY_PCI_CALLER_OFFSET) /* Macro which extracts the polarity invert from lane description */ #define COMPHY_GET_POLARITY_INVERT(x) (((x) & COMPHY_INVERT_MASK) >> \ COMPHY_INVERT_OFFSET) #define COMPHY_SATA_MODE 0x1 #define COMPHY_SGMII_MODE 0x2 /* SGMII 1G */ #define COMPHY_HS_SGMII_MODE 0x3 /* SGMII 2.5G */ #define COMPHY_USB3H_MODE 0x4 #define COMPHY_USB3D_MODE 0x5 #define COMPHY_PCIE_MODE 0x6 #define COMPHY_RXAUI_MODE 0x7 #define COMPHY_XFI_MODE 0x8 #define COMPHY_SFI_MODE 0x9 #define COMPHY_USB3_MODE 0xa #define COMPHY_AP_MODE 0xb #define COMPHY_UNUSED 0xFFFFFFFF /* Polarity invert macro */ #define COMPHY_POLARITY_NO_INVERT 0 #define COMPHY_POLARITY_TXD_INVERT 1 #define COMPHY_POLARITY_RXD_INVERT 2 #define COMPHY_POLARITY_ALL_INVERT (COMPHY_POLARITY_TXD_INVERT | \ COMPHY_POLARITY_RXD_INVERT) enum reg_width_type { REG_16BIT = 0, REG_32BIT, }; enum { COMPHY_LANE0 = 0, COMPHY_LANE1, COMPHY_LANE2, COMPHY_LANE3, COMPHY_LANE4, COMPHY_LANE5, COMPHY_LANE_MAX, }; static inline uint32_t polling_with_timeout(uintptr_t addr, uint32_t val, uint32_t mask, uint32_t usec_timeout, enum reg_width_type type) { uint32_t data; do { udelay(1); if (type == REG_16BIT) data = mmio_read_16(addr) & mask; else data = mmio_read_32(addr) & mask; } while (data != val && --usec_timeout > 0); if (usec_timeout == 0) return data; return 0; } static inline void reg_set(uintptr_t addr, uint32_t data, uint32_t mask) { debug(": WR to addr = 0x%lx, data = 0x%x (mask = 0x%x) - ", addr, data, mask); debug("old value = 0x%x ==> ", mmio_read_32(addr)); mmio_clrsetbits_32(addr, mask, data); debug("new val 0x%x\n", mmio_read_32(addr)); } static inline void __unused reg_set16(uintptr_t addr, uint16_t data, uint16_t mask) { debug(": WR to addr = 0x%lx, data = 0x%x (mask = 0x%x) - ", addr, data, mask); debug("old value = 0x%x ==> ", mmio_read_16(addr)); mmio_clrsetbits_16(addr, mask, data); debug("new val 0x%x\n", mmio_read_16(addr)); } #endif /* PHY_COMPHY_COMMON_H */ trusted-firmware-a-2.2/drivers/marvell/comphy/phy-comphy-cp110.c000066400000000000000000002553761355360272700246350ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* Marvell CP110 SoC COMPHY unit driver */ #include #include #include #include #include #include #include "mvebu.h" #include "comphy-cp110.h" #include "phy-comphy-cp110.h" #include "phy-comphy-common.h" #if __has_include("phy-porting-layer.h") #include "phy-porting-layer.h" #else #include "phy-default-porting-layer.h" #endif /* COMPHY speed macro */ #define COMPHY_SPEED_1_25G 0 /* SGMII 1G */ #define COMPHY_SPEED_2_5G 1 #define COMPHY_SPEED_3_125G 2 /* SGMII 2.5G */ #define COMPHY_SPEED_5G 3 #define COMPHY_SPEED_5_15625G 4 /* XFI 5G */ #define COMPHY_SPEED_6G 5 #define COMPHY_SPEED_10_3125G 6 /* XFI 10G */ #define COMPHY_SPEED_MAX 0x3F /* The default speed for IO with fixed known speed */ #define COMPHY_SPEED_DEFAULT COMPHY_SPEED_MAX /* Commands for comphy driver */ #define COMPHY_COMMAND_DIGITAL_PWR_OFF 0x00000001 #define COMPHY_COMMAND_DIGITAL_PWR_ON 0x00000002 #define COMPHY_PIPE_FROM_COMPHY_ADDR(x) ((x & ~0xffffff) + 0x120000) /* System controller registers */ #define PCIE_MAC_RESET_MASK_PORT0 BIT(13) #define PCIE_MAC_RESET_MASK_PORT1 BIT(11) #define PCIE_MAC_RESET_MASK_PORT2 BIT(12) #define SYS_CTRL_UINIT_SOFT_RESET_REG 0x268 #define SYS_CTRL_FROM_COMPHY_ADDR(x) ((x & ~0xffffff) + 0x440000) /* DFX register spaces */ #define SAR_RST_PCIE0_CLOCK_CONFIG_CP1_OFFSET (0) #define SAR_RST_PCIE0_CLOCK_CONFIG_CP1_MASK (0x1 << \ SAR_RST_PCIE0_CLOCK_CONFIG_CP1_OFFSET) #define SAR_RST_PCIE1_CLOCK_CONFIG_CP1_OFFSET (1) #define SAR_RST_PCIE1_CLOCK_CONFIG_CP1_MASK (0x1 << \ SAR_RST_PCIE1_CLOCK_CONFIG_CP1_OFFSET) #define SAR_STATUS_0_REG 200 #define DFX_FROM_COMPHY_ADDR(x) ((x & ~0xffffff) + DFX_BASE) /* The same Units Soft Reset Config register are accessed in all PCIe ports * initialization, so a spin lock is defined in case when more than 1 CPUs * resets PCIe MAC and need to access the register in the same time. The spin * lock is shared by all CP110 units. */ spinlock_t cp110_mac_reset_lock; /* These values come from the PCI Express Spec */ enum pcie_link_width { PCIE_LNK_WIDTH_RESRV = 0x00, PCIE_LNK_X1 = 0x01, PCIE_LNK_X2 = 0x02, PCIE_LNK_X4 = 0x04, PCIE_LNK_X8 = 0x08, PCIE_LNK_X12 = 0x0C, PCIE_LNK_X16 = 0x10, PCIE_LNK_X32 = 0x20, PCIE_LNK_WIDTH_UNKNOWN = 0xFF, }; _Bool rx_trainng_done[AP_NUM][CP_NUM][MAX_LANE_NR] = {0}; static void mvebu_cp110_get_ap_and_cp_nr(uint8_t *ap_nr, uint8_t *cp_nr, uint64_t comphy_base) { #if (AP_NUM == 1) *ap_nr = 0; #else *ap_nr = (((comphy_base & ~0xffffff) - MVEBU_AP_IO_BASE(0)) / AP_IO_OFFSET); #endif *cp_nr = (((comphy_base & ~0xffffff) - MVEBU_AP_IO_BASE(*ap_nr)) / MVEBU_CP_OFFSET); debug("cp_base 0x%llx, ap_io_base 0x%lx, cp_offset 0x%lx\n", comphy_base, (unsigned long)MVEBU_AP_IO_BASE(*ap_nr), (unsigned long)MVEBU_CP_OFFSET); } /* Clear PIPE selector - avoid collision with previous configuration */ static void mvebu_cp110_comphy_clr_pipe_selector(uint64_t comphy_base, uint8_t comphy_index) { uint32_t reg, mask, field; uint32_t comphy_offset = COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index; mask = COMMON_SELECTOR_COMPHY_MASK << comphy_offset; reg = mmio_read_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET); field = reg & mask; if (field) { reg &= ~mask; mmio_write_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET, reg); } } /* Clear PHY selector - avoid collision with previous configuration */ static void mvebu_cp110_comphy_clr_phy_selector(uint64_t comphy_base, uint8_t comphy_index) { uint32_t reg, mask, field; uint32_t comphy_offset = COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index; mask = COMMON_SELECTOR_COMPHY_MASK << comphy_offset; reg = mmio_read_32(comphy_base + COMMON_SELECTOR_PHY_REG_OFFSET); field = reg & mask; /* Clear comphy selector - if it was already configured. * (might be that this comphy was configured as PCIe/USB, * in such case, no need to clear comphy selector because PCIe/USB * are controlled by hpipe selector). */ if (field) { reg &= ~mask; mmio_write_32(comphy_base + COMMON_SELECTOR_PHY_REG_OFFSET, reg); } } /* PHY selector configures SATA and Network modes */ static void mvebu_cp110_comphy_set_phy_selector(uint64_t comphy_base, uint8_t comphy_index, uint32_t comphy_mode) { uint32_t reg, mask; uint32_t comphy_offset = COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index; int mode; /* If phy selector is used the pipe selector should be marked as * unconnected. */ mvebu_cp110_comphy_clr_pipe_selector(comphy_base, comphy_index); /* Comphy mode (compound of the IO mode and id). Here, only the IO mode * is required to distinguish between SATA and network modes. */ mode = COMPHY_GET_MODE(comphy_mode); mask = COMMON_SELECTOR_COMPHY_MASK << comphy_offset; reg = mmio_read_32(comphy_base + COMMON_SELECTOR_PHY_REG_OFFSET); reg &= ~mask; /* SATA port 0/1 require the same configuration */ if (mode == COMPHY_SATA_MODE) { /* SATA selector values is always 4 */ reg |= COMMON_SELECTOR_COMPHYN_SATA << comphy_offset; } else { switch (comphy_index) { case(0): case(1): case(2): /* For comphy 0,1, and 2: * Network selector value is always 1. */ reg |= COMMON_SELECTOR_COMPHY0_1_2_NETWORK << comphy_offset; break; case(3): /* For comphy 3: * 0x1 = RXAUI_Lane1 * 0x2 = SGMII/HS-SGMII Port1 */ if (mode == COMPHY_RXAUI_MODE) reg |= COMMON_SELECTOR_COMPHY3_RXAUI << comphy_offset; else reg |= COMMON_SELECTOR_COMPHY3_SGMII << comphy_offset; break; case(4): /* For comphy 4: * 0x1 = SGMII/HS-SGMII Port1, XFI1/SFI1 * 0x2 = SGMII/HS-SGMII Port0: XFI0/SFI0, RXAUI_Lane0 * * We want to check if SGMII1/HS_SGMII1 is the * requested mode in order to determine which value * should be set (all other modes use the same value) * so we need to strip the mode, and check the ID * because we might handle SGMII0/HS_SGMII0 too. */ /* TODO: need to distinguish between CP110 and CP115 * as SFI1/XFI1 available only for CP115. */ if ((mode == COMPHY_SGMII_MODE || mode == COMPHY_HS_SGMII_MODE || mode == COMPHY_SFI_MODE || mode == COMPHY_XFI_MODE) && COMPHY_GET_ID(comphy_mode) == 1) reg |= COMMON_SELECTOR_COMPHY4_PORT1 << comphy_offset; else reg |= COMMON_SELECTOR_COMPHY4_ALL_OTHERS << comphy_offset; break; case(5): /* For comphy 5: * 0x1 = SGMII/HS-SGMII Port2 * 0x2 = RXAUI Lane1 */ if (mode == COMPHY_RXAUI_MODE) reg |= COMMON_SELECTOR_COMPHY5_RXAUI << comphy_offset; else reg |= COMMON_SELECTOR_COMPHY5_SGMII << comphy_offset; break; } } mmio_write_32(comphy_base + COMMON_SELECTOR_PHY_REG_OFFSET, reg); } /* PIPE selector configures for PCIe, USB 3.0 Host, and USB 3.0 Device mode */ static void mvebu_cp110_comphy_set_pipe_selector(uint64_t comphy_base, uint8_t comphy_index, uint32_t comphy_mode) { uint32_t reg; uint32_t shift = COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index; int mode = COMPHY_GET_MODE(comphy_mode); uint32_t mask = COMMON_SELECTOR_COMPHY_MASK << shift; uint32_t pipe_sel = 0x0; /* If pipe selector is used the phy selector should be marked as * unconnected. */ mvebu_cp110_comphy_clr_phy_selector(comphy_base, comphy_index); reg = mmio_read_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET); reg &= ~mask; switch (mode) { case (COMPHY_PCIE_MODE): /* For lanes support PCIE, selector value are all same */ pipe_sel = COMMON_SELECTOR_PIPE_COMPHY_PCIE; break; case (COMPHY_USB3H_MODE): /* Only lane 1-4 support USB host, selector value is same */ if (comphy_index == COMPHY_LANE0 || comphy_index == COMPHY_LANE5) ERROR("COMPHY[%d] mode[%d] is invalid\n", comphy_index, mode); else pipe_sel = COMMON_SELECTOR_PIPE_COMPHY_USBH; break; case (COMPHY_USB3D_MODE): /* Lane 1 and 4 support USB device, selector value is same */ if (comphy_index == COMPHY_LANE1 || comphy_index == COMPHY_LANE4) pipe_sel = COMMON_SELECTOR_PIPE_COMPHY_USBD; else ERROR("COMPHY[%d] mode[%d] is invalid\n", comphy_index, mode); break; default: ERROR("COMPHY[%d] mode[%d] is invalid\n", comphy_index, mode); break; } mmio_write_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET, reg | (pipe_sel << shift)); } int mvebu_cp110_comphy_is_pll_locked(uint64_t comphy_base, uint8_t comphy_index) { uintptr_t sd_ip_addr, addr; uint32_t mask, data; int ret = 0; debug_enter(); sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), comphy_index); addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG; data = SD_EXTERNAL_STATUS0_PLL_TX_MASK & SD_EXTERNAL_STATUS0_PLL_RX_MASK; mask = data; data = polling_with_timeout(addr, data, mask, PLL_LOCK_TIMEOUT, REG_32BIT); if (data != 0) { if (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK) ERROR("RX PLL is not locked\n"); if (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK) ERROR("TX PLL is not locked\n"); ret = -ETIMEDOUT; } debug_exit(); return ret; } static int mvebu_cp110_comphy_sata_power_on(uint64_t comphy_base, uint8_t comphy_index, uint32_t comphy_mode) { uintptr_t hpipe_addr, sd_ip_addr, comphy_addr; uint32_t mask, data; uint8_t ap_nr, cp_nr; int ret = 0; debug_enter(); mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base); const struct sata_params *sata_static_values = &sata_static_values_tab[ap_nr][cp_nr][comphy_index]; /* configure phy selector for SATA */ mvebu_cp110_comphy_set_phy_selector(comphy_base, comphy_index, comphy_mode); hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), comphy_index); sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), comphy_index); comphy_addr = COMPHY_ADDR(comphy_base, comphy_index); debug(" add hpipe 0x%lx, sd 0x%lx, comphy 0x%lx\n", hpipe_addr, sd_ip_addr, comphy_addr); debug("stage: RFU configurations - hard reset comphy\n"); /* RFU configurations - hard reset comphy */ mask = COMMON_PHY_CFG1_PWR_UP_MASK; data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK; data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); /* Set select data width 40Bit - SATA mode only */ reg_set(comphy_addr + COMMON_PHY_CFG6_REG, 0x1 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET, COMMON_PHY_CFG6_IF_40_SEL_MASK); /* release from hard reset in SD external */ mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); /* Wait 1ms - until band gap and ref clock ready */ mdelay(1); debug("stage: Comphy configuration\n"); /* Start comphy Configuration */ /* Set reference clock to comes from group 1 - choose 25Mhz */ reg_set(hpipe_addr + HPIPE_MISC_REG, 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET, HPIPE_MISC_REFCLK_SEL_MASK); /* Reference frequency select set 1 (for SATA = 25Mhz) */ mask = HPIPE_PWR_PLL_REF_FREQ_MASK; data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; /* PHY mode select (set SATA = 0x0 */ mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; data |= 0x0 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask); /* Set max PHY generation setting - 6Gbps */ reg_set(hpipe_addr + HPIPE_INTERFACE_REG, 0x2 << HPIPE_INTERFACE_GEN_MAX_OFFSET, HPIPE_INTERFACE_GEN_MAX_MASK); /* Set select data width 40Bit (SEL_BITS[2:0]) */ reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, 0x2 << HPIPE_LOOPBACK_SEL_OFFSET, HPIPE_LOOPBACK_SEL_MASK); debug("stage: Analog parameters from ETP(HW)\n"); /* G1 settings */ mask = HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK; data = sata_static_values->g1_rx_selmupi << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET; mask |= HPIPE_G1_SET_1_G1_RX_SELMUPF_MASK; data |= sata_static_values->g1_rx_selmupf << HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET; mask |= HPIPE_G1_SET_1_G1_RX_SELMUFI_MASK; data |= sata_static_values->g1_rx_selmufi << HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET; mask |= HPIPE_G1_SET_1_G1_RX_SELMUFF_MASK; data |= sata_static_values->g1_rx_selmuff << HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET; mask |= HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_MASK; data |= 0x1 << HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask); mask = HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK; data = 0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET; mask |= HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK; data |= 0x2 << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET; mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK; data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET; mask |= HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_MASK; data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_DEG_RES_LEVEL_OFFSET; mask |= HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_MASK; data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_LOAD_RES_LEVEL_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask); /* G2 settings */ mask = HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK; data = sata_static_values->g2_rx_selmupi << HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET; mask |= HPIPE_G2_SET_1_G2_RX_SELMUPF_MASK; data |= sata_static_values->g2_rx_selmupf << HPIPE_G2_SET_1_G2_RX_SELMUPF_OFFSET; mask |= HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK; data |= sata_static_values->g2_rx_selmufi << HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET; mask |= HPIPE_G2_SET_1_G2_RX_SELMUFF_MASK; data |= sata_static_values->g2_rx_selmuff << HPIPE_G2_SET_1_G2_RX_SELMUFF_OFFSET; mask |= HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_MASK; data |= 0x1 << HPIPE_G2_SET_1_G2_RX_DIGCK_DIV_OFFSET; reg_set(hpipe_addr + HPIPE_G2_SET_1_REG, data, mask); /* G3 settings */ mask = HPIPE_G3_SET_1_G3_RX_SELMUPI_MASK; data = sata_static_values->g3_rx_selmupi << HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET; mask |= HPIPE_G3_SET_1_G3_RX_SELMUPF_MASK; data |= sata_static_values->g3_rx_selmupf << HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET; mask |= HPIPE_G3_SET_1_G3_RX_SELMUFI_MASK; data |= sata_static_values->g3_rx_selmufi << HPIPE_G3_SET_1_G3_RX_SELMUFI_OFFSET; mask |= HPIPE_G3_SET_1_G3_RX_SELMUFF_MASK; data |= sata_static_values->g3_rx_selmuff << HPIPE_G3_SET_1_G3_RX_SELMUFF_OFFSET; mask |= HPIPE_G3_SET_1_G3_RX_DFE_EN_MASK; data |= 0x1 << HPIPE_G3_SET_1_G3_RX_DFE_EN_OFFSET; mask |= HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_MASK; data |= 0x2 << HPIPE_G3_SET_1_G3_RX_DIGCK_DIV_OFFSET; mask |= HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_MASK; data |= 0x0 << HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET; reg_set(hpipe_addr + HPIPE_G3_SET_1_REG, data, mask); /* DTL Control */ mask = HPIPE_PWR_CTR_DTL_SQ_DET_EN_MASK; data = 0x1 << HPIPE_PWR_CTR_DTL_SQ_DET_EN_OFFSET; mask |= HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_MASK; data |= 0x1 << HPIPE_PWR_CTR_DTL_SQ_PLOOP_EN_OFFSET; mask |= HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK; data |= 0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET; mask |= HPIPE_PWR_CTR_DTL_CLAMPING_SEL_MASK; data |= 0x1 << HPIPE_PWR_CTR_DTL_CLAMPING_SEL_OFFSET; mask |= HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_MASK; data |= 0x1 << HPIPE_PWR_CTR_DTL_INTPCLK_DIV_FORCE_OFFSET; mask |= HPIPE_PWR_CTR_DTL_CLK_MODE_MASK; data |= 0x1 << HPIPE_PWR_CTR_DTL_CLK_MODE_OFFSET; mask |= HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_MASK; data |= 0x1 << HPIPE_PWR_CTR_DTL_CLK_MODE_FORCE_OFFSET; reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask); /* Trigger sampler enable pulse */ mask = HPIPE_SMAPLER_MASK; data = 0x1 << HPIPE_SMAPLER_OFFSET; reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask); mask = HPIPE_SMAPLER_MASK; data = 0x0 << HPIPE_SMAPLER_OFFSET; reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask); /* VDD Calibration Control 3 */ mask = HPIPE_EXT_SELLV_RXSAMPL_MASK; data = 0x10 << HPIPE_EXT_SELLV_RXSAMPL_OFFSET; reg_set(hpipe_addr + HPIPE_VDD_CAL_CTRL_REG, data, mask); /* DFE Resolution Control */ mask = HPIPE_DFE_RES_FORCE_MASK; data = 0x1 << HPIPE_DFE_RES_FORCE_OFFSET; reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask); /* DFE F3-F5 Coefficient Control */ mask = HPIPE_DFE_F3_F5_DFE_EN_MASK; data = 0x0 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET; mask |= HPIPE_DFE_F3_F5_DFE_CTRL_MASK; data = 0x0 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET; reg_set(hpipe_addr + HPIPE_DFE_F3_F5_REG, data, mask); /* G3 Setting 3 */ mask = HPIPE_G3_FFE_CAP_SEL_MASK; data = sata_static_values->g3_ffe_cap_sel << HPIPE_G3_FFE_CAP_SEL_OFFSET; mask |= HPIPE_G3_FFE_RES_SEL_MASK; data |= sata_static_values->g3_ffe_res_sel << HPIPE_G3_FFE_RES_SEL_OFFSET; mask |= HPIPE_G3_FFE_SETTING_FORCE_MASK; data |= 0x1 << HPIPE_G3_FFE_SETTING_FORCE_OFFSET; mask |= HPIPE_G3_FFE_DEG_RES_LEVEL_MASK; data |= 0x1 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET; mask |= HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK; data |= 0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET; reg_set(hpipe_addr + HPIPE_G3_SETTING_3_REG, data, mask); /* G3 Setting 4 */ mask = HPIPE_G3_DFE_RES_MASK; data = sata_static_values->g3_dfe_res << HPIPE_G3_DFE_RES_OFFSET; reg_set(hpipe_addr + HPIPE_G3_SETTING_4_REG, data, mask); /* Offset Phase Control */ mask = HPIPE_OS_PH_OFFSET_MASK; data = sata_static_values->align90 << HPIPE_OS_PH_OFFSET_OFFSET; mask |= HPIPE_OS_PH_OFFSET_FORCE_MASK; data |= 0x1 << HPIPE_OS_PH_OFFSET_FORCE_OFFSET; mask |= HPIPE_OS_PH_VALID_MASK; data |= 0x0 << HPIPE_OS_PH_VALID_OFFSET; reg_set(hpipe_addr + HPIPE_PHASE_CONTROL_REG, data, mask); mask = HPIPE_OS_PH_VALID_MASK; data = 0x1 << HPIPE_OS_PH_VALID_OFFSET; reg_set(hpipe_addr + HPIPE_PHASE_CONTROL_REG, data, mask); mask = HPIPE_OS_PH_VALID_MASK; data = 0x0 << HPIPE_OS_PH_VALID_OFFSET; reg_set(hpipe_addr + HPIPE_PHASE_CONTROL_REG, data, mask); /* Set G1 TX amplitude and TX post emphasis value */ mask = HPIPE_G1_SET_0_G1_TX_AMP_MASK; data = sata_static_values->g1_amp << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET; mask |= HPIPE_G1_SET_0_G1_TX_AMP_ADJ_MASK; data |= sata_static_values->g1_tx_amp_adj << HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET; mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_MASK; data |= sata_static_values->g1_emph << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET; mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_EN_MASK; data |= sata_static_values->g1_emph_en << HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, data, mask); /* Set G1 emph */ mask = HPIPE_G1_SET_2_G1_TX_EMPH0_EN_MASK; data = sata_static_values->g1_tx_emph_en << HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET; mask |= HPIPE_G1_SET_2_G1_TX_EMPH0_MASK; data |= sata_static_values->g1_tx_emph << HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SET_2_REG, data, mask); /* Set G2 TX amplitude and TX post emphasis value */ mask = HPIPE_G2_SET_0_G2_TX_AMP_MASK; data = sata_static_values->g2_amp << HPIPE_G2_SET_0_G2_TX_AMP_OFFSET; mask |= HPIPE_G2_SET_0_G2_TX_AMP_ADJ_MASK; data |= sata_static_values->g2_tx_amp_adj << HPIPE_G2_SET_0_G2_TX_AMP_ADJ_OFFSET; mask |= HPIPE_G2_SET_0_G2_TX_EMPH1_MASK; data |= sata_static_values->g2_emph << HPIPE_G2_SET_0_G2_TX_EMPH1_OFFSET; mask |= HPIPE_G2_SET_0_G2_TX_EMPH1_EN_MASK; data |= sata_static_values->g2_emph_en << HPIPE_G2_SET_0_G2_TX_EMPH1_EN_OFFSET; reg_set(hpipe_addr + HPIPE_G2_SET_0_REG, data, mask); /* Set G2 emph */ mask = HPIPE_G2_SET_2_G2_TX_EMPH0_EN_MASK; data = sata_static_values->g2_tx_emph_en << HPIPE_G2_SET_2_G2_TX_EMPH0_EN_OFFSET; mask |= HPIPE_G2_SET_2_G2_TX_EMPH0_MASK; data |= sata_static_values->g2_tx_emph << HPIPE_G2_SET_2_G2_TX_EMPH0_OFFSET; reg_set(hpipe_addr + HPIPE_G2_SET_2_REG, data, mask); /* Set G3 TX amplitude and TX post emphasis value */ mask = HPIPE_G3_SET_0_G3_TX_AMP_MASK; data = sata_static_values->g3_amp << HPIPE_G3_SET_0_G3_TX_AMP_OFFSET; mask |= HPIPE_G3_SET_0_G3_TX_AMP_ADJ_MASK; data |= sata_static_values->g3_tx_amp_adj << HPIPE_G3_SET_0_G3_TX_AMP_ADJ_OFFSET; mask |= HPIPE_G3_SET_0_G3_TX_EMPH1_MASK; data |= sata_static_values->g3_emph << HPIPE_G3_SET_0_G3_TX_EMPH1_OFFSET; mask |= HPIPE_G3_SET_0_G3_TX_EMPH1_EN_MASK; data |= sata_static_values->g3_emph_en << HPIPE_G3_SET_0_G3_TX_EMPH1_EN_OFFSET; mask |= HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_MASK; data |= 0x4 << HPIPE_G3_SET_0_G3_TX_SLEW_RATE_SEL_OFFSET; mask |= HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_MASK; data |= 0x0 << HPIPE_G3_SET_0_G3_TX_SLEW_CTRL_EN_OFFSET; reg_set(hpipe_addr + HPIPE_G3_SET_0_REG, data, mask); /* Set G3 emph */ mask = HPIPE_G3_SET_2_G3_TX_EMPH0_EN_MASK; data = sata_static_values->g3_tx_emph_en << HPIPE_G3_SET_2_G3_TX_EMPH0_EN_OFFSET; mask |= HPIPE_G3_SET_2_G3_TX_EMPH0_MASK; data |= sata_static_values->g3_tx_emph << HPIPE_G3_SET_2_G3_TX_EMPH0_OFFSET; reg_set(hpipe_addr + HPIPE_G3_SET_2_REG, data, mask); /* SERDES External Configuration 2 register */ mask = SD_EXTERNAL_CONFIG2_SSC_ENABLE_MASK; data = 0x1 << SD_EXTERNAL_CONFIG2_SSC_ENABLE_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG2_REG, data, mask); /* DFE reset sequence */ reg_set(hpipe_addr + HPIPE_PWR_CTR_REG, 0x1 << HPIPE_PWR_CTR_RST_DFE_OFFSET, HPIPE_PWR_CTR_RST_DFE_MASK); reg_set(hpipe_addr + HPIPE_PWR_CTR_REG, 0x0 << HPIPE_PWR_CTR_RST_DFE_OFFSET, HPIPE_PWR_CTR_RST_DFE_MASK); /* SW reset for interrupt logic */ reg_set(hpipe_addr + HPIPE_PWR_CTR_REG, 0x1 << HPIPE_PWR_CTR_SFT_RST_OFFSET, HPIPE_PWR_CTR_SFT_RST_MASK); reg_set(hpipe_addr + HPIPE_PWR_CTR_REG, 0x0 << HPIPE_PWR_CTR_SFT_RST_OFFSET, HPIPE_PWR_CTR_SFT_RST_MASK); debug_exit(); return ret; } static int mvebu_cp110_comphy_sgmii_power_on(uint64_t comphy_base, uint8_t comphy_index, uint32_t comphy_mode) { uintptr_t hpipe_addr, sd_ip_addr, comphy_addr, addr; uint32_t mask, data, sgmii_speed = COMPHY_GET_SPEED(comphy_mode); int ret = 0; debug_enter(); hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), comphy_index); sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), comphy_index); comphy_addr = COMPHY_ADDR(comphy_base, comphy_index); /* configure phy selector for SGMII */ mvebu_cp110_comphy_set_phy_selector(comphy_base, comphy_index, comphy_mode); /* Confiugre the lane */ debug("stage: RFU configurations - hard reset comphy\n"); /* RFU configurations - hard reset comphy */ mask = COMMON_PHY_CFG1_PWR_UP_MASK; data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); /* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */ mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK; data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET; mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK; mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK; if (sgmii_speed == COMPHY_SPEED_1_25G) { /* SGMII 1G, SerDes speed 1.25G */ data |= 0x6 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET; data |= 0x6 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET; } else if (sgmii_speed == COMPHY_SPEED_3_125G) { /* HS SGMII (2.5G), SerDes speed 3.125G */ data |= 0x8 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET; data |= 0x8 << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET; } else { /* Other rates are not supported */ ERROR("unsupported SGMII speed on comphy%d\n", comphy_index); return -EINVAL; } mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK; data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET; mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK; data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET; mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK; data |= 1 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask); /* Set hard reset */ mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); /* Release hard reset */ mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); /* Wait 1ms - until band gap and ref clock ready */ mdelay(1); /* Make sure that 40 data bits is disabled * This bit is not cleared by reset */ mask = COMMON_PHY_CFG6_IF_40_SEL_MASK; data = 0 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET; reg_set(comphy_addr + COMMON_PHY_CFG6_REG, data, mask); /* Start comphy Configuration */ debug("stage: Comphy configuration\n"); /* set reference clock */ mask = HPIPE_MISC_REFCLK_SEL_MASK; data = 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET; reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask); /* Power and PLL Control */ mask = HPIPE_PWR_PLL_REF_FREQ_MASK; data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask); /* Loopback register */ mask = HPIPE_LOOPBACK_SEL_MASK; data = 0x1 << HPIPE_LOOPBACK_SEL_OFFSET; reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, data, mask); /* rx control 1 */ mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK; data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET; mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK; data |= 0x0 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET; reg_set(hpipe_addr + HPIPE_RX_CONTROL_1_REG, data, mask); /* DTL Control */ mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK; data = 0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET; reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask); /* Set analog parameters from ETP(HW) - for now use the default data */ debug("stage: Analog parameters from ETP(HW)\n"); reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, 0x1 << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET, HPIPE_G1_SET_0_G1_TX_EMPH1_MASK); debug("stage: RFU configurations- Power Up PLL,Tx,Rx\n"); /* SERDES External Configuration */ mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK; data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET; mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK; data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET; mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK; data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask); ret = mvebu_cp110_comphy_is_pll_locked(comphy_base, comphy_index); if (ret) return ret; /* RX init */ mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK; data = 0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); /* check that RX init done */ addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG; data = SD_EXTERNAL_STATUS0_RX_INIT_MASK; mask = data; data = polling_with_timeout(addr, data, mask, 100, REG_32BIT); if (data != 0) { ERROR("RX init failed\n"); ret = -ETIMEDOUT; } debug("stage: RF Reset\n"); /* RF Reset */ mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK; data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); debug_exit(); return ret; } static int mvebu_cp110_comphy_xfi_power_on(uint64_t comphy_base, uint8_t comphy_index, uint32_t comphy_mode) { uintptr_t hpipe_addr, sd_ip_addr, comphy_addr, addr; uint32_t mask, data, speed = COMPHY_GET_SPEED(comphy_mode); int ret = 0; uint8_t ap_nr, cp_nr; debug_enter(); mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base); if (rx_trainng_done[ap_nr][cp_nr][comphy_index]) { debug("Skip %s for comphy[%d][%d][%d], due to rx training\n", __func__, ap_nr, cp_nr, comphy_index); return 0; } const struct xfi_params *xfi_static_values = &xfi_static_values_tab[ap_nr][cp_nr][comphy_index]; debug("%s: the ap_nr = %d, cp_nr = %d, comphy_index %d\n", __func__, ap_nr, cp_nr, comphy_index); debug("g1_ffe_cap_sel= 0x%x, g1_ffe_res_sel= 0x%x, g1_dfe_res= 0x%x\n", xfi_static_values->g1_ffe_cap_sel, xfi_static_values->g1_ffe_res_sel, xfi_static_values->g1_dfe_res); if (!xfi_static_values->valid) { ERROR("[ap%d][cp[%d][comphy:%d]: Has no valid static params\n", ap_nr, cp_nr, comphy_index); ERROR("[ap%d][cp[%d][comphy:%d]: porting layer needs update\n", ap_nr, cp_nr, comphy_index); return -EINVAL; } if ((speed != COMPHY_SPEED_5_15625G) && (speed != COMPHY_SPEED_10_3125G) && (speed != COMPHY_SPEED_DEFAULT)) { ERROR("comphy:%d: unsupported sfi/xfi speed\n", comphy_index); return -EINVAL; } hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), comphy_index); sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), comphy_index); comphy_addr = COMPHY_ADDR(comphy_base, comphy_index); /* configure phy selector for XFI/SFI */ mvebu_cp110_comphy_set_phy_selector(comphy_base, comphy_index, comphy_mode); debug("stage: RFU configurations - hard reset comphy\n"); /* RFU configurations - hard reset comphy */ mask = COMMON_PHY_CFG1_PWR_UP_MASK; data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); /* Make sure that 40 data bits is disabled * This bit is not cleared by reset */ mask = COMMON_PHY_CFG6_IF_40_SEL_MASK; data = 0 << COMMON_PHY_CFG6_IF_40_SEL_OFFSET; reg_set(comphy_addr + COMMON_PHY_CFG6_REG, data, mask); /* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */ mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK; data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET; mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK; data |= 0xE << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET; mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK; data |= 0xE << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET; mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK; data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET; mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK; data |= 0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET; mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK; data |= 0 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask); /* release from hard reset */ mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); /* Wait 1ms - until band gap and ref clock ready */ mdelay(1); /* Start comphy Configuration */ debug("stage: Comphy configuration\n"); /* set reference clock */ mask = HPIPE_MISC_ICP_FORCE_MASK; data = (speed == COMPHY_SPEED_5_15625G) ? (0x0 << HPIPE_MISC_ICP_FORCE_OFFSET) : (0x1 << HPIPE_MISC_ICP_FORCE_OFFSET); mask |= HPIPE_MISC_REFCLK_SEL_MASK; data |= 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET; reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask); /* Power and PLL Control */ mask = HPIPE_PWR_PLL_REF_FREQ_MASK; data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask); /* Loopback register */ mask = HPIPE_LOOPBACK_SEL_MASK; data = 0x1 << HPIPE_LOOPBACK_SEL_OFFSET; reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, data, mask); /* rx control 1 */ mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK; data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET; mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK; data |= 0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET; reg_set(hpipe_addr + HPIPE_RX_CONTROL_1_REG, data, mask); /* DTL Control */ mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK; data = 0x1 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET; reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask); /* Transmitter/Receiver Speed Divider Force */ if (speed == COMPHY_SPEED_5_15625G) { mask = HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_MASK; data = 1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_OFFSET; mask |= HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_MASK; data |= 1 << HPIPE_SPD_DIV_FORCE_RX_SPD_DIV_FORCE_OFFSET; mask |= HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_MASK; data |= 1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_OFFSET; mask |= HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_MASK; data |= 1 << HPIPE_SPD_DIV_FORCE_TX_SPD_DIV_FORCE_OFFSET; } else { mask = HPIPE_TXDIGCK_DIV_FORCE_MASK; data = 0x1 << HPIPE_TXDIGCK_DIV_FORCE_OFFSET; } reg_set(hpipe_addr + HPIPE_SPD_DIV_FORCE_REG, data, mask); /* Set analog parameters from ETP(HW) */ debug("stage: Analog parameters from ETP(HW)\n"); /* SERDES External Configuration 2 */ mask = SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK; data = 0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG2_REG, data, mask); /* 0x7-DFE Resolution control */ mask = HPIPE_DFE_RES_FORCE_MASK; data = 0x1 << HPIPE_DFE_RES_FORCE_OFFSET; reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask); /* 0xd-G1_Setting_0 */ if (speed == COMPHY_SPEED_5_15625G) { mask = HPIPE_G1_SET_0_G1_TX_EMPH1_MASK; data = 0x6 << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET; } else { mask = HPIPE_G1_SET_0_G1_TX_AMP_MASK; data = xfi_static_values->g1_amp << HPIPE_G1_SET_0_G1_TX_AMP_OFFSET; mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_MASK; data |= xfi_static_values->g1_emph << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET; mask |= HPIPE_G1_SET_0_G1_TX_EMPH1_EN_MASK; data |= xfi_static_values->g1_emph_en << HPIPE_G1_SET_0_G1_TX_EMPH1_EN_OFFSET; mask |= HPIPE_G1_SET_0_G1_TX_AMP_ADJ_MASK; data |= xfi_static_values->g1_tx_amp_adj << HPIPE_G1_SET_0_G1_TX_AMP_ADJ_OFFSET; } reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, data, mask); /* Genration 1 setting 2 (G1_Setting_2) */ mask = HPIPE_G1_SET_2_G1_TX_EMPH0_MASK; data = xfi_static_values->g1_tx_emph << HPIPE_G1_SET_2_G1_TX_EMPH0_OFFSET; mask |= HPIPE_G1_SET_2_G1_TX_EMPH0_EN_MASK; data |= xfi_static_values->g1_tx_emph_en << HPIPE_G1_SET_2_G1_TX_EMPH0_EN_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SET_2_REG, data, mask); /* Transmitter Slew Rate Control register (tx_reg1) */ mask = HPIPE_TX_REG1_TX_EMPH_RES_MASK; data = 0x3 << HPIPE_TX_REG1_TX_EMPH_RES_OFFSET; mask |= HPIPE_TX_REG1_SLC_EN_MASK; data |= 0x3f << HPIPE_TX_REG1_SLC_EN_OFFSET; reg_set(hpipe_addr + HPIPE_TX_REG1_REG, data, mask); /* Impedance Calibration Control register (cal_reg1) */ mask = HPIPE_CAL_REG_1_EXT_TXIMP_MASK; data = 0xe << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET; mask |= HPIPE_CAL_REG_1_EXT_TXIMP_EN_MASK; data |= 0x1 << HPIPE_CAL_REG_1_EXT_TXIMP_EN_OFFSET; reg_set(hpipe_addr + HPIPE_CAL_REG1_REG, data, mask); /* Generation 1 Setting 5 (g1_setting_5) */ mask = HPIPE_G1_SETTING_5_G1_ICP_MASK; data = 0 << HPIPE_CAL_REG_1_EXT_TXIMP_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SETTING_5_REG, data, mask); /* 0xE-G1_Setting_1 */ mask = HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK; data = 0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET; if (speed == COMPHY_SPEED_5_15625G) { mask |= HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK; data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET; mask |= HPIPE_G1_SET_1_G1_RX_SELMUPF_MASK; data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET; } else { mask |= HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK; data |= xfi_static_values->g1_rx_selmupi << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET; mask |= HPIPE_G1_SET_1_G1_RX_SELMUPF_MASK; data |= xfi_static_values->g1_rx_selmupf << HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET; mask |= HPIPE_G1_SET_1_G1_RX_SELMUFI_MASK; data |= xfi_static_values->g1_rx_selmufi << HPIPE_G1_SET_1_G1_RX_SELMUFI_OFFSET; mask |= HPIPE_G1_SET_1_G1_RX_SELMUFF_MASK; data |= xfi_static_values->g1_rx_selmuff << HPIPE_G1_SET_1_G1_RX_SELMUFF_OFFSET; mask |= HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_MASK; data |= 0x3 << HPIPE_G1_SET_1_G1_RX_DIGCK_DIV_OFFSET; } reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask); /* 0xA-DFE_Reg3 */ mask = HPIPE_DFE_F3_F5_DFE_EN_MASK; data = 0x0 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET; mask |= HPIPE_DFE_F3_F5_DFE_CTRL_MASK; data |= 0x0 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET; reg_set(hpipe_addr + HPIPE_DFE_F3_F5_REG, data, mask); /* 0x111-G1_Setting_4 */ mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK; data = 0x1 << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask); /* Genration 1 setting 3 (G1_Setting_3) */ mask = HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_MASK; data = 0x1 << HPIPE_G1_SETTINGS_3_G1_FBCK_SEL_OFFSET; if (speed == COMPHY_SPEED_5_15625G) { /* Force FFE (Feed Forward Equalization) to 5G */ mask |= HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK; data |= 0xf << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET; mask |= HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK; data |= 0x4 << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET; mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK; data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask); } else { mask |= HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK; data |= xfi_static_values->g1_ffe_cap_sel << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET; mask |= HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK; data |= xfi_static_values->g1_ffe_res_sel << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET; mask |= HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK; data |= 0x1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask); /* Use the value from CAL_OS_PH_EXT */ mask = HPIPE_CAL_RXCLKALIGN_90_EXT_EN_MASK; data = 1 << HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET; reg_set(hpipe_addr + HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG, data, mask); /* Update align90 */ mask = HPIPE_CAL_OS_PH_EXT_MASK; data = xfi_static_values->align90 << HPIPE_CAL_OS_PH_EXT_OFFSET; reg_set(hpipe_addr + HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG, data, mask); /* Force DFE resolution (use gen table value) */ mask = HPIPE_DFE_RES_FORCE_MASK; data = 0x0 << HPIPE_DFE_RES_FORCE_OFFSET; reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask); /* 0x111-G1 DFE_Setting_4 */ mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK; data = xfi_static_values->g1_dfe_res << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask); } /* Connfigure RX training timer */ mask = HPIPE_RX_TRAIN_TIMER_MASK; data = 0x13 << HPIPE_RX_TRAIN_TIMER_OFFSET; reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_5_REG, data, mask); /* Enable TX train peak to peak hold */ mask = HPIPE_TX_TRAIN_P2P_HOLD_MASK; data = 0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET; reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_0_REG, data, mask); /* Configure TX preset index */ mask = HPIPE_TX_PRESET_INDEX_MASK; data = 0x2 << HPIPE_TX_PRESET_INDEX_OFFSET; reg_set(hpipe_addr + HPIPE_TX_PRESET_INDEX_REG, data, mask); /* Disable pattern lock lost timeout */ mask = HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK; data = 0x0 << HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET; reg_set(hpipe_addr + HPIPE_FRAME_DETECT_CTRL_3_REG, data, mask); /* Configure TX training pattern and TX training 16bit auto */ mask = HPIPE_TX_TRAIN_16BIT_AUTO_EN_MASK; data = 0x1 << HPIPE_TX_TRAIN_16BIT_AUTO_EN_OFFSET; mask |= HPIPE_TX_TRAIN_PAT_SEL_MASK; data |= 0x1 << HPIPE_TX_TRAIN_PAT_SEL_OFFSET; reg_set(hpipe_addr + HPIPE_TX_TRAIN_REG, data, mask); /* Configure Training patten number */ mask = HPIPE_TRAIN_PAT_NUM_MASK; data = 0x88 << HPIPE_TRAIN_PAT_NUM_OFFSET; reg_set(hpipe_addr + HPIPE_FRAME_DETECT_CTRL_0_REG, data, mask); /* Configure differencial manchester encoter to ethernet mode */ mask = HPIPE_DME_ETHERNET_MODE_MASK; data = 0x1 << HPIPE_DME_ETHERNET_MODE_OFFSET; reg_set(hpipe_addr + HPIPE_DME_REG, data, mask); /* Configure VDD Continuous Calibration */ mask = HPIPE_CAL_VDD_CONT_MODE_MASK; data = 0x1 << HPIPE_CAL_VDD_CONT_MODE_OFFSET; reg_set(hpipe_addr + HPIPE_VDD_CAL_0_REG, data, mask); /* Trigger sampler enable pulse (by toggleing the bit) */ mask = HPIPE_RX_SAMPLER_OS_GAIN_MASK; data = 0x3 << HPIPE_RX_SAMPLER_OS_GAIN_OFFSET; mask |= HPIPE_SMAPLER_MASK; data |= 0x1 << HPIPE_SMAPLER_OFFSET; reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask); mask = HPIPE_SMAPLER_MASK; data = 0x0 << HPIPE_SMAPLER_OFFSET; reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask); /* Set External RX Regulator Control */ mask = HPIPE_EXT_SELLV_RXSAMPL_MASK; data = 0x1A << HPIPE_EXT_SELLV_RXSAMPL_OFFSET; reg_set(hpipe_addr + HPIPE_VDD_CAL_CTRL_REG, data, mask); debug("stage: RFU configurations- Power Up PLL,Tx,Rx\n"); /* SERDES External Configuration */ mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK; data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET; mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK; data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET; mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK; data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask); /* check PLL rx & tx ready */ addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG; data = SD_EXTERNAL_STATUS0_PLL_RX_MASK | SD_EXTERNAL_STATUS0_PLL_TX_MASK; mask = data; data = polling_with_timeout(addr, data, mask, PLL_LOCK_TIMEOUT, REG_32BIT); if (data != 0) { if (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK) ERROR("RX PLL is not locked\n"); if (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK) ERROR("TX PLL is not locked\n"); ret = -ETIMEDOUT; } /* RX init */ mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK; data = 0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); /* check that RX init done */ addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG; data = SD_EXTERNAL_STATUS0_RX_INIT_MASK; mask = data; data = polling_with_timeout(addr, data, mask, 100, REG_32BIT); if (data != 0) { ERROR("RX init failed\n"); ret = -ETIMEDOUT; } debug("stage: RF Reset\n"); /* RF Reset */ mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK; data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); debug_exit(); return ret; } static int mvebu_cp110_comphy_pcie_power_on(uint64_t comphy_base, uint8_t comphy_index, uint32_t comphy_mode) { int ret = 0; uint32_t reg, mask, data, pcie_width; uint32_t clk_dir; uintptr_t hpipe_addr, comphy_addr, addr; _Bool clk_src = COMPHY_GET_CLK_SRC(comphy_mode); _Bool called_from_uboot = COMPHY_GET_CALLER(comphy_mode); /* In Armada 8K DB boards, PCIe initialization can be executed * only once (PCIe reset performed during chip power on and * it cannot be executed via GPIO later). * This means that power on can be executed only once, so let's * mark if the caller is bootloader or Linux. * If bootloader -> run power on. * If Linux -> exit. * * TODO: In MacciatoBIN, PCIe reset is connected via GPIO, * so after GPIO reset is added to Linux Kernel, it can be * powered-on by Linux. */ if (!called_from_uboot) return ret; hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), comphy_index); comphy_addr = COMPHY_ADDR(comphy_base, comphy_index); pcie_width = COMPHY_GET_PCIE_WIDTH(comphy_mode); debug_enter(); spin_lock(&cp110_mac_reset_lock); reg = mmio_read_32(SYS_CTRL_FROM_COMPHY_ADDR(comphy_base) + SYS_CTRL_UINIT_SOFT_RESET_REG); switch (comphy_index) { case COMPHY_LANE0: reg |= PCIE_MAC_RESET_MASK_PORT0; break; case COMPHY_LANE4: reg |= PCIE_MAC_RESET_MASK_PORT1; break; case COMPHY_LANE5: reg |= PCIE_MAC_RESET_MASK_PORT2; break; } mmio_write_32(SYS_CTRL_FROM_COMPHY_ADDR(comphy_base) + SYS_CTRL_UINIT_SOFT_RESET_REG, reg); spin_unlock(&cp110_mac_reset_lock); /* Configure PIPE selector for PCIE */ mvebu_cp110_comphy_set_pipe_selector(comphy_base, comphy_index, comphy_mode); /* * Read SAR (Sample-At-Reset) configuration for the PCIe clock * direction. * * SerDes Lane 4/5 got the PCIe ref-clock #1, * and SerDes Lane 0 got PCIe ref-clock #0 */ reg = mmio_read_32(DFX_FROM_COMPHY_ADDR(comphy_base) + SAR_STATUS_0_REG); if (comphy_index == COMPHY_LANE4 || comphy_index == COMPHY_LANE5) clk_dir = (reg & SAR_RST_PCIE1_CLOCK_CONFIG_CP1_MASK) >> SAR_RST_PCIE1_CLOCK_CONFIG_CP1_OFFSET; else clk_dir = (reg & SAR_RST_PCIE0_CLOCK_CONFIG_CP1_MASK) >> SAR_RST_PCIE0_CLOCK_CONFIG_CP1_OFFSET; debug("On lane %d\n", comphy_index); debug("PCIe clock direction = %x\n", clk_dir); debug("PCIe Width = %d\n", pcie_width); /* enable PCIe X4 and X2 */ if (comphy_index == COMPHY_LANE0) { if (pcie_width == PCIE_LNK_X4) { data = 0x1 << COMMON_PHY_SD_CTRL1_PCIE_X4_EN_OFFSET; mask = COMMON_PHY_SD_CTRL1_PCIE_X4_EN_MASK; reg_set(comphy_base + COMMON_PHY_SD_CTRL1, data, mask); } else if (pcie_width == PCIE_LNK_X2) { data = 0x1 << COMMON_PHY_SD_CTRL1_PCIE_X2_EN_OFFSET; mask = COMMON_PHY_SD_CTRL1_PCIE_X2_EN_MASK; reg_set(comphy_base + COMMON_PHY_SD_CTRL1, data, mask); } } /* If PCIe clock is output and clock source from SerDes lane 5, * need to configure the clock-source MUX. * By default, the clock source is from lane 4 */ if (clk_dir && clk_src && (comphy_index == COMPHY_LANE5)) { data = DFX_DEV_GEN_PCIE_CLK_SRC_MUX << DFX_DEV_GEN_PCIE_CLK_SRC_OFFSET; mask = DFX_DEV_GEN_PCIE_CLK_SRC_MASK; reg_set(DFX_FROM_COMPHY_ADDR(comphy_base) + DFX_DEV_GEN_CTRL12_REG, data, mask); } debug("stage: RFU configurations - hard reset comphy\n"); /* RFU configurations - hard reset comphy */ mask = COMMON_PHY_CFG1_PWR_UP_MASK; data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; data |= 0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK; data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; mask |= COMMON_PHY_PHY_MODE_MASK; data |= 0x0 << COMMON_PHY_PHY_MODE_OFFSET; reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); /* release from hard reset */ mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK; data = 0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; data |= 0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); /* Wait 1ms - until band gap and ref clock ready */ mdelay(1); /* Start comphy Configuration */ debug("stage: Comphy configuration\n"); /* Set PIPE soft reset */ mask = HPIPE_RST_CLK_CTRL_PIPE_RST_MASK; data = 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET; /* Set PHY datapath width mode for V0 */ mask |= HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK; data |= 0x1 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET; /* Set Data bus width USB mode for V0 */ mask |= HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK; data |= 0x0 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET; /* Set CORE_CLK output frequency for 250Mhz */ mask |= HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK; data |= 0x0 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET; reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, data, mask); /* Set PLL ready delay for 0x2 */ data = 0x2 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET; mask = HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK; if (pcie_width != PCIE_LNK_X1) { data |= 0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_OFFSET; mask |= HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SEL_MASK; data |= 0x1 << HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_OFFSET; mask |= HPIPE_CLK_SRC_LO_BUNDLE_PERIOD_SCALE_MASK; } reg_set(hpipe_addr + HPIPE_CLK_SRC_LO_REG, data, mask); /* Set PIPE mode interface to PCIe3 - 0x1 & set lane order */ data = 0x1 << HPIPE_CLK_SRC_HI_MODE_PIPE_OFFSET; mask = HPIPE_CLK_SRC_HI_MODE_PIPE_MASK; if (pcie_width != PCIE_LNK_X1) { mask |= HPIPE_CLK_SRC_HI_LANE_STRT_MASK; mask |= HPIPE_CLK_SRC_HI_LANE_MASTER_MASK; mask |= HPIPE_CLK_SRC_HI_LANE_BREAK_MASK; if (comphy_index == 0) { data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_STRT_OFFSET; data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_MASTER_OFFSET; } else if (comphy_index == (pcie_width - 1)) { data |= 0x1 << HPIPE_CLK_SRC_HI_LANE_BREAK_OFFSET; } } reg_set(hpipe_addr + HPIPE_CLK_SRC_HI_REG, data, mask); /* Config update polarity equalization */ data = 0x1 << HPIPE_CFG_UPDATE_POLARITY_OFFSET; mask = HPIPE_CFG_UPDATE_POLARITY_MASK; reg_set(hpipe_addr + HPIPE_LANE_EQ_CFG1_REG, data, mask); /* Set PIPE version 4 to mode enable */ data = 0x1 << HPIPE_DFE_CTRL_28_PIPE4_OFFSET; mask = HPIPE_DFE_CTRL_28_PIPE4_MASK; reg_set(hpipe_addr + HPIPE_DFE_CTRL_28_REG, data, mask); /* TODO: check if pcie clock is output/input - for bringup use input*/ /* Enable PIN clock 100M_125M */ mask = 0; data = 0; /* Only if clock is output, configure the clock-source mux */ if (clk_dir) { mask |= HPIPE_MISC_CLK100M_125M_MASK; data |= 0x1 << HPIPE_MISC_CLK100M_125M_OFFSET; } /* Set PIN_TXDCLK_2X Clock Freq. Selection for outputs 500MHz clock */ mask |= HPIPE_MISC_TXDCLK_2X_MASK; data |= 0x0 << HPIPE_MISC_TXDCLK_2X_OFFSET; /* Enable 500MHz Clock */ mask |= HPIPE_MISC_CLK500_EN_MASK; data |= 0x1 << HPIPE_MISC_CLK500_EN_OFFSET; if (clk_dir) { /* output */ /* Set reference clock comes from group 1 */ mask |= HPIPE_MISC_REFCLK_SEL_MASK; data |= 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET; } else { /* Set reference clock comes from group 2 */ mask |= HPIPE_MISC_REFCLK_SEL_MASK; data |= 0x1 << HPIPE_MISC_REFCLK_SEL_OFFSET; } mask |= HPIPE_MISC_ICP_FORCE_MASK; data |= 0x1 << HPIPE_MISC_ICP_FORCE_OFFSET; reg_set(hpipe_addr + HPIPE_MISC_REG, data, mask); if (clk_dir) { /* output */ /* Set reference frequcency select - 0x2 for 25MHz*/ mask = HPIPE_PWR_PLL_REF_FREQ_MASK; data = 0x2 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; } else { /* Set reference frequcency select - 0x0 for 100MHz*/ mask = HPIPE_PWR_PLL_REF_FREQ_MASK; data = 0x0 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; } /* Set PHY mode to PCIe */ mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; data |= 0x3 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask); /* ref clock alignment */ if (pcie_width != PCIE_LNK_X1) { mask = HPIPE_LANE_ALIGN_OFF_MASK; data = 0x0 << HPIPE_LANE_ALIGN_OFF_OFFSET; reg_set(hpipe_addr + HPIPE_LANE_ALIGN_REG, data, mask); } /* Set the amount of time spent in the LoZ state - set for 0x7 only if * the PCIe clock is output */ if (clk_dir) reg_set(hpipe_addr + HPIPE_GLOBAL_PM_CTRL, 0x7 << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET, HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK); /* Set Maximal PHY Generation Setting(8Gbps) */ mask = HPIPE_INTERFACE_GEN_MAX_MASK; data = 0x2 << HPIPE_INTERFACE_GEN_MAX_OFFSET; /* Bypass frame detection and sync detection for RX DATA */ mask |= HPIPE_INTERFACE_DET_BYPASS_MASK; data |= 0x1 << HPIPE_INTERFACE_DET_BYPASS_OFFSET; /* Set Link Train Mode (Tx training control pins are used) */ mask |= HPIPE_INTERFACE_LINK_TRAIN_MASK; data |= 0x1 << HPIPE_INTERFACE_LINK_TRAIN_OFFSET; reg_set(hpipe_addr + HPIPE_INTERFACE_REG, data, mask); /* Set Idle_sync enable */ mask = HPIPE_PCIE_IDLE_SYNC_MASK; data = 0x1 << HPIPE_PCIE_IDLE_SYNC_OFFSET; /* Select bits for PCIE Gen3(32bit) */ mask |= HPIPE_PCIE_SEL_BITS_MASK; data |= 0x2 << HPIPE_PCIE_SEL_BITS_OFFSET; reg_set(hpipe_addr + HPIPE_PCIE_REG0, data, mask); /* Enable Tx_adapt_g1 */ mask = HPIPE_TX_TRAIN_CTRL_G1_MASK; data = 0x1 << HPIPE_TX_TRAIN_CTRL_G1_OFFSET; /* Enable Tx_adapt_gn1 */ mask |= HPIPE_TX_TRAIN_CTRL_GN1_MASK; data |= 0x1 << HPIPE_TX_TRAIN_CTRL_GN1_OFFSET; /* Disable Tx_adapt_g0 */ mask |= HPIPE_TX_TRAIN_CTRL_G0_MASK; data |= 0x0 << HPIPE_TX_TRAIN_CTRL_G0_OFFSET; reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_REG, data, mask); /* Set reg_tx_train_chk_init */ mask = HPIPE_TX_TRAIN_CHK_INIT_MASK; data = 0x0 << HPIPE_TX_TRAIN_CHK_INIT_OFFSET; /* Enable TX_COE_FM_PIN_PCIE3_EN */ mask |= HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_MASK; data |= 0x1 << HPIPE_TX_TRAIN_COE_FM_PIN_PCIE3_OFFSET; reg_set(hpipe_addr + HPIPE_TX_TRAIN_REG, data, mask); debug("stage: TRx training parameters\n"); /* Set Preset sweep configurations */ mask = HPIPE_TX_TX_STATUS_CHECK_MODE_MASK; data = 0x1 << HPIPE_TX_STATUS_CHECK_MODE_OFFSET; mask |= HPIPE_TX_NUM_OF_PRESET_MASK; data |= 0x7 << HPIPE_TX_NUM_OF_PRESET_OFFSET; mask |= HPIPE_TX_SWEEP_PRESET_EN_MASK; data |= 0x1 << HPIPE_TX_SWEEP_PRESET_EN_OFFSET; reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_11_REG, data, mask); /* Tx train start configuration */ mask = HPIPE_TX_TRAIN_START_SQ_EN_MASK; data = 0x1 << HPIPE_TX_TRAIN_START_SQ_EN_OFFSET; mask |= HPIPE_TX_TRAIN_START_FRM_DET_EN_MASK; data |= 0x0 << HPIPE_TX_TRAIN_START_FRM_DET_EN_OFFSET; mask |= HPIPE_TX_TRAIN_START_FRM_LOCK_EN_MASK; data |= 0x0 << HPIPE_TX_TRAIN_START_FRM_LOCK_EN_OFFSET; mask |= HPIPE_TX_TRAIN_WAIT_TIME_EN_MASK; data |= 0x1 << HPIPE_TX_TRAIN_WAIT_TIME_EN_OFFSET; reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_5_REG, data, mask); /* Enable Tx train P2P */ mask = HPIPE_TX_TRAIN_P2P_HOLD_MASK; data = 0x1 << HPIPE_TX_TRAIN_P2P_HOLD_OFFSET; reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_0_REG, data, mask); /* Configure Tx train timeout */ mask = HPIPE_TRX_TRAIN_TIMER_MASK; data = 0x17 << HPIPE_TRX_TRAIN_TIMER_OFFSET; reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_4_REG, data, mask); /* Disable G0/G1/GN1 adaptation */ mask = HPIPE_TX_TRAIN_CTRL_G1_MASK | HPIPE_TX_TRAIN_CTRL_GN1_MASK | HPIPE_TX_TRAIN_CTRL_G0_OFFSET; data = 0; reg_set(hpipe_addr + HPIPE_TX_TRAIN_CTRL_REG, data, mask); /* Disable DTL frequency loop */ mask = HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK; data = 0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET; reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, data, mask); /* Configure G3 DFE */ mask = HPIPE_G3_DFE_RES_MASK; data = 0x3 << HPIPE_G3_DFE_RES_OFFSET; reg_set(hpipe_addr + HPIPE_G3_SETTING_4_REG, data, mask); /* Use TX/RX training result for DFE */ mask = HPIPE_DFE_RES_FORCE_MASK; data = 0x0 << HPIPE_DFE_RES_FORCE_OFFSET; reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask); /* Configure initial and final coefficient value for receiver */ mask = HPIPE_G3_SET_1_G3_RX_SELMUPI_MASK; data = 0x1 << HPIPE_G3_SET_1_G3_RX_SELMUPI_OFFSET; mask |= HPIPE_G3_SET_1_G3_RX_SELMUPF_MASK; data |= 0x1 << HPIPE_G3_SET_1_G3_RX_SELMUPF_OFFSET; mask |= HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_MASK; data |= 0x0 << HPIPE_G3_SET_1_G3_SAMPLER_INPAIRX2_EN_OFFSET; reg_set(hpipe_addr + HPIPE_G3_SET_1_REG, data, mask); /* Trigger sampler enable pulse */ mask = HPIPE_SMAPLER_MASK; data = 0x1 << HPIPE_SMAPLER_OFFSET; reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, data, mask); udelay(5); reg_set(hpipe_addr + HPIPE_SAMPLER_N_PROC_CALIB_CTRL_REG, 0, mask); /* FFE resistor tuning for different bandwidth */ mask = HPIPE_G3_FFE_DEG_RES_LEVEL_MASK; data = 0x1 << HPIPE_G3_FFE_DEG_RES_LEVEL_OFFSET; mask |= HPIPE_G3_FFE_LOAD_RES_LEVEL_MASK; data |= 0x3 << HPIPE_G3_FFE_LOAD_RES_LEVEL_OFFSET; reg_set(hpipe_addr + HPIPE_G3_SETTING_3_REG, data, mask); /* Pattern lock lost timeout disable */ mask = HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_MASK; data = 0x0 << HPIPE_PATTERN_LOCK_LOST_TIMEOUT_EN_OFFSET; reg_set(hpipe_addr + HPIPE_FRAME_DETECT_CTRL_3_REG, data, mask); /* Configure DFE adaptations */ mask = HPIPE_CDR_RX_MAX_DFE_ADAPT_0_MASK; data = 0x0 << HPIPE_CDR_RX_MAX_DFE_ADAPT_0_OFFSET; mask |= HPIPE_CDR_RX_MAX_DFE_ADAPT_1_MASK; data |= 0x0 << HPIPE_CDR_RX_MAX_DFE_ADAPT_1_OFFSET; mask |= HPIPE_CDR_MAX_DFE_ADAPT_0_MASK; data |= 0x0 << HPIPE_CDR_MAX_DFE_ADAPT_0_OFFSET; mask |= HPIPE_CDR_MAX_DFE_ADAPT_1_MASK; data |= 0x1 << HPIPE_CDR_MAX_DFE_ADAPT_1_OFFSET; reg_set(hpipe_addr + HPIPE_CDR_CONTROL_REG, data, mask); mask = HPIPE_DFE_TX_MAX_DFE_ADAPT_MASK; data = 0x0 << HPIPE_DFE_TX_MAX_DFE_ADAPT_OFFSET; reg_set(hpipe_addr + HPIPE_DFE_CONTROL_REG, data, mask); /* Genration 2 setting 1*/ mask = HPIPE_G2_SET_1_G2_RX_SELMUPI_MASK; data = 0x0 << HPIPE_G2_SET_1_G2_RX_SELMUPI_OFFSET; mask |= HPIPE_G2_SET_1_G2_RX_SELMUPF_MASK; data |= 0x1 << HPIPE_G2_SET_1_G2_RX_SELMUPF_OFFSET; mask |= HPIPE_G2_SET_1_G2_RX_SELMUFI_MASK; data |= 0x0 << HPIPE_G2_SET_1_G2_RX_SELMUFI_OFFSET; reg_set(hpipe_addr + HPIPE_G2_SET_1_REG, data, mask); /* DFE enable */ mask = HPIPE_G2_DFE_RES_MASK; data = 0x3 << HPIPE_G2_DFE_RES_OFFSET; reg_set(hpipe_addr + HPIPE_G2_SETTINGS_4_REG, data, mask); /* Configure DFE Resolution */ mask = HPIPE_LANE_CFG4_DFE_EN_SEL_MASK; data = 0x1 << HPIPE_LANE_CFG4_DFE_EN_SEL_OFFSET; reg_set(hpipe_addr + HPIPE_LANE_CFG4_REG, data, mask); /* VDD calibration control */ mask = HPIPE_EXT_SELLV_RXSAMPL_MASK; data = 0x16 << HPIPE_EXT_SELLV_RXSAMPL_OFFSET; reg_set(hpipe_addr + HPIPE_VDD_CAL_CTRL_REG, data, mask); /* Set PLL Charge-pump Current Control */ mask = HPIPE_G3_SETTING_5_G3_ICP_MASK; data = 0x4 << HPIPE_G3_SETTING_5_G3_ICP_OFFSET; reg_set(hpipe_addr + HPIPE_G3_SETTING_5_REG, data, mask); /* Set lane rqualization remote setting */ mask = HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_MASK; data = 0x1 << HPIPE_LANE_CFG_FOM_DIRN_OVERRIDE_OFFSET; mask |= HPIPE_LANE_CFG_FOM_ONLY_MODE_MASK; data |= 0x1 << HPIPE_LANE_CFG_FOM_ONLY_MODE_OFFFSET; mask |= HPIPE_LANE_CFG_FOM_PRESET_VECTOR_MASK; data |= 0x6 << HPIPE_LANE_CFG_FOM_PRESET_VECTOR_OFFSET; reg_set(hpipe_addr + HPIPE_LANE_EQ_REMOTE_SETTING_REG, data, mask); mask = HPIPE_CFG_EQ_BUNDLE_DIS_MASK; data = 0x1 << HPIPE_CFG_EQ_BUNDLE_DIS_OFFSET; reg_set(hpipe_addr + HPIPE_LANE_EQ_CFG2_REG, data, mask); debug("stage: Comphy power up\n"); /* For PCIe X4 or X2: * release from reset only after finish to configure all lanes */ if ((pcie_width == PCIE_LNK_X1) || (comphy_index == (pcie_width - 1))) { uint32_t i, start_lane, end_lane; if (pcie_width != PCIE_LNK_X1) { /* allows writing to all lanes in one write */ data = 0x0; if (pcie_width == PCIE_LNK_X2) mask = COMMON_PHY_SD_CTRL1_COMPHY_0_1_PORT_MASK; else if (pcie_width == PCIE_LNK_X4) mask = COMMON_PHY_SD_CTRL1_COMPHY_0_3_PORT_MASK; reg_set(comphy_base + COMMON_PHY_SD_CTRL1, data, mask); start_lane = 0; end_lane = pcie_width; /* Release from PIPE soft reset * For PCIe by4 or by2: * release from soft reset all lanes - can't use * read modify write */ reg_set(HPIPE_ADDR( COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), 0) + HPIPE_RST_CLK_CTRL_REG, 0x24, 0xffffffff); } else { start_lane = comphy_index; end_lane = comphy_index + 1; /* Release from PIPE soft reset * for PCIe by4 or by2: * release from soft reset all lanes */ reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, 0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET, HPIPE_RST_CLK_CTRL_PIPE_RST_MASK); } if (pcie_width != PCIE_LNK_X1) { /* disable writing to all lanes with one write */ if (pcie_width == PCIE_LNK_X2) { data = (COMPHY_LANE0 << COMMON_PHY_SD_CTRL1_COMPHY_0_PORT_OFFSET) | (COMPHY_LANE1 << COMMON_PHY_SD_CTRL1_COMPHY_1_PORT_OFFSET); mask = COMMON_PHY_SD_CTRL1_COMPHY_0_1_PORT_MASK; } else if (pcie_width == PCIE_LNK_X4) { data = (COMPHY_LANE0 << COMMON_PHY_SD_CTRL1_COMPHY_0_PORT_OFFSET) | (COMPHY_LANE1 << COMMON_PHY_SD_CTRL1_COMPHY_1_PORT_OFFSET) | (COMPHY_LANE2 << COMMON_PHY_SD_CTRL1_COMPHY_2_PORT_OFFSET) | (COMPHY_LANE3 << COMMON_PHY_SD_CTRL1_COMPHY_3_PORT_OFFSET); mask = COMMON_PHY_SD_CTRL1_COMPHY_0_3_PORT_MASK; } reg_set(comphy_base + COMMON_PHY_SD_CTRL1, data, mask); } debug("stage: Check PLL\n"); /* Read lane status */ for (i = start_lane; i < end_lane; i++) { addr = HPIPE_ADDR( COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), i) + HPIPE_LANE_STATUS1_REG; data = HPIPE_LANE_STATUS1_PCLK_EN_MASK; mask = data; ret = polling_with_timeout(addr, data, mask, PLL_LOCK_TIMEOUT, REG_32BIT); if (ret) ERROR("Failed to lock PCIE PLL\n"); } } debug_exit(); return ret; } static int mvebu_cp110_comphy_rxaui_power_on(uint64_t comphy_base, uint8_t comphy_index, uint32_t comphy_mode) { uintptr_t hpipe_addr, sd_ip_addr, comphy_addr, addr; uint32_t mask, data; int ret = 0; debug_enter(); hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), comphy_index); comphy_addr = COMPHY_ADDR(comphy_base, comphy_index); sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), comphy_index); /* configure phy selector for RXAUI */ mvebu_cp110_comphy_set_phy_selector(comphy_base, comphy_index, comphy_mode); /* RFU configurations - hard reset comphy */ mask = COMMON_PHY_CFG1_PWR_UP_MASK; data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); if (comphy_index == 2) { reg_set(comphy_base + COMMON_PHY_SD_CTRL1, 0x1 << COMMON_PHY_SD_CTRL1_RXAUI0_OFFSET, COMMON_PHY_SD_CTRL1_RXAUI0_MASK); } if (comphy_index == 4) { reg_set(comphy_base + COMMON_PHY_SD_CTRL1, 0x1 << COMMON_PHY_SD_CTRL1_RXAUI1_OFFSET, COMMON_PHY_SD_CTRL1_RXAUI1_MASK); } /* Select Baud Rate of Comphy And PD_PLL/Tx/Rx */ mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK; data = 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET; mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_MASK; data |= 0xB << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_RX_OFFSET; mask |= SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_MASK; data |= 0xB << SD_EXTERNAL_CONFIG0_SD_PHY_GEN_TX_OFFSET; mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK; data |= 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET; mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK; data |= 0x0 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET; mask |= SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_MASK; data |= 0x0 << SD_EXTERNAL_CONFIG0_HALF_BUS_MODE_OFFSET; mask |= SD_EXTERNAL_CONFIG0_MEDIA_MODE_MASK; data |= 0x1 << SD_EXTERNAL_CONFIG0_MEDIA_MODE_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask); /* release from hard reset */ mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); /* Wait 1ms - until band gap and ref clock ready */ mdelay(1); /* Start comphy Configuration */ debug("stage: Comphy configuration\n"); /* set reference clock */ reg_set(hpipe_addr + HPIPE_MISC_REG, 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET, HPIPE_MISC_REFCLK_SEL_MASK); /* Power and PLL Control */ mask = HPIPE_PWR_PLL_REF_FREQ_MASK; data = 0x1 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; data |= 0x4 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask); /* Loopback register */ reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, 0x1 << HPIPE_LOOPBACK_SEL_OFFSET, HPIPE_LOOPBACK_SEL_MASK); /* rx control 1 */ mask = HPIPE_RX_CONTROL_1_RXCLK2X_SEL_MASK; data = 0x1 << HPIPE_RX_CONTROL_1_RXCLK2X_SEL_OFFSET; mask |= HPIPE_RX_CONTROL_1_CLK8T_EN_MASK; data |= 0x1 << HPIPE_RX_CONTROL_1_CLK8T_EN_OFFSET; reg_set(hpipe_addr + HPIPE_RX_CONTROL_1_REG, data, mask); /* DTL Control */ reg_set(hpipe_addr + HPIPE_PWR_CTR_DTL_REG, 0x0 << HPIPE_PWR_CTR_DTL_FLOOP_EN_OFFSET, HPIPE_PWR_CTR_DTL_FLOOP_EN_MASK); /* Set analog parameters from ETP(HW) */ debug("stage: Analog parameters from ETP(HW)\n"); /* SERDES External Configuration 2 */ reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG2_REG, 0x1 << SD_EXTERNAL_CONFIG2_PIN_DFE_EN_OFFSET, SD_EXTERNAL_CONFIG2_PIN_DFE_EN_MASK); /* 0x7-DFE Resolution control */ reg_set(hpipe_addr + HPIPE_DFE_REG0, 0x1 << HPIPE_DFE_RES_FORCE_OFFSET, HPIPE_DFE_RES_FORCE_MASK); /* 0xd-G1_Setting_0 */ reg_set(hpipe_addr + HPIPE_G1_SET_0_REG, 0xd << HPIPE_G1_SET_0_G1_TX_EMPH1_OFFSET, HPIPE_G1_SET_0_G1_TX_EMPH1_MASK); /* 0xE-G1_Setting_1 */ mask = HPIPE_G1_SET_1_G1_RX_SELMUPI_MASK; data = 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPI_OFFSET; mask |= HPIPE_G1_SET_1_G1_RX_SELMUPF_MASK; data |= 0x1 << HPIPE_G1_SET_1_G1_RX_SELMUPF_OFFSET; mask |= HPIPE_G1_SET_1_G1_RX_DFE_EN_MASK; data |= 0x1 << HPIPE_G1_SET_1_G1_RX_DFE_EN_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SET_1_REG, data, mask); /* 0xA-DFE_Reg3 */ mask = HPIPE_DFE_F3_F5_DFE_EN_MASK; data = 0x0 << HPIPE_DFE_F3_F5_DFE_EN_OFFSET; mask |= HPIPE_DFE_F3_F5_DFE_CTRL_MASK; data |= 0x0 << HPIPE_DFE_F3_F5_DFE_CTRL_OFFSET; reg_set(hpipe_addr + HPIPE_DFE_F3_F5_REG, data, mask); /* 0x111-G1_Setting_4 */ mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK; data = 0x1 << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask); debug("stage: RFU configurations- Power Up PLL,Tx,Rx\n"); /* SERDES External Configuration */ mask = SD_EXTERNAL_CONFIG0_SD_PU_PLL_MASK; data = 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_PLL_OFFSET; mask |= SD_EXTERNAL_CONFIG0_SD_PU_RX_MASK; data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_RX_OFFSET; mask |= SD_EXTERNAL_CONFIG0_SD_PU_TX_MASK; data |= 0x1 << SD_EXTERNAL_CONFIG0_SD_PU_TX_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG0_REG, data, mask); /* check PLL rx & tx ready */ addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG; data = SD_EXTERNAL_STATUS0_PLL_RX_MASK | SD_EXTERNAL_STATUS0_PLL_TX_MASK; mask = data; data = polling_with_timeout(addr, data, mask, 15000, REG_32BIT); if (data != 0) { debug("Read from reg = %lx - value = 0x%x\n", sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data); ERROR("SD_EXTERNAL_STATUS0_PLL_RX is %d, -\"-_PLL_TX is %d\n", (data & SD_EXTERNAL_STATUS0_PLL_RX_MASK), (data & SD_EXTERNAL_STATUS0_PLL_TX_MASK)); ret = -ETIMEDOUT; } /* RX init */ reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, 0x1 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET, SD_EXTERNAL_CONFIG1_RX_INIT_MASK); /* check that RX init done */ addr = sd_ip_addr + SD_EXTERNAL_STATUS0_REG; data = SD_EXTERNAL_STATUS0_RX_INIT_MASK; mask = data; data = polling_with_timeout(addr, data, mask, 100, REG_32BIT); if (data != 0) { debug("Read from reg = %lx - value = 0x%x\n", sd_ip_addr + SD_EXTERNAL_STATUS0_REG, data); ERROR("SD_EXTERNAL_STATUS0_RX_INIT is 0\n"); ret = -ETIMEDOUT; } debug("stage: RF Reset\n"); /* RF Reset */ mask = SD_EXTERNAL_CONFIG1_RX_INIT_MASK; data = 0x0 << SD_EXTERNAL_CONFIG1_RX_INIT_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; data |= 0x1 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); debug_exit(); return ret; } static int mvebu_cp110_comphy_usb3_power_on(uint64_t comphy_base, uint8_t comphy_index, uint32_t comphy_mode) { uintptr_t hpipe_addr, comphy_addr, addr; uint32_t mask, data; int ret = 0; debug_enter(); /* Configure PIPE selector for USB3 */ mvebu_cp110_comphy_set_pipe_selector(comphy_base, comphy_index, comphy_mode); hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), comphy_index); comphy_addr = COMPHY_ADDR(comphy_base, comphy_index); debug("stage: RFU configurations - hard reset comphy\n"); /* RFU configurations - hard reset comphy */ mask = COMMON_PHY_CFG1_PWR_UP_MASK; data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; data |= 0x1 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; mask |= COMMON_PHY_CFG1_PWR_ON_RESET_MASK; data |= 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; mask |= COMMON_PHY_PHY_MODE_MASK; data |= 0x1 << COMMON_PHY_PHY_MODE_OFFSET; reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); /* release from hard reset */ mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK; data = 0x1 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; data |= 0x1 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); /* Wait 1ms - until band gap and ref clock ready */ mdelay(1); /* Start comphy Configuration */ debug("stage: Comphy configuration\n"); /* Set PIPE soft reset */ mask = HPIPE_RST_CLK_CTRL_PIPE_RST_MASK; data = 0x1 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET; /* Set PHY datapath width mode for V0 */ mask |= HPIPE_RST_CLK_CTRL_FIXED_PCLK_MASK; data |= 0x0 << HPIPE_RST_CLK_CTRL_FIXED_PCLK_OFFSET; /* Set Data bus width USB mode for V0 */ mask |= HPIPE_RST_CLK_CTRL_PIPE_WIDTH_MASK; data |= 0x0 << HPIPE_RST_CLK_CTRL_PIPE_WIDTH_OFFSET; /* Set CORE_CLK output frequency for 250Mhz */ mask |= HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_MASK; data |= 0x0 << HPIPE_RST_CLK_CTRL_CORE_FREQ_SEL_OFFSET; reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, data, mask); /* Set PLL ready delay for 0x2 */ reg_set(hpipe_addr + HPIPE_CLK_SRC_LO_REG, 0x2 << HPIPE_CLK_SRC_LO_PLL_RDY_DL_OFFSET, HPIPE_CLK_SRC_LO_PLL_RDY_DL_MASK); /* Set reference clock to come from group 1 - 25Mhz */ reg_set(hpipe_addr + HPIPE_MISC_REG, 0x0 << HPIPE_MISC_REFCLK_SEL_OFFSET, HPIPE_MISC_REFCLK_SEL_MASK); /* Set reference frequcency select - 0x2 */ mask = HPIPE_PWR_PLL_REF_FREQ_MASK; data = 0x2 << HPIPE_PWR_PLL_REF_FREQ_OFFSET; /* Set PHY mode to USB - 0x5 */ mask |= HPIPE_PWR_PLL_PHY_MODE_MASK; data |= 0x5 << HPIPE_PWR_PLL_PHY_MODE_OFFSET; reg_set(hpipe_addr + HPIPE_PWR_PLL_REG, data, mask); /* Set the amount of time spent in the LoZ state - set for 0x7 */ reg_set(hpipe_addr + HPIPE_GLOBAL_PM_CTRL, 0x7 << HPIPE_GLOBAL_PM_RXDLOZ_WAIT_OFFSET, HPIPE_GLOBAL_PM_RXDLOZ_WAIT_MASK); /* Set max PHY generation setting - 5Gbps */ reg_set(hpipe_addr + HPIPE_INTERFACE_REG, 0x1 << HPIPE_INTERFACE_GEN_MAX_OFFSET, HPIPE_INTERFACE_GEN_MAX_MASK); /* Set select data width 20Bit (SEL_BITS[2:0]) */ reg_set(hpipe_addr + HPIPE_LOOPBACK_REG, 0x1 << HPIPE_LOOPBACK_SEL_OFFSET, HPIPE_LOOPBACK_SEL_MASK); /* select de-emphasize 3.5db */ reg_set(hpipe_addr + HPIPE_LANE_CONFIG0_REG, 0x1 << HPIPE_LANE_CONFIG0_TXDEEMPH0_OFFSET, HPIPE_LANE_CONFIG0_TXDEEMPH0_MASK); /* override tx margining from the MAC */ reg_set(hpipe_addr + HPIPE_TST_MODE_CTRL_REG, 0x1 << HPIPE_TST_MODE_CTRL_MODE_MARGIN_OFFSET, HPIPE_TST_MODE_CTRL_MODE_MARGIN_MASK); /* Start analog parameters from ETP(HW) */ debug("stage: Analog parameters from ETP(HW)\n"); /* Set Pin DFE_PAT_DIS -> Bit[1]: PIN_DFE_PAT_DIS = 0x0 */ mask = HPIPE_LANE_CFG4_DFE_CTRL_MASK; data = 0x1 << HPIPE_LANE_CFG4_DFE_CTRL_OFFSET; /* Set Override PHY DFE control pins for 0x1 */ mask |= HPIPE_LANE_CFG4_DFE_OVER_MASK; data |= 0x1 << HPIPE_LANE_CFG4_DFE_OVER_OFFSET; /* Set Spread Spectrum Clock Enable fot 0x1 */ mask |= HPIPE_LANE_CFG4_SSC_CTRL_MASK; data |= 0x1 << HPIPE_LANE_CFG4_SSC_CTRL_OFFSET; reg_set(hpipe_addr + HPIPE_LANE_CFG4_REG, data, mask); /* Confifure SSC amplitude */ mask = HPIPE_G2_TX_SSC_AMP_MASK; data = 0x1f << HPIPE_G2_TX_SSC_AMP_OFFSET; reg_set(hpipe_addr + HPIPE_G2_SET_2_REG, data, mask); /* End of analog parameters */ debug("stage: Comphy power up\n"); /* Release from PIPE soft reset */ reg_set(hpipe_addr + HPIPE_RST_CLK_CTRL_REG, 0x0 << HPIPE_RST_CLK_CTRL_PIPE_RST_OFFSET, HPIPE_RST_CLK_CTRL_PIPE_RST_MASK); /* wait 15ms - for comphy calibration done */ debug("stage: Check PLL\n"); /* Read lane status */ addr = hpipe_addr + HPIPE_LANE_STATUS1_REG; data = HPIPE_LANE_STATUS1_PCLK_EN_MASK; mask = data; data = polling_with_timeout(addr, data, mask, 15000, REG_32BIT); if (data != 0) { debug("Read from reg = %lx - value = 0x%x\n", hpipe_addr + HPIPE_LANE_STATUS1_REG, data); ERROR("HPIPE_LANE_STATUS1_PCLK_EN_MASK is 0\n"); ret = -ETIMEDOUT; } debug_exit(); return ret; } int mvebu_cp110_comphy_xfi_rx_training(uint64_t comphy_base, uint8_t comphy_index) { uint32_t mask, data, timeout; uint32_t g1_ffe_cap_sel, g1_ffe_res_sel, align90, g1_dfe_res; uintptr_t hpipe_addr, sd_ip_addr; uint8_t ap_nr, cp_nr; mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base); hpipe_addr = HPIPE_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), comphy_index); sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), comphy_index); debug_enter(); debug("stage: RF Reset\n"); /* Release from hard reset */ mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; data = 0x1 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; data |= 0x1 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); /* Wait 50ms - until band gap and ref clock ready */ mdelay(50); debug("Preparation for rx_training\n\n"); /* Use the FFE table */ mask = HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK; data = 0 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask); /* Use auto-calibration value */ mask = HPIPE_CAL_RXCLKALIGN_90_EXT_EN_MASK; data = 0 << HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET; reg_set(hpipe_addr + HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG, data, mask); /* Use Tx/Rx training results */ mask = HPIPE_DFE_RES_FORCE_MASK; data = 0 << HPIPE_DFE_RES_FORCE_OFFSET; reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask); debug("PRBS31 loppback\n\n"); /* Configure PRBS counters */ mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK; data = 0xe << HPIPE_PHY_TEST_PATTERN_SEL_OFFSET; reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask); mask = HPIPE_PHY_TEST_DATA_MASK; data = 0xc4 << HPIPE_PHY_TEST_DATA_OFFSET; reg_set(hpipe_addr + HPIPE_PHY_TEST_DATA_REG, data, mask); mask = HPIPE_PHY_TEST_EN_MASK; data = 0x1 << HPIPE_PHY_TEST_EN_OFFSET; reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask); mdelay(10); debug("Enable TX/RX training\n\n"); mask = HPIPE_TRX_RX_TRAIN_EN_MASK; data = 0x1 << HPIPE_TRX_RX_TRAIN_EN_OFFSET; mask |= HPIPE_TRX_RX_ANA_IF_CLK_ENE_MASK; data |= 0x1 << HPIPE_TRX_RX_ANA_IF_CLK_ENE_OFFSET; mask |= HPIPE_TRX_TX_CTRL_CLK_EN_MASK; data |= 0x1 << HPIPE_TRX_TX_CTRL_CLK_EN_OFFSET; mask |= HPIPE_TRX_UPDATE_THEN_HOLD_MASK; data |= 0x1 << HPIPE_TRX_UPDATE_THEN_HOLD_OFFSET; mask |= HPIPE_TRX_TX_F0T_EO_BASED_MASK; data |= 0x1 << HPIPE_TRX_TX_F0T_EO_BASED_OFFSET; reg_set(hpipe_addr + HPIPE_TRX_TRAIN_CTRL_0_REG, data, mask); /* Check the result of RX training */ timeout = RX_TRAINING_TIMEOUT; mask = HPIPE_INTERRUPT_TRX_TRAIN_DONE_OFFSET | HPIPE_INTERRUPT_DFE_DONE_INT_OFFSET | HPIPE_INTERRUPT_RX_TRAIN_COMPLETE_INT_MASK; while (timeout) { data = mmio_read_32(hpipe_addr + HPIPE_INTERRUPT_1_REGISTER); if (data & mask) break; mdelay(1); timeout--; } debug("RX training result: interrupt reg 0x%lx = 0x%x\n\n", hpipe_addr + HPIPE_INTERRUPT_1_REGISTER, data); if (timeout == 0 || data & HPIPE_TRX_TRAIN_TIME_OUT_INT_MASK) { ERROR("Rx training timeout...\n"); return -ETIMEDOUT; } if (data & HPIPE_TRX_TRAIN_FAILED_MASK) { ERROR("Rx training failed...\n"); return -EINVAL; } mask = HPIPE_TRX_RX_TRAIN_EN_MASK; data = 0x0 << HPIPE_TRX_RX_TRAIN_EN_OFFSET; reg_set(hpipe_addr + HPIPE_TRX_TRAIN_CTRL_0_REG, data, mask); debug("Training done, reading results...\n\n"); mask = HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_MASK; g1_ffe_res_sel = ((mmio_read_32(hpipe_addr + HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG) & mask) >> HPIPE_ADAPTED_FFE_ADAPTED_FFE_RES_OFFSET); mask = HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_MASK; g1_ffe_cap_sel = ((mmio_read_32(hpipe_addr + HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG) & mask) >> HPIPE_ADAPTED_FFE_ADAPTED_FFE_CAP_OFFSET); mask = HPIPE_DATA_PHASE_ADAPTED_OS_PH_MASK; align90 = ((mmio_read_32(hpipe_addr + HPIPE_DATA_PHASE_OFF_CTRL_REG) & mask) >> HPIPE_DATA_PHASE_ADAPTED_OS_PH_OFFSET); mask = HPIPE_ADAPTED_DFE_RES_MASK; g1_dfe_res = ((mmio_read_32(hpipe_addr + HPIPE_ADAPTED_DFE_COEFFICIENT_1_REG) & mask) >> HPIPE_ADAPTED_DFE_RES_OFFSET); debug("================================================\n"); debug("Switching to static configuration:\n"); debug("FFE_RES = 0x%x FFE_CAP = 0x%x align90 = 0x%x g1_dfe_res 0x%x\n", g1_ffe_res_sel, g1_ffe_cap_sel, align90, g1_dfe_res); debug("Result after training: 0x%lx= 0x%x, 0x%lx= 0x%x, 0x%lx = 0x%x\n", (hpipe_addr + HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG), mmio_read_32(hpipe_addr + HPIPE_ADAPTED_FFE_CAPACITOR_COUNTER_CTRL_REG), (hpipe_addr + HPIPE_DATA_PHASE_OFF_CTRL_REG), mmio_read_32(hpipe_addr + HPIPE_DATA_PHASE_OFF_CTRL_REG), (hpipe_addr + HPIPE_ADAPTED_DFE_COEFFICIENT_1_REG), mmio_read_32(hpipe_addr + HPIPE_ADAPTED_DFE_COEFFICIENT_1_REG)); debug("================================================\n"); /* Update FFE_RES */ mask = HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_MASK; data = g1_ffe_res_sel << HPIPE_G1_SETTINGS_3_G1_FFE_RES_SEL_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask); /* Update FFE_CAP */ mask = HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_MASK; data = g1_ffe_cap_sel << HPIPE_G1_SETTINGS_3_G1_FFE_CAP_SEL_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask); /* Bypass the FFE table settings and use the FFE settings directly from * registers FFE_RES_SEL and FFE_CAP_SEL */ mask = HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_MASK; data = 1 << HPIPE_G1_SETTINGS_3_G1_FFE_SETTING_FORCE_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SETTINGS_3_REG, data, mask); /* Use the value from CAL_OS_PH_EXT */ mask = HPIPE_CAL_RXCLKALIGN_90_EXT_EN_MASK; data = 1 << HPIPE_CAL_RXCLKALIGN_90_EXT_EN_OFFSET; reg_set(hpipe_addr + HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG, data, mask); /* Update align90 */ mask = HPIPE_CAL_OS_PH_EXT_MASK; data = align90 << HPIPE_CAL_OS_PH_EXT_OFFSET; reg_set(hpipe_addr + HPIPE_RX_CLK_ALIGN90_AND_TX_IDLE_CALIB_CTRL_REG, data, mask); /* Force DFE resolution (use gen table value) */ mask = HPIPE_DFE_RES_FORCE_MASK; data = 0x0 << HPIPE_DFE_RES_FORCE_OFFSET; reg_set(hpipe_addr + HPIPE_DFE_REG0, data, mask); /* 0x111-G1 DFE_Setting_4 */ mask = HPIPE_G1_SETTINGS_4_G1_DFE_RES_MASK; data = g1_dfe_res << HPIPE_G1_SETTINGS_4_G1_DFE_RES_OFFSET; reg_set(hpipe_addr + HPIPE_G1_SETTINGS_4_REG, data, mask); debug("PRBS31 loppback\n\n"); mask = HPIPE_PHY_TEST_PT_TESTMODE_MASK; data = 0x1 << HPIPE_PHY_TEST_PT_TESTMODE_OFFSET; reg_set(hpipe_addr + HPIPE_PHY_TEST_OOB_0_REGISTER, data, mask); /* Configure PRBS counters */ mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK; data = 0xe << HPIPE_PHY_TEST_PATTERN_SEL_OFFSET; reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask); mask = HPIPE_PHY_TEST_DATA_MASK; data = 0xc4 << HPIPE_PHY_TEST_DATA_OFFSET; reg_set(hpipe_addr + HPIPE_PHY_TEST_DATA_REG, data, mask); mask = HPIPE_PHY_TEST_EN_MASK; data = 0x1 << HPIPE_PHY_TEST_EN_OFFSET; reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask); /* Reset PRBS error counter */ mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK; data = 0x1 << HPIPE_PHY_TEST_RESET_OFFSET; reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask); mask = HPIPE_PHY_TEST_PATTERN_SEL_MASK; data = 0x0 << HPIPE_PHY_TEST_RESET_OFFSET; reg_set(hpipe_addr + HPIPE_PHY_TEST_CONTROL_REG, data, mask); mask = HPIPE_PHY_TEST_PT_TESTMODE_MASK; data = 0x1 << HPIPE_PHY_TEST_PT_TESTMODE_OFFSET; reg_set(hpipe_addr + HPIPE_PHY_TEST_OOB_0_REGISTER, data, mask); printf("########################################################\n"); printf("# To use trained values update the ATF sources:\n"); printf("# plat/marvell/a8k//board/phy-porting-layer.h "); printf("file\n# with new values as below (for appropriate AP nr %d", ap_nr); printf("and CP nr: %d comphy_index %d\n\n", cp_nr, comphy_index); printf("static struct xfi_params xfi_static_values_tab[AP_NUM]"); printf("[CP_NUM][MAX_LANE_NR] = {\n"); printf("\t...\n"); printf("\t.g1_ffe_res_sel = 0x%x,\n", g1_ffe_res_sel); printf("\t.g1_ffe_cap_sel = 0x%x,\n", g1_ffe_cap_sel); printf("\t.align90 = 0x%x,\n", align90); printf("\t.g1_dfe_res = 0x%x\n", g1_dfe_res); printf("\t...\n"); printf("};\n\n"); printf("########################################################\n"); /* check */ debug("PRBS error counter[0x%lx] 0x%x\n\n", hpipe_addr + HPIPE_PHY_TEST_PRBS_ERROR_COUNTER_1_REG, mmio_read_32(hpipe_addr + HPIPE_PHY_TEST_PRBS_ERROR_COUNTER_1_REG)); rx_trainng_done[ap_nr][cp_nr][comphy_index] = 1; return 0; } /* During AP the proper mode is auto-negotiated and the mac, pcs and serdes * configuration are done by the firmware loaded to the MG's CM3 for appropriate * negotiated mode. Therefore there is no need to configure the mac, pcs and * serdes from u-boot. The only thing that need to be setup is powering up * the comphy, which is done through Common PHY Configuration 1 Register * (CP0: 0xF2441000, CP1: 0xF4441000). This step can't be done by MG's CM3, * since it doesn't have an access to this register-set (but it has access to * the network registers like: MG, AP, MAC, PCS, Serdes etc.) */ static int mvebu_cp110_comphy_ap_power_on(uint64_t comphy_base, uint8_t comphy_index) { uint32_t mask, data; uintptr_t comphy_addr = comphy_addr = COMPHY_ADDR(comphy_base, comphy_index); debug_enter(); debug("stage: RFU configurations - hard reset comphy\n"); /* RFU configurations - hard reset comphy */ mask = COMMON_PHY_CFG1_PWR_UP_MASK; data = 0x1 << COMMON_PHY_CFG1_PWR_UP_OFFSET; mask |= COMMON_PHY_CFG1_PIPE_SELECT_MASK; data |= 0x0 << COMMON_PHY_CFG1_PIPE_SELECT_OFFSET; reg_set(comphy_addr + COMMON_PHY_CFG1_REG, data, mask); debug_exit(); return 0; } /* * This function allows to reset the digital synchronizers between * the MAC and the PHY, it is required when the MAC changes its state. */ int mvebu_cp110_comphy_digital_reset(uint64_t comphy_base, uint8_t comphy_index, uint32_t comphy_mode, uint32_t command) { int mode = COMPHY_GET_MODE(comphy_mode); uintptr_t sd_ip_addr; uint32_t mask, data; sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), comphy_index); switch (mode) { case (COMPHY_SGMII_MODE): case (COMPHY_HS_SGMII_MODE): case (COMPHY_XFI_MODE): case (COMPHY_SFI_MODE): case (COMPHY_RXAUI_MODE): mask = SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; data = ((command == COMPHY_COMMAND_DIGITAL_PWR_OFF) ? 0x0 : 0x1) << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); break; default: ERROR("comphy%d: Digital PWR ON/OFF is not supported\n", comphy_index); return -EINVAL; } return 0; } int mvebu_cp110_comphy_power_on(uint64_t comphy_base, uint8_t comphy_index, uint64_t comphy_mode) { int mode = COMPHY_GET_MODE(comphy_mode); int err = 0; debug_enter(); switch (mode) { case(COMPHY_SATA_MODE): err = mvebu_cp110_comphy_sata_power_on(comphy_base, comphy_index, comphy_mode); break; case(COMPHY_SGMII_MODE): case(COMPHY_HS_SGMII_MODE): err = mvebu_cp110_comphy_sgmii_power_on(comphy_base, comphy_index, comphy_mode); break; /* From comphy perspective, XFI and SFI are the same */ case (COMPHY_XFI_MODE): case (COMPHY_SFI_MODE): err = mvebu_cp110_comphy_xfi_power_on(comphy_base, comphy_index, comphy_mode); break; case (COMPHY_PCIE_MODE): err = mvebu_cp110_comphy_pcie_power_on(comphy_base, comphy_index, comphy_mode); break; case (COMPHY_RXAUI_MODE): err = mvebu_cp110_comphy_rxaui_power_on(comphy_base, comphy_index, comphy_mode); break; case (COMPHY_USB3H_MODE): case (COMPHY_USB3D_MODE): err = mvebu_cp110_comphy_usb3_power_on(comphy_base, comphy_index, comphy_mode); break; case (COMPHY_AP_MODE): err = mvebu_cp110_comphy_ap_power_on(comphy_base, comphy_index); break; default: ERROR("comphy%d: unsupported comphy mode\n", comphy_index); err = -EINVAL; break; } debug_exit(); return err; } int mvebu_cp110_comphy_power_off(uint64_t comphy_base, uint8_t comphy_index, uint64_t comphy_mode) { uintptr_t sd_ip_addr, comphy_ip_addr; uint32_t mask, data; uint8_t ap_nr, cp_nr; _Bool called_from_uboot = COMPHY_GET_CALLER(comphy_mode); debug_enter(); /* Power-off might happen because of 2 things: * 1. Bootloader turns off unconnected lanes * 2. Linux turns off all lanes during boot * (and then reconfigure it). * * For PCIe, there's a problem: * In Armada 8K DB boards, PCIe initialization can be executed * only once (PCIe reset performed during chip power on and * it cannot be executed via GPIO later) so a lane configured to * PCIe should not be powered off by Linux. * * So, check 2 things: * 1. Is Linux called for power-off? * 2. Is the comphy configured to PCIe? * If the answer is YES for both 1 and 2, skip the power-off. * * TODO: In MacciatoBIN, PCIe reset is connected via GPIO, * so after GPIO reset is added to Linux Kernel, it can be * powered-off. */ if (!called_from_uboot) { data = mmio_read_32(comphy_base + COMMON_SELECTOR_PIPE_REG_OFFSET); data >>= (COMMON_SELECTOR_COMPHYN_FIELD_WIDTH * comphy_index); data &= COMMON_SELECTOR_COMPHY_MASK; if (data == COMMON_SELECTOR_PIPE_COMPHY_PCIE) return 0; } mvebu_cp110_get_ap_and_cp_nr(&ap_nr, &cp_nr, comphy_base); if (rx_trainng_done[ap_nr][cp_nr][comphy_index]) { debug("Skip %s for comphy[%d][%d][%d], due to rx training\n", __func__, ap_nr, cp_nr, comphy_index); return 0; } sd_ip_addr = SD_ADDR(COMPHY_PIPE_FROM_COMPHY_ADDR(comphy_base), comphy_index); comphy_ip_addr = COMPHY_ADDR(comphy_base, comphy_index); /* Hard reset the comphy, for Ethernet modes and Sata */ mask = SD_EXTERNAL_CONFIG1_RESET_IN_MASK; data = 0x0 << SD_EXTERNAL_CONFIG1_RESET_IN_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RESET_CORE_MASK; data |= 0x0 << SD_EXTERNAL_CONFIG1_RESET_CORE_OFFSET; mask |= SD_EXTERNAL_CONFIG1_RF_RESET_IN_MASK; data |= 0x0 << SD_EXTERNAL_CONFIG1_RF_RESET_IN_OFFSET; reg_set(sd_ip_addr + SD_EXTERNAL_CONFIG1_REG, data, mask); /* PCIe reset */ spin_lock(&cp110_mac_reset_lock); /* The mvebu_cp110_comphy_power_off will be called only from Linux (to * override settings done by bootloader) and it will be relevant only * to PCIe (called before check if to skip pcie power off or not). */ data = mmio_read_32(SYS_CTRL_FROM_COMPHY_ADDR(comphy_base) + SYS_CTRL_UINIT_SOFT_RESET_REG); switch (comphy_index) { case COMPHY_LANE0: data &= ~PCIE_MAC_RESET_MASK_PORT0; break; case COMPHY_LANE4: data &= ~PCIE_MAC_RESET_MASK_PORT1; break; case COMPHY_LANE5: data &= ~PCIE_MAC_RESET_MASK_PORT2; break; } mmio_write_32(SYS_CTRL_FROM_COMPHY_ADDR(comphy_base) + SYS_CTRL_UINIT_SOFT_RESET_REG, data); spin_unlock(&cp110_mac_reset_lock); /* Hard reset the comphy, for PCIe and usb3 */ mask = COMMON_PHY_CFG1_PWR_ON_RESET_MASK; data = 0x0 << COMMON_PHY_CFG1_PWR_ON_RESET_OFFSET; mask |= COMMON_PHY_CFG1_CORE_RSTN_MASK; data |= 0x0 << COMMON_PHY_CFG1_CORE_RSTN_OFFSET; reg_set(comphy_ip_addr + COMMON_PHY_CFG1_REG, data, mask); /* Clear comphy PHY and PIPE selector, can't rely on previous config. */ mvebu_cp110_comphy_clr_phy_selector(comphy_base, comphy_index); mvebu_cp110_comphy_clr_pipe_selector(comphy_base, comphy_index); debug_exit(); return 0; } trusted-firmware-a-2.2/drivers/marvell/comphy/phy-comphy-cp110.h000066400000000000000000000037661355360272700246340ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* Those are parameters for xfi mode, which need to be tune for each board type. * For known DB boards the parameters was already calibrated and placed under * the plat/marvell/a8k//board/phy-porting-layer.h */ struct xfi_params { uint8_t g1_ffe_res_sel; uint8_t g1_ffe_cap_sel; uint8_t align90; uint8_t g1_dfe_res; uint8_t g1_amp; uint8_t g1_emph; uint8_t g1_emph_en; uint8_t g1_tx_amp_adj; uint8_t g1_tx_emph_en; uint8_t g1_tx_emph; uint8_t g1_rx_selmuff; uint8_t g1_rx_selmufi; uint8_t g1_rx_selmupf; uint8_t g1_rx_selmupi; _Bool valid; }; struct sata_params { uint8_t g1_amp; uint8_t g2_amp; uint8_t g3_amp; uint8_t g1_emph; uint8_t g2_emph; uint8_t g3_emph; uint8_t g1_emph_en; uint8_t g2_emph_en; uint8_t g3_emph_en; uint8_t g1_tx_amp_adj; uint8_t g2_tx_amp_adj; uint8_t g3_tx_amp_adj; uint8_t g1_tx_emph_en; uint8_t g2_tx_emph_en; uint8_t g3_tx_emph_en; uint8_t g1_tx_emph; uint8_t g2_tx_emph; uint8_t g3_tx_emph; uint8_t g3_dfe_res; uint8_t g3_ffe_res_sel; uint8_t g3_ffe_cap_sel; uint8_t align90; uint8_t g1_rx_selmuff; uint8_t g2_rx_selmuff; uint8_t g3_rx_selmuff; uint8_t g1_rx_selmufi; uint8_t g2_rx_selmufi; uint8_t g3_rx_selmufi; uint8_t g1_rx_selmupf; uint8_t g2_rx_selmupf; uint8_t g3_rx_selmupf; uint8_t g1_rx_selmupi; uint8_t g2_rx_selmupi; uint8_t g3_rx_selmupi; _Bool valid; }; int mvebu_cp110_comphy_is_pll_locked(uint64_t comphy_base, uint8_t comphy_index); int mvebu_cp110_comphy_power_off(uint64_t comphy_base, uint8_t comphy_index, uint64_t comphy_mode); int mvebu_cp110_comphy_power_on(uint64_t comphy_base, uint8_t comphy_index, uint64_t comphy_mode); int mvebu_cp110_comphy_xfi_rx_training(uint64_t comphy_base, uint8_t comphy_index); int mvebu_cp110_comphy_digital_reset(uint64_t comphy_base, uint8_t comphy_index, uint32_t comphy_mode, uint32_t command); trusted-firmware-a-2.2/drivers/marvell/comphy/phy-default-porting-layer.h000066400000000000000000000032511355360272700267160ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef PHY_DEFAULT_PORTING_LAYER_H #define PHY_DEFAULT_PORTING_LAYER_H #define MAX_LANE_NR 6 #warning "Using default comphy params - you may need to suit them to your board" static const struct xfi_params xfi_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = { [0 ... AP_NUM-1][0 ... CP_NUM-1][0 ... MAX_LANE_NR-1] = { .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf, .align90 = 0x5f, .g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe, .g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1, .g1_tx_emph_en = 0x1, .g1_tx_emph = 0x0, .g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0, .g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2, .valid = 1 } }; static const struct sata_params sata_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = { [0 ... AP_NUM-1][0 ... CP_NUM-1][0 ... MAX_LANE_NR-1] = { .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e, .g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe, .g1_emph_en = 0x1, .g2_emph_en = 0x1, .g3_emph_en = 0x1, .g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1, .g3_tx_amp_adj = 0x1, .g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0, .g3_tx_emph_en = 0x0, .g1_tx_emph = 0x1, .g2_tx_emph = 0x1, .g3_tx_emph = 0x1, .g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4, .g3_ffe_cap_sel = 0xf, .align90 = 0x61, .g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3, .g3_rx_selmuff = 0x3, .g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0, .g3_rx_selmufi = 0x3, .g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1, .g3_rx_selmupf = 0x2, .g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0, .g3_rx_selmupi = 0x2, .valid = 0x1 }, }; #endif /* PHY_DEFAULT_PORTING_LAYER_H */ trusted-firmware-a-2.2/drivers/marvell/gwin.c000066400000000000000000000141621355360272700213450ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* GWIN unit device driver for Marvell AP810 SoC */ #include #include #include #include #include #include #if LOG_LEVEL >= LOG_LEVEL_INFO #define DEBUG_ADDR_MAP #endif /* common defines */ #define WIN_ENABLE_BIT (0x1) #define WIN_TARGET_MASK (0xF) #define WIN_TARGET_SHIFT (0x8) #define WIN_TARGET(tgt) (((tgt) & WIN_TARGET_MASK) \ << WIN_TARGET_SHIFT) /* Bits[43:26] of the physical address are the window base, * which is aligned to 64MB */ #define ADDRESS_RSHIFT (26) #define ADDRESS_LSHIFT (10) #define GWIN_ALIGNMENT_64M (0x4000000) /* AP registers */ #define GWIN_CR_OFFSET(ap, win) (MVEBU_GWIN_BASE(ap) + 0x0 + \ (0x10 * (win))) #define GWIN_ALR_OFFSET(ap, win) (MVEBU_GWIN_BASE(ap) + 0x8 + \ (0x10 * (win))) #define GWIN_AHR_OFFSET(ap, win) (MVEBU_GWIN_BASE(ap) + 0xc + \ (0x10 * (win))) #define CCU_GRU_CR_OFFSET(ap) (MVEBU_CCU_GRU_BASE(ap)) #define CCR_GRU_CR_GWIN_MBYPASS (1 << 1) static void gwin_check(struct addr_map_win *win) { /* The base is always 64M aligned */ if (IS_NOT_ALIGN(win->base_addr, GWIN_ALIGNMENT_64M)) { win->base_addr &= ~(GWIN_ALIGNMENT_64M - 1); NOTICE("%s: Align the base address to 0x%llx\n", __func__, win->base_addr); } /* size parameter validity check */ if (IS_NOT_ALIGN(win->win_size, GWIN_ALIGNMENT_64M)) { win->win_size = ALIGN_UP(win->win_size, GWIN_ALIGNMENT_64M); NOTICE("%s: Aligning window size to 0x%llx\n", __func__, win->win_size); } } static void gwin_enable_window(int ap_index, struct addr_map_win *win, uint32_t win_num) { uint32_t alr, ahr; uint64_t end_addr; if ((win->target_id & WIN_TARGET_MASK) != win->target_id) { ERROR("target ID = %d, is invalid\n", win->target_id); return; } /* calculate 64bit end-address */ end_addr = (win->base_addr + win->win_size - 1); alr = (uint32_t)((win->base_addr >> ADDRESS_RSHIFT) << ADDRESS_LSHIFT); ahr = (uint32_t)((end_addr >> ADDRESS_RSHIFT) << ADDRESS_LSHIFT); /* write start address and end address for GWIN */ mmio_write_32(GWIN_ALR_OFFSET(ap_index, win_num), alr); mmio_write_32(GWIN_AHR_OFFSET(ap_index, win_num), ahr); /* write the target ID and enable the window */ mmio_write_32(GWIN_CR_OFFSET(ap_index, win_num), WIN_TARGET(win->target_id) | WIN_ENABLE_BIT); } static void gwin_disable_window(int ap_index, uint32_t win_num) { uint32_t win_reg; win_reg = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_num)); win_reg &= ~WIN_ENABLE_BIT; mmio_write_32(GWIN_CR_OFFSET(ap_index, win_num), win_reg); } /* Insert/Remove temporary window for using the out-of reset default * CPx base address to access the CP configuration space prior to * the further base address update in accordance with address mapping * design. * * NOTE: Use the same window array for insertion and removal of * temporary windows. */ void gwin_temp_win_insert(int ap_index, struct addr_map_win *win, int size) { uint32_t win_id; for (int i = 0; i < size; i++) { win_id = MVEBU_GWIN_MAX_WINS - i - 1; gwin_check(win); gwin_enable_window(ap_index, win, win_id); win++; } } /* * NOTE: Use the same window array for insertion and removal of * temporary windows. */ void gwin_temp_win_remove(int ap_index, struct addr_map_win *win, int size) { uint32_t win_id; for (int i = 0; i < size; i++) { uint64_t base; uint32_t target; win_id = MVEBU_GWIN_MAX_WINS - i - 1; target = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_id)); target >>= WIN_TARGET_SHIFT; target &= WIN_TARGET_MASK; base = mmio_read_32(GWIN_ALR_OFFSET(ap_index, win_id)); base >>= ADDRESS_LSHIFT; base <<= ADDRESS_RSHIFT; if (win->target_id != target) { ERROR("%s: Trying to remove bad window-%d!\n", __func__, win_id); continue; } gwin_disable_window(ap_index, win_id); win++; } } #ifdef DEBUG_ADDR_MAP static void dump_gwin(int ap_index) { uint32_t win_num; /* Dump all GWIN windows */ printf("\tbank target start end\n"); printf("\t----------------------------------------------------\n"); for (win_num = 0; win_num < MVEBU_GWIN_MAX_WINS; win_num++) { uint32_t cr; uint64_t alr, ahr; cr = mmio_read_32(GWIN_CR_OFFSET(ap_index, win_num)); /* Window enabled */ if (cr & WIN_ENABLE_BIT) { alr = mmio_read_32(GWIN_ALR_OFFSET(ap_index, win_num)); alr = (alr >> ADDRESS_LSHIFT) << ADDRESS_RSHIFT; ahr = mmio_read_32(GWIN_AHR_OFFSET(ap_index, win_num)); ahr = (ahr >> ADDRESS_LSHIFT) << ADDRESS_RSHIFT; printf("\tgwin %d 0x%016llx 0x%016llx\n", (cr >> 8) & 0xF, alr, ahr); } } } #endif int init_gwin(int ap_index) { struct addr_map_win *win; uint32_t win_id; uint32_t win_count; uint32_t win_reg; INFO("Initializing GWIN Address decoding\n"); /* Get the array of the windows and its size */ marvell_get_gwin_memory_map(ap_index, &win, &win_count); if (win_count <= 0) { INFO("no windows configurations found\n"); return 0; } if (win_count > MVEBU_GWIN_MAX_WINS) { ERROR("number of windows is bigger than %d\n", MVEBU_GWIN_MAX_WINS); return 0; } /* disable all windows */ for (win_id = 0; win_id < MVEBU_GWIN_MAX_WINS; win_id++) gwin_disable_window(ap_index, win_id); /* enable relevant windows */ for (win_id = 0; win_id < win_count; win_id++, win++) { gwin_check(win); gwin_enable_window(ap_index, win, win_id); } /* GWIN Miss feature has not verified, therefore any access towards * remote AP should be accompanied with proper configuration to * GWIN registers group and therefore the GWIN Miss feature * should be set into Bypass mode, need to make sure all GWIN regions * are defined correctly that will assure no GWIN miss occurrance * JIRA-AURORA2-1630 */ INFO("Update GWIN miss bypass\n"); win_reg = mmio_read_32(CCU_GRU_CR_OFFSET(ap_index)); win_reg |= CCR_GRU_CR_GWIN_MBYPASS; mmio_write_32(CCU_GRU_CR_OFFSET(ap_index), win_reg); #ifdef DEBUG_ADDR_MAP dump_gwin(ap_index); #endif INFO("Done GWIN Address decoding Initializing\n"); return 0; } trusted-firmware-a-2.2/drivers/marvell/io_win.c000066400000000000000000000166711355360272700216740ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* IO Window unit device driver for Marvell AP807, AP807 and AP810 SoCs */ #include #include #include #include #include #include #if LOG_LEVEL >= LOG_LEVEL_INFO #define DEBUG_ADDR_MAP #endif /* common defines */ #define WIN_ENABLE_BIT (0x1) /* Physical address of the base of the window = {Addr[19:0],20`h0} */ #define ADDRESS_SHIFT (20 - 4) #define ADDRESS_MASK (0xFFFFFFF0) #define IO_WIN_ALIGNMENT_1M (0x100000) #define IO_WIN_ALIGNMENT_64K (0x10000) /* AP registers */ #define IO_WIN_ALR_OFFSET(ap, win) (MVEBU_IO_WIN_BASE(ap) + 0x0 + \ (0x10 * win)) #define IO_WIN_AHR_OFFSET(ap, win) (MVEBU_IO_WIN_BASE(ap) + 0x8 + \ (0x10 * win)) #define IO_WIN_CR_OFFSET(ap, win) (MVEBU_IO_WIN_BASE(ap) + 0xC + \ (0x10 * win)) /* For storage of CR, ALR, AHR abd GCR */ static uint32_t io_win_regs_save[MVEBU_IO_WIN_MAX_WINS * 3 + 1]; static void io_win_check(struct addr_map_win *win) { /* for IO The base is always 1M aligned */ /* check if address is aligned to 1M */ if (IS_NOT_ALIGN(win->base_addr, IO_WIN_ALIGNMENT_1M)) { win->base_addr = ALIGN_UP(win->base_addr, IO_WIN_ALIGNMENT_1M); NOTICE("%s: Align up the base address to 0x%llx\n", __func__, win->base_addr); } /* size parameter validity check */ if (IS_NOT_ALIGN(win->win_size, IO_WIN_ALIGNMENT_1M)) { win->win_size = ALIGN_UP(win->win_size, IO_WIN_ALIGNMENT_1M); NOTICE("%s: Aligning size to 0x%llx\n", __func__, win->win_size); } } static void io_win_enable_window(int ap_index, struct addr_map_win *win, uint32_t win_num) { uint32_t alr, ahr; uint64_t end_addr; if (win->target_id < 0 || win->target_id >= MVEBU_IO_WIN_MAX_WINS) { ERROR("target ID = %d, is invalid\n", win->target_id); return; } if ((win_num == 0) || (win_num > MVEBU_IO_WIN_MAX_WINS)) { ERROR("Enabling wrong IOW window %d!\n", win_num); return; } /* calculate the end-address */ end_addr = (win->base_addr + win->win_size - 1); alr = (uint32_t)((win->base_addr >> ADDRESS_SHIFT) & ADDRESS_MASK); alr |= WIN_ENABLE_BIT; ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK); /* write start address and end address for IO window */ mmio_write_32(IO_WIN_ALR_OFFSET(ap_index, win_num), alr); mmio_write_32(IO_WIN_AHR_OFFSET(ap_index, win_num), ahr); /* write window target */ mmio_write_32(IO_WIN_CR_OFFSET(ap_index, win_num), win->target_id); } static void io_win_disable_window(int ap_index, uint32_t win_num) { uint32_t win_reg; if ((win_num == 0) || (win_num > MVEBU_IO_WIN_MAX_WINS)) { ERROR("Disabling wrong IOW window %d!\n", win_num); return; } win_reg = mmio_read_32(IO_WIN_ALR_OFFSET(ap_index, win_num)); win_reg &= ~WIN_ENABLE_BIT; mmio_write_32(IO_WIN_ALR_OFFSET(ap_index, win_num), win_reg); } /* Insert/Remove temporary window for using the out-of reset default * CPx base address to access the CP configuration space prior to * the further base address update in accordance with address mapping * design. * * NOTE: Use the same window array for insertion and removal of * temporary windows. */ void iow_temp_win_insert(int ap_index, struct addr_map_win *win, int size) { uint32_t win_id; for (int i = 0; i < size; i++) { win_id = MVEBU_IO_WIN_MAX_WINS - i - 1; io_win_check(win); io_win_enable_window(ap_index, win, win_id); win++; } } /* * NOTE: Use the same window array for insertion and removal of * temporary windows. */ void iow_temp_win_remove(int ap_index, struct addr_map_win *win, int size) { uint32_t win_id; /* Start from the last window and do not touch Win0 */ for (int i = 0; i < size; i++) { uint64_t base; uint32_t target; win_id = MVEBU_IO_WIN_MAX_WINS - i - 1; target = mmio_read_32(IO_WIN_CR_OFFSET(ap_index, win_id)); base = mmio_read_32(IO_WIN_ALR_OFFSET(ap_index, win_id)); base &= ~WIN_ENABLE_BIT; base <<= ADDRESS_SHIFT; if ((win->target_id != target) || (win->base_addr != base)) { ERROR("%s: Trying to remove bad window-%d!\n", __func__, win_id); continue; } io_win_disable_window(ap_index, win_id); win++; } } #ifdef DEBUG_ADDR_MAP static void dump_io_win(int ap_index) { uint32_t trgt_id, win_id; uint32_t alr, ahr; uint64_t start, end; /* Dump all IO windows */ printf("\tbank target start end\n"); printf("\t----------------------------------------------------\n"); for (win_id = 0; win_id < MVEBU_IO_WIN_MAX_WINS; win_id++) { alr = mmio_read_32(IO_WIN_ALR_OFFSET(ap_index, win_id)); if (alr & WIN_ENABLE_BIT) { alr &= ~WIN_ENABLE_BIT; ahr = mmio_read_32(IO_WIN_AHR_OFFSET(ap_index, win_id)); trgt_id = mmio_read_32(IO_WIN_CR_OFFSET(ap_index, win_id)); start = ((uint64_t)alr << ADDRESS_SHIFT); end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT); printf("\tio-win %d 0x%016llx 0x%016llx\n", trgt_id, start, end); } } printf("\tio-win gcr is %x\n", mmio_read_32(MVEBU_IO_WIN_BASE(ap_index) + MVEBU_IO_WIN_GCR_OFFSET)); } #endif static void iow_save_win_range(int ap_id, int win_first, int win_last, uint32_t *buffer) { int win_id, idx; /* Save IOW */ for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) { buffer[idx++] = mmio_read_32(IO_WIN_CR_OFFSET(ap_id, win_id)); buffer[idx++] = mmio_read_32(IO_WIN_ALR_OFFSET(ap_id, win_id)); buffer[idx++] = mmio_read_32(IO_WIN_AHR_OFFSET(ap_id, win_id)); } buffer[idx] = mmio_read_32(MVEBU_IO_WIN_BASE(ap_id) + MVEBU_IO_WIN_GCR_OFFSET); } static void iow_restore_win_range(int ap_id, int win_first, int win_last, uint32_t *buffer) { int win_id, idx; /* Restore IOW */ for (idx = 0, win_id = win_first; win_id <= win_last; win_id++) { mmio_write_32(IO_WIN_CR_OFFSET(ap_id, win_id), buffer[idx++]); mmio_write_32(IO_WIN_ALR_OFFSET(ap_id, win_id), buffer[idx++]); mmio_write_32(IO_WIN_AHR_OFFSET(ap_id, win_id), buffer[idx++]); } mmio_write_32(MVEBU_IO_WIN_BASE(ap_id) + MVEBU_IO_WIN_GCR_OFFSET, buffer[idx++]); } void iow_save_win_all(int ap_id) { iow_save_win_range(ap_id, 0, MVEBU_IO_WIN_MAX_WINS - 1, io_win_regs_save); } void iow_restore_win_all(int ap_id) { iow_restore_win_range(ap_id, 0, MVEBU_IO_WIN_MAX_WINS - 1, io_win_regs_save); } int init_io_win(int ap_index) { struct addr_map_win *win; uint32_t win_id, win_reg; uint32_t win_count; INFO("Initializing IO WIN Address decoding\n"); /* Get the array of the windows and its size */ marvell_get_io_win_memory_map(ap_index, &win, &win_count); if (win_count <= 0) INFO("no windows configurations found\n"); if (win_count > MVEBU_IO_WIN_MAX_WINS) { INFO("number of windows is bigger than %d\n", MVEBU_IO_WIN_MAX_WINS); return 0; } /* Get the default target id to set the GCR */ win_reg = marvell_get_io_win_gcr_target(ap_index); mmio_write_32(MVEBU_IO_WIN_BASE(ap_index) + MVEBU_IO_WIN_GCR_OFFSET, win_reg); /* disable all IO windows */ for (win_id = 1; win_id < MVEBU_IO_WIN_MAX_WINS; win_id++) io_win_disable_window(ap_index, win_id); /* enable relevant windows, starting from win_id = 1 because * index 0 dedicated for BootROM */ for (win_id = 1; win_id <= win_count; win_id++, win++) { io_win_check(win); io_win_enable_window(ap_index, win, win_id); } #ifdef DEBUG_ADDR_MAP dump_io_win(ap_index); #endif INFO("Done IO WIN Address decoding Initializing\n"); return 0; } trusted-firmware-a-2.2/drivers/marvell/iob.c000066400000000000000000000127241355360272700211540ustar00rootroot00000000000000/* * Copyright (C) 2016 - 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* IOW unit device driver for Marvell CP110 and CP115 SoCs */ #include #include #include #include #include #include #include #if LOG_LEVEL >= LOG_LEVEL_INFO #define DEBUG_ADDR_MAP #endif #define MVEBU_IOB_OFFSET (0x190000) #define MVEBU_IOB_MAX_WINS 16 /* common defines */ #define WIN_ENABLE_BIT (0x1) /* Physical address of the base of the window = {AddrLow[19:0],20`h0} */ #define ADDRESS_SHIFT (20 - 4) #define ADDRESS_MASK (0xFFFFFFF0) #define IOB_WIN_ALIGNMENT (0x100000) /* IOB registers */ #define IOB_WIN_CR_OFFSET(win) (iob_base + 0x0 + (0x20 * win)) #define IOB_TARGET_ID_OFFSET (8) #define IOB_TARGET_ID_MASK (0xF) #define IOB_WIN_SCR_OFFSET(win) (iob_base + 0x4 + (0x20 * win)) #define IOB_WIN_ENA_CTRL_WRITE_SECURE (0x1) #define IOB_WIN_ENA_CTRL_READ_SECURE (0x2) #define IOB_WIN_ENA_WRITE_SECURE (0x4) #define IOB_WIN_ENA_READ_SECURE (0x8) #define IOB_WIN_ALR_OFFSET(win) (iob_base + 0x8 + (0x20 * win)) #define IOB_WIN_AHR_OFFSET(win) (iob_base + 0xC + (0x20 * win)) uintptr_t iob_base; static void iob_win_check(struct addr_map_win *win, uint32_t win_num) { /* check if address is aligned to the size */ if (IS_NOT_ALIGN(win->base_addr, IOB_WIN_ALIGNMENT)) { win->base_addr = ALIGN_UP(win->base_addr, IOB_WIN_ALIGNMENT); ERROR("Window %d: base address unaligned to 0x%x\n", win_num, IOB_WIN_ALIGNMENT); printf("Align up the base address to 0x%llx\n", win->base_addr); } /* size parameter validity check */ if (IS_NOT_ALIGN(win->win_size, IOB_WIN_ALIGNMENT)) { win->win_size = ALIGN_UP(win->win_size, IOB_WIN_ALIGNMENT); ERROR("Window %d: window size unaligned to 0x%x\n", win_num, IOB_WIN_ALIGNMENT); printf("Aligning size to 0x%llx\n", win->win_size); } } static void iob_enable_win(struct addr_map_win *win, uint32_t win_id) { uint32_t iob_win_reg; uint32_t alr, ahr; uint64_t end_addr; end_addr = (win->base_addr + win->win_size - 1); alr = (uint32_t)((win->base_addr >> ADDRESS_SHIFT) & ADDRESS_MASK); ahr = (uint32_t)((end_addr >> ADDRESS_SHIFT) & ADDRESS_MASK); mmio_write_32(IOB_WIN_ALR_OFFSET(win_id), alr); mmio_write_32(IOB_WIN_AHR_OFFSET(win_id), ahr); iob_win_reg = WIN_ENABLE_BIT; iob_win_reg |= (win->target_id & IOB_TARGET_ID_MASK) << IOB_TARGET_ID_OFFSET; mmio_write_32(IOB_WIN_CR_OFFSET(win_id), iob_win_reg); } #ifdef DEBUG_ADDR_MAP static void dump_iob(void) { uint32_t win_id, win_cr, alr, ahr; uint8_t target_id; uint64_t start, end; char *iob_target_name[IOB_MAX_TID] = { "CFG ", "MCI0 ", "PEX1 ", "PEX2 ", "PEX0 ", "NAND ", "RUNIT", "MCI1 " }; /* Dump all IOB windows */ printf("bank id target start end\n"); printf("----------------------------------------------------\n"); for (win_id = 0; win_id < MVEBU_IOB_MAX_WINS; win_id++) { win_cr = mmio_read_32(IOB_WIN_CR_OFFSET(win_id)); if (win_cr & WIN_ENABLE_BIT) { target_id = (win_cr >> IOB_TARGET_ID_OFFSET) & IOB_TARGET_ID_MASK; alr = mmio_read_32(IOB_WIN_ALR_OFFSET(win_id)); start = ((uint64_t)alr << ADDRESS_SHIFT); if (win_id != 0) { ahr = mmio_read_32(IOB_WIN_AHR_OFFSET(win_id)); end = (((uint64_t)ahr + 0x10) << ADDRESS_SHIFT); } else { /* Window #0 size is hardcoded to 16MB, as it's * reserved for CP configuration space. */ end = start + (16 << 20); } printf("iob %02d %s 0x%016llx 0x%016llx\n", win_id, iob_target_name[target_id], start, end); } } } #endif void iob_cfg_space_update(int ap_idx, int cp_idx, uintptr_t base, uintptr_t new_base) { debug_enter(); iob_base = base + MVEBU_IOB_OFFSET; NOTICE("Change the base address of AP%d-CP%d to %lx\n", ap_idx, cp_idx, new_base); mmio_write_32(IOB_WIN_ALR_OFFSET(0), new_base >> ADDRESS_SHIFT); iob_base = new_base + MVEBU_IOB_OFFSET; /* Make sure the address was configured by the CPU before * any possible access to the CP. */ dsb(); debug_exit(); } int init_iob(uintptr_t base) { struct addr_map_win *win; uint32_t win_id, win_reg; uint32_t win_count; INFO("Initializing IOB Address decoding\n"); /* Get the base address of the address decoding MBUS */ iob_base = base + MVEBU_IOB_OFFSET; /* Get the array of the windows and fill the map data */ marvell_get_iob_memory_map(&win, &win_count, base); if (win_count <= 0) { INFO("no windows configurations found\n"); return 0; } else if (win_count > (MVEBU_IOB_MAX_WINS - 1)) { ERROR("IOB mem map array > than max available windows (%d)\n", MVEBU_IOB_MAX_WINS); win_count = MVEBU_IOB_MAX_WINS; } /* disable all IOB windows, start from win_id = 1 * because can't disable internal register window */ for (win_id = 1; win_id < MVEBU_IOB_MAX_WINS; win_id++) { win_reg = mmio_read_32(IOB_WIN_CR_OFFSET(win_id)); win_reg &= ~WIN_ENABLE_BIT; mmio_write_32(IOB_WIN_CR_OFFSET(win_id), win_reg); win_reg = ~IOB_WIN_ENA_CTRL_WRITE_SECURE; win_reg &= ~IOB_WIN_ENA_CTRL_READ_SECURE; win_reg &= ~IOB_WIN_ENA_WRITE_SECURE; win_reg &= ~IOB_WIN_ENA_READ_SECURE; mmio_write_32(IOB_WIN_SCR_OFFSET(win_id), win_reg); } for (win_id = 1; win_id < win_count + 1; win_id++, win++) { iob_win_check(win, win_id); iob_enable_win(win, win_id); } #ifdef DEBUG_ADDR_MAP dump_iob(); #endif INFO("Done IOB Address decoding Initializing\n"); return 0; } trusted-firmware-a-2.2/drivers/marvell/mc_trustzone/000077500000000000000000000000001355360272700227655ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/marvell/mc_trustzone/mc_trustzone.c000066400000000000000000000036701355360272700256730ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include "mc_trustzone.h" #define TZ_SIZE(x) ((x) >> 13) static int fls(int x) { if (!x) return 0; return 32 - __builtin_clz(x); } /* To not duplicate types, the addr_map_win is used, but the "target" * filed is referring to attributes instead of "target". */ void tz_enable_win(int ap_index, const struct addr_map_win *win, int win_id) { int tz_size; uint32_t val, base = win->base_addr; if ((win_id < 0) || (win_id > MVEBU_TZ_MAX_WINS)) { ERROR("Enabling wrong MC TrustZone window %d!\n", win_id); return; } /* map the window size to trustzone register convention */ tz_size = fls(TZ_SIZE(win->win_size)); VERBOSE("%s: window size = 0x%llx maps to tz_size %d\n", __func__, win->win_size, tz_size); if (tz_size < 0 || tz_size > 31) { ERROR("Using not allowed size for MC TrustZone window %d!\n", win_id); return; } if (base & 0xfff) { base = base & ~0xfff; WARN("Attempt to open MC TZ win. at 0x%llx, truncate to 0x%x\n", win->base_addr, base); } val = base | (tz_size << 7) | win->target_id | TZ_VALID; VERBOSE("%s: base 0x%x, tz_size moved 0x%x, attr 0x%x, val 0x%x\n", __func__, base, (tz_size << 7), win->target_id, val); mmio_write_32(MVEBU_AP_MC_TRUSTZONE_REG_LOW(ap_index, win_id), val); VERBOSE("%s: Win%d[0x%x] configured to 0x%x\n", __func__, win_id, MVEBU_AP_MC_TRUSTZONE_REG_LOW(ap_index, win_id), mmio_read_32(MVEBU_AP_MC_TRUSTZONE_REG_LOW(ap_index, win_id))); mmio_write_32(MVEBU_AP_MC_TRUSTZONE_REG_HIGH(ap_index, win_id), (win->base_addr >> 32)); VERBOSE("%s: Win%d[0x%x] configured to 0x%x\n", __func__, win_id, MVEBU_AP_MC_TRUSTZONE_REG_HIGH(ap_index, win_id), mmio_read_32(MVEBU_AP_MC_TRUSTZONE_REG_HIGH(ap_index, win_id))); } trusted-firmware-a-2.2/drivers/marvell/mc_trustzone/mc_trustzone.h000066400000000000000000000011411355360272700256670ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MC_TRUSTZONE_H #define MC_TRUSTZONE_H #include #define MVEBU_TZ_MAX_WINS 16 #define TZ_VALID (1 << 0) #define TZ_PERM(x) ((x) << 1) #define TZ_RZ_ENABLE (1 << 3) /* tz attr definitions */ #define TZ_PERM_RW (TZ_PERM(0)) #define TZ_PERM_RO (TZ_PERM(1)) #define TZ_PERM_WO (TZ_PERM(2)) #define TZ_PERM_ABORT (TZ_PERM(3)) void tz_enable_win(int ap_index, const struct addr_map_win *win, int win_id); #endif /* MC_TRUSTZONE_H */ trusted-firmware-a-2.2/drivers/marvell/mci.c000066400000000000000000000703041355360272700211510ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* MCI bus driver for Marvell ARMADA 8K and 8K+ SoCs */ #include #include #include #include #include #include #include /* /HB /Units /Direct_regs /Direct regs * /Configuration Register Write/Read Data Register */ #define MCI_WRITE_READ_DATA_REG(mci_index) \ MVEBU_MCI_REG_BASE_REMAP(mci_index) /* /HB /Units /Direct_regs /Direct regs * /Configuration Register Access Command Register */ #define MCI_ACCESS_CMD_REG(mci_index) \ (MVEBU_MCI_REG_BASE_REMAP(mci_index) + 0x4) /* Access Command fields : * bit[3:0] - Sub command: 1 => Peripheral Config Register Read, * 0 => Peripheral Config Register Write, * 2 => Peripheral Assign ID request, * 3 => Circular Config Write * bit[5] - 1 => Local (same chip access) 0 => Remote * bit[15:8] - Destination hop ID. Put Global ID (GID) here (see scheme below). * bit[23:22] - 0x3 IHB PHY REG address space, 0x0 IHB Controller space * bit[21:16] - Low 6 bits of offset. Hight 2 bits are taken from bit[28:27] * of IHB_PHY_CTRL * (must be set before any PHY register access occurs): * /IHB_REG /IHB_REGInterchip Hopping Bus Registers * /IHB Version Control Register * * ixi_ihb_top IHB PHY * AXI ----------------------------- ------------- * <--| axi_hb_top | ihb_pipe_top |-->| | * -->| GID=1 | GID=0 |<--| | * ----------------------------- ------------- */ #define MCI_INDIRECT_CTRL_READ_CMD 0x1 #define MCI_INDIRECT_CTRL_ASSIGN_CMD 0x2 #define MCI_INDIRECT_CTRL_CIRCULAR_CMD 0x3 #define MCI_INDIRECT_CTRL_LOCAL_PKT (1 << 5) #define MCI_INDIRECT_CTRL_CMD_DONE_OFFSET 6 #define MCI_INDIRECT_CTRL_CMD_DONE \ (1 << MCI_INDIRECT_CTRL_CMD_DONE_OFFSET) #define MCI_INDIRECT_CTRL_DATA_READY_OFFSET 7 #define MCI_INDIRECT_CTRL_DATA_READY \ (1 << MCI_INDIRECT_CTRL_DATA_READY_OFFSET) #define MCI_INDIRECT_CTRL_HOPID_OFFSET 8 #define MCI_INDIRECT_CTRL_HOPID(id) \ (((id) & 0xFF) << MCI_INDIRECT_CTRL_HOPID_OFFSET) #define MCI_INDIRECT_CTRL_REG_CHIPID_OFFSET 16 #define MCI_INDIRECT_REG_CTRL_ADDR(reg_num) \ (reg_num << MCI_INDIRECT_CTRL_REG_CHIPID_OFFSET) /* Hop ID values */ #define GID_IHB_PIPE 0 #define GID_AXI_HB 1 #define GID_IHB_EXT 2 #define MCI_DID_GLOBAL_ASSIGNMENT_REQUEST_REG 0x2 /* Target MCi Local ID (LID, which is = self DID) */ #define MCI_DID_GLOBAL_ASSIGN_REQ_MCI_LOCAL_ID(val) (((val) & 0xFF) << 16) /* Bits [15:8]: Number of MCis on chip of target MCi */ #define MCI_DID_GLOBAL_ASSIGN_REQ_MCI_COUNT(val) (((val) & 0xFF) << 8) /* Bits [7:0]: Number of hops on chip of target MCi */ #define MCI_DID_GLOBAL_ASSIGN_REQ_HOPS_NUM(val) (((val) & 0xFF) << 0) /* IHB_REG domain registers */ /* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers/ * Rx Memory Configuration Register (RX_MEM_CFG) */ #define MCI_CTRL_RX_MEM_CFG_REG_NUM 0x0 #define MCI_CTRL_RX_TX_MEM_CFG_RQ_THRESH(val) (((val) & 0xFF) << 24) #define MCI_CTRL_RX_TX_MEM_CFG_PQ_THRESH(val) (((val) & 0xFF) << 16) #define MCI_CTRL_RX_TX_MEM_CFG_NQ_THRESH(val) (((val) & 0xFF) << 8) #define MCI_CTRL_RX_TX_MEM_CFG_DELTA_THRESH(val) (((val) & 0xF) << 4) #define MCI_CTRL_RX_TX_MEM_CFG_RTC(val) (((val) & 0x3) << 2) #define MCI_CTRL_RX_TX_MEM_CFG_WTC(val) (((val) & 0x3) << 0) #define MCI_CTRL_RX_MEM_CFG_REG_DEF_CP_VAL \ (MCI_CTRL_RX_TX_MEM_CFG_RQ_THRESH(0x07) | \ MCI_CTRL_RX_TX_MEM_CFG_PQ_THRESH(0x3f) | \ MCI_CTRL_RX_TX_MEM_CFG_NQ_THRESH(0x3f) | \ MCI_CTRL_RX_TX_MEM_CFG_DELTA_THRESH(0xf) | \ MCI_CTRL_RX_TX_MEM_CFG_RTC(1) | \ MCI_CTRL_RX_TX_MEM_CFG_WTC(1)) #define MCI_CTRL_RX_MEM_CFG_REG_DEF_AP_VAL \ (MCI_CTRL_RX_TX_MEM_CFG_RQ_THRESH(0x3f) | \ MCI_CTRL_RX_TX_MEM_CFG_PQ_THRESH(0x03) | \ MCI_CTRL_RX_TX_MEM_CFG_NQ_THRESH(0x3f) | \ MCI_CTRL_RX_TX_MEM_CFG_DELTA_THRESH(0xf) | \ MCI_CTRL_RX_TX_MEM_CFG_RTC(1) | \ MCI_CTRL_RX_TX_MEM_CFG_WTC(1)) /* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers/ * Tx Memory Configuration Register (TX_MEM_CFG) */ #define MCI_CTRL_TX_MEM_CFG_REG_NUM 0x1 /* field mapping for TX mem config register * are the same as for RX register - see register above */ #define MCI_CTRL_TX_MEM_CFG_REG_DEF_VAL \ (MCI_CTRL_RX_TX_MEM_CFG_RQ_THRESH(0x20) | \ MCI_CTRL_RX_TX_MEM_CFG_PQ_THRESH(0x20) | \ MCI_CTRL_RX_TX_MEM_CFG_NQ_THRESH(0x20) | \ MCI_CTRL_RX_TX_MEM_CFG_DELTA_THRESH(2) | \ MCI_CTRL_RX_TX_MEM_CFG_RTC(1) | \ MCI_CTRL_RX_TX_MEM_CFG_WTC(1)) /* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers * /IHB Link CRC Control */ /* MCi Link CRC Control Register (MCi_CRC_CTRL) */ #define MCI_LINK_CRC_CTRL_REG_NUM 0x4 /* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers * /IHB Status Register */ /* MCi Status Register (MCi_STS) */ #define MCI_CTRL_STATUS_REG_NUM 0x5 #define MCI_CTRL_STATUS_REG_PHY_READY (1 << 12) #define MCI_CTRL_STATUS_REG_LINK_PRESENT (1 << 15) #define MCI_CTRL_STATUS_REG_PHY_CID_VIO_OFFSET 24 #define MCI_CTRL_STATUS_REG_PHY_CID_VIO_MASK \ (0xF << MCI_CTRL_STATUS_REG_PHY_CID_VIO_OFFSET) /* Expected successful Link result, including reserved bit */ #define MCI_CTRL_PHY_READY (MCI_CTRL_STATUS_REG_PHY_READY | \ MCI_CTRL_STATUS_REG_LINK_PRESENT | \ MCI_CTRL_STATUS_REG_PHY_CID_VIO_MASK) /* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers/ * MCi PHY Speed Settings Register (MCi_PHY_SETTING) */ #define MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM 0x8 #define MCI_CTRL_MCI_PHY_SET_DLO_FIFO_FULL_TRESH(val) (((val) & 0xF) << 28) #define MCI_CTRL_MCI_PHY_SET_PHY_MAX_SPEED(val) (((val) & 0xF) << 12) #define MCI_CTRL_MCI_PHY_SET_PHYCLK_SEL(val) (((val) & 0xF) << 8) #define MCI_CTRL_MCI_PHY_SET_REFCLK_FREQ_SEL(val) (((val) & 0xF) << 4) #define MCI_CTRL_MCI_PHY_SET_AUTO_LINK_EN(val) (((val) & 0x1) << 1) #define MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL \ (MCI_CTRL_MCI_PHY_SET_DLO_FIFO_FULL_TRESH(0x3) | \ MCI_CTRL_MCI_PHY_SET_PHY_MAX_SPEED(0x3) | \ MCI_CTRL_MCI_PHY_SET_PHYCLK_SEL(0x2) | \ MCI_CTRL_MCI_PHY_SET_REFCLK_FREQ_SEL(0x1)) #define MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL2 \ (MCI_CTRL_MCI_PHY_SET_DLO_FIFO_FULL_TRESH(0x3) | \ MCI_CTRL_MCI_PHY_SET_PHY_MAX_SPEED(0x3) | \ MCI_CTRL_MCI_PHY_SET_PHYCLK_SEL(0x5) | \ MCI_CTRL_MCI_PHY_SET_REFCLK_FREQ_SEL(0x1)) /* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers * /IHB Mode Config */ #define MCI_CTRL_IHB_MODE_CFG_REG_NUM 0x25 #define MCI_CTRL_IHB_MODE_HBCLK_DIV(val) ((val) & 0xFF) #define MCI_CTRL_IHB_MODE_CHUNK_MOD_OFFSET 8 #define MCI_CTRL_IHB_MODE_CHUNK_MOD \ (1 << MCI_CTRL_IHB_MODE_CHUNK_MOD_OFFSET) #define MCI_CTRL_IHB_MODE_FWD_MOD_OFFSET 9 #define MCI_CTRL_IHB_MODE_FWD_MOD \ (1 << MCI_CTRL_IHB_MODE_FWD_MOD_OFFSET) #define MCI_CTRL_IHB_MODE_SEQFF_FINE_MOD(val) (((val) & 0xF) << 12) #define MCI_CTRL_IHB_MODE_RX_COMB_THRESH(val) (((val) & 0xFF) << 16) #define MCI_CTRL_IHB_MODE_TX_COMB_THRESH(val) (((val) & 0xFF) << 24) #define MCI_CTRL_IHB_MODE_CFG_REG_DEF_VAL \ (MCI_CTRL_IHB_MODE_HBCLK_DIV(6) | \ MCI_CTRL_IHB_MODE_FWD_MOD | \ MCI_CTRL_IHB_MODE_SEQFF_FINE_MOD(0xF) | \ MCI_CTRL_IHB_MODE_RX_COMB_THRESH(0x3f) | \ MCI_CTRL_IHB_MODE_TX_COMB_THRESH(0x40)) /* AXI_HB registers */ #define MCI_AXI_ACCESS_DATA_REG_NUM 0x0 #define MCI_AXI_ACCESS_PCIE_MODE 1 #define MCI_AXI_ACCESS_CACHE_CHECK_OFFSET 5 #define MCI_AXI_ACCESS_CACHE_CHECK \ (1 << MCI_AXI_ACCESS_CACHE_CHECK_OFFSET) #define MCI_AXI_ACCESS_FORCE_POST_WR_OFFSET 6 #define MCI_AXI_ACCESS_FORCE_POST_WR \ (1 << MCI_AXI_ACCESS_FORCE_POST_WR_OFFSET) #define MCI_AXI_ACCESS_DISABLE_CLK_GATING_OFFSET 9 #define MCI_AXI_ACCESS_DISABLE_CLK_GATING \ (1 << MCI_AXI_ACCESS_DISABLE_CLK_GATING_OFFSET) /* /HB /Units /HB_REG /HB_REGHopping Bus Registers * /Window 0 Address Mask Register */ #define MCI_HB_CTRL_WIN0_ADDRESS_MASK_REG_NUM 0x2 /* /HB /Units /HB_REG /HB_REGHopping Bus Registers * /Window 0 Destination Register */ #define MCI_HB_CTRL_WIN0_DESTINATION_REG_NUM 0x3 #define MCI_HB_CTRL_WIN0_DEST_VALID_FLAG(val) (((val) & 0x1) << 16) #define MCI_HB_CTRL_WIN0_DEST_ID(val) (((val) & 0xFF) << 0) /* /HB /Units /HB_REG /HB_REGHopping Bus Registers /Tx Control Register */ #define MCI_HB_CTRL_TX_CTRL_REG_NUM 0xD #define MCI_HB_CTRL_TX_CTRL_PCIE_MODE_OFFSET 24 #define MCI_HB_CTRL_TX_CTRL_PCIE_MODE \ (1 << MCI_HB_CTRL_TX_CTRL_PCIE_MODE_OFFSET) #define MCI_HB_CTRL_TX_CTRL_PRI_TH_QOS(val) (((val) & 0xF) << 12) #define MCI_HB_CTRL_TX_CTRL_MAX_RD_CNT(val) (((val) & 0x1F) << 6) #define MCI_HB_CTRL_TX_CTRL_MAX_WR_CNT(val) (((val) & 0x1F) << 0) /* /HB /Units /IHB_REG /IHB_REGInterchip Hopping Bus Registers * /IHB Version Control Register */ #define MCI_PHY_CTRL_REG_NUM 0x7 #define MCI_PHY_CTRL_MCI_MINOR 0x8 /* BITS [3:0] */ #define MCI_PHY_CTRL_MCI_MAJOR_OFFSET 4 #define MCI_PHY_CTRL_MCI_MAJOR \ (1 << MCI_PHY_CTRL_MCI_MAJOR_OFFSET) #define MCI_PHY_CTRL_MCI_SLEEP_REQ_OFFSET 11 #define MCI_PHY_CTRL_MCI_SLEEP_REQ \ (1 << MCI_PHY_CTRL_MCI_SLEEP_REQ_OFFSET) /* Host=1 / Device=0 PHY mode */ #define MCI_PHY_CTRL_MCI_PHY_MODE_OFFSET 24 #define MCI_PHY_CTRL_MCI_PHY_MODE_HOST \ (1 << MCI_PHY_CTRL_MCI_PHY_MODE_OFFSET) /* Register=1 / PWM=0 interface */ #define MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE_OFFSET 25 #define MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE \ (1 << MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE_OFFSET) /* PHY code InReset=1 */ #define MCI_PHY_CTRL_MCI_PHY_RESET_CORE_OFFSET 26 #define MCI_PHY_CTRL_MCI_PHY_RESET_CORE \ (1 << MCI_PHY_CTRL_MCI_PHY_RESET_CORE_OFFSET) #define MCI_PHY_CTRL_PHY_ADDR_MSB_OFFSET 27 #define MCI_PHY_CTRL_PHY_ADDR_MSB(addr) \ (((addr) & 0x3) << \ MCI_PHY_CTRL_PHY_ADDR_MSB_OFFSET) #define MCI_PHY_CTRL_PIDI_MODE_OFFSET 31 #define MCI_PHY_CTRL_PIDI_MODE \ (1U << MCI_PHY_CTRL_PIDI_MODE_OFFSET) /* Number of times to wait for the MCI link ready after MCI configurations * Normally takes 34-35 successive reads */ #define LINK_READY_TIMEOUT 100 enum mci_register_type { MCI_REG_TYPE_PHY = 0, MCI_REG_TYPE_CTRL, }; enum { MCI_CMD_WRITE, MCI_CMD_READ }; /* Write wrapper callback for debug: * will print written data in case LOG_LEVEL >= 40 */ static void mci_mmio_write_32(uintptr_t addr, uint32_t value) { VERBOSE("Write:\t0x%x = 0x%x\n", (uint32_t)addr, value); mmio_write_32(addr, value); } /* Read wrapper callback for debug: * will print read data in case LOG_LEVEL >= 40 */ static uint32_t mci_mmio_read_32(uintptr_t addr) { uint32_t value; value = mmio_read_32(addr); VERBOSE("Read:\t0x%x = 0x%x\n", (uint32_t)addr, value); return value; } /* MCI indirect access command completion polling: * Each write/read command done via MCI indirect registers must be polled * for command completions status. * * Returns 1 in case of error * Returns 0 in case of command completed successfully. */ static int mci_poll_command_completion(int mci_index, int command_type) { uint32_t mci_cmd_value = 0, retry_count = 100, ret = 0; uint32_t completion_flags = MCI_INDIRECT_CTRL_CMD_DONE; debug_enter(); /* Read commands require validating that requested data is ready */ if (command_type == MCI_CMD_READ) completion_flags |= MCI_INDIRECT_CTRL_DATA_READY; do { /* wait 1 ms before each polling */ mdelay(1); mci_cmd_value = mci_mmio_read_32(MCI_ACCESS_CMD_REG(mci_index)); } while (((mci_cmd_value & completion_flags) != completion_flags) && (retry_count-- > 0)); if (retry_count == 0) { ERROR("%s: MCI command timeout (command status = 0x%x)\n", __func__, mci_cmd_value); ret = 1; } debug_exit(); return ret; } int mci_read(int mci_idx, uint32_t cmd, uint32_t *value) { int rval; mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_idx), cmd); rval = mci_poll_command_completion(mci_idx, MCI_CMD_READ); *value = mci_mmio_read_32(MCI_WRITE_READ_DATA_REG(mci_idx)); return rval; } int mci_write(int mci_idx, uint32_t cmd, uint32_t data) { mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_idx), data); mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_idx), cmd); return mci_poll_command_completion(mci_idx, MCI_CMD_WRITE); } /* Perform 3 configurations in one command: PCI mode, * queues separation and cache bit */ static int mci_axi_set_pcie_mode(int mci_index) { uint32_t reg_data, ret = 1; debug_enter(); /* This configuration makes MCI IP behave consistently with AXI protocol * It should be configured at one side only (for example locally at AP). * The IP takes care of performing the same configurations at MCI on * another side (for example remotely at CP). */ mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), MCI_AXI_ACCESS_PCIE_MODE | MCI_AXI_ACCESS_CACHE_CHECK | MCI_AXI_ACCESS_FORCE_POST_WR | MCI_AXI_ACCESS_DISABLE_CLK_GATING); mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), MCI_INDIRECT_REG_CTRL_ADDR( MCI_AXI_ACCESS_DATA_REG_NUM) | MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) | MCI_INDIRECT_CTRL_LOCAL_PKT | MCI_INDIRECT_CTRL_CIRCULAR_CMD); /* if Write command was successful, verify PCIe mode */ if (mci_poll_command_completion(mci_index, MCI_CMD_WRITE) == 0) { /* Verify the PCIe mode selected */ mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), MCI_INDIRECT_REG_CTRL_ADDR( MCI_HB_CTRL_TX_CTRL_REG_NUM) | MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) | MCI_INDIRECT_CTRL_LOCAL_PKT | MCI_INDIRECT_CTRL_READ_CMD); /* if read was completed, verify PCIe mode */ if (mci_poll_command_completion(mci_index, MCI_CMD_READ) == 0) { reg_data = mci_mmio_read_32( MCI_WRITE_READ_DATA_REG(mci_index)); if (reg_data & MCI_HB_CTRL_TX_CTRL_PCIE_MODE) ret = 0; } } debug_exit(); return ret; } /* Reduce sequence FIFO timer expiration threshold */ static int mci_axi_set_fifo_thresh(int mci_index) { uint32_t reg_data, ret = 0; debug_enter(); /* This configuration reduces sequence FIFO timer expiration threshold * (to 0x7 instead of 0xA). * In MCI 1.6 version this configuration prevents possible functional * issues. * In version 1.82 the configuration prevents performance degradation */ /* Configure local AP side */ reg_data = MCI_PHY_CTRL_PIDI_MODE | MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE | MCI_PHY_CTRL_MCI_PHY_MODE_HOST | MCI_PHY_CTRL_MCI_MAJOR | MCI_PHY_CTRL_MCI_MINOR; mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data); mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) | MCI_INDIRECT_CTRL_LOCAL_PKT); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); /* Reduce the threshold */ mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), MCI_CTRL_IHB_MODE_CFG_REG_DEF_VAL); mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), MCI_INDIRECT_REG_CTRL_ADDR( MCI_CTRL_IHB_MODE_CFG_REG_NUM) | MCI_INDIRECT_CTRL_LOCAL_PKT); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); /* Exit PIDI mode */ reg_data = MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE | MCI_PHY_CTRL_MCI_PHY_MODE_HOST | MCI_PHY_CTRL_MCI_MAJOR | MCI_PHY_CTRL_MCI_MINOR; mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data); mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) | MCI_INDIRECT_CTRL_LOCAL_PKT); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); /* Configure remote CP side */ reg_data = MCI_PHY_CTRL_PIDI_MODE | MCI_PHY_CTRL_MCI_MAJOR | MCI_PHY_CTRL_MCI_MINOR | MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE; mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data); mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) | MCI_CTRL_IHB_MODE_FWD_MOD); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); /* Reduce the threshold */ mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), MCI_CTRL_IHB_MODE_CFG_REG_DEF_VAL); mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), MCI_INDIRECT_REG_CTRL_ADDR( MCI_CTRL_IHB_MODE_CFG_REG_NUM) | MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT)); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); /* Exit PIDI mode */ reg_data = MCI_PHY_CTRL_MCI_MAJOR | MCI_PHY_CTRL_MCI_MINOR | MCI_PHY_CTRL_MCI_PHY_REG_IF_MODE; mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), reg_data); mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) | MCI_CTRL_IHB_MODE_FWD_MOD); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); debug_exit(); return ret; } /* Configure: * 1. AP & CP TX thresholds and delta configurations * 2. DLO & DLI FIFO full threshold * 3. RX thresholds and delta configurations * 4. CP AR and AW outstanding * 5. AP AR and AW outstanding */ static int mci_axi_set_fifo_rx_tx_thresh(int mci_index) { uint32_t ret = 0; debug_enter(); /* AP TX thresholds and delta configurations (IHB_reg 0x1) */ mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), MCI_CTRL_TX_MEM_CFG_REG_DEF_VAL); mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), MCI_INDIRECT_REG_CTRL_ADDR( MCI_CTRL_TX_MEM_CFG_REG_NUM) | MCI_INDIRECT_CTRL_LOCAL_PKT); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); /* CP TX thresholds and delta configurations (IHB_reg 0x1) */ mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), MCI_CTRL_TX_MEM_CFG_REG_DEF_VAL); mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), MCI_INDIRECT_REG_CTRL_ADDR( MCI_CTRL_TX_MEM_CFG_REG_NUM) | MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT)); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); /* AP DLO & DLI FIFO full threshold & Auto-Link enable (IHB_reg 0x8) */ mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL | MCI_CTRL_MCI_PHY_SET_AUTO_LINK_EN(1)); mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), MCI_INDIRECT_REG_CTRL_ADDR( MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM) | MCI_INDIRECT_CTRL_LOCAL_PKT); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); /* CP DLO & DLI FIFO full threshold (IHB_reg 0x8) */ mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL); mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), MCI_INDIRECT_REG_CTRL_ADDR( MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM) | MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT)); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); /* AP RX thresholds and delta configurations (IHB_reg 0x0) */ mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), MCI_CTRL_RX_MEM_CFG_REG_DEF_AP_VAL); mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), MCI_INDIRECT_REG_CTRL_ADDR( MCI_CTRL_RX_MEM_CFG_REG_NUM) | MCI_INDIRECT_CTRL_LOCAL_PKT); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); /* CP RX thresholds and delta configurations (IHB_reg 0x0) */ mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), MCI_CTRL_RX_MEM_CFG_REG_DEF_CP_VAL); mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), MCI_INDIRECT_REG_CTRL_ADDR( MCI_CTRL_RX_MEM_CFG_REG_NUM) | MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT)); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); /* AP AR & AW maximum AXI outstanding request cfg (HB_reg 0xd) */ mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), MCI_HB_CTRL_TX_CTRL_PRI_TH_QOS(8) | MCI_HB_CTRL_TX_CTRL_MAX_RD_CNT(3) | MCI_HB_CTRL_TX_CTRL_MAX_WR_CNT(3)); mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), MCI_INDIRECT_REG_CTRL_ADDR( MCI_HB_CTRL_TX_CTRL_REG_NUM) | MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) | MCI_INDIRECT_CTRL_LOCAL_PKT); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); /* CP AR & AW maximum AXI outstanding request cfg (HB_reg 0xd) */ mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(mci_index), MCI_HB_CTRL_TX_CTRL_PRI_TH_QOS(8) | MCI_HB_CTRL_TX_CTRL_MAX_RD_CNT(0xB) | MCI_HB_CTRL_TX_CTRL_MAX_WR_CNT(0x11)); mci_mmio_write_32(MCI_ACCESS_CMD_REG(mci_index), MCI_INDIRECT_REG_CTRL_ADDR( MCI_HB_CTRL_TX_CTRL_REG_NUM) | MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT) | MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB)); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); debug_exit(); return ret; } /* configure MCI to allow read & write transactions to arrive at the same time. * Without the below configuration, MCI won't sent response to CPU for * transactions which arrived simultaneously and will lead to CPU hang. * The below will configure MCI to be able to pass transactions from/to CP/AP. */ static int mci_enable_simultaneous_transactions(int mci_index) { uint32_t ret = 0; debug_enter(); /* ID assignment (assigning global ID offset to CP) */ mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0), MCI_DID_GLOBAL_ASSIGN_REQ_MCI_LOCAL_ID(2) | MCI_DID_GLOBAL_ASSIGN_REQ_MCI_COUNT(2) | MCI_DID_GLOBAL_ASSIGN_REQ_HOPS_NUM(2)); mci_mmio_write_32(MCI_ACCESS_CMD_REG(0), MCI_INDIRECT_REG_CTRL_ADDR( MCI_DID_GLOBAL_ASSIGNMENT_REQUEST_REG) | MCI_INDIRECT_CTRL_ASSIGN_CMD); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); /* Assigning dest. ID=3 to all transactions entering from AXI at AP */ mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0), MCI_HB_CTRL_WIN0_DEST_VALID_FLAG(1) | MCI_HB_CTRL_WIN0_DEST_ID(3)); mci_mmio_write_32(MCI_ACCESS_CMD_REG(0), MCI_INDIRECT_REG_CTRL_ADDR( MCI_HB_CTRL_WIN0_DESTINATION_REG_NUM) | MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) | MCI_INDIRECT_CTRL_LOCAL_PKT); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); /* Assigning dest. ID=1 to all transactions entering from AXI at CP */ mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0), MCI_HB_CTRL_WIN0_DEST_VALID_FLAG(1) | MCI_HB_CTRL_WIN0_DEST_ID(1)); mci_mmio_write_32(MCI_ACCESS_CMD_REG(0), MCI_INDIRECT_REG_CTRL_ADDR( MCI_HB_CTRL_WIN0_DESTINATION_REG_NUM) | MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT) | MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB)); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); /* End address to all transactions entering from AXI at AP. * This will lead to get match for any AXI address * and receive destination ID=3 */ mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0), 0xffffffff); mci_mmio_write_32(MCI_ACCESS_CMD_REG(0), MCI_INDIRECT_REG_CTRL_ADDR( MCI_HB_CTRL_WIN0_ADDRESS_MASK_REG_NUM) | MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) | MCI_INDIRECT_CTRL_LOCAL_PKT); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); /* End address to all transactions entering from AXI at CP. * This will lead to get match for any AXI address * and receive destination ID=1 */ mci_mmio_write_32(MCI_WRITE_READ_DATA_REG(0), 0xffffffff); mci_mmio_write_32(MCI_ACCESS_CMD_REG(0), MCI_INDIRECT_REG_CTRL_ADDR( MCI_HB_CTRL_WIN0_ADDRESS_MASK_REG_NUM) | MCI_INDIRECT_CTRL_HOPID(GID_IHB_EXT) | MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB)); ret |= mci_poll_command_completion(mci_index, MCI_CMD_WRITE); debug_exit(); return ret; } /* Check if MCI simultaneous transaction was already enabled. * Currently bootrom does this mci configuration only when the boot source is * SAR_MCIX4, in other cases it should be done at this stage. * It is worth noticing that in case of booting from uart, the bootrom * flow is different and this mci initialization is skipped even if boot * source is SAR_MCIX4. Therefore new verification bases on appropriate mci's * register content: if the appropriate reg contains 0x0 it means that the * bootrom didn't perform required mci configuration. * * Returns: * 0 - configuration already done * 1 - configuration missing */ static _Bool mci_simulatenous_trans_missing(int mci_index) { uint32_t reg, ret; /* read 'Window 0 Destination ID assignment' from HB register 0x3 * (TX_CFG_W0_DST_ID) to check whether ID assignment was already * performed by BootROM. */ debug_enter(); mci_mmio_write_32(MCI_ACCESS_CMD_REG(0), MCI_INDIRECT_REG_CTRL_ADDR( MCI_HB_CTRL_WIN0_DESTINATION_REG_NUM) | MCI_INDIRECT_CTRL_HOPID(GID_AXI_HB) | MCI_INDIRECT_CTRL_LOCAL_PKT | MCI_INDIRECT_CTRL_READ_CMD); ret = mci_poll_command_completion(mci_index, MCI_CMD_READ); reg = mci_mmio_read_32(MCI_WRITE_READ_DATA_REG(mci_index)); if (ret) ERROR("Failed to verify MCI simultaneous read/write status\n"); debug_exit(); /* default ID assignment is 0, so if register doesn't contain zeros * it means that bootrom already performed required configuration. */ if (reg != 0) return 0; return 1; } /* For A1 revision, configure the MCI link for performance improvement: * - set MCI to support read/write transactions to arrive at the same time * - Switch AXI to PCIe mode * - Reduce sequence FIFO threshold * - Configure RX/TX FIFO thresholds * * Note: * We don't exit on error code from any sub routine, to try (best effort) to * complete the MCI configuration. * (If we exit - Bootloader will surely fail to boot) */ int mci_configure(int mci_index) { int rval; debug_enter(); /* According to design guidelines the MCI simultaneous transaction * shouldn't be enabled more then once - therefore make sure that it * wasn't already enabled in bootrom. */ if (mci_simulatenous_trans_missing(mci_index)) { VERBOSE("Enabling MCI simultaneous transaction\n"); /* set MCI to support read/write transactions * to arrive at the same time */ rval = mci_enable_simultaneous_transactions(mci_index); if (rval) ERROR("Failed to set MCI simultaneous read/write\n"); } else VERBOSE("Skip MCI ID assignment - already done by bootrom\n"); /* Configure MCI for more consistent behavior with AXI protocol */ rval = mci_axi_set_pcie_mode(mci_index); if (rval) ERROR("Failed to set MCI to AXI PCIe mode\n"); /* reduce FIFO global threshold */ rval = mci_axi_set_fifo_thresh(mci_index); if (rval) ERROR("Failed to set MCI FIFO global threshold\n"); /* configure RX/TX FIFO thresholds */ rval = mci_axi_set_fifo_rx_tx_thresh(mci_index); if (rval) ERROR("Failed to set MCI RX/TX FIFO threshold\n"); debug_exit(); return 1; } int mci_get_link_status(void) { uint32_t cmd, data; cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_STATUS_REG_NUM) | MCI_INDIRECT_CTRL_LOCAL_PKT | MCI_INDIRECT_CTRL_READ_CMD); if (mci_read(0, cmd, &data)) { ERROR("Failed to read status register\n"); return -1; } /* Check if the link is ready */ if (data != MCI_CTRL_PHY_READY) { ERROR("Bad link status %x\n", data); return -1; } return 0; } void mci_turn_link_down(void) { uint32_t cmd, data; int rval = 0; debug_enter(); /* Turn off auto-link */ cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM) | MCI_INDIRECT_CTRL_LOCAL_PKT); data = (MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL2 | MCI_CTRL_MCI_PHY_SET_AUTO_LINK_EN(0)); rval = mci_write(0, cmd, data); if (rval) ERROR("Failed to turn off auto-link\n"); /* Reset AP PHY */ cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) | MCI_INDIRECT_CTRL_LOCAL_PKT); data = (MCI_PHY_CTRL_MCI_MINOR | MCI_PHY_CTRL_MCI_MAJOR | MCI_PHY_CTRL_MCI_PHY_MODE_HOST | MCI_PHY_CTRL_MCI_PHY_RESET_CORE); rval = mci_write(0, cmd, data); if (rval) ERROR("Failed to reset AP PHY\n"); /* Clear all status & CRC values */ cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_LINK_CRC_CTRL_REG_NUM) | MCI_INDIRECT_CTRL_LOCAL_PKT); data = 0x0; mci_write(0, cmd, data); cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_STATUS_REG_NUM) | MCI_INDIRECT_CTRL_LOCAL_PKT); data = 0x0; rval = mci_write(0, cmd, data); if (rval) ERROR("Failed to reset AP PHY\n"); /* Wait 5ms before un-reset the PHY */ mdelay(5); /* Un-reset AP PHY */ cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_PHY_CTRL_REG_NUM) | MCI_INDIRECT_CTRL_LOCAL_PKT); data = (MCI_PHY_CTRL_MCI_MINOR | MCI_PHY_CTRL_MCI_MAJOR | MCI_PHY_CTRL_MCI_PHY_MODE_HOST); rval = mci_write(0, cmd, data); if (rval) ERROR("Failed to un-reset AP PHY\n"); debug_exit(); } void mci_turn_link_on(void) { uint32_t cmd, data; int rval = 0; debug_enter(); /* Turn on auto-link */ cmd = (MCI_INDIRECT_REG_CTRL_ADDR(MCI_CTRL_MCI_PHY_SETTINGS_REG_NUM) | MCI_INDIRECT_CTRL_LOCAL_PKT); data = (MCI_CTRL_MCI_PHY_SET_REG_DEF_VAL2 | MCI_CTRL_MCI_PHY_SET_AUTO_LINK_EN(1)); rval = mci_write(0, cmd, data); if (rval) ERROR("Failed to turn on auto-link\n"); debug_exit(); } /* Initialize MCI for performance improvements */ int mci_initialize(int mci_index) { int ret; debug_enter(); INFO("MCI%d initialization:\n", mci_index); ret = mci_configure(mci_index); debug_exit(); return ret; } trusted-firmware-a-2.2/drivers/marvell/mochi/000077500000000000000000000000001355360272700213305ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/marvell/mochi/ap807_setup.c000066400000000000000000000137261355360272700235640ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* AP807 Marvell SoC driver */ #include #include #include #include #include #include #include #include #define SMMU_sACR (MVEBU_SMMU_BASE + 0x10) #define SMMU_sACR_PG_64K (1 << 16) #define CCU_GSPMU_CR (MVEBU_CCU_BASE(MVEBU_AP0) \ + 0x3F0) #define GSPMU_CPU_CONTROL (0x1 << 0) #define CCU_HTC_CR (MVEBU_CCU_BASE(MVEBU_AP0) \ + 0x200) #define CCU_SET_POC_OFFSET 5 #define DSS_CR0 (MVEBU_RFU_BASE + 0x100) #define DVM_48BIT_VA_ENABLE (1 << 21) /* Secure MoChi incoming access */ #define SEC_MOCHI_IN_ACC_REG (MVEBU_RFU_BASE + 0x4738) #define SEC_MOCHI_IN_ACC_IHB0_EN (1) #define SEC_MOCHI_IN_ACC_IHB1_EN (1 << 3) #define SEC_MOCHI_IN_ACC_IHB2_EN (1 << 6) #define SEC_MOCHI_IN_ACC_PIDI_EN (1 << 9) #define SEC_IN_ACCESS_ENA_ALL_MASTERS (SEC_MOCHI_IN_ACC_IHB0_EN | \ SEC_MOCHI_IN_ACC_IHB1_EN | \ SEC_MOCHI_IN_ACC_IHB2_EN | \ SEC_MOCHI_IN_ACC_PIDI_EN) /* SYSRST_OUTn Config definitions */ #define MVEBU_SYSRST_OUT_CONFIG_REG (MVEBU_MISC_SOC_BASE + 0x4) #define WD_MASK_SYS_RST_OUT (1 << 2) /* DSS PHY for DRAM */ #define DSS_SCR_REG (MVEBU_RFU_BASE + 0x208) #define DSS_PPROT_OFFS 4 #define DSS_PPROT_MASK 0x7 #define DSS_PPROT_PRIV_SECURE_DATA 0x1 /* Used for Units of AP-807 (e.g. SDIO and etc) */ #define MVEBU_AXI_ATTR_BASE (MVEBU_REGS_BASE + 0x6F4580) #define MVEBU_AXI_ATTR_REG(index) (MVEBU_AXI_ATTR_BASE + \ 0x4 * index) enum axi_attr { AXI_SDIO_ATTR = 0, AXI_DFX_ATTR, AXI_MAX_ATTR, }; static void ap_sec_masters_access_en(uint32_t enable) { uint32_t reg; /* Open/Close incoming access for all masters. * The access is disabled in trusted boot mode * Could only be done in EL3 */ reg = mmio_read_32(SEC_MOCHI_IN_ACC_REG); if (enable) mmio_write_32(SEC_MOCHI_IN_ACC_REG, reg | SEC_IN_ACCESS_ENA_ALL_MASTERS); else mmio_write_32(SEC_MOCHI_IN_ACC_REG, reg & ~SEC_IN_ACCESS_ENA_ALL_MASTERS); } static void setup_smmu(void) { uint32_t reg; /* Set the SMMU page size to 64 KB */ reg = mmio_read_32(SMMU_sACR); reg |= SMMU_sACR_PG_64K; mmio_write_32(SMMU_sACR, reg); } static void init_aurora2(void) { uint32_t reg; /* Enable GSPMU control by CPU */ reg = mmio_read_32(CCU_GSPMU_CR); reg |= GSPMU_CPU_CONTROL; mmio_write_32(CCU_GSPMU_CR, reg); #if LLC_ENABLE /* Enable LLC for AP807 in exclusive mode */ llc_enable(0, 1); /* Set point of coherency to DDR. * This is required by units which have * SW cache coherency */ reg = mmio_read_32(CCU_HTC_CR); reg |= (0x1 << CCU_SET_POC_OFFSET); mmio_write_32(CCU_HTC_CR, reg); #endif /* LLC_ENABLE */ } /* MCIx indirect access register are based by default at 0xf4000000/0xf6000000 * to avoid conflict of internal registers of units connected via MCIx, which * can be based on the same address (i.e CP1 base is also 0xf4000000), * the following routines remaps the MCIx indirect bases to another domain */ static void mci_remap_indirect_access_base(void) { uint32_t mci; for (mci = 0; mci < MCI_MAX_UNIT_ID; mci++) mmio_write_32(MCIX4_REG_START_ADDRESS_REG(mci), MVEBU_MCI_REG_BASE_REMAP(mci) >> MCI_REMAP_OFF_SHIFT); } static void ap807_axi_attr_init(void) { uint32_t index, data; /* Initialize AXI attributes for AP807 */ /* Go over the AXI attributes and set Ax-Cache and Ax-Domain */ for (index = 0; index < AXI_MAX_ATTR; index++) { switch (index) { /* DFX works with no coherent only - * there's no option to configure the Ax-Cache and Ax-Domain */ case AXI_DFX_ATTR: continue; default: /* Set Ax-Cache as cacheable, no allocate, modifiable, * bufferable. * The values are different because Read & Write * definition is different in Ax-Cache */ data = mmio_read_32(MVEBU_AXI_ATTR_REG(index)); data &= ~MVEBU_AXI_ATTR_ARCACHE_MASK; data |= (CACHE_ATTR_WRITE_ALLOC | CACHE_ATTR_CACHEABLE | CACHE_ATTR_BUFFERABLE) << MVEBU_AXI_ATTR_ARCACHE_OFFSET; data &= ~MVEBU_AXI_ATTR_AWCACHE_MASK; data |= (CACHE_ATTR_READ_ALLOC | CACHE_ATTR_CACHEABLE | CACHE_ATTR_BUFFERABLE) << MVEBU_AXI_ATTR_AWCACHE_OFFSET; /* Set Ax-Domain as Outer domain */ data &= ~MVEBU_AXI_ATTR_ARDOMAIN_MASK; data |= DOMAIN_OUTER_SHAREABLE << MVEBU_AXI_ATTR_ARDOMAIN_OFFSET; data &= ~MVEBU_AXI_ATTR_AWDOMAIN_MASK; data |= DOMAIN_OUTER_SHAREABLE << MVEBU_AXI_ATTR_AWDOMAIN_OFFSET; mmio_write_32(MVEBU_AXI_ATTR_REG(index), data); } } } static void misc_soc_configurations(void) { uint32_t reg; /* Enable 48-bit VA */ mmio_setbits_32(DSS_CR0, DVM_48BIT_VA_ENABLE); /* Un-mask Watchdog reset from influencing the SYSRST_OUTn. * Otherwise, upon WD timeout, the WD reset signal won't trigger reset */ reg = mmio_read_32(MVEBU_SYSRST_OUT_CONFIG_REG); reg &= ~(WD_MASK_SYS_RST_OUT); mmio_write_32(MVEBU_SYSRST_OUT_CONFIG_REG, reg); } void ap_init(void) { /* Setup Aurora2. */ init_aurora2(); /* configure MCI mapping */ mci_remap_indirect_access_base(); /* configure IO_WIN windows */ init_io_win(MVEBU_AP0); /* configure CCU windows */ init_ccu(MVEBU_AP0); /* configure the SMMU */ setup_smmu(); /* Open AP incoming access for all masters */ ap_sec_masters_access_en(1); /* configure axi for AP */ ap807_axi_attr_init(); /* misc configuration of the SoC */ misc_soc_configurations(); } static void ap807_dram_phy_access_config(void) { uint32_t reg_val; /* Update DSS port access permission to DSS_PHY */ reg_val = mmio_read_32(DSS_SCR_REG); reg_val &= ~(DSS_PPROT_MASK << DSS_PPROT_OFFS); reg_val |= ((DSS_PPROT_PRIV_SECURE_DATA & DSS_PPROT_MASK) << DSS_PPROT_OFFS); mmio_write_32(DSS_SCR_REG, reg_val); } void ap_ble_init(void) { /* Enable DSS port */ ap807_dram_phy_access_config(); } int ap_get_count(void) { return 1; } trusted-firmware-a-2.2/drivers/marvell/mochi/apn806_setup.c000066400000000000000000000144041355360272700237330ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* AP806 Marvell SoC driver */ #include #include #include #include #include #include #include #include #define SMMU_sACR (MVEBU_SMMU_BASE + 0x10) #define SMMU_sACR_PG_64K (1 << 16) #define CCU_GSPMU_CR (MVEBU_CCU_BASE(MVEBU_AP0) + \ 0x3F0) #define GSPMU_CPU_CONTROL (0x1 << 0) #define CCU_HTC_CR (MVEBU_CCU_BASE(MVEBU_AP0) + \ 0x200) #define CCU_SET_POC_OFFSET 5 #define CCU_RGF(win) (MVEBU_CCU_BASE(MVEBU_AP0) + \ 0x90 + 4 * (win)) #define DSS_CR0 (MVEBU_RFU_BASE + 0x100) #define DVM_48BIT_VA_ENABLE (1 << 21) /* Secure MoChi incoming access */ #define SEC_MOCHI_IN_ACC_REG (MVEBU_RFU_BASE + 0x4738) #define SEC_MOCHI_IN_ACC_IHB0_EN (1) #define SEC_MOCHI_IN_ACC_IHB1_EN (1 << 3) #define SEC_MOCHI_IN_ACC_IHB2_EN (1 << 6) #define SEC_MOCHI_IN_ACC_PIDI_EN (1 << 9) #define SEC_IN_ACCESS_ENA_ALL_MASTERS (SEC_MOCHI_IN_ACC_IHB0_EN | \ SEC_MOCHI_IN_ACC_IHB1_EN | \ SEC_MOCHI_IN_ACC_IHB2_EN | \ SEC_MOCHI_IN_ACC_PIDI_EN) /* SYSRST_OUTn Config definitions */ #define MVEBU_SYSRST_OUT_CONFIG_REG (MVEBU_MISC_SOC_BASE + 0x4) #define WD_MASK_SYS_RST_OUT (1 << 2) /* Generic Timer System Controller */ #define MVEBU_MSS_GTCR_REG (MVEBU_REGS_BASE + 0x581000) #define MVEBU_MSS_GTCR_ENABLE_BIT 0x1 /* * AXI Configuration. */ /* Used for Units of AP-806 (e.g. SDIO and etc) */ #define MVEBU_AXI_ATTR_BASE (MVEBU_REGS_BASE + 0x6F4580) #define MVEBU_AXI_ATTR_REG(index) (MVEBU_AXI_ATTR_BASE + \ 0x4 * index) enum axi_attr { AXI_SDIO_ATTR = 0, AXI_DFX_ATTR, AXI_MAX_ATTR, }; static void apn_sec_masters_access_en(uint32_t enable) { uint32_t reg; /* Open/Close incoming access for all masters. * The access is disabled in trusted boot mode * Could only be done in EL3 */ reg = mmio_read_32(SEC_MOCHI_IN_ACC_REG); if (enable) mmio_write_32(SEC_MOCHI_IN_ACC_REG, reg | SEC_IN_ACCESS_ENA_ALL_MASTERS); else mmio_write_32(SEC_MOCHI_IN_ACC_REG, reg & ~SEC_IN_ACCESS_ENA_ALL_MASTERS); } static void setup_smmu(void) { uint32_t reg; /* Set the SMMU page size to 64 KB */ reg = mmio_read_32(SMMU_sACR); reg |= SMMU_sACR_PG_64K; mmio_write_32(SMMU_sACR, reg); } static void apn806_errata_wa_init(void) { /* * ERRATA ID: RES-3033912 - Internal Address Space Init state causes * a hang upon accesses to [0xf070_0000, 0xf07f_ffff] * Workaround: Boot Firmware (ATF) should configure CCU_RGF_WIN(4) to * split [0x6e_0000, 0xff_ffff] to values [0x6e_0000, 0x6f_ffff] and * [0x80_0000, 0xff_ffff] that cause accesses to the * segment of [0xf070_0000, 0xf07f_ffff] to act as RAZWI. */ mmio_write_32(CCU_RGF(4), 0x37f9b809); mmio_write_32(CCU_RGF(5), 0x7ffa0009); } static void init_aurora2(void) { uint32_t reg; /* Enable GSPMU control by CPU */ reg = mmio_read_32(CCU_GSPMU_CR); reg |= GSPMU_CPU_CONTROL; mmio_write_32(CCU_GSPMU_CR, reg); #if LLC_ENABLE /* Enable LLC for AP806 in exclusive mode */ llc_enable(0, 1); /* Set point of coherency to DDR. * This is required by units which have * SW cache coherency */ reg = mmio_read_32(CCU_HTC_CR); reg |= (0x1 << CCU_SET_POC_OFFSET); mmio_write_32(CCU_HTC_CR, reg); #endif /* LLC_ENABLE */ apn806_errata_wa_init(); } /* MCIx indirect access register are based by default at 0xf4000000/0xf6000000 * to avoid conflict of internal registers of units connected via MCIx, which * can be based on the same address (i.e CP1 base is also 0xf4000000), * the following routines remaps the MCIx indirect bases to another domain */ static void mci_remap_indirect_access_base(void) { uint32_t mci; for (mci = 0; mci < MCI_MAX_UNIT_ID; mci++) mmio_write_32(MCIX4_REG_START_ADDRESS_REG(mci), MVEBU_MCI_REG_BASE_REMAP(mci) >> MCI_REMAP_OFF_SHIFT); } static void apn806_axi_attr_init(void) { uint32_t index, data; /* Initialize AXI attributes for APN806 */ /* Go over the AXI attributes and set Ax-Cache and Ax-Domain */ for (index = 0; index < AXI_MAX_ATTR; index++) { switch (index) { /* DFX works with no coherent only - * there's no option to configure the Ax-Cache and Ax-Domain */ case AXI_DFX_ATTR: continue; default: /* Set Ax-Cache as cacheable, no allocate, modifiable, * bufferable * The values are different because Read & Write * definition is different in Ax-Cache */ data = mmio_read_32(MVEBU_AXI_ATTR_REG(index)); data &= ~MVEBU_AXI_ATTR_ARCACHE_MASK; data |= (CACHE_ATTR_WRITE_ALLOC | CACHE_ATTR_CACHEABLE | CACHE_ATTR_BUFFERABLE) << MVEBU_AXI_ATTR_ARCACHE_OFFSET; data &= ~MVEBU_AXI_ATTR_AWCACHE_MASK; data |= (CACHE_ATTR_READ_ALLOC | CACHE_ATTR_CACHEABLE | CACHE_ATTR_BUFFERABLE) << MVEBU_AXI_ATTR_AWCACHE_OFFSET; /* Set Ax-Domain as Outer domain */ data &= ~MVEBU_AXI_ATTR_ARDOMAIN_MASK; data |= DOMAIN_OUTER_SHAREABLE << MVEBU_AXI_ATTR_ARDOMAIN_OFFSET; data &= ~MVEBU_AXI_ATTR_AWDOMAIN_MASK; data |= DOMAIN_OUTER_SHAREABLE << MVEBU_AXI_ATTR_AWDOMAIN_OFFSET; mmio_write_32(MVEBU_AXI_ATTR_REG(index), data); } } } static void dss_setup(void) { /* Enable 48-bit VA */ mmio_setbits_32(DSS_CR0, DVM_48BIT_VA_ENABLE); } void misc_soc_configurations(void) { uint32_t reg; /* Un-mask Watchdog reset from influencing the SYSRST_OUTn. * Otherwise, upon WD timeout, the WD reset signal won't trigger reset */ reg = mmio_read_32(MVEBU_SYSRST_OUT_CONFIG_REG); reg &= ~(WD_MASK_SYS_RST_OUT); mmio_write_32(MVEBU_SYSRST_OUT_CONFIG_REG, reg); } void ap_init(void) { /* Setup Aurora2. */ init_aurora2(); /* configure MCI mapping */ mci_remap_indirect_access_base(); /* configure IO_WIN windows */ init_io_win(MVEBU_AP0); /* configure CCU windows */ init_ccu(MVEBU_AP0); /* configure DSS */ dss_setup(); /* configure the SMMU */ setup_smmu(); /* Open APN incoming access for all masters */ apn_sec_masters_access_en(1); /* configure axi for APN*/ apn806_axi_attr_init(); /* misc configuration of the SoC */ misc_soc_configurations(); } void ap_ble_init(void) { } int ap_get_count(void) { return 1; } trusted-firmware-a-2.2/drivers/marvell/mochi/cp110_setup.c000066400000000000000000000316561355360272700235530ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* CP110 Marvell SoC driver */ #include #include #include #include #include #include /* * AXI Configuration. */ /* Used for Units of CP-110 (e.g. USB device, USB Host, and etc) */ #define MVEBU_AXI_ATTR_OFFSET (0x441300) #define MVEBU_AXI_ATTR_REG(index) (MVEBU_AXI_ATTR_OFFSET + \ 0x4 * index) /* AXI Protection bits */ #define MVEBU_AXI_PROT_OFFSET (0x441200) /* AXI Protection regs */ #define MVEBU_AXI_PROT_REG(index) ((index <= 4) ? \ (MVEBU_AXI_PROT_OFFSET + \ 0x4 * index) : \ (MVEBU_AXI_PROT_OFFSET + 0x18)) #define MVEBU_AXI_PROT_REGS_NUM (6) #define MVEBU_SOC_CFGS_OFFSET (0x441900) #define MVEBU_SOC_CFG_REG(index) (MVEBU_SOC_CFGS_OFFSET + \ 0x4 * index) #define MVEBU_SOC_CFG_REG_NUM (0) #define MVEBU_SOC_CFG_GLOG_SECURE_EN_MASK (0xE) /* SATA3 MBUS to AXI regs */ #define MVEBU_BRIDGE_WIN_DIS_REG (MVEBU_SOC_CFGS_OFFSET + 0x10) #define MVEBU_BRIDGE_WIN_DIS_OFF (0x0) /* SATA3 MBUS to AXI regs */ #define MVEBU_SATA_M2A_AXI_PORT_CTRL_REG (0x54ff04) /* AXI to MBUS bridge registers */ #define MVEBU_AMB_IP_OFFSET (0x13ff00) #define MVEBU_AMB_IP_BRIDGE_WIN_REG(win) (MVEBU_AMB_IP_OFFSET + \ (win * 0x8)) #define MVEBU_AMB_IP_BRIDGE_WIN_EN_OFFSET 0 #define MVEBU_AMB_IP_BRIDGE_WIN_EN_MASK \ (0x1 << MVEBU_AMB_IP_BRIDGE_WIN_EN_OFFSET) #define MVEBU_AMB_IP_BRIDGE_WIN_SIZE_OFFSET 16 #define MVEBU_AMB_IP_BRIDGE_WIN_SIZE_MASK \ (0xffffu << MVEBU_AMB_IP_BRIDGE_WIN_SIZE_OFFSET) #define MVEBU_SAMPLE_AT_RESET_REG (0x440600) #define SAR_PCIE1_CLK_CFG_OFFSET 31 #define SAR_PCIE1_CLK_CFG_MASK (0x1u << SAR_PCIE1_CLK_CFG_OFFSET) #define SAR_PCIE0_CLK_CFG_OFFSET 30 #define SAR_PCIE0_CLK_CFG_MASK (0x1 << SAR_PCIE0_CLK_CFG_OFFSET) #define SAR_I2C_INIT_EN_OFFSET 24 #define SAR_I2C_INIT_EN_MASK (1 << SAR_I2C_INIT_EN_OFFSET) /******************************************************************************* * PCIE clock buffer control ******************************************************************************/ #define MVEBU_PCIE_REF_CLK_BUF_CTRL (0x4404F0) #define PCIE1_REFCLK_BUFF_SOURCE 0x800 #define PCIE0_REFCLK_BUFF_SOURCE 0x400 /******************************************************************************* * MSS Device Push Set Register ******************************************************************************/ #define MVEBU_CP_MSS_DPSHSR_REG (0x280040) #define MSS_DPSHSR_REG_PCIE_CLK_SEL 0x8 /******************************************************************************* * RTC Configuration ******************************************************************************/ #define MVEBU_RTC_BASE (0x284000) #define MVEBU_RTC_STATUS_REG (MVEBU_RTC_BASE + 0x0) #define MVEBU_RTC_STATUS_ALARM1_MASK 0x1 #define MVEBU_RTC_STATUS_ALARM2_MASK 0x2 #define MVEBU_RTC_IRQ_1_CONFIG_REG (MVEBU_RTC_BASE + 0x4) #define MVEBU_RTC_IRQ_2_CONFIG_REG (MVEBU_RTC_BASE + 0x8) #define MVEBU_RTC_TIME_REG (MVEBU_RTC_BASE + 0xC) #define MVEBU_RTC_ALARM_1_REG (MVEBU_RTC_BASE + 0x10) #define MVEBU_RTC_ALARM_2_REG (MVEBU_RTC_BASE + 0x14) #define MVEBU_RTC_CCR_REG (MVEBU_RTC_BASE + 0x18) #define MVEBU_RTC_NOMINAL_TIMING 0x2000 #define MVEBU_RTC_NOMINAL_TIMING_MASK 0x7FFF #define MVEBU_RTC_TEST_CONFIG_REG (MVEBU_RTC_BASE + 0x1C) #define MVEBU_RTC_BRIDGE_TIMING_CTRL0_REG (MVEBU_RTC_BASE + 0x80) #define MVEBU_RTC_WRCLK_PERIOD_MASK 0xFFFF #define MVEBU_RTC_WRCLK_PERIOD_DEFAULT 0x3FF #define MVEBU_RTC_WRCLK_SETUP_OFFS 16 #define MVEBU_RTC_WRCLK_SETUP_MASK 0xFFFF0000 #define MVEBU_RTC_WRCLK_SETUP_DEFAULT 0x29 #define MVEBU_RTC_BRIDGE_TIMING_CTRL1_REG (MVEBU_RTC_BASE + 0x84) #define MVEBU_RTC_READ_OUTPUT_DELAY_MASK 0xFFFF #define MVEBU_RTC_READ_OUTPUT_DELAY_DEFAULT 0x1F enum axi_attr { AXI_ADUNIT_ATTR = 0, AXI_COMUNIT_ATTR, AXI_EIP197_ATTR, AXI_USB3D_ATTR, AXI_USB3H0_ATTR, AXI_USB3H1_ATTR, AXI_SATA0_ATTR, AXI_SATA1_ATTR, AXI_DAP_ATTR, AXI_DFX_ATTR, AXI_DBG_TRC_ATTR = 12, AXI_SDIO_ATTR, AXI_MSS_ATTR, AXI_MAX_ATTR, }; /* Most stream IDS are configured centrally in the CP-110 RFU * but some are configured inside the unit registers */ #define RFU_STREAM_ID_BASE (0x450000) #define USB3H_0_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0xC) #define USB3H_1_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x10) #define SATA_0_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x14) #define SATA_1_STREAM_ID_REG (RFU_STREAM_ID_BASE + 0x18) #define CP_DMA_0_STREAM_ID_REG (0x6B0010) #define CP_DMA_1_STREAM_ID_REG (0x6D0010) /* We allocate IDs 128-255 for PCIe */ #define MAX_STREAM_ID (0x80) uintptr_t stream_id_reg[] = { USB3H_0_STREAM_ID_REG, USB3H_1_STREAM_ID_REG, CP_DMA_0_STREAM_ID_REG, CP_DMA_1_STREAM_ID_REG, SATA_0_STREAM_ID_REG, SATA_1_STREAM_ID_REG, 0 }; static void cp110_errata_wa_init(uintptr_t base) { uint32_t data; /* ERRATA GL-4076863: * Reset value for global_secure_enable inputs must be changed * from '1' to '0'. * When asserted, only "secured" transactions can enter IHB * configuration space. * However, blocking AXI transactions is performed by IOB. * Performing it also at IHB/HB complicates programming model. * * Enable non-secure access in SOC configuration register */ data = mmio_read_32(base + MVEBU_SOC_CFG_REG(MVEBU_SOC_CFG_REG_NUM)); data &= ~MVEBU_SOC_CFG_GLOG_SECURE_EN_MASK; mmio_write_32(base + MVEBU_SOC_CFG_REG(MVEBU_SOC_CFG_REG_NUM), data); } static void cp110_pcie_clk_cfg(uintptr_t base) { uint32_t pcie0_clk, pcie1_clk, reg; /* * Determine the pcie0/1 clock direction (input/output) from the * sample at reset. */ reg = mmio_read_32(base + MVEBU_SAMPLE_AT_RESET_REG); pcie0_clk = (reg & SAR_PCIE0_CLK_CFG_MASK) >> SAR_PCIE0_CLK_CFG_OFFSET; pcie1_clk = (reg & SAR_PCIE1_CLK_CFG_MASK) >> SAR_PCIE1_CLK_CFG_OFFSET; /* CP110 revision A2 */ if (cp110_rev_id_get(base) == MVEBU_CP110_REF_ID_A2) { /* * PCIe Reference Clock Buffer Control register must be * set according to the clock direction (input/output) */ reg = mmio_read_32(base + MVEBU_PCIE_REF_CLK_BUF_CTRL); reg &= ~(PCIE0_REFCLK_BUFF_SOURCE | PCIE1_REFCLK_BUFF_SOURCE); if (!pcie0_clk) reg |= PCIE0_REFCLK_BUFF_SOURCE; if (!pcie1_clk) reg |= PCIE1_REFCLK_BUFF_SOURCE; mmio_write_32(base + MVEBU_PCIE_REF_CLK_BUF_CTRL, reg); } /* CP110 revision A1 */ if (cp110_rev_id_get(base) == MVEBU_CP110_REF_ID_A1) { if (!pcie0_clk || !pcie1_clk) { /* * if one of the pcie clocks is set to input, * we need to set mss_push[131] field, otherwise, * the pcie clock might not work. */ reg = mmio_read_32(base + MVEBU_CP_MSS_DPSHSR_REG); reg |= MSS_DPSHSR_REG_PCIE_CLK_SEL; mmio_write_32(base + MVEBU_CP_MSS_DPSHSR_REG, reg); } } } /* Set a unique stream id for all DMA capable devices */ static void cp110_stream_id_init(uintptr_t base, uint32_t stream_id) { int i = 0; while (stream_id_reg[i]) { if (i > MAX_STREAM_ID_PER_CP) { NOTICE("Only first %d (maximum) Stream IDs allocated\n", MAX_STREAM_ID_PER_CP); return; } if ((stream_id_reg[i] == CP_DMA_0_STREAM_ID_REG) || (stream_id_reg[i] == CP_DMA_1_STREAM_ID_REG)) mmio_write_32(base + stream_id_reg[i], stream_id << 16 | stream_id); else mmio_write_32(base + stream_id_reg[i], stream_id); /* SATA port 0/1 are in the same SATA unit, and they should use * the same STREAM ID number */ if (stream_id_reg[i] != SATA_0_STREAM_ID_REG) stream_id++; i++; } } static void cp110_axi_attr_init(uintptr_t base) { uint32_t index, data; /* Initialize AXI attributes for Armada-7K/8K SoC */ /* Go over the AXI attributes and set Ax-Cache and Ax-Domain */ for (index = 0; index < AXI_MAX_ATTR; index++) { switch (index) { /* DFX and MSS unit works with no coherent only - * there's no option to configure the Ax-Cache and Ax-Domain */ case AXI_DFX_ATTR: case AXI_MSS_ATTR: continue; default: /* Set Ax-Cache as cacheable, no allocate, modifiable, * bufferable * The values are different because Read & Write * definition is different in Ax-Cache */ data = mmio_read_32(base + MVEBU_AXI_ATTR_REG(index)); data &= ~MVEBU_AXI_ATTR_ARCACHE_MASK; data |= (CACHE_ATTR_WRITE_ALLOC | CACHE_ATTR_CACHEABLE | CACHE_ATTR_BUFFERABLE) << MVEBU_AXI_ATTR_ARCACHE_OFFSET; data &= ~MVEBU_AXI_ATTR_AWCACHE_MASK; data |= (CACHE_ATTR_READ_ALLOC | CACHE_ATTR_CACHEABLE | CACHE_ATTR_BUFFERABLE) << MVEBU_AXI_ATTR_AWCACHE_OFFSET; /* Set Ax-Domain as Outer domain */ data &= ~MVEBU_AXI_ATTR_ARDOMAIN_MASK; data |= DOMAIN_OUTER_SHAREABLE << MVEBU_AXI_ATTR_ARDOMAIN_OFFSET; data &= ~MVEBU_AXI_ATTR_AWDOMAIN_MASK; data |= DOMAIN_OUTER_SHAREABLE << MVEBU_AXI_ATTR_AWDOMAIN_OFFSET; mmio_write_32(base + MVEBU_AXI_ATTR_REG(index), data); } } /* SATA IOCC supported, cache attributes * for SATA MBUS to AXI configuration. */ data = mmio_read_32(base + MVEBU_SATA_M2A_AXI_PORT_CTRL_REG); data &= ~MVEBU_SATA_M2A_AXI_AWCACHE_MASK; data |= (CACHE_ATTR_WRITE_ALLOC | CACHE_ATTR_CACHEABLE | CACHE_ATTR_BUFFERABLE) << MVEBU_SATA_M2A_AXI_AWCACHE_OFFSET; data &= ~MVEBU_SATA_M2A_AXI_ARCACHE_MASK; data |= (CACHE_ATTR_READ_ALLOC | CACHE_ATTR_CACHEABLE | CACHE_ATTR_BUFFERABLE) << MVEBU_SATA_M2A_AXI_ARCACHE_OFFSET; mmio_write_32(base + MVEBU_SATA_M2A_AXI_PORT_CTRL_REG, data); /* Set all IO's AXI attribute to non-secure access. */ for (index = 0; index < MVEBU_AXI_PROT_REGS_NUM; index++) mmio_write_32(base + MVEBU_AXI_PROT_REG(index), DOMAIN_SYSTEM_SHAREABLE); } static void amb_bridge_init(uintptr_t base) { uint32_t reg; /* Open AMB bridge Window to Access COMPHY/MDIO registers */ reg = mmio_read_32(base + MVEBU_AMB_IP_BRIDGE_WIN_REG(0)); reg &= ~(MVEBU_AMB_IP_BRIDGE_WIN_SIZE_MASK | MVEBU_AMB_IP_BRIDGE_WIN_EN_MASK); reg |= (0x7ff << MVEBU_AMB_IP_BRIDGE_WIN_SIZE_OFFSET) | (0x1 << MVEBU_AMB_IP_BRIDGE_WIN_EN_OFFSET); mmio_write_32(base + MVEBU_AMB_IP_BRIDGE_WIN_REG(0), reg); } static void cp110_rtc_init(uintptr_t base) { /* Update MBus timing parameters before accessing RTC registers */ mmio_clrsetbits_32(base + MVEBU_RTC_BRIDGE_TIMING_CTRL0_REG, MVEBU_RTC_WRCLK_PERIOD_MASK, MVEBU_RTC_WRCLK_PERIOD_DEFAULT); mmio_clrsetbits_32(base + MVEBU_RTC_BRIDGE_TIMING_CTRL0_REG, MVEBU_RTC_WRCLK_SETUP_MASK, MVEBU_RTC_WRCLK_SETUP_DEFAULT << MVEBU_RTC_WRCLK_SETUP_OFFS); mmio_clrsetbits_32(base + MVEBU_RTC_BRIDGE_TIMING_CTRL1_REG, MVEBU_RTC_READ_OUTPUT_DELAY_MASK, MVEBU_RTC_READ_OUTPUT_DELAY_DEFAULT); /* * Issue reset to the RTC if Clock Correction register * contents did not sustain the reboot/power-on. */ if ((mmio_read_32(base + MVEBU_RTC_CCR_REG) & MVEBU_RTC_NOMINAL_TIMING_MASK) != MVEBU_RTC_NOMINAL_TIMING) { /* Reset Test register */ mmio_write_32(base + MVEBU_RTC_TEST_CONFIG_REG, 0); mdelay(500); /* Reset Status register */ mmio_write_32(base + MVEBU_RTC_STATUS_REG, (MVEBU_RTC_STATUS_ALARM1_MASK | MVEBU_RTC_STATUS_ALARM2_MASK)); udelay(62); /* Turn off Int1 and Int2 sources & clear the Alarm count */ mmio_write_32(base + MVEBU_RTC_IRQ_1_CONFIG_REG, 0); mmio_write_32(base + MVEBU_RTC_IRQ_2_CONFIG_REG, 0); mmio_write_32(base + MVEBU_RTC_ALARM_1_REG, 0); mmio_write_32(base + MVEBU_RTC_ALARM_2_REG, 0); /* Setup nominal register access timing */ mmio_write_32(base + MVEBU_RTC_CCR_REG, MVEBU_RTC_NOMINAL_TIMING); /* Reset Status register */ mmio_write_32(base + MVEBU_RTC_STATUS_REG, (MVEBU_RTC_STATUS_ALARM1_MASK | MVEBU_RTC_STATUS_ALARM2_MASK)); udelay(50); } } static void cp110_amb_adec_init(uintptr_t base) { /* enable AXI-MBUS by clearing "Bridge Windows Disable" */ mmio_clrbits_32(base + MVEBU_BRIDGE_WIN_DIS_REG, (1 << MVEBU_BRIDGE_WIN_DIS_OFF)); /* configure AXI-MBUS windows for CP */ init_amb_adec(base); } void cp110_init(uintptr_t cp110_base, uint32_t stream_id) { INFO("%s: Initialize CPx - base = %lx\n", __func__, cp110_base); /* configure IOB windows for CP0*/ init_iob(cp110_base); /* configure AXI-MBUS windows for CP0*/ cp110_amb_adec_init(cp110_base); /* configure axi for CP0*/ cp110_axi_attr_init(cp110_base); /* Execute SW WA for erratas */ cp110_errata_wa_init(cp110_base); /* Confiure pcie clock according to clock direction */ cp110_pcie_clk_cfg(cp110_base); /* configure stream id for CP0 */ cp110_stream_id_init(cp110_base, stream_id); /* Open AMB bridge for comphy for CP0 & CP1*/ amb_bridge_init(cp110_base); /* Reset RTC if needed */ cp110_rtc_init(cp110_base); } /* Do the minimal setup required to configure the CP in BLE */ void cp110_ble_init(uintptr_t cp110_base) { #if PCI_EP_SUPPORT INFO("%s: Initialize CPx - base = %lx\n", __func__, cp110_base); amb_bridge_init(cp110_base); /* Configure PCIe clock */ cp110_pcie_clk_cfg(cp110_base); /* Configure PCIe endpoint */ ble_plat_pcie_ep_setup(); #endif } trusted-firmware-a-2.2/drivers/marvell/thermal.c000066400000000000000000000021561355360272700220350ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* Driver for thermal unit located in Marvell ARMADA 8K and compatible SoCs */ #include #include int marvell_thermal_init(struct tsen_config *tsen_cfg) { if (tsen_cfg->tsen_ready == 1) { INFO("thermal sensor is already initialized\n"); return 0; } if (tsen_cfg->ptr_tsen_probe == NULL) { ERROR("initial thermal sensor configuration is missing\n"); return -1; } if (tsen_cfg->ptr_tsen_probe(tsen_cfg)) { ERROR("thermal sensor initialization failed\n"); return -1; } VERBOSE("thermal sensor was initialized\n"); return 0; } int marvell_thermal_read(struct tsen_config *tsen_cfg, int *temp) { if (temp == NULL) { ERROR("NULL pointer for temperature read\n"); return -1; } if (tsen_cfg->ptr_tsen_read == NULL || tsen_cfg->tsen_ready == 0) { ERROR("thermal sensor was not initialized\n"); return -1; } if (tsen_cfg->ptr_tsen_read(tsen_cfg, temp)) { ERROR("temperature read failed\n"); return -1; } return 0; } trusted-firmware-a-2.2/drivers/marvell/uart/000077500000000000000000000000001355360272700212045ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/marvell/uart/a3700_console.S000066400000000000000000000153311355360272700236070ustar00rootroot00000000000000/* * Copyright (C) 2016 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include /* * "core" functions are low-level implementations that don't require * writable memory and are thus safe to call in BL1 crash context. */ .globl console_a3700_core_putc .globl console_a3700_core_init .globl console_a3700_core_getc .globl console_a3700_core_flush .globl console_a3700_putc .globl console_a3700_getc .globl console_a3700_flush /* ----------------------------------------------- * int console_a3700_core_init(unsigned long base_addr, * unsigned int uart_clk, unsigned int baud_rate) * Function to initialize the console without a * C Runtime to print debug information. This * function will be accessed by console_init and * crash reporting. * In: x0 - console base address * w1 - Uart clock in Hz * w2 - Baud rate * Out: return 1 on success * Clobber list : x1, x2, x3 * ----------------------------------------------- */ func console_a3700_core_init /* Check the input base address */ cbz x0, init_fail /* Check baud rate and uart clock for sanity */ cbz w1, init_fail cbz w2, init_fail /* Program the baudrate */ /* Divisor = Uart clock / (16 * baudrate) */ lsl w2, w2, #4 udiv w2, w1, w2 and w2, w2, #0x3ff ldr w3, [x0, #UART_BAUD_REG] bic w3, w3, 0x3ff orr w3, w3, w2 str w3, [x0, #UART_BAUD_REG]/* set baud rate divisor */ /* Set UART to default 16X scheme */ mov w3, #0 str w3, [x0, #UART_POSSR_REG] /* * Wait for the TX FIFO to be empty. If wait for 20ms, the TX FIFO is * still not empty, TX FIFO will reset by all means. */ mov w1, #20 /* max time out 20ms */ 2: /* Check whether TX FIFO is empty */ ldr w3, [x0, #UART_STATUS_REG] and w3, w3, #UARTLSR_TXFIFOEMPTY cmp w3, #0 b.ne 4f /* Delay */ mov w2, #30000 3: sub w2, w2, #1 cmp w2, #0 b.ne 3b /* Check whether 10ms is waited */ sub w1, w1, #1 cmp w1, #0 b.ne 2b 4: /* Reset FIFO */ mov w3, #UART_CTRL_RXFIFO_RESET orr w3, w3, #UART_CTRL_TXFIFO_RESET str w3, [x0, #UART_CTRL_REG] /* Delay */ mov w2, #2000 1: sub w2, w2, #1 cmp w2, #0 b.ne 1b /* No Parity, 1 Stop */ mov w3, #0 str w3, [x0, #UART_CTRL_REG] mov w0, #1 ret init_fail: mov w0, #0 ret endfunc console_a3700_core_init .globl console_a3700_register /* ----------------------------------------------- * int console_a3700_register(console_16550_t *console, uintptr_t base, uint32_t clk, uint32_t baud) * Function to initialize and register a new a3700 * console. Storage passed in for the console struct * *must* be persistent (i.e. not from the stack). * In: x0 - UART register base address * w1 - UART clock in Hz * w2 - Baud rate * x3 - pointer to empty console_a3700_t struct * Out: return 1 on success, 0 on error * Clobber list : x0, x1, x2, x6, x7, x14 * ----------------------------------------------- */ func console_a3700_register mov x7, x30 mov x6, x3 cbz x6, register_fail str x0, [x6, #CONSOLE_T_A3700_BASE] bl console_a3700_core_init cbz x0, register_fail mov x0, x6 mov x30, x7 finish_console_register a3700, putc=1, getc=1, flush=1 register_fail: ret x7 endfunc console_a3700_register /* -------------------------------------------------------- * int console_a3700_core_putc(int c, unsigned int base_addr) * Function to output a character over the console. It * returns the character printed on success or -1 on error. * In : w0 - character to be printed * x1 - console base address * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_a3700_core_putc /* Check the input parameter */ cbz x1, putc_error /* Prepend '\r' to '\n' */ cmp w0, #0xA b.ne 2f /* Check if the transmit FIFO is full */ 1: ldr w2, [x1, #UART_STATUS_REG] and w2, w2, #UARTLSR_TXFIFOFULL cmp w2, #UARTLSR_TXFIFOFULL b.eq 1b mov w2, #0xD /* '\r' */ str w2, [x1, #UART_TX_REG] /* Check if the transmit FIFO is full */ 2: ldr w2, [x1, #UART_STATUS_REG] and w2, w2, #UARTLSR_TXFIFOFULL cmp w2, #UARTLSR_TXFIFOFULL b.eq 2b str w0, [x1, #UART_TX_REG] ret putc_error: mov w0, #-1 ret endfunc console_a3700_core_putc /* -------------------------------------------------------- * int console_a3700_putc(int c, console_a3700_t *console) * Function to output a character over the console. It * returns the character printed on success or -1 on error. * In : w0 - character to be printed * x1 - pointer to console_t structure * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_a3700_putc ldr x1, [x1, #CONSOLE_T_A3700_BASE] b console_a3700_core_putc endfunc console_a3700_putc /* --------------------------------------------- * int console_a3700_core_getc(void) * Function to get a character from the console. * It returns the character grabbed on success * or -1 on error. * In : w0 - console base address * Out : return -1 on error else return character. * Clobber list : x0, x1 * --------------------------------------------- */ func console_a3700_core_getc mov w0, #-1 ret endfunc console_a3700_core_getc /* --------------------------------------------- * int console_a3700_getc(console_a3700_t *console) * Function to get a character from the console. * It returns the character grabbed on success * or -1 on if no character is available. * In : x0 - pointer to console_t structure * Out : w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ func console_a3700_getc ldr x0, [x0, #CONSOLE_T_A3700_BASE] b console_a3700_core_getc endfunc console_a3700_getc /* --------------------------------------------- * int console_a3700_core_flush(uintptr_t base_addr) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - console base address * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func console_a3700_core_flush mov w0, #0 ret endfunc console_a3700_core_flush /* --------------------------------------------- * int console_a3700_flush(console_a3700_t *console) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - pointer to console_t structure * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func console_a3700_flush ldr x0, [x0, #CONSOLE_T_A3700_BASE] b console_a3700_core_flush endfunc console_a3700_flush trusted-firmware-a-2.2/drivers/mentor/000077500000000000000000000000001355360272700200735ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/mentor/i2c/000077500000000000000000000000001355360272700205505ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/mentor/i2c/mi2cv.c000066400000000000000000000355711355360272700217470ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * Copyright (C) 2018 Icenowy Zheng * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* * This driver is for Mentor Graphics Inventra MI2CV IP core, which is used * for Marvell and Allwinner SoCs in ATF. */ #include #include #include #include #include #include #if LOG_LEVEL >= LOG_LEVEL_VERBOSE #define DEBUG_I2C #endif #define I2C_TIMEOUT_VALUE 0x500 #define I2C_MAX_RETRY_CNT 1000 #define I2C_CMD_WRITE 0x0 #define I2C_CMD_READ 0x1 #define I2C_DATA_ADDR_7BIT_OFFS 0x1 #define I2C_DATA_ADDR_7BIT_MASK (0xFF << I2C_DATA_ADDR_7BIT_OFFS) #define I2C_CONTROL_ACK 0x00000004 #define I2C_CONTROL_IFLG 0x00000008 #define I2C_CONTROL_STOP 0x00000010 #define I2C_CONTROL_START 0x00000020 #define I2C_CONTROL_TWSIEN 0x00000040 #define I2C_CONTROL_INTEN 0x00000080 #define I2C_STATUS_START 0x08 #define I2C_STATUS_REPEATED_START 0x10 #define I2C_STATUS_ADDR_W_ACK 0x18 #define I2C_STATUS_DATA_W_ACK 0x28 #define I2C_STATUS_LOST_ARB_DATA_ADDR_TRANSFER 0x38 #define I2C_STATUS_ADDR_R_ACK 0x40 #define I2C_STATUS_DATA_R_ACK 0x50 #define I2C_STATUS_DATA_R_NAK 0x58 #define I2C_STATUS_LOST_ARB_GENERAL_CALL 0x78 #define I2C_STATUS_IDLE 0xF8 #define I2C_UNSTUCK_TRIGGER 0x1 #define I2C_UNSTUCK_ONGOING 0x2 #define I2C_UNSTUCK_ERROR 0x4 static struct mentor_i2c_regs *base; static int mentor_i2c_lost_arbitration(uint32_t *status) { *status = mmio_read_32((uintptr_t)&base->status); if ((*status == I2C_STATUS_LOST_ARB_DATA_ADDR_TRANSFER) || (*status == I2C_STATUS_LOST_ARB_GENERAL_CALL)) return -EAGAIN; return 0; } static void mentor_i2c_interrupt_clear(void) { uint32_t reg; reg = mmio_read_32((uintptr_t)&base->control); #ifndef I2C_INTERRUPT_CLEAR_INVERTED reg &= ~(I2C_CONTROL_IFLG); #else reg |= I2C_CONTROL_IFLG; #endif mmio_write_32((uintptr_t)&base->control, reg); /* Wait for 1 us for the clear to take effect */ udelay(1); } static int mentor_i2c_interrupt_get(void) { uint32_t reg; /* get the interrupt flag bit */ reg = mmio_read_32((uintptr_t)&base->control); reg &= I2C_CONTROL_IFLG; return reg && I2C_CONTROL_IFLG; } static int mentor_i2c_wait_interrupt(void) { uint32_t timeout = 0; while (!mentor_i2c_interrupt_get() && (timeout++ < I2C_TIMEOUT_VALUE)) ; if (timeout >= I2C_TIMEOUT_VALUE) return -ETIMEDOUT; return 0; } static int mentor_i2c_start_bit_set(void) { int is_int_flag = 0; uint32_t status; if (mentor_i2c_interrupt_get()) is_int_flag = 1; /* set start bit */ mmio_write_32((uintptr_t)&base->control, mmio_read_32((uintptr_t)&base->control) | I2C_CONTROL_START); /* in case that the int flag was set before i.e. repeated start bit */ if (is_int_flag) { VERBOSE("%s: repeated start Bit\n", __func__); mentor_i2c_interrupt_clear(); } if (mentor_i2c_wait_interrupt()) { ERROR("Start clear bit timeout\n"); return -ETIMEDOUT; } /* check that start bit went down */ if ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_START) != 0) { ERROR("Start bit didn't went down\n"); return -EPERM; } /* check the status */ if (mentor_i2c_lost_arbitration(&status)) { ERROR("%s - %d: Lost arbitration, got status %x\n", __func__, __LINE__, status); return -EAGAIN; } if ((status != I2C_STATUS_START) && (status != I2C_STATUS_REPEATED_START)) { ERROR("Got status %x after enable start bit.\n", status); return -EPERM; } return 0; } static int mentor_i2c_stop_bit_set(void) { int timeout; uint32_t status; /* Generate stop bit */ mmio_write_32((uintptr_t)&base->control, mmio_read_32((uintptr_t)&base->control) | I2C_CONTROL_STOP); mentor_i2c_interrupt_clear(); timeout = 0; /* Read control register, check the control stop bit */ while ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_STOP) && (timeout++ < I2C_TIMEOUT_VALUE)) ; if (timeout >= I2C_TIMEOUT_VALUE) { ERROR("Stop bit didn't went down\n"); return -ETIMEDOUT; } /* check that stop bit went down */ if ((mmio_read_32((uintptr_t)&base->control) & I2C_CONTROL_STOP) != 0) { ERROR("Stop bit didn't went down\n"); return -EPERM; } /* check the status */ if (mentor_i2c_lost_arbitration(&status)) { ERROR("%s - %d: Lost arbitration, got status %x\n", __func__, __LINE__, status); return -EAGAIN; } if (status != I2C_STATUS_IDLE) { ERROR("Got status %x after enable stop bit.\n", status); return -EPERM; } return 0; } static int mentor_i2c_address_set(uint8_t chain, int command) { uint32_t reg, status; reg = (chain << I2C_DATA_ADDR_7BIT_OFFS) & I2C_DATA_ADDR_7BIT_MASK; reg |= command; mmio_write_32((uintptr_t)&base->data, reg); udelay(1); mentor_i2c_interrupt_clear(); if (mentor_i2c_wait_interrupt()) { ERROR("Start clear bit timeout\n"); return -ETIMEDOUT; } /* check the status */ if (mentor_i2c_lost_arbitration(&status)) { ERROR("%s - %d: Lost arbitration, got status %x\n", __func__, __LINE__, status); return -EAGAIN; } if (((status != I2C_STATUS_ADDR_R_ACK) && (command == I2C_CMD_READ)) || ((status != I2C_STATUS_ADDR_W_ACK) && (command == I2C_CMD_WRITE))) { /* only in debug, since in boot we try to read the SPD * of both DRAM, and we don't want error messages in cas * DIMM doesn't exist. */ INFO("%s: ERROR - status %x addr in %s mode.\n", __func__, status, (command == I2C_CMD_WRITE) ? "Write" : "Read"); return -EPERM; } return 0; } /* * The I2C module contains a clock divider to generate the SCL clock. * This function calculates and sets the and fields in the I2C Baud * Rate Register (t=01) to obtain given 'requested_speed'. * The requested_speed will be equal to: * CONFIG_SYS_TCLK / (10 * (M + 1) * (2 << N)) * Where M is the value represented by bits[6:3] and N is the value represented * by bits[2:0] of "I2C Baud Rate Register". * Therefore max M which can be set is 16 (2^4) and max N is 8 (2^3). So the * lowest possible baudrate is: * CONFIG_SYS_TCLK/(10 * (16 +1) * (2 << 8), which equals to: * CONFIG_SYS_TCLK/87040. Assuming that CONFIG_SYS_TCLK=250MHz, the lowest * possible frequency is ~2,872KHz. */ static unsigned int mentor_i2c_bus_speed_set(unsigned int requested_speed) { unsigned int n, m, freq, margin, min_margin = 0xffffffff; unsigned int actual_n = 0, actual_m = 0; int val; /* Calculate N and M for the TWSI clock baud rate */ for (n = 0; n < 8; n++) { for (m = 0; m < 16; m++) { freq = CONFIG_SYS_TCLK / (10 * (m + 1) * (2 << n)); val = requested_speed - freq; margin = (val > 0) ? val : -val; if ((freq <= requested_speed) && (margin < min_margin)) { min_margin = margin; actual_n = n; actual_m = m; } } } VERBOSE("%s: actual_n = %u, actual_m = %u\n", __func__, actual_n, actual_m); /* Set the baud rate */ mmio_write_32((uintptr_t)&base->baudrate, (actual_m << 3) | actual_n); return 0; } #ifdef DEBUG_I2C static int mentor_i2c_probe(uint8_t chip) { int ret = 0; ret = mentor_i2c_start_bit_set(); if (ret != 0) { mentor_i2c_stop_bit_set(); ERROR("%s - %d: %s", __func__, __LINE__, "mentor_i2c_start_bit_set failed\n"); return -EPERM; } ret = mentor_i2c_address_set(chip, I2C_CMD_WRITE); if (ret != 0) { mentor_i2c_stop_bit_set(); ERROR("%s - %d: %s", __func__, __LINE__, "mentor_i2c_address_set failed\n"); return -EPERM; } mentor_i2c_stop_bit_set(); VERBOSE("%s: successful I2C probe\n", __func__); return ret; } #endif /* regular i2c transaction */ static int mentor_i2c_data_receive(uint8_t *p_block, uint32_t block_size) { uint32_t reg, status, block_size_read = block_size; /* Wait for cause interrupt */ if (mentor_i2c_wait_interrupt()) { ERROR("Start clear bit timeout\n"); return -ETIMEDOUT; } while (block_size_read) { if (block_size_read == 1) { reg = mmio_read_32((uintptr_t)&base->control); reg &= ~(I2C_CONTROL_ACK); mmio_write_32((uintptr_t)&base->control, reg); } mentor_i2c_interrupt_clear(); if (mentor_i2c_wait_interrupt()) { ERROR("Start clear bit timeout\n"); return -ETIMEDOUT; } /* check the status */ if (mentor_i2c_lost_arbitration(&status)) { ERROR("%s - %d: Lost arbitration, got status %x\n", __func__, __LINE__, status); return -EAGAIN; } if ((status != I2C_STATUS_DATA_R_ACK) && (block_size_read != 1)) { ERROR("Status %x in read transaction\n", status); return -EPERM; } if ((status != I2C_STATUS_DATA_R_NAK) && (block_size_read == 1)) { ERROR("Status %x in Rd Terminate\n", status); return -EPERM; } /* read the data */ *p_block = (uint8_t) mmio_read_32((uintptr_t)&base->data); VERBOSE("%s: place %d read %x\n", __func__, block_size - block_size_read, *p_block); p_block++; block_size_read--; } return 0; } static int mentor_i2c_data_transmit(uint8_t *p_block, uint32_t block_size) { uint32_t status, block_size_write = block_size; if (mentor_i2c_wait_interrupt()) { ERROR("Start clear bit timeout\n"); return -ETIMEDOUT; } while (block_size_write) { /* write the data */ mmio_write_32((uintptr_t)&base->data, (uint32_t) *p_block); VERBOSE("%s: index = %d, data = %x\n", __func__, block_size - block_size_write, *p_block); p_block++; block_size_write--; mentor_i2c_interrupt_clear(); if (mentor_i2c_wait_interrupt()) { ERROR("Start clear bit timeout\n"); return -ETIMEDOUT; } /* check the status */ if (mentor_i2c_lost_arbitration(&status)) { ERROR("%s - %d: Lost arbitration, got status %x\n", __func__, __LINE__, status); return -EAGAIN; } if (status != I2C_STATUS_DATA_W_ACK) { ERROR("Status %x in write transaction\n", status); return -EPERM; } } return 0; } static int mentor_i2c_target_offset_set(uint8_t chip, uint32_t addr, int alen) { uint8_t off_block[2]; uint32_t off_size; if (alen == 2) { /* 2-byte addresses support */ off_block[0] = (addr >> 8) & 0xff; off_block[1] = addr & 0xff; off_size = 2; } else { /* 1-byte addresses support */ off_block[0] = addr & 0xff; off_size = 1; } VERBOSE("%s: off_size = %x addr1 = %x addr2 = %x\n", __func__, off_size, off_block[0], off_block[1]); return mentor_i2c_data_transmit(off_block, off_size); } #ifdef I2C_CAN_UNSTUCK static int mentor_i2c_unstuck(int ret) { uint32_t v; if (ret != -ETIMEDOUT) return ret; VERBOSE("Trying to \"unstuck i2c\"... "); i2c_init(base); mmio_write_32((uintptr_t)&base->unstuck, I2C_UNSTUCK_TRIGGER); do { v = mmio_read_32((uintptr_t)&base->unstuck); } while (v & I2C_UNSTUCK_ONGOING); if (v & I2C_UNSTUCK_ERROR) { VERBOSE("failed - soft reset i2c\n"); ret = -EPERM; } else { VERBOSE("ok\n"); i2c_init(base); ret = -EAGAIN; } return ret; } #else static int mentor_i2c_unstuck(int ret) { VERBOSE("Cannot \"unstuck i2c\" - soft reset i2c\n"); return -EPERM; } #endif /* * API Functions */ void i2c_init(void *i2c_base) { /* For I2C speed and slave address, now we do not set them since * we just provide the working speed and slave address otherwhere * for i2c_init */ base = (struct mentor_i2c_regs *)i2c_base; /* Reset the I2C logic */ mmio_write_32((uintptr_t)&base->soft_reset, 0); udelay(200); mentor_i2c_bus_speed_set(CONFIG_SYS_I2C_SPEED); /* Enable the I2C and slave */ mmio_write_32((uintptr_t)&base->control, I2C_CONTROL_TWSIEN | I2C_CONTROL_ACK); /* set the I2C slave address */ mmio_write_32((uintptr_t)&base->xtnd_slave_addr, 0); mmio_write_32((uintptr_t)&base->slave_address, CONFIG_SYS_I2C_SLAVE); /* unmask I2C interrupt */ mmio_write_32((uintptr_t)&base->control, mmio_read_32((uintptr_t)&base->control) | I2C_CONTROL_INTEN); udelay(10); } /* * i2c_read: - Read multiple bytes from an i2c device * * The higher level routines take into account that this function is only * called with len < page length of the device (see configuration file) * * @chip: address of the chip which is to be read * @addr: i2c data address within the chip * @alen: length of the i2c data address (1..2 bytes) * @buffer: where to write the data * @len: how much byte do we want to read * @return: 0 in case of success */ int i2c_read(uint8_t chip, uint32_t addr, int alen, uint8_t *buffer, int len) { int ret = 0; uint32_t counter = 0; #ifdef DEBUG_I2C mentor_i2c_probe(chip); #endif do { if (ret != -EAGAIN && ret) { ERROR("i2c transaction failed, after %d retries\n", counter); mentor_i2c_stop_bit_set(); return ret; } /* wait for 1 us for the interrupt clear to take effect */ if (counter > 0) udelay(1); counter++; ret = mentor_i2c_start_bit_set(); if (ret) { ret = mentor_i2c_unstuck(ret); continue; } /* if EEPROM device */ if (alen != 0) { ret = mentor_i2c_address_set(chip, I2C_CMD_WRITE); if (ret) continue; ret = mentor_i2c_target_offset_set(chip, addr, alen); if (ret) continue; ret = mentor_i2c_start_bit_set(); if (ret) continue; } ret = mentor_i2c_address_set(chip, I2C_CMD_READ); if (ret) continue; ret = mentor_i2c_data_receive(buffer, len); if (ret) continue; ret = mentor_i2c_stop_bit_set(); } while ((ret == -EAGAIN) && (counter < I2C_MAX_RETRY_CNT)); if (counter == I2C_MAX_RETRY_CNT) { ERROR("I2C transactions failed, got EAGAIN %d times\n", I2C_MAX_RETRY_CNT); ret = -EPERM; } mmio_write_32((uintptr_t)&base->control, mmio_read_32((uintptr_t)&base->control) | I2C_CONTROL_ACK); udelay(1); return ret; } /* * i2c_write: - Write multiple bytes to an i2c device * * The higher level routines take into account that this function is only * called with len < page length of the device (see configuration file) * * @chip: address of the chip which is to be written * @addr: i2c data address within the chip * @alen: length of the i2c data address (1..2 bytes) * @buffer: where to find the data to be written * @len: how much byte do we want to read * @return: 0 in case of success */ int i2c_write(uint8_t chip, uint32_t addr, int alen, uint8_t *buffer, int len) { int ret = 0; uint32_t counter = 0; do { if (ret != -EAGAIN && ret) { ERROR("i2c transaction failed\n"); mentor_i2c_stop_bit_set(); return ret; } /* wait for 1 us for the interrupt clear to take effect */ if (counter > 0) udelay(1); counter++; ret = mentor_i2c_start_bit_set(); if (ret) { ret = mentor_i2c_unstuck(ret); continue; } ret = mentor_i2c_address_set(chip, I2C_CMD_WRITE); if (ret) continue; /* if EEPROM device */ if (alen != 0) { ret = mentor_i2c_target_offset_set(chip, addr, alen); if (ret) continue; } ret = mentor_i2c_data_transmit(buffer, len); if (ret) continue; ret = mentor_i2c_stop_bit_set(); } while ((ret == -EAGAIN) && (counter < I2C_MAX_RETRY_CNT)); if (counter == I2C_MAX_RETRY_CNT) { ERROR("I2C transactions failed, got EAGAIN %d times\n", I2C_MAX_RETRY_CNT); ret = -EPERM; } udelay(1); return ret; } trusted-firmware-a-2.2/drivers/mmc/000077500000000000000000000000001355360272700173435ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/mmc/mmc.c000066400000000000000000000352721355360272700202740ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* Define a simple and generic interface to access eMMC and SD-card devices. */ #include #include #include #include #include #include #include #include #include #define MMC_DEFAULT_MAX_RETRIES 5 #define SEND_OP_COND_MAX_RETRIES 100 #define MULT_BY_512K_SHIFT 19 static const struct mmc_ops *ops; static unsigned int mmc_ocr_value; static struct mmc_csd_emmc mmc_csd; static unsigned char mmc_ext_csd[512] __aligned(16); static unsigned int mmc_flags; static struct mmc_device_info *mmc_dev_info; static unsigned int rca; static unsigned int scr[2]__aligned(16) = { 0 }; static const unsigned char tran_speed_base[16] = { 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80 }; static const unsigned char sd_tran_speed_base[16] = { 0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80 }; static bool is_cmd23_enabled(void) { return ((mmc_flags & MMC_FLAG_CMD23) != 0U); } static int mmc_send_cmd(unsigned int idx, unsigned int arg, unsigned int r_type, unsigned int *r_data) { struct mmc_cmd cmd; int ret; zeromem(&cmd, sizeof(struct mmc_cmd)); cmd.cmd_idx = idx; cmd.cmd_arg = arg; cmd.resp_type = r_type; ret = ops->send_cmd(&cmd); if ((ret == 0) && (r_data != NULL)) { int i; for (i = 0; i < 4; i++) { *r_data = cmd.resp_data[i]; r_data++; } } if (ret != 0) { VERBOSE("Send command %u error: %d\n", idx, ret); } return ret; } static int mmc_device_state(void) { int retries = MMC_DEFAULT_MAX_RETRIES; unsigned int resp_data[4]; do { int ret; if (retries == 0) { ERROR("CMD13 failed after %d retries\n", MMC_DEFAULT_MAX_RETRIES); return -EIO; } ret = mmc_send_cmd(MMC_CMD(13), rca << RCA_SHIFT_OFFSET, MMC_RESPONSE_R1, &resp_data[0]); if (ret != 0) { retries--; continue; } if ((resp_data[0] & STATUS_SWITCH_ERROR) != 0U) { return -EIO; } retries--; } while ((resp_data[0] & STATUS_READY_FOR_DATA) == 0U); return MMC_GET_STATE(resp_data[0]); } static int mmc_set_ext_csd(unsigned int ext_cmd, unsigned int value) { int ret; ret = mmc_send_cmd(MMC_CMD(6), EXTCSD_WRITE_BYTES | EXTCSD_CMD(ext_cmd) | EXTCSD_VALUE(value) | EXTCSD_CMD_SET_NORMAL, MMC_RESPONSE_R1B, NULL); if (ret != 0) { return ret; } do { ret = mmc_device_state(); if (ret < 0) { return ret; } } while (ret == MMC_STATE_PRG); return 0; } static int mmc_sd_switch(unsigned int bus_width) { int ret; int retries = MMC_DEFAULT_MAX_RETRIES; unsigned int bus_width_arg = 0; ret = ops->prepare(0, (uintptr_t)&scr, sizeof(scr)); if (ret != 0) { return ret; } /* CMD55: Application Specific Command */ ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET, MMC_RESPONSE_R5, NULL); if (ret != 0) { return ret; } /* ACMD51: SEND_SCR */ do { ret = mmc_send_cmd(MMC_ACMD(51), 0, MMC_RESPONSE_R1, NULL); if ((ret != 0) && (retries == 0)) { ERROR("ACMD51 failed after %d retries (ret=%d)\n", MMC_DEFAULT_MAX_RETRIES, ret); return ret; } retries--; } while (ret != 0); ret = ops->read(0, (uintptr_t)&scr, sizeof(scr)); if (ret != 0) { return ret; } if (((scr[0] & SD_SCR_BUS_WIDTH_4) != 0U) && (bus_width == MMC_BUS_WIDTH_4)) { bus_width_arg = 2; } /* CMD55: Application Specific Command */ ret = mmc_send_cmd(MMC_CMD(55), rca << RCA_SHIFT_OFFSET, MMC_RESPONSE_R5, NULL); if (ret != 0) { return ret; } /* ACMD6: SET_BUS_WIDTH */ ret = mmc_send_cmd(MMC_ACMD(6), bus_width_arg, MMC_RESPONSE_R1, NULL); if (ret != 0) { return ret; } do { ret = mmc_device_state(); if (ret < 0) { return ret; } } while (ret == MMC_STATE_PRG); return 0; } static int mmc_set_ios(unsigned int clk, unsigned int bus_width) { int ret; unsigned int width = bus_width; if (mmc_dev_info->mmc_dev_type != MMC_IS_EMMC) { if (width == MMC_BUS_WIDTH_8) { WARN("Wrong bus config for SD-card, force to 4\n"); width = MMC_BUS_WIDTH_4; } ret = mmc_sd_switch(width); if (ret != 0) { return ret; } } else if (mmc_csd.spec_vers == 4U) { ret = mmc_set_ext_csd(CMD_EXTCSD_BUS_WIDTH, (unsigned int)width); if (ret != 0) { return ret; } } else { VERBOSE("Wrong MMC type or spec version\n"); } return ops->set_ios(clk, width); } static int mmc_fill_device_info(void) { unsigned long long c_size; unsigned int speed_idx; unsigned int nb_blocks; unsigned int freq_unit; int ret = 0; struct mmc_csd_sd_v2 *csd_sd_v2; switch (mmc_dev_info->mmc_dev_type) { case MMC_IS_EMMC: mmc_dev_info->block_size = MMC_BLOCK_SIZE; ret = ops->prepare(0, (uintptr_t)&mmc_ext_csd, sizeof(mmc_ext_csd)); if (ret != 0) { return ret; } /* MMC CMD8: SEND_EXT_CSD */ ret = mmc_send_cmd(MMC_CMD(8), 0, MMC_RESPONSE_R1, NULL); if (ret != 0) { return ret; } ret = ops->read(0, (uintptr_t)&mmc_ext_csd, sizeof(mmc_ext_csd)); if (ret != 0) { 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) | (mmc_ext_csd[CMD_EXTCSD_SEC_CNT + 3] << 24); mmc_dev_info->device_size = (unsigned long long)nb_blocks * mmc_dev_info->block_size; break; case MMC_IS_SD: /* * Use the same mmc_csd struct, as required fields here * (READ_BL_LEN, C_SIZE, CSIZE_MULT) are common with eMMC. */ mmc_dev_info->block_size = BIT_32(mmc_csd.read_bl_len); c_size = ((unsigned long long)mmc_csd.c_size_high << 2U) | (unsigned long long)mmc_csd.c_size_low; assert(c_size != 0xFFFU); mmc_dev_info->device_size = (c_size + 1U) * BIT_64(mmc_csd.c_size_mult + 2U) * mmc_dev_info->block_size; break; case MMC_IS_SD_HC: assert(mmc_csd.csd_structure == 1U); mmc_dev_info->block_size = MMC_BLOCK_SIZE; /* Need to use mmc_csd_sd_v2 struct */ csd_sd_v2 = (struct mmc_csd_sd_v2 *)&mmc_csd; c_size = ((unsigned long long)csd_sd_v2->c_size_high << 16) | (unsigned long long)csd_sd_v2->c_size_low; mmc_dev_info->device_size = (c_size + 1U) << MULT_BY_512K_SHIFT; break; default: ret = -EINVAL; break; } if (ret < 0) { return ret; } speed_idx = (mmc_csd.tran_speed & CSD_TRAN_SPEED_MULT_MASK) >> CSD_TRAN_SPEED_MULT_SHIFT; assert(speed_idx > 0U); if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) { mmc_dev_info->max_bus_freq = tran_speed_base[speed_idx]; } else { mmc_dev_info->max_bus_freq = sd_tran_speed_base[speed_idx]; } freq_unit = mmc_csd.tran_speed & CSD_TRAN_SPEED_UNIT_MASK; while (freq_unit != 0U) { mmc_dev_info->max_bus_freq *= 10U; --freq_unit; } mmc_dev_info->max_bus_freq *= 10000U; return 0; } static int sd_send_op_cond(void) { int n; unsigned int resp_data[4]; for (n = 0; n < SEND_OP_COND_MAX_RETRIES; n++) { int ret; /* CMD55: Application Specific Command */ ret = mmc_send_cmd(MMC_CMD(55), 0, MMC_RESPONSE_R1, NULL); if (ret != 0) { return ret; } /* ACMD41: SD_SEND_OP_COND */ ret = mmc_send_cmd(MMC_ACMD(41), OCR_HCS | mmc_dev_info->ocr_voltage, MMC_RESPONSE_R3, &resp_data[0]); if (ret != 0) { return ret; } if ((resp_data[0] & OCR_POWERUP) != 0U) { mmc_ocr_value = resp_data[0]; if ((mmc_ocr_value & OCR_HCS) != 0U) { mmc_dev_info->mmc_dev_type = MMC_IS_SD_HC; } else { mmc_dev_info->mmc_dev_type = MMC_IS_SD; } return 0; } mdelay(10); } ERROR("ACMD41 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES); return -EIO; } static int mmc_reset_to_idle(void) { int ret; /* CMD0: reset to IDLE */ ret = mmc_send_cmd(MMC_CMD(0), 0, 0, NULL); if (ret != 0) { return ret; } mdelay(2); return 0; } static int mmc_send_op_cond(void) { int ret, n; unsigned int resp_data[4]; 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 | OCR_VDD_MIN_2V7 | OCR_VDD_MIN_1V7, MMC_RESPONSE_R3, &resp_data[0]); if (ret != 0) { return ret; } if ((resp_data[0] & OCR_POWERUP) != 0U) { mmc_ocr_value = resp_data[0]; return 0; } mdelay(10); } ERROR("CMD1 failed after %d retries\n", SEND_OP_COND_MAX_RETRIES); return -EIO; } static int mmc_enumerate(unsigned int clk, unsigned int bus_width) { int ret; unsigned int resp_data[4]; ops->init(); 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(); } else { /* CMD8: Send Interface Condition Command */ ret = mmc_send_cmd(MMC_CMD(8), VHS_2_7_3_6_V | CMD8_CHECK_PATTERN, MMC_RESPONSE_R5, &resp_data[0]); if ((ret == 0) && ((resp_data[0] & 0xffU) == CMD8_CHECK_PATTERN)) { ret = sd_send_op_cond(); } } if (ret != 0) { return ret; } /* CMD2: Card Identification */ ret = mmc_send_cmd(MMC_CMD(2), 0, MMC_RESPONSE_R2, NULL); if (ret != 0) { return ret; } /* CMD3: Set Relative Address */ if (mmc_dev_info->mmc_dev_type == MMC_IS_EMMC) { rca = MMC_FIX_RCA; ret = mmc_send_cmd(MMC_CMD(3), rca << RCA_SHIFT_OFFSET, MMC_RESPONSE_R1, NULL); if (ret != 0) { return ret; } } else { ret = mmc_send_cmd(MMC_CMD(3), 0, MMC_RESPONSE_R6, &resp_data[0]); if (ret != 0) { return ret; } rca = (resp_data[0] & 0xFFFF0000U) >> 16; } /* CMD9: CSD Register */ ret = mmc_send_cmd(MMC_CMD(9), rca << RCA_SHIFT_OFFSET, MMC_RESPONSE_R2, &resp_data[0]); if (ret != 0) { return ret; } memcpy(&mmc_csd, &resp_data, sizeof(resp_data)); /* CMD7: Select Card */ ret = mmc_send_cmd(MMC_CMD(7), rca << RCA_SHIFT_OFFSET, MMC_RESPONSE_R1, NULL); if (ret != 0) { return ret; } do { ret = mmc_device_state(); if (ret < 0) { return ret; } } while (ret != MMC_STATE_TRAN); ret = mmc_set_ios(clk, bus_width); if (ret != 0) { return ret; } return mmc_fill_device_info(); } size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size) { int ret; unsigned int cmd_idx, cmd_arg; assert((ops != NULL) && (ops->read != NULL) && (size != 0U) && ((size & MMC_BLOCK_MASK) == 0U)); ret = ops->prepare(lba, buf, size); if (ret != 0) { return 0; } if (is_cmd23_enabled()) { /* Set block count */ ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE, MMC_RESPONSE_R1, NULL); if (ret != 0) { return 0; } cmd_idx = MMC_CMD(18); } else { if (size > MMC_BLOCK_SIZE) { cmd_idx = MMC_CMD(18); } else { cmd_idx = MMC_CMD(17); } } if (((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) && (mmc_dev_info->mmc_dev_type != MMC_IS_SD_HC)) { cmd_arg = lba * MMC_BLOCK_SIZE; } else { cmd_arg = lba; } ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL); if (ret != 0) { return 0; } ret = ops->read(lba, buf, size); if (ret != 0) { return 0; } /* Wait buffer empty */ do { ret = mmc_device_state(); if (ret < 0) { return 0; } } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_DATA)); if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) { ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL); if (ret != 0) { return 0; } } return size; } size_t mmc_write_blocks(int lba, const uintptr_t buf, size_t size) { int ret; unsigned int cmd_idx, cmd_arg; assert((ops != NULL) && (ops->write != NULL) && (size != 0U) && ((buf & MMC_BLOCK_MASK) == 0U) && ((size & MMC_BLOCK_MASK) == 0U)); ret = ops->prepare(lba, buf, size); if (ret != 0) { return 0; } if (is_cmd23_enabled()) { /* Set block count */ ret = mmc_send_cmd(MMC_CMD(23), size / MMC_BLOCK_SIZE, MMC_RESPONSE_R1, NULL); if (ret != 0) { return 0; } cmd_idx = MMC_CMD(25); } else { if (size > MMC_BLOCK_SIZE) { cmd_idx = MMC_CMD(25); } else { cmd_idx = MMC_CMD(24); } } if ((mmc_ocr_value & OCR_ACCESS_MODE_MASK) == OCR_BYTE_MODE) { cmd_arg = lba * MMC_BLOCK_SIZE; } else { cmd_arg = lba; } ret = mmc_send_cmd(cmd_idx, cmd_arg, MMC_RESPONSE_R1, NULL); if (ret != 0) { return 0; } ret = ops->write(lba, buf, size); if (ret != 0) { return 0; } /* Wait buffer empty */ do { ret = mmc_device_state(); if (ret < 0) { return 0; } } while ((ret != MMC_STATE_TRAN) && (ret != MMC_STATE_RCV)); if (!is_cmd23_enabled() && (size > MMC_BLOCK_SIZE)) { ret = mmc_send_cmd(MMC_CMD(12), 0, MMC_RESPONSE_R1B, NULL); if (ret != 0) { return 0; } } return size; } size_t mmc_erase_blocks(int lba, size_t size) { int ret; assert(ops != NULL); assert((size != 0U) && ((size & MMC_BLOCK_MASK) == 0U)); ret = mmc_send_cmd(MMC_CMD(35), lba, MMC_RESPONSE_R1, NULL); if (ret != 0) { return 0; } ret = mmc_send_cmd(MMC_CMD(36), lba + (size / MMC_BLOCK_SIZE) - 1U, MMC_RESPONSE_R1, NULL); if (ret != 0) { return 0; } ret = mmc_send_cmd(MMC_CMD(38), lba, MMC_RESPONSE_R1B, NULL); if (ret != 0) { return 0; } do { ret = mmc_device_state(); if (ret < 0) { return 0; } } while (ret != MMC_STATE_TRAN); return size; } static inline void mmc_rpmb_enable(void) { mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG, PART_CFG_BOOT_PARTITION1_ENABLE | PART_CFG_PARTITION1_ACCESS); } static inline void mmc_rpmb_disable(void) { mmc_set_ext_csd(CMD_EXTCSD_PARTITION_CONFIG, PART_CFG_BOOT_PARTITION1_ENABLE); } size_t mmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size) { size_t size_read; mmc_rpmb_enable(); size_read = mmc_read_blocks(lba, buf, size); mmc_rpmb_disable(); return size_read; } size_t mmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size) { size_t size_written; mmc_rpmb_enable(); size_written = mmc_write_blocks(lba, buf, size); mmc_rpmb_disable(); return size_written; } size_t mmc_rpmb_erase_blocks(int lba, size_t size) { size_t size_erased; mmc_rpmb_enable(); size_erased = mmc_erase_blocks(lba, size); mmc_rpmb_disable(); return size_erased; } int mmc_init(const struct mmc_ops *ops_ptr, unsigned int clk, unsigned int width, unsigned int flags, struct mmc_device_info *device_info) { assert((ops_ptr != NULL) && (ops_ptr->init != NULL) && (ops_ptr->send_cmd != NULL) && (ops_ptr->set_ios != NULL) && (ops_ptr->prepare != NULL) && (ops_ptr->read != NULL) && (ops_ptr->write != NULL) && (device_info != NULL) && (clk != 0) && ((width == MMC_BUS_WIDTH_1) || (width == MMC_BUS_WIDTH_4) || (width == MMC_BUS_WIDTH_8) || (width == MMC_BUS_WIDTH_DDR_4) || (width == MMC_BUS_WIDTH_DDR_8))); ops = ops_ptr; mmc_flags = flags; mmc_dev_info = device_info; return mmc_enumerate(clk, width); } trusted-firmware-a-2.2/drivers/partition/000077500000000000000000000000001355360272700206005ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/partition/gpt.c000066400000000000000000000025561355360272700215460ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include static int unicode_to_ascii(unsigned short *str_in, unsigned char *str_out) { uint8_t *name; int i; 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) { if (name[i] != '\0') return -EINVAL; } /* convert the unicode string to ascii string */ for (i = 0; i < (EFI_NAMELEN << 1); i += 2) { str_out[i >> 1] = name[i]; if (name[i] == '\0') break; } return 0; } int parse_gpt_entry(gpt_entry_t *gpt_entry, partition_entry_t *entry) { int result; assert((gpt_entry != NULL) && (entry != NULL)); if ((gpt_entry->first_lba == 0) && (gpt_entry->last_lba == 0)) { return -EINVAL; } zeromem(entry, sizeof(partition_entry_t)); result = unicode_to_ascii(gpt_entry->name, (uint8_t *)entry->name); if (result != 0) { return result; } entry->start = (uint64_t)gpt_entry->first_lba * PLAT_PARTITION_BLOCK_SIZE; entry->length = (uint64_t)(gpt_entry->last_lba - gpt_entry->first_lba + 1) * PLAT_PARTITION_BLOCK_SIZE; return 0; } trusted-firmware-a-2.2/drivers/partition/partition.c000066400000000000000000000142741355360272700227650ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include static uint8_t mbr_sector[PLAT_PARTITION_BLOCK_SIZE]; static partition_entry_list_t list; #if LOG_LEVEL >= LOG_LEVEL_VERBOSE static void dump_entries(int num) { char name[EFI_NAMELEN]; int i, j, len; VERBOSE("Partition table with %d entries:\n", num); for (i = 0; i < num; i++) { len = snprintf(name, EFI_NAMELEN, "%s", list.list[i].name); for (j = 0; j < EFI_NAMELEN - len - 1; j++) { name[len + j] = ' '; } name[EFI_NAMELEN - 1] = '\0'; VERBOSE("%d: %s %llx-%llx\n", i + 1, name, list.list[i].start, list.list[i].start + list.list[i].length - 4); } } #else #define dump_entries(num) ((void)num) #endif /* * Load the first sector that carries MBR header. * The MBR boot signature should be always valid whether it's MBR or GPT. */ static int load_mbr_header(uintptr_t image_handle, mbr_entry_t *mbr_entry) { size_t bytes_read; uintptr_t offset; int result; assert(mbr_entry != NULL); /* MBR partition table is in LBA0. */ result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); if (result != 0) { WARN("Failed to seek (%i)\n", result); return result; } result = io_read(image_handle, (uintptr_t)&mbr_sector, PLAT_PARTITION_BLOCK_SIZE, &bytes_read); if (result != 0) { WARN("Failed to read data (%i)\n", result); return result; } /* Check MBR boot signature. */ if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { return -ENOENT; } offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET; memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t)); return 0; } /* * Load GPT header and check the GPT signature. * If partition numbers could be found, check & update it. */ static int load_gpt_header(uintptr_t image_handle) { gpt_header_t header; size_t bytes_read; int result; result = io_seek(image_handle, IO_SEEK_SET, GPT_HEADER_OFFSET); if (result != 0) { return result; } result = io_read(image_handle, (uintptr_t)&header, sizeof(gpt_header_t), &bytes_read); if ((result != 0) || (sizeof(gpt_header_t) != bytes_read)) { return result; } if (memcmp(header.signature, GPT_SIGNATURE, sizeof(header.signature)) != 0) { return -EINVAL; } /* partition numbers can't exceed PLAT_PARTITION_MAX_ENTRIES */ list.entry_count = header.list_num; if (list.entry_count > PLAT_PARTITION_MAX_ENTRIES) { list.entry_count = PLAT_PARTITION_MAX_ENTRIES; } return 0; } static int load_mbr_entry(uintptr_t image_handle, mbr_entry_t *mbr_entry, int part_number) { size_t bytes_read; uintptr_t offset; int result; assert(mbr_entry != NULL); /* MBR partition table is in LBA0. */ result = io_seek(image_handle, IO_SEEK_SET, MBR_OFFSET); if (result != 0) { WARN("Failed to seek (%i)\n", result); return result; } result = io_read(image_handle, (uintptr_t)&mbr_sector, PLAT_PARTITION_BLOCK_SIZE, &bytes_read); if (result != 0) { WARN("Failed to read data (%i)\n", result); return result; } /* Check MBR boot signature. */ if ((mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 2] != MBR_SIGNATURE_FIRST) || (mbr_sector[LEGACY_PARTITION_BLOCK_SIZE - 1] != MBR_SIGNATURE_SECOND)) { return -ENOENT; } offset = (uintptr_t)&mbr_sector + MBR_PRIMARY_ENTRY_OFFSET + MBR_PRIMARY_ENTRY_SIZE * part_number; memcpy(mbr_entry, (void *)offset, sizeof(mbr_entry_t)); return 0; } static int load_mbr_entries(uintptr_t image_handle) { mbr_entry_t mbr_entry; int i; list.entry_count = MBR_PRIMARY_ENTRY_NUMBER; for (i = 0; i < list.entry_count; i++) { load_mbr_entry(image_handle, &mbr_entry, i); list.list[i].start = mbr_entry.first_lba * 512; list.list[i].length = mbr_entry.sector_nums * 512; list.list[i].name[0] = mbr_entry.type; } return 0; } static int load_gpt_entry(uintptr_t image_handle, gpt_entry_t *entry) { size_t bytes_read; int result; assert(entry != NULL); result = io_read(image_handle, (uintptr_t)entry, sizeof(gpt_entry_t), &bytes_read); if (sizeof(gpt_entry_t) != bytes_read) return -EINVAL; return result; } static int verify_partition_gpt(uintptr_t image_handle) { gpt_entry_t entry; int result, i; for (i = 0; i < list.entry_count; i++) { result = load_gpt_entry(image_handle, &entry); assert(result == 0); result = parse_gpt_entry(&entry, &list.list[i]); if (result != 0) { break; } } if (i == 0) { return -EINVAL; } /* * Only records the valid partition number that is loaded from * partition table. */ list.entry_count = i; dump_entries(list.entry_count); return 0; } int load_partition_table(unsigned int image_id) { uintptr_t dev_handle, image_handle, image_spec = 0; mbr_entry_t mbr_entry; int result; result = plat_get_image_source(image_id, &dev_handle, &image_spec); if (result != 0) { WARN("Failed to obtain reference to image id=%u (%i)\n", image_id, result); return result; } result = io_open(dev_handle, image_spec, &image_handle); if (result != 0) { WARN("Failed to access image id=%u (%i)\n", image_id, result); return result; } result = load_mbr_header(image_handle, &mbr_entry); if (result != 0) { WARN("Failed to access image id=%u (%i)\n", image_id, result); return result; } if (mbr_entry.type == PARTITION_TYPE_GPT) { result = load_gpt_header(image_handle); assert(result == 0); result = io_seek(image_handle, IO_SEEK_SET, GPT_ENTRY_OFFSET); assert(result == 0); result = verify_partition_gpt(image_handle); } else { result = load_mbr_entries(image_handle); } io_close(image_handle); return result; } const partition_entry_t *get_partition_entry(const char *name) { int i; for (i = 0; i < list.entry_count; i++) { if (strcmp(name, list.list[i].name) == 0) { return &list.list[i]; } } return NULL; } const partition_entry_list_t *get_partition_entry_list(void) { return &list; } void partition_init(unsigned int image_id) { load_partition_table(image_id); } trusted-firmware-a-2.2/drivers/renesas/000077500000000000000000000000001355360272700202275ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/000077500000000000000000000000001355360272700211565ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/auth/000077500000000000000000000000001355360272700221175ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/auth/auth_mod.c000066400000000000000000000104111355360272700240600ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights * reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "rom_api.h" typedef int32_t(*secure_boot_api_f) (uint32_t a, uint32_t b, void *c); extern int32_t rcar_get_certificate(const int32_t name, uint32_t *cert_addr); #define RCAR_IMAGE_ID_MAX (10) #define RCAR_CERT_MAGIC_NUM (0xE291F358U) #define RCAR_BOOT_KEY_CERT (0xE6300C00U) #define RCAR_BOOT_KEY_CERT_NEW (0xE6300F00U) #define RST_BASE (0xE6160000U) #define RST_MODEMR (RST_BASE + 0x0060U) #define MFISOFTMDR (0xE6260600U) #define MODEMR_MD5_MASK (0x00000020U) #define MODEMR_MD5_SHIFT (5U) #define SOFTMD_BOOTMODE_MASK (0x00000001U) #define SOFTMD_NORMALBOOT (0x1U) static secure_boot_api_f secure_boot_api; int auth_mod_get_parent_id(unsigned int img_id, unsigned int *parent_id) { return 1; } int auth_mod_verify_img(unsigned int img_id, void *ptr, unsigned int len) { int32_t ret = 0, index = 0; uint32_t cert_addr = 0U; static const struct img_to_cert_t { uint32_t id; int32_t cert; const char *name; } image[RCAR_IMAGE_ID_MAX] = { { BL31_IMAGE_ID, SOC_FW_CONTENT_CERT_ID, "BL31" }, { BL32_IMAGE_ID, TRUSTED_OS_FW_CONTENT_CERT_ID, "BL32" }, { BL33_IMAGE_ID, NON_TRUSTED_FW_CONTENT_CERT_ID, "BL33" }, { BL332_IMAGE_ID, BL332_CERT_ID, "BL332" }, { BL333_IMAGE_ID, BL333_CERT_ID, "BL333" }, { BL334_IMAGE_ID, BL334_CERT_ID, "BL334" }, { BL335_IMAGE_ID, BL335_CERT_ID, "BL335" }, { BL336_IMAGE_ID, BL336_CERT_ID, "BL336" }, { BL337_IMAGE_ID, BL337_CERT_ID, "BL337" }, { BL338_IMAGE_ID, BL338_CERT_ID, "BL338" }, }; #if IMAGE_BL2 switch (img_id) { case TRUSTED_KEY_CERT_ID: case SOC_FW_KEY_CERT_ID: case TRUSTED_OS_FW_KEY_CERT_ID: case NON_TRUSTED_FW_KEY_CERT_ID: case BL332_KEY_CERT_ID: case BL333_KEY_CERT_ID: case BL334_KEY_CERT_ID: case BL335_KEY_CERT_ID: case BL336_KEY_CERT_ID: case BL337_KEY_CERT_ID: case BL338_KEY_CERT_ID: case SOC_FW_CONTENT_CERT_ID: case TRUSTED_OS_FW_CONTENT_CERT_ID: case NON_TRUSTED_FW_CONTENT_CERT_ID: case BL332_CERT_ID: case BL333_CERT_ID: case BL334_CERT_ID: case BL335_CERT_ID: case BL336_CERT_ID: case BL337_CERT_ID: case BL338_CERT_ID: return ret; case BL31_IMAGE_ID: case BL32_IMAGE_ID: case BL33_IMAGE_ID: case BL332_IMAGE_ID: case BL333_IMAGE_ID: case BL334_IMAGE_ID: case BL335_IMAGE_ID: case BL336_IMAGE_ID: case BL337_IMAGE_ID: case BL338_IMAGE_ID: goto verify_image; default: return -1; } verify_image: for (index = 0; index < RCAR_IMAGE_ID_MAX; index++) { if (img_id != image[index].id) continue; ret = rcar_get_certificate(image[index].cert, &cert_addr); break; } if (ret || (index == RCAR_IMAGE_ID_MAX)) { ERROR("Verification Failed for image id = %d\n", img_id); return ret; } #if RCAR_BL2_DCACHE == 1 /* clean and disable */ write_sctlr_el3(read_sctlr_el3() & ~SCTLR_C_BIT); dcsw_op_all(DCCISW); #endif ret = (mmio_read_32(RCAR_BOOT_KEY_CERT_NEW) == RCAR_CERT_MAGIC_NUM) ? secure_boot_api(RCAR_BOOT_KEY_CERT_NEW, cert_addr, NULL) : secure_boot_api(RCAR_BOOT_KEY_CERT, cert_addr, NULL); if (ret) ERROR("Verification Failed 0x%x, %s\n", ret, image[index].name); #if RCAR_BL2_DCACHE == 1 /* enable */ write_sctlr_el3(read_sctlr_el3() | SCTLR_C_BIT); #endif #endif return ret; } static int32_t normal_boot_verify(uint32_t a, uint32_t b, void *c) { return 0; } void auth_mod_init(void) { #if RCAR_SECURE_BOOT uint32_t soft_md = mmio_read_32(MFISOFTMDR) & SOFTMD_BOOTMODE_MASK; uint32_t md = mmio_read_32(RST_MODEMR) & MODEMR_MD5_MASK; uint32_t lcs, ret; secure_boot_api = (secure_boot_api_f) &rcar_rom_secure_boot_api; ret = rcar_rom_get_lcs(&lcs); if (ret) { ERROR("BL2: Failed to get the LCS. (%d)\n", ret); panic(); } switch (lcs) { case LCS_SE: if (soft_md == SOFTMD_NORMALBOOT) secure_boot_api = &normal_boot_verify; break; case LCS_SD: secure_boot_api = &normal_boot_verify; break; default: if (md >> MODEMR_MD5_SHIFT) secure_boot_api = &normal_boot_verify; } NOTICE("BL2: %s boot\n", secure_boot_api == &normal_boot_verify ? "Normal" : "Secure"); #else NOTICE("BL2: Normal boot\n"); secure_boot_api = &normal_boot_verify; #endif } trusted-firmware-a-2.2/drivers/renesas/rcar/avs/000077500000000000000000000000001355360272700217475ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/avs/avs_driver.c000066400000000000000000000446431355360272700242720ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "cpg_registers.h" #include "avs_driver.h" #include "rcar_def.h" #include "rcar_private.h" #if (AVS_SETTING_ENABLE == 1) #if PMIC_ROHM_BD9571 /* Read PMIC register for debug. 1:enable / 0:disable */ #define AVS_READ_PMIC_REG_ENABLE 0 /* The re-try number of times of the AVS setting. */ #define AVS_RETRY_NUM (1U) #endif /* PMIC_ROHM_BD9571 */ /* Base address of Adaptive Voltage Scaling module registers*/ #define AVS_BASE (0xE60A0000U) /* Adaptive Dynamic Voltage ADJust Parameter2 registers */ #define ADVADJP2 (AVS_BASE + 0x013CU) /* Mask VOLCOND bit in ADVADJP2 registers */ #define ADVADJP2_VOLCOND_MASK (0x000001FFU) /* VOLCOND[8:0] */ #if PMIC_ROHM_BD9571 /* I2C for DVFS bit in CPG registers for module standby and software reset*/ #define CPG_SYS_DVFS_BIT (0x04000000U) #endif /* PMIC_ROHM_BD9571 */ /* ADVFS Module bit in CPG registers for module standby and software reset*/ #define CPG_SYS_ADVFS_BIT (0x02000000U) #if PMIC_ROHM_BD9571 /* Base address of IICDVFS registers*/ #define IIC_DVFS_BASE (0xE60B0000U) /* IIC bus data register */ #define IIC_ICDR (IIC_DVFS_BASE + 0x0000U) /* IIC bus control register */ #define IIC_ICCR (IIC_DVFS_BASE + 0x0004U) /* IIC bus status register */ #define IIC_ICSR (IIC_DVFS_BASE + 0x0008U) /* IIC interrupt control register */ #define IIC_ICIC (IIC_DVFS_BASE + 0x000CU) /* IIC clock control register low */ #define IIC_ICCL (IIC_DVFS_BASE + 0x0010U) /* IIC clock control register high */ #define IIC_ICCH (IIC_DVFS_BASE + 0x0014U) /* Bit in ICSR register */ #define ICSR_BUSY (0x10U) #define ICSR_AL (0x08U) #define ICSR_TACK (0x04U) #define ICSR_WAIT (0x02U) #define ICSR_DTE (0x01U) /* Bit in ICIC register */ #define ICIC_TACKE (0x04U) #define ICIC_WAITE (0x02U) #define ICIC_DTEE (0x01U) /* I2C bus interface enable */ #define ICCR_ENABLE (0x80U) /* Start condition */ #define ICCR_START (0x94U) /* Stop condition */ #define ICCR_STOP (0x90U) /* Restart condition with change to receive mode change */ #define ICCR_START_RECV (0x81U) /* Stop condition for receive mode */ #define ICCR_STOP_RECV (0xC0U) /* Low-level period of SCL */ #define ICCL_FREQ_8p33M (0x07U) /* for CP Phy 8.3333MHz */ #define ICCL_FREQ_10M (0x09U) /* for CP Phy 10MHz */ #define ICCL_FREQ_12p5M (0x0BU) /* for CP Phy 12.5MHz */ #define ICCL_FREQ_16p66M (0x0EU) /* for CP Phy 16.6666MHz */ /* High-level period of SCL */ #define ICCH_FREQ_8p33M (0x01U) /* for CP Phy 8.3333MHz */ #define ICCH_FREQ_10M (0x02U) /* for CP Phy 10MHz */ #define ICCH_FREQ_12p5M (0x03U) /* for CP Phy 12.5MHz */ #define ICCH_FREQ_16p66M (0x05U) /* for CP Phy 16.6666MHz */ /* PMIC */ #define PMIC_W_SLAVE_ADDRESS (0x60U) /* ROHM BD9571 slave address + (W) */ #define PMIC_R_SLAVE_ADDRESS (0x61U) /* ROHM BD9571 slave address + (R) */ #define PMIC_DVFS_SETVID (0x54U) /* ROHM BD9571 DVFS SetVID register */ #endif /* PMIC_ROHM_BD9571 */ /* Individual information */ #define EFUSE_AVS0 (0U) #define EFUSE_AVS_NUM ARRAY_SIZE(init_vol_tbl) typedef struct { uint32_t avs; /* AVS code */ uint8_t vol; /* Voltage */ } initial_voltage_t; static const initial_voltage_t init_vol_tbl[] = { /* AVS code, RHOM BD9571 DVFS SetVID register */ {0x00U, 0x53U}, /* AVS0, 0.83V */ {0x01U, 0x52U}, /* AVS1, 0.82V */ {0x02U, 0x51U}, /* AVS2, 0.81V */ {0x04U, 0x50U}, /* AVS3, 0.80V */ {0x08U, 0x4FU}, /* AVS4, 0.79V */ {0x10U, 0x4EU}, /* AVS5, 0.78V */ {0x20U, 0x4DU}, /* AVS6, 0.77V */ {0x40U, 0x4CU} /* AVS7, 0.76V */ }; #if PMIC_ROHM_BD9571 /* Kind of AVS settings status */ typedef enum { avs_status_none = 0, avs_status_init, avs_status_start_condition, avs_status_set_slave_addr, avs_status_write_reg_addr, avs_status_write_reg_data, avs_status_stop_condition, avs_status_end, avs_status_complete, avs_status_al_start, avs_status_al_transfer, avs_status_nack, avs_status_error_stop, ave_status_error_end } avs_status_t; /* Kind of AVS error */ typedef enum { avs_error_none = 0, avs_error_al, avs_error_nack } avs_error_t; static avs_status_t avs_status; static uint32_t avs_retry; #endif /* PMIC_ROHM_BD9571 */ static uint32_t efuse_avs = EFUSE_AVS0; #if PMIC_ROHM_BD9571 /* prototype */ static avs_error_t avs_check_error(void); static void avs_set_iic_clock(void); #if AVS_READ_PMIC_REG_ENABLE == 1 static uint8_t avs_read_pmic_reg(uint8_t addr); static void avs_poll(uint8_t bit_pos, uint8_t val); #endif #endif /* PMIC_ROHM_BD9571 */ #endif /* (AVS_SETTING_ENABLE==1) */ /* * Initialize to enable the AVS setting. */ void rcar_avs_init(void) { #if (AVS_SETTING_ENABLE == 1) uint32_t val; #if PMIC_ROHM_BD9571 /* Initialize AVS status */ avs_status = avs_status_init; #endif /* PMIC_ROHM_BD9571 */ /* Enable clock supply to ADVFS. */ mstpcr_write(CPG_SMSTPCR9, CPG_MSTPSR9, CPG_SYS_ADVFS_BIT); /* Read AVS code (Initial values are derived from eFuse) */ val = mmio_read_32(ADVADJP2) & ADVADJP2_VOLCOND_MASK; for (efuse_avs = 0U; efuse_avs < EFUSE_AVS_NUM; efuse_avs++) { if (val == init_vol_tbl[efuse_avs].avs) break; } if (efuse_avs >= EFUSE_AVS_NUM) efuse_avs = EFUSE_AVS0; /* Not applicable */ #if PMIC_ROHM_BD9571 /* Enable clock supply to DVFS. */ mstpcr_write(CPG_SMSTPCR9, CPG_MSTPSR9, CPG_SYS_DVFS_BIT); /* Disable I2C module and All internal registers initialized. */ mmio_write_8(IIC_ICCR, 0x00U); while ((mmio_read_8(IIC_ICCR) & ICCR_ENABLE) != 0U) { /* Disable I2C module and All internal registers initialized. */ mmio_write_8(IIC_ICCR, 0x00U); } /* Set next status */ avs_status = avs_status_start_condition; #endif /* PMIC_ROHM_BD9571 */ #endif /* (AVS_SETTING_ENABLE==1) */ } /* * Set the value of register corresponding to the voltage * by transfer of I2C to PIMC. */ void rcar_avs_setting(void) { #if (AVS_SETTING_ENABLE == 1) #if PMIC_ROHM_BD9571 avs_error_t err; switch (avs_status) { case avs_status_start_condition: /* Set ICCR.ICE=1 to activate the I2C module. */ mmio_write_8(IIC_ICCR, mmio_read_8(IIC_ICCR) | ICCR_ENABLE); /* Set frequency of 400kHz */ avs_set_iic_clock(); /* Set ICIC.TACKE=1, ICIC.WAITE=1, ICIC.DTEE=1 to */ /* enable interrupt control. */ mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) | ICIC_TACKE | ICIC_WAITE | ICIC_DTEE); /* Write H'94 in ICCR to issue start condition */ mmio_write_8(IIC_ICCR, ICCR_START); /* Set next status */ avs_status = avs_status_set_slave_addr; break; case avs_status_set_slave_addr: /* Check error. */ err = avs_check_error(); if (err == avs_error_al) { /* Recovery sequence of just after start. */ avs_status = avs_status_al_start; } else if (err == avs_error_nack) { /* Recovery sequence of detected NACK */ avs_status = avs_status_nack; } else { /* Was data transmission enabled ? */ if ((mmio_read_8(IIC_ICSR) & ICSR_DTE) == ICSR_DTE) { /* Clear ICIC.DTEE to disable a DTE interrupt */ mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) & (uint8_t) (~ICIC_DTEE)); /* Send PMIC slave address + (W) */ mmio_write_8(IIC_ICDR, PMIC_W_SLAVE_ADDRESS); /* Set next status */ avs_status = avs_status_write_reg_addr; } } break; case avs_status_write_reg_addr: /* Check error. */ err = avs_check_error(); if (err == avs_error_al) { /* Recovery sequence of during data transfer. */ avs_status = avs_status_al_transfer; } else if (err == avs_error_nack) { /* Recovery sequence of detected NACK */ avs_status = avs_status_nack; } else { /* If wait state after data transmission. */ if ((mmio_read_8(IIC_ICSR) & ICSR_WAIT) == ICSR_WAIT) { /* Write PMIC DVFS_SetVID address */ mmio_write_8(IIC_ICDR, PMIC_DVFS_SETVID); /* Clear ICSR.WAIT to exit from wait state. */ mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_WAIT)); /* Set next status */ avs_status = avs_status_write_reg_data; } } break; case avs_status_write_reg_data: /* Check error. */ err = avs_check_error(); if (err == avs_error_al) { /* Recovery sequence of during data transfer. */ avs_status = avs_status_al_transfer; } else if (err == avs_error_nack) { /* Recovery sequence of detected NACK */ avs_status = avs_status_nack; } else { /* If wait state after data transmission. */ if ((mmio_read_8(IIC_ICSR) & ICSR_WAIT) == ICSR_WAIT) { /* Dose efuse_avs exceed the number of */ /* the tables? */ if (efuse_avs >= EFUSE_AVS_NUM) { ERROR("AVS number of eFuse is out " "of a range. number=%u\n", efuse_avs); /* Infinite loop */ panic(); } /* Write PMIC DVFS_SetVID value */ mmio_write_8(IIC_ICDR, init_vol_tbl[efuse_avs].vol); /* Clear ICSR.WAIT to exit from wait state. */ mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_WAIT)); /* Set next status */ avs_status = avs_status_stop_condition; } } break; case avs_status_stop_condition: err = avs_check_error(); if (err == avs_error_al) { /* Recovery sequence of during data transfer. */ avs_status = avs_status_al_transfer; } else if (err == avs_error_nack) { /* Recovery sequence of detected NACK */ avs_status = avs_status_nack; } else { /* If wait state after data transmission. */ if ((mmio_read_8(IIC_ICSR) & ICSR_WAIT) == ICSR_WAIT) { /* Write H'90 in ICCR to issue stop condition */ mmio_write_8(IIC_ICCR, ICCR_STOP); /* Clear ICSR.WAIT to exit from wait state. */ mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_WAIT)); /* Set next status */ avs_status = avs_status_end; } } break; case avs_status_end: /* Is this module not busy?. */ if ((mmio_read_8(IIC_ICSR) & ICSR_BUSY) == 0U) { /* Set ICCR=H'00 to disable the I2C module. */ mmio_write_8(IIC_ICCR, 0x00U); /* Set next status */ avs_status = avs_status_complete; } break; case avs_status_al_start: /* Clear ICSR.AL bit */ mmio_write_8(IIC_ICSR, (mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_AL))); /* Transmit a clock pulse */ mmio_write_8(IIC_ICDR, init_vol_tbl[EFUSE_AVS0].vol); /* Set next status */ avs_status = avs_status_error_stop; break; case avs_status_al_transfer: /* Clear ICSR.AL bit */ mmio_write_8(IIC_ICSR, (mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_AL))); /* Set next status */ avs_status = avs_status_error_stop; break; case avs_status_nack: /* Write H'90 in ICCR to issue stop condition */ mmio_write_8(IIC_ICCR, ICCR_STOP); /* Disable a WAIT and DTEE interrupt. */ mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) & (uint8_t) (~(ICIC_WAITE | ICIC_DTEE))); /* Clear ICSR.TACK bit */ mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_TACK)); /* Set next status */ avs_status = ave_status_error_end; break; case avs_status_error_stop: /* If wait state after data transmission. */ if ((mmio_read_8(IIC_ICSR) & ICSR_WAIT) == ICSR_WAIT) { /* Write H'90 in ICCR to issue stop condition */ mmio_write_8(IIC_ICCR, ICCR_STOP); /* Clear ICSR.WAIT to exit from wait state. */ mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_WAIT)); /* Set next status */ avs_status = ave_status_error_end; } break; case ave_status_error_end: /* Is this module not busy?. */ if ((mmio_read_8(IIC_ICSR) & ICSR_BUSY) == 0U) { /* Set ICCR=H'00 to disable the I2C module. */ mmio_write_8(IIC_ICCR, 0x00U); /* Increment the re-try number of times. */ avs_retry++; /* Set start a re-try to status. */ avs_status = avs_status_start_condition; } break; case avs_status_complete: /* After "avs_status" became the "avs_status_complete", */ /* "avs_setting()" function may be called. */ break; default: /* This case is not possible. */ ERROR("AVS setting is in invalid status. status=%u\n", avs_status); /* Infinite loop */ panic(); break; } #endif /* PMIC_ROHM_BD9571 */ #endif /* (AVS_SETTING_ENABLE==1) */ } /* * Finish the AVS setting. */ void rcar_avs_end(void) { #if (AVS_SETTING_ENABLE == 1) uint32_t mstp; #if PMIC_ROHM_BD9571 /* While status is not completion, be repeated. */ while (avs_status != avs_status_complete) rcar_avs_setting(); NOTICE("AVS setting succeeded. DVFS_SetVID=0x%x\n", init_vol_tbl[efuse_avs].vol); #if AVS_READ_PMIC_REG_ENABLE == 1 { uint8_t addr = PMIC_DVFS_SETVID; uint8_t value = avs_read_pmic_reg(addr); NOTICE("Read PMIC register. address=0x%x value=0x%x \n", addr, value); } #endif /* Bit of the module which wants to disable clock supply. */ mstp = CPG_SYS_DVFS_BIT; /* Disables the supply of clock signal to a module. */ cpg_write(CPG_SMSTPCR9, mmio_read_32(CPG_SMSTPCR9) | mstp); #endif /* PMIC_ROHM_BD9571 */ /* Bit of the module which wants to disable clock supply. */ mstp = CPG_SYS_ADVFS_BIT; /* Disables the supply of clock signal to a module. */ cpg_write(CPG_SMSTPCR9, mmio_read_32(CPG_SMSTPCR9) | mstp); #endif /* (AVS_SETTING_ENABLE==1) */ } #if (AVS_SETTING_ENABLE == 1) #if PMIC_ROHM_BD9571 /* * Check error and judge re-try. */ static avs_error_t avs_check_error(void) { avs_error_t ret; if ((mmio_read_8(IIC_ICSR) & ICSR_AL) == ICSR_AL) { NOTICE("Loss of arbitration is detected. " "AVS status=%d Retry=%u\n", avs_status, avs_retry); /* Check of retry number of times */ if (avs_retry >= AVS_RETRY_NUM) { ERROR("AVS setting failed in retry. max=%u\n", AVS_RETRY_NUM); /* Infinite loop */ panic(); } /* Set the error detected to error status. */ ret = avs_error_al; } else if ((mmio_read_8(IIC_ICSR) & ICSR_TACK) == ICSR_TACK) { NOTICE("Non-acknowledge is detected. " "AVS status=%d Retry=%u\n", avs_status, avs_retry); /* Check of retry number of times */ if (avs_retry >= AVS_RETRY_NUM) { ERROR("AVS setting failed in retry. max=%u\n", AVS_RETRY_NUM); /* Infinite loop */ panic(); } /* Set the error detected to error status. */ ret = avs_error_nack; } else { /* Not error. */ ret = avs_error_none; } return ret; } /* * Set I2C for DVFS clock. */ static void avs_set_iic_clock(void) { uint32_t md_pin; /* Read Mode pin register. */ md_pin = mmio_read_32(RCAR_MODEMR) & CHECK_MD13_MD14; /* Set the module clock (CP phy) for the IIC-DVFS. */ /* CP phy is EXTAL / 2. */ switch (md_pin) { case MD14_MD13_TYPE_0: /* EXTAL = 16.6666MHz */ mmio_write_8(IIC_ICCL, ICCL_FREQ_8p33M); mmio_write_8(IIC_ICCH, ICCH_FREQ_8p33M); break; case MD14_MD13_TYPE_1: /* EXTAL = 20MHz */ mmio_write_8(IIC_ICCL, ICCL_FREQ_10M); mmio_write_8(IIC_ICCH, ICCH_FREQ_10M); break; case MD14_MD13_TYPE_2: /* EXTAL = 25MHz (H3/M3) */ mmio_write_8(IIC_ICCL, ICCL_FREQ_12p5M); mmio_write_8(IIC_ICCH, ICCH_FREQ_12p5M); break; case MD14_MD13_TYPE_3: /* EXTAL = 33.3333MHz */ mmio_write_8(IIC_ICCL, ICCL_FREQ_16p66M); mmio_write_8(IIC_ICCH, ICCH_FREQ_16p66M); break; default: /* This case is not possible. */ /* CP Phy frequency is to be set for the 16.66MHz */ mmio_write_8(IIC_ICCL, ICCL_FREQ_16p66M); mmio_write_8(IIC_ICCH, ICCH_FREQ_16p66M); break; } } #if AVS_READ_PMIC_REG_ENABLE == 1 /* * Read the value of the register of PMIC. */ static uint8_t avs_read_pmic_reg(uint8_t addr) { uint8_t reg; /* Set ICCR.ICE=1 to activate the I2C module. */ mmio_write_8(IIC_ICCR, mmio_read_8(IIC_ICCR) | ICCR_ENABLE); /* Set frequency of 400kHz */ avs_set_iic_clock(); /* Set ICIC.WAITE=1, ICIC.DTEE=1 to enable data transmission */ /* interrupt and wait interrupt. */ mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) | ICIC_WAITE | ICIC_DTEE); /* Write H'94 in ICCR to issue start condition */ mmio_write_8(IIC_ICCR, ICCR_START); /* Wait for a until ICSR.DTE becomes 1. */ avs_poll(ICSR_DTE, 1U); /* Clear ICIC.DTEE to disable a DTE interrupt. */ mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) & (uint8_t) (~ICIC_DTEE)); /* Send slave address of PMIC */ mmio_write_8(IIC_ICDR, PMIC_W_SLAVE_ADDRESS); /* Wait for a until ICSR.WAIT becomes 1. */ avs_poll(ICSR_WAIT, 1U); /* write PMIC address */ mmio_write_8(IIC_ICDR, addr); /* Clear ICSR.WAIT to exit from WAIT status. */ mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_WAIT)); /* Wait for a until ICSR.WAIT becomes 1. */ avs_poll(ICSR_WAIT, 1U); /* Write H'94 in ICCR to issue restart condition */ mmio_write_8(IIC_ICCR, ICCR_START); /* Clear ICSR.WAIT to exit from WAIT status. */ mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_WAIT)); /* Set ICIC.DTEE=1 to enable data transmission interrupt. */ mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) | ICIC_DTEE); /* Wait for a until ICSR.DTE becomes 1. */ avs_poll(ICSR_DTE, 1U); /* Clear ICIC.DTEE to disable a DTE interrupt. */ mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) & (uint8_t) (~ICIC_DTEE)); /* Send slave address of PMIC */ mmio_write_8(IIC_ICDR, PMIC_R_SLAVE_ADDRESS); /* Wait for a until ICSR.WAIT becomes 1. */ avs_poll(ICSR_WAIT, 1U); /* Write H'81 to ICCR to issue the repeated START condition */ /* for changing the transmission mode to the receive mode. */ mmio_write_8(IIC_ICCR, ICCR_START_RECV); /* Clear ICSR.WAIT to exit from WAIT status. */ mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_WAIT)); /* Wait for a until ICSR.WAIT becomes 1. */ avs_poll(ICSR_WAIT, 1U); /* Set ICCR to H'C0 for the STOP condition */ mmio_write_8(IIC_ICCR, ICCR_STOP_RECV); /* Clear ICSR.WAIT to exit from WAIT status. */ mmio_write_8(IIC_ICSR, mmio_read_8(IIC_ICSR) & (uint8_t) (~ICSR_WAIT)); /* Set ICIC.DTEE=1 to enable data transmission interrupt. */ mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) | ICIC_DTEE); /* Wait for a until ICSR.DTE becomes 1. */ avs_poll(ICSR_DTE, 1U); /* Receive DVFS SetVID register */ /* Clear ICIC.DTEE to disable a DTE interrupt. */ mmio_write_8(IIC_ICIC, mmio_read_8(IIC_ICIC) & (uint8_t) (~ICIC_DTEE)); /* Receive DVFS SetVID register */ reg = mmio_read_8(IIC_ICDR); /* Wait until ICSR.BUSY is cleared. */ avs_poll(ICSR_BUSY, 0U); /* Set ICCR=H'00 to disable the I2C module. */ mmio_write_8(IIC_ICCR, 0x00U); return reg; } /* * Wait processing by the polling. */ static void avs_poll(uint8_t bit_pos, uint8_t val) { uint8_t bit_val = 0U; if (val != 0U) bit_val = bit_pos; while (1) { if ((mmio_read_8(IIC_ICSR) & bit_pos) == bit_val) break; } } #endif /* AVS_READ_PMIC_REG_ENABLE */ #endif /* PMIC_ROHM_BD9571 */ #endif /* (AVS_SETTING_ENABLE==1) */ trusted-firmware-a-2.2/drivers/renesas/rcar/avs/avs_driver.h000066400000000000000000000006401355360272700242640ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights * reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef AVS_DRIVER_H #define AVS_DRIVER_H /* AVS Setting. 1:enable / 0:disable */ #ifndef AVS_SETTING_ENABLE #define AVS_SETTING_ENABLE 1 #endif /* AVS_SETTING_ENABLE */ void rcar_avs_init(void); void rcar_avs_setting(void); void rcar_avs_end(void); #endif /* AVS_DRIVER_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/board/000077500000000000000000000000001355360272700222455ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/board/board.c000066400000000000000000000053261355360272700235060ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights * reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "board.h" #ifndef BOARD_DEFAULT #if (RCAR_LSI == RCAR_D3) #define BOARD_DEFAULT (BOARD_DRAAK << BOARD_CODE_SHIFT) #elif (RCAR_LSI == RCAR_E3) #define BOARD_DEFAULT (BOARD_EBISU << BOARD_CODE_SHIFT) #elif (RCAR_LSI == RCAR_V3M) #define BOARD_DEFAULT (BOARD_EAGLE << BOARD_CODE_SHIFT) #else #define BOARD_DEFAULT (BOARD_SALVATOR_X << BOARD_CODE_SHIFT) #endif #endif #define BOARD_CODE_MASK (0xF8) #define BOARD_REV_MASK (0x07) #define BOARD_CODE_SHIFT (0x03) #define BOARD_ID_UNKNOWN (0xFF) #define SXS_ID { 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU } #define SX_ID { 0x10U, 0x11U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU } #define SKP_ID { 0x10U, 0x10U, 0x20U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU } #define SK_ID { 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU } #define EB4_ID { 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU } #define EB_ID { 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU } #define DR_ID { 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU } #define EA_ID { 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU } #define KK_ID { 0x10U, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU, 0xFFU } const char *g_board_tbl[] = { [BOARD_STARTER_KIT_PRE] = "Starter Kit Premier", [BOARD_STARTER_KIT] = "Starter Kit", [BOARD_SALVATOR_XS] = "Salvator-XS", [BOARD_SALVATOR_X] = "Salvator-X", [BOARD_EBISU_4D] = "Ebisu-4D", [BOARD_KRIEK] = "Kriek", [BOARD_EBISU] = "Ebisu", [BOARD_DRAAK] = "Draak", [BOARD_EAGLE] = "Eagle", [BOARD_UNKNOWN] = "unknown" }; int32_t rcar_get_board_type(uint32_t *type, uint32_t *rev) { int32_t ret = 0; const uint8_t board_tbl[][8] = { [BOARD_STARTER_KIT_PRE] = SKP_ID, [BOARD_SALVATOR_XS] = SXS_ID, [BOARD_STARTER_KIT] = SK_ID, [BOARD_SALVATOR_X] = SX_ID, [BOARD_EBISU_4D] = EB4_ID, [BOARD_EBISU] = EB_ID, [BOARD_DRAAK] = DR_ID, [BOARD_EAGLE] = EA_ID, [BOARD_KRIEK] = KK_ID, }; static uint8_t board_id = BOARD_ID_UNKNOWN; if (board_id != BOARD_ID_UNKNOWN) goto get_type; #if PMIC_ROHM_BD9571 /* Board ID detection from EEPROM */ ret = rcar_iic_dvfs_receive(EEPROM, BOARD_ID, &board_id); if (ret) { board_id = BOARD_ID_UNKNOWN; goto get_type; } if (board_id == BOARD_ID_UNKNOWN) board_id = BOARD_DEFAULT; #else board_id = BOARD_DEFAULT; #endif get_type: *type = ((uint32_t) board_id & BOARD_CODE_MASK) >> BOARD_CODE_SHIFT; if (*type >= ARRAY_SIZE(board_tbl)) { /* no revision information, set Rev0.0. */ *rev = 0; return ret; } *rev = board_tbl[*type][(uint8_t) (board_id & BOARD_REV_MASK)]; return ret; } trusted-firmware-a-2.2/drivers/renesas/rcar/board/board.h000066400000000000000000000020551355360272700235070ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights * reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BOARD_H #define BOARD_H #define BOARD_SALVATOR_X (0x00) #define BOARD_KRIEK (0x01) #define BOARD_STARTER_KIT (0x02) #define BOARD_SALVATOR_XS (0x04) #define BOARD_EBISU (0x08) #define BOARD_STARTER_KIT_PRE (0x0B) #define BOARD_EBISU_4D (0x0DU) #define BOARD_DRAAK (0x0EU) #define BOARD_EAGLE (0x0FU) #define BOARD_UNKNOWN (BOARD_EAGLE + 1U) #define BOARD_REV_UNKNOWN (0xFF) extern const char *g_board_tbl[]; /************************************************************************ * Revisions are expressed in 8 bits. * The upper 4 bits are major version. * The lower 4 bits are minor version. ************************************************************************/ #define GET_BOARD_MAJOR(a) ((uint32_t)(a) >> 0x4) #define GET_BOARD_MINOR(a) ((uint32_t)(a) & 0xF) #define GET_BOARD_NAME(a) (g_board_tbl[(a)]) int32_t rcar_get_board_type(uint32_t *type, uint32_t *rev); #endif /* BOARD_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/common.c000066400000000000000000000013031355360272700226070ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "rcar_private.h" void #if IMAGE_BL31 __attribute__ ((section(".system_ram"))) #endif cpg_write(uintptr_t regadr, uint32_t regval) { uint32_t value = (regval); mmio_write_32((uintptr_t) RCAR_CPGWPR, ~value); mmio_write_32(regadr, value); } void #if IMAGE_BL31 __attribute__ ((section(".system_ram"))) #endif mstpcr_write(uint32_t mstpcr, uint32_t mstpsr, uint32_t target_bit) { uint32_t reg; reg = mmio_read_32(mstpcr); reg &= ~target_bit; cpg_write(mstpcr, reg); while ((mmio_read_32(mstpsr) & target_bit) != 0U) { } } trusted-firmware-a-2.2/drivers/renesas/rcar/console/000077500000000000000000000000001355360272700226205ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/console/rcar_console.S000066400000000000000000000053621355360272700254230ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl console_rcar_register .globl console_rcar_init .globl console_rcar_putc .globl console_rcar_flush .extern rcar_log_init .extern rcar_set_log_data /* ----------------------------------------------- * int console_rcar_register( * uintptr_t base, uint32_t clk, uint32_t baud, * console_rcar_t *console) * Function to initialize and register a new rcar * console. Storage passed in for the console struct * *must* be persistent (i.e. not from the stack). * In: x0 - UART register base address * w1 - UART clock in Hz * w2 - Baud rate * x3 - pointer to empty console_rcar_t struct * Out: return 1 on success, 0 on error * Clobber list : x0, x1, x2, x6, x7, x14 * ----------------------------------------------- */ func console_rcar_register mov x7, x30 mov x6, x3 cbz x6, register_fail str x0, [x6, #CONSOLE_T_RCAR_BASE] bl rcar_log_init cbz x0, register_fail mov x0, x6 mov x30, x7 finish_console_register rcar, putc=1, getc=0, flush=1 register_fail: ret x7 endfunc console_rcar_register /* --------------------------------------------- * int console_rcar_init(unsigned long base_addr, * unsigned int uart_clk, unsigned int baud_rate) * Function to initialize the console without a * C Runtime to print debug information. This * function will be accessed by crash reporting. * In: x0 - console base address * w1 - Uart clock in Hz * w2 - Baud rate * Out: return 1 on success * Clobber list : x1, x2 * --------------------------------------------- */ func console_rcar_init mov w0, #0 ret endfunc console_rcar_init /* -------------------------------------------------------- * int console_rcar_putc(int c, console_rcar_t *console) * Function to output a character over the console. It * returns the character printed on success or -1 on error. * In : w0 - character to be printed * x1 - pointer to console_rcar_t structure * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_rcar_putc b rcar_set_log_data endfunc console_rcar_putc /* --------------------------------------------- * int console_rcar_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 : x0, x1 * --------------------------------------------- */ func console_rcar_flush mov w0, #0 ret endfunc console_rcar_flush trusted-firmware-a-2.2/drivers/renesas/rcar/console/rcar_printf.c000066400000000000000000000041441355360272700253000ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "rcar_def.h" #include "rcar_private.h" #include "rcar_printf.h" #define INDEX_TIMER_COUNT (4U) extern RCAR_INSTANTIATE_LOCK typedef struct log_head { uint8_t head[4]; uint32_t index; uint32_t size; uint8_t res[4]; } loghead_t; typedef struct log_map { loghead_t header; uint8_t log_data[RCAR_BL31_LOG_MAX]; uint8_t res_data[RCAR_LOG_RES_SIZE]; } logmap_t; int32_t rcar_set_log_data(int32_t c) { logmap_t *t_log; t_log = (logmap_t *) RCAR_BL31_LOG_BASE; rcar_lock_get(); /* * If index is broken, then index and size initialize */ if (t_log->header.index >= (uint32_t) RCAR_BL31_LOG_MAX) { t_log->header.index = 0U; t_log->header.size = 0U; } /* * data store to log area then index and size renewal */ t_log->log_data[t_log->header.index] = (uint8_t) c; t_log->header.index++; if (t_log->header.size < t_log->header.index) { t_log->header.size = t_log->header.index; } if (t_log->header.index >= (uint32_t) RCAR_BL31_LOG_MAX) { t_log->header.index = 0U; } rcar_lock_release(); return 1; } int32_t rcar_log_init(void) { static const uint8_t const_header[] = "TLOG"; logmap_t *t_log; int16_t init_flag = 0; t_log = (logmap_t *) RCAR_BL31_LOG_BASE; if (memcmp ((const void *)t_log->header.head, (const void *)const_header, sizeof(t_log->header.head)) != 0) { /* * Log header is not "TLOG", then log area initialize */ init_flag = 1; } if (t_log->header.index >= (uint32_t) RCAR_BL31_LOG_MAX) { /* * index is broken, then log area initialize */ init_flag = 1; } if (init_flag == 1) { (void)memset((void *)t_log->log_data, 0, (size_t) RCAR_BL31_LOG_MAX); (void)memcpy((void *)t_log->header.head, (const void *)const_header, sizeof(t_log->header.head)); t_log->header.index = 0U; t_log->header.size = 0U; } rcar_lock_init(); return 1; } trusted-firmware-a-2.2/drivers/renesas/rcar/console/rcar_printf.h000066400000000000000000000004471355360272700253070ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RCAR_PRINTF_H #define RCAR_PRINTF_H #include int32_t rcar_set_log_data(int32_t c); int32_t rcar_log_init(void); #endif /* RCAR_PRINTF_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/cpld/000077500000000000000000000000001355360272700221005ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/cpld/ulcb_cpld.c000066400000000000000000000046771355360272700242110ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "ulcb_cpld.h" #define SCLK 8 /* GP_6_8 */ #define SSTBZ 3 /* GP_2_3 */ #define MOSI 7 /* GP_6_7 */ #define CPLD_ADDR_RESET 0x80 /* RW */ /* LSI Multiplexed Pin Setting Mask Register */ #define PFC_PMMR 0xE6060000 /* General output registers */ #define GPIO_OUTDT2 0xE6052008 #define GPIO_OUTDT6 0xE6055408 /* General input/output switching registers */ #define GPIO_INOUTSEL2 0xE6052004 #define GPIO_INOUTSEL6 0xE6055404 /* General IO/Interrupt Switching Register */ #define GPIO_IOINTSEL6 0xE6055400 /* GPIO/perihperal function select */ #define PFC_GPSR2 0xE6060108 #define PFC_GPSR6 0xE6060118 static void gpio_set_value(uint32_t addr, uint8_t gpio, uint32_t val) { uint32_t reg; reg = mmio_read_32(addr); if (val) reg |= (1 << gpio); else reg &= ~(1 << gpio); mmio_write_32(addr, reg); } static void gpio_direction_output(uint32_t addr, uint8_t gpio) { uint32_t reg; reg = mmio_read_32(addr); reg |= (1 << gpio); mmio_write_32(addr, reg); } static void gpio_pfc(uint32_t addr, uint8_t gpio) { uint32_t reg; reg = mmio_read_32(addr); reg &= ~(1 << gpio); mmio_write_32(PFC_PMMR, ~reg); mmio_write_32(addr, reg); } static void cpld_write(uint8_t addr, uint32_t data) { int i; for (i = 0; i < 32; i++) { /* MSB first */ gpio_set_value(GPIO_OUTDT6, MOSI, data & (1U << 31)); gpio_set_value(GPIO_OUTDT6, SCLK, 1); data <<= 1; gpio_set_value(GPIO_OUTDT6, SCLK, 0); } for (i = 0; i < 8; i++) { /* MSB first */ gpio_set_value(GPIO_OUTDT6, MOSI, addr & 0x80); gpio_set_value(GPIO_OUTDT6, SCLK, 1); addr <<= 1; gpio_set_value(GPIO_OUTDT6, SCLK, 0); } /* WRITE */ gpio_set_value(GPIO_OUTDT6, MOSI, 1); gpio_set_value(GPIO_OUTDT2, SSTBZ, 0); gpio_set_value(GPIO_OUTDT6, SCLK, 1); gpio_set_value(GPIO_OUTDT6, SCLK, 0); gpio_set_value(GPIO_OUTDT2, SSTBZ, 1); } static void cpld_init(void) { gpio_pfc(PFC_GPSR6, SCLK); gpio_pfc(PFC_GPSR2, SSTBZ); gpio_pfc(PFC_GPSR6, MOSI); gpio_set_value(GPIO_IOINTSEL6, SCLK, 0); gpio_set_value(GPIO_OUTDT6, SCLK, 0); gpio_set_value(GPIO_OUTDT2, SSTBZ, 1); gpio_set_value(GPIO_OUTDT6, MOSI, 0); gpio_direction_output(GPIO_INOUTSEL6, SCLK); gpio_direction_output(GPIO_INOUTSEL2, SSTBZ); gpio_direction_output(GPIO_INOUTSEL6, MOSI); } void rcar_cpld_reset_cpu(void) { cpld_init(); cpld_write(CPLD_ADDR_RESET, 1); } trusted-firmware-a-2.2/drivers/renesas/rcar/cpld/ulcb_cpld.h000066400000000000000000000004001355360272700241720ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RCAR_ULCB_CPLD_H__ #define RCAR_ULCB_CPLD_H__ extern void rcar_cpld_reset_cpu(void); #endif /* RCAR_ULCB_CPLD_H__ */ trusted-firmware-a-2.2/drivers/renesas/rcar/delay/000077500000000000000000000000001355360272700222545ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/delay/micro_delay.c000066400000000000000000000011721355360272700247100ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "micro_delay.h" #define RCAR_CONV_MICROSEC 1000000U void #if IMAGE_BL31 __attribute__ ((section (".system_ram"))) #endif rcar_micro_delay(uint64_t micro_sec) { uint64_t freq; uint64_t base_count; uint64_t get_count; uint64_t wait_time = 0U; freq = read_cntfrq_el0(); base_count = read_cntpct_el0(); while (micro_sec > wait_time) { get_count = read_cntpct_el0(); wait_time = ((get_count - base_count) * RCAR_CONV_MICROSEC) / freq; } } trusted-firmware-a-2.2/drivers/renesas/rcar/delay/micro_delay.h000066400000000000000000000004531355360272700247160ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MICRO_DELAY_H #define MICRO_DELAY_H #ifndef __ASSEMBLER__ #include void rcar_micro_delay(uint64_t micro_sec); #endif #endif /* MICRO_DELAY_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/dma/000077500000000000000000000000001355360272700217175ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/dma/dma_driver.c000066400000000000000000000075461355360272700242130ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "rcar_def.h" #include "cpg_registers.h" #include "rcar_private.h" /* DMA CHANNEL setting (0/16/32) */ #if RCAR_LSI == RCAR_V3M #define DMA_CH 16 #else #define DMA_CH 0 #endif #if (DMA_CH == 0) #define SYS_DMAC_BIT ((uint32_t)1U << 19U) #define DMA_BASE (0xE6700000U) #elif (DMA_CH == 16) #define SYS_DMAC_BIT ((uint32_t)1U << 18U) #define DMA_BASE (0xE7300000U) #elif (DMA_CH == 32) #define SYS_DMAC_BIT ((uint32_t)1U << 17U) #define DMA_BASE (0xE7320000U) #else #define SYS_DMAC_BIT ((uint32_t)1U << 19U) #define DMA_BASE (0xE6700000U) #endif /* DMA operation */ #define DMA_DMAOR (DMA_BASE + 0x0060U) /* DMA secure control */ #define DMA_DMASEC (DMA_BASE + 0x0030U) /* DMA channel clear */ #define DMA_DMACHCLR (DMA_BASE + 0x0080U) /* DMA source address */ #define DMA_DMASAR (DMA_BASE + 0x8000U) /* DMA destination address */ #define DMA_DMADAR (DMA_BASE + 0x8004U) /* DMA transfer count */ #define DMA_DMATCR (DMA_BASE + 0x8008U) /* DMA channel control */ #define DMA_DMACHCR (DMA_BASE + 0x800CU) /* DMA fixed destination address */ #define DMA_DMAFIXDAR (DMA_BASE + 0x8014U) #define DMA_USE_CHANNEL (0x00000001U) #define DMAOR_INITIAL (0x0301U) #define DMACHCLR_CH_ALL (0x0000FFFFU) #define DMAFIXDAR_32BIT_SHIFT (32U) #define DMAFIXDAR_DAR_MASK (0x000000FFU) #define DMADAR_BOUNDARY_ADDR (0x100000000ULL) #define DMATCR_CNT_SHIFT (6U) #define DMATCR_MAX (0x00FFFFFFU) #define DMACHCR_TRN_MODE (0x00105409U) #define DMACHCR_DE_BIT (0x00000001U) #define DMACHCR_TE_BIT (0x00000002U) #define DMACHCR_CHE_BIT (0x80000000U) #define DMA_SIZE_UNIT FLASH_TRANS_SIZE_UNIT #define DMA_FRACTION_MASK (0xFFU) #define DMA_DST_LIMIT (0x10000000000ULL) /* transfer length limit */ #define DMA_LENGTH_LIMIT ((DMATCR_MAX * (1U << DMATCR_CNT_SHIFT)) \ & ~DMA_FRACTION_MASK) static void dma_enable(void) { mstpcr_write(CPG_SMSTPCR2, CPG_MSTPSR2, SYS_DMAC_BIT); } static void dma_setup(void) { mmio_write_16(DMA_DMAOR, 0); mmio_write_32(DMA_DMACHCLR, DMACHCLR_CH_ALL); } static void dma_start(uintptr_t dst, uint32_t src, uint32_t len) { mmio_write_16(DMA_DMAOR, DMAOR_INITIAL); mmio_write_32(DMA_DMAFIXDAR, (dst >> DMAFIXDAR_32BIT_SHIFT) & DMAFIXDAR_DAR_MASK); mmio_write_32(DMA_DMADAR, dst & UINT32_MAX); mmio_write_32(DMA_DMASAR, src); mmio_write_32(DMA_DMATCR, len >> DMATCR_CNT_SHIFT); mmio_write_32(DMA_DMASEC, DMA_USE_CHANNEL); mmio_write_32(DMA_DMACHCR, DMACHCR_TRN_MODE); } static void dma_end(void) { while ((mmio_read_32(DMA_DMACHCR) & DMACHCR_TE_BIT) == 0) { if ((mmio_read_32(DMA_DMACHCR) & DMACHCR_CHE_BIT) != 0U) { ERROR("BL2: DMA - Channel Address Error\n"); panic(); break; } } /* DMA transfer Disable */ mmio_clrbits_32(DMA_DMACHCR, DMACHCR_DE_BIT); while ((mmio_read_32(DMA_DMACHCR) & DMACHCR_DE_BIT) != 0) ; mmio_write_32(DMA_DMASEC, 0); mmio_write_16(DMA_DMAOR, 0); mmio_write_32(DMA_DMACHCLR, DMA_USE_CHANNEL); } void rcar_dma_exec(uintptr_t dst, uint32_t src, uint32_t len) { uint32_t dma_len = len; if (len & DMA_FRACTION_MASK) dma_len = (len + DMA_SIZE_UNIT) & ~DMA_FRACTION_MASK; if (!dma_len || dma_len > DMA_LENGTH_LIMIT) { ERROR("BL2: DMA - size invalid, length (0x%x)\n", dma_len); panic(); } if (src & DMA_FRACTION_MASK) { ERROR("BL2: DMA - source address invalid (0x%x), " "length (0x%x)\n", src, dma_len); panic(); } if ((dst & UINT32_MAX) + dma_len > DMADAR_BOUNDARY_ADDR || (dst + dma_len > DMA_DST_LIMIT) || (dst & DMA_FRACTION_MASK)) { ERROR("BL2: DMA - destination address invalid (0x%lx), " "length (0x%x)\n", dst, dma_len); panic(); } dma_start(dst, src, dma_len); dma_end(); } void rcar_dma_init(void) { dma_enable(); dma_setup(); } trusted-firmware-a-2.2/drivers/renesas/rcar/emmc/000077500000000000000000000000001355360272700220775ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/emmc/emmc_cmd.c000066400000000000000000000304461355360272700240160ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "emmc_config.h" #include "emmc_hal.h" #include "emmc_std.h" #include "emmc_registers.h" #include "emmc_def.h" #include "micro_delay.h" static void emmc_little_to_big(uint8_t *p, uint32_t value) { if (p == NULL) return; p[0] = (uint8_t) (value >> 24); p[1] = (uint8_t) (value >> 16); p[2] = (uint8_t) (value >> 8); p[3] = (uint8_t) value; } static void emmc_softreset(void) { int32_t loop = 10000; int32_t retry = 1000; /* flag clear */ mmc_drv_obj.during_cmd_processing = FALSE; mmc_drv_obj.during_transfer = FALSE; mmc_drv_obj.during_dma_transfer = FALSE; mmc_drv_obj.state_machine_blocking = FALSE; mmc_drv_obj.force_terminate = FALSE; mmc_drv_obj.dma_error_flag = FALSE; /* during operation ? */ if ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) == 0) goto reset; /* wait CMDSEQ = 0 */ while (loop > 0) { if ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) == 0) break; /* ready */ loop--; if ((loop == 0) && (retry > 0)) { rcar_micro_delay(1000U); /* wait 1ms */ loop = 10000; retry--; } } reset: /* reset */ SETR_32(SOFT_RST, (GETR_32(SOFT_RST) & (~SOFT_RST_SDRST))); SETR_32(SOFT_RST, (GETR_32(SOFT_RST) | SOFT_RST_SDRST)); /* initialize */ SETR_32(SD_INFO1, 0x00000000U); SETR_32(SD_INFO2, SD_INFO2_CLEAR); SETR_32(SD_INFO1_MASK, 0x00000000U); /* all interrupt disable */ SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* all interrupt disable */ } static void emmc_read_response(uint32_t *response) { uint8_t *p; if (response == NULL) return; /* read response */ if (mmc_drv_obj.response_length != EMMC_MAX_RESPONSE_LENGTH) { *response = GETR_32(SD_RSP10); /* [39:8] */ return; } /* CSD or CID */ p = (uint8_t *) (response); emmc_little_to_big(p, ((GETR_32(SD_RSP76) << 8) | (GETR_32(SD_RSP54) >> 24))); /* [127:96] */ emmc_little_to_big(p + 4, ((GETR_32(SD_RSP54) << 8) | (GETR_32(SD_RSP32) >> 24))); /* [95:64] */ emmc_little_to_big(p + 8, ((GETR_32(SD_RSP32) << 8) | (GETR_32(SD_RSP10) >> 24))); /* [63:32] */ emmc_little_to_big(p + 12, (GETR_32(SD_RSP10) << 8)); } static EMMC_ERROR_CODE emmc_response_check(uint32_t *response, uint32_t error_mask) { HAL_MEMCARD_RESPONSE_TYPE response_type = (HAL_MEMCARD_RESPONSE_TYPE) (mmc_drv_obj.cmd_info. cmd & HAL_MEMCARD_RESPONSE_TYPE_MASK); if (response == NULL) return EMMC_ERR_PARAM; if (response_type == HAL_MEMCARD_RESPONSE_NONE) return EMMC_SUCCESS; if (response_type <= HAL_MEMCARD_RESPONSE_R1b) { /* R1 or R1b */ mmc_drv_obj.current_state = (EMMC_R1_STATE) ((*response & EMMC_R1_STATE_MASK) >> EMMC_R1_STATE_SHIFT); if ((*response & error_mask) != 0) { if ((0x80 & *response) != 0) { ERROR("BL2: emmc SWITCH_ERROR\n"); } return EMMC_ERR_CARD_STATUS_BIT; } return EMMC_SUCCESS;; } if (response_type == HAL_MEMCARD_RESPONSE_R4) { if ((*response & EMMC_R4_STATUS) != 0) return EMMC_ERR_CARD_STATUS_BIT; } return EMMC_SUCCESS; } static void emmc_WaitCmd2Cmd_8Cycle(void) { uint32_t dataL, wait = 0; dataL = GETR_32(SD_CLK_CTRL); dataL &= 0x000000FF; switch (dataL) { case 0xFF: case 0x00: case 0x01: case 0x02: case 0x04: case 0x08: case 0x10: case 0x20: wait = 10U; break; case 0x40: wait = 20U; break; case 0x80: wait = 30U; break; } rcar_micro_delay(wait); } static void cmdErrSdInfo2Log(void) { ERROR("BL2: emmc ERR SD_INFO2 = 0x%x\n", mmc_drv_obj.error_info.info2); } static void emmc_data_transfer_dma(void) { mmc_drv_obj.during_dma_transfer = TRUE; mmc_drv_obj.dma_error_flag = FALSE; SETR_32(SD_INFO1_MASK, 0x00000000U); SETR_32(SD_INFO2_MASK, (SD_INFO2_ALL_ERR | SD_INFO2_CLEAR)); /* DMAC setting */ if (mmc_drv_obj.cmd_info.dir == HAL_MEMCARD_WRITE) { /* transfer complete interrupt enable */ SETR_32(DM_CM_INFO1_MASK, (DM_CM_INFO_MASK_CLEAR | DM_CM_INFO_CH0_ENABLE)); SETR_32(DM_CM_INFO2_MASK, (DM_CM_INFO_MASK_CLEAR | DM_CM_INFO_CH0_ENABLE)); /* BUFF --> FIFO */ SETR_32(DM_CM_DTRAN_MODE, (DM_CM_DTRAN_MODE_CH0 | DM_CM_DTRAN_MODE_BIT_WIDTH)); } else { /* transfer complete interrupt enable */ SETR_32(DM_CM_INFO1_MASK, (DM_CM_INFO_MASK_CLEAR | DM_CM_INFO_CH1_ENABLE)); SETR_32(DM_CM_INFO2_MASK, (DM_CM_INFO_MASK_CLEAR | DM_CM_INFO_CH1_ENABLE)); /* FIFO --> BUFF */ SETR_32(DM_CM_DTRAN_MODE, (DM_CM_DTRAN_MODE_CH1 | DM_CM_DTRAN_MODE_BIT_WIDTH)); } SETR_32(DM_DTRAN_ADDR, (((uintptr_t) mmc_drv_obj.buff_address_virtual & DM_DTRAN_ADDR_WRITE_MASK))); SETR_32(DM_CM_DTRAN_CTRL, DM_CM_DTRAN_CTRL_START); } EMMC_ERROR_CODE emmc_exec_cmd(uint32_t error_mask, uint32_t *response) { EMMC_ERROR_CODE rtn_code = EMMC_SUCCESS; HAL_MEMCARD_RESPONSE_TYPE response_type; HAL_MEMCARD_COMMAND_TYPE cmd_type; EMMC_INT_STATE state; uint32_t err_not_care_flag = FALSE; /* parameter check */ if (response == NULL) { emmc_write_error_info(EMMC_FUNCNO_EXEC_CMD, EMMC_ERR_PARAM); return EMMC_ERR_PARAM; } /* state check */ if (mmc_drv_obj.clock_enable != TRUE) { emmc_write_error_info(EMMC_FUNCNO_EXEC_CMD, EMMC_ERR_STATE); return EMMC_ERR_STATE; } if (mmc_drv_obj.state_machine_blocking == TRUE) { emmc_write_error_info(EMMC_FUNCNO_EXEC_CMD, EMMC_ERR); return EMMC_ERR; } state = ESTATE_BEGIN; response_type = (HAL_MEMCARD_RESPONSE_TYPE) (mmc_drv_obj.cmd_info. cmd & HAL_MEMCARD_RESPONSE_TYPE_MASK); cmd_type = (HAL_MEMCARD_COMMAND_TYPE) (mmc_drv_obj.cmd_info. cmd & HAL_MEMCARD_COMMAND_TYPE_MASK); /* state machine */ while ((mmc_drv_obj.force_terminate != TRUE) && (state != ESTATE_END)) { /* The interrupt factor flag is observed. */ emmc_interrupt(); /* wait interrupt */ if (mmc_drv_obj.state_machine_blocking == TRUE) continue; switch (state) { case ESTATE_BEGIN: /* Busy check */ if ((mmc_drv_obj.error_info.info2 & SD_INFO2_CBSY) != 0) { emmc_write_error_info(EMMC_FUNCNO_EXEC_CMD, EMMC_ERR_CARD_BUSY); return EMMC_ERR_CARD_BUSY; } /* clear register */ SETR_32(SD_INFO1, 0x00000000U); SETR_32(SD_INFO2, SD_INFO2_CLEAR); SETR_32(SD_INFO1_MASK, SD_INFO1_INFO0); SETR_32(SD_INFO2_MASK, (SD_INFO2_ALL_ERR | SD_INFO2_CLEAR)); state = ESTATE_ISSUE_CMD; /* through */ case ESTATE_ISSUE_CMD: /* ARG */ SETR_32(SD_ARG, mmc_drv_obj.cmd_info.arg); /* issue cmd */ SETR_32(SD_CMD, mmc_drv_obj.cmd_info.hw); /* Set driver flag */ mmc_drv_obj.during_cmd_processing = TRUE; mmc_drv_obj.state_machine_blocking = TRUE; if (response_type == HAL_MEMCARD_RESPONSE_NONE) { state = ESTATE_NON_RESP_CMD; } else { state = ESTATE_RCV_RESP; } break; case ESTATE_NON_RESP_CMD: /* interrupt disable */ SETR_32(SD_INFO1_MASK, 0x00000000U); SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* check interrupt */ if ((mmc_drv_obj.int_event2 & SD_INFO2_ALL_ERR) != 0) { /* error interrupt */ cmdErrSdInfo2Log(); rtn_code = EMMC_ERR_INFO2; state = ESTATE_ERROR; } else if ((mmc_drv_obj.int_event1 & SD_INFO1_INFO0) == 0) { /* not receive expected interrupt */ rtn_code = EMMC_ERR_RESPONSE; state = ESTATE_ERROR; } else { emmc_WaitCmd2Cmd_8Cycle(); state = ESTATE_END; } break; case ESTATE_RCV_RESP: /* interrupt disable */ SETR_32(SD_INFO1_MASK, 0x00000000U); SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* check interrupt */ if ((mmc_drv_obj.int_event2 & SD_INFO2_ALL_ERR) != 0) { if ((mmc_drv_obj.get_partition_access_flag == TRUE) && ((mmc_drv_obj.int_event2 & SD_INFO2_ERR6) != 0U)) { err_not_care_flag = TRUE; rtn_code = EMMC_ERR_CMD_TIMEOUT; } else { /* error interrupt */ cmdErrSdInfo2Log(); rtn_code = EMMC_ERR_INFO2; } state = ESTATE_ERROR; break; } else if ((mmc_drv_obj.int_event1 & SD_INFO1_INFO0) == 0) { /* not receive expected interrupt */ rtn_code = EMMC_ERR_RESPONSE; state = ESTATE_ERROR; break; } /* read response */ emmc_read_response(response); /* check response */ rtn_code = emmc_response_check(response, error_mask); if (rtn_code != EMMC_SUCCESS) { state = ESTATE_ERROR; break; } if (response_type == HAL_MEMCARD_RESPONSE_R1b) { /* R1b */ SETR_32(SD_INFO2_MASK, (SD_INFO2_ALL_ERR | SD_INFO2_CLEAR)); state = ESTATE_RCV_RESPONSE_BUSY; } else { state = ESTATE_CHECK_RESPONSE_COMPLETE; } break; case ESTATE_RCV_RESPONSE_BUSY: /* check interrupt */ if ((mmc_drv_obj.int_event2 & SD_INFO2_ALL_ERR) != 0) { /* error interrupt */ cmdErrSdInfo2Log(); rtn_code = EMMC_ERR_INFO2; state = ESTATE_ERROR; break; } /* DAT0 not Busy */ if ((SD_INFO2_DAT0 & mmc_drv_obj.error_info.info2) != 0) { state = ESTATE_CHECK_RESPONSE_COMPLETE; break; } break; case ESTATE_CHECK_RESPONSE_COMPLETE: if (cmd_type >= HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE) { state = ESTATE_DATA_TRANSFER; } else { emmc_WaitCmd2Cmd_8Cycle(); state = ESTATE_END; } break; case ESTATE_DATA_TRANSFER: /* ADTC command */ mmc_drv_obj.during_transfer = TRUE; mmc_drv_obj.state_machine_blocking = TRUE; if (mmc_drv_obj.transfer_mode == HAL_MEMCARD_DMA) { /* DMA */ emmc_data_transfer_dma(); } else { /* PIO */ /* interrupt enable (FIFO read/write enable) */ if (mmc_drv_obj.cmd_info.dir == HAL_MEMCARD_WRITE) { SETR_32(SD_INFO2_MASK, (SD_INFO2_BWE | SD_INFO2_ALL_ERR | SD_INFO2_CLEAR)); } else { SETR_32(SD_INFO2_MASK, (SD_INFO2_BRE | SD_INFO2_ALL_ERR | SD_INFO2_CLEAR)); } } state = ESTATE_DATA_TRANSFER_COMPLETE; break; case ESTATE_DATA_TRANSFER_COMPLETE: /* check interrupt */ if ((mmc_drv_obj.int_event2 & SD_INFO2_ALL_ERR) != 0) { /* error interrupt */ cmdErrSdInfo2Log(); rtn_code = EMMC_ERR_INFO2; state = ESTATE_TRANSFER_ERROR; break; } /* DMAC error ? */ if (mmc_drv_obj.dma_error_flag == TRUE) { /* Error occurred in DMAC driver. */ rtn_code = EMMC_ERR_FROM_DMAC_TRANSFER; state = ESTATE_TRANSFER_ERROR; } else if (mmc_drv_obj.during_dma_transfer == TRUE) { /* DMAC not finished. unknown error */ rtn_code = EMMC_ERR; state = ESTATE_TRANSFER_ERROR; } else { SETR_32(SD_INFO1_MASK, SD_INFO1_INFO2); SETR_32(SD_INFO2_MASK, (SD_INFO2_ALL_ERR | SD_INFO2_CLEAR)); mmc_drv_obj.state_machine_blocking = TRUE; state = ESTATE_ACCESS_END; } break; case ESTATE_ACCESS_END: /* clear flag */ if (HAL_MEMCARD_DMA == mmc_drv_obj.transfer_mode) { SETR_32(CC_EXT_MODE, CC_EXT_MODE_CLEAR); /* W (CC_EXT_MODE, H'0000_1010) SD_BUF DMA transfer disabled */ SETR_32(SD_STOP, 0x00000000U); mmc_drv_obj.during_dma_transfer = FALSE; } SETR_32(SD_INFO1_MASK, 0x00000000U); SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR); SETR_32(SD_INFO1, 0x00000000U); SETR_32(SD_INFO2, SD_INFO2_CLEAR); if ((mmc_drv_obj.int_event1 & SD_INFO1_INFO2) != 0) { emmc_WaitCmd2Cmd_8Cycle(); state = ESTATE_END; } else { state = ESTATE_ERROR; } break; case ESTATE_TRANSFER_ERROR: /* The error occurred in the Data transfer. */ if (HAL_MEMCARD_DMA == mmc_drv_obj.transfer_mode) { SETR_32(CC_EXT_MODE, CC_EXT_MODE_CLEAR); /* W (CC_EXT_MODE, H'0000_1010) SD_BUF DMA transfer disabled */ SETR_32(SD_STOP, 0x00000000U); mmc_drv_obj.during_dma_transfer = FALSE; } /* through */ case ESTATE_ERROR: if (err_not_care_flag == TRUE) { mmc_drv_obj.during_cmd_processing = FALSE; } else { emmc_softreset(); emmc_write_error_info(EMMC_FUNCNO_EXEC_CMD, rtn_code); } return rtn_code; default: state = ESTATE_END; break; } /* switch (state) */ } /* while ( (mmc_drv_obj.force_terminate != TRUE) && (state != ESTATE_END) ) */ /* force terminate */ if (mmc_drv_obj.force_terminate == TRUE) { /* timeout timer is expired. Or, PIO data transfer error. */ /* Timeout occurred in the DMA transfer. */ if (mmc_drv_obj.during_dma_transfer == TRUE) { mmc_drv_obj.during_dma_transfer = FALSE; } ERROR("BL2: emmc exec_cmd:EMMC_ERR_FORCE_TERMINATE\n"); emmc_softreset(); return EMMC_ERR_FORCE_TERMINATE; /* error information has already been written. */ } /* success */ mmc_drv_obj.during_cmd_processing = FALSE; mmc_drv_obj.during_transfer = FALSE; return EMMC_SUCCESS; } trusted-firmware-a-2.2/drivers/renesas/rcar/emmc/emmc_config.h000066400000000000000000000023411355360272700245160ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /** * @file emmc_config.h * @brief Configuration file * */ #ifndef EMMC_CONFIG_H #define EMMC_CONFIG_H /* ************************ HEADER (INCLUDE) SECTION *********************** */ /* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */ /** @brief MMC driver config */ #define EMMC_RCA 1UL /* RCA */ #define EMMC_RW_DATA_TIMEOUT 0x40UL /* 314ms (freq = 400KHz, timeout Counter = 0x04(SDCLK * 2^17) */ #define EMMC_RETRY_COUNT 0 /* how many times to try after fail. Don't change. */ #define EMMC_CMD_MAX 60UL /* Don't change. */ /** @brief etc */ #define LOADIMAGE_FLAGS_DMA_ENABLE 0x00000001UL /* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */ /* ********************** DECLARATION OF EXTERNAL DATA ********************* */ /* ************************** FUNCTION PROTOTYPES ************************** */ /* ********************************* CODE ********************************** */ #endif /* EMMC_CONFIG_H */ /* ******************************** END ************************************ */ trusted-firmware-a-2.2/drivers/renesas/rcar/emmc/emmc_def.h000066400000000000000000000046661355360272700240230ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /** * @file emmc_def.h * @brief eMMC boot is expecting this header file * */ #ifndef EMMC_DEF_H #define EMMC_DEF_H #include "emmc_std.h" /* ************************ HEADER (INCLUDE) SECTION *********************** */ /* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */ #define EMMC_POWER_ON (1U) /* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */ /* ********************** DECLARATION OF EXTERNAL DATA ********************* */ extern st_mmc_base mmc_drv_obj; /* ************************** FUNCTION PROTOTYPES ************************** */ /** @brief for assembler program */ uint32_t _rom_emmc_finalize(void); /** @brief eMMC driver API */ EMMC_ERROR_CODE rcar_emmc_init(void); EMMC_ERROR_CODE emmc_terminate(void); EMMC_ERROR_CODE rcar_emmc_memcard_power(uint8_t mode); EMMC_ERROR_CODE rcar_emmc_mount(void); EMMC_ERROR_CODE emmc_set_request_mmc_clock(uint32_t *freq); EMMC_ERROR_CODE emmc_send_idle_cmd(uint32_t arg); EMMC_ERROR_CODE emmc_select_partition(EMMC_PARTITION_ID id); EMMC_ERROR_CODE emmc_read_sector(uint32_t *buff_address_virtual, uint32_t sector_number, uint32_t count, uint32_t feature_flags); EMMC_ERROR_CODE emmc_write_sector(uint32_t *buff_address_virtual, uint32_t sector_number, uint32_t count, uint32_t feature_flags); EMMC_ERROR_CODE emmc_erase_sector(uint32_t *start_address, uint32_t *end_address); uint32_t emmc_bit_field(uint8_t *data, uint32_t top, uint32_t bottom); /** @brief interrupt service */ uint32_t emmc_interrupt(void); /** @brief DMA */ /** @brief send command API */ EMMC_ERROR_CODE emmc_exec_cmd(uint32_t error_mask, uint32_t *response); void emmc_make_nontrans_cmd(HAL_MEMCARD_COMMAND cmd, uint32_t arg); void emmc_make_trans_cmd(HAL_MEMCARD_COMMAND cmd, uint32_t arg, uint32_t *buff_address_virtual, uint32_t len, HAL_MEMCARD_OPERATION dir, HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode); EMMC_ERROR_CODE emmc_set_ext_csd(uint32_t arg); /** @brief for error information */ void emmc_write_error_info(uint16_t func_no, EMMC_ERROR_CODE error_code); void emmc_write_error_info_func_no(uint16_t func_no); /* ********************************* CODE ********************************** */ #endif /* EMMC_DEF_H */ /* ******************************** END ************************************ */ trusted-firmware-a-2.2/drivers/renesas/rcar/emmc/emmc_hal.h000066400000000000000000000410471355360272700240230ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /** * @file emmc_hal.h * @brief emmc boot driver is expecting this header file * */ #ifndef EMMC_HAL_H #define EMMC_HAL_H /* ************************ HEADER (INCLUDE) SECTION *********************** */ #include /* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */ /** @brief memory card error/status types */ #define HAL_MEMCARD_OUT_OF_RANGE 0x80000000L #define HAL_MEMCARD_ADDRESS_ERROR 0x40000000L #define HAL_MEMCARD_BLOCK_LEN_ERROR 0x20000000L #define HAL_MEMCARD_ERASE_SEQ_ERROR 0x10000000L #define HAL_MEMCARD_ERASE_PARAM 0x08000000L #define HAL_MEMCARD_WP_VIOLATION 0x04000000L #define HAL_MEMCARD_CARD_IS_LOCKED 0x02000000L #define HAL_MEMCARD_LOCK_UNLOCK_FAILED 0x01000000L #define HAL_MEMCARD_COM_CRC_ERROR 0x00800000L #define HAL_MEMCARD_ILEGAL_COMMAND 0x00400000L #define HAL_MEMCARD_CARD_ECC_FAILED 0x00200000L #define HAL_MEMCARD_CC_ERROR 0x00100000L #define HAL_MEMCARD_ERROR 0x00080000L #define HAL_MEMCARD_UNDERRUN 0x00040000L #define HAL_MEMCARD_OVERRUN 0x00020000L #define HAL_MEMCARD_CIDCSD_OVERWRITE 0x00010000L #define HAL_MEMCARD_WP_ERASE_SKIP 0x00008000L #define HAL_MEMCARD_CARD_ECC_DISABLED 0x00004000L #define HAL_MEMCARD_ERASE_RESET 0x00002000L #define HAL_MEMCARD_CARD_STATE 0x00001E00L #define HAL_MEMCARD_CARD_READY_FOR_DATA 0x00000100L #define HAL_MEMCARD_APP_CMD 0x00000020L #define HAL_MEMCARD_SWITCH_ERROR 0x00000080L #define HAL_MEMCARD_AKE_SEQ_ERROR 0x00000008L #define HAL_MEMCARD_NO_ERRORS 0x00000000L /** @brief Memory card response types */ #define HAL_MEMCARD_COMMAND_INDEX_MASK 0x0003f /* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */ /** @brief Type of the return value. */ typedef enum { HAL_MEMCARD_FAIL = 0U, HAL_MEMCARD_OK = 1U, HAL_MEMCARD_DMA_ALLOC_FAIL = 2U, /**< DMA channel allocation failed */ HAL_MEMCARD_DMA_TRANSFER_FAIL = 3U, /**< DMA transfer failed */ HAL_MEMCARD_CARD_STATUS_ERROR = 4U, /**< A non-masked error bit was set in the card status */ HAL_MEMCARD_CMD_TIMEOUT = 5U, /**< Command timeout occurred */ HAL_MEMCARD_DATA_TIMEOUT = 6U, /**< Data timeout occurred */ HAL_MEMCARD_CMD_CRC_ERROR = 7U, /**< Command CRC error occurred */ HAL_MEMCARD_DATA_CRC_ERROR = 8U /**< Data CRC error occurred */ } HAL_MEMCARD_RETURN; /** @brief memory access operation */ typedef enum { HAL_MEMCARD_READ = 0U, /**< read */ HAL_MEMCARD_WRITE = 1U /**< write */ } HAL_MEMCARD_OPERATION; /** @brief Type of data width on memorycard bus */ typedef enum { HAL_MEMCARD_DATA_WIDTH_1_BIT = 0U, HAL_MEMCARD_DATA_WIDTH_4_BIT = 1U, HAL_MEMCARD_DATA_WIDTH_8_BIT = 2U } HAL_MEMCARD_DATA_WIDTH; /**< data (bus) width types */ /** @brief Presence of the memory card */ typedef enum { HAL_MEMCARD_CARD_IS_IN = 0U, HAL_MEMCARD_CARD_IS_OUT = 1U } HAL_MEMCARD_PRESENCE_STATUS; /* presence status of the memory card */ /** @brief mode of data transfer */ typedef enum { HAL_MEMCARD_DMA = 0U, HAL_MEMCARD_NOT_DMA = 1U } HAL_MEMCARD_DATA_TRANSFER_MODE; /** @brief Memory card response types. */ typedef enum hal_memcard_response_type { HAL_MEMCARD_RESPONSE_NONE = 0x00000U, HAL_MEMCARD_RESPONSE_R1 = 0x00100U, HAL_MEMCARD_RESPONSE_R1b = 0x00200U, HAL_MEMCARD_RESPONSE_R2 = 0x00300U, HAL_MEMCARD_RESPONSE_R3 = 0x00400U, HAL_MEMCARD_RESPONSE_R4 = 0x00500U, HAL_MEMCARD_RESPONSE_R5 = 0x00600U, HAL_MEMCARD_RESPONSE_R6 = 0x00700U, HAL_MEMCARD_RESPONSE_R7 = 0x00800U, HAL_MEMCARD_RESPONSE_TYPE_MASK = 0x00f00U } HAL_MEMCARD_RESPONSE_TYPE; /** @brief Memory card command types. */ typedef enum hal_memcard_command_type { HAL_MEMCARD_COMMAND_TYPE_BC = 0x00000U, HAL_MEMCARD_COMMAND_TYPE_BCR = 0x01000U, HAL_MEMCARD_COMMAND_TYPE_AC = 0x02000U, HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE = 0x03000U, HAL_MEMCARD_COMMAND_TYPE_ADTC_READ = 0x04000U, HAL_MEMCARD_COMMAND_TYPE_MASK = 0x07000U } HAL_MEMCARD_COMMAND_TYPE; /** @brief Type of memory card */ typedef enum hal_memcard_command_card_type { HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON = 0x00000U, HAL_MEMCARD_COMMAND_CARD_TYPE_MMC = 0x08000U, HAL_MEMCARD_COMMAND_CARD_TYPE_SD = 0x10000U, HAL_MEMCARD_COMMAND_CARD_TYPE_MASK = 0x18000U } HAL_MEMCARD_COMMAND_CARD_TYPE; /** @brief Memory card application command. */ typedef enum hal_memcard_command_app_norm { HAL_MEMCARD_COMMAND_NORMAL = 0x00000U, HAL_MEMCARD_COMMAND_APP = 0x20000U, HAL_MEMCARD_COMMAND_APP_NORM_MASK = 0x20000U } HAL_MEMCARD_COMMAND_APP_NORM; /** @brief Memory card command codes. */ typedef enum { /* class 0 and class 1 */ CMD0_GO_IDLE_STATE = 0 | HAL_MEMCARD_RESPONSE_NONE | HAL_MEMCARD_COMMAND_TYPE_BC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD0 */ CMD1_SEND_OP_COND = 1 | HAL_MEMCARD_RESPONSE_R3 | HAL_MEMCARD_COMMAND_TYPE_BCR | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD1 */ CMD2_ALL_SEND_CID_MMC = 2 | HAL_MEMCARD_RESPONSE_R2 | HAL_MEMCARD_COMMAND_TYPE_BCR | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD2 */ CMD2_ALL_SEND_CID_SD = 2 | HAL_MEMCARD_RESPONSE_R2 | HAL_MEMCARD_COMMAND_TYPE_BCR | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL, CMD3_SET_RELATIVE_ADDR = 3 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD3 */ CMD3_SEND_RELATIVE_ADDR = 3 | HAL_MEMCARD_RESPONSE_R6 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL, CMD4_SET_DSR = 4 | HAL_MEMCARD_RESPONSE_NONE | HAL_MEMCARD_COMMAND_TYPE_BC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD4 */ CMD5_SLEEP_AWAKE = 5 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD5 */ CMD6_SWITCH = 6 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD6 */ CMD6_SWITCH_FUNC = 6 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL, ACMD6_SET_BUS_WIDTH = 6 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP, CMD7_SELECT_CARD = 7 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD7 */ CMD7_SELECT_CARD_PROG = 7 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD7(from Disconnected State to Programming State) */ CMD7_DESELECT_CARD = 7 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, CMD8_SEND_EXT_CSD = 8 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD8 */ CMD8_SEND_IF_COND = 8 | HAL_MEMCARD_RESPONSE_R7 | HAL_MEMCARD_COMMAND_TYPE_BCR | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL, CMD9_SEND_CSD = 9 | HAL_MEMCARD_RESPONSE_R2 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD9 */ CMD10_SEND_CID = 10 | HAL_MEMCARD_RESPONSE_R2 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD10 */ CMD11_READ_DAT_UNTIL_STOP = 11 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL, /* CMD11 */ CMD12_STOP_TRANSMISSION = 12 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD12 */ CMD12_STOP_TRANSMISSION_WRITE = 12 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD12(R1b : write case) */ CMD13_SEND_STATUS = 13 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD13 */ ACMD13_SD_STATUS = 13 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP, CMD14_BUSTEST_R = 14 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD14 */ CMD15_GO_INACTIVE_STATE = 15 | HAL_MEMCARD_RESPONSE_NONE | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD15 */ /* class 2 */ CMD16_SET_BLOCKLEN = 16 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD16 */ CMD17_READ_SINGLE_BLOCK = 17 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD17 */ CMD18_READ_MULTIPLE_BLOCK = 18 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD18 */ CMD19_BUS_TEST_W = 19 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD19 */ /* class 3 */ CMD20_WRITE_DAT_UNTIL_STOP = 20 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD20 */ CMD21 = 21, /* CMD21 */ CMD22 = 22, /* CMD22 */ ACMD22_SEND_NUM_WR_BLOCKS = 22 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP, /* class 4 */ CMD23_SET_BLOCK_COUNT = 23 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD23 */ ACMD23_SET_WR_BLK_ERASE_COUNT = 23 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP, CMD24_WRITE_BLOCK = 24 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD24 */ CMD25_WRITE_MULTIPLE_BLOCK = 25 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD25 */ CMD26_PROGRAM_CID = 26 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD26 */ CMD27_PROGRAM_CSD = 27 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD27 */ /* class 6 */ CMD28_SET_WRITE_PROT = 28 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD28 */ CMD29_CLR_WRITE_PROT = 29 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD29 */ CMD30_SEND_WRITE_PROT = 30 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD30 */ CMD30_SEND_WRITE_PROT_TYPE = 31 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD31 */ /* class 5 */ CMD32_ERASE_WR_BLK_START = 32 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL, /* CMD32 */ CMD33_ERASE_WR_BLK_END = 33 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_NORMAL, /* CMD33 */ CMD34 = 34, /* CMD34 */ CMD35_ERASE_GROUP_START = 35 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD35 */ CMD36_ERASE_GROUP_END = 36 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD36 */ CMD37 = 37, /* CMD37 */ CMD38_ERASE = 38 | HAL_MEMCARD_RESPONSE_R1b | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD38 */ /* class 9 */ CMD39_FASTIO = 39 | HAL_MEMCARD_RESPONSE_R4 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD39 */ CMD40_GO_IRQSTATE = 40 | HAL_MEMCARD_RESPONSE_R5 | HAL_MEMCARD_COMMAND_TYPE_BCR | HAL_MEMCARD_COMMAND_CARD_TYPE_MMC | HAL_MEMCARD_COMMAND_NORMAL, /* CMD40 */ CMD41 = 41, /* CMD41 */ ACMD41_SD_SEND_OP_COND = 41 | HAL_MEMCARD_RESPONSE_R3 | HAL_MEMCARD_COMMAND_TYPE_BCR | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP, /* class 7 */ CMD42_LOCK_UNLOCK = 42 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD42 */ ACMD42_SET_CLR_CARD_DETECT = 42 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP, CMD43 = 43, /* CMD43 */ CMD44 = 44, /* CMD44 */ CMD45 = 45, /* CMD45 */ CMD46 = 46, /* CMD46 */ CMD47 = 47, /* CMD47 */ CMD48 = 48, /* CMD48 */ CMD49 = 49, /* CMD49 */ CMD50 = 50, /* CMD50 */ CMD51 = 51, /* CMD51 */ ACMD51_SEND_SCR = 51 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_READ | HAL_MEMCARD_COMMAND_CARD_TYPE_SD | HAL_MEMCARD_COMMAND_APP, CMD52 = 52, /* CMD52 */ CMD53 = 53, /* CMD53 */ CMD54 = 54, /* CMD54 */ /* class 8 */ CMD55_APP_CMD = 55 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_AC | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD55 */ CMD56_GEN_CMD = 56 | HAL_MEMCARD_RESPONSE_R1 | HAL_MEMCARD_COMMAND_TYPE_ADTC_WRITE | HAL_MEMCARD_COMMAND_CARD_TYPE_COMMON | HAL_MEMCARD_COMMAND_NORMAL, /* CMD56 */ CMD57 = 57, /* CMD57 */ CMD58 = 58, /* CMD58 */ CMD59 = 59, /* CMD59 */ CMD60 = 60, /* CMD60 */ CMD61 = 61, /* CMD61 */ CMD62 = 62, /* CMD62 */ CMD63 = 63 /* CMD63 */ } HAL_MEMCARD_COMMAND; /** @brief Configuration structure from HAL layer. * * If some field is not available it should be filled with 0xFF. * The API version is 32-bit unsigned integer telling the version of the API. The integer is divided to four sections which each can be treated as a 8-bit unsigned number: * Bits 31-24 make the most significant part of the version number. This number starts from 1 i.e. the second version of the API will be 0x02xxxxxx. This number changes only, if the API itself changes so much that it is not compatible anymore with older releases. * Bits 23-16 API minor version number. For example API version 2.1 would be 0x0201xxxx. * Bits 15-8 are the number of the year when release is done. The 0 is year 2000, 1 is year 2001 and so on * Bits 7- are the week number when release is done. First full week of the year is 1 * * @note Example: let's assume that release 2.1 is done on week 10 year 2008 the version will get the value 0x0201080A */ typedef struct { /** * Version of the chipset API implementation * * bits [31:24] API specification major version number.
* bits [23:16] API specification minor version number.
* bits [15:8] API implemention year. (2000 = 0, 2001 = 1, ...)
* bits [7:0] API implemention week.
* Example: API specification version 4.0, implementation w46 2008 => 0x0400082E */ uint32_t api_version; /** maximum block count which can be transferred at once */ uint32_t max_block_count; /** maximum clock frequence in Hz supported by HW */ uint32_t max_clock_freq; /** maximum data bus width supported by HW */ uint16_t max_data_width; /** Is high-speed mode supported by HW (yes=1, no=0) */ uint8_t hs_mode_supported; /** Is memory card removable (yes=1, no=0) */ uint8_t card_removable; } HAL_MEMCARD_HW_CONF; /** @brief Configuration structure to HAL layer. */ typedef struct { /** how many times to try after fail, for instance sending command */ uint32_t retries_after_fail; } HAL_MEMCARD_INIT_CONF; /* ********************** DECLARATION OF EXTERNAL DATA ********************* */ /* ************************** FUNCTION PROTOTYPES ************************** */ /* ********************************* CODE ********************************** */ #endif /* EMMC_HAL_H */ /* ******************************** END ************************************ */ trusted-firmware-a-2.2/drivers/renesas/rcar/emmc/emmc_init.c000066400000000000000000000072761355360272700242230ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "emmc_config.h" #include "emmc_hal.h" #include "emmc_std.h" #include "emmc_registers.h" #include "emmc_def.h" #include "rcar_private.h" st_mmc_base mmc_drv_obj; EMMC_ERROR_CODE rcar_emmc_memcard_power(uint8_t mode) { if (mode == TRUE) { /* power on (Vcc&Vccq is always power on) */ mmc_drv_obj.card_power_enable = TRUE; } else { /* power off (Vcc&Vccq is always power on) */ mmc_drv_obj.card_power_enable = FALSE; mmc_drv_obj.mount = FALSE; mmc_drv_obj.selected = FALSE; } return EMMC_SUCCESS; } static __inline void emmc_set_retry_count(uint32_t retry) { mmc_drv_obj.retries_after_fail = retry; } static __inline void emmc_set_data_timeout(uint32_t data_timeout) { mmc_drv_obj.data_timeout = data_timeout; } static void emmc_memset(uint8_t *buff, uint8_t data, uint32_t cnt) { if (buff == NULL) { return; } while (cnt > 0) { *buff++ = data; cnt--; } } static void emmc_driver_config(void) { emmc_set_retry_count(EMMC_RETRY_COUNT); emmc_set_data_timeout(EMMC_RW_DATA_TIMEOUT); } static void emmc_drv_init(void) { emmc_memset((uint8_t *) (&mmc_drv_obj), 0, sizeof(st_mmc_base)); mmc_drv_obj.card_present = HAL_MEMCARD_CARD_IS_IN; mmc_drv_obj.data_timeout = EMMC_RW_DATA_TIMEOUT; mmc_drv_obj.bus_width = HAL_MEMCARD_DATA_WIDTH_1_BIT; } static EMMC_ERROR_CODE emmc_dev_finalize(void) { EMMC_ERROR_CODE result; uint32_t dataL; /* MMC power off * the power supply of eMMC device is always turning on. * RST_n : Hi --> Low level. */ result = rcar_emmc_memcard_power(FALSE); /* host controller reset */ SETR_32(SD_INFO1, 0x00000000U); /* all interrupt clear */ SETR_32(SD_INFO2, SD_INFO2_CLEAR); /* all interrupt clear */ SETR_32(SD_INFO1_MASK, 0x00000000U); /* all interrupt disable */ SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* all interrupt disable */ SETR_32(SD_CLK_CTRL, 0x00000000U); /* MMC clock stop */ dataL = mmio_read_32(CPG_SMSTPCR3); if ((dataL & CPG_MSTP_MMC) == 0U) { dataL |= (CPG_MSTP_MMC); mmio_write_32(CPG_CPGWPR, (~dataL)); mmio_write_32(CPG_SMSTPCR3, dataL); } return result; } static EMMC_ERROR_CODE emmc_dev_init(void) { /* Enable clock supply to eMMC. */ mstpcr_write(CPG_SMSTPCR3, CPG_MSTPSR3, CPG_MSTP_MMC); /* Set SD clock */ mmio_write_32(CPG_CPGWPR, ~((uint32_t) (BIT9 | BIT0))); /* SD phy 200MHz */ /* Stop SDnH clock & SDn=200MHz */ mmio_write_32(CPG_SDxCKCR, (BIT9 | BIT0)); /* MMCIF initialize */ SETR_32(SD_INFO1, 0x00000000U); /* all interrupt clear */ SETR_32(SD_INFO2, SD_INFO2_CLEAR); /* all interrupt clear */ SETR_32(SD_INFO1_MASK, 0x00000000U); /* all interrupt disable */ SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* all interrupt disable */ SETR_32(HOST_MODE, 0x00000000U); /* SD_BUF access width = 64-bit */ SETR_32(SD_OPTION, 0x0000C0EEU); /* Bus width = 1bit, timeout=MAX */ SETR_32(SD_CLK_CTRL, 0x00000000U); /* Automatic Control=Disable, Clock Output=Disable */ return EMMC_SUCCESS; } static EMMC_ERROR_CODE emmc_reset_controller(void) { EMMC_ERROR_CODE retult; /* initialize mmc driver */ emmc_drv_init(); /* initialize H/W */ retult = emmc_dev_init(); if (EMMC_SUCCESS != retult) { return retult; } mmc_drv_obj.initialize = TRUE; return retult; } EMMC_ERROR_CODE emmc_terminate(void) { EMMC_ERROR_CODE result; result = emmc_dev_finalize(); emmc_memset((uint8_t *) (&mmc_drv_obj), 0, sizeof(st_mmc_base)); return result; } EMMC_ERROR_CODE rcar_emmc_init(void) { EMMC_ERROR_CODE retult; retult = emmc_reset_controller(); if (EMMC_SUCCESS != retult) { return retult; } emmc_driver_config(); return EMMC_SUCCESS; } trusted-firmware-a-2.2/drivers/renesas/rcar/emmc/emmc_interrupt.c000066400000000000000000000135441355360272700253070ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights * reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "emmc_config.h" #include "emmc_def.h" #include "emmc_hal.h" #include "emmc_registers.h" #include "emmc_std.h" #include "rcar_def.h" static EMMC_ERROR_CODE emmc_trans_sector(uint32_t *buff_address_virtual); uint32_t emmc_interrupt(void) { EMMC_ERROR_CODE result; uint32_t prr_data; uint32_t cut_ver; uint32_t end_bit; prr_data = mmio_read_32((uintptr_t) RCAR_PRR); cut_ver = prr_data & PRR_CUT_MASK; if ((prr_data & PRR_PRODUCT_MASK) == PRR_PRODUCT_H3) { if (cut_ver == PRR_PRODUCT_10) { end_bit = BIT17; } else if (cut_ver == PRR_PRODUCT_11) { end_bit = BIT17; } else { end_bit = BIT20; } } else if ((prr_data & PRR_PRODUCT_MASK) == PRR_PRODUCT_M3) { if (cut_ver == PRR_PRODUCT_10) { end_bit = BIT17; } else { end_bit = BIT20; } } else { end_bit = BIT20; } /* SD_INFO */ mmc_drv_obj.error_info.info1 = GETR_32(SD_INFO1); mmc_drv_obj.error_info.info2 = GETR_32(SD_INFO2); /* SD_INFO EVENT */ mmc_drv_obj.int_event1 = mmc_drv_obj.error_info.info1 & GETR_32(SD_INFO1_MASK); mmc_drv_obj.int_event2 = mmc_drv_obj.error_info.info2 & GETR_32(SD_INFO2_MASK); /* ERR_STS */ mmc_drv_obj.error_info.status1 = GETR_32(SD_ERR_STS1); mmc_drv_obj.error_info.status2 = GETR_32(SD_ERR_STS2); /* DM_CM_INFO */ mmc_drv_obj.error_info.dm_info1 = GETR_32(DM_CM_INFO1); mmc_drv_obj.error_info.dm_info2 = GETR_32(DM_CM_INFO2); /* DM_CM_INFO EVENT */ mmc_drv_obj.dm_event1 = mmc_drv_obj.error_info.dm_info1 & GETR_32(DM_CM_INFO1_MASK); mmc_drv_obj.dm_event2 = mmc_drv_obj.error_info.dm_info2 & GETR_32(DM_CM_INFO2_MASK); /* ERR SD_INFO2 */ if ((SD_INFO2_ALL_ERR & mmc_drv_obj.int_event2) != 0) { SETR_32(SD_INFO1_MASK, 0x00000000U); /* interrupt disable */ SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR); /* interrupt disable */ SETR_32(SD_INFO1, 0x00000000U); /* interrupt clear */ SETR_32(SD_INFO2, SD_INFO2_CLEAR); /* interrupt clear */ mmc_drv_obj.state_machine_blocking = FALSE; } /* PIO Transfer */ /* BWE/BRE */ else if (((SD_INFO2_BWE | SD_INFO2_BRE) & mmc_drv_obj.int_event2)) { /* BWE */ if (SD_INFO2_BWE & mmc_drv_obj.int_event2) { SETR_32(SD_INFO2, (GETR_32(SD_INFO2) & ~SD_INFO2_BWE)); } /* BRE */ else { SETR_32(SD_INFO2, (GETR_32(SD_INFO2) & ~SD_INFO2_BRE)); } result = emmc_trans_sector(mmc_drv_obj.buff_address_virtual); mmc_drv_obj.buff_address_virtual += EMMC_BLOCK_LENGTH; mmc_drv_obj.remain_size -= EMMC_BLOCK_LENGTH; if (result != EMMC_SUCCESS) { /* data transfer error */ emmc_write_error_info(EMMC_FUNCNO_NONE, result); /* Panic */ SETR_32(SD_INFO1_MASK, 0x00000000U); SETR_32(SD_INFO2_MASK, SD_INFO2_CLEAR); SETR_32(SD_INFO1, 0x00000000U); /* interrupt clear */ SETR_32(SD_INFO2, SD_INFO2_CLEAR); mmc_drv_obj.force_terminate = TRUE; } else { mmc_drv_obj.during_transfer = FALSE; } mmc_drv_obj.state_machine_blocking = FALSE; } /* DMA_TRANSFER */ /* DM_CM_INFO1: DMA-ch0 transfer complete or error occurred */ else if ((BIT16 & mmc_drv_obj.dm_event1) != 0) { SETR_32(DM_CM_INFO1, 0x00000000U); SETR_32(DM_CM_INFO2, 0x00000000U); /* interrupt clear */ SETR_32(SD_INFO2, (GETR_32(SD_INFO2) & ~SD_INFO2_BWE)); /* DM_CM_INFO2: DMA-ch0 error occured */ if ((BIT16 & mmc_drv_obj.dm_event2) != 0) { mmc_drv_obj.dma_error_flag = TRUE; } else { mmc_drv_obj.during_dma_transfer = FALSE; mmc_drv_obj.during_transfer = FALSE; } /* wait next interrupt */ mmc_drv_obj.state_machine_blocking = FALSE; } /* DM_CM_INFO1: DMA-ch1 transfer complete or error occured */ else if ((end_bit & mmc_drv_obj.dm_event1) != 0U) { SETR_32(DM_CM_INFO1, 0x00000000U); SETR_32(DM_CM_INFO2, 0x00000000U); /* interrupt clear */ SETR_32(SD_INFO2, (GETR_32(SD_INFO2) & ~SD_INFO2_BRE)); /* DM_CM_INFO2: DMA-ch1 error occured */ if ((BIT17 & mmc_drv_obj.dm_event2) != 0) { mmc_drv_obj.dma_error_flag = TRUE; } else { mmc_drv_obj.during_dma_transfer = FALSE; mmc_drv_obj.during_transfer = FALSE; } /* wait next interrupt */ mmc_drv_obj.state_machine_blocking = FALSE; } /* Response end */ else if ((SD_INFO1_INFO0 & mmc_drv_obj.int_event1) != 0) { /* interrupt clear */ SETR_32(SD_INFO1, (GETR_32(SD_INFO1) & ~SD_INFO1_INFO0)); mmc_drv_obj.state_machine_blocking = FALSE; } /* Access end */ else if ((SD_INFO1_INFO2 & mmc_drv_obj.int_event1) != 0) { /* interrupt clear */ SETR_32(SD_INFO1, (GETR_32(SD_INFO1) & ~SD_INFO1_INFO2)); mmc_drv_obj.state_machine_blocking = FALSE; } else { /* nothing to do. */ } return (uint32_t) 0; } static EMMC_ERROR_CODE emmc_trans_sector(uint32_t *buff_address_virtual) { uint32_t length, i; uint64_t *bufPtrLL; if (buff_address_virtual == NULL) { return EMMC_ERR_PARAM; } if ((mmc_drv_obj.during_transfer != TRUE) || (mmc_drv_obj.remain_size == 0)) { return EMMC_ERR_STATE; } bufPtrLL = (uint64_t *) buff_address_virtual; length = mmc_drv_obj.remain_size; /* data transefer */ for (i = 0; i < (length >> 3); i++) { /* Write */ if (mmc_drv_obj.cmd_info.dir == HAL_MEMCARD_WRITE) { SETR_64(SD_BUF0, *bufPtrLL); /* buffer --> FIFO */ } /* Read */ else { /* Checks when the read data reaches SD_SIZE. */ /* The BRE bit is cleared at emmc_interrupt function. */ if (((i % (uint32_t) (EMMC_BLOCK_LENGTH >> EMMC_BUF_SIZE_SHIFT)) == 0U) && (i != 0U)) { /* BRE check */ while (((GETR_32(SD_INFO2)) & SD_INFO2_BRE) == 0U) { /* ERROR check */ if (((GETR_32(SD_INFO2)) & SD_INFO2_ALL_ERR) != 0U) { return EMMC_ERR_TRANSFER; } } /* BRE clear */ SETR_32(SD_INFO2, (uint32_t) (GETR_32(SD_INFO2) & ~SD_INFO2_BRE)); } *bufPtrLL = GETR_64(SD_BUF0); /* FIFO --> buffer */ } bufPtrLL++; } return EMMC_SUCCESS; } trusted-firmware-a-2.2/drivers/renesas/rcar/emmc/emmc_mount.c000066400000000000000000000430461355360272700244150ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "emmc_config.h" #include "emmc_hal.h" #include "emmc_std.h" #include "emmc_registers.h" #include "emmc_def.h" #include "micro_delay.h" #include "rcar_def.h" static EMMC_ERROR_CODE emmc_clock_ctrl(uint8_t mode); static EMMC_ERROR_CODE emmc_card_init(void); static EMMC_ERROR_CODE emmc_high_speed(void); static EMMC_ERROR_CODE emmc_bus_width(uint32_t width); static uint32_t emmc_set_timeout_register_value(uint32_t freq); static void set_sd_clk(uint32_t clkDiv); static uint32_t emmc_calc_tran_speed(uint32_t *freq); static void emmc_get_partition_access(void); static void emmc_set_bootpartition(void); static void emmc_set_bootpartition(void) { uint32_t reg; reg = mmio_read_32(RCAR_PRR) & (PRR_PRODUCT_MASK | PRR_CUT_MASK); if (reg == PRR_PRODUCT_M3_CUT10) { mmc_drv_obj.boot_partition_en = (EMMC_PARTITION_ID) ((mmc_drv_obj.ext_csd_data[179] & EMMC_BOOT_PARTITION_EN_MASK) >> EMMC_BOOT_PARTITION_EN_SHIFT); } else if ((reg == PRR_PRODUCT_H3_CUT20) || (reg == PRR_PRODUCT_M3_CUT11)) { mmc_drv_obj.boot_partition_en = mmc_drv_obj.partition_access; } else { if ((mmio_read_32(MFISBTSTSR) & MFISBTSTSR_BOOT_PARTITION) != 0U) { mmc_drv_obj.boot_partition_en = PARTITION_ID_BOOT_2; } else { mmc_drv_obj.boot_partition_en = PARTITION_ID_BOOT_1; } } } static EMMC_ERROR_CODE emmc_card_init(void) { int32_t retry; uint32_t freq = MMC_400KHZ; /* 390KHz */ EMMC_ERROR_CODE result; uint32_t resultCalc; /* state check */ if ((mmc_drv_obj.initialize != TRUE) || (mmc_drv_obj.card_power_enable != TRUE) || ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) != 0) ) { emmc_write_error_info(EMMC_FUNCNO_CARD_INIT, EMMC_ERR_STATE); return EMMC_ERR_STATE; } /* clock on (force change) */ mmc_drv_obj.current_freq = 0; mmc_drv_obj.max_freq = MMC_20MHZ; result = emmc_set_request_mmc_clock(&freq); if (result != EMMC_SUCCESS) { emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT); return EMMC_ERR; } rcar_micro_delay(1000U); /* wait 1ms */ /* Get current access partition */ emmc_get_partition_access(); /* CMD0, arg=0x00000000 */ result = emmc_send_idle_cmd(0x00000000); if (result != EMMC_SUCCESS) { emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT); return result; } rcar_micro_delay(200U); /* wait 74clock 390kHz(189.74us) */ /* CMD1 */ emmc_make_nontrans_cmd(CMD1_SEND_OP_COND, EMMC_HOST_OCR_VALUE); for (retry = 300; retry > 0; retry--) { result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT); return result; } if ((mmc_drv_obj.r3_ocr & EMMC_OCR_STATUS_BIT) != 0) { break; /* card is ready. exit loop */ } rcar_micro_delay(1000U); /* wait 1ms */ } if (retry == 0) { emmc_write_error_info(EMMC_FUNCNO_CARD_INIT, EMMC_ERR_TIMEOUT); return EMMC_ERR_TIMEOUT; } switch (mmc_drv_obj.r3_ocr & EMMC_OCR_ACCESS_MODE_MASK) { case EMMC_OCR_ACCESS_MODE_SECT: mmc_drv_obj.access_mode = TRUE; /* sector mode */ break; default: /* unknown value */ emmc_write_error_info(EMMC_FUNCNO_CARD_INIT, EMMC_ERR); return EMMC_ERR; } /* CMD2 */ emmc_make_nontrans_cmd(CMD2_ALL_SEND_CID_MMC, 0x00000000); mmc_drv_obj.response = (uint32_t *) (&mmc_drv_obj.cid_data[0]); /* use CID special buffer */ result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT); return result; } /* CMD3 */ emmc_make_nontrans_cmd(CMD3_SET_RELATIVE_ADDR, EMMC_RCA << 16); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT); return result; } /* CMD9 (CSD) */ emmc_make_nontrans_cmd(CMD9_SEND_CSD, EMMC_RCA << 16); mmc_drv_obj.response = (uint32_t *) (&mmc_drv_obj.csd_data[0]); /* use CSD special buffer */ result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT); return result; } /* card version check */ if (EMMC_CSD_SPEC_VARS() < 4) { emmc_write_error_info(EMMC_FUNCNO_CARD_INIT, EMMC_ERR_ILLEGAL_CARD); return EMMC_ERR_ILLEGAL_CARD; } /* CMD7 (select card) */ emmc_make_nontrans_cmd(CMD7_SELECT_CARD, EMMC_RCA << 16); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT); return result; } mmc_drv_obj.selected = TRUE; /* card speed check */ resultCalc = emmc_calc_tran_speed(&freq); /* Card spec is calculated from TRAN_SPEED(CSD). */ if (resultCalc == 0) { emmc_write_error_info(EMMC_FUNCNO_CARD_INIT, EMMC_ERR_ILLEGAL_CARD); return EMMC_ERR_ILLEGAL_CARD; } mmc_drv_obj.max_freq = freq; /* max frequency (card spec) */ result = emmc_set_request_mmc_clock(&freq); if (result != EMMC_SUCCESS) { emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT); return EMMC_ERR; } /* set read/write timeout */ mmc_drv_obj.data_timeout = emmc_set_timeout_register_value(freq); SETR_32(SD_OPTION, ((GETR_32(SD_OPTION) & ~(SD_OPTION_TIMEOUT_CNT_MASK)) | mmc_drv_obj.data_timeout)); /* SET_BLOCKLEN(512byte) */ /* CMD16 */ emmc_make_nontrans_cmd(CMD16_SET_BLOCKLEN, EMMC_BLOCK_LENGTH); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT); return result; } /* Transfer Data Length */ SETR_32(SD_SIZE, EMMC_BLOCK_LENGTH); /* CMD8 (EXT_CSD) */ emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000, (uint32_t *) (&mmc_drv_obj.ext_csd_data[0]), EMMC_MAX_EXT_CSD_LENGTH, HAL_MEMCARD_READ, HAL_MEMCARD_NOT_DMA); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { /* CMD12 is not send. * If BUS initialization is failed, user must be execute Bus initialization again. * Bus initialization is start CMD0(soft reset command). */ emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT); return result; } /* Set boot partition */ emmc_set_bootpartition(); return EMMC_SUCCESS; } static EMMC_ERROR_CODE emmc_high_speed(void) { uint32_t freq; /**< High speed mode clock frequency */ EMMC_ERROR_CODE result; uint8_t cardType; /* state check */ if (mmc_drv_obj.selected != TRUE) { emmc_write_error_info(EMMC_FUNCNO_HIGH_SPEED, EMMC_ERR_STATE); return EMMC_ERR_STATE; } /* max frequency */ cardType = (uint8_t) mmc_drv_obj.ext_csd_data[EMMC_EXT_CSD_CARD_TYPE]; if ((cardType & EMMC_EXT_CSD_CARD_TYPE_52MHZ) != 0) freq = MMC_52MHZ; else if ((cardType & EMMC_EXT_CSD_CARD_TYPE_26MHZ) != 0) freq = MMC_26MHZ; else freq = MMC_20MHZ; /* Hi-Speed-mode selction */ if ((MMC_52MHZ == freq) || (MMC_26MHZ == freq)) { /* CMD6 */ emmc_make_nontrans_cmd(CMD6_SWITCH, EMMC_SWITCH_HS_TIMING); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { emmc_write_error_info_func_no(EMMC_FUNCNO_HIGH_SPEED); return result; } mmc_drv_obj.hs_timing = TIMING_HIGH_SPEED; /* High-Speed */ } /* set mmc clock */ mmc_drv_obj.max_freq = freq; result = emmc_set_request_mmc_clock(&freq); if (result != EMMC_SUCCESS) { emmc_write_error_info_func_no(EMMC_FUNCNO_HIGH_SPEED); return EMMC_ERR; } /* set read/write timeout */ mmc_drv_obj.data_timeout = emmc_set_timeout_register_value(freq); SETR_32(SD_OPTION, ((GETR_32(SD_OPTION) & ~(SD_OPTION_TIMEOUT_CNT_MASK)) | mmc_drv_obj.data_timeout)); /* CMD13 */ emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK_WITHOUT_CRC, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { emmc_write_error_info_func_no(EMMC_FUNCNO_HIGH_SPEED); return result; } return EMMC_SUCCESS; } static EMMC_ERROR_CODE emmc_clock_ctrl(uint8_t mode) { uint32_t value; /* busy check */ if ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) != 0) { emmc_write_error_info(EMMC_FUNCNO_SET_CLOCK, EMMC_ERR_CARD_BUSY); return EMMC_ERR; } if (mode == TRUE) { /* clock ON */ value = ((GETR_32(SD_CLK_CTRL) | MMC_SD_CLK_START) & SD_CLK_WRITE_MASK); SETR_32(SD_CLK_CTRL, value); /* on */ mmc_drv_obj.clock_enable = TRUE; } else { /* clock OFF */ value = ((GETR_32(SD_CLK_CTRL) & MMC_SD_CLK_STOP) & SD_CLK_WRITE_MASK); SETR_32(SD_CLK_CTRL, value); /* off */ mmc_drv_obj.clock_enable = FALSE; } return EMMC_SUCCESS; } static EMMC_ERROR_CODE emmc_bus_width(uint32_t width) { EMMC_ERROR_CODE result = EMMC_ERR; /* parameter check */ if ((width != 8) && (width != 4) && (width != 1)) { emmc_write_error_info(EMMC_FUNCNO_BUS_WIDTH, EMMC_ERR_PARAM); return EMMC_ERR_PARAM; } /* state check */ if (mmc_drv_obj.selected != TRUE) { emmc_write_error_info(EMMC_FUNCNO_BUS_WIDTH, EMMC_ERR_STATE); return EMMC_ERR_STATE; } mmc_drv_obj.bus_width = (HAL_MEMCARD_DATA_WIDTH) (width >> 2); /* 2 = 8bit, 1 = 4bit, 0 =1bit */ /* CMD6 */ emmc_make_nontrans_cmd(CMD6_SWITCH, (EMMC_SWITCH_BUS_WIDTH_1 | (mmc_drv_obj.bus_width << 8))); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { /* occurred error */ mmc_drv_obj.bus_width = HAL_MEMCARD_DATA_WIDTH_1_BIT; goto EXIT; } switch (mmc_drv_obj.bus_width) { case HAL_MEMCARD_DATA_WIDTH_1_BIT: SETR_32(SD_OPTION, ((GETR_32(SD_OPTION) & ~(BIT15 | BIT13)) | BIT15)); break; case HAL_MEMCARD_DATA_WIDTH_4_BIT: SETR_32(SD_OPTION, (GETR_32(SD_OPTION) & ~(BIT15 | BIT13))); break; case HAL_MEMCARD_DATA_WIDTH_8_BIT: SETR_32(SD_OPTION, ((GETR_32(SD_OPTION) & ~(BIT15 | BIT13)) | BIT13)); break; default: goto EXIT; } /* CMD13 */ emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { goto EXIT; } /* CMD8 (EXT_CSD) */ emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000, (uint32_t *) (&mmc_drv_obj.ext_csd_data[0]), EMMC_MAX_EXT_CSD_LENGTH, HAL_MEMCARD_READ, HAL_MEMCARD_NOT_DMA); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { goto EXIT; } return EMMC_SUCCESS; EXIT: emmc_write_error_info(EMMC_FUNCNO_BUS_WIDTH, result); ERROR("BL2: emmc bus_width error end\n"); return result; } EMMC_ERROR_CODE emmc_select_partition(EMMC_PARTITION_ID id) { EMMC_ERROR_CODE result; uint32_t arg; uint32_t partition_config; /* state check */ if (mmc_drv_obj.mount != TRUE) { emmc_write_error_info(EMMC_FUNCNO_NONE, EMMC_ERR_STATE); return EMMC_ERR_STATE; } /* id = PARTITION_ACCESS(Bit[2:0]) */ if ((id & ~PARTITION_ID_MASK) != 0) { emmc_write_error_info(EMMC_FUNCNO_NONE, EMMC_ERR_PARAM); return EMMC_ERR_PARAM; } /* EXT_CSD[179] value */ partition_config = (uint32_t) mmc_drv_obj.ext_csd_data[EMMC_EXT_CSD_PARTITION_CONFIG]; if ((partition_config & PARTITION_ID_MASK) == id) { result = EMMC_SUCCESS; } else { partition_config = (uint32_t) ((partition_config & ~PARTITION_ID_MASK) | id); arg = EMMC_SWITCH_PARTITION_CONFIG | (partition_config << 8); result = emmc_set_ext_csd(arg); } return result; } static void set_sd_clk(uint32_t clkDiv) { uint32_t dataL; dataL = (GETR_32(SD_CLK_CTRL) & (~SD_CLK_CTRL_CLKDIV_MASK)); switch (clkDiv) { case 1: dataL |= 0x000000FFU; break; /* 1/1 */ case 2: dataL |= 0x00000000U; break; /* 1/2 */ case 4: dataL |= 0x00000001U; break; /* 1/4 */ case 8: dataL |= 0x00000002U; break; /* 1/8 */ case 16: dataL |= 0x00000004U; break; /* 1/16 */ case 32: dataL |= 0x00000008U; break; /* 1/32 */ case 64: dataL |= 0x00000010U; break; /* 1/64 */ case 128: dataL |= 0x00000020U; break; /* 1/128 */ case 256: dataL |= 0x00000040U; break; /* 1/256 */ case 512: dataL |= 0x00000080U; break; /* 1/512 */ } SETR_32(SD_CLK_CTRL, dataL); mmc_drv_obj.current_freq = (uint32_t) clkDiv; } static void emmc_get_partition_access(void) { uint32_t reg; EMMC_ERROR_CODE result; reg = mmio_read_32(RCAR_PRR) & (PRR_PRODUCT_MASK | PRR_CUT_MASK); if ((reg == PRR_PRODUCT_H3_CUT20) || (reg == PRR_PRODUCT_M3_CUT11)) { SETR_32(SD_OPTION, 0x000060EEU); /* 8 bits width */ /* CMD8 (EXT_CSD) */ emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000U, (uint32_t *) (&mmc_drv_obj.ext_csd_data[0]), EMMC_MAX_EXT_CSD_LENGTH, HAL_MEMCARD_READ, HAL_MEMCARD_NOT_DMA); mmc_drv_obj.get_partition_access_flag = TRUE; result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); mmc_drv_obj.get_partition_access_flag = FALSE; if (result == EMMC_SUCCESS) { mmc_drv_obj.partition_access = (EMMC_PARTITION_ID) (mmc_drv_obj.ext_csd_data[179] & PARTITION_ID_MASK); } else if (result == EMMC_ERR_CMD_TIMEOUT) { mmc_drv_obj.partition_access = PARTITION_ID_BOOT_1; } else { emmc_write_error_info(EMMC_FUNCNO_GET_PERTITION_ACCESS, result); panic(); } SETR_32(SD_OPTION, 0x0000C0EEU); /* Initialize */ } } static uint32_t emmc_calc_tran_speed(uint32_t *freq) { const uint32_t unit[8] = { 10000, 100000, 1000000, 10000000, 0, 0, 0, 0 }; /**< frequency unit (1/10) */ const uint32_t mult[16] = { 0, 10, 12, 13, 15, 20, 26, 30, 35, 40, 45, 52, 55, 60, 70, 80 }; uint32_t maxFreq; uint32_t result; uint32_t tran_speed = EMMC_CSD_TRAN_SPEED(); /* tran_speed = 0x32 * unit[tran_speed&0x7] = uint[0x2] = 1000000 * mult[(tran_speed&0x78)>>3] = mult[0x30>>3] = mult[6] = 26 * 1000000 * 26 = 26000000 (26MHz) */ result = 1; maxFreq = unit[tran_speed & EMMC_TRANSPEED_FREQ_UNIT_MASK] * mult[(tran_speed & EMMC_TRANSPEED_MULT_MASK) >> EMMC_TRANSPEED_MULT_SHIFT]; if (maxFreq == 0) { result = 0; } else if (MMC_FREQ_52MHZ <= maxFreq) *freq = MMC_52MHZ; else if (MMC_FREQ_26MHZ <= maxFreq) *freq = MMC_26MHZ; else if (MMC_FREQ_20MHZ <= maxFreq) *freq = MMC_20MHZ; else *freq = MMC_400KHZ; return result; } static uint32_t emmc_set_timeout_register_value(uint32_t freq) { uint32_t timeoutCnt; /* SD_OPTION - Timeout Counter */ switch (freq) { case 1U: timeoutCnt = 0xE0U; break; /* SDCLK * 2^27 */ case 2U: timeoutCnt = 0xE0U; break; /* SDCLK * 2^27 */ case 4U: timeoutCnt = 0xD0U; break; /* SDCLK * 2^26 */ case 8U: timeoutCnt = 0xC0U; break; /* SDCLK * 2^25 */ case 16U: timeoutCnt = 0xB0U; break; /* SDCLK * 2^24 */ case 32U: timeoutCnt = 0xA0U; break; /* SDCLK * 2^23 */ case 64U: timeoutCnt = 0x90U; break; /* SDCLK * 2^22 */ case 128U: timeoutCnt = 0x80U; break; /* SDCLK * 2^21 */ case 256U: timeoutCnt = 0x70U; break; /* SDCLK * 2^20 */ case 512U: timeoutCnt = 0x70U; break; /* SDCLK * 2^20 */ default: timeoutCnt = 0xE0U; break; /* SDCLK * 2^27 */ } return timeoutCnt; } EMMC_ERROR_CODE emmc_set_ext_csd(uint32_t arg) { EMMC_ERROR_CODE result; /* CMD6 */ emmc_make_nontrans_cmd(CMD6_SWITCH, arg); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { return result; } /* CMD13 */ emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { return result; } /* CMD8 (EXT_CSD) */ emmc_make_trans_cmd(CMD8_SEND_EXT_CSD, 0x00000000, (uint32_t *) (&mmc_drv_obj.ext_csd_data[0]), EMMC_MAX_EXT_CSD_LENGTH, HAL_MEMCARD_READ, HAL_MEMCARD_NOT_DMA); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { return result; } return EMMC_SUCCESS; } EMMC_ERROR_CODE emmc_set_request_mmc_clock(uint32_t *freq) { /* parameter check */ if (freq == NULL) { emmc_write_error_info(EMMC_FUNCNO_SET_CLOCK, EMMC_ERR_PARAM); return EMMC_ERR_PARAM; } /* state check */ if ((mmc_drv_obj.initialize != TRUE) || (mmc_drv_obj.card_power_enable != TRUE)) { emmc_write_error_info(EMMC_FUNCNO_SET_CLOCK, EMMC_ERR_STATE); return EMMC_ERR_STATE; } /* clock is already running in the desired frequency. */ if ((mmc_drv_obj.clock_enable == TRUE) && (mmc_drv_obj.current_freq == *freq)) { return EMMC_SUCCESS; } /* busy check */ if ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) != 0) { emmc_write_error_info(EMMC_FUNCNO_SET_CLOCK, EMMC_ERR_CARD_BUSY); return EMMC_ERR; } set_sd_clk(*freq); mmc_drv_obj.clock_enable = FALSE; return emmc_clock_ctrl(TRUE); /* clock on */ } EMMC_ERROR_CODE rcar_emmc_mount(void) { EMMC_ERROR_CODE result; /* state check */ if ((mmc_drv_obj.initialize != TRUE) || (mmc_drv_obj.card_power_enable != TRUE) || ((GETR_32(SD_INFO2) & SD_INFO2_CBSY) != 0) ) { emmc_write_error_info(EMMC_FUNCNO_MOUNT, EMMC_ERR_STATE); return EMMC_ERR_STATE; } /* initialize card (IDLE state --> Transfer state) */ result = emmc_card_init(); if (result != EMMC_SUCCESS) { emmc_write_error_info_func_no(EMMC_FUNCNO_CARD_INIT); if (emmc_clock_ctrl(FALSE) != EMMC_SUCCESS) { /* nothing to do. */ } return result; } /* Switching high speed mode */ result = emmc_high_speed(); if (result != EMMC_SUCCESS) { emmc_write_error_info_func_no(EMMC_FUNCNO_HIGH_SPEED); if (emmc_clock_ctrl(FALSE) != EMMC_SUCCESS) { /* nothing to do. */ } return result; } /* Changing the data bus width */ result = emmc_bus_width(8); if (result != EMMC_SUCCESS) { emmc_write_error_info_func_no(EMMC_FUNCNO_BUS_WIDTH); if (emmc_clock_ctrl(FALSE) != EMMC_SUCCESS) { /* nothing to do. */ } return result; } /* mount complete */ mmc_drv_obj.mount = TRUE; return EMMC_SUCCESS; } trusted-firmware-a-2.2/drivers/renesas/rcar/emmc/emmc_read.c000066400000000000000000000066601355360272700241670ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "emmc_config.h" #include "emmc_hal.h" #include "emmc_std.h" #include "emmc_registers.h" #include "emmc_def.h" #define MIN_EMMC(a, b) (((a) < (b)) ? (a) : (b)) #define EMMC_RW_SECTOR_COUNT_MAX 0x0000ffffU static EMMC_ERROR_CODE emmc_multiple_block_read (uint32_t *buff_address_virtual, uint32_t sector_number, uint32_t count, HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode) { EMMC_ERROR_CODE result; /* parameter check */ if ((count > EMMC_RW_SECTOR_COUNT_MAX) || (count == 0) || ((transfer_mode != HAL_MEMCARD_DMA) && (transfer_mode != HAL_MEMCARD_NOT_DMA)) ) { emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_PARAM); return EMMC_ERR_PARAM; } /* CMD23 */ emmc_make_nontrans_cmd(CMD23_SET_BLOCK_COUNT, count); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { return result; } SETR_32(SD_SECCNT, count); SETR_32(SD_STOP, 0x00000100); SETR_32(CC_EXT_MODE, (CC_EXT_MODE_CLEAR | CC_EXT_MODE_DMASDRW_ENABLE)); /* SD_BUF Read/Write DMA Transfer enable */ /* CMD18 */ emmc_make_trans_cmd(CMD18_READ_MULTIPLE_BLOCK, sector_number, buff_address_virtual, count << EMMC_SECTOR_SIZE_SHIFT, HAL_MEMCARD_READ, transfer_mode); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { return result; /* CMD18 error code */ } /* CMD13 */ emmc_make_nontrans_cmd(CMD13_SEND_STATUS, EMMC_RCA << 16); result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { return result; } #if RCAR_BL2_DCACHE == 1 if (transfer_mode == HAL_MEMCARD_NOT_DMA) { flush_dcache_range((uint64_t) buff_address_virtual, ((size_t) count << EMMC_SECTOR_SIZE_SHIFT)); } #endif /* RCAR_BL2_DCACHE == 1 */ /* ready status check */ if ((mmc_drv_obj.r1_card_status & EMMC_R1_READY) == 0) { emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_CARD_BUSY); return EMMC_ERR_CARD_BUSY; } /* state check */ if (mmc_drv_obj.current_state != EMMC_R1_STATE_TRAN) { emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_CARD_STATE); return EMMC_ERR_CARD_STATE; } return EMMC_SUCCESS; } EMMC_ERROR_CODE emmc_read_sector(uint32_t *buff_address_virtual, uint32_t sector_number, uint32_t count, uint32_t feature_flags) { uint32_t trans_count; uint32_t remain; EMMC_ERROR_CODE result; HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode; /* parameter check */ if (count == 0) { emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_PARAM); return EMMC_ERR_PARAM; } /* state check */ if (mmc_drv_obj.mount != TRUE) { emmc_write_error_info(EMMC_FUNCNO_READ_SECTOR, EMMC_ERR_STATE); return EMMC_ERR_STATE; } /* DMA? */ if ((feature_flags & LOADIMAGE_FLAGS_DMA_ENABLE) != 0) { transfer_mode = HAL_MEMCARD_DMA; } else { transfer_mode = HAL_MEMCARD_NOT_DMA; } remain = count; while (remain != 0) { trans_count = MIN_EMMC(remain, EMMC_RW_SECTOR_COUNT_MAX); result = emmc_multiple_block_read(buff_address_virtual, sector_number, trans_count, transfer_mode); if (result != EMMC_SUCCESS) { return result; } buff_address_virtual += (EMMC_BLOCK_LENGTH_DW * trans_count); sector_number += trans_count; remain -= trans_count; } return EMMC_SUCCESS; } trusted-firmware-a-2.2/drivers/renesas/rcar/emmc/emmc_registers.h000066400000000000000000000234411355360272700252640ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /** * @file emmc_registers.h * @brief emmc boot driver is expecting this header file. HS-MMC module header file. * */ #ifndef EMMC_REGISTERS_H #define EMMC_REGISTERS_H /* ************************ HEADER (INCLUDE) SECTION *********************** */ /* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */ /* MMC channel select */ #define MMC_CH0 (0U) /* SDHI2/MMC0 */ #define MMC_CH1 (1U) /* SDHI3/MMC1 */ #if RCAR_LSI == RCAR_E3 #define USE_MMC_CH (MMC_CH1) /* R-Car E3 */ #else /* RCAR_LSI == RCAR_E3 */ #define USE_MMC_CH (MMC_CH0) /* R-Car H3/M3/M3N */ #endif /* RCAR_LSI == RCAR_E3 */ #define BIT0 (0x00000001U) #define BIT1 (0x00000002U) #define BIT2 (0x00000004U) #define BIT3 (0x00000008U) #define BIT4 (0x00000010U) #define BIT5 (0x00000020U) #define BIT6 (0x00000040U) #define BIT7 (0x00000080U) #define BIT8 (0x00000100U) #define BIT9 (0x00000200U) #define BIT10 (0x00000400U) #define BIT11 (0x00000800U) #define BIT12 (0x00001000U) #define BIT13 (0x00002000U) #define BIT14 (0x00004000U) #define BIT15 (0x00008000U) #define BIT16 (0x00010000U) #define BIT17 (0x00020000U) #define BIT18 (0x00040000U) #define BIT19 (0x00080000U) #define BIT20 (0x00100000U) #define BIT21 (0x00200000U) #define BIT22 (0x00400000U) #define BIT23 (0x00800000U) #define BIT24 (0x01000000U) #define BIT25 (0x02000000U) #define BIT26 (0x04000000U) #define BIT27 (0x08000000U) #define BIT28 (0x10000000U) #define BIT29 (0x20000000U) #define BIT30 (0x40000000U) #define BIT31 (0x80000000U) /** @brief Clock Pulse Generator (CPG) registers */ #define CPG_BASE (0xE6150000U) #define CPG_MSTPSR3 (CPG_BASE+0x0048U) /* Module stop status register 3 */ #define CPG_SMSTPCR3 (CPG_BASE+0x013CU) /* System module stop control register 3 */ #define CPG_SD2CKCR (CPG_BASE+0x0268U) /* SDHI2 clock frequency control register */ #define CPG_SD3CKCR (CPG_BASE+0x026CU) /* SDHI3 clock frequency control register */ #define CPG_CPGWPR (CPG_BASE+0x0900U) /* CPG Write Protect Register */ #if USE_MMC_CH == MMC_CH0 #define CPG_SDxCKCR (CPG_SD2CKCR) /* SDHI2/MMC0 */ #else /* USE_MMC_CH == MMC_CH0 */ #define CPG_SDxCKCR (CPG_SD3CKCR) /* SDHI3/MMC1 */ #endif /* USE_MMC_CH == MMC_CH0 */ /** Boot Status register */ #define MFISBTSTSR (0xE6260604U) #define MFISBTSTSR_BOOT_PARTITION (0x00000010U) /** brief eMMC registers */ #define MMC0_SD_BASE (0xEE140000U) #define MMC1_SD_BASE (0xEE160000U) #if USE_MMC_CH == MMC_CH0 #define MMC_SD_BASE (MMC0_SD_BASE) #else /* USE_MMC_CH == MMC_CH0 */ #define MMC_SD_BASE (MMC1_SD_BASE) #endif /* USE_MMC_CH == MMC_CH0 */ #define SD_CMD (MMC_SD_BASE + 0x0000U) #define SD_PORTSEL (MMC_SD_BASE + 0x0008U) #define SD_ARG (MMC_SD_BASE + 0x0010U) #define SD_ARG1 (MMC_SD_BASE + 0x0018U) #define SD_STOP (MMC_SD_BASE + 0x0020U) #define SD_SECCNT (MMC_SD_BASE + 0x0028U) #define SD_RSP10 (MMC_SD_BASE + 0x0030U) #define SD_RSP1 (MMC_SD_BASE + 0x0038U) #define SD_RSP32 (MMC_SD_BASE + 0x0040U) #define SD_RSP3 (MMC_SD_BASE + 0x0048U) #define SD_RSP54 (MMC_SD_BASE + 0x0050U) #define SD_RSP5 (MMC_SD_BASE + 0x0058U) #define SD_RSP76 (MMC_SD_BASE + 0x0060U) #define SD_RSP7 (MMC_SD_BASE + 0x0068U) #define SD_INFO1 (MMC_SD_BASE + 0x0070U) #define SD_INFO2 (MMC_SD_BASE + 0x0078U) #define SD_INFO1_MASK (MMC_SD_BASE + 0x0080U) #define SD_INFO2_MASK (MMC_SD_BASE + 0x0088U) #define SD_CLK_CTRL (MMC_SD_BASE + 0x0090U) #define SD_SIZE (MMC_SD_BASE + 0x0098U) #define SD_OPTION (MMC_SD_BASE + 0x00A0U) #define SD_ERR_STS1 (MMC_SD_BASE + 0x00B0U) #define SD_ERR_STS2 (MMC_SD_BASE + 0x00B8U) #define SD_BUF0 (MMC_SD_BASE + 0x00C0U) #define SDIO_MODE (MMC_SD_BASE + 0x00D0U) #define SDIO_INFO1 (MMC_SD_BASE + 0x00D8U) #define SDIO_INFO1_MASK (MMC_SD_BASE + 0x00E0U) #define CC_EXT_MODE (MMC_SD_BASE + 0x0360U) #define SOFT_RST (MMC_SD_BASE + 0x0380U) #define VERSION (MMC_SD_BASE + 0x0388U) #define HOST_MODE (MMC_SD_BASE + 0x0390U) #define DM_CM_DTRAN_MODE (MMC_SD_BASE + 0x0820U) #define DM_CM_DTRAN_CTRL (MMC_SD_BASE + 0x0828U) #define DM_CM_RST (MMC_SD_BASE + 0x0830U) #define DM_CM_INFO1 (MMC_SD_BASE + 0x0840U) #define DM_CM_INFO1_MASK (MMC_SD_BASE + 0x0848U) #define DM_CM_INFO2 (MMC_SD_BASE + 0x0850U) #define DM_CM_INFO2_MASK (MMC_SD_BASE + 0x0858U) #define DM_DTRAN_ADDR (MMC_SD_BASE + 0x0880U) /** @brief SD_INFO1 Registers */ #define SD_INFO1_HPIRES 0x00010000UL /* Response Reception Completion */ #define SD_INFO1_INFO10 0x00000400UL /* Indicates the SDDAT3 state */ #define SD_INFO1_INFO9 0x00000200UL /* SDDAT3 Card Insertion */ #define SD_INFO1_INFO8 0x00000100UL /* SDDAT3 Card Removal */ #define SD_INFO1_INFO7 0x00000080UL /* Write Protect */ #define SD_INFO1_INFO5 0x00000020UL /* Indicates the ISDCD state */ #define SD_INFO1_INFO4 0x00000010UL /* ISDCD Card Insertion */ #define SD_INFO1_INFO3 0x00000008UL /* ISDCD Card Removal */ #define SD_INFO1_INFO2 0x00000004UL /* Access end */ #define SD_INFO1_INFO0 0x00000001UL /* Response end */ /** @brief SD_INFO2 Registers */ #define SD_INFO2_ILA 0x00008000UL /* Illegal Access Error */ #define SD_INFO2_CBSY 0x00004000UL /* Command Type Register Busy */ #define SD_INFO2_SCLKDIVEN 0x00002000UL #define SD_INFO2_BWE 0x00000200UL /* SD_BUF Write Enable */ #define SD_INFO2_BRE 0x00000100UL /* SD_BUF Read Enable */ #define SD_INFO2_DAT0 0x00000080UL /* SDDAT0 */ #define SD_INFO2_ERR6 0x00000040UL /* Response Timeout */ #define SD_INFO2_ERR5 0x00000020UL /* SD_BUF Illegal Read Access */ #define SD_INFO2_ERR4 0x00000010UL /* SD_BUF Illegal Write Access */ #define SD_INFO2_ERR3 0x00000008UL /* Data Timeout */ #define SD_INFO2_ERR2 0x00000004UL /* END Error */ #define SD_INFO2_ERR1 0x00000002UL /* CRC Error */ #define SD_INFO2_ERR0 0x00000001UL /* CMD Error */ #define SD_INFO2_ALL_ERR 0x0000807FUL #define SD_INFO2_CLEAR 0x00000800UL /* BIT11 The write value should always be 1. HWM_0003 */ /** @brief SOFT_RST */ #define SOFT_RST_SDRST 0x00000001UL /** @brief SD_CLK_CTRL */ #define SD_CLK_CTRL_SDCLKOFFEN 0x00000200UL #define SD_CLK_CTRL_SCLKEN 0x00000100UL #define SD_CLK_CTRL_CLKDIV_MASK 0x000000FFUL #define SD_CLOCK_ENABLE 0x00000100UL #define SD_CLOCK_DISABLE 0x00000000UL #define SD_CLK_WRITE_MASK 0x000003FFUL #define SD_CLK_CLKDIV_CLEAR_MASK 0xFFFFFF0FUL /** @brief SD_OPTION */ #define SD_OPTION_TIMEOUT_CNT_MASK 0x000000F0UL /** @brief MMC Clock Frequency * 200MHz * 1/x = output clock */ #define MMC_CLK_OFF 0UL /* Clock output is disabled */ #define MMC_400KHZ 512UL /* 200MHz * 1/512 = 390 KHz */ #define MMC_20MHZ 16UL /* 200MHz * 1/16 = 12.5 MHz Normal speed mode */ #define MMC_26MHZ 8UL /* 200MHz * 1/8 = 25 MHz High speed mode 26Mhz */ #define MMC_52MHZ 4UL /* 200MHz * 1/4 = 50 MHz High speed mode 52Mhz */ #define MMC_100MHZ 2UL /* 200MHz * 1/2 = 100 MHz */ #define MMC_200MHZ 1UL /* 200MHz * 1/1 = 200 MHz */ #define MMC_FREQ_52MHZ 52000000UL #define MMC_FREQ_26MHZ 26000000UL #define MMC_FREQ_20MHZ 20000000UL /** @brief MMC Clock DIV */ #define MMC_SD_CLK_START 0x00000100UL /* CLOCK On */ #define MMC_SD_CLK_STOP (~0x00000100UL) /* CLOCK stop */ #define MMC_SD_CLK_DIV1 0x000000FFUL /* 1/1 */ #define MMC_SD_CLK_DIV2 0x00000000UL /* 1/2 */ #define MMC_SD_CLK_DIV4 0x00000001UL /* 1/4 */ #define MMC_SD_CLK_DIV8 0x00000002UL /* 1/8 */ #define MMC_SD_CLK_DIV16 0x00000004UL /* 1/16 */ #define MMC_SD_CLK_DIV32 0x00000008UL /* 1/32 */ #define MMC_SD_CLK_DIV64 0x00000010UL /* 1/64 */ #define MMC_SD_CLK_DIV128 0x00000020UL /* 1/128 */ #define MMC_SD_CLK_DIV256 0x00000040UL /* 1/256 */ #define MMC_SD_CLK_DIV512 0x00000080UL /* 1/512 */ /** @brief DM_CM_DTRAN_MODE */ #define DM_CM_DTRAN_MODE_CH0 0x00000000UL /* CH0(downstream) */ #define DM_CM_DTRAN_MODE_CH1 0x00010000UL /* CH1(upstream) */ #define DM_CM_DTRAN_MODE_BIT_WIDTH 0x00000030UL /** @brief CC_EXT_MODE */ #define CC_EXT_MODE_DMASDRW_ENABLE 0x00000002UL /* SD_BUF Read/Write DMA Transfer */ #define CC_EXT_MODE_CLEAR 0x00001010UL /* BIT 12 & 4 always 1. */ /** @brief DM_CM_INFO_MASK */ #define DM_CM_INFO_MASK_CLEAR 0xFFFCFFFEUL #define DM_CM_INFO_CH0_ENABLE 0x00010001UL #define DM_CM_INFO_CH1_ENABLE 0x00020001UL /** @brief DM_DTRAN_ADDR */ #define DM_DTRAN_ADDR_WRITE_MASK 0xFFFFFFF8UL /** @brief DM_CM_DTRAN_CTRL */ #define DM_CM_DTRAN_CTRL_START 0x00000001UL /** @brief SYSC Registers */ #if USE_MMC_CH == MMC_CH0 #define CPG_MSTP_MMC (BIT12) /* SDHI2/MMC0 */ #else /* USE_MMC_CH == MMC_CH0 */ #define CPG_MSTP_MMC (BIT11) /* SDHI3/MMC1 */ #endif /* USE_MMC_CH == MMC_CH0 */ /* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */ /* ********************** DECLARATION OF EXTERNAL DATA ********************* */ /* ************************** FUNCTION PROTOTYPES ************************** */ /* ********************************* CODE ********************************** */ #endif /* EMMC_REGISTERS_H */ /* ******************************** END ************************************ */ trusted-firmware-a-2.2/drivers/renesas/rcar/emmc/emmc_std.h000066400000000000000000000473631355360272700240600ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /** * @file emmc_std.h * @brief eMMC boot is expecting this header file * */ #ifndef EMMC_STD_H #define EMMC_STD_H #include "emmc_hal.h" /* ************************ HEADER (INCLUDE) SECTION *********************** */ /* ***************** MACROS, CONSTANTS, COMPILATION FLAGS ****************** */ #ifndef FALSE #define FALSE 0U #endif #ifndef TRUE #define TRUE 1U #endif /** @brief 64bit registers **/ #define SETR_64(r, v) (*(volatile uint64_t *)(r) = (v)) #define GETR_64(r) (*(volatile uint64_t *)(r)) /** @brief 32bit registers **/ #define SETR_32(r, v) (*(volatile uint32_t *)(r) = (v)) #define GETR_32(r) (*(volatile uint32_t *)(r)) /** @brief 16bit registers */ #define SETR_16(r, v) (*(volatile uint16_t *)(r) = (v)) #define GETR_16(r) (*(volatile uint16_t *)(r)) /** @brief 8bit registers */ #define SETR_8(r, v) (*(volatile uint8_t *)(r) = (v)) #define GETR_8(r) (*(volatile uint8_t *)(r)) /** @brief CSD register Macros */ #define EMMC_GET_CID(x, y) (emmc_bit_field(mmc_drv_obj.cid_data, (x), (y))) #define EMMC_CID_MID() (EMMC_GET_CID(127, 120)) #define EMMC_CID_CBX() (EMMC_GET_CID(113, 112)) #define EMMC_CID_OID() (EMMC_GET_CID(111, 104)) #define EMMC_CID_PNM1() (EMMC_GET_CID(103, 88)) #define EMMC_CID_PNM2() (EMMC_GET_CID(87, 56)) #define EMMC_CID_PRV() (EMMC_GET_CID(55, 48)) #define EMMC_CID_PSN() (EMMC_GET_CID(47, 16)) #define EMMC_CID_MDT() (EMMC_GET_CID(15, 8)) #define EMMC_CID_CRC() (EMMC_GET_CID(7, 1)) /** @brief CSD register Macros */ #define EMMC_GET_CSD(x, y) (emmc_bit_field(mmc_drv_obj.csd_data, (x), (y))) #define EMMC_CSD_CSD_STRUCTURE() (EMMC_GET_CSD(127, 126)) #define EMMC_CSD_SPEC_VARS() (EMMC_GET_CSD(125, 122)) #define EMMC_CSD_TAAC() (EMMC_GET_CSD(119, 112)) #define EMMC_CSD_NSAC() (EMMC_GET_CSD(111, 104)) #define EMMC_CSD_TRAN_SPEED() (EMMC_GET_CSD(103, 96)) #define EMMC_CSD_CCC() (EMMC_GET_CSD(95, 84)) #define EMMC_CSD_READ_BL_LEN() (EMMC_GET_CSD(83, 80)) #define EMMC_CSD_READ_BL_PARTIAL() (EMMC_GET_CSD(79, 79)) #define EMMC_CSD_WRITE_BLK_MISALIGN() (EMMC_GET_CSD(78, 78)) #define EMMC_CSD_READ_BLK_MISALIGN() (EMMC_GET_CSD(77, 77)) #define EMMC_CSD_DSR_IMP() (EMMC_GET_CSD(76, 76)) #define EMMC_CSD_C_SIZE() (EMMC_GET_CSD(73, 62)) #define EMMC_CSD_VDD_R_CURR_MIN() (EMMC_GET_CSD(61, 59)) #define EMMC_CSD_VDD_R_CURR_MAX() (EMMC_GET_CSD(58, 56)) #define EMMC_CSD_VDD_W_CURR_MIN() (EMMC_GET_CSD(55, 53)) #define EMMC_CSD_VDD_W_CURR_MAX() (EMMC_GET_CSD(52, 50)) #define EMMC_CSD_C_SIZE_MULT() (EMMC_GET_CSD(49, 47)) #define EMMC_CSD_ERASE_GRP_SIZE() (EMMC_GET_CSD(46, 42)) #define EMMC_CSD_ERASE_GRP_MULT() (EMMC_GET_CSD(41, 37)) #define EMMC_CSD_WP_GRP_SIZE() (EMMC_GET_CSD(36, 32)) #define EMMC_CSD_WP_GRP_ENABLE() (EMMC_GET_CSD(31, 31)) #define EMMC_CSD_DEFALT_ECC() (EMMC_GET_CSD(30, 29)) #define EMMC_CSD_R2W_FACTOR() (EMMC_GET_CSD(28, 26)) #define EMMC_CSD_WRITE_BL_LEN() (EMMC_GET_CSD(25, 22)) #define EMMC_CSD_WRITE_BL_PARTIAL() (EMMC_GET_CSD(21, 21)) #define EMMC_CSD_CONTENT_PROT_APP() (EMMC_GET_CSD(16, 16)) #define EMMC_CSD_FILE_FORMAT_GRP() (EMMC_GET_CSD(15, 15)) #define EMMC_CSD_COPY() (EMMC_GET_CSD(14, 14)) #define EMMC_CSD_PERM_WRITE_PROTECT() (EMMC_GET_CSD(13, 13)) #define EMMC_CSD_TMP_WRITE_PROTECT() (EMMC_GET_CSD(12, 12)) #define EMMC_CSD_FILE_FORMAT() (EMMC_GET_CSD(11, 10)) #define EMMC_CSD_ECC() (EMMC_GET_CSD(9, 8)) #define EMMC_CSD_CRC() (EMMC_GET_CSD(7, 1)) /** @brief for sector access */ #define EMMC_4B_BOUNDARY_CHECK_MASK 0x00000003 #define EMMC_SECTOR_SIZE_SHIFT 9U /* 512 = 2^9 */ #define EMMC_SECTOR_SIZE 512 #define EMMC_BLOCK_LENGTH 512 #define EMMC_BLOCK_LENGTH_DW 128 #define EMMC_BUF_SIZE_SHIFT 3U /* 8byte = 2^3 */ /** @brief eMMC specification clock */ #define EMMC_CLOCK_SPEC_400K 400000UL /**< initialize clock 400KHz */ #define EMMC_CLOCK_SPEC_20M 20000000UL /**< normal speed 20MHz */ #define EMMC_CLOCK_SPEC_26M 26000000UL /**< high speed 26MHz */ #define EMMC_CLOCK_SPEC_52M 52000000UL /**< high speed 52MHz */ #define EMMC_CLOCK_SPEC_100M 100000000UL /**< high speed 100MHz */ /** @brief EMMC driver error code. (extended HAL_MEMCARD_RETURN) */ typedef enum { EMMC_ERR = 0, /**< unknown error */ EMMC_SUCCESS, /**< OK */ EMMC_ERR_FROM_DMAC, /**< DMAC allocation error */ EMMC_ERR_FROM_DMAC_TRANSFER, /**< DMAC transfer error */ EMMC_ERR_CARD_STATUS_BIT, /**< card status error. Non-masked error bit was set in the card status */ EMMC_ERR_CMD_TIMEOUT, /**< command timeout error */ EMMC_ERR_DATA_TIMEOUT, /**< data timeout error */ EMMC_ERR_CMD_CRC, /**< command CRC error */ EMMC_ERR_DATA_CRC, /**< data CRC error */ EMMC_ERR_PARAM, /**< parameter error */ EMMC_ERR_RESPONSE, /**< response error */ EMMC_ERR_RESPONSE_BUSY, /**< response busy error */ EMMC_ERR_TRANSFER, /**< data transfer error */ EMMC_ERR_READ_SECTOR, /**< read sector error */ EMMC_ERR_WRITE_SECTOR, /**< write sector error */ EMMC_ERR_STATE, /**< state error */ EMMC_ERR_TIMEOUT, /**< timeout error */ EMMC_ERR_ILLEGAL_CARD, /**< illegal card */ EMMC_ERR_CARD_BUSY, /**< Busy state */ EMMC_ERR_CARD_STATE, /**< card state error */ EMMC_ERR_SET_TRACE, /**< trace information error */ EMMC_ERR_FROM_TIMER, /**< Timer error */ EMMC_ERR_FORCE_TERMINATE, /**< Force terminate */ EMMC_ERR_CARD_POWER, /**< card power fail */ EMMC_ERR_ERASE_SECTOR, /**< erase sector error */ EMMC_ERR_INFO2 /**< exec cmd error info2 */ } EMMC_ERROR_CODE; /** @brief Function number */ #define EMMC_FUNCNO_NONE 0U #define EMMC_FUNCNO_DRIVER_INIT 1U #define EMMC_FUNCNO_CARD_POWER_ON 2U #define EMMC_FUNCNO_MOUNT 3U #define EMMC_FUNCNO_CARD_INIT 4U #define EMMC_FUNCNO_HIGH_SPEED 5U #define EMMC_FUNCNO_BUS_WIDTH 6U #define EMMC_FUNCNO_MULTI_BOOT_SELECT_PARTITION 7U #define EMMC_FUNCNO_MULTI_BOOT_READ_SECTOR 8U #define EMMC_FUNCNO_TRANS_DATA_READ_SECTOR 9U #define EMMC_FUNCNO_UBOOT_IMAGE_SELECT_PARTITION 10U #define EMMC_FUNCNO_UBOOT_IMAGE_READ_SECTOR 11U #define EMMC_FUNCNO_SET_CLOCK 12U #define EMMC_FUNCNO_EXEC_CMD 13U #define EMMC_FUNCNO_READ_SECTOR 14U #define EMMC_FUNCNO_WRITE_SECTOR 15U #define EMMC_FUNCNO_ERASE_SECTOR 16U #define EMMC_FUNCNO_GET_PERTITION_ACCESS 17U /** @brief Response */ /** R1 */ #define EMMC_R1_ERROR_MASK 0xFDBFE080U /* Type 'E' bit and bit14(must be 0). ignore bit22 */ #define EMMC_R1_ERROR_MASK_WITHOUT_CRC (0xFD3FE080U) /* Ignore bit23 (Not check CRC error) */ #define EMMC_R1_STATE_MASK 0x00001E00U /* [12:9] */ #define EMMC_R1_READY 0x00000100U /* bit8 */ #define EMMC_R1_STATE_SHIFT 9 /** R4 */ #define EMMC_R4_RCA_MASK 0xFFFF0000UL #define EMMC_R4_STATUS 0x00008000UL /** CSD */ #define EMMC_TRANSPEED_FREQ_UNIT_MASK 0x07 /* bit[2:0] */ #define EMMC_TRANSPEED_FREQ_UNIT_SHIFT 0 #define EMMC_TRANSPEED_MULT_MASK 0x78 /* bit[6:3] */ #define EMMC_TRANSPEED_MULT_SHIFT 3 /** OCR */ #define EMMC_HOST_OCR_VALUE 0x40FF8080 #define EMMC_OCR_STATUS_BIT 0x80000000L /* Card power up status bit */ #define EMMC_OCR_ACCESS_MODE_MASK 0x60000000L /* bit[30:29] */ #define EMMC_OCR_ACCESS_MODE_SECT 0x40000000L #define EMMC_OCR_ACCESS_MODE_BYTE 0x00000000L /** EXT_CSD */ #define EMMC_EXT_CSD_S_CMD_SET 504 #define EMMC_EXT_CSD_INI_TIMEOUT_AP 241 #define EMMC_EXT_CSD_PWR_CL_DDR_52_360 239 #define EMMC_EXT_CSD_PWR_CL_DDR_52_195 238 #define EMMC_EXT_CSD_MIN_PERF_DDR_W_8_52 235 #define EMMC_EXT_CSD_MIN_PERF_DDR_R_8_52 234 #define EMMC_EXT_CSD_TRIM_MULT 232 #define EMMC_EXT_CSD_SEC_FEATURE_SUPPORT 231 #define EMMC_EXT_CSD_SEC_ERASE_MULT 229 #define EMMC_EXT_CSD_BOOT_INFO 228 #define EMMC_EXT_CSD_BOOT_SIZE_MULTI 226 #define EMMC_EXT_CSD_ACC_SIZE 225 #define EMMC_EXT_CSD_HC_ERASE_GRP_SIZE 224 #define EMMC_EXT_CSD_ERASE_TIMEOUT_MULT 223 #define EMMC_EXT_CSD_PEL_WR_SEC_C 222 #define EMMC_EXT_CSD_HC_WP_GRP_SIZE 221 #define EMMC_EXT_CSD_S_C_VCC 220 #define EMMC_EXT_CSD_S_C_VCCQ 219 #define EMMC_EXT_CSD_S_A_TIMEOUT 217 #define EMMC_EXT_CSD_SEC_COUNT 215 #define EMMC_EXT_CSD_MIN_PERF_W_8_52 210 #define EMMC_EXT_CSD_MIN_PERF_R_8_52 209 #define EMMC_EXT_CSD_MIN_PERF_W_8_26_4_52 208 #define EMMC_EXT_CSD_MIN_PERF_R_8_26_4_52 207 #define EMMC_EXT_CSD_MIN_PERF_W_4_26 206 #define EMMC_EXT_CSD_MIN_PERF_R_4_26 205 #define EMMC_EXT_CSD_PWR_CL_26_360 203 #define EMMC_EXT_CSD_PWR_CL_52_360 202 #define EMMC_EXT_CSD_PWR_CL_26_195 201 #define EMMC_EXT_CSD_PWR_CL_52_195 200 #define EMMC_EXT_CSD_CARD_TYPE 196 #define EMMC_EXT_CSD_CSD_STRUCTURE 194 #define EMMC_EXT_CSD_EXT_CSD_REV 192 #define EMMC_EXT_CSD_CMD_SET 191 #define EMMC_EXT_CSD_CMD_SET_REV 189 #define EMMC_EXT_CSD_POWER_CLASS 187 #define EMMC_EXT_CSD_HS_TIMING 185 #define EMMC_EXT_CSD_BUS_WIDTH 183 #define EMMC_EXT_CSD_ERASED_MEM_CONT 181 #define EMMC_EXT_CSD_PARTITION_CONFIG 179 #define EMMC_EXT_CSD_BOOT_CONFIG_PROT 178 #define EMMC_EXT_CSD_BOOT_BUS_WIDTH 177 #define EMMC_EXT_CSD_ERASE_GROUP_DEF 175 #define EMMC_EXT_CSD_BOOT_WP 173 #define EMMC_EXT_CSD_USER_WP 171 #define EMMC_EXT_CSD_FW_CONFIG 169 #define EMMC_EXT_CSD_RPMB_SIZE_MULT 168 #define EMMC_EXT_CSD_RST_n_FUNCTION 162 #define EMMC_EXT_CSD_PARTITIONING_SUPPORT 160 #define EMMC_EXT_CSD_MAX_ENH_SIZE_MULT 159 #define EMMC_EXT_CSD_PARTITIONS_ATTRIBUTE 156 #define EMMC_EXT_CSD_PARTITION_SETTING_COMPLETED 155 #define EMMC_EXT_CSD_GP_SIZE_MULT 154 #define EMMC_EXT_CSD_ENH_SIZE_MULT 142 #define EMMC_EXT_CSD_ENH_START_ADDR 139 #define EMMC_EXT_CSD_SEC_BAD_BLK_MGMNT 134 #define EMMC_EXT_CSD_CARD_TYPE_26MHZ 0x01 #define EMMC_EXT_CSD_CARD_TYPE_52MHZ 0x02 #define EMMC_EXT_CSD_CARD_TYPE_DDR_52MHZ_12V 0x04 #define EMMC_EXT_CSD_CARD_TYPE_DDR_52MHZ_18V 0x08 #define EMMC_EXT_CSD_CARD_TYPE_52MHZ_MASK 0x0e /** SWITCH (CMD6) argument */ #define EXTCSD_ACCESS_BYTE (BIT25|BIT24) #define EXTCSD_SET_BITS BIT24 #define HS_TIMING_ADD (185<<16) /* H'b9 */ #define HS_TIMING_1 (1<<8) #define HS_TIMING_HS200 (2<<8) #define HS_TIMING_HS400 (3<<8) #define BUS_WIDTH_ADD (183<<16) /* H'b7 */ #define BUS_WIDTH_1 (0<<8) #define BUS_WIDTH_4 (1<<8) #define BUS_WIDTH_8 (2<<8) #define BUS_WIDTH_4DDR (5<<8) #define BUS_WIDTH_8DDR (6<<8) #define EMMC_SWITCH_HS_TIMING (EXTCSD_ACCESS_BYTE|HS_TIMING_ADD|HS_TIMING_1) /**< H'03b90100 */ #define EMMC_SWITCH_HS_TIMING_OFF (EXTCSD_ACCESS_BYTE|HS_TIMING_ADD) /**< H'03b90000 */ #define EMMC_SWITCH_BUS_WIDTH_1 (EXTCSD_ACCESS_BYTE|BUS_WIDTH_ADD|BUS_WIDTH_1) /**< H'03b70000 */ #define EMMC_SWITCH_BUS_WIDTH_4 (EXTCSD_ACCESS_BYTE|BUS_WIDTH_ADD|BUS_WIDTH_4) /**< H'03b70100 */ #define EMMC_SWITCH_BUS_WIDTH_8 (EXTCSD_ACCESS_BYTE|BUS_WIDTH_ADD|BUS_WIDTH_8) /**< H'03b70200 */ #define EMMC_SWITCH_BUS_WIDTH_4DDR (EXTCSD_ACCESS_BYTE|BUS_WIDTH_ADD|BUS_WIDTH_4DDR) /**< H'03b70500 */ #define EMMC_SWITCH_BUS_WIDTH_8DDR (EXTCSD_ACCESS_BYTE|BUS_WIDTH_ADD|BUS_WIDTH_8DDR) /**< H'03b70600 */ #define EMMC_SWITCH_PARTITION_CONFIG 0x03B30000UL /**< Partition config = 0x00 */ #define TIMING_HIGH_SPEED 1UL #define EMMC_BOOT_PARTITION_EN_MASK 0x38U #define EMMC_BOOT_PARTITION_EN_SHIFT 3U /** Bus width */ #define EMMC_BUSWIDTH_1BIT CE_CMD_SET_DATW_1BIT #define EMMC_BUSWIDTH_4BIT CE_CMD_SET_DATW_4BIT #define EMMC_BUSWIDTH_8BIT CE_CMD_SET_DATW_8BIT /** for st_mmc_base */ #define EMMC_MAX_RESPONSE_LENGTH 17 #define EMMC_MAX_CID_LENGTH 16 #define EMMC_MAX_CSD_LENGTH 16 #define EMMC_MAX_EXT_CSD_LENGTH 512U #define EMMC_RES_REG_ALIGNED 4U #define EMMC_BUF_REG_ALIGNED 8U /** @brief for TAAC mask */ #define TAAC_TIME_UNIT_MASK (0x07) #define TAAC_MULTIPLIER_FACTOR_MASK (0x0F) /* ********************** STRUCTURES, TYPE DEFINITIONS ********************* */ /** @brief Partition id */ typedef enum { PARTITION_ID_USER = 0x0, /**< User Area */ PARTITION_ID_BOOT_1 = 0x1, /**< boot partition 1 */ PARTITION_ID_BOOT_2 = 0x2, /**< boot partition 2 */ PARTITION_ID_RPMB = 0x3, /**< Replay Protected Memory Block */ PARTITION_ID_GP_1 = 0x4, /**< General Purpose partition 1 */ PARTITION_ID_GP_2 = 0x5, /**< General Purpose partition 2 */ PARTITION_ID_GP_3 = 0x6, /**< General Purpose partition 3 */ PARTITION_ID_GP_4 = 0x7, /**< General Purpose partition 4 */ PARTITION_ID_MASK = 0x7 /**< [2:0] */ } EMMC_PARTITION_ID; /** @brief card state in R1 response [12:9] */ typedef enum { EMMC_R1_STATE_IDLE = 0, EMMC_R1_STATE_READY, EMMC_R1_STATE_IDENT, EMMC_R1_STATE_STBY, EMMC_R1_STATE_TRAN, EMMC_R1_STATE_DATA, EMMC_R1_STATE_RCV, EMMC_R1_STATE_PRG, EMMC_R1_STATE_DIS, EMMC_R1_STATE_BTST, EMMC_R1_STATE_SLEP } EMMC_R1_STATE; typedef enum { ESTATE_BEGIN = 0, ESTATE_ISSUE_CMD, ESTATE_NON_RESP_CMD, ESTATE_RCV_RESP, ESTATE_RCV_RESPONSE_BUSY, ESTATE_CHECK_RESPONSE_COMPLETE, ESTATE_DATA_TRANSFER, ESTATE_DATA_TRANSFER_COMPLETE, ESTATE_ACCESS_END, ESTATE_TRANSFER_ERROR, ESTATE_ERROR, ESTATE_END } EMMC_INT_STATE; /** @brief eMMC boot driver error information */ typedef struct { uint16_t num; /**< error no */ uint16_t code; /**< error code */ volatile uint32_t info1; /**< SD_INFO1 register value. (hardware dependence) */ volatile uint32_t info2; /**< SD_INFO2 register value. (hardware dependence) */ volatile uint32_t status1;/**< SD_ERR_STS1 register value. (hardware dependence) */ volatile uint32_t status2;/**< SD_ERR_STS2 register value. (hardware dependence) */ volatile uint32_t dm_info1;/**< DM_CM_INFO1 register value. (hardware dependence) */ volatile uint32_t dm_info2;/**< DM_CM_INFO2 register value. (hardware dependence) */ } st_error_info; /** @brief Command information */ typedef struct { HAL_MEMCARD_COMMAND cmd; /**< Command information */ uint32_t arg; /**< argument */ HAL_MEMCARD_OPERATION dir; /**< direction */ uint32_t hw; /**< H/W dependence. SD_CMD register value. */ } st_command_info; /** @brief MMC driver base */ typedef struct { st_error_info error_info; /**< error information */ st_command_info cmd_info; /**< command information */ /* for data transfer */ uint32_t *buff_address_virtual; /**< Dest or Src buff */ uint32_t *buff_address_physical; /**< Dest or Src buff */ HAL_MEMCARD_DATA_WIDTH bus_width; /**< bus width */ uint32_t trans_size; /**< transfer size for this command */ uint32_t remain_size; /**< remain size for this command */ uint32_t response_length; /**< response length for this command */ uint32_t sector_size; /**< sector_size */ /* clock */ uint32_t base_clock; /**< MMC host controller clock */ uint32_t max_freq; /**< Max frequency (Card Spec)[Hz]. It changes dynamically by CSD and EXT_CSD. */ uint32_t request_freq; /**< request freq [Hz] (400K, 26MHz, 52MHz, etc) */ uint32_t current_freq; /**< current MMC clock[Hz] (the closest frequency supported by HW) */ /* state flag */ HAL_MEMCARD_PRESENCE_STATUS card_present; /**< presence status of the memory card */ uint32_t card_power_enable; /**< True : Power ON */ uint32_t clock_enable; /**< True : Clock ON */ uint32_t initialize; /**< True : initialize complete. */ uint32_t access_mode; /**< True : sector access, FALSE : byte access */ uint32_t mount; /**< True : mount complete. */ uint32_t selected; /**< True : selected card. */ HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode; /**< 0: DMA, 1:PIO */ uint32_t image_num; /**< loaded ISSW image No. ISSW have copy image. */ EMMC_R1_STATE current_state; /**< card state */ volatile uint32_t during_cmd_processing; /**< True : during command processing */ volatile uint32_t during_transfer; /**< True : during transfer */ volatile uint32_t during_dma_transfer; /**< True : during transfer (DMA)*/ volatile uint32_t dma_error_flag; /**< True : occurred DMAC error */ volatile uint32_t force_terminate; /**< force terminate flag */ volatile uint32_t state_machine_blocking; /**< state machine blocking flag : True or False */ volatile uint32_t get_partition_access_flag; /**< True : get partition access processing */ EMMC_PARTITION_ID boot_partition_en; /**< Boot partition */ EMMC_PARTITION_ID partition_access; /**< Current access partition */ /* timeout */ uint32_t hs_timing; /**< high speed */ /* timeout */ uint32_t data_timeout; /**< read and write data timeout.*/ /* retry */ uint32_t retries_after_fail; /**< how many times to try after fail, for instance sending command */ /* interrupt */ volatile uint32_t int_event1; /**< interrupt SD_INFO1 Event */ volatile uint32_t int_event2; /**< interrupt SD_INFO2 Event */ volatile uint32_t dm_event1; /**< interrupt DM_CM_INFO1 Event */ volatile uint32_t dm_event2; /**< interrupt DM_CM_INFO2 Event */ /* response */ uint32_t *response; /**< pointer to buffer for executing command. */ uint32_t r1_card_status; /**< R1 response data */ uint32_t r3_ocr; /**< R3 response data */ uint32_t r4_resp; /**< R4 response data */ uint32_t r5_resp; /**< R5 response data */ uint32_t low_clock_mode_enable; /**< True : clock mode is low. (MMC clock = Max26MHz) */ uint32_t reserved2; uint32_t reserved3; uint32_t reserved4; /* CSD registers (4byte align) */ uint8_t csd_data[EMMC_MAX_CSD_LENGTH] /**< CSD */ __attribute__ ((aligned(EMMC_RES_REG_ALIGNED))); /* CID registers (4byte align) */ uint8_t cid_data[EMMC_MAX_CID_LENGTH] /**< CID */ __attribute__ ((aligned(EMMC_RES_REG_ALIGNED))); /* EXT CSD registers (8byte align) */ uint8_t ext_csd_data[EMMC_MAX_EXT_CSD_LENGTH] /**< EXT_CSD */ __attribute__ ((aligned(EMMC_BUF_REG_ALIGNED))); /* Response registers (4byte align) */ uint8_t response_data[EMMC_MAX_RESPONSE_LENGTH] /**< other response */ __attribute__ ((aligned(EMMC_RES_REG_ALIGNED))); } st_mmc_base; typedef int (*func) (void); /* ********************** DECLARATION OF EXTERNAL DATA ********************* */ /* ************************** FUNCTION PROTOTYPES ************************** */ uint32_t emmc_get_csd_time(void); #define MMC_DEBUG /* ********************************* CODE ********************************** */ /* ******************************** END ************************************ */ #endif /* EMMC_STD_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/emmc/emmc_utility.c000066400000000000000000000134151355360272700247530ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "emmc_config.h" #include "emmc_hal.h" #include "emmc_std.h" #include "emmc_registers.h" #include "emmc_def.h" static const uint32_t cmd_reg_hw[EMMC_CMD_MAX + 1] = { 0x00000000, /* CMD0 */ 0x00000701, /* CMD1 */ 0x00000002, /* CMD2 */ 0x00000003, /* CMD3 */ 0x00000004, /* CMD4 */ 0x00000505, /* CMD5 */ 0x00000406, /* CMD6 */ 0x00000007, /* CMD7 */ 0x00001C08, /* CMD8 */ 0x00000009, /* CMD9 */ 0x0000000A, /* CMD10 */ 0x00000000, /* reserved */ 0x0000000C, /* CMD12 */ 0x0000000D, /* CMD13 */ 0x00001C0E, /* CMD14 */ 0x0000000F, /* CMD15 */ 0x00000010, /* CMD16 */ 0x00000011, /* CMD17 */ 0x00007C12, /* CMD18 */ 0x00000C13, /* CMD19 */ 0x00000000, 0x00001C15, /* CMD21 */ 0x00000000, 0x00000017, /* CMD23 */ 0x00000018, /* CMD24 */ 0x00006C19, /* CMD25 */ 0x00000C1A, /* CMD26 */ 0x0000001B, /* CMD27 */ 0x0000001C, /* CMD28 */ 0x0000001D, /* CMD29 */ 0x0000001E, /* CMD30 */ 0x00001C1F, /* CMD31 */ 0x00000000, 0x00000000, 0x00000000, 0x00000423, /* CMD35 */ 0x00000424, /* CMD36 */ 0x00000000, 0x00000026, /* CMD38 */ 0x00000427, /* CMD39 */ 0x00000428, /* CMD40(send cmd) */ 0x00000000, 0x0000002A, /* CMD42 */ 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000C31, 0x00000000, 0x00000000, 0x00000000, 0x00007C35, 0x00006C36, 0x00000037, /* CMD55 */ 0x00000038, /* CMD56(Read) */ 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; uint32_t emmc_bit_field(uint8_t *data, uint32_t top, uint32_t bottom) { uint32_t value; uint32_t index_top = (uint32_t) (15 - (top >> 3)); uint32_t index_bottom = (uint32_t) (15 - (bottom >> 3)); if (index_top == index_bottom) { value = data[index_top]; } else if ((index_top + 1) == index_bottom) { value = (uint32_t) ((data[index_top] << 8) | data[index_bottom]); } else if ((index_top + 2) == index_bottom) { value = (uint32_t) ((data[index_top] << 16) | (data[index_top + 1] << 8) | data[index_top + 2]); } else { value = (uint32_t) ((data[index_top] << 24) | (data[index_top + 1] << 16) | (data[index_top + 2] << 8) | data[index_top + 3]); } value = ((value >> (bottom & 0x07)) & ((1 << (top - bottom + 1)) - 1)); return value; } void emmc_write_error_info(uint16_t func_no, EMMC_ERROR_CODE error_code) { mmc_drv_obj.error_info.num = func_no; mmc_drv_obj.error_info.code = (uint16_t) error_code; ERROR("BL2: emmc err:func_no=0x%x code=0x%x\n", func_no, error_code); } void emmc_write_error_info_func_no(uint16_t func_no) { mmc_drv_obj.error_info.num = func_no; ERROR("BL2: emmc err:func_no=0x%x\n", func_no); } void emmc_make_nontrans_cmd(HAL_MEMCARD_COMMAND cmd, uint32_t arg) { /* command information */ mmc_drv_obj.cmd_info.cmd = cmd; mmc_drv_obj.cmd_info.arg = arg; mmc_drv_obj.cmd_info.dir = HAL_MEMCARD_READ; mmc_drv_obj.cmd_info.hw = cmd_reg_hw[cmd & HAL_MEMCARD_COMMAND_INDEX_MASK]; /* clear data transfer information */ mmc_drv_obj.trans_size = 0; mmc_drv_obj.remain_size = 0; mmc_drv_obj.buff_address_virtual = NULL; mmc_drv_obj.buff_address_physical = NULL; /* response information */ mmc_drv_obj.response_length = 6; switch (mmc_drv_obj.cmd_info.cmd & HAL_MEMCARD_RESPONSE_TYPE_MASK) { case HAL_MEMCARD_RESPONSE_NONE: mmc_drv_obj.response = (uint32_t *) mmc_drv_obj.response_data; mmc_drv_obj.response_length = 0; break; case HAL_MEMCARD_RESPONSE_R1: mmc_drv_obj.response = &mmc_drv_obj.r1_card_status; break; case HAL_MEMCARD_RESPONSE_R1b: mmc_drv_obj.cmd_info.hw |= BIT10; /* bit10 = R1 busy bit */ mmc_drv_obj.response = &mmc_drv_obj.r1_card_status; break; case HAL_MEMCARD_RESPONSE_R2: mmc_drv_obj.response = (uint32_t *) mmc_drv_obj.response_data; mmc_drv_obj.response_length = 17; break; case HAL_MEMCARD_RESPONSE_R3: mmc_drv_obj.response = &mmc_drv_obj.r3_ocr; break; case HAL_MEMCARD_RESPONSE_R4: mmc_drv_obj.response = &mmc_drv_obj.r4_resp; break; case HAL_MEMCARD_RESPONSE_R5: mmc_drv_obj.response = &mmc_drv_obj.r5_resp; break; default: mmc_drv_obj.response = (uint32_t *) mmc_drv_obj.response_data; break; } } void emmc_make_trans_cmd(HAL_MEMCARD_COMMAND cmd, uint32_t arg, uint32_t *buff_address_virtual, uint32_t len, HAL_MEMCARD_OPERATION dir, HAL_MEMCARD_DATA_TRANSFER_MODE transfer_mode) { emmc_make_nontrans_cmd(cmd, arg); /* update common information */ /* for data transfer command */ mmc_drv_obj.cmd_info.dir = dir; mmc_drv_obj.buff_address_virtual = buff_address_virtual; mmc_drv_obj.buff_address_physical = buff_address_virtual; mmc_drv_obj.trans_size = len; mmc_drv_obj.remain_size = len; mmc_drv_obj.transfer_mode = transfer_mode; } EMMC_ERROR_CODE emmc_send_idle_cmd(uint32_t arg) { EMMC_ERROR_CODE result; uint32_t freq; /* initialize state */ mmc_drv_obj.mount = FALSE; mmc_drv_obj.selected = FALSE; mmc_drv_obj.during_transfer = FALSE; mmc_drv_obj.during_cmd_processing = FALSE; mmc_drv_obj.during_dma_transfer = FALSE; mmc_drv_obj.dma_error_flag = FALSE; mmc_drv_obj.force_terminate = FALSE; mmc_drv_obj.state_machine_blocking = FALSE; mmc_drv_obj.bus_width = HAL_MEMCARD_DATA_WIDTH_1_BIT; mmc_drv_obj.max_freq = MMC_20MHZ; /* 20MHz */ mmc_drv_obj.current_state = EMMC_R1_STATE_IDLE; /* CMD0 (MMC clock is current frequency. if Data transfer mode, 20MHz or higher.) */ emmc_make_nontrans_cmd(CMD0_GO_IDLE_STATE, arg); /* CMD0 */ result = emmc_exec_cmd(EMMC_R1_ERROR_MASK, mmc_drv_obj.response); if (result != EMMC_SUCCESS) { return result; } /* change MMC clock(400KHz) */ freq = MMC_400KHZ; result = emmc_set_request_mmc_clock(&freq); if (result != EMMC_SUCCESS) { return result; } return EMMC_SUCCESS; } trusted-firmware-a-2.2/drivers/renesas/rcar/iic_dvfs/000077500000000000000000000000001355360272700227445ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/iic_dvfs/iic_dvfs.c000066400000000000000000000323731355360272700247060ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "rcar_def.h" #include "cpg_registers.h" #include "iic_dvfs.h" #include "rcar_private.h" #define DVFS_RETRY_MAX (2U) #define IIC_DVFS_SET_ICCL_EXTAL_TYPE_0 (0x07) #define IIC_DVFS_SET_ICCL_EXTAL_TYPE_1 (0x09) #define IIC_DVFS_SET_ICCL_EXTAL_TYPE_2 (0x0B) #define IIC_DVFS_SET_ICCL_EXTAL_TYPE_3 (0x0E) #define IIC_DVFS_SET_ICCL_EXTAL_TYPE_E (0x15) #define IIC_DVFS_SET_ICCH_EXTAL_TYPE_0 (0x01) #define IIC_DVFS_SET_ICCH_EXTAL_TYPE_1 (0x02) #define IIC_DVFS_SET_ICCH_EXTAL_TYPE_2 (0x03) #define IIC_DVFS_SET_ICCH_EXTAL_TYPE_3 (0x05) #define IIC_DVFS_SET_ICCH_EXTAL_TYPE_E (0x07) #define CPG_BIT_SMSTPCR9_DVFS (0x04000000) #define IIC_DVFS_REG_BASE (0xE60B0000) #define IIC_DVFS_REG_ICDR (IIC_DVFS_REG_BASE + 0x0000) #define IIC_DVFS_REG_ICCR (IIC_DVFS_REG_BASE + 0x0004) #define IIC_DVFS_REG_ICSR (IIC_DVFS_REG_BASE + 0x0008) #define IIC_DVFS_REG_ICIC (IIC_DVFS_REG_BASE + 0x000C) #define IIC_DVFS_REG_ICCL (IIC_DVFS_REG_BASE + 0x0010) #define IIC_DVFS_REG_ICCH (IIC_DVFS_REG_BASE + 0x0014) #define IIC_DVFS_BIT_ICSR_BUSY (0x10) #define IIC_DVFS_BIT_ICSR_AL (0x08) #define IIC_DVFS_BIT_ICSR_TACK (0x04) #define IIC_DVFS_BIT_ICSR_WAIT (0x02) #define IIC_DVFS_BIT_ICSR_DTE (0x01) #define IIC_DVFS_BIT_ICCR_ENABLE (0x80) #define IIC_DVFS_SET_ICCR_START (0x94) #define IIC_DVFS_SET_ICCR_STOP (0x90) #define IIC_DVFS_SET_ICCR_RETRANSMISSION (0x94) #define IIC_DVFS_SET_ICCR_CHANGE (0x81) #define IIC_DVFS_SET_ICCR_STOP_READ (0xC0) #define IIC_DVFS_BIT_ICIC_TACKE (0x04) #define IIC_DVFS_BIT_ICIC_WAITE (0x02) #define IIC_DVFS_BIT_ICIC_DTEE (0x01) #define DVFS_READ_MODE (0x01) #define DVFS_WRITE_MODE (0x00) #define IIC_DVFS_SET_DUMMY (0x52) #define IIC_DVFS_SET_BUSY_LOOP (500000000U) typedef enum { DVFS_START = 0, DVFS_STOP, DVFS_RETRANSMIT, DVFS_READ, DVFS_STOP_READ, DVFS_SET_SLAVE_READ, DVFS_SET_SLAVE, DVFS_WRITE_ADDR, DVFS_WRITE_DATA, DVFS_CHANGE_SEND_TO_RECIEVE, DVFS_DONE, } DVFS_STATE_T; #define DVFS_PROCESS (1) #define DVFS_COMPLETE (0) #define DVFS_ERROR (-1) #if IMAGE_BL31 #define IIC_DVFS_FUNC(__name, ...) \ static int32_t __attribute__ ((section (".system_ram"))) \ dvfs_ ##__name(__VA_ARGS__) #define RCAR_DVFS_API(__name, ...) \ int32_t __attribute__ ((section (".system_ram"))) \ rcar_iic_dvfs_ ##__name(__VA_ARGS__) #else #define IIC_DVFS_FUNC(__name, ...) \ static int32_t dvfs_ ##__name(__VA_ARGS__) #define RCAR_DVFS_API(__name, ...) \ int32_t rcar_iic_dvfs_ ##__name(__VA_ARGS__) #endif IIC_DVFS_FUNC(check_error, DVFS_STATE_T *state, uint32_t *err, uint8_t mode) { uint8_t icsr_al = 0, icsr_tack = 0; uint8_t reg, stop; uint32_t i = 0; stop = mode == DVFS_READ_MODE ? IIC_DVFS_SET_ICCR_STOP_READ : IIC_DVFS_SET_ICCR_STOP; reg = mmio_read_8(IIC_DVFS_REG_ICSR); icsr_al = (reg & IIC_DVFS_BIT_ICSR_AL) == IIC_DVFS_BIT_ICSR_AL; icsr_tack = (reg & IIC_DVFS_BIT_ICSR_TACK) == IIC_DVFS_BIT_ICSR_TACK; if (icsr_al == 0 && icsr_tack == 0) return DVFS_PROCESS; if (icsr_al) { reg = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_AL; mmio_write_8(IIC_DVFS_REG_ICSR, reg); if (*state == DVFS_SET_SLAVE) mmio_write_8(IIC_DVFS_REG_ICDR, IIC_DVFS_SET_DUMMY); do { reg = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT; } while (reg == 0); mmio_write_8(IIC_DVFS_REG_ICCR, stop); reg = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT; mmio_write_8(IIC_DVFS_REG_ICSR, reg); i = 0; do { reg = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_BUSY; if (reg == 0) break; if (i++ > IIC_DVFS_SET_BUSY_LOOP) panic(); } while (1); mmio_write_8(IIC_DVFS_REG_ICCR, 0x00U); (*err)++; if (*err > DVFS_RETRY_MAX) return DVFS_ERROR; *state = DVFS_START; return DVFS_PROCESS; } /* icsr_tack */ mmio_write_8(IIC_DVFS_REG_ICCR, stop); reg = mmio_read_8(IIC_DVFS_REG_ICIC); reg &= ~(IIC_DVFS_BIT_ICIC_WAITE | IIC_DVFS_BIT_ICIC_DTEE); mmio_write_8(IIC_DVFS_REG_ICIC, reg); reg = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_TACK; mmio_write_8(IIC_DVFS_REG_ICSR, reg); i = 0; while ((mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_BUSY) != 0) { if (i++ > IIC_DVFS_SET_BUSY_LOOP) panic(); } mmio_write_8(IIC_DVFS_REG_ICCR, 0); (*err)++; if (*err > DVFS_RETRY_MAX) return DVFS_ERROR; *state = DVFS_START; return DVFS_PROCESS; } IIC_DVFS_FUNC(start, DVFS_STATE_T * state) { uint8_t iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_E; uint8_t icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_E; int32_t result = DVFS_PROCESS; uint32_t reg, lsi_product; uint8_t mode; mode = mmio_read_8(IIC_DVFS_REG_ICCR) | IIC_DVFS_BIT_ICCR_ENABLE; mmio_write_8(IIC_DVFS_REG_ICCR, mode); lsi_product = mmio_read_32(RCAR_PRR) & PRR_PRODUCT_MASK; if (lsi_product == PRR_PRODUCT_E3) goto start; reg = mmio_read_32(RCAR_MODEMR) & CHECK_MD13_MD14; switch (reg) { case MD14_MD13_TYPE_0: iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_0; icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_0; break; case MD14_MD13_TYPE_1: iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_1; icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_1; break; case MD14_MD13_TYPE_2: iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_2; icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_2; break; default: iccl = IIC_DVFS_SET_ICCL_EXTAL_TYPE_3; icch = IIC_DVFS_SET_ICCH_EXTAL_TYPE_3; break; } start: mmio_write_8(IIC_DVFS_REG_ICCL, iccl); mmio_write_8(IIC_DVFS_REG_ICCH, icch); mode = mmio_read_8(IIC_DVFS_REG_ICIC) | IIC_DVFS_BIT_ICIC_TACKE | IIC_DVFS_BIT_ICIC_WAITE | IIC_DVFS_BIT_ICIC_DTEE; mmio_write_8(IIC_DVFS_REG_ICIC, mode); mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_START); *state = DVFS_SET_SLAVE; return result; } IIC_DVFS_FUNC(set_slave, DVFS_STATE_T * state, uint32_t *err, uint8_t slave) { uint8_t mode; int32_t result; uint8_t address; result = dvfs_check_error(state, err, DVFS_WRITE_MODE); if (result == DVFS_ERROR) return result; mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_DTE; if (mode != IIC_DVFS_BIT_ICSR_DTE) return result; mode = mmio_read_8(IIC_DVFS_REG_ICIC) & ~IIC_DVFS_BIT_ICIC_DTEE; mmio_write_8(IIC_DVFS_REG_ICIC, mode); address = slave << 1; mmio_write_8(IIC_DVFS_REG_ICDR, address); *state = DVFS_WRITE_ADDR; return result; } IIC_DVFS_FUNC(write_addr, DVFS_STATE_T *state, uint32_t *err, uint8_t reg_addr) { uint8_t mode; int32_t result; result = dvfs_check_error(state, err, DVFS_WRITE_MODE); if (result == DVFS_ERROR) return result; mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT; if (mode != IIC_DVFS_BIT_ICSR_WAIT) return result; mmio_write_8(IIC_DVFS_REG_ICDR, reg_addr); mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT; mmio_write_8(IIC_DVFS_REG_ICSR, mode); *state = DVFS_WRITE_DATA; return result; } IIC_DVFS_FUNC(write_data, DVFS_STATE_T *state, uint32_t *err, uint8_t reg_data) { int32_t result; uint8_t mode; result = dvfs_check_error(state, err, DVFS_WRITE_MODE); if (result == DVFS_ERROR) return result; mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT; if (mode != IIC_DVFS_BIT_ICSR_WAIT) return result; mmio_write_8(IIC_DVFS_REG_ICDR, reg_data); mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT; mmio_write_8(IIC_DVFS_REG_ICSR, mode); *state = DVFS_STOP; return result; } IIC_DVFS_FUNC(stop, DVFS_STATE_T *state, uint32_t *err) { int32_t result; uint8_t mode; result = dvfs_check_error(state, err, DVFS_WRITE_MODE); if (result == DVFS_ERROR) return result; mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT; if (mode != IIC_DVFS_BIT_ICSR_WAIT) return result; mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_STOP); mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT; mmio_write_8(IIC_DVFS_REG_ICSR, mode); *state = DVFS_DONE; return result; } IIC_DVFS_FUNC(done, void) { uint32_t i; for (i = 0; i < IIC_DVFS_SET_BUSY_LOOP; i++) { if (mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_BUSY) continue; goto done; } panic(); done: mmio_write_8(IIC_DVFS_REG_ICCR, 0); return DVFS_COMPLETE; } IIC_DVFS_FUNC(write_reg_addr_read, DVFS_STATE_T *state, uint32_t *err, uint8_t reg_addr) { int32_t result; uint8_t mode; result = dvfs_check_error(state, err, DVFS_WRITE_MODE); if (result == DVFS_ERROR) return result; mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT; if (mode != IIC_DVFS_BIT_ICSR_WAIT) return result; mmio_write_8(IIC_DVFS_REG_ICDR, reg_addr); mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT; mmio_write_8(IIC_DVFS_REG_ICSR, mode); *state = DVFS_RETRANSMIT; return result; } IIC_DVFS_FUNC(retransmit, DVFS_STATE_T *state, uint32_t *err) { int32_t result; uint8_t mode; result = dvfs_check_error(state, err, DVFS_WRITE_MODE); if (result == DVFS_ERROR) return result; mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT; if (mode != IIC_DVFS_BIT_ICSR_WAIT) return result; mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_RETRANSMISSION); mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT; mmio_write_8(IIC_DVFS_REG_ICSR, mode); mode = mmio_read_8(IIC_DVFS_REG_ICIC) | IIC_DVFS_BIT_ICIC_DTEE; mmio_write_8(IIC_DVFS_REG_ICIC, mode); *state = DVFS_SET_SLAVE_READ; return result; } IIC_DVFS_FUNC(set_slave_read, DVFS_STATE_T *state, uint32_t *err, uint8_t slave) { uint8_t address; int32_t result; uint8_t mode; result = dvfs_check_error(state, err, DVFS_WRITE_MODE); if (result == DVFS_ERROR) return result; mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_DTE; if (mode != IIC_DVFS_BIT_ICSR_DTE) return result; mode = mmio_read_8(IIC_DVFS_REG_ICIC) & ~IIC_DVFS_BIT_ICIC_DTEE; mmio_write_8(IIC_DVFS_REG_ICIC, mode); address = ((uint8_t) (slave << 1) + DVFS_READ_MODE); mmio_write_8(IIC_DVFS_REG_ICDR, address); *state = DVFS_CHANGE_SEND_TO_RECIEVE; return result; } IIC_DVFS_FUNC(change_send_to_recieve, DVFS_STATE_T *state, uint32_t *err) { int32_t result; uint8_t mode; result = dvfs_check_error(state, err, DVFS_WRITE_MODE); if (result == DVFS_ERROR) return result; mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT; if (mode != IIC_DVFS_BIT_ICSR_WAIT) return result; mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_CHANGE); mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT; mmio_write_8(IIC_DVFS_REG_ICSR, mode); *state = DVFS_STOP_READ; return result; } IIC_DVFS_FUNC(stop_read, DVFS_STATE_T *state, uint32_t *err) { int32_t result; uint8_t mode; result = dvfs_check_error(state, err, DVFS_READ_MODE); if (result == DVFS_ERROR) return result; mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_WAIT; if (mode != IIC_DVFS_BIT_ICSR_WAIT) return result; mmio_write_8(IIC_DVFS_REG_ICCR, IIC_DVFS_SET_ICCR_STOP_READ); mode = mmio_read_8(IIC_DVFS_REG_ICSR) & ~IIC_DVFS_BIT_ICSR_WAIT; mmio_write_8(IIC_DVFS_REG_ICSR, mode); mode = mmio_read_8(IIC_DVFS_REG_ICIC) | IIC_DVFS_BIT_ICIC_DTEE; mmio_write_8(IIC_DVFS_REG_ICIC, mode); *state = DVFS_READ; return result; } IIC_DVFS_FUNC(read, DVFS_STATE_T *state, uint8_t *reg_data) { uint8_t mode; mode = mmio_read_8(IIC_DVFS_REG_ICSR) & IIC_DVFS_BIT_ICSR_DTE; if (mode != IIC_DVFS_BIT_ICSR_DTE) return DVFS_PROCESS; mode = mmio_read_8(IIC_DVFS_REG_ICIC) & ~IIC_DVFS_BIT_ICIC_DTEE; mmio_write_8(IIC_DVFS_REG_ICIC, mode); *reg_data = mmio_read_8(IIC_DVFS_REG_ICDR); *state = DVFS_DONE; return DVFS_PROCESS; } RCAR_DVFS_API(send, uint8_t slave, uint8_t reg_addr, uint8_t reg_data) { DVFS_STATE_T state = DVFS_START; int32_t result = DVFS_PROCESS; uint32_t err = 0; mstpcr_write(SCMSTPCR9, CPG_MSTPSR9, CPG_BIT_SMSTPCR9_DVFS); mmio_write_8(IIC_DVFS_REG_ICCR, 0); again: switch (state) { case DVFS_START: result = dvfs_start(&state); break; case DVFS_SET_SLAVE: result = dvfs_set_slave(&state, &err, slave); break; case DVFS_WRITE_ADDR: result = dvfs_write_addr(&state, &err, reg_addr); break; case DVFS_WRITE_DATA: result = dvfs_write_data(&state, &err, reg_data); break; case DVFS_STOP: result = dvfs_stop(&state, &err); break; case DVFS_DONE: result = dvfs_done(); break; default: panic(); break; } if (result == DVFS_PROCESS) goto again; return result; } RCAR_DVFS_API(receive, uint8_t slave, uint8_t reg, uint8_t *data) { DVFS_STATE_T state = DVFS_START; int32_t result = DVFS_PROCESS; uint32_t err = 0; mstpcr_write(SCMSTPCR9, CPG_MSTPSR9, CPG_BIT_SMSTPCR9_DVFS); mmio_write_8(IIC_DVFS_REG_ICCR, 0); again: switch (state) { case DVFS_START: result = dvfs_start(&state); break; case DVFS_SET_SLAVE: result = dvfs_set_slave(&state, &err, slave); break; case DVFS_WRITE_ADDR: result = dvfs_write_reg_addr_read(&state, &err, reg); break; case DVFS_RETRANSMIT: result = dvfs_retransmit(&state, &err); break; case DVFS_SET_SLAVE_READ: result = dvfs_set_slave_read(&state, &err, slave); break; case DVFS_CHANGE_SEND_TO_RECIEVE: result = dvfs_change_send_to_recieve(&state, &err); break; case DVFS_STOP_READ: result = dvfs_stop_read(&state, &err); break; case DVFS_READ: result = dvfs_read(&state, data); break; case DVFS_DONE: result = dvfs_done(); break; default: panic(); break; } if (result == DVFS_PROCESS) goto again; return result; } trusted-firmware-a-2.2/drivers/renesas/rcar/iic_dvfs/iic_dvfs.h000066400000000000000000000010321355360272700246770ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IIC_DVFS_H #define IIC_DVFS_H /* PMIC slave */ #define PMIC (0x30) #define BKUP_MODE_CNT (0x20) #define DVFS_SET_VID (0x54) #define REG_KEEP10 (0x79) /* EEPROM slave */ #define EEPROM (0x50) #define BOARD_ID (0x70) int32_t rcar_iic_dvfs_receive(uint8_t slave, uint8_t reg, uint8_t *data); int32_t rcar_iic_dvfs_send(uint8_t slave, uint8_t regr, uint8_t data); #endif /* IIC_DVFS_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/io/000077500000000000000000000000001355360272700215655ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/io/io_common.h000066400000000000000000000004541355360272700237200ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IO_COMMON_H #define IO_COMMON_H typedef struct io_drv_spec { size_t offset; size_t length; uint32_t partition; } io_drv_spec_t; #endif /* IO_COMMON_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/io/io_emmcdrv.c000066400000000000000000000101641355360272700240570ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "io_common.h" #include "io_emmcdrv.h" #include "io_private.h" #include "emmc_config.h" #include "emmc_hal.h" #include "emmc_std.h" #include "emmc_def.h" static int32_t emmcdrv_dev_open(const uintptr_t spec __attribute__ ((unused)), io_dev_info_t **dev_info); static int32_t emmcdrv_dev_close(io_dev_info_t *dev_info); typedef struct { uint32_t in_use; uintptr_t base; ssize_t file_pos; EMMC_PARTITION_ID partition; } file_state_t; static file_state_t current_file = { 0 }; static EMMC_PARTITION_ID emmcdrv_bootpartition = PARTITION_ID_USER; static io_type_t device_type_emmcdrv(void) { return IO_TYPE_MEMMAP; } static int32_t emmcdrv_block_seek(io_entity_t *entity, int32_t mode, ssize_t offset) { if (mode != IO_SEEK_SET) return IO_FAIL; ((file_state_t *) entity->info)->file_pos = offset; return IO_SUCCESS; } static int32_t emmcdrv_block_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read) { file_state_t *fp = (file_state_t *) entity->info; uint32_t sector_add, sector_num, emmc_dma = 0; int32_t result = IO_SUCCESS; sector_add = current_file.file_pos >> EMMC_SECTOR_SIZE_SHIFT; sector_num = (length + EMMC_SECTOR_SIZE - 1U) >> EMMC_SECTOR_SIZE_SHIFT; NOTICE("BL2: Load dst=0x%lx src=(p:%d)0x%lx(%d) len=0x%lx(%d)\n", buffer, current_file.partition, current_file.file_pos, sector_add, length, sector_num); if (buffer + length - 1 <= UINT32_MAX) emmc_dma = LOADIMAGE_FLAGS_DMA_ENABLE; if (emmc_read_sector((uint32_t *) buffer, sector_add, sector_num, emmc_dma) != EMMC_SUCCESS) result = IO_FAIL; *length_read = length; fp->file_pos += length; return result; } static int32_t emmcdrv_block_open(io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity) { const io_drv_spec_t *block_spec = (io_drv_spec_t *) spec; if (current_file.in_use) { WARN("mmc_block: Only one open spec at a time\n"); return IO_RESOURCES_EXHAUSTED; } current_file.file_pos = 0; current_file.in_use = 1; if (emmcdrv_bootpartition == PARTITION_ID_USER) { emmcdrv_bootpartition = mmc_drv_obj.boot_partition_en; if ((PARTITION_ID_BOOT_1 == emmcdrv_bootpartition) || (PARTITION_ID_BOOT_2 == emmcdrv_bootpartition)) { current_file.partition = emmcdrv_bootpartition; NOTICE("BL2: eMMC boot from partition %d\n", emmcdrv_bootpartition); goto done; } return IO_FAIL; } if (PARTITION_ID_USER == block_spec->partition || PARTITION_ID_BOOT_1 == block_spec->partition || PARTITION_ID_BOOT_2 == block_spec->partition) current_file.partition = block_spec->partition; else current_file.partition = emmcdrv_bootpartition; done: if (emmc_select_partition(current_file.partition) != EMMC_SUCCESS) return IO_FAIL; entity->info = (uintptr_t) ¤t_file; return IO_SUCCESS; } static int32_t emmcdrv_block_close(io_entity_t *entity) { memset((void *)¤t_file, 0, sizeof(current_file)); entity->info = 0U; return IO_SUCCESS; } static const io_dev_funcs_t emmcdrv_dev_funcs = { .type = &device_type_emmcdrv, .open = &emmcdrv_block_open, .seek = &emmcdrv_block_seek, .size = NULL, .read = &emmcdrv_block_read, .write = NULL, .close = &emmcdrv_block_close, .dev_init = NULL, .dev_close = &emmcdrv_dev_close }; static const io_dev_info_t emmcdrv_dev_info = { .funcs = &emmcdrv_dev_funcs, .info = (uintptr_t) 0 }; static const io_dev_connector_t emmcdrv_dev_connector = { &emmcdrv_dev_open, }; static int32_t emmcdrv_dev_open(const uintptr_t spec __attribute__ ((unused)), io_dev_info_t **dev_info) { *dev_info = (io_dev_info_t *) &emmcdrv_dev_info; return IO_SUCCESS; } static int32_t emmcdrv_dev_close(io_dev_info_t *dev_info) { return IO_SUCCESS; } int32_t rcar_register_io_dev_emmcdrv(const io_dev_connector_t **dev_con) { int32_t rc; rc = io_register_device(&emmcdrv_dev_info); if (rc == IO_SUCCESS) *dev_con = &emmcdrv_dev_connector; return rc; } trusted-firmware-a-2.2/drivers/renesas/rcar/io/io_emmcdrv.h000066400000000000000000000004611355360272700240630ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IO_EMMCDRV_H #define IO_EMMCDRV_H struct io_dev_connector; int32_t rcar_register_io_dev_emmcdrv(const io_dev_connector_t **connector); #endif /* IO_EMMCDRV_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/io/io_memdrv.c000066400000000000000000000066351355360272700237240ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "io_common.h" #include "io_private.h" #include "io_memdrv.h" #include "rcar_def.h" extern void rcar_dma_exec(uintptr_t dst, uint32_t src, uint32_t len); static int32_t memdrv_dev_open(const uintptr_t dev __attribute__ ((unused)), io_dev_info_t **dev_info); static int32_t memdrv_dev_close(io_dev_info_t *dev_info); /* As we need to be able to keep state for seek, only one file can be open * at a time. Make this a structure and point to the entity->info. When we * can malloc memory we can change this to support more open files. */ typedef struct { uint32_t in_use; uintptr_t base; ssize_t file_pos; } file_state_t; static file_state_t current_file = { 0 }; static io_type_t device_type_memdrv(void) { return IO_TYPE_MEMMAP; } static int32_t memdrv_block_open(io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity) { const io_drv_spec_t *block_spec = (io_drv_spec_t *) spec; /* Since we need to track open state for seek() we only allow one open * spec at a time. When we have dynamic memory we can malloc and set * entity->info. */ if (current_file.in_use) return IO_RESOURCES_EXHAUSTED; /* File cursor offset for seek and incremental reads etc. */ current_file.base = block_spec->offset; current_file.file_pos = 0; current_file.in_use = 1; entity->info = (uintptr_t) ¤t_file; return IO_SUCCESS; } static int32_t memdrv_block_seek(io_entity_t *entity, int32_t mode, ssize_t offset) { if (mode != IO_SEEK_SET) return IO_FAIL; ((file_state_t *) entity->info)->file_pos = offset; return IO_SUCCESS; } static int32_t memdrv_block_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *cnt) { file_state_t *fp; fp = (file_state_t *) entity->info; NOTICE("BL2: dst=0x%lx src=0x%lx len=%ld(0x%lx)\n", buffer, fp->base + fp->file_pos, length, length); if (FLASH_MEMORY_SIZE < fp->file_pos + length) { ERROR("BL2: check load image (source address)\n"); return IO_FAIL; } rcar_dma_exec(buffer, fp->base + fp->file_pos, length); fp->file_pos += length; *cnt = length; return IO_SUCCESS; } static int32_t memdrv_block_close(io_entity_t *entity) { entity->info = 0U; memset((void *)¤t_file, 0, sizeof(current_file)); return IO_SUCCESS; } static const io_dev_funcs_t memdrv_dev_funcs = { .type = &device_type_memdrv, .open = &memdrv_block_open, .seek = &memdrv_block_seek, .size = NULL, .read = &memdrv_block_read, .write = NULL, .close = &memdrv_block_close, .dev_init = NULL, .dev_close = &memdrv_dev_close, }; static const io_dev_info_t memdrv_dev_info = { .funcs = &memdrv_dev_funcs, .info = 0, }; static const io_dev_connector_t memdrv_dev_connector = { .dev_open = &memdrv_dev_open }; static int32_t memdrv_dev_open(const uintptr_t dev __attribute__ ((unused)), io_dev_info_t **dev_info) { *dev_info = (io_dev_info_t *) &memdrv_dev_info; return IO_SUCCESS; } static int32_t memdrv_dev_close(io_dev_info_t *dev_info) { return IO_SUCCESS; } int32_t rcar_register_io_dev_memdrv(const io_dev_connector_t **dev_con) { int32_t result; result = io_register_device(&memdrv_dev_info); if (result == IO_SUCCESS) *dev_con = &memdrv_dev_connector; return result; } trusted-firmware-a-2.2/drivers/renesas/rcar/io/io_memdrv.h000066400000000000000000000004551355360272700237230ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IO_MEMDRV_H #define IO_MEMDRV_H struct io_dev_connector; int32_t rcar_register_io_dev_memdrv(const io_dev_connector_t **connector); #endif /* IO_MEMDRV_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/io/io_private.h000066400000000000000000000007541355360272700241050ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IO_PRIVATE_H #define IO_PRIVATE_H /* * Return codes reported by 'io_*' APIs * The value of fail should not overlap with define of the errno. * The errno is in "include/lib/stdlib/sys/errno.h". */ #define IO_SUCCESS (0) #define IO_FAIL (-0x81) #define IO_NOT_SUPPORTED (-0x82) #define IO_RESOURCES_EXHAUSTED (-0x83) #endif /* IO_PRIVATE_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/io/io_rcar.c000066400000000000000000000403701355360272700233530ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "io_rcar.h" #include "io_common.h" #include "io_private.h" extern int32_t plat_get_drv_source(uint32_t id, uintptr_t *dev, uintptr_t *image_spec); extern int auth_mod_verify_img(unsigned int img_id, void *ptr, unsigned int len); static int32_t rcar_dev_open(const uintptr_t dev_spec __attribute__ ((unused)), io_dev_info_t **dev_info); static int32_t rcar_dev_close(io_dev_info_t *dev_info); typedef struct { const int32_t name; const uint32_t offset; const uint32_t attr; } plat_rcar_name_offset_t; typedef struct { /* Put position above the struct to allow {0} on static init. * It is a workaround for a known bug in GCC * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53119 */ uint32_t position; uint32_t no_load; uintptr_t offset; uint32_t size; uintptr_t dst; uintptr_t partition; /* for eMMC */ /* RCAR_EMMC_PARTITION_BOOT_0 */ /* RCAR_EMMC_PARTITION_BOOT_1 */ /* RCAR_EMMC_PARTITION_USER */ } file_state_t; #define RCAR_GET_FLASH_ADR(a, b) ((uint32_t)((0x40000U * (a)) + (b))) #define RCAR_ATTR_SET_CALCADDR(a) ((a) & 0xF) #define RCAR_ATTR_SET_ISNOLOAD(a) (((a) & 0x1) << 16U) #define RCAR_ATTR_SET_CERTOFF(a) (((a) & 0xF) << 8U) #define RCAR_ATTR_SET_ALL(a, b, c) ((uint32_t)(RCAR_ATTR_SET_CALCADDR(a) |\ RCAR_ATTR_SET_ISNOLOAD(b) | \ RCAR_ATTR_SET_CERTOFF(c))) #define RCAR_ATTR_GET_CALCADDR(a) ((a) & 0xFU) #define RCAR_ATTR_GET_ISNOLOAD(a) (((a) >> 16) & 0x1U) #define RCAR_ATTR_GET_CERTOFF(a) ((uint32_t)(((a) >> 8) & 0xFU)) #define RCAR_MAX_BL3X_IMAGE (8U) #define RCAR_SECTOR6_CERT_OFFSET (0x400U) #define RCAR_SDRAM_certESS (0x43F00000U) #define RCAR_CERT_SIZE (0x800U) #define RCAR_CERT_INFO_SIZE_OFFSET (0x264U) #define RCAR_CERT_INFO_DST_OFFSET (0x154U) #define RCAR_CERT_INFO_SIZE_OFFSET1 (0x364U) #define RCAR_CERT_INFO_DST_OFFSET1 (0x1D4U) #define RCAR_CERT_INFO_SIZE_OFFSET2 (0x464U) #define RCAR_CERT_INFO_DST_OFFSET2 (0x254U) #define RCAR_CERT_LOAD (1U) #define RCAR_FLASH_CERT_HEADER RCAR_GET_FLASH_ADR(6U, 0U) #define RCAR_EMMC_CERT_HEADER (0x00030000U) #define RCAR_COUNT_LOAD_BL33 (2U) #define RCAR_COUNT_LOAD_BL33X (3U) static const plat_rcar_name_offset_t name_offset[] = { {BL31_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(0, 0, 0)}, /* BL3-2 is optional in the platform */ {BL32_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(1, 0, 1)}, {BL33_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(2, 0, 2)}, {BL332_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(3, 0, 3)}, {BL333_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(4, 0, 4)}, {BL334_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(5, 0, 5)}, {BL335_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(6, 0, 6)}, {BL336_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(7, 0, 7)}, {BL337_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(8, 0, 8)}, {BL338_IMAGE_ID, 0U, RCAR_ATTR_SET_ALL(9, 0, 9)}, }; #if TRUSTED_BOARD_BOOT static const plat_rcar_name_offset_t cert_offset[] = { /* Certificates */ {TRUSTED_KEY_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 0)}, {SOC_FW_KEY_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 0)}, {TRUSTED_OS_FW_KEY_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 0)}, {NON_TRUSTED_FW_KEY_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 0)}, {SOC_FW_CONTENT_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 0)}, {TRUSTED_OS_FW_CONTENT_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 1)}, {NON_TRUSTED_FW_CONTENT_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 2)}, {BL332_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 3)}, {BL333_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 4)}, {BL334_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 5)}, {BL335_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 6)}, {BL336_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 7)}, {BL337_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 8)}, {BL338_CERT_ID, 0U, RCAR_ATTR_SET_ALL(0, 1, 9)}, }; #endif /* TRUSTED_BOARD_BOOT */ static file_state_t current_file = { 0 }; static uintptr_t rcar_handle, rcar_spec; static uint64_t rcar_image_header[RCAR_MAX_BL3X_IMAGE + 2U] = { 0U }; static uint64_t rcar_image_header_prttn[RCAR_MAX_BL3X_IMAGE + 2U] = { 0U }; static uint64_t rcar_image_number = { 0U }; static uint32_t rcar_cert_load = { 0U }; static io_type_t device_type_rcar(void) { return IO_TYPE_FIRMWARE_IMAGE_PACKAGE; } int32_t rcar_get_certificate(const int32_t name, uint32_t *cert) { #if TRUSTED_BOARD_BOOT int32_t i; for (i = 0; i < ARRAY_SIZE(cert_offset); i++) { if (name != cert_offset[i].name) continue; *cert = RCAR_CERT_SIZE; *cert *= RCAR_ATTR_GET_CERTOFF(cert_offset[i].attr); *cert += RCAR_SDRAM_certESS; return 0; } #endif return -EINVAL; } static int32_t file_to_offset(const int32_t name, uintptr_t *offset, uint32_t *cert, uint32_t *no_load, uintptr_t *partition) { uint32_t addr; int32_t i; for (i = 0; i < ARRAY_SIZE(name_offset); i++) { if (name != name_offset[i].name) continue; addr = RCAR_ATTR_GET_CALCADDR(name_offset[i].attr); if (rcar_image_number + 2 < addr) continue; *offset = rcar_image_header[addr]; *cert = RCAR_CERT_SIZE; *cert *= RCAR_ATTR_GET_CERTOFF(name_offset[i].attr); *cert += RCAR_SDRAM_certESS; *no_load = RCAR_ATTR_GET_ISNOLOAD(name_offset[i].attr); *partition = rcar_image_header_prttn[addr]; return IO_SUCCESS; } #if TRUSTED_BOARD_BOOT for (i = 0; i < ARRAY_SIZE(cert_offset); i++) { if (name != cert_offset[i].name) continue; *no_load = RCAR_ATTR_GET_ISNOLOAD(cert_offset[i].attr); *partition = 0U; *offset = 0U; *cert = 0U; return IO_SUCCESS; } #endif return -EINVAL; } #define RCAR_BOOT_KEY_CERT_NEW (0xE6300F00U) #define RCAR_CERT_MAGIC_NUM (0xE291F358U) void rcar_read_certificate(uint64_t cert, uint32_t *len, uintptr_t *dst) { uint32_t seed, val, info_1, info_2; uintptr_t size, dsth, dstl; cert &= 0xFFFFFFFFU; seed = mmio_read_32(RCAR_BOOT_KEY_CERT_NEW); val = mmio_read_32(RCAR_BOOT_KEY_CERT_NEW + 0xC); info_1 = (val >> 18) & 0x3U; val = mmio_read_32(cert + 0xC); info_2 = (val >> 21) & 0x3; if (seed == RCAR_CERT_MAGIC_NUM) { if (info_1 != 1) { ERROR("BL2: Cert is invalid.\n"); *dst = 0; *len = 0; return; } if (info_2 > 2) { ERROR("BL2: Cert is invalid.\n"); *dst = 0; *len = 0; return; } switch (info_2) { case 2: size = cert + RCAR_CERT_INFO_SIZE_OFFSET2; dstl = cert + RCAR_CERT_INFO_DST_OFFSET2; break; case 1: size = cert + RCAR_CERT_INFO_SIZE_OFFSET1; dstl = cert + RCAR_CERT_INFO_DST_OFFSET1; break; case 0: size = cert + RCAR_CERT_INFO_SIZE_OFFSET; dstl = cert + RCAR_CERT_INFO_DST_OFFSET; break; } *len = mmio_read_32(size) * 4U; dsth = dstl + 4U; *dst = ((uintptr_t) mmio_read_32(dsth) << 32) + ((uintptr_t) mmio_read_32(dstl)); return; } size = cert + RCAR_CERT_INFO_SIZE_OFFSET; *len = mmio_read_32(size) * 4U; dstl = cert + RCAR_CERT_INFO_DST_OFFSET; dsth = dstl + 4U; *dst = ((uintptr_t) mmio_read_32(dsth) << 32) + ((uintptr_t) mmio_read_32(dstl)); } static int32_t check_load_area(uintptr_t dst, uintptr_t len) { uint32_t legacy = dst + len <= UINT32_MAX - 1 ? 1 : 0; uintptr_t dram_start, dram_end; uintptr_t prot_start, prot_end; int32_t result = IO_SUCCESS; dram_start = legacy ? DRAM1_BASE : DRAM_40BIT_BASE; dram_end = legacy ? DRAM1_BASE + DRAM1_SIZE : DRAM_40BIT_BASE + DRAM_40BIT_SIZE; prot_start = legacy ? DRAM_PROTECTED_BASE : DRAM_40BIT_PROTECTED_BASE; prot_end = prot_start + DRAM_PROTECTED_SIZE; if (dst < dram_start || dst > dram_end - len) { ERROR("BL2: dst address is on the protected area.\n"); result = IO_FAIL; goto done; } /* load image is within SDRAM protected area */ if (dst >= prot_start && dst < prot_end) { ERROR("BL2: dst address is on the protected area.\n"); result = IO_FAIL; } if (dst < prot_start && dst > prot_start - len) { ERROR("BL2: loaded data is on the protected area.\n"); result = IO_FAIL; } done: if (result == IO_FAIL) ERROR("BL2: Out of range : dst=0x%lx len=0x%lx\n", dst, len); return result; } static int32_t load_bl33x(void) { static int32_t loaded = IO_NOT_SUPPORTED; uintptr_t dst, partition, handle; uint32_t noload, cert, len, i; uintptr_t offset; int32_t rc; size_t cnt; const int32_t img[] = { BL33_IMAGE_ID, BL332_IMAGE_ID, BL333_IMAGE_ID, BL334_IMAGE_ID, BL335_IMAGE_ID, BL336_IMAGE_ID, BL337_IMAGE_ID, BL338_IMAGE_ID }; if (loaded != IO_NOT_SUPPORTED) return loaded; for (i = 1; i < rcar_image_number; i++) { rc = file_to_offset(img[i], &offset, &cert, &noload, &partition); if (rc != IO_SUCCESS) { WARN("load_bl33x: failed to get offset\n"); loaded = IO_FAIL; return loaded; } rcar_read_certificate((uint64_t) cert, &len, &dst); ((io_drv_spec_t *) rcar_spec)->partition = partition; rc = io_open(rcar_handle, rcar_spec, &handle); if (rc != IO_SUCCESS) { WARN("Failed to open FIP (%i)\n", rc); loaded = IO_FAIL; return loaded; } rc = io_seek(handle, IO_SEEK_SET, offset); if (rc != IO_SUCCESS) { WARN("load_bl33x: failed to seek\n"); loaded = IO_FAIL; return loaded; } rc = check_load_area(dst, len); if (rc != IO_SUCCESS) { WARN("load_bl33x: check load area\n"); loaded = IO_FAIL; return loaded; } rc = io_read(handle, dst, len, &cnt); if (rc != IO_SUCCESS) { WARN("load_bl33x: failed to read\n"); loaded = IO_FAIL; return loaded; } #if TRUSTED_BOARD_BOOT rc = auth_mod_verify_img(img[i], (void *)dst, len); if (rc) { memset((void *)dst, 0x00, len); loaded = IO_FAIL; return loaded; } #endif io_close(handle); } loaded = IO_SUCCESS; return loaded; } static int32_t rcar_dev_init(io_dev_info_t *dev_info, const uintptr_t name) { uint64_t header[64] __aligned(FLASH_TRANS_SIZE_UNIT) = { 0}; uintptr_t handle; ssize_t offset; uint32_t i; int32_t rc; size_t cnt; /* Obtain a reference to the image by querying the platform layer */ rc = plat_get_drv_source(name, &rcar_handle, &rcar_spec); if (rc != IO_SUCCESS) { WARN("Failed to obtain reference to img %ld (%i)\n", name, rc); return IO_FAIL; } if (RCAR_CERT_LOAD == rcar_cert_load) return IO_SUCCESS; rc = io_open(rcar_handle, rcar_spec, &handle); if (rc != IO_SUCCESS) { WARN("Failed to access img %ld (%i)\n", name, rc); return IO_FAIL; } /* get start address list */ /* [0] address num */ /* [1] BL33-1 image address */ /* [2] BL33-2 image address */ /* [3] BL33-3 image address */ /* [4] BL33-4 image address */ /* [5] BL33-5 image address */ /* [6] BL33-6 image address */ /* [7] BL33-7 image address */ /* [8] BL33-8 image address */ offset = name == EMMC_DEV_ID ? RCAR_EMMC_CERT_HEADER : RCAR_FLASH_CERT_HEADER; rc = io_seek(handle, IO_SEEK_SET, offset); if (rc != IO_SUCCESS) { WARN("Firmware Image Package header failed to seek\n"); goto error; } #if RCAR_BL2_DCACHE == 1 inv_dcache_range((uint64_t) header, sizeof(header)); #endif rc = io_read(handle, (uintptr_t) &header, sizeof(header), &cnt); if (rc != IO_SUCCESS) { WARN("Firmware Image Package header failed to read\n"); goto error; } rcar_image_number = header[0]; for (i = 0; i < rcar_image_number + 2; i++) { rcar_image_header[i] = header[i * 2 + 1]; rcar_image_header_prttn[i] = header[i * 2 + 2]; } if (rcar_image_number == 0 || rcar_image_number > RCAR_MAX_BL3X_IMAGE) { WARN("Firmware Image Package header check failed.\n"); goto error; } rc = io_seek(handle, IO_SEEK_SET, offset + RCAR_SECTOR6_CERT_OFFSET); if (rc != IO_SUCCESS) { WARN("Firmware Image Package header failed to seek cert\n"); goto error; } #if RCAR_BL2_DCACHE == 1 inv_dcache_range(RCAR_SDRAM_certESS, RCAR_CERT_SIZE * (2 + rcar_image_number)); #endif rc = io_read(handle, RCAR_SDRAM_certESS, RCAR_CERT_SIZE * (2 + rcar_image_number), &cnt); if (rc != IO_SUCCESS) { WARN("cert file read error.\n"); goto error; } rcar_cert_load = RCAR_CERT_LOAD; error: if (rc != IO_SUCCESS) rc = IO_FAIL; io_close(handle); return rc; } static int32_t rcar_file_open(io_dev_info_t *info, const uintptr_t file_spec, io_entity_t *entity) { const io_drv_spec_t *spec = (io_drv_spec_t *) file_spec; uintptr_t partition, offset, dst; uint32_t noload, cert, len; int32_t rc; /* Only one file open at a time. We need to track state (ie, file * cursor position). Since the header lives at * offset zero, this entry * should never be zero in an active file. * Once the system supports dynamic memory allocation we will allow more * than one open file at a time. */ if (current_file.offset != 0U) { WARN("rcar_file_open : Only one open file at a time.\n"); return IO_RESOURCES_EXHAUSTED; } rc = file_to_offset(spec->offset, &offset, &cert, &noload, &partition); if (rc != IO_SUCCESS) { WARN("Failed to open file name %ld (%i)\n", spec->offset, rc); return IO_FAIL; } if (noload) { current_file.offset = 1; current_file.dst = 0; current_file.size = 1; current_file.position = 0; current_file.no_load = noload; current_file.partition = 0; entity->info = (uintptr_t) ¤t_file; return IO_SUCCESS; } rcar_read_certificate((uint64_t) cert, &len, &dst); /*----------------* * Baylibre: HACK * *----------------*/ if (BL31_IMAGE_ID == spec->offset && len < RCAR_TRUSTED_SRAM_SIZE) { WARN("r-car ignoring the BL31 size from certificate," "using RCAR_TRUSTED_SRAM_SIZE instead\n"); len = RCAR_TRUSTED_SRAM_SIZE; } current_file.partition = partition; current_file.no_load = noload; current_file.offset = offset; current_file.position = 0; current_file.size = len; current_file.dst = dst; entity->info = (uintptr_t) ¤t_file; return IO_SUCCESS; } static int32_t rcar_file_len(io_entity_t *entity, size_t *length) { *length = ((file_state_t *) entity->info)->size; NOTICE("%s: len: 0x%08lx\n", __func__, *length); return IO_SUCCESS; } static int32_t rcar_file_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *cnt) { file_state_t *fp = (file_state_t *) entity->info; ssize_t offset = fp->offset + fp->position; uintptr_t handle; int32_t rc; #ifdef SPD_NONE static uint32_t load_bl33x_counter = 1; #else static uint32_t load_bl33x_counter; #endif if (current_file.no_load) { *cnt = length; return IO_SUCCESS; } ((io_drv_spec_t *) rcar_spec)->partition = fp->partition; rc = io_open(rcar_handle, rcar_spec, &handle); if (rc != IO_SUCCESS) { WARN("Failed to open FIP (%i)\n", rc); return IO_FAIL; } rc = io_seek(handle, IO_SEEK_SET, offset); if (rc != IO_SUCCESS) { WARN("rcar_file_read: failed to seek\n"); goto error; } if (load_bl33x_counter == RCAR_COUNT_LOAD_BL33) { rc = check_load_area(buffer, length); if (rc != IO_SUCCESS) { WARN("rcar_file_read: load area err\n"); goto error; } } rc = io_read(handle, buffer, length, cnt); if (rc != IO_SUCCESS) { WARN("Failed to read payload (%i)\n", rc); goto error; } fp->position += *cnt; io_close(handle); load_bl33x_counter += 1; if (load_bl33x_counter == RCAR_COUNT_LOAD_BL33X) return load_bl33x(); return IO_SUCCESS; error: io_close(handle); return IO_FAIL; } static int32_t rcar_file_close(io_entity_t *entity) { if (current_file.offset) memset(¤t_file, 0, sizeof(current_file)); entity->info = 0U; return IO_SUCCESS; } static const io_dev_funcs_t rcar_dev_funcs = { .type = &device_type_rcar, .open = &rcar_file_open, .seek = NULL, .size = &rcar_file_len, .read = &rcar_file_read, .write = NULL, .close = &rcar_file_close, .dev_init = &rcar_dev_init, .dev_close = &rcar_dev_close, }; static const io_dev_info_t rcar_dev_info = { .funcs = &rcar_dev_funcs, .info = (uintptr_t) 0 }; static const io_dev_connector_t rcar_dev_connector = { .dev_open = &rcar_dev_open }; static int32_t rcar_dev_open(const uintptr_t dev_spec __attribute__ ((unused)), io_dev_info_t **dev_info) { *dev_info = (io_dev_info_t *) &rcar_dev_info; return IO_SUCCESS; } static int32_t rcar_dev_close(io_dev_info_t *dev_info) { rcar_handle = 0; rcar_spec = 0; return IO_SUCCESS; } int32_t rcar_register_io_dev(const io_dev_connector_t **dev_con) { int32_t result; result = io_register_device(&rcar_dev_info); if (result == IO_SUCCESS) *dev_con = &rcar_dev_connector; return result; } trusted-firmware-a-2.2/drivers/renesas/rcar/io/io_rcar.h000066400000000000000000000006231355360272700233550ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IO_RCAR_H #define IO_RCAR_H int32_t rcar_register_io_dev(const io_dev_connector_t **dev_con); int32_t rcar_get_certificate(const int32_t name, uint32_t *cert); void rcar_read_certificate(uint64_t cert, uint32_t *size, uintptr_t *dest); #endif /* IO_RCAR_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/000077500000000000000000000000001355360272700217265ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/D3/000077500000000000000000000000001355360272700221745ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/D3/pfc_init_d3.c000066400000000000000000000650441355360272700245320ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "pfc_init_d3.h" #include "rcar_def.h" #include "../pfc_regs.h" /* PFC */ #define GPSR0_D15 BIT(15) #define GPSR0_D14 BIT(14) #define GPSR0_D13 BIT(13) #define GPSR0_D12 BIT(12) #define GPSR0_D11 BIT(11) #define GPSR0_D10 BIT(10) #define GPSR0_D9 BIT(9) #define GPSR0_D8 BIT(8) #define GPSR0_D7 BIT(7) #define GPSR0_D6 BIT(6) #define GPSR0_D5 BIT(5) #define GPSR0_D4 BIT(4) #define GPSR0_D3 BIT(3) #define GPSR0_D2 BIT(2) #define GPSR0_D1 BIT(1) #define GPSR0_D0 BIT(0) #define GPSR1_CLKOUT BIT(28) #define GPSR1_EX_WAIT0_A BIT(27) #define GPSR1_WE1 BIT(26) #define GPSR1_WE0 BIT(25) #define GPSR1_RD_WR BIT(24) #define GPSR1_RD BIT(23) #define GPSR1_BS BIT(22) #define GPSR1_CS1_A26 BIT(21) #define GPSR1_CS0 BIT(20) #define GPSR1_A19 BIT(19) #define GPSR1_A18 BIT(18) #define GPSR1_A17 BIT(17) #define GPSR1_A16 BIT(16) #define GPSR1_A15 BIT(15) #define GPSR1_A14 BIT(14) #define GPSR1_A13 BIT(13) #define GPSR1_A12 BIT(12) #define GPSR1_A11 BIT(11) #define GPSR1_A10 BIT(10) #define GPSR1_A9 BIT(9) #define GPSR1_A8 BIT(8) #define GPSR1_A7 BIT(7) #define GPSR1_A6 BIT(6) #define GPSR1_A5 BIT(5) #define GPSR1_A4 BIT(4) #define GPSR1_A3 BIT(3) #define GPSR1_A2 BIT(2) #define GPSR1_A1 BIT(1) #define GPSR1_A0 BIT(0) #define GPSR2_AVB_AVTP_CAPTURE_A BIT(14) #define GPSR2_AVB_AVTP_MATCH_A BIT(13) #define GPSR2_AVB_LINK BIT(12) #define GPSR2_AVB_PHY_INT BIT(11) #define GPSR2_AVB_MAGIC BIT(10) #define GPSR2_AVB_MDC BIT(9) #define GPSR2_PWM2_A BIT(8) #define GPSR2_PWM1_A BIT(7) #define GPSR2_PWM0 BIT(6) #define GPSR2_IRQ5 BIT(5) #define GPSR2_IRQ4 BIT(4) #define GPSR2_IRQ3 BIT(3) #define GPSR2_IRQ2 BIT(2) #define GPSR2_IRQ1 BIT(1) #define GPSR2_IRQ0 BIT(0) #define GPSR3_SD1_WP BIT(15) #define GPSR3_SD1_CD BIT(14) #define GPSR3_SD0_WP BIT(13) #define GPSR3_SD0_CD BIT(12) #define GPSR3_SD1_DAT3 BIT(11) #define GPSR3_SD1_DAT2 BIT(10) #define GPSR3_SD1_DAT1 BIT(9) #define GPSR3_SD1_DAT0 BIT(8) #define GPSR3_SD1_CMD BIT(7) #define GPSR3_SD1_CLK BIT(6) #define GPSR3_SD0_DAT3 BIT(5) #define GPSR3_SD0_DAT2 BIT(4) #define GPSR3_SD0_DAT1 BIT(3) #define GPSR3_SD0_DAT0 BIT(2) #define GPSR3_SD0_CMD BIT(1) #define GPSR3_SD0_CLK BIT(0) #define GPSR4_SD3_DS BIT(17) #define GPSR4_SD3_DAT7 BIT(16) #define GPSR4_SD3_DAT6 BIT(15) #define GPSR4_SD3_DAT5 BIT(14) #define GPSR4_SD3_DAT4 BIT(13) #define GPSR4_SD3_DAT3 BIT(12) #define GPSR4_SD3_DAT2 BIT(11) #define GPSR4_SD3_DAT1 BIT(10) #define GPSR4_SD3_DAT0 BIT(9) #define GPSR4_SD3_CMD BIT(8) #define GPSR4_SD3_CLK BIT(7) #define GPSR4_SD2_DS BIT(6) #define GPSR4_SD2_DAT3 BIT(5) #define GPSR4_SD2_DAT2 BIT(4) #define GPSR4_SD2_DAT1 BIT(3) #define GPSR4_SD2_DAT0 BIT(2) #define GPSR4_SD2_CMD BIT(1) #define GPSR4_SD2_CLK BIT(0) #define GPSR5_MLB_DAT BIT(25) #define GPSR5_MLB_SIG BIT(24) #define GPSR5_MLB_CLK BIT(23) #define GPSR5_MSIOF0_RXD BIT(22) #define GPSR5_MSIOF0_SS2 BIT(21) #define GPSR5_MSIOF0_TXD BIT(20) #define GPSR5_MSIOF0_SS1 BIT(19) #define GPSR5_MSIOF0_SYNC BIT(18) #define GPSR5_MSIOF0_SCK BIT(17) #define GPSR5_HRTS0 BIT(16) #define GPSR5_HCTS0 BIT(15) #define GPSR5_HTX0 BIT(14) #define GPSR5_HRX0 BIT(13) #define GPSR5_HSCK0 BIT(12) #define GPSR5_RX2_A BIT(11) #define GPSR5_TX2_A BIT(10) #define GPSR5_SCK2 BIT(9) #define GPSR5_RTS1_TANS BIT(8) #define GPSR5_CTS1 BIT(7) #define GPSR5_TX1_A BIT(6) #define GPSR5_RX1_A BIT(5) #define GPSR5_RTS0_TANS BIT(4) #define GPSR5_CTS0 BIT(3) #define GPSR5_TX0 BIT(2) #define GPSR5_RX0 BIT(1) #define GPSR5_SCK0 BIT(0) #define GPSR6_USB31_OVC BIT(31) #define GPSR6_USB31_PWEN BIT(30) #define GPSR6_USB30_OVC BIT(29) #define GPSR6_USB30_PWEN BIT(28) #define GPSR6_USB1_OVC BIT(27) #define GPSR6_USB1_PWEN BIT(26) #define GPSR6_USB0_OVC BIT(25) #define GPSR6_USB0_PWEN BIT(24) #define GPSR6_AUDIO_CLKB_B BIT(23) #define GPSR6_AUDIO_CLKA_A BIT(22) #define GPSR6_SSI_SDATA9_A BIT(21) #define GPSR6_SSI_SDATA8 BIT(20) #define GPSR6_SSI_SDATA7 BIT(19) #define GPSR6_SSI_WS78 BIT(18) #define GPSR6_SSI_SCK78 BIT(17) #define GPSR6_SSI_SDATA6 BIT(16) #define GPSR6_SSI_WS6 BIT(15) #define GPSR6_SSI_SCK6 BIT(14) #define GPSR6_SSI_SDATA5 BIT(13) #define GPSR6_SSI_WS5 BIT(12) #define GPSR6_SSI_SCK5 BIT(11) #define GPSR6_SSI_SDATA4 BIT(10) #define GPSR6_SSI_WS4 BIT(9) #define GPSR6_SSI_SCK4 BIT(8) #define GPSR6_SSI_SDATA3 BIT(7) #define GPSR6_SSI_WS34 BIT(6) #define GPSR6_SSI_SCK34 BIT(5) #define GPSR6_SSI_SDATA2_A BIT(4) #define GPSR6_SSI_SDATA1_A BIT(3) #define GPSR6_SSI_SDATA0 BIT(2) #define GPSR6_SSI_WS0129 BIT(1) #define GPSR6_SSI_SCK0129 BIT(0) #define GPSR7_HDMI1_CEC BIT(3) #define GPSR7_HDMI0_CEC BIT(2) #define GPSR7_AVS2 BIT(1) #define GPSR7_AVS1 BIT(0) #define IPSR_28_FUNC(x) ((uint32_t)(x) << 28U) #define IPSR_24_FUNC(x) ((uint32_t)(x) << 24U) #define IPSR_20_FUNC(x) ((uint32_t)(x) << 20U) #define IPSR_16_FUNC(x) ((uint32_t)(x) << 16U) #define IPSR_12_FUNC(x) ((uint32_t)(x) << 12U) #define IPSR_8_FUNC(x) ((uint32_t)(x) << 8U) #define IPSR_4_FUNC(x) ((uint32_t)(x) << 4U) #define IPSR_0_FUNC(x) ((uint32_t)(x) << 0U) #define POC_SD3_DS_33V BIT(29) #define POC_SD3_DAT7_33V BIT(28) #define POC_SD3_DAT6_33V BIT(27) #define POC_SD3_DAT5_33V BIT(26) #define POC_SD3_DAT4_33V BIT(25) #define POC_SD3_DAT3_33V BIT(24) #define POC_SD3_DAT2_33V BIT(23) #define POC_SD3_DAT1_33V BIT(22) #define POC_SD3_DAT0_33V BIT(21) #define POC_SD3_CMD_33V BIT(20) #define POC_SD3_CLK_33V BIT(19) #define POC_SD2_DS_33V BIT(18) #define POC_SD2_DAT3_33V BIT(17) #define POC_SD2_DAT2_33V BIT(16) #define POC_SD2_DAT1_33V BIT(15) #define POC_SD2_DAT0_33V BIT(14) #define POC_SD2_CMD_33V BIT(13) #define POC_SD2_CLK_33V BIT(12) #define POC_SD1_DAT3_33V BIT(11) #define POC_SD1_DAT2_33V BIT(10) #define POC_SD1_DAT1_33V BIT(9) #define POC_SD1_DAT0_33V BIT(8) #define POC_SD1_CMD_33V BIT(7) #define POC_SD1_CLK_33V BIT(6) #define POC_SD0_DAT3_33V BIT(5) #define POC_SD0_DAT2_33V BIT(4) #define POC_SD0_DAT1_33V BIT(3) #define POC_SD0_DAT0_33V BIT(2) #define POC_SD0_CMD_33V BIT(1) #define POC_SD0_CLK_33V BIT(0) #define DRVCTRL0_MASK (0xCCCCCCCCU) #define DRVCTRL1_MASK (0xCCCCCCC8U) #define DRVCTRL2_MASK (0x88888888U) #define DRVCTRL3_MASK (0x88888888U) #define DRVCTRL4_MASK (0x88888888U) #define DRVCTRL5_MASK (0x88888888U) #define DRVCTRL6_MASK (0x88888888U) #define DRVCTRL7_MASK (0x88888888U) #define DRVCTRL8_MASK (0x88888888U) #define DRVCTRL9_MASK (0x88888888U) #define DRVCTRL10_MASK (0x88888888U) #define DRVCTRL11_MASK (0x888888CCU) #define DRVCTRL12_MASK (0xCCCFFFCFU) #define DRVCTRL13_MASK (0xCC888888U) #define DRVCTRL14_MASK (0x88888888U) #define DRVCTRL15_MASK (0x88888888U) #define DRVCTRL16_MASK (0x88888888U) #define DRVCTRL17_MASK (0x88888888U) #define DRVCTRL18_MASK (0x88888888U) #define DRVCTRL19_MASK (0x88888888U) #define DRVCTRL20_MASK (0x88888888U) #define DRVCTRL21_MASK (0x88888888U) #define DRVCTRL22_MASK (0x88888888U) #define DRVCTRL23_MASK (0x88888888U) #define DRVCTRL24_MASK (0x8888888FU) #define DRVCTRL0_QSPI0_SPCLK(x) ((uint32_t)(x) << 28U) #define DRVCTRL0_QSPI0_MOSI_IO0(x) ((uint32_t)(x) << 24U) #define DRVCTRL0_QSPI0_MISO_IO1(x) ((uint32_t)(x) << 20U) #define DRVCTRL0_QSPI0_IO2(x) ((uint32_t)(x) << 16U) #define DRVCTRL0_QSPI0_IO3(x) ((uint32_t)(x) << 12U) #define DRVCTRL0_QSPI0_SSL(x) ((uint32_t)(x) << 8U) #define DRVCTRL0_QSPI1_SPCLK(x) ((uint32_t)(x) << 4U) #define DRVCTRL0_QSPI1_MOSI_IO0(x) ((uint32_t)(x) << 0U) #define DRVCTRL1_QSPI1_MISO_IO1(x) ((uint32_t)(x) << 28U) #define DRVCTRL1_QSPI1_IO2(x) ((uint32_t)(x) << 24U) #define DRVCTRL1_QSPI1_IO3(x) ((uint32_t)(x) << 20U) #define DRVCTRL1_QSPI1_SS(x) ((uint32_t)(x) << 16U) #define DRVCTRL1_RPC_INT(x) ((uint32_t)(x) << 12U) #define DRVCTRL1_RPC_WP(x) ((uint32_t)(x) << 8U) #define DRVCTRL1_RPC_RESET(x) ((uint32_t)(x) << 4U) #define DRVCTRL1_AVB_RX_CTL(x) ((uint32_t)(x) << 0U) #define DRVCTRL2_AVB_RXC(x) ((uint32_t)(x) << 28U) #define DRVCTRL2_AVB_RD0(x) ((uint32_t)(x) << 24U) #define DRVCTRL2_AVB_RD1(x) ((uint32_t)(x) << 20U) #define DRVCTRL2_AVB_RD2(x) ((uint32_t)(x) << 16U) #define DRVCTRL2_AVB_RD3(x) ((uint32_t)(x) << 12U) #define DRVCTRL2_AVB_TX_CTL(x) ((uint32_t)(x) << 8U) #define DRVCTRL2_AVB_TXC(x) ((uint32_t)(x) << 4U) #define DRVCTRL2_AVB_TD0(x) ((uint32_t)(x) << 0U) #define DRVCTRL3_AVB_TD1(x) ((uint32_t)(x) << 28U) #define DRVCTRL3_AVB_TD2(x) ((uint32_t)(x) << 24U) #define DRVCTRL3_AVB_TD3(x) ((uint32_t)(x) << 20U) #define DRVCTRL3_AVB_TXCREFCLK(x) ((uint32_t)(x) << 16U) #define DRVCTRL3_AVB_MDIO(x) ((uint32_t)(x) << 12U) #define DRVCTRL3_AVB_MDC(x) ((uint32_t)(x) << 8U) #define DRVCTRL3_AVB_MAGIC(x) ((uint32_t)(x) << 4U) #define DRVCTRL3_AVB_PHY_INT(x) ((uint32_t)(x) << 0U) #define DRVCTRL4_AVB_LINK(x) ((uint32_t)(x) << 28U) #define DRVCTRL4_AVB_AVTP_MATCH(x) ((uint32_t)(x) << 24U) #define DRVCTRL4_AVB_AVTP_CAPTURE(x) ((uint32_t)(x) << 20U) #define DRVCTRL4_IRQ0(x) ((uint32_t)(x) << 16U) #define DRVCTRL4_IRQ1(x) ((uint32_t)(x) << 12U) #define DRVCTRL4_IRQ2(x) ((uint32_t)(x) << 8U) #define DRVCTRL4_IRQ3(x) ((uint32_t)(x) << 4U) #define DRVCTRL4_IRQ4(x) ((uint32_t)(x) << 0U) #define DRVCTRL5_IRQ5(x) ((uint32_t)(x) << 28U) #define DRVCTRL5_PWM0(x) ((uint32_t)(x) << 24U) #define DRVCTRL5_PWM1(x) ((uint32_t)(x) << 20U) #define DRVCTRL5_PWM2(x) ((uint32_t)(x) << 16U) #define DRVCTRL5_A0(x) ((uint32_t)(x) << 12U) #define DRVCTRL5_A1(x) ((uint32_t)(x) << 8U) #define DRVCTRL5_A2(x) ((uint32_t)(x) << 4U) #define DRVCTRL5_A3(x) ((uint32_t)(x) << 0U) #define DRVCTRL6_A4(x) ((uint32_t)(x) << 28U) #define DRVCTRL6_A5(x) ((uint32_t)(x) << 24U) #define DRVCTRL6_A6(x) ((uint32_t)(x) << 20U) #define DRVCTRL6_A7(x) ((uint32_t)(x) << 16U) #define DRVCTRL6_A8(x) ((uint32_t)(x) << 12U) #define DRVCTRL6_A9(x) ((uint32_t)(x) << 8U) #define DRVCTRL6_A10(x) ((uint32_t)(x) << 4U) #define DRVCTRL6_A11(x) ((uint32_t)(x) << 0U) #define DRVCTRL7_A12(x) ((uint32_t)(x) << 28U) #define DRVCTRL7_A13(x) ((uint32_t)(x) << 24U) #define DRVCTRL7_A14(x) ((uint32_t)(x) << 20U) #define DRVCTRL7_A15(x) ((uint32_t)(x) << 16U) #define DRVCTRL7_A16(x) ((uint32_t)(x) << 12U) #define DRVCTRL7_A17(x) ((uint32_t)(x) << 8U) #define DRVCTRL7_A18(x) ((uint32_t)(x) << 4U) #define DRVCTRL7_A19(x) ((uint32_t)(x) << 0U) #define DRVCTRL8_CLKOUT(x) ((uint32_t)(x) << 28U) #define DRVCTRL8_CS0(x) ((uint32_t)(x) << 24U) #define DRVCTRL8_CS1_A2(x) ((uint32_t)(x) << 20U) #define DRVCTRL8_BS(x) ((uint32_t)(x) << 16U) #define DRVCTRL8_RD(x) ((uint32_t)(x) << 12U) #define DRVCTRL8_RD_W(x) ((uint32_t)(x) << 8U) #define DRVCTRL8_WE0(x) ((uint32_t)(x) << 4U) #define DRVCTRL8_WE1(x) ((uint32_t)(x) << 0U) #define DRVCTRL9_EX_WAIT0(x) ((uint32_t)(x) << 28U) #define DRVCTRL9_PRESETOU(x) ((uint32_t)(x) << 24U) #define DRVCTRL9_D0(x) ((uint32_t)(x) << 20U) #define DRVCTRL9_D1(x) ((uint32_t)(x) << 16U) #define DRVCTRL9_D2(x) ((uint32_t)(x) << 12U) #define DRVCTRL9_D3(x) ((uint32_t)(x) << 8U) #define DRVCTRL9_D4(x) ((uint32_t)(x) << 4U) #define DRVCTRL9_D5(x) ((uint32_t)(x) << 0U) #define DRVCTRL10_D6(x) ((uint32_t)(x) << 28U) #define DRVCTRL10_D7(x) ((uint32_t)(x) << 24U) #define DRVCTRL10_D8(x) ((uint32_t)(x) << 20U) #define DRVCTRL10_D9(x) ((uint32_t)(x) << 16U) #define DRVCTRL10_D10(x) ((uint32_t)(x) << 12U) #define DRVCTRL10_D11(x) ((uint32_t)(x) << 8U) #define DRVCTRL10_D12(x) ((uint32_t)(x) << 4U) #define DRVCTRL10_D13(x) ((uint32_t)(x) << 0U) #define DRVCTRL11_D14(x) ((uint32_t)(x) << 28U) #define DRVCTRL11_D15(x) ((uint32_t)(x) << 24U) #define DRVCTRL11_AVS1(x) ((uint32_t)(x) << 20U) #define DRVCTRL11_AVS2(x) ((uint32_t)(x) << 16U) #define DRVCTRL11_HDMI0_CEC(x) ((uint32_t)(x) << 12U) #define DRVCTRL11_HDMI1_CEC(x) ((uint32_t)(x) << 8U) #define DRVCTRL11_DU_DOTCLKIN0(x) ((uint32_t)(x) << 4U) #define DRVCTRL11_DU_DOTCLKIN1(x) ((uint32_t)(x) << 0U) #define DRVCTRL12_DU_DOTCLKIN2(x) ((uint32_t)(x) << 28U) #define DRVCTRL12_DU_DOTCLKIN3(x) ((uint32_t)(x) << 24U) #define DRVCTRL12_DU_FSCLKST(x) ((uint32_t)(x) << 20U) #define DRVCTRL12_DU_TMS(x) ((uint32_t)(x) << 4U) #define DRVCTRL13_TDO(x) ((uint32_t)(x) << 28U) #define DRVCTRL13_ASEBRK(x) ((uint32_t)(x) << 24U) #define DRVCTRL13_SD0_CLK(x) ((uint32_t)(x) << 20U) #define DRVCTRL13_SD0_CMD(x) ((uint32_t)(x) << 16U) #define DRVCTRL13_SD0_DAT0(x) ((uint32_t)(x) << 12U) #define DRVCTRL13_SD0_DAT1(x) ((uint32_t)(x) << 8U) #define DRVCTRL13_SD0_DAT2(x) ((uint32_t)(x) << 4U) #define DRVCTRL13_SD0_DAT3(x) ((uint32_t)(x) << 0U) #define DRVCTRL14_SD1_CLK(x) ((uint32_t)(x) << 28U) #define DRVCTRL14_SD1_CMD(x) ((uint32_t)(x) << 24U) #define DRVCTRL14_SD1_DAT0(x) ((uint32_t)(x) << 20U) #define DRVCTRL14_SD1_DAT1(x) ((uint32_t)(x) << 16U) #define DRVCTRL14_SD1_DAT2(x) ((uint32_t)(x) << 12U) #define DRVCTRL14_SD1_DAT3(x) ((uint32_t)(x) << 8U) #define DRVCTRL14_SD2_CLK(x) ((uint32_t)(x) << 4U) #define DRVCTRL14_SD2_CMD(x) ((uint32_t)(x) << 0U) #define DRVCTRL15_SD2_DAT0(x) ((uint32_t)(x) << 28U) #define DRVCTRL15_SD2_DAT1(x) ((uint32_t)(x) << 24U) #define DRVCTRL15_SD2_DAT2(x) ((uint32_t)(x) << 20U) #define DRVCTRL15_SD2_DAT3(x) ((uint32_t)(x) << 16U) #define DRVCTRL15_SD2_DS(x) ((uint32_t)(x) << 12U) #define DRVCTRL15_SD3_CLK(x) ((uint32_t)(x) << 8U) #define DRVCTRL15_SD3_CMD(x) ((uint32_t)(x) << 4U) #define DRVCTRL15_SD3_DAT0(x) ((uint32_t)(x) << 0U) #define DRVCTRL16_SD3_DAT1(x) ((uint32_t)(x) << 28U) #define DRVCTRL16_SD3_DAT2(x) ((uint32_t)(x) << 24U) #define DRVCTRL16_SD3_DAT3(x) ((uint32_t)(x) << 20U) #define DRVCTRL16_SD3_DAT4(x) ((uint32_t)(x) << 16U) #define DRVCTRL16_SD3_DAT5(x) ((uint32_t)(x) << 12U) #define DRVCTRL16_SD3_DAT6(x) ((uint32_t)(x) << 8U) #define DRVCTRL16_SD3_DAT7(x) ((uint32_t)(x) << 4U) #define DRVCTRL16_SD3_DS(x) ((uint32_t)(x) << 0U) #define DRVCTRL17_SD0_CD(x) ((uint32_t)(x) << 28U) #define DRVCTRL17_SD0_WP(x) ((uint32_t)(x) << 24U) #define DRVCTRL17_SD1_CD(x) ((uint32_t)(x) << 20U) #define DRVCTRL17_SD1_WP(x) ((uint32_t)(x) << 16U) #define DRVCTRL17_SCK0(x) ((uint32_t)(x) << 12U) #define DRVCTRL17_RX0(x) ((uint32_t)(x) << 8U) #define DRVCTRL17_TX0(x) ((uint32_t)(x) << 4U) #define DRVCTRL17_CTS0(x) ((uint32_t)(x) << 0U) #define DRVCTRL18_RTS0_TANS(x) ((uint32_t)(x) << 28U) #define DRVCTRL18_RX1(x) ((uint32_t)(x) << 24U) #define DRVCTRL18_TX1(x) ((uint32_t)(x) << 20U) #define DRVCTRL18_CTS1(x) ((uint32_t)(x) << 16U) #define DRVCTRL18_RTS1_TANS(x) ((uint32_t)(x) << 12U) #define DRVCTRL18_SCK2(x) ((uint32_t)(x) << 8U) #define DRVCTRL18_TX2(x) ((uint32_t)(x) << 4U) #define DRVCTRL18_RX2(x) ((uint32_t)(x) << 0U) #define DRVCTRL19_HSCK0(x) ((uint32_t)(x) << 28U) #define DRVCTRL19_HRX0(x) ((uint32_t)(x) << 24U) #define DRVCTRL19_HTX0(x) ((uint32_t)(x) << 20U) #define DRVCTRL19_HCTS0(x) ((uint32_t)(x) << 16U) #define DRVCTRL19_HRTS0(x) ((uint32_t)(x) << 12U) #define DRVCTRL19_MSIOF0_SCK(x) ((uint32_t)(x) << 8U) #define DRVCTRL19_MSIOF0_SYNC(x) ((uint32_t)(x) << 4U) #define DRVCTRL19_MSIOF0_SS1(x) ((uint32_t)(x) << 0U) #define DRVCTRL20_MSIOF0_TXD(x) ((uint32_t)(x) << 28U) #define DRVCTRL20_MSIOF0_SS2(x) ((uint32_t)(x) << 24U) #define DRVCTRL20_MSIOF0_RXD(x) ((uint32_t)(x) << 20U) #define DRVCTRL20_MLB_CLK(x) ((uint32_t)(x) << 16U) #define DRVCTRL20_MLB_SIG(x) ((uint32_t)(x) << 12U) #define DRVCTRL20_MLB_DAT(x) ((uint32_t)(x) << 8U) #define DRVCTRL20_MLB_REF(x) ((uint32_t)(x) << 4U) #define DRVCTRL20_SSI_SCK0129(x) ((uint32_t)(x) << 0U) #define DRVCTRL21_SSI_WS0129(x) ((uint32_t)(x) << 28U) #define DRVCTRL21_SSI_SDATA0(x) ((uint32_t)(x) << 24U) #define DRVCTRL21_SSI_SDATA1(x) ((uint32_t)(x) << 20U) #define DRVCTRL21_SSI_SDATA2(x) ((uint32_t)(x) << 16U) #define DRVCTRL21_SSI_SCK34(x) ((uint32_t)(x) << 12U) #define DRVCTRL21_SSI_WS34(x) ((uint32_t)(x) << 8U) #define DRVCTRL21_SSI_SDATA3(x) ((uint32_t)(x) << 4U) #define DRVCTRL21_SSI_SCK4(x) ((uint32_t)(x) << 0U) #define DRVCTRL22_SSI_WS4(x) ((uint32_t)(x) << 28U) #define DRVCTRL22_SSI_SDATA4(x) ((uint32_t)(x) << 24U) #define DRVCTRL22_SSI_SCK5(x) ((uint32_t)(x) << 20U) #define DRVCTRL22_SSI_WS5(x) ((uint32_t)(x) << 16U) #define DRVCTRL22_SSI_SDATA5(x) ((uint32_t)(x) << 12U) #define DRVCTRL22_SSI_SCK6(x) ((uint32_t)(x) << 8U) #define DRVCTRL22_SSI_WS6(x) ((uint32_t)(x) << 4U) #define DRVCTRL22_SSI_SDATA6(x) ((uint32_t)(x) << 0U) #define DRVCTRL23_SSI_SCK78(x) ((uint32_t)(x) << 28U) #define DRVCTRL23_SSI_WS78(x) ((uint32_t)(x) << 24U) #define DRVCTRL23_SSI_SDATA7(x) ((uint32_t)(x) << 20U) #define DRVCTRL23_SSI_SDATA8(x) ((uint32_t)(x) << 16U) #define DRVCTRL23_SSI_SDATA9(x) ((uint32_t)(x) << 12U) #define DRVCTRL23_AUDIO_CLKA(x) ((uint32_t)(x) << 8U) #define DRVCTRL23_AUDIO_CLKB(x) ((uint32_t)(x) << 4U) #define DRVCTRL23_USB0_PWEN(x) ((uint32_t)(x) << 0U) #define DRVCTRL24_USB0_OVC(x) ((uint32_t)(x) << 28U) #define DRVCTRL24_USB1_PWEN(x) ((uint32_t)(x) << 24U) #define DRVCTRL24_USB1_OVC(x) ((uint32_t)(x) << 20U) #define DRVCTRL24_USB30_PWEN(x) ((uint32_t)(x) << 16U) #define DRVCTRL24_USB30_OVC(x) ((uint32_t)(x) << 12U) #define DRVCTRL24_USB31_PWEN(x) ((uint32_t)(x) << 8U) #define DRVCTRL24_USB31_OVC(x) ((uint32_t)(x) << 4U) #define MOD_SEL0_MSIOF3_A ((uint32_t)0U << 29U) #define MOD_SEL0_MSIOF3_B ((uint32_t)1U << 29U) #define MOD_SEL0_MSIOF3_C ((uint32_t)2U << 29U) #define MOD_SEL0_MSIOF3_D ((uint32_t)3U << 29U) #define MOD_SEL0_MSIOF3_E ((uint32_t)4U << 29U) #define MOD_SEL0_MSIOF2_A ((uint32_t)0U << 27U) #define MOD_SEL0_MSIOF2_B ((uint32_t)1U << 27U) #define MOD_SEL0_MSIOF2_C ((uint32_t)2U << 27U) #define MOD_SEL0_MSIOF2_D ((uint32_t)3U << 27U) #define MOD_SEL0_MSIOF1_A ((uint32_t)0U << 24U) #define MOD_SEL0_MSIOF1_B ((uint32_t)1U << 24U) #define MOD_SEL0_MSIOF1_C ((uint32_t)2U << 24U) #define MOD_SEL0_MSIOF1_D ((uint32_t)3U << 24U) #define MOD_SEL0_MSIOF1_E ((uint32_t)4U << 24U) #define MOD_SEL0_MSIOF1_F ((uint32_t)5U << 24U) #define MOD_SEL0_MSIOF1_G ((uint32_t)6U << 24U) #define MOD_SEL0_LBSC_A ((uint32_t)0U << 23U) #define MOD_SEL0_LBSC_B ((uint32_t)1U << 23U) #define MOD_SEL0_IEBUS_A ((uint32_t)0U << 22U) #define MOD_SEL0_IEBUS_B ((uint32_t)1U << 22U) #define MOD_SEL0_I2C2_A ((uint32_t)0U << 21U) #define MOD_SEL0_I2C2_B ((uint32_t)1U << 21U) #define MOD_SEL0_I2C1_A ((uint32_t)0U << 20U) #define MOD_SEL0_I2C1_B ((uint32_t)1U << 20U) #define MOD_SEL0_HSCIF4_A ((uint32_t)0U << 19U) #define MOD_SEL0_HSCIF4_B ((uint32_t)1U << 19U) #define MOD_SEL0_HSCIF3_A ((uint32_t)0U << 17U) #define MOD_SEL0_HSCIF3_B ((uint32_t)1U << 17U) #define MOD_SEL0_HSCIF3_C ((uint32_t)2U << 17U) #define MOD_SEL0_HSCIF3_D ((uint32_t)3U << 17U) #define MOD_SEL0_HSCIF1_A ((uint32_t)0U << 16U) #define MOD_SEL0_HSCIF1_B ((uint32_t)1U << 16U) #define MOD_SEL0_FSO_A ((uint32_t)0U << 15U) #define MOD_SEL0_FSO_B ((uint32_t)1U << 15U) #define MOD_SEL0_HSCIF2_A ((uint32_t)0U << 13U) #define MOD_SEL0_HSCIF2_B ((uint32_t)1U << 13U) #define MOD_SEL0_HSCIF2_C ((uint32_t)2U << 13U) #define MOD_SEL0_ETHERAVB_A ((uint32_t)0U << 12U) #define MOD_SEL0_ETHERAVB_B ((uint32_t)1U << 12U) #define MOD_SEL0_DRIF3_A ((uint32_t)0U << 11U) #define MOD_SEL0_DRIF3_B ((uint32_t)1U << 11U) #define MOD_SEL0_DRIF2_A ((uint32_t)0U << 10U) #define MOD_SEL0_DRIF2_B ((uint32_t)1U << 10U) #define MOD_SEL0_DRIF1_A ((uint32_t)0U << 8U) #define MOD_SEL0_DRIF1_B ((uint32_t)1U << 8U) #define MOD_SEL0_DRIF1_C ((uint32_t)2U << 8U) #define MOD_SEL0_DRIF0_A ((uint32_t)0U << 6U) #define MOD_SEL0_DRIF0_B ((uint32_t)1U << 6U) #define MOD_SEL0_DRIF0_C ((uint32_t)2U << 6U) #define MOD_SEL0_CANFD0_A ((uint32_t)0U << 5U) #define MOD_SEL0_CANFD0_B ((uint32_t)1U << 5U) #define MOD_SEL0_ADG_A_A ((uint32_t)0U << 3U) #define MOD_SEL0_ADG_A_B ((uint32_t)1U << 3U) #define MOD_SEL0_ADG_A_C ((uint32_t)2U << 3U) #define MOD_SEL1_TSIF1_A ((uint32_t)0U << 30U) #define MOD_SEL1_TSIF1_B ((uint32_t)1U << 30U) #define MOD_SEL1_TSIF1_C ((uint32_t)2U << 30U) #define MOD_SEL1_TSIF1_D ((uint32_t)3U << 30U) #define MOD_SEL1_TSIF0_A ((uint32_t)0U << 27U) #define MOD_SEL1_TSIF0_B ((uint32_t)1U << 27U) #define MOD_SEL1_TSIF0_C ((uint32_t)2U << 27U) #define MOD_SEL1_TSIF0_D ((uint32_t)3U << 27U) #define MOD_SEL1_TSIF0_E ((uint32_t)4U << 27U) #define MOD_SEL1_TIMER_TMU_A ((uint32_t)0U << 26U) #define MOD_SEL1_TIMER_TMU_B ((uint32_t)1U << 26U) #define MOD_SEL1_SSP1_1_A ((uint32_t)0U << 24U) #define MOD_SEL1_SSP1_1_B ((uint32_t)1U << 24U) #define MOD_SEL1_SSP1_1_C ((uint32_t)2U << 24U) #define MOD_SEL1_SSP1_1_D ((uint32_t)3U << 24U) #define MOD_SEL1_SSP1_0_A ((uint32_t)0U << 21U) #define MOD_SEL1_SSP1_0_B ((uint32_t)1U << 21U) #define MOD_SEL1_SSP1_0_C ((uint32_t)2U << 21U) #define MOD_SEL1_SSP1_0_D ((uint32_t)3U << 21U) #define MOD_SEL1_SSP1_0_E ((uint32_t)4U << 21U) #define MOD_SEL1_SSI_A ((uint32_t)0U << 20U) #define MOD_SEL1_SSI_B ((uint32_t)1U << 20U) #define MOD_SEL1_SPEED_PULSE_IF_A ((uint32_t)0U << 19U) #define MOD_SEL1_SPEED_PULSE_IF_B ((uint32_t)1U << 19U) #define MOD_SEL1_SIMCARD_A ((uint32_t)0U << 17U) #define MOD_SEL1_SIMCARD_B ((uint32_t)1U << 17U) #define MOD_SEL1_SIMCARD_C ((uint32_t)2U << 17U) #define MOD_SEL1_SIMCARD_D ((uint32_t)3U << 17U) #define MOD_SEL1_SDHI2_A ((uint32_t)0U << 16U) #define MOD_SEL1_SDHI2_B ((uint32_t)1U << 16U) #define MOD_SEL1_SCIF4_A ((uint32_t)0U << 14U) #define MOD_SEL1_SCIF4_B ((uint32_t)1U << 14U) #define MOD_SEL1_SCIF4_C ((uint32_t)2U << 14U) #define MOD_SEL1_SCIF3_A ((uint32_t)0U << 13U) #define MOD_SEL1_SCIF3_B ((uint32_t)1U << 13U) #define MOD_SEL1_SCIF2_A ((uint32_t)0U << 12U) #define MOD_SEL1_SCIF2_B ((uint32_t)1U << 12U) #define MOD_SEL1_SCIF1_A ((uint32_t)0U << 11U) #define MOD_SEL1_SCIF1_B ((uint32_t)1U << 11U) #define MOD_SEL1_SCIF_A ((uint32_t)0U << 10U) #define MOD_SEL1_SCIF_B ((uint32_t)1U << 10U) #define MOD_SEL1_REMOCON_A ((uint32_t)0U << 9U) #define MOD_SEL1_REMOCON_B ((uint32_t)1U << 9U) #define MOD_SEL1_RCAN0_A ((uint32_t)0U << 6U) #define MOD_SEL1_RCAN0_B ((uint32_t)1U << 6U) #define MOD_SEL1_PWM6_A ((uint32_t)0U << 5U) #define MOD_SEL1_PWM6_B ((uint32_t)1U << 5U) #define MOD_SEL1_PWM5_A ((uint32_t)0U << 4U) #define MOD_SEL1_PWM5_B ((uint32_t)1U << 4U) #define MOD_SEL1_PWM4_A ((uint32_t)0U << 3U) #define MOD_SEL1_PWM4_B ((uint32_t)1U << 3U) #define MOD_SEL1_PWM3_A ((uint32_t)0U << 2U) #define MOD_SEL1_PWM3_B ((uint32_t)1U << 2U) #define MOD_SEL1_PWM2_A ((uint32_t)0U << 1U) #define MOD_SEL1_PWM2_B ((uint32_t)1U << 1U) #define MOD_SEL1_PWM1_A ((uint32_t)0U << 0U) #define MOD_SEL1_PWM1_B ((uint32_t)1U << 0U) #define MOD_SEL2_I2C_5_A ((uint32_t)0U << 31U) #define MOD_SEL2_I2C_5_B ((uint32_t)1U << 31U) #define MOD_SEL2_I2C_3_A ((uint32_t)0U << 30U) #define MOD_SEL2_I2C_3_B ((uint32_t)1U << 30U) #define MOD_SEL2_I2C_0_A ((uint32_t)0U << 29U) #define MOD_SEL2_I2C_0_B ((uint32_t)1U << 29U) #define MOD_SEL2_FM_A ((uint32_t)0U << 27U) #define MOD_SEL2_FM_B ((uint32_t)1U << 27U) #define MOD_SEL2_FM_C ((uint32_t)2U << 27U) #define MOD_SEL2_FM_D ((uint32_t)3U << 27U) #define MOD_SEL2_SCIF5_A ((uint32_t)0U << 26U) #define MOD_SEL2_SCIF5_B ((uint32_t)1U << 26U) #define MOD_SEL2_I2C6_A ((uint32_t)0U << 23U) #define MOD_SEL2_I2C6_B ((uint32_t)1U << 23U) #define MOD_SEL2_I2C6_C ((uint32_t)2U << 23U) #define MOD_SEL2_NDF_A ((uint32_t)0U << 22U) #define MOD_SEL2_NDF_B ((uint32_t)1U << 22U) #define MOD_SEL2_SSI2_A ((uint32_t)0U << 21U) #define MOD_SEL2_SSI2_B ((uint32_t)1U << 21U) #define MOD_SEL2_SSI9_A ((uint32_t)0U << 20U) #define MOD_SEL2_SSI9_B ((uint32_t)1U << 20U) #define MOD_SEL2_TIMER_TMU2_A ((uint32_t)0U << 19U) #define MOD_SEL2_TIMER_TMU2_B ((uint32_t)1U << 19U) #define MOD_SEL2_ADG_B_A ((uint32_t)0U << 18U) #define MOD_SEL2_ADG_B_B ((uint32_t)1U << 18U) #define MOD_SEL2_ADG_C_A ((uint32_t)0U << 17U) #define MOD_SEL2_ADG_C_B ((uint32_t)1U << 17U) #define MOD_SEL2_VIN4_A ((uint32_t)0U << 0U) #define MOD_SEL2_VIN4_B ((uint32_t)1U << 0U) static void pfc_reg_write(uint32_t addr, uint32_t data) { mmio_write_32(PFC_PMMR, ~data); mmio_write_32((uintptr_t)addr, data); } void pfc_init_d3(void) { /* initialize module select */ pfc_reg_write(PFC_MOD_SEL0, 0x00000000U); pfc_reg_write(PFC_MOD_SEL1, 0x00000000U); /* initialize peripheral function select */ pfc_reg_write(PFC_IPSR0, 0x00000001U); pfc_reg_write(PFC_IPSR1, 0x00000000U); pfc_reg_write(PFC_IPSR2, 0x00000000U); pfc_reg_write(PFC_IPSR3, 0x00000000U); pfc_reg_write(PFC_IPSR4, 0x00002000U); pfc_reg_write(PFC_IPSR5, 0x00000000U); pfc_reg_write(PFC_IPSR6, 0x00000000U); pfc_reg_write(PFC_IPSR7, 0x00000000U); pfc_reg_write(PFC_IPSR8, 0x11003301U); pfc_reg_write(PFC_IPSR9, 0x11111111U); pfc_reg_write(PFC_IPSR10, 0x00020000U); pfc_reg_write(PFC_IPSR11, 0x40001110U); pfc_reg_write(PFC_IPSR12, 0x00000000U); pfc_reg_write(PFC_IPSR13, 0x00000000U); /* initialize GPIO/perihperal function select */ pfc_reg_write(PFC_GPSR0, 0x0000001FU); pfc_reg_write(PFC_GPSR1, 0x3FFFFFFFU); pfc_reg_write(PFC_GPSR2, 0xFFFFFFFFU); pfc_reg_write(PFC_GPSR3, 0x000003FFU); pfc_reg_write(PFC_GPSR4, 0xFC7F0F7EU); pfc_reg_write(PFC_GPSR5, 0x001BFFFBU); pfc_reg_write(PFC_GPSR6, 0x00003FFFU); /* initialize POC control register */ pfc_reg_write(PFC_POCCTRL0, 0xC00FFFFFU); pfc_reg_write(PFC_POCCTRL2, 0XFFFFFFFEU); pfc_reg_write(PFC_TDSELCTRL0, 0x00000000U); /* initialize LSI pin pull-up/down control */ pfc_reg_write(PFC_PUD0, 0x0047C1A2U); pfc_reg_write(PFC_PUD1, 0x4E13ABFFU); pfc_reg_write(PFC_PUD2, 0xFFFFFFFFU); pfc_reg_write(PFC_PUD3, 0xFF0FFFFFU); pfc_reg_write(PFC_PUD4, 0xE0000000U); pfc_reg_write(PFC_PUD5, 0x60000000U); /* initialize LSI pin pull-enable register */ pfc_reg_write(PFC_PUEN0, 0x00000000U); pfc_reg_write(PFC_PUEN1, 0x00000000U); pfc_reg_write(PFC_PUEN2, 0x00000000U); pfc_reg_write(PFC_PUEN3, 0x000F008CU); pfc_reg_write(PFC_PUEN4, 0x00000000U); pfc_reg_write(PFC_PUEN5, 0x00000000U); /* initialize positive/negative logic select */ mmio_write_32(GPIO_POSNEG0, 0x00000000U); mmio_write_32(GPIO_POSNEG1, 0x00000000U); mmio_write_32(GPIO_POSNEG2, 0x00000000U); mmio_write_32(GPIO_POSNEG3, 0x00000000U); mmio_write_32(GPIO_POSNEG4, 0x00000000U); mmio_write_32(GPIO_POSNEG5, 0x00000000U); mmio_write_32(GPIO_POSNEG6, 0x00000000U); /* initialize general IO/interrupt switching */ mmio_write_32(GPIO_IOINTSEL0, 0x00000000U); mmio_write_32(GPIO_IOINTSEL1, 0x00000000U); mmio_write_32(GPIO_IOINTSEL2, 0x00000000U); mmio_write_32(GPIO_IOINTSEL3, 0x00000000U); mmio_write_32(GPIO_IOINTSEL4, 0x00000000U); mmio_write_32(GPIO_IOINTSEL5, 0x00000000U); mmio_write_32(GPIO_IOINTSEL6, 0x00000000U); /* initialize general output register */ mmio_write_32(GPIO_OUTDT0, 0x00000000U); mmio_write_32(GPIO_OUTDT1, 0x00000000U); mmio_write_32(GPIO_OUTDT2, 0x00000400U); mmio_write_32(GPIO_OUTDT3, 0x00000000U); mmio_write_32(GPIO_OUTDT4, 0x00000000U); mmio_write_32(GPIO_OUTDT5, 0x00000006U); mmio_write_32(GPIO_OUTDT6, 0x00003880U); /* initialize general input/output switching */ mmio_write_32(GPIO_INOUTSEL0, 0x00000000U); mmio_write_32(GPIO_INOUTSEL1, 0x00000000U); mmio_write_32(GPIO_INOUTSEL2, 0x00000000U); mmio_write_32(GPIO_INOUTSEL3, 0x00000000U); mmio_write_32(GPIO_INOUTSEL4, 0x00802000U); mmio_write_32(GPIO_INOUTSEL5, 0x00000000U); mmio_write_32(GPIO_INOUTSEL6, 0x00000000U); } trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/D3/pfc_init_d3.h000066400000000000000000000003421355360272700245250ustar00rootroot00000000000000/* * Copyright (c) 2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PFC_INIT_D3_H #define PFC_INIT_D3_H void pfc_init_d3(void); #endif /* PFC_INIT_D3_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/E3/000077500000000000000000000000001355360272700221755ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/E3/pfc_init_e3.c000066400000000000000000000531171355360272700245320ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* for uint32_t */ #include #include "pfc_init_e3.h" #include "rcar_def.h" #include "../pfc_regs.h" /* PFC */ #define GPSR0_SDA4 BIT(17) #define GPSR0_SCL4 BIT(16) #define GPSR0_D15 BIT(15) #define GPSR0_D14 BIT(14) #define GPSR0_D13 BIT(13) #define GPSR0_D12 BIT(12) #define GPSR0_D11 BIT(11) #define GPSR0_D10 BIT(10) #define GPSR0_D9 BIT(9) #define GPSR0_D8 BIT(8) #define GPSR0_D7 BIT(7) #define GPSR0_D6 BIT(6) #define GPSR0_D5 BIT(5) #define GPSR0_D4 BIT(4) #define GPSR0_D3 BIT(3) #define GPSR0_D2 BIT(2) #define GPSR0_D1 BIT(1) #define GPSR0_D0 BIT(0) #define GPSR1_WE0 BIT(22) #define GPSR1_CS0 BIT(21) #define GPSR1_CLKOUT BIT(20) #define GPSR1_A19 BIT(19) #define GPSR1_A18 BIT(18) #define GPSR1_A17 BIT(17) #define GPSR1_A16 BIT(16) #define GPSR1_A15 BIT(15) #define GPSR1_A14 BIT(14) #define GPSR1_A13 BIT(13) #define GPSR1_A12 BIT(12) #define GPSR1_A11 BIT(11) #define GPSR1_A10 BIT(10) #define GPSR1_A9 BIT(9) #define GPSR1_A8 BIT(8) #define GPSR1_A7 BIT(7) #define GPSR1_A6 BIT(6) #define GPSR1_A5 BIT(5) #define GPSR1_A4 BIT(4) #define GPSR1_A3 BIT(3) #define GPSR1_A2 BIT(2) #define GPSR1_A1 BIT(1) #define GPSR1_A0 BIT(0) #define GPSR2_BIT27_REVERSED BIT(27) #define GPSR2_BIT26_REVERSED BIT(26) #define GPSR2_EX_WAIT0 BIT(25) #define GPSR2_RD_WR BIT(24) #define GPSR2_RD BIT(23) #define GPSR2_BS BIT(22) #define GPSR2_AVB_PHY_INT BIT(21) #define GPSR2_AVB_TXCREFCLK BIT(20) #define GPSR2_AVB_RD3 BIT(19) #define GPSR2_AVB_RD2 BIT(18) #define GPSR2_AVB_RD1 BIT(17) #define GPSR2_AVB_RD0 BIT(16) #define GPSR2_AVB_RXC BIT(15) #define GPSR2_AVB_RX_CTL BIT(14) #define GPSR2_RPC_RESET BIT(13) #define GPSR2_RPC_RPC_INT BIT(12) #define GPSR2_QSPI1_SSL BIT(11) #define GPSR2_QSPI1_IO3 BIT(10) #define GPSR2_QSPI1_IO2 BIT(9) #define GPSR2_QSPI1_MISO_IO1 BIT(8) #define GPSR2_QSPI1_MOSI_IO0 BIT(7) #define GPSR2_QSPI1_SPCLK BIT(6) #define GPSR2_QSPI0_SSL BIT(5) #define GPSR2_QSPI0_IO3 BIT(4) #define GPSR2_QSPI0_IO2 BIT(3) #define GPSR2_QSPI0_MISO_IO1 BIT(2) #define GPSR2_QSPI0_MOSI_IO0 BIT(1) #define GPSR2_QSPI0_SPCLK BIT(0) #define GPSR3_SD1_WP BIT(15) #define GPSR3_SD1_CD BIT(14) #define GPSR3_SD0_WP BIT(13) #define GPSR3_SD0_CD BIT(12) #define GPSR3_SD1_DAT3 BIT(11) #define GPSR3_SD1_DAT2 BIT(10) #define GPSR3_SD1_DAT1 BIT(9) #define GPSR3_SD1_DAT0 BIT(8) #define GPSR3_SD1_CMD BIT(7) #define GPSR3_SD1_CLK BIT(6) #define GPSR3_SD0_DAT3 BIT(5) #define GPSR3_SD0_DAT2 BIT(4) #define GPSR3_SD0_DAT1 BIT(3) #define GPSR3_SD0_DAT0 BIT(2) #define GPSR3_SD0_CMD BIT(1) #define GPSR3_SD0_CLK BIT(0) #define GPSR4_SD3_DS BIT(10) #define GPSR4_SD3_DAT7 BIT(9) #define GPSR4_SD3_DAT6 BIT(8) #define GPSR4_SD3_DAT5 BIT(7) #define GPSR4_SD3_DAT4 BIT(6) #define GPSR4_SD3_DAT3 BIT(5) #define GPSR4_SD3_DAT2 BIT(4) #define GPSR4_SD3_DAT1 BIT(3) #define GPSR4_SD3_DAT0 BIT(2) #define GPSR4_SD3_CMD BIT(1) #define GPSR4_SD3_CLK BIT(0) #define GPSR5_MLB_DAT BIT(19) #define GPSR5_MLB_SIG BIT(18) #define GPSR5_MLB_CLK BIT(17) #define GPSR5_SSI_SDATA9 BIT(16) #define GPSR5_MSIOF0_SS2 BIT(15) #define GPSR5_MSIOF0_SS1 BIT(14) #define GPSR5_MSIOF0_SYNC BIT(13) #define GPSR5_MSIOF0_TXD BIT(12) #define GPSR5_MSIOF0_RXD BIT(11) #define GPSR5_MSIOF0_SCK BIT(10) #define GPSR5_RX2_A BIT(9) #define GPSR5_TX2_A BIT(8) #define GPSR5_SCK2_A BIT(7) #define GPSR5_TX1 BIT(6) #define GPSR5_RX1 BIT(5) #define GPSR5_RTS0_A BIT(4) #define GPSR5_CTS0_A BIT(3) #define GPSR5_TX0_A BIT(2) #define GPSR5_RX0_A BIT(1) #define GPSR5_SCK0_A BIT(0) #define GPSR6_USB30_PWEN BIT(17) #define GPSR6_SSI_SDATA6 BIT(16) #define GPSR6_SSI_WS6 BIT(15) #define GPSR6_SSI_SCK6 BIT(14) #define GPSR6_SSI_SDATA5 BIT(13) #define GPSR6_SSI_WS5 BIT(12) #define GPSR6_SSI_SCK5 BIT(11) #define GPSR6_SSI_SDATA4 BIT(10) #define GPSR6_USB30_OVC BIT(9) #define GPSR6_AUDIO_CLKA BIT(8) #define GPSR6_SSI_SDATA3 BIT(7) #define GPSR6_SSI_WS349 BIT(6) #define GPSR6_SSI_SCK349 BIT(5) #define GPSR6_SSI_SDATA2 BIT(4) #define GPSR6_SSI_SDATA1 BIT(3) #define GPSR6_SSI_SDATA0 BIT(2) #define GPSR6_SSI_WS01239 BIT(1) #define GPSR6_SSI_SCK01239 BIT(0) #define IPSR_28_FUNC(x) ((uint32_t)(x) << 28U) #define IPSR_24_FUNC(x) ((uint32_t)(x) << 24U) #define IPSR_20_FUNC(x) ((uint32_t)(x) << 20U) #define IPSR_16_FUNC(x) ((uint32_t)(x) << 16U) #define IPSR_12_FUNC(x) ((uint32_t)(x) << 12U) #define IPSR_8_FUNC(x) ((uint32_t)(x) << 8U) #define IPSR_4_FUNC(x) ((uint32_t)(x) << 4U) #define IPSR_0_FUNC(x) ((uint32_t)(x) << 0U) #define POCCTRL0_MASK (0x0007F000U) #define POC_SD3_DS_33V BIT(29) #define POC_SD3_DAT7_33V BIT(28) #define POC_SD3_DAT6_33V BIT(27) #define POC_SD3_DAT5_33V BIT(26) #define POC_SD3_DAT4_33V BIT(25) #define POC_SD3_DAT3_33V BIT(24) #define POC_SD3_DAT2_33V BIT(23) #define POC_SD3_DAT1_33V BIT(22) #define POC_SD3_DAT0_33V BIT(21) #define POC_SD3_CMD_33V BIT(20) #define POC_SD3_CLK_33V BIT(19) #define POC_SD1_DAT3_33V BIT(11) #define POC_SD1_DAT2_33V BIT(10) #define POC_SD1_DAT1_33V BIT(9) #define POC_SD1_DAT0_33V BIT(8) #define POC_SD1_CMD_33V BIT(7) #define POC_SD1_CLK_33V BIT(6) #define POC_SD0_DAT3_33V BIT(5) #define POC_SD0_DAT2_33V BIT(4) #define POC_SD0_DAT1_33V BIT(3) #define POC_SD0_DAT0_33V BIT(2) #define POC_SD0_CMD_33V BIT(1) #define POC_SD0_CLK_33V BIT(0) #define POCCTRL2_MASK (0xFFFFFFFEU) #define POC2_VREF_33V BIT(0) #define MOD_SEL0_ADGB_A ((uint32_t)0U << 29U) #define MOD_SEL0_ADGB_B ((uint32_t)1U << 29U) #define MOD_SEL0_ADGB_C ((uint32_t)2U << 29U) #define MOD_SEL0_DRIF0_A ((uint32_t)0U << 28U) #define MOD_SEL0_DRIF0_B ((uint32_t)1U << 28U) #define MOD_SEL0_FM_A ((uint32_t)0U << 26U) #define MOD_SEL0_FM_B ((uint32_t)1U << 26U) #define MOD_SEL0_FM_C ((uint32_t)2U << 26U) #define MOD_SEL0_FSO_A ((uint32_t)0U << 25U) #define MOD_SEL0_FSO_B ((uint32_t)1U << 25U) #define MOD_SEL0_HSCIF0_A ((uint32_t)0U << 24U) #define MOD_SEL0_HSCIF0_B ((uint32_t)1U << 24U) #define MOD_SEL0_HSCIF1_A ((uint32_t)0U << 23U) #define MOD_SEL0_HSCIF1_B ((uint32_t)1U << 23U) #define MOD_SEL0_HSCIF2_A ((uint32_t)0U << 22U) #define MOD_SEL0_HSCIF2_B ((uint32_t)1U << 22U) #define MOD_SEL0_I2C1_A ((uint32_t)0U << 20U) #define MOD_SEL0_I2C1_B ((uint32_t)1U << 20U) #define MOD_SEL0_I2C1_C ((uint32_t)2U << 20U) #define MOD_SEL0_I2C1_D ((uint32_t)3U << 20U) #define MOD_SEL0_I2C2_A ((uint32_t)0U << 17U) #define MOD_SEL0_I2C2_B ((uint32_t)1U << 17U) #define MOD_SEL0_I2C2_C ((uint32_t)2U << 17U) #define MOD_SEL0_I2C2_D ((uint32_t)3U << 17U) #define MOD_SEL0_I2C2_E ((uint32_t)4U << 17U) #define MOD_SEL0_NDFC_A ((uint32_t)0U << 16U) #define MOD_SEL0_NDFC_B ((uint32_t)1U << 16U) #define MOD_SEL0_PWM0_A ((uint32_t)0U << 15U) #define MOD_SEL0_PWM0_B ((uint32_t)1U << 15U) #define MOD_SEL0_PWM1_A ((uint32_t)0U << 14U) #define MOD_SEL0_PWM1_B ((uint32_t)1U << 14U) #define MOD_SEL0_PWM2_A ((uint32_t)0U << 12U) #define MOD_SEL0_PWM2_B ((uint32_t)1U << 12U) #define MOD_SEL0_PWM2_C ((uint32_t)2U << 12U) #define MOD_SEL0_PWM3_A ((uint32_t)0U << 10U) #define MOD_SEL0_PWM3_B ((uint32_t)1U << 10U) #define MOD_SEL0_PWM3_C ((uint32_t)2U << 10U) #define MOD_SEL0_PWM4_A ((uint32_t)0U << 9U) #define MOD_SEL0_PWM4_B ((uint32_t)1U << 9U) #define MOD_SEL0_PWM5_A ((uint32_t)0U << 8U) #define MOD_SEL0_PWM5_B ((uint32_t)1U << 8U) #define MOD_SEL0_PWM6_A ((uint32_t)0U << 7U) #define MOD_SEL0_PWM6_B ((uint32_t)1U << 7U) #define MOD_SEL0_REMOCON_A ((uint32_t)0U << 5U) #define MOD_SEL0_REMOCON_B ((uint32_t)1U << 5U) #define MOD_SEL0_REMOCON_C ((uint32_t)2U << 5U) #define MOD_SEL0_SCIF_A ((uint32_t)0U << 4U) #define MOD_SEL0_SCIF_B ((uint32_t)1U << 4U) #define MOD_SEL0_SCIF0_A ((uint32_t)0U << 3U) #define MOD_SEL0_SCIF0_B ((uint32_t)1U << 3U) #define MOD_SEL0_SCIF2_A ((uint32_t)0U << 2U) #define MOD_SEL0_SCIF2_B ((uint32_t)1U << 2U) #define MOD_SEL0_SPEED_PULSE_IF_A ((uint32_t)0U << 0U) #define MOD_SEL0_SPEED_PULSE_IF_B ((uint32_t)1U << 0U) #define MOD_SEL0_SPEED_PULSE_IF_C ((uint32_t)2U << 0U) #define MOD_SEL1_SIMCARD_A ((uint32_t)0U << 31U) #define MOD_SEL1_SIMCARD_B ((uint32_t)1U << 31U) #define MOD_SEL1_SSI2_A ((uint32_t)0U << 30U) #define MOD_SEL1_SSI2_B ((uint32_t)1U << 30U) #define MOD_SEL1_TIMER_TMU_A ((uint32_t)0U << 29U) #define MOD_SEL1_TIMER_TMU_B ((uint32_t)1U << 29U) #define MOD_SEL1_USB20_CH0_A ((uint32_t)0U << 28U) #define MOD_SEL1_USB20_CH0_B ((uint32_t)1U << 28U) #define MOD_SEL1_DRIF2_A ((uint32_t)0U << 26U) #define MOD_SEL1_DRIF2_B ((uint32_t)1U << 26U) #define MOD_SEL1_DRIF3_A ((uint32_t)0U << 25U) #define MOD_SEL1_DRIF3_B ((uint32_t)1U << 25U) #define MOD_SEL1_HSCIF3_A ((uint32_t)0U << 22U) #define MOD_SEL1_HSCIF3_B ((uint32_t)1U << 22U) #define MOD_SEL1_HSCIF3_C ((uint32_t)2U << 22U) #define MOD_SEL1_HSCIF3_D ((uint32_t)3U << 22U) #define MOD_SEL1_HSCIF3_E ((uint32_t)4U << 22U) #define MOD_SEL1_HSCIF4_A ((uint32_t)0U << 19U) #define MOD_SEL1_HSCIF4_B ((uint32_t)1U << 19U) #define MOD_SEL1_HSCIF4_C ((uint32_t)2U << 19U) #define MOD_SEL1_HSCIF4_D ((uint32_t)3U << 19U) #define MOD_SEL1_HSCIF4_E ((uint32_t)4U << 19U) #define MOD_SEL1_I2C6_A ((uint32_t)0U << 18U) #define MOD_SEL1_I2C6_B ((uint32_t)1U << 18U) #define MOD_SEL1_I2C7_A ((uint32_t)0U << 17U) #define MOD_SEL1_I2C7_B ((uint32_t)1U << 17U) #define MOD_SEL1_MSIOF2_A ((uint32_t)0U << 16U) #define MOD_SEL1_MSIOF2_B ((uint32_t)1U << 16U) #define MOD_SEL1_MSIOF3_A ((uint32_t)0U << 15U) #define MOD_SEL1_MSIOF3_B ((uint32_t)1U << 15U) #define MOD_SEL1_SCIF3_A ((uint32_t)0U << 13U) #define MOD_SEL1_SCIF3_B ((uint32_t)1U << 13U) #define MOD_SEL1_SCIF3_C ((uint32_t)2U << 13U) #define MOD_SEL1_SCIF4_A ((uint32_t)0U << 11U) #define MOD_SEL1_SCIF4_B ((uint32_t)1U << 11U) #define MOD_SEL1_SCIF4_C ((uint32_t)2U << 11U) #define MOD_SEL1_SCIF5_A ((uint32_t)0U << 9U) #define MOD_SEL1_SCIF5_B ((uint32_t)1U << 9U) #define MOD_SEL1_SCIF5_C ((uint32_t)2U << 9U) #define MOD_SEL1_VIN4_A ((uint32_t)0U << 8U) #define MOD_SEL1_VIN4_B ((uint32_t)1U << 8U) #define MOD_SEL1_VIN5_A ((uint32_t)0U << 7U) #define MOD_SEL1_VIN5_B ((uint32_t)1U << 7U) #define MOD_SEL1_ADGC_A ((uint32_t)0U << 5U) #define MOD_SEL1_ADGC_B ((uint32_t)1U << 5U) #define MOD_SEL1_ADGC_C ((uint32_t)2U << 5U) #define MOD_SEL1_SSI9_A ((uint32_t)0U << 4U) #define MOD_SEL1_SSI9_B ((uint32_t)1U << 4U) static void pfc_reg_write(uint32_t addr, uint32_t data) { mmio_write_32(PFC_PMMR, ~data); mmio_write_32((uintptr_t)addr, data); } void pfc_init_e3(void) { uint32_t reg; /* initialize module select */ pfc_reg_write(PFC_MOD_SEL0, MOD_SEL0_ADGB_A | MOD_SEL0_DRIF0_A | MOD_SEL0_FM_A | MOD_SEL0_FSO_A | MOD_SEL0_HSCIF0_A | MOD_SEL0_HSCIF1_A | MOD_SEL0_HSCIF2_A | MOD_SEL0_I2C1_A | MOD_SEL0_I2C2_A | MOD_SEL0_NDFC_A | MOD_SEL0_PWM0_A | MOD_SEL0_PWM1_A | MOD_SEL0_PWM2_A | MOD_SEL0_PWM3_A | MOD_SEL0_PWM4_A | MOD_SEL0_PWM5_A | MOD_SEL0_PWM6_A | MOD_SEL0_REMOCON_A | MOD_SEL0_SCIF_A | MOD_SEL0_SCIF0_A | MOD_SEL0_SCIF2_A | MOD_SEL0_SPEED_PULSE_IF_A); pfc_reg_write(PFC_MOD_SEL1, MOD_SEL1_SIMCARD_A | MOD_SEL1_SSI2_A | MOD_SEL1_TIMER_TMU_A | MOD_SEL1_USB20_CH0_B | MOD_SEL1_DRIF2_A | MOD_SEL1_DRIF3_A | MOD_SEL1_HSCIF3_A | MOD_SEL1_HSCIF4_A | MOD_SEL1_I2C6_A | MOD_SEL1_I2C7_A | MOD_SEL1_MSIOF2_A | MOD_SEL1_MSIOF3_A | MOD_SEL1_SCIF3_A | MOD_SEL1_SCIF4_A | MOD_SEL1_SCIF5_A | MOD_SEL1_VIN4_A | MOD_SEL1_VIN5_A | MOD_SEL1_ADGC_A | MOD_SEL1_SSI9_A); /* initialize peripheral function select */ pfc_reg_write(PFC_IPSR0, IPSR_28_FUNC(0) /* QSPI1_MISO/IO1 */ | IPSR_24_FUNC(0) /* QSPI1_MOSI/IO0 */ | IPSR_20_FUNC(0) /* QSPI1_SPCLK */ | IPSR_16_FUNC(0) /* QSPI0_IO3 */ | IPSR_12_FUNC(0) /* QSPI0_IO2 */ | IPSR_8_FUNC(0) /* QSPI0_MISO/IO1 */ | IPSR_4_FUNC(0) /* QSPI0_MOSI/IO0 */ | IPSR_0_FUNC(0)); /* QSPI0_SPCLK */ pfc_reg_write(PFC_IPSR1, IPSR_28_FUNC(0) /* AVB_RD2 */ | IPSR_24_FUNC(0) /* AVB_RD1 */ | IPSR_20_FUNC(0) /* AVB_RD0 */ | IPSR_16_FUNC(0) /* RPC_RESET# */ | IPSR_12_FUNC(0) /* RPC_INT# */ | IPSR_8_FUNC(0) /* QSPI1_SSL */ | IPSR_4_FUNC(0) /* QSPI1_IO3 */ | IPSR_0_FUNC(0)); /* QSPI1_IO2 */ pfc_reg_write(PFC_IPSR2, IPSR_28_FUNC(1) /* IRQ0 */ | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(2) /* AVB_LINK */ | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) /* AVB_MDC */ | IPSR_4_FUNC(0) /* AVB_MDIO */ | IPSR_0_FUNC(0)); /* AVB_TXCREFCLK */ pfc_reg_write(PFC_IPSR3, IPSR_28_FUNC(5) /* DU_HSYNC */ | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(5) /* DU_DG4 */ | IPSR_8_FUNC(5) /* DU_DOTCLKOUT0 */ | IPSR_4_FUNC(5) /* DU_DISP */ | IPSR_0_FUNC(1)); /* IRQ1 */ pfc_reg_write(PFC_IPSR4, IPSR_28_FUNC(5) /* DU_DB5 */ | IPSR_24_FUNC(5) /* DU_DB4 */ | IPSR_20_FUNC(5) /* DU_DB3 */ | IPSR_16_FUNC(5) /* DU_DB2 */ | IPSR_12_FUNC(5) /* DU_DG6 */ | IPSR_8_FUNC(5) /* DU_VSYNC */ | IPSR_4_FUNC(5) /* DU_DG5 */ | IPSR_0_FUNC(5)); /* DU_DG7 */ pfc_reg_write(PFC_IPSR5, IPSR_28_FUNC(5) /* DU_DR3 */ | IPSR_24_FUNC(5) /* DU_DB7 */ | IPSR_20_FUNC(5) /* DU_DR2 */ | IPSR_16_FUNC(5) /* DU_DR1 */ | IPSR_12_FUNC(5) /* DU_DR0 */ | IPSR_8_FUNC(5) /* DU_DB1 */ | IPSR_4_FUNC(5) /* DU_DB0 */ | IPSR_0_FUNC(5)); /* DU_DB6 */ pfc_reg_write(PFC_IPSR6, IPSR_28_FUNC(5) /* DU_DG1 */ | IPSR_24_FUNC(5) /* DU_DG0 */ | IPSR_20_FUNC(5) /* DU_DR7 */ | IPSR_16_FUNC(2) /* IRQ5 */ | IPSR_12_FUNC(5) /* DU_DR6 */ | IPSR_8_FUNC(5) /* DU_DR5 */ | IPSR_4_FUNC(0) | IPSR_0_FUNC(5)); /* DU_DR4 */ pfc_reg_write(PFC_IPSR7, IPSR_28_FUNC(0) /* SD0_CLK */ | IPSR_24_FUNC(0) | IPSR_20_FUNC(5) /* DU_DOTCLKIN0 */ | IPSR_16_FUNC(5) /* DU_DG3 */ | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(5)); /* DU_DG2 */ pfc_reg_write(PFC_IPSR8, IPSR_28_FUNC(0) /* SD1_DAT0 */ | IPSR_24_FUNC(0) /* SD1_CMD */ | IPSR_20_FUNC(0) /* SD1_CLK */ | IPSR_16_FUNC(0) /* SD0_DAT3 */ | IPSR_12_FUNC(0) /* SD0_DAT2 */ | IPSR_8_FUNC(0) /* SD0_DAT1 */ | IPSR_4_FUNC(0) /* SD0_DAT0 */ | IPSR_0_FUNC(0)); /* SD0_CMD */ pfc_reg_write(PFC_IPSR9, IPSR_28_FUNC(0) /* SD3_DAT2 */ | IPSR_24_FUNC(0) /* SD3_DAT1 */ | IPSR_20_FUNC(0) /* SD3_DAT0 */ | IPSR_16_FUNC(0) /* SD3_CMD */ | IPSR_12_FUNC(0) /* SD3_CLK */ | IPSR_8_FUNC(0) /* SD1_DAT3 */ | IPSR_4_FUNC(0) /* SD1_DAT2 */ | IPSR_0_FUNC(0)); /* SD1_DAT1 */ pfc_reg_write(PFC_IPSR10, IPSR_28_FUNC(0) /* SD0_WP */ | IPSR_24_FUNC(0) /* SD0_CD */ | IPSR_20_FUNC(0) /* SD3_DS */ | IPSR_16_FUNC(0) /* SD3_DAT7 */ | IPSR_12_FUNC(0) /* SD3_DAT6 */ | IPSR_8_FUNC(0) /* SD3_DAT5 */ | IPSR_4_FUNC(0) /* SD3_DAT4 */ | IPSR_0_FUNC(0)); /* SD3_DAT3 */ pfc_reg_write(PFC_IPSR11, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(2) /* AUDIO_CLKOUT1_A */ | IPSR_16_FUNC(2) /* AUDIO_CLKOUT_A */ | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) /* SD1_WP */ | IPSR_0_FUNC(0)); /* SD1_CD */ pfc_reg_write(PFC_IPSR12, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) /* RX2_A */ | IPSR_8_FUNC(0) /* TX2_A */ | IPSR_4_FUNC(2) /* AUDIO_CLKB_A */ | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR13, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(2) /* AUDIO_CLKC_A */ | IPSR_4_FUNC(1) /* HTX2_A */ | IPSR_0_FUNC(1)); /* HRX2_A */ pfc_reg_write(PFC_IPSR14, IPSR_28_FUNC(3) /* USB0_PWEN_B */ | IPSR_24_FUNC(0) /* SSI_SDATA4 */ | IPSR_20_FUNC(0) /* SSI_SDATA3 */ | IPSR_16_FUNC(0) /* SSI_WS349 */ | IPSR_12_FUNC(0) /* SSI_SCK349 */ | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) /* SSI_SDATA1 */ | IPSR_0_FUNC(0)); /* SSI_SDATA0 */ pfc_reg_write(PFC_IPSR15, IPSR_28_FUNC(0) /* USB30_OVC */ | IPSR_24_FUNC(0) /* USB30_PWEN */ | IPSR_20_FUNC(0) /* AUDIO_CLKA */ | IPSR_16_FUNC(1) /* HRTS2#_A */ | IPSR_12_FUNC(1) /* HCTS2#_A */ | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(3)); /* USB0_OVC_B */ /* initialize GPIO/perihperal function select */ pfc_reg_write(PFC_GPSR0, GPSR0_SCL4 | GPSR0_D15 | GPSR0_D11 | GPSR0_D10 | GPSR0_D9 | GPSR0_D8 | GPSR0_D7 | GPSR0_D6 | GPSR0_D5 | GPSR0_D3 | GPSR0_D2 | GPSR0_D1 | GPSR0_D0); pfc_reg_write(PFC_GPSR1, GPSR1_WE0 | GPSR1_CS0 | GPSR1_A19 | GPSR1_A18 | GPSR1_A17 | GPSR1_A16 | GPSR1_A15 | GPSR1_A14 | GPSR1_A13 | GPSR1_A12 | GPSR1_A11 | GPSR1_A10 | GPSR1_A9 | GPSR1_A8 | GPSR1_A4 | GPSR1_A3 | GPSR1_A2 | GPSR1_A1 | GPSR1_A0); pfc_reg_write(PFC_GPSR2, GPSR2_BIT27_REVERSED | GPSR2_BIT26_REVERSED | GPSR2_RD | GPSR2_AVB_PHY_INT | GPSR2_AVB_TXCREFCLK | GPSR2_AVB_RD3 | GPSR2_AVB_RD2 | GPSR2_AVB_RD1 | GPSR2_AVB_RD0 | GPSR2_AVB_RXC | GPSR2_AVB_RX_CTL | GPSR2_RPC_RESET | GPSR2_RPC_RPC_INT | GPSR2_QSPI1_SSL | GPSR2_QSPI1_IO3 | GPSR2_QSPI1_IO2 | GPSR2_QSPI1_MISO_IO1 | GPSR2_QSPI1_MOSI_IO0 | GPSR2_QSPI1_SPCLK | GPSR2_QSPI0_SSL | GPSR2_QSPI0_IO3 | GPSR2_QSPI0_IO2 | GPSR2_QSPI0_MISO_IO1 | GPSR2_QSPI0_MOSI_IO0 | GPSR2_QSPI0_SPCLK); pfc_reg_write(PFC_GPSR3, GPSR3_SD1_WP | GPSR3_SD1_CD | GPSR3_SD0_WP | GPSR3_SD0_CD | GPSR3_SD1_DAT3 | GPSR3_SD1_DAT2 | GPSR3_SD1_DAT1 | GPSR3_SD1_DAT0 | GPSR3_SD1_CMD | GPSR3_SD1_CLK | GPSR3_SD0_DAT3 | GPSR3_SD0_DAT2 | GPSR3_SD0_DAT1 | GPSR3_SD0_DAT0 | GPSR3_SD0_CMD | GPSR3_SD0_CLK); pfc_reg_write(PFC_GPSR4, GPSR4_SD3_DS | GPSR4_SD3_DAT7 | GPSR4_SD3_DAT6 | GPSR4_SD3_DAT5 | GPSR4_SD3_DAT4 | GPSR4_SD3_DAT3 | GPSR4_SD3_DAT2 | GPSR4_SD3_DAT1 | GPSR4_SD3_DAT0 | GPSR4_SD3_CMD | GPSR4_SD3_CLK); pfc_reg_write(PFC_GPSR5, GPSR5_SSI_SDATA9 | GPSR5_MSIOF0_SS2 | GPSR5_MSIOF0_SS1 | GPSR5_RX2_A | GPSR5_TX2_A | GPSR5_SCK2_A | GPSR5_RTS0_A | GPSR5_CTS0_A); pfc_reg_write(PFC_GPSR6, GPSR6_USB30_PWEN | GPSR6_SSI_SDATA6 | GPSR6_SSI_WS6 | GPSR6_SSI_WS5 | GPSR6_SSI_SCK5 | GPSR6_SSI_SDATA4 | GPSR6_USB30_OVC | GPSR6_AUDIO_CLKA | GPSR6_SSI_SDATA3 | GPSR6_SSI_WS349 | GPSR6_SSI_SCK349 | GPSR6_SSI_SDATA1 | GPSR6_SSI_SDATA0 | GPSR6_SSI_WS01239 | GPSR6_SSI_SCK01239); /* initialize POC control */ reg = mmio_read_32(PFC_POCCTRL0); reg = ((reg & POCCTRL0_MASK) | POC_SD1_DAT3_33V | POC_SD1_DAT2_33V | POC_SD1_DAT1_33V | POC_SD1_DAT0_33V | POC_SD1_CMD_33V | POC_SD1_CLK_33V | POC_SD0_DAT3_33V | POC_SD0_DAT2_33V | POC_SD0_DAT1_33V | POC_SD0_DAT0_33V | POC_SD0_CMD_33V | POC_SD0_CLK_33V); pfc_reg_write(PFC_POCCTRL0, reg); reg = mmio_read_32(PFC_POCCTRL2); reg = (reg & POCCTRL2_MASK); pfc_reg_write(PFC_POCCTRL2, reg); /* initialize LSI pin pull-up/down control */ pfc_reg_write(PFC_PUD0, 0xFDF80000U); pfc_reg_write(PFC_PUD1, 0xCE298464U); pfc_reg_write(PFC_PUD2, 0xA4C380F4U); pfc_reg_write(PFC_PUD3, 0x0000079FU); pfc_reg_write(PFC_PUD4, 0xFFF0FFFFU); pfc_reg_write(PFC_PUD5, 0x40000000U); /* initialize LSI pin pull-enable register */ pfc_reg_write(PFC_PUEN0, 0xFFF00000U); pfc_reg_write(PFC_PUEN1, 0x00000000U); pfc_reg_write(PFC_PUEN2, 0x00000004U); pfc_reg_write(PFC_PUEN3, 0x00000000U); pfc_reg_write(PFC_PUEN4, 0x07800010U); pfc_reg_write(PFC_PUEN5, 0x00000000U); /* initialize positive/negative logic select */ mmio_write_32(GPIO_POSNEG0, 0x00000000U); mmio_write_32(GPIO_POSNEG1, 0x00000000U); mmio_write_32(GPIO_POSNEG2, 0x00000000U); mmio_write_32(GPIO_POSNEG3, 0x00000000U); mmio_write_32(GPIO_POSNEG4, 0x00000000U); mmio_write_32(GPIO_POSNEG5, 0x00000000U); mmio_write_32(GPIO_POSNEG6, 0x00000000U); /* initialize general IO/interrupt switching */ mmio_write_32(GPIO_IOINTSEL0, 0x00020000U); mmio_write_32(GPIO_IOINTSEL1, 0x00000000U); mmio_write_32(GPIO_IOINTSEL2, 0x00000000U); mmio_write_32(GPIO_IOINTSEL3, 0x00000000U); mmio_write_32(GPIO_IOINTSEL4, 0x00000000U); mmio_write_32(GPIO_IOINTSEL5, 0x00000000U); mmio_write_32(GPIO_IOINTSEL6, 0x00000000U); /* initialize general output register */ mmio_write_32(GPIO_OUTDT0, 0x00000010U); mmio_write_32(GPIO_OUTDT1, 0x00100000U); mmio_write_32(GPIO_OUTDT2, 0x00000000U); mmio_write_32(GPIO_OUTDT3, 0x00008000U); mmio_write_32(GPIO_OUTDT5, 0x00060000U); mmio_write_32(GPIO_OUTDT6, 0x00000000U); /* initialize general input/output switching */ mmio_write_32(GPIO_INOUTSEL0, 0x00000010U); mmio_write_32(GPIO_INOUTSEL1, 0x00100020U); mmio_write_32(GPIO_INOUTSEL2, 0x03000000U); mmio_write_32(GPIO_INOUTSEL3, 0x00008000U); mmio_write_32(GPIO_INOUTSEL4, 0x00000000U); mmio_write_32(GPIO_INOUTSEL5, 0x00060000U); mmio_write_32(GPIO_INOUTSEL6, 0x00004000U); } trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/E3/pfc_init_e3.h000066400000000000000000000003421355360272700245270ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PFC_INIT_E3_H #define PFC_INIT_E3_H void pfc_init_e3(void); #endif /* PFC_INIT_E3_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/H3/000077500000000000000000000000001355360272700222005ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c000066400000000000000000001221051355360272700251400ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "rcar_def.h" #include "../pfc_regs.h" #define GPSR0_D15 BIT(15) #define GPSR0_D14 BIT(14) #define GPSR0_D13 BIT(13) #define GPSR0_D12 BIT(12) #define GPSR0_D11 BIT(11) #define GPSR0_D10 BIT(10) #define GPSR0_D9 BIT(9) #define GPSR0_D8 BIT(8) #define GPSR0_D7 BIT(7) #define GPSR0_D6 BIT(6) #define GPSR0_D5 BIT(5) #define GPSR0_D4 BIT(4) #define GPSR0_D3 BIT(3) #define GPSR0_D2 BIT(2) #define GPSR0_D1 BIT(1) #define GPSR0_D0 BIT(0) #define GPSR1_EX_WAIT0_A BIT(27) #define GPSR1_WE1 BIT(26) #define GPSR1_WE0 BIT(25) #define GPSR1_RD_WR BIT(24) #define GPSR1_RD BIT(23) #define GPSR1_BS BIT(22) #define GPSR1_CS1_A26 BIT(21) #define GPSR1_CS0 BIT(20) #define GPSR1_A19 BIT(19) #define GPSR1_A18 BIT(18) #define GPSR1_A17 BIT(17) #define GPSR1_A16 BIT(16) #define GPSR1_A15 BIT(15) #define GPSR1_A14 BIT(14) #define GPSR1_A13 BIT(13) #define GPSR1_A12 BIT(12) #define GPSR1_A11 BIT(11) #define GPSR1_A10 BIT(10) #define GPSR1_A9 BIT(9) #define GPSR1_A8 BIT(8) #define GPSR1_A7 BIT(7) #define GPSR1_A6 BIT(6) #define GPSR1_A5 BIT(5) #define GPSR1_A4 BIT(4) #define GPSR1_A3 BIT(3) #define GPSR1_A2 BIT(2) #define GPSR1_A1 BIT(1) #define GPSR1_A0 BIT(0) #define GPSR2_AVB_AVTP_CAPTURE_A BIT(14) #define GPSR2_AVB_AVTP_MATCH_A BIT(13) #define GPSR2_AVB_LINK BIT(12) #define GPSR2_AVB_PHY_INT BIT(11) #define GPSR2_AVB_MAGIC BIT(10) #define GPSR2_AVB_MDC BIT(9) #define GPSR2_PWM2_A BIT(8) #define GPSR2_PWM1_A BIT(7) #define GPSR2_PWM0 BIT(6) #define GPSR2_IRQ5 BIT(5) #define GPSR2_IRQ4 BIT(4) #define GPSR2_IRQ3 BIT(3) #define GPSR2_IRQ2 BIT(2) #define GPSR2_IRQ1 BIT(1) #define GPSR2_IRQ0 BIT(0) #define GPSR3_SD1_WP BIT(15) #define GPSR3_SD1_CD BIT(14) #define GPSR3_SD0_WP BIT(13) #define GPSR3_SD0_CD BIT(12) #define GPSR3_SD1_DAT3 BIT(11) #define GPSR3_SD1_DAT2 BIT(10) #define GPSR3_SD1_DAT1 BIT(9) #define GPSR3_SD1_DAT0 BIT(8) #define GPSR3_SD1_CMD BIT(7) #define GPSR3_SD1_CLK BIT(6) #define GPSR3_SD0_DAT3 BIT(5) #define GPSR3_SD0_DAT2 BIT(4) #define GPSR3_SD0_DAT1 BIT(3) #define GPSR3_SD0_DAT0 BIT(2) #define GPSR3_SD0_CMD BIT(1) #define GPSR3_SD0_CLK BIT(0) #define GPSR4_SD3_DS BIT(17) #define GPSR4_SD3_DAT7 BIT(16) #define GPSR4_SD3_DAT6 BIT(15) #define GPSR4_SD3_DAT5 BIT(14) #define GPSR4_SD3_DAT4 BIT(13) #define GPSR4_SD3_DAT3 BIT(12) #define GPSR4_SD3_DAT2 BIT(11) #define GPSR4_SD3_DAT1 BIT(10) #define GPSR4_SD3_DAT0 BIT(9) #define GPSR4_SD3_CMD BIT(8) #define GPSR4_SD3_CLK BIT(7) #define GPSR4_SD2_DS BIT(6) #define GPSR4_SD2_DAT3 BIT(5) #define GPSR4_SD2_DAT2 BIT(4) #define GPSR4_SD2_DAT1 BIT(3) #define GPSR4_SD2_DAT0 BIT(2) #define GPSR4_SD2_CMD BIT(1) #define GPSR4_SD2_CLK BIT(0) #define GPSR5_MLB_DAT BIT(25) #define GPSR5_MLB_SIG BIT(24) #define GPSR5_MLB_CLK BIT(23) #define GPSR5_MSIOF0_RXD BIT(22) #define GPSR5_MSIOF0_SS2 BIT(21) #define GPSR5_MSIOF0_TXD BIT(20) #define GPSR5_MSIOF0_SS1 BIT(19) #define GPSR5_MSIOF0_SYNC BIT(18) #define GPSR5_MSIOF0_SCK BIT(17) #define GPSR5_HRTS0 BIT(16) #define GPSR5_HCTS0 BIT(15) #define GPSR5_HTX0 BIT(14) #define GPSR5_HRX0 BIT(13) #define GPSR5_HSCK0 BIT(12) #define GPSR5_RX2_A BIT(11) #define GPSR5_TX2_A BIT(10) #define GPSR5_SCK2 BIT(9) #define GPSR5_RTS1 BIT(8) #define GPSR5_CTS1 BIT(7) #define GPSR5_TX1_A BIT(6) #define GPSR5_RX1_A BIT(5) #define GPSR5_RTS0 BIT(4) #define GPSR5_CTS0 BIT(3) #define GPSR5_TX0 BIT(2) #define GPSR5_RX0 BIT(1) #define GPSR5_SCK0 BIT(0) #define GPSR6_USB31_OVC BIT(31) #define GPSR6_USB31_PWEN BIT(30) #define GPSR6_USB30_OVC BIT(29) #define GPSR6_USB30_PWEN BIT(28) #define GPSR6_USB1_OVC BIT(27) #define GPSR6_USB1_PWEN BIT(26) #define GPSR6_USB0_OVC BIT(25) #define GPSR6_USB0_PWEN BIT(24) #define GPSR6_AUDIO_CLKB_B BIT(23) #define GPSR6_AUDIO_CLKA_A BIT(22) #define GPSR6_SSI_SDATA9_A BIT(21) #define GPSR6_SSI_SDATA8 BIT(20) #define GPSR6_SSI_SDATA7 BIT(19) #define GPSR6_SSI_WS78 BIT(18) #define GPSR6_SSI_SCK78 BIT(17) #define GPSR6_SSI_SDATA6 BIT(16) #define GPSR6_SSI_WS6 BIT(15) #define GPSR6_SSI_SCK6 BIT(14) #define GPSR6_SSI_SDATA5 BIT(13) #define GPSR6_SSI_WS5 BIT(12) #define GPSR6_SSI_SCK5 BIT(11) #define GPSR6_SSI_SDATA4 BIT(10) #define GPSR6_SSI_WS4 BIT(9) #define GPSR6_SSI_SCK4 BIT(8) #define GPSR6_SSI_SDATA3 BIT(7) #define GPSR6_SSI_WS34 BIT(6) #define GPSR6_SSI_SCK34 BIT(5) #define GPSR6_SSI_SDATA2_A BIT(4) #define GPSR6_SSI_SDATA1_A BIT(3) #define GPSR6_SSI_SDATA0 BIT(2) #define GPSR6_SSI_WS0129 BIT(1) #define GPSR6_SSI_SCK0129 BIT(0) #define GPSR7_AVS2 BIT(1) #define GPSR7_AVS1 BIT(0) #define IPSR_28_FUNC(x) ((uint32_t)(x) << 28U) #define IPSR_24_FUNC(x) ((uint32_t)(x) << 24U) #define IPSR_20_FUNC(x) ((uint32_t)(x) << 20U) #define IPSR_16_FUNC(x) ((uint32_t)(x) << 16U) #define IPSR_12_FUNC(x) ((uint32_t)(x) << 12U) #define IPSR_8_FUNC(x) ((uint32_t)(x) << 8U) #define IPSR_4_FUNC(x) ((uint32_t)(x) << 4U) #define IPSR_0_FUNC(x) ((uint32_t)(x) << 0U) #define POC_SD3_DS_33V BIT(29) #define POC_SD3_DAT7_33V BIT(28) #define POC_SD3_DAT6_33V BIT(27) #define POC_SD3_DAT5_33V BIT(26) #define POC_SD3_DAT4_33V BIT(25) #define POC_SD3_DAT3_33V BIT(24) #define POC_SD3_DAT2_33V BIT(23) #define POC_SD3_DAT1_33V BIT(22) #define POC_SD3_DAT0_33V BIT(21) #define POC_SD3_CMD_33V BIT(20) #define POC_SD3_CLK_33V BIT(19) #define POC_SD2_DS_33V BIT(18) #define POC_SD2_DAT3_33V BIT(17) #define POC_SD2_DAT2_33V BIT(16) #define POC_SD2_DAT1_33V BIT(15) #define POC_SD2_DAT0_33V BIT(14) #define POC_SD2_CMD_33V BIT(13) #define POC_SD2_CLK_33V BIT(12) #define POC_SD1_DAT3_33V BIT(11) #define POC_SD1_DAT2_33V BIT(10) #define POC_SD1_DAT1_33V BIT(9) #define POC_SD1_DAT0_33V BIT(8) #define POC_SD1_CMD_33V BIT(7) #define POC_SD1_CLK_33V BIT(6) #define POC_SD0_DAT3_33V BIT(5) #define POC_SD0_DAT2_33V BIT(4) #define POC_SD0_DAT1_33V BIT(3) #define POC_SD0_DAT0_33V BIT(2) #define POC_SD0_CMD_33V BIT(1) #define POC_SD0_CLK_33V BIT(0) #define DRVCTRL0_MASK (0xCCCCCCCCU) #define DRVCTRL1_MASK (0xCCCCCCC8U) #define DRVCTRL2_MASK (0x88888888U) #define DRVCTRL3_MASK (0x88888888U) #define DRVCTRL4_MASK (0x88888888U) #define DRVCTRL5_MASK (0x88888888U) #define DRVCTRL6_MASK (0x88888888U) #define DRVCTRL7_MASK (0x88888888U) #define DRVCTRL8_MASK (0x88888888U) #define DRVCTRL9_MASK (0x88888888U) #define DRVCTRL10_MASK (0x88888888U) #define DRVCTRL11_MASK (0x888888CCU) #define DRVCTRL12_MASK (0xCCCFFFCFU) #define DRVCTRL13_MASK (0xCC888888U) #define DRVCTRL14_MASK (0x88888888U) #define DRVCTRL15_MASK (0x88888888U) #define DRVCTRL16_MASK (0x88888888U) #define DRVCTRL17_MASK (0x88888888U) #define DRVCTRL18_MASK (0x88888888U) #define DRVCTRL19_MASK (0x88888888U) #define DRVCTRL20_MASK (0x88888888U) #define DRVCTRL21_MASK (0x88888888U) #define DRVCTRL22_MASK (0x88888888U) #define DRVCTRL23_MASK (0x88888888U) #define DRVCTRL24_MASK (0x8888888FU) #define DRVCTRL0_QSPI0_SPCLK(x) ((uint32_t)(x) << 28U) #define DRVCTRL0_QSPI0_MOSI_IO0(x) ((uint32_t)(x) << 24U) #define DRVCTRL0_QSPI0_MISO_IO1(x) ((uint32_t)(x) << 20U) #define DRVCTRL0_QSPI0_IO2(x) ((uint32_t)(x) << 16U) #define DRVCTRL0_QSPI0_IO3(x) ((uint32_t)(x) << 12U) #define DRVCTRL0_QSPI0_SSL(x) ((uint32_t)(x) << 8U) #define DRVCTRL0_QSPI1_SPCLK(x) ((uint32_t)(x) << 4U) #define DRVCTRL0_QSPI1_MOSI_IO0(x) ((uint32_t)(x) << 0U) #define DRVCTRL1_QSPI1_MISO_IO1(x) ((uint32_t)(x) << 28U) #define DRVCTRL1_QSPI1_IO2(x) ((uint32_t)(x) << 24U) #define DRVCTRL1_QSPI1_IO3(x) ((uint32_t)(x) << 20U) #define DRVCTRL1_QSPI1_SS(x) ((uint32_t)(x) << 16U) #define DRVCTRL1_RPC_INT(x) ((uint32_t)(x) << 12U) #define DRVCTRL1_RPC_WP(x) ((uint32_t)(x) << 8U) #define DRVCTRL1_RPC_RESET(x) ((uint32_t)(x) << 4U) #define DRVCTRL1_AVB_RX_CTL(x) ((uint32_t)(x) << 0U) #define DRVCTRL2_AVB_RXC(x) ((uint32_t)(x) << 28U) #define DRVCTRL2_AVB_RD0(x) ((uint32_t)(x) << 24U) #define DRVCTRL2_AVB_RD1(x) ((uint32_t)(x) << 20U) #define DRVCTRL2_AVB_RD2(x) ((uint32_t)(x) << 16U) #define DRVCTRL2_AVB_RD3(x) ((uint32_t)(x) << 12U) #define DRVCTRL2_AVB_TX_CTL(x) ((uint32_t)(x) << 8U) #define DRVCTRL2_AVB_TXC(x) ((uint32_t)(x) << 4U) #define DRVCTRL2_AVB_TD0(x) ((uint32_t)(x) << 0U) #define DRVCTRL3_AVB_TD1(x) ((uint32_t)(x) << 28U) #define DRVCTRL3_AVB_TD2(x) ((uint32_t)(x) << 24U) #define DRVCTRL3_AVB_TD3(x) ((uint32_t)(x) << 20U) #define DRVCTRL3_AVB_TXCREFCLK(x) ((uint32_t)(x) << 16U) #define DRVCTRL3_AVB_MDIO(x) ((uint32_t)(x) << 12U) #define DRVCTRL3_AVB_MDC(x) ((uint32_t)(x) << 8U) #define DRVCTRL3_AVB_MAGIC(x) ((uint32_t)(x) << 4U) #define DRVCTRL3_AVB_PHY_INT(x) ((uint32_t)(x) << 0U) #define DRVCTRL4_AVB_LINK(x) ((uint32_t)(x) << 28U) #define DRVCTRL4_AVB_AVTP_MATCH(x) ((uint32_t)(x) << 24U) #define DRVCTRL4_AVB_AVTP_CAPTURE(x) ((uint32_t)(x) << 20U) #define DRVCTRL4_IRQ0(x) ((uint32_t)(x) << 16U) #define DRVCTRL4_IRQ1(x) ((uint32_t)(x) << 12U) #define DRVCTRL4_IRQ2(x) ((uint32_t)(x) << 8U) #define DRVCTRL4_IRQ3(x) ((uint32_t)(x) << 4U) #define DRVCTRL4_IRQ4(x) ((uint32_t)(x) << 0U) #define DRVCTRL5_IRQ5(x) ((uint32_t)(x) << 28U) #define DRVCTRL5_PWM0(x) ((uint32_t)(x) << 24U) #define DRVCTRL5_PWM1(x) ((uint32_t)(x) << 20U) #define DRVCTRL5_PWM2(x) ((uint32_t)(x) << 16U) #define DRVCTRL5_A0(x) ((uint32_t)(x) << 12U) #define DRVCTRL5_A1(x) ((uint32_t)(x) << 8U) #define DRVCTRL5_A2(x) ((uint32_t)(x) << 4U) #define DRVCTRL5_A3(x) ((uint32_t)(x) << 0U) #define DRVCTRL6_A4(x) ((uint32_t)(x) << 28U) #define DRVCTRL6_A5(x) ((uint32_t)(x) << 24U) #define DRVCTRL6_A6(x) ((uint32_t)(x) << 20U) #define DRVCTRL6_A7(x) ((uint32_t)(x) << 16U) #define DRVCTRL6_A8(x) ((uint32_t)(x) << 12U) #define DRVCTRL6_A9(x) ((uint32_t)(x) << 8U) #define DRVCTRL6_A10(x) ((uint32_t)(x) << 4U) #define DRVCTRL6_A11(x) ((uint32_t)(x) << 0U) #define DRVCTRL7_A12(x) ((uint32_t)(x) << 28U) #define DRVCTRL7_A13(x) ((uint32_t)(x) << 24U) #define DRVCTRL7_A14(x) ((uint32_t)(x) << 20U) #define DRVCTRL7_A15(x) ((uint32_t)(x) << 16U) #define DRVCTRL7_A16(x) ((uint32_t)(x) << 12U) #define DRVCTRL7_A17(x) ((uint32_t)(x) << 8U) #define DRVCTRL7_A18(x) ((uint32_t)(x) << 4U) #define DRVCTRL7_A19(x) ((uint32_t)(x) << 0U) #define DRVCTRL8_CLKOUT(x) ((uint32_t)(x) << 28U) #define DRVCTRL8_CS0(x) ((uint32_t)(x) << 24U) #define DRVCTRL8_CS1_A2(x) ((uint32_t)(x) << 20U) #define DRVCTRL8_BS(x) ((uint32_t)(x) << 16U) #define DRVCTRL8_RD(x) ((uint32_t)(x) << 12U) #define DRVCTRL8_RD_W(x) ((uint32_t)(x) << 8U) #define DRVCTRL8_WE0(x) ((uint32_t)(x) << 4U) #define DRVCTRL8_WE1(x) ((uint32_t)(x) << 0U) #define DRVCTRL9_EX_WAIT0(x) ((uint32_t)(x) << 28U) #define DRVCTRL9_PRESETOU(x) ((uint32_t)(x) << 24U) #define DRVCTRL9_D0(x) ((uint32_t)(x) << 20U) #define DRVCTRL9_D1(x) ((uint32_t)(x) << 16U) #define DRVCTRL9_D2(x) ((uint32_t)(x) << 12U) #define DRVCTRL9_D3(x) ((uint32_t)(x) << 8U) #define DRVCTRL9_D4(x) ((uint32_t)(x) << 4U) #define DRVCTRL9_D5(x) ((uint32_t)(x) << 0U) #define DRVCTRL10_D6(x) ((uint32_t)(x) << 28U) #define DRVCTRL10_D7(x) ((uint32_t)(x) << 24U) #define DRVCTRL10_D8(x) ((uint32_t)(x) << 20U) #define DRVCTRL10_D9(x) ((uint32_t)(x) << 16U) #define DRVCTRL10_D10(x) ((uint32_t)(x) << 12U) #define DRVCTRL10_D11(x) ((uint32_t)(x) << 8U) #define DRVCTRL10_D12(x) ((uint32_t)(x) << 4U) #define DRVCTRL10_D13(x) ((uint32_t)(x) << 0U) #define DRVCTRL11_D14(x) ((uint32_t)(x) << 28U) #define DRVCTRL11_D15(x) ((uint32_t)(x) << 24U) #define DRVCTRL11_AVS1(x) ((uint32_t)(x) << 20U) #define DRVCTRL11_AVS2(x) ((uint32_t)(x) << 16U) #define DRVCTRL11_GP7_02(x) ((uint32_t)(x) << 12U) #define DRVCTRL11_GP7_03(x) ((uint32_t)(x) << 8U) #define DRVCTRL11_DU_DOTCLKIN0(x) ((uint32_t)(x) << 4U) #define DRVCTRL11_DU_DOTCLKIN1(x) ((uint32_t)(x) << 0U) #define DRVCTRL12_DU_DOTCLKIN2(x) ((uint32_t)(x) << 28U) #define DRVCTRL12_DU_DOTCLKIN3(x) ((uint32_t)(x) << 24U) #define DRVCTRL12_DU_FSCLKST(x) ((uint32_t)(x) << 20U) #define DRVCTRL12_DU_TMS(x) ((uint32_t)(x) << 4U) #define DRVCTRL13_TDO(x) ((uint32_t)(x) << 28U) #define DRVCTRL13_ASEBRK(x) ((uint32_t)(x) << 24U) #define DRVCTRL13_SD0_CLK(x) ((uint32_t)(x) << 20U) #define DRVCTRL13_SD0_CMD(x) ((uint32_t)(x) << 16U) #define DRVCTRL13_SD0_DAT0(x) ((uint32_t)(x) << 12U) #define DRVCTRL13_SD0_DAT1(x) ((uint32_t)(x) << 8U) #define DRVCTRL13_SD0_DAT2(x) ((uint32_t)(x) << 4U) #define DRVCTRL13_SD0_DAT3(x) ((uint32_t)(x) << 0U) #define DRVCTRL14_SD1_CLK(x) ((uint32_t)(x) << 28U) #define DRVCTRL14_SD1_CMD(x) ((uint32_t)(x) << 24U) #define DRVCTRL14_SD1_DAT0(x) ((uint32_t)(x) << 20U) #define DRVCTRL14_SD1_DAT1(x) ((uint32_t)(x) << 16U) #define DRVCTRL14_SD1_DAT2(x) ((uint32_t)(x) << 12U) #define DRVCTRL14_SD1_DAT3(x) ((uint32_t)(x) << 8U) #define DRVCTRL14_SD2_CLK(x) ((uint32_t)(x) << 4U) #define DRVCTRL14_SD2_CMD(x) ((uint32_t)(x) << 0U) #define DRVCTRL15_SD2_DAT0(x) ((uint32_t)(x) << 28U) #define DRVCTRL15_SD2_DAT1(x) ((uint32_t)(x) << 24U) #define DRVCTRL15_SD2_DAT2(x) ((uint32_t)(x) << 20U) #define DRVCTRL15_SD2_DAT3(x) ((uint32_t)(x) << 16U) #define DRVCTRL15_SD2_DS(x) ((uint32_t)(x) << 12U) #define DRVCTRL15_SD3_CLK(x) ((uint32_t)(x) << 8U) #define DRVCTRL15_SD3_CMD(x) ((uint32_t)(x) << 4U) #define DRVCTRL15_SD3_DAT0(x) ((uint32_t)(x) << 0U) #define DRVCTRL16_SD3_DAT1(x) ((uint32_t)(x) << 28U) #define DRVCTRL16_SD3_DAT2(x) ((uint32_t)(x) << 24U) #define DRVCTRL16_SD3_DAT3(x) ((uint32_t)(x) << 20U) #define DRVCTRL16_SD3_DAT4(x) ((uint32_t)(x) << 16U) #define DRVCTRL16_SD3_DAT5(x) ((uint32_t)(x) << 12U) #define DRVCTRL16_SD3_DAT6(x) ((uint32_t)(x) << 8U) #define DRVCTRL16_SD3_DAT7(x) ((uint32_t)(x) << 4U) #define DRVCTRL16_SD3_DS(x) ((uint32_t)(x) << 0U) #define DRVCTRL17_SD0_CD(x) ((uint32_t)(x) << 28U) #define DRVCTRL17_SD0_WP(x) ((uint32_t)(x) << 24U) #define DRVCTRL17_SD1_CD(x) ((uint32_t)(x) << 20U) #define DRVCTRL17_SD1_WP(x) ((uint32_t)(x) << 16U) #define DRVCTRL17_SCK0(x) ((uint32_t)(x) << 12U) #define DRVCTRL17_RX0(x) ((uint32_t)(x) << 8U) #define DRVCTRL17_TX0(x) ((uint32_t)(x) << 4U) #define DRVCTRL17_CTS0(x) ((uint32_t)(x) << 0U) #define DRVCTRL18_RTS0_TANS(x) ((uint32_t)(x) << 28U) #define DRVCTRL18_RX1(x) ((uint32_t)(x) << 24U) #define DRVCTRL18_TX1(x) ((uint32_t)(x) << 20U) #define DRVCTRL18_CTS1(x) ((uint32_t)(x) << 16U) #define DRVCTRL18_RTS1_TANS(x) ((uint32_t)(x) << 12U) #define DRVCTRL18_SCK2(x) ((uint32_t)(x) << 8U) #define DRVCTRL18_TX2(x) ((uint32_t)(x) << 4U) #define DRVCTRL18_RX2(x) ((uint32_t)(x) << 0U) #define DRVCTRL19_HSCK0(x) ((uint32_t)(x) << 28U) #define DRVCTRL19_HRX0(x) ((uint32_t)(x) << 24U) #define DRVCTRL19_HTX0(x) ((uint32_t)(x) << 20U) #define DRVCTRL19_HCTS0(x) ((uint32_t)(x) << 16U) #define DRVCTRL19_HRTS0(x) ((uint32_t)(x) << 12U) #define DRVCTRL19_MSIOF0_SCK(x) ((uint32_t)(x) << 8U) #define DRVCTRL19_MSIOF0_SYNC(x) ((uint32_t)(x) << 4U) #define DRVCTRL19_MSIOF0_SS1(x) ((uint32_t)(x) << 0U) #define DRVCTRL20_MSIOF0_TXD(x) ((uint32_t)(x) << 28U) #define DRVCTRL20_MSIOF0_SS2(x) ((uint32_t)(x) << 24U) #define DRVCTRL20_MSIOF0_RXD(x) ((uint32_t)(x) << 20U) #define DRVCTRL20_MLB_CLK(x) ((uint32_t)(x) << 16U) #define DRVCTRL20_MLB_SIG(x) ((uint32_t)(x) << 12U) #define DRVCTRL20_MLB_DAT(x) ((uint32_t)(x) << 8U) #define DRVCTRL20_MLB_REF(x) ((uint32_t)(x) << 4U) #define DRVCTRL20_SSI_SCK0129(x) ((uint32_t)(x) << 0U) #define DRVCTRL21_SSI_WS0129(x) ((uint32_t)(x) << 28U) #define DRVCTRL21_SSI_SDATA0(x) ((uint32_t)(x) << 24U) #define DRVCTRL21_SSI_SDATA1(x) ((uint32_t)(x) << 20U) #define DRVCTRL21_SSI_SDATA2(x) ((uint32_t)(x) << 16U) #define DRVCTRL21_SSI_SCK34(x) ((uint32_t)(x) << 12U) #define DRVCTRL21_SSI_WS34(x) ((uint32_t)(x) << 8U) #define DRVCTRL21_SSI_SDATA3(x) ((uint32_t)(x) << 4U) #define DRVCTRL21_SSI_SCK4(x) ((uint32_t)(x) << 0U) #define DRVCTRL22_SSI_WS4(x) ((uint32_t)(x) << 28U) #define DRVCTRL22_SSI_SDATA4(x) ((uint32_t)(x) << 24U) #define DRVCTRL22_SSI_SCK5(x) ((uint32_t)(x) << 20U) #define DRVCTRL22_SSI_WS5(x) ((uint32_t)(x) << 16U) #define DRVCTRL22_SSI_SDATA5(x) ((uint32_t)(x) << 12U) #define DRVCTRL22_SSI_SCK6(x) ((uint32_t)(x) << 8U) #define DRVCTRL22_SSI_WS6(x) ((uint32_t)(x) << 4U) #define DRVCTRL22_SSI_SDATA6(x) ((uint32_t)(x) << 0U) #define DRVCTRL23_SSI_SCK78(x) ((uint32_t)(x) << 28U) #define DRVCTRL23_SSI_WS78(x) ((uint32_t)(x) << 24U) #define DRVCTRL23_SSI_SDATA7(x) ((uint32_t)(x) << 20U) #define DRVCTRL23_SSI_SDATA8(x) ((uint32_t)(x) << 16U) #define DRVCTRL23_SSI_SDATA9(x) ((uint32_t)(x) << 12U) #define DRVCTRL23_AUDIO_CLKA(x) ((uint32_t)(x) << 8U) #define DRVCTRL23_AUDIO_CLKB(x) ((uint32_t)(x) << 4U) #define DRVCTRL23_USB0_PWEN(x) ((uint32_t)(x) << 0U) #define DRVCTRL24_USB0_OVC(x) ((uint32_t)(x) << 28U) #define DRVCTRL24_USB1_PWEN(x) ((uint32_t)(x) << 24U) #define DRVCTRL24_USB1_OVC(x) ((uint32_t)(x) << 20U) #define DRVCTRL24_USB30_PWEN(x) ((uint32_t)(x) << 16U) #define DRVCTRL24_USB30_OVC(x) ((uint32_t)(x) << 12U) #define DRVCTRL24_USB31_PWEN(x) ((uint32_t)(x) << 8U) #define DRVCTRL24_USB31_OVC(x) ((uint32_t)(x) << 4U) #define MOD_SEL0_MSIOF3_A ((uint32_t)0U << 29U) #define MOD_SEL0_MSIOF3_B ((uint32_t)1U << 29U) #define MOD_SEL0_MSIOF3_C ((uint32_t)2U << 29U) #define MOD_SEL0_MSIOF3_D ((uint32_t)3U << 29U) #define MOD_SEL0_MSIOF2_A ((uint32_t)0U << 27U) #define MOD_SEL0_MSIOF2_B ((uint32_t)1U << 27U) #define MOD_SEL0_MSIOF2_C ((uint32_t)2U << 27U) #define MOD_SEL0_MSIOF2_D ((uint32_t)3U << 27U) #define MOD_SEL0_MSIOF1_A ((uint32_t)0U << 24U) #define MOD_SEL0_MSIOF1_B ((uint32_t)1U << 24U) #define MOD_SEL0_MSIOF1_C ((uint32_t)2U << 24U) #define MOD_SEL0_MSIOF1_D ((uint32_t)3U << 24U) #define MOD_SEL0_MSIOF1_E ((uint32_t)4U << 24U) #define MOD_SEL0_MSIOF1_F ((uint32_t)5U << 24U) #define MOD_SEL0_MSIOF1_G ((uint32_t)6U << 24U) #define MOD_SEL0_LBSC_A ((uint32_t)0U << 23U) #define MOD_SEL0_LBSC_B ((uint32_t)1U << 23U) #define MOD_SEL0_IEBUS_A ((uint32_t)0U << 22U) #define MOD_SEL0_IEBUS_B ((uint32_t)1U << 22U) #define MOD_SEL0_I2C6_A ((uint32_t)0U << 20U) #define MOD_SEL0_I2C6_B ((uint32_t)1U << 20U) #define MOD_SEL0_I2C6_C ((uint32_t)2U << 20U) #define MOD_SEL0_I2C2_A ((uint32_t)0U << 19U) #define MOD_SEL0_I2C2_B ((uint32_t)1U << 19U) #define MOD_SEL0_I2C1_A ((uint32_t)0U << 18U) #define MOD_SEL0_I2C1_B ((uint32_t)1U << 18U) #define MOD_SEL0_HSCIF4_A ((uint32_t)0U << 17U) #define MOD_SEL0_HSCIF4_B ((uint32_t)1U << 17U) #define MOD_SEL0_HSCIF3_A ((uint32_t)0U << 15U) #define MOD_SEL0_HSCIF3_B ((uint32_t)1U << 15U) #define MOD_SEL0_HSCIF3_C ((uint32_t)2U << 15U) #define MOD_SEL0_HSCIF3_D ((uint32_t)3U << 15U) #define MOD_SEL0_HSCIF2_A ((uint32_t)0U << 14U) #define MOD_SEL0_HSCIF2_B ((uint32_t)1U << 14U) #define MOD_SEL0_HSCIF1_A ((uint32_t)0U << 13U) #define MOD_SEL0_HSCIF1_B ((uint32_t)1U << 13U) #define MOD_SEL0_FSO_A ((uint32_t)0U << 12U) #define MOD_SEL0_FSO_B ((uint32_t)1U << 12U) #define MOD_SEL0_FM_A ((uint32_t)0U << 11U) #define MOD_SEL0_FM_B ((uint32_t)1U << 11U) #define MOD_SEL0_ETHERAVB_A ((uint32_t)0U << 10U) #define MOD_SEL0_ETHERAVB_B ((uint32_t)1U << 10U) #define MOD_SEL0_DRIF3_A ((uint32_t)0U << 9U) #define MOD_SEL0_DRIF3_B ((uint32_t)1U << 9U) #define MOD_SEL0_DRIF2_A ((uint32_t)0U << 8U) #define MOD_SEL0_DRIF2_B ((uint32_t)1U << 8U) #define MOD_SEL0_DRIF1_A ((uint32_t)0U << 6U) #define MOD_SEL0_DRIF1_B ((uint32_t)1U << 6U) #define MOD_SEL0_DRIF1_C ((uint32_t)2U << 6U) #define MOD_SEL0_DRIF0_A ((uint32_t)0U << 4U) #define MOD_SEL0_DRIF0_B ((uint32_t)1U << 4U) #define MOD_SEL0_DRIF0_C ((uint32_t)2U << 4U) #define MOD_SEL0_CANFD0_A ((uint32_t)0U << 3U) #define MOD_SEL0_CANFD0_B ((uint32_t)1U << 3U) #define MOD_SEL0_ADG_A ((uint32_t)0U << 1U) #define MOD_SEL0_ADG_B ((uint32_t)1U << 1U) #define MOD_SEL0_ADG_C ((uint32_t)2U << 1U) #define MOD_SEL0_ADG_D ((uint32_t)3U << 1U) #define MOD_SEL0_5LINE_A ((uint32_t)0U << 0U) #define MOD_SEL0_5LINE_B ((uint32_t)1U << 0U) #define MOD_SEL1_TSIF1_A ((uint32_t)0U << 30U) #define MOD_SEL1_TSIF1_B ((uint32_t)1U << 30U) #define MOD_SEL1_TSIF1_C ((uint32_t)2U << 30U) #define MOD_SEL1_TSIF1_D ((uint32_t)3U << 30U) #define MOD_SEL1_TSIF0_A ((uint32_t)0U << 27U) #define MOD_SEL1_TSIF0_B ((uint32_t)1U << 27U) #define MOD_SEL1_TSIF0_C ((uint32_t)2U << 27U) #define MOD_SEL1_TSIF0_D ((uint32_t)3U << 27U) #define MOD_SEL1_TSIF0_E ((uint32_t)4U << 27U) #define MOD_SEL1_TIMER_TMU_A ((uint32_t)0U << 26U) #define MOD_SEL1_TIMER_TMU_B ((uint32_t)1U << 26U) #define MOD_SEL1_SSP1_1_A ((uint32_t)0U << 24U) #define MOD_SEL1_SSP1_1_B ((uint32_t)1U << 24U) #define MOD_SEL1_SSP1_1_C ((uint32_t)2U << 24U) #define MOD_SEL1_SSP1_1_D ((uint32_t)3U << 24U) #define MOD_SEL1_SSP1_0_A ((uint32_t)0U << 21U) #define MOD_SEL1_SSP1_0_B ((uint32_t)1U << 21U) #define MOD_SEL1_SSP1_0_C ((uint32_t)2U << 21U) #define MOD_SEL1_SSP1_0_D ((uint32_t)3U << 21U) #define MOD_SEL1_SSP1_0_E ((uint32_t)4U << 21U) #define MOD_SEL1_SSI_A ((uint32_t)0U << 20U) #define MOD_SEL1_SSI_B ((uint32_t)1U << 20U) #define MOD_SEL1_SPEED_PULSE_IF_A ((uint32_t)0U << 19U) #define MOD_SEL1_SPEED_PULSE_IF_B ((uint32_t)1U << 19U) #define MOD_SEL1_SIMCARD_A ((uint32_t)0U << 17U) #define MOD_SEL1_SIMCARD_B ((uint32_t)1U << 17U) #define MOD_SEL1_SIMCARD_C ((uint32_t)2U << 17U) #define MOD_SEL1_SIMCARD_D ((uint32_t)3U << 17U) #define MOD_SEL1_SDHI2_A ((uint32_t)0U << 16U) #define MOD_SEL1_SDHI2_B ((uint32_t)1U << 16U) #define MOD_SEL1_SCIF4_A ((uint32_t)0U << 14U) #define MOD_SEL1_SCIF4_B ((uint32_t)1U << 14U) #define MOD_SEL1_SCIF4_C ((uint32_t)2U << 14U) #define MOD_SEL1_SCIF3_A ((uint32_t)0U << 13U) #define MOD_SEL1_SCIF3_B ((uint32_t)1U << 13U) #define MOD_SEL1_SCIF2_A ((uint32_t)0U << 12U) #define MOD_SEL1_SCIF2_B ((uint32_t)1U << 12U) #define MOD_SEL1_SCIF1_A ((uint32_t)0U << 11U) #define MOD_SEL1_SCIF1_B ((uint32_t)1U << 11U) #define MOD_SEL1_SCIF_A ((uint32_t)0U << 10U) #define MOD_SEL1_SCIF_B ((uint32_t)1U << 10U) #define MOD_SEL1_REMOCON_A ((uint32_t)0U << 9U) #define MOD_SEL1_REMOCON_B ((uint32_t)1U << 9U) #define MOD_SEL1_RCAN0_A ((uint32_t)0U << 6U) #define MOD_SEL1_RCAN0_B ((uint32_t)1U << 6U) #define MOD_SEL1_PWM6_A ((uint32_t)0U << 5U) #define MOD_SEL1_PWM6_B ((uint32_t)1U << 5U) #define MOD_SEL1_PWM5_A ((uint32_t)0U << 4U) #define MOD_SEL1_PWM5_B ((uint32_t)1U << 4U) #define MOD_SEL1_PWM4_A ((uint32_t)0U << 3U) #define MOD_SEL1_PWM4_B ((uint32_t)1U << 3U) #define MOD_SEL1_PWM3_A ((uint32_t)0U << 2U) #define MOD_SEL1_PWM3_B ((uint32_t)1U << 2U) #define MOD_SEL1_PWM2_A ((uint32_t)0U << 1U) #define MOD_SEL1_PWM2_B ((uint32_t)1U << 1U) #define MOD_SEL1_PWM1_A ((uint32_t)0U << 0U) #define MOD_SEL1_PWM1_B ((uint32_t)1U << 0U) #define MOD_SEL2_I2C_5_A ((uint32_t)0U << 31U) #define MOD_SEL2_I2C_5_B ((uint32_t)1U << 31U) #define MOD_SEL2_I2C_3_A ((uint32_t)0U << 30U) #define MOD_SEL2_I2C_3_B ((uint32_t)1U << 30U) #define MOD_SEL2_I2C_0_A ((uint32_t)0U << 29U) #define MOD_SEL2_I2C_0_B ((uint32_t)1U << 29U) #define MOD_SEL2_VIN4_A ((uint32_t)0U << 0U) #define MOD_SEL2_VIN4_B ((uint32_t)1U << 0U) static void pfc_reg_write(uint32_t addr, uint32_t data) { mmio_write_32(PFC_PMMR, ~data); mmio_write_32((uintptr_t)addr, data); } void pfc_init_h3_v1(void) { uint32_t reg; /* initialize module select */ pfc_reg_write(PFC_MOD_SEL0, MOD_SEL0_MSIOF3_A | MOD_SEL0_MSIOF2_A | MOD_SEL0_MSIOF1_A | MOD_SEL0_LBSC_A | MOD_SEL0_IEBUS_A | MOD_SEL0_I2C6_A | MOD_SEL0_I2C2_A | MOD_SEL0_I2C1_A | MOD_SEL0_HSCIF4_A | MOD_SEL0_HSCIF3_A | MOD_SEL0_HSCIF2_A | MOD_SEL0_HSCIF1_A | MOD_SEL0_FM_A | MOD_SEL0_ETHERAVB_A | MOD_SEL0_DRIF3_A | MOD_SEL0_DRIF2_A | MOD_SEL0_DRIF1_A | MOD_SEL0_DRIF0_A | MOD_SEL0_CANFD0_A | MOD_SEL0_ADG_A | MOD_SEL0_5LINE_A); pfc_reg_write(PFC_MOD_SEL1, MOD_SEL1_TSIF1_A | MOD_SEL1_TSIF0_A | MOD_SEL1_TIMER_TMU_A | MOD_SEL1_SSP1_1_A | MOD_SEL1_SSP1_0_A | MOD_SEL1_SSI_A | MOD_SEL1_SPEED_PULSE_IF_A | MOD_SEL1_SIMCARD_A | MOD_SEL1_SDHI2_A | MOD_SEL1_SCIF4_A | MOD_SEL1_SCIF3_A | MOD_SEL1_SCIF2_A | MOD_SEL1_SCIF1_A | MOD_SEL1_SCIF_A | MOD_SEL1_REMOCON_A | MOD_SEL1_RCAN0_A | MOD_SEL1_PWM6_A | MOD_SEL1_PWM5_A | MOD_SEL1_PWM4_A | MOD_SEL1_PWM3_A | MOD_SEL1_PWM2_A | MOD_SEL1_PWM1_A); pfc_reg_write(PFC_MOD_SEL2, MOD_SEL2_I2C_5_A | MOD_SEL2_I2C_3_A | MOD_SEL2_I2C_0_A | MOD_SEL2_VIN4_A); /* initialize peripheral function select */ pfc_reg_write(PFC_IPSR0, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR1, IPSR_28_FUNC(6) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(3) | IPSR_8_FUNC(3) | IPSR_4_FUNC(3) | IPSR_0_FUNC(3)); pfc_reg_write(PFC_IPSR2, IPSR_28_FUNC(0) | IPSR_24_FUNC(6) | IPSR_20_FUNC(6) | IPSR_16_FUNC(6) | IPSR_12_FUNC(6) | IPSR_8_FUNC(6) | IPSR_4_FUNC(6) | IPSR_0_FUNC(6)); pfc_reg_write(PFC_IPSR3, IPSR_28_FUNC(6) | IPSR_24_FUNC(6) | IPSR_20_FUNC(6) | IPSR_16_FUNC(6) | IPSR_12_FUNC(6) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR4, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(6) | IPSR_4_FUNC(6) | IPSR_0_FUNC(6)); pfc_reg_write(PFC_IPSR5, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(6) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR6, IPSR_28_FUNC(6) | IPSR_24_FUNC(6) | IPSR_20_FUNC(6) | IPSR_16_FUNC(6) | IPSR_12_FUNC(6) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR7, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_8_FUNC(6) | IPSR_4_FUNC(6) | IPSR_0_FUNC(6)); pfc_reg_write(PFC_IPSR8, IPSR_28_FUNC(1) | IPSR_24_FUNC(1) | IPSR_20_FUNC(1) | IPSR_16_FUNC(1) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR9, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR10, IPSR_28_FUNC(0) | IPSR_24_FUNC(4) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(1) | IPSR_0_FUNC(1)); pfc_reg_write(PFC_IPSR11, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(4) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR12, IPSR_28_FUNC(8) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(3) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR13, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(3) | IPSR_0_FUNC(8)); pfc_reg_write(PFC_IPSR14, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR15, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(1) | IPSR_0_FUNC(1)); pfc_reg_write(PFC_IPSR16, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(1) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR17, IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); /* initialize GPIO/perihperal function select */ pfc_reg_write(PFC_GPSR0, GPSR0_D15 | GPSR0_D14 | GPSR0_D13 | GPSR0_D12 | GPSR0_D11 | GPSR0_D10 | GPSR0_D9 | GPSR0_D8); pfc_reg_write(PFC_GPSR1, GPSR1_EX_WAIT0_A | GPSR1_A19 | GPSR1_A18 | GPSR1_A17 | GPSR1_A16 | GPSR1_A15 | GPSR1_A14 | GPSR1_A13 | GPSR1_A12 | GPSR1_A7 | GPSR1_A6 | GPSR1_A5 | GPSR1_A4 | GPSR1_A3 | GPSR1_A2 | GPSR1_A1 | GPSR1_A0); pfc_reg_write(PFC_GPSR2, GPSR2_AVB_AVTP_CAPTURE_A | GPSR2_AVB_AVTP_MATCH_A | GPSR2_AVB_LINK | GPSR2_AVB_PHY_INT | GPSR2_AVB_MDC | GPSR2_PWM2_A | GPSR2_PWM1_A | GPSR2_IRQ5 | GPSR2_IRQ4 | GPSR2_IRQ3 | GPSR2_IRQ2 | GPSR2_IRQ1 | GPSR2_IRQ0); pfc_reg_write(PFC_GPSR3, GPSR3_SD0_WP | GPSR3_SD0_CD | GPSR3_SD1_DAT3 | GPSR3_SD1_DAT2 | GPSR3_SD1_DAT1 | GPSR3_SD1_DAT0 | GPSR3_SD0_DAT3 | GPSR3_SD0_DAT2 | GPSR3_SD0_DAT1 | GPSR3_SD0_DAT0 | GPSR3_SD0_CMD | GPSR3_SD0_CLK); pfc_reg_write(PFC_GPSR4, GPSR4_SD3_DAT7 | GPSR4_SD3_DAT6 | GPSR4_SD3_DAT3 | GPSR4_SD3_DAT2 | GPSR4_SD3_DAT1 | GPSR4_SD3_DAT0 | GPSR4_SD3_CMD | GPSR4_SD3_CLK | GPSR4_SD2_DS | GPSR4_SD2_DAT3 | GPSR4_SD2_DAT2 | GPSR4_SD2_DAT1 | GPSR4_SD2_DAT0 | GPSR4_SD2_CMD | GPSR4_SD2_CLK); pfc_reg_write(PFC_GPSR5, GPSR5_MSIOF0_SS2 | GPSR5_MSIOF0_SS1 | GPSR5_MSIOF0_SYNC | GPSR5_HRTS0 | GPSR5_HCTS0 | GPSR5_HTX0 | GPSR5_HRX0 | GPSR5_HSCK0 | GPSR5_RX2_A | GPSR5_TX2_A | GPSR5_SCK2 | GPSR5_RTS1 | GPSR5_CTS1 | GPSR5_TX1_A | GPSR5_RX1_A | GPSR5_RTS0 | GPSR5_SCK0); pfc_reg_write(PFC_GPSR6, GPSR6_USB30_OVC | GPSR6_USB30_PWEN | GPSR6_USB1_OVC | GPSR6_USB1_PWEN | GPSR6_USB0_OVC | GPSR6_USB0_PWEN | GPSR6_AUDIO_CLKB_B | GPSR6_AUDIO_CLKA_A | GPSR6_SSI_SDATA8 | GPSR6_SSI_SDATA7 | GPSR6_SSI_WS78 | GPSR6_SSI_SCK78 | GPSR6_SSI_WS6 | GPSR6_SSI_SCK6 | GPSR6_SSI_SDATA4 | GPSR6_SSI_WS4 | GPSR6_SSI_SCK4 | GPSR6_SSI_SDATA1_A | GPSR6_SSI_SDATA0 | GPSR6_SSI_WS0129 | GPSR6_SSI_SCK0129); pfc_reg_write(PFC_GPSR7, GPSR7_AVS2 | GPSR7_AVS1); /* initialize POC control register */ pfc_reg_write(PFC_POCCTRL0, POC_SD3_DS_33V | POC_SD3_DAT7_33V | POC_SD3_DAT6_33V | POC_SD3_DAT5_33V | POC_SD3_DAT4_33V | POC_SD3_DAT3_33V | POC_SD3_DAT2_33V | POC_SD3_DAT1_33V | POC_SD3_DAT0_33V | POC_SD3_CMD_33V | POC_SD3_CLK_33V | POC_SD0_DAT3_33V | POC_SD0_DAT2_33V | POC_SD0_DAT1_33V | POC_SD0_DAT0_33V | POC_SD0_CMD_33V | POC_SD0_CLK_33V); /* initialize DRV control register */ reg = mmio_read_32(PFC_DRVCTRL0); reg = ((reg & DRVCTRL0_MASK) | DRVCTRL0_QSPI0_SPCLK(3) | DRVCTRL0_QSPI0_MOSI_IO0(3) | DRVCTRL0_QSPI0_MISO_IO1(3) | DRVCTRL0_QSPI0_IO2(3) | DRVCTRL0_QSPI0_IO3(3) | DRVCTRL0_QSPI0_SSL(3) | DRVCTRL0_QSPI1_SPCLK(3) | DRVCTRL0_QSPI1_MOSI_IO0(3)); pfc_reg_write(PFC_DRVCTRL0, reg); reg = mmio_read_32(PFC_DRVCTRL1); reg = ((reg & DRVCTRL1_MASK) | DRVCTRL1_QSPI1_MISO_IO1(3) | DRVCTRL1_QSPI1_IO2(3) | DRVCTRL1_QSPI1_IO3(3) | DRVCTRL1_QSPI1_SS(3) | DRVCTRL1_RPC_INT(3) | DRVCTRL1_RPC_WP(3) | DRVCTRL1_RPC_RESET(3) | DRVCTRL1_AVB_RX_CTL(7)); pfc_reg_write(PFC_DRVCTRL1, reg); reg = mmio_read_32(PFC_DRVCTRL2); reg = ((reg & DRVCTRL2_MASK) | DRVCTRL2_AVB_RXC(7) | DRVCTRL2_AVB_RD0(7) | DRVCTRL2_AVB_RD1(7) | DRVCTRL2_AVB_RD2(7) | DRVCTRL2_AVB_RD3(7) | DRVCTRL2_AVB_TX_CTL(3) | DRVCTRL2_AVB_TXC(3) | DRVCTRL2_AVB_TD0(3)); pfc_reg_write(PFC_DRVCTRL2, reg); reg = mmio_read_32(PFC_DRVCTRL3); reg = ((reg & DRVCTRL3_MASK) | DRVCTRL3_AVB_TD1(3) | DRVCTRL3_AVB_TD2(3) | DRVCTRL3_AVB_TD3(3) | DRVCTRL3_AVB_TXCREFCLK(7) | DRVCTRL3_AVB_MDIO(7) | DRVCTRL3_AVB_MDC(7) | DRVCTRL3_AVB_MAGIC(7) | DRVCTRL3_AVB_PHY_INT(7)); pfc_reg_write(PFC_DRVCTRL3, reg); reg = mmio_read_32(PFC_DRVCTRL4); reg = ((reg & DRVCTRL4_MASK) | DRVCTRL4_AVB_LINK(7) | DRVCTRL4_AVB_AVTP_MATCH(7) | DRVCTRL4_AVB_AVTP_CAPTURE(7) | DRVCTRL4_IRQ0(7) | DRVCTRL4_IRQ1(7) | DRVCTRL4_IRQ2(7) | DRVCTRL4_IRQ3(7) | DRVCTRL4_IRQ4(7)); pfc_reg_write(PFC_DRVCTRL4, reg); reg = mmio_read_32(PFC_DRVCTRL5); reg = ((reg & DRVCTRL5_MASK) | DRVCTRL5_IRQ5(7) | DRVCTRL5_PWM0(7) | DRVCTRL5_PWM1(7) | DRVCTRL5_PWM2(7) | DRVCTRL5_A0(3) | DRVCTRL5_A1(3) | DRVCTRL5_A2(3) | DRVCTRL5_A3(3)); pfc_reg_write(PFC_DRVCTRL5, reg); reg = mmio_read_32(PFC_DRVCTRL6); reg = ((reg & DRVCTRL6_MASK) | DRVCTRL6_A4(3) | DRVCTRL6_A5(3) | DRVCTRL6_A6(3) | DRVCTRL6_A7(3) | DRVCTRL6_A8(7) | DRVCTRL6_A9(7) | DRVCTRL6_A10(7) | DRVCTRL6_A11(7)); pfc_reg_write(PFC_DRVCTRL6, reg); reg = mmio_read_32(PFC_DRVCTRL7); reg = ((reg & DRVCTRL7_MASK) | DRVCTRL7_A12(3) | DRVCTRL7_A13(3) | DRVCTRL7_A14(3) | DRVCTRL7_A15(3) | DRVCTRL7_A16(3) | DRVCTRL7_A17(3) | DRVCTRL7_A18(3) | DRVCTRL7_A19(3)); pfc_reg_write(PFC_DRVCTRL7, reg); reg = mmio_read_32(PFC_DRVCTRL8); reg = ((reg & DRVCTRL8_MASK) | DRVCTRL8_CLKOUT(7) | DRVCTRL8_CS0(7) | DRVCTRL8_CS1_A2(7) | DRVCTRL8_BS(7) | DRVCTRL8_RD(7) | DRVCTRL8_RD_W(7) | DRVCTRL8_WE0(7) | DRVCTRL8_WE1(7)); pfc_reg_write(PFC_DRVCTRL8, reg); reg = mmio_read_32(PFC_DRVCTRL9); reg = ((reg & DRVCTRL9_MASK) | DRVCTRL9_EX_WAIT0(7) | DRVCTRL9_PRESETOU(7) | DRVCTRL9_D0(7) | DRVCTRL9_D1(7) | DRVCTRL9_D2(7) | DRVCTRL9_D3(7) | DRVCTRL9_D4(7) | DRVCTRL9_D5(7)); pfc_reg_write(PFC_DRVCTRL9, reg); reg = mmio_read_32(PFC_DRVCTRL10); reg = ((reg & DRVCTRL10_MASK) | DRVCTRL10_D6(7) | DRVCTRL10_D7(7) | DRVCTRL10_D8(3) | DRVCTRL10_D9(3) | DRVCTRL10_D10(3) | DRVCTRL10_D11(3) | DRVCTRL10_D12(3) | DRVCTRL10_D13(3)); pfc_reg_write(PFC_DRVCTRL10, reg); reg = mmio_read_32(PFC_DRVCTRL11); reg = ((reg & DRVCTRL11_MASK) | DRVCTRL11_D14(3) | DRVCTRL11_D15(3) | DRVCTRL11_AVS1(7) | DRVCTRL11_AVS2(7) | DRVCTRL11_GP7_02(7) | DRVCTRL11_GP7_03(7) | DRVCTRL11_DU_DOTCLKIN0(3) | DRVCTRL11_DU_DOTCLKIN1(3)); pfc_reg_write(PFC_DRVCTRL11, reg); reg = mmio_read_32(PFC_DRVCTRL12); reg = ((reg & DRVCTRL12_MASK) | DRVCTRL12_DU_DOTCLKIN2(3) | DRVCTRL12_DU_DOTCLKIN3(3) | DRVCTRL12_DU_FSCLKST(3) | DRVCTRL12_DU_TMS(3)); pfc_reg_write(PFC_DRVCTRL12, reg); reg = mmio_read_32(PFC_DRVCTRL13); reg = ((reg & DRVCTRL13_MASK) | DRVCTRL13_TDO(3) | DRVCTRL13_ASEBRK(3) | DRVCTRL13_SD0_CLK(2) | DRVCTRL13_SD0_CMD(2) | DRVCTRL13_SD0_DAT0(2) | DRVCTRL13_SD0_DAT1(2) | DRVCTRL13_SD0_DAT2(2) | DRVCTRL13_SD0_DAT3(2)); pfc_reg_write(PFC_DRVCTRL13, reg); reg = mmio_read_32(PFC_DRVCTRL14); reg = ((reg & DRVCTRL14_MASK) | DRVCTRL14_SD1_CLK(7) | DRVCTRL14_SD1_CMD(7) | DRVCTRL14_SD1_DAT0(5) | DRVCTRL14_SD1_DAT1(5) | DRVCTRL14_SD1_DAT2(5) | DRVCTRL14_SD1_DAT3(5) | DRVCTRL14_SD2_CLK(5) | DRVCTRL14_SD2_CMD(5)); pfc_reg_write(PFC_DRVCTRL14, reg); reg = mmio_read_32(PFC_DRVCTRL15); reg = ((reg & DRVCTRL15_MASK) | DRVCTRL15_SD2_DAT0(5) | DRVCTRL15_SD2_DAT1(5) | DRVCTRL15_SD2_DAT2(5) | DRVCTRL15_SD2_DAT3(5) | DRVCTRL15_SD2_DS(5) | DRVCTRL15_SD3_CLK(2) | DRVCTRL15_SD3_CMD(2) | DRVCTRL15_SD3_DAT0(2)); pfc_reg_write(PFC_DRVCTRL15, reg); reg = mmio_read_32(PFC_DRVCTRL16); reg = ((reg & DRVCTRL16_MASK) | DRVCTRL16_SD3_DAT1(2) | DRVCTRL16_SD3_DAT2(2) | DRVCTRL16_SD3_DAT3(2) | DRVCTRL16_SD3_DAT4(7) | DRVCTRL16_SD3_DAT5(7) | DRVCTRL16_SD3_DAT6(7) | DRVCTRL16_SD3_DAT7(7) | DRVCTRL16_SD3_DS(7)); pfc_reg_write(PFC_DRVCTRL16, reg); reg = mmio_read_32(PFC_DRVCTRL17); reg = ((reg & DRVCTRL17_MASK) | DRVCTRL17_SD0_CD(7) | DRVCTRL17_SD0_WP(7) | DRVCTRL17_SD1_CD(7) | DRVCTRL17_SD1_WP(7) | DRVCTRL17_SCK0(7) | DRVCTRL17_RX0(7) | DRVCTRL17_TX0(7) | DRVCTRL17_CTS0(7)); pfc_reg_write(PFC_DRVCTRL17, reg); reg = mmio_read_32(PFC_DRVCTRL18); reg = ((reg & DRVCTRL18_MASK) | DRVCTRL18_RTS0_TANS(7) | DRVCTRL18_RX1(7) | DRVCTRL18_TX1(7) | DRVCTRL18_CTS1(7) | DRVCTRL18_RTS1_TANS(7) | DRVCTRL18_SCK2(7) | DRVCTRL18_TX2(7) | DRVCTRL18_RX2(7)); pfc_reg_write(PFC_DRVCTRL18, reg); reg = mmio_read_32(PFC_DRVCTRL19); reg = ((reg & DRVCTRL19_MASK) | DRVCTRL19_HSCK0(7) | DRVCTRL19_HRX0(7) | DRVCTRL19_HTX0(7) | DRVCTRL19_HCTS0(7) | DRVCTRL19_HRTS0(7) | DRVCTRL19_MSIOF0_SCK(7) | DRVCTRL19_MSIOF0_SYNC(7) | DRVCTRL19_MSIOF0_SS1(7)); pfc_reg_write(PFC_DRVCTRL19, reg); reg = mmio_read_32(PFC_DRVCTRL20); reg = ((reg & DRVCTRL20_MASK) | DRVCTRL20_MSIOF0_TXD(7) | DRVCTRL20_MSIOF0_SS2(7) | DRVCTRL20_MSIOF0_RXD(7) | DRVCTRL20_MLB_CLK(7) | DRVCTRL20_MLB_SIG(7) | DRVCTRL20_MLB_DAT(7) | DRVCTRL20_MLB_REF(7) | DRVCTRL20_SSI_SCK0129(7)); pfc_reg_write(PFC_DRVCTRL20, reg); reg = mmio_read_32(PFC_DRVCTRL21); reg = ((reg & DRVCTRL21_MASK) | DRVCTRL21_SSI_WS0129(7) | DRVCTRL21_SSI_SDATA0(7) | DRVCTRL21_SSI_SDATA1(7) | DRVCTRL21_SSI_SDATA2(7) | DRVCTRL21_SSI_SCK34(7) | DRVCTRL21_SSI_WS34(7) | DRVCTRL21_SSI_SDATA3(7) | DRVCTRL21_SSI_SCK4(7)); pfc_reg_write(PFC_DRVCTRL21, reg); reg = mmio_read_32(PFC_DRVCTRL22); reg = ((reg & DRVCTRL22_MASK) | DRVCTRL22_SSI_WS4(7) | DRVCTRL22_SSI_SDATA4(7) | DRVCTRL22_SSI_SCK5(7) | DRVCTRL22_SSI_WS5(7) | DRVCTRL22_SSI_SDATA5(7) | DRVCTRL22_SSI_SCK6(7) | DRVCTRL22_SSI_WS6(7) | DRVCTRL22_SSI_SDATA6(7)); pfc_reg_write(PFC_DRVCTRL22, reg); reg = mmio_read_32(PFC_DRVCTRL23); reg = ((reg & DRVCTRL23_MASK) | DRVCTRL23_SSI_SCK78(7) | DRVCTRL23_SSI_WS78(7) | DRVCTRL23_SSI_SDATA7(7) | DRVCTRL23_SSI_SDATA8(7) | DRVCTRL23_SSI_SDATA9(7) | DRVCTRL23_AUDIO_CLKA(7) | DRVCTRL23_AUDIO_CLKB(7) | DRVCTRL23_USB0_PWEN(7)); pfc_reg_write(PFC_DRVCTRL23, reg); reg = mmio_read_32(PFC_DRVCTRL24); reg = ((reg & DRVCTRL24_MASK) | DRVCTRL24_USB0_OVC(7) | DRVCTRL24_USB1_PWEN(7) | DRVCTRL24_USB1_OVC(7) | DRVCTRL24_USB30_PWEN(7) | DRVCTRL24_USB30_OVC(7) | DRVCTRL24_USB31_PWEN(7) | DRVCTRL24_USB31_OVC(7)); pfc_reg_write(PFC_DRVCTRL24, reg); /* initialize LSI pin pull-up/down control */ pfc_reg_write(PFC_PUD0, 0x00005FBFU); pfc_reg_write(PFC_PUD1, 0x00300FFEU); pfc_reg_write(PFC_PUD2, 0x330001E6U); pfc_reg_write(PFC_PUD3, 0x000002E0U); pfc_reg_write(PFC_PUD4, 0xFFFFFF00U); pfc_reg_write(PFC_PUD5, 0x7F5FFF87U); pfc_reg_write(PFC_PUD6, 0x00000055U); /* initialize LSI pin pull-enable register */ pfc_reg_write(PFC_PUEN0, 0x00000FFFU); pfc_reg_write(PFC_PUEN1, 0x00100234U); pfc_reg_write(PFC_PUEN2, 0x000004C4U); pfc_reg_write(PFC_PUEN3, 0x00000200U); pfc_reg_write(PFC_PUEN4, 0x3E000000U); pfc_reg_write(PFC_PUEN5, 0x1F000805U); pfc_reg_write(PFC_PUEN6, 0x00000006U); /* initialize positive/negative logic select */ mmio_write_32(GPIO_POSNEG0, 0x00000000U); mmio_write_32(GPIO_POSNEG1, 0x00000000U); mmio_write_32(GPIO_POSNEG2, 0x00000000U); mmio_write_32(GPIO_POSNEG3, 0x00000000U); mmio_write_32(GPIO_POSNEG4, 0x00000000U); mmio_write_32(GPIO_POSNEG5, 0x00000000U); mmio_write_32(GPIO_POSNEG6, 0x00000000U); mmio_write_32(GPIO_POSNEG7, 0x00000000U); /* initialize general IO/interrupt switching */ mmio_write_32(GPIO_IOINTSEL0, 0x00000000U); mmio_write_32(GPIO_IOINTSEL1, 0x00000000U); mmio_write_32(GPIO_IOINTSEL2, 0x00000000U); mmio_write_32(GPIO_IOINTSEL3, 0x00000000U); mmio_write_32(GPIO_IOINTSEL4, 0x00000000U); mmio_write_32(GPIO_IOINTSEL5, 0x00000000U); mmio_write_32(GPIO_IOINTSEL6, 0x00000000U); mmio_write_32(GPIO_IOINTSEL7, 0x00000000U); /* initialize general output register */ mmio_write_32(GPIO_OUTDT1, 0x00000000U); mmio_write_32(GPIO_OUTDT2, 0x00000400U); mmio_write_32(GPIO_OUTDT3, 0x0000C000U); mmio_write_32(GPIO_OUTDT5, 0x00000006U); mmio_write_32(GPIO_OUTDT6, 0x00003880U); /* initialize general input/output switching */ mmio_write_32(GPIO_INOUTSEL0, 0x00000000U); mmio_write_32(GPIO_INOUTSEL1, 0x01000A00U); mmio_write_32(GPIO_INOUTSEL2, 0x00000400U); mmio_write_32(GPIO_INOUTSEL3, 0x0000C000U); mmio_write_32(GPIO_INOUTSEL4, 0x00000000U); #if (RCAR_GEN3_ULCB == 1) mmio_write_32(GPIO_INOUTSEL5, 0x0000000EU); #else mmio_write_32(GPIO_INOUTSEL5, 0x0000020EU); #endif mmio_write_32(GPIO_INOUTSEL6, 0x00013880U); mmio_write_32(GPIO_INOUTSEL7, 0x00000000U); } trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.h000066400000000000000000000003631355360272700251460ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PFC_INIT_H3_V1_H #define PFC_INIT_H3_V1_H void pfc_init_h3_v1(void); #endif /* PFC_INIT_H3_V1_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c000066400000000000000000001244321355360272700251460ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* for uint32_t */ #include #include "pfc_init_h3_v2.h" #include "rcar_def.h" #include "../pfc_regs.h" #define GPSR0_D15 BIT(15) #define GPSR0_D14 BIT(14) #define GPSR0_D13 BIT(13) #define GPSR0_D12 BIT(12) #define GPSR0_D11 BIT(11) #define GPSR0_D10 BIT(10) #define GPSR0_D9 BIT(9) #define GPSR0_D8 BIT(8) #define GPSR0_D7 BIT(7) #define GPSR0_D6 BIT(6) #define GPSR0_D5 BIT(5) #define GPSR0_D4 BIT(4) #define GPSR0_D3 BIT(3) #define GPSR0_D2 BIT(2) #define GPSR0_D1 BIT(1) #define GPSR0_D0 BIT(0) #define GPSR1_CLKOUT BIT(28) #define GPSR1_EX_WAIT0_A BIT(27) #define GPSR1_WE1 BIT(26) #define GPSR1_WE0 BIT(25) #define GPSR1_RD_WR BIT(24) #define GPSR1_RD BIT(23) #define GPSR1_BS BIT(22) #define GPSR1_CS1_A26 BIT(21) #define GPSR1_CS0 BIT(20) #define GPSR1_A19 BIT(19) #define GPSR1_A18 BIT(18) #define GPSR1_A17 BIT(17) #define GPSR1_A16 BIT(16) #define GPSR1_A15 BIT(15) #define GPSR1_A14 BIT(14) #define GPSR1_A13 BIT(13) #define GPSR1_A12 BIT(12) #define GPSR1_A11 BIT(11) #define GPSR1_A10 BIT(10) #define GPSR1_A9 BIT(9) #define GPSR1_A8 BIT(8) #define GPSR1_A7 BIT(7) #define GPSR1_A6 BIT(6) #define GPSR1_A5 BIT(5) #define GPSR1_A4 BIT(4) #define GPSR1_A3 BIT(3) #define GPSR1_A2 BIT(2) #define GPSR1_A1 BIT(1) #define GPSR1_A0 BIT(0) #define GPSR2_AVB_AVTP_CAPTURE_A BIT(14) #define GPSR2_AVB_AVTP_MATCH_A BIT(13) #define GPSR2_AVB_LINK BIT(12) #define GPSR2_AVB_PHY_INT BIT(11) #define GPSR2_AVB_MAGIC BIT(10) #define GPSR2_AVB_MDC BIT(9) #define GPSR2_PWM2_A BIT(8) #define GPSR2_PWM1_A BIT(7) #define GPSR2_PWM0 BIT(6) #define GPSR2_IRQ5 BIT(5) #define GPSR2_IRQ4 BIT(4) #define GPSR2_IRQ3 BIT(3) #define GPSR2_IRQ2 BIT(2) #define GPSR2_IRQ1 BIT(1) #define GPSR2_IRQ0 BIT(0) #define GPSR3_SD1_WP BIT(15) #define GPSR3_SD1_CD BIT(14) #define GPSR3_SD0_WP BIT(13) #define GPSR3_SD0_CD BIT(12) #define GPSR3_SD1_DAT3 BIT(11) #define GPSR3_SD1_DAT2 BIT(10) #define GPSR3_SD1_DAT1 BIT(9) #define GPSR3_SD1_DAT0 BIT(8) #define GPSR3_SD1_CMD BIT(7) #define GPSR3_SD1_CLK BIT(6) #define GPSR3_SD0_DAT3 BIT(5) #define GPSR3_SD0_DAT2 BIT(4) #define GPSR3_SD0_DAT1 BIT(3) #define GPSR3_SD0_DAT0 BIT(2) #define GPSR3_SD0_CMD BIT(1) #define GPSR3_SD0_CLK BIT(0) #define GPSR4_SD3_DS BIT(17) #define GPSR4_SD3_DAT7 BIT(16) #define GPSR4_SD3_DAT6 BIT(15) #define GPSR4_SD3_DAT5 BIT(14) #define GPSR4_SD3_DAT4 BIT(13) #define GPSR4_SD3_DAT3 BIT(12) #define GPSR4_SD3_DAT2 BIT(11) #define GPSR4_SD3_DAT1 BIT(10) #define GPSR4_SD3_DAT0 BIT(9) #define GPSR4_SD3_CMD BIT(8) #define GPSR4_SD3_CLK BIT(7) #define GPSR4_SD2_DS BIT(6) #define GPSR4_SD2_DAT3 BIT(5) #define GPSR4_SD2_DAT2 BIT(4) #define GPSR4_SD2_DAT1 BIT(3) #define GPSR4_SD2_DAT0 BIT(2) #define GPSR4_SD2_CMD BIT(1) #define GPSR4_SD2_CLK BIT(0) #define GPSR5_MLB_DAT BIT(25) #define GPSR5_MLB_SIG BIT(24) #define GPSR5_MLB_CLK BIT(23) #define GPSR5_MSIOF0_RXD BIT(22) #define GPSR5_MSIOF0_SS2 BIT(21) #define GPSR5_MSIOF0_TXD BIT(20) #define GPSR5_MSIOF0_SS1 BIT(19) #define GPSR5_MSIOF0_SYNC BIT(18) #define GPSR5_MSIOF0_SCK BIT(17) #define GPSR5_HRTS0 BIT(16) #define GPSR5_HCTS0 BIT(15) #define GPSR5_HTX0 BIT(14) #define GPSR5_HRX0 BIT(13) #define GPSR5_HSCK0 BIT(12) #define GPSR5_RX2_A BIT(11) #define GPSR5_TX2_A BIT(10) #define GPSR5_SCK2 BIT(9) #define GPSR5_RTS1 BIT(8) #define GPSR5_CTS1 BIT(7) #define GPSR5_TX1_A BIT(6) #define GPSR5_RX1_A BIT(5) #define GPSR5_RTS0 BIT(4) #define GPSR5_CTS0 BIT(3) #define GPSR5_TX0 BIT(2) #define GPSR5_RX0 BIT(1) #define GPSR5_SCK0 BIT(0) #define GPSR6_USB31_OVC BIT(31) #define GPSR6_USB31_PWEN BIT(30) #define GPSR6_USB30_OVC BIT(29) #define GPSR6_USB30_PWEN BIT(28) #define GPSR6_USB1_OVC BIT(27) #define GPSR6_USB1_PWEN BIT(26) #define GPSR6_USB0_OVC BIT(25) #define GPSR6_USB0_PWEN BIT(24) #define GPSR6_AUDIO_CLKB_B BIT(23) #define GPSR6_AUDIO_CLKA_A BIT(22) #define GPSR6_SSI_SDATA9_A BIT(21) #define GPSR6_SSI_SDATA8 BIT(20) #define GPSR6_SSI_SDATA7 BIT(19) #define GPSR6_SSI_WS78 BIT(18) #define GPSR6_SSI_SCK78 BIT(17) #define GPSR6_SSI_SDATA6 BIT(16) #define GPSR6_SSI_WS6 BIT(15) #define GPSR6_SSI_SCK6 BIT(14) #define GPSR6_SSI_SDATA5 BIT(13) #define GPSR6_SSI_WS5 BIT(12) #define GPSR6_SSI_SCK5 BIT(11) #define GPSR6_SSI_SDATA4 BIT(10) #define GPSR6_SSI_WS4 BIT(9) #define GPSR6_SSI_SCK4 BIT(8) #define GPSR6_SSI_SDATA3 BIT(7) #define GPSR6_SSI_WS34 BIT(6) #define GPSR6_SSI_SCK34 BIT(5) #define GPSR6_SSI_SDATA2_A BIT(4) #define GPSR6_SSI_SDATA1_A BIT(3) #define GPSR6_SSI_SDATA0 BIT(2) #define GPSR6_SSI_WS0129 BIT(1) #define GPSR6_SSI_SCK0129 BIT(0) #define GPSR7_AVS2 BIT(1) #define GPSR7_AVS1 BIT(0) #define IPSR_28_FUNC(x) ((uint32_t)(x) << 28U) #define IPSR_24_FUNC(x) ((uint32_t)(x) << 24U) #define IPSR_20_FUNC(x) ((uint32_t)(x) << 20U) #define IPSR_16_FUNC(x) ((uint32_t)(x) << 16U) #define IPSR_12_FUNC(x) ((uint32_t)(x) << 12U) #define IPSR_8_FUNC(x) ((uint32_t)(x) << 8U) #define IPSR_4_FUNC(x) ((uint32_t)(x) << 4U) #define IPSR_0_FUNC(x) ((uint32_t)(x) << 0U) #define POC_SD3_DS_33V BIT(29) #define POC_SD3_DAT7_33V BIT(28) #define POC_SD3_DAT6_33V BIT(27) #define POC_SD3_DAT5_33V BIT(26) #define POC_SD3_DAT4_33V BIT(25) #define POC_SD3_DAT3_33V BIT(24) #define POC_SD3_DAT2_33V BIT(23) #define POC_SD3_DAT1_33V BIT(22) #define POC_SD3_DAT0_33V BIT(21) #define POC_SD3_CMD_33V BIT(20) #define POC_SD3_CLK_33V BIT(19) #define POC_SD2_DS_33V BIT(18) #define POC_SD2_DAT3_33V BIT(17) #define POC_SD2_DAT2_33V BIT(16) #define POC_SD2_DAT1_33V BIT(15) #define POC_SD2_DAT0_33V BIT(14) #define POC_SD2_CMD_33V BIT(13) #define POC_SD2_CLK_33V BIT(12) #define POC_SD1_DAT3_33V BIT(11) #define POC_SD1_DAT2_33V BIT(10) #define POC_SD1_DAT1_33V BIT(9) #define POC_SD1_DAT0_33V BIT(8) #define POC_SD1_CMD_33V BIT(7) #define POC_SD1_CLK_33V BIT(6) #define POC_SD0_DAT3_33V BIT(5) #define POC_SD0_DAT2_33V BIT(4) #define POC_SD0_DAT1_33V BIT(3) #define POC_SD0_DAT0_33V BIT(2) #define POC_SD0_CMD_33V BIT(1) #define POC_SD0_CLK_33V BIT(0) #define DRVCTRL0_MASK (0xCCCCCCCCU) #define DRVCTRL1_MASK (0xCCCCCCC8U) #define DRVCTRL2_MASK (0x88888888U) #define DRVCTRL3_MASK (0x88888888U) #define DRVCTRL4_MASK (0x88888888U) #define DRVCTRL5_MASK (0x88888888U) #define DRVCTRL6_MASK (0x88888888U) #define DRVCTRL7_MASK (0x88888888U) #define DRVCTRL8_MASK (0x88888888U) #define DRVCTRL9_MASK (0x88888888U) #define DRVCTRL10_MASK (0x88888888U) #define DRVCTRL11_MASK (0x888888CCU) #define DRVCTRL12_MASK (0xCCCFFFCFU) #define DRVCTRL13_MASK (0xCC888888U) #define DRVCTRL14_MASK (0x88888888U) #define DRVCTRL15_MASK (0x88888888U) #define DRVCTRL16_MASK (0x88888888U) #define DRVCTRL17_MASK (0x88888888U) #define DRVCTRL18_MASK (0x88888888U) #define DRVCTRL19_MASK (0x88888888U) #define DRVCTRL20_MASK (0x88888888U) #define DRVCTRL21_MASK (0x88888888U) #define DRVCTRL22_MASK (0x88888888U) #define DRVCTRL23_MASK (0x88888888U) #define DRVCTRL24_MASK (0x8888888FU) #define DRVCTRL0_QSPI0_SPCLK(x) ((uint32_t)(x) << 28U) #define DRVCTRL0_QSPI0_MOSI_IO0(x) ((uint32_t)(x) << 24U) #define DRVCTRL0_QSPI0_MISO_IO1(x) ((uint32_t)(x) << 20U) #define DRVCTRL0_QSPI0_IO2(x) ((uint32_t)(x) << 16U) #define DRVCTRL0_QSPI0_IO3(x) ((uint32_t)(x) << 12U) #define DRVCTRL0_QSPI0_SSL(x) ((uint32_t)(x) << 8U) #define DRVCTRL0_QSPI1_SPCLK(x) ((uint32_t)(x) << 4U) #define DRVCTRL0_QSPI1_MOSI_IO0(x) ((uint32_t)(x) << 0U) #define DRVCTRL1_QSPI1_MISO_IO1(x) ((uint32_t)(x) << 28U) #define DRVCTRL1_QSPI1_IO2(x) ((uint32_t)(x) << 24U) #define DRVCTRL1_QSPI1_IO3(x) ((uint32_t)(x) << 20U) #define DRVCTRL1_QSPI1_SS(x) ((uint32_t)(x) << 16U) #define DRVCTRL1_RPC_INT(x) ((uint32_t)(x) << 12U) #define DRVCTRL1_RPC_WP(x) ((uint32_t)(x) << 8U) #define DRVCTRL1_RPC_RESET(x) ((uint32_t)(x) << 4U) #define DRVCTRL1_AVB_RX_CTL(x) ((uint32_t)(x) << 0U) #define DRVCTRL2_AVB_RXC(x) ((uint32_t)(x) << 28U) #define DRVCTRL2_AVB_RD0(x) ((uint32_t)(x) << 24U) #define DRVCTRL2_AVB_RD1(x) ((uint32_t)(x) << 20U) #define DRVCTRL2_AVB_RD2(x) ((uint32_t)(x) << 16U) #define DRVCTRL2_AVB_RD3(x) ((uint32_t)(x) << 12U) #define DRVCTRL2_AVB_TX_CTL(x) ((uint32_t)(x) << 8U) #define DRVCTRL2_AVB_TXC(x) ((uint32_t)(x) << 4U) #define DRVCTRL2_AVB_TD0(x) ((uint32_t)(x) << 0U) #define DRVCTRL3_AVB_TD1(x) ((uint32_t)(x) << 28U) #define DRVCTRL3_AVB_TD2(x) ((uint32_t)(x) << 24U) #define DRVCTRL3_AVB_TD3(x) ((uint32_t)(x) << 20U) #define DRVCTRL3_AVB_TXCREFCLK(x) ((uint32_t)(x) << 16U) #define DRVCTRL3_AVB_MDIO(x) ((uint32_t)(x) << 12U) #define DRVCTRL3_AVB_MDC(x) ((uint32_t)(x) << 8U) #define DRVCTRL3_AVB_MAGIC(x) ((uint32_t)(x) << 4U) #define DRVCTRL3_AVB_PHY_INT(x) ((uint32_t)(x) << 0U) #define DRVCTRL4_AVB_LINK(x) ((uint32_t)(x) << 28U) #define DRVCTRL4_AVB_AVTP_MATCH(x) ((uint32_t)(x) << 24U) #define DRVCTRL4_AVB_AVTP_CAPTURE(x) ((uint32_t)(x) << 20U) #define DRVCTRL4_IRQ0(x) ((uint32_t)(x) << 16U) #define DRVCTRL4_IRQ1(x) ((uint32_t)(x) << 12U) #define DRVCTRL4_IRQ2(x) ((uint32_t)(x) << 8U) #define DRVCTRL4_IRQ3(x) ((uint32_t)(x) << 4U) #define DRVCTRL4_IRQ4(x) ((uint32_t)(x) << 0U) #define DRVCTRL5_IRQ5(x) ((uint32_t)(x) << 28U) #define DRVCTRL5_PWM0(x) ((uint32_t)(x) << 24U) #define DRVCTRL5_PWM1(x) ((uint32_t)(x) << 20U) #define DRVCTRL5_PWM2(x) ((uint32_t)(x) << 16U) #define DRVCTRL5_A0(x) ((uint32_t)(x) << 12U) #define DRVCTRL5_A1(x) ((uint32_t)(x) << 8U) #define DRVCTRL5_A2(x) ((uint32_t)(x) << 4U) #define DRVCTRL5_A3(x) ((uint32_t)(x) << 0U) #define DRVCTRL6_A4(x) ((uint32_t)(x) << 28U) #define DRVCTRL6_A5(x) ((uint32_t)(x) << 24U) #define DRVCTRL6_A6(x) ((uint32_t)(x) << 20U) #define DRVCTRL6_A7(x) ((uint32_t)(x) << 16U) #define DRVCTRL6_A8(x) ((uint32_t)(x) << 12U) #define DRVCTRL6_A9(x) ((uint32_t)(x) << 8U) #define DRVCTRL6_A10(x) ((uint32_t)(x) << 4U) #define DRVCTRL6_A11(x) ((uint32_t)(x) << 0U) #define DRVCTRL7_A12(x) ((uint32_t)(x) << 28U) #define DRVCTRL7_A13(x) ((uint32_t)(x) << 24U) #define DRVCTRL7_A14(x) ((uint32_t)(x) << 20U) #define DRVCTRL7_A15(x) ((uint32_t)(x) << 16U) #define DRVCTRL7_A16(x) ((uint32_t)(x) << 12U) #define DRVCTRL7_A17(x) ((uint32_t)(x) << 8U) #define DRVCTRL7_A18(x) ((uint32_t)(x) << 4U) #define DRVCTRL7_A19(x) ((uint32_t)(x) << 0U) #define DRVCTRL8_CLKOUT(x) ((uint32_t)(x) << 28U) #define DRVCTRL8_CS0(x) ((uint32_t)(x) << 24U) #define DRVCTRL8_CS1_A2(x) ((uint32_t)(x) << 20U) #define DRVCTRL8_BS(x) ((uint32_t)(x) << 16U) #define DRVCTRL8_RD(x) ((uint32_t)(x) << 12U) #define DRVCTRL8_RD_W(x) ((uint32_t)(x) << 8U) #define DRVCTRL8_WE0(x) ((uint32_t)(x) << 4U) #define DRVCTRL8_WE1(x) ((uint32_t)(x) << 0U) #define DRVCTRL9_EX_WAIT0(x) ((uint32_t)(x) << 28U) #define DRVCTRL9_PRESETOU(x) ((uint32_t)(x) << 24U) #define DRVCTRL9_D0(x) ((uint32_t)(x) << 20U) #define DRVCTRL9_D1(x) ((uint32_t)(x) << 16U) #define DRVCTRL9_D2(x) ((uint32_t)(x) << 12U) #define DRVCTRL9_D3(x) ((uint32_t)(x) << 8U) #define DRVCTRL9_D4(x) ((uint32_t)(x) << 4U) #define DRVCTRL9_D5(x) ((uint32_t)(x) << 0U) #define DRVCTRL10_D6(x) ((uint32_t)(x) << 28U) #define DRVCTRL10_D7(x) ((uint32_t)(x) << 24U) #define DRVCTRL10_D8(x) ((uint32_t)(x) << 20U) #define DRVCTRL10_D9(x) ((uint32_t)(x) << 16U) #define DRVCTRL10_D10(x) ((uint32_t)(x) << 12U) #define DRVCTRL10_D11(x) ((uint32_t)(x) << 8U) #define DRVCTRL10_D12(x) ((uint32_t)(x) << 4U) #define DRVCTRL10_D13(x) ((uint32_t)(x) << 0U) #define DRVCTRL11_D14(x) ((uint32_t)(x) << 28U) #define DRVCTRL11_D15(x) ((uint32_t)(x) << 24U) #define DRVCTRL11_AVS1(x) ((uint32_t)(x) << 20U) #define DRVCTRL11_AVS2(x) ((uint32_t)(x) << 16U) #define DRVCTRL11_GP7_02(x) ((uint32_t)(x) << 12U) #define DRVCTRL11_GP7_03(x) ((uint32_t)(x) << 8U) #define DRVCTRL11_DU_DOTCLKIN0(x) ((uint32_t)(x) << 4U) #define DRVCTRL11_DU_DOTCLKIN1(x) ((uint32_t)(x) << 0U) #define DRVCTRL12_DU_DOTCLKIN2(x) ((uint32_t)(x) << 28U) #define DRVCTRL12_DU_DOTCLKIN3(x) ((uint32_t)(x) << 24U) #define DRVCTRL12_DU_FSCLKST(x) ((uint32_t)(x) << 20U) #define DRVCTRL12_DU_TMS(x) ((uint32_t)(x) << 4U) #define DRVCTRL13_TDO(x) ((uint32_t)(x) << 28U) #define DRVCTRL13_ASEBRK(x) ((uint32_t)(x) << 24U) #define DRVCTRL13_SD0_CLK(x) ((uint32_t)(x) << 20U) #define DRVCTRL13_SD0_CMD(x) ((uint32_t)(x) << 16U) #define DRVCTRL13_SD0_DAT0(x) ((uint32_t)(x) << 12U) #define DRVCTRL13_SD0_DAT1(x) ((uint32_t)(x) << 8U) #define DRVCTRL13_SD0_DAT2(x) ((uint32_t)(x) << 4U) #define DRVCTRL13_SD0_DAT3(x) ((uint32_t)(x) << 0U) #define DRVCTRL14_SD1_CLK(x) ((uint32_t)(x) << 28U) #define DRVCTRL14_SD1_CMD(x) ((uint32_t)(x) << 24U) #define DRVCTRL14_SD1_DAT0(x) ((uint32_t)(x) << 20U) #define DRVCTRL14_SD1_DAT1(x) ((uint32_t)(x) << 16U) #define DRVCTRL14_SD1_DAT2(x) ((uint32_t)(x) << 12U) #define DRVCTRL14_SD1_DAT3(x) ((uint32_t)(x) << 8U) #define DRVCTRL14_SD2_CLK(x) ((uint32_t)(x) << 4U) #define DRVCTRL14_SD2_CMD(x) ((uint32_t)(x) << 0U) #define DRVCTRL15_SD2_DAT0(x) ((uint32_t)(x) << 28U) #define DRVCTRL15_SD2_DAT1(x) ((uint32_t)(x) << 24U) #define DRVCTRL15_SD2_DAT2(x) ((uint32_t)(x) << 20U) #define DRVCTRL15_SD2_DAT3(x) ((uint32_t)(x) << 16U) #define DRVCTRL15_SD2_DS(x) ((uint32_t)(x) << 12U) #define DRVCTRL15_SD3_CLK(x) ((uint32_t)(x) << 8U) #define DRVCTRL15_SD3_CMD(x) ((uint32_t)(x) << 4U) #define DRVCTRL15_SD3_DAT0(x) ((uint32_t)(x) << 0U) #define DRVCTRL16_SD3_DAT1(x) ((uint32_t)(x) << 28U) #define DRVCTRL16_SD3_DAT2(x) ((uint32_t)(x) << 24U) #define DRVCTRL16_SD3_DAT3(x) ((uint32_t)(x) << 20U) #define DRVCTRL16_SD3_DAT4(x) ((uint32_t)(x) << 16U) #define DRVCTRL16_SD3_DAT5(x) ((uint32_t)(x) << 12U) #define DRVCTRL16_SD3_DAT6(x) ((uint32_t)(x) << 8U) #define DRVCTRL16_SD3_DAT7(x) ((uint32_t)(x) << 4U) #define DRVCTRL16_SD3_DS(x) ((uint32_t)(x) << 0U) #define DRVCTRL17_SD0_CD(x) ((uint32_t)(x) << 28U) #define DRVCTRL17_SD0_WP(x) ((uint32_t)(x) << 24U) #define DRVCTRL17_SD1_CD(x) ((uint32_t)(x) << 20U) #define DRVCTRL17_SD1_WP(x) ((uint32_t)(x) << 16U) #define DRVCTRL17_SCK0(x) ((uint32_t)(x) << 12U) #define DRVCTRL17_RX0(x) ((uint32_t)(x) << 8U) #define DRVCTRL17_TX0(x) ((uint32_t)(x) << 4U) #define DRVCTRL17_CTS0(x) ((uint32_t)(x) << 0U) #define DRVCTRL18_RTS0_TANS(x) ((uint32_t)(x) << 28U) #define DRVCTRL18_RX1(x) ((uint32_t)(x) << 24U) #define DRVCTRL18_TX1(x) ((uint32_t)(x) << 20U) #define DRVCTRL18_CTS1(x) ((uint32_t)(x) << 16U) #define DRVCTRL18_RTS1_TANS(x) ((uint32_t)(x) << 12U) #define DRVCTRL18_SCK2(x) ((uint32_t)(x) << 8U) #define DRVCTRL18_TX2(x) ((uint32_t)(x) << 4U) #define DRVCTRL18_RX2(x) ((uint32_t)(x) << 0U) #define DRVCTRL19_HSCK0(x) ((uint32_t)(x) << 28U) #define DRVCTRL19_HRX0(x) ((uint32_t)(x) << 24U) #define DRVCTRL19_HTX0(x) ((uint32_t)(x) << 20U) #define DRVCTRL19_HCTS0(x) ((uint32_t)(x) << 16U) #define DRVCTRL19_HRTS0(x) ((uint32_t)(x) << 12U) #define DRVCTRL19_MSIOF0_SCK(x) ((uint32_t)(x) << 8U) #define DRVCTRL19_MSIOF0_SYNC(x) ((uint32_t)(x) << 4U) #define DRVCTRL19_MSIOF0_SS1(x) ((uint32_t)(x) << 0U) #define DRVCTRL20_MSIOF0_TXD(x) ((uint32_t)(x) << 28U) #define DRVCTRL20_MSIOF0_SS2(x) ((uint32_t)(x) << 24U) #define DRVCTRL20_MSIOF0_RXD(x) ((uint32_t)(x) << 20U) #define DRVCTRL20_MLB_CLK(x) ((uint32_t)(x) << 16U) #define DRVCTRL20_MLB_SIG(x) ((uint32_t)(x) << 12U) #define DRVCTRL20_MLB_DAT(x) ((uint32_t)(x) << 8U) #define DRVCTRL20_MLB_REF(x) ((uint32_t)(x) << 4U) #define DRVCTRL20_SSI_SCK0129(x) ((uint32_t)(x) << 0U) #define DRVCTRL21_SSI_WS0129(x) ((uint32_t)(x) << 28U) #define DRVCTRL21_SSI_SDATA0(x) ((uint32_t)(x) << 24U) #define DRVCTRL21_SSI_SDATA1(x) ((uint32_t)(x) << 20U) #define DRVCTRL21_SSI_SDATA2(x) ((uint32_t)(x) << 16U) #define DRVCTRL21_SSI_SCK34(x) ((uint32_t)(x) << 12U) #define DRVCTRL21_SSI_WS34(x) ((uint32_t)(x) << 8U) #define DRVCTRL21_SSI_SDATA3(x) ((uint32_t)(x) << 4U) #define DRVCTRL21_SSI_SCK4(x) ((uint32_t)(x) << 0U) #define DRVCTRL22_SSI_WS4(x) ((uint32_t)(x) << 28U) #define DRVCTRL22_SSI_SDATA4(x) ((uint32_t)(x) << 24U) #define DRVCTRL22_SSI_SCK5(x) ((uint32_t)(x) << 20U) #define DRVCTRL22_SSI_WS5(x) ((uint32_t)(x) << 16U) #define DRVCTRL22_SSI_SDATA5(x) ((uint32_t)(x) << 12U) #define DRVCTRL22_SSI_SCK6(x) ((uint32_t)(x) << 8U) #define DRVCTRL22_SSI_WS6(x) ((uint32_t)(x) << 4U) #define DRVCTRL22_SSI_SDATA6(x) ((uint32_t)(x) << 0U) #define DRVCTRL23_SSI_SCK78(x) ((uint32_t)(x) << 28U) #define DRVCTRL23_SSI_WS78(x) ((uint32_t)(x) << 24U) #define DRVCTRL23_SSI_SDATA7(x) ((uint32_t)(x) << 20U) #define DRVCTRL23_SSI_SDATA8(x) ((uint32_t)(x) << 16U) #define DRVCTRL23_SSI_SDATA9(x) ((uint32_t)(x) << 12U) #define DRVCTRL23_AUDIO_CLKA(x) ((uint32_t)(x) << 8U) #define DRVCTRL23_AUDIO_CLKB(x) ((uint32_t)(x) << 4U) #define DRVCTRL23_USB0_PWEN(x) ((uint32_t)(x) << 0U) #define DRVCTRL24_USB0_OVC(x) ((uint32_t)(x) << 28U) #define DRVCTRL24_USB1_PWEN(x) ((uint32_t)(x) << 24U) #define DRVCTRL24_USB1_OVC(x) ((uint32_t)(x) << 20U) #define DRVCTRL24_USB30_PWEN(x) ((uint32_t)(x) << 16U) #define DRVCTRL24_USB30_OVC(x) ((uint32_t)(x) << 12U) #define DRVCTRL24_USB31_PWEN(x) ((uint32_t)(x) << 8U) #define DRVCTRL24_USB31_OVC(x) ((uint32_t)(x) << 4U) #define MOD_SEL0_MSIOF3_A ((uint32_t)0U << 29U) #define MOD_SEL0_MSIOF3_B ((uint32_t)1U << 29U) #define MOD_SEL0_MSIOF3_C ((uint32_t)2U << 29U) #define MOD_SEL0_MSIOF3_D ((uint32_t)3U << 29U) #define MOD_SEL0_MSIOF3_E ((uint32_t)4U << 29U) #define MOD_SEL0_MSIOF2_A ((uint32_t)0U << 27U) #define MOD_SEL0_MSIOF2_B ((uint32_t)1U << 27U) #define MOD_SEL0_MSIOF2_C ((uint32_t)2U << 27U) #define MOD_SEL0_MSIOF2_D ((uint32_t)3U << 27U) #define MOD_SEL0_MSIOF1_A ((uint32_t)0U << 24U) #define MOD_SEL0_MSIOF1_B ((uint32_t)1U << 24U) #define MOD_SEL0_MSIOF1_C ((uint32_t)2U << 24U) #define MOD_SEL0_MSIOF1_D ((uint32_t)3U << 24U) #define MOD_SEL0_MSIOF1_E ((uint32_t)4U << 24U) #define MOD_SEL0_MSIOF1_F ((uint32_t)5U << 24U) #define MOD_SEL0_MSIOF1_G ((uint32_t)6U << 24U) #define MOD_SEL0_LBSC_A ((uint32_t)0U << 23U) #define MOD_SEL0_LBSC_B ((uint32_t)1U << 23U) #define MOD_SEL0_IEBUS_A ((uint32_t)0U << 22U) #define MOD_SEL0_IEBUS_B ((uint32_t)1U << 22U) #define MOD_SEL0_I2C2_A ((uint32_t)0U << 21U) #define MOD_SEL0_I2C2_B ((uint32_t)1U << 21U) #define MOD_SEL0_I2C1_A ((uint32_t)0U << 20U) #define MOD_SEL0_I2C1_B ((uint32_t)1U << 20U) #define MOD_SEL0_HSCIF4_A ((uint32_t)0U << 19U) #define MOD_SEL0_HSCIF4_B ((uint32_t)1U << 19U) #define MOD_SEL0_HSCIF3_A ((uint32_t)0U << 17U) #define MOD_SEL0_HSCIF3_B ((uint32_t)1U << 17U) #define MOD_SEL0_HSCIF3_C ((uint32_t)2U << 17U) #define MOD_SEL0_HSCIF3_D ((uint32_t)3U << 17U) #define MOD_SEL0_HSCIF1_A ((uint32_t)0U << 16U) #define MOD_SEL0_HSCIF1_B ((uint32_t)1U << 16U) #define MOD_SEL0_FSO_A ((uint32_t)0U << 15U) #define MOD_SEL0_FSO_B ((uint32_t)1U << 15U) #define MOD_SEL0_HSCIF2_A ((uint32_t)0U << 13U) #define MOD_SEL0_HSCIF2_B ((uint32_t)1U << 13U) #define MOD_SEL0_HSCIF2_C ((uint32_t)2U << 13U) #define MOD_SEL0_ETHERAVB_A ((uint32_t)0U << 12U) #define MOD_SEL0_ETHERAVB_B ((uint32_t)1U << 12U) #define MOD_SEL0_DRIF3_A ((uint32_t)0U << 11U) #define MOD_SEL0_DRIF3_B ((uint32_t)1U << 11U) #define MOD_SEL0_DRIF2_A ((uint32_t)0U << 10U) #define MOD_SEL0_DRIF2_B ((uint32_t)1U << 10U) #define MOD_SEL0_DRIF1_A ((uint32_t)0U << 8U) #define MOD_SEL0_DRIF1_B ((uint32_t)1U << 8U) #define MOD_SEL0_DRIF1_C ((uint32_t)2U << 8U) #define MOD_SEL0_DRIF0_A ((uint32_t)0U << 6U) #define MOD_SEL0_DRIF0_B ((uint32_t)1U << 6U) #define MOD_SEL0_DRIF0_C ((uint32_t)2U << 6U) #define MOD_SEL0_CANFD0_A ((uint32_t)0U << 5U) #define MOD_SEL0_CANFD0_B ((uint32_t)1U << 5U) #define MOD_SEL0_ADG_A_A ((uint32_t)0U << 3U) #define MOD_SEL0_ADG_A_B ((uint32_t)1U << 3U) #define MOD_SEL0_ADG_A_C ((uint32_t)2U << 3U) #define MOD_SEL1_TSIF1_A ((uint32_t)0U << 30U) #define MOD_SEL1_TSIF1_B ((uint32_t)1U << 30U) #define MOD_SEL1_TSIF1_C ((uint32_t)2U << 30U) #define MOD_SEL1_TSIF1_D ((uint32_t)3U << 30U) #define MOD_SEL1_TSIF0_A ((uint32_t)0U << 27U) #define MOD_SEL1_TSIF0_B ((uint32_t)1U << 27U) #define MOD_SEL1_TSIF0_C ((uint32_t)2U << 27U) #define MOD_SEL1_TSIF0_D ((uint32_t)3U << 27U) #define MOD_SEL1_TSIF0_E ((uint32_t)4U << 27U) #define MOD_SEL1_TIMER_TMU_A ((uint32_t)0U << 26U) #define MOD_SEL1_TIMER_TMU_B ((uint32_t)1U << 26U) #define MOD_SEL1_SSP1_1_A ((uint32_t)0U << 24U) #define MOD_SEL1_SSP1_1_B ((uint32_t)1U << 24U) #define MOD_SEL1_SSP1_1_C ((uint32_t)2U << 24U) #define MOD_SEL1_SSP1_1_D ((uint32_t)3U << 24U) #define MOD_SEL1_SSP1_0_A ((uint32_t)0U << 21U) #define MOD_SEL1_SSP1_0_B ((uint32_t)1U << 21U) #define MOD_SEL1_SSP1_0_C ((uint32_t)2U << 21U) #define MOD_SEL1_SSP1_0_D ((uint32_t)3U << 21U) #define MOD_SEL1_SSP1_0_E ((uint32_t)4U << 21U) #define MOD_SEL1_SSI_A ((uint32_t)0U << 20U) #define MOD_SEL1_SSI_B ((uint32_t)1U << 20U) #define MOD_SEL1_SPEED_PULSE_IF_A ((uint32_t)0U << 19U) #define MOD_SEL1_SPEED_PULSE_IF_B ((uint32_t)1U << 19U) #define MOD_SEL1_SIMCARD_A ((uint32_t)0U << 17U) #define MOD_SEL1_SIMCARD_B ((uint32_t)1U << 17U) #define MOD_SEL1_SIMCARD_C ((uint32_t)2U << 17U) #define MOD_SEL1_SIMCARD_D ((uint32_t)3U << 17U) #define MOD_SEL1_SDHI2_A ((uint32_t)0U << 16U) #define MOD_SEL1_SDHI2_B ((uint32_t)1U << 16U) #define MOD_SEL1_SCIF4_A ((uint32_t)0U << 14U) #define MOD_SEL1_SCIF4_B ((uint32_t)1U << 14U) #define MOD_SEL1_SCIF4_C ((uint32_t)2U << 14U) #define MOD_SEL1_SCIF3_A ((uint32_t)0U << 13U) #define MOD_SEL1_SCIF3_B ((uint32_t)1U << 13U) #define MOD_SEL1_SCIF2_A ((uint32_t)0U << 12U) #define MOD_SEL1_SCIF2_B ((uint32_t)1U << 12U) #define MOD_SEL1_SCIF1_A ((uint32_t)0U << 11U) #define MOD_SEL1_SCIF1_B ((uint32_t)1U << 11U) #define MOD_SEL1_SCIF_A ((uint32_t)0U << 10U) #define MOD_SEL1_SCIF_B ((uint32_t)1U << 10U) #define MOD_SEL1_REMOCON_A ((uint32_t)0U << 9U) #define MOD_SEL1_REMOCON_B ((uint32_t)1U << 9U) #define MOD_SEL1_RCAN0_A ((uint32_t)0U << 6U) #define MOD_SEL1_RCAN0_B ((uint32_t)1U << 6U) #define MOD_SEL1_PWM6_A ((uint32_t)0U << 5U) #define MOD_SEL1_PWM6_B ((uint32_t)1U << 5U) #define MOD_SEL1_PWM5_A ((uint32_t)0U << 4U) #define MOD_SEL1_PWM5_B ((uint32_t)1U << 4U) #define MOD_SEL1_PWM4_A ((uint32_t)0U << 3U) #define MOD_SEL1_PWM4_B ((uint32_t)1U << 3U) #define MOD_SEL1_PWM3_A ((uint32_t)0U << 2U) #define MOD_SEL1_PWM3_B ((uint32_t)1U << 2U) #define MOD_SEL1_PWM2_A ((uint32_t)0U << 1U) #define MOD_SEL1_PWM2_B ((uint32_t)1U << 1U) #define MOD_SEL1_PWM1_A ((uint32_t)0U << 0U) #define MOD_SEL1_PWM1_B ((uint32_t)1U << 0U) #define MOD_SEL2_I2C_5_A ((uint32_t)0U << 31U) #define MOD_SEL2_I2C_5_B ((uint32_t)1U << 31U) #define MOD_SEL2_I2C_3_A ((uint32_t)0U << 30U) #define MOD_SEL2_I2C_3_B ((uint32_t)1U << 30U) #define MOD_SEL2_I2C_0_A ((uint32_t)0U << 29U) #define MOD_SEL2_I2C_0_B ((uint32_t)1U << 29U) #define MOD_SEL2_FM_A ((uint32_t)0U << 27U) #define MOD_SEL2_FM_B ((uint32_t)1U << 27U) #define MOD_SEL2_FM_C ((uint32_t)2U << 27U) #define MOD_SEL2_FM_D ((uint32_t)3U << 27U) #define MOD_SEL2_SCIF5_A ((uint32_t)0U << 26U) #define MOD_SEL2_SCIF5_B ((uint32_t)1U << 26U) #define MOD_SEL2_I2C6_A ((uint32_t)0U << 23U) #define MOD_SEL2_I2C6_B ((uint32_t)1U << 23U) #define MOD_SEL2_I2C6_C ((uint32_t)2U << 23U) #define MOD_SEL2_NDF_A ((uint32_t)0U << 22U) #define MOD_SEL2_NDF_B ((uint32_t)1U << 22U) #define MOD_SEL2_SSI2_A ((uint32_t)0U << 21U) #define MOD_SEL2_SSI2_B ((uint32_t)1U << 21U) #define MOD_SEL2_SSI9_A ((uint32_t)0U << 20U) #define MOD_SEL2_SSI9_B ((uint32_t)1U << 20U) #define MOD_SEL2_TIMER_TMU2_A ((uint32_t)0U << 19U) #define MOD_SEL2_TIMER_TMU2_B ((uint32_t)1U << 19U) #define MOD_SEL2_ADG_B_A ((uint32_t)0U << 18U) #define MOD_SEL2_ADG_B_B ((uint32_t)1U << 18U) #define MOD_SEL2_ADG_C_A ((uint32_t)0U << 17U) #define MOD_SEL2_ADG_C_B ((uint32_t)1U << 17U) #define MOD_SEL2_VIN4_A ((uint32_t)0U << 0U) #define MOD_SEL2_VIN4_B ((uint32_t)1U << 0U) static void pfc_reg_write(uint32_t addr, uint32_t data) { mmio_write_32(PFC_PMMR, ~data); mmio_write_32((uintptr_t)addr, data); } void pfc_init_h3_v2(void) { uint32_t reg; /* initialize module select */ pfc_reg_write(PFC_MOD_SEL0, MOD_SEL0_MSIOF3_A | MOD_SEL0_MSIOF2_A | MOD_SEL0_MSIOF1_A | MOD_SEL0_LBSC_A | MOD_SEL0_IEBUS_A | MOD_SEL0_I2C2_A | MOD_SEL0_I2C1_A | MOD_SEL0_HSCIF4_A | MOD_SEL0_HSCIF3_A | MOD_SEL0_HSCIF1_A | MOD_SEL0_FSO_A | MOD_SEL0_HSCIF2_A | MOD_SEL0_ETHERAVB_A | MOD_SEL0_DRIF3_A | MOD_SEL0_DRIF2_A | MOD_SEL0_DRIF1_A | MOD_SEL0_DRIF0_A | MOD_SEL0_CANFD0_A | MOD_SEL0_ADG_A_A); pfc_reg_write(PFC_MOD_SEL1, MOD_SEL1_TSIF1_A | MOD_SEL1_TSIF0_A | MOD_SEL1_TIMER_TMU_A | MOD_SEL1_SSP1_1_A | MOD_SEL1_SSP1_0_A | MOD_SEL1_SSI_A | MOD_SEL1_SPEED_PULSE_IF_A | MOD_SEL1_SIMCARD_A | MOD_SEL1_SDHI2_A | MOD_SEL1_SCIF4_A | MOD_SEL1_SCIF3_A | MOD_SEL1_SCIF2_A | MOD_SEL1_SCIF1_A | MOD_SEL1_SCIF_A | MOD_SEL1_REMOCON_A | MOD_SEL1_RCAN0_A | MOD_SEL1_PWM6_A | MOD_SEL1_PWM5_A | MOD_SEL1_PWM4_A | MOD_SEL1_PWM3_A | MOD_SEL1_PWM2_A | MOD_SEL1_PWM1_A); pfc_reg_write(PFC_MOD_SEL2, MOD_SEL2_I2C_5_A | MOD_SEL2_I2C_3_A | MOD_SEL2_I2C_0_A | MOD_SEL2_FM_A | MOD_SEL2_SCIF5_A | MOD_SEL2_I2C6_A | MOD_SEL2_NDF_A | MOD_SEL2_SSI2_A | MOD_SEL2_SSI9_A | MOD_SEL2_TIMER_TMU2_A | MOD_SEL2_ADG_B_A | MOD_SEL2_ADG_C_A | MOD_SEL2_VIN4_A); /* initialize peripheral function select */ pfc_reg_write(PFC_IPSR0, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR1, IPSR_28_FUNC(6) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(3) | IPSR_8_FUNC(3) | IPSR_4_FUNC(3) | IPSR_0_FUNC(3)); pfc_reg_write(PFC_IPSR2, IPSR_28_FUNC(0) | IPSR_24_FUNC(6) | IPSR_20_FUNC(6) | IPSR_16_FUNC(6) | IPSR_12_FUNC(6) | IPSR_8_FUNC(6) | IPSR_4_FUNC(6) | IPSR_0_FUNC(6)); pfc_reg_write(PFC_IPSR3, IPSR_28_FUNC(6) | IPSR_24_FUNC(6) | IPSR_20_FUNC(6) | IPSR_16_FUNC(6) | IPSR_12_FUNC(6) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR4, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(6) | IPSR_4_FUNC(6) | IPSR_0_FUNC(6)); pfc_reg_write(PFC_IPSR5, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(6) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR6, IPSR_28_FUNC(6) | IPSR_24_FUNC(6) | IPSR_20_FUNC(6) | IPSR_16_FUNC(6) | IPSR_12_FUNC(6) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR7, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_8_FUNC(6) | IPSR_4_FUNC(6) | IPSR_0_FUNC(6)); pfc_reg_write(PFC_IPSR8, IPSR_28_FUNC(1) | IPSR_24_FUNC(1) | IPSR_20_FUNC(1) | IPSR_16_FUNC(1) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR9, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR10, IPSR_28_FUNC(1) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR11, IPSR_28_FUNC(0) | IPSR_24_FUNC(4) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(1)); pfc_reg_write(PFC_IPSR12, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(4) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR13, IPSR_28_FUNC(8) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(3) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR14, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(3) | IPSR_0_FUNC(8)); pfc_reg_write(PFC_IPSR15, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR16, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR17, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(1) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR18, IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); /* initialize GPIO/perihperal function select */ pfc_reg_write(PFC_GPSR0, GPSR0_D15 | GPSR0_D14 | GPSR0_D13 | GPSR0_D12 | GPSR0_D11 | GPSR0_D10 | GPSR0_D9 | GPSR0_D8); pfc_reg_write(PFC_GPSR1, GPSR1_CLKOUT | GPSR1_EX_WAIT0_A | GPSR1_A19 | GPSR1_A18 | GPSR1_A17 | GPSR1_A16 | GPSR1_A15 | GPSR1_A14 | GPSR1_A13 | GPSR1_A12 | GPSR1_A7 | GPSR1_A6 | GPSR1_A5 | GPSR1_A4 | GPSR1_A3 | GPSR1_A2 | GPSR1_A1 | GPSR1_A0); pfc_reg_write(PFC_GPSR2, GPSR2_AVB_AVTP_CAPTURE_A | GPSR2_AVB_AVTP_MATCH_A | GPSR2_AVB_LINK | GPSR2_AVB_PHY_INT | GPSR2_AVB_MDC | GPSR2_PWM2_A | GPSR2_PWM1_A | GPSR2_IRQ5 | GPSR2_IRQ4 | GPSR2_IRQ3 | GPSR2_IRQ2 | GPSR2_IRQ1 | GPSR2_IRQ0); pfc_reg_write(PFC_GPSR3, GPSR3_SD0_WP | GPSR3_SD0_CD | GPSR3_SD1_DAT3 | GPSR3_SD1_DAT2 | GPSR3_SD1_DAT1 | GPSR3_SD1_DAT0 | GPSR3_SD0_DAT3 | GPSR3_SD0_DAT2 | GPSR3_SD0_DAT1 | GPSR3_SD0_DAT0 | GPSR3_SD0_CMD | GPSR3_SD0_CLK); pfc_reg_write(PFC_GPSR4, GPSR4_SD3_DAT7 | GPSR4_SD3_DAT6 | GPSR4_SD3_DAT3 | GPSR4_SD3_DAT2 | GPSR4_SD3_DAT1 | GPSR4_SD3_DAT0 | GPSR4_SD3_CMD | GPSR4_SD3_CLK | GPSR4_SD2_DS | GPSR4_SD2_DAT3 | GPSR4_SD2_DAT2 | GPSR4_SD2_DAT1 | GPSR4_SD2_DAT0 | GPSR4_SD2_CMD | GPSR4_SD2_CLK); pfc_reg_write(PFC_GPSR5, GPSR5_MSIOF0_SS2 | GPSR5_MSIOF0_SS1 | GPSR5_MSIOF0_SYNC | GPSR5_HRTS0 | GPSR5_HCTS0 | GPSR5_HTX0 | GPSR5_HRX0 | GPSR5_HSCK0 | GPSR5_RX2_A | GPSR5_TX2_A | GPSR5_SCK2 | GPSR5_RTS1 | GPSR5_CTS1 | GPSR5_TX1_A | GPSR5_RX1_A | GPSR5_RTS0 | GPSR5_SCK0); pfc_reg_write(PFC_GPSR6, GPSR6_USB30_OVC | GPSR6_USB30_PWEN | GPSR6_USB1_OVC | GPSR6_USB1_PWEN | GPSR6_USB0_OVC | GPSR6_USB0_PWEN | GPSR6_AUDIO_CLKB_B | GPSR6_AUDIO_CLKA_A | GPSR6_SSI_SDATA8 | GPSR6_SSI_SDATA7 | GPSR6_SSI_WS78 | GPSR6_SSI_SCK78 | GPSR6_SSI_WS6 | GPSR6_SSI_SCK6 | GPSR6_SSI_SDATA4 | GPSR6_SSI_WS4 | GPSR6_SSI_SCK4 | GPSR6_SSI_SDATA1_A | GPSR6_SSI_SDATA0 | GPSR6_SSI_WS0129 | GPSR6_SSI_SCK0129); pfc_reg_write(PFC_GPSR7, GPSR7_AVS2 | GPSR7_AVS1); /* initialize POC control register */ pfc_reg_write(PFC_POCCTRL0, POC_SD3_DS_33V | POC_SD3_DAT7_33V | POC_SD3_DAT6_33V | POC_SD3_DAT5_33V | POC_SD3_DAT4_33V | POC_SD3_DAT3_33V | POC_SD3_DAT2_33V | POC_SD3_DAT1_33V | POC_SD3_DAT0_33V | POC_SD3_CMD_33V | POC_SD3_CLK_33V | POC_SD0_DAT3_33V | POC_SD0_DAT2_33V | POC_SD0_DAT1_33V | POC_SD0_DAT0_33V | POC_SD0_CMD_33V | POC_SD0_CLK_33V); /* initialize DRV control register */ reg = mmio_read_32(PFC_DRVCTRL0); reg = ((reg & DRVCTRL0_MASK) | DRVCTRL0_QSPI0_SPCLK(3) | DRVCTRL0_QSPI0_MOSI_IO0(3) | DRVCTRL0_QSPI0_MISO_IO1(3) | DRVCTRL0_QSPI0_IO2(3) | DRVCTRL0_QSPI0_IO3(3) | DRVCTRL0_QSPI0_SSL(3) | DRVCTRL0_QSPI1_SPCLK(3) | DRVCTRL0_QSPI1_MOSI_IO0(3)); pfc_reg_write(PFC_DRVCTRL0, reg); reg = mmio_read_32(PFC_DRVCTRL1); reg = ((reg & DRVCTRL1_MASK) | DRVCTRL1_QSPI1_MISO_IO1(3) | DRVCTRL1_QSPI1_IO2(3) | DRVCTRL1_QSPI1_IO3(3) | DRVCTRL1_QSPI1_SS(3) | DRVCTRL1_RPC_INT(3) | DRVCTRL1_RPC_WP(3) | DRVCTRL1_RPC_RESET(3) | DRVCTRL1_AVB_RX_CTL(7)); pfc_reg_write(PFC_DRVCTRL1, reg); reg = mmio_read_32(PFC_DRVCTRL2); reg = ((reg & DRVCTRL2_MASK) | DRVCTRL2_AVB_RXC(7) | DRVCTRL2_AVB_RD0(7) | DRVCTRL2_AVB_RD1(7) | DRVCTRL2_AVB_RD2(7) | DRVCTRL2_AVB_RD3(7) | DRVCTRL2_AVB_TX_CTL(3) | DRVCTRL2_AVB_TXC(3) | DRVCTRL2_AVB_TD0(3)); pfc_reg_write(PFC_DRVCTRL2, reg); reg = mmio_read_32(PFC_DRVCTRL3); reg = ((reg & DRVCTRL3_MASK) | DRVCTRL3_AVB_TD1(3) | DRVCTRL3_AVB_TD2(3) | DRVCTRL3_AVB_TD3(3) | DRVCTRL3_AVB_TXCREFCLK(7) | DRVCTRL3_AVB_MDIO(7) | DRVCTRL3_AVB_MDC(7) | DRVCTRL3_AVB_MAGIC(7) | DRVCTRL3_AVB_PHY_INT(7)); pfc_reg_write(PFC_DRVCTRL3, reg); reg = mmio_read_32(PFC_DRVCTRL4); reg = ((reg & DRVCTRL4_MASK) | DRVCTRL4_AVB_LINK(7) | DRVCTRL4_AVB_AVTP_MATCH(7) | DRVCTRL4_AVB_AVTP_CAPTURE(7) | DRVCTRL4_IRQ0(7) | DRVCTRL4_IRQ1(7) | DRVCTRL4_IRQ2(7) | DRVCTRL4_IRQ3(7) | DRVCTRL4_IRQ4(7)); pfc_reg_write(PFC_DRVCTRL4, reg); reg = mmio_read_32(PFC_DRVCTRL5); reg = ((reg & DRVCTRL5_MASK) | DRVCTRL5_IRQ5(7) | DRVCTRL5_PWM0(7) | DRVCTRL5_PWM1(7) | DRVCTRL5_PWM2(7) | DRVCTRL5_A0(3) | DRVCTRL5_A1(3) | DRVCTRL5_A2(3) | DRVCTRL5_A3(3)); pfc_reg_write(PFC_DRVCTRL5, reg); reg = mmio_read_32(PFC_DRVCTRL6); reg = ((reg & DRVCTRL6_MASK) | DRVCTRL6_A4(3) | DRVCTRL6_A5(3) | DRVCTRL6_A6(3) | DRVCTRL6_A7(3) | DRVCTRL6_A8(7) | DRVCTRL6_A9(7) | DRVCTRL6_A10(7) | DRVCTRL6_A11(7)); pfc_reg_write(PFC_DRVCTRL6, reg); reg = mmio_read_32(PFC_DRVCTRL7); reg = ((reg & DRVCTRL7_MASK) | DRVCTRL7_A12(3) | DRVCTRL7_A13(3) | DRVCTRL7_A14(3) | DRVCTRL7_A15(3) | DRVCTRL7_A16(3) | DRVCTRL7_A17(3) | DRVCTRL7_A18(3) | DRVCTRL7_A19(3)); pfc_reg_write(PFC_DRVCTRL7, reg); reg = mmio_read_32(PFC_DRVCTRL8); reg = ((reg & DRVCTRL8_MASK) | DRVCTRL8_CLKOUT(7) | DRVCTRL8_CS0(7) | DRVCTRL8_CS1_A2(7) | DRVCTRL8_BS(7) | DRVCTRL8_RD(7) | DRVCTRL8_RD_W(7) | DRVCTRL8_WE0(7) | DRVCTRL8_WE1(7)); pfc_reg_write(PFC_DRVCTRL8, reg); reg = mmio_read_32(PFC_DRVCTRL9); reg = ((reg & DRVCTRL9_MASK) | DRVCTRL9_EX_WAIT0(7) | DRVCTRL9_PRESETOU(7) | DRVCTRL9_D0(7) | DRVCTRL9_D1(7) | DRVCTRL9_D2(7) | DRVCTRL9_D3(7) | DRVCTRL9_D4(7) | DRVCTRL9_D5(7)); pfc_reg_write(PFC_DRVCTRL9, reg); reg = mmio_read_32(PFC_DRVCTRL10); reg = ((reg & DRVCTRL10_MASK) | DRVCTRL10_D6(7) | DRVCTRL10_D7(7) | DRVCTRL10_D8(3) | DRVCTRL10_D9(3) | DRVCTRL10_D10(3) | DRVCTRL10_D11(3) | DRVCTRL10_D12(3) | DRVCTRL10_D13(3)); pfc_reg_write(PFC_DRVCTRL10, reg); reg = mmio_read_32(PFC_DRVCTRL11); reg = ((reg & DRVCTRL11_MASK) | DRVCTRL11_D14(3) | DRVCTRL11_D15(3) | DRVCTRL11_AVS1(7) | DRVCTRL11_AVS2(7) | DRVCTRL11_GP7_02(7) | DRVCTRL11_GP7_03(7) | DRVCTRL11_DU_DOTCLKIN0(3) | DRVCTRL11_DU_DOTCLKIN1(3)); pfc_reg_write(PFC_DRVCTRL11, reg); reg = mmio_read_32(PFC_DRVCTRL12); reg = ((reg & DRVCTRL12_MASK) | DRVCTRL12_DU_DOTCLKIN2(3) | DRVCTRL12_DU_DOTCLKIN3(3) | DRVCTRL12_DU_FSCLKST(3) | DRVCTRL12_DU_TMS(3)); pfc_reg_write(PFC_DRVCTRL12, reg); reg = mmio_read_32(PFC_DRVCTRL13); reg = ((reg & DRVCTRL13_MASK) | DRVCTRL13_TDO(3) | DRVCTRL13_ASEBRK(3) | DRVCTRL13_SD0_CLK(7) | DRVCTRL13_SD0_CMD(7) | DRVCTRL13_SD0_DAT0(7) | DRVCTRL13_SD0_DAT1(7) | DRVCTRL13_SD0_DAT2(7) | DRVCTRL13_SD0_DAT3(7)); pfc_reg_write(PFC_DRVCTRL13, reg); reg = mmio_read_32(PFC_DRVCTRL14); reg = ((reg & DRVCTRL14_MASK) | DRVCTRL14_SD1_CLK(7) | DRVCTRL14_SD1_CMD(7) | DRVCTRL14_SD1_DAT0(5) | DRVCTRL14_SD1_DAT1(5) | DRVCTRL14_SD1_DAT2(5) | DRVCTRL14_SD1_DAT3(5) | DRVCTRL14_SD2_CLK(5) | DRVCTRL14_SD2_CMD(5)); pfc_reg_write(PFC_DRVCTRL14, reg); reg = mmio_read_32(PFC_DRVCTRL15); reg = ((reg & DRVCTRL15_MASK) | DRVCTRL15_SD2_DAT0(5) | DRVCTRL15_SD2_DAT1(5) | DRVCTRL15_SD2_DAT2(5) | DRVCTRL15_SD2_DAT3(5) | DRVCTRL15_SD2_DS(5) | DRVCTRL15_SD3_CLK(7) | DRVCTRL15_SD3_CMD(7) | DRVCTRL15_SD3_DAT0(7)); pfc_reg_write(PFC_DRVCTRL15, reg); reg = mmio_read_32(PFC_DRVCTRL16); reg = ((reg & DRVCTRL16_MASK) | DRVCTRL16_SD3_DAT1(7) | DRVCTRL16_SD3_DAT2(7) | DRVCTRL16_SD3_DAT3(7) | DRVCTRL16_SD3_DAT4(7) | DRVCTRL16_SD3_DAT5(7) | DRVCTRL16_SD3_DAT6(7) | DRVCTRL16_SD3_DAT7(7) | DRVCTRL16_SD3_DS(7)); pfc_reg_write(PFC_DRVCTRL16, reg); reg = mmio_read_32(PFC_DRVCTRL17); reg = ((reg & DRVCTRL17_MASK) | DRVCTRL17_SD0_CD(7) | DRVCTRL17_SD0_WP(7) | DRVCTRL17_SD1_CD(7) | DRVCTRL17_SD1_WP(7) | DRVCTRL17_SCK0(7) | DRVCTRL17_RX0(7) | DRVCTRL17_TX0(7) | DRVCTRL17_CTS0(7)); pfc_reg_write(PFC_DRVCTRL17, reg); reg = mmio_read_32(PFC_DRVCTRL18); reg = ((reg & DRVCTRL18_MASK) | DRVCTRL18_RTS0_TANS(7) | DRVCTRL18_RX1(7) | DRVCTRL18_TX1(7) | DRVCTRL18_CTS1(7) | DRVCTRL18_RTS1_TANS(7) | DRVCTRL18_SCK2(7) | DRVCTRL18_TX2(7) | DRVCTRL18_RX2(7)); pfc_reg_write(PFC_DRVCTRL18, reg); reg = mmio_read_32(PFC_DRVCTRL19); reg = ((reg & DRVCTRL19_MASK) | DRVCTRL19_HSCK0(7) | DRVCTRL19_HRX0(7) | DRVCTRL19_HTX0(7) | DRVCTRL19_HCTS0(7) | DRVCTRL19_HRTS0(7) | DRVCTRL19_MSIOF0_SCK(7) | DRVCTRL19_MSIOF0_SYNC(7) | DRVCTRL19_MSIOF0_SS1(7)); pfc_reg_write(PFC_DRVCTRL19, reg); reg = mmio_read_32(PFC_DRVCTRL20); reg = ((reg & DRVCTRL20_MASK) | DRVCTRL20_MSIOF0_TXD(7) | DRVCTRL20_MSIOF0_SS2(7) | DRVCTRL20_MSIOF0_RXD(7) | DRVCTRL20_MLB_CLK(7) | DRVCTRL20_MLB_SIG(7) | DRVCTRL20_MLB_DAT(7) | DRVCTRL20_MLB_REF(7) | DRVCTRL20_SSI_SCK0129(7)); pfc_reg_write(PFC_DRVCTRL20, reg); reg = mmio_read_32(PFC_DRVCTRL21); reg = ((reg & DRVCTRL21_MASK) | DRVCTRL21_SSI_WS0129(7) | DRVCTRL21_SSI_SDATA0(7) | DRVCTRL21_SSI_SDATA1(7) | DRVCTRL21_SSI_SDATA2(7) | DRVCTRL21_SSI_SCK34(7) | DRVCTRL21_SSI_WS34(7) | DRVCTRL21_SSI_SDATA3(7) | DRVCTRL21_SSI_SCK4(7)); pfc_reg_write(PFC_DRVCTRL21, reg); reg = mmio_read_32(PFC_DRVCTRL22); reg = ((reg & DRVCTRL22_MASK) | DRVCTRL22_SSI_WS4(7) | DRVCTRL22_SSI_SDATA4(7) | DRVCTRL22_SSI_SCK5(7) | DRVCTRL22_SSI_WS5(7) | DRVCTRL22_SSI_SDATA5(7) | DRVCTRL22_SSI_SCK6(7) | DRVCTRL22_SSI_WS6(7) | DRVCTRL22_SSI_SDATA6(7)); pfc_reg_write(PFC_DRVCTRL22, reg); reg = mmio_read_32(PFC_DRVCTRL23); reg = ((reg & DRVCTRL23_MASK) | DRVCTRL23_SSI_SCK78(7) | DRVCTRL23_SSI_WS78(7) | DRVCTRL23_SSI_SDATA7(7) | DRVCTRL23_SSI_SDATA8(7) | DRVCTRL23_SSI_SDATA9(7) | DRVCTRL23_AUDIO_CLKA(7) | DRVCTRL23_AUDIO_CLKB(7) | DRVCTRL23_USB0_PWEN(7)); pfc_reg_write(PFC_DRVCTRL23, reg); reg = mmio_read_32(PFC_DRVCTRL24); reg = ((reg & DRVCTRL24_MASK) | DRVCTRL24_USB0_OVC(7) | DRVCTRL24_USB1_PWEN(7) | DRVCTRL24_USB1_OVC(7) | DRVCTRL24_USB30_PWEN(7) | DRVCTRL24_USB30_OVC(7) | DRVCTRL24_USB31_PWEN(7) | DRVCTRL24_USB31_OVC(7)); pfc_reg_write(PFC_DRVCTRL24, reg); /* initialize LSI pin pull-up/down control */ pfc_reg_write(PFC_PUD0, 0x00005FBFU); pfc_reg_write(PFC_PUD1, 0x00300FFEU); pfc_reg_write(PFC_PUD2, 0x330001E6U); pfc_reg_write(PFC_PUD3, 0x000002E0U); pfc_reg_write(PFC_PUD4, 0xFFFFFF00U); pfc_reg_write(PFC_PUD5, 0x7F5FFF87U); pfc_reg_write(PFC_PUD6, 0x00000055U); /* initialize LSI pin pull-enable register */ pfc_reg_write(PFC_PUEN0, 0x00000FFFU); pfc_reg_write(PFC_PUEN1, 0x00100234U); pfc_reg_write(PFC_PUEN2, 0x000004C4U); pfc_reg_write(PFC_PUEN3, 0x00000200U); pfc_reg_write(PFC_PUEN4, 0x3E000000U); pfc_reg_write(PFC_PUEN5, 0x1F000805U); pfc_reg_write(PFC_PUEN6, 0x00000006U); /* initialize positive/negative logic select */ mmio_write_32(GPIO_POSNEG0, 0x00000000U); mmio_write_32(GPIO_POSNEG1, 0x00000000U); mmio_write_32(GPIO_POSNEG2, 0x00000000U); mmio_write_32(GPIO_POSNEG3, 0x00000000U); mmio_write_32(GPIO_POSNEG4, 0x00000000U); mmio_write_32(GPIO_POSNEG5, 0x00000000U); mmio_write_32(GPIO_POSNEG6, 0x00000000U); mmio_write_32(GPIO_POSNEG7, 0x00000000U); /* initialize general IO/interrupt switching */ mmio_write_32(GPIO_IOINTSEL0, 0x00000000U); mmio_write_32(GPIO_IOINTSEL1, 0x00000000U); mmio_write_32(GPIO_IOINTSEL2, 0x00000000U); mmio_write_32(GPIO_IOINTSEL3, 0x00000000U); mmio_write_32(GPIO_IOINTSEL4, 0x00000000U); mmio_write_32(GPIO_IOINTSEL5, 0x00000000U); mmio_write_32(GPIO_IOINTSEL6, 0x00000000U); mmio_write_32(GPIO_IOINTSEL7, 0x00000000U); /* initialize general output register */ mmio_write_32(GPIO_OUTDT1, 0x00000000U); mmio_write_32(GPIO_OUTDT2, 0x00000400U); mmio_write_32(GPIO_OUTDT3, 0x0000C000U); mmio_write_32(GPIO_OUTDT5, 0x00000006U); mmio_write_32(GPIO_OUTDT6, 0x00003880U); /* initialize general input/output switching */ mmio_write_32(GPIO_INOUTSEL0, 0x00000000U); mmio_write_32(GPIO_INOUTSEL1, 0x01000A00U); mmio_write_32(GPIO_INOUTSEL2, 0x00000400U); mmio_write_32(GPIO_INOUTSEL3, 0x0000C000U); mmio_write_32(GPIO_INOUTSEL4, 0x00000000U); #if (RCAR_GEN3_ULCB == 1) mmio_write_32(GPIO_INOUTSEL5, 0x0000000EU); #else mmio_write_32(GPIO_INOUTSEL5, 0x0000020EU); #endif mmio_write_32(GPIO_INOUTSEL6, 0x00013880U); mmio_write_32(GPIO_INOUTSEL7, 0x00000000U); } trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.h000066400000000000000000000003631355360272700251470ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PFC_INIT_H3_V2_H #define PFC_INIT_H3_V2_H void pfc_init_h3_v2(void); #endif /* PFC_INIT_H3_V2_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/M3/000077500000000000000000000000001355360272700222055ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/M3/pfc_init_m3.c000066400000000000000000001331031355360272700245440ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* for uint32_t */ #include #include "pfc_init_m3.h" #include "rcar_def.h" #include "rcar_private.h" #include "../pfc_regs.h" #define GPSR0_D15 BIT(15) #define GPSR0_D14 BIT(14) #define GPSR0_D13 BIT(13) #define GPSR0_D12 BIT(12) #define GPSR0_D11 BIT(11) #define GPSR0_D10 BIT(10) #define GPSR0_D9 BIT(9) #define GPSR0_D8 BIT(8) #define GPSR0_D7 BIT(7) #define GPSR0_D6 BIT(6) #define GPSR0_D5 BIT(5) #define GPSR0_D4 BIT(4) #define GPSR0_D3 BIT(3) #define GPSR0_D2 BIT(2) #define GPSR0_D1 BIT(1) #define GPSR0_D0 BIT(0) #define GPSR1_CLKOUT BIT(28) #define GPSR1_EX_WAIT0_A BIT(27) #define GPSR1_WE1 BIT(26) #define GPSR1_WE0 BIT(25) #define GPSR1_RD_WR BIT(24) #define GPSR1_RD BIT(23) #define GPSR1_BS BIT(22) #define GPSR1_CS1_A26 BIT(21) #define GPSR1_CS0 BIT(20) #define GPSR1_A19 BIT(19) #define GPSR1_A18 BIT(18) #define GPSR1_A17 BIT(17) #define GPSR1_A16 BIT(16) #define GPSR1_A15 BIT(15) #define GPSR1_A14 BIT(14) #define GPSR1_A13 BIT(13) #define GPSR1_A12 BIT(12) #define GPSR1_A11 BIT(11) #define GPSR1_A10 BIT(10) #define GPSR1_A9 BIT(9) #define GPSR1_A8 BIT(8) #define GPSR1_A7 BIT(7) #define GPSR1_A6 BIT(6) #define GPSR1_A5 BIT(5) #define GPSR1_A4 BIT(4) #define GPSR1_A3 BIT(3) #define GPSR1_A2 BIT(2) #define GPSR1_A1 BIT(1) #define GPSR1_A0 BIT(0) #define GPSR2_AVB_AVTP_CAPTURE_A BIT(14) #define GPSR2_AVB_AVTP_MATCH_A BIT(13) #define GPSR2_AVB_LINK BIT(12) #define GPSR2_AVB_PHY_INT BIT(11) #define GPSR2_AVB_MAGIC BIT(10) #define GPSR2_AVB_MDC BIT(9) #define GPSR2_PWM2_A BIT(8) #define GPSR2_PWM1_A BIT(7) #define GPSR2_PWM0 BIT(6) #define GPSR2_IRQ5 BIT(5) #define GPSR2_IRQ4 BIT(4) #define GPSR2_IRQ3 BIT(3) #define GPSR2_IRQ2 BIT(2) #define GPSR2_IRQ1 BIT(1) #define GPSR2_IRQ0 BIT(0) #define GPSR3_SD1_WP BIT(15) #define GPSR3_SD1_CD BIT(14) #define GPSR3_SD0_WP BIT(13) #define GPSR3_SD0_CD BIT(12) #define GPSR3_SD1_DAT3 BIT(11) #define GPSR3_SD1_DAT2 BIT(10) #define GPSR3_SD1_DAT1 BIT(9) #define GPSR3_SD1_DAT0 BIT(8) #define GPSR3_SD1_CMD BIT(7) #define GPSR3_SD1_CLK BIT(6) #define GPSR3_SD0_DAT3 BIT(5) #define GPSR3_SD0_DAT2 BIT(4) #define GPSR3_SD0_DAT1 BIT(3) #define GPSR3_SD0_DAT0 BIT(2) #define GPSR3_SD0_CMD BIT(1) #define GPSR3_SD0_CLK BIT(0) #define GPSR4_SD3_DS BIT(17) #define GPSR4_SD3_DAT7 BIT(16) #define GPSR4_SD3_DAT6 BIT(15) #define GPSR4_SD3_DAT5 BIT(14) #define GPSR4_SD3_DAT4 BIT(13) #define GPSR4_SD3_DAT3 BIT(12) #define GPSR4_SD3_DAT2 BIT(11) #define GPSR4_SD3_DAT1 BIT(10) #define GPSR4_SD3_DAT0 BIT(9) #define GPSR4_SD3_CMD BIT(8) #define GPSR4_SD3_CLK BIT(7) #define GPSR4_SD2_DS BIT(6) #define GPSR4_SD2_DAT3 BIT(5) #define GPSR4_SD2_DAT2 BIT(4) #define GPSR4_SD2_DAT1 BIT(3) #define GPSR4_SD2_DAT0 BIT(2) #define GPSR4_SD2_CMD BIT(1) #define GPSR4_SD2_CLK BIT(0) #define GPSR5_MLB_DAT BIT(25) #define GPSR5_MLB_SIG BIT(24) #define GPSR5_MLB_CLK BIT(23) #define GPSR5_MSIOF0_RXD BIT(22) #define GPSR5_MSIOF0_SS2 BIT(21) #define GPSR5_MSIOF0_TXD BIT(20) #define GPSR5_MSIOF0_SS1 BIT(19) #define GPSR5_MSIOF0_SYNC BIT(18) #define GPSR5_MSIOF0_SCK BIT(17) #define GPSR5_HRTS0 BIT(16) #define GPSR5_HCTS0 BIT(15) #define GPSR5_HTX0 BIT(14) #define GPSR5_HRX0 BIT(13) #define GPSR5_HSCK0 BIT(12) #define GPSR5_RX2_A BIT(11) #define GPSR5_TX2_A BIT(10) #define GPSR5_SCK2 BIT(9) #define GPSR5_RTS1 BIT(8) #define GPSR5_CTS1 BIT(7) #define GPSR5_TX1_A BIT(6) #define GPSR5_RX1_A BIT(5) #define GPSR5_RTS0 BIT(4) #define GPSR5_CTS0 BIT(3) #define GPSR5_TX0 BIT(2) #define GPSR5_RX0 BIT(1) #define GPSR5_SCK0 BIT(0) #define GPSR6_USB31_OVC BIT(31) #define GPSR6_USB31_PWEN BIT(30) #define GPSR6_USB30_OVC BIT(29) #define GPSR6_USB30_PWEN BIT(28) #define GPSR6_USB1_OVC BIT(27) #define GPSR6_USB1_PWEN BIT(26) #define GPSR6_USB0_OVC BIT(25) #define GPSR6_USB0_PWEN BIT(24) #define GPSR6_AUDIO_CLKB_B BIT(23) #define GPSR6_AUDIO_CLKA_A BIT(22) #define GPSR6_SSI_SDATA9_A BIT(21) #define GPSR6_SSI_SDATA8 BIT(20) #define GPSR6_SSI_SDATA7 BIT(19) #define GPSR6_SSI_WS78 BIT(18) #define GPSR6_SSI_SCK78 BIT(17) #define GPSR6_SSI_SDATA6 BIT(16) #define GPSR6_SSI_WS6 BIT(15) #define GPSR6_SSI_SCK6 BIT(14) #define GPSR6_SSI_SDATA5 BIT(13) #define GPSR6_SSI_WS5 BIT(12) #define GPSR6_SSI_SCK5 BIT(11) #define GPSR6_SSI_SDATA4 BIT(10) #define GPSR6_SSI_WS4 BIT(9) #define GPSR6_SSI_SCK4 BIT(8) #define GPSR6_SSI_SDATA3 BIT(7) #define GPSR6_SSI_WS34 BIT(6) #define GPSR6_SSI_SCK34 BIT(5) #define GPSR6_SSI_SDATA2_A BIT(4) #define GPSR6_SSI_SDATA1_A BIT(3) #define GPSR6_SSI_SDATA0 BIT(2) #define GPSR6_SSI_WS0129 BIT(1) #define GPSR6_SSI_SCK0129 BIT(0) #define GPSR7_AVS2 BIT(1) #define GPSR7_AVS1 BIT(0) #define IPSR_28_FUNC(x) ((uint32_t)(x) << 28U) #define IPSR_24_FUNC(x) ((uint32_t)(x) << 24U) #define IPSR_20_FUNC(x) ((uint32_t)(x) << 20U) #define IPSR_16_FUNC(x) ((uint32_t)(x) << 16U) #define IPSR_12_FUNC(x) ((uint32_t)(x) << 12U) #define IPSR_8_FUNC(x) ((uint32_t)(x) << 8U) #define IPSR_4_FUNC(x) ((uint32_t)(x) << 4U) #define IPSR_0_FUNC(x) ((uint32_t)(x) << 0U) #define POC_SD3_DS_33V BIT(29) #define POC_SD3_DAT7_33V BIT(28) #define POC_SD3_DAT6_33V BIT(27) #define POC_SD3_DAT5_33V BIT(26) #define POC_SD3_DAT4_33V BIT(25) #define POC_SD3_DAT3_33V BIT(24) #define POC_SD3_DAT2_33V BIT(23) #define POC_SD3_DAT1_33V BIT(22) #define POC_SD3_DAT0_33V BIT(21) #define POC_SD3_CMD_33V BIT(20) #define POC_SD3_CLK_33V BIT(19) #define POC_SD2_DS_33V BIT(18) #define POC_SD2_DAT3_33V BIT(17) #define POC_SD2_DAT2_33V BIT(16) #define POC_SD2_DAT1_33V BIT(15) #define POC_SD2_DAT0_33V BIT(14) #define POC_SD2_CMD_33V BIT(13) #define POC_SD2_CLK_33V BIT(12) #define POC_SD1_DAT3_33V BIT(11) #define POC_SD1_DAT2_33V BIT(10) #define POC_SD1_DAT1_33V BIT(9) #define POC_SD1_DAT0_33V BIT(8) #define POC_SD1_CMD_33V BIT(7) #define POC_SD1_CLK_33V BIT(6) #define POC_SD0_DAT3_33V BIT(5) #define POC_SD0_DAT2_33V BIT(4) #define POC_SD0_DAT1_33V BIT(3) #define POC_SD0_DAT0_33V BIT(2) #define POC_SD0_CMD_33V BIT(1) #define POC_SD0_CLK_33V BIT(0) #define DRVCTRL0_MASK (0xCCCCCCCCU) #define DRVCTRL1_MASK (0xCCCCCCC8U) #define DRVCTRL2_MASK (0x88888888U) #define DRVCTRL3_MASK (0x88888888U) #define DRVCTRL4_MASK (0x88888888U) #define DRVCTRL5_MASK (0x88888888U) #define DRVCTRL6_MASK (0x88888888U) #define DRVCTRL7_MASK (0x88888888U) #define DRVCTRL8_MASK (0x88888888U) #define DRVCTRL9_MASK (0x88888888U) #define DRVCTRL10_MASK (0x88888888U) #define DRVCTRL11_MASK (0x888888CCU) #define DRVCTRL12_MASK (0xCCCFFFCFU) #define DRVCTRL13_MASK (0xCC888888U) #define DRVCTRL14_MASK (0x88888888U) #define DRVCTRL15_MASK (0x88888888U) #define DRVCTRL16_MASK (0x88888888U) #define DRVCTRL17_MASK (0x88888888U) #define DRVCTRL18_MASK (0x88888888U) #define DRVCTRL19_MASK (0x88888888U) #define DRVCTRL20_MASK (0x88888888U) #define DRVCTRL21_MASK (0x88888888U) #define DRVCTRL22_MASK (0x88888888U) #define DRVCTRL23_MASK (0x88888888U) #define DRVCTRL24_MASK (0x8888888FU) #define DRVCTRL0_QSPI0_SPCLK(x) ((uint32_t)(x) << 28U) #define DRVCTRL0_QSPI0_MOSI_IO0(x) ((uint32_t)(x) << 24U) #define DRVCTRL0_QSPI0_MISO_IO1(x) ((uint32_t)(x) << 20U) #define DRVCTRL0_QSPI0_IO2(x) ((uint32_t)(x) << 16U) #define DRVCTRL0_QSPI0_IO3(x) ((uint32_t)(x) << 12U) #define DRVCTRL0_QSPI0_SSL(x) ((uint32_t)(x) << 8U) #define DRVCTRL0_QSPI1_SPCLK(x) ((uint32_t)(x) << 4U) #define DRVCTRL0_QSPI1_MOSI_IO0(x) ((uint32_t)(x) << 0U) #define DRVCTRL1_QSPI1_MISO_IO1(x) ((uint32_t)(x) << 28U) #define DRVCTRL1_QSPI1_IO2(x) ((uint32_t)(x) << 24U) #define DRVCTRL1_QSPI1_IO3(x) ((uint32_t)(x) << 20U) #define DRVCTRL1_QSPI1_SS(x) ((uint32_t)(x) << 16U) #define DRVCTRL1_RPC_INT(x) ((uint32_t)(x) << 12U) #define DRVCTRL1_RPC_WP(x) ((uint32_t)(x) << 8U) #define DRVCTRL1_RPC_RESET(x) ((uint32_t)(x) << 4U) #define DRVCTRL1_AVB_RX_CTL(x) ((uint32_t)(x) << 0U) #define DRVCTRL2_AVB_RXC(x) ((uint32_t)(x) << 28U) #define DRVCTRL2_AVB_RD0(x) ((uint32_t)(x) << 24U) #define DRVCTRL2_AVB_RD1(x) ((uint32_t)(x) << 20U) #define DRVCTRL2_AVB_RD2(x) ((uint32_t)(x) << 16U) #define DRVCTRL2_AVB_RD3(x) ((uint32_t)(x) << 12U) #define DRVCTRL2_AVB_TX_CTL(x) ((uint32_t)(x) << 8U) #define DRVCTRL2_AVB_TXC(x) ((uint32_t)(x) << 4U) #define DRVCTRL2_AVB_TD0(x) ((uint32_t)(x) << 0U) #define DRVCTRL3_AVB_TD1(x) ((uint32_t)(x) << 28U) #define DRVCTRL3_AVB_TD2(x) ((uint32_t)(x) << 24U) #define DRVCTRL3_AVB_TD3(x) ((uint32_t)(x) << 20U) #define DRVCTRL3_AVB_TXCREFCLK(x) ((uint32_t)(x) << 16U) #define DRVCTRL3_AVB_MDIO(x) ((uint32_t)(x) << 12U) #define DRVCTRL3_AVB_MDC(x) ((uint32_t)(x) << 8U) #define DRVCTRL3_AVB_MAGIC(x) ((uint32_t)(x) << 4U) #define DRVCTRL3_AVB_PHY_INT(x) ((uint32_t)(x) << 0U) #define DRVCTRL4_AVB_LINK(x) ((uint32_t)(x) << 28U) #define DRVCTRL4_AVB_AVTP_MATCH(x) ((uint32_t)(x) << 24U) #define DRVCTRL4_AVB_AVTP_CAPTURE(x) ((uint32_t)(x) << 20U) #define DRVCTRL4_IRQ0(x) ((uint32_t)(x) << 16U) #define DRVCTRL4_IRQ1(x) ((uint32_t)(x) << 12U) #define DRVCTRL4_IRQ2(x) ((uint32_t)(x) << 8U) #define DRVCTRL4_IRQ3(x) ((uint32_t)(x) << 4U) #define DRVCTRL4_IRQ4(x) ((uint32_t)(x) << 0U) #define DRVCTRL5_IRQ5(x) ((uint32_t)(x) << 28U) #define DRVCTRL5_PWM0(x) ((uint32_t)(x) << 24U) #define DRVCTRL5_PWM1(x) ((uint32_t)(x) << 20U) #define DRVCTRL5_PWM2(x) ((uint32_t)(x) << 16U) #define DRVCTRL5_A0(x) ((uint32_t)(x) << 12U) #define DRVCTRL5_A1(x) ((uint32_t)(x) << 8U) #define DRVCTRL5_A2(x) ((uint32_t)(x) << 4U) #define DRVCTRL5_A3(x) ((uint32_t)(x) << 0U) #define DRVCTRL6_A4(x) ((uint32_t)(x) << 28U) #define DRVCTRL6_A5(x) ((uint32_t)(x) << 24U) #define DRVCTRL6_A6(x) ((uint32_t)(x) << 20U) #define DRVCTRL6_A7(x) ((uint32_t)(x) << 16U) #define DRVCTRL6_A8(x) ((uint32_t)(x) << 12U) #define DRVCTRL6_A9(x) ((uint32_t)(x) << 8U) #define DRVCTRL6_A10(x) ((uint32_t)(x) << 4U) #define DRVCTRL6_A11(x) ((uint32_t)(x) << 0U) #define DRVCTRL7_A12(x) ((uint32_t)(x) << 28U) #define DRVCTRL7_A13(x) ((uint32_t)(x) << 24U) #define DRVCTRL7_A14(x) ((uint32_t)(x) << 20U) #define DRVCTRL7_A15(x) ((uint32_t)(x) << 16U) #define DRVCTRL7_A16(x) ((uint32_t)(x) << 12U) #define DRVCTRL7_A17(x) ((uint32_t)(x) << 8U) #define DRVCTRL7_A18(x) ((uint32_t)(x) << 4U) #define DRVCTRL7_A19(x) ((uint32_t)(x) << 0U) #define DRVCTRL8_CLKOUT(x) ((uint32_t)(x) << 28U) #define DRVCTRL8_CS0(x) ((uint32_t)(x) << 24U) #define DRVCTRL8_CS1_A2(x) ((uint32_t)(x) << 20U) #define DRVCTRL8_BS(x) ((uint32_t)(x) << 16U) #define DRVCTRL8_RD(x) ((uint32_t)(x) << 12U) #define DRVCTRL8_RD_W(x) ((uint32_t)(x) << 8U) #define DRVCTRL8_WE0(x) ((uint32_t)(x) << 4U) #define DRVCTRL8_WE1(x) ((uint32_t)(x) << 0U) #define DRVCTRL9_EX_WAIT0(x) ((uint32_t)(x) << 28U) #define DRVCTRL9_PRESETOU(x) ((uint32_t)(x) << 24U) #define DRVCTRL9_D0(x) ((uint32_t)(x) << 20U) #define DRVCTRL9_D1(x) ((uint32_t)(x) << 16U) #define DRVCTRL9_D2(x) ((uint32_t)(x) << 12U) #define DRVCTRL9_D3(x) ((uint32_t)(x) << 8U) #define DRVCTRL9_D4(x) ((uint32_t)(x) << 4U) #define DRVCTRL9_D5(x) ((uint32_t)(x) << 0U) #define DRVCTRL10_D6(x) ((uint32_t)(x) << 28U) #define DRVCTRL10_D7(x) ((uint32_t)(x) << 24U) #define DRVCTRL10_D8(x) ((uint32_t)(x) << 20U) #define DRVCTRL10_D9(x) ((uint32_t)(x) << 16U) #define DRVCTRL10_D10(x) ((uint32_t)(x) << 12U) #define DRVCTRL10_D11(x) ((uint32_t)(x) << 8U) #define DRVCTRL10_D12(x) ((uint32_t)(x) << 4U) #define DRVCTRL10_D13(x) ((uint32_t)(x) << 0U) #define DRVCTRL11_D14(x) ((uint32_t)(x) << 28U) #define DRVCTRL11_D15(x) ((uint32_t)(x) << 24U) #define DRVCTRL11_AVS1(x) ((uint32_t)(x) << 20U) #define DRVCTRL11_AVS2(x) ((uint32_t)(x) << 16U) #define DRVCTRL11_GP7_02(x) ((uint32_t)(x) << 12U) #define DRVCTRL11_GP7_03(x) ((uint32_t)(x) << 8U) #define DRVCTRL11_DU_DOTCLKIN0(x) ((uint32_t)(x) << 4U) #define DRVCTRL11_DU_DOTCLKIN1(x) ((uint32_t)(x) << 0U) #define DRVCTRL12_DU_DOTCLKIN2(x) ((uint32_t)(x) << 28U) #define DRVCTRL12_DU_DOTCLKIN3(x) ((uint32_t)(x) << 24U) #define DRVCTRL12_DU_FSCLKST(x) ((uint32_t)(x) << 20U) #define DRVCTRL12_DU_TMS(x) ((uint32_t)(x) << 4U) #define DRVCTRL13_TDO(x) ((uint32_t)(x) << 28U) #define DRVCTRL13_ASEBRK(x) ((uint32_t)(x) << 24U) #define DRVCTRL13_SD0_CLK(x) ((uint32_t)(x) << 20U) #define DRVCTRL13_SD0_CMD(x) ((uint32_t)(x) << 16U) #define DRVCTRL13_SD0_DAT0(x) ((uint32_t)(x) << 12U) #define DRVCTRL13_SD0_DAT1(x) ((uint32_t)(x) << 8U) #define DRVCTRL13_SD0_DAT2(x) ((uint32_t)(x) << 4U) #define DRVCTRL13_SD0_DAT3(x) ((uint32_t)(x) << 0U) #define DRVCTRL14_SD1_CLK(x) ((uint32_t)(x) << 28U) #define DRVCTRL14_SD1_CMD(x) ((uint32_t)(x) << 24U) #define DRVCTRL14_SD1_DAT0(x) ((uint32_t)(x) << 20U) #define DRVCTRL14_SD1_DAT1(x) ((uint32_t)(x) << 16U) #define DRVCTRL14_SD1_DAT2(x) ((uint32_t)(x) << 12U) #define DRVCTRL14_SD1_DAT3(x) ((uint32_t)(x) << 8U) #define DRVCTRL14_SD2_CLK(x) ((uint32_t)(x) << 4U) #define DRVCTRL14_SD2_CMD(x) ((uint32_t)(x) << 0U) #define DRVCTRL15_SD2_DAT0(x) ((uint32_t)(x) << 28U) #define DRVCTRL15_SD2_DAT1(x) ((uint32_t)(x) << 24U) #define DRVCTRL15_SD2_DAT2(x) ((uint32_t)(x) << 20U) #define DRVCTRL15_SD2_DAT3(x) ((uint32_t)(x) << 16U) #define DRVCTRL15_SD2_DS(x) ((uint32_t)(x) << 12U) #define DRVCTRL15_SD3_CLK(x) ((uint32_t)(x) << 8U) #define DRVCTRL15_SD3_CMD(x) ((uint32_t)(x) << 4U) #define DRVCTRL15_SD3_DAT0(x) ((uint32_t)(x) << 0U) #define DRVCTRL16_SD3_DAT1(x) ((uint32_t)(x) << 28U) #define DRVCTRL16_SD3_DAT2(x) ((uint32_t)(x) << 24U) #define DRVCTRL16_SD3_DAT3(x) ((uint32_t)(x) << 20U) #define DRVCTRL16_SD3_DAT4(x) ((uint32_t)(x) << 16U) #define DRVCTRL16_SD3_DAT5(x) ((uint32_t)(x) << 12U) #define DRVCTRL16_SD3_DAT6(x) ((uint32_t)(x) << 8U) #define DRVCTRL16_SD3_DAT7(x) ((uint32_t)(x) << 4U) #define DRVCTRL16_SD3_DS(x) ((uint32_t)(x) << 0U) #define DRVCTRL17_SD0_CD(x) ((uint32_t)(x) << 28U) #define DRVCTRL17_SD0_WP(x) ((uint32_t)(x) << 24U) #define DRVCTRL17_SD1_CD(x) ((uint32_t)(x) << 20U) #define DRVCTRL17_SD1_WP(x) ((uint32_t)(x) << 16U) #define DRVCTRL17_SCK0(x) ((uint32_t)(x) << 12U) #define DRVCTRL17_RX0(x) ((uint32_t)(x) << 8U) #define DRVCTRL17_TX0(x) ((uint32_t)(x) << 4U) #define DRVCTRL17_CTS0(x) ((uint32_t)(x) << 0U) #define DRVCTRL18_RTS0_TANS(x) ((uint32_t)(x) << 28U) #define DRVCTRL18_RX1(x) ((uint32_t)(x) << 24U) #define DRVCTRL18_TX1(x) ((uint32_t)(x) << 20U) #define DRVCTRL18_CTS1(x) ((uint32_t)(x) << 16U) #define DRVCTRL18_RTS1_TANS(x) ((uint32_t)(x) << 12U) #define DRVCTRL18_SCK2(x) ((uint32_t)(x) << 8U) #define DRVCTRL18_TX2(x) ((uint32_t)(x) << 4U) #define DRVCTRL18_RX2(x) ((uint32_t)(x) << 0U) #define DRVCTRL19_HSCK0(x) ((uint32_t)(x) << 28U) #define DRVCTRL19_HRX0(x) ((uint32_t)(x) << 24U) #define DRVCTRL19_HTX0(x) ((uint32_t)(x) << 20U) #define DRVCTRL19_HCTS0(x) ((uint32_t)(x) << 16U) #define DRVCTRL19_HRTS0(x) ((uint32_t)(x) << 12U) #define DRVCTRL19_MSIOF0_SCK(x) ((uint32_t)(x) << 8U) #define DRVCTRL19_MSIOF0_SYNC(x) ((uint32_t)(x) << 4U) #define DRVCTRL19_MSIOF0_SS1(x) ((uint32_t)(x) << 0U) #define DRVCTRL20_MSIOF0_TXD(x) ((uint32_t)(x) << 28U) #define DRVCTRL20_MSIOF0_SS2(x) ((uint32_t)(x) << 24U) #define DRVCTRL20_MSIOF0_RXD(x) ((uint32_t)(x) << 20U) #define DRVCTRL20_MLB_CLK(x) ((uint32_t)(x) << 16U) #define DRVCTRL20_MLB_SIG(x) ((uint32_t)(x) << 12U) #define DRVCTRL20_MLB_DAT(x) ((uint32_t)(x) << 8U) #define DRVCTRL20_MLB_REF(x) ((uint32_t)(x) << 4U) #define DRVCTRL20_SSI_SCK0129(x) ((uint32_t)(x) << 0U) #define DRVCTRL21_SSI_WS0129(x) ((uint32_t)(x) << 28U) #define DRVCTRL21_SSI_SDATA0(x) ((uint32_t)(x) << 24U) #define DRVCTRL21_SSI_SDATA1(x) ((uint32_t)(x) << 20U) #define DRVCTRL21_SSI_SDATA2(x) ((uint32_t)(x) << 16U) #define DRVCTRL21_SSI_SCK34(x) ((uint32_t)(x) << 12U) #define DRVCTRL21_SSI_WS34(x) ((uint32_t)(x) << 8U) #define DRVCTRL21_SSI_SDATA3(x) ((uint32_t)(x) << 4U) #define DRVCTRL21_SSI_SCK4(x) ((uint32_t)(x) << 0U) #define DRVCTRL22_SSI_WS4(x) ((uint32_t)(x) << 28U) #define DRVCTRL22_SSI_SDATA4(x) ((uint32_t)(x) << 24U) #define DRVCTRL22_SSI_SCK5(x) ((uint32_t)(x) << 20U) #define DRVCTRL22_SSI_WS5(x) ((uint32_t)(x) << 16U) #define DRVCTRL22_SSI_SDATA5(x) ((uint32_t)(x) << 12U) #define DRVCTRL22_SSI_SCK6(x) ((uint32_t)(x) << 8U) #define DRVCTRL22_SSI_WS6(x) ((uint32_t)(x) << 4U) #define DRVCTRL22_SSI_SDATA6(x) ((uint32_t)(x) << 0U) #define DRVCTRL23_SSI_SCK78(x) ((uint32_t)(x) << 28U) #define DRVCTRL23_SSI_WS78(x) ((uint32_t)(x) << 24U) #define DRVCTRL23_SSI_SDATA7(x) ((uint32_t)(x) << 20U) #define DRVCTRL23_SSI_SDATA8(x) ((uint32_t)(x) << 16U) #define DRVCTRL23_SSI_SDATA9(x) ((uint32_t)(x) << 12U) #define DRVCTRL23_AUDIO_CLKA(x) ((uint32_t)(x) << 8U) #define DRVCTRL23_AUDIO_CLKB(x) ((uint32_t)(x) << 4U) #define DRVCTRL23_USB0_PWEN(x) ((uint32_t)(x) << 0U) #define DRVCTRL24_USB0_OVC(x) ((uint32_t)(x) << 28U) #define DRVCTRL24_USB1_PWEN(x) ((uint32_t)(x) << 24U) #define DRVCTRL24_USB1_OVC(x) ((uint32_t)(x) << 20U) #define DRVCTRL24_USB30_PWEN(x) ((uint32_t)(x) << 16U) #define DRVCTRL24_USB30_OVC(x) ((uint32_t)(x) << 12U) #define DRVCTRL24_USB31_PWEN(x) ((uint32_t)(x) << 8U) #define DRVCTRL24_USB31_OVC(x) ((uint32_t)(x) << 4U) #define MOD_SEL0_MSIOF3_A ((uint32_t)0U << 29U) #define MOD_SEL0_MSIOF3_B ((uint32_t)1U << 29U) #define MOD_SEL0_MSIOF3_C ((uint32_t)2U << 29U) #define MOD_SEL0_MSIOF3_D ((uint32_t)3U << 29U) #define MOD_SEL0_MSIOF3_E ((uint32_t)4U << 29U) #define MOD_SEL0_MSIOF2_A ((uint32_t)0U << 27U) #define MOD_SEL0_MSIOF2_B ((uint32_t)1U << 27U) #define MOD_SEL0_MSIOF2_C ((uint32_t)2U << 27U) #define MOD_SEL0_MSIOF2_D ((uint32_t)3U << 27U) #define MOD_SEL0_MSIOF1_A ((uint32_t)0U << 24U) #define MOD_SEL0_MSIOF1_B ((uint32_t)1U << 24U) #define MOD_SEL0_MSIOF1_C ((uint32_t)2U << 24U) #define MOD_SEL0_MSIOF1_D ((uint32_t)3U << 24U) #define MOD_SEL0_MSIOF1_E ((uint32_t)4U << 24U) #define MOD_SEL0_MSIOF1_F ((uint32_t)5U << 24U) #define MOD_SEL0_MSIOF1_G ((uint32_t)6U << 24U) #define MOD_SEL0_LBSC_A ((uint32_t)0U << 23U) #define MOD_SEL0_LBSC_B ((uint32_t)1U << 23U) #define MOD_SEL0_IEBUS_A ((uint32_t)0U << 22U) #define MOD_SEL0_IEBUS_B ((uint32_t)1U << 22U) #define MOD_SEL0_I2C2_A ((uint32_t)0U << 21U) #define MOD_SEL0_I2C2_B ((uint32_t)1U << 21U) #define MOD_SEL0_I2C1_A ((uint32_t)0U << 20U) #define MOD_SEL0_I2C1_B ((uint32_t)1U << 20U) #define MOD_SEL0_HSCIF4_A ((uint32_t)0U << 19U) #define MOD_SEL0_HSCIF4_B ((uint32_t)1U << 19U) #define MOD_SEL0_HSCIF3_A ((uint32_t)0U << 17U) #define MOD_SEL0_HSCIF3_B ((uint32_t)1U << 17U) #define MOD_SEL0_HSCIF3_C ((uint32_t)2U << 17U) #define MOD_SEL0_HSCIF3_D ((uint32_t)3U << 17U) #define MOD_SEL0_HSCIF1_A ((uint32_t)0U << 16U) #define MOD_SEL0_HSCIF1_B ((uint32_t)1U << 16U) #define MOD_SEL0_FSO_A ((uint32_t)0U << 15U) #define MOD_SEL0_FSO_B ((uint32_t)1U << 15U) #define MOD_SEL0_HSCIF2_A ((uint32_t)0U << 13U) #define MOD_SEL0_HSCIF2_B ((uint32_t)1U << 13U) #define MOD_SEL0_HSCIF2_C ((uint32_t)2U << 13U) #define MOD_SEL0_ETHERAVB_A ((uint32_t)0U << 12U) #define MOD_SEL0_ETHERAVB_B ((uint32_t)1U << 12U) #define MOD_SEL0_DRIF3_A ((uint32_t)0U << 11U) #define MOD_SEL0_DRIF3_B ((uint32_t)1U << 11U) #define MOD_SEL0_DRIF2_A ((uint32_t)0U << 10U) #define MOD_SEL0_DRIF2_B ((uint32_t)1U << 10U) #define MOD_SEL0_DRIF1_A ((uint32_t)0U << 8U) #define MOD_SEL0_DRIF1_B ((uint32_t)1U << 8U) #define MOD_SEL0_DRIF1_C ((uint32_t)2U << 8U) #define MOD_SEL0_DRIF0_A ((uint32_t)0U << 6U) #define MOD_SEL0_DRIF0_B ((uint32_t)1U << 6U) #define MOD_SEL0_DRIF0_C ((uint32_t)2U << 6U) #define MOD_SEL0_CANFD0_A ((uint32_t)0U << 5U) #define MOD_SEL0_CANFD0_B ((uint32_t)1U << 5U) #define MOD_SEL0_ADG_A_A ((uint32_t)0U << 3U) #define MOD_SEL0_ADG_A_B ((uint32_t)1U << 3U) #define MOD_SEL0_ADG_A_C ((uint32_t)2U << 3U) #define MOD_SEL1_TSIF1_A ((uint32_t)0U << 30U) #define MOD_SEL1_TSIF1_B ((uint32_t)1U << 30U) #define MOD_SEL1_TSIF1_C ((uint32_t)2U << 30U) #define MOD_SEL1_TSIF1_D ((uint32_t)3U << 30U) #define MOD_SEL1_TSIF0_A ((uint32_t)0U << 27U) #define MOD_SEL1_TSIF0_B ((uint32_t)1U << 27U) #define MOD_SEL1_TSIF0_C ((uint32_t)2U << 27U) #define MOD_SEL1_TSIF0_D ((uint32_t)3U << 27U) #define MOD_SEL1_TSIF0_E ((uint32_t)4U << 27U) #define MOD_SEL1_TIMER_TMU_A ((uint32_t)0U << 26U) #define MOD_SEL1_TIMER_TMU_B ((uint32_t)1U << 26U) #define MOD_SEL1_SSP1_1_A ((uint32_t)0U << 24U) #define MOD_SEL1_SSP1_1_B ((uint32_t)1U << 24U) #define MOD_SEL1_SSP1_1_C ((uint32_t)2U << 24U) #define MOD_SEL1_SSP1_1_D ((uint32_t)3U << 24U) #define MOD_SEL1_SSP1_0_A ((uint32_t)0U << 21U) #define MOD_SEL1_SSP1_0_B ((uint32_t)1U << 21U) #define MOD_SEL1_SSP1_0_C ((uint32_t)2U << 21U) #define MOD_SEL1_SSP1_0_D ((uint32_t)3U << 21U) #define MOD_SEL1_SSP1_0_E ((uint32_t)4U << 21U) #define MOD_SEL1_SSI_A ((uint32_t)0U << 20U) #define MOD_SEL1_SSI_B ((uint32_t)1U << 20U) #define MOD_SEL1_SPEED_PULSE_IF_A ((uint32_t)0U << 19U) #define MOD_SEL1_SPEED_PULSE_IF_B ((uint32_t)1U << 19U) #define MOD_SEL1_SIMCARD_A ((uint32_t)0U << 17U) #define MOD_SEL1_SIMCARD_B ((uint32_t)1U << 17U) #define MOD_SEL1_SIMCARD_C ((uint32_t)2U << 17U) #define MOD_SEL1_SIMCARD_D ((uint32_t)3U << 17U) #define MOD_SEL1_SDHI2_A ((uint32_t)0U << 16U) #define MOD_SEL1_SDHI2_B ((uint32_t)1U << 16U) #define MOD_SEL1_SCIF4_A ((uint32_t)0U << 14U) #define MOD_SEL1_SCIF4_B ((uint32_t)1U << 14U) #define MOD_SEL1_SCIF4_C ((uint32_t)2U << 14U) #define MOD_SEL1_SCIF3_A ((uint32_t)0U << 13U) #define MOD_SEL1_SCIF3_B ((uint32_t)1U << 13U) #define MOD_SEL1_SCIF2_A ((uint32_t)0U << 12U) #define MOD_SEL1_SCIF2_B ((uint32_t)1U << 12U) #define MOD_SEL1_SCIF1_A ((uint32_t)0U << 11U) #define MOD_SEL1_SCIF1_B ((uint32_t)1U << 11U) #define MOD_SEL1_SCIF_A ((uint32_t)0U << 10U) #define MOD_SEL1_SCIF_B ((uint32_t)1U << 10U) #define MOD_SEL1_REMOCON_A ((uint32_t)0U << 9U) #define MOD_SEL1_REMOCON_B ((uint32_t)1U << 9U) #define MOD_SEL1_RCAN0_A ((uint32_t)0U << 6U) #define MOD_SEL1_RCAN0_B ((uint32_t)1U << 6U) #define MOD_SEL1_PWM6_A ((uint32_t)0U << 5U) #define MOD_SEL1_PWM6_B ((uint32_t)1U << 5U) #define MOD_SEL1_PWM5_A ((uint32_t)0U << 4U) #define MOD_SEL1_PWM5_B ((uint32_t)1U << 4U) #define MOD_SEL1_PWM4_A ((uint32_t)0U << 3U) #define MOD_SEL1_PWM4_B ((uint32_t)1U << 3U) #define MOD_SEL1_PWM3_A ((uint32_t)0U << 2U) #define MOD_SEL1_PWM3_B ((uint32_t)1U << 2U) #define MOD_SEL1_PWM2_A ((uint32_t)0U << 1U) #define MOD_SEL1_PWM2_B ((uint32_t)1U << 1U) #define MOD_SEL1_PWM1_A ((uint32_t)0U << 0U) #define MOD_SEL1_PWM1_B ((uint32_t)1U << 0U) #define MOD_SEL2_I2C_5_A ((uint32_t)0U << 31U) #define MOD_SEL2_I2C_5_B ((uint32_t)1U << 31U) #define MOD_SEL2_I2C_3_A ((uint32_t)0U << 30U) #define MOD_SEL2_I2C_3_B ((uint32_t)1U << 30U) #define MOD_SEL2_I2C_0_A ((uint32_t)0U << 29U) #define MOD_SEL2_I2C_0_B ((uint32_t)1U << 29U) #define MOD_SEL2_FM_A ((uint32_t)0U << 27U) #define MOD_SEL2_FM_B ((uint32_t)1U << 27U) #define MOD_SEL2_FM_C ((uint32_t)2U << 27U) #define MOD_SEL2_FM_D ((uint32_t)3U << 27U) #define MOD_SEL2_SCIF5_A ((uint32_t)0U << 26U) #define MOD_SEL2_SCIF5_B ((uint32_t)1U << 26U) #define MOD_SEL2_I2C6_A ((uint32_t)0U << 23U) #define MOD_SEL2_I2C6_B ((uint32_t)1U << 23U) #define MOD_SEL2_I2C6_C ((uint32_t)2U << 23U) #define MOD_SEL2_NDF_A ((uint32_t)0U << 22U) #define MOD_SEL2_NDF_B ((uint32_t)1U << 22U) #define MOD_SEL2_SSI2_A ((uint32_t)0U << 21U) #define MOD_SEL2_SSI2_B ((uint32_t)1U << 21U) #define MOD_SEL2_SSI9_A ((uint32_t)0U << 20U) #define MOD_SEL2_SSI9_B ((uint32_t)1U << 20U) #define MOD_SEL2_TIMER_TMU2_A ((uint32_t)0U << 19U) #define MOD_SEL2_TIMER_TMU2_B ((uint32_t)1U << 19U) #define MOD_SEL2_ADG_B_A ((uint32_t)0U << 18U) #define MOD_SEL2_ADG_B_B ((uint32_t)1U << 18U) #define MOD_SEL2_ADG_C_A ((uint32_t)0U << 17U) #define MOD_SEL2_ADG_C_B ((uint32_t)1U << 17U) #define MOD_SEL2_VIN4_A ((uint32_t)0U << 0U) #define MOD_SEL2_VIN4_B ((uint32_t)1U << 0U) /* SCIF3 Registers for Dummy write */ #define SCIF3_BASE (0xE6C50000U) #define SCIF3_SCFCR (SCIF3_BASE + 0x0018U) #define SCIF3_SCFDR (SCIF3_BASE + 0x001CU) #define SCFCR_DATA (0x0000U) /* Realtime module stop control */ #define CPG_BASE (0xE6150000U) #define CPG_SCMSTPCR0 (CPG_BASE + 0x0B20U) #define CPG_MSTPSR0 (CPG_BASE + 0x0030U) #define SCMSTPCR0_RTDMAC (0x00200000U) /* RT-DMAC Registers */ #define RTDMAC_CH (0U) /* choose 0 to 15 */ #define RTDMAC_BASE (0xFFC10000U) #define RTDMAC_RDMOR (RTDMAC_BASE + 0x0060U) #define RTDMAC_RDMCHCLR (RTDMAC_BASE + 0x0080U) #define RTDMAC_RDMSAR(x) (RTDMAC_BASE + 0x8000U + (0x80U * (x))) #define RTDMAC_RDMDAR(x) (RTDMAC_BASE + 0x8004U + (0x80U * (x))) #define RTDMAC_RDMTCR(x) (RTDMAC_BASE + 0x8008U + (0x80U * (x))) #define RTDMAC_RDMCHCR(x) (RTDMAC_BASE + 0x800CU + (0x80U * (x))) #define RTDMAC_RDMCHCRB(x) (RTDMAC_BASE + 0x801CU + (0x80U * (x))) #define RTDMAC_RDMDPBASE(x) (RTDMAC_BASE + 0x8050U + (0x80U * (x))) #define RTDMAC_DESC_BASE (RTDMAC_BASE + 0xA000U) #define RTDMAC_DESC_RDMSAR (RTDMAC_DESC_BASE + 0x0000U) #define RTDMAC_DESC_RDMDAR (RTDMAC_DESC_BASE + 0x0004U) #define RTDMAC_DESC_RDMTCR (RTDMAC_DESC_BASE + 0x0008U) #define RDMOR_DME (0x0001U) /* DMA Master Enable */ #define RDMCHCR_DPM_INFINITE (0x30000000U) /* Infinite repeat mode */ #define RDMCHCR_RPT_TCR (0x02000000U) /* enable to update TCR */ #define RDMCHCR_TS_2 (0x00000008U) /* Word(2byte) units transfer */ #define RDMCHCR_RS_AUTO (0x00000400U) /* Auto request */ #define RDMCHCR_DE (0x00000001U) /* DMA Enable */ #define RDMCHCRB_DRST (0x00008000U) /* Descriptor reset */ #define RDMCHCRB_SLM_256 (0x00000080U) /* once in 256 clock cycle */ #define RDMDPBASE_SEL_EXT (0x00000001U) /* External memory use */ static void start_rtdma0_descriptor(void) { uint32_t reg; reg = mmio_read_32(RCAR_PRR); reg &= (PRR_PRODUCT_MASK | PRR_CUT_MASK); if (reg == (PRR_PRODUCT_M3_CUT10)) { /* Enable clock supply to RTDMAC. */ mstpcr_write(CPG_SCMSTPCR0, CPG_MSTPSR0, SCMSTPCR0_RTDMAC); /* Initialize ch0, Reset Descriptor */ mmio_write_32(RTDMAC_RDMCHCLR, BIT(RTDMAC_CH)); mmio_write_32(RTDMAC_RDMCHCRB(RTDMAC_CH), RDMCHCRB_DRST); /* Enable DMA */ mmio_write_16(RTDMAC_RDMOR, RDMOR_DME); /* Set first transfer */ mmio_write_32(RTDMAC_RDMSAR(RTDMAC_CH), RCAR_PRR); mmio_write_32(RTDMAC_RDMDAR(RTDMAC_CH), SCIF3_SCFDR); mmio_write_32(RTDMAC_RDMTCR(RTDMAC_CH), 0x00000001U); /* Set descriptor */ mmio_write_32(RTDMAC_DESC_RDMSAR, 0x00000000U); mmio_write_32(RTDMAC_DESC_RDMDAR, 0x00000000U); mmio_write_32(RTDMAC_DESC_RDMTCR, 0x00200000U); mmio_write_32(RTDMAC_RDMCHCRB(RTDMAC_CH), RDMCHCRB_SLM_256); mmio_write_32(RTDMAC_RDMDPBASE(RTDMAC_CH), RTDMAC_DESC_BASE | RDMDPBASE_SEL_EXT); /* Set transfer parameter, Start transfer */ mmio_write_32(RTDMAC_RDMCHCR(RTDMAC_CH), RDMCHCR_DPM_INFINITE | RDMCHCR_RPT_TCR | RDMCHCR_TS_2 | RDMCHCR_RS_AUTO | RDMCHCR_DE); } } static void pfc_reg_write(uint32_t addr, uint32_t data) { uint32_t prr; prr = mmio_read_32(RCAR_PRR); prr &= (PRR_PRODUCT_MASK | PRR_CUT_MASK); mmio_write_32(PFC_PMMR, ~data); if (prr == (PRR_PRODUCT_M3_CUT10)) { mmio_write_16(SCIF3_SCFCR, SCFCR_DATA); /* Dummy write */ } mmio_write_32((uintptr_t)addr, data); if (prr == (PRR_PRODUCT_M3_CUT10)) { mmio_write_16(SCIF3_SCFCR, SCFCR_DATA); /* Dummy write */ } } void pfc_init_m3(void) { uint32_t reg; /* Work around for PFC eratta */ start_rtdma0_descriptor(); /* initialize module select */ pfc_reg_write(PFC_MOD_SEL0, MOD_SEL0_MSIOF3_A | MOD_SEL0_MSIOF2_A | MOD_SEL0_MSIOF1_A | MOD_SEL0_LBSC_A | MOD_SEL0_IEBUS_A | MOD_SEL0_I2C2_A | MOD_SEL0_I2C1_A | MOD_SEL0_HSCIF4_A | MOD_SEL0_HSCIF3_A | MOD_SEL0_HSCIF1_A | MOD_SEL0_FSO_A | MOD_SEL0_HSCIF2_A | MOD_SEL0_ETHERAVB_A | MOD_SEL0_DRIF3_A | MOD_SEL0_DRIF2_A | MOD_SEL0_DRIF1_A | MOD_SEL0_DRIF0_A | MOD_SEL0_CANFD0_A | MOD_SEL0_ADG_A_A); pfc_reg_write(PFC_MOD_SEL1, MOD_SEL1_TSIF1_A | MOD_SEL1_TSIF0_A | MOD_SEL1_TIMER_TMU_A | MOD_SEL1_SSP1_1_A | MOD_SEL1_SSP1_0_A | MOD_SEL1_SSI_A | MOD_SEL1_SPEED_PULSE_IF_A | MOD_SEL1_SIMCARD_A | MOD_SEL1_SDHI2_A | MOD_SEL1_SCIF4_A | MOD_SEL1_SCIF3_A | MOD_SEL1_SCIF2_A | MOD_SEL1_SCIF1_A | MOD_SEL1_SCIF_A | MOD_SEL1_REMOCON_A | MOD_SEL1_RCAN0_A | MOD_SEL1_PWM6_A | MOD_SEL1_PWM5_A | MOD_SEL1_PWM4_A | MOD_SEL1_PWM3_A | MOD_SEL1_PWM2_A | MOD_SEL1_PWM1_A); pfc_reg_write(PFC_MOD_SEL2, MOD_SEL2_I2C_5_A | MOD_SEL2_I2C_3_A | MOD_SEL2_I2C_0_A | MOD_SEL2_FM_A | MOD_SEL2_SCIF5_A | MOD_SEL2_I2C6_A | MOD_SEL2_NDF_A | MOD_SEL2_SSI2_A | MOD_SEL2_SSI9_A | MOD_SEL2_TIMER_TMU2_A | MOD_SEL2_ADG_B_A | MOD_SEL2_ADG_C_A | MOD_SEL2_VIN4_A); /* initialize peripheral function select */ pfc_reg_write(PFC_IPSR0, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR1, IPSR_28_FUNC(6) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(3) | IPSR_8_FUNC(3) | IPSR_4_FUNC(3) | IPSR_0_FUNC(3)); pfc_reg_write(PFC_IPSR2, IPSR_28_FUNC(0) | IPSR_24_FUNC(6) | IPSR_20_FUNC(6) | IPSR_16_FUNC(6) | IPSR_12_FUNC(6) | IPSR_8_FUNC(6) | IPSR_4_FUNC(6) | IPSR_0_FUNC(6)); pfc_reg_write(PFC_IPSR3, IPSR_28_FUNC(6) | IPSR_24_FUNC(6) | IPSR_20_FUNC(6) | IPSR_16_FUNC(6) | IPSR_12_FUNC(6) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR4, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(6) | IPSR_4_FUNC(6) | IPSR_0_FUNC(6)); pfc_reg_write(PFC_IPSR5, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(6) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR6, IPSR_28_FUNC(6) | IPSR_24_FUNC(6) | IPSR_20_FUNC(6) | IPSR_16_FUNC(6) | IPSR_12_FUNC(6) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR7, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_8_FUNC(6) | IPSR_4_FUNC(6) | IPSR_0_FUNC(6)); pfc_reg_write(PFC_IPSR8, IPSR_28_FUNC(1) | IPSR_24_FUNC(1) | IPSR_20_FUNC(1) | IPSR_16_FUNC(1) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR9, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR10, IPSR_28_FUNC(1) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR11, IPSR_28_FUNC(0) | IPSR_24_FUNC(4) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(1)); pfc_reg_write(PFC_IPSR12, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(4) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR13, IPSR_28_FUNC(8) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(3) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR14, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(3) | IPSR_0_FUNC(8)); pfc_reg_write(PFC_IPSR15, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR16, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR17, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(1) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR18, IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); /* initialize GPIO/perihperal function select */ pfc_reg_write(PFC_GPSR0, GPSR0_D15 | GPSR0_D14 | GPSR0_D13 | GPSR0_D12 | GPSR0_D11 | GPSR0_D10 | GPSR0_D9 | GPSR0_D8); pfc_reg_write(PFC_GPSR1, GPSR1_CLKOUT | GPSR1_EX_WAIT0_A | GPSR1_A19 | GPSR1_A18 | GPSR1_A17 | GPSR1_A16 | GPSR1_A15 | GPSR1_A14 | GPSR1_A13 | GPSR1_A12 | GPSR1_A7 | GPSR1_A6 | GPSR1_A5 | GPSR1_A4 | GPSR1_A3 | GPSR1_A2 | GPSR1_A1 | GPSR1_A0); pfc_reg_write(PFC_GPSR2, GPSR2_AVB_AVTP_CAPTURE_A | GPSR2_AVB_AVTP_MATCH_A | GPSR2_AVB_LINK | GPSR2_AVB_PHY_INT | GPSR2_AVB_MDC | GPSR2_PWM2_A | GPSR2_PWM1_A | GPSR2_IRQ5 | GPSR2_IRQ4 | GPSR2_IRQ3 | GPSR2_IRQ2 | GPSR2_IRQ1 | GPSR2_IRQ0); pfc_reg_write(PFC_GPSR3, GPSR3_SD0_WP | GPSR3_SD0_CD | GPSR3_SD1_DAT3 | GPSR3_SD1_DAT2 | GPSR3_SD1_DAT1 | GPSR3_SD1_DAT0 | GPSR3_SD0_DAT3 | GPSR3_SD0_DAT2 | GPSR3_SD0_DAT1 | GPSR3_SD0_DAT0 | GPSR3_SD0_CMD | GPSR3_SD0_CLK); pfc_reg_write(PFC_GPSR4, GPSR4_SD3_DAT7 | GPSR4_SD3_DAT6 | GPSR4_SD3_DAT3 | GPSR4_SD3_DAT2 | GPSR4_SD3_DAT1 | GPSR4_SD3_DAT0 | GPSR4_SD3_CMD | GPSR4_SD3_CLK | GPSR4_SD2_DS | GPSR4_SD2_DAT3 | GPSR4_SD2_DAT2 | GPSR4_SD2_DAT1 | GPSR4_SD2_DAT0 | GPSR4_SD2_CMD | GPSR4_SD2_CLK); pfc_reg_write(PFC_GPSR5, GPSR5_MSIOF0_SS2 | GPSR5_MSIOF0_SS1 | GPSR5_MSIOF0_SYNC | GPSR5_HRTS0 | GPSR5_HCTS0 | GPSR5_HTX0 | GPSR5_HRX0 | GPSR5_HSCK0 | GPSR5_RX2_A | GPSR5_TX2_A | GPSR5_SCK2 | GPSR5_RTS1 | GPSR5_CTS1 | GPSR5_TX1_A | GPSR5_RX1_A | GPSR5_RTS0 | GPSR5_SCK0); pfc_reg_write(PFC_GPSR6, GPSR6_USB30_OVC | GPSR6_USB30_PWEN | GPSR6_USB1_OVC | GPSR6_USB1_PWEN | GPSR6_USB0_OVC | GPSR6_USB0_PWEN | GPSR6_AUDIO_CLKB_B | GPSR6_AUDIO_CLKA_A | GPSR6_SSI_SDATA8 | GPSR6_SSI_SDATA7 | GPSR6_SSI_WS78 | GPSR6_SSI_SCK78 | GPSR6_SSI_WS6 | GPSR6_SSI_SCK6 | GPSR6_SSI_SDATA4 | GPSR6_SSI_WS4 | GPSR6_SSI_SCK4 | GPSR6_SSI_SDATA1_A | GPSR6_SSI_SDATA0 | GPSR6_SSI_WS0129 | GPSR6_SSI_SCK0129); pfc_reg_write(PFC_GPSR7, GPSR7_AVS2 | GPSR7_AVS1); /* initialize POC control register */ pfc_reg_write(PFC_POCCTRL0, POC_SD3_DS_33V | POC_SD3_DAT7_33V | POC_SD3_DAT6_33V | POC_SD3_DAT5_33V | POC_SD3_DAT4_33V | POC_SD3_DAT3_33V | POC_SD3_DAT2_33V | POC_SD3_DAT1_33V | POC_SD3_DAT0_33V | POC_SD3_CMD_33V | POC_SD3_CLK_33V | POC_SD0_DAT3_33V | POC_SD0_DAT2_33V | POC_SD0_DAT1_33V | POC_SD0_DAT0_33V | POC_SD0_CMD_33V | POC_SD0_CLK_33V); /* initialize DRV control register */ reg = mmio_read_32(PFC_DRVCTRL0); reg = ((reg & DRVCTRL0_MASK) | DRVCTRL0_QSPI0_SPCLK(3) | DRVCTRL0_QSPI0_MOSI_IO0(3) | DRVCTRL0_QSPI0_MISO_IO1(3) | DRVCTRL0_QSPI0_IO2(3) | DRVCTRL0_QSPI0_IO3(3) | DRVCTRL0_QSPI0_SSL(3) | DRVCTRL0_QSPI1_SPCLK(3) | DRVCTRL0_QSPI1_MOSI_IO0(3)); pfc_reg_write(PFC_DRVCTRL0, reg); reg = mmio_read_32(PFC_DRVCTRL1); reg = ((reg & DRVCTRL1_MASK) | DRVCTRL1_QSPI1_MISO_IO1(3) | DRVCTRL1_QSPI1_IO2(3) | DRVCTRL1_QSPI1_IO3(3) | DRVCTRL1_QSPI1_SS(3) | DRVCTRL1_RPC_INT(3) | DRVCTRL1_RPC_WP(3) | DRVCTRL1_RPC_RESET(3) | DRVCTRL1_AVB_RX_CTL(7)); pfc_reg_write(PFC_DRVCTRL1, reg); reg = mmio_read_32(PFC_DRVCTRL2); reg = ((reg & DRVCTRL2_MASK) | DRVCTRL2_AVB_RXC(7) | DRVCTRL2_AVB_RD0(7) | DRVCTRL2_AVB_RD1(7) | DRVCTRL2_AVB_RD2(7) | DRVCTRL2_AVB_RD3(7) | DRVCTRL2_AVB_TX_CTL(3) | DRVCTRL2_AVB_TXC(3) | DRVCTRL2_AVB_TD0(3)); pfc_reg_write(PFC_DRVCTRL2, reg); reg = mmio_read_32(PFC_DRVCTRL3); reg = ((reg & DRVCTRL3_MASK) | DRVCTRL3_AVB_TD1(3) | DRVCTRL3_AVB_TD2(3) | DRVCTRL3_AVB_TD3(3) | DRVCTRL3_AVB_TXCREFCLK(7) | DRVCTRL3_AVB_MDIO(7) | DRVCTRL3_AVB_MDC(7) | DRVCTRL3_AVB_MAGIC(7) | DRVCTRL3_AVB_PHY_INT(7)); pfc_reg_write(PFC_DRVCTRL3, reg); reg = mmio_read_32(PFC_DRVCTRL4); reg = ((reg & DRVCTRL4_MASK) | DRVCTRL4_AVB_LINK(7) | DRVCTRL4_AVB_AVTP_MATCH(7) | DRVCTRL4_AVB_AVTP_CAPTURE(7) | DRVCTRL4_IRQ0(7) | DRVCTRL4_IRQ1(7) | DRVCTRL4_IRQ2(7) | DRVCTRL4_IRQ3(7) | DRVCTRL4_IRQ4(7)); pfc_reg_write(PFC_DRVCTRL4, reg); reg = mmio_read_32(PFC_DRVCTRL5); reg = ((reg & DRVCTRL5_MASK) | DRVCTRL5_IRQ5(7) | DRVCTRL5_PWM0(7) | DRVCTRL5_PWM1(7) | DRVCTRL5_PWM2(7) | DRVCTRL5_A0(3) | DRVCTRL5_A1(3) | DRVCTRL5_A2(3) | DRVCTRL5_A3(3)); pfc_reg_write(PFC_DRVCTRL5, reg); reg = mmio_read_32(PFC_DRVCTRL6); reg = ((reg & DRVCTRL6_MASK) | DRVCTRL6_A4(3) | DRVCTRL6_A5(3) | DRVCTRL6_A6(3) | DRVCTRL6_A7(3) | DRVCTRL6_A8(7) | DRVCTRL6_A9(7) | DRVCTRL6_A10(7) | DRVCTRL6_A11(7)); pfc_reg_write(PFC_DRVCTRL6, reg); reg = mmio_read_32(PFC_DRVCTRL7); reg = ((reg & DRVCTRL7_MASK) | DRVCTRL7_A12(3) | DRVCTRL7_A13(3) | DRVCTRL7_A14(3) | DRVCTRL7_A15(3) | DRVCTRL7_A16(3) | DRVCTRL7_A17(3) | DRVCTRL7_A18(3) | DRVCTRL7_A19(3)); pfc_reg_write(PFC_DRVCTRL7, reg); reg = mmio_read_32(PFC_DRVCTRL8); reg = ((reg & DRVCTRL8_MASK) | DRVCTRL8_CLKOUT(7) | DRVCTRL8_CS0(7) | DRVCTRL8_CS1_A2(7) | DRVCTRL8_BS(7) | DRVCTRL8_RD(7) | DRVCTRL8_RD_W(7) | DRVCTRL8_WE0(7) | DRVCTRL8_WE1(7)); pfc_reg_write(PFC_DRVCTRL8, reg); reg = mmio_read_32(PFC_DRVCTRL9); reg = ((reg & DRVCTRL9_MASK) | DRVCTRL9_EX_WAIT0(7) | DRVCTRL9_PRESETOU(7) | DRVCTRL9_D0(7) | DRVCTRL9_D1(7) | DRVCTRL9_D2(7) | DRVCTRL9_D3(7) | DRVCTRL9_D4(7) | DRVCTRL9_D5(7)); pfc_reg_write(PFC_DRVCTRL9, reg); reg = mmio_read_32(PFC_DRVCTRL10); reg = ((reg & DRVCTRL10_MASK) | DRVCTRL10_D6(7) | DRVCTRL10_D7(7) | DRVCTRL10_D8(3) | DRVCTRL10_D9(3) | DRVCTRL10_D10(3) | DRVCTRL10_D11(3) | DRVCTRL10_D12(3) | DRVCTRL10_D13(3)); pfc_reg_write(PFC_DRVCTRL10, reg); reg = mmio_read_32(PFC_DRVCTRL11); reg = ((reg & DRVCTRL11_MASK) | DRVCTRL11_D14(3) | DRVCTRL11_D15(3) | DRVCTRL11_AVS1(7) | DRVCTRL11_AVS2(7) | DRVCTRL11_GP7_02(7) | DRVCTRL11_GP7_03(7) | DRVCTRL11_DU_DOTCLKIN0(3) | DRVCTRL11_DU_DOTCLKIN1(3)); pfc_reg_write(PFC_DRVCTRL11, reg); reg = mmio_read_32(PFC_DRVCTRL12); reg = ((reg & DRVCTRL12_MASK) | DRVCTRL12_DU_DOTCLKIN2(3) | DRVCTRL12_DU_DOTCLKIN3(3) | DRVCTRL12_DU_FSCLKST(3) | DRVCTRL12_DU_TMS(3)); pfc_reg_write(PFC_DRVCTRL12, reg); reg = mmio_read_32(PFC_DRVCTRL13); reg = ((reg & DRVCTRL13_MASK) | DRVCTRL13_TDO(3) | DRVCTRL13_ASEBRK(3) | DRVCTRL13_SD0_CLK(7) | DRVCTRL13_SD0_CMD(7) | DRVCTRL13_SD0_DAT0(7) | DRVCTRL13_SD0_DAT1(7) | DRVCTRL13_SD0_DAT2(7) | DRVCTRL13_SD0_DAT3(7)); pfc_reg_write(PFC_DRVCTRL13, reg); reg = mmio_read_32(PFC_DRVCTRL14); reg = ((reg & DRVCTRL14_MASK) | DRVCTRL14_SD1_CLK(7) | DRVCTRL14_SD1_CMD(7) | DRVCTRL14_SD1_DAT0(5) | DRVCTRL14_SD1_DAT1(5) | DRVCTRL14_SD1_DAT2(5) | DRVCTRL14_SD1_DAT3(5) | DRVCTRL14_SD2_CLK(5) | DRVCTRL14_SD2_CMD(5)); pfc_reg_write(PFC_DRVCTRL14, reg); reg = mmio_read_32(PFC_DRVCTRL15); reg = ((reg & DRVCTRL15_MASK) | DRVCTRL15_SD2_DAT0(5) | DRVCTRL15_SD2_DAT1(5) | DRVCTRL15_SD2_DAT2(5) | DRVCTRL15_SD2_DAT3(5) | DRVCTRL15_SD2_DS(5) | DRVCTRL15_SD3_CLK(7) | DRVCTRL15_SD3_CMD(7) | DRVCTRL15_SD3_DAT0(7)); pfc_reg_write(PFC_DRVCTRL15, reg); reg = mmio_read_32(PFC_DRVCTRL16); reg = ((reg & DRVCTRL16_MASK) | DRVCTRL16_SD3_DAT1(7) | DRVCTRL16_SD3_DAT2(7) | DRVCTRL16_SD3_DAT3(7) | DRVCTRL16_SD3_DAT4(7) | DRVCTRL16_SD3_DAT5(7) | DRVCTRL16_SD3_DAT6(7) | DRVCTRL16_SD3_DAT7(7) | DRVCTRL16_SD3_DS(7)); pfc_reg_write(PFC_DRVCTRL16, reg); reg = mmio_read_32(PFC_DRVCTRL17); reg = ((reg & DRVCTRL17_MASK) | DRVCTRL17_SD0_CD(7) | DRVCTRL17_SD0_WP(7) | DRVCTRL17_SD1_CD(7) | DRVCTRL17_SD1_WP(7) | DRVCTRL17_SCK0(7) | DRVCTRL17_RX0(7) | DRVCTRL17_TX0(7) | DRVCTRL17_CTS0(7)); pfc_reg_write(PFC_DRVCTRL17, reg); reg = mmio_read_32(PFC_DRVCTRL18); reg = ((reg & DRVCTRL18_MASK) | DRVCTRL18_RTS0_TANS(7) | DRVCTRL18_RX1(7) | DRVCTRL18_TX1(7) | DRVCTRL18_CTS1(7) | DRVCTRL18_RTS1_TANS(7) | DRVCTRL18_SCK2(7) | DRVCTRL18_TX2(7) | DRVCTRL18_RX2(7)); pfc_reg_write(PFC_DRVCTRL18, reg); reg = mmio_read_32(PFC_DRVCTRL19); reg = ((reg & DRVCTRL19_MASK) | DRVCTRL19_HSCK0(7) | DRVCTRL19_HRX0(7) | DRVCTRL19_HTX0(7) | DRVCTRL19_HCTS0(7) | DRVCTRL19_HRTS0(7) | DRVCTRL19_MSIOF0_SCK(7) | DRVCTRL19_MSIOF0_SYNC(7) | DRVCTRL19_MSIOF0_SS1(7)); pfc_reg_write(PFC_DRVCTRL19, reg); reg = mmio_read_32(PFC_DRVCTRL20); reg = ((reg & DRVCTRL20_MASK) | DRVCTRL20_MSIOF0_TXD(7) | DRVCTRL20_MSIOF0_SS2(7) | DRVCTRL20_MSIOF0_RXD(7) | DRVCTRL20_MLB_CLK(7) | DRVCTRL20_MLB_SIG(7) | DRVCTRL20_MLB_DAT(7) | DRVCTRL20_MLB_REF(7) | DRVCTRL20_SSI_SCK0129(7)); pfc_reg_write(PFC_DRVCTRL20, reg); reg = mmio_read_32(PFC_DRVCTRL21); reg = ((reg & DRVCTRL21_MASK) | DRVCTRL21_SSI_WS0129(7) | DRVCTRL21_SSI_SDATA0(7) | DRVCTRL21_SSI_SDATA1(7) | DRVCTRL21_SSI_SDATA2(7) | DRVCTRL21_SSI_SCK34(7) | DRVCTRL21_SSI_WS34(7) | DRVCTRL21_SSI_SDATA3(7) | DRVCTRL21_SSI_SCK4(7)); pfc_reg_write(PFC_DRVCTRL21, reg); reg = mmio_read_32(PFC_DRVCTRL22); reg = ((reg & DRVCTRL22_MASK) | DRVCTRL22_SSI_WS4(7) | DRVCTRL22_SSI_SDATA4(7) | DRVCTRL22_SSI_SCK5(7) | DRVCTRL22_SSI_WS5(7) | DRVCTRL22_SSI_SDATA5(7) | DRVCTRL22_SSI_SCK6(7) | DRVCTRL22_SSI_WS6(7) | DRVCTRL22_SSI_SDATA6(7)); pfc_reg_write(PFC_DRVCTRL22, reg); reg = mmio_read_32(PFC_DRVCTRL23); reg = ((reg & DRVCTRL23_MASK) | DRVCTRL23_SSI_SCK78(7) | DRVCTRL23_SSI_WS78(7) | DRVCTRL23_SSI_SDATA7(7) | DRVCTRL23_SSI_SDATA8(7) | DRVCTRL23_SSI_SDATA9(7) | DRVCTRL23_AUDIO_CLKA(7) | DRVCTRL23_AUDIO_CLKB(7) | DRVCTRL23_USB0_PWEN(7)); pfc_reg_write(PFC_DRVCTRL23, reg); reg = mmio_read_32(PFC_DRVCTRL24); reg = ((reg & DRVCTRL24_MASK) | DRVCTRL24_USB0_OVC(7) | DRVCTRL24_USB1_PWEN(7) | DRVCTRL24_USB1_OVC(7) | DRVCTRL24_USB30_PWEN(7) | DRVCTRL24_USB30_OVC(7) | DRVCTRL24_USB31_PWEN(7) | DRVCTRL24_USB31_OVC(7)); pfc_reg_write(PFC_DRVCTRL24, reg); /* initialize LSI pin pull-up/down control */ pfc_reg_write(PFC_PUD0, 0x00005FBFU); pfc_reg_write(PFC_PUD1, 0x00300FFEU); pfc_reg_write(PFC_PUD2, 0x330001E6U); pfc_reg_write(PFC_PUD3, 0x000002E0U); pfc_reg_write(PFC_PUD4, 0xFFFFFF00U); pfc_reg_write(PFC_PUD5, 0x7F5FFF87U); pfc_reg_write(PFC_PUD6, 0x00000055U); /* initialize LSI pin pull-enable register */ pfc_reg_write(PFC_PUEN0, 0x00000FFFU); pfc_reg_write(PFC_PUEN1, 0x00100234U); pfc_reg_write(PFC_PUEN2, 0x000004C4U); pfc_reg_write(PFC_PUEN3, 0x00000200U); pfc_reg_write(PFC_PUEN4, 0x3E000000U); pfc_reg_write(PFC_PUEN5, 0x1F000805U); pfc_reg_write(PFC_PUEN6, 0x00000006U); /* initialize positive/negative logic select */ mmio_write_32(GPIO_POSNEG0, 0x00000000U); mmio_write_32(GPIO_POSNEG1, 0x00000000U); mmio_write_32(GPIO_POSNEG2, 0x00000000U); mmio_write_32(GPIO_POSNEG3, 0x00000000U); mmio_write_32(GPIO_POSNEG4, 0x00000000U); mmio_write_32(GPIO_POSNEG5, 0x00000000U); mmio_write_32(GPIO_POSNEG6, 0x00000000U); mmio_write_32(GPIO_POSNEG7, 0x00000000U); /* initialize general IO/interrupt switching */ mmio_write_32(GPIO_IOINTSEL0, 0x00000000U); mmio_write_32(GPIO_IOINTSEL1, 0x00000000U); mmio_write_32(GPIO_IOINTSEL2, 0x00000000U); mmio_write_32(GPIO_IOINTSEL3, 0x00000000U); mmio_write_32(GPIO_IOINTSEL4, 0x00000000U); mmio_write_32(GPIO_IOINTSEL5, 0x00000000U); mmio_write_32(GPIO_IOINTSEL6, 0x00000000U); mmio_write_32(GPIO_IOINTSEL7, 0x00000000U); /* initialize general output register */ mmio_write_32(GPIO_OUTDT1, 0x00000000U); mmio_write_32(GPIO_OUTDT2, 0x00000400U); mmio_write_32(GPIO_OUTDT3, 0x0000C000U); mmio_write_32(GPIO_OUTDT5, 0x00000006U); mmio_write_32(GPIO_OUTDT6, 0x00003880U); /* initialize general input/output switching */ mmio_write_32(GPIO_INOUTSEL0, 0x00000000U); mmio_write_32(GPIO_INOUTSEL1, 0x01000A00U); mmio_write_32(GPIO_INOUTSEL2, 0x00000400U); mmio_write_32(GPIO_INOUTSEL3, 0x0000C000U); mmio_write_32(GPIO_INOUTSEL4, 0x00000000U); #if (RCAR_GEN3_ULCB == 1) mmio_write_32(GPIO_INOUTSEL5, 0x0000000EU); #else mmio_write_32(GPIO_INOUTSEL5, 0x0000020EU); #endif mmio_write_32(GPIO_INOUTSEL6, 0x00013880U); mmio_write_32(GPIO_INOUTSEL7, 0x00000000U); } trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/M3/pfc_init_m3.h000066400000000000000000000003471355360272700245540ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PFC_INIT_M3_H #define PFC_INIT_M3_H void pfc_init_m3(void); #endif /* PFC_INIT_M3_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/M3N/000077500000000000000000000000001355360272700223235ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.c000066400000000000000000001244301355360272700250430ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* for uint32_t */ #include #include "pfc_init_m3n.h" #include "rcar_def.h" #include "../pfc_regs.h" #define GPSR0_D15 BIT(15) #define GPSR0_D14 BIT(14) #define GPSR0_D13 BIT(13) #define GPSR0_D12 BIT(12) #define GPSR0_D11 BIT(11) #define GPSR0_D10 BIT(10) #define GPSR0_D9 BIT(9) #define GPSR0_D8 BIT(8) #define GPSR0_D7 BIT(7) #define GPSR0_D6 BIT(6) #define GPSR0_D5 BIT(5) #define GPSR0_D4 BIT(4) #define GPSR0_D3 BIT(3) #define GPSR0_D2 BIT(2) #define GPSR0_D1 BIT(1) #define GPSR0_D0 BIT(0) #define GPSR1_CLKOUT BIT(28) #define GPSR1_EX_WAIT0_A BIT(27) #define GPSR1_WE1 BIT(26) #define GPSR1_WE0 BIT(25) #define GPSR1_RD_WR BIT(24) #define GPSR1_RD BIT(23) #define GPSR1_BS BIT(22) #define GPSR1_CS1_A26 BIT(21) #define GPSR1_CS0 BIT(20) #define GPSR1_A19 BIT(19) #define GPSR1_A18 BIT(18) #define GPSR1_A17 BIT(17) #define GPSR1_A16 BIT(16) #define GPSR1_A15 BIT(15) #define GPSR1_A14 BIT(14) #define GPSR1_A13 BIT(13) #define GPSR1_A12 BIT(12) #define GPSR1_A11 BIT(11) #define GPSR1_A10 BIT(10) #define GPSR1_A9 BIT(9) #define GPSR1_A8 BIT(8) #define GPSR1_A7 BIT(7) #define GPSR1_A6 BIT(6) #define GPSR1_A5 BIT(5) #define GPSR1_A4 BIT(4) #define GPSR1_A3 BIT(3) #define GPSR1_A2 BIT(2) #define GPSR1_A1 BIT(1) #define GPSR1_A0 BIT(0) #define GPSR2_AVB_AVTP_CAPTURE_A BIT(14) #define GPSR2_AVB_AVTP_MATCH_A BIT(13) #define GPSR2_AVB_LINK BIT(12) #define GPSR2_AVB_PHY_INT BIT(11) #define GPSR2_AVB_MAGIC BIT(10) #define GPSR2_AVB_MDC BIT(9) #define GPSR2_PWM2_A BIT(8) #define GPSR2_PWM1_A BIT(7) #define GPSR2_PWM0 BIT(6) #define GPSR2_IRQ5 BIT(5) #define GPSR2_IRQ4 BIT(4) #define GPSR2_IRQ3 BIT(3) #define GPSR2_IRQ2 BIT(2) #define GPSR2_IRQ1 BIT(1) #define GPSR2_IRQ0 BIT(0) #define GPSR3_SD1_WP BIT(15) #define GPSR3_SD1_CD BIT(14) #define GPSR3_SD0_WP BIT(13) #define GPSR3_SD0_CD BIT(12) #define GPSR3_SD1_DAT3 BIT(11) #define GPSR3_SD1_DAT2 BIT(10) #define GPSR3_SD1_DAT1 BIT(9) #define GPSR3_SD1_DAT0 BIT(8) #define GPSR3_SD1_CMD BIT(7) #define GPSR3_SD1_CLK BIT(6) #define GPSR3_SD0_DAT3 BIT(5) #define GPSR3_SD0_DAT2 BIT(4) #define GPSR3_SD0_DAT1 BIT(3) #define GPSR3_SD0_DAT0 BIT(2) #define GPSR3_SD0_CMD BIT(1) #define GPSR3_SD0_CLK BIT(0) #define GPSR4_SD3_DS BIT(17) #define GPSR4_SD3_DAT7 BIT(16) #define GPSR4_SD3_DAT6 BIT(15) #define GPSR4_SD3_DAT5 BIT(14) #define GPSR4_SD3_DAT4 BIT(13) #define GPSR4_SD3_DAT3 BIT(12) #define GPSR4_SD3_DAT2 BIT(11) #define GPSR4_SD3_DAT1 BIT(10) #define GPSR4_SD3_DAT0 BIT(9) #define GPSR4_SD3_CMD BIT(8) #define GPSR4_SD3_CLK BIT(7) #define GPSR4_SD2_DS BIT(6) #define GPSR4_SD2_DAT3 BIT(5) #define GPSR4_SD2_DAT2 BIT(4) #define GPSR4_SD2_DAT1 BIT(3) #define GPSR4_SD2_DAT0 BIT(2) #define GPSR4_SD2_CMD BIT(1) #define GPSR4_SD2_CLK BIT(0) #define GPSR5_MLB_DAT BIT(25) #define GPSR5_MLB_SIG BIT(24) #define GPSR5_MLB_CLK BIT(23) #define GPSR5_MSIOF0_RXD BIT(22) #define GPSR5_MSIOF0_SS2 BIT(21) #define GPSR5_MSIOF0_TXD BIT(20) #define GPSR5_MSIOF0_SS1 BIT(19) #define GPSR5_MSIOF0_SYNC BIT(18) #define GPSR5_MSIOF0_SCK BIT(17) #define GPSR5_HRTS0 BIT(16) #define GPSR5_HCTS0 BIT(15) #define GPSR5_HTX0 BIT(14) #define GPSR5_HRX0 BIT(13) #define GPSR5_HSCK0 BIT(12) #define GPSR5_RX2_A BIT(11) #define GPSR5_TX2_A BIT(10) #define GPSR5_SCK2 BIT(9) #define GPSR5_RTS1 BIT(8) #define GPSR5_CTS1 BIT(7) #define GPSR5_TX1_A BIT(6) #define GPSR5_RX1_A BIT(5) #define GPSR5_RTS0 BIT(4) #define GPSR5_CTS0 BIT(3) #define GPSR5_TX0 BIT(2) #define GPSR5_RX0 BIT(1) #define GPSR5_SCK0 BIT(0) #define GPSR6_USB31_OVC BIT(31) #define GPSR6_USB31_PWEN BIT(30) #define GPSR6_USB30_OVC BIT(29) #define GPSR6_USB30_PWEN BIT(28) #define GPSR6_USB1_OVC BIT(27) #define GPSR6_USB1_PWEN BIT(26) #define GPSR6_USB0_OVC BIT(25) #define GPSR6_USB0_PWEN BIT(24) #define GPSR6_AUDIO_CLKB_B BIT(23) #define GPSR6_AUDIO_CLKA_A BIT(22) #define GPSR6_SSI_SDATA9_A BIT(21) #define GPSR6_SSI_SDATA8 BIT(20) #define GPSR6_SSI_SDATA7 BIT(19) #define GPSR6_SSI_WS78 BIT(18) #define GPSR6_SSI_SCK78 BIT(17) #define GPSR6_SSI_SDATA6 BIT(16) #define GPSR6_SSI_WS6 BIT(15) #define GPSR6_SSI_SCK6 BIT(14) #define GPSR6_SSI_SDATA5 BIT(13) #define GPSR6_SSI_WS5 BIT(12) #define GPSR6_SSI_SCK5 BIT(11) #define GPSR6_SSI_SDATA4 BIT(10) #define GPSR6_SSI_WS4 BIT(9) #define GPSR6_SSI_SCK4 BIT(8) #define GPSR6_SSI_SDATA3 BIT(7) #define GPSR6_SSI_WS34 BIT(6) #define GPSR6_SSI_SCK34 BIT(5) #define GPSR6_SSI_SDATA2_A BIT(4) #define GPSR6_SSI_SDATA1_A BIT(3) #define GPSR6_SSI_SDATA0 BIT(2) #define GPSR6_SSI_WS0129 BIT(1) #define GPSR6_SSI_SCK0129 BIT(0) #define GPSR7_AVS2 BIT(1) #define GPSR7_AVS1 BIT(0) #define IPSR_28_FUNC(x) ((uint32_t)(x) << 28U) #define IPSR_24_FUNC(x) ((uint32_t)(x) << 24U) #define IPSR_20_FUNC(x) ((uint32_t)(x) << 20U) #define IPSR_16_FUNC(x) ((uint32_t)(x) << 16U) #define IPSR_12_FUNC(x) ((uint32_t)(x) << 12U) #define IPSR_8_FUNC(x) ((uint32_t)(x) << 8U) #define IPSR_4_FUNC(x) ((uint32_t)(x) << 4U) #define IPSR_0_FUNC(x) ((uint32_t)(x) << 0U) #define POC_SD3_DS_33V BIT(29) #define POC_SD3_DAT7_33V BIT(28) #define POC_SD3_DAT6_33V BIT(27) #define POC_SD3_DAT5_33V BIT(26) #define POC_SD3_DAT4_33V BIT(25) #define POC_SD3_DAT3_33V BIT(24) #define POC_SD3_DAT2_33V BIT(23) #define POC_SD3_DAT1_33V BIT(22) #define POC_SD3_DAT0_33V BIT(21) #define POC_SD3_CMD_33V BIT(20) #define POC_SD3_CLK_33V BIT(19) #define POC_SD2_DS_33V BIT(18) #define POC_SD2_DAT3_33V BIT(17) #define POC_SD2_DAT2_33V BIT(16) #define POC_SD2_DAT1_33V BIT(15) #define POC_SD2_DAT0_33V BIT(14) #define POC_SD2_CMD_33V BIT(13) #define POC_SD2_CLK_33V BIT(12) #define POC_SD1_DAT3_33V BIT(11) #define POC_SD1_DAT2_33V BIT(10) #define POC_SD1_DAT1_33V BIT(9) #define POC_SD1_DAT0_33V BIT(8) #define POC_SD1_CMD_33V BIT(7) #define POC_SD1_CLK_33V BIT(6) #define POC_SD0_DAT3_33V BIT(5) #define POC_SD0_DAT2_33V BIT(4) #define POC_SD0_DAT1_33V BIT(3) #define POC_SD0_DAT0_33V BIT(2) #define POC_SD0_CMD_33V BIT(1) #define POC_SD0_CLK_33V BIT(0) #define DRVCTRL0_MASK (0xCCCCCCCCU) #define DRVCTRL1_MASK (0xCCCCCCC8U) #define DRVCTRL2_MASK (0x88888888U) #define DRVCTRL3_MASK (0x88888888U) #define DRVCTRL4_MASK (0x88888888U) #define DRVCTRL5_MASK (0x88888888U) #define DRVCTRL6_MASK (0x88888888U) #define DRVCTRL7_MASK (0x88888888U) #define DRVCTRL8_MASK (0x88888888U) #define DRVCTRL9_MASK (0x88888888U) #define DRVCTRL10_MASK (0x88888888U) #define DRVCTRL11_MASK (0x888888CCU) #define DRVCTRL12_MASK (0xCCCFFFCFU) #define DRVCTRL13_MASK (0xCC888888U) #define DRVCTRL14_MASK (0x88888888U) #define DRVCTRL15_MASK (0x88888888U) #define DRVCTRL16_MASK (0x88888888U) #define DRVCTRL17_MASK (0x88888888U) #define DRVCTRL18_MASK (0x88888888U) #define DRVCTRL19_MASK (0x88888888U) #define DRVCTRL20_MASK (0x88888888U) #define DRVCTRL21_MASK (0x88888888U) #define DRVCTRL22_MASK (0x88888888U) #define DRVCTRL23_MASK (0x88888888U) #define DRVCTRL24_MASK (0x8888888FU) #define DRVCTRL0_QSPI0_SPCLK(x) ((uint32_t)(x) << 28U) #define DRVCTRL0_QSPI0_MOSI_IO0(x) ((uint32_t)(x) << 24U) #define DRVCTRL0_QSPI0_MISO_IO1(x) ((uint32_t)(x) << 20U) #define DRVCTRL0_QSPI0_IO2(x) ((uint32_t)(x) << 16U) #define DRVCTRL0_QSPI0_IO3(x) ((uint32_t)(x) << 12U) #define DRVCTRL0_QSPI0_SSL(x) ((uint32_t)(x) << 8U) #define DRVCTRL0_QSPI1_SPCLK(x) ((uint32_t)(x) << 4U) #define DRVCTRL0_QSPI1_MOSI_IO0(x) ((uint32_t)(x) << 0U) #define DRVCTRL1_QSPI1_MISO_IO1(x) ((uint32_t)(x) << 28U) #define DRVCTRL1_QSPI1_IO2(x) ((uint32_t)(x) << 24U) #define DRVCTRL1_QSPI1_IO3(x) ((uint32_t)(x) << 20U) #define DRVCTRL1_QSPI1_SS(x) ((uint32_t)(x) << 16U) #define DRVCTRL1_RPC_INT(x) ((uint32_t)(x) << 12U) #define DRVCTRL1_RPC_WP(x) ((uint32_t)(x) << 8U) #define DRVCTRL1_RPC_RESET(x) ((uint32_t)(x) << 4U) #define DRVCTRL1_AVB_RX_CTL(x) ((uint32_t)(x) << 0U) #define DRVCTRL2_AVB_RXC(x) ((uint32_t)(x) << 28U) #define DRVCTRL2_AVB_RD0(x) ((uint32_t)(x) << 24U) #define DRVCTRL2_AVB_RD1(x) ((uint32_t)(x) << 20U) #define DRVCTRL2_AVB_RD2(x) ((uint32_t)(x) << 16U) #define DRVCTRL2_AVB_RD3(x) ((uint32_t)(x) << 12U) #define DRVCTRL2_AVB_TX_CTL(x) ((uint32_t)(x) << 8U) #define DRVCTRL2_AVB_TXC(x) ((uint32_t)(x) << 4U) #define DRVCTRL2_AVB_TD0(x) ((uint32_t)(x) << 0U) #define DRVCTRL3_AVB_TD1(x) ((uint32_t)(x) << 28U) #define DRVCTRL3_AVB_TD2(x) ((uint32_t)(x) << 24U) #define DRVCTRL3_AVB_TD3(x) ((uint32_t)(x) << 20U) #define DRVCTRL3_AVB_TXCREFCLK(x) ((uint32_t)(x) << 16U) #define DRVCTRL3_AVB_MDIO(x) ((uint32_t)(x) << 12U) #define DRVCTRL3_AVB_MDC(x) ((uint32_t)(x) << 8U) #define DRVCTRL3_AVB_MAGIC(x) ((uint32_t)(x) << 4U) #define DRVCTRL3_AVB_PHY_INT(x) ((uint32_t)(x) << 0U) #define DRVCTRL4_AVB_LINK(x) ((uint32_t)(x) << 28U) #define DRVCTRL4_AVB_AVTP_MATCH(x) ((uint32_t)(x) << 24U) #define DRVCTRL4_AVB_AVTP_CAPTURE(x) ((uint32_t)(x) << 20U) #define DRVCTRL4_IRQ0(x) ((uint32_t)(x) << 16U) #define DRVCTRL4_IRQ1(x) ((uint32_t)(x) << 12U) #define DRVCTRL4_IRQ2(x) ((uint32_t)(x) << 8U) #define DRVCTRL4_IRQ3(x) ((uint32_t)(x) << 4U) #define DRVCTRL4_IRQ4(x) ((uint32_t)(x) << 0U) #define DRVCTRL5_IRQ5(x) ((uint32_t)(x) << 28U) #define DRVCTRL5_PWM0(x) ((uint32_t)(x) << 24U) #define DRVCTRL5_PWM1(x) ((uint32_t)(x) << 20U) #define DRVCTRL5_PWM2(x) ((uint32_t)(x) << 16U) #define DRVCTRL5_A0(x) ((uint32_t)(x) << 12U) #define DRVCTRL5_A1(x) ((uint32_t)(x) << 8U) #define DRVCTRL5_A2(x) ((uint32_t)(x) << 4U) #define DRVCTRL5_A3(x) ((uint32_t)(x) << 0U) #define DRVCTRL6_A4(x) ((uint32_t)(x) << 28U) #define DRVCTRL6_A5(x) ((uint32_t)(x) << 24U) #define DRVCTRL6_A6(x) ((uint32_t)(x) << 20U) #define DRVCTRL6_A7(x) ((uint32_t)(x) << 16U) #define DRVCTRL6_A8(x) ((uint32_t)(x) << 12U) #define DRVCTRL6_A9(x) ((uint32_t)(x) << 8U) #define DRVCTRL6_A10(x) ((uint32_t)(x) << 4U) #define DRVCTRL6_A11(x) ((uint32_t)(x) << 0U) #define DRVCTRL7_A12(x) ((uint32_t)(x) << 28U) #define DRVCTRL7_A13(x) ((uint32_t)(x) << 24U) #define DRVCTRL7_A14(x) ((uint32_t)(x) << 20U) #define DRVCTRL7_A15(x) ((uint32_t)(x) << 16U) #define DRVCTRL7_A16(x) ((uint32_t)(x) << 12U) #define DRVCTRL7_A17(x) ((uint32_t)(x) << 8U) #define DRVCTRL7_A18(x) ((uint32_t)(x) << 4U) #define DRVCTRL7_A19(x) ((uint32_t)(x) << 0U) #define DRVCTRL8_CLKOUT(x) ((uint32_t)(x) << 28U) #define DRVCTRL8_CS0(x) ((uint32_t)(x) << 24U) #define DRVCTRL8_CS1_A2(x) ((uint32_t)(x) << 20U) #define DRVCTRL8_BS(x) ((uint32_t)(x) << 16U) #define DRVCTRL8_RD(x) ((uint32_t)(x) << 12U) #define DRVCTRL8_RD_W(x) ((uint32_t)(x) << 8U) #define DRVCTRL8_WE0(x) ((uint32_t)(x) << 4U) #define DRVCTRL8_WE1(x) ((uint32_t)(x) << 0U) #define DRVCTRL9_EX_WAIT0(x) ((uint32_t)(x) << 28U) #define DRVCTRL9_PRESETOU(x) ((uint32_t)(x) << 24U) #define DRVCTRL9_D0(x) ((uint32_t)(x) << 20U) #define DRVCTRL9_D1(x) ((uint32_t)(x) << 16U) #define DRVCTRL9_D2(x) ((uint32_t)(x) << 12U) #define DRVCTRL9_D3(x) ((uint32_t)(x) << 8U) #define DRVCTRL9_D4(x) ((uint32_t)(x) << 4U) #define DRVCTRL9_D5(x) ((uint32_t)(x) << 0U) #define DRVCTRL10_D6(x) ((uint32_t)(x) << 28U) #define DRVCTRL10_D7(x) ((uint32_t)(x) << 24U) #define DRVCTRL10_D8(x) ((uint32_t)(x) << 20U) #define DRVCTRL10_D9(x) ((uint32_t)(x) << 16U) #define DRVCTRL10_D10(x) ((uint32_t)(x) << 12U) #define DRVCTRL10_D11(x) ((uint32_t)(x) << 8U) #define DRVCTRL10_D12(x) ((uint32_t)(x) << 4U) #define DRVCTRL10_D13(x) ((uint32_t)(x) << 0U) #define DRVCTRL11_D14(x) ((uint32_t)(x) << 28U) #define DRVCTRL11_D15(x) ((uint32_t)(x) << 24U) #define DRVCTRL11_AVS1(x) ((uint32_t)(x) << 20U) #define DRVCTRL11_AVS2(x) ((uint32_t)(x) << 16U) #define DRVCTRL11_GP7_02(x) ((uint32_t)(x) << 12U) #define DRVCTRL11_GP7_03(x) ((uint32_t)(x) << 8U) #define DRVCTRL11_DU_DOTCLKIN0(x) ((uint32_t)(x) << 4U) #define DRVCTRL11_DU_DOTCLKIN1(x) ((uint32_t)(x) << 0U) #define DRVCTRL12_DU_DOTCLKIN2(x) ((uint32_t)(x) << 28U) #define DRVCTRL12_DU_DOTCLKIN3(x) ((uint32_t)(x) << 24U) #define DRVCTRL12_DU_FSCLKST(x) ((uint32_t)(x) << 20U) #define DRVCTRL12_DU_TMS(x) ((uint32_t)(x) << 4U) #define DRVCTRL13_TDO(x) ((uint32_t)(x) << 28U) #define DRVCTRL13_ASEBRK(x) ((uint32_t)(x) << 24U) #define DRVCTRL13_SD0_CLK(x) ((uint32_t)(x) << 20U) #define DRVCTRL13_SD0_CMD(x) ((uint32_t)(x) << 16U) #define DRVCTRL13_SD0_DAT0(x) ((uint32_t)(x) << 12U) #define DRVCTRL13_SD0_DAT1(x) ((uint32_t)(x) << 8U) #define DRVCTRL13_SD0_DAT2(x) ((uint32_t)(x) << 4U) #define DRVCTRL13_SD0_DAT3(x) ((uint32_t)(x) << 0U) #define DRVCTRL14_SD1_CLK(x) ((uint32_t)(x) << 28U) #define DRVCTRL14_SD1_CMD(x) ((uint32_t)(x) << 24U) #define DRVCTRL14_SD1_DAT0(x) ((uint32_t)(x) << 20U) #define DRVCTRL14_SD1_DAT1(x) ((uint32_t)(x) << 16U) #define DRVCTRL14_SD1_DAT2(x) ((uint32_t)(x) << 12U) #define DRVCTRL14_SD1_DAT3(x) ((uint32_t)(x) << 8U) #define DRVCTRL14_SD2_CLK(x) ((uint32_t)(x) << 4U) #define DRVCTRL14_SD2_CMD(x) ((uint32_t)(x) << 0U) #define DRVCTRL15_SD2_DAT0(x) ((uint32_t)(x) << 28U) #define DRVCTRL15_SD2_DAT1(x) ((uint32_t)(x) << 24U) #define DRVCTRL15_SD2_DAT2(x) ((uint32_t)(x) << 20U) #define DRVCTRL15_SD2_DAT3(x) ((uint32_t)(x) << 16U) #define DRVCTRL15_SD2_DS(x) ((uint32_t)(x) << 12U) #define DRVCTRL15_SD3_CLK(x) ((uint32_t)(x) << 8U) #define DRVCTRL15_SD3_CMD(x) ((uint32_t)(x) << 4U) #define DRVCTRL15_SD3_DAT0(x) ((uint32_t)(x) << 0U) #define DRVCTRL16_SD3_DAT1(x) ((uint32_t)(x) << 28U) #define DRVCTRL16_SD3_DAT2(x) ((uint32_t)(x) << 24U) #define DRVCTRL16_SD3_DAT3(x) ((uint32_t)(x) << 20U) #define DRVCTRL16_SD3_DAT4(x) ((uint32_t)(x) << 16U) #define DRVCTRL16_SD3_DAT5(x) ((uint32_t)(x) << 12U) #define DRVCTRL16_SD3_DAT6(x) ((uint32_t)(x) << 8U) #define DRVCTRL16_SD3_DAT7(x) ((uint32_t)(x) << 4U) #define DRVCTRL16_SD3_DS(x) ((uint32_t)(x) << 0U) #define DRVCTRL17_SD0_CD(x) ((uint32_t)(x) << 28U) #define DRVCTRL17_SD0_WP(x) ((uint32_t)(x) << 24U) #define DRVCTRL17_SD1_CD(x) ((uint32_t)(x) << 20U) #define DRVCTRL17_SD1_WP(x) ((uint32_t)(x) << 16U) #define DRVCTRL17_SCK0(x) ((uint32_t)(x) << 12U) #define DRVCTRL17_RX0(x) ((uint32_t)(x) << 8U) #define DRVCTRL17_TX0(x) ((uint32_t)(x) << 4U) #define DRVCTRL17_CTS0(x) ((uint32_t)(x) << 0U) #define DRVCTRL18_RTS0_TANS(x) ((uint32_t)(x) << 28U) #define DRVCTRL18_RX1(x) ((uint32_t)(x) << 24U) #define DRVCTRL18_TX1(x) ((uint32_t)(x) << 20U) #define DRVCTRL18_CTS1(x) ((uint32_t)(x) << 16U) #define DRVCTRL18_RTS1_TANS(x) ((uint32_t)(x) << 12U) #define DRVCTRL18_SCK2(x) ((uint32_t)(x) << 8U) #define DRVCTRL18_TX2(x) ((uint32_t)(x) << 4U) #define DRVCTRL18_RX2(x) ((uint32_t)(x) << 0U) #define DRVCTRL19_HSCK0(x) ((uint32_t)(x) << 28U) #define DRVCTRL19_HRX0(x) ((uint32_t)(x) << 24U) #define DRVCTRL19_HTX0(x) ((uint32_t)(x) << 20U) #define DRVCTRL19_HCTS0(x) ((uint32_t)(x) << 16U) #define DRVCTRL19_HRTS0(x) ((uint32_t)(x) << 12U) #define DRVCTRL19_MSIOF0_SCK(x) ((uint32_t)(x) << 8U) #define DRVCTRL19_MSIOF0_SYNC(x) ((uint32_t)(x) << 4U) #define DRVCTRL19_MSIOF0_SS1(x) ((uint32_t)(x) << 0U) #define DRVCTRL20_MSIOF0_TXD(x) ((uint32_t)(x) << 28U) #define DRVCTRL20_MSIOF0_SS2(x) ((uint32_t)(x) << 24U) #define DRVCTRL20_MSIOF0_RXD(x) ((uint32_t)(x) << 20U) #define DRVCTRL20_MLB_CLK(x) ((uint32_t)(x) << 16U) #define DRVCTRL20_MLB_SIG(x) ((uint32_t)(x) << 12U) #define DRVCTRL20_MLB_DAT(x) ((uint32_t)(x) << 8U) #define DRVCTRL20_MLB_REF(x) ((uint32_t)(x) << 4U) #define DRVCTRL20_SSI_SCK0129(x) ((uint32_t)(x) << 0U) #define DRVCTRL21_SSI_WS0129(x) ((uint32_t)(x) << 28U) #define DRVCTRL21_SSI_SDATA0(x) ((uint32_t)(x) << 24U) #define DRVCTRL21_SSI_SDATA1(x) ((uint32_t)(x) << 20U) #define DRVCTRL21_SSI_SDATA2(x) ((uint32_t)(x) << 16U) #define DRVCTRL21_SSI_SCK34(x) ((uint32_t)(x) << 12U) #define DRVCTRL21_SSI_WS34(x) ((uint32_t)(x) << 8U) #define DRVCTRL21_SSI_SDATA3(x) ((uint32_t)(x) << 4U) #define DRVCTRL21_SSI_SCK4(x) ((uint32_t)(x) << 0U) #define DRVCTRL22_SSI_WS4(x) ((uint32_t)(x) << 28U) #define DRVCTRL22_SSI_SDATA4(x) ((uint32_t)(x) << 24U) #define DRVCTRL22_SSI_SCK5(x) ((uint32_t)(x) << 20U) #define DRVCTRL22_SSI_WS5(x) ((uint32_t)(x) << 16U) #define DRVCTRL22_SSI_SDATA5(x) ((uint32_t)(x) << 12U) #define DRVCTRL22_SSI_SCK6(x) ((uint32_t)(x) << 8U) #define DRVCTRL22_SSI_WS6(x) ((uint32_t)(x) << 4U) #define DRVCTRL22_SSI_SDATA6(x) ((uint32_t)(x) << 0U) #define DRVCTRL23_SSI_SCK78(x) ((uint32_t)(x) << 28U) #define DRVCTRL23_SSI_WS78(x) ((uint32_t)(x) << 24U) #define DRVCTRL23_SSI_SDATA7(x) ((uint32_t)(x) << 20U) #define DRVCTRL23_SSI_SDATA8(x) ((uint32_t)(x) << 16U) #define DRVCTRL23_SSI_SDATA9(x) ((uint32_t)(x) << 12U) #define DRVCTRL23_AUDIO_CLKA(x) ((uint32_t)(x) << 8U) #define DRVCTRL23_AUDIO_CLKB(x) ((uint32_t)(x) << 4U) #define DRVCTRL23_USB0_PWEN(x) ((uint32_t)(x) << 0U) #define DRVCTRL24_USB0_OVC(x) ((uint32_t)(x) << 28U) #define DRVCTRL24_USB1_PWEN(x) ((uint32_t)(x) << 24U) #define DRVCTRL24_USB1_OVC(x) ((uint32_t)(x) << 20U) #define DRVCTRL24_USB30_PWEN(x) ((uint32_t)(x) << 16U) #define DRVCTRL24_USB30_OVC(x) ((uint32_t)(x) << 12U) #define DRVCTRL24_USB31_PWEN(x) ((uint32_t)(x) << 8U) #define DRVCTRL24_USB31_OVC(x) ((uint32_t)(x) << 4U) #define MOD_SEL0_MSIOF3_A ((uint32_t)0U << 29U) #define MOD_SEL0_MSIOF3_B ((uint32_t)1U << 29U) #define MOD_SEL0_MSIOF3_C ((uint32_t)2U << 29U) #define MOD_SEL0_MSIOF3_D ((uint32_t)3U << 29U) #define MOD_SEL0_MSIOF3_E ((uint32_t)4U << 29U) #define MOD_SEL0_MSIOF2_A ((uint32_t)0U << 27U) #define MOD_SEL0_MSIOF2_B ((uint32_t)1U << 27U) #define MOD_SEL0_MSIOF2_C ((uint32_t)2U << 27U) #define MOD_SEL0_MSIOF2_D ((uint32_t)3U << 27U) #define MOD_SEL0_MSIOF1_A ((uint32_t)0U << 24U) #define MOD_SEL0_MSIOF1_B ((uint32_t)1U << 24U) #define MOD_SEL0_MSIOF1_C ((uint32_t)2U << 24U) #define MOD_SEL0_MSIOF1_D ((uint32_t)3U << 24U) #define MOD_SEL0_MSIOF1_E ((uint32_t)4U << 24U) #define MOD_SEL0_MSIOF1_F ((uint32_t)5U << 24U) #define MOD_SEL0_MSIOF1_G ((uint32_t)6U << 24U) #define MOD_SEL0_LBSC_A ((uint32_t)0U << 23U) #define MOD_SEL0_LBSC_B ((uint32_t)1U << 23U) #define MOD_SEL0_IEBUS_A ((uint32_t)0U << 22U) #define MOD_SEL0_IEBUS_B ((uint32_t)1U << 22U) #define MOD_SEL0_I2C2_A ((uint32_t)0U << 21U) #define MOD_SEL0_I2C2_B ((uint32_t)1U << 21U) #define MOD_SEL0_I2C1_A ((uint32_t)0U << 20U) #define MOD_SEL0_I2C1_B ((uint32_t)1U << 20U) #define MOD_SEL0_HSCIF4_A ((uint32_t)0U << 19U) #define MOD_SEL0_HSCIF4_B ((uint32_t)1U << 19U) #define MOD_SEL0_HSCIF3_A ((uint32_t)0U << 17U) #define MOD_SEL0_HSCIF3_B ((uint32_t)1U << 17U) #define MOD_SEL0_HSCIF3_C ((uint32_t)2U << 17U) #define MOD_SEL0_HSCIF3_D ((uint32_t)3U << 17U) #define MOD_SEL0_HSCIF1_A ((uint32_t)0U << 16U) #define MOD_SEL0_HSCIF1_B ((uint32_t)1U << 16U) #define MOD_SEL0_FSO_A ((uint32_t)0U << 15U) #define MOD_SEL0_FSO_B ((uint32_t)1U << 15U) #define MOD_SEL0_HSCIF2_A ((uint32_t)0U << 13U) #define MOD_SEL0_HSCIF2_B ((uint32_t)1U << 13U) #define MOD_SEL0_HSCIF2_C ((uint32_t)2U << 13U) #define MOD_SEL0_ETHERAVB_A ((uint32_t)0U << 12U) #define MOD_SEL0_ETHERAVB_B ((uint32_t)1U << 12U) #define MOD_SEL0_DRIF3_A ((uint32_t)0U << 11U) #define MOD_SEL0_DRIF3_B ((uint32_t)1U << 11U) #define MOD_SEL0_DRIF2_A ((uint32_t)0U << 10U) #define MOD_SEL0_DRIF2_B ((uint32_t)1U << 10U) #define MOD_SEL0_DRIF1_A ((uint32_t)0U << 8U) #define MOD_SEL0_DRIF1_B ((uint32_t)1U << 8U) #define MOD_SEL0_DRIF1_C ((uint32_t)2U << 8U) #define MOD_SEL0_DRIF0_A ((uint32_t)0U << 6U) #define MOD_SEL0_DRIF0_B ((uint32_t)1U << 6U) #define MOD_SEL0_DRIF0_C ((uint32_t)2U << 6U) #define MOD_SEL0_CANFD0_A ((uint32_t)0U << 5U) #define MOD_SEL0_CANFD0_B ((uint32_t)1U << 5U) #define MOD_SEL0_ADG_A_A ((uint32_t)0U << 3U) #define MOD_SEL0_ADG_A_B ((uint32_t)1U << 3U) #define MOD_SEL0_ADG_A_C ((uint32_t)2U << 3U) #define MOD_SEL1_TSIF1_A ((uint32_t)0U << 30U) #define MOD_SEL1_TSIF1_B ((uint32_t)1U << 30U) #define MOD_SEL1_TSIF1_C ((uint32_t)2U << 30U) #define MOD_SEL1_TSIF1_D ((uint32_t)3U << 30U) #define MOD_SEL1_TSIF0_A ((uint32_t)0U << 27U) #define MOD_SEL1_TSIF0_B ((uint32_t)1U << 27U) #define MOD_SEL1_TSIF0_C ((uint32_t)2U << 27U) #define MOD_SEL1_TSIF0_D ((uint32_t)3U << 27U) #define MOD_SEL1_TSIF0_E ((uint32_t)4U << 27U) #define MOD_SEL1_TIMER_TMU_A ((uint32_t)0U << 26U) #define MOD_SEL1_TIMER_TMU_B ((uint32_t)1U << 26U) #define MOD_SEL1_SSP1_1_A ((uint32_t)0U << 24U) #define MOD_SEL1_SSP1_1_B ((uint32_t)1U << 24U) #define MOD_SEL1_SSP1_1_C ((uint32_t)2U << 24U) #define MOD_SEL1_SSP1_1_D ((uint32_t)3U << 24U) #define MOD_SEL1_SSP1_0_A ((uint32_t)0U << 21U) #define MOD_SEL1_SSP1_0_B ((uint32_t)1U << 21U) #define MOD_SEL1_SSP1_0_C ((uint32_t)2U << 21U) #define MOD_SEL1_SSP1_0_D ((uint32_t)3U << 21U) #define MOD_SEL1_SSP1_0_E ((uint32_t)4U << 21U) #define MOD_SEL1_SSI_A ((uint32_t)0U << 20U) #define MOD_SEL1_SSI_B ((uint32_t)1U << 20U) #define MOD_SEL1_SPEED_PULSE_IF_A ((uint32_t)0U << 19U) #define MOD_SEL1_SPEED_PULSE_IF_B ((uint32_t)1U << 19U) #define MOD_SEL1_SIMCARD_A ((uint32_t)0U << 17U) #define MOD_SEL1_SIMCARD_B ((uint32_t)1U << 17U) #define MOD_SEL1_SIMCARD_C ((uint32_t)2U << 17U) #define MOD_SEL1_SIMCARD_D ((uint32_t)3U << 17U) #define MOD_SEL1_SDHI2_A ((uint32_t)0U << 16U) #define MOD_SEL1_SDHI2_B ((uint32_t)1U << 16U) #define MOD_SEL1_SCIF4_A ((uint32_t)0U << 14U) #define MOD_SEL1_SCIF4_B ((uint32_t)1U << 14U) #define MOD_SEL1_SCIF4_C ((uint32_t)2U << 14U) #define MOD_SEL1_SCIF3_A ((uint32_t)0U << 13U) #define MOD_SEL1_SCIF3_B ((uint32_t)1U << 13U) #define MOD_SEL1_SCIF2_A ((uint32_t)0U << 12U) #define MOD_SEL1_SCIF2_B ((uint32_t)1U << 12U) #define MOD_SEL1_SCIF1_A ((uint32_t)0U << 11U) #define MOD_SEL1_SCIF1_B ((uint32_t)1U << 11U) #define MOD_SEL1_SCIF_A ((uint32_t)0U << 10U) #define MOD_SEL1_SCIF_B ((uint32_t)1U << 10U) #define MOD_SEL1_REMOCON_A ((uint32_t)0U << 9U) #define MOD_SEL1_REMOCON_B ((uint32_t)1U << 9U) #define MOD_SEL1_RCAN0_A ((uint32_t)0U << 6U) #define MOD_SEL1_RCAN0_B ((uint32_t)1U << 6U) #define MOD_SEL1_PWM6_A ((uint32_t)0U << 5U) #define MOD_SEL1_PWM6_B ((uint32_t)1U << 5U) #define MOD_SEL1_PWM5_A ((uint32_t)0U << 4U) #define MOD_SEL1_PWM5_B ((uint32_t)1U << 4U) #define MOD_SEL1_PWM4_A ((uint32_t)0U << 3U) #define MOD_SEL1_PWM4_B ((uint32_t)1U << 3U) #define MOD_SEL1_PWM3_A ((uint32_t)0U << 2U) #define MOD_SEL1_PWM3_B ((uint32_t)1U << 2U) #define MOD_SEL1_PWM2_A ((uint32_t)0U << 1U) #define MOD_SEL1_PWM2_B ((uint32_t)1U << 1U) #define MOD_SEL1_PWM1_A ((uint32_t)0U << 0U) #define MOD_SEL1_PWM1_B ((uint32_t)1U << 0U) #define MOD_SEL2_I2C_5_A ((uint32_t)0U << 31U) #define MOD_SEL2_I2C_5_B ((uint32_t)1U << 31U) #define MOD_SEL2_I2C_3_A ((uint32_t)0U << 30U) #define MOD_SEL2_I2C_3_B ((uint32_t)1U << 30U) #define MOD_SEL2_I2C_0_A ((uint32_t)0U << 29U) #define MOD_SEL2_I2C_0_B ((uint32_t)1U << 29U) #define MOD_SEL2_FM_A ((uint32_t)0U << 27U) #define MOD_SEL2_FM_B ((uint32_t)1U << 27U) #define MOD_SEL2_FM_C ((uint32_t)2U << 27U) #define MOD_SEL2_FM_D ((uint32_t)3U << 27U) #define MOD_SEL2_SCIF5_A ((uint32_t)0U << 26U) #define MOD_SEL2_SCIF5_B ((uint32_t)1U << 26U) #define MOD_SEL2_I2C6_A ((uint32_t)0U << 23U) #define MOD_SEL2_I2C6_B ((uint32_t)1U << 23U) #define MOD_SEL2_I2C6_C ((uint32_t)2U << 23U) #define MOD_SEL2_NDF_A ((uint32_t)0U << 22U) #define MOD_SEL2_NDF_B ((uint32_t)1U << 22U) #define MOD_SEL2_SSI2_A ((uint32_t)0U << 21U) #define MOD_SEL2_SSI2_B ((uint32_t)1U << 21U) #define MOD_SEL2_SSI9_A ((uint32_t)0U << 20U) #define MOD_SEL2_SSI9_B ((uint32_t)1U << 20U) #define MOD_SEL2_TIMER_TMU2_A ((uint32_t)0U << 19U) #define MOD_SEL2_TIMER_TMU2_B ((uint32_t)1U << 19U) #define MOD_SEL2_ADG_B_A ((uint32_t)0U << 18U) #define MOD_SEL2_ADG_B_B ((uint32_t)1U << 18U) #define MOD_SEL2_ADG_C_A ((uint32_t)0U << 17U) #define MOD_SEL2_ADG_C_B ((uint32_t)1U << 17U) #define MOD_SEL2_VIN4_A ((uint32_t)0U << 0U) #define MOD_SEL2_VIN4_B ((uint32_t)1U << 0U) static void pfc_reg_write(uint32_t addr, uint32_t data) { mmio_write_32(PFC_PMMR, ~data); mmio_write_32((uintptr_t)addr, data); } void pfc_init_m3n(void) { uint32_t reg; /* initialize module select */ pfc_reg_write(PFC_MOD_SEL0, MOD_SEL0_MSIOF3_A | MOD_SEL0_MSIOF2_A | MOD_SEL0_MSIOF1_A | MOD_SEL0_LBSC_A | MOD_SEL0_IEBUS_A | MOD_SEL0_I2C2_A | MOD_SEL0_I2C1_A | MOD_SEL0_HSCIF4_A | MOD_SEL0_HSCIF3_A | MOD_SEL0_HSCIF1_A | MOD_SEL0_FSO_A | MOD_SEL0_HSCIF2_A | MOD_SEL0_ETHERAVB_A | MOD_SEL0_DRIF3_A | MOD_SEL0_DRIF2_A | MOD_SEL0_DRIF1_A | MOD_SEL0_DRIF0_A | MOD_SEL0_CANFD0_A | MOD_SEL0_ADG_A_A); pfc_reg_write(PFC_MOD_SEL1, MOD_SEL1_TSIF1_A | MOD_SEL1_TSIF0_A | MOD_SEL1_TIMER_TMU_A | MOD_SEL1_SSP1_1_A | MOD_SEL1_SSP1_0_A | MOD_SEL1_SSI_A | MOD_SEL1_SPEED_PULSE_IF_A | MOD_SEL1_SIMCARD_A | MOD_SEL1_SDHI2_A | MOD_SEL1_SCIF4_A | MOD_SEL1_SCIF3_A | MOD_SEL1_SCIF2_A | MOD_SEL1_SCIF1_A | MOD_SEL1_SCIF_A | MOD_SEL1_REMOCON_A | MOD_SEL1_RCAN0_A | MOD_SEL1_PWM6_A | MOD_SEL1_PWM5_A | MOD_SEL1_PWM4_A | MOD_SEL1_PWM3_A | MOD_SEL1_PWM2_A | MOD_SEL1_PWM1_A); pfc_reg_write(PFC_MOD_SEL2, MOD_SEL2_I2C_5_A | MOD_SEL2_I2C_3_A | MOD_SEL2_I2C_0_A | MOD_SEL2_FM_A | MOD_SEL2_SCIF5_A | MOD_SEL2_I2C6_A | MOD_SEL2_NDF_A | MOD_SEL2_SSI2_A | MOD_SEL2_SSI9_A | MOD_SEL2_TIMER_TMU2_A | MOD_SEL2_ADG_B_A | MOD_SEL2_ADG_C_A | MOD_SEL2_VIN4_A); /* initialize peripheral function select */ pfc_reg_write(PFC_IPSR0, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR1, IPSR_28_FUNC(6) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(3) | IPSR_8_FUNC(3) | IPSR_4_FUNC(3) | IPSR_0_FUNC(3)); pfc_reg_write(PFC_IPSR2, IPSR_28_FUNC(0) | IPSR_24_FUNC(6) | IPSR_20_FUNC(6) | IPSR_16_FUNC(6) | IPSR_12_FUNC(6) | IPSR_8_FUNC(6) | IPSR_4_FUNC(6) | IPSR_0_FUNC(6)); pfc_reg_write(PFC_IPSR3, IPSR_28_FUNC(6) | IPSR_24_FUNC(6) | IPSR_20_FUNC(6) | IPSR_16_FUNC(6) | IPSR_12_FUNC(6) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR4, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(6) | IPSR_4_FUNC(6) | IPSR_0_FUNC(6)); pfc_reg_write(PFC_IPSR5, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(6) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR6, IPSR_28_FUNC(6) | IPSR_24_FUNC(6) | IPSR_20_FUNC(6) | IPSR_16_FUNC(6) | IPSR_12_FUNC(6) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR7, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_8_FUNC(6) | IPSR_4_FUNC(6) | IPSR_0_FUNC(6)); pfc_reg_write(PFC_IPSR8, IPSR_28_FUNC(1) | IPSR_24_FUNC(1) | IPSR_20_FUNC(1) | IPSR_16_FUNC(1) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR9, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR10, IPSR_28_FUNC(1) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR11, IPSR_28_FUNC(0) | IPSR_24_FUNC(4) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(1)); pfc_reg_write(PFC_IPSR12, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(4) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR13, IPSR_28_FUNC(8) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(3) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR14, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(3) | IPSR_0_FUNC(8)); pfc_reg_write(PFC_IPSR15, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR16, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR17, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(1) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR18, IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); /* initialize GPIO/perihperal function select */ pfc_reg_write(PFC_GPSR0, GPSR0_D15 | GPSR0_D14 | GPSR0_D13 | GPSR0_D12 | GPSR0_D11 | GPSR0_D10 | GPSR0_D9 | GPSR0_D8); pfc_reg_write(PFC_GPSR1, GPSR1_CLKOUT | GPSR1_EX_WAIT0_A | GPSR1_A19 | GPSR1_A18 | GPSR1_A17 | GPSR1_A16 | GPSR1_A15 | GPSR1_A14 | GPSR1_A13 | GPSR1_A12 | GPSR1_A7 | GPSR1_A6 | GPSR1_A5 | GPSR1_A4 | GPSR1_A3 | GPSR1_A2 | GPSR1_A1 | GPSR1_A0); pfc_reg_write(PFC_GPSR2, GPSR2_AVB_AVTP_CAPTURE_A | GPSR2_AVB_AVTP_MATCH_A | GPSR2_AVB_LINK | GPSR2_AVB_PHY_INT | GPSR2_AVB_MDC | GPSR2_PWM2_A | GPSR2_PWM1_A | GPSR2_IRQ5 | GPSR2_IRQ4 | GPSR2_IRQ3 | GPSR2_IRQ2 | GPSR2_IRQ1 | GPSR2_IRQ0); pfc_reg_write(PFC_GPSR3, GPSR3_SD0_WP | GPSR3_SD0_CD | GPSR3_SD1_DAT3 | GPSR3_SD1_DAT2 | GPSR3_SD1_DAT1 | GPSR3_SD1_DAT0 | GPSR3_SD0_DAT3 | GPSR3_SD0_DAT2 | GPSR3_SD0_DAT1 | GPSR3_SD0_DAT0 | GPSR3_SD0_CMD | GPSR3_SD0_CLK); pfc_reg_write(PFC_GPSR4, GPSR4_SD3_DAT7 | GPSR4_SD3_DAT6 | GPSR4_SD3_DAT3 | GPSR4_SD3_DAT2 | GPSR4_SD3_DAT1 | GPSR4_SD3_DAT0 | GPSR4_SD3_CMD | GPSR4_SD3_CLK | GPSR4_SD2_DS | GPSR4_SD2_DAT3 | GPSR4_SD2_DAT2 | GPSR4_SD2_DAT1 | GPSR4_SD2_DAT0 | GPSR4_SD2_CMD | GPSR4_SD2_CLK); pfc_reg_write(PFC_GPSR5, GPSR5_MSIOF0_SS2 | GPSR5_MSIOF0_SS1 | GPSR5_MSIOF0_SYNC | GPSR5_HRTS0 | GPSR5_HCTS0 | GPSR5_HTX0 | GPSR5_HRX0 | GPSR5_HSCK0 | GPSR5_RX2_A | GPSR5_TX2_A | GPSR5_SCK2 | GPSR5_RTS1 | GPSR5_CTS1 | GPSR5_TX1_A | GPSR5_RX1_A | GPSR5_RTS0 | GPSR5_SCK0); pfc_reg_write(PFC_GPSR6, GPSR6_USB30_OVC | GPSR6_USB30_PWEN | GPSR6_USB1_OVC | GPSR6_USB1_PWEN | GPSR6_USB0_OVC | GPSR6_USB0_PWEN | GPSR6_AUDIO_CLKB_B | GPSR6_AUDIO_CLKA_A | GPSR6_SSI_SDATA8 | GPSR6_SSI_SDATA7 | GPSR6_SSI_WS78 | GPSR6_SSI_SCK78 | GPSR6_SSI_WS6 | GPSR6_SSI_SCK6 | GPSR6_SSI_SDATA4 | GPSR6_SSI_WS4 | GPSR6_SSI_SCK4 | GPSR6_SSI_SDATA1_A | GPSR6_SSI_SDATA0 | GPSR6_SSI_WS0129 | GPSR6_SSI_SCK0129); pfc_reg_write(PFC_GPSR7, GPSR7_AVS2 | GPSR7_AVS1); /* initialize POC control register */ pfc_reg_write(PFC_POCCTRL0, POC_SD3_DS_33V | POC_SD3_DAT7_33V | POC_SD3_DAT6_33V | POC_SD3_DAT5_33V | POC_SD3_DAT4_33V | POC_SD3_DAT3_33V | POC_SD3_DAT2_33V | POC_SD3_DAT1_33V | POC_SD3_DAT0_33V | POC_SD3_CMD_33V | POC_SD3_CLK_33V | POC_SD0_DAT3_33V | POC_SD0_DAT2_33V | POC_SD0_DAT1_33V | POC_SD0_DAT0_33V | POC_SD0_CMD_33V | POC_SD0_CLK_33V); /* initialize DRV control register */ reg = mmio_read_32(PFC_DRVCTRL0); reg = ((reg & DRVCTRL0_MASK) | DRVCTRL0_QSPI0_SPCLK(3) | DRVCTRL0_QSPI0_MOSI_IO0(3) | DRVCTRL0_QSPI0_MISO_IO1(3) | DRVCTRL0_QSPI0_IO2(3) | DRVCTRL0_QSPI0_IO3(3) | DRVCTRL0_QSPI0_SSL(3) | DRVCTRL0_QSPI1_SPCLK(3) | DRVCTRL0_QSPI1_MOSI_IO0(3)); pfc_reg_write(PFC_DRVCTRL0, reg); reg = mmio_read_32(PFC_DRVCTRL1); reg = ((reg & DRVCTRL1_MASK) | DRVCTRL1_QSPI1_MISO_IO1(3) | DRVCTRL1_QSPI1_IO2(3) | DRVCTRL1_QSPI1_IO3(3) | DRVCTRL1_QSPI1_SS(3) | DRVCTRL1_RPC_INT(3) | DRVCTRL1_RPC_WP(3) | DRVCTRL1_RPC_RESET(3) | DRVCTRL1_AVB_RX_CTL(7)); pfc_reg_write(PFC_DRVCTRL1, reg); reg = mmio_read_32(PFC_DRVCTRL2); reg = ((reg & DRVCTRL2_MASK) | DRVCTRL2_AVB_RXC(7) | DRVCTRL2_AVB_RD0(7) | DRVCTRL2_AVB_RD1(7) | DRVCTRL2_AVB_RD2(7) | DRVCTRL2_AVB_RD3(7) | DRVCTRL2_AVB_TX_CTL(3) | DRVCTRL2_AVB_TXC(3) | DRVCTRL2_AVB_TD0(3)); pfc_reg_write(PFC_DRVCTRL2, reg); reg = mmio_read_32(PFC_DRVCTRL3); reg = ((reg & DRVCTRL3_MASK) | DRVCTRL3_AVB_TD1(3) | DRVCTRL3_AVB_TD2(3) | DRVCTRL3_AVB_TD3(3) | DRVCTRL3_AVB_TXCREFCLK(7) | DRVCTRL3_AVB_MDIO(7) | DRVCTRL3_AVB_MDC(7) | DRVCTRL3_AVB_MAGIC(7) | DRVCTRL3_AVB_PHY_INT(7)); pfc_reg_write(PFC_DRVCTRL3, reg); reg = mmio_read_32(PFC_DRVCTRL4); reg = ((reg & DRVCTRL4_MASK) | DRVCTRL4_AVB_LINK(7) | DRVCTRL4_AVB_AVTP_MATCH(7) | DRVCTRL4_AVB_AVTP_CAPTURE(7) | DRVCTRL4_IRQ0(7) | DRVCTRL4_IRQ1(7) | DRVCTRL4_IRQ2(7) | DRVCTRL4_IRQ3(7) | DRVCTRL4_IRQ4(7)); pfc_reg_write(PFC_DRVCTRL4, reg); reg = mmio_read_32(PFC_DRVCTRL5); reg = ((reg & DRVCTRL5_MASK) | DRVCTRL5_IRQ5(7) | DRVCTRL5_PWM0(7) | DRVCTRL5_PWM1(7) | DRVCTRL5_PWM2(7) | DRVCTRL5_A0(3) | DRVCTRL5_A1(3) | DRVCTRL5_A2(3) | DRVCTRL5_A3(3)); pfc_reg_write(PFC_DRVCTRL5, reg); reg = mmio_read_32(PFC_DRVCTRL6); reg = ((reg & DRVCTRL6_MASK) | DRVCTRL6_A4(3) | DRVCTRL6_A5(3) | DRVCTRL6_A6(3) | DRVCTRL6_A7(3) | DRVCTRL6_A8(7) | DRVCTRL6_A9(7) | DRVCTRL6_A10(7) | DRVCTRL6_A11(7)); pfc_reg_write(PFC_DRVCTRL6, reg); reg = mmio_read_32(PFC_DRVCTRL7); reg = ((reg & DRVCTRL7_MASK) | DRVCTRL7_A12(3) | DRVCTRL7_A13(3) | DRVCTRL7_A14(3) | DRVCTRL7_A15(3) | DRVCTRL7_A16(3) | DRVCTRL7_A17(3) | DRVCTRL7_A18(3) | DRVCTRL7_A19(3)); pfc_reg_write(PFC_DRVCTRL7, reg); reg = mmio_read_32(PFC_DRVCTRL8); reg = ((reg & DRVCTRL8_MASK) | DRVCTRL8_CLKOUT(7) | DRVCTRL8_CS0(7) | DRVCTRL8_CS1_A2(7) | DRVCTRL8_BS(7) | DRVCTRL8_RD(7) | DRVCTRL8_RD_W(7) | DRVCTRL8_WE0(7) | DRVCTRL8_WE1(7)); pfc_reg_write(PFC_DRVCTRL8, reg); reg = mmio_read_32(PFC_DRVCTRL9); reg = ((reg & DRVCTRL9_MASK) | DRVCTRL9_EX_WAIT0(7) | DRVCTRL9_PRESETOU(7) | DRVCTRL9_D0(7) | DRVCTRL9_D1(7) | DRVCTRL9_D2(7) | DRVCTRL9_D3(7) | DRVCTRL9_D4(7) | DRVCTRL9_D5(7)); pfc_reg_write(PFC_DRVCTRL9, reg); reg = mmio_read_32(PFC_DRVCTRL10); reg = ((reg & DRVCTRL10_MASK) | DRVCTRL10_D6(7) | DRVCTRL10_D7(7) | DRVCTRL10_D8(3) | DRVCTRL10_D9(3) | DRVCTRL10_D10(3) | DRVCTRL10_D11(3) | DRVCTRL10_D12(3) | DRVCTRL10_D13(3)); pfc_reg_write(PFC_DRVCTRL10, reg); reg = mmio_read_32(PFC_DRVCTRL11); reg = ((reg & DRVCTRL11_MASK) | DRVCTRL11_D14(3) | DRVCTRL11_D15(3) | DRVCTRL11_AVS1(7) | DRVCTRL11_AVS2(7) | DRVCTRL11_GP7_02(7) | DRVCTRL11_GP7_03(7) | DRVCTRL11_DU_DOTCLKIN0(3) | DRVCTRL11_DU_DOTCLKIN1(3)); pfc_reg_write(PFC_DRVCTRL11, reg); reg = mmio_read_32(PFC_DRVCTRL12); reg = ((reg & DRVCTRL12_MASK) | DRVCTRL12_DU_DOTCLKIN2(3) | DRVCTRL12_DU_DOTCLKIN3(3) | DRVCTRL12_DU_FSCLKST(3) | DRVCTRL12_DU_TMS(3)); pfc_reg_write(PFC_DRVCTRL12, reg); reg = mmio_read_32(PFC_DRVCTRL13); reg = ((reg & DRVCTRL13_MASK) | DRVCTRL13_TDO(3) | DRVCTRL13_ASEBRK(3) | DRVCTRL13_SD0_CLK(7) | DRVCTRL13_SD0_CMD(7) | DRVCTRL13_SD0_DAT0(7) | DRVCTRL13_SD0_DAT1(7) | DRVCTRL13_SD0_DAT2(7) | DRVCTRL13_SD0_DAT3(7)); pfc_reg_write(PFC_DRVCTRL13, reg); reg = mmio_read_32(PFC_DRVCTRL14); reg = ((reg & DRVCTRL14_MASK) | DRVCTRL14_SD1_CLK(7) | DRVCTRL14_SD1_CMD(7) | DRVCTRL14_SD1_DAT0(5) | DRVCTRL14_SD1_DAT1(5) | DRVCTRL14_SD1_DAT2(5) | DRVCTRL14_SD1_DAT3(5) | DRVCTRL14_SD2_CLK(5) | DRVCTRL14_SD2_CMD(5)); pfc_reg_write(PFC_DRVCTRL14, reg); reg = mmio_read_32(PFC_DRVCTRL15); reg = ((reg & DRVCTRL15_MASK) | DRVCTRL15_SD2_DAT0(5) | DRVCTRL15_SD2_DAT1(5) | DRVCTRL15_SD2_DAT2(5) | DRVCTRL15_SD2_DAT3(5) | DRVCTRL15_SD2_DS(5) | DRVCTRL15_SD3_CLK(7) | DRVCTRL15_SD3_CMD(7) | DRVCTRL15_SD3_DAT0(7)); pfc_reg_write(PFC_DRVCTRL15, reg); reg = mmio_read_32(PFC_DRVCTRL16); reg = ((reg & DRVCTRL16_MASK) | DRVCTRL16_SD3_DAT1(7) | DRVCTRL16_SD3_DAT2(7) | DRVCTRL16_SD3_DAT3(7) | DRVCTRL16_SD3_DAT4(7) | DRVCTRL16_SD3_DAT5(7) | DRVCTRL16_SD3_DAT6(7) | DRVCTRL16_SD3_DAT7(7) | DRVCTRL16_SD3_DS(7)); pfc_reg_write(PFC_DRVCTRL16, reg); reg = mmio_read_32(PFC_DRVCTRL17); reg = ((reg & DRVCTRL17_MASK) | DRVCTRL17_SD0_CD(7) | DRVCTRL17_SD0_WP(7) | DRVCTRL17_SD1_CD(7) | DRVCTRL17_SD1_WP(7) | DRVCTRL17_SCK0(7) | DRVCTRL17_RX0(7) | DRVCTRL17_TX0(7) | DRVCTRL17_CTS0(7)); pfc_reg_write(PFC_DRVCTRL17, reg); reg = mmio_read_32(PFC_DRVCTRL18); reg = ((reg & DRVCTRL18_MASK) | DRVCTRL18_RTS0_TANS(7) | DRVCTRL18_RX1(7) | DRVCTRL18_TX1(7) | DRVCTRL18_CTS1(7) | DRVCTRL18_RTS1_TANS(7) | DRVCTRL18_SCK2(7) | DRVCTRL18_TX2(7) | DRVCTRL18_RX2(7)); pfc_reg_write(PFC_DRVCTRL18, reg); reg = mmio_read_32(PFC_DRVCTRL19); reg = ((reg & DRVCTRL19_MASK) | DRVCTRL19_HSCK0(7) | DRVCTRL19_HRX0(7) | DRVCTRL19_HTX0(7) | DRVCTRL19_HCTS0(7) | DRVCTRL19_HRTS0(7) | DRVCTRL19_MSIOF0_SCK(7) | DRVCTRL19_MSIOF0_SYNC(7) | DRVCTRL19_MSIOF0_SS1(7)); pfc_reg_write(PFC_DRVCTRL19, reg); reg = mmio_read_32(PFC_DRVCTRL20); reg = ((reg & DRVCTRL20_MASK) | DRVCTRL20_MSIOF0_TXD(7) | DRVCTRL20_MSIOF0_SS2(7) | DRVCTRL20_MSIOF0_RXD(7) | DRVCTRL20_MLB_CLK(7) | DRVCTRL20_MLB_SIG(7) | DRVCTRL20_MLB_DAT(7) | DRVCTRL20_MLB_REF(7) | DRVCTRL20_SSI_SCK0129(7)); pfc_reg_write(PFC_DRVCTRL20, reg); reg = mmio_read_32(PFC_DRVCTRL21); reg = ((reg & DRVCTRL21_MASK) | DRVCTRL21_SSI_WS0129(7) | DRVCTRL21_SSI_SDATA0(7) | DRVCTRL21_SSI_SDATA1(7) | DRVCTRL21_SSI_SDATA2(7) | DRVCTRL21_SSI_SCK34(7) | DRVCTRL21_SSI_WS34(7) | DRVCTRL21_SSI_SDATA3(7) | DRVCTRL21_SSI_SCK4(7)); pfc_reg_write(PFC_DRVCTRL21, reg); reg = mmio_read_32(PFC_DRVCTRL22); reg = ((reg & DRVCTRL22_MASK) | DRVCTRL22_SSI_WS4(7) | DRVCTRL22_SSI_SDATA4(7) | DRVCTRL22_SSI_SCK5(7) | DRVCTRL22_SSI_WS5(7) | DRVCTRL22_SSI_SDATA5(7) | DRVCTRL22_SSI_SCK6(7) | DRVCTRL22_SSI_WS6(7) | DRVCTRL22_SSI_SDATA6(7)); pfc_reg_write(PFC_DRVCTRL22, reg); reg = mmio_read_32(PFC_DRVCTRL23); reg = ((reg & DRVCTRL23_MASK) | DRVCTRL23_SSI_SCK78(7) | DRVCTRL23_SSI_WS78(7) | DRVCTRL23_SSI_SDATA7(7) | DRVCTRL23_SSI_SDATA8(7) | DRVCTRL23_SSI_SDATA9(7) | DRVCTRL23_AUDIO_CLKA(7) | DRVCTRL23_AUDIO_CLKB(7) | DRVCTRL23_USB0_PWEN(7)); pfc_reg_write(PFC_DRVCTRL23, reg); reg = mmio_read_32(PFC_DRVCTRL24); reg = ((reg & DRVCTRL24_MASK) | DRVCTRL24_USB0_OVC(7) | DRVCTRL24_USB1_PWEN(7) | DRVCTRL24_USB1_OVC(7) | DRVCTRL24_USB30_PWEN(7) | DRVCTRL24_USB30_OVC(7) | DRVCTRL24_USB31_PWEN(7) | DRVCTRL24_USB31_OVC(7)); pfc_reg_write(PFC_DRVCTRL24, reg); /* initialize LSI pin pull-up/down control */ pfc_reg_write(PFC_PUD0, 0x00005FBFU); pfc_reg_write(PFC_PUD1, 0x00300FFEU); pfc_reg_write(PFC_PUD2, 0x330001E6U); pfc_reg_write(PFC_PUD3, 0x000002E0U); pfc_reg_write(PFC_PUD4, 0xFFFFFF00U); pfc_reg_write(PFC_PUD5, 0x7F5FFF87U); pfc_reg_write(PFC_PUD6, 0x00000055U); /* initialize LSI pin pull-enable register */ pfc_reg_write(PFC_PUEN0, 0x00000FFFU); pfc_reg_write(PFC_PUEN1, 0x00100234U); pfc_reg_write(PFC_PUEN2, 0x000004C4U); pfc_reg_write(PFC_PUEN3, 0x00000200U); pfc_reg_write(PFC_PUEN4, 0x3E000000U); pfc_reg_write(PFC_PUEN5, 0x1F000805U); pfc_reg_write(PFC_PUEN6, 0x00000006U); /* initialize positive/negative logic select */ mmio_write_32(GPIO_POSNEG0, 0x00000000U); mmio_write_32(GPIO_POSNEG1, 0x00000000U); mmio_write_32(GPIO_POSNEG2, 0x00000000U); mmio_write_32(GPIO_POSNEG3, 0x00000000U); mmio_write_32(GPIO_POSNEG4, 0x00000000U); mmio_write_32(GPIO_POSNEG5, 0x00000000U); mmio_write_32(GPIO_POSNEG6, 0x00000000U); mmio_write_32(GPIO_POSNEG7, 0x00000000U); /* initialize general IO/interrupt switching */ mmio_write_32(GPIO_IOINTSEL0, 0x00000000U); mmio_write_32(GPIO_IOINTSEL1, 0x00000000U); mmio_write_32(GPIO_IOINTSEL2, 0x00000000U); mmio_write_32(GPIO_IOINTSEL3, 0x00000000U); mmio_write_32(GPIO_IOINTSEL4, 0x00000000U); mmio_write_32(GPIO_IOINTSEL5, 0x00000000U); mmio_write_32(GPIO_IOINTSEL6, 0x00000000U); mmio_write_32(GPIO_IOINTSEL7, 0x00000000U); /* initialize general output register */ mmio_write_32(GPIO_OUTDT1, 0x00000000U); mmio_write_32(GPIO_OUTDT2, 0x00000400U); mmio_write_32(GPIO_OUTDT3, 0x0000C000U); mmio_write_32(GPIO_OUTDT5, 0x00000006U); mmio_write_32(GPIO_OUTDT6, 0x00003880U); /* initialize general input/output switching */ mmio_write_32(GPIO_INOUTSEL0, 0x00000000U); mmio_write_32(GPIO_INOUTSEL1, 0x01000A00U); mmio_write_32(GPIO_INOUTSEL2, 0x00000400U); mmio_write_32(GPIO_INOUTSEL3, 0x0000C000U); mmio_write_32(GPIO_INOUTSEL4, 0x00000000U); #if (RCAR_GEN3_ULCB == 1) mmio_write_32(GPIO_INOUTSEL5, 0x0000000EU); #else mmio_write_32(GPIO_INOUTSEL5, 0x0000020EU); #endif mmio_write_32(GPIO_INOUTSEL6, 0x00013880U); mmio_write_32(GPIO_INOUTSEL7, 0x00000000U); } trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.h000066400000000000000000000003531355360272700250450ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PFC_INIT_M3N_H #define PFC_INIT_M3N_H void pfc_init_m3n(void); #endif /* PFC_INIT_M3N_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/V3M/000077500000000000000000000000001355360272700223335ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c000066400000000000000000000714341355360272700250700ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* for uint32_t */ #include #include "pfc_init_v3m.h" #include "include/rcar_def.h" #include "rcar_private.h" #include "../pfc_regs.h" /* Pin functon bit */ #define GPSR0_DU_EXODDF_DU_ODDF_DISP_CDE BIT(21) #define GPSR0_DU_EXVSYNC_DU_VSYNC BIT(20) #define GPSR0_DU_EXHSYNC_DU_HSYNC BIT(19) #define GPSR0_DU_DOTCLKOUT BIT(18) #define GPSR0_DU_DB7 BIT(17) #define GPSR0_DU_DB6 BIT(16) #define GPSR0_DU_DB5 BIT(15) #define GPSR0_DU_DB4 BIT(14) #define GPSR0_DU_DB3 BIT(13) #define GPSR0_DU_DB2 BIT(12) #define GPSR0_DU_DG7 BIT(11) #define GPSR0_DU_DG6 BIT(10) #define GPSR0_DU_DG5 BIT(9) #define GPSR0_DU_DG4 BIT(8) #define GPSR0_DU_DG3 BIT(7) #define GPSR0_DU_DG2 BIT(6) #define GPSR0_DU_DR7 BIT(5) #define GPSR0_DU_DR6 BIT(4) #define GPSR0_DU_DR5 BIT(3) #define GPSR0_DU_DR4 BIT(2) #define GPSR0_DU_DR3 BIT(1) #define GPSR0_DU_DR2 BIT(0) #define GPSR1_DIGRF_CLKOUT BIT(27) #define GPSR1_DIGRF_CLKIN BIT(26) #define GPSR1_CANFD_CLK BIT(25) #define GPSR1_CANFD1_RX BIT(24) #define GPSR1_CANFD1_TX BIT(23) #define GPSR1_CANFD0_RX BIT(22) #define GPSR1_CANFD0_TX BIT(21) #define GPSR1_AVB0_AVTP_CAPTURE BIT(20) #define GPSR1_AVB0_AVTP_MATCH BIT(19) #define GPSR1_AVB0_LINK BIT(18) #define GPSR1_AVB0_PHY_INT BIT(17) #define GPSR1_AVB0_MAGIC BIT(16) #define GPSR1_AVB0_MDC BIT(15) #define GPSR1_AVB0_MDIO BIT(14) #define GPSR1_AVB0_TXCREFCLK BIT(13) #define GPSR1_AVB0_TD3 BIT(12) #define GPSR1_AVB0_TD2 BIT(11) #define GPSR1_AVB0_TD1 BIT(10) #define GPSR1_AVB0_TD0 BIT(9) #define GPSR1_AVB0_TXC BIT(8) #define GPSR1_AVB0_TX_CTL BIT(7) #define GPSR1_AVB0_RD3 BIT(6) #define GPSR1_AVB0_RD2 BIT(5) #define GPSR1_AVB0_RD1 BIT(4) #define GPSR1_AVB0_RD0 BIT(3) #define GPSR1_AVB0_RXC BIT(2) #define GPSR1_AVB0_RX_CTL BIT(1) #define GPSR1_IRQ0 BIT(0) #define GPSR2_VI0_FIELD BIT(16) #define GPSR2_VI0_DATA11 BIT(15) #define GPSR2_VI0_DATA10 BIT(14) #define GPSR2_VI0_DATA9 BIT(13) #define GPSR2_VI0_DATA8 BIT(12) #define GPSR2_VI0_DATA7 BIT(11) #define GPSR2_VI0_DATA6 BIT(10) #define GPSR2_VI0_DATA5 BIT(9) #define GPSR2_VI0_DATA4 BIT(8) #define GPSR2_VI0_DATA3 BIT(7) #define GPSR2_VI0_DATA2 BIT(6) #define GPSR2_VI0_DATA1 BIT(5) #define GPSR2_VI0_DATA0 BIT(4) #define GPSR2_VI0_VSYNC_N BIT(3) #define GPSR2_VI0_HSYNC_N BIT(2) #define GPSR2_VI0_CLKENB BIT(1) #define GPSR2_VI0_CLK BIT(0) #define GPSR3_VI1_FIELD BIT(16) #define GPSR3_VI1_DATA11 BIT(15) #define GPSR3_VI1_DATA10 BIT(14) #define GPSR3_VI1_DATA9 BIT(13) #define GPSR3_VI1_DATA8 BIT(12) #define GPSR3_VI1_DATA7 BIT(11) #define GPSR3_VI1_DATA6 BIT(10) #define GPSR3_VI1_DATA5 BIT(9) #define GPSR3_VI1_DATA4 BIT(8) #define GPSR3_VI1_DATA3 BIT(7) #define GPSR3_VI1_DATA2 BIT(6) #define GPSR3_VI1_DATA1 BIT(5) #define GPSR3_VI1_DATA0 BIT(4) #define GPSR3_VI1_VSYNC_N BIT(3) #define GPSR3_VI1_HSYNC_N BIT(2) #define GPSR3_VI1_CLKENB BIT(1) #define GPSR3_VI1_CLK BIT(0) #define GPSR4_SDA2 BIT(5) #define GPSR4_SCL2 BIT(4) #define GPSR4_SDA1 BIT(3) #define GPSR4_SCL1 BIT(2) #define GPSR4_SDA0 BIT(1) #define GPSR4_SCL0 BIT(0) #define GPSR5_RPC_INT_N BIT(14) #define GPSR5_RPC_WP_N BIT(13) #define GPSR5_RPC_RESET_N BIT(12) #define GPSR5_QSPI1_SSL BIT(11) #define GPSR5_QSPI1_IO3 BIT(10) #define GPSR5_QSPI1_IO2 BIT(9) #define GPSR5_QSPI1_MISO_IO1 BIT(8) #define GPSR5_QSPI1_MOSI_IO0 BIT(7) #define GPSR5_QSPI1_SPCLK BIT(6) #define GPSR5_QSPI0_SSL BIT(5) #define GPSR5_QSPI0_IO3 BIT(4) #define GPSR5_QSPI0_IO2 BIT(3) #define GPSR5_QSPI0_MISO_IO1 BIT(2) #define GPSR5_QSPI0_MOSI_IO0 BIT(1) #define GPSR5_QSPI0_SPCLK BIT(0) #define IPSR_28_FUNC(x) ((uint32_t)(x) << 28U) #define IPSR_24_FUNC(x) ((uint32_t)(x) << 24U) #define IPSR_20_FUNC(x) ((uint32_t)(x) << 20U) #define IPSR_16_FUNC(x) ((uint32_t)(x) << 16U) #define IPSR_12_FUNC(x) ((uint32_t)(x) << 12U) #define IPSR_8_FUNC(x) ((uint32_t)(x) << 8U) #define IPSR_4_FUNC(x) ((uint32_t)(x) << 4U) #define IPSR_0_FUNC(x) ((uint32_t)(x) << 0U) #define IOCTRL30_POC_VI0_DATA5 BIT(31) #define IOCTRL30_POC_VI0_DATA4 BIT(30) #define IOCTRL30_POC_VI0_DATA3 BIT(29) #define IOCTRL30_POC_VI0_DATA2 BIT(28) #define IOCTRL30_POC_VI0_DATA1 BIT(27) #define IOCTRL30_POC_VI0_DATA0 BIT(26) #define IOCTRL30_POC_VI0_VSYNC_N BIT(25) #define IOCTRL30_POC_VI0_HSYNC_N BIT(24) #define IOCTRL30_POC_VI0_CLKENB BIT(23) #define IOCTRL30_POC_VI0_CLK BIT(22) #define IOCTRL30_POC_DU_EXODDF_DU_ODDF_DISP_CDE BIT(21) #define IOCTRL30_POC_DU_EXVSYNC_DU_VSYNC BIT(20) #define IOCTRL30_POC_DU_EXHSYNC_DU_HSYNC BIT(19) #define IOCTRL30_POC_DU_DOTCLKOUT BIT(18) #define IOCTRL30_POC_DU_DB7 BIT(17) #define IOCTRL30_POC_DU_DB6 BIT(16) #define IOCTRL30_POC_DU_DB5 BIT(15) #define IOCTRL30_POC_DU_DB4 BIT(14) #define IOCTRL30_POC_DU_DB3 BIT(13) #define IOCTRL30_POC_DU_DB2 BIT(12) #define IOCTRL30_POC_DU_DG7 BIT(11) #define IOCTRL30_POC_DU_DG6 BIT(10) #define IOCTRL30_POC_DU_DG5 BIT(9) #define IOCTRL30_POC_DU_DG4 BIT(8) #define IOCTRL30_POC_DU_DG3 BIT(7) #define IOCTRL30_POC_DU_DG2 BIT(6) #define IOCTRL30_POC_DU_DR7 BIT(5) #define IOCTRL30_POC_DU_DR6 BIT(4) #define IOCTRL30_POC_DU_DR5 BIT(3) #define IOCTRL30_POC_DU_DR4 BIT(2) #define IOCTRL30_POC_DU_DR3 BIT(1) #define IOCTRL30_POC_DU_DR2 BIT(0) #define IOCTRL31_POC_DUMMY_31 BIT(31) #define IOCTRL31_POC_DUMMY_30 BIT(30) #define IOCTRL31_POC_DUMMY_29 BIT(29) #define IOCTRL31_POC_DUMMY_28 BIT(28) #define IOCTRL31_POC_DUMMY_27 BIT(27) #define IOCTRL31_POC_DUMMY_26 BIT(26) #define IOCTRL31_POC_DUMMY_25 BIT(25) #define IOCTRL31_POC_DUMMY_24 BIT(24) #define IOCTRL31_POC_VI1_FIELD BIT(23) #define IOCTRL31_POC_VI1_DATA11 BIT(22) #define IOCTRL31_POC_VI1_DATA10 BIT(21) #define IOCTRL31_POC_VI1_DATA9 BIT(20) #define IOCTRL31_POC_VI1_DATA8 BIT(19) #define IOCTRL31_POC_VI1_DATA7 BIT(18) #define IOCTRL31_POC_VI1_DATA6 BIT(17) #define IOCTRL31_POC_VI1_DATA5 BIT(16) #define IOCTRL31_POC_VI1_DATA4 BIT(15) #define IOCTRL31_POC_VI1_DATA3 BIT(14) #define IOCTRL31_POC_VI1_DATA2 BIT(13) #define IOCTRL31_POC_VI1_DATA1 BIT(12) #define IOCTRL31_POC_VI1_DATA0 BIT(11) #define IOCTRL31_POC_VI1_VSYNC_N BIT(10) #define IOCTRL31_POC_VI1_HSYNC_N BIT(9) #define IOCTRL31_POC_VI1_CLKENB BIT(8) #define IOCTRL31_POC_VI1_CLK BIT(7) #define IOCTRL31_POC_VI0_FIELD BIT(6) #define IOCTRL31_POC_VI0_DATA11 BIT(5) #define IOCTRL31_POC_VI0_DATA10 BIT(4) #define IOCTRL31_POC_VI0_DATA9 BIT(3) #define IOCTRL31_POC_VI0_DATA8 BIT(2) #define IOCTRL31_POC_VI0_DATA7 BIT(1) #define IOCTRL31_POC_VI0_DATA6 BIT(0) #define IOCTRL32_POC2_VREF BIT(0) #define IOCTRL40_SD0TDSEL1 BIT(1) #define IOCTRL40_SD0TDSEL0 BIT(0) #define PUEN0_PUEN_VI0_CLK BIT(31) #define PUEN0_PUEN_TDI BIT(30) #define PUEN0_PUEN_TMS BIT(29) #define PUEN0_PUEN_TCK BIT(28) #define PUEN0_PUEN_TRST_N BIT(27) #define PUEN0_PUEN_IRQ0 BIT(26) #define PUEN0_PUEN_FSCLKST_N BIT(25) #define PUEN0_PUEN_EXTALR BIT(24) #define PUEN0_PUEN_PRESETOUT_N BIT(23) #define PUEN0_PUEN_DU_DOTCLKIN BIT(22) #define PUEN0_PUEN_DU_EXODDF_DU_ODDF_DISP_CDE BIT(21) #define PUEN0_PUEN_DU_EXVSYNC_DU_VSYNC BIT(20) #define PUEN0_PUEN_DU_EXHSYNC_DU_HSYNC BIT(19) #define PUEN0_PUEN_DU_DOTCLKOUT BIT(18) #define PUEN0_PUEN_DU_DB7 BIT(17) #define PUEN0_PUEN_DU_DB6 BIT(16) #define PUEN0_PUEN_DU_DB5 BIT(15) #define PUEN0_PUEN_DU_DB4 BIT(14) #define PUEN0_PUEN_DU_DB3 BIT(13) #define PUEN0_PUEN_DU_DB2 BIT(12) #define PUEN0_PUEN_DU_DG7 BIT(11) #define PUEN0_PUEN_DU_DG6 BIT(10) #define PUEN0_PUEN_DU_DG5 BIT(9) #define PUEN0_PUEN_DU_DG4 BIT(8) #define PUEN0_PUEN_DU_DG3 BIT(7) #define PUEN0_PUEN_DU_DG2 BIT(6) #define PUEN0_PUEN_DU_DR7 BIT(5) #define PUEN0_PUEN_DU_DR6 BIT(4) #define PUEN0_PUEN_DU_DR5 BIT(3) #define PUEN0_PUEN_DU_DR4 BIT(2) #define PUEN0_PUEN_DU_DR3 BIT(1) #define PUEN0_PUEN_DU_DR2 BIT(0) #define PUEN1_PUEN_VI1_DATA11 BIT(31) #define PUEN1_PUEN_VI1_DATA10 BIT(30) #define PUEN1_PUEN_VI1_DATA9 BIT(29) #define PUEN1_PUEN_VI1_DATA8 BIT(28) #define PUEN1_PUEN_VI1_DATA7 BIT(27) #define PUEN1_PUEN_VI1_DATA6 BIT(26) #define PUEN1_PUEN_VI1_DATA5 BIT(25) #define PUEN1_PUEN_VI1_DATA4 BIT(24) #define PUEN1_PUEN_VI1_DATA3 BIT(23) #define PUEN1_PUEN_VI1_DATA2 BIT(22) #define PUEN1_PUEN_VI1_DATA1 BIT(21) #define PUEN1_PUEN_VI1_DATA0 BIT(20) #define PUEN1_PUEN_VI1_VSYNC_N BIT(19) #define PUEN1_PUEN_VI1_HSYNC_N BIT(18) #define PUEN1_PUEN_VI1_CLKENB BIT(17) #define PUEN1_PUEN_VI1_CLK BIT(16) #define PUEN1_PUEN_VI0_FIELD BIT(15) #define PUEN1_PUEN_VI0_DATA11 BIT(14) #define PUEN1_PUEN_VI0_DATA10 BIT(13) #define PUEN1_PUEN_VI0_DATA9 BIT(12) #define PUEN1_PUEN_VI0_DATA8 BIT(11) #define PUEN1_PUEN_VI0_DATA7 BIT(10) #define PUEN1_PUEN_VI0_DATA6 BIT(9) #define PUEN1_PUEN_VI0_DATA5 BIT(8) #define PUEN1_PUEN_VI0_DATA4 BIT(7) #define PUEN1_PUEN_VI0_DATA3 BIT(6) #define PUEN1_PUEN_VI0_DATA2 BIT(5) #define PUEN1_PUEN_VI0_DATA1 BIT(4) #define PUEN1_PUEN_VI0_DATA0 BIT(3) #define PUEN1_PUEN_VI0_VSYNC_N BIT(2) #define PUEN1_PUEN_VI0_HSYNC_N BIT(1) #define PUEN1_PUEN_VI0_CLKENB BIT(0) #define PUEN2_PUEN_CANFD_CLK BIT(31) #define PUEN2_PUEN_CANFD1_RX BIT(30) #define PUEN2_PUEN_CANFD1_TX BIT(29) #define PUEN2_PUEN_CANFD0_RX BIT(28) #define PUEN2_PUEN_CANFD0_TX BIT(27) #define PUEN2_PUEN_AVB0_AVTP_CAPTURE BIT(26) #define PUEN2_PUEN_AVB0_AVTP_MATCH BIT(25) #define PUEN2_PUEN_AVB0_LINK BIT(24) #define PUEN2_PUEN_AVB0_PHY_INT BIT(23) #define PUEN2_PUEN_AVB0_MAGIC BIT(22) #define PUEN2_PUEN_AVB0_MDC BIT(21) #define PUEN2_PUEN_AVB0_MDIO BIT(20) #define PUEN2_PUEN_AVB0_TXCREFCLK BIT(19) #define PUEN2_PUEN_AVB0_TD3 BIT(18) #define PUEN2_PUEN_AVB0_TD2 BIT(17) #define PUEN2_PUEN_AVB0_TD1 BIT(16) #define PUEN2_PUEN_AVB0_TD0 BIT(15) #define PUEN2_PUEN_AVB0_TXC BIT(14) #define PUEN2_PUEN_AVB0_TX_CTL BIT(13) #define PUEN2_PUEN_AVB0_RD3 BIT(12) #define PUEN2_PUEN_AVB0_RD2 BIT(11) #define PUEN2_PUEN_AVB0_RD1 BIT(10) #define PUEN2_PUEN_AVB0_RD0 BIT(9) #define PUEN2_PUEN_AVB0_RXC BIT(8) #define PUEN2_PUEN_AVB0_RX_CTL BIT(7) #define PUEN2_PUEN_SDA2 BIT(6) #define PUEN2_PUEN_SCL2 BIT(5) #define PUEN2_PUEN_SDA1 BIT(4) #define PUEN2_PUEN_SCL1 BIT(3) #define PUEN2_PUEN_SDA0 BIT(2) #define PUEN2_PUEN_SCL0 BIT(1) #define PUEN2_PUEN_VI1_FIELD BIT(0) #define PUEN3_PUEN_DIGRF_CLKOUT BIT(16) #define PUEN3_PUEN_DIGRF_CLKIN BIT(15) #define PUEN3_PUEN_RPC_INT_N BIT(14) #define PUEN3_PUEN_RPC_WP_N BIT(13) #define PUEN3_PUEN_RPC_RESET_N BIT(12) #define PUEN3_PUEN_QSPI1_SSL BIT(11) #define PUEN3_PUEN_QSPI1_IO3 BIT(10) #define PUEN3_PUEN_QSPI1_IO2 BIT(9) #define PUEN3_PUEN_QSPI1_MISO_IO1 BIT(8) #define PUEN3_PUEN_QSPI1_MOSI_IO0 BIT(7) #define PUEN3_PUEN_QSPI1_SPCLK BIT(6) #define PUEN3_PUEN_QSPI0_SSL BIT(5) #define PUEN3_PUEN_QSPI0_IO3 BIT(4) #define PUEN3_PUEN_QSPI0_IO2 BIT(3) #define PUEN3_PUEN_QSPI0_MISO_IO1 BIT(2) #define PUEN3_PUEN_QSPI0_MOSI_IO0 BIT(1) #define PUEN3_PUEN_QSPI0_SPCLK BIT(0) #define PUD0_PUD_VI0_CLK BIT(31) #define PUD0_PUD_IRQ0 BIT(26) #define PUD0_PUD_FSCLKST_N BIT(25) #define PUD0_PUD_PRESETOUT_N BIT(23) #define PUD0_PUD_DU_EXODDF_DU_ODDF_DISP_CDE BIT(21) #define PUD0_PUD_DU_EXVSYNC_DU_VSYNC BIT(20) #define PUD0_PUD_DU_EXHSYNC_DU_HSYNC BIT(19) #define PUD0_PUD_DU_DOTCLKOUT BIT(18) #define PUD0_PUD_DU_DB7 BIT(17) #define PUD0_PUD_DU_DB6 BIT(16) #define PUD0_PUD_DU_DB5 BIT(15) #define PUD0_PUD_DU_DB4 BIT(14) #define PUD0_PUD_DU_DB3 BIT(13) #define PUD0_PUD_DU_DB2 BIT(12) #define PUD0_PUD_DU_DG7 BIT(11) #define PUD0_PUD_DU_DG6 BIT(10) #define PUD0_PUD_DU_DG5 BIT(9) #define PUD0_PUD_DU_DG4 BIT(8) #define PUD0_PUD_DU_DG3 BIT(7) #define PUD0_PUD_DU_DG2 BIT(6) #define PUD0_PUD_DU_DR7 BIT(5) #define PUD0_PUD_DU_DR6 BIT(4) #define PUD0_PUD_DU_DR5 BIT(3) #define PUD0_PUD_DU_DR4 BIT(2) #define PUD0_PUD_DU_DR3 BIT(1) #define PUD0_PUD_DU_DR2 BIT(0) #define PUD1_PUD_VI1_DATA11 BIT(31) #define PUD1_PUD_VI1_DATA10 BIT(30) #define PUD1_PUD_VI1_DATA9 BIT(29) #define PUD1_PUD_VI1_DATA8 BIT(28) #define PUD1_PUD_VI1_DATA7 BIT(27) #define PUD1_PUD_VI1_DATA6 BIT(26) #define PUD1_PUD_VI1_DATA5 BIT(25) #define PUD1_PUD_VI1_DATA4 BIT(24) #define PUD1_PUD_VI1_DATA3 BIT(23) #define PUD1_PUD_VI1_DATA2 BIT(22) #define PUD1_PUD_VI1_DATA1 BIT(21) #define PUD1_PUD_VI1_DATA0 BIT(20) #define PUD1_PUD_VI1_VSYNC_N BIT(19) #define PUD1_PUD_VI1_HSYNC_N BIT(18) #define PUD1_PUD_VI1_CLKENB BIT(17) #define PUD1_PUD_VI1_CLK BIT(16) #define PUD1_PUD_VI0_FIELD BIT(15) #define PUD1_PUD_VI0_DATA11 BIT(14) #define PUD1_PUD_VI0_DATA10 BIT(13) #define PUD1_PUD_VI0_DATA9 BIT(12) #define PUD1_PUD_VI0_DATA8 BIT(11) #define PUD1_PUD_VI0_DATA7 BIT(10) #define PUD1_PUD_VI0_DATA6 BIT(9) #define PUD1_PUD_VI0_DATA5 BIT(8) #define PUD1_PUD_VI0_DATA4 BIT(7) #define PUD1_PUD_VI0_DATA3 BIT(6) #define PUD1_PUD_VI0_DATA2 BIT(5) #define PUD1_PUD_VI0_DATA1 BIT(4) #define PUD1_PUD_VI0_DATA0 BIT(3) #define PUD1_PUD_VI0_VSYNC_N BIT(2) #define PUD1_PUD_VI0_HSYNC_N BIT(1) #define PUD1_PUD_VI0_CLKENB BIT(0) #define PUD2_PUD_CANFD_CLK BIT(31) #define PUD2_PUD_CANFD1_RX BIT(30) #define PUD2_PUD_CANFD1_TX BIT(29) #define PUD2_PUD_CANFD0_RX BIT(28) #define PUD2_PUD_CANFD0_TX BIT(27) #define PUD2_PUD_AVB0_AVTP_CAPTURE BIT(26) #define PUD2_PUD_AVB0_AVTP_MATCH BIT(25) #define PUD2_PUD_AVB0_LINK BIT(24) #define PUD2_PUD_AVB0_PHY_INT BIT(23) #define PUD2_PUD_AVB0_MAGIC BIT(22) #define PUD2_PUD_AVB0_MDC BIT(21) #define PUD2_PUD_AVB0_MDIO BIT(20) #define PUD2_PUD_AVB0_TXCREFCLK BIT(19) #define PUD2_PUD_AVB0_TD3 BIT(18) #define PUD2_PUD_AVB0_TD2 BIT(17) #define PUD2_PUD_AVB0_TD1 BIT(16) #define PUD2_PUD_AVB0_TD0 BIT(15) #define PUD2_PUD_AVB0_TXC BIT(14) #define PUD2_PUD_AVB0_TX_CTL BIT(13) #define PUD2_PUD_AVB0_RD3 BIT(12) #define PUD2_PUD_AVB0_RD2 BIT(11) #define PUD2_PUD_AVB0_RD1 BIT(10) #define PUD2_PUD_AVB0_RD0 BIT(9) #define PUD2_PUD_AVB0_RXC BIT(8) #define PUD2_PUD_AVB0_RX_CTL BIT(7) #define PUD2_PUD_SDA2 BIT(6) #define PUD2_PUD_SCL2 BIT(5) #define PUD2_PUD_SDA1 BIT(4) #define PUD2_PUD_SCL1 BIT(3) #define PUD2_PUD_SDA0 BIT(2) #define PUD2_PUD_SCL0 BIT(1) #define PUD2_PUD_VI1_FIELD BIT(0) #define PUD3_PUD_DIGRF_CLKOUT BIT(16) #define PUD3_PUD_DIGRF_CLKIN BIT(15) #define PUD3_PUD_RPC_INT_N BIT(14) #define PUD3_PUD_RPC_WP_N BIT(13) #define PUD3_PUD_RPC_RESET_N BIT(12) #define PUD3_PUD_QSPI1_SSL BIT(11) #define PUD3_PUD_QSPI1_IO3 BIT(10) #define PUD3_PUD_QSPI1_IO2 BIT(9) #define PUD3_PUD_QSPI1_MISO_IO1 BIT(8) #define PUD3_PUD_QSPI1_MOSI_IO0 BIT(7) #define PUD3_PUD_QSPI1_SPCLK BIT(6) #define PUD3_PUD_QSPI0_SSL BIT(5) #define PUD3_PUD_QSPI0_IO3 BIT(4) #define PUD3_PUD_QSPI0_IO2 BIT(3) #define PUD3_PUD_QSPI0_MISO_IO1 BIT(2) #define PUD3_PUD_QSPI0_MOSI_IO0 BIT(1) #define PUD3_PUD_QSPI0_SPCLK BIT(0) #define MOD_SEL0_sel_hscif0 BIT(10) #define MOD_SEL0_sel_scif1 BIT(9) #define MOD_SEL0_sel_canfd0 BIT(8) #define MOD_SEL0_sel_pwm4 BIT(7) #define MOD_SEL0_sel_pwm3 BIT(6) #define MOD_SEL0_sel_pwm2 BIT(5) #define MOD_SEL0_sel_pwm1 BIT(4) #define MOD_SEL0_sel_pwm0 BIT(3) #define MOD_SEL0_sel_rfso BIT(2) #define MOD_SEL0_sel_rsp BIT(1) #define MOD_SEL0_sel_tmu BIT(0) /* SCIF3 Registers for Dummy write */ #define SCIF3_BASE (0xE6C50000U) #define SCIF3_SCFCR (SCIF3_BASE + 0x0018U) #define SCIF3_SCFDR (SCIF3_BASE + 0x001CU) #define SCFCR_DATA (0x0000U) /* Realtime module stop control */ #define CPG_BASE (0xE6150000U) #define CPG_MSTPSR0 (CPG_BASE + 0x0030U) #define CPG_RMSTPCR0 (CPG_BASE + 0x0110U) #define RMSTPCR0_RTDMAC (0x00200000U) /* RT-DMAC Registers */ #define RTDMAC_CH (0U) /* choose 0 to 15 */ #define RTDMAC_BASE (0xFFC10000U) #define RTDMAC_RDMOR (RTDMAC_BASE + 0x0060U) #define RTDMAC_RDMCHCLR (RTDMAC_BASE + 0x0080U) #define RTDMAC_RDMSAR(x) (RTDMAC_BASE + 0x8000U + (0x80U * (x))) #define RTDMAC_RDMDAR(x) (RTDMAC_BASE + 0x8004U + (0x80U * (x))) #define RTDMAC_RDMTCR(x) (RTDMAC_BASE + 0x8008U + (0x80U * (x))) #define RTDMAC_RDMCHCR(x) (RTDMAC_BASE + 0x800CU + (0x80U * (x))) #define RTDMAC_RDMCHCRB(x) (RTDMAC_BASE + 0x801CU + (0x80U * (x))) #define RTDMAC_RDMDPBASE(x) (RTDMAC_BASE + 0x8050U + (0x80U * (x))) #define RTDMAC_DESC_BASE (RTDMAC_BASE + 0xA000U) #define RTDMAC_DESC_RDMSAR (RTDMAC_DESC_BASE + 0x0000U) #define RTDMAC_DESC_RDMDAR (RTDMAC_DESC_BASE + 0x0004U) #define RTDMAC_DESC_RDMTCR (RTDMAC_DESC_BASE + 0x0008U) #define RDMOR_DME (0x0001U) /* DMA Master Enable */ #define RDMCHCR_DPM_INFINITE (0x30000000U) /* Infinite repeat mode */ #define RDMCHCR_RPT_TCR (0x02000000U) /* enable to update TCR */ #define RDMCHCR_TS_2 (0x00000008U) /* Word(2byte) units transfer */ #define RDMCHCR_RS_AUTO (0x00000400U) /* Auto request */ #define RDMCHCR_DE (0x00000001U) /* DMA Enable */ #define RDMCHCRB_DRST (0x00008000U) /* Descriptor reset */ #define RDMCHCRB_SLM_256 (0x00000080U) /* once in 256 clock cycle */ #define RDMDPBASE_SEL_EXT (0x00000001U) /* External memory use */ static void pfc_reg_write(uint32_t addr, uint32_t data) { mmio_write_32(PFC_PMMR, ~data); mmio_write_32((uintptr_t)addr, data); } static void start_rtdma0_descriptor(void) { uint32_t reg; /* Module stop clear */ while ((mmio_read_32(CPG_MSTPSR0) & RMSTPCR0_RTDMAC) != 0U) { reg = mmio_read_32(CPG_RMSTPCR0); reg &= ~RMSTPCR0_RTDMAC; cpg_write(CPG_RMSTPCR0, reg); } /* Initialize ch0, Reset Descriptor */ mmio_write_32(RTDMAC_RDMCHCLR, BIT(RTDMAC_CH)); mmio_write_32(RTDMAC_RDMCHCRB(RTDMAC_CH), RDMCHCRB_DRST); /* Enable DMA */ mmio_write_16(RTDMAC_RDMOR, RDMOR_DME); /* Set first transfer */ mmio_write_32(RTDMAC_RDMSAR(RTDMAC_CH), RCAR_PRR); mmio_write_32(RTDMAC_RDMDAR(RTDMAC_CH), SCIF3_SCFDR); mmio_write_32(RTDMAC_RDMTCR(RTDMAC_CH), 0x00000001U); /* Set descriptor */ mmio_write_32(RTDMAC_DESC_RDMSAR, 0x00000000U); mmio_write_32(RTDMAC_DESC_RDMDAR, 0x00000000U); mmio_write_32(RTDMAC_DESC_RDMTCR, 0x00200000U); mmio_write_32(RTDMAC_RDMCHCRB(RTDMAC_CH), RDMCHCRB_SLM_256); mmio_write_32(RTDMAC_RDMDPBASE(RTDMAC_CH), RTDMAC_DESC_BASE | RDMDPBASE_SEL_EXT); /* Set transfer parameter, Start transfer */ mmio_write_32(RTDMAC_RDMCHCR(RTDMAC_CH), RDMCHCR_DPM_INFINITE | RDMCHCR_RPT_TCR | RDMCHCR_TS_2 | RDMCHCR_RS_AUTO | RDMCHCR_DE); } void pfc_init_v3m(void) { /* Work around for PFC eratta */ start_rtdma0_descriptor(); // pin function // md[4:1]!=0000 /* initialize GPIO/perihperal function select */ pfc_reg_write(PFC_GPSR0, 0x00000000); pfc_reg_write(PFC_GPSR1, GPSR1_CANFD_CLK); pfc_reg_write(PFC_GPSR2, 0x00000000); pfc_reg_write(PFC_GPSR3, 0x00000000); pfc_reg_write(PFC_GPSR4, GPSR4_SDA2 | GPSR4_SCL2); pfc_reg_write(PFC_GPSR5, GPSR5_QSPI1_SSL | GPSR5_QSPI1_IO3 | GPSR5_QSPI1_IO2 | GPSR5_QSPI1_MISO_IO1 | GPSR5_QSPI1_MOSI_IO0 | GPSR5_QSPI1_SPCLK | GPSR5_QSPI0_SSL | GPSR5_QSPI0_IO3 | GPSR5_QSPI0_IO2 | GPSR5_QSPI0_MISO_IO1 | GPSR5_QSPI0_MOSI_IO0 | GPSR5_QSPI0_SPCLK); /* initialize peripheral function select */ pfc_reg_write(PFC_IPSR0, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR1, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR2, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR3, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR4, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR5, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR6, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(0) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR7, IPSR_28_FUNC(0) | IPSR_24_FUNC(4) | IPSR_20_FUNC(4) | IPSR_16_FUNC(4) | IPSR_12_FUNC(4) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); pfc_reg_write(PFC_IPSR8, IPSR_28_FUNC(0) | IPSR_24_FUNC(0) | IPSR_20_FUNC(0) | IPSR_16_FUNC(4) | IPSR_12_FUNC(0) | IPSR_8_FUNC(0) | IPSR_4_FUNC(0) | IPSR_0_FUNC(0)); /* initialize POC Control */ pfc_reg_write(PFC_POCCTRL0, IOCTRL30_POC_VI0_DATA5 | IOCTRL30_POC_VI0_DATA4 | IOCTRL30_POC_VI0_DATA3 | IOCTRL30_POC_VI0_DATA2 | IOCTRL30_POC_VI0_DATA1 | IOCTRL30_POC_VI0_DATA0 | IOCTRL30_POC_VI0_VSYNC_N | IOCTRL30_POC_VI0_HSYNC_N | IOCTRL30_POC_VI0_CLKENB | IOCTRL30_POC_VI0_CLK | IOCTRL30_POC_DU_EXODDF_DU_ODDF_DISP_CDE | IOCTRL30_POC_DU_EXVSYNC_DU_VSYNC | IOCTRL30_POC_DU_EXHSYNC_DU_HSYNC | IOCTRL30_POC_DU_DOTCLKOUT | IOCTRL30_POC_DU_DB7 | IOCTRL30_POC_DU_DB6 | IOCTRL30_POC_DU_DB5 | IOCTRL30_POC_DU_DB4 | IOCTRL30_POC_DU_DB3 | IOCTRL30_POC_DU_DB2 | IOCTRL30_POC_DU_DG7 | IOCTRL30_POC_DU_DG6 | IOCTRL30_POC_DU_DG5 | IOCTRL30_POC_DU_DG4 | IOCTRL30_POC_DU_DG3 | IOCTRL30_POC_DU_DG2 | IOCTRL30_POC_DU_DR7 | IOCTRL30_POC_DU_DR6 | IOCTRL30_POC_DU_DR5 | IOCTRL30_POC_DU_DR4 | IOCTRL30_POC_DU_DR3 | IOCTRL30_POC_DU_DR2); pfc_reg_write(PFC_IOCTRL31, IOCTRL31_POC_DUMMY_31 | IOCTRL31_POC_DUMMY_30 | IOCTRL31_POC_DUMMY_29 | IOCTRL31_POC_DUMMY_28 | IOCTRL31_POC_DUMMY_27 | IOCTRL31_POC_DUMMY_26 | IOCTRL31_POC_DUMMY_25 | IOCTRL31_POC_DUMMY_24 | IOCTRL31_POC_VI1_FIELD | IOCTRL31_POC_VI1_DATA11 | IOCTRL31_POC_VI1_DATA10 | IOCTRL31_POC_VI1_DATA9 | IOCTRL31_POC_VI1_DATA8 | IOCTRL31_POC_VI1_DATA7 | IOCTRL31_POC_VI1_DATA6 | IOCTRL31_POC_VI1_DATA5 | IOCTRL31_POC_VI1_DATA4 | IOCTRL31_POC_VI1_DATA3 | IOCTRL31_POC_VI1_DATA2 | IOCTRL31_POC_VI1_DATA1 | IOCTRL31_POC_VI1_DATA0 | IOCTRL31_POC_VI1_VSYNC_N | IOCTRL31_POC_VI1_HSYNC_N | IOCTRL31_POC_VI1_CLKENB | IOCTRL31_POC_VI1_CLK | IOCTRL31_POC_VI0_FIELD | IOCTRL31_POC_VI0_DATA11 | IOCTRL31_POC_VI0_DATA10 | IOCTRL31_POC_VI0_DATA9 | IOCTRL31_POC_VI0_DATA8 | IOCTRL31_POC_VI0_DATA7 | IOCTRL31_POC_VI0_DATA6); pfc_reg_write(PFC_POCCTRL2, 0x00000000); pfc_reg_write(PFC_TDSELCTRL0, 0x00000000); /* initialize Pull enable */ pfc_reg_write(PFC_PUEN0, PUEN0_PUEN_VI0_CLK | PUEN0_PUEN_TDI | PUEN0_PUEN_TMS | PUEN0_PUEN_TCK | PUEN0_PUEN_TRST_N | PUEN0_PUEN_IRQ0 | PUEN0_PUEN_FSCLKST_N | PUEN0_PUEN_DU_EXHSYNC_DU_HSYNC | PUEN0_PUEN_DU_DOTCLKOUT | PUEN0_PUEN_DU_DB7 | PUEN0_PUEN_DU_DB6 | PUEN0_PUEN_DU_DB5 | PUEN0_PUEN_DU_DB4 | PUEN0_PUEN_DU_DB3 | PUEN0_PUEN_DU_DB2 | PUEN0_PUEN_DU_DG7 | PUEN0_PUEN_DU_DG6 | PUEN0_PUEN_DU_DG5 | PUEN0_PUEN_DU_DG4 | PUEN0_PUEN_DU_DG3 | PUEN0_PUEN_DU_DG2 | PUEN0_PUEN_DU_DR7 | PUEN0_PUEN_DU_DR6 | PUEN0_PUEN_DU_DR5 | PUEN0_PUEN_DU_DR4 | PUEN0_PUEN_DU_DR3 | PUEN0_PUEN_DU_DR2); pfc_reg_write(PFC_PUEN1, PUEN1_PUEN_VI1_DATA11 | PUEN1_PUEN_VI1_DATA10 | PUEN1_PUEN_VI1_DATA9 | PUEN1_PUEN_VI1_DATA8 | PUEN1_PUEN_VI1_DATA7 | PUEN1_PUEN_VI1_DATA6 | PUEN1_PUEN_VI1_DATA5 | PUEN1_PUEN_VI1_DATA4 | PUEN1_PUEN_VI1_DATA3 | PUEN1_PUEN_VI1_DATA2 | PUEN1_PUEN_VI1_DATA1 | PUEN1_PUEN_VI1_DATA0 | PUEN1_PUEN_VI1_VSYNC_N | PUEN1_PUEN_VI1_HSYNC_N | PUEN1_PUEN_VI1_CLKENB | PUEN1_PUEN_VI1_CLK | PUEN1_PUEN_VI0_DATA11 | PUEN1_PUEN_VI0_DATA10 | PUEN1_PUEN_VI0_DATA9 | PUEN1_PUEN_VI0_DATA8 | PUEN1_PUEN_VI0_DATA7 | PUEN1_PUEN_VI0_DATA6 | PUEN1_PUEN_VI0_DATA5 | PUEN1_PUEN_VI0_DATA4 | PUEN1_PUEN_VI0_DATA3 | PUEN1_PUEN_VI0_DATA2 | PUEN1_PUEN_VI0_DATA1); pfc_reg_write(PFC_PUEN2, PUEN2_PUEN_CANFD_CLK | PUEN2_PUEN_CANFD1_RX | PUEN2_PUEN_CANFD1_TX | PUEN2_PUEN_CANFD0_RX | PUEN2_PUEN_CANFD0_TX | PUEN2_PUEN_AVB0_AVTP_CAPTURE | PUEN2_PUEN_AVB0_AVTP_MATCH | PUEN2_PUEN_AVB0_LINK | PUEN2_PUEN_AVB0_PHY_INT | PUEN2_PUEN_AVB0_MAGIC | PUEN2_PUEN_AVB0_TXCREFCLK | PUEN2_PUEN_AVB0_TD3 | PUEN2_PUEN_AVB0_TD2 | PUEN2_PUEN_AVB0_TD1 | PUEN2_PUEN_AVB0_TD0 | PUEN2_PUEN_AVB0_TXC | PUEN2_PUEN_AVB0_TX_CTL | PUEN2_PUEN_AVB0_RD3 | PUEN2_PUEN_AVB0_RD2 | PUEN2_PUEN_AVB0_RD1 | PUEN2_PUEN_AVB0_RD0 | PUEN2_PUEN_AVB0_RXC | PUEN2_PUEN_AVB0_RX_CTL | PUEN2_PUEN_VI1_FIELD); pfc_reg_write(PFC_PUEN3, PUEN3_PUEN_DIGRF_CLKOUT | PUEN3_PUEN_DIGRF_CLKIN); /* initialize PUD Control */ pfc_reg_write(PFC_PUD0, PUD0_PUD_VI0_CLK | PUD0_PUD_IRQ0 | PUD0_PUD_FSCLKST_N | PUD0_PUD_DU_EXODDF_DU_ODDF_DISP_CDE | PUD0_PUD_DU_EXVSYNC_DU_VSYNC | PUD0_PUD_DU_EXHSYNC_DU_HSYNC | PUD0_PUD_DU_DOTCLKOUT | PUD0_PUD_DU_DB7 | PUD0_PUD_DU_DB6 | PUD0_PUD_DU_DB5 | PUD0_PUD_DU_DB4 | PUD0_PUD_DU_DB3 | PUD0_PUD_DU_DB2 | PUD0_PUD_DU_DG7 | PUD0_PUD_DU_DG6 | PUD0_PUD_DU_DG5 | PUD0_PUD_DU_DG4 | PUD0_PUD_DU_DG3 | PUD0_PUD_DU_DG2 | PUD0_PUD_DU_DR7 | PUD0_PUD_DU_DR6 | PUD0_PUD_DU_DR5 | PUD0_PUD_DU_DR4 | PUD0_PUD_DU_DR3 | PUD0_PUD_DU_DR2); pfc_reg_write(PFC_PUD1, PUD1_PUD_VI1_DATA11 | PUD1_PUD_VI1_DATA10 | PUD1_PUD_VI1_DATA9 | PUD1_PUD_VI1_DATA8 | PUD1_PUD_VI1_DATA7 | PUD1_PUD_VI1_DATA6 | PUD1_PUD_VI1_DATA5 | PUD1_PUD_VI1_DATA4 | PUD1_PUD_VI1_DATA3 | PUD1_PUD_VI1_DATA2 | PUD1_PUD_VI1_DATA1 | PUD1_PUD_VI1_DATA0 | PUD1_PUD_VI1_VSYNC_N | PUD1_PUD_VI1_HSYNC_N | PUD1_PUD_VI1_CLKENB | PUD1_PUD_VI1_CLK | PUD1_PUD_VI0_DATA11 | PUD1_PUD_VI0_DATA10 | PUD1_PUD_VI0_DATA9 | PUD1_PUD_VI0_DATA8 | PUD1_PUD_VI0_DATA7 | PUD1_PUD_VI0_DATA6 | PUD1_PUD_VI0_DATA5 | PUD1_PUD_VI0_DATA4 | PUD1_PUD_VI0_DATA3 | PUD1_PUD_VI0_DATA2 | PUD1_PUD_VI0_DATA1 | PUD1_PUD_VI0_DATA0 | PUD1_PUD_VI0_VSYNC_N | PUD1_PUD_VI0_HSYNC_N | PUD1_PUD_VI0_CLKENB); pfc_reg_write(PFC_PUD2, PUD2_PUD_CANFD_CLK | PUD2_PUD_CANFD1_RX | PUD2_PUD_CANFD1_TX | PUD2_PUD_CANFD0_RX | PUD2_PUD_CANFD0_TX | PUD2_PUD_AVB0_AVTP_CAPTURE | PUD2_PUD_VI1_FIELD); pfc_reg_write(PFC_PUD3, PUD3_PUD_DIGRF_CLKOUT | PUD3_PUD_DIGRF_CLKIN); /* initialize Module Select */ pfc_reg_write(PFC_MOD_SEL0, 0x00000000); // gpio /* initialize positive/negative logic select */ mmio_write_32(GPIO_POSNEG0, 0x00000000U); mmio_write_32(GPIO_POSNEG1, 0x00000000U); mmio_write_32(GPIO_POSNEG2, 0x00000000U); mmio_write_32(GPIO_POSNEG3, 0x00000000U); mmio_write_32(GPIO_POSNEG4, 0x00000000U); mmio_write_32(GPIO_POSNEG5, 0x00000000U); /* initialize general IO/interrupt switching */ mmio_write_32(GPIO_IOINTSEL0, 0x00000000U); mmio_write_32(GPIO_IOINTSEL1, 0x00000000U); mmio_write_32(GPIO_IOINTSEL2, 0x00000000U); mmio_write_32(GPIO_IOINTSEL3, 0x00000000U); mmio_write_32(GPIO_IOINTSEL4, 0x00000000U); mmio_write_32(GPIO_IOINTSEL5, 0x00000000U); /* initialize general output register */ mmio_write_32(GPIO_OUTDT0, 0x00000000U); mmio_write_32(GPIO_OUTDT1, 0x00000000U); mmio_write_32(GPIO_OUTDT2, 0x00000000U); mmio_write_32(GPIO_OUTDT3, 0x00000000U); mmio_write_32(GPIO_OUTDT4, 0x00000000U); mmio_write_32(GPIO_OUTDT5, 0x00000000U); /* initialize general input/output switching */ mmio_write_32(GPIO_INOUTSEL0, 0x00000000U); mmio_write_32(GPIO_INOUTSEL1, 0x00000000U); mmio_write_32(GPIO_INOUTSEL2, 0x00000000U); mmio_write_32(GPIO_INOUTSEL3, 0x00000000U); mmio_write_32(GPIO_INOUTSEL4, 0x00000000U); mmio_write_32(GPIO_INOUTSEL5, 0x00000000U); } trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.h000066400000000000000000000003551355360272700250670ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PFC_INIT_V3M_H #define PFC_INIT_V3M_H void pfc_init_v3m(void); #endif /* PFC_INIT_V3M_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/pfc.mk000066400000000000000000000045041355360272700230320ustar00rootroot00000000000000# # Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ifeq (${RCAR_LSI},${RCAR_AUTO}) BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c BL2_SOURCES += drivers/renesas/rcar/pfc/M3/pfc_init_m3.c BL2_SOURCES += drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.c BL2_SOURCES += drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c else ifdef RCAR_LSI_CUT_COMPAT ifeq (${RCAR_LSI},${RCAR_H3}) BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c endif ifeq (${RCAR_LSI},${RCAR_H3N}) BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c endif ifeq (${RCAR_LSI},${RCAR_M3}) BL2_SOURCES += drivers/renesas/rcar/pfc/M3/pfc_init_m3.c endif ifeq (${RCAR_LSI},${RCAR_M3N}) BL2_SOURCES += drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.c endif ifeq (${RCAR_LSI},${RCAR_V3M}) BL2_SOURCES += drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c endif ifeq (${RCAR_LSI},${RCAR_E3}) BL2_SOURCES += drivers/renesas/rcar/pfc/E3/pfc_init_e3.c endif ifeq (${RCAR_LSI},${RCAR_D3}) BL2_SOURCES += drivers/renesas/rcar/pfc/D3/pfc_init_d3.c endif else ifeq (${RCAR_LSI},${RCAR_H3}) ifeq (${LSI_CUT},10) BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c else ifeq (${LSI_CUT},11) BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v1.c else # LSI_CUT 20 or later BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c endif endif ifeq (${RCAR_LSI},${RCAR_H3N}) BL2_SOURCES += drivers/renesas/rcar/pfc/H3/pfc_init_h3_v2.c endif ifeq (${RCAR_LSI},${RCAR_M3}) BL2_SOURCES += drivers/renesas/rcar/pfc/M3/pfc_init_m3.c endif ifeq (${RCAR_LSI},${RCAR_M3N}) BL2_SOURCES += drivers/renesas/rcar/pfc/M3N/pfc_init_m3n.c endif ifeq (${RCAR_LSI},${RCAR_V3M}) BL2_SOURCES += drivers/renesas/rcar/pfc/V3M/pfc_init_v3m.c endif ifeq (${RCAR_LSI},${RCAR_E3}) BL2_SOURCES += drivers/renesas/rcar/pfc/E3/pfc_init_e3.c endif ifeq (${RCAR_LSI},${RCAR_D3}) BL2_SOURCES += drivers/renesas/rcar/pfc/D3/pfc_init_d3.c endif endif BL2_SOURCES += drivers/renesas/rcar/pfc/pfc_init.c trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/pfc_init.c000066400000000000000000000100711355360272700236640ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "rcar_def.h" #if RCAR_LSI == RCAR_AUTO #include "H3/pfc_init_h3_v1.h" #include "H3/pfc_init_h3_v2.h" #include "M3/pfc_init_m3.h" #include "M3N/pfc_init_m3n.h" #include "V3M/pfc_init_v3m.h" #endif #if (RCAR_LSI == RCAR_H3) || (RCAR_LSI == RCAR_H3N) /* H3 */ #include "H3/pfc_init_h3_v1.h" #include "H3/pfc_init_h3_v2.h" #endif #if RCAR_LSI == RCAR_M3 /* M3 */ #include "M3/pfc_init_m3.h" #endif #if RCAR_LSI == RCAR_M3N /* M3N */ #include "M3N/pfc_init_m3n.h" #endif #if RCAR_LSI == RCAR_V3M /* V3M */ #include "V3M/pfc_init_v3m.h" #endif #if RCAR_LSI == RCAR_E3 /* E3 */ #include "E3/pfc_init_e3.h" #endif #if RCAR_LSI == RCAR_D3 /* D3 */ #include "D3/pfc_init_d3.h" #endif #define PRR_PRODUCT_ERR(reg) \ do { \ ERROR("LSI Product ID(PRR=0x%x) PFC initialize not supported.\n", \ reg); \ panic(); \ } while (0) #define PRR_CUT_ERR(reg) \ do { \ ERROR("LSI Cut ID(PRR=0x%x) PFC initialize not supported.\n", \ reg); \ panic();\ } while (0) void rcar_pfc_init(void) { uint32_t reg; reg = mmio_read_32(RCAR_PRR); #if RCAR_LSI == RCAR_AUTO switch (reg & PRR_PRODUCT_MASK) { case PRR_PRODUCT_H3: switch (reg & PRR_CUT_MASK) { case PRR_PRODUCT_10: /* H3 Ver.1.0 */ pfc_init_h3_v1(); break; case PRR_PRODUCT_11: /* H3 Ver.1.1 */ pfc_init_h3_v1(); break; default: /* H3 Ver.2.0 or later */ pfc_init_h3_v2(); break; } break; case PRR_PRODUCT_M3: pfc_init_m3(); break; case PRR_PRODUCT_M3N: pfc_init_m3n(); break; case PRR_PRODUCT_V3M: pfc_init_v3m(); break; default: PRR_PRODUCT_ERR(reg); break; } #elif RCAR_LSI_CUT_COMPAT switch (reg & PRR_PRODUCT_MASK) { case PRR_PRODUCT_H3: #if (RCAR_LSI != RCAR_H3) && (RCAR_LSI != RCAR_H3N) PRR_PRODUCT_ERR(reg); #else switch (reg & PRR_CUT_MASK) { case PRR_PRODUCT_10: /* H3 Ver.1.0 */ pfc_init_h3_v1(); break; case PRR_PRODUCT_11: /* H3 Ver.1.1 */ pfc_init_h3_v1(); break; default: /* H3 Ver.2.0 or later */ pfc_init_h3_v2(); break; } #endif break; case PRR_PRODUCT_M3: #if RCAR_LSI != RCAR_M3 PRR_PRODUCT_ERR(reg); #else pfc_init_m3(); #endif break; case PRR_PRODUCT_M3N: #if RCAR_LSI != RCAR_M3N PRR_PRODUCT_ERR(reg); #else pfc_init_m3n(); #endif break; case PRR_PRODUCT_V3M: #if RCAR_LSI != RCAR_V3M PRR_PRODUCT_ERR(reg); #else pfc_init_v3m(); #endif break; case PRR_PRODUCT_E3: #if RCAR_LSI != RCAR_E3 PRR_PRODUCT_ERR(reg); #else pfc_init_e3(); #endif break; case PRR_PRODUCT_D3: #if RCAR_LSI != RCAR_D3 PRR_PRODUCT_ERR(reg); #else pfc_init_d3(); #endif break; default: PRR_PRODUCT_ERR(reg); break; } #else #if (RCAR_LSI == RCAR_H3) || (RCAR_LSI == RCAR_H3N) /* H3 */ #if RCAR_LSI_CUT == RCAR_CUT_10 /* H3 Ver.1.0 */ if ((PRR_PRODUCT_H3 | PRR_PRODUCT_10) != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) { PRR_PRODUCT_ERR(reg); } pfc_init_h3_v1(); #elif RCAR_LSI_CUT == RCAR_CUT_11 /* H3 Ver.1.1 */ if ((PRR_PRODUCT_H3 | PRR_PRODUCT_11) != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) { PRR_PRODUCT_ERR(reg); } pfc_init_h3_v1(); #else /* H3 Ver.2.0 or later */ if (PRR_PRODUCT_H3 != (reg & PRR_PRODUCT_MASK)) { PRR_PRODUCT_ERR(reg); } pfc_init_h3_v2(); #endif #elif RCAR_LSI == RCAR_M3 /* M3 */ if ((PRR_PRODUCT_M3) != (reg & PRR_PRODUCT_MASK)) { PRR_PRODUCT_ERR(reg); } pfc_init_m3(); #elif RCAR_LSI == RCAR_M3N /* M3N */ if ((PRR_PRODUCT_M3N) != (reg & PRR_PRODUCT_MASK)) { PRR_PRODUCT_ERR(reg); } pfc_init_m3n(); #elif RCAR_LSI == RCAR_V3M /* V3M */ if ((PRR_PRODUCT_V3M) != (reg & PRR_PRODUCT_MASK)) { PRR_PRODUCT_ERR(reg); } pfc_init_v3m(); #elif RCAR_LSI == RCAR_E3 /* E3 */ if ((PRR_PRODUCT_E3) != (reg & PRR_PRODUCT_MASK)) { PRR_PRODUCT_ERR(reg); } pfc_init_e3(); #elif RCAR_LSI == RCAR_D3 /* D3 */ if ((PRR_PRODUCT_D3) != (reg & PRR_PRODUCT_MASK)) { PRR_PRODUCT_ERR(reg); } pfc_init_d3(); #else #error "Don't have PFC initialize routine(unknown)." #endif #endif } trusted-firmware-a-2.2/drivers/renesas/rcar/pfc/pfc_regs.h000066400000000000000000000225121355360272700236710ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PFC_REGS_H #define PFC_REGS_H /* GPIO base address */ #define GPIO_BASE (0xE6050000U) /* GPIO registers */ #define GPIO_IOINTSEL0 (GPIO_BASE + 0x0000U) #define GPIO_INOUTSEL0 (GPIO_BASE + 0x0004U) #define GPIO_OUTDT0 (GPIO_BASE + 0x0008U) #define GPIO_INDT0 (GPIO_BASE + 0x000CU) #define GPIO_INTDT0 (GPIO_BASE + 0x0010U) #define GPIO_INTCLR0 (GPIO_BASE + 0x0014U) #define GPIO_INTMSK0 (GPIO_BASE + 0x0018U) #define GPIO_MSKCLR0 (GPIO_BASE + 0x001CU) #define GPIO_POSNEG0 (GPIO_BASE + 0x0020U) #define GPIO_EDGLEVEL0 (GPIO_BASE + 0x0024U) #define GPIO_FILONOFF0 (GPIO_BASE + 0x0028U) #define GPIO_INTMSKS0 (GPIO_BASE + 0x0038U) #define GPIO_MSKCLRS0 (GPIO_BASE + 0x003CU) #define GPIO_OUTDTSEL0 (GPIO_BASE + 0x0040U) #define GPIO_OUTDTH0 (GPIO_BASE + 0x0044U) #define GPIO_OUTDTL0 (GPIO_BASE + 0x0048U) #define GPIO_BOTHEDGE0 (GPIO_BASE + 0x004CU) #define GPIO_IOINTSEL1 (GPIO_BASE + 0x1000U) #define GPIO_INOUTSEL1 (GPIO_BASE + 0x1004U) #define GPIO_OUTDT1 (GPIO_BASE + 0x1008U) #define GPIO_INDT1 (GPIO_BASE + 0x100CU) #define GPIO_INTDT1 (GPIO_BASE + 0x1010U) #define GPIO_INTCLR1 (GPIO_BASE + 0x1014U) #define GPIO_INTMSK1 (GPIO_BASE + 0x1018U) #define GPIO_MSKCLR1 (GPIO_BASE + 0x101CU) #define GPIO_POSNEG1 (GPIO_BASE + 0x1020U) #define GPIO_EDGLEVEL1 (GPIO_BASE + 0x1024U) #define GPIO_FILONOFF1 (GPIO_BASE + 0x1028U) #define GPIO_INTMSKS1 (GPIO_BASE + 0x1038U) #define GPIO_MSKCLRS1 (GPIO_BASE + 0x103CU) #define GPIO_OUTDTSEL1 (GPIO_BASE + 0x1040U) #define GPIO_OUTDTH1 (GPIO_BASE + 0x1044U) #define GPIO_OUTDTL1 (GPIO_BASE + 0x1048U) #define GPIO_BOTHEDGE1 (GPIO_BASE + 0x104CU) #define GPIO_IOINTSEL2 (GPIO_BASE + 0x2000U) #define GPIO_INOUTSEL2 (GPIO_BASE + 0x2004U) #define GPIO_OUTDT2 (GPIO_BASE + 0x2008U) #define GPIO_INDT2 (GPIO_BASE + 0x200CU) #define GPIO_INTDT2 (GPIO_BASE + 0x2010U) #define GPIO_INTCLR2 (GPIO_BASE + 0x2014U) #define GPIO_INTMSK2 (GPIO_BASE + 0x2018U) #define GPIO_MSKCLR2 (GPIO_BASE + 0x201CU) #define GPIO_POSNEG2 (GPIO_BASE + 0x2020U) #define GPIO_EDGLEVEL2 (GPIO_BASE + 0x2024U) #define GPIO_FILONOFF2 (GPIO_BASE + 0x2028U) #define GPIO_INTMSKS2 (GPIO_BASE + 0x2038U) #define GPIO_MSKCLRS2 (GPIO_BASE + 0x203CU) #define GPIO_OUTDTSEL2 (GPIO_BASE + 0x2040U) #define GPIO_OUTDTH2 (GPIO_BASE + 0x2044U) #define GPIO_OUTDTL2 (GPIO_BASE + 0x2048U) #define GPIO_BOTHEDGE2 (GPIO_BASE + 0x204CU) #define GPIO_IOINTSEL3 (GPIO_BASE + 0x3000U) #define GPIO_INOUTSEL3 (GPIO_BASE + 0x3004U) #define GPIO_OUTDT3 (GPIO_BASE + 0x3008U) #define GPIO_INDT3 (GPIO_BASE + 0x300CU) #define GPIO_INTDT3 (GPIO_BASE + 0x3010U) #define GPIO_INTCLR3 (GPIO_BASE + 0x3014U) #define GPIO_INTMSK3 (GPIO_BASE + 0x3018U) #define GPIO_MSKCLR3 (GPIO_BASE + 0x301CU) #define GPIO_POSNEG3 (GPIO_BASE + 0x3020U) #define GPIO_EDGLEVEL3 (GPIO_BASE + 0x3024U) #define GPIO_FILONOFF3 (GPIO_BASE + 0x3028U) #define GPIO_INTMSKS3 (GPIO_BASE + 0x3038U) #define GPIO_MSKCLRS3 (GPIO_BASE + 0x303CU) #define GPIO_OUTDTSEL3 (GPIO_BASE + 0x3040U) #define GPIO_OUTDTH3 (GPIO_BASE + 0x3044U) #define GPIO_OUTDTL3 (GPIO_BASE + 0x3048U) #define GPIO_BOTHEDGE3 (GPIO_BASE + 0x304CU) #define GPIO_IOINTSEL4 (GPIO_BASE + 0x4000U) #define GPIO_INOUTSEL4 (GPIO_BASE + 0x4004U) #define GPIO_OUTDT4 (GPIO_BASE + 0x4008U) #define GPIO_INDT4 (GPIO_BASE + 0x400CU) #define GPIO_INTDT4 (GPIO_BASE + 0x4010U) #define GPIO_INTCLR4 (GPIO_BASE + 0x4014U) #define GPIO_INTMSK4 (GPIO_BASE + 0x4018U) #define GPIO_MSKCLR4 (GPIO_BASE + 0x401CU) #define GPIO_POSNEG4 (GPIO_BASE + 0x4020U) #define GPIO_EDGLEVEL4 (GPIO_BASE + 0x4024U) #define GPIO_FILONOFF4 (GPIO_BASE + 0x4028U) #define GPIO_INTMSKS4 (GPIO_BASE + 0x4038U) #define GPIO_MSKCLRS4 (GPIO_BASE + 0x403CU) #define GPIO_OUTDTSEL4 (GPIO_BASE + 0x4040U) #define GPIO_OUTDTH4 (GPIO_BASE + 0x4044U) #define GPIO_OUTDTL4 (GPIO_BASE + 0x4048U) #define GPIO_BOTHEDGE4 (GPIO_BASE + 0x404CU) #define GPIO_IOINTSEL5 (GPIO_BASE + 0x5000U) #define GPIO_INOUTSEL5 (GPIO_BASE + 0x5004U) #define GPIO_OUTDT5 (GPIO_BASE + 0x5008U) #define GPIO_INDT5 (GPIO_BASE + 0x500CU) #define GPIO_INTDT5 (GPIO_BASE + 0x5010U) #define GPIO_INTCLR5 (GPIO_BASE + 0x5014U) #define GPIO_INTMSK5 (GPIO_BASE + 0x5018U) #define GPIO_MSKCLR5 (GPIO_BASE + 0x501CU) #define GPIO_POSNEG5 (GPIO_BASE + 0x5020U) #define GPIO_EDGLEVEL5 (GPIO_BASE + 0x5024U) #define GPIO_FILONOFF5 (GPIO_BASE + 0x5028U) #define GPIO_INTMSKS5 (GPIO_BASE + 0x5038U) #define GPIO_MSKCLRS5 (GPIO_BASE + 0x503CU) #define GPIO_OUTDTSEL5 (GPIO_BASE + 0x5040U) #define GPIO_OUTDTH5 (GPIO_BASE + 0x5044U) #define GPIO_OUTDTL5 (GPIO_BASE + 0x5048U) #define GPIO_BOTHEDGE5 (GPIO_BASE + 0x504CU) #define GPIO_IOINTSEL6 (GPIO_BASE + 0x5400U) #define GPIO_INOUTSEL6 (GPIO_BASE + 0x5404U) #define GPIO_OUTDT6 (GPIO_BASE + 0x5408U) #define GPIO_INTDT6 (GPIO_BASE + 0x5410U) #define GPIO_INTCLR6 (GPIO_BASE + 0x5414U) #define GPIO_INTMSK6 (GPIO_BASE + 0x5418U) #define GPIO_MSKCLR6 (GPIO_BASE + 0x541CU) #define GPIO_POSNEG6 (GPIO_BASE + 0x5420U) #define GPIO_EDGLEVEL6 (GPIO_BASE + 0x5424U) #define GPIO_FILONOFF6 (GPIO_BASE + 0x5428U) #define GPIO_INTMSKS6 (GPIO_BASE + 0x5438U) #define GPIO_MSKCLRS6 (GPIO_BASE + 0x543CU) #define GPIO_OUTDTSEL6 (GPIO_BASE + 0x5440U) #define GPIO_OUTDTH6 (GPIO_BASE + 0x5444U) #define GPIO_OUTDTL6 (GPIO_BASE + 0x5448U) #define GPIO_BOTHEDGE6 (GPIO_BASE + 0x544CU) #define GPIO_IOINTSEL7 (GPIO_BASE + 0x5800U) #define GPIO_INOUTSEL7 (GPIO_BASE + 0x5804U) #define GPIO_OUTDT7 (GPIO_BASE + 0x5808U) #define GPIO_INDT7 (GPIO_BASE + 0x580CU) #define GPIO_INTDT7 (GPIO_BASE + 0x5810U) #define GPIO_INTCLR7 (GPIO_BASE + 0x5814U) #define GPIO_INTMSK7 (GPIO_BASE + 0x5818U) #define GPIO_MSKCLR7 (GPIO_BASE + 0x581CU) #define GPIO_POSNEG7 (GPIO_BASE + 0x5820U) #define GPIO_EDGLEVEL7 (GPIO_BASE + 0x5824U) #define GPIO_FILONOFF7 (GPIO_BASE + 0x5828U) #define GPIO_INTMSKS7 (GPIO_BASE + 0x5838U) #define GPIO_MSKCLRS7 (GPIO_BASE + 0x583CU) #define GPIO_OUTDTSEL7 (GPIO_BASE + 0x5840U) #define GPIO_OUTDTH7 (GPIO_BASE + 0x5844U) #define GPIO_OUTDTL7 (GPIO_BASE + 0x5848U) #define GPIO_BOTHEDGE7 (GPIO_BASE + 0x584CU) /* Pin functon base address */ #define PFC_BASE (0xE6060000U) /* Pin functon registers */ #define PFC_PMMR (PFC_BASE + 0x0000U) #define PFC_GPSR0 (PFC_BASE + 0x0100U) #define PFC_GPSR1 (PFC_BASE + 0x0104U) #define PFC_GPSR2 (PFC_BASE + 0x0108U) #define PFC_GPSR3 (PFC_BASE + 0x010CU) #define PFC_GPSR4 (PFC_BASE + 0x0110U) #define PFC_GPSR5 (PFC_BASE + 0x0114U) #define PFC_GPSR6 (PFC_BASE + 0x0118U) #define PFC_GPSR7 (PFC_BASE + 0x011CU) #define PFC_IPSR0 (PFC_BASE + 0x0200U) #define PFC_IPSR1 (PFC_BASE + 0x0204U) #define PFC_IPSR2 (PFC_BASE + 0x0208U) #define PFC_IPSR3 (PFC_BASE + 0x020CU) #define PFC_IPSR4 (PFC_BASE + 0x0210U) #define PFC_IPSR5 (PFC_BASE + 0x0214U) #define PFC_IPSR6 (PFC_BASE + 0x0218U) #define PFC_IPSR7 (PFC_BASE + 0x021CU) #define PFC_IPSR8 (PFC_BASE + 0x0220U) #define PFC_IPSR9 (PFC_BASE + 0x0224U) #define PFC_IPSR10 (PFC_BASE + 0x0228U) #define PFC_IPSR11 (PFC_BASE + 0x022CU) #define PFC_IPSR12 (PFC_BASE + 0x0230U) #define PFC_IPSR13 (PFC_BASE + 0x0234U) #define PFC_IPSR14 (PFC_BASE + 0x0238U) #define PFC_IPSR15 (PFC_BASE + 0x023CU) #define PFC_IPSR16 (PFC_BASE + 0x0240U) #define PFC_IPSR17 (PFC_BASE + 0x0244U) #define PFC_IPSR18 (PFC_BASE + 0x0248U) #define PFC_DRVCTRL0 (PFC_BASE + 0x0300U) #define PFC_DRVCTRL1 (PFC_BASE + 0x0304U) #define PFC_DRVCTRL2 (PFC_BASE + 0x0308U) #define PFC_DRVCTRL3 (PFC_BASE + 0x030CU) #define PFC_DRVCTRL4 (PFC_BASE + 0x0310U) #define PFC_DRVCTRL5 (PFC_BASE + 0x0314U) #define PFC_DRVCTRL6 (PFC_BASE + 0x0318U) #define PFC_DRVCTRL7 (PFC_BASE + 0x031CU) #define PFC_DRVCTRL8 (PFC_BASE + 0x0320U) #define PFC_DRVCTRL9 (PFC_BASE + 0x0324U) #define PFC_DRVCTRL10 (PFC_BASE + 0x0328U) #define PFC_DRVCTRL11 (PFC_BASE + 0x032CU) #define PFC_DRVCTRL12 (PFC_BASE + 0x0330U) #define PFC_DRVCTRL13 (PFC_BASE + 0x0334U) #define PFC_DRVCTRL14 (PFC_BASE + 0x0338U) #define PFC_DRVCTRL15 (PFC_BASE + 0x033CU) #define PFC_DRVCTRL16 (PFC_BASE + 0x0340U) #define PFC_DRVCTRL17 (PFC_BASE + 0x0344U) #define PFC_DRVCTRL18 (PFC_BASE + 0x0348U) #define PFC_DRVCTRL19 (PFC_BASE + 0x034CU) #define PFC_DRVCTRL20 (PFC_BASE + 0x0350U) #define PFC_DRVCTRL21 (PFC_BASE + 0x0354U) #define PFC_DRVCTRL22 (PFC_BASE + 0x0358U) #define PFC_DRVCTRL23 (PFC_BASE + 0x035CU) #define PFC_DRVCTRL24 (PFC_BASE + 0x0360U) #define PFC_POCCTRL0 (PFC_BASE + 0x0380U) #define PFC_IOCTRL31 (PFC_BASE + 0x0384U) #define PFC_POCCTRL2 (PFC_BASE + 0x0388U) #define PFC_TDSELCTRL0 (PFC_BASE + 0x03C0U) #define PFC_IOCTRL (PFC_BASE + 0x03E0U) #define PFC_TSREG (PFC_BASE + 0x03E4U) #define PFC_PUEN0 (PFC_BASE + 0x0400U) #define PFC_PUEN1 (PFC_BASE + 0x0404U) #define PFC_PUEN2 (PFC_BASE + 0x0408U) #define PFC_PUEN3 (PFC_BASE + 0x040CU) #define PFC_PUEN4 (PFC_BASE + 0x0410U) #define PFC_PUEN5 (PFC_BASE + 0x0414U) #define PFC_PUEN6 (PFC_BASE + 0x0418U) #define PFC_PUD0 (PFC_BASE + 0x0440U) #define PFC_PUD1 (PFC_BASE + 0x0444U) #define PFC_PUD2 (PFC_BASE + 0x0448U) #define PFC_PUD3 (PFC_BASE + 0x044CU) #define PFC_PUD4 (PFC_BASE + 0x0450U) #define PFC_PUD5 (PFC_BASE + 0x0454U) #define PFC_PUD6 (PFC_BASE + 0x0458U) #define PFC_MOD_SEL0 (PFC_BASE + 0x0500U) #define PFC_MOD_SEL1 (PFC_BASE + 0x0504U) #define PFC_MOD_SEL2 (PFC_BASE + 0x0508U) #endif /* PFC_REGS_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/pwrc/000077500000000000000000000000001355360272700221315ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/pwrc/call_sram.S000066400000000000000000000013701355360272700242130ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .global rcar_pwrc_switch_stack /* * x0 : jump address, * x1 : stack address, * x2 : arg, * x3 : stack address (temporary) */ func rcar_pwrc_switch_stack /* lr to stack */ stp x29, x30, [sp,#-16] /* change stack pointer */ mov x3, sp mov sp, x1 /* save stack pointer */ sub sp, sp, #16 stp x0, x3, [sp] /* data synchronization barrier */ dsb sy /* jump to code */ mov x1, x0 mov x0, x2 blr x1 /* load stack pointer */ ldp x0, x2, [sp,#0] /* change stack pointer */ mov sp, x2 /* return */ ldp x29, x30, [sp,#-16] ret endfunc rcar_pwrc_switch_stack trusted-firmware-a-2.2/drivers/renesas/rcar/pwrc/pwrc.c000066400000000000000000000575451355360272700232700ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "iic_dvfs.h" #include "rcar_def.h" #include "rcar_private.h" #include "micro_delay.h" #include "pwrc.h" /* * Someday there will be a generic power controller api. At the moment each * platform has its own pwrc so just exporting functions should be acceptable. */ RCAR_INSTANTIATE_LOCK #define WUP_IRQ_SHIFT (0U) #define WUP_FIQ_SHIFT (8U) #define WUP_CSD_SHIFT (16U) #define BIT_SOFTRESET (1U<<15) #define BIT_CA53_SCU (1U<<21) #define BIT_CA57_SCU (1U<<12) #define REQ_RESUME (1U<<1) #define REQ_OFF (1U<<0) #define STATUS_PWRUP (1U<<4) #define STATUS_PWRDOWN (1U<<0) #define STATE_CA57_CPU (27U) #define STATE_CA53_CPU (22U) #define MODE_L2_DOWN (0x00000002U) #define CPU_PWR_OFF (0x00000003U) #define RCAR_PSTR_MASK (0x00000003U) #define ST_ALL_STANDBY (0x00003333U) /* Suspend to ram */ #define DBSC4_REG_BASE (0xE6790000U) #define DBSC4_REG_DBSYSCNT0 (DBSC4_REG_BASE + 0x0100U) #define DBSC4_REG_DBACEN (DBSC4_REG_BASE + 0x0200U) #define DBSC4_REG_DBCMD (DBSC4_REG_BASE + 0x0208U) #define DBSC4_REG_DBRFEN (DBSC4_REG_BASE + 0x0204U) #define DBSC4_REG_DBWAIT (DBSC4_REG_BASE + 0x0210U) #define DBSC4_REG_DBCALCNF (DBSC4_REG_BASE + 0x0424U) #define DBSC4_REG_DBDFIPMSTRCNF (DBSC4_REG_BASE + 0x0520U) #define DBSC4_REG_DBPDLK0 (DBSC4_REG_BASE + 0x0620U) #define DBSC4_REG_DBPDRGA0 (DBSC4_REG_BASE + 0x0624U) #define DBSC4_REG_DBPDRGD0 (DBSC4_REG_BASE + 0x0628U) #define DBSC4_REG_DBCAM0CTRL0 (DBSC4_REG_BASE + 0x0940U) #define DBSC4_REG_DBCAM0STAT0 (DBSC4_REG_BASE + 0x0980U) #define DBSC4_REG_DBCAM1STAT0 (DBSC4_REG_BASE + 0x0990U) #define DBSC4_REG_DBCAM2STAT0 (DBSC4_REG_BASE + 0x09A0U) #define DBSC4_REG_DBCAM3STAT0 (DBSC4_REG_BASE + 0x09B0U) #define DBSC4_BIT_DBACEN_ACCEN ((uint32_t)(1U << 0)) #define DBSC4_BIT_DBRFEN_ARFEN ((uint32_t)(1U << 0)) #define DBSC4_BIT_DBCAMxSTAT0 (0x00000001U) #define DBSC4_BIT_DBDFIPMSTRCNF_PMSTREN (0x00000001U) #define DBSC4_SET_DBCMD_OPC_PRE (0x04000000U) #define DBSC4_SET_DBCMD_OPC_SR (0x0A000000U) #define DBSC4_SET_DBCMD_OPC_PD (0x08000000U) #define DBSC4_SET_DBCMD_OPC_MRW (0x0E000000U) #define DBSC4_SET_DBCMD_CH_ALL (0x00800000U) #define DBSC4_SET_DBCMD_RANK_ALL (0x00040000U) #define DBSC4_SET_DBCMD_ARG_ALL (0x00000010U) #define DBSC4_SET_DBCMD_ARG_ENTER (0x00000000U) #define DBSC4_SET_DBCMD_ARG_MRW_ODTC (0x00000B00U) #define DBSC4_SET_DBSYSCNT0_WRITE_ENABLE (0x00001234U) #define DBSC4_SET_DBSYSCNT0_WRITE_DISABLE (0x00000000U) #define DBSC4_SET_DBPDLK0_PHY_ACCESS (0x0000A55AU) #define DBSC4_SET_DBPDRGA0_ACIOCR0 (0x0000001AU) #define DBSC4_SET_DBPDRGD0_ACIOCR0 (0x33C03C11U) #define DBSC4_SET_DBPDRGA0_DXCCR (0x00000020U) #define DBSC4_SET_DBPDRGD0_DXCCR (0x00181006U) #define DBSC4_SET_DBPDRGA0_PGCR1 (0x00000003U) #define DBSC4_SET_DBPDRGD0_PGCR1 (0x0380C600U) #define DBSC4_SET_DBPDRGA0_ACIOCR1 (0x0000001BU) #define DBSC4_SET_DBPDRGD0_ACIOCR1 (0xAAAAAAAAU) #define DBSC4_SET_DBPDRGA0_ACIOCR3 (0x0000001DU) #define DBSC4_SET_DBPDRGD0_ACIOCR3 (0xAAAAAAAAU) #define DBSC4_SET_DBPDRGA0_ACIOCR5 (0x0000001FU) #define DBSC4_SET_DBPDRGD0_ACIOCR5 (0x000000AAU) #define DBSC4_SET_DBPDRGA0_DX0GCR2 (0x000000A2U) #define DBSC4_SET_DBPDRGD0_DX0GCR2 (0xAAAA0000U) #define DBSC4_SET_DBPDRGA0_DX1GCR2 (0x000000C2U) #define DBSC4_SET_DBPDRGD0_DX1GCR2 (0xAAAA0000U) #define DBSC4_SET_DBPDRGA0_DX2GCR2 (0x000000E2U) #define DBSC4_SET_DBPDRGD0_DX2GCR2 (0xAAAA0000U) #define DBSC4_SET_DBPDRGA0_DX3GCR2 (0x00000102U) #define DBSC4_SET_DBPDRGD0_DX3GCR2 (0xAAAA0000U) #define DBSC4_SET_DBPDRGA0_ZQCR (0x00000090U) #define DBSC4_SET_DBPDRGD0_ZQCR_MD19_0 (0x04058904U) #define DBSC4_SET_DBPDRGD0_ZQCR_MD19_1 (0x04058A04U) #define DBSC4_SET_DBPDRGA0_DX0GCR0 (0x000000A0U) #define DBSC4_SET_DBPDRGD0_DX0GCR0 (0x7C0002E5U) #define DBSC4_SET_DBPDRGA0_DX1GCR0 (0x000000C0U) #define DBSC4_SET_DBPDRGD0_DX1GCR0 (0x7C0002E5U) #define DBSC4_SET_DBPDRGA0_DX2GCR0 (0x000000E0U) #define DBSC4_SET_DBPDRGD0_DX2GCR0 (0x7C0002E5U) #define DBSC4_SET_DBPDRGA0_DX3GCR0 (0x00000100U) #define DBSC4_SET_DBPDRGD0_DX3GCR0 (0x7C0002E5U) #define DBSC4_SET_DBPDRGA0_DX0GCR1 (0x000000A1U) #define DBSC4_SET_DBPDRGD0_DX0GCR1 (0x55550000U) #define DBSC4_SET_DBPDRGA0_DX1GCR1 (0x000000C1U) #define DBSC4_SET_DBPDRGD0_DX1GCR1 (0x55550000U) #define DBSC4_SET_DBPDRGA0_DX2GCR1 (0x000000E1U) #define DBSC4_SET_DBPDRGD0_DX2GCR1 (0x55550000U) #define DBSC4_SET_DBPDRGA0_DX3GCR1 (0x00000101U) #define DBSC4_SET_DBPDRGD0_DX3GCR1 (0x55550000U) #define DBSC4_SET_DBPDRGA0_DX0GCR3 (0x000000A3U) #define DBSC4_SET_DBPDRGD0_DX0GCR3 (0x00008484U) #define DBSC4_SET_DBPDRGA0_DX1GCR3 (0x000000C3U) #define DBSC4_SET_DBPDRGD0_DX1GCR3 (0x00008484U) #define DBSC4_SET_DBPDRGA0_DX2GCR3 (0x000000E3U) #define DBSC4_SET_DBPDRGD0_DX2GCR3 (0x00008484U) #define DBSC4_SET_DBPDRGA0_DX3GCR3 (0x00000103U) #define DBSC4_SET_DBPDRGD0_DX3GCR3 (0x00008484U) #define RST_BASE (0xE6160000U) #define RST_MODEMR (RST_BASE + 0x0060U) #define RST_MODEMR_BIT0 (0x00000001U) #define RCAR_CNTCR_OFF (0x00U) #define RCAR_CNTCVL_OFF (0x08U) #define RCAR_CNTCVU_OFF (0x0CU) #define RCAR_CNTFID_OFF (0x20U) #define RCAR_CNTCR_EN ((uint32_t)1U << 0U) #define RCAR_CNTCR_FCREQ(x) ((uint32_t)(x) << 8U) #if PMIC_ROHM_BD9571 #define BIT_BKUP_CTRL_OUT ((uint8_t)(1U << 4)) #define PMIC_BKUP_MODE_CNT (0x20U) #define PMIC_QLLM_CNT (0x27U) #define PMIC_RETRY_MAX (100U) #endif #define SCTLR_EL3_M_BIT ((uint32_t)1U << 0) #define RCAR_CA53CPU_NUM_MAX (4U) #define RCAR_CA57CPU_NUM_MAX (4U) #define IS_A53A57(c) ((c) == RCAR_CLUSTER_A53A57) #define IS_CA57(c) ((c) == RCAR_CLUSTER_CA57) #define IS_CA53(c) ((c) == RCAR_CLUSTER_CA53) #ifndef __ASSEMBLER__ IMPORT_SYM(unsigned long, __system_ram_start__, SYSTEM_RAM_START); IMPORT_SYM(unsigned long, __system_ram_end__, SYSTEM_RAM_END); IMPORT_SYM(unsigned long, __SRAM_COPY_START__, SRAM_COPY_START); #endif uint32_t rcar_pwrc_status(uint64_t mpidr) { uint32_t ret = 0; uint64_t cm, cpu; uint32_t reg; uint32_t c; rcar_lock_get(); c = rcar_pwrc_get_cluster(); cm = mpidr & MPIDR_CLUSTER_MASK; if (!IS_A53A57(c) && cm != 0) { ret = RCAR_INVALID; goto done; } reg = mmio_read_32(RCAR_PRR); cpu = mpidr & MPIDR_CPU_MASK; if (IS_CA53(c)) if (reg & (1 << (STATE_CA53_CPU + cpu))) ret = RCAR_INVALID; if (IS_CA57(c)) if (reg & (1 << (STATE_CA57_CPU + cpu))) ret = RCAR_INVALID; done: rcar_lock_release(); return ret; } static void scu_power_up(uint64_t mpidr) { uintptr_t reg_pwrsr, reg_cpumcr, reg_pwron, reg_pwrer; uint32_t c, sysc_reg_bit; c = rcar_pwrc_get_mpidr_cluster(mpidr); reg_cpumcr = IS_CA57(c) ? RCAR_CA57CPUCMCR : RCAR_CA53CPUCMCR; sysc_reg_bit = IS_CA57(c) ? BIT_CA57_SCU : BIT_CA53_SCU; reg_pwron = IS_CA57(c) ? RCAR_PWRONCR5 : RCAR_PWRONCR3; reg_pwrer = IS_CA57(c) ? RCAR_PWRER5 : RCAR_PWRER3; reg_pwrsr = IS_CA57(c) ? RCAR_PWRSR5 : RCAR_PWRSR3; if ((mmio_read_32(reg_pwrsr) & STATUS_PWRDOWN) == 0) return; if (mmio_read_32(reg_cpumcr) != 0) mmio_write_32(reg_cpumcr, 0); mmio_setbits_32(RCAR_SYSCIER, sysc_reg_bit); mmio_setbits_32(RCAR_SYSCIMR, sysc_reg_bit); do { while ((mmio_read_32(RCAR_SYSCSR) & REQ_RESUME) == 0) ; mmio_write_32(reg_pwron, 1); } while (mmio_read_32(reg_pwrer) & 1); while ((mmio_read_32(RCAR_SYSCISR) & sysc_reg_bit) == 0) ; mmio_write_32(RCAR_SYSCISR, sysc_reg_bit); while ((mmio_read_32(reg_pwrsr) & STATUS_PWRUP) == 0) ; } void rcar_pwrc_cpuon(uint64_t mpidr) { uint32_t res_data, on_data; uintptr_t res_reg, on_reg; uint32_t limit, c; uint64_t cpu; rcar_lock_get(); c = rcar_pwrc_get_mpidr_cluster(mpidr); res_reg = IS_CA53(c) ? RCAR_CA53RESCNT : RCAR_CA57RESCNT; on_reg = IS_CA53(c) ? RCAR_CA53WUPCR : RCAR_CA57WUPCR; limit = IS_CA53(c) ? 0x5A5A0000 : 0xA5A50000; res_data = mmio_read_32(res_reg) | limit; scu_power_up(mpidr); cpu = mpidr & MPIDR_CPU_MASK; on_data = 1 << cpu; mmio_write_32(RCAR_CPGWPR, ~on_data); mmio_write_32(on_reg, on_data); mmio_write_32(res_reg, res_data & (~(1 << (3 - cpu)))); rcar_lock_release(); } void rcar_pwrc_cpuoff(uint64_t mpidr) { uint32_t c; uintptr_t reg; uint64_t cpu; rcar_lock_get(); cpu = mpidr & MPIDR_CPU_MASK; c = rcar_pwrc_get_mpidr_cluster(mpidr); reg = IS_CA53(c) ? RCAR_CA53CPU0CR : RCAR_CA57CPU0CR; if (read_mpidr_el1() != mpidr) panic(); mmio_write_32(RCAR_CPGWPR, ~CPU_PWR_OFF); mmio_write_32(reg + cpu * 0x0010, CPU_PWR_OFF); rcar_lock_release(); } void rcar_pwrc_enable_interrupt_wakeup(uint64_t mpidr) { uint32_t c, shift_irq, shift_fiq; uintptr_t reg; uint64_t cpu; rcar_lock_get(); cpu = mpidr & MPIDR_CPU_MASK; c = rcar_pwrc_get_mpidr_cluster(mpidr); reg = IS_CA53(c) ? RCAR_WUPMSKCA53 : RCAR_WUPMSKCA57; shift_irq = WUP_IRQ_SHIFT + cpu; shift_fiq = WUP_FIQ_SHIFT + cpu; mmio_write_32(reg, ~((uint32_t) 1 << shift_irq) & ~((uint32_t) 1 << shift_fiq)); rcar_lock_release(); } void rcar_pwrc_disable_interrupt_wakeup(uint64_t mpidr) { uint32_t c, shift_irq, shift_fiq; uintptr_t reg; uint64_t cpu; rcar_lock_get(); cpu = mpidr & MPIDR_CPU_MASK; c = rcar_pwrc_get_mpidr_cluster(mpidr); reg = IS_CA53(c) ? RCAR_WUPMSKCA53 : RCAR_WUPMSKCA57; shift_irq = WUP_IRQ_SHIFT + cpu; shift_fiq = WUP_FIQ_SHIFT + cpu; mmio_write_32(reg, ((uint32_t) 1 << shift_irq) | ((uint32_t) 1 << shift_fiq)); rcar_lock_release(); } void rcar_pwrc_clusteroff(uint64_t mpidr) { uint32_t c, product, cut, reg; uintptr_t dst; rcar_lock_get(); reg = mmio_read_32(RCAR_PRR); product = reg & PRR_PRODUCT_MASK; cut = reg & PRR_CUT_MASK; c = rcar_pwrc_get_mpidr_cluster(mpidr); dst = IS_CA53(c) ? RCAR_CA53CPUCMCR : RCAR_CA57CPUCMCR; if (PRR_PRODUCT_M3 == product && cut < PRR_PRODUCT_30) goto done; if (PRR_PRODUCT_H3 == product && cut <= PRR_PRODUCT_20) goto done; /* all of the CPUs in the cluster is in the CoreStandby mode */ mmio_write_32(dst, MODE_L2_DOWN); done: rcar_lock_release(); } static uint64_t rcar_pwrc_saved_cntpct_el0; static uint32_t rcar_pwrc_saved_cntfid; #if RCAR_SYSTEM_SUSPEND static void rcar_pwrc_save_timer_state(void) { rcar_pwrc_saved_cntpct_el0 = read_cntpct_el0(); rcar_pwrc_saved_cntfid = mmio_read_32((uintptr_t)(RCAR_CNTC_BASE + RCAR_CNTFID_OFF)); } #endif void rcar_pwrc_restore_timer_state(void) { /* Stop timer before restoring counter value */ mmio_write_32((uintptr_t)(RCAR_CNTC_BASE + RCAR_CNTCR_OFF), 0U); mmio_write_32((uintptr_t)(RCAR_CNTC_BASE + RCAR_CNTCVL_OFF), (uint32_t)(rcar_pwrc_saved_cntpct_el0 & 0xFFFFFFFFU)); mmio_write_32((uintptr_t)(RCAR_CNTC_BASE + RCAR_CNTCVU_OFF), (uint32_t)(rcar_pwrc_saved_cntpct_el0 >> 32U)); mmio_write_32((uintptr_t)(RCAR_CNTC_BASE + RCAR_CNTFID_OFF), rcar_pwrc_saved_cntfid); /* Start generic timer back */ write_cntfrq_el0((u_register_t)plat_get_syscnt_freq2()); mmio_write_32((uintptr_t)(RCAR_CNTC_BASE + RCAR_CNTCR_OFF), (RCAR_CNTCR_FCREQ(0U) | RCAR_CNTCR_EN)); } #if !PMIC_ROHM_BD9571 void rcar_pwrc_system_reset(void) { mmio_write_32(RCAR_SRESCR, 0x5AA50000U | BIT_SOFTRESET); } #endif /* PMIC_ROHM_BD9571 */ #define RST_CA53_CPU0_BARH (0xE6160080U) #define RST_CA53_CPU0_BARL (0xE6160084U) #define RST_CA57_CPU0_BARH (0xE61600C0U) #define RST_CA57_CPU0_BARL (0xE61600C4U) void rcar_pwrc_setup(void) { uintptr_t rst_barh; uintptr_t rst_barl; uint32_t i, j; uint64_t reset = (uint64_t) (&plat_secondary_reset) & 0xFFFFFFFF; const uint32_t cluster[PLATFORM_CLUSTER_COUNT] = { RCAR_CLUSTER_CA53, RCAR_CLUSTER_CA57 }; const uintptr_t reg_barh[PLATFORM_CLUSTER_COUNT] = { RST_CA53_CPU0_BARH, RST_CA57_CPU0_BARH }; const uintptr_t reg_barl[PLATFORM_CLUSTER_COUNT] = { RST_CA53_CPU0_BARL, RST_CA57_CPU0_BARL }; for (i = 0; i < PLATFORM_CLUSTER_COUNT; i++) { rst_barh = reg_barh[i]; rst_barl = reg_barl[i]; for (j = 0; j < rcar_pwrc_get_cpu_num(cluster[i]); j++) { mmio_write_32(rst_barh, 0); mmio_write_32(rst_barl, (uint32_t) reset); rst_barh += 0x10; rst_barl += 0x10; } } rcar_lock_init(); } #if RCAR_SYSTEM_SUSPEND #define DBCAM_FLUSH(__bit) \ do { \ ; \ } while (!(mmio_read_32(DBSC4_REG_DBCAM##__bit##STAT0) & DBSC4_BIT_DBCAMxSTAT0)) static void __attribute__ ((section(".system_ram"))) rcar_pwrc_set_self_refresh(void) { uint32_t reg = mmio_read_32(RCAR_PRR); uint32_t cut, product; product = reg & PRR_PRODUCT_MASK; cut = reg & PRR_CUT_MASK; if (product == PRR_PRODUCT_M3 && cut < PRR_PRODUCT_30) goto self_refresh; if (product == PRR_PRODUCT_H3 && cut < PRR_PRODUCT_20) goto self_refresh; mmio_write_32(DBSC4_REG_DBSYSCNT0, DBSC4_SET_DBSYSCNT0_WRITE_ENABLE); self_refresh: /* DFI_PHYMSTR_ACK setting */ mmio_write_32(DBSC4_REG_DBDFIPMSTRCNF, mmio_read_32(DBSC4_REG_DBDFIPMSTRCNF) & (~DBSC4_BIT_DBDFIPMSTRCNF_PMSTREN)); /* Set the Self-Refresh mode */ mmio_write_32(DBSC4_REG_DBACEN, 0); if (product == PRR_PRODUCT_H3 && cut < PRR_PRODUCT_20) rcar_micro_delay(100); else if (product == PRR_PRODUCT_H3) { mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 1); DBCAM_FLUSH(0); DBCAM_FLUSH(1); DBCAM_FLUSH(2); DBCAM_FLUSH(3); mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 0); } else if (product == PRR_PRODUCT_M3) { mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 1); DBCAM_FLUSH(0); DBCAM_FLUSH(1); mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 0); } else { mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 1); DBCAM_FLUSH(0); mmio_write_32(DBSC4_REG_DBCAM0CTRL0, 0); } /* Set the SDRAM calibration configuration register */ mmio_write_32(DBSC4_REG_DBCALCNF, 0); reg = DBSC4_SET_DBCMD_OPC_PRE | DBSC4_SET_DBCMD_CH_ALL | DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ALL; mmio_write_32(DBSC4_REG_DBCMD, reg); while (mmio_read_32(DBSC4_REG_DBWAIT)) ; /* Self-Refresh entry command */ reg = DBSC4_SET_DBCMD_OPC_SR | DBSC4_SET_DBCMD_CH_ALL | DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ENTER; mmio_write_32(DBSC4_REG_DBCMD, reg); while (mmio_read_32(DBSC4_REG_DBWAIT)) ; /* Mode Register Write command. (ODT disabled) */ reg = DBSC4_SET_DBCMD_OPC_MRW | DBSC4_SET_DBCMD_CH_ALL | DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_MRW_ODTC; mmio_write_32(DBSC4_REG_DBCMD, reg); while (mmio_read_32(DBSC4_REG_DBWAIT)) ; /* Power Down entry command */ reg = DBSC4_SET_DBCMD_OPC_PD | DBSC4_SET_DBCMD_CH_ALL | DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ENTER; mmio_write_32(DBSC4_REG_DBCMD, reg); while (mmio_read_32(DBSC4_REG_DBWAIT)) ; /* Set the auto-refresh enable register */ mmio_write_32(DBSC4_REG_DBRFEN, 0U); rcar_micro_delay(1U); if (product == PRR_PRODUCT_M3 && cut < PRR_PRODUCT_30) return; if (product == PRR_PRODUCT_H3 && cut < PRR_PRODUCT_20) return; mmio_write_32(DBSC4_REG_DBSYSCNT0, DBSC4_SET_DBSYSCNT0_WRITE_DISABLE); } static void __attribute__ ((section(".system_ram"))) rcar_pwrc_set_self_refresh_e3(void) { uint32_t ddr_md; uint32_t reg; ddr_md = (mmio_read_32(RST_MODEMR) >> 19) & RST_MODEMR_BIT0; /* Write enable */ mmio_write_32(DBSC4_REG_DBSYSCNT0, DBSC4_SET_DBSYSCNT0_WRITE_ENABLE); mmio_write_32(DBSC4_REG_DBACEN, 0); DBCAM_FLUSH(0); reg = DBSC4_SET_DBCMD_OPC_PRE | DBSC4_SET_DBCMD_CH_ALL | DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ALL; mmio_write_32(DBSC4_REG_DBCMD, reg); while (mmio_read_32(DBSC4_REG_DBWAIT)) ; reg = DBSC4_SET_DBCMD_OPC_SR | DBSC4_SET_DBCMD_CH_ALL | DBSC4_SET_DBCMD_RANK_ALL | DBSC4_SET_DBCMD_ARG_ENTER; mmio_write_32(DBSC4_REG_DBCMD, reg); while (mmio_read_32(DBSC4_REG_DBWAIT)) ; /* Set the auto-refresh enable register */ /* Set the ARFEN bit to 0 in the DBRFEN */ mmio_write_32(DBSC4_REG_DBRFEN, 0); mmio_write_32(DBSC4_REG_DBPDLK0, DBSC4_SET_DBPDLK0_PHY_ACCESS); mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_ACIOCR0); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_ACIOCR0); /* DDR_DXCCR */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DXCCR); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DXCCR); /* DDR_PGCR1 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_PGCR1); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_PGCR1); /* DDR_ACIOCR1 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_ACIOCR1); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_ACIOCR1); /* DDR_ACIOCR3 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_ACIOCR3); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_ACIOCR3); /* DDR_ACIOCR5 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_ACIOCR5); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_ACIOCR5); /* DDR_DX0GCR2 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX0GCR2); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX0GCR2); /* DDR_DX1GCR2 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX1GCR2); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX1GCR2); /* DDR_DX2GCR2 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX2GCR2); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX2GCR2); /* DDR_DX3GCR2 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX3GCR2); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX3GCR2); /* DDR_ZQCR */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_ZQCR); mmio_write_32(DBSC4_REG_DBPDRGD0, ddr_md == 0 ? DBSC4_SET_DBPDRGD0_ZQCR_MD19_0 : DBSC4_SET_DBPDRGD0_ZQCR_MD19_1); /* DDR_DX0GCR0 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX0GCR0); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX0GCR0); /* DDR_DX1GCR0 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX1GCR0); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX1GCR0); /* DDR_DX2GCR0 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX2GCR0); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX2GCR0); /* DDR_DX3GCR0 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX3GCR0); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX3GCR0); /* DDR_DX0GCR1 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX0GCR1); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX0GCR1); /* DDR_DX1GCR1 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX1GCR1); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX1GCR1); /* DDR_DX2GCR1 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX2GCR1); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX2GCR1); /* DDR_DX3GCR1 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX3GCR1); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX3GCR1); /* DDR_DX0GCR3 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX0GCR3); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX0GCR3); /* DDR_DX1GCR3 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX1GCR3); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX1GCR3); /* DDR_DX2GCR3 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX2GCR3); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX2GCR3); /* DDR_DX3GCR3 */ mmio_write_32(DBSC4_REG_DBPDRGA0, DBSC4_SET_DBPDRGA0_DX3GCR3); mmio_write_32(DBSC4_REG_DBPDRGD0, DBSC4_SET_DBPDRGD0_DX3GCR3); /* Write disable */ mmio_write_32(DBSC4_REG_DBSYSCNT0, DBSC4_SET_DBSYSCNT0_WRITE_DISABLE); } void __attribute__ ((section(".system_ram"))) __attribute__ ((noinline)) rcar_pwrc_go_suspend_to_ram(void) { #if PMIC_ROHM_BD9571 int32_t rc = -1, qllm = -1; uint8_t mode; uint32_t i; #endif uint32_t reg, product; reg = mmio_read_32(RCAR_PRR); product = reg & PRR_PRODUCT_MASK; if (product != PRR_PRODUCT_E3) rcar_pwrc_set_self_refresh(); else rcar_pwrc_set_self_refresh_e3(); #if PMIC_ROHM_BD9571 /* Set QLLM Cnt Disable */ for (i = 0; (i < PMIC_RETRY_MAX) && (qllm != 0); i++) qllm = rcar_iic_dvfs_send(PMIC, PMIC_QLLM_CNT, 0); /* Set trigger of power down to PMIV */ for (i = 0; (i < PMIC_RETRY_MAX) && (rc != 0) && (qllm == 0); i++) { rc = rcar_iic_dvfs_receive(PMIC, PMIC_BKUP_MODE_CNT, &mode); if (rc == 0) { mode |= BIT_BKUP_CTRL_OUT; rc = rcar_iic_dvfs_send(PMIC, PMIC_BKUP_MODE_CNT, mode); } } #endif wfi(); while (1) ; } void rcar_pwrc_set_suspend_to_ram(void) { uintptr_t jump = (uintptr_t) &rcar_pwrc_go_suspend_to_ram; uintptr_t stack = (uintptr_t) (DEVICE_SRAM_STACK_BASE + DEVICE_SRAM_STACK_SIZE); uint32_t sctlr; rcar_pwrc_save_timer_state(); /* disable MMU */ sctlr = (uint32_t) read_sctlr_el3(); sctlr &= (uint32_t) ~SCTLR_EL3_M_BIT; write_sctlr_el3((uint64_t) sctlr); rcar_pwrc_switch_stack(jump, stack, NULL); } void rcar_pwrc_init_suspend_to_ram(void) { #if PMIC_ROHM_BD9571 uint8_t mode; if (rcar_iic_dvfs_receive(PMIC, PMIC_BKUP_MODE_CNT, &mode)) panic(); mode &= (uint8_t) (~BIT_BKUP_CTRL_OUT); if (rcar_iic_dvfs_send(PMIC, PMIC_BKUP_MODE_CNT, mode)) panic(); #endif } void rcar_pwrc_suspend_to_ram(void) { #if RCAR_SYSTEM_RESET_KEEPON_DDR int32_t error; error = rcar_iic_dvfs_send(PMIC, REG_KEEP10, 0); if (error) { ERROR("Failed send KEEP10 init ret=%d \n", error); return; } #endif rcar_pwrc_set_suspend_to_ram(); } #endif void rcar_pwrc_code_copy_to_system_ram(void) { int ret __attribute__ ((unused)); /* in assert */ uint32_t attr; struct device_sram_t { uintptr_t base; size_t len; } sram = { .base = (uintptr_t) DEVICE_SRAM_BASE, .len = DEVICE_SRAM_SIZE, }; struct ddr_code_t { void *base; size_t len; } code = { .base = (void *) SRAM_COPY_START, .len = SYSTEM_RAM_END - SYSTEM_RAM_START, }; attr = MT_MEMORY | MT_RW | MT_SECURE | MT_EXECUTE_NEVER; ret = xlat_change_mem_attributes(sram.base, sram.len, attr); assert(ret == 0); memcpy((void *)sram.base, code.base, code.len); flush_dcache_range((uint64_t) sram.base, code.len); /* Invalidate instruction cache */ plat_invalidate_icache(); dsb(); isb(); attr = MT_MEMORY | MT_RO | MT_SECURE | MT_EXECUTE; ret = xlat_change_mem_attributes(sram.base, sram.len, attr); assert(ret == 0); } uint32_t rcar_pwrc_get_cluster(void) { uint32_t reg; reg = mmio_read_32(RCAR_PRR); if (reg & (1U << (STATE_CA53_CPU + RCAR_CA53CPU_NUM_MAX))) return RCAR_CLUSTER_CA57; if (reg & (1U << (STATE_CA57_CPU + RCAR_CA57CPU_NUM_MAX))) return RCAR_CLUSTER_CA53; return RCAR_CLUSTER_A53A57; } uint32_t rcar_pwrc_get_mpidr_cluster(uint64_t mpidr) { uint32_t c = rcar_pwrc_get_cluster(); if (IS_A53A57(c)) { if (mpidr & MPIDR_CLUSTER_MASK) return RCAR_CLUSTER_CA53; return RCAR_CLUSTER_CA57; } return c; } #if RCAR_LSI == RCAR_D3 uint32_t rcar_pwrc_get_cpu_num(uint32_t c) { return 1; } #else uint32_t rcar_pwrc_get_cpu_num(uint32_t c) { uint32_t reg = mmio_read_32(RCAR_PRR); uint32_t count = 0, i; if (IS_A53A57(c) || IS_CA53(c)) { if (reg & (1 << (STATE_CA53_CPU + RCAR_CA53CPU_NUM_MAX))) goto count_ca57; for (i = 0; i < RCAR_CA53CPU_NUM_MAX; i++) { if (reg & (1 << (STATE_CA53_CPU + i))) continue; count++; } } count_ca57: if (IS_A53A57(c) || IS_CA57(c)) { if (reg & (1U << (STATE_CA57_CPU + RCAR_CA57CPU_NUM_MAX))) goto done; for (i = 0; i < RCAR_CA57CPU_NUM_MAX; i++) { if (reg & (1 << (STATE_CA57_CPU + i))) continue; count++; } } done: return count; } #endif int32_t rcar_pwrc_cpu_on_check(uint64_t mpidr) { uint64_t i; uint64_t j; uint64_t cpu_count; uintptr_t reg_PSTR; uint32_t status; uint64_t my_cpu; int32_t rtn; uint32_t my_cluster_type; const uint32_t cluster_type[PLATFORM_CLUSTER_COUNT] = { RCAR_CLUSTER_CA53, RCAR_CLUSTER_CA57 }; const uintptr_t registerPSTR[PLATFORM_CLUSTER_COUNT] = { RCAR_CA53PSTR, RCAR_CA57PSTR }; my_cluster_type = rcar_pwrc_get_cluster(); rtn = 0; my_cpu = mpidr & ((uint64_t)(MPIDR_CPU_MASK)); for (i = 0U; i < ((uint64_t)(PLATFORM_CLUSTER_COUNT)); i++) { cpu_count = rcar_pwrc_get_cpu_num(cluster_type[i]); reg_PSTR = registerPSTR[i]; for (j = 0U; j < cpu_count; j++) { if ((my_cluster_type != cluster_type[i]) || (my_cpu != j)) { status = mmio_read_32(reg_PSTR) >> (j * 4U); if ((status & 0x00000003U) == 0U) { rtn--; } } } } return (rtn); } trusted-firmware-a-2.2/drivers/renesas/rcar/pwrc/pwrc.h000066400000000000000000000036511355360272700232620ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PWRC_H #define PWRC_H #define PPOFFR_OFF 0x0 #define PPONR_OFF 0x4 #define PCOFFR_OFF 0x8 #define PWKUPR_OFF 0xc #define PSYSR_OFF 0x10 #define PWKUPR_WEN (1ull << 31) #define PSYSR_AFF_L2 (1U << 31) #define PSYSR_AFF_L1 (1 << 30) #define PSYSR_AFF_L0 (1 << 29) #define PSYSR_WEN (1 << 28) #define PSYSR_PC (1 << 27) #define PSYSR_PP (1 << 26) #define PSYSR_WK_SHIFT (24) #define PSYSR_WK_MASK (0x3) #define PSYSR_WK(x) (((x) >> PSYSR_WK_SHIFT) & PSYSR_WK_MASK) #define WKUP_COLD 0x0 #define WKUP_RESET 0x1 #define WKUP_PPONR 0x2 #define WKUP_GICREQ 0x3 #define RCAR_INVALID (0xffffffffU) #define PSYSR_INVALID 0xffffffff #define RCAR_CLUSTER_A53A57 (0U) #define RCAR_CLUSTER_CA53 (1U) #define RCAR_CLUSTER_CA57 (2U) #ifndef __ASSEMBLER__ void rcar_pwrc_disable_interrupt_wakeup(uint64_t mpidr); void rcar_pwrc_enable_interrupt_wakeup(uint64_t mpidr); void rcar_pwrc_clusteroff(uint64_t mpidr); void rcar_pwrc_cpuoff(uint64_t mpidr); void rcar_pwrc_cpuon(uint64_t mpidr); int32_t rcar_pwrc_cpu_on_check(uint64_t mpidr); void rcar_pwrc_setup(void); uint32_t rcar_pwrc_get_cpu_wkr(uint64_t mpidr); uint32_t rcar_pwrc_status(uint64_t mpidr); uint32_t rcar_pwrc_get_cluster(void); uint32_t rcar_pwrc_get_mpidr_cluster(uint64_t mpidr); uint32_t rcar_pwrc_get_cpu_num(uint32_t cluster_type); void rcar_pwrc_restore_timer_state(void); void plat_secondary_reset(void); void rcar_pwrc_code_copy_to_system_ram(void); #if !PMIC_ROHM_BD9571 void rcar_pwrc_system_reset(void); #endif #if RCAR_SYSTEM_SUSPEND void rcar_pwrc_go_suspend_to_ram(void); void rcar_pwrc_set_suspend_to_ram(void); void rcar_pwrc_init_suspend_to_ram(void); void rcar_pwrc_suspend_to_ram(void); #endif extern uint32_t rcar_pwrc_switch_stack(uintptr_t jump, uintptr_t stack, void *arg); #endif #endif /* PWRC_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/qos/000077500000000000000000000000001355360272700217605ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/qos/D3/000077500000000000000000000000001355360272700222265ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/qos/D3/qos_init_d3.c000066400000000000000000000102231355360272700246030ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "../qos_common.h" #include "../qos_reg.h" #include "qos_init_d3.h" #define RCAR_QOS_VERSION "rev.0.05" #include "qos_init_d3_mstat.h" struct rcar_gen3_dbsc_qos_settings d3_qos[] = { /* BUFCAM settings */ { DBSC_DBCAM0CNF1, 0x00043218 }, { DBSC_DBCAM0CNF2, 0x000000F4 }, { DBSC_DBSCHCNT0, 0x000F0037 }, { DBSC_DBSCHSZ0, 0x00000001 }, { DBSC_DBSCHRW0, 0x22421111 }, /* DDR3 */ { DBSC_SCFCTST2, 0x012F1123 }, /* QoS Settings */ { DBSC_DBSCHQOS00, 0x00000F00 }, { DBSC_DBSCHQOS01, 0x00000B00 }, { DBSC_DBSCHQOS02, 0x00000000 }, { DBSC_DBSCHQOS03, 0x00000000 }, { DBSC_DBSCHQOS40, 0x00000300 }, { DBSC_DBSCHQOS41, 0x000002F0 }, { DBSC_DBSCHQOS42, 0x00000200 }, { DBSC_DBSCHQOS43, 0x00000100 }, { DBSC_DBSCHQOS90, 0x00000300 }, { DBSC_DBSCHQOS91, 0x000002F0 }, { DBSC_DBSCHQOS92, 0x00000200 }, { DBSC_DBSCHQOS93, 0x00000100 }, { DBSC_DBSCHQOS130, 0x00000100 }, { DBSC_DBSCHQOS131, 0x000000F0 }, { DBSC_DBSCHQOS132, 0x000000A0 }, { DBSC_DBSCHQOS133, 0x00000040 }, { DBSC_DBSCHQOS140, 0x000000C0 }, { DBSC_DBSCHQOS141, 0x000000B0 }, { DBSC_DBSCHQOS142, 0x00000080 }, { DBSC_DBSCHQOS143, 0x00000040 }, { DBSC_DBSCHQOS150, 0x00000040 }, { DBSC_DBSCHQOS151, 0x00000030 }, { DBSC_DBSCHQOS152, 0x00000020 }, { DBSC_DBSCHQOS153, 0x00000010 }, }; void qos_init_d3(void) { rcar_qos_dbsc_setting(d3_qos, ARRAY_SIZE(d3_qos), true); /* DRAM Split Address mapping */ #if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH ERROR("DRAM Split 4ch not supported.(D3)"); panic(); #elif RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH ERROR("DRAM Split 2ch not supported.(D3)"); panic(); #elif RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO ERROR("DRAM Split Auto not supported.(D3)"); panic(); #elif RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_LINEAR /* NOTICE("BL2: DRAM Split is OFF\n"); */ /* Split setting(DDR 1ch) */ io_write_32(AXI_ADSPLCR0, 0x00000000U); io_write_32(AXI_ADSPLCR3, 0x00000000U); #else ERROR("DRAM split is an invalid value.(D3)"); panic(); #endif #if !(RCAR_QOS_TYPE == RCAR_QOS_NONE) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION); #endif /* Resource Alloc setting */ io_write_32(QOSCTRL_RAS, 0x00000020U); io_write_32(QOSCTRL_FIXTH, 0x000F0005U); io_write_32(QOSCTRL_RAEN, 0x00000001U); io_write_32(QOSCTRL_REGGD, 0x00000000U); io_write_64(QOSCTRL_DANN, 0x0404020002020201U); io_write_32(QOSCTRL_DANT, 0x00100804U); io_write_32(QOSCTRL_EC, 0x00000000U); io_write_64(QOSCTRL_EMS, 0x0000000000000000U); io_write_32(QOSCTRL_FSS, 0x0000000AU); io_write_32(QOSCTRL_INSFC, 0xC7840001U); io_write_32(QOSCTRL_BERR, 0x00000000U); io_write_32(QOSCTRL_EARLYR, 0x00000000U); io_write_32(QOSCTRL_RACNT0, 0x00010003U); io_write_32(QOSCTRL_STATGEN0, 0x00000000U); /* GPU setting */ io_write_32(0xFD812030U, 0x00000000U); /* QOSBW setting */ io_write_32(QOSCTRL_SL_INIT, 0x030500ACU); io_write_32(QOSCTRL_REF_ARS, 0x00780000U); /* QOSBW SRAM setting */ uint32_t i; for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) { io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]); io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]); } for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) { io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]); io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]); } /* 3DG bus Leaf setting */ io_write_32(GPU_ACT_GRD, 0x00001234U); io_write_32(GPU_ACT0, 0x00000000U); io_write_32(GPU_ACT1, 0x00000000U); io_write_32(GPU_ACT2, 0x00000000U); io_write_32(GPU_ACT3, 0x00000000U); /* RT bus Leaf setting */ io_write_32(CPU_ACT0, 0x00000003U); io_write_32(CPU_ACT1, 0x00000003U); io_write_32(RT_ACT0, 0x00000000U); io_write_32(RT_ACT1, 0x00000000U); /* Resource Alloc start */ io_write_32(QOSCTRL_RAEN, 0x00000001U); /* QOSBW start */ io_write_32(QOSCTRL_STATQC, 0x00000001U); #else NOTICE("BL2: QoS is None\n"); /* Resource Alloc setting */ io_write_32(QOSCTRL_EC, 0x00000000U); /* Resource Alloc start */ io_write_32(QOSCTRL_RAEN, 0x00000001U); #endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */ } trusted-firmware-a-2.2/drivers/renesas/rcar/qos/D3/qos_init_d3.h000066400000000000000000000003571355360272700246170ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef QOS_INIT_H_D3__ #define QOS_INIT_H_D3__ void qos_init_d3(void); #endif /* QOS_INIT_H_D3__ */ trusted-firmware-a-2.2/drivers/renesas/rcar/qos/D3/qos_init_d3_mstat.h000066400000000000000000000211121355360272700260170ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT static const uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001004340000FFFFUL, /* 0x0038, */ 0x001004140000FFFFUL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x00140B030000FFFFUL, /* 0x0060, */ 0x001408610000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001410620000FFFFUL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00A0, */ 0x000C041C0000FFFFUL, /* 0x00A8, */ 0x000C04090000FFFFUL, /* 0x00B0, */ 0x000C04110000FFFFUL, /* 0x00B8, */ 0x0000000000000000UL, /* 0x00C0, */ 0x000C041C0000FFFFUL, /* 0x00C8, */ 0x000C04090000FFFFUL, /* 0x00D0, */ 0x000C04110000FFFFUL, /* 0x00D8, */ 0x0000000000000000UL, /* 0x00E0, */ 0x0000000000000000UL, /* 0x00E8, */ 0x0000000000000000UL, /* 0x00F0, */ 0x001018570000FFFFUL, /* 0x00F8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x001008570000FFFFUL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x001008520000FFFFUL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x00100CA30000FFFFUL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01A0, */ 0x0000000000000000UL, /* 0x01A8, */ 0x0000000000000000UL, /* 0x01B0, */ 0x0000000000000000UL, /* 0x01B8, */ 0x0000000000000000UL, /* 0x01C0, */ 0x0000000000000000UL, /* 0x01C8, */ 0x0000000000000000UL, /* 0x01D0, */ 0x0000000000000000UL, /* 0x01D8, */ 0x0000000000000000UL, /* 0x01E0, */ 0x0000000000000000UL, /* 0x01E8, */ 0x000C04020000FFFFUL, /* 0x01F0, */ 0x0000000000000000UL, /* 0x01F8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x000C04090000FFFFUL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x001410040000FFFFUL, /* 0x0270, */ 0x001404020000FFFFUL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001410040000FFFFUL, /* 0x0298, */ 0x001404020000FFFFUL, /* 0x02A0, */ 0x000C04050000FFFFUL, /* 0x02A8, */ 0x000C04050000FFFFUL, /* 0x02B0, */ 0x0000000000000000UL, /* 0x02B8, */ 0x0000000000000000UL, /* 0x02C0, */ 0x0000000000000000UL, /* 0x02C8, */ 0x0000000000000000UL, /* 0x02D0, */ 0x000C04050000FFFFUL, /* 0x02D8, */ 0x000C04050000FFFFUL, /* 0x02E0, */ 0x0000000000000000UL, /* 0x02E8, */ 0x0000000000000000UL, /* 0x02F0, */ 0x0000000000000000UL, /* 0x02F8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, /* 0x0370, */ 0x000C04020000FFFFUL, /* 0x0378, */ 0x000C04020000FFFFUL, /* 0x0380, */ 0x000C04090000FFFFUL, /* 0x0388, */ 0x000C04090000FFFFUL, /* 0x0390, */ 0x0000000000000000UL, }; static const uint64_t mstat_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00A0, */ 0x0000000000000000UL, /* 0x00A8, */ 0x0000000000000000UL, /* 0x00B0, */ 0x0000000000000000UL, /* 0x00B8, */ 0x0000000000000000UL, /* 0x00C0, */ 0x0000000000000000UL, /* 0x00C8, */ 0x0000000000000000UL, /* 0x00D0, */ 0x0000000000000000UL, /* 0x00D8, */ 0x0000000000000000UL, /* 0x00E0, */ 0x0000000000000000UL, /* 0x00E8, */ 0x0000000000000000UL, /* 0x00F0, */ 0x0000000000000000UL, /* 0x00F8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01A0, */ 0x0000000000000000UL, /* 0x01A8, */ 0x0000000000000000UL, /* 0x01B0, */ 0x0000000000000000UL, /* 0x01B8, */ 0x0000000000000000UL, /* 0x01C0, */ 0x00110090060FA001UL, /* 0x01C8, */ 0x00110090060FA001UL, /* 0x01D0, */ 0x0000000000000000UL, /* 0x01D8, */ 0x0000000000000000UL, /* 0x01E0, */ 0x0000000000000000UL, /* 0x01E8, */ 0x0000000000000000UL, /* 0x01F0, */ 0x0011001006004401UL, /* 0x01F8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0011001006004401UL, /* 0x0218, */ 0x0011001006009801UL, /* 0x0220, */ 0x0011001006009801UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0011001006009801UL, /* 0x0238, */ 0x0011001006009801UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02A0, */ 0x0000000000000000UL, /* 0x02A8, */ 0x0000000000000000UL, /* 0x02B0, */ 0x0000000000000000UL, /* 0x02B8, */ 0x0011001006003401UL, /* 0x02C0, */ 0x0000000000000000UL, /* 0x02C8, */ 0x0000000000000000UL, /* 0x02D0, */ 0x0000000000000000UL, /* 0x02D8, */ 0x0000000000000000UL, /* 0x02E0, */ 0x0000000000000000UL, /* 0x02E8, */ 0x0011001006003401UL, /* 0x02F0, */ 0x00110090060FA001UL, /* 0x02F8, */ 0x00110090060FA001UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0012001006003401UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x00120090060FA001UL, /* 0x0360, */ 0x00120090060FA001UL, /* 0x0368, */ 0x0012001006003401UL, /* 0x0370, */ 0x0000000000000000UL, /* 0x0378, */ 0x0000000000000000UL, /* 0x0380, */ 0x0000000000000000UL, /* 0x0388, */ 0x0000000000000000UL, /* 0x0390, */ 0x0012001006003401UL, }; #endif trusted-firmware-a-2.2/drivers/renesas/rcar/qos/E3/000077500000000000000000000000001355360272700222275ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/qos/E3/qos_init_e3_v10.c000066400000000000000000000072111355360272700252760ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "../qos_common.h" #include "../qos_reg.h" #include "qos_init_e3_v10.h" #define RCAR_QOS_VERSION "rev.0.05" #define REF_ARS_ARBSTOPCYCLE_E3 (((SL_INIT_SSLOTCLK_E3) - 5U) << 16U) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT #if RCAR_REF_INT == RCAR_REF_DEFAULT #include "qos_init_e3_v10_mstat390.h" #else #include "qos_init_e3_v10_mstat780.h" #endif #endif struct rcar_gen3_dbsc_qos_settings e3_qos[] = { /* BUFCAM settings */ { DBSC_DBCAM0CNF1, 0x00043218 }, { DBSC_DBCAM0CNF2, 0x000000F4 }, { DBSC_DBSCHCNT0, 0x000F0037 }, { DBSC_DBSCHSZ0, 0x00000001 }, { DBSC_DBSCHRW0, 0x22421111 }, /* DDR3 */ { DBSC_SCFCTST2, 0x012F1123 }, /* QoS Settings */ { DBSC_DBSCHQOS00, 0x00000F00 }, { DBSC_DBSCHQOS01, 0x00000B00 }, { DBSC_DBSCHQOS02, 0x00000000 }, { DBSC_DBSCHQOS03, 0x00000000 }, { DBSC_DBSCHQOS40, 0x00000300 }, { DBSC_DBSCHQOS41, 0x000002F0 }, { DBSC_DBSCHQOS42, 0x00000200 }, { DBSC_DBSCHQOS43, 0x00000100 }, { DBSC_DBSCHQOS90, 0x00000100 }, { DBSC_DBSCHQOS91, 0x000000F0 }, { DBSC_DBSCHQOS92, 0x000000A0 }, { DBSC_DBSCHQOS93, 0x00000040 }, { DBSC_DBSCHQOS130, 0x00000100 }, { DBSC_DBSCHQOS131, 0x000000F0 }, { DBSC_DBSCHQOS132, 0x000000A0 }, { DBSC_DBSCHQOS133, 0x00000040 }, { DBSC_DBSCHQOS140, 0x000000C0 }, { DBSC_DBSCHQOS141, 0x000000B0 }, { DBSC_DBSCHQOS142, 0x00000080 }, { DBSC_DBSCHQOS143, 0x00000040 }, { DBSC_DBSCHQOS150, 0x00000040 }, { DBSC_DBSCHQOS151, 0x00000030 }, { DBSC_DBSCHQOS152, 0x00000020 }, { DBSC_DBSCHQOS153, 0x00000010 }, }; void qos_init_e3_v10(void) { rcar_qos_dbsc_setting(e3_qos, ARRAY_SIZE(e3_qos), true); /* DRAM Split Address mapping */ #if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH #if RCAR_LSI == RCAR_E3 #error "Don't set DRAM Split 4ch(E3)" #else ERROR("DRAM Split 4ch not supported.(E3)"); panic(); #endif #elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH) #if RCAR_LSI == RCAR_E3 #error "Don't set DRAM Split 2ch(E3)" #else ERROR("DRAM Split 2ch not supported.(E3)"); panic(); #endif #else NOTICE("BL2: DRAM Split is OFF\n"); #endif #if !(RCAR_QOS_TYPE == RCAR_QOS_NONE) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION); #endif #if RCAR_REF_INT == RCAR_REF_DEFAULT NOTICE("BL2: DRAM refresh interval 3.9 usec\n"); #else NOTICE("BL2: DRAM refresh interval 7.8 usec\n"); #endif io_write_32(QOSCTRL_RAS, 0x00000020U); io_write_64(QOSCTRL_DANN, 0x0404020002020201UL); io_write_32(QOSCTRL_DANT, 0x00100804U); io_write_32(QOSCTRL_FSS, 0x0000000AU); io_write_32(QOSCTRL_INSFC, 0x06330001U); io_write_32(QOSCTRL_EARLYR, 0x00000000U); io_write_32(QOSCTRL_RACNT0, 0x00010003U); io_write_32(QOSCTRL_SL_INIT, SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK_E3); io_write_32(QOSCTRL_REF_ARS, REF_ARS_ARBSTOPCYCLE_E3); /* QOSBW SRAM setting */ uint32_t i; for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) { io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]); io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]); } for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) { io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]); io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]); } /* RT bus Leaf setting */ io_write_32(RT_ACT0, 0x00000000U); io_write_32(RT_ACT1, 0x00000000U); /* CCI bus Leaf setting */ io_write_32(CPU_ACT0, 0x00000003U); io_write_32(CPU_ACT1, 0x00000003U); io_write_32(QOSCTRL_RAEN, 0x00000001U); io_write_32(QOSCTRL_STATQC, 0x00000001U); #else NOTICE("BL2: QoS is None\n"); io_write_32(QOSCTRL_RAEN, 0x00000001U); #endif } trusted-firmware-a-2.2/drivers/renesas/rcar/qos/E3/qos_init_e3_v10.h000066400000000000000000000003621355360272700253030ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef QOS_INIT_E3_V10_H #define QOS_INIT_E3_V10_H void qos_init_e3_v10(void); #endif /* QOS_INIT_E3_V10_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/qos/E3/qos_init_e3_v10_mstat390.h000066400000000000000000000210051355360272700267440ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001008620000FFFFUL, /* 0x0038, */ 0x001008620000FFFFUL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x001415260000FFFFUL, /* 0x0060, */ 0x001415260000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001414930000FFFFUL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x000C08380000FFFFUL, /* 0x00a8, */ 0x000C04110000FFFFUL, /* 0x00b0, */ 0x000C04150000FFFFUL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x000C08380000FFFFUL, /* 0x00c8, */ 0x000C04110000FFFFUL, /* 0x00d0, */ 0x000C04150000FFFFUL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x001018580000FFFFUL, /* 0x00f8, */ 0x000C084F0000FFFFUL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x001008580000FFFFUL, /* 0x0118, */ 0x000C21E40000FFFFUL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x001008530000FFFFUL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x00100C960000FFFFUL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x001008530000FFFFUL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0010042A0000FFFFUL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x00101D8D0000FFFFUL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x001008530000FFFFUL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x000C04010000FFFFUL, /* 0x01c8, */ 0x000C04010000FFFFUL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x000C04020000FFFFUL, /* 0x01f0, */ 0x000C04090000FFFFUL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x000C04090000FFFFUL, /* 0x0210, */ 0x000C04090000FFFFUL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C0C2A0000FFFFUL, /* 0x0268, */ 0x001410040000FFFFUL, /* 0x0270, */ 0x001404020000FFFFUL, /* 0x0278, */ 0x000C08110000FFFFUL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001410040000FFFFUL, /* 0x0298, */ 0x001404020000FFFFUL, /* 0x02a0, */ 0x000C04090000FFFFUL, /* 0x02a8, */ 0x000C04090000FFFFUL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x000C04020000FFFFUL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x000C04090000FFFFUL, /* 0x02d8, */ 0x000C04090000FFFFUL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x000C04020000FFFFUL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, /* 0x0370, */ 0x000C04020000FFFFUL, /* 0x0378, */ 0x000C04020000FFFFUL, /* 0x0380, */ 0x000C04090000FFFFUL, /* 0x0388, */ 0x000C04090000FFFFUL, /* 0x0390, */ 0x0000000000000000UL, }; static uint64_t mstat_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0012001005F03401UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0021060005FFFC01UL, /* 0x01c8, */ 0x0021060005FFFC01UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0021010005F79801UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0021010005F79801UL, /* 0x0218, */ 0x0011010005F79801UL, /* 0x0220, */ 0x0011010005F79801UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0011010005F79801UL, /* 0x0238, */ 0x0011010005F79801UL, /* 0x0240, */ 0x0012010005F79801UL, /* 0x0248, */ 0x0011010005F79801UL, /* 0x0250, */ 0x0012010005F79801UL, /* 0x0258, */ 0x0011010005F79801UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0011060005FFFC01UL, /* 0x02f8, */ 0x0011060005FFFC01UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0012001005F03401UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0012060005FFFC01UL, /* 0x0360, */ 0x0012060005FFFC01UL, /* 0x0368, */ 0x0012001005F03401UL, /* 0x0370, */ 0x0000000000000000UL, /* 0x0378, */ 0x0000000000000000UL, /* 0x0380, */ 0x0000000000000000UL, /* 0x0388, */ 0x0000000000000000UL, /* 0x0390, */ 0x0012001005F03401UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/E3/qos_init_e3_v10_mstat780.h000066400000000000000000000210051355360272700267470ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001010C40000FFFFUL, /* 0x0038, */ 0x001010C40000FFFFUL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x00142A4B0000FFFFUL, /* 0x0060, */ 0x00142A4B0000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001429260000FFFFUL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x000C10700000FFFFUL, /* 0x00a8, */ 0x000C08210000FFFFUL, /* 0x00b0, */ 0x000C082A0000FFFFUL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x000C10700000FFFFUL, /* 0x00c8, */ 0x000C08210000FFFFUL, /* 0x00d0, */ 0x000C082A0000FFFFUL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x00102CAF0000FFFFUL, /* 0x00f8, */ 0x000C0C9D0000FFFFUL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x00100CAF0000FFFFUL, /* 0x0118, */ 0x000C43C80000FFFFUL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x00100CA50000FFFFUL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0010152C0000FFFFUL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x00100CA50000FFFFUL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x001008530000FFFFUL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x001037190000FFFFUL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x00100CA50000FFFFUL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x000C04010000FFFFUL, /* 0x01c8, */ 0x000C04010000FFFFUL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x000C04040000FFFFUL, /* 0x01f0, */ 0x000C08110000FFFFUL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x000C04110000FFFFUL, /* 0x0210, */ 0x000C08110000FFFFUL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C18530000FFFFUL, /* 0x0268, */ 0x00141C070000FFFFUL, /* 0x0270, */ 0x001404040000FFFFUL, /* 0x0278, */ 0x000C0C210000FFFFUL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x00141C070000FFFFUL, /* 0x0298, */ 0x001404040000FFFFUL, /* 0x02a0, */ 0x000C04110000FFFFUL, /* 0x02a8, */ 0x000C04110000FFFFUL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x000C04040000FFFFUL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x000C04110000FFFFUL, /* 0x02d8, */ 0x000C04110000FFFFUL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x000C04040000FFFFUL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, /* 0x0370, */ 0x000C04040000FFFFUL, /* 0x0378, */ 0x000C04040000FFFFUL, /* 0x0380, */ 0x000C04110000FFFFUL, /* 0x0388, */ 0x000C04110000FFFFUL, /* 0x0390, */ 0x0000000000000000UL, }; static uint64_t mstat_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0012001002F03401UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0021060002FFFC01UL, /* 0x01c8, */ 0x0021060002FFFC01UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0021010002F3CC01UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0021010002F3CC01UL, /* 0x0218, */ 0x0011010002F3CC01UL, /* 0x0220, */ 0x0011010002F3CC01UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0011010002F3CC01UL, /* 0x0238, */ 0x0011010002F3CC01UL, /* 0x0240, */ 0x0012010002F3CC01UL, /* 0x0248, */ 0x0011010002F3CC01UL, /* 0x0250, */ 0x0012010002F3CC01UL, /* 0x0258, */ 0x0011010002F3CC01UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0011060002FFFC01UL, /* 0x02f8, */ 0x0011060002FFFC01UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0012001002F03401UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0012060002FFFC01UL, /* 0x0360, */ 0x0012060002FFFC01UL, /* 0x0368, */ 0x0012001002F03401UL, /* 0x0370, */ 0x0000000000000000UL, /* 0x0378, */ 0x0000000000000000UL, /* 0x0380, */ 0x0000000000000000UL, /* 0x0388, */ 0x0000000000000000UL, /* 0x0390, */ 0x0012001002F03401UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/000077500000000000000000000000001355360272700222325ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v10.c000066400000000000000000000060541355360272700253100ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "../qos_common.h" #include "../qos_reg.h" #include "qos_init_h3_v10.h" #define RCAR_QOS_VERSION "rev.0.36" #include "qos_init_h3_v10_mstat.h" void qos_init_h3_v10(void) { /* DRAM Split Address mapping */ #if (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH) || \ (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO) NOTICE("BL2: DRAM Split is 4ch\n"); io_write_32(AXI_ADSPLCR0, ADSPLCR0_ADRMODE_DEFAULT | ADSPLCR0_SPLITSEL(0xFFU) | ADSPLCR0_AREA(0x1BU) | ADSPLCR0_SWP); io_write_32(AXI_ADSPLCR1, 0x00000000U); io_write_32(AXI_ADSPLCR2, 0xA8A90000U); io_write_32(AXI_ADSPLCR3, 0x00000000U); #elif RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH NOTICE("BL2: DRAM Split is 2ch\n"); io_write_32(AXI_ADSPLCR0, 0x00000000U); io_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT | ADSPLCR0_SPLITSEL(0xFFU) | ADSPLCR0_AREA(0x1BU) | ADSPLCR0_SWP); io_write_32(AXI_ADSPLCR2, 0x00000000U); io_write_32(AXI_ADSPLCR3, 0x00000000U); #else NOTICE("BL2: DRAM Split is OFF\n"); #endif #if !(RCAR_QOS_TYPE == RCAR_QOS_NONE) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION); #endif /* AR Cache setting */ io_write_32(0xE67D1000U, 0x00000100U); io_write_32(0xE67D1008U, 0x00000100U); /* Resource Alloc setting */ io_write_32(QOSCTRL_RAS, 0x00000040U); io_write_32(QOSCTRL_FIXTH, 0x000F0005U); io_write_32(QOSCTRL_REGGD, 0x00000004U); io_write_64(QOSCTRL_DANN, 0x0202000004040404UL); io_write_32(QOSCTRL_DANT, 0x003C1110U); io_write_32(QOSCTRL_EC, 0x00080001U); /* need for H3 v1.* */ io_write_64(QOSCTRL_EMS, 0x0000000000000000UL); io_write_32(QOSCTRL_INSFC, 0xC7840001U); io_write_32(QOSCTRL_BERR, 0x00000000U); /* QOSBW setting */ io_write_32(QOSCTRL_SL_INIT, SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK); io_write_32(QOSCTRL_REF_ARS, 0x00330000U); /* QOSBW SRAM setting */ uint32_t i; for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) { io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]); io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]); } for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) { io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]); io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]); } /* 3DG bus Leaf setting */ io_write_32(0xFD820808U, 0x00001234U); io_write_32(0xFD820800U, 0x0000003FU); io_write_32(0xFD821800U, 0x0000003FU); io_write_32(0xFD822800U, 0x0000003FU); io_write_32(0xFD823800U, 0x0000003FU); io_write_32(0xFD824800U, 0x0000003FU); io_write_32(0xFD825800U, 0x0000003FU); io_write_32(0xFD826800U, 0x0000003FU); io_write_32(0xFD827800U, 0x0000003FU); /* Resource Alloc start */ io_write_32(QOSCTRL_RAEN, 0x00000001U); /* QOSBW start */ io_write_32(QOSCTRL_STATQC, 0x00000001U); #else NOTICE("BL2: QoS is None\n"); /* Resource Alloc setting */ io_write_32(QOSCTRL_EC, 0x00080001U); /* need for H3 v1.* */ #endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */ } trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v10.h000066400000000000000000000003671355360272700253160ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef QOS_INIT_H3_V10_H #define QOS_INIT_H3_V10_H void qos_init_h3_v10(void); #endif /* QOS_INIT_H3_V10_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v10_mstat.h000066400000000000000000000174331355360272700265300ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT static const uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x00140C050000FFFFUL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x001404030000FFFFUL, /* 0x0060, */ 0x001408060000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x00140C050000FFFFUL, /* 0x0090, */ 0x001408060000FFFFUL, /* 0x0098, */ 0x001404020000FFFFUL, /* 0x00A0, */ 0x0000000000000000UL, /* 0x00A8, */ 0x0000000000000000UL, /* 0x00B0, */ 0x0000000000000000UL, /* 0x00B8, */ 0x0000000000000000UL, /* 0x00C0, */ 0x0000000000000000UL, /* 0x00C8, */ 0x0000000000000000UL, /* 0x00D0, */ 0x0000000000000000UL, /* 0x00D8, */ 0x0000000000000000UL, /* 0x00E0, */ 0x0000000000000000UL, /* 0x00E8, */ 0x0000000000000000UL, /* 0x00F0, */ 0x0000000000000000UL, /* 0x00F8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x001004020000FFFFUL, /* 0x0140, */ 0x001004020000FFFFUL, /* 0x0148, */ 0x001004020000FFFFUL, /* 0x0150, */ 0x001008050000FFFFUL, /* 0x0158, */ 0x001008050000FFFFUL, /* 0x0160, */ 0x001008050000FFFFUL, /* 0x0168, */ 0x001008050000FFFFUL, /* 0x0170, */ 0x001008050000FFFFUL, /* 0x0178, */ 0x001004030000FFFFUL, /* 0x0180, */ 0x001004030000FFFFUL, /* 0x0188, */ 0x001004030000FFFFUL, /* 0x0190, */ 0x001014140000FFFFUL, /* 0x0198, */ 0x001014140000FFFFUL, /* 0x01A0, */ 0x001008060000FFFFUL, /* 0x01A8, */ 0x001008060000FFFFUL, /* 0x01B0, */ 0x001008060000FFFFUL, /* 0x01B8, */ 0x0000000000000000UL, /* 0x01C0, */ 0x0000000000000000UL, /* 0x01C8, */ 0x0000000000000000UL, /* 0x01D0, */ 0x0000000000000000UL, /* 0x01D8, */ 0x0000000000000000UL, /* 0x01E0, */ 0x0000000000000000UL, /* 0x01E8, */ 0x0000000000000000UL, /* 0x01F0, */ 0x0000000000000000UL, /* 0x01F8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02A0, */ 0x0000000000000000UL, /* 0x02A8, */ 0x0000000000000000UL, /* 0x02B0, */ 0x0000000000000000UL, /* 0x02B8, */ 0x0000000000000000UL, /* 0x02C0, */ 0x0000000000000000UL, /* 0x02C8, */ 0x0000000000000000UL, /* 0x02D0, */ 0x0000000000000000UL, /* 0x02D8, */ 0x0000000000000000UL, /* 0x02E0, */ 0x0000000000000000UL, /* 0x02E8, */ 0x0000000000000000UL, /* 0x02F0, */ 0x0000000000000000UL, /* 0x02F8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, }; static const uint64_t mstat_be[] = { /* 0x0000, */ 0x001000100C8FFC01UL, /* 0x0008, */ 0x001000100C8FFC01UL, /* 0x0010, */ 0x001000100C8FFC01UL, /* 0x0018, */ 0x001000100C8FFC01UL, /* 0x0020, */ 0x001000100C8FFC01UL, /* 0x0028, */ 0x001000100C8FFC01UL, /* 0x0030, */ 0x001000100C8FFC01UL, /* 0x0038, */ 0x001000100C8FFC01UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x001000100C8FFC01UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x001000100C8FFC01UL, /* 0x0070, */ 0x001000100C8FFC01UL, /* 0x0078, */ 0x001000100C8FFC01UL, /* 0x0080, */ 0x001000100C8FFC01UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00A0, */ 0x001000100C8FFC01UL, /* 0x00A8, */ 0x001000100C8FFC01UL, /* 0x00B0, */ 0x001000100C8FFC01UL, /* 0x00B8, */ 0x001000100C8FFC01UL, /* 0x00C0, */ 0x001000100C8FFC01UL, /* 0x00C8, */ 0x001000100C8FFC01UL, /* 0x00D0, */ 0x001000100C8FFC01UL, /* 0x00D8, */ 0x002000200C8FFC01UL, /* 0x00E0, */ 0x002000200C8FFC01UL, /* 0x00E8, */ 0x001000100C8FFC01UL, /* 0x00F0, */ 0x001000100C8FFC01UL, /* 0x00F8, */ 0x001000100C8FFC01UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x002000200C8FFC01UL, /* 0x0110, */ 0x001000100C8FFC01UL, /* 0x0118, */ 0x001000100C8FFC01UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x002000200C8FFC01UL, /* 0x0130, */ 0x001000100C8FFC01UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01A0, */ 0x0000000000000000UL, /* 0x01A8, */ 0x0000000000000000UL, /* 0x01B0, */ 0x0000000000000000UL, /* 0x01B8, */ 0x001000100C8FFC01UL, /* 0x01C0, */ 0x001000200C8FFC01UL, /* 0x01C8, */ 0x001000200C8FFC01UL, /* 0x01D0, */ 0x001000200C8FFC01UL, /* 0x01D8, */ 0x001000200C8FFC01UL, /* 0x01E0, */ 0x001000100C8FFC01UL, /* 0x01E8, */ 0x001000100C8FFC01UL, /* 0x01F0, */ 0x001000100C8FFC01UL, /* 0x01F8, */ 0x001000100C8FFC01UL, /* 0x0200, */ 0x001000100C8FFC01UL, /* 0x0208, */ 0x001000100C8FFC01UL, /* 0x0210, */ 0x001000100C8FFC01UL, /* 0x0218, */ 0x001000100C8FFC01UL, /* 0x0220, */ 0x001000100C8FFC01UL, /* 0x0228, */ 0x001000100C8FFC01UL, /* 0x0230, */ 0x001000100C8FFC01UL, /* 0x0238, */ 0x001000100C8FFC01UL, /* 0x0240, */ 0x001000100C8FFC01UL, /* 0x0248, */ 0x001000100C8FFC01UL, /* 0x0250, */ 0x001000100C8FFC01UL, /* 0x0258, */ 0x001000100C8FFC01UL, /* 0x0260, */ 0x001000100C8FFC01UL, /* 0x0268, */ 0x001000100C8FFC01UL, /* 0x0270, */ 0x001000100C8FFC01UL, /* 0x0278, */ 0x001000100C8FFC01UL, /* 0x0280, */ 0x001000100C8FFC01UL, /* 0x0288, */ 0x001000100C8FFC01UL, /* 0x0290, */ 0x001000100C8FFC01UL, /* 0x0298, */ 0x001000100C8FFC01UL, /* 0x02A0, */ 0x001000100C8FFC01UL, /* 0x02A8, */ 0x001000100C8FFC01UL, /* 0x02B0, */ 0x001000100C8FFC01UL, /* 0x02B8, */ 0x001000100C8FFC01UL, /* 0x02C0, */ 0x001000100C8FFC01UL, /* 0x02C8, */ 0x001000100C8FFC01UL, /* 0x02D0, */ 0x001000100C8FFC01UL, /* 0x02D8, */ 0x001000100C8FFC01UL, /* 0x02E0, */ 0x001000100C8FFC01UL, /* 0x02E8, */ 0x001000100C8FFC01UL, /* 0x02F0, */ 0x001000200C8FFC01UL, /* 0x02F8, */ 0x001000300C8FFC01UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x001000200C8FFC01UL, /* 0x0310, */ 0x001000300C8FFC01UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x001000200C8FFC01UL, /* 0x0328, */ 0x001000300C8FFC01UL, /* 0x0330, */ 0x001000200C8FFC01UL, /* 0x0338, */ 0x001000300C8FFC01UL, }; #endif trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v11.c000066400000000000000000000133671355360272700253160ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "../qos_common.h" #include "../qos_reg.h" #include "qos_init_h3_v11.h" #define RCAR_QOS_VERSION "rev.0.37" #include "qos_init_h3_v11_mstat.h" struct rcar_gen3_dbsc_qos_settings h3_v11_qos[] = { /* BUFCAM settings */ /* DBSC_DBCAM0CNF0 not set */ { DBSC_DBCAM0CNF1, 0x00044218 }, { DBSC_DBCAM0CNF2, 0x000000F4 }, /* DBSC_DBCAM0CNF3 not set */ { DBSC_DBSCHCNT0, 0x080F0037 }, { DBSC_DBSCHCNT1, 0x00001010 }, { DBSC_DBSCHSZ0, 0x00000001 }, { DBSC_DBSCHRW0, 0x22421111 }, /* DDR3 */ { DBSC_SCFCTST2, 0x012F1123 }, /* QoS Settings */ { DBSC_DBSCHQOS00, 0x0000F000 }, { DBSC_DBSCHQOS01, 0x0000E000 }, { DBSC_DBSCHQOS02, 0x00007000 }, { DBSC_DBSCHQOS03, 0x00000000 }, { DBSC_DBSCHQOS40, 0x00000E00 }, { DBSC_DBSCHQOS41, 0x00000DFF }, { DBSC_DBSCHQOS42, 0x00000400 }, { DBSC_DBSCHQOS43, 0x00000200 }, { DBSC_DBSCHQOS90, 0x00000C00 }, { DBSC_DBSCHQOS91, 0x00000BFF }, { DBSC_DBSCHQOS92, 0x00000400 }, { DBSC_DBSCHQOS93, 0x00000200 }, { DBSC_DBSCHQOS130, 0x00000980 }, { DBSC_DBSCHQOS131, 0x0000097F }, { DBSC_DBSCHQOS132, 0x00000300 }, { DBSC_DBSCHQOS133, 0x00000180 }, { DBSC_DBSCHQOS140, 0x00000800 }, { DBSC_DBSCHQOS141, 0x000007FF }, { DBSC_DBSCHQOS142, 0x00000300 }, { DBSC_DBSCHQOS143, 0x00000180 }, { DBSC_DBSCHQOS150, 0x000007D0 }, { DBSC_DBSCHQOS151, 0x000007CF }, { DBSC_DBSCHQOS152, 0x000005D0 }, { DBSC_DBSCHQOS153, 0x000003D0 }, }; void qos_init_h3_v11(void) { rcar_qos_dbsc_setting(h3_v11_qos, ARRAY_SIZE(h3_v11_qos), false); /* DRAM Split Address mapping */ #if (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH) || \ (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO) NOTICE("BL2: DRAM Split is 4ch\n"); io_write_32(AXI_ADSPLCR0, ADSPLCR0_ADRMODE_DEFAULT | ADSPLCR0_SPLITSEL(0xFFU) | ADSPLCR0_AREA(0x1BU) | ADSPLCR0_SWP); io_write_32(AXI_ADSPLCR1, 0x00000000U); io_write_32(AXI_ADSPLCR2, 0xA8A90000U); io_write_32(AXI_ADSPLCR3, 0x00000000U); #elif RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH NOTICE("BL2: DRAM Split is 2ch\n"); io_write_32(AXI_ADSPLCR0, 0x00000000U); io_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT | ADSPLCR0_SPLITSEL(0xFFU) | ADSPLCR0_AREA(0x1BU) | ADSPLCR0_SWP); io_write_32(AXI_ADSPLCR2, 0x00000000U); io_write_32(AXI_ADSPLCR3, 0x00000000U); #else NOTICE("BL2: DRAM Split is OFF\n"); #endif #if !(RCAR_QOS_TYPE == RCAR_QOS_NONE) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION); #endif /* AR Cache setting */ io_write_32(0xE67D1000U, 0x00000100U); io_write_32(0xE67D1008U, 0x00000100U); /* Resource Alloc setting */ #if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH io_write_32(QOSCTRL_RAS, 0x00000020U); #else io_write_32(QOSCTRL_RAS, 0x00000040U); #endif io_write_32(QOSCTRL_FIXTH, 0x000F0005U); io_write_32(QOSCTRL_REGGD, 0x00000000U); #if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH io_write_64(QOSCTRL_DANN, 0x0101010102020201UL); io_write_32(QOSCTRL_DANT, 0x00181008U); #else io_write_64(QOSCTRL_DANN, 0x0101000004040401UL); io_write_32(QOSCTRL_DANT, 0x003C2010U); #endif io_write_32(QOSCTRL_EC, 0x00080001U); /* need for H3 v1.* */ io_write_64(QOSCTRL_EMS, 0x0000000000000000UL); io_write_32(QOSCTRL_INSFC, 0xC7840001U); io_write_32(QOSCTRL_BERR, 0x00000000U); io_write_32(QOSCTRL_RACNT0, 0x00000000U); /* QOSBW setting */ io_write_32(QOSCTRL_SL_INIT, SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK); io_write_32(QOSCTRL_REF_ARS, 0x00330000U); /* QOSBW SRAM setting */ uint32_t i; for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) { io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]); io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]); } for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) { io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]); io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]); } /* 3DG bus Leaf setting */ io_write_32(0xFD820808U, 0x00001234U); io_write_32(0xFD820800U, 0x0000003FU); io_write_32(0xFD821800U, 0x0000003FU); io_write_32(0xFD822800U, 0x0000003FU); io_write_32(0xFD823800U, 0x0000003FU); io_write_32(0xFD824800U, 0x0000003FU); io_write_32(0xFD825800U, 0x0000003FU); io_write_32(0xFD826800U, 0x0000003FU); io_write_32(0xFD827800U, 0x0000003FU); /* VIO bus Leaf setting */ io_write_32(0xFEB89800, 0x00000001U); io_write_32(0xFEB8A800, 0x00000001U); io_write_32(0xFEB8B800, 0x00000001U); io_write_32(0xFEB8C800, 0x00000001U); /* HSC bus Leaf setting */ io_write_32(0xE6430800, 0x00000001U); io_write_32(0xE6431800, 0x00000001U); io_write_32(0xE6432800, 0x00000001U); io_write_32(0xE6433800, 0x00000001U); /* MP bus Leaf setting */ io_write_32(0xEC620800, 0x00000001U); io_write_32(0xEC621800, 0x00000001U); /* PERIE bus Leaf setting */ io_write_32(0xE7760800, 0x00000001U); io_write_32(0xE7768800, 0x00000001U); /* PERIW bus Leaf setting */ io_write_32(0xE6760800, 0x00000001U); io_write_32(0xE6768800, 0x00000001U); /* RT bus Leaf setting */ io_write_32(0xFFC50800, 0x00000001U); io_write_32(0xFFC51800, 0x00000001U); /* CCI bus Leaf setting */ uint32_t modemr = io_read_32(RCAR_MODEMR); modemr &= MODEMR_BOOT_CPU_MASK; if ((modemr == MODEMR_BOOT_CPU_CA57) || (modemr == MODEMR_BOOT_CPU_CA53)) { io_write_32(0xF1300800, 0x00000001U); io_write_32(0xF1340800, 0x00000001U); io_write_32(0xF1380800, 0x00000001U); io_write_32(0xF13C0800, 0x00000001U); } /* Resource Alloc start */ io_write_32(QOSCTRL_RAEN, 0x00000001U); /* QOSBW start */ io_write_32(QOSCTRL_STATQC, 0x00000001U); #else NOTICE("BL2: QoS is None\n"); /* Resource Alloc setting */ io_write_32(QOSCTRL_EC, 0x00080001U); /* need for H3 v1.* */ #endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */ } trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v11.h000066400000000000000000000003671355360272700253170ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef QOS_INIT_H3_V11_H #define QOS_INIT_H3_V11_H void qos_init_h3_v11(void); #endif /* QOS_INIT_H3_V11_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v11_mstat.h000066400000000000000000000174331355360272700265310ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT static const uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001004030000FFFFUL, /* 0x0038, */ 0x001008060000FFFFUL, /* 0x0040, */ 0x001414090000FFFFUL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x001410010000FFFFUL, /* 0x0058, */ 0x00140C0C0000FFFFUL, /* 0x0060, */ 0x00140C0C0000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x001410010000FFFFUL, /* 0x0078, */ 0x001008060000FFFFUL, /* 0x0080, */ 0x001004020000FFFFUL, /* 0x0088, */ 0x001414090000FFFFUL, /* 0x0090, */ 0x00140C0C0000FFFFUL, /* 0x0098, */ 0x001408080000FFFFUL, /* 0x00A0, */ 0x000C08020000FFFFUL, /* 0x00A8, */ 0x000C04010000FFFFUL, /* 0x00B0, */ 0x000C04010000FFFFUL, /* 0x00B8, */ 0x0000000000000000UL, /* 0x00C0, */ 0x000C08020000FFFFUL, /* 0x00C8, */ 0x000C04010000FFFFUL, /* 0x00D0, */ 0x000C04010000FFFFUL, /* 0x00D8, */ 0x000C04030000FFFFUL, /* 0x00E0, */ 0x000C100F0000FFFFUL, /* 0x00E8, */ 0x0000000000000000UL, /* 0x00F0, */ 0x001010080000FFFFUL, /* 0x00F8, */ 0x001010080000FFFFUL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x000C04030000FFFFUL, /* 0x0110, */ 0x001010080000FFFFUL, /* 0x0118, */ 0x001010080000FFFFUL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x000C100E0000FFFFUL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x001008050000FFFFUL, /* 0x0140, */ 0x001008050000FFFFUL, /* 0x0148, */ 0x001008050000FFFFUL, /* 0x0150, */ 0x001008050000FFFFUL, /* 0x0158, */ 0x001008050000FFFFUL, /* 0x0160, */ 0x001008050000FFFFUL, /* 0x0168, */ 0x001008050000FFFFUL, /* 0x0170, */ 0x001008050000FFFFUL, /* 0x0178, */ 0x001004030000FFFFUL, /* 0x0180, */ 0x001004030000FFFFUL, /* 0x0188, */ 0x001004030000FFFFUL, /* 0x0190, */ 0x001014140000FFFFUL, /* 0x0198, */ 0x001014140000FFFFUL, /* 0x01A0, */ 0x001008050000FFFFUL, /* 0x01A8, */ 0x001008050000FFFFUL, /* 0x01B0, */ 0x001008050000FFFFUL, /* 0x01B8, */ 0x0000000000000000UL, /* 0x01C0, */ 0x0000000000000000UL, /* 0x01C8, */ 0x0000000000000000UL, /* 0x01D0, */ 0x0000000000000000UL, /* 0x01D8, */ 0x0000000000000000UL, /* 0x01E0, */ 0x0000000000000000UL, /* 0x01E8, */ 0x0000000000000000UL, /* 0x01F0, */ 0x0000000000000000UL, /* 0x01F8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x001408010000FFFFUL, /* 0x0270, */ 0x001404010000FFFFUL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001408010000FFFFUL, /* 0x0298, */ 0x001404010000FFFFUL, /* 0x02A0, */ 0x000C04010000FFFFUL, /* 0x02A8, */ 0x000C04010000FFFFUL, /* 0x02B0, */ 0x001404010000FFFFUL, /* 0x02B8, */ 0x0000000000000000UL, /* 0x02C0, */ 0x0000000000000000UL, /* 0x02C8, */ 0x0000000000000000UL, /* 0x02D0, */ 0x000C04010000FFFFUL, /* 0x02D8, */ 0x000C04010000FFFFUL, /* 0x02E0, */ 0x001404010000FFFFUL, /* 0x02E8, */ 0x0000000000000000UL, /* 0x02F0, */ 0x0000000000000000UL, /* 0x02F8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, }; static const uint64_t mstat_be[] = { /* 0x0000, */ 0x001200100C89C401UL, /* 0x0008, */ 0x001200100C89C401UL, /* 0x0010, */ 0x001200100C89C401UL, /* 0x0018, */ 0x001200100C89C401UL, /* 0x0020, */ 0x001100100C803401UL, /* 0x0028, */ 0x001100100C80FC01UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x001100100C803401UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00A0, */ 0x0000000000000000UL, /* 0x00A8, */ 0x0000000000000000UL, /* 0x00B0, */ 0x0000000000000000UL, /* 0x00B8, */ 0x001100100C803401UL, /* 0x00C0, */ 0x0000000000000000UL, /* 0x00C8, */ 0x0000000000000000UL, /* 0x00D0, */ 0x0000000000000000UL, /* 0x00D8, */ 0x0000000000000000UL, /* 0x00E0, */ 0x0000000000000000UL, /* 0x00E8, */ 0x001100100C803401UL, /* 0x00F0, */ 0x0000000000000000UL, /* 0x00F8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x001100100C803401UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01A0, */ 0x0000000000000000UL, /* 0x01A8, */ 0x0000000000000000UL, /* 0x01B0, */ 0x0000000000000000UL, /* 0x01B8, */ 0x001100100C803401UL, /* 0x01C0, */ 0x001100800C8FFC01UL, /* 0x01C8, */ 0x001100800C8FFC01UL, /* 0x01D0, */ 0x001100800C8FFC01UL, /* 0x01D8, */ 0x001100800C8FFC01UL, /* 0x01E0, */ 0x001100100C80FC01UL, /* 0x01E8, */ 0x001200100C80FC01UL, /* 0x01F0, */ 0x001100100C80FC01UL, /* 0x01F8, */ 0x001100100C803401UL, /* 0x0200, */ 0x001100100C80FC01UL, /* 0x0208, */ 0x001200100C80FC01UL, /* 0x0210, */ 0x001100100C80FC01UL, /* 0x0218, */ 0x001100100C825801UL, /* 0x0220, */ 0x001100100C825801UL, /* 0x0228, */ 0x001100100C803401UL, /* 0x0230, */ 0x001100100C825801UL, /* 0x0238, */ 0x001100100C825801UL, /* 0x0240, */ 0x001200100C8BB801UL, /* 0x0248, */ 0x001100200C8FFC01UL, /* 0x0250, */ 0x001200100C8BB801UL, /* 0x0258, */ 0x001100200C8FFC01UL, /* 0x0260, */ 0x001100100C84E401UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x001100100C81F401UL, /* 0x0280, */ 0x001100100C803401UL, /* 0x0288, */ 0x001100100C803401UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02A0, */ 0x0000000000000000UL, /* 0x02A8, */ 0x0000000000000000UL, /* 0x02B0, */ 0x0000000000000000UL, /* 0x02B8, */ 0x001100100C803401UL, /* 0x02C0, */ 0x001100100C803401UL, /* 0x02C8, */ 0x001100100C803401UL, /* 0x02D0, */ 0x0000000000000000UL, /* 0x02D8, */ 0x0000000000000000UL, /* 0x02E0, */ 0x0000000000000000UL, /* 0x02E8, */ 0x001100100C803401UL, /* 0x02F0, */ 0x001100300C8FFC01UL, /* 0x02F8, */ 0x001100500C8FFC01UL, /* 0x0300, */ 0x001100100C803401UL, /* 0x0308, */ 0x001100300C8FFC01UL, /* 0x0310, */ 0x001100500C8FFC01UL, /* 0x0318, */ 0x001200100C803401UL, /* 0x0320, */ 0x001100300C8FFC01UL, /* 0x0328, */ 0x001100500C8FFC01UL, /* 0x0330, */ 0x001100300C8FFC01UL, /* 0x0338, */ 0x001100500C8FFC01UL, }; #endif trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v20.c000066400000000000000000000161471355360272700253150ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "../qos_common.h" #include "../qos_reg.h" #include "qos_init_h3_v20.h" #define RCAR_QOS_VERSION "rev.0.21" #define QOSWT_TIME_BANK0 20000000U /* unit:ns */ #define QOSWT_WTEN_ENABLE 0x1U #define QOSCTRL_REF_ARS_ARBSTOPCYCLE_H3_20 (SL_INIT_SSLOTCLK_H3_20 - 0x5U) #define OSWT_WTREF_SLOT0_EN_REQ1_SLOT 3U #define OSWT_WTREF_SLOT0_EN_REQ2_SLOT 9U #define QOSWT_WTREF_SLOT0_EN \ ((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) | \ (0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT)) #define QOSWT_WTREF_SLOT1_EN \ ((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) | \ (0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT)) #define QOSWT_WTSET0_REQ_SSLOT0 5U #define WT_BASE_SUB_SLOT_NUM0 12U #define QOSWT_WTSET0_PERIOD0_H3_20 \ ((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_H3_20) - 1U) #define QOSWT_WTSET0_SSLOT0 (QOSWT_WTSET0_REQ_SSLOT0 - 1U) #define QOSWT_WTSET0_SLOTSLOT0 (WT_BASE_SUB_SLOT_NUM0 - 1U) #define QOSWT_WTSET1_PERIOD1_H3_20 \ ((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_H3_20) - 1U) #define QOSWT_WTSET1_SSLOT1 (QOSWT_WTSET0_REQ_SSLOT0 - 1U) #define QOSWT_WTSET1_SLOTSLOT1 (WT_BASE_SUB_SLOT_NUM0 - 1U) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT #if RCAR_REF_INT == RCAR_REF_DEFAULT #include "qos_init_h3_v20_mstat195.h" #else #include "qos_init_h3_v20_mstat390.h" #endif #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE #if RCAR_REF_INT == RCAR_REF_DEFAULT #include "qos_init_h3_v20_qoswt195.h" #else #include "qos_init_h3_v20_qoswt390.h" #endif #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ #endif struct rcar_gen3_dbsc_qos_settings h3_v20_qos[] = { /* BUFCAM settings */ { DBSC_DBCAM0CNF1, 0x00043218U }, { DBSC_DBCAM0CNF2, 0x000000F4U }, { DBSC_DBCAM0CNF3, 0x00000000U }, { DBSC_DBSCHCNT0, 0x000F0037U }, { DBSC_DBSCHSZ0, 0x00000001U }, { DBSC_DBSCHRW0, 0x22421111U }, /* DDR3 */ { DBSC_SCFCTST2, 0x012F1123U }, /* QoS Settings */ { DBSC_DBSCHQOS00, 0x00000F00U }, { DBSC_DBSCHQOS01, 0x00000B00U }, { DBSC_DBSCHQOS02, 0x00000000U }, { DBSC_DBSCHQOS03, 0x00000000U }, { DBSC_DBSCHQOS40, 0x00000300U }, { DBSC_DBSCHQOS41, 0x000002F0U }, { DBSC_DBSCHQOS42, 0x00000200U }, { DBSC_DBSCHQOS43, 0x00000100U }, { DBSC_DBSCHQOS90, 0x00000100U }, { DBSC_DBSCHQOS91, 0x000000F0U }, { DBSC_DBSCHQOS92, 0x000000A0U }, { DBSC_DBSCHQOS93, 0x00000040U }, { DBSC_DBSCHQOS120, 0x00000040U }, { DBSC_DBSCHQOS121, 0x00000030U }, { DBSC_DBSCHQOS122, 0x00000020U }, { DBSC_DBSCHQOS123, 0x00000010U }, { DBSC_DBSCHQOS130, 0x00000100U }, { DBSC_DBSCHQOS131, 0x000000F0U }, { DBSC_DBSCHQOS132, 0x000000A0U }, { DBSC_DBSCHQOS133, 0x00000040U }, { DBSC_DBSCHQOS140, 0x000000C0U }, { DBSC_DBSCHQOS141, 0x000000B0U }, { DBSC_DBSCHQOS142, 0x00000080U }, { DBSC_DBSCHQOS143, 0x00000040U }, { DBSC_DBSCHQOS150, 0x00000040U }, { DBSC_DBSCHQOS151, 0x00000030U }, { DBSC_DBSCHQOS152, 0x00000020U }, { DBSC_DBSCHQOS153, 0x00000010U }, }; void qos_init_h3_v20(void) { rcar_qos_dbsc_setting(h3_v20_qos, ARRAY_SIZE(h3_v20_qos), true); /* DRAM Split Address mapping */ #if (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH) || \ (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO) NOTICE("BL2: DRAM Split is 4ch\n"); io_write_32(AXI_ADSPLCR0, ADSPLCR0_ADRMODE_DEFAULT | ADSPLCR0_SPLITSEL(0xFFU) | ADSPLCR0_AREA(0x1BU) | ADSPLCR0_SWP); io_write_32(AXI_ADSPLCR1, 0x00000000U); io_write_32(AXI_ADSPLCR2, 0x00001054U); io_write_32(AXI_ADSPLCR3, 0x00000000U); #elif RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH NOTICE("BL2: DRAM Split is 2ch\n"); io_write_32(AXI_ADSPLCR0, 0x00000000U); io_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT | ADSPLCR0_SPLITSEL(0xFFU) | ADSPLCR0_AREA(0x1BU) | ADSPLCR0_SWP); io_write_32(AXI_ADSPLCR2, 0x00001004U); io_write_32(AXI_ADSPLCR3, 0x00000000U); #else NOTICE("BL2: DRAM Split is OFF\n"); #endif #if !(RCAR_QOS_TYPE == RCAR_QOS_NONE) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION); #endif #if RCAR_REF_INT == RCAR_REF_DEFAULT NOTICE("BL2: DRAM refresh interval 1.95 usec\n"); #else NOTICE("BL2: DRAM refresh interval 3.9 usec\n"); #endif #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE NOTICE("BL2: Periodic Write DQ Training\n"); #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ io_write_32(QOSCTRL_RAS, 0x00000044U); io_write_64(QOSCTRL_DANN, 0x0404010002020201UL); io_write_32(QOSCTRL_DANT, 0x0020100AU); io_write_32(QOSCTRL_INSFC, 0x06330001U); io_write_32(QOSCTRL_RACNT0, 0x00010003U); /* GPU Boost Mode */ io_write_32(QOSCTRL_STATGEN0, 0x00000001U); io_write_32(QOSCTRL_SL_INIT, SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK_H3_20); #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE io_write_32(QOSCTRL_REF_ARS, ((QOSCTRL_REF_ARS_ARBSTOPCYCLE_H3_20 << 16))); #else io_write_32(QOSCTRL_REF_ARS, 0x00330000U); #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ uint32_t i; for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) { io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]); io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]); } for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) { io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]); io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]); } #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE for (i = 0U; i < ARRAY_SIZE(qoswt_fix); i++) { io_write_64(QOSWT_FIX_WTQOS_BANK0 + i * 8, qoswt_fix[i]); io_write_64(QOSWT_FIX_WTQOS_BANK1 + i * 8, qoswt_fix[i]); } for (i = 0U; i < ARRAY_SIZE(qoswt_be); i++) { io_write_64(QOSWT_BE_WTQOS_BANK0 + i * 8, qoswt_be[i]); io_write_64(QOSWT_BE_WTQOS_BANK1 + i * 8, qoswt_be[i]); } #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ /* 3DG bus Leaf setting */ io_write_32(GPU_ACT0, 0x00000000U); io_write_32(GPU_ACT1, 0x00000000U); io_write_32(GPU_ACT2, 0x00000000U); io_write_32(GPU_ACT3, 0x00000000U); io_write_32(GPU_ACT4, 0x00000000U); io_write_32(GPU_ACT5, 0x00000000U); io_write_32(GPU_ACT6, 0x00000000U); io_write_32(GPU_ACT7, 0x00000000U); /* RT bus Leaf setting */ io_write_32(RT_ACT0, 0x00000000U); io_write_32(RT_ACT1, 0x00000000U); /* CCI bus Leaf setting */ io_write_32(CPU_ACT0, 0x00000003U); io_write_32(CPU_ACT1, 0x00000003U); io_write_32(CPU_ACT2, 0x00000003U); io_write_32(CPU_ACT3, 0x00000003U); io_write_32(QOSCTRL_RAEN, 0x00000001U); #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE /* re-write training setting */ io_write_32(QOSWT_WTREF, ((QOSWT_WTREF_SLOT1_EN << 16) | QOSWT_WTREF_SLOT0_EN)); io_write_32(QOSWT_WTSET0, ((QOSWT_WTSET0_PERIOD0_H3_20 << 16) | (QOSWT_WTSET0_SSLOT0 << 8) | QOSWT_WTSET0_SLOTSLOT0)); io_write_32(QOSWT_WTSET1, ((QOSWT_WTSET1_PERIOD1_H3_20 << 16) | (QOSWT_WTSET1_SSLOT1 << 8) | QOSWT_WTSET1_SLOTSLOT1)); io_write_32(QOSWT_WTEN, QOSWT_WTEN_ENABLE); #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ io_write_32(QOSCTRL_STATQC, 0x00000001U); #else NOTICE("BL2: QoS is None\n"); io_write_32(QOSCTRL_RAEN, 0x00000001U); #endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */ } trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v20.h000066400000000000000000000003671355360272700253170ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef QOS_INIT_H3_V20_H #define QOS_INIT_H3_V20_H void qos_init_h3_v20(void); #endif /* QOS_INIT_H3_V20_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_mstat195.h000066400000000000000000000202231355360272700267570ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001004040000FFFFUL, /* 0x0038, */ 0x001008070000FFFFUL, /* 0x0040, */ 0x001424110000FFFFUL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x001404010000FFFFUL, /* 0x0058, */ 0x001410100000FFFFUL, /* 0x0060, */ 0x0014100D0000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x001404010000FFFFUL, /* 0x0078, */ 0x001008070000FFFFUL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001424110000FFFFUL, /* 0x0090, */ 0x0014100D0000FFFFUL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x000C04020000FFFFUL, /* 0x00a8, */ 0x000C04010000FFFFUL, /* 0x00b0, */ 0x000C04010000FFFFUL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x000C04020000FFFFUL, /* 0x00c8, */ 0x000C04010000FFFFUL, /* 0x00d0, */ 0x000C04010000FFFFUL, /* 0x00d8, */ 0x001024090000FFFFUL, /* 0x00e0, */ 0x00100C090000FFFFUL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x001024090000FFFFUL, /* 0x00f8, */ 0x000C08070000FFFFUL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x00100C090000FFFFUL, /* 0x0118, */ 0x000C10100000FFFFUL, /* 0x0120, */ 0x000C10100000FFFFUL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x00100C0B0000FFFFUL, /* 0x0140, */ 0x00100C0B0000FFFFUL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0010100D0000FFFFUL, /* 0x0158, */ 0x0010100D0000FFFFUL, /* 0x0160, */ 0x00100C0B0000FFFFUL, /* 0x0168, */ 0x00100C0B0000FFFFUL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x001008060000FFFFUL, /* 0x0180, */ 0x001008060000FFFFUL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x00102C2C0000FFFFUL, /* 0x0198, */ 0x00102C2C0000FFFFUL, /* 0x01a0, */ 0x00100C0B0000FFFFUL, /* 0x01a8, */ 0x00100C0B0000FFFFUL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x000C04010000FFFFUL, /* 0x01c8, */ 0x000C04010000FFFFUL, /* 0x01d0, */ 0x000C04010000FFFFUL, /* 0x01d8, */ 0x000C04010000FFFFUL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x000C04010000FFFFUL, /* 0x01f0, */ 0x000C04010000FFFFUL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x000C04010000FFFFUL, /* 0x0210, */ 0x000C04010000FFFFUL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C08020000FFFFUL, /* 0x0268, */ 0x001408010000FFFFUL, /* 0x0270, */ 0x001404010000FFFFUL, /* 0x0278, */ 0x000C04010000FFFFUL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001408010000FFFFUL, /* 0x0298, */ 0x001404010000FFFFUL, /* 0x02a0, */ 0x000C04010000FFFFUL, /* 0x02a8, */ 0x000C04010000FFFFUL, /* 0x02b0, */ 0x001408010000FFFFUL, /* 0x02b8, */ 0x000C04010000FFFFUL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x000C04010000FFFFUL, /* 0x02d8, */ 0x000C04010000FFFFUL, /* 0x02e0, */ 0x001408010000FFFFUL, /* 0x02e8, */ 0x000C04010000FFFFUL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; static uint64_t mstat_be[] = { /* 0x0000, */ 0x001200200BDFFC01UL, /* 0x0008, */ 0x001200200BDFFC01UL, /* 0x0010, */ 0x001200200BDFFC01UL, /* 0x0018, */ 0x001200200BDFFC01UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x001200100BD0FC01UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x002100700BDFFC01UL, /* 0x01c8, */ 0x002100700BDFFC01UL, /* 0x01d0, */ 0x002100700BDFFC01UL, /* 0x01d8, */ 0x002100700BDFFC01UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x002100200BDFFC01UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x002100200BDFFC01UL, /* 0x0218, */ 0x001100200BDFFC01UL, /* 0x0220, */ 0x001100200BDFFC01UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x001100200BDFFC01UL, /* 0x0238, */ 0x001100200BDFFC01UL, /* 0x0240, */ 0x001200200BDFFC01UL, /* 0x0248, */ 0x001100200BDFFC01UL, /* 0x0250, */ 0x001200200BDFFC01UL, /* 0x0258, */ 0x001100200BDFFC01UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x001100400BDFFC01UL, /* 0x02f8, */ 0x001100600BDFFC01UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x001100400BDFFC01UL, /* 0x0310, */ 0x001100600BDFFC01UL, /* 0x0318, */ 0x001200100BD03401UL, /* 0x0320, */ 0x001100400BDFFC01UL, /* 0x0328, */ 0x001100600BDFFC01UL, /* 0x0330, */ 0x001100400BDFFC01UL, /* 0x0338, */ 0x001100600BDFFC01UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x001200100BD0FC01UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_mstat390.h000066400000000000000000000202231355360272700267540ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001008070000FFFFUL, /* 0x0038, */ 0x0010100D0000FFFFUL, /* 0x0040, */ 0x001444210000FFFFUL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x001404010000FFFFUL, /* 0x0058, */ 0x0014201F0000FFFFUL, /* 0x0060, */ 0x00141C190000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x001404010000FFFFUL, /* 0x0078, */ 0x0010100D0000FFFFUL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001444210000FFFFUL, /* 0x0090, */ 0x00141C190000FFFFUL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x000C08040000FFFFUL, /* 0x00a8, */ 0x000C04020000FFFFUL, /* 0x00b0, */ 0x000C04020000FFFFUL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x000C08040000FFFFUL, /* 0x00c8, */ 0x000C04020000FFFFUL, /* 0x00d0, */ 0x000C04020000FFFFUL, /* 0x00d8, */ 0x001044110000FFFFUL, /* 0x00e0, */ 0x001014110000FFFFUL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x001044110000FFFFUL, /* 0x00f8, */ 0x000C100D0000FFFFUL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x001014110000FFFFUL, /* 0x0118, */ 0x000C20200000FFFFUL, /* 0x0120, */ 0x000C20200000FFFFUL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x001018150000FFFFUL, /* 0x0140, */ 0x001018150000FFFFUL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x00101C190000FFFFUL, /* 0x0158, */ 0x00101C190000FFFFUL, /* 0x0160, */ 0x001018150000FFFFUL, /* 0x0168, */ 0x001018150000FFFFUL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x00100C0B0000FFFFUL, /* 0x0180, */ 0x00100C0B0000FFFFUL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x001058570000FFFFUL, /* 0x0198, */ 0x001058570000FFFFUL, /* 0x01a0, */ 0x001018150000FFFFUL, /* 0x01a8, */ 0x001018150000FFFFUL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x000C04010000FFFFUL, /* 0x01c8, */ 0x000C04010000FFFFUL, /* 0x01d0, */ 0x000C04010000FFFFUL, /* 0x01d8, */ 0x000C04010000FFFFUL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x000C04010000FFFFUL, /* 0x01f0, */ 0x000C04010000FFFFUL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x000C04010000FFFFUL, /* 0x0210, */ 0x000C04010000FFFFUL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C0C030000FFFFUL, /* 0x0268, */ 0x001410010000FFFFUL, /* 0x0270, */ 0x001404010000FFFFUL, /* 0x0278, */ 0x000C08020000FFFFUL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001410010000FFFFUL, /* 0x0298, */ 0x001404010000FFFFUL, /* 0x02a0, */ 0x000C04010000FFFFUL, /* 0x02a8, */ 0x000C04010000FFFFUL, /* 0x02b0, */ 0x00140C010000FFFFUL, /* 0x02b8, */ 0x000C04010000FFFFUL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x000C04010000FFFFUL, /* 0x02d8, */ 0x000C04010000FFFFUL, /* 0x02e0, */ 0x00140C010000FFFFUL, /* 0x02e8, */ 0x000C04010000FFFFUL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; static uint64_t mstat_be[] = { /* 0x0000, */ 0x0012003005EFFC01UL, /* 0x0008, */ 0x0012003005EFFC01UL, /* 0x0010, */ 0x0012003005EFFC01UL, /* 0x0018, */ 0x0012003005EFFC01UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0012001005E0FC01UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x002100D005EFFC01UL, /* 0x01c8, */ 0x002100D005EFFC01UL, /* 0x01d0, */ 0x002100D005EFFC01UL, /* 0x01d8, */ 0x002100D005EFFC01UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0021003005EFFC01UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0021003005EFFC01UL, /* 0x0218, */ 0x0011003005EFFC01UL, /* 0x0220, */ 0x0011003005EFFC01UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0011003005EFFC01UL, /* 0x0238, */ 0x0011003005EFFC01UL, /* 0x0240, */ 0x0012003005EFFC01UL, /* 0x0248, */ 0x0011003005EFFC01UL, /* 0x0250, */ 0x0012003005EFFC01UL, /* 0x0258, */ 0x0011003005EFFC01UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0011007005EFFC01UL, /* 0x02f8, */ 0x001100B005EFFC01UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0011007005EFFC01UL, /* 0x0310, */ 0x001100B005EFFC01UL, /* 0x0318, */ 0x0012001005E03401UL, /* 0x0320, */ 0x0011007005EFFC01UL, /* 0x0328, */ 0x001100B005EFFC01UL, /* 0x0330, */ 0x0011007005EFFC01UL, /* 0x0338, */ 0x001100B005EFFC01UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0012001005E0FC01UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_qoswt195.h000066400000000000000000000202231355360272700270040ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t qoswt_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001004040000C010UL, /* 0x0038, */ 0x001008070000C010UL, /* 0x0040, */ 0x001424110000FFF0UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x001410100000C010UL, /* 0x0060, */ 0x0014100D0000C010UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x001008070000C010UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001424110000FFF0UL, /* 0x0090, */ 0x0014100D0000C010UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C08020000FFF0UL, /* 0x0268, */ 0x001408010000FFF0UL, /* 0x0270, */ 0x001404010000FFF0UL, /* 0x0278, */ 0x000C04010000FFF0UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001408010000FFF0UL, /* 0x0298, */ 0x001404010000FFF0UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; static uint64_t qoswt_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v20_qoswt390.h000066400000000000000000000202231355360272700270010ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t qoswt_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001008070000C010UL, /* 0x0038, */ 0x0010100D0000C010UL, /* 0x0040, */ 0x001444210000FFF0UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0014201F0000C010UL, /* 0x0060, */ 0x00141C190000C010UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0010100D0000C010UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001444210000FFF0UL, /* 0x0090, */ 0x00141C190000C010UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C0C030000FFF0UL, /* 0x0268, */ 0x001410010000FFF0UL, /* 0x0270, */ 0x001404010000FFF0UL, /* 0x0278, */ 0x000C08020000FFF0UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001410010000FFF0UL, /* 0x0298, */ 0x001404010000FFF0UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; static uint64_t qoswt_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v30.c000066400000000000000000000161171355360272700253130ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "../qos_common.h" #include "../qos_reg.h" #include "qos_init_h3_v30.h" #define RCAR_QOS_VERSION "rev.0.11" #define QOSWT_TIME_BANK0 20000000U /* unit:ns */ #define QOSWT_WTEN_ENABLE 0x1U #define QOSCTRL_REF_ARS_ARBSTOPCYCLE_H3_30 (SL_INIT_SSLOTCLK_H3_30 - 0x5U) #define OSWT_WTREF_SLOT0_EN_REQ1_SLOT 3U #define OSWT_WTREF_SLOT0_EN_REQ2_SLOT 9U #define QOSWT_WTREF_SLOT0_EN \ ((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) | \ (0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT)) #define QOSWT_WTREF_SLOT1_EN \ ((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) | \ (0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT)) #define QOSWT_WTSET0_REQ_SSLOT0 5U #define WT_BASE_SUB_SLOT_NUM0 12U #define QOSWT_WTSET0_PERIOD0_H3_30 \ ((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_H3_30) - 1U) #define QOSWT_WTSET0_SSLOT0 (QOSWT_WTSET0_REQ_SSLOT0 - 1U) #define QOSWT_WTSET0_SLOTSLOT0 (WT_BASE_SUB_SLOT_NUM0 - 1U) #define QOSWT_WTSET1_PERIOD1_H3_30 (QOSWT_WTSET0_PERIOD0_H3_30) #define QOSWT_WTSET1_SSLOT1 (QOSWT_WTSET0_SSLOT0) #define QOSWT_WTSET1_SLOTSLOT1 (QOSWT_WTSET0_SLOTSLOT0) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT #if RCAR_REF_INT == RCAR_REF_DEFAULT #include "qos_init_h3_v30_mstat195.h" #else #include "qos_init_h3_v30_mstat390.h" #endif #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE #if RCAR_REF_INT == RCAR_REF_DEFAULT #include "qos_init_h3_v30_qoswt195.h" #else #include "qos_init_h3_v30_qoswt390.h" #endif #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ #endif struct rcar_gen3_dbsc_qos_settings h3_v30_qos[] = { /* BUFCAM settings */ { DBSC_DBCAM0CNF1, 0x00043218U }, { DBSC_DBCAM0CNF2, 0x000000F4U }, { DBSC_DBCAM0CNF3, 0x00000000U }, { DBSC_DBSCHCNT0, 0x000F0037U }, { DBSC_DBSCHSZ0, 0x00000001U }, { DBSC_DBSCHRW0, 0x22421111U }, /* DDR3 */ { DBSC_SCFCTST2, 0x012F1123U }, /* QoS Settings */ { DBSC_DBSCHQOS00, 0x00000F00U }, { DBSC_DBSCHQOS01, 0x00000B00U }, { DBSC_DBSCHQOS02, 0x00000000U }, { DBSC_DBSCHQOS03, 0x00000000U }, { DBSC_DBSCHQOS40, 0x00000300U }, { DBSC_DBSCHQOS41, 0x000002F0U }, { DBSC_DBSCHQOS42, 0x00000200U }, { DBSC_DBSCHQOS43, 0x00000100U }, { DBSC_DBSCHQOS90, 0x00000100U }, { DBSC_DBSCHQOS91, 0x000000F0U }, { DBSC_DBSCHQOS92, 0x000000A0U }, { DBSC_DBSCHQOS93, 0x00000040U }, { DBSC_DBSCHQOS120, 0x00000040U }, { DBSC_DBSCHQOS121, 0x00000030U }, { DBSC_DBSCHQOS122, 0x00000020U }, { DBSC_DBSCHQOS123, 0x00000010U }, { DBSC_DBSCHQOS130, 0x00000100U }, { DBSC_DBSCHQOS131, 0x000000F0U }, { DBSC_DBSCHQOS132, 0x000000A0U }, { DBSC_DBSCHQOS133, 0x00000040U }, { DBSC_DBSCHQOS140, 0x000000C0U }, { DBSC_DBSCHQOS141, 0x000000B0U }, { DBSC_DBSCHQOS142, 0x00000080U }, { DBSC_DBSCHQOS143, 0x00000040U }, { DBSC_DBSCHQOS150, 0x00000040U }, { DBSC_DBSCHQOS151, 0x00000030U }, { DBSC_DBSCHQOS152, 0x00000020U }, { DBSC_DBSCHQOS153, 0x00000010U }, }; void qos_init_h3_v30(void) { unsigned int split_area; rcar_qos_dbsc_setting(h3_v30_qos, ARRAY_SIZE(h3_v30_qos), true); #if RCAR_DRAM_LPDDR4_MEMCONF == 0 /* 1GB */ split_area = 0x1BU; #else /* default 2GB */ split_area = 0x1CU; #endif /* DRAM Split Address mapping */ #if (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH) || \ (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO) NOTICE("BL2: DRAM Split is 4ch(DDR %x)\n", (int)qos_init_ddr_phyvalid); io_write_32(AXI_ADSPLCR0, ADSPLCR0_ADRMODE_DEFAULT | ADSPLCR0_SPLITSEL(0xFFU) | ADSPLCR0_AREA(split_area) | ADSPLCR0_SWP); io_write_32(AXI_ADSPLCR1, 0x00000000U); io_write_32(AXI_ADSPLCR2, 0x00001054U); io_write_32(AXI_ADSPLCR3, 0x00000000U); #elif RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH NOTICE("BL2: DRAM Split is 2ch(DDR %x)\n", (int)qos_init_ddr_phyvalid); io_write_32(AXI_ADSPLCR0, ADSPLCR0_AREA(split_area)); io_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT | ADSPLCR0_SPLITSEL(0xFFU) | ADSPLCR0_AREA(split_area) | ADSPLCR0_SWP); io_write_32(AXI_ADSPLCR2, 0x00001004U); io_write_32(AXI_ADSPLCR3, 0x00000000U); #else io_write_32(AXI_ADSPLCR0, ADSPLCR0_AREA(split_area)); NOTICE("BL2: DRAM Split is OFF(DDR %x)\n", (int)qos_init_ddr_phyvalid); #endif #if !(RCAR_QOS_TYPE == RCAR_QOS_NONE) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION); #endif #if RCAR_REF_INT == RCAR_REF_DEFAULT NOTICE("BL2: DRAM refresh interval 1.95 usec\n"); #else NOTICE("BL2: DRAM refresh interval 3.9 usec\n"); #endif #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE NOTICE("BL2: Periodic Write DQ Training\n"); #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ io_write_32(QOSCTRL_RAS, 0x00000044U); io_write_64(QOSCTRL_DANN, 0x0404010002020201UL); io_write_32(QOSCTRL_DANT, 0x0020100AU); io_write_32(QOSCTRL_FSS, 0x0000000AU); io_write_32(QOSCTRL_INSFC, 0x06330001U); io_write_32(QOSCTRL_RACNT0, 0x00010003U); /* GPU Boost Mode */ io_write_32(QOSCTRL_STATGEN0, 0x00000001U); io_write_32(QOSCTRL_SL_INIT, SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK_H3_30); io_write_32(QOSCTRL_REF_ARS, ((QOSCTRL_REF_ARS_ARBSTOPCYCLE_H3_30 << 16))); uint32_t i; for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) { io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]); io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]); } for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) { io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]); io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]); } #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE for (i = 0U; i < ARRAY_SIZE(qoswt_fix); i++) { io_write_64(QOSWT_FIX_WTQOS_BANK0 + i * 8, qoswt_fix[i]); io_write_64(QOSWT_FIX_WTQOS_BANK1 + i * 8, qoswt_fix[i]); } for (i = 0U; i < ARRAY_SIZE(qoswt_be); i++) { io_write_64(QOSWT_BE_WTQOS_BANK0 + i * 8, qoswt_be[i]); io_write_64(QOSWT_BE_WTQOS_BANK1 + i * 8, qoswt_be[i]); } #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ /* AXI setting */ io_write_32(AXI_MMCR, 0x00010008U); io_write_32(AXI_TR3CR, 0x00010000U); io_write_32(AXI_TR4CR, 0x00010000U); /* RT bus Leaf setting */ io_write_32(RT_ACT0, 0x00000000U); io_write_32(RT_ACT1, 0x00000000U); /* CCI bus Leaf setting */ io_write_32(CPU_ACT0, 0x00000003U); io_write_32(CPU_ACT1, 0x00000003U); io_write_32(CPU_ACT2, 0x00000003U); io_write_32(CPU_ACT3, 0x00000003U); io_write_32(QOSCTRL_RAEN, 0x00000001U); #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE /* re-write training setting */ io_write_32(QOSWT_WTREF, ((QOSWT_WTREF_SLOT1_EN << 16) | QOSWT_WTREF_SLOT0_EN)); io_write_32(QOSWT_WTSET0, ((QOSWT_WTSET0_PERIOD0_H3_30 << 16) | (QOSWT_WTSET0_SSLOT0 << 8) | QOSWT_WTSET0_SLOTSLOT0)); io_write_32(QOSWT_WTSET1, ((QOSWT_WTSET1_PERIOD1_H3_30 << 16) | (QOSWT_WTSET1_SSLOT1 << 8) | QOSWT_WTSET1_SLOTSLOT1)); io_write_32(QOSWT_WTEN, QOSWT_WTEN_ENABLE); #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ io_write_32(QOSCTRL_STATQC, 0x00000001U); #else NOTICE("BL2: QoS is None\n"); io_write_32(QOSCTRL_RAEN, 0x00000001U); #endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */ } trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v30.h000066400000000000000000000003621355360272700253130ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef QOS_INIT_H3_V30_H #define QOS_INIT_H3_V30_H void qos_init_h3_v30(void); #endif /* QOS_INIT_H3_V30_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_mstat195.h000066400000000000000000000202231355360272700267600ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001004040000FFFFUL, /* 0x0038, */ 0x001008070000FFFFUL, /* 0x0040, */ 0x001410070000FFFFUL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x001404010000FFFFUL, /* 0x0058, */ 0x0014100D0000FFFFUL, /* 0x0060, */ 0x0014100D0000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x001404010000FFFFUL, /* 0x0078, */ 0x001008070000FFFFUL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001410070000FFFFUL, /* 0x0090, */ 0x0014100D0000FFFFUL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x000C04020000FFFFUL, /* 0x00a8, */ 0x000C04010000FFFFUL, /* 0x00b0, */ 0x000C04010000FFFFUL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x000C04020000FFFFUL, /* 0x00c8, */ 0x000C04010000FFFFUL, /* 0x00d0, */ 0x000C04010000FFFFUL, /* 0x00d8, */ 0x001024090000FFFFUL, /* 0x00e0, */ 0x00100C090000FFFFUL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x001024090000FFFFUL, /* 0x00f8, */ 0x000C100D0000FFFFUL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x00100C090000FFFFUL, /* 0x0118, */ 0x000C1C1B0000FFFFUL, /* 0x0120, */ 0x000C1C1B0000FFFFUL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x00100C0B0000FFFFUL, /* 0x0140, */ 0x00100C0B0000FFFFUL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0010100D0000FFFFUL, /* 0x0158, */ 0x0010100D0000FFFFUL, /* 0x0160, */ 0x00100C0B0000FFFFUL, /* 0x0168, */ 0x00100C0B0000FFFFUL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x001008060000FFFFUL, /* 0x0180, */ 0x001008060000FFFFUL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x00102C2C0000FFFFUL, /* 0x0198, */ 0x00102C2C0000FFFFUL, /* 0x01a0, */ 0x00100C0B0000FFFFUL, /* 0x01a8, */ 0x00100C0B0000FFFFUL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x000C04010000FFFFUL, /* 0x01c8, */ 0x000C04010000FFFFUL, /* 0x01d0, */ 0x000C04010000FFFFUL, /* 0x01d8, */ 0x000C04010000FFFFUL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x000C04010000FFFFUL, /* 0x01f0, */ 0x000C04010000FFFFUL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x000C04010000FFFFUL, /* 0x0210, */ 0x000C04010000FFFFUL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C08020000FFFFUL, /* 0x0268, */ 0x001408010000FFFFUL, /* 0x0270, */ 0x001404010000FFFFUL, /* 0x0278, */ 0x000C04010000FFFFUL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001408010000FFFFUL, /* 0x0298, */ 0x001404010000FFFFUL, /* 0x02a0, */ 0x000C04010000FFFFUL, /* 0x02a8, */ 0x000C04010000FFFFUL, /* 0x02b0, */ 0x001408010000FFFFUL, /* 0x02b8, */ 0x000C04010000FFFFUL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x000C04010000FFFFUL, /* 0x02d8, */ 0x000C04010000FFFFUL, /* 0x02e0, */ 0x001408010000FFFFUL, /* 0x02e8, */ 0x000C04010000FFFFUL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; static uint64_t mstat_be[] = { /* 0x0000, */ 0x001200600BDFFC01UL, /* 0x0008, */ 0x001200600BDFFC01UL, /* 0x0010, */ 0x001200600BDFFC01UL, /* 0x0018, */ 0x001200600BDFFC01UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x001200100BD0FC01UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x002100600BDFFC01UL, /* 0x01c8, */ 0x002100600BDFFC01UL, /* 0x01d0, */ 0x002100600BDFFC01UL, /* 0x01d8, */ 0x002100600BDFFC01UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x002100100BDF2401UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x002100100BDF2401UL, /* 0x0218, */ 0x001100100BDF2401UL, /* 0x0220, */ 0x001100100BDF2401UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x001100100BDF2401UL, /* 0x0238, */ 0x001100100BDF2401UL, /* 0x0240, */ 0x001200100BDF2401UL, /* 0x0248, */ 0x001100100BDF2401UL, /* 0x0250, */ 0x001200100BDF2401UL, /* 0x0258, */ 0x001100100BDF2401UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x001100600BDFFC01UL, /* 0x02f8, */ 0x001100600BDFFC01UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x001100600BDFFC01UL, /* 0x0310, */ 0x001100600BDFFC01UL, /* 0x0318, */ 0x001200100BD03401UL, /* 0x0320, */ 0x001100600BDFFC01UL, /* 0x0328, */ 0x001100600BDFFC01UL, /* 0x0330, */ 0x001100600BDFFC01UL, /* 0x0338, */ 0x001100600BDFFC01UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x001200100BD0FC01UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_mstat390.h000066400000000000000000000202231355360272700267550ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001008070000FFFFUL, /* 0x0038, */ 0x0010100D0000FFFFUL, /* 0x0040, */ 0x00141C0E0000FFFFUL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x001408010000FFFFUL, /* 0x0058, */ 0x00141C190000FFFFUL, /* 0x0060, */ 0x00141C190000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x001408010000FFFFUL, /* 0x0078, */ 0x0010100D0000FFFFUL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x00141C0E0000FFFFUL, /* 0x0090, */ 0x00141C190000FFFFUL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x000C08040000FFFFUL, /* 0x00a8, */ 0x000C04020000FFFFUL, /* 0x00b0, */ 0x000C04020000FFFFUL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x000C08040000FFFFUL, /* 0x00c8, */ 0x000C04020000FFFFUL, /* 0x00d0, */ 0x000C04020000FFFFUL, /* 0x00d8, */ 0x001044110000FFFFUL, /* 0x00e0, */ 0x001014110000FFFFUL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x001044110000FFFFUL, /* 0x00f8, */ 0x000C1C1A0000FFFFUL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x001014110000FFFFUL, /* 0x0118, */ 0x000C38360000FFFFUL, /* 0x0120, */ 0x000C38360000FFFFUL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x001018150000FFFFUL, /* 0x0140, */ 0x001018150000FFFFUL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x00101C190000FFFFUL, /* 0x0158, */ 0x00101C190000FFFFUL, /* 0x0160, */ 0x001018150000FFFFUL, /* 0x0168, */ 0x001018150000FFFFUL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x00100C0B0000FFFFUL, /* 0x0180, */ 0x00100C0B0000FFFFUL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x001058570000FFFFUL, /* 0x0198, */ 0x001058570000FFFFUL, /* 0x01a0, */ 0x001018150000FFFFUL, /* 0x01a8, */ 0x001018150000FFFFUL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x000C04010000FFFFUL, /* 0x01c8, */ 0x000C04010000FFFFUL, /* 0x01d0, */ 0x000C04010000FFFFUL, /* 0x01d8, */ 0x000C04010000FFFFUL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x000C04010000FFFFUL, /* 0x01f0, */ 0x000C04010000FFFFUL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x000C04010000FFFFUL, /* 0x0210, */ 0x000C04010000FFFFUL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C0C030000FFFFUL, /* 0x0268, */ 0x001410010000FFFFUL, /* 0x0270, */ 0x001404010000FFFFUL, /* 0x0278, */ 0x000C08020000FFFFUL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001410010000FFFFUL, /* 0x0298, */ 0x001404010000FFFFUL, /* 0x02a0, */ 0x000C04010000FFFFUL, /* 0x02a8, */ 0x000C04010000FFFFUL, /* 0x02b0, */ 0x00140C010000FFFFUL, /* 0x02b8, */ 0x000C04010000FFFFUL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x000C04010000FFFFUL, /* 0x02d8, */ 0x000C04010000FFFFUL, /* 0x02e0, */ 0x00140C010000FFFFUL, /* 0x02e8, */ 0x000C04010000FFFFUL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; static uint64_t mstat_be[] = { /* 0x0000, */ 0x0012006005EFFC01UL, /* 0x0008, */ 0x0012006005EFFC01UL, /* 0x0010, */ 0x0012006005EFFC01UL, /* 0x0018, */ 0x0012006005EFFC01UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0012001005E0FC01UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0021006005EFFC01UL, /* 0x01c8, */ 0x0021006005EFFC01UL, /* 0x01d0, */ 0x0021006005EFFC01UL, /* 0x01d8, */ 0x0021006005EFFC01UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0021001005E79401UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0021001005E79401UL, /* 0x0218, */ 0x0011001005E79401UL, /* 0x0220, */ 0x0011001005E79401UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0011001005E79401UL, /* 0x0238, */ 0x0011001005E79401UL, /* 0x0240, */ 0x0012001005E79401UL, /* 0x0248, */ 0x0011001005E79401UL, /* 0x0250, */ 0x0012001005E79401UL, /* 0x0258, */ 0x0011001005E79401UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0011006005EFFC01UL, /* 0x02f8, */ 0x0011006005EFFC01UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0011006005EFFC01UL, /* 0x0310, */ 0x0011006005EFFC01UL, /* 0x0318, */ 0x0012001005E03401UL, /* 0x0320, */ 0x0011006005EFFC01UL, /* 0x0328, */ 0x0011006005EFFC01UL, /* 0x0330, */ 0x0011006005EFFC01UL, /* 0x0338, */ 0x0011006005EFFC01UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0012001005E0FC01UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_qoswt195.h000066400000000000000000000202231355360272700270050ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t qoswt_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001004040000C010UL, /* 0x0038, */ 0x001008070000C010UL, /* 0x0040, */ 0x001410070000FFF0UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0014100D0000C010UL, /* 0x0060, */ 0x0014100D0000C010UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x001008070000C010UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001410070000FFF0UL, /* 0x0090, */ 0x0014100D0000C010UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C08020000FFF0UL, /* 0x0268, */ 0x001408010000FFF0UL, /* 0x0270, */ 0x001404010000FFF0UL, /* 0x0278, */ 0x000C04010000FFF0UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001408010000FFF0UL, /* 0x0298, */ 0x001404010000FFF0UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; static uint64_t qoswt_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3_v30_qoswt390.h000066400000000000000000000202231355360272700270020ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t qoswt_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001008070000C010UL, /* 0x0038, */ 0x0010100D0000C010UL, /* 0x0040, */ 0x00141C0E0000FFF0UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x00141C190000C010UL, /* 0x0060, */ 0x00141C190000C010UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0010100D0000C010UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x00141C0E0000FFF0UL, /* 0x0090, */ 0x00141C190000C010UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C0C030000FFF0UL, /* 0x0268, */ 0x001410010000FFF0UL, /* 0x0270, */ 0x001404010000FFF0UL, /* 0x0278, */ 0x000C08020000FFF0UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001410010000FFF0UL, /* 0x0298, */ 0x001404010000FFF0UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; static uint64_t qoswt_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.c000066400000000000000000000155171355360272700254740ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "../qos_common.h" #include "../qos_reg.h" #include "qos_init_h3n_v30.h" #define RCAR_QOS_VERSION "rev.0.07" #define QOSWT_TIME_BANK0 20000000U /* unit:ns */ #define QOSWT_WTEN_ENABLE 0x1U #define QOSCTRL_REF_ARS_ARBSTOPCYCLE_H3N (SL_INIT_SSLOTCLK_H3N - 0x5U) #define OSWT_WTREF_SLOT0_EN_REQ1_SLOT 3U #define OSWT_WTREF_SLOT0_EN_REQ2_SLOT 9U #define QOSWT_WTREF_SLOT0_EN \ ((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) | \ (0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT)) #define QOSWT_WTREF_SLOT1_EN \ ((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) | \ (0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT)) #define QOSWT_WTSET0_REQ_SSLOT0 5U #define WT_BASE_SUB_SLOT_NUM0 12U #define QOSWT_WTSET0_PERIOD0_H3N \ ((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_H3N) - 1U) #define QOSWT_WTSET0_SSLOT0 (QOSWT_WTSET0_REQ_SSLOT0 - 1U) #define QOSWT_WTSET0_SLOTSLOT0 (WT_BASE_SUB_SLOT_NUM0 - 1U) #define QOSWT_WTSET1_PERIOD1_H3N (QOSWT_WTSET0_PERIOD0_H3N) #define QOSWT_WTSET1_SSLOT1 (QOSWT_WTSET0_SSLOT0) #define QOSWT_WTSET1_SLOTSLOT1 (QOSWT_WTSET0_SLOTSLOT0) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT #if RCAR_REF_INT == RCAR_REF_DEFAULT #include "qos_init_h3n_v30_mstat195.h" #else #include "qos_init_h3n_v30_mstat390.h" #endif #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE #if RCAR_REF_INT == RCAR_REF_DEFAULT #include "qos_init_h3n_v30_qoswt195.h" #else #include "qos_init_h3n_v30_qoswt390.h" #endif #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ #endif struct rcar_gen3_dbsc_qos_settings h3n_v30_qos[] = { /* BUFCAM settings */ { DBSC_DBCAM0CNF1, 0x00043218U }, { DBSC_DBCAM0CNF2, 0x000000F4U }, { DBSC_DBCAM0CNF3, 0x00000000U }, { DBSC_DBSCHCNT0, 0x000F0037U }, { DBSC_DBSCHSZ0, 0x00000001U }, { DBSC_DBSCHRW0, 0x22421111U }, /* DDR3 */ { DBSC_SCFCTST2, 0x012F1123U }, /* QoS Settings */ { DBSC_DBSCHQOS00, 0x00000F00U }, { DBSC_DBSCHQOS01, 0x00000B00U }, { DBSC_DBSCHQOS02, 0x00000000U }, { DBSC_DBSCHQOS03, 0x00000000U }, { DBSC_DBSCHQOS40, 0x00000300U }, { DBSC_DBSCHQOS41, 0x000002F0U }, { DBSC_DBSCHQOS42, 0x00000200U }, { DBSC_DBSCHQOS43, 0x00000100U }, { DBSC_DBSCHQOS90, 0x00000100U }, { DBSC_DBSCHQOS91, 0x000000F0U }, { DBSC_DBSCHQOS92, 0x000000A0U }, { DBSC_DBSCHQOS93, 0x00000040U }, { DBSC_DBSCHQOS120, 0x00000040U }, { DBSC_DBSCHQOS121, 0x00000030U }, { DBSC_DBSCHQOS122, 0x00000020U }, { DBSC_DBSCHQOS123, 0x00000010U }, { DBSC_DBSCHQOS130, 0x00000100U }, { DBSC_DBSCHQOS131, 0x000000F0U }, { DBSC_DBSCHQOS132, 0x000000A0U }, { DBSC_DBSCHQOS133, 0x00000040U }, { DBSC_DBSCHQOS140, 0x000000C0U }, { DBSC_DBSCHQOS141, 0x000000B0U }, { DBSC_DBSCHQOS142, 0x00000080U }, { DBSC_DBSCHQOS143, 0x00000040U }, { DBSC_DBSCHQOS150, 0x00000040U }, { DBSC_DBSCHQOS151, 0x00000030U }, { DBSC_DBSCHQOS152, 0x00000020U }, { DBSC_DBSCHQOS153, 0x00000010U }, }; void qos_init_h3n_v30(void) { unsigned int split_area; rcar_qos_dbsc_setting(h3n_v30_qos, ARRAY_SIZE(h3n_v30_qos), true); /* use 1(2GB) for RCAR_DRAM_LPDDR4_MEMCONF for H3N */ split_area = 0x1CU; /* DRAM Split Address mapping */ #if (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH) #if RCAR_LSI == RCAR_H3N #error "Don't set DRAM Split 4ch(H3N)" #else ERROR("DRAM Split 4ch not supported.(H3N)"); panic(); #endif #elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH) || \ (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO) NOTICE("BL2: DRAM Split is 2ch(DDR %x)\n", (int)qos_init_ddr_phyvalid); io_write_32(AXI_ADSPLCR0, ADSPLCR0_AREA(split_area)); io_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT | ADSPLCR0_SPLITSEL(0xFFU) | ADSPLCR0_AREA(split_area) | ADSPLCR0_SWP); io_write_32(AXI_ADSPLCR2, 0x00001004U); io_write_32(AXI_ADSPLCR3, 0x00000000U); #else io_write_32(AXI_ADSPLCR0, ADSPLCR0_AREA(split_area)); NOTICE("BL2: DRAM Split is OFF(DDR %x)\n", (int)qos_init_ddr_phyvalid); #endif #if !(RCAR_QOS_TYPE == RCAR_QOS_NONE) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION); #endif #if RCAR_REF_INT == RCAR_REF_DEFAULT NOTICE("BL2: DRAM refresh interval 1.95 usec\n"); #else NOTICE("BL2: DRAM refresh interval 3.9 usec\n"); #endif #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE NOTICE("BL2: Periodic Write DQ Training\n"); #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ io_write_32(QOSCTRL_RAS, 0x00000044U); io_write_64(QOSCTRL_DANN, 0x0404020002020201UL); io_write_32(QOSCTRL_DANT, 0x0020100AU); io_write_32(QOSCTRL_FSS, 0x0000000AU); io_write_32(QOSCTRL_INSFC, 0x06330001U); io_write_32(QOSCTRL_RACNT0, 0x00010003U); /* GPU Boost Mode */ io_write_32(QOSCTRL_STATGEN0, 0x00000001U); io_write_32(QOSCTRL_SL_INIT, SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK_H3N); io_write_32(QOSCTRL_REF_ARS, ((QOSCTRL_REF_ARS_ARBSTOPCYCLE_H3N << 16))); uint32_t i; for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) { io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]); io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]); } for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) { io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]); io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]); } #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE for (i = 0U; i < ARRAY_SIZE(qoswt_fix); i++) { io_write_64(QOSWT_FIX_WTQOS_BANK0 + i * 8, qoswt_fix[i]); io_write_64(QOSWT_FIX_WTQOS_BANK1 + i * 8, qoswt_fix[i]); } for (i = 0U; i < ARRAY_SIZE(qoswt_be); i++) { io_write_64(QOSWT_BE_WTQOS_BANK0 + i * 8, qoswt_be[i]); io_write_64(QOSWT_BE_WTQOS_BANK1 + i * 8, qoswt_be[i]); } #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ /* AXI setting */ io_write_32(AXI_MMCR, 0x00010008U); io_write_32(AXI_TR3CR, 0x00010000U); io_write_32(AXI_TR4CR, 0x00010000U); /* RT bus Leaf setting */ io_write_32(RT_ACT0, 0x00000000U); io_write_32(RT_ACT1, 0x00000000U); /* CCI bus Leaf setting */ io_write_32(CPU_ACT0, 0x00000003U); io_write_32(CPU_ACT1, 0x00000003U); io_write_32(CPU_ACT2, 0x00000003U); io_write_32(CPU_ACT3, 0x00000003U); io_write_32(QOSCTRL_RAEN, 0x00000001U); #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE /* re-write training setting */ io_write_32(QOSWT_WTREF, ((QOSWT_WTREF_SLOT1_EN << 16) | QOSWT_WTREF_SLOT0_EN)); io_write_32(QOSWT_WTSET0, ((QOSWT_WTSET0_PERIOD0_H3N << 16) | (QOSWT_WTSET0_SSLOT0 << 8) | QOSWT_WTSET0_SLOTSLOT0)); io_write_32(QOSWT_WTSET1, ((QOSWT_WTSET1_PERIOD1_H3N << 16) | (QOSWT_WTSET1_SSLOT1 << 8) | QOSWT_WTSET1_SLOTSLOT1)); io_write_32(QOSWT_WTEN, QOSWT_WTEN_ENABLE); #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ io_write_32(QOSCTRL_STATQC, 0x00000001U); #else NOTICE("BL2: QoS is None\n"); io_write_32(QOSCTRL_RAEN, 0x00000001U); #endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */ } trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.h000066400000000000000000000003661355360272700254750ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef QOS_INIT_H3N_V30_H #define QOS_INIT_H3N_V30_H void qos_init_h3n_v30(void); #endif /* QOS_INIT_H3N_V30_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_mstat195.h000066400000000000000000000202231355360272700271360ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001004040000FFFFUL, /* 0x0038, */ 0x001008070000FFFFUL, /* 0x0040, */ 0x001410070000FFFFUL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x001404010000FFFFUL, /* 0x0058, */ 0x0014100D0000FFFFUL, /* 0x0060, */ 0x0014100D0000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x001404010000FFFFUL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001410070000FFFFUL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x000C04020000FFFFUL, /* 0x00a8, */ 0x000C04010000FFFFUL, /* 0x00b0, */ 0x000C04010000FFFFUL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x000C04020000FFFFUL, /* 0x00c8, */ 0x000C04010000FFFFUL, /* 0x00d0, */ 0x000C04010000FFFFUL, /* 0x00d8, */ 0x001024090000FFFFUL, /* 0x00e0, */ 0x00100C090000FFFFUL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x001024090000FFFFUL, /* 0x00f8, */ 0x000C100D0000FFFFUL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x00100C090000FFFFUL, /* 0x0118, */ 0x000C1C1B0000FFFFUL, /* 0x0120, */ 0x000C1C1B0000FFFFUL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x00100C0B0000FFFFUL, /* 0x0140, */ 0x00100C0B0000FFFFUL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0010100D0000FFFFUL, /* 0x0158, */ 0x0010100D0000FFFFUL, /* 0x0160, */ 0x00100C0B0000FFFFUL, /* 0x0168, */ 0x00100C0B0000FFFFUL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x001008060000FFFFUL, /* 0x0180, */ 0x001008060000FFFFUL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x00102C2C0000FFFFUL, /* 0x0198, */ 0x00102C2C0000FFFFUL, /* 0x01a0, */ 0x00100C0B0000FFFFUL, /* 0x01a8, */ 0x00100C0B0000FFFFUL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x000C04010000FFFFUL, /* 0x01c8, */ 0x000C04010000FFFFUL, /* 0x01d0, */ 0x000C04010000FFFFUL, /* 0x01d8, */ 0x000C04010000FFFFUL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x000C04010000FFFFUL, /* 0x01f0, */ 0x000C04010000FFFFUL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x000C04010000FFFFUL, /* 0x0210, */ 0x000C04010000FFFFUL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C08020000FFFFUL, /* 0x0268, */ 0x001408010000FFFFUL, /* 0x0270, */ 0x001404010000FFFFUL, /* 0x0278, */ 0x000C04010000FFFFUL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001408010000FFFFUL, /* 0x0298, */ 0x001404010000FFFFUL, /* 0x02a0, */ 0x000C04010000FFFFUL, /* 0x02a8, */ 0x000C04010000FFFFUL, /* 0x02b0, */ 0x001408010000FFFFUL, /* 0x02b8, */ 0x000C04010000FFFFUL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x000C04010000FFFFUL, /* 0x02d8, */ 0x000C04010000FFFFUL, /* 0x02e0, */ 0x001408010000FFFFUL, /* 0x02e8, */ 0x000C04010000FFFFUL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; static uint64_t mstat_be[] = { /* 0x0000, */ 0x001200600BDFFC01UL, /* 0x0008, */ 0x001200600BDFFC01UL, /* 0x0010, */ 0x001200600BDFFC01UL, /* 0x0018, */ 0x001200600BDFFC01UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x001200100BD0FC01UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x002100600BDFFC01UL, /* 0x01c8, */ 0x002100600BDFFC01UL, /* 0x01d0, */ 0x002100600BDFFC01UL, /* 0x01d8, */ 0x002100600BDFFC01UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x002100100BDF2401UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x002100100BDF2401UL, /* 0x0218, */ 0x001100100BDF2401UL, /* 0x0220, */ 0x001100100BDF2401UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x001100100BDF2401UL, /* 0x0238, */ 0x001100100BDF2401UL, /* 0x0240, */ 0x001200100BDF2401UL, /* 0x0248, */ 0x001100100BDF2401UL, /* 0x0250, */ 0x001200100BDF2401UL, /* 0x0258, */ 0x001100100BDF2401UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x001100600BDFFC01UL, /* 0x02f8, */ 0x001100600BDFFC01UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x001100600BDFFC01UL, /* 0x0310, */ 0x001100600BDFFC01UL, /* 0x0318, */ 0x001200100BD03401UL, /* 0x0320, */ 0x001100600BDFFC01UL, /* 0x0328, */ 0x001100600BDFFC01UL, /* 0x0330, */ 0x001100600BDFFC01UL, /* 0x0338, */ 0x001100600BDFFC01UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x001200100BD0FC01UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_mstat390.h000066400000000000000000000202231355360272700271330ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001008070000FFFFUL, /* 0x0038, */ 0x0010100D0000FFFFUL, /* 0x0040, */ 0x00141C0E0000FFFFUL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x001408010000FFFFUL, /* 0x0058, */ 0x00141C190000FFFFUL, /* 0x0060, */ 0x00141C190000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x001408010000FFFFUL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x00141C0E0000FFFFUL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x000C08040000FFFFUL, /* 0x00a8, */ 0x000C04020000FFFFUL, /* 0x00b0, */ 0x000C04020000FFFFUL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x000C08040000FFFFUL, /* 0x00c8, */ 0x000C04020000FFFFUL, /* 0x00d0, */ 0x000C04020000FFFFUL, /* 0x00d8, */ 0x001044110000FFFFUL, /* 0x00e0, */ 0x001014110000FFFFUL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x001044110000FFFFUL, /* 0x00f8, */ 0x000C1C1A0000FFFFUL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x001014110000FFFFUL, /* 0x0118, */ 0x000C38360000FFFFUL, /* 0x0120, */ 0x000C38360000FFFFUL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x001018150000FFFFUL, /* 0x0140, */ 0x001018150000FFFFUL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x00101C190000FFFFUL, /* 0x0158, */ 0x00101C190000FFFFUL, /* 0x0160, */ 0x001018150000FFFFUL, /* 0x0168, */ 0x001018150000FFFFUL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x00100C0B0000FFFFUL, /* 0x0180, */ 0x00100C0B0000FFFFUL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x001058570000FFFFUL, /* 0x0198, */ 0x001058570000FFFFUL, /* 0x01a0, */ 0x001018150000FFFFUL, /* 0x01a8, */ 0x001018150000FFFFUL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x000C04010000FFFFUL, /* 0x01c8, */ 0x000C04010000FFFFUL, /* 0x01d0, */ 0x000C04010000FFFFUL, /* 0x01d8, */ 0x000C04010000FFFFUL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x000C04010000FFFFUL, /* 0x01f0, */ 0x000C04010000FFFFUL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x000C04010000FFFFUL, /* 0x0210, */ 0x000C04010000FFFFUL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C0C030000FFFFUL, /* 0x0268, */ 0x001410010000FFFFUL, /* 0x0270, */ 0x001404010000FFFFUL, /* 0x0278, */ 0x000C08020000FFFFUL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001410010000FFFFUL, /* 0x0298, */ 0x001404010000FFFFUL, /* 0x02a0, */ 0x000C04010000FFFFUL, /* 0x02a8, */ 0x000C04010000FFFFUL, /* 0x02b0, */ 0x00140C010000FFFFUL, /* 0x02b8, */ 0x000C04010000FFFFUL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x000C04010000FFFFUL, /* 0x02d8, */ 0x000C04010000FFFFUL, /* 0x02e0, */ 0x00140C010000FFFFUL, /* 0x02e8, */ 0x000C04010000FFFFUL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; static uint64_t mstat_be[] = { /* 0x0000, */ 0x0012006005EFFC01UL, /* 0x0008, */ 0x0012006005EFFC01UL, /* 0x0010, */ 0x0012006005EFFC01UL, /* 0x0018, */ 0x0012006005EFFC01UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0012001005E0FC01UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0021006005EFFC01UL, /* 0x01c8, */ 0x0021006005EFFC01UL, /* 0x01d0, */ 0x0021006005EFFC01UL, /* 0x01d8, */ 0x0021006005EFFC01UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0021001005E79401UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0021001005E79401UL, /* 0x0218, */ 0x0011001005E79401UL, /* 0x0220, */ 0x0011001005E79401UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0011001005E79401UL, /* 0x0238, */ 0x0011001005E79401UL, /* 0x0240, */ 0x0012001005E79401UL, /* 0x0248, */ 0x0011001005E79401UL, /* 0x0250, */ 0x0012001005E79401UL, /* 0x0258, */ 0x0011001005E79401UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0011006005EFFC01UL, /* 0x02f8, */ 0x0011006005EFFC01UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0011006005EFFC01UL, /* 0x0310, */ 0x0011006005EFFC01UL, /* 0x0318, */ 0x0012001005E03401UL, /* 0x0320, */ 0x0011006005EFFC01UL, /* 0x0328, */ 0x0011006005EFFC01UL, /* 0x0330, */ 0x0011006005EFFC01UL, /* 0x0338, */ 0x0011006005EFFC01UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0012001005E0FC01UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_qoswt195.h000066400000000000000000000202231355360272700271630ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t qoswt_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001004040000C010UL, /* 0x0038, */ 0x001008070000C010UL, /* 0x0040, */ 0x001410070000FFF0UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0014100D0000C010UL, /* 0x0060, */ 0x0014100D0000C010UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001410070000FFF0UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C08020000FFF0UL, /* 0x0268, */ 0x001408010000FFF0UL, /* 0x0270, */ 0x001404010000FFF0UL, /* 0x0278, */ 0x000C04010000FFF0UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001408010000FFF0UL, /* 0x0298, */ 0x001404010000FFF0UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; static uint64_t qoswt_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/H3/qos_init_h3n_v30_qoswt390.h000066400000000000000000000202231355360272700271600ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t qoswt_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001008070000C010UL, /* 0x0038, */ 0x0010100D0000C010UL, /* 0x0040, */ 0x00141C0E0000FFF0UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x00141C190000C010UL, /* 0x0060, */ 0x00141C190000C010UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x00141C0E0000FFF0UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C0C030000FFF0UL, /* 0x0268, */ 0x001410010000FFF0UL, /* 0x0270, */ 0x001404010000FFF0UL, /* 0x0278, */ 0x000C08020000FFF0UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001410010000FFF0UL, /* 0x0298, */ 0x001404010000FFF0UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; static uint64_t qoswt_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3/000077500000000000000000000000001355360272700222375ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3/qos_init_m3_v10.c000066400000000000000000000104111355360272700253120ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "../qos_common.h" #include "../qos_reg.h" #include "qos_init_m3_v10.h" #define RCAR_QOS_VERSION "rev.0.19" #include "qos_init_m3_v10_mstat.h" struct rcar_gen3_dbsc_qos_settings m3_v10_qos[] = { /* BUFCAM settings */ /* DBSC_DBCAM0CNF0 not set */ { DBSC_DBCAM0CNF1, 0x00043218 }, { DBSC_DBCAM0CNF2, 0x000000F4 }, { DBSC_DBCAM0CNF3, 0x00000000 }, { DBSC_DBSCHCNT0, 0x080F0037 }, /* DBSC_DBSCHCNT1 not set */ { DBSC_DBSCHSZ0, 0x00000001 }, { DBSC_DBSCHRW0, 0x22421111 }, /* DDR3 */ { DBSC_SCFCTST2, 0x012F1123 }, /* QoS Settings */ { DBSC_DBSCHQOS00, 0x00000F00 }, { DBSC_DBSCHQOS01, 0x00000B00 }, { DBSC_DBSCHQOS02, 0x00000000 }, { DBSC_DBSCHQOS03, 0x00000000 }, { DBSC_DBSCHQOS40, 0x00000300 }, { DBSC_DBSCHQOS41, 0x000002F0 }, { DBSC_DBSCHQOS42, 0x00000200 }, { DBSC_DBSCHQOS43, 0x00000100 }, { DBSC_DBSCHQOS90, 0x00000300 }, { DBSC_DBSCHQOS91, 0x000002F0 }, { DBSC_DBSCHQOS92, 0x00000200 }, { DBSC_DBSCHQOS93, 0x00000100 }, { DBSC_DBSCHQOS130, 0x00000100 }, { DBSC_DBSCHQOS131, 0x000000F0 }, { DBSC_DBSCHQOS132, 0x000000A0 }, { DBSC_DBSCHQOS133, 0x00000040 }, { DBSC_DBSCHQOS140, 0x000000C0 }, { DBSC_DBSCHQOS141, 0x000000B0 }, { DBSC_DBSCHQOS142, 0x00000080 }, { DBSC_DBSCHQOS143, 0x00000040 }, { DBSC_DBSCHQOS150, 0x00000040 }, { DBSC_DBSCHQOS151, 0x00000030 }, { DBSC_DBSCHQOS152, 0x00000020 }, { DBSC_DBSCHQOS153, 0x00000010 }, }; void qos_init_m3_v10(void) { rcar_qos_dbsc_setting(m3_v10_qos, ARRAY_SIZE(m3_v10_qos), false); /* DRAM Split Address mapping */ #if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH #if RCAR_LSI == RCAR_M3 #error "Don't set DRAM Split 4ch(M3)" #else ERROR("DRAM Split 4ch not supported.(M3)"); panic(); #endif #elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH) || \ (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO) NOTICE("BL2: DRAM Split is 2ch\n"); io_write_32(AXI_ADSPLCR0, 0x00000000U); io_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT | ADSPLCR0_SPLITSEL(0xFFU) | ADSPLCR0_AREA(0x1CU) | ADSPLCR0_SWP); io_write_32(AXI_ADSPLCR2, 0x089A0000U); io_write_32(AXI_ADSPLCR3, 0x00000000U); #else NOTICE("BL2: DRAM Split is OFF\n"); #endif #if !(RCAR_QOS_TYPE == RCAR_QOS_NONE) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION); #endif /* Resource Alloc setting */ io_write_32(QOSCTRL_RAS, 0x00000028U); io_write_32(QOSCTRL_FIXTH, 0x000F0005U); io_write_32(QOSCTRL_REGGD, 0x00000000U); io_write_64(QOSCTRL_DANN, 0x0101010102020201UL); io_write_32(QOSCTRL_DANT, 0x00100804U); io_write_32(QOSCTRL_EC, 0x00000000U); io_write_64(QOSCTRL_EMS, 0x0000000000000000UL); io_write_32(QOSCTRL_FSS, 0x000003e8U); io_write_32(QOSCTRL_INSFC, 0xC7840001U); io_write_32(QOSCTRL_BERR, 0x00000000U); io_write_32(QOSCTRL_RACNT0, 0x00000000U); /* QOSBW setting */ io_write_32(QOSCTRL_SL_INIT, SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK); io_write_32(QOSCTRL_REF_ARS, 0x00330000U); /* QOSBW SRAM setting */ uint32_t i; for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) { io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]); io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]); } for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) { io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]); io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]); } /* 3DG bus Leaf setting */ io_write_32(0xFD820808U, 0x00001234U); io_write_32(0xFD820800U, 0x00000006U); io_write_32(0xFD821800U, 0x00000006U); io_write_32(0xFD822800U, 0x00000006U); io_write_32(0xFD823800U, 0x00000006U); io_write_32(0xFD824800U, 0x00000006U); io_write_32(0xFD825800U, 0x00000006U); io_write_32(0xFD826800U, 0x00000006U); io_write_32(0xFD827800U, 0x00000006U); /* RT bus Leaf setting */ io_write_32(0xFFC50800U, 0x00000000U); io_write_32(0xFFC51800U, 0x00000000U); /* Resource Alloc start */ io_write_32(QOSCTRL_RAEN, 0x00000001U); /* QOSBW start */ io_write_32(QOSCTRL_STATQC, 0x00000001U); #else NOTICE("BL2: QoS is None\n"); /* Resource Alloc setting */ io_write_32(QOSCTRL_EC, 0x00000000U); /* Resource Alloc start */ io_write_32(QOSCTRL_RAEN, 0x00000001U); #endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */ } trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3/qos_init_m3_v10.h000066400000000000000000000003671355360272700253300ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef QOS_INIT_M3_V10_H #define QOS_INIT_M3_V10_H void qos_init_m3_v10(void); #endif /* QOS_INIT_M3_V10_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3/qos_init_m3_v10_mstat.h000066400000000000000000000177711355360272700265470ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT static const uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001004030000FFFFUL, /* 0x0038, */ 0x001004030000FFFFUL, /* 0x0040, */ 0x001414090000FFFFUL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x001410010000FFFFUL, /* 0x0058, */ 0x00140C090000FFFFUL, /* 0x0060, */ 0x00140C090000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x001410010000FFFFUL, /* 0x0078, */ 0x001004020000FFFFUL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001414090000FFFFUL, /* 0x0090, */ 0x001408060000FFFFUL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00A0, */ 0x000C08020000FFFFUL, /* 0x00A8, */ 0x000C04010000FFFFUL, /* 0x00B0, */ 0x000C04010000FFFFUL, /* 0x00B8, */ 0x0000000000000000UL, /* 0x00C0, */ 0x000C08020000FFFFUL, /* 0x00C8, */ 0x000C04010000FFFFUL, /* 0x00D0, */ 0x000C04010000FFFFUL, /* 0x00D8, */ 0x000C04030000FFFFUL, /* 0x00E0, */ 0x000C100F0000FFFFUL, /* 0x00E8, */ 0x0000000000000000UL, /* 0x00F0, */ 0x001010080000FFFFUL, /* 0x00F8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x001010080000FFFFUL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x00100C0A0000FFFFUL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x00100C0A0000FFFFUL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x00100C0A0000FFFFUL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x001008050000FFFFUL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x001028280000FFFFUL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01A0, */ 0x00100C0A0000FFFFUL, /* 0x01A8, */ 0x0000000000000000UL, /* 0x01B0, */ 0x0000000000000000UL, /* 0x01B8, */ 0x0000000000000000UL, /* 0x01C0, */ 0x0000000000000000UL, /* 0x01C8, */ 0x0000000000000000UL, /* 0x01D0, */ 0x0000000000000000UL, /* 0x01D8, */ 0x0000000000000000UL, /* 0x01E0, */ 0x0000000000000000UL, /* 0x01E8, */ 0x0000000000000000UL, /* 0x01F0, */ 0x0000000000000000UL, /* 0x01F8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x001408010000FFFFUL, /* 0x0270, */ 0x001404010000FFFFUL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001408010000FFFFUL, /* 0x0298, */ 0x001404010000FFFFUL, /* 0x02A0, */ 0x000C04010000FFFFUL, /* 0x02A8, */ 0x000C04010000FFFFUL, /* 0x02B0, */ 0x001404010000FFFFUL, /* 0x02B8, */ 0x0000000000000000UL, /* 0x02C0, */ 0x0000000000000000UL, /* 0x02C8, */ 0x0000000000000000UL, /* 0x02D0, */ 0x000C04010000FFFFUL, /* 0x02D8, */ 0x000C04010000FFFFUL, /* 0x02E0, */ 0x001404010000FFFFUL, /* 0x02E8, */ 0x0000000000000000UL, /* 0x02F0, */ 0x0000000000000000UL, /* 0x02F8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; static const uint64_t mstat_be[] = { /* 0x0000, */ 0x001200100C89C401UL, /* 0x0008, */ 0x001200100C89C401UL, /* 0x0010, */ 0x001200100C89C401UL, /* 0x0018, */ 0x001200100C89C401UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x001100100C803401UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00A0, */ 0x0000000000000000UL, /* 0x00A8, */ 0x0000000000000000UL, /* 0x00B0, */ 0x0000000000000000UL, /* 0x00B8, */ 0x0000000000000000UL, /* 0x00C0, */ 0x0000000000000000UL, /* 0x00C8, */ 0x0000000000000000UL, /* 0x00D0, */ 0x0000000000000000UL, /* 0x00D8, */ 0x0000000000000000UL, /* 0x00E0, */ 0x0000000000000000UL, /* 0x00E8, */ 0x0000000000000000UL, /* 0x00F0, */ 0x0000000000000000UL, /* 0x00F8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01A0, */ 0x0000000000000000UL, /* 0x01A8, */ 0x0000000000000000UL, /* 0x01B0, */ 0x0000000000000000UL, /* 0x01B8, */ 0x0000000000000000UL, /* 0x01C0, */ 0x001100500C8FFC01UL, /* 0x01C8, */ 0x001100500C8FFC01UL, /* 0x01D0, */ 0x001100500C8FFC01UL, /* 0x01D8, */ 0x001100500C8FFC01UL, /* 0x01E0, */ 0x0000000000000000UL, /* 0x01E8, */ 0x001200100C803401UL, /* 0x01F0, */ 0x001100100C80FC01UL, /* 0x01F8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x001200100C80FC01UL, /* 0x0210, */ 0x001100100C80FC01UL, /* 0x0218, */ 0x001100100C825801UL, /* 0x0220, */ 0x001100100C825801UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x001100100C825801UL, /* 0x0238, */ 0x001100100C825801UL, /* 0x0240, */ 0x001200100C8BB801UL, /* 0x0248, */ 0x001100100C8EA401UL, /* 0x0250, */ 0x001200100C8BB801UL, /* 0x0258, */ 0x001100100C8EA401UL, /* 0x0260, */ 0x001100100C84E401UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x001100100C81F401UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02A0, */ 0x0000000000000000UL, /* 0x02A8, */ 0x0000000000000000UL, /* 0x02B0, */ 0x0000000000000000UL, /* 0x02B8, */ 0x001100100C803401UL, /* 0x02C0, */ 0x0000000000000000UL, /* 0x02C8, */ 0x0000000000000000UL, /* 0x02D0, */ 0x0000000000000000UL, /* 0x02D8, */ 0x0000000000000000UL, /* 0x02E0, */ 0x0000000000000000UL, /* 0x02E8, */ 0x001100100C803401UL, /* 0x02F0, */ 0x001100300C8FFC01UL, /* 0x02F8, */ 0x001100500C8FFC01UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x001100300C8FFC01UL, /* 0x0310, */ 0x001100500C8FFC01UL, /* 0x0318, */ 0x001200100C803401UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; #endif trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3/qos_init_m3_v11.c000066400000000000000000000153711355360272700253250ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "../qos_common.h" #include "../qos_reg.h" #include "qos_init_m3_v11.h" #define RCAR_QOS_VERSION "rev.0.19" #define QOSWT_TIME_BANK0 20000000U /* unit:ns */ #define QOSWT_WTEN_ENABLE 0x1U #define QOSCTRL_REF_ARS_ARBSTOPCYCLE_M3_11 (SL_INIT_SSLOTCLK_M3_11 - 0x5U) #define OSWT_WTREF_SLOT0_EN_REQ1_SLOT 3U #define OSWT_WTREF_SLOT0_EN_REQ2_SLOT 9U #define QOSWT_WTREF_SLOT0_EN \ ((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) | \ (0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT)) #define QOSWT_WTREF_SLOT1_EN \ ((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) | \ (0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT)) #define QOSWT_WTSET0_REQ_SSLOT0 5U #define WT_BASE_SUB_SLOT_NUM0 12U #define QOSWT_WTSET0_PERIOD0_M3_11 \ ((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_M3_11) - 1U) #define QOSWT_WTSET0_SSLOT0 (QOSWT_WTSET0_REQ_SSLOT0 - 1U) #define QOSWT_WTSET0_SLOTSLOT0 (WT_BASE_SUB_SLOT_NUM0 - 1U) #define QOSWT_WTSET1_PERIOD1_M3_11 \ ((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_M3_11) - 1U) #define QOSWT_WTSET1_SSLOT1 (QOSWT_WTSET0_REQ_SSLOT0 - 1U) #define QOSWT_WTSET1_SLOTSLOT1 (WT_BASE_SUB_SLOT_NUM0 - 1U) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT #if RCAR_REF_INT == RCAR_REF_DEFAULT #include "qos_init_m3_v11_mstat195.h" #else #include "qos_init_m3_v11_mstat390.h" #endif #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE #if RCAR_REF_INT == RCAR_REF_DEFAULT #include "qos_init_m3_v11_qoswt195.h" #else #include "qos_init_m3_v11_qoswt390.h" #endif #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ #endif struct rcar_gen3_dbsc_qos_settings m3_v11_qos[] = { /* BUFCAM settings */ { DBSC_DBCAM0CNF1, 0x00043218 }, { DBSC_DBCAM0CNF2, 0x000000F4 }, { DBSC_DBCAM0CNF3, 0x00000000 }, { DBSC_DBSCHCNT0, 0x000F0037 }, { DBSC_DBSCHSZ0, 0x00000001 }, { DBSC_DBSCHRW0, 0x22421111 }, /* DDR3 */ { DBSC_SCFCTST2, 0x012F1123 }, /* QoS Settings */ { DBSC_DBSCHQOS00, 0x00000F00 }, { DBSC_DBSCHQOS01, 0x00000B00 }, { DBSC_DBSCHQOS02, 0x00000000 }, { DBSC_DBSCHQOS03, 0x00000000 }, { DBSC_DBSCHQOS40, 0x00000300 }, { DBSC_DBSCHQOS41, 0x000002F0 }, { DBSC_DBSCHQOS42, 0x00000200 }, { DBSC_DBSCHQOS43, 0x00000100 }, { DBSC_DBSCHQOS90, 0x00000100 }, { DBSC_DBSCHQOS91, 0x000000F0 }, { DBSC_DBSCHQOS92, 0x000000A0 }, { DBSC_DBSCHQOS93, 0x00000040 }, { DBSC_DBSCHQOS120, 0x00000040 }, { DBSC_DBSCHQOS121, 0x00000030 }, { DBSC_DBSCHQOS122, 0x00000020 }, { DBSC_DBSCHQOS123, 0x00000010 }, { DBSC_DBSCHQOS130, 0x00000100 }, { DBSC_DBSCHQOS131, 0x000000F0 }, { DBSC_DBSCHQOS132, 0x000000A0 }, { DBSC_DBSCHQOS133, 0x00000040 }, { DBSC_DBSCHQOS140, 0x000000C0 }, { DBSC_DBSCHQOS141, 0x000000B0 }, { DBSC_DBSCHQOS142, 0x00000080 }, { DBSC_DBSCHQOS143, 0x00000040 }, { DBSC_DBSCHQOS150, 0x00000040 }, { DBSC_DBSCHQOS151, 0x00000030 }, { DBSC_DBSCHQOS152, 0x00000020 }, { DBSC_DBSCHQOS153, 0x00000010 }, }; void qos_init_m3_v11(void) { rcar_qos_dbsc_setting(m3_v11_qos, ARRAY_SIZE(m3_v11_qos), false); /* DRAM Split Address mapping */ #if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH #if RCAR_LSI == RCAR_M3 #error "Don't set DRAM Split 4ch(M3)" #else ERROR("DRAM Split 4ch not supported.(M3)"); panic(); #endif #elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH) || \ (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO) NOTICE("BL2: DRAM Split is 2ch\n"); io_write_32(AXI_ADSPLCR0, 0x00000000U); io_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT | ADSPLCR0_SPLITSEL(0xFFU) | ADSPLCR0_AREA(0x1CU) | ADSPLCR0_SWP); io_write_32(AXI_ADSPLCR2, 0x00001004U); io_write_32(AXI_ADSPLCR3, 0x00000000U); #else NOTICE("BL2: DRAM Split is OFF\n"); #endif #if !(RCAR_QOS_TYPE == RCAR_QOS_NONE) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION); #endif #if RCAR_REF_INT == RCAR_REF_DEFAULT NOTICE("BL2: DRAM refresh interval 1.95 usec\n"); #else NOTICE("BL2: DRAM refresh interval 3.9 usec\n"); #endif #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE NOTICE("BL2: Periodic Write DQ Training\n"); #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ io_write_32(QOSCTRL_RAS, 0x00000044U); io_write_64(QOSCTRL_DANN, 0x0404020002020201UL); io_write_32(QOSCTRL_DANT, 0x0020100AU); io_write_32(QOSCTRL_INSFC, 0x06330001U); io_write_32(QOSCTRL_RACNT0, 0x02010003U); /* GPU Boost Mode ON */ io_write_32(QOSCTRL_SL_INIT, SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK_M3_11); #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE io_write_32(QOSCTRL_REF_ARS, ((QOSCTRL_REF_ARS_ARBSTOPCYCLE_M3_11 << 16))); #else io_write_32(QOSCTRL_REF_ARS, 0x00330000U); #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ uint32_t i; for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) { io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]); io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]); } for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) { io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]); io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]); } #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE for (i = 0U; i < ARRAY_SIZE(qoswt_fix); i++) { io_write_64(QOSWT_FIX_WTQOS_BANK0 + i * 8, qoswt_fix[i]); io_write_64(QOSWT_FIX_WTQOS_BANK1 + i * 8, qoswt_fix[i]); } for (i = 0U; i < ARRAY_SIZE(qoswt_be); i++) { io_write_64(QOSWT_BE_WTQOS_BANK0 + i * 8, qoswt_be[i]); io_write_64(QOSWT_BE_WTQOS_BANK1 + i * 8, qoswt_be[i]); } #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ /* 3DG bus Leaf setting */ io_write_32(GPU_ACT_GRD, 0x00001234U); io_write_32(GPU_ACT0, 0x00000000U); io_write_32(GPU_ACT1, 0x00000000U); io_write_32(GPU_ACT2, 0x00000000U); io_write_32(GPU_ACT3, 0x00000000U); /* RT bus Leaf setting */ io_write_32(RT_ACT0, 0x00000000U); io_write_32(RT_ACT1, 0x00000000U); /* CCI bus Leaf setting */ io_write_32(CPU_ACT0, 0x00000003U); io_write_32(CPU_ACT1, 0x00000003U); io_write_32(CPU_ACT2, 0x00000003U); io_write_32(CPU_ACT3, 0x00000003U); io_write_32(QOSCTRL_RAEN, 0x00000001U); #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE /* re-write training setting */ io_write_32(QOSWT_WTREF, ((QOSWT_WTREF_SLOT1_EN << 16) | QOSWT_WTREF_SLOT0_EN)); io_write_32(QOSWT_WTSET0, ((QOSWT_WTSET0_PERIOD0_M3_11 << 16) | (QOSWT_WTSET0_SSLOT0 << 8) | QOSWT_WTSET0_SLOTSLOT0)); io_write_32(QOSWT_WTSET1, ((QOSWT_WTSET1_PERIOD1_M3_11 << 16) | (QOSWT_WTSET1_SSLOT1 << 8) | QOSWT_WTSET1_SLOTSLOT1)); io_write_32(QOSWT_WTEN, QOSWT_WTEN_ENABLE); #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ io_write_32(QOSCTRL_STATQC, 0x00000001U); #else NOTICE("BL2: QoS is None\n"); io_write_32(QOSCTRL_RAEN, 0x00000001U); #endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */ } trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3/qos_init_m3_v11.h000066400000000000000000000003621355360272700253240ustar00rootroot00000000000000/* * Copyright (c) 2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef QOS_INIT_M3_V11_H #define QOS_INIT_M3_V11_H void qos_init_m3_v11(void); #endif /* QOS_INIT_M3_V11_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_mstat195.h000066400000000000000000000176651355360272700270110ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001004040000FFFFUL, /* 0x0038, */ 0x001004040000FFFFUL, /* 0x0040, */ 0x001414090000FFFFUL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x001404010000FFFFUL, /* 0x0058, */ 0x00140C0A0000FFFFUL, /* 0x0060, */ 0x00140C0A0000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x001404010000FFFFUL, /* 0x0078, */ 0x001004030000FFFFUL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001414090000FFFFUL, /* 0x0090, */ 0x001408070000FFFFUL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x000C04020000FFFFUL, /* 0x00a8, */ 0x000C04010000FFFFUL, /* 0x00b0, */ 0x000C04010000FFFFUL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x000C04020000FFFFUL, /* 0x00c8, */ 0x000C04010000FFFFUL, /* 0x00d0, */ 0x000C04010000FFFFUL, /* 0x00d8, */ 0x000C08050000FFFFUL, /* 0x00e0, */ 0x000C14120000FFFFUL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x001024090000FFFFUL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x00100C090000FFFFUL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x00100C0B0000FFFFUL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0010100D0000FFFFUL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x00100C0B0000FFFFUL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x001008060000FFFFUL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x00102C2C0000FFFFUL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x00100C0B0000FFFFUL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x000C04010000FFFFUL, /* 0x01c8, */ 0x000C04010000FFFFUL, /* 0x01d0, */ 0x000C04010000FFFFUL, /* 0x01d8, */ 0x000C04010000FFFFUL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x000C04010000FFFFUL, /* 0x01f0, */ 0x000C04010000FFFFUL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x000C04010000FFFFUL, /* 0x0210, */ 0x000C04010000FFFFUL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C08020000FFFFUL, /* 0x0268, */ 0x001408010000FFFFUL, /* 0x0270, */ 0x001404010000FFFFUL, /* 0x0278, */ 0x000C04010000FFFFUL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001408010000FFFFUL, /* 0x0298, */ 0x001404010000FFFFUL, /* 0x02a0, */ 0x000C04010000FFFFUL, /* 0x02a8, */ 0x000C04010000FFFFUL, /* 0x02b0, */ 0x001408010000FFFFUL, /* 0x02b8, */ 0x000C04010000FFFFUL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x000C04010000FFFFUL, /* 0x02d8, */ 0x000C04010000FFFFUL, /* 0x02e0, */ 0x001408010000FFFFUL, /* 0x02e8, */ 0x000C04010000FFFFUL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; static uint64_t mstat_be[] = { /* 0x0000, */ 0x001200200BDFFC01UL, /* 0x0008, */ 0x001200200BDFFC01UL, /* 0x0010, */ 0x001200200BDFFC01UL, /* 0x0018, */ 0x001200200BDFFC01UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x001200100BD03401UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x002100600BDFFC01UL, /* 0x01c8, */ 0x002100600BDFFC01UL, /* 0x01d0, */ 0x002100600BDFFC01UL, /* 0x01d8, */ 0x002100600BDFFC01UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x002100200BDFFC01UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x002100200BDFFC01UL, /* 0x0218, */ 0x001100200BDFFC01UL, /* 0x0220, */ 0x001100200BDFFC01UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x001100200BDFFC01UL, /* 0x0238, */ 0x001100200BDFFC01UL, /* 0x0240, */ 0x001200200BDFFC01UL, /* 0x0248, */ 0x001100200BDFFC01UL, /* 0x0250, */ 0x001200200BDFFC01UL, /* 0x0258, */ 0x001100200BDFFC01UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x001100400BDFFC01UL, /* 0x02f8, */ 0x001100600BDFFC01UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x001100400BDFFC01UL, /* 0x0310, */ 0x001100600BDFFC01UL, /* 0x0318, */ 0x001200100BD03401UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_mstat390.h000066400000000000000000000176651355360272700270060ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001008070000FFFFUL, /* 0x0038, */ 0x001008070000FFFFUL, /* 0x0040, */ 0x001424120000FFFFUL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x001404010000FFFFUL, /* 0x0058, */ 0x001414130000FFFFUL, /* 0x0060, */ 0x001414130000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x001404010000FFFFUL, /* 0x0078, */ 0x001008050000FFFFUL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001424120000FFFFUL, /* 0x0090, */ 0x0014100D0000FFFFUL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x000C08040000FFFFUL, /* 0x00a8, */ 0x000C04020000FFFFUL, /* 0x00b0, */ 0x000C04020000FFFFUL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x000C08040000FFFFUL, /* 0x00c8, */ 0x000C04020000FFFFUL, /* 0x00d0, */ 0x000C04020000FFFFUL, /* 0x00d8, */ 0x000C0C0A0000FFFFUL, /* 0x00e0, */ 0x000C24230000FFFFUL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x001044110000FFFFUL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x001014110000FFFFUL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x001018150000FFFFUL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x00101C190000FFFFUL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x001018150000FFFFUL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x00100C0B0000FFFFUL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x001058570000FFFFUL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x001018150000FFFFUL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x000C04010000FFFFUL, /* 0x01c8, */ 0x000C04010000FFFFUL, /* 0x01d0, */ 0x000C04010000FFFFUL, /* 0x01d8, */ 0x000C04010000FFFFUL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x000C04010000FFFFUL, /* 0x01f0, */ 0x000C04010000FFFFUL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x000C04010000FFFFUL, /* 0x0210, */ 0x000C04010000FFFFUL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C0C030000FFFFUL, /* 0x0268, */ 0x001410010000FFFFUL, /* 0x0270, */ 0x001404010000FFFFUL, /* 0x0278, */ 0x000C08020000FFFFUL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001410010000FFFFUL, /* 0x0298, */ 0x001404010000FFFFUL, /* 0x02a0, */ 0x000C04010000FFFFUL, /* 0x02a8, */ 0x000C04010000FFFFUL, /* 0x02b0, */ 0x00140C010000FFFFUL, /* 0x02b8, */ 0x000C04010000FFFFUL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x000C04010000FFFFUL, /* 0x02d8, */ 0x000C04010000FFFFUL, /* 0x02e0, */ 0x00140C010000FFFFUL, /* 0x02e8, */ 0x000C04010000FFFFUL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; static uint64_t mstat_be[] = { /* 0x0000, */ 0x0012003005EFFC01UL, /* 0x0008, */ 0x0012003005EFFC01UL, /* 0x0010, */ 0x0012003005EFFC01UL, /* 0x0018, */ 0x0012003005EFFC01UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0012001005E03401UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x002100B005EFFC01UL, /* 0x01c8, */ 0x002100B005EFFC01UL, /* 0x01d0, */ 0x002100B005EFFC01UL, /* 0x01d8, */ 0x002100B005EFFC01UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0021003005EFFC01UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0021003005EFFC01UL, /* 0x0218, */ 0x0011003005EFFC01UL, /* 0x0220, */ 0x0011003005EFFC01UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0011003005EFFC01UL, /* 0x0238, */ 0x0011003005EFFC01UL, /* 0x0240, */ 0x0012003005EFFC01UL, /* 0x0248, */ 0x0011003005EFFC01UL, /* 0x0250, */ 0x0012003005EFFC01UL, /* 0x0258, */ 0x0011003005EFFC01UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0011007005EFFC01UL, /* 0x02f8, */ 0x001100B005EFFC01UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0011007005EFFC01UL, /* 0x0310, */ 0x001100B005EFFC01UL, /* 0x0318, */ 0x0012001005E03401UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_qoswt195.h000066400000000000000000000176651355360272700270360ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t qoswt_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001004040000C010UL, /* 0x0038, */ 0x001004040000C010UL, /* 0x0040, */ 0x001414090000FFF0UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x00140C0A0000C010UL, /* 0x0060, */ 0x00140C0A0000C010UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x001004030000C010UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001414090000FFF0UL, /* 0x0090, */ 0x001408070000C010UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C08020000FFF0UL, /* 0x0268, */ 0x001408010000FFF0UL, /* 0x0270, */ 0x001404010000FFF0UL, /* 0x0278, */ 0x000C04010000FFF0UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001408010000FFF0UL, /* 0x0298, */ 0x001404010000FFF0UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; static uint64_t qoswt_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3/qos_init_m3_v11_qoswt390.h000066400000000000000000000176651355360272700270330ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t qoswt_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001008070000C010UL, /* 0x0038, */ 0x001008070000C010UL, /* 0x0040, */ 0x001424120000FFF0UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x001414130000C010UL, /* 0x0060, */ 0x001414130000C010UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x001008050000C010UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001424120000FFF0UL, /* 0x0090, */ 0x0014100D0000C010UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C0C030000FFF0UL, /* 0x0268, */ 0x001410010000FFF0UL, /* 0x0270, */ 0x001404010000FFF0UL, /* 0x0278, */ 0x000C08020000FFF0UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001410010000FFF0UL, /* 0x0298, */ 0x001404010000FFF0UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; static uint64_t qoswt_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3/qos_init_m3_v30.c000066400000000000000000000147521355360272700253300ustar00rootroot00000000000000/* * Copyright (c) 2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "../qos_common.h" #include "../qos_reg.h" #include "qos_init_m3_v30.h" #define RCAR_QOS_VERSION "rev.0.04" #define QOSWT_TIME_BANK0 20000000U /* unit:ns */ #define QOSWT_WTEN_ENABLE 0x1U #define QOSCTRL_REF_ARS_ARBSTOPCYCLE_M3_30 (SL_INIT_SSLOTCLK_M3_30 - 0x5U) #define OSWT_WTREF_SLOT0_EN_REQ1_SLOT 3U #define OSWT_WTREF_SLOT0_EN_REQ2_SLOT 9U #define QOSWT_WTREF_SLOT0_EN \ ((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) | \ (0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT)) #define QOSWT_WTREF_SLOT1_EN \ ((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) | \ (0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT)) #define QOSWT_WTSET0_REQ_SSLOT0 5U #define WT_BASE_SUB_SLOT_NUM0 12U #define QOSWT_WTSET0_PERIOD0_M3_30 \ ((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_M3_30) - 1U) #define QOSWT_WTSET0_SSLOT0 (QOSWT_WTSET0_REQ_SSLOT0 - 1U) #define QOSWT_WTSET0_SLOTSLOT0 (WT_BASE_SUB_SLOT_NUM0 - 1U) #define QOSWT_WTSET1_PERIOD1_M3_30 \ ((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_M3_30) - 1U) #define QOSWT_WTSET1_SSLOT1 (QOSWT_WTSET0_REQ_SSLOT0 - 1U) #define QOSWT_WTSET1_SLOTSLOT1 (WT_BASE_SUB_SLOT_NUM0 - 1U) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT #if RCAR_REF_INT == RCAR_REF_DEFAULT #include "qos_init_m3_v30_mstat195.h" #else #include "qos_init_m3_v30_mstat390.h" #endif #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE #if RCAR_REF_INT == RCAR_REF_DEFAULT #include "qos_init_m3_v30_qoswt195.h" #else #include "qos_init_m3_v30_qoswt390.h" #endif #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ #endif struct rcar_gen3_dbsc_qos_settings m3_v30_qos[] = { /* BUFCAM settings */ { DBSC_DBCAM0CNF1, 0x00043218 }, { DBSC_DBCAM0CNF2, 0x000000F4 }, { DBSC_DBCAM0CNF3, 0x00000000 }, { DBSC_DBSCHCNT0, 0x000F0037 }, { DBSC_DBSCHSZ0, 0x00000001 }, { DBSC_DBSCHRW0, 0x22421111 }, /* DDR3 */ { DBSC_SCFCTST2, 0x012F1123 }, /* QoS Settings */ { DBSC_DBSCHQOS00, 0x00000F00 }, { DBSC_DBSCHQOS01, 0x00000B00 }, { DBSC_DBSCHQOS02, 0x00000000 }, { DBSC_DBSCHQOS03, 0x00000000 }, { DBSC_DBSCHQOS40, 0x00000300 }, { DBSC_DBSCHQOS41, 0x000002F0 }, { DBSC_DBSCHQOS42, 0x00000200 }, { DBSC_DBSCHQOS43, 0x00000100 }, { DBSC_DBSCHQOS90, 0x00000100 }, { DBSC_DBSCHQOS91, 0x000000F0 }, { DBSC_DBSCHQOS92, 0x000000A0 }, { DBSC_DBSCHQOS93, 0x00000040 }, { DBSC_DBSCHQOS120, 0x00000040 }, { DBSC_DBSCHQOS121, 0x00000030 }, { DBSC_DBSCHQOS122, 0x00000020 }, { DBSC_DBSCHQOS123, 0x00000010 }, { DBSC_DBSCHQOS130, 0x00000100 }, { DBSC_DBSCHQOS131, 0x000000F0 }, { DBSC_DBSCHQOS132, 0x000000A0 }, { DBSC_DBSCHQOS133, 0x00000040 }, { DBSC_DBSCHQOS140, 0x000000C0 }, { DBSC_DBSCHQOS141, 0x000000B0 }, { DBSC_DBSCHQOS142, 0x00000080 }, { DBSC_DBSCHQOS143, 0x00000040 }, { DBSC_DBSCHQOS150, 0x00000040 }, { DBSC_DBSCHQOS151, 0x00000030 }, { DBSC_DBSCHQOS152, 0x00000020 }, { DBSC_DBSCHQOS153, 0x00000010 }, }; void qos_init_m3_v30(void) { rcar_qos_dbsc_setting(m3_v30_qos, ARRAY_SIZE(m3_v30_qos), true); /* DRAM Split Address mapping */ #if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH #if RCAR_LSI == RCAR_M3 #error "Don't set DRAM Split 4ch(M3)" #else ERROR("DRAM Split 4ch not supported.(M3)"); panic(); #endif #elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH) || \ (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_AUTO) NOTICE("BL2: DRAM Split is 2ch\n"); io_write_32(AXI_ADSPLCR0, 0x00000000U); io_write_32(AXI_ADSPLCR1, ADSPLCR0_ADRMODE_DEFAULT | ADSPLCR0_SPLITSEL(0xFFU) | ADSPLCR0_AREA(0x1DU) | ADSPLCR0_SWP); io_write_32(AXI_ADSPLCR2, 0x00001004U); io_write_32(AXI_ADSPLCR3, 0x00000000U); #else NOTICE("BL2: DRAM Split is OFF\n"); #endif #if !(RCAR_QOS_TYPE == RCAR_QOS_NONE) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION); #endif #if RCAR_REF_INT == RCAR_REF_DEFAULT NOTICE("BL2: DRAM refresh interval 1.95 usec\n"); #else NOTICE("BL2: DRAM refresh interval 3.9 usec\n"); #endif #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE NOTICE("BL2: Periodic Write DQ Training\n"); #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ io_write_32(QOSCTRL_RAS, 0x00000044U); io_write_64(QOSCTRL_DANN, 0x0404020002020201UL); io_write_32(QOSCTRL_DANT, 0x0020100AU); io_write_32(QOSCTRL_FSS, 0x0000000AU); io_write_32(QOSCTRL_INSFC, 0x06330001U); io_write_32(QOSCTRL_EARLYR, 0x00000001U); io_write_32(QOSCTRL_RACNT0, 0x02010003U); /* GPU Boost Mode ON */ /* GPU Boost Mode */ io_write_32(QOSCTRL_STATGEN0, 0x00000001U); io_write_32(QOSCTRL_SL_INIT, SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK_M3_30); io_write_32(QOSCTRL_REF_ARS, ((QOSCTRL_REF_ARS_ARBSTOPCYCLE_M3_30 << 16))); uint32_t i; for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) { io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]); io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]); } for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) { io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]); io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]); } #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE for (i = 0U; i < ARRAY_SIZE(qoswt_fix); i++) { io_write_64(QOSWT_FIX_WTQOS_BANK0 + i * 8, qoswt_fix[i]); io_write_64(QOSWT_FIX_WTQOS_BANK1 + i * 8, qoswt_fix[i]); } for (i = 0U; i < ARRAY_SIZE(qoswt_be); i++) { io_write_64(QOSWT_BE_WTQOS_BANK0 + i * 8, qoswt_be[i]); io_write_64(QOSWT_BE_WTQOS_BANK1 + i * 8, qoswt_be[i]); } #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ /* RT bus Leaf setting */ io_write_32(RT_ACT0, 0x00000000U); io_write_32(RT_ACT1, 0x00000000U); /* CCI bus Leaf setting */ io_write_32(CPU_ACT0, 0x00000003U); io_write_32(CPU_ACT1, 0x00000003U); io_write_32(CPU_ACT2, 0x00000003U); io_write_32(CPU_ACT3, 0x00000003U); io_write_32(QOSCTRL_RAEN, 0x00000001U); #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE /* re-write training setting */ io_write_32(QOSWT_WTREF, ((QOSWT_WTREF_SLOT1_EN << 16) | QOSWT_WTREF_SLOT0_EN)); io_write_32(QOSWT_WTSET0, ((QOSWT_WTSET0_PERIOD0_M3_30 << 16) | (QOSWT_WTSET0_SSLOT0 << 8) | QOSWT_WTSET0_SLOTSLOT0)); io_write_32(QOSWT_WTSET1, ((QOSWT_WTSET1_PERIOD1_M3_30 << 16) | (QOSWT_WTSET1_SSLOT1 << 8) | QOSWT_WTSET1_SLOTSLOT1)); io_write_32(QOSWT_WTEN, QOSWT_WTEN_ENABLE); #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ io_write_32(QOSCTRL_STATQC, 0x00000001U); #else NOTICE("BL2: QoS is None\n"); io_write_32(QOSCTRL_RAEN, 0x00000001U); #endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */ } trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3/qos_init_m3_v30.h000066400000000000000000000003701355360272700253240ustar00rootroot00000000000000/* * Copyright (c) 2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef QOS_INIT_H_M3_V30__ #define QOS_INIT_H_M3_V30__ void qos_init_m3_v30(void); #endif /* QOS_INIT_H_M3_V30__ */ trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_mstat195.h000066400000000000000000000176651355360272700270120ustar00rootroot00000000000000/* * Copyright (c) 2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001004040000FFFFUL, /* 0x0038, */ 0x001004040000FFFFUL, /* 0x0040, */ 0x001414090000FFFFUL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x001404010000FFFFUL, /* 0x0058, */ 0x00140C0A0000FFFFUL, /* 0x0060, */ 0x00140C0A0000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x001404010000FFFFUL, /* 0x0078, */ 0x001004030000FFFFUL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001414090000FFFFUL, /* 0x0090, */ 0x001408070000FFFFUL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x000C04020000FFFFUL, /* 0x00a8, */ 0x000C04010000FFFFUL, /* 0x00b0, */ 0x000C04010000FFFFUL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x000C04020000FFFFUL, /* 0x00c8, */ 0x000C04010000FFFFUL, /* 0x00d0, */ 0x000C04010000FFFFUL, /* 0x00d8, */ 0x000C08050000FFFFUL, /* 0x00e0, */ 0x000C10100000FFFFUL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x001024090000FFFFUL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x00100C090000FFFFUL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x000C10100000FFFFUL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x00100C0B0000FFFFUL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0010100D0000FFFFUL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x00100C0B0000FFFFUL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x001008060000FFFFUL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x00102C2C0000FFFFUL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x00100C0B0000FFFFUL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x000C04010000FFFFUL, /* 0x01c8, */ 0x000C04010000FFFFUL, /* 0x01d0, */ 0x000C04010000FFFFUL, /* 0x01d8, */ 0x000C04010000FFFFUL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x000C04010000FFFFUL, /* 0x01f0, */ 0x000C04010000FFFFUL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x000C04010000FFFFUL, /* 0x0210, */ 0x000C04010000FFFFUL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C08020000FFFFUL, /* 0x0268, */ 0x001408010000FFFFUL, /* 0x0270, */ 0x001404010000FFFFUL, /* 0x0278, */ 0x000C04010000FFFFUL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001408010000FFFFUL, /* 0x0298, */ 0x001404010000FFFFUL, /* 0x02a0, */ 0x000C04010000FFFFUL, /* 0x02a8, */ 0x000C04010000FFFFUL, /* 0x02b0, */ 0x001408010000FFFFUL, /* 0x02b8, */ 0x000C04010000FFFFUL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x000C04010000FFFFUL, /* 0x02d8, */ 0x000C04010000FFFFUL, /* 0x02e0, */ 0x001408010000FFFFUL, /* 0x02e8, */ 0x000C04010000FFFFUL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; static uint64_t mstat_be[] = { /* 0x0000, */ 0x001200200BDFFC01UL, /* 0x0008, */ 0x001200200BDFFC01UL, /* 0x0010, */ 0x001200200BDFFC01UL, /* 0x0018, */ 0x001200200BDFFC01UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x001200100BD03401UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x002100600BDFFC01UL, /* 0x01c8, */ 0x002100600BDFFC01UL, /* 0x01d0, */ 0x002100600BDFFC01UL, /* 0x01d8, */ 0x002100600BDFFC01UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x002100200BDFFC01UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x002100200BDFFC01UL, /* 0x0218, */ 0x001100200BDFFC01UL, /* 0x0220, */ 0x001100200BDFFC01UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x001100200BDFFC01UL, /* 0x0238, */ 0x001100200BDFFC01UL, /* 0x0240, */ 0x001200200BDFFC01UL, /* 0x0248, */ 0x001100200BDFFC01UL, /* 0x0250, */ 0x001200200BDFFC01UL, /* 0x0258, */ 0x001100200BDFFC01UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x001100400BDFFC01UL, /* 0x02f8, */ 0x001100600BDFFC01UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x001100400BDFFC01UL, /* 0x0310, */ 0x001100600BDFFC01UL, /* 0x0318, */ 0x001200100BD03401UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_mstat390.h000066400000000000000000000176651355360272700270070ustar00rootroot00000000000000/* * Copyright (c) 2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001008070000FFFFUL, /* 0x0038, */ 0x001008070000FFFFUL, /* 0x0040, */ 0x001424120000FFFFUL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x001404010000FFFFUL, /* 0x0058, */ 0x001414130000FFFFUL, /* 0x0060, */ 0x001414130000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x001404010000FFFFUL, /* 0x0078, */ 0x001008050000FFFFUL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001424120000FFFFUL, /* 0x0090, */ 0x0014100D0000FFFFUL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x000C08040000FFFFUL, /* 0x00a8, */ 0x000C04020000FFFFUL, /* 0x00b0, */ 0x000C04020000FFFFUL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x000C08040000FFFFUL, /* 0x00c8, */ 0x000C04020000FFFFUL, /* 0x00d0, */ 0x000C04020000FFFFUL, /* 0x00d8, */ 0x000C0C0A0000FFFFUL, /* 0x00e0, */ 0x000C201F0000FFFFUL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x001044110000FFFFUL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x001014110000FFFFUL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x000C201F0000FFFFUL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x001018150000FFFFUL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x00101C190000FFFFUL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x001018150000FFFFUL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x00100C0B0000FFFFUL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x001058570000FFFFUL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x001018150000FFFFUL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x000C04010000FFFFUL, /* 0x01c8, */ 0x000C04010000FFFFUL, /* 0x01d0, */ 0x000C04010000FFFFUL, /* 0x01d8, */ 0x000C04010000FFFFUL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x000C04010000FFFFUL, /* 0x01f0, */ 0x000C04010000FFFFUL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x000C04010000FFFFUL, /* 0x0210, */ 0x000C04010000FFFFUL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C0C030000FFFFUL, /* 0x0268, */ 0x001410010000FFFFUL, /* 0x0270, */ 0x001404010000FFFFUL, /* 0x0278, */ 0x000C08020000FFFFUL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001410010000FFFFUL, /* 0x0298, */ 0x001404010000FFFFUL, /* 0x02a0, */ 0x000C04010000FFFFUL, /* 0x02a8, */ 0x000C04010000FFFFUL, /* 0x02b0, */ 0x00140C010000FFFFUL, /* 0x02b8, */ 0x000C04010000FFFFUL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x000C04010000FFFFUL, /* 0x02d8, */ 0x000C04010000FFFFUL, /* 0x02e0, */ 0x00140C010000FFFFUL, /* 0x02e8, */ 0x000C04010000FFFFUL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; static uint64_t mstat_be[] = { /* 0x0000, */ 0x0012003005EFFC01UL, /* 0x0008, */ 0x0012003005EFFC01UL, /* 0x0010, */ 0x0012003005EFFC01UL, /* 0x0018, */ 0x0012003005EFFC01UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0012001005E03401UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x002100B005EFFC01UL, /* 0x01c8, */ 0x002100B005EFFC01UL, /* 0x01d0, */ 0x002100B005EFFC01UL, /* 0x01d8, */ 0x002100B005EFFC01UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0021003005EFFC01UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0021003005EFFC01UL, /* 0x0218, */ 0x0011003005EFFC01UL, /* 0x0220, */ 0x0011003005EFFC01UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0011003005EFFC01UL, /* 0x0238, */ 0x0011003005EFFC01UL, /* 0x0240, */ 0x0012003005EFFC01UL, /* 0x0248, */ 0x0011003005EFFC01UL, /* 0x0250, */ 0x0012003005EFFC01UL, /* 0x0258, */ 0x0011003005EFFC01UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0011007005EFFC01UL, /* 0x02f8, */ 0x001100B005EFFC01UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0011007005EFFC01UL, /* 0x0310, */ 0x001100B005EFFC01UL, /* 0x0318, */ 0x0012001005E03401UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_qoswt195.h000066400000000000000000000176651355360272700270370ustar00rootroot00000000000000/* * Copyright (c) 2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t qoswt_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001004040000C010UL, /* 0x0038, */ 0x001004040000C010UL, /* 0x0040, */ 0x001414090000FFF0UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x00140C0A0000C010UL, /* 0x0060, */ 0x00140C0A0000C010UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x001004030000C010UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001414090000FFF0UL, /* 0x0090, */ 0x001408070000C010UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C08020000FFF0UL, /* 0x0268, */ 0x001408010000FFF0UL, /* 0x0270, */ 0x001404010000FFF0UL, /* 0x0278, */ 0x000C04010000FFF0UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001408010000FFF0UL, /* 0x0298, */ 0x001404010000FFF0UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; static uint64_t qoswt_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3/qos_init_m3_v30_qoswt390.h000066400000000000000000000176651355360272700270340ustar00rootroot00000000000000/* * Copyright (c) 2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t qoswt_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001008070000C010UL, /* 0x0038, */ 0x001008070000C010UL, /* 0x0040, */ 0x001424120000FFF0UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x001414130000C010UL, /* 0x0060, */ 0x001414130000C010UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x001008050000C010UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x001424120000FFF0UL, /* 0x0090, */ 0x0014100D0000C010UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C0C030000FFF0UL, /* 0x0268, */ 0x001410010000FFF0UL, /* 0x0270, */ 0x001404010000FFF0UL, /* 0x0278, */ 0x000C08020000FFF0UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001410010000FFF0UL, /* 0x0298, */ 0x001404010000FFF0UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; static uint64_t qoswt_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3N/000077500000000000000000000000001355360272700223555ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.c000066400000000000000000000135431355360272700256170ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "../qos_common.h" #include "../qos_reg.h" #include "qos_init_m3n_v10.h" #define RCAR_QOS_VERSION "rev.0.09" #define REF_ARS_ARBSTOPCYCLE_M3N \ (((SL_INIT_SSLOTCLK_M3N) - 5U) << 16U) #define QOSWT_TIME_BANK0 20000000U /* unit:ns */ #define QOSWT_WTEN_ENABLE 0x1U #define OSWT_WTREF_SLOT0_EN_REQ1_SLOT 3U #define OSWT_WTREF_SLOT0_EN_REQ2_SLOT 9U #define QOSWT_WTREF_SLOT0_EN \ ((0x1U << OSWT_WTREF_SLOT0_EN_REQ1_SLOT) | \ (0x1U << OSWT_WTREF_SLOT0_EN_REQ2_SLOT)) #define QOSWT_WTREF_SLOT1_EN QOSWT_WTREF_SLOT0_EN #define QOSWT_WTSET0_REQ_SSLOT0 5U #define WT_BASE_SUB_SLOT_NUM0 12U #define QOSWT_WTSET0_PERIOD0_M3N \ ((QOSWT_TIME_BANK0 / QOSWT_WTSET0_CYCLE_M3N) - 1U) #define QOSWT_WTSET0_SSLOT0 (QOSWT_WTSET0_REQ_SSLOT0 - 1U) #define QOSWT_WTSET0_SLOTSLOT0 (WT_BASE_SUB_SLOT_NUM0 - 1U) #define QOSWT_WTSET1_PERIOD1_M3N QOSWT_WTSET0_PERIOD0_M3N #define QOSWT_WTSET1_SSLOT1 QOSWT_WTSET0_SSLOT0 #define QOSWT_WTSET1_SLOTSLOT1 QOSWT_WTSET0_SLOTSLOT0 #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT #if RCAR_REF_INT == RCAR_REF_DEFAULT #include "qos_init_m3n_v10_mstat195.h" #else #include "qos_init_m3n_v10_mstat390.h" #endif #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE #if RCAR_REF_INT == RCAR_REF_DEFAULT #include "qos_init_m3n_v10_qoswt195.h" #else #include "qos_init_m3n_v10_qoswt390.h" #endif #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ #endif struct rcar_gen3_dbsc_qos_settings m3n_v10_qos[] = { /* BUFCAM settings */ { DBSC_DBCAM0CNF1, 0x00043218 }, { DBSC_DBCAM0CNF2, 0x000000F4 }, { DBSC_DBSCHCNT0, 0x000F0037 }, { DBSC_DBSCHSZ0, 0x00000001 }, { DBSC_DBSCHRW0, 0x22421111 }, /* DDR3 */ { DBSC_SCFCTST2, 0x012F1123 }, /* QoS Settings */ { DBSC_DBSCHQOS00, 0x00000F00 }, { DBSC_DBSCHQOS01, 0x00000B00 }, { DBSC_DBSCHQOS02, 0x00000000 }, { DBSC_DBSCHQOS03, 0x00000000 }, { DBSC_DBSCHQOS40, 0x00000300 }, { DBSC_DBSCHQOS41, 0x000002F0 }, { DBSC_DBSCHQOS42, 0x00000200 }, { DBSC_DBSCHQOS43, 0x00000100 }, { DBSC_DBSCHQOS90, 0x00000100 }, { DBSC_DBSCHQOS91, 0x000000F0 }, { DBSC_DBSCHQOS92, 0x000000A0 }, { DBSC_DBSCHQOS93, 0x00000040 }, { DBSC_DBSCHQOS130, 0x00000100 }, { DBSC_DBSCHQOS131, 0x000000F0 }, { DBSC_DBSCHQOS132, 0x000000A0 }, { DBSC_DBSCHQOS133, 0x00000040 }, { DBSC_DBSCHQOS140, 0x000000C0 }, { DBSC_DBSCHQOS141, 0x000000B0 }, { DBSC_DBSCHQOS142, 0x00000080 }, { DBSC_DBSCHQOS143, 0x00000040 }, { DBSC_DBSCHQOS150, 0x00000040 }, { DBSC_DBSCHQOS151, 0x00000030 }, { DBSC_DBSCHQOS152, 0x00000020 }, { DBSC_DBSCHQOS153, 0x00000010 }, }; void qos_init_m3n_v10(void) { rcar_qos_dbsc_setting(m3n_v10_qos, ARRAY_SIZE(m3n_v10_qos), true); /* DRAM Split Address mapping */ #if RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_4CH #if RCAR_LSI == RCAR_M3N #error "Don't set DRAM Split 4ch(M3N)" #else ERROR("DRAM Split 4ch not supported.(M3N)"); panic(); #endif #elif (RCAR_DRAM_SPLIT == RCAR_DRAM_SPLIT_2CH) #if RCAR_LSI == RCAR_M3N #error "Don't set DRAM Split 2ch(M3N)" #else ERROR("DRAM Split 2ch not supported.(M3N)"); panic(); #endif #else NOTICE("BL2: DRAM Split is OFF\n"); #endif #if !(RCAR_QOS_TYPE == RCAR_QOS_NONE) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION); #endif #if RCAR_REF_INT == RCAR_REF_DEFAULT NOTICE("BL2: DRAM refresh interval 1.95 usec\n"); #else NOTICE("BL2: DRAM refresh interval 3.9 usec\n"); #endif #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE NOTICE("BL2: Periodic Write DQ Training\n"); #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ io_write_32(QOSCTRL_RAS, 0x00000028U); io_write_64(QOSCTRL_DANN, 0x0402000002020201UL); io_write_32(QOSCTRL_DANT, 0x00100804U); io_write_32(QOSCTRL_FSS, 0x0000000AU); io_write_32(QOSCTRL_INSFC, 0x06330001U); io_write_32(QOSCTRL_EARLYR, 0x00000001U); io_write_32(QOSCTRL_RACNT0, 0x00010003U); io_write_32(QOSCTRL_SL_INIT, SL_INIT_REFFSSLOT | SL_INIT_SLOTSSLOT | SL_INIT_SSLOTCLK_M3N); io_write_32(QOSCTRL_REF_ARS, REF_ARS_ARBSTOPCYCLE_M3N); uint32_t i; for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) { io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]); io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]); } for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) { io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]); io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]); } #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE for (i = 0U; i < ARRAY_SIZE(qoswt_fix); i++) { io_write_64(QOSWT_FIX_WTQOS_BANK0 + i * 8, qoswt_fix[i]); io_write_64(QOSWT_FIX_WTQOS_BANK1 + i * 8, qoswt_fix[i]); } for (i = 0U; i < ARRAY_SIZE(qoswt_be); i++) { io_write_64(QOSWT_BE_WTQOS_BANK0 + i * 8, qoswt_be[i]); io_write_64(QOSWT_BE_WTQOS_BANK1 + i * 8, qoswt_be[i]); } #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ /* RT bus Leaf setting */ io_write_32(RT_ACT0, 0x00000000U); io_write_32(RT_ACT1, 0x00000000U); /* CCI bus Leaf setting */ io_write_32(CPU_ACT0, 0x00000003U); io_write_32(CPU_ACT1, 0x00000003U); io_write_32(QOSCTRL_RAEN, 0x00000001U); #if RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE /* re-write training setting */ io_write_32(QOSWT_WTREF, ((QOSWT_WTREF_SLOT1_EN << 16) | QOSWT_WTREF_SLOT0_EN)); io_write_32(QOSWT_WTSET0, ((QOSWT_WTSET0_PERIOD0_M3N << 16) | (QOSWT_WTSET0_SSLOT0 << 8) | QOSWT_WTSET0_SLOTSLOT0)); io_write_32(QOSWT_WTSET1, ((QOSWT_WTSET1_PERIOD1_M3N << 16) | (QOSWT_WTSET1_SSLOT1 << 8) | QOSWT_WTSET1_SLOTSLOT1)); io_write_32(QOSWT_WTEN, QOSWT_WTEN_ENABLE); #endif /* RCAR_REWT_TRAINING != RCAR_REWT_TRAINING_DISABLE */ io_write_32(QOSCTRL_STATQC, 0x00000001U); #else NOTICE("BL2: QoS is None\n"); io_write_32(QOSCTRL_RAEN, 0x00000001U); #endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */ } trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.h000066400000000000000000000003661355360272700256230ustar00rootroot00000000000000/* * Copyright (c) 2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef QOS_INIT_M3N_V10_H #define QOS_INIT_M3N_V10_H void qos_init_m3n_v10(void); #endif /* QOS_INIT_M3N_V10_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_mstat195.h000066400000000000000000000210051355360272700272630ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001004320000FFFFUL, /* 0x0038, */ 0x001004320000FFFFUL, /* 0x0040, */ 0x00140C5D0000FFFFUL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x001404040000FFFFUL, /* 0x0058, */ 0x00140C940000FFFFUL, /* 0x0060, */ 0x00140C940000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x001404040000FFFFUL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0014041F0000FFFFUL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x000C041D0000FFFFUL, /* 0x00a8, */ 0x000C04090000FFFFUL, /* 0x00b0, */ 0x000C040B0000FFFFUL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x000C041D0000FFFFUL, /* 0x00c8, */ 0x000C04090000FFFFUL, /* 0x00d0, */ 0x000C040B0000FFFFUL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x001024840000FFFFUL, /* 0x00f8, */ 0x000C084F0000FFFFUL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x00100C840000FFFFUL, /* 0x0118, */ 0x000C21E60000FFFFUL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x00100CA50000FFFFUL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x001010C90000FFFFUL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x00100CA50000FFFFUL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x001008530000FFFFUL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x00101D9D0000FFFFUL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x00100CA50000FFFFUL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x000C04010000FFFFUL, /* 0x01c8, */ 0x000C04010000FFFFUL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x000C04010000FFFFUL, /* 0x01f0, */ 0x000C04050000FFFFUL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x000C04050000FFFFUL, /* 0x0210, */ 0x000C04050000FFFFUL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C08150000FFFFUL, /* 0x0268, */ 0x001408020000FFFFUL, /* 0x0270, */ 0x001404010000FFFFUL, /* 0x0278, */ 0x000C04090000FFFFUL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001408020000FFFFUL, /* 0x0298, */ 0x001404010000FFFFUL, /* 0x02a0, */ 0x000C04050000FFFFUL, /* 0x02a8, */ 0x000C04050000FFFFUL, /* 0x02b0, */ 0x001408050000FFFFUL, /* 0x02b8, */ 0x000C04010000FFFFUL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x000C04050000FFFFUL, /* 0x02d8, */ 0x000C04050000FFFFUL, /* 0x02e0, */ 0x001408050000FFFFUL, /* 0x02e8, */ 0x000C04010000FFFFUL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, /* 0x0370, */ 0x000C04010000FFFFUL, /* 0x0378, */ 0x000C04010000FFFFUL, /* 0x0380, */ 0x000C04050000FFFFUL, /* 0x0388, */ 0x000C04050000FFFFUL, /* 0x0390, */ 0x0000000000000000UL, }; static uint64_t mstat_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x001200100BD03401UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x002106000BDFFC01UL, /* 0x01c8, */ 0x002106000BDFFC01UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x002101000BDF2401UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x002101000BDF2401UL, /* 0x0218, */ 0x001101000BDF2401UL, /* 0x0220, */ 0x001101000BDF2401UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x001101000BDF2401UL, /* 0x0238, */ 0x001101000BDF2401UL, /* 0x0240, */ 0x001201000BDF2401UL, /* 0x0248, */ 0x001101000BDF2401UL, /* 0x0250, */ 0x001201000BDF2401UL, /* 0x0258, */ 0x001101000BDF2401UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x001106000BDFFC01UL, /* 0x02f8, */ 0x001106000BDFFC01UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x001200100BD03401UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x001206000BDFFC01UL, /* 0x0360, */ 0x001206000BDFFC01UL, /* 0x0368, */ 0x001200100BD03401UL, /* 0x0370, */ 0x0000000000000000UL, /* 0x0378, */ 0x0000000000000000UL, /* 0x0380, */ 0x0000000000000000UL, /* 0x0388, */ 0x0000000000000000UL, /* 0x0390, */ 0x001200100BD03401UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_mstat390.h000066400000000000000000000210051355360272700272600ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t mstat_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001008630000FFFFUL, /* 0x0038, */ 0x001008630000FFFFUL, /* 0x0040, */ 0x001418BA0000FFFFUL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x001404070000FFFFUL, /* 0x0058, */ 0x001415270000FFFFUL, /* 0x0060, */ 0x001415270000FFFFUL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x001404070000FFFFUL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0014083E0000FFFFUL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x000C08390000FFFFUL, /* 0x00a8, */ 0x000C04110000FFFFUL, /* 0x00b0, */ 0x000C04150000FFFFUL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x000C08390000FFFFUL, /* 0x00c8, */ 0x000C04110000FFFFUL, /* 0x00d0, */ 0x000C04150000FFFFUL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x001045080000FFFFUL, /* 0x00f8, */ 0x000C0C9E0000FFFFUL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x001015080000FFFFUL, /* 0x0118, */ 0x000C43CB0000FFFFUL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0010194A0000FFFFUL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x00101D910000FFFFUL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0010194A0000FFFFUL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x00100CA50000FFFFUL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x001037390000FFFFUL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0010194A0000FFFFUL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x000C04010000FFFFUL, /* 0x01c8, */ 0x000C04010000FFFFUL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x000C04020000FFFFUL, /* 0x01f0, */ 0x000C04090000FFFFUL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x000C04090000FFFFUL, /* 0x0210, */ 0x000C04090000FFFFUL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C0C2A0000FFFFUL, /* 0x0268, */ 0x001410040000FFFFUL, /* 0x0270, */ 0x001404020000FFFFUL, /* 0x0278, */ 0x000C08110000FFFFUL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001410040000FFFFUL, /* 0x0298, */ 0x001404020000FFFFUL, /* 0x02a0, */ 0x000C04090000FFFFUL, /* 0x02a8, */ 0x000C04090000FFFFUL, /* 0x02b0, */ 0x00140C090000FFFFUL, /* 0x02b8, */ 0x000C04020000FFFFUL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x000C04090000FFFFUL, /* 0x02d8, */ 0x000C04090000FFFFUL, /* 0x02e0, */ 0x00140C090000FFFFUL, /* 0x02e8, */ 0x000C04020000FFFFUL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, /* 0x0370, */ 0x000C04020000FFFFUL, /* 0x0378, */ 0x000C04020000FFFFUL, /* 0x0380, */ 0x000C04090000FFFFUL, /* 0x0388, */ 0x000C04090000FFFFUL, /* 0x0390, */ 0x0000000000000000UL, }; static uint64_t mstat_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0012001005E03401UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0021060005EFFC01UL, /* 0x01c8, */ 0x0021060005EFFC01UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0021010005E79401UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0021010005E79401UL, /* 0x0218, */ 0x0011010005E79401UL, /* 0x0220, */ 0x0011010005E79401UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0011010005E79401UL, /* 0x0238, */ 0x0011010005E79401UL, /* 0x0240, */ 0x0012010005E79401UL, /* 0x0248, */ 0x0011010005E79401UL, /* 0x0250, */ 0x0012010005E79401UL, /* 0x0258, */ 0x0011010005E79401UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0011060005EFFC01UL, /* 0x02f8, */ 0x0011060005EFFC01UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0012001005E03401UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0012060005EFFC01UL, /* 0x0360, */ 0x0012060005EFFC01UL, /* 0x0368, */ 0x0012001005E03401UL, /* 0x0370, */ 0x0000000000000000UL, /* 0x0378, */ 0x0000000000000000UL, /* 0x0380, */ 0x0000000000000000UL, /* 0x0388, */ 0x0000000000000000UL, /* 0x0390, */ 0x0012001005E03401UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_qoswt195.h000066400000000000000000000210051355360272700273100ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t qoswt_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001004320000C010UL, /* 0x0038, */ 0x001004320000C010UL, /* 0x0040, */ 0x00140C5D0000FFF0UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x00140C940000C010UL, /* 0x0060, */ 0x00140C940000C010UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0014041F0000FFF0UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C08150000FFF0UL, /* 0x0268, */ 0x001408020000FFF0UL, /* 0x0270, */ 0x001404010000FFF0UL, /* 0x0278, */ 0x000C04090000FFF0UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001408020000FFF0UL, /* 0x0298, */ 0x001404010000FFF0UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, /* 0x0370, */ 0x0000000000000000UL, /* 0x0378, */ 0x0000000000000000UL, /* 0x0380, */ 0x0000000000000000UL, /* 0x0388, */ 0x0000000000000000UL, /* 0x0390, */ 0x0000000000000000UL, }; static uint64_t qoswt_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, /* 0x0370, */ 0x0000000000000000UL, /* 0x0378, */ 0x0000000000000000UL, /* 0x0380, */ 0x0000000000000000UL, /* 0x0388, */ 0x0000000000000000UL, /* 0x0390, */ 0x0000000000000000UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10_qoswt390.h000066400000000000000000000210051355360272700273050ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint64_t qoswt_fix[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x001008630000C010UL, /* 0x0038, */ 0x001008630000C010UL, /* 0x0040, */ 0x001418BA0000FFF0UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x001415270000C010UL, /* 0x0060, */ 0x001415270000C010UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0014083E0000FFF0UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x000C0C2A0000FFF0UL, /* 0x0268, */ 0x001410040000FFF0UL, /* 0x0270, */ 0x001404020000FFF0UL, /* 0x0278, */ 0x000C08110000FFF0UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x001410040000FFF0UL, /* 0x0298, */ 0x001404020000FFF0UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, /* 0x0370, */ 0x0000000000000000UL, /* 0x0378, */ 0x0000000000000000UL, /* 0x0380, */ 0x0000000000000000UL, /* 0x0388, */ 0x0000000000000000UL, /* 0x0390, */ 0x0000000000000000UL, }; static uint64_t qoswt_be[] = { /* 0x0000, */ 0x0000000000000000UL, /* 0x0008, */ 0x0000000000000000UL, /* 0x0010, */ 0x0000000000000000UL, /* 0x0018, */ 0x0000000000000000UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00a0, */ 0x0000000000000000UL, /* 0x00a8, */ 0x0000000000000000UL, /* 0x00b0, */ 0x0000000000000000UL, /* 0x00b8, */ 0x0000000000000000UL, /* 0x00c0, */ 0x0000000000000000UL, /* 0x00c8, */ 0x0000000000000000UL, /* 0x00d0, */ 0x0000000000000000UL, /* 0x00d8, */ 0x0000000000000000UL, /* 0x00e0, */ 0x0000000000000000UL, /* 0x00e8, */ 0x0000000000000000UL, /* 0x00f0, */ 0x0000000000000000UL, /* 0x00f8, */ 0x0000000000000000UL, /* 0x0100, */ 0x0000000000000000UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x0000000000000000UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x0000000000000000UL, /* 0x0128, */ 0x0000000000000000UL, /* 0x0130, */ 0x0000000000000000UL, /* 0x0138, */ 0x0000000000000000UL, /* 0x0140, */ 0x0000000000000000UL, /* 0x0148, */ 0x0000000000000000UL, /* 0x0150, */ 0x0000000000000000UL, /* 0x0158, */ 0x0000000000000000UL, /* 0x0160, */ 0x0000000000000000UL, /* 0x0168, */ 0x0000000000000000UL, /* 0x0170, */ 0x0000000000000000UL, /* 0x0178, */ 0x0000000000000000UL, /* 0x0180, */ 0x0000000000000000UL, /* 0x0188, */ 0x0000000000000000UL, /* 0x0190, */ 0x0000000000000000UL, /* 0x0198, */ 0x0000000000000000UL, /* 0x01a0, */ 0x0000000000000000UL, /* 0x01a8, */ 0x0000000000000000UL, /* 0x01b0, */ 0x0000000000000000UL, /* 0x01b8, */ 0x0000000000000000UL, /* 0x01c0, */ 0x0000000000000000UL, /* 0x01c8, */ 0x0000000000000000UL, /* 0x01d0, */ 0x0000000000000000UL, /* 0x01d8, */ 0x0000000000000000UL, /* 0x01e0, */ 0x0000000000000000UL, /* 0x01e8, */ 0x0000000000000000UL, /* 0x01f0, */ 0x0000000000000000UL, /* 0x01f8, */ 0x0000000000000000UL, /* 0x0200, */ 0x0000000000000000UL, /* 0x0208, */ 0x0000000000000000UL, /* 0x0210, */ 0x0000000000000000UL, /* 0x0218, */ 0x0000000000000000UL, /* 0x0220, */ 0x0000000000000000UL, /* 0x0228, */ 0x0000000000000000UL, /* 0x0230, */ 0x0000000000000000UL, /* 0x0238, */ 0x0000000000000000UL, /* 0x0240, */ 0x0000000000000000UL, /* 0x0248, */ 0x0000000000000000UL, /* 0x0250, */ 0x0000000000000000UL, /* 0x0258, */ 0x0000000000000000UL, /* 0x0260, */ 0x0000000000000000UL, /* 0x0268, */ 0x0000000000000000UL, /* 0x0270, */ 0x0000000000000000UL, /* 0x0278, */ 0x0000000000000000UL, /* 0x0280, */ 0x0000000000000000UL, /* 0x0288, */ 0x0000000000000000UL, /* 0x0290, */ 0x0000000000000000UL, /* 0x0298, */ 0x0000000000000000UL, /* 0x02a0, */ 0x0000000000000000UL, /* 0x02a8, */ 0x0000000000000000UL, /* 0x02b0, */ 0x0000000000000000UL, /* 0x02b8, */ 0x0000000000000000UL, /* 0x02c0, */ 0x0000000000000000UL, /* 0x02c8, */ 0x0000000000000000UL, /* 0x02d0, */ 0x0000000000000000UL, /* 0x02d8, */ 0x0000000000000000UL, /* 0x02e0, */ 0x0000000000000000UL, /* 0x02e8, */ 0x0000000000000000UL, /* 0x02f0, */ 0x0000000000000000UL, /* 0x02f8, */ 0x0000000000000000UL, /* 0x0300, */ 0x0000000000000000UL, /* 0x0308, */ 0x0000000000000000UL, /* 0x0310, */ 0x0000000000000000UL, /* 0x0318, */ 0x0000000000000000UL, /* 0x0320, */ 0x0000000000000000UL, /* 0x0328, */ 0x0000000000000000UL, /* 0x0330, */ 0x0000000000000000UL, /* 0x0338, */ 0x0000000000000000UL, /* 0x0340, */ 0x0000000000000000UL, /* 0x0348, */ 0x0000000000000000UL, /* 0x0350, */ 0x0000000000000000UL, /* 0x0358, */ 0x0000000000000000UL, /* 0x0360, */ 0x0000000000000000UL, /* 0x0368, */ 0x0000000000000000UL, /* 0x0370, */ 0x0000000000000000UL, /* 0x0378, */ 0x0000000000000000UL, /* 0x0380, */ 0x0000000000000000UL, /* 0x0388, */ 0x0000000000000000UL, /* 0x0390, */ 0x0000000000000000UL, }; trusted-firmware-a-2.2/drivers/renesas/rcar/qos/V3M/000077500000000000000000000000001355360272700223655ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/qos/V3M/qos_init_v3m.c000066400000000000000000000057751355360272700251610ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "../qos_common.h" #include "../qos_reg.h" #include "qos_init_v3m.h" #define RCAR_QOS_VERSION "rev.0.01" #include "qos_init_v3m_mstat.h" struct rcar_gen3_dbsc_qos_settings v3m_qos[] = { /* BUFCAM settings */ { DBSC_DBCAM0CNF1, 0x00044218 }, { DBSC_DBCAM0CNF2, 0x000000F4 }, { DBSC_DBSCHCNT0, 0x080F003F }, { DBSC_DBSCHCNT1, 0x00001010 }, { DBSC_DBSCHSZ0, 0x00000001 }, { DBSC_DBSCHRW0, 0x22421111 }, { DBSC_DBSCHRW1, 0x00180034 }, { DBSC_SCFCTST0, 0x180B1708 }, { DBSC_SCFCTST1, 0x0808070C }, { DBSC_SCFCTST2, 0x012F1123 }, /* QoS Settings */ { DBSC_DBSCHQOS00, 0x0000F000 }, { DBSC_DBSCHQOS01, 0x0000E000 }, { DBSC_DBSCHQOS02, 0x00007000 }, { DBSC_DBSCHQOS03, 0x00000000 }, { DBSC_DBSCHQOS40, 0x0000F000 }, { DBSC_DBSCHQOS41, 0x0000EFFF }, { DBSC_DBSCHQOS42, 0x0000B000 }, { DBSC_DBSCHQOS43, 0x00000000 }, { DBSC_DBSCHQOS90, 0x0000F000 }, { DBSC_DBSCHQOS91, 0x0000EFFF }, { DBSC_DBSCHQOS92, 0x0000D000 }, { DBSC_DBSCHQOS93, 0x00000000 }, { DBSC_DBSCHQOS130, 0x0000F000 }, { DBSC_DBSCHQOS131, 0x0000EFFF }, { DBSC_DBSCHQOS132, 0x0000E800 }, { DBSC_DBSCHQOS133, 0x00007000 }, { DBSC_DBSCHQOS140, 0x0000F000 }, { DBSC_DBSCHQOS141, 0x0000EFFF }, { DBSC_DBSCHQOS142, 0x0000E800 }, { DBSC_DBSCHQOS143, 0x0000B000 }, { DBSC_DBSCHQOS150, 0x000007D0 }, { DBSC_DBSCHQOS151, 0x000007CF }, { DBSC_DBSCHQOS152, 0x000005D0 }, { DBSC_DBSCHQOS153, 0x000003D0 }, }; void qos_init_v3m(void) { return; rcar_qos_dbsc_setting(v3m_qos, ARRAY_SIZE(v3m_qos), false); #if !(RCAR_QOS_TYPE == RCAR_QOS_NONE) #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT NOTICE("BL2: QoS is default setting(%s)\n", RCAR_QOS_VERSION); #endif /* Resource Alloc setting */ io_write_32(QOSCTRL_RAS, 0x00000020U); io_write_32(QOSCTRL_FIXTH, 0x000F0005U); io_write_32(QOSCTRL_REGGD, 0x00000004U); io_write_64(QOSCTRL_DANN, 0x0202020104040200U); io_write_32(QOSCTRL_DANT, 0x00201008U); io_write_32(QOSCTRL_EC, 0x00080001U); /* need for H3 ES1 */ io_write_64(QOSCTRL_EMS, 0x0000000000000000U); io_write_32(QOSCTRL_INSFC, 0x63C20001U); io_write_32(QOSCTRL_BERR, 0x00000000U); /* QOSBW setting */ io_write_32(QOSCTRL_SL_INIT, 0x0305007DU); io_write_32(QOSCTRL_REF_ARS, 0x00330000U); /* QOSBW SRAM setting */ uint32_t i; for (i = 0U; i < ARRAY_SIZE(mstat_fix); i++) { io_write_64(QOSBW_FIX_QOS_BANK0 + i * 8, mstat_fix[i]); io_write_64(QOSBW_FIX_QOS_BANK1 + i * 8, mstat_fix[i]); } for (i = 0U; i < ARRAY_SIZE(mstat_be); i++) { io_write_64(QOSBW_BE_QOS_BANK0 + i * 8, mstat_be[i]); io_write_64(QOSBW_BE_QOS_BANK1 + i * 8, mstat_be[i]); } /* AXI-IF arbitration setting */ io_write_32(DBSC_AXARB, 0x18010000U); /* Resource Alloc start */ io_write_32(QOSCTRL_RAEN, 0x00000001U); /* QOSBW start */ io_write_32(QOSCTRL_STATQC, 0x00000001U); #else NOTICE("BL2: QoS is None\n"); #endif /* !(RCAR_QOS_TYPE == RCAR_QOS_NONE) */ } trusted-firmware-a-2.2/drivers/renesas/rcar/qos/V3M/qos_init_v3m.h000066400000000000000000000003631355360272700251520ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef QOS_INIT_H_V3M__ #define QOS_INIT_H_V3M__ void qos_init_v3m(void); #endif /* QOS_INIT_H_V3M__ */ trusted-firmware-a-2.2/drivers/renesas/rcar/qos/V3M/qos_init_v3m_mstat.h000066400000000000000000000064611355360272700263670ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #if RCAR_QOS_TYPE == RCAR_QOS_TYPE_DEFAULT static const uint64_t mstat_fix[] = { /* 0x0000, */ 0x000000000000FFFFUL, /* 0x0008, */ 0x000000000000FFFFUL, /* 0x0010, */ 0x000000000000FFFFUL, /* 0x0018, */ 0x000000000000FFFFUL, /* 0x0020, */ 0x001414090000FFFFUL, /* 0x0028, */ 0x000C00000000FFFFUL, /* 0x0030, */ 0x001008040000FFFFUL, /* 0x0038, */ 0x001004040000FFFFUL, /* 0x0040, */ 0x001004040000FFFFUL, /* 0x0048, */ 0x000000000000FFFFUL, /* 0x0050, */ 0x001004040000FFFFUL, /* 0x0058, */ 0x001004040000FFFFUL, /* 0x0060, */ 0x000000000000FFFFUL, /* 0x0068, */ 0x001404040000FFFFUL, /* 0x0070, */ 0x001008030000FFFFUL, /* 0x0078, */ 0x001004030000FFFFUL, /* 0x0080, */ 0x001004030000FFFFUL, /* 0x0088, */ 0x000000000000FFFFUL, /* 0x0090, */ 0x001004040000FFFFUL, /* 0x0098, */ 0x001004040000FFFFUL, /* 0x00A0, */ 0x000000000000FFFFUL, /* 0x00A8, */ 0x000000000000FFFFUL, /* 0x00B0, */ 0x000000000000FFFFUL, /* 0x00B8, */ 0x000000000000FFFFUL, /* 0x00C0, */ 0x000000000000FFFFUL, /* 0x00C8, */ 0x000000000000FFFFUL, /* 0x00D0, */ 0x000000000000FFFFUL, /* 0x00D8, */ 0x000000000000FFFFUL, /* 0x00E0, */ 0x001404020000FFFFUL, /* 0x00E8, */ 0x000000000000FFFFUL, /* 0x00F0, */ 0x000000000000FFFFUL, /* 0x00F8, */ 0x000000000000FFFFUL, /* 0x0100, */ 0x000000000000FFFFUL, /* 0x0108, */ 0x000C04020000FFFFUL, /* 0x0110, */ 0x000000000000FFFFUL, /* 0x0118, */ 0x001404020000FFFFUL, /* 0x0120, */ 0x000000000000FFFFUL, /* 0x0128, */ 0x000000000000FFFFUL, /* 0x0130, */ 0x000000000000FFFFUL, /* 0x0138, */ 0x000000000000FFFFUL, /* 0x0140, */ 0x000000000000FFFFUL, /* 0x0148, */ 0x000000000000FFFFUL, }; static const uint64_t mstat_be[] = { /* 0x0000, */ 0x00100020447FFC01UL, /* 0x0008, */ 0x00100020447FFC01UL, /* 0x0010, */ 0x00100040447FFC01UL, /* 0x0018, */ 0x00100040447FFC01UL, /* 0x0020, */ 0x0000000000000000UL, /* 0x0028, */ 0x0000000000000000UL, /* 0x0030, */ 0x0000000000000000UL, /* 0x0038, */ 0x0000000000000000UL, /* 0x0040, */ 0x0000000000000000UL, /* 0x0048, */ 0x0000000000000000UL, /* 0x0050, */ 0x0000000000000000UL, /* 0x0058, */ 0x0000000000000000UL, /* 0x0060, */ 0x0000000000000000UL, /* 0x0068, */ 0x0000000000000000UL, /* 0x0070, */ 0x0000000000000000UL, /* 0x0078, */ 0x0000000000000000UL, /* 0x0080, */ 0x0000000000000000UL, /* 0x0088, */ 0x0000000000000000UL, /* 0x0090, */ 0x0000000000000000UL, /* 0x0098, */ 0x0000000000000000UL, /* 0x00A0, */ 0x00100010447FFC01UL, /* 0x00A8, */ 0x00100010447FFC01UL, /* 0x00B0, */ 0x00100010447FFC01UL, /* 0x00B8, */ 0x00100010447FFC01UL, /* 0x00C0, */ 0x00100010447FFC01UL, /* 0x00C8, */ 0x00100010447FFC01UL, /* 0x00D0, */ 0x0000000000000000UL, /* 0x00D8, */ 0x00100010447FFC01UL, /* 0x00E0, */ 0x0000000000000000UL, /* 0x00E8, */ 0x00100010447FFC01UL, /* 0x00F0, */ 0x00100010447FFC01UL, /* 0x00F8, */ 0x00100010447FFC01UL, /* 0x0100, */ 0x00100010447FFC01UL, /* 0x0108, */ 0x0000000000000000UL, /* 0x0110, */ 0x00100010447FFC01UL, /* 0x0118, */ 0x0000000000000000UL, /* 0x0120, */ 0x00100010447FFC01UL, /* 0x0128, */ 0x00100010447FFC01UL, /* 0x0130, */ 0x00100010447FFC01UL, /* 0x0138, */ 0x00100010447FFC01UL, /* 0x0140, */ 0x00100020447FFC01UL, /* 0x0148, */ 0x00100020447FFC01UL, }; #endif trusted-firmware-a-2.2/drivers/renesas/rcar/qos/qos.mk000066400000000000000000000075451355360272700231260ustar00rootroot00000000000000# # Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ifeq (${RCAR_LSI},${RCAR_AUTO}) # E3, H3N not available for LSI_AUTO BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v10.c BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v11.c BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v20.c BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v30.c BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v10.c BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v11.c BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v30.c BL2_SOURCES += drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.c BL2_SOURCES += drivers/renesas/rcar/qos/V3M/qos_init_v3m.c else ifdef RCAR_LSI_CUT_COMPAT ifeq (${RCAR_LSI},${RCAR_H3}) BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v10.c BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v11.c BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v20.c BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v30.c endif ifeq (${RCAR_LSI},${RCAR_H3N}) BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.c endif ifeq (${RCAR_LSI},${RCAR_M3}) BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v10.c BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v11.c BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v30.c endif ifeq (${RCAR_LSI},${RCAR_M3N}) BL2_SOURCES += drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.c endif ifeq (${RCAR_LSI},${RCAR_V3M}) BL2_SOURCES += drivers/renesas/rcar/qos/V3M/qos_init_v3m.c endif ifeq (${RCAR_LSI},${RCAR_E3}) BL2_SOURCES += drivers/renesas/rcar/qos/E3/qos_init_e3_v10.c endif ifeq (${RCAR_LSI},${RCAR_D3}) BL2_SOURCES += drivers/renesas/rcar/qos/D3/qos_init_d3.c endif else ifeq (${RCAR_LSI},${RCAR_H3}) ifeq (${LSI_CUT},10) BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v10.c else ifeq (${LSI_CUT},11) BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v11.c else ifeq (${LSI_CUT},20) BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v20.c else ifeq (${LSI_CUT},30) BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v30.c else # LSI_CUT 30 or later BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3_v30.c endif endif ifeq (${RCAR_LSI},${RCAR_H3N}) ifeq (${LSI_CUT},30) BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.c else # LSI_CUT 30 or later BL2_SOURCES += drivers/renesas/rcar/qos/H3/qos_init_h3n_v30.c endif endif ifeq (${RCAR_LSI},${RCAR_M3}) ifeq (${LSI_CUT},10) BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v10.c else ifeq (${LSI_CUT},11) BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v11.c else ifeq (${LSI_CUT},13) BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v11.c else ifeq (${LSI_CUT},30) BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v30.c else # LSI_CUT 30 or later BL2_SOURCES += drivers/renesas/rcar/qos/M3/qos_init_m3_v30.c endif endif ifeq (${RCAR_LSI},${RCAR_M3N}) ifeq (${LSI_CUT},10) BL2_SOURCES += drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.c else # LSI_CUT 10 or later BL2_SOURCES += drivers/renesas/rcar/qos/M3N/qos_init_m3n_v10.c endif endif ifeq (${RCAR_LSI},${RCAR_V3M}) BL2_SOURCES += drivers/renesas/rcar/qos/V3M/qos_init_v3m.c endif ifeq (${RCAR_LSI},${RCAR_E3}) ifeq (${LSI_CUT},10) BL2_SOURCES += drivers/renesas/rcar/qos/E3/qos_init_e3_v10.c else # LSI_CUT 10 or later BL2_SOURCES += drivers/renesas/rcar/qos/E3/qos_init_e3_v10.c endif endif ifeq (${RCAR_LSI},${RCAR_D3}) BL2_SOURCES += drivers/renesas/rcar/qos/E3/qos_init_d3.c endif endif BL2_SOURCES += drivers/renesas/rcar/qos/qos_init.c trusted-firmware-a-2.2/drivers/renesas/rcar/qos/qos_common.h000066400000000000000000000106311355360272700243040ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef QOS_COMMON_H #define QOS_COMMON_H #define RCAR_REF_DEFAULT 0U /* define used for get_refperiod. */ /* REFPERIOD_CYCLE need smaller than QOSWT_WTSET0_CYCLEs */ /* refere to plat/renesas/rcar/ddr/ddr_a/ddr_init_e3.h for E3. */ #if (RCAR_REF_INT == RCAR_REF_DEFAULT) /* REF default */ #define REFPERIOD_CYCLE /* unit:ns */ \ ((126 * BASE_SUB_SLOT_NUM * 1000U) / 400) #else /* REF option */ #define REFPERIOD_CYCLE /* unit:ns */ \ ((252 * BASE_SUB_SLOT_NUM * 1000U) / 400) #endif #if (RCAR_LSI == RCAR_E3) /* define used for E3 */ #if (RCAR_REF_INT == RCAR_REF_DEFAULT) /* REF 3.9usec */ #define SUB_SLOT_CYCLE_E3 0xAFU /* 175 */ #else /* REF 7.8usec */ #define SUB_SLOT_CYCLE_E3 0x15EU /* 350 */ #endif /* (RCAR_REF_INT == RCAR_REF_DEFAULT) */ #define OPERATING_FREQ_E3 266U /* MHz */ #define SL_INIT_SSLOTCLK_E3 (SUB_SLOT_CYCLE_E3 - 1U) #endif #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3N) /* define used for M3N */ #if (RCAR_REF_INT == RCAR_REF_DEFAULT) /* REF 1.95usec */ #define SUB_SLOT_CYCLE_M3N 0x7EU /* 126 */ #else /* REF 3.9usec */ #define SUB_SLOT_CYCLE_M3N 0xFCU /* 252 */ #endif /* (RCAR_REF_INT == RCAR_REF_DEFAULT) */ #define SL_INIT_SSLOTCLK_M3N (SUB_SLOT_CYCLE_M3N - 1U) #define QOSWT_WTSET0_CYCLE_M3N /* unit:ns */ \ ((SUB_SLOT_CYCLE_M3N * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ) #endif #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_H3) /* define used for H3 */ #if (RCAR_REF_INT == RCAR_REF_DEFAULT) /* REF 1.95usec */ #define SUB_SLOT_CYCLE_H3_20 0x7EU /* 126 */ #else /* REF 3.9usec */ #define SUB_SLOT_CYCLE_H3_20 0xFCU /* 252 */ #endif /* (RCAR_REF_INT == RCAR_REF_DEFAULT) */ #define SL_INIT_SSLOTCLK_H3_20 (SUB_SLOT_CYCLE_H3_20 - 1U) #define QOSWT_WTSET0_CYCLE_H3_20 /* unit:ns */ \ ((SUB_SLOT_CYCLE_H3_20 * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ) /* define used for H3 Cut 30 */ #define SUB_SLOT_CYCLE_H3_30 (SUB_SLOT_CYCLE_H3_20) /* same as H3 Cut 20 */ #define SL_INIT_SSLOTCLK_H3_30 (SUB_SLOT_CYCLE_H3_30 - 1U) #define QOSWT_WTSET0_CYCLE_H3_30 /* unit:ns */ \ ((SUB_SLOT_CYCLE_H3_30 * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ) #endif #if (RCAR_LSI == RCAR_H3N) /* define used for H3N */ #if (RCAR_REF_INT == RCAR_REF_DEFAULT) /* REF 1.95usec */ #define SUB_SLOT_CYCLE_H3N 0x7EU /* 126 */ #else /* REF 3.9usec */ #define SUB_SLOT_CYCLE_H3N 0xFCU /* 252 */ #endif /* (RCAR_REF_INT == RCAR_REF_DEFAULT) */ #define SL_INIT_SSLOTCLK_H3N (SUB_SLOT_CYCLE_H3N - 1U) #define QOSWT_WTSET0_CYCLE_H3N /* unit:ns */ \ ((SUB_SLOT_CYCLE_H3N * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ) #endif #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3) /* define used for M3 */ #if (RCAR_REF_INT == RCAR_REF_DEFAULT) /* REF 1.95usec */ #define SUB_SLOT_CYCLE_M3_11 0x7EU /* 126 */ #define SUB_SLOT_CYCLE_M3_30 0x7EU /* 126 */ #else /* REF 3.9usec */ #define SUB_SLOT_CYCLE_M3_11 0xFCU /* 252 */ #define SUB_SLOT_CYCLE_M3_30 0xFCU /* 252 */ #endif /* (RCAR_REF_INT == RCAR_REF_DEFAULT) */ #define SL_INIT_SSLOTCLK_M3_11 (SUB_SLOT_CYCLE_M3_11 - 1U) #define SL_INIT_SSLOTCLK_M3_30 (SUB_SLOT_CYCLE_M3_30 - 1U) #define QOSWT_WTSET0_CYCLE_M3_11 /* unit:ns */ \ ((SUB_SLOT_CYCLE_M3_11 * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ) #define QOSWT_WTSET0_CYCLE_M3_30 /* unit:ns */ \ ((SUB_SLOT_CYCLE_M3_30 * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ) #endif #define OPERATING_FREQ 400U /* MHz */ #define BASE_SUB_SLOT_NUM 0x6U #define SUB_SLOT_CYCLE 0x7EU /* 126 */ #define QOSWT_WTSET0_CYCLE /* unit:ns */ \ ((SUB_SLOT_CYCLE * BASE_SUB_SLOT_NUM * 1000U) / OPERATING_FREQ) #define SL_INIT_REFFSSLOT (0x3U << 24U) #define SL_INIT_SLOTSSLOT ((BASE_SUB_SLOT_NUM - 1U) << 16U) #define SL_INIT_SSLOTCLK (SUB_SLOT_CYCLE - 1U) static inline void io_write_32(uintptr_t addr, uint32_t value) { *(volatile uint32_t *)addr = value; } static inline uint32_t io_read_32(uintptr_t addr) { return *(volatile uint32_t *)addr; } static inline void io_write_64(uintptr_t addr, uint64_t value) { *(volatile uint64_t *)addr = value; } typedef struct { uintptr_t addr; uint64_t value; } mstat_slot_t; struct rcar_gen3_dbsc_qos_settings { uint32_t reg; uint32_t val; }; extern uint32_t qos_init_ddr_ch; extern uint8_t qos_init_ddr_phyvalid; void rcar_qos_dbsc_setting(struct rcar_gen3_dbsc_qos_settings *qos, unsigned int qos_size, bool dbsc_wren); #endif /* QOS_COMMON_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/qos/qos_init.c000066400000000000000000000206141355360272700237540ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "qos_init.h" #include "qos_common.h" #include "qos_reg.h" #include "rcar_def.h" #if RCAR_LSI == RCAR_AUTO #include "H3/qos_init_h3_v10.h" #include "H3/qos_init_h3_v11.h" #include "H3/qos_init_h3_v20.h" #include "H3/qos_init_h3_v30.h" #include "M3/qos_init_m3_v10.h" #include "M3/qos_init_m3_v11.h" #include "M3/qos_init_m3_v30.h" #include "M3N/qos_init_m3n_v10.h" #include "V3M/qos_init_v3m.h" #endif #if RCAR_LSI == RCAR_H3 /* H3 */ #include "H3/qos_init_h3_v10.h" #include "H3/qos_init_h3_v11.h" #include "H3/qos_init_h3_v20.h" #include "H3/qos_init_h3_v30.h" #endif #if RCAR_LSI == RCAR_H3N /* H3 */ #include "H3/qos_init_h3n_v30.h" #endif #if RCAR_LSI == RCAR_M3 /* M3 */ #include "M3/qos_init_m3_v10.h" #include "M3/qos_init_m3_v11.h" #include "M3/qos_init_m3_v30.h" #endif #if RCAR_LSI == RCAR_M3N /* M3N */ #include "M3N/qos_init_m3n_v10.h" #endif #if RCAR_LSI == RCAR_V3M /* V3M */ #include "V3M/qos_init_v3m.h" #endif #if RCAR_LSI == RCAR_E3 /* E3 */ #include "E3/qos_init_e3_v10.h" #endif #if RCAR_LSI == RCAR_D3 /* D3 */ #include "D3/qos_init_d3.h" #endif #if (RCAR_LSI != RCAR_E3) && (RCAR_LSI != RCAR_D3) && (RCAR_LSI != RCAR_V3M) #define DRAM_CH_CNT 0x04 uint32_t qos_init_ddr_ch; uint8_t qos_init_ddr_phyvalid; #endif #define PRR_PRODUCT_ERR(reg) \ do { \ ERROR("LSI Product ID(PRR=0x%x) QoS " \ "initialize not supported.\n", reg); \ panic(); \ } while (0) #define PRR_CUT_ERR(reg) \ do { \ ERROR("LSI Cut ID(PRR=0x%x) QoS " \ "initialize not supported.\n", reg); \ panic(); \ } while (0) void rcar_qos_init(void) { uint32_t reg; #if (RCAR_LSI != RCAR_E3) && (RCAR_LSI != RCAR_D3) && (RCAR_LSI != RCAR_V3M) uint32_t i; qos_init_ddr_ch = 0; qos_init_ddr_phyvalid = get_boardcnf_phyvalid(); for (i = 0; i < DRAM_CH_CNT; i++) { if ((qos_init_ddr_phyvalid & (1 << i))) { qos_init_ddr_ch++; } } #endif reg = mmio_read_32(PRR); #if (RCAR_LSI == RCAR_AUTO) || RCAR_LSI_CUT_COMPAT switch (reg & PRR_PRODUCT_MASK) { case PRR_PRODUCT_H3: #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_H3) switch (reg & PRR_CUT_MASK) { case PRR_PRODUCT_10: qos_init_h3_v10(); break; case PRR_PRODUCT_11: qos_init_h3_v11(); break; case PRR_PRODUCT_20: qos_init_h3_v20(); break; case PRR_PRODUCT_30: default: qos_init_h3_v30(); break; } #elif (RCAR_LSI == RCAR_H3N) switch (reg & PRR_CUT_MASK) { case PRR_PRODUCT_30: default: qos_init_h3n_v30(); break; } #else PRR_PRODUCT_ERR(reg); #endif break; case PRR_PRODUCT_M3: #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3) switch (reg & PRR_CUT_MASK) { case PRR_PRODUCT_10: qos_init_m3_v10(); break; case PRR_PRODUCT_21: /* M3 Cut 13 */ qos_init_m3_v11(); break; case PRR_PRODUCT_30: /* M3 Cut 30 */ default: qos_init_m3_v30(); break; } #else PRR_PRODUCT_ERR(reg); #endif break; case PRR_PRODUCT_M3N: #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3N) switch (reg & PRR_CUT_MASK) { case PRR_PRODUCT_10: default: qos_init_m3n_v10(); break; } #else PRR_PRODUCT_ERR(reg); #endif break; case PRR_PRODUCT_V3M: #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_V3M) switch (reg & PRR_CUT_MASK) { case PRR_PRODUCT_10: case PRR_PRODUCT_20: default: qos_init_v3m(); break; } #else PRR_PRODUCT_ERR(reg); #endif break; case PRR_PRODUCT_E3: #if (RCAR_LSI == RCAR_E3) switch (reg & PRR_CUT_MASK) { case PRR_PRODUCT_10: default: qos_init_e3_v10(); break; } #else PRR_PRODUCT_ERR(reg); #endif break; case PRR_PRODUCT_D3: #if (RCAR_LSI == RCAR_D3) switch (reg & PRR_CUT_MASK) { case PRR_PRODUCT_10: default: qos_init_d3(); break; } #else PRR_PRODUCT_ERR(reg); #endif break; default: PRR_PRODUCT_ERR(reg); break; } #else #if RCAR_LSI == RCAR_H3 /* H3 */ #if RCAR_LSI_CUT == RCAR_CUT_10 /* H3 Cut 10 */ if ((PRR_PRODUCT_H3 | PRR_PRODUCT_10) != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) { PRR_PRODUCT_ERR(reg); } qos_init_h3_v10(); #elif RCAR_LSI_CUT == RCAR_CUT_11 /* H3 Cut 11 */ if ((PRR_PRODUCT_H3 | PRR_PRODUCT_11) != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) { PRR_PRODUCT_ERR(reg); } qos_init_h3_v11(); #elif RCAR_LSI_CUT == RCAR_CUT_20 /* H3 Cut 20 */ if ((PRR_PRODUCT_H3 | PRR_PRODUCT_20) != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) { PRR_PRODUCT_ERR(reg); } qos_init_h3_v20(); #else /* H3 Cut 30 or later */ if ((PRR_PRODUCT_H3) != (reg & (PRR_PRODUCT_MASK))) { PRR_PRODUCT_ERR(reg); } qos_init_h3_v30(); #endif #elif RCAR_LSI == RCAR_H3N /* H3 */ /* H3N Cut 30 or later */ if ((PRR_PRODUCT_H3) != (reg & (PRR_PRODUCT_MASK))) { PRR_PRODUCT_ERR(reg); } qos_init_h3n_v30(); #elif RCAR_LSI == RCAR_M3 /* M3 */ #if RCAR_LSI_CUT == RCAR_CUT_10 /* M3 Cut 10 */ if ((PRR_PRODUCT_M3 | PRR_PRODUCT_10) != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) { PRR_PRODUCT_ERR(reg); } qos_init_m3_v10(); #elif RCAR_LSI_CUT == RCAR_CUT_11 /* M3 Cut 11 */ if ((PRR_PRODUCT_M3 | PRR_PRODUCT_20) != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) { PRR_PRODUCT_ERR(reg); } qos_init_m3_v11(); #elif RCAR_LSI_CUT == RCAR_CUT_13 /* M3 Cut 13 */ if ((PRR_PRODUCT_M3 | PRR_PRODUCT_21) != (reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK))) { PRR_PRODUCT_ERR(reg); } qos_init_m3_v11(); #else /* M3 Cut 30 or later */ if ((PRR_PRODUCT_M3) != (reg & (PRR_PRODUCT_MASK))) { PRR_PRODUCT_ERR(reg); } qos_init_m3_v30(); #endif #elif RCAR_LSI == RCAR_M3N /* M3N */ /* M3N Cut 10 or later */ if ((PRR_PRODUCT_M3N) != (reg & (PRR_PRODUCT_MASK))) { PRR_PRODUCT_ERR(reg); } qos_init_m3n_v10(); #elif RCAR_LSI == RCAR_V3M /* V3M */ /* V3M Cut 10 or later */ if ((PRR_PRODUCT_V3M) != (reg & (PRR_PRODUCT_MASK))) { PRR_PRODUCT_ERR(reg); } qos_init_v3m(); #elif RCAR_LSI == RCAR_D3 /* D3 */ /* D3 Cut 10 or later */ if ((PRR_PRODUCT_D3) != (reg & (PRR_PRODUCT_MASK))) { PRR_PRODUCT_ERR(reg); } qos_init_d3(); #elif RCAR_LSI == RCAR_E3 /* E3 */ /* E3 Cut 10 or later */ if ((PRR_PRODUCT_E3) != (reg & (PRR_PRODUCT_MASK))) { PRR_PRODUCT_ERR(reg); } qos_init_e3_v10(); #else #error "Don't have QoS initialize routine(Unknown chip)." #endif #endif } #if (RCAR_LSI != RCAR_E3) && (RCAR_LSI != RCAR_D3) && (RCAR_LSI != RCAR_V3M) uint32_t get_refperiod(void) { uint32_t refperiod = QOSWT_WTSET0_CYCLE; #if (RCAR_LSI == RCAR_AUTO) || RCAR_LSI_CUT_COMPAT uint32_t reg; reg = mmio_read_32(PRR); switch (reg & PRR_PRODUCT_MASK) { #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_H3) case PRR_PRODUCT_H3: switch (reg & PRR_CUT_MASK) { case PRR_PRODUCT_10: case PRR_PRODUCT_11: break; case PRR_PRODUCT_20: case PRR_PRODUCT_30: default: refperiod = REFPERIOD_CYCLE; break; } break; #elif (RCAR_LSI == RCAR_H3N) case PRR_PRODUCT_H3: switch (reg & PRR_CUT_MASK) { case PRR_PRODUCT_30: default: refperiod = REFPERIOD_CYCLE; break; } break; #endif #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3) case PRR_PRODUCT_M3: switch (reg & PRR_CUT_MASK) { case PRR_PRODUCT_10: break; case PRR_PRODUCT_20: /* M3 Cut 11 */ case PRR_PRODUCT_21: /* M3 Cut 13 */ case PRR_PRODUCT_30: /* M3 Cut 30 */ default: refperiod = REFPERIOD_CYCLE; break; } break; #endif #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3N) case PRR_PRODUCT_M3N: refperiod = REFPERIOD_CYCLE; break; #endif default: break; } #elif RCAR_LSI == RCAR_H3 #if RCAR_LSI_CUT == RCAR_CUT_10 /* H3 Cut 10 */ #elif RCAR_LSI_CUT == RCAR_CUT_11 /* H3 Cut 11 */ #else /* H3 Cut 20 */ /* H3 Cut 30 or later */ refperiod = REFPERIOD_CYCLE; #endif #elif RCAR_LSI == RCAR_H3N /* H3N Cut 30 or later */ refperiod = REFPERIOD_CYCLE; #elif RCAR_LSI == RCAR_M3 #if RCAR_LSI_CUT == RCAR_CUT_10 /* M3 Cut 10 */ #else /* M3 Cut 11 */ /* M3 Cut 13 */ /* M3 Cut 30 or later */ refperiod = REFPERIOD_CYCLE; #endif #elif RCAR_LSI == RCAR_M3N /* for M3N */ refperiod = REFPERIOD_CYCLE; #endif return refperiod; } #endif void rcar_qos_dbsc_setting(struct rcar_gen3_dbsc_qos_settings *qos, unsigned int qos_size, bool dbsc_wren) { int i; /* Register write enable */ if (dbsc_wren) io_write_32(DBSC_DBSYSCNT0, 0x00001234U); for (i = 0; i < qos_size; i++) io_write_32(qos[i].reg, qos[i].val); /* Register write protect */ if (dbsc_wren) io_write_32(DBSC_DBSYSCNT0, 0x00000000U); } trusted-firmware-a-2.2/drivers/renesas/rcar/qos/qos_init.h000066400000000000000000000004231355360272700237550ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef QOS_INIT_H #define QOS_INIT_H extern void rcar_qos_init(void); extern uint8_t get_boardcnf_phyvalid(void); #endif /* QOS_INIT_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/qos/qos_reg.h000066400000000000000000000116321355360272700235730ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef QOS_REG_H #define QOS_REG_H #define RCAR_QOS_NONE 3U #define RCAR_QOS_TYPE_DEFAULT 0U #define RCAR_DRAM_SPLIT_LINEAR 0U #define RCAR_DRAM_SPLIT_4CH 1U #define RCAR_DRAM_SPLIT_2CH 2U #define RCAR_DRAM_SPLIT_AUTO 3U #define RST_BASE (0xE6160000U) #define RST_MODEMR (RST_BASE + 0x0060U) #define DBSC_BASE 0xE6790000U #define DBSC_DBSYSCNT0 (DBSC_BASE + 0x0100U) #define DBSC_AXARB (DBSC_BASE + 0x0800U) #define DBSC_DBCAM0CNF1 (DBSC_BASE + 0x0904U) #define DBSC_DBCAM0CNF2 (DBSC_BASE + 0x0908U) #define DBSC_DBCAM0CNF3 (DBSC_BASE + 0x090CU) #define DBSC_DBSCHCNT0 (DBSC_BASE + 0x1000U) #define DBSC_DBSCHCNT1 (DBSC_BASE + 0x1004U) #define DBSC_DBSCHSZ0 (DBSC_BASE + 0x1010U) #define DBSC_DBSCHRW0 (DBSC_BASE + 0x1020U) #define DBSC_DBSCHRW1 (DBSC_BASE + 0x1024U) #define DBSC_DBSCHQOS00 (DBSC_BASE + 0x1030U) #define DBSC_DBSCHQOS01 (DBSC_BASE + 0x1034U) #define DBSC_DBSCHQOS02 (DBSC_BASE + 0x1038U) #define DBSC_DBSCHQOS03 (DBSC_BASE + 0x103CU) #define DBSC_DBSCHQOS40 (DBSC_BASE + 0x1070U) #define DBSC_DBSCHQOS41 (DBSC_BASE + 0x1074U) #define DBSC_DBSCHQOS42 (DBSC_BASE + 0x1078U) #define DBSC_DBSCHQOS43 (DBSC_BASE + 0x107CU) #define DBSC_DBSCHQOS90 (DBSC_BASE + 0x10C0U) #define DBSC_DBSCHQOS91 (DBSC_BASE + 0x10C4U) #define DBSC_DBSCHQOS92 (DBSC_BASE + 0x10C8U) #define DBSC_DBSCHQOS93 (DBSC_BASE + 0x10CCU) #define DBSC_DBSCHQOS120 (DBSC_BASE + 0x10F0U) #define DBSC_DBSCHQOS121 (DBSC_BASE + 0x10F4U) #define DBSC_DBSCHQOS122 (DBSC_BASE + 0x10F8U) #define DBSC_DBSCHQOS123 (DBSC_BASE + 0x10FCU) #define DBSC_DBSCHQOS130 (DBSC_BASE + 0x1100U) #define DBSC_DBSCHQOS131 (DBSC_BASE + 0x1104U) #define DBSC_DBSCHQOS132 (DBSC_BASE + 0x1108U) #define DBSC_DBSCHQOS133 (DBSC_BASE + 0x110CU) #define DBSC_DBSCHQOS140 (DBSC_BASE + 0x1110U) #define DBSC_DBSCHQOS141 (DBSC_BASE + 0x1114U) #define DBSC_DBSCHQOS142 (DBSC_BASE + 0x1118U) #define DBSC_DBSCHQOS143 (DBSC_BASE + 0x111CU) #define DBSC_DBSCHQOS150 (DBSC_BASE + 0x1120U) #define DBSC_DBSCHQOS151 (DBSC_BASE + 0x1124U) #define DBSC_DBSCHQOS152 (DBSC_BASE + 0x1128U) #define DBSC_DBSCHQOS153 (DBSC_BASE + 0x112CU) #define DBSC_SCFCTST0 (DBSC_BASE + 0x1700U) #define DBSC_SCFCTST1 (DBSC_BASE + 0x1708U) #define DBSC_SCFCTST2 (DBSC_BASE + 0x170CU) #define AXI_BASE 0xE6784000U #define AXI_ADSPLCR0 (AXI_BASE + 0x0008U) #define AXI_ADSPLCR1 (AXI_BASE + 0x000CU) #define AXI_ADSPLCR2 (AXI_BASE + 0x0010U) #define AXI_ADSPLCR3 (AXI_BASE + 0x0014U) #define AXI_MMCR (AXI_BASE + 0x0300U) #define ADSPLCR0_ADRMODE_DEFAULT ((uint32_t)0U << 31U) #define ADSPLCR0_ADRMODE_GEN2 ((uint32_t)1U << 31U) #define ADSPLCR0_SPLITSEL(x) ((uint32_t)(x) << 16U) #define ADSPLCR0_AREA(x) ((uint32_t)(x) << 8U) #define ADSPLCR0_SWP 0x0CU #define AXI_TR3CR 0xE67D100CU #define AXI_TR4CR 0xE67D1014U #define QOS_BASE0 0xE67E0000U #define QOSBW_FIX_QOS_BANK0 (QOS_BASE0 + 0x0000U) #define QOSBW_FIX_QOS_BANK1 (QOS_BASE0 + 0x1000U) #define QOSBW_BE_QOS_BANK0 (QOS_BASE0 + 0x2000U) #define QOSBW_BE_QOS_BANK1 (QOS_BASE0 + 0x3000U) #define QOSCTRL_SL_INIT (QOS_BASE0 + 0x8000U) #define QOSCTRL_REF_ARS (QOS_BASE0 + 0x8004U) #define QOSCTRL_STATQC (QOS_BASE0 + 0x8008U) #define QOS_BASE1 0xE67F0000U #define QOSCTRL_RAS (QOS_BASE1 + 0x0000U) #define QOSCTRL_FIXTH (QOS_BASE1 + 0x0004U) #define QOSCTRL_RAEN (QOS_BASE1 + 0x0018U) #define QOSCTRL_REGGD (QOS_BASE1 + 0x0020U) #define QOSCTRL_DANN (QOS_BASE1 + 0x0030U) #define QOSCTRL_DANT (QOS_BASE1 + 0x0038U) #define QOSCTRL_EC (QOS_BASE1 + 0x003CU) #define QOSCTRL_EMS (QOS_BASE1 + 0x0040U) #define QOSCTRL_FSS (QOS_BASE1 + 0x0048U) #define QOSCTRL_INSFC (QOS_BASE1 + 0x0050U) #define QOSCTRL_BERR (QOS_BASE1 + 0x0054U) #define QOSCTRL_EARLYR (QOS_BASE1 + 0x0060U) #define QOSCTRL_RACNT0 (QOS_BASE1 + 0x0080U) #define QOSCTRL_STATGEN0 (QOS_BASE1 + 0x0088U) #define GPU_ACT_GRD 0xFD820808U #define GPU_ACT0 0xFD820800U #define GPU_ACT1 0xFD821800U #define GPU_ACT2 0xFD822800U #define GPU_ACT3 0xFD823800U #define GPU_ACT4 0xFD824800U #define GPU_ACT5 0xFD825800U #define GPU_ACT6 0xFD826800U #define GPU_ACT7 0xFD827800U #define RT_ACT0 0xFFC50800U #define RT_ACT1 0xFFC51800U #define CPU_ACT0 0xF1300800U #define CPU_ACT1 0xF1340800U #define CPU_ACT2 0xF1380800U #define CPU_ACT3 0xF13C0800U #define RCAR_REWT_TRAINING_DISABLE 0U #define RCAR_REWT_TRAINING_ENABLE 1U #define QOSWT_FIX_WTQOS_BANK0 (QOSBW_FIX_QOS_BANK0 + 0x0800U) #define QOSWT_FIX_WTQOS_BANK1 (QOSBW_FIX_QOS_BANK1 + 0x0800U) #define QOSWT_BE_WTQOS_BANK0 (QOSBW_BE_QOS_BANK0 + 0x0800U) #define QOSWT_BE_WTQOS_BANK1 (QOSBW_BE_QOS_BANK1 + 0x0800U) #define QOSWT_WTEN (QOS_BASE0 + 0x8030U) #define QOSWT_WTREF (QOS_BASE0 + 0x8034U) #define QOSWT_WTSET0 (QOS_BASE0 + 0x8038U) #define QOSWT_WTSET1 (QOS_BASE0 + 0x803CU) #endif /* QOS_REG_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/rom/000077500000000000000000000000001355360272700217535ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/rom/rom_api.c000066400000000000000000000051751355360272700235550ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "rcar_def.h" #include "rom_api.h" typedef uint32_t(*rom_secure_boot_api_f) (uint32_t *key, uint32_t *cert, rom_read_flash_f pFuncReadFlash); typedef uint32_t(*rom_get_lcs_api_f) (uint32_t *lcs); #define OLD_API_TABLE1 (0U) /* H3 Ver.1.0/Ver.1.1 */ #define OLD_API_TABLE2 (1U) /* H3 Ver.2.0 */ #define OLD_API_TABLE3 (2U) /* M3 Ver.1.0 */ #define NEW_API_TABLE (3U) /* H3 Ver.3.0, M3 Ver.1.1 or later, M3N, E3, D3, V3M WS2.0 */ #define NEW_API_TABLE2 (4U) /* V3M WS1.0 */ #define API_TABLE_MAX (5U) /* table max */ /* Later than H3 Ver.2.0 */ static uint32_t get_table_index(void) { uint32_t product; uint32_t cut_ver; uint32_t index; product = mmio_read_32(RCAR_PRR) & PRR_PRODUCT_MASK; cut_ver = mmio_read_32(RCAR_PRR) & PRR_CUT_MASK; switch (product) { case PRR_PRODUCT_H3: if (cut_ver == PRR_PRODUCT_10) index = OLD_API_TABLE1; else if (cut_ver == PRR_PRODUCT_11) index = OLD_API_TABLE1; else if (cut_ver == PRR_PRODUCT_20) index = OLD_API_TABLE2; else /* Later than H3 Ver.2.0 */ index = NEW_API_TABLE; break; case PRR_PRODUCT_M3: if (cut_ver == PRR_PRODUCT_10) index = OLD_API_TABLE3; else /* M3 Ver.1.1 or later */ index = NEW_API_TABLE; break; case PRR_PRODUCT_V3M: if (cut_ver == PRR_PRODUCT_10) /* V3M WS1.0 */ index = NEW_API_TABLE2; else /* V3M WS2.0 or later */ index = NEW_API_TABLE; break; default: index = NEW_API_TABLE; break; } return index; } uint32_t rcar_rom_secure_boot_api(uint32_t *key, uint32_t *cert, rom_read_flash_f read_flash) { static const uintptr_t rom_api_table[API_TABLE_MAX] = { 0xEB10DD64U, /* H3 Ver.1.0/Ver.1.1 */ 0xEB116ED4U, /* H3 Ver.2.0 */ 0xEB1102FCU, /* M3 Ver.1.0 */ 0xEB100180U, /* H3 Ver.3.0, M3 Ver.1.1 or later, M3N, E3, D3, V3M WS2.0 */ 0xEB110128U, /* V3M WS1.0 */ }; rom_secure_boot_api_f secure_boot; uint32_t index; index = get_table_index(); secure_boot = (rom_secure_boot_api_f) rom_api_table[index]; return secure_boot(key, cert, read_flash); } uint32_t rcar_rom_get_lcs(uint32_t *lcs) { static const uintptr_t rom_get_lcs_table[API_TABLE_MAX] = { 0xEB10DFE0U, /* H3 Ver.1.0/Ver.1.1 */ 0xEB117150U, /* H3 Ver.2.0 */ 0xEB110578U, /* M3 Ver.1.0 */ 0xEB10018CU, /* H3 Ver.3.0, M3 Ver.1.1 or later, M3N, E3, D3, V3M WS2.0 */ 0xEB1103A4U, /* V3M WS1.0 */ }; rom_get_lcs_api_f get_lcs; uint32_t index; index = get_table_index(); get_lcs = (rom_get_lcs_api_f) rom_get_lcs_table[index]; return get_lcs(lcs); } trusted-firmware-a-2.2/drivers/renesas/rcar/rom/rom_api.h000066400000000000000000000016431355360272700235560ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ROM_API_H #define ROM_API_H #include #define SBROM_OK (0x00000000U) #define SBROM_ILLEGAL_INPUT_PARAM_ERR (0x0B000001U) #define SBROM_ILLEGAL_OEM_HASH_VALUE_ERR (0x0B000008U) #define SBROM_ILLEGAL_LCS_FOR_OPERATION_ERR (0x0B000010U) #define SBROM_HASH_NOT_PROGRAMMED_ERR (0x0B000100U) #define SBROM_PUB_KEY_HASH_VALIDATION_FAILURE (0xF1000006U) #define SBROM_RSA_SIG_VERIFICATION_FAILED (0xF1000007U) #define LCS_CM (0x0U) #define LCS_DM (0x1U) #define LCS_SD (0x3U) #define LCS_SE (0x5U) #define LCS_FA (0x7U) typedef uint32_t(*rom_read_flash_f) (uint64_t src, uint8_t *dst, uint32_t len); uint32_t rcar_rom_secure_boot_api(uint32_t *key, uint32_t *cert, rom_read_flash_f f); uint32_t rcar_rom_get_lcs(uint32_t *lcs); #endif /* ROM_API_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/rpc/000077500000000000000000000000001355360272700217425ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/rpc/rpc_driver.c000066400000000000000000000024171355360272700242510ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "cpg_registers.h" #include "rcar_def.h" #include "rcar_private.h" #include "rpc_registers.h" #define MSTPSR9_RPC_BIT (0x00020000U) #define RPC_CMNCR_MD_BIT (0x80000000U) #define RPC_PHYCNT_CAL BIT(31) #define RPC_PHYCNT_STRTIM_M3V1 (0x6 << 15UL) #define RPC_PHYCNT_STRTIM (0x7 << 15UL) static void rpc_enable(void) { /* Enable clock supply to RPC. */ mstpcr_write(CPG_SMSTPCR9, CPG_MSTPSR9, MSTPSR9_RPC_BIT); } static void rpc_setup(void) { uint32_t product, cut, reg, phy_strtim; if (mmio_read_32(RPC_CMNCR) & RPC_CMNCR_MD_BIT) mmio_clrbits_32(RPC_CMNCR, RPC_CMNCR_MD_BIT); product = mmio_read_32(RCAR_PRR) & PRR_PRODUCT_MASK; cut = mmio_read_32(RCAR_PRR) & PRR_CUT_MASK; if ((product == PRR_PRODUCT_M3) && (cut < PRR_PRODUCT_30)) phy_strtim = RPC_PHYCNT_STRTIM_M3V1; else phy_strtim = RPC_PHYCNT_STRTIM; reg = mmio_read_32(RPC_PHYCNT); reg &= ~RPC_PHYCNT_STRTIM; reg |= phy_strtim; mmio_write_32(RPC_PHYCNT, reg); reg |= RPC_PHYCNT_CAL; mmio_write_32(RPC_PHYCNT, reg); } void rcar_rpc_init(void) { rpc_enable(); rpc_setup(); } trusted-firmware-a-2.2/drivers/renesas/rcar/rpc/rpc_registers.h000066400000000000000000000013621355360272700247700ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RPC_REGISTERS_H #define RPC_REGISTERS_H #define RPC_BASE (0xEE200000U) #define RPC_CMNCR (RPC_BASE + 0x0000U) #define RPC_SSLDR (RPC_BASE + 0x0004U) #define RPC_DRCR (RPC_BASE + 0x000CU) #define RPC_DRCMR (RPC_BASE + 0x0010U) #define RPC_DRENR (RPC_BASE + 0x001CU) #define RPC_SMCR (RPC_BASE + 0x0020U) #define RPC_SMCMR (RPC_BASE + 0x0024U) #define RPC_SMENR (RPC_BASE + 0x0030U) #define RPC_CMNSR (RPC_BASE + 0x0048U) #define RPC_DRDMCR (RPC_BASE + 0x0058U) #define RPC_DRDRENR (RPC_BASE + 0x005CU) #define RPC_PHYCNT (RPC_BASE + 0x007CU) #define RPC_PHYINT (RPC_BASE + 0x0088U) #endif /* RPC_REGISTERS_H */ trusted-firmware-a-2.2/drivers/renesas/rcar/scif/000077500000000000000000000000001355360272700221025ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/scif/scif.S000066400000000000000000000206021355360272700231520ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #define SCIF_INTERNAL_CLK 0 #define SCIF_EXTARNAL_CLK 1 #define SCIF_CLK SCIF_INTERNAL_CLK /* product register */ #define PRR (0xFFF00044) #define PRR_PRODUCT_MASK (0x00007F00) #define PRR_CUT_MASK (0x000000FF) #define PRR_PRODUCT_H3_VER_10 (0x00004F00) #define PRR_PRODUCT_E3 (0x00005700) #define PRR_PRODUCT_D3 (0x00005800) /* module stop */ #define CPG_BASE (0xE6150000) #define CPG_SMSTPCR2 (0x0138) #define CPG_SMSTPCR3 (0x013C) #define CPG_MSTPSR2 (0x0040) #define CPG_MSTPSR3 (0x0048) #define MSTP207 (1 << 7) #define MSTP310 (1 << 10) #define CPG_CPGWPR (0x0900) /* scif */ #define SCIF0_BASE (0xE6E60000) #define SCIF2_BASE (0xE6E88000) #define SCIF_SCSMR (0x00) #define SCIF_SCBRR (0x04) #define SCIF_SCSCR (0x08) #define SCIF_SCFTDR (0x0C) #define SCIF_SCFSR (0x10) #define SCIF_SCFRDR (0x14) #define SCIF_SCFCR (0x18) #define SCIF_SCFDR (0x1C) #define SCIF_SCSPTR (0x20) #define SCIF_SCLSR (0x24) #define SCIF_DL (0x30) #define SCIF_CKS (0x34) #if RCAR_LSI == RCAR_V3M #define SCIF_BASE SCIF0_BASE #define CPG_SMSTPCR CPG_SMSTPCR2 #define CPG_MSTPSR CPG_MSTPSR2 #define MSTP MSTP207 #else #define SCIF_BASE SCIF2_BASE #define CPG_SMSTPCR CPG_SMSTPCR3 #define CPG_MSTPSR CPG_MSTPSR3 #define MSTP MSTP310 #endif /* mode pin */ #define RST_MODEMR (0xE6160060) #define MODEMR_MD12 (0x00001000) #define SCSMR_CA_MASK (1 << 7) #define SCSMR_CA_ASYNC (0x0000) #define SCSMR_CHR_MASK (1 << 6) #define SCSMR_CHR_8 (0x0000) #define SCSMR_PE_MASK (1 << 5) #define SCSMR_PE_DIS (0x0000) #define SCSMR_STOP_MASK (1 << 3) #define SCSMR_STOP_1 (0x0000) #define SCSMR_CKS_MASK (3 << 0) #define SCSMR_CKS_DIV1 (0x0000) #define SCSMR_INIT_DATA (SCSMR_CA_ASYNC + \ SCSMR_CHR_8 + \ SCSMR_PE_DIS + \ SCSMR_STOP_1 + \ SCSMR_CKS_DIV1) #define SCBRR_115200BPS (17) #define SCBRR_115200BPSON (16) #define SCBRR_115200BPS_E3_SSCG (15) #define SCBRR_230400BPS (8) #define SCSCR_TE_MASK (1 << 5) #define SCSCR_TE_DIS (0x0000) #define SCSCR_TE_EN (0x0020) #define SCSCR_RE_MASK (1 << 4) #define SCSCR_RE_DIS (0x0000) #define SCSCR_RE_EN (0x0010) #define SCSCR_CKE_MASK (3 << 0) #define SCSCR_CKE_INT (0x0000) #define SCSCR_CKE_BRG (0x0002) #if SCIF_CLK == SCIF_EXTARNAL_CLK #define SCSCR_CKE_INT_CLK (SCSCR_CKE_BRG) #else #define SCFSR_TEND_MASK (1 << 6) #define SCFSR_TEND_TRANS_END (0x0040) #define SCSCR_CKE_INT_CLK (SCSCR_CKE_INT) #endif #define SCFSR_INIT_DATA (0x0000) #define SCFCR_TTRG_MASK (3 << 4) #define SCFCR_TTRG_8 (0x0000) #define SCFCR_TTRG_0 (0x0030) #define SCFCR_TFRST_MASK (1 << 2) #define SCFCR_TFRST_DIS (0x0000) #define SCFCR_TFRST_EN (0x0004) #define SCFCR_RFRS_MASK (1 << 1) #define SCFCR_RFRS_DIS (0x0000) #define SCFCR_RFRS_EN (0x0002) #define SCFCR_INIT_DATA (SCFCR_TTRG_8) #define SCFDR_T_MASK (0x1f << 8) #define DL_INIT_DATA (8) #define CKS_CKS_DIV_MASK (1 << 15) #define CKS_CKS_DIV_CLK (0x0000) #define CKS_XIN_MASK (1 << 14) #define CKS_XIN_SCIF_CLK (0x0000) #define CKS_INIT_DATA (CKS_CKS_DIV_CLK + CKS_XIN_SCIF_CLK) .globl console_rcar_register .globl console_rcar_init .globl console_rcar_putc .globl console_rcar_flush /* ----------------------------------------------- * int console_rcar_register( * uintptr_t base, uint32_t clk, uint32_t baud, * console_rcar_t *console) * Function to initialize and register a new rcar * console. Storage passed in for the console struct * *must* be persistent (i.e. not from the stack). * In: x0 - UART register base address * w1 - UART clock in Hz * w2 - Baud rate * x3 - pointer to empty console_rcar_t struct * Out: return 1 on success, 0 on error * Clobber list : x0, x1, x2, x6, x7, x14 * ----------------------------------------------- */ func console_rcar_register mov x7, x30 mov x6, x3 cbz x6, register_fail str x0, [x6, #CONSOLE_T_RCAR_BASE] bl console_rcar_init mov x0, x6 mov x30, x7 finish_console_register rcar, putc=1, getc=0, flush=1 register_fail: ret x7 endfunc console_rcar_register /* ----------------------------------------------- * int console_rcar_init(unsigned long base_addr, * unsigned int uart_clk, unsigned int baud_rate) * Function to initialize the console without a * C Runtime to print debug information. This * function will be accessed by console_rcar_register * and crash reporting. * In: x0 - console base address * w1 - Uart clock in Hz * w2 - Baud rate * Out: return 1 on success * Clobber list : x1, x2 * ----------------------------------------------- */ func console_rcar_init ldr x0, =CPG_BASE ldr w1, [x0, #CPG_SMSTPCR] and w1, w1, #~MSTP mvn w2, w1 str w2, [x0, #CPG_CPGWPR] str w1, [x0, #CPG_SMSTPCR] 5: ldr w1, [x0, #CPG_MSTPSR] and w1, w1, #MSTP cbnz w1, 5b ldr x0, =SCIF_BASE /* Clear bits TE and RE in SCSCR to 0 */ mov w1, #(SCSCR_TE_DIS + SCSCR_RE_DIS) strh w1, [x0, #SCIF_SCSCR] /* Set bits TFRST and RFRST in SCFCR to 1 */ ldrh w1, [x0, #SCIF_SCFCR] orr w1, w1, #(SCFCR_TFRST_EN + SCFCR_RFRS_EN) strh w1, [x0, #SCIF_SCFCR] /* Read flags of ER, DR, BRK, and RDF in SCFSR and those of TO and ORER in SCLSR, then clear them to 0 */ mov w1, #SCFSR_INIT_DATA strh w1, [x0, #SCIF_SCFSR] mov w1, #0 strh w1, [x0, #SCIF_SCLSR] /* Set bits CKE[1:0] in SCSCR */ ldrh w1, [x0, #SCIF_SCSCR] and w1, w1, #~SCSCR_CKE_MASK mov w2, #SCSCR_CKE_INT_CLK orr w1, w1, w2 strh w1, [x0, #SCIF_SCSCR] /* Set data transfer format in SCSMR */ mov w1, #SCSMR_INIT_DATA strh w1, [x0, #SCIF_SCSMR] /* Set value in SCBRR */ #if SCIF_CLK == SCIF_INTERNAL_CLK ldr x1, =PRR ldr w1, [x1] and w1, w1, #(PRR_PRODUCT_MASK | PRR_CUT_MASK) mov w2, #PRR_PRODUCT_H3_VER_10 cmp w1, w2 beq 3f and w1, w1, #PRR_PRODUCT_MASK mov w2, #PRR_PRODUCT_D3 cmp w1, w2 beq 4f and w1, w1, #PRR_PRODUCT_MASK mov w2, #PRR_PRODUCT_E3 cmp w1, w2 bne 5f ldr x1, =RST_MODEMR ldr w1, [x1] and w1, w1, #MODEMR_MD12 mov w2, #MODEMR_MD12 cmp w1, w2 bne 5f mov w1, #SCBRR_115200BPS_E3_SSCG b 2f 5: mov w1, #SCBRR_115200BPS b 2f 4: mov w1, #SCBRR_115200BPSON b 2f 3: mov w1, #SCBRR_230400BPS 2: strb w1, [x0, SCIF_SCBRR] #else mov w1, #DL_INIT_DATA strh w1, [x0, #SCIF_DL] mov w1, #CKS_INIT_DATA strh w1, [x0, #SCIF_CKS] #endif /* 1-bit interval elapsed */ mov w1, #100 1: subs w1, w1, #1 cbnz w1, 1b /* * Set bits RTRG[1:0], TTRG[1:0], and MCE in SCFCR * Clear bits FRST and RFRST to 0 */ mov w1, #SCFCR_INIT_DATA strh w1, [x0, #SCIF_SCFCR] /* Set bits TE and RE in SCSCR to 1 */ ldrh w1, [x0, #SCIF_SCSCR] orr w1, w1, #(SCSCR_TE_EN + SCSCR_RE_EN) strh w1, [x0, #SCIF_SCSCR] mov x0, #1 ret endfunc console_rcar_init /* -------------------------------------------------------- * int console_rcar_putc(int c, unsigned int base_addr) * Function to output a character over the console. It * returns the character printed on success or -1 on error. * In : w0 - character to be printed * x1 - pointer to console_t structure * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_rcar_putc ldr x1, =SCIF_BASE cmp w0, #0xA /* Prepend '\r' to '\n' */ bne 2f 1: /* Check if the transmit FIFO is full */ ldrh w2, [x1, #SCIF_SCFDR] ubfx w2, w2, #8, #5 cmp w2, #16 bcs 1b mov w2, #0x0D strb w2, [x1, #SCIF_SCFTDR] 2: /* Check if the transmit FIFO is full */ ldrh w2, [x1, #SCIF_SCFDR] ubfx w2, w2, #8, #5 cmp w2, #16 bcs 2b strb w0, [x1, #SCIF_SCFTDR] /* Clear TEND flag */ ldrh w2, [x1, #SCIF_SCFSR] and w2, w2, #~SCFSR_TEND_MASK strh w2, [x1, #SCIF_SCFSR] ret endfunc console_rcar_putc /* --------------------------------------------- * int console_rcar_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 : x0, x1 * --------------------------------------------- */ func console_rcar_flush ldr x0, =SCIF_BASE 1: /* Check TEND flag */ ldrh w1, [x0, #SCIF_SCFSR] and w1, w1, #SCFSR_TEND_MASK cmp w1, #SCFSR_TEND_TRANS_END bne 1b ldr x0, =SCIF_BASE ldrh w1, [x0, #SCIF_SCSCR] and w1, w1, #~(SCSCR_TE_EN + SCSCR_RE_EN) strh w1, [x0, #SCIF_SCSCR] mov w0, #0 ret endfunc console_rcar_flush trusted-firmware-a-2.2/drivers/renesas/rcar/watchdog/000077500000000000000000000000001355360272700227565ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/renesas/rcar/watchdog/swdt.c000066400000000000000000000111501355360272700241010ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "rcar_def.h" extern void gicd_set_icenabler(uintptr_t base, unsigned int id); #define RST_BASE (0xE6160000U) #define RST_WDTRSTCR (RST_BASE + 0x0054U) #define SWDT_BASE (0xE6030000U) #define SWDT_WTCNT (SWDT_BASE + 0x0000U) #define SWDT_WTCSRA (SWDT_BASE + 0x0004U) #define SWDT_WTCSRB (SWDT_BASE + 0x0008U) #define SWDT_GICD_BASE (0xF1010000U) #define SWDT_GICC_BASE (0xF1020000U) #define SWDT_GICD_CTLR (SWDT_GICD_BASE + 0x0000U) #define SWDT_GICD_IGROUPR (SWDT_GICD_BASE + 0x0080U) #define SWDT_GICD_ISPRIORITYR (SWDT_GICD_BASE + 0x0400U) #define SWDT_GICC_CTLR (SWDT_GICC_BASE + 0x0000U) #define SWDT_GICC_PMR (SWDT_GICC_BASE + 0x0004U) #define SWDT_GICD_ITARGETSR (SWDT_GICD_BASE + 0x0800U) #define IGROUPR_NUM (16U) #define ISPRIORITY_NUM (128U) #define ITARGET_MASK (0x03U) #define WDTRSTCR_UPPER_BYTE (0xA55A0000U) #define WTCSRA_UPPER_BYTE (0xA5A5A500U) #define WTCSRB_UPPER_BYTE (0xA5A5A500U) #define WTCNT_UPPER_BYTE (0x5A5A0000U) #define WTCNT_RESET_VALUE (0xF488U) #define WTCSRA_BIT_CKS (0x0007U) #define WTCSRB_BIT_CKS (0x003FU) #define SWDT_RSTMSK (1U << 1U) #define WTCSRA_WOVFE (1U << 3U) #define WTCSRA_WRFLG (1U << 5U) #define SWDT_ENABLE (1U << 7U) #define WDTRSTCR_MASK_ALL (0x0000FFFFU) #define WTCSRA_MASK_ALL (0x000000FFU) #define WTCNT_INIT_DATA (WTCNT_UPPER_BYTE + WTCNT_RESET_VALUE) #define WTCSRA_INIT_DATA (WTCSRA_UPPER_BYTE + 0x0FU) #define WTCSRB_INIT_DATA (WTCSRB_UPPER_BYTE + 0x21U) #if RCAR_LSI == RCAR_D3 #define WTCNT_COUNT_8p13k (0x10000U - 40760U) #else #define WTCNT_COUNT_8p13k (0x10000U - 40687U) #endif #define WTCNT_COUNT_8p13k_H3VER10 (0x10000U - 20343U) #define WTCNT_COUNT_8p22k (0x10000U - 41115U) #define WTCNT_COUNT_7p81k (0x10000U - 39062U) #define WTCSRA_CKS_DIV16 (0x00000002U) static void swdt_disable(void) { uint32_t rmsk; rmsk = mmio_read_32(RST_WDTRSTCR) & WDTRSTCR_MASK_ALL; rmsk |= SWDT_RSTMSK; mmio_write_32(RST_WDTRSTCR, WDTRSTCR_UPPER_BYTE | rmsk); mmio_write_32(SWDT_WTCNT, WTCNT_INIT_DATA); mmio_write_32(SWDT_WTCSRA, WTCSRA_INIT_DATA); mmio_write_32(SWDT_WTCSRB, WTCSRB_INIT_DATA); /* Set the interrupt clear enable register */ gicd_set_icenabler(RCAR_GICD_BASE, ARM_IRQ_SEC_WDT); } void rcar_swdt_init(void) { uint32_t rmsk, sr; #if (RCAR_LSI != RCAR_E3) uint32_t reg, val, product_cut, chk_data; reg = mmio_read_32(RCAR_PRR); product_cut = reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK); reg = mmio_read_32(RCAR_MODEMR); chk_data = reg & CHECK_MD13_MD14; #endif /* stop watchdog */ if (mmio_read_32(SWDT_WTCSRA) & SWDT_ENABLE) mmio_write_32(SWDT_WTCSRA, WTCSRA_UPPER_BYTE); mmio_write_32(SWDT_WTCSRA, WTCSRA_UPPER_BYTE | WTCSRA_WOVFE | WTCSRA_CKS_DIV16); #if (RCAR_LSI == RCAR_E3) mmio_write_32(SWDT_WTCNT, WTCNT_UPPER_BYTE | WTCNT_COUNT_7p81k); #else val = WTCNT_UPPER_BYTE; switch (chk_data) { case MD14_MD13_TYPE_0: case MD14_MD13_TYPE_2: val |= WTCNT_COUNT_8p13k; break; case MD14_MD13_TYPE_1: val |= WTCNT_COUNT_8p22k; break; case MD14_MD13_TYPE_3: val |= product_cut == (PRR_PRODUCT_H3 | PRR_PRODUCT_10) ? WTCNT_COUNT_8p13k_H3VER10 : WTCNT_COUNT_8p13k; break; default: ERROR("MODEMR ERROR value = %x\n", chk_data); panic(); break; } mmio_write_32(SWDT_WTCNT, val); #endif rmsk = mmio_read_32(RST_WDTRSTCR) & WDTRSTCR_MASK_ALL; rmsk |= SWDT_RSTMSK | WDTRSTCR_UPPER_BYTE; mmio_write_32(RST_WDTRSTCR, rmsk); while ((mmio_read_8(SWDT_WTCSRA) & WTCSRA_WRFLG) != 0U) ; /* Start the System WatchDog Timer */ sr = mmio_read_32(SWDT_WTCSRA) & WTCSRA_MASK_ALL; mmio_write_32(SWDT_WTCSRA, (WTCSRA_UPPER_BYTE | sr | SWDT_ENABLE)); } void rcar_swdt_release(void) { uintptr_t itarget = SWDT_GICD_ITARGETSR + (ARM_IRQ_SEC_WDT & ~ITARGET_MASK); uint32_t i; /* Disable FIQ interrupt */ write_daifset(DAIF_FIQ_BIT); /* FIQ interrupts are not taken to EL3 */ write_scr_el3(read_scr_el3() & ~SCR_FIQ_BIT); swdt_disable(); gicv2_cpuif_disable(); for (i = 0; i < IGROUPR_NUM; i++) mmio_write_32(SWDT_GICD_IGROUPR + i * 4, 0U); for (i = 0; i < ISPRIORITY_NUM; i++) mmio_write_32(SWDT_GICD_ISPRIORITYR + i * 4, 0U); mmio_write_32(itarget, 0U); mmio_write_32(SWDT_GICD_CTLR, 0U); mmio_write_32(SWDT_GICC_CTLR, 0U); mmio_write_32(SWDT_GICC_PMR, 0U); } void rcar_swdt_exec(uint64_t p) { gicv2_end_of_interrupt(ARM_IRQ_SEC_WDT); rcar_swdt_release(); ERROR("\n"); ERROR("System WDT overflow, occured address is %p\n", (void *)p); panic(); } trusted-firmware-a-2.2/drivers/rpi3/000077500000000000000000000000001355360272700174445ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/rpi3/gpio/000077500000000000000000000000001355360272700204025ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/rpi3/gpio/rpi3_gpio.c000066400000000000000000000112761355360272700224500ustar00rootroot00000000000000/* * Copyright (c) 2019, Linaro Limited * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include static struct rpi3_gpio_params rpi3_gpio_params; static int rpi3_gpio_get_direction(int gpio); static void rpi3_gpio_set_direction(int gpio, int direction); static int rpi3_gpio_get_value(int gpio); static void rpi3_gpio_set_value(int gpio, int value); static void rpi3_gpio_set_pull(int gpio, int pull); static const gpio_ops_t rpi3_gpio_ops = { .get_direction = rpi3_gpio_get_direction, .set_direction = rpi3_gpio_set_direction, .get_value = rpi3_gpio_get_value, .set_value = rpi3_gpio_set_value, .set_pull = rpi3_gpio_set_pull, }; /** * Get selection of GPIO pinmux settings. * * @param gpio The pin number of GPIO. From 0 to 53. * @return The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input, * RPI3_GPIO_FUNC_OUTPUT: output, * RPI3_GPIO_FUNC_ALT0: alt-0, * RPI3_GPIO_FUNC_ALT1: alt-1, * RPI3_GPIO_FUNC_ALT2: alt-2, * RPI3_GPIO_FUNC_ALT3: alt-3, * RPI3_GPIO_FUNC_ALT4: alt-4, * RPI3_GPIO_FUNC_ALT5: alt-5 */ int rpi3_gpio_get_select(int gpio) { int ret; uintptr_t reg_base = rpi3_gpio_params.reg_base; int regN = gpio / 10; int shift = 3 * (gpio % 10); uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN); uint32_t sel = mmio_read_32(reg_sel); ret = (sel >> shift) & 0x07; return ret; } /** * Set selection of GPIO pinmux settings. * * @param gpio The pin number of GPIO. From 0 to 53. * @param fsel The selection of pinmux. RPI3_GPIO_FUNC_INPUT: input, * RPI3_GPIO_FUNC_OUTPUT: output, * RPI3_GPIO_FUNC_ALT0: alt-0, * RPI3_GPIO_FUNC_ALT1: alt-1, * RPI3_GPIO_FUNC_ALT2: alt-2, * RPI3_GPIO_FUNC_ALT3: alt-3, * RPI3_GPIO_FUNC_ALT4: alt-4, * RPI3_GPIO_FUNC_ALT5: alt-5 */ void rpi3_gpio_set_select(int gpio, int fsel) { uintptr_t reg_base = rpi3_gpio_params.reg_base; int regN = gpio / 10; int shift = 3 * (gpio % 10); uintptr_t reg_sel = reg_base + RPI3_GPIO_GPFSEL(regN); uint32_t sel = mmio_read_32(reg_sel); uint32_t mask = U(0x07) << shift; sel = (sel & (~mask)) | ((fsel << shift) & mask); mmio_write_32(reg_sel, sel); } static int rpi3_gpio_get_direction(int gpio) { int result = rpi3_gpio_get_select(gpio); if (result == RPI3_GPIO_FUNC_INPUT) return GPIO_DIR_IN; else if (result == RPI3_GPIO_FUNC_OUTPUT) return GPIO_DIR_OUT; return GPIO_DIR_IN; } static void rpi3_gpio_set_direction(int gpio, int direction) { switch (direction) { case GPIO_DIR_IN: rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_INPUT); break; case GPIO_DIR_OUT: rpi3_gpio_set_select(gpio, RPI3_GPIO_FUNC_OUTPUT); break; } } static int rpi3_gpio_get_value(int gpio) { uintptr_t reg_base = rpi3_gpio_params.reg_base; int regN = gpio / 32; int shift = gpio % 32; uintptr_t reg_lev = reg_base + RPI3_GPIO_GPLEV(regN); uint32_t value = mmio_read_32(reg_lev); if ((value >> shift) & 0x01) return GPIO_LEVEL_HIGH; return GPIO_LEVEL_LOW; } static void rpi3_gpio_set_value(int gpio, int value) { uintptr_t reg_base = rpi3_gpio_params.reg_base; int regN = gpio / 32; int shift = gpio % 32; uintptr_t reg_set = reg_base + RPI3_GPIO_GPSET(regN); uintptr_t reg_clr = reg_base + RPI3_GPIO_GPSET(regN); switch (value) { case GPIO_LEVEL_LOW: mmio_write_32(reg_clr, U(1) << shift); break; case GPIO_LEVEL_HIGH: mmio_write_32(reg_set, U(1) << shift); break; } } static void rpi3_gpio_set_pull(int gpio, int pull) { uintptr_t reg_base = rpi3_gpio_params.reg_base; int regN = gpio / 32; int shift = gpio % 32; uintptr_t reg_pud = reg_base + RPI3_GPIO_GPPUD; uintptr_t reg_clk = reg_base + RPI3_GPIO_GPPUDCLK(regN); switch (pull) { case GPIO_PULL_NONE: mmio_write_32(reg_pud, 0x0); break; case GPIO_PULL_UP: mmio_write_32(reg_pud, 0x2); break; case GPIO_PULL_DOWN: mmio_write_32(reg_pud, 0x1); break; } mdelay(150); mmio_write_32(reg_clk, U(1) << shift); mdelay(150); mmio_write_32(reg_clk, 0x0); mmio_write_32(reg_pud, 0x0); } void rpi3_gpio_init(struct rpi3_gpio_params *params) { assert(params != 0); memcpy(&rpi3_gpio_params, params, sizeof(struct rpi3_gpio_params)); gpio_init(&rpi3_gpio_ops); } trusted-firmware-a-2.2/drivers/rpi3/mailbox/000077500000000000000000000000001355360272700210775ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/rpi3/mailbox/rpi3_mbox.c000066400000000000000000000041651355360272700231530ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #define RPI3_MAILBOX_MAX_RETRIES U(1000000) /******************************************************************************* * Routine to send requests to the VideoCore using the mailboxes. ******************************************************************************/ void rpi3_vc_mailbox_request_send(rpi3_mbox_request_t *req, int req_size) { uint32_t st, data; uintptr_t resp_addr, addr; unsigned int retries; /* This is the location of the request buffer */ addr = (uintptr_t)req; /* Make sure that the changes are seen by the VideoCore */ flush_dcache_range(addr, req_size); /* Wait until the outbound mailbox is empty */ retries = 0U; do { st = mmio_read_32(RPI3_MBOX_BASE + RPI3_MBOX1_STATUS_OFFSET); retries++; if (retries == RPI3_MAILBOX_MAX_RETRIES) { ERROR("rpi3: mbox: Send request timeout\n"); return; } } while ((st & RPI3_MBOX_STATUS_EMPTY_MASK) == 0U); /* Send base address of this message to start request */ mmio_write_32(RPI3_MBOX_BASE + RPI3_MBOX1_WRITE_OFFSET, RPI3_CHANNEL_ARM_TO_VC | (uint32_t) addr); /* Wait until the inbound mailbox isn't empty */ retries = 0U; do { st = mmio_read_32(RPI3_MBOX_BASE + RPI3_MBOX0_STATUS_OFFSET); retries++; if (retries == RPI3_MAILBOX_MAX_RETRIES) { ERROR("rpi3: mbox: Receive response timeout\n"); return; } } while ((st & RPI3_MBOX_STATUS_EMPTY_MASK) != 0U); /* Get location and channel */ data = mmio_read_32(RPI3_MBOX_BASE + RPI3_MBOX0_READ_OFFSET); if ((data & RPI3_CHANNEL_MASK) != RPI3_CHANNEL_ARM_TO_VC) { ERROR("rpi3: mbox: Wrong channel: 0x%08x\n", data); panic(); } resp_addr = (uintptr_t)(data & ~RPI3_CHANNEL_MASK); if (addr != resp_addr) { ERROR("rpi3: mbox: Unexpected address: 0x%08x\n", data); panic(); } /* Make sure that the data seen by the CPU is up to date */ inv_dcache_range(addr, req_size); } trusted-firmware-a-2.2/drivers/rpi3/rng/000077500000000000000000000000001355360272700202325ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/rpi3/rng/rpi3_rng.c000066400000000000000000000033171355360272700221250ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /* Initial amount of values to discard */ #define RNG_WARMUP_COUNT U(0x40000) static void rpi3_rng_initialize(void) { uint32_t int_mask, ctrl; /* Return if it is already enabled */ ctrl = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET); if ((ctrl & RPI3_RNG_CTRL_ENABLE) != 0U) { return; } /* Mask interrupts */ int_mask = mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET); int_mask |= RPI3_RNG_INT_MASK_DISABLE; mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_INT_MASK_OFFSET, int_mask); /* Discard several values when initializing to give it time to warmup */ mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET, RNG_WARMUP_COUNT); mmio_write_32(RPI3_RNG_BASE + RPI3_RNG_CTRL_OFFSET, RPI3_RNG_CTRL_ENABLE); } static uint32_t rpi3_rng_get_word(void) { size_t nwords; do { /* Get number of available words to read */ nwords = (mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_STATUS_OFFSET) >> RPI3_RNG_STATUS_NUM_WORDS_SHIFT) & RPI3_RNG_STATUS_NUM_WORDS_MASK; } while (nwords == 0U); return mmio_read_32(RPI3_RNG_BASE + RPI3_RNG_DATA_OFFSET); } void rpi3_rng_read(void *buf, size_t len) { uint32_t data; size_t left = len; uint32_t *dst = buf; assert(buf != NULL); assert(len != 0U); assert(check_uptr_overflow((uintptr_t) buf, (uintptr_t) len) == 0); rpi3_rng_initialize(); while (left >= sizeof(uint32_t)) { data = rpi3_rng_get_word(); *dst++ = data; left -= sizeof(uint32_t); } if (left > 0U) { data = rpi3_rng_get_word(); memcpy(dst, &data, left); } } trusted-firmware-a-2.2/drivers/rpi3/sdhost/000077500000000000000000000000001355360272700207505ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/rpi3/sdhost/rpi3_sdhost.c000066400000000000000000000441451355360272700233650ustar00rootroot00000000000000/* * Copyright (c) 2019, Linaro Limited * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include static void rpi3_sdhost_initialize(void); static int rpi3_sdhost_send_cmd(struct mmc_cmd *cmd); static int rpi3_sdhost_set_ios(unsigned int clk, unsigned int width); static int rpi3_sdhost_prepare(int lba, uintptr_t buf, size_t size); static int rpi3_sdhost_read(int lba, uintptr_t buf, size_t size); static int rpi3_sdhost_write(int lba, uintptr_t buf, size_t size); static const struct mmc_ops rpi3_sdhost_ops = { .init = rpi3_sdhost_initialize, .send_cmd = rpi3_sdhost_send_cmd, .set_ios = rpi3_sdhost_set_ios, .prepare = rpi3_sdhost_prepare, .read = rpi3_sdhost_read, .write = rpi3_sdhost_write, }; static struct rpi3_sdhost_params rpi3_sdhost_params; /** * Wait for command being processed. * * This function waits the command being processed. It compares * the ENABLE flag of the HC_COMMAND register. When ENABLE flag disappeared * it means the command is processed by the SDHOST. * The timeout is currently 1000*100 us = 100 ms. * * @return 0: command finished. 1: command timed out. */ static int rpi3_sdhost_waitcommand(void) { uintptr_t reg_base = rpi3_sdhost_params.reg_base; volatile int timeout = 1000; while ((mmio_read_32(reg_base + HC_COMMAND) & HC_CMD_ENABLE) && (--timeout > 0)) { udelay(100); } return ((timeout > 0) ? 0 : (-(ETIMEDOUT))); } /** * Send the command and argument to the SDHOST * * This function will wait for the previous command finished. And then * clear any error status of previous command. And then * send out the command and args. The command will be turned on the ENABLE * flag before sending out. */ static void send_command_raw(unsigned int cmd, unsigned int arg) { unsigned int status; uintptr_t reg_base = rpi3_sdhost_params.reg_base; /* wait for previous command finish */ rpi3_sdhost_waitcommand(); /* clean error status */ status = mmio_read_32(reg_base + HC_HOSTSTATUS); if (status & HC_HSTST_MASK_ERROR_ALL) mmio_write_32(reg_base + HC_HOSTSTATUS, status); /* recording the command */ rpi3_sdhost_params.current_cmd = cmd & HC_CMD_COMMAND_MASK; /* send the argument and command */ mmio_write_32(reg_base + HC_ARGUMENT, arg); mmio_write_32(reg_base + HC_COMMAND, cmd | HC_CMD_ENABLE); } /** * Send the command and argument to the SDHOST, decorated with control * flags. * * This function will use send_command_raw to send the commands to SDHOST. * But before sending it will decorate the command with control flags specific * to SDHOST. */ static void send_command_decorated(unsigned int cmd, unsigned int arg) { unsigned int cmd_flags = 0; switch (cmd & HC_CMD_COMMAND_MASK) { case MMC_CMD(0): cmd_flags |= HC_CMD_RESPONSE_NONE; break; case MMC_ACMD(51): cmd_flags |= HC_CMD_READ; break; case MMC_CMD(8): case MMC_CMD(11): case MMC_CMD(17): case MMC_CMD(18): cmd_flags |= HC_CMD_READ; break; case MMC_CMD(20): case MMC_CMD(24): case MMC_CMD(25): cmd_flags |= HC_CMD_WRITE; break; case MMC_CMD(12): cmd_flags |= HC_CMD_BUSY; break; default: break; } send_command_raw(cmd | cmd_flags, arg); } /** * drains the FIFO on DATA port * * This function drains any data left in the DATA port. */ static void rpi3_drain_fifo(void) { uintptr_t reg_base = rpi3_sdhost_params.reg_base; volatile int timeout = 100000; rpi3_sdhost_waitcommand(); while (mmio_read_32(reg_base + HC_HOSTSTATUS) & HC_HSTST_HAVEDATA) { mmio_read_32(reg_base + HC_DATAPORT); udelay(100); } while (1) { uint32_t edm, fsm; edm = mmio_read_32(reg_base + HC_DEBUG); fsm = edm & HC_DBG_FSM_MASK; if ((fsm == HC_DBG_FSM_IDENTMODE) || (fsm == HC_DBG_FSM_DATAMODE)) break; if ((fsm == HC_DBG_FSM_READWAIT) || (fsm == HC_DBG_FSM_WRITESTART1) || (fsm == HC_DBG_FSM_READDATA)) { mmio_write_32(reg_base + HC_DEBUG, edm | HC_DBG_FORCE_DATA_MODE); break; } if (--timeout <= 0) { ERROR("rpi3_sdhost: %s cannot recover stat\n", __func__); return; } } } /** * Dump SDHOST registers */ static void rpi3_sdhost_print_regs(void) { uintptr_t reg_base = rpi3_sdhost_params.reg_base; INFO("rpi3_sdhost: HC_COMMAND: 0x%08x\n", mmio_read_32(reg_base + HC_COMMAND)); INFO("rpi3_sdhost: HC_ARGUMENT: 0x%08x\n", mmio_read_32(reg_base + HC_ARGUMENT)); INFO("rpi3_sdhost: HC_TIMEOUTCOUNTER: 0x%08x\n", mmio_read_32(reg_base + HC_TIMEOUTCOUNTER)); INFO("rpi3_sdhost: HC_CLOCKDIVISOR: 0x%08x\n", mmio_read_32(reg_base + HC_CLOCKDIVISOR)); INFO("rpi3_sdhost: HC_RESPONSE_0: 0x%08x\n", mmio_read_32(reg_base + HC_RESPONSE_0)); INFO("rpi3_sdhost: HC_RESPONSE_1: 0x%08x\n", mmio_read_32(reg_base + HC_RESPONSE_1)); INFO("rpi3_sdhost: HC_RESPONSE_2: 0x%08x\n", mmio_read_32(reg_base + HC_RESPONSE_2)); INFO("rpi3_sdhost: HC_RESPONSE_3: 0x%08x\n", mmio_read_32(reg_base + HC_RESPONSE_3)); INFO("rpi3_sdhost: HC_HOSTSTATUS: 0x%08x\n", mmio_read_32(reg_base + HC_HOSTSTATUS)); INFO("rpi3_sdhost: HC_POWER: 0x%08x\n", mmio_read_32(reg_base + HC_POWER)); INFO("rpi3_sdhost: HC_DEBUG: 0x%08x\n", mmio_read_32(reg_base + HC_DEBUG)); INFO("rpi3_sdhost: HC_HOSTCONFIG: 0x%08x\n", mmio_read_32(reg_base + HC_HOSTCONFIG)); INFO("rpi3_sdhost: HC_BLOCKSIZE: 0x%08x\n", mmio_read_32(reg_base + HC_BLOCKSIZE)); INFO("rpi3_sdhost: HC_BLOCKCOUNT: 0x%08x\n", mmio_read_32(reg_base + HC_BLOCKCOUNT)); } /** * Reset SDHOST */ static void rpi3_sdhost_reset(void) { uintptr_t reg_base = rpi3_sdhost_params.reg_base; unsigned int dbg; uint32_t tmp1; mmio_write_32(reg_base + HC_POWER, 0); mmio_write_32(reg_base + HC_COMMAND, 0); mmio_write_32(reg_base + HC_ARGUMENT, 0); mmio_write_32(reg_base + HC_TIMEOUTCOUNTER, HC_TIMEOUT_DEFAULT); mmio_write_32(reg_base + HC_CLOCKDIVISOR, 0); mmio_write_32(reg_base + HC_HOSTSTATUS, HC_HSTST_RESET); mmio_write_32(reg_base + HC_HOSTCONFIG, 0); mmio_write_32(reg_base + HC_BLOCKSIZE, 0); mmio_write_32(reg_base + HC_BLOCKCOUNT, 0); dbg = mmio_read_32(reg_base + HC_DEBUG); dbg &= ~((HC_DBG_FIFO_THRESH_MASK << HC_DBG_FIFO_THRESH_READ_SHIFT) | (HC_DBG_FIFO_THRESH_MASK << HC_DBG_FIFO_THRESH_WRITE_SHIFT)); dbg |= (HC_FIFO_THRESH_READ << HC_DBG_FIFO_THRESH_READ_SHIFT) | (HC_FIFO_THRESH_WRITE << HC_DBG_FIFO_THRESH_WRITE_SHIFT); mmio_write_32(reg_base + HC_DEBUG, dbg); mdelay(250); mmio_write_32(reg_base + HC_POWER, 1); mdelay(250); rpi3_sdhost_params.clk_rate = 0; mmio_write_32(reg_base + HC_CLOCKDIVISOR, HC_CLOCKDIVISOR_MAXVAL); tmp1 = mmio_read_32(reg_base + HC_HOSTCONFIG); mmio_write_32(reg_base + HC_HOSTCONFIG, tmp1 | HC_HSTCF_INT_BUSY); } static void rpi3_sdhost_initialize(void) { uintptr_t reg_base = rpi3_sdhost_params.reg_base; assert((rpi3_sdhost_params.reg_base & MMC_BLOCK_MASK) == 0); rpi3_sdhost_reset(); mmio_write_32(reg_base + HC_CLOCKDIVISOR, HC_CLOCKDIVISOR_PREFERVAL); udelay(300); } static int rpi3_sdhost_send_cmd(struct mmc_cmd *cmd) { uintptr_t reg_base = rpi3_sdhost_params.reg_base; int err = 0; uint32_t cmd_idx; uint32_t cmd_arg; uint32_t cmd_flags = 0; uint32_t intmask; /* Wait for the command done */ err = rpi3_sdhost_waitcommand(); if (err != 0) { WARN("previous command not done yet\n"); return err; } cmd_idx = cmd->cmd_idx & HC_CMD_COMMAND_MASK; cmd_arg = cmd->cmd_arg; if (cmd_idx == MMC_ACMD(51)) { /* if previous cmd send to SDHOST is not MMC_CMD(55). * It means this MMC_ACMD(51) is a resend. * And we must also resend MMC_CMD(55) in this case */ if (rpi3_sdhost_params.current_cmd != MMC_CMD(55)) { send_command_decorated( MMC_CMD(55), rpi3_sdhost_params.sdcard_rca << RCA_SHIFT_OFFSET); rpi3_sdhost_params.mmc_app_cmd = 1; rpi3_sdhost_waitcommand(); /* Also we need to call prepare to clean the buffer */ rpi3_sdhost_prepare(0, (uintptr_t)NULL, 8); } } /* We ignore MMC_CMD(12) sending from the TF-A's MMC driver * because we send MMC_CMD(12) by ourselves. */ if (cmd_idx == MMC_CMD(12)) return 0; if ((cmd->resp_type & MMC_RSP_136) && (cmd->resp_type & MMC_RSP_BUSY)) { ERROR("rpi3_sdhost: unsupported response type!\n"); return -(EOPNOTSUPP); } if (cmd->resp_type & MMC_RSP_48 && cmd->resp_type != MMC_RESPONSE_R2) { /* 48-bit command * We don't need to set any flags here because it is default. */ } else if (cmd->resp_type & MMC_RSP_136) { /* 136-bit command */ cmd_flags |= HC_CMD_RESPONSE_LONG; } else { /* no respond command */ cmd_flags |= HC_CMD_RESPONSE_NONE; } rpi3_sdhost_params.cmdbusy = 0; if (cmd->resp_type & MMC_RSP_BUSY) { cmd_flags |= HC_CMD_BUSY; rpi3_sdhost_params.cmdbusy = 1; } if (rpi3_sdhost_params.mmc_app_cmd) { switch (cmd_idx) { case MMC_ACMD(41): if (cmd_arg == OCR_HCS) cmd_arg |= OCR_3_3_3_4; break; default: break; } rpi3_sdhost_params.mmc_app_cmd = 0; } if (cmd_idx == MMC_CMD(55)) rpi3_sdhost_params.mmc_app_cmd = 1; send_command_decorated(cmd_idx | cmd_flags, cmd_arg); intmask = mmio_read_32(reg_base + HC_HOSTSTATUS); if (rpi3_sdhost_params.cmdbusy && (intmask & HC_HSTST_INT_BUSY)) { mmio_write_32(reg_base + HC_HOSTSTATUS, HC_HSTST_INT_BUSY); rpi3_sdhost_params.cmdbusy = 0; } if (!(cmd_flags & HC_CMD_RESPONSE_NONE)) { err = rpi3_sdhost_waitcommand(); if (err != 0) ERROR("rpi3_sdhost: cmd cannot be finished\n"); } cmd->resp_data[0] = mmio_read_32(reg_base + HC_RESPONSE_0); cmd->resp_data[1] = mmio_read_32(reg_base + HC_RESPONSE_1); cmd->resp_data[2] = mmio_read_32(reg_base + HC_RESPONSE_2); cmd->resp_data[3] = mmio_read_32(reg_base + HC_RESPONSE_3); if (mmio_read_32(reg_base + HC_COMMAND) & HC_CMD_FAILED) { uint32_t sdhsts = mmio_read_32(reg_base + HC_HOSTSTATUS); mmio_write_32(reg_base + HC_HOSTSTATUS, HC_HSTST_MASK_ERROR_ALL); /* * If the command SEND_OP_COND returns with CRC7 error, * it can be considered as having completed successfully. */ if (!(sdhsts & HC_HSTST_ERROR_CRC7) || (cmd_idx != MMC_CMD(1))) { if (sdhsts & HC_HSTST_TIMEOUT_CMD) { ERROR("rpi3_sdhost: timeout status 0x%x\n", sdhsts); err = -(ETIMEDOUT); } else { ERROR("rpi3_sdhost: unknown err, cmd = 0x%x\n", mmio_read_32(reg_base + HC_COMMAND)); ERROR("rpi3_sdhost status: 0x%x\n", sdhsts); err = -(EILSEQ); } } } if ((!err) && (cmd_idx == MMC_CMD(3))) { /* we keep the RCA in case to send MMC_CMD(55) ourselves */ rpi3_sdhost_params.sdcard_rca = (cmd->resp_data[0] & 0xFFFF0000U) >> 16; } return err; } static int rpi3_sdhost_set_clock(unsigned int clk) { uintptr_t reg_base = rpi3_sdhost_params.reg_base; uint32_t max_clk = 250000000; uint32_t div; if (clk < 100000) { mmio_write_32(reg_base + HC_CLOCKDIVISOR, HC_CLOCKDIVISOR_MAXVAL); return 0; } div = max_clk / clk; if (div < 2) div = 2; if ((max_clk / div) > clk) div++; div -= 2; if (div > HC_CLOCKDIVISOR_MAXVAL) div = HC_CLOCKDIVISOR_MAXVAL; rpi3_sdhost_params.clk_rate = max_clk / (div + 2); rpi3_sdhost_params.ns_per_fifo_word = (1000000000 / rpi3_sdhost_params.clk_rate) * 8; mmio_write_32(reg_base + HC_CLOCKDIVISOR, div); return 0; } static int rpi3_sdhost_set_ios(unsigned int clk, unsigned int width) { uintptr_t reg_base = rpi3_sdhost_params.reg_base; uint32_t tmp1; rpi3_sdhost_set_clock(clk); VERBOSE("rpi3_sdhost: Changing clock to %dHz for data mode\n", clk); if (width != MMC_BUS_WIDTH_4 && width != MMC_BUS_WIDTH_1) { ERROR("rpi3_sdhost: width %d not supported\n", width); return -(EOPNOTSUPP); } rpi3_sdhost_params.bus_width = width; tmp1 = mmio_read_32(reg_base + HC_HOSTCONFIG); tmp1 &= ~(HC_HSTCF_EXTBUS_4BIT); if (rpi3_sdhost_params.bus_width == MMC_BUS_WIDTH_4) tmp1 |= HC_HSTCF_EXTBUS_4BIT; mmio_write_32(reg_base + HC_HOSTCONFIG, tmp1); tmp1 = mmio_read_32(reg_base + HC_HOSTCONFIG); mmio_write_32(reg_base + HC_HOSTCONFIG, tmp1 | HC_HSTCF_SLOW_CARD | HC_HSTCF_INTBUS_WIDE); return 0; } static int rpi3_sdhost_prepare(int lba, uintptr_t buf, size_t size) { uintptr_t reg_base = rpi3_sdhost_params.reg_base; size_t blocks; size_t blocksize; if (size < 512) { blocksize = size; blocks = 1; } else { blocksize = 512; blocks = size / blocksize; if (size % blocksize != 0) blocks++; } rpi3_drain_fifo(); mmio_write_32(reg_base + HC_BLOCKSIZE, blocksize); mmio_write_32(reg_base + HC_BLOCKCOUNT, blocks); udelay(100); return 0; } static int rpi3_sdhost_read(int lba, uintptr_t buf, size_t size) { int err = 0; uint32_t *buf1 = ((uint32_t *) buf); uintptr_t reg_base = rpi3_sdhost_params.reg_base; int timeout = 100000; int remaining_words = 0; for (int i = 0; i < size / 4; i++) { volatile int t = timeout; uint32_t hsts_err; while ((mmio_read_32(reg_base + HC_HOSTSTATUS) & HC_HSTST_HAVEDATA) == 0) { if (t == 0) { ERROR("rpi3_sdhost: fifo timeout after %dus\n", timeout); err = -(ETIMEDOUT); break; } t--; udelay(10); } if (t == 0) break; uint32_t data = mmio_read_32(reg_base + HC_DATAPORT); hsts_err = mmio_read_32(reg_base + HC_HOSTSTATUS) & HC_HSTST_MASK_ERROR_ALL; if (hsts_err) { ERROR("rpi3_sdhost: transfer FIFO word %d: 0x%x\n", i, mmio_read_32(reg_base + HC_HOSTSTATUS)); rpi3_sdhost_print_regs(); err = -(EILSEQ); /* clean the error status */ mmio_write_32(reg_base + HC_HOSTSTATUS, hsts_err); } if (buf1) buf1[i] = data; /* speeding up if the remaining words are still a lot */ remaining_words = (mmio_read_32(reg_base + HC_DEBUG) >> 4) & HC_DBG_FIFO_THRESH_MASK; if (remaining_words >= 7) continue; /* delay. slowing down the read process */ udelay(100); } /* We decide to stop by ourselves. * It is because MMC_CMD(18) -> MMC_CMD(13) -> MMC_CMD(12) * doesn't work for RPi3 SDHost. */ if (rpi3_sdhost_params.current_cmd == MMC_CMD(18)) send_command_decorated(MMC_CMD(12), 0); return err; } static int rpi3_sdhost_write(int lba, uintptr_t buf, size_t size) { uint32_t *buf1 = ((uint32_t *) buf); uintptr_t reg_base = rpi3_sdhost_params.reg_base; int err = 0; int remaining_words = 0; for (int i = 0; i < size / 4; i++) { uint32_t hsts_err; uint32_t data = buf1[i]; uint32_t dbg; uint32_t fsm_state; mmio_write_32(reg_base + HC_DATAPORT, data); dbg = mmio_read_32(reg_base + HC_DEBUG); fsm_state = dbg & HC_DBG_FSM_MASK; if (fsm_state != HC_DBG_FSM_WRITEDATA && fsm_state != HC_DBG_FSM_WRITESTART1 && fsm_state != HC_DBG_FSM_WRITESTART2 && fsm_state != HC_DBG_FSM_WRITECRC && fsm_state != HC_DBG_FSM_WRITEWAIT1 && fsm_state != HC_DBG_FSM_WRITEWAIT2) { hsts_err = mmio_read_32(reg_base + HC_HOSTSTATUS) & HC_HSTST_MASK_ERROR_ALL; if (hsts_err) err = -(EILSEQ); } /* speeding up if the remaining words are not many */ remaining_words = (mmio_read_32(reg_base + HC_DEBUG) >> 4) & HC_DBG_FIFO_THRESH_MASK; if (remaining_words <= 4) continue; udelay(100); } /* We decide to stop by ourselves. * It is because MMC_CMD(25) -> MMC_CMD(13) -> MMC_CMD(12) * doesn't work for RPi3 SDHost. */ if (rpi3_sdhost_params.current_cmd == MMC_CMD(25)) send_command_decorated(MMC_CMD(12), 0); return err; } void rpi3_sdhost_init(struct rpi3_sdhost_params *params, struct mmc_device_info *mmc_dev_info) { assert((params != 0) && ((params->reg_base & MMC_BLOCK_MASK) == 0)); memcpy(&rpi3_sdhost_params, params, sizeof(struct rpi3_sdhost_params)); /* backup GPIO 48 to 53 configurations */ for (int i = 48; i <= 53; i++) { rpi3_sdhost_params.gpio48_pinselect[i - 48] = rpi3_gpio_get_select(i); VERBOSE("rpi3_sdhost: Original GPIO state %d: %d\n", i, rpi3_sdhost_params.gpio48_pinselect[i - 48]); } /* setting pull resistors for 48 to 53. * It is debatable to set SD_CLK to UP or NONE. We massively * tested different brands of SD Cards and found NONE works * most stable. * * GPIO 48 (SD_CLK) to GPIO_PULL_NONE * GPIO 49 (SD_CMD) to GPIO_PULL_UP * GPIO 50 (SD_D0) to GPIO_PULL_UP * GPIO 51 (SD_D1) to GPIO_PULL_UP * GPIO 52 (SD_D2) to GPIO_PULL_UP * GPIO 53 (SD_D3) to GPIO_PULL_UP */ gpio_set_pull(48, GPIO_PULL_NONE); for (int i = 49; i <= 53; i++) gpio_set_pull(i, GPIO_PULL_UP); /* Set pin 48-53 to alt-0. It means route SDHOST to card slot */ for (int i = 48; i <= 53; i++) rpi3_gpio_set_select(i, RPI3_GPIO_FUNC_ALT0); mmc_init(&rpi3_sdhost_ops, params->clk_rate, params->bus_width, params->flags, mmc_dev_info); } void rpi3_sdhost_stop(void) { uintptr_t reg_base = rpi3_sdhost_params.reg_base; VERBOSE("rpi3_sdhost: Shutting down: drain FIFO out\n"); rpi3_drain_fifo(); VERBOSE("rpi3_sdhost: Shutting down: slowing down the clock\n"); mmio_write_32(reg_base+HC_CLOCKDIVISOR, HC_CLOCKDIVISOR_SLOWVAL); udelay(500); VERBOSE("rpi3_sdhost: Shutting down: put SDHost into idle state\n"); send_command_decorated(MMC_CMD(0), 0); udelay(500); mmio_write_32(reg_base + HC_COMMAND, 0); mmio_write_32(reg_base + HC_ARGUMENT, 0); mmio_write_32(reg_base + HC_TIMEOUTCOUNTER, HC_TIMEOUT_IDLE); mmio_write_32(reg_base + HC_CLOCKDIVISOR, HC_CLOCKDIVISOR_STOPVAL); udelay(100); mmio_write_32(reg_base + HC_POWER, 0); mmio_write_32(reg_base + HC_HOSTCONFIG, 0); mmio_write_32(reg_base + HC_BLOCKSIZE, 0x400); mmio_write_32(reg_base + HC_BLOCKCOUNT, 0); mmio_write_32(reg_base + HC_HOSTSTATUS, 0x7f8); mmio_write_32(reg_base + HC_COMMAND, 0); mmio_write_32(reg_base + HC_ARGUMENT, 0); udelay(100); /* Restore the pinmux to original state */ for (int i = 48; i <= 53; i++) { rpi3_gpio_set_select(i, rpi3_sdhost_params.gpio48_pinselect[i-48]); } /* Reset the pull resistors before entering BL33. * GPIO 48 (SD_CLK) to GPIO_PULL_UP * GPIO 49 (SD_CMD) to GPIO_PULL_UP * GPIO 50 (SD_D0) to GPIO_PULL_UP * GPIO 51 (SD_D1) to GPIO_PULL_UP * GPIO 52 (SD_D2) to GPIO_PULL_UP * GPIO 53 (SD_D3) to GPIO_PULL_UP */ for (int i = 48; i <= 53; i++) gpio_set_pull(i, GPIO_PULL_UP); } trusted-firmware-a-2.2/drivers/st/000077500000000000000000000000001355360272700172155ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/st/bsec/000077500000000000000000000000001355360272700201315ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/st/bsec/bsec.c000066400000000000000000000440601355360272700212150ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #define BSEC_IP_VERSION_1_0 0x10 #define BSEC_COMPAT "st,stm32mp15-bsec" #define OTP_ACCESS_SIZE (round_up(OTP_MAX_SIZE, __WORD_BIT) / __WORD_BIT) static uint32_t otp_nsec_access[OTP_ACCESS_SIZE] __unused; static uint32_t bsec_power_safmem(bool power); /* BSEC access protection */ static spinlock_t bsec_spinlock; static uintptr_t bsec_base; static void bsec_lock(void) { if (stm32mp_lock_available()) { spin_lock(&bsec_spinlock); } } static void bsec_unlock(void) { if (stm32mp_lock_available()) { 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_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 (stm32mp_is_closed_device()) { if (!non_secure_can_access(otp)) { return BSEC_ERROR; } } } #endif return BSEC_OK; } trusted-firmware-a-2.2/drivers/st/clk/000077500000000000000000000000001355360272700177665ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/st/clk/stm32mp1_clk.c000066400000000000000000001325661355360272700223660ustar00rootroot00000000000000/* * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_HSI_HZ 64000000 #define USB_PHY_48_MHZ 48000000 #define TIMEOUT_US_200MS U(200000) #define TIMEOUT_US_1S U(1000000) #define PLLRDY_TIMEOUT TIMEOUT_US_200MS #define CLKSRC_TIMEOUT TIMEOUT_US_200MS #define CLKDIV_TIMEOUT TIMEOUT_US_200MS #define HSIDIV_TIMEOUT TIMEOUT_US_200MS #define OSCRDY_TIMEOUT TIMEOUT_US_1S const char *stm32mp_osc_node_label[NB_OSC] = { [_LSI] = "clk-lsi", [_LSE] = "clk-lse", [_HSI] = "clk-hsi", [_HSE] = "clk-hse", [_CSI] = "clk-csi", [_I2S_CKIN] = "i2s_ckin", }; enum stm32mp1_parent_id { /* Oscillators are defined in enum stm32mp_osc_id */ /* Other parent source */ _HSI_KER = NB_OSC, _HSE_KER, _HSE_KER_DIV2, _CSI_KER, _PLL1_P, _PLL1_Q, _PLL1_R, _PLL2_P, _PLL2_Q, _PLL2_R, _PLL3_P, _PLL3_Q, _PLL3_R, _PLL4_P, _PLL4_Q, _PLL4_R, _ACLK, _PCLK1, _PCLK2, _PCLK3, _PCLK4, _PCLK5, _HCLK6, _HCLK2, _CK_PER, _CK_MPU, _CK_MCU, _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, _UART1_SEL, _RNG1_SEL, _UART6_SEL, _UART24_SEL, _UART35_SEL, _UART78_SEL, _SDMMC12_SEL, _SDMMC3_SEL, _QSPI_SEL, _FMC_SEL, _AXIS_SEL, _MCUS_SEL, _USBPHY_SEL, _USBO_SEL, _PARENT_SEL_NB, _UNKNOWN_SEL = 0xff, }; enum stm32mp1_pll_id { _PLL1, _PLL2, _PLL3, _PLL4, _PLL_NB }; enum stm32mp1_div_id { _DIV_P, _DIV_Q, _DIV_R, _DIV_NB, }; enum stm32mp1_clksrc_id { CLKSRC_MPU, CLKSRC_AXI, CLKSRC_MCU, CLKSRC_PLL12, CLKSRC_PLL3, CLKSRC_PLL4, CLKSRC_RTC, CLKSRC_MCO1, CLKSRC_MCO2, CLKSRC_NB }; enum stm32mp1_clkdiv_id { CLKDIV_MPU, CLKDIV_AXI, CLKDIV_MCU, CLKDIV_APB1, CLKDIV_APB2, CLKDIV_APB3, CLKDIV_APB4, CLKDIV_APB5, CLKDIV_RTC, CLKDIV_MCO1, CLKDIV_MCO2, CLKDIV_NB }; enum stm32mp1_pllcfg { PLLCFG_M, PLLCFG_N, PLLCFG_P, PLLCFG_Q, PLLCFG_R, PLLCFG_O, PLLCFG_NB }; enum stm32mp1_pllcsg { PLLCSG_MOD_PER, PLLCSG_INC_STEP, PLLCSG_SSCG_MODE, PLLCSG_NB }; enum stm32mp1_plltype { PLL_800, PLL_1600, PLL_TYPE_NB }; struct stm32mp1_pll { uint8_t refclk_min; uint8_t refclk_max; uint8_t divn_max; }; struct stm32mp1_clk_gate { uint16_t offset; uint8_t bit; uint8_t index; uint8_t set_clr; uint8_t sel; /* Relates to enum stm32mp1_parent_sel */ uint8_t fixed; /* Relates to enum stm32mp1_parent_id */ }; struct stm32mp1_clk_sel { uint16_t offset; uint8_t src; uint8_t msk; uint8_t nb_parent; const uint8_t *parent; }; #define REFCLK_SIZE 4 struct stm32mp1_clk_pll { enum stm32mp1_plltype plltype; uint16_t rckxselr; uint16_t pllxcfgr1; uint16_t pllxcfgr2; uint16_t pllxfracr; uint16_t pllxcr; uint16_t pllxcsgr; enum stm32mp_osc_id refclk[REFCLK_SIZE]; }; /* Clocks with selectable source and non set/clr register access */ #define _CLK_SELEC(off, b, idx, s) \ { \ .offset = (off), \ .bit = (b), \ .index = (idx), \ .set_clr = 0, \ .sel = (s), \ .fixed = _UNKNOWN_ID, \ } /* Clocks with fixed source and non set/clr register access */ #define _CLK_FIXED(off, b, idx, f) \ { \ .offset = (off), \ .bit = (b), \ .index = (idx), \ .set_clr = 0, \ .sel = _UNKNOWN_SEL, \ .fixed = (f), \ } /* Clocks with selectable source and set/clr register access */ #define _CLK_SC_SELEC(off, b, idx, s) \ { \ .offset = (off), \ .bit = (b), \ .index = (idx), \ .set_clr = 1, \ .sel = (s), \ .fixed = _UNKNOWN_ID, \ } /* Clocks with fixed source and set/clr register access */ #define _CLK_SC_FIXED(off, b, idx, f) \ { \ .offset = (off), \ .bit = (b), \ .index = (idx), \ .set_clr = 1, \ .sel = _UNKNOWN_SEL, \ .fixed = (f), \ } #define _CLK_PARENT_SEL(_label, _rcc_selr, _parents) \ [_ ## _label ## _SEL] = { \ .offset = _rcc_selr, \ .src = _rcc_selr ## _ ## _label ## SRC_SHIFT, \ .msk = _rcc_selr ## _ ## _label ## SRC_MASK, \ .parent = (_parents), \ .nb_parent = ARRAY_SIZE(_parents) \ } #define _CLK_PLL(idx, type, off1, off2, off3, \ off4, off5, off6, \ p1, p2, p3, p4) \ [(idx)] = { \ .plltype = (type), \ .rckxselr = (off1), \ .pllxcfgr1 = (off2), \ .pllxcfgr2 = (off3), \ .pllxfracr = (off4), \ .pllxcr = (off5), \ .pllxcsgr = (off6), \ .refclk[0] = (p1), \ .refclk[1] = (p2), \ .refclk[2] = (p3), \ .refclk[3] = (p4), \ } static const uint8_t stm32mp1_clks[][2] = { { CK_PER, _CK_PER }, { CK_MPU, _CK_MPU }, { CK_AXI, _ACLK }, { CK_MCU, _CK_MCU }, { CK_HSE, _HSE }, { CK_CSI, _CSI }, { CK_LSI, _LSI }, { CK_LSE, _LSE }, { CK_HSI, _HSI }, { CK_HSE_DIV2, _HSE_KER_DIV2 }, }; #define NB_GATES ARRAY_SIZE(stm32mp1_clk_gate) static const struct stm32mp1_clk_gate stm32mp1_clk_gate[] = { _CLK_FIXED(RCC_DDRITFCR, 0, DDRC1, _ACLK), _CLK_FIXED(RCC_DDRITFCR, 1, DDRC1LP, _ACLK), _CLK_FIXED(RCC_DDRITFCR, 2, DDRC2, _ACLK), _CLK_FIXED(RCC_DDRITFCR, 3, DDRC2LP, _ACLK), _CLK_FIXED(RCC_DDRITFCR, 4, DDRPHYC, _PLL2_R), _CLK_FIXED(RCC_DDRITFCR, 5, DDRPHYCLP, _PLL2_R), _CLK_FIXED(RCC_DDRITFCR, 6, DDRCAPB, _PCLK4), _CLK_FIXED(RCC_DDRITFCR, 7, DDRCAPBLP, _PCLK4), _CLK_FIXED(RCC_DDRITFCR, 8, AXIDCG, _ACLK), _CLK_FIXED(RCC_DDRITFCR, 9, DDRPHYCAPB, _PCLK4), _CLK_FIXED(RCC_DDRITFCR, 10, DDRPHYCAPBLP, _PCLK4), _CLK_SC_FIXED(RCC_MP_APB1ENSETR, 6, TIM12_K, _PCLK1), _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 14, USART2_K, _UART24_SEL), _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 15, USART3_K, _UART35_SEL), _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 16, UART4_K, _UART24_SEL), _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 17, UART5_K, _UART35_SEL), _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 18, UART7_K, _UART78_SEL), _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 19, UART8_K, _UART78_SEL), _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 21, I2C1_K, _I2C12_SEL), _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 22, I2C2_K, _I2C12_SEL), _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 23, I2C3_K, _I2C35_SEL), _CLK_SC_SELEC(RCC_MP_APB1ENSETR, 24, I2C5_K, _I2C35_SEL), _CLK_SC_FIXED(RCC_MP_APB2ENSETR, 2, TIM15_K, _PCLK2), _CLK_SC_SELEC(RCC_MP_APB2ENSETR, 13, USART6_K, _UART6_SEL), _CLK_SC_FIXED(RCC_MP_APB3ENSETR, 11, SYSCFG, _UNKNOWN_ID), _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 8, DDRPERFM, _UNKNOWN_SEL), _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 15, IWDG2, _UNKNOWN_SEL), _CLK_SC_SELEC(RCC_MP_APB4ENSETR, 16, USBPHY_K, _USBPHY_SEL), _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 0, SPI6_K, _SPI6_SEL), _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 2, I2C4_K, _I2C46_SEL), _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 3, I2C6_K, _I2C46_SEL), _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 4, USART1_K, _UART1_SEL), _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 8, RTCAPB, _PCLK5), _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 11, TZC1, _PCLK5), _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 12, TZC2, _PCLK5), _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 13, TZPC, _PCLK5), _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 15, IWDG1, _PCLK5), _CLK_SC_FIXED(RCC_MP_APB5ENSETR, 16, BSEC, _PCLK5), _CLK_SC_SELEC(RCC_MP_APB5ENSETR, 20, STGEN_K, _STGEN_SEL), _CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 8, USBO_K, _USBO_SEL), _CLK_SC_SELEC(RCC_MP_AHB2ENSETR, 16, SDMMC3_K, _SDMMC3_SEL), _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 0, GPIOA, _UNKNOWN_SEL), _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 1, GPIOB, _UNKNOWN_SEL), _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 2, GPIOC, _UNKNOWN_SEL), _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 3, GPIOD, _UNKNOWN_SEL), _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 4, GPIOE, _UNKNOWN_SEL), _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 5, GPIOF, _UNKNOWN_SEL), _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 6, GPIOG, _UNKNOWN_SEL), _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 7, GPIOH, _UNKNOWN_SEL), _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 8, GPIOI, _UNKNOWN_SEL), _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 9, GPIOJ, _UNKNOWN_SEL), _CLK_SC_SELEC(RCC_MP_AHB4ENSETR, 10, GPIOK, _UNKNOWN_SEL), _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 0, GPIOZ, _PCLK5), _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 4, CRYP1, _PCLK5), _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 5, HASH1, _PCLK5), _CLK_SC_SELEC(RCC_MP_AHB5ENSETR, 6, RNG1_K, _RNG1_SEL), _CLK_SC_FIXED(RCC_MP_AHB5ENSETR, 8, BKPSRAM, _PCLK5), _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 12, FMC_K, _FMC_SEL), _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 14, QSPI_K, _QSPI_SEL), _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 16, SDMMC1_K, _SDMMC12_SEL), _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 17, SDMMC2_K, _SDMMC12_SEL), _CLK_SC_SELEC(RCC_MP_AHB6ENSETR, 24, USBH, _UNKNOWN_SEL), _CLK_SELEC(RCC_DBGCFGR, 8, CK_DBG, _UNKNOWN_SEL), }; 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 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] = { _CLK_PARENT_SEL(I2C12, RCC_I2C12CKSELR, i2c12_parents), _CLK_PARENT_SEL(I2C35, RCC_I2C35CKSELR, i2c35_parents), _CLK_PARENT_SEL(STGEN, RCC_STGENCKSELR, stgen_parents), _CLK_PARENT_SEL(I2C46, RCC_I2C46CKSELR, i2c46_parents), _CLK_PARENT_SEL(SPI6, RCC_SPI6CKSELR, spi6_parents), _CLK_PARENT_SEL(UART1, RCC_UART1CKSELR, usart1_parents), _CLK_PARENT_SEL(RNG1, RCC_RNG1CKSELR, rng1_parents), _CLK_PARENT_SEL(UART6, RCC_UART6CKSELR, uart6_parents), _CLK_PARENT_SEL(UART24, RCC_UART24CKSELR, uart234578_parents), _CLK_PARENT_SEL(UART35, RCC_UART35CKSELR, uart234578_parents), _CLK_PARENT_SEL(UART78, RCC_UART78CKSELR, uart234578_parents), _CLK_PARENT_SEL(SDMMC12, RCC_SDMMC12CKSELR, sdmmc12_parents), _CLK_PARENT_SEL(SDMMC3, RCC_SDMMC3CKSELR, sdmmc3_parents), _CLK_PARENT_SEL(QSPI, RCC_QSPICKSELR, qspi_parents), _CLK_PARENT_SEL(FMC, RCC_FMCCKSELR, fmc_parents), _CLK_PARENT_SEL(AXIS, RCC_ASSCKSELR, ass_parents), _CLK_PARENT_SEL(MCUS, RCC_MSSCKSELR, mss_parents), _CLK_PARENT_SEL(USBPHY, RCC_USBCKSELR, usbphy_parents), _CLK_PARENT_SEL(USBO, RCC_USBCKSELR, usbo_parents), }; /* Define characteristic of PLL according type */ #define DIVN_MIN 24 static const struct stm32mp1_pll stm32mp1_pll[PLL_TYPE_NB] = { [PLL_800] = { .refclk_min = 4, .refclk_max = 16, .divn_max = 99, }, [PLL_1600] = { .refclk_min = 8, .refclk_max = 16, .divn_max = 199, }, }; /* PLLNCFGR2 register divider by output */ static const uint8_t pllncfgr2[_DIV_NB] = { [_DIV_P] = RCC_PLLNCFGR2_DIVP_SHIFT, [_DIV_Q] = RCC_PLLNCFGR2_DIVQ_SHIFT, [_DIV_R] = RCC_PLLNCFGR2_DIVR_SHIFT, }; static const struct stm32mp1_clk_pll stm32mp1_clk_pll[_PLL_NB] = { _CLK_PLL(_PLL1, PLL_1600, RCC_RCK12SELR, RCC_PLL1CFGR1, RCC_PLL1CFGR2, RCC_PLL1FRACR, RCC_PLL1CR, RCC_PLL1CSGR, _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), _CLK_PLL(_PLL2, PLL_1600, RCC_RCK12SELR, RCC_PLL2CFGR1, RCC_PLL2CFGR2, RCC_PLL2FRACR, RCC_PLL2CR, RCC_PLL2CSGR, _HSI, _HSE, _UNKNOWN_OSC_ID, _UNKNOWN_OSC_ID), _CLK_PLL(_PLL3, PLL_800, RCC_RCK3SELR, RCC_PLL3CFGR1, RCC_PLL3CFGR2, RCC_PLL3FRACR, RCC_PLL3CR, RCC_PLL3CSGR, _HSI, _HSE, _CSI, _UNKNOWN_OSC_ID), _CLK_PLL(_PLL4, PLL_800, RCC_RCK4SELR, RCC_PLL4CFGR1, RCC_PLL4CFGR2, RCC_PLL4FRACR, RCC_PLL4CR, RCC_PLL4CSGR, _HSI, _HSE, _CSI, _I2S_CKIN), }; /* Prescaler table lookups for clock computation */ /* div = /1 /2 /4 /8 / 16 /64 /128 /512 */ static const uint8_t stm32mp1_mcu_div[16] = { 0, 1, 2, 3, 4, 6, 7, 8, 9, 9, 9, 9, 9, 9, 9, 9 }; /* div = /1 /2 /4 /8 /16 : same divider for PMU and APBX */ #define stm32mp1_mpu_div stm32mp1_mpu_apbx_div #define stm32mp1_apbx_div stm32mp1_mpu_apbx_div static const uint8_t stm32mp1_mpu_apbx_div[8] = { 0, 1, 2, 3, 4, 4, 4, 4 }; /* div = /1 /2 /3 /4 */ static const uint8_t stm32mp1_axi_div[8] = { 1, 2, 3, 4, 4, 4, 4, 4 }; /* 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]; } static void stm32mp1_clk_lock(struct spinlock *lock) { if (stm32mp_lock_available()) { /* Assume interrupts are masked */ spin_lock(lock); } } static void stm32mp1_clk_unlock(struct spinlock *lock) { if (stm32mp_lock_available()) { 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 long stm32mp1_clk_get_fixed(enum stm32mp_osc_id idx) { if (idx >= NB_OSC) { return 0; } return stm32mp1_osc[idx]; } static int stm32mp1_clk_get_gated_id(unsigned long id) { unsigned int i; for (i = 0U; i < NB_GATES; i++) { if (gate_ref(i)->index == id) { return i; } } ERROR("%s: clk id %d not found\n", __func__, (uint32_t)id); return -EINVAL; } static enum stm32mp1_parent_sel stm32mp1_clk_get_sel(int i) { return (enum stm32mp1_parent_sel)(gate_ref(i)->sel); } static enum stm32mp1_parent_id stm32mp1_clk_get_fixed_parent(int i) { return (enum stm32mp1_parent_id)(gate_ref(i)->fixed); } static int stm32mp1_clk_get_parent(unsigned long id) { const struct stm32mp1_clk_sel *sel; 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 = 0U; j < ARRAY_SIZE(stm32mp1_clks); j++) { if (stm32mp1_clks[j][0] == id) { return (int)stm32mp1_clks[j][1]; } } i = stm32mp1_clk_get_gated_id(id); if (i < 0) { panic(); } p = stm32mp1_clk_get_fixed_parent(i); if (p < _PARENT_NB) { return (int)p; } s = stm32mp1_clk_get_sel(i); if (s == _UNKNOWN_SEL) { return -EINVAL; } if (s >= _PARENT_SEL_NB) { panic(); } sel = clk_sel_ref(s); p_sel = (mmio_read_32(rcc_base + sel->offset) & sel->msk) >> sel->src; if (p_sel < sel->nb_parent) { return (int)sel->parent[p_sel]; } return -EINVAL; } static unsigned long stm32mp1_pll_get_fref(const struct stm32mp1_clk_pll *pll) { uint32_t selr = mmio_read_32(stm32mp_rcc_base() + pll->rckxselr); uint32_t src = selr & RCC_SELR_REFCLK_SRC_MASK; return stm32mp1_clk_get_fixed(pll->refclk[src]); } /* * pll_get_fvco() : return the VCO or (VCO / 2) frequency for the requested PLL * - PLL1 & PLL2 => return VCO / 2 with Fpll_y_ck = FVCO / 2 * (DIVy + 1) * - PLL3 & PLL4 => return VCO with Fpll_y_ck = FVCO / (DIVy + 1) * => in all cases Fpll_y_ck = pll_get_fvco() / (DIVy + 1) */ static unsigned long stm32mp1_pll_get_fvco(const struct stm32mp1_clk_pll *pll) { unsigned long refclk, fvco; uint32_t cfgr1, fracr, divm, divn; uintptr_t rcc_base = stm32mp_rcc_base(); 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(pll); /* * With FRACV : * Fvco = Fck_ref * ((DIVN + 1) + FRACV / 2^13) / (DIVM + 1) * Without FRACV * Fvco = Fck_ref * ((DIVN + 1) / (DIVM + 1) */ if ((fracr & RCC_PLLNFRACR_FRACLE) != 0U) { uint32_t fracv = (fracr & RCC_PLLNFRACR_FRACV_MASK) >> RCC_PLLNFRACR_FRACV_SHIFT; unsigned long long numerator, denominator; numerator = (((unsigned long long)divn + 1U) << 13) + fracv; numerator = refclk * numerator; denominator = ((unsigned long long)divm + 1U) << 13; fvco = (unsigned long)(numerator / denominator); } else { fvco = (unsigned long)(refclk * (divn + 1U) / (divm + 1U)); } return fvco; } static unsigned long stm32mp1_read_pll_freq(enum stm32mp1_pll_id pll_id, enum stm32mp1_div_id div_id) { const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); unsigned long dfout; uint32_t cfgr2, divy; if (div_id >= _DIV_NB) { return 0; } cfgr2 = mmio_read_32(stm32mp_rcc_base() + pll->pllxcfgr2); divy = (cfgr2 >> pllncfgr2[div_id]) & RCC_PLLNCFGR2_DIVX_MASK; dfout = stm32mp1_pll_get_fvco(pll) / (divy + 1U); return dfout; } static unsigned long get_clock_rate(int p) { uint32_t reg, clkdiv; unsigned long clock = 0; uintptr_t rcc_base = stm32mp_rcc_base(); switch (p) { case _CK_MPU: /* MPU sub system */ reg = mmio_read_32(rcc_base + RCC_MPCKSELR); switch (reg & RCC_SELR_SRC_MASK) { case RCC_MPCKSELR_HSI: clock = stm32mp1_clk_get_fixed(_HSI); break; case RCC_MPCKSELR_HSE: clock = stm32mp1_clk_get_fixed(_HSE); break; case RCC_MPCKSELR_PLL: clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); break; case RCC_MPCKSELR_PLL_MPUDIV: clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); reg = mmio_read_32(rcc_base + RCC_MPCKDIVR); clkdiv = reg & RCC_MPUDIV_MASK; if (clkdiv != 0U) { clock /= stm32mp1_mpu_div[clkdiv]; } break; default: break; } break; /* AXI sub system */ case _ACLK: case _HCLK2: case _HCLK6: case _PCLK4: case _PCLK5: reg = mmio_read_32(rcc_base + RCC_ASSCKSELR); switch (reg & RCC_SELR_SRC_MASK) { case RCC_ASSCKSELR_HSI: clock = stm32mp1_clk_get_fixed(_HSI); break; case RCC_ASSCKSELR_HSE: clock = stm32mp1_clk_get_fixed(_HSE); break; case RCC_ASSCKSELR_PLL: clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); break; default: break; } /* System clock divider */ reg = mmio_read_32(rcc_base + RCC_AXIDIVR); clock /= stm32mp1_axi_div[reg & RCC_AXIDIV_MASK]; switch (p) { case _PCLK4: reg = mmio_read_32(rcc_base + RCC_APB4DIVR); clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; break; case _PCLK5: reg = mmio_read_32(rcc_base + RCC_APB5DIVR); clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; break; default: break; } break; /* MCU sub system */ case _CK_MCU: case _PCLK1: case _PCLK2: case _PCLK3: reg = mmio_read_32(rcc_base + RCC_MSSCKSELR); switch (reg & RCC_SELR_SRC_MASK) { case RCC_MSSCKSELR_HSI: clock = stm32mp1_clk_get_fixed(_HSI); break; case RCC_MSSCKSELR_HSE: clock = stm32mp1_clk_get_fixed(_HSE); break; case RCC_MSSCKSELR_CSI: clock = stm32mp1_clk_get_fixed(_CSI); break; case RCC_MSSCKSELR_PLL: clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); break; default: break; } /* MCU clock divider */ reg = mmio_read_32(rcc_base + RCC_MCUDIVR); clock >>= stm32mp1_mcu_div[reg & RCC_MCUDIV_MASK]; switch (p) { case _PCLK1: reg = mmio_read_32(rcc_base + RCC_APB1DIVR); clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; break; case _PCLK2: reg = mmio_read_32(rcc_base + RCC_APB2DIVR); clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; break; case _PCLK3: reg = mmio_read_32(rcc_base + RCC_APB3DIVR); clock >>= stm32mp1_apbx_div[reg & RCC_APBXDIV_MASK]; break; case _CK_MCU: default: break; } break; case _CK_PER: reg = mmio_read_32(rcc_base + RCC_CPERCKSELR); switch (reg & RCC_SELR_SRC_MASK) { case RCC_CPERCKSELR_HSI: clock = stm32mp1_clk_get_fixed(_HSI); break; case RCC_CPERCKSELR_HSE: clock = stm32mp1_clk_get_fixed(_HSE); break; case RCC_CPERCKSELR_CSI: clock = stm32mp1_clk_get_fixed(_CSI); break; default: break; } break; case _HSI: case _HSI_KER: clock = stm32mp1_clk_get_fixed(_HSI); break; case _CSI: case _CSI_KER: clock = stm32mp1_clk_get_fixed(_CSI); break; case _HSE: case _HSE_KER: clock = stm32mp1_clk_get_fixed(_HSE); break; case _HSE_KER_DIV2: clock = stm32mp1_clk_get_fixed(_HSE) >> 1; break; case _LSI: clock = stm32mp1_clk_get_fixed(_LSI); break; case _LSE: clock = stm32mp1_clk_get_fixed(_LSE); break; /* PLL */ case _PLL1_P: clock = stm32mp1_read_pll_freq(_PLL1, _DIV_P); break; case _PLL1_Q: clock = stm32mp1_read_pll_freq(_PLL1, _DIV_Q); break; case _PLL1_R: clock = stm32mp1_read_pll_freq(_PLL1, _DIV_R); break; case _PLL2_P: clock = stm32mp1_read_pll_freq(_PLL2, _DIV_P); break; case _PLL2_Q: clock = stm32mp1_read_pll_freq(_PLL2, _DIV_Q); break; case _PLL2_R: clock = stm32mp1_read_pll_freq(_PLL2, _DIV_R); break; case _PLL3_P: clock = stm32mp1_read_pll_freq(_PLL3, _DIV_P); break; case _PLL3_Q: clock = stm32mp1_read_pll_freq(_PLL3, _DIV_Q); break; case _PLL3_R: clock = stm32mp1_read_pll_freq(_PLL3, _DIV_R); break; case _PLL4_P: clock = stm32mp1_read_pll_freq(_PLL4, _DIV_P); break; case _PLL4_Q: clock = stm32mp1_read_pll_freq(_PLL4, _DIV_Q); break; case _PLL4_R: clock = stm32mp1_read_pll_freq(_PLL4, _DIV_R); break; /* Other */ case _USB_PHY_48: clock = USB_PHY_48_MHZ; break; default: break; } return clock; } 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 { mmio_setbits_32(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 { mmio_clrbits_32(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) { int i = stm32mp1_clk_get_gated_id(id); if (i < 0) { panic(); } return gate_refcounts[i]; } void __stm32mp1_clk_enable(unsigned long id, bool secure) { const struct stm32mp1_clk_gate *gate; int i = stm32mp1_clk_get_gated_id(id); unsigned int *refcnt; if (i < 0) { ERROR("Clock %d can't be enabled\n", (uint32_t)id); panic(); } gate = gate_ref(i); refcnt = &gate_refcounts[i]; stm32mp1_clk_lock(&refcount_lock); if (stm32mp_incr_shrefcnt(refcnt, secure) != 0) { __clk_enable(gate); } stm32mp1_clk_unlock(&refcount_lock); } void __stm32mp1_clk_disable(unsigned long id, bool secure) { const struct stm32mp1_clk_gate *gate; int i = stm32mp1_clk_get_gated_id(id); unsigned int *refcnt; if (i < 0) { ERROR("Clock %d can't be disabled\n", (uint32_t)id); panic(); } gate = gate_ref(i); refcnt = &gate_refcounts[i]; stm32mp1_clk_lock(&refcount_lock); if (stm32mp_decr_shrefcnt(refcnt, secure) != 0) { __clk_disable(gate); } stm32mp1_clk_unlock(&refcount_lock); } void stm32mp_clk_enable(unsigned long id) { __stm32mp1_clk_enable(id, true); } void stm32mp_clk_disable(unsigned long id) { __stm32mp1_clk_disable(id, true); } bool stm32mp_clk_is_enabled(unsigned long id) { 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; } return get_clock_rate(p); } static void stm32mp1_ls_osc_set(bool enable, uint32_t offset, uint32_t mask_on) { uintptr_t address = stm32mp_rcc_base() + offset; if (enable) { mmio_setbits_32(address, mask_on); } else { mmio_clrbits_32(address, mask_on); } } static void stm32mp1_hs_ocs_set(bool enable, uint32_t mask_on) { uint32_t offset = enable ? RCC_OCENSETR : RCC_OCENCLRR; uintptr_t address = stm32mp_rcc_base() + offset; mmio_write_32(address, mask_on); } static int stm32mp1_osc_wait(bool enable, uint32_t offset, uint32_t mask_rdy) { uint64_t timeout; uint32_t mask_test; uintptr_t address = stm32mp_rcc_base() + offset; if (enable) { mask_test = mask_rdy; } else { mask_test = 0; } timeout = timeout_init_us(OSCRDY_TIMEOUT); while ((mmio_read_32(address) & mask_rdy) != mask_test) { if (timeout_elapsed(timeout)) { ERROR("OSC %x @ %lx timeout for enable=%d : 0x%x\n", mask_rdy, address, enable, mmio_read_32(address)); return -ETIMEDOUT; } } return 0; } 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 || 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_base + RCC_BDCR) & RCC_BDCR_LSEDRV_MASK) >> RCC_BDCR_LSEDRV_SHIFT; while (value != lsedrv) { if (value > lsedrv) { value--; } else { value++; } mmio_clrsetbits_32(rcc_base + RCC_BDCR, RCC_BDCR_LSEDRV_MASK, value << RCC_BDCR_LSEDRV_SHIFT); } stm32mp1_ls_osc_set(true, RCC_BDCR, RCC_BDCR_LSEON); } static void stm32mp1_lse_wait(void) { if (stm32mp1_osc_wait(true, RCC_BDCR, RCC_BDCR_LSERDY) != 0) { VERBOSE("%s: failed\n", __func__); } } static void stm32mp1_lsi_set(bool enable) { 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(bool bypass, bool digbyp, bool css) { 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(true, RCC_OCENR_HSEON); if (stm32mp1_osc_wait(true, RCC_OCRDYR, RCC_OCRDYR_HSERDY) != 0) { VERBOSE("%s: failed\n", __func__); } if (css) { mmio_write_32(rcc_base + RCC_OCENSETR, RCC_OCENR_HSECSSON); } } static void stm32mp1_csi_set(bool enable) { 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(bool enable) { 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(uint8_t hsidiv) { uint64_t timeout; uintptr_t rcc_base = stm32mp_rcc_base(); uintptr_t address = rcc_base + RCC_OCRDYR; mmio_clrsetbits_32(rcc_base + RCC_HSICFGR, RCC_HSICFGR_HSIDIV_MASK, RCC_HSICFGR_HSIDIV_MASK & (uint32_t)hsidiv); timeout = timeout_init_us(HSIDIV_TIMEOUT); while ((mmio_read_32(address) & RCC_OCRDYR_HSIDIVRDY) == 0U) { if (timeout_elapsed(timeout)) { ERROR("HSIDIV failed @ 0x%lx: 0x%x\n", address, mmio_read_32(address)); return -ETIMEDOUT; } } return 0; } static int stm32mp1_hsidiv(unsigned long hsifreq) { uint8_t hsidiv; uint32_t hsidivfreq = MAX_HSI_HZ; for (hsidiv = 0; hsidiv < 4U; hsidiv++) { if (hsidivfreq == hsifreq) { break; } hsidivfreq /= 2U; } if (hsidiv == 4U) { ERROR("Invalid clk-hsi frequency\n"); return -1; } if (hsidiv != 0U) { return stm32mp1_set_hsidiv(hsidiv); } return 0; } 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(); uintptr_t pllxcr = rcc_base + pll->pllxcr; enum stm32mp1_plltype type = pll->plltype; uintptr_t clksrc_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(clksrc_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 = pll_ref(pll_id); uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; /* Preserve RCC_PLLNCR_SSCG_CTRL value */ mmio_clrsetbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | RCC_PLLNCR_DIVREN, RCC_PLLNCR_PLLON); } static int stm32mp1_pll_output(enum stm32mp1_pll_id pll_id, uint32_t output) { const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; uint64_t timeout = timeout_init_us(PLLRDY_TIMEOUT); /* Wait PLL lock */ while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) == 0U) { if (timeout_elapsed(timeout)) { ERROR("PLL%d start failed @ 0x%lx: 0x%x\n", pll_id, pllxcr, mmio_read_32(pllxcr)); return -ETIMEDOUT; } } /* Start the requested output */ mmio_setbits_32(pllxcr, output << RCC_PLLNCR_DIVEN_SHIFT); return 0; } static int stm32mp1_pll_stop(enum stm32mp1_pll_id pll_id) { const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); uintptr_t pllxcr = stm32mp_rcc_base() + pll->pllxcr; uint64_t timeout; /* Stop all output */ mmio_clrbits_32(pllxcr, RCC_PLLNCR_DIVPEN | RCC_PLLNCR_DIVQEN | RCC_PLLNCR_DIVREN); /* Stop PLL */ mmio_clrbits_32(pllxcr, RCC_PLLNCR_PLLON); timeout = timeout_init_us(PLLRDY_TIMEOUT); /* Wait PLL stopped */ while ((mmio_read_32(pllxcr) & RCC_PLLNCR_PLLRDY) != 0U) { if (timeout_elapsed(timeout)) { ERROR("PLL%d stop failed @ 0x%lx: 0x%x\n", pll_id, pllxcr, mmio_read_32(pllxcr)); return -ETIMEDOUT; } } return 0; } static void stm32mp1_pll_config_output(enum stm32mp1_pll_id pll_id, uint32_t *pllcfg) { const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); uintptr_t rcc_base = stm32mp_rcc_base(); uint32_t value; value = (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; mmio_write_32(rcc_base + pll->pllxcfgr2, value); } static int stm32mp1_pll_config(enum stm32mp1_pll_id pll_id, uint32_t *pllcfg, uint32_t fracv) { const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); uintptr_t rcc_base = stm32mp_rcc_base(); enum stm32mp1_plltype type = pll->plltype; unsigned long refclk; uint32_t ifrge = 0; uint32_t src, value; 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 -EINVAL; } 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; mmio_write_32(rcc_base + pll->pllxcfgr1, value); /* Fractional configuration */ value = 0; mmio_write_32(rcc_base + pll->pllxfracr, value); value = fracv << RCC_PLLNFRACR_FRACV_SHIFT; mmio_write_32(rcc_base + pll->pllxfracr, value); value |= RCC_PLLNFRACR_FRACLE; mmio_write_32(rcc_base + pll->pllxfracr, value); stm32mp1_pll_config_output(pll_id, pllcfg); return 0; } static void stm32mp1_pll_csg(enum stm32mp1_pll_id pll_id, uint32_t *csg) { const struct stm32mp1_clk_pll *pll = pll_ref(pll_id); uint32_t pllxcsg = 0; pllxcsg |= (csg[PLLCSG_MOD_PER] << RCC_PLLNCSGR_MOD_PER_SHIFT) & RCC_PLLNCSGR_MOD_PER_MASK; pllxcsg |= (csg[PLLCSG_INC_STEP] << RCC_PLLNCSGR_INC_STEP_SHIFT) & RCC_PLLNCSGR_INC_STEP_MASK; pllxcsg |= (csg[PLLCSG_SSCG_MODE] << RCC_PLLNCSGR_SSCG_MODE_SHIFT) & RCC_PLLNCSGR_SSCG_MODE_MASK; mmio_write_32(stm32mp_rcc_base() + pll->pllxcsgr, pllxcsg); mmio_setbits_32(stm32mp_rcc_base() + pll->pllxcr, RCC_PLLNCR_SSCG_CTRL); } static int stm32mp1_set_clksrc(unsigned int clksrc) { uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4); uint64_t timeout; mmio_clrsetbits_32(clksrc_address, RCC_SELR_SRC_MASK, clksrc & RCC_SELR_SRC_MASK); timeout = timeout_init_us(CLKSRC_TIMEOUT); while ((mmio_read_32(clksrc_address) & RCC_SELR_SRCRDY) == 0U) { if (timeout_elapsed(timeout)) { ERROR("CLKSRC %x start failed @ 0x%lx: 0x%x\n", clksrc, clksrc_address, mmio_read_32(clksrc_address)); return -ETIMEDOUT; } } return 0; } static int stm32mp1_set_clkdiv(unsigned int clkdiv, uintptr_t address) { uint64_t timeout; mmio_clrsetbits_32(address, RCC_DIVR_DIV_MASK, clkdiv & RCC_DIVR_DIV_MASK); timeout = timeout_init_us(CLKDIV_TIMEOUT); while ((mmio_read_32(address) & RCC_DIVR_DIVRDY) == 0U) { if (timeout_elapsed(timeout)) { ERROR("CLKDIV %x start failed @ 0x%lx: 0x%x\n", clkdiv, address, mmio_read_32(address)); return -ETIMEDOUT; } } return 0; } static void stm32mp1_mco_csg(uint32_t clksrc, uint32_t clkdiv) { uintptr_t clksrc_address = stm32mp_rcc_base() + (clksrc >> 4); /* * Binding clksrc : * bit15-4 offset * bit3: disable * bit2-0: MCOSEL[2:0] */ if ((clksrc & 0x8U) != 0U) { mmio_clrbits_32(clksrc_address, RCC_MCOCFG_MCOON); } else { mmio_clrsetbits_32(clksrc_address, RCC_MCOCFG_MCOSRC_MASK, clksrc & RCC_MCOCFG_MCOSRC_MASK); mmio_clrsetbits_32(clksrc_address, RCC_MCOCFG_MCODIV_MASK, clkdiv << RCC_MCOCFG_MCODIV_SHIFT); mmio_setbits_32(clksrc_address, RCC_MCOCFG_MCOON); } } static void stm32mp1_set_rtcsrc(unsigned int clksrc, bool lse_css) { uintptr_t address = stm32mp_rcc_base() + RCC_BDCR; if (((mmio_read_32(address) & RCC_BDCR_RTCCKEN) == 0U) || (clksrc != (uint32_t)CLK_RTC_DISABLED)) { mmio_clrsetbits_32(address, RCC_BDCR_RTCSRC_MASK, clksrc << RCC_BDCR_RTCSRC_SHIFT); mmio_setbits_32(address, RCC_BDCR_RTCCKEN); } if (lse_css) { mmio_setbits_32(address, RCC_BDCR_LSECSSON); } } static void stm32mp1_stgen_config(void) { uintptr_t stgen; uint32_t cntfid0; unsigned long rate; unsigned long long counter; stgen = fdt_get_stgen_base(); cntfid0 = mmio_read_32(stgen + CNTFID_OFF); rate = get_clock_rate(stm32mp1_clk_get_parent(STGEN_K)); 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); 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) { 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; mmio_clrbits_32(stgen + CNTCR_OFF, CNTCR_EN); mmio_write_32(stgen + CNTCVL_OFF, (uint32_t)cnt); mmio_write_32(stgen + CNTCVU_OFF, (uint32_t)(cnt >> 32)); mmio_setbits_32(stgen + CNTCR_OFF, CNTCR_EN); } static void stm32mp1_pkcs_config(uint32_t pkcs) { uintptr_t address = stm32mp_rcc_base() + ((pkcs >> 4) & 0xFFFU); uint32_t value = pkcs & 0xFU; uint32_t mask = 0xFU; if ((pkcs & BIT(31)) != 0U) { mask <<= 4; value <<= 4; } mmio_clrsetbits_32(address, mask, value); } int stm32mp1_clk_init(void) { uintptr_t rcc_base = stm32mp_rcc_base(); unsigned int clksrc[CLKSRC_NB]; unsigned int clkdiv[CLKDIV_NB]; unsigned int pllcfg[_PLL_NB][PLLCFG_NB]; int plloff[_PLL_NB]; int ret, len; enum stm32mp1_pll_id i; bool lse_css = false; bool pll3_preserve = false; bool pll4_preserve = false; bool pll4_bootrom = false; const fdt32_t *pkcs_cell; /* Check status field to disable security */ if (!fdt_get_rcc_secure_status()) { mmio_write_32(rcc_base + RCC_TZCR, 0); } ret = fdt_rcc_read_uint32_array("st,clksrc", clksrc, (uint32_t)CLKSRC_NB); if (ret < 0) { return -FDT_ERR_NOTFOUND; } ret = fdt_rcc_read_uint32_array("st,clkdiv", clkdiv, (uint32_t)CLKDIV_NB); if (ret < 0) { return -FDT_ERR_NOTFOUND; } for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { char name[12]; snprintf(name, sizeof(name), "st,pll@%d", i); plloff[i] = fdt_rcc_subnode_offset(name); if (!fdt_check_node(plloff[i])) { continue; } ret = fdt_read_uint32_array(plloff[i], "cfg", pllcfg[i], (int)PLLCFG_NB); if (ret < 0) { return -FDT_ERR_NOTFOUND; } } stm32mp1_mco_csg(clksrc[CLKSRC_MCO1], clkdiv[CLKDIV_MCO1]); stm32mp1_mco_csg(clksrc[CLKSRC_MCO2], clkdiv[CLKDIV_MCO2]); /* * Switch ON oscillator found in device-tree. * Note: HSI already ON after BootROM stage. */ if (stm32mp1_osc[_LSI] != 0U) { stm32mp1_lsi_set(true); } if (stm32mp1_osc[_LSE] != 0U) { bool bypass, digbyp; uint32_t lsedrv; bypass = fdt_osc_read_bool(_LSE, "st,bypass"); digbyp = fdt_osc_read_bool(_LSE, "st,digbypass"); lse_css = fdt_osc_read_bool(_LSE, "st,css"); lsedrv = fdt_osc_read_uint32_default(_LSE, "st,drive", LSEDRV_MEDIUM_HIGH); stm32mp1_lse_enable(bypass, digbyp, lsedrv); } if (stm32mp1_osc[_HSE] != 0U) { bool bypass, digbyp, css; bypass = fdt_osc_read_bool(_HSE, "st,bypass"); digbyp = fdt_osc_read_bool(_HSE, "st,digbypass"); css = fdt_osc_read_bool(_HSE, "st,css"); stm32mp1_hse_enable(bypass, digbyp, css); } /* * CSI is mandatory for automatic I/O compensation (SYSCFG_CMPCR) * => switch on CSI even if node is not present in device tree */ stm32mp1_csi_set(true); /* Come back to HSI */ ret = stm32mp1_set_clksrc(CLK_MPU_HSI); if (ret != 0) { return ret; } ret = stm32mp1_set_clksrc(CLK_AXI_HSI); if (ret != 0) { return ret; } 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]); } for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { if (((i == _PLL3) && pll3_preserve) || ((i == _PLL4) && pll4_preserve)) { continue; } ret = stm32mp1_pll_stop(i); if (ret != 0) { return ret; } } /* Configure HSIDIV */ if (stm32mp1_osc[_HSI] != 0U) { ret = stm32mp1_hsidiv(stm32mp1_osc[_HSI]); if (ret != 0) { return ret; } stm32mp1_stgen_config(); } /* Select DIV */ /* No ready bit when MPUSRC != CLK_MPU_PLL1P_DIV, MPUDIV is disabled */ mmio_write_32(rcc_base + RCC_MPCKDIVR, clkdiv[CLKDIV_MPU] & RCC_DIVR_DIV_MASK); 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_APB5], rcc_base + RCC_APB5DIVR); if (ret != 0) { return ret; } ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_MCU], rcc_base + RCC_MCUDIVR); if (ret != 0) { return ret; } ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB1], rcc_base + RCC_APB1DIVR); if (ret != 0) { return ret; } ret = stm32mp1_set_clkdiv(clkdiv[CLKDIV_APB2], rcc_base + RCC_APB2DIVR); if (ret != 0) { return ret; } 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_base + RCC_RTCDIVR, clkdiv[CLKDIV_RTC] & RCC_DIVR_DIV_MASK); /* Configure PLLs source */ ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL12]); if (ret != 0) { return ret; } if (!pll3_preserve) { ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL3]); if (ret != 0) { return ret; } } if (!pll4_preserve) { ret = stm32mp1_set_clksrc(clksrc[CLKSRC_PLL4]); if (ret != 0) { return ret; } } /* Configure and start PLLs */ for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { uint32_t fracv; uint32_t csg[PLLCSG_NB]; if (((i == _PLL3) && pll3_preserve) || ((i == _PLL4) && pll4_preserve && !pll4_bootrom)) { continue; } if (!fdt_check_node(plloff[i])) { 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(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(i, csg); } else if (ret != -FDT_ERR_NOTFOUND) { return ret; } stm32mp1_pll_start(i); } /* Wait and start PLLs ouptut when ready */ for (i = (enum stm32mp1_pll_id)0; i < _PLL_NB; i++) { if (!fdt_check_node(plloff[i])) { continue; } ret = stm32mp1_pll_output(i, pllcfg[i][PLLCFG_O]); if (ret != 0) { return ret; } } /* Wait LSE ready before to use it */ if (stm32mp1_osc[_LSE] != 0U) { stm32mp1_lse_wait(); } /* Configure with expected clock source */ ret = stm32mp1_set_clksrc(clksrc[CLKSRC_MPU]); if (ret != 0) { return ret; } ret = stm32mp1_set_clksrc(clksrc[CLKSRC_AXI]); if (ret != 0) { return ret; } 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; for (j = 0; j < ((uint32_t)len / sizeof(uint32_t)); j++) { uint32_t pkcs = fdt32_to_cpu(pkcs_cell[j]); if (pkcs == (uint32_t)CLK_CKPER_DISABLED) { ckper_disabled = true; continue; } stm32mp1_pkcs_config(pkcs); } /* * CKPER is source for some peripheral clocks * (FMC-NAND / QPSI-NOR) and switching source is allowed * only if previous clock is still ON * => deactivated CKPER only after switching clock */ if (ckper_disabled) { stm32mp1_pkcs_config(CLK_CKPER_DISABLED); } } /* Switch OFF HSI if not found in device-tree */ if (stm32mp1_osc[_HSI] == 0U) { stm32mp1_hsi_set(false); } stm32mp1_stgen_config(); /* Software Self-Refresh mode (SSR) during DDR initilialization */ mmio_clrsetbits_32(rcc_base + RCC_DDRITFCR, RCC_DDRITFCR_DDRCKMOD_MASK, RCC_DDRITFCR_DDRCKMOD_SSR << RCC_DDRITFCR_DDRCKMOD_SHIFT); return 0; } static void stm32mp1_osc_clk_init(const char *name, enum stm32mp_osc_id index) { uint32_t frequency; if (fdt_osc_read_freq(name, &frequency) == 0) { stm32mp1_osc[index] = frequency; } } static void stm32mp1_osc_init(void) { 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], i); } } static void sync_earlyboot_clocks_state(void) { if (!stm32mp_is_single_core()) { stm32mp1_clk_enable_secure(RTCAPB); } } int stm32mp1_clk_probe(void) { stm32mp1_osc_init(); sync_earlyboot_clocks_state(); return 0; } trusted-firmware-a-2.2/drivers/st/clk/stm32mp_clkfunc.c000066400000000000000000000150741355360272700231530ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #define DT_STGEN_COMPAT "st,stm32-stgen" /* * Get the frequency of an oscillator from its name in device tree. * @param name: oscillator name * @param freq: stores the frequency of the oscillator * @return: 0 on success, and a negative FDT/ERRNO error code on failure. */ int fdt_osc_read_freq(const char *name, uint32_t *freq) { int node, subnode; void *fdt; if (fdt_get_address(&fdt) == 0) { return -ENOENT; } node = fdt_path_offset(fdt, "/clocks"); if (node < 0) { return -FDT_ERR_NOTFOUND; } fdt_for_each_subnode(subnode, fdt, node) { const char *cchar; int ret; cchar = fdt_get_name(fdt, subnode, &ret); if (cchar == NULL) { return ret; } if (strncmp(cchar, name, (size_t)ret) == 0) { const fdt32_t *cuint; cuint = fdt_getprop(fdt, subnode, "clock-frequency", &ret); if (cuint == NULL) { return ret; } *freq = fdt32_to_cpu(*cuint); return 0; } } /* Oscillator not found, freq=0 */ *freq = 0; return 0; } /* * Check the presence of an oscillator property from its id. * @param osc_id: oscillator ID * @param prop_name: property name * @return: true/false regarding search result. */ bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name) { int node, subnode; void *fdt; if (fdt_get_address(&fdt) == 0) { return false; } if (osc_id >= NB_OSC) { return false; } node = fdt_path_offset(fdt, "/clocks"); if (node < 0) { return false; } fdt_for_each_subnode(subnode, fdt, node) { const char *cchar; int ret; cchar = fdt_get_name(fdt, subnode, &ret); if (cchar == NULL) { return false; } if (strncmp(cchar, stm32mp_osc_node_label[osc_id], (size_t)ret) != 0) { continue; } if (fdt_getprop(fdt, subnode, prop_name, NULL) != NULL) { return true; } } return false; } /* * Get the value of a oscillator property from its ID. * @param osc_id: oscillator ID * @param prop_name: property name * @param dflt_value: default value * @return oscillator value on success, default value if property not found. */ uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id, const char *prop_name, uint32_t dflt_value) { int node, subnode; void *fdt; if (fdt_get_address(&fdt) == 0) { return dflt_value; } if (osc_id >= NB_OSC) { return dflt_value; } node = fdt_path_offset(fdt, "/clocks"); if (node < 0) { return dflt_value; } fdt_for_each_subnode(subnode, fdt, node) { const char *cchar; int ret; cchar = fdt_get_name(fdt, subnode, &ret); if (cchar == NULL) { return dflt_value; } if (strncmp(cchar, stm32mp_osc_node_label[osc_id], (size_t)ret) != 0) { continue; } return fdt_read_uint32_default(subnode, prop_name, dflt_value); } return dflt_value; } /* * Get the RCC node offset from the device tree * @param fdt: Device tree reference * @return: Node offset or a negative value on error */ int fdt_get_rcc_node(void *fdt) { return fdt_node_offset_by_compatible(fdt, -1, DT_RCC_CLK_COMPAT); } /* * Get the RCC base address from the device tree * @return: RCC address or 0 on error */ uint32_t fdt_rcc_read_addr(void) { int node; void *fdt; const fdt32_t *cuint; if (fdt_get_address(&fdt) == 0) { return 0; } node = fdt_get_rcc_node(fdt); if (node < 0) { return 0; } cuint = fdt_getprop(fdt, node, "reg", NULL); if (cuint == NULL) { return 0; } return fdt32_to_cpu(*cuint); } /* * Read a series of parameters in rcc-clk section in device tree * @param prop_name: Name of the RCC property to be read * @param array: the array to store the property parameters * @param count: number of parameters to be read * @return: 0 on succes or a negative value on error */ 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); } /* * Get the subnode offset in rcc-clk section from its name in device tree * @param name: name of the RCC property * @return: 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; } /* * Get the pointer to a rcc-clk property from its name. * @param name: name of the RCC property * @param lenp: stores the length of the property. * @return: pointer to the property 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; } /* * Get the secure status for rcc node in device tree. * @return: 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); } /* * Get the stgen base address. * @return: address of stgen 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); } /* * Get the clock ID of the given node in device tree. * @param node: node offset * @return: Clock 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); } trusted-firmware-a-2.2/drivers/st/crypto/000077500000000000000000000000001355360272700205355ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/st/crypto/stm32_hash.c000066400000000000000000000147131355360272700226620ustar00rootroot00000000000000/* * Copyright (c) 2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define DT_HASH_COMPAT "st,stm32f756-hash" #define HASH_CR 0x00U #define HASH_DIN 0x04U #define HASH_STR 0x08U #define HASH_SR 0x24U #define HASH_HREG(x) (0x310U + ((x) * 0x04U)) /* Control Register */ #define HASH_CR_INIT BIT(2) #define HASH_CR_DATATYPE_SHIFT U(4) #define HASH_CR_ALGO_SHA1 0x0U #define HASH_CR_ALGO_MD5 BIT(7) #define HASH_CR_ALGO_SHA224 BIT(18) #define HASH_CR_ALGO_SHA256 (BIT(18) | BIT(7)) /* Status Flags */ #define HASH_SR_DCIS BIT(1) #define HASH_SR_BUSY BIT(3) /* STR Register */ #define HASH_STR_NBLW_MASK GENMASK(4, 0) #define HASH_STR_DCAL BIT(8) #define MD5_DIGEST_SIZE 16U #define SHA1_DIGEST_SIZE 20U #define SHA224_DIGEST_SIZE 28U #define SHA256_DIGEST_SIZE 32U #define HASH_TIMEOUT_US 10000U enum stm32_hash_data_format { HASH_DATA_32_BITS, HASH_DATA_16_BITS, HASH_DATA_8_BITS, HASH_DATA_1_BIT }; struct stm32_hash_instance { uintptr_t base; unsigned int clock; size_t digest_size; }; struct stm32_hash_remain { uint32_t buffer; size_t length; }; /* Expect a single HASH peripheral */ static struct stm32_hash_instance stm32_hash; static struct stm32_hash_remain stm32_remain; static uintptr_t hash_base(void) { return stm32_hash.base; } static int hash_wait_busy(void) { uint64_t timeout = timeout_init_us(HASH_TIMEOUT_US); while ((mmio_read_32(hash_base() + HASH_SR) & HASH_SR_BUSY) != 0U) { if (timeout_elapsed(timeout)) { ERROR("%s: busy timeout\n", __func__); return -ETIMEDOUT; } } return 0; } static int hash_wait_computation(void) { uint64_t timeout = timeout_init_us(HASH_TIMEOUT_US); while ((mmio_read_32(hash_base() + HASH_SR) & HASH_SR_DCIS) == 0U) { if (timeout_elapsed(timeout)) { ERROR("%s: busy timeout\n", __func__); return -ETIMEDOUT; } } return 0; } static int hash_write_data(uint32_t data) { int ret; ret = hash_wait_busy(); if (ret != 0) { return ret; } mmio_write_32(hash_base() + HASH_DIN, data); return 0; } static void hash_hw_init(enum stm32_hash_algo_mode mode) { uint32_t reg; reg = HASH_CR_INIT | (HASH_DATA_8_BITS << HASH_CR_DATATYPE_SHIFT); switch (mode) { case HASH_MD5SUM: reg |= HASH_CR_ALGO_MD5; stm32_hash.digest_size = MD5_DIGEST_SIZE; break; case HASH_SHA1: reg |= HASH_CR_ALGO_SHA1; stm32_hash.digest_size = SHA1_DIGEST_SIZE; break; case HASH_SHA224: reg |= HASH_CR_ALGO_SHA224; stm32_hash.digest_size = SHA224_DIGEST_SIZE; break; /* Default selected algo is SHA256 */ case HASH_SHA256: default: reg |= HASH_CR_ALGO_SHA256; stm32_hash.digest_size = SHA256_DIGEST_SIZE; break; } mmio_write_32(hash_base() + HASH_CR, reg); } static int hash_get_digest(uint8_t *digest) { int ret; uint32_t i; uint32_t dsg; ret = hash_wait_computation(); if (ret != 0) { return ret; } for (i = 0U; i < (stm32_hash.digest_size / sizeof(uint32_t)); i++) { dsg = __builtin_bswap32(mmio_read_32(hash_base() + HASH_HREG(i))); memcpy(digest + (i * sizeof(uint32_t)), &dsg, sizeof(uint32_t)); } #if defined(IMAGE_BL2) /* * Clean hardware context as HASH could be used later * by non-secure software */ hash_hw_init(HASH_SHA256); #endif return 0; } int stm32_hash_update(const uint8_t *buffer, size_t length) { size_t remain_length = length; int ret = 0; if ((length == 0U) || (buffer == NULL)) { return 0; } stm32mp_clk_enable(stm32_hash.clock); if (stm32_remain.length != 0U) { uint32_t copysize; copysize = MIN((sizeof(uint32_t) - stm32_remain.length), length); memcpy(((uint8_t *)&stm32_remain.buffer) + stm32_remain.length, buffer, copysize); remain_length -= copysize; buffer += copysize; if (stm32_remain.length == sizeof(uint32_t)) { ret = hash_write_data(stm32_remain.buffer); if (ret != 0) { goto exit; } zeromem(&stm32_remain, sizeof(stm32_remain)); } } while (remain_length / sizeof(uint32_t) != 0U) { uint32_t tmp_buf; memcpy(&tmp_buf, buffer, sizeof(uint32_t)); ret = hash_write_data(tmp_buf); if (ret != 0) { goto exit; } buffer += sizeof(uint32_t); remain_length -= sizeof(uint32_t); } if (remain_length != 0U) { assert(stm32_remain.length == 0U); memcpy((uint8_t *)&stm32_remain.buffer, buffer, remain_length); stm32_remain.length = remain_length; } exit: stm32mp_clk_disable(stm32_hash.clock); return ret; } int stm32_hash_final(uint8_t *digest) { int ret; stm32mp_clk_enable(stm32_hash.clock); if (stm32_remain.length != 0U) { ret = hash_write_data(stm32_remain.buffer); if (ret != 0) { stm32mp_clk_disable(stm32_hash.clock); return ret; } mmio_clrsetbits_32(hash_base() + HASH_STR, HASH_STR_NBLW_MASK, 8U * stm32_remain.length); zeromem(&stm32_remain, sizeof(stm32_remain)); } mmio_setbits_32(hash_base() + HASH_STR, HASH_STR_DCAL); ret = hash_get_digest(digest); stm32mp_clk_disable(stm32_hash.clock); return ret; } int stm32_hash_final_update(const uint8_t *buffer, uint32_t length, uint8_t *digest) { int ret; ret = stm32_hash_update(buffer, length); if (ret != 0) { return ret; } return stm32_hash_final(digest); } void stm32_hash_init(enum stm32_hash_algo_mode mode) { stm32mp_clk_enable(stm32_hash.clock); hash_hw_init(mode); stm32mp_clk_disable(stm32_hash.clock); zeromem(&stm32_remain, sizeof(stm32_remain)); } int stm32_hash_register(void) { struct dt_node_info hash_info; int node; for (node = dt_get_node(&hash_info, -1, DT_HASH_COMPAT); node != -FDT_ERR_NOTFOUND; node = dt_get_node(&hash_info, node, DT_HASH_COMPAT)) { #if defined(IMAGE_BL2) if (hash_info.status != DT_DISABLED) { break; } #else if (hash_info.status == DT_SECURE) { break; } #endif } if (node == -FDT_ERR_NOTFOUND) { return -ENODEV; } if (hash_info.clock < 0) { return -EINVAL; } stm32_hash.base = hash_info.base; stm32_hash.clock = hash_info.clock; stm32mp_clk_enable(stm32_hash.clock); if (hash_info.reset >= 0) { stm32mp_reset_assert((unsigned long)hash_info.reset); udelay(20); stm32mp_reset_deassert((unsigned long)hash_info.reset); } stm32mp_clk_disable(stm32_hash.clock); return 0; } trusted-firmware-a-2.2/drivers/st/ddr/000077500000000000000000000000001355360272700177665ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/st/ddr/stm32mp1_ddr.c000066400000000000000000000622731355360272700223630ustar00rootroot00000000000000/* * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct reg_desc { const char *name; uint16_t offset; /* Offset for base address */ uint8_t par_offset; /* Offset for parameter array */ }; #define INVALID_OFFSET 0xFFU #define TIMEOUT_US_1S 1000000U #define DDRCTL_REG(x, y) \ { \ .name = #x, \ .offset = offsetof(struct stm32mp1_ddrctl, x), \ .par_offset = offsetof(struct y, x) \ } #define DDRPHY_REG(x, y) \ { \ .name = #x, \ .offset = offsetof(struct stm32mp1_ddrphy, x), \ .par_offset = offsetof(struct y, x) \ } #define DDRCTL_REG_REG(x) DDRCTL_REG(x, stm32mp1_ddrctrl_reg) static const struct reg_desc ddr_reg[] = { DDRCTL_REG_REG(mstr), DDRCTL_REG_REG(mrctrl0), DDRCTL_REG_REG(mrctrl1), DDRCTL_REG_REG(derateen), DDRCTL_REG_REG(derateint), DDRCTL_REG_REG(pwrctl), DDRCTL_REG_REG(pwrtmg), DDRCTL_REG_REG(hwlpctl), DDRCTL_REG_REG(rfshctl0), DDRCTL_REG_REG(rfshctl3), DDRCTL_REG_REG(crcparctl0), DDRCTL_REG_REG(zqctl0), DDRCTL_REG_REG(dfitmg0), DDRCTL_REG_REG(dfitmg1), DDRCTL_REG_REG(dfilpcfg0), DDRCTL_REG_REG(dfiupd0), DDRCTL_REG_REG(dfiupd1), DDRCTL_REG_REG(dfiupd2), DDRCTL_REG_REG(dfiphymstr), DDRCTL_REG_REG(odtmap), DDRCTL_REG_REG(dbg0), DDRCTL_REG_REG(dbg1), DDRCTL_REG_REG(dbgcmd), DDRCTL_REG_REG(poisoncfg), DDRCTL_REG_REG(pccfg), }; #define DDRCTL_REG_TIMING(x) DDRCTL_REG(x, stm32mp1_ddrctrl_timing) static const struct reg_desc ddr_timing[] = { DDRCTL_REG_TIMING(rfshtmg), DDRCTL_REG_TIMING(dramtmg0), DDRCTL_REG_TIMING(dramtmg1), DDRCTL_REG_TIMING(dramtmg2), DDRCTL_REG_TIMING(dramtmg3), DDRCTL_REG_TIMING(dramtmg4), DDRCTL_REG_TIMING(dramtmg5), DDRCTL_REG_TIMING(dramtmg6), DDRCTL_REG_TIMING(dramtmg7), DDRCTL_REG_TIMING(dramtmg8), DDRCTL_REG_TIMING(dramtmg14), DDRCTL_REG_TIMING(odtcfg), }; #define DDRCTL_REG_MAP(x) DDRCTL_REG(x, stm32mp1_ddrctrl_map) static const struct reg_desc ddr_map[] = { DDRCTL_REG_MAP(addrmap1), DDRCTL_REG_MAP(addrmap2), DDRCTL_REG_MAP(addrmap3), DDRCTL_REG_MAP(addrmap4), DDRCTL_REG_MAP(addrmap5), DDRCTL_REG_MAP(addrmap6), DDRCTL_REG_MAP(addrmap9), DDRCTL_REG_MAP(addrmap10), DDRCTL_REG_MAP(addrmap11), }; #define DDRCTL_REG_PERF(x) DDRCTL_REG(x, stm32mp1_ddrctrl_perf) static const struct reg_desc ddr_perf[] = { DDRCTL_REG_PERF(sched), DDRCTL_REG_PERF(sched1), DDRCTL_REG_PERF(perfhpr1), DDRCTL_REG_PERF(perflpr1), DDRCTL_REG_PERF(perfwr1), DDRCTL_REG_PERF(pcfgr_0), DDRCTL_REG_PERF(pcfgw_0), DDRCTL_REG_PERF(pcfgqos0_0), DDRCTL_REG_PERF(pcfgqos1_0), DDRCTL_REG_PERF(pcfgwqos0_0), DDRCTL_REG_PERF(pcfgwqos1_0), DDRCTL_REG_PERF(pcfgr_1), DDRCTL_REG_PERF(pcfgw_1), DDRCTL_REG_PERF(pcfgqos0_1), DDRCTL_REG_PERF(pcfgqos1_1), DDRCTL_REG_PERF(pcfgwqos0_1), DDRCTL_REG_PERF(pcfgwqos1_1), }; #define DDRPHY_REG_REG(x) DDRPHY_REG(x, stm32mp1_ddrphy_reg) static const struct reg_desc ddrphy_reg[] = { DDRPHY_REG_REG(pgcr), DDRPHY_REG_REG(aciocr), DDRPHY_REG_REG(dxccr), DDRPHY_REG_REG(dsgcr), DDRPHY_REG_REG(dcr), DDRPHY_REG_REG(odtcr), DDRPHY_REG_REG(zq0cr1), DDRPHY_REG_REG(dx0gcr), DDRPHY_REG_REG(dx1gcr), DDRPHY_REG_REG(dx2gcr), DDRPHY_REG_REG(dx3gcr), }; #define DDRPHY_REG_TIMING(x) DDRPHY_REG(x, stm32mp1_ddrphy_timing) static const struct reg_desc ddrphy_timing[] = { DDRPHY_REG_TIMING(ptr0), DDRPHY_REG_TIMING(ptr1), DDRPHY_REG_TIMING(ptr2), DDRPHY_REG_TIMING(dtpr0), DDRPHY_REG_TIMING(dtpr1), DDRPHY_REG_TIMING(dtpr2), DDRPHY_REG_TIMING(mr0), DDRPHY_REG_TIMING(mr1), DDRPHY_REG_TIMING(mr2), DDRPHY_REG_TIMING(mr3), }; #define DDRPHY_REG_CAL(x) DDRPHY_REG(x, stm32mp1_ddrphy_cal) static const struct reg_desc ddrphy_cal[] = { DDRPHY_REG_CAL(dx0dllcr), DDRPHY_REG_CAL(dx0dqtr), DDRPHY_REG_CAL(dx0dqstr), DDRPHY_REG_CAL(dx1dllcr), DDRPHY_REG_CAL(dx1dqtr), DDRPHY_REG_CAL(dx1dqstr), DDRPHY_REG_CAL(dx2dllcr), DDRPHY_REG_CAL(dx2dqtr), DDRPHY_REG_CAL(dx2dqstr), DDRPHY_REG_CAL(dx3dllcr), DDRPHY_REG_CAL(dx3dqtr), DDRPHY_REG_CAL(dx3dqstr), }; #define DDR_REG_DYN(x) \ { \ .name = #x, \ .offset = offsetof(struct stm32mp1_ddrctl, x), \ .par_offset = INVALID_OFFSET \ } static const struct reg_desc ddr_dyn[] = { DDR_REG_DYN(stat), DDR_REG_DYN(init0), DDR_REG_DYN(dfimisc), DDR_REG_DYN(dfistat), DDR_REG_DYN(swctl), DDR_REG_DYN(swstat), DDR_REG_DYN(pctrl_0), DDR_REG_DYN(pctrl_1), }; #define DDRPHY_REG_DYN(x) \ { \ .name = #x, \ .offset = offsetof(struct stm32mp1_ddrphy, x), \ .par_offset = INVALID_OFFSET \ } static const struct reg_desc ddrphy_dyn[] = { DDRPHY_REG_DYN(pir), DDRPHY_REG_DYN(pgsr), }; enum reg_type { REG_REG, REG_TIMING, REG_PERF, REG_MAP, REGPHY_REG, REGPHY_TIMING, REGPHY_CAL, /* * Dynamic registers => managed in driver or not changed, * can be dumped in interactive mode. */ REG_DYN, REGPHY_DYN, REG_TYPE_NB }; enum base_type { DDR_BASE, DDRPHY_BASE, NONE_BASE }; struct ddr_reg_info { const char *name; const struct reg_desc *desc; uint8_t size; enum base_type base; }; static const struct ddr_reg_info ddr_registers[REG_TYPE_NB] = { [REG_REG] = { .name = "static", .desc = ddr_reg, .size = ARRAY_SIZE(ddr_reg), .base = DDR_BASE }, [REG_TIMING] = { .name = "timing", .desc = ddr_timing, .size = ARRAY_SIZE(ddr_timing), .base = DDR_BASE }, [REG_PERF] = { .name = "perf", .desc = ddr_perf, .size = ARRAY_SIZE(ddr_perf), .base = DDR_BASE }, [REG_MAP] = { .name = "map", .desc = ddr_map, .size = ARRAY_SIZE(ddr_map), .base = DDR_BASE }, [REGPHY_REG] = { .name = "static", .desc = ddrphy_reg, .size = ARRAY_SIZE(ddrphy_reg), .base = DDRPHY_BASE }, [REGPHY_TIMING] = { .name = "timing", .desc = ddrphy_timing, .size = ARRAY_SIZE(ddrphy_timing), .base = DDRPHY_BASE }, [REGPHY_CAL] = { .name = "cal", .desc = ddrphy_cal, .size = ARRAY_SIZE(ddrphy_cal), .base = DDRPHY_BASE }, [REG_DYN] = { .name = "dyn", .desc = ddr_dyn, .size = ARRAY_SIZE(ddr_dyn), .base = DDR_BASE }, [REGPHY_DYN] = { .name = "dyn", .desc = ddrphy_dyn, .size = ARRAY_SIZE(ddrphy_dyn), .base = DDRPHY_BASE }, }; static uintptr_t get_base_addr(const struct ddr_info *priv, enum base_type base) { if (base == DDRPHY_BASE) { return (uintptr_t)priv->phy; } else { return (uintptr_t)priv->ctl; } } static void set_reg(const struct ddr_info *priv, enum reg_type type, const void *param) { unsigned int i; unsigned int value; enum base_type base = ddr_registers[type].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++) { 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 *)((uintptr_t)param + desc[i].par_offset)); mmio_write_32(ptr, value); } } } static void stm32mp1_ddrphy_idone_wait(struct stm32mp1_ddrphy *phy) { uint32_t pgsr; int error = 0; uint64_t timeout = timeout_init_us(TIMEOUT_US_1S); do { pgsr = mmio_read_32((uintptr_t)&phy->pgsr); VERBOSE(" > [0x%lx] pgsr = 0x%x &\n", (uintptr_t)&phy->pgsr, pgsr); if (timeout_elapsed(timeout)) { panic(); } if ((pgsr & DDRPHYC_PGSR_DTERR) != 0U) { VERBOSE("DQS Gate Trainig Error\n"); error++; } if ((pgsr & DDRPHYC_PGSR_DTIERR) != 0U) { VERBOSE("DQS Gate Trainig Intermittent Error\n"); error++; } if ((pgsr & DDRPHYC_PGSR_DFTERR) != 0U) { VERBOSE("DQS Drift Error\n"); error++; } if ((pgsr & DDRPHYC_PGSR_RVERR) != 0U) { VERBOSE("Read Valid Training Error\n"); error++; } if ((pgsr & DDRPHYC_PGSR_RVEIRR) != 0U) { VERBOSE("Read Valid Training Intermittent Error\n"); error++; } } while (((pgsr & DDRPHYC_PGSR_IDONE) == 0U) && (error == 0)); 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((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); /* Wait DRAM initialization and Gate Training Evaluation complete */ stm32mp1_ddrphy_idone_wait(phy); } /* Start quasi dynamic register update */ static void stm32mp1_start_sw_done(struct stm32mp1_ddrctl *ctl) { 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) { uint64_t timeout; uint32_t swstat; 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)); timeout = timeout_init_us(TIMEOUT_US_1S); do { swstat = mmio_read_32((uintptr_t)&ctl->swstat); VERBOSE("[0x%lx] swstat = 0x%x ", (uintptr_t)&ctl->swstat, swstat); if (timeout_elapsed(timeout)) { panic(); } } while ((swstat & DDRCTRL_SWSTAT_SW_DONE_ACK) == 0U); 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) { uint64_t timeout; uint32_t stat; int break_loop = 0; timeout = timeout_init_us(TIMEOUT_US_1S); for ( ; ; ) { 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%lx] stat = 0x%x\n", (uintptr_t)&priv->ctl->stat, stat); if (timeout_elapsed(timeout)) { panic(); } if (mode == DDRCTRL_STAT_OPERATING_MODE_SR) { /* * Self-refresh due to software * => checking also STAT.selfref_type. */ if ((operating_mode == DDRCTRL_STAT_OPERATING_MODE_SR) && (selref_type == DDRCTRL_STAT_SELFREF_TYPE_SR)) { break_loop = 1; } } else if (operating_mode == mode) { break_loop = 1; } else if ((mode == DDRCTRL_STAT_OPERATING_MODE_NORMAL) && (operating_mode == DDRCTRL_STAT_OPERATING_MODE_SR) && (selref_type == DDRCTRL_STAT_SELFREF_TYPE_ASR)) { /* Normal mode: handle also automatic self refresh */ break_loop = 1; } if (break_loop == 1) { break; } } VERBOSE("[0x%lx] stat = 0x%x\n", (uintptr_t)&priv->ctl->stat, stat); } /* Mode Register Writes (MRW or MRS) */ static void stm32mp1_mode_register_write(struct ddr_info *priv, uint8_t addr, uint32_t data) { uint32_t mrctrl0; VERBOSE("MRS: %d = %x\n", addr, data); /* * 1. Poll MRSTAT.mr_wr_busy until it is '0'. * This checks that there is no outstanding MR transaction. * No write should be performed to MRCTRL0 and MRCTRL1 * if MRSTAT.mr_wr_busy = 1. */ while ((mmio_read_32((uintptr_t)&priv->ctl->mrstat) & DDRCTRL_MRSTAT_MR_WR_BUSY) != 0U) { ; } /* * 2. Write the MRCTRL0.mr_type, MRCTRL0.mr_addr, MRCTRL0.mr_rank * and (for MRWs) MRCTRL1.mr_data to define the MR transaction. */ mrctrl0 = DDRCTRL_MRCTRL0_MR_TYPE_WRITE | DDRCTRL_MRCTRL0_MR_RANK_ALL | (((uint32_t)addr << DDRCTRL_MRCTRL0_MR_ADDR_SHIFT) & DDRCTRL_MRCTRL0_MR_ADDR_MASK); 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 * bit is self-clearing, and triggers the MR transaction. * The uMCTL2 then asserts the MRSTAT.mr_wr_busy while it performs * the MR transaction to SDRAM, and no further access can be * initiated until it is deasserted. */ mrctrl0 |= DDRCTRL_MRCTRL0_MR_WR; mmio_write_32((uintptr_t)&priv->ctl->mrctrl0, mrctrl0); while ((mmio_read_32((uintptr_t)&priv->ctl->mrstat) & DDRCTRL_MRSTAT_MR_WR_BUSY) != 0U) { ; } 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((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); VERBOSE("mr2: 0x%x\n", mr2); /* * 1. Set the DBG1.dis_hif = 1. * This prevents further reads/writes being received on the HIF. */ 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 * DBGCAM.wr_data_pipeline_empty = 1, * DBGCAM.rd_data_pipeline_empty = 1, * DBGCAM.dbg_wr_q_depth = 0 , * DBGCAM.dbg_lpr_q_depth = 0, and * DBGCAM.dbg_hpr_q_depth = 0. */ do { 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)); /* * 3. Perform an MRS command (using MRCTRL0 and MRCTRL1 registers) * to disable RTT_NOM: * a. DDR3: Write to MR1[9], MR1[6] and MR1[2] * b. DDR4: Write to MR1[10:8] */ mr1 &= ~(BIT(9) | BIT(6) | BIT(2)); stm32mp1_mode_register_write(priv, 1, mr1); /* * 4. For DDR4 only: Perform an MRS command * (using MRCTRL0 and MRCTRL1 registers) to write to MR5[8:6] * to disable RTT_PARK */ /* * 5. Perform an MRS command (using MRCTRL0 and MRCTRL1 registers) * to write to MR2[10:9], to disable RTT_WR * (and therefore disable dynamic ODT). * This applies for both DDR3 and DDR4. */ mr2 &= ~GENMASK(10, 9); stm32mp1_mode_register_write(priv, 2, mr2); /* * 6. Perform an MRS command (using MRCTRL0 and MRCTRL1 registers) * to disable the DLL. The timing of this MRS is automatically * handled by the uMCTL2. * a. DDR3: Write to MR1[0] * b. DDR4: Write to MR1[0] */ mr1 |= BIT(0); stm32mp1_mode_register_write(priv, 1, mr1); /* * 7. Put the SDRAM into self-refresh mode by setting * PWRCTL.selfref_sw = 1, and polling STAT.operating_mode to ensure * the DDRC has entered self-refresh. */ mmio_setbits_32((uintptr_t)&priv->ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_SW); 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 * DWC_ddr_umctl2 core is in self-refresh mode. * Ensure transition to self-refresh was due to software * by checking that STAT.selfref_type[1:0]=2. */ stm32mp1_wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_SR); /* * 9. Set the MSTR.dll_off_mode = 1. * warning: MSTR.dll_off_mode is a quasi-dynamic type 2 field */ stm32mp1_start_sw_done(priv->ctl); 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); /* 10. Change the clock frequency to the desired value. */ /* * 11. Update any registers which may be required to change for the new * frequency. This includes static and dynamic registers. * This includes both uMCTL2 registers and PHY registers. */ /* Change Bypass Mode Frequency Range */ if (stm32mp_clk_get_rate(DDRPHYC) < 100000000U) { mmio_clrbits_32((uintptr_t)&priv->phy->dllgcr, DDRPHYC_DLLGCR_BPS200); } else { mmio_setbits_32((uintptr_t)&priv->phy->dllgcr, DDRPHYC_DLLGCR_BPS200); } mmio_setbits_32((uintptr_t)&priv->phy->acdllcr, DDRPHYC_ACDLLCR_DLLDIS); mmio_setbits_32((uintptr_t)&priv->phy->dx0dllcr, DDRPHYC_DXNDLLCR_DLLDIS); mmio_setbits_32((uintptr_t)&priv->phy->dx1dllcr, DDRPHYC_DXNDLLCR_DLLDIS); mmio_setbits_32((uintptr_t)&priv->phy->dx2dllcr, DDRPHYC_DXNDLLCR_DLLDIS); 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((uintptr_t)&priv->ctl->pwrctl, DDRCTRL_PWRCTL_SELFREF_SW); stm32mp1_wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL); /* * 13. If ZQCTL0.dis_srx_zqcl = 0, the uMCTL2 performs a ZQCL command * at this point. */ /* * 14. Perform MRS commands as required to re-program timing registers * in the SDRAM for the new frequency * (in particular, CL, CWL and WR may need to be changed). */ /* 15. Write DBG1.dis_hif = 0 to re-enable reads and writes. */ 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((uintptr_t)&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH); mmio_clrbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN); mmio_clrbits_32((uintptr_t)&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); stm32mp1_wait_sw_done_ack(ctl); } static void stm32mp1_refresh_restore(struct stm32mp1_ddrctl *ctl, uint32_t rfshctl3, uint32_t pwrctl) { stm32mp1_start_sw_done(ctl); if ((rfshctl3 & DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH) == 0U) { mmio_clrbits_32((uintptr_t)&ctl->rfshctl3, DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH); } if ((pwrctl & DDRCTRL_PWRCTL_POWERDOWN_EN) != 0U) { mmio_setbits_32((uintptr_t)&ctl->pwrctl, DDRCTRL_PWRCTL_POWERDOWN_EN); } mmio_setbits_32((uintptr_t)&ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); stm32mp1_wait_sw_done_ack(ctl); } static int board_ddr_power_init(enum ddr_type ddr_type) { if (dt_pmic_status() > 0) { return pmic_ddr_power_init(ddr_type); } return 0; } void stm32mp1_ddr_init(struct ddr_info *priv, struct stm32mp1_ddr_config *config) { uint32_t pir; int ret = -EINVAL; if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR3) != 0U) { ret = board_ddr_power_init(STM32MP_DDR3); } 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) { panic(); } VERBOSE("name = %s\n", config->info.name); VERBOSE("speed = %d kHz\n", config->info.speed); VERBOSE("size = 0x%x\n", config->info.size); /* DDR INIT SEQUENCE */ /* * 1. Program the DWC_ddr_umctl2 registers * nota: check DFIMISC.dfi_init_complete = 0 */ /* 1.1 RESETS: presetn, core_ddrc_rstn, aresetn */ mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAPBRST); mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAXIRST); mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCORERST); mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYAPBRST); mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYRST); mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYCTLRST); /* 1.2. start CLOCK */ if (stm32mp1_ddr_clk_enable(priv, config->info.speed) != 0) { panic(); } /* 1.3. deassert reset */ /* De-assert PHY rstn and ctl_rstn via DPHYRST and DPHYCTLRST. */ mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYRST); mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYCTLRST); /* * De-assert presetn once the clocks are active * and stable via DDRCAPBRST bit. */ mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAPBRST); /* 1.4. wait 128 cycles to permit initialization of end logic */ udelay(2); /* For PCLK = 133MHz => 1 us is enough, 2 to allow lower frequency */ /* 1.5. initialize registers ddr_umctl2 */ /* Stop uMCTL2 before PHY is ready */ mmio_clrbits_32((uintptr_t)&priv->ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); 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); /* DDR3 = don't set DLLOFF for init mode */ if ((config->c_reg.mstr & (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((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)); } 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((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); /* 2. deassert reset signal core_ddrc_rstn, aresetn and presetn */ mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCORERST); mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DDRCAXIRST); mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_DPHYAPBRST); /* * 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); /* DDR3 = don't set DLLOFF for init mode */ if ((config->c_reg.mstr & (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((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)); } /* * 4. Monitor PHY init status by polling PUBL register PGSR.IDONE * Perform DDR PHY DRAM initialization and Gate Training Evaluation */ stm32mp1_ddrphy_idone_wait(priv->phy); /* * 5. Indicate to PUBL that controller performs SDRAM initialization * by setting PIR.INIT and PIR CTLDINIT and pool PGSR.IDONE * DRAM init is done by PHY, init0.skip_dram.init = 1 */ pir = DDRPHYC_PIR_DLLSRST | DDRPHYC_PIR_DLLLOCK | DDRPHYC_PIR_ZCAL | DDRPHYC_PIR_ITMSRST | DDRPHYC_PIR_DRAMINIT | DDRPHYC_PIR_ICPC; if ((config->c_reg.mstr & DDRCTRL_MSTR_DDR3) != 0U) { pir |= DDRPHYC_PIR_DRAMRST; /* Only for DDR3 */ } stm32mp1_ddrphy_init(priv->phy, pir); /* * 6. SET DFIMISC.dfi_init_complete_en to 1 * Enable quasi-dynamic register programming. */ stm32mp1_start_sw_done(priv->ctl); mmio_setbits_32((uintptr_t)&priv->ctl->dfimisc, DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN); 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); /* * 7. Wait for DWC_ddr_umctl2 to move to normal operation mode * by monitoring STAT.operating_mode signal */ /* Wait uMCTL2 ready */ stm32mp1_wait_operating_mode(priv, DDRCTRL_STAT_OPERATING_MODE_NORMAL); /* Switch to DLL OFF mode */ if ((config->c_reg.mstr & DDRCTRL_MSTR_DLL_OFF_MODE) != 0U) { stm32mp1_ddr3_dll_off(priv); } VERBOSE("DDR DQS training : "); /* * 8. Disable Auto refresh and power down by setting * - RFSHCTL3.dis_au_refresh = 1 * - PWRCTL.powerdown_en = 0 * - DFIMISC.dfiinit_complete_en = 0 */ stm32mp1_refresh_disable(priv->ctl); /* * 9. Program PUBL PGCR to enable refresh during training * and rank to train * not done => keep the programed value in PGCR */ /* * 10. configure PUBL PIR register to specify which training step * to run * Warning : RVTRN is not supported by this PUBL */ stm32mp1_ddrphy_init(priv->phy, DDRPHYC_PIR_QSTRN); /* 11. monitor PUB PGSR.IDONE to poll cpmpletion of training sequence */ stm32mp1_ddrphy_idone_wait(priv->phy); /* * 12. set back registers in step 8 to the orginal values if desidered */ stm32mp1_refresh_restore(priv->ctl, config->c_reg.rfshctl3, config->c_reg.pwrctl); /* Enable uMCTL2 AXI port 0 */ mmio_setbits_32((uintptr_t)&priv->ctl->pctrl_0, 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((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)); } trusted-firmware-a-2.2/drivers/st/ddr/stm32mp1_ddr_helpers.c000066400000000000000000000007711355360272700241000ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include void ddr_enable_clock(void) { 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(); } trusted-firmware-a-2.2/drivers/st/ddr/stm32mp1_ram.c000066400000000000000000000175641355360272700223740ustar00rootroot00000000000000/* * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #define DDR_PATTERN 0xAAAAAAAAU #define DDR_ANTIPATTERN 0x55555555U static struct ddr_info ddr_priv_data; int stm32mp1_ddr_clk_enable(struct ddr_info *priv, uint32_t mem_speed) { unsigned long ddrphy_clk, ddr_clk, mem_speed_hz; ddr_enable_clock(); ddrphy_clk = stm32mp_clk_get_rate(DDRPHYC); VERBOSE("DDR: mem_speed (%d kHz), RCC %ld kHz\n", mem_speed, ddrphy_clk / 1000U); mem_speed_hz = mem_speed * 1000U; /* Max 10% frequency delta */ if (ddrphy_clk > mem_speed_hz) { ddr_clk = ddrphy_clk - mem_speed_hz; } else { ddr_clk = mem_speed_hz - ddrphy_clk; } 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 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. * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/ * File: memtest.c - This source code belongs to Public Domain. * Returns 0 if success, and address value else. ******************************************************************************/ static uint32_t ddr_test_data_bus(void) { uint32_t pattern; for (pattern = 1U; pattern != 0U; pattern <<= 1) { mmio_write_32(STM32MP_DDR_BASE, pattern); if (mmio_read_32(STM32MP_DDR_BASE) != pattern) { return (uint32_t)STM32MP_DDR_BASE; } } return 0; } /******************************************************************************* * This function tests the DDR address bus wiring. * This is inspired from the Data Bus Test algorithm written by Michael Barr * in "Programming Embedded Systems in C and C++" book. * resources.oreilly.com/examples/9781565923546/blob/master/Chapter6/ * File: memtest.c - This source code belongs to Public Domain. * Returns 0 if success, and address value else. ******************************************************************************/ static uint32_t ddr_test_addr_bus(void) { uint64_t addressmask = (ddr_priv_data.info.size - 1U); uint64_t offset; uint64_t testoffset = 0; /* 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(STM32MP_DDR_BASE + (uint32_t)offset, DDR_PATTERN); } /* Check for address bits stuck high. */ 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(STM32MP_DDR_BASE + (uint32_t)offset) != DDR_PATTERN) { return (uint32_t)(STM32MP_DDR_BASE + offset); } } 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(STM32MP_DDR_BASE + (uint32_t)testoffset, DDR_ANTIPATTERN); 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(STM32MP_DDR_BASE + (uint32_t)offset) != DDR_PATTERN) && (offset != testoffset)) { return (uint32_t)(STM32MP_DDR_BASE + offset); } } mmio_write_32(STM32MP_DDR_BASE + (uint32_t)testoffset, DDR_PATTERN); } return 0; } /******************************************************************************* * This function checks the DDR size. It has to be run with Data Cache off. * This test is run before data have been put in DDR, and is only done for * cold boot. The DDR data can then be overwritten, and it is not useful to * restore its content. * Returns DDR computed size. ******************************************************************************/ static uint32_t ddr_check_size(void) { uint32_t offset = sizeof(uint32_t); mmio_write_32(STM32MP_DDR_BASE, DDR_PATTERN); while (offset < STM32MP_DDR_MAX_SIZE) { mmio_write_32(STM32MP_DDR_BASE + offset, DDR_ANTIPATTERN); dsb(); if (mmio_read_32(STM32MP_DDR_BASE) != DDR_PATTERN) { break; } offset <<= 1; } INFO("Memory size = 0x%x (%d MB)\n", offset, offset / (1024U * 1024U)); return offset; } static int stm32mp1_ddr_setup(void) { struct ddr_info *priv = &ddr_priv_data; int ret; struct stm32mp1_ddr_config config; int node, len; uint32_t uret, idx; void *fdt; #define PARAM(x, y) \ { \ .name = x, \ .offset = offsetof(struct stm32mp1_ddr_config, y), \ .size = sizeof(config.y) / sizeof(uint32_t) \ } #define CTL_PARAM(x) PARAM("st,ctl-"#x, c_##x) #define PHY_PARAM(x) PARAM("st,phy-"#x, p_##x) const struct { const char *name; /* Name in DT */ const uint32_t offset; /* Offset in config struct */ const uint32_t size; /* Size of parameters */ } param[] = { CTL_PARAM(reg), CTL_PARAM(timing), CTL_PARAM(map), CTL_PARAM(perf), PHY_PARAM(reg), PHY_PARAM(timing), PHY_PARAM(cal) }; if (fdt_get_address(&fdt) == 0) { return -ENOENT; } node = fdt_node_offset_by_compatible(fdt, -1, DT_DDR_COMPAT); if (node < 0) { ERROR("%s: Cannot read DDR node in DT\n", __func__); return -EINVAL; } 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__); return -EINVAL; } INFO("RAM: %s\n", config.info.name); for (idx = 0; idx < ARRAY_SIZE(param); idx++) { ret = fdt_read_uint32_array(node, param[idx].name, (void *)((uintptr_t)&config + param[idx].offset), param[idx].size); VERBOSE("%s: %s[0x%x] = %d\n", __func__, param[idx].name, param[idx].size, ret); if (ret != 0) { ERROR("%s: Cannot read %s\n", __func__, param[idx].name); return -EINVAL; } } /* Disable axidcg clock gating during init */ mmio_clrbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); stm32mp1_ddr_init(priv, &config); /* Enable axidcg clock gating */ mmio_setbits_32(priv->rcc + RCC_DDRITFCR, RCC_DDRITFCR_AXIDCGEN); priv->info.size = config.info.size; VERBOSE("%s : ram size(%x, %x)\n", __func__, (uint32_t)priv->info.base, (uint32_t)priv->info.size); write_sctlr(read_sctlr() & ~SCTLR_C_BIT); dcsw_op_all(DC_OP_CISW); 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_check_size(); if (uret < config.info.size) { ERROR("DDR size: 0x%x does not match DT config: 0x%x\n", uret, config.info.size); panic(); } write_sctlr(read_sctlr() | SCTLR_C_BIT); return 0; } int stm32mp1_ddr_probe(void) { struct ddr_info *priv = &ddr_priv_data; VERBOSE("STM32MP DDR probe\n"); 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 = STM32MP_DDR_BASE; priv->info.size = 0; return stm32mp1_ddr_setup(); } trusted-firmware-a-2.2/drivers/st/gpio/000077500000000000000000000000001355360272700201535ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/st/gpio/stm32_gpio.c000066400000000000000000000160201355360272700223040ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #define DT_GPIO_BANK_SHIFT 12 #define DT_GPIO_BANK_MASK GENMASK(16, 12) #define DT_GPIO_PIN_SHIFT 8 #define DT_GPIO_PIN_MASK GENMASK(11, 8) #define DT_GPIO_MODE_MASK GENMASK(7, 0) /******************************************************************************* * 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) { int pinctrl_subnode; uint32_t bank_offset = stm32_get_gpio_bank_offset(bank); fdt_for_each_subnode(pinctrl_subnode, fdt, pinctrl_node) { 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; } if ((fdt32_to_cpu(*cuint) == bank_offset) && (fdt_get_status(pinctrl_subnode) != DT_DISABLED)) { return pinctrl_subnode; } } 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 error code on failure. ******************************************************************************/ static int dt_set_gpio_config(void *fdt, int node, uint8_t status) { 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; } 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 = 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((unsigned long)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 -FDT_ERR_NOTFOUND; } if (status == DT_DISABLED) { 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 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); unsigned long clock = stm32_get_gpio_bank_clock(bank); assert(pin <= GPIO_PIN_MAX); stm32mp_clk_enable(clock); mmio_clrbits_32(base + GPIO_MODE_OFFSET, ((uint32_t)GPIO_MODE_MASK << (pin << 1))); mmio_setbits_32(base + GPIO_MODE_OFFSET, (mode & ~GPIO_OPEN_DRAIN) << (pin << 1)); if ((mode & GPIO_OPEN_DRAIN) != 0U) { mmio_setbits_32(base + GPIO_TYPE_OFFSET, BIT(pin)); } else { mmio_clrbits_32(base + GPIO_TYPE_OFFSET, BIT(pin)); } mmio_clrbits_32(base + GPIO_SPEED_OFFSET, ((uint32_t)GPIO_SPEED_MASK << (pin << 1))); mmio_setbits_32(base + GPIO_SPEED_OFFSET, speed << (pin << 1)); mmio_clrbits_32(base + GPIO_PUPD_OFFSET, ((uint32_t)GPIO_PULL_MASK << (pin << 1))); mmio_setbits_32(base + GPIO_PUPD_OFFSET, pull << (pin << 1)); if (pin < GPIO_ALT_LOWER_LIMIT) { mmio_clrbits_32(base + GPIO_AFRL_OFFSET, ((uint32_t)GPIO_ALTERNATE_MASK << (pin << 2))); mmio_setbits_32(base + GPIO_AFRL_OFFSET, alternate << (pin << 2)); } else { mmio_clrbits_32(base + GPIO_AFRH_OFFSET, ((uint32_t)GPIO_ALTERNATE_MASK << ((pin - GPIO_ALT_LOWER_LIMIT) << 2))); 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(base + GPIO_MODE_OFFSET)); VERBOSE("GPIO %u speed set to 0x%x\n", bank, mmio_read_32(base + GPIO_SPEED_OFFSET)); VERBOSE("GPIO %u mode pull to 0x%x\n", bank, mmio_read_32(base + GPIO_PUPD_OFFSET)); VERBOSE("GPIO %u mode alternate low to 0x%x\n", bank, mmio_read_32(base + GPIO_AFRL_OFFSET)); VERBOSE("GPIO %u mode alternate high to 0x%x\n", bank, mmio_read_32(base + GPIO_AFRH_OFFSET)); stm32mp_clk_disable(clock); } void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure) { uintptr_t base = stm32_get_gpio_bank_base(bank); unsigned long clock = stm32_get_gpio_bank_clock(bank); assert(pin <= GPIO_PIN_MAX); stm32mp_clk_enable(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(clock); } trusted-firmware-a-2.2/drivers/st/i2c/000077500000000000000000000000001355360272700176725ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/st/i2c/stm32_i2c.c000066400000000000000000000657121355360272700215560ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include /* STM32 I2C registers offsets */ #define I2C_CR1 0x00U #define I2C_CR2 0x04U #define I2C_OAR1 0x08U #define I2C_OAR2 0x0CU #define I2C_TIMINGR 0x10U #define I2C_TIMEOUTR 0x14U #define I2C_ISR 0x18U #define I2C_ICR 0x1CU #define I2C_PECR 0x20U #define I2C_RXDR 0x24U #define I2C_TXDR 0x28U #define TIMINGR_CLEAR_MASK 0xF0FFFFFFU #define MAX_NBYTE_SIZE 255U #define I2C_NSEC_PER_SEC 1000000000L /* I2C Timing hard-coded value, for I2C clock source is HSI at 64MHz */ #define I2C_TIMING 0x10D07DB5 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 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 = I2C_TIMING; if (hi2c == NULL) { return -ENOENT; } if (hi2c->i2c_state == I2C_STATE_RESET) { hi2c->lock = 0; } hi2c->i2c_state = I2C_STATE_BUSY; 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 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_ref: Reference to target timeout * @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 timeout_ref) { for ( ; ; ) { uint32_t isr = mmio_read_32(hi2c->i2c_base_addr + I2C_ISR); if (!!(isr & flag) != !!awaited_value) { return 0; } if (timeout_elapsed(timeout_ref)) { notif_i2c_timeout(hi2c); hi2c->lock = 0; return -EIO; } } } /* * @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_ref: Reference to target timeout * @retval 0 if OK, negative value else */ static int i2c_ack_failed(struct i2c_handle_s *hi2c, uint64_t timeout_ref) { 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(timeout_ref)) { 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 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_ref: Reference to target timeout * @retval 0 if OK, negative value else */ static int i2c_wait_txis(struct i2c_handle_s *hi2c, uint64_t timeout_ref) { while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_TXIS) == 0U) { if (i2c_ack_failed(hi2c, timeout_ref) != 0) { return -EIO; } if (timeout_elapsed(timeout_ref)) { 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 timeout_ref: Reference to target timeout * @retval 0 if OK, negative value else */ static int i2c_wait_stop(struct i2c_handle_s *hi2c, uint64_t timeout_ref) { while ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & I2C_FLAG_STOPF) == 0U) { if (i2c_ack_failed(hi2c, timeout_ref) != 0) { return -EIO; } if (timeout_elapsed(timeout_ref)) { notif_i2c_timeout(hi2c); hi2c->lock = 0; return -EIO; } } return 0; } /* * @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 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_ref: Reference to target timeout * @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 timeout_ref) { i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_RELOAD_MODE, I2C_GENERATE_START_WRITE); if (i2c_wait_txis(hi2c, timeout_ref) != 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, timeout_ref) != 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_ref) != 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_ref: Reference to target timeout * @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 timeout_ref) { i2c_transfer_config(hi2c, dev_addr, mem_add_size, I2C_SOFTEND_MODE, I2C_GENERATE_START_WRITE); if (i2c_wait_txis(hi2c, timeout_ref) != 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, timeout_ref) != 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_ref) != 0) { return -EIO; } return 0; } /* * @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 timeout_ref; 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; timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_MS * 1000); if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, timeout_ref) != 0) { goto bail; } hi2c->i2c_state = I2C_STATE_BUSY_TX; hi2c->i2c_mode = mode; hi2c->i2c_err = I2C_ERROR_NONE; timeout_ref = timeout_init_us(timeout_ms * 1000); 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, timeout_ref) != 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, timeout_ref) != 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, timeout_ref) != 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, timeout_ref) != 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 timeout_ref; 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; timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_MS * 1000); if (i2c_wait_flag(hi2c, I2C_FLAG_BUSY, 1, timeout_ref) != 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, timeout_ref) != 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, timeout_ref) != 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, timeout_ref) != 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, timeout_ref) != 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; 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 timeout_ref; /* 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. */ timeout_ref = timeout_init_us(timeout_ms * 1000); do { if ((mmio_read_32(hi2c->i2c_base_addr + I2C_ISR) & (I2C_FLAG_STOPF | I2C_FLAG_AF)) != 0U) { break; } if (timeout_elapsed(timeout_ref)) { 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, timeout_ref) != 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, timeout_ref) != 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, timeout_ref) != 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; } trusted-firmware-a-2.2/drivers/st/io/000077500000000000000000000000001355360272700176245ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/st/io/io_mmc.c000066400000000000000000000056661355360272700212500ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include /* 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, ssize_t offset); static int mmc_block_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read); static int mmc_block_close(io_entity_t *entity); static int mmc_dev_close(io_dev_info_t *dev_info); static io_type_t device_type_mmc(void); static ssize_t seek_offset; static 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, ssize_t 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) { *length_read = mmc_read_blocks(seek_offset / MMC_BLOCK_SIZE, buffer, length); if (*length_read != length) { return -EIO; } 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; } trusted-firmware-a-2.2/drivers/st/io/io_stm32image.c000066400000000000000000000224151355360272700224360ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include static uintptr_t backend_dev_handle; static uintptr_t backend_image_spec; static uint32_t *stm32_img; static uint8_t first_lba_buffer[MAX_LBA_SIZE] __aligned(4); static struct stm32image_part_info *current_part; /* STM32 Image driver functions */ static int stm32image_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info); static int stm32image_partition_open(io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity); static int stm32image_partition_size(io_entity_t *entity, size_t *length); static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read); static int stm32image_partition_close(io_entity_t *entity); static int stm32image_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params); static int stm32image_dev_close(io_dev_info_t *dev_info); /* Identify the device type as a virtual driver */ static io_type_t device_type_stm32image(void) { return IO_TYPE_STM32IMAGE; } static const io_dev_connector_t stm32image_dev_connector = { .dev_open = stm32image_dev_open }; static const io_dev_funcs_t stm32image_dev_funcs = { .type = device_type_stm32image, .open = stm32image_partition_open, .size = stm32image_partition_size, .read = stm32image_partition_read, .close = stm32image_partition_close, .dev_init = stm32image_dev_init, .dev_close = stm32image_dev_close, }; static io_dev_info_t stm32image_dev_info = { .funcs = &stm32image_dev_funcs, .info = (uintptr_t)0, }; static struct stm32image_device_info stm32image_dev; static int get_part_idx_by_binary_type(uint32_t binary_type) { int i; for (i = 0; i < STM32_PART_NUM; i++) { if (stm32image_dev.part_info[i].binary_type == binary_type) { return i; } } return -EINVAL; } /* Open a connection to the STM32IMAGE device */ static int stm32image_dev_open(const uintptr_t init_params, io_dev_info_t **dev_info) { int i; struct stm32image_device_info *device_info = (struct stm32image_device_info *)init_params; assert(dev_info != NULL); *dev_info = (io_dev_info_t *)&stm32image_dev_info; stm32image_dev.device_size = device_info->device_size; stm32image_dev.lba_size = device_info->lba_size; for (i = 0; i < STM32_PART_NUM; i++) { memcpy(stm32image_dev.part_info[i].name, device_info->part_info[i].name, MAX_PART_NAME_SIZE); stm32image_dev.part_info[i].binary_type = device_info->part_info[i].binary_type; stm32image_dev.part_info[i].part_offset = device_info->part_info[i].part_offset; stm32image_dev.part_info[i].bkp_offset = device_info->part_info[i].bkp_offset; } return 0; } /* Do some basic package checks */ static int stm32image_dev_init(io_dev_info_t *dev_info, const uintptr_t init_params) { int result; if ((backend_dev_handle != 0U) || (backend_image_spec != 0U)) { ERROR("STM32 Image io supports only one session\n"); return -ENOMEM; } /* Obtain a reference to the image by querying the platform layer */ result = plat_get_image_source(STM32_IMAGE_ID, &backend_dev_handle, &backend_image_spec); if (result != 0) { ERROR("STM32 image error (%i)\n", result); return -EINVAL; } return result; } /* Close a connection to the STM32 Image device */ static int stm32image_dev_close(io_dev_info_t *dev_info) { backend_dev_handle = 0U; backend_image_spec = 0U; stm32_img = NULL; return 0; } /* Open a partition */ static int stm32image_partition_open(io_dev_info_t *dev_info, const uintptr_t spec, io_entity_t *entity) { const struct stm32image_part_info *partition_spec; int idx; assert(entity != NULL); partition_spec = (struct stm32image_part_info *)spec; assert(partition_spec != NULL); idx = get_part_idx_by_binary_type(partition_spec->binary_type); if ((idx < 0) || (idx > STM32_PART_NUM)) { ERROR("Wrong partition index (%d)\n", idx); return -EINVAL; } current_part = &stm32image_dev.part_info[idx]; stm32_img = (uint32_t *)¤t_part->part_offset; return 0; } /* Return the size of a partition */ static int stm32image_partition_size(io_entity_t *entity, size_t *length) { int result; uintptr_t backend_handle; size_t bytes_read; boot_api_image_header_t *header = (boot_api_image_header_t *)first_lba_buffer; assert(entity != NULL); assert(length != NULL); /* Attempt to access the image */ result = io_open(backend_dev_handle, backend_image_spec, &backend_handle); if (result < 0) { ERROR("%s: io_open (%i)\n", __func__, result); return result; } /* Reset magic header value */ header->magic = 0; while (header->magic == 0U) { result = io_seek(backend_handle, IO_SEEK_SET, *stm32_img); if (result != 0) { ERROR("%s: io_seek (%i)\n", __func__, result); break; } result = io_read(backend_handle, (uintptr_t)header, MAX_LBA_SIZE, (size_t *)&bytes_read); if (result != 0) { if (current_part->bkp_offset == 0U) { ERROR("%s: io_read (%i)\n", __func__, result); } header->magic = 0; } if ((header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) || (header->binary_type != current_part->binary_type) || (header->image_length >= stm32image_dev.device_size)) { VERBOSE("%s: partition %s not found at %x\n", __func__, current_part->name, *stm32_img); if (current_part->bkp_offset == 0U) { result = -ENOMEM; break; } /* Header not correct, check next offset for backup */ *stm32_img += current_part->bkp_offset; if (*stm32_img > stm32image_dev.device_size) { /* No backup found, end of device reached */ WARN("%s : partition %s not found\n", __func__, current_part->name); result = -ENOMEM; break; } header->magic = 0; } } io_close(backend_handle); if (result != 0) { return result; } if (header->image_length < stm32image_dev.lba_size) { *length = stm32image_dev.lba_size; } else { *length = header->image_length; } INFO("STM32 Image size : %lu\n", (unsigned long)*length); return 0; } /* Read data from a partition */ static int stm32image_partition_read(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read) { int result; 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 = stm32mp_check_header(header, buffer); if (result != 0) { ERROR("Header check failed\n"); *length_read = 0; header->magic = 0; } result = stm32mp_auth_image(header, buffer); if (result != 0) { ERROR("Authentication Failed (%i)\n", result); return result; } 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; } trusted-firmware-a-2.2/drivers/st/iwdg/000077500000000000000000000000001355360272700201475ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/st/iwdg/stm32_iwdg.c000066400000000000000000000062131355360272700222770ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* IWDG registers offsets */ #define IWDG_KR_OFFSET 0x00U /* Registers values */ #define IWDG_KR_RELOAD_KEY 0xAAAA 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, DT_IWDG_COMPAT); if (node < 0) { if (offset == -1) { VERBOSE("%s: No IDWG found\n", __func__); } return -FDT_ERR_NOTFOUND; } return node; } void stm32_iwdg_refresh(void) { uint8_t i; for (i = 0U; i < IWDG_MAX_INSTANCE; i++) { struct stm32_iwdg_instance *iwdg = &stm32_iwdg[i]; /* 0x00000000 is not a valid address for IWDG peripherals */ if (iwdg->base != 0U) { 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; struct dt_node_info dt_info; void *fdt; uint32_t __unused count = 0; 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; uint32_t idx; count++; 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_DISABLE_ON_STOP; } if (fdt_getprop(fdt, node, "stm32,enable-on-standby", NULL) == NULL) { iwdg->flags |= IWDG_DISABLE_ON_STANDBY; } /* Explicit list of supported bit flags */ hw_init = stm32_iwdg_get_otp_config(idx); if ((hw_init & IWDG_HW_ENABLED) != 0) { if (dt_info.status == DT_DISABLED) { ERROR("OTP enabled but iwdg%u DT-disabled\n", idx + 1U); panic(); } iwdg->flags |= IWDG_HW_ENABLED; } if (dt_info.status == DT_DISABLED) { zeromem((void *)iwdg, sizeof(struct stm32_iwdg_instance)); continue; } if ((hw_init & IWDG_DISABLE_ON_STOP) != 0) { iwdg->flags |= IWDG_DISABLE_ON_STOP; } if ((hw_init & IWDG_DISABLE_ON_STANDBY) != 0) { iwdg->flags |= IWDG_DISABLE_ON_STANDBY; } VERBOSE("IWDG%u found, %ssecure\n", idx + 1U, ((dt_info.status & DT_NON_SECURE) != 0) ? "non-" : ""); #if defined(IMAGE_BL2) if (stm32_iwdg_shadow_update(idx, iwdg->flags) != BSEC_OK) { return -1; } #endif } VERBOSE("%u IWDG instance%s found\n", count, (count > 1U) ? "s" : ""); return 0; } trusted-firmware-a-2.2/drivers/st/mmc/000077500000000000000000000000001355360272700177715ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/st/mmc/stm32_sdmmc2.c000066400000000000000000000431631355360272700223610ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* 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 GENMASK(7, 4) #define SDMMC_DCTRLR_DBLOCKSIZE_SHIFT 4 #define SDMMC_DCTRLR_FIFORST BIT(13) #define SDMMC_DCTRLR_CLEAR_MASK (SDMMC_DCTRLR_DTEN | \ SDMMC_DCTRLR_DTDIR | \ SDMMC_DCTRLR_DTMODE | \ SDMMC_DCTRLR_DBLOCKSIZE) /* 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_US_10_MS 10000U #define TIMEOUT_US_1_S 1000000U #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 stm32_sdmmc2_init(void) { uint32_t clock_div; uint32_t freq = STM32MP_MMC_INIT_FREQ; uintptr_t base = sdmmc2_params.reg_base; if (sdmmc2_params.max_freq != 0U) { freq = MIN(sdmmc2_params.max_freq, freq); } clock_div = div_round_up(sdmmc2_params.clk_rate, freq * 2U); 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 timeout; 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); timeout = timeout_init_us(TIMEOUT_US_10_MS); while ((status & flags_cmd) == 0U) { if (timeout_elapsed(timeout)) { 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); timeout = timeout_init_us(TIMEOUT_US_10_MS); while ((status & flags_data) == 0U) { if (timeout_elapsed(timeout)) { 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, 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; } } if (sdmmc2_params.max_freq != 0U) { freq = MIN(sdmmc2_params.max_freq, max_freq); } else { freq = max_freq; } clock_div = div_round_up(clk_rate, freq * 2U); 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; uint32_t arg_size; assert(size != 0U); if (size > MMC_BLOCK_SIZE) { arg_size = MMC_BLOCK_SIZE; } else { arg_size = size; } 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); cmd.cmd_arg = 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); } data_ctrl |= __builtin_ctz(arg_size) << SDMMC_DCTRLR_DBLOCKSIZE_SHIFT; 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; uint64_t timeout; 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; } timeout = timeout_init_us(TIMEOUT_US_1_S); do { status = mmio_read_32(base + SDMMC_STAR); if ((status & error_flags) != 0U) { ERROR("%s: Read error (status = %x)\n", __func__, status); 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(timeout)) { ERROR("%s: timeout 1s (status = %x)\n", __func__, status); 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; } } cuint = fdt_getprop(fdt, sdmmc_node, "max-frequency", NULL); if (cuint != NULL) { sdmmc2_params.max_freq = fdt32_to_cpu(*cuint); } 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); sdmmc2_params.device_info->ocr_voltage = OCR_3_2_3_3 | OCR_3_3_3_4; return mmc_init(&stm32_sdmmc2_ops, sdmmc2_params.clk_rate, sdmmc2_params.bus_width, sdmmc2_params.flags, sdmmc2_params.device_info); } trusted-firmware-a-2.2/drivers/st/pmic/000077500000000000000000000000001355360272700201455ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/st/pmic/stm32mp_pmic.c000066400000000000000000000172101355360272700226270ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #define STPMIC1_LDO12356_OUTPUT_MASK (uint8_t)(GENMASK(6, 2)) #define STPMIC1_LDO12356_OUTPUT_SHIFT 2 #define STPMIC1_LDO3_MODE (uint8_t)(BIT(7)) #define STPMIC1_LDO3_DDR_SEL 31U #define STPMIC1_LDO3_1800000 (9U << STPMIC1_LDO12356_OUTPUT_SHIFT) #define STPMIC1_BUCK_OUTPUT_SHIFT 2 #define STPMIC1_BUCK3_1V8 (39U << STPMIC1_BUCK_OUTPUT_SHIFT) #define 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); } /* * Get PMIC and its I2C bus configuration from the device tree. * Return 0 on success, negative on error, 1 if no PMIC node is found. */ static int dt_pmic_i2c_config(struct dt_node_info *i2c_info, struct stm32_i2c_init_s *init) { 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) { status = stpmic1_regulator_pull_down_set(node_name); if (status != 0) { return status; } } if (fdt_getprop(fdt, regulator_node, "st,mask-reset", NULL) != NULL) { 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; } 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; } void initialize_pmic(void) { unsigned long pmic_version; if (!initialize_pmic_i2c()) { VERBOSE("No PMIC\n"); 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 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; } trusted-firmware-a-2.2/drivers/st/pmic/stpmic1.c000066400000000000000000000277711355360272700217070ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #define I2C_TIMEOUT_MS 25 struct regul_struct { const char *dt_node_name; const uint16_t *voltage_table; uint8_t voltage_table_size; uint8_t control_reg; uint8_t low_power_reg; uint8_t pull_down_reg; uint8_t pull_down; uint8_t mask_reset_reg; uint8_t mask_reset; }; static struct i2c_handle_s *pmic_i2c_handle; static uint16_t pmic_i2c_addr; /* Voltage tables in mV */ static const uint16_t buck1_voltage_table[] = { 725, 725, 725, 725, 725, 725, 750, 775, 800, 825, 850, 875, 900, 925, 950, 975, 1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300, 1325, 1350, 1375, 1400, 1425, 1450, 1475, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, 1500, }; static const uint16_t buck2_voltage_table[] = { 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1050, 1050, 1100, 1100, 1150, 1150, 1200, 1200, 1250, 1250, 1300, 1300, 1350, 1350, 1400, 1400, 1450, 1450, 1500, }; static const uint16_t buck3_voltage_table[] = { 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1100, 1100, 1100, 1100, 1200, 1200, 1200, 1200, 1300, 1300, 1300, 1300, 1400, 1400, 1400, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400, }; static const uint16_t buck4_voltage_table[] = { 600, 625, 650, 675, 700, 725, 750, 775, 800, 825, 850, 875, 900, 925, 950, 975, 1000, 1025, 1050, 1075, 1100, 1125, 1150, 1175, 1200, 1225, 1250, 1275, 1300, 1300, 1350, 1350, 1400, 1400, 1450, 1450, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900, }; static const uint16_t ldo1_voltage_table[] = { 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, }; static const uint16_t ldo2_voltage_table[] = { 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, }; static const uint16_t ldo3_voltage_table[] = { 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3300, 3300, 3300, 3300, 3300, 3300, 500, 0xFFFF, /* VREFDDR */ }; static const uint16_t ldo5_voltage_table[] = { 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700, 3800, 3900, }; static const uint16_t ldo6_voltage_table[] = { 900, 1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, 1800, 1900, 2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, 2800, 2900, 3000, 3100, 3200, 3300, }; static const uint16_t ldo4_voltage_table[] = { 3300, }; static const uint16_t vref_ddr_voltage_table[] = { 3300, }; /* Table of Regulators in PMIC SoC */ static const struct regul_struct regulators_table[] = { { .dt_node_name = "buck1", .voltage_table = buck1_voltage_table, .voltage_table_size = ARRAY_SIZE(buck1_voltage_table), .control_reg = BUCK1_CONTROL_REG, .low_power_reg = BUCK1_PWRCTRL_REG, .pull_down_reg = BUCK_PULL_DOWN_REG, .pull_down = BUCK1_PULL_DOWN_SHIFT, .mask_reset_reg = MASK_RESET_BUCK_REG, .mask_reset = BUCK1_MASK_RESET, }, { .dt_node_name = "buck2", .voltage_table = buck2_voltage_table, .voltage_table_size = ARRAY_SIZE(buck2_voltage_table), .control_reg = BUCK2_CONTROL_REG, .low_power_reg = BUCK2_PWRCTRL_REG, .pull_down_reg = BUCK_PULL_DOWN_REG, .pull_down = BUCK2_PULL_DOWN_SHIFT, .mask_reset_reg = MASK_RESET_BUCK_REG, .mask_reset = BUCK2_MASK_RESET, }, { .dt_node_name = "buck3", .voltage_table = buck3_voltage_table, .voltage_table_size = ARRAY_SIZE(buck3_voltage_table), .control_reg = BUCK3_CONTROL_REG, .low_power_reg = BUCK3_PWRCTRL_REG, .pull_down_reg = BUCK_PULL_DOWN_REG, .pull_down = BUCK3_PULL_DOWN_SHIFT, .mask_reset_reg = MASK_RESET_BUCK_REG, .mask_reset = BUCK3_MASK_RESET, }, { .dt_node_name = "buck4", .voltage_table = buck4_voltage_table, .voltage_table_size = ARRAY_SIZE(buck4_voltage_table), .control_reg = BUCK4_CONTROL_REG, .low_power_reg = BUCK4_PWRCTRL_REG, .pull_down_reg = BUCK_PULL_DOWN_REG, .pull_down = BUCK4_PULL_DOWN_SHIFT, .mask_reset_reg = MASK_RESET_BUCK_REG, .mask_reset = BUCK4_MASK_RESET, }, { .dt_node_name = "ldo1", .voltage_table = ldo1_voltage_table, .voltage_table_size = ARRAY_SIZE(ldo1_voltage_table), .control_reg = LDO1_CONTROL_REG, .low_power_reg = LDO1_PWRCTRL_REG, .mask_reset_reg = MASK_RESET_LDO_REG, .mask_reset = LDO1_MASK_RESET, }, { .dt_node_name = "ldo2", .voltage_table = ldo2_voltage_table, .voltage_table_size = ARRAY_SIZE(ldo2_voltage_table), .control_reg = LDO2_CONTROL_REG, .low_power_reg = LDO2_PWRCTRL_REG, .mask_reset_reg = MASK_RESET_LDO_REG, .mask_reset = LDO2_MASK_RESET, }, { .dt_node_name = "ldo3", .voltage_table = ldo3_voltage_table, .voltage_table_size = ARRAY_SIZE(ldo3_voltage_table), .control_reg = LDO3_CONTROL_REG, .low_power_reg = LDO3_PWRCTRL_REG, .mask_reset_reg = MASK_RESET_LDO_REG, .mask_reset = LDO3_MASK_RESET, }, { .dt_node_name = "ldo4", .voltage_table = ldo4_voltage_table, .voltage_table_size = ARRAY_SIZE(ldo4_voltage_table), .control_reg = LDO4_CONTROL_REG, .low_power_reg = LDO4_PWRCTRL_REG, .mask_reset_reg = MASK_RESET_LDO_REG, .mask_reset = LDO4_MASK_RESET, }, { .dt_node_name = "ldo5", .voltage_table = ldo5_voltage_table, .voltage_table_size = ARRAY_SIZE(ldo5_voltage_table), .control_reg = LDO5_CONTROL_REG, .low_power_reg = LDO5_PWRCTRL_REG, .mask_reset_reg = MASK_RESET_LDO_REG, .mask_reset = LDO5_MASK_RESET, }, { .dt_node_name = "ldo6", .voltage_table = ldo6_voltage_table, .voltage_table_size = ARRAY_SIZE(ldo6_voltage_table), .control_reg = LDO6_CONTROL_REG, .low_power_reg = LDO6_PWRCTRL_REG, .mask_reset_reg = MASK_RESET_LDO_REG, .mask_reset = LDO6_MASK_RESET, }, { .dt_node_name = "vref_ddr", .voltage_table = vref_ddr_voltage_table, .voltage_table_size = ARRAY_SIZE(vref_ddr_voltage_table), .control_reg = VREF_DDR_CONTROL_REG, .low_power_reg = VREF_DDR_PWRCTRL_REG, .mask_reset_reg = MASK_RESET_LDO_REG, .mask_reset = VREF_DDR_MASK_RESET, }, }; #define MAX_REGUL ARRAY_SIZE(regulators_table) static const struct regul_struct *get_regulator_data(const char *name) { uint8_t i; for (i = 0 ; i < MAX_REGUL ; i++) { if (strncmp(name, regulators_table[i].dt_node_name, strlen(regulators_table[i].dt_node_name)) == 0) { return ®ulators_table[i]; } } /* Regulator not found */ panic(); return NULL; } static uint8_t voltage_to_index(const char *name, uint16_t millivolts) { const struct regul_struct *regul = get_regulator_data(name); uint8_t i; for (i = 0 ; i < regul->voltage_table_size ; i++) { if (regul->voltage_table[i] == millivolts) { return i; } } /* Voltage not found */ panic(); return 0; } int stpmic1_powerctrl_on(void) { return stpmic1_register_update(MAIN_CONTROL_REG, PWRCTRL_PIN_VALID, PWRCTRL_PIN_VALID); } int stpmic1_switch_off(void) { return stpmic1_register_update(MAIN_CONTROL_REG, 1, SOFTWARE_SWITCH_OFF_ENABLED); } int stpmic1_regulator_enable(const char *name) { const struct regul_struct *regul = get_regulator_data(name); return stpmic1_register_update(regul->control_reg, BIT(0), BIT(0)); } int stpmic1_regulator_disable(const char *name) { const struct regul_struct *regul = get_regulator_data(name); return stpmic1_register_update(regul->control_reg, 0, BIT(0)); } uint8_t stpmic1_is_regulator_enabled(const char *name) { uint8_t val; const struct regul_struct *regul = get_regulator_data(name); if (stpmic1_register_read(regul->control_reg, &val) != 0) { panic(); } return (val & 0x1U); } int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts) { uint8_t voltage_index = voltage_to_index(name, millivolts); const struct regul_struct *regul = get_regulator_data(name); uint8_t mask; /* Voltage can be set for buck or ldo (except ldo4) regulators */ if (strncmp(name, "buck", 4) == 0) { mask = BUCK_VOLTAGE_MASK; } else if ((strncmp(name, "ldo", 3) == 0) && (strncmp(name, "ldo4", 4) != 0)) { mask = LDO_VOLTAGE_MASK; } else { return 0; } return stpmic1_register_update(regul->control_reg, voltage_index << LDO_BUCK_VOLTAGE_SHIFT, mask); } int stpmic1_regulator_pull_down_set(const char *name) { const struct regul_struct *regul = get_regulator_data(name); if (regul->pull_down_reg != 0) { return stpmic1_register_update(regul->pull_down_reg, BIT(regul->pull_down), LDO_BUCK_PULL_DOWN_MASK << regul->pull_down); } return 0; } int stpmic1_regulator_mask_reset_set(const char *name) { const struct regul_struct *regul = get_regulator_data(name); return stpmic1_register_update(regul->mask_reset_reg, BIT(regul->mask_reset), LDO_BUCK_RESET_MASK << regul->mask_reset); } int stpmic1_regulator_voltage_get(const char *name) { const struct regul_struct *regul = get_regulator_data(name); uint8_t value; uint8_t mask; /* Voltage can be set for buck or ldo (except ldo4) regulators */ if (strncmp(name, "buck", 4) == 0) { mask = BUCK_VOLTAGE_MASK; } else if ((strncmp(name, "ldo", 3) == 0) && (strncmp(name, "ldo4", 4) != 0)) { mask = LDO_VOLTAGE_MASK; } else { return 0; } if (stpmic1_register_read(regul->control_reg, &value)) return -1; value = (value & mask) >> LDO_BUCK_VOLTAGE_SHIFT; if (value > regul->voltage_table_size) return -1; return (int)regul->voltage_table[value]; } int stpmic1_register_read(uint8_t register_id, uint8_t *value) { return stm32_i2c_mem_read(pmic_i2c_handle, pmic_i2c_addr, (uint16_t)register_id, I2C_MEMADD_SIZE_8BIT, value, 1, I2C_TIMEOUT_MS); } int stpmic1_register_write(uint8_t register_id, uint8_t value) { int status; status = stm32_i2c_mem_write(pmic_i2c_handle, pmic_i2c_addr, (uint16_t)register_id, I2C_MEMADD_SIZE_8BIT, &value, 1, I2C_TIMEOUT_MS); #if ENABLE_ASSERTIONS if (status != 0) { return status; } if ((register_id != WATCHDOG_CONTROL_REG) && (register_id <= 0x40U)) { uint8_t readval; status = stpmic1_register_read(register_id, &readval); if (status != 0) { return status; } if (readval != value) { return -1; } } #endif return status; } int stpmic1_register_update(uint8_t register_id, uint8_t value, uint8_t mask) { int status; uint8_t val; status = stpmic1_register_read(register_id, &val); if (status != 0) { return status; } val = (val & ~mask) | (value & mask); return stpmic1_register_write(register_id, val); } void stpmic1_bind_i2c(struct i2c_handle_s *i2c_handle, uint16_t i2c_addr) { pmic_i2c_handle = i2c_handle; pmic_i2c_addr = i2c_addr; } void stpmic1_dump_regulators(void) { uint32_t i; for (i = 0U; i < MAX_REGUL; i++) { const char *name __unused = regulators_table[i].dt_node_name; VERBOSE("PMIC regul %s: %sable, %dmV", name, stpmic1_is_regulator_enabled(name) ? "en" : "dis", stpmic1_regulator_voltage_get(name)); } } int stpmic1_get_version(unsigned long *version) { int rc; uint8_t read_val; rc = stpmic1_register_read(VERSION_STATUS_REG, &read_val); if (rc) { return -1; } *version = (unsigned long)read_val; return 0; } trusted-firmware-a-2.2/drivers/st/reset/000077500000000000000000000000001355360272700203375ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/st/reset/stm32mp1_reset.c000066400000000000000000000026441355360272700233010ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #define RESET_TIMEOUT_US_1MS U(1000) static uint32_t id2reg_offset(unsigned int reset_id) { return ((reset_id & GENMASK(31, 5)) >> 5) * sizeof(uint32_t); } 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)); uint64_t timeout_ref; uintptr_t rcc_base = stm32mp_rcc_base(); mmio_write_32(rcc_base + offset, bitmsk); timeout_ref = timeout_init_us(RESET_TIMEOUT_US_1MS); while ((mmio_read_32(rcc_base + offset) & bitmsk) == 0U) { if (timeout_elapsed(timeout_ref)) { panic(); } } } void stm32mp_reset_deassert(uint32_t id) { uint32_t offset = id2reg_offset(id) + RCC_RSTCLRR_OFFSET; uint32_t bitmsk = BIT(id2reg_bit_pos(id)); uint64_t timeout_ref; uintptr_t rcc_base = stm32mp_rcc_base(); mmio_write_32(rcc_base + offset, bitmsk); timeout_ref = timeout_init_us(RESET_TIMEOUT_US_1MS); while ((mmio_read_32(rcc_base + offset) & bitmsk) != 0U) { if (timeout_elapsed(timeout_ref)) { panic(); } } } trusted-firmware-a-2.2/drivers/st/uart/000077500000000000000000000000001355360272700201705ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/st/uart/aarch32/000077500000000000000000000000001355360272700214135ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/st/uart/aarch32/stm32_console.S000066400000000000000000000145431355360272700242400ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #define USART_TIMEOUT 0x1000 /* * "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 .globl console_stm32_putc .globl console_stm32_flush /* ----------------------------------------------------------------- * int console_core_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. This function will be accessed by console_init * and crash reporting. * * 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, r2, r3 * ----------------------------------------------------------------- */ func console_stm32_core_init /* Check the input base address */ cmp r0, #0 beq core_init_fail #if defined(IMAGE_BL2) /* Check baud rate and uart clock for sanity */ cmp r1, #0 beq core_init_fail cmp r2, #0 beq core_init_fail /* Disable UART */ ldr r3, [r0, #USART_CR1] bic r3, r3, #USART_CR1_UE str r3, [r0, #USART_CR1] /* Configure UART */ orr r3, r3, #(USART_CR1_TE | USART_CR1_FIFOEN) str r3, [r0, #USART_CR1] ldr r3, [r0, #USART_CR2] bic r3, r3, #USART_CR2_STOP str r3, [r0, #USART_CR2] /* Divisor = (Uart clock + (baudrate / 2)) / baudrate */ lsl r3, r2, #1 add r3, r1, r3 udiv r3, r3, r2 str r3, [r0, #USART_BRR] /* Enable UART */ ldr r3, [r0, #USART_CR1] orr r3, r3, #USART_CR1_UE str r3, [r0, #USART_CR1] /* Check TEACK bit */ mov r2, #USART_TIMEOUT teack_loop: subs r2, r2, #1 beq core_init_fail ldr r3, [r0, #USART_ISR] tst r3, #USART_ISR_TEACK beq teack_loop #endif /* IMAGE_BL2 */ mov r0, #1 bx lr core_init_fail: mov r0, #0 bx lr 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. * * In : r0 - character to be printed * r1 - console base address * Out : return -1 on error else return character. * Clobber list : r2 * --------------------------------------------------------------- */ func console_stm32_core_putc /* Check the input parameter */ cmp r1, #0 beq putc_error /* Check Transmit Data Register Empty */ txe_loop: ldr r2, [r1, #USART_ISR] tst r2, #USART_ISR_TXE beq txe_loop str r0, [r1, #USART_TDR] /* Check transmit complete flag */ tc_loop: ldr r2, [r1, #USART_ISR] tst r2, #USART_ISR_TC beq tc_loop bx lr putc_error: mov r0, #-1 bx lr 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) * * Function to get a character from the console. * It returns the character grabbed on success or -1 on error. * * In : r0 - console base address * Out : return -1. * Clobber list : r0, r1 * ----------------------------------------------------------- */ func console_stm32_core_getc /* Not supported */ mov r0, #-1 bx lr endfunc console_stm32_core_getc /* --------------------------------------------------------------- * int console_core_flush(uintptr_t base_addr) * * Function to force a write of all buffered data that hasn't been * output. * * In : r0 - console base address * Out : return -1 on error else return 0. * Clobber list : r0, r1 * --------------------------------------------------------------- */ func console_stm32_core_flush cmp r0, #0 beq flush_error /* Check Transmit Data Register Empty */ txe_loop_3: ldr r1, [r0, #USART_ISR] tst r1, #USART_ISR_TXE beq txe_loop_3 mov r0, #0 bx lr flush_error: mov r0, #-1 bx lr 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 trusted-firmware-a-2.2/drivers/staging/000077500000000000000000000000001355360272700202235ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/staging/renesas/000077500000000000000000000000001355360272700216635ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/staging/renesas/rcar/000077500000000000000000000000001355360272700226125ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/000077500000000000000000000000001355360272700233635ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/boot_init_dram.h000066400000000000000000000006361355360272700265320ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BOOT_INIT_DRAM_H #define BOOT_INIT_DRAM_H extern int32_t rcar_dram_init(void); #define INITDRAM_OK 0 #define INITDRAM_NG 0xffffffff #define INITDRAM_ERR_I 0xffffffff #define INITDRAM_ERR_O 0xfffffffe #define INITDRAM_ERR_T 0xfffffff0 #endif /* BOOT_INIT_DRAM_H */ trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr.mk000066400000000000000000000011501355360272700244620ustar00rootroot00000000000000# # Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ifeq (${RCAR_LSI},${RCAR_E3}) include drivers/staging/renesas/rcar/ddr/ddr_a/ddr_a.mk BL2_SOURCES += drivers/staging/renesas/rcar/ddr/dram_sub_func.c else ifeq (${RCAR_LSI},${RCAR_D3}) include drivers/staging/renesas/rcar/ddr/ddr_a/ddr_a.mk else ifeq (${RCAR_LSI},${RCAR_V3M}) include drivers/staging/renesas/rcar/ddr/ddr_a/ddr_a.mk else include drivers/staging/renesas/rcar/ddr/ddr_b/ddr_b.mk BL2_SOURCES += drivers/staging/renesas/rcar/ddr/dram_sub_func.c endif trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_a/000077500000000000000000000000001355360272700244345ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_a/boot_init_dram_regdef.h000066400000000000000000000002411355360272700311070ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "../ddr_regs.h" trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_a/ddr_a.mk000066400000000000000000000006311355360272700260360ustar00rootroot00000000000000# # Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ifeq (${RCAR_LSI},${RCAR_E3}) BL2_SOURCES += drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_e3.c else ifeq (${RCAR_LSI},${RCAR_D3}) BL2_SOURCES += drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_d3.c else BL2_SOURCES += drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_v3m.c endif trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_d3.c000066400000000000000000000621531355360272700267710ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "rcar_def.h" #include "../ddr_regs.h" #define RCAR_DDR_VERSION "rev.0.01" #if RCAR_LSI != RCAR_D3 #error "Don't have DDR initialize routine." #endif static void init_ddr_d3_1866(void) { uint32_t i, r2, r3, r5, r6, r7, r12; mmio_write_32(DBSC_DBSYSCNT0, 0x00001234); mmio_write_32(DBSC_DBKIND, 0x00000007); mmio_write_32(DBSC_DBMEMCONF_0_0, 0x0f030a01); mmio_write_32(DBSC_DBPHYCONF0, 0x00000001); mmio_write_32(DBSC_DBTR0, 0x0000000D); mmio_write_32(DBSC_DBTR1, 0x00000009); mmio_write_32(DBSC_DBTR2, 0x00000000); mmio_write_32(DBSC_DBTR3, 0x0000000D); mmio_write_32(DBSC_DBTR4, 0x000D000D); mmio_write_32(DBSC_DBTR5, 0x0000002D); mmio_write_32(DBSC_DBTR6, 0x00000020); mmio_write_32(DBSC_DBTR7, 0x00060006); mmio_write_32(DBSC_DBTR8, 0x00000021); mmio_write_32(DBSC_DBTR9, 0x00000007); mmio_write_32(DBSC_DBTR10, 0x0000000E); mmio_write_32(DBSC_DBTR11, 0x0000000C); mmio_write_32(DBSC_DBTR12, 0x00140014); mmio_write_32(DBSC_DBTR13, 0x000000F2); mmio_write_32(DBSC_DBTR14, 0x00170006); mmio_write_32(DBSC_DBTR15, 0x00060005); mmio_write_32(DBSC_DBTR16, 0x09210507); mmio_write_32(DBSC_DBTR17, 0x040E0000); mmio_write_32(DBSC_DBTR18, 0x00000200); mmio_write_32(DBSC_DBTR19, 0x012B004B); mmio_write_32(DBSC_DBTR20, 0x020000FB); mmio_write_32(DBSC_DBTR21, 0x00040004); mmio_write_32(DBSC_DBBL, 0x00000000); mmio_write_32(DBSC_DBODT0, 0x00000001); mmio_write_32(DBSC_DBADJ0, 0x00000001); mmio_write_32(DBSC_DBSYSCONF1, 0x00000002); mmio_write_32(DBSC_DBDFICNT_0, 0x00000010); mmio_write_32(DBSC_DBBCAMDIS, 0x00000001); mmio_write_32(DBSC_DBSCHRW1, 0x00000046); mmio_write_32(DBSC_SCFCTST0, 0x0D020D04); mmio_write_32(DBSC_SCFCTST1, 0x0306040C); mmio_write_32(DBSC_DBPDLK_0, 0x0000A55A); mmio_write_32(DBSC_DBCMD, 0x01000001); mmio_write_32(DBSC_DBCMD, 0x08000000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x80010000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000008); mmio_write_32(DBSC_DBPDRGD_0, 0x000B8000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); mmio_write_32(DBSC_DBPDRGD_0, 0x04058A04); mmio_write_32(DBSC_DBPDRGA_0, 0x00000091); mmio_write_32(DBSC_DBPDRGD_0, 0x0007BB6B); mmio_write_32(DBSC_DBPDRGA_0, 0x00000095); mmio_write_32(DBSC_DBPDRGD_0, 0x0007BBAD); mmio_write_32(DBSC_DBPDRGA_0, 0x00000099); mmio_write_32(DBSC_DBPDRGD_0, 0x0007BB6B); mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); mmio_write_32(DBSC_DBPDRGD_0, 0x04058A00); mmio_write_32(DBSC_DBPDRGA_0, 0x00000021); mmio_write_32(DBSC_DBPDRGD_0, 0x0024641E); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010073); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); mmio_write_32(DBSC_DBPDRGD_0, 0x0C058A00); mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); mmio_write_32(DBSC_DBPDRGD_0, 0x04058A00); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000003); mmio_write_32(DBSC_DBPDRGD_0, 0x0780C700); mmio_write_32(DBSC_DBPDRGA_0, 0x00000007); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(30))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000004); mmio_write_32(DBSC_DBPDRGD_0, 0x0A206F89); mmio_write_32(DBSC_DBPDRGA_0, 0x00000022); mmio_write_32(DBSC_DBPDRGD_0, 0x1000040B); mmio_write_32(DBSC_DBPDRGA_0, 0x00000023); mmio_write_32(DBSC_DBPDRGD_0, 0x35A00D77); mmio_write_32(DBSC_DBPDRGA_0, 0x00000024); mmio_write_32(DBSC_DBPDRGD_0, 0x2A8A2C28); mmio_write_32(DBSC_DBPDRGA_0, 0x00000025); mmio_write_32(DBSC_DBPDRGD_0, 0x30005E00); mmio_write_32(DBSC_DBPDRGA_0, 0x00000026); mmio_write_32(DBSC_DBPDRGD_0, 0x0014CB49); mmio_write_32(DBSC_DBPDRGA_0, 0x00000027); mmio_write_32(DBSC_DBPDRGD_0, 0x00000F14); mmio_write_32(DBSC_DBPDRGA_0, 0x00000028); mmio_write_32(DBSC_DBPDRGD_0, 0x00000046); mmio_write_32(DBSC_DBPDRGA_0, 0x00000029); mmio_write_32(DBSC_DBPDRGD_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGA_0, 0x0000002C); mmio_write_32(DBSC_DBPDRGD_0, 0x81003047); mmio_write_32(DBSC_DBPDRGA_0, 0x00000020); mmio_write_32(DBSC_DBPDRGD_0, 0x00181884); mmio_write_32(DBSC_DBPDRGA_0, 0x0000001A); mmio_write_32(DBSC_DBPDRGD_0, 0x33C03C10); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x000000A7); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A8); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A9); mmio_write_32(DBSC_DBPDRGD_0, 0x000D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C7); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C8); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C9); mmio_write_32(DBSC_DBPDRGD_0, 0x000D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x0000000E); r2 = (mmio_read_32(DBSC_DBPDRGD_0) & 0x0000FF00) >> 0x9; r3 = (r2 << 16) + (r2 << 8) + r2; r6 = (r2 << 24) + (r2 << 16) + (r2 << 8) + r2; mmio_write_32(DBSC_DBPDRGA_0, 0x00000011); mmio_write_32(DBSC_DBPDRGD_0, r3); mmio_write_32(DBSC_DBPDRGA_0, 0x00000012); mmio_write_32(DBSC_DBPDRGD_0, r3); mmio_write_32(DBSC_DBPDRGA_0, 0x00000016); mmio_write_32(DBSC_DBPDRGD_0, r6); mmio_write_32(DBSC_DBPDRGA_0, 0x00000017); mmio_write_32(DBSC_DBPDRGD_0, r6); mmio_write_32(DBSC_DBPDRGA_0, 0x00000018); mmio_write_32(DBSC_DBPDRGD_0, r6); mmio_write_32(DBSC_DBPDRGA_0, 0x00000019); mmio_write_32(DBSC_DBPDRGD_0, r6); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010181); mmio_write_32(DBSC_DBCMD, 0x08000001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010601); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; for (i = 0; i < 2; i++) { mmio_write_32(DBSC_DBPDRGA_0, 0xB1 + i * 0x20); r5 = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFF00) >> 0x8; mmio_write_32(DBSC_DBPDRGA_0, 0xB4 + i * 0x20); r6 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFF; mmio_write_32(DBSC_DBPDRGA_0, 0xB3 + i * 0x20); r7 = mmio_read_32(DBSC_DBPDRGD_0) & 0x7; if (r6 > 0) { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r7 + 0x1) & 0x7)); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | r6); } else { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | r7); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r6 + (r5 << 1)) & 0xFF)); } } mmio_write_32(DBSC_DBPDRGA_0, 0x00000005); mmio_write_32(DBSC_DBPDRGD_0, 0xC1AA00C0); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010801); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000005); mmio_write_32(DBSC_DBPDRGD_0, 0xC1AA00D8); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x0001F001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x000000AF); r2 = mmio_read_32(DBSC_DBPDRGD_0); mmio_write_32(DBSC_DBPDRGD_0, ((r2 + 0x1) & 0xFF) | (r2 & 0xFFFFFF00)); mmio_write_32(DBSC_DBPDRGA_0, 0x000000CF); r2 = mmio_read_32(DBSC_DBPDRGD_0); mmio_write_32(DBSC_DBPDRGD_0, ((r2 + 0x1) & 0xFF) | (r2 & 0xFFFFFF00)); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x0000002C); mmio_write_32(DBSC_DBPDRGD_0, 0x81003087); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010401); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; for (i = 0; i < 2; i++) { mmio_write_32(DBSC_DBPDRGA_0, 0xB1 + i * 0x20); r5 = ((mmio_read_32(DBSC_DBPDRGD_0) & 0xFF00) >> 0x8); mmio_write_32(DBSC_DBPDRGA_0, 0xB4 + i * 0x20); r6 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFF; mmio_write_32(DBSC_DBPDRGA_0, 0xB3 + i * 0x20); r7 = mmio_read_32(DBSC_DBPDRGD_0) & 0x7; r12 = (r5 >> 0x2); if (r12 < r6) { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r7 + 0x1) & 0x7)); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r6 - r12) & 0xFF)); } else { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | (r7 & 0x7)); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r6 + r5 + (r5 >> 1) + r12) & 0xFF)); } } mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00015001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000003); mmio_write_32(DBSC_DBPDRGD_0, 0x0380C700); mmio_write_32(DBSC_DBPDRGA_0, 0x00000007); while (mmio_read_32(DBSC_DBPDRGD_0) & BIT(30)) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000021); mmio_write_32(DBSC_DBPDRGD_0, 0x0024643E); mmio_write_32(DBSC_DBBUS0CNF1, 0x00000010); mmio_write_32(DBSC_DBCALCNF, 0x0100401B); mmio_write_32(DBSC_DBRFCNF1, 0x00080E23); mmio_write_32(DBSC_DBRFCNF2, 0x00010000); mmio_write_32(DBSC_DBDFICUPDCNF, 0x40100001); mmio_write_32(DBSC_DBRFEN, 0x00000001); mmio_write_32(DBSC_DBACEN, 0x00000001); mmio_write_32(DBSC_DBPDLK_0, 0x00000000); mmio_write_32(DBSC_DBSYSCNT0, 0x00000000); #ifdef ddr_qos_init_setting // only for non qos_init mmio_write_32(DBSC_DBSYSCNT0, 0x00001234); mmio_write_32(DBSC_DBCAM0CNF1, 0x00043218); mmio_write_32(DBSC_DBCAM0CNF2, 0x000000F4); mmio_write_32(DBSC_DBSCHCNT0, 0x000f0037); mmio_write_32(DBSC_DBSCHSZ0, 0x00000001); mmio_write_32(DBSC_DBSCHRW0, 0x22421111); mmio_write_32(DBSC_SCFCTST2, 0x012F1123); mmio_write_32(DBSC_DBSCHQOS00, 0x00000F00); mmio_write_32(DBSC_DBSCHQOS01, 0x00000B00); mmio_write_32(DBSC_DBSCHQOS02, 0x00000000); mmio_write_32(DBSC_DBSCHQOS03, 0x00000000); mmio_write_32(DBSC_DBSCHQOS40, 0x00000300); mmio_write_32(DBSC_DBSCHQOS41, 0x000002F0); mmio_write_32(DBSC_DBSCHQOS42, 0x00000200); mmio_write_32(DBSC_DBSCHQOS43, 0x00000100); mmio_write_32(DBSC_DBSCHQOS90, 0x00000300); mmio_write_32(DBSC_DBSCHQOS91, 0x000002F0); mmio_write_32(DBSC_DBSCHQOS92, 0x00000200); mmio_write_32(DBSC_DBSCHQOS93, 0x00000100); mmio_write_32(DBSC_DBSCHQOS130, 0x00000100); mmio_write_32(DBSC_DBSCHQOS131, 0x000000F0); mmio_write_32(DBSC_DBSCHQOS132, 0x000000A0); mmio_write_32(DBSC_DBSCHQOS133, 0x00000040); mmio_write_32(DBSC_DBSCHQOS140, 0x000000C0); mmio_write_32(DBSC_DBSCHQOS141, 0x000000B0); mmio_write_32(DBSC_DBSCHQOS142, 0x00000080); mmio_write_32(DBSC_DBSCHQOS143, 0x00000040); mmio_write_32(DBSC_DBSCHQOS150, 0x00000040); mmio_write_32(DBSC_DBSCHQOS151, 0x00000030); mmio_write_32(DBSC_DBSCHQOS152, 0x00000020); mmio_write_32(DBSC_DBSCHQOS153, 0x00000010); mmio_write_32(0xE67F0018, 0x00000001); mmio_write_32(DBSC_DBSYSCNT0, 0x00000000); #endif } static void init_ddr_d3_1600(void) { uint32_t i, r2, r3, r5, r6, r7, r12; mmio_write_32(DBSC_DBSYSCNT0, 0x00001234); mmio_write_32(DBSC_DBKIND, 0x00000007); mmio_write_32(DBSC_DBMEMCONF_0_0, 0x0f030a01); mmio_write_32(DBSC_DBPHYCONF0, 0x00000001); mmio_write_32(DBSC_DBTR0, 0x0000000B); mmio_write_32(DBSC_DBTR1, 0x00000008); mmio_write_32(DBSC_DBTR2, 0x00000000); mmio_write_32(DBSC_DBTR3, 0x0000000B); mmio_write_32(DBSC_DBTR4, 0x000B000B); mmio_write_32(DBSC_DBTR5, 0x00000027); mmio_write_32(DBSC_DBTR6, 0x0000001C); mmio_write_32(DBSC_DBTR7, 0x00060006); mmio_write_32(DBSC_DBTR8, 0x00000020); mmio_write_32(DBSC_DBTR9, 0x00000006); mmio_write_32(DBSC_DBTR10, 0x0000000C); mmio_write_32(DBSC_DBTR11, 0x0000000A); mmio_write_32(DBSC_DBTR12, 0x00120012); mmio_write_32(DBSC_DBTR13, 0x000000D0); mmio_write_32(DBSC_DBTR14, 0x00140005); mmio_write_32(DBSC_DBTR15, 0x00050004); mmio_write_32(DBSC_DBTR16, 0x071F0305); mmio_write_32(DBSC_DBTR17, 0x040C0000); mmio_write_32(DBSC_DBTR18, 0x00000200); mmio_write_32(DBSC_DBTR19, 0x01000040); mmio_write_32(DBSC_DBTR20, 0x020000D8); mmio_write_32(DBSC_DBTR21, 0x00040004); mmio_write_32(DBSC_DBBL, 0x00000000); mmio_write_32(DBSC_DBODT0, 0x00000001); mmio_write_32(DBSC_DBADJ0, 0x00000001); mmio_write_32(DBSC_DBSYSCONF1, 0x00000002); mmio_write_32(DBSC_DBDFICNT_0, 0x00000010); mmio_write_32(DBSC_DBBCAMDIS, 0x00000001); mmio_write_32(DBSC_DBSCHRW1, 0x00000046); mmio_write_32(DBSC_SCFCTST0, 0x0D020C04); mmio_write_32(DBSC_SCFCTST1, 0x0305040C); mmio_write_32(DBSC_DBPDLK_0, 0x0000A55A); mmio_write_32(DBSC_DBCMD, 0x01000001); mmio_write_32(DBSC_DBCMD, 0x08000000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x80010000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000008); mmio_write_32(DBSC_DBPDRGD_0, 0x000B8000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); mmio_write_32(DBSC_DBPDRGD_0, 0x04058904); mmio_write_32(DBSC_DBPDRGA_0, 0x00000091); mmio_write_32(DBSC_DBPDRGD_0, 0x0007BB6B); mmio_write_32(DBSC_DBPDRGA_0, 0x00000095); mmio_write_32(DBSC_DBPDRGD_0, 0x0007BBAD); mmio_write_32(DBSC_DBPDRGA_0, 0x00000099); mmio_write_32(DBSC_DBPDRGD_0, 0x0007BB6B); mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); mmio_write_32(DBSC_DBPDRGD_0, 0x04058900); mmio_write_32(DBSC_DBPDRGA_0, 0x00000021); mmio_write_32(DBSC_DBPDRGD_0, 0x0024641E); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010073); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); mmio_write_32(DBSC_DBPDRGD_0, 0x0C058900); mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); mmio_write_32(DBSC_DBPDRGD_0, 0x04058900); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000003); mmio_write_32(DBSC_DBPDRGD_0, 0x0780C700); mmio_write_32(DBSC_DBPDRGA_0, 0x00000007); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(30))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000004); mmio_write_32(DBSC_DBPDRGD_0, 0x08C05FF0); mmio_write_32(DBSC_DBPDRGA_0, 0x00000022); mmio_write_32(DBSC_DBPDRGD_0, 0x1000040B); mmio_write_32(DBSC_DBPDRGA_0, 0x00000023); mmio_write_32(DBSC_DBPDRGD_0, 0x2D9C0B66); mmio_write_32(DBSC_DBPDRGA_0, 0x00000024); mmio_write_32(DBSC_DBPDRGD_0, 0x2A88C400); mmio_write_32(DBSC_DBPDRGA_0, 0x00000025); mmio_write_32(DBSC_DBPDRGD_0, 0x30005200); mmio_write_32(DBSC_DBPDRGA_0, 0x00000026); mmio_write_32(DBSC_DBPDRGD_0, 0x0014A9C9); mmio_write_32(DBSC_DBPDRGA_0, 0x00000027); mmio_write_32(DBSC_DBPDRGD_0, 0x00000D70); mmio_write_32(DBSC_DBPDRGA_0, 0x00000028); mmio_write_32(DBSC_DBPDRGD_0, 0x00000046); mmio_write_32(DBSC_DBPDRGA_0, 0x00000029); mmio_write_32(DBSC_DBPDRGD_0, 0x00000098); mmio_write_32(DBSC_DBPDRGA_0, 0x0000002C); mmio_write_32(DBSC_DBPDRGD_0, 0x81003047); mmio_write_32(DBSC_DBPDRGA_0, 0x00000020); mmio_write_32(DBSC_DBPDRGD_0, 0x00181884); mmio_write_32(DBSC_DBPDRGA_0, 0x0000001A); mmio_write_32(DBSC_DBPDRGD_0, 0x33C03C10); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x000000A7); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A8); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A9); mmio_write_32(DBSC_DBPDRGD_0, 0x000D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C7); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C8); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C9); mmio_write_32(DBSC_DBPDRGD_0, 0x000D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x0000000E); r2 = (mmio_read_32(DBSC_DBPDRGD_0) & 0x0000FF00) >> 0x9; r3 = (r2 << 16) + (r2 << 8) + r2; r6 = (r2 << 24) + (r2 << 16) + (r2 << 8) + r2; mmio_write_32(DBSC_DBPDRGA_0, 0x00000011); mmio_write_32(DBSC_DBPDRGD_0, r3); mmio_write_32(DBSC_DBPDRGA_0, 0x00000012); mmio_write_32(DBSC_DBPDRGD_0, r3); mmio_write_32(DBSC_DBPDRGA_0, 0x00000016); mmio_write_32(DBSC_DBPDRGD_0, r6); mmio_write_32(DBSC_DBPDRGA_0, 0x00000017); mmio_write_32(DBSC_DBPDRGD_0, r6); mmio_write_32(DBSC_DBPDRGA_0, 0x00000018); mmio_write_32(DBSC_DBPDRGD_0, r6); mmio_write_32(DBSC_DBPDRGA_0, 0x00000019); mmio_write_32(DBSC_DBPDRGD_0, r6); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010181); mmio_write_32(DBSC_DBCMD, 0x08000001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010601); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; for (i = 0; i < 2; i++) { mmio_write_32(DBSC_DBPDRGA_0, 0xB1 + i * 0x20); r5 = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFF00) >> 0x8; mmio_write_32(DBSC_DBPDRGA_0, 0xB4 + i * 0x20); r6 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFF; mmio_write_32(DBSC_DBPDRGA_0, 0xB3 + i * 0x20); r7 = mmio_read_32(DBSC_DBPDRGD_0) & 0x7; if (r6 > 0) { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r7 + 0x1) & 0x7)); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | r6); } else { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | r7); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r6 + (r5 << 1)) & 0xFF)); } } mmio_write_32(DBSC_DBPDRGA_0, 0x00000005); mmio_write_32(DBSC_DBPDRGD_0, 0xC1AA00C0); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010801); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000005); mmio_write_32(DBSC_DBPDRGD_0, 0xC1AA00D8); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x0001F001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x000000AF); r2 = mmio_read_32(DBSC_DBPDRGD_0); mmio_write_32(DBSC_DBPDRGD_0, ((r2 + 0x1) & 0xFF) | (r2 & 0xFFFFFF00)); mmio_write_32(DBSC_DBPDRGA_0, 0x000000CF); r2 = mmio_read_32(DBSC_DBPDRGD_0); mmio_write_32(DBSC_DBPDRGD_0, ((r2 + 0x1) & 0xFF) | (r2 & 0xFFFFFF00)); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x0000002C); mmio_write_32(DBSC_DBPDRGD_0, 0x81003087); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010401); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; for (i = 0; i < 2; i++) { mmio_write_32(DBSC_DBPDRGA_0, 0xB1 + i * 0x20); r5 = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFF00) >> 0x8; mmio_write_32(DBSC_DBPDRGA_0, 0xB4 + i * 0x20); r6 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFF; mmio_write_32(DBSC_DBPDRGA_0, 0xB3 + i * 0x20); r7 = mmio_read_32(DBSC_DBPDRGD_0) & 0x7; r12 = (r5 >> 0x2); if (r12 < r6) { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r7 + 0x1) & 0x7)); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r6 - r12) & 0xFF)); } else { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | (r7 & 0x7)); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r6 + r5 + (r5 >> 1) + r12) & 0xFF)); } } mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00015001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000003); mmio_write_32(DBSC_DBPDRGD_0, 0x0380C700); mmio_write_32(DBSC_DBPDRGA_0, 0x00000007); while (mmio_read_32(DBSC_DBPDRGD_0) & BIT(30)) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000021); mmio_write_32(DBSC_DBPDRGD_0, 0x0024643E); mmio_write_32(DBSC_DBBUS0CNF1, 0x00000010); mmio_write_32(DBSC_DBCALCNF, 0x0100401B); mmio_write_32(DBSC_DBRFCNF1, 0x00080C30); mmio_write_32(DBSC_DBRFCNF2, 0x00010000); mmio_write_32(DBSC_DBDFICUPDCNF, 0x40100001); mmio_write_32(DBSC_DBRFEN, 0x00000001); mmio_write_32(DBSC_DBACEN, 0x00000001); mmio_write_32(DBSC_DBPDLK_0, 0x00000000); mmio_write_32(DBSC_DBSYSCNT0, 0x00000000); #ifdef ddr_qos_init_setting // only for non qos_init mmio_write_32(DBSC_DBSYSCNT0, 0x00001234); mmio_write_32(DBSC_DBCAM0CNF1, 0x00043218); mmio_write_32(DBSC_DBCAM0CNF2, 0x000000F4); mmio_write_32(DBSC_DBSCHCNT0, 0x000f0037); mmio_write_32(DBSC_DBSCHSZ0, 0x00000001); mmio_write_32(DBSC_DBSCHRW0, 0x22421111); mmio_write_32(DBSC_SCFCTST2, 0x012F1123); mmio_write_32(DBSC_DBSCHQOS00, 0x00000F00); mmio_write_32(DBSC_DBSCHQOS01, 0x00000B00); mmio_write_32(DBSC_DBSCHQOS02, 0x00000000); mmio_write_32(DBSC_DBSCHQOS03, 0x00000000); mmio_write_32(DBSC_DBSCHQOS40, 0x00000300); mmio_write_32(DBSC_DBSCHQOS41, 0x000002F0); mmio_write_32(DBSC_DBSCHQOS42, 0x00000200); mmio_write_32(DBSC_DBSCHQOS43, 0x00000100); mmio_write_32(DBSC_DBSCHQOS90, 0x00000300); mmio_write_32(DBSC_DBSCHQOS91, 0x000002F0); mmio_write_32(DBSC_DBSCHQOS92, 0x00000200); mmio_write_32(DBSC_DBSCHQOS93, 0x00000100); mmio_write_32(DBSC_DBSCHQOS130, 0x00000100); mmio_write_32(DBSC_DBSCHQOS131, 0x000000F0); mmio_write_32(DBSC_DBSCHQOS132, 0x000000A0); mmio_write_32(DBSC_DBSCHQOS133, 0x00000040); mmio_write_32(DBSC_DBSCHQOS140, 0x000000C0); mmio_write_32(DBSC_DBSCHQOS141, 0x000000B0); mmio_write_32(DBSC_DBSCHQOS142, 0x00000080); mmio_write_32(DBSC_DBSCHQOS143, 0x00000040); mmio_write_32(DBSC_DBSCHQOS150, 0x00000040); mmio_write_32(DBSC_DBSCHQOS151, 0x00000030); mmio_write_32(DBSC_DBSCHQOS152, 0x00000020); mmio_write_32(DBSC_DBSCHQOS153, 0x00000010); mmio_write_32(0xE67F0018, 0x00000001); mmio_write_32(DBSC_DBSYSCNT0, 0x00000000); #endif } #define PRR 0xFFF00044U #define PRR_PRODUCT_MASK 0x00007F00U #define PRR_PRODUCT_D3 0x00005800U #define MODEMR_MD19 BIT(19) int32_t rcar_dram_init(void) { uint32_t reg; uint32_t ddr_mbps; reg = mmio_read_32(PRR); if ((reg & PRR_PRODUCT_MASK) != PRR_PRODUCT_D3) { ERROR("LSI Product ID (PRR=0x%x) DDR initialize not supported.\n", reg); panic(); } reg = mmio_read_32(RST_MODEMR); if (reg & MODEMR_MD19) { init_ddr_d3_1866(); ddr_mbps = 1866; } else { init_ddr_d3_1600(); ddr_mbps = 1600; } NOTICE("BL2: DDR%d\n", ddr_mbps); return 0; } trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_e3.c000066400000000000000000001535171355360272700267770ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "boot_init_dram.h" #include "rcar_def.h" #include "../ddr_regs.h" #include "../dram_sub_func.h" #define RCAR_E3_DDR_VERSION "rev.0.12" /* Average periodic refresh interval[ns]. Support 3900,7800 */ #ifdef ddr_qos_init_setting #define REFRESH_RATE 3900U #else #if RCAR_REF_INT == 1 #define REFRESH_RATE 7800U #else #define REFRESH_RATE 3900U #endif #endif /* * Initialize ddr */ uint32_t init_ddr(void) { uint32_t i, r2, r5, r6, r7, r12; uint32_t ddr_md; uint32_t regval, j; uint32_t dqsgd_0c, bdlcount_0c, bdlcount_0c_div2, bdlcount_0c_div4; uint32_t bdlcount_0c_div8, bdlcount_0c_div16; uint32_t gatesl_0c, rdqsd_0c, rdqsnd_0c, rbd_0c[4]; uint32_t pdqsr_ctl, lcdl_ctl, lcdl_judge1, lcdl_judge2; uint32_t pdr_ctl; uint32_t byp_ctl; if ((mmio_read_32(0xFFF00044) & 0x000000FF) == 0x00000000) { pdqsr_ctl = 1; lcdl_ctl = 1; pdr_ctl = 1; byp_ctl = 1; } else { pdqsr_ctl = 0; lcdl_ctl = 0; pdr_ctl = 0; byp_ctl = 0; } /* Judge the DDR bit rate (ddr_md : 0 = 1584Mbps, 1 = 1856Mbps) */ ddr_md = (mmio_read_32(RST_MODEMR) >> 19) & BIT(0); /* 1584Mbps setting */ if (ddr_md == 0) { mmio_write_32(CPG_CPGWPR, 0x5A5AFFFF); mmio_write_32(CPG_CPGWPCR, 0xA5A50000); mmio_write_32(CPG_SRCR4, 0x20000000); mmio_write_32(0xE61500DC, 0xe2200000); /* Change to 1584Mbps */ while (!(mmio_read_32(CPG_PLLECR) & BIT(11))) ; mmio_write_32(CPG_SRSTCLR4, 0x20000000); mmio_write_32(CPG_CPGWPCR, 0xA5A50001); } mmio_write_32(DBSC_DBSYSCNT0, 0x00001234); mmio_write_32(DBSC_DBKIND, 0x00000007); #if RCAR_DRAM_DDR3L_MEMCONF == 0 mmio_write_32(DBSC_DBMEMCONF_0_0, 0x0f030a02); /* 1GB */ #else mmio_write_32(DBSC_DBMEMCONF_0_0, 0x10030a02); /* 2GB(default) */ #endif #if RCAR_DRAM_DDR3L_MEMDUAL == 1 r2 = mmio_read_32(0xE6790614); mmio_write_32(0xE6790614, r2 | 0x3); /* MCS1_N/MODT1 are activated. */ #endif mmio_write_32(DBSC_DBPHYCONF0, 0x1); /* Select setting value in bps */ if (ddr_md == 0) { /* 1584Mbps */ mmio_write_32(DBSC_DBTR0, 0xB); mmio_write_32(DBSC_DBTR1, 0x8); } else { /* 1856Mbps */ mmio_write_32(DBSC_DBTR0, 0xD); mmio_write_32(DBSC_DBTR1, 0x9); } mmio_write_32(DBSC_DBTR2, 0x00000000); /* Select setting value in bps */ if (ddr_md == 0) { /* 1584Mbps */ mmio_write_32(DBSC_DBTR3, 0x0000000B); mmio_write_32(DBSC_DBTR4, 0x000B000B); mmio_write_32(DBSC_DBTR5, 0x00000027); mmio_write_32(DBSC_DBTR6, 0x0000001C); } else { /* 1856Mbps */ mmio_write_32(DBSC_DBTR3, 0x0000000D); mmio_write_32(DBSC_DBTR4, 0x000D000D); mmio_write_32(DBSC_DBTR5, 0x0000002D); mmio_write_32(DBSC_DBTR6, 0x00000020); } mmio_write_32(DBSC_DBTR7, 0x00060006); /* Select setting value in bps */ if (ddr_md == 0) { /* 1584Mbps */ mmio_write_32(DBSC_DBTR8, 0x00000020); mmio_write_32(DBSC_DBTR9, 0x00000006); mmio_write_32(DBSC_DBTR10, 0x0000000C); mmio_write_32(DBSC_DBTR11, 0x0000000A); mmio_write_32(DBSC_DBTR12, 0x00120012); mmio_write_32(DBSC_DBTR13, 0x000000CE); mmio_write_32(DBSC_DBTR14, 0x00140005); mmio_write_32(DBSC_DBTR15, 0x00050004); mmio_write_32(DBSC_DBTR16, 0x071F0305); mmio_write_32(DBSC_DBTR17, 0x040C0000); } else { /* 1856Mbps */ mmio_write_32(DBSC_DBTR8, 0x00000021); mmio_write_32(DBSC_DBTR9, 0x00000007); mmio_write_32(DBSC_DBTR10, 0x0000000E); mmio_write_32(DBSC_DBTR11, 0x0000000C); mmio_write_32(DBSC_DBTR12, 0x00140014); mmio_write_32(DBSC_DBTR13, 0x000000F2); mmio_write_32(DBSC_DBTR14, 0x00170006); mmio_write_32(DBSC_DBTR15, 0x00060005); mmio_write_32(DBSC_DBTR16, 0x09210507); mmio_write_32(DBSC_DBTR17, 0x040E0000); } mmio_write_32(DBSC_DBTR18, 0x00000200); /* Select setting value in bps */ if (ddr_md == 0) { /* 1584Mbps */ mmio_write_32(DBSC_DBTR19, 0x01000040); mmio_write_32(DBSC_DBTR20, 0x020000D6); } else { /* 1856Mbps */ mmio_write_32(DBSC_DBTR19, 0x0129004B); mmio_write_32(DBSC_DBTR20, 0x020000FB); } mmio_write_32(DBSC_DBTR21, 0x00040004); mmio_write_32(DBSC_DBBL, 0x00000000); mmio_write_32(DBSC_DBODT0, 0x00000001); mmio_write_32(DBSC_DBADJ0, 0x00000001); mmio_write_32(DBSC_DBSYSCONF1, 0x00000002); mmio_write_32(DBSC_DBDFICNT_0, 0x00000010); mmio_write_32(DBSC_DBBCAMDIS, 0x00000001); mmio_write_32(DBSC_DBSCHRW1, 0x00000046); /* Select setting value in bps */ if (ddr_md == 0) { /* 1584Mbps */ mmio_write_32(DBSC_SCFCTST0, 0x0D050B03); mmio_write_32(DBSC_SCFCTST1, 0x0306030C); } else { /* 1856Mbps */ mmio_write_32(DBSC_SCFCTST0, 0x0C050B03); mmio_write_32(DBSC_SCFCTST1, 0x0305030C); } /* * Initial_Step0( INITBYP ) */ mmio_write_32(DBSC_DBPDLK_0, 0x0000A55A); mmio_write_32(DBSC_DBCMD, 0x01840001); mmio_write_32(DBSC_DBCMD, 0x08840000); NOTICE("BL2: [COLD_BOOT]\n"); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x80010000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; /* * Initial_Step1( ZCAL,PLLINIT,DCAL,PHYRST training ) */ mmio_write_32(DBSC_DBPDRGA_0, 0x00000008); mmio_write_32(DBSC_DBPDRGD_0, 0x000B8000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x04058904); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x04058A04); mmio_write_32(DBSC_DBPDRGA_0, 0x00000091); mmio_write_32(DBSC_DBPDRGD_0, 0x0007BB6B); mmio_write_32(DBSC_DBPDRGA_0, 0x00000095); mmio_write_32(DBSC_DBPDRGD_0, 0x0007BBAD); mmio_write_32(DBSC_DBPDRGA_0, 0x00000099); mmio_write_32(DBSC_DBPDRGD_0, 0x0007BB6B); mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x04058900); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x04058A00); mmio_write_32(DBSC_DBPDRGA_0, 0x00000021); mmio_write_32(DBSC_DBPDRGD_0, 0x0024641E); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010073); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; /* * Initial_Step2( DRAMRST/DRAMINT training ) */ mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x0C058900); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x0C058A00); mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x04058900); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x04058A00); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000003); if (byp_ctl == 1) mmio_write_32(DBSC_DBPDRGD_0, 0x0780C720); else mmio_write_32(DBSC_DBPDRGD_0, 0x0780C700); mmio_write_32(DBSC_DBPDRGA_0, 0x00000007); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(30))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000004); /* Select setting value in bps */ if (ddr_md == 0) { /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, (REFRESH_RATE * 792 / 125) - 400 + 0x08B00000); } else { /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, (REFRESH_RATE * 928 / 125) - 400 + 0x0A300000); } mmio_write_32(DBSC_DBPDRGA_0, 0x00000022); mmio_write_32(DBSC_DBPDRGD_0, 0x1000040B); mmio_write_32(DBSC_DBPDRGA_0, 0x00000023); /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x2D9C0B66); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x35A00D77); mmio_write_32(DBSC_DBPDRGA_0, 0x00000024); /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x2A88B400); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x2A8A2C28); mmio_write_32(DBSC_DBPDRGA_0, 0x00000025); /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x30005200); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x30005E00); mmio_write_32(DBSC_DBPDRGA_0, 0x00000026); /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x0014A9C9); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x0014CB49); mmio_write_32(DBSC_DBPDRGA_0, 0x00000027); /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x00000D70); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x00000F14); mmio_write_32(DBSC_DBPDRGA_0, 0x00000028); mmio_write_32(DBSC_DBPDRGD_0, 0x00000046); mmio_write_32(DBSC_DBPDRGA_0, 0x00000029); /* Select setting value in bps */ if (ddr_md == 0) { /* 1584Mbps */ if (REFRESH_RATE > 3900) /* [7]SRT=0 */ mmio_write_32(DBSC_DBPDRGD_0, 0x18); else /* [7]SRT=1 */ mmio_write_32(DBSC_DBPDRGD_0, 0x98); } else { /* 1856Mbps */ if (REFRESH_RATE > 3900) /* [7]SRT=0 */ mmio_write_32(DBSC_DBPDRGD_0, 0x20); else /* [7]SRT=1 */ mmio_write_32(DBSC_DBPDRGD_0, 0xA0); } mmio_write_32(DBSC_DBPDRGA_0, 0x0000002C); mmio_write_32(DBSC_DBPDRGD_0, 0x81003047); mmio_write_32(DBSC_DBPDRGA_0, 0x00000020); mmio_write_32(DBSC_DBPDRGD_0, 0x00181884); mmio_write_32(DBSC_DBPDRGA_0, 0x0000001A); mmio_write_32(DBSC_DBPDRGD_0, 0x33C03C10); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x000000A7); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A8); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A9); mmio_write_32(DBSC_DBPDRGD_0, 0x000D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C7); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C8); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C9); mmio_write_32(DBSC_DBPDRGD_0, 0x000D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E7); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E8); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E9); mmio_write_32(DBSC_DBPDRGD_0, 0x000D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x00000107); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x00000108); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x00000109); mmio_write_32(DBSC_DBPDRGD_0, 0x000D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010181); mmio_write_32(DBSC_DBCMD, 0x08840001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; /* * Initial_Step3( WL/QSG training ) */ mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010601); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; for (i = 0; i < 4; i++) { mmio_write_32(DBSC_DBPDRGA_0, 0xB1 + i * 0x20); r5 = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFF00) >> 0x8; mmio_write_32(DBSC_DBPDRGA_0, 0xB4 + i * 0x20); r6 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFF; mmio_write_32(DBSC_DBPDRGA_0, 0xB3 + i * 0x20); r7 = mmio_read_32(DBSC_DBPDRGD_0) & 0x7; if (r6 > 0) { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r7 + 0x1) & 0x7)); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | r6); } else { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | r7); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r6 + ((r5) << 1)) & 0xFF)); } } /* * Initial_Step4( WLADJ training ) */ mmio_write_32(DBSC_DBPDRGA_0, 0x00000005); mmio_write_32(DBSC_DBPDRGD_0, 0xC1AA00C0); if (pdqsr_ctl == 0) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); } /* PDR always off */ if (pdr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x00000103); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); } mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010801); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; /* * Initial_Step5(Read Data Bit Deskew) */ mmio_write_32(DBSC_DBPDRGA_0, 0x00000005); mmio_write_32(DBSC_DBPDRGD_0, 0xC1AA00D8); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00011001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; if (pdqsr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); } /* PDR dynamic */ if (pdr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000103); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); } /* * Initial_Step6(Write Data Bit Deskew) */ mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00012001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; /* * Initial_Step7(Read Data Eye Training) */ if (pdqsr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); } /* PDR always off */ if (pdr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x00000103); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); } mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00014001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; if (pdqsr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); } /* PDR dynamic */ if (pdr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000103); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); } /* * Initial_Step8(Write Data Eye Training) */ mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00018001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; /* * Initial_Step3_2( DQS Gate Training ) */ mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x0000002C); mmio_write_32(DBSC_DBPDRGD_0, 0x81003087); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010401); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; for (i = 0; i < 4; i++) { mmio_write_32(DBSC_DBPDRGA_0, 0xB1 + i * 0x20); r5 = ((mmio_read_32(DBSC_DBPDRGD_0) & 0xFF00) >> 0x8); mmio_write_32(DBSC_DBPDRGA_0, 0xB4 + i * 0x20); r6 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFF; mmio_write_32(DBSC_DBPDRGA_0, 0xB3 + i * 0x20); r7 = mmio_read_32(DBSC_DBPDRGD_0) & 0x7; r12 = (r5 >> 0x2); if (r12 < r6) { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r7 + 0x1) & 0x7)); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r6 - r12) & 0xFF)); } else { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | (r7 & 0x7)); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r6 + r5 + (r5 >> 1) + r12) & 0xFF)); } } /* * Initial_Step5-2_7-2( Rd bit Rd eye ) */ if (pdqsr_ctl == 0) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); } /* PDR always off */ if (pdr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x00000103); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); } mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00015001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; if (lcdl_ctl == 1) { for (i = 0; i < 4; i++) { mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); dqsgd_0c = mmio_read_32(DBSC_DBPDRGD_0) & 0xFF; mmio_write_32(DBSC_DBPDRGA_0, 0xB1 + i * 0x20); bdlcount_0c = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFF00) >> 8; bdlcount_0c_div2 = bdlcount_0c >> 1; bdlcount_0c_div4 = bdlcount_0c >> 2; bdlcount_0c_div8 = bdlcount_0c >> 3; bdlcount_0c_div16 = bdlcount_0c >> 4; if (ddr_md == 0) { /* 1584Mbps */ lcdl_judge1 = bdlcount_0c_div2 + bdlcount_0c_div4 + bdlcount_0c_div8; lcdl_judge2 = bdlcount_0c + bdlcount_0c_div4 + bdlcount_0c_div16; } else { /* 1856Mbps */ lcdl_judge1 = bdlcount_0c_div2 + bdlcount_0c_div4; lcdl_judge2 = bdlcount_0c + bdlcount_0c_div4; } if (dqsgd_0c <= lcdl_judge1) continue; if (dqsgd_0c <= lcdl_judge2) { mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); regval = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGD_0, (dqsgd_0c - bdlcount_0c_div8) | regval); } else { mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); regval = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGD_0, regval); mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); gatesl_0c = mmio_read_32(DBSC_DBPDRGD_0) & 0x7; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); regval = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGD_0, regval | (gatesl_0c + 1)); mmio_write_32(DBSC_DBPDRGA_0, 0xAF + i * 0x20); regval = (mmio_read_32(DBSC_DBPDRGD_0)); rdqsd_0c = (regval & 0xFF00) >> 8; rdqsnd_0c = (regval & 0xFF0000) >> 16; mmio_write_32(DBSC_DBPDRGA_0, 0xAF + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, (regval & 0xFF0000FF) | ((rdqsd_0c + bdlcount_0c_div4) << 8) | ((rdqsnd_0c + bdlcount_0c_div4) << 16)); mmio_write_32(DBSC_DBPDRGA_0, 0xAA + i * 0x20); regval = (mmio_read_32(DBSC_DBPDRGD_0)); rbd_0c[0] = (regval) & 0x1f; rbd_0c[1] = (regval >> 8) & 0x1f; rbd_0c[2] = (regval >> 16) & 0x1f; rbd_0c[3] = (regval >> 24) & 0x1f; mmio_write_32(DBSC_DBPDRGA_0, 0xAA + i * 0x20); regval = mmio_read_32(DBSC_DBPDRGD_0) & 0xE0E0E0E0; for (j = 0; j < 4; j++) { rbd_0c[j] = rbd_0c[j] + bdlcount_0c_div4; if (rbd_0c[j] > 0x1F) rbd_0c[j] = 0x1F; regval = regval | (rbd_0c[j] << 8 * j); } mmio_write_32(DBSC_DBPDRGD_0, regval); mmio_write_32(DBSC_DBPDRGA_0, 0xAB + i * 0x20); regval = (mmio_read_32(DBSC_DBPDRGD_0)); rbd_0c[0] = (regval) & 0x1f; rbd_0c[1] = (regval >> 8) & 0x1f; rbd_0c[2] = (regval >> 16) & 0x1f; rbd_0c[3] = (regval >> 24) & 0x1f; mmio_write_32(DBSC_DBPDRGA_0, 0xAB + i * 0x20); regval = mmio_read_32(DBSC_DBPDRGD_0) & 0xE0E0E0E0; for (j = 0; j < 4; j++) { rbd_0c[j] = rbd_0c[j] + bdlcount_0c_div4; if (rbd_0c[j] > 0x1F) rbd_0c[j] = 0x1F; regval = regval | (rbd_0c[j] << 8 * j); } mmio_write_32(DBSC_DBPDRGD_0, regval); } } mmio_write_32(DBSC_DBPDRGA_0, 0x2); mmio_write_32(DBSC_DBPDRGD_0, 0x7D81E37); } mmio_write_32(DBSC_DBPDRGA_0, 0x00000003); if (byp_ctl == 1) mmio_write_32(DBSC_DBPDRGD_0, 0x0380C720); else mmio_write_32(DBSC_DBPDRGD_0, 0x0380C700); mmio_write_32(DBSC_DBPDRGA_0, 0x00000007); while (mmio_read_32(DBSC_DBPDRGD_0) & BIT(30)) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000021); mmio_write_32(DBSC_DBPDRGD_0, 0x0024643E); mmio_write_32(DBSC_DBBUS0CNF1, 0x00000010); mmio_write_32(DBSC_DBCALCNF, (64000000 / REFRESH_RATE) + 0x01000000); /* Select setting value in bps */ if (ddr_md == 0) { /* 1584Mbps */ mmio_write_32(DBSC_DBRFCNF1, (REFRESH_RATE * 99 / 125) + 0x00080000); } else { /* 1856Mbps */ mmio_write_32(DBSC_DBRFCNF1, (REFRESH_RATE * 116 / 125) + 0x00080000); } mmio_write_32(DBSC_DBRFCNF2, 0x00010000); mmio_write_32(DBSC_DBDFICUPDCNF, 0x40100001); mmio_write_32(DBSC_DBRFEN, 0x00000001); mmio_write_32(DBSC_DBACEN, 0x00000001); if (pdqsr_ctl == 1) { mmio_write_32(0xE67F0018, 0x00000001); regval = mmio_read_32(0x40000000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000000); mmio_write_32(DBSC_DBPDRGD_0, regval); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); } /* PDR dynamic */ if (pdr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000103); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); } /* * Initial_Step9( Initial End ) */ mmio_write_32(DBSC_DBPDLK_0, 0x00000000); mmio_write_32(DBSC_DBSYSCNT0, 0x00000000); #ifdef ddr_qos_init_setting /* only for non qos_init */ mmio_write_32(DBSC_DBSYSCNT0, 0x00001234); mmio_write_32(DBSC_DBCAM0CNF1, 0x00043218); mmio_write_32(DBSC_DBCAM0CNF2, 0x000000F4); mmio_write_32(DBSC_DBSCHCNT0, 0x000f0037); mmio_write_32(DBSC_DBSCHSZ0, 0x00000001); mmio_write_32(DBSC_DBSCHRW0, 0x22421111); mmio_write_32(DBSC_SCFCTST2, 0x012F1123); mmio_write_32(DBSC_DBSCHQOS00, 0x00000F00); mmio_write_32(DBSC_DBSCHQOS01, 0x00000B00); mmio_write_32(DBSC_DBSCHQOS02, 0x00000000); mmio_write_32(DBSC_DBSCHQOS03, 0x00000000); mmio_write_32(DBSC_DBSCHQOS40, 0x00000300); mmio_write_32(DBSC_DBSCHQOS41, 0x000002F0); mmio_write_32(DBSC_DBSCHQOS42, 0x00000200); mmio_write_32(DBSC_DBSCHQOS43, 0x00000100); mmio_write_32(DBSC_DBSCHQOS90, 0x00000100); mmio_write_32(DBSC_DBSCHQOS91, 0x000000F0); mmio_write_32(DBSC_DBSCHQOS92, 0x000000A0); mmio_write_32(DBSC_DBSCHQOS93, 0x00000040); mmio_write_32(DBSC_DBSCHQOS130, 0x00000100); mmio_write_32(DBSC_DBSCHQOS131, 0x000000F0); mmio_write_32(DBSC_DBSCHQOS132, 0x000000A0); mmio_write_32(DBSC_DBSCHQOS133, 0x00000040); mmio_write_32(DBSC_DBSCHQOS140, 0x000000C0); mmio_write_32(DBSC_DBSCHQOS141, 0x000000B0); mmio_write_32(DBSC_DBSCHQOS142, 0x00000080); mmio_write_32(DBSC_DBSCHQOS143, 0x00000040); mmio_write_32(DBSC_DBSCHQOS150, 0x00000040); mmio_write_32(DBSC_DBSCHQOS151, 0x00000030); mmio_write_32(DBSC_DBSCHQOS152, 0x00000020); mmio_write_32(DBSC_DBSCHQOS153, 0x00000010); if (pdqsr_ctl == 0) mmio_write_32(0xE67F0018, 0x00000001); mmio_write_32(DBSC_DBSYSCNT0, 0x00000000); #endif return 1; } static uint32_t recovery_from_backup_mode(uint32_t ddr_backup) { /* * recovery_Step0(DBSC Setting 1) / same "init_ddr" */ uint32_t r2, r5, r6, r7, r12, i; uint32_t ddr_md; uint32_t err; uint32_t regval, j; uint32_t dqsgd_0c, bdlcount_0c, bdlcount_0c_div2, bdlcount_0c_div4; uint32_t bdlcount_0c_div8, bdlcount_0c_div16; uint32_t gatesl_0c, rdqsd_0c, rdqsnd_0c, rbd_0c[4]; uint32_t pdqsr_ctl, lcdl_ctl, lcdl_judge1, lcdl_judge2; uint32_t pdr_ctl; uint32_t byp_ctl; if ((mmio_read_32(0xFFF00044) & 0x000000FF) == 0x00000000) { pdqsr_ctl = 1; lcdl_ctl = 1; pdr_ctl = 1; byp_ctl = 1; } else { pdqsr_ctl = 0; lcdl_ctl = 0; pdr_ctl = 0; byp_ctl = 0; } /* Judge the DDR bit rate (ddr_md : 0 = 1584Mbps, 1 = 1856Mbps) */ ddr_md = (mmio_read_32(RST_MODEMR) >> 19) & BIT(0); /* 1584Mbps setting */ if (ddr_md == 0) { mmio_write_32(CPG_CPGWPR, 0x5A5AFFFF); mmio_write_32(CPG_CPGWPCR, 0xA5A50000); mmio_write_32(CPG_SRCR4, 0x20000000); mmio_write_32(0xE61500DC, 0xe2200000); /* Change to 1584Mbps */ while (!(mmio_read_32(CPG_PLLECR) & BIT(11))) ; mmio_write_32(CPG_SRSTCLR4, 0x20000000); mmio_write_32(CPG_CPGWPCR, 0xA5A50001); } mmio_write_32(DBSC_DBSYSCNT0, 0x00001234); mmio_write_32(DBSC_DBKIND, 0x00000007); #if RCAR_DRAM_DDR3L_MEMCONF == 0 mmio_write_32(DBSC_DBMEMCONF_0_0, 0x0f030a02); #else mmio_write_32(DBSC_DBMEMCONF_0_0, 0x10030a02); #endif #if RCAR_DRAM_DDR3L_MEMDUAL == 1 r2 = mmio_read_32(0xE6790614); mmio_write_32(0xE6790614, r2 | 0x3); /* MCS1_N/MODT1 are activated. */ #endif mmio_write_32(DBSC_DBPHYCONF0, 0x00000001); /* Select setting value in bps */ if (ddr_md == 0) { /* 1584Mbps */ mmio_write_32(DBSC_DBTR0, 0x0000000B); mmio_write_32(DBSC_DBTR1, 0x00000008); } else { /* 1856Mbps */ mmio_write_32(DBSC_DBTR0, 0x0000000D); mmio_write_32(DBSC_DBTR1, 0x00000009); } mmio_write_32(DBSC_DBTR2, 0x00000000); /* Select setting value in bps */ if (ddr_md == 0) { /* 1584Mbps */ mmio_write_32(DBSC_DBTR3, 0x0000000B); mmio_write_32(DBSC_DBTR4, 0x000B000B); mmio_write_32(DBSC_DBTR5, 0x00000027); mmio_write_32(DBSC_DBTR6, 0x0000001C); } else { /* 1856Mbps */ mmio_write_32(DBSC_DBTR3, 0x0000000D); mmio_write_32(DBSC_DBTR4, 0x000D000D); mmio_write_32(DBSC_DBTR5, 0x0000002D); mmio_write_32(DBSC_DBTR6, 0x00000020); } mmio_write_32(DBSC_DBTR7, 0x00060006); /* Select setting value in bps */ if (ddr_md == 0) { /* 1584Mbps */ mmio_write_32(DBSC_DBTR8, 0x00000020); mmio_write_32(DBSC_DBTR9, 0x00000006); mmio_write_32(DBSC_DBTR10, 0x0000000C); mmio_write_32(DBSC_DBTR11, 0x0000000A); mmio_write_32(DBSC_DBTR12, 0x00120012); mmio_write_32(DBSC_DBTR13, 0x000000CE); mmio_write_32(DBSC_DBTR14, 0x00140005); mmio_write_32(DBSC_DBTR15, 0x00050004); mmio_write_32(DBSC_DBTR16, 0x071F0305); mmio_write_32(DBSC_DBTR17, 0x040C0000); } else { /* 1856Mbps */ mmio_write_32(DBSC_DBTR8, 0x00000021); mmio_write_32(DBSC_DBTR9, 0x00000007); mmio_write_32(DBSC_DBTR10, 0x0000000E); mmio_write_32(DBSC_DBTR11, 0x0000000C); mmio_write_32(DBSC_DBTR12, 0x00140014); mmio_write_32(DBSC_DBTR13, 0x000000F2); mmio_write_32(DBSC_DBTR14, 0x00170006); mmio_write_32(DBSC_DBTR15, 0x00060005); mmio_write_32(DBSC_DBTR16, 0x09210507); mmio_write_32(DBSC_DBTR17, 0x040E0000); } mmio_write_32(DBSC_DBTR18, 0x00000200); /* Select setting value in bps */ if (ddr_md == 0) { /* 1584Mbps */ mmio_write_32(DBSC_DBTR19, 0x01000040); mmio_write_32(DBSC_DBTR20, 0x020000D6); } else { /* 1856Mbps */ mmio_write_32(DBSC_DBTR19, 0x0129004B); mmio_write_32(DBSC_DBTR20, 0x020000FB); } mmio_write_32(DBSC_DBTR21, 0x00040004); mmio_write_32(DBSC_DBBL, 0x00000000); mmio_write_32(DBSC_DBODT0, 0x00000001); mmio_write_32(DBSC_DBADJ0, 0x00000001); mmio_write_32(DBSC_DBSYSCONF1, 0x00000002); mmio_write_32(DBSC_DBDFICNT_0, 0x00000010); mmio_write_32(DBSC_DBBCAMDIS, 0x00000001); mmio_write_32(DBSC_DBSCHRW1, 0x00000046); /* Select setting value in bps */ if (ddr_md == 0) { /* 1584Mbps */ mmio_write_32(DBSC_SCFCTST0, 0x0D050B03); mmio_write_32(DBSC_SCFCTST1, 0x0306030C); } else { /* 1856Mbps */ mmio_write_32(DBSC_SCFCTST0, 0x0C050B03); mmio_write_32(DBSC_SCFCTST1, 0x0305030C); } /* * recovery_Step1(PHY setting 1) */ mmio_write_32(DBSC_DBPDLK_0, 0x0000A55A); mmio_write_32(DBSC_DBCMD, 0x01840001); mmio_write_32(DBSC_DBCMD, 0x0A840000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000008); /* DDR_PLLCR */ mmio_write_32(DBSC_DBPDRGD_0, 0x000B8000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000003); /* DDR_PGCR1 */ if (byp_ctl == 1) mmio_write_32(DBSC_DBPDRGD_0, 0x0780C720); else mmio_write_32(DBSC_DBPDRGD_0, 0x0780C700); mmio_write_32(DBSC_DBPDRGA_0, 0x00000020); /* DDR_DXCCR */ mmio_write_32(DBSC_DBPDRGD_0, 0x00181884); mmio_write_32(DBSC_DBPDRGA_0, 0x0000001A); /* DDR_ACIOCR0 */ mmio_write_32(DBSC_DBPDRGD_0, 0x33C03C10); mmio_write_32(DBSC_DBPDRGA_0, 0x00000007); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(30))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000004); /* Select setting value in bps */ if (ddr_md == 0) { /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, (REFRESH_RATE * 792 / 125) - 400 + 0x08B00000); } else { /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, (REFRESH_RATE * 928 / 125) - 400 + 0x0A300000); } mmio_write_32(DBSC_DBPDRGA_0, 0x00000022); mmio_write_32(DBSC_DBPDRGD_0, 0x1000040B); mmio_write_32(DBSC_DBPDRGA_0, 0x00000023); /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x2D9C0B66); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x35A00D77); mmio_write_32(DBSC_DBPDRGA_0, 0x00000024); /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x2A88B400); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x2A8A2C28); mmio_write_32(DBSC_DBPDRGA_0, 0x00000025); /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x30005200); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x30005E00); mmio_write_32(DBSC_DBPDRGA_0, 0x00000026); /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x0014A9C9); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x0014CB49); mmio_write_32(DBSC_DBPDRGA_0, 0x00000027); /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x00000D70); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x00000F14); mmio_write_32(DBSC_DBPDRGA_0, 0x00000028); mmio_write_32(DBSC_DBPDRGD_0, 0x00000046); mmio_write_32(DBSC_DBPDRGA_0, 0x00000029); /* Select setting value in bps */ if (ddr_md == 0) { /* 1584Mbps */ if (REFRESH_RATE > 3900) mmio_write_32(DBSC_DBPDRGD_0, 0x18); /* [7]SRT=0 */ else mmio_write_32(DBSC_DBPDRGD_0, 0x98); /* [7]SRT=1 */ } else { /* 1856Mbps */ if (REFRESH_RATE > 3900) mmio_write_32(DBSC_DBPDRGD_0, 0x20); /* [7]SRT=0 */ else mmio_write_32(DBSC_DBPDRGD_0, 0xA0); /* [7]SRT=1 */ } mmio_write_32(DBSC_DBPDRGA_0, 0x0000002C); mmio_write_32(DBSC_DBPDRGD_0, 0x81003047); mmio_write_32(DBSC_DBPDRGA_0, 0x00000091); mmio_write_32(DBSC_DBPDRGD_0, 0x0007BB6B); mmio_write_32(DBSC_DBPDRGA_0, 0x00000095); mmio_write_32(DBSC_DBPDRGD_0, 0x0007BBAD); mmio_write_32(DBSC_DBPDRGA_0, 0x00000099); mmio_write_32(DBSC_DBPDRGD_0, 0x0007BB6B); mmio_write_32(DBSC_DBPDRGA_0, 0x00000021); /* DDR_DSGCR */ mmio_write_32(DBSC_DBPDRGD_0, 0x0024641E); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); /* DDR_PGSR0 */ while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); /* DDR_PIR */ mmio_write_32(DBSC_DBPDRGD_0, 0x40010000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); /* DDR_PGSR0 */ while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000092); /* DDR_ZQ0DR */ mmio_write_32(DBSC_DBPDRGD_0, 0xC2C59AB5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000096); /* DDR_ZQ1DR */ mmio_write_32(DBSC_DBPDRGD_0, 0xC4285FBF); mmio_write_32(DBSC_DBPDRGA_0, 0x0000009A); /* DDR_ZQ2DR */ mmio_write_32(DBSC_DBPDRGD_0, 0xC2C59AB5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); /* DDR_ZQCR */ /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x0C058900); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x0C058A00); mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); /* DDR_ZQCR */ /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x04058900); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x04058A00); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); /* DDR_PIR */ mmio_write_32(DBSC_DBPDRGD_0, 0x00050001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); /* DDR_PGSR0 */ while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; /* ddr backupmode end */ if (ddr_backup) NOTICE("BL2: [WARM_BOOT]\n"); else NOTICE("BL2: [COLD_BOOT]\n"); err = rcar_dram_update_boot_status(ddr_backup); if (err) { NOTICE("BL2: [BOOT_STATUS_UPDATE_ERROR]\n"); return INITDRAM_ERR_I; } mmio_write_32(DBSC_DBPDRGA_0, 0x00000092); /* DDR_ZQ0DR */ mmio_write_32(DBSC_DBPDRGD_0, 0x02C59AB5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000096); /* DDR_ZQ1DR */ mmio_write_32(DBSC_DBPDRGD_0, 0x04285FBF); mmio_write_32(DBSC_DBPDRGA_0, 0x0000009A); /* DDR_ZQ2DR */ mmio_write_32(DBSC_DBPDRGD_0, 0x02C59AB5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); /* DDR_PIR */ mmio_write_32(DBSC_DBPDRGD_0, 0x08000000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); /* DDR_PIR */ mmio_write_32(DBSC_DBPDRGD_0, 0x00000003); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); /* DDR_PGSR0 */ while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); /* DDR_PIR */ mmio_write_32(DBSC_DBPDRGD_0, 0x80010000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); /* DDR_PGSR0 */ while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); /* DDR_PIR */ mmio_write_32(DBSC_DBPDRGD_0, 0x00010073); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); /* DDR_PGSR0 */ while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); /* DDR_ZQCR */ /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x0C058900); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x0C058A00); mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); /* DDR_ZQCR */ /* Select setting value in bps */ if (ddr_md == 0) /* 1584Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x04058900); else /* 1856Mbps */ mmio_write_32(DBSC_DBPDRGD_0, 0x04058A00); mmio_write_32(DBSC_DBPDRGA_0, 0x0000000C); mmio_write_32(DBSC_DBPDRGD_0, 0x18000040); /* * recovery_Step2(PHY setting 2) */ mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x000000A7); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A8); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A9); mmio_write_32(DBSC_DBPDRGD_0, 0x000D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C7); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C8); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C9); mmio_write_32(DBSC_DBPDRGD_0, 0x000D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E7); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E8); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E9); mmio_write_32(DBSC_DBPDRGD_0, 0x000D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x00000107); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x00000108); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x00000109); mmio_write_32(DBSC_DBPDRGD_0, 0x000D0D0D); mmio_write_32(DBSC_DBCALCNF, (64000000 / REFRESH_RATE) + 0x01000000); mmio_write_32(DBSC_DBBUS0CNF1, 0x00000010); /* Select setting value in bps */ if (ddr_md == 0) { /* 1584Mbps */ mmio_write_32(DBSC_DBRFCNF1, (REFRESH_RATE * 99 / 125) + 0x00080000); } else { /* 1856Mbps */ mmio_write_32(DBSC_DBRFCNF1, (REFRESH_RATE * 116 / 125) + 0x00080000); } mmio_write_32(DBSC_DBRFCNF2, 0x00010000); mmio_write_32(DBSC_DBRFEN, 0x00000001); mmio_write_32(DBSC_DBCMD, 0x0A840001); while (mmio_read_32(DBSC_DBWAIT) & BIT(0)) ; mmio_write_32(DBSC_DBCMD, 0x00000000); mmio_write_32(DBSC_DBCMD, 0x04840010); while (mmio_read_32(DBSC_DBWAIT) & BIT(0)) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); /* DDR_PGSR0 */ while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); /* DDR_PIR */ mmio_write_32(DBSC_DBPDRGD_0, 0x00010701); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); /* DDR_PGSR0 */ while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; for (i = 0; i < 4; i++) { mmio_write_32(DBSC_DBPDRGA_0, 0xB1 + i * 0x20); r5 = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFF00) >> 0x8; mmio_write_32(DBSC_DBPDRGA_0, 0xB4 + i * 0x20); r6 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFF; mmio_write_32(DBSC_DBPDRGA_0, 0xB3 + i * 0x20); r7 = mmio_read_32(DBSC_DBPDRGD_0) & 0x7; if (r6 > 0) { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r7 + 0x1) & 0x7)); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | r6); } else { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | r7); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r6 + (r5 << 1)) & 0xFF)); } } mmio_write_32(DBSC_DBPDRGA_0, 0x00000005); mmio_write_32(DBSC_DBPDRGD_0, 0xC1AA00C0); if (pdqsr_ctl == 0) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); } /* PDR always off */ if (pdr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x00000103); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); } mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010801); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000005); mmio_write_32(DBSC_DBPDRGD_0, 0xC1AA00D8); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00011001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; if (pdqsr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); } /* PDR dynamic */ if (pdr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000103); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); } mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00012001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; if (pdqsr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); } /* PDR always off */ if (pdr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x00000103); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); } mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00014001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; if (pdqsr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); } /* PDR dynamic */ if (pdr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000103); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); } mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00018001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x0000002C); mmio_write_32(DBSC_DBPDRGD_0, 0x81003087); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010401); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; for (i = 0; i < 4; i++) { mmio_write_32(DBSC_DBPDRGA_0, 0xB1 + i * 0x20); r5 = ((mmio_read_32(DBSC_DBPDRGD_0) & 0xFF00) >> 0x8); mmio_write_32(DBSC_DBPDRGA_0, 0xB4 + i * 0x20); r6 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFF; mmio_write_32(DBSC_DBPDRGA_0, 0xB3 + i * 0x20); r7 = mmio_read_32(DBSC_DBPDRGD_0) & 0x7; r12 = r5 >> 0x2; if (r12 < r6) { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r7 + 0x1) & 0x7)); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r6 - r12) & 0xFF)); } else { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | (r7 & 0x7)); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r6 + r5 + (r5 >> 1) + r12) & 0xFF)); } } if (pdqsr_ctl == 0) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); } /* PDR always off */ if (pdr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); mmio_write_32(DBSC_DBPDRGA_0, 0x00000103); mmio_write_32(DBSC_DBPDRGD_0, 0x00000008); } mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00015001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; if (lcdl_ctl == 1) { for (i = 0; i < 4; i++) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000B0 + i * 0x20); dqsgd_0c = mmio_read_32(DBSC_DBPDRGD_0) & 0x000000FF; mmio_write_32(DBSC_DBPDRGA_0, 0x000000B1 + i * 0x20); bdlcount_0c = (mmio_read_32(DBSC_DBPDRGD_0) & 0x0000FF00) >> 8; bdlcount_0c_div2 = (bdlcount_0c >> 1); bdlcount_0c_div4 = (bdlcount_0c >> 2); bdlcount_0c_div8 = (bdlcount_0c >> 3); bdlcount_0c_div16 = (bdlcount_0c >> 4); if (ddr_md == 0) { /* 1584Mbps */ lcdl_judge1 = bdlcount_0c_div2 + bdlcount_0c_div4 + bdlcount_0c_div8; lcdl_judge2 = bdlcount_0c + bdlcount_0c_div4 + bdlcount_0c_div16; } else { /* 1856Mbps */ lcdl_judge1 = bdlcount_0c_div2 + bdlcount_0c_div4; lcdl_judge2 = bdlcount_0c + bdlcount_0c_div4; } if (dqsgd_0c <= lcdl_judge1) continue; if (dqsgd_0c <= lcdl_judge2) { mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); regval = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGD_0, (dqsgd_0c - bdlcount_0c_div8) | regval); } else { mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); regval = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00; mmio_write_32(DBSC_DBPDRGD_0, regval); mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); gatesl_0c = mmio_read_32(DBSC_DBPDRGD_0) & 0x7; mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); regval = mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8; mmio_write_32(DBSC_DBPDRGD_0, regval | (gatesl_0c + 1)); mmio_write_32(DBSC_DBPDRGA_0, 0xAF + i * 0x20); regval = mmio_read_32(DBSC_DBPDRGD_0); rdqsd_0c = (regval & 0xFF00) >> 8; rdqsnd_0c = (regval & 0xFF0000) >> 16; mmio_write_32(DBSC_DBPDRGA_0, 0xAF + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, (regval & 0xFF0000FF) | ((rdqsd_0c + bdlcount_0c_div4) << 8) | ((rdqsnd_0c + bdlcount_0c_div4) << 16)); mmio_write_32(DBSC_DBPDRGA_0, 0xAA + i * 0x20); regval = (mmio_read_32(DBSC_DBPDRGD_0)); rbd_0c[0] = (regval) & 0x1f; rbd_0c[1] = (regval >> 8) & 0x1f; rbd_0c[2] = (regval >> 16) & 0x1f; rbd_0c[3] = (regval >> 24) & 0x1f; mmio_write_32(DBSC_DBPDRGA_0, 0xAA + i * 0x20); regval = mmio_read_32(DBSC_DBPDRGD_0) & 0xE0E0E0E0; for (j = 0; j < 4; j++) { rbd_0c[j] = rbd_0c[j] + bdlcount_0c_div4; if (rbd_0c[j] > 0x1F) rbd_0c[j] = 0x1F; regval = regval | (rbd_0c[j] << 8 * j); } mmio_write_32(DBSC_DBPDRGD_0, regval); mmio_write_32(DBSC_DBPDRGA_0, 0xAB + i * 0x20); regval = (mmio_read_32(DBSC_DBPDRGD_0)); rbd_0c[0] = regval & 0x1f; rbd_0c[1] = (regval >> 8) & 0x1f; rbd_0c[2] = (regval >> 16) & 0x1f; rbd_0c[3] = (regval >> 24) & 0x1f; mmio_write_32(DBSC_DBPDRGA_0, 0xAB + i * 0x20); regval = mmio_read_32(DBSC_DBPDRGD_0) & 0xE0E0E0E0; for (j = 0; j < 4; j++) { rbd_0c[j] = rbd_0c[j] + bdlcount_0c_div4; if (rbd_0c[j] > 0x1F) rbd_0c[j] = 0x1F; regval = regval | (rbd_0c[j] << 8 * j); } mmio_write_32(DBSC_DBPDRGD_0, regval); } } mmio_write_32(DBSC_DBPDRGA_0, 0x00000002); mmio_write_32(DBSC_DBPDRGD_0, 0x07D81E37); } mmio_write_32(DBSC_DBPDRGA_0, 0x00000003); if (byp_ctl == 1) mmio_write_32(DBSC_DBPDRGD_0, 0x0380C720); else mmio_write_32(DBSC_DBPDRGD_0, 0x0380C700); mmio_write_32(DBSC_DBPDRGA_0, 0x00000007); while (mmio_read_32(DBSC_DBPDRGD_0) & BIT(30)) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000021); mmio_write_32(DBSC_DBPDRGD_0, 0x0024643E); /* * recovery_Step3(DBSC Setting 2) */ mmio_write_32(DBSC_DBDFICUPDCNF, 0x40100001); mmio_write_32(DBSC_DBACEN, 0x00000001); if (pdqsr_ctl == 1) { mmio_write_32(0xE67F0018, 0x00000001); regval = mmio_read_32(0x40000000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000000); mmio_write_32(DBSC_DBPDRGD_0, regval); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); } /* PDR dynamic */ if (pdr_ctl == 1) { mmio_write_32(DBSC_DBPDRGA_0, 0x000000A3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E3); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000103); mmio_write_32(DBSC_DBPDRGD_0, 0x00000000); } mmio_write_32(DBSC_DBPDLK_0, 0x00000000); mmio_write_32(DBSC_DBSYSCNT0, 0x00000000); #ifdef ddr_qos_init_setting /* only for non qos_init */ mmio_write_32(DBSC_DBSYSCNT0, 0x00001234); mmio_write_32(DBSC_DBCAM0CNF1, 0x00043218); mmio_write_32(DBSC_DBCAM0CNF2, 0x000000F4); mmio_write_32(DBSC_DBSCHCNT0, 0x000f0037); mmio_write_32(DBSC_DBSCHSZ0, 0x00000001); mmio_write_32(DBSC_DBSCHRW0, 0x22421111); mmio_write_32(DBSC_SCFCTST2, 0x012F1123); mmio_write_32(DBSC_DBSCHQOS00, 0x00000F00); mmio_write_32(DBSC_DBSCHQOS01, 0x00000B00); mmio_write_32(DBSC_DBSCHQOS02, 0x00000000); mmio_write_32(DBSC_DBSCHQOS03, 0x00000000); mmio_write_32(DBSC_DBSCHQOS40, 0x00000300); mmio_write_32(DBSC_DBSCHQOS41, 0x000002F0); mmio_write_32(DBSC_DBSCHQOS42, 0x00000200); mmio_write_32(DBSC_DBSCHQOS43, 0x00000100); mmio_write_32(DBSC_DBSCHQOS90, 0x00000100); mmio_write_32(DBSC_DBSCHQOS91, 0x000000F0); mmio_write_32(DBSC_DBSCHQOS92, 0x000000A0); mmio_write_32(DBSC_DBSCHQOS93, 0x00000040); mmio_write_32(DBSC_DBSCHQOS130, 0x00000100); mmio_write_32(DBSC_DBSCHQOS131, 0x000000F0); mmio_write_32(DBSC_DBSCHQOS132, 0x000000A0); mmio_write_32(DBSC_DBSCHQOS133, 0x00000040); mmio_write_32(DBSC_DBSCHQOS140, 0x000000C0); mmio_write_32(DBSC_DBSCHQOS141, 0x000000B0); mmio_write_32(DBSC_DBSCHQOS142, 0x00000080); mmio_write_32(DBSC_DBSCHQOS143, 0x00000040); mmio_write_32(DBSC_DBSCHQOS150, 0x00000040); mmio_write_32(DBSC_DBSCHQOS151, 0x00000030); mmio_write_32(DBSC_DBSCHQOS152, 0x00000020); mmio_write_32(DBSC_DBSCHQOS153, 0x00000010); if (pdqsr_ctl == 0) mmio_write_32(0xE67F0018, 0x00000001); mmio_write_32(DBSC_DBSYSCNT0, 0x00000000); #endif return 1; } /* recovery_from_backup_mode */ /* * init_ddr : MD19=0,DDR3L,1584Mbps / MD19=1,DDR3L,1856Mbps */ /* * DDR Initialize entry for IPL */ int32_t rcar_dram_init(void) { uint32_t dataL; uint32_t failcount; uint32_t md = 0; uint32_t ddr = 0; uint32_t ddr_backup; md = *((volatile uint32_t*)RST_MODEMR); ddr = (md & 0x00080000) >> 19; if (ddr == 0x0) NOTICE("BL2: DDR1584(%s)\n", RCAR_E3_DDR_VERSION); else if (ddr == 0x1) NOTICE("BL2: DDR1856(%s)\n", RCAR_E3_DDR_VERSION); rcar_dram_get_boot_status(&ddr_backup); if (ddr_backup == DRAM_BOOT_STATUS_WARM) dataL = recovery_from_backup_mode(ddr_backup); /* WARM boot */ else dataL = init_ddr(); /* COLD boot */ if (dataL == 1) failcount = 0; else failcount = 1; if (failcount == 0) return INITDRAM_OK; else return INITDRAM_NG; } trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_a/ddr_init_v3m.c000066400000000000000000000306201355360272700271620ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "boot_init_dram.h" #include "rcar_def.h" #include "../ddr_regs.h" static uint32_t init_ddr_v3m_1600(void) { uint32_t i, r2, r5, r6, r7, r12; mmio_write_32(DBSC_DBSYSCNT0, 0x00001234); mmio_write_32(DBSC_DBKIND, 0x00000007); #if RCAR_DRAM_DDR3L_MEMCONF == 0 mmio_write_32(DBSC_DBMEMCONF_0_0, 0x0f030a02); // 1GB: Eagle #else mmio_write_32(DBSC_DBMEMCONF_0_0, 0x10030a02); // 2GB: V3MSK #endif mmio_write_32(DBSC_DBPHYCONF0, 0x00000001); mmio_write_32(DBSC_DBTR0, 0x0000000B); mmio_write_32(DBSC_DBTR1, 0x00000008); mmio_write_32(DBSC_DBTR3, 0x0000000B); mmio_write_32(DBSC_DBTR4, 0x000B000B); mmio_write_32(DBSC_DBTR5, 0x00000027); mmio_write_32(DBSC_DBTR6, 0x0000001C); mmio_write_32(DBSC_DBTR7, 0x00060006); mmio_write_32(DBSC_DBTR8, 0x00000020); mmio_write_32(DBSC_DBTR9, 0x00000006); mmio_write_32(DBSC_DBTR10, 0x0000000C); mmio_write_32(DBSC_DBTR11, 0x0000000B); mmio_write_32(DBSC_DBTR12, 0x00120012); mmio_write_32(DBSC_DBTR13, 0x01180118); mmio_write_32(DBSC_DBTR14, 0x00140005); mmio_write_32(DBSC_DBTR15, 0x00050004); mmio_write_32(DBSC_DBTR16, 0x071D0305); mmio_write_32(DBSC_DBTR17, 0x040C0010); mmio_write_32(DBSC_DBTR18, 0x00000200); mmio_write_32(DBSC_DBTR19, 0x01000040); mmio_write_32(DBSC_DBTR20, 0x02000120); mmio_write_32(DBSC_DBTR21, 0x00040004); mmio_write_32(DBSC_DBBL, 0x00000000); mmio_write_32(DBSC_DBODT0, 0x00000001); mmio_write_32(DBSC_DBADJ0, 0x00000001); mmio_write_32(DBSC_DBCAM0CNF1, 0x00082010); mmio_write_32(DBSC_DBCAM0CNF2, 0x00002000); mmio_write_32(DBSC_DBSCHCNT0, 0x080f003f); mmio_write_32(DBSC_DBSCHCNT1, 0x00001010); mmio_write_32(DBSC_DBSCHSZ0, 0x00000001); mmio_write_32(DBSC_DBSCHRW0, 0x00000200); mmio_write_32(DBSC_DBSCHRW1, 0x00000040); mmio_write_32(DBSC_DBSCHQOS40, 0x00000600); mmio_write_32(DBSC_DBSCHQOS41, 0x00000480); mmio_write_32(DBSC_DBSCHQOS42, 0x00000300); mmio_write_32(DBSC_DBSCHQOS43, 0x00000180); mmio_write_32(DBSC_DBSCHQOS90, 0x00000400); mmio_write_32(DBSC_DBSCHQOS91, 0x00000300); mmio_write_32(DBSC_DBSCHQOS92, 0x00000200); mmio_write_32(DBSC_DBSCHQOS93, 0x00000100); mmio_write_32(DBSC_DBSCHQOS130, 0x00000300); mmio_write_32(DBSC_DBSCHQOS131, 0x00000240); mmio_write_32(DBSC_DBSCHQOS132, 0x00000180); mmio_write_32(DBSC_DBSCHQOS133, 0x000000c0); mmio_write_32(DBSC_DBSCHQOS140, 0x00000200); mmio_write_32(DBSC_DBSCHQOS141, 0x00000180); mmio_write_32(DBSC_DBSCHQOS142, 0x00000100); mmio_write_32(DBSC_DBSCHQOS143, 0x00000080); mmio_write_32(DBSC_DBSCHQOS150, 0x00000100); mmio_write_32(DBSC_DBSCHQOS151, 0x000000c0); mmio_write_32(DBSC_DBSCHQOS152, 0x00000080); mmio_write_32(DBSC_DBSCHQOS153, 0x00000040); mmio_write_32(DBSC_DBSYSCONF1, 0x00000002); mmio_write_32(DBSC_DBCAM0CNF1, 0x00040C04); mmio_write_32(DBSC_DBCAM0CNF2, 0x000001c4); mmio_write_32(DBSC_DBSCHSZ0, 0x00000003); mmio_write_32(DBSC_DBSCHRW1, 0x001a0080); mmio_write_32(DBSC_DBDFICNT_0, 0x00000010); mmio_write_32(DBSC_DBPDLK_0, 0x0000A55A); mmio_write_32(DBSC_DBCMD, 0x01000001); mmio_write_32(DBSC_DBCMD, 0x08000000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x80010000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000008); mmio_write_32(DBSC_DBPDRGD_0, 0x000B8000); mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); mmio_write_32(DBSC_DBPDRGD_0, 0x04058904); mmio_write_32(DBSC_DBPDRGA_0, 0x00000091); mmio_write_32(DBSC_DBPDRGD_0, 0x0007BB6D); mmio_write_32(DBSC_DBPDRGA_0, 0x00000095); mmio_write_32(DBSC_DBPDRGD_0, 0x0007BB6B); mmio_write_32(DBSC_DBPDRGA_0, 0x00000099); mmio_write_32(DBSC_DBPDRGD_0, 0x0007BB6D); mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); mmio_write_32(DBSC_DBPDRGD_0, 0x04058900); mmio_write_32(DBSC_DBPDRGA_0, 0x00000021); mmio_write_32(DBSC_DBPDRGD_0, 0x0024641E); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010073); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); mmio_write_32(DBSC_DBPDRGD_0, 0x0C058900); mmio_write_32(DBSC_DBPDRGA_0, 0x00000090); mmio_write_32(DBSC_DBPDRGD_0, 0x04058900); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000003); mmio_write_32(DBSC_DBPDRGD_0, 0x0780C700); mmio_write_32(DBSC_DBPDRGA_0, 0x00000007); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(30))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000004); mmio_write_32(DBSC_DBPDRGD_0, 0x08C0C170); mmio_write_32(DBSC_DBPDRGA_0, 0x00000022); mmio_write_32(DBSC_DBPDRGD_0, 0x1000040B); mmio_write_32(DBSC_DBPDRGA_0, 0x00000023); mmio_write_32(DBSC_DBPDRGD_0, 0x2D9C0B66); mmio_write_32(DBSC_DBPDRGA_0, 0x00000024); mmio_write_32(DBSC_DBPDRGD_0, 0x2A88C400); mmio_write_32(DBSC_DBPDRGA_0, 0x00000025); mmio_write_32(DBSC_DBPDRGD_0, 0x30005200); mmio_write_32(DBSC_DBPDRGA_0, 0x00000026); mmio_write_32(DBSC_DBPDRGD_0, 0x0014A9C9); mmio_write_32(DBSC_DBPDRGA_0, 0x00000027); mmio_write_32(DBSC_DBPDRGD_0, 0x00000D70); mmio_write_32(DBSC_DBPDRGA_0, 0x00000028); mmio_write_32(DBSC_DBPDRGD_0, 0x00000004); mmio_write_32(DBSC_DBPDRGA_0, 0x00000029); mmio_write_32(DBSC_DBPDRGD_0, 0x00000018); mmio_write_32(DBSC_DBPDRGA_0, 0x0000002C); mmio_write_32(DBSC_DBPDRGD_0, 0x81003047); mmio_write_32(DBSC_DBPDRGA_0, 0x00000020); mmio_write_32(DBSC_DBPDRGD_0, 0x00181884); mmio_write_32(DBSC_DBPDRGA_0, 0x0000001A); mmio_write_32(DBSC_DBPDRGD_0, 0x13C03C10); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x000000A7); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A8); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A9); mmio_write_32(DBSC_DBPDRGD_0, 0x000D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C7); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C8); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C9); mmio_write_32(DBSC_DBPDRGD_0, 0x000D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E7); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E8); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E9); mmio_write_32(DBSC_DBPDRGD_0, 0x000D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x00000107); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x00000108); mmio_write_32(DBSC_DBPDRGD_0, 0x0D0D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x00000109); mmio_write_32(DBSC_DBPDRGD_0, 0x000D0D0D); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010181); mmio_write_32(DBSC_DBCMD, 0x08000001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010601); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; for (i = 0; i < 4; i++) { mmio_write_32(DBSC_DBPDRGA_0, 0xB1 + i * 0x20); r5 = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFF00) >> 8; mmio_write_32(DBSC_DBPDRGA_0, 0xB4 + i * 0x20); r6 = mmio_read_32(DBSC_DBPDRGD_0) & 0xFF; mmio_write_32(DBSC_DBPDRGA_0, 0xB3 + i * 0x20); r7 = mmio_read_32(DBSC_DBPDRGD_0) & 0x7; if (r6 > 0) { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8); mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, ((r7 + 1) & 0x7) | r2); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | r6); } else { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8); mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | r7); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | (((r5 << 1) + r6) & 0xFF)); } } mmio_write_32(DBSC_DBPDRGA_0, 0x00000005); mmio_write_32(DBSC_DBPDRGD_0, 0xC1AA00A0); mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010801); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000005); mmio_write_32(DBSC_DBPDRGD_0, 0xC1AA00B8); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x0001F001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C000285); mmio_write_32(DBSC_DBPDRGA_0, 0x0000002C); mmio_write_32(DBSC_DBPDRGD_0, 0x81003087); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00010401); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; for (i = 0; i < 4; i++) { mmio_write_32(DBSC_DBPDRGA_0, 0xB1 + i * 0x20); r5 = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFF00) >> 8; mmio_write_32(DBSC_DBPDRGA_0, 0xB4 + i * 0x20); r6 = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFF); mmio_write_32(DBSC_DBPDRGA_0, 0xB3 + i * 0x20); r7 = (mmio_read_32(DBSC_DBPDRGD_0) & 0x7); r12 = (r5 >> 2); if (r6 - r12 > 0) { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8); mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, ((r7 + 1) & 0x7) | r2); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, ((r6 - r12) & 0xFF) | r2); } else { mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); r2 = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFFF8); mmio_write_32(DBSC_DBPDRGA_0, 0xB2 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, (r7 & 0x7) | r2); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); r2 = (mmio_read_32(DBSC_DBPDRGD_0) & 0xFFFFFF00); mmio_write_32(DBSC_DBPDRGA_0, 0xB0 + i * 0x20); mmio_write_32(DBSC_DBPDRGD_0, r2 | ((r6 + r5 + (r5 >> 1) + r12) & 0xFF)); } } mmio_write_32(DBSC_DBPDRGA_0, 0x000000A0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000C0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x000000E0); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000100); mmio_write_32(DBSC_DBPDRGD_0, 0x7C0002C5); mmio_write_32(DBSC_DBPDRGA_0, 0x00000001); mmio_write_32(DBSC_DBPDRGD_0, 0x00015001); mmio_write_32(DBSC_DBPDRGA_0, 0x00000006); while (!(mmio_read_32(DBSC_DBPDRGD_0) & BIT(0))) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000003); mmio_write_32(DBSC_DBPDRGD_0, 0x0380C700); mmio_write_32(DBSC_DBPDRGA_0, 0x00000007); while (mmio_read_32(DBSC_DBPDRGD_0) & BIT(30)) ; mmio_write_32(DBSC_DBPDRGA_0, 0x00000021); mmio_write_32(DBSC_DBPDRGD_0, 0x0024643E); mmio_write_32(DBSC_DBBUS0CNF1, 0x00000000); mmio_write_32(DBSC_DBBUS0CNF0, 0x00010001); mmio_write_32(DBSC_DBCALCNF, 0x0100200E); mmio_write_32(DBSC_DBRFCNF1, 0x00081860); mmio_write_32(DBSC_DBRFCNF2, 0x00010000); mmio_write_32(DBSC_DBDFICUPDCNF, 0x40100001); mmio_write_32(DBSC_DBRFEN, 0x00000001); mmio_write_32(DBSC_DBACEN, 0x00000001); mmio_write_32(DBSC_DBPDLK_0, 0x00000000); mmio_write_32(0xE67F0024, 0x00000001); mmio_write_32(DBSC_DBSYSCNT0, 0x00000000); return INITDRAM_OK; } int32_t rcar_dram_init(void) { return init_ddr_v3m_1600(); } trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_b/000077500000000000000000000000001355360272700244355ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_b/boot_init_dram.c000066400000000000000000003423051355360272700276010ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "ddr_regdef.h" #include "init_dram_tbl_h3.h" #include "init_dram_tbl_m3.h" #include "init_dram_tbl_h3ver2.h" #include "init_dram_tbl_m3n.h" #include "boot_init_dram_regdef.h" #include "boot_init_dram.h" #include "dram_sub_func.h" #include "micro_delay.h" #include "rcar_def.h" #define DDR_BACKUPMODE #define FATAL_MSG(x) NOTICE(x) /* variables */ #ifdef RCAR_DDR_FIXED_LSI_TYPE #ifndef RCAR_AUTO #define RCAR_AUTO 99 #define RCAR_H3 0 #define RCAR_M3 1 #define RCAR_M3N 2 #define RCAR_E3 3 /* NON */ #define RCAR_H3N 4 #define RCAR_CUT_10 0 #define RCAR_CUT_11 1 #define RCAR_CUT_20 10 #define RCAR_CUT_30 20 #endif #ifndef RCAR_LSI #define RCAR_LSI RCAR_AUTO #endif #if (RCAR_LSI == RCAR_AUTO) static uint32_t prr_product; static uint32_t prr_cut; #else #if (RCAR_LSI == RCAR_H3) static const uint32_t prr_product = PRR_PRODUCT_H3; #elif(RCAR_LSI == RCAR_M3) static const uint32_t prr_product = PRR_PRODUCT_M3; #elif(RCAR_LSI == RCAR_M3N) static const uint32_t prr_product = PRR_PRODUCT_M3N; #elif(RCAR_LSI == RCAR_H3N) static const uint32_t prr_product = PRR_PRODUCT_H3; #endif /* RCAR_LSI */ #ifndef RCAR_LSI_CUT static uint32_t prr_cut; #else /* RCAR_LSI_CUT */ #if (RCAR_LSI_CUT == RCAR_CUT_10) static const uint32_t prr_cut = PRR_PRODUCT_10; #elif(RCAR_LSI_CUT == RCAR_CUT_11) static const uint32_t prr_cut = PRR_PRODUCT_11; #elif(RCAR_LSI_CUT == RCAR_CUT_20) static const uint32_t prr_cut = PRR_PRODUCT_20; #elif(RCAR_LSI_CUT == RCAR_CUT_30) static const uint32_t prr_cut = PRR_PRODUCT_30; #endif /* RCAR_LSI_CUT */ #endif /* RCAR_LSI_CUT */ #endif /* RCAR_AUTO_NON */ #else /* RCAR_DDR_FIXED_LSI_TYPE */ static uint32_t prr_product; static uint32_t prr_cut; #endif /* RCAR_DDR_FIXED_LSI_TYPE */ static const uint32_t *p_ddr_regdef_tbl; static uint32_t brd_clk; static uint32_t brd_clkdiv; static uint32_t brd_clkdiva; static uint32_t ddr_mbps; static uint32_t ddr_mbpsdiv; static uint32_t ddr_tccd; static uint32_t ddr_phycaslice; static const struct _boardcnf *board_cnf; static uint32_t ddr_phyvalid; static uint32_t ddr_density[DRAM_CH_CNT][CS_CNT]; static uint32_t ch_have_this_cs[CS_CNT] __aligned(64); static uint32_t rdqdm_dly[DRAM_CH_CNT][CSAB_CNT][SLICE_CNT * 2][9]; static uint32_t max_density; static uint32_t ddr0800_mul; static uint32_t ddr_mul; static uint32_t DDR_PHY_SLICE_REGSET_OFS; static uint32_t DDR_PHY_ADR_V_REGSET_OFS; static uint32_t DDR_PHY_ADR_I_REGSET_OFS; static uint32_t DDR_PHY_ADR_G_REGSET_OFS; static uint32_t DDR_PI_REGSET_OFS; static uint32_t DDR_PHY_SLICE_REGSET_SIZE; static uint32_t DDR_PHY_ADR_V_REGSET_SIZE; static uint32_t DDR_PHY_ADR_I_REGSET_SIZE; static uint32_t DDR_PHY_ADR_G_REGSET_SIZE; static uint32_t DDR_PI_REGSET_SIZE; static uint32_t DDR_PHY_SLICE_REGSET_NUM; static uint32_t DDR_PHY_ADR_V_REGSET_NUM; static uint32_t DDR_PHY_ADR_I_REGSET_NUM; static uint32_t DDR_PHY_ADR_G_REGSET_NUM; static uint32_t DDR_PI_REGSET_NUM; static uint32_t DDR_PHY_ADR_I_NUM; #define DDR_PHY_REGSET_MAX 128 #define DDR_PI_REGSET_MAX 320 static uint32_t _cnf_DDR_PHY_SLICE_REGSET[DDR_PHY_REGSET_MAX]; static uint32_t _cnf_DDR_PHY_ADR_V_REGSET[DDR_PHY_REGSET_MAX]; static uint32_t _cnf_DDR_PHY_ADR_I_REGSET[DDR_PHY_REGSET_MAX]; static uint32_t _cnf_DDR_PHY_ADR_G_REGSET[DDR_PHY_REGSET_MAX]; static uint32_t _cnf_DDR_PI_REGSET[DDR_PI_REGSET_MAX]; static uint32_t pll3_mode; static uint32_t loop_max; #ifdef DDR_BACKUPMODE uint32_t ddr_backup; /* #define DDR_BACKUPMODE_HALF //for Half channel(ch0,1 only) */ #endif #ifdef ddr_qos_init_setting /* only for non qos_init */ #define OPERATING_FREQ (400U) /* Mhz */ #define BASE_SUB_SLOT_NUM (0x6U) #define SUB_SLOT_CYCLE (0x7EU) /* 126 */ #define QOSWT_WTSET0_CYCLE \ ((SUB_SLOT_CYCLE * BASE_SUB_SLOT_NUM * 1000U) / \ OPERATING_FREQ) /* unit:ns */ uint32_t get_refperiod(void) { return QOSWT_WTSET0_CYCLE; } #else /* ddr_qos_init_setting // only for non qos_init */ extern uint32_t get_refperiod(void); #endif /* ddr_qos_init_setting // only for non qos_init */ #define _reg_PHY_RX_CAL_X_NUM 11 static const uint32_t _reg_PHY_RX_CAL_X[_reg_PHY_RX_CAL_X_NUM] = { _reg_PHY_RX_CAL_DQ0, _reg_PHY_RX_CAL_DQ1, _reg_PHY_RX_CAL_DQ2, _reg_PHY_RX_CAL_DQ3, _reg_PHY_RX_CAL_DQ4, _reg_PHY_RX_CAL_DQ5, _reg_PHY_RX_CAL_DQ6, _reg_PHY_RX_CAL_DQ7, _reg_PHY_RX_CAL_DM, _reg_PHY_RX_CAL_DQS, _reg_PHY_RX_CAL_FDBK }; #define _reg_PHY_CLK_WRX_SLAVE_DELAY_NUM 10 static const uint32_t _reg_PHY_CLK_WRX_SLAVE_DELAY [_reg_PHY_CLK_WRX_SLAVE_DELAY_NUM] = { _reg_PHY_CLK_WRDQ0_SLAVE_DELAY, _reg_PHY_CLK_WRDQ1_SLAVE_DELAY, _reg_PHY_CLK_WRDQ2_SLAVE_DELAY, _reg_PHY_CLK_WRDQ3_SLAVE_DELAY, _reg_PHY_CLK_WRDQ4_SLAVE_DELAY, _reg_PHY_CLK_WRDQ5_SLAVE_DELAY, _reg_PHY_CLK_WRDQ6_SLAVE_DELAY, _reg_PHY_CLK_WRDQ7_SLAVE_DELAY, _reg_PHY_CLK_WRDM_SLAVE_DELAY, _reg_PHY_CLK_WRDQS_SLAVE_DELAY }; #define _reg_PHY_RDDQS_X_FALL_SLAVE_DELAY_NUM 9 static const uint32_t _reg_PHY_RDDQS_X_FALL_SLAVE_DELAY [_reg_PHY_RDDQS_X_FALL_SLAVE_DELAY_NUM] = { _reg_PHY_RDDQS_DQ0_FALL_SLAVE_DELAY, _reg_PHY_RDDQS_DQ1_FALL_SLAVE_DELAY, _reg_PHY_RDDQS_DQ2_FALL_SLAVE_DELAY, _reg_PHY_RDDQS_DQ3_FALL_SLAVE_DELAY, _reg_PHY_RDDQS_DQ4_FALL_SLAVE_DELAY, _reg_PHY_RDDQS_DQ5_FALL_SLAVE_DELAY, _reg_PHY_RDDQS_DQ6_FALL_SLAVE_DELAY, _reg_PHY_RDDQS_DQ7_FALL_SLAVE_DELAY, _reg_PHY_RDDQS_DM_FALL_SLAVE_DELAY }; #define _reg_PHY_RDDQS_X_RISE_SLAVE_DELAY_NUM 9 static const uint32_t _reg_PHY_RDDQS_X_RISE_SLAVE_DELAY [_reg_PHY_RDDQS_X_RISE_SLAVE_DELAY_NUM] = { _reg_PHY_RDDQS_DQ0_RISE_SLAVE_DELAY, _reg_PHY_RDDQS_DQ1_RISE_SLAVE_DELAY, _reg_PHY_RDDQS_DQ2_RISE_SLAVE_DELAY, _reg_PHY_RDDQS_DQ3_RISE_SLAVE_DELAY, _reg_PHY_RDDQS_DQ4_RISE_SLAVE_DELAY, _reg_PHY_RDDQS_DQ5_RISE_SLAVE_DELAY, _reg_PHY_RDDQS_DQ6_RISE_SLAVE_DELAY, _reg_PHY_RDDQS_DQ7_RISE_SLAVE_DELAY, _reg_PHY_RDDQS_DM_RISE_SLAVE_DELAY }; #define _reg_PHY_PAD_TERM_X_NUM 8 static const uint32_t _reg_PHY_PAD_TERM_X[_reg_PHY_PAD_TERM_X_NUM] = { _reg_PHY_PAD_FDBK_TERM, _reg_PHY_PAD_DATA_TERM, _reg_PHY_PAD_DQS_TERM, _reg_PHY_PAD_ADDR_TERM, _reg_PHY_PAD_CLK_TERM, _reg_PHY_PAD_CKE_TERM, _reg_PHY_PAD_RST_TERM, _reg_PHY_PAD_CS_TERM }; #define _reg_PHY_CLK_CACS_SLAVE_DELAY_X_NUM 10 static const uint32_t _reg_PHY_CLK_CACS_SLAVE_DELAY_X [_reg_PHY_CLK_CACS_SLAVE_DELAY_X_NUM] = { _reg_PHY_ADR0_CLK_WR_SLAVE_DELAY, _reg_PHY_ADR1_CLK_WR_SLAVE_DELAY, _reg_PHY_ADR2_CLK_WR_SLAVE_DELAY, _reg_PHY_ADR3_CLK_WR_SLAVE_DELAY, _reg_PHY_ADR4_CLK_WR_SLAVE_DELAY, _reg_PHY_ADR5_CLK_WR_SLAVE_DELAY, _reg_PHY_GRP_SLAVE_DELAY_0, _reg_PHY_GRP_SLAVE_DELAY_1, _reg_PHY_GRP_SLAVE_DELAY_2, _reg_PHY_GRP_SLAVE_DELAY_3 }; /* Prototypes */ static inline uint32_t vch_nxt(uint32_t pos); static void cpg_write_32(uint32_t a, uint32_t v); static void pll3_control(uint32_t high); static inline void dsb_sev(void); static void wait_dbcmd(void); static void send_dbcmd(uint32_t cmd); static uint32_t reg_ddrphy_read(uint32_t phyno, uint32_t regadd); static void reg_ddrphy_write(uint32_t phyno, uint32_t regadd, uint32_t regdata); static void reg_ddrphy_write_a(uint32_t regadd, uint32_t regdata); static inline uint32_t ddr_regdef(uint32_t _regdef); static inline uint32_t ddr_regdef_adr(uint32_t _regdef); static inline uint32_t ddr_regdef_lsb(uint32_t _regdef); static void ddr_setval_s(uint32_t ch, uint32_t slice, uint32_t _regdef, uint32_t val); static uint32_t ddr_getval_s(uint32_t ch, uint32_t slice, uint32_t _regdef); static void ddr_setval(uint32_t ch, uint32_t regdef, uint32_t val); static void ddr_setval_ach_s(uint32_t slice, uint32_t regdef, uint32_t val); static void ddr_setval_ach(uint32_t regdef, uint32_t val); static void ddr_setval_ach_as(uint32_t regdef, uint32_t val); static uint32_t ddr_getval(uint32_t ch, uint32_t regdef); static uint32_t ddr_getval_ach(uint32_t regdef, uint32_t *p); static uint32_t ddr_getval_ach_as(uint32_t regdef, uint32_t *p); static void _tblcopy(uint32_t *to, const uint32_t *from, uint32_t size); static void ddrtbl_setval(uint32_t *tbl, uint32_t _regdef, uint32_t val); static uint32_t ddrtbl_getval(uint32_t *tbl, uint32_t _regdef); static uint32_t ddrphy_regif_chk(void); static inline void ddrphy_regif_idle(void); static uint16_t _f_scale(uint32_t ddr_mbps, uint32_t ddr_mbpsdiv, uint32_t ps, uint16_t cyc); static void _f_scale_js2(uint32_t ddr_mbps, uint32_t ddr_mbpsdiv, uint16_t *js2); static int16_t _f_scale_adj(int16_t ps); static void ddrtbl_load(void); static void ddr_config_sub(void); static void get_ca_swizzle(uint32_t ch, uint32_t ddr_csn, uint32_t *p_swz); static void ddr_config_sub_h3v1x(void); static void ddr_config(void); static void dbsc_regset(void); static void dbsc_regset_post(void); static uint32_t dfi_init_start(void); static void change_lpddr4_en(uint32_t mode); static uint32_t set_term_code(void); static void ddr_register_set(void); static inline uint32_t wait_freqchgreq(uint32_t assert); static inline void set_freqchgack(uint32_t assert); static inline void set_dfifrequency(uint32_t freq); static uint32_t pll3_freq(uint32_t on); static void update_dly(void); static uint32_t pi_training_go(void); static uint32_t init_ddr(void); static uint32_t swlvl1(uint32_t ddr_csn, uint32_t reg_cs, uint32_t reg_kick); static uint32_t wdqdm_man1(void); static uint32_t wdqdm_man(void); static uint32_t rdqdm_man1(void); static uint32_t rdqdm_man(void); static int32_t _find_change(uint64_t val, uint32_t dir); static uint32_t _rx_offset_cal_updn(uint32_t code); static uint32_t rx_offset_cal(void); static uint32_t rx_offset_cal_hw(void); static void adjust_rddqs_latency(void); static void adjust_wpath_latency(void); struct ddrt_data { int32_t init_temp; /* Initial Temperature (do) */ uint32_t init_cal[4]; /* Initial io-code (4 is for H3) */ uint32_t tcomp_cal[4]; /* Temp. compensated io-code (4 is for H3) */ }; static struct ddrt_data tcal; static void pvtcode_update(void); static void pvtcode_update2(void); static void ddr_padcal_tcompensate_getinit(uint32_t override); /* load board configuration */ #include "boot_init_dram_config.c" #ifndef DDR_FAST_INIT static uint32_t rdqdm_le[DRAM_CH_CNT][CS_CNT][SLICE_CNT * 2][9]; static uint32_t rdqdm_te[DRAM_CH_CNT][CS_CNT][SLICE_CNT * 2][9]; static uint32_t rdqdm_nw[DRAM_CH_CNT][CS_CNT][SLICE_CNT * 2][9]; static uint32_t rdqdm_win[DRAM_CH_CNT][CS_CNT][SLICE_CNT]; static uint32_t rdqdm_st[DRAM_CH_CNT][CS_CNT][SLICE_CNT * 2]; static void rdqdm_clr1(uint32_t ch, uint32_t ddr_csn); static uint32_t rdqdm_ana1(uint32_t ch, uint32_t ddr_csn); static uint32_t wdqdm_le[DRAM_CH_CNT][CS_CNT][SLICE_CNT][9]; static uint32_t wdqdm_te[DRAM_CH_CNT][CS_CNT][SLICE_CNT][9]; static uint32_t wdqdm_dly[DRAM_CH_CNT][CS_CNT][SLICE_CNT][9]; static uint32_t wdqdm_st[DRAM_CH_CNT][CS_CNT][SLICE_CNT]; static uint32_t wdqdm_win[DRAM_CH_CNT][CS_CNT][SLICE_CNT]; static void wdqdm_clr1(uint32_t ch, uint32_t ddr_csn); static uint32_t wdqdm_ana1(uint32_t ch, uint32_t ddr_csn); #endif/* DDR_FAST_INIT */ /* macro for channel selection loop */ static inline uint32_t vch_nxt(uint32_t pos) { uint32_t posn; for (posn = pos; posn < DRAM_CH_CNT; posn++) { if (ddr_phyvalid & (1U << posn)) break; } return posn; } #define foreach_vch(ch) \ for (ch = vch_nxt(0); ch < DRAM_CH_CNT; ch = vch_nxt(ch + 1)) #define foreach_ech(ch) \ for (ch = 0; ch < DRAM_CH_CNT; ch++) /* Printing functions */ #define MSG_LF(...) /* clock settings, reset control */ static void cpg_write_32(uint32_t a, uint32_t v) { mmio_write_32(CPG_CPGWPR, ~v); mmio_write_32(a, v); } static void pll3_control(uint32_t high) { uint32_t data_l, data_div, data_mul, tmp_div; if (high) { tmp_div = 3999 * brd_clkdiv * (brd_clkdiva + 1) / (brd_clk * ddr_mul) / 2; data_mul = ((ddr_mul * tmp_div) - 1) << 24; pll3_mode = 1; loop_max = 2; } else { tmp_div = 3999 * brd_clkdiv * (brd_clkdiva + 1) / (brd_clk * ddr0800_mul) / 2; data_mul = ((ddr0800_mul * tmp_div) - 1) << 24; pll3_mode = 0; loop_max = 8; } switch (tmp_div) { case 1: data_div = 0; break; case 2: case 3: case 4: data_div = tmp_div; break; default: data_div = 6; data_mul = (data_mul * tmp_div) / 3; break; } data_mul = data_mul | (brd_clkdiva << 7); /* PLL3 disable */ data_l = mmio_read_32(CPG_PLLECR) & ~CPG_PLLECR_PLL3E_BIT; cpg_write_32(CPG_PLLECR, data_l); dsb_sev(); if ((prr_product == PRR_PRODUCT_M3) || ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_20))) { /* PLL3 DIV resetting(Lowest value:3) */ data_l = 0x00030003 | (0xFF80FF80 & mmio_read_32(CPG_FRQCRD)); cpg_write_32(CPG_FRQCRD, data_l); dsb_sev(); /* zb3 clk stop */ data_l = CPG_ZB3CKCR_ZB3ST_BIT | mmio_read_32(CPG_ZB3CKCR); cpg_write_32(CPG_ZB3CKCR, data_l); dsb_sev(); /* PLL3 enable */ data_l = CPG_PLLECR_PLL3E_BIT | mmio_read_32(CPG_PLLECR); cpg_write_32(CPG_PLLECR, data_l); dsb_sev(); do { data_l = mmio_read_32(CPG_PLLECR); } while ((data_l & CPG_PLLECR_PLL3ST_BIT) == 0); dsb_sev(); /* PLL3 DIV resetting (Highest value:0) */ data_l = (0xFF80FF80 & mmio_read_32(CPG_FRQCRD)); cpg_write_32(CPG_FRQCRD, data_l); dsb_sev(); /* DIV SET KICK */ data_l = CPG_FRQCRB_KICK_BIT | mmio_read_32(CPG_FRQCRB); cpg_write_32(CPG_FRQCRB, data_l); dsb_sev(); /* PLL3 multiplie set */ cpg_write_32(CPG_PLL3CR, data_mul); dsb_sev(); do { data_l = mmio_read_32(CPG_PLLECR); } while ((data_l & CPG_PLLECR_PLL3ST_BIT) == 0); dsb_sev(); /* PLL3 DIV resetting(Target value) */ data_l = (data_div << 16) | data_div | (mmio_read_32(CPG_FRQCRD) & 0xFF80FF80); cpg_write_32(CPG_FRQCRD, data_l); dsb_sev(); /* DIV SET KICK */ data_l = CPG_FRQCRB_KICK_BIT | mmio_read_32(CPG_FRQCRB); cpg_write_32(CPG_FRQCRB, data_l); dsb_sev(); do { data_l = mmio_read_32(CPG_PLLECR); } while ((data_l & CPG_PLLECR_PLL3ST_BIT) == 0); dsb_sev(); /* zb3 clk start */ data_l = (~CPG_ZB3CKCR_ZB3ST_BIT) & mmio_read_32(CPG_ZB3CKCR); cpg_write_32(CPG_ZB3CKCR, data_l); dsb_sev(); } else { /* H3Ver.3.0/M3N/V3H */ /* PLL3 multiplie set */ cpg_write_32(CPG_PLL3CR, data_mul); dsb_sev(); /* PLL3 DIV set(Target value) */ data_l = (data_div << 16) | data_div | (mmio_read_32(CPG_FRQCRD) & 0xFF80FF80); cpg_write_32(CPG_FRQCRD, data_l); /* DIV SET KICK */ data_l = CPG_FRQCRB_KICK_BIT | mmio_read_32(CPG_FRQCRB); cpg_write_32(CPG_FRQCRB, data_l); dsb_sev(); /* PLL3 enable */ data_l = CPG_PLLECR_PLL3E_BIT | mmio_read_32(CPG_PLLECR); cpg_write_32(CPG_PLLECR, data_l); dsb_sev(); do { data_l = mmio_read_32(CPG_PLLECR); } while ((data_l & CPG_PLLECR_PLL3ST_BIT) == 0); dsb_sev(); } } /* barrier */ static inline void dsb_sev(void) { __asm__ __volatile__("dsb sy"); } /* DDR memory register access */ static void wait_dbcmd(void) { uint32_t data_l; /* dummy read */ data_l = mmio_read_32(DBSC_DBCMD); dsb_sev(); while (1) { /* wait DBCMD 1=busy, 0=ready */ data_l = mmio_read_32(DBSC_DBWAIT); dsb_sev(); if ((data_l & 0x00000001) == 0x00) break; } } static void send_dbcmd(uint32_t cmd) { /* dummy read */ wait_dbcmd(); mmio_write_32(DBSC_DBCMD, cmd); dsb_sev(); } /* DDRPHY register access (raw) */ static uint32_t reg_ddrphy_read(uint32_t phyno, uint32_t regadd) { uint32_t val; uint32_t loop; val = 0; if ((prr_product != PRR_PRODUCT_M3N) && (prr_product != PRR_PRODUCT_V3H)) { mmio_write_32(DBSC_DBPDRGA(phyno), regadd); dsb_sev(); while (mmio_read_32(DBSC_DBPDRGA(phyno)) != regadd) { dsb_sev(); } dsb_sev(); for (loop = 0; loop < loop_max; loop++) { val = mmio_read_32(DBSC_DBPDRGD(phyno)); dsb_sev(); } (void)val; } else { mmio_write_32(DBSC_DBPDRGA(phyno), regadd | 0x00004000); dsb_sev(); while (mmio_read_32(DBSC_DBPDRGA(phyno)) != (regadd | 0x0000C000)) { dsb_sev(); }; val = mmio_read_32(DBSC_DBPDRGA(phyno)); mmio_write_32(DBSC_DBPDRGA(phyno), regadd | 0x00008000); while (mmio_read_32(DBSC_DBPDRGA(phyno)) != regadd) { dsb_sev(); }; dsb_sev(); mmio_write_32(DBSC_DBPDRGA(phyno), regadd | 0x00008000); while (mmio_read_32(DBSC_DBPDRGA(phyno)) != regadd) { dsb_sev(); }; dsb_sev(); val = mmio_read_32(DBSC_DBPDRGD(phyno)); dsb_sev(); (void)val; } return val; } static void reg_ddrphy_write(uint32_t phyno, uint32_t regadd, uint32_t regdata) { uint32_t val; uint32_t loop; if ((prr_product != PRR_PRODUCT_M3N) && (prr_product != PRR_PRODUCT_V3H)) { mmio_write_32(DBSC_DBPDRGA(phyno), regadd); dsb_sev(); for (loop = 0; loop < loop_max; loop++) { val = mmio_read_32(DBSC_DBPDRGA(phyno)); dsb_sev(); } mmio_write_32(DBSC_DBPDRGD(phyno), regdata); dsb_sev(); for (loop = 0; loop < loop_max; loop++) { val = mmio_read_32(DBSC_DBPDRGD(phyno)); dsb_sev(); } } else { mmio_write_32(DBSC_DBPDRGA(phyno), regadd); dsb_sev(); while (mmio_read_32(DBSC_DBPDRGA(phyno)) != regadd) { dsb_sev(); }; dsb_sev(); mmio_write_32(DBSC_DBPDRGD(phyno), regdata); dsb_sev(); while (mmio_read_32(DBSC_DBPDRGA(phyno)) != (regadd | 0x00008000)) { dsb_sev(); }; mmio_write_32(DBSC_DBPDRGA(phyno), regadd | 0x00008000); while (mmio_read_32(DBSC_DBPDRGA(phyno)) != regadd) { dsb_sev(); }; dsb_sev(); mmio_write_32(DBSC_DBPDRGA(phyno), regadd); } (void)val; } static void reg_ddrphy_write_a(uint32_t regadd, uint32_t regdata) { uint32_t ch; uint32_t val; uint32_t loop; if ((prr_product != PRR_PRODUCT_M3N) && (prr_product != PRR_PRODUCT_V3H)) { foreach_vch(ch) { mmio_write_32(DBSC_DBPDRGA(ch), regadd); dsb_sev(); } foreach_vch(ch) { mmio_write_32(DBSC_DBPDRGD(ch), regdata); dsb_sev(); } for (loop = 0; loop < loop_max; loop++) { val = mmio_read_32(DBSC_DBPDRGD(0)); dsb_sev(); } (void)val; } else { foreach_vch(ch) { reg_ddrphy_write(ch, regadd, regdata); dsb_sev(); } } } static inline void ddrphy_regif_idle(void) { uint32_t val; val = reg_ddrphy_read(0, ddr_regdef_adr(_reg_PI_INT_STATUS)); dsb_sev(); (void)val; } /* DDRPHY register access (field modify) */ static inline uint32_t ddr_regdef(uint32_t _regdef) { return p_ddr_regdef_tbl[_regdef]; } static inline uint32_t ddr_regdef_adr(uint32_t _regdef) { return DDR_REGDEF_ADR(p_ddr_regdef_tbl[_regdef]); } static inline uint32_t ddr_regdef_lsb(uint32_t _regdef) { return DDR_REGDEF_LSB(p_ddr_regdef_tbl[_regdef]); } static void ddr_setval_s(uint32_t ch, uint32_t slice, uint32_t _regdef, uint32_t val) { uint32_t adr; uint32_t lsb; uint32_t len; uint32_t msk; uint32_t tmp; uint32_t regdef; regdef = ddr_regdef(_regdef); adr = DDR_REGDEF_ADR(regdef) + 0x80 * slice; len = DDR_REGDEF_LEN(regdef); lsb = DDR_REGDEF_LSB(regdef); if (len == 0x20) msk = 0xffffffff; else msk = ((1U << len) - 1) << lsb; tmp = reg_ddrphy_read(ch, adr); tmp = (tmp & (~msk)) | ((val << lsb) & msk); reg_ddrphy_write(ch, adr, tmp); } static uint32_t ddr_getval_s(uint32_t ch, uint32_t slice, uint32_t _regdef) { uint32_t adr; uint32_t lsb; uint32_t len; uint32_t msk; uint32_t tmp; uint32_t regdef; regdef = ddr_regdef(_regdef); adr = DDR_REGDEF_ADR(regdef) + 0x80 * slice; len = DDR_REGDEF_LEN(regdef); lsb = DDR_REGDEF_LSB(regdef); if (len == 0x20) msk = 0xffffffff; else msk = ((1U << len) - 1); tmp = reg_ddrphy_read(ch, adr); tmp = (tmp >> lsb) & msk; return tmp; } static void ddr_setval(uint32_t ch, uint32_t regdef, uint32_t val) { ddr_setval_s(ch, 0, regdef, val); } static void ddr_setval_ach_s(uint32_t slice, uint32_t regdef, uint32_t val) { uint32_t ch; foreach_vch(ch) ddr_setval_s(ch, slice, regdef, val); } static void ddr_setval_ach(uint32_t regdef, uint32_t val) { ddr_setval_ach_s(0, regdef, val); } static void ddr_setval_ach_as(uint32_t regdef, uint32_t val) { uint32_t slice; for (slice = 0; slice < SLICE_CNT; slice++) ddr_setval_ach_s(slice, regdef, val); } static uint32_t ddr_getval(uint32_t ch, uint32_t regdef) { return ddr_getval_s(ch, 0, regdef); } static uint32_t ddr_getval_ach(uint32_t regdef, uint32_t *p) { uint32_t ch; foreach_vch(ch) p[ch] = ddr_getval_s(ch, 0, regdef); return p[0]; } static uint32_t ddr_getval_ach_as(uint32_t regdef, uint32_t *p) { uint32_t ch, slice; uint32_t *pp; pp = p; foreach_vch(ch) for (slice = 0; slice < SLICE_CNT; slice++) *pp++ = ddr_getval_s(ch, slice, regdef); return p[0]; } /* handling functions for setteing ddrphy value table */ static void _tblcopy(uint32_t *to, const uint32_t *from, uint32_t size) { uint32_t i; for (i = 0; i < size; i++) { to[i] = from[i]; } } static void ddrtbl_setval(uint32_t *tbl, uint32_t _regdef, uint32_t val) { uint32_t adr; uint32_t lsb; uint32_t len; uint32_t msk; uint32_t tmp; uint32_t adrmsk; uint32_t regdef; regdef = ddr_regdef(_regdef); adr = DDR_REGDEF_ADR(regdef); len = DDR_REGDEF_LEN(regdef); lsb = DDR_REGDEF_LSB(regdef); if (len == 0x20) msk = 0xffffffff; else msk = ((1U << len) - 1) << lsb; if (adr < 0x400) { adrmsk = 0xff; } else { adrmsk = 0x7f; } tmp = tbl[adr & adrmsk]; tmp = (tmp & (~msk)) | ((val << lsb) & msk); tbl[adr & adrmsk] = tmp; } static uint32_t ddrtbl_getval(uint32_t *tbl, uint32_t _regdef) { uint32_t adr; uint32_t lsb; uint32_t len; uint32_t msk; uint32_t tmp; uint32_t adrmsk; uint32_t regdef; regdef = ddr_regdef(_regdef); adr = DDR_REGDEF_ADR(regdef); len = DDR_REGDEF_LEN(regdef); lsb = DDR_REGDEF_LSB(regdef); if (len == 0x20) msk = 0xffffffff; else msk = ((1U << len) - 1); if (adr < 0x400) { adrmsk = 0xff; } else { adrmsk = 0x7f; } tmp = tbl[adr & adrmsk]; tmp = (tmp >> lsb) & msk; return tmp; } /* DDRPHY register access handling */ static uint32_t ddrphy_regif_chk(void) { uint32_t tmp_ach[DRAM_CH_CNT]; uint32_t ch; uint32_t err; uint32_t PI_VERSION_CODE; if (((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) || (prr_product == PRR_PRODUCT_M3)) { PI_VERSION_CODE = 0x2041; /* H3 Ver.1.x/M3-W */ } else { PI_VERSION_CODE = 0x2040; /* H3 Ver.2.0 or later/M3-N/V3H */ } ddr_getval_ach(_reg_PI_VERSION, (uint32_t *)tmp_ach); err = 0; foreach_vch(ch) { if (tmp_ach[ch] != PI_VERSION_CODE) err = 1; } return err; } /* functions and parameters for timing setting */ struct _jedec_spec1 { uint16_t fx3; uint8_t rlwodbi; uint8_t rlwdbi; uint8_t WL; uint8_t nwr; uint8_t nrtp; uint8_t MR1; uint8_t MR2; }; #define JS1_USABLEC_SPEC_LO 2 #define JS1_USABLEC_SPEC_HI 5 #define JS1_FREQ_TBL_NUM 8 #define JS1_MR1(f) (0x04 | ((f) << 4)) #define JS1_MR2(f) (0x00 | ((f) << 3) | (f)) const struct _jedec_spec1 js1[JS1_FREQ_TBL_NUM] = { /* 533.333Mbps */ { 800, 6, 6, 4, 6, 8, JS1_MR1(0), JS1_MR2(0) | 0x40 }, /* 1066.666Mbps */ { 1600, 10, 12, 8, 10, 8, JS1_MR1(1), JS1_MR2(1) | 0x40 }, /* 1600.000Mbps */ { 2400, 14, 16, 12, 16, 8, JS1_MR1(2), JS1_MR2(2) | 0x40 }, /* 2133.333Mbps */ { 3200, 20, 22, 10, 20, 8, JS1_MR1(3), JS1_MR2(3) }, /* 2666.666Mbps */ { 4000, 24, 28, 12, 24, 10, JS1_MR1(4), JS1_MR2(4) }, /* 3200.000Mbps */ { 4800, 28, 32, 14, 30, 12, JS1_MR1(5), JS1_MR2(5) }, /* 3733.333Mbps */ { 5600, 32, 36, 16, 34, 14, JS1_MR1(6), JS1_MR2(6) }, /* 4266.666Mbps */ { 6400, 36, 40, 18, 40, 16, JS1_MR1(7), JS1_MR2(7) } }; struct _jedec_spec2 { uint16_t ps; uint16_t cyc; }; #define js2_tsr 0 #define js2_txp 1 #define js2_trtp 2 #define js2_trcd 3 #define js2_trppb 4 #define js2_trpab 5 #define js2_tras 6 #define js2_twr 7 #define js2_twtr 8 #define js2_trrd 9 #define js2_tppd 10 #define js2_tfaw 11 #define js2_tdqsck 12 #define js2_tckehcmd 13 #define js2_tckelcmd 14 #define js2_tckelpd 15 #define js2_tmrr 16 #define js2_tmrw 17 #define js2_tmrd 18 #define js2_tzqcalns 19 #define js2_tzqlat 20 #define js2_tiedly 21 #define JS2_TBLCNT 22 #define js2_trcpb (JS2_TBLCNT) #define js2_trcab (JS2_TBLCNT + 1) #define js2_trfcab (JS2_TBLCNT + 2) #define JS2_CNT (JS2_TBLCNT + 3) #ifndef JS2_DERATE #define JS2_DERATE 0 #endif const struct _jedec_spec2 jedec_spec2[2][JS2_TBLCNT] = { { /*tSR */ {15000, 3}, /*tXP */ {7500, 3}, /*tRTP */ {7500, 8}, /*tRCD */ {18000, 4}, /*tRPpb */ {18000, 3}, /*tRPab */ {21000, 3}, /*tRAS */ {42000, 3}, /*tWR */ {18000, 4}, /*tWTR */ {10000, 8}, /*tRRD */ {10000, 4}, /*tPPD */ {0, 0}, /*tFAW */ {40000, 0}, /*tDQSCK*/ {3500, 0}, /*tCKEHCMD*/ {7500, 3}, /*tCKELCMD*/ {7500, 3}, /*tCKELPD*/ {7500, 3}, /*tMRR*/ {0, 8}, /*tMRW*/ {10000, 10}, /*tMRD*/ {14000, 10}, /*tZQCALns*/ {1000 * 10, 0}, /*tZQLAT*/ {30000, 10}, /*tIEdly*/ {12500, 0} }, { /*tSR */ {15000, 3}, /*tXP */ {7500, 3}, /*tRTP */ {7500, 8}, /*tRCD */ {19875, 4}, /*tRPpb */ {19875, 3}, /*tRPab */ {22875, 3}, /*tRAS */ {43875, 3}, /*tWR */ {18000, 4}, /*tWTR */ {10000, 8}, /*tRRD */ {11875, 4}, /*tPPD */ {0, 0}, /*tFAW */ {40000, 0}, /*tDQSCK*/ {3600, 0}, /*tCKEHCMD*/ {7500, 3}, /*tCKELCMD*/ {7500, 3}, /*tCKELPD*/ {7500, 3}, /*tMRR*/ {0, 8}, /*tMRW*/ {10000, 10}, /*tMRD*/ {14000, 10}, /*tZQCALns*/ {1000 * 10, 0}, /*tZQLAT*/ {30000, 10}, /*tIEdly*/ {12500, 0} } }; const uint16_t jedec_spec2_trfc_ab[7] = { /* 4Gb, 6Gb, 8Gb,12Gb, 16Gb, 24Gb(non), 32Gb(non) */ 130, 180, 180, 280, 280, 560, 560 }; static uint32_t js1_ind; static uint16_t js2[JS2_CNT]; static uint8_t RL; static uint8_t WL; static uint16_t _f_scale(uint32_t ddr_mbps, uint32_t ddr_mbpsdiv, uint32_t ps, uint16_t cyc) { uint32_t tmp; uint32_t div; tmp = (((uint32_t)(ps) + 9) / 10) * ddr_mbps; div = tmp / (200000 * ddr_mbpsdiv); if (tmp != (div * 200000 * ddr_mbpsdiv)) div = div + 1; if (div > cyc) return (uint16_t)div; return cyc; } static void _f_scale_js2(uint32_t ddr_mbps, uint32_t ddr_mbpsdiv, uint16_t *js2) { int i; for (i = 0; i < JS2_TBLCNT; i++) { js2[i] = _f_scale(ddr_mbps, ddr_mbpsdiv, 1UL * jedec_spec2[JS2_DERATE][i].ps, jedec_spec2[JS2_DERATE][i].cyc); } js2[js2_trcpb] = js2[js2_tras] + js2[js2_trppb]; js2[js2_trcab] = js2[js2_tras] + js2[js2_trpab]; } /* scaler for DELAY value */ static int16_t _f_scale_adj(int16_t ps) { int32_t tmp; /* * tmp = (int32_t)512 * ps * ddr_mbps /2 / ddr_mbpsdiv / 1000 / 1000; * = ps * ddr_mbps /2 / ddr_mbpsdiv *512 / 8 / 8 / 125 / 125 * = ps * ddr_mbps / ddr_mbpsdiv *4 / 125 / 125 */ tmp = (int32_t)4 * (int32_t)ps * (int32_t)ddr_mbps / (int32_t)ddr_mbpsdiv; tmp = (int32_t)tmp / (int32_t)15625; return (int16_t)tmp; } static const uint32_t reg_pi_mr1_data_fx_csx[2][CSAB_CNT] = { { _reg_PI_MR1_DATA_F0_0, _reg_PI_MR1_DATA_F0_1, _reg_PI_MR1_DATA_F0_2, _reg_PI_MR1_DATA_F0_3}, { _reg_PI_MR1_DATA_F1_0, _reg_PI_MR1_DATA_F1_1, _reg_PI_MR1_DATA_F1_2, _reg_PI_MR1_DATA_F1_3} }; static const uint32_t reg_pi_mr2_data_fx_csx[2][CSAB_CNT] = { { _reg_PI_MR2_DATA_F0_0, _reg_PI_MR2_DATA_F0_1, _reg_PI_MR2_DATA_F0_2, _reg_PI_MR2_DATA_F0_3}, { _reg_PI_MR2_DATA_F1_0, _reg_PI_MR2_DATA_F1_1, _reg_PI_MR2_DATA_F1_2, _reg_PI_MR2_DATA_F1_3} }; static const uint32_t reg_pi_mr3_data_fx_csx[2][CSAB_CNT] = { { _reg_PI_MR3_DATA_F0_0, _reg_PI_MR3_DATA_F0_1, _reg_PI_MR3_DATA_F0_2, _reg_PI_MR3_DATA_F0_3}, { _reg_PI_MR3_DATA_F1_0, _reg_PI_MR3_DATA_F1_1, _reg_PI_MR3_DATA_F1_2, _reg_PI_MR3_DATA_F1_3} }; const uint32_t reg_pi_mr11_data_fx_csx[2][CSAB_CNT] = { { _reg_PI_MR11_DATA_F0_0, _reg_PI_MR11_DATA_F0_1, _reg_PI_MR11_DATA_F0_2, _reg_PI_MR11_DATA_F0_3}, { _reg_PI_MR11_DATA_F1_0, _reg_PI_MR11_DATA_F1_1, _reg_PI_MR11_DATA_F1_2, _reg_PI_MR11_DATA_F1_3} }; const uint32_t reg_pi_mr12_data_fx_csx[2][CSAB_CNT] = { { _reg_PI_MR12_DATA_F0_0, _reg_PI_MR12_DATA_F0_1, _reg_PI_MR12_DATA_F0_2, _reg_PI_MR12_DATA_F0_3}, { _reg_PI_MR12_DATA_F1_0, _reg_PI_MR12_DATA_F1_1, _reg_PI_MR12_DATA_F1_2, _reg_PI_MR12_DATA_F1_3} }; const uint32_t reg_pi_mr14_data_fx_csx[2][CSAB_CNT] = { { _reg_PI_MR14_DATA_F0_0, _reg_PI_MR14_DATA_F0_1, _reg_PI_MR14_DATA_F0_2, _reg_PI_MR14_DATA_F0_3}, { _reg_PI_MR14_DATA_F1_0, _reg_PI_MR14_DATA_F1_1, _reg_PI_MR14_DATA_F1_2, _reg_PI_MR14_DATA_F1_3} }; /* * regif pll w/a ( REGIF H3 Ver.2.0 or later/M3-N/V3H WA ) */ static void regif_pll_wa(void) { uint32_t ch; if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { // PLL setting for PHY : H3 Ver.1.x reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_PLL_WAIT), (0x0064U << ddr_regdef_lsb(_reg_PHY_PLL_WAIT))); reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_PLL_CTRL), ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_PLL_CTRL)); reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_LP4_BOOT_PLL_CTRL), ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_LP4_BOOT_PLL_CTRL)); } else { /* PLL setting for PHY : M3-W/M3-N/V3H/H3 Ver.2.0 or later */ reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_PLL_WAIT), (0x5064U << ddr_regdef_lsb(_reg_PHY_PLL_WAIT))); reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_PLL_CTRL), (ddrtbl_getval (_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_PLL_CTRL_TOP) << 16) | ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_PLL_CTRL)); reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_PLL_CTRL_CA), ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_PLL_CTRL_CA)); reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_LP4_BOOT_PLL_CTRL), (ddrtbl_getval (_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_LP4_BOOT_PLL_CTRL_CA) << 16) | ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_LP4_BOOT_PLL_CTRL)); reg_ddrphy_write_a(ddr_regdef_adr (_reg_PHY_LP4_BOOT_TOP_PLL_CTRL), ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_LP4_BOOT_TOP_PLL_CTRL )); } reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_LPDDR3_CS), _cnf_DDR_PHY_ADR_G_REGSET [ddr_regdef_adr(_reg_PHY_LPDDR3_CS) - DDR_PHY_ADR_G_REGSET_OFS]); /* protect register interface */ ddrphy_regif_idle(); pll3_control(0); if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { /* non */ } else { reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_DLL_RST_EN), (0x01U << ddr_regdef_lsb(_reg_PHY_DLL_RST_EN))); ddrphy_regif_idle(); } /* init start */ /* dbdficnt0: * dfi_dram_clk_disable=1 * dfi_frequency = 0 * freq_ratio = 01 (2:1) * init_start =0 */ foreach_vch(ch) mmio_write_32(DBSC_DBDFICNT(ch), 0x00000F10); dsb_sev(); /* dbdficnt0: * dfi_dram_clk_disable=1 * dfi_frequency = 0 * freq_ratio = 01 (2:1) * init_start =1 */ foreach_vch(ch) mmio_write_32(DBSC_DBDFICNT(ch), 0x00000F11); dsb_sev(); foreach_ech(ch) if ((board_cnf->phyvalid) & BIT(ch)) while ((mmio_read_32(DBSC_PLL_LOCK(ch)) & 0x1f) != 0x1f) ; dsb_sev(); } /* load table data into DDR registers */ static void ddrtbl_load(void) { uint32_t i; uint32_t slice; uint32_t csab; uint32_t adr; uint32_t data_l; uint32_t tmp[3]; uint16_t dataS; /* TIMING REGISTERS */ /* search jedec_spec1 index */ for (i = JS1_USABLEC_SPEC_LO; i < JS1_FREQ_TBL_NUM - 1; i++) { if (js1[i].fx3 * 2U * ddr_mbpsdiv >= ddr_mbps * 3U) break; } if (i > JS1_USABLEC_SPEC_HI) js1_ind = JS1_USABLEC_SPEC_HI; else js1_ind = i; if (board_cnf->dbi_en) RL = js1[js1_ind].rlwdbi; else RL = js1[js1_ind].rlwodbi; WL = js1[js1_ind].WL; /* calculate jedec_spec2 */ _f_scale_js2(ddr_mbps, ddr_mbpsdiv, js2); /* PREPARE TBL */ if (prr_product == PRR_PRODUCT_H3) { if (prr_cut <= PRR_PRODUCT_11) { /* H3 Ver.1.x */ _tblcopy(_cnf_DDR_PHY_SLICE_REGSET, DDR_PHY_SLICE_REGSET_H3, DDR_PHY_SLICE_REGSET_NUM_H3); _tblcopy(_cnf_DDR_PHY_ADR_V_REGSET, DDR_PHY_ADR_V_REGSET_H3, DDR_PHY_ADR_V_REGSET_NUM_H3); _tblcopy(_cnf_DDR_PHY_ADR_I_REGSET, DDR_PHY_ADR_I_REGSET_H3, DDR_PHY_ADR_I_REGSET_NUM_H3); _tblcopy(_cnf_DDR_PHY_ADR_G_REGSET, DDR_PHY_ADR_G_REGSET_H3, DDR_PHY_ADR_G_REGSET_NUM_H3); _tblcopy(_cnf_DDR_PI_REGSET, DDR_PI_REGSET_H3, DDR_PI_REGSET_NUM_H3); DDR_PHY_SLICE_REGSET_OFS = DDR_PHY_SLICE_REGSET_OFS_H3; DDR_PHY_ADR_V_REGSET_OFS = DDR_PHY_ADR_V_REGSET_OFS_H3; DDR_PHY_ADR_I_REGSET_OFS = DDR_PHY_ADR_I_REGSET_OFS_H3; DDR_PHY_ADR_G_REGSET_OFS = DDR_PHY_ADR_G_REGSET_OFS_H3; DDR_PI_REGSET_OFS = DDR_PI_REGSET_OFS_H3; DDR_PHY_SLICE_REGSET_SIZE = DDR_PHY_SLICE_REGSET_SIZE_H3; DDR_PHY_ADR_V_REGSET_SIZE = DDR_PHY_ADR_V_REGSET_SIZE_H3; DDR_PHY_ADR_I_REGSET_SIZE = DDR_PHY_ADR_I_REGSET_SIZE_H3; DDR_PHY_ADR_G_REGSET_SIZE = DDR_PHY_ADR_G_REGSET_SIZE_H3; DDR_PI_REGSET_SIZE = DDR_PI_REGSET_SIZE_H3; DDR_PHY_SLICE_REGSET_NUM = DDR_PHY_SLICE_REGSET_NUM_H3; DDR_PHY_ADR_V_REGSET_NUM = DDR_PHY_ADR_V_REGSET_NUM_H3; DDR_PHY_ADR_I_REGSET_NUM = DDR_PHY_ADR_I_REGSET_NUM_H3; DDR_PHY_ADR_G_REGSET_NUM = DDR_PHY_ADR_G_REGSET_NUM_H3; DDR_PI_REGSET_NUM = DDR_PI_REGSET_NUM_H3; DDR_PHY_ADR_I_NUM = 1; } else { /* H3 Ver.2.0 or later */ _tblcopy(_cnf_DDR_PHY_SLICE_REGSET, DDR_PHY_SLICE_REGSET_H3VER2, DDR_PHY_SLICE_REGSET_NUM_H3VER2); _tblcopy(_cnf_DDR_PHY_ADR_V_REGSET, DDR_PHY_ADR_V_REGSET_H3VER2, DDR_PHY_ADR_V_REGSET_NUM_H3VER2); _tblcopy(_cnf_DDR_PHY_ADR_G_REGSET, DDR_PHY_ADR_G_REGSET_H3VER2, DDR_PHY_ADR_G_REGSET_NUM_H3VER2); _tblcopy(_cnf_DDR_PI_REGSET, DDR_PI_REGSET_H3VER2, DDR_PI_REGSET_NUM_H3VER2); DDR_PHY_SLICE_REGSET_OFS = DDR_PHY_SLICE_REGSET_OFS_H3VER2; DDR_PHY_ADR_V_REGSET_OFS = DDR_PHY_ADR_V_REGSET_OFS_H3VER2; DDR_PHY_ADR_G_REGSET_OFS = DDR_PHY_ADR_G_REGSET_OFS_H3VER2; DDR_PI_REGSET_OFS = DDR_PI_REGSET_OFS_H3VER2; DDR_PHY_SLICE_REGSET_SIZE = DDR_PHY_SLICE_REGSET_SIZE_H3VER2; DDR_PHY_ADR_V_REGSET_SIZE = DDR_PHY_ADR_V_REGSET_SIZE_H3VER2; DDR_PHY_ADR_G_REGSET_SIZE = DDR_PHY_ADR_G_REGSET_SIZE_H3VER2; DDR_PI_REGSET_SIZE = DDR_PI_REGSET_SIZE_H3VER2; DDR_PHY_SLICE_REGSET_NUM = DDR_PHY_SLICE_REGSET_NUM_H3VER2; DDR_PHY_ADR_V_REGSET_NUM = DDR_PHY_ADR_V_REGSET_NUM_H3VER2; DDR_PHY_ADR_G_REGSET_NUM = DDR_PHY_ADR_G_REGSET_NUM_H3VER2; DDR_PI_REGSET_NUM = DDR_PI_REGSET_NUM_H3VER2; DDR_PHY_ADR_I_NUM = 0; } } else if (prr_product == PRR_PRODUCT_M3) { /* M3-W */ _tblcopy(_cnf_DDR_PHY_SLICE_REGSET, DDR_PHY_SLICE_REGSET_M3, DDR_PHY_SLICE_REGSET_NUM_M3); _tblcopy(_cnf_DDR_PHY_ADR_V_REGSET, DDR_PHY_ADR_V_REGSET_M3, DDR_PHY_ADR_V_REGSET_NUM_M3); _tblcopy(_cnf_DDR_PHY_ADR_I_REGSET, DDR_PHY_ADR_I_REGSET_M3, DDR_PHY_ADR_I_REGSET_NUM_M3); _tblcopy(_cnf_DDR_PHY_ADR_G_REGSET, DDR_PHY_ADR_G_REGSET_M3, DDR_PHY_ADR_G_REGSET_NUM_M3); _tblcopy(_cnf_DDR_PI_REGSET, DDR_PI_REGSET_M3, DDR_PI_REGSET_NUM_M3); DDR_PHY_SLICE_REGSET_OFS = DDR_PHY_SLICE_REGSET_OFS_M3; DDR_PHY_ADR_V_REGSET_OFS = DDR_PHY_ADR_V_REGSET_OFS_M3; DDR_PHY_ADR_I_REGSET_OFS = DDR_PHY_ADR_I_REGSET_OFS_M3; DDR_PHY_ADR_G_REGSET_OFS = DDR_PHY_ADR_G_REGSET_OFS_M3; DDR_PI_REGSET_OFS = DDR_PI_REGSET_OFS_M3; DDR_PHY_SLICE_REGSET_SIZE = DDR_PHY_SLICE_REGSET_SIZE_M3; DDR_PHY_ADR_V_REGSET_SIZE = DDR_PHY_ADR_V_REGSET_SIZE_M3; DDR_PHY_ADR_I_REGSET_SIZE = DDR_PHY_ADR_I_REGSET_SIZE_M3; DDR_PHY_ADR_G_REGSET_SIZE = DDR_PHY_ADR_G_REGSET_SIZE_M3; DDR_PI_REGSET_SIZE = DDR_PI_REGSET_SIZE_M3; DDR_PHY_SLICE_REGSET_NUM = DDR_PHY_SLICE_REGSET_NUM_M3; DDR_PHY_ADR_V_REGSET_NUM = DDR_PHY_ADR_V_REGSET_NUM_M3; DDR_PHY_ADR_I_REGSET_NUM = DDR_PHY_ADR_I_REGSET_NUM_M3; DDR_PHY_ADR_G_REGSET_NUM = DDR_PHY_ADR_G_REGSET_NUM_M3; DDR_PI_REGSET_NUM = DDR_PI_REGSET_NUM_M3; DDR_PHY_ADR_I_NUM = 2; } else { /* M3-N/V3H */ _tblcopy(_cnf_DDR_PHY_SLICE_REGSET, DDR_PHY_SLICE_REGSET_M3N, DDR_PHY_SLICE_REGSET_NUM_M3N); _tblcopy(_cnf_DDR_PHY_ADR_V_REGSET, DDR_PHY_ADR_V_REGSET_M3N, DDR_PHY_ADR_V_REGSET_NUM_M3N); _tblcopy(_cnf_DDR_PHY_ADR_I_REGSET, DDR_PHY_ADR_I_REGSET_M3N, DDR_PHY_ADR_I_REGSET_NUM_M3N); _tblcopy(_cnf_DDR_PHY_ADR_G_REGSET, DDR_PHY_ADR_G_REGSET_M3N, DDR_PHY_ADR_G_REGSET_NUM_M3N); _tblcopy(_cnf_DDR_PI_REGSET, DDR_PI_REGSET_M3N, DDR_PI_REGSET_NUM_M3N); DDR_PHY_SLICE_REGSET_OFS = DDR_PHY_SLICE_REGSET_OFS_M3N; DDR_PHY_ADR_V_REGSET_OFS = DDR_PHY_ADR_V_REGSET_OFS_M3N; DDR_PHY_ADR_I_REGSET_OFS = DDR_PHY_ADR_I_REGSET_OFS_M3N; DDR_PHY_ADR_G_REGSET_OFS = DDR_PHY_ADR_G_REGSET_OFS_M3N; DDR_PI_REGSET_OFS = DDR_PI_REGSET_OFS_M3N; DDR_PHY_SLICE_REGSET_SIZE = DDR_PHY_SLICE_REGSET_SIZE_M3N; DDR_PHY_ADR_V_REGSET_SIZE = DDR_PHY_ADR_V_REGSET_SIZE_M3N; DDR_PHY_ADR_I_REGSET_SIZE = DDR_PHY_ADR_I_REGSET_SIZE_M3N; DDR_PHY_ADR_G_REGSET_SIZE = DDR_PHY_ADR_G_REGSET_SIZE_M3N; DDR_PI_REGSET_SIZE = DDR_PI_REGSET_SIZE_M3N; DDR_PHY_SLICE_REGSET_NUM = DDR_PHY_SLICE_REGSET_NUM_M3N; DDR_PHY_ADR_V_REGSET_NUM = DDR_PHY_ADR_V_REGSET_NUM_M3N; DDR_PHY_ADR_I_REGSET_NUM = DDR_PHY_ADR_I_REGSET_NUM_M3N; DDR_PHY_ADR_G_REGSET_NUM = DDR_PHY_ADR_G_REGSET_NUM_M3N; DDR_PI_REGSET_NUM = DDR_PI_REGSET_NUM_M3N; DDR_PHY_ADR_I_NUM = 2; } /* PLL CODE CHANGE */ if ((prr_product == PRR_PRODUCT_H3) && (prr_cut == PRR_PRODUCT_11)) { ddrtbl_setval(_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_PLL_CTRL, 0x1142); ddrtbl_setval(_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_LP4_BOOT_PLL_CTRL, 0x1142); } /* on fly gate adjust */ if ((prr_product == PRR_PRODUCT_M3) && (prr_cut == PRR_PRODUCT_10)) { ddrtbl_setval(_cnf_DDR_PHY_SLICE_REGSET, _reg_ON_FLY_GATE_ADJUST_EN, 0x00); } /* Adjust PI parameters */ #ifdef _def_LPDDR4_ODT for (i = 0; i < 2; i++) { for (csab = 0; csab < CSAB_CNT; csab++) { ddrtbl_setval(_cnf_DDR_PI_REGSET, reg_pi_mr11_data_fx_csx[i][csab], _def_LPDDR4_ODT); } } #endif /* _def_LPDDR4_ODT */ #ifdef _def_LPDDR4_VREFCA for (i = 0; i < 2; i++) { for (csab = 0; csab < CSAB_CNT; csab++) { ddrtbl_setval(_cnf_DDR_PI_REGSET, reg_pi_mr12_data_fx_csx[i][csab], _def_LPDDR4_VREFCA); } } #endif /* _def_LPDDR4_VREFCA */ if ((prr_product == PRR_PRODUCT_M3N) || (prr_product == PRR_PRODUCT_V3H)) { js2[js2_tiedly] = _f_scale(ddr_mbps, ddr_mbpsdiv, 7000, 0) + 7U; if (js2[js2_tiedly] > (RL)) js2[js2_tiedly] = RL; } else if ((prr_product == PRR_PRODUCT_H3) && (prr_cut > PRR_PRODUCT_11)) { js2[js2_tiedly] = _f_scale(ddr_mbps, ddr_mbpsdiv, 9000, 0) + 4U; } else if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { js2[js2_tiedly] = _f_scale(ddr_mbps, ddr_mbpsdiv, 10000, 0); } if (((prr_product == PRR_PRODUCT_H3) && (prr_cut > PRR_PRODUCT_11)) || (prr_product == PRR_PRODUCT_M3N) || (prr_product == PRR_PRODUCT_V3H)) { if ((js2[js2_tiedly]) >= 0x1e) dataS = 0x1e; else dataS = js2[js2_tiedly]; } else { if ((js2[js2_tiedly]) >= 0x0e) dataS = 0x0e; else dataS = js2[js2_tiedly]; } ddrtbl_setval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_RDDATA_EN_DLY, dataS); ddrtbl_setval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_RDDATA_EN_TSEL_DLY, (dataS - 2)); if ((prr_product == PRR_PRODUCT_M3N) || (prr_product == PRR_PRODUCT_V3H)) { ddrtbl_setval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_RDDATA_EN_OE_DLY, dataS); } ddrtbl_setval(_cnf_DDR_PI_REGSET, _reg_PI_RDLAT_ADJ_F1, RL - dataS); if (ddrtbl_getval (_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_WRITE_PATH_LAT_ADD)) { data_l = WL - 1; } else { data_l = WL; } ddrtbl_setval(_cnf_DDR_PI_REGSET, _reg_PI_WRLAT_ADJ_F1, data_l - 2); ddrtbl_setval(_cnf_DDR_PI_REGSET, _reg_PI_WRLAT_F1, data_l); if (board_cnf->dbi_en) { ddrtbl_setval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_DBI_MODE, 0x01); ddrtbl_setval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_WDQLVL_DATADM_MASK, 0x000); } else { ddrtbl_setval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_DBI_MODE, 0x00); ddrtbl_setval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_WDQLVL_DATADM_MASK, 0x100); } tmp[0] = js1[js1_ind].MR1; tmp[1] = js1[js1_ind].MR2; data_l = ddrtbl_getval(_cnf_DDR_PI_REGSET, _reg_PI_MR3_DATA_F1_0); if (board_cnf->dbi_en) tmp[2] = data_l | 0xc0; else tmp[2] = data_l & (~0xc0); for (i = 0; i < 2; i++) { for (csab = 0; csab < CSAB_CNT; csab++) { ddrtbl_setval(_cnf_DDR_PI_REGSET, reg_pi_mr1_data_fx_csx[i][csab], tmp[0]); ddrtbl_setval(_cnf_DDR_PI_REGSET, reg_pi_mr2_data_fx_csx[i][csab], tmp[1]); ddrtbl_setval(_cnf_DDR_PI_REGSET, reg_pi_mr3_data_fx_csx[i][csab], tmp[2]); } } /* DDRPHY INT START */ if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { /* non */ } else { regif_pll_wa(); } /* FREQ_SEL_MULTICAST & PER_CS_TRAINING_MULTICAST SET (for safety) */ reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_FREQ_SEL_MULTICAST_EN), BIT(ddr_regdef_lsb(_reg_PHY_FREQ_SEL_MULTICAST_EN))); ddr_setval_ach_as(_reg_PHY_PER_CS_TRAINING_MULTICAST_EN, 0x01); /* SET DATA SLICE TABLE */ for (slice = 0; slice < SLICE_CNT; slice++) { adr = DDR_PHY_SLICE_REGSET_OFS + DDR_PHY_SLICE_REGSET_SIZE * slice; for (i = 0; i < DDR_PHY_SLICE_REGSET_NUM; i++) { reg_ddrphy_write_a(adr + i, _cnf_DDR_PHY_SLICE_REGSET[i]); } } /* SET ADR SLICE TABLE */ adr = DDR_PHY_ADR_V_REGSET_OFS; for (i = 0; i < DDR_PHY_ADR_V_REGSET_NUM; i++) { reg_ddrphy_write_a(adr + i, _cnf_DDR_PHY_ADR_V_REGSET[i]); } if (((prr_product == PRR_PRODUCT_M3) || (prr_product == PRR_PRODUCT_M3N)) && ((0x00ffffff & (uint32_t)((board_cnf->ch[0].ca_swap) >> 40)) != 0x00)) { adr = DDR_PHY_ADR_I_REGSET_OFS + DDR_PHY_ADR_I_REGSET_SIZE; for (i = 0; i < DDR_PHY_ADR_V_REGSET_NUM; i++) { reg_ddrphy_write_a(adr + i, _cnf_DDR_PHY_ADR_V_REGSET[i]); } ddrtbl_setval(_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_ADR_DISABLE, 0x02); DDR_PHY_ADR_I_NUM -= 1; ddr_phycaslice = 1; #ifndef _def_LPDDR4_ODT for (i = 0; i < 2; i++) { for (csab = 0; csab < CSAB_CNT; csab++) { ddrtbl_setval(_cnf_DDR_PI_REGSET, reg_pi_mr11_data_fx_csx[i][csab], 0x66); } } #endif/* _def_LPDDR4_ODT */ } else { ddr_phycaslice = 0; } if (DDR_PHY_ADR_I_NUM > 0) { for (slice = 0; slice < DDR_PHY_ADR_I_NUM; slice++) { adr = DDR_PHY_ADR_I_REGSET_OFS + DDR_PHY_ADR_I_REGSET_SIZE * slice; for (i = 0; i < DDR_PHY_ADR_I_REGSET_NUM; i++) { reg_ddrphy_write_a(adr + i, _cnf_DDR_PHY_ADR_I_REGSET [i]); } } } /* SET ADRCTRL SLICE TABLE */ adr = DDR_PHY_ADR_G_REGSET_OFS; for (i = 0; i < DDR_PHY_ADR_G_REGSET_NUM; i++) { reg_ddrphy_write_a(adr + i, _cnf_DDR_PHY_ADR_G_REGSET[i]); } /* SET PI REGISTERS */ adr = DDR_PI_REGSET_OFS; for (i = 0; i < DDR_PI_REGSET_NUM; i++) { reg_ddrphy_write_a(adr + i, _cnf_DDR_PI_REGSET[i]); } } /* CONFIGURE DDR REGISTERS */ static void ddr_config_sub(void) { uint32_t i; uint32_t ch, slice; uint32_t data_l; uint32_t tmp; uint8_t high_byte[SLICE_CNT]; const uint32_t _par_CALVL_DEVICE_MAP = 1; foreach_vch(ch) { /* BOARD SETTINGS (DQ,DM,VREF_DRIVING) */ for (slice = 0; slice < SLICE_CNT; slice++) { high_byte[slice] = (board_cnf->ch[ch].dqs_swap >> (4 * slice)) % 2; ddr_setval_s(ch, slice, _reg_PHY_DQ_DM_SWIZZLE0, board_cnf->ch[ch].dq_swap[slice]); ddr_setval_s(ch, slice, _reg_PHY_DQ_DM_SWIZZLE1, board_cnf->ch[ch].dm_swap[slice]); if (high_byte[slice]) { /* HIGHER 16 BYTE */ ddr_setval_s(ch, slice, _reg_PHY_CALVL_VREF_DRIVING_SLICE, 0x00); } else { /* LOWER 16 BYTE */ ddr_setval_s(ch, slice, _reg_PHY_CALVL_VREF_DRIVING_SLICE, 0x01); } } /* BOARD SETTINGS (CA,ADDR_SEL) */ data_l = (0x00ffffff & (uint32_t)(board_cnf->ch[ch].ca_swap)) | 0x00888888; /* --- ADR_CALVL_SWIZZLE --- */ if (prr_product == PRR_PRODUCT_M3) { ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE0_0, data_l); ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE1_0, 0x00000000); ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE0_1, data_l); ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE1_1, 0x00000000); ddr_setval(ch, _reg_PHY_ADR_CALVL_DEVICE_MAP, _par_CALVL_DEVICE_MAP); } else { ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE0, data_l); ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE1, 0x00000000); ddr_setval(ch, _reg_PHY_CALVL_DEVICE_MAP, _par_CALVL_DEVICE_MAP); } /* --- ADR_ADDR_SEL --- */ if ((prr_product == PRR_PRODUCT_H3) && (prr_cut > PRR_PRODUCT_11)) { data_l = 0x00FFFFFF & board_cnf->ch[ch].ca_swap; } else { data_l = 0; tmp = board_cnf->ch[ch].ca_swap; for (i = 0; i < 6; i++) { data_l |= ((tmp & 0x0f) << (i * 5)); tmp = tmp >> 4; } } ddr_setval(ch, _reg_PHY_ADR_ADDR_SEL, data_l); if (ddr_phycaslice == 1) { /* ----------- adr slice2 swap ----------- */ tmp = (uint32_t)((board_cnf->ch[ch].ca_swap) >> 40); data_l = (tmp & 0x00ffffff) | 0x00888888; /* --- ADR_CALVL_SWIZZLE --- */ if (prr_product == PRR_PRODUCT_M3) { ddr_setval_s(ch, 2, _reg_PHY_ADR_CALVL_SWIZZLE0_0, data_l); ddr_setval_s(ch, 2, _reg_PHY_ADR_CALVL_SWIZZLE1_0, 0x00000000); ddr_setval_s(ch, 2, _reg_PHY_ADR_CALVL_SWIZZLE0_1, data_l); ddr_setval_s(ch, 2, _reg_PHY_ADR_CALVL_SWIZZLE1_1, 0x00000000); ddr_setval_s(ch, 2, _reg_PHY_ADR_CALVL_DEVICE_MAP, _par_CALVL_DEVICE_MAP); } else { ddr_setval_s(ch, 2, _reg_PHY_ADR_CALVL_SWIZZLE0, data_l); ddr_setval_s(ch, 2, _reg_PHY_ADR_CALVL_SWIZZLE1, 0x00000000); ddr_setval_s(ch, 2, _reg_PHY_CALVL_DEVICE_MAP, _par_CALVL_DEVICE_MAP); } /* --- ADR_ADDR_SEL --- */ data_l = 0; for (i = 0; i < 6; i++) { data_l |= ((tmp & 0x0f) << (i * 5)); tmp = tmp >> 4; } ddr_setval_s(ch, 2, _reg_PHY_ADR_ADDR_SEL, data_l); } /* BOARD SETTINGS (BYTE_ORDER_SEL) */ if (prr_product == PRR_PRODUCT_M3) { /* --- DATA_BYTE_SWAP --- */ data_l = 0; tmp = board_cnf->ch[ch].dqs_swap; for (i = 0; i < 4; i++) { data_l |= ((tmp & 0x03) << (i * 2)); tmp = tmp >> 4; } } else { /* --- DATA_BYTE_SWAP --- */ data_l = board_cnf->ch[ch].dqs_swap; ddr_setval(ch, _reg_PI_DATA_BYTE_SWAP_EN, 0x01); ddr_setval(ch, _reg_PI_DATA_BYTE_SWAP_SLICE0, (data_l) & 0x0f); ddr_setval(ch, _reg_PI_DATA_BYTE_SWAP_SLICE1, (data_l >> 4 * 1) & 0x0f); ddr_setval(ch, _reg_PI_DATA_BYTE_SWAP_SLICE2, (data_l >> 4 * 2) & 0x0f); ddr_setval(ch, _reg_PI_DATA_BYTE_SWAP_SLICE3, (data_l >> 4 * 3) & 0x0f); ddr_setval(ch, _reg_PHY_DATA_BYTE_ORDER_SEL_HIGH, 0x00); } ddr_setval(ch, _reg_PHY_DATA_BYTE_ORDER_SEL, data_l); } } static void get_ca_swizzle(uint32_t ch, uint32_t ddr_csn, uint32_t *p_swz) { uint32_t slice; uint32_t tmp; uint32_t tgt; if (ddr_csn / 2) { tgt = 3; } else { tgt = 1; } for (slice = 0; slice < SLICE_CNT; slice++) { tmp = (board_cnf->ch[ch].dqs_swap >> (4 * slice)) & 0x0f; if (tgt == tmp) break; } tmp = 0x00FFFFFF & board_cnf->ch[ch].ca_swap; if (slice % 2) tmp |= 0x00888888; *p_swz = tmp; } static void ddr_config_sub_h3v1x(void) { uint32_t ch, slice; uint32_t data_l; uint32_t tmp; uint8_t high_byte[SLICE_CNT]; uint32_t ca_swizzle; uint32_t ca; uint32_t csmap; uint32_t o_inv; uint32_t inv; uint32_t bit_soc; uint32_t bit_mem; uint32_t j; const uint8_t o_mr15 = 0x55; const uint8_t o_mr20 = 0x55; const uint16_t o_mr32_mr40 = 0x5a3c; foreach_vch(ch) { /* BOARD SETTINGS (DQ,DM,VREF_DRIVING) */ csmap = 0; for (slice = 0; slice < SLICE_CNT; slice++) { tmp = (board_cnf->ch[ch].dqs_swap >> (4 * slice)) & 0x0f; high_byte[slice] = tmp % 2; if (tmp == 1 && (slice >= 2)) csmap |= 0x05; if (tmp == 3 && (slice >= 2)) csmap |= 0x50; ddr_setval_s(ch, slice, _reg_PHY_DQ_SWIZZLING, board_cnf->ch[ch].dq_swap[slice]); if (high_byte[slice]) { /* HIGHER 16 BYTE */ ddr_setval_s(ch, slice, _reg_PHY_CALVL_VREF_DRIVING_SLICE, 0x00); } else { /* LOWER 16 BYTE */ ddr_setval_s(ch, slice, _reg_PHY_CALVL_VREF_DRIVING_SLICE, 0x01); } } /* BOARD SETTINGS (CA,ADDR_SEL) */ ca = 0x00FFFFFF & board_cnf->ch[ch].ca_swap; ddr_setval(ch, _reg_PHY_ADR_ADDR_SEL, ca); ddr_setval(ch, _reg_PHY_CALVL_CS_MAP, csmap); get_ca_swizzle(ch, 0, &ca_swizzle); ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE0_0, ca_swizzle); ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE1_0, 0x00000000); ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE0_1, 0x00000000); ddr_setval(ch, _reg_PHY_ADR_CALVL_SWIZZLE1_1, 0x00000000); ddr_setval(ch, _reg_PHY_ADR_CALVL_DEVICE_MAP, 0x01); for (slice = 0; slice < SLICE_CNT; slice++) { ddr_setval_s(ch, slice, _reg_PI_RDLVL_PATTERN_NUM, 0x01); ddr_setval_s(ch, slice, _reg_PI_RDLVL_PATTERN_START, 0x08); if (high_byte[slice]) o_inv = o_mr20; else o_inv = o_mr15; tmp = board_cnf->ch[ch].dq_swap[slice]; inv = 0; j = 0; for (bit_soc = 0; bit_soc < 8; bit_soc++) { bit_mem = (tmp >> (4 * bit_soc)) & 0x0f; j |= (1U << bit_mem); if (o_inv & (1U << bit_mem)) inv |= (1U << bit_soc); } data_l = o_mr32_mr40; if (!high_byte[slice]) data_l |= (inv << 24); if (high_byte[slice]) data_l |= (inv << 16); ddr_setval_s(ch, slice, _reg_PHY_LP4_RDLVL_PATT8, data_l); } } } static void ddr_config(void) { int32_t i; uint32_t ch, slice; uint32_t data_l; uint32_t tmp; int8_t _adj; int16_t adj; uint32_t dq; union { uint32_t ui32[4]; uint8_t ui8[16]; } patt; uint16_t patm; /* configure ddrphy registers */ if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { ddr_config_sub_h3v1x(); } else { /* H3 Ver.2.0 or later/M3-N/V3H is same as M3-W */ ddr_config_sub(); } /* WDQ_USER_PATT */ foreach_vch(ch) { for (slice = 0; slice < SLICE_CNT; slice++) { patm = 0; for (i = 0; i < 16; i++) { tmp = board_cnf->ch[ch].wdqlvl_patt[i]; patt.ui8[i] = tmp & 0xff; if (tmp & 0x100) patm |= (1U << i); } ddr_setval_s(ch, slice, _reg_PHY_USER_PATT0, patt.ui32[0]); ddr_setval_s(ch, slice, _reg_PHY_USER_PATT1, patt.ui32[1]); ddr_setval_s(ch, slice, _reg_PHY_USER_PATT2, patt.ui32[2]); ddr_setval_s(ch, slice, _reg_PHY_USER_PATT3, patt.ui32[3]); ddr_setval_s(ch, slice, _reg_PHY_USER_PATT4, patm); } } /* CACS DLY */ data_l = board_cnf->cacs_dly + _f_scale_adj(board_cnf->cacs_dly_adj); reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_FREQ_SEL_MULTICAST_EN), 0x00U); foreach_vch(ch) { for (i = 0; i < _reg_PHY_CLK_CACS_SLAVE_DELAY_X_NUM - 4; i++) { adj = _f_scale_adj(board_cnf->ch[ch].cacs_adj[i]); ddrtbl_setval(_cnf_DDR_PHY_ADR_V_REGSET, _reg_PHY_CLK_CACS_SLAVE_DELAY_X[i], data_l + adj); reg_ddrphy_write(ch, ddr_regdef_adr (_reg_PHY_CLK_CACS_SLAVE_DELAY_X[i]), _cnf_DDR_PHY_ADR_V_REGSET [ddr_regdef_adr (_reg_PHY_CLK_CACS_SLAVE_DELAY_X[i]) - DDR_PHY_ADR_V_REGSET_OFS]); } for (i = (_reg_PHY_CLK_CACS_SLAVE_DELAY_X_NUM - 4); i < _reg_PHY_CLK_CACS_SLAVE_DELAY_X_NUM; i++) { adj = _f_scale_adj(board_cnf->ch[ch].cacs_adj[i]); ddrtbl_setval(_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_CLK_CACS_SLAVE_DELAY_X[i], data_l + adj); reg_ddrphy_write(ch, ddr_regdef_adr (_reg_PHY_CLK_CACS_SLAVE_DELAY_X[i]), _cnf_DDR_PHY_ADR_G_REGSET [ddr_regdef_adr (_reg_PHY_CLK_CACS_SLAVE_DELAY_X[i]) - DDR_PHY_ADR_G_REGSET_OFS]); } if (ddr_phycaslice == 1) { for (i = 0; i < 6; i++) { adj = _f_scale_adj (board_cnf->ch[ch].cacs_adj [i + _reg_PHY_CLK_CACS_SLAVE_DELAY_X_NUM]); ddrtbl_setval(_cnf_DDR_PHY_ADR_V_REGSET, _reg_PHY_CLK_CACS_SLAVE_DELAY_X [i], data_l + adj); reg_ddrphy_write(ch, ddr_regdef_adr (_reg_PHY_CLK_CACS_SLAVE_DELAY_X[i]) + 0x0100, _cnf_DDR_PHY_ADR_V_REGSET [ddr_regdef_adr (_reg_PHY_CLK_CACS_SLAVE_DELAY_X[i]) - DDR_PHY_ADR_V_REGSET_OFS]); } } } reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_FREQ_SEL_MULTICAST_EN), BIT(ddr_regdef_lsb(_reg_PHY_FREQ_SEL_MULTICAST_EN))); /* WDQDM DLY */ data_l = board_cnf->dqdm_dly_w; foreach_vch(ch) { for (slice = 0; slice < SLICE_CNT; slice++) { for (i = 0; i <= 8; i++) { dq = slice * 8 + i; if (i == 8) _adj = board_cnf->ch[ch].dm_adj_w[slice]; else _adj = board_cnf->ch[ch].dq_adj_w[dq]; adj = _f_scale_adj(_adj); ddr_setval_s(ch, slice, _reg_PHY_CLK_WRX_SLAVE_DELAY[i], data_l + adj); } } } /* RDQDM DLY */ data_l = board_cnf->dqdm_dly_r; foreach_vch(ch) { for (slice = 0; slice < SLICE_CNT; slice++) { for (i = 0; i <= 8; i++) { dq = slice * 8 + i; if (i == 8) _adj = board_cnf->ch[ch].dm_adj_r[slice]; else _adj = board_cnf->ch[ch].dq_adj_r[dq]; adj = _f_scale_adj(_adj); ddr_setval_s(ch, slice, _reg_PHY_RDDQS_X_FALL_SLAVE_DELAY [i], data_l + adj); ddr_setval_s(ch, slice, _reg_PHY_RDDQS_X_RISE_SLAVE_DELAY [i], data_l + adj); } } } } /* DBSC register setting functions */ static void dbsc_regset_pre(void) { uint32_t ch, csab; uint32_t data_l; /* PRIMARY SETTINGS */ /* LPDDR4, BL=16, DFI interface */ mmio_write_32(DBSC_DBKIND, 0x0000000a); mmio_write_32(DBSC_DBBL, 0x00000002); mmio_write_32(DBSC_DBPHYCONF0, 0x00000001); /* FREQRATIO=2 */ mmio_write_32(DBSC_DBSYSCONF1, 0x00000002); /* Chanel map (H3 Ver.1.x) */ if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) mmio_write_32(DBSC_DBSCHCNT1, 0x00001010); /* DRAM SIZE REGISTER: * set all ranks as density=0(4Gb) for PHY initialization */ foreach_vch(ch) { for (csab = 0; csab < 4; csab++) { mmio_write_32(DBSC_DBMEMCONF(ch, csab), DBMEMCONF_REGD(0)); } } if (prr_product == PRR_PRODUCT_M3) { data_l = 0xe4e4e4e4; foreach_ech(ch) { if ((ddr_phyvalid & (1U << ch))) data_l = (data_l & (~(0x000000FF << (ch * 8)))) | (((board_cnf->ch[ch].dqs_swap & 0x0003) | ((board_cnf->ch[ch].dqs_swap & 0x0030) >> 2) | ((board_cnf->ch[ch].dqs_swap & 0x0300) >> 4) | ((board_cnf->ch[ch].dqs_swap & 0x3000) >> 6)) << (ch * 8)); } mmio_write_32(DBSC_DBBSWAP, data_l); } } static void dbsc_regset(void) { int32_t i; uint32_t ch; uint32_t data_l; uint32_t data_l2; uint32_t tmp[4]; /* RFC */ if ((prr_product == PRR_PRODUCT_H3) && (prr_cut == PRR_PRODUCT_20) && (max_density == 0)) { js2[js2_trfcab] = _f_scale(ddr_mbps, ddr_mbpsdiv, 1UL * jedec_spec2_trfc_ab[1] * 1000, 0); } else { js2[js2_trfcab] = _f_scale(ddr_mbps, ddr_mbpsdiv, 1UL * jedec_spec2_trfc_ab[max_density] * 1000, 0); } /* DBTR0.CL : RL */ mmio_write_32(DBSC_DBTR(0), RL); /* DBTR1.CWL : WL */ mmio_write_32(DBSC_DBTR(1), WL); /* DBTR2.AL : 0 */ mmio_write_32(DBSC_DBTR(2), 0); /* DBTR3.TRCD: tRCD */ mmio_write_32(DBSC_DBTR(3), js2[js2_trcd]); /* DBTR4.TRPA,TRP: tRPab,tRPpb */ mmio_write_32(DBSC_DBTR(4), (js2[js2_trpab] << 16) | js2[js2_trppb]); /* DBTR5.TRC : use tRCpb */ mmio_write_32(DBSC_DBTR(5), js2[js2_trcpb]); /* DBTR6.TRAS : tRAS */ mmio_write_32(DBSC_DBTR(6), js2[js2_tras]); /* DBTR7.TRRD : tRRD */ mmio_write_32(DBSC_DBTR(7), (js2[js2_trrd] << 16) | js2[js2_trrd]); /* DBTR8.TFAW : tFAW */ mmio_write_32(DBSC_DBTR(8), js2[js2_tfaw]); /* DBTR9.TRDPR : tRTP */ mmio_write_32(DBSC_DBTR(9), js2[js2_trtp]); /* DBTR10.TWR : nwr */ mmio_write_32(DBSC_DBTR(10), js1[js1_ind].nwr); /* DBTR11.TRDWR : RL + tDQSCK + BL/2 + Rounddown(tRPST) - WL + tWPRE */ mmio_write_32(DBSC_DBTR(11), RL + js2[js2_tdqsck] + (16 / 2) + 1 - WL + 2 + 2); /* DBTR12.TWRRD : WL + 1 + BL/2 + tWTR */ data_l = WL + 1 + (16 / 2) + js2[js2_twtr]; mmio_write_32(DBSC_DBTR(12), (data_l << 16) | data_l); /* DBTR13.TRFCAB : tRFCab */ mmio_write_32(DBSC_DBTR(13), (js2[js2_trfcab])); /* DBTR14.TCKEHDLL,tCKEH : tCKEHCMD,tCKEHCMD */ mmio_write_32(DBSC_DBTR(14), (js2[js2_tckehcmd] << 16) | (js2[js2_tckehcmd])); /* DBTR15.TCKESR,TCKEL : tSR,tCKELPD */ mmio_write_32(DBSC_DBTR(15), (js2[js2_tsr] << 16) | (js2[js2_tckelpd])); /* DBTR16 */ /* WDQL : tphy_wrlat + tphy_wrdata */ tmp[0] = ddrtbl_getval(_cnf_DDR_PI_REGSET, _reg_PI_WRLAT_F1); /* DQENLTNCY : tphy_wrlat = WL-2 : PHY_WRITE_PATH_LAT_ADD == 0 * tphy_wrlat = WL-3 : PHY_WRITE_PATH_LAT_ADD != 0 */ tmp[1] = ddrtbl_getval(_cnf_DDR_PI_REGSET, _reg_PI_WRLAT_ADJ_F1); /* DQL : tphy_rdlat + trdata_en */ /* it is not important for dbsc */ tmp[2] = RL + 16; /* DQIENLTNCY : trdata_en */ tmp[3] = ddrtbl_getval(_cnf_DDR_PI_REGSET, _reg_PI_RDLAT_ADJ_F1) - 1; mmio_write_32(DBSC_DBTR(16), (tmp[3] << 24) | (tmp[2] << 16) | (tmp[1] << 8) | tmp[0]); /* DBTR24 */ /* WRCSLAT = WRLAT -5 */ tmp[0] -= 5; /* WRCSGAP = 5 */ tmp[1] = 5; /* RDCSLAT = RDLAT_ADJ +2 */ if (prr_product == PRR_PRODUCT_M3) { tmp[2] = tmp[3]; } else { tmp[2] = tmp[3] + 2; } /* RDCSGAP = 6 */ if (prr_product == PRR_PRODUCT_M3) { tmp[3] = 4; } else { tmp[3] = 6; } mmio_write_32(DBSC_DBTR(24), (tmp[3] << 24) | (tmp[2] << 16) | (tmp[1] << 8) | tmp[0]); /* DBTR17.TMODRD,TMOD,TRDMR: tMRR,tMRD,(0) */ mmio_write_32(DBSC_DBTR(17), (js2[js2_tmrr] << 24) | (js2[js2_tmrd] << 16)); /* DBTR18.RODTL, RODTA, WODTL, WODTA : do not use in LPDDR4 */ mmio_write_32(DBSC_DBTR(18), 0); /* DBTR19.TZQCL, TZQCS : do not use in LPDDR4 */ mmio_write_32(DBSC_DBTR(19), 0); /* DBTR20.TXSDLL, TXS : tRFCab+tCKEHCMD */ data_l = js2[js2_trfcab] + js2[js2_tckehcmd]; mmio_write_32(DBSC_DBTR(20), (data_l << 16) | data_l); /* DBTR21.TCCD */ /* DBTR23.TCCD */ /* H3 Ver.1.0 cannot use TBTR23 feature */ if (ddr_tccd == 8 && !((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_10)) ) { data_l = 8; mmio_write_32(DBSC_DBTR(21), (data_l << 16) | data_l); mmio_write_32(DBSC_DBTR(23), 0x00000002); } else if (ddr_tccd <= 11) { data_l = 11; mmio_write_32(DBSC_DBTR(21), (data_l << 16) | data_l); mmio_write_32(DBSC_DBTR(23), 0x00000000); } else { data_l = ddr_tccd; mmio_write_32(DBSC_DBTR(21), (data_l << 16) | data_l); mmio_write_32(DBSC_DBTR(23), 0x00000000); } /* DBTR22.ZQLAT : */ data_l = js2[js2_tzqcalns] * 100; /* 1000 * 1000 ps */ data_l = (data_l << 16) | (js2[js2_tzqlat] + 24 + 20); mmio_write_32(DBSC_DBTR(22), data_l); /* DBTR25 : do not use in LPDDR4 */ mmio_write_32(DBSC_DBTR(25), 0); /* DBRNK : */ /* * DBSC_DBRNK2 rkrr * DBSC_DBRNK3 rkrw * DBSC_DBRNK4 rkwr * DBSC_DBRNK5 rkww */ #define _par_DBRNK_VAL (0x7007) for (i = 0; i < 4; i++) { data_l = (_par_DBRNK_VAL >> (i * 4)) & 0x0f; if ((prr_product == PRR_PRODUCT_H3) && (prr_cut > PRR_PRODUCT_11) && (i == 0)) { data_l += 1; } data_l2 = 0; foreach_vch(ch) { data_l2 = data_l2 | (data_l << (4 * ch)); } mmio_write_32(DBSC_DBRNK(2 + i), data_l2); } mmio_write_32(DBSC_DBADJ0, 0x00000000); /* timing registers for Scheduler */ /* SCFCTST0 */ /* SCFCTST0 ACT-ACT */ tmp[3] = 1UL * js2[js2_trcpb] * 800 * ddr_mbpsdiv / ddr_mbps; /* SCFCTST0 RDA-ACT */ tmp[2] = 1UL * ((16 / 2) + js2[js2_trtp] - 8 + js2[js2_trppb]) * 800 * ddr_mbpsdiv / ddr_mbps; /* SCFCTST0 WRA-ACT */ tmp[1] = 1UL * (WL + 1 + (16 / 2) + js1[js1_ind].nwr) * 800 * ddr_mbpsdiv / ddr_mbps; /* SCFCTST0 PRE-ACT */ tmp[0] = 1UL * js2[js2_trppb]; mmio_write_32(DBSC_SCFCTST0, (tmp[3] << 24) | (tmp[2] << 16) | (tmp[1] << 8) | tmp[0]); /* SCFCTST1 */ /* SCFCTST1 RD-WR */ tmp[3] = 1UL * (mmio_read_32(DBSC_DBTR(11)) & 0xff) * 800 * ddr_mbpsdiv / ddr_mbps; /* SCFCTST1 WR-RD */ tmp[2] = 1UL * (mmio_read_32(DBSC_DBTR(12)) & 0xff) * 800 * ddr_mbpsdiv / ddr_mbps; /* SCFCTST1 ACT-RD/WR */ tmp[1] = 1UL * js2[js2_trcd] * 800 * ddr_mbpsdiv / ddr_mbps; /* SCFCTST1 ASYNCOFS */ tmp[0] = 12; mmio_write_32(DBSC_SCFCTST1, (tmp[3] << 24) | (tmp[2] << 16) | (tmp[1] << 8) | tmp[0]); /* DBSCHRW1 */ /* DBSCHRW1 SCTRFCAB */ tmp[0] = 1UL * js2[js2_trfcab] * 800 * ddr_mbpsdiv / ddr_mbps; data_l = (((mmio_read_32(DBSC_DBTR(16)) & 0x00FF0000) >> 16) + (mmio_read_32(DBSC_DBTR(22)) & 0x0000FFFF) + (0x28 * 2)) * 400 * 2 * ddr_mbpsdiv / ddr_mbps + 7; if (tmp[0] < data_l) tmp[0] = data_l; if ((prr_product == PRR_PRODUCT_M3) && (prr_cut < PRR_PRODUCT_30)) { mmio_write_32(DBSC_DBSCHRW1, tmp[0] + ((mmio_read_32(DBSC_DBTR(22)) & 0x0000FFFF) * 400 * 2 * ddr_mbpsdiv + (ddr_mbps - 1)) / ddr_mbps - 3); } else { mmio_write_32(DBSC_DBSCHRW1, tmp[0] + ((mmio_read_32(DBSC_DBTR(22)) & 0x0000FFFF) * 400 * 2 * ddr_mbpsdiv + (ddr_mbps - 1)) / ddr_mbps); } /* QOS and CAM */ #ifdef ddr_qos_init_setting /* only for non qos_init */ /*wbkwait(0004), wbkmdhi(4,2),wbkmdlo(1,8) */ mmio_write_32(DBSC_DBCAM0CNF1, 0x00043218); /*0(fillunit),8(dirtymax),4(dirtymin) */ mmio_write_32(DBSC_DBCAM0CNF2, 0x000000F4); /*stop_tolerance */ mmio_write_32(DBSC_DBSCHRW0, 0x22421111); /*rd-wr/wr-rd toggle priority */ mmio_write_32(DBSC_SCFCTST2, 0x012F1123); mmio_write_32(DBSC_DBSCHSZ0, 0x00000001); mmio_write_32(DBSC_DBSCHCNT0, 0x000F0037); /* QoS Settings */ mmio_write_32(DBSC_DBSCHQOS00, 0x00000F00U); mmio_write_32(DBSC_DBSCHQOS01, 0x00000B00U); mmio_write_32(DBSC_DBSCHQOS02, 0x00000000U); mmio_write_32(DBSC_DBSCHQOS03, 0x00000000U); mmio_write_32(DBSC_DBSCHQOS40, 0x00000300U); mmio_write_32(DBSC_DBSCHQOS41, 0x000002F0U); mmio_write_32(DBSC_DBSCHQOS42, 0x00000200U); mmio_write_32(DBSC_DBSCHQOS43, 0x00000100U); mmio_write_32(DBSC_DBSCHQOS90, 0x00000100U); mmio_write_32(DBSC_DBSCHQOS91, 0x000000F0U); mmio_write_32(DBSC_DBSCHQOS92, 0x000000A0U); mmio_write_32(DBSC_DBSCHQOS93, 0x00000040U); mmio_write_32(DBSC_DBSCHQOS120, 0x00000040U); mmio_write_32(DBSC_DBSCHQOS121, 0x00000030U); mmio_write_32(DBSC_DBSCHQOS122, 0x00000020U); mmio_write_32(DBSC_DBSCHQOS123, 0x00000010U); mmio_write_32(DBSC_DBSCHQOS130, 0x00000100U); mmio_write_32(DBSC_DBSCHQOS131, 0x000000F0U); mmio_write_32(DBSC_DBSCHQOS132, 0x000000A0U); mmio_write_32(DBSC_DBSCHQOS133, 0x00000040U); mmio_write_32(DBSC_DBSCHQOS140, 0x000000C0U); mmio_write_32(DBSC_DBSCHQOS141, 0x000000B0U); mmio_write_32(DBSC_DBSCHQOS142, 0x00000080U); mmio_write_32(DBSC_DBSCHQOS143, 0x00000040U); mmio_write_32(DBSC_DBSCHQOS150, 0x00000040U); mmio_write_32(DBSC_DBSCHQOS151, 0x00000030U); mmio_write_32(DBSC_DBSCHQOS152, 0x00000020U); mmio_write_32(DBSC_DBSCHQOS153, 0x00000010U); mmio_write_32(QOSCTRL_RAEN, 0x00000001U); #endif /* ddr_qos_init_setting */ /* H3 Ver.1.1 need to set monitor function */ if ((prr_product == PRR_PRODUCT_H3) && (prr_cut == PRR_PRODUCT_11)) { mmio_write_32(DBSC_DBMONCONF4, 0x00700000); } if (prr_product == PRR_PRODUCT_H3) { if (prr_cut == PRR_PRODUCT_10) { /* resrdis, simple mode, sc off */ mmio_write_32(DBSC_DBBCAMDIS, 0x00000007); } else if (prr_cut == PRR_PRODUCT_11) { /* resrdis, simple mode */ mmio_write_32(DBSC_DBBCAMDIS, 0x00000005); } else if (prr_cut < PRR_PRODUCT_30) { /* H3 Ver.2.0 */ /* resrdis */ mmio_write_32(DBSC_DBBCAMDIS, 0x00000001); } else { /* H3 Ver.3.0(include H3N) */ /* exprespque */ mmio_write_32(DBSC_DBBCAMDIS, 0x00000010); } } else { /* M3-W/M3-N/V3H */ /* resrdis */ mmio_write_32(DBSC_DBBCAMDIS, 0x00000001); } } static void dbsc_regset_post(void) { uint32_t ch, cs; uint32_t data_l; uint32_t slice, rdlat_max, rdlat_min; rdlat_max = 0; rdlat_min = 0xffff; foreach_vch(ch) { for (cs = 0; cs < CS_CNT; cs++) { if ((ch_have_this_cs[cs] & (1U << ch)) != 0) { for (slice = 0; slice < SLICE_CNT; slice++) { ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_INDEX, cs); data_l = ddr_getval_s(ch, slice, _reg_PHY_RDDQS_LATENCY_ADJUST); if (data_l > rdlat_max) rdlat_max = data_l; if (data_l < rdlat_min) rdlat_min = data_l; } } } } if ((prr_product == PRR_PRODUCT_H3) && (prr_cut > PRR_PRODUCT_11)) { mmio_write_32(DBSC_DBTR(24), ((rdlat_max * 2 - rdlat_min + 4) << 24) + ((rdlat_min + 2) << 16) + mmio_read_32(DBSC_DBTR(24))); } else { mmio_write_32(DBSC_DBTR(24), ((rdlat_max + 2) << 24) + ((rdlat_max + 2) << 16) + mmio_read_32(DBSC_DBTR(24))); } /* set ddr density information */ foreach_ech(ch) { for (cs = 0; cs < CS_CNT; cs++) { if (ddr_density[ch][cs] == 0xff) { mmio_write_32(DBSC_DBMEMCONF(ch, cs), 0x00); } else { mmio_write_32(DBSC_DBMEMCONF(ch, cs), DBMEMCONF_REGD(ddr_density[ch] [cs])); } } mmio_write_32(DBSC_DBMEMCONF(ch, 2), 0x00000000); mmio_write_32(DBSC_DBMEMCONF(ch, 3), 0x00000000); } mmio_write_32(DBSC_DBBUS0CNF1, 0x00000010); /*set DBI */ if (board_cnf->dbi_en) mmio_write_32(DBSC_DBDBICNT, 0x00000003); /* H3 Ver.2.0 or later/M3-N/V3H DBI wa */ if ((((prr_product == PRR_PRODUCT_H3) && (prr_cut > PRR_PRODUCT_11)) || (prr_product == PRR_PRODUCT_M3N) || (prr_product == PRR_PRODUCT_V3H)) && board_cnf->dbi_en) reg_ddrphy_write_a(0x00001010, 0x01000000); /*set REFCYCLE */ data_l = (get_refperiod()) * ddr_mbps / 2000 / ddr_mbpsdiv; mmio_write_32(DBSC_DBRFCNF1, 0x00080000 | (data_l & 0x0000ffff)); mmio_write_32(DBSC_DBRFCNF2, 0x00010000 | DBSC_REFINTS); #ifdef DDR_BACKUPMODE if (ddr_backup == DRAM_BOOT_STATUS_WARM) { #ifdef DDR_BACKUPMODE_HALF /* for Half channel(ch0,1 only) */ DEBUG(" DEBUG_MESS : DDR_BACKUPMODE_HALF ", 1); send_dbcmd(0x08040001); wait_dbcmd(); send_dbcmd(0x0A040001); wait_dbcmd(); send_dbcmd(0x04040010); wait_dbcmd(); if (prr_product == PRR_PRODUCT_H3) { send_dbcmd(0x08140001); wait_dbcmd(); send_dbcmd(0x0A140001); wait_dbcmd(); send_dbcmd(0x04140010); wait_dbcmd(); } #else /* DDR_BACKUPMODE_HALF //for All channels */ send_dbcmd(0x08840001); wait_dbcmd(); send_dbcmd(0x0A840001); wait_dbcmd(); send_dbcmd(0x04840010); wait_dbcmd(); #endif /* DDR_BACKUPMODE_HALF */ } #endif /* DDR_BACKUPMODE */ #if RCAR_REWT_TRAINING != 0 /* Periodic-WriteDQ Training seeting */ if (((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) || ((prr_product == PRR_PRODUCT_M3) && (prr_cut == PRR_PRODUCT_10))) { /* non : H3 Ver.1.x/M3-W Ver.1.0 not support */ } else { /* * H3 Ver.2.0 or later/M3-W Ver.1.1 or * later/M3-N/V3H -> Periodic-WriteDQ Training seeting */ /* Periodic WriteDQ Training seeting */ mmio_write_32(DBSC_DBDFIPMSTRCNF, 0x00000000); ddr_setval_ach_as(_reg_PHY_WDQLVL_PATT, 0x04); ddr_setval_ach_as(_reg_PHY_WDQLVL_QTR_DLY_STEP, 0x0F); ddr_setval_ach_as(_reg_PHY_WDQLVL_DLY_STEP, 0x50); ddr_setval_ach_as(_reg_PHY_WDQLVL_DQDM_SLV_DLY_START, 0x0300); ddr_setval_ach(_reg_PI_WDQLVL_CS_MAP, ddrtbl_getval(_cnf_DDR_PI_REGSET, _reg_PI_WDQLVL_CS_MAP)); ddr_setval_ach(_reg_PI_LONG_COUNT_MASK, 0x1f); ddr_setval_ach(_reg_PI_WDQLVL_VREF_EN, 0x00); ddr_setval_ach(_reg_PI_WDQLVL_INTERVAL, 0x0100); ddr_setval_ach(_reg_PI_WDQLVL_ROTATE, 0x01); ddr_setval_ach(_reg_PI_TREF_F0, 0x0000); ddr_setval_ach(_reg_PI_TREF_F1, 0x0000); ddr_setval_ach(_reg_PI_TREF_F2, 0x0000); if (prr_product == PRR_PRODUCT_M3) { ddr_setval_ach(_reg_PI_WDQLVL_EN, 0x02); } else { ddr_setval_ach(_reg_PI_WDQLVL_EN_F1, 0x02); } ddr_setval_ach(_reg_PI_WDQLVL_PERIODIC, 0x01); /* DFI_PHYMSTR_ACK , WTmode setting */ /* DFI_PHYMSTR_ACK: WTmode =b'01 */ mmio_write_32(DBSC_DBDFIPMSTRCNF, 0x00000011); } #endif /* RCAR_REWT_TRAINING */ /* periodic dram zqcal and phy ctrl update enable */ mmio_write_32(DBSC_DBCALCNF, 0x01000010); if (((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) || ((prr_product == PRR_PRODUCT_M3) && (prr_cut < PRR_PRODUCT_30))) { /* non : H3 Ver.1.x/M3-W Ver.1.x not support */ } else { #if RCAR_DRAM_SPLIT == 2 if ((prr_product == PRR_PRODUCT_H3) && (board_cnf->phyvalid == 0x05)) mmio_write_32(DBSC_DBDFICUPDCNF, 0x2a240001); else mmio_write_32(DBSC_DBDFICUPDCNF, 0x28240001); #else /* RCAR_DRAM_SPLIT == 2 */ mmio_write_32(DBSC_DBDFICUPDCNF, 0x28240001); #endif /* RCAR_DRAM_SPLIT == 2 */ } mmio_write_32(DBSC_DBRFEN, 0x00000001); /* dram access enable */ mmio_write_32(DBSC_DBACEN, 0x00000001); MSG_LF(__func__ "(done)"); } /* DFI_INIT_START */ static uint32_t dfi_init_start(void) { uint32_t ch; uint32_t phytrainingok; uint32_t retry; uint32_t data_l; const uint32_t RETRY_MAX = 0x10000; if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { /* PLL3 Disable */ /* protect register interface */ ddrphy_regif_idle(); pll3_control(0); /* init start */ /* dbdficnt0: * dfi_dram_clk_disable=1 * dfi_frequency = 0 * freq_ratio = 01 (2:1) * init_start =0 */ foreach_vch(ch) mmio_write_32(DBSC_DBDFICNT(ch), 0x00000F10); dsb_sev(); /* dbdficnt0: * dfi_dram_clk_disable=1 * dfi_frequency = 0 * freq_ratio = 01 (2:1) * init_start =1 */ foreach_vch(ch) mmio_write_32(DBSC_DBDFICNT(ch), 0x00000F11); dsb_sev(); } else { ddr_setval_ach_as(_reg_PHY_DLL_RST_EN, 0x02); dsb_sev(); ddrphy_regif_idle(); } /* dll_rst negate */ foreach_vch(ch) mmio_write_32(DBSC_DBPDCNT3(ch), 0x0000CF01); dsb_sev(); /* wait init_complete */ phytrainingok = 0; retry = 0; while (retry++ < RETRY_MAX) { foreach_vch(ch) { data_l = mmio_read_32(DBSC_DBDFISTAT(ch)); if (data_l & 0x00000001) phytrainingok |= (1U << ch); } dsb_sev(); if (phytrainingok == ddr_phyvalid) break; if (retry % 256 == 0) ddr_setval_ach_as(_reg_SC_PHY_RX_CAL_START, 0x01); } /* all ch ok? */ if ((phytrainingok & ddr_phyvalid) != ddr_phyvalid) return 0xff; /* dbdficnt0: * dfi_dram_clk_disable=0 * dfi_frequency = 0 * freq_ratio = 01 (2:1) * init_start =0 */ foreach_vch(ch) mmio_write_32(DBSC_DBDFICNT(ch), 0x00000010); dsb_sev(); return 0; } /* drivablity setting : CMOS MODE ON/OFF */ static void change_lpddr4_en(uint32_t mode) { uint32_t ch; uint32_t i; uint32_t data_l; const uint32_t _reg_PHY_PAD_DRIVE_X[3] = { _reg_PHY_PAD_ADDR_DRIVE, _reg_PHY_PAD_CLK_DRIVE, _reg_PHY_PAD_CS_DRIVE }; foreach_vch(ch) { for (i = 0; i < 3; i++) { data_l = ddr_getval(ch, _reg_PHY_PAD_DRIVE_X[i]); if (mode) { data_l |= (1U << 14); } else { data_l &= ~(1U << 14); } ddr_setval(ch, _reg_PHY_PAD_DRIVE_X[i], data_l); } } } /* drivablity setting */ static uint32_t set_term_code(void) { int32_t i; uint32_t ch, index; uint32_t data_l; uint32_t chip_id[2]; uint32_t term_code; uint32_t override; uint32_t pvtr; uint32_t pvtp; uint32_t pvtn; term_code = ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_PAD_DATA_TERM); override = 0; for (i = 0; i < 2; i++) chip_id[i] = mmio_read_32(LIFEC_CHIPID(i)); index = 0; while (1) { if (termcode_by_sample[index][0] == 0xffffffff) { break; } if ((termcode_by_sample[index][0] == chip_id[0]) && (termcode_by_sample[index][1] == chip_id[1])) { term_code = termcode_by_sample[index][2]; override = 1; break; } index++; } if (override) { for (index = 0; index < _reg_PHY_PAD_TERM_X_NUM; index++) { data_l = ddrtbl_getval(_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_PAD_TERM_X[index]); data_l = (data_l & 0xfffe0000) | term_code; ddr_setval_ach(_reg_PHY_PAD_TERM_X[index], data_l); } } else if ((prr_product == PRR_PRODUCT_M3) && (prr_cut == PRR_PRODUCT_10)) { /* non */ } else { ddr_setval_ach(_reg_PHY_PAD_TERM_X[0], (ddrtbl_getval (_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_PAD_TERM_X[0]) & 0xFFFE0000)); ddr_setval_ach(_reg_PHY_CAL_CLEAR_0, 0x01); ddr_setval_ach(_reg_PHY_CAL_START_0, 0x01); foreach_vch(ch) { do { data_l = ddr_getval(ch, _reg_PHY_CAL_RESULT2_OBS_0); } while (!(data_l & 0x00800000)); } if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { foreach_vch(ch) { data_l = ddr_getval(ch, _reg_PHY_PAD_TERM_X[0]); pvtr = (data_l >> 12) & 0x1f; pvtr += 8; if (pvtr > 0x1f) pvtr = 0x1f; data_l = ddr_getval(ch, _reg_PHY_CAL_RESULT2_OBS_0); pvtn = (data_l >> 6) & 0x03f; pvtp = (data_l >> 0) & 0x03f; for (index = 0; index < _reg_PHY_PAD_TERM_X_NUM; index++) { data_l = ddrtbl_getval (_cnf_DDR_PHY_ADR_G_REGSET, _reg_PHY_PAD_TERM_X[index]); data_l = (data_l & 0xfffe0000) | (pvtr << 12) | (pvtn << 6) | (pvtp); ddr_setval(ch, _reg_PHY_PAD_TERM_X[index], data_l); } } } else { /* M3-W Ver.1.1 or later/H3 Ver.2.0 or later/M3-N/V3H */ foreach_vch(ch) { for (index = 0; index < _reg_PHY_PAD_TERM_X_NUM; index++) { data_l = ddr_getval(ch, _reg_PHY_PAD_TERM_X [index]); ddr_setval(ch, _reg_PHY_PAD_TERM_X[index], (data_l & 0xFFFE0FFF) | 0x00015000); } } } } if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { /* non */ } else { ddr_padcal_tcompensate_getinit(override); } return 0; } /* DDR mode register setting */ static void ddr_register_set(void) { int32_t fspwp; uint32_t tmp; for (fspwp = 1; fspwp >= 0; fspwp--) { /*MR13, fspwp */ send_dbcmd(0x0e840d08 | ((2 - fspwp) << 6)); tmp = ddrtbl_getval(_cnf_DDR_PI_REGSET, reg_pi_mr1_data_fx_csx[fspwp][0]); send_dbcmd(0x0e840100 | tmp); tmp = ddrtbl_getval(_cnf_DDR_PI_REGSET, reg_pi_mr2_data_fx_csx[fspwp][0]); send_dbcmd(0x0e840200 | tmp); tmp = ddrtbl_getval(_cnf_DDR_PI_REGSET, reg_pi_mr3_data_fx_csx[fspwp][0]); send_dbcmd(0x0e840300 | tmp); tmp = ddrtbl_getval(_cnf_DDR_PI_REGSET, reg_pi_mr11_data_fx_csx[fspwp][0]); send_dbcmd(0x0e840b00 | tmp); tmp = ddrtbl_getval(_cnf_DDR_PI_REGSET, reg_pi_mr12_data_fx_csx[fspwp][0]); send_dbcmd(0x0e840c00 | tmp); tmp = ddrtbl_getval(_cnf_DDR_PI_REGSET, reg_pi_mr14_data_fx_csx[fspwp][0]); send_dbcmd(0x0e840e00 | tmp); /* MR22 */ send_dbcmd(0x0e841616); /* ZQCAL start */ send_dbcmd(0x0d84004F); /* ZQLAT */ send_dbcmd(0x0d840051); } /* MR13, fspwp */ send_dbcmd(0x0e840d08); } /* Training handshake functions */ static inline uint32_t wait_freqchgreq(uint32_t assert) { uint32_t data_l; uint32_t count; uint32_t ch; count = 100000; /* H3 Ver.1.x cannot see frqchg_req */ if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { return 0; } if (assert) { do { data_l = 1; foreach_vch(ch) { data_l &= mmio_read_32(DBSC_DBPDSTAT(ch)); } count = count - 1; } while (((data_l & 0x01) != 0x01) & (count != 0)); } else { do { data_l = 0; foreach_vch(ch) { data_l |= mmio_read_32(DBSC_DBPDSTAT(ch)); } count = count - 1; } while (((data_l & 0x01) != 0x00) & (count != 0)); } return (count == 0); } static inline void set_freqchgack(uint32_t assert) { uint32_t ch; uint32_t data_l; if (assert) data_l = 0x0CF20000; else data_l = 0x00000000; foreach_vch(ch) mmio_write_32(DBSC_DBPDCNT2(ch), data_l); } static inline void set_dfifrequency(uint32_t freq) { uint32_t ch; if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { foreach_vch(ch) mmio_clrsetbits_32(DBSC_DBPDCNT1(ch), 0x1fU, freq); } else { foreach_vch(ch) { mmio_clrsetbits_32(DBSC_DBDFICNT(ch), 0x1fU << 24, (freq << 24)); } } dsb_sev(); } static uint32_t pll3_freq(uint32_t on) { uint32_t timeout; timeout = wait_freqchgreq(1); if (timeout) { return 1; } pll3_control(on); set_dfifrequency(on); set_freqchgack(1); timeout = wait_freqchgreq(0); set_freqchgack(0); if (timeout) { FATAL_MSG("BL2: Time out[2]\n"); return 1; } return 0; } /* update dly */ static void update_dly(void) { ddr_setval_ach(_reg_SC_PHY_MANUAL_UPDATE, 0x01); ddr_setval_ach(_reg_PHY_ADRCTL_MANUAL_UPDATE, 0x01); } /* training by pi */ static uint32_t pi_training_go(void) { uint32_t flag; uint32_t data_l; uint32_t retry; const uint32_t RETRY_MAX = 4096 * 16; uint32_t ch; uint32_t mst_ch; uint32_t cur_frq; uint32_t complete; uint32_t frqchg_req; /* pi_start */ ddr_setval_ach(_reg_PI_START, 0x01); foreach_vch(ch) ddr_getval(ch, _reg_PI_INT_STATUS); /* set dfi_phymstr_ack = 1 */ mmio_write_32(DBSC_DBDFIPMSTRCNF, 0x00000001); dsb_sev(); /* wait pi_int_status[0] */ mst_ch = 0; flag = 0; complete = 0; cur_frq = 0; retry = RETRY_MAX; do { frqchg_req = mmio_read_32(DBSC_DBPDSTAT(mst_ch)) & 0x01; /* H3 Ver.1.x cannot see frqchg_req */ if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { if ((retry % 4096) == 1) { frqchg_req = 1; } else { frqchg_req = 0; } } if (frqchg_req) { if (cur_frq) { /* Low frequency */ flag = pll3_freq(0); cur_frq = 0; } else { /* High frequency */ flag = pll3_freq(1); cur_frq = 1; } if (flag) break; } else { if (cur_frq) { foreach_vch(ch) { if (complete & (1U << ch)) continue; data_l = ddr_getval(ch, _reg_PI_INT_STATUS); if (data_l & 0x01) { complete |= (1U << ch); } } if (complete == ddr_phyvalid) break; } } } while (--retry); foreach_vch(ch) { /* dummy read */ data_l = ddr_getval_s(ch, 0, _reg_PHY_CAL_RESULT2_OBS_0); data_l = ddr_getval(ch, _reg_PI_INT_STATUS); ddr_setval(ch, _reg_PI_INT_ACK, data_l); } if (ddrphy_regif_chk()) { return 0xfd; } return complete; } /* Initialize DDR */ static uint32_t init_ddr(void) { int32_t i; uint32_t data_l; uint32_t phytrainingok; uint32_t ch, slice; uint32_t err; int16_t adj; MSG_LF(__func__ ":0\n"); #ifdef DDR_BACKUPMODE rcar_dram_get_boot_status(&ddr_backup); #endif /* unlock phy */ /* Unlock DDRPHY register(AGAIN) */ foreach_vch(ch) mmio_write_32(DBSC_DBPDLK(ch), 0x0000A55A); dsb_sev(); if ((((prr_product == PRR_PRODUCT_H3) && (prr_cut > PRR_PRODUCT_11)) || (prr_product == PRR_PRODUCT_M3N) || (prr_product == PRR_PRODUCT_V3H)) && board_cnf->dbi_en) reg_ddrphy_write_a(0x00001010, 0x01000001); else reg_ddrphy_write_a(0x00001010, 0x00000001); /* DBSC register pre-setting */ dbsc_regset_pre(); /* load ddrphy registers */ ddrtbl_load(); /* configure ddrphy registers */ ddr_config(); /* dfi_reset assert */ foreach_vch(ch) mmio_write_32(DBSC_DBPDCNT0(ch), 0x01); dsb_sev(); /* dbsc register set */ dbsc_regset(); MSG_LF(__func__ ":1\n"); /* dfi_reset negate */ foreach_vch(ch) mmio_write_32(DBSC_DBPDCNT0(ch), 0x00); dsb_sev(); /* dfi_init_start (start ddrphy) */ err = dfi_init_start(); if (err) { return INITDRAM_ERR_I; } MSG_LF(__func__ ":2\n"); /* ddr backupmode end */ #ifdef DDR_BACKUPMODE if (ddr_backup) { NOTICE("BL2: [WARM_BOOT]\n"); } else { NOTICE("BL2: [COLD_BOOT]\n"); } err = rcar_dram_update_boot_status(ddr_backup); if (err) { NOTICE("BL2: [BOOT_STATUS_UPDATE_ERROR]\n"); return INITDRAM_ERR_I; } #endif MSG_LF(__func__ ":3\n"); /* override term code after dfi_init_complete */ err = set_term_code(); if (err) { return INITDRAM_ERR_I; } MSG_LF(__func__ ":4\n"); /* rx offset calibration */ if ((prr_cut > PRR_PRODUCT_11) || (prr_product == PRR_PRODUCT_M3N) || (prr_product == PRR_PRODUCT_V3H)) { err = rx_offset_cal_hw(); } else { err = rx_offset_cal(); } if (err) return INITDRAM_ERR_O; MSG_LF(__func__ ":5\n"); /* PDX */ send_dbcmd(0x08840001); /* check register i/f is alive */ err = ddrphy_regif_chk(); if (err) { return INITDRAM_ERR_O; } MSG_LF(__func__ ":6\n"); /* phy initialize end */ /* setup DDR mode registers */ /* CMOS MODE */ change_lpddr4_en(0); /* MRS */ ddr_register_set(); /* Thermal sensor setting */ /* THCTR Bit6: PONM=0 , Bit0: THSST=1 */ data_l = (mmio_read_32(THS1_THCTR) & 0xFFFFFFBF) | 0x00000001; mmio_write_32(THS1_THCTR, data_l); /* LPDDR4 MODE */ change_lpddr4_en(1); MSG_LF(__func__ ":7\n"); /* mask CS_MAP if RANKx is not found */ foreach_vch(ch) { data_l = ddr_getval(ch, _reg_PI_CS_MAP); if (!(ch_have_this_cs[1] & (1U << ch))) data_l = data_l & 0x05; ddr_setval(ch, _reg_PI_CS_MAP, data_l); } /* exec pi_training */ reg_ddrphy_write_a(ddr_regdef_adr(_reg_PHY_FREQ_SEL_MULTICAST_EN), BIT(ddr_regdef_lsb(_reg_PHY_FREQ_SEL_MULTICAST_EN))); ddr_setval_ach_as(_reg_PHY_PER_CS_TRAINING_MULTICAST_EN, 0x00); if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { ddr_setval_ach_as(_reg_PHY_PER_CS_TRAINING_EN, 0x01); } else { foreach_vch(ch) { for (slice = 0; slice < SLICE_CNT; slice++) { ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_EN, ((ch_have_this_cs[1]) >> ch) & 0x01); } } } phytrainingok = pi_training_go(); if (ddr_phyvalid != (phytrainingok & ddr_phyvalid)) { return INITDRAM_ERR_T | phytrainingok; } MSG_LF(__func__ ":8\n"); /* CACS DLY ADJUST */ data_l = board_cnf->cacs_dly + _f_scale_adj(board_cnf->cacs_dly_adj); foreach_vch(ch) { for (i = 0; i < _reg_PHY_CLK_CACS_SLAVE_DELAY_X_NUM; i++) { adj = _f_scale_adj(board_cnf->ch[ch].cacs_adj[i]); ddr_setval(ch, _reg_PHY_CLK_CACS_SLAVE_DELAY_X[i], data_l + adj); } if (ddr_phycaslice == 1) { for (i = 0; i < 6; i++) { adj = _f_scale_adj(board_cnf->ch[ch].cacs_adj [i + _reg_PHY_CLK_CACS_SLAVE_DELAY_X_NUM]); ddr_setval_s(ch, 2, _reg_PHY_CLK_CACS_SLAVE_DELAY_X [i], data_l + adj ); } } } update_dly(); MSG_LF(__func__ ":9\n"); /* H3 fix rd latency to avoid bug in elasitic buffer */ if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) adjust_rddqs_latency(); /* Adjust Write path latency */ if (ddrtbl_getval (_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_WRITE_PATH_LAT_ADD)) adjust_wpath_latency(); /* RDQLVL Training */ if (!ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_IE_MODE)) ddr_setval_ach_as(_reg_PHY_IE_MODE, 0x01); err = rdqdm_man(); if (!ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_IE_MODE)) ddr_setval_ach_as(_reg_PHY_IE_MODE, 0x00); if (err) { return INITDRAM_ERR_T; } update_dly(); MSG_LF(__func__ ":10\n"); /* WDQLVL Training */ err = wdqdm_man(); if (err) { return INITDRAM_ERR_T; } update_dly(); MSG_LF(__func__ ":11\n"); /* training complete, setup DBSC */ if (((prr_product == PRR_PRODUCT_H3) && (prr_cut > PRR_PRODUCT_11)) || (prr_product == PRR_PRODUCT_M3N) || (prr_product == PRR_PRODUCT_V3H)) { ddr_setval_ach_as(_reg_PHY_DFI40_POLARITY, 0x00); ddr_setval_ach(_reg_PI_DFI40_POLARITY, 0x00); } dbsc_regset_post(); MSG_LF(__func__ ":12\n"); return phytrainingok; } /* SW LEVELING COMMON */ static uint32_t swlvl1(uint32_t ddr_csn, uint32_t reg_cs, uint32_t reg_kick) { uint32_t ch; uint32_t data_l; uint32_t retry; uint32_t waiting; uint32_t err; const uint32_t RETRY_MAX = 0x1000; err = 0; /* set EXIT -> OP_DONE is cleared */ ddr_setval_ach(_reg_PI_SWLVL_EXIT, 0x01); /* kick */ foreach_vch(ch) { if (ch_have_this_cs[ddr_csn % 2] & (1U << ch)) { ddr_setval(ch, reg_cs, ddr_csn); ddr_setval(ch, reg_kick, 0x01); } } foreach_vch(ch) { /*PREPARE ADDR REGISTER (for SWLVL_OP_DONE) */ ddr_getval(ch, _reg_PI_SWLVL_OP_DONE); } waiting = ch_have_this_cs[ddr_csn % 2]; dsb_sev(); retry = RETRY_MAX; do { foreach_vch(ch) { if (!(waiting & (1U << ch))) continue; data_l = ddr_getval(ch, _reg_PI_SWLVL_OP_DONE); if (data_l & 0x01) waiting &= ~(1U << ch); } retry--; } while (waiting && (retry > 0)); if (retry == 0) { err = 1; } dsb_sev(); /* set EXIT -> OP_DONE is cleared */ ddr_setval_ach(_reg_PI_SWLVL_EXIT, 0x01); dsb_sev(); return err; } /* WDQ TRAINING */ #ifndef DDR_FAST_INIT static void wdqdm_clr1(uint32_t ch, uint32_t ddr_csn) { int32_t i, k; uint32_t cs, slice; uint32_t data_l; /* clr of training results buffer */ cs = ddr_csn % 2; data_l = board_cnf->dqdm_dly_w; for (slice = 0; slice < SLICE_CNT; slice++) { k = (board_cnf->ch[ch].dqs_swap >> (4 * slice)) & 0x0f; if (((k >= 2) && (ddr_csn < 2)) || ((k < 2) && (ddr_csn >= 2))) continue; for (i = 0; i <= 8; i++) { if (ch_have_this_cs[CS_CNT - 1 - cs] & (1U << ch)) wdqdm_dly[ch][cs][slice][i] = wdqdm_dly[ch][CS_CNT - 1 - cs][slice][i]; else wdqdm_dly[ch][cs][slice][i] = data_l; wdqdm_le[ch][cs][slice][i] = 0; wdqdm_te[ch][cs][slice][i] = 0; } wdqdm_st[ch][cs][slice] = 0; wdqdm_win[ch][cs][slice] = 0; } } static uint32_t wdqdm_ana1(uint32_t ch, uint32_t ddr_csn) { int32_t i, k; uint32_t cs, slice; uint32_t data_l; uint32_t err; const uint32_t _par_WDQLVL_RETRY_THRES = 0x7c0; int32_t min_win; int32_t win; int8_t _adj; int16_t adj; uint32_t dq; /* analysis of training results */ err = 0; for (slice = 0; slice < SLICE_CNT; slice += 1) { k = (board_cnf->ch[ch].dqs_swap >> (4 * slice)) & 0x0f; if (((k >= 2) && (ddr_csn < 2)) || ((k < 2) && (ddr_csn >= 2))) continue; cs = ddr_csn % 2; ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_INDEX, cs); for (i = 0; i < 9; i++) { dq = slice * 8 + i; if (i == 8) _adj = board_cnf->ch[ch].dm_adj_w[slice]; else _adj = board_cnf->ch[ch].dq_adj_w[dq]; adj = _f_scale_adj(_adj); data_l = ddr_getval_s(ch, slice, _reg_PHY_CLK_WRX_SLAVE_DELAY[i]) + adj; ddr_setval_s(ch, slice, _reg_PHY_CLK_WRX_SLAVE_DELAY[i], data_l); wdqdm_dly[ch][cs][slice][i] = data_l; } ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_EN, 0x00); data_l = ddr_getval_s(ch, slice, _reg_PHY_WDQLVL_STATUS_OBS); wdqdm_st[ch][cs][slice] = data_l; min_win = INT_LEAST32_MAX; for (i = 0; i <= 8; i++) { ddr_setval_s(ch, slice, _reg_PHY_WDQLVL_DQDM_OBS_SELECT, i); data_l = ddr_getval_s(ch, slice, _reg_PHY_WDQLVL_DQDM_TE_DLY_OBS); wdqdm_te[ch][cs][slice][i] = data_l; data_l = ddr_getval_s(ch, slice, _reg_PHY_WDQLVL_DQDM_LE_DLY_OBS); wdqdm_le[ch][cs][slice][i] = data_l; win = (int32_t)wdqdm_te[ch][cs][slice][i] - wdqdm_le[ch][cs][slice][i]; if (min_win > win) min_win = win; if (data_l >= _par_WDQLVL_RETRY_THRES) err = 2; } wdqdm_win[ch][cs][slice] = min_win; if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_EN, 0x01); } else { ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_EN, ((ch_have_this_cs[1]) >> ch) & 0x01); } } return err; } #endif/* DDR_FAST_INIT */ static void wdqdm_cp(uint32_t ddr_csn, uint32_t restore) { uint32_t i; uint32_t ch, slice; uint32_t tgt_cs, src_cs; uint32_t tmp_r; /* copy of training results */ foreach_vch(ch) { for (tgt_cs = 0; tgt_cs < CS_CNT; tgt_cs++) { for (slice = 0; slice < SLICE_CNT; slice++) { ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_INDEX, tgt_cs); src_cs = ddr_csn % 2; if (!(ch_have_this_cs[1] & (1U << ch))) src_cs = 0; for (i = 0; i <= 4; i += 4) { if (restore) tmp_r = rdqdm_dly[ch][tgt_cs][slice] [i]; else tmp_r = rdqdm_dly[ch][src_cs][slice] [i]; ddr_setval_s(ch, slice, _reg_PHY_RDDQS_X_RISE_SLAVE_DELAY [i], tmp_r); } } } } } static uint32_t wdqdm_man1(void) { int32_t k; uint32_t ch, cs, slice; uint32_t ddr_csn; uint32_t data_l; uint32_t err; uint32_t high_dq[DRAM_CH_CNT]; uint32_t mr14_csab0_bak[DRAM_CH_CNT]; #ifndef DDR_FAST_INIT uint32_t err_flg; #endif/* DDR_FAST_INIT */ /* manual execution of training */ if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { foreach_vch(ch) { high_dq[ch] = 0; for (slice = 0; slice < SLICE_CNT; slice++) { k = (board_cnf->ch[ch].dqs_swap >> (4 * slice)) & 0x0f; if (k >= 2) high_dq[ch] |= (1U << slice); } ddr_setval(ch, _reg_PI_16BIT_DRAM_CONNECT, 0x00); } } err = 0; /* CLEAR PREV RESULT */ for (cs = 0; cs < CS_CNT; cs++) { ddr_setval_ach_as(_reg_PHY_PER_CS_TRAINING_INDEX, cs); if (((prr_product == PRR_PRODUCT_H3) && (prr_cut > PRR_PRODUCT_11)) || (prr_product == PRR_PRODUCT_M3N) || (prr_product == PRR_PRODUCT_V3H)) { ddr_setval_ach_as(_reg_SC_PHY_WDQLVL_CLR_PREV_RESULTS, 0x01); } else { ddr_setval_ach_as(_reg_PHY_WDQLVL_CLR_PREV_RESULTS, 0x01); } } ddrphy_regif_idle(); #ifndef DDR_FAST_INIT err_flg = 0; #endif/* DDR_FAST_INIT */ for (ddr_csn = 0; ddr_csn < CSAB_CNT; ddr_csn++) { if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { foreach_vch(ch) { data_l = mmio_read_32(DBSC_DBDFICNT(ch)); data_l &= ~(0x00ffU << 16); if (ddr_csn >= 2) k = (high_dq[ch] ^ 0x0f); else k = high_dq[ch]; data_l |= (k << 16); mmio_write_32(DBSC_DBDFICNT(ch), data_l); ddr_setval(ch, _reg_PI_WDQLVL_RESP_MASK, k); } } if (((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) || ((prr_product == PRR_PRODUCT_M3) && (prr_cut == PRR_PRODUCT_10))) { wdqdm_cp(ddr_csn, 0); } foreach_vch(ch) { data_l = ddr_getval(ch, reg_pi_mr14_data_fx_csx[1][ddr_csn]); ddr_setval(ch, reg_pi_mr14_data_fx_csx[1][0], data_l); } /* KICK WDQLVL */ err = swlvl1(ddr_csn, _reg_PI_WDQLVL_CS, _reg_PI_WDQLVL_REQ); if (err) goto err_exit; if (ddr_csn == 0) foreach_vch(ch) { mr14_csab0_bak[ch] = ddr_getval(ch, reg_pi_mr14_data_fx_csx[1][0]); } else foreach_vch(ch) { ddr_setval(ch, reg_pi_mr14_data_fx_csx[1][0], mr14_csab0_bak[ch]); } #ifndef DDR_FAST_INIT foreach_vch(ch) { if (!(ch_have_this_cs[ddr_csn % 2] & (1U << ch))) { wdqdm_clr1(ch, ddr_csn); continue; } err = wdqdm_ana1(ch, ddr_csn); if (err) err_flg |= (1U << (ddr_csn * 4 + ch)); ddrphy_regif_idle(); } #endif/* DDR_FAST_INIT */ } err_exit: #ifndef DDR_FAST_INIT err |= err_flg; #endif/* DDR_FAST_INIT */ if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { ddr_setval_ach(_reg_PI_16BIT_DRAM_CONNECT, 0x01); foreach_vch(ch) { data_l = mmio_read_32(DBSC_DBDFICNT(ch)); data_l &= ~(0x00ffU << 16); mmio_write_32(DBSC_DBDFICNT(ch), data_l); ddr_setval(ch, _reg_PI_WDQLVL_RESP_MASK, 0x00); } } return err; } static uint32_t wdqdm_man(void) { uint32_t err, retry_cnt; const uint32_t retry_max = 0x10; uint32_t ch, ddr_csn, mr14_bkup[4][4]; ddr_setval_ach(_reg_PI_TDFI_WDQLVL_RW, (mmio_read_32(DBSC_DBTR(11)) & 0xFF) + 19); if (((prr_product == PRR_PRODUCT_H3) && (prr_cut > PRR_PRODUCT_11)) || (prr_product == PRR_PRODUCT_M3N) || (prr_product == PRR_PRODUCT_V3H)) { ddr_setval_ach(_reg_PI_TDFI_WDQLVL_WR_F0, (mmio_read_32(DBSC_DBTR(12)) & 0xFF) + 10); ddr_setval_ach(_reg_PI_TDFI_WDQLVL_WR_F1, (mmio_read_32(DBSC_DBTR(12)) & 0xFF) + 10); } else { ddr_setval_ach(_reg_PI_TDFI_WDQLVL_WR, (mmio_read_32(DBSC_DBTR(12)) & 0xFF) + 10); } ddr_setval_ach(_reg_PI_TRFC_F0, mmio_read_32(DBSC_DBTR(13)) & 0x1FF); ddr_setval_ach(_reg_PI_TRFC_F1, mmio_read_32(DBSC_DBTR(13)) & 0x1FF); retry_cnt = 0; err = 0; do { if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { err = wdqdm_man1(); } else { ddr_setval_ach(_reg_PI_WDQLVL_VREF_EN, 0x01); ddr_setval_ach(_reg_PI_WDQLVL_VREF_NORMAL_STEPSIZE, 0x01); if ((prr_product == PRR_PRODUCT_M3N) || (prr_product == PRR_PRODUCT_V3H)) { ddr_setval_ach(_reg_PI_WDQLVL_VREF_DELTA_F1, 0x0C); } else { ddr_setval_ach(_reg_PI_WDQLVL_VREF_DELTA, 0x0C); } dsb_sev(); err = wdqdm_man1(); foreach_vch(ch) { for (ddr_csn = 0; ddr_csn < CSAB_CNT; ddr_csn++) { mr14_bkup[ch][ddr_csn] = ddr_getval(ch, reg_pi_mr14_data_fx_csx [1][ddr_csn]); dsb_sev(); } } if ((prr_product == PRR_PRODUCT_M3N) || (prr_product == PRR_PRODUCT_V3H)) { ddr_setval_ach(_reg_PI_WDQLVL_VREF_DELTA_F1, 0x04); } else { ddr_setval_ach(_reg_PI_WDQLVL_VREF_DELTA, 0x04); } pvtcode_update(); err = wdqdm_man1(); foreach_vch(ch) { for (ddr_csn = 0; ddr_csn < CSAB_CNT; ddr_csn++) { mr14_bkup[ch][ddr_csn] = (mr14_bkup[ch][ddr_csn] + ddr_getval(ch, reg_pi_mr14_data_fx_csx [1][ddr_csn])) / 2; ddr_setval(ch, reg_pi_mr14_data_fx_csx[1] [ddr_csn], mr14_bkup[ch][ddr_csn]); } } ddr_setval_ach(_reg_PI_WDQLVL_VREF_NORMAL_STEPSIZE, 0x00); if ((prr_product == PRR_PRODUCT_M3N) || (prr_product == PRR_PRODUCT_V3H)) { ddr_setval_ach(_reg_PI_WDQLVL_VREF_DELTA_F1, 0x00); ddr_setval_ach (_reg_PI_WDQLVL_VREF_INITIAL_START_POINT_F1, 0x00); ddr_setval_ach (_reg_PI_WDQLVL_VREF_INITIAL_STOP_POINT_F1, 0x00); } else { ddr_setval_ach(_reg_PI_WDQLVL_VREF_DELTA, 0x00); ddr_setval_ach (_reg_PI_WDQLVL_VREF_INITIAL_START_POINT, 0x00); ddr_setval_ach (_reg_PI_WDQLVL_VREF_INITIAL_STOP_POINT, 0x00); } ddr_setval_ach(_reg_PI_WDQLVL_VREF_INITIAL_STEPSIZE, 0x00); pvtcode_update2(); err = wdqdm_man1(); ddr_setval_ach(_reg_PI_WDQLVL_VREF_EN, 0x00); } } while (err && (++retry_cnt < retry_max)); if (((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) || ((prr_product == PRR_PRODUCT_M3) && (prr_cut <= PRR_PRODUCT_10))) { wdqdm_cp(0, 1); } return (retry_cnt >= retry_max); } /* RDQ TRAINING */ #ifndef DDR_FAST_INIT static void rdqdm_clr1(uint32_t ch, uint32_t ddr_csn) { int32_t i, k; uint32_t cs, slice; uint32_t data_l; /* clr of training results buffer */ cs = ddr_csn % 2; data_l = board_cnf->dqdm_dly_r; for (slice = 0; slice < SLICE_CNT; slice++) { k = (board_cnf->ch[ch].dqs_swap >> (4 * slice)) & 0x0f; if (((k >= 2) && (ddr_csn < 2)) || ((k < 2) && (ddr_csn >= 2))) continue; for (i = 0; i <= 8; i++) { if (ch_have_this_cs[CS_CNT - 1 - cs] & (1U << ch)) { rdqdm_dly[ch][cs][slice][i] = rdqdm_dly[ch][CS_CNT - 1 - cs][slice][i]; rdqdm_dly[ch][cs][slice + SLICE_CNT][i] = rdqdm_dly[ch][CS_CNT - 1 - cs][slice + SLICE_CNT] [i]; } else { rdqdm_dly[ch][cs][slice][i] = data_l; rdqdm_dly[ch][cs][slice + SLICE_CNT][i] = data_l; } rdqdm_le[ch][cs][slice][i] = 0; rdqdm_le[ch][cs][slice + SLICE_CNT][i] = 0; rdqdm_te[ch][cs][slice][i] = 0; rdqdm_te[ch][cs][slice + SLICE_CNT][i] = 0; rdqdm_nw[ch][cs][slice][i] = 0; rdqdm_nw[ch][cs][slice + SLICE_CNT][i] = 0; } rdqdm_st[ch][cs][slice] = 0; rdqdm_win[ch][cs][slice] = 0; } } static uint32_t rdqdm_ana1(uint32_t ch, uint32_t ddr_csn) { int32_t i, k; uint32_t cs, slice; uint32_t data_l; uint32_t err; int8_t _adj; int16_t adj; uint32_t dq; int32_t min_win; int32_t win; uint32_t rdq_status_obs_select; /* analysis of training results */ err = 0; for (slice = 0; slice < SLICE_CNT; slice++) { k = (board_cnf->ch[ch].dqs_swap >> (4 * slice)) & 0x0f; if (((k >= 2) && (ddr_csn < 2)) || ((k < 2) && (ddr_csn >= 2))) continue; cs = ddr_csn % 2; ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_INDEX, cs); ddrphy_regif_idle(); ddr_getval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_INDEX); ddrphy_regif_idle(); for (i = 0; i <= 8; i++) { dq = slice * 8 + i; if (i == 8) _adj = board_cnf->ch[ch].dm_adj_r[slice]; else _adj = board_cnf->ch[ch].dq_adj_r[dq]; adj = _f_scale_adj(_adj); data_l = ddr_getval_s(ch, slice, _reg_PHY_RDDQS_X_RISE_SLAVE_DELAY[i]) + adj; ddr_setval_s(ch, slice, _reg_PHY_RDDQS_X_RISE_SLAVE_DELAY[i], data_l); rdqdm_dly[ch][cs][slice][i] = data_l; data_l = ddr_getval_s(ch, slice, _reg_PHY_RDDQS_X_FALL_SLAVE_DELAY[i]) + adj; ddr_setval_s(ch, slice, _reg_PHY_RDDQS_X_FALL_SLAVE_DELAY[i], data_l); rdqdm_dly[ch][cs][slice + SLICE_CNT][i] = data_l; } min_win = INT_LEAST32_MAX; for (i = 0; i <= 8; i++) { data_l = ddr_getval_s(ch, slice, _reg_PHY_RDLVL_STATUS_OBS); rdqdm_st[ch][cs][slice] = data_l; rdqdm_st[ch][cs][slice + SLICE_CNT] = data_l; /* k : rise/fall */ for (k = 0; k < 2; k++) { if (i == 8) { rdq_status_obs_select = 16 + 8 * k; } else { rdq_status_obs_select = i + k * 8; } ddr_setval_s(ch, slice, _reg_PHY_RDLVL_RDDQS_DQ_OBS_SELECT, rdq_status_obs_select); data_l = ddr_getval_s(ch, slice, _reg_PHY_RDLVL_RDDQS_DQ_LE_DLY_OBS); rdqdm_le[ch][cs][slice + SLICE_CNT * k][i] = data_l; data_l = ddr_getval_s(ch, slice, _reg_PHY_RDLVL_RDDQS_DQ_TE_DLY_OBS); rdqdm_te[ch][cs][slice + SLICE_CNT * k][i] = data_l; data_l = ddr_getval_s(ch, slice, _reg_PHY_RDLVL_RDDQS_DQ_NUM_WINDOWS_OBS); rdqdm_nw[ch][cs][slice + SLICE_CNT * k][i] = data_l; win = (int32_t)rdqdm_te[ch][cs][slice + SLICE_CNT * k][i] - rdqdm_le[ch][cs][slice + SLICE_CNT * k][i]; if (i != 8) { if (min_win > win) min_win = win; } } } rdqdm_win[ch][cs][slice] = min_win; if (min_win <= 0) { err = 2; } } return err; } #endif/* DDR_FAST_INIT */ static uint32_t rdqdm_man1(void) { uint32_t ch; uint32_t ddr_csn; #ifdef DDR_FAST_INIT uint32_t slice; uint32_t i, adj, data_l; #endif/* DDR_FAST_INIT */ uint32_t err; /* manual execution of training */ err = 0; for (ddr_csn = 0; ddr_csn < CSAB_CNT; ddr_csn++) { /* KICK RDQLVL */ err = swlvl1(ddr_csn, _reg_PI_RDLVL_CS, _reg_PI_RDLVL_REQ); if (err) goto err_exit; #ifndef DDR_FAST_INIT foreach_vch(ch) { if (!(ch_have_this_cs[ddr_csn % 2] & (1U << ch))) { rdqdm_clr1(ch, ddr_csn); ddrphy_regif_idle(); continue; } err = rdqdm_ana1(ch, ddr_csn); ddrphy_regif_idle(); if (err) goto err_exit; } #else/* DDR_FAST_INIT */ foreach_vch(ch) { if (ch_have_this_cs[ddr_csn] & (1U << ch)) { for (slice = 0; slice < SLICE_CNT; slice++) { if (ddr_getval_s(ch, slice, _reg_PHY_RDLVL_STATUS_OBS) != 0x0D00FFFF) { err = (1U << ch) | (0x10U << slice); goto err_exit; } } } if (((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) || ((prr_product == PRR_PRODUCT_M3) && (prr_cut <= PRR_PRODUCT_10))) { for (slice = 0; slice < SLICE_CNT; slice++) { for (i = 0; i <= 8; i++) { if (i == 8) adj = _f_scale_adj(board_cnf->ch[ch].dm_adj_r[slice]); else adj = _f_scale_adj(board_cnf->ch[ch].dq_adj_r[slice * 8 + i]); ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_INDEX, ddr_csn); data_l = ddr_getval_s(ch, slice, _reg_PHY_RDDQS_X_RISE_SLAVE_DELAY[i]) + adj; ddr_setval_s(ch, slice, _reg_PHY_RDDQS_X_RISE_SLAVE_DELAY[i], data_l); rdqdm_dly[ch][ddr_csn][slice][i] = data_l; rdqdm_dly[ch][ddr_csn | 1][slice][i] = data_l; data_l = ddr_getval_s(ch, slice, _reg_PHY_RDDQS_X_FALL_SLAVE_DELAY[i]) + adj; ddr_setval_s(ch, slice, _reg_PHY_RDDQS_X_FALL_SLAVE_DELAY[i], data_l); rdqdm_dly[ch][ddr_csn][slice + SLICE_CNT][i] = data_l; rdqdm_dly[ch][ddr_csn | 1][slice + SLICE_CNT][i] = data_l; } } } } ddrphy_regif_idle(); #endif/* DDR_FAST_INIT */ } err_exit: return err; } static uint32_t rdqdm_man(void) { uint32_t err, retry_cnt; const uint32_t retry_max = 0x01; ddr_setval_ach_as(_reg_PHY_DQ_TSEL_ENABLE, 0x00000004 | ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_DQ_TSEL_ENABLE)); ddr_setval_ach_as(_reg_PHY_DQS_TSEL_ENABLE, 0x00000004 | ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_DQS_TSEL_ENABLE)); ddr_setval_ach_as(_reg_PHY_DQ_TSEL_SELECT, 0xFF0FFFFF & ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_DQ_TSEL_SELECT)); ddr_setval_ach_as(_reg_PHY_DQS_TSEL_SELECT, 0xFF0FFFFF & ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_DQS_TSEL_SELECT)); retry_cnt = 0; do { err = rdqdm_man1(); ddrphy_regif_idle(); } while (err && (++retry_cnt < retry_max)); ddr_setval_ach_as(_reg_PHY_DQ_TSEL_ENABLE, ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_DQ_TSEL_ENABLE)); ddr_setval_ach_as(_reg_PHY_DQS_TSEL_ENABLE, ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_DQS_TSEL_ENABLE)); ddr_setval_ach_as(_reg_PHY_DQ_TSEL_SELECT, ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_DQ_TSEL_SELECT)); ddr_setval_ach_as(_reg_PHY_DQS_TSEL_SELECT, ddrtbl_getval(_cnf_DDR_PHY_SLICE_REGSET, _reg_PHY_DQS_TSEL_SELECT)); return (retry_cnt >= retry_max); } /* rx offset calibration */ static int32_t _find_change(uint64_t val, uint32_t dir) { int32_t i; uint32_t startval; uint32_t curval; const int32_t VAL_END = 0x3f; if (dir == 0) { startval = (val & 0x01); for (i = 1; i <= VAL_END; i++) { curval = (val >> i) & 0x01; if (curval != startval) return i; } return VAL_END; } startval = (val >> dir) & 0x01; for (i = dir - 1; i >= 0; i--) { curval = (val >> i) & 0x01; if (curval != startval) return i; } return 0; } static uint32_t _rx_offset_cal_updn(uint32_t code) { const uint32_t CODE_MAX = 0x40; uint32_t tmp; if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { if (code == 0) tmp = (1U << 6) | (CODE_MAX - 1); else if (code <= 0x20) tmp = ((CODE_MAX - 1 - (0x20 - code) * 2) << 6) | (CODE_MAX - 1); else tmp = ((CODE_MAX - 1) << 6) | (CODE_MAX - 1 - (code - 0x20) * 2); } else { if (code == 0) tmp = (1U << 6) | (CODE_MAX - 1); else tmp = (code << 6) | (CODE_MAX - code); } return tmp; } static uint32_t rx_offset_cal(void) { uint32_t index; uint32_t code; const uint32_t CODE_MAX = 0x40; const uint32_t CODE_STEP = 2; uint32_t ch, slice; uint32_t tmp; uint32_t tmp_ach_as[DRAM_CH_CNT][SLICE_CNT]; uint64_t val[DRAM_CH_CNT][SLICE_CNT][_reg_PHY_RX_CAL_X_NUM]; uint64_t tmpval; int32_t lsb, msb; ddr_setval_ach_as(_reg_PHY_RX_CAL_OVERRIDE, 0x01); foreach_vch(ch) { for (slice = 0; slice < SLICE_CNT; slice++) { for (index = 0; index < _reg_PHY_RX_CAL_X_NUM; index++) val[ch][slice][index] = 0; } } for (code = 0; code < CODE_MAX / CODE_STEP; code++) { tmp = _rx_offset_cal_updn(code * CODE_STEP); for (index = 0; index < _reg_PHY_RX_CAL_X_NUM; index++) { ddr_setval_ach_as(_reg_PHY_RX_CAL_X[index], tmp); } dsb_sev(); ddr_getval_ach_as(_reg_PHY_RX_CAL_OBS, (uint32_t *)tmp_ach_as); foreach_vch(ch) { for (slice = 0; slice < SLICE_CNT; slice++) { tmp = tmp_ach_as[ch][slice]; for (index = 0; index < _reg_PHY_RX_CAL_X_NUM; index++) { if (tmp & (1U << index)) { val[ch][slice][index] |= (1ULL << code); } else { val[ch][slice][index] &= ~(1ULL << code); } } } } } foreach_vch(ch) { for (slice = 0; slice < SLICE_CNT; slice++) { for (index = 0; index < _reg_PHY_RX_CAL_X_NUM; index++) { tmpval = val[ch][slice][index]; lsb = _find_change(tmpval, 0); msb = _find_change(tmpval, (CODE_MAX / CODE_STEP) - 1); tmp = (lsb + msb) >> 1; tmp = _rx_offset_cal_updn(tmp * CODE_STEP); ddr_setval_s(ch, slice, _reg_PHY_RX_CAL_X[index], tmp); } } } ddr_setval_ach_as(_reg_PHY_RX_CAL_OVERRIDE, 0x00); return 0; } static uint32_t rx_offset_cal_hw(void) { uint32_t ch, slice; uint32_t retry; uint32_t complete; uint32_t tmp; uint32_t tmp_ach_as[DRAM_CH_CNT][SLICE_CNT]; ddr_setval_ach_as(_reg_PHY_RX_CAL_X[9], 0x00); ddr_setval_ach_as(_reg_PHY_RX_CAL_OVERRIDE, 0x00); ddr_setval_ach_as(_reg_PHY_RX_CAL_SAMPLE_WAIT, 0x0f); retry = 0; while (retry < 4096) { if ((retry & 0xff) == 0) { ddr_setval_ach_as(_reg_SC_PHY_RX_CAL_START, 0x01); } foreach_vch(ch) for (slice = 0; slice < SLICE_CNT; slice++) tmp_ach_as[ch][slice] = ddr_getval_s(ch, slice, _reg_PHY_RX_CAL_X[9]); complete = 1; foreach_vch(ch) { for (slice = 0; slice < SLICE_CNT; slice++) { tmp = tmp_ach_as[ch][slice]; tmp = (tmp & 0x3f) + ((tmp >> 6) & 0x3f); if (((prr_product == PRR_PRODUCT_H3) && (prr_cut > PRR_PRODUCT_11)) || (prr_product == PRR_PRODUCT_M3N) || (prr_product == PRR_PRODUCT_V3H)) { if (tmp != 0x3E) complete = 0; } else { if (tmp != 0x40) complete = 0; } } } if (complete) break; retry++; } return (complete == 0); } /* adjust rddqs latency */ static void adjust_rddqs_latency(void) { uint32_t ch, slice; uint32_t dly; uint32_t maxlatx2; uint32_t tmp; uint32_t rdlat_adjx2[SLICE_CNT]; foreach_vch(ch) { maxlatx2 = 0; for (slice = 0; slice < SLICE_CNT; slice++) { ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_INDEX, 0x00); dly = ddr_getval_s(ch, slice, _reg_PHY_RDDQS_GATE_SLAVE_DELAY); tmp = ddr_getval_s(ch, slice, _reg_PHY_RDDQS_LATENCY_ADJUST); /* note gate_slave_delay[9] is always 0 */ tmp = (tmp << 1) + (dly >> 8); rdlat_adjx2[slice] = tmp; if (maxlatx2 < tmp) maxlatx2 = tmp; } maxlatx2 = ((maxlatx2 + 1) >> 1) << 1; for (slice = 0; slice < SLICE_CNT; slice++) { tmp = maxlatx2 - rdlat_adjx2[slice]; tmp = (tmp >> 1); if (tmp) { ddr_setval_s(ch, slice, _reg_PHY_RPTR_UPDATE, ddr_getval_s(ch, slice, _reg_PHY_RPTR_UPDATE) + 1); } } } } /* adjust wpath latency */ static void adjust_wpath_latency(void) { uint32_t ch, cs, slice; uint32_t dly; uint32_t wpath_add; const uint32_t _par_EARLY_THRESHOLD_VAL = 0x180; foreach_vch(ch) { for (slice = 0; slice < SLICE_CNT; slice += 1) { for (cs = 0; cs < CS_CNT; cs++) { ddr_setval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_INDEX, cs); ddr_getval_s(ch, slice, _reg_PHY_PER_CS_TRAINING_INDEX); dly = ddr_getval_s(ch, slice, _reg_PHY_CLK_WRDQS_SLAVE_DELAY); if (dly <= _par_EARLY_THRESHOLD_VAL) continue; wpath_add = ddr_getval_s(ch, slice, _reg_PHY_WRITE_PATH_LAT_ADD); ddr_setval_s(ch, slice, _reg_PHY_WRITE_PATH_LAT_ADD, wpath_add - 1); } } } } /* DDR Initialize entry */ int32_t rcar_dram_init(void) { uint32_t ch, cs; uint32_t data_l; uint32_t bus_mbps, bus_mbpsdiv; uint32_t tmp_tccd; uint32_t failcount; uint32_t cnf_boardtype; /* Thermal sensor setting */ data_l = mmio_read_32(CPG_MSTPSR5); if (data_l & BIT(22)) { /* case THS/TSC Standby */ data_l &= ~BIT(22); cpg_write_32(CPG_SMSTPCR5, data_l); while (mmio_read_32(CPG_MSTPSR5) & BIT(22)) ; /* wait bit=0 */ } /* THCTR Bit6: PONM=0 , Bit0: THSST=0 */ data_l = mmio_read_32(THS1_THCTR) & 0xFFFFFFBE; mmio_write_32(THS1_THCTR, data_l); /* Judge product and cut */ #ifdef RCAR_DDR_FIXED_LSI_TYPE #if (RCAR_LSI == RCAR_AUTO) prr_product = mmio_read_32(PRR) & PRR_PRODUCT_MASK; prr_cut = mmio_read_32(PRR) & PRR_CUT_MASK; #else /* RCAR_LSI */ #ifndef RCAR_LSI_CUT prr_cut = mmio_read_32(PRR) & PRR_CUT_MASK; #endif /* RCAR_LSI_CUT */ #endif /* RCAR_LSI */ #else /* RCAR_DDR_FIXED_LSI_TYPE */ prr_product = mmio_read_32(PRR) & PRR_PRODUCT_MASK; prr_cut = mmio_read_32(PRR) & PRR_CUT_MASK; #endif /* RCAR_DDR_FIXED_LSI_TYPE */ if (prr_product == PRR_PRODUCT_H3) { if (prr_cut <= PRR_PRODUCT_11) { p_ddr_regdef_tbl = (const uint32_t *)&DDR_REGDEF_TBL[0][0]; } else { p_ddr_regdef_tbl = (const uint32_t *)&DDR_REGDEF_TBL[2][0]; } } else if (prr_product == PRR_PRODUCT_M3) { p_ddr_regdef_tbl = (const uint32_t *)&DDR_REGDEF_TBL[1][0]; } else if ((prr_product == PRR_PRODUCT_M3N) || (prr_product == PRR_PRODUCT_V3H)) { p_ddr_regdef_tbl = (const uint32_t *)&DDR_REGDEF_TBL[3][0]; } else { FATAL_MSG("BL2: DDR:Unknown Product\n"); return 0xff; } if (((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) || ((prr_product == PRR_PRODUCT_M3) && (prr_cut < PRR_PRODUCT_30))) { /* non : H3 Ver.1.x/M3-W Ver.1.x not support */ } else { mmio_write_32(DBSC_DBSYSCNT0, 0x00001234); } /* Judge board type */ cnf_boardtype = boardcnf_get_brd_type(); if (cnf_boardtype >= BOARDNUM) { FATAL_MSG("BL2: DDR:Unknown Board\n"); return 0xff; } board_cnf = (const struct _boardcnf *)&boardcnfs[cnf_boardtype]; /* RCAR_DRAM_SPLIT_2CH (2U) */ #if RCAR_DRAM_SPLIT == 2 /* H3(Test for future H3-N): Swap ch2 and ch1 for 2ch-split */ if ((prr_product == PRR_PRODUCT_H3) && (board_cnf->phyvalid == 0x05)) { mmio_write_32(DBSC_DBMEMSWAPCONF0, 0x00000006); ddr_phyvalid = 0x03; } else { ddr_phyvalid = board_cnf->phyvalid; } #else /* RCAR_DRAM_SPLIT_2CH */ ddr_phyvalid = board_cnf->phyvalid; #endif /* RCAR_DRAM_SPLIT_2CH */ max_density = 0; for (cs = 0; cs < CS_CNT; cs++) { ch_have_this_cs[cs] = 0; } foreach_ech(ch) for (cs = 0; cs < CS_CNT; cs++) ddr_density[ch][cs] = 0xff; foreach_vch(ch) { for (cs = 0; cs < CS_CNT; cs++) { data_l = board_cnf->ch[ch].ddr_density[cs]; ddr_density[ch][cs] = data_l; if (data_l == 0xff) continue; if (data_l > max_density) max_density = data_l; if ((cs == 1) && (prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) continue; ch_have_this_cs[cs] |= (1U << ch); } } /* Judge board clock frequency (in MHz) */ boardcnf_get_brd_clk(cnf_boardtype, &brd_clk, &brd_clkdiv); if ((brd_clk / brd_clkdiv) > 25) { brd_clkdiva = 1; } else { brd_clkdiva = 0; } /* Judge ddr operating frequency clock(in Mbps) */ boardcnf_get_ddr_mbps(cnf_boardtype, &ddr_mbps, &ddr_mbpsdiv); ddr0800_mul = CLK_DIV(800, 2, brd_clk, brd_clkdiv * (brd_clkdiva + 1)); ddr_mul = CLK_DIV(ddr_mbps, ddr_mbpsdiv * 2, brd_clk, brd_clkdiv * (brd_clkdiva + 1)); /* Adjust tccd */ data_l = (0x00006000 & mmio_read_32(RST_MODEMR)) >> 13; bus_mbps = 0; bus_mbpsdiv = 0; switch (data_l) { case 0: bus_mbps = brd_clk * 0x60 * 2; bus_mbpsdiv = brd_clkdiv * 1; break; case 1: bus_mbps = brd_clk * 0x50 * 2; bus_mbpsdiv = brd_clkdiv * 1; break; case 2: bus_mbps = brd_clk * 0x40 * 2; bus_mbpsdiv = brd_clkdiv * 1; break; case 3: bus_mbps = brd_clk * 0x60 * 2; bus_mbpsdiv = brd_clkdiv * 2; break; default: bus_mbps = brd_clk * 0x60 * 2; bus_mbpsdiv = brd_clkdiv * 2; break; } tmp_tccd = CLK_DIV(ddr_mbps * 8, ddr_mbpsdiv, bus_mbps, bus_mbpsdiv); if (8 * ddr_mbps * bus_mbpsdiv != tmp_tccd * bus_mbps * ddr_mbpsdiv) tmp_tccd = tmp_tccd + 1; if (tmp_tccd < 8) ddr_tccd = 8; else ddr_tccd = tmp_tccd; NOTICE("BL2: DDR%d(%s)\n", ddr_mbps / ddr_mbpsdiv, RCAR_DDR_VERSION); MSG_LF("Start\n"); /* PLL Setting */ pll3_control(1); /* initialize DDR */ data_l = init_ddr(); if (data_l == ddr_phyvalid) { failcount = 0; } else { failcount = 1; } foreach_vch(ch) mmio_write_32(DBSC_DBPDLK(ch), 0x00000000); if (((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) || ((prr_product == PRR_PRODUCT_M3) && (prr_cut < PRR_PRODUCT_30))) { /* non : H3 Ver.1.x/M3-W Ver.1.x not support */ } else { mmio_write_32(DBSC_DBSYSCNT0, 0x00000000); } if (failcount == 0) { return INITDRAM_OK; } else { return INITDRAM_NG; } } void pvtcode_update(void) { uint32_t ch; uint32_t data_l; uint32_t pvtp[4], pvtn[4], pvtp_init, pvtn_init; int32_t pvtp_tmp, pvtn_tmp; foreach_vch(ch) { pvtn_init = (tcal.tcomp_cal[ch] & 0xFC0) >> 6; pvtp_init = (tcal.tcomp_cal[ch] & 0x03F) >> 0; if (8912 * pvtp_init > 44230) { pvtp_tmp = (5000 + 8912 * pvtp_init - 44230) / 10000; } else { pvtp_tmp = -((-(5000 + 8912 * pvtp_init - 44230)) / 10000); } pvtn_tmp = (5000 + 5776 * pvtn_init + 30280) / 10000; pvtn[ch] = pvtn_tmp + pvtn_init; pvtp[ch] = pvtp_tmp + pvtp_init; if (pvtn[ch] > 63) { pvtn[ch] = 63; pvtp[ch] = (pvtp_tmp) * (63 - 6 * pvtn_tmp - pvtn_init) / (pvtn_tmp) + 6 * pvtp_tmp + pvtp_init; } if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { data_l = pvtp[ch] | (pvtn[ch] << 6) | (tcal.tcomp_cal[ch] & 0xfffff000); reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_FDBK_TERM), data_l | 0x00020000); reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_DATA_TERM), data_l); reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_DQS_TERM), data_l); reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_ADDR_TERM), data_l); reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_CS_TERM), data_l); } else { data_l = pvtp[ch] | (pvtn[ch] << 6) | 0x00015000; reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_FDBK_TERM), data_l | 0x00020000); reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_DATA_TERM), data_l); reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_DQS_TERM), data_l); reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_ADDR_TERM), data_l); reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_CS_TERM), data_l); } } } void pvtcode_update2(void) { uint32_t ch; foreach_vch(ch) { reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_FDBK_TERM), tcal.init_cal[ch] | 0x00020000); reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_DATA_TERM), tcal.init_cal[ch]); reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_DQS_TERM), tcal.init_cal[ch]); reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_ADDR_TERM), tcal.init_cal[ch]); reg_ddrphy_write(ch, ddr_regdef_adr(_reg_PHY_PAD_CS_TERM), tcal.init_cal[ch]); } } void ddr_padcal_tcompensate_getinit(uint32_t override) { uint32_t ch; uint32_t data_l; uint32_t pvtp, pvtn; tcal.init_temp = 0; for (ch = 0; ch < 4; ch++) { tcal.init_cal[ch] = 0; tcal.tcomp_cal[ch] = 0; } foreach_vch(ch) { tcal.init_cal[ch] = ddr_getval(ch, _reg_PHY_PAD_TERM_X[1]); tcal.tcomp_cal[ch] = ddr_getval(ch, _reg_PHY_PAD_TERM_X[1]); } if (!override) { data_l = mmio_read_32(THS1_TEMP); if (data_l < 2800) { tcal.init_temp = (143 * (int32_t)data_l - 359000) / 1000; } else { tcal.init_temp = (121 * (int32_t)data_l - 296300) / 1000; } foreach_vch(ch) { pvtp = (tcal.init_cal[ch] >> 0) & 0x000003F; pvtn = (tcal.init_cal[ch] >> 6) & 0x000003F; if ((int32_t)pvtp > ((tcal.init_temp * 29 - 3625) / 1000)) pvtp = (int32_t)pvtp + ((3625 - tcal.init_temp * 29) / 1000); else pvtp = 0; if ((int32_t)pvtn > ((tcal.init_temp * 54 - 6750) / 1000)) pvtn = (int32_t)pvtn + ((6750 - tcal.init_temp * 54) / 1000); else pvtn = 0; if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { tcal.init_cal[ch] = (tcal.init_cal[ch] & 0xfffff000) | (pvtn << 6) | pvtp; } else { tcal.init_cal[ch] = 0x00015000 | (pvtn << 6) | pvtp; } } tcal.init_temp = 125; } } #ifndef ddr_qos_init_setting /* For QoS init */ uint8_t get_boardcnf_phyvalid(void) { return ddr_phyvalid; } #endif /* ddr_qos_init_setting */ trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_b/boot_init_dram_config.c000066400000000000000000001122031355360272700311160ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #define BOARDNUM 22 #define BOARD_JUDGE_AUTO #ifdef BOARD_JUDGE_AUTO static uint32_t _board_judge(void); static uint32_t boardcnf_get_brd_type(void) { return _board_judge(); } #else static uint32_t boardcnf_get_brd_type(void) { return 1; } #endif #define DDR_FAST_INIT struct _boardcnf_ch { uint8_t ddr_density[CS_CNT]; uint64_t ca_swap; uint16_t dqs_swap; uint32_t dq_swap[SLICE_CNT]; uint8_t dm_swap[SLICE_CNT]; uint16_t wdqlvl_patt[16]; int8_t cacs_adj[16]; int8_t dm_adj_w[SLICE_CNT]; int8_t dq_adj_w[SLICE_CNT * 8]; int8_t dm_adj_r[SLICE_CNT]; int8_t dq_adj_r[SLICE_CNT * 8]; }; struct _boardcnf { uint8_t phyvalid; uint8_t dbi_en; uint16_t cacs_dly; int16_t cacs_dly_adj; uint16_t dqdm_dly_w; uint16_t dqdm_dly_r; struct _boardcnf_ch ch[DRAM_CH_CNT]; }; #define WDQLVL_PAT {\ 0x00AA,\ 0x0055,\ 0x00AA,\ 0x0155,\ 0x01CC,\ 0x0133,\ 0x00CC,\ 0x0033,\ 0x00F0,\ 0x010F,\ 0x01F0,\ 0x010F,\ 0x00F0,\ 0x00F0,\ 0x000F,\ 0x010F} static const struct _boardcnf boardcnfs[BOARDNUM] = { { /* boardcnf[0] RENESAS SALVATOR-X board with M3-W/SIP */ .phyvalid = 0x03, .dbi_en = 0x01, .cacs_dly = 0x02c0, .cacs_dly_adj = 0, .dqdm_dly_w = 0x0300, .dqdm_dly_r = 0x00a0, .ch = { { {0x02, 0x02}, 0x00543210U, 0x3201U, {0x70612543, 0x43251670, 0x45326170, 0x10672534}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0x02}, 0x00543210, 0x2310, {0x01327654, 0x34526107, 0x35421670, 0x70615324}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[1] RENESAS KRIEK board with M3-W/SoC */ { 0x03, 0x01, 0x2c0, 0, 0x300, 0x0a0, { { {0x02, 0x02}, 0x00345201, 0x3201, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0x02}, 0x00302154, 0x2310, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[2] RENESAS SALVATOR-X board with H3 Ver.1.x/SIP(8Gbit 1rank) */ { 0x0f, 0x00, 0x300, -320, 0x300, 0x0a0, { { {0x02, 0xff}, 0x00543210, 0x3210, {0x20741365, 0x34256107, 0x57460321, 0x70614532}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0xff}, 0x00543210, 0x3102, {0x23547610, 0x34526107, 0x67452310, 0x32106754}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0xff}, 0x00543210, 0x0213, {0x30216754, 0x67453210, 0x70165243, 0x07162345}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0xff}, 0x00543210, 0x0213, {0x01327654, 0x70615432, 0x54760123, 0x07162345}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[3] RENESAS Starter Kit board with M3-W/SIP(8Gbit 1rank) */ { 0x03, 0x01, 0x02c0, 0, 0x0300, 0x00a0, { { {0x02, 0xFF}, 0x00543210U, 0x3201, {0x70612543, 0x43251670, 0x45326170, 0x10672534}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0xFF}, 0x00543210, 0x2310, {0x01327654, 0x34526107, 0x35421670, 0x70615324}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[4] RENESAS SALVATOR-M(1rank) board with H3 Ver.1.x/SoC */ { 0x0f, 0x00, 0x2c0, -320, 0x300, 0x0a0, { { {0x02, 0xff}, 0x00315024, 0x3120, {0x30671254, 0x26541037, 0x17054623, 0x12307645}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0xff}, 0x00025143, 0x3210, {0x70613542, 0x16245307, 0x30712645, 0x21706354}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0xff}, 0x00523104, 0x2301, {0x70613542, 0x16245307, 0x30712645, 0x21706354}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0xff}, 0x00153402, 0x2031, {0x30671254, 0x26541037, 0x17054623, 0x12307645}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[5] RENESAS KRIEK-1rank board with M3-W/SoC */ { 0x03, 0x01, 0x2c0, 0, 0x300, 0x0a0, { { {0x02, 0xff}, 0x00345201, 0x3201, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0xff}, 0x00302154, 0x2310, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[6] RENESAS SALVATOR-X board with H3 Ver.1.x/SIP(8Gbit 2rank) */ { 0x0f, 0x00, 0x300, -320, 0x300, 0x0a0, { { {0x02, 0x02}, 0x00543210, 0x3210, {0x20741365, 0x34256107, 0x57460321, 0x70614532}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0x02}, 0x00543210, 0x3102, {0x23547610, 0x34526107, 0x67452310, 0x32106754}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0x02}, 0x00543210, 0x0213, {0x30216754, 0x67453210, 0x70165243, 0x07162345}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0x02}, 0x00543210, 0x0213, {0x01327654, 0x70615432, 0x54760123, 0x07162345}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* * boardcnf[7] RENESAS SALVATOR-X board with * H3 Ver.2.0 or later/SIP(8Gbit 1rank) */ { 0x0f, 0x01, 0x300, 0, 0x300, 0x0a0, { { {0x02, 0xff}, 0x00543210, 0x2310, {0x70631425, 0x34527016, 0x43527610, 0x32104567}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0xff}, 0x00105432, 0x3210, {0x43256107, 0x07162354, 0x10234567, 0x01235467}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0xff}, 0x00543210, 0x2301, {0x01327654, 0x02316457, 0x10234567, 0x01325467}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0xff}, 0x00543210, 0x2301, {0x12034765, 0x23105467, 0x23017645, 0x32106745}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* * boardcnf[8] RENESAS SALVATOR-X board with * H3 Ver.2.0 or later/SIP(8Gbit 2rank) */ { #if RCAR_DRAM_CHANNEL == 5 0x05, #else 0x0f, #endif 0x01, 0x300, 0, 0x300, 0x0a0, { { {0x02, 0x02}, 0x00543210, 0x2310, {0x70631425, 0x34527016, 0x43527610, 0x32104567}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, #if ((RCAR_DRAM_CHANNEL == 5) && (RCAR_DRAM_SPLIT == 2)) { {0x02, 0x02}, 0x00543210, 0x2301, {0x01327654, 0x02316457, 0x10234567, 0x01325467}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, #else { {0x02, 0x02}, 0x00105432, 0x3210, {0x43256107, 0x07162354, 0x10234567, 0x01235467}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, #endif { {0x02, 0x02}, 0x00543210, 0x2301, {0x01327654, 0x02316457, 0x10234567, 0x01325467}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0x02}, 0x00543210, 0x2301, {0x12034765, 0x23105467, 0x23017645, 0x32106745}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[9] RENESAS SALVATOR-MS(1rank) board with H3 Ver.2.0 or later/SoC */ { 0x0f, 0x01, 0x300, 0, 0x300, 0x0a0, { { {0x02, 0xff}, 0x00543210, 0x3210, {0x27645310, 0x75346210, 0x53467210, 0x23674510}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0xff}, 0x00543210, 0x2301, {0x23764510, 0x43257610, 0x43752610, 0x37652401}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {-128, -128, -128, -128, -128, -128, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0xff}, 0x00452103, 0x3210, {0x32764510, 0x43257610, 0x43752610, 0x26573401}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0xff}, 0x00520413, 0x2301, {0x47652301, 0x75346210, 0x53467210, 0x32674501}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[10] RENESAS Kriek(2rank) board with M3-N/SoC */ { 0x01, 0x01, 0x300, 0, 0x300, 0x0a0, { { {0x02, 0x02}, 0x00345201, 0x3201, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[11] RENESAS SALVATOR-X board with M3-N/SIP(8Gbit 2rank) */ { 0x01, 0x01, 0x300, 0, 0x300, 0x0a0, { { #if (RCAR_DRAM_LPDDR4_MEMCONF == 2) {0x04, 0x04}, #else {0x02, 0x02}, #endif 0x00342501, 0x3201, {0x10672534, 0x43257106, 0x34527601, 0x71605243}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[12] RENESAS CONDOR board with V3H/SoC */ { 0x01, 0x1, 0x300, 0, 0x300, 0x0a0, { { {0x02, 0x02}, 0x00501342, 0x3201, {0x70562134, 0x34526071, 0x23147506, 0x12430567}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[13] RENESAS KRIEK board with PM3/SoC */ { 0x05, 0x00, 0x2c0, -320, 0x300, 0x0a0, { { {0x02, 0x02}, 0x00345201, 0x3201, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0x02}, 0x00302154, 0x2310, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0x02}, 0x00302154, 0x2310, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0xff, 0xff}, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[14] SALVATOR-X board with H3 Ver.2.0 or later/SIP(16Gbit 1rank) */ { #if RCAR_DRAM_CHANNEL == 5 0x05, #else 0x0f, #endif 0x01, 0x300, 0, 0x300, 0x0a0, { { {0x04, 0xff}, 0x00543210, 0x2310, {0x70631425, 0x34527016, 0x43527610, 0x32104567}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, #if ((RCAR_DRAM_CHANNEL == 5) && (RCAR_DRAM_SPLIT == 2)) { {0x04, 0xff}, 0x00543210, 0x2301, {0x01327654, 0x02316457, 0x10234567, 0x01325467}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, #else { {0x04, 0xff}, 0x00105432, 0x3210, {0x43256107, 0x07162354, 0x10234567, 0x01235467}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, #endif { {0x04, 0xff}, 0x00543210, 0x2301, {0x01327654, 0x02316457, 0x10234567, 0x01325467}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x04, 0xff}, 0x00543210, 0x2301, {0x12034765, 0x23105467, 0x23017645, 0x32106745}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[15] RENESAS KRIEK board with H3N */ { 0x05, 0x01, 0x300, 0, 0x300, 0x0a0, { { {0x02, 0x02}, 0x00345201, 0x3201, {0x01672543, 0x45367012, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0x02}, 0x00302154, 0x2310, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x02, 0x02}, 0x00302154, 0x2310, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0xff, 0xff}, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[16] RENESAS KRIEK-P2P board with M3-W/SoC */ { 0x03, 0x01, 0x0320, 0, 0x0300, 0x00a0, { { {0x04, 0x04}, 0x520314FFFF523041, 0x3201, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x04, 0x04}, 0x314250FFFF312405, 0x2310, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[17] RENESAS KRIEK-P2P board with M3-N/SoC */ { 0x01, 0x01, 0x0300, 0, 0x0300, 0x00a0, { { {0x04, 0x04}, 0x520314FFFF523041, 0x3201, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[18] RENESAS SALVATOR-X board with M3-W/SIP(16Gbit 2rank) */ { 0x03, 0x01, 0x02c0, 0, 0x0300, 0x00a0, { { {0x04, 0x04}, 0x00543210, 0x3201, {0x70612543, 0x43251670, 0x45326170, 0x10672534}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x04, 0x04}, 0x00543210, 0x2310, {0x01327654, 0x34526107, 0x35421670, 0x70615324}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[19] RENESAS SALVATOR-X board with M3-W/SIP(16Gbit 1rank) */ { 0x03, 0x01, 0x02c0, 0, 0x0300, 0x00a0, { { {0x04, 0xff}, 0x00543210, 0x3201, {0x70612543, 0x43251670, 0x45326170, 0x10672534}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x04, 0xff}, 0x00543210, 0x2310, {0x01327654, 0x34526107, 0x35421670, 0x70615324}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[20] RENESAS KRIEK 16Gbit/2rank/2ch board with M3-W/SoC */ { 0x03, 0x01, 0x02c0, 0, 0x0300, 0x00a0, { { {0x04, 0x04}, 0x00345201, 0x3201, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x04, 0x04}, 0x00302154, 0x2310, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } }, /* boardcnf[21] RENESAS KRIEK 16Gbit/1rank/2ch board with M3-W/SoC */ { 0x03, 0x01, 0x02c0, 0, 0x0300, 0x00a0, { { {0x04, 0xff}, 0x00345201, 0x3201, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, { {0x04, 0xff}, 0x00302154, 0x2310, {0x01672543, 0x45361207, 0x45632107, 0x60715234}, {0x08, 0x08, 0x08, 0x08}, WDQLVL_PAT, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} } } } }; void boardcnf_get_brd_clk(uint32_t brd, uint32_t *clk, uint32_t *div) { uint32_t md; if ((prr_product == PRR_PRODUCT_H3) && (prr_cut == PRR_PRODUCT_10)) { *clk = 50; *div = 3; } else { md = (mmio_read_32(RST_MODEMR) >> 13) & 0x3; switch (md) { case 0x0: *clk = 50; *div = 3; break; case 0x1: *clk = 60; *div = 3; break; case 0x2: *clk = 75; *div = 3; break; case 0x3: *clk = 100; *div = 3; break; } } (void)brd; } void boardcnf_get_ddr_mbps(uint32_t brd, uint32_t *mbps, uint32_t *div) { uint32_t md; md = (mmio_read_32(RST_MODEMR) >> 17) & 0x5; md = (md | (md >> 1)) & 0x3; switch (md) { case 0x0: *mbps = 3200; *div = 1; break; case 0x1: *mbps = 2800; *div = 1; break; case 0x2: *mbps = 2400; *div = 1; break; case 0x3: *mbps = 1600; *div = 1; break; } (void)brd; } #define _def_REFPERIOD 1890 #define M3_SAMPLE_TT_A84 0xB866CC10, 0x3B250421 #define M3_SAMPLE_TT_A85 0xB866CC10, 0x3AA50421 #define M3_SAMPLE_TT_A86 0xB866CC10, 0x3AA48421 #define M3_SAMPLE_FF_B45 0xB866CC10, 0x3AB00C21 #define M3_SAMPLE_FF_B49 0xB866CC10, 0x39B10C21 #define M3_SAMPLE_FF_B56 0xB866CC10, 0x3AAF8C21 #define M3_SAMPLE_SS_E24 0xB866CC10, 0x3BA39421 #define M3_SAMPLE_SS_E28 0xB866CC10, 0x3C231421 #define M3_SAMPLE_SS_E32 0xB866CC10, 0x3C241421 static const uint32_t termcode_by_sample[20][3] = { {M3_SAMPLE_TT_A84, 0x000158D5}, {M3_SAMPLE_TT_A85, 0x00015955}, {M3_SAMPLE_TT_A86, 0x00015955}, {M3_SAMPLE_FF_B45, 0x00015690}, {M3_SAMPLE_FF_B49, 0x00015753}, {M3_SAMPLE_FF_B56, 0x00015793}, {M3_SAMPLE_SS_E24, 0x00015996}, {M3_SAMPLE_SS_E28, 0x000159D7}, {M3_SAMPLE_SS_E32, 0x00015997}, {0xFFFFFFFF, 0xFFFFFFFF, 0x0001554F} }; #ifdef BOARD_JUDGE_AUTO /* * SAMPLE board detect function */ #define PFC_PMMR 0xE6060000U #define PFC_PUEN5 0xE6060414U #define PFC_PUEN6 0xE6060418U #define PFC_PUD5 0xE6060454U #define PFC_PUD6 0xE6060458U #define GPIO_INDT5 0xE605500CU #define GPIO_GPSR6 0xE6060118U #if (RCAR_GEN3_ULCB == 0) static void pfc_write_and_poll(uint32_t a, uint32_t v) { mmio_write_32(PFC_PMMR, ~v); v = ~mmio_read_32(PFC_PMMR); mmio_write_32(a, v); while (v != mmio_read_32(a)) ; dsb_sev(); } #endif #ifndef RCAR_GEN3_ULCB #define RCAR_GEN3_ULCB 0 #endif #if (RCAR_GEN3_ULCB == 0) /* non Starter Kit */ static uint32_t opencheck_SSI_WS6(void) { uint32_t dataL, down, up; uint32_t gpsr6_bak; uint32_t puen5_bak; uint32_t pud5_bak; gpsr6_bak = mmio_read_32(GPIO_GPSR6); puen5_bak = mmio_read_32(PFC_PUEN5); pud5_bak = mmio_read_32(PFC_PUD5); dsb_sev(); dataL = (gpsr6_bak & ~BIT(15)); pfc_write_and_poll(GPIO_GPSR6, dataL); /* Pull-Up/Down Enable (PUEN5[22]=1) */ dataL = puen5_bak; dataL |= (BIT(22)); pfc_write_and_poll(PFC_PUEN5, dataL); /* Pull-Down-Enable (PUD5[22]=0, PUEN5[22]=1) */ dataL = pud5_bak; dataL &= ~(BIT(22)); pfc_write_and_poll(PFC_PUD5, dataL); /* GPSR6[15]=SSI_WS6 */ rcar_micro_delay(10); down = (mmio_read_32(GPIO_INDT6) >> 15) & 0x1; dsb_sev(); /* Pull-Up-Enable (PUD5[22]=1, PUEN5[22]=1) */ dataL = pud5_bak; dataL |= (BIT(22)); pfc_write_and_poll(PFC_PUD5, dataL); /* GPSR6[15]=SSI_WS6 */ rcar_micro_delay(10); up = (mmio_read_32(GPIO_INDT6) >> 15) & 0x1; dsb_sev(); pfc_write_and_poll(GPIO_GPSR6, gpsr6_bak); pfc_write_and_poll(PFC_PUEN5, puen5_bak); pfc_write_and_poll(PFC_PUD5, pud5_bak); if (down == up) { /* Same = Connect */ return 0; } /* Diff = Open */ return 1; } #endif static uint32_t _board_judge(void) { uint32_t brd; #if (RCAR_GEN3_ULCB == 1) /* Starter Kit */ if (prr_product == PRR_PRODUCT_H3) { if (prr_cut <= PRR_PRODUCT_11) { /* RENESAS Starter Kit(H3 Ver.1.x/SIP) board */ brd = 2; } else { /* RENESAS Starter Kit(H3 Ver.2.0 or later/SIP) board */ #if (RCAR_DRAM_LPDDR4_MEMCONF == 0) brd = 7; #else brd = 8; #endif } } else if (prr_product == PRR_PRODUCT_M3) { /* RENESAS Starter Kit(M3-W/SIP 8Gbit 1rank) board */ brd = 3; } else { /* RENESAS Starter Kit(M3-N/SIP) board */ brd = 11; } #else uint32_t usb2_ovc_open; usb2_ovc_open = opencheck_SSI_WS6(); /* RENESAS Eva-board */ brd = 99; if (prr_product == PRR_PRODUCT_V3H) { /* RENESAS Condor board */ brd = 12; } else if (usb2_ovc_open) { if (prr_product == PRR_PRODUCT_M3N) { /* RENESAS Kriek board with M3-N */ brd = 10; } else if (prr_product == PRR_PRODUCT_M3) { /* RENESAS Kriek board with M3-W */ brd = 1; } else if ((prr_product == PRR_PRODUCT_H3) && (prr_cut <= PRR_PRODUCT_11)) { /* RENESAS Kriek board with PM3 */ brd = 13; } else if ((prr_product == PRR_PRODUCT_H3) && (prr_cut > PRR_PRODUCT_20)) { /* RENESAS Kriek board with H3N */ brd = 15; } } else { if (prr_product == PRR_PRODUCT_H3) { if (prr_cut <= PRR_PRODUCT_11) { /* RENESAS SALVATOR-X (H3 Ver.1.x/SIP) */ brd = 2; } else if (prr_cut < PRR_PRODUCT_30) { /* RENESAS SALVATOR-X (H3 Ver.2.0/SIP) */ brd = 7; // 8Gbit/1rank } else { /* RENESAS SALVATOR-X (H3 Ver.3.0/SIP) */ #if (RCAR_DRAM_LPDDR4_MEMCONF == 0) brd = 7; #else brd = 8; #endif } } else if (prr_product == PRR_PRODUCT_M3N) { /* RENESAS SALVATOR-X (M3-N/SIP) */ brd = 11; } else if ((prr_product == PRR_PRODUCT_M3) && (prr_cut <= PRR_PRODUCT_20)) { /* RENESAS SALVATOR-X (M3-W/SIP) */ brd = 0; } else if ((prr_product == PRR_PRODUCT_M3) && (prr_cut < PRR_PRODUCT_30)) { /* RENESAS SALVATOR-X (M3-W Ver.1.x/SIP) */ brd = 19; } else if ((prr_product == PRR_PRODUCT_M3) && (prr_cut >= PRR_PRODUCT_30)) { /* RENESAS SALVATOR-X (M3-W ver.3.0/SIP) */ brd = 18; } } #endif return brd; } #endif trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_b/boot_init_dram_regdef.h000066400000000000000000000055121355360272700311160ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #define RCAR_DDR_VERSION "rev.0.37" #define DRAM_CH_CNT 0x04 #define SLICE_CNT 0x04 #define CS_CNT 0x02 /* order : CS0A, CS0B, CS1A, CS1B */ #define CSAB_CNT (CS_CNT * 2) /* order : CH0A, CH0B, CH1A, CH1B, CH2A, CH2B, CH3A, CH3B */ #define CHAB_CNT (DRAM_CH_CNT * 2) /* pll setting */ #define CLK_DIV(a, diva, b, divb) (((a) * (divb)) / ((b) * (diva))) #define CLK_MUL(a, diva, b, divb) (((a) * (b)) / ((diva) * (divb))) /* for ddr deisity setting */ #define DBMEMCONF_REG(d3, row, bank, col, dw) \ ((d3) << 30 | ((row) << 24) | ((bank) << 16) | ((col) << 8) | (dw)) #define DBMEMCONF_REGD(density) \ (DBMEMCONF_REG((density) % 2, ((density) + 1) / \ 2 + (29 - 3 - 10 - 2), 3, 10, 2)) #define DBMEMCONF_VAL(ch, cs) (DBMEMCONF_REGD(DBMEMCONF_DENS(ch, cs))) /* refresh mode */ #define DBSC_REFINTS (0x0) /* system registers */ #define CPG_FRQCRB (CPG_BASE + 0x0004U) #define CPG_PLLECR (CPG_BASE + 0x00D0U) #define CPG_MSTPSR5 (CPG_BASE + 0x003CU) #define CPG_SRCR4 (CPG_BASE + 0x00BCU) #define CPG_PLL3CR (CPG_BASE + 0x00DCU) #define CPG_ZB3CKCR (CPG_BASE + 0x0380U) #define CPG_FRQCRD (CPG_BASE + 0x00E4U) #define CPG_SMSTPCR5 (CPG_BASE + 0x0144U) #define CPG_CPGWPR (CPG_BASE + 0x0900U) #define CPG_SRSTCLR4 (CPG_BASE + 0x0950U) #define CPG_FRQCRB_KICK_BIT BIT(31) #define CPG_PLLECR_PLL3E_BIT BIT(3) #define CPG_PLLECR_PLL3ST_BIT BIT(11) #define CPG_ZB3CKCR_ZB3ST_BIT BIT(11) #define RST_BASE (0xE6160000U) #define RST_MODEMR (RST_BASE + 0x0060U) #define LIFEC_CHIPID(x) (0xE6110040U + 0x04U * (x)) /* DBSC registers */ #include "../ddr_regs.h" #define DBSC_DBMONCONF4 0xE6793010U #define DBSC_PLL_LOCK(ch) (0xE6794054U + 0x100U * (ch)) #define DBSC_PLL_LOCK_0 0xE6794054U #define DBSC_PLL_LOCK_1 0xE6794154U #define DBSC_PLL_LOCK_2 0xE6794254U #define DBSC_PLL_LOCK_3 0xE6794354U /* STAT registers */ #define MSTAT_SL_INIT 0xE67E8000U #define MSTAT_REF_ARS 0xE67E8004U #define MSTATQ_STATQC 0xE67E8008U #define MSTATQ_WTENABLE 0xE67E8030U #define MSTATQ_WTREFRESH 0xE67E8034U #define MSTATQ_WTSETTING0 0xE67E8038U #define MSTATQ_WTSETTING1 0xE67E803CU #define QOS_BASE1 (0xE67F0000U) #define QOSCTRL_RAS (QOS_BASE1 + 0x0000U) #define QOSCTRL_FIXTH (QOS_BASE1 + 0x0004U) #define QOSCTRL_RAEN (QOS_BASE1 + 0x0018U) #define QOSCTRL_REGGD (QOS_BASE1 + 0x0020U) #define QOSCTRL_DANN (QOS_BASE1 + 0x0030U) #define QOSCTRL_DANT (QOS_BASE1 + 0x0038U) #define QOSCTRL_EC (QOS_BASE1 + 0x003CU) #define QOSCTRL_EMS (QOS_BASE1 + 0x0040U) #define QOSCTRL_INSFC (QOS_BASE1 + 0x0050U) #define QOSCTRL_BERR (QOS_BASE1 + 0x0054U) #define QOSCTRL_RACNT0 (QOS_BASE1 + 0x0080U) #define QOSCTRL_STATGEN0 (QOS_BASE1 + 0x0088U) /* other module */ #define THS1_THCTR 0xE6198020U #define THS1_TEMP 0xE6198028U trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_b/ddr_b.mk000066400000000000000000000003071355360272700260400ustar00rootroot00000000000000# # Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # BL2_SOURCES += drivers/staging/renesas/rcar/ddr/ddr_b/boot_init_dram.c trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_b/ddr_regdef.h000066400000000000000000005550161355360272700267070ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Renesas Electronics Corporation. * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #define _reg_PHY_DQ_DM_SWIZZLE0 0x00000000U #define _reg_PHY_DQ_DM_SWIZZLE1 0x00000001U #define _reg_PHY_CLK_WR_BYPASS_SLAVE_DELAY 0x00000002U #define _reg_PHY_RDDQS_GATE_BYPASS_SLAVE_DELAY 0x00000003U #define _reg_PHY_BYPASS_TWO_CYC_PREAMBLE 0x00000004U #define _reg_PHY_CLK_BYPASS_OVERRIDE 0x00000005U #define _reg_PHY_SW_WRDQ0_SHIFT 0x00000006U #define _reg_PHY_SW_WRDQ1_SHIFT 0x00000007U #define _reg_PHY_SW_WRDQ2_SHIFT 0x00000008U #define _reg_PHY_SW_WRDQ3_SHIFT 0x00000009U #define _reg_PHY_SW_WRDQ4_SHIFT 0x0000000aU #define _reg_PHY_SW_WRDQ5_SHIFT 0x0000000bU #define _reg_PHY_SW_WRDQ6_SHIFT 0x0000000cU #define _reg_PHY_SW_WRDQ7_SHIFT 0x0000000dU #define _reg_PHY_SW_WRDM_SHIFT 0x0000000eU #define _reg_PHY_SW_WRDQS_SHIFT 0x0000000fU #define _reg_PHY_DQ_TSEL_ENABLE 0x00000010U #define _reg_PHY_DQ_TSEL_SELECT 0x00000011U #define _reg_PHY_DQS_TSEL_ENABLE 0x00000012U #define _reg_PHY_DQS_TSEL_SELECT 0x00000013U #define _reg_PHY_TWO_CYC_PREAMBLE 0x00000014U #define _reg_PHY_DBI_MODE 0x00000015U #define _reg_PHY_PER_RANK_CS_MAP 0x00000016U #define _reg_PHY_PER_CS_TRAINING_MULTICAST_EN 0x00000017U #define _reg_PHY_PER_CS_TRAINING_INDEX 0x00000018U #define _reg_PHY_LP4_BOOT_RDDATA_EN_IE_DLY 0x00000019U #define _reg_PHY_LP4_BOOT_RDDATA_EN_DLY 0x0000001aU #define _reg_PHY_LP4_BOOT_RDDATA_EN_TSEL_DLY 0x0000001bU #define _reg_PHY_LP4_BOOT_RPTR_UPDATE 0x0000001cU #define _reg_PHY_LP4_BOOT_RDDQS_GATE_SLAVE_DELAY 0x0000001dU #define _reg_PHY_LP4_BOOT_RDDQS_LATENCY_ADJUST 0x0000001eU #define _reg_PHY_LP4_BOOT_WRPATH_GATE_DISABLE 0x0000001fU #define _reg_PHY_LP4_BOOT_RDDATA_EN_OE_DLY 0x00000020U #define _reg_PHY_LPBK_CONTROL 0x00000021U #define _reg_PHY_LPBK_DFX_TIMEOUT_EN 0x00000022U #define _reg_PHY_AUTO_TIMING_MARGIN_CONTROL 0x00000023U #define _reg_PHY_AUTO_TIMING_MARGIN_OBS 0x00000024U #define _reg_PHY_SLICE_PWR_RDC_DISABLE 0x00000025U #define _reg_PHY_PRBS_PATTERN_START 0x00000026U #define _reg_PHY_PRBS_PATTERN_MASK 0x00000027U #define _reg_PHY_RDDQS_DQ_BYPASS_SLAVE_DELAY 0x00000028U #define _reg_PHY_GATE_ERROR_DELAY_SELECT 0x00000029U #define _reg_SC_PHY_SNAP_OBS_REGS 0x0000002aU #define _reg_PHY_LPDDR 0x0000002bU #define _reg_PHY_LPDDR_TYPE 0x0000002cU #define _reg_PHY_GATE_SMPL1_SLAVE_DELAY 0x0000002dU #define _reg_PHY_GATE_SMPL2_SLAVE_DELAY 0x0000002eU #define _reg_ON_FLY_GATE_ADJUST_EN 0x0000002fU #define _reg_PHY_GATE_TRACKING_OBS 0x00000030U #define _reg_PHY_DFI40_POLARITY 0x00000031U #define _reg_PHY_LP4_PST_AMBLE 0x00000032U #define _reg_PHY_RDLVL_PATT8 0x00000033U #define _reg_PHY_RDLVL_PATT9 0x00000034U #define _reg_PHY_RDLVL_PATT10 0x00000035U #define _reg_PHY_RDLVL_PATT11 0x00000036U #define _reg_PHY_LP4_RDLVL_PATT8 0x00000037U #define _reg_PHY_LP4_RDLVL_PATT9 0x00000038U #define _reg_PHY_LP4_RDLVL_PATT10 0x00000039U #define _reg_PHY_LP4_RDLVL_PATT11 0x0000003aU #define _reg_PHY_SLAVE_LOOP_CNT_UPDATE 0x0000003bU #define _reg_PHY_SW_FIFO_PTR_RST_DISABLE 0x0000003cU #define _reg_PHY_MASTER_DLY_LOCK_OBS_SELECT 0x0000003dU #define _reg_PHY_RDDQ_ENC_OBS_SELECT 0x0000003eU #define _reg_PHY_RDDQS_DQ_ENC_OBS_SELECT 0x0000003fU #define _reg_PHY_WR_ENC_OBS_SELECT 0x00000040U #define _reg_PHY_WR_SHIFT_OBS_SELECT 0x00000041U #define _reg_PHY_FIFO_PTR_OBS_SELECT 0x00000042U #define _reg_PHY_LVL_DEBUG_MODE 0x00000043U #define _reg_SC_PHY_LVL_DEBUG_CONT 0x00000044U #define _reg_PHY_WRLVL_CAPTURE_CNT 0x00000045U #define _reg_PHY_WRLVL_UPDT_WAIT_CNT 0x00000046U #define _reg_PHY_WRLVL_DQ_MASK 0x00000047U #define _reg_PHY_GTLVL_CAPTURE_CNT 0x00000048U #define _reg_PHY_GTLVL_UPDT_WAIT_CNT 0x00000049U #define _reg_PHY_RDLVL_CAPTURE_CNT 0x0000004aU #define _reg_PHY_RDLVL_UPDT_WAIT_CNT 0x0000004bU #define _reg_PHY_RDLVL_OP_MODE 0x0000004cU #define _reg_PHY_RDLVL_RDDQS_DQ_OBS_SELECT 0x0000004dU #define _reg_PHY_RDLVL_DATA_MASK 0x0000004eU #define _reg_PHY_RDLVL_DATA_SWIZZLE 0x0000004fU #define _reg_PHY_WDQLVL_BURST_CNT 0x00000050U #define _reg_PHY_WDQLVL_PATT 0x00000051U #define _reg_PHY_WDQLVL_DQDM_SLV_DLY_JUMP_OFFSET 0x00000052U #define _reg_PHY_WDQLVL_UPDT_WAIT_CNT 0x00000053U #define _reg_PHY_WDQLVL_DQDM_OBS_SELECT 0x00000054U #define _reg_PHY_WDQLVL_QTR_DLY_STEP 0x00000055U #define _reg_SC_PHY_WDQLVL_CLR_PREV_RESULTS 0x00000056U #define _reg_PHY_WDQLVL_CLR_PREV_RESULTS 0x00000057U #define _reg_PHY_WDQLVL_DATADM_MASK 0x00000058U #define _reg_PHY_USER_PATT0 0x00000059U #define _reg_PHY_USER_PATT1 0x0000005aU #define _reg_PHY_USER_PATT2 0x0000005bU #define _reg_PHY_USER_PATT3 0x0000005cU #define _reg_PHY_USER_PATT4 0x0000005dU #define _reg_PHY_DQ_SWIZZLING 0x0000005eU #define _reg_PHY_CALVL_VREF_DRIVING_SLICE 0x0000005fU #define _reg_SC_PHY_MANUAL_CLEAR 0x00000060U #define _reg_PHY_FIFO_PTR_OBS 0x00000061U #define _reg_PHY_LPBK_RESULT_OBS 0x00000062U #define _reg_PHY_LPBK_ERROR_COUNT_OBS 0x00000063U #define _reg_PHY_MASTER_DLY_LOCK_OBS 0x00000064U #define _reg_PHY_RDDQ_SLV_DLY_ENC_OBS 0x00000065U #define _reg_PHY_RDDQS_BASE_SLV_DLY_ENC_OBS 0x00000066U #define _reg_PHY_RDDQS_DQ_RISE_ADDER_SLV_DLY_ENC_OBS 0x00000067U #define _reg_PHY_RDDQS_DQ_FALL_ADDER_SLV_DLY_ENC_OBS 0x00000068U #define _reg_PHY_RDDQS_GATE_SLV_DLY_ENC_OBS 0x00000069U #define _reg_PHY_WRDQS_BASE_SLV_DLY_ENC_OBS 0x0000006aU #define _reg_PHY_WRDQ_BASE_SLV_DLY_ENC_OBS 0x0000006bU #define _reg_PHY_WR_ADDER_SLV_DLY_ENC_OBS 0x0000006cU #define _reg_PHY_WR_SHIFT_OBS 0x0000006dU #define _reg_PHY_WRLVL_HARD0_DELAY_OBS 0x0000006eU #define _reg_PHY_WRLVL_HARD1_DELAY_OBS 0x0000006fU #define _reg_PHY_WRLVL_STATUS_OBS 0x00000070U #define _reg_PHY_GATE_SMPL1_SLV_DLY_ENC_OBS 0x00000071U #define _reg_PHY_GATE_SMPL2_SLV_DLY_ENC_OBS 0x00000072U #define _reg_PHY_WRLVL_ERROR_OBS 0x00000073U #define _reg_PHY_GTLVL_HARD0_DELAY_OBS 0x00000074U #define _reg_PHY_GTLVL_HARD1_DELAY_OBS 0x00000075U #define _reg_PHY_GTLVL_STATUS_OBS 0x00000076U #define _reg_PHY_RDLVL_RDDQS_DQ_LE_DLY_OBS 0x00000077U #define _reg_PHY_RDLVL_RDDQS_DQ_TE_DLY_OBS 0x00000078U #define _reg_PHY_RDLVL_RDDQS_DQ_NUM_WINDOWS_OBS 0x00000079U #define _reg_PHY_RDLVL_STATUS_OBS 0x0000007aU #define _reg_PHY_WDQLVL_DQDM_LE_DLY_OBS 0x0000007bU #define _reg_PHY_WDQLVL_DQDM_TE_DLY_OBS 0x0000007cU #define _reg_PHY_WDQLVL_STATUS_OBS 0x0000007dU #define _reg_PHY_DDL_MODE 0x0000007eU #define _reg_PHY_DDL_TEST_OBS 0x0000007fU #define _reg_PHY_DDL_TEST_MSTR_DLY_OBS 0x00000080U #define _reg_PHY_DDL_TRACK_UPD_THRESHOLD 0x00000081U #define _reg_PHY_LP4_WDQS_OE_EXTEND 0x00000082U #define _reg_SC_PHY_RX_CAL_START 0x00000083U #define _reg_PHY_RX_CAL_OVERRIDE 0x00000084U #define _reg_PHY_RX_CAL_SAMPLE_WAIT 0x00000085U #define _reg_PHY_RX_CAL_DQ0 0x00000086U #define _reg_PHY_RX_CAL_DQ1 0x00000087U #define _reg_PHY_RX_CAL_DQ2 0x00000088U #define _reg_PHY_RX_CAL_DQ3 0x00000089U #define _reg_PHY_RX_CAL_DQ4 0x0000008aU #define _reg_PHY_RX_CAL_DQ5 0x0000008bU #define _reg_PHY_RX_CAL_DQ6 0x0000008cU #define _reg_PHY_RX_CAL_DQ7 0x0000008dU #define _reg_PHY_RX_CAL_DM 0x0000008eU #define _reg_PHY_RX_CAL_DQS 0x0000008fU #define _reg_PHY_RX_CAL_FDBK 0x00000090U #define _reg_PHY_RX_CAL_OBS 0x00000091U #define _reg_PHY_RX_CAL_LOCK_OBS 0x00000092U #define _reg_PHY_RX_CAL_DISABLE 0x00000093U #define _reg_PHY_CLK_WRDQ0_SLAVE_DELAY 0x00000094U #define _reg_PHY_CLK_WRDQ1_SLAVE_DELAY 0x00000095U #define _reg_PHY_CLK_WRDQ2_SLAVE_DELAY 0x00000096U #define _reg_PHY_CLK_WRDQ3_SLAVE_DELAY 0x00000097U #define _reg_PHY_CLK_WRDQ4_SLAVE_DELAY 0x00000098U #define _reg_PHY_CLK_WRDQ5_SLAVE_DELAY 0x00000099U #define _reg_PHY_CLK_WRDQ6_SLAVE_DELAY 0x0000009aU #define _reg_PHY_CLK_WRDQ7_SLAVE_DELAY 0x0000009bU #define _reg_PHY_CLK_WRDM_SLAVE_DELAY 0x0000009cU #define _reg_PHY_CLK_WRDQS_SLAVE_DELAY 0x0000009dU #define _reg_PHY_WRLVL_THRESHOLD_ADJUST 0x0000009eU #define _reg_PHY_RDDQ0_SLAVE_DELAY 0x0000009fU #define _reg_PHY_RDDQ1_SLAVE_DELAY 0x000000a0U #define _reg_PHY_RDDQ2_SLAVE_DELAY 0x000000a1U #define _reg_PHY_RDDQ3_SLAVE_DELAY 0x000000a2U #define _reg_PHY_RDDQ4_SLAVE_DELAY 0x000000a3U #define _reg_PHY_RDDQ5_SLAVE_DELAY 0x000000a4U #define _reg_PHY_RDDQ6_SLAVE_DELAY 0x000000a5U #define _reg_PHY_RDDQ7_SLAVE_DELAY 0x000000a6U #define _reg_PHY_RDDM_SLAVE_DELAY 0x000000a7U #define _reg_PHY_RDDQS_DQ0_RISE_SLAVE_DELAY 0x000000a8U #define _reg_PHY_RDDQS_DQ0_FALL_SLAVE_DELAY 0x000000a9U #define _reg_PHY_RDDQS_DQ1_RISE_SLAVE_DELAY 0x000000aaU #define _reg_PHY_RDDQS_DQ1_FALL_SLAVE_DELAY 0x000000abU #define _reg_PHY_RDDQS_DQ2_RISE_SLAVE_DELAY 0x000000acU #define _reg_PHY_RDDQS_DQ2_FALL_SLAVE_DELAY 0x000000adU #define _reg_PHY_RDDQS_DQ3_RISE_SLAVE_DELAY 0x000000aeU #define _reg_PHY_RDDQS_DQ3_FALL_SLAVE_DELAY 0x000000afU #define _reg_PHY_RDDQS_DQ4_RISE_SLAVE_DELAY 0x000000b0U #define _reg_PHY_RDDQS_DQ4_FALL_SLAVE_DELAY 0x000000b1U #define _reg_PHY_RDDQS_DQ5_RISE_SLAVE_DELAY 0x000000b2U #define _reg_PHY_RDDQS_DQ5_FALL_SLAVE_DELAY 0x000000b3U #define _reg_PHY_RDDQS_DQ6_RISE_SLAVE_DELAY 0x000000b4U #define _reg_PHY_RDDQS_DQ6_FALL_SLAVE_DELAY 0x000000b5U #define _reg_PHY_RDDQS_DQ7_RISE_SLAVE_DELAY 0x000000b6U #define _reg_PHY_RDDQS_DQ7_FALL_SLAVE_DELAY 0x000000b7U #define _reg_PHY_RDDQS_DM_RISE_SLAVE_DELAY 0x000000b8U #define _reg_PHY_RDDQS_DM_FALL_SLAVE_DELAY 0x000000b9U #define _reg_PHY_RDDQS_GATE_SLAVE_DELAY 0x000000baU #define _reg_PHY_RDDQS_LATENCY_ADJUST 0x000000bbU #define _reg_PHY_WRITE_PATH_LAT_ADD 0x000000bcU #define _reg_PHY_WRLVL_DELAY_EARLY_THRESHOLD 0x000000bdU #define _reg_PHY_WRLVL_DELAY_PERIOD_THRESHOLD 0x000000beU #define _reg_PHY_WRLVL_EARLY_FORCE_ZERO 0x000000bfU #define _reg_PHY_GTLVL_RDDQS_SLV_DLY_START 0x000000c0U #define _reg_PHY_GTLVL_LAT_ADJ_START 0x000000c1U #define _reg_PHY_WDQLVL_DQDM_SLV_DLY_START 0x000000c2U #define _reg_PHY_RDLVL_RDDQS_DQ_SLV_DLY_START 0x000000c3U #define _reg_PHY_FDBK_PWR_CTRL 0x000000c4U #define _reg_PHY_DQ_OE_TIMING 0x000000c5U #define _reg_PHY_DQ_TSEL_RD_TIMING 0x000000c6U #define _reg_PHY_DQ_TSEL_WR_TIMING 0x000000c7U #define _reg_PHY_DQS_OE_TIMING 0x000000c8U #define _reg_PHY_DQS_TSEL_RD_TIMING 0x000000c9U #define _reg_PHY_DQS_OE_RD_TIMING 0x000000caU #define _reg_PHY_DQS_TSEL_WR_TIMING 0x000000cbU #define _reg_PHY_PER_CS_TRAINING_EN 0x000000ccU #define _reg_PHY_DQ_IE_TIMING 0x000000cdU #define _reg_PHY_DQS_IE_TIMING 0x000000ceU #define _reg_PHY_RDDATA_EN_IE_DLY 0x000000cfU #define _reg_PHY_IE_MODE 0x000000d0U #define _reg_PHY_RDDATA_EN_DLY 0x000000d1U #define _reg_PHY_RDDATA_EN_TSEL_DLY 0x000000d2U #define _reg_PHY_RDDATA_EN_OE_DLY 0x000000d3U #define _reg_PHY_SW_MASTER_MODE 0x000000d4U #define _reg_PHY_MASTER_DELAY_START 0x000000d5U #define _reg_PHY_MASTER_DELAY_STEP 0x000000d6U #define _reg_PHY_MASTER_DELAY_WAIT 0x000000d7U #define _reg_PHY_MASTER_DELAY_HALF_MEASURE 0x000000d8U #define _reg_PHY_RPTR_UPDATE 0x000000d9U #define _reg_PHY_WRLVL_DLY_STEP 0x000000daU #define _reg_PHY_WRLVL_RESP_WAIT_CNT 0x000000dbU #define _reg_PHY_GTLVL_DLY_STEP 0x000000dcU #define _reg_PHY_GTLVL_RESP_WAIT_CNT 0x000000ddU #define _reg_PHY_GTLVL_BACK_STEP 0x000000deU #define _reg_PHY_GTLVL_FINAL_STEP 0x000000dfU #define _reg_PHY_WDQLVL_DLY_STEP 0x000000e0U #define _reg_PHY_TOGGLE_PRE_SUPPORT 0x000000e1U #define _reg_PHY_RDLVL_DLY_STEP 0x000000e2U #define _reg_PHY_WRPATH_GATE_DISABLE 0x000000e3U #define _reg_PHY_WRPATH_GATE_TIMING 0x000000e4U #define _reg_PHY_ADR0_SW_WRADDR_SHIFT 0x000000e5U #define _reg_PHY_ADR1_SW_WRADDR_SHIFT 0x000000e6U #define _reg_PHY_ADR2_SW_WRADDR_SHIFT 0x000000e7U #define _reg_PHY_ADR3_SW_WRADDR_SHIFT 0x000000e8U #define _reg_PHY_ADR4_SW_WRADDR_SHIFT 0x000000e9U #define _reg_PHY_ADR5_SW_WRADDR_SHIFT 0x000000eaU #define _reg_PHY_ADR_CLK_WR_BYPASS_SLAVE_DELAY 0x000000ebU #define _reg_PHY_ADR_CLK_BYPASS_OVERRIDE 0x000000ecU #define _reg_SC_PHY_ADR_MANUAL_CLEAR 0x000000edU #define _reg_PHY_ADR_LPBK_RESULT_OBS 0x000000eeU #define _reg_PHY_ADR_LPBK_ERROR_COUNT_OBS 0x000000efU #define _reg_PHY_ADR_MASTER_DLY_LOCK_OBS_SELECT 0x000000f0U #define _reg_PHY_ADR_MASTER_DLY_LOCK_OBS 0x000000f1U #define _reg_PHY_ADR_BASE_SLV_DLY_ENC_OBS 0x000000f2U #define _reg_PHY_ADR_ADDER_SLV_DLY_ENC_OBS 0x000000f3U #define _reg_PHY_ADR_SLAVE_LOOP_CNT_UPDATE 0x000000f4U #define _reg_PHY_ADR_SLV_DLY_ENC_OBS_SELECT 0x000000f5U #define _reg_SC_PHY_ADR_SNAP_OBS_REGS 0x000000f6U #define _reg_PHY_ADR_TSEL_ENABLE 0x000000f7U #define _reg_PHY_ADR_LPBK_CONTROL 0x000000f8U #define _reg_PHY_ADR_PRBS_PATTERN_START 0x000000f9U #define _reg_PHY_ADR_PRBS_PATTERN_MASK 0x000000faU #define _reg_PHY_ADR_PWR_RDC_DISABLE 0x000000fbU #define _reg_PHY_ADR_TYPE 0x000000fcU #define _reg_PHY_ADR_WRADDR_SHIFT_OBS 0x000000fdU #define _reg_PHY_ADR_IE_MODE 0x000000feU #define _reg_PHY_ADR_DDL_MODE 0x000000ffU #define _reg_PHY_ADR_DDL_TEST_OBS 0x00000100U #define _reg_PHY_ADR_DDL_TEST_MSTR_DLY_OBS 0x00000101U #define _reg_PHY_ADR_CALVL_START 0x00000102U #define _reg_PHY_ADR_CALVL_COARSE_DLY 0x00000103U #define _reg_PHY_ADR_CALVL_QTR 0x00000104U #define _reg_PHY_ADR_CALVL_SWIZZLE0 0x00000105U #define _reg_PHY_ADR_CALVL_SWIZZLE1 0x00000106U #define _reg_PHY_ADR_CALVL_SWIZZLE0_0 0x00000107U #define _reg_PHY_ADR_CALVL_SWIZZLE1_0 0x00000108U #define _reg_PHY_ADR_CALVL_SWIZZLE0_1 0x00000109U #define _reg_PHY_ADR_CALVL_SWIZZLE1_1 0x0000010aU #define _reg_PHY_ADR_CALVL_DEVICE_MAP 0x0000010bU #define _reg_PHY_ADR_CALVL_RANK_CTRL 0x0000010cU #define _reg_PHY_ADR_CALVL_NUM_PATTERNS 0x0000010dU #define _reg_PHY_ADR_CALVL_CAPTURE_CNT 0x0000010eU #define _reg_PHY_ADR_CALVL_RESP_WAIT_CNT 0x0000010fU #define _reg_PHY_ADR_CALVL_DEBUG_MODE 0x00000110U #define _reg_SC_PHY_ADR_CALVL_DEBUG_CONT 0x00000111U #define _reg_SC_PHY_ADR_CALVL_ERROR_CLR 0x00000112U #define _reg_PHY_ADR_CALVL_OBS_SELECT 0x00000113U #define _reg_PHY_ADR_CALVL_OBS0 0x00000114U #define _reg_PHY_ADR_CALVL_OBS1 0x00000115U #define _reg_PHY_ADR_CALVL_RESULT 0x00000116U #define _reg_PHY_ADR_CALVL_FG_0 0x00000117U #define _reg_PHY_ADR_CALVL_BG_0 0x00000118U #define _reg_PHY_ADR_CALVL_FG_1 0x00000119U #define _reg_PHY_ADR_CALVL_BG_1 0x0000011aU #define _reg_PHY_ADR_CALVL_FG_2 0x0000011bU #define _reg_PHY_ADR_CALVL_BG_2 0x0000011cU #define _reg_PHY_ADR_CALVL_FG_3 0x0000011dU #define _reg_PHY_ADR_CALVL_BG_3 0x0000011eU #define _reg_PHY_ADR_ADDR_SEL 0x0000011fU #define _reg_PHY_ADR_LP4_BOOT_SLV_DELAY 0x00000120U #define _reg_PHY_ADR_BIT_MASK 0x00000121U #define _reg_PHY_ADR_SEG_MASK 0x00000122U #define _reg_PHY_ADR_CALVL_TRAIN_MASK 0x00000123U #define _reg_PHY_ADR_CSLVL_TRAIN_MASK 0x00000124U #define _reg_PHY_ADR_SW_TXIO_CTRL 0x00000125U #define _reg_PHY_ADR_TSEL_SELECT 0x00000126U #define _reg_PHY_ADR0_CLK_WR_SLAVE_DELAY 0x00000127U #define _reg_PHY_ADR1_CLK_WR_SLAVE_DELAY 0x00000128U #define _reg_PHY_ADR2_CLK_WR_SLAVE_DELAY 0x00000129U #define _reg_PHY_ADR3_CLK_WR_SLAVE_DELAY 0x0000012aU #define _reg_PHY_ADR4_CLK_WR_SLAVE_DELAY 0x0000012bU #define _reg_PHY_ADR5_CLK_WR_SLAVE_DELAY 0x0000012cU #define _reg_PHY_ADR_SW_MASTER_MODE 0x0000012dU #define _reg_PHY_ADR_MASTER_DELAY_START 0x0000012eU #define _reg_PHY_ADR_MASTER_DELAY_STEP 0x0000012fU #define _reg_PHY_ADR_MASTER_DELAY_WAIT 0x00000130U #define _reg_PHY_ADR_MASTER_DELAY_HALF_MEASURE 0x00000131U #define _reg_PHY_ADR_CALVL_DLY_STEP 0x00000132U #define _reg_PHY_FREQ_SEL 0x00000133U #define _reg_PHY_FREQ_SEL_FROM_REGIF 0x00000134U #define _reg_PHY_FREQ_SEL_MULTICAST_EN 0x00000135U #define _reg_PHY_FREQ_SEL_INDEX 0x00000136U #define _reg_PHY_SW_GRP_SHIFT_0 0x00000137U #define _reg_PHY_SW_GRP_SHIFT_1 0x00000138U #define _reg_PHY_SW_GRP_SHIFT_2 0x00000139U #define _reg_PHY_SW_GRP_SHIFT_3 0x0000013aU #define _reg_PHY_GRP_BYPASS_SLAVE_DELAY 0x0000013bU #define _reg_PHY_SW_GRP_BYPASS_SHIFT 0x0000013cU #define _reg_PHY_GRP_BYPASS_OVERRIDE 0x0000013dU #define _reg_SC_PHY_MANUAL_UPDATE 0x0000013eU #define _reg_SC_PHY_MANUAL_UPDATE_PHYUPD_ENABLE 0x0000013fU #define _reg_PHY_LP4_BOOT_DISABLE 0x00000140U #define _reg_PHY_CSLVL_ENABLE 0x00000141U #define _reg_PHY_CSLVL_CS_MAP 0x00000142U #define _reg_PHY_CSLVL_START 0x00000143U #define _reg_PHY_CSLVL_QTR 0x00000144U #define _reg_PHY_CSLVL_COARSE_CHK 0x00000145U #define _reg_PHY_CSLVL_CAPTURE_CNT 0x00000146U #define _reg_PHY_CSLVL_COARSE_DLY 0x00000147U #define _reg_PHY_CSLVL_COARSE_CAPTURE_CNT 0x00000148U #define _reg_PHY_CSLVL_DEBUG_MODE 0x00000149U #define _reg_SC_PHY_CSLVL_DEBUG_CONT 0x0000014aU #define _reg_SC_PHY_CSLVL_ERROR_CLR 0x0000014bU #define _reg_PHY_CSLVL_OBS0 0x0000014cU #define _reg_PHY_CSLVL_OBS1 0x0000014dU #define _reg_PHY_CALVL_CS_MAP 0x0000014eU #define _reg_PHY_GRP_SLV_DLY_ENC_OBS_SELECT 0x0000014fU #define _reg_PHY_GRP_SHIFT_OBS_SELECT 0x00000150U #define _reg_PHY_GRP_SLV_DLY_ENC_OBS 0x00000151U #define _reg_PHY_GRP_SHIFT_OBS 0x00000152U #define _reg_PHY_ADRCTL_SLAVE_LOOP_CNT_UPDATE 0x00000153U #define _reg_PHY_ADRCTL_SNAP_OBS_REGS 0x00000154U #define _reg_PHY_DFI_PHYUPD_TYPE 0x00000155U #define _reg_PHY_ADRCTL_LPDDR 0x00000156U #define _reg_PHY_LP4_ACTIVE 0x00000157U #define _reg_PHY_LPDDR3_CS 0x00000158U #define _reg_PHY_CALVL_RESULT_MASK 0x00000159U #define _reg_SC_PHY_UPDATE_CLK_CAL_VALUES 0x0000015aU #define _reg_PHY_SW_TXIO_CTRL_0 0x0000015bU #define _reg_PHY_SW_TXIO_CTRL_1 0x0000015cU #define _reg_PHY_SW_TXIO_CTRL_2 0x0000015dU #define _reg_PHY_SW_TXIO_CTRL_3 0x0000015eU #define _reg_PHY_MEMCLK_SW_TXIO_CTRL 0x0000015fU #define _reg_PHY_CA_SW_TXPWR_CTRL 0x00000160U #define _reg_PHY_MEMCLK_SW_TXPWR_CTRL 0x00000161U #define _reg_PHY_USER_DEF_REG_AC_0 0x00000162U #define _reg_PHY_USER_DEF_REG_AC_1 0x00000163U #define _reg_PHY_USER_DEF_REG_AC_2 0x00000164U #define _reg_PHY_USER_DEF_REG_AC_3 0x00000165U #define _reg_PHY_UPDATE_CLK_CAL_VALUES 0x00000166U #define _reg_PHY_CONTINUOUS_CLK_CAL_UPDATE 0x00000167U #define _reg_PHY_PLL_CTRL 0x00000168U #define _reg_PHY_PLL_CTRL_TOP 0x00000169U #define _reg_PHY_PLL_CTRL_CA 0x0000016aU #define _reg_PHY_PLL_BYPASS 0x0000016bU #define _reg_PHY_LOW_FREQ_SEL 0x0000016cU #define _reg_PHY_PAD_VREF_CTRL_DQ_0 0x0000016dU #define _reg_PHY_PAD_VREF_CTRL_DQ_1 0x0000016eU #define _reg_PHY_PAD_VREF_CTRL_DQ_2 0x0000016fU #define _reg_PHY_PAD_VREF_CTRL_DQ_3 0x00000170U #define _reg_PHY_PAD_VREF_CTRL_AC 0x00000171U #define _reg_PHY_CSLVL_DLY_STEP 0x00000172U #define _reg_PHY_SET_DFI_INPUT_0 0x00000173U #define _reg_PHY_SET_DFI_INPUT_1 0x00000174U #define _reg_PHY_SET_DFI_INPUT_2 0x00000175U #define _reg_PHY_SET_DFI_INPUT_3 0x00000176U #define _reg_PHY_GRP_SLAVE_DELAY_0 0x00000177U #define _reg_PHY_GRP_SLAVE_DELAY_1 0x00000178U #define _reg_PHY_GRP_SLAVE_DELAY_2 0x00000179U #define _reg_PHY_GRP_SLAVE_DELAY_3 0x0000017aU #define _reg_PHY_CS_ACS_ALLOCATION_0 0x0000017bU #define _reg_PHY_CS_ACS_ALLOCATION_1 0x0000017cU #define _reg_PHY_CS_ACS_ALLOCATION_2 0x0000017dU #define _reg_PHY_CS_ACS_ALLOCATION_3 0x0000017eU #define _reg_PHY_LP4_BOOT_PLL_CTRL 0x0000017fU #define _reg_PHY_LP4_BOOT_PLL_CTRL_CA 0x00000180U #define _reg_PHY_LP4_BOOT_TOP_PLL_CTRL 0x00000181U #define _reg_PHY_PLL_CTRL_OVERRIDE 0x00000182U #define _reg_PHY_PLL_WAIT 0x00000183U #define _reg_PHY_PLL_WAIT_TOP 0x00000184U #define _reg_PHY_PLL_OBS_0 0x00000185U #define _reg_PHY_PLL_OBS_1 0x00000186U #define _reg_PHY_PLL_OBS_2 0x00000187U #define _reg_PHY_PLL_OBS_3 0x00000188U #define _reg_PHY_PLL_OBS_4 0x00000189U #define _reg_PHY_PLL_TESTOUT_SEL 0x0000018aU #define _reg_PHY_TCKSRE_WAIT 0x0000018bU #define _reg_PHY_LP4_BOOT_LOW_FREQ_SEL 0x0000018cU #define _reg_PHY_LP_WAKEUP 0x0000018dU #define _reg_PHY_LS_IDLE_EN 0x0000018eU #define _reg_PHY_LP_CTRLUPD_CNTR_CFG 0x0000018fU #define _reg_PHY_TDFI_PHY_WRDELAY 0x00000190U #define _reg_PHY_PAD_FDBK_DRIVE 0x00000191U #define _reg_PHY_PAD_DATA_DRIVE 0x00000192U #define _reg_PHY_PAD_DQS_DRIVE 0x00000193U #define _reg_PHY_PAD_ADDR_DRIVE 0x00000194U #define _reg_PHY_PAD_CLK_DRIVE 0x00000195U #define _reg_PHY_PAD_FDBK_TERM 0x00000196U #define _reg_PHY_PAD_DATA_TERM 0x00000197U #define _reg_PHY_PAD_DQS_TERM 0x00000198U #define _reg_PHY_PAD_ADDR_TERM 0x00000199U #define _reg_PHY_PAD_CLK_TERM 0x0000019aU #define _reg_PHY_PAD_CKE_DRIVE 0x0000019bU #define _reg_PHY_PAD_CKE_TERM 0x0000019cU #define _reg_PHY_PAD_RST_DRIVE 0x0000019dU #define _reg_PHY_PAD_RST_TERM 0x0000019eU #define _reg_PHY_PAD_CS_DRIVE 0x0000019fU #define _reg_PHY_PAD_CS_TERM 0x000001a0U #define _reg_PHY_PAD_ODT_DRIVE 0x000001a1U #define _reg_PHY_PAD_ODT_TERM 0x000001a2U #define _reg_PHY_ADRCTL_RX_CAL 0x000001a3U #define _reg_PHY_ADRCTL_LP3_RX_CAL 0x000001a4U #define _reg_PHY_TST_CLK_PAD_CTRL 0x000001a5U #define _reg_PHY_TST_CLK_PAD_CTRL2 0x000001a6U #define _reg_PHY_CAL_MODE_0 0x000001a7U #define _reg_PHY_CAL_CLEAR_0 0x000001a8U #define _reg_PHY_CAL_START_0 0x000001a9U #define _reg_PHY_CAL_INTERVAL_COUNT_0 0x000001aaU #define _reg_PHY_CAL_SAMPLE_WAIT_0 0x000001abU #define _reg_PHY_LP4_BOOT_CAL_CLK_SELECT_0 0x000001acU #define _reg_PHY_CAL_CLK_SELECT_0 0x000001adU #define _reg_PHY_CAL_RESULT_OBS_0 0x000001aeU #define _reg_PHY_CAL_RESULT2_OBS_0 0x000001afU #define _reg_PHY_CAL_CPTR_CNT_0 0x000001b0U #define _reg_PHY_CAL_SETTLING_PRD_0 0x000001b1U #define _reg_PHY_CAL_PU_FINE_ADJ_0 0x000001b2U #define _reg_PHY_CAL_PD_FINE_ADJ_0 0x000001b3U #define _reg_PHY_CAL_RCV_FINE_ADJ_0 0x000001b4U #define _reg_PHY_CAL_DBG_CFG_0 0x000001b5U #define _reg_SC_PHY_PAD_DBG_CONT_0 0x000001b6U #define _reg_PHY_CAL_RESULT3_OBS_0 0x000001b7U #define _reg_PHY_ADRCTL_PVT_MAP_0 0x000001b8U #define _reg_PHY_CAL_SLOPE_ADJ_0 0x000001b9U #define _reg_PHY_CAL_SLOPE_ADJ_PASS2_0 0x000001baU #define _reg_PHY_CAL_TWO_PASS_CFG_0 0x000001bbU #define _reg_PHY_CAL_SW_CAL_CFG_0 0x000001bcU #define _reg_PHY_CAL_RANGE_MIN_0 0x000001bdU #define _reg_PHY_CAL_RANGE_MAX_0 0x000001beU #define _reg_PHY_PAD_ATB_CTRL 0x000001bfU #define _reg_PHY_ADRCTL_MANUAL_UPDATE 0x000001c0U #define _reg_PHY_AC_LPBK_ERR_CLEAR 0x000001c1U #define _reg_PHY_AC_LPBK_OBS_SELECT 0x000001c2U #define _reg_PHY_AC_LPBK_ENABLE 0x000001c3U #define _reg_PHY_AC_LPBK_CONTROL 0x000001c4U #define _reg_PHY_AC_PRBS_PATTERN_START 0x000001c5U #define _reg_PHY_AC_PRBS_PATTERN_MASK 0x000001c6U #define _reg_PHY_AC_LPBK_RESULT_OBS 0x000001c7U #define _reg_PHY_AC_CLK_LPBK_OBS_SELECT 0x000001c8U #define _reg_PHY_AC_CLK_LPBK_ENABLE 0x000001c9U #define _reg_PHY_AC_CLK_LPBK_CONTROL 0x000001caU #define _reg_PHY_AC_CLK_LPBK_RESULT_OBS 0x000001cbU #define _reg_PHY_AC_PWR_RDC_DISABLE 0x000001ccU #define _reg_PHY_DATA_BYTE_ORDER_SEL 0x000001cdU #define _reg_PHY_DATA_BYTE_ORDER_SEL_HIGH 0x000001ceU #define _reg_PHY_LPDDR4_CONNECT 0x000001cfU #define _reg_PHY_CALVL_DEVICE_MAP 0x000001d0U #define _reg_PHY_ADR_DISABLE 0x000001d1U #define _reg_PHY_ADRCTL_MSTR_DLY_ENC_SEL 0x000001d2U #define _reg_PHY_CS_DLY_UPT_PER_AC_SLICE 0x000001d3U #define _reg_PHY_DDL_AC_ENABLE 0x000001d4U #define _reg_PHY_DDL_AC_MODE 0x000001d5U #define _reg_PHY_PAD_BACKGROUND_CAL 0x000001d6U #define _reg_PHY_INIT_UPDATE_CONFIG 0x000001d7U #define _reg_PHY_DDL_TRACK_UPD_THRESHOLD_AC 0x000001d8U #define _reg_PHY_DLL_RST_EN 0x000001d9U #define _reg_PHY_AC_INIT_COMPLETE_OBS 0x000001daU #define _reg_PHY_DS_INIT_COMPLETE_OBS 0x000001dbU #define _reg_PHY_UPDATE_MASK 0x000001dcU #define _reg_PHY_PLL_SWITCH_CNT 0x000001ddU #define _reg_PI_START 0x000001deU #define _reg_PI_DRAM_CLASS 0x000001dfU #define _reg_PI_VERSION 0x000001e0U #define _reg_PI_NORMAL_LVL_SEQ 0x000001e1U #define _reg_PI_INIT_LVL_EN 0x000001e2U #define _reg_PI_NOTCARE_PHYUPD 0x000001e3U #define _reg_PI_ONBUS_MBIST 0x000001e4U #define _reg_PI_TCMD_GAP 0x000001e5U #define _reg_PI_MASTER_ACK_DURATION_MIN 0x000001e6U #define _reg_PI_DFI_VERSION 0x000001e7U #define _reg_PI_TDFI_PHYMSTR_TYPE0 0x000001e8U #define _reg_PI_TDFI_PHYMSTR_TYPE1 0x000001e9U #define _reg_PI_TDFI_PHYMSTR_TYPE2 0x000001eaU #define _reg_PI_TDFI_PHYMSTR_TYPE3 0x000001ebU #define _reg_PI_DFI_PHYMSTR_TYPE 0x000001ecU #define _reg_PI_DFI_PHYMSTR_CS_STATE_R 0x000001edU #define _reg_PI_DFI_PHYMSTR_STATE_SEL_R 0x000001eeU #define _reg_PI_TDFI_PHYMSTR_MAX_F0 0x000001efU #define _reg_PI_TDFI_PHYMSTR_RESP_F0 0x000001f0U #define _reg_PI_TDFI_PHYMSTR_MAX_F1 0x000001f1U #define _reg_PI_TDFI_PHYMSTR_RESP_F1 0x000001f2U #define _reg_PI_TDFI_PHYMSTR_MAX_F2 0x000001f3U #define _reg_PI_TDFI_PHYMSTR_RESP_F2 0x000001f4U #define _reg_PI_TDFI_PHYUPD_RESP_F0 0x000001f5U #define _reg_PI_TDFI_PHYUPD_TYPE0_F0 0x000001f6U #define _reg_PI_TDFI_PHYUPD_TYPE1_F0 0x000001f7U #define _reg_PI_TDFI_PHYUPD_TYPE2_F0 0x000001f8U #define _reg_PI_TDFI_PHYUPD_TYPE3_F0 0x000001f9U #define _reg_PI_TDFI_PHYUPD_RESP_F1 0x000001faU #define _reg_PI_TDFI_PHYUPD_TYPE0_F1 0x000001fbU #define _reg_PI_TDFI_PHYUPD_TYPE1_F1 0x000001fcU #define _reg_PI_TDFI_PHYUPD_TYPE2_F1 0x000001fdU #define _reg_PI_TDFI_PHYUPD_TYPE3_F1 0x000001feU #define _reg_PI_TDFI_PHYUPD_RESP_F2 0x000001ffU #define _reg_PI_TDFI_PHYUPD_TYPE0_F2 0x00000200U #define _reg_PI_TDFI_PHYUPD_TYPE1_F2 0x00000201U #define _reg_PI_TDFI_PHYUPD_TYPE2_F2 0x00000202U #define _reg_PI_TDFI_PHYUPD_TYPE3_F2 0x00000203U #define _reg_PI_CONTROL_ERROR_STATUS 0x00000204U #define _reg_PI_EXIT_AFTER_INIT_CALVL 0x00000205U #define _reg_PI_FREQ_MAP 0x00000206U #define _reg_PI_INIT_WORK_FREQ 0x00000207U #define _reg_PI_INIT_DFS_CALVL_ONLY 0x00000208U #define _reg_PI_POWER_ON_SEQ_BYPASS_ARRAY 0x00000209U #define _reg_PI_POWER_ON_SEQ_END_ARRAY 0x0000020aU #define _reg_PI_SEQ1_PAT 0x0000020bU #define _reg_PI_SEQ1_PAT_MASK 0x0000020cU #define _reg_PI_SEQ2_PAT 0x0000020dU #define _reg_PI_SEQ2_PAT_MASK 0x0000020eU #define _reg_PI_SEQ3_PAT 0x0000020fU #define _reg_PI_SEQ3_PAT_MASK 0x00000210U #define _reg_PI_SEQ4_PAT 0x00000211U #define _reg_PI_SEQ4_PAT_MASK 0x00000212U #define _reg_PI_SEQ5_PAT 0x00000213U #define _reg_PI_SEQ5_PAT_MASK 0x00000214U #define _reg_PI_SEQ6_PAT 0x00000215U #define _reg_PI_SEQ6_PAT_MASK 0x00000216U #define _reg_PI_SEQ7_PAT 0x00000217U #define _reg_PI_SEQ7_PAT_MASK 0x00000218U #define _reg_PI_SEQ8_PAT 0x00000219U #define _reg_PI_SEQ8_PAT_MASK 0x0000021aU #define _reg_PI_WDT_DISABLE 0x0000021bU #define _reg_PI_SW_RST_N 0x0000021cU #define _reg_RESERVED_R0 0x0000021dU #define _reg_PI_CS_MAP 0x0000021eU #define _reg_PI_TDELAY_RDWR_2_BUS_IDLE_F0 0x0000021fU #define _reg_PI_TDELAY_RDWR_2_BUS_IDLE_F1 0x00000220U #define _reg_PI_TDELAY_RDWR_2_BUS_IDLE_F2 0x00000221U #define _reg_PI_TMRR 0x00000222U #define _reg_PI_WRLAT_F0 0x00000223U #define _reg_PI_ADDITIVE_LAT_F0 0x00000224U #define _reg_PI_CASLAT_LIN_F0 0x00000225U #define _reg_PI_WRLAT_F1 0x00000226U #define _reg_PI_ADDITIVE_LAT_F1 0x00000227U #define _reg_PI_CASLAT_LIN_F1 0x00000228U #define _reg_PI_WRLAT_F2 0x00000229U #define _reg_PI_ADDITIVE_LAT_F2 0x0000022aU #define _reg_PI_CASLAT_LIN_F2 0x0000022bU #define _reg_PI_PREAMBLE_SUPPORT 0x0000022cU #define _reg_PI_AREFRESH 0x0000022dU #define _reg_PI_MCAREF_FORWARD_ONLY 0x0000022eU #define _reg_PI_TRFC_F0 0x0000022fU #define _reg_PI_TREF_F0 0x00000230U #define _reg_PI_TRFC_F1 0x00000231U #define _reg_PI_TREF_F1 0x00000232U #define _reg_PI_TRFC_F2 0x00000233U #define _reg_PI_TREF_F2 0x00000234U #define _reg_RESERVED_H3VER2 0x00000235U #define _reg_PI_TREF_INTERVAL 0x00000236U #define _reg_PI_FREQ_CHANGE_REG_COPY 0x00000237U #define _reg_PI_FREQ_SEL_FROM_REGIF 0x00000238U #define _reg_PI_SWLVL_LOAD 0x00000239U #define _reg_PI_SWLVL_OP_DONE 0x0000023aU #define _reg_PI_SW_WRLVL_RESP_0 0x0000023bU #define _reg_PI_SW_WRLVL_RESP_1 0x0000023cU #define _reg_PI_SW_WRLVL_RESP_2 0x0000023dU #define _reg_PI_SW_WRLVL_RESP_3 0x0000023eU #define _reg_PI_SW_RDLVL_RESP_0 0x0000023fU #define _reg_PI_SW_RDLVL_RESP_1 0x00000240U #define _reg_PI_SW_RDLVL_RESP_2 0x00000241U #define _reg_PI_SW_RDLVL_RESP_3 0x00000242U #define _reg_PI_SW_CALVL_RESP_0 0x00000243U #define _reg_PI_SW_LEVELING_MODE 0x00000244U #define _reg_PI_SWLVL_START 0x00000245U #define _reg_PI_SWLVL_EXIT 0x00000246U #define _reg_PI_SWLVL_WR_SLICE_0 0x00000247U #define _reg_PI_SWLVL_RD_SLICE_0 0x00000248U #define _reg_PI_SWLVL_VREF_UPDATE_SLICE_0 0x00000249U #define _reg_PI_SW_WDQLVL_RESP_0 0x0000024aU #define _reg_PI_SWLVL_WR_SLICE_1 0x0000024bU #define _reg_PI_SWLVL_RD_SLICE_1 0x0000024cU #define _reg_PI_SWLVL_VREF_UPDATE_SLICE_1 0x0000024dU #define _reg_PI_SW_WDQLVL_RESP_1 0x0000024eU #define _reg_PI_SWLVL_WR_SLICE_2 0x0000024fU #define _reg_PI_SWLVL_RD_SLICE_2 0x00000250U #define _reg_PI_SWLVL_VREF_UPDATE_SLICE_2 0x00000251U #define _reg_PI_SW_WDQLVL_RESP_2 0x00000252U #define _reg_PI_SWLVL_WR_SLICE_3 0x00000253U #define _reg_PI_SWLVL_RD_SLICE_3 0x00000254U #define _reg_PI_SWLVL_VREF_UPDATE_SLICE_3 0x00000255U #define _reg_PI_SW_WDQLVL_RESP_3 0x00000256U #define _reg_PI_SW_WDQLVL_VREF 0x00000257U #define _reg_PI_SWLVL_SM2_START 0x00000258U #define _reg_PI_SWLVL_SM2_WR 0x00000259U #define _reg_PI_SWLVL_SM2_RD 0x0000025aU #define _reg_PI_SEQUENTIAL_LVL_REQ 0x0000025bU #define _reg_PI_DFS_PERIOD_EN 0x0000025cU #define _reg_PI_SRE_PERIOD_EN 0x0000025dU #define _reg_PI_DFI40_POLARITY 0x0000025eU #define _reg_PI_16BIT_DRAM_CONNECT 0x0000025fU #define _reg_PI_TDFI_CTRL_DELAY_F0 0x00000260U #define _reg_PI_TDFI_CTRL_DELAY_F1 0x00000261U #define _reg_PI_TDFI_CTRL_DELAY_F2 0x00000262U #define _reg_PI_WRLVL_REQ 0x00000263U #define _reg_PI_WRLVL_CS 0x00000264U #define _reg_PI_WLDQSEN 0x00000265U #define _reg_PI_WLMRD 0x00000266U #define _reg_PI_WRLVL_EN_F0 0x00000267U #define _reg_PI_WRLVL_EN_F1 0x00000268U #define _reg_PI_WRLVL_EN_F2 0x00000269U #define _reg_PI_WRLVL_EN 0x0000026aU #define _reg_PI_WRLVL_INTERVAL 0x0000026bU #define _reg_PI_WRLVL_PERIODIC 0x0000026cU #define _reg_PI_WRLVL_ON_SREF_EXIT 0x0000026dU #define _reg_PI_WRLVL_DISABLE_DFS 0x0000026eU #define _reg_PI_WRLVL_RESP_MASK 0x0000026fU #define _reg_PI_WRLVL_ROTATE 0x00000270U #define _reg_PI_WRLVL_CS_MAP 0x00000271U #define _reg_PI_WRLVL_ERROR_STATUS 0x00000272U #define _reg_PI_TDFI_WRLVL_EN 0x00000273U #define _reg_PI_TDFI_WRLVL_WW_F0 0x00000274U #define _reg_PI_TDFI_WRLVL_WW_F1 0x00000275U #define _reg_PI_TDFI_WRLVL_WW_F2 0x00000276U #define _reg_PI_TDFI_WRLVL_WW 0x00000277U #define _reg_PI_TDFI_WRLVL_RESP 0x00000278U #define _reg_PI_TDFI_WRLVL_MAX 0x00000279U #define _reg_PI_WRLVL_STROBE_NUM 0x0000027aU #define _reg_PI_WRLVL_MRR_DQ_RETURN_HIZ 0x0000027bU #define _reg_PI_WRLVL_EN_DEASSERT_2_MRR 0x0000027cU #define _reg_PI_TODTL_2CMD_F0 0x0000027dU #define _reg_PI_ODT_EN_F0 0x0000027eU #define _reg_PI_TODTL_2CMD_F1 0x0000027fU #define _reg_PI_ODT_EN_F1 0x00000280U #define _reg_PI_TODTL_2CMD_F2 0x00000281U #define _reg_PI_ODT_EN_F2 0x00000282U #define _reg_PI_TODTH_WR 0x00000283U #define _reg_PI_TODTH_RD 0x00000284U #define _reg_PI_ODT_RD_MAP_CS0 0x00000285U #define _reg_PI_ODT_WR_MAP_CS0 0x00000286U #define _reg_PI_ODT_RD_MAP_CS1 0x00000287U #define _reg_PI_ODT_WR_MAP_CS1 0x00000288U #define _reg_PI_ODT_RD_MAP_CS2 0x00000289U #define _reg_PI_ODT_WR_MAP_CS2 0x0000028aU #define _reg_PI_ODT_RD_MAP_CS3 0x0000028bU #define _reg_PI_ODT_WR_MAP_CS3 0x0000028cU #define _reg_PI_EN_ODT_ASSERT_EXCEPT_RD 0x0000028dU #define _reg_PI_ODTLON_F0 0x0000028eU #define _reg_PI_TODTON_MIN_F0 0x0000028fU #define _reg_PI_ODTLON_F1 0x00000290U #define _reg_PI_TODTON_MIN_F1 0x00000291U #define _reg_PI_ODTLON_F2 0x00000292U #define _reg_PI_TODTON_MIN_F2 0x00000293U #define _reg_PI_WR_TO_ODTH_F0 0x00000294U #define _reg_PI_WR_TO_ODTH_F1 0x00000295U #define _reg_PI_WR_TO_ODTH_F2 0x00000296U #define _reg_PI_RD_TO_ODTH_F0 0x00000297U #define _reg_PI_RD_TO_ODTH_F1 0x00000298U #define _reg_PI_RD_TO_ODTH_F2 0x00000299U #define _reg_PI_ADDRESS_MIRRORING 0x0000029aU #define _reg_PI_RDLVL_REQ 0x0000029bU #define _reg_PI_RDLVL_GATE_REQ 0x0000029cU #define _reg_PI_RDLVL_CS 0x0000029dU #define _reg_PI_RDLVL_PAT_0 0x0000029eU #define _reg_PI_RDLVL_PAT_1 0x0000029fU #define _reg_PI_RDLVL_PAT_2 0x000002a0U #define _reg_PI_RDLVL_PAT_3 0x000002a1U #define _reg_PI_RDLVL_PAT_4 0x000002a2U #define _reg_PI_RDLVL_PAT_5 0x000002a3U #define _reg_PI_RDLVL_PAT_6 0x000002a4U #define _reg_PI_RDLVL_PAT_7 0x000002a5U #define _reg_PI_RDLVL_SEQ_EN 0x000002a6U #define _reg_PI_RDLVL_GATE_SEQ_EN 0x000002a7U #define _reg_PI_RDLVL_PERIODIC 0x000002a8U #define _reg_PI_RDLVL_ON_SREF_EXIT 0x000002a9U #define _reg_PI_RDLVL_DISABLE_DFS 0x000002aaU #define _reg_PI_RDLVL_GATE_PERIODIC 0x000002abU #define _reg_PI_RDLVL_GATE_ON_SREF_EXIT 0x000002acU #define _reg_PI_RDLVL_GATE_DISABLE_DFS 0x000002adU #define _reg_RESERVED_R1 0x000002aeU #define _reg_PI_RDLVL_ROTATE 0x000002afU #define _reg_PI_RDLVL_GATE_ROTATE 0x000002b0U #define _reg_PI_RDLVL_CS_MAP 0x000002b1U #define _reg_PI_RDLVL_GATE_CS_MAP 0x000002b2U #define _reg_PI_TDFI_RDLVL_RR 0x000002b3U #define _reg_PI_TDFI_RDLVL_RESP 0x000002b4U #define _reg_PI_RDLVL_RESP_MASK 0x000002b5U #define _reg_PI_TDFI_RDLVL_EN 0x000002b6U #define _reg_PI_RDLVL_EN_F0 0x000002b7U #define _reg_PI_RDLVL_GATE_EN_F0 0x000002b8U #define _reg_PI_RDLVL_EN_F1 0x000002b9U #define _reg_PI_RDLVL_GATE_EN_F1 0x000002baU #define _reg_PI_RDLVL_EN_F2 0x000002bbU #define _reg_PI_RDLVL_GATE_EN_F2 0x000002bcU #define _reg_PI_RDLVL_EN 0x000002bdU #define _reg_PI_RDLVL_GATE_EN 0x000002beU #define _reg_PI_TDFI_RDLVL_MAX 0x000002bfU #define _reg_PI_RDLVL_ERROR_STATUS 0x000002c0U #define _reg_PI_RDLVL_INTERVAL 0x000002c1U #define _reg_PI_RDLVL_GATE_INTERVAL 0x000002c2U #define _reg_PI_RDLVL_PATTERN_START 0x000002c3U #define _reg_PI_RDLVL_PATTERN_NUM 0x000002c4U #define _reg_PI_RDLVL_STROBE_NUM 0x000002c5U #define _reg_PI_RDLVL_GATE_STROBE_NUM 0x000002c6U #define _reg_PI_LPDDR4_RDLVL_PATTERN_8 0x000002c7U #define _reg_PI_LPDDR4_RDLVL_PATTERN_9 0x000002c8U #define _reg_PI_LPDDR4_RDLVL_PATTERN_10 0x000002c9U #define _reg_PI_LPDDR4_RDLVL_PATTERN_11 0x000002caU #define _reg_PI_RD_PREAMBLE_TRAINING_EN 0x000002cbU #define _reg_PI_REG_DIMM_ENABLE 0x000002ccU #define _reg_PI_RDLAT_ADJ_F0 0x000002cdU #define _reg_PI_RDLAT_ADJ_F1 0x000002ceU #define _reg_PI_RDLAT_ADJ_F2 0x000002cfU #define _reg_PI_TDFI_RDDATA_EN 0x000002d0U #define _reg_PI_WRLAT_ADJ_F0 0x000002d1U #define _reg_PI_WRLAT_ADJ_F1 0x000002d2U #define _reg_PI_WRLAT_ADJ_F2 0x000002d3U #define _reg_PI_TDFI_PHY_WRLAT 0x000002d4U #define _reg_PI_TDFI_WRCSLAT_F0 0x000002d5U #define _reg_PI_TDFI_WRCSLAT_F1 0x000002d6U #define _reg_PI_TDFI_WRCSLAT_F2 0x000002d7U #define _reg_PI_TDFI_RDCSLAT_F0 0x000002d8U #define _reg_PI_TDFI_RDCSLAT_F1 0x000002d9U #define _reg_PI_TDFI_RDCSLAT_F2 0x000002daU #define _reg_PI_TDFI_PHY_WRDATA_F0 0x000002dbU #define _reg_PI_TDFI_PHY_WRDATA_F1 0x000002dcU #define _reg_PI_TDFI_PHY_WRDATA_F2 0x000002ddU #define _reg_PI_TDFI_PHY_WRDATA 0x000002deU #define _reg_PI_CALVL_REQ 0x000002dfU #define _reg_PI_CALVL_CS 0x000002e0U #define _reg_RESERVED_R2 0x000002e1U #define _reg_RESERVED_R3 0x000002e2U #define _reg_PI_CALVL_SEQ_EN 0x000002e3U #define _reg_PI_CALVL_PERIODIC 0x000002e4U #define _reg_PI_CALVL_ON_SREF_EXIT 0x000002e5U #define _reg_PI_CALVL_DISABLE_DFS 0x000002e6U #define _reg_PI_CALVL_ROTATE 0x000002e7U #define _reg_PI_CALVL_CS_MAP 0x000002e8U #define _reg_PI_TDFI_CALVL_EN 0x000002e9U #define _reg_PI_TDFI_CALVL_CC_F0 0x000002eaU #define _reg_PI_TDFI_CALVL_CAPTURE_F0 0x000002ebU #define _reg_PI_TDFI_CALVL_CC_F1 0x000002ecU #define _reg_PI_TDFI_CALVL_CAPTURE_F1 0x000002edU #define _reg_PI_TDFI_CALVL_CC_F2 0x000002eeU #define _reg_PI_TDFI_CALVL_CAPTURE_F2 0x000002efU #define _reg_PI_TDFI_CALVL_RESP 0x000002f0U #define _reg_PI_TDFI_CALVL_MAX 0x000002f1U #define _reg_PI_CALVL_RESP_MASK 0x000002f2U #define _reg_PI_CALVL_EN_F0 0x000002f3U #define _reg_PI_CALVL_EN_F1 0x000002f4U #define _reg_PI_CALVL_EN_F2 0x000002f5U #define _reg_PI_CALVL_EN 0x000002f6U #define _reg_PI_CALVL_ERROR_STATUS 0x000002f7U #define _reg_PI_CALVL_INTERVAL 0x000002f8U #define _reg_PI_TCACKEL 0x000002f9U #define _reg_PI_TCAMRD 0x000002faU #define _reg_PI_TCACKEH 0x000002fbU #define _reg_PI_TMRZ_F0 0x000002fcU #define _reg_PI_TCAENT_F0 0x000002fdU #define _reg_PI_TMRZ_F1 0x000002feU #define _reg_PI_TCAENT_F1 0x000002ffU #define _reg_PI_TMRZ_F2 0x00000300U #define _reg_PI_TCAENT_F2 0x00000301U #define _reg_PI_TCAEXT 0x00000302U #define _reg_PI_CA_TRAIN_VREF_EN 0x00000303U #define _reg_PI_TDFI_CACSCA_F0 0x00000304U #define _reg_PI_TDFI_CASEL_F0 0x00000305U #define _reg_PI_TVREF_SHORT_F0 0x00000306U #define _reg_PI_TVREF_LONG_F0 0x00000307U #define _reg_PI_TDFI_CACSCA_F1 0x00000308U #define _reg_PI_TDFI_CASEL_F1 0x00000309U #define _reg_PI_TVREF_SHORT_F1 0x0000030aU #define _reg_PI_TVREF_LONG_F1 0x0000030bU #define _reg_PI_TDFI_CACSCA_F2 0x0000030cU #define _reg_PI_TDFI_CASEL_F2 0x0000030dU #define _reg_PI_TVREF_SHORT_F2 0x0000030eU #define _reg_PI_TVREF_LONG_F2 0x0000030fU #define _reg_PI_CALVL_VREF_INITIAL_START_POINT_F0 0x00000310U #define _reg_PI_CALVL_VREF_INITIAL_STOP_POINT_F0 0x00000311U #define _reg_PI_CALVL_VREF_INITIAL_START_POINT_F1 0x00000312U #define _reg_PI_CALVL_VREF_INITIAL_STOP_POINT_F1 0x00000313U #define _reg_PI_CALVL_VREF_INITIAL_START_POINT_F2 0x00000314U #define _reg_PI_CALVL_VREF_INITIAL_STOP_POINT_F2 0x00000315U #define _reg_PI_CALVL_VREF_INITIAL_START_POINT 0x00000316U #define _reg_PI_CALVL_VREF_INITIAL_STOP_POINT 0x00000317U #define _reg_PI_CALVL_VREF_INITIAL_STEPSIZE 0x00000318U #define _reg_PI_CALVL_VREF_NORMAL_STEPSIZE 0x00000319U #define _reg_PI_CALVL_VREF_DELTA_F0 0x0000031aU #define _reg_PI_CALVL_VREF_DELTA_F1 0x0000031bU #define _reg_PI_CALVL_VREF_DELTA_F2 0x0000031cU #define _reg_PI_CALVL_VREF_DELTA 0x0000031dU #define _reg_PI_TDFI_INIT_START_MIN 0x0000031eU #define _reg_PI_TDFI_INIT_COMPLETE_MIN 0x0000031fU #define _reg_PI_TDFI_CALVL_STROBE_F0 0x00000320U #define _reg_PI_TXP_F0 0x00000321U #define _reg_PI_TMRWCKEL_F0 0x00000322U #define _reg_PI_TCKELCK_F0 0x00000323U #define _reg_PI_TDFI_CALVL_STROBE_F1 0x00000324U #define _reg_PI_TXP_F1 0x00000325U #define _reg_PI_TMRWCKEL_F1 0x00000326U #define _reg_PI_TCKELCK_F1 0x00000327U #define _reg_PI_TDFI_CALVL_STROBE_F2 0x00000328U #define _reg_PI_TXP_F2 0x00000329U #define _reg_PI_TMRWCKEL_F2 0x0000032aU #define _reg_PI_TCKELCK_F2 0x0000032bU #define _reg_PI_TCKCKEH 0x0000032cU #define _reg_PI_CALVL_STROBE_NUM 0x0000032dU #define _reg_PI_SW_CA_TRAIN_VREF 0x0000032eU #define _reg_PI_TDFI_INIT_START_F0 0x0000032fU #define _reg_PI_TDFI_INIT_COMPLETE_F0 0x00000330U #define _reg_PI_TDFI_INIT_START_F1 0x00000331U #define _reg_PI_TDFI_INIT_COMPLETE_F1 0x00000332U #define _reg_PI_TDFI_INIT_START_F2 0x00000333U #define _reg_PI_TDFI_INIT_COMPLETE_F2 0x00000334U #define _reg_PI_CLKDISABLE_2_INIT_START 0x00000335U #define _reg_PI_INIT_STARTORCOMPLETE_2_CLKDISABLE 0x00000336U #define _reg_PI_DRAM_CLK_DISABLE_DEASSERT_SEL 0x00000337U #define _reg_PI_REFRESH_BETWEEN_SEGMENT_DISABLE 0x00000338U #define _reg_PI_TCKEHDQS_F0 0x00000339U #define _reg_PI_TCKEHDQS_F1 0x0000033aU #define _reg_PI_TCKEHDQS_F2 0x0000033bU #define _reg_PI_MC_DFS_PI_SET_VREF_ENABLE 0x0000033cU #define _reg_PI_WDQLVL_VREF_EN 0x0000033dU #define _reg_PI_WDQLVL_BST_NUM 0x0000033eU #define _reg_PI_TDFI_WDQLVL_WR_F0 0x0000033fU #define _reg_PI_TDFI_WDQLVL_WR_F1 0x00000340U #define _reg_PI_TDFI_WDQLVL_WR_F2 0x00000341U #define _reg_PI_TDFI_WDQLVL_WR 0x00000342U #define _reg_PI_TDFI_WDQLVL_RW 0x00000343U #define _reg_PI_WDQLVL_RESP_MASK 0x00000344U #define _reg_PI_WDQLVL_ROTATE 0x00000345U #define _reg_PI_WDQLVL_CS_MAP 0x00000346U #define _reg_PI_WDQLVL_VREF_INITIAL_START_POINT_F0 0x00000347U #define _reg_PI_WDQLVL_VREF_INITIAL_STOP_POINT_F0 0x00000348U #define _reg_PI_WDQLVL_VREF_INITIAL_START_POINT_F1 0x00000349U #define _reg_PI_WDQLVL_VREF_INITIAL_STOP_POINT_F1 0x0000034aU #define _reg_PI_WDQLVL_VREF_INITIAL_START_POINT_F2 0x0000034bU #define _reg_PI_WDQLVL_VREF_INITIAL_STOP_POINT_F2 0x0000034cU #define _reg_PI_WDQLVL_VREF_INITIAL_START_POINT 0x0000034dU #define _reg_PI_WDQLVL_VREF_INITIAL_STOP_POINT 0x0000034eU #define _reg_PI_WDQLVL_VREF_INITIAL_STEPSIZE 0x0000034fU #define _reg_PI_WDQLVL_VREF_NORMAL_STEPSIZE 0x00000350U #define _reg_PI_WDQLVL_VREF_DELTA_F0 0x00000351U #define _reg_PI_WDQLVL_VREF_DELTA_F1 0x00000352U #define _reg_PI_WDQLVL_VREF_DELTA_F2 0x00000353U #define _reg_PI_WDQLVL_VREF_DELTA 0x00000354U #define _reg_PI_WDQLVL_PERIODIC 0x00000355U #define _reg_PI_WDQLVL_REQ 0x00000356U #define _reg_PI_WDQLVL_CS 0x00000357U #define _reg_PI_TDFI_WDQLVL_EN 0x00000358U #define _reg_PI_TDFI_WDQLVL_RESP 0x00000359U #define _reg_PI_TDFI_WDQLVL_MAX 0x0000035aU #define _reg_PI_WDQLVL_INTERVAL 0x0000035bU #define _reg_PI_WDQLVL_EN_F0 0x0000035cU #define _reg_PI_WDQLVL_EN_F1 0x0000035dU #define _reg_PI_WDQLVL_EN_F2 0x0000035eU #define _reg_PI_WDQLVL_EN 0x0000035fU #define _reg_PI_WDQLVL_ON_SREF_EXIT 0x00000360U #define _reg_PI_WDQLVL_DISABLE_DFS 0x00000361U #define _reg_PI_WDQLVL_ERROR_STATUS 0x00000362U #define _reg_PI_MR1_DATA_F0_0 0x00000363U #define _reg_PI_MR2_DATA_F0_0 0x00000364U #define _reg_PI_MR3_DATA_F0_0 0x00000365U #define _reg_PI_MR11_DATA_F0_0 0x00000366U #define _reg_PI_MR12_DATA_F0_0 0x00000367U #define _reg_PI_MR14_DATA_F0_0 0x00000368U #define _reg_PI_MR22_DATA_F0_0 0x00000369U #define _reg_PI_MR1_DATA_F1_0 0x0000036aU #define _reg_PI_MR2_DATA_F1_0 0x0000036bU #define _reg_PI_MR3_DATA_F1_0 0x0000036cU #define _reg_PI_MR11_DATA_F1_0 0x0000036dU #define _reg_PI_MR12_DATA_F1_0 0x0000036eU #define _reg_PI_MR14_DATA_F1_0 0x0000036fU #define _reg_PI_MR22_DATA_F1_0 0x00000370U #define _reg_PI_MR1_DATA_F2_0 0x00000371U #define _reg_PI_MR2_DATA_F2_0 0x00000372U #define _reg_PI_MR3_DATA_F2_0 0x00000373U #define _reg_PI_MR11_DATA_F2_0 0x00000374U #define _reg_PI_MR12_DATA_F2_0 0x00000375U #define _reg_PI_MR14_DATA_F2_0 0x00000376U #define _reg_PI_MR22_DATA_F2_0 0x00000377U #define _reg_PI_MR13_DATA_0 0x00000378U #define _reg_PI_MR1_DATA_F0_1 0x00000379U #define _reg_PI_MR2_DATA_F0_1 0x0000037aU #define _reg_PI_MR3_DATA_F0_1 0x0000037bU #define _reg_PI_MR11_DATA_F0_1 0x0000037cU #define _reg_PI_MR12_DATA_F0_1 0x0000037dU #define _reg_PI_MR14_DATA_F0_1 0x0000037eU #define _reg_PI_MR22_DATA_F0_1 0x0000037fU #define _reg_PI_MR1_DATA_F1_1 0x00000380U #define _reg_PI_MR2_DATA_F1_1 0x00000381U #define _reg_PI_MR3_DATA_F1_1 0x00000382U #define _reg_PI_MR11_DATA_F1_1 0x00000383U #define _reg_PI_MR12_DATA_F1_1 0x00000384U #define _reg_PI_MR14_DATA_F1_1 0x00000385U #define _reg_PI_MR22_DATA_F1_1 0x00000386U #define _reg_PI_MR1_DATA_F2_1 0x00000387U #define _reg_PI_MR2_DATA_F2_1 0x00000388U #define _reg_PI_MR3_DATA_F2_1 0x00000389U #define _reg_PI_MR11_DATA_F2_1 0x0000038aU #define _reg_PI_MR12_DATA_F2_1 0x0000038bU #define _reg_PI_MR14_DATA_F2_1 0x0000038cU #define _reg_PI_MR22_DATA_F2_1 0x0000038dU #define _reg_PI_MR13_DATA_1 0x0000038eU #define _reg_PI_MR1_DATA_F0_2 0x0000038fU #define _reg_PI_MR2_DATA_F0_2 0x00000390U #define _reg_PI_MR3_DATA_F0_2 0x00000391U #define _reg_PI_MR11_DATA_F0_2 0x00000392U #define _reg_PI_MR12_DATA_F0_2 0x00000393U #define _reg_PI_MR14_DATA_F0_2 0x00000394U #define _reg_PI_MR22_DATA_F0_2 0x00000395U #define _reg_PI_MR1_DATA_F1_2 0x00000396U #define _reg_PI_MR2_DATA_F1_2 0x00000397U #define _reg_PI_MR3_DATA_F1_2 0x00000398U #define _reg_PI_MR11_DATA_F1_2 0x00000399U #define _reg_PI_MR12_DATA_F1_2 0x0000039aU #define _reg_PI_MR14_DATA_F1_2 0x0000039bU #define _reg_PI_MR22_DATA_F1_2 0x0000039cU #define _reg_PI_MR1_DATA_F2_2 0x0000039dU #define _reg_PI_MR2_DATA_F2_2 0x0000039eU #define _reg_PI_MR3_DATA_F2_2 0x0000039fU #define _reg_PI_MR11_DATA_F2_2 0x000003a0U #define _reg_PI_MR12_DATA_F2_2 0x000003a1U #define _reg_PI_MR14_DATA_F2_2 0x000003a2U #define _reg_PI_MR22_DATA_F2_2 0x000003a3U #define _reg_PI_MR13_DATA_2 0x000003a4U #define _reg_PI_MR1_DATA_F0_3 0x000003a5U #define _reg_PI_MR2_DATA_F0_3 0x000003a6U #define _reg_PI_MR3_DATA_F0_3 0x000003a7U #define _reg_PI_MR11_DATA_F0_3 0x000003a8U #define _reg_PI_MR12_DATA_F0_3 0x000003a9U #define _reg_PI_MR14_DATA_F0_3 0x000003aaU #define _reg_PI_MR22_DATA_F0_3 0x000003abU #define _reg_PI_MR1_DATA_F1_3 0x000003acU #define _reg_PI_MR2_DATA_F1_3 0x000003adU #define _reg_PI_MR3_DATA_F1_3 0x000003aeU #define _reg_PI_MR11_DATA_F1_3 0x000003afU #define _reg_PI_MR12_DATA_F1_3 0x000003b0U #define _reg_PI_MR14_DATA_F1_3 0x000003b1U #define _reg_PI_MR22_DATA_F1_3 0x000003b2U #define _reg_PI_MR1_DATA_F2_3 0x000003b3U #define _reg_PI_MR2_DATA_F2_3 0x000003b4U #define _reg_PI_MR3_DATA_F2_3 0x000003b5U #define _reg_PI_MR11_DATA_F2_3 0x000003b6U #define _reg_PI_MR12_DATA_F2_3 0x000003b7U #define _reg_PI_MR14_DATA_F2_3 0x000003b8U #define _reg_PI_MR22_DATA_F2_3 0x000003b9U #define _reg_PI_MR13_DATA_3 0x000003baU #define _reg_PI_BANK_DIFF 0x000003bbU #define _reg_PI_ROW_DIFF 0x000003bcU #define _reg_PI_TFC_F0 0x000003bdU #define _reg_PI_TFC_F1 0x000003beU #define _reg_PI_TFC_F2 0x000003bfU #define _reg_PI_TCCD 0x000003c0U #define _reg_PI_TRTP_F0 0x000003c1U #define _reg_PI_TRP_F0 0x000003c2U #define _reg_PI_TRCD_F0 0x000003c3U #define _reg_PI_TWTR_F0 0x000003c4U #define _reg_PI_TWR_F0 0x000003c5U #define _reg_PI_TRAS_MAX_F0 0x000003c6U #define _reg_PI_TRAS_MIN_F0 0x000003c7U #define _reg_PI_TDQSCK_MAX_F0 0x000003c8U #define _reg_PI_TCCDMW_F0 0x000003c9U #define _reg_PI_TSR_F0 0x000003caU #define _reg_PI_TMRD_F0 0x000003cbU #define _reg_PI_TMRW_F0 0x000003ccU #define _reg_PI_TMOD_F0 0x000003cdU #define _reg_PI_TRTP_F1 0x000003ceU #define _reg_PI_TRP_F1 0x000003cfU #define _reg_PI_TRCD_F1 0x000003d0U #define _reg_PI_TWTR_F1 0x000003d1U #define _reg_PI_TWR_F1 0x000003d2U #define _reg_PI_TRAS_MAX_F1 0x000003d3U #define _reg_PI_TRAS_MIN_F1 0x000003d4U #define _reg_PI_TDQSCK_MAX_F1 0x000003d5U #define _reg_PI_TCCDMW_F1 0x000003d6U #define _reg_PI_TSR_F1 0x000003d7U #define _reg_PI_TMRD_F1 0x000003d8U #define _reg_PI_TMRW_F1 0x000003d9U #define _reg_PI_TMOD_F1 0x000003daU #define _reg_PI_TRTP_F2 0x000003dbU #define _reg_PI_TRP_F2 0x000003dcU #define _reg_PI_TRCD_F2 0x000003ddU #define _reg_PI_TWTR_F2 0x000003deU #define _reg_PI_TWR_F2 0x000003dfU #define _reg_PI_TRAS_MAX_F2 0x000003e0U #define _reg_PI_TRAS_MIN_F2 0x000003e1U #define _reg_PI_TDQSCK_MAX_F2 0x000003e2U #define _reg_PI_TCCDMW_F2 0x000003e3U #define _reg_PI_TSR_F2 0x000003e4U #define _reg_PI_TMRD_F2 0x000003e5U #define _reg_PI_TMRW_F2 0x000003e6U #define _reg_PI_TMOD_F2 0x000003e7U #define _reg_RESERVED_R4 0x000003e8U #define _reg_RESERVED_R5 0x000003e9U #define _reg_RESERVED_R6 0x000003eaU #define _reg_RESERVED_R7 0x000003ebU #define _reg_RESERVED_R8 0x000003ecU #define _reg_RESERVED_R9 0x000003edU #define _reg_RESERVED_R10 0x000003eeU #define _reg_RESERVED_R11 0x000003efU #define _reg_RESERVED_R12 0x000003f0U #define _reg_RESERVED_R13 0x000003f1U #define _reg_RESERVED_R14 0x000003f2U #define _reg_RESERVED_R15 0x000003f3U #define _reg_RESERVED_R16 0x000003f4U #define _reg_RESERVED_R17 0x000003f5U #define _reg_RESERVED_R18 0x000003f6U #define _reg_RESERVED_R19 0x000003f7U #define _reg_RESERVED_R20 0x000003f8U #define _reg_RESERVED_R21 0x000003f9U #define _reg_RESERVED_R22 0x000003faU #define _reg_RESERVED_R23 0x000003fbU #define _reg_PI_INT_STATUS 0x000003fcU #define _reg_PI_INT_ACK 0x000003fdU #define _reg_PI_INT_MASK 0x000003feU #define _reg_PI_BIST_EXP_DATA_P0 0x000003ffU #define _reg_PI_BIST_EXP_DATA_P1 0x00000400U #define _reg_PI_BIST_EXP_DATA_P2 0x00000401U #define _reg_PI_BIST_EXP_DATA_P3 0x00000402U #define _reg_PI_BIST_FAIL_DATA_P0 0x00000403U #define _reg_PI_BIST_FAIL_DATA_P1 0x00000404U #define _reg_PI_BIST_FAIL_DATA_P2 0x00000405U #define _reg_PI_BIST_FAIL_DATA_P3 0x00000406U #define _reg_PI_BIST_FAIL_ADDR_P0 0x00000407U #define _reg_PI_BIST_FAIL_ADDR_P1 0x00000408U #define _reg_PI_BSTLEN 0x00000409U #define _reg_PI_LONG_COUNT_MASK 0x0000040aU #define _reg_PI_CMD_SWAP_EN 0x0000040bU #define _reg_PI_CKE_MUX_0 0x0000040cU #define _reg_PI_CKE_MUX_1 0x0000040dU #define _reg_PI_CKE_MUX_2 0x0000040eU #define _reg_PI_CKE_MUX_3 0x0000040fU #define _reg_PI_CS_MUX_0 0x00000410U #define _reg_PI_CS_MUX_1 0x00000411U #define _reg_PI_CS_MUX_2 0x00000412U #define _reg_PI_CS_MUX_3 0x00000413U #define _reg_PI_RAS_N_MUX 0x00000414U #define _reg_PI_CAS_N_MUX 0x00000415U #define _reg_PI_WE_N_MUX 0x00000416U #define _reg_PI_BANK_MUX_0 0x00000417U #define _reg_PI_BANK_MUX_1 0x00000418U #define _reg_PI_BANK_MUX_2 0x00000419U #define _reg_PI_ODT_MUX_0 0x0000041aU #define _reg_PI_ODT_MUX_1 0x0000041bU #define _reg_PI_ODT_MUX_2 0x0000041cU #define _reg_PI_ODT_MUX_3 0x0000041dU #define _reg_PI_RESET_N_MUX_0 0x0000041eU #define _reg_PI_RESET_N_MUX_1 0x0000041fU #define _reg_PI_RESET_N_MUX_2 0x00000420U #define _reg_PI_RESET_N_MUX_3 0x00000421U #define _reg_PI_DATA_BYTE_SWAP_EN 0x00000422U #define _reg_PI_DATA_BYTE_SWAP_SLICE0 0x00000423U #define _reg_PI_DATA_BYTE_SWAP_SLICE1 0x00000424U #define _reg_PI_DATA_BYTE_SWAP_SLICE2 0x00000425U #define _reg_PI_DATA_BYTE_SWAP_SLICE3 0x00000426U #define _reg_PI_CTRLUPD_REQ_PER_AREF_EN 0x00000427U #define _reg_PI_TDFI_CTRLUPD_MIN 0x00000428U #define _reg_PI_TDFI_CTRLUPD_MAX_F0 0x00000429U #define _reg_PI_TDFI_CTRLUPD_INTERVAL_F0 0x0000042aU #define _reg_PI_TDFI_CTRLUPD_MAX_F1 0x0000042bU #define _reg_PI_TDFI_CTRLUPD_INTERVAL_F1 0x0000042cU #define _reg_PI_TDFI_CTRLUPD_MAX_F2 0x0000042dU #define _reg_PI_TDFI_CTRLUPD_INTERVAL_F2 0x0000042eU #define _reg_PI_UPDATE_ERROR_STATUS 0x0000042fU #define _reg_PI_BIST_GO 0x00000430U #define _reg_PI_BIST_RESULT 0x00000431U #define _reg_PI_ADDR_SPACE 0x00000432U #define _reg_PI_BIST_DATA_CHECK 0x00000433U #define _reg_PI_BIST_ADDR_CHECK 0x00000434U #define _reg_PI_BIST_START_ADDRESS_P0 0x00000435U #define _reg_PI_BIST_START_ADDRESS_P1 0x00000436U #define _reg_PI_BIST_DATA_MASK_P0 0x00000437U #define _reg_PI_BIST_DATA_MASK_P1 0x00000438U #define _reg_PI_BIST_ERR_COUNT 0x00000439U #define _reg_PI_BIST_ERR_STOP 0x0000043aU #define _reg_PI_BIST_ADDR_MASK_0_P0 0x0000043bU #define _reg_PI_BIST_ADDR_MASK_0_P1 0x0000043cU #define _reg_PI_BIST_ADDR_MASK_1_P0 0x0000043dU #define _reg_PI_BIST_ADDR_MASK_1_P1 0x0000043eU #define _reg_PI_BIST_ADDR_MASK_2_P0 0x0000043fU #define _reg_PI_BIST_ADDR_MASK_2_P1 0x00000440U #define _reg_PI_BIST_ADDR_MASK_3_P0 0x00000441U #define _reg_PI_BIST_ADDR_MASK_3_P1 0x00000442U #define _reg_PI_BIST_ADDR_MASK_4_P0 0x00000443U #define _reg_PI_BIST_ADDR_MASK_4_P1 0x00000444U #define _reg_PI_BIST_ADDR_MASK_5_P0 0x00000445U #define _reg_PI_BIST_ADDR_MASK_5_P1 0x00000446U #define _reg_PI_BIST_ADDR_MASK_6_P0 0x00000447U #define _reg_PI_BIST_ADDR_MASK_6_P1 0x00000448U #define _reg_PI_BIST_ADDR_MASK_7_P0 0x00000449U #define _reg_PI_BIST_ADDR_MASK_7_P1 0x0000044aU #define _reg_PI_BIST_ADDR_MASK_8_P0 0x0000044bU #define _reg_PI_BIST_ADDR_MASK_8_P1 0x0000044cU #define _reg_PI_BIST_ADDR_MASK_9_P0 0x0000044dU #define _reg_PI_BIST_ADDR_MASK_9_P1 0x0000044eU #define _reg_PI_BIST_MODE 0x0000044fU #define _reg_PI_BIST_ADDR_MODE 0x00000450U #define _reg_PI_BIST_PAT_MODE 0x00000451U #define _reg_PI_BIST_USER_PAT_P0 0x00000452U #define _reg_PI_BIST_USER_PAT_P1 0x00000453U #define _reg_PI_BIST_USER_PAT_P2 0x00000454U #define _reg_PI_BIST_USER_PAT_P3 0x00000455U #define _reg_PI_BIST_PAT_NUM 0x00000456U #define _reg_PI_BIST_STAGE_0 0x00000457U #define _reg_PI_BIST_STAGE_1 0x00000458U #define _reg_PI_BIST_STAGE_2 0x00000459U #define _reg_PI_BIST_STAGE_3 0x0000045aU #define _reg_PI_BIST_STAGE_4 0x0000045bU #define _reg_PI_BIST_STAGE_5 0x0000045cU #define _reg_PI_BIST_STAGE_6 0x0000045dU #define _reg_PI_BIST_STAGE_7 0x0000045eU #define _reg_PI_COL_DIFF 0x0000045fU #define _reg_PI_SELF_REFRESH_EN 0x00000460U #define _reg_PI_TXSR_F0 0x00000461U #define _reg_PI_TXSR_F1 0x00000462U #define _reg_PI_TXSR_F2 0x00000463U #define _reg_PI_MONITOR_SRC_SEL_0 0x00000464U #define _reg_PI_MONITOR_CAP_SEL_0 0x00000465U #define _reg_PI_MONITOR_0 0x00000466U #define _reg_PI_MONITOR_SRC_SEL_1 0x00000467U #define _reg_PI_MONITOR_CAP_SEL_1 0x00000468U #define _reg_PI_MONITOR_1 0x00000469U #define _reg_PI_MONITOR_SRC_SEL_2 0x0000046aU #define _reg_PI_MONITOR_CAP_SEL_2 0x0000046bU #define _reg_PI_MONITOR_2 0x0000046cU #define _reg_PI_MONITOR_SRC_SEL_3 0x0000046dU #define _reg_PI_MONITOR_CAP_SEL_3 0x0000046eU #define _reg_PI_MONITOR_3 0x0000046fU #define _reg_PI_MONITOR_SRC_SEL_4 0x00000470U #define _reg_PI_MONITOR_CAP_SEL_4 0x00000471U #define _reg_PI_MONITOR_4 0x00000472U #define _reg_PI_MONITOR_SRC_SEL_5 0x00000473U #define _reg_PI_MONITOR_CAP_SEL_5 0x00000474U #define _reg_PI_MONITOR_5 0x00000475U #define _reg_PI_MONITOR_SRC_SEL_6 0x00000476U #define _reg_PI_MONITOR_CAP_SEL_6 0x00000477U #define _reg_PI_MONITOR_6 0x00000478U #define _reg_PI_MONITOR_SRC_SEL_7 0x00000479U #define _reg_PI_MONITOR_CAP_SEL_7 0x0000047aU #define _reg_PI_MONITOR_7 0x0000047bU #define _reg_PI_MONITOR_STROBE 0x0000047cU #define _reg_PI_DLL_LOCK 0x0000047dU #define _reg_PI_FREQ_NUMBER_STATUS 0x0000047eU #define _reg_RESERVED_R24 0x0000047fU #define _reg_PI_PHYMSTR_TYPE 0x00000480U #define _reg_PI_POWER_REDUC_EN 0x00000481U #define _reg_RESERVED_R25 0x00000482U #define _reg_RESERVED_R26 0x00000483U #define _reg_RESERVED_R27 0x00000484U #define _reg_RESERVED_R28 0x00000485U #define _reg_RESERVED_R29 0x00000486U #define _reg_RESERVED_R30 0x00000487U #define _reg_RESERVED_R31 0x00000488U #define _reg_RESERVED_R32 0x00000489U #define _reg_RESERVED_R33 0x0000048aU #define _reg_RESERVED_R34 0x0000048bU #define _reg_RESERVED_R35 0x0000048cU #define _reg_RESERVED_R36 0x0000048dU #define _reg_RESERVED_R37 0x0000048eU #define _reg_RESERVED_R38 0x0000048fU #define _reg_RESERVED_R39 0x00000490U #define _reg_PI_WRLVL_MAX_STROBE_PEND 0x00000491U #define _reg_PI_TSDO_F0 0x00000492U #define _reg_PI_TSDO_F1 0x00000493U #define _reg_PI_TSDO_F2 0x00000494U #define DDR_REGDEF_ADR(regdef) ((regdef) & 0xffff) #define DDR_REGDEF_LEN(regdef) (((regdef) >> 16) & 0xff) #define DDR_REGDEF_LSB(regdef) (((regdef) >> 24) & 0xff) static const uint32_t DDR_REGDEF_TBL[4][1173] = { { /*0000*/ 0xffffffffU, /*0001*/ 0xffffffffU, /*0002*/ 0x000b0400U, /*0003*/ 0xffffffffU, /*0004*/ 0xffffffffU, /*0005*/ 0x10010400U, /*0006*/ 0x18050400U, /*0007*/ 0x00050401U, /*0008*/ 0x08050401U, /*0009*/ 0x10050401U, /*000a*/ 0x18050401U, /*000b*/ 0x00050402U, /*000c*/ 0x08050402U, /*000d*/ 0x10050402U, /*000e*/ 0x18050402U, /*000f*/ 0x00040403U, /*0010*/ 0x08030403U, /*0011*/ 0x00180404U, /*0012*/ 0x18030404U, /*0013*/ 0x00180405U, /*0014*/ 0x18020405U, /*0015*/ 0x00010406U, /*0016*/ 0x08020406U, /*0017*/ 0x10010406U, /*0018*/ 0x18010406U, /*0019*/ 0x00020407U, /*001a*/ 0x08040407U, /*001b*/ 0x10040407U, /*001c*/ 0x18040407U, /*001d*/ 0x000a0408U, /*001e*/ 0x10040408U, /*001f*/ 0xffffffffU, /*0020*/ 0xffffffffU, /*0021*/ 0x18070408U, /*0022*/ 0xffffffffU, /*0023*/ 0xffffffffU, /*0024*/ 0xffffffffU, /*0025*/ 0xffffffffU, /*0026*/ 0xffffffffU, /*0027*/ 0xffffffffU, /*0028*/ 0x000a0409U, /*0029*/ 0x10040409U, /*002a*/ 0x18010409U, /*002b*/ 0x0001040aU, /*002c*/ 0x0802040aU, /*002d*/ 0x1009040aU, /*002e*/ 0x0009040bU, /*002f*/ 0x1002040bU, /*0030*/ 0x0020040cU, /*0031*/ 0xffffffffU, /*0032*/ 0x0001040dU, /*0033*/ 0xffffffffU, /*0034*/ 0xffffffffU, /*0035*/ 0xffffffffU, /*0036*/ 0xffffffffU, /*0037*/ 0x0020040eU, /*0038*/ 0x0020040fU, /*0039*/ 0x00200410U, /*003a*/ 0x00200411U, /*003b*/ 0x00030412U, /*003c*/ 0x08010412U, /*003d*/ 0x10030412U, /*003e*/ 0x18030412U, /*003f*/ 0x00040413U, /*0040*/ 0x08040413U, /*0041*/ 0x10040413U, /*0042*/ 0x18040413U, /*0043*/ 0x00010414U, /*0044*/ 0x08010414U, /*0045*/ 0x10060414U, /*0046*/ 0x18040414U, /*0047*/ 0xffffffffU, /*0048*/ 0x00060415U, /*0049*/ 0x08040415U, /*004a*/ 0x10060415U, /*004b*/ 0x18040415U, /*004c*/ 0x00020416U, /*004d*/ 0x08050416U, /*004e*/ 0x10080416U, /*004f*/ 0x00200417U, /*0050*/ 0x00060418U, /*0051*/ 0x08030418U, /*0052*/ 0x100b0418U, /*0053*/ 0x00040419U, /*0054*/ 0x08040419U, /*0055*/ 0x10040419U, /*0056*/ 0xffffffffU, /*0057*/ 0x18010419U, /*0058*/ 0x0009041aU, /*0059*/ 0x0020041bU, /*005a*/ 0x0020041cU, /*005b*/ 0x0020041dU, /*005c*/ 0x0020041eU, /*005d*/ 0x0010041fU, /*005e*/ 0x00200420U, /*005f*/ 0x00010421U, /*0060*/ 0x08060421U, /*0061*/ 0x10080421U, /*0062*/ 0x00200422U, /*0063*/ 0xffffffffU, /*0064*/ 0x000a0423U, /*0065*/ 0x10060423U, /*0066*/ 0x18070423U, /*0067*/ 0x00080424U, /*0068*/ 0x08080424U, /*0069*/ 0x100a0424U, /*006a*/ 0x00070425U, /*006b*/ 0x08080425U, /*006c*/ 0x10080425U, /*006d*/ 0x18030425U, /*006e*/ 0x000a0426U, /*006f*/ 0x100a0426U, /*0070*/ 0x00110427U, /*0071*/ 0x00090428U, /*0072*/ 0x10090428U, /*0073*/ 0x00100429U, /*0074*/ 0x100e0429U, /*0075*/ 0x000e042aU, /*0076*/ 0x100c042aU, /*0077*/ 0x000a042bU, /*0078*/ 0x100a042bU, /*0079*/ 0x0002042cU, /*007a*/ 0x0020042dU, /*007b*/ 0x000b042eU, /*007c*/ 0x100b042eU, /*007d*/ 0x0020042fU, /*007e*/ 0x00120430U, /*007f*/ 0x00200431U, /*0080*/ 0x00200432U, /*0081*/ 0xffffffffU, /*0082*/ 0xffffffffU, /*0083*/ 0x00010433U, /*0084*/ 0x08010433U, /*0085*/ 0x10080433U, /*0086*/ 0x000c0434U, /*0087*/ 0x100c0434U, /*0088*/ 0x000c0435U, /*0089*/ 0x100c0435U, /*008a*/ 0x000c0436U, /*008b*/ 0x100c0436U, /*008c*/ 0x000c0437U, /*008d*/ 0x100c0437U, /*008e*/ 0x000c0438U, /*008f*/ 0x100c0438U, /*0090*/ 0x000c0439U, /*0091*/ 0x100b0439U, /*0092*/ 0xffffffffU, /*0093*/ 0xffffffffU, /*0094*/ 0x000b043aU, /*0095*/ 0x100b043aU, /*0096*/ 0x000b043bU, /*0097*/ 0x100b043bU, /*0098*/ 0x000b043cU, /*0099*/ 0x100b043cU, /*009a*/ 0x000b043dU, /*009b*/ 0x100b043dU, /*009c*/ 0x000b043eU, /*009d*/ 0x100a043eU, /*009e*/ 0xffffffffU, /*009f*/ 0x000a043fU, /*00a0*/ 0x100a043fU, /*00a1*/ 0x000a0440U, /*00a2*/ 0x100a0440U, /*00a3*/ 0x000a0441U, /*00a4*/ 0x100a0441U, /*00a5*/ 0x000a0442U, /*00a6*/ 0x100a0442U, /*00a7*/ 0xffffffffU, /*00a8*/ 0x000a0443U, /*00a9*/ 0x100a0443U, /*00aa*/ 0x000a0444U, /*00ab*/ 0x100a0444U, /*00ac*/ 0x000a0445U, /*00ad*/ 0x100a0445U, /*00ae*/ 0x000a0446U, /*00af*/ 0x100a0446U, /*00b0*/ 0x000a0447U, /*00b1*/ 0x100a0447U, /*00b2*/ 0x000a0448U, /*00b3*/ 0x100a0448U, /*00b4*/ 0x000a0449U, /*00b5*/ 0x100a0449U, /*00b6*/ 0x000a044aU, /*00b7*/ 0x100a044aU, /*00b8*/ 0x000a044bU, /*00b9*/ 0x100a044bU, /*00ba*/ 0x000a044cU, /*00bb*/ 0x1004044cU, /*00bc*/ 0x1803044cU, /*00bd*/ 0x000a044dU, /*00be*/ 0x100a044dU, /*00bf*/ 0x0001044eU, /*00c0*/ 0x080a044eU, /*00c1*/ 0x1804044eU, /*00c2*/ 0x000b044fU, /*00c3*/ 0x100a044fU, /*00c4*/ 0xffffffffU, /*00c5*/ 0x00080450U, /*00c6*/ 0x08080450U, /*00c7*/ 0x10080450U, /*00c8*/ 0x18080450U, /*00c9*/ 0x00080451U, /*00ca*/ 0xffffffffU, /*00cb*/ 0x08080451U, /*00cc*/ 0x10010451U, /*00cd*/ 0x18080451U, /*00ce*/ 0x00080452U, /*00cf*/ 0x08020452U, /*00d0*/ 0x10020452U, /*00d1*/ 0x18040452U, /*00d2*/ 0x00040453U, /*00d3*/ 0xffffffffU, /*00d4*/ 0x08040453U, /*00d5*/ 0x100a0453U, /*00d6*/ 0x00060454U, /*00d7*/ 0x08080454U, /*00d8*/ 0xffffffffU, /*00d9*/ 0x10040454U, /*00da*/ 0x18040454U, /*00db*/ 0x00050455U, /*00dc*/ 0x08040455U, /*00dd*/ 0x10050455U, /*00de*/ 0x000a0456U, /*00df*/ 0x100a0456U, /*00e0*/ 0x00080457U, /*00e1*/ 0xffffffffU, /*00e2*/ 0x08040457U, /*00e3*/ 0xffffffffU, /*00e4*/ 0xffffffffU, /*00e5*/ 0x00050600U, /*00e6*/ 0x08050600U, /*00e7*/ 0x10050600U, /*00e8*/ 0x18050600U, /*00e9*/ 0x00050601U, /*00ea*/ 0x08050601U, /*00eb*/ 0x100b0601U, /*00ec*/ 0x00010602U, /*00ed*/ 0x08030602U, /*00ee*/ 0x00200603U, /*00ef*/ 0xffffffffU, /*00f0*/ 0x00030604U, /*00f1*/ 0x080a0604U, /*00f2*/ 0xffffffffU, /*00f3*/ 0xffffffffU, /*00f4*/ 0x18030604U, /*00f5*/ 0x00030605U, /*00f6*/ 0x08010605U, /*00f7*/ 0x10010605U, /*00f8*/ 0x18060605U, /*00f9*/ 0xffffffffU, /*00fa*/ 0xffffffffU, /*00fb*/ 0xffffffffU, /*00fc*/ 0x00020606U, /*00fd*/ 0x08030606U, /*00fe*/ 0x10010606U, /*00ff*/ 0x000f0607U, /*0100*/ 0x00200608U, /*0101*/ 0x00200609U, /*0102*/ 0x000b060aU, /*0103*/ 0x100b060aU, /*0104*/ 0x000b060bU, /*0105*/ 0xffffffffU, /*0106*/ 0xffffffffU, /*0107*/ 0x0018060cU, /*0108*/ 0x0018060dU, /*0109*/ 0x0018060eU, /*010a*/ 0x0018060fU, /*010b*/ 0x1804060fU, /*010c*/ 0x00050610U, /*010d*/ 0x08020610U, /*010e*/ 0x10040610U, /*010f*/ 0x18040610U, /*0110*/ 0x00010611U, /*0111*/ 0x08010611U, /*0112*/ 0x10010611U, /*0113*/ 0x18030611U, /*0114*/ 0x00200612U, /*0115*/ 0x00200613U, /*0116*/ 0x00010614U, /*0117*/ 0x08140614U, /*0118*/ 0x00140615U, /*0119*/ 0x00140616U, /*011a*/ 0x00140617U, /*011b*/ 0x00140618U, /*011c*/ 0x00140619U, /*011d*/ 0x0014061aU, /*011e*/ 0x0014061bU, /*011f*/ 0x0018061cU, /*0120*/ 0x000a061dU, /*0121*/ 0x1006061dU, /*0122*/ 0x1806061dU, /*0123*/ 0x0006061eU, /*0124*/ 0xffffffffU, /*0125*/ 0xffffffffU, /*0126*/ 0x0008061fU, /*0127*/ 0x080b061fU, /*0128*/ 0x000b0620U, /*0129*/ 0x100b0620U, /*012a*/ 0x000b0621U, /*012b*/ 0x100b0621U, /*012c*/ 0x000b0622U, /*012d*/ 0x10040622U, /*012e*/ 0x000a0623U, /*012f*/ 0x10060623U, /*0130*/ 0x18080623U, /*0131*/ 0xffffffffU, /*0132*/ 0x00040624U, /*0133*/ 0xffffffffU, /*0134*/ 0xffffffffU, /*0135*/ 0x00010700U, /*0136*/ 0x08020700U, /*0137*/ 0x10050700U, /*0138*/ 0x18050700U, /*0139*/ 0x00050701U, /*013a*/ 0x08050701U, /*013b*/ 0x100b0701U, /*013c*/ 0x00050702U, /*013d*/ 0x08010702U, /*013e*/ 0x10010702U, /*013f*/ 0xffffffffU, /*0140*/ 0x18010702U, /*0141*/ 0x00010703U, /*0142*/ 0x08040703U, /*0143*/ 0x100b0703U, /*0144*/ 0x000b0704U, /*0145*/ 0xffffffffU, /*0146*/ 0x10040704U, /*0147*/ 0x000b0705U, /*0148*/ 0x10040705U, /*0149*/ 0x18010705U, /*014a*/ 0x00010706U, /*014b*/ 0x08010706U, /*014c*/ 0x00200707U, /*014d*/ 0x00200708U, /*014e*/ 0x00080709U, /*014f*/ 0x080a0709U, /*0150*/ 0x18050709U, /*0151*/ 0x000a070aU, /*0152*/ 0x1003070aU, /*0153*/ 0x1803070aU, /*0154*/ 0x0001070bU, /*0155*/ 0x0802070bU, /*0156*/ 0x1001070bU, /*0157*/ 0x1801070bU, /*0158*/ 0x0001070cU, /*0159*/ 0x0802070cU, /*015a*/ 0xffffffffU, /*015b*/ 0xffffffffU, /*015c*/ 0xffffffffU, /*015d*/ 0xffffffffU, /*015e*/ 0xffffffffU, /*015f*/ 0xffffffffU, /*0160*/ 0xffffffffU, /*0161*/ 0xffffffffU, /*0162*/ 0xffffffffU, /*0163*/ 0xffffffffU, /*0164*/ 0xffffffffU, /*0165*/ 0xffffffffU, /*0166*/ 0x1001070cU, /*0167*/ 0x1801070cU, /*0168*/ 0x000d070dU, /*0169*/ 0xffffffffU, /*016a*/ 0xffffffffU, /*016b*/ 0x0005070eU, /*016c*/ 0x0001070fU, /*016d*/ 0x080e070fU, /*016e*/ 0x000e0710U, /*016f*/ 0x100e0710U, /*0170*/ 0x000e0711U, /*0171*/ 0x100e0711U, /*0172*/ 0x00040712U, /*0173*/ 0xffffffffU, /*0174*/ 0xffffffffU, /*0175*/ 0xffffffffU, /*0176*/ 0xffffffffU, /*0177*/ 0x080b0712U, /*0178*/ 0x000b0713U, /*0179*/ 0x100b0713U, /*017a*/ 0x000b0714U, /*017b*/ 0xffffffffU, /*017c*/ 0xffffffffU, /*017d*/ 0xffffffffU, /*017e*/ 0xffffffffU, /*017f*/ 0x000d0715U, /*0180*/ 0xffffffffU, /*0181*/ 0xffffffffU, /*0182*/ 0x10100715U, /*0183*/ 0x00080716U, /*0184*/ 0xffffffffU, /*0185*/ 0x08100716U, /*0186*/ 0x00100717U, /*0187*/ 0x10100717U, /*0188*/ 0x00100718U, /*0189*/ 0x10100718U, /*018a*/ 0x00030719U, /*018b*/ 0x08040719U, /*018c*/ 0x10010719U, /*018d*/ 0x18040719U, /*018e*/ 0xffffffffU, /*018f*/ 0xffffffffU, /*0190*/ 0x0001071aU, /*0191*/ 0x0812071aU, /*0192*/ 0x000a071bU, /*0193*/ 0x100c071bU, /*0194*/ 0x0012071cU, /*0195*/ 0x0014071dU, /*0196*/ 0x0012071eU, /*0197*/ 0x0011071fU, /*0198*/ 0x00110720U, /*0199*/ 0x00120721U, /*019a*/ 0x00120722U, /*019b*/ 0x00120723U, /*019c*/ 0x00120724U, /*019d*/ 0x00120725U, /*019e*/ 0x00120726U, /*019f*/ 0x00120727U, /*01a0*/ 0x00120728U, /*01a1*/ 0xffffffffU, /*01a2*/ 0xffffffffU, /*01a3*/ 0x00190729U, /*01a4*/ 0x0019072aU, /*01a5*/ 0x0020072bU, /*01a6*/ 0x0017072cU, /*01a7*/ 0x1808072cU, /*01a8*/ 0x0001072dU, /*01a9*/ 0x0801072dU, /*01aa*/ 0x0020072eU, /*01ab*/ 0x0008072fU, /*01ac*/ 0xffffffffU, /*01ad*/ 0x0803072fU, /*01ae*/ 0x00180730U, /*01af*/ 0x00180731U, /*01b0*/ 0xffffffffU, /*01b1*/ 0xffffffffU, /*01b2*/ 0xffffffffU, /*01b3*/ 0xffffffffU, /*01b4*/ 0xffffffffU, /*01b5*/ 0xffffffffU, /*01b6*/ 0xffffffffU, /*01b7*/ 0xffffffffU, /*01b8*/ 0xffffffffU, /*01b9*/ 0xffffffffU, /*01ba*/ 0xffffffffU, /*01bb*/ 0xffffffffU, /*01bc*/ 0xffffffffU, /*01bd*/ 0xffffffffU, /*01be*/ 0xffffffffU, /*01bf*/ 0x00100732U, /*01c0*/ 0x10010732U, /*01c1*/ 0x18010732U, /*01c2*/ 0x00050733U, /*01c3*/ 0x00200734U, /*01c4*/ 0x00090735U, /*01c5*/ 0xffffffffU, /*01c6*/ 0xffffffffU, /*01c7*/ 0x00200736U, /*01c8*/ 0x00040737U, /*01c9*/ 0x08100737U, /*01ca*/ 0x18060737U, /*01cb*/ 0x00100738U, /*01cc*/ 0xffffffffU, /*01cd*/ 0xffffffffU, /*01ce*/ 0xffffffffU, /*01cf*/ 0xffffffffU, /*01d0*/ 0xffffffffU, /*01d1*/ 0xffffffffU, /*01d2*/ 0xffffffffU, /*01d3*/ 0xffffffffU, /*01d4*/ 0x00200739U, /*01d5*/ 0x000b073aU, /*01d6*/ 0xffffffffU, /*01d7*/ 0xffffffffU, /*01d8*/ 0xffffffffU, /*01d9*/ 0xffffffffU, /*01da*/ 0xffffffffU, /*01db*/ 0xffffffffU, /*01dc*/ 0xffffffffU, /*01dd*/ 0xffffffffU, /*01de*/ 0x00010200U, /*01df*/ 0x08040200U, /*01e0*/ 0x10100200U, /*01e1*/ 0x00010201U, /*01e2*/ 0x08010201U, /*01e3*/ 0xffffffffU, /*01e4*/ 0xffffffffU, /*01e5*/ 0x10100201U, /*01e6*/ 0xffffffffU, /*01e7*/ 0xffffffffU, /*01e8*/ 0xffffffffU, /*01e9*/ 0xffffffffU, /*01ea*/ 0xffffffffU, /*01eb*/ 0xffffffffU, /*01ec*/ 0xffffffffU, /*01ed*/ 0xffffffffU, /*01ee*/ 0xffffffffU, /*01ef*/ 0x00200202U, /*01f0*/ 0x00100203U, /*01f1*/ 0x00200204U, /*01f2*/ 0x00100205U, /*01f3*/ 0x00200206U, /*01f4*/ 0x00100207U, /*01f5*/ 0x10100207U, /*01f6*/ 0x00200208U, /*01f7*/ 0x00200209U, /*01f8*/ 0x0020020aU, /*01f9*/ 0x0020020bU, /*01fa*/ 0x0010020cU, /*01fb*/ 0x0020020dU, /*01fc*/ 0x0020020eU, /*01fd*/ 0x0020020fU, /*01fe*/ 0x00200210U, /*01ff*/ 0x00100211U, /*0200*/ 0x00200212U, /*0201*/ 0x00200213U, /*0202*/ 0x00200214U, /*0203*/ 0x00200215U, /*0204*/ 0x00090216U, /*0205*/ 0x10010216U, /*0206*/ 0x00200217U, /*0207*/ 0x00050218U, /*0208*/ 0x08010218U, /*0209*/ 0x10080218U, /*020a*/ 0x18080218U, /*020b*/ 0x001c0219U, /*020c*/ 0x001c021aU, /*020d*/ 0x001c021bU, /*020e*/ 0x001c021cU, /*020f*/ 0x001c021dU, /*0210*/ 0x001c021eU, /*0211*/ 0x001c021fU, /*0212*/ 0x001c0220U, /*0213*/ 0x001c0221U, /*0214*/ 0x001c0222U, /*0215*/ 0x001c0223U, /*0216*/ 0x001c0224U, /*0217*/ 0x001c0225U, /*0218*/ 0x001c0226U, /*0219*/ 0x001c0227U, /*021a*/ 0x001c0228U, /*021b*/ 0x00010229U, /*021c*/ 0x08010229U, /*021d*/ 0x10010229U, /*021e*/ 0x18040229U, /*021f*/ 0x0008022aU, /*0220*/ 0x0808022aU, /*0221*/ 0x1008022aU, /*0222*/ 0x1804022aU, /*0223*/ 0x0006022bU, /*0224*/ 0xffffffffU, /*0225*/ 0x0807022bU, /*0226*/ 0x1006022bU, /*0227*/ 0xffffffffU, /*0228*/ 0x1807022bU, /*0229*/ 0x0006022cU, /*022a*/ 0xffffffffU, /*022b*/ 0x0807022cU, /*022c*/ 0x1002022cU, /*022d*/ 0x1801022cU, /*022e*/ 0xffffffffU, /*022f*/ 0x000a022dU, /*0230*/ 0x1010022dU, /*0231*/ 0x000a022eU, /*0232*/ 0x1010022eU, /*0233*/ 0x000a022fU, /*0234*/ 0x1010022fU, /*0235*/ 0xffffffffU, /*0236*/ 0x00100230U, /*0237*/ 0xffffffffU, /*0238*/ 0xffffffffU, /*0239*/ 0x10010230U, /*023a*/ 0x18010230U, /*023b*/ 0x00010231U, /*023c*/ 0x08010231U, /*023d*/ 0x10010231U, /*023e*/ 0x18010231U, /*023f*/ 0x00020232U, /*0240*/ 0x08020232U, /*0241*/ 0x10020232U, /*0242*/ 0x18020232U, /*0243*/ 0x00020233U, /*0244*/ 0x08030233U, /*0245*/ 0x10010233U, /*0246*/ 0x18010233U, /*0247*/ 0x00010234U, /*0248*/ 0x08010234U, /*0249*/ 0xffffffffU, /*024a*/ 0x10020234U, /*024b*/ 0x18010234U, /*024c*/ 0x00010235U, /*024d*/ 0xffffffffU, /*024e*/ 0x08020235U, /*024f*/ 0x10010235U, /*0250*/ 0x18010235U, /*0251*/ 0xffffffffU, /*0252*/ 0x00020236U, /*0253*/ 0x08010236U, /*0254*/ 0x10010236U, /*0255*/ 0xffffffffU, /*0256*/ 0x18020236U, /*0257*/ 0x00070237U, /*0258*/ 0x08010237U, /*0259*/ 0x10010237U, /*025a*/ 0x18010237U, /*025b*/ 0x00010238U, /*025c*/ 0x08010238U, /*025d*/ 0x10010238U, /*025e*/ 0xffffffffU, /*025f*/ 0x18010238U, /*0260*/ 0x00040239U, /*0261*/ 0x08040239U, /*0262*/ 0x10040239U, /*0263*/ 0x18010239U, /*0264*/ 0x0002023aU, /*0265*/ 0x0806023aU, /*0266*/ 0x1006023aU, /*0267*/ 0xffffffffU, /*0268*/ 0xffffffffU, /*0269*/ 0xffffffffU, /*026a*/ 0x1802023aU, /*026b*/ 0x0010023bU, /*026c*/ 0x1001023bU, /*026d*/ 0x1801023bU, /*026e*/ 0xffffffffU, /*026f*/ 0x0004023cU, /*0270*/ 0x0801023cU, /*0271*/ 0x1004023cU, /*0272*/ 0x1802023cU, /*0273*/ 0x0008023dU, /*0274*/ 0xffffffffU, /*0275*/ 0xffffffffU, /*0276*/ 0xffffffffU, /*0277*/ 0x080a023dU, /*0278*/ 0x0020023eU, /*0279*/ 0x0020023fU, /*027a*/ 0x00050240U, /*027b*/ 0x08010240U, /*027c*/ 0x10050240U, /*027d*/ 0x18080240U, /*027e*/ 0x00010241U, /*027f*/ 0x08080241U, /*0280*/ 0x10010241U, /*0281*/ 0x18080241U, /*0282*/ 0x00010242U, /*0283*/ 0x08040242U, /*0284*/ 0x10040242U, /*0285*/ 0x18040242U, /*0286*/ 0x00040243U, /*0287*/ 0x08040243U, /*0288*/ 0x10040243U, /*0289*/ 0x18040243U, /*028a*/ 0x00040244U, /*028b*/ 0x08040244U, /*028c*/ 0x10040244U, /*028d*/ 0x18010244U, /*028e*/ 0x00040245U, /*028f*/ 0x08040245U, /*0290*/ 0x10040245U, /*0291*/ 0x18040245U, /*0292*/ 0x00040246U, /*0293*/ 0x08040246U, /*0294*/ 0x10060246U, /*0295*/ 0x18060246U, /*0296*/ 0x00060247U, /*0297*/ 0x08060247U, /*0298*/ 0x10060247U, /*0299*/ 0x18060247U, /*029a*/ 0xffffffffU, /*029b*/ 0x00010248U, /*029c*/ 0x08010248U, /*029d*/ 0x10020248U, /*029e*/ 0xffffffffU, /*029f*/ 0xffffffffU, /*02a0*/ 0xffffffffU, /*02a1*/ 0xffffffffU, /*02a2*/ 0xffffffffU, /*02a3*/ 0xffffffffU, /*02a4*/ 0xffffffffU, /*02a5*/ 0xffffffffU, /*02a6*/ 0x18040248U, /*02a7*/ 0x00040249U, /*02a8*/ 0x08010249U, /*02a9*/ 0x10010249U, /*02aa*/ 0xffffffffU, /*02ab*/ 0x18010249U, /*02ac*/ 0x0001024aU, /*02ad*/ 0xffffffffU, /*02ae*/ 0x0801024aU, /*02af*/ 0x1001024aU, /*02b0*/ 0x1801024aU, /*02b1*/ 0x0004024bU, /*02b2*/ 0x0804024bU, /*02b3*/ 0x100a024bU, /*02b4*/ 0x0020024cU, /*02b5*/ 0x0004024dU, /*02b6*/ 0x0808024dU, /*02b7*/ 0xffffffffU, /*02b8*/ 0xffffffffU, /*02b9*/ 0xffffffffU, /*02ba*/ 0xffffffffU, /*02bb*/ 0xffffffffU, /*02bc*/ 0xffffffffU, /*02bd*/ 0x1002024dU, /*02be*/ 0x1802024dU, /*02bf*/ 0x0020024eU, /*02c0*/ 0x0002024fU, /*02c1*/ 0x0810024fU, /*02c2*/ 0x00100250U, /*02c3*/ 0x10040250U, /*02c4*/ 0x18040250U, /*02c5*/ 0x00050251U, /*02c6*/ 0x08050251U, /*02c7*/ 0xffffffffU, /*02c8*/ 0xffffffffU, /*02c9*/ 0xffffffffU, /*02ca*/ 0xffffffffU, /*02cb*/ 0x10010251U, /*02cc*/ 0x18010251U, /*02cd*/ 0x00070252U, /*02ce*/ 0x08070252U, /*02cf*/ 0x10070252U, /*02d0*/ 0x18070252U, /*02d1*/ 0x00070253U, /*02d2*/ 0x08070253U, /*02d3*/ 0x10070253U, /*02d4*/ 0x18070253U, /*02d5*/ 0x00070254U, /*02d6*/ 0x08070254U, /*02d7*/ 0x10070254U, /*02d8*/ 0xffffffffU, /*02d9*/ 0xffffffffU, /*02da*/ 0xffffffffU, /*02db*/ 0xffffffffU, /*02dc*/ 0xffffffffU, /*02dd*/ 0xffffffffU, /*02de*/ 0x18030254U, /*02df*/ 0x00010255U, /*02e0*/ 0x08020255U, /*02e1*/ 0x10010255U, /*02e2*/ 0x18040255U, /*02e3*/ 0x00020256U, /*02e4*/ 0x08010256U, /*02e5*/ 0x10010256U, /*02e6*/ 0xffffffffU, /*02e7*/ 0x18010256U, /*02e8*/ 0x00040257U, /*02e9*/ 0x08080257U, /*02ea*/ 0x100a0257U, /*02eb*/ 0x000a0258U, /*02ec*/ 0x100a0258U, /*02ed*/ 0x000a0259U, /*02ee*/ 0x100a0259U, /*02ef*/ 0x000a025aU, /*02f0*/ 0x0020025bU, /*02f1*/ 0x0020025cU, /*02f2*/ 0x0001025dU, /*02f3*/ 0xffffffffU, /*02f4*/ 0xffffffffU, /*02f5*/ 0xffffffffU, /*02f6*/ 0x0802025dU, /*02f7*/ 0x1002025dU, /*02f8*/ 0x0010025eU, /*02f9*/ 0x1005025eU, /*02fa*/ 0x1806025eU, /*02fb*/ 0x0005025fU, /*02fc*/ 0x0805025fU, /*02fd*/ 0x100e025fU, /*02fe*/ 0x00050260U, /*02ff*/ 0x080e0260U, /*0300*/ 0x18050260U, /*0301*/ 0x000e0261U, /*0302*/ 0x10050261U, /*0303*/ 0x18010261U, /*0304*/ 0x00050262U, /*0305*/ 0x08050262U, /*0306*/ 0x100a0262U, /*0307*/ 0x000a0263U, /*0308*/ 0x10050263U, /*0309*/ 0x18050263U, /*030a*/ 0x000a0264U, /*030b*/ 0x100a0264U, /*030c*/ 0x00050265U, /*030d*/ 0x08050265U, /*030e*/ 0x100a0265U, /*030f*/ 0x000a0266U, /*0310*/ 0xffffffffU, /*0311*/ 0xffffffffU, /*0312*/ 0xffffffffU, /*0313*/ 0xffffffffU, /*0314*/ 0xffffffffU, /*0315*/ 0xffffffffU, /*0316*/ 0x10070266U, /*0317*/ 0x18070266U, /*0318*/ 0x00040267U, /*0319*/ 0x08040267U, /*031a*/ 0xffffffffU, /*031b*/ 0xffffffffU, /*031c*/ 0xffffffffU, /*031d*/ 0x10040267U, /*031e*/ 0x18080267U, /*031f*/ 0x00080268U, /*0320*/ 0x08040268U, /*0321*/ 0xffffffffU, /*0322*/ 0xffffffffU, /*0323*/ 0xffffffffU, /*0324*/ 0x10040268U, /*0325*/ 0xffffffffU, /*0326*/ 0xffffffffU, /*0327*/ 0xffffffffU, /*0328*/ 0x18040268U, /*0329*/ 0xffffffffU, /*032a*/ 0xffffffffU, /*032b*/ 0xffffffffU, /*032c*/ 0x00040269U, /*032d*/ 0x08050269U, /*032e*/ 0x10070269U, /*032f*/ 0x18080269U, /*0330*/ 0x0010026aU, /*0331*/ 0x1008026aU, /*0332*/ 0x0010026bU, /*0333*/ 0x1008026bU, /*0334*/ 0x0010026cU, /*0335*/ 0x1008026cU, /*0336*/ 0x1808026cU, /*0337*/ 0x0001026dU, /*0338*/ 0x0801026dU, /*0339*/ 0x1006026dU, /*033a*/ 0x1806026dU, /*033b*/ 0x0006026eU, /*033c*/ 0xffffffffU, /*033d*/ 0x0801026eU, /*033e*/ 0x1003026eU, /*033f*/ 0xffffffffU, /*0340*/ 0xffffffffU, /*0341*/ 0xffffffffU, /*0342*/ 0x000a026fU, /*0343*/ 0x100a026fU, /*0344*/ 0x00040270U, /*0345*/ 0x08010270U, /*0346*/ 0x10040270U, /*0347*/ 0xffffffffU, /*0348*/ 0xffffffffU, /*0349*/ 0xffffffffU, /*034a*/ 0xffffffffU, /*034b*/ 0xffffffffU, /*034c*/ 0xffffffffU, /*034d*/ 0x18070270U, /*034e*/ 0x00070271U, /*034f*/ 0x08050271U, /*0350*/ 0x10050271U, /*0351*/ 0xffffffffU, /*0352*/ 0xffffffffU, /*0353*/ 0xffffffffU, /*0354*/ 0x18040271U, /*0355*/ 0x00010272U, /*0356*/ 0x08010272U, /*0357*/ 0x10020272U, /*0358*/ 0x18080272U, /*0359*/ 0x00200273U, /*035a*/ 0x00200274U, /*035b*/ 0x00100275U, /*035c*/ 0xffffffffU, /*035d*/ 0xffffffffU, /*035e*/ 0xffffffffU, /*035f*/ 0x10020275U, /*0360*/ 0x18010275U, /*0361*/ 0xffffffffU, /*0362*/ 0x00020276U, /*0363*/ 0x08080276U, /*0364*/ 0x10080276U, /*0365*/ 0x18080276U, /*0366*/ 0x00080277U, /*0367*/ 0x08080277U, /*0368*/ 0x10080277U, /*0369*/ 0xffffffffU, /*036a*/ 0x18080277U, /*036b*/ 0x00080278U, /*036c*/ 0x08080278U, /*036d*/ 0x10080278U, /*036e*/ 0x18080278U, /*036f*/ 0x00080279U, /*0370*/ 0xffffffffU, /*0371*/ 0x08080279U, /*0372*/ 0x10080279U, /*0373*/ 0x18080279U, /*0374*/ 0x0008027aU, /*0375*/ 0x0808027aU, /*0376*/ 0x1008027aU, /*0377*/ 0xffffffffU, /*0378*/ 0x1808027aU, /*0379*/ 0x0008027bU, /*037a*/ 0x0808027bU, /*037b*/ 0x1008027bU, /*037c*/ 0x1808027bU, /*037d*/ 0x0008027cU, /*037e*/ 0x0808027cU, /*037f*/ 0xffffffffU, /*0380*/ 0x1008027cU, /*0381*/ 0x1808027cU, /*0382*/ 0x0008027dU, /*0383*/ 0x0808027dU, /*0384*/ 0x1008027dU, /*0385*/ 0x1808027dU, /*0386*/ 0xffffffffU, /*0387*/ 0x0008027eU, /*0388*/ 0x0808027eU, /*0389*/ 0x1008027eU, /*038a*/ 0x1808027eU, /*038b*/ 0x0008027fU, /*038c*/ 0x0808027fU, /*038d*/ 0xffffffffU, /*038e*/ 0x1008027fU, /*038f*/ 0x1808027fU, /*0390*/ 0x00080280U, /*0391*/ 0x08080280U, /*0392*/ 0x10080280U, /*0393*/ 0x18080280U, /*0394*/ 0x00080281U, /*0395*/ 0xffffffffU, /*0396*/ 0x08080281U, /*0397*/ 0x10080281U, /*0398*/ 0x18080281U, /*0399*/ 0x00080282U, /*039a*/ 0x08080282U, /*039b*/ 0x10080282U, /*039c*/ 0xffffffffU, /*039d*/ 0x18080282U, /*039e*/ 0x00080283U, /*039f*/ 0x08080283U, /*03a0*/ 0x10080283U, /*03a1*/ 0x18080283U, /*03a2*/ 0x00080284U, /*03a3*/ 0xffffffffU, /*03a4*/ 0x08080284U, /*03a5*/ 0x10080284U, /*03a6*/ 0x18080284U, /*03a7*/ 0x00080285U, /*03a8*/ 0x08080285U, /*03a9*/ 0x10080285U, /*03aa*/ 0x18080285U, /*03ab*/ 0xffffffffU, /*03ac*/ 0x00080286U, /*03ad*/ 0x08080286U, /*03ae*/ 0x10080286U, /*03af*/ 0x18080286U, /*03b0*/ 0x00080287U, /*03b1*/ 0x08080287U, /*03b2*/ 0xffffffffU, /*03b3*/ 0x10080287U, /*03b4*/ 0x18080287U, /*03b5*/ 0x00080288U, /*03b6*/ 0x08080288U, /*03b7*/ 0x10080288U, /*03b8*/ 0x18080288U, /*03b9*/ 0xffffffffU, /*03ba*/ 0x00080289U, /*03bb*/ 0x08020289U, /*03bc*/ 0x10030289U, /*03bd*/ 0x000a028aU, /*03be*/ 0x100a028aU, /*03bf*/ 0x000a028bU, /*03c0*/ 0x1005028bU, /*03c1*/ 0x1804028bU, /*03c2*/ 0x0008028cU, /*03c3*/ 0x0808028cU, /*03c4*/ 0x1006028cU, /*03c5*/ 0x1806028cU, /*03c6*/ 0x0011028dU, /*03c7*/ 0x1808028dU, /*03c8*/ 0x0004028eU, /*03c9*/ 0x0806028eU, /*03ca*/ 0xffffffffU, /*03cb*/ 0x1006028eU, /*03cc*/ 0x1808028eU, /*03cd*/ 0xffffffffU, /*03ce*/ 0x0004028fU, /*03cf*/ 0x0808028fU, /*03d0*/ 0x1008028fU, /*03d1*/ 0x1806028fU, /*03d2*/ 0x00060290U, /*03d3*/ 0x08110290U, /*03d4*/ 0x00080291U, /*03d5*/ 0x08040291U, /*03d6*/ 0x10060291U, /*03d7*/ 0xffffffffU, /*03d8*/ 0x18060291U, /*03d9*/ 0x00080292U, /*03da*/ 0xffffffffU, /*03db*/ 0x08040292U, /*03dc*/ 0x10080292U, /*03dd*/ 0x18080292U, /*03de*/ 0x00060293U, /*03df*/ 0x08060293U, /*03e0*/ 0x00110294U, /*03e1*/ 0x18080294U, /*03e2*/ 0x00040295U, /*03e3*/ 0x08060295U, /*03e4*/ 0xffffffffU, /*03e5*/ 0x10060295U, /*03e6*/ 0x18080295U, /*03e7*/ 0xffffffffU, /*03e8*/ 0x00040296U, /*03e9*/ 0x08040296U, /*03ea*/ 0x10040296U, /*03eb*/ 0x18040296U, /*03ec*/ 0x00040297U, /*03ed*/ 0x08040297U, /*03ee*/ 0x10040297U, /*03ef*/ 0x18040297U, /*03f0*/ 0x00040298U, /*03f1*/ 0x08040298U, /*03f2*/ 0x10040298U, /*03f3*/ 0x18040298U, /*03f4*/ 0x00040299U, /*03f5*/ 0x08040299U, /*03f6*/ 0x10040299U, /*03f7*/ 0x18040299U, /*03f8*/ 0x0004029aU, /*03f9*/ 0x0804029aU, /*03fa*/ 0x1004029aU, /*03fb*/ 0x1804029aU, /*03fc*/ 0x0011029bU, /*03fd*/ 0x0010029cU, /*03fe*/ 0x0011029dU, /*03ff*/ 0x0020029eU, /*0400*/ 0x0020029fU, /*0401*/ 0x002002a0U, /*0402*/ 0x002002a1U, /*0403*/ 0x002002a2U, /*0404*/ 0x002002a3U, /*0405*/ 0x002002a4U, /*0406*/ 0x002002a5U, /*0407*/ 0x002002a6U, /*0408*/ 0x000202a7U, /*0409*/ 0x080502a7U, /*040a*/ 0x100502a7U, /*040b*/ 0xffffffffU, /*040c*/ 0xffffffffU, /*040d*/ 0xffffffffU, /*040e*/ 0xffffffffU, /*040f*/ 0xffffffffU, /*0410*/ 0xffffffffU, /*0411*/ 0xffffffffU, /*0412*/ 0xffffffffU, /*0413*/ 0xffffffffU, /*0414*/ 0xffffffffU, /*0415*/ 0xffffffffU, /*0416*/ 0xffffffffU, /*0417*/ 0xffffffffU, /*0418*/ 0xffffffffU, /*0419*/ 0xffffffffU, /*041a*/ 0xffffffffU, /*041b*/ 0xffffffffU, /*041c*/ 0xffffffffU, /*041d*/ 0xffffffffU, /*041e*/ 0xffffffffU, /*041f*/ 0xffffffffU, /*0420*/ 0xffffffffU, /*0421*/ 0xffffffffU, /*0422*/ 0xffffffffU, /*0423*/ 0xffffffffU, /*0424*/ 0xffffffffU, /*0425*/ 0xffffffffU, /*0426*/ 0xffffffffU, /*0427*/ 0x180102a7U, /*0428*/ 0x000402a8U, /*0429*/ 0x081002a8U, /*042a*/ 0x002002a9U, /*042b*/ 0x001002aaU, /*042c*/ 0x002002abU, /*042d*/ 0x001002acU, /*042e*/ 0x002002adU, /*042f*/ 0x000702aeU, /*0430*/ 0x080102aeU, /*0431*/ 0x100202aeU, /*0432*/ 0x180602aeU, /*0433*/ 0x000102afU, /*0434*/ 0x080102afU, /*0435*/ 0x002002b0U, /*0436*/ 0x000202b1U, /*0437*/ 0x002002b2U, /*0438*/ 0x002002b3U, /*0439*/ 0xffffffffU, /*043a*/ 0xffffffffU, /*043b*/ 0xffffffffU, /*043c*/ 0xffffffffU, /*043d*/ 0xffffffffU, /*043e*/ 0xffffffffU, /*043f*/ 0xffffffffU, /*0440*/ 0xffffffffU, /*0441*/ 0xffffffffU, /*0442*/ 0xffffffffU, /*0443*/ 0xffffffffU, /*0444*/ 0xffffffffU, /*0445*/ 0xffffffffU, /*0446*/ 0xffffffffU, /*0447*/ 0xffffffffU, /*0448*/ 0xffffffffU, /*0449*/ 0xffffffffU, /*044a*/ 0xffffffffU, /*044b*/ 0xffffffffU, /*044c*/ 0xffffffffU, /*044d*/ 0xffffffffU, /*044e*/ 0xffffffffU, /*044f*/ 0xffffffffU, /*0450*/ 0xffffffffU, /*0451*/ 0xffffffffU, /*0452*/ 0xffffffffU, /*0453*/ 0xffffffffU, /*0454*/ 0xffffffffU, /*0455*/ 0xffffffffU, /*0456*/ 0xffffffffU, /*0457*/ 0xffffffffU, /*0458*/ 0xffffffffU, /*0459*/ 0xffffffffU, /*045a*/ 0xffffffffU, /*045b*/ 0xffffffffU, /*045c*/ 0xffffffffU, /*045d*/ 0xffffffffU, /*045e*/ 0xffffffffU, /*045f*/ 0x000402b4U, /*0460*/ 0xffffffffU, /*0461*/ 0xffffffffU, /*0462*/ 0xffffffffU, /*0463*/ 0xffffffffU, /*0464*/ 0xffffffffU, /*0465*/ 0xffffffffU, /*0466*/ 0xffffffffU, /*0467*/ 0xffffffffU, /*0468*/ 0xffffffffU, /*0469*/ 0xffffffffU, /*046a*/ 0xffffffffU, /*046b*/ 0xffffffffU, /*046c*/ 0xffffffffU, /*046d*/ 0xffffffffU, /*046e*/ 0xffffffffU, /*046f*/ 0xffffffffU, /*0470*/ 0xffffffffU, /*0471*/ 0xffffffffU, /*0472*/ 0xffffffffU, /*0473*/ 0xffffffffU, /*0474*/ 0xffffffffU, /*0475*/ 0xffffffffU, /*0476*/ 0xffffffffU, /*0477*/ 0xffffffffU, /*0478*/ 0xffffffffU, /*0479*/ 0xffffffffU, /*047a*/ 0xffffffffU, /*047b*/ 0xffffffffU, /*047c*/ 0xffffffffU, /*047d*/ 0xffffffffU, /*047e*/ 0xffffffffU, /*047f*/ 0xffffffffU, /*0480*/ 0xffffffffU, /*0481*/ 0xffffffffU, /*0482*/ 0xffffffffU, /*0483*/ 0xffffffffU, /*0484*/ 0xffffffffU, /*0485*/ 0xffffffffU, /*0486*/ 0xffffffffU, /*0487*/ 0xffffffffU, /*0488*/ 0xffffffffU, /*0489*/ 0xffffffffU, /*048a*/ 0xffffffffU, /*048b*/ 0xffffffffU, /*048c*/ 0xffffffffU, /*048d*/ 0xffffffffU, /*048e*/ 0xffffffffU, /*048f*/ 0xffffffffU, /*0490*/ 0xffffffffU, /*0491*/ 0xffffffffU, /*0492*/ 0xffffffffU, /*0493*/ 0xffffffffU, /*0494*/ 0xffffffffU, }, { /*0000*/ 0x00200800U, /*0001*/ 0x00040801U, /*0002*/ 0x080b0801U, /*0003*/ 0xffffffffU, /*0004*/ 0xffffffffU, /*0005*/ 0x18010801U, /*0006*/ 0x00050802U, /*0007*/ 0x08050802U, /*0008*/ 0x10050802U, /*0009*/ 0x18050802U, /*000a*/ 0x00050803U, /*000b*/ 0x08050803U, /*000c*/ 0x10050803U, /*000d*/ 0x18050803U, /*000e*/ 0x00050804U, /*000f*/ 0x08040804U, /*0010*/ 0x10030804U, /*0011*/ 0x00180805U, /*0012*/ 0x18030805U, /*0013*/ 0x00180806U, /*0014*/ 0x18020806U, /*0015*/ 0x00010807U, /*0016*/ 0x08020807U, /*0017*/ 0x10010807U, /*0018*/ 0x18010807U, /*0019*/ 0x00020808U, /*001a*/ 0x08040808U, /*001b*/ 0x10040808U, /*001c*/ 0x18040808U, /*001d*/ 0x000a0809U, /*001e*/ 0x10040809U, /*001f*/ 0xffffffffU, /*0020*/ 0xffffffffU, /*0021*/ 0x18070809U, /*0022*/ 0xffffffffU, /*0023*/ 0xffffffffU, /*0024*/ 0xffffffffU, /*0025*/ 0xffffffffU, /*0026*/ 0xffffffffU, /*0027*/ 0xffffffffU, /*0028*/ 0x000a080aU, /*0029*/ 0x1005080aU, /*002a*/ 0x1801080aU, /*002b*/ 0x0001080bU, /*002c*/ 0x0802080bU, /*002d*/ 0x1009080bU, /*002e*/ 0x0009080cU, /*002f*/ 0x1002080cU, /*0030*/ 0x0020080dU, /*0031*/ 0xffffffffU, /*0032*/ 0x0001080eU, /*0033*/ 0xffffffffU, /*0034*/ 0xffffffffU, /*0035*/ 0xffffffffU, /*0036*/ 0xffffffffU, /*0037*/ 0x0020080fU, /*0038*/ 0x00200810U, /*0039*/ 0x00200811U, /*003a*/ 0x00200812U, /*003b*/ 0x00030813U, /*003c*/ 0x08010813U, /*003d*/ 0x10030813U, /*003e*/ 0x18030813U, /*003f*/ 0x00040814U, /*0040*/ 0x08040814U, /*0041*/ 0x10040814U, /*0042*/ 0x18040814U, /*0043*/ 0x00010815U, /*0044*/ 0x08010815U, /*0045*/ 0x10060815U, /*0046*/ 0x18040815U, /*0047*/ 0xffffffffU, /*0048*/ 0x00060816U, /*0049*/ 0x08040816U, /*004a*/ 0x10060816U, /*004b*/ 0x18040816U, /*004c*/ 0x00020817U, /*004d*/ 0x08050817U, /*004e*/ 0x10080817U, /*004f*/ 0x00200818U, /*0050*/ 0x00060819U, /*0051*/ 0x08030819U, /*0052*/ 0x100b0819U, /*0053*/ 0x0004081aU, /*0054*/ 0x0804081aU, /*0055*/ 0x1004081aU, /*0056*/ 0xffffffffU, /*0057*/ 0x1801081aU, /*0058*/ 0x0009081bU, /*0059*/ 0x0020081cU, /*005a*/ 0x0020081dU, /*005b*/ 0x0020081eU, /*005c*/ 0x0020081fU, /*005d*/ 0x00100820U, /*005e*/ 0xffffffffU, /*005f*/ 0x10010820U, /*0060*/ 0x18060820U, /*0061*/ 0x00080821U, /*0062*/ 0x00200822U, /*0063*/ 0xffffffffU, /*0064*/ 0x000a0823U, /*0065*/ 0x10060823U, /*0066*/ 0x18070823U, /*0067*/ 0x00080824U, /*0068*/ 0x08080824U, /*0069*/ 0x100a0824U, /*006a*/ 0x00070825U, /*006b*/ 0x08080825U, /*006c*/ 0x10080825U, /*006d*/ 0x18030825U, /*006e*/ 0x000a0826U, /*006f*/ 0x100a0826U, /*0070*/ 0x00110827U, /*0071*/ 0x00090828U, /*0072*/ 0x10090828U, /*0073*/ 0x00100829U, /*0074*/ 0x100e0829U, /*0075*/ 0x000e082aU, /*0076*/ 0x100c082aU, /*0077*/ 0x000a082bU, /*0078*/ 0x100a082bU, /*0079*/ 0x0002082cU, /*007a*/ 0x0020082dU, /*007b*/ 0x000b082eU, /*007c*/ 0x100b082eU, /*007d*/ 0x0020082fU, /*007e*/ 0x00120830U, /*007f*/ 0x00200831U, /*0080*/ 0x00200832U, /*0081*/ 0xffffffffU, /*0082*/ 0xffffffffU, /*0083*/ 0x00010833U, /*0084*/ 0x08010833U, /*0085*/ 0x10080833U, /*0086*/ 0x000c0834U, /*0087*/ 0x100c0834U, /*0088*/ 0x000c0835U, /*0089*/ 0x100c0835U, /*008a*/ 0x000c0836U, /*008b*/ 0x100c0836U, /*008c*/ 0x000c0837U, /*008d*/ 0x100c0837U, /*008e*/ 0x000c0838U, /*008f*/ 0x100c0838U, /*0090*/ 0x000c0839U, /*0091*/ 0x100b0839U, /*0092*/ 0xffffffffU, /*0093*/ 0xffffffffU, /*0094*/ 0x000b083aU, /*0095*/ 0x100b083aU, /*0096*/ 0x000b083bU, /*0097*/ 0x100b083bU, /*0098*/ 0x000b083cU, /*0099*/ 0x100b083cU, /*009a*/ 0x000b083dU, /*009b*/ 0x100b083dU, /*009c*/ 0x000b083eU, /*009d*/ 0x100a083eU, /*009e*/ 0xffffffffU, /*009f*/ 0x000a083fU, /*00a0*/ 0x100a083fU, /*00a1*/ 0x000a0840U, /*00a2*/ 0x100a0840U, /*00a3*/ 0x000a0841U, /*00a4*/ 0x100a0841U, /*00a5*/ 0x000a0842U, /*00a6*/ 0x100a0842U, /*00a7*/ 0x000a0843U, /*00a8*/ 0x100a0843U, /*00a9*/ 0x000a0844U, /*00aa*/ 0x100a0844U, /*00ab*/ 0x000a0845U, /*00ac*/ 0x100a0845U, /*00ad*/ 0x000a0846U, /*00ae*/ 0x100a0846U, /*00af*/ 0x000a0847U, /*00b0*/ 0x100a0847U, /*00b1*/ 0x000a0848U, /*00b2*/ 0x100a0848U, /*00b3*/ 0x000a0849U, /*00b4*/ 0x100a0849U, /*00b5*/ 0x000a084aU, /*00b6*/ 0x100a084aU, /*00b7*/ 0x000a084bU, /*00b8*/ 0x100a084bU, /*00b9*/ 0x000a084cU, /*00ba*/ 0x100a084cU, /*00bb*/ 0x0004084dU, /*00bc*/ 0x0803084dU, /*00bd*/ 0x100a084dU, /*00be*/ 0x000a084eU, /*00bf*/ 0x1001084eU, /*00c0*/ 0x000a084fU, /*00c1*/ 0x1004084fU, /*00c2*/ 0x000b0850U, /*00c3*/ 0x100a0850U, /*00c4*/ 0xffffffffU, /*00c5*/ 0x00080851U, /*00c6*/ 0x08080851U, /*00c7*/ 0x10080851U, /*00c8*/ 0x18080851U, /*00c9*/ 0x00080852U, /*00ca*/ 0xffffffffU, /*00cb*/ 0x08080852U, /*00cc*/ 0x10010852U, /*00cd*/ 0x18080852U, /*00ce*/ 0x00080853U, /*00cf*/ 0x08020853U, /*00d0*/ 0x10020853U, /*00d1*/ 0x18040853U, /*00d2*/ 0x00040854U, /*00d3*/ 0xffffffffU, /*00d4*/ 0x08040854U, /*00d5*/ 0x100a0854U, /*00d6*/ 0x00060855U, /*00d7*/ 0x08080855U, /*00d8*/ 0xffffffffU, /*00d9*/ 0x10040855U, /*00da*/ 0x18040855U, /*00db*/ 0x00050856U, /*00dc*/ 0x08040856U, /*00dd*/ 0x10050856U, /*00de*/ 0x000a0857U, /*00df*/ 0x100a0857U, /*00e0*/ 0x00080858U, /*00e1*/ 0xffffffffU, /*00e2*/ 0x08040858U, /*00e3*/ 0xffffffffU, /*00e4*/ 0xffffffffU, /*00e5*/ 0x00050a00U, /*00e6*/ 0x08050a00U, /*00e7*/ 0x10050a00U, /*00e8*/ 0x18050a00U, /*00e9*/ 0x00050a01U, /*00ea*/ 0x08050a01U, /*00eb*/ 0x100b0a01U, /*00ec*/ 0x00010a02U, /*00ed*/ 0x08030a02U, /*00ee*/ 0x00200a03U, /*00ef*/ 0xffffffffU, /*00f0*/ 0x00030a04U, /*00f1*/ 0x080a0a04U, /*00f2*/ 0xffffffffU, /*00f3*/ 0xffffffffU, /*00f4*/ 0x18030a04U, /*00f5*/ 0x00030a05U, /*00f6*/ 0x08010a05U, /*00f7*/ 0x10010a05U, /*00f8*/ 0x18060a05U, /*00f9*/ 0xffffffffU, /*00fa*/ 0xffffffffU, /*00fb*/ 0xffffffffU, /*00fc*/ 0x00020a06U, /*00fd*/ 0x08030a06U, /*00fe*/ 0x10010a06U, /*00ff*/ 0x000f0a07U, /*0100*/ 0x00200a08U, /*0101*/ 0x00200a09U, /*0102*/ 0x000b0a0aU, /*0103*/ 0x100b0a0aU, /*0104*/ 0x000b0a0bU, /*0105*/ 0xffffffffU, /*0106*/ 0xffffffffU, /*0107*/ 0x00180a0cU, /*0108*/ 0x00180a0dU, /*0109*/ 0x00180a0eU, /*010a*/ 0x00180a0fU, /*010b*/ 0x18040a0fU, /*010c*/ 0x00020a10U, /*010d*/ 0x08020a10U, /*010e*/ 0x10040a10U, /*010f*/ 0x18040a10U, /*0110*/ 0x00010a11U, /*0111*/ 0x08010a11U, /*0112*/ 0x10010a11U, /*0113*/ 0x18030a11U, /*0114*/ 0x00200a12U, /*0115*/ 0x00200a13U, /*0116*/ 0xffffffffU, /*0117*/ 0x00140a14U, /*0118*/ 0x00140a15U, /*0119*/ 0x00140a16U, /*011a*/ 0x00140a17U, /*011b*/ 0x00140a18U, /*011c*/ 0x00140a19U, /*011d*/ 0x00140a1aU, /*011e*/ 0x00140a1bU, /*011f*/ 0x001e0a1cU, /*0120*/ 0x000a0a1dU, /*0121*/ 0x10060a1dU, /*0122*/ 0x18060a1dU, /*0123*/ 0x00060a1eU, /*0124*/ 0xffffffffU, /*0125*/ 0x08060a1eU, /*0126*/ 0x00080a1fU, /*0127*/ 0x080b0a1fU, /*0128*/ 0x000b0a20U, /*0129*/ 0x100b0a20U, /*012a*/ 0x000b0a21U, /*012b*/ 0x100b0a21U, /*012c*/ 0x000b0a22U, /*012d*/ 0x10040a22U, /*012e*/ 0x000a0a23U, /*012f*/ 0x10060a23U, /*0130*/ 0x18080a23U, /*0131*/ 0xffffffffU, /*0132*/ 0x00040a24U, /*0133*/ 0xffffffffU, /*0134*/ 0xffffffffU, /*0135*/ 0x00010b80U, /*0136*/ 0x08020b80U, /*0137*/ 0x10050b80U, /*0138*/ 0x18050b80U, /*0139*/ 0x00050b81U, /*013a*/ 0x08050b81U, /*013b*/ 0x100b0b81U, /*013c*/ 0x00050b82U, /*013d*/ 0x08010b82U, /*013e*/ 0x10010b82U, /*013f*/ 0xffffffffU, /*0140*/ 0x18010b82U, /*0141*/ 0x00010b83U, /*0142*/ 0x08040b83U, /*0143*/ 0x100b0b83U, /*0144*/ 0x000b0b84U, /*0145*/ 0xffffffffU, /*0146*/ 0x10040b84U, /*0147*/ 0x000b0b85U, /*0148*/ 0x10040b85U, /*0149*/ 0x18010b85U, /*014a*/ 0x00010b86U, /*014b*/ 0x08010b86U, /*014c*/ 0x00200b87U, /*014d*/ 0x00200b88U, /*014e*/ 0x00080b89U, /*014f*/ 0x080a0b89U, /*0150*/ 0x18050b89U, /*0151*/ 0x000a0b8aU, /*0152*/ 0x10030b8aU, /*0153*/ 0x18030b8aU, /*0154*/ 0x00010b8bU, /*0155*/ 0x08020b8bU, /*0156*/ 0x10010b8bU, /*0157*/ 0x18010b8bU, /*0158*/ 0x00010b8cU, /*0159*/ 0x08030b8cU, /*015a*/ 0xffffffffU, /*015b*/ 0x10040b8cU, /*015c*/ 0x18040b8cU, /*015d*/ 0x00040b8dU, /*015e*/ 0x08040b8dU, /*015f*/ 0xffffffffU, /*0160*/ 0xffffffffU, /*0161*/ 0xffffffffU, /*0162*/ 0xffffffffU, /*0163*/ 0xffffffffU, /*0164*/ 0xffffffffU, /*0165*/ 0xffffffffU, /*0166*/ 0xffffffffU, /*0167*/ 0xffffffffU, /*0168*/ 0x000d0b8eU, /*0169*/ 0x100d0b8eU, /*016a*/ 0x000d0b8fU, /*016b*/ 0x00050b90U, /*016c*/ 0x00010b91U, /*016d*/ 0x080e0b91U, /*016e*/ 0x000e0b92U, /*016f*/ 0x100e0b92U, /*0170*/ 0x000e0b93U, /*0171*/ 0x100e0b93U, /*0172*/ 0x00040b94U, /*0173*/ 0x08040b94U, /*0174*/ 0x10040b94U, /*0175*/ 0x18040b94U, /*0176*/ 0x00040b95U, /*0177*/ 0x080b0b95U, /*0178*/ 0x000b0b96U, /*0179*/ 0x100b0b96U, /*017a*/ 0x000b0b97U, /*017b*/ 0xffffffffU, /*017c*/ 0xffffffffU, /*017d*/ 0xffffffffU, /*017e*/ 0xffffffffU, /*017f*/ 0x000d0b98U, /*0180*/ 0x100d0b98U, /*0181*/ 0x000d0b99U, /*0182*/ 0x10100b99U, /*0183*/ 0x10080b8dU, /*0184*/ 0x18080b8dU, /*0185*/ 0x00100b9aU, /*0186*/ 0x10100b9aU, /*0187*/ 0x00100b9bU, /*0188*/ 0x10100b9bU, /*0189*/ 0x00100b9cU, /*018a*/ 0x10030b9cU, /*018b*/ 0x18040b9cU, /*018c*/ 0x00010b9dU, /*018d*/ 0x08040b9dU, /*018e*/ 0xffffffffU, /*018f*/ 0xffffffffU, /*0190*/ 0x10010b9dU, /*0191*/ 0x00140b9eU, /*0192*/ 0x000a0b9fU, /*0193*/ 0x100c0b9fU, /*0194*/ 0x00120ba0U, /*0195*/ 0x00140ba1U, /*0196*/ 0x00120ba2U, /*0197*/ 0x00110ba3U, /*0198*/ 0x00110ba4U, /*0199*/ 0x00120ba5U, /*019a*/ 0x00120ba6U, /*019b*/ 0x00120ba7U, /*019c*/ 0x00120ba8U, /*019d*/ 0x00120ba9U, /*019e*/ 0x00120baaU, /*019f*/ 0x00120babU, /*01a0*/ 0x00120bacU, /*01a1*/ 0xffffffffU, /*01a2*/ 0xffffffffU, /*01a3*/ 0x00190badU, /*01a4*/ 0x00190baeU, /*01a5*/ 0x00200bafU, /*01a6*/ 0x00170bb0U, /*01a7*/ 0x18080bb0U, /*01a8*/ 0x00010bb1U, /*01a9*/ 0x08010bb1U, /*01aa*/ 0x00200bb2U, /*01ab*/ 0x00080bb3U, /*01ac*/ 0xffffffffU, /*01ad*/ 0x08030bb3U, /*01ae*/ 0x00180bb4U, /*01af*/ 0x00180bb5U, /*01b0*/ 0xffffffffU, /*01b1*/ 0xffffffffU, /*01b2*/ 0xffffffffU, /*01b3*/ 0xffffffffU, /*01b4*/ 0xffffffffU, /*01b5*/ 0xffffffffU, /*01b6*/ 0xffffffffU, /*01b7*/ 0xffffffffU, /*01b8*/ 0xffffffffU, /*01b9*/ 0xffffffffU, /*01ba*/ 0xffffffffU, /*01bb*/ 0xffffffffU, /*01bc*/ 0xffffffffU, /*01bd*/ 0xffffffffU, /*01be*/ 0xffffffffU, /*01bf*/ 0x00100bb6U, /*01c0*/ 0x10010bb6U, /*01c1*/ 0x18010bb6U, /*01c2*/ 0x00050bb7U, /*01c3*/ 0x00200bb8U, /*01c4*/ 0x00090bb9U, /*01c5*/ 0xffffffffU, /*01c6*/ 0xffffffffU, /*01c7*/ 0x00200bbaU, /*01c8*/ 0x00040bbbU, /*01c9*/ 0x08100bbbU, /*01ca*/ 0x18060bbbU, /*01cb*/ 0x00100bbcU, /*01cc*/ 0xffffffffU, /*01cd*/ 0x10080bbcU, /*01ce*/ 0xffffffffU, /*01cf*/ 0xffffffffU, /*01d0*/ 0xffffffffU, /*01d1*/ 0x18030bbcU, /*01d2*/ 0x00020bbdU, /*01d3*/ 0xffffffffU, /*01d4*/ 0x00200bbeU, /*01d5*/ 0x000b0bbfU, /*01d6*/ 0xffffffffU, /*01d7*/ 0xffffffffU, /*01d8*/ 0xffffffffU, /*01d9*/ 0x10020bbfU, /*01da*/ 0xffffffffU, /*01db*/ 0xffffffffU, /*01dc*/ 0xffffffffU, /*01dd*/ 0xffffffffU, /*01de*/ 0x00010200U, /*01df*/ 0x08040200U, /*01e0*/ 0x10100200U, /*01e1*/ 0x00010201U, /*01e2*/ 0x08010201U, /*01e3*/ 0xffffffffU, /*01e4*/ 0xffffffffU, /*01e5*/ 0x10100201U, /*01e6*/ 0xffffffffU, /*01e7*/ 0xffffffffU, /*01e8*/ 0xffffffffU, /*01e9*/ 0xffffffffU, /*01ea*/ 0xffffffffU, /*01eb*/ 0xffffffffU, /*01ec*/ 0xffffffffU, /*01ed*/ 0xffffffffU, /*01ee*/ 0xffffffffU, /*01ef*/ 0x00200202U, /*01f0*/ 0x00100203U, /*01f1*/ 0x00200204U, /*01f2*/ 0x00100205U, /*01f3*/ 0x00200206U, /*01f4*/ 0x00100207U, /*01f5*/ 0x10100207U, /*01f6*/ 0x00200208U, /*01f7*/ 0x00200209U, /*01f8*/ 0x0020020aU, /*01f9*/ 0x0020020bU, /*01fa*/ 0x0010020cU, /*01fb*/ 0x0020020dU, /*01fc*/ 0x0020020eU, /*01fd*/ 0x0020020fU, /*01fe*/ 0x00200210U, /*01ff*/ 0x00100211U, /*0200*/ 0x00200212U, /*0201*/ 0x00200213U, /*0202*/ 0x00200214U, /*0203*/ 0x00200215U, /*0204*/ 0x00090216U, /*0205*/ 0x10010216U, /*0206*/ 0x00200217U, /*0207*/ 0x00050218U, /*0208*/ 0x08010218U, /*0209*/ 0x10080218U, /*020a*/ 0x18080218U, /*020b*/ 0x001e0219U, /*020c*/ 0x001e021aU, /*020d*/ 0x001e021bU, /*020e*/ 0x001e021cU, /*020f*/ 0x001e021dU, /*0210*/ 0x001e021eU, /*0211*/ 0x001e021fU, /*0212*/ 0x001e0220U, /*0213*/ 0x001e0221U, /*0214*/ 0x001e0222U, /*0215*/ 0x001e0223U, /*0216*/ 0x001e0224U, /*0217*/ 0x001e0225U, /*0218*/ 0x001e0226U, /*0219*/ 0x001e0227U, /*021a*/ 0x001e0228U, /*021b*/ 0x00010229U, /*021c*/ 0x08010229U, /*021d*/ 0x10010229U, /*021e*/ 0x18040229U, /*021f*/ 0x0008022aU, /*0220*/ 0x0808022aU, /*0221*/ 0x1008022aU, /*0222*/ 0x1804022aU, /*0223*/ 0x0005022bU, /*0224*/ 0x0806022bU, /*0225*/ 0x1007022bU, /*0226*/ 0x1805022bU, /*0227*/ 0x0006022cU, /*0228*/ 0x0807022cU, /*0229*/ 0x1005022cU, /*022a*/ 0x1806022cU, /*022b*/ 0x0007022dU, /*022c*/ 0x0802022dU, /*022d*/ 0x1001022dU, /*022e*/ 0xffffffffU, /*022f*/ 0x000a022eU, /*0230*/ 0x1010022eU, /*0231*/ 0x000a022fU, /*0232*/ 0x1010022fU, /*0233*/ 0x000a0230U, /*0234*/ 0x10100230U, /*0235*/ 0xffffffffU, /*0236*/ 0x00100231U, /*0237*/ 0xffffffffU, /*0238*/ 0xffffffffU, /*0239*/ 0x10010231U, /*023a*/ 0x18010231U, /*023b*/ 0x00010232U, /*023c*/ 0x08010232U, /*023d*/ 0x10010232U, /*023e*/ 0x18010232U, /*023f*/ 0x00020233U, /*0240*/ 0x08020233U, /*0241*/ 0x10020233U, /*0242*/ 0x18020233U, /*0243*/ 0x00020234U, /*0244*/ 0x08030234U, /*0245*/ 0x10010234U, /*0246*/ 0x18010234U, /*0247*/ 0x00010235U, /*0248*/ 0x08010235U, /*0249*/ 0xffffffffU, /*024a*/ 0x10020235U, /*024b*/ 0x18010235U, /*024c*/ 0x00010236U, /*024d*/ 0xffffffffU, /*024e*/ 0x08020236U, /*024f*/ 0x10010236U, /*0250*/ 0x18010236U, /*0251*/ 0xffffffffU, /*0252*/ 0x00020237U, /*0253*/ 0x08010237U, /*0254*/ 0x10010237U, /*0255*/ 0xffffffffU, /*0256*/ 0x18020237U, /*0257*/ 0x00070238U, /*0258*/ 0x08010238U, /*0259*/ 0x10010238U, /*025a*/ 0x18010238U, /*025b*/ 0x00010239U, /*025c*/ 0x08010239U, /*025d*/ 0x10010239U, /*025e*/ 0xffffffffU, /*025f*/ 0x18010239U, /*0260*/ 0x0004023aU, /*0261*/ 0x0804023aU, /*0262*/ 0x1004023aU, /*0263*/ 0x1801023aU, /*0264*/ 0x0002023bU, /*0265*/ 0x0806023bU, /*0266*/ 0x1006023bU, /*0267*/ 0xffffffffU, /*0268*/ 0xffffffffU, /*0269*/ 0xffffffffU, /*026a*/ 0x1802023bU, /*026b*/ 0x0010023cU, /*026c*/ 0x1001023cU, /*026d*/ 0x1801023cU, /*026e*/ 0xffffffffU, /*026f*/ 0x0004023dU, /*0270*/ 0x0801023dU, /*0271*/ 0x1004023dU, /*0272*/ 0x1802023dU, /*0273*/ 0x0008023eU, /*0274*/ 0xffffffffU, /*0275*/ 0xffffffffU, /*0276*/ 0xffffffffU, /*0277*/ 0x080a023eU, /*0278*/ 0x0020023fU, /*0279*/ 0x00200240U, /*027a*/ 0x00050241U, /*027b*/ 0x08010241U, /*027c*/ 0x10050241U, /*027d*/ 0x18080241U, /*027e*/ 0x00010242U, /*027f*/ 0x08080242U, /*0280*/ 0x10010242U, /*0281*/ 0x18080242U, /*0282*/ 0x00010243U, /*0283*/ 0x08040243U, /*0284*/ 0x10040243U, /*0285*/ 0x18040243U, /*0286*/ 0x00040244U, /*0287*/ 0x08040244U, /*0288*/ 0x10040244U, /*0289*/ 0x18040244U, /*028a*/ 0x00040245U, /*028b*/ 0x08040245U, /*028c*/ 0x10040245U, /*028d*/ 0x18010245U, /*028e*/ 0x00040246U, /*028f*/ 0x08040246U, /*0290*/ 0x10040246U, /*0291*/ 0x18040246U, /*0292*/ 0x00040247U, /*0293*/ 0x08040247U, /*0294*/ 0x10060247U, /*0295*/ 0x18060247U, /*0296*/ 0x00060248U, /*0297*/ 0x08060248U, /*0298*/ 0x10060248U, /*0299*/ 0x18060248U, /*029a*/ 0x00040249U, /*029b*/ 0x08010249U, /*029c*/ 0x10010249U, /*029d*/ 0x18020249U, /*029e*/ 0xffffffffU, /*029f*/ 0xffffffffU, /*02a0*/ 0xffffffffU, /*02a1*/ 0xffffffffU, /*02a2*/ 0xffffffffU, /*02a3*/ 0xffffffffU, /*02a4*/ 0xffffffffU, /*02a5*/ 0xffffffffU, /*02a6*/ 0x0004024aU, /*02a7*/ 0x0804024aU, /*02a8*/ 0x1001024aU, /*02a9*/ 0x1801024aU, /*02aa*/ 0xffffffffU, /*02ab*/ 0x0001024bU, /*02ac*/ 0x0801024bU, /*02ad*/ 0xffffffffU, /*02ae*/ 0x1001024bU, /*02af*/ 0x1801024bU, /*02b0*/ 0x0001024cU, /*02b1*/ 0x0804024cU, /*02b2*/ 0x1004024cU, /*02b3*/ 0x000a024dU, /*02b4*/ 0x0020024eU, /*02b5*/ 0x0004024fU, /*02b6*/ 0x0808024fU, /*02b7*/ 0xffffffffU, /*02b8*/ 0xffffffffU, /*02b9*/ 0xffffffffU, /*02ba*/ 0xffffffffU, /*02bb*/ 0xffffffffU, /*02bc*/ 0xffffffffU, /*02bd*/ 0x1002024fU, /*02be*/ 0x1802024fU, /*02bf*/ 0x00200250U, /*02c0*/ 0x00020251U, /*02c1*/ 0x08100251U, /*02c2*/ 0x00100252U, /*02c3*/ 0x10040252U, /*02c4*/ 0x18040252U, /*02c5*/ 0x00050253U, /*02c6*/ 0x08050253U, /*02c7*/ 0xffffffffU, /*02c8*/ 0xffffffffU, /*02c9*/ 0xffffffffU, /*02ca*/ 0xffffffffU, /*02cb*/ 0x10010253U, /*02cc*/ 0x18010253U, /*02cd*/ 0x00080254U, /*02ce*/ 0x08080254U, /*02cf*/ 0x10080254U, /*02d0*/ 0x18080254U, /*02d1*/ 0x00080255U, /*02d2*/ 0x08080255U, /*02d3*/ 0x10080255U, /*02d4*/ 0x18080255U, /*02d5*/ 0x00080256U, /*02d6*/ 0x08080256U, /*02d7*/ 0x10080256U, /*02d8*/ 0xffffffffU, /*02d9*/ 0xffffffffU, /*02da*/ 0xffffffffU, /*02db*/ 0xffffffffU, /*02dc*/ 0xffffffffU, /*02dd*/ 0xffffffffU, /*02de*/ 0x18030256U, /*02df*/ 0x00010257U, /*02e0*/ 0x08020257U, /*02e1*/ 0x10010257U, /*02e2*/ 0x18040257U, /*02e3*/ 0x00020258U, /*02e4*/ 0x08010258U, /*02e5*/ 0x10010258U, /*02e6*/ 0xffffffffU, /*02e7*/ 0x18010258U, /*02e8*/ 0x00040259U, /*02e9*/ 0x08080259U, /*02ea*/ 0x100a0259U, /*02eb*/ 0x000a025aU, /*02ec*/ 0x100a025aU, /*02ed*/ 0x000a025bU, /*02ee*/ 0x100a025bU, /*02ef*/ 0x000a025cU, /*02f0*/ 0x0020025dU, /*02f1*/ 0x0020025eU, /*02f2*/ 0x0001025fU, /*02f3*/ 0xffffffffU, /*02f4*/ 0xffffffffU, /*02f5*/ 0xffffffffU, /*02f6*/ 0x0802025fU, /*02f7*/ 0x1002025fU, /*02f8*/ 0x00100260U, /*02f9*/ 0x10050260U, /*02fa*/ 0x18060260U, /*02fb*/ 0x00050261U, /*02fc*/ 0x08050261U, /*02fd*/ 0x100e0261U, /*02fe*/ 0x00050262U, /*02ff*/ 0x080e0262U, /*0300*/ 0x18050262U, /*0301*/ 0x000e0263U, /*0302*/ 0x10050263U, /*0303*/ 0x18010263U, /*0304*/ 0x00050264U, /*0305*/ 0x08050264U, /*0306*/ 0x100a0264U, /*0307*/ 0x000a0265U, /*0308*/ 0x10050265U, /*0309*/ 0x18050265U, /*030a*/ 0x000a0266U, /*030b*/ 0x100a0266U, /*030c*/ 0x00050267U, /*030d*/ 0x08050267U, /*030e*/ 0x100a0267U, /*030f*/ 0x000a0268U, /*0310*/ 0xffffffffU, /*0311*/ 0xffffffffU, /*0312*/ 0xffffffffU, /*0313*/ 0xffffffffU, /*0314*/ 0xffffffffU, /*0315*/ 0xffffffffU, /*0316*/ 0x10070268U, /*0317*/ 0x18070268U, /*0318*/ 0x00040269U, /*0319*/ 0x08040269U, /*031a*/ 0xffffffffU, /*031b*/ 0xffffffffU, /*031c*/ 0xffffffffU, /*031d*/ 0x10040269U, /*031e*/ 0x18080269U, /*031f*/ 0x0008026aU, /*0320*/ 0x0804026aU, /*0321*/ 0xffffffffU, /*0322*/ 0xffffffffU, /*0323*/ 0xffffffffU, /*0324*/ 0x1004026aU, /*0325*/ 0xffffffffU, /*0326*/ 0xffffffffU, /*0327*/ 0xffffffffU, /*0328*/ 0x1804026aU, /*0329*/ 0xffffffffU, /*032a*/ 0xffffffffU, /*032b*/ 0xffffffffU, /*032c*/ 0x0004026bU, /*032d*/ 0x0805026bU, /*032e*/ 0x1007026bU, /*032f*/ 0x1808026bU, /*0330*/ 0x0010026cU, /*0331*/ 0x1008026cU, /*0332*/ 0x0010026dU, /*0333*/ 0x1008026dU, /*0334*/ 0x0010026eU, /*0335*/ 0x1008026eU, /*0336*/ 0x1808026eU, /*0337*/ 0x0001026fU, /*0338*/ 0x0801026fU, /*0339*/ 0x1006026fU, /*033a*/ 0x1806026fU, /*033b*/ 0x00060270U, /*033c*/ 0xffffffffU, /*033d*/ 0x08010270U, /*033e*/ 0x10030270U, /*033f*/ 0xffffffffU, /*0340*/ 0xffffffffU, /*0341*/ 0xffffffffU, /*0342*/ 0x000a0271U, /*0343*/ 0x100a0271U, /*0344*/ 0x00040272U, /*0345*/ 0x08010272U, /*0346*/ 0x10040272U, /*0347*/ 0xffffffffU, /*0348*/ 0xffffffffU, /*0349*/ 0xffffffffU, /*034a*/ 0xffffffffU, /*034b*/ 0xffffffffU, /*034c*/ 0xffffffffU, /*034d*/ 0x18070272U, /*034e*/ 0x00070273U, /*034f*/ 0x08050273U, /*0350*/ 0x10050273U, /*0351*/ 0xffffffffU, /*0352*/ 0xffffffffU, /*0353*/ 0xffffffffU, /*0354*/ 0x18040273U, /*0355*/ 0x00010274U, /*0356*/ 0x08010274U, /*0357*/ 0x10020274U, /*0358*/ 0x18080274U, /*0359*/ 0x00200275U, /*035a*/ 0x00200276U, /*035b*/ 0x00100277U, /*035c*/ 0xffffffffU, /*035d*/ 0xffffffffU, /*035e*/ 0xffffffffU, /*035f*/ 0x10020277U, /*0360*/ 0x18010277U, /*0361*/ 0xffffffffU, /*0362*/ 0x00020278U, /*0363*/ 0x08100278U, /*0364*/ 0x00100279U, /*0365*/ 0x10100279U, /*0366*/ 0x0008027aU, /*0367*/ 0x0808027aU, /*0368*/ 0x1008027aU, /*0369*/ 0xffffffffU, /*036a*/ 0x0010027bU, /*036b*/ 0x1010027bU, /*036c*/ 0x0010027cU, /*036d*/ 0x1008027cU, /*036e*/ 0x1808027cU, /*036f*/ 0x0008027dU, /*0370*/ 0xffffffffU, /*0371*/ 0x0810027dU, /*0372*/ 0x0010027eU, /*0373*/ 0x1010027eU, /*0374*/ 0x0008027fU, /*0375*/ 0x0808027fU, /*0376*/ 0x1008027fU, /*0377*/ 0xffffffffU, /*0378*/ 0x1808027fU, /*0379*/ 0x00100280U, /*037a*/ 0x10100280U, /*037b*/ 0x00100281U, /*037c*/ 0x10080281U, /*037d*/ 0x18080281U, /*037e*/ 0x00080282U, /*037f*/ 0xffffffffU, /*0380*/ 0x08100282U, /*0381*/ 0x00100283U, /*0382*/ 0x10100283U, /*0383*/ 0x00080284U, /*0384*/ 0x08080284U, /*0385*/ 0x10080284U, /*0386*/ 0xffffffffU, /*0387*/ 0x00100285U, /*0388*/ 0x10100285U, /*0389*/ 0x00100286U, /*038a*/ 0x10080286U, /*038b*/ 0x18080286U, /*038c*/ 0x00080287U, /*038d*/ 0xffffffffU, /*038e*/ 0x08080287U, /*038f*/ 0x10100287U, /*0390*/ 0x00100288U, /*0391*/ 0x10100288U, /*0392*/ 0x00080289U, /*0393*/ 0x08080289U, /*0394*/ 0x10080289U, /*0395*/ 0xffffffffU, /*0396*/ 0x0010028aU, /*0397*/ 0x1010028aU, /*0398*/ 0x0010028bU, /*0399*/ 0x1008028bU, /*039a*/ 0x1808028bU, /*039b*/ 0x0008028cU, /*039c*/ 0xffffffffU, /*039d*/ 0x0810028cU, /*039e*/ 0x0010028dU, /*039f*/ 0x1010028dU, /*03a0*/ 0x0008028eU, /*03a1*/ 0x0808028eU, /*03a2*/ 0x1008028eU, /*03a3*/ 0xffffffffU, /*03a4*/ 0x1808028eU, /*03a5*/ 0x0010028fU, /*03a6*/ 0x1010028fU, /*03a7*/ 0x00100290U, /*03a8*/ 0x10080290U, /*03a9*/ 0x18080290U, /*03aa*/ 0x00080291U, /*03ab*/ 0xffffffffU, /*03ac*/ 0x08100291U, /*03ad*/ 0x00100292U, /*03ae*/ 0x10100292U, /*03af*/ 0x00080293U, /*03b0*/ 0x08080293U, /*03b1*/ 0x10080293U, /*03b2*/ 0xffffffffU, /*03b3*/ 0x00100294U, /*03b4*/ 0x10100294U, /*03b5*/ 0x00100295U, /*03b6*/ 0x10080295U, /*03b7*/ 0x18080295U, /*03b8*/ 0x00080296U, /*03b9*/ 0xffffffffU, /*03ba*/ 0x08080296U, /*03bb*/ 0x10020296U, /*03bc*/ 0x18030296U, /*03bd*/ 0x000a0297U, /*03be*/ 0x100a0297U, /*03bf*/ 0x000a0298U, /*03c0*/ 0x10050298U, /*03c1*/ 0x18040298U, /*03c2*/ 0x00080299U, /*03c3*/ 0x08080299U, /*03c4*/ 0x10060299U, /*03c5*/ 0x18060299U, /*03c6*/ 0x0011029aU, /*03c7*/ 0x1808029aU, /*03c8*/ 0x0004029bU, /*03c9*/ 0x0806029bU, /*03ca*/ 0xffffffffU, /*03cb*/ 0x1006029bU, /*03cc*/ 0x1808029bU, /*03cd*/ 0x0008029cU, /*03ce*/ 0x0804029cU, /*03cf*/ 0x1008029cU, /*03d0*/ 0x1808029cU, /*03d1*/ 0x0006029dU, /*03d2*/ 0x0806029dU, /*03d3*/ 0x0011029eU, /*03d4*/ 0x1808029eU, /*03d5*/ 0x0004029fU, /*03d6*/ 0x0806029fU, /*03d7*/ 0xffffffffU, /*03d8*/ 0x1006029fU, /*03d9*/ 0x1808029fU, /*03da*/ 0x000802a0U, /*03db*/ 0x080402a0U, /*03dc*/ 0x100802a0U, /*03dd*/ 0x180802a0U, /*03de*/ 0x000602a1U, /*03df*/ 0x080602a1U, /*03e0*/ 0x001102a2U, /*03e1*/ 0x180802a2U, /*03e2*/ 0x000402a3U, /*03e3*/ 0x080602a3U, /*03e4*/ 0xffffffffU, /*03e5*/ 0x100602a3U, /*03e6*/ 0x180802a3U, /*03e7*/ 0x000802a4U, /*03e8*/ 0x080402a4U, /*03e9*/ 0x100402a4U, /*03ea*/ 0x180402a4U, /*03eb*/ 0x000402a5U, /*03ec*/ 0x080402a5U, /*03ed*/ 0x100402a5U, /*03ee*/ 0x180402a5U, /*03ef*/ 0x000402a6U, /*03f0*/ 0x080402a6U, /*03f1*/ 0x100402a6U, /*03f2*/ 0x180402a6U, /*03f3*/ 0x000402a7U, /*03f4*/ 0x080402a7U, /*03f5*/ 0x100402a7U, /*03f6*/ 0x180402a7U, /*03f7*/ 0x000402a8U, /*03f8*/ 0x080402a8U, /*03f9*/ 0x100402a8U, /*03fa*/ 0x180402a8U, /*03fb*/ 0x000402a9U, /*03fc*/ 0x081202a9U, /*03fd*/ 0x001102aaU, /*03fe*/ 0x001202abU, /*03ff*/ 0x002002acU, /*0400*/ 0x002002adU, /*0401*/ 0x002002aeU, /*0402*/ 0x002002afU, /*0403*/ 0x002002b0U, /*0404*/ 0x002002b1U, /*0405*/ 0x002002b2U, /*0406*/ 0x002002b3U, /*0407*/ 0x002002b4U, /*0408*/ 0x000302b5U, /*0409*/ 0x080502b5U, /*040a*/ 0x100502b5U, /*040b*/ 0x180102b5U, /*040c*/ 0x000502b6U, /*040d*/ 0x080502b6U, /*040e*/ 0x100502b6U, /*040f*/ 0x180502b6U, /*0410*/ 0x000502b7U, /*0411*/ 0x080502b7U, /*0412*/ 0x100502b7U, /*0413*/ 0x180502b7U, /*0414*/ 0x000502b8U, /*0415*/ 0x080502b8U, /*0416*/ 0x100502b8U, /*0417*/ 0x180502b8U, /*0418*/ 0x000502b9U, /*0419*/ 0x080502b9U, /*041a*/ 0x100502b9U, /*041b*/ 0x180502b9U, /*041c*/ 0x000502baU, /*041d*/ 0x080502baU, /*041e*/ 0x100502baU, /*041f*/ 0x180502baU, /*0420*/ 0x000502bbU, /*0421*/ 0x080502bbU, /*0422*/ 0x100102bbU, /*0423*/ 0x180202bbU, /*0424*/ 0x000202bcU, /*0425*/ 0x080202bcU, /*0426*/ 0x100202bcU, /*0427*/ 0x180102bcU, /*0428*/ 0x000402bdU, /*0429*/ 0x081002bdU, /*042a*/ 0x002002beU, /*042b*/ 0x001002bfU, /*042c*/ 0x002002c0U, /*042d*/ 0x001002c1U, /*042e*/ 0x002002c2U, /*042f*/ 0x000702c3U, /*0430*/ 0x080102c3U, /*0431*/ 0x100202c3U, /*0432*/ 0x180602c3U, /*0433*/ 0x000102c4U, /*0434*/ 0x080102c4U, /*0435*/ 0x002002c5U, /*0436*/ 0x000302c6U, /*0437*/ 0x002002c7U, /*0438*/ 0x002002c8U, /*0439*/ 0xffffffffU, /*043a*/ 0xffffffffU, /*043b*/ 0xffffffffU, /*043c*/ 0xffffffffU, /*043d*/ 0xffffffffU, /*043e*/ 0xffffffffU, /*043f*/ 0xffffffffU, /*0440*/ 0xffffffffU, /*0441*/ 0xffffffffU, /*0442*/ 0xffffffffU, /*0443*/ 0xffffffffU, /*0444*/ 0xffffffffU, /*0445*/ 0xffffffffU, /*0446*/ 0xffffffffU, /*0447*/ 0xffffffffU, /*0448*/ 0xffffffffU, /*0449*/ 0xffffffffU, /*044a*/ 0xffffffffU, /*044b*/ 0xffffffffU, /*044c*/ 0xffffffffU, /*044d*/ 0xffffffffU, /*044e*/ 0xffffffffU, /*044f*/ 0xffffffffU, /*0450*/ 0xffffffffU, /*0451*/ 0xffffffffU, /*0452*/ 0xffffffffU, /*0453*/ 0xffffffffU, /*0454*/ 0xffffffffU, /*0455*/ 0xffffffffU, /*0456*/ 0xffffffffU, /*0457*/ 0xffffffffU, /*0458*/ 0xffffffffU, /*0459*/ 0xffffffffU, /*045a*/ 0xffffffffU, /*045b*/ 0xffffffffU, /*045c*/ 0xffffffffU, /*045d*/ 0xffffffffU, /*045e*/ 0xffffffffU, /*045f*/ 0x000402c9U, /*0460*/ 0xffffffffU, /*0461*/ 0xffffffffU, /*0462*/ 0xffffffffU, /*0463*/ 0xffffffffU, /*0464*/ 0xffffffffU, /*0465*/ 0xffffffffU, /*0466*/ 0xffffffffU, /*0467*/ 0xffffffffU, /*0468*/ 0xffffffffU, /*0469*/ 0xffffffffU, /*046a*/ 0xffffffffU, /*046b*/ 0xffffffffU, /*046c*/ 0xffffffffU, /*046d*/ 0xffffffffU, /*046e*/ 0xffffffffU, /*046f*/ 0xffffffffU, /*0470*/ 0xffffffffU, /*0471*/ 0xffffffffU, /*0472*/ 0xffffffffU, /*0473*/ 0xffffffffU, /*0474*/ 0xffffffffU, /*0475*/ 0xffffffffU, /*0476*/ 0xffffffffU, /*0477*/ 0xffffffffU, /*0478*/ 0xffffffffU, /*0479*/ 0xffffffffU, /*047a*/ 0xffffffffU, /*047b*/ 0xffffffffU, /*047c*/ 0xffffffffU, /*047d*/ 0xffffffffU, /*047e*/ 0xffffffffU, /*047f*/ 0xffffffffU, /*0480*/ 0xffffffffU, /*0481*/ 0xffffffffU, /*0482*/ 0xffffffffU, /*0483*/ 0xffffffffU, /*0484*/ 0xffffffffU, /*0485*/ 0xffffffffU, /*0486*/ 0xffffffffU, /*0487*/ 0xffffffffU, /*0488*/ 0xffffffffU, /*0489*/ 0xffffffffU, /*048a*/ 0xffffffffU, /*048b*/ 0xffffffffU, /*048c*/ 0xffffffffU, /*048d*/ 0xffffffffU, /*048e*/ 0xffffffffU, /*048f*/ 0xffffffffU, /*0490*/ 0xffffffffU, /*0491*/ 0xffffffffU, /*0492*/ 0xffffffffU, /*0493*/ 0xffffffffU, /*0494*/ 0xffffffffU, }, { /*0000*/ 0x00200400U, /*0001*/ 0x00040401U, /*0002*/ 0x080b0401U, /*0003*/ 0x000a0402U, /*0004*/ 0x10020402U, /*0005*/ 0x18010402U, /*0006*/ 0x00050403U, /*0007*/ 0x08050403U, /*0008*/ 0x10050403U, /*0009*/ 0x18050403U, /*000a*/ 0x00050404U, /*000b*/ 0x08050404U, /*000c*/ 0x10050404U, /*000d*/ 0x18050404U, /*000e*/ 0x00050405U, /*000f*/ 0x08040405U, /*0010*/ 0x10030405U, /*0011*/ 0x00180406U, /*0012*/ 0x18030406U, /*0013*/ 0x00180407U, /*0014*/ 0x18020407U, /*0015*/ 0x00010408U, /*0016*/ 0x08020408U, /*0017*/ 0x10010408U, /*0018*/ 0x18010408U, /*0019*/ 0x00020409U, /*001a*/ 0x08040409U, /*001b*/ 0x10040409U, /*001c*/ 0x18040409U, /*001d*/ 0xffffffffU, /*001e*/ 0x0004040aU, /*001f*/ 0xffffffffU, /*0020*/ 0xffffffffU, /*0021*/ 0x0809040aU, /*0022*/ 0x1801040aU, /*0023*/ 0x0020040bU, /*0024*/ 0x001c040cU, /*0025*/ 0x0001040dU, /*0026*/ 0x0807040dU, /*0027*/ 0x1009040dU, /*0028*/ 0x000a040eU, /*0029*/ 0x1005040eU, /*002a*/ 0x1801040eU, /*002b*/ 0x1001040fU, /*002c*/ 0x1802040fU, /*002d*/ 0x0009040fU, /*002e*/ 0x00090410U, /*002f*/ 0x10020410U, /*0030*/ 0x00200411U, /*0031*/ 0x00010412U, /*0032*/ 0x08020412U, /*0033*/ 0xffffffffU, /*0034*/ 0xffffffffU, /*0035*/ 0xffffffffU, /*0036*/ 0xffffffffU, /*0037*/ 0x00200413U, /*0038*/ 0x00200414U, /*0039*/ 0x00200415U, /*003a*/ 0x00200416U, /*003b*/ 0x00030417U, /*003c*/ 0x08010417U, /*003d*/ 0x10040417U, /*003e*/ 0x18030417U, /*003f*/ 0x00040418U, /*0040*/ 0x08040418U, /*0041*/ 0x10040418U, /*0042*/ 0x18040418U, /*0043*/ 0x00010419U, /*0044*/ 0x08010419U, /*0045*/ 0x10060419U, /*0046*/ 0x18040419U, /*0047*/ 0xffffffffU, /*0048*/ 0x0006041aU, /*0049*/ 0x0804041aU, /*004a*/ 0x1006041aU, /*004b*/ 0x1804041aU, /*004c*/ 0x0002041bU, /*004d*/ 0x0805041bU, /*004e*/ 0x1008041bU, /*004f*/ 0xffffffffU, /*0050*/ 0x1806041bU, /*0051*/ 0x0003041cU, /*0052*/ 0x080b041cU, /*0053*/ 0x1804041cU, /*0054*/ 0x0004041dU, /*0055*/ 0x0804041dU, /*0056*/ 0x1001041dU, /*0057*/ 0xffffffffU, /*0058*/ 0x0009041eU, /*0059*/ 0x0020041fU, /*005a*/ 0x00200420U, /*005b*/ 0x00200421U, /*005c*/ 0x00200422U, /*005d*/ 0x00100423U, /*005e*/ 0xffffffffU, /*005f*/ 0x10010423U, /*0060*/ 0x18060423U, /*0061*/ 0x00080424U, /*0062*/ 0x00200425U, /*0063*/ 0x00100426U, /*0064*/ 0x100a0426U, /*0065*/ 0x00060427U, /*0066*/ 0x08070427U, /*0067*/ 0x10080427U, /*0068*/ 0x18080427U, /*0069*/ 0x000a0428U, /*006a*/ 0x10070428U, /*006b*/ 0x18080428U, /*006c*/ 0x00080429U, /*006d*/ 0x08030429U, /*006e*/ 0x100a0429U, /*006f*/ 0x000a042aU, /*0070*/ 0x0011042bU, /*0071*/ 0x0009042cU, /*0072*/ 0x1009042cU, /*0073*/ 0x0010042dU, /*0074*/ 0x100e042dU, /*0075*/ 0x000e042eU, /*0076*/ 0x0012042fU, /*0077*/ 0x000a0430U, /*0078*/ 0x100a0430U, /*0079*/ 0x00020431U, /*007a*/ 0x00200432U, /*007b*/ 0x000b0433U, /*007c*/ 0x100b0433U, /*007d*/ 0x00200434U, /*007e*/ 0x00120435U, /*007f*/ 0x00200436U, /*0080*/ 0x00200437U, /*0081*/ 0x00080438U, /*0082*/ 0x08010438U, /*0083*/ 0x10010438U, /*0084*/ 0x18010438U, /*0085*/ 0x00080439U, /*0086*/ 0x080c0439U, /*0087*/ 0x000c043aU, /*0088*/ 0x100c043aU, /*0089*/ 0x000c043bU, /*008a*/ 0x100c043bU, /*008b*/ 0x000c043cU, /*008c*/ 0x100c043cU, /*008d*/ 0x000c043dU, /*008e*/ 0x100c043dU, /*008f*/ 0x000c043eU, /*0090*/ 0x100c043eU, /*0091*/ 0x000b043fU, /*0092*/ 0x1009043fU, /*0093*/ 0x00010440U, /*0094*/ 0x000b0441U, /*0095*/ 0x100b0441U, /*0096*/ 0x000b0442U, /*0097*/ 0x100b0442U, /*0098*/ 0x000b0443U, /*0099*/ 0x100b0443U, /*009a*/ 0x000b0444U, /*009b*/ 0x100b0444U, /*009c*/ 0x000b0445U, /*009d*/ 0x100a0445U, /*009e*/ 0x00020446U, /*009f*/ 0x080a0446U, /*00a0*/ 0x000a0447U, /*00a1*/ 0x100a0447U, /*00a2*/ 0x000a0448U, /*00a3*/ 0x100a0448U, /*00a4*/ 0x000a0449U, /*00a5*/ 0x100a0449U, /*00a6*/ 0x000a044aU, /*00a7*/ 0x100a044aU, /*00a8*/ 0x000a044bU, /*00a9*/ 0x100a044bU, /*00aa*/ 0x000a044cU, /*00ab*/ 0x100a044cU, /*00ac*/ 0x000a044dU, /*00ad*/ 0x100a044dU, /*00ae*/ 0x000a044eU, /*00af*/ 0x100a044eU, /*00b0*/ 0x000a044fU, /*00b1*/ 0x100a044fU, /*00b2*/ 0x000a0450U, /*00b3*/ 0x100a0450U, /*00b4*/ 0x000a0451U, /*00b5*/ 0x100a0451U, /*00b6*/ 0x000a0452U, /*00b7*/ 0x100a0452U, /*00b8*/ 0x000a0453U, /*00b9*/ 0x100a0453U, /*00ba*/ 0x000a0454U, /*00bb*/ 0x10040454U, /*00bc*/ 0x18030454U, /*00bd*/ 0x000a0455U, /*00be*/ 0x100a0455U, /*00bf*/ 0x00010456U, /*00c0*/ 0x080a0456U, /*00c1*/ 0x18040456U, /*00c2*/ 0x000b0457U, /*00c3*/ 0x100a0457U, /*00c4*/ 0x00030458U, /*00c5*/ 0x00080459U, /*00c6*/ 0x08080459U, /*00c7*/ 0x10080459U, /*00c8*/ 0x18080459U, /*00c9*/ 0x0008045aU, /*00ca*/ 0xffffffffU, /*00cb*/ 0x0808045aU, /*00cc*/ 0x1001045aU, /*00cd*/ 0x1808045aU, /*00ce*/ 0x0008045bU, /*00cf*/ 0x0802045bU, /*00d0*/ 0x1002045bU, /*00d1*/ 0x1805045bU, /*00d2*/ 0x0005045cU, /*00d3*/ 0xffffffffU, /*00d4*/ 0x0804045cU, /*00d5*/ 0x100a045cU, /*00d6*/ 0x0006045dU, /*00d7*/ 0x0808045dU, /*00d8*/ 0x1008045dU, /*00d9*/ 0x1804045dU, /*00da*/ 0x0004045eU, /*00db*/ 0x0805045eU, /*00dc*/ 0x1004045eU, /*00dd*/ 0x1805045eU, /*00de*/ 0x000a045fU, /*00df*/ 0x100a045fU, /*00e0*/ 0x00080460U, /*00e1*/ 0xffffffffU, /*00e2*/ 0x08040460U, /*00e3*/ 0xffffffffU, /*00e4*/ 0xffffffffU, /*00e5*/ 0x00050600U, /*00e6*/ 0x08050600U, /*00e7*/ 0x10050600U, /*00e8*/ 0x18050600U, /*00e9*/ 0x00050601U, /*00ea*/ 0x08050601U, /*00eb*/ 0x100b0601U, /*00ec*/ 0x00010602U, /*00ed*/ 0x08030602U, /*00ee*/ 0x00200603U, /*00ef*/ 0x00100604U, /*00f0*/ 0x10040604U, /*00f1*/ 0x000a0605U, /*00f2*/ 0x10090605U, /*00f3*/ 0x00080606U, /*00f4*/ 0x08030606U, /*00f5*/ 0x10030606U, /*00f6*/ 0x18010606U, /*00f7*/ 0x00010607U, /*00f8*/ 0x08070607U, /*00f9*/ 0x10070607U, /*00fa*/ 0x18050607U, /*00fb*/ 0x00010608U, /*00fc*/ 0x08020608U, /*00fd*/ 0x10030608U, /*00fe*/ 0x18010608U, /*00ff*/ 0x000f0609U, /*0100*/ 0x0020060aU, /*0101*/ 0x0020060bU, /*0102*/ 0x000b060cU, /*0103*/ 0x100b060cU, /*0104*/ 0x000b060dU, /*0105*/ 0x0018060eU, /*0106*/ 0x0018060fU, /*0107*/ 0xffffffffU, /*0108*/ 0xffffffffU, /*0109*/ 0xffffffffU, /*010a*/ 0xffffffffU, /*010b*/ 0xffffffffU, /*010c*/ 0x1802060fU, /*010d*/ 0x00020610U, /*010e*/ 0x08040610U, /*010f*/ 0x10040610U, /*0110*/ 0x18010610U, /*0111*/ 0x00010611U, /*0112*/ 0x08010611U, /*0113*/ 0x10030611U, /*0114*/ 0x00200612U, /*0115*/ 0x00200613U, /*0116*/ 0xffffffffU, /*0117*/ 0x00140614U, /*0118*/ 0x00140615U, /*0119*/ 0x00140616U, /*011a*/ 0x00140617U, /*011b*/ 0x00140618U, /*011c*/ 0x00140619U, /*011d*/ 0x0014061aU, /*011e*/ 0x0014061bU, /*011f*/ 0x0018061cU, /*0120*/ 0x000a061dU, /*0121*/ 0x1006061dU, /*0122*/ 0x1806061dU, /*0123*/ 0x0006061eU, /*0124*/ 0xffffffffU, /*0125*/ 0x0806061eU, /*0126*/ 0x0008061fU, /*0127*/ 0x080b061fU, /*0128*/ 0x000b0620U, /*0129*/ 0x100b0620U, /*012a*/ 0x000b0621U, /*012b*/ 0x100b0621U, /*012c*/ 0x000b0622U, /*012d*/ 0x10040622U, /*012e*/ 0x000a0623U, /*012f*/ 0x10060623U, /*0130*/ 0x18080623U, /*0131*/ 0x00080624U, /*0132*/ 0x08040624U, /*0133*/ 0x00020680U, /*0134*/ 0x00010681U, /*0135*/ 0x08010681U, /*0136*/ 0x10020681U, /*0137*/ 0x18050681U, /*0138*/ 0x00050682U, /*0139*/ 0x08050682U, /*013a*/ 0x10050682U, /*013b*/ 0x000b0683U, /*013c*/ 0x10050683U, /*013d*/ 0x18010683U, /*013e*/ 0x00010684U, /*013f*/ 0xffffffffU, /*0140*/ 0x08010684U, /*0141*/ 0x10010684U, /*0142*/ 0x18040684U, /*0143*/ 0x000b0685U, /*0144*/ 0x100b0685U, /*0145*/ 0x000b0686U, /*0146*/ 0x10040686U, /*0147*/ 0x000b0687U, /*0148*/ 0x10040687U, /*0149*/ 0x18010687U, /*014a*/ 0x00010688U, /*014b*/ 0x08010688U, /*014c*/ 0x00200689U, /*014d*/ 0x0020068aU, /*014e*/ 0x0008068bU, /*014f*/ 0x080a068bU, /*0150*/ 0x1805068bU, /*0151*/ 0x000a068cU, /*0152*/ 0x1003068cU, /*0153*/ 0x1803068cU, /*0154*/ 0x0001068dU, /*0155*/ 0x0802068dU, /*0156*/ 0x1001068dU, /*0157*/ 0x1801068dU, /*0158*/ 0x0001068eU, /*0159*/ 0x0802068eU, /*015a*/ 0x1001068eU, /*015b*/ 0x0004068fU, /*015c*/ 0x0804068fU, /*015d*/ 0x1004068fU, /*015e*/ 0x1804068fU, /*015f*/ 0x00010690U, /*0160*/ 0x08010690U, /*0161*/ 0x10010690U, /*0162*/ 0x00200691U, /*0163*/ 0x00200692U, /*0164*/ 0x00200693U, /*0165*/ 0x00200694U, /*0166*/ 0xffffffffU, /*0167*/ 0x1801068eU, /*0168*/ 0x000d0696U, /*0169*/ 0x100d0696U, /*016a*/ 0x000d0697U, /*016b*/ 0x00050698U, /*016c*/ 0x00010699U, /*016d*/ 0x080e0699U, /*016e*/ 0x000e069aU, /*016f*/ 0x100e069aU, /*0170*/ 0x000e069bU, /*0171*/ 0x100e069bU, /*0172*/ 0x0004069cU, /*0173*/ 0x0804069cU, /*0174*/ 0x1004069cU, /*0175*/ 0x1804069cU, /*0176*/ 0x0004069dU, /*0177*/ 0x080b069dU, /*0178*/ 0x000b069eU, /*0179*/ 0x100b069eU, /*017a*/ 0x000b069fU, /*017b*/ 0xffffffffU, /*017c*/ 0xffffffffU, /*017d*/ 0xffffffffU, /*017e*/ 0xffffffffU, /*017f*/ 0x000d06a0U, /*0180*/ 0x100d06a0U, /*0181*/ 0x000d06a1U, /*0182*/ 0x101006a1U, /*0183*/ 0x00080695U, /*0184*/ 0x08080695U, /*0185*/ 0x001006a2U, /*0186*/ 0x101006a2U, /*0187*/ 0x001006a3U, /*0188*/ 0x101006a3U, /*0189*/ 0x001006a4U, /*018a*/ 0x100306a4U, /*018b*/ 0x180406a4U, /*018c*/ 0x000106a5U, /*018d*/ 0x080806a5U, /*018e*/ 0x100106a5U, /*018f*/ 0x180506a5U, /*0190*/ 0x000106a6U, /*0191*/ 0x081406a6U, /*0192*/ 0x000a06a7U, /*0193*/ 0x100c06a7U, /*0194*/ 0x001206a8U, /*0195*/ 0x001406a9U, /*0196*/ 0x001206aaU, /*0197*/ 0x001106abU, /*0198*/ 0x001106acU, /*0199*/ 0x001206adU, /*019a*/ 0x001206aeU, /*019b*/ 0x001206afU, /*019c*/ 0x001206b0U, /*019d*/ 0x001206b1U, /*019e*/ 0x001206b2U, /*019f*/ 0x001206b3U, /*01a0*/ 0x001206b4U, /*01a1*/ 0x001206b5U, /*01a2*/ 0x001206b6U, /*01a3*/ 0x000e06b7U, /*01a4*/ 0x100d06b7U, /*01a5*/ 0x002006b8U, /*01a6*/ 0x001706b9U, /*01a7*/ 0x000906baU, /*01a8*/ 0x100106baU, /*01a9*/ 0x180106baU, /*01aa*/ 0x002006bbU, /*01ab*/ 0x000806bcU, /*01ac*/ 0x080306bcU, /*01ad*/ 0x100306bcU, /*01ae*/ 0x001806bdU, /*01af*/ 0x001806beU, /*01b0*/ 0x180706beU, /*01b1*/ 0x000506bfU, /*01b2*/ 0x080806bfU, /*01b3*/ 0x100806bfU, /*01b4*/ 0x180806bfU, /*01b5*/ 0x000106c0U, /*01b6*/ 0x080106c0U, /*01b7*/ 0x002006c1U, /*01b8*/ 0xffffffffU, /*01b9*/ 0xffffffffU, /*01ba*/ 0xffffffffU, /*01bb*/ 0xffffffffU, /*01bc*/ 0xffffffffU, /*01bd*/ 0xffffffffU, /*01be*/ 0xffffffffU, /*01bf*/ 0x001006c2U, /*01c0*/ 0x100106c2U, /*01c1*/ 0x180106c2U, /*01c2*/ 0x000206c3U, /*01c3*/ 0x080406c3U, /*01c4*/ 0x100906c3U, /*01c5*/ 0x000706c4U, /*01c6*/ 0x080406c4U, /*01c7*/ 0x002006c5U, /*01c8*/ 0x000106c6U, /*01c9*/ 0x080206c6U, /*01ca*/ 0x100606c6U, /*01cb*/ 0x001006c7U, /*01cc*/ 0x100106c7U, /*01cd*/ 0x002006c8U, /*01ce*/ 0x000806c9U, /*01cf*/ 0x080106c9U, /*01d0*/ 0x100506c9U, /*01d1*/ 0xffffffffU, /*01d2*/ 0x180206c9U, /*01d3*/ 0x000106caU, /*01d4*/ 0x002006cbU, /*01d5*/ 0x000b06ccU, /*01d6*/ 0x100106ccU, /*01d7*/ 0x180306ccU, /*01d8*/ 0x000806cdU, /*01d9*/ 0x080206cdU, /*01da*/ 0x100c06cdU, /*01db*/ 0x000406ceU, /*01dc*/ 0x080106ceU, /*01dd*/ 0xffffffffU, /*01de*/ 0x00010200U, /*01df*/ 0x08040200U, /*01e0*/ 0x10100200U, /*01e1*/ 0x00010201U, /*01e2*/ 0x08010201U, /*01e3*/ 0x10010201U, /*01e4*/ 0xffffffffU, /*01e5*/ 0x00100202U, /*01e6*/ 0x10080202U, /*01e7*/ 0xffffffffU, /*01e8*/ 0xffffffffU, /*01e9*/ 0xffffffffU, /*01ea*/ 0xffffffffU, /*01eb*/ 0xffffffffU, /*01ec*/ 0xffffffffU, /*01ed*/ 0xffffffffU, /*01ee*/ 0xffffffffU, /*01ef*/ 0x00200203U, /*01f0*/ 0x00100204U, /*01f1*/ 0x00200205U, /*01f2*/ 0x00100206U, /*01f3*/ 0x00200207U, /*01f4*/ 0x00100208U, /*01f5*/ 0x00140209U, /*01f6*/ 0x0020020aU, /*01f7*/ 0x0020020bU, /*01f8*/ 0x0020020cU, /*01f9*/ 0x0020020dU, /*01fa*/ 0x0014020eU, /*01fb*/ 0x0020020fU, /*01fc*/ 0x00200210U, /*01fd*/ 0x00200211U, /*01fe*/ 0x00200212U, /*01ff*/ 0x00140213U, /*0200*/ 0x00200214U, /*0201*/ 0x00200215U, /*0202*/ 0x00200216U, /*0203*/ 0x00200217U, /*0204*/ 0x00090218U, /*0205*/ 0x10010218U, /*0206*/ 0x00200219U, /*0207*/ 0x0005021aU, /*0208*/ 0x0801021aU, /*0209*/ 0x1008021aU, /*020a*/ 0x1808021aU, /*020b*/ 0x001c021bU, /*020c*/ 0x001c021cU, /*020d*/ 0x001c021dU, /*020e*/ 0x001c021eU, /*020f*/ 0x001c021fU, /*0210*/ 0x001c0220U, /*0211*/ 0x001c0221U, /*0212*/ 0x001c0222U, /*0213*/ 0x001c0223U, /*0214*/ 0x001c0224U, /*0215*/ 0x001c0225U, /*0216*/ 0x001c0226U, /*0217*/ 0x001c0227U, /*0218*/ 0x001c0228U, /*0219*/ 0x001c0229U, /*021a*/ 0x001c022aU, /*021b*/ 0x0001022bU, /*021c*/ 0x0801022bU, /*021d*/ 0x1001022bU, /*021e*/ 0x1804022bU, /*021f*/ 0x0008022cU, /*0220*/ 0x0808022cU, /*0221*/ 0x1008022cU, /*0222*/ 0x1804022cU, /*0223*/ 0x0007022dU, /*0224*/ 0xffffffffU, /*0225*/ 0x0807022dU, /*0226*/ 0x1007022dU, /*0227*/ 0xffffffffU, /*0228*/ 0x1807022dU, /*0229*/ 0x0007022eU, /*022a*/ 0xffffffffU, /*022b*/ 0x0807022eU, /*022c*/ 0x1002022eU, /*022d*/ 0x1801022eU, /*022e*/ 0x0001022fU, /*022f*/ 0x080a022fU, /*0230*/ 0x00140230U, /*0231*/ 0x000a0231U, /*0232*/ 0x00140232U, /*0233*/ 0x000a0233U, /*0234*/ 0x00140234U, /*0235*/ 0x18010234U, /*0236*/ 0x00100235U, /*0237*/ 0x10050235U, /*0238*/ 0x18010235U, /*0239*/ 0x00010236U, /*023a*/ 0x08010236U, /*023b*/ 0x10010236U, /*023c*/ 0x18010236U, /*023d*/ 0x00010237U, /*023e*/ 0x08010237U, /*023f*/ 0x10020237U, /*0240*/ 0x18020237U, /*0241*/ 0x00020238U, /*0242*/ 0x08020238U, /*0243*/ 0x10020238U, /*0244*/ 0x18030238U, /*0245*/ 0x00010239U, /*0246*/ 0x08010239U, /*0247*/ 0x10010239U, /*0248*/ 0x18010239U, /*0249*/ 0xffffffffU, /*024a*/ 0x0002023aU, /*024b*/ 0x0801023aU, /*024c*/ 0x1001023aU, /*024d*/ 0xffffffffU, /*024e*/ 0x1802023aU, /*024f*/ 0x0001023bU, /*0250*/ 0x0801023bU, /*0251*/ 0xffffffffU, /*0252*/ 0x1002023bU, /*0253*/ 0x1801023bU, /*0254*/ 0x0001023cU, /*0255*/ 0xffffffffU, /*0256*/ 0x0802023cU, /*0257*/ 0x1007023cU, /*0258*/ 0x1801023cU, /*0259*/ 0x0001023dU, /*025a*/ 0x0801023dU, /*025b*/ 0x1001023dU, /*025c*/ 0x1801023dU, /*025d*/ 0x0001023eU, /*025e*/ 0x0801023eU, /*025f*/ 0x1001023eU, /*0260*/ 0x1804023eU, /*0261*/ 0x0004023fU, /*0262*/ 0x0804023fU, /*0263*/ 0x1001023fU, /*0264*/ 0x1802023fU, /*0265*/ 0x00060240U, /*0266*/ 0x08060240U, /*0267*/ 0x10020240U, /*0268*/ 0x18020240U, /*0269*/ 0x00020241U, /*026a*/ 0xffffffffU, /*026b*/ 0x08100241U, /*026c*/ 0x18010241U, /*026d*/ 0x00010242U, /*026e*/ 0x08010242U, /*026f*/ 0x10040242U, /*0270*/ 0x18010242U, /*0271*/ 0x00040243U, /*0272*/ 0x08020243U, /*0273*/ 0x10080243U, /*0274*/ 0xffffffffU, /*0275*/ 0xffffffffU, /*0276*/ 0xffffffffU, /*0277*/ 0x000a0244U, /*0278*/ 0x00200245U, /*0279*/ 0x00200246U, /*027a*/ 0x00050247U, /*027b*/ 0x08010247U, /*027c*/ 0x10050247U, /*027d*/ 0x18080247U, /*027e*/ 0x00010248U, /*027f*/ 0x08080248U, /*0280*/ 0x10010248U, /*0281*/ 0x18080248U, /*0282*/ 0x00010249U, /*0283*/ 0x08040249U, /*0284*/ 0x10040249U, /*0285*/ 0x18040249U, /*0286*/ 0x0004024aU, /*0287*/ 0x0804024aU, /*0288*/ 0x1004024aU, /*0289*/ 0x1804024aU, /*028a*/ 0x0004024bU, /*028b*/ 0x0804024bU, /*028c*/ 0x1004024bU, /*028d*/ 0x1801024bU, /*028e*/ 0x0004024cU, /*028f*/ 0x0804024cU, /*0290*/ 0x1004024cU, /*0291*/ 0x1804024cU, /*0292*/ 0x0004024dU, /*0293*/ 0x0804024dU, /*0294*/ 0x1006024dU, /*0295*/ 0x1806024dU, /*0296*/ 0x0006024eU, /*0297*/ 0x0806024eU, /*0298*/ 0x1006024eU, /*0299*/ 0x1806024eU, /*029a*/ 0xffffffffU, /*029b*/ 0x0001024fU, /*029c*/ 0x0801024fU, /*029d*/ 0x1002024fU, /*029e*/ 0xffffffffU, /*029f*/ 0xffffffffU, /*02a0*/ 0xffffffffU, /*02a1*/ 0xffffffffU, /*02a2*/ 0xffffffffU, /*02a3*/ 0xffffffffU, /*02a4*/ 0xffffffffU, /*02a5*/ 0xffffffffU, /*02a6*/ 0x1804024fU, /*02a7*/ 0x00040250U, /*02a8*/ 0x08010250U, /*02a9*/ 0x10010250U, /*02aa*/ 0x18010250U, /*02ab*/ 0x00010251U, /*02ac*/ 0x08010251U, /*02ad*/ 0x10010251U, /*02ae*/ 0x18010251U, /*02af*/ 0x00010252U, /*02b0*/ 0x08010252U, /*02b1*/ 0x10040252U, /*02b2*/ 0x18040252U, /*02b3*/ 0x000a0253U, /*02b4*/ 0x00200254U, /*02b5*/ 0x00040255U, /*02b6*/ 0x08080255U, /*02b7*/ 0x10020255U, /*02b8*/ 0x18020255U, /*02b9*/ 0x00020256U, /*02ba*/ 0x08020256U, /*02bb*/ 0x10020256U, /*02bc*/ 0x18020256U, /*02bd*/ 0xffffffffU, /*02be*/ 0xffffffffU, /*02bf*/ 0x00200257U, /*02c0*/ 0x00020258U, /*02c1*/ 0x08100258U, /*02c2*/ 0x00100259U, /*02c3*/ 0x10040259U, /*02c4*/ 0x18040259U, /*02c5*/ 0x0005025aU, /*02c6*/ 0x0805025aU, /*02c7*/ 0x0020025bU, /*02c8*/ 0x0020025cU, /*02c9*/ 0x0020025dU, /*02ca*/ 0x0020025eU, /*02cb*/ 0x0001025fU, /*02cc*/ 0x0801025fU, /*02cd*/ 0x1007025fU, /*02ce*/ 0x1807025fU, /*02cf*/ 0x00070260U, /*02d0*/ 0x08070260U, /*02d1*/ 0x10070260U, /*02d2*/ 0x18070260U, /*02d3*/ 0x00070261U, /*02d4*/ 0x08070261U, /*02d5*/ 0x10070261U, /*02d6*/ 0x18070261U, /*02d7*/ 0x00070262U, /*02d8*/ 0x08070262U, /*02d9*/ 0x10070262U, /*02da*/ 0x18070262U, /*02db*/ 0x00030263U, /*02dc*/ 0x08030263U, /*02dd*/ 0x10030263U, /*02de*/ 0xffffffffU, /*02df*/ 0x18010263U, /*02e0*/ 0x00020264U, /*02e1*/ 0x08010264U, /*02e2*/ 0x10040264U, /*02e3*/ 0x18020264U, /*02e4*/ 0x00010265U, /*02e5*/ 0x08010265U, /*02e6*/ 0x10010265U, /*02e7*/ 0x18010265U, /*02e8*/ 0x00040266U, /*02e9*/ 0x08080266U, /*02ea*/ 0x100a0266U, /*02eb*/ 0x000a0267U, /*02ec*/ 0x100a0267U, /*02ed*/ 0x000a0268U, /*02ee*/ 0x100a0268U, /*02ef*/ 0x000a0269U, /*02f0*/ 0x0020026aU, /*02f1*/ 0x0020026bU, /*02f2*/ 0x0001026cU, /*02f3*/ 0x0802026cU, /*02f4*/ 0x1002026cU, /*02f5*/ 0x1802026cU, /*02f6*/ 0xffffffffU, /*02f7*/ 0x0002026dU, /*02f8*/ 0x0810026dU, /*02f9*/ 0x1805026dU, /*02fa*/ 0x0006026eU, /*02fb*/ 0x0805026eU, /*02fc*/ 0x1005026eU, /*02fd*/ 0x000e026fU, /*02fe*/ 0x1005026fU, /*02ff*/ 0x000e0270U, /*0300*/ 0x10050270U, /*0301*/ 0x000e0271U, /*0302*/ 0x10050271U, /*0303*/ 0x18010271U, /*0304*/ 0x00050272U, /*0305*/ 0x08050272U, /*0306*/ 0x100a0272U, /*0307*/ 0x000a0273U, /*0308*/ 0x10050273U, /*0309*/ 0x18050273U, /*030a*/ 0x000a0274U, /*030b*/ 0x100a0274U, /*030c*/ 0x00050275U, /*030d*/ 0x08050275U, /*030e*/ 0x100a0275U, /*030f*/ 0x000a0276U, /*0310*/ 0xffffffffU, /*0311*/ 0xffffffffU, /*0312*/ 0xffffffffU, /*0313*/ 0xffffffffU, /*0314*/ 0xffffffffU, /*0315*/ 0xffffffffU, /*0316*/ 0x10070276U, /*0317*/ 0x18070276U, /*0318*/ 0x00040277U, /*0319*/ 0x08040277U, /*031a*/ 0xffffffffU, /*031b*/ 0xffffffffU, /*031c*/ 0xffffffffU, /*031d*/ 0x10040277U, /*031e*/ 0x18080277U, /*031f*/ 0x00080278U, /*0320*/ 0x08040278U, /*0321*/ 0xffffffffU, /*0322*/ 0xffffffffU, /*0323*/ 0xffffffffU, /*0324*/ 0x10040278U, /*0325*/ 0xffffffffU, /*0326*/ 0xffffffffU, /*0327*/ 0xffffffffU, /*0328*/ 0x18040278U, /*0329*/ 0xffffffffU, /*032a*/ 0xffffffffU, /*032b*/ 0xffffffffU, /*032c*/ 0x00040279U, /*032d*/ 0x08050279U, /*032e*/ 0x10070279U, /*032f*/ 0x18080279U, /*0330*/ 0x0010027aU, /*0331*/ 0x1008027aU, /*0332*/ 0x0010027bU, /*0333*/ 0x1008027bU, /*0334*/ 0x0010027cU, /*0335*/ 0x1008027cU, /*0336*/ 0x1808027cU, /*0337*/ 0x0001027dU, /*0338*/ 0x0801027dU, /*0339*/ 0x1006027dU, /*033a*/ 0x1806027dU, /*033b*/ 0x0006027eU, /*033c*/ 0x0801027eU, /*033d*/ 0x1001027eU, /*033e*/ 0x1803027eU, /*033f*/ 0x000a027fU, /*0340*/ 0x100a027fU, /*0341*/ 0x000a0280U, /*0342*/ 0xffffffffU, /*0343*/ 0x100a0280U, /*0344*/ 0x00040281U, /*0345*/ 0x08010281U, /*0346*/ 0x10040281U, /*0347*/ 0xffffffffU, /*0348*/ 0xffffffffU, /*0349*/ 0xffffffffU, /*034a*/ 0xffffffffU, /*034b*/ 0xffffffffU, /*034c*/ 0xffffffffU, /*034d*/ 0x18070281U, /*034e*/ 0x00070282U, /*034f*/ 0x08050282U, /*0350*/ 0x10050282U, /*0351*/ 0xffffffffU, /*0352*/ 0xffffffffU, /*0353*/ 0xffffffffU, /*0354*/ 0x18040282U, /*0355*/ 0x00010283U, /*0356*/ 0x08010283U, /*0357*/ 0x10020283U, /*0358*/ 0x18080283U, /*0359*/ 0x00200284U, /*035a*/ 0x00200285U, /*035b*/ 0x00100286U, /*035c*/ 0x10020286U, /*035d*/ 0x18020286U, /*035e*/ 0x00020287U, /*035f*/ 0xffffffffU, /*0360*/ 0x08010287U, /*0361*/ 0x10010287U, /*0362*/ 0x18020287U, /*0363*/ 0x00080288U, /*0364*/ 0x08080288U, /*0365*/ 0x10080288U, /*0366*/ 0x18080288U, /*0367*/ 0x00080289U, /*0368*/ 0x08080289U, /*0369*/ 0xffffffffU, /*036a*/ 0x10080289U, /*036b*/ 0x18080289U, /*036c*/ 0x0008028aU, /*036d*/ 0x0808028aU, /*036e*/ 0x1008028aU, /*036f*/ 0x1808028aU, /*0370*/ 0xffffffffU, /*0371*/ 0x0008028bU, /*0372*/ 0x0808028bU, /*0373*/ 0x1008028bU, /*0374*/ 0x1808028bU, /*0375*/ 0x0008028cU, /*0376*/ 0x0808028cU, /*0377*/ 0xffffffffU, /*0378*/ 0x1008028cU, /*0379*/ 0x1808028cU, /*037a*/ 0x0008028dU, /*037b*/ 0x0808028dU, /*037c*/ 0x1008028dU, /*037d*/ 0x1808028dU, /*037e*/ 0x0008028eU, /*037f*/ 0xffffffffU, /*0380*/ 0x0808028eU, /*0381*/ 0x1008028eU, /*0382*/ 0x1808028eU, /*0383*/ 0x0008028fU, /*0384*/ 0x0808028fU, /*0385*/ 0x1008028fU, /*0386*/ 0xffffffffU, /*0387*/ 0x1808028fU, /*0388*/ 0x00080290U, /*0389*/ 0x08080290U, /*038a*/ 0x10080290U, /*038b*/ 0x18080290U, /*038c*/ 0x00080291U, /*038d*/ 0xffffffffU, /*038e*/ 0x08080291U, /*038f*/ 0x10080291U, /*0390*/ 0x18080291U, /*0391*/ 0x00080292U, /*0392*/ 0x08080292U, /*0393*/ 0x10080292U, /*0394*/ 0x18080292U, /*0395*/ 0xffffffffU, /*0396*/ 0x00080293U, /*0397*/ 0x08080293U, /*0398*/ 0x10080293U, /*0399*/ 0x18080293U, /*039a*/ 0x00080294U, /*039b*/ 0x08080294U, /*039c*/ 0xffffffffU, /*039d*/ 0x10080294U, /*039e*/ 0x18080294U, /*039f*/ 0x00080295U, /*03a0*/ 0x08080295U, /*03a1*/ 0x10080295U, /*03a2*/ 0x18080295U, /*03a3*/ 0xffffffffU, /*03a4*/ 0x00080296U, /*03a5*/ 0x08080296U, /*03a6*/ 0x10080296U, /*03a7*/ 0x18080296U, /*03a8*/ 0x00080297U, /*03a9*/ 0x08080297U, /*03aa*/ 0x10080297U, /*03ab*/ 0xffffffffU, /*03ac*/ 0x18080297U, /*03ad*/ 0x00080298U, /*03ae*/ 0x08080298U, /*03af*/ 0x10080298U, /*03b0*/ 0x18080298U, /*03b1*/ 0x00080299U, /*03b2*/ 0xffffffffU, /*03b3*/ 0x08080299U, /*03b4*/ 0x10080299U, /*03b5*/ 0x18080299U, /*03b6*/ 0x0008029aU, /*03b7*/ 0x0808029aU, /*03b8*/ 0x1008029aU, /*03b9*/ 0xffffffffU, /*03ba*/ 0x1808029aU, /*03bb*/ 0x0002029bU, /*03bc*/ 0x0803029bU, /*03bd*/ 0x100a029bU, /*03be*/ 0x000a029cU, /*03bf*/ 0x100a029cU, /*03c0*/ 0x0005029dU, /*03c1*/ 0x0808029dU, /*03c2*/ 0x1008029dU, /*03c3*/ 0x1808029dU, /*03c4*/ 0x0006029eU, /*03c5*/ 0x0806029eU, /*03c6*/ 0x0011029fU, /*03c7*/ 0x1808029fU, /*03c8*/ 0x000402a0U, /*03c9*/ 0x080602a0U, /*03ca*/ 0xffffffffU, /*03cb*/ 0x100602a0U, /*03cc*/ 0x180802a0U, /*03cd*/ 0xffffffffU, /*03ce*/ 0x000802a1U, /*03cf*/ 0x080802a1U, /*03d0*/ 0x100802a1U, /*03d1*/ 0x180602a1U, /*03d2*/ 0x000602a2U, /*03d3*/ 0x081102a2U, /*03d4*/ 0x000802a3U, /*03d5*/ 0x080402a3U, /*03d6*/ 0x100602a3U, /*03d7*/ 0xffffffffU, /*03d8*/ 0x180602a3U, /*03d9*/ 0x000802a4U, /*03da*/ 0xffffffffU, /*03db*/ 0x080802a4U, /*03dc*/ 0x100802a4U, /*03dd*/ 0x180802a4U, /*03de*/ 0x000602a5U, /*03df*/ 0x080602a5U, /*03e0*/ 0x001102a6U, /*03e1*/ 0x180802a6U, /*03e2*/ 0x000402a7U, /*03e3*/ 0x080602a7U, /*03e4*/ 0xffffffffU, /*03e5*/ 0x100602a7U, /*03e6*/ 0x180802a7U, /*03e7*/ 0xffffffffU, /*03e8*/ 0x000402a8U, /*03e9*/ 0x080402a8U, /*03ea*/ 0x100402a8U, /*03eb*/ 0x180402a8U, /*03ec*/ 0x000402a9U, /*03ed*/ 0x080402a9U, /*03ee*/ 0x100402a9U, /*03ef*/ 0x180402a9U, /*03f0*/ 0x000402aaU, /*03f1*/ 0x080402aaU, /*03f2*/ 0x100402aaU, /*03f3*/ 0x180402aaU, /*03f4*/ 0x000402abU, /*03f5*/ 0x080402abU, /*03f6*/ 0x100402abU, /*03f7*/ 0x180402abU, /*03f8*/ 0x000402acU, /*03f9*/ 0x080402acU, /*03fa*/ 0x100402acU, /*03fb*/ 0x180402acU, /*03fc*/ 0x001202adU, /*03fd*/ 0x001102aeU, /*03fe*/ 0x001202afU, /*03ff*/ 0x002002b0U, /*0400*/ 0x002002b1U, /*0401*/ 0x002002b2U, /*0402*/ 0x002002b3U, /*0403*/ 0x002002b4U, /*0404*/ 0x002002b5U, /*0405*/ 0x002002b6U, /*0406*/ 0x002002b7U, /*0407*/ 0x002002b8U, /*0408*/ 0x000202b9U, /*0409*/ 0x080502b9U, /*040a*/ 0x100502b9U, /*040b*/ 0x180102b9U, /*040c*/ 0x000402baU, /*040d*/ 0x080402baU, /*040e*/ 0x100402baU, /*040f*/ 0x180402baU, /*0410*/ 0x000402bbU, /*0411*/ 0x080402bbU, /*0412*/ 0x100402bbU, /*0413*/ 0x180402bbU, /*0414*/ 0xffffffffU, /*0415*/ 0xffffffffU, /*0416*/ 0xffffffffU, /*0417*/ 0xffffffffU, /*0418*/ 0xffffffffU, /*0419*/ 0xffffffffU, /*041a*/ 0x000402bcU, /*041b*/ 0x080402bcU, /*041c*/ 0x100402bcU, /*041d*/ 0x180402bcU, /*041e*/ 0x000402bdU, /*041f*/ 0x080402bdU, /*0420*/ 0x100402bdU, /*0421*/ 0x180402bdU, /*0422*/ 0x000102beU, /*0423*/ 0x080202beU, /*0424*/ 0x100202beU, /*0425*/ 0x180202beU, /*0426*/ 0x000202bfU, /*0427*/ 0x080102bfU, /*0428*/ 0x100402bfU, /*0429*/ 0x001002c0U, /*042a*/ 0x002002c1U, /*042b*/ 0x001002c2U, /*042c*/ 0x002002c3U, /*042d*/ 0x001002c4U, /*042e*/ 0x002002c5U, /*042f*/ 0x000702c6U, /*0430*/ 0x080102c6U, /*0431*/ 0x100202c6U, /*0432*/ 0x180602c6U, /*0433*/ 0x000102c7U, /*0434*/ 0x080102c7U, /*0435*/ 0x002002c8U, /*0436*/ 0x000202c9U, /*0437*/ 0x002002caU, /*0438*/ 0x002002cbU, /*0439*/ 0x000c02ccU, /*043a*/ 0x100c02ccU, /*043b*/ 0x002002cdU, /*043c*/ 0x000302ceU, /*043d*/ 0x002002cfU, /*043e*/ 0x000302d0U, /*043f*/ 0x002002d1U, /*0440*/ 0x000302d2U, /*0441*/ 0x002002d3U, /*0442*/ 0x000302d4U, /*0443*/ 0x002002d5U, /*0444*/ 0x000302d6U, /*0445*/ 0x002002d7U, /*0446*/ 0x000302d8U, /*0447*/ 0x002002d9U, /*0448*/ 0x000302daU, /*0449*/ 0x002002dbU, /*044a*/ 0x000302dcU, /*044b*/ 0x002002ddU, /*044c*/ 0x000302deU, /*044d*/ 0x002002dfU, /*044e*/ 0x000302e0U, /*044f*/ 0x080302e0U, /*0450*/ 0x100202e0U, /*0451*/ 0x180202e0U, /*0452*/ 0x002002e1U, /*0453*/ 0x002002e2U, /*0454*/ 0x002002e3U, /*0455*/ 0x002002e4U, /*0456*/ 0x000402e5U, /*0457*/ 0x001e02e6U, /*0458*/ 0x001e02e7U, /*0459*/ 0x001e02e8U, /*045a*/ 0x001e02e9U, /*045b*/ 0x001e02eaU, /*045c*/ 0x001e02ebU, /*045d*/ 0x001e02ecU, /*045e*/ 0x001e02edU, /*045f*/ 0x000402eeU, /*0460*/ 0xffffffffU, /*0461*/ 0xffffffffU, /*0462*/ 0xffffffffU, /*0463*/ 0xffffffffU, /*0464*/ 0x080402eeU, /*0465*/ 0x100102eeU, /*0466*/ 0x180802eeU, /*0467*/ 0x000402efU, /*0468*/ 0x080102efU, /*0469*/ 0x100802efU, /*046a*/ 0x180402efU, /*046b*/ 0x000102f0U, /*046c*/ 0x080802f0U, /*046d*/ 0x100402f0U, /*046e*/ 0x180102f0U, /*046f*/ 0x000802f1U, /*0470*/ 0x080402f1U, /*0471*/ 0x100102f1U, /*0472*/ 0x180802f1U, /*0473*/ 0x000402f2U, /*0474*/ 0x080102f2U, /*0475*/ 0x100802f2U, /*0476*/ 0x180402f2U, /*0477*/ 0x000102f3U, /*0478*/ 0x080802f3U, /*0479*/ 0x100402f3U, /*047a*/ 0x180102f3U, /*047b*/ 0x000802f4U, /*047c*/ 0x080802f4U, /*047d*/ 0x100102f4U, /*047e*/ 0x180502f4U, /*047f*/ 0xffffffffU, /*0480*/ 0xffffffffU, /*0481*/ 0xffffffffU, /*0482*/ 0xffffffffU, /*0483*/ 0xffffffffU, /*0484*/ 0xffffffffU, /*0485*/ 0xffffffffU, /*0486*/ 0xffffffffU, /*0487*/ 0xffffffffU, /*0488*/ 0xffffffffU, /*0489*/ 0xffffffffU, /*048a*/ 0xffffffffU, /*048b*/ 0xffffffffU, /*048c*/ 0xffffffffU, /*048d*/ 0xffffffffU, /*048e*/ 0xffffffffU, /*048f*/ 0xffffffffU, /*0490*/ 0xffffffffU, /*0491*/ 0xffffffffU, /*0492*/ 0xffffffffU, /*0493*/ 0xffffffffU, /*0494*/ 0xffffffffU, }, { /*0000*/ 0x00200800U, /*0001*/ 0x00040801U, /*0002*/ 0x080b0801U, /*0003*/ 0x000a0802U, /*0004*/ 0x10020802U, /*0005*/ 0x18010802U, /*0006*/ 0x00060803U, /*0007*/ 0x08060803U, /*0008*/ 0x10060803U, /*0009*/ 0x18060803U, /*000a*/ 0x00060804U, /*000b*/ 0x08060804U, /*000c*/ 0x10050804U, /*000d*/ 0x18060804U, /*000e*/ 0x00060805U, /*000f*/ 0x08040805U, /*0010*/ 0x10030805U, /*0011*/ 0x00180806U, /*0012*/ 0x18030806U, /*0013*/ 0x00180807U, /*0014*/ 0x18020807U, /*0015*/ 0x0801085eU, /*0016*/ 0x00020808U, /*0017*/ 0x08010808U, /*0018*/ 0x10010808U, /*0019*/ 0x18020808U, /*001a*/ 0x00050809U, /*001b*/ 0x08050809U, /*001c*/ 0x10040809U, /*001d*/ 0xffffffffU, /*001e*/ 0x18040809U, /*001f*/ 0x0002080aU, /*0020*/ 0x0805080aU, /*0021*/ 0x1009080aU, /*0022*/ 0x0001080bU, /*0023*/ 0x0020080cU, /*0024*/ 0x001c080dU, /*0025*/ 0x0001080eU, /*0026*/ 0x0807080eU, /*0027*/ 0x1009080eU, /*0028*/ 0x000a080fU, /*0029*/ 0x1005080fU, /*002a*/ 0x1801080fU, /*002b*/ 0x10010810U, /*002c*/ 0x18020810U, /*002d*/ 0x00090810U, /*002e*/ 0x00090811U, /*002f*/ 0x10020811U, /*0030*/ 0x00200812U, /*0031*/ 0x00010813U, /*0032*/ 0x08020813U, /*0033*/ 0x00200814U, /*0034*/ 0x00200815U, /*0035*/ 0x00200816U, /*0036*/ 0x00200817U, /*0037*/ 0xffffffffU, /*0038*/ 0xffffffffU, /*0039*/ 0xffffffffU, /*003a*/ 0xffffffffU, /*003b*/ 0x00030818U, /*003c*/ 0x08010818U, /*003d*/ 0x10040818U, /*003e*/ 0x18030818U, /*003f*/ 0x00040819U, /*0040*/ 0x08040819U, /*0041*/ 0x10040819U, /*0042*/ 0x18040819U, /*0043*/ 0x0001081aU, /*0044*/ 0x0801081aU, /*0045*/ 0x1006081aU, /*0046*/ 0x1804081aU, /*0047*/ 0x0008081bU, /*0048*/ 0x0806081bU, /*0049*/ 0x1004081bU, /*004a*/ 0x1806081bU, /*004b*/ 0x0004081cU, /*004c*/ 0x0802081cU, /*004d*/ 0x1005081cU, /*004e*/ 0x1808081cU, /*004f*/ 0xffffffffU, /*0050*/ 0x0006081dU, /*0051*/ 0x0803081dU, /*0052*/ 0x100b081dU, /*0053*/ 0x0004081eU, /*0054*/ 0x0804081eU, /*0055*/ 0x1004081eU, /*0056*/ 0x1801081eU, /*0057*/ 0xffffffffU, /*0058*/ 0x0009081fU, /*0059*/ 0x00200820U, /*005a*/ 0x00200821U, /*005b*/ 0x00200822U, /*005c*/ 0x00200823U, /*005d*/ 0x00100824U, /*005e*/ 0xffffffffU, /*005f*/ 0x10010824U, /*0060*/ 0x18060824U, /*0061*/ 0x00080825U, /*0062*/ 0x00200826U, /*0063*/ 0x00100827U, /*0064*/ 0x100b0827U, /*0065*/ 0x00070828U, /*0066*/ 0x08070828U, /*0067*/ 0x10090828U, /*0068*/ 0x00090829U, /*0069*/ 0x100b0829U, /*006a*/ 0x0007082aU, /*006b*/ 0x0808082aU, /*006c*/ 0x1009082aU, /*006d*/ 0x0003082bU, /*006e*/ 0x080a082bU, /*006f*/ 0x000a082cU, /*0070*/ 0x0011082dU, /*0071*/ 0x000a082eU, /*0072*/ 0x100a082eU, /*0073*/ 0x0010082fU, /*0074*/ 0x100e082fU, /*0075*/ 0x000e0830U, /*0076*/ 0x00120831U, /*0077*/ 0x000a0832U, /*0078*/ 0x100a0832U, /*0079*/ 0x00020833U, /*007a*/ 0x00200834U, /*007b*/ 0x000b0835U, /*007c*/ 0x100b0835U, /*007d*/ 0x00200836U, /*007e*/ 0x00130837U, /*007f*/ 0x00200838U, /*0080*/ 0x00200839U, /*0081*/ 0x0008083aU, /*0082*/ 0x0801083aU, /*0083*/ 0x1001083aU, /*0084*/ 0x1801083aU, /*0085*/ 0x0008083bU, /*0086*/ 0x080c083bU, /*0087*/ 0x000c083cU, /*0088*/ 0x100c083cU, /*0089*/ 0x000c083dU, /*008a*/ 0x100c083dU, /*008b*/ 0x000c083eU, /*008c*/ 0x100c083eU, /*008d*/ 0x000c083fU, /*008e*/ 0x100c083fU, /*008f*/ 0x000c0840U, /*0090*/ 0x100c0840U, /*0091*/ 0x000b0841U, /*0092*/ 0x10090841U, /*0093*/ 0x00010842U, /*0094*/ 0x000b0843U, /*0095*/ 0x100b0843U, /*0096*/ 0x000b0844U, /*0097*/ 0x100b0844U, /*0098*/ 0x000b0845U, /*0099*/ 0x100b0845U, /*009a*/ 0x000b0846U, /*009b*/ 0x100b0846U, /*009c*/ 0x000b0847U, /*009d*/ 0x100a0847U, /*009e*/ 0x00020848U, /*009f*/ 0x080a0848U, /*00a0*/ 0x000a0849U, /*00a1*/ 0x100a0849U, /*00a2*/ 0x000a084aU, /*00a3*/ 0x100a084aU, /*00a4*/ 0x000a084bU, /*00a5*/ 0x100a084bU, /*00a6*/ 0x000a084cU, /*00a7*/ 0x100a084cU, /*00a8*/ 0x000a084dU, /*00a9*/ 0x100a084dU, /*00aa*/ 0x000a084eU, /*00ab*/ 0x100a084eU, /*00ac*/ 0x000a084fU, /*00ad*/ 0x100a084fU, /*00ae*/ 0x000a0850U, /*00af*/ 0x100a0850U, /*00b0*/ 0x000a0851U, /*00b1*/ 0x100a0851U, /*00b2*/ 0x000a0852U, /*00b3*/ 0x100a0852U, /*00b4*/ 0x000a0853U, /*00b5*/ 0x100a0853U, /*00b6*/ 0x000a0854U, /*00b7*/ 0x100a0854U, /*00b8*/ 0x000a0855U, /*00b9*/ 0x100a0855U, /*00ba*/ 0x000a0856U, /*00bb*/ 0x10040856U, /*00bc*/ 0x18030856U, /*00bd*/ 0x000a0857U, /*00be*/ 0x100a0857U, /*00bf*/ 0x00010858U, /*00c0*/ 0x080a0858U, /*00c1*/ 0x18040858U, /*00c2*/ 0x000b0859U, /*00c3*/ 0x100a0859U, /*00c4*/ 0x0003085aU, /*00c5*/ 0x0008085bU, /*00c6*/ 0x0808085bU, /*00c7*/ 0x1008085bU, /*00c8*/ 0x1808085bU, /*00c9*/ 0x0008085cU, /*00ca*/ 0x0808085cU, /*00cb*/ 0x1008085cU, /*00cc*/ 0x1801085cU, /*00cd*/ 0x0008085dU, /*00ce*/ 0x0808085dU, /*00cf*/ 0x1002085dU, /*00d0*/ 0x1802085dU, /*00d1*/ 0x0005085eU, /*00d2*/ 0x1005085eU, /*00d3*/ 0x1805085eU, /*00d4*/ 0x0004085fU, /*00d5*/ 0x080b085fU, /*00d6*/ 0x1806085fU, /*00d7*/ 0x00080860U, /*00d8*/ 0x08080860U, /*00d9*/ 0x10040860U, /*00da*/ 0x18040860U, /*00db*/ 0x00060861U, /*00dc*/ 0x08040861U, /*00dd*/ 0x10050861U, /*00de*/ 0x000a0862U, /*00df*/ 0x100a0862U, /*00e0*/ 0x00080863U, /*00e1*/ 0x08010863U, /*00e2*/ 0x10040863U, /*00e3*/ 0x00020864U, /*00e4*/ 0x08030864U, /*00e5*/ 0x00050a00U, /*00e6*/ 0x08050a00U, /*00e7*/ 0x10050a00U, /*00e8*/ 0x18050a00U, /*00e9*/ 0x00050a01U, /*00ea*/ 0x08050a01U, /*00eb*/ 0x100b0a01U, /*00ec*/ 0x00010a02U, /*00ed*/ 0x08030a02U, /*00ee*/ 0x00200a03U, /*00ef*/ 0x00100a04U, /*00f0*/ 0x10040a04U, /*00f1*/ 0x000b0a05U, /*00f2*/ 0x10070a05U, /*00f3*/ 0x00090a06U, /*00f4*/ 0x10030a06U, /*00f5*/ 0x18030a06U, /*00f6*/ 0x00010a07U, /*00f7*/ 0x08010a07U, /*00f8*/ 0x10070a07U, /*00f9*/ 0x18070a07U, /*00fa*/ 0x00050a08U, /*00fb*/ 0x08010a08U, /*00fc*/ 0x10020a08U, /*00fd*/ 0x18030a08U, /*00fe*/ 0x00010a09U, /*00ff*/ 0x080f0a09U, /*0100*/ 0x00200a0aU, /*0101*/ 0x00200a0bU, /*0102*/ 0x000b0a0cU, /*0103*/ 0x100b0a0cU, /*0104*/ 0x000b0a0dU, /*0105*/ 0x00180a0eU, /*0106*/ 0x00180a0fU, /*0107*/ 0xffffffffU, /*0108*/ 0xffffffffU, /*0109*/ 0xffffffffU, /*010a*/ 0xffffffffU, /*010b*/ 0xffffffffU, /*010c*/ 0x18020a0fU, /*010d*/ 0x00020a10U, /*010e*/ 0x08040a10U, /*010f*/ 0x10040a10U, /*0110*/ 0x18010a10U, /*0111*/ 0x00010a11U, /*0112*/ 0x08010a11U, /*0113*/ 0x10030a11U, /*0114*/ 0x00200a12U, /*0115*/ 0x00200a13U, /*0116*/ 0xffffffffU, /*0117*/ 0x00140a14U, /*0118*/ 0x00140a15U, /*0119*/ 0x00140a16U, /*011a*/ 0x00140a17U, /*011b*/ 0x00140a18U, /*011c*/ 0x00140a19U, /*011d*/ 0x00140a1aU, /*011e*/ 0x00140a1bU, /*011f*/ 0x001e0a1cU, /*0120*/ 0x000a0a1dU, /*0121*/ 0x10060a1dU, /*0122*/ 0x18060a1dU, /*0123*/ 0x00060a1eU, /*0124*/ 0x08060a1eU, /*0125*/ 0x10060a1eU, /*0126*/ 0x00080a1fU, /*0127*/ 0x080b0a1fU, /*0128*/ 0x000b0a20U, /*0129*/ 0x100b0a20U, /*012a*/ 0x000b0a21U, /*012b*/ 0x100b0a21U, /*012c*/ 0x000b0a22U, /*012d*/ 0x10040a22U, /*012e*/ 0x000b0a23U, /*012f*/ 0x10060a23U, /*0130*/ 0x18080a23U, /*0131*/ 0x00080a24U, /*0132*/ 0x08040a24U, /*0133*/ 0x00020b80U, /*0134*/ 0x00010b81U, /*0135*/ 0x08010b81U, /*0136*/ 0x10020b81U, /*0137*/ 0x18050b81U, /*0138*/ 0x00050b82U, /*0139*/ 0x08050b82U, /*013a*/ 0x10050b82U, /*013b*/ 0x000b0b83U, /*013c*/ 0x10050b83U, /*013d*/ 0x18010b83U, /*013e*/ 0x00010b84U, /*013f*/ 0x08010b84U, /*0140*/ 0x10010b84U, /*0141*/ 0x18010b84U, /*0142*/ 0x00040b85U, /*0143*/ 0x080b0b85U, /*0144*/ 0x000b0b86U, /*0145*/ 0x100b0b86U, /*0146*/ 0x00040b87U, /*0147*/ 0x080b0b87U, /*0148*/ 0x18040b87U, /*0149*/ 0x00010b88U, /*014a*/ 0x08010b88U, /*014b*/ 0x10010b88U, /*014c*/ 0x00200b89U, /*014d*/ 0x00200b8aU, /*014e*/ 0x00080b8bU, /*014f*/ 0x080a0b8bU, /*0150*/ 0x18050b8bU, /*0151*/ 0x000b0b8cU, /*0152*/ 0x10030b8cU, /*0153*/ 0x18030b8cU, /*0154*/ 0x00010b8dU, /*0155*/ 0x08020b8dU, /*0156*/ 0x10010b8dU, /*0157*/ 0x18010b8dU, /*0158*/ 0x00010b8eU, /*0159*/ 0xffffffffU, /*015a*/ 0x08010b8eU, /*015b*/ 0x18040b8eU, /*015c*/ 0x00040b8fU, /*015d*/ 0x08040b8fU, /*015e*/ 0x10040b8fU, /*015f*/ 0x18010b8fU, /*0160*/ 0x00010b90U, /*0161*/ 0x08010b90U, /*0162*/ 0x00200b91U, /*0163*/ 0x00200b92U, /*0164*/ 0x00200b93U, /*0165*/ 0x00200b94U, /*0166*/ 0xffffffffU, /*0167*/ 0x10010b8eU, /*0168*/ 0x000d0b96U, /*0169*/ 0x100d0b96U, /*016a*/ 0x000d0b97U, /*016b*/ 0x00050b98U, /*016c*/ 0x00010b99U, /*016d*/ 0x080e0b99U, /*016e*/ 0x000e0b9aU, /*016f*/ 0x100e0b9aU, /*0170*/ 0x000e0b9bU, /*0171*/ 0x100e0b9bU, /*0172*/ 0x00040b9cU, /*0173*/ 0x08040b9cU, /*0174*/ 0x10040b9cU, /*0175*/ 0x18040b9cU, /*0176*/ 0x00040b9dU, /*0177*/ 0x080b0b9dU, /*0178*/ 0x000b0b9eU, /*0179*/ 0x100b0b9eU, /*017a*/ 0x000b0b9fU, /*017b*/ 0x00040ba0U, /*017c*/ 0x08040ba0U, /*017d*/ 0x10040ba0U, /*017e*/ 0x18040ba0U, /*017f*/ 0x000d0ba1U, /*0180*/ 0x100d0ba1U, /*0181*/ 0x000d0ba2U, /*0182*/ 0x10100ba2U, /*0183*/ 0x00080b95U, /*0184*/ 0x08080b95U, /*0185*/ 0x00100ba3U, /*0186*/ 0x10100ba3U, /*0187*/ 0x00100ba4U, /*0188*/ 0x10100ba4U, /*0189*/ 0x00100ba5U, /*018a*/ 0x10030ba5U, /*018b*/ 0x18040ba5U, /*018c*/ 0x00010ba6U, /*018d*/ 0x08080ba6U, /*018e*/ 0x10010ba6U, /*018f*/ 0x000a0ba7U, /*0190*/ 0x10010ba7U, /*0191*/ 0x00140ba8U, /*0192*/ 0x000b0ba9U, /*0193*/ 0x100c0ba9U, /*0194*/ 0x00120baaU, /*0195*/ 0x00140babU, /*0196*/ 0x00120bacU, /*0197*/ 0x00110badU, /*0198*/ 0x00110baeU, /*0199*/ 0x00120bafU, /*019a*/ 0x00120bb0U, /*019b*/ 0x00120bb1U, /*019c*/ 0x00120bb2U, /*019d*/ 0x00120bb3U, /*019e*/ 0x00120bb4U, /*019f*/ 0x00120bb5U, /*01a0*/ 0x00120bb6U, /*01a1*/ 0x00120bb7U, /*01a2*/ 0x00120bb8U, /*01a3*/ 0x000e0bb9U, /*01a4*/ 0x100d0bb9U, /*01a5*/ 0x00200bbaU, /*01a6*/ 0x00170bbbU, /*01a7*/ 0x000d0bbcU, /*01a8*/ 0x10010bbcU, /*01a9*/ 0x18010bbcU, /*01aa*/ 0x00200bbdU, /*01ab*/ 0x00080bbeU, /*01ac*/ 0x08030bbeU, /*01ad*/ 0x10030bbeU, /*01ae*/ 0x00180bbfU, /*01af*/ 0x00180bc0U, /*01b0*/ 0x18070bc0U, /*01b1*/ 0x00070bc1U, /*01b2*/ 0x08080bc1U, /*01b3*/ 0x10080bc1U, /*01b4*/ 0x18080bc1U, /*01b5*/ 0x00010bc2U, /*01b6*/ 0x08010bc2U, /*01b7*/ 0x00200bc3U, /*01b8*/ 0x00070bc4U, /*01b9*/ 0x08140bc4U, /*01ba*/ 0x00140bc5U, /*01bb*/ 0x00190bc6U, /*01bc*/ 0x00170bc7U, /*01bd*/ 0x00110bc8U, /*01be*/ 0x00110bc9U, /*01bf*/ 0x00100bcaU, /*01c0*/ 0x10010bcaU, /*01c1*/ 0x18010bcaU, /*01c2*/ 0x00020bcbU, /*01c3*/ 0x08040bcbU, /*01c4*/ 0x10090bcbU, /*01c5*/ 0x00070bccU, /*01c6*/ 0x08040bccU, /*01c7*/ 0x00200bcdU, /*01c8*/ 0x00010bceU, /*01c9*/ 0x08020bceU, /*01ca*/ 0x10060bceU, /*01cb*/ 0x00100bcfU, /*01cc*/ 0x10010bcfU, /*01cd*/ 0x00200bd0U, /*01ce*/ 0x00080bd1U, /*01cf*/ 0x08010bd1U, /*01d0*/ 0x10050bd1U, /*01d1*/ 0x18030bd1U, /*01d2*/ 0x00020bd2U, /*01d3*/ 0xffffffffU, /*01d4*/ 0x00200bd3U, /*01d5*/ 0x000b0bd4U, /*01d6*/ 0xffffffffU, /*01d7*/ 0x10030bd4U, /*01d8*/ 0x18080bd4U, /*01d9*/ 0x00020bd5U, /*01da*/ 0x080c0bd5U, /*01db*/ 0x18040bd5U, /*01dc*/ 0x00010bd6U, /*01dd*/ 0x08050bd6U, /*01de*/ 0x00010200U, /*01df*/ 0x08040200U, /*01e0*/ 0x10100200U, /*01e1*/ 0x00010201U, /*01e2*/ 0x08010201U, /*01e3*/ 0x10010201U, /*01e4*/ 0x18010201U, /*01e5*/ 0x00100202U, /*01e6*/ 0x10080202U, /*01e7*/ 0x18010202U, /*01e8*/ 0x00200203U, /*01e9*/ 0x00200204U, /*01ea*/ 0x00200205U, /*01eb*/ 0x00200206U, /*01ec*/ 0x00020207U, /*01ed*/ 0x08010207U, /*01ee*/ 0x10010207U, /*01ef*/ 0x00200208U, /*01f0*/ 0x00140209U, /*01f1*/ 0x0020020aU, /*01f2*/ 0x0014020bU, /*01f3*/ 0x0020020cU, /*01f4*/ 0x0014020dU, /*01f5*/ 0x0014020eU, /*01f6*/ 0x0020020fU, /*01f7*/ 0x00200210U, /*01f8*/ 0x00200211U, /*01f9*/ 0x00200212U, /*01fa*/ 0x00140213U, /*01fb*/ 0x00200214U, /*01fc*/ 0x00200215U, /*01fd*/ 0x00200216U, /*01fe*/ 0x00200217U, /*01ff*/ 0x00140218U, /*0200*/ 0x00200219U, /*0201*/ 0x0020021aU, /*0202*/ 0x0020021bU, /*0203*/ 0x0020021cU, /*0204*/ 0x0009021dU, /*0205*/ 0x1001021dU, /*0206*/ 0x0020021eU, /*0207*/ 0x0005021fU, /*0208*/ 0x0801021fU, /*0209*/ 0x1008021fU, /*020a*/ 0x1808021fU, /*020b*/ 0x001e0220U, /*020c*/ 0x001e0221U, /*020d*/ 0x001e0222U, /*020e*/ 0x001e0223U, /*020f*/ 0x001e0224U, /*0210*/ 0x001e0225U, /*0211*/ 0x001e0226U, /*0212*/ 0x001e0227U, /*0213*/ 0x001e0228U, /*0214*/ 0x001e0229U, /*0215*/ 0x001e022aU, /*0216*/ 0x001e022bU, /*0217*/ 0x001e022cU, /*0218*/ 0x001e022dU, /*0219*/ 0x001e022eU, /*021a*/ 0x001e022fU, /*021b*/ 0x00010230U, /*021c*/ 0x08010230U, /*021d*/ 0x10010230U, /*021e*/ 0x18040230U, /*021f*/ 0x00080231U, /*0220*/ 0x08080231U, /*0221*/ 0x10080231U, /*0222*/ 0x18040231U, /*0223*/ 0x00070232U, /*0224*/ 0x08060232U, /*0225*/ 0x10070232U, /*0226*/ 0x18070232U, /*0227*/ 0x00060233U, /*0228*/ 0x08070233U, /*0229*/ 0x10070233U, /*022a*/ 0x18060233U, /*022b*/ 0x00070234U, /*022c*/ 0x08020234U, /*022d*/ 0x10010234U, /*022e*/ 0x18010234U, /*022f*/ 0x000a0235U, /*0230*/ 0x00140236U, /*0231*/ 0x000a0237U, /*0232*/ 0x00140238U, /*0233*/ 0x000a0239U, /*0234*/ 0x0014023aU, /*0235*/ 0xffffffffU, /*0236*/ 0xffffffffU, /*0237*/ 0x0005023bU, /*0238*/ 0x0001023cU, /*0239*/ 0x1001023cU, /*023a*/ 0x1801023cU, /*023b*/ 0x0001023dU, /*023c*/ 0x0801023dU, /*023d*/ 0x1001023dU, /*023e*/ 0x1801023dU, /*023f*/ 0x0002023eU, /*0240*/ 0x0802023eU, /*0241*/ 0x1002023eU, /*0242*/ 0x1802023eU, /*0243*/ 0x0002023fU, /*0244*/ 0x0803023fU, /*0245*/ 0x1001023fU, /*0246*/ 0x1801023fU, /*0247*/ 0x00010240U, /*0248*/ 0x08010240U, /*0249*/ 0x10010240U, /*024a*/ 0x18020240U, /*024b*/ 0x00010241U, /*024c*/ 0x08010241U, /*024d*/ 0x10010241U, /*024e*/ 0x18020241U, /*024f*/ 0x00010242U, /*0250*/ 0x08010242U, /*0251*/ 0x10010242U, /*0252*/ 0x18020242U, /*0253*/ 0x00010243U, /*0254*/ 0x08010243U, /*0255*/ 0x10010243U, /*0256*/ 0x18020243U, /*0257*/ 0xffffffffU, /*0258*/ 0x00010244U, /*0259*/ 0x08010244U, /*025a*/ 0x10010244U, /*025b*/ 0x18010244U, /*025c*/ 0x00010245U, /*025d*/ 0x08010245U, /*025e*/ 0x10010245U, /*025f*/ 0x18010245U, /*0260*/ 0x00040246U, /*0261*/ 0x08040246U, /*0262*/ 0x10040246U, /*0263*/ 0x18010246U, /*0264*/ 0x00020247U, /*0265*/ 0x08060247U, /*0266*/ 0x10060247U, /*0267*/ 0x18020247U, /*0268*/ 0x00020248U, /*0269*/ 0x08020248U, /*026a*/ 0xffffffffU, /*026b*/ 0x10100248U, /*026c*/ 0x00010249U, /*026d*/ 0x08010249U, /*026e*/ 0x10010249U, /*026f*/ 0x18040249U, /*0270*/ 0x0001024aU, /*0271*/ 0x0804024aU, /*0272*/ 0x1003024aU, /*0273*/ 0x1808024aU, /*0274*/ 0x000a024bU, /*0275*/ 0x100a024bU, /*0276*/ 0x000a024cU, /*0277*/ 0xffffffffU, /*0278*/ 0x0020024dU, /*0279*/ 0x0020024eU, /*027a*/ 0x0005024fU, /*027b*/ 0x1801023aU, /*027c*/ 0x0805023cU, /*027d*/ 0x0808024fU, /*027e*/ 0x1001024fU, /*027f*/ 0x1808024fU, /*0280*/ 0x00010250U, /*0281*/ 0x08080250U, /*0282*/ 0x10010250U, /*0283*/ 0x18040250U, /*0284*/ 0x00040251U, /*0285*/ 0x08040251U, /*0286*/ 0x10040251U, /*0287*/ 0x18040251U, /*0288*/ 0x00040252U, /*0289*/ 0x08040252U, /*028a*/ 0x10040252U, /*028b*/ 0x18040252U, /*028c*/ 0x00040253U, /*028d*/ 0x08010253U, /*028e*/ 0x10040253U, /*028f*/ 0x18040253U, /*0290*/ 0x00040254U, /*0291*/ 0x08040254U, /*0292*/ 0x10040254U, /*0293*/ 0x18040254U, /*0294*/ 0x00060255U, /*0295*/ 0x08060255U, /*0296*/ 0x10060255U, /*0297*/ 0x18060255U, /*0298*/ 0x00060256U, /*0299*/ 0x08060256U, /*029a*/ 0x10040256U, /*029b*/ 0x18010256U, /*029c*/ 0x00010257U, /*029d*/ 0x08020257U, /*029e*/ 0x00200258U, /*029f*/ 0x00200259U, /*02a0*/ 0x0020025aU, /*02a1*/ 0x0020025bU, /*02a2*/ 0x0020025cU, /*02a3*/ 0x0020025dU, /*02a4*/ 0x0020025eU, /*02a5*/ 0x0020025fU, /*02a6*/ 0x00040260U, /*02a7*/ 0x08040260U, /*02a8*/ 0x10010260U, /*02a9*/ 0x18010260U, /*02aa*/ 0x00010261U, /*02ab*/ 0x08010261U, /*02ac*/ 0x10010261U, /*02ad*/ 0x18010261U, /*02ae*/ 0x00010262U, /*02af*/ 0x08010262U, /*02b0*/ 0x10010262U, /*02b1*/ 0x18040262U, /*02b2*/ 0x00040263U, /*02b3*/ 0x080a0263U, /*02b4*/ 0x00200264U, /*02b5*/ 0x00040265U, /*02b6*/ 0x08080265U, /*02b7*/ 0x10020265U, /*02b8*/ 0x18020265U, /*02b9*/ 0x00020266U, /*02ba*/ 0x08020266U, /*02bb*/ 0x10020266U, /*02bc*/ 0x18020266U, /*02bd*/ 0xffffffffU, /*02be*/ 0xffffffffU, /*02bf*/ 0x00200267U, /*02c0*/ 0x00030268U, /*02c1*/ 0x08100268U, /*02c2*/ 0x00100269U, /*02c3*/ 0x10040269U, /*02c4*/ 0x18040269U, /*02c5*/ 0x0005026aU, /*02c6*/ 0x0805026aU, /*02c7*/ 0xffffffffU, /*02c8*/ 0xffffffffU, /*02c9*/ 0xffffffffU, /*02ca*/ 0xffffffffU, /*02cb*/ 0x1001026aU, /*02cc*/ 0x1801026aU, /*02cd*/ 0x0008026bU, /*02ce*/ 0x0808026bU, /*02cf*/ 0x1008026bU, /*02d0*/ 0x1808026bU, /*02d1*/ 0x0008026cU, /*02d2*/ 0x0808026cU, /*02d3*/ 0x1008026cU, /*02d4*/ 0x1808026cU, /*02d5*/ 0x0008026dU, /*02d6*/ 0x0808026dU, /*02d7*/ 0x1008026dU, /*02d8*/ 0x1808026dU, /*02d9*/ 0x0008026eU, /*02da*/ 0x0808026eU, /*02db*/ 0x1003026eU, /*02dc*/ 0x1803026eU, /*02dd*/ 0x0003026fU, /*02de*/ 0xffffffffU, /*02df*/ 0x0801026fU, /*02e0*/ 0x1002026fU, /*02e1*/ 0x1801026fU, /*02e2*/ 0x00040270U, /*02e3*/ 0x08020270U, /*02e4*/ 0x10010270U, /*02e5*/ 0x18010270U, /*02e6*/ 0x00010271U, /*02e7*/ 0x08010271U, /*02e8*/ 0x10040271U, /*02e9*/ 0x18080271U, /*02ea*/ 0x000a0272U, /*02eb*/ 0x100a0272U, /*02ec*/ 0x000a0273U, /*02ed*/ 0x100a0273U, /*02ee*/ 0x000a0274U, /*02ef*/ 0x100a0274U, /*02f0*/ 0x00200275U, /*02f1*/ 0x00200276U, /*02f2*/ 0x00010277U, /*02f3*/ 0x08020277U, /*02f4*/ 0x10020277U, /*02f5*/ 0x18020277U, /*02f6*/ 0xffffffffU, /*02f7*/ 0x00020278U, /*02f8*/ 0x08100278U, /*02f9*/ 0x18050278U, /*02fa*/ 0x00060279U, /*02fb*/ 0x08050279U, /*02fc*/ 0x10050279U, /*02fd*/ 0x000e027aU, /*02fe*/ 0x1005027aU, /*02ff*/ 0x000e027bU, /*0300*/ 0x1005027bU, /*0301*/ 0x000e027cU, /*0302*/ 0x1005027cU, /*0303*/ 0x1801027cU, /*0304*/ 0x0005027dU, /*0305*/ 0x0805027dU, /*0306*/ 0x100a027dU, /*0307*/ 0x000a027eU, /*0308*/ 0x1005027eU, /*0309*/ 0x1805027eU, /*030a*/ 0x000a027fU, /*030b*/ 0x100a027fU, /*030c*/ 0x00050280U, /*030d*/ 0x08050280U, /*030e*/ 0x100a0280U, /*030f*/ 0x000a0281U, /*0310*/ 0x10070281U, /*0311*/ 0x18070281U, /*0312*/ 0x00070282U, /*0313*/ 0x08070282U, /*0314*/ 0x10070282U, /*0315*/ 0x18070282U, /*0316*/ 0xffffffffU, /*0317*/ 0xffffffffU, /*0318*/ 0x00040283U, /*0319*/ 0x08040283U, /*031a*/ 0x10040283U, /*031b*/ 0x18040283U, /*031c*/ 0x00040284U, /*031d*/ 0xffffffffU, /*031e*/ 0x08080284U, /*031f*/ 0x10080284U, /*0320*/ 0x18040284U, /*0321*/ 0x00050285U, /*0322*/ 0x08080285U, /*0323*/ 0x10050285U, /*0324*/ 0x18040285U, /*0325*/ 0x00050286U, /*0326*/ 0x08080286U, /*0327*/ 0x10050286U, /*0328*/ 0x18040286U, /*0329*/ 0x00050287U, /*032a*/ 0x08080287U, /*032b*/ 0x10050287U, /*032c*/ 0x18040287U, /*032d*/ 0x00050288U, /*032e*/ 0x08070288U, /*032f*/ 0x10080288U, /*0330*/ 0x00100289U, /*0331*/ 0x10080289U, /*0332*/ 0x0010028aU, /*0333*/ 0x1008028aU, /*0334*/ 0x0010028bU, /*0335*/ 0x1008028bU, /*0336*/ 0x1808028bU, /*0337*/ 0x0001028cU, /*0338*/ 0x0801028cU, /*0339*/ 0x1006028cU, /*033a*/ 0x1806028cU, /*033b*/ 0x0006028dU, /*033c*/ 0x0801028dU, /*033d*/ 0x1001028dU, /*033e*/ 0x1803028dU, /*033f*/ 0x000a028eU, /*0340*/ 0x100a028eU, /*0341*/ 0x000a028fU, /*0342*/ 0xffffffffU, /*0343*/ 0x100a028fU, /*0344*/ 0x00040290U, /*0345*/ 0x08010290U, /*0346*/ 0x10040290U, /*0347*/ 0x18070290U, /*0348*/ 0x00070291U, /*0349*/ 0x08070291U, /*034a*/ 0x10070291U, /*034b*/ 0x18070291U, /*034c*/ 0x00070292U, /*034d*/ 0xffffffffU, /*034e*/ 0xffffffffU, /*034f*/ 0x08050292U, /*0350*/ 0x10050292U, /*0351*/ 0x18040292U, /*0352*/ 0x00040293U, /*0353*/ 0x08040293U, /*0354*/ 0xffffffffU, /*0355*/ 0x10010293U, /*0356*/ 0x18010293U, /*0357*/ 0x00020294U, /*0358*/ 0x08080294U, /*0359*/ 0x00200295U, /*035a*/ 0x00200296U, /*035b*/ 0x00100297U, /*035c*/ 0x10020297U, /*035d*/ 0x18020297U, /*035e*/ 0x00020298U, /*035f*/ 0xffffffffU, /*0360*/ 0x08010298U, /*0361*/ 0x10010298U, /*0362*/ 0x18020298U, /*0363*/ 0x00100299U, /*0364*/ 0x10100299U, /*0365*/ 0x0010029aU, /*0366*/ 0x1008029aU, /*0367*/ 0x1808029aU, /*0368*/ 0x0008029bU, /*0369*/ 0x0808029bU, /*036a*/ 0x1010029bU, /*036b*/ 0x0010029cU, /*036c*/ 0x1010029cU, /*036d*/ 0x0008029dU, /*036e*/ 0x0808029dU, /*036f*/ 0x1008029dU, /*0370*/ 0x1808029dU, /*0371*/ 0x0010029eU, /*0372*/ 0x1010029eU, /*0373*/ 0x0010029fU, /*0374*/ 0x1008029fU, /*0375*/ 0x1808029fU, /*0376*/ 0x000802a0U, /*0377*/ 0x080802a0U, /*0378*/ 0x100802a0U, /*0379*/ 0x001002a1U, /*037a*/ 0x101002a1U, /*037b*/ 0x001002a2U, /*037c*/ 0x100802a2U, /*037d*/ 0x180802a2U, /*037e*/ 0x000802a3U, /*037f*/ 0x080802a3U, /*0380*/ 0x101002a3U, /*0381*/ 0x001002a4U, /*0382*/ 0x101002a4U, /*0383*/ 0x000802a5U, /*0384*/ 0x080802a5U, /*0385*/ 0x100802a5U, /*0386*/ 0x180802a5U, /*0387*/ 0x001002a6U, /*0388*/ 0x101002a6U, /*0389*/ 0x001002a7U, /*038a*/ 0x100802a7U, /*038b*/ 0x180802a7U, /*038c*/ 0x000802a8U, /*038d*/ 0x080802a8U, /*038e*/ 0x100802a8U, /*038f*/ 0x001002a9U, /*0390*/ 0x101002a9U, /*0391*/ 0x001002aaU, /*0392*/ 0x100802aaU, /*0393*/ 0x180802aaU, /*0394*/ 0x000802abU, /*0395*/ 0x080802abU, /*0396*/ 0x101002abU, /*0397*/ 0x001002acU, /*0398*/ 0x101002acU, /*0399*/ 0x000802adU, /*039a*/ 0x080802adU, /*039b*/ 0x100802adU, /*039c*/ 0x180802adU, /*039d*/ 0x001002aeU, /*039e*/ 0x101002aeU, /*039f*/ 0x001002afU, /*03a0*/ 0x100802afU, /*03a1*/ 0x180802afU, /*03a2*/ 0x000802b0U, /*03a3*/ 0x080802b0U, /*03a4*/ 0x100802b0U, /*03a5*/ 0x001002b1U, /*03a6*/ 0x101002b1U, /*03a7*/ 0x001002b2U, /*03a8*/ 0x100802b2U, /*03a9*/ 0x180802b2U, /*03aa*/ 0x000802b3U, /*03ab*/ 0x080802b3U, /*03ac*/ 0x101002b3U, /*03ad*/ 0x001002b4U, /*03ae*/ 0x101002b4U, /*03af*/ 0x000802b5U, /*03b0*/ 0x080802b5U, /*03b1*/ 0x100802b5U, /*03b2*/ 0x180802b5U, /*03b3*/ 0x001002b6U, /*03b4*/ 0x101002b6U, /*03b5*/ 0x001002b7U, /*03b6*/ 0x100802b7U, /*03b7*/ 0x180802b7U, /*03b8*/ 0x000802b8U, /*03b9*/ 0x080802b8U, /*03ba*/ 0x100802b8U, /*03bb*/ 0x180202b8U, /*03bc*/ 0x000302b9U, /*03bd*/ 0x080a02b9U, /*03be*/ 0x000a02baU, /*03bf*/ 0x100a02baU, /*03c0*/ 0x000502bbU, /*03c1*/ 0x080802bbU, /*03c2*/ 0x100802bbU, /*03c3*/ 0x180802bbU, /*03c4*/ 0x000602bcU, /*03c5*/ 0x080602bcU, /*03c6*/ 0x001102bdU, /*03c7*/ 0x180802bdU, /*03c8*/ 0x000402beU, /*03c9*/ 0x080602beU, /*03ca*/ 0x100802beU, /*03cb*/ 0x180802beU, /*03cc*/ 0x000802bfU, /*03cd*/ 0x080802bfU, /*03ce*/ 0x100802bfU, /*03cf*/ 0x180802bfU, /*03d0*/ 0x000802c0U, /*03d1*/ 0x080602c0U, /*03d2*/ 0x100602c0U, /*03d3*/ 0x001102c1U, /*03d4*/ 0x180802c1U, /*03d5*/ 0x000402c2U, /*03d6*/ 0x080602c2U, /*03d7*/ 0x100802c2U, /*03d8*/ 0x180802c2U, /*03d9*/ 0x000802c3U, /*03da*/ 0x080802c3U, /*03db*/ 0x100802c3U, /*03dc*/ 0x180802c3U, /*03dd*/ 0x000802c4U, /*03de*/ 0x080602c4U, /*03df*/ 0x100602c4U, /*03e0*/ 0x001102c5U, /*03e1*/ 0x180802c5U, /*03e2*/ 0x000402c6U, /*03e3*/ 0x080602c6U, /*03e4*/ 0x100802c6U, /*03e5*/ 0x180802c6U, /*03e6*/ 0x000802c7U, /*03e7*/ 0x080802c7U, /*03e8*/ 0x100402c7U, /*03e9*/ 0x180402c7U, /*03ea*/ 0x000402c8U, /*03eb*/ 0x080402c8U, /*03ec*/ 0x100402c8U, /*03ed*/ 0x180402c8U, /*03ee*/ 0x000402c9U, /*03ef*/ 0x080402c9U, /*03f0*/ 0x100402c9U, /*03f1*/ 0x180402c9U, /*03f2*/ 0x000402caU, /*03f3*/ 0x080402caU, /*03f4*/ 0x100402caU, /*03f5*/ 0x180402caU, /*03f6*/ 0x000402cbU, /*03f7*/ 0x080402cbU, /*03f8*/ 0x100402cbU, /*03f9*/ 0x180402cbU, /*03fa*/ 0x000402ccU, /*03fb*/ 0x080402ccU, /*03fc*/ 0x001702cdU, /*03fd*/ 0x001602ceU, /*03fe*/ 0x001702cfU, /*03ff*/ 0x002002d0U, /*0400*/ 0x002002d1U, /*0401*/ 0x002002d2U, /*0402*/ 0x002002d3U, /*0403*/ 0x002002d4U, /*0404*/ 0x002002d5U, /*0405*/ 0x002002d6U, /*0406*/ 0x002002d7U, /*0407*/ 0x002002d8U, /*0408*/ 0x000202d9U, /*0409*/ 0x080502d9U, /*040a*/ 0x100502d9U, /*040b*/ 0x180102d9U, /*040c*/ 0x000502daU, /*040d*/ 0x080502daU, /*040e*/ 0x100502daU, /*040f*/ 0x180502daU, /*0410*/ 0x000502dbU, /*0411*/ 0x080502dbU, /*0412*/ 0x100502dbU, /*0413*/ 0x180502dbU, /*0414*/ 0x000502dcU, /*0415*/ 0x080502dcU, /*0416*/ 0x100502dcU, /*0417*/ 0x180502dcU, /*0418*/ 0x000502ddU, /*0419*/ 0x080502ddU, /*041a*/ 0x100502ddU, /*041b*/ 0x180502ddU, /*041c*/ 0x000502deU, /*041d*/ 0x080502deU, /*041e*/ 0x100502deU, /*041f*/ 0x180502deU, /*0420*/ 0x000502dfU, /*0421*/ 0x080502dfU, /*0422*/ 0x100102dfU, /*0423*/ 0x180202dfU, /*0424*/ 0x000202e0U, /*0425*/ 0x080202e0U, /*0426*/ 0x100202e0U, /*0427*/ 0x180102e0U, /*0428*/ 0x000802e1U, /*0429*/ 0x081502e1U, /*042a*/ 0x002002e2U, /*042b*/ 0x001502e3U, /*042c*/ 0x002002e4U, /*042d*/ 0x001502e5U, /*042e*/ 0x002002e6U, /*042f*/ 0x000702e7U, /*0430*/ 0x080102e7U, /*0431*/ 0x100202e7U, /*0432*/ 0x180602e7U, /*0433*/ 0x000102e8U, /*0434*/ 0x080102e8U, /*0435*/ 0x002002e9U, /*0436*/ 0x000202eaU, /*0437*/ 0x002002ebU, /*0438*/ 0x002002ecU, /*0439*/ 0x000c02edU, /*043a*/ 0x100c02edU, /*043b*/ 0x002002eeU, /*043c*/ 0x000302efU, /*043d*/ 0x002002f0U, /*043e*/ 0x000302f1U, /*043f*/ 0x002002f2U, /*0440*/ 0x000302f3U, /*0441*/ 0x002002f4U, /*0442*/ 0x000302f5U, /*0443*/ 0x002002f6U, /*0444*/ 0x000302f7U, /*0445*/ 0x002002f8U, /*0446*/ 0x000302f9U, /*0447*/ 0x002002faU, /*0448*/ 0x000302fbU, /*0449*/ 0x002002fcU, /*044a*/ 0x000302fdU, /*044b*/ 0x002002feU, /*044c*/ 0x000302ffU, /*044d*/ 0x00200300U, /*044e*/ 0x00030301U, /*044f*/ 0x08030301U, /*0450*/ 0x10020301U, /*0451*/ 0x18020301U, /*0452*/ 0x00200302U, /*0453*/ 0x00200303U, /*0454*/ 0x00200304U, /*0455*/ 0x00200305U, /*0456*/ 0x00040306U, /*0457*/ 0x001e0307U, /*0458*/ 0x001e0308U, /*0459*/ 0x001e0309U, /*045a*/ 0x001e030aU, /*045b*/ 0x001e030bU, /*045c*/ 0x001e030cU, /*045d*/ 0x001e030dU, /*045e*/ 0x001e030eU, /*045f*/ 0x0004030fU, /*0460*/ 0x0801030fU, /*0461*/ 0x1010030fU, /*0462*/ 0x00100310U, /*0463*/ 0x10100310U, /*0464*/ 0x00040311U, /*0465*/ 0x08010311U, /*0466*/ 0x10080311U, /*0467*/ 0x18040311U, /*0468*/ 0x00010312U, /*0469*/ 0x08080312U, /*046a*/ 0x10040312U, /*046b*/ 0x18010312U, /*046c*/ 0x00080313U, /*046d*/ 0x08040313U, /*046e*/ 0x10010313U, /*046f*/ 0x18080313U, /*0470*/ 0x00040314U, /*0471*/ 0x08010314U, /*0472*/ 0x10080314U, /*0473*/ 0x18040314U, /*0474*/ 0x00010315U, /*0475*/ 0x08080315U, /*0476*/ 0x10040315U, /*0477*/ 0x18010315U, /*0478*/ 0x00080316U, /*0479*/ 0x08040316U, /*047a*/ 0x10010316U, /*047b*/ 0x18080316U, /*047c*/ 0x00080317U, /*047d*/ 0x00010318U, /*047e*/ 0x08050318U, /*047f*/ 0x10010318U, /*0480*/ 0x18020318U, /*0481*/ 0x00010319U, /*0482*/ 0x08010319U, /*0483*/ 0x10010319U, /*0484*/ 0x18010319U, /*0485*/ 0x0001031aU, /*0486*/ 0x0801031aU, /*0487*/ 0x1001031aU, /*0488*/ 0x1801031aU, /*0489*/ 0x0001031bU, /*048a*/ 0x0801031bU, /*048b*/ 0x1001031bU, /*048c*/ 0x1801031bU, /*048d*/ 0x0001031cU, /*048e*/ 0x0801031cU, /*048f*/ 0x1001031cU, /*0490*/ 0x1801031cU, /*0491*/ 0x0008031dU, /*0492*/ 0x0808031dU, /*0493*/ 0x1008031dU, /*0494*/ 0x1808031dU, } }; trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_b/init_dram_tbl_h3.h000066400000000000000000000234331355360272700300140ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #define DDR_PHY_SLICE_REGSET_OFS_H3 0x0400 #define DDR_PHY_ADR_V_REGSET_OFS_H3 0x0600 #define DDR_PHY_ADR_I_REGSET_OFS_H3 0x0680 #define DDR_PHY_ADR_G_REGSET_OFS_H3 0x0700 #define DDR_PI_REGSET_OFS_H3 0x0200 #define DDR_PHY_SLICE_REGSET_SIZE_H3 0x80 #define DDR_PHY_ADR_V_REGSET_SIZE_H3 0x80 #define DDR_PHY_ADR_I_REGSET_SIZE_H3 0x80 #define DDR_PHY_ADR_G_REGSET_SIZE_H3 0x80 #define DDR_PI_REGSET_SIZE_H3 0x100 #define DDR_PHY_SLICE_REGSET_NUM_H3 88 #define DDR_PHY_ADR_V_REGSET_NUM_H3 37 #define DDR_PHY_ADR_I_REGSET_NUM_H3 37 #define DDR_PHY_ADR_G_REGSET_NUM_H3 59 #define DDR_PI_REGSET_NUM_H3 181 static const uint32_t DDR_PHY_SLICE_REGSET_H3[DDR_PHY_SLICE_REGSET_NUM_H3] = { /*0400*/ 0x000004f0, /*0401*/ 0x00000000, /*0402*/ 0x00000000, /*0403*/ 0x00000100, /*0404*/ 0x01003c0c, /*0405*/ 0x02003c0c, /*0406*/ 0x00010300, /*0407*/ 0x04000100, /*0408*/ 0x00000300, /*0409*/ 0x000700c0, /*040a*/ 0x00b00201, /*040b*/ 0x00000020, /*040c*/ 0x00000000, /*040d*/ 0x00000000, /*040e*/ 0x00000000, /*040f*/ 0x00000000, /*0410*/ 0x00000000, /*0411*/ 0x00000000, /*0412*/ 0x00000000, /*0413*/ 0x09000000, /*0414*/ 0x04080000, /*0415*/ 0x04080400, /*0416*/ 0x00000000, /*0417*/ 0x32103210, /*0418*/ 0x00800708, /*0419*/ 0x000f000c, /*041a*/ 0x00000100, /*041b*/ 0x55aa55aa, /*041c*/ 0x33cc33cc, /*041d*/ 0x0ff00ff0, /*041e*/ 0x0f0ff0f0, /*041f*/ 0x00008e38, /*0420*/ 0x76543210, /*0421*/ 0x00000001, /*0422*/ 0x00000000, /*0423*/ 0x00000000, /*0424*/ 0x00000000, /*0425*/ 0x00000000, /*0426*/ 0x00000000, /*0427*/ 0x00000000, /*0428*/ 0x00000000, /*0429*/ 0x00000000, /*042a*/ 0x00000000, /*042b*/ 0x00000000, /*042c*/ 0x00000000, /*042d*/ 0x00000000, /*042e*/ 0x00000000, /*042f*/ 0x00000000, /*0430*/ 0x00000000, /*0431*/ 0x00000000, /*0432*/ 0x00000000, /*0433*/ 0x00200000, /*0434*/ 0x08200820, /*0435*/ 0x08200820, /*0436*/ 0x08200820, /*0437*/ 0x08200820, /*0438*/ 0x08200820, /*0439*/ 0x00000820, /*043a*/ 0x03000300, /*043b*/ 0x03000300, /*043c*/ 0x03000300, /*043d*/ 0x03000300, /*043e*/ 0x00000300, /*043f*/ 0x00000000, /*0440*/ 0x00000000, /*0441*/ 0x00000000, /*0442*/ 0x00000000, /*0443*/ 0x00a000a0, /*0444*/ 0x00a000a0, /*0445*/ 0x00a000a0, /*0446*/ 0x00a000a0, /*0447*/ 0x00a000a0, /*0448*/ 0x00a000a0, /*0449*/ 0x00a000a0, /*044a*/ 0x00a000a0, /*044b*/ 0x00a000a0, /*044c*/ 0x01040109, /*044d*/ 0x00000200, /*044e*/ 0x01000000, /*044f*/ 0x00000200, /*0450*/ 0x4041a151, /*0451*/ 0xc00141a0, /*0452*/ 0x0e0100c0, /*0453*/ 0x0010000c, /*0454*/ 0x0c064208, /*0455*/ 0x000f0c18, /*0456*/ 0x00e00140, /*0457*/ 0x00000c20 }; static const uint32_t DDR_PHY_ADR_V_REGSET_H3[DDR_PHY_ADR_V_REGSET_NUM_H3] = { /*0600*/ 0x00000000, /*0601*/ 0x00000000, /*0602*/ 0x00000000, /*0603*/ 0x00000000, /*0604*/ 0x00000000, /*0605*/ 0x00000000, /*0606*/ 0x00000002, /*0607*/ 0x00000000, /*0608*/ 0x00000000, /*0609*/ 0x00000000, /*060a*/ 0x00400320, /*060b*/ 0x00000040, /*060c*/ 0x00dcba98, /*060d*/ 0x00000000, /*060e*/ 0x00dcba98, /*060f*/ 0x01000000, /*0610*/ 0x00020003, /*0611*/ 0x00000000, /*0612*/ 0x00000000, /*0613*/ 0x00000000, /*0614*/ 0x00002a01, /*0615*/ 0x00000015, /*0616*/ 0x00000015, /*0617*/ 0x0000002a, /*0618*/ 0x00000033, /*0619*/ 0x0000000c, /*061a*/ 0x0000000c, /*061b*/ 0x00000033, /*061c*/ 0x00418820, /*061d*/ 0x003f0000, /*061e*/ 0x0000003f, /*061f*/ 0x0002006e, /*0620*/ 0x02000200, /*0621*/ 0x02000200, /*0622*/ 0x00000200, /*0623*/ 0x42080010, /*0624*/ 0x00000003 }; static const uint32_t DDR_PHY_ADR_I_REGSET_H3[DDR_PHY_ADR_I_REGSET_NUM_H3] = { /*0680*/ 0x04040404, /*0681*/ 0x00000404, /*0682*/ 0x00000000, /*0683*/ 0x00000000, /*0684*/ 0x00000000, /*0685*/ 0x00000000, /*0686*/ 0x00000002, /*0687*/ 0x00000000, /*0688*/ 0x00000000, /*0689*/ 0x00000000, /*068a*/ 0x00400320, /*068b*/ 0x00000040, /*068c*/ 0x00000000, /*068d*/ 0x00000000, /*068e*/ 0x00000000, /*068f*/ 0x01000000, /*0690*/ 0x00020003, /*0691*/ 0x00000000, /*0692*/ 0x00000000, /*0693*/ 0x00000000, /*0694*/ 0x00002a01, /*0695*/ 0x00000015, /*0696*/ 0x00000015, /*0697*/ 0x0000002a, /*0698*/ 0x00000033, /*0699*/ 0x0000000c, /*069a*/ 0x0000000c, /*069b*/ 0x00000033, /*069c*/ 0x00000000, /*069d*/ 0x00000000, /*069e*/ 0x00000000, /*069f*/ 0x0002006e, /*06a0*/ 0x02000200, /*06a1*/ 0x02000200, /*06a2*/ 0x00000200, /*06a3*/ 0x42080010, /*06a4*/ 0x00000003 }; static const uint32_t DDR_PHY_ADR_G_REGSET_H3[DDR_PHY_ADR_G_REGSET_NUM_H3] = { /*0700*/ 0x00000001, /*0701*/ 0x00000000, /*0702*/ 0x00000005, /*0703*/ 0x04000f00, /*0704*/ 0x00020080, /*0705*/ 0x00020055, /*0706*/ 0x00000000, /*0707*/ 0x00000000, /*0708*/ 0x00000000, /*0709*/ 0x00000050, /*070a*/ 0x00000000, /*070b*/ 0x01010100, /*070c*/ 0x00000200, /*070d*/ 0x00001102, /*070e*/ 0x00000000, /*070f*/ 0x000f1f00, /*0710*/ 0x0f1f0f1f, /*0711*/ 0x0f1f0f1f, /*0712*/ 0x00020003, /*0713*/ 0x02000200, /*0714*/ 0x00000200, /*0715*/ 0x00001102, /*0716*/ 0x00000064, /*0717*/ 0x00000000, /*0718*/ 0x00000000, /*0719*/ 0x00000502, /*071a*/ 0x027f6e00, /*071b*/ 0x007f007f, /*071c*/ 0x00007f3c, /*071d*/ 0x00047f6e, /*071e*/ 0x0003154f, /*071f*/ 0x0001154f, /*0720*/ 0x0001154f, /*0721*/ 0x0001154f, /*0722*/ 0x0001154f, /*0723*/ 0x00003fee, /*0724*/ 0x0001154f, /*0725*/ 0x00003fee, /*0726*/ 0x0001154f, /*0727*/ 0x00007f3c, /*0728*/ 0x0001154f, /*0729*/ 0x00000000, /*072a*/ 0x00000000, /*072b*/ 0x00000000, /*072c*/ 0x65000000, /*072d*/ 0x00000000, /*072e*/ 0x00000000, /*072f*/ 0x00000201, /*0730*/ 0x00000000, /*0731*/ 0x00000000, /*0732*/ 0x00000000, /*0733*/ 0x00000000, /*0734*/ 0x00000000, /*0735*/ 0x00000000, /*0736*/ 0x00000000, /*0737*/ 0x00000000, /*0738*/ 0x00000000, /*0739*/ 0x00000000, /*073a*/ 0x00000000 }; static const uint32_t DDR_PI_REGSET_H3[DDR_PI_REGSET_NUM_H3] = { /*0200*/ 0x00000b00, /*0201*/ 0x00000100, /*0202*/ 0x00000000, /*0203*/ 0x0000ffff, /*0204*/ 0x00000000, /*0205*/ 0x0000ffff, /*0206*/ 0x00000000, /*0207*/ 0x304cffff, /*0208*/ 0x00000200, /*0209*/ 0x00000200, /*020a*/ 0x00000200, /*020b*/ 0x00000200, /*020c*/ 0x0000304c, /*020d*/ 0x00000200, /*020e*/ 0x00000200, /*020f*/ 0x00000200, /*0210*/ 0x00000200, /*0211*/ 0x0000304c, /*0212*/ 0x00000200, /*0213*/ 0x00000200, /*0214*/ 0x00000200, /*0215*/ 0x00000200, /*0216*/ 0x00010000, /*0217*/ 0x00000003, /*0218*/ 0x01000001, /*0219*/ 0x00000000, /*021a*/ 0x00000000, /*021b*/ 0x00000000, /*021c*/ 0x00000000, /*021d*/ 0x00000000, /*021e*/ 0x00000000, /*021f*/ 0x00000000, /*0220*/ 0x00000000, /*0221*/ 0x00000000, /*0222*/ 0x00000000, /*0223*/ 0x00000000, /*0224*/ 0x00000000, /*0225*/ 0x00000000, /*0226*/ 0x00000000, /*0227*/ 0x00000000, /*0228*/ 0x00000000, /*0229*/ 0x0f000101, /*022a*/ 0x08492d25, /*022b*/ 0x500e0c04, /*022c*/ 0x0002500e, /*022d*/ 0x00460003, /*022e*/ 0x182600cf, /*022f*/ 0x182600cf, /*0230*/ 0x00000005, /*0231*/ 0x00000000, /*0232*/ 0x00000000, /*0233*/ 0x00000000, /*0234*/ 0x00000000, /*0235*/ 0x00000000, /*0236*/ 0x00000000, /*0237*/ 0x00000000, /*0238*/ 0x01000000, /*0239*/ 0x00040404, /*023a*/ 0x01280a00, /*023b*/ 0x00000000, /*023c*/ 0x000f0000, /*023d*/ 0x00001803, /*023e*/ 0x00000000, /*023f*/ 0x00000000, /*0240*/ 0x00060002, /*0241*/ 0x00010001, /*0242*/ 0x01000101, /*0243*/ 0x04020201, /*0244*/ 0x00080804, /*0245*/ 0x00000000, /*0246*/ 0x08030000, /*0247*/ 0x15150408, /*0248*/ 0x00000000, /*0249*/ 0x00000000, /*024a*/ 0x00000000, /*024b*/ 0x001e0f0f, /*024c*/ 0x00000000, /*024d*/ 0x01000300, /*024e*/ 0x00000000, /*024f*/ 0x00000000, /*0250*/ 0x01000000, /*0251*/ 0x00010101, /*0252*/ 0x000e0e0e, /*0253*/ 0x000c0c0c, /*0254*/ 0x02060601, /*0255*/ 0x00000000, /*0256*/ 0x00000003, /*0257*/ 0x00181703, /*0258*/ 0x00280006, /*0259*/ 0x00280016, /*025a*/ 0x00000016, /*025b*/ 0x00000000, /*025c*/ 0x00000000, /*025d*/ 0x00000000, /*025e*/ 0x140a0000, /*025f*/ 0x0005010a, /*0260*/ 0x03018d03, /*0261*/ 0x000a018d, /*0262*/ 0x00060100, /*0263*/ 0x01000006, /*0264*/ 0x018e018e, /*0265*/ 0x018e0100, /*0266*/ 0x1111018e, /*0267*/ 0x10010204, /*0268*/ 0x09090650, /*0269*/ 0x20110202, /*026a*/ 0x00201000, /*026b*/ 0x00201000, /*026c*/ 0x04041000, /*026d*/ 0x18020100, /*026e*/ 0x00010118, /*026f*/ 0x004b004a, /*0270*/ 0x050f0000, /*0271*/ 0x0c01021e, /*0272*/ 0x34000000, /*0273*/ 0x00000000, /*0274*/ 0x00000000, /*0275*/ 0x00000000, /*0276*/ 0x312ed400, /*0277*/ 0xd4111132, /*0278*/ 0x1132312e, /*0279*/ 0x312ed411, /*027a*/ 0x00111132, /*027b*/ 0x32312ed4, /*027c*/ 0x2ed41111, /*027d*/ 0x11113231, /*027e*/ 0x32312ed4, /*027f*/ 0xd4001111, /*0280*/ 0x1132312e, /*0281*/ 0x312ed411, /*0282*/ 0xd4111132, /*0283*/ 0x1132312e, /*0284*/ 0x2ed40011, /*0285*/ 0x11113231, /*0286*/ 0x32312ed4, /*0287*/ 0x2ed41111, /*0288*/ 0x11113231, /*0289*/ 0x00020000, /*028a*/ 0x018d018d, /*028b*/ 0x0c08018d, /*028c*/ 0x1f121d22, /*028d*/ 0x4301b344, /*028e*/ 0x10172006, /*028f*/ 0x121d220c, /*0290*/ 0x01b3441f, /*0291*/ 0x17200643, /*0292*/ 0x1d220c10, /*0293*/ 0x00001f12, /*0294*/ 0x4301b344, /*0295*/ 0x10172006, /*0296*/ 0x00020002, /*0297*/ 0x00020002, /*0298*/ 0x00020002, /*0299*/ 0x00020002, /*029a*/ 0x00020002, /*029b*/ 0x00000000, /*029c*/ 0x00000000, /*029d*/ 0x00000000, /*029e*/ 0x00000000, /*029f*/ 0x00000000, /*02a0*/ 0x00000000, /*02a1*/ 0x00000000, /*02a2*/ 0x00000000, /*02a3*/ 0x00000000, /*02a4*/ 0x00000000, /*02a5*/ 0x00000000, /*02a6*/ 0x00000000, /*02a7*/ 0x01000400, /*02a8*/ 0x00304c00, /*02a9*/ 0x0001e2f8, /*02aa*/ 0x0000304c, /*02ab*/ 0x0001e2f8, /*02ac*/ 0x0000304c, /*02ad*/ 0x0001e2f8, /*02ae*/ 0x08000000, /*02af*/ 0x00000100, /*02b0*/ 0x00000000, /*02b1*/ 0x00000000, /*02b2*/ 0x00000000, /*02b3*/ 0x00000000, /*02b4*/ 0x00000002 }; trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_b/init_dram_tbl_h3ver2.h000066400000000000000000000276021355360272700306150ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #define DDR_PHY_SLICE_REGSET_OFS_H3VER2 0x0400 #define DDR_PHY_ADR_V_REGSET_OFS_H3VER2 0x0600 #define DDR_PHY_ADR_I_REGSET_OFS_H3VER2 0x0640 #define DDR_PHY_ADR_G_REGSET_OFS_H3VER2 0x0680 #define DDR_PI_REGSET_OFS_H3VER2 0x0200 #define DDR_PHY_SLICE_REGSET_SIZE_H3VER2 0x80 #define DDR_PHY_ADR_V_REGSET_SIZE_H3VER2 0x40 #define DDR_PHY_ADR_I_REGSET_SIZE_H3VER2 0x40 #define DDR_PHY_ADR_G_REGSET_SIZE_H3VER2 0x80 #define DDR_PI_REGSET_SIZE_H3VER2 0x100 #define DDR_PHY_SLICE_REGSET_NUM_H3VER2 97 #define DDR_PHY_ADR_V_REGSET_NUM_H3VER2 37 #define DDR_PHY_ADR_I_REGSET_NUM_H3VER2 37 #define DDR_PHY_ADR_G_REGSET_NUM_H3VER2 79 #define DDR_PI_REGSET_NUM_H3VER2 245 static const uint32_t DDR_PHY_SLICE_REGSET_H3VER2 [DDR_PHY_SLICE_REGSET_NUM_H3VER2] = { /*0400*/ 0x76543210, /*0401*/ 0x0004f008, /*0402*/ 0x00020133, /*0403*/ 0x00000000, /*0404*/ 0x00000000, /*0405*/ 0x00010000, /*0406*/ 0x016e6e0e, /*0407*/ 0x026e6e0e, /*0408*/ 0x00010300, /*0409*/ 0x04000100, /*040a*/ 0x01000000, /*040b*/ 0x00000000, /*040c*/ 0x00000000, /*040d*/ 0x00000100, /*040e*/ 0x001700c0, /*040f*/ 0x020100b0, /*0410*/ 0x00030020, /*0411*/ 0x00000000, /*0412*/ 0x00000000, /*0413*/ 0x00000000, /*0414*/ 0x00000000, /*0415*/ 0x00000000, /*0416*/ 0x00000000, /*0417*/ 0x00000000, /*0418*/ 0x09000000, /*0419*/ 0x04080000, /*041a*/ 0x04080400, /*041b*/ 0x08000000, /*041c*/ 0x0c008007, /*041d*/ 0x00000f00, /*041e*/ 0x00000100, /*041f*/ 0x55aa55aa, /*0420*/ 0x33cc33cc, /*0421*/ 0x0ff00ff0, /*0422*/ 0x0f0ff0f0, /*0423*/ 0x00018e38, /*0424*/ 0x00000000, /*0425*/ 0x00000000, /*0426*/ 0x00000000, /*0427*/ 0x00000000, /*0428*/ 0x00000000, /*0429*/ 0x00000000, /*042a*/ 0x00000000, /*042b*/ 0x00000000, /*042c*/ 0x00000000, /*042d*/ 0x00000000, /*042e*/ 0x00000000, /*042f*/ 0x00000000, /*0430*/ 0x00000000, /*0431*/ 0x00000000, /*0432*/ 0x00000000, /*0433*/ 0x00000000, /*0434*/ 0x00000000, /*0435*/ 0x00000000, /*0436*/ 0x00000000, /*0437*/ 0x00000000, /*0438*/ 0x00000104, /*0439*/ 0x00082020, /*043a*/ 0x08200820, /*043b*/ 0x08200820, /*043c*/ 0x08200820, /*043d*/ 0x08200820, /*043e*/ 0x08200820, /*043f*/ 0x00000000, /*0440*/ 0x00000000, /*0441*/ 0x03000300, /*0442*/ 0x03000300, /*0443*/ 0x03000300, /*0444*/ 0x03000300, /*0445*/ 0x00000300, /*0446*/ 0x00000000, /*0447*/ 0x00000000, /*0448*/ 0x00000000, /*0449*/ 0x00000000, /*044a*/ 0x00000000, /*044b*/ 0x00a000a0, /*044c*/ 0x00a000a0, /*044d*/ 0x00a000a0, /*044e*/ 0x00a000a0, /*044f*/ 0x00a000a0, /*0450*/ 0x00a000a0, /*0451*/ 0x00a000a0, /*0452*/ 0x00a000a0, /*0453*/ 0x00a000a0, /*0454*/ 0x01040109, /*0455*/ 0x00000200, /*0456*/ 0x01000000, /*0457*/ 0x00000200, /*0458*/ 0x00000004, /*0459*/ 0x4041a151, /*045a*/ 0xc00141a0, /*045b*/ 0x0e0000c0, /*045c*/ 0x0010000c, /*045d*/ 0x063e4208, /*045e*/ 0x0f0c180c, /*045f*/ 0x00e00140, /*0460*/ 0x00000c20 }; static const uint32_t DDR_PHY_ADR_V_REGSET_H3VER2[DDR_PHY_ADR_V_REGSET_NUM_H3VER2] = { /*0600*/ 0x00000000, /*0601*/ 0x00000000, /*0602*/ 0x00000000, /*0603*/ 0x00000000, /*0604*/ 0x00000000, /*0605*/ 0x00000000, /*0606*/ 0x00000000, /*0607*/ 0x00010000, /*0608*/ 0x00000200, /*0609*/ 0x00000000, /*060a*/ 0x00000000, /*060b*/ 0x00000000, /*060c*/ 0x00400320, /*060d*/ 0x00000040, /*060e*/ 0x00dcba98, /*060f*/ 0x03000000, /*0610*/ 0x00000200, /*0611*/ 0x00000000, /*0612*/ 0x00000000, /*0613*/ 0x00000000, /*0614*/ 0x0000002a, /*0615*/ 0x00000015, /*0616*/ 0x00000015, /*0617*/ 0x0000002a, /*0618*/ 0x00000033, /*0619*/ 0x0000000c, /*061a*/ 0x0000000c, /*061b*/ 0x00000033, /*061c*/ 0x00418820, /*061d*/ 0x003f0000, /*061e*/ 0x0000003f, /*061f*/ 0x0002c06e, /*0620*/ 0x02c002c0, /*0621*/ 0x02c002c0, /*0622*/ 0x000002c0, /*0623*/ 0x42080010, /*0624*/ 0x0000033e }; static const uint32_t DDR_PHY_ADR_I_REGSET_H3VER2[DDR_PHY_ADR_I_REGSET_NUM_H3VER2] = { /*0640*/ 0x00000000, /*0641*/ 0x00000000, /*0642*/ 0x00000000, /*0643*/ 0x00000000, /*0644*/ 0x00000000, /*0645*/ 0x00000000, /*0646*/ 0x00000000, /*0647*/ 0x00000000, /*0648*/ 0x00000000, /*0649*/ 0x00000000, /*064a*/ 0x00000000, /*064b*/ 0x00000000, /*064c*/ 0x00000000, /*064d*/ 0x00000000, /*064e*/ 0x00000000, /*064f*/ 0x00000000, /*0650*/ 0x00000000, /*0651*/ 0x00000000, /*0652*/ 0x00000000, /*0653*/ 0x00000000, /*0654*/ 0x00000000, /*0655*/ 0x00000000, /*0656*/ 0x00000000, /*0657*/ 0x00000000, /*0658*/ 0x00000000, /*0659*/ 0x00000000, /*065a*/ 0x00000000, /*065b*/ 0x00000000, /*065c*/ 0x00000000, /*065d*/ 0x00000000, /*065e*/ 0x00000000, /*065f*/ 0x00000000, /*0660*/ 0x00000000, /*0661*/ 0x00000000, /*0662*/ 0x00000000, /*0663*/ 0x00000000, /*0664*/ 0x00000000 }; static const uint32_t DDR_PHY_ADR_G_REGSET_H3VER2[DDR_PHY_ADR_G_REGSET_NUM_H3VER2] = { /*0680*/ 0x00000000, /*0681*/ 0x00000100, /*0682*/ 0x00000000, /*0683*/ 0x00050000, /*0684*/ 0x0f000000, /*0685*/ 0x00800400, /*0686*/ 0x00020032, /*0687*/ 0x00020055, /*0688*/ 0x00000000, /*0689*/ 0x00000000, /*068a*/ 0x00000000, /*068b*/ 0x00000050, /*068c*/ 0x00000000, /*068d*/ 0x01010100, /*068e*/ 0x01000200, /*068f*/ 0x00000000, /*0690*/ 0x00010100, /*0691*/ 0x00000000, /*0692*/ 0x00000000, /*0693*/ 0x00000000, /*0694*/ 0x00000000, /*0695*/ 0x00005064, /*0696*/ 0x01421142, /*0697*/ 0x00000142, /*0698*/ 0x00000000, /*0699*/ 0x000f1100, /*069a*/ 0x0f110f11, /*069b*/ 0x09000f11, /*069c*/ 0x00000003, /*069d*/ 0x0002c000, /*069e*/ 0x02c002c0, /*069f*/ 0x000002c0, /*06a0*/ 0x03421342, /*06a1*/ 0x00000342, /*06a2*/ 0x00000000, /*06a3*/ 0x00000000, /*06a4*/ 0x05020000, /*06a5*/ 0x14000000, /*06a6*/ 0x027f6e00, /*06a7*/ 0x047f027f, /*06a8*/ 0x00027f6e, /*06a9*/ 0x00047f6e, /*06aa*/ 0x0003554f, /*06ab*/ 0x0001554f, /*06ac*/ 0x0001554f, /*06ad*/ 0x0001554f, /*06ae*/ 0x0001554f, /*06af*/ 0x00003fee, /*06b0*/ 0x0001554f, /*06b1*/ 0x00003fee, /*06b2*/ 0x0001554f, /*06b3*/ 0x00027f6e, /*06b4*/ 0x0001554f, /*06b5*/ 0x00004011, /*06b6*/ 0x00004410, /*06b7*/ 0x00000000, /*06b8*/ 0x00000000, /*06b9*/ 0x00000000, /*06ba*/ 0x00000065, /*06bb*/ 0x00000000, /*06bc*/ 0x00020201, /*06bd*/ 0x00000000, /*06be*/ 0x03000000, /*06bf*/ 0x00000008, /*06c0*/ 0x00000000, /*06c1*/ 0x00000000, /*06c2*/ 0x00000000, /*06c3*/ 0x00000000, /*06c4*/ 0x00000001, /*06c5*/ 0x00000000, /*06c6*/ 0x00000000, /*06c7*/ 0x00000000, /*06c8*/ 0x000000e4, /*06c9*/ 0x00010198, /*06ca*/ 0x00000000, /*06cb*/ 0x00000000, /*06cc*/ 0x07010000, /*06cd*/ 0x00000104, /*06ce*/ 0x00000000 }; static const uint32_t DDR_PI_REGSET_H3VER2[DDR_PI_REGSET_NUM_H3VER2] = { /*0200*/ 0x00000b00, /*0201*/ 0x00000100, /*0202*/ 0x00640000, /*0203*/ 0x00000000, /*0204*/ 0x0000ffff, /*0205*/ 0x00000000, /*0206*/ 0x0000ffff, /*0207*/ 0x00000000, /*0208*/ 0x0000ffff, /*0209*/ 0x0000304c, /*020a*/ 0x00000200, /*020b*/ 0x00000200, /*020c*/ 0x00000200, /*020d*/ 0x00000200, /*020e*/ 0x0000304c, /*020f*/ 0x00000200, /*0210*/ 0x00000200, /*0211*/ 0x00000200, /*0212*/ 0x00000200, /*0213*/ 0x0000304c, /*0214*/ 0x00000200, /*0215*/ 0x00000200, /*0216*/ 0x00000200, /*0217*/ 0x00000200, /*0218*/ 0x00010000, /*0219*/ 0x00000003, /*021a*/ 0x01000001, /*021b*/ 0x00000000, /*021c*/ 0x00000000, /*021d*/ 0x00000000, /*021e*/ 0x00000000, /*021f*/ 0x00000000, /*0220*/ 0x00000000, /*0221*/ 0x00000000, /*0222*/ 0x00000000, /*0223*/ 0x00000000, /*0224*/ 0x00000000, /*0225*/ 0x00000000, /*0226*/ 0x00000000, /*0227*/ 0x00000000, /*0228*/ 0x00000000, /*0229*/ 0x00000000, /*022a*/ 0x00000000, /*022b*/ 0x0f000101, /*022c*/ 0x08492d25, /*022d*/ 0x500e0c04, /*022e*/ 0x0002500e, /*022f*/ 0x00000301, /*0230*/ 0x00000046, /*0231*/ 0x000000cf, /*0232*/ 0x00001826, /*0233*/ 0x000000cf, /*0234*/ 0x00001826, /*0235*/ 0x00000005, /*0236*/ 0x00000000, /*0237*/ 0x00000000, /*0238*/ 0x00000000, /*0239*/ 0x00000000, /*023a*/ 0x00000000, /*023b*/ 0x00000000, /*023c*/ 0x00000000, /*023d*/ 0x00000000, /*023e*/ 0x04010000, /*023f*/ 0x00000404, /*0240*/ 0x0101280a, /*0241*/ 0x00000000, /*0242*/ 0x00000000, /*0243*/ 0x0003000f, /*0244*/ 0x00000018, /*0245*/ 0x00000000, /*0246*/ 0x00000000, /*0247*/ 0x00060002, /*0248*/ 0x00010001, /*0249*/ 0x01000101, /*024a*/ 0x04020201, /*024b*/ 0x00080804, /*024c*/ 0x00000000, /*024d*/ 0x08030000, /*024e*/ 0x15150408, /*024f*/ 0x00000000, /*0250*/ 0x00000000, /*0251*/ 0x00000000, /*0252*/ 0x0f0f0000, /*0253*/ 0x0000001e, /*0254*/ 0x00000000, /*0255*/ 0x01000300, /*0256*/ 0x00000100, /*0257*/ 0x00000000, /*0258*/ 0x00000000, /*0259*/ 0x01000000, /*025a*/ 0x00000101, /*025b*/ 0x55555a5a, /*025c*/ 0x55555a5a, /*025d*/ 0x55555a5a, /*025e*/ 0x55555a5a, /*025f*/ 0x0e0e0001, /*0260*/ 0x0c0c000e, /*0261*/ 0x0601000c, /*0262*/ 0x17170106, /*0263*/ 0x00020202, /*0264*/ 0x03000000, /*0265*/ 0x00000000, /*0266*/ 0x00181703, /*0267*/ 0x00280006, /*0268*/ 0x00280016, /*0269*/ 0x00000016, /*026a*/ 0x00000000, /*026b*/ 0x00000000, /*026c*/ 0x00000000, /*026d*/ 0x0a000000, /*026e*/ 0x00010a14, /*026f*/ 0x00030005, /*0270*/ 0x0003018d, /*0271*/ 0x000a018d, /*0272*/ 0x00060100, /*0273*/ 0x01000006, /*0274*/ 0x018e018e, /*0275*/ 0x018e0100, /*0276*/ 0x1111018e, /*0277*/ 0x10010204, /*0278*/ 0x09090650, /*0279*/ 0xff110202, /*027a*/ 0x00ff1000, /*027b*/ 0x00ff1000, /*027c*/ 0x04041000, /*027d*/ 0x18020100, /*027e*/ 0x01010018, /*027f*/ 0x004a004a, /*0280*/ 0x004b004a, /*0281*/ 0x050f0000, /*0282*/ 0x0c01021e, /*0283*/ 0x34000000, /*0284*/ 0x00000000, /*0285*/ 0x00000000, /*0286*/ 0x00000000, /*0287*/ 0x00000000, /*0288*/ 0x36312ed4, /*0289*/ 0x2ed41111, /*028a*/ 0x11113631, /*028b*/ 0x36312ed4, /*028c*/ 0xd4001111, /*028d*/ 0x1136312e, /*028e*/ 0x312ed411, /*028f*/ 0xd4111136, /*0290*/ 0x1136312e, /*0291*/ 0x2ed40011, /*0292*/ 0x11113631, /*0293*/ 0x36312ed4, /*0294*/ 0x2ed41111, /*0295*/ 0x11113631, /*0296*/ 0x312ed400, /*0297*/ 0xd4111136, /*0298*/ 0x1136312e, /*0299*/ 0x312ed411, /*029a*/ 0x00111136, /*029b*/ 0x018d0200, /*029c*/ 0x018d018d, /*029d*/ 0x1d220c08, /*029e*/ 0x00001f12, /*029f*/ 0x4301b344, /*02a0*/ 0x10172006, /*02a1*/ 0x121d220c, /*02a2*/ 0x01b3441f, /*02a3*/ 0x17200643, /*02a4*/ 0x1d220c10, /*02a5*/ 0x00001f12, /*02a6*/ 0x4301b344, /*02a7*/ 0x10172006, /*02a8*/ 0x00020002, /*02a9*/ 0x00020002, /*02aa*/ 0x00020002, /*02ab*/ 0x00020002, /*02ac*/ 0x00020002, /*02ad*/ 0x00000000, /*02ae*/ 0x00000000, /*02af*/ 0x00000000, /*02b0*/ 0x00000000, /*02b1*/ 0x00000000, /*02b2*/ 0x00000000, /*02b3*/ 0x00000000, /*02b4*/ 0x00000000, /*02b5*/ 0x00000000, /*02b6*/ 0x00000000, /*02b7*/ 0x00000000, /*02b8*/ 0x00000000, /*02b9*/ 0x00000400, /*02ba*/ 0x05040302, /*02bb*/ 0x01000f0e, /*02bc*/ 0x07060504, /*02bd*/ 0x03020100, /*02be*/ 0x02010000, /*02bf*/ 0x00000103, /*02c0*/ 0x0000304c, /*02c1*/ 0x0001e2f8, /*02c2*/ 0x0000304c, /*02c3*/ 0x0001e2f8, /*02c4*/ 0x0000304c, /*02c5*/ 0x0001e2f8, /*02c6*/ 0x08000000, /*02c7*/ 0x00000100, /*02c8*/ 0x00000000, /*02c9*/ 0x00000000, /*02ca*/ 0x00000000, /*02cb*/ 0x00000000, /*02cc*/ 0x00010000, /*02cd*/ 0x00000000, /*02ce*/ 0x00000000, /*02cf*/ 0x00000000, /*02d0*/ 0x00000000, /*02d1*/ 0x00000000, /*02d2*/ 0x00000000, /*02d3*/ 0x00000000, /*02d4*/ 0x00000000, /*02d5*/ 0x00000000, /*02d6*/ 0x00000000, /*02d7*/ 0x00000000, /*02d8*/ 0x00000000, /*02d9*/ 0x00000000, /*02da*/ 0x00000000, /*02db*/ 0x00000000, /*02dc*/ 0x00000000, /*02dd*/ 0x00000000, /*02de*/ 0x00000000, /*02df*/ 0x00000000, /*02e0*/ 0x00000000, /*02e1*/ 0x00000000, /*02e2*/ 0x00000000, /*02e3*/ 0x00000000, /*02e4*/ 0x00000000, /*02e5*/ 0x00000000, /*02e6*/ 0x00000000, /*02e7*/ 0x00000000, /*02e8*/ 0x00000000, /*02e9*/ 0x00000000, /*02ea*/ 0x00000000, /*02eb*/ 0x00000000, /*02ec*/ 0x00000000, /*02ed*/ 0x00000000, /*02ee*/ 0x00000002, /*02ef*/ 0x00000000, /*02f0*/ 0x00000000, /*02f1*/ 0x00000000, /*02f2*/ 0x00000000, /*02f3*/ 0x00000000, /*02f4*/ 0x00000000 }; trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_b/init_dram_tbl_m3.h000066400000000000000000000245551355360272700300270ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #define DDR_PHY_SLICE_REGSET_OFS_M3 0x0800 #define DDR_PHY_ADR_V_REGSET_OFS_M3 0x0a00 #define DDR_PHY_ADR_I_REGSET_OFS_M3 0x0a80 #define DDR_PHY_ADR_G_REGSET_OFS_M3 0x0b80 #define DDR_PI_REGSET_OFS_M3 0x0200 #define DDR_PHY_SLICE_REGSET_SIZE_M3 0x80 #define DDR_PHY_ADR_V_REGSET_SIZE_M3 0x80 #define DDR_PHY_ADR_I_REGSET_SIZE_M3 0x80 #define DDR_PHY_ADR_G_REGSET_SIZE_M3 0x80 #define DDR_PI_REGSET_SIZE_M3 0x100 #define DDR_PHY_SLICE_REGSET_NUM_M3 89 #define DDR_PHY_ADR_V_REGSET_NUM_M3 37 #define DDR_PHY_ADR_I_REGSET_NUM_M3 37 #define DDR_PHY_ADR_G_REGSET_NUM_M3 64 #define DDR_PI_REGSET_NUM_M3 202 static const uint32_t DDR_PHY_SLICE_REGSET_M3[DDR_PHY_SLICE_REGSET_NUM_M3] = { /*0800*/ 0x76543210, /*0801*/ 0x0004f008, /*0802*/ 0x00000000, /*0803*/ 0x00000000, /*0804*/ 0x00010000, /*0805*/ 0x036e6e0e, /*0806*/ 0x026e6e0e, /*0807*/ 0x00010300, /*0808*/ 0x04000100, /*0809*/ 0x00000300, /*080a*/ 0x001700c0, /*080b*/ 0x00b00201, /*080c*/ 0x00030020, /*080d*/ 0x00000000, /*080e*/ 0x00000000, /*080f*/ 0x00000000, /*0810*/ 0x00000000, /*0811*/ 0x00000000, /*0812*/ 0x00000000, /*0813*/ 0x00000000, /*0814*/ 0x09000000, /*0815*/ 0x04080000, /*0816*/ 0x04080400, /*0817*/ 0x00000000, /*0818*/ 0x32103210, /*0819*/ 0x00800708, /*081a*/ 0x000f000c, /*081b*/ 0x00000100, /*081c*/ 0x55aa55aa, /*081d*/ 0x33cc33cc, /*081e*/ 0x0ff00ff0, /*081f*/ 0x0f0ff0f0, /*0820*/ 0x00018e38, /*0821*/ 0x00000000, /*0822*/ 0x00000000, /*0823*/ 0x00000000, /*0824*/ 0x00000000, /*0825*/ 0x00000000, /*0826*/ 0x00000000, /*0827*/ 0x00000000, /*0828*/ 0x00000000, /*0829*/ 0x00000000, /*082a*/ 0x00000000, /*082b*/ 0x00000000, /*082c*/ 0x00000000, /*082d*/ 0x00000000, /*082e*/ 0x00000000, /*082f*/ 0x00000000, /*0830*/ 0x00000000, /*0831*/ 0x00000000, /*0832*/ 0x00000000, /*0833*/ 0x00200000, /*0834*/ 0x08200820, /*0835*/ 0x08200820, /*0836*/ 0x08200820, /*0837*/ 0x08200820, /*0838*/ 0x08200820, /*0839*/ 0x00000820, /*083a*/ 0x03000300, /*083b*/ 0x03000300, /*083c*/ 0x03000300, /*083d*/ 0x03000300, /*083e*/ 0x00000300, /*083f*/ 0x00000000, /*0840*/ 0x00000000, /*0841*/ 0x00000000, /*0842*/ 0x00000000, /*0843*/ 0x00a00000, /*0844*/ 0x00a000a0, /*0845*/ 0x00a000a0, /*0846*/ 0x00a000a0, /*0847*/ 0x00a000a0, /*0848*/ 0x00a000a0, /*0849*/ 0x00a000a0, /*084a*/ 0x00a000a0, /*084b*/ 0x00a000a0, /*084c*/ 0x010900a0, /*084d*/ 0x02000104, /*084e*/ 0x00000000, /*084f*/ 0x00010000, /*0850*/ 0x00000200, /*0851*/ 0x4041a151, /*0852*/ 0xc00141a0, /*0853*/ 0x0e0100c0, /*0854*/ 0x0010000c, /*0855*/ 0x0c064208, /*0856*/ 0x000f0c18, /*0857*/ 0x00e00140, /*0858*/ 0x00000c20 }; static const uint32_t DDR_PHY_ADR_V_REGSET_M3[DDR_PHY_ADR_V_REGSET_NUM_M3] = { /*0a00*/ 0x00000000, /*0a01*/ 0x00000000, /*0a02*/ 0x00000000, /*0a03*/ 0x00000000, /*0a04*/ 0x00000000, /*0a05*/ 0x00000000, /*0a06*/ 0x00000002, /*0a07*/ 0x00000000, /*0a08*/ 0x00000000, /*0a09*/ 0x00000000, /*0a0a*/ 0x00400320, /*0a0b*/ 0x00000040, /*0a0c*/ 0x00dcba98, /*0a0d*/ 0x00000000, /*0a0e*/ 0x00dcba98, /*0a0f*/ 0x01000000, /*0a10*/ 0x00020003, /*0a11*/ 0x00000000, /*0a12*/ 0x00000000, /*0a13*/ 0x00000000, /*0a14*/ 0x0000002a, /*0a15*/ 0x00000015, /*0a16*/ 0x00000015, /*0a17*/ 0x0000002a, /*0a18*/ 0x00000033, /*0a19*/ 0x0000000c, /*0a1a*/ 0x0000000c, /*0a1b*/ 0x00000033, /*0a1c*/ 0x0a418820, /*0a1d*/ 0x003f0000, /*0a1e*/ 0x0000003f, /*0a1f*/ 0x0002c06e, /*0a20*/ 0x02c002c0, /*0a21*/ 0x02c002c0, /*0a22*/ 0x000002c0, /*0a23*/ 0x42080010, /*0a24*/ 0x00000003 }; static const uint32_t DDR_PHY_ADR_I_REGSET_M3[DDR_PHY_ADR_I_REGSET_NUM_M3] = { /*0a80*/ 0x04040404, /*0a81*/ 0x00000404, /*0a82*/ 0x00000000, /*0a83*/ 0x00000000, /*0a84*/ 0x00000000, /*0a85*/ 0x00000000, /*0a86*/ 0x00000002, /*0a87*/ 0x00000000, /*0a88*/ 0x00000000, /*0a89*/ 0x00000000, /*0a8a*/ 0x00400320, /*0a8b*/ 0x00000040, /*0a8c*/ 0x00000000, /*0a8d*/ 0x00000000, /*0a8e*/ 0x00000000, /*0a8f*/ 0x01000000, /*0a90*/ 0x00020003, /*0a91*/ 0x00000000, /*0a92*/ 0x00000000, /*0a93*/ 0x00000000, /*0a94*/ 0x0000002a, /*0a95*/ 0x00000015, /*0a96*/ 0x00000015, /*0a97*/ 0x0000002a, /*0a98*/ 0x00000033, /*0a99*/ 0x0000000c, /*0a9a*/ 0x0000000c, /*0a9b*/ 0x00000033, /*0a9c*/ 0x00000000, /*0a9d*/ 0x00000000, /*0a9e*/ 0x00000000, /*0a9f*/ 0x0002c06e, /*0aa0*/ 0x02c002c0, /*0aa1*/ 0x02c002c0, /*0aa2*/ 0x000002c0, /*0aa3*/ 0x42080010, /*0aa4*/ 0x00000003 }; static const uint32_t DDR_PHY_ADR_G_REGSET_M3[DDR_PHY_ADR_G_REGSET_NUM_M3] = { /*0b80*/ 0x00000001, /*0b81*/ 0x00000000, /*0b82*/ 0x00000005, /*0b83*/ 0x04000f00, /*0b84*/ 0x00020080, /*0b85*/ 0x00020055, /*0b86*/ 0x00000000, /*0b87*/ 0x00000000, /*0b88*/ 0x00000000, /*0b89*/ 0x00000050, /*0b8a*/ 0x00000000, /*0b8b*/ 0x01010100, /*0b8c*/ 0x00000600, /*0b8d*/ 0x50640000, /*0b8e*/ 0x01421142, /*0b8f*/ 0x00000142, /*0b90*/ 0x00000000, /*0b91*/ 0x000f1600, /*0b92*/ 0x0f160f16, /*0b93*/ 0x0f160f16, /*0b94*/ 0x00000003, /*0b95*/ 0x0002c000, /*0b96*/ 0x02c002c0, /*0b97*/ 0x000002c0, /*0b98*/ 0x03421342, /*0b99*/ 0x00000342, /*0b9a*/ 0x00000000, /*0b9b*/ 0x00000000, /*0b9c*/ 0x05020000, /*0b9d*/ 0x00000000, /*0b9e*/ 0x00027f6e, /*0b9f*/ 0x047f027f, /*0ba0*/ 0x00027f6e, /*0ba1*/ 0x00047f6e, /*0ba2*/ 0x0003554f, /*0ba3*/ 0x0001554f, /*0ba4*/ 0x0001554f, /*0ba5*/ 0x0001554f, /*0ba6*/ 0x0001554f, /*0ba7*/ 0x00003fee, /*0ba8*/ 0x0001554f, /*0ba9*/ 0x00003fee, /*0baa*/ 0x0001554f, /*0bab*/ 0x00027f6e, /*0bac*/ 0x0001554f, /*0bad*/ 0x00000000, /*0bae*/ 0x00000000, /*0baf*/ 0x00000000, /*0bb0*/ 0x65000000, /*0bb1*/ 0x00000000, /*0bb2*/ 0x00000000, /*0bb3*/ 0x00000201, /*0bb4*/ 0x00000000, /*0bb5*/ 0x00000000, /*0bb6*/ 0x00000000, /*0bb7*/ 0x00000000, /*0bb8*/ 0x00000000, /*0bb9*/ 0x00000000, /*0bba*/ 0x00000000, /*0bbb*/ 0x00000000, /*0bbc*/ 0x06e40000, /*0bbd*/ 0x00000000, /*0bbe*/ 0x00000000, /*0bbf*/ 0x00010000 }; static const uint32_t DDR_PI_REGSET_M3[DDR_PI_REGSET_NUM_M3] = { /*0200*/ 0x00000b00, /*0201*/ 0x00000100, /*0202*/ 0x00000000, /*0203*/ 0x0000ffff, /*0204*/ 0x00000000, /*0205*/ 0x0000ffff, /*0206*/ 0x00000000, /*0207*/ 0x304cffff, /*0208*/ 0x00000200, /*0209*/ 0x00000200, /*020a*/ 0x00000200, /*020b*/ 0x00000200, /*020c*/ 0x0000304c, /*020d*/ 0x00000200, /*020e*/ 0x00000200, /*020f*/ 0x00000200, /*0210*/ 0x00000200, /*0211*/ 0x0000304c, /*0212*/ 0x00000200, /*0213*/ 0x00000200, /*0214*/ 0x00000200, /*0215*/ 0x00000200, /*0216*/ 0x00010000, /*0217*/ 0x00000003, /*0218*/ 0x01000001, /*0219*/ 0x00000000, /*021a*/ 0x00000000, /*021b*/ 0x00000000, /*021c*/ 0x00000000, /*021d*/ 0x00000000, /*021e*/ 0x00000000, /*021f*/ 0x00000000, /*0220*/ 0x00000000, /*0221*/ 0x00000000, /*0222*/ 0x00000000, /*0223*/ 0x00000000, /*0224*/ 0x00000000, /*0225*/ 0x00000000, /*0226*/ 0x00000000, /*0227*/ 0x00000000, /*0228*/ 0x00000000, /*0229*/ 0x0f000101, /*022a*/ 0x08492d25, /*022b*/ 0x0e0c0004, /*022c*/ 0x000e5000, /*022d*/ 0x00000250, /*022e*/ 0x00460003, /*022f*/ 0x182600cf, /*0230*/ 0x182600cf, /*0231*/ 0x00000005, /*0232*/ 0x00000000, /*0233*/ 0x00000000, /*0234*/ 0x00000000, /*0235*/ 0x00000000, /*0236*/ 0x00000000, /*0237*/ 0x00000000, /*0238*/ 0x00000000, /*0239*/ 0x01000000, /*023a*/ 0x00040404, /*023b*/ 0x01280a00, /*023c*/ 0x00000000, /*023d*/ 0x000f0000, /*023e*/ 0x00001803, /*023f*/ 0x00000000, /*0240*/ 0x00000000, /*0241*/ 0x00060002, /*0242*/ 0x00010001, /*0243*/ 0x01000101, /*0244*/ 0x04020201, /*0245*/ 0x00080804, /*0246*/ 0x00000000, /*0247*/ 0x08030000, /*0248*/ 0x15150408, /*0249*/ 0x00000000, /*024a*/ 0x00000000, /*024b*/ 0x00000000, /*024c*/ 0x000f0f00, /*024d*/ 0x0000001e, /*024e*/ 0x00000000, /*024f*/ 0x01000300, /*0250*/ 0x00000000, /*0251*/ 0x00000000, /*0252*/ 0x01000000, /*0253*/ 0x00010101, /*0254*/ 0x000e0e0e, /*0255*/ 0x000c0c0c, /*0256*/ 0x02060601, /*0257*/ 0x00000000, /*0258*/ 0x00000003, /*0259*/ 0x00181703, /*025a*/ 0x00280006, /*025b*/ 0x00280016, /*025c*/ 0x00000016, /*025d*/ 0x00000000, /*025e*/ 0x00000000, /*025f*/ 0x00000000, /*0260*/ 0x140a0000, /*0261*/ 0x0005010a, /*0262*/ 0x03018d03, /*0263*/ 0x000a018d, /*0264*/ 0x00060100, /*0265*/ 0x01000006, /*0266*/ 0x018e018e, /*0267*/ 0x018e0100, /*0268*/ 0x1111018e, /*0269*/ 0x10010204, /*026a*/ 0x09090650, /*026b*/ 0x20110202, /*026c*/ 0x00201000, /*026d*/ 0x00201000, /*026e*/ 0x04041000, /*026f*/ 0x18020100, /*0270*/ 0x00010118, /*0271*/ 0x004b004a, /*0272*/ 0x050f0000, /*0273*/ 0x0c01021e, /*0274*/ 0x34000000, /*0275*/ 0x00000000, /*0276*/ 0x00000000, /*0277*/ 0x00000000, /*0278*/ 0x0000d400, /*0279*/ 0x0031002e, /*027a*/ 0x00111136, /*027b*/ 0x002e00d4, /*027c*/ 0x11360031, /*027d*/ 0x0000d411, /*027e*/ 0x0031002e, /*027f*/ 0x00111136, /*0280*/ 0x002e00d4, /*0281*/ 0x11360031, /*0282*/ 0x0000d411, /*0283*/ 0x0031002e, /*0284*/ 0x00111136, /*0285*/ 0x002e00d4, /*0286*/ 0x11360031, /*0287*/ 0x00d40011, /*0288*/ 0x0031002e, /*0289*/ 0x00111136, /*028a*/ 0x002e00d4, /*028b*/ 0x11360031, /*028c*/ 0x0000d411, /*028d*/ 0x0031002e, /*028e*/ 0x00111136, /*028f*/ 0x002e00d4, /*0290*/ 0x11360031, /*0291*/ 0x0000d411, /*0292*/ 0x0031002e, /*0293*/ 0x00111136, /*0294*/ 0x002e00d4, /*0295*/ 0x11360031, /*0296*/ 0x02000011, /*0297*/ 0x018d018d, /*0298*/ 0x0c08018d, /*0299*/ 0x1f121d22, /*029a*/ 0x4301b344, /*029b*/ 0x10172006, /*029c*/ 0x1d220c10, /*029d*/ 0x00001f12, /*029e*/ 0x4301b344, /*029f*/ 0x10172006, /*02a0*/ 0x1d220c10, /*02a1*/ 0x00001f12, /*02a2*/ 0x4301b344, /*02a3*/ 0x10172006, /*02a4*/ 0x02000210, /*02a5*/ 0x02000200, /*02a6*/ 0x02000200, /*02a7*/ 0x02000200, /*02a8*/ 0x02000200, /*02a9*/ 0x00000000, /*02aa*/ 0x00000000, /*02ab*/ 0x00000000, /*02ac*/ 0x00000000, /*02ad*/ 0x00000000, /*02ae*/ 0x00000000, /*02af*/ 0x00000000, /*02b0*/ 0x00000000, /*02b1*/ 0x00000000, /*02b2*/ 0x00000000, /*02b3*/ 0x00000000, /*02b4*/ 0x00000000, /*02b5*/ 0x00000400, /*02b6*/ 0x15141312, /*02b7*/ 0x11100f0e, /*02b8*/ 0x080b0c0d, /*02b9*/ 0x05040a09, /*02ba*/ 0x01000706, /*02bb*/ 0x00000302, /*02bc*/ 0x01030201, /*02bd*/ 0x00304c00, /*02be*/ 0x0001e2f8, /*02bf*/ 0x0000304c, /*02c0*/ 0x0001e2f8, /*02c1*/ 0x0000304c, /*02c2*/ 0x0001e2f8, /*02c3*/ 0x08000000, /*02c4*/ 0x00000100, /*02c5*/ 0x00000000, /*02c6*/ 0x00000000, /*02c7*/ 0x00000000, /*02c8*/ 0x00000000, /*02c9*/ 0x00000002 }; trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_b/init_dram_tbl_m3n.h000066400000000000000000000317011355360272700301740ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #define DDR_PHY_SLICE_REGSET_OFS_M3N 0x0800 #define DDR_PHY_ADR_V_REGSET_OFS_M3N 0x0a00 #define DDR_PHY_ADR_I_REGSET_OFS_M3N 0x0a80 #define DDR_PHY_ADR_G_REGSET_OFS_M3N 0x0b80 #define DDR_PI_REGSET_OFS_M3N 0x0200 #define DDR_PHY_SLICE_REGSET_SIZE_M3N 0x80 #define DDR_PHY_ADR_V_REGSET_SIZE_M3N 0x80 #define DDR_PHY_ADR_I_REGSET_SIZE_M3N 0x80 #define DDR_PHY_ADR_G_REGSET_SIZE_M3N 0x80 #define DDR_PI_REGSET_SIZE_M3N 0x100 #define DDR_PHY_SLICE_REGSET_NUM_M3N 101 #define DDR_PHY_ADR_V_REGSET_NUM_M3N 37 #define DDR_PHY_ADR_I_REGSET_NUM_M3N 37 #define DDR_PHY_ADR_G_REGSET_NUM_M3N 87 #define DDR_PI_REGSET_NUM_M3N 286 static const uint32_t DDR_PHY_SLICE_REGSET_M3N[DDR_PHY_SLICE_REGSET_NUM_M3N] = { /*0800*/ 0x76543210, /*0801*/ 0x0004f008, /*0802*/ 0x00020200, /*0803*/ 0x00000000, /*0804*/ 0x00000000, /*0805*/ 0x00010000, /*0806*/ 0x036e6e0e, /*0807*/ 0x026e6e0e, /*0808*/ 0x00000103, /*0809*/ 0x00040001, /*080a*/ 0x00000103, /*080b*/ 0x00000001, /*080c*/ 0x00000000, /*080d*/ 0x00000000, /*080e*/ 0x00000100, /*080f*/ 0x001800c0, /*0810*/ 0x020100b0, /*0811*/ 0x00030020, /*0812*/ 0x00000000, /*0813*/ 0x00000000, /*0814*/ 0x0000aaaa, /*0815*/ 0x00005555, /*0816*/ 0x0000b5b5, /*0817*/ 0x00004a4a, /*0818*/ 0x00000000, /*0819*/ 0x09000000, /*081a*/ 0x04080000, /*081b*/ 0x08040000, /*081c*/ 0x00000004, /*081d*/ 0x00800710, /*081e*/ 0x000f000c, /*081f*/ 0x00000100, /*0820*/ 0x55aa55aa, /*0821*/ 0x33cc33cc, /*0822*/ 0x0ff00ff0, /*0823*/ 0x0f0ff0f0, /*0824*/ 0x00018e38, /*0825*/ 0x00000000, /*0826*/ 0x00000000, /*0827*/ 0x00000000, /*0828*/ 0x00000000, /*0829*/ 0x00000000, /*082a*/ 0x00000000, /*082b*/ 0x00000000, /*082c*/ 0x00000000, /*082d*/ 0x00000000, /*082e*/ 0x00000000, /*082f*/ 0x00000000, /*0830*/ 0x00000000, /*0831*/ 0x00000000, /*0832*/ 0x00000000, /*0833*/ 0x00000000, /*0834*/ 0x00000000, /*0835*/ 0x00000000, /*0836*/ 0x00000000, /*0837*/ 0x00000000, /*0838*/ 0x00000000, /*0839*/ 0x00000000, /*083a*/ 0x00000104, /*083b*/ 0x00082020, /*083c*/ 0x08200820, /*083d*/ 0x08200820, /*083e*/ 0x08200820, /*083f*/ 0x08200820, /*0840*/ 0x08200820, /*0841*/ 0x00000000, /*0842*/ 0x00000000, /*0843*/ 0x03000300, /*0844*/ 0x03000300, /*0845*/ 0x03000300, /*0846*/ 0x03000300, /*0847*/ 0x00000300, /*0848*/ 0x00000000, /*0849*/ 0x00000000, /*084a*/ 0x00000000, /*084b*/ 0x00000000, /*084c*/ 0x00000000, /*084d*/ 0x00a000a0, /*084e*/ 0x00a000a0, /*084f*/ 0x00a000a0, /*0850*/ 0x00a000a0, /*0851*/ 0x00a000a0, /*0852*/ 0x00a000a0, /*0853*/ 0x00a000a0, /*0854*/ 0x00a000a0, /*0855*/ 0x00a000a0, /*0856*/ 0x01040119, /*0857*/ 0x00000200, /*0858*/ 0x01000000, /*0859*/ 0x00000200, /*085a*/ 0x00000004, /*085b*/ 0x4041a151, /*085c*/ 0x0141c0a0, /*085d*/ 0x0000c0c0, /*085e*/ 0x0e0c000e, /*085f*/ 0x10001000, /*0860*/ 0x0c073e42, /*0861*/ 0x000f0c28, /*0862*/ 0x00e00140, /*0863*/ 0x000c0020, /*0864*/ 0x00000203 }; static const uint32_t DDR_PHY_ADR_V_REGSET_M3N[DDR_PHY_ADR_V_REGSET_NUM_M3N] = { /*0a00*/ 0x00000000, /*0a01*/ 0x00000000, /*0a02*/ 0x00000000, /*0a03*/ 0x00000000, /*0a04*/ 0x00000000, /*0a05*/ 0x00000000, /*0a06*/ 0x00000000, /*0a07*/ 0x01000000, /*0a08*/ 0x00020000, /*0a09*/ 0x00000000, /*0a0a*/ 0x00000000, /*0a0b*/ 0x00000000, /*0a0c*/ 0x00400000, /*0a0d*/ 0x00000080, /*0a0e*/ 0x00dcba98, /*0a0f*/ 0x03000000, /*0a10*/ 0x00000200, /*0a11*/ 0x00000000, /*0a12*/ 0x00000000, /*0a13*/ 0x00000000, /*0a14*/ 0x0000002a, /*0a15*/ 0x00000015, /*0a16*/ 0x00000015, /*0a17*/ 0x0000002a, /*0a18*/ 0x00000033, /*0a19*/ 0x0000000c, /*0a1a*/ 0x0000000c, /*0a1b*/ 0x00000033, /*0a1c*/ 0x0a418820, /*0a1d*/ 0x003f0000, /*0a1e*/ 0x0000013f, /*0a1f*/ 0x0002c06e, /*0a20*/ 0x02c002c0, /*0a21*/ 0x02c002c0, /*0a22*/ 0x000002c0, /*0a23*/ 0x42080010, /*0a24*/ 0x0000033e }; static const uint32_t DDR_PHY_ADR_I_REGSET_M3N[DDR_PHY_ADR_I_REGSET_NUM_M3N] = { /*0a80*/ 0x00000000, /*0a81*/ 0x00000000, /*0a82*/ 0x00000000, /*0a83*/ 0x00000000, /*0a84*/ 0x00000000, /*0a85*/ 0x00000000, /*0a86*/ 0x00000000, /*0a87*/ 0x01000000, /*0a88*/ 0x00020000, /*0a89*/ 0x00000000, /*0a8a*/ 0x00000000, /*0a8b*/ 0x00000000, /*0a8c*/ 0x00400000, /*0a8d*/ 0x00000080, /*0a8e*/ 0x00000000, /*0a8f*/ 0x03000000, /*0a90*/ 0x00000200, /*0a91*/ 0x00000000, /*0a92*/ 0x00000000, /*0a93*/ 0x00000000, /*0a94*/ 0x0000002a, /*0a95*/ 0x00000015, /*0a96*/ 0x00000015, /*0a97*/ 0x0000002a, /*0a98*/ 0x00000033, /*0a99*/ 0x0000000c, /*0a9a*/ 0x0000000c, /*0a9b*/ 0x00000033, /*0a9c*/ 0x00000000, /*0a9d*/ 0x00000000, /*0a9e*/ 0x00000000, /*0a9f*/ 0x0002c06e, /*0aa0*/ 0x02c002c0, /*0aa1*/ 0x02c002c0, /*0aa2*/ 0x000002c0, /*0aa3*/ 0x42080010, /*0aa4*/ 0x0000033e }; static const uint32_t DDR_PHY_ADR_G_REGSET_M3N[DDR_PHY_ADR_G_REGSET_NUM_M3N] = { /*0b80*/ 0x00000000, /*0b81*/ 0x00000100, /*0b82*/ 0x00000000, /*0b83*/ 0x00050000, /*0b84*/ 0x00000000, /*0b85*/ 0x0004000f, /*0b86*/ 0x00280080, /*0b87*/ 0x02005502, /*0b88*/ 0x00000000, /*0b89*/ 0x00000000, /*0b8a*/ 0x00000000, /*0b8b*/ 0x00000050, /*0b8c*/ 0x00000000, /*0b8d*/ 0x01010100, /*0b8e*/ 0x00010000, /*0b8f*/ 0x00000000, /*0b90*/ 0x00000101, /*0b91*/ 0x00000000, /*0b92*/ 0x00000000, /*0b93*/ 0x00000000, /*0b94*/ 0x00000000, /*0b95*/ 0x00005064, /*0b96*/ 0x01421142, /*0b97*/ 0x00000142, /*0b98*/ 0x00000000, /*0b99*/ 0x000f1600, /*0b9a*/ 0x0f160f16, /*0b9b*/ 0x0f160f16, /*0b9c*/ 0x00000003, /*0b9d*/ 0x0002c000, /*0b9e*/ 0x02c002c0, /*0b9f*/ 0x000002c0, /*0ba0*/ 0x08040201, /*0ba1*/ 0x03421342, /*0ba2*/ 0x00000342, /*0ba3*/ 0x00000000, /*0ba4*/ 0x00000000, /*0ba5*/ 0x05030000, /*0ba6*/ 0x00010700, /*0ba7*/ 0x00000014, /*0ba8*/ 0x00027f6e, /*0ba9*/ 0x047f027f, /*0baa*/ 0x00027f6e, /*0bab*/ 0x00047f6e, /*0bac*/ 0x0003554f, /*0bad*/ 0x0001554f, /*0bae*/ 0x0001554f, /*0baf*/ 0x0001554f, /*0bb0*/ 0x0001554f, /*0bb1*/ 0x00003fee, /*0bb2*/ 0x0001554f, /*0bb3*/ 0x00003fee, /*0bb4*/ 0x0001554f, /*0bb5*/ 0x00027f6e, /*0bb6*/ 0x0001554f, /*0bb7*/ 0x00004011, /*0bb8*/ 0x00004410, /*0bb9*/ 0x00000000, /*0bba*/ 0x00000000, /*0bbb*/ 0x00000000, /*0bbc*/ 0x00000265, /*0bbd*/ 0x00000000, /*0bbe*/ 0x00040401, /*0bbf*/ 0x00000000, /*0bc0*/ 0x03000000, /*0bc1*/ 0x00000020, /*0bc2*/ 0x00000000, /*0bc3*/ 0x00000000, /*0bc4*/ 0x04102006, /*0bc5*/ 0x00041020, /*0bc6*/ 0x01c98c98, /*0bc7*/ 0x00400000, /*0bc8*/ 0x00000000, /*0bc9*/ 0x0001ffff, /*0bca*/ 0x00000000, /*0bcb*/ 0x00000000, /*0bcc*/ 0x00000001, /*0bcd*/ 0x00000000, /*0bce*/ 0x00000000, /*0bcf*/ 0x00000000, /*0bd0*/ 0x76543210, /*0bd1*/ 0x06010198, /*0bd2*/ 0x00000000, /*0bd3*/ 0x00000000, /*0bd4*/ 0x04070000, /*0bd5*/ 0x00000001, /*0bd6*/ 0x00000f00 }; static const uint32_t DDR_PI_REGSET_M3N[DDR_PI_REGSET_NUM_M3N] = { /*0200*/ 0x00000b00, /*0201*/ 0x00000101, /*0202*/ 0x01640000, /*0203*/ 0x00000014, /*0204*/ 0x00000014, /*0205*/ 0x00000014, /*0206*/ 0x00000014, /*0207*/ 0x00000000, /*0208*/ 0x00000000, /*0209*/ 0x0000ffff, /*020a*/ 0x00000000, /*020b*/ 0x0000ffff, /*020c*/ 0x00000000, /*020d*/ 0x0000ffff, /*020e*/ 0x0000304c, /*020f*/ 0x00000200, /*0210*/ 0x00000200, /*0211*/ 0x00000200, /*0212*/ 0x00000200, /*0213*/ 0x0000304c, /*0214*/ 0x00000200, /*0215*/ 0x00000200, /*0216*/ 0x00000200, /*0217*/ 0x00000200, /*0218*/ 0x0000304c, /*0219*/ 0x00000200, /*021a*/ 0x00000200, /*021b*/ 0x00000200, /*021c*/ 0x00000200, /*021d*/ 0x00010000, /*021e*/ 0x00000003, /*021f*/ 0x01000001, /*0220*/ 0x00000000, /*0221*/ 0x00000000, /*0222*/ 0x00000000, /*0223*/ 0x00000000, /*0224*/ 0x00000000, /*0225*/ 0x00000000, /*0226*/ 0x00000000, /*0227*/ 0x00000000, /*0228*/ 0x00000000, /*0229*/ 0x00000000, /*022a*/ 0x00000000, /*022b*/ 0x00000000, /*022c*/ 0x00000000, /*022d*/ 0x00000000, /*022e*/ 0x00000000, /*022f*/ 0x00000000, /*0230*/ 0x0f000101, /*0231*/ 0x084d3129, /*0232*/ 0x0e0c0004, /*0233*/ 0x000e5000, /*0234*/ 0x01000250, /*0235*/ 0x00000003, /*0236*/ 0x00000046, /*0237*/ 0x000000cf, /*0238*/ 0x00001826, /*0239*/ 0x000000cf, /*023a*/ 0x00001826, /*023b*/ 0x00000000, /*023c*/ 0x00000000, /*023d*/ 0x00000000, /*023e*/ 0x00000000, /*023f*/ 0x00000000, /*0240*/ 0x00000000, /*0241*/ 0x00000000, /*0242*/ 0x00000000, /*0243*/ 0x00000000, /*0244*/ 0x00000000, /*0245*/ 0x01000000, /*0246*/ 0x00040404, /*0247*/ 0x01280a00, /*0248*/ 0x00000001, /*0249*/ 0x00000000, /*024a*/ 0x03000f00, /*024b*/ 0x00200020, /*024c*/ 0x00000020, /*024d*/ 0x00000000, /*024e*/ 0x00000000, /*024f*/ 0x00010002, /*0250*/ 0x01010001, /*0251*/ 0x02010100, /*0252*/ 0x08040402, /*0253*/ 0x00000008, /*0254*/ 0x00000000, /*0255*/ 0x04080803, /*0256*/ 0x00001515, /*0257*/ 0x00000000, /*0258*/ 0x000000aa, /*0259*/ 0x00000055, /*025a*/ 0x000000b5, /*025b*/ 0x0000004a, /*025c*/ 0x00000056, /*025d*/ 0x000000a9, /*025e*/ 0x000000a9, /*025f*/ 0x000000b5, /*0260*/ 0x00000000, /*0261*/ 0x00000000, /*0262*/ 0x0f000000, /*0263*/ 0x00001e0f, /*0264*/ 0x000007d0, /*0265*/ 0x01000300, /*0266*/ 0x00000100, /*0267*/ 0x00000000, /*0268*/ 0x00000000, /*0269*/ 0x01000000, /*026a*/ 0x00010101, /*026b*/ 0x000e0e0e, /*026c*/ 0x000c0c0c, /*026d*/ 0x01060601, /*026e*/ 0x04041717, /*026f*/ 0x00000004, /*0270*/ 0x00000300, /*0271*/ 0x17030000, /*0272*/ 0x00060018, /*0273*/ 0x00160028, /*0274*/ 0x00160028, /*0275*/ 0x00000000, /*0276*/ 0x00000000, /*0277*/ 0x00000000, /*0278*/ 0x0a000000, /*0279*/ 0x00010a14, /*027a*/ 0x00030005, /*027b*/ 0x0003018d, /*027c*/ 0x000a018d, /*027d*/ 0x00060100, /*027e*/ 0x01000006, /*027f*/ 0x018e018e, /*0280*/ 0x018e0100, /*0281*/ 0x1e1a018e, /*0282*/ 0x1e1a1e1a, /*0283*/ 0x01010204, /*0284*/ 0x06501001, /*0285*/ 0x090d0a07, /*0286*/ 0x090d0a07, /*0287*/ 0x0811180f, /*0288*/ 0x00ff1102, /*0289*/ 0x00ff1000, /*028a*/ 0x00ff1000, /*028b*/ 0x04041000, /*028c*/ 0x18020100, /*028d*/ 0x01010018, /*028e*/ 0x005f005f, /*028f*/ 0x005f005f, /*0290*/ 0x050f0000, /*0291*/ 0x051e051e, /*0292*/ 0x0c01021e, /*0293*/ 0x00000c0c, /*0294*/ 0x00003400, /*0295*/ 0x00000000, /*0296*/ 0x00000000, /*0297*/ 0x00000000, /*0298*/ 0x00000000, /*0299*/ 0x002e00d4, /*029a*/ 0x11360031, /*029b*/ 0x00d41611, /*029c*/ 0x0031002e, /*029d*/ 0x16111136, /*029e*/ 0x002e00d4, /*029f*/ 0x11360031, /*02a0*/ 0x00001611, /*02a1*/ 0x002e00d4, /*02a2*/ 0x11360031, /*02a3*/ 0x00d41611, /*02a4*/ 0x0031002e, /*02a5*/ 0x16111136, /*02a6*/ 0x002e00d4, /*02a7*/ 0x11360031, /*02a8*/ 0x00001611, /*02a9*/ 0x002e00d4, /*02aa*/ 0x11360031, /*02ab*/ 0x00d41611, /*02ac*/ 0x0031002e, /*02ad*/ 0x16111136, /*02ae*/ 0x002e00d4, /*02af*/ 0x11360031, /*02b0*/ 0x00001611, /*02b1*/ 0x002e00d4, /*02b2*/ 0x11360031, /*02b3*/ 0x00d41611, /*02b4*/ 0x0031002e, /*02b5*/ 0x16111136, /*02b6*/ 0x002e00d4, /*02b7*/ 0x11360031, /*02b8*/ 0x00001611, /*02b9*/ 0x00018d00, /*02ba*/ 0x018d018d, /*02bb*/ 0x1d220c08, /*02bc*/ 0x00001f12, /*02bd*/ 0x4301b344, /*02be*/ 0x17032006, /*02bf*/ 0x220c1010, /*02c0*/ 0x001f121d, /*02c1*/ 0x4301b344, /*02c2*/ 0x17062006, /*02c3*/ 0x220c1010, /*02c4*/ 0x001f121d, /*02c5*/ 0x4301b344, /*02c6*/ 0x17182006, /*02c7*/ 0x00021010, /*02c8*/ 0x00020002, /*02c9*/ 0x00020002, /*02ca*/ 0x00020002, /*02cb*/ 0x00020002, /*02cc*/ 0x00000002, /*02cd*/ 0x00000000, /*02ce*/ 0x00000000, /*02cf*/ 0x00000000, /*02d0*/ 0x00000000, /*02d1*/ 0x00000000, /*02d2*/ 0x00000000, /*02d3*/ 0x00000000, /*02d4*/ 0x00000000, /*02d5*/ 0x00000000, /*02d6*/ 0x00000000, /*02d7*/ 0x00000000, /*02d8*/ 0x00000000, /*02d9*/ 0x00000400, /*02da*/ 0x15141312, /*02db*/ 0x11100f0e, /*02dc*/ 0x080b0c0d, /*02dd*/ 0x05040a09, /*02de*/ 0x01000706, /*02df*/ 0x00000302, /*02e0*/ 0x01030201, /*02e1*/ 0x00304c08, /*02e2*/ 0x0001e2f8, /*02e3*/ 0x0000304c, /*02e4*/ 0x0001e2f8, /*02e5*/ 0x0000304c, /*02e6*/ 0x0001e2f8, /*02e7*/ 0x08000000, /*02e8*/ 0x00000100, /*02e9*/ 0x00000000, /*02ea*/ 0x00000000, /*02eb*/ 0x00000000, /*02ec*/ 0x00000000, /*02ed*/ 0x00010000, /*02ee*/ 0x00000000, /*02ef*/ 0x00000000, /*02f0*/ 0x00000000, /*02f1*/ 0x00000000, /*02f2*/ 0x00000000, /*02f3*/ 0x00000000, /*02f4*/ 0x00000000, /*02f5*/ 0x00000000, /*02f6*/ 0x00000000, /*02f7*/ 0x00000000, /*02f8*/ 0x00000000, /*02f9*/ 0x00000000, /*02fa*/ 0x00000000, /*02fb*/ 0x00000000, /*02fc*/ 0x00000000, /*02fd*/ 0x00000000, /*02fe*/ 0x00000000, /*02ff*/ 0x00000000, /*0300*/ 0x00000000, /*0301*/ 0x00000000, /*0302*/ 0x00000000, /*0303*/ 0x00000000, /*0304*/ 0x00000000, /*0305*/ 0x00000000, /*0306*/ 0x00000000, /*0307*/ 0x00000000, /*0308*/ 0x00000000, /*0309*/ 0x00000000, /*030a*/ 0x00000000, /*030b*/ 0x00000000, /*030c*/ 0x00000000, /*030d*/ 0x00000000, /*030e*/ 0x00000000, /*030f*/ 0x00050002, /*0310*/ 0x015c0057, /*0311*/ 0x01000100, /*0312*/ 0x01020001, /*0313*/ 0x00010300, /*0314*/ 0x05000104, /*0315*/ 0x01060001, /*0316*/ 0x00010700, /*0317*/ 0x00000000, /*0318*/ 0x00000000, /*0319*/ 0x00000001, /*031a*/ 0x00000000, /*031b*/ 0x00000000, /*031c*/ 0x00000000, /*031d*/ 0x20080101 }; trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/ddr_regs.h000066400000000000000000000223021355360272700253240ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BOOT_INIT_DRAM_REGDEF_H_ #define BOOT_INIT_DRAM_REGDEF_H_ /* DBSC registers */ #define DBSC_DBSYSCONF0 0xE6790000U #define DBSC_DBSYSCONF1 0xE6790004U #define DBSC_DBPHYCONF0 0xE6790010U #define DBSC_DBKIND 0xE6790020U #define DBSC_DBMEMCONF(ch, cs) (0xE6790030U + 0x10U * (ch) + 0x04U * (cs)) #define DBSC_DBMEMCONF_0_0 0xE6790030U #define DBSC_DBMEMCONF_0_1 0xE6790034U #define DBSC_DBMEMCONF_0_2 0xE6790038U #define DBSC_DBMEMCONF_0_3 0xE679003CU #define DBSC_DBMEMCONF_1_2 0xE6790048U #define DBSC_DBMEMCONF_1_3 0xE679004CU #define DBSC_DBMEMCONF_1_0 0xE6790040U #define DBSC_DBMEMCONF_1_1 0xE6790044U #define DBSC_DBMEMCONF_2_0 0xE6790050U #define DBSC_DBMEMCONF_2_1 0xE6790054U #define DBSC_DBMEMCONF_2_2 0xE6790058U #define DBSC_DBMEMCONF_2_3 0xE679005CU #define DBSC_DBMEMCONF_3_0 0xE6790060U #define DBSC_DBMEMCONF_3_1 0xE6790064U #define DBSC_DBMEMCONF_3_2 0xE6790068U #define DBSC_DBMEMCONF_3_3 0xE679006CU #define DBSC_DBSYSCNT0 0xE6790100U #define DBSC_DBSVCR1 0xE6790104U #define DBSC_DBSTATE0 0xE6790108U #define DBSC_DBSTATE1 0xE679010CU #define DBSC_DBINTEN 0xE6790180U #define DBSC_DBINTSTAT0 0xE6790184U #define DBSC_DBACEN 0xE6790200U #define DBSC_DBRFEN 0xE6790204U #define DBSC_DBCMD 0xE6790208U #define DBSC_DBWAIT 0xE6790210U #define DBSC_DBSYSCTRL0 0xE6790280U #define DBSC_DBTR(x) (0xE6790300U + 0x04U * (x)) #define DBSC_DBTR0 0xE6790300U #define DBSC_DBTR1 0xE6790304U #define DBSC_DBTR2 0xE6790308U #define DBSC_DBTR3 0xE679030CU #define DBSC_DBTR4 0xE6790310U #define DBSC_DBTR5 0xE6790314U #define DBSC_DBTR6 0xE6790318U #define DBSC_DBTR7 0xE679031CU #define DBSC_DBTR8 0xE6790320U #define DBSC_DBTR9 0xE6790324U #define DBSC_DBTR10 0xE6790328U #define DBSC_DBTR11 0xE679032CU #define DBSC_DBTR12 0xE6790330U #define DBSC_DBTR13 0xE6790334U #define DBSC_DBTR14 0xE6790338U #define DBSC_DBTR15 0xE679033CU #define DBSC_DBTR16 0xE6790340U #define DBSC_DBTR17 0xE6790344U #define DBSC_DBTR18 0xE6790348U #define DBSC_DBTR19 0xE679034CU #define DBSC_DBTR20 0xE6790350U #define DBSC_DBTR21 0xE6790354U #define DBSC_DBTR22 0xE6790358U #define DBSC_DBTR23 0xE679035CU #define DBSC_DBTR24 0xE6790360U #define DBSC_DBTR25 0xE6790364U #define DBSC_DBTR26 0xE6790368U #define DBSC_DBBL 0xE6790400U #define DBSC_DBRFCNF1 0xE6790414U #define DBSC_DBRFCNF2 0xE6790418U #define DBSC_DBTSPCNF 0xE6790420U #define DBSC_DBCALCNF 0xE6790424U #define DBSC_DBRNK(x) (0xE6790430U + 0x04U * (x)) #define DBSC_DBRNK2 0xE6790438U #define DBSC_DBRNK3 0xE679043CU #define DBSC_DBRNK4 0xE6790440U #define DBSC_DBRNK5 0xE6790444U #define DBSC_DBPDNCNF 0xE6790450U #define DBSC_DBODT(x) (0xE6790460U + 0x04U * (x)) #define DBSC_DBODT0 0xE6790460U #define DBSC_DBODT1 0xE6790464U #define DBSC_DBODT2 0xE6790468U #define DBSC_DBODT3 0xE679046CU #define DBSC_DBODT4 0xE6790470U #define DBSC_DBODT5 0xE6790474U #define DBSC_DBODT6 0xE6790478U #define DBSC_DBODT7 0xE679047CU #define DBSC_DBADJ0 0xE6790500U #define DBSC_DBDBICNT 0xE6790518U #define DBSC_DBDFIPMSTRCNF 0xE6790520U #define DBSC_DBDFICUPDCNF 0xE679052CU #define DBSC_DBDFISTAT(ch) (0xE6790600U + 0x40U * (ch)) #define DBSC_DBDFISTAT_0 0xE6790600U #define DBSC_DBDFISTAT_1 0xE6790640U #define DBSC_DBDFISTAT_2 0xE6790680U #define DBSC_DBDFISTAT_3 0xE67906C0U #define DBSC_DBDFICNT(ch) (0xE6790604U + 0x40U * (ch)) #define DBSC_DBDFICNT_0 0xE6790604U #define DBSC_DBDFICNT_1 0xE6790644U #define DBSC_DBDFICNT_2 0xE6790684U #define DBSC_DBDFICNT_3 0xE67906C4U #define DBSC_DBPDCNT0(ch) (0xE6790610U + 0x40U * (ch)) #define DBSC_DBPDCNT0_0 0xE6790610U #define DBSC_DBPDCNT0_1 0xE6790650U #define DBSC_DBPDCNT0_2 0xE6790690U #define DBSC_DBPDCNT0_3 0xE67906D0U #define DBSC_DBPDCNT1(ch) (0xE6790614U + 0x40U * (ch)) #define DBSC_DBPDCNT1_0 0xE6790614U #define DBSC_DBPDCNT1_1 0xE6790654U #define DBSC_DBPDCNT1_2 0xE6790694U #define DBSC_DBPDCNT1_3 0xE67906D4U #define DBSC_DBPDCNT2(ch) (0xE6790618U + 0x40U * (ch)) #define DBSC_DBPDCNT2_0 0xE6790618U #define DBSC_DBPDCNT2_1 0xE6790658U #define DBSC_DBPDCNT2_2 0xE6790698U #define DBSC_DBPDCNT2_3 0xE67906D8U #define DBSC_DBPDCNT3(ch) (0xE679061CU + 0x40U * (ch)) #define DBSC_DBPDCNT3_0 0xE679061CU #define DBSC_DBPDCNT3_1 0xE679065CU #define DBSC_DBPDCNT3_2 0xE679069CU #define DBSC_DBPDCNT3_3 0xE67906DCU #define DBSC_DBPDLK(ch) (0xE6790620U + 0x40U * (ch)) #define DBSC_DBPDLK_0 0xE6790620U #define DBSC_DBPDLK_1 0xE6790660U #define DBSC_DBPDLK_2 0xE67906a0U #define DBSC_DBPDLK_3 0xE67906e0U #define DBSC_DBPDRGA(ch) (0xE6790624U + 0x40U * (ch)) #define DBSC_DBPDRGD(ch) (0xE6790628U + 0x40U * (ch)) #define DBSC_DBPDRGA_0 0xE6790624U #define DBSC_DBPDRGD_0 0xE6790628U #define DBSC_DBPDRGA_1 0xE6790664U #define DBSC_DBPDRGD_1 0xE6790668U #define DBSC_DBPDRGA_2 0xE67906A4U #define DBSC_DBPDRGD_2 0xE67906A8U #define DBSC_DBPDRGA_3 0xE67906E4U #define DBSC_DBPDRGD_3 0xE67906E8U #define DBSC_DBPDSTAT(ch) (0xE6790630U + 0x40U * (ch)) #define DBSC_DBPDSTAT_0 0xE6790630U #define DBSC_DBPDSTAT_1 0xE6790670U #define DBSC_DBPDSTAT_2 0xE67906B0U #define DBSC_DBPDSTAT_3 0xE67906F0U #define DBSC_DBBUS0CNF0 0xE6790800U #define DBSC_DBBUS0CNF1 0xE6790804U #define DBSC_DBCAM0CNF1 0xE6790904U #define DBSC_DBCAM0CNF2 0xE6790908U #define DBSC_DBCAM0CNF3 0xE679090CU #define DBSC_DBBSWAP 0xE67909F0U #define DBSC_DBBCAMDIS 0xE67909FCU #define DBSC_DBSCHCNT0 0xE6791000U #define DBSC_DBSCHCNT1 0xE6791004U #define DBSC_DBSCHSZ0 0xE6791010U #define DBSC_DBSCHRW0 0xE6791020U #define DBSC_DBSCHRW1 0xE6791024U #define DBSC_DBSCHQOS_0(x) (0xE6791030U + 0x10U * (x)) #define DBSC_DBSCHQOS_1(x) (0xE6791034U + 0x10U * (x)) #define DBSC_DBSCHQOS_2(x) (0xE6791038U + 0x10U * (x)) #define DBSC_DBSCHQOS_3(x) (0xE679103CU + 0x10U * (x)) #define DBSC_DBSCHQOS00 0xE6791030U #define DBSC_DBSCHQOS01 0xE6791034U #define DBSC_DBSCHQOS02 0xE6791038U #define DBSC_DBSCHQOS03 0xE679103CU #define DBSC_DBSCHQOS10 0xE6791040U #define DBSC_DBSCHQOS11 0xE6791044U #define DBSC_DBSCHQOS12 0xE6791048U #define DBSC_DBSCHQOS13 0xE679104CU #define DBSC_DBSCHQOS20 0xE6791050U #define DBSC_DBSCHQOS21 0xE6791054U #define DBSC_DBSCHQOS22 0xE6791058U #define DBSC_DBSCHQOS23 0xE679105CU #define DBSC_DBSCHQOS30 0xE6791060U #define DBSC_DBSCHQOS31 0xE6791064U #define DBSC_DBSCHQOS32 0xE6791068U #define DBSC_DBSCHQOS33 0xE679106CU #define DBSC_DBSCHQOS40 0xE6791070U #define DBSC_DBSCHQOS41 0xE6791074U #define DBSC_DBSCHQOS42 0xE6791078U #define DBSC_DBSCHQOS43 0xE679107CU #define DBSC_DBSCHQOS50 0xE6791080U #define DBSC_DBSCHQOS51 0xE6791084U #define DBSC_DBSCHQOS52 0xE6791088U #define DBSC_DBSCHQOS53 0xE679108CU #define DBSC_DBSCHQOS60 0xE6791090U #define DBSC_DBSCHQOS61 0xE6791094U #define DBSC_DBSCHQOS62 0xE6791098U #define DBSC_DBSCHQOS63 0xE679109CU #define DBSC_DBSCHQOS70 0xE67910A0U #define DBSC_DBSCHQOS71 0xE67910A4U #define DBSC_DBSCHQOS72 0xE67910A8U #define DBSC_DBSCHQOS73 0xE67910ACU #define DBSC_DBSCHQOS80 0xE67910B0U #define DBSC_DBSCHQOS81 0xE67910B4U #define DBSC_DBSCHQOS82 0xE67910B8U #define DBSC_DBSCHQOS83 0xE67910BCU #define DBSC_DBSCHQOS90 0xE67910C0U #define DBSC_DBSCHQOS91 0xE67910C4U #define DBSC_DBSCHQOS92 0xE67910C8U #define DBSC_DBSCHQOS93 0xE67910CCU #define DBSC_DBSCHQOS100 0xE67910D0U #define DBSC_DBSCHQOS101 0xE67910D4U #define DBSC_DBSCHQOS102 0xE67910D8U #define DBSC_DBSCHQOS103 0xE67910DCU #define DBSC_DBSCHQOS110 0xE67910E0U #define DBSC_DBSCHQOS111 0xE67910E4U #define DBSC_DBSCHQOS112 0xE67910E8U #define DBSC_DBSCHQOS113 0xE67910ECU #define DBSC_DBSCHQOS120 0xE67910F0U #define DBSC_DBSCHQOS121 0xE67910F4U #define DBSC_DBSCHQOS122 0xE67910F8U #define DBSC_DBSCHQOS123 0xE67910FCU #define DBSC_DBSCHQOS130 0xE6791100U #define DBSC_DBSCHQOS131 0xE6791104U #define DBSC_DBSCHQOS132 0xE6791108U #define DBSC_DBSCHQOS133 0xE679110CU #define DBSC_DBSCHQOS140 0xE6791110U #define DBSC_DBSCHQOS141 0xE6791114U #define DBSC_DBSCHQOS142 0xE6791118U #define DBSC_DBSCHQOS143 0xE679111CU #define DBSC_DBSCHQOS150 0xE6791120U #define DBSC_DBSCHQOS151 0xE6791124U #define DBSC_DBSCHQOS152 0xE6791128U #define DBSC_DBSCHQOS153 0xE679112CU #define DBSC_DBSCTR0 0xE6791700U #define DBSC_DBSCTR1 0xE6791708U #define DBSC_DBSCHRW2 0xE679170CU #define DBSC_SCFCTST01(x) (0xE6791700U + 0x08U * (x)) #define DBSC_SCFCTST0 0xE6791700U #define DBSC_SCFCTST1 0xE6791708U #define DBSC_SCFCTST2 0xE679170CU #define DBSC_DBMRRDR(chab) (0xE6791800U + 0x04U * (chab)) #define DBSC_DBMRRDR_0 0xE6791800U #define DBSC_DBMRRDR_1 0xE6791804U #define DBSC_DBMRRDR_2 0xE6791808U #define DBSC_DBMRRDR_3 0xE679180CU #define DBSC_DBMRRDR_4 0xE6791810U #define DBSC_DBMRRDR_5 0xE6791814U #define DBSC_DBMRRDR_6 0xE6791818U #define DBSC_DBMRRDR_7 0xE679181CU #define DBSC_DBMEMSWAPCONF0 0xE6792000U /* CPG registers */ #define CPG_BASE 0xE6150000U #define CPG_FRQCRB (CPG_BASE + 0x0004U) #define CPG_PLLECR (CPG_BASE + 0x00D0U) #define CPG_MSTPSR5 (CPG_BASE + 0x003CU) #define CPG_SRCR4 (CPG_BASE + 0x00BCU) #define CPG_PLL3CR (CPG_BASE + 0x00DCU) #define CPG_ZB3CKCR (CPG_BASE + 0x0380U) #define CPG_FRQCRD (CPG_BASE + 0x00E4U) #define CPG_SMSTPCR5 (CPG_BASE + 0x0144U) #define CPG_CPGWPR (CPG_BASE + 0x0900U) #define CPG_SRSTCLR4 (CPG_BASE + 0x0950U) #endif /* BOOT_INIT_DRAM_REGDEF_H_*/ trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/dram_sub_func.c000066400000000000000000000102241355360272700263350ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "dram_sub_func.h" #include "rcar_def.h" #if RCAR_SYSTEM_SUSPEND /* Local defines */ #define DRAM_BACKUP_GPIO_USE 0 #include "iic_dvfs.h" #if PMIC_ROHM_BD9571 #define PMIC_SLAVE_ADDR 0x30U #define PMIC_BKUP_MODE_CNT 0x20U #define PMIC_QLLM_CNT 0x27U #define BIT_BKUP_CTRL_OUT BIT(4) #define BIT_QLLM_DDR0_EN BIT(0) #define BIT_QLLM_DDR1_EN BIT(1) #endif #define GPIO_BKUP_REQB_SHIFT_SALVATOR 9U /* GP1_9 (BKUP_REQB) */ #define GPIO_BKUP_TRG_SHIFT_SALVATOR 8U /* GP1_8 (BKUP_TRG) */ #define GPIO_BKUP_REQB_SHIFT_EBISU 14U /* GP6_14(BKUP_REQB) */ #define GPIO_BKUP_TRG_SHIFT_EBISU 13U /* GP6_13(BKUP_TRG) */ #define GPIO_BKUP_REQB_SHIFT_CONDOR 1U /* GP3_1 (BKUP_REQB) */ #define GPIO_BKUP_TRG_SHIFT_CONDOR 0U /* GP3_0 (BKUP_TRG) */ #define DRAM_BKUP_TRG_LOOP_CNT 1000U #endif void rcar_dram_get_boot_status(uint32_t *status) { #if RCAR_SYSTEM_SUSPEND uint32_t reg_data; uint32_t product; uint32_t shift; uint32_t gpio; product = mmio_read_32(PRR) & PRR_PRODUCT_MASK; if (product == PRR_PRODUCT_V3H) { shift = GPIO_BKUP_TRG_SHIFT_CONDOR; gpio = GPIO_INDT3; } else if (product == PRR_PRODUCT_E3) { shift = GPIO_BKUP_TRG_SHIFT_EBISU; gpio = GPIO_INDT6; } else { shift = GPIO_BKUP_TRG_SHIFT_SALVATOR; gpio = GPIO_INDT1; } reg_data = mmio_read_32(gpio); if (reg_data & BIT(shift)) *status = DRAM_BOOT_STATUS_WARM; else *status = DRAM_BOOT_STATUS_COLD; #else /* RCAR_SYSTEM_SUSPEND */ *status = DRAM_BOOT_STATUS_COLD; #endif /* RCAR_SYSTEM_SUSPEND */ } int32_t rcar_dram_update_boot_status(uint32_t status) { int32_t ret = 0; #if RCAR_SYSTEM_SUSPEND uint32_t reg_data; #if PMIC_ROHM_BD9571 #if DRAM_BACKUP_GPIO_USE == 0 uint8_t bkup_mode_cnt = 0U; #else uint32_t reqb, outd; #endif uint8_t qllm_cnt = 0U; int32_t i2c_dvfs_ret = -1; #endif uint32_t loop_count; uint32_t product; uint32_t trg; uint32_t gpio; product = mmio_read_32(PRR) & PRR_PRODUCT_MASK; if (product == PRR_PRODUCT_V3H) { #if DRAM_BACKUP_GPIO_USE == 1 reqb = GPIO_BKUP_REQB_SHIFT_CONDOR; outd = GPIO_OUTDT3; #endif trg = GPIO_BKUP_TRG_SHIFT_CONDOR; gpio = GPIO_INDT3; } else if (product == PRR_PRODUCT_E3) { #if DRAM_BACKUP_GPIO_USE == 1 reqb = GPIO_BKUP_REQB_SHIFT_EBISU; outd = GPIO_OUTDT6; #endif trg = GPIO_BKUP_TRG_SHIFT_EBISU; gpio = GPIO_INDT6; } else { #if DRAM_BACKUP_GPIO_USE == 1 reqb = GPIO_BKUP_REQB_SHIFT_SALVATOR; outd = GPIO_OUTDT1; #endif trg = GPIO_BKUP_TRG_SHIFT_SALVATOR; gpio = GPIO_INDT1; } if (status == DRAM_BOOT_STATUS_WARM) { #if DRAM_BACKUP_GPIO_USE == 1 mmio_setbits_32(outd, BIT(reqb)); #else #if PMIC_ROHM_BD9571 /* Set BKUP_CRTL_OUT=High (BKUP mode cnt register) */ i2c_dvfs_ret = rcar_iic_dvfs_receive(PMIC_SLAVE_ADDR, PMIC_BKUP_MODE_CNT, &bkup_mode_cnt); if (i2c_dvfs_ret) { ERROR("BKUP mode cnt READ ERROR.\n"); ret = DRAM_UPDATE_STATUS_ERR; } else { bkup_mode_cnt &= (uint8_t)~BIT_BKUP_CTRL_OUT; i2c_dvfs_ret = rcar_iic_dvfs_send(PMIC_SLAVE_ADDR, PMIC_BKUP_MODE_CNT, bkup_mode_cnt); if (i2c_dvfs_ret) { ERROR("BKUP mode cnt WRITE ERROR. value = %d\n", bkup_mode_cnt); ret = DRAM_UPDATE_STATUS_ERR; } } #endif /* PMIC_ROHM_BD9571 */ #endif /* DRAM_BACKUP_GPIO_USE == 1 */ /* Wait BKUP_TRG=Low */ loop_count = DRAM_BKUP_TRG_LOOP_CNT; while (loop_count > 0) { reg_data = mmio_read_32(gpio); if (!(reg_data & BIT(trg))) break; loop_count--; } if (!loop_count) { ERROR("\nWarm booting...\n" " The potential of BKUP_TRG did not switch to Low.\n" " If you expect the operation of cold boot,\n" " check the board configuration (ex, Dip-SW) and/or the H/W failure.\n"); ret = DRAM_UPDATE_STATUS_ERR; } } #if PMIC_ROHM_BD9571 if (!ret) { qllm_cnt = BIT_QLLM_DDR0_EN | BIT_QLLM_DDR1_EN; i2c_dvfs_ret = rcar_iic_dvfs_send(PMIC_SLAVE_ADDR, PMIC_QLLM_CNT, qllm_cnt); if (i2c_dvfs_ret) { ERROR("QLLM cnt WRITE ERROR. value = %d\n", qllm_cnt); ret = DRAM_UPDATE_STATUS_ERR; } } #endif #endif return ret; } trusted-firmware-a-2.2/drivers/staging/renesas/rcar/ddr/dram_sub_func.h000066400000000000000000000006411355360272700263440ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef DRAM_SUB_FUNC_H #define DRAM_SUB_FUNC_H #define DRAM_UPDATE_STATUS_ERR -1 #define DRAM_BOOT_STATUS_COLD 0 #define DRAM_BOOT_STATUS_WARM 1 int32_t rcar_dram_update_boot_status(uint32_t status); void rcar_dram_get_boot_status(uint32_t *status); #endif /* DRAM_SUB_FUNC_H */ trusted-firmware-a-2.2/drivers/synopsys/000077500000000000000000000000001355360272700204765ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/synopsys/emmc/000077500000000000000000000000001355360272700214175ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/synopsys/emmc/dw_mmc.c000066400000000000000000000254711355360272700230420ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #define DWMMC_CTRL (0x00) #define CTRL_IDMAC_EN (1 << 25) #define CTRL_DMA_EN (1 << 5) #define CTRL_INT_EN (1 << 4) #define CTRL_DMA_RESET (1 << 2) #define CTRL_FIFO_RESET (1 << 1) #define CTRL_RESET (1 << 0) #define CTRL_RESET_ALL (CTRL_DMA_RESET | CTRL_FIFO_RESET | \ CTRL_RESET) #define DWMMC_PWREN (0x04) #define DWMMC_CLKDIV (0x08) #define DWMMC_CLKSRC (0x0c) #define DWMMC_CLKENA (0x10) #define DWMMC_TMOUT (0x14) #define DWMMC_CTYPE (0x18) #define CTYPE_8BIT (1 << 16) #define CTYPE_4BIT (1) #define CTYPE_1BIT (0) #define DWMMC_BLKSIZ (0x1c) #define DWMMC_BYTCNT (0x20) #define DWMMC_INTMASK (0x24) #define INT_EBE (1 << 15) #define INT_SBE (1 << 13) #define INT_HLE (1 << 12) #define INT_FRUN (1 << 11) #define INT_DRT (1 << 9) #define INT_RTO (1 << 8) #define INT_DCRC (1 << 7) #define INT_RCRC (1 << 6) #define INT_RXDR (1 << 5) #define INT_TXDR (1 << 4) #define INT_DTO (1 << 3) #define INT_CMD_DONE (1 << 2) #define INT_RE (1 << 1) #define DWMMC_CMDARG (0x28) #define DWMMC_CMD (0x2c) #define CMD_START (U(1) << 31) #define CMD_USE_HOLD_REG (1 << 29) /* 0 if SDR50/100 */ #define CMD_UPDATE_CLK_ONLY (1 << 21) #define CMD_SEND_INIT (1 << 15) #define CMD_STOP_ABORT_CMD (1 << 14) #define CMD_WAIT_PRVDATA_COMPLETE (1 << 13) #define CMD_WRITE (1 << 10) #define CMD_DATA_TRANS_EXPECT (1 << 9) #define CMD_CHECK_RESP_CRC (1 << 8) #define CMD_RESP_LEN (1 << 7) #define CMD_RESP_EXPECT (1 << 6) #define CMD(x) (x & 0x3f) #define DWMMC_RESP0 (0x30) #define DWMMC_RESP1 (0x34) #define DWMMC_RESP2 (0x38) #define DWMMC_RESP3 (0x3c) #define DWMMC_RINTSTS (0x44) #define DWMMC_STATUS (0x48) #define STATUS_DATA_BUSY (1 << 9) #define DWMMC_FIFOTH (0x4c) #define FIFOTH_TWMARK(x) (x & 0xfff) #define FIFOTH_RWMARK(x) ((x & 0x1ff) << 16) #define FIFOTH_DMA_BURST_SIZE(x) ((x & 0x7) << 28) #define DWMMC_DEBNCE (0x64) #define DWMMC_BMOD (0x80) #define BMOD_ENABLE (1 << 7) #define BMOD_FB (1 << 1) #define BMOD_SWRESET (1 << 0) #define DWMMC_DBADDR (0x88) #define DWMMC_IDSTS (0x8c) #define DWMMC_IDINTEN (0x90) #define DWMMC_CARDTHRCTL (0x100) #define CARDTHRCTL_RD_THR(x) ((x & 0xfff) << 16) #define CARDTHRCTL_RD_THR_EN (1 << 0) #define IDMAC_DES0_DIC (1 << 1) #define IDMAC_DES0_LD (1 << 2) #define IDMAC_DES0_FS (1 << 3) #define IDMAC_DES0_CH (1 << 4) #define IDMAC_DES0_ER (1 << 5) #define IDMAC_DES0_CES (1 << 30) #define IDMAC_DES0_OWN (U(1) << 31) #define IDMAC_DES1_BS1(x) ((x) & 0x1fff) #define IDMAC_DES2_BS2(x) (((x) & 0x1fff) << 13) #define DWMMC_DMA_MAX_BUFFER_SIZE (512 * 8) #define DWMMC_8BIT_MODE (1 << 6) #define DWMMC_ADDRESS_MASK U(0x0f) #define TIMEOUT 100000 struct dw_idmac_desc { unsigned int des0; unsigned int des1; unsigned int des2; unsigned int des3; }; static void dw_init(void); static int dw_send_cmd(struct mmc_cmd *cmd); static int dw_set_ios(unsigned int clk, unsigned int width); static int dw_prepare(int lba, uintptr_t buf, size_t size); static int dw_read(int lba, uintptr_t buf, size_t size); static int dw_write(int lba, uintptr_t buf, size_t size); static const struct mmc_ops dw_mmc_ops = { .init = dw_init, .send_cmd = dw_send_cmd, .set_ios = dw_set_ios, .prepare = dw_prepare, .read = dw_read, .write = dw_write, }; static dw_mmc_params_t dw_params; static void dw_update_clk(void) { unsigned int data; mmio_write_32(dw_params.reg_base + DWMMC_CMD, CMD_WAIT_PRVDATA_COMPLETE | CMD_UPDATE_CLK_ONLY | CMD_START); while (1) { data = mmio_read_32(dw_params.reg_base + DWMMC_CMD); if ((data & CMD_START) == 0) break; data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS); assert((data & INT_HLE) == 0); } } static void dw_set_clk(int clk) { unsigned int data; int div; assert(clk > 0); for (div = 1; div < 256; div++) { if ((dw_params.clk_rate / (2 * div)) <= clk) { break; } } assert(div < 256); /* wait until controller is idle */ do { data = mmio_read_32(dw_params.reg_base + DWMMC_STATUS); } while (data & STATUS_DATA_BUSY); /* disable clock before change clock rate */ mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 0); dw_update_clk(); mmio_write_32(dw_params.reg_base + DWMMC_CLKDIV, div); dw_update_clk(); /* enable clock */ mmio_write_32(dw_params.reg_base + DWMMC_CLKENA, 1); mmio_write_32(dw_params.reg_base + DWMMC_CLKSRC, 0); dw_update_clk(); } static void dw_init(void) { unsigned int data; uintptr_t base; assert((dw_params.reg_base & MMC_BLOCK_MASK) == 0); base = dw_params.reg_base; mmio_write_32(base + DWMMC_PWREN, 1); mmio_write_32(base + DWMMC_CTRL, CTRL_RESET_ALL); do { data = mmio_read_32(base + DWMMC_CTRL); } while (data); /* enable DMA in CTRL */ data = CTRL_INT_EN | CTRL_DMA_EN | CTRL_IDMAC_EN; mmio_write_32(base + DWMMC_CTRL, data); mmio_write_32(base + DWMMC_RINTSTS, ~0); mmio_write_32(base + DWMMC_INTMASK, 0); mmio_write_32(base + DWMMC_TMOUT, ~0); mmio_write_32(base + DWMMC_IDINTEN, ~0); mmio_write_32(base + DWMMC_BLKSIZ, MMC_BLOCK_SIZE); mmio_write_32(base + DWMMC_BYTCNT, 256 * 1024); mmio_write_32(base + DWMMC_DEBNCE, 0x00ffffff); mmio_write_32(base + DWMMC_BMOD, BMOD_SWRESET); do { data = mmio_read_32(base + DWMMC_BMOD); } while (data & BMOD_SWRESET); /* enable DMA in BMOD */ data |= BMOD_ENABLE | BMOD_FB; mmio_write_32(base + DWMMC_BMOD, data); udelay(100); dw_set_clk(MMC_BOOT_CLK_RATE); udelay(100); } static int dw_send_cmd(struct mmc_cmd *cmd) { unsigned int op, data, err_mask; uintptr_t base; int timeout; assert(cmd); base = dw_params.reg_base; switch (cmd->cmd_idx) { case 0: op = CMD_SEND_INIT; break; case 12: op = CMD_STOP_ABORT_CMD; break; case 13: op = CMD_WAIT_PRVDATA_COMPLETE; break; case 8: if (dw_params.mmc_dev_type == MMC_IS_EMMC) op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE; else op = CMD_WAIT_PRVDATA_COMPLETE; break; case 17: case 18: op = CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE; break; case 24: case 25: op = CMD_WRITE | CMD_DATA_TRANS_EXPECT | CMD_WAIT_PRVDATA_COMPLETE; break; case 51: op = CMD_DATA_TRANS_EXPECT; break; default: op = 0; break; } op |= CMD_USE_HOLD_REG | CMD_START; switch (cmd->resp_type) { case 0: break; case MMC_RESPONSE_R2: op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC | CMD_RESP_LEN; break; case MMC_RESPONSE_R3: op |= CMD_RESP_EXPECT; break; default: op |= CMD_RESP_EXPECT | CMD_CHECK_RESP_CRC; break; } timeout = TIMEOUT; do { data = mmio_read_32(base + DWMMC_STATUS); if (--timeout <= 0) panic(); } while (data & STATUS_DATA_BUSY); mmio_write_32(base + DWMMC_RINTSTS, ~0); mmio_write_32(base + DWMMC_CMDARG, cmd->cmd_arg); mmio_write_32(base + DWMMC_CMD, op | cmd->cmd_idx); err_mask = INT_EBE | INT_HLE | INT_RTO | INT_RCRC | INT_RE | INT_DCRC | INT_DRT | INT_SBE; timeout = TIMEOUT; do { udelay(500); data = mmio_read_32(base + DWMMC_RINTSTS); if (data & err_mask) return -EIO; if (data & INT_DTO) break; if (--timeout == 0) { ERROR("%s, RINTSTS:0x%x\n", __func__, data); panic(); } } while (!(data & INT_CMD_DONE)); if (op & CMD_RESP_EXPECT) { cmd->resp_data[0] = mmio_read_32(base + DWMMC_RESP0); if (op & CMD_RESP_LEN) { cmd->resp_data[1] = mmio_read_32(base + DWMMC_RESP1); cmd->resp_data[2] = mmio_read_32(base + DWMMC_RESP2); cmd->resp_data[3] = mmio_read_32(base + DWMMC_RESP3); } } return 0; } static int dw_set_ios(unsigned int clk, unsigned int width) { switch (width) { case MMC_BUS_WIDTH_1: mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_1BIT); break; case MMC_BUS_WIDTH_4: mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_4BIT); break; case MMC_BUS_WIDTH_8: mmio_write_32(dw_params.reg_base + DWMMC_CTYPE, CTYPE_8BIT); break; default: assert(0); break; } dw_set_clk(clk); return 0; } static int dw_prepare(int lba, uintptr_t buf, size_t size) { struct dw_idmac_desc *desc; int desc_cnt, i, last; uintptr_t base; assert(((buf & DWMMC_ADDRESS_MASK) == 0) && (dw_params.desc_size > 0) && ((dw_params.reg_base & MMC_BLOCK_MASK) == 0) && ((dw_params.desc_base & MMC_BLOCK_MASK) == 0) && ((dw_params.desc_size & MMC_BLOCK_MASK) == 0)); flush_dcache_range(buf, size); desc_cnt = (size + DWMMC_DMA_MAX_BUFFER_SIZE - 1) / DWMMC_DMA_MAX_BUFFER_SIZE; assert(desc_cnt * sizeof(struct dw_idmac_desc) < dw_params.desc_size); base = dw_params.reg_base; desc = (struct dw_idmac_desc *)dw_params.desc_base; mmio_write_32(base + DWMMC_BYTCNT, size); if (size < MMC_BLOCK_SIZE) mmio_write_32(base + DWMMC_BLKSIZ, size); else mmio_write_32(base + DWMMC_BLKSIZ, MMC_BLOCK_SIZE); mmio_write_32(base + DWMMC_RINTSTS, ~0); for (i = 0; i < desc_cnt; i++) { desc[i].des0 = IDMAC_DES0_OWN | IDMAC_DES0_CH | IDMAC_DES0_DIC; desc[i].des1 = IDMAC_DES1_BS1(DWMMC_DMA_MAX_BUFFER_SIZE); desc[i].des2 = buf + DWMMC_DMA_MAX_BUFFER_SIZE * i; desc[i].des3 = dw_params.desc_base + (sizeof(struct dw_idmac_desc)) * (i + 1); } /* first descriptor */ desc->des0 |= IDMAC_DES0_FS; /* last descriptor */ last = desc_cnt - 1; (desc + last)->des0 |= IDMAC_DES0_LD; (desc + last)->des0 &= ~(IDMAC_DES0_DIC | IDMAC_DES0_CH); (desc + last)->des1 = IDMAC_DES1_BS1(size - (last * DWMMC_DMA_MAX_BUFFER_SIZE)); /* set next descriptor address as 0 */ (desc + last)->des3 = 0; mmio_write_32(base + DWMMC_DBADDR, dw_params.desc_base); flush_dcache_range(dw_params.desc_base, desc_cnt * DWMMC_DMA_MAX_BUFFER_SIZE); return 0; } static int dw_read(int lba, uintptr_t buf, size_t size) { uint32_t data = 0; int timeout = TIMEOUT; do { data = mmio_read_32(dw_params.reg_base + DWMMC_RINTSTS); udelay(50); } while (!(data & INT_DTO) && timeout-- > 0); inv_dcache_range(buf, size); return 0; } static int dw_write(int lba, uintptr_t buf, size_t size) { return 0; } void dw_mmc_init(dw_mmc_params_t *params, struct mmc_device_info *info) { assert((params != 0) && ((params->reg_base & MMC_BLOCK_MASK) == 0) && ((params->desc_base & MMC_BLOCK_MASK) == 0) && ((params->desc_size & MMC_BLOCK_MASK) == 0) && (params->desc_size > 0) && (params->clk_rate > 0) && ((params->bus_width == MMC_BUS_WIDTH_1) || (params->bus_width == MMC_BUS_WIDTH_4) || (params->bus_width == MMC_BUS_WIDTH_8))); memcpy(&dw_params, params, sizeof(dw_mmc_params_t)); dw_params.mmc_dev_type = info->mmc_dev_type; mmc_init(&dw_mmc_ops, params->clk_rate, params->bus_width, params->flags, info); } trusted-firmware-a-2.2/drivers/synopsys/ufs/000077500000000000000000000000001355360272700212735ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/synopsys/ufs/dw_ufs.c000066400000000000000000000142531355360272700227330ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include static int dwufs_phy_init(ufs_params_t *params) { uintptr_t base; unsigned int fsm0, fsm1; unsigned int data; int result; assert((params != NULL) && (params->reg_base != 0)); base = params->reg_base; /* Unipro VS_MPHY disable */ ufshc_dme_set(VS_MPHY_DISABLE_OFFSET, 0, VS_MPHY_DISABLE_MPHYDIS); ufshc_dme_set(PA_HS_SERIES_OFFSET, 0, 2); /* MPHY CBRATESEL */ ufshc_dme_set(0x8114, 0, 1); /* MPHY CBOVRCTRL2 */ ufshc_dme_set(0x8121, 0, 0x2d); /* MPHY CBOVRCTRL3 */ ufshc_dme_set(0x8122, 0, 0x1); ufshc_dme_set(VS_MPHY_CFG_UPDT_OFFSET, 0, 1); /* MPHY RXOVRCTRL4 rx0 */ ufshc_dme_set(0x800d, 4, 0x58); /* MPHY RXOVRCTRL4 rx1 */ ufshc_dme_set(0x800d, 5, 0x58); /* MPHY RXOVRCTRL5 rx0 */ ufshc_dme_set(0x800e, 4, 0xb); /* MPHY RXOVRCTRL5 rx1 */ ufshc_dme_set(0x800e, 5, 0xb); /* MPHY RXSQCONTROL rx0 */ ufshc_dme_set(0x8009, 4, 0x1); /* MPHY RXSQCONTROL rx1 */ ufshc_dme_set(0x8009, 5, 0x1); ufshc_dme_set(VS_MPHY_CFG_UPDT_OFFSET, 0, 1); ufshc_dme_set(0x8113, 0, 0x1); ufshc_dme_set(VS_MPHY_CFG_UPDT_OFFSET, 0, 1); ufshc_dme_set(RX_HS_G3_SYNC_LENGTH_CAP_OFFSET, 4, 0x4a); ufshc_dme_set(RX_HS_G3_SYNC_LENGTH_CAP_OFFSET, 5, 0x4a); ufshc_dme_set(RX_HS_G2_SYNC_LENGTH_CAP_OFFSET, 4, 0x4a); ufshc_dme_set(RX_HS_G2_SYNC_LENGTH_CAP_OFFSET, 5, 0x4a); ufshc_dme_set(RX_MIN_ACTIVATETIME_CAP_OFFSET, 4, 0x7); ufshc_dme_set(RX_MIN_ACTIVATETIME_CAP_OFFSET, 5, 0x7); ufshc_dme_set(TX_HIBERN8TIME_CAP_OFFSET, 0, 0x5); ufshc_dme_set(TX_HIBERN8TIME_CAP_OFFSET, 1, 0x5); ufshc_dme_set(VS_MPHY_CFG_UPDT_OFFSET, 0, 1); result = ufshc_dme_get(VS_MPHY_DISABLE_OFFSET, 0, &data); assert((result == 0) && (data == VS_MPHY_DISABLE_MPHYDIS)); /* enable Unipro VS MPHY */ ufshc_dme_set(VS_MPHY_DISABLE_OFFSET, 0, 0); while (1) { result = ufshc_dme_get(TX_FSM_STATE_OFFSET, 0, &fsm0); assert(result == 0); result = ufshc_dme_get(TX_FSM_STATE_OFFSET, 1, &fsm1); assert(result == 0); if ((fsm0 == TX_FSM_STATE_HIBERN8) && (fsm1 == TX_FSM_STATE_HIBERN8)) break; } mmio_write_32(base + HCLKDIV, 0xE4); mmio_clrbits_32(base + AHIT, 0x3FF); ufshc_dme_set(PA_LOCAL_TX_LCC_ENABLE_OFFSET, 0, 0); ufshc_dme_set(VS_MK2_EXTN_SUPPORT_OFFSET, 0, 0); result = ufshc_dme_get(VS_MK2_EXTN_SUPPORT_OFFSET, 0, &data); assert((result == 0) && (data == 0)); ufshc_dme_set(DL_AFC0_CREDIT_THRESHOLD_OFFSET, 0, 0); ufshc_dme_set(DL_TC0_OUT_ACK_THRESHOLD_OFFSET, 0, 0); ufshc_dme_set(DL_TC0_TX_FC_THRESHOLD_OFFSET, 0, 9); (void)result; return 0; } static int dwufs_phy_set_pwr_mode(ufs_params_t *params) { int result; unsigned int data, tx_lanes, rx_lanes; uintptr_t base; unsigned int flags; assert((params != NULL) && (params->reg_base != 0)); base = params->reg_base; flags = params->flags; if ((flags & UFS_FLAGS_VENDOR_SKHYNIX) != 0U) { NOTICE("ufs: H**** device must set VS_DebugSaveConfigTime 0x10\n"); /* VS_DebugSaveConfigTime */ result = ufshc_dme_set(0xd0a0, 0x0, 0x10); assert(result == 0); /* sync length */ result = ufshc_dme_set(0x1556, 0x0, 0x48); assert(result == 0); } result = ufshc_dme_get(PA_TACTIVATE_OFFSET, 0, &data); assert(result == 0); if (data < 7) { result = ufshc_dme_set(PA_TACTIVATE_OFFSET, 0, 7); assert(result == 0); } result = ufshc_dme_get(PA_CONNECTED_TX_DATA_LANES_OFFSET, 0, &tx_lanes); assert(result == 0); result = ufshc_dme_get(PA_CONNECTED_RX_DATA_LANES_OFFSET, 0, &rx_lanes); assert(result == 0); result = ufshc_dme_set(PA_TX_SKIP_OFFSET, 0, 0); assert(result == 0); result = ufshc_dme_set(PA_TX_GEAR_OFFSET, 0, 3); assert(result == 0); result = ufshc_dme_set(PA_RX_GEAR_OFFSET, 0, 3); assert(result == 0); result = ufshc_dme_set(PA_HS_SERIES_OFFSET, 0, 2); assert(result == 0); result = ufshc_dme_set(PA_TX_TERMINATION_OFFSET, 0, 1); assert(result == 0); result = ufshc_dme_set(PA_RX_TERMINATION_OFFSET, 0, 1); assert(result == 0); result = ufshc_dme_set(PA_SCRAMBLING_OFFSET, 0, 0); assert(result == 0); result = ufshc_dme_set(PA_ACTIVE_TX_DATA_LANES_OFFSET, 0, tx_lanes); assert(result == 0); result = ufshc_dme_set(PA_ACTIVE_RX_DATA_LANES_OFFSET, 0, rx_lanes); assert(result == 0); result = ufshc_dme_set(PA_PWR_MODE_USER_DATA0_OFFSET, 0, 8191); assert(result == 0); result = ufshc_dme_set(PA_PWR_MODE_USER_DATA1_OFFSET, 0, 65535); assert(result == 0); result = ufshc_dme_set(PA_PWR_MODE_USER_DATA2_OFFSET, 0, 32767); assert(result == 0); result = ufshc_dme_set(DME_FC0_PROTECTION_TIMEOUT_OFFSET, 0, 8191); assert(result == 0); result = ufshc_dme_set(DME_TC0_REPLAY_TIMEOUT_OFFSET, 0, 65535); assert(result == 0); result = ufshc_dme_set(DME_AFC0_REQ_TIMEOUT_OFFSET, 0, 32767); assert(result == 0); result = ufshc_dme_set(PA_PWR_MODE_USER_DATA3_OFFSET, 0, 8191); assert(result == 0); result = ufshc_dme_set(PA_PWR_MODE_USER_DATA4_OFFSET, 0, 65535); assert(result == 0); result = ufshc_dme_set(PA_PWR_MODE_USER_DATA5_OFFSET, 0, 32767); assert(result == 0); result = ufshc_dme_set(DME_FC1_PROTECTION_TIMEOUT_OFFSET, 0, 8191); assert(result == 0); result = ufshc_dme_set(DME_TC1_REPLAY_TIMEOUT_OFFSET, 0, 65535); assert(result == 0); result = ufshc_dme_set(DME_AFC1_REQ_TIMEOUT_OFFSET, 0, 32767); assert(result == 0); result = ufshc_dme_set(PA_PWR_MODE_OFFSET, 0, 0x11); assert(result == 0); do { data = mmio_read_32(base + IS); } while ((data & UFS_INT_UPMS) == 0); mmio_write_32(base + IS, UFS_INT_UPMS); data = mmio_read_32(base + HCS); if ((data & HCS_UPMCRS_MASK) == HCS_PWR_LOCAL) INFO("ufs: change power mode success\n"); else WARN("ufs: HCS.UPMCRS error, HCS:0x%x\n", data); (void)result; return 0; } static const ufs_ops_t dw_ufs_ops = { .phy_init = dwufs_phy_init, .phy_set_pwr_mode = dwufs_phy_set_pwr_mode, }; int dw_ufs_init(dw_ufs_params_t *params) { ufs_params_t ufs_params; memset(&ufs_params, 0, sizeof(ufs_params)); ufs_params.reg_base = params->reg_base; ufs_params.desc_base = params->desc_base; ufs_params.desc_size = params->desc_size; ufs_params.flags = params->flags; ufs_init(&dw_ufs_ops, &ufs_params); return 0; } trusted-firmware-a-2.2/drivers/ti/000077500000000000000000000000001355360272700172035ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/ti/uart/000077500000000000000000000000001355360272700201565ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/ti/uart/aarch32/000077500000000000000000000000001355360272700214015ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/ti/uart/aarch32/16550_console.S000066400000000000000000000166161355360272700237410ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* * "core" functions are low-level implementations that don't require * writable memory and are thus safe to call in BL1 crash context. */ .globl console_16550_core_init .globl console_16550_core_putc .globl console_16550_core_getc .globl console_16550_core_flush .globl console_16550_putc .globl console_16550_getc .globl console_16550_flush /* ----------------------------------------------- * int console_16550_core_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. This * function will be accessed by console_init and * crash reporting. * In: r0 - console base address * r1 - Uart clock in Hz * r2 - Baud rate * Out: return 1 on success, 0 on error * Clobber list : r1, r2, r3 * ----------------------------------------------- */ func console_16550_core_init /* Check the input base address */ cmp r0, #0 beq init_fail /* Check baud rate and uart clock for sanity */ cmp r1, #0 beq init_fail cmp r2, #0 beq init_fail /* Program the baudrate */ /* Divisor = Uart clock / (16 * baudrate) */ lsl r2, r2, #4 udiv r2, r1, r2 and r1, r2, #0xff /* w1 = DLL */ lsr r2, r2, #8 and r2, r2, #0xff /* w2 = DLLM */ ldr r3, [r0, #UARTLCR] orr r3, r3, #UARTLCR_DLAB str r3, [r0, #UARTLCR] /* enable DLL, DLLM programming */ str r1, [r0, #UARTDLL] /* program DLL */ str r2, [r0, #UARTDLLM] /* program DLLM */ mov r2, #~UARTLCR_DLAB and r3, r3, r2 str r3, [r0, #UARTLCR] /* disable DLL, DLLM programming */ /* 8n1 */ mov r3, #3 str r3, [r0, #UARTLCR] /* no interrupt */ mov r3, #0 str r3, [r0, #UARTIER] #ifdef TI_16550_MDR_QUIRK /* UART must be enabled on some platforms via the MDR register */ str r3, [r0, #UARTMDR1] #endif /* TI_16550_MDR_QUIRK */ /* enable fifo, DMA */ mov r3, #(UARTFCR_FIFOEN | UARTFCR_DMAEN) str r3, [r0, #UARTFCR] /* DTR + RTS */ mov r3, #3 str r3, [r0, #UARTMCR] mov r0, #1 bx lr init_fail: mov r0, #0 bx lr endfunc console_16550_core_init .globl console_16550_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_16550_register push {r4, lr} mov r4, r3 cmp r4, #0 beq register_fail str r0, [r4, #CONSOLE_T_16550_BASE] bl console_16550_core_init cmp r0, #0 beq register_fail mov r0, r4 pop {r4, lr} finish_console_register 16550 putc=1, getc=1, flush=1 register_fail: pop {r4, pc} endfunc console_16550_register /* -------------------------------------------------------- * int console_16550_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. * In : r0 - character to be printed * r1 - console base address * Out : return -1 on error else return character. * Clobber list : r2 * -------------------------------------------------------- */ func console_16550_core_putc #if ENABLE_ASSERTIONS cmp r1, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ /* Prepend '\r' to '\n' */ cmp r0, #0xA bne 2f /* Check if the transmit FIFO is full */ 1: ldr r2, [r1, #UARTLSR] and r2, r2, #(UARTLSR_TEMT | UARTLSR_THRE) cmp r2, #(UARTLSR_TEMT | UARTLSR_THRE) bne 1b mov r2, #0xD /* '\r' */ str r2, [r1, #UARTTX] /* Check if the transmit FIFO is full */ 2: ldr r2, [r1, #UARTLSR] and r2, r2, #(UARTLSR_TEMT | UARTLSR_THRE) cmp r2, #(UARTLSR_TEMT | UARTLSR_THRE) bne 2b str r0, [r1, #UARTTX] bx lr endfunc console_16550_core_putc /* -------------------------------------------------------- * int console_16550_putc(int c, console_16550_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_16550_putc #if ENABLE_ASSERTIONS cmp r1, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr r1, [r1, #CONSOLE_T_16550_BASE] b console_16550_core_putc endfunc console_16550_putc /* --------------------------------------------- * int console_16550_core_getc(uintptr_t base_addr) * Function to get a character from the console. * It returns the character grabbed on success * or -1 on if no character is available. * In : r0 - console base address * Clobber list : r0, r1 * --------------------------------------------- */ func console_16550_core_getc #if ENABLE_ASSERTIONS cmp r0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ /* Check if the receive FIFO is empty */ 1: ldr r1, [r0, #UARTLSR] tst r1, #UARTLSR_RDR_BIT beq no_char ldr r1, [r0, #UARTRX] mov r0, r1 bx lr no_char: mov r0, #ERROR_NO_PENDING_CHAR bx lr endfunc console_16550_core_getc /* --------------------------------------------- * int console_16550_getc(console_16550_t *console) * Function to get a character from the console. * It returns the character grabbed on success * or -1 on if no character is available. * In : r0 - pointer to console_t stucture * Out : r0 - character if available, else -1 * Clobber list : r0, r1 * --------------------------------------------- */ func console_16550_getc #if ENABLE_ASSERTIONS cmp r0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr r0, [r0, #CONSOLE_T_16550_BASE] b console_16550_core_getc endfunc console_16550_getc /* --------------------------------------------- * int console_16550_core_flush(uintptr_t base_addr) * Function to force a write of all buffered * data that hasn't been output. * In : r0 - console base address * Out : return -1 on error else return 0. * Clobber list : r0, r1 * --------------------------------------------- */ func console_16550_core_flush #if ENABLE_ASSERTIONS cmp r0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ /* Loop until the transmit FIFO is empty */ 1: ldr r1, [r0, #UARTLSR] and r1, r1, #(UARTLSR_TEMT | UARTLSR_THRE) cmp r1, #(UARTLSR_TEMT | UARTLSR_THRE) bne 1b mov r0, #0 bx lr endfunc console_16550_core_flush /* --------------------------------------------- * int console_16550_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_16550_flush #if ENABLE_ASSERTIONS cmp r0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr r0, [r0, #CONSOLE_T_16550_BASE] b console_16550_core_flush endfunc console_16550_flush trusted-firmware-a-2.2/drivers/ti/uart/aarch64/000077500000000000000000000000001355360272700214065ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/ti/uart/aarch64/16550_console.S000066400000000000000000000165561355360272700237510ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* * "core" functions are low-level implementations that don't require * writable memory and are thus safe to call in BL1 crash context. */ .globl console_16550_core_init .globl console_16550_core_putc .globl console_16550_core_getc .globl console_16550_core_flush .globl console_16550_putc .globl console_16550_getc .globl console_16550_flush /* ----------------------------------------------- * int console_16550_core_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. This * function will be accessed by console_init and * crash reporting. * In: x0 - console base address * w1 - Uart clock in Hz * w2 - Baud rate * Out: return 1 on success, 0 on error * Clobber list : x1, x2, x3 * ----------------------------------------------- */ func console_16550_core_init /* Check the input base address */ cbz x0, init_fail /* Check baud rate and uart clock for sanity */ cbz w1, init_fail cbz w2, init_fail /* Program the baudrate */ /* Divisor = Uart clock / (16 * baudrate) */ lsl w2, w2, #4 udiv w2, w1, w2 and w1, w2, #0xff /* w1 = DLL */ lsr w2, w2, #8 and w2, w2, #0xff /* w2 = DLLM */ ldr w3, [x0, #UARTLCR] orr w3, w3, #UARTLCR_DLAB str w3, [x0, #UARTLCR] /* enable DLL, DLLM programming */ str w1, [x0, #UARTDLL] /* program DLL */ str w2, [x0, #UARTDLLM] /* program DLLM */ mov w2, #~UARTLCR_DLAB and w3, w3, w2 str w3, [x0, #UARTLCR] /* disable DLL, DLLM programming */ /* 8n1 */ mov w3, #3 str w3, [x0, #UARTLCR] /* no interrupt */ mov w3, #0 str w3, [x0, #UARTIER] #ifdef TI_16550_MDR_QUIRK /* UART must be enabled on some platforms via the MDR register */ str w3, [x0, #UARTMDR1] #endif /* TI_16550_MDR_QUIRK */ /* enable fifo, DMA */ mov w3, #(UARTFCR_FIFOEN | UARTFCR_DMAEN) str w3, [x0, #UARTFCR] /* DTR + RTS */ mov w3, #3 str w3, [x0, #UARTMCR] mov w0, #1 ret init_fail: mov w0, #0 ret endfunc console_16550_core_init .globl console_16550_register /* ----------------------------------------------- * int console_16550_register(uintptr_t baseaddr, * uint32_t clock, uint32_t baud, * console_16550_t *console); * Function to initialize and register a new 16550 * console. Storage passed in for the console struct * *must* be persistent (i.e. not from the stack). * In: x0 - UART register base address * w1 - UART clock in Hz * w2 - Baud rate * x3 - pointer to empty console_16550_t struct * Out: return 1 on success, 0 on error * Clobber list : x0, x1, x2, x6, x7, x14 * ----------------------------------------------- */ func console_16550_register mov x7, x30 mov x6, x3 cbz x6, register_fail str x0, [x6, #CONSOLE_T_16550_BASE] bl console_16550_core_init cbz x0, register_fail mov x0, x6 mov x30, x7 finish_console_register 16550 putc=1, getc=1, flush=1 register_fail: ret x7 endfunc console_16550_register /* -------------------------------------------------------- * int console_16550_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. * In : w0 - character to be printed * x1 - console base address * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_16550_core_putc #if ENABLE_ASSERTIONS cmp x1, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ /* Prepend '\r' to '\n' */ cmp w0, #0xA b.ne 2f /* Check if the transmit FIFO is full */ 1: ldr w2, [x1, #UARTLSR] and w2, w2, #(UARTLSR_TEMT | UARTLSR_THRE) cmp w2, #(UARTLSR_TEMT | UARTLSR_THRE) b.ne 1b mov w2, #0xD /* '\r' */ str w2, [x1, #UARTTX] /* Check if the transmit FIFO is full */ 2: ldr w2, [x1, #UARTLSR] and w2, w2, #(UARTLSR_TEMT | UARTLSR_THRE) cmp w2, #(UARTLSR_TEMT | UARTLSR_THRE) b.ne 2b str w0, [x1, #UARTTX] ret endfunc console_16550_core_putc /* -------------------------------------------------------- * int console_16550_putc(int c, console_16550_t *console) * Function to output a character over the console. It * returns the character printed on success or -1 on error. * In : w0 - character to be printed * x1 - pointer to console_t structure * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_16550_putc #if ENABLE_ASSERTIONS cmp x1, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr x1, [x1, #CONSOLE_T_16550_BASE] b console_16550_core_putc endfunc console_16550_putc /* --------------------------------------------- * int console_16550_core_getc(uintptr_t base_addr) * Function to get a character from the console. * It returns the character grabbed on success * or -1 on if no character is available. * In : x0 - console base address * Out : w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ func console_16550_core_getc #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ /* Check if the receive FIFO is empty */ 1: ldr w1, [x0, #UARTLSR] tbz w1, #UARTLSR_RDR_BIT, no_char ldr w0, [x0, #UARTRX] ret no_char: mov w0, #ERROR_NO_PENDING_CHAR ret endfunc console_16550_core_getc /* --------------------------------------------- * int console_16550_getc(console_16550_t *console) * Function to get a character from the console. * It returns the character grabbed on success * or -1 on if no character is available. * In : x0 - pointer to console_t stucture * Out : w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ func console_16550_getc #if ENABLE_ASSERTIONS cmp x1, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr x0, [x0, #CONSOLE_T_16550_BASE] b console_16550_core_getc endfunc console_16550_getc /* --------------------------------------------- * int console_16550_core_flush(uintptr_t base_addr) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - console base address * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func console_16550_core_flush #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ /* Loop until the transmit FIFO is empty */ 1: ldr w1, [x0, #UARTLSR] and w1, w1, #(UARTLSR_TEMT | UARTLSR_THRE) cmp w1, #(UARTLSR_TEMT | UARTLSR_THRE) b.ne 1b mov w0, #0 ret endfunc console_16550_core_flush /* --------------------------------------------- * int console_16550_flush(console_pl011_t *console) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - pointer to console_t structure * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func console_16550_flush #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr x0, [x0, #CONSOLE_T_16550_BASE] b console_16550_core_flush endfunc console_16550_flush trusted-firmware-a-2.2/drivers/ufs/000077500000000000000000000000001355360272700173645ustar00rootroot00000000000000trusted-firmware-a-2.2/drivers/ufs/ufs.c000066400000000000000000000472321355360272700203350ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #define CDB_ADDR_MASK 127 #define ALIGN_CDB(x) (((x) + CDB_ADDR_MASK) & ~CDB_ADDR_MASK) #define ALIGN_8(x) (((x) + 7) & ~7) #define UFS_DESC_SIZE 0x400 #define MAX_UFS_DESC_SIZE 0x8000 /* 32 descriptors */ #define MAX_PRDT_SIZE 0x40000 /* 256KB */ static ufs_params_t ufs_params; static int nutrs; /* Number of UTP Transfer Request Slots */ int ufshc_send_uic_cmd(uintptr_t base, uic_cmd_t *cmd) { unsigned int data; data = mmio_read_32(base + HCS); if ((data & HCS_UCRDY) == 0) return -EBUSY; mmio_write_32(base + IS, ~0); mmio_write_32(base + UCMDARG1, cmd->arg1); mmio_write_32(base + UCMDARG2, cmd->arg2); mmio_write_32(base + UCMDARG3, cmd->arg3); mmio_write_32(base + UICCMD, cmd->op); do { data = mmio_read_32(base + IS); } while ((data & UFS_INT_UCCS) == 0); mmio_write_32(base + IS, UFS_INT_UCCS); return mmio_read_32(base + UCMDARG2) & CONFIG_RESULT_CODE_MASK; } int ufshc_dme_get(unsigned int attr, unsigned int idx, unsigned int *val) { uintptr_t base; unsigned int data; int retries; assert((ufs_params.reg_base != 0) && (val != NULL)); base = ufs_params.reg_base; for (retries = 0; retries < 100; retries++) { data = mmio_read_32(base + HCS); if ((data & HCS_UCRDY) != 0) break; mdelay(1); } if (retries >= 100) return -EBUSY; mmio_write_32(base + IS, ~0); mmio_write_32(base + UCMDARG1, (attr << 16) | GEN_SELECTOR_IDX(idx)); mmio_write_32(base + UCMDARG2, 0); mmio_write_32(base + UCMDARG3, 0); mmio_write_32(base + UICCMD, DME_GET); do { data = mmio_read_32(base + IS); if (data & UFS_INT_UE) return -EINVAL; } while ((data & UFS_INT_UCCS) == 0); mmio_write_32(base + IS, UFS_INT_UCCS); data = mmio_read_32(base + UCMDARG2) & CONFIG_RESULT_CODE_MASK; assert(data == 0); *val = mmio_read_32(base + UCMDARG3); return 0; } int ufshc_dme_set(unsigned int attr, unsigned int idx, unsigned int val) { uintptr_t base; unsigned int data; assert((ufs_params.reg_base != 0)); base = ufs_params.reg_base; data = mmio_read_32(base + HCS); if ((data & HCS_UCRDY) == 0) return -EBUSY; mmio_write_32(base + IS, ~0); mmio_write_32(base + UCMDARG1, (attr << 16) | GEN_SELECTOR_IDX(idx)); mmio_write_32(base + UCMDARG2, 0); mmio_write_32(base + UCMDARG3, val); mmio_write_32(base + UICCMD, DME_SET); do { data = mmio_read_32(base + IS); if (data & UFS_INT_UE) return -EINVAL; } while ((data & UFS_INT_UCCS) == 0); mmio_write_32(base + IS, UFS_INT_UCCS); data = mmio_read_32(base + UCMDARG2) & CONFIG_RESULT_CODE_MASK; assert(data == 0); return 0; } static void ufshc_reset(uintptr_t base) { unsigned int data; /* Enable Host Controller */ mmio_write_32(base + HCE, HCE_ENABLE); /* Wait until basic initialization sequence completed */ do { data = mmio_read_32(base + HCE); } while ((data & HCE_ENABLE) == 0); /* Enable Interrupts */ data = UFS_INT_UCCS | UFS_INT_ULSS | UFS_INT_UE | UFS_INT_UTPES | UFS_INT_DFES | UFS_INT_HCFES | UFS_INT_SBFES; mmio_write_32(base + IE, data); } static int ufshc_link_startup(uintptr_t base) { uic_cmd_t cmd; int data, result; int retries; for (retries = 10; retries > 0; retries--) { memset(&cmd, 0, sizeof(cmd)); cmd.op = DME_LINKSTARTUP; result = ufshc_send_uic_cmd(base, &cmd); if (result != 0) continue; while ((mmio_read_32(base + HCS) & HCS_DP) == 0) ; data = mmio_read_32(base + IS); if (data & UFS_INT_ULSS) mmio_write_32(base + IS, UFS_INT_ULSS); return 0; } return -EIO; } /* Check Door Bell register to get an empty slot */ static int get_empty_slot(int *slot) { unsigned int data; int i; data = mmio_read_32(ufs_params.reg_base + UTRLDBR); for (i = 0; i < nutrs; i++) { if ((data & 1) == 0) break; data = data >> 1; } if (i >= nutrs) return -EBUSY; *slot = i; return 0; } static void get_utrd(utp_utrd_t *utrd) { uintptr_t base; int slot = 0, result; utrd_header_t *hd; assert(utrd != NULL); result = get_empty_slot(&slot); assert(result == 0); /* clear utrd */ memset((void *)utrd, 0, sizeof(utp_utrd_t)); base = ufs_params.desc_base + (slot * UFS_DESC_SIZE); /* clear the descriptor */ memset((void *)base, 0, UFS_DESC_SIZE); utrd->header = base; utrd->task_tag = slot + 1; /* CDB address should be aligned with 128 bytes */ utrd->upiu = ALIGN_CDB(utrd->header + sizeof(utrd_header_t)); utrd->resp_upiu = ALIGN_8(utrd->upiu + sizeof(cmd_upiu_t)); utrd->size_upiu = utrd->resp_upiu - utrd->upiu; utrd->size_resp_upiu = ALIGN_8(sizeof(resp_upiu_t)); utrd->prdt = utrd->resp_upiu + utrd->size_resp_upiu; hd = (utrd_header_t *)utrd->header; hd->ucdba = utrd->upiu & UINT32_MAX; hd->ucdbau = (utrd->upiu >> 32) & UINT32_MAX; /* Both RUL and RUO is based on DWORD */ hd->rul = utrd->size_resp_upiu >> 2; hd->ruo = utrd->size_upiu >> 2; (void)result; } /* * Prepare UTRD, Command UPIU, Response UPIU. */ static int ufs_prepare_cmd(utp_utrd_t *utrd, uint8_t op, uint8_t lun, int lba, uintptr_t buf, size_t length) { utrd_header_t *hd; cmd_upiu_t *upiu; prdt_t *prdt; unsigned int ulba; unsigned int lba_cnt; int prdt_size; mmio_write_32(ufs_params.reg_base + UTRLBA, utrd->header & UINT32_MAX); mmio_write_32(ufs_params.reg_base + UTRLBAU, (utrd->upiu >> 32) & UINT32_MAX); hd = (utrd_header_t *)utrd->header; upiu = (cmd_upiu_t *)utrd->upiu; hd->i = 1; hd->ct = CT_UFS_STORAGE; hd->ocs = OCS_MASK; upiu->trans_type = CMD_UPIU; upiu->task_tag = utrd->task_tag; upiu->cdb[0] = op; ulba = (unsigned int)lba; lba_cnt = (unsigned int)(length >> UFS_BLOCK_SHIFT); switch (op) { case CDBCMD_TEST_UNIT_READY: break; case CDBCMD_READ_CAPACITY_10: hd->dd = DD_OUT; upiu->flags = UPIU_FLAGS_R | UPIU_FLAGS_ATTR_S; upiu->lun = lun; break; case CDBCMD_READ_10: hd->dd = DD_OUT; upiu->flags = UPIU_FLAGS_R | UPIU_FLAGS_ATTR_S; upiu->lun = lun; upiu->cdb[1] = RW_WITHOUT_CACHE; /* set logical block address */ upiu->cdb[2] = (ulba >> 24) & 0xff; upiu->cdb[3] = (ulba >> 16) & 0xff; upiu->cdb[4] = (ulba >> 8) & 0xff; upiu->cdb[5] = ulba & 0xff; /* set transfer length */ upiu->cdb[7] = (lba_cnt >> 8) & 0xff; upiu->cdb[8] = lba_cnt & 0xff; break; case CDBCMD_WRITE_10: hd->dd = DD_IN; upiu->flags = UPIU_FLAGS_W | UPIU_FLAGS_ATTR_S; upiu->lun = lun; upiu->cdb[1] = RW_WITHOUT_CACHE; /* set logical block address */ upiu->cdb[2] = (ulba >> 24) & 0xff; upiu->cdb[3] = (ulba >> 16) & 0xff; upiu->cdb[4] = (ulba >> 8) & 0xff; upiu->cdb[5] = ulba & 0xff; /* set transfer length */ upiu->cdb[7] = (lba_cnt >> 8) & 0xff; upiu->cdb[8] = lba_cnt & 0xff; break; default: assert(0); break; } if (hd->dd == DD_IN) flush_dcache_range(buf, length); else if (hd->dd == DD_OUT) inv_dcache_range(buf, length); if (length) { upiu->exp_data_trans_len = htobe32(length); assert(lba_cnt <= UINT16_MAX); prdt = (prdt_t *)utrd->prdt; prdt_size = 0; while (length > 0) { prdt->dba = (unsigned int)(buf & UINT32_MAX); prdt->dbau = (unsigned int)((buf >> 32) & UINT32_MAX); /* prdt->dbc counts from 0 */ if (length > MAX_PRDT_SIZE) { prdt->dbc = MAX_PRDT_SIZE - 1; length = length - MAX_PRDT_SIZE; } else { prdt->dbc = length - 1; length = 0; } buf += MAX_PRDT_SIZE; prdt++; prdt_size += sizeof(prdt_t); } utrd->size_prdt = ALIGN_8(prdt_size); hd->prdtl = utrd->size_prdt >> 2; hd->prdto = (utrd->size_upiu + utrd->size_resp_upiu) >> 2; } flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t)); flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE); return 0; } static int ufs_prepare_query(utp_utrd_t *utrd, uint8_t op, uint8_t idn, uint8_t index, uint8_t sel, uintptr_t buf, size_t length) { utrd_header_t *hd; query_upiu_t *query_upiu; hd = (utrd_header_t *)utrd->header; query_upiu = (query_upiu_t *)utrd->upiu; mmio_write_32(ufs_params.reg_base + UTRLBA, utrd->header & UINT32_MAX); mmio_write_32(ufs_params.reg_base + UTRLBAU, (utrd->header >> 32) & UINT32_MAX); hd->i = 1; hd->ct = CT_UFS_STORAGE; hd->ocs = OCS_MASK; query_upiu->trans_type = QUERY_REQUEST_UPIU; query_upiu->task_tag = utrd->task_tag; query_upiu->ts.desc.opcode = op; query_upiu->ts.desc.idn = idn; query_upiu->ts.desc.index = index; query_upiu->ts.desc.selector = sel; switch (op) { case QUERY_READ_DESC: query_upiu->query_func = QUERY_FUNC_STD_READ; query_upiu->ts.desc.length = htobe16(length); break; case QUERY_WRITE_DESC: query_upiu->query_func = QUERY_FUNC_STD_WRITE; query_upiu->ts.desc.length = htobe16(length); memcpy((void *)(utrd->upiu + sizeof(query_upiu_t)), (void *)buf, length); break; case QUERY_READ_ATTR: case QUERY_READ_FLAG: query_upiu->query_func = QUERY_FUNC_STD_READ; break; case QUERY_CLEAR_FLAG: case QUERY_SET_FLAG: query_upiu->query_func = QUERY_FUNC_STD_WRITE; break; case QUERY_WRITE_ATTR: query_upiu->query_func = QUERY_FUNC_STD_WRITE; memcpy((void *)&query_upiu->ts.attr.value, (void *)buf, length); break; default: assert(0); break; } flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t)); flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE); return 0; } static void ufs_prepare_nop_out(utp_utrd_t *utrd) { utrd_header_t *hd; nop_out_upiu_t *nop_out; mmio_write_32(ufs_params.reg_base + UTRLBA, utrd->header & UINT32_MAX); mmio_write_32(ufs_params.reg_base + UTRLBAU, (utrd->header >> 32) & UINT32_MAX); hd = (utrd_header_t *)utrd->header; nop_out = (nop_out_upiu_t *)utrd->upiu; hd->i = 1; hd->ct = CT_UFS_STORAGE; hd->ocs = OCS_MASK; nop_out->trans_type = 0; nop_out->task_tag = utrd->task_tag; flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t)); flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE); } static void ufs_send_request(int task_tag) { unsigned int data; int slot; slot = task_tag - 1; /* clear all interrupts */ mmio_write_32(ufs_params.reg_base + IS, ~0); mmio_write_32(ufs_params.reg_base + UTRLRSR, 1); do { data = mmio_read_32(ufs_params.reg_base + UTRLRSR); } while (data == 0); data = UTRIACR_IAEN | UTRIACR_CTR | UTRIACR_IACTH(0x1F) | UTRIACR_IATOVAL(0xFF); mmio_write_32(ufs_params.reg_base + UTRIACR, data); /* send request */ mmio_setbits_32(ufs_params.reg_base + UTRLDBR, 1 << slot); } static int ufs_check_resp(utp_utrd_t *utrd, int trans_type) { utrd_header_t *hd; resp_upiu_t *resp; unsigned int data; int slot; hd = (utrd_header_t *)utrd->header; resp = (resp_upiu_t *)utrd->resp_upiu; inv_dcache_range((uintptr_t)hd, UFS_DESC_SIZE); inv_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t)); do { data = mmio_read_32(ufs_params.reg_base + IS); if ((data & ~(UFS_INT_UCCS | UFS_INT_UTRCS)) != 0) return -EIO; } while ((data & UFS_INT_UTRCS) == 0); slot = utrd->task_tag - 1; data = mmio_read_32(ufs_params.reg_base + UTRLDBR); assert((data & (1 << slot)) == 0); assert(hd->ocs == OCS_SUCCESS); assert((resp->trans_type & TRANS_TYPE_CODE_MASK) == trans_type); (void)resp; (void)slot; return 0; } #ifdef UFS_RESP_DEBUG static void dump_upiu(utp_utrd_t *utrd) { utrd_header_t *hd; int i; hd = (utrd_header_t *)utrd->header; INFO("utrd:0x%x, ruo:0x%x, rul:0x%x, ocs:0x%x, UTRLDBR:0x%x\n", (unsigned int)(uintptr_t)utrd, hd->ruo, hd->rul, hd->ocs, mmio_read_32(ufs_params.reg_base + UTRLDBR)); for (i = 0; i < sizeof(utrd_header_t); i += 4) { INFO("[%lx]:0x%x\n", (uintptr_t)utrd->header + i, *(unsigned int *)((uintptr_t)utrd->header + i)); } for (i = 0; i < sizeof(cmd_upiu_t); i += 4) { INFO("cmd[%lx]:0x%x\n", utrd->upiu + i, *(unsigned int *)(utrd->upiu + i)); } for (i = 0; i < sizeof(resp_upiu_t); i += 4) { INFO("resp[%lx]:0x%x\n", utrd->resp_upiu + i, *(unsigned int *)(utrd->resp_upiu + i)); } for (i = 0; i < sizeof(prdt_t); i += 4) { INFO("prdt[%lx]:0x%x\n", utrd->prdt + i, *(unsigned int *)(utrd->prdt + i)); } } #endif static void ufs_verify_init(void) { utp_utrd_t utrd; int result; get_utrd(&utrd); ufs_prepare_nop_out(&utrd); ufs_send_request(utrd.task_tag); result = ufs_check_resp(&utrd, NOP_IN_UPIU); assert(result == 0); (void)result; } static void ufs_verify_ready(void) { utp_utrd_t utrd; int result; get_utrd(&utrd); ufs_prepare_cmd(&utrd, CDBCMD_TEST_UNIT_READY, 0, 0, 0, 0); ufs_send_request(utrd.task_tag); result = ufs_check_resp(&utrd, RESPONSE_UPIU); assert(result == 0); (void)result; } static void ufs_query(uint8_t op, uint8_t idn, uint8_t index, uint8_t sel, uintptr_t buf, size_t size) { utp_utrd_t utrd; query_resp_upiu_t *resp; int result; switch (op) { case QUERY_READ_FLAG: case QUERY_READ_ATTR: case QUERY_READ_DESC: case QUERY_WRITE_DESC: case QUERY_WRITE_ATTR: assert(((buf & 3) == 0) && (size != 0)); break; default: /* Do nothing in default case */ break; } get_utrd(&utrd); ufs_prepare_query(&utrd, op, idn, index, sel, buf, size); ufs_send_request(utrd.task_tag); result = ufs_check_resp(&utrd, QUERY_RESPONSE_UPIU); assert(result == 0); resp = (query_resp_upiu_t *)utrd.resp_upiu; #ifdef UFS_RESP_DEBUG dump_upiu(&utrd); #endif assert(resp->query_resp == QUERY_RESP_SUCCESS); switch (op) { case QUERY_READ_FLAG: *(uint32_t *)buf = (uint32_t)resp->ts.flag.value; break; case QUERY_READ_ATTR: case QUERY_READ_DESC: memcpy((void *)buf, (void *)(utrd.resp_upiu + sizeof(query_resp_upiu_t)), size); break; default: /* Do nothing in default case */ break; } (void)result; } unsigned int ufs_read_attr(int idn) { unsigned int value; ufs_query(QUERY_READ_ATTR, idn, 0, 0, (uintptr_t)&value, sizeof(value)); return value; } void ufs_write_attr(int idn, unsigned int value) { ufs_query(QUERY_WRITE_ATTR, idn, 0, 0, (uintptr_t)&value, sizeof(value)); } unsigned int ufs_read_flag(int idn) { unsigned int value; ufs_query(QUERY_READ_FLAG, idn, 0, 0, (uintptr_t)&value, sizeof(value)); return value; } void ufs_set_flag(int idn) { ufs_query(QUERY_SET_FLAG, idn, 0, 0, 0, 0); } void ufs_clear_flag(int idn) { ufs_query(QUERY_CLEAR_FLAG, idn, 0, 0, 0, 0); } void ufs_read_desc(int idn, int index, uintptr_t buf, size_t size) { ufs_query(QUERY_READ_DESC, idn, index, 0, buf, size); } void ufs_write_desc(int idn, int index, uintptr_t buf, size_t size) { ufs_query(QUERY_WRITE_DESC, idn, index, 0, buf, size); } static void ufs_read_capacity(int lun, unsigned int *num, unsigned int *size) { utp_utrd_t utrd; resp_upiu_t *resp; sense_data_t *sense; unsigned char data[CACHE_WRITEBACK_GRANULE << 1]; uintptr_t buf; int result; int retry; assert((ufs_params.reg_base != 0) && (ufs_params.desc_base != 0) && (ufs_params.desc_size >= UFS_DESC_SIZE) && (num != NULL) && (size != NULL)); /* align buf address */ buf = (uintptr_t)data; buf = (buf + CACHE_WRITEBACK_GRANULE - 1) & ~(CACHE_WRITEBACK_GRANULE - 1); memset((void *)buf, 0, CACHE_WRITEBACK_GRANULE); flush_dcache_range(buf, CACHE_WRITEBACK_GRANULE); do { get_utrd(&utrd); ufs_prepare_cmd(&utrd, CDBCMD_READ_CAPACITY_10, lun, 0, buf, READ_CAPACITY_LENGTH); ufs_send_request(utrd.task_tag); result = ufs_check_resp(&utrd, RESPONSE_UPIU); assert(result == 0); #ifdef UFS_RESP_DEBUG dump_upiu(&utrd); #endif resp = (resp_upiu_t *)utrd.resp_upiu; retry = 0; sense = &resp->sd.sense; if (sense->resp_code == SENSE_DATA_VALID) { if ((sense->sense_key == SENSE_KEY_UNIT_ATTENTION) && (sense->asc == 0x29) && (sense->ascq == 0)) { retry = 1; } } inv_dcache_range(buf, CACHE_WRITEBACK_GRANULE); /* last logical block address */ *num = be32toh(*(unsigned int *)buf); if (*num) *num += 1; /* logical block length in bytes */ *size = be32toh(*(unsigned int *)(buf + 4)); } while (retry); (void)result; } size_t ufs_read_blocks(int lun, int lba, uintptr_t buf, size_t size) { utp_utrd_t utrd; resp_upiu_t *resp; int result; assert((ufs_params.reg_base != 0) && (ufs_params.desc_base != 0) && (ufs_params.desc_size >= UFS_DESC_SIZE)); memset((void *)buf, 0, size); get_utrd(&utrd); ufs_prepare_cmd(&utrd, CDBCMD_READ_10, lun, lba, buf, size); ufs_send_request(utrd.task_tag); result = ufs_check_resp(&utrd, RESPONSE_UPIU); assert(result == 0); #ifdef UFS_RESP_DEBUG dump_upiu(&utrd); #endif resp = (resp_upiu_t *)utrd.resp_upiu; (void)result; return size - resp->res_trans_cnt; } size_t ufs_write_blocks(int lun, int lba, const uintptr_t buf, size_t size) { utp_utrd_t utrd; resp_upiu_t *resp; int result; assert((ufs_params.reg_base != 0) && (ufs_params.desc_base != 0) && (ufs_params.desc_size >= UFS_DESC_SIZE)); memset((void *)buf, 0, size); get_utrd(&utrd); ufs_prepare_cmd(&utrd, CDBCMD_WRITE_10, lun, lba, buf, size); ufs_send_request(utrd.task_tag); result = ufs_check_resp(&utrd, RESPONSE_UPIU); assert(result == 0); #ifdef UFS_RESP_DEBUG dump_upiu(&utrd); #endif resp = (resp_upiu_t *)utrd.resp_upiu; (void)result; return size - resp->res_trans_cnt; } static void ufs_enum(void) { unsigned int blk_num, blk_size; int i; /* 0 means 1 slot */ nutrs = (mmio_read_32(ufs_params.reg_base + CAP) & CAP_NUTRS_MASK) + 1; if (nutrs > (ufs_params.desc_size / UFS_DESC_SIZE)) nutrs = ufs_params.desc_size / UFS_DESC_SIZE; ufs_verify_init(); ufs_verify_ready(); ufs_set_flag(FLAG_DEVICE_INIT); mdelay(200); /* dump available LUNs */ for (i = 0; i < UFS_MAX_LUNS; i++) { ufs_read_capacity(i, &blk_num, &blk_size); if (blk_num && blk_size) { INFO("UFS LUN%d contains %d blocks with %d-byte size\n", i, blk_num, blk_size); } } } static void ufs_get_device_info(struct ufs_dev_desc *card_data) { uint8_t desc_buf[DESC_DEVICE_MAX_SIZE]; ufs_query(QUERY_READ_DESC, DESC_TYPE_DEVICE, 0, 0, (uintptr_t)desc_buf, DESC_DEVICE_MAX_SIZE); /* * getting vendor (manufacturerID) and Bank Index in big endian * format */ card_data->wmanufacturerid = (uint16_t)((desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8) | (desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1])); } int ufs_init(const ufs_ops_t *ops, ufs_params_t *params) { int result; unsigned int data; uic_cmd_t cmd; struct ufs_dev_desc card = {0}; assert((params != NULL) && (params->reg_base != 0) && (params->desc_base != 0) && (params->desc_size >= UFS_DESC_SIZE)); memcpy(&ufs_params, params, sizeof(ufs_params_t)); if (ufs_params.flags & UFS_FLAGS_SKIPINIT) { result = ufshc_dme_get(0x1571, 0, &data); assert(result == 0); result = ufshc_dme_get(0x41, 0, &data); assert(result == 0); if (data == 1) { /* prepare to exit hibernate mode */ memset(&cmd, 0, sizeof(uic_cmd_t)); cmd.op = DME_HIBERNATE_EXIT; result = ufshc_send_uic_cmd(ufs_params.reg_base, &cmd); assert(result == 0); data = mmio_read_32(ufs_params.reg_base + UCMDARG2); assert(data == 0); do { data = mmio_read_32(ufs_params.reg_base + IS); } while ((data & UFS_INT_UHXS) == 0); mmio_write_32(ufs_params.reg_base + IS, UFS_INT_UHXS); data = mmio_read_32(ufs_params.reg_base + HCS); assert((data & HCS_UPMCRS_MASK) == HCS_PWR_LOCAL); } result = ufshc_dme_get(0x1568, 0, &data); assert(result == 0); assert((data > 0) && (data <= 3)); } else { assert((ops != NULL) && (ops->phy_init != NULL) && (ops->phy_set_pwr_mode != NULL)); ufshc_reset(ufs_params.reg_base); ops->phy_init(&ufs_params); result = ufshc_link_startup(ufs_params.reg_base); assert(result == 0); ufs_enum(); ufs_get_device_info(&card); if (card.wmanufacturerid == UFS_VENDOR_SKHYNIX) { ufs_params.flags |= UFS_FLAGS_VENDOR_SKHYNIX; } ops->phy_set_pwr_mode(&ufs_params); } (void)result; return 0; } trusted-firmware-a-2.2/fdts/000077500000000000000000000000001355360272700160515ustar00rootroot00000000000000trusted-firmware-a-2.2/fdts/a5ds.dts000066400000000000000000000045311355360272700174240ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { model = "A5DS"; compatible = "arm,A5DS"; interrupt-parent = <&gic>; #address-cells = <1>; #size-cells = <1>; psci { compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci"; method = "smc"; cpu_on = <0x84000003>; }; cpus { #address-cells = <1>; #size-cells = <0>; cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a5"; enable-method = "psci"; reg = <0>; }; cpu@1 { device_type = "cpu"; compatible = "arm,cortex-a5"; enable-method = "psci"; reg = <1>; }; cpu@2 { device_type = "cpu"; compatible = "arm,cortex-a5"; enable-method = "psci"; reg = <2>; }; cpu@3 { device_type = "cpu"; compatible = "arm,cortex-a5"; enable-method = "psci"; reg = <3>; }; }; memory@80000000 { device_type = "memory"; reg = <0x80000000 0x7F000000>; }; refclk100mhz: refclk100mhz { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <100000000>; clock-output-names = "apb_pclk"; }; smbclk: refclk24mhzx2 { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <48000000>; clock-output-names = "smclk"; }; rtc@1a220000 { compatible = "arm,pl031", "arm,primecell"; reg = <0x1a220000 0x1000>; clocks = <&refclk100mhz>; interrupts = <0 6 0xf04>; clock-names = "apb_pclk"; }; gic: interrupt-controller@1c001000 { compatible = "arm,cortex-a9-gic"; #interrupt-cells = <3>; #address-cells = <0>; interrupt-controller; reg = <0x1c001000 0x1000>, <0x1c000100 0x100>; interrupts = <1 9 0xf04>; }; serial0: uart@1a200000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x1a200000 0x1000>; interrupt-parent = <&gic>; interrupts = <0 8 0xf04>; clocks = <&refclk100mhz>; clock-names = "apb_pclk"; }; serial1: uart@1a210000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x1a210000 0x1000>; interrupt-parent = <&gic>; interrupts = <0 9 0xf04>; clocks = <&refclk100mhz>; clock-names = "apb_pclk"; }; timer0: timer@1a040000 { compatible = "arm,armv7-timer-mem"; #address-cells = <1>; #size-cells = <1>; ranges; reg = <0x1a040000 0x1000>; clock-frequency = <50000000>; frame@1a050000 { frame-number = <0>; interrupts = <0 2 0xf04>; reg = <0x1a050000 0x1000>; }; }; }; trusted-firmware-a-2.2/fdts/corstone700.dts000066400000000000000000000061101355360272700206460ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { model = "corstone700"; compatible = "arm,Corstone-700"; interrupt-parent = <&gic>; #address-cells = <1>; #size-cells = <1>; chosen { bootargs = "console=ttyAMA0 root=/dev/vda2 rw loglevel=9"; linux,initrd-start = <0x02a00000>; linux,initrd-end = <0x04000000>; }; cpus { #address-cells = <1>; #size-cells = <0>; cpu@0 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0>; next-level-cache = <&L2_0>; }; }; memory@2000000 { device_type = "memory"; reg = <0x02000000 0x02000000>; }; gic: interrupt-controller@1c000000 { compatible = "arm,gic-400"; #interrupt-cells = <3>; #address-cells = <0>; interrupt-controller; reg = <0x1c010000 0x1000>, <0x1c02f000 0x2000>, <0x1c04f000 0x1000>, <0x1c06f000 0x2000>; interrupts = <1 9 0xf08>; }; L2_0: l2-cache0 { compatible = "cache"; }; refclk100mhz: refclk100mhz { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <100000000>; clock-output-names = "apb_pclk"; }; smbclk: refclk24mhzx2 { /* Reference 24MHz clock x 2 */ compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <48000000>; clock-output-names = "smclk"; }; serial0: uart@1a510000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x1a510000 0x1000>; interrupt-parent = <&gic>; interrupts = <0 19 4>; clocks = <&refclk100mhz>, <&smbclk>; clock-names = "apb_pclk", "smclk"; }; serial1: uart@1a520000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x1a520000 0x1000>; interrupt-parent = <&gic>; interrupts = <0 20 4>; clocks = <&refclk100mhz>, <&smbclk>; clock-names = "apb_pclk", "smclk"; }; timer { compatible = "arm,armv8-timer"; interrupts = <1 13 0xf08>, <1 14 0xf08>, <1 11 0xf08>, <1 10 0xf08>; }; mbox_es0mhu0: mhu@1b000000 { compatible = "arm,mhuv2","arm,primecell"; reg = <0x1b000000 0x1000>, <0x1b010000 0x1000>; clocks = <&refclk100mhz>; clock-names = "apb_pclk"; interrupts = <0 12 4>; interrupt-names = "mhu_rx"; #mbox-cells = <1>; mbox-name = "arm-es0-mhu0"; }; mbox_es0mhu1: mhu@1b020000 { compatible = "arm,mhuv2","arm,primecell"; reg = <0x1b020000 0x1000>, <0x1b030000 0x1000>; clocks = <&refclk100mhz>; clock-names = "apb_pclk"; interrupts = <0 47 4>; interrupt-names = "mhu_rx"; #mbox-cells = <1>; mbox-name = "arm-es0-mhu1"; }; mbox_semhu1: mhu@1b820000 { compatible = "arm,mhuv2","arm,primecell"; reg = <0x1b820000 0x1000>, <0x1b830000 0x1000>; clocks = <&refclk100mhz>; clock-names = "apb_pclk"; interrupts = <0 45 4>; interrupt-names = "mhu_rx"; #mbox-cells = <1>; mbox-name = "arm-se-mhu1"; }; client { compatible = "arm,client"; mboxes = <&mbox_es0mhu0 0>, <&mbox_es0mhu1 0>, <&mbox_semhu1 0>; mbox-names = "es0mhu0", "es0mhu1", "semhu1"; }; extsys0: extsys@1A010310 { compatible = "arm,extsys_ctrl"; reg = <0x1A010310 0x4>, <0x1A010314 0x4>; reg-names = "rstreg", "streg"; }; }; trusted-firmware-a-2.2/fdts/fvp-base-gicv2-psci-aarch32.dts000066400000000000000000000145201355360272700234570ustar00rootroot00000000000000/* * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; /memreserve/ 0x80000000 0x00010000; / { }; / { model = "FVP Base"; compatible = "arm,vfp-base", "arm,vexpress"; interrupt-parent = <&gic>; #address-cells = <2>; #size-cells = <2>; chosen { }; aliases { serial0 = &v2m_serial0; serial1 = &v2m_serial1; serial2 = &v2m_serial2; serial3 = &v2m_serial3; }; psci { compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci"; method = "smc"; cpu_suspend = <0x84000001>; cpu_off = <0x84000002>; cpu_on = <0x84000003>; sys_poweroff = <0x84000008>; sys_reset = <0x84000009>; }; cpus { #address-cells = <1>; #size-cells = <0>; cpu-map { cluster0 { core0 { cpu = <&CPU0>; }; core1 { cpu = <&CPU1>; }; core2 { cpu = <&CPU2>; }; core3 { cpu = <&CPU3>; }; }; cluster1 { core0 { cpu = <&CPU4>; }; core1 { cpu = <&CPU5>; }; core2 { cpu = <&CPU6>; }; core3 { cpu = <&CPU7>; }; }; }; idle-states { entry-method = "arm,psci"; CPU_SLEEP_0: cpu-sleep-0 { compatible = "arm,idle-state"; local-timer-stop; arm,psci-suspend-param = <0x0010000>; entry-latency-us = <40>; exit-latency-us = <100>; min-residency-us = <150>; }; CLUSTER_SLEEP_0: cluster-sleep-0 { compatible = "arm,idle-state"; local-timer-stop; arm,psci-suspend-param = <0x1010000>; entry-latency-us = <500>; exit-latency-us = <1000>; min-residency-us = <2500>; }; }; CPU0:cpu@0 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU1:cpu@1 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x1>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU2:cpu@2 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x2>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU3:cpu@3 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x3>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU4:cpu@100 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x100>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU5:cpu@101 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x101>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU6:cpu@102 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x102>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU7:cpu@103 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x103>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; L2_0: l2-cache0 { compatible = "cache"; }; }; memory@80000000 { device_type = "memory"; reg = <0x00000000 0x80000000 0 0x7F000000>, <0x00000008 0x80000000 0 0x80000000>; }; gic: interrupt-controller@2f000000 { compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; #interrupt-cells = <3>; #address-cells = <0>; interrupt-controller; reg = <0x0 0x2f000000 0 0x10000>, <0x0 0x2c000000 0 0x2000>, <0x0 0x2c010000 0 0x2000>, <0x0 0x2c02F000 0 0x2000>; interrupts = <1 9 0xf04>; }; timer { compatible = "arm,armv8-timer"; interrupts = <1 13 0xff01>, <1 14 0xff01>, <1 11 0xff01>, <1 10 0xff01>; clock-frequency = <100000000>; }; timer@2a810000 { compatible = "arm,armv7-timer-mem"; reg = <0x0 0x2a810000 0x0 0x10000>; clock-frequency = <100000000>; #address-cells = <2>; #size-cells = <2>; ranges; frame@2a830000 { frame-number = <1>; interrupts = <0 26 4>; reg = <0x0 0x2a830000 0x0 0x10000>; }; }; pmu { compatible = "arm,armv8-pmuv3"; interrupts = <0 60 4>, <0 61 4>, <0 62 4>, <0 63 4>; }; smb { compatible = "simple-bus"; #address-cells = <2>; #size-cells = <1>; ranges = <0 0 0 0x08000000 0x04000000>, <1 0 0 0x14000000 0x04000000>, <2 0 0 0x18000000 0x04000000>, <3 0 0 0x1c000000 0x04000000>, <4 0 0 0x0c000000 0x04000000>, <5 0 0 0x10000000 0x04000000>; #interrupt-cells = <1>; interrupt-map-mask = <0 0 63>; interrupt-map = <0 0 0 &gic 0 0 4>, <0 0 1 &gic 0 1 4>, <0 0 2 &gic 0 2 4>, <0 0 3 &gic 0 3 4>, <0 0 4 &gic 0 4 4>, <0 0 5 &gic 0 5 4>, <0 0 6 &gic 0 6 4>, <0 0 7 &gic 0 7 4>, <0 0 8 &gic 0 8 4>, <0 0 9 &gic 0 9 4>, <0 0 10 &gic 0 10 4>, <0 0 11 &gic 0 11 4>, <0 0 12 &gic 0 12 4>, <0 0 13 &gic 0 13 4>, <0 0 14 &gic 0 14 4>, <0 0 15 &gic 0 15 4>, <0 0 16 &gic 0 16 4>, <0 0 17 &gic 0 17 4>, <0 0 18 &gic 0 18 4>, <0 0 19 &gic 0 19 4>, <0 0 20 &gic 0 20 4>, <0 0 21 &gic 0 21 4>, <0 0 22 &gic 0 22 4>, <0 0 23 &gic 0 23 4>, <0 0 24 &gic 0 24 4>, <0 0 25 &gic 0 25 4>, <0 0 26 &gic 0 26 4>, <0 0 27 &gic 0 27 4>, <0 0 28 &gic 0 28 4>, <0 0 29 &gic 0 29 4>, <0 0 30 &gic 0 30 4>, <0 0 31 &gic 0 31 4>, <0 0 32 &gic 0 32 4>, <0 0 33 &gic 0 33 4>, <0 0 34 &gic 0 34 4>, <0 0 35 &gic 0 35 4>, <0 0 36 &gic 0 36 4>, <0 0 37 &gic 0 37 4>, <0 0 38 &gic 0 38 4>, <0 0 39 &gic 0 39 4>, <0 0 40 &gic 0 40 4>, <0 0 41 &gic 0 41 4>, <0 0 42 &gic 0 42 4>; /include/ "rtsm_ve-motherboard-aarch32.dtsi" }; panels { panel@0 { compatible = "panel"; mode = "XVGA"; refresh = <60>; xres = <1024>; yres = <768>; pixclock = <15748>; left_margin = <152>; right_margin = <48>; upper_margin = <23>; lower_margin = <3>; hsync_len = <104>; vsync_len = <4>; sync = <0>; vmode = "FB_VMODE_NONINTERLACED"; tim2 = "TIM2_BCD", "TIM2_IPC"; cntl = "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)"; caps = "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888"; bpp = <16>; }; }; }; trusted-firmware-a-2.2/fdts/fvp-base-gicv2-psci.dts000066400000000000000000000123001355360272700222300ustar00rootroot00000000000000/* * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; /memreserve/ 0x80000000 0x00010000; / { }; / { model = "FVP Base"; compatible = "arm,vfp-base", "arm,vexpress"; interrupt-parent = <&gic>; #address-cells = <2>; #size-cells = <2>; chosen { }; aliases { serial0 = &v2m_serial0; serial1 = &v2m_serial1; serial2 = &v2m_serial2; serial3 = &v2m_serial3; }; psci { compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci"; method = "smc"; cpu_suspend = <0xc4000001>; cpu_off = <0x84000002>; cpu_on = <0xc4000003>; sys_poweroff = <0x84000008>; sys_reset = <0x84000009>; }; cpus { #address-cells = <2>; #size-cells = <0>; cpu-map { cluster0 { core0 { cpu = <&CPU0>; }; core1 { cpu = <&CPU1>; }; core2 { cpu = <&CPU2>; }; core3 { cpu = <&CPU3>; }; }; cluster1 { core0 { cpu = <&CPU4>; }; core1 { cpu = <&CPU5>; }; core2 { cpu = <&CPU6>; }; core3 { cpu = <&CPU7>; }; }; }; idle-states { entry-method = "arm,psci"; CPU_SLEEP_0: cpu-sleep-0 { compatible = "arm,idle-state"; local-timer-stop; arm,psci-suspend-param = <0x0010000>; entry-latency-us = <40>; exit-latency-us = <100>; min-residency-us = <150>; }; CLUSTER_SLEEP_0: cluster-sleep-0 { compatible = "arm,idle-state"; local-timer-stop; arm,psci-suspend-param = <0x1010000>; entry-latency-us = <500>; exit-latency-us = <1000>; min-residency-us = <2500>; }; }; CPU0:cpu@0 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x0>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU1:cpu@1 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x1>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU2:cpu@2 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x2>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU3:cpu@3 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x3>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU4:cpu@100 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x100>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU5:cpu@101 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x101>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU6:cpu@102 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x102>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU7:cpu@103 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x103>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; L2_0: l2-cache0 { compatible = "cache"; }; }; memory@80000000 { device_type = "memory"; reg = <0x00000000 0x80000000 0 0x7F000000>, <0x00000008 0x80000000 0 0x80000000>; }; gic: interrupt-controller@2f000000 { compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; #interrupt-cells = <3>; #address-cells = <0>; interrupt-controller; reg = <0x0 0x2f000000 0 0x10000>, <0x0 0x2c000000 0 0x2000>, <0x0 0x2c010000 0 0x2000>, <0x0 0x2c02F000 0 0x2000>; interrupts = <1 9 0xf04>; }; timer { compatible = "arm,armv8-timer"; interrupts = <1 13 0xff01>, <1 14 0xff01>, <1 11 0xff01>, <1 10 0xff01>; clock-frequency = <100000000>; }; timer@2a810000 { compatible = "arm,armv7-timer-mem"; reg = <0x0 0x2a810000 0x0 0x10000>; clock-frequency = <100000000>; #address-cells = <2>; #size-cells = <2>; ranges; frame@2a830000 { frame-number = <1>; interrupts = <0 26 4>; reg = <0x0 0x2a830000 0x0 0x10000>; }; }; pmu { compatible = "arm,armv8-pmuv3"; interrupts = <0 60 4>, <0 61 4>, <0 62 4>, <0 63 4>; }; smb { compatible = "simple-bus"; #address-cells = <2>; #size-cells = <1>; ranges = <0 0 0 0x08000000 0x04000000>, <1 0 0 0x14000000 0x04000000>, <2 0 0 0x18000000 0x04000000>, <3 0 0 0x1c000000 0x04000000>, <4 0 0 0x0c000000 0x04000000>, <5 0 0 0x10000000 0x04000000>; /include/ "rtsm_ve-motherboard.dtsi" }; panels { panel@0 { compatible = "panel"; mode = "XVGA"; refresh = <60>; xres = <1024>; yres = <768>; pixclock = <15748>; left_margin = <152>; right_margin = <48>; upper_margin = <23>; lower_margin = <3>; hsync_len = <104>; vsync_len = <4>; sync = <0>; vmode = "FB_VMODE_NONINTERLACED"; tim2 = "TIM2_BCD", "TIM2_IPC"; cntl = "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)"; caps = "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888"; bpp = <16>; }; }; }; trusted-firmware-a-2.2/fdts/fvp-base-gicv3-psci-1t.dts000066400000000000000000000006731355360272700225650ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; /include/ "fvp-base-gicv3-psci-common.dtsi" &CPU0 { reg = <0x0 0x0>; }; &CPU1 { reg = <0x0 0x100>; }; &CPU2 { reg = <0x0 0x200>; }; &CPU3 { reg = <0x0 0x300>; }; &CPU4 { reg = <0x0 0x10000>; }; &CPU5 { reg = <0x0 0x10100>; }; &CPU6 { reg = <0x0 0x10200>; }; &CPU7 { reg = <0x0 0x10300>; }; trusted-firmware-a-2.2/fdts/fvp-base-gicv3-psci-aarch32-1t.dts000066400000000000000000000006221355360272700240000ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; /include/ "fvp-base-gicv3-psci-aarch32-common.dtsi" &CPU0 { reg = <0x0>; }; &CPU1 { reg = <0x100>; }; &CPU2 { reg = <0x200>; }; &CPU3 { reg = <0x300>; }; &CPU4 { reg = <0x10000>; }; &CPU5 { reg = <0x10100>; }; &CPU6 { reg = <0x10200>; }; &CPU7 { reg = <0x10300>; }; trusted-firmware-a-2.2/fdts/fvp-base-gicv3-psci-aarch32-common.dtsi000066400000000000000000000152741355360272700251260ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /memreserve/ 0x80000000 0x00010000; / { }; / { model = "FVP Base"; compatible = "arm,vfp-base", "arm,vexpress"; interrupt-parent = <&gic>; #address-cells = <2>; #size-cells = <2>; chosen { }; aliases { serial0 = &v2m_serial0; serial1 = &v2m_serial1; serial2 = &v2m_serial2; serial3 = &v2m_serial3; }; psci { compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci"; method = "smc"; cpu_suspend = <0x84000001>; cpu_off = <0x84000002>; cpu_on = <0x84000003>; sys_poweroff = <0x84000008>; sys_reset = <0x84000009>; }; cpus { #address-cells = <1>; #size-cells = <0>; cpu-map { cluster0 { core0 { cpu = <&CPU0>; }; core1 { cpu = <&CPU1>; }; core2 { cpu = <&CPU2>; }; core3 { cpu = <&CPU3>; }; }; cluster1 { core0 { cpu = <&CPU4>; }; core1 { cpu = <&CPU5>; }; core2 { cpu = <&CPU6>; }; core3 { cpu = <&CPU7>; }; }; }; idle-states { entry-method = "arm,psci"; CPU_SLEEP_0: cpu-sleep-0 { compatible = "arm,idle-state"; local-timer-stop; arm,psci-suspend-param = <0x0010000>; entry-latency-us = <40>; exit-latency-us = <100>; min-residency-us = <150>; }; CLUSTER_SLEEP_0: cluster-sleep-0 { compatible = "arm,idle-state"; local-timer-stop; arm,psci-suspend-param = <0x1010000>; entry-latency-us = <500>; exit-latency-us = <1000>; min-residency-us = <2500>; }; }; CPU0:cpu@0 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU1:cpu@1 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x1>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU2:cpu@2 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x2>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU3:cpu@3 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x3>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU4:cpu@100 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x100>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU5:cpu@101 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x101>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU6:cpu@102 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x102>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU7:cpu@103 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x103>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; L2_0: l2-cache0 { compatible = "cache"; }; }; memory@80000000 { device_type = "memory"; reg = <0x00000000 0x80000000 0 0x7F000000>, <0x00000008 0x80000000 0 0x80000000>; }; gic: interrupt-controller@2f000000 { compatible = "arm,gic-v3"; #interrupt-cells = <3>; #address-cells = <2>; #size-cells = <2>; ranges; interrupt-controller; reg = <0x0 0x2f000000 0 0x10000>, // GICD <0x0 0x2f100000 0 0x200000>, // GICR <0x0 0x2c000000 0 0x2000>, // GICC <0x0 0x2c010000 0 0x2000>, // GICH <0x0 0x2c02f000 0 0x2000>; // GICV interrupts = <1 9 4>; its: its@2f020000 { compatible = "arm,gic-v3-its"; msi-controller; reg = <0x0 0x2f020000 0x0 0x20000>; // GITS }; }; timer { compatible = "arm,armv8-timer"; interrupts = <1 13 0xff01>, <1 14 0xff01>, <1 11 0xff01>, <1 10 0xff01>; clock-frequency = <100000000>; }; timer@2a810000 { compatible = "arm,armv7-timer-mem"; reg = <0x0 0x2a810000 0x0 0x10000>; clock-frequency = <100000000>; #address-cells = <2>; #size-cells = <2>; ranges; frame@2a830000 { frame-number = <1>; interrupts = <0 26 4>; reg = <0x0 0x2a830000 0x0 0x10000>; }; }; pmu { compatible = "arm,armv8-pmuv3"; interrupts = <0 60 4>, <0 61 4>, <0 62 4>, <0 63 4>; }; smb { compatible = "simple-bus"; #address-cells = <2>; #size-cells = <1>; ranges = <0 0 0 0x08000000 0x04000000>, <1 0 0 0x14000000 0x04000000>, <2 0 0 0x18000000 0x04000000>, <3 0 0 0x1c000000 0x04000000>, <4 0 0 0x0c000000 0x04000000>, <5 0 0 0x10000000 0x04000000>; #interrupt-cells = <1>; interrupt-map-mask = <0 0 63>; interrupt-map = <0 0 0 &gic 0 0 0 0 4>, <0 0 1 &gic 0 0 0 1 4>, <0 0 2 &gic 0 0 0 2 4>, <0 0 3 &gic 0 0 0 3 4>, <0 0 4 &gic 0 0 0 4 4>, <0 0 5 &gic 0 0 0 5 4>, <0 0 6 &gic 0 0 0 6 4>, <0 0 7 &gic 0 0 0 7 4>, <0 0 8 &gic 0 0 0 8 4>, <0 0 9 &gic 0 0 0 9 4>, <0 0 10 &gic 0 0 0 10 4>, <0 0 11 &gic 0 0 0 11 4>, <0 0 12 &gic 0 0 0 12 4>, <0 0 13 &gic 0 0 0 13 4>, <0 0 14 &gic 0 0 0 14 4>, <0 0 15 &gic 0 0 0 15 4>, <0 0 16 &gic 0 0 0 16 4>, <0 0 17 &gic 0 0 0 17 4>, <0 0 18 &gic 0 0 0 18 4>, <0 0 19 &gic 0 0 0 19 4>, <0 0 20 &gic 0 0 0 20 4>, <0 0 21 &gic 0 0 0 21 4>, <0 0 22 &gic 0 0 0 22 4>, <0 0 23 &gic 0 0 0 23 4>, <0 0 24 &gic 0 0 0 24 4>, <0 0 25 &gic 0 0 0 25 4>, <0 0 26 &gic 0 0 0 26 4>, <0 0 27 &gic 0 0 0 27 4>, <0 0 28 &gic 0 0 0 28 4>, <0 0 29 &gic 0 0 0 29 4>, <0 0 30 &gic 0 0 0 30 4>, <0 0 31 &gic 0 0 0 31 4>, <0 0 32 &gic 0 0 0 32 4>, <0 0 33 &gic 0 0 0 33 4>, <0 0 34 &gic 0 0 0 34 4>, <0 0 35 &gic 0 0 0 35 4>, <0 0 36 &gic 0 0 0 36 4>, <0 0 37 &gic 0 0 0 37 4>, <0 0 38 &gic 0 0 0 38 4>, <0 0 39 &gic 0 0 0 39 4>, <0 0 40 &gic 0 0 0 40 4>, <0 0 41 &gic 0 0 0 41 4>, <0 0 42 &gic 0 0 0 42 4>; /include/ "rtsm_ve-motherboard-aarch32.dtsi" }; panels { panel@0 { compatible = "panel"; mode = "XVGA"; refresh = <60>; xres = <1024>; yres = <768>; pixclock = <15748>; left_margin = <152>; right_margin = <48>; upper_margin = <23>; lower_margin = <3>; hsync_len = <104>; vsync_len = <4>; sync = <0>; vmode = "FB_VMODE_NONINTERLACED"; tim2 = "TIM2_BCD", "TIM2_IPC"; cntl = "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)"; caps = "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888"; bpp = <16>; }; }; }; trusted-firmware-a-2.2/fdts/fvp-base-gicv3-psci-aarch32.dts000066400000000000000000000003021355360272700234510ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; /include/ "fvp-base-gicv3-psci-aarch32-common.dtsi" trusted-firmware-a-2.2/fdts/fvp-base-gicv3-psci-common.dtsi000066400000000000000000000126021355360272700236750ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /memreserve/ 0x80000000 0x00010000; / { }; / { model = "FVP Base"; compatible = "arm,vfp-base", "arm,vexpress"; interrupt-parent = <&gic>; #address-cells = <2>; #size-cells = <2>; chosen { }; aliases { serial0 = &v2m_serial0; serial1 = &v2m_serial1; serial2 = &v2m_serial2; serial3 = &v2m_serial3; }; psci { compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci"; method = "smc"; cpu_suspend = <0xc4000001>; cpu_off = <0x84000002>; cpu_on = <0xc4000003>; sys_poweroff = <0x84000008>; sys_reset = <0x84000009>; }; cpus { #address-cells = <2>; #size-cells = <0>; cpu-map { cluster0 { core0 { cpu = <&CPU0>; }; core1 { cpu = <&CPU1>; }; core2 { cpu = <&CPU2>; }; core3 { cpu = <&CPU3>; }; }; cluster1 { core0 { cpu = <&CPU4>; }; core1 { cpu = <&CPU5>; }; core2 { cpu = <&CPU6>; }; core3 { cpu = <&CPU7>; }; }; }; idle-states { entry-method = "arm,psci"; CPU_SLEEP_0: cpu-sleep-0 { compatible = "arm,idle-state"; local-timer-stop; arm,psci-suspend-param = <0x0010000>; entry-latency-us = <40>; exit-latency-us = <100>; min-residency-us = <150>; }; CLUSTER_SLEEP_0: cluster-sleep-0 { compatible = "arm,idle-state"; local-timer-stop; arm,psci-suspend-param = <0x1010000>; entry-latency-us = <500>; exit-latency-us = <1000>; min-residency-us = <2500>; }; }; CPU0:cpu@0 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x0>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU1:cpu@1 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x1>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU2:cpu@2 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x2>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU3:cpu@3 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x3>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU4:cpu@100 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x100>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU5:cpu@101 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x101>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU6:cpu@102 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x102>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU7:cpu@103 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x103>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; L2_0: l2-cache0 { compatible = "cache"; }; }; memory@80000000 { device_type = "memory"; reg = <0x00000000 0x80000000 0 0x7F000000>, <0x00000008 0x80000000 0 0x80000000>; }; gic: interrupt-controller@2f000000 { compatible = "arm,gic-v3"; #interrupt-cells = <3>; #address-cells = <2>; #size-cells = <2>; ranges; interrupt-controller; reg = <0x0 0x2f000000 0 0x10000>, // GICD <0x0 0x2f100000 0 0x200000>, // GICR <0x0 0x2c000000 0 0x2000>, // GICC <0x0 0x2c010000 0 0x2000>, // GICH <0x0 0x2c02f000 0 0x2000>; // GICV interrupts = <1 9 4>; its: its@2f020000 { compatible = "arm,gic-v3-its"; msi-controller; reg = <0x0 0x2f020000 0x0 0x20000>; // GITS }; }; timer { compatible = "arm,armv8-timer"; interrupts = <1 13 0xff01>, <1 14 0xff01>, <1 11 0xff01>, <1 10 0xff01>; clock-frequency = <100000000>; }; timer@2a810000 { compatible = "arm,armv7-timer-mem"; reg = <0x0 0x2a810000 0x0 0x10000>; clock-frequency = <100000000>; #address-cells = <2>; #size-cells = <2>; ranges; frame@2a830000 { frame-number = <1>; interrupts = <0 26 4>; reg = <0x0 0x2a830000 0x0 0x10000>; }; }; pmu { compatible = "arm,armv8-pmuv3"; interrupts = <0 60 4>, <0 61 4>, <0 62 4>, <0 63 4>; }; smb@0,0 { compatible = "simple-bus"; #address-cells = <2>; #size-cells = <1>; ranges = <0 0 0 0x08000000 0x04000000>, <1 0 0 0x14000000 0x04000000>, <2 0 0 0x18000000 0x04000000>, <3 0 0 0x1c000000 0x04000000>, <4 0 0 0x0c000000 0x04000000>, <5 0 0 0x10000000 0x04000000>; /include/ "rtsm_ve-motherboard.dtsi" }; panels { panel { compatible = "panel"; mode = "XVGA"; refresh = <60>; xres = <1024>; yres = <768>; pixclock = <15748>; left_margin = <152>; right_margin = <48>; upper_margin = <23>; lower_margin = <3>; hsync_len = <104>; vsync_len = <4>; sync = <0>; vmode = "FB_VMODE_NONINTERLACED"; tim2 = "TIM2_BCD", "TIM2_IPC"; cntl = "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)"; caps = "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888"; bpp = <16>; }; }; }; trusted-firmware-a-2.2/fdts/fvp-base-gicv3-psci-dynamiq.dts000066400000000000000000000006631355360272700237020ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; /include/ "fvp-base-gicv3-psci-common.dtsi" &CPU0 { reg = <0x0 0x0>; }; &CPU1 { reg = <0x0 0x100>; }; &CPU2 { reg = <0x0 0x200>; }; &CPU3 { reg = <0x0 0x300>; }; &CPU4 { reg = <0x0 0x400>; }; &CPU5 { reg = <0x0 0x500>; }; &CPU6 { reg = <0x0 0x600>; }; &CPU7 { reg = <0x0 0x700>; }; trusted-firmware-a-2.2/fdts/fvp-base-gicv3-psci.dts000066400000000000000000000002721355360272700222360ustar00rootroot00000000000000/* * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; /include/ "fvp-base-gicv3-psci-common.dtsi" trusted-firmware-a-2.2/fdts/fvp-foundation-gicv2-psci.dts000066400000000000000000000073201355360272700234720ustar00rootroot00000000000000/* * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; /memreserve/ 0x80000000 0x00010000; / { }; / { model = "FVP Foundation"; compatible = "arm,fvp-base", "arm,vexpress"; interrupt-parent = <&gic>; #address-cells = <2>; #size-cells = <2>; chosen { }; aliases { serial0 = &v2m_serial0; serial1 = &v2m_serial1; serial2 = &v2m_serial2; serial3 = &v2m_serial3; }; psci { compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci"; method = "smc"; cpu_suspend = <0xc4000001>; cpu_off = <0x84000002>; cpu_on = <0xc4000003>; sys_poweroff = <0x84000008>; sys_reset = <0x84000009>; }; cpus { #address-cells = <2>; #size-cells = <0>; cpu-map { cluster0 { core0 { cpu = <&CPU0>; }; core1 { cpu = <&CPU1>; }; core2 { cpu = <&CPU2>; }; core3 { cpu = <&CPU3>; }; }; }; idle-states { entry-method = "arm,psci"; CPU_SLEEP_0: cpu-sleep-0 { compatible = "arm,idle-state"; local-timer-stop; arm,psci-suspend-param = <0x0010000>; entry-latency-us = <40>; exit-latency-us = <100>; min-residency-us = <150>; }; CLUSTER_SLEEP_0: cluster-sleep-0 { compatible = "arm,idle-state"; local-timer-stop; arm,psci-suspend-param = <0x1010000>; entry-latency-us = <500>; exit-latency-us = <1000>; min-residency-us = <2500>; }; }; CPU0:cpu@0 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x0>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU1:cpu@1 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x1>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU2:cpu@2 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x2>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU3:cpu@3 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x3>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; L2_0: l2-cache0 { compatible = "cache"; }; }; memory@80000000 { device_type = "memory"; reg = <0x00000000 0x80000000 0 0x7F000000>, <0x00000008 0x80000000 0 0x80000000>; }; gic: interrupt-controller@2f000000 { compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic"; #interrupt-cells = <3>; #address-cells = <0>; interrupt-controller; reg = <0x0 0x2f000000 0 0x10000>, <0x0 0x2c000000 0 0x2000>, <0x0 0x2c010000 0 0x2000>, <0x0 0x2c02F000 0 0x2000>; interrupts = <1 9 0xf04>; }; timer { compatible = "arm,armv8-timer"; interrupts = <1 13 0xff01>, <1 14 0xff01>, <1 11 0xff01>, <1 10 0xff01>; clock-frequency = <100000000>; }; timer@2a810000 { compatible = "arm,armv7-timer-mem"; reg = <0x0 0x2a810000 0x0 0x10000>; clock-frequency = <100000000>; #address-cells = <2>; #size-cells = <2>; ranges; frame@2a830000 { frame-number = <1>; interrupts = <0 26 4>; reg = <0x0 0x2a830000 0x0 0x10000>; }; }; pmu { compatible = "arm,armv8-pmuv3"; interrupts = <0 60 4>, <0 61 4>, <0 62 4>, <0 63 4>; }; smb { compatible = "simple-bus"; #address-cells = <2>; #size-cells = <1>; ranges = <0 0 0 0x08000000 0x04000000>, <1 0 0 0x14000000 0x04000000>, <2 0 0 0x18000000 0x04000000>, <3 0 0 0x1c000000 0x04000000>, <4 0 0 0x0c000000 0x04000000>, <5 0 0 0x10000000 0x04000000>; /include/ "fvp-foundation-motherboard.dtsi" }; }; trusted-firmware-a-2.2/fdts/fvp-foundation-gicv3-psci.dts000066400000000000000000000076331355360272700235020ustar00rootroot00000000000000/* * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; /memreserve/ 0x80000000 0x00010000; / { }; / { model = "FVP Foundation"; compatible = "arm,fvp-base", "arm,vexpress"; interrupt-parent = <&gic>; #address-cells = <2>; #size-cells = <2>; chosen { }; aliases { serial0 = &v2m_serial0; serial1 = &v2m_serial1; serial2 = &v2m_serial2; serial3 = &v2m_serial3; }; psci { compatible = "arm,psci-1.0", "arm,psci-0.2", "arm,psci"; method = "smc"; cpu_suspend = <0xc4000001>; cpu_off = <0x84000002>; cpu_on = <0xc4000003>; sys_poweroff = <0x84000008>; sys_reset = <0x84000009>; }; cpus { #address-cells = <2>; #size-cells = <0>; cpu-map { cluster0 { core0 { cpu = <&CPU0>; }; core1 { cpu = <&CPU1>; }; core2 { cpu = <&CPU2>; }; core3 { cpu = <&CPU3>; }; }; }; idle-states { entry-method = "arm,psci"; CPU_SLEEP_0: cpu-sleep-0 { compatible = "arm,idle-state"; local-timer-stop; arm,psci-suspend-param = <0x0010000>; entry-latency-us = <40>; exit-latency-us = <100>; min-residency-us = <150>; }; CLUSTER_SLEEP_0: cluster-sleep-0 { compatible = "arm,idle-state"; local-timer-stop; arm,psci-suspend-param = <0x1010000>; entry-latency-us = <500>; exit-latency-us = <1000>; min-residency-us = <2500>; }; }; CPU0:cpu@0 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x0>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU1:cpu@1 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x1>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU2:cpu@2 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x2>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; CPU3:cpu@3 { device_type = "cpu"; compatible = "arm,armv8"; reg = <0x0 0x3>; enable-method = "psci"; cpu-idle-states = <&CPU_SLEEP_0 &CLUSTER_SLEEP_0>; next-level-cache = <&L2_0>; }; L2_0: l2-cache0 { compatible = "cache"; }; }; memory@80000000 { device_type = "memory"; reg = <0x00000000 0x80000000 0 0x7F000000>, <0x00000008 0x80000000 0 0x80000000>; }; gic: interrupt-controller@2f000000 { compatible = "arm,gic-v3"; #interrupt-cells = <3>; #address-cells = <2>; #size-cells = <2>; ranges; interrupt-controller; reg = <0x0 0x2f000000 0 0x10000>, // GICD <0x0 0x2f100000 0 0x200000>, // GICR <0x0 0x2c000000 0 0x2000>, // GICC <0x0 0x2c010000 0 0x2000>, // GICH <0x0 0x2c02f000 0 0x2000>; // GICV interrupts = <1 9 4>; its: its@2f020000 { compatible = "arm,gic-v3-its"; msi-controller; reg = <0x0 0x2f020000 0x0 0x20000>; // GITS }; }; timer { compatible = "arm,armv8-timer"; interrupts = <1 13 0xff01>, <1 14 0xff01>, <1 11 0xff01>, <1 10 0xff01>; clock-frequency = <100000000>; }; timer@2a810000 { compatible = "arm,armv7-timer-mem"; reg = <0x0 0x2a810000 0x0 0x10000>; clock-frequency = <100000000>; #address-cells = <2>; #size-cells = <2>; ranges; frame@2a830000 { frame-number = <1>; interrupts = <0 26 4>; reg = <0x0 0x2a830000 0x0 0x10000>; }; }; pmu { compatible = "arm,armv8-pmuv3"; interrupts = <0 60 4>, <0 61 4>, <0 62 4>, <0 63 4>; }; smb { compatible = "simple-bus"; #address-cells = <2>; #size-cells = <1>; ranges = <0 0 0 0x08000000 0x04000000>, <1 0 0 0x14000000 0x04000000>, <2 0 0 0x18000000 0x04000000>, <3 0 0 0x1c000000 0x04000000>, <4 0 0 0x0c000000 0x04000000>, <5 0 0 0x10000000 0x04000000>; /include/ "fvp-foundation-motherboard.dtsi" }; }; trusted-firmware-a-2.2/fdts/fvp-foundation-motherboard.dtsi000066400000000000000000000107431355360272700242060ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ motherboard { arm,v2m-memory-map = "rs1"; compatible = "arm,vexpress,v2m-p1", "simple-bus"; #address-cells = <2>; /* SMB chipselect number and offset */ #size-cells = <1>; ranges; ethernet@2,02000000 { compatible = "smsc,lan91c111"; reg = <2 0x02000000 0x10000>; interrupts = <0 15 4>; }; v2m_clk24mhz: clk24mhz { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <24000000>; clock-output-names = "v2m:clk24mhz"; }; v2m_refclk1mhz: refclk1mhz { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <1000000>; clock-output-names = "v2m:refclk1mhz"; }; v2m_refclk32khz: refclk32khz { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <32768>; clock-output-names = "v2m:refclk32khz"; }; iofpga@3,00000000 { compatible = "arm,amba-bus", "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0 3 0 0x200000>; v2m_sysreg: sysreg@10000 { compatible = "arm,vexpress-sysreg"; reg = <0x010000 0x1000>; gpio-controller; #gpio-cells = <2>; }; v2m_sysctl: sysctl@20000 { compatible = "arm,sp810", "arm,primecell"; reg = <0x020000 0x1000>; clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&v2m_clk24mhz>; clock-names = "refclk", "timclk", "apb_pclk"; #clock-cells = <1>; clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3"; }; v2m_serial0: uart@90000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x090000 0x1000>; interrupts = <0 5 4>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "uartclk", "apb_pclk"; }; v2m_serial1: uart@a0000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0a0000 0x1000>; interrupts = <0 6 4>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "uartclk", "apb_pclk"; }; v2m_serial2: uart@b0000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0b0000 0x1000>; interrupts = <0 7 4>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "uartclk", "apb_pclk"; }; v2m_serial3: uart@c0000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0c0000 0x1000>; interrupts = <0 8 4>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "uartclk", "apb_pclk"; }; wdt@f0000 { compatible = "arm,sp805", "arm,primecell"; reg = <0x0f0000 0x1000>; interrupts = <0 0 4>; clocks = <&v2m_refclk32khz>, <&v2m_clk24mhz>; clock-names = "wdogclk", "apb_pclk"; }; v2m_timer01: timer@110000 { compatible = "arm,sp804", "arm,primecell"; reg = <0x110000 0x1000>; interrupts = <0 2 4>; clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&v2m_clk24mhz>; clock-names = "timclken1", "timclken2", "apb_pclk"; }; v2m_timer23: timer@120000 { compatible = "arm,sp804", "arm,primecell"; reg = <0x120000 0x1000>; interrupts = <0 3 4>; clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&v2m_clk24mhz>; clock-names = "timclken1", "timclken2", "apb_pclk"; }; rtc@170000 { compatible = "arm,pl031", "arm,primecell"; reg = <0x170000 0x1000>; interrupts = <0 4 4>; clocks = <&v2m_clk24mhz>; clock-names = "apb_pclk"; }; virtio_block@130000 { compatible = "virtio,mmio"; reg = <0x130000 0x1000>; interrupts = <0 0x2a 4>; }; }; v2m_fixed_3v3: fixedregulator@0 { compatible = "regulator-fixed"; regulator-name = "3V3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; }; mcc { compatible = "arm,vexpress,config-bus", "simple-bus"; arm,vexpress,config-bridge = <&v2m_sysreg>; /* * Not supported in FVP models * * reset@0 { * compatible = "arm,vexpress-reset"; * arm,vexpress-sysreg,func = <5 0>; * }; */ muxfpga@0 { compatible = "arm,vexpress-muxfpga"; arm,vexpress-sysreg,func = <7 0>; }; /* * Not used - Superseded by PSCI sys_poweroff * * shutdown@0 { * compatible = "arm,vexpress-shutdown"; * arm,vexpress-sysreg,func = <8 0>; * }; */ /* * Not used - Superseded by PSCI sys_reset * * reboot@0 { * compatible = "arm,vexpress-reboot"; * arm,vexpress-sysreg,func = <9 0>; * }; */ dvimode@0 { compatible = "arm,vexpress-dvimode"; arm,vexpress-sysreg,func = <11 0>; }; }; }; trusted-firmware-a-2.2/fdts/fvp-ve-Cortex-A5x1.dts000066400000000000000000000060071355360272700217510ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { model = "V2P-CA5s"; compatible = "arm,vexpress,v2p-ca5s", "arm,vexpress"; interrupt-parent = <&gic>; #address-cells = <1>; #size-cells = <1>; cpus { #address-cells = <1>; #size-cells = <0>; cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a5"; reg = <0>; }; }; memory@80000000 { device_type = "memory"; reg = <0x80000000 0x1000000>; }; hdlcd@2a110000 { compatible = "arm,hdlcd"; reg = <0x2a110000 0x1000>; interrupts = <0 85 4>; clocks = <&oscclk3>; clock-names = "pxlclk"; }; scu@2c000000 { compatible = "arm,cortex-a5-scu"; reg = <0x2c000000 0x58>; }; watchdog@2c000620 { compatible = "arm,cortex-a5-twd-wdt"; reg = <0x2c000620 0x20>; interrupts = <1 14 0x304>; }; gic: interrupt-controller@2c001000 { compatible = "arm,cortex-a9-gic"; #interrupt-cells = <3>; #address-cells = <0>; interrupt-controller; reg = <0x2c001000 0x1000>, <0x2c000100 0x100>; }; dcc { compatible = "arm,vexpress,config-bus"; arm,vexpress,config-bridge = <&v2m_sysreg>; oscclk0: osc@0 { /* CPU and internal AXI reference clock */ compatible = "arm,vexpress-osc"; arm,vexpress-sysreg,func = <1 0>; freq-range = <50000000 100000000>; #clock-cells = <0>; clock-output-names = "oscclk0"; }; oscclk1: osc@1 { /* Multiplexed AXI master clock */ compatible = "arm,vexpress-osc"; arm,vexpress-sysreg,func = <1 1>; freq-range = <5000000 50000000>; #clock-cells = <0>; clock-output-names = "oscclk1"; }; osc@2 { /* DDR2 */ compatible = "arm,vexpress-osc"; arm,vexpress-sysreg,func = <1 2>; freq-range = <80000000 120000000>; #clock-cells = <0>; clock-output-names = "oscclk2"; }; oscclk3: osc@3 { /* HDLCD */ compatible = "arm,vexpress-osc"; arm,vexpress-sysreg,func = <1 3>; freq-range = <23750000 165000000>; #clock-cells = <0>; clock-output-names = "oscclk3"; }; osc@4 { /* Test chip gate configuration */ compatible = "arm,vexpress-osc"; arm,vexpress-sysreg,func = <1 4>; freq-range = <80000000 80000000>; #clock-cells = <0>; clock-output-names = "oscclk4"; }; smbclk: osc@5 { /* SMB clock */ compatible = "arm,vexpress-osc"; arm,vexpress-sysreg,func = <1 5>; freq-range = <25000000 60000000>; #clock-cells = <0>; clock-output-names = "oscclk5"; }; }; smb { compatible = "simple-bus"; #address-cells = <2>; #size-cells = <1>; ranges = <0 0 0x08000000 0x04000000>, <1 0 0x14000000 0x04000000>, <2 0 0x18000000 0x04000000>, <3 0 0x1c000000 0x04000000>, <4 0 0x0c000000 0x04000000>, <5 0 0x10000000 0x04000000>; #interrupt-cells = <1>; interrupt-map-mask = <0 0 63>; interrupt-map = <0 0 0 &gic 0 0 4>, <0 0 1 &gic 0 1 4>, <0 0 2 &gic 0 2 4>, <0 0 3 &gic 0 3 4>, <0 0 4 &gic 0 4 4>, <0 0 5 &gic 0 5 4>, <0 0 42 &gic 0 42 4>; /include/ "rtsm_ve-motherboard-aarch32.dtsi" }; }; trusted-firmware-a-2.2/fdts/fvp-ve-Cortex-A7x1.dts000066400000000000000000000031541355360272700217530ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { model = "V2F-1XV7 Cortex-A7x1 SMM"; compatible = "arm,vexpress,v2f-1xv7", "arm,vexpress"; interrupt-parent = <&gic>; #address-cells = <2>; #size-cells = <2>; cpus { #address-cells = <2>; #size-cells = <0>; cpu@0 { device_type = "cpu"; compatible = "arm,cortex-a7"; reg = <0 0>; }; }; memory@0,80000000 { device_type = "memory"; reg = <0 0x80000000 0 0x80000000>; /* 2GB @ 2GB */ }; gic: interrupt-controller@2c001000 { compatible = "arm,cortex-a15-gic"; #interrupt-cells = <3>; #address-cells = <0>; interrupt-controller; reg = <0 0x2c001000 0 0x1000>, <0 0x2c002000 0 0x1000>, <0 0x2c004000 0 0x2000>, <0 0x2c006000 0 0x2000>; interrupts = <1 9 0xf04>; }; smbclk: refclk24mhzx2 { /* Reference 24MHz clock x 2 */ compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <48000000>; clock-output-names = "smclk"; }; smb { compatible = "simple-bus"; #address-cells = <2>; #size-cells = <1>; ranges = <0 0 0 0x08000000 0x04000000>, <1 0 0 0x14000000 0x04000000>, <2 0 0 0x18000000 0x04000000>, <3 0 0 0x1c000000 0x04000000>, <4 0 0 0x0c000000 0x04000000>, <5 0 0 0x10000000 0x04000000>; #interrupt-cells = <1>; interrupt-map-mask = <0 0 63>; interrupt-map = <0 0 0 &gic 0 0 4>, <0 0 1 &gic 0 1 4>, <0 0 2 &gic 0 2 4>, <0 0 3 &gic 0 3 4>, <0 0 4 &gic 0 4 4>, <0 0 5 &gic 0 5 4>, <0 0 42 &gic 0 42 4>; /include/ "rtsm_ve-motherboard-aarch32.dtsi" }; }; trusted-firmware-a-2.2/fdts/rtsm_ve-motherboard-aarch32.dtsi000066400000000000000000000142321355360272700241440ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ motherboard { arm,v2m-memory-map = "rs1"; compatible = "arm,vexpress,v2m-p1", "simple-bus"; #address-cells = <2>; /* SMB chipselect number and offset */ #size-cells = <1>; #interrupt-cells = <1>; ranges; flash@0,00000000 { compatible = "arm,vexpress-flash", "cfi-flash"; reg = <0 0x00000000 0x04000000>, <4 0x00000000 0x04000000>; bank-width = <4>; }; vram@2,00000000 { compatible = "arm,vexpress-vram"; reg = <2 0x00000000 0x00800000>; }; ethernet@2,02000000 { compatible = "smsc,lan91c111"; reg = <2 0x02000000 0x10000>; interrupts = <15>; }; v2m_clk24mhz: clk24mhz { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <24000000>; clock-output-names = "v2m:clk24mhz"; }; v2m_refclk1mhz: refclk1mhz { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <1000000>; clock-output-names = "v2m:refclk1mhz"; }; v2m_refclk32khz: refclk32khz { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <32768>; clock-output-names = "v2m:refclk32khz"; }; iofpga@3,00000000 { compatible = "arm,amba-bus", "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0 3 0 0x200000>; v2m_sysreg: sysreg@10000 { compatible = "arm,vexpress-sysreg"; reg = <0x010000 0x1000>; gpio-controller; #gpio-cells = <2>; }; v2m_sysctl: sysctl@20000 { compatible = "arm,sp810", "arm,primecell"; reg = <0x020000 0x1000>; clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&v2m_clk24mhz>; clock-names = "refclk", "timclk", "apb_pclk"; #clock-cells = <1>; clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3"; }; aaci@40000 { compatible = "arm,pl041", "arm,primecell"; reg = <0x040000 0x1000>; interrupts = <11>; clocks = <&v2m_clk24mhz>; clock-names = "apb_pclk"; }; mmci@50000 { compatible = "arm,pl180", "arm,primecell"; reg = <0x050000 0x1000>; interrupts = <9 10>; cd-gpios = <&v2m_sysreg 0 0>; wp-gpios = <&v2m_sysreg 1 0>; max-frequency = <12000000>; vmmc-supply = <&v2m_fixed_3v3>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "mclk", "apb_pclk"; }; kmi@60000 { compatible = "arm,pl050", "arm,primecell"; reg = <0x060000 0x1000>; interrupts = <12>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "KMIREFCLK", "apb_pclk"; }; kmi@70000 { compatible = "arm,pl050", "arm,primecell"; reg = <0x070000 0x1000>; interrupts = <13>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "KMIREFCLK", "apb_pclk"; }; v2m_serial0: uart@90000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x090000 0x1000>; interrupts = <5>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "uartclk", "apb_pclk"; }; v2m_serial1: uart@a0000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0a0000 0x1000>; interrupts = <6>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "uartclk", "apb_pclk"; }; v2m_serial2: uart@b0000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0b0000 0x1000>; interrupts = <7>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "uartclk", "apb_pclk"; }; v2m_serial3: uart@c0000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0c0000 0x1000>; interrupts = <8>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "uartclk", "apb_pclk"; }; wdt@f0000 { compatible = "arm,sp805", "arm,primecell"; reg = <0x0f0000 0x1000>; interrupts = <0>; clocks = <&v2m_refclk32khz>, <&v2m_clk24mhz>; clock-names = "wdogclk", "apb_pclk"; }; v2m_timer01: timer@110000 { compatible = "arm,sp804", "arm,primecell"; reg = <0x110000 0x1000>; interrupts = <2>; clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&v2m_clk24mhz>; clock-names = "timclken1", "timclken2", "apb_pclk"; }; v2m_timer23: timer@120000 { compatible = "arm,sp804", "arm,primecell"; reg = <0x120000 0x1000>; interrupts = <3>; clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&v2m_clk24mhz>; clock-names = "timclken1", "timclken2", "apb_pclk"; }; rtc@170000 { compatible = "arm,pl031", "arm,primecell"; reg = <0x170000 0x1000>; interrupts = <4>; clocks = <&v2m_clk24mhz>; clock-names = "apb_pclk"; }; clcd@1f0000 { compatible = "arm,pl111", "arm,primecell"; reg = <0x1f0000 0x1000>; interrupts = <14>; clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>; clock-names = "clcdclk", "apb_pclk"; mode = "XVGA"; use_dma = <0>; framebuffer = <0x18000000 0x00180000>; }; virtio_block@130000 { compatible = "virtio,mmio"; reg = <0x130000 0x1000>; interrupts = <0x2a>; }; }; v2m_fixed_3v3: fixedregulator@0 { compatible = "regulator-fixed"; regulator-name = "3V3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; }; mcc { compatible = "arm,vexpress,config-bus", "simple-bus"; arm,vexpress,config-bridge = <&v2m_sysreg>; v2m_oscclk1: osc@1 { /* CLCD clock */ compatible = "arm,vexpress-osc"; arm,vexpress-sysreg,func = <1 1>; freq-range = <23750000 63500000>; #clock-cells = <0>; clock-output-names = "v2m:oscclk1"; }; /* * Not supported in FVP models * * reset@0 { * compatible = "arm,vexpress-reset"; * arm,vexpress-sysreg,func = <5 0>; * }; */ muxfpga@0 { compatible = "arm,vexpress-muxfpga"; arm,vexpress-sysreg,func = <7 0>; }; /* * Not used - Superseded by PSCI sys_poweroff * * shutdown@0 { * compatible = "arm,vexpress-shutdown"; * arm,vexpress-sysreg,func = <8 0>; * }; */ /* * Not used - Superseded by PSCI sys_reset * * reboot@0 { * compatible = "arm,vexpress-reboot"; * arm,vexpress-sysreg,func = <9 0>; * }; */ dvimode@0 { compatible = "arm,vexpress-dvimode"; arm,vexpress-sysreg,func = <11 0>; }; }; }; trusted-firmware-a-2.2/fdts/rtsm_ve-motherboard.dtsi000066400000000000000000000142751355360272700227320ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ motherboard { arm,v2m-memory-map = "rs1"; compatible = "arm,vexpress,v2m-p1", "simple-bus"; #address-cells = <2>; /* SMB chipselect number and offset */ #size-cells = <1>; ranges; flash@0,00000000 { compatible = "arm,vexpress-flash", "cfi-flash"; reg = <0 0x00000000 0x04000000>, <4 0x00000000 0x04000000>; bank-width = <4>; }; vram@2,00000000 { compatible = "arm,vexpress-vram"; reg = <2 0x00000000 0x00800000>; }; ethernet@2,02000000 { compatible = "smsc,lan91c111"; reg = <2 0x02000000 0x10000>; interrupts = <0 15 4>; }; v2m_clk24mhz: clk24mhz { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <24000000>; clock-output-names = "v2m:clk24mhz"; }; v2m_refclk1mhz: refclk1mhz { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <1000000>; clock-output-names = "v2m:refclk1mhz"; }; v2m_refclk32khz: refclk32khz { compatible = "fixed-clock"; #clock-cells = <0>; clock-frequency = <32768>; clock-output-names = "v2m:refclk32khz"; }; iofpga@3,00000000 { compatible = "arm,amba-bus", "simple-bus"; #address-cells = <1>; #size-cells = <1>; ranges = <0 3 0 0x200000>; v2m_sysreg: sysreg@10000 { compatible = "arm,vexpress-sysreg"; reg = <0x010000 0x1000>; gpio-controller; #gpio-cells = <2>; }; v2m_sysctl: sysctl@20000 { compatible = "arm,sp810", "arm,primecell"; reg = <0x020000 0x1000>; clocks = <&v2m_refclk32khz>, <&v2m_refclk1mhz>, <&v2m_clk24mhz>; clock-names = "refclk", "timclk", "apb_pclk"; #clock-cells = <1>; clock-output-names = "timerclken0", "timerclken1", "timerclken2", "timerclken3"; }; aaci@40000 { compatible = "arm,pl041", "arm,primecell"; reg = <0x040000 0x1000>; interrupts = <0 11 4>; clocks = <&v2m_clk24mhz>; clock-names = "apb_pclk"; }; mmci@50000 { compatible = "arm,pl180", "arm,primecell"; reg = <0x050000 0x1000>; interrupts = <0 9 4 0 10 4>; cd-gpios = <&v2m_sysreg 0 0>; wp-gpios = <&v2m_sysreg 1 0>; max-frequency = <12000000>; vmmc-supply = <&v2m_fixed_3v3>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "mclk", "apb_pclk"; }; kmi@60000 { compatible = "arm,pl050", "arm,primecell"; reg = <0x060000 0x1000>; interrupts = <0 12 4>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "KMIREFCLK", "apb_pclk"; }; kmi@70000 { compatible = "arm,pl050", "arm,primecell"; reg = <0x070000 0x1000>; interrupts = <0 13 4>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "KMIREFCLK", "apb_pclk"; }; v2m_serial0: uart@90000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x090000 0x1000>; interrupts = <0 5 4>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "uartclk", "apb_pclk"; }; v2m_serial1: uart@a0000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0a0000 0x1000>; interrupts = <0 6 4>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "uartclk", "apb_pclk"; }; v2m_serial2: uart@b0000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0b0000 0x1000>; interrupts = <0 7 4>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "uartclk", "apb_pclk"; }; v2m_serial3: uart@c0000 { compatible = "arm,pl011", "arm,primecell"; reg = <0x0c0000 0x1000>; interrupts = <0 8 4>; clocks = <&v2m_clk24mhz>, <&v2m_clk24mhz>; clock-names = "uartclk", "apb_pclk"; }; wdt@f0000 { compatible = "arm,sp805", "arm,primecell"; reg = <0x0f0000 0x1000>; interrupts = <0 0 4>; clocks = <&v2m_refclk32khz>, <&v2m_clk24mhz>; clock-names = "wdogclk", "apb_pclk"; }; v2m_timer01: timer@110000 { compatible = "arm,sp804", "arm,primecell"; reg = <0x110000 0x1000>; interrupts = <0 2 4>; clocks = <&v2m_sysctl 0>, <&v2m_sysctl 1>, <&v2m_clk24mhz>; clock-names = "timclken1", "timclken2", "apb_pclk"; }; v2m_timer23: timer@120000 { compatible = "arm,sp804", "arm,primecell"; reg = <0x120000 0x1000>; interrupts = <0 3 4>; clocks = <&v2m_sysctl 2>, <&v2m_sysctl 3>, <&v2m_clk24mhz>; clock-names = "timclken1", "timclken2", "apb_pclk"; }; rtc@170000 { compatible = "arm,pl031", "arm,primecell"; reg = <0x170000 0x1000>; interrupts = <0 4 4>; clocks = <&v2m_clk24mhz>; clock-names = "apb_pclk"; }; clcd@1f0000 { compatible = "arm,pl111", "arm,primecell"; reg = <0x1f0000 0x1000>; interrupts = <0 14 4>; clocks = <&v2m_oscclk1>, <&v2m_clk24mhz>; clock-names = "clcdclk", "apb_pclk"; mode = "XVGA"; use_dma = <0>; framebuffer = <0x18000000 0x00180000>; }; virtio_block@130000 { compatible = "virtio,mmio"; reg = <0x130000 0x1000>; interrupts = <0 0x2a 4>; }; }; v2m_fixed_3v3: fixedregulator { compatible = "regulator-fixed"; regulator-name = "3V3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; }; mcc { compatible = "arm,vexpress,config-bus", "simple-bus"; arm,vexpress,config-bridge = <&v2m_sysreg>; v2m_oscclk1: osc { /* CLCD clock */ compatible = "arm,vexpress-osc"; arm,vexpress-sysreg,func = <1 1>; freq-range = <23750000 63500000>; #clock-cells = <0>; clock-output-names = "v2m:oscclk1"; }; /* * Not supported in FVP models * * reset@0 { * compatible = "arm,vexpress-reset"; * arm,vexpress-sysreg,func = <5 0>; * }; */ muxfpga { compatible = "arm,vexpress-muxfpga"; arm,vexpress-sysreg,func = <7 0>; }; /* * Not used - Superseded by PSCI sys_poweroff * * shutdown@0 { * compatible = "arm,vexpress-shutdown"; * arm,vexpress-sysreg,func = <8 0>; * }; */ /* * Not used - Superseded by PSCI sys_reset * * reboot@0 { * compatible = "arm,vexpress-reboot"; * arm,vexpress-sysreg,func = <9 0>; * }; */ dvimode { compatible = "arm,vexpress-dvimode"; arm,vexpress-sysreg,func = <11 0>; }; }; }; trusted-firmware-a-2.2/fdts/stm32mp15-ddr.dtsi000066400000000000000000000045021355360272700211610ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* * Copyright (C) 2018, STMicroelectronics - All Rights Reserved */ / { soc { ddr: ddr@5a003000{ compatible = "st,stm32mp1-ddr"; reg = <0x5A003000 0x550 0x5A004000 0x234>; clocks = <&rcc AXIDCG>, <&rcc DDRC1>, <&rcc DDRC2>, <&rcc DDRPHYC>, <&rcc DDRCAPB>, <&rcc DDRPHYCAPB>; clock-names = "axidcg", "ddrc1", "ddrc2", "ddrphyc", "ddrcapb", "ddrphycapb"; st,mem-name = DDR_MEM_NAME; st,mem-speed = ; st,mem-size = ; st,ctl-reg = < DDR_MSTR DDR_MRCTRL0 DDR_MRCTRL1 DDR_DERATEEN DDR_DERATEINT DDR_PWRCTL DDR_PWRTMG DDR_HWLPCTL DDR_RFSHCTL0 DDR_RFSHCTL3 DDR_CRCPARCTL0 DDR_ZQCTL0 DDR_DFITMG0 DDR_DFITMG1 DDR_DFILPCFG0 DDR_DFIUPD0 DDR_DFIUPD1 DDR_DFIUPD2 DDR_DFIPHYMSTR DDR_ODTMAP DDR_DBG0 DDR_DBG1 DDR_DBGCMD DDR_POISONCFG DDR_PCCFG >; st,ctl-timing = < DDR_RFSHTMG DDR_DRAMTMG0 DDR_DRAMTMG1 DDR_DRAMTMG2 DDR_DRAMTMG3 DDR_DRAMTMG4 DDR_DRAMTMG5 DDR_DRAMTMG6 DDR_DRAMTMG7 DDR_DRAMTMG8 DDR_DRAMTMG14 DDR_ODTCFG >; st,ctl-map = < DDR_ADDRMAP1 DDR_ADDRMAP2 DDR_ADDRMAP3 DDR_ADDRMAP4 DDR_ADDRMAP5 DDR_ADDRMAP6 DDR_ADDRMAP9 DDR_ADDRMAP10 DDR_ADDRMAP11 >; st,ctl-perf = < DDR_SCHED DDR_SCHED1 DDR_PERFHPR1 DDR_PERFLPR1 DDR_PERFWR1 DDR_PCFGR_0 DDR_PCFGW_0 DDR_PCFGQOS0_0 DDR_PCFGQOS1_0 DDR_PCFGWQOS0_0 DDR_PCFGWQOS1_0 DDR_PCFGR_1 DDR_PCFGW_1 DDR_PCFGQOS0_1 DDR_PCFGQOS1_1 DDR_PCFGWQOS0_1 DDR_PCFGWQOS1_1 >; st,phy-reg = < DDR_PGCR DDR_ACIOCR DDR_DXCCR DDR_DSGCR DDR_DCR DDR_ODTCR DDR_ZQ0CR1 DDR_DX0GCR DDR_DX1GCR DDR_DX2GCR DDR_DX3GCR >; st,phy-timing = < DDR_PTR0 DDR_PTR1 DDR_PTR2 DDR_DTPR0 DDR_DTPR1 DDR_DTPR2 DDR_MR0 DDR_MR1 DDR_MR2 DDR_MR3 >; st,phy-cal = < DDR_DX0DLLCR DDR_DX0DQTR DDR_DX0DQSTR DDR_DX1DLLCR DDR_DX1DQTR DDR_DX1DQSTR DDR_DX2DLLCR DDR_DX2DQTR DDR_DX2DQSTR DDR_DX3DLLCR DDR_DX3DQTR DDR_DX3DQSTR >; status = "okay"; }; }; }; trusted-firmware-a-2.2/fdts/stm32mp15-ddr3-1x4Gb-1066-binG.dtsi000066400000000000000000000070451355360272700234030ustar00rootroot00000000000000// 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.45" #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 0xF200011F #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 0x0000CE80 #define DDR_DX2DLLCR 0x40000000 #define DDR_DX2DQTR 0xFFFFFFFF #define DDR_DX2DQSTR 0x3DB02000 #define DDR_DX3GCR 0x0000CE80 #define DDR_DX3DLLCR 0x40000000 #define DDR_DX3DQTR 0xFFFFFFFF #define DDR_DX3DQSTR 0x3DB02000 #include "stm32mp15-ddr.dtsi" trusted-firmware-a-2.2/fdts/stm32mp15-ddr3-2x4Gb-1066-binG.dtsi000066400000000000000000000071141355360272700234010ustar00rootroot00000000000000// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause /* * Copyright (C) 2018, STMicroelectronics - All Rights Reserved * * STM32MP157C ED1 BOARD configuration * 2x DDR3L 4Gb each, 16-bit, 533MHz, Single Die Package in flyby topology. * Reference used NT5CC256M16DP-DI from NANYA * * DDR type / Platform DDR3/3L * freq 533MHz * width 32 * datasheet 0 = MT41J256M16-187 / DDR3-1066 bin G * DDR density 8 * timing mode optimized * Scheduling/QoS options : type = 2 * address mapping : RBC * Tc > + 85C : N */ #define DDR_MEM_NAME "DDR3-1066/888 bin G 2x4Gb 533MHz v1.45" #define DDR_MEM_SPEED 533000 #define DDR_MEM_SIZE 0x40000000 #define DDR_MSTR 0x00040401 #define DDR_MRCTRL0 0x00000010 #define DDR_MRCTRL1 0x00000000 #define DDR_DERATEEN 0x00000000 #define DDR_DERATEINT 0x00800000 #define DDR_PWRCTL 0x00000000 #define DDR_PWRTMG 0x00400010 #define DDR_HWLPCTL 0x00000000 #define DDR_RFSHCTL0 0x00210000 #define DDR_RFSHCTL3 0x00000000 #define DDR_RFSHTMG 0x0081008B #define DDR_CRCPARCTL0 0x00000000 #define DDR_DRAMTMG0 0x121B2414 #define DDR_DRAMTMG1 0x000A041C #define DDR_DRAMTMG2 0x0608090F #define DDR_DRAMTMG3 0x0050400C #define DDR_DRAMTMG4 0x08040608 #define DDR_DRAMTMG5 0x06060403 #define DDR_DRAMTMG6 0x02020002 #define DDR_DRAMTMG7 0x00000202 #define DDR_DRAMTMG8 0x00001005 #define DDR_DRAMTMG14 0x000000A0 #define DDR_ZQCTL0 0xC2000040 #define DDR_DFITMG0 0x02060105 #define DDR_DFITMG1 0x00000202 #define DDR_DFILPCFG0 0x07000000 #define DDR_DFIUPD0 0xC0400003 #define DDR_DFIUPD1 0x00000000 #define DDR_DFIUPD2 0x00000000 #define DDR_DFIPHYMSTR 0x00000000 #define DDR_ADDRMAP1 0x00080808 #define DDR_ADDRMAP2 0x00000000 #define DDR_ADDRMAP3 0x00000000 #define DDR_ADDRMAP4 0x00001F1F #define DDR_ADDRMAP5 0x07070707 #define DDR_ADDRMAP6 0x0F070707 #define DDR_ADDRMAP9 0x00000000 #define DDR_ADDRMAP10 0x00000000 #define DDR_ADDRMAP11 0x00000000 #define DDR_ODTCFG 0x06000600 #define DDR_ODTMAP 0x00000001 #define DDR_SCHED 0x00000C01 #define DDR_SCHED1 0x00000000 #define DDR_PERFHPR1 0x01000001 #define DDR_PERFLPR1 0x08000200 #define DDR_PERFWR1 0x08000400 #define DDR_DBG0 0x00000000 #define DDR_DBG1 0x00000000 #define DDR_DBGCMD 0x00000000 #define DDR_POISONCFG 0x00000000 #define DDR_PCCFG 0x00000010 #define DDR_PCFGR_0 0x00010000 #define DDR_PCFGW_0 0x00000000 #define DDR_PCFGQOS0_0 0x02100C03 #define DDR_PCFGQOS1_0 0x00800100 #define DDR_PCFGWQOS0_0 0x01100C03 #define DDR_PCFGWQOS1_0 0x01000200 #define DDR_PCFGR_1 0x00010000 #define DDR_PCFGW_1 0x00000000 #define DDR_PCFGQOS0_1 0x02100C03 #define DDR_PCFGQOS1_1 0x00800040 #define DDR_PCFGWQOS0_1 0x01100C03 #define DDR_PCFGWQOS1_1 0x01000200 #define DDR_PGCR 0x01442E02 #define DDR_PTR0 0x0022AA5B #define DDR_PTR1 0x04841104 #define DDR_PTR2 0x042DA068 #define DDR_ACIOCR 0x10400812 #define DDR_DXCCR 0x00000C40 #define DDR_DSGCR 0xF200011F #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" trusted-firmware-a-2.2/fdts/stm32mp157-pinctrl.dtsi000066400000000000000000000201631355360272700221530ustar00rootroot00000000000000// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* * Copyright (C) STMicroelectronics 2017 - All Rights Reserved * Author: Ludovic Barre for STMicroelectronics. */ #include / { soc { pinctrl: pin-controller@50002000 { #address-cells = <1>; #size-cells = <1>; compatible = "st,stm32mp157-pinctrl"; ranges = <0 0x50002000 0xa400>; pins-are-numbered; gpioa: gpio@50002000 { gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; reg = <0x0 0x400>; clocks = <&rcc GPIOA>; st,bank-name = "GPIOA"; status = "disabled"; }; gpiob: gpio@50003000 { gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; reg = <0x1000 0x400>; clocks = <&rcc GPIOB>; st,bank-name = "GPIOB"; status = "disabled"; }; gpioc: gpio@50004000 { gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; reg = <0x2000 0x400>; clocks = <&rcc GPIOC>; st,bank-name = "GPIOC"; status = "disabled"; }; gpiod: gpio@50005000 { gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; reg = <0x3000 0x400>; clocks = <&rcc GPIOD>; st,bank-name = "GPIOD"; status = "disabled"; }; gpioe: gpio@50006000 { gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; reg = <0x4000 0x400>; clocks = <&rcc GPIOE>; st,bank-name = "GPIOE"; status = "disabled"; }; gpiof: gpio@50007000 { gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; reg = <0x5000 0x400>; clocks = <&rcc GPIOF>; st,bank-name = "GPIOF"; status = "disabled"; }; gpiog: gpio@50008000 { gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; reg = <0x6000 0x400>; clocks = <&rcc GPIOG>; st,bank-name = "GPIOG"; status = "disabled"; }; gpioh: gpio@50009000 { gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; reg = <0x7000 0x400>; clocks = <&rcc GPIOH>; st,bank-name = "GPIOH"; status = "disabled"; }; gpioi: gpio@5000a000 { gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; reg = <0x8000 0x400>; clocks = <&rcc GPIOI>; st,bank-name = "GPIOI"; status = "disabled"; }; gpioj: gpio@5000b000 { gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; reg = <0x9000 0x400>; clocks = <&rcc GPIOJ>; st,bank-name = "GPIOJ"; status = "disabled"; }; gpiok: gpio@5000c000 { gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; reg = <0xa000 0x400>; clocks = <&rcc GPIOK>; st,bank-name = "GPIOK"; status = "disabled"; }; qspi_bk1_pins_a: qspi-bk1-0 { pins1 { pinmux = , /* QSPI_BK1_IO0 */ , /* QSPI_BK1_IO1 */ , /* QSPI_BK1_IO2 */ ; /* QSPI_BK1_IO3 */ bias-disable; drive-push-pull; slew-rate = <1>; }; pins2 { pinmux = ; /* QSPI_BK1_NCS */ bias-pull-up; drive-push-pull; slew-rate = <1>; }; }; qspi_bk2_pins_a: qspi-bk2-0 { pins1 { pinmux = , /* QSPI_BK2_IO0 */ , /* QSPI_BK2_IO1 */ , /* QSPI_BK2_IO2 */ ; /* QSPI_BK2_IO3 */ bias-disable; drive-push-pull; slew-rate = <1>; }; pins2 { pinmux = ; /* QSPI_BK2_NCS */ bias-pull-up; drive-push-pull; slew-rate = <1>; }; }; qspi_clk_pins_a: qspi-clk-0 { pins { pinmux = ; /* QSPI_CLK */ bias-disable; drive-push-pull; slew-rate = <3>; }; }; sdmmc1_b4_pins_a: sdmmc1-b4-0 { pins1 { pinmux = , /* SDMMC1_D0 */ , /* SDMMC1_D1 */ , /* SDMMC1_D2 */ , /* SDMMC1_D3 */ ; /* SDMMC1_CMD */ slew-rate = <1>; drive-push-pull; bias-disable; }; pins2 { pinmux = ; /* SDMMC1_CK */ slew-rate = <2>; drive-push-pull; bias-disable; }; }; sdmmc1_dir_pins_a: sdmmc1-dir-0 { pins1 { pinmux = , /* SDMMC1_D0DIR */ , /* SDMMC1_D123DIR */ ; /* SDMMC1_CDIR */ slew-rate = <1>; drive-push-pull; bias-pull-up; }; pins2{ pinmux = ; /* SDMMC1_CKIN */ bias-pull-up; }; }; sdmmc2_b4_pins_a: sdmmc2-b4-0 { pins1 { pinmux = , /* SDMMC2_D0 */ , /* SDMMC2_D1 */ , /* SDMMC2_D2 */ , /* SDMMC2_D3 */ ; /* SDMMC2_CMD */ slew-rate = <1>; drive-push-pull; bias-pull-up; }; pins2 { pinmux = ; /* SDMMC2_CK */ slew-rate = <2>; drive-push-pull; bias-pull-up; }; }; sdmmc2_d47_pins_a: sdmmc2-d47-0 { pins { pinmux = , /* SDMMC2_D4 */ , /* SDMMC2_D5 */ , /* SDMMC2_D6 */ ; /* SDMMC2_D7 */ slew-rate = <1>; drive-push-pull; bias-pull-up; }; }; uart4_pins_a: uart4-0 { pins1 { pinmux = ; /* UART4_TX */ bias-disable; drive-push-pull; slew-rate = <0>; }; pins2 { pinmux = ; /* UART4_RX */ bias-disable; }; }; uart4_pins_b: uart4-1 { pins1 { pinmux = ; /* UART4_TX */ bias-disable; drive-push-pull; slew-rate = <0>; }; pins2 { pinmux = ; /* UART4_RX */ bias-disable; }; }; uart7_pins_a: uart7-0 { pins1 { pinmux = ; /* USART7_TX */ bias-disable; drive-push-pull; slew-rate = <0>; }; pins2 { pinmux = ; /* USART7_RX */ bias-disable; }; }; usart3_pins_a: usart3-0 { pins1 { pinmux = , /* USART3_TX */ ; /* USART3_RTS */ bias-disable; drive-push-pull; slew-rate = <0>; }; pins2 { pinmux = , /* USART3_RX */ ; /* USART3_CTS_NSS */ bias-disable; }; }; usart3_pins_b: usart3-1 { pins1 { pinmux = , /* USART3_TX */ ; /* USART3_RTS */ bias-disable; drive-push-pull; slew-rate = <0>; }; pins2 { pinmux = , /* USART3_RX */ ; /* USART3_CTS_NSS */ bias-disable; }; }; }; pinctrl_z: pin-controller-z@54004000 { #address-cells = <1>; #size-cells = <1>; compatible = "st,stm32mp157-z-pinctrl"; ranges = <0 0x54004000 0x400>; pins-are-numbered; gpioz: gpio@54004000 { gpio-controller; #gpio-cells = <2>; interrupt-controller; #interrupt-cells = <2>; reg = <0 0x400>; clocks = <&rcc GPIOZ>; st,bank-name = "GPIOZ"; st,bank-ioport = <11>; status = "disabled"; }; i2c4_pins_a: i2c4-0 { pins { pinmux = , /* I2C4_SCL */ ; /* I2C4_SDA */ bias-disable; drive-open-drain; slew-rate = <0>; }; }; }; }; }; trusted-firmware-a-2.2/fdts/stm32mp157a-avenger96.dts000066400000000000000000000126401355360272700222770ustar00rootroot00000000000000// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* * Copyright (C) Arrow Electronics 2019 - All Rights Reserved * Author: Botond Kardos * * Copyright (C) Linaro Ltd 2019 - All Rights Reserved * Author: Manivannan Sadhasivam */ /dts-v1/; #include "stm32mp157c.dtsi" #include "stm32mp157cac-pinctrl.dtsi" / { model = "Arrow Electronics STM32MP157A Avenger96 board"; compatible = "st,stm32mp157a-avenger96", "st,stm32mp157"; aliases { serial0 = &uart4; }; chosen { stdout-path = "serial0:115200n8"; }; }; &i2c4 { pinctrl-names = "default"; pinctrl-0 = <&i2c4_pins_a>; i2c-scl-rising-time-ns = <185>; i2c-scl-falling-time-ns = <20>; status = "okay"; pmic: stpmic@33 { compatible = "st,stpmic1"; reg = <0x33>; interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; interrupt-controller; #interrupt-cells = <2>; status = "okay"; st,main-control-register = <0x04>; st,vin-control-register = <0xc0>; st,usb-control-register = <0x20>; regulators { compatible = "st,stpmic1-regulators"; ldo1-supply = <&v3v3>; ldo2-supply = <&v3v3>; ldo3-supply = <&vdd_ddr>; ldo5-supply = <&v3v3>; ldo6-supply = <&v3v3>; vddcore: buck1 { regulator-name = "vddcore"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1350000>; regulator-always-on; regulator-initial-mode = <0>; regulator-over-current-protection; }; vdd_ddr: buck2 { regulator-name = "vdd_ddr"; regulator-min-microvolt = <1350000>; regulator-max-microvolt = <1350000>; regulator-always-on; regulator-initial-mode = <0>; regulator-over-current-protection; }; vdd: buck3 { regulator-name = "vdd"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; st,mask-reset; regulator-initial-mode = <0>; regulator-over-current-protection; }; v3v3: buck4 { regulator-name = "v3v3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; regulator-over-current-protection; regulator-initial-mode = <0>; }; vdda: ldo1 { regulator-name = "vdda"; regulator-min-microvolt = <2900000>; regulator-max-microvolt = <2900000>; }; v2v8: ldo2 { regulator-name = "v2v8"; regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; }; vtt_ddr: ldo3 { regulator-name = "vtt_ddr"; regulator-min-microvolt = <500000>; regulator-max-microvolt = <750000>; regulator-always-on; regulator-over-current-protection; }; vdd_usb: ldo4 { regulator-name = "vdd_usb"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; }; vdd_sd: ldo5 { regulator-name = "vdd_sd"; regulator-min-microvolt = <2900000>; regulator-max-microvolt = <2900000>; regulator-boot-on; }; v1v8: ldo6 { regulator-name = "v1v8"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; vref_ddr: vref_ddr { regulator-name = "vref_ddr"; regulator-always-on; regulator-over-current-protection; }; }; }; }; &iwdg2 { timeout-sec = <32>; status = "okay"; }; &rng1 { status = "okay"; }; &rtc { status = "okay"; }; &sdmmc1 { pinctrl-names = "default"; pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>; broken-cd; st,sig-dir; st,neg-edge; st,use-ckin; bus-width = <4>; vmmc-supply = <&vdda>; status = "okay"; }; &uart4 { pinctrl-names = "default"; pinctrl-0 = <&uart4_pins_b>; status = "okay"; }; /* ATF Specific */ #include #include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi" #include "stm32mp157c-security.dtsi" / { aliases { gpio0 = &gpioa; gpio1 = &gpiob; gpio2 = &gpioc; gpio3 = &gpiod; gpio4 = &gpioe; gpio5 = &gpiof; gpio6 = &gpiog; gpio7 = &gpioh; gpio8 = &gpioi; gpio25 = &gpioz; i2c3 = &i2c4; }; }; /* CLOCK init */ &rcc { secure-status = "disabled"; st,clksrc = < CLK_MPU_PLL1P CLK_AXI_PLL2P CLK_MCU_PLL3P CLK_PLL12_HSE CLK_PLL3_HSE CLK_PLL4_HSE CLK_RTC_LSE CLK_MCO1_DISABLED CLK_MCO2_DISABLED >; st,clkdiv = < 1 /*MPU*/ 0 /*AXI*/ 0 /*MCU*/ 1 /*APB1*/ 1 /*APB2*/ 1 /*APB3*/ 1 /*APB4*/ 2 /*APB5*/ 23 /*RTC*/ 0 /*MCO1*/ 0 /*MCO2*/ >; st,pkcs = < CLK_CKPER_HSE CLK_FMC_ACLK CLK_QSPI_ACLK CLK_ETH_DISABLED CLK_SDMMC12_PLL4P CLK_DSI_DSIPLL CLK_STGEN_HSE CLK_USBPHY_HSE CLK_SPI2S1_PLL3Q CLK_SPI2S23_PLL3Q CLK_SPI45_HSI CLK_SPI6_HSI CLK_I2C46_HSI CLK_SDMMC3_PLL4P CLK_USBO_USBPHY CLK_ADC_CKPER CLK_CEC_LSE CLK_I2C12_HSI CLK_I2C35_HSI CLK_UART1_HSI CLK_UART24_HSI CLK_UART35_HSI CLK_UART6_HSI CLK_UART78_HSI CLK_SPDIF_PLL4P CLK_FDCAN_PLL4R CLK_SAI1_PLL3Q CLK_SAI2_PLL3Q CLK_SAI3_PLL3Q CLK_SAI4_PLL3Q CLK_RNG1_LSI CLK_RNG2_LSI CLK_LPTIM1_PCLK1 CLK_LPTIM23_PCLK3 CLK_LPTIM45_LSE >; /* VCO = 1300.0 MHz => P = 650 (CPU) */ pll1: st,pll@0 { cfg = < 2 80 0 0 0 PQR(1,0,0) >; frac = < 0x800 >; }; /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ pll2: st,pll@1 { cfg = < 2 65 1 0 0 PQR(1,1,1) >; frac = < 0x1400 >; }; /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */ pll3: st,pll@2 { cfg = < 1 33 1 16 36 PQR(1,1,1) >; frac = < 0x1a04 >; }; /* VCO = 480.0 MHz => P = 120, Q = 40, R = 96 */ pll4: st,pll@3 { cfg = < 1 39 3 11 4 PQR(1,1,1) >; }; }; trusted-firmware-a-2.2/fdts/stm32mp157a-dk1.dts000066400000000000000000000133151355360272700211500ustar00rootroot00000000000000// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* * Copyright (C) STMicroelectronics 2018-2019 - All Rights Reserved * Author: Alexandre Torgue . */ /dts-v1/; #include "stm32mp157c.dtsi" #include "stm32mp157cac-pinctrl.dtsi" / { model = "STMicroelectronics STM32MP157A-DK1 Discovery Board"; compatible = "st,stm32mp157a-dk1", "st,stm32mp157"; aliases { serial0 = &uart4; serial1 = &usart3; serial2 = &uart7; }; chosen { stdout-path = "serial0:115200n8"; }; }; &clk_hse { st,digbypass; }; &i2c4 { pinctrl-names = "default"; pinctrl-0 = <&i2c4_pins_a>; i2c-scl-rising-time-ns = <185>; i2c-scl-falling-time-ns = <20>; status = "okay"; pmic: stpmic@33 { compatible = "st,stpmic1"; reg = <0x33>; interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; interrupt-controller; #interrupt-cells = <2>; status = "okay"; st,main-control-register = <0x04>; st,vin-control-register = <0xc0>; st,usb-control-register = <0x20>; regulators { compatible = "st,stpmic1-regulators"; ldo1-supply = <&v3v3>; ldo3-supply = <&vdd_ddr>; ldo6-supply = <&v3v3>; vddcore: buck1 { regulator-name = "vddcore"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1350000>; regulator-always-on; regulator-initial-mode = <0>; regulator-over-current-protection; }; vdd_ddr: buck2 { regulator-name = "vdd_ddr"; regulator-min-microvolt = <1350000>; regulator-max-microvolt = <1350000>; regulator-always-on; regulator-initial-mode = <0>; regulator-over-current-protection; }; vdd: buck3 { regulator-name = "vdd"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; st,mask-reset; regulator-initial-mode = <0>; regulator-over-current-protection; }; v3v3: buck4 { regulator-name = "v3v3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; regulator-over-current-protection; regulator-initial-mode = <0>; }; v1v8_audio: ldo1 { regulator-name = "v1v8_audio"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; regulator-always-on; }; v3v3_hdmi: ldo2 { regulator-name = "v3v3_hdmi"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; }; vtt_ddr: ldo3 { regulator-name = "vtt_ddr"; regulator-min-microvolt = <500000>; regulator-max-microvolt = <750000>; regulator-always-on; regulator-over-current-protection; }; vdd_usb: ldo4 { regulator-name = "vdd_usb"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; }; vdda: ldo5 { regulator-name = "vdda"; regulator-min-microvolt = <2900000>; regulator-max-microvolt = <2900000>; regulator-boot-on; }; v1v2_hdmi: ldo6 { regulator-name = "v1v2_hdmi"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1200000>; regulator-always-on; }; vref_ddr: vref_ddr { regulator-name = "vref_ddr"; regulator-always-on; regulator-over-current-protection; }; }; }; }; &iwdg2 { timeout-sec = <32>; status = "okay"; }; &pwr { pwr-regulators { vdd-supply = <&vdd>; }; }; &rng1 { status = "okay"; }; &rtc { status = "okay"; }; &sdmmc1 { pinctrl-names = "default"; pinctrl-0 = <&sdmmc1_b4_pins_a>; broken-cd; st,neg-edge; bus-width = <4>; vmmc-supply = <&v3v3>; status = "okay"; }; &uart4 { pinctrl-names = "default"; pinctrl-0 = <&uart4_pins_a>; status = "okay"; }; &uart7 { pinctrl-names = "default"; pinctrl-0 = <&uart7_pins_a>; status = "disabled"; }; &usart3 { pinctrl-names = "default"; pinctrl-0 = <&usart3_pins_b>; status = "disabled"; }; /* ATF Specific */ #include #include "stm32mp15-ddr3-1x4Gb-1066-binG.dtsi" #include "stm32mp157c-security.dtsi" / { aliases { gpio0 = &gpioa; gpio1 = &gpiob; gpio2 = &gpioc; gpio3 = &gpiod; gpio4 = &gpioe; gpio5 = &gpiof; gpio6 = &gpiog; gpio7 = &gpioh; gpio8 = &gpioi; gpio25 = &gpioz; i2c3 = &i2c4; }; }; /* CLOCK init */ &rcc { secure-status = "disabled"; st,clksrc = < CLK_MPU_PLL1P CLK_AXI_PLL2P CLK_MCU_PLL3P CLK_PLL12_HSE CLK_PLL3_HSE CLK_PLL4_HSE CLK_RTC_LSE CLK_MCO1_DISABLED CLK_MCO2_DISABLED >; st,clkdiv = < 1 /*MPU*/ 0 /*AXI*/ 0 /*MCU*/ 1 /*APB1*/ 1 /*APB2*/ 1 /*APB3*/ 1 /*APB4*/ 2 /*APB5*/ 23 /*RTC*/ 0 /*MCO1*/ 0 /*MCO2*/ >; st,pkcs = < CLK_CKPER_HSE CLK_FMC_ACLK CLK_QSPI_ACLK CLK_ETH_DISABLED CLK_SDMMC12_PLL4P CLK_DSI_DSIPLL CLK_STGEN_HSE CLK_USBPHY_HSE CLK_SPI2S1_PLL3Q CLK_SPI2S23_PLL3Q CLK_SPI45_HSI CLK_SPI6_HSI CLK_I2C46_HSI CLK_SDMMC3_PLL4P CLK_USBO_USBPHY CLK_ADC_CKPER CLK_CEC_LSE CLK_I2C12_HSI CLK_I2C35_HSI CLK_UART1_HSI CLK_UART24_HSI CLK_UART35_HSI CLK_UART6_HSI CLK_UART78_HSI CLK_SPDIF_PLL4P CLK_FDCAN_PLL4R CLK_SAI1_PLL3Q CLK_SAI2_PLL3Q CLK_SAI3_PLL3Q CLK_SAI4_PLL3Q CLK_RNG1_LSI CLK_RNG2_LSI CLK_LPTIM1_PCLK1 CLK_LPTIM23_PCLK3 CLK_LPTIM45_LSE >; /* VCO = 1300.0 MHz => P = 650 (CPU) */ pll1: st,pll@0 { cfg = < 2 80 0 0 0 PQR(1,0,0) >; frac = < 0x800 >; }; /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ pll2: st,pll@1 { cfg = < 2 65 1 0 0 PQR(1,1,1) >; frac = < 0x1400 >; }; /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */ pll3: st,pll@2 { cfg = < 1 33 1 16 36 PQR(1,1,1) >; frac = < 0x1a04 >; }; /* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */ pll4: st,pll@3 { cfg = < 3 98 5 7 7 PQR(1,1,1) >; }; }; &bsec { board_id: board_id@ec { reg = <0xec 0x4>; status = "okay"; secure-status = "okay"; }; }; trusted-firmware-a-2.2/fdts/stm32mp157c-dk2.dts000066400000000000000000000005351355360272700211530ustar00rootroot00000000000000// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* * Copyright (C) STMicroelectronics 2018 - All Rights Reserved * Author: Alexandre Torgue . */ /dts-v1/; #include "stm32mp157a-dk1.dts" / { model = "STMicroelectronics STM32MP157C-DK2 Discovery Board"; compatible = "st,stm32mp157c-dk2", "st,stm32mp157"; }; trusted-firmware-a-2.2/fdts/stm32mp157c-ed1.dts000066400000000000000000000135221355360272700211440ustar00rootroot00000000000000// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* * Copyright (C) STMicroelectronics 2017-2019 - All Rights Reserved * Author: Ludovic Barre for STMicroelectronics. */ /dts-v1/; #include "stm32mp157c.dtsi" #include "stm32mp157caa-pinctrl.dtsi" / { model = "STMicroelectronics STM32MP157C eval daughter"; compatible = "st,stm32mp157c-ed1", "st,stm32mp157"; chosen { stdout-path = "serial0:115200n8"; }; aliases { serial0 = &uart4; }; }; &clk_hse { st,digbypass; }; &i2c4 { pinctrl-names = "default"; pinctrl-0 = <&i2c4_pins_a>; i2c-scl-rising-time-ns = <185>; i2c-scl-falling-time-ns = <20>; status = "okay"; pmic: stpmic@33 { compatible = "st,stpmic1"; reg = <0x33>; interrupts-extended = <&exti_pwr 55 IRQ_TYPE_EDGE_FALLING>; interrupt-controller; #interrupt-cells = <2>; status = "okay"; st,main-control-register = <0x04>; st,vin-control-register = <0xc0>; st,usb-control-register = <0x20>; regulators { compatible = "st,stpmic1-regulators"; ldo1-supply = <&v3v3>; ldo2-supply = <&v3v3>; ldo3-supply = <&vdd_ddr>; ldo5-supply = <&v3v3>; ldo6-supply = <&v3v3>; vddcore: buck1 { regulator-name = "vddcore"; regulator-min-microvolt = <1200000>; regulator-max-microvolt = <1350000>; regulator-always-on; regulator-initial-mode = <0>; regulator-over-current-protection; }; vdd_ddr: buck2 { regulator-name = "vdd_ddr"; regulator-min-microvolt = <1350000>; regulator-max-microvolt = <1350000>; regulator-always-on; regulator-initial-mode = <0>; regulator-over-current-protection; }; vdd: buck3 { regulator-name = "vdd"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; st,mask-reset; regulator-initial-mode = <0>; regulator-over-current-protection; }; v3v3: buck4 { regulator-name = "v3v3"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; regulator-always-on; regulator-over-current-protection; regulator-initial-mode = <0>; }; vdda: ldo1 { regulator-name = "vdda"; regulator-min-microvolt = <2900000>; regulator-max-microvolt = <2900000>; }; v2v8: ldo2 { regulator-name = "v2v8"; regulator-min-microvolt = <2800000>; regulator-max-microvolt = <2800000>; }; vtt_ddr: ldo3 { regulator-name = "vtt_ddr"; regulator-min-microvolt = <500000>; regulator-max-microvolt = <750000>; regulator-always-on; regulator-over-current-protection; }; vdd_usb: ldo4 { regulator-name = "vdd_usb"; regulator-min-microvolt = <3300000>; regulator-max-microvolt = <3300000>; }; vdd_sd: ldo5 { regulator-name = "vdd_sd"; regulator-min-microvolt = <2900000>; regulator-max-microvolt = <2900000>; regulator-boot-on; }; v1v8: ldo6 { regulator-name = "v1v8"; regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; }; vref_ddr: vref_ddr { regulator-name = "vref_ddr"; regulator-always-on; regulator-over-current-protection; }; }; }; }; &iwdg2 { timeout-sec = <32>; status = "okay"; }; &pwr { pwr-regulators { vdd-supply = <&vdd>; }; }; &rng1 { status = "okay"; }; &rtc { status = "okay"; }; &sdmmc1 { pinctrl-names = "default"; pinctrl-0 = <&sdmmc1_b4_pins_a &sdmmc1_dir_pins_a>; broken-cd; st,sig-dir; st,neg-edge; st,use-ckin; bus-width = <4>; vmmc-supply = <&vdd_sd>; sd-uhs-sdr12; sd-uhs-sdr25; sd-uhs-sdr50; sd-uhs-ddr50; sd-uhs-sdr104; status = "okay"; }; &sdmmc2 { pinctrl-names = "default"; pinctrl-0 = <&sdmmc2_b4_pins_a &sdmmc2_d47_pins_a>; non-removable; no-sd; no-sdio; st,neg-edge; bus-width = <8>; vmmc-supply = <&v3v3>; vqmmc-supply = <&v3v3>; mmc-ddr-3_3v; status = "okay"; }; &uart4 { pinctrl-names = "default"; pinctrl-0 = <&uart4_pins_a>; status = "okay"; }; /* ATF Specific */ #include #include "stm32mp15-ddr3-2x4Gb-1066-binG.dtsi" #include "stm32mp157c-security.dtsi" / { aliases { gpio0 = &gpioa; gpio1 = &gpiob; gpio2 = &gpioc; gpio3 = &gpiod; gpio4 = &gpioe; gpio5 = &gpiof; gpio6 = &gpiog; gpio7 = &gpioh; gpio8 = &gpioi; gpio9 = &gpioj; gpio10 = &gpiok; gpio25 = &gpioz; i2c3 = &i2c4; }; }; /* CLOCK init */ &rcc { secure-status = "disabled"; st,clksrc = < CLK_MPU_PLL1P CLK_AXI_PLL2P CLK_MCU_PLL3P CLK_PLL12_HSE CLK_PLL3_HSE CLK_PLL4_HSE CLK_RTC_LSE CLK_MCO1_DISABLED CLK_MCO2_DISABLED >; st,clkdiv = < 1 /*MPU*/ 0 /*AXI*/ 0 /*MCU*/ 1 /*APB1*/ 1 /*APB2*/ 1 /*APB3*/ 1 /*APB4*/ 2 /*APB5*/ 23 /*RTC*/ 0 /*MCO1*/ 0 /*MCO2*/ >; st,pkcs = < CLK_CKPER_HSE CLK_FMC_ACLK CLK_QSPI_ACLK CLK_ETH_DISABLED CLK_SDMMC12_PLL4P CLK_DSI_DSIPLL CLK_STGEN_HSE CLK_USBPHY_HSE CLK_SPI2S1_PLL3Q CLK_SPI2S23_PLL3Q CLK_SPI45_HSI CLK_SPI6_HSI CLK_I2C46_HSI CLK_SDMMC3_PLL4P CLK_USBO_USBPHY CLK_ADC_CKPER CLK_CEC_LSE CLK_I2C12_HSI CLK_I2C35_HSI CLK_UART1_HSI CLK_UART24_HSI CLK_UART35_HSI CLK_UART6_HSI CLK_UART78_HSI CLK_SPDIF_PLL4P CLK_FDCAN_PLL4R CLK_SAI1_PLL3Q CLK_SAI2_PLL3Q CLK_SAI3_PLL3Q CLK_SAI4_PLL3Q CLK_RNG1_LSI CLK_RNG2_LSI CLK_LPTIM1_PCLK1 CLK_LPTIM23_PCLK3 CLK_LPTIM45_LSE >; /* VCO = 1300.0 MHz => P = 650 (CPU) */ pll1: st,pll@0 { cfg = < 2 80 0 0 0 PQR(1,0,0) >; frac = < 0x800 >; }; /* VCO = 1066.0 MHz => P = 266 (AXI), Q = 533 (GPU), R = 533 (DDR) */ pll2: st,pll@1 { cfg = < 2 65 1 0 0 PQR(1,1,1) >; frac = < 0x1400 >; }; /* VCO = 417.8 MHz => P = 209, Q = 24, R = 11 */ pll3: st,pll@2 { cfg = < 1 33 1 16 36 PQR(1,1,1) >; frac = < 0x1a04 >; }; /* VCO = 594.0 MHz => P = 99, Q = 74, R = 74 */ pll4: st,pll@3 { cfg = < 3 98 5 7 7 PQR(1,1,1) >; }; }; &bsec { board_id: board_id@ec { reg = <0xec 0x4>; status = "okay"; secure-status = "okay"; }; }; trusted-firmware-a-2.2/fdts/stm32mp157c-ev1.dts000066400000000000000000000024631355360272700211700ustar00rootroot00000000000000// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* * Copyright (C) STMicroelectronics 2017 - All Rights Reserved * Author: Ludovic Barre for STMicroelectronics. */ /dts-v1/; #include "stm32mp157c-ed1.dts" / { model = "STMicroelectronics STM32MP157C eval daughter on eval mother"; compatible = "st,stm32mp157c-ev1", "st,stm32mp157c-ed1", "st,stm32mp157"; chosen { stdout-path = "serial0:115200n8"; }; aliases { serial1 = &usart3; }; }; &fmc { status = "okay"; #address-cells = <1>; #size-cells = <0>; nand: nand@0 { reg = <0>; nand-on-flash-bbt; #address-cells = <1>; #size-cells = <1>; }; }; &qspi { pinctrl-names = "default"; pinctrl-0 = <&qspi_clk_pins_a &qspi_bk1_pins_a &qspi_bk2_pins_a>; reg = <0x58003000 0x1000>, <0x70000000 0x4000000>; #address-cells = <1>; #size-cells = <0>; status = "okay"; flash0: mx66l51235l@0 { compatible = "jedec,spi-nor"; reg = <0>; spi-rx-bus-width = <4>; spi-max-frequency = <108000000>; #address-cells = <1>; #size-cells = <1>; }; flash1: mx66l51235l@1 { compatible = "jedec,spi-nor"; reg = <1>; spi-rx-bus-width = <4>; spi-max-frequency = <108000000>; #address-cells = <1>; #size-cells = <1>; }; }; &usart3 { pinctrl-names = "default"; pinctrl-0 = <&usart3_pins_a>; status = "disabled"; }; trusted-firmware-a-2.2/fdts/stm32mp157c-security.dtsi000066400000000000000000000012201355360272700225030ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ BSD-3-Clause */ / { soc { stgen: stgen@5c008000 { compatible = "st,stm32-stgen"; reg = <0x5C008000 0x1000>; status = "okay"; }; }; }; &bsec { mac_addr: mac_addr@e4 { reg = <0xe4 0x6>; status = "okay"; secure-status = "okay"; }; /* Spare field to align on 32-bit OTP granularity */ spare_ns_ea: spare_ns_ea@ea { reg = <0xea 0x2>; status = "okay"; secure-status = "okay"; }; }; &hash1 { secure-status = "okay"; }; &sdmmc1 { compatible = "st,stm32-sdmmc2"; }; &sdmmc2 { compatible = "st,stm32-sdmmc2"; }; trusted-firmware-a-2.2/fdts/stm32mp157c.dtsi000066400000000000000000000210651355360272700206470ustar00rootroot00000000000000// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* * Copyright (C) STMicroelectronics 2017-2019 - All Rights Reserved * Author: Ludovic Barre for STMicroelectronics. */ #include #include #include / { #address-cells = <1>; #size-cells = <1>; intc: interrupt-controller@a0021000 { compatible = "arm,cortex-a7-gic"; #interrupt-cells = <3>; interrupt-controller; reg = <0xa0021000 0x1000>, <0xa0022000 0x2000>; }; clocks { clk_hse: clk-hse { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <24000000>; }; clk_hsi: clk-hsi { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <64000000>; }; clk_lse: clk-lse { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <32768>; }; clk_lsi: clk-lsi { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <32000>; }; clk_csi: clk-csi { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <4000000>; }; clk_i2s_ckin: i2s_ckin { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <0>; }; clk_dsi_phy: ck_dsi_phy { #clock-cells = <0>; compatible = "fixed-clock"; clock-frequency = <0>; }; }; soc { compatible = "simple-bus"; #address-cells = <1>; #size-cells = <1>; interrupt-parent = <&intc>; ranges; timers12: timer@40006000 { #address-cells = <1>; #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x40006000 0x400>; clocks = <&rcc TIM12_K>; clock-names = "int"; status = "disabled"; }; usart2: serial@4000e000 { compatible = "st,stm32h7-uart"; reg = <0x4000e000 0x400>; clocks = <&rcc USART2_K>; resets = <&rcc USART2_R>; status = "disabled"; }; usart3: serial@4000f000 { compatible = "st,stm32h7-uart"; reg = <0x4000f000 0x400>; clocks = <&rcc USART3_K>; resets = <&rcc USART3_R>; status = "disabled"; }; uart4: serial@40010000 { compatible = "st,stm32h7-uart"; reg = <0x40010000 0x400>; clocks = <&rcc UART4_K>; resets = <&rcc UART4_R>; status = "disabled"; }; uart5: serial@40011000 { compatible = "st,stm32h7-uart"; reg = <0x40011000 0x400>; clocks = <&rcc UART5_K>; resets = <&rcc UART5_R>; status = "disabled"; }; uart7: serial@40018000 { compatible = "st,stm32h7-uart"; reg = <0x40018000 0x400>; clocks = <&rcc UART7_K>; resets = <&rcc UART7_R>; status = "disabled"; }; uart8: serial@40019000 { compatible = "st,stm32h7-uart"; reg = <0x40019000 0x400>; clocks = <&rcc UART8_K>; resets = <&rcc UART8_R>; status = "disabled"; }; usart6: serial@44003000 { compatible = "st,stm32h7-uart"; reg = <0x44003000 0x400>; clocks = <&rcc USART6_K>; resets = <&rcc USART6_R>; status = "disabled"; }; timers15: timer@44006000 { #address-cells = <1>; #size-cells = <0>; compatible = "st,stm32-timers"; reg = <0x44006000 0x400>; clocks = <&rcc TIM15_K>; clock-names = "int"; status = "disabled"; }; sdmmc3: sdmmc@48004000 { compatible = "arm,pl18x", "arm,primecell"; arm,primecell-periphid = <0x00253180>; reg = <0x48004000 0x400>, <0x48005000 0x400>; clocks = <&rcc SDMMC3_K>; clock-names = "apb_pclk"; resets = <&rcc SDMMC3_R>; cap-sd-highspeed; cap-mmc-highspeed; max-frequency = <120000000>; status = "disabled"; }; usbotg_hs: usb-otg@49000000 { compatible = "st,stm32mp1-hsotg", "snps,dwc2"; reg = <0x49000000 0x10000>; clocks = <&rcc USBO_K>; clock-names = "otg"; resets = <&rcc USBO_R>; reset-names = "dwc2"; status = "disabled"; }; rcc: rcc@50000000 { compatible = "st,stm32mp1-rcc", "syscon"; reg = <0x50000000 0x1000>; #clock-cells = <1>; #reset-cells = <1>; interrupts = ; }; pwr: pwr@50001000 { compatible = "st,stm32mp1-pwr", "syscon", "simple-mfd"; reg = <0x50001000 0x400>; }; exti: interrupt-controller@5000d000 { compatible = "st,stm32mp1-exti", "syscon"; interrupt-controller; #interrupt-cells = <2>; reg = <0x5000d000 0x400>; /* exti_pwr is an extra interrupt controller used for * EXTI 55 to 60. It's mapped on pwr interrupt * controller. */ exti_pwr: exti-pwr { interrupt-controller; #interrupt-cells = <2>; interrupt-parent = <&pwr>; st,irq-number = <6>; }; }; syscfg: syscon@50020000 { compatible = "st,stm32mp157-syscfg", "syscon"; reg = <0x50020000 0x400>; clocks = <&rcc SYSCFG>; }; cryp1: cryp@54001000 { compatible = "st,stm32mp1-cryp"; reg = <0x54001000 0x400>; interrupts = ; clocks = <&rcc CRYP1>; resets = <&rcc CRYP1_R>; status = "disabled"; }; hash1: hash@54002000 { compatible = "st,stm32f756-hash"; reg = <0x54002000 0x400>; interrupts = ; clocks = <&rcc HASH1>; resets = <&rcc HASH1_R>; status = "disabled"; }; rng1: rng@54003000 { compatible = "st,stm32-rng"; reg = <0x54003000 0x400>; clocks = <&rcc RNG1_K>; resets = <&rcc RNG1_R>; status = "disabled"; }; fmc: nand-controller@58002000 { compatible = "st,stm32mp15-fmc2"; reg = <0x58002000 0x1000>, <0x80000000 0x1000>, <0x88010000 0x1000>, <0x88020000 0x1000>, <0x81000000 0x1000>, <0x89010000 0x1000>, <0x89020000 0x1000>; clocks = <&rcc FMC_K>; resets = <&rcc FMC_R>; status = "disabled"; }; qspi: qspi@58003000 { compatible = "st,stm32f469-qspi"; reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; reg-names = "qspi", "qspi_mm"; clocks = <&rcc QSPI_K>; resets = <&rcc QSPI_R>; status = "disabled"; }; sdmmc1: sdmmc@58005000 { compatible = "arm,pl18x", "arm,primecell"; arm,primecell-periphid = <0x00253180>; reg = <0x58005000 0x1000>, <0x58006000 0x1000>; clocks = <&rcc SDMMC1_K>; clock-names = "apb_pclk"; resets = <&rcc SDMMC1_R>; cap-sd-highspeed; cap-mmc-highspeed; max-frequency = <120000000>; status = "disabled"; }; sdmmc2: sdmmc@58007000 { compatible = "arm,pl18x", "arm,primecell"; arm,primecell-periphid = <0x00253180>; reg = <0x58007000 0x1000>, <0x58008000 0x1000>; clocks = <&rcc SDMMC2_K>; clock-names = "apb_pclk"; resets = <&rcc SDMMC2_R>; cap-sd-highspeed; cap-mmc-highspeed; max-frequency = <120000000>; status = "disabled"; }; iwdg2: watchdog@5a002000 { compatible = "st,stm32mp1-iwdg"; reg = <0x5a002000 0x400>; clocks = <&rcc IWDG2>, <&rcc CK_LSI>; clock-names = "pclk", "lsi"; status = "disabled"; }; usart1: serial@5c000000 { compatible = "st,stm32h7-uart"; reg = <0x5c000000 0x400>; interrupt-names = "event", "wakeup"; interrupts-extended = <&intc GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>, <&exti 26 1>; clocks = <&rcc USART1_K>; resets = <&rcc USART1_R>; status = "disabled"; }; spi6: spi@5c001000 { #address-cells = <1>; #size-cells = <0>; compatible = "st,stm32h7-spi"; reg = <0x5c001000 0x400>; interrupts = ; clocks = <&rcc SPI6_K>; resets = <&rcc SPI6_R>; status = "disabled"; }; i2c4: i2c@5c002000 { compatible = "st,stm32f7-i2c"; reg = <0x5c002000 0x400>; interrupt-names = "event", "error", "wakeup"; interrupts-extended = <&intc GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>, <&intc GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>, <&exti 24 1>; clocks = <&rcc I2C4_K>; resets = <&rcc I2C4_R>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; }; rtc: rtc@5c004000 { compatible = "st,stm32mp1-rtc"; reg = <0x5c004000 0x400>; clocks = <&rcc RTCAPB>, <&rcc RTC>; clock-names = "pclk", "rtc_ck"; interrupts-extended = <&intc GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>, <&exti 19 1>; status = "disabled"; }; bsec: nvmem@5c005000 { compatible = "st,stm32mp15-bsec"; reg = <0x5c005000 0x400>; #address-cells = <1>; #size-cells = <1>; ts_cal1: calib@5c { reg = <0x5c 0x2>; }; ts_cal2: calib@5e { reg = <0x5e 0x2>; }; }; i2c6: i2c@5c009000 { compatible = "st,stm32f7-i2c"; reg = <0x5c009000 0x400>; interrupt-names = "event", "error", "wakeup"; interrupts-extended = <&intc GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>, <&intc GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>, <&exti 54 1>; clocks = <&rcc I2C6_K>; resets = <&rcc I2C6_R>; #address-cells = <1>; #size-cells = <0>; status = "disabled"; }; }; }; trusted-firmware-a-2.2/fdts/stm32mp157caa-pinctrl.dtsi000066400000000000000000000032721355360272700226220ustar00rootroot00000000000000// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* * Copyright (C) STMicroelectronics 2018 - All Rights Reserved * Author: Alexandre Torgue */ #include "stm32mp157-pinctrl.dtsi" / { soc { pinctrl: pin-controller@50002000 { st,package = ; gpioa: gpio@50002000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 0 16>; }; gpiob: gpio@50003000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 16 16>; }; gpioc: gpio@50004000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 32 16>; }; gpiod: gpio@50005000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 48 16>; }; gpioe: gpio@50006000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 64 16>; }; gpiof: gpio@50007000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 80 16>; }; gpiog: gpio@50008000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 96 16>; }; gpioh: gpio@50009000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 112 16>; }; gpioi: gpio@5000a000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 128 16>; }; gpioj: gpio@5000b000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 144 16>; }; gpiok: gpio@5000c000 { status = "okay"; ngpios = <8>; gpio-ranges = <&pinctrl 0 160 8>; }; }; pinctrl_z: pin-controller-z@54004000 { st,package = ; gpioz: gpio@54004000 { status = "okay"; ngpios = <8>; gpio-ranges = <&pinctrl_z 0 400 8>; }; }; }; }; trusted-firmware-a-2.2/fdts/stm32mp157cac-pinctrl.dtsi000066400000000000000000000027341355360272700226260ustar00rootroot00000000000000// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* * Copyright (C) STMicroelectronics 2018 - All Rights Reserved * Author: Alexandre Torgue */ #include "stm32mp157-pinctrl.dtsi" / { soc { pinctrl: pin-controller@50002000 { st,package = ; gpioa: gpio@50002000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 0 16>; }; gpiob: gpio@50003000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 16 16>; }; gpioc: gpio@50004000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 32 16>; }; gpiod: gpio@50005000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 48 16>; }; gpioe: gpio@50006000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 64 16>; }; gpiof: gpio@50007000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 80 16>; }; gpiog: gpio@50008000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 96 16>; }; gpioh: gpio@50009000 { status = "okay"; ngpios = <16>; gpio-ranges = <&pinctrl 0 112 16>; }; gpioi: gpio@5000a000 { status = "okay"; ngpios = <12>; gpio-ranges = <&pinctrl 0 128 12>; }; }; pinctrl_z: pin-controller-z@54004000 { st,package = ; gpioz: gpio@54004000 { status = "okay"; ngpios = <8>; gpio-ranges = <&pinctrl_z 0 400 8>; }; }; }; }; trusted-firmware-a-2.2/include/000077500000000000000000000000001355360272700165345ustar00rootroot00000000000000trusted-firmware-a-2.2/include/arch/000077500000000000000000000000001355360272700174515ustar00rootroot00000000000000trusted-firmware-a-2.2/include/arch/aarch32/000077500000000000000000000000001355360272700206745ustar00rootroot00000000000000trusted-firmware-a-2.2/include/arch/aarch32/arch.h000066400000000000000000000527631355360272700217770ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARCH_H #define ARCH_H #include /******************************************************************************* * MIDR bit definitions ******************************************************************************/ #define MIDR_IMPL_MASK U(0xff) #define MIDR_IMPL_SHIFT U(24) #define MIDR_VAR_SHIFT U(20) #define MIDR_VAR_BITS U(4) #define MIDR_REV_SHIFT U(0) #define MIDR_REV_BITS U(4) #define MIDR_PN_MASK U(0xfff) #define MIDR_PN_SHIFT U(4) /******************************************************************************* * MPIDR macros ******************************************************************************/ #define MPIDR_MT_MASK (U(1) << 24) #define MPIDR_CPU_MASK MPIDR_AFFLVL_MASK #define MPIDR_CLUSTER_MASK (MPIDR_AFFLVL_MASK << MPIDR_AFFINITY_BITS) #define MPIDR_AFFINITY_BITS U(8) #define MPIDR_AFFLVL_MASK U(0xff) #define MPIDR_AFFLVL_SHIFT U(3) #define MPIDR_AFF0_SHIFT U(0) #define MPIDR_AFF1_SHIFT U(8) #define MPIDR_AFF2_SHIFT U(16) #define MPIDR_AFF_SHIFT(_n) MPIDR_AFF##_n##_SHIFT #define MPIDR_AFFINITY_MASK U(0x00ffffff) #define MPIDR_AFFLVL0 U(0) #define MPIDR_AFFLVL1 U(1) #define MPIDR_AFFLVL2 U(2) #define MPIDR_AFFLVL(_n) MPIDR_AFFLVL##_n #define MPIDR_AFFLVL0_VAL(mpidr) \ (((mpidr) >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK) #define MPIDR_AFFLVL1_VAL(mpidr) \ (((mpidr) >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK) #define MPIDR_AFFLVL2_VAL(mpidr) \ (((mpidr) >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK) #define MPIDR_AFFLVL3_VAL(mpidr) U(0) #define MPIDR_AFF_ID(mpid, n) \ (((mpid) >> MPIDR_AFF_SHIFT(n)) & MPIDR_AFFLVL_MASK) #define MPID_MASK (MPIDR_MT_MASK |\ (MPIDR_AFFLVL_MASK << MPIDR_AFF2_SHIFT)|\ (MPIDR_AFFLVL_MASK << MPIDR_AFF1_SHIFT)|\ (MPIDR_AFFLVL_MASK << MPIDR_AFF0_SHIFT)) /* * An invalid MPID. This value can be used by functions that return an MPID to * indicate an error. */ #define INVALID_MPID U(0xFFFFFFFF) /* * The MPIDR_MAX_AFFLVL count starts from 0. Take care to * add one while using this macro to define array sizes. */ #define MPIDR_MAX_AFFLVL U(2) /* Data Cache set/way op type defines */ #define DC_OP_ISW U(0x0) #define DC_OP_CISW U(0x1) #if ERRATA_A53_827319 #define DC_OP_CSW DC_OP_CISW #else #define DC_OP_CSW U(0x2) #endif /******************************************************************************* * Generic timer memory mapped registers & offsets ******************************************************************************/ #define CNTCR_OFF U(0x000) /* Counter Count Value Lower register */ #define CNTCVL_OFF U(0x008) /* Counter Count Value Upper register */ #define CNTCVU_OFF U(0x00C) #define CNTFID_OFF U(0x020) #define CNTCR_EN (U(1) << 0) #define CNTCR_HDBG (U(1) << 1) #define CNTCR_FCREQ(x) ((x) << 8) /******************************************************************************* * System register bit definitions ******************************************************************************/ /* CLIDR definitions */ #define LOUIS_SHIFT U(21) #define LOC_SHIFT U(24) #define CLIDR_FIELD_WIDTH U(3) /* CSSELR definitions */ #define LEVEL_SHIFT U(1) /* ID_MMFR4 definitions */ #define ID_MMFR4_CNP_SHIFT U(12) #define ID_MMFR4_CNP_LENGTH U(4) #define ID_MMFR4_CNP_MASK U(0xf) /* ID_PFR0 definitions */ #define ID_PFR0_AMU_SHIFT U(20) #define ID_PFR0_AMU_LENGTH U(4) #define ID_PFR0_AMU_MASK U(0xf) #define ID_PFR0_DIT_SHIFT U(24) #define ID_PFR0_DIT_LENGTH U(4) #define ID_PFR0_DIT_MASK U(0xf) #define ID_PFR0_DIT_SUPPORTED (U(1) << ID_PFR0_DIT_SHIFT) /* ID_PFR1 definitions */ #define ID_PFR1_VIRTEXT_SHIFT U(12) #define ID_PFR1_VIRTEXT_MASK U(0xf) #define GET_VIRT_EXT(id) (((id) >> ID_PFR1_VIRTEXT_SHIFT) \ & ID_PFR1_VIRTEXT_MASK) #define ID_PFR1_GENTIMER_SHIFT U(16) #define ID_PFR1_GENTIMER_MASK U(0xf) #define ID_PFR1_GIC_SHIFT U(28) #define ID_PFR1_GIC_MASK U(0xf) /* SCTLR definitions */ #define SCTLR_RES1_DEF ((U(1) << 23) | (U(1) << 22) | (U(1) << 4) | \ (U(1) << 3)) #if ARM_ARCH_MAJOR == 7 #define SCTLR_RES1 SCTLR_RES1_DEF #else #define SCTLR_RES1 (SCTLR_RES1_DEF | (U(1) << 11)) #endif #define SCTLR_M_BIT (U(1) << 0) #define SCTLR_A_BIT (U(1) << 1) #define SCTLR_C_BIT (U(1) << 2) #define SCTLR_CP15BEN_BIT (U(1) << 5) #define SCTLR_ITD_BIT (U(1) << 7) #define SCTLR_Z_BIT (U(1) << 11) #define SCTLR_I_BIT (U(1) << 12) #define SCTLR_V_BIT (U(1) << 13) #define SCTLR_RR_BIT (U(1) << 14) #define SCTLR_NTWI_BIT (U(1) << 16) #define SCTLR_NTWE_BIT (U(1) << 18) #define SCTLR_WXN_BIT (U(1) << 19) #define SCTLR_UWXN_BIT (U(1) << 20) #define SCTLR_EE_BIT (U(1) << 25) #define SCTLR_TRE_BIT (U(1) << 28) #define SCTLR_AFE_BIT (U(1) << 29) #define SCTLR_TE_BIT (U(1) << 30) #define SCTLR_DSSBS_BIT (U(1) << 31) #define SCTLR_RESET_VAL (SCTLR_RES1 | SCTLR_NTWE_BIT | \ SCTLR_NTWI_BIT | SCTLR_CP15BEN_BIT) /* SDCR definitions */ #define SDCR_SPD(x) ((x) << 14) #define SDCR_SPD_LEGACY U(0x0) #define SDCR_SPD_DISABLE U(0x2) #define SDCR_SPD_ENABLE U(0x3) #define SDCR_SCCD_BIT (U(1) << 23) #define SDCR_SPME_BIT (U(1) << 17) #define SDCR_RESET_VAL U(0x0) /* HSCTLR definitions */ #define HSCTLR_RES1 ((U(1) << 29) | (U(1) << 28) | (U(1) << 23) | \ (U(1) << 22) | (U(1) << 18) | (U(1) << 16) | \ (U(1) << 11) | (U(1) << 4) | (U(1) << 3)) #define HSCTLR_M_BIT (U(1) << 0) #define HSCTLR_A_BIT (U(1) << 1) #define HSCTLR_C_BIT (U(1) << 2) #define HSCTLR_CP15BEN_BIT (U(1) << 5) #define HSCTLR_ITD_BIT (U(1) << 7) #define HSCTLR_SED_BIT (U(1) << 8) #define HSCTLR_I_BIT (U(1) << 12) #define HSCTLR_WXN_BIT (U(1) << 19) #define HSCTLR_EE_BIT (U(1) << 25) #define HSCTLR_TE_BIT (U(1) << 30) /* CPACR definitions */ #define CPACR_FPEN(x) ((x) << 20) #define CPACR_FP_TRAP_PL0 U(0x1) #define CPACR_FP_TRAP_ALL U(0x2) #define CPACR_FP_TRAP_NONE U(0x3) /* SCR definitions */ #define SCR_TWE_BIT (U(1) << 13) #define SCR_TWI_BIT (U(1) << 12) #define SCR_SIF_BIT (U(1) << 9) #define SCR_HCE_BIT (U(1) << 8) #define SCR_SCD_BIT (U(1) << 7) #define SCR_NET_BIT (U(1) << 6) #define SCR_AW_BIT (U(1) << 5) #define SCR_FW_BIT (U(1) << 4) #define SCR_EA_BIT (U(1) << 3) #define SCR_FIQ_BIT (U(1) << 2) #define SCR_IRQ_BIT (U(1) << 1) #define SCR_NS_BIT (U(1) << 0) #define SCR_VALID_BIT_MASK U(0x33ff) #define SCR_RESET_VAL U(0x0) #define GET_NS_BIT(scr) ((scr) & SCR_NS_BIT) /* HCR definitions */ #define HCR_TGE_BIT (U(1) << 27) #define HCR_AMO_BIT (U(1) << 5) #define HCR_IMO_BIT (U(1) << 4) #define HCR_FMO_BIT (U(1) << 3) #define HCR_RESET_VAL U(0x0) /* CNTHCTL definitions */ #define CNTHCTL_RESET_VAL U(0x0) #define PL1PCEN_BIT (U(1) << 1) #define PL1PCTEN_BIT (U(1) << 0) /* CNTKCTL definitions */ #define PL0PTEN_BIT (U(1) << 9) #define PL0VTEN_BIT (U(1) << 8) #define PL0PCTEN_BIT (U(1) << 0) #define PL0VCTEN_BIT (U(1) << 1) #define EVNTEN_BIT (U(1) << 2) #define EVNTDIR_BIT (U(1) << 3) #define EVNTI_SHIFT U(4) #define EVNTI_MASK U(0xf) /* HCPTR definitions */ #define HCPTR_RES1 ((U(1) << 13) | (U(1) << 12) | U(0x3ff)) #define TCPAC_BIT (U(1) << 31) #define TAM_BIT (U(1) << 30) #define TTA_BIT (U(1) << 20) #define TCP11_BIT (U(1) << 11) #define TCP10_BIT (U(1) << 10) #define HCPTR_RESET_VAL HCPTR_RES1 /* VTTBR defintions */ #define VTTBR_RESET_VAL ULL(0x0) #define VTTBR_VMID_MASK ULL(0xff) #define VTTBR_VMID_SHIFT U(48) #define VTTBR_BADDR_MASK ULL(0xffffffffffff) #define VTTBR_BADDR_SHIFT U(0) /* HDCR definitions */ #define HDCR_HLP_BIT (U(1) << 26) #define HDCR_HPME_BIT (U(1) << 7) #define HDCR_RESET_VAL U(0x0) /* HSTR definitions */ #define HSTR_RESET_VAL U(0x0) /* CNTHP_CTL definitions */ #define CNTHP_CTL_RESET_VAL U(0x0) /* NSACR definitions */ #define NSASEDIS_BIT (U(1) << 15) #define NSTRCDIS_BIT (U(1) << 20) #define NSACR_CP11_BIT (U(1) << 11) #define NSACR_CP10_BIT (U(1) << 10) #define NSACR_IMP_DEF_MASK (U(0x7) << 16) #define NSACR_ENABLE_FP_ACCESS (NSACR_CP11_BIT | NSACR_CP10_BIT) #define NSACR_RESET_VAL U(0x0) /* CPACR definitions */ #define ASEDIS_BIT (U(1) << 31) #define TRCDIS_BIT (U(1) << 28) #define CPACR_CP11_SHIFT U(22) #define CPACR_CP10_SHIFT U(20) #define CPACR_ENABLE_FP_ACCESS ((U(0x3) << CPACR_CP11_SHIFT) |\ (U(0x3) << CPACR_CP10_SHIFT)) #define CPACR_RESET_VAL U(0x0) /* FPEXC definitions */ #define FPEXC_RES1 ((U(1) << 10) | (U(1) << 9) | (U(1) << 8)) #define FPEXC_EN_BIT (U(1) << 30) #define FPEXC_RESET_VAL FPEXC_RES1 /* SPSR/CPSR definitions */ #define SPSR_FIQ_BIT (U(1) << 0) #define SPSR_IRQ_BIT (U(1) << 1) #define SPSR_ABT_BIT (U(1) << 2) #define SPSR_AIF_SHIFT U(6) #define SPSR_AIF_MASK U(0x7) #define SPSR_E_SHIFT U(9) #define SPSR_E_MASK U(0x1) #define SPSR_E_LITTLE U(0) #define SPSR_E_BIG U(1) #define SPSR_T_SHIFT U(5) #define SPSR_T_MASK U(0x1) #define SPSR_T_ARM U(0) #define SPSR_T_THUMB U(1) #define SPSR_MODE_SHIFT U(0) #define SPSR_MODE_MASK U(0x7) #define SPSR_SSBS_BIT BIT_32(23) #define DISABLE_ALL_EXCEPTIONS \ (SPSR_FIQ_BIT | SPSR_IRQ_BIT | SPSR_ABT_BIT) #define CPSR_DIT_BIT (U(1) << 21) /* * TTBCR definitions */ #define TTBCR_EAE_BIT (U(1) << 31) #define TTBCR_SH1_NON_SHAREABLE (U(0x0) << 28) #define TTBCR_SH1_OUTER_SHAREABLE (U(0x2) << 28) #define TTBCR_SH1_INNER_SHAREABLE (U(0x3) << 28) #define TTBCR_RGN1_OUTER_NC (U(0x0) << 26) #define TTBCR_RGN1_OUTER_WBA (U(0x1) << 26) #define TTBCR_RGN1_OUTER_WT (U(0x2) << 26) #define TTBCR_RGN1_OUTER_WBNA (U(0x3) << 26) #define TTBCR_RGN1_INNER_NC (U(0x0) << 24) #define TTBCR_RGN1_INNER_WBA (U(0x1) << 24) #define TTBCR_RGN1_INNER_WT (U(0x2) << 24) #define TTBCR_RGN1_INNER_WBNA (U(0x3) << 24) #define TTBCR_EPD1_BIT (U(1) << 23) #define TTBCR_A1_BIT (U(1) << 22) #define TTBCR_T1SZ_SHIFT U(16) #define TTBCR_T1SZ_MASK U(0x7) #define TTBCR_TxSZ_MIN U(0) #define TTBCR_TxSZ_MAX U(7) #define TTBCR_SH0_NON_SHAREABLE (U(0x0) << 12) #define TTBCR_SH0_OUTER_SHAREABLE (U(0x2) << 12) #define TTBCR_SH0_INNER_SHAREABLE (U(0x3) << 12) #define TTBCR_RGN0_OUTER_NC (U(0x0) << 10) #define TTBCR_RGN0_OUTER_WBA (U(0x1) << 10) #define TTBCR_RGN0_OUTER_WT (U(0x2) << 10) #define TTBCR_RGN0_OUTER_WBNA (U(0x3) << 10) #define TTBCR_RGN0_INNER_NC (U(0x0) << 8) #define TTBCR_RGN0_INNER_WBA (U(0x1) << 8) #define TTBCR_RGN0_INNER_WT (U(0x2) << 8) #define TTBCR_RGN0_INNER_WBNA (U(0x3) << 8) #define TTBCR_EPD0_BIT (U(1) << 7) #define TTBCR_T0SZ_SHIFT U(0) #define TTBCR_T0SZ_MASK U(0x7) /* * HTCR definitions */ #define HTCR_RES1 ((U(1) << 31) | (U(1) << 23)) #define HTCR_SH0_NON_SHAREABLE (U(0x0) << 12) #define HTCR_SH0_OUTER_SHAREABLE (U(0x2) << 12) #define HTCR_SH0_INNER_SHAREABLE (U(0x3) << 12) #define HTCR_RGN0_OUTER_NC (U(0x0) << 10) #define HTCR_RGN0_OUTER_WBA (U(0x1) << 10) #define HTCR_RGN0_OUTER_WT (U(0x2) << 10) #define HTCR_RGN0_OUTER_WBNA (U(0x3) << 10) #define HTCR_RGN0_INNER_NC (U(0x0) << 8) #define HTCR_RGN0_INNER_WBA (U(0x1) << 8) #define HTCR_RGN0_INNER_WT (U(0x2) << 8) #define HTCR_RGN0_INNER_WBNA (U(0x3) << 8) #define HTCR_T0SZ_SHIFT U(0) #define HTCR_T0SZ_MASK U(0x7) #define MODE_RW_SHIFT U(0x4) #define MODE_RW_MASK U(0x1) #define MODE_RW_32 U(0x1) #define MODE32_SHIFT U(0) #define MODE32_MASK U(0x1f) #define MODE32_usr U(0x10) #define MODE32_fiq U(0x11) #define MODE32_irq U(0x12) #define MODE32_svc U(0x13) #define MODE32_mon U(0x16) #define MODE32_abt U(0x17) #define MODE32_hyp U(0x1a) #define MODE32_und U(0x1b) #define MODE32_sys U(0x1f) #define GET_M32(mode) (((mode) >> MODE32_SHIFT) & MODE32_MASK) #define SPSR_MODE32(mode, isa, endian, aif) \ ((MODE_RW_32 << MODE_RW_SHIFT | \ ((mode) & MODE32_MASK) << MODE32_SHIFT | \ ((isa) & SPSR_T_MASK) << SPSR_T_SHIFT | \ ((endian) & SPSR_E_MASK) << SPSR_E_SHIFT | \ ((aif) & SPSR_AIF_MASK) << SPSR_AIF_SHIFT) & \ (~(SPSR_SSBS_BIT))) /* * TTBR definitions */ #define TTBR_CNP_BIT ULL(0x1) /* * CTR definitions */ #define CTR_CWG_SHIFT U(24) #define CTR_CWG_MASK U(0xf) #define CTR_ERG_SHIFT U(20) #define CTR_ERG_MASK U(0xf) #define CTR_DMINLINE_SHIFT U(16) #define CTR_DMINLINE_WIDTH U(4) #define CTR_DMINLINE_MASK ((U(1) << 4) - U(1)) #define CTR_L1IP_SHIFT U(14) #define CTR_L1IP_MASK U(0x3) #define CTR_IMINLINE_SHIFT U(0) #define CTR_IMINLINE_MASK U(0xf) #define MAX_CACHE_LINE_SIZE U(0x800) /* 2KB */ /* PMCR definitions */ #define PMCR_N_SHIFT U(11) #define PMCR_N_MASK U(0x1f) #define PMCR_N_BITS (PMCR_N_MASK << PMCR_N_SHIFT) #define PMCR_LP_BIT (U(1) << 7) #define PMCR_LC_BIT (U(1) << 6) #define PMCR_DP_BIT (U(1) << 5) #define PMCR_RESET_VAL U(0x0) /******************************************************************************* * Definitions of register offsets, fields and macros for CPU system * instructions. ******************************************************************************/ #define TLBI_ADDR_SHIFT U(0) #define TLBI_ADDR_MASK U(0xFFFFF000) #define TLBI_ADDR(x) (((x) >> TLBI_ADDR_SHIFT) & TLBI_ADDR_MASK) /******************************************************************************* * Definitions of register offsets and fields in the CNTCTLBase Frame of the * system level implementation of the Generic Timer. ******************************************************************************/ #define CNTCTLBASE_CNTFRQ U(0x0) #define CNTNSAR U(0x4) #define CNTNSAR_NS_SHIFT(x) (x) #define CNTACR_BASE(x) (U(0x40) + ((x) << 2)) #define CNTACR_RPCT_SHIFT U(0x0) #define CNTACR_RVCT_SHIFT U(0x1) #define CNTACR_RFRQ_SHIFT U(0x2) #define CNTACR_RVOFF_SHIFT U(0x3) #define CNTACR_RWVT_SHIFT U(0x4) #define CNTACR_RWPT_SHIFT U(0x5) /******************************************************************************* * Definitions of register offsets and fields in the CNTBaseN Frame of the * system level implementation of the Generic Timer. ******************************************************************************/ /* Physical Count register. */ #define CNTPCT_LO U(0x0) /* Counter Frequency register. */ #define CNTBASEN_CNTFRQ U(0x10) /* Physical Timer CompareValue register. */ #define CNTP_CVAL_LO U(0x20) /* Physical Timer Control register. */ #define CNTP_CTL U(0x2c) /* Physical timer control register bit fields shifts and masks */ #define CNTP_CTL_ENABLE_SHIFT 0 #define CNTP_CTL_IMASK_SHIFT 1 #define CNTP_CTL_ISTATUS_SHIFT 2 #define CNTP_CTL_ENABLE_MASK U(1) #define CNTP_CTL_IMASK_MASK U(1) #define CNTP_CTL_ISTATUS_MASK U(1) /* MAIR macros */ #define MAIR0_ATTR_SET(attr, index) ((attr) << ((index) << U(3))) #define MAIR1_ATTR_SET(attr, index) ((attr) << (((index) - U(3)) << U(3))) /* System register defines The format is: coproc, opt1, CRn, CRm, opt2 */ #define SCR p15, 0, c1, c1, 0 #define SCTLR p15, 0, c1, c0, 0 #define ACTLR p15, 0, c1, c0, 1 #define SDCR p15, 0, c1, c3, 1 #define MPIDR p15, 0, c0, c0, 5 #define MIDR p15, 0, c0, c0, 0 #define HVBAR p15, 4, c12, c0, 0 #define VBAR p15, 0, c12, c0, 0 #define MVBAR p15, 0, c12, c0, 1 #define NSACR p15, 0, c1, c1, 2 #define CPACR p15, 0, c1, c0, 2 #define DCCIMVAC p15, 0, c7, c14, 1 #define DCCMVAC p15, 0, c7, c10, 1 #define DCIMVAC p15, 0, c7, c6, 1 #define DCCISW p15, 0, c7, c14, 2 #define DCCSW p15, 0, c7, c10, 2 #define DCISW p15, 0, c7, c6, 2 #define CTR p15, 0, c0, c0, 1 #define CNTFRQ p15, 0, c14, c0, 0 #define ID_MMFR4 p15, 0, c0, c2, 6 #define ID_PFR0 p15, 0, c0, c1, 0 #define ID_PFR1 p15, 0, c0, c1, 1 #define MAIR0 p15, 0, c10, c2, 0 #define MAIR1 p15, 0, c10, c2, 1 #define TTBCR p15, 0, c2, c0, 2 #define TTBR0 p15, 0, c2, c0, 0 #define TTBR1 p15, 0, c2, c0, 1 #define TLBIALL p15, 0, c8, c7, 0 #define TLBIALLH p15, 4, c8, c7, 0 #define TLBIALLIS p15, 0, c8, c3, 0 #define TLBIMVA p15, 0, c8, c7, 1 #define TLBIMVAA p15, 0, c8, c7, 3 #define TLBIMVAAIS p15, 0, c8, c3, 3 #define TLBIMVAHIS p15, 4, c8, c3, 1 #define BPIALLIS p15, 0, c7, c1, 6 #define BPIALL p15, 0, c7, c5, 6 #define ICIALLU p15, 0, c7, c5, 0 #define HSCTLR p15, 4, c1, c0, 0 #define HCR p15, 4, c1, c1, 0 #define HCPTR p15, 4, c1, c1, 2 #define HSTR p15, 4, c1, c1, 3 #define CNTHCTL p15, 4, c14, c1, 0 #define CNTKCTL p15, 0, c14, c1, 0 #define VPIDR p15, 4, c0, c0, 0 #define VMPIDR p15, 4, c0, c0, 5 #define ISR p15, 0, c12, c1, 0 #define CLIDR p15, 1, c0, c0, 1 #define CSSELR p15, 2, c0, c0, 0 #define CCSIDR p15, 1, c0, c0, 0 #define HTCR p15, 4, c2, c0, 2 #define HMAIR0 p15, 4, c10, c2, 0 #define ATS1CPR p15, 0, c7, c8, 0 #define ATS1HR p15, 4, c7, c8, 0 #define DBGOSDLR p14, 0, c1, c3, 4 /* Debug register defines. The format is: coproc, opt1, CRn, CRm, opt2 */ #define HDCR p15, 4, c1, c1, 1 #define PMCR p15, 0, c9, c12, 0 #define CNTHP_TVAL p15, 4, c14, c2, 0 #define CNTHP_CTL p15, 4, c14, c2, 1 /* AArch32 coproc registers for 32bit MMU descriptor support */ #define PRRR p15, 0, c10, c2, 0 #define NMRR p15, 0, c10, c2, 1 #define DACR p15, 0, c3, c0, 0 /* GICv3 CPU Interface system register defines. The format is: coproc, opt1, CRn, CRm, opt2 */ #define ICC_IAR1 p15, 0, c12, c12, 0 #define ICC_IAR0 p15, 0, c12, c8, 0 #define ICC_EOIR1 p15, 0, c12, c12, 1 #define ICC_EOIR0 p15, 0, c12, c8, 1 #define ICC_HPPIR1 p15, 0, c12, c12, 2 #define ICC_HPPIR0 p15, 0, c12, c8, 2 #define ICC_BPR1 p15, 0, c12, c12, 3 #define ICC_BPR0 p15, 0, c12, c8, 3 #define ICC_DIR p15, 0, c12, c11, 1 #define ICC_PMR p15, 0, c4, c6, 0 #define ICC_RPR p15, 0, c12, c11, 3 #define ICC_CTLR p15, 0, c12, c12, 4 #define ICC_MCTLR p15, 6, c12, c12, 4 #define ICC_SRE p15, 0, c12, c12, 5 #define ICC_HSRE p15, 4, c12, c9, 5 #define ICC_MSRE p15, 6, c12, c12, 5 #define ICC_IGRPEN0 p15, 0, c12, c12, 6 #define ICC_IGRPEN1 p15, 0, c12, c12, 7 #define ICC_MGRPEN1 p15, 6, c12, c12, 7 /* 64 bit system register defines The format is: coproc, opt1, CRm */ #define TTBR0_64 p15, 0, c2 #define TTBR1_64 p15, 1, c2 #define CNTVOFF_64 p15, 4, c14 #define VTTBR_64 p15, 6, c2 #define CNTPCT_64 p15, 0, c14 #define HTTBR_64 p15, 4, c2 #define CNTHP_CVAL_64 p15, 6, c14 #define PAR_64 p15, 0, c7 /* 64 bit GICv3 CPU Interface system register defines. The format is: coproc, opt1, CRm */ #define ICC_SGI1R_EL1_64 p15, 0, c12 #define ICC_ASGI1R_EL1_64 p15, 1, c12 #define ICC_SGI0R_EL1_64 p15, 2, c12 /******************************************************************************* * Definitions of MAIR encodings for device and normal memory ******************************************************************************/ /* * MAIR encodings for device memory attributes. */ #define MAIR_DEV_nGnRnE U(0x0) #define MAIR_DEV_nGnRE U(0x4) #define MAIR_DEV_nGRE U(0x8) #define MAIR_DEV_GRE U(0xc) /* * MAIR encodings for normal memory attributes. * * Cache Policy * WT: Write Through * WB: Write Back * NC: Non-Cacheable * * Transient Hint * NTR: Non-Transient * TR: Transient * * Allocation Policy * RA: Read Allocate * WA: Write Allocate * RWA: Read and Write Allocate * NA: No Allocation */ #define MAIR_NORM_WT_TR_WA U(0x1) #define MAIR_NORM_WT_TR_RA U(0x2) #define MAIR_NORM_WT_TR_RWA U(0x3) #define MAIR_NORM_NC U(0x4) #define MAIR_NORM_WB_TR_WA U(0x5) #define MAIR_NORM_WB_TR_RA U(0x6) #define MAIR_NORM_WB_TR_RWA U(0x7) #define MAIR_NORM_WT_NTR_NA U(0x8) #define MAIR_NORM_WT_NTR_WA U(0x9) #define MAIR_NORM_WT_NTR_RA U(0xa) #define MAIR_NORM_WT_NTR_RWA U(0xb) #define MAIR_NORM_WB_NTR_NA U(0xc) #define MAIR_NORM_WB_NTR_WA U(0xd) #define MAIR_NORM_WB_NTR_RA U(0xe) #define MAIR_NORM_WB_NTR_RWA U(0xf) #define MAIR_NORM_OUTER_SHIFT U(4) #define MAKE_MAIR_NORMAL_MEMORY(inner, outer) \ ((inner) | ((outer) << MAIR_NORM_OUTER_SHIFT)) /* PAR fields */ #define PAR_F_SHIFT U(0) #define PAR_F_MASK ULL(0x1) #define PAR_ADDR_SHIFT U(12) #define PAR_ADDR_MASK (BIT_64(40) - ULL(1)) /* 40-bits-wide page address */ /******************************************************************************* * Definitions for system register interface to AMU for ARMv8.4 onwards ******************************************************************************/ #define AMCR p15, 0, c13, c2, 0 #define AMCFGR p15, 0, c13, c2, 1 #define AMCGCR p15, 0, c13, c2, 2 #define AMUSERENR p15, 0, c13, c2, 3 #define AMCNTENCLR0 p15, 0, c13, c2, 4 #define AMCNTENSET0 p15, 0, c13, c2, 5 #define AMCNTENCLR1 p15, 0, c13, c3, 0 #define AMCNTENSET1 p15, 0, c13, c3, 1 /* Activity Monitor Group 0 Event Counter Registers */ #define AMEVCNTR00 p15, 0, c0 #define AMEVCNTR01 p15, 1, c0 #define AMEVCNTR02 p15, 2, c0 #define AMEVCNTR03 p15, 3, c0 /* Activity Monitor Group 0 Event Type Registers */ #define AMEVTYPER00 p15, 0, c13, c6, 0 #define AMEVTYPER01 p15, 0, c13, c6, 1 #define AMEVTYPER02 p15, 0, c13, c6, 2 #define AMEVTYPER03 p15, 0, c13, c6, 3 /* Activity Monitor Group 1 Event Counter Registers */ #define AMEVCNTR10 p15, 0, c4 #define AMEVCNTR11 p15, 1, c4 #define AMEVCNTR12 p15, 2, c4 #define AMEVCNTR13 p15, 3, c4 #define AMEVCNTR14 p15, 4, c4 #define AMEVCNTR15 p15, 5, c4 #define AMEVCNTR16 p15, 6, c4 #define AMEVCNTR17 p15, 7, c4 #define AMEVCNTR18 p15, 0, c5 #define AMEVCNTR19 p15, 1, c5 #define AMEVCNTR1A p15, 2, c5 #define AMEVCNTR1B p15, 3, c5 #define AMEVCNTR1C p15, 4, c5 #define AMEVCNTR1D p15, 5, c5 #define AMEVCNTR1E p15, 6, c5 #define AMEVCNTR1F p15, 7, c5 /* Activity Monitor Group 1 Event Type Registers */ #define AMEVTYPER10 p15, 0, c13, c14, 0 #define AMEVTYPER11 p15, 0, c13, c14, 1 #define AMEVTYPER12 p15, 0, c13, c14, 2 #define AMEVTYPER13 p15, 0, c13, c14, 3 #define AMEVTYPER14 p15, 0, c13, c14, 4 #define AMEVTYPER15 p15, 0, c13, c14, 5 #define AMEVTYPER16 p15, 0, c13, c14, 6 #define AMEVTYPER17 p15, 0, c13, c14, 7 #define AMEVTYPER18 p15, 0, c13, c15, 0 #define AMEVTYPER19 p15, 0, c13, c15, 1 #define AMEVTYPER1A p15, 0, c13, c15, 2 #define AMEVTYPER1B p15, 0, c13, c15, 3 #define AMEVTYPER1C p15, 0, c13, c15, 4 #define AMEVTYPER1D p15, 0, c13, c15, 5 #define AMEVTYPER1E p15, 0, c13, c15, 6 #define AMEVTYPER1F p15, 0, c13, c15, 7 #endif /* ARCH_H */ trusted-firmware-a-2.2/include/arch/aarch32/arch_features.h000066400000000000000000000010001355360272700236470ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARCH_FEATURES_H #define ARCH_FEATURES_H #include #include static inline bool is_armv7_gentimer_present(void) { return ((read_id_pfr1() >> ID_PFR1_GENTIMER_SHIFT) & ID_PFR1_GENTIMER_MASK) != 0U; } static inline bool is_armv8_2_ttcnp_present(void) { return ((read_id_mmfr4() >> ID_MMFR4_CNP_SHIFT) & ID_MMFR4_CNP_MASK) != 0U; } #endif /* ARCH_FEATURES_H */ trusted-firmware-a-2.2/include/arch/aarch32/arch_helpers.h000066400000000000000000000343541355360272700235150ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARCH_HELPERS_H #define ARCH_HELPERS_H #include #include #include #include /********************************************************************** * Macros which create inline functions to read or write CPU system * registers *********************************************************************/ #define _DEFINE_COPROCR_WRITE_FUNC(_name, coproc, opc1, CRn, CRm, opc2) \ static inline void write_## _name(u_register_t v) \ { \ __asm__ volatile ("mcr "#coproc","#opc1",%0,"#CRn","#CRm","#opc2 : : "r" (v));\ } #define _DEFINE_COPROCR_READ_FUNC(_name, coproc, opc1, CRn, CRm, opc2) \ static inline u_register_t read_ ## _name(void) \ { \ u_register_t v; \ __asm__ volatile ("mrc "#coproc","#opc1",%0,"#CRn","#CRm","#opc2 : "=r" (v));\ return v; \ } /* * The undocumented %Q and %R extended asm are used to implemented the below * 64 bit `mrrc` and `mcrr` instructions. */ #define _DEFINE_COPROCR_WRITE_FUNC_64(_name, coproc, opc1, CRm) \ static inline void write64_## _name(uint64_t v) \ { \ __asm__ volatile ("mcrr "#coproc","#opc1", %Q0, %R0,"#CRm : : "r" (v));\ } #define _DEFINE_COPROCR_READ_FUNC_64(_name, coproc, opc1, CRm) \ static inline uint64_t read64_## _name(void) \ { uint64_t v; \ __asm__ volatile ("mrrc "#coproc","#opc1", %Q0, %R0,"#CRm : "=r" (v));\ return v; \ } #define _DEFINE_SYSREG_READ_FUNC(_name, _reg_name) \ static inline u_register_t read_ ## _name(void) \ { \ u_register_t v; \ __asm__ volatile ("mrs %0, " #_reg_name : "=r" (v)); \ return v; \ } #define _DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name) \ static inline void write_ ## _name(u_register_t v) \ { \ __asm__ volatile ("msr " #_reg_name ", %0" : : "r" (v)); \ } #define _DEFINE_SYSREG_WRITE_CONST_FUNC(_name, _reg_name) \ static inline void write_ ## _name(const u_register_t v) \ { \ __asm__ volatile ("msr " #_reg_name ", %0" : : "i" (v)); \ } /* Define read function for coproc register */ #define DEFINE_COPROCR_READ_FUNC(_name, ...) \ _DEFINE_COPROCR_READ_FUNC(_name, __VA_ARGS__) /* Define write function for coproc register */ #define DEFINE_COPROCR_WRITE_FUNC(_name, ...) \ _DEFINE_COPROCR_WRITE_FUNC(_name, __VA_ARGS__) /* Define read & write function for coproc register */ #define DEFINE_COPROCR_RW_FUNCS(_name, ...) \ _DEFINE_COPROCR_READ_FUNC(_name, __VA_ARGS__) \ _DEFINE_COPROCR_WRITE_FUNC(_name, __VA_ARGS__) /* Define 64 bit read function for coproc register */ #define DEFINE_COPROCR_READ_FUNC_64(_name, ...) \ _DEFINE_COPROCR_READ_FUNC_64(_name, __VA_ARGS__) /* Define 64 bit write function for coproc register */ #define DEFINE_COPROCR_WRITE_FUNC_64(_name, ...) \ _DEFINE_COPROCR_WRITE_FUNC_64(_name, __VA_ARGS__) /* Define 64 bit read & write function for coproc register */ #define DEFINE_COPROCR_RW_FUNCS_64(_name, ...) \ _DEFINE_COPROCR_READ_FUNC_64(_name, __VA_ARGS__) \ _DEFINE_COPROCR_WRITE_FUNC_64(_name, __VA_ARGS__) /* Define read & write function for system register */ #define DEFINE_SYSREG_RW_FUNCS(_name) \ _DEFINE_SYSREG_READ_FUNC(_name, _name) \ _DEFINE_SYSREG_WRITE_FUNC(_name, _name) /********************************************************************** * Macros to create inline functions for tlbi operations *********************************************************************/ #define _DEFINE_TLBIOP_FUNC(_op, coproc, opc1, CRn, CRm, opc2) \ static inline void tlbi##_op(void) \ { \ u_register_t v = 0; \ __asm__ volatile ("mcr "#coproc","#opc1",%0,"#CRn","#CRm","#opc2 : : "r" (v));\ } #define _DEFINE_BPIOP_FUNC(_op, coproc, opc1, CRn, CRm, opc2) \ static inline void bpi##_op(void) \ { \ u_register_t v = 0; \ __asm__ volatile ("mcr "#coproc","#opc1",%0,"#CRn","#CRm","#opc2 : : "r" (v));\ } #define _DEFINE_TLBIOP_PARAM_FUNC(_op, coproc, opc1, CRn, CRm, opc2) \ static inline void tlbi##_op(u_register_t v) \ { \ __asm__ volatile ("mcr "#coproc","#opc1",%0,"#CRn","#CRm","#opc2 : : "r" (v));\ } /* Define function for simple TLBI operation */ #define DEFINE_TLBIOP_FUNC(_op, ...) \ _DEFINE_TLBIOP_FUNC(_op, __VA_ARGS__) /* Define function for TLBI operation with register parameter */ #define DEFINE_TLBIOP_PARAM_FUNC(_op, ...) \ _DEFINE_TLBIOP_PARAM_FUNC(_op, __VA_ARGS__) /* Define function for simple BPI operation */ #define DEFINE_BPIOP_FUNC(_op, ...) \ _DEFINE_BPIOP_FUNC(_op, __VA_ARGS__) /********************************************************************** * Macros to create inline functions for DC operations *********************************************************************/ #define _DEFINE_DCOP_PARAM_FUNC(_op, coproc, opc1, CRn, CRm, opc2) \ static inline void dc##_op(u_register_t v) \ { \ __asm__ volatile ("mcr "#coproc","#opc1",%0,"#CRn","#CRm","#opc2 : : "r" (v));\ } /* Define function for DC operation with register parameter */ #define DEFINE_DCOP_PARAM_FUNC(_op, ...) \ _DEFINE_DCOP_PARAM_FUNC(_op, __VA_ARGS__) /********************************************************************** * Macros to create inline functions for system instructions *********************************************************************/ /* Define function for simple system instruction */ #define DEFINE_SYSOP_FUNC(_op) \ static inline void _op(void) \ { \ __asm__ (#_op); \ } /* Define function for system instruction with type specifier */ #define DEFINE_SYSOP_TYPE_FUNC(_op, _type) \ static inline void _op ## _type(void) \ { \ __asm__ (#_op " " #_type); \ } /* Define function for system instruction with register parameter */ #define DEFINE_SYSOP_TYPE_PARAM_FUNC(_op, _type) \ static inline void _op ## _type(u_register_t v) \ { \ __asm__ (#_op " " #_type ", %0" : : "r" (v)); \ } void flush_dcache_range(uintptr_t addr, size_t size); void clean_dcache_range(uintptr_t addr, size_t size); void inv_dcache_range(uintptr_t addr, size_t size); void dcsw_op_louis(u_register_t op_type); void dcsw_op_all(u_register_t op_type); void disable_mmu_secure(void); void disable_mmu_icache_secure(void); DEFINE_SYSOP_FUNC(wfi) DEFINE_SYSOP_FUNC(wfe) DEFINE_SYSOP_FUNC(sev) DEFINE_SYSOP_TYPE_FUNC(dsb, sy) DEFINE_SYSOP_TYPE_FUNC(dmb, sy) DEFINE_SYSOP_TYPE_FUNC(dmb, st) /* dmb ld is not valid for armv7/thumb machines */ #if ARM_ARCH_MAJOR != 7 DEFINE_SYSOP_TYPE_FUNC(dmb, ld) #endif DEFINE_SYSOP_TYPE_FUNC(dsb, ish) DEFINE_SYSOP_TYPE_FUNC(dsb, ishst) DEFINE_SYSOP_TYPE_FUNC(dmb, ish) DEFINE_SYSOP_TYPE_FUNC(dmb, ishst) DEFINE_SYSOP_FUNC(isb) void __dead2 smc(uint32_t r0, uint32_t r1, uint32_t r2, uint32_t r3, uint32_t r4, uint32_t r5, uint32_t r6, uint32_t r7); DEFINE_SYSREG_RW_FUNCS(spsr) DEFINE_SYSREG_RW_FUNCS(cpsr) /******************************************************************************* * System register accessor prototypes ******************************************************************************/ DEFINE_COPROCR_READ_FUNC(mpidr, MPIDR) DEFINE_COPROCR_READ_FUNC(midr, MIDR) DEFINE_COPROCR_READ_FUNC(id_mmfr4, ID_MMFR4) DEFINE_COPROCR_READ_FUNC(id_pfr0, ID_PFR0) DEFINE_COPROCR_READ_FUNC(id_pfr1, ID_PFR1) DEFINE_COPROCR_READ_FUNC(isr, ISR) DEFINE_COPROCR_READ_FUNC(clidr, CLIDR) DEFINE_COPROCR_READ_FUNC_64(cntpct, CNTPCT_64) DEFINE_COPROCR_RW_FUNCS(scr, SCR) DEFINE_COPROCR_RW_FUNCS(ctr, CTR) DEFINE_COPROCR_RW_FUNCS(sctlr, SCTLR) DEFINE_COPROCR_RW_FUNCS(actlr, ACTLR) DEFINE_COPROCR_RW_FUNCS(hsctlr, HSCTLR) DEFINE_COPROCR_RW_FUNCS(hcr, HCR) DEFINE_COPROCR_RW_FUNCS(hcptr, HCPTR) DEFINE_COPROCR_RW_FUNCS(cntfrq, CNTFRQ) DEFINE_COPROCR_RW_FUNCS(cnthctl, CNTHCTL) DEFINE_COPROCR_RW_FUNCS(mair0, MAIR0) DEFINE_COPROCR_RW_FUNCS(mair1, MAIR1) DEFINE_COPROCR_RW_FUNCS(hmair0, HMAIR0) DEFINE_COPROCR_RW_FUNCS(ttbcr, TTBCR) DEFINE_COPROCR_RW_FUNCS(htcr, HTCR) DEFINE_COPROCR_RW_FUNCS(ttbr0, TTBR0) DEFINE_COPROCR_RW_FUNCS_64(ttbr0, TTBR0_64) DEFINE_COPROCR_RW_FUNCS(ttbr1, TTBR1) DEFINE_COPROCR_RW_FUNCS_64(httbr, HTTBR_64) DEFINE_COPROCR_RW_FUNCS(vpidr, VPIDR) DEFINE_COPROCR_RW_FUNCS(vmpidr, VMPIDR) DEFINE_COPROCR_RW_FUNCS_64(vttbr, VTTBR_64) 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(cnthp_ctl_el2, CNTHP_CTL) DEFINE_COPROCR_RW_FUNCS(cnthp_tval_el2, CNTHP_TVAL) DEFINE_COPROCR_RW_FUNCS_64(cnthp_cval_el2, CNTHP_CVAL_64) #define get_cntp_ctl_enable(x) (((x) >> CNTP_CTL_ENABLE_SHIFT) & \ CNTP_CTL_ENABLE_MASK) #define get_cntp_ctl_imask(x) (((x) >> CNTP_CTL_IMASK_SHIFT) & \ CNTP_CTL_IMASK_MASK) #define get_cntp_ctl_istatus(x) (((x) >> CNTP_CTL_ISTATUS_SHIFT) & \ CNTP_CTL_ISTATUS_MASK) #define set_cntp_ctl_enable(x) ((x) |= U(1) << CNTP_CTL_ENABLE_SHIFT) #define set_cntp_ctl_imask(x) ((x) |= U(1) << CNTP_CTL_IMASK_SHIFT) #define clr_cntp_ctl_enable(x) ((x) &= ~(U(1) << CNTP_CTL_ENABLE_SHIFT)) #define clr_cntp_ctl_imask(x) ((x) &= ~(U(1) << CNTP_CTL_IMASK_SHIFT)) DEFINE_COPROCR_RW_FUNCS(icc_sre_el1, ICC_SRE) DEFINE_COPROCR_RW_FUNCS(icc_sre_el2, ICC_HSRE) DEFINE_COPROCR_RW_FUNCS(icc_sre_el3, ICC_MSRE) DEFINE_COPROCR_RW_FUNCS(icc_pmr_el1, ICC_PMR) DEFINE_COPROCR_RW_FUNCS(icc_rpr_el1, ICC_RPR) DEFINE_COPROCR_RW_FUNCS(icc_igrpen1_el3, ICC_MGRPEN1) DEFINE_COPROCR_RW_FUNCS(icc_igrpen1_el1, ICC_IGRPEN1) DEFINE_COPROCR_RW_FUNCS(icc_igrpen0_el1, ICC_IGRPEN0) DEFINE_COPROCR_RW_FUNCS(icc_hppir0_el1, ICC_HPPIR0) DEFINE_COPROCR_RW_FUNCS(icc_hppir1_el1, ICC_HPPIR1) DEFINE_COPROCR_RW_FUNCS(icc_iar0_el1, ICC_IAR0) DEFINE_COPROCR_RW_FUNCS(icc_iar1_el1, ICC_IAR1) DEFINE_COPROCR_RW_FUNCS(icc_eoir0_el1, ICC_EOIR0) DEFINE_COPROCR_RW_FUNCS(icc_eoir1_el1, ICC_EOIR1) DEFINE_COPROCR_RW_FUNCS_64(icc_sgi0r_el1, ICC_SGI0R_EL1_64) DEFINE_COPROCR_WRITE_FUNC_64(icc_sgi1r, ICC_SGI1R_EL1_64) DEFINE_COPROCR_RW_FUNCS(hdcr, HDCR) DEFINE_COPROCR_RW_FUNCS(cnthp_ctl, CNTHP_CTL) DEFINE_COPROCR_READ_FUNC(pmcr, PMCR) /* * Address translation */ DEFINE_COPROCR_WRITE_FUNC(ats1cpr, ATS1CPR) DEFINE_COPROCR_WRITE_FUNC(ats1hr, ATS1HR) DEFINE_COPROCR_RW_FUNCS_64(par, PAR_64) DEFINE_COPROCR_RW_FUNCS(nsacr, NSACR) /* AArch32 coproc registers for 32bit MMU descriptor support */ DEFINE_COPROCR_RW_FUNCS(prrr, PRRR) DEFINE_COPROCR_RW_FUNCS(nmrr, NMRR) DEFINE_COPROCR_RW_FUNCS(dacr, DACR) DEFINE_COPROCR_RW_FUNCS(amcntenset0, AMCNTENSET0) DEFINE_COPROCR_RW_FUNCS(amcntenset1, AMCNTENSET1) DEFINE_COPROCR_RW_FUNCS(amcntenclr0, AMCNTENCLR0) DEFINE_COPROCR_RW_FUNCS(amcntenclr1, AMCNTENCLR1) DEFINE_COPROCR_RW_FUNCS_64(amevcntr00, AMEVCNTR00) DEFINE_COPROCR_RW_FUNCS_64(amevcntr01, AMEVCNTR01) DEFINE_COPROCR_RW_FUNCS_64(amevcntr02, AMEVCNTR02) DEFINE_COPROCR_RW_FUNCS_64(amevcntr03, AMEVCNTR03) /* * TLBI operation prototypes */ DEFINE_TLBIOP_FUNC(all, TLBIALL) DEFINE_TLBIOP_FUNC(allis, TLBIALLIS) DEFINE_TLBIOP_PARAM_FUNC(mva, TLBIMVA) DEFINE_TLBIOP_PARAM_FUNC(mvaa, TLBIMVAA) DEFINE_TLBIOP_PARAM_FUNC(mvaais, TLBIMVAAIS) DEFINE_TLBIOP_PARAM_FUNC(mvahis, TLBIMVAHIS) /* * BPI operation prototypes. */ DEFINE_BPIOP_FUNC(allis, BPIALLIS) /* * DC operation prototypes */ DEFINE_DCOP_PARAM_FUNC(civac, DCCIMVAC) DEFINE_DCOP_PARAM_FUNC(ivac, DCIMVAC) #if ERRATA_A53_819472 || ERRATA_A53_824069 || ERRATA_A53_827319 DEFINE_DCOP_PARAM_FUNC(cvac, DCCIMVAC) #else DEFINE_DCOP_PARAM_FUNC(cvac, DCCMVAC) #endif /* Previously defined accessor functions with incomplete register names */ #define dsb() dsbsy() #define dmb() dmbsy() /* dmb ld is not valid for armv7/thumb machines, so alias it to dmb */ #if ARM_ARCH_MAJOR == 7 #define dmbld() dmb() #endif #define IS_IN_SECURE() \ (GET_NS_BIT(read_scr()) == 0) #define IS_IN_HYP() (GET_M32(read_cpsr()) == MODE32_hyp) #define IS_IN_SVC() (GET_M32(read_cpsr()) == MODE32_svc) #define IS_IN_MON() (GET_M32(read_cpsr()) == MODE32_mon) #define IS_IN_EL2() IS_IN_HYP() /* If EL3 is AArch32, then secure PL1 and monitor mode correspond to EL3 */ #define IS_IN_EL3() \ ((GET_M32(read_cpsr()) == MODE32_mon) || \ (IS_IN_SECURE() && (GET_M32(read_cpsr()) != MODE32_usr))) static inline unsigned int get_current_el(void) { if (IS_IN_EL3()) { return 3U; } else if (IS_IN_EL2()) { return 2U; } else { return 1U; } } /* Macros for compatibility with AArch64 system registers */ #define read_mpidr_el1() read_mpidr() #define read_scr_el3() read_scr() #define write_scr_el3(_v) write_scr(_v) #define read_hcr_el2() read_hcr() #define write_hcr_el2(_v) write_hcr(_v) #define read_cpacr_el1() read_cpacr() #define write_cpacr_el1(_v) write_cpacr(_v) #define read_cntfrq_el0() read_cntfrq() #define write_cntfrq_el0(_v) write_cntfrq(_v) #define read_isr_el1() read_isr() #define read_cntpct_el0() read64_cntpct() #define read_ctr_el0() read_ctr() #define write_icc_sgi0r_el1(_v) write64_icc_sgi0r_el1(_v) #define read_daif() read_cpsr() #define write_daif(flags) write_cpsr(flags) #define read_cnthp_cval_el2() read64_cnthp_cval_el2() #define write_cnthp_cval_el2(v) write64_cnthp_cval_el2(v) #define read_amcntenset0_el0() read_amcntenset0() #define read_amcntenset1_el0() read_amcntenset1() /* Helper functions to manipulate CPSR */ static inline void enable_irq(void) { /* * The compiler memory barrier will prevent the compiler from * scheduling non-volatile memory access after the write to the * register. * * This could happen if some initialization code issues non-volatile * accesses to an area used by an interrupt handler, in the assumption * that it is safe as the interrupts are disabled at the time it does * that (according to program order). However, non-volatile accesses * are not necessarily in program order relatively with volatile inline * assembly statements (and volatile accesses). */ COMPILER_BARRIER(); __asm__ volatile ("cpsie i"); isb(); } static inline void enable_serror(void) { COMPILER_BARRIER(); __asm__ volatile ("cpsie a"); isb(); } static inline void enable_fiq(void) { COMPILER_BARRIER(); __asm__ volatile ("cpsie f"); isb(); } static inline void disable_irq(void) { COMPILER_BARRIER(); __asm__ volatile ("cpsid i"); isb(); } static inline void disable_serror(void) { COMPILER_BARRIER(); __asm__ volatile ("cpsid a"); isb(); } static inline void disable_fiq(void) { COMPILER_BARRIER(); __asm__ volatile ("cpsid f"); isb(); } #endif /* ARCH_HELPERS_H */ trusted-firmware-a-2.2/include/arch/aarch32/asm_macros.S000066400000000000000000000130301355360272700231410ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ASM_MACROS_S #define ASM_MACROS_S #include #include #include /* * TLBI instruction with type specifier that implements the workaround for * errata 813419 of Cortex-A57. */ #if ERRATA_A57_813419 #define TLB_INVALIDATE(_reg, _coproc) \ stcopr _reg, _coproc; \ dsb ish; \ stcopr _reg, _coproc #else #define TLB_INVALIDATE(_reg, _coproc) \ stcopr _reg, _coproc #endif #define WORD_SIZE 4 /* * Co processor register accessors */ .macro ldcopr reg, coproc, opc1, CRn, CRm, opc2 mrc \coproc, \opc1, \reg, \CRn, \CRm, \opc2 .endm .macro ldcopr16 reg1, reg2, coproc, opc1, CRm mrrc \coproc, \opc1, \reg1, \reg2, \CRm .endm .macro stcopr reg, coproc, opc1, CRn, CRm, opc2 mcr \coproc, \opc1, \reg, \CRn, \CRm, \opc2 .endm .macro stcopr16 reg1, reg2, coproc, opc1, CRm mcrr \coproc, \opc1, \reg1, \reg2, \CRm .endm /* Cache line size helpers */ .macro dcache_line_size reg, tmp ldcopr \tmp, CTR ubfx \tmp, \tmp, #CTR_DMINLINE_SHIFT, #CTR_DMINLINE_WIDTH mov \reg, #WORD_SIZE lsl \reg, \reg, \tmp .endm .macro icache_line_size reg, tmp ldcopr \tmp, CTR and \tmp, \tmp, #CTR_IMINLINE_MASK mov \reg, #WORD_SIZE lsl \reg, \reg, \tmp .endm /* * Declare the exception vector table, enforcing it is aligned on a * 32 byte boundary. */ .macro vector_base label .section .vectors, "ax" .align 5 \label: .endm /* * This macro calculates the base address of the current CPU's multi * processor(MP) stack using the plat_my_core_pos() index, the name of * the stack storage and the size of each stack. * Out: r0 = physical address of stack base * Clobber: r14, r1, r2 */ .macro get_my_mp_stack _name, _size bl plat_my_core_pos ldr r2, =(\_name + \_size) mov r1, #\_size mla r0, r0, r1, r2 .endm /* * This macro calculates the base address of a uniprocessor(UP) stack * using the name of the stack storage and the size of the stack * Out: r0 = physical address of stack base */ .macro get_up_stack _name, _size ldr r0, =(\_name + \_size) .endm #if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION) /* * ARMv7 cores without Virtualization extension do not support the * eret instruction. */ .macro eret movs pc, lr .endm #endif #if (ARM_ARCH_MAJOR == 7) /* ARMv7 does not support stl instruction */ .macro stl _reg, _write_lock dmb str \_reg, \_write_lock dsb .endm #endif /* * Helper macro to generate the best mov/movw/movt combinations * according to the value to be moved. */ .macro mov_imm _reg, _val .if ((\_val) & 0xffff0000) == 0 mov \_reg, #(\_val) .else movw \_reg, #((\_val) & 0xffff) movt \_reg, #((\_val) >> 16) .endif .endm /* * Macro to mark instances where we're jumping to a function and don't * expect a return. To provide the function being jumped to with * additional information, we use 'bl' instruction to jump rather than * 'b'. * * Debuggers infer the location of a call from where LR points to, which * is usually the instruction after 'bl'. If this macro expansion * happens to be the last location in a function, that'll cause the LR * to point a location beyond the function, thereby misleading debugger * back trace. We therefore insert a 'nop' after the function call for * debug builds, unless 'skip_nop' parameter is non-zero. */ .macro no_ret _func:req, skip_nop=0 bl \_func #if DEBUG .ifeq \skip_nop nop .endif #endif .endm /* * Reserve space for a spin lock in assembly file. */ .macro define_asm_spinlock _name:req .align SPINLOCK_ASM_ALIGN \_name: .space SPINLOCK_ASM_SIZE .endm /* * Helper macro to OR the bottom 32 bits of `_val` into `_reg_l` * and the top 32 bits of `_val` into `_reg_h`. If either the bottom * or top word of `_val` is zero, the corresponding OR operation * is skipped. */ .macro orr64_imm _reg_l, _reg_h, _val .if (\_val >> 32) orr \_reg_h, \_reg_h, #(\_val >> 32) .endif .if (\_val & 0xffffffff) orr \_reg_l, \_reg_l, #(\_val & 0xffffffff) .endif .endm /* * Helper macro to bitwise-clear bits in `_reg_l` and * `_reg_h` given a 64 bit immediate `_val`. The set bits * in the bottom word of `_val` dictate which bits from * `_reg_l` should be cleared. Similarly, the set bits in * the top word of `_val` dictate which bits from `_reg_h` * should be cleared. If either the bottom or top word of * `_val` is zero, the corresponding BIC operation is skipped. */ .macro bic64_imm _reg_l, _reg_h, _val .if (\_val >> 32) bic \_reg_h, \_reg_h, #(\_val >> 32) .endif .if (\_val & 0xffffffff) bic \_reg_l, \_reg_l, #(\_val & 0xffffffff) .endif .endm /* * Helper macro for carrying out division in software when * hardware division is not suported. \top holds the dividend * in the function call and the remainder after * the function is executed. \bot holds the divisor. \div holds * the quotient and \temp is a temporary registed used in calcualtion. * The division algorithm has been obtained from: * http://www.keil.com/support/man/docs/armasm/armasm_dom1359731155623.htm */ .macro softudiv div:req,top:req,bot:req,temp:req mov \temp, \bot cmp \temp, \top, lsr #1 div1: movls \temp, \temp, lsl #1 cmp \temp, \top, lsr #1 bls div1 mov \div, #0 div2: cmp \top, \temp subcs \top, \top,\temp ADC \div, \div, \div mov \temp, \temp, lsr #1 cmp \temp, \bot bhs div2 .endm #endif /* ASM_MACROS_S */ trusted-firmware-a-2.2/include/arch/aarch32/assert_macros.S000066400000000000000000000011131355360272700236610ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ASSERT_MACROS_S #define ASSERT_MACROS_S /* * Assembler macro to enable asm_assert. We assume that the stack is * initialized prior to invoking this macro. */ #define ASM_ASSERT(_cc) \ .ifndef .L_assert_filename ;\ .pushsection .rodata.str1.1, "aS" ;\ .L_assert_filename: ;\ .string __FILE__ ;\ .popsection ;\ .endif ;\ b##_cc 300f ;\ ldr r0, =.L_assert_filename ;\ ldr r1, =__LINE__ ;\ b asm_assert;\ 300: #endif /* ASSERT_MACROS_S */ trusted-firmware-a-2.2/include/arch/aarch32/console_macros.S000066400000000000000000000026041355360272700240300ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CONSOLE_MACROS_S #define CONSOLE_MACROS_S #include /* * This macro encapsulates the common setup that has to be done at the end of * a console driver's register function. It will register all of the driver's * callbacks in the console_t structure and initialize the flags field (by * default consoles are enabled for the "boot" and "crash" states, this can be * changed after registration with the console_set_scope() function). It ends * with a tail call that will include return to the caller. * REQUIRES console_t pointer in r0 and a valid return address in lr. */ .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 /* CONSOLE_MACROS_S */ trusted-firmware-a-2.2/include/arch/aarch32/el3_common_macros.S000066400000000000000000000321471355360272700244260ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef EL3_COMMON_MACROS_S #define EL3_COMMON_MACROS_S #include #include #include /* * Helper macro to initialise EL3 registers we care about. */ .macro el3_arch_init_common /* --------------------------------------------------------------------- * SCTLR has already been initialised - read current value before * modifying. * * SCTLR.I: Enable the instruction cache. * * SCTLR.A: Enable Alignment fault checking. All instructions that load * or store one or more registers have an alignment check that the * address being accessed is aligned to the size of the data element(s) * being accessed. * --------------------------------------------------------------------- */ ldr r1, =(SCTLR_I_BIT | SCTLR_A_BIT) ldcopr r0, SCTLR orr r0, r0, r1 stcopr r0, SCTLR isb /* --------------------------------------------------------------------- * Initialise SCR, setting all fields rather than relying on the hw. * * SCR.SIF: Enabled so that Secure state instruction fetches from * Non-secure memory are not permitted. * --------------------------------------------------------------------- */ ldr r0, =(SCR_RESET_VAL | SCR_SIF_BIT) stcopr r0, SCR /* ----------------------------------------------------- * Enable the Asynchronous data abort now that the * exception vectors have been setup. * ----------------------------------------------------- */ cpsie a isb /* --------------------------------------------------------------------- * Initialise NSACR, setting all the fields, except for the * IMPLEMENTATION DEFINED field, rather than relying on the hw. Some * fields are architecturally UNKNOWN on reset. * * NSACR_ENABLE_FP_ACCESS: Represents NSACR.cp11 and NSACR.cp10. The * cp11 field is ignored, but is set to same value as cp10. The cp10 * field is set to allow access to Advanced SIMD and floating point * features from both Security states. * --------------------------------------------------------------------- */ ldcopr r0, NSACR and r0, r0, #NSACR_IMP_DEF_MASK orr r0, r0, #(NSACR_RESET_VAL | NSACR_ENABLE_FP_ACCESS) stcopr r0, NSACR isb /* --------------------------------------------------------------------- * Initialise CPACR, setting all fields rather than relying on hw. Some * fields are architecturally UNKNOWN on reset. * * CPACR.TRCDIS: Trap control for PL0 and PL1 System register accesses * to trace registers. Set to zero to allow access. * * CPACR_ENABLE_FP_ACCESS: Represents CPACR.cp11 and CPACR.cp10. The * cp11 field is ignored, but is set to same value as cp10. The cp10 * field is set to allow full access from PL0 and PL1 to floating-point * and Advanced SIMD features. * --------------------------------------------------------------------- */ ldr r0, =((CPACR_RESET_VAL | CPACR_ENABLE_FP_ACCESS) & ~(TRCDIS_BIT)) stcopr r0, CPACR isb /* --------------------------------------------------------------------- * Initialise FPEXC, setting all fields rather than relying on hw. Some * fields are architecturally UNKNOWN on reset and are set to zero * except for field(s) listed below. * * FPEXC.EN: Enable access to Advanced SIMD and floating point features * from all exception levels. * * __SOFTFP__: Predefined macro exposed by soft-float toolchain. * ARMv7 and Cortex-A32(ARMv8/aarch32) has both soft-float and * hard-float variants of toolchain, avoid compiling below code with * soft-float toolchain as "vmsr" instruction will not be recognized. * --------------------------------------------------------------------- */ #if ((ARM_ARCH_MAJOR > 7) || defined(ARMV7_SUPPORTS_VFP)) && !(__SOFTFP__) ldr r0, =(FPEXC_RESET_VAL | FPEXC_EN_BIT) vmsr FPEXC, r0 isb #endif #if (ARM_ARCH_MAJOR > 7) /* --------------------------------------------------------------------- * Initialise SDCR, setting all the fields rather than relying on hw. * * SDCR.SPD: Disable AArch32 privileged debug. Debug exceptions from * Secure EL1 are disabled. * * SDCR.SCCD: Set to one so that cycle counting by PMCCNTR is prohibited * in Secure state. This bit is RES0 in versions of the architecture * earlier than ARMv8.5, setting it to 1 doesn't have any effect on * them. * --------------------------------------------------------------------- */ ldr r0, =(SDCR_RESET_VAL | SDCR_SPD(SDCR_SPD_DISABLE) | SDCR_SCCD_BIT) stcopr r0, SDCR /* --------------------------------------------------------------------- * Initialise PMCR, setting all fields rather than relying * on hw. Some fields are architecturally UNKNOWN on reset. * * PMCR.LP: Set to one so that event counter overflow, that * is recorded in PMOVSCLR[0-30], occurs on the increment * that changes PMEVCNTR[63] from 1 to 0, when ARMv8.5-PMU * is implemented. This bit is RES0 in versions of the architecture * earlier than ARMv8.5, setting it to 1 doesn't have any effect * on them. * This bit is Reserved, UNK/SBZP in ARMv7. * * PMCR.LC: Set to one so that cycle counter overflow, that * is recorded in PMOVSCLR[31], occurs on the increment * that changes PMCCNTR[63] from 1 to 0. * This bit is Reserved, UNK/SBZP in ARMv7. * * PMCR.DP: Set to one to prohibit cycle counting whilst in Secure mode. * --------------------------------------------------------------------- */ ldr r0, =(PMCR_RESET_VAL | PMCR_DP_BIT | PMCR_LC_BIT | \ PMCR_LP_BIT) #else ldr r0, =(PMCR_RESET_VAL | PMCR_DP_BIT) #endif stcopr r0, PMCR /* * If Data Independent Timing (DIT) functionality is implemented, * always enable DIT in EL3 */ ldcopr r0, ID_PFR0 and r0, r0, #(ID_PFR0_DIT_MASK << ID_PFR0_DIT_SHIFT) cmp r0, #ID_PFR0_DIT_SUPPORTED bne 1f mrs r0, cpsr orr r0, r0, #CPSR_DIT_BIT msr cpsr_cxsf, r0 1: .endm /* ----------------------------------------------------------------------------- * This is the super set of actions that need to be performed during a cold boot * or a warm boot in EL3. This code is shared by BL1 and BL32 (SP_MIN). * * This macro will always perform reset handling, architectural initialisations * and stack setup. The rest of the actions are optional because they might not * be needed, depending on the context in which this macro is called. This is * why this macro is parameterised ; each parameter allows to enable/disable * some actions. * * _init_sctlr: * Whether the macro needs to initialise the SCTLR register including * configuring the endianness of data accesses. * * _warm_boot_mailbox: * Whether the macro needs to detect the type of boot (cold/warm). The * detection is based on the platform entrypoint address : if it is zero * then it is a cold boot, otherwise it is a warm boot. In the latter case, * this macro jumps on the platform entrypoint address. * * _secondary_cold_boot: * Whether the macro needs to identify the CPU that is calling it: primary * CPU or secondary CPU. The primary CPU will be allowed to carry on with * the platform initialisations, while the secondaries will be put in a * platform-specific state in the meantime. * * If the caller knows this macro will only be called by the primary CPU * then this parameter can be defined to 0 to skip this step. * * _init_memory: * Whether the macro needs to initialise the memory. * * _init_c_runtime: * Whether the macro needs to initialise the C runtime environment. * * _exception_vectors: * Address of the exception vectors to program in the VBAR_EL3 register. * ----------------------------------------------------------------------------- */ .macro el3_entrypoint_common \ _init_sctlr, _warm_boot_mailbox, _secondary_cold_boot, \ _init_memory, _init_c_runtime, _exception_vectors /* Make sure we are in Secure Mode */ #if ENABLE_ASSERTIONS ldcopr r0, SCR tst r0, #SCR_NS_BIT ASM_ASSERT(eq) #endif .if \_init_sctlr /* ------------------------------------------------------------- * This is the initialisation of SCTLR and so must ensure that * all fields are explicitly set rather than relying on hw. Some * fields reset to an IMPLEMENTATION DEFINED value. * * SCTLR.TE: Set to zero so that exceptions to an Exception * Level executing at PL1 are taken to A32 state. * * SCTLR.EE: Set the CPU endianness before doing anything that * might involve memory reads or writes. Set to zero to select * Little Endian. * * SCTLR.V: Set to zero to select the normal exception vectors * with base address held in VBAR. * * SCTLR.DSSBS: Set to zero to disable speculation store bypass * safe behaviour upon exception entry to EL3. * ------------------------------------------------------------- */ ldr r0, =(SCTLR_RESET_VAL & ~(SCTLR_TE_BIT | SCTLR_EE_BIT | \ SCTLR_V_BIT | SCTLR_DSSBS_BIT)) stcopr r0, SCTLR isb .endif /* _init_sctlr */ /* Switch to monitor mode */ cps #MODE32_mon isb .if \_warm_boot_mailbox /* ------------------------------------------------------------- * This code will be executed for both warm and cold resets. * Now is the time to distinguish between the two. * Query the platform entrypoint address and if it is not zero * then it means it is a warm boot so jump to this address. * ------------------------------------------------------------- */ bl plat_get_my_entrypoint cmp r0, #0 bxne r0 .endif /* _warm_boot_mailbox */ /* --------------------------------------------------------------------- * Set the exception vectors (VBAR/MVBAR). * --------------------------------------------------------------------- */ ldr r0, =\_exception_vectors stcopr r0, VBAR stcopr r0, MVBAR isb /* --------------------------------------------------------------------- * It is a cold boot. * Perform any processor specific actions upon reset e.g. cache, TLB * invalidations etc. * --------------------------------------------------------------------- */ bl reset_handler el3_arch_init_common .if \_secondary_cold_boot /* ------------------------------------------------------------- * Check if this is a primary or secondary CPU cold boot. * The primary CPU will set up the platform while the * secondaries are placed in a platform-specific state until the * primary CPU performs the necessary actions to bring them out * of that state and allows entry into the OS. * ------------------------------------------------------------- */ bl plat_is_my_cpu_primary cmp r0, #0 bne do_primary_cold_boot /* This is a cold boot on a secondary CPU */ bl plat_secondary_cold_boot_setup /* plat_secondary_cold_boot_setup() is not supposed to return */ no_ret plat_panic_handler do_primary_cold_boot: .endif /* _secondary_cold_boot */ /* --------------------------------------------------------------------- * Initialize memory now. Secondary CPU initialization won't get to this * point. * --------------------------------------------------------------------- */ .if \_init_memory bl platform_mem_init .endif /* _init_memory */ /* --------------------------------------------------------------------- * Init C runtime environment: * - Zero-initialise the NOBITS sections. There are 2 of them: * - the .bss section; * - the coherent memory section (if any). * - Relocate the data section from ROM to RAM, if required. * --------------------------------------------------------------------- */ .if \_init_c_runtime #if defined(IMAGE_BL32) || (defined(IMAGE_BL2) && BL2_AT_EL3) /* ----------------------------------------------------------------- * Invalidate the RW memory used by the image. This * includes the data and NOBITS sections. This is done to * safeguard against possible corruption of this memory by * dirty cache lines in a system cache as a result of use by * an earlier boot loader stage. * ----------------------------------------------------------------- */ ldr r0, =__RW_START__ ldr r1, =__RW_END__ sub r1, r1, r0 bl inv_dcache_range #endif ldr r0, =__BSS_START__ ldr r1, =__BSS_SIZE__ bl zeromem #if USE_COHERENT_MEM ldr r0, =__COHERENT_RAM_START__ ldr r1, =__COHERENT_RAM_UNALIGNED_SIZE__ bl zeromem #endif #if defined(IMAGE_BL1) || (defined(IMAGE_BL2) && BL2_AT_EL3 && BL2_IN_XIP_MEM) /* ----------------------------------------------------- * Copy data from ROM to RAM. * ----------------------------------------------------- */ ldr r0, =__DATA_RAM_START__ ldr r1, =__DATA_ROM_START__ ldr r2, =__DATA_SIZE__ bl memcpy4 #endif .endif /* _init_c_runtime */ /* --------------------------------------------------------------------- * Allocate a stack whose memory will be marked as Normal-IS-WBWA when * the MMU is enabled. There is no risk of reading stale stack memory * after enabling the MMU as only the primary CPU is running at the * moment. * --------------------------------------------------------------------- */ bl plat_set_my_stack #if STACK_PROTECTOR_ENABLED .if \_init_c_runtime bl update_stack_protector_canary .endif /* _init_c_runtime */ #endif .endm #endif /* EL3_COMMON_MACROS_S */ trusted-firmware-a-2.2/include/arch/aarch32/smccc_helpers.h000066400000000000000000000114431355360272700236620ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SMCCC_HELPERS_H #define SMCCC_HELPERS_H #include /* These are offsets to registers in smc_ctx_t */ #define SMC_CTX_GPREG_R0 U(0x0) #define SMC_CTX_GPREG_R1 U(0x4) #define SMC_CTX_GPREG_R2 U(0x8) #define SMC_CTX_GPREG_R3 U(0xC) #define SMC_CTX_GPREG_R4 U(0x10) #define SMC_CTX_GPREG_R5 U(0x14) #define SMC_CTX_SP_USR U(0x34) #define SMC_CTX_SPSR_MON U(0x78) #define SMC_CTX_SP_MON U(0x7C) #define SMC_CTX_LR_MON U(0x80) #define SMC_CTX_SCR U(0x84) #define SMC_CTX_PMCR U(0x88) #define SMC_CTX_SIZE U(0x90) #ifndef __ASSEMBLER__ #include #include /* * The generic structure to save arguments and callee saved registers during * an SMC. Also this structure is used to store the result return values after * the completion of SMC service. */ typedef struct smc_ctx { u_register_t r0; u_register_t r1; u_register_t r2; u_register_t r3; u_register_t r4; u_register_t r5; u_register_t r6; u_register_t r7; u_register_t r8; u_register_t r9; u_register_t r10; u_register_t r11; u_register_t r12; /* spsr_usr doesn't exist */ u_register_t sp_usr; u_register_t lr_usr; u_register_t spsr_irq; u_register_t sp_irq; u_register_t lr_irq; u_register_t spsr_fiq; u_register_t sp_fiq; u_register_t lr_fiq; u_register_t spsr_svc; u_register_t sp_svc; u_register_t lr_svc; u_register_t spsr_abt; u_register_t sp_abt; u_register_t lr_abt; u_register_t spsr_und; u_register_t sp_und; u_register_t lr_und; u_register_t spsr_mon; /* * `sp_mon` will point to the C runtime stack in monitor mode. But prior * to exit from SMC, this will point to the `smc_ctx_t` so that * on next entry due to SMC, the `smc_ctx_t` can be easily accessed. */ u_register_t sp_mon; u_register_t lr_mon; u_register_t scr; u_register_t pmcr; /* * The workaround for CVE-2017-5715 requires storing information in * the bottom 3 bits of the stack pointer. Add a padding field to * force the size of the struct to be a multiple of 8. */ u_register_t pad; } smc_ctx_t __aligned(8); /* * Compile time assertions related to the 'smc_context' structure to * ensure that the assembler and the compiler view of the offsets of * the structure members is the same. */ CASSERT(SMC_CTX_GPREG_R0 == __builtin_offsetof(smc_ctx_t, r0), \ assert_smc_ctx_greg_r0_offset_mismatch); CASSERT(SMC_CTX_GPREG_R1 == __builtin_offsetof(smc_ctx_t, r1), \ assert_smc_ctx_greg_r1_offset_mismatch); CASSERT(SMC_CTX_GPREG_R2 == __builtin_offsetof(smc_ctx_t, r2), \ assert_smc_ctx_greg_r2_offset_mismatch); CASSERT(SMC_CTX_GPREG_R3 == __builtin_offsetof(smc_ctx_t, r3), \ assert_smc_ctx_greg_r3_offset_mismatch); CASSERT(SMC_CTX_GPREG_R4 == __builtin_offsetof(smc_ctx_t, r4), \ assert_smc_ctx_greg_r4_offset_mismatch); CASSERT(SMC_CTX_SP_USR == __builtin_offsetof(smc_ctx_t, sp_usr), \ assert_smc_ctx_sp_usr_offset_mismatch); CASSERT(SMC_CTX_LR_MON == __builtin_offsetof(smc_ctx_t, lr_mon), \ assert_smc_ctx_lr_mon_offset_mismatch); CASSERT(SMC_CTX_SPSR_MON == __builtin_offsetof(smc_ctx_t, spsr_mon), \ assert_smc_ctx_spsr_mon_offset_mismatch); CASSERT((sizeof(smc_ctx_t) & 0x7U) == 0U, assert_smc_ctx_not_aligned); CASSERT(SMC_CTX_SIZE == sizeof(smc_ctx_t), assert_smc_ctx_size_mismatch); /* Convenience macros to return from SMC handler */ #define SMC_RET0(_h) { \ return (uintptr_t)(_h); \ } #define SMC_RET1(_h, _r0) { \ ((smc_ctx_t *)(_h))->r0 = (_r0); \ SMC_RET0(_h); \ } #define SMC_RET2(_h, _r0, _r1) { \ ((smc_ctx_t *)(_h))->r1 = (_r1); \ SMC_RET1(_h, (_r0)); \ } #define SMC_RET3(_h, _r0, _r1, _r2) { \ ((smc_ctx_t *)(_h))->r2 = (_r2); \ SMC_RET2(_h, (_r0), (_r1)); \ } #define SMC_RET4(_h, _r0, _r1, _r2, _r3) { \ ((smc_ctx_t *)(_h))->r3 = (_r3); \ SMC_RET3(_h, (_r0), (_r1), (_r2)); \ } /* * Helper macro to retrieve the SMC parameters from smc_ctx_t. */ #define get_smc_params_from_ctx(_hdl, _r1, _r2, _r3, _r4) { \ _r1 = ((smc_ctx_t *)_hdl)->r1; \ _r2 = ((smc_ctx_t *)_hdl)->r2; \ _r3 = ((smc_ctx_t *)_hdl)->r3; \ _r4 = ((smc_ctx_t *)_hdl)->r4; \ } /* ------------------------------------------------------------------------ * Helper APIs for setting and retrieving appropriate `smc_ctx_t`. * These functions need to implemented by the BL including this library. * ------------------------------------------------------------------------ */ /* Get the pointer to `smc_ctx_t` corresponding to the security state. */ void *smc_get_ctx(unsigned int security_state); /* Set the next `smc_ctx_t` corresponding to the security state. */ void smc_set_next_ctx(unsigned int security_state); /* Get the pointer to next `smc_ctx_t` already set by `smc_set_next_ctx()`. */ void *smc_get_next_ctx(void); #endif /*__ASSEMBLER__*/ #endif /* SMCCC_HELPERS_H */ trusted-firmware-a-2.2/include/arch/aarch32/smccc_macros.S000066400000000000000000000115231355360272700234560ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SMCCC_MACROS_S #define SMCCC_MACROS_S #include /* * Macro to save the General purpose registers (r0 - r12), the banked * spsr, lr, sp registers and the `scr` register to the SMC context on entry * due a SMC call. The `lr` of the current mode (monitor) is expected to be * already saved. The `sp` must point to the `smc_ctx_t` to save to. * Additionally, also save the 'pmcr' register as this is updated whilst * executing in the secure world. */ .macro smccc_save_gp_mode_regs /* Save r0 - r12 in the SMC context */ stm sp, {r0-r12} mov r0, sp add r0, r0, #SMC_CTX_SP_USR #if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION) /* Must be in secure state to restore Monitor mode */ ldcopr r4, SCR bic r2, r4, #SCR_NS_BIT stcopr r2, SCR isb cps #MODE32_sys stm r0!, {sp, lr} cps #MODE32_irq mrs r2, spsr stm r0!, {r2, sp, lr} cps #MODE32_fiq mrs r2, spsr stm r0!, {r2, sp, lr} cps #MODE32_svc mrs r2, spsr stm r0!, {r2, sp, lr} cps #MODE32_abt mrs r2, spsr stm r0!, {r2, sp, lr} cps #MODE32_und mrs r2, spsr stm r0!, {r2, sp, lr} /* lr_mon is already saved by caller */ cps #MODE32_mon mrs r2, spsr stm r0!, {r2} stcopr r4, SCR #else /* Save the banked registers including the current SPSR and LR */ mrs r4, sp_usr mrs r5, lr_usr mrs r6, spsr_irq mrs r7, sp_irq mrs r8, lr_irq mrs r9, spsr_fiq mrs r10, sp_fiq mrs r11, lr_fiq mrs r12, spsr_svc stm r0!, {r4-r12} mrs r4, sp_svc mrs r5, lr_svc mrs r6, spsr_abt mrs r7, sp_abt mrs r8, lr_abt mrs r9, spsr_und mrs r10, sp_und mrs r11, lr_und mrs r12, spsr stm r0!, {r4-r12} /* lr_mon is already saved by caller */ ldcopr r4, SCR #if ARM_ARCH_MAJOR > 7 /* * Check if earlier initialization of SDCR.SCCD to 1 * failed, meaning that ARMv8-PMU is not implemented, * cycle counting is not disabled and PMCR should be * saved in Non-secure context. */ ldcopr r5, SDCR tst r5, #SDCR_SCCD_BIT bne 1f #endif /* Secure Cycle Counter is not disabled */ #endif ldcopr r5, PMCR /* Check caller's security state */ tst r4, #SCR_NS_BIT beq 2f /* Save PMCR if called from Non-secure state */ str r5, [sp, #SMC_CTX_PMCR] /* Disable cycle counter when event counting is prohibited */ 2: orr r5, r5, #PMCR_DP_BIT stcopr r5, PMCR isb 1: str r4, [sp, #SMC_CTX_SCR] .endm /* * Macro to restore the `smc_ctx_t`, which includes the General purpose * registers and banked mode registers, and exit from the monitor mode. * r0 must point to the `smc_ctx_t` to restore from. */ .macro monitor_exit /* * Save the current sp and restore the smc context * pointer to sp which will be used for handling the * next SMC. */ str sp, [r0, #SMC_CTX_SP_MON] mov sp, r0 /* * Restore SCR first so that we access the right banked register * when the other mode registers are restored. */ ldr r1, [r0, #SMC_CTX_SCR] stcopr r1, SCR isb /* * Restore PMCR when returning to Non-secure state */ tst r1, #SCR_NS_BIT beq 2f /* * Back to Non-secure state */ #if ARM_ARCH_MAJOR > 7 /* * Check if earlier initialization SDCR.SCCD to 1 * failed, meaning that ARMv8-PMU is not implemented and * PMCR should be restored from Non-secure context. */ ldcopr r1, SDCR tst r1, #SDCR_SCCD_BIT bne 2f #endif /* * Restore the PMCR register. */ ldr r1, [r0, #SMC_CTX_PMCR] stcopr r1, PMCR 2: /* Restore the banked registers including the current SPSR */ add r1, r0, #SMC_CTX_SP_USR #if ARM_ARCH_MAJOR == 7 && !defined(ARMV7_SUPPORTS_VIRTUALIZATION) /* Must be in secure state to restore Monitor mode */ ldcopr r4, SCR bic r2, r4, #SCR_NS_BIT stcopr r2, SCR isb cps #MODE32_sys ldm r1!, {sp, lr} cps #MODE32_irq ldm r1!, {r2, sp, lr} msr spsr_fsxc, r2 cps #MODE32_fiq ldm r1!, {r2, sp, lr} msr spsr_fsxc, r2 cps #MODE32_svc ldm r1!, {r2, sp, lr} msr spsr_fsxc, r2 cps #MODE32_abt ldm r1!, {r2, sp, lr} msr spsr_fsxc, r2 cps #MODE32_und ldm r1!, {r2, sp, lr} msr spsr_fsxc, r2 cps #MODE32_mon ldm r1!, {r2} msr spsr_fsxc, r2 stcopr r4, SCR isb #else ldm r1!, {r4-r12} msr sp_usr, r4 msr lr_usr, r5 msr spsr_irq, r6 msr sp_irq, r7 msr lr_irq, r8 msr spsr_fiq, r9 msr sp_fiq, r10 msr lr_fiq, r11 msr spsr_svc, r12 ldm r1!, {r4-r12} msr sp_svc, r4 msr lr_svc, r5 msr spsr_abt, r6 msr sp_abt, r7 msr lr_abt, r8 msr spsr_und, r9 msr sp_und, r10 msr lr_und, r11 /* * Use the `_fsxc` suffix explicitly to instruct the assembler * to update all the 32 bits of SPSR. Else, by default, the * assembler assumes `_fc` suffix which only modifies * f->[31:24] and c->[7:0] bits of SPSR. */ msr spsr_fsxc, r12 #endif /* Restore the LR */ ldr lr, [r0, #SMC_CTX_LR_MON] /* Restore the rest of the general purpose registers */ ldm r0, {r0-r12} eret .endm #endif /* SMCCC_MACROS_S */ trusted-firmware-a-2.2/include/arch/aarch64/000077500000000000000000000000001355360272700207015ustar00rootroot00000000000000trusted-firmware-a-2.2/include/arch/aarch64/arch.h000066400000000000000000000726201355360272700217760ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARCH_H #define ARCH_H #include /******************************************************************************* * MIDR bit definitions ******************************************************************************/ #define MIDR_IMPL_MASK U(0xff) #define MIDR_IMPL_SHIFT U(0x18) #define MIDR_VAR_SHIFT U(20) #define MIDR_VAR_BITS U(4) #define MIDR_VAR_MASK U(0xf) #define MIDR_REV_SHIFT U(0) #define MIDR_REV_BITS U(4) #define MIDR_REV_MASK U(0xf) #define MIDR_PN_MASK U(0xfff) #define MIDR_PN_SHIFT U(0x4) /******************************************************************************* * MPIDR macros ******************************************************************************/ #define MPIDR_MT_MASK (ULL(1) << 24) #define MPIDR_CPU_MASK MPIDR_AFFLVL_MASK #define MPIDR_CLUSTER_MASK (MPIDR_AFFLVL_MASK << MPIDR_AFFINITY_BITS) #define MPIDR_AFFINITY_BITS U(8) #define MPIDR_AFFLVL_MASK ULL(0xff) #define MPIDR_AFF0_SHIFT U(0) #define MPIDR_AFF1_SHIFT U(8) #define MPIDR_AFF2_SHIFT U(16) #define MPIDR_AFF3_SHIFT U(32) #define MPIDR_AFF_SHIFT(_n) MPIDR_AFF##_n##_SHIFT #define MPIDR_AFFINITY_MASK ULL(0xff00ffffff) #define MPIDR_AFFLVL_SHIFT U(3) #define MPIDR_AFFLVL0 ULL(0x0) #define MPIDR_AFFLVL1 ULL(0x1) #define MPIDR_AFFLVL2 ULL(0x2) #define MPIDR_AFFLVL3 ULL(0x3) #define MPIDR_AFFLVL(_n) MPIDR_AFFLVL##_n #define MPIDR_AFFLVL0_VAL(mpidr) \ (((mpidr) >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK) #define MPIDR_AFFLVL1_VAL(mpidr) \ (((mpidr) >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK) #define MPIDR_AFFLVL2_VAL(mpidr) \ (((mpidr) >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK) #define MPIDR_AFFLVL3_VAL(mpidr) \ (((mpidr) >> MPIDR_AFF3_SHIFT) & MPIDR_AFFLVL_MASK) /* * The MPIDR_MAX_AFFLVL count starts from 0. Take care to * add one while using this macro to define array sizes. * TODO: Support only the first 3 affinity levels for now. */ #define MPIDR_MAX_AFFLVL U(2) #define MPID_MASK (MPIDR_MT_MASK | \ (MPIDR_AFFLVL_MASK << MPIDR_AFF3_SHIFT) | \ (MPIDR_AFFLVL_MASK << MPIDR_AFF2_SHIFT) | \ (MPIDR_AFFLVL_MASK << MPIDR_AFF1_SHIFT) | \ (MPIDR_AFFLVL_MASK << MPIDR_AFF0_SHIFT)) #define MPIDR_AFF_ID(mpid, n) \ (((mpid) >> MPIDR_AFF_SHIFT(n)) & MPIDR_AFFLVL_MASK) /* * An invalid MPID. This value can be used by functions that return an MPID to * indicate an error. */ #define INVALID_MPID U(0xFFFFFFFF) /******************************************************************************* * Definitions for CPU system register interface to GICv3 ******************************************************************************/ #define ICC_IGRPEN1_EL1 S3_0_C12_C12_7 #define ICC_SGI1R S3_0_C12_C11_5 #define ICC_SRE_EL1 S3_0_C12_C12_5 #define ICC_SRE_EL2 S3_4_C12_C9_5 #define ICC_SRE_EL3 S3_6_C12_C12_5 #define ICC_CTLR_EL1 S3_0_C12_C12_4 #define ICC_CTLR_EL3 S3_6_C12_C12_4 #define ICC_PMR_EL1 S3_0_C4_C6_0 #define ICC_RPR_EL1 S3_0_C12_C11_3 #define ICC_IGRPEN1_EL3 S3_6_c12_c12_7 #define ICC_IGRPEN0_EL1 S3_0_c12_c12_6 #define ICC_HPPIR0_EL1 S3_0_c12_c8_2 #define ICC_HPPIR1_EL1 S3_0_c12_c12_2 #define ICC_IAR0_EL1 S3_0_c12_c8_0 #define ICC_IAR1_EL1 S3_0_c12_c12_0 #define ICC_EOIR0_EL1 S3_0_c12_c8_1 #define ICC_EOIR1_EL1 S3_0_c12_c12_1 #define ICC_SGI0R_EL1 S3_0_c12_c11_7 /******************************************************************************* * Generic timer memory mapped registers & offsets ******************************************************************************/ #define CNTCR_OFF U(0x000) #define CNTCV_OFF U(0x008) #define CNTFID_OFF U(0x020) #define CNTCR_EN (U(1) << 0) #define CNTCR_HDBG (U(1) << 1) #define CNTCR_FCREQ(x) ((x) << 8) /******************************************************************************* * System register bit definitions ******************************************************************************/ /* CLIDR definitions */ #define LOUIS_SHIFT U(21) #define LOC_SHIFT U(24) #define CTYPE_SHIFT(n) U(3 * (n - 1)) #define CLIDR_FIELD_WIDTH U(3) /* CSSELR definitions */ #define LEVEL_SHIFT U(1) /* Data cache set/way op type defines */ #define DCISW U(0x0) #define DCCISW U(0x1) #if ERRATA_A53_827319 #define DCCSW DCCISW #else #define DCCSW U(0x2) #endif /* ID_AA64PFR0_EL1 definitions */ #define ID_AA64PFR0_EL0_SHIFT U(0) #define ID_AA64PFR0_EL1_SHIFT U(4) #define ID_AA64PFR0_EL2_SHIFT U(8) #define ID_AA64PFR0_EL3_SHIFT U(12) #define ID_AA64PFR0_AMU_SHIFT U(44) #define ID_AA64PFR0_AMU_MASK ULL(0xf) #define ID_AA64PFR0_ELX_MASK ULL(0xf) #define ID_AA64PFR0_GIC_SHIFT U(24) #define ID_AA64PFR0_GIC_WIDTH U(4) #define ID_AA64PFR0_GIC_MASK ULL(0xf) #define ID_AA64PFR0_SVE_SHIFT U(32) #define ID_AA64PFR0_SVE_MASK ULL(0xf) #define ID_AA64PFR0_MPAM_SHIFT U(40) #define ID_AA64PFR0_MPAM_MASK ULL(0xf) #define ID_AA64PFR0_DIT_SHIFT U(48) #define ID_AA64PFR0_DIT_MASK ULL(0xf) #define ID_AA64PFR0_DIT_LENGTH U(4) #define ID_AA64PFR0_DIT_SUPPORTED U(1) #define ID_AA64PFR0_CSV2_SHIFT U(56) #define ID_AA64PFR0_CSV2_MASK ULL(0xf) #define ID_AA64PFR0_CSV2_LENGTH U(4) /* Exception level handling */ #define EL_IMPL_NONE ULL(0) #define EL_IMPL_A64ONLY ULL(1) #define EL_IMPL_A64_A32 ULL(2) /* ID_AA64DFR0_EL1.PMS definitions (for ARMv8.2+) */ #define ID_AA64DFR0_PMS_SHIFT U(32) #define ID_AA64DFR0_PMS_MASK ULL(0xf) /* ID_AA64ISAR1_EL1 definitions */ #define ID_AA64ISAR1_EL1 S3_0_C0_C6_1 #define ID_AA64ISAR1_GPI_SHIFT U(28) #define ID_AA64ISAR1_GPI_MASK ULL(0xf) #define ID_AA64ISAR1_GPA_SHIFT U(24) #define ID_AA64ISAR1_GPA_MASK ULL(0xf) #define ID_AA64ISAR1_API_SHIFT U(8) #define ID_AA64ISAR1_API_MASK ULL(0xf) #define ID_AA64ISAR1_APA_SHIFT U(4) #define ID_AA64ISAR1_APA_MASK ULL(0xf) /* ID_AA64MMFR0_EL1 definitions */ #define ID_AA64MMFR0_EL1_PARANGE_SHIFT U(0) #define ID_AA64MMFR0_EL1_PARANGE_MASK ULL(0xf) #define PARANGE_0000 U(32) #define PARANGE_0001 U(36) #define PARANGE_0010 U(40) #define PARANGE_0011 U(42) #define PARANGE_0100 U(44) #define PARANGE_0101 U(48) #define PARANGE_0110 U(52) #define ID_AA64MMFR0_EL1_TGRAN4_SHIFT U(28) #define ID_AA64MMFR0_EL1_TGRAN4_MASK ULL(0xf) #define ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED ULL(0x0) #define ID_AA64MMFR0_EL1_TGRAN4_NOT_SUPPORTED ULL(0xf) #define ID_AA64MMFR0_EL1_TGRAN64_SHIFT U(24) #define ID_AA64MMFR0_EL1_TGRAN64_MASK ULL(0xf) #define ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED ULL(0x0) #define ID_AA64MMFR0_EL1_TGRAN64_NOT_SUPPORTED ULL(0xf) #define ID_AA64MMFR0_EL1_TGRAN16_SHIFT U(20) #define ID_AA64MMFR0_EL1_TGRAN16_MASK ULL(0xf) #define ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED ULL(0x1) #define ID_AA64MMFR0_EL1_TGRAN16_NOT_SUPPORTED ULL(0x0) /* ID_AA64MMFR2_EL1 definitions */ #define ID_AA64MMFR2_EL1 S3_0_C0_C7_2 #define ID_AA64MMFR2_EL1_ST_SHIFT U(28) #define ID_AA64MMFR2_EL1_ST_MASK ULL(0xf) #define ID_AA64MMFR2_EL1_CNP_SHIFT U(0) #define ID_AA64MMFR2_EL1_CNP_MASK ULL(0xf) /* ID_AA64PFR1_EL1 definitions */ #define ID_AA64PFR1_EL1_SSBS_SHIFT U(4) #define ID_AA64PFR1_EL1_SSBS_MASK ULL(0xf) #define SSBS_UNAVAILABLE ULL(0) /* No architectural SSBS support */ #define ID_AA64PFR1_EL1_BT_SHIFT U(0) #define ID_AA64PFR1_EL1_BT_MASK ULL(0xf) #define BTI_IMPLEMENTED ULL(1) /* The BTI mechanism is implemented */ #define ID_AA64PFR1_EL1_MTE_SHIFT U(8) #define ID_AA64PFR1_EL1_MTE_MASK ULL(0xf) #define MTE_UNIMPLEMENTED ULL(0) #define MTE_IMPLEMENTED_EL0 ULL(1) /* MTE is only implemented at EL0 */ #define MTE_IMPLEMENTED_ELX ULL(2) /* MTE is implemented at all ELs */ /* ID_PFR1_EL1 definitions */ #define ID_PFR1_VIRTEXT_SHIFT U(12) #define ID_PFR1_VIRTEXT_MASK U(0xf) #define GET_VIRT_EXT(id) (((id) >> ID_PFR1_VIRTEXT_SHIFT) \ & ID_PFR1_VIRTEXT_MASK) /* SCTLR definitions */ #define SCTLR_EL2_RES1 ((U(1) << 29) | (U(1) << 28) | (U(1) << 23) | \ (U(1) << 22) | (U(1) << 18) | (U(1) << 16) | \ (U(1) << 11) | (U(1) << 5) | (U(1) << 4)) #define SCTLR_EL1_RES1 ((U(1) << 29) | (U(1) << 28) | (U(1) << 23) | \ (U(1) << 22) | (U(1) << 20) | (U(1) << 11)) #define SCTLR_AARCH32_EL1_RES1 \ ((U(1) << 23) | (U(1) << 22) | (U(1) << 11) | \ (U(1) << 4) | (U(1) << 3)) #define SCTLR_EL3_RES1 ((U(1) << 29) | (U(1) << 28) | (U(1) << 23) | \ (U(1) << 22) | (U(1) << 18) | (U(1) << 16) | \ (U(1) << 11) | (U(1) << 5) | (U(1) << 4)) #define SCTLR_M_BIT (ULL(1) << 0) #define SCTLR_A_BIT (ULL(1) << 1) #define SCTLR_C_BIT (ULL(1) << 2) #define SCTLR_SA_BIT (ULL(1) << 3) #define SCTLR_SA0_BIT (ULL(1) << 4) #define SCTLR_CP15BEN_BIT (ULL(1) << 5) #define SCTLR_ITD_BIT (ULL(1) << 7) #define SCTLR_SED_BIT (ULL(1) << 8) #define SCTLR_UMA_BIT (ULL(1) << 9) #define SCTLR_I_BIT (ULL(1) << 12) #define SCTLR_EnDB_BIT (ULL(1) << 13) #define SCTLR_DZE_BIT (ULL(1) << 14) #define SCTLR_UCT_BIT (ULL(1) << 15) #define SCTLR_NTWI_BIT (ULL(1) << 16) #define SCTLR_NTWE_BIT (ULL(1) << 18) #define SCTLR_WXN_BIT (ULL(1) << 19) #define SCTLR_UWXN_BIT (ULL(1) << 20) #define SCTLR_IESB_BIT (ULL(1) << 21) #define SCTLR_E0E_BIT (ULL(1) << 24) #define SCTLR_EE_BIT (ULL(1) << 25) #define SCTLR_UCI_BIT (ULL(1) << 26) #define SCTLR_EnDA_BIT (ULL(1) << 27) #define SCTLR_EnIB_BIT (ULL(1) << 30) #define SCTLR_EnIA_BIT (ULL(1) << 31) #define SCTLR_BT0_BIT (ULL(1) << 35) #define SCTLR_BT1_BIT (ULL(1) << 36) #define SCTLR_BT_BIT (ULL(1) << 36) #define SCTLR_DSSBS_BIT (ULL(1) << 44) #define SCTLR_RESET_VAL SCTLR_EL3_RES1 /* CPACR_El1 definitions */ #define CPACR_EL1_FPEN(x) ((x) << 20) #define CPACR_EL1_FP_TRAP_EL0 U(0x1) #define CPACR_EL1_FP_TRAP_ALL U(0x2) #define CPACR_EL1_FP_TRAP_NONE U(0x3) /* SCR definitions */ #define SCR_RES1_BITS ((U(1) << 4) | (U(1) << 5)) #define SCR_ATA_BIT (U(1) << 26) #define SCR_FIEN_BIT (U(1) << 21) #define SCR_API_BIT (U(1) << 17) #define SCR_APK_BIT (U(1) << 16) #define SCR_TWE_BIT (U(1) << 13) #define SCR_TWI_BIT (U(1) << 12) #define SCR_ST_BIT (U(1) << 11) #define SCR_RW_BIT (U(1) << 10) #define SCR_SIF_BIT (U(1) << 9) #define SCR_HCE_BIT (U(1) << 8) #define SCR_SMD_BIT (U(1) << 7) #define SCR_EA_BIT (U(1) << 3) #define SCR_FIQ_BIT (U(1) << 2) #define SCR_IRQ_BIT (U(1) << 1) #define SCR_NS_BIT (U(1) << 0) #define SCR_VALID_BIT_MASK U(0x2f8f) #define SCR_RESET_VAL SCR_RES1_BITS /* MDCR_EL3 definitions */ #define MDCR_SCCD_BIT (ULL(1) << 23) #define MDCR_SPME_BIT (ULL(1) << 17) #define MDCR_SDD_BIT (ULL(1) << 16) #define MDCR_SPD32(x) ((x) << 14) #define MDCR_SPD32_LEGACY ULL(0x0) #define MDCR_SPD32_DISABLE ULL(0x2) #define MDCR_SPD32_ENABLE ULL(0x3) #define MDCR_NSPB(x) ((x) << 12) #define MDCR_NSPB_EL1 ULL(0x3) #define MDCR_TDOSA_BIT (ULL(1) << 10) #define MDCR_TDA_BIT (ULL(1) << 9) #define MDCR_TPM_BIT (ULL(1) << 6) #define MDCR_EL3_RESET_VAL ULL(0x0) /* MDCR_EL2 definitions */ #define MDCR_EL2_HLP (U(1) << 26) #define MDCR_EL2_HCCD (U(1) << 23) #define MDCR_EL2_TTRF (U(1) << 19) #define MDCR_EL2_HPMD (U(1) << 17) #define MDCR_EL2_TPMS (U(1) << 14) #define MDCR_EL2_E2PB(x) ((x) << 12) #define MDCR_EL2_E2PB_EL1 U(0x3) #define MDCR_EL2_TDRA_BIT (U(1) << 11) #define MDCR_EL2_TDOSA_BIT (U(1) << 10) #define MDCR_EL2_TDA_BIT (U(1) << 9) #define MDCR_EL2_TDE_BIT (U(1) << 8) #define MDCR_EL2_HPME_BIT (U(1) << 7) #define MDCR_EL2_TPM_BIT (U(1) << 6) #define MDCR_EL2_TPMCR_BIT (U(1) << 5) #define MDCR_EL2_RESET_VAL U(0x0) /* HSTR_EL2 definitions */ #define HSTR_EL2_RESET_VAL U(0x0) #define HSTR_EL2_T_MASK U(0xff) /* CNTHP_CTL_EL2 definitions */ #define CNTHP_CTL_ENABLE_BIT (U(1) << 0) #define CNTHP_CTL_RESET_VAL U(0x0) /* VTTBR_EL2 definitions */ #define VTTBR_RESET_VAL ULL(0x0) #define VTTBR_VMID_MASK ULL(0xff) #define VTTBR_VMID_SHIFT U(48) #define VTTBR_BADDR_MASK ULL(0xffffffffffff) #define VTTBR_BADDR_SHIFT U(0) /* HCR definitions */ #define HCR_API_BIT (ULL(1) << 41) #define HCR_APK_BIT (ULL(1) << 40) #define HCR_TGE_BIT (ULL(1) << 27) #define HCR_RW_SHIFT U(31) #define HCR_RW_BIT (ULL(1) << HCR_RW_SHIFT) #define HCR_AMO_BIT (ULL(1) << 5) #define HCR_IMO_BIT (ULL(1) << 4) #define HCR_FMO_BIT (ULL(1) << 3) /* ISR definitions */ #define ISR_A_SHIFT U(8) #define ISR_I_SHIFT U(7) #define ISR_F_SHIFT U(6) /* CNTHCTL_EL2 definitions */ #define CNTHCTL_RESET_VAL U(0x0) #define EVNTEN_BIT (U(1) << 2) #define EL1PCEN_BIT (U(1) << 1) #define EL1PCTEN_BIT (U(1) << 0) /* CNTKCTL_EL1 definitions */ #define EL0PTEN_BIT (U(1) << 9) #define EL0VTEN_BIT (U(1) << 8) #define EL0PCTEN_BIT (U(1) << 0) #define EL0VCTEN_BIT (U(1) << 1) #define EVNTEN_BIT (U(1) << 2) #define EVNTDIR_BIT (U(1) << 3) #define EVNTI_SHIFT U(4) #define EVNTI_MASK U(0xf) /* CPTR_EL3 definitions */ #define TCPAC_BIT (U(1) << 31) #define TAM_BIT (U(1) << 30) #define TTA_BIT (U(1) << 20) #define TFP_BIT (U(1) << 10) #define CPTR_EZ_BIT (U(1) << 8) #define CPTR_EL3_RESET_VAL U(0x0) /* CPTR_EL2 definitions */ #define CPTR_EL2_RES1 ((U(1) << 13) | (U(1) << 12) | (U(0x3ff))) #define CPTR_EL2_TCPAC_BIT (U(1) << 31) #define CPTR_EL2_TAM_BIT (U(1) << 30) #define CPTR_EL2_TTA_BIT (U(1) << 20) #define CPTR_EL2_TFP_BIT (U(1) << 10) #define CPTR_EL2_TZ_BIT (U(1) << 8) #define CPTR_EL2_RESET_VAL CPTR_EL2_RES1 /* CPSR/SPSR definitions */ #define DAIF_FIQ_BIT (U(1) << 0) #define DAIF_IRQ_BIT (U(1) << 1) #define DAIF_ABT_BIT (U(1) << 2) #define DAIF_DBG_BIT (U(1) << 3) #define SPSR_DAIF_SHIFT U(6) #define SPSR_DAIF_MASK U(0xf) #define SPSR_AIF_SHIFT U(6) #define SPSR_AIF_MASK U(0x7) #define SPSR_E_SHIFT U(9) #define SPSR_E_MASK U(0x1) #define SPSR_E_LITTLE U(0x0) #define SPSR_E_BIG U(0x1) #define SPSR_T_SHIFT U(5) #define SPSR_T_MASK U(0x1) #define SPSR_T_ARM U(0x0) #define SPSR_T_THUMB U(0x1) #define SPSR_M_SHIFT U(4) #define SPSR_M_MASK U(0x1) #define SPSR_M_AARCH64 U(0x0) #define SPSR_M_AARCH32 U(0x1) #define SPSR_SSBS_BIT_AARCH64 BIT_64(12) #define SPSR_SSBS_BIT_AARCH32 BIT_64(23) #define DISABLE_ALL_EXCEPTIONS \ (DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT | DAIF_DBG_BIT) #define DISABLE_INTERRUPTS (DAIF_FIQ_BIT | DAIF_IRQ_BIT) /* * RMR_EL3 definitions */ #define RMR_EL3_RR_BIT (U(1) << 1) #define RMR_EL3_AA64_BIT (U(1) << 0) /* * HI-VECTOR address for AArch32 state */ #define HI_VECTOR_BASE U(0xFFFF0000) /* * TCR defintions */ #define TCR_EL3_RES1 ((ULL(1) << 31) | (ULL(1) << 23)) #define TCR_EL2_RES1 ((ULL(1) << 31) | (ULL(1) << 23)) #define TCR_EL1_IPS_SHIFT U(32) #define TCR_EL2_PS_SHIFT U(16) #define TCR_EL3_PS_SHIFT U(16) #define TCR_TxSZ_MIN ULL(16) #define TCR_TxSZ_MAX ULL(39) #define TCR_TxSZ_MAX_TTST ULL(48) #define TCR_T0SZ_SHIFT U(0) #define TCR_T1SZ_SHIFT U(16) /* (internal) physical address size bits in EL3/EL1 */ #define TCR_PS_BITS_4GB ULL(0x0) #define TCR_PS_BITS_64GB ULL(0x1) #define TCR_PS_BITS_1TB ULL(0x2) #define TCR_PS_BITS_4TB ULL(0x3) #define TCR_PS_BITS_16TB ULL(0x4) #define TCR_PS_BITS_256TB ULL(0x5) #define ADDR_MASK_48_TO_63 ULL(0xFFFF000000000000) #define ADDR_MASK_44_TO_47 ULL(0x0000F00000000000) #define ADDR_MASK_42_TO_43 ULL(0x00000C0000000000) #define ADDR_MASK_40_TO_41 ULL(0x0000030000000000) #define ADDR_MASK_36_TO_39 ULL(0x000000F000000000) #define ADDR_MASK_32_TO_35 ULL(0x0000000F00000000) #define TCR_RGN_INNER_NC (ULL(0x0) << 8) #define TCR_RGN_INNER_WBA (ULL(0x1) << 8) #define TCR_RGN_INNER_WT (ULL(0x2) << 8) #define TCR_RGN_INNER_WBNA (ULL(0x3) << 8) #define TCR_RGN_OUTER_NC (ULL(0x0) << 10) #define TCR_RGN_OUTER_WBA (ULL(0x1) << 10) #define TCR_RGN_OUTER_WT (ULL(0x2) << 10) #define TCR_RGN_OUTER_WBNA (ULL(0x3) << 10) #define TCR_SH_NON_SHAREABLE (ULL(0x0) << 12) #define TCR_SH_OUTER_SHAREABLE (ULL(0x2) << 12) #define TCR_SH_INNER_SHAREABLE (ULL(0x3) << 12) #define TCR_RGN1_INNER_NC (ULL(0x0) << 24) #define TCR_RGN1_INNER_WBA (ULL(0x1) << 24) #define TCR_RGN1_INNER_WT (ULL(0x2) << 24) #define TCR_RGN1_INNER_WBNA (ULL(0x3) << 24) #define TCR_RGN1_OUTER_NC (ULL(0x0) << 26) #define TCR_RGN1_OUTER_WBA (ULL(0x1) << 26) #define TCR_RGN1_OUTER_WT (ULL(0x2) << 26) #define TCR_RGN1_OUTER_WBNA (ULL(0x3) << 26) #define TCR_SH1_NON_SHAREABLE (ULL(0x0) << 28) #define TCR_SH1_OUTER_SHAREABLE (ULL(0x2) << 28) #define TCR_SH1_INNER_SHAREABLE (ULL(0x3) << 28) #define TCR_TG0_SHIFT U(14) #define TCR_TG0_MASK ULL(3) #define TCR_TG0_4K (ULL(0) << TCR_TG0_SHIFT) #define TCR_TG0_64K (ULL(1) << TCR_TG0_SHIFT) #define TCR_TG0_16K (ULL(2) << TCR_TG0_SHIFT) #define TCR_TG1_SHIFT U(30) #define TCR_TG1_MASK ULL(3) #define TCR_TG1_16K (ULL(1) << TCR_TG1_SHIFT) #define TCR_TG1_4K (ULL(2) << TCR_TG1_SHIFT) #define TCR_TG1_64K (ULL(3) << TCR_TG1_SHIFT) #define TCR_EPD0_BIT (ULL(1) << 7) #define TCR_EPD1_BIT (ULL(1) << 23) #define MODE_SP_SHIFT U(0x0) #define MODE_SP_MASK U(0x1) #define MODE_SP_EL0 U(0x0) #define MODE_SP_ELX U(0x1) #define MODE_RW_SHIFT U(0x4) #define MODE_RW_MASK U(0x1) #define MODE_RW_64 U(0x0) #define MODE_RW_32 U(0x1) #define MODE_EL_SHIFT U(0x2) #define MODE_EL_MASK U(0x3) #define MODE_EL3 U(0x3) #define MODE_EL2 U(0x2) #define MODE_EL1 U(0x1) #define MODE_EL0 U(0x0) #define MODE32_SHIFT U(0) #define MODE32_MASK U(0xf) #define MODE32_usr U(0x0) #define MODE32_fiq U(0x1) #define MODE32_irq U(0x2) #define MODE32_svc U(0x3) #define MODE32_mon U(0x6) #define MODE32_abt U(0x7) #define MODE32_hyp U(0xa) #define MODE32_und U(0xb) #define MODE32_sys U(0xf) #define GET_RW(mode) (((mode) >> MODE_RW_SHIFT) & MODE_RW_MASK) #define GET_EL(mode) (((mode) >> MODE_EL_SHIFT) & MODE_EL_MASK) #define GET_SP(mode) (((mode) >> MODE_SP_SHIFT) & MODE_SP_MASK) #define GET_M32(mode) (((mode) >> MODE32_SHIFT) & MODE32_MASK) #define SPSR_64(el, sp, daif) \ (((MODE_RW_64 << MODE_RW_SHIFT) | \ (((el) & MODE_EL_MASK) << MODE_EL_SHIFT) | \ (((sp) & MODE_SP_MASK) << MODE_SP_SHIFT) | \ (((daif) & SPSR_DAIF_MASK) << SPSR_DAIF_SHIFT)) & \ (~(SPSR_SSBS_BIT_AARCH64))) #define SPSR_MODE32(mode, isa, endian, aif) \ (((MODE_RW_32 << MODE_RW_SHIFT) | \ (((mode) & MODE32_MASK) << MODE32_SHIFT) | \ (((isa) & SPSR_T_MASK) << SPSR_T_SHIFT) | \ (((endian) & SPSR_E_MASK) << SPSR_E_SHIFT) | \ (((aif) & SPSR_AIF_MASK) << SPSR_AIF_SHIFT)) & \ (~(SPSR_SSBS_BIT_AARCH32))) /* * TTBR Definitions */ #define TTBR_CNP_BIT ULL(0x1) /* * CTR_EL0 definitions */ #define CTR_CWG_SHIFT U(24) #define CTR_CWG_MASK U(0xf) #define CTR_ERG_SHIFT U(20) #define CTR_ERG_MASK U(0xf) #define CTR_DMINLINE_SHIFT U(16) #define CTR_DMINLINE_MASK U(0xf) #define CTR_L1IP_SHIFT U(14) #define CTR_L1IP_MASK U(0x3) #define CTR_IMINLINE_SHIFT U(0) #define CTR_IMINLINE_MASK U(0xf) #define MAX_CACHE_LINE_SIZE U(0x800) /* 2KB */ /* Physical timer control register bit fields shifts and masks */ #define CNTP_CTL_ENABLE_SHIFT U(0) #define CNTP_CTL_IMASK_SHIFT U(1) #define CNTP_CTL_ISTATUS_SHIFT U(2) #define CNTP_CTL_ENABLE_MASK U(1) #define CNTP_CTL_IMASK_MASK U(1) #define CNTP_CTL_ISTATUS_MASK U(1) /* Exception Syndrome register bits and bobs */ #define ESR_EC_SHIFT U(26) #define ESR_EC_MASK U(0x3f) #define ESR_EC_LENGTH U(6) #define ESR_ISS_SHIFT U(0) #define ESR_ISS_LENGTH U(25) #define EC_UNKNOWN U(0x0) #define EC_WFE_WFI U(0x1) #define EC_AARCH32_CP15_MRC_MCR U(0x3) #define EC_AARCH32_CP15_MRRC_MCRR U(0x4) #define EC_AARCH32_CP14_MRC_MCR U(0x5) #define EC_AARCH32_CP14_LDC_STC U(0x6) #define EC_FP_SIMD U(0x7) #define EC_AARCH32_CP10_MRC U(0x8) #define EC_AARCH32_CP14_MRRC_MCRR U(0xc) #define EC_ILLEGAL U(0xe) #define EC_AARCH32_SVC U(0x11) #define EC_AARCH32_HVC U(0x12) #define EC_AARCH32_SMC U(0x13) #define EC_AARCH64_SVC U(0x15) #define EC_AARCH64_HVC U(0x16) #define EC_AARCH64_SMC U(0x17) #define EC_AARCH64_SYS U(0x18) #define EC_IABORT_LOWER_EL U(0x20) #define EC_IABORT_CUR_EL U(0x21) #define EC_PC_ALIGN U(0x22) #define EC_DABORT_LOWER_EL U(0x24) #define EC_DABORT_CUR_EL U(0x25) #define EC_SP_ALIGN U(0x26) #define EC_AARCH32_FP U(0x28) #define EC_AARCH64_FP U(0x2c) #define EC_SERROR U(0x2f) #define EC_BRK U(0x3c) /* * External Abort bit in Instruction and Data Aborts synchronous exception * syndromes. */ #define ESR_ISS_EABORT_EA_BIT U(9) #define EC_BITS(x) (((x) >> ESR_EC_SHIFT) & ESR_EC_MASK) /* Reset bit inside the Reset management register for EL3 (RMR_EL3) */ #define RMR_RESET_REQUEST_SHIFT U(0x1) #define RMR_WARM_RESET_CPU (U(1) << RMR_RESET_REQUEST_SHIFT) /******************************************************************************* * Definitions of register offsets, fields and macros for CPU system * instructions. ******************************************************************************/ #define TLBI_ADDR_SHIFT U(12) #define TLBI_ADDR_MASK ULL(0x00000FFFFFFFFFFF) #define TLBI_ADDR(x) (((x) >> TLBI_ADDR_SHIFT) & TLBI_ADDR_MASK) /******************************************************************************* * Definitions of register offsets and fields in the CNTCTLBase Frame of the * system level implementation of the Generic Timer. ******************************************************************************/ #define CNTCTLBASE_CNTFRQ U(0x0) #define CNTNSAR U(0x4) #define CNTNSAR_NS_SHIFT(x) (x) #define CNTACR_BASE(x) (U(0x40) + ((x) << 2)) #define CNTACR_RPCT_SHIFT U(0x0) #define CNTACR_RVCT_SHIFT U(0x1) #define CNTACR_RFRQ_SHIFT U(0x2) #define CNTACR_RVOFF_SHIFT U(0x3) #define CNTACR_RWVT_SHIFT U(0x4) #define CNTACR_RWPT_SHIFT U(0x5) /******************************************************************************* * Definitions of register offsets and fields in the CNTBaseN Frame of the * system level implementation of the Generic Timer. ******************************************************************************/ /* Physical Count register. */ #define CNTPCT_LO U(0x0) /* Counter Frequency register. */ #define CNTBASEN_CNTFRQ U(0x10) /* Physical Timer CompareValue register. */ #define CNTP_CVAL_LO U(0x20) /* Physical Timer Control register. */ #define CNTP_CTL U(0x2c) /* PMCR_EL0 definitions */ #define PMCR_EL0_RESET_VAL U(0x0) #define PMCR_EL0_N_SHIFT U(11) #define PMCR_EL0_N_MASK U(0x1f) #define PMCR_EL0_N_BITS (PMCR_EL0_N_MASK << PMCR_EL0_N_SHIFT) #define PMCR_EL0_LP_BIT (U(1) << 7) #define PMCR_EL0_LC_BIT (U(1) << 6) #define PMCR_EL0_DP_BIT (U(1) << 5) #define PMCR_EL0_X_BIT (U(1) << 4) #define PMCR_EL0_D_BIT (U(1) << 3) #define PMCR_EL0_C_BIT (U(1) << 2) #define PMCR_EL0_P_BIT (U(1) << 1) #define PMCR_EL0_E_BIT (U(1) << 0) /******************************************************************************* * Definitions for system register interface to SVE ******************************************************************************/ #define ZCR_EL3 S3_6_C1_C2_0 #define ZCR_EL2 S3_4_C1_C2_0 /* ZCR_EL3 definitions */ #define ZCR_EL3_LEN_MASK U(0xf) /* ZCR_EL2 definitions */ #define ZCR_EL2_LEN_MASK U(0xf) /******************************************************************************* * Definitions of MAIR encodings for device and normal memory ******************************************************************************/ /* * MAIR encodings for device memory attributes. */ #define MAIR_DEV_nGnRnE ULL(0x0) #define MAIR_DEV_nGnRE ULL(0x4) #define MAIR_DEV_nGRE ULL(0x8) #define MAIR_DEV_GRE ULL(0xc) /* * MAIR encodings for normal memory attributes. * * Cache Policy * WT: Write Through * WB: Write Back * NC: Non-Cacheable * * Transient Hint * NTR: Non-Transient * TR: Transient * * Allocation Policy * RA: Read Allocate * WA: Write Allocate * RWA: Read and Write Allocate * NA: No Allocation */ #define MAIR_NORM_WT_TR_WA ULL(0x1) #define MAIR_NORM_WT_TR_RA ULL(0x2) #define MAIR_NORM_WT_TR_RWA ULL(0x3) #define MAIR_NORM_NC ULL(0x4) #define MAIR_NORM_WB_TR_WA ULL(0x5) #define MAIR_NORM_WB_TR_RA ULL(0x6) #define MAIR_NORM_WB_TR_RWA ULL(0x7) #define MAIR_NORM_WT_NTR_NA ULL(0x8) #define MAIR_NORM_WT_NTR_WA ULL(0x9) #define MAIR_NORM_WT_NTR_RA ULL(0xa) #define MAIR_NORM_WT_NTR_RWA ULL(0xb) #define MAIR_NORM_WB_NTR_NA ULL(0xc) #define MAIR_NORM_WB_NTR_WA ULL(0xd) #define MAIR_NORM_WB_NTR_RA ULL(0xe) #define MAIR_NORM_WB_NTR_RWA ULL(0xf) #define MAIR_NORM_OUTER_SHIFT U(4) #define MAKE_MAIR_NORMAL_MEMORY(inner, outer) \ ((inner) | ((outer) << MAIR_NORM_OUTER_SHIFT)) /* PAR_EL1 fields */ #define PAR_F_SHIFT U(0) #define PAR_F_MASK ULL(0x1) #define PAR_ADDR_SHIFT U(12) #define PAR_ADDR_MASK (BIT(40) - ULL(1)) /* 40-bits-wide page address */ /******************************************************************************* * Definitions for system register interface to SPE ******************************************************************************/ #define PMBLIMITR_EL1 S3_0_C9_C10_0 /******************************************************************************* * Definitions for system register interface to MPAM ******************************************************************************/ #define MPAMIDR_EL1 S3_0_C10_C4_4 #define MPAM2_EL2 S3_4_C10_C5_0 #define MPAMHCR_EL2 S3_4_C10_C4_0 #define MPAM3_EL3 S3_6_C10_C5_0 /******************************************************************************* * Definitions for system register interface to AMU for ARMv8.4 onwards ******************************************************************************/ #define AMCR_EL0 S3_3_C13_C2_0 #define AMCFGR_EL0 S3_3_C13_C2_1 #define AMCGCR_EL0 S3_3_C13_C2_2 #define AMUSERENR_EL0 S3_3_C13_C2_3 #define AMCNTENCLR0_EL0 S3_3_C13_C2_4 #define AMCNTENSET0_EL0 S3_3_C13_C2_5 #define AMCNTENCLR1_EL0 S3_3_C13_C3_0 #define AMCNTENSET1_EL0 S3_3_C13_C3_1 /* Activity Monitor Group 0 Event Counter Registers */ #define AMEVCNTR00_EL0 S3_3_C13_C4_0 #define AMEVCNTR01_EL0 S3_3_C13_C4_1 #define AMEVCNTR02_EL0 S3_3_C13_C4_2 #define AMEVCNTR03_EL0 S3_3_C13_C4_3 /* Activity Monitor Group 0 Event Type Registers */ #define AMEVTYPER00_EL0 S3_3_C13_C6_0 #define AMEVTYPER01_EL0 S3_3_C13_C6_1 #define AMEVTYPER02_EL0 S3_3_C13_C6_2 #define AMEVTYPER03_EL0 S3_3_C13_C6_3 /* Activity Monitor Group 1 Event Counter Registers */ #define AMEVCNTR10_EL0 S3_3_C13_C12_0 #define AMEVCNTR11_EL0 S3_3_C13_C12_1 #define AMEVCNTR12_EL0 S3_3_C13_C12_2 #define AMEVCNTR13_EL0 S3_3_C13_C12_3 #define AMEVCNTR14_EL0 S3_3_C13_C12_4 #define AMEVCNTR15_EL0 S3_3_C13_C12_5 #define AMEVCNTR16_EL0 S3_3_C13_C12_6 #define AMEVCNTR17_EL0 S3_3_C13_C12_7 #define AMEVCNTR18_EL0 S3_3_C13_C13_0 #define AMEVCNTR19_EL0 S3_3_C13_C13_1 #define AMEVCNTR1A_EL0 S3_3_C13_C13_2 #define AMEVCNTR1B_EL0 S3_3_C13_C13_3 #define AMEVCNTR1C_EL0 S3_3_C13_C13_4 #define AMEVCNTR1D_EL0 S3_3_C13_C13_5 #define AMEVCNTR1E_EL0 S3_3_C13_C13_6 #define AMEVCNTR1F_EL0 S3_3_C13_C13_7 /* Activity Monitor Group 1 Event Type Registers */ #define AMEVTYPER10_EL0 S3_3_C13_C14_0 #define AMEVTYPER11_EL0 S3_3_C13_C14_1 #define AMEVTYPER12_EL0 S3_3_C13_C14_2 #define AMEVTYPER13_EL0 S3_3_C13_C14_3 #define AMEVTYPER14_EL0 S3_3_C13_C14_4 #define AMEVTYPER15_EL0 S3_3_C13_C14_5 #define AMEVTYPER16_EL0 S3_3_C13_C14_6 #define AMEVTYPER17_EL0 S3_3_C13_C14_7 #define AMEVTYPER18_EL0 S3_3_C13_C15_0 #define AMEVTYPER19_EL0 S3_3_C13_C15_1 #define AMEVTYPER1A_EL0 S3_3_C13_C15_2 #define AMEVTYPER1B_EL0 S3_3_C13_C15_3 #define AMEVTYPER1C_EL0 S3_3_C13_C15_4 #define AMEVTYPER1D_EL0 S3_3_C13_C15_5 #define AMEVTYPER1E_EL0 S3_3_C13_C15_6 #define AMEVTYPER1F_EL0 S3_3_C13_C15_7 /* AMCGCR_EL0 definitions */ #define AMCGCR_EL0_CG1NC_SHIFT U(8) #define AMCGCR_EL0_CG1NC_LENGTH U(8) #define AMCGCR_EL0_CG1NC_MASK U(0xff) /* MPAM register definitions */ #define MPAM3_EL3_MPAMEN_BIT (ULL(1) << 63) #define MPAMHCR_EL2_TRAP_MPAMIDR_EL1 (ULL(1) << 31) #define MPAM2_EL2_TRAPMPAM0EL1 (ULL(1) << 49) #define MPAM2_EL2_TRAPMPAM1EL1 (ULL(1) << 48) #define MPAMIDR_HAS_HCR_BIT (ULL(1) << 17) /******************************************************************************* * RAS system registers ******************************************************************************/ #define DISR_EL1 S3_0_C12_C1_1 #define DISR_A_BIT U(31) #define ERRIDR_EL1 S3_0_C5_C3_0 #define ERRIDR_MASK U(0xffff) #define ERRSELR_EL1 S3_0_C5_C3_1 /* System register access to Standard Error Record registers */ #define ERXFR_EL1 S3_0_C5_C4_0 #define ERXCTLR_EL1 S3_0_C5_C4_1 #define ERXSTATUS_EL1 S3_0_C5_C4_2 #define ERXADDR_EL1 S3_0_C5_C4_3 #define ERXPFGF_EL1 S3_0_C5_C4_4 #define ERXPFGCTL_EL1 S3_0_C5_C4_5 #define ERXPFGCDN_EL1 S3_0_C5_C4_6 #define ERXMISC0_EL1 S3_0_C5_C5_0 #define ERXMISC1_EL1 S3_0_C5_C5_1 #define ERXCTLR_ED_BIT (U(1) << 0) #define ERXCTLR_UE_BIT (U(1) << 4) #define ERXPFGCTL_UC_BIT (U(1) << 1) #define ERXPFGCTL_UEU_BIT (U(1) << 2) #define ERXPFGCTL_CDEN_BIT (U(1) << 31) /******************************************************************************* * Armv8.3 Pointer Authentication Registers ******************************************************************************/ #define APIAKeyLo_EL1 S3_0_C2_C1_0 #define APIAKeyHi_EL1 S3_0_C2_C1_1 #define APIBKeyLo_EL1 S3_0_C2_C1_2 #define APIBKeyHi_EL1 S3_0_C2_C1_3 #define APDAKeyLo_EL1 S3_0_C2_C2_0 #define APDAKeyHi_EL1 S3_0_C2_C2_1 #define APDBKeyLo_EL1 S3_0_C2_C2_2 #define APDBKeyHi_EL1 S3_0_C2_C2_3 #define APGAKeyLo_EL1 S3_0_C2_C3_0 #define APGAKeyHi_EL1 S3_0_C2_C3_1 /******************************************************************************* * Armv8.4 Data Independent Timing Registers ******************************************************************************/ #define DIT S3_3_C4_C2_5 #define DIT_BIT BIT(24) /******************************************************************************* * Armv8.5 - new MSR encoding to directly access PSTATE.SSBS field ******************************************************************************/ #define SSBS S3_3_C4_C2_6 /******************************************************************************* * Armv8.5 - Memory Tagging Extension Registers ******************************************************************************/ #define TFSRE0_EL1 S3_0_C5_C6_1 #define TFSR_EL1 S3_0_C5_C6_0 #define RGSR_EL1 S3_0_C1_C0_5 #define GCR_EL1 S3_0_C1_C0_6 #endif /* ARCH_H */ trusted-firmware-a-2.2/include/arch/aarch64/arch_features.h000066400000000000000000000025761355360272700236770ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARCH_FEATURES_H #define ARCH_FEATURES_H #include #include static inline bool is_armv7_gentimer_present(void) { /* The Generic Timer is always present in an ARMv8-A implementation */ return true; } static inline bool is_armv8_2_ttcnp_present(void) { return ((read_id_aa64mmfr2_el1() >> ID_AA64MMFR2_EL1_CNP_SHIFT) & ID_AA64MMFR2_EL1_CNP_MASK) != 0U; } static inline bool is_armv8_3_pauth_present(void) { uint64_t mask = (ID_AA64ISAR1_GPI_MASK << ID_AA64ISAR1_GPI_SHIFT) | (ID_AA64ISAR1_GPA_MASK << ID_AA64ISAR1_GPA_SHIFT) | (ID_AA64ISAR1_API_MASK << ID_AA64ISAR1_API_SHIFT) | (ID_AA64ISAR1_APA_MASK << ID_AA64ISAR1_APA_SHIFT); /* If any of the fields is not zero, PAuth is present */ return (read_id_aa64isar1_el1() & mask) != 0U; } static inline bool is_armv8_4_ttst_present(void) { return ((read_id_aa64mmfr2_el1() >> ID_AA64MMFR2_EL1_ST_SHIFT) & ID_AA64MMFR2_EL1_ST_MASK) == 1U; } static inline bool is_armv8_5_bti_present(void) { return ((read_id_aa64pfr1_el1() >> ID_AA64PFR1_EL1_BT_SHIFT) & ID_AA64PFR1_EL1_BT_MASK) == BTI_IMPLEMENTED; } static inline unsigned int get_armv8_5_mte_support(void) { return ((read_id_aa64pfr1_el1() >> ID_AA64PFR1_EL1_MTE_SHIFT) & ID_AA64PFR1_EL1_MTE_MASK); } #endif /* ARCH_FEATURES_H */ trusted-firmware-a-2.2/include/arch/aarch64/arch_helpers.h000066400000000000000000000420721355360272700235160ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARCH_HELPERS_H #define ARCH_HELPERS_H #include #include #include #include #include /********************************************************************** * Macros which create inline functions to read or write CPU system * registers *********************************************************************/ #define _DEFINE_SYSREG_READ_FUNC(_name, _reg_name) \ static inline u_register_t read_ ## _name(void) \ { \ u_register_t v; \ __asm__ volatile ("mrs %0, " #_reg_name : "=r" (v)); \ return v; \ } #define _DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name) \ static inline void write_ ## _name(u_register_t v) \ { \ __asm__ volatile ("msr " #_reg_name ", %0" : : "r" (v)); \ } #define SYSREG_WRITE_CONST(reg_name, v) \ __asm__ volatile ("msr " #reg_name ", %0" : : "i" (v)) /* Define read function for system register */ #define DEFINE_SYSREG_READ_FUNC(_name) \ _DEFINE_SYSREG_READ_FUNC(_name, _name) /* Define read & write function for system register */ #define DEFINE_SYSREG_RW_FUNCS(_name) \ _DEFINE_SYSREG_READ_FUNC(_name, _name) \ _DEFINE_SYSREG_WRITE_FUNC(_name, _name) /* Define read & write function for renamed system register */ #define DEFINE_RENAME_SYSREG_RW_FUNCS(_name, _reg_name) \ _DEFINE_SYSREG_READ_FUNC(_name, _reg_name) \ _DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name) /* Define read function for renamed system register */ #define DEFINE_RENAME_SYSREG_READ_FUNC(_name, _reg_name) \ _DEFINE_SYSREG_READ_FUNC(_name, _reg_name) /* Define write function for renamed system register */ #define DEFINE_RENAME_SYSREG_WRITE_FUNC(_name, _reg_name) \ _DEFINE_SYSREG_WRITE_FUNC(_name, _reg_name) /********************************************************************** * Macros to create inline functions for system instructions *********************************************************************/ /* Define function for simple system instruction */ #define DEFINE_SYSOP_FUNC(_op) \ static inline void _op(void) \ { \ __asm__ (#_op); \ } /* Define function for system instruction with type specifier */ #define DEFINE_SYSOP_TYPE_FUNC(_op, _type) \ static inline void _op ## _type(void) \ { \ __asm__ (#_op " " #_type); \ } /* Define function for system instruction with register parameter */ #define DEFINE_SYSOP_TYPE_PARAM_FUNC(_op, _type) \ static inline void _op ## _type(uint64_t v) \ { \ __asm__ (#_op " " #_type ", %0" : : "r" (v)); \ } /******************************************************************************* * TLB maintenance accessor prototypes ******************************************************************************/ #if ERRATA_A57_813419 || ERRATA_A76_1286807 /* * Define function for TLBI instruction with type specifier that implements * the workaround for errata 813419 of Cortex-A57 or errata 1286807 of * Cortex-A76. */ #define DEFINE_TLBIOP_ERRATA_TYPE_FUNC(_type)\ static inline void tlbi ## _type(void) \ { \ __asm__("tlbi " #_type "\n" \ "dsb ish\n" \ "tlbi " #_type); \ } /* * Define function for TLBI instruction with register parameter that implements * the workaround for errata 813419 of Cortex-A57 or errata 1286807 of * Cortex-A76. */ #define DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(_type) \ static inline void tlbi ## _type(uint64_t v) \ { \ __asm__("tlbi " #_type ", %0\n" \ "dsb ish\n" \ "tlbi " #_type ", %0" : : "r" (v)); \ } #endif /* ERRATA_A57_813419 */ #if ERRATA_A53_819472 || ERRATA_A53_824069 || ERRATA_A53_827319 /* * Define function for DC instruction with register parameter that enables * the workaround for errata 819472, 824069 and 827319 of Cortex-A53. */ #define DEFINE_DCOP_ERRATA_A53_TYPE_PARAM_FUNC(_name, _type) \ static inline void dc ## _name(uint64_t v) \ { \ __asm__("dc " #_type ", %0" : : "r" (v)); \ } #endif /* ERRATA_A53_819472 || ERRATA_A53_824069 || ERRATA_A53_827319 */ #if ERRATA_A57_813419 DEFINE_SYSOP_TYPE_FUNC(tlbi, alle1) DEFINE_SYSOP_TYPE_FUNC(tlbi, alle1is) DEFINE_SYSOP_TYPE_FUNC(tlbi, alle2) DEFINE_SYSOP_TYPE_FUNC(tlbi, alle2is) DEFINE_TLBIOP_ERRATA_TYPE_FUNC(alle3) DEFINE_TLBIOP_ERRATA_TYPE_FUNC(alle3is) DEFINE_SYSOP_TYPE_FUNC(tlbi, vmalle1) #elif ERRATA_A76_1286807 DEFINE_TLBIOP_ERRATA_TYPE_FUNC(alle1) DEFINE_TLBIOP_ERRATA_TYPE_FUNC(alle1is) DEFINE_TLBIOP_ERRATA_TYPE_FUNC(alle2) DEFINE_TLBIOP_ERRATA_TYPE_FUNC(alle2is) DEFINE_TLBIOP_ERRATA_TYPE_FUNC(alle3) DEFINE_TLBIOP_ERRATA_TYPE_FUNC(alle3is) DEFINE_TLBIOP_ERRATA_TYPE_FUNC(vmalle1) #else DEFINE_SYSOP_TYPE_FUNC(tlbi, alle1) DEFINE_SYSOP_TYPE_FUNC(tlbi, alle1is) DEFINE_SYSOP_TYPE_FUNC(tlbi, alle2) DEFINE_SYSOP_TYPE_FUNC(tlbi, alle2is) DEFINE_SYSOP_TYPE_FUNC(tlbi, alle3) DEFINE_SYSOP_TYPE_FUNC(tlbi, alle3is) DEFINE_SYSOP_TYPE_FUNC(tlbi, vmalle1) #endif #if ERRATA_A57_813419 DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vaae1is) DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vaale1is) DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vae2is) DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vale2is) DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(vae3is) DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(vale3is) #elif ERRATA_A76_1286807 DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(vaae1is) DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(vaale1is) DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(vae2is) DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(vale2is) DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(vae3is) DEFINE_TLBIOP_ERRATA_TYPE_PARAM_FUNC(vale3is) #else DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vaae1is) DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vaale1is) DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vae2is) DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vale2is) DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vae3is) DEFINE_SYSOP_TYPE_PARAM_FUNC(tlbi, vale3is) #endif /******************************************************************************* * Cache maintenance accessor prototypes ******************************************************************************/ DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, isw) DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, cisw) #if ERRATA_A53_827319 DEFINE_DCOP_ERRATA_A53_TYPE_PARAM_FUNC(csw, cisw) #else DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, csw) #endif #if ERRATA_A53_819472 || ERRATA_A53_824069 || ERRATA_A53_827319 DEFINE_DCOP_ERRATA_A53_TYPE_PARAM_FUNC(cvac, civac) #else DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, cvac) #endif DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, ivac) DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, civac) #if ERRATA_A53_819472 || ERRATA_A53_824069 || ERRATA_A53_827319 DEFINE_DCOP_ERRATA_A53_TYPE_PARAM_FUNC(cvau, civac) #else DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, cvau) #endif DEFINE_SYSOP_TYPE_PARAM_FUNC(dc, zva) /******************************************************************************* * Address translation accessor prototypes ******************************************************************************/ DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e1r) DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e1w) DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e0r) DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s12e0w) DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s1e1r) DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s1e2r) DEFINE_SYSOP_TYPE_PARAM_FUNC(at, s1e3r) void flush_dcache_range(uintptr_t addr, size_t size); void clean_dcache_range(uintptr_t addr, size_t size); void inv_dcache_range(uintptr_t addr, size_t size); void dcsw_op_louis(u_register_t op_type); void dcsw_op_all(u_register_t op_type); void disable_mmu_el1(void); void disable_mmu_el3(void); void disable_mmu_icache_el1(void); void disable_mmu_icache_el3(void); /******************************************************************************* * Misc. accessor prototypes ******************************************************************************/ #define write_daifclr(val) SYSREG_WRITE_CONST(daifclr, val) #define write_daifset(val) SYSREG_WRITE_CONST(daifset, val) DEFINE_SYSREG_RW_FUNCS(par_el1) DEFINE_SYSREG_READ_FUNC(id_pfr1_el1) DEFINE_SYSREG_READ_FUNC(id_aa64isar1_el1) DEFINE_SYSREG_READ_FUNC(id_aa64pfr0_el1) DEFINE_SYSREG_READ_FUNC(id_aa64pfr1_el1) DEFINE_SYSREG_READ_FUNC(id_aa64dfr0_el1) DEFINE_SYSREG_READ_FUNC(id_afr0_el1) DEFINE_SYSREG_READ_FUNC(CurrentEl) DEFINE_SYSREG_READ_FUNC(ctr_el0) DEFINE_SYSREG_RW_FUNCS(daif) DEFINE_SYSREG_RW_FUNCS(spsr_el1) DEFINE_SYSREG_RW_FUNCS(spsr_el2) DEFINE_SYSREG_RW_FUNCS(spsr_el3) DEFINE_SYSREG_RW_FUNCS(elr_el1) DEFINE_SYSREG_RW_FUNCS(elr_el2) DEFINE_SYSREG_RW_FUNCS(elr_el3) DEFINE_SYSOP_FUNC(wfi) DEFINE_SYSOP_FUNC(wfe) DEFINE_SYSOP_FUNC(sev) DEFINE_SYSOP_TYPE_FUNC(dsb, sy) DEFINE_SYSOP_TYPE_FUNC(dmb, sy) DEFINE_SYSOP_TYPE_FUNC(dmb, st) DEFINE_SYSOP_TYPE_FUNC(dmb, ld) DEFINE_SYSOP_TYPE_FUNC(dsb, ish) DEFINE_SYSOP_TYPE_FUNC(dsb, nsh) DEFINE_SYSOP_TYPE_FUNC(dsb, ishst) DEFINE_SYSOP_TYPE_FUNC(dmb, oshld) DEFINE_SYSOP_TYPE_FUNC(dmb, oshst) DEFINE_SYSOP_TYPE_FUNC(dmb, osh) DEFINE_SYSOP_TYPE_FUNC(dmb, nshld) DEFINE_SYSOP_TYPE_FUNC(dmb, nshst) DEFINE_SYSOP_TYPE_FUNC(dmb, nsh) DEFINE_SYSOP_TYPE_FUNC(dmb, ishld) DEFINE_SYSOP_TYPE_FUNC(dmb, ishst) DEFINE_SYSOP_TYPE_FUNC(dmb, ish) DEFINE_SYSOP_FUNC(isb) static inline void enable_irq(void) { /* * The compiler memory barrier will prevent the compiler from * scheduling non-volatile memory access after the write to the * register. * * This could happen if some initialization code issues non-volatile * accesses to an area used by an interrupt handler, in the assumption * that it is safe as the interrupts are disabled at the time it does * that (according to program order). However, non-volatile accesses * are not necessarily in program order relatively with volatile inline * assembly statements (and volatile accesses). */ COMPILER_BARRIER(); write_daifclr(DAIF_IRQ_BIT); isb(); } static inline void enable_fiq(void) { COMPILER_BARRIER(); write_daifclr(DAIF_FIQ_BIT); isb(); } static inline void enable_serror(void) { COMPILER_BARRIER(); write_daifclr(DAIF_ABT_BIT); isb(); } static inline void enable_debug_exceptions(void) { COMPILER_BARRIER(); write_daifclr(DAIF_DBG_BIT); isb(); } static inline void disable_irq(void) { COMPILER_BARRIER(); write_daifset(DAIF_IRQ_BIT); isb(); } static inline void disable_fiq(void) { COMPILER_BARRIER(); write_daifset(DAIF_FIQ_BIT); isb(); } static inline void disable_serror(void) { COMPILER_BARRIER(); write_daifset(DAIF_ABT_BIT); isb(); } static inline void disable_debug_exceptions(void) { COMPILER_BARRIER(); write_daifset(DAIF_DBG_BIT); isb(); } void __dead2 smc(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6, uint64_t x7); /******************************************************************************* * System register accessor prototypes ******************************************************************************/ DEFINE_SYSREG_READ_FUNC(midr_el1) DEFINE_SYSREG_READ_FUNC(mpidr_el1) DEFINE_SYSREG_READ_FUNC(id_aa64mmfr0_el1) DEFINE_SYSREG_RW_FUNCS(scr_el3) DEFINE_SYSREG_RW_FUNCS(hcr_el2) DEFINE_SYSREG_RW_FUNCS(vbar_el1) DEFINE_SYSREG_RW_FUNCS(vbar_el2) DEFINE_SYSREG_RW_FUNCS(vbar_el3) DEFINE_SYSREG_RW_FUNCS(sctlr_el1) DEFINE_SYSREG_RW_FUNCS(sctlr_el2) DEFINE_SYSREG_RW_FUNCS(sctlr_el3) DEFINE_SYSREG_RW_FUNCS(actlr_el1) DEFINE_SYSREG_RW_FUNCS(actlr_el2) DEFINE_SYSREG_RW_FUNCS(actlr_el3) DEFINE_SYSREG_RW_FUNCS(esr_el1) DEFINE_SYSREG_RW_FUNCS(esr_el2) DEFINE_SYSREG_RW_FUNCS(esr_el3) DEFINE_SYSREG_RW_FUNCS(afsr0_el1) DEFINE_SYSREG_RW_FUNCS(afsr0_el2) DEFINE_SYSREG_RW_FUNCS(afsr0_el3) DEFINE_SYSREG_RW_FUNCS(afsr1_el1) DEFINE_SYSREG_RW_FUNCS(afsr1_el2) DEFINE_SYSREG_RW_FUNCS(afsr1_el3) DEFINE_SYSREG_RW_FUNCS(far_el1) DEFINE_SYSREG_RW_FUNCS(far_el2) DEFINE_SYSREG_RW_FUNCS(far_el3) DEFINE_SYSREG_RW_FUNCS(mair_el1) DEFINE_SYSREG_RW_FUNCS(mair_el2) DEFINE_SYSREG_RW_FUNCS(mair_el3) DEFINE_SYSREG_RW_FUNCS(amair_el1) DEFINE_SYSREG_RW_FUNCS(amair_el2) DEFINE_SYSREG_RW_FUNCS(amair_el3) DEFINE_SYSREG_READ_FUNC(rvbar_el1) DEFINE_SYSREG_READ_FUNC(rvbar_el2) DEFINE_SYSREG_READ_FUNC(rvbar_el3) DEFINE_SYSREG_RW_FUNCS(rmr_el1) DEFINE_SYSREG_RW_FUNCS(rmr_el2) DEFINE_SYSREG_RW_FUNCS(rmr_el3) DEFINE_SYSREG_RW_FUNCS(tcr_el1) DEFINE_SYSREG_RW_FUNCS(tcr_el2) DEFINE_SYSREG_RW_FUNCS(tcr_el3) DEFINE_SYSREG_RW_FUNCS(ttbr0_el1) DEFINE_SYSREG_RW_FUNCS(ttbr0_el2) DEFINE_SYSREG_RW_FUNCS(ttbr0_el3) DEFINE_SYSREG_RW_FUNCS(ttbr1_el1) DEFINE_SYSREG_RW_FUNCS(vttbr_el2) DEFINE_SYSREG_RW_FUNCS(cptr_el2) DEFINE_SYSREG_RW_FUNCS(cptr_el3) DEFINE_SYSREG_RW_FUNCS(cpacr_el1) DEFINE_SYSREG_RW_FUNCS(cntfrq_el0) DEFINE_SYSREG_RW_FUNCS(cnthp_ctl_el2) DEFINE_SYSREG_RW_FUNCS(cnthp_tval_el2) DEFINE_SYSREG_RW_FUNCS(cnthp_cval_el2) DEFINE_SYSREG_RW_FUNCS(cntps_ctl_el1) DEFINE_SYSREG_RW_FUNCS(cntps_tval_el1) DEFINE_SYSREG_RW_FUNCS(cntps_cval_el1) DEFINE_SYSREG_RW_FUNCS(cntp_ctl_el0) DEFINE_SYSREG_RW_FUNCS(cntp_tval_el0) DEFINE_SYSREG_RW_FUNCS(cntp_cval_el0) DEFINE_SYSREG_READ_FUNC(cntpct_el0) DEFINE_SYSREG_RW_FUNCS(cnthctl_el2) #define get_cntp_ctl_enable(x) (((x) >> CNTP_CTL_ENABLE_SHIFT) & \ CNTP_CTL_ENABLE_MASK) #define get_cntp_ctl_imask(x) (((x) >> CNTP_CTL_IMASK_SHIFT) & \ CNTP_CTL_IMASK_MASK) #define get_cntp_ctl_istatus(x) (((x) >> CNTP_CTL_ISTATUS_SHIFT) & \ CNTP_CTL_ISTATUS_MASK) #define set_cntp_ctl_enable(x) ((x) |= (U(1) << CNTP_CTL_ENABLE_SHIFT)) #define set_cntp_ctl_imask(x) ((x) |= (U(1) << CNTP_CTL_IMASK_SHIFT)) #define clr_cntp_ctl_enable(x) ((x) &= ~(U(1) << CNTP_CTL_ENABLE_SHIFT)) #define clr_cntp_ctl_imask(x) ((x) &= ~(U(1) << CNTP_CTL_IMASK_SHIFT)) DEFINE_SYSREG_RW_FUNCS(tpidr_el3) DEFINE_SYSREG_RW_FUNCS(cntvoff_el2) DEFINE_SYSREG_RW_FUNCS(vpidr_el2) DEFINE_SYSREG_RW_FUNCS(vmpidr_el2) DEFINE_SYSREG_READ_FUNC(isr_el1) DEFINE_SYSREG_RW_FUNCS(mdcr_el2) DEFINE_SYSREG_RW_FUNCS(mdcr_el3) DEFINE_SYSREG_RW_FUNCS(hstr_el2) DEFINE_SYSREG_RW_FUNCS(pmcr_el0) /* GICv3 System Registers */ DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el1, ICC_SRE_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el2, ICC_SRE_EL2) DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sre_el3, ICC_SRE_EL3) DEFINE_RENAME_SYSREG_RW_FUNCS(icc_pmr_el1, ICC_PMR_EL1) DEFINE_RENAME_SYSREG_READ_FUNC(icc_rpr_el1, ICC_RPR_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen1_el3, ICC_IGRPEN1_EL3) DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen1_el1, ICC_IGRPEN1_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(icc_igrpen0_el1, ICC_IGRPEN0_EL1) DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir0_el1, ICC_HPPIR0_EL1) DEFINE_RENAME_SYSREG_READ_FUNC(icc_hppir1_el1, ICC_HPPIR1_EL1) DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar0_el1, ICC_IAR0_EL1) DEFINE_RENAME_SYSREG_READ_FUNC(icc_iar1_el1, ICC_IAR1_EL1) DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir0_el1, ICC_EOIR0_EL1) DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_eoir1_el1, ICC_EOIR1_EL1) DEFINE_RENAME_SYSREG_WRITE_FUNC(icc_sgi0r_el1, ICC_SGI0R_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(icc_sgi1r, ICC_SGI1R) DEFINE_RENAME_SYSREG_RW_FUNCS(amcgcr_el0, AMCGCR_EL0) DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenclr0_el0, AMCNTENCLR0_EL0) DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenset0_el0, AMCNTENSET0_EL0) DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenclr1_el0, AMCNTENCLR1_EL0) DEFINE_RENAME_SYSREG_RW_FUNCS(amcntenset1_el0, AMCNTENSET1_EL0) DEFINE_RENAME_SYSREG_READ_FUNC(mpamidr_el1, MPAMIDR_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(mpam3_el3, MPAM3_EL3) DEFINE_RENAME_SYSREG_RW_FUNCS(mpam2_el2, MPAM2_EL2) DEFINE_RENAME_SYSREG_RW_FUNCS(mpamhcr_el2, MPAMHCR_EL2) DEFINE_RENAME_SYSREG_RW_FUNCS(pmblimitr_el1, PMBLIMITR_EL1) DEFINE_RENAME_SYSREG_WRITE_FUNC(zcr_el3, ZCR_EL3) DEFINE_RENAME_SYSREG_WRITE_FUNC(zcr_el2, ZCR_EL2) DEFINE_RENAME_SYSREG_READ_FUNC(erridr_el1, ERRIDR_EL1) DEFINE_RENAME_SYSREG_WRITE_FUNC(errselr_el1, ERRSELR_EL1) DEFINE_RENAME_SYSREG_READ_FUNC(erxfr_el1, ERXFR_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(erxctlr_el1, ERXCTLR_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(erxstatus_el1, ERXSTATUS_EL1) DEFINE_RENAME_SYSREG_READ_FUNC(erxaddr_el1, ERXADDR_EL1) DEFINE_RENAME_SYSREG_READ_FUNC(erxmisc0_el1, ERXMISC0_EL1) DEFINE_RENAME_SYSREG_READ_FUNC(erxmisc1_el1, ERXMISC1_EL1) /* Armv8.2 Registers */ DEFINE_RENAME_SYSREG_READ_FUNC(id_aa64mmfr2_el1, ID_AA64MMFR2_EL1) /* Armv8.3 Pointer Authentication Registers */ DEFINE_RENAME_SYSREG_RW_FUNCS(apiakeyhi_el1, APIAKeyHi_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(apiakeylo_el1, APIAKeyLo_EL1) /* Armv8.5 MTE Registers */ DEFINE_RENAME_SYSREG_RW_FUNCS(tfsre0_el1, TFSRE0_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(tfsr_el1, TFSR_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(rgsr_el1, RGSR_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(gcr_el1, GCR_EL1) #define IS_IN_EL(x) \ (GET_EL(read_CurrentEl()) == MODE_EL##x) #define IS_IN_EL1() IS_IN_EL(1) #define IS_IN_EL2() IS_IN_EL(2) #define IS_IN_EL3() IS_IN_EL(3) static inline unsigned int get_current_el(void) { return GET_EL(read_CurrentEl()); } /* * Check if an EL is implemented from AA64PFR0 register fields. */ static inline uint64_t el_implemented(unsigned int el) { if (el > 3U) { return EL_IMPL_NONE; } else { unsigned int shift = ID_AA64PFR0_EL1_SHIFT * el; return (read_id_aa64pfr0_el1() >> shift) & ID_AA64PFR0_ELX_MASK; } } /* Previously defined accesor functions with incomplete register names */ #define read_current_el() read_CurrentEl() #define dsb() dsbsy() #define read_midr() read_midr_el1() #define read_mpidr() read_mpidr_el1() #define read_scr() read_scr_el3() #define write_scr(_v) write_scr_el3(_v) #define read_hcr() read_hcr_el2() #define write_hcr(_v) write_hcr_el2(_v) #define read_cpacr() read_cpacr_el1() #define write_cpacr(_v) write_cpacr_el1(_v) #endif /* ARCH_HELPERS_H */ trusted-firmware-a-2.2/include/arch/aarch64/asm_macros.S000066400000000000000000000124231355360272700231530ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ASM_MACROS_S #define ASM_MACROS_S #include #include #include #if ENABLE_BTI && !ARM_ARCH_AT_LEAST(8, 5) #error Branch Target Identification requires ARM_ARCH_MINOR >= 5 #endif /* * TLBI instruction with type specifier that implements the workaround for * errata 813419 of Cortex-A57 or errata 1286807 of Cortex-A76. */ #if ERRATA_A57_813419 || ERRATA_A76_1286807 #define TLB_INVALIDATE(_type) \ tlbi _type; \ dsb ish; \ tlbi _type #else #define TLB_INVALIDATE(_type) \ tlbi _type #endif .macro func_prologue stp x29, x30, [sp, #-0x10]! mov x29,sp .endm .macro func_epilogue ldp x29, x30, [sp], #0x10 .endm .macro dcache_line_size reg, tmp mrs \tmp, ctr_el0 ubfx \tmp, \tmp, #16, #4 mov \reg, #4 lsl \reg, \reg, \tmp .endm .macro icache_line_size reg, tmp mrs \tmp, ctr_el0 and \tmp, \tmp, #0xf mov \reg, #4 lsl \reg, \reg, \tmp .endm .macro smc_check label mrs x0, esr_el3 ubfx x0, x0, #ESR_EC_SHIFT, #ESR_EC_LENGTH cmp x0, #EC_AARCH64_SMC b.ne $label .endm /* * Declare the exception vector table, enforcing it is aligned on a * 2KB boundary, as required by the ARMv8 architecture. * Use zero bytes as the fill value to be stored in the padding bytes * so that it inserts illegal AArch64 instructions. This increases * security, robustness and potentially facilitates debugging. */ .macro vector_base label, section_name=.vectors .section \section_name, "ax" .align 11, 0 \label: .endm /* * Create an entry in the exception vector table, enforcing it is * aligned on a 128-byte boundary, as required by the ARMv8 architecture. * Use zero bytes as the fill value to be stored in the padding bytes * so that it inserts illegal AArch64 instructions. This increases * security, robustness and potentially facilitates debugging. */ .macro vector_entry label, section_name=.vectors .cfi_sections .debug_frame .section \section_name, "ax" .align 7, 0 .type \label, %function .cfi_startproc \label: .endm /* * Add the bytes until fill the full exception vector, whose size is always * 32 instructions. If there are more than 32 instructions in the * exception vector then an error is emitted. */ .macro end_vector_entry label .cfi_endproc .fill \label + (32 * 4) - . .endm /* * This macro calculates the base address of the current CPU's MP stack * using the plat_my_core_pos() index, the name of the stack storage * and the size of each stack * Out: X0 = physical address of stack base * Clobber: X30, X1, X2 */ .macro get_my_mp_stack _name, _size bl plat_my_core_pos adrp x2, (\_name + \_size) add x2, x2, :lo12:(\_name + \_size) mov x1, #\_size madd x0, x0, x1, x2 .endm /* * This macro calculates the base address of a UP stack using the * name of the stack storage and the size of the stack * Out: X0 = physical address of stack base */ .macro get_up_stack _name, _size adrp x0, (\_name + \_size) add x0, x0, :lo12:(\_name + \_size) .endm /* * Helper macro to generate the best mov/movk combinations according * the value to be moved. The 16 bits from '_shift' are tested and * if not zero, they are moved into '_reg' without affecting * other bits. */ .macro _mov_imm16 _reg, _val, _shift .if (\_val >> \_shift) & 0xffff .if (\_val & (1 << \_shift - 1)) movk \_reg, (\_val >> \_shift) & 0xffff, LSL \_shift .else mov \_reg, \_val & (0xffff << \_shift) .endif .endif .endm /* * Helper macro to load arbitrary values into 32 or 64-bit registers * which generates the best mov/movk combinations. Many base addresses * are 64KB aligned the macro will eliminate updating bits 15:0 in * that case */ .macro mov_imm _reg, _val .if (\_val) == 0 mov \_reg, #0 .else _mov_imm16 \_reg, (\_val), 0 _mov_imm16 \_reg, (\_val), 16 _mov_imm16 \_reg, (\_val), 32 _mov_imm16 \_reg, (\_val), 48 .endif .endm /* * Macro to mark instances where we're jumping to a function and don't * expect a return. To provide the function being jumped to with * additional information, we use 'bl' instruction to jump rather than * 'b'. * * Debuggers infer the location of a call from where LR points to, which * is usually the instruction after 'bl'. If this macro expansion * happens to be the last location in a function, that'll cause the LR * to point a location beyond the function, thereby misleading debugger * back trace. We therefore insert a 'nop' after the function call for * debug builds, unless 'skip_nop' parameter is non-zero. */ .macro no_ret _func:req, skip_nop=0 bl \_func #if DEBUG .ifeq \skip_nop nop .endif #endif .endm /* * Reserve space for a spin lock in assembly file. */ .macro define_asm_spinlock _name:req .align SPINLOCK_ASM_ALIGN \_name: .space SPINLOCK_ASM_SIZE .endm #if RAS_EXTENSION .macro esb .inst 0xd503221f .endm #endif /* * Helper macro to read system register value into x0 */ .macro read reg:req #if ENABLE_BTI bti j #endif mrs x0, \reg ret .endm /* * Helper macro to write value from x1 to system register */ .macro write reg:req #if ENABLE_BTI bti j #endif msr \reg, x1 ret .endm #endif /* ASM_MACROS_S */ trusted-firmware-a-2.2/include/arch/aarch64/assert_macros.S000066400000000000000000000013701355360272700236730ustar00rootroot00000000000000/* * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ASSERT_MACROS_S #define ASSERT_MACROS_S /* * Assembler macro to enable asm_assert. Use this macro wherever * assert is required in assembly. Please note that the macro makes * use of label '300' to provide the logic and the caller * should make sure that this label is not used to branch prior * to calling this macro. */ #define ASM_ASSERT(_cc) \ .ifndef .L_assert_filename ;\ .pushsection .rodata.str1.1, "aS" ;\ .L_assert_filename: ;\ .string __FILE__ ;\ .popsection ;\ .endif ;\ b._cc 300f ;\ adr x0, .L_assert_filename ;\ mov x1, __LINE__ ;\ b asm_assert ;\ 300: #endif /* ASSERT_MACROS_S */ trusted-firmware-a-2.2/include/arch/aarch64/console_macros.S000066400000000000000000000031231355360272700240320ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CONSOLE_MACROS_S #define CONSOLE_MACROS_S #include /* * This macro encapsulates the common setup that has to be done at the end of * a console driver's register function. It will register all of the driver's * callbacks in the console_t structure and initialize the flags field (by * default consoles are enabled for the "boot" and "crash" states, this can be * changed after registration with the console_set_scope() function). It ends * with a tail call that will include return to the caller. * REQUIRES console_t pointer in x0 and a valid return address in x30. */ .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 /* CONSOLE_MACROS_S */ trusted-firmware-a-2.2/include/arch/aarch64/el3_common_macros.S000066400000000000000000000363251355360272700244350ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef EL3_COMMON_MACROS_S #define EL3_COMMON_MACROS_S #include #include /* * Helper macro to initialise EL3 registers we care about. */ .macro el3_arch_init_common /* --------------------------------------------------------------------- * SCTLR_EL3 has already been initialised - read current value before * modifying. * * SCTLR_EL3.I: Enable the instruction cache. * * SCTLR_EL3.SA: Enable Stack Alignment check. A SP alignment fault * exception is generated if a load or store instruction executed at * EL3 uses the SP as the base address and the SP is not aligned to a * 16-byte boundary. * * SCTLR_EL3.A: Enable Alignment fault checking. All instructions that * load or store one or more registers have an alignment check that the * address being accessed is aligned to the size of the data element(s) * being accessed. * --------------------------------------------------------------------- */ mov x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT) mrs x0, sctlr_el3 orr x0, x0, x1 msr sctlr_el3, x0 isb #ifdef IMAGE_BL31 /* --------------------------------------------------------------------- * Initialise the per-cpu cache pointer to the CPU. * This is done early to enable crash reporting to have access to crash * stack. Since crash reporting depends on cpu_data to report the * unhandled exception, not doing so can lead to recursive exceptions * due to a NULL TPIDR_EL3. * --------------------------------------------------------------------- */ bl init_cpu_data_ptr #endif /* IMAGE_BL31 */ /* --------------------------------------------------------------------- * Initialise SCR_EL3, setting all fields rather than relying on hw. * All fields are architecturally UNKNOWN on reset. The following fields * do not change during the TF lifetime. The remaining fields are set to * zero here but are updated ahead of transitioning to a lower EL in the * function cm_init_context_common(). * * SCR_EL3.TWE: Set to zero so that execution of WFE instructions at * EL2, EL1 and EL0 are not trapped to EL3. * * SCR_EL3.TWI: Set to zero so that execution of WFI instructions at * EL2, EL1 and EL0 are not trapped to EL3. * * SCR_EL3.SIF: Set to one to disable instruction fetches from * Non-secure memory. * * SCR_EL3.SMD: Set to zero to enable SMC calls at EL1 and above, from * both Security states and both Execution states. * * SCR_EL3.EA: Set to one to route External Aborts and SError Interrupts * to EL3 when executing at any EL. * * SCR_EL3.{API,APK}: For Armv8.3 pointer authentication feature, * disable traps to EL3 when accessing key registers or using pointer * authentication instructions from lower ELs. * --------------------------------------------------------------------- */ mov_imm x0, ((SCR_RESET_VAL | SCR_EA_BIT | SCR_SIF_BIT) \ & ~(SCR_TWE_BIT | SCR_TWI_BIT | SCR_SMD_BIT)) #if CTX_INCLUDE_PAUTH_REGS /* * If the pointer authentication registers are saved during world * switches, enable pointer authentication everywhere, as it is safe to * do so. */ orr x0, x0, #(SCR_API_BIT | SCR_APK_BIT) #endif msr scr_el3, x0 /* --------------------------------------------------------------------- * Initialise MDCR_EL3, setting all fields rather than relying on hw. * Some fields are architecturally UNKNOWN on reset. * * MDCR_EL3.SDD: Set to one to disable AArch64 Secure self-hosted debug. * Debug exceptions, other than Breakpoint Instruction exceptions, are * disabled from all ELs in Secure state. * * MDCR_EL3.SPD32: Set to 0b10 to disable AArch32 Secure self-hosted * privileged debug from S-EL1. * * MDCR_EL3.TDOSA: Set to zero so that EL2 and EL2 System register * access to the powerdown debug registers do not trap to EL3. * * MDCR_EL3.TDA: Set to zero to allow EL0, EL1 and EL2 access to the * debug registers, other than those registers that are controlled by * MDCR_EL3.TDOSA. * * MDCR_EL3.TPM: Set to zero so that EL0, EL1, and EL2 System register * accesses to all Performance Monitors registers do not trap to EL3. * * MDCR_EL3.SCCD: Set to one so that cycle counting by PMCCNTR_EL0 is * prohibited in Secure state. This bit is RES0 in versions of the * architecture earlier than ARMv8.5, setting it to 1 doesn't have any * effect on them. * * MDCR_EL3.SPME: Set to zero so that event counting by the programmable * counters PMEVCNTR_EL0 is prohibited in Secure state. If ARMv8.2 * Debug is not implemented this bit does not have any effect on the * counters unless there is support for the implementation defined * authentication interface ExternalSecureNoninvasiveDebugEnabled(). * --------------------------------------------------------------------- */ mov_imm x0, ((MDCR_EL3_RESET_VAL | MDCR_SDD_BIT | \ MDCR_SPD32(MDCR_SPD32_DISABLE) | MDCR_SCCD_BIT) & \ ~(MDCR_SPME_BIT | MDCR_TDOSA_BIT | MDCR_TDA_BIT | \ MDCR_TPM_BIT)) msr mdcr_el3, x0 /* --------------------------------------------------------------------- * Initialise PMCR_EL0 setting all fields rather than relying * on hw. Some fields are architecturally UNKNOWN on reset. * * PMCR_EL0.LP: Set to one so that event counter overflow, that * is recorded in PMOVSCLR_EL0[0-30], occurs on the increment * that changes PMEVCNTR_EL0[63] from 1 to 0, when ARMv8.5-PMU * is implemented. This bit is RES0 in versions of the architecture * earlier than ARMv8.5, setting it to 1 doesn't have any effect * on them. * * PMCR_EL0.LC: Set to one so that cycle counter overflow, that * is recorded in PMOVSCLR_EL0[31], occurs on the increment * that changes PMCCNTR_EL0[63] from 1 to 0. * * PMCR_EL0.DP: Set to one so that the cycle counter, * PMCCNTR_EL0 does not count when event counting is prohibited. * * PMCR_EL0.X: Set to zero to disable export of events. * * PMCR_EL0.D: Set to zero so that, when enabled, PMCCNTR_EL0 * counts on every clock cycle. * --------------------------------------------------------------------- */ mov_imm x0, ((PMCR_EL0_RESET_VAL | PMCR_EL0_LP_BIT | \ PMCR_EL0_LC_BIT | PMCR_EL0_DP_BIT) & \ ~(PMCR_EL0_X_BIT | PMCR_EL0_D_BIT)) msr pmcr_el0, x0 /* --------------------------------------------------------------------- * Enable External Aborts and SError Interrupts now that the exception * vectors have been setup. * --------------------------------------------------------------------- */ msr daifclr, #DAIF_ABT_BIT /* --------------------------------------------------------------------- * Initialise CPTR_EL3, setting all fields rather than relying on hw. * All fields are architecturally UNKNOWN on reset. * * CPTR_EL3.TCPAC: Set to zero so that any accesses to CPACR_EL1, * CPTR_EL2, CPACR, or HCPTR do not trap to EL3. * * CPTR_EL3.TTA: Set to zero so that System register accesses to the * trace registers do not trap to EL3. * * CPTR_EL3.TFP: Set to zero so that accesses to the V- or Z- registers * by Advanced SIMD, floating-point or SVE instructions (if implemented) * do not trap to EL3. */ mov_imm x0, (CPTR_EL3_RESET_VAL & ~(TCPAC_BIT | TTA_BIT | TFP_BIT)) msr cptr_el3, x0 /* * If Data Independent Timing (DIT) functionality is implemented, * always enable DIT in EL3 */ mrs x0, id_aa64pfr0_el1 ubfx x0, x0, #ID_AA64PFR0_DIT_SHIFT, #ID_AA64PFR0_DIT_LENGTH cmp x0, #ID_AA64PFR0_DIT_SUPPORTED bne 1f mov x0, #DIT_BIT msr DIT, x0 1: .endm /* ----------------------------------------------------------------------------- * This is the super set of actions that need to be performed during a cold boot * or a warm boot in EL3. This code is shared by BL1 and BL31. * * This macro will always perform reset handling, architectural initialisations * and stack setup. The rest of the actions are optional because they might not * be needed, depending on the context in which this macro is called. This is * why this macro is parameterised ; each parameter allows to enable/disable * some actions. * * _init_sctlr: * Whether the macro needs to initialise SCTLR_EL3, including configuring * the endianness of data accesses. * * _warm_boot_mailbox: * Whether the macro needs to detect the type of boot (cold/warm). The * detection is based on the platform entrypoint address : if it is zero * then it is a cold boot, otherwise it is a warm boot. In the latter case, * this macro jumps on the platform entrypoint address. * * _secondary_cold_boot: * Whether the macro needs to identify the CPU that is calling it: primary * CPU or secondary CPU. The primary CPU will be allowed to carry on with * the platform initialisations, while the secondaries will be put in a * platform-specific state in the meantime. * * If the caller knows this macro will only be called by the primary CPU * then this parameter can be defined to 0 to skip this step. * * _init_memory: * Whether the macro needs to initialise the memory. * * _init_c_runtime: * Whether the macro needs to initialise the C runtime environment. * * _exception_vectors: * Address of the exception vectors to program in the VBAR_EL3 register. * ----------------------------------------------------------------------------- */ .macro el3_entrypoint_common \ _init_sctlr, _warm_boot_mailbox, _secondary_cold_boot, \ _init_memory, _init_c_runtime, _exception_vectors .if \_init_sctlr /* ------------------------------------------------------------- * This is the initialisation of SCTLR_EL3 and so must ensure * that all fields are explicitly set rather than relying on hw. * Some fields reset to an IMPLEMENTATION DEFINED value and * others are architecturally UNKNOWN on reset. * * SCTLR.EE: Set the CPU endianness before doing anything that * might involve memory reads or writes. Set to zero to select * Little Endian. * * SCTLR_EL3.WXN: For the EL3 translation regime, this field can * force all memory regions that are writeable to be treated as * XN (Execute-never). Set to zero so that this control has no * effect on memory access permissions. * * SCTLR_EL3.SA: Set to zero to disable Stack Alignment check. * * SCTLR_EL3.A: Set to zero to disable Alignment fault checking. * * SCTLR.DSSBS: Set to zero to disable speculation store bypass * safe behaviour upon exception entry to EL3. * ------------------------------------------------------------- */ mov_imm x0, (SCTLR_RESET_VAL & ~(SCTLR_EE_BIT | SCTLR_WXN_BIT \ | SCTLR_SA_BIT | SCTLR_A_BIT | SCTLR_DSSBS_BIT)) msr sctlr_el3, x0 isb .endif /* _init_sctlr */ .if \_warm_boot_mailbox /* ------------------------------------------------------------- * This code will be executed for both warm and cold resets. * Now is the time to distinguish between the two. * Query the platform entrypoint address and if it is not zero * then it means it is a warm boot so jump to this address. * ------------------------------------------------------------- */ bl plat_get_my_entrypoint cbz x0, do_cold_boot br x0 do_cold_boot: .endif /* _warm_boot_mailbox */ /* --------------------------------------------------------------------- * Set the exception vectors. * --------------------------------------------------------------------- */ adr x0, \_exception_vectors msr vbar_el3, x0 isb /* --------------------------------------------------------------------- * It is a cold boot. * Perform any processor specific actions upon reset e.g. cache, TLB * invalidations etc. * --------------------------------------------------------------------- */ bl reset_handler el3_arch_init_common .if \_secondary_cold_boot /* ------------------------------------------------------------- * Check if this is a primary or secondary CPU cold boot. * The primary CPU will set up the platform while the * secondaries are placed in a platform-specific state until the * primary CPU performs the necessary actions to bring them out * of that state and allows entry into the OS. * ------------------------------------------------------------- */ bl plat_is_my_cpu_primary cbnz w0, do_primary_cold_boot /* This is a cold boot on a secondary CPU */ bl plat_secondary_cold_boot_setup /* plat_secondary_cold_boot_setup() is not supposed to return */ bl el3_panic do_primary_cold_boot: .endif /* _secondary_cold_boot */ /* --------------------------------------------------------------------- * Initialize memory now. Secondary CPU initialization won't get to this * point. * --------------------------------------------------------------------- */ .if \_init_memory bl platform_mem_init .endif /* _init_memory */ /* --------------------------------------------------------------------- * Init C runtime environment: * - Zero-initialise the NOBITS sections. There are 2 of them: * - the .bss section; * - the coherent memory section (if any). * - Relocate the data section from ROM to RAM, if required. * --------------------------------------------------------------------- */ .if \_init_c_runtime #if defined(IMAGE_BL31) || (defined(IMAGE_BL2) && BL2_AT_EL3 && BL2_INV_DCACHE) /* ------------------------------------------------------------- * Invalidate the RW memory used by the BL31 image. This * includes the data and NOBITS sections. This is done to * safeguard against possible corruption of this memory by * dirty cache lines in a system cache as a result of use by * an earlier boot loader stage. * ------------------------------------------------------------- */ adrp x0, __RW_START__ add x0, x0, :lo12:__RW_START__ adrp x1, __RW_END__ add x1, x1, :lo12:__RW_END__ sub x1, x1, x0 bl inv_dcache_range #endif adrp x0, __BSS_START__ add x0, x0, :lo12:__BSS_START__ adrp x1, __BSS_END__ add x1, x1, :lo12:__BSS_END__ sub x1, x1, x0 bl zeromem #if USE_COHERENT_MEM adrp x0, __COHERENT_RAM_START__ add x0, x0, :lo12:__COHERENT_RAM_START__ adrp x1, __COHERENT_RAM_END_UNALIGNED__ add x1, x1, :lo12: __COHERENT_RAM_END_UNALIGNED__ sub x1, x1, x0 bl zeromem #endif #if defined(IMAGE_BL1) || (defined(IMAGE_BL2) && BL2_AT_EL3 && BL2_IN_XIP_MEM) adrp x0, __DATA_RAM_START__ add x0, x0, :lo12:__DATA_RAM_START__ adrp x1, __DATA_ROM_START__ add x1, x1, :lo12:__DATA_ROM_START__ adrp x2, __DATA_RAM_END__ add x2, x2, :lo12:__DATA_RAM_END__ sub x2, x2, x0 bl memcpy16 #endif .endif /* _init_c_runtime */ /* --------------------------------------------------------------------- * Use SP_EL0 for the C runtime stack. * --------------------------------------------------------------------- */ msr spsel, #0 /* --------------------------------------------------------------------- * Allocate a stack whose memory will be marked as Normal-IS-WBWA when * the MMU is enabled. There is no risk of reading stale stack memory * after enabling the MMU as only the primary CPU is running at the * moment. * --------------------------------------------------------------------- */ bl plat_set_my_stack #if STACK_PROTECTOR_ENABLED .if \_init_c_runtime bl update_stack_protector_canary .endif /* _init_c_runtime */ #endif .endm #endif /* EL3_COMMON_MACROS_S */ trusted-firmware-a-2.2/include/arch/aarch64/smccc_helpers.h000066400000000000000000000052541355360272700236720ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SMCCC_HELPERS_H #define SMCCC_HELPERS_H #include #ifndef __ASSEMBLER__ #include #include /* Convenience macros to return from SMC handler */ #define SMC_RET0(_h) { \ return (uint64_t) (_h); \ } #define SMC_RET1(_h, _x0) { \ write_ctx_reg((get_gpregs_ctx(_h)), (CTX_GPREG_X0), (_x0)); \ SMC_RET0(_h); \ } #define SMC_RET2(_h, _x0, _x1) { \ write_ctx_reg((get_gpregs_ctx(_h)), (CTX_GPREG_X1), (_x1)); \ SMC_RET1(_h, (_x0)); \ } #define SMC_RET3(_h, _x0, _x1, _x2) { \ write_ctx_reg((get_gpregs_ctx(_h)), (CTX_GPREG_X2), (_x2)); \ SMC_RET2(_h, (_x0), (_x1)); \ } #define SMC_RET4(_h, _x0, _x1, _x2, _x3) { \ write_ctx_reg((get_gpregs_ctx(_h)), (CTX_GPREG_X3), (_x3)); \ SMC_RET3(_h, (_x0), (_x1), (_x2)); \ } #define SMC_RET5(_h, _x0, _x1, _x2, _x3, _x4) { \ write_ctx_reg((get_gpregs_ctx(_h)), (CTX_GPREG_X4), (_x4)); \ SMC_RET4(_h, (_x0), (_x1), (_x2), (_x3)); \ } #define SMC_RET6(_h, _x0, _x1, _x2, _x3, _x4, _x5) { \ write_ctx_reg((get_gpregs_ctx(_h)), (CTX_GPREG_X5), (_x5)); \ SMC_RET5(_h, (_x0), (_x1), (_x2), (_x3), (_x4)); \ } #define SMC_RET7(_h, _x0, _x1, _x2, _x3, _x4, _x5, _x6) { \ write_ctx_reg((get_gpregs_ctx(_h)), (CTX_GPREG_X6), (_x6)); \ SMC_RET6(_h, (_x0), (_x1), (_x2), (_x3), (_x4), (_x5)); \ } #define SMC_RET8(_h, _x0, _x1, _x2, _x3, _x4, _x5, _x6, _x7) { \ write_ctx_reg((get_gpregs_ctx(_h)), (CTX_GPREG_X7), (_x7)); \ SMC_RET7(_h, (_x0), (_x1), (_x2), (_x3), (_x4), (_x5), (_x6)); \ } /* * Convenience macros to access general purpose registers using handle provided * to SMC handler. These take the offset values defined in context.h */ #define SMC_GET_GP(_h, _g) \ read_ctx_reg((get_gpregs_ctx(_h)), (_g)) #define SMC_SET_GP(_h, _g, _v) \ write_ctx_reg((get_gpregs_ctx(_h)), (_g), (_v)) /* * Convenience macros to access EL3 context registers using handle provided to * SMC handler. These take the offset values defined in context.h */ #define SMC_GET_EL3(_h, _e) \ read_ctx_reg((get_el3state_ctx(_h)), (_e)) #define SMC_SET_EL3(_h, _e, _v) \ write_ctx_reg((get_el3state_ctx(_h)), (_e), (_v)) /* * Helper macro to retrieve the SMC parameters from cpu_context_t. */ #define get_smc_params_from_ctx(_hdl, _x1, _x2, _x3, _x4) \ do { \ const gp_regs_t *regs = get_gpregs_ctx(_hdl); \ _x1 = read_ctx_reg(regs, CTX_GPREG_X1); \ _x2 = read_ctx_reg(regs, CTX_GPREG_X2); \ _x3 = read_ctx_reg(regs, CTX_GPREG_X3); \ _x4 = read_ctx_reg(regs, CTX_GPREG_X4); \ } while (false) #endif /*__ASSEMBLER__*/ #endif /* SMCCC_HELPERS_H */ trusted-firmware-a-2.2/include/bl1/000077500000000000000000000000001355360272700172125ustar00rootroot00000000000000trusted-firmware-a-2.2/include/bl1/bl1.h000066400000000000000000000042331355360272700200430ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BL1_H #define BL1_H #include /* * Defines for BL1 SMC function ids. */ #define BL1_SMC_CALL_COUNT 0x0 #define BL1_SMC_UID 0x1 /* SMC #0x2 reserved */ #define BL1_SMC_VERSION 0x3 /* * Corresponds to the function ID of the SMC that * the BL1 exception handler service to execute BL31. */ #define BL1_SMC_RUN_IMAGE 0x4 /* * BL1 SMC version */ #define BL1_SMC_MAJOR_VER 0x0 #define BL1_SMC_MINOR_VER 0x1 /* * Defines for FWU SMC function ids. */ #define FWU_SMC_IMAGE_COPY 0x10 #define FWU_SMC_IMAGE_AUTH 0x11 #define FWU_SMC_IMAGE_EXECUTE 0x12 #define FWU_SMC_IMAGE_RESUME 0x13 #define FWU_SMC_SEC_IMAGE_DONE 0x14 #define FWU_SMC_UPDATE_DONE 0x15 #define FWU_SMC_IMAGE_RESET 0x16 /* * Number of FWU calls (above) implemented */ #define FWU_NUM_SMC_CALLS 7 #if TRUSTED_BOARD_BOOT # define BL1_NUM_SMC_CALLS (FWU_NUM_SMC_CALLS + 4) #else # define BL1_NUM_SMC_CALLS 4 #endif /* * The macros below are used to identify FWU * calls from the SMC function ID */ #define FWU_SMC_FID_START FWU_SMC_IMAGE_COPY #define FWU_SMC_FID_END FWU_SMC_IMAGE_RESET #define is_fwu_fid(_fid) \ ((_fid >= FWU_SMC_FID_START) && (_fid <= FWU_SMC_FID_END)) #ifndef __ASSEMBLER__ #include struct entry_point_info; register_t bl1_smc_wrapper(uint32_t smc_fid, void *cookie, void *handle, unsigned int flags); register_t bl1_smc_handler(unsigned int smc_fid, register_t x1, register_t x2, register_t x3, register_t x4, void *cookie, void *handle, unsigned int flags); void bl1_print_next_bl_ep_info(const struct entry_point_info *bl_ep_info); void bl1_setup(void); void bl1_main(void); void bl1_plat_prepare_exit(entry_point_info_t *ep_info); /* * Check if the total number of FWU SMC calls are as expected. */ CASSERT(FWU_NUM_SMC_CALLS == \ (FWU_SMC_FID_END - FWU_SMC_FID_START + 1),\ assert_FWU_NUM_SMC_CALLS_mismatch); /* Utility functions */ void bl1_calc_bl2_mem_layout(const meminfo_t *bl1_mem_layout, meminfo_t *bl2_mem_layout); #endif /* __ASSEMBLER__ */ #endif /* BL1_H */ trusted-firmware-a-2.2/include/bl1/tbbr/000077500000000000000000000000001355360272700201435ustar00rootroot00000000000000trusted-firmware-a-2.2/include/bl1/tbbr/tbbr_img_desc.h000066400000000000000000000004301355360272700230740ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TBBR_IMG_DESC_H #define TBBR_IMG_DESC_H #include extern image_desc_t bl1_tbbr_image_descs[]; #endif /* TBBR_IMG_DESC_H */ trusted-firmware-a-2.2/include/bl2/000077500000000000000000000000001355360272700172135ustar00rootroot00000000000000trusted-firmware-a-2.2/include/bl2/bl2.h000066400000000000000000000006471355360272700200520ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BL2_H #define BL2_H #include void bl2_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3); void bl2_el3_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3); void bl2_main(void); #endif /* BL2_H */ trusted-firmware-a-2.2/include/bl2u/000077500000000000000000000000001355360272700174005ustar00rootroot00000000000000trusted-firmware-a-2.2/include/bl2u/bl2u.h000066400000000000000000000003101355360272700204070ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BL2U_H #define BL2U_H void bl2u_main(void); #endif /* BL2U_H */ trusted-firmware-a-2.2/include/bl31/000077500000000000000000000000001355360272700172755ustar00rootroot00000000000000trusted-firmware-a-2.2/include/bl31/bl31.h000066400000000000000000000014541355360272700202130ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BL31_H #define BL31_H #include /******************************************************************************* * Function prototypes ******************************************************************************/ void bl31_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3); void bl31_next_el_arch_setup(uint32_t security_state); void bl31_set_next_image_type(uint32_t security_state); uint32_t bl31_get_next_image_type(void); void bl31_prepare_next_image_entry(void); void bl31_register_bl32_init(int32_t (*func)(void)); void bl31_warm_entrypoint(void); void bl31_main(void); void bl31_lib_init(void); #endif /* BL31_H */ trusted-firmware-a-2.2/include/bl31/ea_handle.h000066400000000000000000000011071355360272700213450ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef EA_HANDLE_H #define EA_HANDLE_H /* Constants indicating the reason for an External Abort */ /* External Abort received at SError vector */ #define ERROR_EA_ASYNC 0 /* Synchronous External Abort received at Synchronous exception vector */ #define ERROR_EA_SYNC 1 /* External Abort synchronized by ESB instruction */ #define ERROR_EA_ESB 2 /* RAS event signalled as peripheral interrupt */ #define ERROR_INTERRUPT 3 #endif /* EA_HANDLE_H */ trusted-firmware-a-2.2/include/bl31/ehf.h000066400000000000000000000052041355360272700202110ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef EHF_H #define EHF_H #ifndef __ASSEMBLER__ #include #include #include /* Valid priorities set bit 0 of the priority handler. */ #define EHF_PRI_VALID_ BIT(0) /* Marker for no handler registered for a valid priority */ #define EHF_NO_HANDLER_ (0U | EHF_PRI_VALID_) /* Extract the specified number of top bits from 7 lower bits of priority */ #define EHF_PRI_TO_IDX(pri, plat_bits) \ ((((unsigned) (pri)) & 0x7fu) >> (7u - (plat_bits))) /* Install exception priority descriptor at a suitable index */ #define EHF_PRI_DESC(plat_bits, priority) \ [EHF_PRI_TO_IDX(priority, plat_bits)] = { \ .ehf_handler = EHF_NO_HANDLER_, \ } /* Macro for platforms to regiter its exception priorities */ #define EHF_REGISTER_PRIORITIES(priorities, num, bits) \ const ehf_priorities_t exception_data = { \ .num_priorities = (num), \ .ehf_priorities = (priorities), \ .pri_bits = (bits), \ } /* * Priority stack, managed as a bitmap. * * Currently only supports 32 priority levels, allowing platforms to use up to 5 * top bits of priority. But the type can be changed to uint64_t should need * arise to support 64 priority levels, allowing platforms to use up to 6 top * bits of priority. */ typedef uint32_t ehf_pri_bits_t; /* * Per-PE exception data. The data for each PE is kept as a per-CPU data field. * See cpu_data.h. */ typedef struct { ehf_pri_bits_t active_pri_bits; /* Priority mask value before any priority levels were active */ uint8_t init_pri_mask; /* Non-secure priority mask value stashed during Secure execution */ uint8_t ns_pri_mask; } __aligned(sizeof(uint64_t)) pe_exc_data_t; typedef int (*ehf_handler_t)(uint32_t intr_raw, uint32_t flags, void *handle, void *cookie); typedef struct ehf_pri_desc { /* * 4-byte-aligned exception handler. Bit 0 indicates the corresponding * priority level is valid. This is effectively of ehf_handler_t type, * but left as uintptr_t in order to make pointer arithmetic convenient. */ uintptr_t ehf_handler; } ehf_pri_desc_t; typedef struct ehf_priority_type { ehf_pri_desc_t *ehf_priorities; unsigned int num_priorities; unsigned int pri_bits; } ehf_priorities_t; void ehf_init(void); void ehf_activate_priority(unsigned int priority); void ehf_deactivate_priority(unsigned int priority); void ehf_register_priority_handler(unsigned int pri, ehf_handler_t handler); void ehf_allow_ns_preemption(uint64_t preempt_ret_code); unsigned int ehf_is_ns_preemption_allowed(void); #endif /* __ASSEMBLER__ */ #endif /* EHF_H */ trusted-firmware-a-2.2/include/bl31/interrupt_mgmt.h000066400000000000000000000126771355360272700225430ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef INTERRUPT_MGMT_H #define INTERRUPT_MGMT_H #include #include /******************************************************************************* * Constants for the types of interrupts recognised by the IM framework ******************************************************************************/ #define INTR_TYPE_S_EL1 U(0) #define INTR_TYPE_EL3 U(1) #define INTR_TYPE_NS U(2) #define MAX_INTR_TYPES U(3) #define INTR_TYPE_INVAL MAX_INTR_TYPES /* Interrupt routing modes */ #define INTR_ROUTING_MODE_PE 0 #define INTR_ROUTING_MODE_ANY 1 /* * Constant passed to the interrupt handler in the 'id' field when the * framework does not read the gic registers to determine the interrupt id. */ #define INTR_ID_UNAVAILABLE U(0xFFFFFFFF) /******************************************************************************* * Mask for _both_ the routing model bits in the 'flags' parameter and * constants to define the valid routing models for each supported interrupt * type ******************************************************************************/ #define INTR_RM_FLAGS_SHIFT U(0x0) #define INTR_RM_FLAGS_MASK U(0x3) /* Routed to EL3 from NS. Taken to S-EL1 from Secure */ #define INTR_SEL1_VALID_RM0 U(0x2) /* Routed to EL3 from NS and Secure */ #define INTR_SEL1_VALID_RM1 U(0x3) /* Routed to EL1/EL2 from NS and to S-EL1 from Secure */ #define INTR_NS_VALID_RM0 U(0x0) /* Routed to EL1/EL2 from NS and to EL3 from Secure */ #define INTR_NS_VALID_RM1 U(0x1) /* Routed to EL3 from NS. Taken to S-EL1 from Secure and handed over to EL3 */ #define INTR_EL3_VALID_RM0 U(0x2) /* Routed to EL3 from NS and Secure */ #define INTR_EL3_VALID_RM1 U(0x3) /* This is the default routing model */ #define INTR_DEFAULT_RM U(0x0) /******************************************************************************* * Constants for the _individual_ routing model bits in the 'flags' field for * each interrupt type and mask to validate the 'flags' parameter while * registering an interrupt handler ******************************************************************************/ #define INTR_TYPE_FLAGS_MASK U(0xFFFFFFFC) #define INTR_RM_FROM_SEC_SHIFT SECURE /* BIT[0] */ #define INTR_RM_FROM_NS_SHIFT NON_SECURE /* BIT[1] */ #define INTR_RM_FROM_FLAG_MASK U(1) #define get_interrupt_rm_flag(flag, ss) \ ((((flag) >> INTR_RM_FLAGS_SHIFT) >> (ss)) & INTR_RM_FROM_FLAG_MASK) #define set_interrupt_rm_flag(flag, ss) ((flag) |= U(1) << (ss)) #define clr_interrupt_rm_flag(flag, ss) ((flag) &= ~(U(1) << (ss))) /******************************************************************************* * Macros to set the 'flags' parameter passed to an interrupt type handler. Only * the flag to indicate the security state when the exception was generated is * supported. ******************************************************************************/ #define INTR_SRC_SS_FLAG_SHIFT U(0) /* BIT[0] */ #define INTR_SRC_SS_FLAG_MASK U(1) #define set_interrupt_src_ss(flag, val) ((flag) |= (val) << INTR_SRC_SS_FLAG_SHIFT) #define clr_interrupt_src_ss(flag) ((flag) &= ~(U(1) << INTR_SRC_SS_FLAG_SHIFT)) #define get_interrupt_src_ss(flag) (((flag) >> INTR_SRC_SS_FLAG_SHIFT) & \ INTR_SRC_SS_FLAG_MASK) #ifndef __ASSEMBLER__ #include #include /******************************************************************************* * Helpers to validate the routing model bits in the 'flags' for a type * of interrupt. If the model does not match one of the valid masks * -EINVAL is returned. ******************************************************************************/ static inline int32_t validate_sel1_interrupt_rm(uint32_t x) { if ((x == INTR_SEL1_VALID_RM0) || (x == INTR_SEL1_VALID_RM1)) return 0; return -EINVAL; } static inline int32_t validate_ns_interrupt_rm(uint32_t x) { if ((x == INTR_NS_VALID_RM0) || (x == INTR_NS_VALID_RM1)) return 0; return -EINVAL; } static inline int32_t validate_el3_interrupt_rm(uint32_t x) { #if EL3_EXCEPTION_HANDLING /* * With EL3 exception handling, EL3 interrupts are always routed to EL3 * from both Secure and Non-secure, and therefore INTR_EL3_VALID_RM1 is * the only valid routing model. */ if (x == INTR_EL3_VALID_RM1) return 0; #else if ((x == INTR_EL3_VALID_RM0) || (x == INTR_EL3_VALID_RM1)) return 0; #endif return -EINVAL; } /******************************************************************************* * Prototype for defining a handler for an interrupt type ******************************************************************************/ typedef uint64_t (*interrupt_type_handler_t)(uint32_t id, uint32_t flags, void *handle, void *cookie); /******************************************************************************* * Function & variable prototypes ******************************************************************************/ uint32_t get_scr_el3_from_routing_model(uint32_t security_state); int32_t set_routing_model(uint32_t type, uint32_t flags); int32_t register_interrupt_type_handler(uint32_t type, interrupt_type_handler_t handler, uint32_t flags); interrupt_type_handler_t get_interrupt_type_handler(uint32_t type); int disable_intr_rm_local(uint32_t type, uint32_t security_state); int enable_intr_rm_local(uint32_t type, uint32_t security_state); #endif /*__ASSEMBLER__*/ #endif /* INTERRUPT_MGMT_H */ trusted-firmware-a-2.2/include/bl32/000077500000000000000000000000001355360272700172765ustar00rootroot00000000000000trusted-firmware-a-2.2/include/bl32/payloads/000077500000000000000000000000001355360272700211125ustar00rootroot00000000000000trusted-firmware-a-2.2/include/bl32/payloads/tlk.h000066400000000000000000000042571355360272700220650ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TLK_H #define TLK_H #include /* * Generate function IDs for the Trusted OS/Apps */ #define TLK_TOS_YIELD_FID(fid) ((fid) | 0x72000000 | (0 << 31)) #define TLK_TA_YIELD_FID(fid) ((fid) | 0x70000000 | (0 << 31)) /* * Trusted OS specific function IDs */ #define TLK_REGISTER_LOGBUF TLK_TOS_YIELD_FID(0x1) #define TLK_REGISTER_REQBUF TLK_TOS_YIELD_FID(0x2) #define TLK_SS_REGISTER_HANDLER TLK_TOS_YIELD_FID(0x3) #define TLK_REGISTER_NS_DRAM_RANGES TLK_TOS_YIELD_FID(0x4) #define TLK_SET_ROOT_OF_TRUST TLK_TOS_YIELD_FID(0x5) #define TLK_RESUME_FID TLK_TOS_YIELD_FID(0x100) #define TLK_SYSTEM_SUSPEND TLK_TOS_YIELD_FID(0xE001) #define TLK_SYSTEM_RESUME TLK_TOS_YIELD_FID(0xE002) #define TLK_SYSTEM_OFF TLK_TOS_YIELD_FID(0xE003) /* * SMC function IDs that TLK uses to signal various forms of completions * to the secure payload dispatcher. */ #define TLK_REQUEST_DONE (0x32000001 | (ULL(1) << 31)) #define TLK_PREEMPTED (0x32000002 | (ULL(1) << 31)) #define TLK_ENTRY_DONE (0x32000003 | (ULL(1) << 31)) #define TLK_VA_TRANSLATE (0x32000004 | (ULL(1) << 31)) #define TLK_SUSPEND_DONE (0x32000005 | (ULL(1) << 31)) #define TLK_RESUME_DONE (0x32000006 | (ULL(1) << 31)) #define TLK_SYSTEM_OFF_DONE (0x32000007 | (ULL(1) << 31)) /* * Trusted Application specific function IDs */ #define TLK_OPEN_TA_SESSION TLK_TA_YIELD_FID(0x1) #define TLK_CLOSE_TA_SESSION TLK_TA_YIELD_FID(0x2) #define TLK_TA_LAUNCH_OP TLK_TA_YIELD_FID(0x3) #define TLK_TA_SEND_EVENT TLK_TA_YIELD_FID(0x4) /* * Total number of function IDs implemented for services offered to NS clients. */ #define TLK_NUM_FID 7 /* TLK implementation version numbers */ #define TLK_VERSION_MAJOR 0x0 /* Major version */ #define TLK_VERSION_MINOR 0x1 /* Minor version */ /* * Standard Trusted OS Function IDs that fall under Trusted OS call range * according to SMC calling convention */ #define TOS_CALL_COUNT 0xbf00ff00 /* Number of calls implemented */ #define TOS_UID 0xbf00ff01 /* Implementation UID */ #define TOS_CALL_VERSION 0xbf00ff03 /* Trusted OS Call Version */ #endif /* TLK_H */ trusted-firmware-a-2.2/include/bl32/sp_min/000077500000000000000000000000001355360272700205635ustar00rootroot00000000000000trusted-firmware-a-2.2/include/bl32/sp_min/platform_sp_min.h000066400000000000000000000015341355360272700241300ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_SP_MIN_H #define PLATFORM_SP_MIN_H #include /******************************************************************************* * Mandatory SP_MIN functions ******************************************************************************/ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3); void sp_min_platform_setup(void); void sp_min_plat_runtime_setup(void); void sp_min_plat_arch_setup(void); entry_point_info_t *sp_min_plat_get_bl33_ep_info(void); void sp_min_warm_entrypoint(void); /* Platforms that enable SP_MIN_WITH_SECURE_FIQ shall implement this api */ void sp_min_plat_fiq_handler(uint32_t id); #endif /* PLATFORM_SP_MIN_H */ trusted-firmware-a-2.2/include/bl32/tsp/000077500000000000000000000000001355360272700201045ustar00rootroot00000000000000trusted-firmware-a-2.2/include/bl32/tsp/platform_tsp.h000066400000000000000000000010151355360272700227640ustar00rootroot00000000000000/* * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_TSP_H #define PLATFORM_TSP_H /******************************************************************************* * Mandatory TSP functions (only if platform contains a TSP) ******************************************************************************/ void tsp_early_platform_setup(void); void tsp_plat_arch_setup(void); void tsp_platform_setup(void); #endif /* PLATFORM_TSP_H */ trusted-firmware-a-2.2/include/bl32/tsp/tsp.h000066400000000000000000000062711355360272700210710ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TSP_H #define TSP_H /* * SMC function IDs that TSP uses to signal various forms of completions * to the secure payload dispatcher. */ #define TSP_ENTRY_DONE 0xf2000000 #define TSP_ON_DONE 0xf2000001 #define TSP_OFF_DONE 0xf2000002 #define TSP_SUSPEND_DONE 0xf2000003 #define TSP_RESUME_DONE 0xf2000004 #define TSP_PREEMPTED 0xf2000005 #define TSP_ABORT_DONE 0xf2000007 #define TSP_SYSTEM_OFF_DONE 0xf2000008 #define TSP_SYSTEM_RESET_DONE 0xf2000009 /* * Function identifiers to handle S-EL1 interrupt through the synchronous * handling model. If the TSP was previously interrupted then control has to * be returned to the TSPD after handling the interrupt else execution can * remain in the TSP. */ #define TSP_HANDLED_S_EL1_INTR 0xf2000006 /* SMC function ID that TSP uses to request service from secure monitor */ #define TSP_GET_ARGS 0xf2001000 /* * Identifiers for various TSP services. Corresponding function IDs (whether * fast or yielding) are generated by macros defined below */ #define TSP_ADD 0x2000 #define TSP_SUB 0x2001 #define TSP_MUL 0x2002 #define TSP_DIV 0x2003 #define TSP_HANDLE_SEL1_INTR_AND_RETURN 0x2004 /* * Identify a TSP service from function ID filtering the last 16 bits from the * SMC function ID */ #define TSP_BARE_FID(fid) ((fid) & 0xffff) /* * Generate function IDs for TSP services to be used in SMC calls, by * appropriately setting bit 31 to differentiate yielding and fast SMC calls */ #define TSP_YIELD_FID(fid) ((TSP_BARE_FID(fid) | 0x72000000)) #define TSP_FAST_FID(fid) ((TSP_BARE_FID(fid) | 0x72000000) | (1u << 31)) /* SMC function ID to request a previously preempted yielding smc */ #define TSP_FID_RESUME TSP_YIELD_FID(0x3000) /* * SMC function ID to request abortion of a previously preempted yielding SMC. A * fast SMC is used so that the TSP abort handler does not have to be * reentrant. */ #define TSP_FID_ABORT TSP_FAST_FID(0x3001) /* * Total number of function IDs implemented for services offered to NS clients. * The function IDs are defined above */ #define TSP_NUM_FID 0x5 /* TSP implementation version numbers */ #define TSP_VERSION_MAJOR 0x0 /* Major version */ #define TSP_VERSION_MINOR 0x1 /* Minor version */ /* * Standard Trusted OS Function IDs that fall under Trusted OS call range * according to SMC calling convention */ #define TOS_CALL_COUNT 0xbf00ff00 /* Number of calls implemented */ #define TOS_UID 0xbf00ff01 /* Implementation UID */ /* 0xbf00ff02 is reserved */ #define TOS_CALL_VERSION 0xbf00ff03 /* Trusted OS Call Version */ #ifndef __ASSEMBLER__ #include typedef uint32_t tsp_vector_isn_t; typedef struct tsp_vectors { tsp_vector_isn_t yield_smc_entry; tsp_vector_isn_t fast_smc_entry; tsp_vector_isn_t cpu_on_entry; tsp_vector_isn_t cpu_off_entry; tsp_vector_isn_t cpu_resume_entry; tsp_vector_isn_t cpu_suspend_entry; tsp_vector_isn_t sel1_intr_entry; tsp_vector_isn_t system_off_entry; tsp_vector_isn_t system_reset_entry; tsp_vector_isn_t abort_yield_smc_entry; } tsp_vectors_t; void tsp_setup(void); #endif /* __ASSEMBLER__ */ #endif /* TSP_H */ trusted-firmware-a-2.2/include/common/000077500000000000000000000000001355360272700200245ustar00rootroot00000000000000trusted-firmware-a-2.2/include/common/asm_macros_common.S000066400000000000000000000062111355360272700236440ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ASM_MACROS_COMMON_S #define ASM_MACROS_COMMON_S /* * This macro is used to create a function label and place the * code into a separate text section based on the function name * to enable elimination of unused code during linking. It also adds * basic debug information to enable call stack printing most of the * time. The optional _align parameter can be used to force a * non-standard alignment (indicated in powers of 2). The default is * _align=2 because both Aarch32 and Aarch64 instructions must be * word aligned. Do *not* try to use a raw .align directive. Since func * switches to a new section, this would not have the desired effect. */ .macro func _name, _align=2 /* * Add Call Frame Information entry in the .debug_frame section for * debugger consumption. This enables callstack printing in debuggers. * This does not use any space in the final loaded binary, only in the * ELF file. * Note that a function manipulating the CFA pointer location (i.e. the * x29 frame pointer on AArch64) should declare it using the * appropriate .cfi* directives, or be prepared to have a degraded * debugging experience. */ .cfi_sections .debug_frame .section .text.asm.\_name, "ax" .type \_name, %function /* * .cfi_startproc and .cfi_endproc are needed to output entries in * .debug_frame */ .cfi_startproc .align \_align \_name: #if ENABLE_BTI /* When Branch Target Identification is enabled, insert "bti jc" * instruction to enable indirect calls and branches */ bti jc #endif .endm /* * This macro is used to mark the end of a function. */ .macro endfunc _name .cfi_endproc .size \_name, . - \_name .endm /* * Theses macros are used to create function labels for deprecated * APIs. If ERROR_DEPRECATED is non zero, the callers of these APIs * will fail to link and cause build failure. */ #if ERROR_DEPRECATED .macro func_deprecated _name func deprecated\_name .endm .macro endfunc_deprecated _name endfunc deprecated\_name .endm #else .macro func_deprecated _name func \_name .endm .macro endfunc_deprecated _name endfunc \_name .endm #endif /* * Helper assembler macro to count trailing zeros. The output is * populated in the `TZ_COUNT` symbol. */ .macro count_tz _value, _tz_count .if \_value count_tz "(\_value >> 1)", "(\_tz_count + 1)" .else .equ TZ_COUNT, (\_tz_count - 1) .endif .endm /* * This macro declares an array of 1 or more stacks, properly * aligned and in the requested section */ #define DEFAULT_STACK_ALIGN (1 << 6) /* In case the caller doesnt provide alignment */ .macro declare_stack _name, _section, _size, _count, _align=DEFAULT_STACK_ALIGN count_tz \_align, 0 .if (\_align - (1 << TZ_COUNT)) .error "Incorrect stack alignment specified (Must be a power of 2)." .endif .if ((\_size & ((1 << TZ_COUNT) - 1)) <> 0) .error "Stack size not correctly aligned" .endif .section \_section, "aw", %nobits .align TZ_COUNT \_name: .space ((\_count) * (\_size)), 0 .endm #endif /* ASM_MACROS_COMMON_S */ trusted-firmware-a-2.2/include/common/bl_common.h000066400000000000000000000151201355360272700221410ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BL_COMMON_H #define BL_COMMON_H #include #include #include #ifndef __ASSEMBLER__ #include #include #include #endif /* __ASSEMBLER__ */ #include #define UP U(1) #define DOWN U(0) /******************************************************************************* * Constants to identify the location of a memory region in a given memory * layout. ******************************************************************************/ #define TOP U(0x1) #define BOTTOM U(0x0) /******************************************************************************* * Constants to indicate type of exception to the common exception handler. ******************************************************************************/ #define SYNC_EXCEPTION_SP_EL0 U(0x0) #define IRQ_SP_EL0 U(0x1) #define FIQ_SP_EL0 U(0x2) #define SERROR_SP_EL0 U(0x3) #define SYNC_EXCEPTION_SP_ELX U(0x4) #define IRQ_SP_ELX U(0x5) #define FIQ_SP_ELX U(0x6) #define SERROR_SP_ELX U(0x7) #define SYNC_EXCEPTION_AARCH64 U(0x8) #define IRQ_AARCH64 U(0x9) #define FIQ_AARCH64 U(0xa) #define SERROR_AARCH64 U(0xb) #define SYNC_EXCEPTION_AARCH32 U(0xc) #define IRQ_AARCH32 U(0xd) #define FIQ_AARCH32 U(0xe) #define SERROR_AARCH32 U(0xf) /* * Mapping to connect linker symbols from .ld.S with their counterparts * from .scat for the BL31 image */ #if defined(USE_ARM_LINK) #define __BL31_END__ Load$$LR$$LR_END$$Base #define __BSS_START__ Load$$LR$$LR_BSS$$Base #define __BSS_END__ Load$$LR$$LR_BSS$$Limit #define __BSS_SIZE__ Load$$LR$$LR_BSS$$Length #define __COHERENT_RAM_START__ Load$$LR$$LR_COHERENT_RAM$$Base #define __COHERENT_RAM_END_UNALIGNED__ Load$$__COHERENT_RAM_EPILOGUE_UNALIGNED__$$Base #define __COHERENT_RAM_END__ Load$$LR$$LR_COHERENT_RAM$$Limit #define __COHERENT_RAM_UNALIGNED_SIZE__ Load$$__COHERENT_RAM__$$Length #define __CPU_OPS_START__ Load$$__CPU_OPS__$$Base #define __CPU_OPS_END__ Load$$__CPU_OPS__$$Limit #define __DATA_START__ Load$$__DATA__$$Base #define __DATA_END__ Load$$__DATA__$$Limit #define __GOT_START__ Load$$__GOT__$$Base #define __GOT_END__ Load$$__GOT__$$Limit #define __PERCPU_BAKERY_LOCK_START__ Load$$__BAKERY_LOCKS__$$Base #define __PERCPU_BAKERY_LOCK_END__ Load$$__BAKERY_LOCKS_EPILOGUE__$$Base #define __PMF_SVC_DESCS_START__ Load$$__PMF_SVC_DESCS__$$Base #define __PMF_SVC_DESCS_END__ Load$$__PMF_SVC_DESCS__$$Limit #define __PMF_TIMESTAMP_START__ Load$$__PMF_TIMESTAMP__$$Base #define __PMF_TIMESTAMP_END__ Load$$__PER_CPU_TIMESTAMPS__$$Limit #define __PMF_PERCPU_TIMESTAMP_END__ Load$$__PMF_TIMESTAMP_EPILOGUE__$$Base #define __RELA_END__ Load$$__RELA__$$Limit #define __RELA_START__ Load$$__RELA__$$Base #define __RODATA_START__ Load$$__RODATA__$$Base #define __RODATA_END__ Load$$__RODATA_EPILOGUE__$$Base #define __RT_SVC_DESCS_START__ Load$$__RT_SVC_DESCS__$$Base #define __RT_SVC_DESCS_END__ Load$$__RT_SVC_DESCS__$$Limit #define __RW_START__ Load$$LR$$LR_RW_DATA$$Base #define __RW_END__ Load$$LR$$LR_END$$Base #define __SPM_SHIM_EXCEPTIONS_START__ Load$$__SPM_SHIM_EXCEPTIONS__$$Base #define __SPM_SHIM_EXCEPTIONS_END__ Load$$__SPM_SHIM_EXCEPTIONS_EPILOGUE__$$Base #define __STACKS_START__ Load$$__STACKS__$$Base #define __STACKS_END__ Load$$__STACKS__$$Limit #define __TEXT_START__ Load$$__TEXT__$$Base #define __TEXT_END__ Load$$__TEXT_EPILOGUE__$$Base #endif /* USE_ARM_LINK */ #ifndef __ASSEMBLER__ /* * Declarations of linker defined symbols to help determine memory layout of * BL images */ #if SEPARATE_CODE_AND_RODATA IMPORT_SYM(uintptr_t, __TEXT_START__, BL_CODE_BASE); IMPORT_SYM(uintptr_t, __TEXT_END__, BL_CODE_END); IMPORT_SYM(uintptr_t, __RODATA_START__, BL_RO_DATA_BASE); IMPORT_SYM(uintptr_t, __RODATA_END__, BL_RO_DATA_END); #else IMPORT_SYM(uintptr_t, __RO_START__, BL_CODE_BASE); IMPORT_SYM(uintptr_t, __RO_END__, BL_CODE_END); #endif #if defined(IMAGE_BL1) IMPORT_SYM(uintptr_t, __BL1_ROM_END__, BL1_ROM_END); IMPORT_SYM(uintptr_t, __BL1_RAM_START__, BL1_RAM_BASE); IMPORT_SYM(uintptr_t, __BL1_RAM_END__, BL1_RAM_LIMIT); #elif defined(IMAGE_BL2) IMPORT_SYM(uintptr_t, __BL2_END__, BL2_END); #elif defined(IMAGE_BL2U) IMPORT_SYM(uintptr_t, __BL2U_END__, BL2U_END); #elif defined(IMAGE_BL31) IMPORT_SYM(uintptr_t, __BL31_START__, BL31_START); IMPORT_SYM(uintptr_t, __BL31_END__, BL31_END); #elif defined(IMAGE_BL32) IMPORT_SYM(uintptr_t, __BL32_END__, BL32_END); #endif /* IMAGE_BLX */ /* The following symbols are only exported from the BL2 at EL3 linker script. */ #if BL2_IN_XIP_MEM && defined(IMAGE_BL2) IMPORT_SYM(uintptr_t, __BL2_ROM_END__, BL2_ROM_END); IMPORT_SYM(uintptr_t, __BL2_RAM_START__, BL2_RAM_BASE); IMPORT_SYM(uintptr_t, __BL2_RAM_END__, BL2_RAM_END); #endif /* BL2_IN_XIP_MEM */ /* * The next 2 constants identify the extents of the coherent memory region. * These addresses are used by the MMU setup code and therefore they must be * page-aligned. It is the responsibility of the linker script to ensure that * __COHERENT_RAM_START__ and __COHERENT_RAM_END__ linker symbols refer to * page-aligned addresses. */ #if USE_COHERENT_MEM IMPORT_SYM(uintptr_t, __COHERENT_RAM_START__, BL_COHERENT_RAM_BASE); IMPORT_SYM(uintptr_t, __COHERENT_RAM_END__, BL_COHERENT_RAM_END); #endif /******************************************************************************* * Structure used for telling the next BL how much of a particular type of * memory is available for its use and how much is already used. ******************************************************************************/ typedef struct meminfo { uintptr_t total_base; size_t total_size; } meminfo_t; /******************************************************************************* * Function & variable prototypes ******************************************************************************/ int load_auth_image(unsigned int image_id, image_info_t *image_data); #if TRUSTED_BOARD_BOOT && defined(DYN_DISABLE_AUTH) /* * API to dynamically disable authentication. Only meant for development * systems. */ void dyn_disable_auth(void); #endif extern const char build_message[]; extern const char version_string[]; void print_entry_point_info(const entry_point_info_t *ep_info); uintptr_t page_align(uintptr_t value, unsigned dir); struct mmap_region; void setup_page_tables(const struct mmap_region *bl_regions, const struct mmap_region *plat_regions); void bl_handle_pauth(void); #endif /*__ASSEMBLER__*/ #endif /* BL_COMMON_H */ trusted-firmware-a-2.2/include/common/debug.h000066400000000000000000000057731355360272700212770ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef DEBUG_H #define DEBUG_H #include /* * The log output macros print output to the console. These macros produce * compiled log output only if the LOG_LEVEL defined in the makefile (or the * make command line) is greater or equal than the level required for that * type of log output. * * The format expected is the same as for printf(). For example: * INFO("Info %s.\n", "message") -> INFO: Info message. * WARN("Warning %s.\n", "message") -> WARNING: Warning message. */ #define LOG_LEVEL_NONE U(0) #define LOG_LEVEL_ERROR U(10) #define LOG_LEVEL_NOTICE U(20) #define LOG_LEVEL_WARNING U(30) #define LOG_LEVEL_INFO U(40) #define LOG_LEVEL_VERBOSE U(50) #ifndef __ASSEMBLER__ #include #include #include #include #include /* * Define Log Markers corresponding to each log level which will * be embedded in the format string and is expected by tf_log() to determine * the log level. */ #define LOG_MARKER_ERROR "\xa" /* 10 */ #define LOG_MARKER_NOTICE "\x14" /* 20 */ #define LOG_MARKER_WARNING "\x1e" /* 30 */ #define LOG_MARKER_INFO "\x28" /* 40 */ #define LOG_MARKER_VERBOSE "\x32" /* 50 */ /* * If the log output is too low then this macro is used in place of tf_log() * below. The intent is to get the compiler to evaluate the function call for * type checking and format specifier correctness but let it optimize it out. */ #define no_tf_log(fmt, ...) \ do { \ if (false) { \ tf_log(fmt, ##__VA_ARGS__); \ } \ } while (false) #if LOG_LEVEL >= LOG_LEVEL_ERROR # define ERROR(...) tf_log(LOG_MARKER_ERROR __VA_ARGS__) #else # define ERROR(...) no_tf_log(LOG_MARKER_ERROR __VA_ARGS__) #endif #if LOG_LEVEL >= LOG_LEVEL_NOTICE # define NOTICE(...) tf_log(LOG_MARKER_NOTICE __VA_ARGS__) #else # define NOTICE(...) no_tf_log(LOG_MARKER_NOTICE __VA_ARGS__) #endif #if LOG_LEVEL >= LOG_LEVEL_WARNING # define WARN(...) tf_log(LOG_MARKER_WARNING __VA_ARGS__) #else # define WARN(...) no_tf_log(LOG_MARKER_WARNING __VA_ARGS__) #endif #if LOG_LEVEL >= LOG_LEVEL_INFO # define INFO(...) tf_log(LOG_MARKER_INFO __VA_ARGS__) #else # define INFO(...) no_tf_log(LOG_MARKER_INFO __VA_ARGS__) #endif #if LOG_LEVEL >= LOG_LEVEL_VERBOSE # define VERBOSE(...) tf_log(LOG_MARKER_VERBOSE __VA_ARGS__) #else # define VERBOSE(...) no_tf_log(LOG_MARKER_VERBOSE __VA_ARGS__) #endif #if ENABLE_BACKTRACE void backtrace(const char *cookie); #else #define backtrace(x) #endif void __dead2 do_panic(void); #define panic() \ do { \ backtrace(__func__); \ (void)console_flush(); \ do_panic(); \ } while (false) /* Function called when stack protection check code detects a corrupted stack */ void __dead2 __stack_chk_fail(void); void tf_log(const char *fmt, ...) __printflike(1, 2); void tf_log_set_max_level(unsigned int log_level); #endif /* __ASSEMBLER__ */ #endif /* DEBUG_H */ trusted-firmware-a-2.2/include/common/desc_image_load.h000066400000000000000000000032341355360272700232560ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef DESC_IMAGE_LOAD_H #define DESC_IMAGE_LOAD_H #include /* Following structure is used to store BL ep/image info. */ typedef struct bl_mem_params_node { unsigned int image_id; image_info_t image_info; entry_point_info_t ep_info; unsigned int next_handoff_image_id; bl_load_info_node_t load_node_mem; bl_params_node_t params_node_mem; } bl_mem_params_node_t; extern bl_mem_params_node_t *bl_mem_params_desc_ptr; extern unsigned int bl_mem_params_desc_num; /* * Macro to register list of BL image descriptors, * defined as an array of bl_mem_params_node_t. */ #define REGISTER_BL_IMAGE_DESCS(_img_desc) \ bl_mem_params_node_t *bl_mem_params_desc_ptr = &_img_desc[0]; \ unsigned int bl_mem_params_desc_num = ARRAY_SIZE(_img_desc); /* BL image loading utility functions */ void flush_bl_params_desc(void); void flush_bl_params_desc_args(bl_mem_params_node_t *mem_params_desc_ptr, unsigned int mem_params_desc_num, bl_params_t *next_bl_params_ptr); int get_bl_params_node_index(unsigned int image_id); bl_mem_params_node_t *get_bl_mem_params_node(unsigned int image_id); bl_load_info_t *get_bl_load_info_from_mem_params_desc(void); bl_params_t *get_next_bl_params_from_mem_params_desc(void); void populate_next_bl_params_config(bl_params_t *bl2_to_next_bl_params); /* Helper to extract BL32/BL33 entry point info from arg0 passed to BL31. */ void bl31_params_parse_helper(u_register_t param, entry_point_info_t *bl32_ep_info_out, entry_point_info_t *bl33_ep_info_out); #endif /* DESC_IMAGE_LOAD_H */ trusted-firmware-a-2.2/include/common/ep_info.h000066400000000000000000000031261355360272700216160ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef EP_INFO_H #define EP_INFO_H #include #ifndef __ASSEMBLER__ #include #include #endif /* __ASSEMBLER__ */ #include #define SECURE EP_SECURE #define NON_SECURE EP_NON_SECURE #define sec_state_is_valid(s) (((s) == SECURE) || ((s) == NON_SECURE)) #define PARAM_EP_SECURITY_MASK EP_SECURITY_MASK #define NON_EXECUTABLE EP_NON_EXECUTABLE #define EXECUTABLE EP_EXECUTABLE /* Secure or Non-secure image */ #define GET_SECURITY_STATE(x) ((x) & EP_SECURITY_MASK) #define SET_SECURITY_STATE(x, security) \ ((x) = ((x) & ~EP_SECURITY_MASK) | (security)) #ifndef __ASSEMBLER__ /* * Compile time assertions related to the 'entry_point_info' structure to * ensure that the assembler and the compiler view of the offsets of * the structure members is the same. */ CASSERT(ENTRY_POINT_INFO_PC_OFFSET == __builtin_offsetof(entry_point_info_t, pc), \ assert_BL31_pc_offset_mismatch); #ifndef __aarch64__ CASSERT(ENTRY_POINT_INFO_LR_SVC_OFFSET == __builtin_offsetof(entry_point_info_t, lr_svc), assert_entrypoint_lr_offset_error); #endif CASSERT(ENTRY_POINT_INFO_ARGS_OFFSET == \ __builtin_offsetof(entry_point_info_t, args), \ assert_BL31_args_offset_mismatch); CASSERT(sizeof(uintptr_t) == __builtin_offsetof(entry_point_info_t, spsr) - \ __builtin_offsetof(entry_point_info_t, pc), \ assert_entrypoint_and_spsr_should_be_adjacent); #endif /*__ASSEMBLER__*/ #endif /* EP_INFO_H */ trusted-firmware-a-2.2/include/common/fdt_fixup.h000066400000000000000000000005641355360272700221720ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef FDT_FIXUP_H #define FDT_FIXUP_H int dt_add_psci_node(void *fdt); int dt_add_psci_cpu_enable_methods(void *fdt); int fdt_add_reserved_memory(void *dtb, const char *node_name, uintptr_t base, size_t size); #endif /* FDT_FIXUP_H */ trusted-firmware-a-2.2/include/common/fdt_wrappers.h000066400000000000000000000014201355360272700226720ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* Helper functions to offer easier navigation of Device Tree Blob */ #ifndef FDT_WRAPPERS_H #define FDT_WRAPPERS_H /* Number of cells, given total length in bytes. Each cell is 4 bytes long */ #define NCELLS(len) ((len) / 4U) int fdtw_read_cells(const void *dtb, int node, const char *prop, unsigned int cells, void *value); int fdtw_read_array(const void *dtb, int node, const char *prop, unsigned int cells, void *value); int fdtw_read_string(const void *dtb, int node, const char *prop, char *str, size_t size); int fdtw_write_inplace_cells(void *dtb, int node, const char *prop, unsigned int cells, void *value); #endif /* FDT_WRAPPERS_H */ trusted-firmware-a-2.2/include/common/image_decompress.h000066400000000000000000000011731355360272700235050ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMAGE_DECOMPRESS_H #define IMAGE_DECOMPRESS_H #include #include struct image_info; typedef int (decompressor_t)(uintptr_t *in_buf, size_t in_len, uintptr_t *out_buf, size_t out_len, uintptr_t work_buf, size_t work_len); void image_decompress_init(uintptr_t buf_base, uint32_t buf_size, decompressor_t *decompressor); void image_decompress_prepare(struct image_info *info); int image_decompress(struct image_info *info); #endif /* IMAGE_DECOMPRESS_H */ trusted-firmware-a-2.2/include/common/interrupt_props.h000066400000000000000000000012041355360272700234510ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef INTERRUPT_PROPS_H #define INTERRUPT_PROPS_H #ifndef __ASSEMBLER__ /* Create an interrupt property descriptor from various interrupt properties */ #define INTR_PROP_DESC(num, pri, grp, cfg) \ { \ .intr_num = (num), \ .intr_pri = (pri), \ .intr_grp = (grp), \ .intr_cfg = (cfg), \ } typedef struct interrupt_prop { unsigned int intr_num:10; unsigned int intr_pri:8; unsigned int intr_grp:2; unsigned int intr_cfg:2; } interrupt_prop_t; #endif /* __ASSEMBLER__ */ #endif /* INTERRUPT_PROPS_H */ trusted-firmware-a-2.2/include/common/param_header.h000066400000000000000000000016251355360272700226110ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PARAM_HEADER_H #define PARAM_HEADER_H #include #ifndef __ASSEMBLER__ #include #endif /*__ASSEMBLER__*/ #include #define VERSION_1 PARAM_VERSION_1 #define VERSION_2 PARAM_VERSION_2 #define SET_PARAM_HEAD(_p, _type, _ver, _attr) do { \ (_p)->h.type = (uint8_t)(_type); \ (_p)->h.version = (uint8_t)(_ver); \ (_p)->h.size = (uint16_t)sizeof(*(_p)); \ (_p)->h.attr = (uint32_t)(_attr) ; \ } while (false) /* Following is used for populating structure members statically. */ #define SET_STATIC_PARAM_HEAD(_p, _type, _ver, _p_type, _attr) \ ._p.h.type = (uint8_t)(_type), \ ._p.h.version = (uint8_t)(_ver), \ ._p.h.size = (uint16_t)sizeof(_p_type), \ ._p.h.attr = (uint32_t)(_attr) #endif /* PARAM_HEADER_H */ trusted-firmware-a-2.2/include/common/romlib.h000066400000000000000000000005061355360272700214620ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ROMLIB_H #define ROMLIB_H #define ROMLIB_MAJOR 0 #define ROMLIB_MINOR 1 #define ROMLIB_VERSION ((ROMLIB_MAJOR << 8) | ROMLIB_MINOR) int rom_lib_init(int version); #endif /* ROMLIB_H */ trusted-firmware-a-2.2/include/common/runtime_svc.h000066400000000000000000000107461355360272700225430ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RUNTIME_SVC_H #define RUNTIME_SVC_H #include /* to include exception types */ #include #include #include /* to include SMCCC definitions */ /******************************************************************************* * Structure definition, typedefs & constants for the runtime service framework ******************************************************************************/ /* * Constants to allow the assembler access a runtime service * descriptor */ #ifdef __aarch64__ #define RT_SVC_SIZE_LOG2 U(5) #define RT_SVC_DESC_INIT U(16) #define RT_SVC_DESC_HANDLE U(24) #else #define RT_SVC_SIZE_LOG2 U(4) #define RT_SVC_DESC_INIT U(8) #define RT_SVC_DESC_HANDLE U(12) #endif /* __aarch64__ */ #define SIZEOF_RT_SVC_DESC (U(1) << RT_SVC_SIZE_LOG2) /* * In SMCCC 1.X, the function identifier has 6 bits for the owning entity number * and a single bit for the type of smc call. When taken together, those values * limit the maximum number of runtime services to 128. */ #define MAX_RT_SVCS U(128) #ifndef __ASSEMBLER__ /* Prototype for runtime service initializing function */ typedef int32_t (*rt_svc_init_t)(void); /* * Prototype for runtime service SMC handler function. x0 (SMC Function ID) to * x4 are as passed by the caller. Rest of the arguments to SMC and the context * can be accessed using the handle pointer. The cookie parameter is reserved * for future use */ typedef uintptr_t (*rt_svc_handle_t)(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); typedef struct rt_svc_desc { uint8_t start_oen; uint8_t end_oen; uint8_t call_type; const char *name; rt_svc_init_t init; rt_svc_handle_t handle; } rt_svc_desc_t; /* * Convenience macros to declare a service descriptor */ #define DECLARE_RT_SVC(_name, _start, _end, _type, _setup, _smch) \ static const rt_svc_desc_t __svc_desc_ ## _name \ __section("rt_svc_descs") __used = { \ .start_oen = (_start), \ .end_oen = (_end), \ .call_type = (_type), \ .name = #_name, \ .init = (_setup), \ .handle = (_smch) \ } /* * Compile time assertions related to the 'rt_svc_desc' structure to: * 1. ensure that the assembler and the compiler view of the size * of the structure are the same. * 2. ensure that the assembler and the compiler see the initialisation * routine at the same offset. * 3. ensure that the assembler and the compiler see the handler * routine at the same offset. */ CASSERT((sizeof(rt_svc_desc_t) == SIZEOF_RT_SVC_DESC), \ assert_sizeof_rt_svc_desc_mismatch); CASSERT(RT_SVC_DESC_INIT == __builtin_offsetof(rt_svc_desc_t, init), \ assert_rt_svc_desc_init_offset_mismatch); CASSERT(RT_SVC_DESC_HANDLE == __builtin_offsetof(rt_svc_desc_t, handle), \ assert_rt_svc_desc_handle_offset_mismatch); /* * This function combines the call type and the owning entity number * corresponding to a runtime service to generate a unique owning entity number. * This unique oen is used to access an entry in the 'rt_svc_descs_indices' * array. The entry contains the index of the service descriptor in the * 'rt_svc_descs' array. */ static inline uint32_t get_unique_oen(uint32_t oen, uint32_t call_type) { return ((call_type & FUNCID_TYPE_MASK) << FUNCID_OEN_WIDTH) | (oen & FUNCID_OEN_MASK); } /* * This function generates the unique owning entity number from the SMC Function * ID. This unique oen is used to access an entry in the 'rt_svc_descs_indices' * array to invoke the corresponding runtime service handler during SMC * handling. */ static inline uint32_t get_unique_oen_from_smc_fid(uint32_t fid) { return get_unique_oen(GET_SMC_OEN(fid), GET_SMC_TYPE(fid)); } /******************************************************************************* * Function & variable prototypes ******************************************************************************/ void runtime_svc_init(void); uintptr_t handle_runtime_svc(uint32_t smc_fid, void *cookie, void *handle, unsigned int flags); IMPORT_SYM(uintptr_t, __RT_SVC_DESCS_START__, RT_SVC_DESCS_START); IMPORT_SYM(uintptr_t, __RT_SVC_DESCS_END__, RT_SVC_DESCS_END); void init_crash_reporting(void); extern uint8_t rt_svc_descs_indices[MAX_RT_SVCS]; #endif /*__ASSEMBLER__*/ #endif /* RUNTIME_SVC_H */ trusted-firmware-a-2.2/include/common/tbbr/000077500000000000000000000000001355360272700207555ustar00rootroot00000000000000trusted-firmware-a-2.2/include/common/tbbr/cot_def.h000066400000000000000000000003721355360272700225330ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef COT_DEF_H #define COT_DEF_H /* TBBR CoT definitions */ #define COT_MAX_VERIFIED_PARAMS 4 #endif /* COT_DEF_H */ trusted-firmware-a-2.2/include/common/tbbr/tbbr_img_def.h000066400000000000000000000004001355360272700235230ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TBBR_IMG_DEF_H #define TBBR_IMG_DEF_H #include #endif /* TBBR_IMG_DEF_H */ trusted-firmware-a-2.2/include/drivers/000077500000000000000000000000001355360272700202125ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/allwinner/000077500000000000000000000000001355360272700222055ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/allwinner/sunxi_rsb.h000066400000000000000000000010361355360272700243720ustar00rootroot00000000000000/* * Copyright (c) 2017-2018 ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SUNXI_RSB_H #define SUNXI_RSB_H #include int rsb_init_controller(void); int rsb_set_bus_speed(uint32_t source_freq, uint32_t bus_freq); int rsb_set_device_mode(uint32_t device_mode); int rsb_assign_runtime_address(uint16_t hw_addr, uint8_t rt_addr); int rsb_read(uint8_t rt_addr, uint8_t reg_addr); int rsb_write(uint8_t rt_addr, uint8_t reg_addr, uint8_t value); #endif /* SUNXI_RSB_H */ trusted-firmware-a-2.2/include/drivers/amlogic/000077500000000000000000000000001355360272700216255ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/amlogic/crypto/000077500000000000000000000000001355360272700231455ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/amlogic/crypto/sha_dma.h000066400000000000000000000012131355360272700247070ustar00rootroot00000000000000/* * Copyright (c) 2019, Remi Pommarel * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SHA_DMA_H #define SHA_DMA_H #define SHA256_HASHSZ 32 #define SHA256_BLOCKSZ 0x40 enum ASD_MODE { ASM_INVAL, ASM_SHA256, ASM_SHA224, }; struct asd_ctx { uint8_t digest[SHA256_HASHSZ]; uint8_t block[SHA256_BLOCKSZ]; size_t blocksz; enum ASD_MODE mode; uint8_t started; }; static inline void asd_sha_init(struct asd_ctx *ctx, enum ASD_MODE mode) { ctx->started = 0; ctx->mode = mode; ctx->blocksz = 0; } void asd_sha_update(struct asd_ctx *ctx, void *data, size_t len); void asd_sha_finalize(struct asd_ctx *ctx); #endif trusted-firmware-a-2.2/include/drivers/amlogic/meson_console.h000066400000000000000000000016731355360272700246500ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MESON_CONSOLE_H #define MESON_CONSOLE_H #include #define CONSOLE_T_MESON_BASE CONSOLE_T_DRVDATA #ifndef __ASSEMBLER__ #include typedef struct { console_t console; uintptr_t base; } console_meson_t; /* * Initialize a new meson 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. * * NOTE: The clock is actually fixed to 24 MHz. The argument is only there in * order to make this function future-proof. */ int console_meson_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, console_meson_t *console); #endif /*__ASSEMBLER__*/ #endif /* MESON_CONSOLE_H */ trusted-firmware-a-2.2/include/drivers/arm/000077500000000000000000000000001355360272700207715ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/arm/arm_gicv3_common.h000066400000000000000000000012031355360272700243600ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_GICV3_COMMON_H #define ARM_GICV3_COMMON_H /******************************************************************************* * GIC500/GIC600 Re-distributor interface registers & constants ******************************************************************************/ /* GICR_WAKER implementation-defined bit definitions */ #define WAKER_SL_SHIFT 0 #define WAKER_QSC_SHIFT 31 #define WAKER_SL_BIT (1U << WAKER_SL_SHIFT) #define WAKER_QSC_BIT (1U << WAKER_QSC_SHIFT) #endif /* ARM_GICV3_COMMON_H */ trusted-firmware-a-2.2/include/drivers/arm/cci.h000066400000000000000000000073321355360272700217050ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CCI_H #define CCI_H #include /* Slave interface offsets from PERIPHBASE */ #define SLAVE_IFACE6_OFFSET UL(0x7000) #define SLAVE_IFACE5_OFFSET UL(0x6000) #define SLAVE_IFACE4_OFFSET UL(0x5000) #define SLAVE_IFACE3_OFFSET UL(0x4000) #define SLAVE_IFACE2_OFFSET UL(0x3000) #define SLAVE_IFACE1_OFFSET UL(0x2000) #define SLAVE_IFACE0_OFFSET UL(0x1000) #define SLAVE_IFACE_OFFSET(index) (SLAVE_IFACE0_OFFSET + \ (UL(0x1000) * (index))) /* Slave interface event and count register offsets from PERIPHBASE */ #define EVENT_SELECT7_OFFSET UL(0x80000) #define EVENT_SELECT6_OFFSET UL(0x70000) #define EVENT_SELECT5_OFFSET UL(0x60000) #define EVENT_SELECT4_OFFSET UL(0x50000) #define EVENT_SELECT3_OFFSET UL(0x40000) #define EVENT_SELECT2_OFFSET UL(0x30000) #define EVENT_SELECT1_OFFSET UL(0x20000) #define EVENT_SELECT0_OFFSET UL(0x10000) #define EVENT_OFFSET(index) (EVENT_SELECT0_OFFSET + \ (UL(0x10000) * (index))) /* Control and ID register offsets */ #define CTRL_OVERRIDE_REG U(0x0) #define SECURE_ACCESS_REG U(0x8) #define STATUS_REG U(0xc) #define IMPRECISE_ERR_REG U(0x10) #define PERFMON_CTRL_REG U(0x100) #define IFACE_MON_CTRL_REG U(0x104) /* Component and peripheral ID registers */ #define PERIPHERAL_ID0 U(0xFE0) #define PERIPHERAL_ID1 U(0xFE4) #define PERIPHERAL_ID2 U(0xFE8) #define PERIPHERAL_ID3 U(0xFEC) #define PERIPHERAL_ID4 U(0xFD0) #define PERIPHERAL_ID5 U(0xFD4) #define PERIPHERAL_ID6 U(0xFD8) #define PERIPHERAL_ID7 U(0xFDC) #define COMPONENT_ID0 U(0xFF0) #define COMPONENT_ID1 U(0xFF4) #define COMPONENT_ID2 U(0xFF8) #define COMPONENT_ID3 U(0xFFC) #define COMPONENT_ID4 U(0x1000) #define COMPONENT_ID5 U(0x1004) #define COMPONENT_ID6 U(0x1008) #define COMPONENT_ID7 U(0x100C) /* Slave interface register offsets */ #define SNOOP_CTRL_REG U(0x0) #define SH_OVERRIDE_REG U(0x4) #define READ_CHNL_QOS_VAL_OVERRIDE_REG U(0x100) #define WRITE_CHNL_QOS_VAL_OVERRIDE_REG U(0x104) #define MAX_OT_REG U(0x110) /* Snoop Control register bit definitions */ #define DVM_EN_BIT BIT_32(1) #define SNOOP_EN_BIT BIT_32(0) #define SUPPORT_SNOOPS BIT_32(30) #define SUPPORT_DVM BIT_32(31) /* Status register bit definitions */ #define CHANGE_PENDING_BIT BIT_32(0) /* Event and count register offsets */ #define EVENT_SELECT_REG U(0x0) #define EVENT_COUNT_REG U(0x4) #define COUNT_CNTRL_REG U(0x8) #define COUNT_OVERFLOW_REG U(0xC) /* Slave interface monitor registers */ #define INT_MON_REG_SI0 U(0x90000) #define INT_MON_REG_SI1 U(0x90004) #define INT_MON_REG_SI2 U(0x90008) #define INT_MON_REG_SI3 U(0x9000C) #define INT_MON_REG_SI4 U(0x90010) #define INT_MON_REG_SI5 U(0x90014) #define INT_MON_REG_SI6 U(0x90018) /* Master interface monitor registers */ #define INT_MON_REG_MI0 U(0x90100) #define INT_MON_REG_MI1 U(0x90104) #define INT_MON_REG_MI2 U(0x90108) #define INT_MON_REG_MI3 U(0x9010c) #define INT_MON_REG_MI4 U(0x90110) #define INT_MON_REG_MI5 U(0x90114) #define SLAVE_IF_UNUSED -1 #ifndef __ASSEMBLER__ #include /* Function declarations */ /* * The ARM CCI driver needs the following: * 1. Base address of the CCI product * 2. An array of map between AMBA 4 master ids and ACE/ACE lite slave * interfaces. * 3. Size of the array. * * SLAVE_IF_UNUSED should be used in the map to represent no AMBA 4 master exists * for that interface. */ void cci_init(uintptr_t base, const int *map, unsigned int num_cci_masters); void cci_enable_snoop_dvm_reqs(unsigned int master_id); void cci_disable_snoop_dvm_reqs(unsigned int master_id); #endif /* __ASSEMBLER__ */ #endif /* CCI_H */ trusted-firmware-a-2.2/include/drivers/arm/ccn.h000066400000000000000000000076661355360272700217240ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CCN_H #define CCN_H /* * This macro defines the maximum number of master interfaces that reside on * Request nodes which the CCN driver can accommodate. The driver APIs to add * and remove Request nodes from snoop/dvm domains take a bit map of master * interfaces as inputs. The largest C data type that can be used is a 64-bit * unsigned integer. Hence the value of 64. The platform will have to ensure * that the master interfaces are numbered from 0-63. */ #define CCN_MAX_RN_MASTERS 64 /* * The following constants define the various run modes that the platform can * request the CCN driver to place the L3 cache in. These map to the * programmable P-State values in a HN-F P-state register. */ #define CCN_L3_RUN_MODE_NOL3 0x0 /* HNF_PM_NOL3 */ #define CCN_L3_RUN_MODE_SFONLY 0x1 /* HNF_PM_SFONLY */ #define CCN_L3_RUN_MODE_HAM 0x2 /* HNF_PM_HALF */ #define CCN_L3_RUN_MODE_FAM 0x3 /* HNF_PM_FULL */ /* part 0 IDs for various CCN variants */ #define CCN_502_PART0_ID 0x30 #define CCN_504_PART0_ID 0x26 #define CCN_505_PART0_ID 0x27 #define CCN_508_PART0_ID 0x28 #define CCN_512_PART0_ID 0x29 /* * The following macro takes the value returned from a read of a HN-F P-state * status register and returns the retention state value. */ #define CCN_GET_RETENTION_STATE(pstate) ((pstate >> 4) & 0x3) /* * The following macro takes the value returned from a read of a HN-F P-state * status register and returns the run state value. */ #define CCN_GET_RUN_STATE(pstate) (pstate & 0xf) #ifndef __ASSEMBLER__ #include /* * This structure describes some of the implementation defined attributes of the * CCN IP. It is used by the platform port to specify these attributes in order * to initialise the CCN driver. The attributes are described below. * * 1. The 'num_masters' field specifies the total number of master interfaces * resident on Request nodes. * * 2. The 'master_to_rn_id_map' field is a ponter to an array in which each * index corresponds to a master interface and its value corresponds to the * Request node on which the master interface resides. * This field is not simply defined as an array of size CCN_MAX_RN_MASTERS. * In reality, a platform will have much fewer master * interfaces than * CCN_MAX_RN_MASTERS. With an array of this size, it would also have to * set the unused entries to a suitable value. Zeroing the array would not * be enough since 0 is also a valid node id. Hence, such an array is not * used. * * 3. The 'periphbase' field is the base address of the programmer's view of the * CCN IP. */ typedef struct ccn_desc { unsigned int num_masters; const unsigned char *master_to_rn_id_map; uintptr_t periphbase; } ccn_desc_t; /* Enum used to loop through all types of nodes in CCN*/ typedef enum node_types { NODE_TYPE_RNF = 0, NODE_TYPE_RNI, NODE_TYPE_RND, NODE_TYPE_HNF, NODE_TYPE_HNI, NODE_TYPE_SN, NUM_NODE_TYPES } node_types_t; void ccn_init(const ccn_desc_t *plat_ccn_desc); void ccn_enter_snoop_dvm_domain(unsigned long long master_iface_map); void ccn_exit_snoop_dvm_domain(unsigned long long master_iface_map); void ccn_enter_dvm_domain(unsigned long long master_iface_map); void ccn_exit_dvm_domain(unsigned long long master_iface_map); void ccn_set_l3_run_mode(unsigned int mode); void ccn_program_sys_addrmap(unsigned int sn0_id, unsigned int sn1_id, unsigned int sn2_id, unsigned int top_addr_bit0, unsigned int top_addr_bit1, unsigned char three_sn_en); unsigned int ccn_get_l3_run_mode(void); int ccn_get_part0_id(uintptr_t periphbase); void ccn_write_node_reg(node_types_t node_type, unsigned int node_id, unsigned int reg_offset, unsigned long long val); unsigned long long ccn_read_node_reg(node_types_t node_type, unsigned int node_id, unsigned int reg_offset); #endif /* __ASSEMBLER__ */ #endif /* CCN_H */ trusted-firmware-a-2.2/include/drivers/arm/cryptocell/000077500000000000000000000000001355360272700231515ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/arm/cryptocell/712/000077500000000000000000000000001355360272700234625ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/arm/cryptocell/712/cc_crypto_boot_defs.h000066400000000000000000000016771355360272700276570ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _CC_CRYPTO_BOOT_DEFS_H #define _CC_CRYPTO_BOOT_DEFS_H /*! @file @brief This file contains SBROM definitions */ /*! Version counters value. */ typedef enum { CC_SW_VERSION_COUNTER1 = 1, /*!< Counter 1 - trusted version. */ CC_SW_VERSION_COUNTER2, /*!< Counter 2 - non trusted version. */ CC_SW_VERSION_MAX = 0x7FFFFFFF } CCSbSwVersionId_t; /* HASH boot key definition */ typedef enum { CC_SB_HASH_BOOT_KEY_0_128B = 0, /*!< 128-bit truncated SHA256 digest of public key 0. */ CC_SB_HASH_BOOT_KEY_1_128B = 1, /*!< 128-bit truncated SHA256 digest of public key 1. */ CC_SB_HASH_BOOT_KEY_256B = 2, /*!< 256-bit SHA256 digest of public key. */ CC_SB_HASH_BOOT_NOT_USED = 0xFF, CC_SB_HASH_MAX_NUM = 0x7FFFFFFF, /*!\internal use external 128-bit truncated SHA256 digest */ } CCSbPubKeyIndexType_t; #endif trusted-firmware-a-2.2/include/drivers/arm/cryptocell/712/cc_pal_sb_plat.h000066400000000000000000000012031355360272700265540ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /*! @file @brief This file contains the platform-dependent definitions that are used in the SBROM code. */ #ifndef _CC_PAL_SB_PLAT_H #define _CC_PAL_SB_PLAT_H #include "cc_pal_types.h" #ifdef __cplusplus extern "C" { #endif /*! Definition of DMA address type, can be 32 bits or 64 bits according to CryptoCell's HW. */ typedef uint64_t CCDmaAddr_t; /*! Definition of CryptoCell address type, can be 32 bits or 64 bits according to platform. */ typedef uintptr_t CCAddr_t; #ifdef __cplusplus } #endif #endif trusted-firmware-a-2.2/include/drivers/arm/cryptocell/712/cc_pal_types.h000066400000000000000000000016621355360272700263050ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CC_PAL_TYPES_H #define CC_PAL_TYPES_H /*! @file @brief This file contains platform-dependent definitions and types. */ #include "cc_pal_types_plat.h" typedef enum { CC_FALSE = 0, CC_TRUE = 1 } CCBool; #define CC_SUCCESS 0UL #define CC_FAIL 1UL #define CC_1K_SIZE_IN_BYTES 1024 #define CC_BITS_IN_BYTE 8 #define CC_BITS_IN_32BIT_WORD 32 #define CC_32BIT_WORD_SIZE (sizeof(uint32_t)) #define CC_OK CC_SUCCESS #define CC_UNUSED_PARAM(prm) ((void)prm) #define CC_MAX_UINT32_VAL (0xFFFFFFFF) #define CALC_FULL_BYTES(numBits) (((numBits) + (CC_BITS_IN_BYTE - 1))/CC_BITS_IN_BYTE) #define CALC_FULL_32BIT_WORDS(numBits) (((numBits) + (CC_BITS_IN_32BIT_WORD - 1))/CC_BITS_IN_32BIT_WRD) #define CALC_32BIT_WORDS_FROM_BYTES(sizeBytes) (((sizeBytes) + CC_32BIT_WORD_SIZE - 1)/CC_32BIT_WORD_SIZE) #endif trusted-firmware-a-2.2/include/drivers/arm/cryptocell/712/cc_pal_types_plat.h000066400000000000000000000010361355360272700273200ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /*! @file @brief This file contains basic type definitions that are platform-dependent. */ #ifndef _CC_PAL_TYPES_PLAT_H #define _CC_PAL_TYPES_PLAT_H /* Host specific types for standard (ISO-C99) compilant platforms */ #include #include typedef uint32_t CCStatus; #define CCError_t CCStatus #define CC_INFINITE 0xFFFFFFFF #define CEXPORT_C #define CIMPORT_C #endif /*_CC_PAL_TYPES_PLAT_H*/ trusted-firmware-a-2.2/include/drivers/arm/cryptocell/712/cc_sec_defs.h000066400000000000000000000012111355360272700260460ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _CC_SEC_DEFS_H #define _CC_SEC_DEFS_H /*! @file @brief This file contains general hash definitions and types. */ #ifdef __cplusplus extern "C" { #endif /*! The hashblock size in words. */ #define HASH_BLOCK_SIZE_IN_WORDS 16 /*! The hash - SHA2 results in words. */ #define HASH_RESULT_SIZE_IN_WORDS 8 #define HASH_RESULT_SIZE_IN_BYTES 32 /*! Definition for hash result array. */ typedef uint32_t CCHashResult_t[HASH_RESULT_SIZE_IN_WORDS]; #ifdef __cplusplus } #endif #endif trusted-firmware-a-2.2/include/drivers/arm/cryptocell/712/crypto_driver.h000066400000000000000000000013131355360272700265240ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _CRYPTO_DRIVER_H #define _CRYPTO_DRIVER_H #ifdef __cplusplus extern "C" { #endif #include "cc_pal_sb_plat.h" #include "cc_sec_defs.h" /*---------------------------- PUBLIC FUNCTIONS -----------------------------------*/ /*! * @brief This function gives the functionality of integrated hash * * @param[in] hwBaseAddress - CryptoCell base address * @param[out] hashResult - the HASH result. * */ CCError_t SBROM_CryptoHash(unsigned long hwBaseAddress, CCDmaAddr_t inputDataAddr, uint32_t BlockSize, CCHashResult_t hashResult); #ifdef __cplusplus } #endif #endif trusted-firmware-a-2.2/include/drivers/arm/cryptocell/712/nvm.h000066400000000000000000000026441355360272700244410ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _NVM__H #define _NVM__H #ifdef __cplusplus extern "C" { #endif #include "cc_crypto_boot_defs.h" #include "cc_pal_types.h" #include "cc_sec_defs.h" /*------------------------------------ DEFINES -------------------------------------*/ /** * @brief This function reads the LCS from the SRAM/NVM * * @param[in] hwBaseAddress - CryptoCell base address * * @param[in/out] lcs_ptr - pointer to memory to store the LCS * * @return CCError_t - On success the value CC_OK is returned, and on failure -a value from NVM_error.h */ CCError_t NVM_GetLCS(unsigned long hwBaseAddress, uint32_t *lcs_ptr); /** * @brief The NVM_ReadHASHPubKey function is a NVM interface function - * The function retrieves the HASH of the device Public key from the SRAM/NVM * * @param[in] hwBaseAddress - CryptoCell base address * * @param[in] pubKeyIndex - Index of HASH in the OTP * * @param[out] PubKeyHASH - the public key HASH. * * @param[in] hashSizeInWords - hash size (valid values: 4W, 8W) * * @return CCError_t - On success the value CC_OK is returned, and on failure -a value from NVM_error.h */ CCError_t NVM_ReadHASHPubKey(unsigned long hwBaseAddress, CCSbPubKeyIndexType_t pubKeyIndex, CCHashResult_t PubKeyHASH, uint32_t hashSizeInWords); #ifdef __cplusplus } #endif #endif trusted-firmware-a-2.2/include/drivers/arm/cryptocell/712/nvm_otp.h000066400000000000000000000032231355360272700253150ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _NVM_OTP_H #define _NVM_OTP_H #ifdef __cplusplus extern "C" { #endif #include "cc_crypto_boot_defs.h" #include "cc_pal_types.h" /*------------------------------------ DEFINES -------------------------------------*/ /** * @brief The NVM_GetSwVersion function is a NVM interface function - * The function retrieves the SW version from the SRAM/NVM. * In case of OTP, we support up to 16 anti-rollback counters (taken from the certificate) * * @param[in] hwBaseAddress - CryptoCell base address * * @param[in] counterId - relevant only for OTP (valid values: 1,2) * * @param[out] swVersion - the minimum SW version * * @return CCError_t - On success the value CC_OK is returned, and on failure -a value from NVM_error.h */ CCError_t NVM_GetSwVersion(unsigned long hwBaseAddress, CCSbSwVersionId_t counterId, uint32_t *swVersion); /** * @brief The NVM_SetSwVersion function is a NVM interface function - * The function writes the SW version into the SRAM/NVM. * In case of OTP, we support up to 16 anti-rollback counters (taken from the certificate) * * @param[in] hwBaseAddress - CryptoCell base address * * @param[in] counterId - relevant only for OTP (valid values: 1,2) * * @param[in] swVersion - the minimum SW version * * @return CCError_t - On success the value CC_OK is returned, and on failure -a value from NVM_error.h */ CCError_t NVM_SetSwVersion(unsigned long hwBaseAddress, CCSbSwVersionId_t counterId, uint32_t swVersion); #ifdef __cplusplus } #endif #endif trusted-firmware-a-2.2/include/drivers/arm/cryptocell/712/rsa.h000066400000000000000000000031431355360272700244210ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RSA_H #define RSA_H /* * All the includes that are needed for code using this module to * compile correctly should be #included here. */ #ifdef __cplusplus extern "C" { #endif #include "cc_pal_types.h" /************************ Defines ******************************/ /* the modulus size ion bits */ #define RSA_MOD_SIZE_IN_BITS 2048UL #define RSA_MOD_SIZE_IN_BYTES (CALC_FULL_BYTES(RSA_MOD_SIZE_IN_BITS)) #define RSA_MOD_SIZE_IN_WORDS (CALC_FULL_32BIT_WORDS(RSA_MOD_SIZE_IN_BITS)) #define RSA_MOD_SIZE_IN_256BITS (RSA_MOD_SIZE_IN_WORDS/8) #define RSA_EXP_SIZE_IN_BITS 17UL #define RSA_EXP_SIZE_IN_BYTES (CALC_FULL_BYTES(RSA_EXP_SIZE_IN_BITS)) /* size of buffer for Barrett modulus tag NP, used in PKA algorithms */ #define RSA_HW_PKI_PKA_BARRETT_MOD_TAG_SIZE_IN_BITS 132 #define RSA_HW_PKI_PKA_BARRETT_MOD_TAG_SIZE_IN_BYTES (CALC_FULL_BYTES(RSA_HW_PKI_PKA_BARRETT_MOD_TAG_SIZE_IN_BITS)) #define RSA_HW_PKI_PKA_BARRETT_MOD_TAG_SIZE_IN_WORDS (CALC_FULL_32BIT_WORDS(RSA_HW_PKI_PKA_BARRETT_MOD_TAG_SIZE_IN_BITS)) /* * @brief The RSA_CalcNp calculates Np value and saves it into Np_ptr: * * * @param[in] hwBaseAddress - HW base address. Relevant for HW * implementation, for SW it is ignored. * @N_ptr[in] - The pointer to the modulus buffer. * @Np_ptr[out] - pointer to Np vector buffer. Its size must be >= 160. */ void RSA_CalcNp(unsigned long hwBaseAddress, uint32_t *N_ptr, uint32_t *Np_ptr); #ifdef __cplusplus } #endif #endif trusted-firmware-a-2.2/include/drivers/arm/cryptocell/712/sbrom_bsv_api.h000066400000000000000000000040361355360272700264630ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _SBROM_BSV_API_H #define _SBROM_BSV_API_H #ifdef __cplusplus extern "C" { #endif /*! @file @brief This file contains all SBROM library APIs and definitions. */ #include "cc_pal_types.h" /* Life cycle state definitions */ #define CC_BSV_CHIP_MANUFACTURE_LCS 0x0 /*!< CM lifecycle value. */ #define CC_BSV_DEVICE_MANUFACTURE_LCS 0x1 /*!< DM lifecycle value. */ #define CC_BSV_SECURITY_DISABLED_LCS 0x3 /*!< SD lifecycle value. */ #define CC_BSV_SECURE_LCS 0x5 /*!< Secure lifecycle value. */ #define CC_BSV_RMA_LCS 0x7 /*!< RMA lifecycle value. */ /*---------------------------- PUBLIC FUNCTIONS -----------------------------------*/ /*! @brief This function should be the first ARM TrustZone CryptoCell TEE SBROM library API called. It verifies the HW product and version numbers. @return CC_OK On success. @return A non-zero value from sbrom_bsv_error.h on failure. */ CCError_t CC_BsvSbromInit( unsigned long hwBaseAddress /*!< [in] HW registers base address. */ ); /*! @brief This function can be used for checking the LCS value, after CC_BsvLcsGetAndInit was called by the Boot ROM. @return CC_OK On success. @return A non-zero value from sbrom_bsv_error.h on failure. */ CCError_t CC_BsvLcsGet( unsigned long hwBaseAddress, /*!< [in] HW registers base address. */ uint32_t *pLcs /*!< [out] Returned lifecycle state. */ ); /*! @brief This function retrieves the HW security lifecycle state, performs validity checks, and additional initializations in case the LCS is RMA (sets the Kce to fixed value). \note Invalid LCS results in an error returned. In this case, the customer's code must completely disable the device. @return CC_OK On success. @return A non-zero value from sbrom_bsv_error.h on failure. */ CCError_t CC_BsvLcsGetAndInit( unsigned long hwBaseAddress, /*!< [in] HW registers base address. */ uint32_t *pLcs /*!< [out] Returned lifecycle state. */ ); #ifdef __cplusplus } #endif #endif trusted-firmware-a-2.2/include/drivers/arm/cryptocell/712/secureboot_base_func.h000066400000000000000000000023271355360272700300160ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _SECURE_BOOT_BASE_FUNC_H #define _SECURE_BOOT_BASE_FUNC_H #ifdef __cplusplus extern "C" { #endif #include "cc_pal_types.h" #include "secureboot_gen_defs.h" /*---------------------------- PUBLIC FUNCTIONS -----------------------------------*/ /** * @brief This function calculates the HASH over the given data and than verify * RSA signature on that hashed data * * @param[in] hwBaseAddr - CryptoCell base address * @param[in] pData - pointer to the data to be verified * @param[in] pNParams - a pointer to the public key parameters * @param[in] pSignature - a pointer to the signature structure * @param[in] sizeOfData - size of the data to calculate the HASH on (in bytes) * @param[in] RSAAlg - RSA algorithm to use * * @return CCError_t - On success the value CC_OK is returned, * on failure - a value from BootImagesVerifier_error.h */ CCError_t CCSbVerifySignature(unsigned long hwBaseAddress, uint32_t *pData, CCSbNParams_t *pNParams, CCSbSignature_t *pSignature, uint32_t sizeOfData, CCSbRsaAlg_t RSAAlg); #ifdef __cplusplus } #endif #endif trusted-firmware-a-2.2/include/drivers/arm/cryptocell/712/secureboot_gen_defs.h000066400000000000000000000024021355360272700276350ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _SECURE_BOOT_GEN_DEFS_H #define _SECURE_BOOT_GEN_DEFS_H #ifdef __cplusplus extern "C" { #endif /*! @file @brief This file contains all of the definitions and structures that are used for the secure boot. */ #include "cc_pal_sb_plat.h" #include "cc_sec_defs.h" /* General definitions */ /***********************/ /*RSA definitions*/ #define SB_RSA_MOD_SIZE_IN_WORDS 64 #define SB_RSA_HW_PKI_PKA_BARRETT_MOD_TAG_SIZE_IN_WORDS 5 /*! Public key data structure. */ typedef struct { uint32_t N[SB_RSA_MOD_SIZE_IN_WORDS]; /*!< N public key, big endian representation. */ uint32_t Np[SB_RSA_HW_PKI_PKA_BARRETT_MOD_TAG_SIZE_IN_WORDS]; /*!< Np (Barrett n' value). */ } CCSbNParams_t; /*! Signature structure. */ typedef struct { uint32_t sig[SB_RSA_MOD_SIZE_IN_WORDS]; /*!< RSA PSS signature. */ } CCSbSignature_t; /********* Supported algorithms definitions ***********/ /*! RSA supported algorithms */ typedef enum { RSA_PSS_2048 = 0x01, /*!< RSA PSS 2048 after hash SHA 256 */ RSA_PKCS15_2048 = 0x02, /*!< RSA PKX15 */ RSA_Last = 0x7FFFFFFF } CCSbRsaAlg_t; #ifdef __cplusplus } #endif #endif trusted-firmware-a-2.2/include/drivers/arm/cryptocell/712/util.h000066400000000000000000000035031355360272700246110ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef UTIL_H #define UTIL_H /* * All the includes that are needed for code using this module to * compile correctly should be #included here. */ #ifdef __cplusplus extern "C" { #endif /************************ Defines ******************************/ /* invers the bytes on a word- used for output from HASH */ #ifdef BIG__ENDIAN #define UTIL_INVERSE_UINT32_BYTES(val) (val) #else #define UTIL_INVERSE_UINT32_BYTES(val) \ (((val) >> 24) | (((val) & 0x00FF0000) >> 8) | (((val) & 0x0000FF00) << 8) | (((val) & 0x000000FF) << 24)) #endif /* invers the bytes on a word - used for input data for HASH */ #ifdef BIG__ENDIAN #define UTIL_REVERT_UINT32_BYTES(val) \ (((val) >> 24) | (((val) & 0x00FF0000) >> 8) | (((val) & 0x0000FF00) << 8) | (((val) & 0x000000FF) << 24)) #else #define UTIL_REVERT_UINT32_BYTES(val) (val) #endif /* ------------------------------------------------------------ ** * @brief This function executes a reverse bytes copying from one buffer to another buffer. * * @param[in] dst_ptr - The pointer to destination buffer. * @param[in] src_ptr - The pointer to source buffer. * @param[in] size - The size in bytes. * */ void UTIL_ReverseMemCopy(uint8_t *dst_ptr, uint8_t *src_ptr, uint32_t size); /* ------------------------------------------------------------ ** * @brief This function executes a reversed byte copy on a specified buffer. * * on a 6 byte byffer: * * buff[5] <---> buff[0] * buff[4] <---> buff[1] * buff[3] <---> buff[2] * * @param[in] dst_ptr - The counter buffer. * @param[in] src_ptr - The counter size in bytes. * */ void UTIL_ReverseBuff(uint8_t *buff_ptr, uint32_t size); #ifdef __cplusplus } #endif #endif trusted-firmware-a-2.2/include/drivers/arm/cryptocell/cc_rotpk.h000066400000000000000000000004111355360272700251220ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _CC_ROTPK_H #define _CC_ROTPK_H int cc_get_rotpk_hash(unsigned char *dst, unsigned int len, unsigned int *flags); #endif trusted-firmware-a-2.2/include/drivers/arm/css/000077500000000000000000000000001355360272700215615ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/arm/css/css_mhu.h000066400000000000000000000006661355360272700234030ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CSS_MHU_H #define CSS_MHU_H #include void mhu_secure_message_start(unsigned int slot_id); void mhu_secure_message_send(unsigned int slot_id); uint32_t mhu_secure_message_wait(void); void mhu_secure_message_end(unsigned int slot_id); void mhu_secure_init(void); #endif /* CSS_MHU_H */ trusted-firmware-a-2.2/include/drivers/arm/css/css_mhu_doorbell.h000066400000000000000000000023751355360272700252640ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CSS_MHU_DOORBELL_H #define CSS_MHU_DOORBELL_H #include #include /* MHUv2 Base Address */ #define MHUV2_BASE_ADDR PLAT_MHUV2_BASE /* MHUv2 Control Registers Offsets */ #define MHU_V2_MSG_NO_CAP_OFFSET 0xF80 #define MHU_V2_ACCESS_REQ_OFFSET 0xF88 #define MHU_V2_ACCESS_READY_OFFSET 0xF8C #define SENDER_REG_STAT(_channel) (0x20 * (_channel)) #define SENDER_REG_SET(_channel) ((0x20 * (_channel)) + 0xC) /* Helper macro to ring doorbell */ #define MHU_RING_DOORBELL(addr, modify_mask, preserve_mask) do { \ uint32_t db = mmio_read_32(addr) & (preserve_mask); \ mmio_write_32(addr, db | (modify_mask)); \ } while (0) #define MHU_V2_ACCESS_REQUEST(addr) \ mmio_write_32((addr) + MHU_V2_ACCESS_REQ_OFFSET, 0x1) #define MHU_V2_CLEAR_REQUEST(addr) \ mmio_write_32((addr) + MHU_V2_ACCESS_REQ_OFFSET, 0x0) #define MHU_V2_IS_ACCESS_READY(addr) \ (mmio_read_32((addr) + MHU_V2_ACCESS_READY_OFFSET) & 0x1) struct scmi_channel_plat_info; void mhu_ring_doorbell(struct scmi_channel_plat_info *plat_info); void mhuv2_ring_doorbell(struct scmi_channel_plat_info *plat_info); #endif /* CSS_MHU_DOORBELL_H */ trusted-firmware-a-2.2/include/drivers/arm/css/css_scp.h000066400000000000000000000030701355360272700233670ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CSS_SCP_H #define CSS_SCP_H #include #include #include /* Forward declarations */ struct psci_power_state; /* API for power management by SCP */ int css_system_reset2(int is_vendor, int reset_type, u_register_t cookie); void css_scp_suspend(const struct psci_power_state *target_state); void css_scp_off(const struct psci_power_state *target_state); void css_scp_on(u_register_t mpidr); int css_scp_get_power_state(u_register_t mpidr, unsigned int power_level); void __dead2 css_scp_sys_shutdown(void); void __dead2 css_scp_sys_reboot(void); void __dead2 css_scp_system_off(int state); /* API for SCP Boot Image transfer. Return 0 on success, -1 on error */ int css_scp_boot_image_xfer(void *image, unsigned int image_size); /* * API to wait for SCP to signal till it's ready after booting the transferred * image. */ int css_scp_boot_ready(void); #if CSS_LOAD_SCP_IMAGES /* * All CSS platforms load SCP_BL2/SCP_BL2U just below BL2 (this is where BL31 * usually resides except when ARM_BL31_IN_DRAM is * set). Ensure that SCP_BL2/SCP_BL2U do not overflow into tb_fw_config. */ CASSERT(SCP_BL2_LIMIT <= BL2_BASE, assert_scp_bl2_overwrite_bl2); CASSERT(SCP_BL2U_LIMIT <= BL2_BASE, assert_scp_bl2u_overwrite_bl2); CASSERT(SCP_BL2_BASE >= ARM_TB_FW_CONFIG_LIMIT, assert_scp_bl2_overflow); CASSERT(SCP_BL2U_BASE >= ARM_TB_FW_CONFIG_LIMIT, assert_scp_bl2u_overflow); #endif #endif /* CSS_SCP_H */ trusted-firmware-a-2.2/include/drivers/arm/css/css_scpi.h000066400000000000000000000060641355360272700235460ustar00rootroot00000000000000/* * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CSS_SCPI_H #define CSS_SCPI_H #include #include /* * An SCPI command consists of a header and a payload. * The following structure describes the header. It is 64-bit long. */ typedef struct { /* Command ID */ uint32_t id : 7; /* Set ID. Identifies whether this is a standard or extended command. */ uint32_t set : 1; /* Sender ID to match a reply. The value is sender specific. */ uint32_t sender : 8; /* Size of the payload in bytes (0 - 511) */ uint32_t size : 9; uint32_t reserved : 7; /* * Status indicating the success of a command. * See the enum below. */ uint32_t status; } scpi_cmd_t; typedef enum { SCPI_SET_NORMAL = 0, /* Normal SCPI commands */ SCPI_SET_EXTENDED /* Extended SCPI commands */ } scpi_set_t; enum { SCP_OK = 0, /* Success */ SCP_E_PARAM, /* Invalid parameter(s) */ SCP_E_ALIGN, /* Invalid alignment */ SCP_E_SIZE, /* Invalid size */ SCP_E_HANDLER, /* Invalid handler or callback */ SCP_E_ACCESS, /* Invalid access or permission denied */ SCP_E_RANGE, /* Value out of range */ SCP_E_TIMEOUT, /* Time out has ocurred */ SCP_E_NOMEM, /* Invalid memory area or pointer */ SCP_E_PWRSTATE, /* Invalid power state */ SCP_E_SUPPORT, /* Feature not supported or disabled */ SCPI_E_DEVICE, /* Device error */ SCPI_E_BUSY, /* Device is busy */ }; typedef uint32_t scpi_status_t; typedef enum { SCPI_CMD_SCP_READY = 0x01, SCPI_CMD_SET_CSS_POWER_STATE = 0x03, SCPI_CMD_GET_CSS_POWER_STATE = 0x04, SCPI_CMD_SYS_POWER_STATE = 0x05 } scpi_command_t; /* * Macros to parse SCP response to GET_CSS_POWER_STATE command * * [3:0] : cluster ID * [7:4] : cluster state: 0 = on; 3 = off; rest are reserved * [15:8]: on/off state for individual CPUs in the cluster * * Payload is in little-endian */ #define CLUSTER_ID(_resp) ((_resp) & 0xf) #define CLUSTER_POWER_STATE(_resp) (((_resp) >> 4) & 0xf) /* Result is a bit mask of CPU on/off states in the cluster */ #define CPU_POWER_STATE(_resp) (((_resp) >> 8) & 0xff) /* * For GET_CSS_POWER_STATE, SCP returns the power states of every cluster. The * size of response depends on the number of clusters in the system. The * SCP-to-AP payload contains 2 bytes per cluster. Make sure the response is * large enough to contain power states of a given cluster */ #define CHECK_RESPONSE(_resp, _clus) \ (_resp.size >= (((_clus) + 1) * 2)) typedef enum { scpi_power_on = 0, scpi_power_retention = 1, scpi_power_off = 3, } scpi_power_state_t; typedef enum { scpi_system_shutdown = 0, scpi_system_reboot = 1, scpi_system_reset = 2 } scpi_system_state_t; int scpi_wait_ready(void); void scpi_set_css_power_state(unsigned int mpidr, scpi_power_state_t cpu_state, scpi_power_state_t cluster_state, scpi_power_state_t css_state); int scpi_get_css_power_state(unsigned int mpidr, unsigned int *cpu_state_p, unsigned int *cluster_state_p); uint32_t scpi_sys_power_state(scpi_system_state_t system_state); #endif /* CSS_SCPI_H */ trusted-firmware-a-2.2/include/drivers/arm/css/scmi.h000066400000000000000000000127211355360272700226700ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SCMI_H #define SCMI_H #include #include #include #include #include /* Supported SCMI Protocol Versions */ #define SCMI_AP_CORE_PROTO_VER MAKE_SCMI_VERSION(1, 0) #define SCMI_PWR_DMN_PROTO_VER MAKE_SCMI_VERSION(1, 0) #define SCMI_SYS_PWR_PROTO_VER MAKE_SCMI_VERSION(1, 0) #define GET_SCMI_MAJOR_VER(ver) (((ver) >> 16) & 0xffff) #define GET_SCMI_MINOR_VER(ver) ((ver) & 0xffff) #define MAKE_SCMI_VERSION(maj, min) \ ((((maj) & 0xffff) << 16) | ((min) & 0xffff)) /* Macro to check if the driver is compatible with the SCMI version reported */ #define is_scmi_version_compatible(drv, scmi) \ ((GET_SCMI_MAJOR_VER(drv) == GET_SCMI_MAJOR_VER(scmi)) && \ (GET_SCMI_MINOR_VER(drv) <= GET_SCMI_MINOR_VER(scmi))) /* SCMI Protocol identifiers */ #define SCMI_PWR_DMN_PROTO_ID 0x11 #define SCMI_SYS_PWR_PROTO_ID 0x12 /* The AP core protocol is a CSS platform-specific extension */ #define SCMI_AP_CORE_PROTO_ID 0x90 /* Mandatory messages IDs for all SCMI protocols */ #define SCMI_PROTO_VERSION_MSG 0x0 #define SCMI_PROTO_ATTR_MSG 0x1 #define SCMI_PROTO_MSG_ATTR_MSG 0x2 /* SCMI power domain management protocol message IDs */ #define SCMI_PWR_STATE_SET_MSG 0x4 #define SCMI_PWR_STATE_GET_MSG 0x5 /* SCMI system power management protocol message IDs */ #define SCMI_SYS_PWR_STATE_SET_MSG 0x3 #define SCMI_SYS_PWR_STATE_GET_MSG 0x4 /* SCMI AP core protocol message IDs */ #define SCMI_AP_CORE_RESET_ADDR_SET_MSG 0x3 #define SCMI_AP_CORE_RESET_ADDR_GET_MSG 0x4 /* Helper macros for system power management protocol commands */ /* * Macros to describe the bit-fields of the `attribute` of system power domain * protocol PROTOCOL_MSG_ATTRIBUTE message. */ #define SYS_PWR_ATTR_WARM_RESET_SHIFT 31 #define SCMI_SYS_PWR_WARM_RESET_SUPPORTED (1U << SYS_PWR_ATTR_WARM_RESET_SHIFT) #define SYS_PWR_ATTR_SUSPEND_SHIFT 30 #define SCMI_SYS_PWR_SUSPEND_SUPPORTED (1 << SYS_PWR_ATTR_SUSPEND_SHIFT) /* * Macros to describe the bit-fields of the `flags` parameter of system power * domain protocol SYSTEM_POWER_STATE_SET message. */ #define SYS_PWR_SET_GRACEFUL_REQ_SHIFT 0 #define SCMI_SYS_PWR_GRACEFUL_REQ (1 << SYS_PWR_SET_GRACEFUL_REQ_SHIFT) #define SCMI_SYS_PWR_FORCEFUL_REQ (0 << SYS_PWR_SET_GRACEFUL_REQ_SHIFT) /* * Macros to describe the `system_state` parameter of system power * domain protocol SYSTEM_POWER_STATE_SET message. */ #define SCMI_SYS_PWR_SHUTDOWN 0x0 #define SCMI_SYS_PWR_COLD_RESET 0x1 #define SCMI_SYS_PWR_WARM_RESET 0x2 #define SCMI_SYS_PWR_POWER_UP 0x3 #define SCMI_SYS_PWR_SUSPEND 0x4 /* * Macros to describe the bit-fields of the `attribute` of AP core protocol * AP_CORE_RESET_ADDR set/get messages. */ #define SCMI_AP_CORE_LOCK_ATTR_SHIFT 0x0 #define SCMI_AP_CORE_LOCK_ATTR (1U << SCMI_AP_CORE_LOCK_ATTR_SHIFT) /* SCMI Error code definitions */ #define SCMI_E_QUEUED 1 #define SCMI_E_SUCCESS 0 #define SCMI_E_NOT_SUPPORTED -1 #define SCMI_E_INVALID_PARAM -2 #define SCMI_E_DENIED -3 #define SCMI_E_NOT_FOUND -4 #define SCMI_E_OUT_OF_RANGE -5 #define SCMI_E_BUSY -6 /* * SCMI driver platform information. The details of the doorbell mechanism * can be found in the SCMI specification. */ typedef struct scmi_channel_plat_info { /* SCMI mailbox memory */ uintptr_t scmi_mbx_mem; /* The door bell register address */ uintptr_t db_reg_addr; /* The bit mask that need to be preserved when ringing doorbell */ uint32_t db_preserve_mask; /* The bit mask that need to be set to ring doorbell */ uint32_t db_modify_mask; /* The handler for ringing doorbell */ void (*ring_doorbell)(struct scmi_channel_plat_info *plat_info); /* cookie is unused now. But added for future enhancements. */ void *cookie; } scmi_channel_plat_info_t; #if HW_ASSISTED_COHERENCY typedef spinlock_t scmi_lock_t; #else typedef bakery_lock_t scmi_lock_t; #endif /* * Structure to represent an SCMI channel. */ typedef struct scmi_channel { scmi_channel_plat_info_t *info; /* The lock for channel access */ scmi_lock_t *lock; /* Indicate whether the channel is initialized */ int is_initialized; } scmi_channel_t; /* External Common API */ void *scmi_init(scmi_channel_t *ch); int scmi_proto_msg_attr(void *p, uint32_t proto_id, uint32_t command_id, uint32_t *attr); int scmi_proto_version(void *p, uint32_t proto_id, uint32_t *version); /* * Power domain protocol commands. Refer to the SCMI specification for more * details on these commands. */ int scmi_pwr_state_set(void *p, uint32_t domain_id, uint32_t scmi_pwr_state); int scmi_pwr_state_get(void *p, uint32_t domain_id, uint32_t *scmi_pwr_state); /* * System power management protocol commands. Refer SCMI specification for more * details on these commands. */ int scmi_sys_pwr_state_set(void *p, uint32_t flags, uint32_t system_state); int scmi_sys_pwr_state_get(void *p, uint32_t *system_state); /* SCMI AP core configuration protocol commands. */ int scmi_ap_core_set_reset_addr(void *p, uint64_t reset_addr, uint32_t attr); int scmi_ap_core_get_reset_addr(void *p, uint64_t *reset_addr, uint32_t *attr); /* API to get the platform specific SCMI channel information. */ scmi_channel_plat_info_t *plat_css_get_scmi_info(void); /* API to override default PSCI callbacks for platforms that support SCMI. */ const plat_psci_ops_t *css_scmi_override_pm_ops(plat_psci_ops_t *ops); #endif /* SCMI_H */ trusted-firmware-a-2.2/include/drivers/arm/css/sds.h000066400000000000000000000054341355360272700225310ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SDS_H #define SDS_H /* SDS Structure Identifier defines */ /* AP CPU INFO defines */ #define SDS_AP_CPU_INFO_STRUCT_ID 1 #define SDS_AP_CPU_INFO_PRIMARY_CPUID_OFFSET 0x0 #define SDS_AP_CPU_INFO_PRIMARY_CPUID_SIZE 0x4 /* ROM Firmware Version defines */ #define SDS_ROM_VERSION_STRUCT_ID 2 #define SDS_ROM_VERSION_OFFSET 0x0 #define SDS_ROM_VERSION_SIZE 0x4 /* RAM Firmware version defines */ #define SDS_RAM_VERSION_STRUCT_ID 3 #define SDS_RAM_VERSION_OFFSET 0x0 #define SDS_RAM_VERSION_SIZE 0x4 /* Platform Identity defines */ #define SDS_PLATFORM_IDENTITY_STRUCT_ID 4 #define SDS_PLATFORM_IDENTITY_ID_OFFSET 0x0 #define SDS_PLATFORM_IDENTITY_ID_SIZE 0x4 #define SDS_PLATFORM_IDENTITY_ID_CONFIG_SHIFT 28 #define SDS_PLATFORM_IDENTITY_ID_CONFIG_WIDTH 4 #define SDS_PLATFORM_IDENTITY_ID_CONFIG_MASK \ ((1 << SDS_PLATFORM_IDENTITY_ID_CONFIG_WIDTH) - 1) #define SDS_PLATFORM_IDENTITY_PLAT_TYPE_OFFSET 0x4 #define SDS_PLATFORM_IDENTITY_PLAT_TYPE_SIZE 0x4 /* Reset Syndrome defines */ #define SDS_RESET_SYNDROME_STRUCT_ID 5 #define SDS_RESET_SYNDROME_OFFSET 0 #define SDS_RESET_SYNDROME_SIZE 4 #define SDS_RESET_SYNDROME_POW_ON_RESET_BIT (1 << 0) #define SDS_RESET_SYNDROME_SCP_WD_RESET_BIT (1 << 1) #define SDS_RESET_SYNDROME_AP_WD_RESET_BIT (1 << 2) #define SDS_RESET_SYNDROME_SYS_RESET_REQ_BIT (1 << 3) #define SDS_RESET_SYNDROME_M3_LOCKUP_BIT (1 << 4) /* SCP Firmware Feature Availability defines */ #define SDS_FEATURE_AVAIL_STRUCT_ID 6 #define SDS_FEATURE_AVAIL_OFFSET 0 #define SDS_FEATURE_AVAIL_SIZE 4 #define SDS_FEATURE_AVAIL_SCP_RAM_READY_BIT (1 << 0) #define SDS_FEATURE_AVAIL_DMC_READY_BIT (1 << 1) #define SDS_FEATURE_AVAIL_MSG_IF_READY_BIT (1 << 2) /* SCP BL2 Image Metadata defines */ #define SDS_SCP_IMG_STRUCT_ID 9 #define SDS_SCP_IMG_FLAG_OFFSET 0 #define SDS_SCP_IMG_FLAG_SIZE 4 #define SDS_SCP_IMG_VALID_FLAG_BIT (1 << 0) #define SDS_SCP_IMG_ADDR_OFFSET 4 #define SDS_SCP_IMG_ADDR_SIZE 4 #define SDS_SCP_IMG_SIZE_OFFSET 8 #define SDS_SCP_IMG_SIZE_SIZE 4 /* SDS Driver Error Codes */ #define SDS_OK 0 #define SDS_ERR_FAIL -1 #define SDS_ERR_INVALID_PARAMS -2 #define SDS_ERR_STRUCT_NOT_FOUND -3 #define SDS_ERR_STRUCT_NOT_FINALIZED -4 #ifndef __ASSEMBLER__ #include #include typedef enum { SDS_ACCESS_MODE_NON_CACHED, SDS_ACCESS_MODE_CACHED, } sds_access_mode_t; int sds_init(void); int sds_struct_exists(unsigned int structure_id); int sds_struct_read(uint32_t structure_id, unsigned int fld_off, void *data, size_t size, sds_access_mode_t mode); int sds_struct_write(uint32_t structure_id, unsigned int fld_off, void *data, size_t size, sds_access_mode_t mode); #endif /*__ASSEMBLER__ */ #endif /* SDS_H */ trusted-firmware-a-2.2/include/drivers/arm/fvp/000077500000000000000000000000001355360272700215645ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/arm/fvp/fvp_pwrc.h000066400000000000000000000027561355360272700235750ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef FVP_PWRC_H #define FVP_PWRC_H /* FVP Power controller register offset etc */ #define PPOFFR_OFF U(0x0) #define PPONR_OFF U(0x4) #define PCOFFR_OFF U(0x8) #define PWKUPR_OFF U(0xc) #define PSYSR_OFF U(0x10) #define PWKUPR_WEN BIT_32(31) #define PSYSR_AFF_L2 BIT_32(31) #define PSYSR_AFF_L1 BIT_32(30) #define PSYSR_AFF_L0 BIT_32(29) #define PSYSR_WEN BIT_32(28) #define PSYSR_PC BIT_32(27) #define PSYSR_PP BIT_32(26) #define PSYSR_WK_SHIFT 24 #define PSYSR_WK_WIDTH 0x2 #define PSYSR_WK_MASK ((1U << PSYSR_WK_WIDTH) - 1U) #define PSYSR_WK(x) ((x) >> PSYSR_WK_SHIFT) & PSYSR_WK_MASK #define WKUP_COLD U(0x0) #define WKUP_RESET U(0x1) #define WKUP_PPONR U(0x2) #define WKUP_GICREQ U(0x3) #define PSYSR_INVALID U(0xffffffff) #ifndef __ASSEMBLER__ #include /******************************************************************************* * Function & variable prototypes ******************************************************************************/ void fvp_pwrc_write_pcoffr(u_register_t mpidr); void fvp_pwrc_write_ppoffr(u_register_t mpidr); void fvp_pwrc_write_pponr(u_register_t mpidr); void fvp_pwrc_set_wen(u_register_t mpidr); void fvp_pwrc_clr_wen(u_register_t mpidr); unsigned int fvp_pwrc_read_psysr(u_register_t mpidr); unsigned int fvp_pwrc_get_cpu_wkr(u_register_t mpidr); #endif /*__ASSEMBLER__*/ #endif /* FVP_PWRC_H */ trusted-firmware-a-2.2/include/drivers/arm/gic_common.h000066400000000000000000000064271355360272700232650ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef GIC_COMMON_H #define GIC_COMMON_H #include /******************************************************************************* * GIC Distributor interface general definitions ******************************************************************************/ /* Constants to categorise interrupts */ #define MIN_SGI_ID U(0) #define MIN_SEC_SGI_ID U(8) #define MIN_PPI_ID U(16) #define MIN_SPI_ID U(32) #define MAX_SPI_ID U(1019) #define TOTAL_SPI_INTR_NUM (MAX_SPI_ID - MIN_SPI_ID + U(1)) #define TOTAL_PCPU_INTR_NUM (MIN_SPI_ID - MIN_SGI_ID) /* Mask for the priority field common to all GIC interfaces */ #define GIC_PRI_MASK U(0xff) /* Mask for the configuration field common to all GIC interfaces */ #define GIC_CFG_MASK U(0x3) /* Constant to indicate a spurious interrupt in all GIC versions */ #define GIC_SPURIOUS_INTERRUPT U(1023) /* Interrupt configurations: 2-bit fields with LSB reserved */ #define GIC_INTR_CFG_LEVEL (0 << 1) #define GIC_INTR_CFG_EDGE (1 << 1) /* Highest possible interrupt priorities */ #define GIC_HIGHEST_SEC_PRIORITY U(0x00) #define GIC_HIGHEST_NS_PRIORITY U(0x80) /******************************************************************************* * GIC Distributor interface register offsets that are common to GICv3 & GICv2 ******************************************************************************/ #define GICD_CTLR U(0x0) #define GICD_TYPER U(0x4) #define GICD_IIDR U(0x8) #define GICD_IGROUPR U(0x80) #define GICD_ISENABLER U(0x100) #define GICD_ICENABLER U(0x180) #define GICD_ISPENDR U(0x200) #define GICD_ICPENDR U(0x280) #define GICD_ISACTIVER U(0x300) #define GICD_ICACTIVER U(0x380) #define GICD_IPRIORITYR U(0x400) #define GICD_ICFGR U(0xc00) #define GICD_NSACR U(0xe00) /* GICD_CTLR bit definitions */ #define CTLR_ENABLE_G0_SHIFT 0 #define CTLR_ENABLE_G0_MASK U(0x1) #define CTLR_ENABLE_G0_BIT BIT_32(CTLR_ENABLE_G0_SHIFT) /******************************************************************************* * GIC Distributor interface register constants that are common to GICv3 & GICv2 ******************************************************************************/ #define PIDR2_ARCH_REV_SHIFT 4 #define PIDR2_ARCH_REV_MASK U(0xf) /* GICv3 revision as reported by the PIDR2 register */ #define ARCH_REV_GICV3 U(0x3) /* GICv2 revision as reported by the PIDR2 register */ #define ARCH_REV_GICV2 U(0x2) /* GICv1 revision as reported by the PIDR2 register */ #define ARCH_REV_GICV1 U(0x1) #define IGROUPR_SHIFT 5 #define ISENABLER_SHIFT 5 #define ICENABLER_SHIFT ISENABLER_SHIFT #define ISPENDR_SHIFT 5 #define ICPENDR_SHIFT ISPENDR_SHIFT #define ISACTIVER_SHIFT 5 #define ICACTIVER_SHIFT ISACTIVER_SHIFT #define IPRIORITYR_SHIFT 2 #define ITARGETSR_SHIFT 2 #define ICFGR_SHIFT 4 #define NSACR_SHIFT 4 /* GICD_TYPER shifts and masks */ #define TYPER_IT_LINES_NO_SHIFT U(0) #define TYPER_IT_LINES_NO_MASK U(0x1f) /* Value used to initialize Normal world interrupt priorities four at a time */ #define GICD_IPRIORITYR_DEF_VAL \ (GIC_HIGHEST_NS_PRIORITY | \ (GIC_HIGHEST_NS_PRIORITY << 8) | \ (GIC_HIGHEST_NS_PRIORITY << 16) | \ (GIC_HIGHEST_NS_PRIORITY << 24)) #endif /* GIC_COMMON_H */ trusted-firmware-a-2.2/include/drivers/arm/gicv2.h000066400000000000000000000146211355360272700221600ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef GICV2_H #define GICV2_H #include /******************************************************************************* * GICv2 miscellaneous definitions ******************************************************************************/ /* Interrupt group definitions */ #define GICV2_INTR_GROUP0 U(0) #define GICV2_INTR_GROUP1 U(1) /* Interrupt IDs reported by the HPPIR and IAR registers */ #define PENDING_G1_INTID U(1022) /* GICv2 can only target up to 8 PEs */ #define GICV2_MAX_TARGET_PE U(8) /******************************************************************************* * GICv2 specific Distributor interface register offsets and constants. ******************************************************************************/ #define GICD_ITARGETSR U(0x800) #define GICD_SGIR U(0xF00) #define GICD_CPENDSGIR U(0xF10) #define GICD_SPENDSGIR U(0xF20) #define GICD_PIDR2_GICV2 U(0xFE8) #define ITARGETSR_SHIFT 2 #define GIC_TARGET_CPU_MASK U(0xff) #define CPENDSGIR_SHIFT 2 #define SPENDSGIR_SHIFT CPENDSGIR_SHIFT #define SGIR_TGTLSTFLT_SHIFT 24 #define SGIR_TGTLSTFLT_MASK U(0x3) #define SGIR_TGTLST_SHIFT 16 #define SGIR_TGTLST_MASK U(0xff) #define SGIR_INTID_MASK ULL(0xf) #define SGIR_TGT_SPECIFIC U(0) #define GICV2_SGIR_VALUE(tgt_lst_flt, tgt, intid) \ ((((tgt_lst_flt) & SGIR_TGTLSTFLT_MASK) << SGIR_TGTLSTFLT_SHIFT) | \ (((tgt) & SGIR_TGTLST_MASK) << SGIR_TGTLST_SHIFT) | \ ((intid) & SGIR_INTID_MASK)) /******************************************************************************* * GICv2 specific CPU interface register offsets and constants. ******************************************************************************/ /* Physical CPU Interface registers */ #define GICC_CTLR U(0x0) #define GICC_PMR U(0x4) #define GICC_BPR U(0x8) #define GICC_IAR U(0xC) #define GICC_EOIR U(0x10) #define GICC_RPR U(0x14) #define GICC_HPPIR U(0x18) #define GICC_AHPPIR U(0x28) #define GICC_IIDR U(0xFC) #define GICC_DIR U(0x1000) #define GICC_PRIODROP GICC_EOIR /* GICC_CTLR bit definitions */ #define EOI_MODE_NS BIT_32(10) #define EOI_MODE_S BIT_32(9) #define IRQ_BYP_DIS_GRP1 BIT_32(8) #define FIQ_BYP_DIS_GRP1 BIT_32(7) #define IRQ_BYP_DIS_GRP0 BIT_32(6) #define FIQ_BYP_DIS_GRP0 BIT_32(5) #define CBPR BIT_32(4) #define FIQ_EN_SHIFT 3 #define FIQ_EN_BIT BIT_32(FIQ_EN_SHIFT) #define ACK_CTL BIT_32(2) /* GICC_IIDR bit masks and shifts */ #define GICC_IIDR_PID_SHIFT 20 #define GICC_IIDR_ARCH_SHIFT 16 #define GICC_IIDR_REV_SHIFT 12 #define GICC_IIDR_IMP_SHIFT 0 #define GICC_IIDR_PID_MASK U(0xfff) #define GICC_IIDR_ARCH_MASK U(0xf) #define GICC_IIDR_REV_MASK U(0xf) #define GICC_IIDR_IMP_MASK U(0xfff) /* HYP view virtual CPU Interface registers */ #define GICH_CTL U(0x0) #define GICH_VTR U(0x4) #define GICH_ELRSR0 U(0x30) #define GICH_ELRSR1 U(0x34) #define GICH_APR0 U(0xF0) #define GICH_LR_BASE U(0x100) /* Virtual CPU Interface registers */ #define GICV_CTL U(0x0) #define GICV_PRIMASK U(0x4) #define GICV_BP U(0x8) #define GICV_INTACK U(0xC) #define GICV_EOI U(0x10) #define GICV_RUNNINGPRI U(0x14) #define GICV_HIGHESTPEND U(0x18) #define GICV_DEACTIVATE U(0x1000) /* GICD_CTLR bit definitions */ #define CTLR_ENABLE_G1_SHIFT 1 #define CTLR_ENABLE_G1_MASK U(0x1) #define CTLR_ENABLE_G1_BIT BIT_32(CTLR_ENABLE_G1_SHIFT) /* Interrupt ID mask for HPPIR, AHPPIR, IAR and AIAR CPU Interface registers */ #define INT_ID_MASK U(0x3ff) #ifndef __ASSEMBLER__ #include #include #include /******************************************************************************* * This structure describes some of the implementation defined attributes of * the GICv2 IP. It is used by the platform port to specify these attributes * in order to initialize the GICv2 driver. The attributes are described * below. * * The 'gicd_base' field contains the base address of the Distributor interface * programmer's view. * * The 'gicc_base' field contains the base address of the CPU Interface * programmer's view. * * The 'target_masks' is a pointer to an array containing 'target_masks_num' * elements. The GIC driver will populate the array with per-PE target mask to * use to when targeting interrupts. * * The 'interrupt_props' field is a pointer to an array that enumerates secure * interrupts and their properties. If this field is not NULL, both * 'g0_interrupt_array' and 'g1s_interrupt_array' fields are ignored. * * The 'interrupt_props_num' field contains the number of entries in the * 'interrupt_props' array. If this field is non-zero, 'g0_interrupt_num' is * ignored. ******************************************************************************/ typedef struct gicv2_driver_data { uintptr_t gicd_base; uintptr_t gicc_base; unsigned int *target_masks; unsigned int target_masks_num; const interrupt_prop_t *interrupt_props; unsigned int interrupt_props_num; } gicv2_driver_data_t; /******************************************************************************* * Function prototypes ******************************************************************************/ void gicv2_driver_init(const gicv2_driver_data_t *plat_driver_data); void gicv2_distif_init(void); void gicv2_pcpu_distif_init(void); void gicv2_cpuif_enable(void); void gicv2_cpuif_disable(void); unsigned int gicv2_is_fiq_enabled(void); unsigned int gicv2_get_pending_interrupt_type(void); unsigned int gicv2_get_pending_interrupt_id(void); unsigned int gicv2_acknowledge_interrupt(void); void gicv2_end_of_interrupt(unsigned int id); unsigned int gicv2_get_interrupt_group(unsigned int id); unsigned int gicv2_get_running_priority(void); void gicv2_set_pe_target_mask(unsigned int proc_num); unsigned int gicv2_get_interrupt_active(unsigned int id); void gicv2_enable_interrupt(unsigned int id); void gicv2_disable_interrupt(unsigned int id); void gicv2_set_interrupt_priority(unsigned int id, unsigned int priority); void gicv2_set_interrupt_type(unsigned int id, unsigned int type); void gicv2_raise_sgi(int sgi_num, int proc_num); void gicv2_set_spi_routing(unsigned int id, int proc_num); void gicv2_set_interrupt_pending(unsigned int id); void gicv2_clear_interrupt_pending(unsigned int id); unsigned int gicv2_set_pmr(unsigned int mask); void gicv2_interrupt_set_cfg(unsigned int id, unsigned int cfg); #endif /* __ASSEMBLER__ */ #endif /* GICV2_H */ trusted-firmware-a-2.2/include/drivers/arm/gicv3.h000066400000000000000000000351651355360272700221670ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef GICV3_H #define GICV3_H /******************************************************************************* * GICv3 miscellaneous definitions ******************************************************************************/ /* Interrupt group definitions */ #define INTR_GROUP1S U(0) #define INTR_GROUP0 U(1) #define INTR_GROUP1NS U(2) /* Interrupt IDs reported by the HPPIR and IAR registers */ #define PENDING_G1S_INTID U(1020) #define PENDING_G1NS_INTID U(1021) /* Constant to categorize LPI interrupt */ #define MIN_LPI_ID U(8192) /* GICv3 can only target up to 16 PEs with SGI */ #define GICV3_MAX_SGI_TARGETS U(16) /******************************************************************************* * GICv3 specific Distributor interface register offsets and constants. ******************************************************************************/ #define GICD_STATUSR U(0x10) #define GICD_SETSPI_NSR U(0x40) #define GICD_CLRSPI_NSR U(0x48) #define GICD_SETSPI_SR U(0x50) #define GICD_CLRSPI_SR U(0x50) #define GICD_IGRPMODR U(0xd00) /* * GICD_IROUTER register is at 0x6000 + 8n, where n is the interrupt id and * n >= 32, making the effective offset as 0x6100. */ #define GICD_IROUTER U(0x6000) #define GICD_PIDR2_GICV3 U(0xffe8) #define IGRPMODR_SHIFT 5 /* GICD_CTLR bit definitions */ #define CTLR_ENABLE_G1NS_SHIFT 1 #define CTLR_ENABLE_G1S_SHIFT 2 #define CTLR_ARE_S_SHIFT 4 #define CTLR_ARE_NS_SHIFT 5 #define CTLR_DS_SHIFT 6 #define CTLR_E1NWF_SHIFT 7 #define GICD_CTLR_RWP_SHIFT 31 #define CTLR_ENABLE_G1NS_MASK U(0x1) #define CTLR_ENABLE_G1S_MASK U(0x1) #define CTLR_ARE_S_MASK U(0x1) #define CTLR_ARE_NS_MASK U(0x1) #define CTLR_DS_MASK U(0x1) #define CTLR_E1NWF_MASK U(0x1) #define GICD_CTLR_RWP_MASK U(0x1) #define CTLR_ENABLE_G1NS_BIT BIT_32(CTLR_ENABLE_G1NS_SHIFT) #define CTLR_ENABLE_G1S_BIT BIT_32(CTLR_ENABLE_G1S_SHIFT) #define CTLR_ARE_S_BIT BIT_32(CTLR_ARE_S_SHIFT) #define CTLR_ARE_NS_BIT BIT_32(CTLR_ARE_NS_SHIFT) #define CTLR_DS_BIT BIT_32(CTLR_DS_SHIFT) #define CTLR_E1NWF_BIT BIT_32(CTLR_E1NWF_SHIFT) #define GICD_CTLR_RWP_BIT BIT_32(GICD_CTLR_RWP_SHIFT) /* GICD_IROUTER shifts and masks */ #define IROUTER_SHIFT 0 #define IROUTER_IRM_SHIFT 31 #define IROUTER_IRM_MASK U(0x1) #define GICV3_IRM_PE U(0) #define GICV3_IRM_ANY U(1) #define NUM_OF_DIST_REGS 30 /******************************************************************************* * GICv3 Re-distributor interface registers & constants ******************************************************************************/ #define GICR_PCPUBASE_SHIFT 0x11 #define GICR_SGIBASE_OFFSET U(65536) /* 64 KB */ #define GICR_CTLR U(0x0) #define GICR_IIDR U(0x04) #define GICR_TYPER U(0x08) #define GICR_WAKER U(0x14) #define GICR_PROPBASER U(0x70) #define GICR_PENDBASER U(0x78) #define GICR_IGROUPR0 (GICR_SGIBASE_OFFSET + U(0x80)) #define GICR_ISENABLER0 (GICR_SGIBASE_OFFSET + U(0x100)) #define GICR_ICENABLER0 (GICR_SGIBASE_OFFSET + U(0x180)) #define GICR_ISPENDR0 (GICR_SGIBASE_OFFSET + U(0x200)) #define GICR_ICPENDR0 (GICR_SGIBASE_OFFSET + U(0x280)) #define GICR_ISACTIVER0 (GICR_SGIBASE_OFFSET + U(0x300)) #define GICR_ICACTIVER0 (GICR_SGIBASE_OFFSET + U(0x380)) #define GICR_IPRIORITYR (GICR_SGIBASE_OFFSET + U(0x400)) #define GICR_ICFGR0 (GICR_SGIBASE_OFFSET + U(0xc00)) #define GICR_ICFGR1 (GICR_SGIBASE_OFFSET + U(0xc04)) #define GICR_IGRPMODR0 (GICR_SGIBASE_OFFSET + U(0xd00)) #define GICR_NSACR (GICR_SGIBASE_OFFSET + U(0xe00)) /* GICR_CTLR bit definitions */ #define GICR_CTLR_UWP_SHIFT 31 #define GICR_CTLR_UWP_MASK U(0x1) #define GICR_CTLR_UWP_BIT BIT_32(GICR_CTLR_UWP_SHIFT) #define GICR_CTLR_RWP_SHIFT 3 #define GICR_CTLR_RWP_MASK U(0x1) #define GICR_CTLR_RWP_BIT BIT_32(GICR_CTLR_RWP_SHIFT) #define GICR_CTLR_EN_LPIS_BIT BIT_32(0) /* GICR_WAKER bit definitions */ #define WAKER_CA_SHIFT 2 #define WAKER_PS_SHIFT 1 #define WAKER_CA_MASK U(0x1) #define WAKER_PS_MASK U(0x1) #define WAKER_CA_BIT BIT_32(WAKER_CA_SHIFT) #define WAKER_PS_BIT BIT_32(WAKER_PS_SHIFT) /* GICR_TYPER bit definitions */ #define TYPER_AFF_VAL_SHIFT 32 #define TYPER_PROC_NUM_SHIFT 8 #define TYPER_LAST_SHIFT 4 #define TYPER_AFF_VAL_MASK U(0xffffffff) #define TYPER_PROC_NUM_MASK U(0xffff) #define TYPER_LAST_MASK U(0x1) #define TYPER_LAST_BIT BIT_32(TYPER_LAST_SHIFT) #define NUM_OF_REDIST_REGS 30 /******************************************************************************* * GICv3 CPU interface registers & constants ******************************************************************************/ /* ICC_SRE bit definitions*/ #define ICC_SRE_EN_BIT BIT_32(3) #define ICC_SRE_DIB_BIT BIT_32(2) #define ICC_SRE_DFB_BIT BIT_32(1) #define ICC_SRE_SRE_BIT BIT_32(0) /* ICC_IGRPEN1_EL3 bit definitions */ #define IGRPEN1_EL3_ENABLE_G1NS_SHIFT 0 #define IGRPEN1_EL3_ENABLE_G1S_SHIFT 1 #define IGRPEN1_EL3_ENABLE_G1NS_BIT BIT_32(IGRPEN1_EL3_ENABLE_G1NS_SHIFT) #define IGRPEN1_EL3_ENABLE_G1S_BIT BIT_32(IGRPEN1_EL3_ENABLE_G1S_SHIFT) /* ICC_IGRPEN0_EL1 bit definitions */ #define IGRPEN1_EL1_ENABLE_G0_SHIFT 0 #define IGRPEN1_EL1_ENABLE_G0_BIT BIT_32(IGRPEN1_EL1_ENABLE_G0_SHIFT) /* ICC_HPPIR0_EL1 bit definitions */ #define HPPIR0_EL1_INTID_SHIFT 0 #define HPPIR0_EL1_INTID_MASK U(0xffffff) /* ICC_HPPIR1_EL1 bit definitions */ #define HPPIR1_EL1_INTID_SHIFT 0 #define HPPIR1_EL1_INTID_MASK U(0xffffff) /* ICC_IAR0_EL1 bit definitions */ #define IAR0_EL1_INTID_SHIFT 0 #define IAR0_EL1_INTID_MASK U(0xffffff) /* ICC_IAR1_EL1 bit definitions */ #define IAR1_EL1_INTID_SHIFT 0 #define IAR1_EL1_INTID_MASK U(0xffffff) /* ICC SGI macros */ #define SGIR_TGT_MASK ULL(0xffff) #define SGIR_AFF1_SHIFT 16 #define SGIR_INTID_SHIFT 24 #define SGIR_INTID_MASK ULL(0xf) #define SGIR_AFF2_SHIFT 32 #define SGIR_IRM_SHIFT 40 #define SGIR_IRM_MASK ULL(0x1) #define SGIR_AFF3_SHIFT 48 #define SGIR_AFF_MASK ULL(0xf) #define SGIR_IRM_TO_AFF U(0) #define GICV3_SGIR_VALUE(_aff3, _aff2, _aff1, _intid, _irm, _tgt) \ ((((uint64_t) (_aff3) & SGIR_AFF_MASK) << SGIR_AFF3_SHIFT) | \ (((uint64_t) (_irm) & SGIR_IRM_MASK) << SGIR_IRM_SHIFT) | \ (((uint64_t) (_aff2) & SGIR_AFF_MASK) << SGIR_AFF2_SHIFT) | \ (((_intid) & SGIR_INTID_MASK) << SGIR_INTID_SHIFT) | \ (((_aff1) & SGIR_AFF_MASK) << SGIR_AFF1_SHIFT) | \ ((_tgt) & SGIR_TGT_MASK)) /***************************************************************************** * GICv3 ITS registers and constants *****************************************************************************/ #define GITS_CTLR U(0x0) #define GITS_IIDR U(0x4) #define GITS_TYPER U(0x8) #define GITS_CBASER U(0x80) #define GITS_CWRITER U(0x88) #define GITS_CREADR U(0x90) #define GITS_BASER U(0x100) /* GITS_CTLR bit definitions */ #define GITS_CTLR_ENABLED_BIT BIT_32(0) #define GITS_CTLR_QUIESCENT_SHIFT 31 #define GITS_CTLR_QUIESCENT_BIT BIT_32(GITS_CTLR_QUIESCENT_SHIFT) #ifndef __ASSEMBLER__ #include #include #include #include #include #include static inline bool gicv3_is_intr_id_special_identifier(unsigned int id) { return (id >= PENDING_G1S_INTID) && (id <= GIC_SPURIOUS_INTERRUPT); } /******************************************************************************* * Helper GICv3 macros for SEL1 ******************************************************************************/ static inline uint32_t gicv3_acknowledge_interrupt_sel1(void) { return (uint32_t)read_icc_iar1_el1() & IAR1_EL1_INTID_MASK; } static inline uint32_t gicv3_get_pending_interrupt_id_sel1(void) { return (uint32_t)read_icc_hppir1_el1() & HPPIR1_EL1_INTID_MASK; } static inline void gicv3_end_of_interrupt_sel1(unsigned int id) { write_icc_eoir1_el1(id); } /******************************************************************************* * Helper GICv3 macros for EL3 ******************************************************************************/ static inline uint32_t gicv3_acknowledge_interrupt(void) { return (uint32_t)read_icc_iar0_el1() & IAR0_EL1_INTID_MASK; } static inline void gicv3_end_of_interrupt(unsigned int id) { return write_icc_eoir0_el1(id); } /* * This macro returns the total number of GICD registers corresponding to * the name. */ #define GICD_NUM_REGS(reg_name) \ DIV_ROUND_UP_2EVAL(TOTAL_SPI_INTR_NUM, (1 << reg_name ## _SHIFT)) #define GICR_NUM_REGS(reg_name) \ DIV_ROUND_UP_2EVAL(TOTAL_PCPU_INTR_NUM, (1 << reg_name ## _SHIFT)) /* Interrupt ID mask for HPPIR, AHPPIR, IAR and AIAR CPU Interface registers */ #define INT_ID_MASK U(0xffffff) /******************************************************************************* * This structure describes some of the implementation defined attributes of the * GICv3 IP. It is used by the platform port to specify these attributes in order * to initialise the GICV3 driver. The attributes are described below. * * The 'gicd_base' field contains the base address of the Distributor interface * programmer's view. * * The 'gicr_base' field contains the base address of the Re-distributor * interface programmer's view. * * The 'interrupt_props' field is a pointer to an array that enumerates secure * interrupts and their properties. If this field is not NULL, both * 'g0_interrupt_array' and 'g1s_interrupt_array' fields are ignored. * * The 'interrupt_props_num' field contains the number of entries in the * 'interrupt_props' array. If this field is non-zero, both 'g0_interrupt_num' * and 'g1s_interrupt_num' are ignored. * * The 'rdistif_num' field contains the number of Redistributor interfaces the * GIC implements. This is equal to the number of CPUs or CPU interfaces * instantiated in the GIC. * * The 'rdistif_base_addrs' field is a pointer to an array that has an entry for * storing the base address of the Redistributor interface frame of each CPU in * the system. The size of the array = 'rdistif_num'. The base addresses are * detected during driver initialisation. * * The 'mpidr_to_core_pos' field is a pointer to a hash function which the * driver will use to convert an MPIDR value to a linear core index. This index * will be used for accessing the 'rdistif_base_addrs' array. This is an * optional field. A GICv3 implementation maps each MPIDR to a linear core index * as well. This mapping can be found by reading the "Affinity Value" and * "Processor Number" fields in the GICR_TYPER. It is IMP. DEF. if the * "Processor Numbers" are suitable to index into an array to access core * specific information. If this not the case, the platform port must provide a * hash function. Otherwise, the "Processor Number" field will be used to access * the array elements. ******************************************************************************/ typedef unsigned int (*mpidr_hash_fn)(u_register_t mpidr); typedef struct gicv3_driver_data { uintptr_t gicd_base; uintptr_t gicr_base; const interrupt_prop_t *interrupt_props; unsigned int interrupt_props_num; unsigned int rdistif_num; uintptr_t *rdistif_base_addrs; mpidr_hash_fn mpidr_to_core_pos; } gicv3_driver_data_t; typedef struct gicv3_redist_ctx { /* 64 bits registers */ uint64_t gicr_propbaser; uint64_t gicr_pendbaser; /* 32 bits registers */ uint32_t gicr_ctlr; uint32_t gicr_igroupr0; uint32_t gicr_isenabler0; uint32_t gicr_ispendr0; uint32_t gicr_isactiver0; uint32_t gicr_ipriorityr[GICR_NUM_REGS(IPRIORITYR)]; uint32_t gicr_icfgr0; uint32_t gicr_icfgr1; uint32_t gicr_igrpmodr0; uint32_t gicr_nsacr; } gicv3_redist_ctx_t; typedef struct gicv3_dist_ctx { /* 64 bits registers */ uint64_t gicd_irouter[TOTAL_SPI_INTR_NUM]; /* 32 bits registers */ uint32_t gicd_ctlr; uint32_t gicd_igroupr[GICD_NUM_REGS(IGROUPR)]; uint32_t gicd_isenabler[GICD_NUM_REGS(ISENABLER)]; uint32_t gicd_ispendr[GICD_NUM_REGS(ISPENDR)]; uint32_t gicd_isactiver[GICD_NUM_REGS(ISACTIVER)]; uint32_t gicd_ipriorityr[GICD_NUM_REGS(IPRIORITYR)]; uint32_t gicd_icfgr[GICD_NUM_REGS(ICFGR)]; uint32_t gicd_igrpmodr[GICD_NUM_REGS(IGRPMODR)]; uint32_t gicd_nsacr[GICD_NUM_REGS(NSACR)]; } gicv3_dist_ctx_t; typedef struct gicv3_its_ctx { /* 64 bits registers */ uint64_t gits_cbaser; uint64_t gits_cwriter; uint64_t gits_baser[8]; /* 32 bits registers */ uint32_t gits_ctlr; } gicv3_its_ctx_t; /******************************************************************************* * GICv3 EL3 driver API ******************************************************************************/ void gicv3_driver_init(const gicv3_driver_data_t *plat_driver_data); int gicv3_rdistif_probe(const uintptr_t gicr_frame); void gicv3_distif_init(void); void gicv3_rdistif_init(unsigned int proc_num); void gicv3_rdistif_on(unsigned int proc_num); void gicv3_rdistif_off(unsigned int proc_num); void gicv3_cpuif_enable(unsigned int proc_num); void gicv3_cpuif_disable(unsigned int proc_num); unsigned int gicv3_get_pending_interrupt_type(void); unsigned int gicv3_get_pending_interrupt_id(void); unsigned int gicv3_get_interrupt_type(unsigned int id, unsigned int proc_num); void gicv3_distif_init_restore(const gicv3_dist_ctx_t * const dist_ctx); void gicv3_distif_save(gicv3_dist_ctx_t * const dist_ctx); /* * gicv3_distif_post_restore and gicv3_distif_pre_save must be implemented if * gicv3_distif_save and gicv3_rdistif_init_restore are used. If no * implementation-defined sequence is needed at these steps, an empty function * can be provided. */ void gicv3_distif_post_restore(unsigned int proc_num); void gicv3_distif_pre_save(unsigned int proc_num); void gicv3_rdistif_init_restore(unsigned int proc_num, const gicv3_redist_ctx_t * const rdist_ctx); void gicv3_rdistif_save(unsigned int proc_num, gicv3_redist_ctx_t * const rdist_ctx); void gicv3_its_save_disable(uintptr_t gits_base, gicv3_its_ctx_t * const its_ctx); void gicv3_its_restore(uintptr_t gits_base, const gicv3_its_ctx_t * const its_ctx); unsigned int gicv3_get_running_priority(void); unsigned int gicv3_get_interrupt_active(unsigned int id, unsigned int proc_num); void gicv3_enable_interrupt(unsigned int id, unsigned int proc_num); void gicv3_disable_interrupt(unsigned int id, unsigned int proc_num); void gicv3_set_interrupt_priority(unsigned int id, unsigned int proc_num, unsigned int priority); void gicv3_set_interrupt_type(unsigned int id, unsigned int proc_num, unsigned int type); void gicv3_raise_secure_g0_sgi(unsigned int sgi_num, u_register_t target); void gicv3_set_spi_routing(unsigned int id, unsigned int irm, u_register_t mpidr); void gicv3_set_interrupt_pending(unsigned int id, unsigned int proc_num); void gicv3_clear_interrupt_pending(unsigned int id, unsigned int proc_num); unsigned int gicv3_set_pmr(unsigned int mask); #endif /* __ASSEMBLER__ */ #endif /* GICV3_H */ trusted-firmware-a-2.2/include/drivers/arm/nic_400.h000066400000000000000000000005151355360272700222770ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef NIC_400_H #define NIC_400_H /* * Address of slave 'n' security setting in the NIC-400 address region * control */ #define NIC400_ADDR_CTRL_SECURITY_REG(n) (0x8 + (n) * 4) #endif /* NIC_400_H */ trusted-firmware-a-2.2/include/drivers/arm/pl011.h000066400000000000000000000075331355360272700220070ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PL011_H #define PL011_H #include /* PL011 Registers */ #define UARTDR 0x000 #define UARTRSR 0x004 #define UARTECR 0x004 #define UARTFR 0x018 #define UARTIMSC 0x038 #define UARTRIS 0x03C #define UARTICR 0x044 /* PL011 registers (out of the SBSA specification) */ #if !PL011_GENERIC_UART #define UARTILPR 0x020 #define UARTIBRD 0x024 #define UARTFBRD 0x028 #define UARTLCR_H 0x02C #define UARTCR 0x030 #define UARTIFLS 0x034 #define UARTMIS 0x040 #define UARTDMACR 0x048 #endif /* !PL011_GENERIC_UART */ /* Data status bits */ #define UART_DATA_ERROR_MASK 0x0F00 /* Status reg bits */ #define UART_STATUS_ERROR_MASK 0x0F /* Flag reg bits */ #define PL011_UARTFR_RI (1 << 8) /* Ring indicator */ #define PL011_UARTFR_TXFE (1 << 7) /* Transmit FIFO empty */ #define PL011_UARTFR_RXFF (1 << 6) /* Receive FIFO full */ #define PL011_UARTFR_TXFF (1 << 5) /* Transmit FIFO full */ #define PL011_UARTFR_RXFE (1 << 4) /* Receive FIFO empty */ #define PL011_UARTFR_BUSY (1 << 3) /* UART busy */ #define PL011_UARTFR_DCD (1 << 2) /* Data carrier detect */ #define PL011_UARTFR_DSR (1 << 1) /* Data set ready */ #define PL011_UARTFR_CTS (1 << 0) /* Clear to send */ #define PL011_UARTFR_TXFF_BIT 5 /* Transmit FIFO full bit in UARTFR register */ #define PL011_UARTFR_RXFE_BIT 4 /* Receive FIFO empty bit in UARTFR register */ #define PL011_UARTFR_BUSY_BIT 3 /* UART busy bit in UARTFR register */ /* Control reg bits */ #if !PL011_GENERIC_UART #define PL011_UARTCR_CTSEN (1 << 15) /* CTS hardware flow control enable */ #define PL011_UARTCR_RTSEN (1 << 14) /* RTS hardware flow control enable */ #define PL011_UARTCR_RTS (1 << 11) /* Request to send */ #define PL011_UARTCR_DTR (1 << 10) /* Data transmit ready. */ #define PL011_UARTCR_RXE (1 << 9) /* Receive enable */ #define PL011_UARTCR_TXE (1 << 8) /* Transmit enable */ #define PL011_UARTCR_LBE (1 << 7) /* Loopback enable */ #define PL011_UARTCR_UARTEN (1 << 0) /* UART Enable */ #if !defined(PL011_LINE_CONTROL) /* FIFO Enabled / No Parity / 8 Data bit / One Stop Bit */ #define PL011_LINE_CONTROL (PL011_UARTLCR_H_FEN | PL011_UARTLCR_H_WLEN_8) #endif /* Line Control Register Bits */ #define PL011_UARTLCR_H_SPS (1 << 7) /* Stick parity select */ #define PL011_UARTLCR_H_WLEN_8 (3 << 5) #define PL011_UARTLCR_H_WLEN_7 (2 << 5) #define PL011_UARTLCR_H_WLEN_6 (1 << 5) #define PL011_UARTLCR_H_WLEN_5 (0 << 5) #define PL011_UARTLCR_H_FEN (1 << 4) /* FIFOs Enable */ #define PL011_UARTLCR_H_STP2 (1 << 3) /* Two stop bits select */ #define PL011_UARTLCR_H_EPS (1 << 2) /* Even parity select */ #define PL011_UARTLCR_H_PEN (1 << 1) /* Parity Enable */ #define PL011_UARTLCR_H_BRK (1 << 0) /* Send break */ #endif /* !PL011_GENERIC_UART */ #define CONSOLE_T_PL011_BASE CONSOLE_T_DRVDATA #ifndef __ASSEMBLER__ #include typedef struct { console_t console; uintptr_t base; } console_pl011_t; /* * Initialize a new PL011 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_pl011_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, console_pl011_t *console); #endif /*__ASSEMBLER__*/ #endif /* PL011_H */ trusted-firmware-a-2.2/include/drivers/arm/pl061_gpio.h000066400000000000000000000004701355360272700230230ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PL061_GPIO_H #define PL061_GPIO_H #include void pl061_gpio_register(uintptr_t base_addr, int gpio_dev); void pl061_gpio_init(void); #endif /* PL061_GPIO_H */ trusted-firmware-a-2.2/include/drivers/arm/sbsa.h000066400000000000000000000007541355360272700221000ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SBSA_H #define SBSA_H #include /* Register Offsets */ #define SBSA_WDOG_WCS_OFFSET UL(0x000) #define SBSA_WDOG_WOR_LOW_OFFSET UL(0x008) #define SBSA_WDOG_WOR_HIGH_OFFSET UL(0x00C) #define SBSA_WDOG_WCS_EN U(0x1) #define SBSA_WDOG_WOR_WIDTH UL(48) void sbsa_wdog_start(uintptr_t base, uint64_t ms); void sbsa_wdog_stop(uintptr_t base); #endif /* SBSA_H */ trusted-firmware-a-2.2/include/drivers/arm/smmu_v3.h000066400000000000000000000015451355360272700225400ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SMMU_V3_H #define SMMU_V3_H #include #include /* SMMUv3 register offsets from device base */ #define SMMU_GBPA U(0x0044) #define SMMU_S_IDR1 U(0x8004) #define SMMU_S_INIT U(0x803c) #define SMMU_S_GBPA U(0x8044) /* SMMU_GBPA register fields */ #define SMMU_GBPA_UPDATE (1UL << 31) #define SMMU_GBPA_ABORT (1UL << 20) /* SMMU_S_IDR1 register fields */ #define SMMU_S_IDR1_SECURE_IMPL (1UL << 31) /* SMMU_S_INIT register fields */ #define SMMU_S_INIT_INV_ALL (1UL << 0) /* SMMU_S_GBPA register fields */ #define SMMU_S_GBPA_UPDATE (1UL << 31) #define SMMU_S_GBPA_ABORT (1UL << 20) int smmuv3_init(uintptr_t smmu_base); int smmuv3_security_init(uintptr_t smmu_base); #endif /* SMMU_V3_H */ trusted-firmware-a-2.2/include/drivers/arm/sp804_delay_timer.h000066400000000000000000000012261355360272700243770ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SP804_DELAY_TIMER_H #define SP804_DELAY_TIMER_H #include #include uint32_t sp804_get_timer_value(void); void sp804_timer_ops_init(uintptr_t base_addr, const timer_ops_t *ops); #define sp804_timer_init(base_addr, clk_mult, clk_div) \ do { \ static const timer_ops_t sp804_timer_ops = { \ sp804_get_timer_value, \ (clk_mult), \ (clk_div) \ }; \ sp804_timer_ops_init((base_addr), &sp804_timer_ops); \ } while (0) #endif /* SP804_DELAY_TIMER_H */ trusted-firmware-a-2.2/include/drivers/arm/sp805.h000066400000000000000000000014361355360272700220250ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SP805_H #define SP805_H #include /* SP805 register offset */ #define SP805_WDOG_LOAD_OFF UL(0x000) #define SP805_WDOG_CTR_OFF UL(0x008) #define SP805_WDOG_LOCK_OFF UL(0xc00) /* Magic word to unlock the wd registers */ #define WDOG_UNLOCK_KEY U(0x1ACCE551) /* Register field definitions */ #define SP805_CTR_RESEN (U(1) << 1) #define SP805_CTR_INTEN (U(1) << 0) #ifndef __ASSEMBLER__ #include /* Public high level API */ void sp805_start(uintptr_t base, unsigned int ticks); void sp805_stop(uintptr_t base); void sp805_refresh(uintptr_t base, unsigned int ticks); #endif /* __ASSEMBLER__ */ #endif /* SP805_H */ trusted-firmware-a-2.2/include/drivers/arm/tzc380.h000066400000000000000000000113021355360272700221720ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TZC380_H #define TZC380_H #include #include #define TZC380_CONFIGURATION_OFF U(0x000) #define ACTION_OFF U(0x004) #define LOCKDOWN_RANGE_OFF U(0x008) #define LOCKDOWN_SELECT_OFF U(0x00C) #define INT_STATUS U(0x010) #define INT_CLEAR U(0x014) #define FAIL_ADDRESS_LOW_OFF U(0x020) #define FAIL_ADDRESS_HIGH_OFF U(0x024) #define FAIL_CONTROL_OFF U(0x028) #define FAIL_ID U(0x02c) #define SPECULATION_CTRL_OFF U(0x030) #define SECURITY_INV_EN_OFF U(0x034) #define REGION_SETUP_LOW_OFF(n) U(0x100 + (n) * 0x10) #define REGION_SETUP_HIGH_OFF(n) U(0x104 + (n) * 0x10) #define REGION_ATTRIBUTES_OFF(n) U(0x108 + (n) * 0x10) #define BUILD_CONFIG_AW_SHIFT 8 #define BUILD_CONFIG_AW_MASK U(0x3f) #define BUILD_CONFIG_NR_SHIFT 0 #define BUILD_CONFIG_NR_MASK U(0xf) #define ACTION_RV_SHIFT 0 #define ACTION_RV_MASK U(0x3) #define ACTION_RV_LOWOK U(0x0) #define ACTION_RV_LOWERR U(0x1) #define ACTION_RV_HIGHOK U(0x2) #define ACTION_RV_HIGHERR U(0x3) /* Speculation is enabled by default. */ #define SPECULATION_CTRL_WRITE_DISABLE BIT_32(1) #define SPECULATION_CTRL_READ_DISABLE BIT_32(0) #define INT_STATUS_OVERRUN_SHIFT 1 #define INT_STATUS_OVERRUN_MASK U(0x1) #define INT_STATUS_STATUS_SHIFT 0 #define INT_STATUS_STATUS_MASK U(0x1) #define INT_CLEAR_CLEAR_SHIFT 0 #define INT_CLEAR_CLEAR_MASK U(0x1) #define TZC380_COMPONENT_ID U(0xb105f00d) #define TZC380_PERIPH_ID_LOW U(0x001bb380) #define TZC380_PERIPH_ID_HIGH U(0x00000004) #define TZC_SP_NS_W BIT_32(0) #define TZC_SP_NS_R BIT_32(1) #define TZC_SP_S_W BIT_32(2) #define TZC_SP_S_R BIT_32(3) #define TZC_ATTR_SP_SHIFT 28 #define TZC_ATTR_SP_ALL ((TZC_SP_S_W | TZC_SP_S_R | TZC_SP_NS_W | \ TZC_SP_NS_R) << TZC_ATTR_SP_SHIFT) #define TZC_ATTR_SP_S_RW ((TZC_SP_S_W | TZC_SP_S_R) << \ TZC_ATTR_SP_SHIFT) #define TZC_ATTR_SP_NS_RW ((TZC_SP_NS_W | TZC_SP_NS_R) << \ TZC_ATTR_SP_SHIFT) #define TZC_REGION_SIZE_32K U(0xe) #define TZC_REGION_SIZE_64K U(0xf) #define TZC_REGION_SIZE_128K U(0x10) #define TZC_REGION_SIZE_256K U(0x11) #define TZC_REGION_SIZE_512K U(0x12) #define TZC_REGION_SIZE_1M U(0x13) #define TZC_REGION_SIZE_2M U(0x14) #define TZC_REGION_SIZE_4M U(0x15) #define TZC_REGION_SIZE_8M U(0x16) #define TZC_REGION_SIZE_16M U(0x17) #define TZC_REGION_SIZE_32M U(0x18) #define TZC_REGION_SIZE_64M U(0x19) #define TZC_REGION_SIZE_128M U(0x1a) #define TZC_REGION_SIZE_256M U(0x1b) #define TZC_REGION_SIZE_512M U(0x1c) #define TZC_REGION_SIZE_1G U(0x1d) #define TZC_REGION_SIZE_2G U(0x1e) #define TZC_REGION_SIZE_4G U(0x1f) #define TZC_REGION_SIZE_8G U(0x20) #define TZC_REGION_SIZE_16G U(0x21) #define TZC_REGION_SIZE_32G U(0x22) #define TZC_REGION_SIZE_64G U(0x23) #define TZC_REGION_SIZE_128G U(0x24) #define TZC_REGION_SIZE_256G U(0x25) #define TZC_REGION_SIZE_512G U(0x26) #define TZC_REGION_SIZE_1T U(0x27) #define TZC_REGION_SIZE_2T U(0x28) #define TZC_REGION_SIZE_4T U(0x29) #define TZC_REGION_SIZE_8T U(0x2a) #define TZC_REGION_SIZE_16T U(0x2b) #define TZC_REGION_SIZE_32T U(0x2c) #define TZC_REGION_SIZE_64T U(0x2d) #define TZC_REGION_SIZE_128T U(0x2e) #define TZC_REGION_SIZE_256T U(0x2f) #define TZC_REGION_SIZE_512T U(0x30) #define TZC_REGION_SIZE_1P U(0x31) #define TZC_REGION_SIZE_2P U(0x32) #define TZC_REGION_SIZE_4P U(0x33) #define TZC_REGION_SIZE_8P U(0x34) #define TZC_REGION_SIZE_16P U(0x35) #define TZC_REGION_SIZE_32P U(0x36) #define TZC_REGION_SIZE_64P U(0x37) #define TZC_REGION_SIZE_128P U(0x38) #define TZC_REGION_SIZE_256P U(0x39) #define TZC_REGION_SIZE_512P U(0x3a) #define TZC_REGION_SIZE_1E U(0x3b) #define TZC_REGION_SIZE_2E U(0x3c) #define TZC_REGION_SIZE_4E U(0x3d) #define TZC_REGION_SIZE_8E U(0x3e) #define TZC_REGION_SIZE_16E U(0x3f) #define TZC_REGION_SIZE_SHIFT 0x1 #define TZC_REGION_SIZE_MASK U(0x7e) #define TZC_ATTR_REGION_SIZE(s) ((s) << TZC_REGION_SIZE_SHIFT) #define TZC_ATTR_REGION_EN_SHIFT 0x0 #define TZC_ATTR_REGION_EN_MASK U(0x1) #define TZC_ATTR_REGION_EN #define TZC_ATTR_REGION_ENABLE U(0x1) #define TZC_ATTR_REGION_DISABLE U(0x0) #define REGION_MAX 16 void tzc380_init(uintptr_t base); void tzc380_configure_region(uint8_t region, uintptr_t region_base, unsigned int attr); void tzc380_set_action(unsigned int action); static inline void tzc_init(uintptr_t base) { tzc380_init(base); } static inline void tzc_configure_region(uint8_t region, uintptr_t region_base, unsigned int attr) { tzc380_configure_region(region, region_base, attr); } static inline void tzc_set_action(unsigned int action) { tzc380_set_action(action); } #endif /* TZC380_H */ trusted-firmware-a-2.2/include/drivers/arm/tzc400.h000066400000000000000000000105271355360272700221730ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TZC400_H #define TZC400_H #include #include #define BUILD_CONFIG_OFF U(0x000) #define GATE_KEEPER_OFF U(0x008) #define SPECULATION_CTRL_OFF U(0x00c) #define INT_STATUS U(0x010) #define INT_CLEAR U(0x014) #define FAIL_ADDRESS_LOW_OFF U(0x020) #define FAIL_ADDRESS_HIGH_OFF U(0x024) #define FAIL_CONTROL_OFF U(0x028) #define FAIL_ID U(0x02c) /* ID registers not common across different varieties of TZC */ #define PID5 U(0xFD4) #define PID6 U(0xFD8) #define PID7 U(0xFDC) #define BUILD_CONFIG_NF_SHIFT 24 #define BUILD_CONFIG_NF_MASK U(0x3) #define BUILD_CONFIG_AW_SHIFT 8 #define BUILD_CONFIG_AW_MASK U(0x3f) #define BUILD_CONFIG_NR_SHIFT 0 #define BUILD_CONFIG_NR_MASK U(0x1f) /* * Number of gate keepers is implementation defined. But we know the max for * this device is 4. Get implementation details from BUILD_CONFIG. */ #define GATE_KEEPER_OS_SHIFT 16 #define GATE_KEEPER_OS_MASK U(0xf) #define GATE_KEEPER_OR_SHIFT 0 #define GATE_KEEPER_OR_MASK U(0xf) #define GATE_KEEPER_FILTER_MASK U(0x1) /* Speculation is enabled by default. */ #define SPECULATION_CTRL_WRITE_DISABLE BIT_32(1) #define SPECULATION_CTRL_READ_DISABLE BIT_32(0) /* Max number of filters allowed is 4. */ #define INT_STATUS_OVERLAP_SHIFT 16 #define INT_STATUS_OVERLAP_MASK U(0xf) #define INT_STATUS_OVERRUN_SHIFT 8 #define INT_STATUS_OVERRUN_MASK U(0xf) #define INT_STATUS_STATUS_SHIFT 0 #define INT_STATUS_STATUS_MASK U(0xf) #define INT_CLEAR_CLEAR_SHIFT 0 #define INT_CLEAR_CLEAR_MASK U(0xf) #define FAIL_CONTROL_DIR_SHIFT 24 #define FAIL_CONTROL_DIR_READ U(0) #define FAIL_CONTROL_DIR_WRITE U(1) #define FAIL_CONTROL_NS_SHIFT 21 #define FAIL_CONTROL_NS_SECURE U(0) #define FAIL_CONTROL_NS_NONSECURE U(1) #define FAIL_CONTROL_PRIV_SHIFT 20 #define FAIL_CONTROL_PRIV_PRIV U(0) #define FAIL_CONTROL_PRIV_UNPRIV U(1) /* * FAIL_ID_ID_MASK depends on AID_WIDTH which is platform specific. * Platform should provide the value on initialisation. */ #define FAIL_ID_VNET_SHIFT 24 #define FAIL_ID_VNET_MASK U(0xf) #define FAIL_ID_ID_SHIFT 0 #define TZC_400_PERIPHERAL_ID U(0x460) /* Filter enable bits in a TZC */ #define TZC_400_REGION_ATTR_F_EN_MASK U(0xf) #define TZC_400_REGION_ATTR_FILTER_BIT(x) \ ((U(1) << (x)) << TZC_REGION_ATTR_F_EN_SHIFT) #define TZC_400_REGION_ATTR_FILTER_BIT_ALL \ (TZC_400_REGION_ATTR_F_EN_MASK << \ TZC_REGION_ATTR_F_EN_SHIFT) /* * All TZC region configuration registers are placed one after another. It * depicts size of block of registers for programming each region. */ #define TZC_400_REGION_SIZE U(0x20) #define TZC_400_ACTION_OFF U(0x4) #ifndef __ASSEMBLER__ #include #include /******************************************************************************* * Function & variable prototypes ******************************************************************************/ void tzc400_init(uintptr_t base); void tzc400_configure_region0(unsigned int sec_attr, unsigned int ns_device_access); void tzc400_configure_region(unsigned int filters, unsigned int region, unsigned long long region_base, unsigned long long region_top, unsigned int sec_attr, unsigned int nsaid_permissions); void tzc400_set_action(unsigned int action); void tzc400_enable_filters(void); void tzc400_disable_filters(void); static inline void tzc_init(uintptr_t base) { tzc400_init(base); } static inline void tzc_configure_region0( unsigned int sec_attr, unsigned int ns_device_access) { tzc400_configure_region0(sec_attr, ns_device_access); } static inline void tzc_configure_region( unsigned int filters, unsigned int region, unsigned long long region_base, unsigned long long region_top, unsigned int sec_attr, unsigned int ns_device_access) { tzc400_configure_region(filters, region, region_base, region_top, sec_attr, ns_device_access); } static inline void tzc_set_action(unsigned int action) { tzc400_set_action(action); } static inline void tzc_enable_filters(void) { tzc400_enable_filters(); } static inline void tzc_disable_filters(void) { tzc400_disable_filters(); } #endif /* __ASSEMBLER__ */ #endif /* TZC400_H */ trusted-firmware-a-2.2/include/drivers/arm/tzc_common.h000066400000000000000000000055331355360272700233200ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TZC_COMMON_H #define TZC_COMMON_H #include /* * Offset of core registers from the start of the base of configuration * registers for each region. */ /* ID Registers */ #define PID0_OFF U(0xfe0) #define PID1_OFF U(0xfe4) #define PID2_OFF U(0xfe8) #define PID3_OFF U(0xfec) #define PID4_OFF U(0xfd0) #define CID0_OFF U(0xff0) #define CID1_OFF U(0xff4) #define CID2_OFF U(0xff8) #define CID3_OFF U(0xffc) /* * What type of action is expected when an access violation occurs. * The memory requested is returned as zero. But we can also raise an event to * let the system know it happened. * We can raise an interrupt(INT) and/or cause an exception(ERR). * TZC_ACTION_NONE - No interrupt, no Exception * TZC_ACTION_ERR - No interrupt, raise exception -> sync external * data abort * TZC_ACTION_INT - Raise interrupt, no exception * TZC_ACTION_ERR_INT - Raise interrupt, raise exception -> sync * external data abort */ #define TZC_ACTION_NONE U(0) #define TZC_ACTION_ERR U(1) #define TZC_ACTION_INT U(2) #define TZC_ACTION_ERR_INT (TZC_ACTION_ERR | TZC_ACTION_INT) /* Bit positions of TZC_ACTION registers */ #define TZC_ACTION_RV_SHIFT 0 #define TZC_ACTION_RV_MASK U(0x3) #define TZC_ACTION_RV_LOWOK U(0x0) #define TZC_ACTION_RV_LOWERR U(0x1) #define TZC_ACTION_RV_HIGHOK U(0x2) #define TZC_ACTION_RV_HIGHERR U(0x3) /* * Controls secure access to a region. If not enabled secure access is not * allowed to region. */ #define TZC_REGION_S_NONE U(0) #define TZC_REGION_S_RD U(1) #define TZC_REGION_S_WR U(2) #define TZC_REGION_S_RDWR (TZC_REGION_S_RD | TZC_REGION_S_WR) #define TZC_REGION_ATTR_S_RD_SHIFT 30 #define TZC_REGION_ATTR_S_WR_SHIFT 31 #define TZC_REGION_ATTR_F_EN_SHIFT 0 #define TZC_REGION_ATTR_SEC_SHIFT 30 #define TZC_REGION_ATTR_S_RD_MASK U(0x1) #define TZC_REGION_ATTR_S_WR_MASK U(0x1) #define TZC_REGION_ATTR_SEC_MASK U(0x3) #define TZC_REGION_ACCESS_WR_EN_SHIFT 16 #define TZC_REGION_ACCESS_RD_EN_SHIFT 0 #define TZC_REGION_ACCESS_ID_MASK U(0xf) /* Macros for allowing Non-Secure access to a region based on NSAID */ #define TZC_REGION_ACCESS_RD(nsaid) \ ((U(1) << ((nsaid) & TZC_REGION_ACCESS_ID_MASK)) << \ TZC_REGION_ACCESS_RD_EN_SHIFT) #define TZC_REGION_ACCESS_WR(nsaid) \ ((U(1) << ((nsaid) & TZC_REGION_ACCESS_ID_MASK)) << \ TZC_REGION_ACCESS_WR_EN_SHIFT) #define TZC_REGION_ACCESS_RDWR(nsaid) \ (TZC_REGION_ACCESS_RD(nsaid) | \ TZC_REGION_ACCESS_WR(nsaid)) /* Returns offset of registers to program for a given region no */ #define TZC_REGION_OFFSET(region_size, region_no) \ ((region_size) * (region_no)) #endif /* TZC_COMMON_H */ trusted-firmware-a-2.2/include/drivers/arm/tzc_dmc500.h000066400000000000000000000114471355360272700230210ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TZC_DMC500_H #define TZC_DMC500_H #include #include #define SI_STATUS_OFFSET U(0x000) #define SI_STATE_CTRL_OFFSET U(0x030) #define SI_FLUSH_CTRL_OFFSET U(0x034) #define SI_INT_CONTROL_OFFSET U(0x048) #define SI_INT_STATUS_OFFSET U(0x004) #define SI_TZ_FAIL_ADDRESS_LOW_OFFSET U(0x008) #define SI_TZ_FAIL_ADDRESS_HIGH_OFFSET U(0x00c) #define SI_FAIL_CONTROL_OFFSET U(0x010) #define SI_FAIL_ID_OFFSET U(0x014) #define SI_INT_CLR_OFFSET U(0x04c) /* * DMC-500 has 2 system interfaces each having a similar set of regs * to configure each interface. */ #define SI0_BASE U(0x0000) #define SI1_BASE U(0x0200) /* Bit positions of SIx_SI_STATUS */ #define SI_EMPTY_SHIFT 1 #define SI_STALL_ACK_SHIFT 0 #define SI_EMPTY_MASK U(0x01) #define SI_STALL_ACK_MASK U(0x01) /* Bit positions of SIx_SI_INT_STATUS */ #define PMU_REQ_INT_OVERFLOW_STATUS_SHIFT 18 #define FAILED_ACCESS_INT_OVERFLOW_STATUS_SHIFT 16 #define PMU_REQ_INT_STATUS_SHIFT 2 #define FAILED_ACCESS_INT_INFO_TZ_OVERLAP_STATUS_SHIFT 1 #define FAILED_ACCESS_INT_STATUS_SHIFT 0 #define PMU_REQ_INT_OVERFLOW_STATUS_MASK U(0x1) #define FAILED_ACCESS_INT_OVERFLOW_STATUS_MASK U(0x1) #define PMU_REQ_INT_STATUS_MASK U(0x1) #define FAILED_ACCESS_INT_INFO_TZ_OVERLAP_STATUS_MASK U(0x1) #define FAILED_ACCESS_INT_STATUS_MASK U(0x1) /* Bit positions of SIx_TZ_FAIL_CONTROL */ #define DIRECTION_SHIFT 24 #define NON_SECURE_SHIFT 21 #define PRIVILEGED_SHIFT 20 #define FAILED_ACCESS_INT_INFO_RANK_MASKED_SHIFT 3 #define FAILED_ACCESS_INT_INFO_UNMAPPED_SHIFT 2 #define FAILED_ACCESS_INT_TZ_FAIL_SHIFT 1 #define FAILED_ACCESS_INT_INFO_OUTSIDE_DEFAULT_SHIFT 0 #define DIRECTION_MASK U(0x1) #define NON_SECURE_MASK U(0x1) #define PRIVILEGED_MASK U(0x1) #define FAILED_ACCESS_INT_INFO_RANK_MASKED_MASK U(0x1) #define FAILED_ACCESS_INT_INFO_UNMAPPED_MASK U(0x1) #define FAILED_ACCESS_INT_TZ_FAIL_MASK U(0x1) #define FAILED_ACCESS_INT_INFO_OUTSIDE_DEFAULT_MASK U(0x1) /* Bit positions of SIx_FAIL_STATUS */ #define FAIL_ID_VNET_SHIFT 24 #define FAIL_ID_ID_SHIFT 0 #define FAIL_ID_VNET_MASK U(0xf) #define FAIL_ID_ID_MASK U(0xffffff) /* Bit positions of SIx_SI_STATE_CONTRL */ #define SI_STALL_REQ_GO 0x0 #define SI_STALL_REQ_STALL 0x1 /* Bit positions of SIx_SI_FLUSH_CONTROL */ #define SI_FLUSH_REQ_INACTIVE 0x0 #define SI_FLUSH_REQ_ACTIVE 0x1 #define SI_FLUSH_REQ_MASK 0x1 /* Bit positions of SIx_SI_INT_CONTROL */ #define PMU_REQ_INT_EN_SHIFT 2 #define OVERLAP_DETECT_INT_EN_SHIFT 1 #define FAILED_ACCESS_INT_EN_SHIFT 0 #define PMU_REQ_INT_EN_MASK U(0x1) #define OVERLAP_DETECT_INT_EN_MASK U(0x1) #define FAILED_ACCESS_INT_EN_MASK U(0x1) #define PMU_REQ_INT_EN U(0x1) #define OVERLAP_DETECT_INT_EN U(0x1) #define FAILED_ACCESS_INT_EN U(0x1) /* Bit positions of SIx_SI_INT_CLR */ #define PMU_REQ_OFLOW_CLR_SHIFT 18 #define FAILED_ACCESS_OFLOW_CLR_SHIFT 16 #define PMU_REQ_INT_CLR_SHIFT 2 #define FAILED_ACCESS_INT_CLR_SHIFT 0 #define PMU_REQ_OFLOW_CLR_MASK U(0x1) #define FAILED_ACCESS_OFLOW_CLR_MASK U(0x1) #define PMU_REQ_INT_CLR_MASK U(0x1) #define FAILED_ACCESS_INT_CLR_MASK U(0x1) #define PMU_REQ_OFLOW_CLR U(0x1) #define FAILED_ACCESS_OFLOW_CLR U(0x1) #define PMU_REQ_INT_CLR U(0x1) #define FAILED_ACCESS_INT_CLR U(0x1) /* Macro to get the correct base register for a system interface */ #define IFACE_OFFSET(sys_if) ((sys_if) ? SI1_BASE : SI0_BASE) #define MAX_SYS_IF_COUNT U(2) #define MAX_REGION_VAL 8 /* DMC-500 supports striping across a max of 4 DMC instances */ #define MAX_DMC_COUNT 4 /* Consist of part_number_1 and part_number_0 */ #define DMC500_PERIPHERAL_ID U(0x0450) /* Filter enable bits in a TZC */ #define TZC_DMC500_REGION_ATTR_F_EN_MASK U(0x1) /* Length of registers for configuring each region */ #define TZC_DMC500_REGION_SIZE U(0x018) #ifndef __ASSEMBLER__ #include /* * Contains the base addresses of all the DMC instances. */ typedef struct tzc_dmc500_driver_data { uintptr_t dmc_base[MAX_DMC_COUNT]; int dmc_count; unsigned int sys_if_count; } tzc_dmc500_driver_data_t; void tzc_dmc500_driver_init(const tzc_dmc500_driver_data_t *plat_driver_data); void tzc_dmc500_configure_region0(unsigned int sec_attr, unsigned int nsaid_permissions); void tzc_dmc500_configure_region(unsigned int region_no, unsigned long long region_base, unsigned long long region_top, unsigned int sec_attr, unsigned int nsaid_permissions); void tzc_dmc500_set_action(unsigned int action); void tzc_dmc500_config_complete(void); int tzc_dmc500_verify_complete(void); #endif /* __ASSEMBLER__ */ #endif /* TZC_DMC500_H */ trusted-firmware-a-2.2/include/drivers/arm/tzc_dmc620.h000066400000000000000000000066711355360272700230270ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TZC_DMC620_H #define TZC_DMC620_H #include /* DMC-620 memc register offsets */ #define DMC620_MEMC_STATUS U(0x0000) #define DMC620_MEMC_CMD U(0x0008) /* Mask value to check the status of memc_cmd register */ #define DMC620_MEMC_CMD_MASK U(0x00000007) /* memc_cmd register's action values */ #define DMC620_MEMC_CMD_GO U(0x00000003) #define DMC620_MEMC_CMD_EXECUTE U(0x00000004) /* Address offsets of access address next region 0 registers */ #define DMC620_ACC_ADDR_MIN_31_00_NEXT_BASE U(0x0080) #define DMC620_ACC_ADDR_MIN_47_32_NEXT_BASE U(0x0084) #define DMC620_ACC_ADDR_MAX_31_00_NEXT_BASE U(0x0088) #define DMC620_ACC_ADDR_MAX_47_32_NEXT_BASE U(0x008c) /* Length of one block of access address next register region */ #define DMC620_ACC_ADDR_NEXT_SIZE U(0x0010) /* Address offsets of access address next registers */ #define DMC620_ACC_ADDR_MIN_31_00_NEXT(region_no) \ (DMC620_ACC_ADDR_MIN_31_00_NEXT_BASE + \ (region_no * DMC620_ACC_ADDR_NEXT_SIZE)) #define DMC620_ACC_ADDR_MIN_47_32_NEXT(region_no) \ (DMC620_ACC_ADDR_MIN_47_32_NEXT_BASE + \ (region_no * DMC620_ACC_ADDR_NEXT_SIZE)) #define DMC620_ACC_ADDR_MAX_31_00_NEXT(region_no) \ (DMC620_ACC_ADDR_MAX_31_00_NEXT_BASE + \ (region_no * DMC620_ACC_ADDR_NEXT_SIZE)) #define DMC620_ACC_ADDR_MAX_47_32_NEXT(region_no) \ (DMC620_ACC_ADDR_MAX_47_32_NEXT_BASE + \ (region_no * DMC620_ACC_ADDR_NEXT_SIZE)) /* Number of TZC address regions in DMC-620 */ #define DMC620_ACC_ADDR_COUNT U(8) /* Width of access address registers */ #define DMC620_ACC_ADDR_WIDTH U(32) /* Peripheral ID registers offsets */ #define DMC620_PERIPHERAL_ID_0 U(0x1fe0) /* Default values in id registers */ #define DMC620_PERIPHERAL_ID_0_VALUE U(0x00000054) /* Secure access region attributes. */ #define TZC_DMC620_REGION_NS_RD U(0x00000001) #define TZC_DMC620_REGION_NS_WR U(0x00000002) #define TZC_DMC620_REGION_NS_RDWR \ (TZC_DMC620_REGION_NS_RD | TZC_DMC620_REGION_NS_WR) #define TZC_DMC620_REGION_S_RD U(0x00000004) #define TZC_DMC620_REGION_S_WR U(0x00000008) #define TZC_DMC620_REGION_S_RDWR \ (TZC_DMC620_REGION_S_RD | TZC_DMC620_REGION_S_WR) #define TZC_DMC620_REGION_S_NS_RDWR \ (TZC_DMC620_REGION_NS_RDWR | TZC_DMC620_REGION_S_RDWR) /* * Contains pointer to the base addresses of all the DMC-620 instances. * 'dmc_count' specifies the number of DMC base addresses contained in the * array pointed to by dmc_base. */ typedef struct tzc_dmc620_driver_data { const uintptr_t *dmc_base; const unsigned int dmc_count; } tzc_dmc620_driver_data_t; /* * Contains region base, region top addresses and corresponding attributes * for configuring TZC access region registers. */ typedef struct tzc_dmc620_acc_addr_data { const unsigned long long region_base; const unsigned long long region_top; const unsigned int sec_attr; } tzc_dmc620_acc_addr_data_t; /* * Contains platform specific data for configuring TZC region base and * region top address. 'acc_addr_count' specifies the number of * valid entries in 'plat_acc_addr_data' array. */ typedef struct tzc_dmc620_config_data { const tzc_dmc620_driver_data_t *plat_drv_data; const tzc_dmc620_acc_addr_data_t *plat_acc_addr_data; const uint8_t acc_addr_count; } tzc_dmc620_config_data_t; /* Function prototypes */ void arm_tzc_dmc620_setup(const tzc_dmc620_config_data_t *plat_config_data); #endif /* TZC_DMC620_H */ trusted-firmware-a-2.2/include/drivers/auth/000077500000000000000000000000001355360272700211535ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/auth/auth_common.h000066400000000000000000000060341355360272700236400ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef AUTH_COMMON_H #define AUTH_COMMON_H /* * Authentication framework common types */ /* * Type of parameters that can be extracted from an image and * used for authentication */ typedef enum auth_param_type_enum { AUTH_PARAM_NONE, AUTH_PARAM_RAW_DATA, /* Raw image data */ AUTH_PARAM_SIG, /* The image signature */ AUTH_PARAM_SIG_ALG, /* The image signature algorithm */ AUTH_PARAM_HASH, /* A hash (including the algorithm) */ AUTH_PARAM_PUB_KEY, /* A public key */ AUTH_PARAM_NV_CTR, /* A non-volatile counter */ } auth_param_type_t; /* * Defines an authentication parameter. The cookie will be interpreted by the * image parser module. */ typedef struct auth_param_type_desc_s { auth_param_type_t type; void *cookie; } auth_param_type_desc_t; /* * Store a pointer to the authentication parameter and its length */ typedef struct auth_param_data_desc_s { void *ptr; unsigned int len; } auth_param_data_desc_t; /* * Authentication parameter descriptor, including type and value */ typedef struct auth_param_desc_s { auth_param_type_desc_t *type_desc; auth_param_data_desc_t data; } auth_param_desc_t; /* * The method type defines how an image is authenticated */ typedef enum auth_method_type_enum { AUTH_METHOD_NONE = 0, AUTH_METHOD_HASH, /* Authenticate by hash matching */ AUTH_METHOD_SIG, /* Authenticate by PK operation */ AUTH_METHOD_NV_CTR, /* Authenticate by Non-Volatile Counter */ AUTH_METHOD_NUM /* Number of methods */ } auth_method_type_t; /* * Parameters for authentication by hash matching */ typedef struct auth_method_param_hash_s { auth_param_type_desc_t *data; /* Data to hash */ auth_param_type_desc_t *hash; /* Hash to match with */ } auth_method_param_hash_t; /* * Parameters for authentication by signature */ typedef struct auth_method_param_sig_s { auth_param_type_desc_t *pk; /* Public key */ auth_param_type_desc_t *sig; /* Signature to check */ auth_param_type_desc_t *alg; /* Signature algorithm */ auth_param_type_desc_t *data; /* Data signed */ } auth_method_param_sig_t; /* * Parameters for authentication by NV counter */ typedef struct auth_method_param_nv_ctr_s { auth_param_type_desc_t *cert_nv_ctr; /* NV counter in certificate */ auth_param_type_desc_t *plat_nv_ctr; /* NV counter in platform */ } auth_method_param_nv_ctr_t; /* * Authentication method descriptor */ typedef struct auth_method_desc_s { auth_method_type_t type; union { auth_method_param_hash_t hash; auth_method_param_sig_t sig; auth_method_param_nv_ctr_t nv_ctr; } param; } auth_method_desc_t; /* * Helper macro to define an authentication parameter type descriptor */ #define AUTH_PARAM_TYPE_DESC(_type, _cookie) \ { \ .type = _type, \ .cookie = (void *)_cookie \ } /* * Helper macro to define an authentication parameter data descriptor */ #define AUTH_PARAM_DATA_DESC(_ptr, _len) \ { \ .ptr = (void *)_ptr, \ .len = (unsigned int)_len \ } #endif /* AUTH_COMMON_H */ trusted-firmware-a-2.2/include/drivers/auth/auth_mod.h000066400000000000000000000024061355360272700231260ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef AUTH_MOD_H #define AUTH_MOD_H #if TRUSTED_BOARD_BOOT #include #include #include #include /* * Image flags */ #define IMG_FLAG_AUTHENTICATED (1 << 0) /* * Authentication image descriptor */ typedef struct auth_img_desc_s { unsigned int img_id; img_type_t img_type; const struct auth_img_desc_s *parent; const auth_method_desc_t *const img_auth_methods; const auth_param_desc_t *const authenticated_data; } auth_img_desc_t; /* Public functions */ void auth_mod_init(void); int auth_mod_get_parent_id(unsigned int img_id, unsigned int *parent_id); int auth_mod_verify_img(unsigned int img_id, void *img_ptr, unsigned int img_len); /* Macro to register a CoT defined as an array of auth_img_desc_t pointers */ #define REGISTER_COT(_cot) \ const auth_img_desc_t *const *const cot_desc_ptr = (_cot); \ unsigned int auth_img_flags[MAX_NUMBER_IDS] extern const auth_img_desc_t *const *const cot_desc_ptr; extern unsigned int auth_img_flags[MAX_NUMBER_IDS]; #endif /* TRUSTED_BOARD_BOOT */ #endif /* AUTH_MOD_H */ trusted-firmware-a-2.2/include/drivers/auth/crypto_mod.h000066400000000000000000000035011355360272700235020ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CRYPTO_MOD_H #define CRYPTO_MOD_H /* Return values */ enum crypto_ret_value { CRYPTO_SUCCESS = 0, CRYPTO_ERR_INIT, CRYPTO_ERR_HASH, CRYPTO_ERR_SIGNATURE, CRYPTO_ERR_UNKNOWN }; /* * Cryptographic library descriptor */ typedef struct crypto_lib_desc_s { const char *name; /* Initialize library. This function is not expected to fail. All errors * must be handled inside the function, asserting or panicing in case of * a non-recoverable error */ void (*init)(void); /* Verify a digital signature. Return one of the * 'enum crypto_ret_value' options */ int (*verify_signature)(void *data_ptr, unsigned int data_len, void *sig_ptr, unsigned int sig_len, void *sig_alg, unsigned int sig_alg_len, void *pk_ptr, unsigned int pk_len); /* Verify a hash. Return one of the 'enum crypto_ret_value' options */ int (*verify_hash)(void *data_ptr, unsigned int data_len, void *digest_info_ptr, unsigned int digest_info_len); } crypto_lib_desc_t; /* Public functions */ void crypto_mod_init(void); int crypto_mod_verify_signature(void *data_ptr, unsigned int data_len, void *sig_ptr, unsigned int sig_len, void *sig_alg_ptr, unsigned int sig_alg_len, void *pk_ptr, unsigned int pk_len); int crypto_mod_verify_hash(void *data_ptr, unsigned int data_len, void *digest_info_ptr, unsigned int digest_info_len); /* Macro to register a cryptographic library */ #define REGISTER_CRYPTO_LIB(_name, _init, _verify_signature, _verify_hash) \ const crypto_lib_desc_t crypto_lib_desc = { \ .name = _name, \ .init = _init, \ .verify_signature = _verify_signature, \ .verify_hash = _verify_hash \ } extern const crypto_lib_desc_t crypto_lib_desc; #endif /* CRYPTO_MOD_H */ trusted-firmware-a-2.2/include/drivers/auth/img_parser_mod.h000066400000000000000000000034141355360272700243150ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMG_PARSER_MOD_H #define IMG_PARSER_MOD_H #include /* * Return values */ enum img_parser_ret_value { IMG_PARSER_OK, IMG_PARSER_ERR, /* Parser internal error */ IMG_PARSER_ERR_FORMAT, /* Malformed image */ IMG_PARSER_ERR_NOT_FOUND /* Authentication data not found */ }; /* * Image types. A parser should be instantiated and registered for each type */ typedef enum img_type_enum { IMG_RAW, /* Binary image */ IMG_PLAT, /* Platform specific format */ IMG_CERT, /* X509v3 certificate */ IMG_MAX_TYPES, } img_type_t; /* Image parser library structure */ typedef struct img_parser_lib_desc_s { img_type_t img_type; const char *name; void (*init)(void); int (*check_integrity)(void *img, unsigned int img_len); int (*get_auth_param)(const auth_param_type_desc_t *type_desc, void *img, unsigned int img_len, void **param, unsigned int *param_len); } img_parser_lib_desc_t; /* Exported functions */ void img_parser_init(void); int img_parser_check_integrity(img_type_t img_type, void *img_ptr, unsigned int img_len); int img_parser_get_auth_param(img_type_t img_type, const auth_param_type_desc_t *type_desc, void *img_ptr, unsigned int img_len, void **param_ptr, unsigned int *param_len); /* Macro to register an image parser library */ #define REGISTER_IMG_PARSER_LIB(_type, _name, _init, _check_int, _get_param) \ static const img_parser_lib_desc_t __img_parser_lib_desc_##_type \ __section(".img_parser_lib_descs") __used = { \ .img_type = _type, \ .name = _name, \ .init = _init, \ .check_integrity = _check_int, \ .get_auth_param = _get_param \ } #endif /* IMG_PARSER_MOD_H */ trusted-firmware-a-2.2/include/drivers/auth/mbedtls/000077500000000000000000000000001355360272700226055ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/auth/mbedtls/mbedtls_common.h000066400000000000000000000003511355360272700257570ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MBEDTLS_COMMON_H #define MBEDTLS_COMMON_H void mbedtls_init(void); #endif /* MBEDTLS_COMMON_H */ trusted-firmware-a-2.2/include/drivers/auth/mbedtls/mbedtls_config.h000066400000000000000000000053231355360272700257400ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MBEDTLS_CONFIG_H #define MBEDTLS_CONFIG_H /* * Key algorithms currently supported on mbed TLS libraries */ #define TF_MBEDTLS_RSA 1 #define TF_MBEDTLS_ECDSA 2 #define TF_MBEDTLS_RSA_AND_ECDSA 3 #define TF_MBEDTLS_USE_RSA (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA \ || TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA) #define TF_MBEDTLS_USE_ECDSA (TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA \ || TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA) /* * Hash algorithms currently supported on mbed TLS libraries */ #define TF_MBEDTLS_SHA256 1 #define TF_MBEDTLS_SHA384 2 #define TF_MBEDTLS_SHA512 3 /* * Configuration file to build mbed TLS with the required features for * Trusted Boot */ #define MBEDTLS_PLATFORM_MEMORY #define MBEDTLS_PLATFORM_NO_STD_FUNCTIONS /* Prevent mbed TLS from using snprintf so that it can use tf_snprintf. */ #define MBEDTLS_PLATFORM_SNPRINTF_ALT #define MBEDTLS_PKCS1_V21 #define MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION #define MBEDTLS_X509_CHECK_KEY_USAGE #define MBEDTLS_X509_CHECK_EXTENDED_KEY_USAGE #define MBEDTLS_ASN1_PARSE_C #define MBEDTLS_ASN1_WRITE_C #define MBEDTLS_BASE64_C #define MBEDTLS_BIGNUM_C #define MBEDTLS_ERROR_C #define MBEDTLS_MD_C #define MBEDTLS_MEMORY_BUFFER_ALLOC_C #define MBEDTLS_OID_C #define MBEDTLS_PK_C #define MBEDTLS_PK_PARSE_C #define MBEDTLS_PK_WRITE_C #define MBEDTLS_PLATFORM_C #if TF_MBEDTLS_USE_ECDSA #define MBEDTLS_ECDSA_C #define MBEDTLS_ECP_C #define MBEDTLS_ECP_DP_SECP256R1_ENABLED #endif #if TF_MBEDTLS_USE_RSA #define MBEDTLS_RSA_C #define MBEDTLS_X509_RSASSA_PSS_SUPPORT #endif #define MBEDTLS_SHA256_C #if (TF_MBEDTLS_HASH_ALG_ID != TF_MBEDTLS_SHA256) #define MBEDTLS_SHA512_C #endif #define MBEDTLS_VERSION_C #define MBEDTLS_X509_USE_C #define MBEDTLS_X509_CRT_PARSE_C /* MPI / BIGNUM options */ #define MBEDTLS_MPI_WINDOW_SIZE 2 #if TF_MBEDTLS_USE_RSA #if TF_MBEDTLS_KEY_SIZE <= 2048 #define MBEDTLS_MPI_MAX_SIZE 256 #else #define MBEDTLS_MPI_MAX_SIZE 512 #endif #else #define MBEDTLS_MPI_MAX_SIZE 256 #endif /* Memory buffer allocator options */ #define MBEDTLS_MEMORY_ALIGN_MULTIPLE 8 #ifndef __ASSEMBLER__ /* System headers required to build mbed TLS with the current configuration */ #include #include #endif /* * Determine Mbed TLS heap size * 13312 = 13*1024 * 11264 = 11*1024 * 7168 = 7*1024 */ #if TF_MBEDTLS_USE_ECDSA #define TF_MBEDTLS_HEAP_SIZE U(13312) #elif TF_MBEDTLS_USE_RSA #if TF_MBEDTLS_KEY_SIZE <= 2048 #define TF_MBEDTLS_HEAP_SIZE U(7168) #else #define TF_MBEDTLS_HEAP_SIZE U(11264) #endif #endif #endif /* MBEDTLS_CONFIG_H */ trusted-firmware-a-2.2/include/drivers/cadence/000077500000000000000000000000001355360272700215745ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/cadence/cdns_uart.h000066400000000000000000000023701355360272700237310ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CDNS_UART_H #define CDNS_UART_H #include /* This is very minimalistic and will only work in QEMU. */ /* CADENCE Registers */ #define R_UART_CR 0 #define R_UART_CR_RXRST (1 << 0) /* RX logic reset */ #define R_UART_CR_TXRST (1 << 1) /* TX logic reset */ #define R_UART_CR_RX_EN (1 << 2) /* RX enabled */ #define R_UART_CR_TX_EN (1 << 4) /* TX enabled */ #define R_UART_SR 0x2C #define UART_SR_INTR_REMPTY_BIT 1 #define UART_SR_INTR_TFUL_BIT 4 #define R_UART_TX 0x30 #define R_UART_RX 0x30 #define CONSOLE_T_CDNS_BASE CONSOLE_T_DRVDATA #ifndef __ASSEMBLER__ #include typedef struct { console_t console; uintptr_t base; } console_cdns_t; /* * Initialize a new Cadence 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_cdns_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, console_cdns_t *console); #endif /*__ASSEMBLER__*/ #endif /* CDNS_UART_H */ trusted-firmware-a-2.2/include/drivers/cfi/000077500000000000000000000000001355360272700207535ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/cfi/v2m_flash.h000066400000000000000000000022331355360272700230050ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef V2M_FLASH_H #define V2M_FLASH_H #include /* First bus cycle */ #define NOR_CMD_READ_ARRAY 0xFF #define NOR_CMD_READ_ID_CODE 0x90 #define NOR_CMD_READ_QUERY 0x98 #define NOR_CMD_READ_STATUS_REG 0x70 #define NOR_CMD_CLEAR_STATUS_REG 0x50 #define NOR_CMD_WRITE_TO_BUFFER 0xE8 #define NOR_CMD_WORD_PROGRAM 0x40 #define NOR_CMD_BLOCK_ERASE 0x20 #define NOR_CMD_LOCK_UNLOCK 0x60 #define NOR_CMD_BLOCK_ERASE_ACK 0xD0 /* Second bus cycle */ #define NOR_LOCK_BLOCK 0x01 #define NOR_UNLOCK_BLOCK 0xD0 /* Status register bits */ #define NOR_DWS (1 << 7) #define NOR_ESS (1 << 6) #define NOR_ES (1 << 5) #define NOR_PS (1 << 4) #define NOR_VPPS (1 << 3) #define NOR_PSS (1 << 2) #define NOR_BLS (1 << 1) #define NOR_BWS (1 << 0) /* Public API */ void nor_send_cmd(uintptr_t base_addr, unsigned long cmd); int nor_word_program(uintptr_t base_addr, unsigned long data); int nor_lock(uintptr_t base_addr); int nor_unlock(uintptr_t base_addr); int nor_erase(uintptr_t base_addr); #endif /* V2M_FLASH_H*/ trusted-firmware-a-2.2/include/drivers/console.h000066400000000000000000000055061355360272700220330ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CONSOLE_H #define CONSOLE_H #include #define CONSOLE_T_NEXT (U(0) * REGSZ) #define CONSOLE_T_FLAGS (U(1) * REGSZ) #define CONSOLE_T_PUTC (U(2) * REGSZ) #define CONSOLE_T_GETC (U(3) * REGSZ) #define CONSOLE_T_FLUSH (U(4) * REGSZ) #define CONSOLE_T_DRVDATA (U(5) * REGSZ) #define CONSOLE_FLAG_BOOT (U(1) << 0) #define CONSOLE_FLAG_RUNTIME (U(1) << 1) #define CONSOLE_FLAG_CRASH (U(1) << 2) /* Bits 3 to 7 reserved for additional scopes in future expansion. */ #define CONSOLE_FLAG_SCOPE_MASK ((U(1) << 8) - 1) /* Bits 8 to 31 for non-scope use. */ #define CONSOLE_FLAG_TRANSLATE_CRLF (U(1) << 8) /* Returned by getc callbacks when receive FIFO is empty. */ #define ERROR_NO_PENDING_CHAR (-1) /* Returned by console_xxx() if no registered console implements xxx. */ #define ERROR_NO_VALID_CONSOLE (-128) #ifndef __ASSEMBLER__ #include typedef struct console { struct console *next; /* * Only the low 32 bits are used. The type is u_register_t to align the * fields of the struct to 64 bits in AArch64 and 32 bits in AArch32 */ u_register_t flags; int (*const putc)(int character, struct console *console); int (*const getc)(struct console *console); int (*const flush)(struct console *console); /* Additional private driver data may follow here. */ } console_t; /* offset macro assertions for console_t */ #include /* * Add a console_t instance to the console list. This should only be called by * console drivers after they have initialized all fields in the console * structure. Platforms seeking to register a new console need to call the * respective console__register() function instead. */ int console_register(console_t *console); /* Remove a single console_t instance from the console list. Return a pointer to * the console that was removed if it was found, or NULL if not. */ console_t *console_unregister(console_t *console); /* Returns 1 if this console is already registered, 0 if not */ int console_is_registered(console_t *console); /* * Set scope mask of a console that determines in what states it is active. * By default they are registered with (CONSOLE_FLAG_BOOT|CONSOLE_FLAG_CRASH). */ void console_set_scope(console_t *console, unsigned int scope); /* Switch to a new global console state (CONSOLE_FLAG_BOOT/RUNTIME/CRASH). */ void console_switch_state(unsigned int new_state); /* Output a character on all consoles registered for the current state. */ int console_putc(int c); /* Read a character (blocking) from any console registered for current state. */ int console_getc(void); /* Flush all consoles registered for the current state. */ int console_flush(void); #endif /* __ASSEMBLER__ */ #endif /* CONSOLE_H */ trusted-firmware-a-2.2/include/drivers/console_assertions.h000066400000000000000000000017741355360272700243100ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CONSOLE_ASSERTIONS_H #define CONSOLE_ASSERTIONS_H #include /* * This file contains some separate assertions about console_t, moved here to * keep them out of the way. Should only be included from . */ CASSERT(CONSOLE_T_NEXT == __builtin_offsetof(console_t, next), assert_console_t_next_offset_mismatch); CASSERT(CONSOLE_T_FLAGS == __builtin_offsetof(console_t, flags), assert_console_t_flags_offset_mismatch); CASSERT(CONSOLE_T_PUTC == __builtin_offsetof(console_t, putc), assert_console_t_putc_offset_mismatch); CASSERT(CONSOLE_T_GETC == __builtin_offsetof(console_t, getc), assert_console_t_getc_offset_mismatch); CASSERT(CONSOLE_T_FLUSH == __builtin_offsetof(console_t, flush), assert_console_t_flush_offset_mismatch); CASSERT(CONSOLE_T_DRVDATA == sizeof(console_t), assert_console_t_drvdata_offset_mismatch); #endif /* CONSOLE_ASSERTIONS_H */ trusted-firmware-a-2.2/include/drivers/coreboot/000077500000000000000000000000001355360272700220265ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/coreboot/cbmem_console.h000066400000000000000000000010421355360272700250010ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CBMEM_CONSOLE_H #define CBMEM_CONSOLE_H #include #define CONSOLE_T_CBMC_BASE CONSOLE_T_DRVDATA #define CONSOLE_T_CBMC_SIZE (CONSOLE_T_DRVDATA + REGSZ) #ifndef __ASSEMBLER__ typedef struct { console_t console; uintptr_t base; uint32_t size; } console_cbmc_t; int console_cbmc_register(uintptr_t base, console_cbmc_t *console); #endif /* __ASSEMBLER__ */ #endif /* CBMEM_CONSOLE_H */ trusted-firmware-a-2.2/include/drivers/delay_timer.h000066400000000000000000000024731355360272700226670ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2019, Linaro Limited * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef DELAY_TIMER_H #define DELAY_TIMER_H #include #include #include /******************************************************************** * A simple timer driver providing synchronous delay functionality. * The driver must be initialized with a structure that provides a * function pointer to return the timer value and a clock * multiplier/divider. The ratio of the multiplier and the divider is * the clock period in microseconds. ********************************************************************/ typedef struct timer_ops { uint32_t (*get_timer_value)(void); uint32_t clk_mult; uint32_t clk_div; } timer_ops_t; static inline uint64_t timeout_cnt_us2cnt(uint32_t us) { return ((uint64_t)us * (uint64_t)read_cntfrq_el0()) / 1000000ULL; } static inline uint64_t timeout_init_us(uint32_t us) { uint64_t cnt = timeout_cnt_us2cnt(us); cnt += read_cntpct_el0(); return cnt; } static inline bool timeout_elapsed(uint64_t expire_cnt) { return read_cntpct_el0() > expire_cnt; } void mdelay(uint32_t msec); void udelay(uint32_t usec); void timer_init(const timer_ops_t *ops_ptr); #endif /* DELAY_TIMER_H */ trusted-firmware-a-2.2/include/drivers/dw_ufs.h000066400000000000000000000067321355360272700216620ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef DW_UFS_H #define DW_UFS_H #include /* Bus Throtting */ #define BUSTHRTL 0xC0 /* Outstanding OCP Requests */ #define OOCPR 0xC4 /* Fatal Error Interrupt Enable */ #define FEIE 0xC8 /* C-Port Direct Access Configuration register */ #define CDACFG 0xD0 /* C-Port Direct Access Transmit 1 register */ #define CDATX1 0xD4 /* C-Port Direct Access Transmit 2 register */ #define CDATX2 0xD8 /* C-Port Direct Access Receive 1 register */ #define CDARX1 0xDC /* C-Port Direct Access Receive 2 register */ #define CDARX2 0xE0 /* C-Port Direct Access Status register */ #define CDASTA 0xE4 /* UPIU Loopback Configuration register */ #define LBMCFG 0xF0 /* UPIU Loopback Status */ #define LBMSTA 0xF4 /* Debug register */ #define DBG 0xF8 /* HClk Divider register */ #define HCLKDIV 0xFC #define TX_HIBERN8TIME_CAP_OFFSET 0x000F #define TX_FSM_STATE_OFFSET 0x0041 #define TX_FSM_STATE_LINE_RESET 7 #define TX_FSM_STATE_LINE_CFG 6 #define TX_FSM_STATE_HS_BURST 5 #define TX_FSM_STATE_LS_BURST 4 #define TX_FSM_STATE_STALL 3 #define TX_FSM_STATE_SLEEP 2 #define TX_FSM_STATE_HIBERN8 1 #define TX_FSM_STATE_DISABLE 0 #define RX_MIN_ACTIVATETIME_CAP_OFFSET 0x008F #define RX_HS_G2_SYNC_LENGTH_CAP_OFFSET 0x0094 #define RX_HS_G3_SYNC_LENGTH_CAP_OFFSET 0x0095 #define PA_AVAIL_TX_DATA_LANES_OFFSET 0x1520 #define PA_TX_SKIP_OFFSET 0x155C #define PA_TX_SKIP_PERIOD_OFFSET 0x155D #define PA_LOCAL_TX_LCC_ENABLE_OFFSET 0x155E #define PA_ACTIVE_TX_DATA_LANES_OFFSET 0x1560 #define PA_CONNECTED_TX_DATA_LANES_OFFSET 0x1561 #define PA_TX_TRAILING_CLOCKS_OFFSET 0x1564 #define PA_TX_GEAR_OFFSET 0x1568 #define PA_TX_TERMINATION_OFFSET 0x1569 #define PA_HS_SERIES_OFFSET 0x156A #define PA_PWR_MODE_OFFSET 0x1571 #define PA_ACTIVE_RX_DATA_LANES_OFFSET 0x1580 #define PA_CONNECTED_RX_DATA_LANES_OFFSET 0x1581 #define PA_RX_PWR_STATUS_OFFSET 0x1582 #define PA_RX_GEAR_OFFSET 0x1583 #define PA_RX_TERMINATION_OFFSET 0x1584 #define PA_SCRAMBLING_OFFSET 0x1585 #define PA_MAX_RX_PWM_GEAR_OFFSET 0x1586 #define PA_MAX_RX_HS_GEAR_OFFSET 0x1587 #define PA_PACP_REQ_TIMEOUT_OFFSET 0x1590 #define PA_PACP_REQ_EOB_TIMEOUT_OFFSET 0x1591 #define PA_REMOTE_VER_INFO_OFFSET 0x15A0 #define PA_LOGICAL_LANE_MAP_OFFSET 0x15A1 #define PA_TACTIVATE_OFFSET 0x15A8 #define PA_PWR_MODE_USER_DATA0_OFFSET 0x15B0 #define PA_PWR_MODE_USER_DATA1_OFFSET 0x15B1 #define PA_PWR_MODE_USER_DATA2_OFFSET 0x15B2 #define PA_PWR_MODE_USER_DATA3_OFFSET 0x15B3 #define PA_PWR_MODE_USER_DATA4_OFFSET 0x15B4 #define PA_PWR_MODE_USER_DATA5_OFFSET 0x15B5 #define DL_TC0_TX_FC_THRESHOLD_OFFSET 0x2040 #define DL_AFC0_CREDIT_THRESHOLD_OFFSET 0x2044 #define DL_TC0_OUT_ACK_THRESHOLD_OFFSET 0x2045 #define DME_FC0_PROTECTION_TIMEOUT_OFFSET 0xD041 #define DME_TC0_REPLAY_TIMEOUT_OFFSET 0xD042 #define DME_AFC0_REQ_TIMEOUT_OFFSET 0xD043 #define DME_FC1_PROTECTION_TIMEOUT_OFFSET 0xD044 #define DME_TC1_REPLAY_TIMEOUT_OFFSET 0xD045 #define DME_AFC1_REQ_TIMEOUT_OFFSET 0xD046 #define VS_MPHY_CFG_UPDT_OFFSET 0xD085 #define VS_MK2_EXTN_SUPPORT_OFFSET 0xD0AB #define VS_MPHY_DISABLE_OFFSET 0xD0C1 #define VS_MPHY_DISABLE_MPHYDIS (1 << 0) typedef struct dw_ufs_params { uintptr_t reg_base; uintptr_t desc_base; size_t desc_size; unsigned long flags; } dw_ufs_params_t; int dw_ufs_init(dw_ufs_params_t *params); #endif /* DW_UFS_H */ trusted-firmware-a-2.2/include/drivers/generic_delay_timer.h000066400000000000000000000005331355360272700243560ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef GENERIC_DELAY_TIMER_H #define GENERIC_DELAY_TIMER_H #include void generic_delay_timer_init_args(uint32_t mult, uint32_t div); void generic_delay_timer_init(void); #endif /* GENERIC_DELAY_TIMER_H */ trusted-firmware-a-2.2/include/drivers/gpio.h000066400000000000000000000020421355360272700213170ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef GPIO_H #define GPIO_H #include #define GPIO_DIR_OUT ARM_TF_GPIO_DIR_OUT #define GPIO_DIR_IN ARM_TF_GPIO_DIR_IN #define GPIO_LEVEL_LOW ARM_TF_GPIO_LEVEL_LOW #define GPIO_LEVEL_HIGH ARM_TF_GPIO_LEVEL_HIGH #define GPIO_PULL_NONE ARM_TF_GPIO_PULL_NONE #define GPIO_PULL_UP ARM_TF_GPIO_PULL_UP #define GPIO_PULL_DOWN ARM_TF_GPIO_PULL_DOWN typedef struct gpio_ops { int (*get_direction)(int gpio); void (*set_direction)(int gpio, int direction); int (*get_value)(int gpio); void (*set_value)(int gpio, int value); void (*set_pull)(int gpio, int pull); int (*get_pull)(int gpio); } gpio_ops_t; int gpio_get_direction(int gpio); void gpio_set_direction(int gpio, int direction); int gpio_get_value(int gpio); void gpio_set_value(int gpio, int value); void gpio_set_pull(int gpio, int pull); int gpio_get_pull(int gpio); void gpio_init(const gpio_ops_t *ops); #endif /* GPIO_H */ trusted-firmware-a-2.2/include/drivers/io/000077500000000000000000000000001355360272700206215ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/io/io_block.h000066400000000000000000000011721355360272700225540ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IO_BLOCK_H #define IO_BLOCK_H #include /* block devices ops */ typedef struct io_block_ops { size_t (*read)(int lba, uintptr_t buf, size_t size); size_t (*write)(int lba, const uintptr_t buf, size_t size); } io_block_ops_t; typedef struct io_block_dev_spec { io_block_spec_t buffer; io_block_ops_t ops; size_t block_size; } io_block_dev_spec_t; struct io_dev_connector; int register_io_dev_block(const struct io_dev_connector **dev_con); #endif /* IO_BLOCK_H */ trusted-firmware-a-2.2/include/drivers/io/io_driver.h000066400000000000000000000033301355360272700227530ustar00rootroot00000000000000/* * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IO_DRIVER_H #define IO_DRIVER_H #include #include /* Generic IO entity structure,representing an accessible IO construct on the * device, such as a file */ typedef struct io_entity { struct io_dev_info *dev_handle; uintptr_t info; } io_entity_t; /* Device info structure, providing device-specific functions and a means of * adding driver-specific state */ typedef struct io_dev_info { const struct io_dev_funcs *funcs; uintptr_t info; } io_dev_info_t; /* Structure used to create a connection to a type of device */ typedef struct io_dev_connector { /* dev_open opens a connection to a particular device driver */ int (*dev_open)(const uintptr_t dev_spec, io_dev_info_t **dev_info); } io_dev_connector_t; /* Structure to hold device driver function pointers */ 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 (*size)(io_entity_t *entity, size_t *length); int (*read)(io_entity_t *entity, uintptr_t buffer, size_t length, size_t *length_read); int (*write)(io_entity_t *entity, const uintptr_t buffer, size_t length, size_t *length_written); int (*close)(io_entity_t *entity); int (*dev_init)(io_dev_info_t *dev_info, const uintptr_t init_params); int (*dev_close)(io_dev_info_t *dev_info); } io_dev_funcs_t; /* Operations intended to be performed during platform initialisation */ /* Register an IO device */ int io_register_device(const io_dev_info_t *dev_info); #endif /* IO_DRIVER_H */ trusted-firmware-a-2.2/include/drivers/io/io_dummy.h000066400000000000000000000004021355360272700226100ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IO_DUMMY_H #define IO_DUMMY_H int register_io_dev_dummy(const struct io_dev_connector **dev_con); #endif /* IO_DUMMY_H */ trusted-firmware-a-2.2/include/drivers/io/io_fip.h000066400000000000000000000004241355360272700222370ustar00rootroot00000000000000/* * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IO_FIP_H #define IO_FIP_H struct io_dev_connector; int register_io_dev_fip(const struct io_dev_connector **dev_con); #endif /* IO_FIP_H */ trusted-firmware-a-2.2/include/drivers/io/io_memmap.h000066400000000000000000000004401355360272700227330ustar00rootroot00000000000000/* * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IO_MEMMAP_H #define IO_MEMMAP_H struct io_dev_connector; int register_io_dev_memmap(const struct io_dev_connector **dev_con); #endif /* IO_MEMMAP_H */ trusted-firmware-a-2.2/include/drivers/io/io_semihosting.h000066400000000000000000000004531355360272700240140ustar00rootroot00000000000000/* * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IO_SEMIHOSTING_H #define IO_SEMIHOSTING_H struct io_dev_connector; int register_io_dev_sh(const struct io_dev_connector **dev_con); #endif /* IO_SEMIHOSTING_H */ trusted-firmware-a-2.2/include/drivers/io/io_storage.h000066400000000000000000000044621355360272700231330ustar00rootroot00000000000000/* * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IO_STORAGE_H #define IO_STORAGE_H #include #include #include /* For ssize_t */ #include /* Device type which can be used to enable policy decisions about which device * to access */ typedef enum { IO_TYPE_INVALID, IO_TYPE_SEMIHOSTING, IO_TYPE_MEMMAP, IO_TYPE_DUMMY, IO_TYPE_FIRMWARE_IMAGE_PACKAGE, IO_TYPE_BLOCK, IO_TYPE_MMC, IO_TYPE_STM32IMAGE, IO_TYPE_MAX } io_type_t; /* Modes used when seeking data on a supported device */ typedef enum { IO_SEEK_INVALID, IO_SEEK_SET, IO_SEEK_END, IO_SEEK_CUR, IO_SEEK_MAX } io_seek_mode_t; /* Connector type, providing a means of identifying a device to open */ struct io_dev_connector; /* File specification - used to refer to data on a device supporting file-like * entities */ typedef struct io_file_spec { const char *path; unsigned int mode; } io_file_spec_t; /* UUID specification - used to refer to data accessed using UUIDs (i.e. FIP * images) */ typedef struct io_uuid_spec { const uuid_t uuid; } io_uuid_spec_t; /* Block specification - used to refer to data on a device supporting * block-like entities */ typedef struct io_block_spec { size_t offset; size_t length; } io_block_spec_t; /* Access modes used when accessing data on a device */ #define IO_MODE_INVALID (0) #define IO_MODE_RO (1 << 0) #define IO_MODE_RW (1 << 1) /* Open a connection to a device */ int io_dev_open(const struct io_dev_connector *dev_con, const uintptr_t dev_spec, uintptr_t *handle); /* Initialise a device explicitly - to permit lazy initialisation or * re-initialisation */ int io_dev_init(uintptr_t dev_handle, const uintptr_t init_params); /* Close a connection to a device */ 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_size(uintptr_t handle, size_t *length); int io_read(uintptr_t handle, uintptr_t buffer, size_t length, size_t *length_read); int io_write(uintptr_t handle, const uintptr_t buffer, size_t length, size_t *length_written); int io_close(uintptr_t handle); #endif /* IO_STORAGE_H */ trusted-firmware-a-2.2/include/drivers/marvell/000077500000000000000000000000001355360272700216545ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/marvell/addr_map.h000066400000000000000000000005701355360272700235760ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* Address map types for Marvell address translation unit drivers */ #ifndef ADDR_MAP_H #define ADDR_MAP_H #include struct addr_map_win { uint64_t base_addr; uint64_t win_size; uint32_t target_id; }; #endif /* ADDR_MAP_H */ trusted-firmware-a-2.2/include/drivers/marvell/amb_adec.h000066400000000000000000000013361355360272700235430ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* AXI to M-Bridge decoding unit driver for Marvell Armada 8K and 8K+ SoCs */ #ifndef AMB_ADEC_H #define AMB_ADEC_H #include enum amb_attribute_ids { AMB_SPI0_CS0_ID = 0x1E, AMB_SPI0_CS1_ID = 0x5E, AMB_SPI0_CS2_ID = 0x9E, AMB_SPI0_CS3_ID = 0xDE, AMB_SPI1_CS0_ID = 0x1A, AMB_SPI1_CS1_ID = 0x5A, AMB_SPI1_CS2_ID = 0x9A, AMB_SPI1_CS3_ID = 0xDA, AMB_DEV_CS0_ID = 0x3E, AMB_DEV_CS1_ID = 0x3D, AMB_DEV_CS2_ID = 0x3B, AMB_DEV_CS3_ID = 0x37, AMB_BOOT_CS_ID = 0x2f, AMB_BOOT_ROM_ID = 0x1D, }; #define AMB_MAX_WIN_ID 7 int init_amb_adec(uintptr_t base); #endif /* AMB_ADEC_H */ trusted-firmware-a-2.2/include/drivers/marvell/ap807_clocks_init.h000066400000000000000000000004241355360272700252450ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef AP807_INIT_CLOCKS_H #define AP807_INIT_CLOCKS_H void ap807_clocks_init(unsigned int freq_option); #endif /* AP807_INIT_CLOCKS_H */ trusted-firmware-a-2.2/include/drivers/marvell/aro.h000066400000000000000000000020571355360272700226120ustar00rootroot00000000000000/* * Copyright (C) 2017 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef ARO_H #define ARO_H enum hws_freq { CPU_FREQ_2000, CPU_FREQ_1800, CPU_FREQ_1600, CPU_FREQ_1400, CPU_FREQ_1300, CPU_FREQ_1200, CPU_FREQ_1000, CPU_FREQ_600, CPU_FREQ_800, DDR_FREQ_LAST, DDR_FREQ_SAR }; enum cpu_clock_freq_mode { CPU_2000_DDR_1200_RCLK_1200 = 0x0, CPU_2000_DDR_1050_RCLK_1050 = 0x1, CPU_1600_DDR_800_RCLK_800 = 0x4, CPU_1800_DDR_1200_RCLK_1200 = 0x6, CPU_1800_DDR_1050_RCLK_1050 = 0x7, CPU_1600_DDR_900_RCLK_900 = 0x0B, CPU_1600_DDR_1050_RCLK_1050 = 0x0D, CPU_1600_DDR_1200_RCLK_1200 = 0x0D, CPU_1600_DDR_900_RCLK_900_2 = 0x0E, CPU_1000_DDR_650_RCLK_650 = 0x13, CPU_1300_DDR_800_RCLK_800 = 0x14, CPU_1300_DDR_650_RCLK_650 = 0x17, CPU_1200_DDR_800_RCLK_800 = 0x19, CPU_1400_DDR_800_RCLK_800 = 0x1a, CPU_600_DDR_800_RCLK_800 = 0x1B, CPU_800_DDR_800_RCLK_800 = 0x1C, CPU_1000_DDR_800_RCLK_800 = 0x1D, CPU_DDR_RCLK_INVALID }; int init_aro(void); #endif /* ARO_H */ trusted-firmware-a-2.2/include/drivers/marvell/cache_llc.h000066400000000000000000000022561355360272700237270ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* LLC driver is the Last Level Cache (L3C) driver * for Marvell SoCs in AP806, AP807, and AP810 */ #ifndef CACHE_LLC_H #define CACHE_LLC_H #define LLC_CTRL(ap) (MVEBU_LLC_BASE(ap) + 0x100) #define LLC_SYNC(ap) (MVEBU_LLC_BASE(ap) + 0x700) #define L2X0_INV_WAY(ap) (MVEBU_LLC_BASE(ap) + 0x77C) #define L2X0_CLEAN_WAY(ap) (MVEBU_LLC_BASE(ap) + 0x7BC) #define L2X0_CLEAN_INV_WAY(ap) (MVEBU_LLC_BASE(ap) + 0x7FC) #define LLC_TC0_LOCK(ap) (MVEBU_LLC_BASE(ap) + 0x920) #define MASTER_LLC_CTRL LLC_CTRL(MVEBU_AP0) #define MASTER_L2X0_INV_WAY L2X0_INV_WAY(MVEBU_AP0) #define MASTER_LLC_TC0_LOCK LLC_TC0_LOCK(MVEBU_AP0) #define LLC_CTRL_EN 1 #define LLC_EXCLUSIVE_EN 0x100 #define LLC_WAY_MASK 0xFFFFFFFF #ifndef __ASSEMBLER__ void llc_cache_sync(int ap_index); void llc_flush_all(int ap_index); void llc_clean_all(int ap_index); void llc_inv_all(int ap_index); void llc_disable(int ap_index); void llc_enable(int ap_index, int excl_mode); int llc_is_exclusive(int ap_index); void llc_runtime_enable(int ap_index); #endif #endif /* CACHE_LLC_H */ trusted-firmware-a-2.2/include/drivers/marvell/ccu.h000066400000000000000000000030371355360272700226020ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* CCU unit device driver for Marvell AP807, AP807 and AP810 SoCs */ #ifndef CCU_H #define CCU_H #ifndef __ASSEMBLER__ #include #endif /* CCU registers definitions */ #define CCU_WIN_CR_OFFSET(ap, win) (MVEBU_CCU_BASE(ap) + 0x0 + \ (0x10 * win)) #define CCU_TARGET_ID_OFFSET (8) #define CCU_TARGET_ID_MASK (0x7F) #define CCU_WIN_SCR_OFFSET(ap, win) (MVEBU_CCU_BASE(ap) + 0x4 + \ (0x10 * win)) #define CCU_WIN_ENA_WRITE_SECURE (0x1) #define CCU_WIN_ENA_READ_SECURE (0x2) #define CCU_WIN_ALR_OFFSET(ap, win) (MVEBU_CCU_BASE(ap) + 0x8 + \ (0x10 * win)) #define CCU_WIN_AHR_OFFSET(ap, win) (MVEBU_CCU_BASE(ap) + 0xC + \ (0x10 * win)) #define CCU_WIN_GCR_OFFSET(ap) (MVEBU_CCU_BASE(ap) + 0xD0) #define CCU_GCR_TARGET_OFFSET (8) #define CCU_GCR_TARGET_MASK (0xFF) #define CCU_SRAM_WIN_CR CCU_WIN_CR_OFFSET(MVEBU_AP0, 1) #ifndef __ASSEMBLER__ int init_ccu(int); void ccu_win_check(struct addr_map_win *win); void ccu_enable_win(int ap_index, struct addr_map_win *win, uint32_t win_id); void ccu_temp_win_insert(int ap_index, struct addr_map_win *win, int size); void ccu_temp_win_remove(int ap_index, struct addr_map_win *win, int size); void ccu_dram_win_config(int ap_index, struct addr_map_win *win); void ccu_dram_target_set(int ap_index, uint32_t target); void ccu_save_win_all(int ap_id); void ccu_restore_win_all(int ap_id); #endif #endif /* CCU_H */ trusted-firmware-a-2.2/include/drivers/marvell/gwin.h000066400000000000000000000007151355360272700227740ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* GWIN unit device driver for Marvell AP810 SoC */ #ifndef GWIN_H #define GWIN_H #include int init_gwin(int ap_index); void gwin_temp_win_insert(int ap_index, struct addr_map_win *win, int size); void gwin_temp_win_remove(int ap_index, struct addr_map_win *win, int size); #endif /* GWIN_H */ trusted-firmware-a-2.2/include/drivers/marvell/i2c.h000066400000000000000000000006031355360272700225010ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef I2C_H #define I2C_H void i2c_init(void); int i2c_read(uint8_t chip, unsigned int addr, int alen, uint8_t *buffer, int len); int i2c_write(uint8_t chip, unsigned int addr, int alen, uint8_t *buffer, int len); #endif /* I2C_H */ trusted-firmware-a-2.2/include/drivers/marvell/io_win.h000066400000000000000000000010611355360272700233070ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* IO Window unit device driver for Marvell AP807, AP807 and AP810 SoCs */ #ifndef IO_WIN_H #define IO_WIN_H #include int init_io_win(int ap_index); void iow_temp_win_insert(int ap_index, struct addr_map_win *win, int size); void iow_temp_win_remove(int ap_index, struct addr_map_win *win, int size); void iow_save_win_all(int ap_id); void iow_restore_win_all(int ap_id); #endif /* IO_WIN_H */ trusted-firmware-a-2.2/include/drivers/marvell/iob.h000066400000000000000000000011131355360272700225720ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* IOW unit device driver for Marvell CP110 and CP115 SoCs */ #ifndef IOB_H #define IOB_H #include enum target_ids_iob { INTERNAL_TID = 0x0, MCI0_TID = 0x1, PEX1_TID = 0x2, PEX2_TID = 0x3, PEX0_TID = 0x4, NAND_TID = 0x5, RUNIT_TID = 0x6, MCI1_TID = 0x7, IOB_MAX_TID }; int init_iob(uintptr_t base); void iob_cfg_space_update(int ap_idx, int cp_idx, uintptr_t base, uintptr_t new_base); #endif /* IOB_H */ trusted-firmware-a-2.2/include/drivers/marvell/mci.h000066400000000000000000000005561355360272700226030ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* MCI bus driver for Marvell ARMADA 8K and 8K+ SoCs */ #ifndef MCI_H #define MCI_H int mci_initialize(int mci_index); void mci_turn_link_down(void); void mci_turn_link_on(void); int mci_get_link_status(void); #endif /* MCI_H */ trusted-firmware-a-2.2/include/drivers/marvell/mochi/000077500000000000000000000000001355360272700227535ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/marvell/mochi/ap_setup.h000066400000000000000000000004521355360272700247450ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* AP8xx Marvell SoC driver */ #ifndef AP_SETUP_H #define AP_SETUP_H void ap_init(void); void ap_ble_init(void); int ap_get_count(void); #endif /* AP_SETUP_H */ trusted-firmware-a-2.2/include/drivers/marvell/mochi/cp110_setup.h000066400000000000000000000027531355360272700251770ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* CP110 Marvell SoC driver */ #ifndef CP110_SETUP_H #define CP110_SETUP_H #include #include #define MVEBU_DEVICE_ID_REG (MVEBU_CP_DFX_OFFSET + 0x40) #define MVEBU_DEVICE_ID_OFFSET (0) #define MVEBU_DEVICE_ID_MASK (0xffff << MVEBU_DEVICE_ID_OFFSET) #define MVEBU_DEVICE_REV_OFFSET (16) #define MVEBU_DEVICE_REV_MASK (0xf << MVEBU_DEVICE_REV_OFFSET) #define MVEBU_70X0_DEV_ID (0x7040) #define MVEBU_70X0_CP115_DEV_ID (0x7045) #define MVEBU_3900_DEV_ID (0x6025) #define MVEBU_80X0_DEV_ID (0x8040) #define MVEBU_80X0_CP115_DEV_ID (0x8045) #define MVEBU_CP110_SA_DEV_ID (0x110) #define MVEBU_CP110_REF_ID_A1 1 #define MVEBU_CP110_REF_ID_A2 2 #define MAX_STREAM_ID_PER_CP (0x10) #define STREAM_ID_BASE (0x40) static inline uint32_t cp110_device_id_get(uintptr_t base) { /* Returns: * - MVEBU_70X0_DEV_ID for A70X0 family * - MVEBU_80X0_DEV_ID for A80X0 family * - MVEBU_CP110_SA_DEV_ID for CP that connected stand alone */ return (mmio_read_32(base + MVEBU_DEVICE_ID_REG) >> MVEBU_DEVICE_ID_OFFSET) & MVEBU_DEVICE_ID_MASK; } static inline uint32_t cp110_rev_id_get(uintptr_t base) { return (mmio_read_32(base + MVEBU_DEVICE_ID_REG) & MVEBU_DEVICE_REV_MASK) >> MVEBU_DEVICE_REV_OFFSET; } void cp110_init(uintptr_t cp110_base, uint32_t stream_id); void cp110_ble_init(uintptr_t cp110_base); #endif /* CP110_SETUP_H */ trusted-firmware-a-2.2/include/drivers/marvell/thermal.h000066400000000000000000000014161355360272700234630ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* Driver for thermal unit located in Marvell ARMADA 8K and compatible SoCs */ #ifndef THERMAL_H #define THERMAL_H struct tsen_config { /* thermal temperature parameters */ int tsen_offset; int tsen_gain; int tsen_divisor; /* thermal data */ int tsen_ready; void *regs_base; /* thermal functionality */ int (*ptr_tsen_probe)(struct tsen_config *cfg); int (*ptr_tsen_read)(struct tsen_config *cfg, int *temp); }; /* Thermal driver APIs */ int marvell_thermal_init(struct tsen_config *tsen_cfg); int marvell_thermal_read(struct tsen_config *tsen_cfg, int *temp); struct tsen_config *marvell_thermal_config_get(void); #endif /* THERMAL_H */ trusted-firmware-a-2.2/include/drivers/marvell/uart/000077500000000000000000000000001355360272700226275ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/marvell/uart/a3700_console.h000066400000000000000000000046251355360272700252630ustar00rootroot00000000000000/* * Copyright (C) 2016 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef A3700_CONSOLE_H #define A3700_CONSOLE_H #include /* MVEBU UART Registers */ #define UART_RX_REG 0x00 #define UART_TX_REG 0x04 #define UART_CTRL_REG 0x08 #define UART_STATUS_REG 0x0c #define UART_BAUD_REG 0x10 #define UART_POSSR_REG 0x14 /* FIFO Control Register bits */ #define UARTFCR_FIFOMD_16450 (0 << 6) #define UARTFCR_FIFOMD_16550 (1 << 6) #define UARTFCR_RXTRIG_1 (0 << 6) #define UARTFCR_RXTRIG_4 (1 << 6) #define UARTFCR_RXTRIG_8 (2 << 6) #define UARTFCR_RXTRIG_16 (3 << 6) #define UARTFCR_TXTRIG_1 (0 << 4) #define UARTFCR_TXTRIG_4 (1 << 4) #define UARTFCR_TXTRIG_8 (2 << 4) #define UARTFCR_TXTRIG_16 (3 << 4) #define UARTFCR_DMAEN (1 << 3) /* Enable DMA mode */ #define UARTFCR_TXCLR (1 << 2) /* Clear contents of Tx FIFO */ #define UARTFCR_RXCLR (1 << 1) /* Clear contents of Rx FIFO */ #define UARTFCR_FIFOEN (1 << 0) /* Enable the Tx/Rx FIFO */ /* Line Control Register bits */ #define UARTLCR_DLAB (1 << 7) /* Divisor Latch Access */ #define UARTLCR_SETB (1 << 6) /* Set BREAK Condition */ #define UARTLCR_SETP (1 << 5) /* Set Parity to LCR[4] */ #define UARTLCR_EVEN (1 << 4) /* Even Parity Format */ #define UARTLCR_PAR (1 << 3) /* Parity */ #define UARTLCR_STOP (1 << 2) /* Stop Bit */ #define UARTLCR_WORDSZ_5 0 /* Word Length of 5 */ #define UARTLCR_WORDSZ_6 1 /* Word Length of 6 */ #define UARTLCR_WORDSZ_7 2 /* Word Length of 7 */ #define UARTLCR_WORDSZ_8 3 /* Word Length of 8 */ /* Line Status Register bits */ #define UARTLSR_TXFIFOFULL (1 << 11) /* Tx Fifo Full */ /* UART Control Register bits */ #define UART_CTRL_RXFIFO_RESET (1 << 14) #define UART_CTRL_TXFIFO_RESET (1 << 15) #define UARTLSR_TXFIFOEMPTY (1 << 6) #define CONSOLE_T_A3700_BASE CONSOLE_T_DRVDATA #ifndef __ASSEMBLER__ #include typedef struct { console_t console; uintptr_t base; } console_a3700_t; /* * Initialize a new a3700 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_a3700_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, console_a3700_t *console); #endif /*__ASSEMBLER__*/ #endif /* A3700_CONSOLE_H */ trusted-firmware-a-2.2/include/drivers/mentor/000077500000000000000000000000001355360272700215165ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/mentor/mi2cv.h000066400000000000000000000021251355360272700227070ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * Copyright (C) 2018 Icenowy Zheng * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* This driver provides support for Mentor Graphics MI2CV IP core */ #ifndef MI2CV_H #define MI2CV_H #include /* * Initialization, must be called once on start up, may be called * repeatedly to change the speed and slave addresses. */ void i2c_init(void *i2c_base); /* * Read/Write interface: * chip: I2C chip address, range 0..127 * addr: Memory (register) address within the chip * alen: Number of bytes to use for addr (typically 1, 2 for larger * memories, 0 for register type devices with only one * register) * buffer: Where to read/write the data * len: How many bytes to read/write * * Returns: 0 on success, not 0 on failure */ int i2c_read(uint8_t chip, unsigned int addr, int alen, uint8_t *buffer, int len); int i2c_write(uint8_t chip, unsigned int addr, int alen, uint8_t *buffer, int len); #endif /* MI2CV_H */ trusted-firmware-a-2.2/include/drivers/mmc.h000066400000000000000000000156161355360272700211500ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MMC_H #define MMC_H #include #include #define MMC_BLOCK_SIZE U(512) #define MMC_BLOCK_MASK (MMC_BLOCK_SIZE - U(1)) #define MMC_BOOT_CLK_RATE (400 * 1000) #define MMC_CMD(_x) U(_x) #define MMC_ACMD(_x) U(_x) #define OCR_POWERUP BIT(31) #define OCR_HCS BIT(30) #define OCR_BYTE_MODE (U(0) << 29) #define OCR_SECTOR_MODE (U(2) << 29) #define OCR_ACCESS_MODE_MASK (U(3) << 29) #define OCR_3_5_3_6 BIT(23) #define OCR_3_4_3_5 BIT(22) #define OCR_3_3_3_4 BIT(21) #define OCR_3_2_3_3 BIT(20) #define OCR_3_1_3_2 BIT(19) #define OCR_3_0_3_1 BIT(18) #define OCR_2_9_3_0 BIT(17) #define OCR_2_8_2_9 BIT(16) #define OCR_2_7_2_8 BIT(15) #define OCR_VDD_MIN_2V7 GENMASK(23, 15) #define OCR_VDD_MIN_2V0 GENMASK(14, 8) #define OCR_VDD_MIN_1V7 BIT(7) #define MMC_RSP_48 BIT(0) #define MMC_RSP_136 BIT(1) /* 136 bit response */ #define MMC_RSP_CRC BIT(2) /* expect valid crc */ #define MMC_RSP_CMD_IDX BIT(3) /* response contains cmd idx */ #define MMC_RSP_BUSY BIT(4) /* device may be busy */ /* JEDEC 4.51 chapter 6.12 */ #define MMC_RESPONSE_R1 (MMC_RSP_48 | MMC_RSP_CMD_IDX | MMC_RSP_CRC) #define MMC_RESPONSE_R1B (MMC_RESPONSE_R1 | MMC_RSP_BUSY) #define MMC_RESPONSE_R2 (MMC_RSP_48 | MMC_RSP_136 | MMC_RSP_CRC) #define MMC_RESPONSE_R3 (MMC_RSP_48) #define MMC_RESPONSE_R4 (MMC_RSP_48) #define MMC_RESPONSE_R5 (MMC_RSP_48 | MMC_RSP_CRC | MMC_RSP_CMD_IDX) #define MMC_RESPONSE_R6 (MMC_RSP_48 | MMC_RSP_CRC | MMC_RSP_CMD_IDX) #define MMC_RESPONSE_R7 (MMC_RSP_48 | MMC_RSP_CRC | MMC_RSP_CMD_IDX) /* Value randomly chosen for eMMC RCA, it should be > 1 */ #define MMC_FIX_RCA 6 #define RCA_SHIFT_OFFSET 16 #define CMD_EXTCSD_PARTITION_CONFIG 179 #define CMD_EXTCSD_BUS_WIDTH 183 #define CMD_EXTCSD_HS_TIMING 185 #define CMD_EXTCSD_SEC_CNT 212 #define PART_CFG_BOOT_PARTITION1_ENABLE (U(1) << 3) #define PART_CFG_PARTITION1_ACCESS (U(1) << 0) /* Values in EXT CSD register */ #define MMC_BUS_WIDTH_1 U(0) #define MMC_BUS_WIDTH_4 U(1) #define MMC_BUS_WIDTH_8 U(2) #define MMC_BUS_WIDTH_DDR_4 U(5) #define MMC_BUS_WIDTH_DDR_8 U(6) #define MMC_BOOT_MODE_BACKWARD (U(0) << 3) #define MMC_BOOT_MODE_HS_TIMING (U(1) << 3) #define MMC_BOOT_MODE_DDR (U(2) << 3) #define EXTCSD_SET_CMD (U(0) << 24) #define EXTCSD_SET_BITS (U(1) << 24) #define EXTCSD_CLR_BITS (U(2) << 24) #define EXTCSD_WRITE_BYTES (U(3) << 24) #define EXTCSD_CMD(x) (((x) & 0xff) << 16) #define EXTCSD_VALUE(x) (((x) & 0xff) << 8) #define EXTCSD_CMD_SET_NORMAL U(1) #define CSD_TRAN_SPEED_UNIT_MASK GENMASK(2, 0) #define CSD_TRAN_SPEED_MULT_MASK GENMASK(6, 3) #define CSD_TRAN_SPEED_MULT_SHIFT 3 #define STATUS_CURRENT_STATE(x) (((x) & 0xf) << 9) #define STATUS_READY_FOR_DATA BIT(8) #define STATUS_SWITCH_ERROR BIT(7) #define MMC_GET_STATE(x) (((x) >> 9) & 0xf) #define MMC_STATE_IDLE 0 #define MMC_STATE_READY 1 #define MMC_STATE_IDENT 2 #define MMC_STATE_STBY 3 #define MMC_STATE_TRAN 4 #define MMC_STATE_DATA 5 #define MMC_STATE_RCV 6 #define MMC_STATE_PRG 7 #define MMC_STATE_DIS 8 #define MMC_STATE_BTST 9 #define MMC_STATE_SLP 10 #define MMC_FLAG_CMD23 (U(1) << 0) #define CMD8_CHECK_PATTERN U(0xAA) #define VHS_2_7_3_6_V BIT(8) #define SD_SCR_BUS_WIDTH_1 BIT(8) #define SD_SCR_BUS_WIDTH_4 BIT(10) struct mmc_cmd { unsigned int cmd_idx; unsigned int cmd_arg; unsigned int resp_type; unsigned int resp_data[4]; }; struct mmc_ops { void (*init)(void); int (*send_cmd)(struct mmc_cmd *cmd); int (*set_ios)(unsigned int clk, unsigned int width); int (*prepare)(int lba, uintptr_t buf, size_t size); int (*read)(int lba, uintptr_t buf, size_t size); int (*write)(int lba, const uintptr_t buf, size_t size); }; struct mmc_csd_emmc { unsigned int not_used: 1; unsigned int crc: 7; unsigned int ecc: 2; unsigned int file_format: 2; unsigned int tmp_write_protect: 1; unsigned int perm_write_protect: 1; unsigned int copy: 1; unsigned int file_format_grp: 1; unsigned int reserved_1: 5; unsigned int write_bl_partial: 1; unsigned int write_bl_len: 4; unsigned int r2w_factor: 3; unsigned int default_ecc: 2; unsigned int wp_grp_enable: 1; unsigned int wp_grp_size: 5; unsigned int erase_grp_mult: 5; unsigned int erase_grp_size: 5; unsigned int c_size_mult: 3; unsigned int vdd_w_curr_max: 3; unsigned int vdd_w_curr_min: 3; unsigned int vdd_r_curr_max: 3; unsigned int vdd_r_curr_min: 3; unsigned int c_size_low: 2; unsigned int c_size_high: 10; unsigned int reserved_2: 2; unsigned int dsr_imp: 1; unsigned int read_blk_misalign: 1; unsigned int write_blk_misalign: 1; unsigned int read_bl_partial: 1; unsigned int read_bl_len: 4; unsigned int ccc: 12; unsigned int tran_speed: 8; unsigned int nsac: 8; unsigned int taac: 8; unsigned int reserved_3: 2; unsigned int spec_vers: 4; unsigned int csd_structure: 2; }; struct mmc_csd_sd_v2 { unsigned int not_used: 1; unsigned int crc: 7; unsigned int reserved_1: 2; unsigned int file_format: 2; unsigned int tmp_write_protect: 1; unsigned int perm_write_protect: 1; unsigned int copy: 1; unsigned int file_format_grp: 1; unsigned int reserved_2: 5; unsigned int write_bl_partial: 1; unsigned int write_bl_len: 4; unsigned int r2w_factor: 3; unsigned int reserved_3: 2; unsigned int wp_grp_enable: 1; unsigned int wp_grp_size: 7; unsigned int sector_size: 7; unsigned int erase_block_en: 1; unsigned int reserved_4: 1; unsigned int c_size_low: 16; unsigned int c_size_high: 6; unsigned int reserved_5: 6; unsigned int dsr_imp: 1; unsigned int read_blk_misalign: 1; unsigned int write_blk_misalign: 1; unsigned int read_bl_partial: 1; unsigned int read_bl_len: 4; unsigned int ccc: 12; unsigned int tran_speed: 8; unsigned int nsac: 8; unsigned int taac: 8; unsigned int reserved_6: 6; unsigned int csd_structure: 2; }; enum mmc_device_type { MMC_IS_EMMC, MMC_IS_SD, MMC_IS_SD_HC, }; struct mmc_device_info { unsigned long long device_size; /* Size of device in bytes */ unsigned int block_size; /* Block size in bytes */ unsigned int max_bus_freq; /* Max bus freq in Hz */ unsigned int ocr_voltage; /* OCR voltage */ enum mmc_device_type mmc_dev_type; /* Type of MMC */ }; size_t mmc_read_blocks(int lba, uintptr_t buf, size_t size); size_t mmc_write_blocks(int lba, const uintptr_t buf, size_t size); size_t mmc_erase_blocks(int lba, size_t size); size_t mmc_rpmb_read_blocks(int lba, uintptr_t buf, size_t size); size_t mmc_rpmb_write_blocks(int lba, const uintptr_t buf, size_t size); size_t mmc_rpmb_erase_blocks(int lba, size_t size); int mmc_init(const struct mmc_ops *ops_ptr, unsigned int clk, unsigned int width, unsigned int flags, struct mmc_device_info *device_info); #endif /* MMC_H */ trusted-firmware-a-2.2/include/drivers/partition/000077500000000000000000000000001355360272700222235ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/partition/gpt.h000066400000000000000000000024761355360272700231770ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef GPT_H #define GPT_H #include #define PARTITION_TYPE_GPT 0xee #define GPT_HEADER_OFFSET PLAT_PARTITION_BLOCK_SIZE #define GPT_ENTRY_OFFSET (GPT_HEADER_OFFSET + \ PLAT_PARTITION_BLOCK_SIZE) #define GUID_LEN 16 #define GPT_SIGNATURE "EFI PART" typedef struct gpt_entry { unsigned char type_uuid[GUID_LEN]; unsigned char unique_uuid[GUID_LEN]; unsigned long long first_lba; unsigned long long last_lba; unsigned long long attr; unsigned short name[EFI_NAMELEN]; } gpt_entry_t; typedef struct gpt_header { unsigned char signature[8]; unsigned int revision; unsigned int size; unsigned int header_crc; unsigned int reserved; unsigned long long current_lba; unsigned long long backup_lba; unsigned long long first_lba; unsigned long long last_lba; unsigned char disk_uuid[16]; /* starting LBA of array of partition entries */ unsigned long long part_lba; /* number of partition entries in array */ unsigned int list_num; /* size of a single partition entry (usually 128) */ unsigned int part_size; unsigned int part_crc; } gpt_header_t; int parse_gpt_entry(gpt_entry_t *gpt_entry, partition_entry_t *entry); #endif /* GPT_H */ trusted-firmware-a-2.2/include/drivers/partition/mbr.h000066400000000000000000000012171355360272700231550ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MBR_H #define MBR_H #define MBR_OFFSET 0 #define MBR_PRIMARY_ENTRY_OFFSET 0x1be #define MBR_PRIMARY_ENTRY_SIZE 0x10 #define MBR_PRIMARY_ENTRY_NUMBER 4 #define MBR_CHS_ADDRESS_LEN 3 #define MBR_SIGNATURE_FIRST 0x55 #define MBR_SIGNATURE_SECOND 0xAA typedef struct mbr_entry { unsigned char status; unsigned char first_sector[MBR_CHS_ADDRESS_LEN]; unsigned char type; unsigned char last_sector[MBR_CHS_ADDRESS_LEN]; unsigned int first_lba; unsigned int sector_nums; } mbr_entry_t; #endif /* MBR_H */ trusted-firmware-a-2.2/include/drivers/partition/partition.h000066400000000000000000000022741355360272700244120ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PARTITION_H #define PARTITION_H #include #include #if !PLAT_PARTITION_MAX_ENTRIES # define PLAT_PARTITION_MAX_ENTRIES 128 #endif /* PLAT_PARTITION_MAX_ENTRIES */ CASSERT(PLAT_PARTITION_MAX_ENTRIES <= 128, assert_plat_partition_max_entries); #if !PLAT_PARTITION_BLOCK_SIZE # define PLAT_PARTITION_BLOCK_SIZE 512 #endif /* PLAT_PARTITION_BLOCK_SIZE */ CASSERT((PLAT_PARTITION_BLOCK_SIZE == 512) || (PLAT_PARTITION_BLOCK_SIZE == 4096), assert_plat_partition_block_size); #define LEGACY_PARTITION_BLOCK_SIZE 512 #define EFI_NAMELEN 36 typedef struct partition_entry { uint64_t start; uint64_t length; char name[EFI_NAMELEN]; } partition_entry_t; typedef struct partition_entry_list { partition_entry_t list[PLAT_PARTITION_MAX_ENTRIES]; int entry_count; } partition_entry_list_t; int load_partition_table(unsigned int image_id); const partition_entry_t *get_partition_entry(const char *name); const partition_entry_list_t *get_partition_entry_list(void); void partition_init(unsigned int image_id); #endif /* PARTITION_H */ trusted-firmware-a-2.2/include/drivers/renesas/000077500000000000000000000000001355360272700216525ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/renesas/rcar/000077500000000000000000000000001355360272700226015ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/renesas/rcar/console/000077500000000000000000000000001355360272700242435ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/renesas/rcar/console/console.h000066400000000000000000000014331355360272700260570ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RCAR_PRINTF_H #define RCAR_PRINTF_H #define CONSOLE_T_RCAR_BASE CONSOLE_T_DRVDATA #ifndef __ASSEMBLER__ #include typedef struct { console_t console; uintptr_t base; } console_rcar_t; /* * Initialize a new rcar 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_rcar_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, console_rcar_t *console); #endif /*__ASSEMBLER__*/ #endif /* RCAR_PRINTF_H */ trusted-firmware-a-2.2/include/drivers/rpi3/000077500000000000000000000000001355360272700210675ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/rpi3/gpio/000077500000000000000000000000001355360272700220255ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/rpi3/gpio/rpi3_gpio.h000066400000000000000000000020161355360272700240700ustar00rootroot00000000000000/* * Copyright (c) 2019, Linaro Limited * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RPI3_GPIO_H #define RPI3_GPIO_H #include #include struct rpi3_gpio_params { uintptr_t reg_base; }; void rpi3_gpio_init(struct rpi3_gpio_params *params); int rpi3_gpio_get_select(int gpio); void rpi3_gpio_set_select(int gpio, int fsel); #define RPI3_GPIO_GPFSEL(n) ((n) * U(0x04)) #define RPI3_GPIO_GPSET(n) (((n) * U(0x04)) + U(0x1C)) #define RPI3_GPIO_GPCLR(n) (((n) * U(0x04)) + U(0x28)) #define RPI3_GPIO_GPLEV(n) (((n) * U(0x04)) + U(0x34)) #define RPI3_GPIO_GPPUD U(0x94) #define RPI3_GPIO_GPPUDCLK(n) (((n) * U(0x04)) + U(0x98)) #define RPI3_GPIO_FUNC_INPUT U(0) #define RPI3_GPIO_FUNC_OUTPUT U(1) #define RPI3_GPIO_FUNC_ALT0 U(4) #define RPI3_GPIO_FUNC_ALT1 U(5) #define RPI3_GPIO_FUNC_ALT2 U(6) #define RPI3_GPIO_FUNC_ALT3 U(7) #define RPI3_GPIO_FUNC_ALT4 U(3) #define RPI3_GPIO_FUNC_ALT5 U(2) #endif /* RPI3_GPIO_H */ trusted-firmware-a-2.2/include/drivers/rpi3/mailbox/000077500000000000000000000000001355360272700225225ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/rpi3/mailbox/rpi3_mbox.h000066400000000000000000000021321355360272700245730ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RPI3_MBOX_H #define RPI3_MBOX_H #include /* This struct must be aligned to 16 bytes */ typedef struct __packed __aligned(16) rpi3_mbox_request { uint32_t size; /* Buffer size in bytes */ uint32_t code; /* Request/response code */ uint32_t tags[0]; } rpi3_mbox_request_t; #define RPI3_MBOX_BUFFER_SIZE U(256) /* Constants to perform a request/check the status of a request. */ #define RPI3_MBOX_PROCESS_REQUEST U(0x00000000) #define RPI3_MBOX_REQUEST_SUCCESSFUL U(0x80000000) #define RPI3_MBOX_REQUEST_ERROR U(0x80000001) /* Command constants */ #define RPI3_TAG_HARDWARE_GET_BOARD_REVISION U(0x00010002) #define RPI3_TAG_END U(0x00000000) #define RPI3_TAG_REQUEST U(0x00000000) #define RPI3_TAG_IS_RESPONSE U(0x80000000) /* Set if response */ #define RPI3_TAG_RESPONSE_LENGTH_MASK U(0x7FFFFFFF) #define RPI3_CHANNEL_ARM_TO_VC U(0x8) #define RPI3_CHANNEL_MASK U(0xF) void rpi3_vc_mailbox_request_send(rpi3_mbox_request_t *req, int req_size); #endif trusted-firmware-a-2.2/include/drivers/rpi3/rng/000077500000000000000000000000001355360272700216555ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/rpi3/rng/rpi3_rng.h000066400000000000000000000003301355360272700235450ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RPI3_RNG_H #define RPI3_RNG_H void rpi3_rng_read(void *buf, size_t len); #endif trusted-firmware-a-2.2/include/drivers/rpi3/sdhost/000077500000000000000000000000001355360272700223735ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/rpi3/sdhost/rpi3_sdhost.h000066400000000000000000000065141355360272700250130ustar00rootroot00000000000000/* * Copyright (c) 2019, Linaro Limited * Copyright (c) 2019, Ying-Chun Liu (PaulLiu) * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RPI3_SDHOST_H #define RPI3_SDHOST_H #include #include #include struct rpi3_sdhost_params { uintptr_t reg_base; uint32_t clk_rate; uint32_t bus_width; uint32_t flags; uint32_t current_cmd; uint8_t cmdbusy; uint8_t mmc_app_cmd; uint32_t ns_per_fifo_word; uint32_t sdcard_rca; uint32_t gpio48_pinselect[6]; }; void rpi3_sdhost_init(struct rpi3_sdhost_params *params, struct mmc_device_info *mmc_dev_info); void rpi3_sdhost_stop(void); /* Registers */ #define HC_COMMAND 0x00 /* Command and flags */ #define HC_ARGUMENT 0x04 #define HC_TIMEOUTCOUNTER 0x08 #define HC_CLOCKDIVISOR 0x0c #define HC_RESPONSE_0 0x10 #define HC_RESPONSE_1 0x14 #define HC_RESPONSE_2 0x18 #define HC_RESPONSE_3 0x1c #define HC_HOSTSTATUS 0x20 #define HC_POWER 0x30 #define HC_DEBUG 0x34 #define HC_HOSTCONFIG 0x38 #define HC_BLOCKSIZE 0x3c #define HC_DATAPORT 0x40 #define HC_BLOCKCOUNT 0x50 /* Flags for HC_COMMAND register */ #define HC_CMD_ENABLE 0x8000 #define HC_CMD_FAILED 0x4000 #define HC_CMD_BUSY 0x0800 #define HC_CMD_RESPONSE_NONE 0x0400 #define HC_CMD_RESPONSE_LONG 0x0200 #define HC_CMD_WRITE 0x0080 #define HC_CMD_READ 0x0040 #define HC_CMD_COMMAND_MASK 0x003f #define HC_CLOCKDIVISOR_MAXVAL 0x07ff #define HC_CLOCKDIVISOR_PREFERVAL 0x027b #define HC_CLOCKDIVISOR_SLOWVAL 0x0148 #define HC_CLOCKDIVISOR_STOPVAL 0x01fb /* Flags for HC_HOSTSTATUS register */ #define HC_HSTST_HAVEDATA 0x0001 #define HC_HSTST_ERROR_FIFO 0x0008 #define HC_HSTST_ERROR_CRC7 0x0010 #define HC_HSTST_ERROR_CRC16 0x0020 #define HC_HSTST_TIMEOUT_CMD 0x0040 #define HC_HSTST_TIMEOUT_DATA 0x0080 #define HC_HSTST_INT_BLOCK 0x0200 #define HC_HSTST_INT_BUSY 0x0400 #define HC_HSTST_RESET 0xffff #define HC_HSTST_MASK_ERROR_DATA (HC_HSTST_ERROR_FIFO | \ HC_HSTST_ERROR_CRC7 | \ HC_HSTST_ERROR_CRC16 | \ HC_HSTST_TIMEOUT_DATA) #define HC_HSTST_MASK_ERROR_ALL (HC_HSTST_MASK_ERROR_DATA | \ HC_HSTST_TIMEOUT_CMD) /* Flags for HC_HOSTCONFIG register */ #define HC_HSTCF_INTBUS_WIDE 0x0002 #define HC_HSTCF_EXTBUS_4BIT 0x0004 #define HC_HSTCF_SLOW_CARD 0x0008 #define HC_HSTCF_INT_DATA 0x0010 #define HC_HSTCF_INT_BLOCK 0x0100 #define HC_HSTCF_INT_BUSY 0x0400 /* Flags for HC_DEBUG register */ #define HC_DBG_FIFO_THRESH_WRITE_SHIFT 9 #define HC_DBG_FIFO_THRESH_READ_SHIFT 14 #define HC_DBG_FIFO_THRESH_MASK 0x001f #define HC_DBG_FSM_MASK 0xf #define HC_DBG_FSM_IDENTMODE 0x0 #define HC_DBG_FSM_DATAMODE 0x1 #define HC_DBG_FSM_READDATA 0x2 #define HC_DBG_FSM_WRITEDATA 0x3 #define HC_DBG_FSM_READWAIT 0x4 #define HC_DBG_FSM_READCRC 0x5 #define HC_DBG_FSM_WRITECRC 0x6 #define HC_DBG_FSM_WRITEWAIT1 0x7 #define HC_DBG_FSM_POWERDOWN 0x8 #define HC_DBG_FSM_POWERUP 0x9 #define HC_DBG_FSM_WRITESTART1 0xa #define HC_DBG_FSM_WRITESTART2 0xb #define HC_DBG_FSM_GENPULSES 0xc #define HC_DBG_FSM_WRITEWAIT2 0xd #define HC_DBG_FSM_STARTPOWDOWN 0xf #define HC_DBG_FORCE_DATA_MODE 0x40000 /* Settings */ #define HC_FIFO_SIZE 16 #define HC_FIFO_THRESH_READ 4 #define HC_FIFO_THRESH_WRITE 4 #define HC_TIMEOUT_DEFAULT 0x00f00000 #define HC_TIMEOUT_IDLE 0x00a00000 #endif /* RPI3_SDHOST_H */ trusted-firmware-a-2.2/include/drivers/st/000077500000000000000000000000001355360272700206405ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/st/bsec.h000066400000000000000000000136241355360272700217330ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BSEC_H #define BSEC_H #include #include #include /* * IP configuration */ #define BSEC_OTP_MASK GENMASK(4, 0) #define BSEC_OTP_BANK_SHIFT 5 #define BSEC_TIMEOUT_VALUE 0xFFFF #define ADDR_LOWER_OTP_PERLOCK_SHIFT 0x03 #define DATA_LOWER_OTP_PERLOCK_BIT 0x03U /* 2 significants bits are used */ #define DATA_LOWER_OTP_PERLOCK_MASK GENMASK(2, 0) #define ADDR_UPPER_OTP_PERLOCK_SHIFT 0x04 #define DATA_UPPER_OTP_PERLOCK_BIT 0x01U /* 1 significants bits are used */ #define DATA_UPPER_OTP_PERLOCK_MASK GENMASK(3, 0) /* * Return status */ #define BSEC_OK 0U #define BSEC_ERROR 0xFFFFFFFFU #define BSEC_DISTURBED 0xFFFFFFFEU #define BSEC_INVALID_PARAM 0xFFFFFFFCU #define BSEC_PROG_FAIL 0xFFFFFFFBU #define BSEC_LOCK_FAIL 0xFFFFFFFAU #define BSEC_WRITE_FAIL 0xFFFFFFF9U #define BSEC_SHADOW_FAIL 0xFFFFFFF8U #define BSEC_TIMEOUT 0xFFFFFFF7U /* * BSEC REGISTER OFFSET (base relative) */ #define BSEC_OTP_CONF_OFF 0x000U #define BSEC_OTP_CTRL_OFF 0x004U #define BSEC_OTP_WRDATA_OFF 0x008U #define BSEC_OTP_STATUS_OFF 0x00CU #define BSEC_OTP_LOCK_OFF 0x010U #define BSEC_DEN_OFF 0x014U #define BSEC_DISTURBED_OFF 0x01CU #define BSEC_DISTURBED1_OFF 0x020U #define BSEC_DISTURBED2_OFF 0x024U #define BSEC_ERROR_OFF 0x034U #define BSEC_ERROR1_OFF 0x038U #define BSEC_ERROR2_OFF 0x03CU #define BSEC_WRLOCK_OFF 0x04CU /* Safmem permanent lock */ #define BSEC_WRLOCK1_OFF 0x050U #define BSEC_WRLOCK2_OFF 0x054U #define BSEC_SPLOCK_OFF 0x064U /* Program safmem sticky lock */ #define BSEC_SPLOCK1_OFF 0x068U #define BSEC_SPLOCK2_OFF 0x06CU #define BSEC_SWLOCK_OFF 0x07CU /* Write in OTP sticky lock */ #define BSEC_SWLOCK1_OFF 0x080U #define BSEC_SWLOCK2_OFF 0x084U #define BSEC_SRLOCK_OFF 0x094U /* Shadowing sticky lock */ #define BSEC_SRLOCK1_OFF 0x098U #define BSEC_SRLOCK2_OFF 0x09CU #define BSEC_JTAG_IN_OFF 0x0ACU #define BSEC_JTAG_OUT_OFF 0x0B0U #define BSEC_SCRATCH_OFF 0x0B4U #define BSEC_OTP_DATA_OFF 0x200U #define BSEC_IPHW_CFG_OFF 0xFF0U #define BSEC_IPVR_OFF 0xFF4U #define BSEC_IP_ID_OFF 0xFF8U #define BSEC_IP_MAGIC_ID_OFF 0xFFCU /* * BSEC_CONFIGURATION Register */ #define BSEC_CONF_POWER_UP_MASK BIT(0) #define BSEC_CONF_POWER_UP_SHIFT 0 #define BSEC_CONF_FRQ_MASK GENMASK(2, 1) #define BSEC_CONF_FRQ_SHIFT 1 #define BSEC_CONF_PRG_WIDTH_MASK GENMASK(6, 3) #define BSEC_CONF_PRG_WIDTH_SHIFT 3 #define BSEC_CONF_TREAD_MASK GENMASK(8, 7) #define BSEC_CONF_TREAD_SHIFT 7 /* * BSEC_CONTROL Register */ #define BSEC_READ 0x000U #define BSEC_WRITE 0x100U #define BSEC_LOCK 0x200U /* * BSEC_OTP_LOCK register */ #define UPPER_OTP_LOCK_MASK BIT(0) #define UPPER_OTP_LOCK_SHIFT 0 #define DENREG_LOCK_MASK BIT(2) #define DENREG_LOCK_SHIFT 2 #define GPLOCK_LOCK_MASK BIT(4) #define GPLOCK_LOCK_SHIFT 4 /* * BSEC_OTP_STATUS Register */ #define BSEC_MODE_STATUS_MASK GENMASK(2, 0) #define BSEC_MODE_BUSY_MASK BIT(3) #define BSEC_MODE_PROGFAIL_MASK BIT(4) #define BSEC_MODE_PWR_MASK BIT(5) #define BSEC_MODE_BIST1_LOCK_MASK BIT(6) #define BSEC_MODE_BIST2_LOCK_MASK BIT(7) /* OTP MODE*/ #define BSEC_MODE_OPEN1 0x00 #define BSEC_MODE_SECURED 0x01 #define BSEC_MODE_OPEN2 0x02 #define BSEC_MODE_INVALID 0x04 /* BSEC_DENABLE Register */ #define BSEC_HDPEN BIT(4) #define BSEC_SPIDEN BIT(5) #define BSEC_SPINDEN BIT(6) #define BSEC_DBGSWGEN BIT(10) #define BSEC_DEN_ALL_MSK GENMASK(10, 0) /* BSEC_FENABLE Register */ #define BSEC_FEN_ALL_MSK GENMASK(14, 0) /* * OTP Lock services definition * Value must corresponding to the bit number in the register */ #define BSEC_LOCK_UPPER_OTP 0x00 #define BSEC_LOCK_DEBUG 0x02 #define BSEC_LOCK_PROGRAM 0x03 /* Values for struct bsec_config::freq */ #define FREQ_10_20_MHZ 0x0 #define FREQ_20_30_MHZ 0x1 #define FREQ_30_45_MHZ 0x2 #define FREQ_45_67_MHZ 0x3 /* * Device info structure, providing device-specific functions and a means of * adding driver-specific state */ struct bsec_config { uint8_t tread; /* SAFMEM Reading current level default 0 */ uint8_t pulse_width; /* SAFMEM Programming pulse width default 1 */ uint8_t freq; /* SAFMEM CLOCK see freq value define * default FREQ_45_67_MHZ */ uint8_t power; /* Power up SAFMEM. 1 power up, 0 power off */ uint8_t prog_lock; /* Programming Sticky lock * 1 programming is locked until next reset */ uint8_t den_lock; /* Debug enable sticky lock * 1 debug enable is locked until next reset */ uint8_t upper_otp_lock; /* Shadowing of upper OTP 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); 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 */ trusted-firmware-a-2.2/include/drivers/st/io_mmc.h000066400000000000000000000004351355360272700222560ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IO_MMC_H #define IO_MMC_H #include int register_io_dev_mmc(const io_dev_connector_t **dev_con); #endif /* IO_MMC_H */ trusted-firmware-a-2.2/include/drivers/st/io_stm32image.h000066400000000000000000000013741355360272700234600ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IO_STM32IMAGE_H #define IO_STM32IMAGE_H #include #include #define MAX_LBA_SIZE 512 #define MAX_PART_NAME_SIZE (EFI_NAMELEN + 1) #define STM32_PART_NUM (PLAT_PARTITION_MAX_ENTRIES - STM32_TF_A_COPIES) struct stm32image_part_info { char name[MAX_PART_NAME_SIZE]; uint32_t binary_type; uintptr_t part_offset; uint32_t bkp_offset; }; struct stm32image_device_info { struct stm32image_part_info part_info[STM32_PART_NUM]; uint32_t device_size; uint32_t lba_size; }; int register_io_dev_stm32image(const io_dev_connector_t **dev_con); #endif /* IO_STM32IMAGE_H */ trusted-firmware-a-2.2/include/drivers/st/stm32_console.h000066400000000000000000000014701355360272700235050ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32_CONSOLE_H #define STM32_CONSOLE_H #include #define CONSOLE_T_STM32_BASE CONSOLE_T_DRVDATA #ifndef __ASSEMBLER__ #include struct console_stm32 { console_t console; uintptr_t base; }; /* * Initialize a new STM32 console instance and register it with the console * framework. The |console| pointer must point to storage that will be valid * for the lifetime of the console, such as a global or static local variable. * Its contents will be reinitialized from scratch. */ int console_stm32_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, struct console_stm32 *console); #endif /*__ASSEMBLER__*/ #endif /* STM32_CONSOLE_H */ trusted-firmware-a-2.2/include/drivers/st/stm32_gpio.h000066400000000000000000000026261355360272700230050ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32_GPIO_H #define STM32_GPIO_H #include #define GPIO_MODE_OFFSET U(0x00) #define GPIO_TYPE_OFFSET U(0x04) #define GPIO_SPEED_OFFSET U(0x08) #define GPIO_PUPD_OFFSET U(0x0C) #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_PIN_(_x) U(_x) #define GPIO_PIN_MAX GPIO_PIN_(15) #define GPIO_ALTERNATE_(_x) U(_x) #define GPIO_ALTERNATE_MASK U(0x0F) #define GPIO_MODE_INPUT 0x00 #define GPIO_MODE_OUTPUT 0x01 #define GPIO_MODE_ALTERNATE 0x02 #define GPIO_MODE_ANALOG 0x03 #define GPIO_MODE_MASK U(0x03) #define GPIO_OPEN_DRAIN U(0x10) #define GPIO_SPEED_LOW 0x00 #define GPIO_SPEED_MEDIUM 0x01 #define GPIO_SPEED_HIGH 0x02 #define GPIO_SPEED_VERY_HIGH 0x03 #define GPIO_SPEED_MASK U(0x03) #define GPIO_NO_PULL 0x00 #define GPIO_PULL_UP 0x01 #define GPIO_PULL_DOWN 0x02 #define GPIO_PULL_MASK U(0x03) #ifndef __ASSEMBLER__ #include int dt_set_pinctrl_config(int node); void set_gpio(uint32_t bank, uint32_t pin, uint32_t mode, uint32_t speed, uint32_t pull, uint32_t alternate, uint8_t status); void set_gpio_secure_cfg(uint32_t bank, uint32_t pin, bool secure); #endif /*__ASSEMBLER__*/ #endif /* STM32_GPIO_H */ trusted-firmware-a-2.2/include/drivers/st/stm32_hash.h000066400000000000000000000010511355360272700227610ustar00rootroot00000000000000/* * Copyright (c) 2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32_HASH_H #define STM32_HASH_H enum stm32_hash_algo_mode { HASH_MD5SUM, HASH_SHA1, HASH_SHA224, HASH_SHA256 }; int stm32_hash_update(const uint8_t *buffer, size_t length); int stm32_hash_final(uint8_t *digest); int stm32_hash_final_update(const uint8_t *buffer, uint32_t buf_length, uint8_t *digest); void stm32_hash_init(enum stm32_hash_algo_mode mode); int stm32_hash_register(void); #endif /* STM32_HASH_H */ trusted-firmware-a-2.2/include/drivers/st/stm32_i2c.h000066400000000000000000000241261355360272700225230ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32_I2C_H #define STM32_I2C_H #include #include /* Bit definition for I2C_CR1 register */ #define I2C_CR1_PE BIT(0) #define I2C_CR1_TXIE BIT(1) #define I2C_CR1_RXIE BIT(2) #define I2C_CR1_ADDRIE BIT(3) #define I2C_CR1_NACKIE BIT(4) #define I2C_CR1_STOPIE BIT(5) #define I2C_CR1_TCIE BIT(6) #define I2C_CR1_ERRIE BIT(7) #define I2C_CR1_DNF GENMASK(11, 8) #define I2C_CR1_ANFOFF BIT(12) #define I2C_CR1_SWRST BIT(13) #define I2C_CR1_TXDMAEN BIT(14) #define I2C_CR1_RXDMAEN BIT(15) #define I2C_CR1_SBC BIT(16) #define I2C_CR1_NOSTRETCH BIT(17) #define I2C_CR1_WUPEN BIT(18) #define I2C_CR1_GCEN BIT(19) #define I2C_CR1_SMBHEN BIT(22) #define I2C_CR1_SMBDEN BIT(21) #define I2C_CR1_ALERTEN BIT(22) #define I2C_CR1_PECEN BIT(23) /* Bit definition for I2C_CR2 register */ #define I2C_CR2_SADD GENMASK(9, 0) #define I2C_CR2_RD_WRN BIT(10) #define I2C_CR2_RD_WRN_OFFSET 10U #define I2C_CR2_ADD10 BIT(11) #define I2C_CR2_HEAD10R BIT(12) #define I2C_CR2_START BIT(13) #define I2C_CR2_STOP BIT(14) #define I2C_CR2_NACK BIT(15) #define I2C_CR2_NBYTES GENMASK(23, 16) #define I2C_CR2_NBYTES_OFFSET 16U #define I2C_CR2_RELOAD BIT(24) #define I2C_CR2_AUTOEND BIT(25) #define I2C_CR2_PECBYTE BIT(26) /* Bit definition for I2C_OAR1 register */ #define I2C_OAR1_OA1 GENMASK(9, 0) #define I2C_OAR1_OA1MODE BIT(10) #define I2C_OAR1_OA1EN BIT(15) /* Bit definition for I2C_OAR2 register */ #define I2C_OAR2_OA2 GENMASK(7, 1) #define I2C_OAR2_OA2MSK GENMASK(10, 8) #define I2C_OAR2_OA2NOMASK 0 #define I2C_OAR2_OA2MASK01 BIT(8) #define I2C_OAR2_OA2MASK02 BIT(9) #define I2C_OAR2_OA2MASK03 GENMASK(9, 8) #define I2C_OAR2_OA2MASK04 BIT(10) #define I2C_OAR2_OA2MASK05 (BIT(8) | BIT(10)) #define I2C_OAR2_OA2MASK06 (BIT(9) | BIT(10)) #define I2C_OAR2_OA2MASK07 GENMASK(10, 8) #define I2C_OAR2_OA2EN BIT(15) /* Bit definition for I2C_TIMINGR register */ #define I2C_TIMINGR_SCLL GENMASK(7, 0) #define I2C_TIMINGR_SCLH GENMASK(15, 8) #define I2C_TIMINGR_SDADEL GENMASK(19, 16) #define I2C_TIMINGR_SCLDEL GENMASK(23, 20) #define I2C_TIMINGR_PRESC GENMASK(31, 28) /* Bit definition for I2C_TIMEOUTR register */ #define I2C_TIMEOUTR_TIMEOUTA GENMASK(11, 0) #define I2C_TIMEOUTR_TIDLE BIT(12) #define I2C_TIMEOUTR_TIMOUTEN BIT(15) #define I2C_TIMEOUTR_TIMEOUTB GENMASK(27, 16) #define I2C_TIMEOUTR_TEXTEN BIT(31) /* Bit definition for I2C_ISR register */ #define I2C_ISR_TXE BIT(0) #define I2C_ISR_TXIS BIT(1) #define I2C_ISR_RXNE BIT(2) #define I2C_ISR_ADDR BIT(3) #define I2C_ISR_NACKF BIT(4) #define I2C_ISR_STOPF BIT(5) #define I2C_ISR_TC BIT(6) #define I2C_ISR_TCR BIT(7) #define I2C_ISR_BERR BIT(8) #define I2C_ISR_ARLO BIT(9) #define I2C_ISR_OVR BIT(10) #define I2C_ISR_PECERR BIT(11) #define I2C_ISR_TIMEOUT BIT(12) #define I2C_ISR_ALERT BIT(13) #define I2C_ISR_BUSY BIT(15) #define I2C_ISR_DIR BIT(16) #define I2C_ISR_ADDCODE GENMASK(23, 17) /* Bit definition for I2C_ICR register */ #define I2C_ICR_ADDRCF BIT(3) #define I2C_ICR_NACKCF BIT(4) #define I2C_ICR_STOPCF BIT(5) #define I2C_ICR_BERRCF BIT(8) #define I2C_ICR_ARLOCF BIT(9) #define I2C_ICR_OVRCF BIT(10) #define I2C_ICR_PECCF BIT(11) #define I2C_ICR_TIMOUTCF BIT(12) #define I2C_ICR_ALERTCF BIT(13) enum i2c_speed_e { I2C_SPEED_STANDARD, /* 100 kHz */ I2C_SPEED_FAST, /* 400 kHz */ I2C_SPEED_FAST_PLUS, /* 1 MHz */ }; #define STANDARD_RATE 100000 #define FAST_RATE 400000 #define FAST_PLUS_RATE 1000000 struct stm32_i2c_init_s { uint32_t own_address1; /* * Specifies the first device own * address. This parameter can be a * 7-bit or 10-bit address. */ uint32_t addressing_mode; /* * Specifies if 7-bit or 10-bit * addressing mode is selected. * This parameter can be a value of * @ref I2C_ADDRESSING_MODE. */ uint32_t dual_address_mode; /* * Specifies if dual addressing mode is * selected. * This parameter can be a value of @ref * I2C_DUAL_ADDRESSING_MODE. */ uint32_t own_address2; /* * Specifies the second device own * address if dual addressing mode is * selected. This parameter can be a * 7-bit address. */ uint32_t own_address2_masks; /* * Specifies the acknowledge mask * address second device own address * if dual addressing mode is selected * This parameter can be a value of @ref * I2C_OWN_ADDRESS2_MASKS. */ uint32_t general_call_mode; /* * Specifies if general call mode is * selected. * This parameter can be a value of @ref * I2C_GENERAL_CALL_ADDRESSING_MODE. */ uint32_t no_stretch_mode; /* * Specifies if nostretch mode is * selected. * This parameter can be a value of @ref * I2C_NOSTRETCH_MODE. */ uint32_t rise_time; /* * Specifies the SCL clock pin rising * time in nanoseconds. */ uint32_t fall_time; /* * Specifies the SCL clock pin falling * time in nanoseconds. */ enum i2c_speed_e speed_mode; /* * Specifies the I2C clock source * frequency mode. * This parameter can be a value of @ref * i2c_speed_mode_e. */ int analog_filter; /* * Specifies if the I2C analog noise * filter is selected. * This parameter can be 0 (filter * off), all other values mean filter * on. */ uint8_t digital_filter_coef; /* * Specifies the I2C digital noise * filter coefficient. * This parameter can be a value * between 0 and * STM32_I2C_DIGITAL_FILTER_MAX. */ }; enum i2c_state_e { I2C_STATE_RESET = 0x00U, /* Not yet initialized */ I2C_STATE_READY = 0x20U, /* Ready for use */ I2C_STATE_BUSY = 0x24U, /* Internal process ongoing */ I2C_STATE_BUSY_TX = 0x21U, /* Data Transmission ongoing */ I2C_STATE_BUSY_RX = 0x22U, /* Data Reception ongoing */ }; enum i2c_mode_e { I2C_MODE_NONE = 0x00U, /* No active communication */ I2C_MODE_MASTER = 0x10U, /* Communication in Master Mode */ I2C_MODE_SLAVE = 0x20U, /* Communication in Slave Mode */ I2C_MODE_MEM = 0x40U /* Communication in Memory Mode */ }; #define I2C_ERROR_NONE 0x00000000U /* No error */ #define I2C_ERROR_BERR 0x00000001U /* BERR error */ #define I2C_ERROR_ARLO 0x00000002U /* ARLO error */ #define I2C_ERROR_AF 0x00000004U /* ACKF error */ #define I2C_ERROR_OVR 0x00000008U /* OVR error */ #define I2C_ERROR_DMA 0x00000010U /* DMA transfer error */ #define I2C_ERROR_TIMEOUT 0x00000020U /* Timeout error */ #define I2C_ERROR_SIZE 0x00000040U /* Size Management error */ struct i2c_handle_s { uint32_t i2c_base_addr; /* Registers base address */ 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_DUALADDRESS_DISABLE 0x00000000U #define I2C_DUALADDRESS_ENABLE I2C_OAR2_OA2EN #define I2C_GENERALCALL_DISABLE 0x00000000U #define I2C_GENERALCALL_ENABLE I2C_CR1_GCEN #define I2C_NOSTRETCH_DISABLE 0x00000000U #define I2C_NOSTRETCH_ENABLE I2C_CR1_NOSTRETCH #define I2C_MEMADD_SIZE_8BIT 0x00000001U #define I2C_MEMADD_SIZE_16BIT 0x00000002U #define I2C_RELOAD_MODE I2C_CR2_RELOAD #define I2C_AUTOEND_MODE I2C_CR2_AUTOEND #define I2C_SOFTEND_MODE 0x00000000U #define I2C_NO_STARTSTOP 0x00000000U #define I2C_GENERATE_STOP (BIT(31) | I2C_CR2_STOP) #define I2C_GENERATE_START_READ (BIT(31) | I2C_CR2_START | \ I2C_CR2_RD_WRN) #define I2C_GENERATE_START_WRITE (BIT(31) | I2C_CR2_START) #define I2C_FLAG_TXE I2C_ISR_TXE #define I2C_FLAG_TXIS I2C_ISR_TXIS #define I2C_FLAG_RXNE I2C_ISR_RXNE #define I2C_FLAG_ADDR I2C_ISR_ADDR #define I2C_FLAG_AF I2C_ISR_NACKF #define I2C_FLAG_STOPF I2C_ISR_STOPF #define I2C_FLAG_TC I2C_ISR_TC #define I2C_FLAG_TCR I2C_ISR_TCR #define I2C_FLAG_BERR I2C_ISR_BERR #define I2C_FLAG_ARLO I2C_ISR_ARLO #define I2C_FLAG_OVR I2C_ISR_OVR #define I2C_FLAG_PECERR I2C_ISR_PECERR #define I2C_FLAG_TIMEOUT I2C_ISR_TIMEOUT #define I2C_FLAG_ALERT I2C_ISR_ALERT #define I2C_FLAG_BUSY I2C_ISR_BUSY #define I2C_FLAG_DIR I2C_ISR_DIR #define I2C_RESET_CR2 (I2C_CR2_SADD | I2C_CR2_HEAD10R | \ I2C_CR2_NBYTES | I2C_CR2_RELOAD | \ I2C_CR2_RD_WRN) #define I2C_TIMEOUT_BUSY_MS 25U #define I2C_ANALOGFILTER_ENABLE 0x00000000U #define I2C_ANALOGFILTER_DISABLE I2C_CR1_ANFOFF /* STM32 specific defines */ #define STM32_I2C_RISE_TIME_DEFAULT 25 /* ns */ #define STM32_I2C_FALL_TIME_DEFAULT 10 /* ns */ #define STM32_I2C_SPEED_DEFAULT I2C_SPEED_STANDARD #define STM32_I2C_ANALOG_FILTER_DELAY_MIN 50 /* ns */ #define STM32_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */ #define STM32_I2C_DIGITAL_FILTER_MAX 16 int stm32_i2c_get_setup_from_fdt(void *fdt, int node, struct stm32_i2c_init_s *init); int stm32_i2c_init(struct i2c_handle_s *hi2c, struct stm32_i2c_init_s *init_data); int stm32_i2c_mem_write(struct i2c_handle_s *hi2c, uint16_t dev_addr, uint16_t mem_addr, uint16_t mem_add_size, uint8_t *p_data, uint16_t size, uint32_t timeout_ms); int stm32_i2c_mem_read(struct i2c_handle_s *hi2c, uint16_t dev_addr, uint16_t mem_addr, uint16_t mem_add_size, uint8_t *p_data, uint16_t size, uint32_t timeout_ms); int stm32_i2c_master_transmit(struct i2c_handle_s *hi2c, uint16_t dev_addr, uint8_t *p_data, uint16_t size, uint32_t timeout_ms); int stm32_i2c_master_receive(struct i2c_handle_s *hi2c, uint16_t dev_addr, uint8_t *p_data, uint16_t size, uint32_t timeout_ms); bool stm32_i2c_is_device_ready(struct i2c_handle_s *hi2c, uint16_t dev_addr, uint32_t trials, uint32_t timeout_ms); #endif /* STM32_I2C_H */ trusted-firmware-a-2.2/include/drivers/st/stm32_iwdg.h000066400000000000000000000005751355360272700230020ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32_IWDG_H #define STM32_IWDG_H #include #define IWDG_HW_ENABLED BIT(0) #define IWDG_DISABLE_ON_STOP BIT(1) #define IWDG_DISABLE_ON_STANDBY BIT(2) int stm32_iwdg_init(void); void stm32_iwdg_refresh(void); #endif /* STM32_IWDG_H */ trusted-firmware-a-2.2/include/drivers/st/stm32_sdmmc2.h000066400000000000000000000013771355360272700232360ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32_SDMMC2_H #define STM32_SDMMC2_H #include #include struct stm32_sdmmc2_params { uintptr_t reg_base; unsigned int clk_rate; unsigned int bus_width; unsigned int flags; struct mmc_device_info *device_info; unsigned int pin_ckin; unsigned int negedge; unsigned int dirpol; unsigned int clock_id; unsigned int reset_id; unsigned int max_freq; 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 */ trusted-firmware-a-2.2/include/drivers/st/stm32_uart_regs.h000066400000000000000000000134711355360272700240420ustar00rootroot00000000000000/* * Copyright (C) 2018, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32_UART_REGS_H #define STM32_UART_REGS_H #include #define USART_CR1 U(0x00) #define USART_CR2 U(0x04) #define USART_CR3 U(0x08) #define USART_BRR U(0x0C) #define USART_GTPR U(0x10) #define USART_RTOR U(0x14) #define USART_RQR U(0x18) #define USART_ISR U(0x1C) #define USART_ICR U(0x20) #define USART_RDR U(0x24) #define USART_TDR U(0x28) #define USART_PRESC U(0x2C) /* USART_CR1 register fields */ #define USART_CR1_UE BIT(0) #define USART_CR1_UESM BIT(1) #define USART_CR1_RE BIT(2) #define USART_CR1_TE BIT(3) #define USART_CR1_IDLEIE BIT(4) #define USART_CR1_RXNEIE BIT(5) #define USART_CR1_TCIE BIT(6) #define USART_CR1_TXEIE BIT(7) #define USART_CR1_PEIE BIT(8) #define USART_CR1_PS BIT(9) #define USART_CR1_PCE BIT(10) #define USART_CR1_WAKE BIT(11) #define USART_CR1_M (BIT(28) | BIT(12)) #define USART_CR1_M0 BIT(12) #define USART_CR1_MME BIT(13) #define USART_CR1_CMIE BIT(14) #define USART_CR1_OVER8 BIT(15) #define USART_CR1_DEDT GENMASK(20, 16) #define USART_CR1_DEDT_0 BIT(16) #define USART_CR1_DEDT_1 BIT(17) #define USART_CR1_DEDT_2 BIT(18) #define USART_CR1_DEDT_3 BIT(19) #define USART_CR1_DEDT_4 BIT(20) #define USART_CR1_DEAT GENMASK(25, 21) #define USART_CR1_DEAT_0 BIT(21) #define USART_CR1_DEAT_1 BIT(22) #define USART_CR1_DEAT_2 BIT(23) #define USART_CR1_DEAT_3 BIT(24) #define USART_CR1_DEAT_4 BIT(25) #define USART_CR1_RTOIE BIT(26) #define USART_CR1_EOBIE BIT(27) #define USART_CR1_M1 BIT(28) #define USART_CR1_FIFOEN BIT(29) #define USART_CR1_TXFEIE BIT(30) #define USART_CR1_RXFFIE BIT(31) /* USART_CR2 register fields */ #define USART_CR2_SLVEN BIT(0) #define USART_CR2_DIS_NSS BIT(3) #define USART_CR2_ADDM7 BIT(4) #define USART_CR2_LBDL BIT(5) #define USART_CR2_LBDIE BIT(6) #define USART_CR2_LBCL BIT(8) #define USART_CR2_CPHA BIT(9) #define USART_CR2_CPOL BIT(10) #define USART_CR2_CLKEN BIT(11) #define USART_CR2_STOP GENMASK(13, 12) #define USART_CR2_STOP_0 BIT(12) #define USART_CR2_STOP_1 BIT(13) #define USART_CR2_LINEN BIT(14) #define USART_CR2_SWAP BIT(15) #define USART_CR2_RXINV BIT(16) #define USART_CR2_TXINV BIT(17) #define USART_CR2_DATAINV BIT(18) #define USART_CR2_MSBFIRST BIT(19) #define USART_CR2_ABREN BIT(20) #define USART_CR2_ABRMODE GENMASK(22, 21) #define USART_CR2_ABRMODE_0 BIT(21) #define USART_CR2_ABRMODE_1 BIT(22) #define USART_CR2_RTOEN BIT(23) #define USART_CR2_ADD GENMASK(31, 24) /* USART_CR3 register fields */ #define USART_CR3_EIE BIT(0) #define USART_CR3_IREN BIT(1) #define USART_CR3_IRLP BIT(2) #define USART_CR3_HDSEL BIT(3) #define USART_CR3_NACK BIT(4) #define USART_CR3_SCEN BIT(5) #define USART_CR3_DMAR BIT(6) #define USART_CR3_DMAT BIT(7) #define USART_CR3_RTSE BIT(8) #define USART_CR3_CTSE BIT(9) #define USART_CR3_CTSIE BIT(10) #define USART_CR3_ONEBIT BIT(11) #define USART_CR3_OVRDIS BIT(12) #define USART_CR3_DDRE BIT(13) #define USART_CR3_DEM BIT(14) #define USART_CR3_DEP BIT(15) #define USART_CR3_SCARCNT GENMASK(19, 17) #define USART_CR3_SCARCNT_0 BIT(17) #define USART_CR3_SCARCNT_1 BIT(18) #define USART_CR3_SCARCNT_2 BIT(19) #define USART_CR3_WUS GENMASK(21, 20) #define USART_CR3_WUS_0 BIT(20) #define USART_CR3_WUS_1 BIT(21) #define USART_CR3_WUFIE BIT(22) #define USART_CR3_TXFTIE BIT(23) #define USART_CR3_TCBGTIE BIT(24) #define USART_CR3_RXFTCFG GENMASK(27, 25) #define USART_CR3_RXFTCFG_0 BIT(25) #define USART_CR3_RXFTCFG_1 BIT(26) #define USART_CR3_RXFTCFG_2 BIT(27) #define USART_CR3_RXFTIE BIT(28) #define USART_CR3_TXFTCFG GENMASK(31, 29) #define USART_CR3_TXFTCFG_0 BIT(29) #define USART_CR3_TXFTCFG_1 BIT(30) #define USART_CR3_TXFTCFG_2 BIT(31) /* USART_BRR register fields */ #define USART_BRR_DIV_FRACTION GENMASK(3, 0) #define USART_BRR_DIV_MANTISSA GENMASK(15, 4) /* USART_GTPR register fields */ #define USART_GTPR_PSC GENMASK(7, 0) #define USART_GTPR_GT GENMASK(15, 8) /* USART_RTOR register fields */ #define USART_RTOR_RTO GENMASK(23, 0) #define USART_RTOR_BLEN GENMASK(31, 24) /* USART_RQR register fields */ #define USART_RQR_ABRRQ BIT(0) #define USART_RQR_SBKRQ BIT(1) #define USART_RQR_MMRQ BIT(2) #define USART_RQR_RXFRQ BIT(3) #define USART_RQR_TXFRQ BIT(4) /* USART_ISR register fields */ #define USART_ISR_PE BIT(0) #define USART_ISR_FE BIT(1) #define USART_ISR_NE BIT(2) #define USART_ISR_ORE BIT(3) #define USART_ISR_IDLE BIT(4) #define USART_ISR_RXNE BIT(5) #define USART_ISR_TC BIT(6) #define USART_ISR_TXE BIT(7) #define USART_ISR_LBDF BIT(8) #define USART_ISR_CTSIF BIT(9) #define USART_ISR_CTS BIT(10) #define USART_ISR_RTOF BIT(11) #define USART_ISR_EOBF BIT(12) #define USART_ISR_UDR BIT(13) #define USART_ISR_ABRE BIT(14) #define USART_ISR_ABRF BIT(15) #define USART_ISR_BUSY BIT(16) #define USART_ISR_CMF BIT(17) #define USART_ISR_SBKF BIT(18) #define USART_ISR_RWU BIT(19) #define USART_ISR_WUF BIT(20) #define USART_ISR_TEACK BIT(21) #define USART_ISR_REACK BIT(22) #define USART_ISR_TXFE BIT(23) #define USART_ISR_RXFF BIT(24) #define USART_ISR_TCBGT BIT(25) #define USART_ISR_RXFT BIT(26) #define USART_ISR_TXFT BIT(27) /* USART_ICR register fields */ #define USART_ICR_PECF BIT(0) #define USART_ICR_FECF BIT(1) #define USART_ICR_NCF BIT(2) #define USART_ICR_ORECF BIT(3) #define USART_ICR_IDLECF BIT(4) #define USART_ICR_TCCF BIT(6) #define USART_ICR_TCBGT BIT(7) #define USART_ICR_LBDCF BIT(8) #define USART_ICR_CTSCF BIT(9) #define USART_ICR_RTOCF BIT(11) #define USART_ICR_EOBCF BIT(12) #define USART_ICR_UDRCF BIT(13) #define USART_ICR_CMCF BIT(17) #define USART_ICR_WUCF BIT(20) /* USART_RDR register fields */ #define USART_RDR_RDR GENMASK(8, 0) /* USART_TDR register fields */ #define USART_TDR_TDR GENMASK(8, 0) /* USART_PRESC register fields */ #define USART_PRESC_PRESCALER GENMASK(3, 0) #endif /* STM32_UART_REGS_H */ trusted-firmware-a-2.2/include/drivers/st/stm32mp1_clk.h000066400000000000000000000024611355360272700232330ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32MP1_CLK_H #define STM32MP1_CLK_H #include enum stm32mp_osc_id { _HSI, _HSE, _CSI, _LSI, _LSE, _I2S_CKIN, NB_OSC, _UNKNOWN_OSC_ID = 0xFF }; extern const char *stm32mp_osc_node_label[NB_OSC]; 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); static inline void stm32mp1_clk_enable_non_secure(unsigned long id) { __stm32mp1_clk_enable(id, false); } static inline void stm32mp1_clk_enable_secure(unsigned long id) { __stm32mp1_clk_enable(id, true); } static inline void stm32mp1_clk_disable_non_secure(unsigned long id) { __stm32mp1_clk_disable(id, false); } static inline void stm32mp1_clk_disable_secure(unsigned long id) { __stm32mp1_clk_disable(id, true); } unsigned int stm32mp1_clk_get_refcount(unsigned long id); /* SMP protection on RCC registers access */ void stm32mp1_clk_rcc_regs_lock(void); void stm32mp1_clk_rcc_regs_unlock(void); void stm32mp1_stgen_increment(unsigned long long offset_in_ms); #endif /* STM32MP1_CLK_H */ trusted-firmware-a-2.2/include/drivers/st/stm32mp1_ddr.h000066400000000000000000000065101355360272700232320ustar00rootroot00000000000000/* * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ #ifndef STM32MP1_DDR_H #define STM32MP1_DDR_H #include #include #define DT_DDR_COMPAT "st,stm32mp1-ddr" struct stm32mp1_ddr_size { uint64_t base; uint64_t size; }; /** * struct ddr_info * * @dev: pointer for the device * @info: UCLASS RAM information * @ctl: DDR controleur base address * @phy: DDR PHY base address * @syscfg: syscfg base address */ struct ddr_info { struct stm32mp1_ddr_size info; struct stm32mp1_ddrctl *ctl; struct stm32mp1_ddrphy *phy; uintptr_t pwr; uintptr_t rcc; }; struct stm32mp1_ddrctrl_reg { uint32_t mstr; uint32_t mrctrl0; uint32_t mrctrl1; uint32_t derateen; uint32_t derateint; uint32_t pwrctl; uint32_t pwrtmg; uint32_t hwlpctl; uint32_t rfshctl0; uint32_t rfshctl3; uint32_t crcparctl0; uint32_t zqctl0; uint32_t dfitmg0; uint32_t dfitmg1; uint32_t dfilpcfg0; uint32_t dfiupd0; uint32_t dfiupd1; uint32_t dfiupd2; uint32_t dfiphymstr; uint32_t odtmap; uint32_t dbg0; uint32_t dbg1; uint32_t dbgcmd; uint32_t poisoncfg; uint32_t pccfg; }; struct stm32mp1_ddrctrl_timing { uint32_t rfshtmg; uint32_t dramtmg0; uint32_t dramtmg1; uint32_t dramtmg2; uint32_t dramtmg3; uint32_t dramtmg4; uint32_t dramtmg5; uint32_t dramtmg6; uint32_t dramtmg7; uint32_t dramtmg8; uint32_t dramtmg14; uint32_t odtcfg; }; struct stm32mp1_ddrctrl_map { uint32_t addrmap1; uint32_t addrmap2; uint32_t addrmap3; uint32_t addrmap4; uint32_t addrmap5; uint32_t addrmap6; uint32_t addrmap9; uint32_t addrmap10; uint32_t addrmap11; }; struct stm32mp1_ddrctrl_perf { uint32_t sched; uint32_t sched1; uint32_t perfhpr1; uint32_t perflpr1; uint32_t perfwr1; uint32_t pcfgr_0; uint32_t pcfgw_0; uint32_t pcfgqos0_0; uint32_t pcfgqos1_0; uint32_t pcfgwqos0_0; uint32_t pcfgwqos1_0; uint32_t pcfgr_1; uint32_t pcfgw_1; uint32_t pcfgqos0_1; uint32_t pcfgqos1_1; uint32_t pcfgwqos0_1; uint32_t pcfgwqos1_1; }; struct stm32mp1_ddrphy_reg { uint32_t pgcr; uint32_t aciocr; uint32_t dxccr; uint32_t dsgcr; uint32_t dcr; uint32_t odtcr; uint32_t zq0cr1; uint32_t dx0gcr; uint32_t dx1gcr; uint32_t dx2gcr; uint32_t dx3gcr; }; struct stm32mp1_ddrphy_timing { uint32_t ptr0; uint32_t ptr1; uint32_t ptr2; uint32_t dtpr0; uint32_t dtpr1; uint32_t dtpr2; uint32_t mr0; uint32_t mr1; uint32_t mr2; uint32_t mr3; }; struct stm32mp1_ddrphy_cal { uint32_t dx0dllcr; uint32_t dx0dqtr; uint32_t dx0dqstr; uint32_t dx1dllcr; uint32_t dx1dqtr; uint32_t dx1dqstr; uint32_t dx2dllcr; uint32_t dx2dqtr; uint32_t dx2dqstr; uint32_t dx3dllcr; uint32_t dx3dqtr; uint32_t dx3dqstr; }; struct stm32mp1_ddr_info { const char *name; uint32_t speed; /* in kHZ */ uint32_t size; /* Memory size in byte = col * row * width */ }; struct stm32mp1_ddr_config { struct stm32mp1_ddr_info info; struct stm32mp1_ddrctrl_reg c_reg; struct stm32mp1_ddrctrl_timing c_timing; struct stm32mp1_ddrctrl_map c_map; struct stm32mp1_ddrctrl_perf c_perf; struct stm32mp1_ddrphy_reg p_reg; struct stm32mp1_ddrphy_timing p_timing; struct stm32mp1_ddrphy_cal p_cal; }; 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 */ trusted-firmware-a-2.2/include/drivers/st/stm32mp1_ddr_helpers.h000066400000000000000000000003721355360272700247540ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32MP1_DDR_HELPERS_H #define STM32MP1_DDR_HELPERS_H void ddr_enable_clock(void); #endif /* STM32MP1_DDR_HELPERS_H */ trusted-firmware-a-2.2/include/drivers/st/stm32mp1_ddr_regs.h000066400000000000000000000377441355360272700242670ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ #ifndef STM32MP1_DDR_REGS_H #define STM32MP1_DDR_REGS_H #include /* DDR3/LPDDR2/LPDDR3 Controller (DDRCTRL) registers */ struct stm32mp1_ddrctl { uint32_t mstr ; /* 0x0 Master */ uint32_t stat; /* 0x4 Operating Mode Status */ uint8_t reserved008[0x10 - 0x8]; uint32_t mrctrl0; /* 0x10 Control 0 */ uint32_t mrctrl1; /* 0x14 Control 1 */ uint32_t mrstat; /* 0x18 Status */ uint32_t reserved01c; /* 0x1c */ uint32_t derateen; /* 0x20 Temperature Derate Enable */ uint32_t derateint; /* 0x24 Temperature Derate Interval */ uint8_t reserved028[0x30 - 0x28]; uint32_t pwrctl; /* 0x30 Low Power Control */ uint32_t pwrtmg; /* 0x34 Low Power Timing */ uint32_t hwlpctl; /* 0x38 Hardware Low Power Control */ uint8_t reserved03c[0x50 - 0x3C]; uint32_t rfshctl0; /* 0x50 Refresh Control 0 */ uint32_t reserved054; /* 0x54 Refresh Control 1 */ uint32_t reserved058; /* 0x58 Refresh Control 2 */ uint32_t reserved05C; uint32_t rfshctl3; /* 0x60 Refresh Control 0 */ uint32_t rfshtmg; /* 0x64 Refresh Timing */ uint8_t reserved068[0xc0 - 0x68]; uint32_t crcparctl0; /* 0xc0 CRC Parity Control0 */ uint32_t reserved0c4; /* 0xc4 CRC Parity Control1 */ uint32_t reserved0c8; /* 0xc8 CRC Parity Control2 */ uint32_t crcparstat; /* 0xcc CRC Parity Status */ uint32_t init0; /* 0xd0 SDRAM Initialization 0 */ uint32_t init1; /* 0xd4 SDRAM Initialization 1 */ uint32_t init2; /* 0xd8 SDRAM Initialization 2 */ uint32_t init3; /* 0xdc SDRAM Initialization 3 */ uint32_t init4; /* 0xe0 SDRAM Initialization 4 */ uint32_t init5; /* 0xe4 SDRAM Initialization 5 */ uint32_t reserved0e8; uint32_t reserved0ec; uint32_t dimmctl; /* 0xf0 DIMM Control */ uint8_t reserved0f4[0x100 - 0xf4]; uint32_t dramtmg0; /* 0x100 SDRAM Timing 0 */ uint32_t dramtmg1; /* 0x104 SDRAM Timing 1 */ uint32_t dramtmg2; /* 0x108 SDRAM Timing 2 */ uint32_t dramtmg3; /* 0x10c SDRAM Timing 3 */ uint32_t dramtmg4; /* 0x110 SDRAM Timing 4 */ uint32_t dramtmg5; /* 0x114 SDRAM Timing 5 */ uint32_t dramtmg6; /* 0x118 SDRAM Timing 6 */ uint32_t dramtmg7; /* 0x11c SDRAM Timing 7 */ uint32_t dramtmg8; /* 0x120 SDRAM Timing 8 */ uint8_t reserved124[0x138 - 0x124]; uint32_t dramtmg14; /* 0x138 SDRAM Timing 14 */ uint32_t dramtmg15; /* 0x13C SDRAM Timing 15 */ uint8_t reserved140[0x180 - 0x140]; uint32_t zqctl0; /* 0x180 ZQ Control 0 */ uint32_t zqctl1; /* 0x184 ZQ Control 1 */ uint32_t zqctl2; /* 0x188 ZQ Control 2 */ uint32_t zqstat; /* 0x18c ZQ Status */ uint32_t dfitmg0; /* 0x190 DFI Timing 0 */ uint32_t dfitmg1; /* 0x194 DFI Timing 1 */ uint32_t dfilpcfg0; /* 0x198 DFI Low Power Configuration 0 */ uint32_t reserved19c; uint32_t dfiupd0; /* 0x1a0 DFI Update 0 */ uint32_t dfiupd1; /* 0x1a4 DFI Update 1 */ uint32_t dfiupd2; /* 0x1a8 DFI Update 2 */ uint32_t reserved1ac; uint32_t dfimisc; /* 0x1b0 DFI Miscellaneous Control */ uint8_t reserved1b4[0x1bc - 0x1b4]; uint32_t dfistat; /* 0x1bc DFI Miscellaneous Control */ uint8_t reserved1c0[0x1c4 - 0x1c0]; uint32_t dfiphymstr; /* 0x1c4 DFI PHY Master interface */ uint8_t reserved1c8[0x204 - 0x1c8]; uint32_t addrmap1; /* 0x204 Address Map 1 */ uint32_t addrmap2; /* 0x208 Address Map 2 */ uint32_t addrmap3; /* 0x20c Address Map 3 */ uint32_t addrmap4; /* 0x210 Address Map 4 */ uint32_t addrmap5; /* 0x214 Address Map 5 */ uint32_t addrmap6; /* 0x218 Address Map 6 */ uint8_t reserved21c[0x224 - 0x21c]; uint32_t addrmap9; /* 0x224 Address Map 9 */ uint32_t addrmap10; /* 0x228 Address Map 10 */ uint32_t addrmap11; /* 0x22C Address Map 11 */ uint8_t reserved230[0x240 - 0x230]; uint32_t odtcfg; /* 0x240 ODT Configuration */ uint32_t odtmap; /* 0x244 ODT/Rank Map */ uint8_t reserved248[0x250 - 0x248]; uint32_t sched; /* 0x250 Scheduler Control */ uint32_t sched1; /* 0x254 Scheduler Control 1 */ uint32_t reserved258; uint32_t perfhpr1; /* 0x25c High Priority Read CAM 1 */ uint32_t reserved260; uint32_t perflpr1; /* 0x264 Low Priority Read CAM 1 */ uint32_t reserved268; uint32_t perfwr1; /* 0x26c Write CAM 1 */ uint8_t reserved27c[0x300 - 0x270]; uint32_t dbg0; /* 0x300 Debug 0 */ uint32_t dbg1; /* 0x304 Debug 1 */ uint32_t dbgcam; /* 0x308 CAM Debug */ uint32_t dbgcmd; /* 0x30c Command Debug */ uint32_t dbgstat; /* 0x310 Status Debug */ uint8_t reserved314[0x320 - 0x314]; uint32_t swctl; /* 0x320 Software Programming Control Enable */ uint32_t swstat; /* 0x324 Software Programming Control Status */ uint8_t reserved328[0x36c - 0x328]; uint32_t poisoncfg; /* 0x36c AXI Poison Configuration Register */ uint32_t poisonstat; /* 0x370 AXI Poison Status Register */ uint8_t reserved374[0x3fc - 0x374]; /* Multi Port registers */ uint32_t pstat; /* 0x3fc Port Status */ uint32_t pccfg; /* 0x400 Port Common Configuration */ /* PORT 0 */ uint32_t pcfgr_0; /* 0x404 Configuration Read */ uint32_t pcfgw_0; /* 0x408 Configuration Write */ uint8_t reserved40c[0x490 - 0x40c]; uint32_t pctrl_0; /* 0x490 Port Control Register */ uint32_t pcfgqos0_0; /* 0x494 Read QoS Configuration 0 */ uint32_t pcfgqos1_0; /* 0x498 Read QoS Configuration 1 */ uint32_t pcfgwqos0_0; /* 0x49c Write QoS Configuration 0 */ uint32_t pcfgwqos1_0; /* 0x4a0 Write QoS Configuration 1 */ uint8_t reserved4a4[0x4b4 - 0x4a4]; /* PORT 1 */ uint32_t pcfgr_1; /* 0x4b4 Configuration Read */ uint32_t pcfgw_1; /* 0x4b8 Configuration Write */ uint8_t reserved4bc[0x540 - 0x4bc]; uint32_t pctrl_1; /* 0x540 Port 2 Control Register */ uint32_t pcfgqos0_1; /* 0x544 Read QoS Configuration 0 */ uint32_t pcfgqos1_1; /* 0x548 Read QoS Configuration 1 */ uint32_t pcfgwqos0_1; /* 0x54c Write QoS Configuration 0 */ uint32_t pcfgwqos1_1; /* 0x550 Write QoS Configuration 1 */ } __packed; /* DDR Physical Interface Control (DDRPHYC) registers*/ struct stm32mp1_ddrphy { uint32_t ridr; /* 0x00 R Revision Identification */ uint32_t pir; /* 0x04 R/W PHY Initialization */ uint32_t pgcr; /* 0x08 R/W PHY General Configuration */ uint32_t pgsr; /* 0x0C PHY General Status */ uint32_t dllgcr; /* 0x10 R/W DLL General Control */ uint32_t acdllcr; /* 0x14 R/W AC DLL Control */ uint32_t ptr0; /* 0x18 R/W PHY Timing 0 */ uint32_t ptr1; /* 0x1C R/W PHY Timing 1 */ uint32_t ptr2; /* 0x20 R/W PHY Timing 2 */ uint32_t aciocr; /* 0x24 AC I/O Configuration */ uint32_t dxccr; /* 0x28 DATX8 Common Configuration */ uint32_t dsgcr; /* 0x2C DDR System General Configuration */ uint32_t dcr; /* 0x30 DRAM Configuration */ uint32_t dtpr0; /* 0x34 DRAM Timing Parameters0 */ uint32_t dtpr1; /* 0x38 DRAM Timing Parameters1 */ uint32_t dtpr2; /* 0x3C DRAM Timing Parameters2 */ uint32_t mr0; /* 0x40 Mode 0 */ uint32_t mr1; /* 0x44 Mode 1 */ uint32_t mr2; /* 0x48 Mode 2 */ uint32_t mr3; /* 0x4C Mode 3 */ uint32_t odtcr; /* 0x50 ODT Configuration */ uint32_t dtar; /* 0x54 data training address */ uint32_t dtdr0; /* 0x58 */ uint32_t dtdr1; /* 0x5c */ uint8_t res1[0x0c0 - 0x060]; /* 0x60 */ uint32_t dcuar; /* 0xc0 Address */ uint32_t dcudr; /* 0xc4 DCU Data */ uint32_t dcurr; /* 0xc8 DCU Run */ uint32_t dculr; /* 0xcc DCU Loop */ uint32_t dcugcr; /* 0xd0 DCU General Configuration */ uint32_t dcutpr; /* 0xd4 DCU Timing Parameters */ uint32_t dcusr0; /* 0xd8 DCU Status 0 */ uint32_t dcusr1; /* 0xdc DCU Status 1 */ uint8_t res2[0x100 - 0xe0]; /* 0xe0 */ uint32_t bistrr; /* 0x100 BIST Run */ uint32_t bistmskr0; /* 0x104 BIST Mask 0 */ uint32_t bistmskr1; /* 0x108 BIST Mask 0 */ uint32_t bistwcr; /* 0x10c BIST Word Count */ uint32_t bistlsr; /* 0x110 BIST LFSR Seed */ uint32_t bistar0; /* 0x114 BIST Address 0 */ uint32_t bistar1; /* 0x118 BIST Address 1 */ uint32_t bistar2; /* 0x11c BIST Address 2 */ uint32_t bistupdr; /* 0x120 BIST User Data Pattern */ uint32_t bistgsr; /* 0x124 BIST General Status */ uint32_t bistwer; /* 0x128 BIST Word Error */ uint32_t bistber0; /* 0x12c BIST Bit Error 0 */ uint32_t bistber1; /* 0x130 BIST Bit Error 1 */ uint32_t bistber2; /* 0x134 BIST Bit Error 2 */ uint32_t bistwcsr; /* 0x138 BIST Word Count Status */ uint32_t bistfwr0; /* 0x13c BIST Fail Word 0 */ uint32_t bistfwr1; /* 0x140 BIST Fail Word 1 */ uint8_t res3[0x178 - 0x144]; /* 0x144 */ uint32_t gpr0; /* 0x178 General Purpose 0 (GPR0) */ uint32_t gpr1; /* 0x17C General Purpose 1 (GPR1) */ uint32_t zq0cr0; /* 0x180 zq 0 control 0 */ uint32_t zq0cr1; /* 0x184 zq 0 control 1 */ uint32_t zq0sr0; /* 0x188 zq 0 status 0 */ uint32_t zq0sr1; /* 0x18C zq 0 status 1 */ uint8_t res4[0x1C0 - 0x190]; /* 0x190 */ uint32_t dx0gcr; /* 0x1c0 Byte lane 0 General Configuration */ uint32_t dx0gsr0; /* 0x1c4 Byte lane 0 General Status 0 */ uint32_t dx0gsr1; /* 0x1c8 Byte lane 0 General Status 1 */ uint32_t dx0dllcr; /* 0x1cc Byte lane 0 DLL Control */ uint32_t dx0dqtr; /* 0x1d0 Byte lane 0 DQ Timing */ uint32_t dx0dqstr; /* 0x1d4 Byte lane 0 DQS Timing */ uint8_t res5[0x200 - 0x1d8]; /* 0x1d8 */ uint32_t dx1gcr; /* 0x200 Byte lane 1 General Configuration */ uint32_t dx1gsr0; /* 0x204 Byte lane 1 General Status 0 */ uint32_t dx1gsr1; /* 0x208 Byte lane 1 General Status 1 */ uint32_t dx1dllcr; /* 0x20c Byte lane 1 DLL Control */ uint32_t dx1dqtr; /* 0x210 Byte lane 1 DQ Timing */ uint32_t dx1dqstr; /* 0x214 Byte lane 1 QS Timing */ uint8_t res6[0x240 - 0x218]; /* 0x218 */ uint32_t dx2gcr; /* 0x240 Byte lane 2 General Configuration */ uint32_t dx2gsr0; /* 0x244 Byte lane 2 General Status 0 */ uint32_t dx2gsr1; /* 0x248 Byte lane 2 General Status 1 */ uint32_t dx2dllcr; /* 0x24c Byte lane 2 DLL Control */ uint32_t dx2dqtr; /* 0x250 Byte lane 2 DQ Timing */ uint32_t dx2dqstr; /* 0x254 Byte lane 2 QS Timing */ uint8_t res7[0x280 - 0x258]; /* 0x258 */ uint32_t dx3gcr; /* 0x280 Byte lane 3 General Configuration */ uint32_t dx3gsr0; /* 0x284 Byte lane 3 General Status 0 */ uint32_t dx3gsr1; /* 0x288 Byte lane 3 General Status 1 */ uint32_t dx3dllcr; /* 0x28c Byte lane 3 DLL Control */ uint32_t dx3dqtr; /* 0x290 Byte lane 3 DQ Timing */ uint32_t dx3dqstr; /* 0x294 Byte lane 3 QS Timing */ } __packed; /* DDR Controller registers offsets */ #define DDRCTRL_MSTR 0x000 #define DDRCTRL_STAT 0x004 #define DDRCTRL_MRCTRL0 0x010 #define DDRCTRL_MRSTAT 0x018 #define DDRCTRL_PWRCTL 0x030 #define DDRCTRL_PWRTMG 0x034 #define DDRCTRL_HWLPCTL 0x038 #define DDRCTRL_RFSHCTL3 0x060 #define DDRCTRL_RFSHTMG 0x064 #define DDRCTRL_INIT0 0x0D0 #define DDRCTRL_DFIMISC 0x1B0 #define DDRCTRL_DBG1 0x304 #define DDRCTRL_DBGCAM 0x308 #define DDRCTRL_DBGCMD 0x30C #define DDRCTRL_DBGSTAT 0x310 #define DDRCTRL_SWCTL 0x320 #define DDRCTRL_SWSTAT 0x324 #define DDRCTRL_PSTAT 0x3FC #define DDRCTRL_PCTRL_0 0x490 #define DDRCTRL_PCTRL_1 0x540 /* DDR Controller Register fields */ #define DDRCTRL_MSTR_DDR3 BIT(0) #define DDRCTRL_MSTR_LPDDR2 BIT(2) #define DDRCTRL_MSTR_LPDDR3 BIT(3) #define DDRCTRL_MSTR_DATA_BUS_WIDTH_MASK GENMASK(13, 12) #define DDRCTRL_MSTR_DATA_BUS_WIDTH_FULL 0 #define DDRCTRL_MSTR_DATA_BUS_WIDTH_HALF BIT(12) #define DDRCTRL_MSTR_DATA_BUS_WIDTH_QUARTER BIT(13) #define DDRCTRL_MSTR_DLL_OFF_MODE BIT(15) #define DDRCTRL_STAT_OPERATING_MODE_MASK GENMASK(2, 0) #define DDRCTRL_STAT_OPERATING_MODE_NORMAL BIT(0) #define DDRCTRL_STAT_OPERATING_MODE_SR (BIT(0) | BIT(1)) #define DDRCTRL_STAT_SELFREF_TYPE_MASK GENMASK(5, 4) #define DDRCTRL_STAT_SELFREF_TYPE_ASR (BIT(4) | BIT(5)) #define DDRCTRL_STAT_SELFREF_TYPE_SR BIT(5) #define DDRCTRL_MRCTRL0_MR_TYPE_WRITE U(0) /* Only one rank supported */ #define DDRCTRL_MRCTRL0_MR_RANK_SHIFT 4 #define DDRCTRL_MRCTRL0_MR_RANK_ALL \ BIT(DDRCTRL_MRCTRL0_MR_RANK_SHIFT) #define DDRCTRL_MRCTRL0_MR_ADDR_SHIFT 12 #define DDRCTRL_MRCTRL0_MR_ADDR_MASK GENMASK(15, 12) #define DDRCTRL_MRCTRL0_MR_WR BIT(31) #define DDRCTRL_MRSTAT_MR_WR_BUSY BIT(0) #define DDRCTRL_PWRCTL_SELFREF_EN BIT(0) #define DDRCTRL_PWRCTL_POWERDOWN_EN BIT(1) #define DDRCTRL_PWRCTL_EN_DFI_DRAM_CLK_DISABLE BIT(3) #define DDRCTRL_PWRCTL_SELFREF_SW BIT(5) #define DDRCTRL_PWRTMG_SELFREF_TO_X32_MASK GENMASK(19, 12) #define DDRCTRL_PWRTMG_SELFREF_TO_X32_0 BIT(16) #define DDRCTRL_RFSHCTL3_DIS_AUTO_REFRESH BIT(0) #define DDRCTRL_HWLPCTL_HW_LP_EN BIT(0) #define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_MASK GENMASK(27, 16) #define DDRCTRL_RFSHTMG_T_RFC_NOM_X1_X32_SHIFT 16 #define DDRCTRL_INIT0_SKIP_DRAM_INIT_MASK GENMASK(31, 30) #define DDRCTRL_INIT0_SKIP_DRAM_INIT_NORMAL BIT(30) #define DDRCTRL_DFIMISC_DFI_INIT_COMPLETE_EN BIT(0) #define DDRCTRL_DBG1_DIS_HIF BIT(1) #define DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY BIT(29) #define DDRCTRL_DBGCAM_RD_DATA_PIPELINE_EMPTY BIT(28) #define DDRCTRL_DBGCAM_DBG_WR_Q_EMPTY BIT(26) #define DDRCTRL_DBGCAM_DBG_LPR_Q_DEPTH GENMASK(12, 8) #define DDRCTRL_DBGCAM_DBG_HPR_Q_DEPTH GENMASK(4, 0) #define DDRCTRL_DBGCAM_DATA_PIPELINE_EMPTY \ (DDRCTRL_DBGCAM_WR_DATA_PIPELINE_EMPTY | \ DDRCTRL_DBGCAM_RD_DATA_PIPELINE_EMPTY) #define DDRCTRL_DBGCAM_DBG_Q_DEPTH \ (DDRCTRL_DBGCAM_DBG_WR_Q_EMPTY | \ DDRCTRL_DBGCAM_DBG_LPR_Q_DEPTH | \ DDRCTRL_DBGCAM_DBG_HPR_Q_DEPTH) #define DDRCTRL_DBGCMD_RANK0_REFRESH BIT(0) #define DDRCTRL_DBGSTAT_RANK0_REFRESH_BUSY BIT(0) #define DDRCTRL_SWCTL_SW_DONE BIT(0) #define DDRCTRL_SWSTAT_SW_DONE_ACK BIT(0) #define DDRCTRL_PCTRL_N_PORT_EN BIT(0) /* DDR PHY registers offsets */ #define DDRPHYC_PIR 0x004 #define DDRPHYC_PGCR 0x008 #define DDRPHYC_PGSR 0x00C #define DDRPHYC_DLLGCR 0x010 #define DDRPHYC_ACDLLCR 0x014 #define DDRPHYC_PTR0 0x018 #define DDRPHYC_ACIOCR 0x024 #define DDRPHYC_DXCCR 0x028 #define DDRPHYC_DSGCR 0x02C #define DDRPHYC_ZQ0CR0 0x180 #define DDRPHYC_DX0GCR 0x1C0 #define DDRPHYC_DX0DLLCR 0x1CC #define DDRPHYC_DX1GCR 0x200 #define DDRPHYC_DX1DLLCR 0x20C #define DDRPHYC_DX2GCR 0x240 #define DDRPHYC_DX2DLLCR 0x24C #define DDRPHYC_DX3GCR 0x280 #define DDRPHYC_DX3DLLCR 0x28C /* DDR PHY Register fields */ #define DDRPHYC_PIR_INIT BIT(0) #define DDRPHYC_PIR_DLLSRST BIT(1) #define DDRPHYC_PIR_DLLLOCK BIT(2) #define DDRPHYC_PIR_ZCAL BIT(3) #define DDRPHYC_PIR_ITMSRST BIT(4) #define DDRPHYC_PIR_DRAMRST BIT(5) #define DDRPHYC_PIR_DRAMINIT BIT(6) #define DDRPHYC_PIR_QSTRN BIT(7) #define DDRPHYC_PIR_ICPC BIT(16) #define DDRPHYC_PIR_ZCALBYP BIT(30) #define DDRPHYC_PIR_INITSTEPS_MASK GENMASK(31, 7) #define DDRPHYC_PGCR_DFTCMP BIT(2) #define DDRPHYC_PGCR_PDDISDX BIT(24) #define DDRPHYC_PGCR_RFSHDT_MASK GENMASK(28, 25) #define DDRPHYC_PGSR_IDONE BIT(0) #define DDRPHYC_PGSR_DTERR BIT(5) #define DDRPHYC_PGSR_DTIERR BIT(6) #define DDRPHYC_PGSR_DFTERR BIT(7) #define DDRPHYC_PGSR_RVERR BIT(8) #define DDRPHYC_PGSR_RVEIRR BIT(9) #define DDRPHYC_DLLGCR_BPS200 BIT(23) #define DDRPHYC_ACDLLCR_DLLSRST BIT(30) #define DDRPHYC_ACDLLCR_DLLDIS BIT(31) #define DDRPHYC_PTR0_TDLLSRST_OFFSET 0 #define DDRPHYC_PTR0_TDLLSRST_MASK GENMASK(5, 0) #define DDRPHYC_PTR0_TDLLLOCK_OFFSET 6 #define DDRPHYC_PTR0_TDLLLOCK_MASK GENMASK(17, 6) #define DDRPHYC_PTR0_TITMSRST_OFFSET 18 #define DDRPHYC_PTR0_TITMSRST_MASK GENMASK(21, 18) #define DDRPHYC_ACIOCR_ACPDD BIT(3) #define DDRPHYC_ACIOCR_ACPDR BIT(4) #define DDRPHYC_ACIOCR_CKPDD_MASK GENMASK(10, 8) #define DDRPHYC_ACIOCR_CKPDD_0 BIT(8) #define DDRPHYC_ACIOCR_CKPDR_MASK GENMASK(13, 11) #define DDRPHYC_ACIOCR_CKPDR_0 BIT(11) #define DDRPHYC_ACIOCR_CSPDD_MASK GENMASK(21, 18) #define DDRPHYC_ACIOCR_CSPDD_0 BIT(18) #define DDRPHYC_ACIOCR_RSTPDD BIT(27) #define DDRPHYC_ACIOCR_RSTPDR BIT(28) #define DDRPHYC_DXCCR_DXPDD BIT(2) #define DDRPHYC_DXCCR_DXPDR BIT(3) #define DDRPHYC_DSGCR_CKEPDD_MASK GENMASK(19, 16) #define DDRPHYC_DSGCR_CKEPDD_0 BIT(16) #define DDRPHYC_DSGCR_ODTPDD_MASK GENMASK(23, 20) #define DDRPHYC_DSGCR_ODTPDD_0 BIT(20) #define DDRPHYC_DSGCR_NL2PD BIT(24) #define DDRPHYC_ZQ0CRN_ZDATA_MASK GENMASK(27, 0) #define DDRPHYC_ZQ0CRN_ZDATA_SHIFT 0 #define DDRPHYC_ZQ0CRN_ZDEN BIT(28) #define DDRPHYC_ZQ0CRN_ZQPD BIT(31) #define DDRPHYC_DXNGCR_DXEN BIT(0) #define DDRPHYC_DXNDLLCR_DLLSRST BIT(30) #define DDRPHYC_DXNDLLCR_DLLDIS BIT(31) #define DDRPHYC_DXNDLLCR_SDPHASE_MASK GENMASK(17, 14) #define DDRPHYC_DXNDLLCR_SDPHASE_SHIFT 14 #endif /* STM32MP1_DDR_REGS_H */ trusted-firmware-a-2.2/include/drivers/st/stm32mp1_pwr.h000066400000000000000000000013011355360272700232620ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32MP1_PWR_H #define STM32MP1_PWR_H #include #define PWR_CR1 U(0x00) #define PWR_CR2 U(0x08) #define PWR_CR3 U(0x0C) #define PWR_MPUCR U(0x10) #define PWR_WKUPCR U(0x20) #define PWR_MPUWKUPENR U(0x28) #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_CR3_DDRSREN BIT(10) #define PWR_CR3_DDRSRDIS BIT(11) #define PWR_CR3_DDRRETEN BIT(12) #define PWR_MPUCR_PDDS BIT(0) #define PWR_MPUCR_CSTDBYDIS BIT(3) #define PWR_MPUCR_CSSF BIT(9) #endif /* STM32MP1_PWR_H */ trusted-firmware-a-2.2/include/drivers/st/stm32mp1_ram.h000066400000000000000000000003431355360272700232360ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32MP1_RAM_H #define STM32MP1_RAM_H int stm32mp1_ddr_probe(void); #endif /* STM32MP1_RAM_H */ trusted-firmware-a-2.2/include/drivers/st/stm32mp1_rcc.h000066400000000000000000000447331355360272700232410ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32MP1_RCC_H #define STM32MP1_RCC_H #include #define RCC_TZCR U(0x00) #define RCC_OCENSETR U(0x0C) #define RCC_OCENCLRR U(0x10) #define RCC_HSICFGR U(0x18) #define RCC_CSICFGR U(0x1C) #define RCC_MPCKSELR U(0x20) #define RCC_ASSCKSELR U(0x24) #define RCC_RCK12SELR U(0x28) #define RCC_MPCKDIVR U(0x2C) #define RCC_AXIDIVR U(0x30) #define RCC_APB4DIVR U(0x3C) #define RCC_APB5DIVR U(0x40) #define RCC_RTCDIVR U(0x44) #define RCC_MSSCKSELR U(0x48) #define RCC_PLL1CR U(0x80) #define RCC_PLL1CFGR1 U(0x84) #define RCC_PLL1CFGR2 U(0x88) #define RCC_PLL1FRACR U(0x8C) #define RCC_PLL1CSGR U(0x90) #define RCC_PLL2CR U(0x94) #define RCC_PLL2CFGR1 U(0x98) #define RCC_PLL2CFGR2 U(0x9C) #define RCC_PLL2FRACR U(0xA0) #define RCC_PLL2CSGR U(0xA4) #define RCC_I2C46CKSELR U(0xC0) #define RCC_SPI6CKSELR U(0xC4) #define RCC_UART1CKSELR U(0xC8) #define RCC_RNG1CKSELR U(0xCC) #define RCC_CPERCKSELR U(0xD0) #define RCC_STGENCKSELR U(0xD4) #define RCC_DDRITFCR U(0xD8) #define RCC_MP_BOOTCR U(0x100) #define RCC_MP_SREQSETR U(0x104) #define RCC_MP_SREQCLRR U(0x108) #define RCC_MP_GCR U(0x10C) #define RCC_MP_APRSTCR U(0x110) #define RCC_MP_APRSTSR U(0x114) #define RCC_BDCR U(0x140) #define RCC_RDLSICR U(0x144) #define RCC_APB4RSTSETR U(0x180) #define RCC_APB4RSTCLRR U(0x184) #define RCC_APB5RSTSETR U(0x188) #define RCC_APB5RSTCLRR U(0x18C) #define RCC_AHB5RSTSETR U(0x190) #define RCC_AHB5RSTCLRR U(0x194) #define RCC_AHB6RSTSETR U(0x198) #define RCC_AHB6RSTCLRR U(0x19C) #define RCC_TZAHB6RSTSETR U(0x1A0) #define RCC_TZAHB6RSTCLRR U(0x1A4) #define RCC_MP_APB4ENSETR U(0x200) #define RCC_MP_APB4ENCLRR U(0x204) #define RCC_MP_APB5ENSETR U(0x208) #define RCC_MP_APB5ENCLRR U(0x20C) #define RCC_MP_AHB5ENSETR U(0x210) #define RCC_MP_AHB5ENCLRR U(0x214) #define RCC_MP_AHB6ENSETR U(0x218) #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) #define RCC_MP_APB5LPENCLRR U(0x30C) #define RCC_MP_AHB5LPENSETR U(0x310) #define RCC_MP_AHB5LPENCLRR U(0x314) #define RCC_MP_AHB6LPENSETR U(0x318) #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) #define RCC_MP_IWDGFZSETR U(0x40C) #define RCC_MP_IWDGFZCLRR U(0x410) #define RCC_MP_CIER U(0x414) #define RCC_MP_CIFR U(0x418) #define RCC_PWRLPDLYCR U(0x41C) #define RCC_MP_RSTSSETR U(0x420) #define RCC_MCO1CFGR U(0x800) #define RCC_MCO2CFGR U(0x804) #define RCC_OCRDYR U(0x808) #define RCC_DBGCFGR U(0x80C) #define RCC_RCK3SELR U(0x820) #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) #define RCC_PLL3CR U(0x880) #define RCC_PLL3CFGR1 U(0x884) #define RCC_PLL3CFGR2 U(0x888) #define RCC_PLL3FRACR U(0x88C) #define RCC_PLL3CSGR U(0x890) #define RCC_PLL4CR U(0x894) #define RCC_PLL4CFGR1 U(0x898) #define RCC_PLL4CFGR2 U(0x89C) #define RCC_PLL4FRACR U(0x8A0) #define RCC_PLL4CSGR U(0x8A4) #define RCC_I2C12CKSELR U(0x8C0) #define RCC_I2C35CKSELR U(0x8C4) #define RCC_SAI1CKSELR U(0x8C8) #define RCC_SAI2CKSELR U(0x8CC) #define RCC_SAI3CKSELR U(0x8D0) #define RCC_SAI4CKSELR U(0x8D4) #define RCC_SPI2S1CKSELR U(0x8D8) #define RCC_SPI2S23CKSELR U(0x8DC) #define RCC_SPI45CKSELR U(0x8E0) #define RCC_UART6CKSELR U(0x8E4) #define RCC_UART24CKSELR U(0x8E8) #define RCC_UART35CKSELR U(0x8EC) #define RCC_UART78CKSELR U(0x8F0) #define RCC_SDMMC12CKSELR U(0x8F4) #define RCC_SDMMC3CKSELR U(0x8F8) #define RCC_ETHCKSELR U(0x8FC) #define RCC_QSPICKSELR U(0x900) #define RCC_FMCCKSELR U(0x904) #define RCC_FDCANCKSELR U(0x90C) #define RCC_SPDIFCKSELR U(0x914) #define RCC_CECCKSELR U(0x918) #define RCC_USBCKSELR U(0x91C) #define RCC_RNG2CKSELR U(0x920) #define RCC_DSICKSELR U(0x924) #define RCC_ADCCKSELR U(0x928) #define RCC_LPTIM45CKSELR U(0x92C) #define RCC_LPTIM23CKSELR U(0x930) #define RCC_LPTIM1CKSELR U(0x934) #define RCC_APB1RSTSETR U(0x980) #define RCC_APB1RSTCLRR U(0x984) #define RCC_APB2RSTSETR U(0x988) #define RCC_APB2RSTCLRR U(0x98C) #define RCC_APB3RSTSETR U(0x990) #define RCC_APB3RSTCLRR U(0x994) #define RCC_AHB2RSTSETR U(0x998) #define RCC_AHB2RSTCLRR U(0x99C) #define RCC_AHB3RSTSETR U(0x9A0) #define RCC_AHB3RSTCLRR U(0x9A4) #define RCC_AHB4RSTSETR U(0x9A8) #define RCC_AHB4RSTCLRR U(0x9AC) #define RCC_MP_APB1ENSETR U(0xA00) #define RCC_MP_APB1ENCLRR U(0xA04) #define RCC_MP_APB2ENSETR U(0xA08) #define RCC_MP_APB2ENCLRR U(0xA0C) #define RCC_MP_APB3ENSETR U(0xA10) #define RCC_MP_APB3ENCLRR U(0xA14) #define RCC_MP_AHB2ENSETR U(0xA18) #define RCC_MP_AHB2ENCLRR U(0xA1C) #define RCC_MP_AHB3ENSETR U(0xA20) #define RCC_MP_AHB3ENCLRR U(0xA24) #define RCC_MP_AHB4ENSETR U(0xA28) #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) #define RCC_MP_APB2LPENCLRR U(0xB0C) #define RCC_MP_APB3LPENSETR U(0xB10) #define RCC_MP_APB3LPENCLRR U(0xB14) #define RCC_MP_AHB2LPENSETR U(0xB18) #define RCC_MP_AHB2LPENCLRR U(0xB1C) #define RCC_MP_AHB3LPENSETR U(0xB20) #define RCC_MP_AHB3LPENCLRR U(0xB24) #define RCC_MP_AHB4LPENSETR U(0xB28) #define RCC_MP_AHB4LPENCLRR U(0xB2C) #define RCC_MP_AXIMLPENSETR U(0xB30) #define RCC_MP_AXIMLPENCLRR U(0xB34) #define RCC_MP_MLAHBLPENSETR U(0xB38) #define RCC_MP_MLAHBLPENCLRR U(0xB3C) #define RCC_MC_APB1LPENSETR U(0xB80) #define RCC_MC_APB1LPENCLRR U(0xB84) #define RCC_MC_APB2LPENSETR U(0xB88) #define RCC_MC_APB2LPENCLRR U(0xB8C) #define RCC_MC_APB3LPENSETR U(0xB90) #define RCC_MC_APB3LPENCLRR U(0xB94) #define RCC_MC_AHB2LPENSETR U(0xB98) #define RCC_MC_AHB2LPENCLRR U(0xB9C) #define RCC_MC_AHB3LPENSETR U(0xBA0) #define RCC_MC_AHB3LPENCLRR U(0xBA4) #define RCC_MC_AHB4LPENSETR U(0xBA8) #define RCC_MC_AHB4LPENCLRR U(0xBAC) #define RCC_MC_AXIMLPENSETR U(0xBB0) #define RCC_MC_AXIMLPENCLRR U(0xBB4) #define RCC_MC_MLAHBLPENSETR U(0xBB8) #define RCC_MC_MLAHBLPENCLRR U(0xBBC) #define RCC_MC_RSTSCLRR U(0xC00) #define RCC_MC_CIER U(0xC14) #define RCC_MC_CIFR U(0xC18) #define RCC_VERR U(0xFF4) #define RCC_IDR U(0xFF8) #define RCC_SIDR U(0xFFC) #define RCC_OFFSET_MASK GENMASK(11, 0) /* Values for RCC_TZCR register */ #define RCC_TZCR_TZEN BIT(0) #define RCC_TZCR_MCKPROT BIT(1) /* Used for most of RCC_SELR registers */ #define RCC_SELR_SRC_MASK GENMASK(2, 0) #define RCC_SELR_REFCLK_SRC_MASK GENMASK(1, 0) #define RCC_SELR_SRCRDY BIT(31) /* Values of RCC_MPCKSELR register */ #define RCC_MPCKSELR_HSI 0x00000000 #define RCC_MPCKSELR_HSE 0x00000001 #define RCC_MPCKSELR_PLL 0x00000002 #define RCC_MPCKSELR_PLL_MPUDIV 0x00000003 /* Values of RCC_ASSCKSELR register */ #define RCC_ASSCKSELR_HSI 0x00000000 #define RCC_ASSCKSELR_HSE 0x00000001 #define RCC_ASSCKSELR_PLL 0x00000002 /* Values of RCC_MSSCKSELR register */ #define RCC_MSSCKSELR_HSI 0x00000000 #define RCC_MSSCKSELR_HSE 0x00000001 #define RCC_MSSCKSELR_CSI 0x00000002 #define RCC_MSSCKSELR_PLL 0x00000003 /* Values of RCC_CPERCKSELR register */ #define RCC_CPERCKSELR_HSI 0x00000000 #define RCC_CPERCKSELR_CSI 0x00000001 #define RCC_CPERCKSELR_HSE 0x00000002 /* Used for most of DIVR register: max div for RTC */ #define RCC_DIVR_DIV_MASK GENMASK(5, 0) #define RCC_DIVR_DIVRDY BIT(31) /* Masks for specific DIVR registers */ #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) /* Offset between RCC_xxxRSTSETR and RCC_xxxRSTCLRR registers */ #define RCC_RSTCLRR_OFFSET U(4) /* Fields of RCC_BDCR register */ #define RCC_BDCR_LSEON BIT(0) #define RCC_BDCR_LSEBYP BIT(1) #define RCC_BDCR_LSERDY BIT(2) #define RCC_BDCR_DIGBYP BIT(3) #define RCC_BDCR_LSEDRV_MASK GENMASK(5, 4) #define RCC_BDCR_LSEDRV_SHIFT 4 #define RCC_BDCR_LSECSSON BIT(8) #define RCC_BDCR_RTCCKEN BIT(20) #define RCC_BDCR_RTCSRC_MASK GENMASK(17, 16) #define RCC_BDCR_RTCSRC_SHIFT 16 #define RCC_BDCR_VSWRST BIT(31) /* Fields of RCC_RDLSICR register */ #define RCC_RDLSICR_LSION BIT(0) #define RCC_RDLSICR_LSIRDY BIT(1) /* Used for all RCC_PLLCR registers */ #define RCC_PLLNCR_PLLON BIT(0) #define RCC_PLLNCR_PLLRDY BIT(1) #define RCC_PLLNCR_SSCG_CTRL BIT(2) #define RCC_PLLNCR_DIVPEN BIT(4) #define RCC_PLLNCR_DIVQEN BIT(5) #define RCC_PLLNCR_DIVREN BIT(6) #define RCC_PLLNCR_DIVEN_SHIFT 4 /* Used for all RCC_PLLCFGR1 registers */ #define RCC_PLLNCFGR1_DIVM_SHIFT 16 #define RCC_PLLNCFGR1_DIVM_MASK GENMASK(21, 16) #define RCC_PLLNCFGR1_DIVN_SHIFT 0 #define RCC_PLLNCFGR1_DIVN_MASK GENMASK(8, 0) /* Only for PLL3 and PLL4 */ #define RCC_PLLNCFGR1_IFRGE_SHIFT 24 #define RCC_PLLNCFGR1_IFRGE_MASK GENMASK(25, 24) /* Used for all RCC_PLLCFGR2 registers */ #define RCC_PLLNCFGR2_DIVX_MASK GENMASK(6, 0) #define RCC_PLLNCFGR2_DIVP_SHIFT 0 #define RCC_PLLNCFGR2_DIVP_MASK GENMASK(6, 0) #define RCC_PLLNCFGR2_DIVQ_SHIFT 8 #define RCC_PLLNCFGR2_DIVQ_MASK GENMASK(14, 8) #define RCC_PLLNCFGR2_DIVR_SHIFT 16 #define RCC_PLLNCFGR2_DIVR_MASK GENMASK(22, 16) /* Used for all RCC_PLLFRACR registers */ #define RCC_PLLNFRACR_FRACV_SHIFT 3 #define RCC_PLLNFRACR_FRACV_MASK GENMASK(15, 3) #define RCC_PLLNFRACR_FRACLE BIT(16) /* Used for all RCC_PLLCSGR registers */ #define RCC_PLLNCSGR_INC_STEP_SHIFT 16 #define RCC_PLLNCSGR_INC_STEP_MASK GENMASK(30, 16) #define RCC_PLLNCSGR_MOD_PER_SHIFT 0 #define RCC_PLLNCSGR_MOD_PER_MASK GENMASK(12, 0) #define RCC_PLLNCSGR_SSCG_MODE_SHIFT 15 #define RCC_PLLNCSGR_SSCG_MODE_MASK BIT(15) /* Used for RCC_OCENSETR and RCC_OCENCLRR registers */ #define RCC_OCENR_HSION BIT(0) #define RCC_OCENR_HSIKERON BIT(1) #define RCC_OCENR_CSION BIT(4) #define RCC_OCENR_CSIKERON BIT(5) #define RCC_OCENR_DIGBYP BIT(7) #define RCC_OCENR_HSEON BIT(8) #define RCC_OCENR_HSEKERON BIT(9) #define RCC_OCENR_HSEBYP BIT(10) #define RCC_OCENR_HSECSSON BIT(11) /* Fields of RCC_OCRDYR register */ #define RCC_OCRDYR_HSIRDY BIT(0) #define RCC_OCRDYR_HSIDIVRDY BIT(2) #define RCC_OCRDYR_CSIRDY BIT(4) #define RCC_OCRDYR_HSERDY BIT(8) /* Fields of RCC_DDRITFCR register */ #define RCC_DDRITFCR_DDRC1EN BIT(0) #define RCC_DDRITFCR_DDRC1LPEN BIT(1) #define RCC_DDRITFCR_DDRC2EN BIT(2) #define RCC_DDRITFCR_DDRC2LPEN BIT(3) #define RCC_DDRITFCR_DDRPHYCEN BIT(4) #define RCC_DDRITFCR_DDRPHYCLPEN BIT(5) #define RCC_DDRITFCR_DDRCAPBEN BIT(6) #define RCC_DDRITFCR_DDRCAPBLPEN BIT(7) #define RCC_DDRITFCR_AXIDCGEN BIT(8) #define RCC_DDRITFCR_DDRPHYCAPBEN BIT(9) #define RCC_DDRITFCR_DDRPHYCAPBLPEN BIT(10) #define RCC_DDRITFCR_DDRCAPBRST BIT(14) #define RCC_DDRITFCR_DDRCAXIRST BIT(15) #define RCC_DDRITFCR_DDRCORERST BIT(16) #define RCC_DDRITFCR_DPHYAPBRST BIT(17) #define RCC_DDRITFCR_DPHYRST BIT(18) #define RCC_DDRITFCR_DPHYCTLRST BIT(19) #define RCC_DDRITFCR_DDRCKMOD_MASK GENMASK(22, 20) #define RCC_DDRITFCR_DDRCKMOD_SHIFT 20 #define RCC_DDRITFCR_DDRCKMOD_SSR 0 #define RCC_DDRITFCR_DDRCKMOD_ASR1 BIT(20) #define RCC_DDRITFCR_DDRCKMOD_HSR1 BIT(21) #define RCC_DDRITFCR_GSKPCTRL BIT(24) /* Fields of RCC_HSICFGR register */ #define RCC_HSICFGR_HSIDIV_MASK GENMASK(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) #define RCC_MCOCFG_MCODIV_MASK GENMASK(7, 4) #define RCC_MCOCFG_MCODIV_SHIFT 4 #define RCC_MCOCFG_MCOSRC_MASK GENMASK(2, 0) /* Fields of RCC_DBGCFGR register */ #define RCC_DBGCFGR_DBGCKEN BIT(8) /* RCC register fields for reset reasons */ #define RCC_MP_RSTSCLRR_PORRSTF BIT(0) #define RCC_MP_RSTSCLRR_BORRSTF BIT(1) #define RCC_MP_RSTSCLRR_PADRSTF BIT(2) #define RCC_MP_RSTSCLRR_HCSSRSTF BIT(3) #define RCC_MP_RSTSCLRR_VCORERSTF BIT(4) #define RCC_MP_RSTSCLRR_MPSYSRSTF BIT(6) #define RCC_MP_RSTSCLRR_MCSYSRSTF BIT(7) #define RCC_MP_RSTSCLRR_IWDG1RSTF BIT(8) #define RCC_MP_RSTSCLRR_IWDG2RSTF BIT(9) #define RCC_MP_RSTSCLRR_STDBYRSTF BIT(11) #define RCC_MP_RSTSCLRR_CSTDBYRSTF BIT(12) #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 */ #define RCC_MP_SREQSETR_STPREQ_P0 BIT(0) #define RCC_MP_SREQSETR_STPREQ_P1 BIT(1) /* Stop Request Clear Register */ #define RCC_MP_SREQCLRR_STPREQ_P0 BIT(0) #define RCC_MP_SREQCLRR_STPREQ_P1 BIT(1) /* Values of RCC_UART24CKSELR register */ #define RCC_UART24CKSELR_HSI 0x00000002 /* 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) /* RCC_ASSCKSELR register fields */ #define RCC_ASSCKSELR_AXISSRC_MASK GENMASK(2, 0) #define RCC_ASSCKSELR_AXISSRC_SHIFT 0 /* RCC_MSSCKSELR register fields */ #define RCC_MSSCKSELR_MCUSSRC_MASK GENMASK(1, 0) #define RCC_MSSCKSELR_MCUSSRC_SHIFT 0 /* RCC_I2C46CKSELR register fields */ #define RCC_I2C46CKSELR_I2C46SRC_MASK GENMASK(2, 0) #define RCC_I2C46CKSELR_I2C46SRC_SHIFT 0 /* RCC_SPI6CKSELR register fields */ #define RCC_SPI6CKSELR_SPI6SRC_MASK GENMASK(2, 0) #define RCC_SPI6CKSELR_SPI6SRC_SHIFT 0 /* RCC_UART1CKSELR register fields */ #define RCC_UART1CKSELR_UART1SRC_MASK GENMASK(2, 0) #define RCC_UART1CKSELR_UART1SRC_SHIFT 0 /* RCC_RNG1CKSELR register fields */ #define RCC_RNG1CKSELR_RNG1SRC_MASK GENMASK(1, 0) #define RCC_RNG1CKSELR_RNG1SRC_SHIFT 0 /* RCC_STGENCKSELR register fields */ #define RCC_STGENCKSELR_STGENSRC_MASK GENMASK(1, 0) #define RCC_STGENCKSELR_STGENSRC_SHIFT 0 /* RCC_I2C12CKSELR register fields */ #define RCC_I2C12CKSELR_I2C12SRC_MASK GENMASK(2, 0) #define RCC_I2C12CKSELR_I2C12SRC_SHIFT 0 /* RCC_I2C35CKSELR register fields */ #define RCC_I2C35CKSELR_I2C35SRC_MASK GENMASK(2, 0) #define RCC_I2C35CKSELR_I2C35SRC_SHIFT 0 /* RCC_UART6CKSELR register fields */ #define RCC_UART6CKSELR_UART6SRC_MASK GENMASK(2, 0) #define RCC_UART6CKSELR_UART6SRC_SHIFT 0 /* RCC_UART24CKSELR register fields */ #define RCC_UART24CKSELR_UART24SRC_MASK GENMASK(2, 0) #define RCC_UART24CKSELR_UART24SRC_SHIFT 0 /* RCC_UART35CKSELR register fields */ #define RCC_UART35CKSELR_UART35SRC_MASK GENMASK(2, 0) #define RCC_UART35CKSELR_UART35SRC_SHIFT 0 /* RCC_UART78CKSELR register fields */ #define RCC_UART78CKSELR_UART78SRC_MASK GENMASK(2, 0) #define RCC_UART78CKSELR_UART78SRC_SHIFT 0 /* RCC_SDMMC12CKSELR register fields */ #define RCC_SDMMC12CKSELR_SDMMC12SRC_MASK GENMASK(2, 0) #define RCC_SDMMC12CKSELR_SDMMC12SRC_SHIFT 0 /* RCC_SDMMC3CKSELR register fields */ #define RCC_SDMMC3CKSELR_SDMMC3SRC_MASK GENMASK(2, 0) #define RCC_SDMMC3CKSELR_SDMMC3SRC_SHIFT 0 /* RCC_ETHCKSELR register fields */ #define RCC_ETHCKSELR_ETHSRC_MASK GENMASK(1, 0) #define RCC_ETHCKSELR_ETHSRC_SHIFT 0 /* RCC_QSPICKSELR register fields */ #define RCC_QSPICKSELR_QSPISRC_MASK GENMASK(1, 0) #define RCC_QSPICKSELR_QSPISRC_SHIFT 0 /* RCC_FMCCKSELR register fields */ #define RCC_FMCCKSELR_FMCSRC_MASK GENMASK(1, 0) #define RCC_FMCCKSELR_FMCSRC_SHIFT 0 /* RCC_USBCKSELR register fields */ #define RCC_USBCKSELR_USBPHYSRC_MASK GENMASK(1, 0) #define RCC_USBCKSELR_USBPHYSRC_SHIFT 0 #define RCC_USBCKSELR_USBOSRC_MASK BIT(4) #define RCC_USBCKSELR_USBOSRC_SHIFT 4 #endif /* STM32MP1_RCC_H */ trusted-firmware-a-2.2/include/drivers/st/stm32mp_clkfunc.h000066400000000000000000000016311355360272700240240ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32MP_CLKFUNC_H #define STM32MP_CLKFUNC_H #include #include #include int fdt_osc_read_freq(const char *name, uint32_t *freq); bool fdt_osc_read_bool(enum stm32mp_osc_id osc_id, const char *prop_name); uint32_t fdt_osc_read_uint32_default(enum stm32mp_osc_id osc_id, const char *prop_name, uint32_t dflt_value); int fdt_get_rcc_node(void *fdt); uint32_t fdt_rcc_read_addr(void); int fdt_rcc_read_uint32_array(const char *prop_name, uint32_t *array, uint32_t count); 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); #endif /* STM32MP_CLKFUNC_H */ trusted-firmware-a-2.2/include/drivers/st/stm32mp_pmic.h000066400000000000000000000022031355360272700233230ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32MP_PMIC_H #define STM32MP_PMIC_H #include #include /* * dt_pmic_status - Check PMIC status from device tree * * Returns the status of the PMIC (secure, non-secure), or a negative value on * error */ int dt_pmic_status(void); /* * dt_pmic_configure_boot_on_regulators - Configure boot-on and always-on * regulators from device tree configuration * * Returns 0 on success, and negative values on errors */ int dt_pmic_configure_boot_on_regulators(void); /* * initialize_pmic_i2c - Initialize I2C for the PMIC control * * Returns true if PMIC is available, false if not found, panics on errors */ bool initialize_pmic_i2c(void); /* * initialize_pmic - Main PMIC initialization function, called at platform init * * Panics on errors */ void initialize_pmic(void); /* * pmic_ddr_power_init - Initialize regulators required for DDR * * Returns 0 on success, and negative values on errors */ int pmic_ddr_power_init(enum ddr_type ddr_type); #endif /* STM32MP_PMIC_H */ trusted-firmware-a-2.2/include/drivers/st/stm32mp_reset.h000066400000000000000000000004731355360272700235240ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32MP_RESET_H #define STM32MP_RESET_H #include void stm32mp_reset_assert(uint32_t reset_id); void stm32mp_reset_deassert(uint32_t reset_id); #endif /* STM32MP_RESET_H */ trusted-firmware-a-2.2/include/drivers/st/stpmic1.h000066400000000000000000000124051355360272700223730ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STPMIC1_H #define STPMIC1_H #include #include #define TURN_ON_REG 0x1U #define TURN_OFF_REG 0x2U #define ICC_LDO_TURN_OFF_REG 0x3U #define ICC_BUCK_TURN_OFF_REG 0x4U #define RESET_STATUS_REG 0x5U #define VERSION_STATUS_REG 0x6U #define MAIN_CONTROL_REG 0x10U #define PADS_PULL_REG 0x11U #define BUCK_PULL_DOWN_REG 0x12U #define LDO14_PULL_DOWN_REG 0x13U #define LDO56_PULL_DOWN_REG 0x14U #define VIN_CONTROL_REG 0x15U #define PONKEY_TIMER_REG 0x16U #define MASK_RANK_BUCK_REG 0x17U #define MASK_RESET_BUCK_REG 0x18U #define MASK_RANK_LDO_REG 0x19U #define MASK_RESET_LDO_REG 0x1AU #define WATCHDOG_CONTROL_REG 0x1BU #define WATCHDOG_TIMER_REG 0x1CU #define BUCK_ICC_TURNOFF_REG 0x1DU #define LDO_ICC_TURNOFF_REG 0x1EU #define BUCK_APM_CONTROL_REG 0x1FU #define BUCK1_CONTROL_REG 0x20U #define BUCK2_CONTROL_REG 0x21U #define BUCK3_CONTROL_REG 0x22U #define BUCK4_CONTROL_REG 0x23U #define VREF_DDR_CONTROL_REG 0x24U #define LDO1_CONTROL_REG 0x25U #define LDO2_CONTROL_REG 0x26U #define LDO3_CONTROL_REG 0x27U #define LDO4_CONTROL_REG 0x28U #define LDO5_CONTROL_REG 0x29U #define LDO6_CONTROL_REG 0x2AU #define BUCK1_PWRCTRL_REG 0x30U #define BUCK2_PWRCTRL_REG 0x31U #define BUCK3_PWRCTRL_REG 0x32U #define BUCK4_PWRCTRL_REG 0x33U #define VREF_DDR_PWRCTRL_REG 0x34U #define LDO1_PWRCTRL_REG 0x35U #define LDO2_PWRCTRL_REG 0x36U #define LDO3_PWRCTRL_REG 0x37U #define LDO4_PWRCTRL_REG 0x38U #define LDO5_PWRCTRL_REG 0x39U #define LDO6_PWRCTRL_REG 0x3AU #define FREQUENCY_SPREADING_REG 0x3BU #define USB_CONTROL_REG 0x40U #define ITLATCH1_REG 0x50U #define ITLATCH2_REG 0x51U #define ITLATCH3_REG 0x52U #define ITLATCH4_REG 0x53U #define ITSETLATCH1_REG 0x60U #define ITSETLATCH2_REG 0x61U #define ITSETLATCH3_REG 0x62U #define ITSETLATCH4_REG 0x63U #define ITCLEARLATCH1_REG 0x70U #define ITCLEARLATCH2_REG 0x71U #define ITCLEARLATCH3_REG 0x72U #define ITCLEARLATCH4_REG 0x73U #define ITMASK1_REG 0x80U #define ITMASK2_REG 0x81U #define ITMASK3_REG 0x82U #define ITMASK4_REG 0x83U #define ITSETMASK1_REG 0x90U #define ITSETMASK2_REG 0x91U #define ITSETMASK3_REG 0x92U #define ITSETMASK4_REG 0x93U #define ITCLEARMASK1_REG 0xA0U #define ITCLEARMASK2_REG 0xA1U #define ITCLEARMASK3_REG 0xA2U #define ITCLEARMASK4_REG 0xA3U #define ITSOURCE1_REG 0xB0U #define ITSOURCE2_REG 0xB1U #define ITSOURCE3_REG 0xB2U #define ITSOURCE4_REG 0xB3U /* Registers masks */ #define LDO_VOLTAGE_MASK 0x7CU #define BUCK_VOLTAGE_MASK 0xFCU #define LDO_BUCK_VOLTAGE_SHIFT 2 #define LDO_BUCK_ENABLE_MASK 0x01U #define LDO_BUCK_HPLP_ENABLE_MASK 0x02U #define LDO_BUCK_HPLP_SHIFT 1 #define LDO_BUCK_RANK_MASK 0x01U #define LDO_BUCK_RESET_MASK 0x01U #define LDO_BUCK_PULL_DOWN_MASK 0x03U /* Pull down register */ #define BUCK1_PULL_DOWN_SHIFT 0 #define BUCK2_PULL_DOWN_SHIFT 2 #define BUCK3_PULL_DOWN_SHIFT 4 #define BUCK4_PULL_DOWN_SHIFT 6 #define VREF_DDR_PULL_DOWN_SHIFT 4 /* Buck Mask reset register */ #define BUCK1_MASK_RESET 0 #define BUCK2_MASK_RESET 1 #define BUCK3_MASK_RESET 2 #define BUCK4_MASK_RESET 3 /* LDO Mask reset register */ #define LDO1_MASK_RESET 0 #define LDO2_MASK_RESET 1 #define LDO3_MASK_RESET 2 #define LDO4_MASK_RESET 3 #define LDO5_MASK_RESET 4 #define LDO6_MASK_RESET 5 #define VREF_DDR_MASK_RESET 6 /* Main PMIC Control Register (MAIN_CONTROL_REG) */ #define ICC_EVENT_ENABLED BIT(4) #define PWRCTRL_POLARITY_HIGH BIT(3) #define PWRCTRL_PIN_VALID BIT(2) #define RESTART_REQUEST_ENABLED BIT(1) #define SOFTWARE_SWITCH_OFF_ENABLED BIT(0) /* Main PMIC PADS Control Register (PADS_PULL_REG) */ #define WAKEUP_DETECTOR_DISABLED BIT(4) #define PWRCTRL_PD_ACTIVE BIT(3) #define PWRCTRL_PU_ACTIVE BIT(2) #define WAKEUP_PD_ACTIVE BIT(1) #define PONKEY_PU_ACTIVE BIT(0) /* Main PMIC VINLOW Control Register (VIN_CONTROL_REGC DMSC) */ #define SWIN_DETECTOR_ENABLED BIT(7) #define SWOUT_DETECTOR_ENABLED BIT(6) #define VINLOW_HYST_MASK 0x3 #define VINLOW_HYST_SHIFT 4 #define VINLOW_THRESHOLD_MASK 0x7 #define VINLOW_THRESHOLD_SHIFT 1 #define VINLOW_ENABLED 0x01 #define VINLOW_CTRL_REG_MASK 0xFF /* USB Control Register */ #define BOOST_OVP_DISABLED BIT(7) #define VBUS_OTG_DETECTION_DISABLED BIT(6) #define OCP_LIMIT_HIGH BIT(3) #define SWIN_SWOUT_ENABLED BIT(2) #define USBSW_OTG_SWITCH_ENABLED BIT(1) int stpmic1_powerctrl_on(void); int stpmic1_switch_off(void); int stpmic1_register_read(uint8_t register_id, uint8_t *value); int stpmic1_register_write(uint8_t register_id, uint8_t value); int stpmic1_register_update(uint8_t register_id, uint8_t value, uint8_t mask); int stpmic1_regulator_enable(const char *name); int stpmic1_regulator_disable(const char *name); uint8_t stpmic1_is_regulator_enabled(const char *name); int stpmic1_regulator_voltage_set(const char *name, uint16_t millivolts); int stpmic1_regulator_voltage_get(const char *name); int stpmic1_regulator_pull_down_set(const char *name); int stpmic1_regulator_mask_reset_set(const char *name); 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 */ trusted-firmware-a-2.2/include/drivers/synopsys/000077500000000000000000000000001355360272700221215ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/synopsys/dw_mmc.h000066400000000000000000000007541355360272700235460ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef DW_MMC_H #define DW_MMC_H #include typedef struct dw_mmc_params { uintptr_t reg_base; uintptr_t desc_base; size_t desc_size; int clk_rate; int bus_width; unsigned int flags; enum mmc_device_type mmc_dev_type; } dw_mmc_params_t; void dw_mmc_init(dw_mmc_params_t *params, struct mmc_device_info *info); #endif /* DW_MMC_H */ trusted-firmware-a-2.2/include/drivers/ti/000077500000000000000000000000001355360272700206265ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/ti/uart/000077500000000000000000000000001355360272700216015ustar00rootroot00000000000000trusted-firmware-a-2.2/include/drivers/ti/uart/uart_16550.h000066400000000000000000000061131355360272700234660ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef UART_16550_H #define UART_16550_H #include /* UART16550 Registers */ #define UARTTX 0x0 #define UARTRX 0x0 #define UARTDLL 0x0 #define UARTIER 0x4 #define UARTDLLM 0x4 #define UARTIIR 0x8 #define UARTFCR 0x8 #define UARTLCR 0xc #define UARTMCR 0x10 #define UARTLSR 0x14 #define UARTMSR 0x18 #define UARTSPR 0x1c #define UARTCSR 0x20 /* Some instances have MDR1 defined as well */ #define UARTMDR1 0x20 #define UARTRXFIFOCFG 0x24 #define UARTMIE 0x28 #define UARTVNDR 0x2c #define UARTASR 0x3c /* FIFO Control Register bits */ #define UARTFCR_FIFOMD_16450 (0 << 6) #define UARTFCR_FIFOMD_16550 (1 << 6) #define UARTFCR_RXTRIG_1 (0 << 6) #define UARTFCR_RXTRIG_4 (1 << 6) #define UARTFCR_RXTRIG_8 (2 << 6) #define UARTFCR_RXTRIG_16 (3 << 6) #define UARTFCR_TXTRIG_1 (0 << 4) #define UARTFCR_TXTRIG_4 (1 << 4) #define UARTFCR_TXTRIG_8 (2 << 4) #define UARTFCR_TXTRIG_16 (3 << 4) #define UARTFCR_DMAEN (1 << 3) /* Enable DMA mode */ #define UARTFCR_TXCLR (1 << 2) /* Clear contents of Tx FIFO */ #define UARTFCR_RXCLR (1 << 1) /* Clear contents of Rx FIFO */ #define UARTFCR_FIFOEN (1 << 0) /* Enable the Tx/Rx FIFO */ /* Line Control Register bits */ #define UARTLCR_DLAB (1 << 7) /* Divisor Latch Access */ #define UARTLCR_SETB (1 << 6) /* Set BREAK Condition */ #define UARTLCR_SETP (1 << 5) /* Set Parity to LCR[4] */ #define UARTLCR_EVEN (1 << 4) /* Even Parity Format */ #define UARTLCR_PAR (1 << 3) /* Parity */ #define UARTLCR_STOP (1 << 2) /* Stop Bit */ #define UARTLCR_WORDSZ_5 0 /* Word Length of 5 */ #define UARTLCR_WORDSZ_6 1 /* Word Length of 6 */ #define UARTLCR_WORDSZ_7 2 /* Word Length of 7 */ #define UARTLCR_WORDSZ_8 3 /* Word Length of 8 */ /* Line Status Register bits */ #define UARTLSR_RXFIFOEMT (1 << 9) /* Rx Fifo Empty */ #define UARTLSR_TXFIFOFULL (1 << 8) /* Tx Fifo Full */ #define UARTLSR_RXFIFOERR (1 << 7) /* Rx Fifo Error */ #define UARTLSR_TEMT (1 << 6) /* Tx Shift Register Empty */ #define UARTLSR_THRE (1 << 5) /* Tx Holding Register Empty */ #define UARTLSR_BRK (1 << 4) /* Break Condition Detected */ #define UARTLSR_FERR (1 << 3) /* Framing Error */ #define UARTLSR_PERR (1 << 3) /* Parity Error */ #define UARTLSR_OVRF (1 << 2) /* Rx Overrun Error */ #define UARTLSR_RDR_BIT (0) /* Rx Data Ready Bit */ #define UARTLSR_RDR (1 << UARTLSR_RDR_BIT) /* Rx Data Ready */ #define CONSOLE_T_16550_BASE CONSOLE_T_DRVDATA #ifndef __ASSEMBLER__ #include typedef struct { console_t console; uintptr_t base; } console_16550_t; /* * Initialize a new 16550 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_16550_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, console_16550_t *console); #endif /*__ASSEMBLER__*/ #endif /* UART_16550_H */ trusted-firmware-a-2.2/include/drivers/ufs.h000066400000000000000000000337731355360272700211750ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef UFS_H #define UFS_H #include /* register map of UFSHCI */ /* Controller Capabilities */ #define CAP 0x00 #define CAP_NUTRS_MASK 0x1F /* UFS Version */ #define VER 0x08 /* Host Controller Identification - Product ID */ #define HCDDID 0x10 /* Host Controller Identification Descriptor - Manufacturer ID */ #define HCPMID 0x14 /* Auto-Hibernate Idle Timer */ #define AHIT 0x18 /* Interrupt Status */ #define IS 0x20 /* Interrupt Enable */ #define IE 0x24 /* System Bus Fatal Error Status */ #define UFS_INT_SBFES (1 << 17) /* Host Controller Fatal Error Status */ #define UFS_INT_HCFES (1 << 16) /* UTP Error Status */ #define UFS_INT_UTPES (1 << 12) /* Device Fatal Error Status */ #define UFS_INT_DFES (1 << 11) /* UIC Command Completion Status */ #define UFS_INT_UCCS (1 << 10) /* UTP Task Management Request Completion Status */ #define UFS_INT_UTMRCS (1 << 9) /* UIC Link Startup Status */ #define UFS_INT_ULSS (1 << 8) /* UIC Link Lost Status */ #define UFS_INT_ULLS (1 << 7) /* UIC Hibernate Enter Status */ #define UFS_INT_UHES (1 << 6) /* UIC Hibernate Exit Status */ #define UFS_INT_UHXS (1 << 5) /* UIC Power Mode Status */ #define UFS_INT_UPMS (1 << 4) /* UIC Test Mode Status */ #define UFS_INT_UTMS (1 << 3) /* UIC Error */ #define UFS_INT_UE (1 << 2) /* UIC DME_ENDPOINTRESET Indication */ #define UFS_INT_UDEPRI (1 << 1) /* UTP Transfer Request Completion Status */ #define UFS_INT_UTRCS (1 << 0) /* Host Controller Status */ #define HCS 0x30 #define HCS_UPMCRS_MASK (7 << 8) #define HCS_PWR_LOCAL (1 << 8) #define HCS_UCRDY (1 << 3) #define HCS_UTMRLRDY (1 << 2) #define HCS_UTRLRDY (1 << 1) #define HCS_DP (1 << 0) /* Host Controller Enable */ #define HCE 0x34 #define HCE_ENABLE 1 /* Host UIC Error Code PHY Adapter Layer */ #define UECPA 0x38 /* Host UIC Error Code Data Link Layer */ #define UECDL 0x3C /* Host UIC Error Code Network Layer */ #define UECN 0x40 /* Host UIC Error Code Transport Layer */ #define UECT 0x44 /* Host UIC Error Code */ #define UECDME 0x48 /* UTP Transfer Request Interrupt Aggregation Control Register */ #define UTRIACR 0x4C #define UTRIACR_IAEN (1U << 31) #define UTRIACR_IAPWEN (1 << 24) #define UTRIACR_IASB (1 << 20) #define UTRIACR_CTR (1 << 16) #define UTRIACR_IACTH(x) (((x) & 0x1F) << 8) #define UTRIACR_IATOVAL(x) ((x) & 0xFF) /* UTP Transfer Request List Base Address */ #define UTRLBA 0x50 /* UTP Transfer Request List Base Address Upper 32-bits */ #define UTRLBAU 0x54 /* UTP Transfer Request List Door Bell Register */ #define UTRLDBR 0x58 /* UTP Transfer Request List Clear Register */ #define UTRLCLR 0x5C /* UTP Transfer Request List Run Stop Register */ #define UTRLRSR 0x60 #define UTMRLBA 0x70 #define UTMRLBAU 0x74 #define UTMRLDBR 0x78 #define UTMRLCLR 0x7C #define UTMRLRSR 0x80 /* UIC Command */ #define UICCMD 0x90 /* UIC Command Argument 1 */ #define UCMDARG1 0x94 /* UIC Command Argument 2 */ #define UCMDARG2 0x98 /* UIC Command Argument 3 */ #define UCMDARG3 0x9C #define UFS_BLOCK_SHIFT 12 /* 4KB */ #define UFS_BLOCK_SIZE (1 << UFS_BLOCK_SHIFT) #define UFS_BLOCK_MASK (UFS_BLOCK_SIZE - 1) #define UFS_MAX_LUNS 8 /* UTP Transfer Request Descriptor */ /* Command Type */ #define CT_UFS_STORAGE 1 #define CT_SCSI 0 /* Data Direction */ #define DD_OUT 2 /* Device --> Host */ #define DD_IN 1 /* Host --> Device */ #define DD_NO_DATA_TRANSFER 0 #define UTP_TRD_SIZE 32 /* Transaction Type */ #define TRANS_TYPE_HD (1 << 7) /* E2ECRC */ #define TRANS_TYPE_DD (1 << 6) #define TRANS_TYPE_CODE_MASK 0x3F #define QUERY_RESPONSE_UPIU (0x36 << 0) #define READY_TO_TRANSACTION_UPIU (0x31 << 0) #define DATA_IN_UPIU (0x22 << 0) #define RESPONSE_UPIU (0x21 << 0) #define NOP_IN_UPIU (0x20 << 0) #define QUERY_REQUEST_UPIU (0x16 << 0) #define DATA_OUT_UPIU (0x02 << 0) #define CMD_UPIU (0x01 << 0) #define NOP_OUT_UPIU (0x00 << 0) #define OCS_SUCCESS 0x0 #define OCS_INVALID_FUNC_ATTRIBUTE 0x1 #define OCS_MISMATCH_REQUEST_SIZE 0x2 #define OCS_MISMATCH_RESPONSE_SIZE 0x3 #define OCS_PEER_COMMUNICATION_FAILURE 0x4 #define OCS_ABORTED 0x5 #define OCS_FATAL_ERROR 0x6 #define OCS_MASK 0xF /* UIC Command */ #define DME_GET 0x01 #define DME_SET 0x02 #define DME_PEER_GET 0x03 #define DME_PEER_SET 0x04 #define DME_POWERON 0x10 #define DME_POWEROFF 0x11 #define DME_ENABLE 0x12 #define DME_RESET 0x14 #define DME_ENDPOINTRESET 0x15 #define DME_LINKSTARTUP 0x16 #define DME_HIBERNATE_ENTER 0x17 #define DME_HIBERNATE_EXIT 0x18 #define DME_TEST_MODE 0x1A #define GEN_SELECTOR_IDX(x) ((x) & 0xFFFF) #define CONFIG_RESULT_CODE_MASK 0xFF #define CDBCMD_TEST_UNIT_READY 0x00 #define CDBCMD_READ_6 0x08 #define CDBCMD_WRITE_6 0x0A #define CDBCMD_START_STOP_UNIT 0x1B #define CDBCMD_READ_CAPACITY_10 0x25 #define CDBCMD_READ_10 0x28 #define CDBCMD_WRITE_10 0x2A #define CDBCMD_READ_16 0x88 #define CDBCMD_WRITE_16 0x8A #define CDBCMD_READ_CAPACITY_16 0x9E #define CDBCMD_REPORT_LUNS 0xA0 #define UPIU_FLAGS_R (1 << 6) #define UPIU_FLAGS_W (1 << 5) #define UPIU_FLAGS_ATTR_MASK (3 << 0) #define UPIU_FLAGS_ATTR_S (0 << 0) /* Simple */ #define UPIU_FLAGS_ATTR_O (1 << 0) /* Ordered */ #define UPIU_FLAGS_ATTR_HQ (2 << 0) /* Head of Queue */ #define UPIU_FLAGS_ATTR_ACA (3 << 0) #define UPIU_FLAGS_O (1 << 6) #define UPIU_FLAGS_U (1 << 5) #define UPIU_FLAGS_D (1 << 4) #define QUERY_FUNC_STD_READ 0x01 #define QUERY_FUNC_STD_WRITE 0x81 #define QUERY_NOP 0x00 #define QUERY_READ_DESC 0x01 #define QUERY_WRITE_DESC 0x02 #define QUERY_READ_ATTR 0x03 #define QUERY_WRITE_ATTR 0x04 #define QUERY_READ_FLAG 0x05 #define QUERY_SET_FLAG 0x06 #define QUERY_CLEAR_FLAG 0x07 #define QUERY_TOGGLE_FLAG 0x08 #define RW_WITHOUT_CACHE 0x18 #define DESC_TYPE_DEVICE 0x00 #define DESC_TYPE_CONFIGURATION 0x01 #define DESC_TYPE_UNIT 0x02 #define DESC_TYPE_INTERCONNECT 0x04 #define DESC_TYPE_STRING 0x05 #define DESC_DEVICE_MAX_SIZE 0x1F #define DEVICE_DESC_PARAM_MANF_ID 0x18 #define ATTR_CUR_PWR_MODE 0x02 /* bCurrentPowerMode */ #define ATTR_ACTIVECC 0x03 /* bActiveICCLevel */ #define DEVICE_DESCRIPTOR_LEN 0x40 #define UNIT_DESCRIPTOR_LEN 0x23 #define QUERY_RESP_SUCCESS 0x00 #define QUERY_RESP_OPCODE 0xFE #define QUERY_RESP_GENERAL_FAIL 0xFF #define SENSE_KEY_NO_SENSE 0x00 #define SENSE_KEY_RECOVERED_ERROR 0x01 #define SENSE_KEY_NOT_READY 0x02 #define SENSE_KEY_MEDIUM_ERROR 0x03 #define SENSE_KEY_HARDWARE_ERROR 0x04 #define SENSE_KEY_ILLEGAL_REQUEST 0x05 #define SENSE_KEY_UNIT_ATTENTION 0x06 #define SENSE_KEY_DATA_PROTECT 0x07 #define SENSE_KEY_BLANK_CHECK 0x08 #define SENSE_KEY_VENDOR_SPECIFIC 0x09 #define SENSE_KEY_COPY_ABORTED 0x0A #define SENSE_KEY_ABORTED_COMMAND 0x0B #define SENSE_KEY_VOLUME_OVERFLOW 0x0D #define SENSE_KEY_MISCOMPARE 0x0E #define SENSE_DATA_VALID 0x70 #define SENSE_DATA_LENGTH 18 #define READ_CAPACITY_LENGTH 8 #define FLAG_DEVICE_INIT 0x01 #define UFS_VENDOR_SKHYNIX U(0x1AD) #define MAX_MODEL_LEN 16 /** * ufs_dev_desc - ufs device details from the device descriptor * @wmanufacturerid: card details * @model: card model */ struct ufs_dev_desc { uint16_t wmanufacturerid; int8_t model[MAX_MODEL_LEN + 1]; }; /* UFS Driver Flags */ #define UFS_FLAGS_SKIPINIT (1 << 0) #define UFS_FLAGS_VENDOR_SKHYNIX (U(1) << 2) typedef struct sense_data { uint8_t resp_code : 7; uint8_t valid : 1; uint8_t reserved0; uint8_t sense_key : 4; uint8_t reserved1 : 1; uint8_t ili : 1; uint8_t eom : 1; uint8_t file_mark : 1; uint8_t info[4]; uint8_t asl; uint8_t cmd_spec_len[4]; uint8_t asc; uint8_t ascq; uint8_t fruc; uint8_t sense_key_spec0 : 7; uint8_t sksv : 1; uint8_t sense_key_spec1; uint8_t sense_key_spec2; } sense_data_t; /* UTP Transfer Request Descriptor */ typedef struct utrd_header { uint32_t reserved0 : 24; uint32_t i : 1; /* interrupt */ uint32_t dd : 2; /* data direction */ uint32_t reserved1 : 1; uint32_t ct : 4; /* command type */ uint32_t reserved2; uint32_t ocs : 8; /* Overall Command Status */ uint32_t reserved3 : 24; uint32_t reserved4; uint32_t ucdba; /* aligned to 128-byte */ uint32_t ucdbau; /* Upper 32-bits */ uint32_t rul : 16; /* Response UPIU Length */ uint32_t ruo : 16; /* Response UPIU Offset */ uint32_t prdtl : 16; /* PRDT Length */ uint32_t prdto : 16; /* PRDT Offset */ } utrd_header_t; /* 8 words with little endian */ /* UTP Task Management Request Descriptor */ typedef struct utp_utmrd { /* 4 words with little endian */ uint32_t reserved0 : 24; uint32_t i : 1; /* interrupt */ uint32_t reserved1 : 7; uint32_t reserved2; uint32_t ocs : 8; /* Overall Command Status */ uint32_t reserved3 : 24; uint32_t reserved4; /* followed by 8 words UPIU with big endian */ /* followed by 8 words Response UPIU with big endian */ } utp_utmrd_t; /* NOP OUT UPIU */ typedef struct nop_out_upiu { uint8_t trans_type; uint8_t flags; uint8_t reserved0; uint8_t task_tag; uint8_t reserved1; uint8_t reserved2; uint8_t reserved3; uint8_t reserved4; uint8_t total_ehs_len; uint8_t reserved5; uint16_t data_segment_len; uint32_t reserved6; uint32_t reserved7; uint32_t reserved8; uint32_t reserved9; uint32_t reserved10; uint32_t e2ecrc; } nop_out_upiu_t; /* 36 bytes with big endian */ /* NOP IN UPIU */ typedef struct nop_in_upiu { uint8_t trans_type; uint8_t flags; uint8_t reserved0; uint8_t task_tag; uint8_t reserved1; uint8_t reserved2; uint8_t response; uint8_t reserved3; uint8_t total_ehs_len; uint8_t dev_info; uint16_t data_segment_len; uint32_t reserved4; uint32_t reserved5; uint32_t reserved6; uint32_t reserved7; uint32_t reserved8; uint32_t e2ecrc; } nop_in_upiu_t; /* 36 bytes with big endian */ /* Command UPIU */ typedef struct cmd_upiu { uint8_t trans_type; uint8_t flags; uint8_t lun; uint8_t task_tag; uint8_t cmd_set_type; uint8_t reserved0; uint8_t reserved1; uint8_t reserved2; uint8_t total_ehs_len; uint8_t reserved3; uint16_t data_segment_len; uint32_t exp_data_trans_len; /* * A CDB has a fixed length of 16bytes or a variable length * of between 12 and 260 bytes */ uint8_t cdb[16]; /* little endian */ } cmd_upiu_t; /* 32 bytes with big endian except for cdb[] */ typedef struct query_desc { uint8_t opcode; uint8_t idn; uint8_t index; uint8_t selector; uint8_t reserved0[2]; uint16_t length; uint32_t reserved2[2]; } query_desc_t; /* 16 bytes with big endian */ typedef struct query_flag { uint8_t opcode; uint8_t idn; uint8_t index; uint8_t selector; uint8_t reserved0[7]; uint8_t value; uint32_t reserved8; } query_flag_t; /* 16 bytes with big endian */ typedef struct query_attr { uint8_t opcode; uint8_t idn; uint8_t index; uint8_t selector; uint8_t reserved0[4]; uint32_t value; /* little endian */ uint32_t reserved4; } query_attr_t; /* 16 bytes with big endian except for value */ /* Query Request UPIU */ typedef struct query_upiu { uint8_t trans_type; uint8_t flags; uint8_t reserved0; uint8_t task_tag; uint8_t reserved1; uint8_t query_func; uint8_t reserved2; uint8_t reserved3; uint8_t total_ehs_len; uint8_t reserved4; uint16_t data_segment_len; /* Transaction Specific Fields */ union { query_desc_t desc; query_flag_t flag; query_attr_t attr; } ts; uint32_t reserved5; } query_upiu_t; /* 32 bytes with big endian */ /* Query Response UPIU */ typedef struct query_resp_upiu { uint8_t trans_type; uint8_t flags; uint8_t reserved0; uint8_t task_tag; uint8_t reserved1; uint8_t query_func; uint8_t query_resp; uint8_t reserved2; uint8_t total_ehs_len; uint8_t dev_info; uint16_t data_segment_len; union { query_desc_t desc; query_flag_t flag; query_attr_t attr; } ts; uint32_t reserved3; } query_resp_upiu_t; /* 32 bytes with big endian */ /* Response UPIU */ typedef struct resp_upiu { uint8_t trans_type; uint8_t flags; uint8_t lun; uint8_t task_tag; uint8_t cmd_set_type; uint8_t reserved0; uint8_t reserved1; uint8_t status; uint8_t total_ehs_len; uint8_t dev_info; uint16_t data_segment_len; uint32_t res_trans_cnt; /* Residual Transfer Count */ uint32_t reserved2[4]; uint16_t sense_data_len; union { uint8_t sense_data[18]; sense_data_t sense; } sd; } resp_upiu_t; /* 52 bytes with big endian */ typedef struct cmd_info { uintptr_t buf; size_t length; int lba; uint8_t op; uint8_t direction; uint8_t lun; } cmd_info_t; typedef struct utp_utrd { uintptr_t header; /* utrd_header_t */ uintptr_t upiu; uintptr_t resp_upiu; uintptr_t prdt; size_t size_upiu; size_t size_resp_upiu; size_t size_prdt; int task_tag; } utp_utrd_t; /* Physical Region Description Table */ typedef struct prdt { uint32_t dba; /* Data Base Address */ uint32_t dbau; /* Data Base Address Upper 32-bits */ uint32_t reserved0; uint32_t dbc : 18; /* Data Byte Count */ uint32_t reserved1 : 14; } prdt_t; typedef struct uic_cmd { uint32_t op; uint32_t arg1; uint32_t arg2; uint32_t arg3; } uic_cmd_t; typedef struct ufs_params { uintptr_t reg_base; uintptr_t desc_base; size_t desc_size; unsigned long flags; } ufs_params_t; typedef struct ufs_ops { int (*phy_init)(ufs_params_t *params); int (*phy_set_pwr_mode)(ufs_params_t *params); } ufs_ops_t; int ufshc_send_uic_cmd(uintptr_t base, uic_cmd_t *cmd); int ufshc_dme_get(unsigned int attr, unsigned int idx, unsigned int *val); int ufshc_dme_set(unsigned int attr, unsigned int idx, unsigned int val); unsigned int ufs_read_attr(int idn); void ufs_write_attr(int idn, unsigned int value); unsigned int ufs_read_flag(int idn); void ufs_set_flag(int idn); void ufs_clear_flag(int idn); void ufs_read_desc(int idn, int index, uintptr_t buf, size_t size); void ufs_write_desc(int idn, int index, uintptr_t buf, size_t size); size_t ufs_read_blocks(int lun, int lba, uintptr_t buf, size_t size); size_t ufs_write_blocks(int lun, int lba, const uintptr_t buf, size_t size); int ufs_init(const ufs_ops_t *ops, ufs_params_t *params); #endif /* UFS_H */ trusted-firmware-a-2.2/include/dt-bindings/000077500000000000000000000000001355360272700207365ustar00rootroot00000000000000trusted-firmware-a-2.2/include/dt-bindings/clock/000077500000000000000000000000001355360272700220315ustar00rootroot00000000000000trusted-firmware-a-2.2/include/dt-bindings/clock/stm32mp1-clks.h000066400000000000000000000111031355360272700245160ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ /* * Copyright (C) STMicroelectronics 2018 - All Rights Reserved * Author: Gabriel Fernandez for STMicroelectronics. */ #ifndef _DT_BINDINGS_STM32MP1_CLKS_H_ #define _DT_BINDINGS_STM32MP1_CLKS_H_ /* OSCILLATOR clocks */ #define CK_HSE 0 #define CK_CSI 1 #define CK_LSI 2 #define CK_LSE 3 #define CK_HSI 4 #define CK_HSE_DIV2 5 /* Bus clocks */ #define TIM2 6 #define TIM3 7 #define TIM4 8 #define TIM5 9 #define TIM6 10 #define TIM7 11 #define TIM12 12 #define TIM13 13 #define TIM14 14 #define LPTIM1 15 #define SPI2 16 #define SPI3 17 #define USART2 18 #define USART3 19 #define UART4 20 #define UART5 21 #define UART7 22 #define UART8 23 #define I2C1 24 #define I2C2 25 #define I2C3 26 #define I2C5 27 #define SPDIF 28 #define CEC 29 #define DAC12 30 #define MDIO 31 #define TIM1 32 #define TIM8 33 #define TIM15 34 #define TIM16 35 #define TIM17 36 #define SPI1 37 #define SPI4 38 #define SPI5 39 #define USART6 40 #define SAI1 41 #define SAI2 42 #define SAI3 43 #define DFSDM 44 #define FDCAN 45 #define LPTIM2 46 #define LPTIM3 47 #define LPTIM4 48 #define LPTIM5 49 #define SAI4 50 #define SYSCFG 51 #define VREF 52 #define TMPSENS 53 #define PMBCTRL 54 #define HDP 55 #define LTDC 56 #define DSI 57 #define IWDG2 58 #define USBPHY 59 #define STGENRO 60 #define SPI6 61 #define I2C4 62 #define I2C6 63 #define USART1 64 #define RTCAPB 65 #define TZC1 66 #define TZPC 67 #define IWDG1 68 #define BSEC 69 #define STGEN 70 #define DMA1 71 #define DMA2 72 #define DMAMUX 73 #define ADC12 74 #define USBO 75 #define SDMMC3 76 #define DCMI 77 #define CRYP2 78 #define HASH2 79 #define RNG2 80 #define CRC2 81 #define HSEM 82 #define IPCC 83 #define GPIOA 84 #define GPIOB 85 #define GPIOC 86 #define GPIOD 87 #define GPIOE 88 #define GPIOF 89 #define GPIOG 90 #define GPIOH 91 #define GPIOI 92 #define GPIOJ 93 #define GPIOK 94 #define GPIOZ 95 #define CRYP1 96 #define HASH1 97 #define RNG1 98 #define BKPSRAM 99 #define MDMA 100 #define GPU 101 #define ETHCK 102 #define ETHTX 103 #define ETHRX 104 #define ETHMAC 105 #define FMC 106 #define QSPI 107 #define SDMMC1 108 #define SDMMC2 109 #define CRC1 110 #define USBH 111 #define ETHSTP 112 #define TZC2 113 /* Kernel clocks */ #define SDMMC1_K 118 #define SDMMC2_K 119 #define SDMMC3_K 120 #define FMC_K 121 #define QSPI_K 122 #define ETHCK_K 123 #define RNG1_K 124 #define RNG2_K 125 #define GPU_K 126 #define USBPHY_K 127 #define STGEN_K 128 #define SPDIF_K 129 #define SPI1_K 130 #define SPI2_K 131 #define SPI3_K 132 #define SPI4_K 133 #define SPI5_K 134 #define SPI6_K 135 #define CEC_K 136 #define I2C1_K 137 #define I2C2_K 138 #define I2C3_K 139 #define I2C4_K 140 #define I2C5_K 141 #define I2C6_K 142 #define LPTIM1_K 143 #define LPTIM2_K 144 #define LPTIM3_K 145 #define LPTIM4_K 146 #define LPTIM5_K 147 #define USART1_K 148 #define USART2_K 149 #define USART3_K 150 #define UART4_K 151 #define UART5_K 152 #define USART6_K 153 #define UART7_K 154 #define UART8_K 155 #define DFSDM_K 156 #define FDCAN_K 157 #define SAI1_K 158 #define SAI2_K 159 #define SAI3_K 160 #define SAI4_K 161 #define ADC12_K 162 #define DSI_K 163 #define DSI_PX 164 #define ADFSDM_K 165 #define USBO_K 166 #define LTDC_PX 167 #define DAC12_K 168 #define ETHPTP_K 169 /* PLL */ #define PLL1 176 #define PLL2 177 #define PLL3 178 #define PLL4 179 /* ODF */ #define PLL1_P 180 #define PLL1_Q 181 #define PLL1_R 182 #define PLL2_P 183 #define PLL2_Q 184 #define PLL2_R 185 #define PLL3_P 186 #define PLL3_Q 187 #define PLL3_R 188 #define PLL4_P 189 #define PLL4_Q 190 #define PLL4_R 191 /* AUX */ #define RTC 192 /* MCLK */ #define CK_PER 193 #define CK_MPU 194 #define CK_AXI 195 #define CK_MCU 196 /* Time base */ #define TIM2_K 197 #define TIM3_K 198 #define TIM4_K 199 #define TIM5_K 200 #define TIM6_K 201 #define TIM7_K 202 #define TIM12_K 203 #define TIM13_K 204 #define TIM14_K 205 #define TIM1_K 206 #define TIM8_K 207 #define TIM15_K 208 #define TIM16_K 209 #define TIM17_K 210 /* MCO clocks */ #define CK_MCO1 211 #define CK_MCO2 212 /* TRACE & DEBUG clocks */ #define CK_DBG 214 #define CK_TRACE 215 /* DDR */ #define DDRC1 220 #define DDRC1LP 221 #define DDRC2 222 #define DDRC2LP 223 #define DDRPHYC 224 #define DDRPHYCLP 225 #define DDRCAPB 226 #define DDRCAPBLP 227 #define AXIDCG 228 #define DDRPHYCAPB 229 #define DDRPHYCAPBLP 230 #define DDRPERFM 231 #define STM32MP1_LAST_CLK 232 #endif /* _DT_BINDINGS_STM32MP1_CLKS_H_ */ trusted-firmware-a-2.2/include/dt-bindings/clock/stm32mp1-clksrc.h000066400000000000000000000200461355360272700250510ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ /* * Copyright (C) 2017, STMicroelectronics - All Rights Reserved */ #ifndef _DT_BINDINGS_CLOCK_STM32MP1_CLKSRC_H_ #define _DT_BINDINGS_CLOCK_STM32MP1_CLKSRC_H_ /* PLL output is enable when x=1, with x=p,q or r */ #define PQR(p, q, r) (((p) & 1) | (((q) & 1) << 1) | (((r) & 1) << 2)) /* st,clksrc: mandatory clock source */ #define CLK_MPU_HSI 0x00000200 #define CLK_MPU_HSE 0x00000201 #define CLK_MPU_PLL1P 0x00000202 #define CLK_MPU_PLL1P_DIV 0x00000203 #define CLK_AXI_HSI 0x00000240 #define CLK_AXI_HSE 0x00000241 #define CLK_AXI_PLL2P 0x00000242 #define CLK_MCU_HSI 0x00000480 #define CLK_MCU_HSE 0x00000481 #define CLK_MCU_CSI 0x00000482 #define CLK_MCU_PLL3P 0x00000483 #define CLK_PLL12_HSI 0x00000280 #define CLK_PLL12_HSE 0x00000281 #define CLK_PLL3_HSI 0x00008200 #define CLK_PLL3_HSE 0x00008201 #define CLK_PLL3_CSI 0x00008202 #define CLK_PLL4_HSI 0x00008240 #define CLK_PLL4_HSE 0x00008241 #define CLK_PLL4_CSI 0x00008242 #define CLK_PLL4_I2SCKIN 0x00008243 #define CLK_RTC_DISABLED 0x00001400 #define CLK_RTC_LSE 0x00001401 #define CLK_RTC_LSI 0x00001402 #define CLK_RTC_HSE 0x00001403 #define CLK_MCO1_HSI 0x00008000 #define CLK_MCO1_HSE 0x00008001 #define CLK_MCO1_CSI 0x00008002 #define CLK_MCO1_LSI 0x00008003 #define CLK_MCO1_LSE 0x00008004 #define CLK_MCO1_DISABLED 0x0000800F #define CLK_MCO2_MPU 0x00008040 #define CLK_MCO2_AXI 0x00008041 #define CLK_MCO2_MCU 0x00008042 #define CLK_MCO2_PLL4P 0x00008043 #define CLK_MCO2_HSE 0x00008044 #define CLK_MCO2_HSI 0x00008045 #define CLK_MCO2_DISABLED 0x0000804F /* st,pkcs: peripheral kernel clock source */ #define CLK_I2C12_PCLK1 0x00008C00 #define CLK_I2C12_PLL4R 0x00008C01 #define CLK_I2C12_HSI 0x00008C02 #define CLK_I2C12_CSI 0x00008C03 #define CLK_I2C12_DISABLED 0x00008C07 #define CLK_I2C35_PCLK1 0x00008C40 #define CLK_I2C35_PLL4R 0x00008C41 #define CLK_I2C35_HSI 0x00008C42 #define CLK_I2C35_CSI 0x00008C43 #define CLK_I2C35_DISABLED 0x00008C47 #define CLK_I2C46_PCLK5 0x00000C00 #define CLK_I2C46_PLL3Q 0x00000C01 #define CLK_I2C46_HSI 0x00000C02 #define CLK_I2C46_CSI 0x00000C03 #define CLK_I2C46_DISABLED 0x00000C07 #define CLK_SAI1_PLL4Q 0x00008C80 #define CLK_SAI1_PLL3Q 0x00008C81 #define CLK_SAI1_I2SCKIN 0x00008C82 #define CLK_SAI1_CKPER 0x00008C83 #define CLK_SAI1_PLL3R 0x00008C84 #define CLK_SAI1_DISABLED 0x00008C87 #define CLK_SAI2_PLL4Q 0x00008CC0 #define CLK_SAI2_PLL3Q 0x00008CC1 #define CLK_SAI2_I2SCKIN 0x00008CC2 #define CLK_SAI2_CKPER 0x00008CC3 #define CLK_SAI2_SPDIF 0x00008CC4 #define CLK_SAI2_PLL3R 0x00008CC5 #define CLK_SAI2_DISABLED 0x00008CC7 #define CLK_SAI3_PLL4Q 0x00008D00 #define CLK_SAI3_PLL3Q 0x00008D01 #define CLK_SAI3_I2SCKIN 0x00008D02 #define CLK_SAI3_CKPER 0x00008D03 #define CLK_SAI3_PLL3R 0x00008D04 #define CLK_SAI3_DISABLED 0x00008D07 #define CLK_SAI4_PLL4Q 0x00008D40 #define CLK_SAI4_PLL3Q 0x00008D41 #define CLK_SAI4_I2SCKIN 0x00008D42 #define CLK_SAI4_CKPER 0x00008D43 #define CLK_SAI4_PLL3R 0x00008D44 #define CLK_SAI4_DISABLED 0x00008D47 #define CLK_SPI2S1_PLL4P 0x00008D80 #define CLK_SPI2S1_PLL3Q 0x00008D81 #define CLK_SPI2S1_I2SCKIN 0x00008D82 #define CLK_SPI2S1_CKPER 0x00008D83 #define CLK_SPI2S1_PLL3R 0x00008D84 #define CLK_SPI2S1_DISABLED 0x00008D87 #define CLK_SPI2S23_PLL4P 0x00008DC0 #define CLK_SPI2S23_PLL3Q 0x00008DC1 #define CLK_SPI2S23_I2SCKIN 0x00008DC2 #define CLK_SPI2S23_CKPER 0x00008DC3 #define CLK_SPI2S23_PLL3R 0x00008DC4 #define CLK_SPI2S23_DISABLED 0x00008DC7 #define CLK_SPI45_PCLK2 0x00008E00 #define CLK_SPI45_PLL4Q 0x00008E01 #define CLK_SPI45_HSI 0x00008E02 #define CLK_SPI45_CSI 0x00008E03 #define CLK_SPI45_HSE 0x00008E04 #define CLK_SPI45_DISABLED 0x00008E07 #define CLK_SPI6_PCLK5 0x00000C40 #define CLK_SPI6_PLL4Q 0x00000C41 #define CLK_SPI6_HSI 0x00000C42 #define CLK_SPI6_CSI 0x00000C43 #define CLK_SPI6_HSE 0x00000C44 #define CLK_SPI6_PLL3Q 0x00000C45 #define CLK_SPI6_DISABLED 0x00000C47 #define CLK_UART6_PCLK2 0x00008E40 #define CLK_UART6_PLL4Q 0x00008E41 #define CLK_UART6_HSI 0x00008E42 #define CLK_UART6_CSI 0x00008E43 #define CLK_UART6_HSE 0x00008E44 #define CLK_UART6_DISABLED 0x00008E47 #define CLK_UART24_PCLK1 0x00008E80 #define CLK_UART24_PLL4Q 0x00008E81 #define CLK_UART24_HSI 0x00008E82 #define CLK_UART24_CSI 0x00008E83 #define CLK_UART24_HSE 0x00008E84 #define CLK_UART24_DISABLED 0x00008E87 #define CLK_UART35_PCLK1 0x00008EC0 #define CLK_UART35_PLL4Q 0x00008EC1 #define CLK_UART35_HSI 0x00008EC2 #define CLK_UART35_CSI 0x00008EC3 #define CLK_UART35_HSE 0x00008EC4 #define CLK_UART35_DISABLED 0x00008EC7 #define CLK_UART78_PCLK1 0x00008F00 #define CLK_UART78_PLL4Q 0x00008F01 #define CLK_UART78_HSI 0x00008F02 #define CLK_UART78_CSI 0x00008F03 #define CLK_UART78_HSE 0x00008F04 #define CLK_UART78_DISABLED 0x00008F07 #define CLK_UART1_PCLK5 0x00000C80 #define CLK_UART1_PLL3Q 0x00000C81 #define CLK_UART1_HSI 0x00000C82 #define CLK_UART1_CSI 0x00000C83 #define CLK_UART1_PLL4Q 0x00000C84 #define CLK_UART1_HSE 0x00000C85 #define CLK_UART1_DISABLED 0x00000C87 #define CLK_SDMMC12_HCLK6 0x00008F40 #define CLK_SDMMC12_PLL3R 0x00008F41 #define CLK_SDMMC12_PLL4P 0x00008F42 #define CLK_SDMMC12_HSI 0x00008F43 #define CLK_SDMMC12_DISABLED 0x00008F47 #define CLK_SDMMC3_HCLK2 0x00008F80 #define CLK_SDMMC3_PLL3R 0x00008F81 #define CLK_SDMMC3_PLL4P 0x00008F82 #define CLK_SDMMC3_HSI 0x00008F83 #define CLK_SDMMC3_DISABLED 0x00008F87 #define CLK_ETH_PLL4P 0x00008FC0 #define CLK_ETH_PLL3Q 0x00008FC1 #define CLK_ETH_DISABLED 0x00008FC3 #define CLK_QSPI_ACLK 0x00009000 #define CLK_QSPI_PLL3R 0x00009001 #define CLK_QSPI_PLL4P 0x00009002 #define CLK_QSPI_CKPER 0x00009003 #define CLK_FMC_ACLK 0x00009040 #define CLK_FMC_PLL3R 0x00009041 #define CLK_FMC_PLL4P 0x00009042 #define CLK_FMC_CKPER 0x00009043 #define CLK_FDCAN_HSE 0x000090C0 #define CLK_FDCAN_PLL3Q 0x000090C1 #define CLK_FDCAN_PLL4Q 0x000090C2 #define CLK_FDCAN_PLL4R 0x000090C3 #define CLK_SPDIF_PLL4P 0x00009140 #define CLK_SPDIF_PLL3Q 0x00009141 #define CLK_SPDIF_HSI 0x00009142 #define CLK_SPDIF_DISABLED 0x00009143 #define CLK_CEC_LSE 0x00009180 #define CLK_CEC_LSI 0x00009181 #define CLK_CEC_CSI_DIV122 0x00009182 #define CLK_CEC_DISABLED 0x00009183 #define CLK_USBPHY_HSE 0x000091C0 #define CLK_USBPHY_PLL4R 0x000091C1 #define CLK_USBPHY_HSE_DIV2 0x000091C2 #define CLK_USBPHY_DISABLED 0x000091C3 #define CLK_USBO_PLL4R 0x800091C0 #define CLK_USBO_USBPHY 0x800091C1 #define CLK_RNG1_CSI 0x00000CC0 #define CLK_RNG1_PLL4R 0x00000CC1 #define CLK_RNG1_LSE 0x00000CC2 #define CLK_RNG1_LSI 0x00000CC3 #define CLK_RNG2_CSI 0x00009200 #define CLK_RNG2_PLL4R 0x00009201 #define CLK_RNG2_LSE 0x00009202 #define CLK_RNG2_LSI 0x00009203 #define CLK_CKPER_HSI 0x00000D00 #define CLK_CKPER_CSI 0x00000D01 #define CLK_CKPER_HSE 0x00000D02 #define CLK_CKPER_DISABLED 0x00000D03 #define CLK_STGEN_HSI 0x00000D40 #define CLK_STGEN_HSE 0x00000D41 #define CLK_STGEN_DISABLED 0x00000D43 #define CLK_DSI_DSIPLL 0x00009240 #define CLK_DSI_PLL4P 0x00009241 #define CLK_ADC_PLL4R 0x00009280 #define CLK_ADC_CKPER 0x00009281 #define CLK_ADC_PLL3Q 0x00009282 #define CLK_ADC_DISABLED 0x00009283 #define CLK_LPTIM45_PCLK3 0x000092C0 #define CLK_LPTIM45_PLL4P 0x000092C1 #define CLK_LPTIM45_PLL3Q 0x000092C2 #define CLK_LPTIM45_LSE 0x000092C3 #define CLK_LPTIM45_LSI 0x000092C4 #define CLK_LPTIM45_CKPER 0x000092C5 #define CLK_LPTIM45_DISABLED 0x000092C7 #define CLK_LPTIM23_PCLK3 0x00009300 #define CLK_LPTIM23_PLL4Q 0x00009301 #define CLK_LPTIM23_CKPER 0x00009302 #define CLK_LPTIM23_LSE 0x00009303 #define CLK_LPTIM23_LSI 0x00009304 #define CLK_LPTIM23_DISABLED 0x00009307 #define CLK_LPTIM1_PCLK1 0x00009340 #define CLK_LPTIM1_PLL4P 0x00009341 #define CLK_LPTIM1_PLL3Q 0x00009342 #define CLK_LPTIM1_LSE 0x00009343 #define CLK_LPTIM1_LSI 0x00009344 #define CLK_LPTIM1_CKPER 0x00009345 #define CLK_LPTIM1_DISABLED 0x00009347 /* define for st,pll /csg */ #define SSCG_MODE_CENTER_SPREAD 0 #define SSCG_MODE_DOWN_SPREAD 1 /* define for st,drive */ #define LSEDRV_LOWEST 0 #define LSEDRV_MEDIUM_LOW 1 #define LSEDRV_MEDIUM_HIGH 2 #define LSEDRV_HIGHEST 3 #endif trusted-firmware-a-2.2/include/dt-bindings/interrupt-controller/000077500000000000000000000000001355360272700251535ustar00rootroot00000000000000trusted-firmware-a-2.2/include/dt-bindings/interrupt-controller/arm-gic.h000066400000000000000000000010071355360272700266410ustar00rootroot00000000000000/* 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 trusted-firmware-a-2.2/include/dt-bindings/pinctrl/000077500000000000000000000000001355360272700224115ustar00rootroot00000000000000trusted-firmware-a-2.2/include/dt-bindings/pinctrl/stm32-pinfunc.h000066400000000000000000000016611355360272700251760ustar00rootroot00000000000000/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ /* * Copyright (C) STMicroelectronics 2017 - All Rights Reserved * Author: Torgue Alexandre for STMicroelectronics. */ #ifndef _DT_BINDINGS_STM32_PINFUNC_H #define _DT_BINDINGS_STM32_PINFUNC_H /* define PIN modes */ #define GPIO 0x0 #define AF0 0x1 #define AF1 0x2 #define AF2 0x3 #define AF3 0x4 #define AF4 0x5 #define AF5 0x6 #define AF6 0x7 #define AF7 0x8 #define AF8 0x9 #define AF9 0xa #define AF10 0xb #define AF11 0xc #define AF12 0xd #define AF13 0xe #define AF14 0xf #define AF15 0x10 #define ANALOG 0x11 /* define Pins number*/ #define PIN_NO(port, line) (((port) - 'A') * 0x10 + (line)) #define STM32_PINMUX(port, line, mode) (((PIN_NO(port, line)) << 8) | (mode)) /* package information */ #define STM32MP157CAA 0x1 #define STM32MP157CAB 0x2 #define STM32MP157CAC 0x4 #define STM32MP157CAD 0x8 #endif /* _DT_BINDINGS_STM32_PINFUNC_H */ trusted-firmware-a-2.2/include/dt-bindings/reset/000077500000000000000000000000001355360272700220605ustar00rootroot00000000000000trusted-firmware-a-2.2/include/dt-bindings/reset/stm32mp1-resets.h000066400000000000000000000046731355360272700251340ustar00rootroot00000000000000/* SPDX-License-Identifier: GPL-2.0 or BSD-3-Clause */ /* * Copyright (C) STMicroelectronics 2018 - All Rights Reserved * Author: Gabriel Fernandez for STMicroelectronics. */ #ifndef _DT_BINDINGS_STM32MP1_RESET_H_ #define _DT_BINDINGS_STM32MP1_RESET_H_ #define LTDC_R 3072 #define DSI_R 3076 #define DDRPERFM_R 3080 #define USBPHY_R 3088 #define SPI6_R 3136 #define I2C4_R 3138 #define I2C6_R 3139 #define USART1_R 3140 #define STGEN_R 3156 #define GPIOZ_R 3200 #define CRYP1_R 3204 #define HASH1_R 3205 #define RNG1_R 3206 #define AXIM_R 3216 #define GPU_R 3269 #define ETHMAC_R 3274 #define FMC_R 3276 #define QSPI_R 3278 #define SDMMC1_R 3280 #define SDMMC2_R 3281 #define CRC1_R 3284 #define USBH_R 3288 #define MDMA_R 3328 #define MCU_R 8225 #define TIM2_R 19456 #define TIM3_R 19457 #define TIM4_R 19458 #define TIM5_R 19459 #define TIM6_R 19460 #define TIM7_R 19461 #define TIM12_R 16462 #define TIM13_R 16463 #define TIM14_R 16464 #define LPTIM1_R 19465 #define SPI2_R 19467 #define SPI3_R 19468 #define USART2_R 19470 #define USART3_R 19471 #define UART4_R 19472 #define UART5_R 19473 #define UART7_R 19474 #define UART8_R 19475 #define I2C1_R 19477 #define I2C2_R 19478 #define I2C3_R 19479 #define I2C5_R 19480 #define SPDIF_R 19482 #define CEC_R 19483 #define DAC12_R 19485 #define MDIO_R 19847 #define TIM1_R 19520 #define TIM8_R 19521 #define TIM15_R 19522 #define TIM16_R 19523 #define TIM17_R 19524 #define SPI1_R 19528 #define SPI4_R 19529 #define SPI5_R 19530 #define USART6_R 19533 #define SAI1_R 19536 #define SAI2_R 19537 #define SAI3_R 19538 #define DFSDM_R 19540 #define FDCAN_R 19544 #define LPTIM2_R 19584 #define LPTIM3_R 19585 #define LPTIM4_R 19586 #define LPTIM5_R 19587 #define SAI4_R 19592 #define SYSCFG_R 19595 #define VREF_R 19597 #define TMPSENS_R 19600 #define PMBCTRL_R 19601 #define DMA1_R 19648 #define DMA2_R 19649 #define DMAMUX_R 19650 #define ADC12_R 19653 #define USBO_R 19656 #define SDMMC3_R 19664 #define CAMITF_R 19712 #define CRYP2_R 19716 #define HASH2_R 19717 #define RNG2_R 19718 #define CRC2_R 19719 #define HSEM_R 19723 #define MBOX_R 19724 #define GPIOA_R 19776 #define GPIOB_R 19777 #define GPIOC_R 19778 #define GPIOD_R 19779 #define GPIOE_R 19780 #define GPIOF_R 19781 #define GPIOG_R 19782 #define GPIOH_R 19783 #define GPIOI_R 19784 #define GPIOJ_R 19785 #define GPIOK_R 19786 #endif /* _DT_BINDINGS_STM32MP1_RESET_H_ */ trusted-firmware-a-2.2/include/export/000077500000000000000000000000001355360272700200555ustar00rootroot00000000000000trusted-firmware-a-2.2/include/export/README000066400000000000000000000031511355360272700207350ustar00rootroot00000000000000All headers under include/export/ are export headers that are intended for inclusion in third-party code which needs to interact with TF-A data structures or interfaces. They must follow these special rules: - Header guards should start with ARM_TRUSTED_FIRMWARE_ to reduce clash risk. - All definitions should be sufficiently namespaced (e.g. with BL_ or TF_) to make name clashes with third-party code unlikely. - They must not #include any headers except other export headers, and those includes must use relative paths with "../double_quotes.h" notation. - They must not rely on any type definitions other that types defined in the ISO C standard (i.e. uint64_t is fine, but not u_register_t). They should still not #include . Instead, wrapper headers including export headers need to ensure that they #include earlier in their include order. - They must not rely on any macro definitions other than those which are pre-defined by all common compilers (e.g. __ASSEMBLER__ or __aarch64__). - They must only contain macro, type and structure definitions, no prototypes. - They should avoid using integer types with architecture-dependent widths (e.g. long, uintptr_t, pointer types) where possible. (Some existing export headers are violating this for now.) - Their names should always end in "_exp.h". - Normal TF-A code should never include export headers directly. Instead, it should include a wrapper header that ensures the export header is included in the right manner. (The wrapper header for include/export/x/y/z_exp.h should normally be placed at include/x/y/z.h.) trusted-firmware-a-2.2/include/export/common/000077500000000000000000000000001355360272700213455ustar00rootroot00000000000000trusted-firmware-a-2.2/include/export/common/bl_common_exp.h000066400000000000000000000056241355360272700243460ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_BL_COMMON_EXP_H #define ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_BL_COMMON_EXP_H /* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */ #include "ep_info_exp.h" #include "tbbr/tbbr_img_def_exp.h" /* * The following are used for image state attributes. * Image can only be in one of the following state. */ #define IMAGE_STATE_RESET U(0) #define IMAGE_STATE_COPIED U(1) #define IMAGE_STATE_COPYING U(2) #define IMAGE_STATE_AUTHENTICATED U(3) #define IMAGE_STATE_EXECUTED U(4) #define IMAGE_STATE_INTERRUPTED U(5) #define IMAGE_ATTRIB_SKIP_LOADING U(0x02) #define IMAGE_ATTRIB_PLAT_SETUP U(0x04) #define INVALID_IMAGE_ID U(0xFFFFFFFF) #ifndef __ASSEMBLER__ /***************************************************************************** * Image info binary provides information from the image loader that * can be used by the firmware to manage available trusted RAM. * More advanced firmware image formats can provide additional * information that enables optimization or greater flexibility in the * common firmware code *****************************************************************************/ typedef struct image_info { param_header_t h; uintptr_t image_base; /* physical address of base of image */ uint32_t image_size; /* bytes read from image file */ uint32_t image_max_size; } image_info_t; /* BL image node in the BL image execution sequence */ typedef struct bl_params_node { unsigned int image_id; image_info_t *image_info; entry_point_info_t *ep_info; struct bl_params_node *next_params_info; } bl_params_node_t; /* * BL image head node in the BL image execution sequence * It is also used to pass information to next BL image. */ typedef struct bl_params { param_header_t h; bl_params_node_t *head; } bl_params_t; /***************************************************************************** * The image descriptor struct definition. *****************************************************************************/ typedef struct image_desc { /* Contains unique image id for the image. */ unsigned int image_id; /* * This member contains Image state information. * Refer IMAGE_STATE_XXX defined above. */ unsigned int state; uint32_t copied_size; /* image size copied in blocks */ image_info_t image_info; entry_point_info_t ep_info; } image_desc_t; /* BL image node in the BL image loading sequence */ typedef struct bl_load_info_node { unsigned int image_id; image_info_t *image_info; struct bl_load_info_node *next_load_info; } bl_load_info_node_t; /* BL image head node in the BL image loading sequence */ typedef struct bl_load_info { param_header_t h; bl_load_info_node_t *head; } bl_load_info_t; #endif /* __ASSEMBLER__ */ #endif /* ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_BL_COMMON_EXP_H */ trusted-firmware-a-2.2/include/export/common/ep_info_exp.h000066400000000000000000000063521355360272700240170ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_EP_INFO_EXP_H #define ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_EP_INFO_EXP_H /* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */ #include "../lib/utils_def_exp.h" #include "param_header_exp.h" /******************************************************************************* * Constants that allow assembler code to access members of and the * 'entry_point_info' structure at their correct offsets. ******************************************************************************/ #define ENTRY_POINT_INFO_PC_OFFSET U(0x08) #ifdef __aarch64__ #define ENTRY_POINT_INFO_ARGS_OFFSET U(0x18) #else #define ENTRY_POINT_INFO_LR_SVC_OFFSET U(0x10) #define ENTRY_POINT_INFO_ARGS_OFFSET U(0x14) #endif /* Security state of the image. */ #define EP_SECURITY_MASK U(0x1) #define EP_SECURITY_SHIFT U(0) #define EP_SECURE U(0x0) #define EP_NON_SECURE U(0x1) /* Endianness of the image. */ #define EP_EE_MASK U(0x2) #define EP_EE_SHIFT U(1) #define EP_EE_LITTLE U(0x0) #define EP_EE_BIG U(0x2) #define EP_GET_EE(x) ((x) & EP_EE_MASK) #define EP_SET_EE(x, ee) ((x) = ((x) & ~EP_EE_MASK) | (ee)) /* Enable or disable access to the secure timer from secure images. */ #define EP_ST_MASK U(0x4) #define EP_ST_SHIFT U(2) #define EP_ST_DISABLE U(0x0) #define EP_ST_ENABLE U(0x4) #define EP_GET_ST(x) ((x) & EP_ST_MASK) #define EP_SET_ST(x, ee) ((x) = ((x) & ~EP_ST_MASK) | (ee)) /* Determine if an image is executable or not. */ #define EP_EXE_MASK U(0x8) #define EP_EXE_SHIFT U(3) #define EP_NON_EXECUTABLE U(0x0) #define EP_EXECUTABLE U(0x8) #define EP_GET_EXE(x) ((x) & EP_EXE_MASK) #define EP_SET_EXE(x, ee) ((x) = ((x) & ~EP_EXE_MASK) | (ee)) /* Flag to indicate the first image that is executed. */ #define EP_FIRST_EXE_MASK U(0x10) #define EP_FIRST_EXE_SHIFT U(4) #define EP_FIRST_EXE U(0x10) #define EP_GET_FIRST_EXE(x) ((x) & EP_FIRST_EXE_MASK) #define EP_SET_FIRST_EXE(x, ee) ((x) = ((x) & ~EP_FIRST_EXE_MASK) | (ee)) #ifndef __ASSEMBLER__ typedef struct aapcs64_params { uint64_t arg0; uint64_t arg1; uint64_t arg2; uint64_t arg3; uint64_t arg4; uint64_t arg5; uint64_t arg6; uint64_t arg7; } aapcs64_params_t; typedef struct aapcs32_params { uint32_t arg0; uint32_t arg1; uint32_t arg2; uint32_t arg3; } aapcs32_params_t; /***************************************************************************** * This structure represents the superset of information needed while * switching exception levels. The only two mechanisms to do so are * ERET & SMC. Security state is indicated using bit zero of header * attribute * NOTE: BL1 expects entrypoint followed by spsr at an offset from the start * of this structure defined by the macro `ENTRY_POINT_INFO_PC_OFFSET` while * processing SMC to jump to BL31. *****************************************************************************/ typedef struct entry_point_info { param_header_t h; uintptr_t pc; uint32_t spsr; #ifdef __aarch64__ aapcs64_params_t args; #else uintptr_t lr_svc; aapcs32_params_t args; #endif } entry_point_info_t; #endif /*__ASSEMBLER__*/ #endif /* ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_EP_INFO_EXP_H */ trusted-firmware-a-2.2/include/export/common/param_header_exp.h000066400000000000000000000025341355360272700250060ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_PARAM_HEADER_EXP_H #define ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_PARAM_HEADER_EXP_H /* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */ #include "../lib/utils_def_exp.h" /* Param header types */ #define PARAM_EP U(0x01) #define PARAM_IMAGE_BINARY U(0x02) #define PARAM_BL31 U(0x03) #define PARAM_BL_LOAD_INFO U(0x04) #define PARAM_BL_PARAMS U(0x05) #define PARAM_PSCI_LIB_ARGS U(0x06) #define PARAM_SP_IMAGE_BOOT_INFO U(0x07) /* Param header version */ #define PARAM_VERSION_1 U(0x01) #define PARAM_VERSION_2 U(0x02) #ifndef __ASSEMBLER__ /*************************************************************************** * This structure provides version information and the size of the * structure, attributes for the structure it represents ***************************************************************************/ typedef struct param_header { uint8_t type; /* type of the structure */ uint8_t version; /* version of this structure */ uint16_t size; /* size of this structure in bytes */ uint32_t attr; /* attributes: unused bits SBZ */ } param_header_t; #endif /*__ASSEMBLER__*/ #endif /* ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_PARAM_HEADER_EXP_H */ trusted-firmware-a-2.2/include/export/common/tbbr/000077500000000000000000000000001355360272700222765ustar00rootroot00000000000000trusted-firmware-a-2.2/include/export/common/tbbr/tbbr_img_def_exp.h000066400000000000000000000042321355360272700257270ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_TBBR_TBBR_IMG_DEF_EXP_H #define ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_TBBR_TBBR_IMG_DEF_EXP_H /* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */ #include "../../lib/utils_def_exp.h" /* Firmware Image Package */ #define FIP_IMAGE_ID U(0) /* Trusted Boot Firmware BL2 */ #define BL2_IMAGE_ID U(1) /* SCP Firmware SCP_BL2 */ #define SCP_BL2_IMAGE_ID U(2) /* EL3 Runtime Firmware BL31 */ #define BL31_IMAGE_ID U(3) /* Secure Payload BL32 (Trusted OS) */ #define BL32_IMAGE_ID U(4) /* Non-Trusted Firmware BL33 */ #define BL33_IMAGE_ID U(5) /* Certificates */ #define TRUSTED_BOOT_FW_CERT_ID U(6) #define TRUSTED_KEY_CERT_ID U(7) #define SCP_FW_KEY_CERT_ID U(8) #define SOC_FW_KEY_CERT_ID U(9) #define TRUSTED_OS_FW_KEY_CERT_ID U(10) #define NON_TRUSTED_FW_KEY_CERT_ID U(11) #define SCP_FW_CONTENT_CERT_ID U(12) #define SOC_FW_CONTENT_CERT_ID U(13) #define TRUSTED_OS_FW_CONTENT_CERT_ID U(14) #define NON_TRUSTED_FW_CONTENT_CERT_ID U(15) /* Non-Trusted ROM Firmware NS_BL1U */ #define NS_BL1U_IMAGE_ID U(16) /* Trusted FWU Certificate */ #define FWU_CERT_ID U(17) /* Trusted FWU SCP Firmware SCP_BL2U */ #define SCP_BL2U_IMAGE_ID U(18) /* Trusted FWU Boot Firmware BL2U */ #define BL2U_IMAGE_ID U(19) /* Non-Trusted FWU Firmware NS_BL2U */ #define NS_BL2U_IMAGE_ID U(20) /* Secure Payload BL32_EXTRA1 (Trusted OS Extra1) */ #define BL32_EXTRA1_IMAGE_ID U(21) /* Secure Payload BL32_EXTRA2 (Trusted OS Extra2) */ #define BL32_EXTRA2_IMAGE_ID U(22) /* HW_CONFIG (e.g. Kernel DT) */ #define HW_CONFIG_ID U(23) /* TB_FW_CONFIG */ #define TB_FW_CONFIG_ID U(24) /* SOC_FW_CONFIG */ #define SOC_FW_CONFIG_ID U(25) /* TOS_FW_CONFIG */ #define TOS_FW_CONFIG_ID U(26) /* 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(30) #endif /* ARM_TRUSTED_FIRMWARE_EXPORT_COMMON_TBBR_TBBR_IMG_DEF_EXP_H */ trusted-firmware-a-2.2/include/export/drivers/000077500000000000000000000000001355360272700215335ustar00rootroot00000000000000trusted-firmware-a-2.2/include/export/drivers/gpio_exp.h000066400000000000000000000011351355360272700235160ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_TRUSTED_FIRMWARE_EXPORT_DRIVERS_GPIO_EXP_H #define ARM_TRUSTED_FIRMWARE_EXPORT_DRIVERS_GPIO_EXP_H /* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */ #define ARM_TF_GPIO_DIR_OUT 0 #define ARM_TF_GPIO_DIR_IN 1 #define ARM_TF_GPIO_LEVEL_LOW 0 #define ARM_TF_GPIO_LEVEL_HIGH 1 #define ARM_TF_GPIO_PULL_NONE 0 #define ARM_TF_GPIO_PULL_UP 1 #define ARM_TF_GPIO_PULL_DOWN 2 #endif /* ARM_TRUSTED_FIRMWARE_EXPORT_DRIVERS_GPIO_EXP_H */ trusted-firmware-a-2.2/include/export/lib/000077500000000000000000000000001355360272700206235ustar00rootroot00000000000000trusted-firmware-a-2.2/include/export/lib/bl_aux_params/000077500000000000000000000000001355360272700234405ustar00rootroot00000000000000trusted-firmware-a-2.2/include/export/lib/bl_aux_params/bl_aux_params_exp.h000066400000000000000000000066321355360272700273110ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_TRUSTED_FIRMWARE_EXPORT_LIB_BL_AUX_PARAMS_EXP_H #define ARM_TRUSTED_FIRMWARE_EXPORT_LIB_BL_AUX_PARAMS_EXP_H /* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */ #include "../../drivers/gpio_exp.h" /* * This API implements a lightweight parameter passing mechanism that can be * used to pass SoC Firmware configuration data from BL2 to BL31 by platforms or * configurations that do not want to depend on libfdt. It is structured as a * singly-linked list of parameter structures that all share the same common * header but may have different (and differently-sized) structure bodies after * that. The header contains a type field to indicate the parameter type (which * is used to infer the structure length and how to interpret its contents) and * a next pointer which contains the absolute physical address of the next * parameter structure. The next pointer in the last structure block is set to * NULL. The picture below shows how the parameters are kept in memory. * * head of list ---> +----------------+ --+ * | type | | * +----------------+ |--> struct bl_aux_param * +----| next | | * | +----------------+ --+ * | | parameter data | * | +----------------+ * | * +--> +----------------+ --+ * | type | | * +----------------+ |--> struct bl_aux_param * NULL <---| next | | * +----------------+ --+ * | parameter data | * +----------------+ * * Note: The SCTLR_EL3.A bit (Alignment fault check enable) is set in TF-A, so * BL2 must ensure that each parameter struct starts on a 64-bit aligned address * to avoid alignment faults. Parameters may be allocated in any address range * accessible at the time of BL31 handoff (e.g. SRAM, DRAM, SoC-internal scratch * registers, etc.), in particular address ranges that may not be mapped in * BL31's page tables, so the parameter list must be parsed before the MMU is * enabled and any information that is required at a later point should be * deep-copied out into BL31-internal data structures. */ enum bl_aux_param_type { BL_AUX_PARAM_NONE = 0, BL_AUX_PARAM_VENDOR_SPECIFIC_FIRST = 0x1, /* 0x1 - 0x7fffffff can be used by vendor-specific handlers. */ BL_AUX_PARAM_VENDOR_SPECIFIC_LAST = 0x7fffffff, BL_AUX_PARAM_GENERIC_FIRST = 0x80000001, BL_AUX_PARAM_COREBOOT_TABLE = BL_AUX_PARAM_GENERIC_FIRST, /* 0x80000001 - 0xffffffff are reserved for the generic handler. */ BL_AUX_PARAM_GENERIC_LAST = 0xffffffff, /* Top 32 bits of the type field are reserved for future use. */ }; /* common header for all BL aux parameters */ struct bl_aux_param_header { uint64_t type; uint64_t next; }; /* commonly useful parameter structures that can be shared by multiple types */ struct bl_aux_param_uint64 { struct bl_aux_param_header h; uint64_t value; }; struct bl_aux_gpio_info { uint8_t polarity; uint8_t direction; uint8_t pull_mode; uint8_t reserved; uint32_t index; }; struct bl_aux_param_gpio { struct bl_aux_param_header h; struct bl_aux_gpio_info gpio; }; #endif /* ARM_TRUSTED_FIRMWARE_EXPORT_LIB_BL_AUX_PARAMS_EXP_H */ trusted-firmware-a-2.2/include/export/lib/utils_def_exp.h000066400000000000000000000020301355360272700236210ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_TRUSTED_FIRMWARE_EXPORT_LIB_UTILS_DEF_EXP_H #define ARM_TRUSTED_FIRMWARE_EXPORT_LIB_UTILS_DEF_EXP_H /* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */ /* * For those constants to be shared between C and other sources, apply a 'U', * 'UL', 'ULL', 'L' or 'LL' suffix to the argument only in C, to avoid * undefined or unintended behaviour. * * The GNU assembler and linker do not support these suffixes (it causes the * build process to fail) therefore the suffix is omitted when used in linker * scripts and assembler files. */ #if defined(__ASSEMBLER__) # define U(_x) (_x) # define UL(_x) (_x) # define ULL(_x) (_x) # define L(_x) (_x) # define LL(_x) (_x) #else # define U(_x) (_x##U) # define UL(_x) (_x##UL) # define ULL(_x) (_x##ULL) # define L(_x) (_x##L) # define LL(_x) (_x##LL) #endif #endif /* ARM_TRUSTED_FIRMWARE_EXPORT_LIB_UTILS_DEF_EXP_H */ trusted-firmware-a-2.2/include/export/plat/000077500000000000000000000000001355360272700210155ustar00rootroot00000000000000trusted-firmware-a-2.2/include/export/plat/mediatek/000077500000000000000000000000001355360272700226005ustar00rootroot00000000000000trusted-firmware-a-2.2/include/export/plat/mediatek/common/000077500000000000000000000000001355360272700240705ustar00rootroot00000000000000trusted-firmware-a-2.2/include/export/plat/mediatek/common/plat_params_exp.h000066400000000000000000000011451355360272700274210ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_TRUSTED_FIRMWARE_EXPORT_PLAT_MEDIATEK_COMMON_PLAT_PARAMS_EXP_H #define ARM_TRUSTED_FIRMWARE_EXPORT_PLAT_MEDIATEK_COMMON_PLAT_PARAMS_EXP_H /* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */ #include "../../../lib/bl_aux_params/bl_aux_params_exp.h" /* param type */ enum bl_aux_mtk_param_type { BL_AUX_PARAM_MTK_RESET_GPIO = BL_AUX_PARAM_VENDOR_SPECIFIC_FIRST, }; #endif /* ARM_TRUSTED_FIRMWARE_EXPORT_PLAT_MEDIATEK_COMMON_PLAT_PARAMS_EXP_H */ trusted-firmware-a-2.2/include/export/plat/rockchip/000077500000000000000000000000001355360272700226175ustar00rootroot00000000000000trusted-firmware-a-2.2/include/export/plat/rockchip/common/000077500000000000000000000000001355360272700241075ustar00rootroot00000000000000trusted-firmware-a-2.2/include/export/plat/rockchip/common/plat_params_exp.h000066400000000000000000000016511355360272700274420ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_TRUSTED_FIRMWARE_EXPORT_PLAT_ROCKCHIP_COMMON_PLAT_PARAMS_EXP_H #define ARM_TRUSTED_FIRMWARE_EXPORT_PLAT_ROCKCHIP_COMMON_PLAT_PARAMS_EXP_H /* EXPORT HEADER -- See include/export/README for details! -- EXPORT HEADER */ #include "../../../lib/bl_aux_params/bl_aux_params_exp.h" /* param type */ enum bl_aux_rk_param_type { BL_AUX_PARAM_RK_RESET_GPIO = BL_AUX_PARAM_VENDOR_SPECIFIC_FIRST, BL_AUX_PARAM_RK_POWEROFF_GPIO, BL_AUX_PARAM_RK_SUSPEND_GPIO, BL_AUX_PARAM_RK_SUSPEND_APIO, }; struct bl_aux_rk_apio_info { uint8_t apio1 : 1; uint8_t apio2 : 1; uint8_t apio3 : 1; uint8_t apio4 : 1; uint8_t apio5 : 1; }; struct bl_aux_param_rk_apio { struct bl_aux_param_header h; struct bl_aux_rk_apio_info apio; }; #endif /* ARM_TRUSTED_FIRMWARE_EXPORT_PLAT_ROCKCHIP_COMMON_PLAT_PARAMS_EXP_H */ trusted-firmware-a-2.2/include/lib/000077500000000000000000000000001355360272700173025ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/bakery_lock.h000066400000000000000000000055141355360272700217450ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BAKERY_LOCK_H #define BAKERY_LOCK_H #include #define BAKERY_LOCK_MAX_CPUS PLATFORM_CORE_COUNT #ifndef __ASSEMBLER__ #include #include #include #include /***************************************************************************** * Internal helpers used by the bakery lock implementation. ****************************************************************************/ /* Convert a ticket to priority */ static inline unsigned int bakery_get_priority(unsigned int t, unsigned int pos) { return (t << 8) | pos; } #define CHOOSING_TICKET U(0x1) #define CHOSEN_TICKET U(0x0) static inline bool bakery_is_choosing(unsigned int info) { return (info & 1U) == CHOOSING_TICKET; } static inline unsigned int bakery_ticket_number(unsigned int info) { return (info >> 1) & 0x7FFFU; } static inline uint16_t make_bakery_data(unsigned int choosing, unsigned int num) { unsigned int val = (choosing & 0x1U) | (num << 1); return (uint16_t) val; } /***************************************************************************** * External bakery lock interface. ****************************************************************************/ #if USE_COHERENT_MEM /* * Bakery locks are stored in coherent memory * * Each lock's data is contiguous and fully allocated by the compiler */ typedef struct bakery_lock { /* * The lock_data is a bit-field of 2 members: * Bit[0] : choosing. This field is set when the CPU is * choosing its bakery number. * Bits[1 - 15] : number. This is the bakery number allocated. */ volatile uint16_t lock_data[BAKERY_LOCK_MAX_CPUS]; } bakery_lock_t; #else /* * Bakery locks are stored in normal .bss memory * * Each lock's data is spread across multiple cache lines, one per CPU, * but multiple locks can share the same cache line. * The compiler will allocate enough memory for one CPU's bakery locks, * the remaining cache lines are allocated by the linker script */ typedef struct bakery_info { /* * The lock_data is a bit-field of 2 members: * Bit[0] : choosing. This field is set when the CPU is * choosing its bakery number. * Bits[1 - 15] : number. This is the bakery number allocated. */ volatile uint16_t lock_data; } bakery_info_t; typedef bakery_info_t bakery_lock_t; #endif /* __USE_COHERENT_MEM__ */ static inline void bakery_lock_init(bakery_lock_t *bakery) {} void bakery_lock_get(bakery_lock_t *bakery); void bakery_lock_release(bakery_lock_t *bakery); #define DEFINE_BAKERY_LOCK(_name) bakery_lock_t _name __section("bakery_lock") #define DECLARE_BAKERY_LOCK(_name) extern bakery_lock_t _name #endif /* __ASSEMBLER__ */ #endif /* BAKERY_LOCK_H */ trusted-firmware-a-2.2/include/lib/bl_aux_params/000077500000000000000000000000001355360272700221175ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/bl_aux_params/bl_aux_params.h000066400000000000000000000016751355360272700251160ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef LIB_BL_AUX_PARAMS_H #define LIB_BL_AUX_PARAMS_H #include #include #include /* * Handler function that handles an individual aux parameter. Return true if * the parameter was handled, and flase if bl_aux_params_parse() should make its * own attempt at handling it (for generic parameters). */ typedef bool (*bl_aux_param_handler_t)(struct bl_aux_param_header *param); /* * Interprets head as the start of an aux parameter list, and passes the * parameters individually to handler(). Handles generic parameters directly if * handler() hasn't already done so. If only generic parameters are expected, * handler() can be NULL. */ void bl_aux_params_parse(u_register_t head, bl_aux_param_handler_t handler); #endif /* LIB_BL_AUX_PARAMS_H */ trusted-firmware-a-2.2/include/lib/cassert.h000066400000000000000000000014321355360272700211170ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CASSERT_H #define CASSERT_H #include /******************************************************************************* * Macro to flag a compile time assertion. It uses the preprocessor to generate * an invalid C construct if 'cond' evaluates to false. * The following compilation error is triggered if the assertion fails: * "error: size of array 'msg' is negative" * The 'unused' attribute ensures that the unused typedef does not emit a * compiler warning. ******************************************************************************/ #define CASSERT(cond, msg) \ typedef char msg[(cond) ? 1 : -1] __unused #endif /* CASSERT_H */ trusted-firmware-a-2.2/include/lib/coreboot.h000066400000000000000000000010651355360272700212710ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef COREBOOT_H #define COREBOOT_H #include typedef struct { uint32_t type; /* always 2 (memory-mapped) on ARM */ uint32_t baseaddr; uint32_t baud; uint32_t regwidth; /* in bytes, i.e. usually 4 */ uint32_t input_hertz; uint32_t uart_pci_addr; /* unused on current ARM systems */ } coreboot_serial_t; extern coreboot_serial_t coreboot_serial; void coreboot_table_setup(void *base); #endif /* COREBOOT_H */ trusted-firmware-a-2.2/include/lib/cpus/000077500000000000000000000000001355360272700202545ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/cpus/aarch32/000077500000000000000000000000001355360272700214775ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/cpus/aarch32/aem_generic.h000066400000000000000000000004601355360272700241060ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef AEM_GENERIC_H #define AEM_GENERIC_H #include /* BASE AEM midr for revision 0 */ #define BASE_AEM_MIDR U(0x410FD0F0) #endif /* AEM_GENERIC_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch32/cortex_a12.h000066400000000000000000000013511355360272700236170ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A12_H #define CORTEX_A12_H #include /******************************************************************************* * Cortex-A12 midr with version/revision set to 0 ******************************************************************************/ #define CORTEX_A12_MIDR U(0x410FC0D0) /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A12_ACTLR_SMP_BIT (U(1) << 6) #endif /* CORTEX_A12_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch32/cortex_a15.h000066400000000000000000000021261355360272700236230ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A15_H #define CORTEX_A15_H #include /******************************************************************************* * Auxiliary Control Register 2 specific definitions. ******************************************************************************/ #define CORTEX_A15_ACTLR2 p15, 1, c15, c0, 4 #define CORTEX_A15_ACTLR2_INV_DCC_BIT (U(1) << 0) /******************************************************************************* * Cortex-A15 midr with version/revision set to 0 ******************************************************************************/ #define CORTEX_A15_MIDR U(0x410FC0F0) /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A15_ACTLR_INV_BTB_BIT (U(1) << 0) #define CORTEX_A15_ACTLR_SMP_BIT (U(1) << 6) #endif /* CORTEX_A15_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch32/cortex_a17.h000066400000000000000000000017711355360272700236320ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A17_H #define CORTEX_A17_H #include /******************************************************************************* * Cortex-A17 midr with version/revision set to 0 ******************************************************************************/ #define CORTEX_A17_MIDR U(0x410FC0E0) /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A17_ACTLR_SMP_BIT (U(1) << 6) /******************************************************************************* * Implementation defined register specific definitions. ******************************************************************************/ #define CORTEX_A17_IMP_DEF_REG1 p15, 0, c15, c0, 1 #endif /* CORTEX_A17_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch32/cortex_a32.h000066400000000000000000000012641355360272700236240ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A32_H #define CORTEX_A32_H #include /* Cortex-A32 Main ID register for revision 0 */ #define CORTEX_A32_MIDR U(0x410FD010) /******************************************************************************* * CPU Extended Control register specific definitions. * CPUECTLR_EL1 is an implementation-specific register. ******************************************************************************/ #define CORTEX_A32_CPUECTLR_EL1 p15, 1, c15 #define CORTEX_A32_CPUECTLR_SMPEN_BIT (ULL(1) << 6) #endif /* CORTEX_A32_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch32/cortex_a5.h000066400000000000000000000013441355360272700235430ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A5_H #define CORTEX_A5_H #include /******************************************************************************* * Cortex-A8 midr with version/revision set to 0 ******************************************************************************/ #define CORTEX_A5_MIDR U(0x410FC050) /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A5_ACTLR_SMP_BIT (U(1) << 6) #endif /* CORTEX_A5_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch32/cortex_a53.h000066400000000000000000000057401355360272700236320ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A53_H #define CORTEX_A53_H #include /* Cortex-A53 midr for revision 0 */ #define CORTEX_A53_MIDR U(0x410FD030) /* Retention timer tick definitions */ #define RETENTION_ENTRY_TICKS_2 U(0x1) #define RETENTION_ENTRY_TICKS_8 U(0x2) #define RETENTION_ENTRY_TICKS_32 U(0x3) #define RETENTION_ENTRY_TICKS_64 U(0x4) #define RETENTION_ENTRY_TICKS_128 U(0x5) #define RETENTION_ENTRY_TICKS_256 U(0x6) #define RETENTION_ENTRY_TICKS_512 U(0x7) /******************************************************************************* * CPU Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_A53_ECTLR p15, 1, c15 #define CORTEX_A53_ECTLR_SMP_BIT (U(1) << 6) #define CORTEX_A53_ECTLR_CPU_RET_CTRL_SHIFT U(0) #define CORTEX_A53_ECTLR_CPU_RET_CTRL_MASK (ULL(0x7) << CORTEX_A53_ECTLR_CPU_RET_CTRL_SHIFT) #define CORTEX_A53_ECTLR_FPU_RET_CTRL_SHIFT U(3) #define CORTEX_A53_ECTLR_FPU_RET_CTRL_MASK (ULL(0x7) << CORTEX_A53_ECTLR_FPU_RET_CTRL_SHIFT) /******************************************************************************* * CPU Memory Error Syndrome register specific definitions. ******************************************************************************/ #define CORTEX_A53_MERRSR p15, 2, c15 /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A53_CPUACTLR p15, 0, c15 #define CORTEX_A53_CPUACTLR_ENDCCASCI_SHIFT U(44) #define CORTEX_A53_CPUACTLR_ENDCCASCI (ULL(1) << CORTEX_A53_CPUACTLR_ENDCCASCI_SHIFT) #define CORTEX_A53_CPUACTLR_DTAH_SHIFT U(24) #define CORTEX_A53_CPUACTLR_DTAH (ULL(1) << CORTEX_A53_CPUACTLR_DTAH_SHIFT) /******************************************************************************* * L2 Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A53_L2ACTLR p15, 1, c15, c0, 0 #define CORTEX_A53_L2ACTLR_ENABLE_UNIQUECLEAN (U(1) << 14) #define CORTEX_A53_L2ACTLR_DISABLE_CLEAN_PUSH (U(1) << 3) /******************************************************************************* * L2 Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_A53_L2ECTLR p15, 1, c9, c0, 3 #define CORTEX_A53_L2ECTLR_RET_CTRL_SHIFT U(0) #define CORTEX_A53_L2ECTLR_RET_CTRL_MASK (U(0x7) << L2ECTLR_RET_CTRL_SHIFT) /******************************************************************************* * L2 Memory Error Syndrome register specific definitions. ******************************************************************************/ #define CORTEX_A53_L2MERRSR p15, 3, c15 #endif /* CORTEX_A53_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch32/cortex_a57.h000066400000000000000000000071221355360272700236320ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A57_H #define CORTEX_A57_H #include /* Cortex-A57 midr for revision 0 */ #define CORTEX_A57_MIDR U(0x410FD070) /* Retention timer tick definitions */ #define RETENTION_ENTRY_TICKS_2 U(0x1) #define RETENTION_ENTRY_TICKS_8 U(0x2) #define RETENTION_ENTRY_TICKS_32 U(0x3) #define RETENTION_ENTRY_TICKS_64 U(0x4) #define RETENTION_ENTRY_TICKS_128 U(0x5) #define RETENTION_ENTRY_TICKS_256 U(0x6) #define RETENTION_ENTRY_TICKS_512 U(0x7) /******************************************************************************* * CPU Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_A57_ECTLR p15, 1, c15 #define CORTEX_A57_ECTLR_SMP_BIT (ULL(1) << 6) #define CORTEX_A57_ECTLR_DIS_TWD_ACC_PFTCH_BIT (ULL(1) << 38) #define CORTEX_A57_ECTLR_L2_IPFTCH_DIST_MASK (ULL(0x3) << 35) #define CORTEX_A57_ECTLR_L2_DPFTCH_DIST_MASK (ULL(0x3) << 32) #define CORTEX_A57_ECTLR_CPU_RET_CTRL_SHIFT U(0) #define CORTEX_A57_ECTLR_CPU_RET_CTRL_MASK (ULL(0x7) << CORTEX_A57_ECTLR_CPU_RET_CTRL_SHIFT) /******************************************************************************* * CPU Memory Error Syndrome register specific definitions. ******************************************************************************/ #define CORTEX_A57_CPUMERRSR p15, 2, c15 /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A57_CPUACTLR p15, 0, c15 #define CORTEX_A57_CPUACTLR_DIS_LOAD_PASS_DMB (ULL(1) << 59) #define CORTEX_A57_CPUACTLR_DIS_DMB_NULLIFICATION (ULL(1) << 58) #define CORTEX_A57_CPUACTLR_DIS_LOAD_PASS_STORE (ULL(1) << 55) #define CORTEX_A57_CPUACTLR_GRE_NGRE_AS_NGNRE (ULL(1) << 54) #define CORTEX_A57_CPUACTLR_DIS_OVERREAD (ULL(1) << 52) #define CORTEX_A57_CPUACTLR_NO_ALLOC_WBWA (ULL(1) << 49) #define CORTEX_A57_CPUACTLR_DCC_AS_DCCI (ULL(1) << 44) #define CORTEX_A57_CPUACTLR_FORCE_FPSCR_FLUSH (ULL(1) << 38) #define CORTEX_A57_CPUACTLR_DIS_INSTR_PREFETCH (ULL(1) << 32) #define CORTEX_A57_CPUACTLR_DIS_STREAMING (ULL(3) << 27) #define CORTEX_A57_CPUACTLR_DIS_L1_STREAMING (ULL(3) << 25) #define CORTEX_A57_CPUACTLR_DIS_INDIRECT_PREDICTOR (ULL(1) << 4) /******************************************************************************* * L2 Control register specific definitions. ******************************************************************************/ #define CORTEX_A57_L2CTLR p15, 1, c9, c0, 2 #define CORTEX_A57_L2CTLR_DATA_RAM_LATENCY_SHIFT U(0) #define CORTEX_A57_L2CTLR_TAG_RAM_LATENCY_SHIFT U(6) #define CORTEX_A57_L2_DATA_RAM_LATENCY_3_CYCLES U(0x2) #define CORTEX_A57_L2_TAG_RAM_LATENCY_3_CYCLES U(0x2) /******************************************************************************* * L2 Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_A57_L2ECTLR p15, 1, c9, c0, 3 #define CORTEX_A57_L2ECTLR_RET_CTRL_SHIFT U(0) #define CORTEX_A57_L2ECTLR_RET_CTRL_MASK (U(0x7) << CORTEX_A57_L2ECTLR_RET_CTRL_SHIFT) /******************************************************************************* * L2 Memory Error Syndrome register specific definitions. ******************************************************************************/ #define CORTEX_A57_L2MERRSR p15, 3, c15 #endif /* CORTEX_A57_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch32/cortex_a7.h000066400000000000000000000013441355360272700235450ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A7_H #define CORTEX_A7_H #include /******************************************************************************* * Cortex-A7 midr with version/revision set to 0 ******************************************************************************/ #define CORTEX_A7_MIDR U(0x410FC070) /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A7_ACTLR_SMP_BIT (U(1) << 6) #endif /* CORTEX_A7_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch32/cortex_a72.h000066400000000000000000000046051355360272700236320ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A72_H #define CORTEX_A72_H #include /* Cortex-A72 midr for revision 0 */ #define CORTEX_A72_MIDR U(0x410FD080) /******************************************************************************* * CPU Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_A72_ECTLR p15, 1, c15 #define CORTEX_A72_ECTLR_SMP_BIT (ULL(1) << 6) #define CORTEX_A72_ECTLR_DIS_TWD_ACC_PFTCH_BIT (ULL(1) << 38) #define CORTEX_A72_ECTLR_L2_IPFTCH_DIST_MASK (ULL(0x3) << 35) #define CORTEX_A72_ECTLR_L2_DPFTCH_DIST_MASK (ULL(0x3) << 32) /******************************************************************************* * CPU Memory Error Syndrome register specific definitions. ******************************************************************************/ #define CORTEX_A72_MERRSR p15, 2, c15 /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A72_CPUACTLR p15, 0, c15 #define CORTEX_A72_CPUACTLR_DISABLE_L1_DCACHE_HW_PFTCH (ULL(1) << 56) #define CORTEX_A72_CPUACTLR_DIS_LOAD_PASS_STORE (ULL(1) << 55) #define CORTEX_A72_CPUACTLR_NO_ALLOC_WBWA (ULL(1) << 49) #define CORTEX_A72_CPUACTLR_DCC_AS_DCCI (ULL(1) << 44) #define CORTEX_A72_CPUACTLR_DIS_INSTR_PREFETCH (ULL(1) << 32) /******************************************************************************* * L2 Control register specific definitions. ******************************************************************************/ #define CORTEX_A72_L2CTLR p15, 1, c9, c0, 2 #define CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT U(0) #define CORTEX_A72_L2CTLR_TAG_RAM_LATENCY_SHIFT U(6) #define CORTEX_A72_L2_DATA_RAM_LATENCY_3_CYCLES U(0x2) #define CORTEX_A72_L2_TAG_RAM_LATENCY_2_CYCLES U(0x1) #define CORTEX_A72_L2_TAG_RAM_LATENCY_3_CYCLES U(0x2) /******************************************************************************* * L2 Memory Error Syndrome register specific definitions. ******************************************************************************/ #define CORTEX_A72_L2MERRSR p15, 3, c15 #endif /* CORTEX_A72_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch32/cortex_a9.h000066400000000000000000000021141355360272700235430ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A9_H #define CORTEX_A9_H #include /******************************************************************************* * Cortex-A9 midr with version/revision set to 0 ******************************************************************************/ #define CORTEX_A9_MIDR U(0x410FC090) /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A9_ACTLR_SMP_BIT (U(1) << 6) #define CORTEX_A9_ACTLR_FLZW_BIT (U(1) << 3) /******************************************************************************* * CPU Power Control Register ******************************************************************************/ #define PCR p15, 0, c15, c0, 0 #ifndef __ASSEMBLER__ #include DEFINE_COPROCR_RW_FUNCS(pcr, PCR) #endif #endif /* CORTEX_A9_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch32/cpu_macros.S000066400000000000000000000135371355360272700237670ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CPU_MACROS_S #define CPU_MACROS_S #include #include #if defined(IMAGE_BL1) || defined(IMAGE_BL32) || (defined(IMAGE_BL2) && BL2_AT_EL3) #define IMAGE_AT_EL3 #endif #define CPU_IMPL_PN_MASK (MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | \ (MIDR_PN_MASK << MIDR_PN_SHIFT) /* The number of CPU operations allowed */ #define CPU_MAX_PWR_DWN_OPS 2 /* Special constant to specify that CPU has no reset function */ #define CPU_NO_RESET_FUNC 0 /* Word size for 32-bit CPUs */ #define CPU_WORD_SIZE 4 /* * Whether errata status needs reporting. Errata status is printed in debug * builds for both BL1 and BL32 images. */ #if (defined(IMAGE_BL1) || defined(IMAGE_BL32)) && DEBUG # define REPORT_ERRATA 1 #else # define REPORT_ERRATA 0 #endif .equ CPU_MIDR_SIZE, CPU_WORD_SIZE .equ CPU_RESET_FUNC_SIZE, CPU_WORD_SIZE .equ CPU_PWR_DWN_OPS_SIZE, CPU_WORD_SIZE * CPU_MAX_PWR_DWN_OPS .equ CPU_ERRATA_FUNC_SIZE, CPU_WORD_SIZE .equ CPU_ERRATA_LOCK_SIZE, CPU_WORD_SIZE .equ CPU_ERRATA_PRINTED_SIZE, CPU_WORD_SIZE #ifndef IMAGE_AT_EL3 .equ CPU_RESET_FUNC_SIZE, 0 #endif /* The power down core and cluster is needed only in BL32 */ #ifndef IMAGE_BL32 .equ CPU_PWR_DWN_OPS_SIZE, 0 #endif /* Fields required to print errata status */ #if !REPORT_ERRATA .equ CPU_ERRATA_FUNC_SIZE, 0 #endif /* Only BL32 requires mutual exclusion and printed flag. */ #if !(REPORT_ERRATA && defined(IMAGE_BL32)) .equ CPU_ERRATA_LOCK_SIZE, 0 .equ CPU_ERRATA_PRINTED_SIZE, 0 #endif /* * Define the offsets to the fields in cpu_ops structure. * Every offset is defined based on the offset and size of the previous * field. */ .equ CPU_MIDR, 0 .equ CPU_RESET_FUNC, CPU_MIDR + CPU_MIDR_SIZE .equ CPU_PWR_DWN_OPS, CPU_RESET_FUNC + CPU_RESET_FUNC_SIZE .equ CPU_ERRATA_FUNC, CPU_PWR_DWN_OPS + CPU_PWR_DWN_OPS_SIZE .equ CPU_ERRATA_LOCK, CPU_ERRATA_FUNC + CPU_ERRATA_FUNC_SIZE .equ CPU_ERRATA_PRINTED, CPU_ERRATA_LOCK + CPU_ERRATA_LOCK_SIZE .equ CPU_OPS_SIZE, CPU_ERRATA_PRINTED + CPU_ERRATA_PRINTED_SIZE /* * Write given expressions as words * * _count: * Write at least _count words. If the given number of expressions * is less than _count, repeat the last expression to fill _count * words in total * _rest: * Optional list of expressions. _this is for parameter extraction * only, and has no significance to the caller * * Invoked as: * fill_constants 2, foo, bar, blah, ... */ .macro fill_constants _count:req, _this, _rest:vararg .ifgt \_count /* Write the current expression */ .ifb \_this .error "Nothing to fill" .endif .word \_this /* Invoke recursively for remaining expressions */ .ifnb \_rest fill_constants \_count-1, \_rest .else fill_constants \_count-1, \_this .endif .endif .endm /* * Declare CPU operations * * _name: * Name of the CPU for which operations are being specified * _midr: * Numeric value expected to read from CPU's MIDR * _resetfunc: * Reset function for the CPU. If there's no CPU reset function, * specify CPU_NO_RESET_FUNC * _power_down_ops: * Comma-separated list of functions to perform power-down * operatios on the CPU. At least one, and up to * CPU_MAX_PWR_DWN_OPS number of functions may be specified. * Starting at power level 0, these functions shall handle power * down at subsequent power levels. If there aren't exactly * CPU_MAX_PWR_DWN_OPS functions, the last specified one will be * used to handle power down at subsequent levels */ .macro declare_cpu_ops _name:req, _midr:req, _resetfunc:req, \ _power_down_ops:vararg .section cpu_ops, "a" .align 2 .type cpu_ops_\_name, %object .word \_midr #if defined(IMAGE_AT_EL3) .word \_resetfunc #endif #ifdef IMAGE_BL32 /* Insert list of functions */ fill_constants CPU_MAX_PWR_DWN_OPS, \_power_down_ops #endif #if REPORT_ERRATA .ifndef \_name\()_cpu_str /* * Place errata reported flag, and the spinlock to arbitrate access to * it in the data section. */ .pushsection .data define_asm_spinlock \_name\()_errata_lock \_name\()_errata_reported: .word 0 .popsection /* Place CPU string in rodata */ .pushsection .rodata \_name\()_cpu_str: .asciz "\_name" .popsection .endif /* * Mandatory errata status printing function for CPUs of * this class. */ .word \_name\()_errata_report #ifdef IMAGE_BL32 /* Pointers to errata lock and reported flag */ .word \_name\()_errata_lock .word \_name\()_errata_reported #endif #endif .endm #if REPORT_ERRATA /* * Print status of a CPU errata * * _chosen: * Identifier indicating whether or not a CPU errata has been * compiled in. * _cpu: * Name of the CPU * _id: * Errata identifier * _rev_var: * Register containing the combined value CPU revision and variant * - typically the return value of cpu_get_rev_var */ .macro report_errata _chosen, _cpu, _id, _rev_var=r4 /* Stash a string with errata ID */ .pushsection .rodata \_cpu\()_errata_\_id\()_str: .asciz "\_id" .popsection /* Check whether errata applies */ mov r0, \_rev_var bl check_errata_\_id .ifeq \_chosen /* * Errata workaround has not been compiled in. If the errata would have * applied had it been compiled in, print its status as missing. */ cmp r0, #0 movne r0, #ERRATA_MISSING .endif ldr r1, =\_cpu\()_cpu_str ldr r2, =\_cpu\()_errata_\_id\()_str bl errata_print_msg .endm #endif /* * Helper macro that reads the part number of the current CPU and jumps * to the given label if it matches the CPU MIDR provided. * * Clobbers: r0-r1 */ .macro jump_if_cpu_midr _cpu_midr, _label ldcopr r0, MIDR ubfx r0, r0, #MIDR_PN_SHIFT, #12 ldr r1, =((\_cpu_midr >> MIDR_PN_SHIFT) & MIDR_PN_MASK) cmp r0, r1 beq \_label .endm #endif /* CPU_MACROS_S */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/000077500000000000000000000000001355360272700215045ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/cpus/aarch64/aem_generic.h000066400000000000000000000006041355360272700241130ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef AEM_GENERIC_H #define AEM_GENERIC_H #include /* BASE AEM midr for revision 0 */ #define BASE_AEM_MIDR U(0x410FD0F0) /* Foundation AEM midr for revision 0 */ #define FOUNDATION_AEM_MIDR U(0x410FD000) #endif /* AEM_GENERIC_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/cortex_a35.h000066400000000000000000000017731355360272700236410ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A35_H #define CORTEX_A35_H #include /* Cortex-A35 Main ID register for revision 0 */ #define CORTEX_A35_MIDR U(0x410FD040) /******************************************************************************* * CPU Extended Control register specific definitions. * CPUECTLR_EL1 is an implementation-specific register. ******************************************************************************/ #define CORTEX_A35_CPUECTLR_EL1 S3_1_C15_C2_1 #define CORTEX_A35_CPUECTLR_SMPEN_BIT (ULL(1) << 6) /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A35_CPUACTLR_EL1 S3_1_C15_C2_0 #define CORTEX_A35_CPUACTLR_EL1_ENDCCASCI (ULL(1) << 44) #endif /* CORTEX_A35_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/cortex_a53.h000066400000000000000000000072411355360272700236350ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A53_H #define CORTEX_A53_H #include /* Cortex-A53 midr for revision 0 */ #define CORTEX_A53_MIDR U(0x410FD030) /* Retention timer tick definitions */ #define RETENTION_ENTRY_TICKS_2 U(0x1) #define RETENTION_ENTRY_TICKS_8 U(0x2) #define RETENTION_ENTRY_TICKS_32 U(0x3) #define RETENTION_ENTRY_TICKS_64 U(0x4) #define RETENTION_ENTRY_TICKS_128 U(0x5) #define RETENTION_ENTRY_TICKS_256 U(0x6) #define RETENTION_ENTRY_TICKS_512 U(0x7) /******************************************************************************* * CPU Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_A53_ECTLR_EL1 S3_1_C15_C2_1 #define CORTEX_A53_ECTLR_SMP_BIT (ULL(1) << 6) #define CORTEX_A53_ECTLR_CPU_RET_CTRL_SHIFT U(0) #define CORTEX_A53_ECTLR_CPU_RET_CTRL_MASK (ULL(0x7) << CORTEX_A53_ECTLR_CPU_RET_CTRL_SHIFT) #define CORTEX_A53_ECTLR_FPU_RET_CTRL_SHIFT U(3) #define CORTEX_A53_ECTLR_FPU_RET_CTRL_MASK (ULL(0x7) << CORTEX_A53_ECTLR_FPU_RET_CTRL_SHIFT) /******************************************************************************* * CPU Memory Error Syndrome register specific definitions. ******************************************************************************/ #define CORTEX_A53_MERRSR_EL1 S3_1_C15_C2_2 /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A53_CPUACTLR_EL1 S3_1_C15_C2_0 #define CORTEX_A53_CPUACTLR_EL1_ENDCCASCI_SHIFT U(44) #define CORTEX_A53_CPUACTLR_EL1_ENDCCASCI (ULL(1) << CORTEX_A53_CPUACTLR_EL1_ENDCCASCI_SHIFT) #define CORTEX_A53_CPUACTLR_EL1_RADIS_SHIFT U(27) #define CORTEX_A53_CPUACTLR_EL1_RADIS (ULL(3) << CORTEX_A53_CPUACTLR_EL1_RADIS_SHIFT) #define CORTEX_A53_CPUACTLR_EL1_L1RADIS_SHIFT U(25) #define CORTEX_A53_CPUACTLR_EL1_L1RADIS (ULL(3) << CORTEX_A53_CPUACTLR_EL1_L1RADIS_SHIFT) #define CORTEX_A53_CPUACTLR_EL1_DTAH_SHIFT U(24) #define CORTEX_A53_CPUACTLR_EL1_DTAH (ULL(1) << CORTEX_A53_CPUACTLR_EL1_DTAH_SHIFT) /******************************************************************************* * L2 Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A53_L2ACTLR_EL1 S3_1_C15_C0_0 #define CORTEX_A53_L2ACTLR_ENABLE_UNIQUECLEAN (U(1) << 14) #define CORTEX_A53_L2ACTLR_DISABLE_CLEAN_PUSH (U(1) << 3) /******************************************************************************* * L2 Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_A53_L2ECTLR_EL1 S3_1_C11_C0_3 #define CORTEX_A53_L2ECTLR_RET_CTRL_SHIFT U(0) #define CORTEX_A53_L2ECTLR_RET_CTRL_MASK (U(0x7) << L2ECTLR_RET_CTRL_SHIFT) /******************************************************************************* * L2 Memory Error Syndrome register specific definitions. ******************************************************************************/ #define CORTEX_A53_L2MERRSR_EL1 S3_1_C15_C2_3 /******************************************************************************* * Helper function to access a53_cpuectlr_el1 register on Cortex-A53 CPUs ******************************************************************************/ #ifndef __ASSEMBLER__ DEFINE_RENAME_SYSREG_RW_FUNCS(a53_cpuectlr_el1, CORTEX_A53_ECTLR_EL1) #endif /* __ASSEMBLER__ */ #endif /* CORTEX_A53_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/cortex_a55.h000066400000000000000000000033271355360272700236400ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A55_H #define CORTEX_A55_H #include /* Cortex-A55 MIDR for revision 0 */ #define CORTEX_A55_MIDR U(0x410fd050) /******************************************************************************* * CPU Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_A55_CPUPWRCTLR_EL1 S3_0_C15_C2_7 #define CORTEX_A55_CPUECTLR_EL1 S3_0_C15_C1_4 #define CORTEX_A55_CPUECTLR_EL1_L1WSCTL (ULL(3) << 25) /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A55_CPUACTLR_EL1 S3_0_C15_C1_0 #define CORTEX_A55_CPUACTLR_EL1_DISABLE_WRITE_STREAMING (ULL(1) << 24) #define CORTEX_A55_CPUACTLR_EL1_DISABLE_DUAL_ISSUE (ULL(1) << 31) #define CORTEX_A55_CPUACTLR_EL1_DISABLE_L1_PAGEWALKS (ULL(1) << 49) /******************************************************************************* * CPU Identification register specific definitions. ******************************************************************************/ #define CORTEX_A55_CLIDR_EL1 S3_1_C0_C0_1 #define CORTEX_A55_CLIDR_EL1_CTYPE3 (ULL(7) << 6) /* Definitions of register field mask in CORTEX_A55_CPUPWRCTLR_EL1 */ #define CORTEX_A55_CORE_PWRDN_EN_MASK U(0x1) /* Instruction patching registers */ #define CPUPSELR_EL3 S3_6_C15_C8_0 #define CPUPCR_EL3 S3_6_C15_C8_1 #define CPUPOR_EL3 S3_6_C15_C8_2 #define CPUPMR_EL3 S3_6_C15_C8_3 #endif /* CORTEX_A55_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/cortex_a57.h000066400000000000000000000073171355360272700236450ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A57_H #define CORTEX_A57_H #include /* Cortex-A57 midr for revision 0 */ #define CORTEX_A57_MIDR U(0x410FD070) /* Retention timer tick definitions */ #define RETENTION_ENTRY_TICKS_2 U(0x1) #define RETENTION_ENTRY_TICKS_8 U(0x2) #define RETENTION_ENTRY_TICKS_32 U(0x3) #define RETENTION_ENTRY_TICKS_64 U(0x4) #define RETENTION_ENTRY_TICKS_128 U(0x5) #define RETENTION_ENTRY_TICKS_256 U(0x6) #define RETENTION_ENTRY_TICKS_512 U(0x7) /******************************************************************************* * CPU Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_A57_ECTLR_EL1 S3_1_C15_C2_1 #define CORTEX_A57_ECTLR_SMP_BIT (ULL(1) << 6) #define CORTEX_A57_ECTLR_DIS_TWD_ACC_PFTCH_BIT (ULL(1) << 38) #define CORTEX_A57_ECTLR_L2_IPFTCH_DIST_MASK (ULL(0x3) << 35) #define CORTEX_A57_ECTLR_L2_DPFTCH_DIST_MASK (ULL(0x3) << 32) #define CORTEX_A57_ECTLR_CPU_RET_CTRL_SHIFT U(0) #define CORTEX_A57_ECTLR_CPU_RET_CTRL_MASK (ULL(0x7) << CORTEX_A57_ECTLR_CPU_RET_CTRL_SHIFT) /******************************************************************************* * CPU Memory Error Syndrome register specific definitions. ******************************************************************************/ #define CORTEX_A57_MERRSR_EL1 S3_1_C15_C2_2 /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A57_CPUACTLR_EL1 S3_1_C15_C2_0 #define CORTEX_A57_CPUACTLR_EL1_DIS_LOAD_PASS_DMB (ULL(1) << 59) #define CORTEX_A57_CPUACTLR_EL1_DIS_DMB_NULLIFICATION (ULL(1) << 58) #define CORTEX_A57_CPUACTLR_EL1_DIS_LOAD_PASS_STORE (ULL(1) << 55) #define CORTEX_A57_CPUACTLR_EL1_GRE_NGRE_AS_NGNRE (ULL(1) << 54) #define CORTEX_A57_CPUACTLR_EL1_DIS_OVERREAD (ULL(1) << 52) #define CORTEX_A57_CPUACTLR_EL1_NO_ALLOC_WBWA (ULL(1) << 49) #define CORTEX_A57_CPUACTLR_EL1_DCC_AS_DCCI (ULL(1) << 44) #define CORTEX_A57_CPUACTLR_EL1_FORCE_FPSCR_FLUSH (ULL(1) << 38) #define CORTEX_A57_CPUACTLR_EL1_DIS_INSTR_PREFETCH (ULL(1) << 32) #define CORTEX_A57_CPUACTLR_EL1_DIS_STREAMING (ULL(3) << 27) #define CORTEX_A57_CPUACTLR_EL1_DIS_L1_STREAMING (ULL(3) << 25) #define CORTEX_A57_CPUACTLR_EL1_DIS_INDIRECT_PREDICTOR (ULL(1) << 4) /******************************************************************************* * L2 Control register specific definitions. ******************************************************************************/ #define CORTEX_A57_L2CTLR_EL1 S3_1_C11_C0_2 #define CORTEX_A57_L2CTLR_DATA_RAM_LATENCY_SHIFT U(0) #define CORTEX_A57_L2CTLR_TAG_RAM_LATENCY_SHIFT U(6) #define CORTEX_A57_L2_DATA_RAM_LATENCY_3_CYCLES U(0x2) #define CORTEX_A57_L2_TAG_RAM_LATENCY_3_CYCLES U(0x2) #define CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT (U(1) << 21) /******************************************************************************* * L2 Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_A57_L2ECTLR_EL1 S3_1_C11_C0_3 #define CORTEX_A57_L2ECTLR_RET_CTRL_SHIFT U(0) #define CORTEX_A57_L2ECTLR_RET_CTRL_MASK (U(0x7) << CORTEX_A57_L2ECTLR_RET_CTRL_SHIFT) /******************************************************************************* * L2 Memory Error Syndrome register specific definitions. ******************************************************************************/ #define CORTEX_A57_L2MERRSR_EL1 S3_1_C15_C2_3 #endif /* CORTEX_A57_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/cortex_a65.h000066400000000000000000000021111355360272700236270ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A65_H #define CORTEX_A65_H #include #define CORTEX_A65_MIDR U(0x410FD060) /******************************************************************************* * CPU Extended Control register specific definitions ******************************************************************************/ #define CORTEX_A65_ECTLR_EL1 S3_0_C15_C1_4 /******************************************************************************* * CPU Auxiliary Control register specific definitions ******************************************************************************/ #define CORTEX_A65_CPUACTLR_EL1 S3_0_C15_C1_0 /******************************************************************************* * CPU Power Control register specific definitions ******************************************************************************/ #define CORTEX_A65_CPUPWRCTLR_EL1 S3_0_C15_C2_7 #define CORTEX_A65_CPUPWRCTLR_EL1_CORE_PWRDN_BIT (U(1) << 0) #endif /* CORTEX_A65_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/cortex_a65ae.h000066400000000000000000000021301355360272700241360ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A65AE_H #define CORTEX_A65AE_H #include #define CORTEX_A65AE_MIDR U(0x410FD430) /******************************************************************************* * CPU Extended Control register specific definitions ******************************************************************************/ #define CORTEX_A65AE_ECTLR_EL1 S3_0_C15_C1_4 /******************************************************************************* * CPU Auxiliary Control register specific definitions ******************************************************************************/ #define CORTEX_A65AE_CPUACTLR_EL1 S3_0_C15_C1_0 /******************************************************************************* * CPU Power Control register specific definitions ******************************************************************************/ #define CORTEX_A65AE_CPUPWRCTLR_EL1 S3_0_C15_C2_7 #define CORTEX_A65AE_CPUPWRCTLR_EL1_CORE_PWRDN_BIT (U(1) << 0) #endif /* CORTEX_A65AE_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/cortex_a72.h000066400000000000000000000054031355360272700236340ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A72_H #define CORTEX_A72_H #include /* Cortex-A72 midr for revision 0 */ #define CORTEX_A72_MIDR U(0x410FD080) /******************************************************************************* * CPU Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_A72_ECTLR_EL1 S3_1_C15_C2_1 #define CORTEX_A72_ECTLR_SMP_BIT (ULL(1) << 6) #define CORTEX_A72_ECTLR_DIS_TWD_ACC_PFTCH_BIT (ULL(1) << 38) #define CORTEX_A72_ECTLR_L2_IPFTCH_DIST_MASK (ULL(0x3) << 35) #define CORTEX_A72_ECTLR_L2_DPFTCH_DIST_MASK (ULL(0x3) << 32) /******************************************************************************* * CPU Memory Error Syndrome register specific definitions. ******************************************************************************/ #define CORTEX_A72_MERRSR_EL1 S3_1_C15_C2_2 /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A72_CPUACTLR_EL1 S3_1_C15_C2_0 #define CORTEX_A72_CPUACTLR_EL1_DISABLE_L1_DCACHE_HW_PFTCH (ULL(1) << 56) #define CORTEX_A72_CPUACTLR_EL1_DIS_LOAD_PASS_STORE (ULL(1) << 55) #define CORTEX_A72_CPUACTLR_EL1_NO_ALLOC_WBWA (ULL(1) << 49) #define CORTEX_A72_CPUACTLR_EL1_DCC_AS_DCCI (ULL(1) << 44) #define CORTEX_A72_CPUACTLR_EL1_DIS_INSTR_PREFETCH (ULL(1) << 32) /******************************************************************************* * L2 Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A72_L2ACTLR_EL1 S3_1_C15_C0_0 #define CORTEX_A72_L2ACTLR_ENABLE_UNIQUE_CLEAN (ULL(1) << 14) /******************************************************************************* * L2 Control register specific definitions. ******************************************************************************/ #define CORTEX_A72_L2CTLR_EL1 S3_1_C11_C0_2 #define CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT U(0) #define CORTEX_A72_L2CTLR_TAG_RAM_LATENCY_SHIFT U(6) #define CORTEX_A72_L2_DATA_RAM_LATENCY_3_CYCLES U(0x2) #define CORTEX_A72_L2_TAG_RAM_LATENCY_2_CYCLES U(0x1) #define CORTEX_A72_L2_TAG_RAM_LATENCY_3_CYCLES U(0x2) /******************************************************************************* * L2 Memory Error Syndrome register specific definitions. ******************************************************************************/ #define CORTEX_A72_L2MERRSR_EL1 S3_1_C15_C2_3 #endif /* CORTEX_A72_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/cortex_a73.h000066400000000000000000000033161355360272700236360ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A73_H #define CORTEX_A73_H #include /* Cortex-A73 midr for revision 0 */ #define CORTEX_A73_MIDR U(0x410FD090) /******************************************************************************* * CPU Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_A73_CPUECTLR_EL1 S3_1_C15_C2_1 /* Instruction def. */ #define CORTEX_A73_CPUECTLR_SMP_BIT (ULL(1) << 6) /******************************************************************************* * L2 Memory Error Syndrome register specific definitions. ******************************************************************************/ #define CORTEX_A73_L2MERRSR_EL1 S3_1_C15_C2_3 /* Instruction def. */ /******************************************************************************* * CPU implementation defined register specific definitions. ******************************************************************************/ #define CORTEX_A73_IMP_DEF_REG1 S3_0_C15_C0_0 #define CORTEX_A73_IMP_DEF_REG1_DISABLE_LOAD_PASS_STORE (ULL(1) << 3) #define CORTEX_A73_DIAGNOSTIC_REGISTER S3_0_C15_C0_1 #define CORTEX_A73_IMP_DEF_REG2 S3_0_C15_C0_2 /******************************************************************************* * Helper function to access a73_cpuectlr_el1 register on Cortex-A73 CPUs ******************************************************************************/ #ifndef __ASSEMBLER__ DEFINE_RENAME_SYSREG_RW_FUNCS(a73_cpuectlr_el1, CORTEX_A73_CPUECTLR_EL1) #endif /* __ASSEMBLER__ */ #endif /* CORTEX_A73_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/cortex_a75.h000066400000000000000000000036661355360272700236500ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A75_H #define CORTEX_A75_H #include /* Cortex-A75 MIDR */ #define CORTEX_A75_MIDR U(0x410fd0a0) /******************************************************************************* * CPU Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_A75_CPUPWRCTLR_EL1 S3_0_C15_C2_7 #define CORTEX_A75_CPUECTLR_EL1 S3_0_C15_C1_4 /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A75_CPUACTLR_EL1 S3_0_C15_C1_0 #define CORTEX_A75_CPUACTLR_EL1_DISABLE_LOAD_PASS_STORE (ULL(1) << 35) /* Definitions of register field mask in CORTEX_A75_CPUPWRCTLR_EL1 */ #define CORTEX_A75_CORE_PWRDN_EN_MASK U(0x1) #define CORTEX_A75_ACTLR_AMEN_BIT (ULL(1) << 4) /* * The Cortex-A75 core implements five counters, 0-4. Events 0, 1, 2, are * fixed and are enabled (Group 0). Events 3 and 4 (Group 1) are * programmable by programming the appropriate Event count bits in * CPUAMEVTYPER register and are disabled by default. Platforms may * enable this with suitable programming. */ #define CORTEX_A75_AMU_NR_COUNTERS U(5) #define CORTEX_A75_AMU_GROUP0_MASK U(0x7) #define CORTEX_A75_AMU_GROUP1_MASK (U(0) << 3) #ifndef __ASSEMBLER__ #include uint64_t cortex_a75_amu_cnt_read(int idx); void cortex_a75_amu_cnt_write(int idx, uint64_t val); unsigned int cortex_a75_amu_read_cpuamcntenset_el0(void); unsigned int cortex_a75_amu_read_cpuamcntenclr_el0(void); void cortex_a75_amu_write_cpuamcntenset_el0(unsigned int mask); void cortex_a75_amu_write_cpuamcntenclr_el0(unsigned int mask); #endif /* __ASSEMBLER__ */ #endif /* CORTEX_A75_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/cortex_a76.h000066400000000000000000000026731355360272700236460ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A76_H #define CORTEX_A76_H #include /* Cortex-A76 MIDR for revision 0 */ #define CORTEX_A76_MIDR U(0x410fd0b0) /******************************************************************************* * CPU Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_A76_CPUPWRCTLR_EL1 S3_0_C15_C2_7 #define CORTEX_A76_CPUECTLR_EL1 S3_0_C15_C1_4 #define CORTEX_A76_CPUECTLR_EL1_WS_THR_L2 (ULL(3) << 24) #define CORTEX_A76_CPUECTLR_EL1_BIT_51 (ULL(1) << 51) /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_A76_CPUACTLR_EL1 S3_0_C15_C1_0 #define CORTEX_A76_CPUACTLR_EL1_DISABLE_STATIC_PREDICTION (ULL(1) << 6) #define CORTEX_A76_CPUACTLR_EL1_BIT_13 (ULL(1) << 13) #define CORTEX_A76_CPUACTLR2_EL1 S3_0_C15_C1_1 #define CORTEX_A76_CPUACTLR2_EL1_DISABLE_LOAD_PASS_STORE (ULL(1) << 16) #define CORTEX_A76_CPUACTLR3_EL1 S3_0_C15_C1_2 #define CORTEX_A76_CPUACTLR3_EL1_BIT_10 (ULL(1) << 10) /* Definitions of register field mask in CORTEX_A76_CPUPWRCTLR_EL1 */ #define CORTEX_A76_CORE_PWRDN_EN_MASK U(0x1) #endif /* CORTEX_A76_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/cortex_a76ae.h000066400000000000000000000013321355360272700241430ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A76AE_H #define CORTEX_A76AE_H #include /* Cortex-A76AE MIDR for revision 0 */ #define CORTEX_A76AE_MIDR U(0x410FD0E0) /******************************************************************************* * CPU Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_A76AE_CPUPWRCTLR_EL1 S3_0_C15_C2_7 /* Definitions of register field mask in CORTEX_A76AE_CPUPWRCTLR_EL1 */ #define CORTEX_A76AE_CORE_PWRDN_EN_MASK U(0x1) #define CORTEX_A76AE_CPUECTLR_EL1 S3_0_C15_C1_4 #endif /* CORTEX_A76AE_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/cortex_a77.h000066400000000000000000000015661355360272700236470ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_A77_H #define CORTEX_A77_H #include /* Cortex-A77 MIDR */ #define CORTEX_A77_MIDR U(0x410FD0D0) /******************************************************************************* * CPU Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_A77_CPUECTLR_EL1 S3_0_C15_C1_4 /******************************************************************************* * CPU Power Control register specific definitions. ******************************************************************************/ #define CORTEX_A77_CPUPWRCTLR_EL1 S3_0_C15_C2_7 #define CORTEX_A77_CPUPWRCTLR_EL1_CORE_PWRDN_BIT (U(1) << 0) #endif /* CORTEX_A77_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/cortex_hercules.h000066400000000000000000000031641355360272700250570ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_HERCULES_H #define CORTEX_HERCULES_H #include #define CORTEX_HERCULES_MIDR U(0x410FD410) /******************************************************************************* * CPU Extended Control register specific definitions. ******************************************************************************/ #define CORTEX_HERCULES_CPUECTLR_EL1 S3_0_C15_C1_4 /******************************************************************************* * CPU Power Control register specific definitions ******************************************************************************/ #define CORTEX_HERCULES_CPUPWRCTLR_EL1 S3_0_C15_C2_7 #define CORTEX_HERCULES_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT U(1) /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define CORTEX_HERCULES_ACTLR_TAM_BIT (ULL(1) << 30) /******************************************************************************* * CPU Activity Monitor Unit register specific definitions. ******************************************************************************/ #define CPUAMCNTENCLR0_EL0 S3_3_C15_C2_4 #define CPUAMCNTENSET0_EL0 S3_3_C15_C2_5 #define CPUAMCNTENCLR1_EL0 S3_3_C15_C3_0 #define CPUAMCNTENSET1_EL0 S3_3_C15_C3_1 #define CORTEX_HERCULES_AMU_GROUP0_MASK U(0xF) #define CORTEX_HERCULES_AMU_GROUP1_MASK U(0x7) #endif /* CORTEX_HERCULES_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/cortex_hercules_ae.h000066400000000000000000000004271355360272700255230ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CORTEX_HERCULES_AE_H #define CORTEX_HERCULES_AE_H #include #define CORTEX_HERCULES_AE_MIDR U(0x410FD420) #endif /* CORTEX_HERCULES_AE_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/cpu_macros.S000066400000000000000000000207041355360272700237660ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CPU_MACROS_S #define CPU_MACROS_S #include #include #include #define CPU_IMPL_PN_MASK (MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | \ (MIDR_PN_MASK << MIDR_PN_SHIFT) /* The number of CPU operations allowed */ #define CPU_MAX_PWR_DWN_OPS 2 /* Special constant to specify that CPU has no reset function */ #define CPU_NO_RESET_FUNC 0 #define CPU_NO_EXTRA1_FUNC 0 #define CPU_NO_EXTRA2_FUNC 0 /* Word size for 64-bit CPUs */ #define CPU_WORD_SIZE 8 #if defined(IMAGE_BL1) || defined(IMAGE_BL31) ||(defined(IMAGE_BL2) && BL2_AT_EL3) #define IMAGE_AT_EL3 #endif /* * Whether errata status needs reporting. Errata status is printed in debug * builds for both BL1 and BL31 images. */ #if (defined(IMAGE_BL1) || defined(IMAGE_BL31)) && DEBUG # define REPORT_ERRATA 1 #else # define REPORT_ERRATA 0 #endif .equ CPU_MIDR_SIZE, CPU_WORD_SIZE .equ CPU_EXTRA1_FUNC_SIZE, CPU_WORD_SIZE .equ CPU_EXTRA2_FUNC_SIZE, CPU_WORD_SIZE .equ CPU_E_HANDLER_FUNC_SIZE, CPU_WORD_SIZE .equ CPU_RESET_FUNC_SIZE, CPU_WORD_SIZE .equ CPU_PWR_DWN_OPS_SIZE, CPU_WORD_SIZE * CPU_MAX_PWR_DWN_OPS .equ CPU_ERRATA_FUNC_SIZE, CPU_WORD_SIZE .equ CPU_ERRATA_LOCK_SIZE, CPU_WORD_SIZE .equ CPU_ERRATA_PRINTED_SIZE, CPU_WORD_SIZE .equ CPU_REG_DUMP_SIZE, CPU_WORD_SIZE #ifndef IMAGE_AT_EL3 .equ CPU_RESET_FUNC_SIZE, 0 #endif /* The power down core and cluster is needed only in BL31 */ #ifndef IMAGE_BL31 .equ CPU_PWR_DWN_OPS_SIZE, 0 #endif /* Fields required to print errata status. */ #if !REPORT_ERRATA .equ CPU_ERRATA_FUNC_SIZE, 0 #endif /* Only BL31 requieres mutual exclusion and printed flag. */ #if !(REPORT_ERRATA && defined(IMAGE_BL31)) .equ CPU_ERRATA_LOCK_SIZE, 0 .equ CPU_ERRATA_PRINTED_SIZE, 0 #endif #if !defined(IMAGE_BL31) || !CRASH_REPORTING .equ CPU_REG_DUMP_SIZE, 0 #endif /* * Define the offsets to the fields in cpu_ops structure. * Every offset is defined based in the offset and size of the previous * field. */ .equ CPU_MIDR, 0 .equ CPU_RESET_FUNC, CPU_MIDR + CPU_MIDR_SIZE .equ CPU_EXTRA1_FUNC, CPU_RESET_FUNC + CPU_RESET_FUNC_SIZE .equ CPU_EXTRA2_FUNC, CPU_EXTRA1_FUNC + CPU_EXTRA1_FUNC_SIZE .equ CPU_E_HANDLER_FUNC, CPU_EXTRA2_FUNC + CPU_EXTRA2_FUNC_SIZE .equ CPU_PWR_DWN_OPS, CPU_E_HANDLER_FUNC + CPU_E_HANDLER_FUNC_SIZE .equ CPU_ERRATA_FUNC, CPU_PWR_DWN_OPS + CPU_PWR_DWN_OPS_SIZE .equ CPU_ERRATA_LOCK, CPU_ERRATA_FUNC + CPU_ERRATA_FUNC_SIZE .equ CPU_ERRATA_PRINTED, CPU_ERRATA_LOCK + CPU_ERRATA_LOCK_SIZE .equ CPU_REG_DUMP, CPU_ERRATA_PRINTED + CPU_ERRATA_PRINTED_SIZE .equ CPU_OPS_SIZE, CPU_REG_DUMP + CPU_REG_DUMP_SIZE /* * Write given expressions as quad words * * _count: * Write at least _count quad words. If the given number of * expressions is less than _count, repeat the last expression to * fill _count quad words in total * _rest: * Optional list of expressions. _this is for parameter extraction * only, and has no significance to the caller * * Invoked as: * fill_constants 2, foo, bar, blah, ... */ .macro fill_constants _count:req, _this, _rest:vararg .ifgt \_count /* Write the current expression */ .ifb \_this .error "Nothing to fill" .endif .quad \_this /* Invoke recursively for remaining expressions */ .ifnb \_rest fill_constants \_count-1, \_rest .else fill_constants \_count-1, \_this .endif .endif .endm /* * Declare CPU operations * * _name: * Name of the CPU for which operations are being specified * _midr: * Numeric value expected to read from CPU's MIDR * _resetfunc: * Reset function for the CPU. If there's no CPU reset function, * specify CPU_NO_RESET_FUNC * _extra1: * This is a placeholder for future per CPU operations. Currently, * some CPUs use this entry to set a test function to determine if * the workaround for CVE-2017-5715 needs to be applied or not. * _extra2: * This is a placeholder for future per CPU operations. Currently * some CPUs use this entry to set a function to disable the * workaround for CVE-2018-3639. * _e_handler: * This is a placeholder for future per CPU exception handlers. * _power_down_ops: * Comma-separated list of functions to perform power-down * operatios on the CPU. At least one, and up to * CPU_MAX_PWR_DWN_OPS number of functions may be specified. * Starting at power level 0, these functions shall handle power * down at subsequent power levels. If there aren't exactly * CPU_MAX_PWR_DWN_OPS functions, the last specified one will be * used to handle power down at subsequent levels */ .macro declare_cpu_ops_base _name:req, _midr:req, _resetfunc:req, \ _extra1:req, _extra2:req, _e_handler:req, _power_down_ops:vararg .section cpu_ops, "a" .align 3 .type cpu_ops_\_name, %object .quad \_midr #if defined(IMAGE_AT_EL3) .quad \_resetfunc #endif .quad \_extra1 .quad \_extra2 .quad \_e_handler #ifdef IMAGE_BL31 /* Insert list of functions */ fill_constants CPU_MAX_PWR_DWN_OPS, \_power_down_ops #endif #if REPORT_ERRATA .ifndef \_name\()_cpu_str /* * Place errata reported flag, and the spinlock to arbitrate access to * it in the data section. */ .pushsection .data define_asm_spinlock \_name\()_errata_lock \_name\()_errata_reported: .word 0 .popsection /* Place CPU string in rodata */ .pushsection .rodata \_name\()_cpu_str: .asciz "\_name" .popsection .endif /* * Mandatory errata status printing function for CPUs of * this class. */ .quad \_name\()_errata_report #ifdef IMAGE_BL31 /* Pointers to errata lock and reported flag */ .quad \_name\()_errata_lock .quad \_name\()_errata_reported #endif #endif #if defined(IMAGE_BL31) && CRASH_REPORTING .quad \_name\()_cpu_reg_dump #endif .endm .macro declare_cpu_ops _name:req, _midr:req, _resetfunc:req, \ _power_down_ops:vararg declare_cpu_ops_base \_name, \_midr, \_resetfunc, 0, 0, 0, \ \_power_down_ops .endm .macro declare_cpu_ops_eh _name:req, _midr:req, _resetfunc:req, \ _e_handler:req, _power_down_ops:vararg declare_cpu_ops_base \_name, \_midr, \_resetfunc, \ 0, 0, \_e_handler, \_power_down_ops .endm .macro declare_cpu_ops_wa _name:req, _midr:req, \ _resetfunc:req, _extra1:req, _extra2:req, \ _power_down_ops:vararg declare_cpu_ops_base \_name, \_midr, \_resetfunc, \ \_extra1, \_extra2, 0, \_power_down_ops .endm #if REPORT_ERRATA /* * Print status of a CPU errata * * _chosen: * Identifier indicating whether or not a CPU errata has been * compiled in. * _cpu: * Name of the CPU * _id: * Errata identifier * _rev_var: * Register containing the combined value CPU revision and variant * - typically the return value of cpu_get_rev_var */ .macro report_errata _chosen, _cpu, _id, _rev_var=x8 /* Stash a string with errata ID */ .pushsection .rodata \_cpu\()_errata_\_id\()_str: .asciz "\_id" .popsection /* Check whether errata applies */ mov x0, \_rev_var /* Shall clobber: x0-x7 */ bl check_errata_\_id .ifeq \_chosen /* * Errata workaround has not been compiled in. If the errata would have * applied had it been compiled in, print its status as missing. */ cbz x0, 900f mov x0, #ERRATA_MISSING .endif 900: adr x1, \_cpu\()_cpu_str adr x2, \_cpu\()_errata_\_id\()_str bl errata_print_msg .endm #endif /* * This macro is used on some CPUs to detect if they are vulnerable * to CVE-2017-5715. */ .macro cpu_check_csv2 _reg _label mrs \_reg, id_aa64pfr0_el1 ubfx \_reg, \_reg, #ID_AA64PFR0_CSV2_SHIFT, #ID_AA64PFR0_CSV2_LENGTH /* * If the field equals 1, branch targets trained in one context cannot * affect speculative execution in a different context. * * If the field equals 2, it means that the system is also aware of * SCXTNUM_ELx register contexts. We aren't using them in the TF, so we * expect users of the registers to do the right thing. * * Only apply mitigations if the value of this field is 0. */ #if ENABLE_ASSERTIONS cmp \_reg, #3 /* Only values 0 to 2 are expected */ ASM_ASSERT(lo) #endif cmp \_reg, #0 bne \_label .endm /* * Helper macro that reads the part number of the current * CPU and jumps to the given label if it matches the CPU * MIDR provided. * * Clobbers x0. */ .macro jump_if_cpu_midr _cpu_midr, _label mrs x0, midr_el1 ubfx x0, x0, MIDR_PN_SHIFT, #12 cmp w0, #((\_cpu_midr >> MIDR_PN_SHIFT) & MIDR_PN_MASK) b.eq \_label .endm #endif /* CPU_MACROS_S */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/cpuamu.h000066400000000000000000000030631355360272700231510ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CPUAMU_H #define CPUAMU_H /******************************************************************************* * CPU Activity Monitor Unit register specific definitions. ******************************************************************************/ #define CPUAMCNTENCLR_EL0 S3_3_C15_C9_7 #define CPUAMCNTENSET_EL0 S3_3_C15_C9_6 #define CPUAMCFGR_EL0 S3_3_C15_C10_6 #define CPUAMUSERENR_EL0 S3_3_C15_C10_7 /* Activity Monitor Event Counter Registers */ #define CPUAMEVCNTR0_EL0 S3_3_C15_C9_0 #define CPUAMEVCNTR1_EL0 S3_3_C15_C9_1 #define CPUAMEVCNTR2_EL0 S3_3_C15_C9_2 #define CPUAMEVCNTR3_EL0 S3_3_C15_C9_3 #define CPUAMEVCNTR4_EL0 S3_3_C15_C9_4 /* Activity Monitor Event Type Registers */ #define CPUAMEVTYPER0_EL0 S3_3_C15_C10_0 #define CPUAMEVTYPER1_EL0 S3_3_C15_C10_1 #define CPUAMEVTYPER2_EL0 S3_3_C15_C10_2 #define CPUAMEVTYPER3_EL0 S3_3_C15_C10_3 #define CPUAMEVTYPER4_EL0 S3_3_C15_C10_4 #ifndef __ASSEMBLER__ #include uint64_t cpuamu_cnt_read(unsigned int idx); void cpuamu_cnt_write(unsigned int idx, uint64_t val); unsigned int cpuamu_read_cpuamcntenset_el0(void); unsigned int cpuamu_read_cpuamcntenclr_el0(void); void cpuamu_write_cpuamcntenset_el0(unsigned int mask); void cpuamu_write_cpuamcntenclr_el0(unsigned int mask); int midr_match(unsigned int cpu_midr); void cpuamu_context_save(unsigned int nr_counters); void cpuamu_context_restore(unsigned int nr_counters); #endif /* __ASSEMBLER__ */ #endif /* CPUAMU_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/denver.h000066400000000000000000000022021355360272700231340ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef DENVER_H #define DENVER_H /* MIDR values for Denver */ #define DENVER_MIDR_PN0 U(0x4E0F0000) #define DENVER_MIDR_PN1 U(0x4E0F0010) #define DENVER_MIDR_PN2 U(0x4E0F0020) #define DENVER_MIDR_PN3 U(0x4E0F0030) #define DENVER_MIDR_PN4 U(0x4E0F0040) /* Implementer code in the MIDR register */ #define DENVER_IMPL U(0x4E) /* CPU state ids - implementation defined */ #define DENVER_CPU_STATE_POWER_DOWN U(0x3) /* Speculative store buffering */ #define DENVER_CPU_DIS_SSB_EL3 (U(1) << 11) #define DENVER_PN4_CPU_DIS_SSB_EL3 (U(1) << 18) /* Speculative memory disambiguation */ #define DENVER_CPU_DIS_MD_EL3 (U(1) << 9) #define DENVER_PN4_CPU_DIS_MD_EL3 (U(1) << 17) /* Core power management states */ #define DENVER_CPU_PMSTATE_C1 U(0x1) #define DENVER_CPU_PMSTATE_C6 U(0x6) #define DENVER_CPU_PMSTATE_C7 U(0x7) #define DENVER_CPU_PMSTATE_MASK U(0xF) #ifndef __ASSEMBLER__ /* Disable Dynamic Code Optimisation */ void denver_disable_dco(void); #endif /* __ASSEMBLER__ */ #endif /* DENVER_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/dsu_def.h000066400000000000000000000025511355360272700232710ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef DSU_DEF_H #define DSU_DEF_H #include /******************************************************************** * DSU Cluster Configuration registers definitions ********************************************************************/ #define CLUSTERCFR_EL1 S3_0_C15_C3_0 #define CLUSTERCFR_ACP_SHIFT U(11) /******************************************************************** * DSU Cluster Main Revision ID registers definitions ********************************************************************/ #define CLUSTERIDR_EL1 S3_0_C15_C3_1 #define CLUSTERIDR_REV_SHIFT U(0) #define CLUSTERIDR_REV_BITS U(4) #define CLUSTERIDR_VAR_SHIFT U(4) #define CLUSTERIDR_VAR_BITS U(4) /******************************************************************** * DSU Cluster Auxiliary Control registers definitions ********************************************************************/ #define CLUSTERACTLR_EL1 S3_0_C15_C3_3 #define CLUSTERACTLR_EL1_DISABLE_CLOCK_GATING (ULL(1) << 15) /******************************************************************** * Masks applied for DSU errata workarounds ********************************************************************/ #define DSU_ERRATA_936184_MASK (U(0x3) << 15) #endif /* DSU_DEF_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/neoverse_e1.h000066400000000000000000000021541355360272700240720ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef NEOVERSE_E1_H #define NEOVERSE_E1_H #include #define NEOVERSE_E1_MIDR U(0x410FD4A0) /******************************************************************************* * CPU Extended Control register specific definitions. ******************************************************************************/ #define NEOVERSE_E1_ECTLR_EL1 S3_0_C15_C1_4 /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define NEOVERSE_E1_CPUACTLR_EL1 S3_0_C15_C1_0 /******************************************************************************* * CPU Power Control register specific definitions. ******************************************************************************/ #define NEOVERSE_E1_CPUPWRCTLR_EL1 S3_0_C15_C2_7 #define NEOVERSE_E1_CPUPWRCTLR_EL1_CORE_PWRDN_BIT (U(1) << 0) #endif /* NEOVERSE_E1_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/neoverse_n1.h000066400000000000000000000044431355360272700241060ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef NEOVERSE_N1_H #define NEOVERSE_N1_H #include /* Neoverse N1 MIDR for revision 0 */ #define NEOVERSE_N1_MIDR U(0x410fd0c0) /* Exception Syndrome register EC code for IC Trap */ #define NEOVERSE_N1_EC_IC_TRAP U(0x1f) /******************************************************************************* * CPU Power Control register specific definitions. ******************************************************************************/ #define NEOVERSE_N1_CPUPWRCTLR_EL1 S3_0_C15_C2_7 /* Definitions of register field mask in NEOVERSE_N1_CPUPWRCTLR_EL1 */ #define NEOVERSE_N1_CORE_PWRDN_EN_MASK U(0x1) #define NEOVERSE_N1_ACTLR_AMEN_BIT (U(1) << 4) #define NEOVERSE_N1_AMU_NR_COUNTERS U(5) #define NEOVERSE_N1_AMU_GROUP0_MASK U(0x1f) /******************************************************************************* * CPU Extended Control register specific definitions. ******************************************************************************/ #define NEOVERSE_N1_CPUECTLR_EL1 S3_0_C15_C1_4 #define NEOVERSE_N1_WS_THR_L2_MASK (ULL(3) << 24) #define NEOVERSE_N1_CPUECTLR_EL1_MM_TLBPF_DIS_BIT (ULL(1) << 51) /******************************************************************************* * CPU Auxiliary Control register specific definitions. ******************************************************************************/ #define NEOVERSE_N1_CPUACTLR_EL1 S3_0_C15_C1_0 #define NEOVERSE_N1_CPUACTLR_EL1_BIT_6 (ULL(1) << 6) #define NEOVERSE_N1_CPUACTLR_EL1_BIT_13 (ULL(1) << 13) #define NEOVERSE_N1_CPUACTLR2_EL1 S3_0_C15_C1_1 #define NEOVERSE_N1_CPUACTLR2_EL1_BIT_0 (ULL(1) << 0) #define NEOVERSE_N1_CPUACTLR2_EL1_BIT_2 (ULL(1) << 2) #define NEOVERSE_N1_CPUACTLR2_EL1_BIT_11 (ULL(1) << 11) #define NEOVERSE_N1_CPUACTLR2_EL1_BIT_15 (ULL(1) << 15) #define NEOVERSE_N1_CPUACTLR2_EL1_BIT_16 (ULL(1) << 16) #define NEOVERSE_N1_CPUACTLR2_EL1_BIT_59 (ULL(1) << 59) #define NEOVERSE_N1_CPUACTLR3_EL1 S3_0_C15_C1_2 #define NEOVERSE_N1_CPUACTLR3_EL1_BIT_10 (ULL(1) << 10) /* Instruction patching registers */ #define CPUPSELR_EL3 S3_6_C15_C8_0 #define CPUPCR_EL3 S3_6_C15_C8_1 #define CPUPOR_EL3 S3_6_C15_C8_2 #define CPUPMR_EL3 S3_6_C15_C8_3 #endif /* NEOVERSE_N1_H */ trusted-firmware-a-2.2/include/lib/cpus/aarch64/neoverse_zeus.h000066400000000000000000000014751355360272700245600ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef NEOVERSE_ZEUS_H #define NEOVERSE_ZEUS_H #define NEOVERSE_ZEUS_MIDR U(0x410FD400) /******************************************************************************* * CPU Extended Control register specific definitions. ******************************************************************************/ #define NEOVERSE_ZEUS_CPUECTLR_EL1 S3_0_C15_C1_4 /******************************************************************************* * CPU Power Control register specific definitions ******************************************************************************/ #define NEOVERSE_ZEUS_CPUPWRCTLR_EL1 S3_0_C15_C2_7 #define NEOVERSE_ZEUS_CPUPWRCTLR_EL1_CORE_PWRDN_BIT U(1) #endif /* NEOVERSE_ZEUS_H */ trusted-firmware-a-2.2/include/lib/cpus/errata_report.h000066400000000000000000000013041355360272700232740ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ERRATA_REPORT_H #define ERRATA_REPORT_H #ifndef __ASSEMBLER__ #include #include #include #include #if DEBUG void print_errata_status(void); #else static inline void print_errata_status(void) {} #endif void errata_print_msg(unsigned int status, const char *cpu, const char *id); int errata_needs_reporting(spinlock_t *lock, uint32_t *reported); #endif /* __ASSEMBLER__ */ /* Errata status */ #define ERRATA_NOT_APPLIES 0 #define ERRATA_APPLIES 1 #define ERRATA_MISSING 2 #endif /* ERRATA_REPORT_H */ trusted-firmware-a-2.2/include/lib/cpus/wa_cve_2017_5715.h000066400000000000000000000003701355360272700230230ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef WA_CVE_2017_5715_H #define WA_CVE_2017_5715_H int check_wa_cve_2017_5715(void); #endif /* WA_CVE_2017_5715_H */ trusted-firmware-a-2.2/include/lib/cpus/wa_cve_2018_3639.h000066400000000000000000000004041355360272700230250ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef WA_CVE_2018_3639_H #define WA_CVE_2018_3639_H void *wa_cve_2018_3639_get_disable_ptr(void); #endif /* WA_CVE_2018_3639_H */ trusted-firmware-a-2.2/include/lib/el3_runtime/000077500000000000000000000000001355360272700215305ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/el3_runtime/aarch32/000077500000000000000000000000001355360272700227535ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/el3_runtime/aarch32/context.h000066400000000000000000000036551355360272700246210ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CONTEXT_H #define CONTEXT_H #include /******************************************************************************* * Constants that allow assembler code to access members of and the 'regs' * structure at their correct offsets. ******************************************************************************/ #define CTX_REGS_OFFSET U(0x0) #define CTX_GPREG_R0 U(0x0) #define CTX_GPREG_R1 U(0x4) #define CTX_GPREG_R2 U(0x8) #define CTX_GPREG_R3 U(0xC) #define CTX_LR U(0x10) #define CTX_SCR U(0x14) #define CTX_SPSR U(0x18) #define CTX_NS_SCTLR U(0x1C) #define CTX_REGS_END U(0x20) #ifndef __ASSEMBLER__ #include #include /* * Common constants to help define the 'cpu_context' structure and its * members below. */ #define WORD_SHIFT U(2) #define DEFINE_REG_STRUCT(name, num_regs) \ typedef struct name { \ uint32_t _regs[num_regs]; \ } __aligned(8) name##_t /* Constants to determine the size of individual context structures */ #define CTX_REG_ALL (CTX_REGS_END >> WORD_SHIFT) DEFINE_REG_STRUCT(regs, CTX_REG_ALL); #undef CTX_REG_ALL #define read_ctx_reg(ctx, offset) ((ctx)->_regs[offset >> WORD_SHIFT]) #define write_ctx_reg(ctx, offset, val) (((ctx)->_regs[offset >> WORD_SHIFT]) \ = val) typedef struct cpu_context { regs_t regs_ctx; } cpu_context_t; /* Macros to access members of the 'cpu_context_t' structure */ #define get_regs_ctx(h) (&((cpu_context_t *) h)->regs_ctx) /* * Compile time assertions related to the 'cpu_context' structure to * ensure that the assembler and the compiler view of the offsets of * the structure members is the same. */ CASSERT(CTX_REGS_OFFSET == __builtin_offsetof(cpu_context_t, regs_ctx), \ assert_core_context_regs_offset_mismatch); #endif /* __ASSEMBLER__ */ #endif /* CONTEXT_H */ trusted-firmware-a-2.2/include/lib/el3_runtime/aarch64/000077500000000000000000000000001355360272700227605ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/el3_runtime/aarch64/context.h000066400000000000000000000336621355360272700246270ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CONTEXT_H #define CONTEXT_H #include /******************************************************************************* * Constants that allow assembler code to access members of and the 'gp_regs' * structure at their correct offsets. ******************************************************************************/ #define CTX_GPREGS_OFFSET U(0x0) #define CTX_GPREG_X0 U(0x0) #define CTX_GPREG_X1 U(0x8) #define CTX_GPREG_X2 U(0x10) #define CTX_GPREG_X3 U(0x18) #define CTX_GPREG_X4 U(0x20) #define CTX_GPREG_X5 U(0x28) #define CTX_GPREG_X6 U(0x30) #define CTX_GPREG_X7 U(0x38) #define CTX_GPREG_X8 U(0x40) #define CTX_GPREG_X9 U(0x48) #define CTX_GPREG_X10 U(0x50) #define CTX_GPREG_X11 U(0x58) #define CTX_GPREG_X12 U(0x60) #define CTX_GPREG_X13 U(0x68) #define CTX_GPREG_X14 U(0x70) #define CTX_GPREG_X15 U(0x78) #define CTX_GPREG_X16 U(0x80) #define CTX_GPREG_X17 U(0x88) #define CTX_GPREG_X18 U(0x90) #define CTX_GPREG_X19 U(0x98) #define CTX_GPREG_X20 U(0xa0) #define CTX_GPREG_X21 U(0xa8) #define CTX_GPREG_X22 U(0xb0) #define CTX_GPREG_X23 U(0xb8) #define CTX_GPREG_X24 U(0xc0) #define CTX_GPREG_X25 U(0xc8) #define CTX_GPREG_X26 U(0xd0) #define CTX_GPREG_X27 U(0xd8) #define CTX_GPREG_X28 U(0xe0) #define CTX_GPREG_X29 U(0xe8) #define CTX_GPREG_LR U(0xf0) #define CTX_GPREG_SP_EL0 U(0xf8) #define CTX_GPREGS_END U(0x100) /******************************************************************************* * Constants that allow assembler code to access members of and the 'el3_state' * structure at their correct offsets. Note that some of the registers are only * 32-bits wide but are stored as 64-bit values for convenience ******************************************************************************/ #define CTX_EL3STATE_OFFSET (CTX_GPREGS_OFFSET + CTX_GPREGS_END) #define CTX_SCR_EL3 U(0x0) #define CTX_ESR_EL3 U(0x8) #define CTX_RUNTIME_SP U(0x10) #define CTX_SPSR_EL3 U(0x18) #define CTX_ELR_EL3 U(0x20) #define CTX_PMCR_EL0 U(0x28) #define CTX_EL3STATE_END U(0x30) /******************************************************************************* * Constants that allow assembler code to access members of and the * 'el1_sys_regs' structure at their correct offsets. Note that some of the * registers are only 32-bits wide but are stored as 64-bit values for * convenience ******************************************************************************/ #define CTX_SYSREGS_OFFSET (CTX_EL3STATE_OFFSET + CTX_EL3STATE_END) #define CTX_SPSR_EL1 U(0x0) #define CTX_ELR_EL1 U(0x8) #define CTX_SCTLR_EL1 U(0x10) #define CTX_ACTLR_EL1 U(0x18) #define CTX_CPACR_EL1 U(0x20) #define CTX_CSSELR_EL1 U(0x28) #define CTX_SP_EL1 U(0x30) #define CTX_ESR_EL1 U(0x38) #define CTX_TTBR0_EL1 U(0x40) #define CTX_TTBR1_EL1 U(0x48) #define CTX_MAIR_EL1 U(0x50) #define CTX_AMAIR_EL1 U(0x58) #define CTX_TCR_EL1 U(0x60) #define CTX_TPIDR_EL1 U(0x68) #define CTX_TPIDR_EL0 U(0x70) #define CTX_TPIDRRO_EL0 U(0x78) #define CTX_PAR_EL1 U(0x80) #define CTX_FAR_EL1 U(0x88) #define CTX_AFSR0_EL1 U(0x90) #define CTX_AFSR1_EL1 U(0x98) #define CTX_CONTEXTIDR_EL1 U(0xa0) #define CTX_VBAR_EL1 U(0xa8) /* * If the platform is AArch64-only, there is no need to save and restore these * AArch32 registers. */ #if CTX_INCLUDE_AARCH32_REGS #define CTX_SPSR_ABT U(0xb0) /* Align to the next 16 byte boundary */ #define CTX_SPSR_UND U(0xb8) #define CTX_SPSR_IRQ U(0xc0) #define CTX_SPSR_FIQ U(0xc8) #define CTX_DACR32_EL2 U(0xd0) #define CTX_IFSR32_EL2 U(0xd8) #define CTX_AARCH32_END U(0xe0) /* Align to the next 16 byte boundary */ #else #define CTX_AARCH32_END U(0xb0) /* Align to the next 16 byte boundary */ #endif /* CTX_INCLUDE_AARCH32_REGS */ /* * If the timer registers aren't saved and restored, we don't have to reserve * space for them in the context */ #if NS_TIMER_SWITCH #define CTX_CNTP_CTL_EL0 (CTX_AARCH32_END + U(0x0)) #define CTX_CNTP_CVAL_EL0 (CTX_AARCH32_END + U(0x8)) #define CTX_CNTV_CTL_EL0 (CTX_AARCH32_END + U(0x10)) #define CTX_CNTV_CVAL_EL0 (CTX_AARCH32_END + U(0x18)) #define CTX_CNTKCTL_EL1 (CTX_AARCH32_END + U(0x20)) #define CTX_TIMER_SYSREGS_END (CTX_AARCH32_END + U(0x30)) /* Align to the next 16 byte boundary */ #else #define CTX_TIMER_SYSREGS_END CTX_AARCH32_END #endif /* NS_TIMER_SWITCH */ #if CTX_INCLUDE_MTE_REGS #define CTX_TFSRE0_EL1 (CTX_TIMER_SYSREGS_END + U(0x0)) #define CTX_TFSR_EL1 (CTX_TIMER_SYSREGS_END + U(0x8)) #define CTX_RGSR_EL1 (CTX_TIMER_SYSREGS_END + U(0x10)) #define CTX_GCR_EL1 (CTX_TIMER_SYSREGS_END + U(0x18)) /* Align to the next 16 byte boundary */ #define CTX_MTE_REGS_END (CTX_TIMER_SYSREGS_END + U(0x20)) #else #define CTX_MTE_REGS_END CTX_TIMER_SYSREGS_END #endif /* CTX_INCLUDE_MTE_REGS */ /* * End of system registers. */ #define CTX_SYSREGS_END CTX_MTE_REGS_END /******************************************************************************* * Constants that allow assembler code to access members of and the 'fp_regs' * structure at their correct offsets. ******************************************************************************/ #define CTX_FPREGS_OFFSET (CTX_SYSREGS_OFFSET + CTX_SYSREGS_END) #if CTX_INCLUDE_FPREGS #define CTX_FP_Q0 U(0x0) #define CTX_FP_Q1 U(0x10) #define CTX_FP_Q2 U(0x20) #define CTX_FP_Q3 U(0x30) #define CTX_FP_Q4 U(0x40) #define CTX_FP_Q5 U(0x50) #define CTX_FP_Q6 U(0x60) #define CTX_FP_Q7 U(0x70) #define CTX_FP_Q8 U(0x80) #define CTX_FP_Q9 U(0x90) #define CTX_FP_Q10 U(0xa0) #define CTX_FP_Q11 U(0xb0) #define CTX_FP_Q12 U(0xc0) #define CTX_FP_Q13 U(0xd0) #define CTX_FP_Q14 U(0xe0) #define CTX_FP_Q15 U(0xf0) #define CTX_FP_Q16 U(0x100) #define CTX_FP_Q17 U(0x110) #define CTX_FP_Q18 U(0x120) #define CTX_FP_Q19 U(0x130) #define CTX_FP_Q20 U(0x140) #define CTX_FP_Q21 U(0x150) #define CTX_FP_Q22 U(0x160) #define CTX_FP_Q23 U(0x170) #define CTX_FP_Q24 U(0x180) #define CTX_FP_Q25 U(0x190) #define CTX_FP_Q26 U(0x1a0) #define CTX_FP_Q27 U(0x1b0) #define CTX_FP_Q28 U(0x1c0) #define CTX_FP_Q29 U(0x1d0) #define CTX_FP_Q30 U(0x1e0) #define CTX_FP_Q31 U(0x1f0) #define CTX_FP_FPSR U(0x200) #define CTX_FP_FPCR U(0x208) #if CTX_INCLUDE_AARCH32_REGS #define CTX_FP_FPEXC32_EL2 U(0x210) #define CTX_FPREGS_END U(0x220) /* Align to the next 16 byte boundary */ #else #define CTX_FPREGS_END U(0x210) /* Align to the next 16 byte boundary */ #endif #else #define CTX_FPREGS_END U(0) #endif /******************************************************************************* * Registers related to CVE-2018-3639 ******************************************************************************/ #define CTX_CVE_2018_3639_OFFSET (CTX_FPREGS_OFFSET + CTX_FPREGS_END) #define CTX_CVE_2018_3639_DISABLE U(0) #define CTX_CVE_2018_3639_END U(0x10) /* Align to the next 16 byte boundary */ /******************************************************************************* * Registers related to ARMv8.3-PAuth. ******************************************************************************/ #define CTX_PAUTH_REGS_OFFSET (CTX_CVE_2018_3639_OFFSET + CTX_CVE_2018_3639_END) #if CTX_INCLUDE_PAUTH_REGS #define CTX_PACIAKEY_LO U(0x0) #define CTX_PACIAKEY_HI U(0x8) #define CTX_PACIBKEY_LO U(0x10) #define CTX_PACIBKEY_HI U(0x18) #define CTX_PACDAKEY_LO U(0x20) #define CTX_PACDAKEY_HI U(0x28) #define CTX_PACDBKEY_LO U(0x30) #define CTX_PACDBKEY_HI U(0x38) #define CTX_PACGAKEY_LO U(0x40) #define CTX_PACGAKEY_HI U(0x48) #define CTX_PAUTH_REGS_END U(0x50) /* Align to the next 16 byte boundary */ #else #define CTX_PAUTH_REGS_END U(0) #endif /* CTX_INCLUDE_PAUTH_REGS */ #ifndef __ASSEMBLER__ #include #include /* * Common constants to help define the 'cpu_context' structure and its * members below. */ #define DWORD_SHIFT U(3) #define DEFINE_REG_STRUCT(name, num_regs) \ typedef struct name { \ uint64_t _regs[num_regs]; \ } __aligned(16) name##_t /* Constants to determine the size of individual context structures */ #define CTX_GPREG_ALL (CTX_GPREGS_END >> DWORD_SHIFT) #define CTX_SYSREG_ALL (CTX_SYSREGS_END >> DWORD_SHIFT) #if CTX_INCLUDE_FPREGS # define CTX_FPREG_ALL (CTX_FPREGS_END >> DWORD_SHIFT) #endif #define CTX_EL3STATE_ALL (CTX_EL3STATE_END >> DWORD_SHIFT) #define CTX_CVE_2018_3639_ALL (CTX_CVE_2018_3639_END >> DWORD_SHIFT) #if CTX_INCLUDE_PAUTH_REGS # define CTX_PAUTH_REGS_ALL (CTX_PAUTH_REGS_END >> DWORD_SHIFT) #endif /* * AArch64 general purpose register context structure. Usually x0-x18, * lr are saved as the compiler is expected to preserve the remaining * callee saved registers if used by the C runtime and the assembler * does not touch the remaining. But in case of world switch during * exception handling, we need to save the callee registers too. */ DEFINE_REG_STRUCT(gp_regs, CTX_GPREG_ALL); /* * AArch64 EL1 system register context structure for preserving the * architectural state during switches from one security state to * another in EL1. */ DEFINE_REG_STRUCT(el1_sys_regs, CTX_SYSREG_ALL); /* * AArch64 floating point register context structure for preserving * the floating point state during switches from one security state to * another. */ #if CTX_INCLUDE_FPREGS DEFINE_REG_STRUCT(fp_regs, CTX_FPREG_ALL); #endif /* * Miscellaneous registers used by EL3 firmware to maintain its state * across exception entries and exits */ DEFINE_REG_STRUCT(el3_state, CTX_EL3STATE_ALL); /* Function pointer used by CVE-2018-3639 dynamic mitigation */ DEFINE_REG_STRUCT(cve_2018_3639, CTX_CVE_2018_3639_ALL); /* Registers associated to ARMv8.3-PAuth */ #if CTX_INCLUDE_PAUTH_REGS DEFINE_REG_STRUCT(pauth, CTX_PAUTH_REGS_ALL); #endif /* * Macros to access members of any of the above structures using their * offsets */ #define read_ctx_reg(ctx, offset) ((ctx)->_regs[(offset) >> DWORD_SHIFT]) #define write_ctx_reg(ctx, offset, val) (((ctx)->_regs[(offset) >> DWORD_SHIFT]) \ = (uint64_t) (val)) /* * Top-level context structure which is used by EL3 firmware to * preserve the state of a core at EL1 in one of the two security * states and save enough EL3 meta data to be able to return to that * EL and security state. The context management library will be used * to ensure that SP_EL3 always points to an instance of this * structure at exception entry and exit. Each instance will * correspond to either the secure or the non-secure state. */ typedef struct cpu_context { gp_regs_t gpregs_ctx; el3_state_t el3state_ctx; el1_sys_regs_t sysregs_ctx; #if CTX_INCLUDE_FPREGS fp_regs_t fpregs_ctx; #endif cve_2018_3639_t cve_2018_3639_ctx; #if CTX_INCLUDE_PAUTH_REGS pauth_t pauth_ctx; #endif } cpu_context_t; /* Macros to access members of the 'cpu_context_t' structure */ #define get_el3state_ctx(h) (&((cpu_context_t *) h)->el3state_ctx) #if CTX_INCLUDE_FPREGS # define get_fpregs_ctx(h) (&((cpu_context_t *) h)->fpregs_ctx) #endif #define get_sysregs_ctx(h) (&((cpu_context_t *) h)->sysregs_ctx) #define get_gpregs_ctx(h) (&((cpu_context_t *) h)->gpregs_ctx) #define get_cve_2018_3639_ctx(h) (&((cpu_context_t *) h)->cve_2018_3639_ctx) #if CTX_INCLUDE_PAUTH_REGS # define get_pauth_ctx(h) (&((cpu_context_t *) h)->pauth_ctx) #endif /* * Compile time assertions related to the 'cpu_context' structure to * ensure that the assembler and the compiler view of the offsets of * the structure members is the same. */ CASSERT(CTX_GPREGS_OFFSET == __builtin_offsetof(cpu_context_t, gpregs_ctx), \ assert_core_context_gp_offset_mismatch); CASSERT(CTX_SYSREGS_OFFSET == __builtin_offsetof(cpu_context_t, sysregs_ctx), \ assert_core_context_sys_offset_mismatch); #if CTX_INCLUDE_FPREGS CASSERT(CTX_FPREGS_OFFSET == __builtin_offsetof(cpu_context_t, fpregs_ctx), \ assert_core_context_fp_offset_mismatch); #endif CASSERT(CTX_EL3STATE_OFFSET == __builtin_offsetof(cpu_context_t, el3state_ctx), \ assert_core_context_el3state_offset_mismatch); CASSERT(CTX_CVE_2018_3639_OFFSET == __builtin_offsetof(cpu_context_t, cve_2018_3639_ctx), \ assert_core_context_cve_2018_3639_offset_mismatch); #if CTX_INCLUDE_PAUTH_REGS CASSERT(CTX_PAUTH_REGS_OFFSET == __builtin_offsetof(cpu_context_t, pauth_ctx), \ assert_core_context_pauth_offset_mismatch); #endif /* * Helper macro to set the general purpose registers that correspond to * parameters in an aapcs_64 call i.e. x0-x7 */ #define set_aapcs_args0(ctx, x0) do { \ write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X0, x0); \ } while (0) #define set_aapcs_args1(ctx, x0, x1) do { \ write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X1, x1); \ set_aapcs_args0(ctx, x0); \ } while (0) #define set_aapcs_args2(ctx, x0, x1, x2) do { \ write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X2, x2); \ set_aapcs_args1(ctx, x0, x1); \ } while (0) #define set_aapcs_args3(ctx, x0, x1, x2, x3) do { \ write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X3, x3); \ set_aapcs_args2(ctx, x0, x1, x2); \ } while (0) #define set_aapcs_args4(ctx, x0, x1, x2, x3, x4) do { \ write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X4, x4); \ set_aapcs_args3(ctx, x0, x1, x2, x3); \ } while (0) #define set_aapcs_args5(ctx, x0, x1, x2, x3, x4, x5) do { \ write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X5, x5); \ set_aapcs_args4(ctx, x0, x1, x2, x3, x4); \ } while (0) #define set_aapcs_args6(ctx, x0, x1, x2, x3, x4, x5, x6) do { \ write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X6, x6); \ set_aapcs_args5(ctx, x0, x1, x2, x3, x4, x5); \ } while (0) #define set_aapcs_args7(ctx, x0, x1, x2, x3, x4, x5, x6, x7) do { \ write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_X7, x7); \ set_aapcs_args6(ctx, x0, x1, x2, x3, x4, x5, x6); \ } while (0) /******************************************************************************* * Function prototypes ******************************************************************************/ void el1_sysregs_context_save(el1_sys_regs_t *regs); void el1_sysregs_context_restore(el1_sys_regs_t *regs); #if CTX_INCLUDE_FPREGS void fpregs_context_save(fp_regs_t *regs); void fpregs_context_restore(fp_regs_t *regs); #endif #endif /* __ASSEMBLER__ */ #endif /* CONTEXT_H */ trusted-firmware-a-2.2/include/lib/el3_runtime/context_mgmt.h000066400000000000000000000052141355360272700244130ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CONTEXT_MGMT_H #define CONTEXT_MGMT_H #include #include #include #include /******************************************************************************* * Forward declarations ******************************************************************************/ struct entry_point_info; /******************************************************************************* * Function & variable prototypes ******************************************************************************/ void cm_init(void); void *cm_get_context_by_index(unsigned int cpu_idx, unsigned int security_state); void cm_set_context_by_index(unsigned int cpu_idx, void *context, unsigned int security_state); void *cm_get_context(uint32_t security_state); void cm_set_context(void *context, uint32_t security_state); void cm_init_my_context(const struct entry_point_info *ep); void cm_init_context_by_index(unsigned int cpu_idx, const struct entry_point_info *ep); void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep); void cm_prepare_el3_exit(uint32_t security_state); #ifdef __aarch64__ void cm_el1_sysregs_context_save(uint32_t security_state); void cm_el1_sysregs_context_restore(uint32_t security_state); void cm_set_elr_el3(uint32_t security_state, uintptr_t entrypoint); void cm_set_elr_spsr_el3(uint32_t security_state, uintptr_t entrypoint, uint32_t spsr); void cm_write_scr_el3_bit(uint32_t security_state, uint32_t bit_pos, uint32_t value); void cm_set_next_eret_context(uint32_t security_state); uint32_t cm_get_scr_el3(uint32_t security_state); /* Inline definitions */ /******************************************************************************* * This function is used to program the context that's used for exception * return. This initializes the SP_EL3 to a pointer to a 'cpu_context' set for * the required security state ******************************************************************************/ static inline void cm_set_next_context(void *context) { #if ENABLE_ASSERTIONS uint64_t sp_mode; /* * Check that this function is called with SP_EL0 as the stack * pointer */ __asm__ volatile("mrs %0, SPSel\n" : "=r" (sp_mode)); assert(sp_mode == MODE_SP_EL0); #endif /* ENABLE_ASSERTIONS */ __asm__ volatile("msr spsel, #1\n" "mov sp, %0\n" "msr spsel, #0\n" : : "r" (context)); } #else void *cm_get_next_context(void); void cm_set_next_context(void *context); #endif /* __aarch64__ */ #endif /* CONTEXT_MGMT_H */ trusted-firmware-a-2.2/include/lib/el3_runtime/cpu_data.h000066400000000000000000000133121355360272700234610ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CPU_DATA_H #define CPU_DATA_H #include /* CACHE_WRITEBACK_GRANULE required */ #include /* Size of psci_cpu_data structure */ #define PSCI_CPU_DATA_SIZE 12 #ifdef __aarch64__ /* 8-bytes aligned size of psci_cpu_data structure */ #define PSCI_CPU_DATA_SIZE_ALIGNED ((PSCI_CPU_DATA_SIZE + 7) & ~7) /* Offset of cpu_ops_ptr, size 8 bytes */ #define CPU_DATA_CPU_OPS_PTR 0x10 #if ENABLE_PAUTH /* 8-bytes aligned offset of apiakey[2], size 16 bytes */ #define CPU_DATA_APIAKEY_OFFSET (0x18 + PSCI_CPU_DATA_SIZE_ALIGNED) #define CPU_DATA_CRASH_BUF_OFFSET (CPU_DATA_APIAKEY_OFFSET + 0x10) #else #define CPU_DATA_CRASH_BUF_OFFSET (0x18 + PSCI_CPU_DATA_SIZE_ALIGNED) #endif /* ENABLE_PAUTH */ /* need enough space in crash buffer to save 8 registers */ #define CPU_DATA_CRASH_BUF_SIZE 64 #else /* !__aarch64__ */ #if CRASH_REPORTING #error "Crash reporting is not supported in AArch32" #endif #define CPU_DATA_CPU_OPS_PTR 0x0 #define CPU_DATA_CRASH_BUF_OFFSET (0x4 + PSCI_CPU_DATA_SIZE) #endif /* __aarch64__ */ #if CRASH_REPORTING #define CPU_DATA_CRASH_BUF_END (CPU_DATA_CRASH_BUF_OFFSET + \ CPU_DATA_CRASH_BUF_SIZE) #else #define CPU_DATA_CRASH_BUF_END CPU_DATA_CRASH_BUF_OFFSET #endif /* cpu_data size is the data size rounded up to the platform cache line size */ #define CPU_DATA_SIZE (((CPU_DATA_CRASH_BUF_END + \ CACHE_WRITEBACK_GRANULE - 1) / \ CACHE_WRITEBACK_GRANULE) * \ CACHE_WRITEBACK_GRANULE) #if ENABLE_RUNTIME_INSTRUMENTATION /* Temporary space to store PMF timestamps from assembly code */ #define CPU_DATA_PMF_TS_COUNT 1 #define CPU_DATA_PMF_TS0_OFFSET CPU_DATA_CRASH_BUF_END #define CPU_DATA_PMF_TS0_IDX 0 #endif #ifndef __ASSEMBLER__ #include #include #include #include #include /* Offsets for the cpu_data structure */ #define CPU_DATA_PSCI_LOCK_OFFSET __builtin_offsetof\ (cpu_data_t, psci_svc_cpu_data.pcpu_bakery_info) #if PLAT_PCPU_DATA_SIZE #define CPU_DATA_PLAT_PCPU_OFFSET __builtin_offsetof\ (cpu_data_t, platform_cpu_data) #endif /******************************************************************************* * Function & variable prototypes ******************************************************************************/ /******************************************************************************* * Cache of frequently used per-cpu data: * Pointers to non-secure and secure security state contexts * Address of the crash stack * It is aligned to the cache line boundary to allow efficient concurrent * manipulation of these pointers on different cpus * * TODO: Add other commonly used variables to this (tf_issues#90) * * The data structure and the _cpu_data accessors should not be used directly * by components that have per-cpu members. The member access macros should be * used for this. ******************************************************************************/ typedef struct cpu_data { #ifdef __aarch64__ void *cpu_context[2]; #endif uintptr_t cpu_ops_ptr; struct psci_cpu_data psci_svc_cpu_data; #if ENABLE_PAUTH uint64_t apiakey[2]; #endif #if CRASH_REPORTING u_register_t crash_buf[CPU_DATA_CRASH_BUF_SIZE >> 3]; #endif #if ENABLE_RUNTIME_INSTRUMENTATION uint64_t cpu_data_pmf_ts[CPU_DATA_PMF_TS_COUNT]; #endif #if PLAT_PCPU_DATA_SIZE uint8_t platform_cpu_data[PLAT_PCPU_DATA_SIZE]; #endif #if defined(IMAGE_BL31) && EL3_EXCEPTION_HANDLING pe_exc_data_t ehf_data; #endif } __aligned(CACHE_WRITEBACK_GRANULE) cpu_data_t; extern cpu_data_t percpu_data[PLATFORM_CORE_COUNT]; #if ENABLE_PAUTH CASSERT(CPU_DATA_APIAKEY_OFFSET == __builtin_offsetof (cpu_data_t, apiakey), assert_cpu_data_crash_stack_offset_mismatch); #endif #if CRASH_REPORTING /* verify assembler offsets match data structures */ CASSERT(CPU_DATA_CRASH_BUF_OFFSET == __builtin_offsetof (cpu_data_t, crash_buf), assert_cpu_data_crash_stack_offset_mismatch); #endif CASSERT(CPU_DATA_SIZE == sizeof(cpu_data_t), assert_cpu_data_size_mismatch); CASSERT(CPU_DATA_CPU_OPS_PTR == __builtin_offsetof (cpu_data_t, cpu_ops_ptr), assert_cpu_data_cpu_ops_ptr_offset_mismatch); #if ENABLE_RUNTIME_INSTRUMENTATION CASSERT(CPU_DATA_PMF_TS0_OFFSET == __builtin_offsetof (cpu_data_t, cpu_data_pmf_ts[0]), assert_cpu_data_pmf_ts0_offset_mismatch); #endif struct cpu_data *_cpu_data_by_index(uint32_t cpu_index); #ifdef __aarch64__ /* Return the cpu_data structure for the current CPU. */ static inline struct cpu_data *_cpu_data(void) { return (cpu_data_t *)read_tpidr_el3(); } #else struct cpu_data *_cpu_data(void); #endif /************************************************************************** * APIs for initialising and accessing per-cpu data *************************************************************************/ void init_cpu_data_ptr(void); void init_cpu_ops(void); #define get_cpu_data(_m) _cpu_data()->_m #define set_cpu_data(_m, _v) _cpu_data()->_m = (_v) #define get_cpu_data_by_index(_ix, _m) _cpu_data_by_index(_ix)->_m #define set_cpu_data_by_index(_ix, _m, _v) _cpu_data_by_index(_ix)->_m = (_v) /* ((cpu_data_t *)0)->_m is a dummy to get the sizeof the struct member _m */ #define flush_cpu_data(_m) flush_dcache_range((uintptr_t) \ &(_cpu_data()->_m), \ sizeof(((cpu_data_t *)0)->_m)) #define inv_cpu_data(_m) inv_dcache_range((uintptr_t) \ &(_cpu_data()->_m), \ sizeof(((cpu_data_t *)0)->_m)) #define flush_cpu_data_by_index(_ix, _m) \ flush_dcache_range((uintptr_t) \ &(_cpu_data_by_index(_ix)->_m), \ sizeof(((cpu_data_t *)0)->_m)) #endif /* __ASSEMBLER__ */ #endif /* CPU_DATA_H */ trusted-firmware-a-2.2/include/lib/el3_runtime/pubsub.h000066400000000000000000000060471355360272700232100ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PUBSUB_H #define PUBSUB_H #ifdef __LINKER__ /* For the linker ... */ #define __pubsub_start_sym(event) __pubsub_##event##_start #define __pubsub_end_sym(event) __pubsub_##event##_end #define __pubsub_section(event) __pubsub_##event /* * REGISTER_PUBSUB_EVENT has a different definition between linker and compiler * contexts. In linker context, this collects pubsub sections for each event, * placing guard symbols around each. */ #if defined(USE_ARM_LINK) #define REGISTER_PUBSUB_EVENT(event) \ __pubsub_start_sym(event) +0 FIXED \ { \ *(__pubsub_section(event)) \ } \ __pubsub_end_sym(event) +0 FIXED EMPTY 0 \ { \ /* placeholder */ \ } #else #define REGISTER_PUBSUB_EVENT(event) \ __pubsub_start_sym(event) = .; \ KEEP(*(__pubsub_section(event))); \ __pubsub_end_sym(event) = . #endif #else /* __LINKER__ */ /* For the compiler ... */ #include #include #include #include #if defined(USE_ARM_LINK) #define __pubsub_start_sym(event) Load$$__pubsub_##event##_start$$Base #define __pubsub_end_sym(event) Load$$__pubsub_##event##_end$$Base #else #define __pubsub_start_sym(event) __pubsub_##event##_start #define __pubsub_end_sym(event) __pubsub_##event##_end #endif #define __pubsub_section(event) __section("__pubsub_" #event) /* * In compiler context, REGISTER_PUBSUB_EVENT declares the per-event symbols * exported by the linker required for the other pubsub macros to work. */ #define REGISTER_PUBSUB_EVENT(event) \ extern pubsub_cb_t __pubsub_start_sym(event)[]; \ extern pubsub_cb_t __pubsub_end_sym(event)[] /* * Have the function func called back when the specified event happens. This * macro places the function address into the pubsub section, which is picked up * and invoked by the invoke_pubsubs() function via the PUBLISH_EVENT* macros. * * The extern declaration is there to satisfy MISRA C-2012 rule 8.4. */ #define SUBSCRIBE_TO_EVENT(event, func) \ extern pubsub_cb_t __cb_func_##func##event __pubsub_section(event); \ pubsub_cb_t __cb_func_##func##event __pubsub_section(event) = (func) /* * Iterate over subscribed handlers for a defined event. 'event' is the name of * the event, and 'subscriber' a local variable of type 'pubsub_cb_t *'. */ #define for_each_subscriber(event, subscriber) \ for (subscriber = __pubsub_start_sym(event); \ subscriber < __pubsub_end_sym(event); \ subscriber++) /* * Publish a defined event supplying an argument. All subscribed handlers are * invoked, but the return value of handlers are ignored for now. */ #define PUBLISH_EVENT_ARG(event, arg) \ do { \ pubsub_cb_t *subscriber; \ for_each_subscriber(event, subscriber) { \ (*subscriber)(arg); \ } \ } while (0) /* Publish a defined event with NULL argument */ #define PUBLISH_EVENT(event) PUBLISH_EVENT_ARG(event, NULL) /* Subscriber callback type */ typedef void* (*pubsub_cb_t)(const void *arg); #endif /* __LINKER__ */ #endif /* PUBSUB_H */ trusted-firmware-a-2.2/include/lib/el3_runtime/pubsub_events.h000066400000000000000000000023011355360272700245610ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* * This file defines a list of pubsub events, declared using * REGISTER_PUBSUB_EVENT() macro. */ /* * Event published after a CPU has been powered up and finished its * initialization. */ REGISTER_PUBSUB_EVENT(psci_cpu_on_finish); /* * These events are published before/after a CPU has been powered down/up * via the PSCI CPU SUSPEND API. */ REGISTER_PUBSUB_EVENT(psci_suspend_pwrdown_start); REGISTER_PUBSUB_EVENT(psci_suspend_pwrdown_finish); #ifdef __aarch64__ /* * These events are published by the AArch64 context management framework * after the secure context is restored/saved via * cm_el1_sysregs_context_{restore,save}() API. */ REGISTER_PUBSUB_EVENT(cm_entering_secure_world); REGISTER_PUBSUB_EVENT(cm_exited_secure_world); /* * These events are published by the AArch64 context management framework * after the normal context is restored/saved via * cm_el1_sysregs_context_{restore,save}() API. */ REGISTER_PUBSUB_EVENT(cm_entering_normal_world); REGISTER_PUBSUB_EVENT(cm_exited_normal_world); #endif /* __aarch64__ */ trusted-firmware-a-2.2/include/lib/extensions/000077500000000000000000000000001355360272700215015ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/extensions/amu.h000066400000000000000000000022421355360272700224340ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef AMU_H #define AMU_H #include #include #include #include #include /* All group 0 counters */ #define AMU_GROUP0_COUNTERS_MASK U(0xf) #ifdef PLAT_AMU_GROUP1_COUNTERS_MASK #define AMU_GROUP1_COUNTERS_MASK PLAT_AMU_GROUP1_COUNTERS_MASK #else #define AMU_GROUP1_COUNTERS_MASK U(0) #endif #ifdef PLAT_AMU_GROUP1_NR_COUNTERS #define AMU_GROUP1_NR_COUNTERS PLAT_AMU_GROUP1_NR_COUNTERS #else #define AMU_GROUP1_NR_COUNTERS U(0) #endif CASSERT(AMU_GROUP1_COUNTERS_MASK <= 0xffff, invalid_amu_group1_counters_mask); CASSERT(AMU_GROUP1_NR_COUNTERS <= 16, invalid_amu_group1_nr_counters); bool amu_supported(void); void amu_enable(bool el2_unused); /* Group 0 configuration helpers */ uint64_t amu_group0_cnt_read(int idx); void amu_group0_cnt_write(int idx, uint64_t val); /* Group 1 configuration helpers */ uint64_t amu_group1_cnt_read(int idx); void amu_group1_cnt_write(int idx, uint64_t val); void amu_group1_set_evtype(int idx, unsigned int val); #endif /* AMU_H */ trusted-firmware-a-2.2/include/lib/extensions/amu_private.h000066400000000000000000000007701355360272700241720ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef AMU_PRIVATE_H #define AMU_PRIVATE_H #include uint64_t amu_group0_cnt_read_internal(int idx); void amu_group0_cnt_write_internal(int idx, uint64_t val); uint64_t amu_group1_cnt_read_internal(int idx); void amu_group1_cnt_write_internal(int idx, uint64_t val); void amu_group1_set_evtype_internal(int idx, unsigned int val); #endif /* AMU_PRIVATE_H */ trusted-firmware-a-2.2/include/lib/extensions/mpam.h000066400000000000000000000004061355360272700226040ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MPAM_H #define MPAM_H #include bool mpam_supported(void); void mpam_enable(bool el2_unused); #endif /* MPAM_H */ trusted-firmware-a-2.2/include/lib/extensions/pauth.h000066400000000000000000000007571355360272700230040ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PAUTH_H #define PAUTH_H /******************************************************************************* * ARMv8.3-PAuth support functions ******************************************************************************/ /* Disable ARMv8.3 pointer authentication in EL1/EL3 */ void pauth_disable_el1(void); void pauth_disable_el3(void); #endif /* PAUTH_H */ trusted-firmware-a-2.2/include/lib/extensions/ras.h000066400000000000000000000121051355360272700224360ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RAS_H #define RAS_H #define ERR_HANDLER_VERSION 1U /* Error record access mechanism */ #define ERR_ACCESS_SYSREG 0 #define ERR_ACCESS_MEMMAP 1 /* * Register all error records on the platform. * * This macro must be used in the same file as the array of error record info * are declared. Only then would ARRAY_SIZE() yield a meaningful value. */ #define REGISTER_ERR_RECORD_INFO(_records) \ const struct err_record_mapping err_record_mappings = { \ .err_records = (_records), \ .num_err_records = ARRAY_SIZE(_records), \ } /* Error record info iterator */ #define for_each_err_record_info(_i, _info) \ for ((_i) = 0, (_info) = err_record_mappings.err_records; \ (_i) < err_record_mappings.num_err_records; \ (_i)++, (_info)++) #define ERR_RECORD_COMMON_(_probe, _handler, _aux) \ .probe = _probe, \ .handler = _handler, \ .aux_data = _aux, #define ERR_RECORD_SYSREG_V1(_idx_start, _num_idx, _probe, _handler, _aux) \ { \ .version = 1, \ .sysreg.idx_start = _idx_start, \ .sysreg.num_idx = _num_idx, \ .access = ERR_ACCESS_SYSREG, \ ERR_RECORD_COMMON_(_probe, _handler, _aux) \ } #define ERR_RECORD_MEMMAP_V1(_base_addr, _size_num_k, _probe, _handler, _aux) \ { \ .version = 1, \ .memmap.base_addr = _base_addr, \ .memmap.size_num_k = _size_num_k, \ .access = ERR_ACCESS_MEMMAP, \ ERR_RECORD_COMMON_(_probe, _handler, _aux) \ } /* * Macro to be used to name and declare an array of RAS interrupts along with * their handlers. * * This macro must be used in the same file as the array of interrupts are * declared. Only then would ARRAY_SIZE() yield a meaningful value. Also, the * array is expected to be sorted in the increasing order of interrupt number. */ #define REGISTER_RAS_INTERRUPTS(_array) \ const struct ras_interrupt_mapping ras_interrupt_mappings = { \ .intrs = (_array), \ .num_intrs = ARRAY_SIZE(_array), \ } #ifndef __ASSEMBLER__ #include #include struct err_record_info; struct ras_interrupt { /* Interrupt number, and the associated error record info */ unsigned int intr_number; struct err_record_info *err_record; void *cookie; }; /* Function to probe a error record group for error */ typedef int (*err_record_probe_t)(const struct err_record_info *info, int *probe_data); /* Data passed to error record group handler */ struct err_handler_data { /* Info passed on from top-level exception handler */ uint64_t flags; void *cookie; void *handle; /* Data structure version */ unsigned int version; /* Reason for EA: one the ERROR_* constants */ unsigned int ea_reason; /* * For EAs received at vector, the value read from ESR; for an EA * synchronized by ESB, the value of DISR. */ uint32_t syndrome; /* For errors signalled via interrupt, the raw interrupt ID; otherwise, 0. */ unsigned int interrupt; }; /* Function to handle error from an error record group */ typedef int (*err_record_handler_t)(const struct err_record_info *info, int probe_data, const struct err_handler_data *const data); /* Error record information */ struct err_record_info { /* Function to probe error record group for errors */ err_record_probe_t probe; /* Function to handle error record group errors */ err_record_handler_t handler; /* Opaque group-specific data */ void *aux_data; /* Additional information for Standard Error Records */ union { struct { /* * For a group accessed via memory-mapped register, * base address of the page hosting error records, and * the size of the record group. */ uintptr_t base_addr; /* Size of group in number of KBs */ unsigned int size_num_k; } memmap; struct { /* * For error records accessed via system register, index of * the error record. */ unsigned int idx_start; unsigned int num_idx; } sysreg; }; /* Data structure version */ unsigned int version; /* Error record access mechanism */ unsigned int access:1; }; struct err_record_mapping { struct err_record_info *err_records; size_t num_err_records; }; struct ras_interrupt_mapping { struct ras_interrupt *intrs; size_t num_intrs; }; extern const struct err_record_mapping err_record_mappings; extern const struct ras_interrupt_mapping ras_interrupt_mappings; /* * Helper functions to probe memory-mapped and system registers implemented in * Standard Error Record format */ static inline int ras_err_ser_probe_memmap(const struct err_record_info *info, int *probe_data) { assert(info->version == ERR_HANDLER_VERSION); return ser_probe_memmap(info->memmap.base_addr, info->memmap.size_num_k, probe_data); } static inline int ras_err_ser_probe_sysreg(const struct err_record_info *info, int *probe_data) { assert(info->version == ERR_HANDLER_VERSION); return ser_probe_sysreg(info->sysreg.idx_start, info->sysreg.num_idx, probe_data); } int ras_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie, void *handle, uint64_t flags); void ras_init(void); #endif /* __ASSEMBLER__ */ #endif /* RAS_H */ trusted-firmware-a-2.2/include/lib/extensions/ras_arch.h000066400000000000000000000163641355360272700234460ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RAS_ARCH_H #define RAS_ARCH_H /* * Size of nodes implementing Standard Error Records - currently only 4k is * supported. */ #define STD_ERR_NODE_SIZE_NUM_K 4U /* * Individual register offsets within an error record in Standard Error Record * format when error records are accessed through memory-mapped registers. */ #define ERR_FR(n) (0x0ULL + (64ULL * (n))) #define ERR_CTLR(n) (0x8ULL + (64ULL * (n))) #define ERR_STATUS(n) (0x10ULL + (64ULL * (n))) #define ERR_ADDR(n) (0x18ULL + (64ULL * (n))) #define ERR_MISC0(n) (0x20ULL + (64ULL * (n))) #define ERR_MISC1(n) (0x28ULL + (64ULL * (n))) /* Group Status Register (ERR_STATUS) offset */ #define ERR_GSR(base, size_num_k, n) \ ((base) + (0x380ULL * (size_num_k)) + (8ULL * (n))) /* Management register offsets */ #define ERR_DEVID(base, size_num_k) \ ((base) + ((0x400ULL * (size_num_k)) - 0x100ULL) + 0xc8ULL) #define ERR_DEVID_MASK 0xffffUL /* Standard Error Record status register fields */ #define ERR_STATUS_AV_SHIFT 31 #define ERR_STATUS_AV_MASK U(0x1) #define ERR_STATUS_V_SHIFT 30 #define ERR_STATUS_V_MASK U(0x1) #define ERR_STATUS_UE_SHIFT 29 #define ERR_STATUS_UE_MASK U(0x1) #define ERR_STATUS_ER_SHIFT 28 #define ERR_STATUS_ER_MASK U(0x1) #define ERR_STATUS_OF_SHIFT 27 #define ERR_STATUS_OF_MASK U(0x1) #define ERR_STATUS_MV_SHIFT 26 #define ERR_STATUS_MV_MASK U(0x1) #define ERR_STATUS_CE_SHIFT 24 #define ERR_STATUS_CE_MASK U(0x3) #define ERR_STATUS_DE_SHIFT 23 #define ERR_STATUS_DE_MASK U(0x1) #define ERR_STATUS_PN_SHIFT 22 #define ERR_STATUS_PN_MASK U(0x1) #define ERR_STATUS_UET_SHIFT 20 #define ERR_STATUS_UET_MASK U(0x3) #define ERR_STATUS_IERR_SHIFT 8 #define ERR_STATUS_IERR_MASK U(0xff) #define ERR_STATUS_SERR_SHIFT 0 #define ERR_STATUS_SERR_MASK U(0xff) #define ERR_STATUS_GET_FIELD(_status, _field) \ (((_status) >> ERR_STATUS_ ##_field ##_SHIFT) & ERR_STATUS_ ##_field ##_MASK) #define ERR_STATUS_CLR_FIELD(_status, _field) \ (_status) &= ~(ERR_STATUS_ ##_field ##_MASK << ERR_STATUS_ ##_field ##_SHIFT) #define ERR_STATUS_SET_FIELD(_status, _field, _value) \ (_status) |= (((_value) & ERR_STATUS_ ##_field ##_MASK) << ERR_STATUS_ ##_field ##_SHIFT) #define ERR_STATUS_WRITE_FIELD(_status, _field, _value) do { \ ERR_STATUS_CLR_FIELD(_status, _field, _value); \ ERR_STATUS_SET_FIELD(_status, _field, _value); \ } while (0) /* Standard Error Record control register fields */ #define ERR_CTLR_WDUI_SHIFT 11 #define ERR_CTLR_WDUI_MASK 0x1 #define ERR_CTLR_RDUI_SHIFT 10 #define ERR_CTLR_RDUI_MASK 0x1 #define ERR_CTLR_DUI_SHIFT ERR_CTLR_RDUI_SHIFT #define ERR_CTLR_DUI_MASK ERR_CTLR_RDUI_MASK #define ERR_CTLR_WCFI_SHIFT 9 #define ERR_CTLR_WCFI_MASK 0x1 #define ERR_CTLR_RCFI_SHIFT 8 #define ERR_CTLR_RCFI_MASK 0x1 #define ERR_CTLR_CFI_SHIFT ERR_CTLR_RCFI_SHIFT #define ERR_CTLR_CFI_MASK ERR_CTLR_RCFI_MASK #define ERR_CTLR_WUE_SHIFT 7 #define ERR_CTLR_WUE_MASK 0x1 #define ERR_CTLR_WFI_SHIFT 6 #define ERR_CTLR_WFI_MASK 0x1 #define ERR_CTLR_WUI_SHIFT 5 #define ERR_CTLR_WUI_MASK 0x1 #define ERR_CTLR_RUE_SHIFT 4 #define ERR_CTLR_RUE_MASK 0x1 #define ERR_CTLR_UE_SHIFT ERR_CTLR_RUE_SHIFT #define ERR_CTLR_UE_MASK ERR_CTLR_RUE_MASK #define ERR_CTLR_RFI_SHIFT 3 #define ERR_CTLR_RFI_MASK 0x1 #define ERR_CTLR_FI_SHIFT ERR_CTLR_RFI_SHIFT #define ERR_CTLR_FI_MASK ERR_CTLR_RFI_MASK #define ERR_CTLR_RUI_SHIFT 2 #define ERR_CTLR_RUI_MASK 0x1 #define ERR_CTLR_UI_SHIFT ERR_CTLR_RUI_SHIFT #define ERR_CTLR_UI_MASK ERR_CTLR_RUI_MASK #define ERR_CTLR_ED_SHIFT 0 #define ERR_CTLR_ED_MASK 0x1 #define ERR_CTLR_CLR_FIELD(_ctlr, _field) \ (_ctlr) &= ~(ERR_CTLR_ ##_field _MASK << ERR_CTLR_ ##_field ##_SHIFT) #define ERR_CTLR_SET_FIELD(_ctlr, _field, _value) \ (_ctlr) |= (((_value) & ERR_CTLR_ ##_field ##_MASK) << ERR_CTLR_ ##_field ##_SHIFT) #define ERR_CTLR_ENABLE_FIELD(_ctlr, _field) \ ERR_CTLR_SET_FIELD(_ctlr, _field, ERR_CTLR_ ##_field ##_MASK) /* Uncorrected error types for Asynchronous exceptions */ #define ERROR_STATUS_UET_UC 0x0 /* Uncontainable */ #define ERROR_STATUS_UET_UEU 0x1 /* Unrecoverable */ #define ERROR_STATUS_UET_UEO 0x2 /* Restable */ #define ERROR_STATUS_UET_UER 0x3 /* Recoverable */ /* Error types for Synchronous exceptions */ #define ERROR_STATUS_SET_UER 0x0 /* Recoverable */ #define ERROR_STATUS_SET_UEO 0x1 /* Restable */ #define ERROR_STATUS_SET_UC 0x2 /* Uncontainable */ #define ERROR_STATUS_SET_CE 0x3 /* Corrected */ /* Implementation Defined Syndrome bit in ESR */ #define SERROR_IDS_BIT U(24) /* * Asynchronous Error Type in exception syndrome. The field has same values in * both DISR_EL1 and ESR_EL3 for SError. */ #define EABORT_AET_SHIFT U(10) #define EABORT_AET_WIDTH U(3) #define EABORT_AET_MASK U(0x7) /* DFSC field in Asynchronous exception syndrome */ #define EABORT_DFSC_SHIFT U(0) #define EABORT_DFSC_WIDTH U(6) #define EABORT_DFSC_MASK U(0x3f) /* Synchronous Error Type in exception syndrome. */ #define EABORT_SET_SHIFT U(11) #define EABORT_SET_WIDTH U(2) #define EABORT_SET_MASK U(0x3) /* DFSC code for SErrors */ #define DFSC_SERROR 0x11 /* I/DFSC code for synchronous external abort */ #define SYNC_EA_FSC 0x10 #ifndef __ASSEMBLER__ #include #include #include #include #include #include /* * Standard Error Record accessors for memory-mapped registers. */ static inline uint64_t ser_get_feature(uintptr_t base, unsigned int idx) { return mmio_read_64(base + ERR_FR(idx)); } static inline uint64_t ser_get_control(uintptr_t base, unsigned int idx) { return mmio_read_64(base + ERR_CTLR(idx)); } static inline uint64_t ser_get_status(uintptr_t base, unsigned int idx) { return mmio_read_64(base + ERR_STATUS(idx)); } /* * Error handling agent would write to the status register to clear an * identified/handled error. Most fields in the status register are * conditional write-one-to-clear. * * Typically, to clear the status, it suffices to write back the same value * previously read. However, if there were new, higher-priority errors recorded * on the node since status was last read, writing read value won't clear the * status. Therefore, an error handling agent must wait on and verify the status * has indeed been cleared. */ static inline void ser_set_status(uintptr_t base, unsigned int idx, uint64_t status) { mmio_write_64(base + ERR_STATUS(idx), status); } static inline uint64_t ser_get_addr(uintptr_t base, unsigned int idx) { return mmio_read_64(base + ERR_ADDR(idx)); } static inline uint64_t ser_get_misc0(uintptr_t base, unsigned int idx) { return mmio_read_64(base + ERR_MISC0(idx)); } static inline uint64_t ser_get_misc1(uintptr_t base, unsigned int idx) { return mmio_read_64(base + ERR_MISC1(idx)); } /* * Standard Error Record helpers for System registers. */ static inline void ser_sys_select_record(unsigned int idx) { unsigned int max_idx __unused = (unsigned int) read_erridr_el1() & ERRIDR_MASK; assert(idx < max_idx); write_errselr_el1(idx); isb(); } /* Library functions to probe Standard Error Record */ int ser_probe_memmap(uintptr_t base, unsigned int size_num_k, int *probe_data); int ser_probe_sysreg(unsigned int idx_start, unsigned int num_idx, int *probe_data); #endif /* __ASSEMBLER__ */ #endif /* RAS_ARCH_H */ trusted-firmware-a-2.2/include/lib/extensions/spe.h000066400000000000000000000004361355360272700224440ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPE_H #define SPE_H #include bool spe_supported(void); void spe_enable(bool el2_unused); void spe_disable(void); #endif /* SPE_H */ trusted-firmware-a-2.2/include/lib/extensions/sve.h000066400000000000000000000004061355360272700224470ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SVE_H #define SVE_H #include bool sve_supported(void); void sve_enable(bool el2_unused); #endif /* SVE_H */ trusted-firmware-a-2.2/include/lib/libc/000077500000000000000000000000001355360272700202135ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/libc/aarch32/000077500000000000000000000000001355360272700214365ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/libc/aarch32/endian_.h000066400000000000000000000104101355360272700232000ustar00rootroot00000000000000/*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 2001 David E. O'Brien * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)endian.h 8.1 (Berkeley) 6/10/93 * $NetBSD: endian.h,v 1.7 1999/08/21 05:53:51 simonb Exp $ * $FreeBSD$ */ /* * Portions copyright (c) 2018, ARM Limited and Contributors. * All rights reserved. */ #ifndef ENDIAN__H #define ENDIAN__H #include /* * Definitions for byte order, according to byte significance from low * address to high. */ #define _LITTLE_ENDIAN 1234 /* LSB first: i386, vax */ #define _BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net */ #define _PDP_ENDIAN 3412 /* LSB first in word, MSW first in long */ #ifdef __ARMEB__ #define _BYTE_ORDER _BIG_ENDIAN #else #define _BYTE_ORDER _LITTLE_ENDIAN #endif /* __ARMEB__ */ #if __BSD_VISIBLE #define LITTLE_ENDIAN _LITTLE_ENDIAN #define BIG_ENDIAN _BIG_ENDIAN #define PDP_ENDIAN _PDP_ENDIAN #define BYTE_ORDER _BYTE_ORDER #endif #ifdef __ARMEB__ #define _QUAD_HIGHWORD 0 #define _QUAD_LOWWORD 1 #define __ntohl(x) ((uint32_t)(x)) #define __ntohs(x) ((uint16_t)(x)) #define __htonl(x) ((uint32_t)(x)) #define __htons(x) ((uint16_t)(x)) #else #define _QUAD_HIGHWORD 1 #define _QUAD_LOWWORD 0 #define __ntohl(x) (__bswap32(x)) #define __ntohs(x) (__bswap16(x)) #define __htonl(x) (__bswap32(x)) #define __htons(x) (__bswap16(x)) #endif /* __ARMEB__ */ static __inline uint64_t __bswap64(uint64_t _x) { return ((_x >> 56) | ((_x >> 40) & 0xff00) | ((_x >> 24) & 0xff0000) | ((_x >> 8) & 0xff000000) | ((_x << 8) & ((uint64_t)0xff << 32)) | ((_x << 24) & ((uint64_t)0xff << 40)) | ((_x << 40) & ((uint64_t)0xff << 48)) | ((_x << 56))); } static __inline uint32_t __bswap32_var(uint32_t v) { uint32_t t1; __asm __volatile("eor %1, %0, %0, ror #16\n" "bic %1, %1, #0x00ff0000\n" "mov %0, %0, ror #8\n" "eor %0, %0, %1, lsr #8\n" : "+r" (v), "=r" (t1)); return (v); } static __inline uint16_t __bswap16_var(uint16_t v) { uint32_t ret = v & 0xffff; __asm __volatile( "mov %0, %0, ror #8\n" "orr %0, %0, %0, lsr #16\n" "bic %0, %0, %0, lsl #16" : "+r" (ret)); return ((uint16_t)ret); } #ifdef __OPTIMIZE__ #define __bswap32_constant(x) \ ((((x) & 0xff000000U) >> 24) | \ (((x) & 0x00ff0000U) >> 8) | \ (((x) & 0x0000ff00U) << 8) | \ (((x) & 0x000000ffU) << 24)) #define __bswap16_constant(x) \ ((((x) & 0xff00) >> 8) | \ (((x) & 0x00ff) << 8)) #define __bswap16(x) \ ((uint16_t)(__builtin_constant_p(x) ? \ __bswap16_constant(x) : \ __bswap16_var(x))) #define __bswap32(x) \ ((uint32_t)(__builtin_constant_p(x) ? \ __bswap32_constant(x) : \ __bswap32_var(x))) #else #define __bswap16(x) __bswap16_var(x) #define __bswap32(x) __bswap32_var(x) #endif /* __OPTIMIZE__ */ #endif /* ENDIAN__H */ trusted-firmware-a-2.2/include/lib/libc/aarch32/limits_.h000066400000000000000000000013141355360272700232460ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #define SCHAR_MAX 0x7F #define SCHAR_MIN (-SCHAR_MIN - 1) #define CHAR_MAX 0x7F #define CHAR_MIN (-CHAR_MAX - 1) #define UCHAR_MAX 0xFFU #define SHRT_MAX 0x7FFF #define SHRT_MIN (-SHRT_MAX - 1) #define USHRT_MAX 0xFFFFU #define INT_MAX 0x7FFFFFFF #define INT_MIN (-INT_MAX - 1) #define UINT_MAX 0xFFFFFFFFU #define LONG_MAX 0x7FFFFFFFL #define LONG_MIN (-LONG_MAX - 1L) #define ULONG_MAX 0xFFFFFFFFUL #define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL #define LLONG_MIN (-LLONG_MAX - 1LL) #define ULLONG_MAX 0xFFFFFFFFFFFFFFFFULL #define __LONG_BIT 32 #define __WORD_BIT 32 trusted-firmware-a-2.2/include/lib/libc/aarch32/stddef_.h000066400000000000000000000005031355360272700232150ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STDDEF__H #define STDDEF__H #ifndef SIZET_ typedef unsigned int size_t; #define SIZET_ #endif #ifndef _PTRDIFF_T typedef long ptrdiff_t; #define _PTRDIFF_T #endif #endif /* STDDEF__H */ trusted-firmware-a-2.2/include/lib/libc/aarch32/stdint_.h000066400000000000000000000054241355360272700232600ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #define INT8_MAX 0x7F #define INT8_MIN (-INT8_MAX - 1) #define UINT8_MAX 0xFFU #define INT16_MAX 0x7FFF #define INT16_MIN (-INT16_MAX - 1) #define UINT16_MAX 0xFFFFU #define INT32_MAX 0x7FFFFFFF #define INT32_MIN (-INT32_MAX - 1) #define UINT32_MAX 0xFFFFFFFFU #define INT64_MAX 0x7FFFFFFFFFFFFFFFLL #define INT64_MIN (-INT64_MAX - 1LL) #define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL #define INT_LEAST8_MIN INT8_MIN #define INT_LEAST8_MAX INT8_MAX #define UINT_LEAST8_MAX UINT8_MAX #define INT_LEAST16_MIN INT16_MIN #define INT_LEAST16_MAX INT16_MAX #define UINT_LEAST16_MAX UINT16_MAX #define INT_LEAST32_MIN INT32_MIN #define INT_LEAST32_MAX INT32_MAX #define UINT_LEAST32_MAX UINT32_MAX #define INT_LEAST64_MIN INT64_MIN #define INT_LEAST64_MAX INT64_MAX #define UINT_LEAST64_MAX UINT64_MAX #define INT_FAST8_MIN INT32_MIN #define INT_FAST8_MAX INT32_MAX #define UINT_FAST8_MAX UINT32_MAX #define INT_FAST16_MIN INT32_MIN #define INT_FAST16_MAX INT32_MAX #define UINT_FAST16_MAX UINT32_MAX #define INT_FAST32_MIN INT32_MIN #define INT_FAST32_MAX INT32_MAX #define UINT_FAST32_MAX UINT32_MAX #define INT_FAST64_MIN INT64_MIN #define INT_FAST64_MAX INT64_MAX #define UINT_FAST64_MAX UINT64_MAX #define INTPTR_MIN INT32_MIN #define INTPTR_MAX INT32_MAX #define UINTPTR_MAX UINT32_MAX #define INTMAX_MIN INT64_MIN #define INTMAX_MAX INT64_MAX #define UINTMAX_MAX UINT64_MAX #define PTRDIFF_MIN INT32_MIN #define PTRDIFF_MAX INT32_MAX #define SIZE_MAX UINT32_MAX #define INT8_C(x) x #define INT16_C(x) x #define INT32_C(x) x #define INT64_C(x) x ## LL #define UINT8_C(x) x #define UINT16_C(x) x #define UINT32_C(x) x ## U #define UINT64_C(x) x ## ULL #define INTMAX_C(x) x ## LL #define UINTMAX_C(x) x ## ULL typedef signed char int8_t; typedef short int16_t; typedef int int32_t; typedef long long int64_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; typedef signed char int8_least_t; typedef short int16_least_t; typedef int int32_least_t; typedef long long int64_least_t; typedef unsigned char uint8_least_t; typedef unsigned short uint16_least_t; typedef unsigned int uint32_least_t; typedef unsigned long long uint64_least_t; typedef int int8_fast_t; typedef int int16_fast_t; typedef int int32_fast_t; typedef long long int64_fast_t; typedef unsigned int uint8_fast_t; typedef unsigned int uint16_fast_t; typedef unsigned int uint32_fast_t; typedef unsigned long long uint64_fast_t; typedef long intptr_t; typedef unsigned long uintptr_t; typedef long long intmax_t; typedef unsigned long long uintmax_t; typedef long register_t; typedef unsigned long u_register_t; trusted-firmware-a-2.2/include/lib/libc/aarch32/stdio_.h000066400000000000000000000004671355360272700230770ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STDIO__H #define STDIO__H #ifndef SIZET_ typedef unsigned int size_t; #define SIZET_ #endif #ifndef SSIZET_ typedef int ssize_t; #define SSIZET_ #endif #endif /* STDIO__H */ trusted-firmware-a-2.2/include/lib/libc/aarch32/stdlib_.h000066400000000000000000000004541355360272700232320ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STDLIB__H #define STDLIB__H #ifndef SIZET_ typedef unsigned int size_t; #define SIZET_ #endif #define EXIT_FAILURE 1 #define EXIT_SUCCESS 0 #endif /* STDLIB__H */ trusted-firmware-a-2.2/include/lib/libc/aarch32/string_.h000066400000000000000000000003751355360272700232610ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STRING__H #define STRING__H #ifndef SIZET_ typedef unsigned int size_t; #define SIZET_ #endif #endif /* STRING__H */ trusted-firmware-a-2.2/include/lib/libc/aarch32/time_.h000066400000000000000000000004211355360272700227010ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TIME__H #define TIME__H #ifndef SIZET_ typedef unsigned int size_t; #define SIZET_ #endif typedef long int time_t; #endif /* TIME__H */ trusted-firmware-a-2.2/include/lib/libc/aarch64/000077500000000000000000000000001355360272700214435ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/libc/aarch64/endian_.h000066400000000000000000000072231355360272700232150ustar00rootroot00000000000000/*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 2001 David E. O'Brien * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)endian.h 8.1 (Berkeley) 6/10/93 * $NetBSD: endian.h,v 1.7 1999/08/21 05:53:51 simonb Exp $ * $FreeBSD$ */ /* * Portions copyright (c) 2018, ARM Limited and Contributors. * All rights reserved. */ #ifndef ENDIAN__H #define ENDIAN__H #include /* * Definitions for byte order, according to byte significance from low * address to high. */ #define _LITTLE_ENDIAN 1234 /* LSB first: i386, vax */ #define _BIG_ENDIAN 4321 /* MSB first: 68000, ibm, net */ #define _PDP_ENDIAN 3412 /* LSB first in word, MSW first in long */ #define _BYTE_ORDER _LITTLE_ENDIAN #if __BSD_VISIBLE #define LITTLE_ENDIAN _LITTLE_ENDIAN #define BIG_ENDIAN _BIG_ENDIAN #define PDP_ENDIAN _PDP_ENDIAN #define BYTE_ORDER _BYTE_ORDER #endif #define _QUAD_HIGHWORD 1 #define _QUAD_LOWWORD 0 #define __ntohl(x) (__bswap32(x)) #define __ntohs(x) (__bswap16(x)) #define __htonl(x) (__bswap32(x)) #define __htons(x) (__bswap16(x)) static __inline uint64_t __bswap64(uint64_t x) { uint64_t ret; __asm __volatile("rev %0, %1\n" : "=&r" (ret), "+r" (x)); return (ret); } static __inline uint32_t __bswap32_var(uint32_t v) { uint32_t ret; __asm __volatile("rev32 %x0, %x1\n" : "=&r" (ret), "+r" (v)); return (ret); } static __inline uint16_t __bswap16_var(uint16_t v) { uint32_t ret; __asm __volatile("rev16 %w0, %w1\n" : "=&r" (ret), "+r" (v)); return ((uint16_t)ret); } #ifdef __OPTIMIZE__ #define __bswap32_constant(x) \ ((((x) & 0xff000000U) >> 24) | \ (((x) & 0x00ff0000U) >> 8) | \ (((x) & 0x0000ff00U) << 8) | \ (((x) & 0x000000ffU) << 24)) #define __bswap16_constant(x) \ ((((x) & 0xff00) >> 8) | \ (((x) & 0x00ff) << 8)) #define __bswap16(x) \ ((uint16_t)(__builtin_constant_p(x) ? \ __bswap16_constant((uint16_t)(x)) : \ __bswap16_var(x))) #define __bswap32(x) \ ((uint32_t)(__builtin_constant_p(x) ? \ __bswap32_constant((uint32_t)(x)) : \ __bswap32_var(x))) #else #define __bswap16(x) __bswap16_var(x) #define __bswap32(x) __bswap32_var(x) #endif /* __OPTIMIZE__ */ #endif /* ENDIAN__H */ trusted-firmware-a-2.2/include/lib/libc/aarch64/limits_.h000066400000000000000000000013341355360272700232550ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #define SCHAR_MAX 0x7F #define SCHAR_MIN (-SCHAR_MIN - 1) #define CHAR_MAX 0x7F #define CHAR_MIN (-CHAR_MAX - 1) #define UCHAR_MAX 0xFFU #define SHRT_MAX 0x7FFF #define SHRT_MIN (-SHRT_MAX - 1) #define USHRT_MAX 0xFFFFU #define INT_MAX 0x7FFFFFFF #define INT_MIN (-INT_MAX - 1) #define UINT_MAX 0xFFFFFFFFU #define LONG_MAX 0x7FFFFFFFFFFFFFFFL #define LONG_MIN (-LONG_MAX - 1L) #define ULONG_MAX 0xFFFFFFFFFFFFFFFFUL #define LLONG_MAX 0x7FFFFFFFFFFFFFFFLL #define LLONG_MIN (-LLONG_MAX - 1LL) #define ULLONG_MAX 0xFFFFFFFFFFFFFFFFULL #define __LONG_BIT 64 #define __WORD_BIT 32 trusted-firmware-a-2.2/include/lib/libc/aarch64/setjmp_.h000066400000000000000000000011701355360272700232540ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SETJMP__H #define SETJMP__H #define JMP_CTX_X19 0x0 #define JMP_CTX_X21 0x10 #define JMP_CTX_X23 0x20 #define JMP_CTX_X25 0x30 #define JMP_CTX_X27 0x40 #define JMP_CTX_X29 0x50 #define JMP_CTX_SP 0x60 #define JMP_CTX_END 0x70 /* Aligned to 16 bytes */ #define JMP_SIZE (JMP_CTX_END >> 3) #ifndef __ASSEMBLER__ #include /* Jump buffer hosting x18 - x30 and sp_el0 registers */ typedef uint64_t jmp_buf[JMP_SIZE] __aligned(16); #endif /* __ASSEMBLER__ */ #endif /* SETJMP__H */ trusted-firmware-a-2.2/include/lib/libc/aarch64/stddef_.h000066400000000000000000000005041355360272700232230ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STDDEF__H #define STDDEF__H #ifndef SIZET_ typedef unsigned long size_t; #define SIZET_ #endif #ifndef _PTRDIFF_T typedef long ptrdiff_t; #define _PTRDIFF_T #endif #endif /* STDDEF__H */ trusted-firmware-a-2.2/include/lib/libc/aarch64/stdint_.h000066400000000000000000000055171355360272700232700ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #define INT8_MAX 0x7F #define INT8_MIN (-INT8_MAX - 1) #define UINT8_MAX 0xFFU #define INT16_MAX 0x7FFF #define INT16_MIN (-INT16_MAX - 1) #define UINT16_MAX 0xFFFFU #define INT32_MAX 0x7FFFFFFF #define INT32_MIN (-INT32_MAX - 1) #define UINT32_MAX 0xFFFFFFFFU #define INT64_MAX 0x7FFFFFFFFFFFFFFFLL #define INT64_MIN (-INT64_MAX - 1LL) #define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL #define INT_LEAST8_MIN INT8_MIN #define INT_LEAST8_MAX INT8_MAX #define UINT_LEAST8_MAX UINT8_MAX #define INT_LEAST16_MIN INT16_MIN #define INT_LEAST16_MAX INT16_MAX #define UINT_LEAST16_MAX UINT16_MAX #define INT_LEAST32_MIN INT32_MIN #define INT_LEAST32_MAX INT32_MAX #define UINT_LEAST32_MAX UINT32_MAX #define INT_LEAST64_MIN INT64_MIN #define INT_LEAST64_MAX INT64_MAX #define UINT_LEAST64_MAX UINT64_MAX #define INT_FAST8_MIN INT32_MIN #define INT_FAST8_MAX INT32_MAX #define UINT_FAST8_MAX UINT32_MAX #define INT_FAST16_MIN INT32_MIN #define INT_FAST16_MAX INT32_MAX #define UINT_FAST16_MAX UINT32_MAX #define INT_FAST32_MIN INT32_MIN #define INT_FAST32_MAX INT32_MAX #define UINT_FAST32_MAX UINT32_MAX #define INT_FAST64_MIN INT64_MIN #define INT_FAST64_MAX INT64_MAX #define UINT_FAST64_MAX UINT64_MAX #define INTPTR_MIN INT64_MIN #define INTPTR_MAX INT64_MAX #define UINTPTR_MAX UINT64_MAX #define INTMAX_MIN INT64_MIN #define INTMAX_MAX INT64_MAX #define UINTMAX_MAX UINT64_MAX #define PTRDIFF_MIN INT64_MIN #define PTRDIFF_MAX INT64_MAX #define SIZE_MAX UINT64_MAX #define INT8_C(x) x #define INT16_C(x) x #define INT32_C(x) x #define INT64_C(x) x ## LL #define UINT8_C(x) x #define UINT16_C(x) x #define UINT32_C(x) x ## U #define UINT64_C(x) x ## ULL #define INTMAX_C(x) x ## L #define UINTMAX_C(x) x ## ULL typedef signed char int8_t; typedef short int16_t; typedef int int32_t; typedef long long int64_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned long long uint64_t; typedef signed char int8_least_t; typedef short int16_least_t; typedef int int32_least_t; typedef long long int64_least_t; typedef unsigned char uint8_least_t; typedef unsigned short uint16_least_t; typedef unsigned int uint32_least_t; typedef unsigned long long uint64_least_t; typedef int int8_fast_t; typedef int int16_fast_t; typedef int int32_fast_t; typedef long long int64_fast_t; typedef unsigned int uint8_fast_t; typedef unsigned int uint16_fast_t; typedef unsigned int uint32_fast_t; typedef unsigned long long uint64_fast_t; typedef long intptr_t; typedef unsigned long uintptr_t; typedef long intmax_t; typedef unsigned long uintmax_t; typedef long register_t; typedef unsigned long u_register_t; typedef __int128 int128_t; typedef unsigned __int128 uint128_t; trusted-firmware-a-2.2/include/lib/libc/aarch64/stdio_.h000066400000000000000000000004711355360272700230770ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STDIO__H #define STDIO__H #ifndef SIZET_ typedef unsigned long size_t; #define SIZET_ #endif #ifndef SSIZET_ typedef long ssize_t; #define SSIZET_ #endif #endif /* STDIO__H */ trusted-firmware-a-2.2/include/lib/libc/aarch64/stdlib_.h000066400000000000000000000004551355360272700232400ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STDLIB__H #define STDLIB__H #ifndef SIZET_ typedef unsigned long size_t; #define SIZET_ #endif #define EXIT_FAILURE 1 #define EXIT_SUCCESS 0 #endif /* STDLIB__H */ trusted-firmware-a-2.2/include/lib/libc/aarch64/string_.h000066400000000000000000000003761355360272700232670ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STRING__H #define STRING__H #ifndef SIZET_ typedef unsigned long size_t; #define SIZET_ #endif #endif /* STRING__H */ trusted-firmware-a-2.2/include/lib/libc/aarch64/time_.h000066400000000000000000000004221355360272700227070ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TIME__H #define TIME__H #ifndef SIZET_ typedef unsigned long size_t; #define SIZET_ #endif typedef long int time_t; #endif /* TIME__H */ trusted-firmware-a-2.2/include/lib/libc/assert.h000066400000000000000000000017641355360272700216750ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ASSERT_H #define ASSERT_H #include #include #include #ifndef PLAT_LOG_LEVEL_ASSERT #define PLAT_LOG_LEVEL_ASSERT LOG_LEVEL #endif #if ENABLE_ASSERTIONS # if PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_VERBOSE # define assert(e) ((e) ? (void)0 : __assert(__FILE__, __LINE__, #e)) # elif PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_INFO # define assert(e) ((e) ? (void)0 : __assert(__FILE__, __LINE__)) # else # define assert(e) ((e) ? (void)0 : __assert()) # endif #else #define assert(e) ((void)0) #endif /* ENABLE_ASSERTIONS */ #if PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_VERBOSE void __dead2 __assert(const char *file, unsigned int line, const char *assertion); #elif PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_INFO void __dead2 __assert(const char *file, unsigned int line); #else void __dead2 __assert(void); #endif #endif /* ASSERT_H */ trusted-firmware-a-2.2/include/lib/libc/cdefs.h000066400000000000000000000017641355360272700214600ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CDEFS_H #define CDEFS_H #define __dead2 __attribute__((__noreturn__)) #define __deprecated __attribute__((__deprecated__)) #define __packed __attribute__((__packed__)) #define __used __attribute__((__used__)) #define __unused __attribute__((__unused__)) #define __aligned(x) __attribute__((__aligned__(x))) #define __section(x) __attribute__((__section__(x))) #if RECLAIM_INIT_CODE /* * Add each function to a section that is unique so the functions can still * be garbage collected */ #define __init __section(".text.init." __FILE__ "." __XSTRING(__LINE__)) #else #define __init #endif #define __printflike(fmtarg, firstvararg) \ __attribute__((__format__ (__printf__, fmtarg, firstvararg))) #define __weak_reference(sym, alias) \ __asm__(".weak alias"); \ __asm__(".equ alias, sym") #define __STRING(x) #x #define __XSTRING(x) __STRING(x) #endif /* CDEFS_H */ trusted-firmware-a-2.2/include/lib/libc/endian.h000066400000000000000000000112751355360272700216300ustar00rootroot00000000000000/*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2002 Thomas Moestl * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ /* * Portions copyright (c) 2018, ARM Limited and Contributors. * All rights reserved. */ #ifndef ENDIAN_H #define ENDIAN_H #include #include #include /* * General byte order swapping functions. */ #define bswap16(x) __bswap16(x) #define bswap32(x) __bswap32(x) #define bswap64(x) __bswap64(x) /* * Host to big endian, host to little endian, big endian to host, and little * endian to host byte order functions as detailed in byteorder(9). */ #if _BYTE_ORDER == _LITTLE_ENDIAN #define htobe16(x) bswap16((x)) #define htobe32(x) bswap32((x)) #define htobe64(x) bswap64((x)) #define htole16(x) ((uint16_t)(x)) #define htole32(x) ((uint32_t)(x)) #define htole64(x) ((uint64_t)(x)) #define be16toh(x) bswap16((x)) #define be32toh(x) bswap32((x)) #define be64toh(x) bswap64((x)) #define le16toh(x) ((uint16_t)(x)) #define le32toh(x) ((uint32_t)(x)) #define le64toh(x) ((uint64_t)(x)) #else /* _BYTE_ORDER != _LITTLE_ENDIAN */ #define htobe16(x) ((uint16_t)(x)) #define htobe32(x) ((uint32_t)(x)) #define htobe64(x) ((uint64_t)(x)) #define htole16(x) bswap16((x)) #define htole32(x) bswap32((x)) #define htole64(x) bswap64((x)) #define be16toh(x) ((uint16_t)(x)) #define be32toh(x) ((uint32_t)(x)) #define be64toh(x) ((uint64_t)(x)) #define le16toh(x) bswap16((x)) #define le32toh(x) bswap32((x)) #define le64toh(x) bswap64((x)) #endif /* _BYTE_ORDER == _LITTLE_ENDIAN */ /* Alignment-agnostic encode/decode bytestream to/from little/big endian. */ static __inline uint16_t be16dec(const void *pp) { uint8_t const *p = (uint8_t const *)pp; return ((p[0] << 8) | p[1]); } static __inline uint32_t be32dec(const void *pp) { uint8_t const *p = (uint8_t const *)pp; return (((unsigned)p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]); } static __inline uint64_t be64dec(const void *pp) { uint8_t const *p = (uint8_t const *)pp; return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4)); } static __inline uint16_t le16dec(const void *pp) { uint8_t const *p = (uint8_t const *)pp; return ((p[1] << 8) | p[0]); } static __inline uint32_t le32dec(const void *pp) { uint8_t const *p = (uint8_t const *)pp; return (((unsigned)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]); } static __inline uint64_t le64dec(const void *pp) { uint8_t const *p = (uint8_t const *)pp; return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p)); } static __inline void be16enc(void *pp, uint16_t u) { uint8_t *p = (uint8_t *)pp; p[0] = (u >> 8) & 0xff; p[1] = u & 0xff; } static __inline void be32enc(void *pp, uint32_t u) { uint8_t *p = (uint8_t *)pp; p[0] = (u >> 24) & 0xff; p[1] = (u >> 16) & 0xff; p[2] = (u >> 8) & 0xff; p[3] = u & 0xff; } static __inline void be64enc(void *pp, uint64_t u) { uint8_t *p = (uint8_t *)pp; be32enc(p, (uint32_t)(u >> 32)); be32enc(p + 4, (uint32_t)(u & 0xffffffffU)); } static __inline void le16enc(void *pp, uint16_t u) { uint8_t *p = (uint8_t *)pp; p[0] = u & 0xff; p[1] = (u >> 8) & 0xff; } static __inline void le32enc(void *pp, uint32_t u) { uint8_t *p = (uint8_t *)pp; p[0] = u & 0xff; p[1] = (u >> 8) & 0xff; p[2] = (u >> 16) & 0xff; p[3] = (u >> 24) & 0xff; } static __inline void le64enc(void *pp, uint64_t u) { uint8_t *p = (uint8_t *)pp; le32enc(p, (uint32_t)(u & 0xffffffffU)); le32enc(p + 4, (uint32_t)(u >> 32)); } #endif /* ENDIAN_H */ trusted-firmware-a-2.2/include/lib/libc/errno.h000066400000000000000000000163651355360272700215240ustar00rootroot00000000000000/*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1982, 1986, 1989, 1993 * The Regents of the University of California. All rights reserved. * (c) UNIX System Laboratories, Inc. * All or some portions of this file are derived from material licensed * to the University of California by American Telephone and Telegraph * Co. or Unix System Laboratories, Inc. and are reproduced herein with * the permission of UNIX System Laboratories, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)errno.h 8.5 (Berkeley) 1/21/94 * $FreeBSD$ */ /* * Portions copyright (c) 2018, ARM Limited and Contributors. * All rights reserved. */ #ifndef ERRNO_H #define ERRNO_H #define EPERM 1 /* Operation not permitted */ #define ENOENT 2 /* No such file or directory */ #define ESRCH 3 /* No such process */ #define EINTR 4 /* Interrupted system call */ #define EIO 5 /* Input/output error */ #define ENXIO 6 /* Device not configured */ #define E2BIG 7 /* Argument list too long */ #define ENOEXEC 8 /* Exec format error */ #define EBADF 9 /* Bad file descriptor */ #define ECHILD 10 /* No child processes */ #define EDEADLK 11 /* Resource deadlock avoided */ /* 11 was EAGAIN */ #define ENOMEM 12 /* Cannot allocate memory */ #define EACCES 13 /* Permission denied */ #define EFAULT 14 /* Bad address */ #define ENOTBLK 15 /* Block device required */ #define EBUSY 16 /* Device busy */ #define EEXIST 17 /* File exists */ #define EXDEV 18 /* Cross-device link */ #define ENODEV 19 /* Operation not supported by device */ #define ENOTDIR 20 /* Not a directory */ #define EISDIR 21 /* Is a directory */ #define EINVAL 22 /* Invalid argument */ #define ENFILE 23 /* Too many open files in system */ #define EMFILE 24 /* Too many open files */ #define ENOTTY 25 /* Inappropriate ioctl for device */ #define ETXTBSY 26 /* Text file busy */ #define EFBIG 27 /* File too large */ #define ENOSPC 28 /* No space left on device */ #define ESPIPE 29 /* Illegal seek */ #define EROFS 30 /* Read-only filesystem */ #define EMLINK 31 /* Too many links */ #define EPIPE 32 /* Broken pipe */ /* math software */ #define EDOM 33 /* Numerical argument out of domain */ #define ERANGE 34 /* Result too large */ /* non-blocking and interrupt i/o */ #define EAGAIN 35 /* Resource temporarily unavailable */ #define EWOULDBLOCK EAGAIN /* Operation would block */ #define EINPROGRESS 36 /* Operation now in progress */ #define EALREADY 37 /* Operation already in progress */ /* ipc/network software -- argument errors */ #define ENOTSOCK 38 /* Socket operation on non-socket */ #define EDESTADDRREQ 39 /* Destination address required */ #define EMSGSIZE 40 /* Message too long */ #define EPROTOTYPE 41 /* Protocol wrong type for socket */ #define ENOPROTOOPT 42 /* Protocol not available */ #define EPROTONOSUPPORT 43 /* Protocol not supported */ #define ESOCKTNOSUPPORT 44 /* Socket type not supported */ #define EOPNOTSUPP 45 /* Operation not supported */ #define ENOTSUP EOPNOTSUPP /* Operation not supported */ #define EPFNOSUPPORT 46 /* Protocol family not supported */ #define EAFNOSUPPORT 47 /* Address family not supported by protocol family */ #define EADDRINUSE 48 /* Address already in use */ #define EADDRNOTAVAIL 49 /* Can't assign requested address */ /* ipc/network software -- operational errors */ #define ENETDOWN 50 /* Network is down */ #define ENETUNREACH 51 /* Network is unreachable */ #define ENETRESET 52 /* Network dropped connection on reset */ #define ECONNABORTED 53 /* Software caused connection abort */ #define ECONNRESET 54 /* Connection reset by peer */ #define ENOBUFS 55 /* No buffer space available */ #define EISCONN 56 /* Socket is already connected */ #define ENOTCONN 57 /* Socket is not connected */ #define ESHUTDOWN 58 /* Can't send after socket shutdown */ #define ETOOMANYREFS 59 /* Too many references: can't splice */ #define ETIMEDOUT 60 /* Operation timed out */ #define ECONNREFUSED 61 /* Connection refused */ #define ELOOP 62 /* Too many levels of symbolic links */ #define ENAMETOOLONG 63 /* File name too long */ /* should be rearranged */ #define EHOSTDOWN 64 /* Host is down */ #define EHOSTUNREACH 65 /* No route to host */ #define ENOTEMPTY 66 /* Directory not empty */ /* quotas & mush */ #define EPROCLIM 67 /* Too many processes */ #define EUSERS 68 /* Too many users */ #define EDQUOT 69 /* Disc quota exceeded */ /* Network File System */ #define ESTALE 70 /* Stale NFS file handle */ #define EREMOTE 71 /* Too many levels of remote in path */ #define EBADRPC 72 /* RPC struct is bad */ #define ERPCMISMATCH 73 /* RPC version wrong */ #define EPROGUNAVAIL 74 /* RPC prog. not avail */ #define EPROGMISMATCH 75 /* Program version wrong */ #define EPROCUNAVAIL 76 /* Bad procedure for program */ #define ENOLCK 77 /* No locks available */ #define ENOSYS 78 /* Function not implemented */ #define EFTYPE 79 /* Inappropriate file type or format */ #define EAUTH 80 /* Authentication error */ #define ENEEDAUTH 81 /* Need authenticator */ #define EIDRM 82 /* Identifier removed */ #define ENOMSG 83 /* No message of desired type */ #define EOVERFLOW 84 /* Value too large to be stored in data type */ #define ECANCELED 85 /* Operation canceled */ #define EILSEQ 86 /* Illegal byte sequence */ #define ENOATTR 87 /* Attribute not found */ #define EDOOFUS 88 /* Programming error */ #define EBADMSG 89 /* Bad message */ #define EMULTIHOP 90 /* Multihop attempted */ #define ENOLINK 91 /* Link has been severed */ #define EPROTO 92 /* Protocol error */ #define ENOTCAPABLE 93 /* Capabilities insufficient */ #define ECAPMODE 94 /* Not permitted in capability mode */ #define ENOTRECOVERABLE 95 /* State not recoverable */ #define EOWNERDEAD 96 /* Previous owner died */ #define ELAST 96 /* Must be equal largest errno */ #endif /* ERRNO_H */ trusted-firmware-a-2.2/include/lib/libc/limits.h000066400000000000000000000005021355360272700216620ustar00rootroot00000000000000/* * Copyright (c) 2012-2017 Roberto E. Vargas Caballero * * SPDX-License-Identifier: BSD-3-Clause */ /* * Portions copyright (c) 2018, ARM Limited and Contributors. * All rights reserved. */ #ifndef LIMITS_H #define LIMITS_H #include #define CHAR_BIT 8 #define MB_LEN_MAX 1 #endif /* LIMITS_H */ trusted-firmware-a-2.2/include/lib/libc/setjmp.h000066400000000000000000000005361355360272700216720ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SETJMP_H #define SETJMP_H #include #ifndef __ASSEMBLER__ #include int setjmp(jmp_buf env); __dead2 void longjmp(jmp_buf env, int val); #endif /* __ASSEMBLER__ */ #endif /* SETJMP_H */ trusted-firmware-a-2.2/include/lib/libc/stdarg.h000066400000000000000000000007561355360272700216600ustar00rootroot00000000000000/* * Copyright (c) 2012-2017 Roberto E. Vargas Caballero * * SPDX-License-Identifier: BSD-3-Clause */ /* * Portions copyright (c) 2018, ARM Limited and Contributors. * All rights reserved. */ #ifndef STDARG_H #define STDARG_H #define va_list __builtin_va_list #define va_start(ap, last) __builtin_va_start(ap, last) #define va_end(ap) __builtin_va_end(ap) #define va_copy(to, from) __builtin_va_copy(to, from) #define va_arg(to, type) __builtin_va_arg(to, type) #endif /* STDARG_H */ trusted-firmware-a-2.2/include/lib/libc/stdbool.h000066400000000000000000000004271355360272700220350ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STDBOOL_H #define STDBOOL_H #define bool _Bool #define true 1 #define false 0 #define __bool_true_false_are_defined 1 #endif /* STDBOOL_H */ trusted-firmware-a-2.2/include/lib/libc/stddef.h000066400000000000000000000005711355360272700216400ustar00rootroot00000000000000/* * Copyright (c) 2012-2017 Roberto E. Vargas Caballero * * SPDX-License-Identifier: BSD-3-Clause */ /* * Portions copyright (c) 2018, ARM Limited and Contributors. * All rights reserved. */ #ifndef STDDEF_H #define STDDEF_H #include #ifndef NULL #define NULL ((void *) 0) #endif #define offsetof(st, m) __builtin_offsetof(st, m) #endif /* STDDEF_H */ trusted-firmware-a-2.2/include/lib/libc/stdint.h000066400000000000000000000004271355360272700216740ustar00rootroot00000000000000/* * Copyright (c) 2012-2017 Roberto E. Vargas Caballero * * SPDX-License-Identifier: BSD-3-Clause */ /* * Portions copyright (c) 2018, ARM Limited and Contributors. * All rights reserved. */ #ifndef STDINT_H #define STDINT_H #include #endif /* STDINT_H */ trusted-firmware-a-2.2/include/lib/libc/stdio.h000066400000000000000000000011421355360272700215040ustar00rootroot00000000000000/* * Copyright (c) 2012-2017 Roberto E. Vargas Caballero * * SPDX-License-Identifier: BSD-3-Clause */ /* * Portions copyright (c) 2018, ARM Limited and Contributors. * All rights reserved. */ #ifndef STDIO_H #define STDIO_H #include #include #ifndef NULL #define NULL ((void *) 0) #endif #define EOF -1 int printf(const char *fmt, ...) __printflike(1, 2); int snprintf(char *s, size_t n, const char *fmt, ...) __printflike(3, 4); #ifdef STDARG_H int vprintf(const char *fmt, va_list args); #endif int putchar(int c); int puts(const char *s); #endif /* STDIO_H */ trusted-firmware-a-2.2/include/lib/libc/stdlib.h000066400000000000000000000006741355360272700216540ustar00rootroot00000000000000/* * Copyright (c) 2012-2017 Roberto E. Vargas Caballero * * SPDX-License-Identifier: BSD-3-Clause */ /* * Portions copyright (c) 2018, ARM Limited and Contributors. * All rights reserved. */ #ifndef STDLIB_H #define STDLIB_H #include #ifndef NULL #define NULL ((void *) 0) #endif #define _ATEXIT_MAX 1 extern void abort(void); extern int atexit(void (*func)(void)); extern void exit(int status); #endif /* STDLIB_H */ trusted-firmware-a-2.2/include/lib/libc/string.h000066400000000000000000000016031355360272700216720ustar00rootroot00000000000000/* * Copyright (c) 2012-2017 Roberto E. Vargas Caballero * * SPDX-License-Identifier: BSD-3-Clause */ /* * Portions copyright (c) 2018, ARM Limited and Contributors. * All rights reserved. */ #ifndef STRING_H #define STRING_H #include #ifndef NULL #define NULL ((void *) 0) #endif void *memcpy(void *dst, const void *src, size_t len); void *memmove(void *dst, const void *src, size_t len); int memcmp(const void *s1, const void *s2, size_t len); int strcmp(const char *s1, const char *s2); int strncmp(const char *s1, const char *s2, size_t n); void *memchr(const void *src, int c, size_t len); char *strchr(const char *s, int c); void *memset(void *dst, int val, size_t count); size_t strlen(const char *s); size_t strnlen(const char *s, size_t maxlen); char *strrchr(const char *p, int ch); size_t strlcpy(char * dst, const char * src, size_t dsize); #endif /* STRING_H */ trusted-firmware-a-2.2/include/lib/libc/time.h000066400000000000000000000004761355360272700213310ustar00rootroot00000000000000/* * Copyright (c) 2012-2017 Roberto E. Vargas Caballero * * SPDX-License-Identifier: BSD-3-Clause */ /* * Portions copyright (c) 2018, ARM Limited and Contributors. * All rights reserved. */ #ifndef TIME_H #define TIME_H #include #ifndef NULL #define NULL ((void *) 0) #endif #endif /* TIME_H */ trusted-firmware-a-2.2/include/lib/libfdt/000077500000000000000000000000001355360272700205465ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/libfdt/fdt.h000066400000000000000000000076671355360272700215140ustar00rootroot00000000000000#ifndef FDT_H #define FDT_H /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * Copyright 2012 Kim Phillips, Freescale Semiconductor. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef __ASSEMBLER__ struct fdt_header { fdt32_t magic; /* magic word FDT_MAGIC */ fdt32_t totalsize; /* total size of DT block */ fdt32_t off_dt_struct; /* offset to structure */ fdt32_t off_dt_strings; /* offset to strings */ fdt32_t off_mem_rsvmap; /* offset to memory reserve map */ fdt32_t version; /* format version */ fdt32_t last_comp_version; /* last compatible version */ /* version 2 fields below */ fdt32_t boot_cpuid_phys; /* Which physical CPU id we're booting on */ /* version 3 fields below */ fdt32_t size_dt_strings; /* size of the strings block */ /* version 17 fields below */ fdt32_t size_dt_struct; /* size of the structure block */ }; struct fdt_reserve_entry { fdt64_t address; fdt64_t size; }; struct fdt_node_header { fdt32_t tag; char name[0]; }; struct fdt_property { fdt32_t tag; fdt32_t len; fdt32_t nameoff; char data[0]; }; #endif /* !__ASSEMBLER__ */ #define FDT_MAGIC 0xd00dfeed /* 4: version, 4: total size */ #define FDT_TAGSIZE sizeof(fdt32_t) #define FDT_BEGIN_NODE 0x1 /* Start node: full name */ #define FDT_END_NODE 0x2 /* End node */ #define FDT_PROP 0x3 /* Property: name off, size, content */ #define FDT_NOP 0x4 /* nop */ #define FDT_END 0x9 #define FDT_V1_SIZE (7*sizeof(fdt32_t)) #define FDT_V2_SIZE (FDT_V1_SIZE + sizeof(fdt32_t)) #define FDT_V3_SIZE (FDT_V2_SIZE + sizeof(fdt32_t)) #define FDT_V16_SIZE FDT_V3_SIZE #define FDT_V17_SIZE (FDT_V16_SIZE + sizeof(fdt32_t)) #endif /* FDT_H */ trusted-firmware-a-2.2/include/lib/libfdt/libfdt.h000066400000000000000000002073151355360272700221730ustar00rootroot00000000000000#ifndef LIBFDT_H #define LIBFDT_H /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #define FDT_FIRST_SUPPORTED_VERSION 0x02 #define FDT_LAST_SUPPORTED_VERSION 0x11 /* Error codes: informative error codes */ #define FDT_ERR_NOTFOUND 1 /* FDT_ERR_NOTFOUND: The requested node or property does not exist */ #define FDT_ERR_EXISTS 2 /* FDT_ERR_EXISTS: Attempted to create a node or property which * already exists */ #define FDT_ERR_NOSPACE 3 /* FDT_ERR_NOSPACE: Operation needed to expand the device * tree, but its buffer did not have sufficient space to * contain the expanded tree. Use fdt_open_into() to move the * device tree to a buffer with more space. */ /* Error codes: codes for bad parameters */ #define FDT_ERR_BADOFFSET 4 /* FDT_ERR_BADOFFSET: Function was passed a structure block * offset which is out-of-bounds, or which points to an * unsuitable part of the structure for the operation. */ #define FDT_ERR_BADPATH 5 /* FDT_ERR_BADPATH: Function was passed a badly formatted path * (e.g. missing a leading / for a function which requires an * absolute path) */ #define FDT_ERR_BADPHANDLE 6 /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle. * This can be caused either by an invalid phandle property * length, or the phandle value was either 0 or -1, which are * not permitted. */ #define FDT_ERR_BADSTATE 7 /* FDT_ERR_BADSTATE: Function was passed an incomplete device * tree created by the sequential-write functions, which is * not sufficiently complete for the requested operation. */ /* Error codes: codes for bad device tree blobs */ #define FDT_ERR_TRUNCATED 8 /* FDT_ERR_TRUNCATED: Structure block of the given device tree * ends without an FDT_END tag. */ #define FDT_ERR_BADMAGIC 9 /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a * device tree at all - it is missing the flattened device * tree magic number. */ #define FDT_ERR_BADVERSION 10 /* FDT_ERR_BADVERSION: Given device tree has a version which * can't be handled by the requested operation. For * read-write functions, this may mean that fdt_open_into() is * required to convert the tree to the expected version. */ #define FDT_ERR_BADSTRUCTURE 11 /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt * structure block or other serious error (e.g. misnested * nodes, or subnodes preceding properties). */ #define FDT_ERR_BADLAYOUT 12 /* FDT_ERR_BADLAYOUT: For read-write functions, the given * device tree has it's sub-blocks in an order that the * function can't handle (memory reserve map, then structure, * then strings). Use fdt_open_into() to reorganize the tree * into a form suitable for the read-write operations. */ /* "Can't happen" error indicating a bug in libfdt */ #define FDT_ERR_INTERNAL 13 /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion. * Should never be returned, if it is, it indicates a bug in * libfdt itself. */ /* Errors in device tree content */ #define FDT_ERR_BADNCELLS 14 /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells * or similar property with a bad format or value */ #define FDT_ERR_BADVALUE 15 /* FDT_ERR_BADVALUE: Device tree has a property with an unexpected * value. For example: a property expected to contain a string list * is not NUL-terminated within the length of its value. */ #define FDT_ERR_BADOVERLAY 16 /* FDT_ERR_BADOVERLAY: The device tree overlay, while * correctly structured, cannot be applied due to some * unexpected or missing value, property or node. */ #define FDT_ERR_NOPHANDLES 17 /* FDT_ERR_NOPHANDLES: The device tree doesn't have any * phandle available anymore without causing an overflow */ #define FDT_ERR_MAX 17 /**********************************************************************/ /* Low-level functions (you probably don't need these) */ /**********************************************************************/ #ifndef SWIG /* This function is not useful in Python */ const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen); #endif static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen) { return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen); } uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset); /**********************************************************************/ /* Traversal functions */ /**********************************************************************/ int fdt_next_node(const void *fdt, int offset, int *depth); /** * fdt_first_subnode() - get offset of first direct subnode * * @fdt: FDT blob * @offset: Offset of node to check * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none */ int fdt_first_subnode(const void *fdt, int offset); /** * fdt_next_subnode() - get offset of next direct subnode * * After first calling fdt_first_subnode(), call this function repeatedly to * get direct subnodes of a parent node. * * @fdt: FDT blob * @offset: Offset of previous subnode * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more * subnodes */ int fdt_next_subnode(const void *fdt, int offset); /** * fdt_for_each_subnode - iterate over all subnodes of a parent * * @node: child node (int, lvalue) * @fdt: FDT blob (const void *) * @parent: parent node (int) * * This is actually a wrapper around a for loop and would be used like so: * * fdt_for_each_subnode(node, fdt, parent) { * Use node * ... * } * * if ((node < 0) && (node != -FDT_ERR_NOT_FOUND)) { * Error handling * } * * Note that this is implemented as a macro and @node is used as * iterator in the loop. The parent variable be constant or even a * literal. * */ #define fdt_for_each_subnode(node, fdt, parent) \ for (node = fdt_first_subnode(fdt, parent); \ node >= 0; \ node = fdt_next_subnode(fdt, node)) /**********************************************************************/ /* General functions */ /**********************************************************************/ #define fdt_get_header(fdt, field) \ (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field)) #define fdt_magic(fdt) (fdt_get_header(fdt, magic)) #define fdt_totalsize(fdt) (fdt_get_header(fdt, totalsize)) #define fdt_off_dt_struct(fdt) (fdt_get_header(fdt, off_dt_struct)) #define fdt_off_dt_strings(fdt) (fdt_get_header(fdt, off_dt_strings)) #define fdt_off_mem_rsvmap(fdt) (fdt_get_header(fdt, off_mem_rsvmap)) #define fdt_version(fdt) (fdt_get_header(fdt, version)) #define fdt_last_comp_version(fdt) (fdt_get_header(fdt, last_comp_version)) #define fdt_boot_cpuid_phys(fdt) (fdt_get_header(fdt, boot_cpuid_phys)) #define fdt_size_dt_strings(fdt) (fdt_get_header(fdt, size_dt_strings)) #define fdt_size_dt_struct(fdt) (fdt_get_header(fdt, size_dt_struct)) #define fdt_set_hdr_(name) \ static inline void fdt_set_##name(void *fdt, uint32_t val) \ { \ struct fdt_header *fdth = (struct fdt_header *)fdt; \ fdth->name = cpu_to_fdt32(val); \ } fdt_set_hdr_(magic); fdt_set_hdr_(totalsize); fdt_set_hdr_(off_dt_struct); fdt_set_hdr_(off_dt_strings); fdt_set_hdr_(off_mem_rsvmap); fdt_set_hdr_(version); fdt_set_hdr_(last_comp_version); fdt_set_hdr_(boot_cpuid_phys); fdt_set_hdr_(size_dt_strings); fdt_set_hdr_(size_dt_struct); #undef fdt_set_hdr_ /** * fdt_check_header - sanity check a device tree or possible device tree * @fdt: pointer to data which might be a flattened device tree * * fdt_check_header() checks that the given buffer contains what * appears to be a flattened device tree with sane information in its * header. * * returns: * 0, if the buffer appears to contain a valid device tree * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings, as above */ int fdt_check_header(const void *fdt); /** * fdt_move - move a device tree around in memory * @fdt: pointer to the device tree to move * @buf: pointer to memory where the device is to be moved * @bufsize: size of the memory space at buf * * fdt_move() relocates, if possible, the device tree blob located at * fdt to the buffer at buf of size bufsize. The buffer may overlap * with the existing device tree blob at fdt. Therefore, * fdt_move(fdt, fdt, fdt_totalsize(fdt)) * should always succeed. * * returns: * 0, on success * -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings */ int fdt_move(const void *fdt, void *buf, int bufsize); /**********************************************************************/ /* Read-only functions */ /**********************************************************************/ /** * fdt_string - retrieve a string from the strings block of a device tree * @fdt: pointer to the device tree blob * @stroffset: offset of the string within the strings block (native endian) * * fdt_string() retrieves a pointer to a single string from the * strings block of the device tree blob at fdt. * * returns: * a pointer to the string, on success * NULL, if stroffset is out of bounds */ const char *fdt_string(const void *fdt, int stroffset); /** * fdt_get_max_phandle - retrieves the highest phandle in a tree * @fdt: pointer to the device tree blob * * fdt_get_max_phandle retrieves the highest phandle in the given * device tree. This will ignore badly formatted phandles, or phandles * with a value of 0 or -1. * * returns: * the highest phandle on success * 0, if no phandle was found in the device tree * -1, if an error occurred */ uint32_t fdt_get_max_phandle(const void *fdt); /** * fdt_num_mem_rsv - retrieve the number of memory reserve map entries * @fdt: pointer to the device tree blob * * Returns the number of entries in the device tree blob's memory * reservation map. This does not include the terminating 0,0 entry * or any other (0,0) entries reserved for expansion. * * returns: * the number of entries */ int fdt_num_mem_rsv(const void *fdt); /** * fdt_get_mem_rsv - retrieve one memory reserve map entry * @fdt: pointer to the device tree blob * @address, @size: pointers to 64-bit variables * * On success, *address and *size will contain the address and size of * the n-th reserve map entry from the device tree blob, in * native-endian format. * * returns: * 0, on success * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings */ int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size); /** * fdt_subnode_offset_namelen - find a subnode based on substring * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node * @name: name of the subnode to locate * @namelen: number of characters of name to consider * * Identical to fdt_subnode_offset(), but only examine the first * namelen characters of name for matching the subnode name. This is * useful for finding subnodes based on a portion of a larger string, * such as a full path. */ #ifndef SWIG /* Not available in Python */ int fdt_subnode_offset_namelen(const void *fdt, int parentoffset, const char *name, int namelen); #endif /** * fdt_subnode_offset - find a subnode of a given node * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node * @name: name of the subnode to locate * * fdt_subnode_offset() finds a subnode of the node at structure block * offset parentoffset with the given name. name may include a unit * address, in which case fdt_subnode_offset() will find the subnode * with that unit address, or the unit address may be omitted, in * which case fdt_subnode_offset() will find an arbitrary subnode * whose name excluding unit address matches the given name. * * returns: * structure block offset of the requested subnode (>=0), on success * -FDT_ERR_NOTFOUND, if the requested subnode does not exist * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name); /** * fdt_path_offset_namelen - find a tree node by its full path * @fdt: pointer to the device tree blob * @path: full path of the node to locate * @namelen: number of characters of path to consider * * Identical to fdt_path_offset(), but only consider the first namelen * characters of path as the path name. */ #ifndef SWIG /* Not available in Python */ int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen); #endif /** * fdt_path_offset - find a tree node by its full path * @fdt: pointer to the device tree blob * @path: full path of the node to locate * * fdt_path_offset() finds a node of a given path in the device tree. * Each path component may omit the unit address portion, but the * results of this are undefined if any such path component is * ambiguous (that is if there are multiple nodes at the relevant * level matching the given component, differentiated only by unit * address). * * returns: * structure block offset of the node with the requested path (>=0), on * success * -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid * -FDT_ERR_NOTFOUND, if the requested node does not exist * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_path_offset(const void *fdt, const char *path); /** * fdt_get_name - retrieve the name of a given node * @fdt: pointer to the device tree blob * @nodeoffset: structure block offset of the starting node * @lenp: pointer to an integer variable (will be overwritten) or NULL * * fdt_get_name() retrieves the name (including unit address) of the * device tree node at structure block offset nodeoffset. If lenp is * non-NULL, the length of this name is also returned, in the integer * pointed to by lenp. * * returns: * pointer to the node's name, on success * If lenp is non-NULL, *lenp contains the length of that name * (>=0) * NULL, on error * if lenp is non-NULL *lenp contains an error code (<0): * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings */ const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp); /** * fdt_first_property_offset - find the offset of a node's first property * @fdt: pointer to the device tree blob * @nodeoffset: structure block offset of a node * * fdt_first_property_offset() finds the first property of the node at * the given structure block offset. * * returns: * structure block offset of the property (>=0), on success * -FDT_ERR_NOTFOUND, if the requested node has no properties * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_first_property_offset(const void *fdt, int nodeoffset); /** * fdt_next_property_offset - step through a node's properties * @fdt: pointer to the device tree blob * @offset: structure block offset of a property * * fdt_next_property_offset() finds the property immediately after the * one at the given structure block offset. This will be a property * of the same node as the given property. * * returns: * structure block offset of the next property (>=0), on success * -FDT_ERR_NOTFOUND, if the given property is the last in its node * -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_next_property_offset(const void *fdt, int offset); /** * fdt_for_each_property_offset - iterate over all properties of a node * * @property_offset: property offset (int, lvalue) * @fdt: FDT blob (const void *) * @node: node offset (int) * * This is actually a wrapper around a for loop and would be used like so: * * fdt_for_each_property_offset(property, fdt, node) { * Use property * ... * } * * if ((property < 0) && (property != -FDT_ERR_NOT_FOUND)) { * Error handling * } * * Note that this is implemented as a macro and property is used as * iterator in the loop. The node variable can be constant or even a * literal. */ #define fdt_for_each_property_offset(property, fdt, node) \ for (property = fdt_first_property_offset(fdt, node); \ property >= 0; \ property = fdt_next_property_offset(fdt, property)) /** * fdt_get_property_by_offset - retrieve the property at a given offset * @fdt: pointer to the device tree blob * @offset: offset of the property to retrieve * @lenp: pointer to an integer variable (will be overwritten) or NULL * * fdt_get_property_by_offset() retrieves a pointer to the * fdt_property structure within the device tree blob at the given * offset. If lenp is non-NULL, the length of the property value is * also returned, in the integer pointed to by lenp. * * Note that this code only works on device tree versions >= 16. fdt_getprop() * works on all versions. * * returns: * pointer to the structure representing the property * if lenp is non-NULL, *lenp contains the length of the property * value (>=0) * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ const struct fdt_property *fdt_get_property_by_offset(const void *fdt, int offset, int *lenp); /** * fdt_get_property_namelen - find a property based on substring * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to find * @name: name of the property to find * @namelen: number of characters of name to consider * @lenp: pointer to an integer variable (will be overwritten) or NULL * * Identical to fdt_get_property(), but only examine the first namelen * characters of name for matching the property name. */ #ifndef SWIG /* Not available in Python */ const struct fdt_property *fdt_get_property_namelen(const void *fdt, int nodeoffset, const char *name, int namelen, int *lenp); #endif /** * fdt_get_property - find a given property in a given node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to find * @name: name of the property to find * @lenp: pointer to an integer variable (will be overwritten) or NULL * * fdt_get_property() retrieves a pointer to the fdt_property * structure within the device tree blob corresponding to the property * named 'name' of the node at offset nodeoffset. If lenp is * non-NULL, the length of the property value is also returned, in the * integer pointed to by lenp. * * returns: * pointer to the structure representing the property * if lenp is non-NULL, *lenp contains the length of the property * value (>=0) * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_NOTFOUND, node does not have named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, const char *name, int *lenp); static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset, const char *name, int *lenp) { return (struct fdt_property *)(uintptr_t) fdt_get_property(fdt, nodeoffset, name, lenp); } /** * fdt_getprop_by_offset - retrieve the value of a property at a given offset * @fdt: pointer to the device tree blob * @ffset: offset of the property to read * @namep: pointer to a string variable (will be overwritten) or NULL * @lenp: pointer to an integer variable (will be overwritten) or NULL * * fdt_getprop_by_offset() retrieves a pointer to the value of the * property at structure block offset 'offset' (this will be a pointer * to within the device blob itself, not a copy of the value). If * lenp is non-NULL, the length of the property value is also * returned, in the integer pointed to by lenp. If namep is non-NULL, * the property's namne will also be returned in the char * pointed to * by namep (this will be a pointer to within the device tree's string * block, not a new copy of the name). * * returns: * pointer to the property's value * if lenp is non-NULL, *lenp contains the length of the property * value (>=0) * if namep is non-NULL *namep contiains a pointer to the property * name. * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ #ifndef SWIG /* This function is not useful in Python */ const void *fdt_getprop_by_offset(const void *fdt, int offset, const char **namep, int *lenp); #endif /** * fdt_getprop_namelen - get property value based on substring * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to find * @name: name of the property to find * @namelen: number of characters of name to consider * @lenp: pointer to an integer variable (will be overwritten) or NULL * * Identical to fdt_getprop(), but only examine the first namelen * characters of name for matching the property name. */ #ifndef SWIG /* Not available in Python */ const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, const char *name, int namelen, int *lenp); static inline void *fdt_getprop_namelen_w(void *fdt, int nodeoffset, const char *name, int namelen, int *lenp) { return (void *)(uintptr_t)fdt_getprop_namelen(fdt, nodeoffset, name, namelen, lenp); } #endif /** * fdt_getprop - retrieve the value of a given property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to find * @name: name of the property to find * @lenp: pointer to an integer variable (will be overwritten) or NULL * * fdt_getprop() retrieves a pointer to the value of the property * named 'name' of the node at offset nodeoffset (this will be a * pointer to within the device blob itself, not a copy of the value). * If lenp is non-NULL, the length of the property value is also * returned, in the integer pointed to by lenp. * * returns: * pointer to the property's value * if lenp is non-NULL, *lenp contains the length of the property * value (>=0) * NULL, on error * if lenp is non-NULL, *lenp contains an error code (<0): * -FDT_ERR_NOTFOUND, node does not have named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE * tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ const void *fdt_getprop(const void *fdt, int nodeoffset, const char *name, int *lenp); static inline void *fdt_getprop_w(void *fdt, int nodeoffset, const char *name, int *lenp) { return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp); } /** * fdt_get_phandle - retrieve the phandle of a given node * @fdt: pointer to the device tree blob * @nodeoffset: structure block offset of the node * * fdt_get_phandle() retrieves the phandle of the device tree node at * structure block offset nodeoffset. * * returns: * the phandle of the node at nodeoffset, on success (!= 0, != -1) * 0, if the node has no phandle, or another error occurs */ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset); /** * fdt_get_alias_namelen - get alias based on substring * @fdt: pointer to the device tree blob * @name: name of the alias th look up * @namelen: number of characters of name to consider * * Identical to fdt_get_alias(), but only examine the first namelen * characters of name for matching the alias name. */ #ifndef SWIG /* Not available in Python */ const char *fdt_get_alias_namelen(const void *fdt, const char *name, int namelen); #endif /** * fdt_get_alias - retrieve the path referenced by a given alias * @fdt: pointer to the device tree blob * @name: name of the alias th look up * * fdt_get_alias() retrieves the value of a given alias. That is, the * value of the property named 'name' in the node /aliases. * * returns: * a pointer to the expansion of the alias named 'name', if it exists * NULL, if the given alias or the /aliases node does not exist */ const char *fdt_get_alias(const void *fdt, const char *name); /** * fdt_get_path - determine the full path of a node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose path to find * @buf: character buffer to contain the returned path (will be overwritten) * @buflen: size of the character buffer at buf * * fdt_get_path() computes the full path of the node at offset * nodeoffset, and records that path in the buffer at buf. * * NOTE: This function is expensive, as it must scan the device tree * structure from the start to nodeoffset. * * returns: * 0, on success * buf contains the absolute path of the node at * nodeoffset, as a NUL-terminated string. * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1) * characters and will not fit in the given buffer. * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen); /** * fdt_supernode_atdepth_offset - find a specific ancestor of a node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose parent to find * @supernodedepth: depth of the ancestor to find * @nodedepth: pointer to an integer variable (will be overwritten) or NULL * * fdt_supernode_atdepth_offset() finds an ancestor of the given node * at a specific depth from the root (where the root itself has depth * 0, its immediate subnodes depth 1 and so forth). So * fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL); * will always return 0, the offset of the root node. If the node at * nodeoffset has depth D, then: * fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL); * will return nodeoffset itself. * * NOTE: This function is expensive, as it must scan the device tree * structure from the start to nodeoffset. * * returns: * structure block offset of the node at node offset's ancestor * of depth supernodedepth (>=0), on success * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of * nodeoffset * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, int supernodedepth, int *nodedepth); /** * fdt_node_depth - find the depth of a given node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose parent to find * * fdt_node_depth() finds the depth of a given node. The root node * has depth 0, its immediate subnodes depth 1 and so forth. * * NOTE: This function is expensive, as it must scan the device tree * structure from the start to nodeoffset. * * returns: * depth of the node at nodeoffset (>=0), on success * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_depth(const void *fdt, int nodeoffset); /** * fdt_parent_offset - find the parent of a given node * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose parent to find * * fdt_parent_offset() locates the parent node of a given node (that * is, it finds the offset of the node which contains the node at * nodeoffset as a subnode). * * NOTE: This function is expensive, as it must scan the device tree * structure from the start to nodeoffset, *twice*. * * returns: * structure block offset of the parent of the node at nodeoffset * (>=0), on success * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_parent_offset(const void *fdt, int nodeoffset); /** * fdt_node_offset_by_prop_value - find nodes with a given property value * @fdt: pointer to the device tree blob * @startoffset: only find nodes after this offset * @propname: property name to check * @propval: property value to search for * @proplen: length of the value in propval * * fdt_node_offset_by_prop_value() returns the offset of the first * node after startoffset, which has a property named propname whose * value is of length proplen and has value equal to propval; or if * startoffset is -1, the very first such node in the tree. * * To iterate through all nodes matching the criterion, the following * idiom can be used: * offset = fdt_node_offset_by_prop_value(fdt, -1, propname, * propval, proplen); * while (offset != -FDT_ERR_NOTFOUND) { * // other code here * offset = fdt_node_offset_by_prop_value(fdt, offset, propname, * propval, proplen); * } * * Note the -1 in the first call to the function, if 0 is used here * instead, the function will never locate the root node, even if it * matches the criterion. * * returns: * structure block offset of the located node (>= 0, >startoffset), * on success * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the * tree after startoffset * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, const char *propname, const void *propval, int proplen); /** * fdt_node_offset_by_phandle - find the node with a given phandle * @fdt: pointer to the device tree blob * @phandle: phandle value * * fdt_node_offset_by_phandle() returns the offset of the node * which has the given phandle value. If there is more than one node * in the tree with the given phandle (an invalid tree), results are * undefined. * * returns: * structure block offset of the located node (>= 0), on success * -FDT_ERR_NOTFOUND, no node with that phandle exists * -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1) * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle); /** * fdt_node_check_compatible: check a node's compatible property * @fdt: pointer to the device tree blob * @nodeoffset: offset of a tree node * @compatible: string to match against * * * fdt_node_check_compatible() returns 0 if the given node contains a * 'compatible' property with the given string as one of its elements, * it returns non-zero otherwise, or on error. * * returns: * 0, if the node has a 'compatible' property listing the given string * 1, if the node has a 'compatible' property, but it does not list * the given string * -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property * -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_check_compatible(const void *fdt, int nodeoffset, const char *compatible); /** * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value * @fdt: pointer to the device tree blob * @startoffset: only find nodes after this offset * @compatible: 'compatible' string to match against * * fdt_node_offset_by_compatible() returns the offset of the first * node after startoffset, which has a 'compatible' property which * lists the given compatible string; or if startoffset is -1, the * very first such node in the tree. * * To iterate through all nodes matching the criterion, the following * idiom can be used: * offset = fdt_node_offset_by_compatible(fdt, -1, compatible); * while (offset != -FDT_ERR_NOTFOUND) { * // other code here * offset = fdt_node_offset_by_compatible(fdt, offset, compatible); * } * * Note the -1 in the first call to the function, if 0 is used here * instead, the function will never locate the root node, even if it * matches the criterion. * * returns: * structure block offset of the located node (>= 0, >startoffset), * on success * -FDT_ERR_NOTFOUND, no node matching the criterion exists in the * tree after startoffset * -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, standard meanings */ int fdt_node_offset_by_compatible(const void *fdt, int startoffset, const char *compatible); /** * fdt_stringlist_contains - check a string list property for a string * @strlist: Property containing a list of strings to check * @listlen: Length of property * @str: String to search for * * This is a utility function provided for convenience. The list contains * one or more strings, each terminated by \0, as is found in a device tree * "compatible" property. * * @return: 1 if the string is found in the list, 0 not found, or invalid list */ int fdt_stringlist_contains(const char *strlist, int listlen, const char *str); /** * fdt_stringlist_count - count the number of strings in a string list * @fdt: pointer to the device tree blob * @nodeoffset: offset of a tree node * @property: name of the property containing the string list * @return: * the number of strings in the given property * -FDT_ERR_BADVALUE if the property value is not NUL-terminated * -FDT_ERR_NOTFOUND if the property does not exist */ int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property); /** * fdt_stringlist_search - find a string in a string list and return its index * @fdt: pointer to the device tree blob * @nodeoffset: offset of a tree node * @property: name of the property containing the string list * @string: string to look up in the string list * * Note that it is possible for this function to succeed on property values * that are not NUL-terminated. That's because the function will stop after * finding the first occurrence of @string. This can for example happen with * small-valued cell properties, such as #address-cells, when searching for * the empty string. * * @return: * the index of the string in the list of strings * -FDT_ERR_BADVALUE if the property value is not NUL-terminated * -FDT_ERR_NOTFOUND if the property does not exist or does not contain * the given string */ int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, const char *string); /** * fdt_stringlist_get() - obtain the string at a given index in a string list * @fdt: pointer to the device tree blob * @nodeoffset: offset of a tree node * @property: name of the property containing the string list * @index: index of the string to return * @lenp: return location for the string length or an error code on failure * * Note that this will successfully extract strings from properties with * non-NUL-terminated values. For example on small-valued cell properties * this function will return the empty string. * * If non-NULL, the length of the string (on success) or a negative error-code * (on failure) will be stored in the integer pointer to by lenp. * * @return: * A pointer to the string at the given index in the string list or NULL on * failure. On success the length of the string will be stored in the memory * location pointed to by the lenp parameter, if non-NULL. On failure one of * the following negative error codes will be returned in the lenp parameter * (if non-NULL): * -FDT_ERR_BADVALUE if the property value is not NUL-terminated * -FDT_ERR_NOTFOUND if the property does not exist */ const char *fdt_stringlist_get(const void *fdt, int nodeoffset, const char *property, int index, int *lenp); /**********************************************************************/ /* Read-only functions (addressing related) */ /**********************************************************************/ /** * FDT_MAX_NCELLS - maximum value for #address-cells and #size-cells * * This is the maximum value for #address-cells, #size-cells and * similar properties that will be processed by libfdt. IEE1275 * requires that OF implementations handle values up to 4. * Implementations may support larger values, but in practice higher * values aren't used. */ #define FDT_MAX_NCELLS 4 /** * fdt_address_cells - retrieve address size for a bus represented in the tree * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node to find the address size for * * When the node has a valid #address-cells property, returns its value. * * returns: * 0 <= n < FDT_MAX_NCELLS, on success * 2, if the node has no #address-cells property * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid * #address-cells property * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_address_cells(const void *fdt, int nodeoffset); /** * fdt_size_cells - retrieve address range size for a bus represented in the * tree * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node to find the address range size for * * When the node has a valid #size-cells property, returns its value. * * returns: * 0 <= n < FDT_MAX_NCELLS, on success * 2, if the node has no #address-cells property * -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid * #size-cells property * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_size_cells(const void *fdt, int nodeoffset); /**********************************************************************/ /* Write-in-place functions */ /**********************************************************************/ /** * fdt_setprop_inplace_namelen_partial - change a property's value, * but not its size * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @namelen: number of characters of name to consider * @idx: index of the property to change in the array * @val: pointer to data to replace the property value with * @len: length of the property value * * Identical to fdt_setprop_inplace(), but modifies the given property * starting from the given index, and using only the first characters * of the name. It is useful when you want to manipulate only one value of * an array and you have a string that doesn't end with \0. */ #ifndef SWIG /* Not available in Python */ int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, const char *name, int namelen, uint32_t idx, const void *val, int len); #endif /** * fdt_setprop_inplace - change a property's value, but not its size * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: pointer to data to replace the property value with * @len: length of the property value * * fdt_setprop_inplace() replaces the value of a given property with * the data in val, of length len. This function cannot change the * size of a property, and so will only work if len is equal to the * current length of the property. * * This function will alter only the bytes in the blob which contain * the given property value, and will not alter or move any other part * of the tree. * * returns: * 0, on success * -FDT_ERR_NOSPACE, if len is not equal to the property's current length * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ #ifndef SWIG /* Not available in Python */ int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, const void *val, int len); #endif /** * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: 32-bit integer value to replace the property with * * fdt_setprop_inplace_u32() replaces the value of a given property * with the 32-bit integer value in val, converting val to big-endian * if necessary. This function cannot change the size of a property, * and so will only work if the property already exists and has length * 4. * * This function will alter only the bytes in the blob which contain * the given property value, and will not alter or move any other part * of the tree. * * returns: * 0, on success * -FDT_ERR_NOSPACE, if the property's length is not equal to 4 * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset, const char *name, uint32_t val) { fdt32_t tmp = cpu_to_fdt32(val); return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: 64-bit integer value to replace the property with * * fdt_setprop_inplace_u64() replaces the value of a given property * with the 64-bit integer value in val, converting val to big-endian * if necessary. This function cannot change the size of a property, * and so will only work if the property already exists and has length * 8. * * This function will alter only the bytes in the blob which contain * the given property value, and will not alter or move any other part * of the tree. * * returns: * 0, on success * -FDT_ERR_NOSPACE, if the property's length is not equal to 8 * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset, const char *name, uint64_t val) { fdt64_t tmp = cpu_to_fdt64(val); return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** * fdt_setprop_inplace_cell - change the value of a single-cell property * * This is an alternative name for fdt_setprop_inplace_u32() */ static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) { return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val); } /** * fdt_nop_property - replace a property with nop tags * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to nop * @name: name of the property to nop * * fdt_nop_property() will replace a given property's representation * in the blob with FDT_NOP tags, effectively removing it from the * tree. * * This function will alter only the bytes in the blob which contain * the property, and will not alter or move any other part of the * tree. * * returns: * 0, on success * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_nop_property(void *fdt, int nodeoffset, const char *name); /** * fdt_nop_node - replace a node (subtree) with nop tags * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node to nop * * fdt_nop_node() will replace a given node's representation in the * blob, including all its subnodes, if any, with FDT_NOP tags, * effectively removing it from the tree. * * This function will alter only the bytes in the blob which contain * the node and its properties and subnodes, and will not alter or * move any other part of the tree. * * returns: * 0, on success * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_nop_node(void *fdt, int nodeoffset); /**********************************************************************/ /* Sequential write functions */ /**********************************************************************/ int fdt_create(void *buf, int bufsize); int fdt_resize(void *fdt, void *buf, int bufsize); int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size); int fdt_finish_reservemap(void *fdt); int fdt_begin_node(void *fdt, const char *name); int fdt_property(void *fdt, const char *name, const void *val, int len); static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val) { fdt32_t tmp = cpu_to_fdt32(val); return fdt_property(fdt, name, &tmp, sizeof(tmp)); } static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val) { fdt64_t tmp = cpu_to_fdt64(val); return fdt_property(fdt, name, &tmp, sizeof(tmp)); } static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val) { return fdt_property_u32(fdt, name, val); } /** * fdt_property_placeholder - add a new property and return a ptr to its value * * @fdt: pointer to the device tree blob * @name: name of property to add * @len: length of property value in bytes * @valp: returns a pointer to where where the value should be placed * * returns: * 0, on success * -FDT_ERR_BADMAGIC, * -FDT_ERR_NOSPACE, standard meanings */ int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp); #define fdt_property_string(fdt, name, str) \ fdt_property(fdt, name, str, strlen(str)+1) int fdt_end_node(void *fdt); int fdt_finish(void *fdt); /**********************************************************************/ /* Read-write functions */ /**********************************************************************/ int fdt_create_empty_tree(void *buf, int bufsize); int fdt_open_into(const void *fdt, void *buf, int bufsize); int fdt_pack(void *fdt); /** * fdt_add_mem_rsv - add one memory reserve map entry * @fdt: pointer to the device tree blob * @address, @size: 64-bit values (native endian) * * Adds a reserve map entry to the given blob reserving a region at * address address of length size. * * This function will insert data into the reserve map and will * therefore change the indexes of some entries in the table. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new reservation entry * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size); /** * fdt_del_mem_rsv - remove a memory reserve map entry * @fdt: pointer to the device tree blob * @n: entry to remove * * fdt_del_mem_rsv() removes the n-th memory reserve map entry from * the blob. * * This function will delete data from the reservation table and will * therefore change the indexes of some entries in the table. * * returns: * 0, on success * -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there * are less than n+1 reserve map entries) * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_del_mem_rsv(void *fdt, int n); /** * fdt_set_name - change the name of a given node * @fdt: pointer to the device tree blob * @nodeoffset: structure block offset of a node * @name: name to give the node * * fdt_set_name() replaces the name (including unit address, if any) * of the given node with the given string. NOTE: this function can't * efficiently check if the new name is unique amongst the given * node's siblings; results are undefined if this function is invoked * with a name equal to one of the given node's siblings. * * This function may insert or delete data from the blob, and will * therefore change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob * to contain the new name * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, standard meanings */ int fdt_set_name(void *fdt, int nodeoffset, const char *name); /** * fdt_setprop - create or change a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: pointer to data to set the property value to * @len: length of the property value * * fdt_setprop() sets the value of the named property in the given * node to the given value and length, creating the property if it * does not already exist. * * This function may insert or delete data from the blob, and will * therefore change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_setprop(void *fdt, int nodeoffset, const char *name, const void *val, int len); /** * fdt_setprop_placeholder - allocate space for a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @len: length of the property value * @prop_data: return pointer to property data * * fdt_setprop_placeholer() allocates the named property in the given node. * If the property exists it is resized. In either case a pointer to the * property data is returned. * * This function may insert or delete data from the blob, and will * therefore change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, int len, void **prop_data); /** * fdt_setprop_u32 - set a property to a 32-bit integer * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: 32-bit integer value for the property (native endian) * * fdt_setprop_u32() sets the value of the named property in the given * node to the given 32-bit integer value (converting to big-endian if * necessary), or creates a new property with that value if it does * not already exist. * * This function may insert or delete data from the blob, and will * therefore change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name, uint32_t val) { fdt32_t tmp = cpu_to_fdt32(val); return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** * fdt_setprop_u64 - set a property to a 64-bit integer * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: 64-bit integer value for the property (native endian) * * fdt_setprop_u64() sets the value of the named property in the given * node to the given 64-bit integer value (converting to big-endian if * necessary), or creates a new property with that value if it does * not already exist. * * This function may insert or delete data from the blob, and will * therefore change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name, uint64_t val) { fdt64_t tmp = cpu_to_fdt64(val); return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** * fdt_setprop_cell - set a property to a single cell value * * This is an alternative name for fdt_setprop_u32() */ static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) { return fdt_setprop_u32(fdt, nodeoffset, name, val); } /** * fdt_setprop_string - set a property to a string value * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @str: string value for the property * * fdt_setprop_string() sets the value of the named property in the * given node to the given string value (using the length of the * string to determine the new length of the property), or creates a * new property with that value if it does not already exist. * * This function may insert or delete data from the blob, and will * therefore change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ #define fdt_setprop_string(fdt, nodeoffset, name, str) \ fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) /** * fdt_setprop_empty - set a property to an empty value * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * * fdt_setprop_empty() sets the value of the named property in the * given node to an empty (zero length) value, or creates a new empty * property if it does not already exist. * * This function may insert or delete data from the blob, and will * therefore change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ #define fdt_setprop_empty(fdt, nodeoffset, name) \ fdt_setprop((fdt), (nodeoffset), (name), NULL, 0) /** * fdt_appendprop - append to or create a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to append to * @val: pointer to data to append to the property value * @len: length of the data to append to the property value * * fdt_appendprop() appends the value to the named property in the * given node, creating the property if it does not already exist. * * This function may insert data into the blob, and will therefore * change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_appendprop(void *fdt, int nodeoffset, const char *name, const void *val, int len); /** * fdt_appendprop_u32 - append a 32-bit integer value to a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: 32-bit integer value to append to the property (native endian) * * fdt_appendprop_u32() appends the given 32-bit integer value * (converting to big-endian if necessary) to the value of the named * property in the given node, or creates a new property with that * value if it does not already exist. * * This function may insert data into the blob, and will therefore * change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_appendprop_u32(void *fdt, int nodeoffset, const char *name, uint32_t val) { fdt32_t tmp = cpu_to_fdt32(val); return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** * fdt_appendprop_u64 - append a 64-bit integer value to a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @val: 64-bit integer value to append to the property (native endian) * * fdt_appendprop_u64() appends the given 64-bit integer value * (converting to big-endian if necessary) to the value of the named * property in the given node, or creates a new property with that * value if it does not already exist. * * This function may insert data into the blob, and will therefore * change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ static inline int fdt_appendprop_u64(void *fdt, int nodeoffset, const char *name, uint64_t val) { fdt64_t tmp = cpu_to_fdt64(val); return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp)); } /** * fdt_appendprop_cell - append a single cell value to a property * * This is an alternative name for fdt_appendprop_u32() */ static inline int fdt_appendprop_cell(void *fdt, int nodeoffset, const char *name, uint32_t val) { return fdt_appendprop_u32(fdt, nodeoffset, name, val); } /** * fdt_appendprop_string - append a string to a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to change * @name: name of the property to change * @str: string value to append to the property * * fdt_appendprop_string() appends the given string to the value of * the named property in the given node, or creates a new property * with that value if it does not already exist. * * This function may insert data into the blob, and will therefore * change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there is insufficient free space in the blob to * contain the new property value * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_TRUNCATED, standard meanings */ #define fdt_appendprop_string(fdt, nodeoffset, name, str) \ fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1) /** * fdt_delprop - delete a property * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node whose property to nop * @name: name of the property to nop * * fdt_del_property() will delete the given property. * * This function will delete data from the blob, and will therefore * change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_NOTFOUND, node does not have the named property * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_delprop(void *fdt, int nodeoffset, const char *name); /** * fdt_add_subnode_namelen - creates a new node based on substring * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node * @name: name of the subnode to locate * @namelen: number of characters of name to consider * * Identical to fdt_add_subnode(), but use only the first namelen * characters of name as the name of the new node. This is useful for * creating subnodes based on a portion of a larger string, such as a * full path. */ #ifndef SWIG /* Not available in Python */ int fdt_add_subnode_namelen(void *fdt, int parentoffset, const char *name, int namelen); #endif /** * fdt_add_subnode - creates a new node * @fdt: pointer to the device tree blob * @parentoffset: structure block offset of a node * @name: name of the subnode to locate * * fdt_add_subnode() creates a new node as a subnode of the node at * structure block offset parentoffset, with the given name (which * should include the unit address, if any). * * This function will insert data into the blob, and will therefore * change the offsets of some existing nodes. * returns: * structure block offset of the created nodeequested subnode (>=0), on * success * -FDT_ERR_NOTFOUND, if the requested subnode does not exist * -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE * tag * -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of * the given name * -FDT_ERR_NOSPACE, if there is insufficient free space in the * blob to contain the new node * -FDT_ERR_NOSPACE * -FDT_ERR_BADLAYOUT * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings. */ int fdt_add_subnode(void *fdt, int parentoffset, const char *name); /** * fdt_del_node - delete a node (subtree) * @fdt: pointer to the device tree blob * @nodeoffset: offset of the node to nop * * fdt_del_node() will remove the given node, including all its * subnodes if any, from the blob. * * This function will delete data from the blob, and will therefore * change the offsets of some existing nodes. * * returns: * 0, on success * -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTATE, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_del_node(void *fdt, int nodeoffset); /** * fdt_overlay_apply - Applies a DT overlay on a base DT * @fdt: pointer to the base device tree blob * @fdto: pointer to the device tree overlay blob * * fdt_overlay_apply() will apply the given device tree overlay on the * given base device tree. * * Expect the base device tree to be modified, even if the function * returns an error. * * returns: * 0, on success * -FDT_ERR_NOSPACE, there's not enough space in the base device tree * -FDT_ERR_NOTFOUND, the overlay points to some inexistant nodes or * properties in the base DT * -FDT_ERR_BADPHANDLE, * -FDT_ERR_BADOVERLAY, * -FDT_ERR_NOPHANDLES, * -FDT_ERR_INTERNAL, * -FDT_ERR_BADLAYOUT, * -FDT_ERR_BADMAGIC, * -FDT_ERR_BADOFFSET, * -FDT_ERR_BADPATH, * -FDT_ERR_BADVERSION, * -FDT_ERR_BADSTRUCTURE, * -FDT_ERR_BADSTATE, * -FDT_ERR_TRUNCATED, standard meanings */ int fdt_overlay_apply(void *fdt, void *fdto); /**********************************************************************/ /* Debugging / informational functions */ /**********************************************************************/ const char *fdt_strerror(int errval); #endif /* LIBFDT_H */ trusted-firmware-a-2.2/include/lib/libfdt/libfdt_env.h000066400000000000000000000115521355360272700230370ustar00rootroot00000000000000#ifndef LIBFDT_ENV_H #define LIBFDT_ENV_H /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * Copyright 2012 Kim Phillips, Freescale Semiconductor. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #ifdef __CHECKER__ #define FDT_FORCE __attribute__((force)) #define FDT_BITWISE __attribute__((bitwise)) #else #define FDT_FORCE #define FDT_BITWISE #endif typedef uint16_t FDT_BITWISE fdt16_t; typedef uint32_t FDT_BITWISE fdt32_t; typedef uint64_t FDT_BITWISE fdt64_t; #define EXTRACT_BYTE(x, n) ((unsigned long long)((uint8_t *)&x)[n]) #define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1)) #define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \ (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3)) #define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \ (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \ (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \ (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7)) static inline uint16_t fdt16_to_cpu(fdt16_t x) { return (FDT_FORCE uint16_t)CPU_TO_FDT16(x); } static inline fdt16_t cpu_to_fdt16(uint16_t x) { return (FDT_FORCE fdt16_t)CPU_TO_FDT16(x); } static inline uint32_t fdt32_to_cpu(fdt32_t x) { return (FDT_FORCE uint32_t)CPU_TO_FDT32(x); } static inline fdt32_t cpu_to_fdt32(uint32_t x) { return (FDT_FORCE fdt32_t)CPU_TO_FDT32(x); } static inline uint64_t fdt64_to_cpu(fdt64_t x) { return (FDT_FORCE uint64_t)CPU_TO_FDT64(x); } static inline fdt64_t cpu_to_fdt64(uint64_t x) { return (FDT_FORCE fdt64_t)CPU_TO_FDT64(x); } #undef CPU_TO_FDT64 #undef CPU_TO_FDT32 #undef CPU_TO_FDT16 #undef EXTRACT_BYTE #ifdef __APPLE__ #include /* strnlen() is not available on Mac OS < 10.7 */ # if !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < \ MAC_OS_X_VERSION_10_7) #define strnlen fdt_strnlen /* * fdt_strnlen: returns the length of a string or max_count - which ever is * smallest. * Input 1 string: the string whose size is to be determined * Input 2 max_count: the maximum value returned by this function * Output: length of the string or max_count (the smallest of the two) */ static inline size_t fdt_strnlen(const char *string, size_t max_count) { const char *p = memchr(string, 0, max_count); return p ? p - string : max_count; } #endif /* !defined(MAC_OS_X_VERSION_10_7) || (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7) */ #endif /* __APPLE__ */ #endif /* LIBFDT_ENV_H */ trusted-firmware-a-2.2/include/lib/mmio.h000066400000000000000000000030061355360272700204130ustar00rootroot00000000000000/* * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MMIO_H #define MMIO_H #include static inline void mmio_write_8(uintptr_t addr, uint8_t value) { *(volatile uint8_t*)addr = value; } static inline uint8_t mmio_read_8(uintptr_t addr) { return *(volatile uint8_t*)addr; } static inline void mmio_write_16(uintptr_t addr, uint16_t value) { *(volatile uint16_t*)addr = value; } static inline uint16_t mmio_read_16(uintptr_t addr) { return *(volatile uint16_t*)addr; } static inline void mmio_clrsetbits_16(uintptr_t addr, uint16_t clear, uint16_t set) { mmio_write_16(addr, (mmio_read_16(addr) & ~clear) | set); } static inline void mmio_write_32(uintptr_t addr, uint32_t value) { *(volatile uint32_t*)addr = value; } static inline uint32_t mmio_read_32(uintptr_t addr) { return *(volatile uint32_t*)addr; } static inline void mmio_write_64(uintptr_t addr, uint64_t value) { *(volatile uint64_t*)addr = value; } static inline uint64_t mmio_read_64(uintptr_t addr) { return *(volatile uint64_t*)addr; } static inline void mmio_clrbits_32(uintptr_t addr, uint32_t clear) { mmio_write_32(addr, mmio_read_32(addr) & ~clear); } static inline void mmio_setbits_32(uintptr_t addr, uint32_t set) { mmio_write_32(addr, mmio_read_32(addr) | set); } static inline void mmio_clrsetbits_32(uintptr_t addr, uint32_t clear, uint32_t set) { mmio_write_32(addr, (mmio_read_32(addr) & ~clear) | set); } #endif /* MMIO_H */ trusted-firmware-a-2.2/include/lib/object_pool.h000066400000000000000000000040721355360272700217550ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef OBJECT_POOL_H #define OBJECT_POOL_H #include #include #include /* * Pool of statically allocated objects. * * Objects can be reserved but not freed. This is by design and it is not a * limitation. We do not want to introduce complexity induced by memory freeing, * such as use-after-free bugs, memory fragmentation and so on. * * The object size and capacity of the pool are fixed at build time. So is the * address of the objects back store. */ struct object_pool { /* Size of 1 object in the pool in byte unit. */ const size_t obj_size; /* Number of objects in the pool. */ const size_t capacity; /* Objects back store. */ void *const objects; /* How many objects are currently allocated. */ size_t used; }; /* Create a static pool of objects. */ #define OBJECT_POOL(_pool_name, _obj_backstore, _obj_size, _obj_count) \ struct object_pool _pool_name = { \ .objects = (_obj_backstore), \ .obj_size = (_obj_size), \ .capacity = (_obj_count), \ .used = 0U, \ } /* Create a static pool of objects out of an array of pre-allocated objects. */ #define OBJECT_POOL_ARRAY(_pool_name, _obj_array) \ OBJECT_POOL(_pool_name, (_obj_array), \ sizeof((_obj_array)[0]), ARRAY_SIZE(_obj_array)) /* * Allocate 'count' objects from a pool. * Return the address of the first object. Panic on error. */ static inline void *pool_alloc_n(struct object_pool *pool, size_t count) { if (pool->used + count > pool->capacity) { ERROR("Cannot allocate %zu objects out of pool (%zu objects left).\n", count, pool->capacity - pool->used); panic(); } void *obj = (char *)(pool->objects) + pool->obj_size * pool->used; pool->used += count; return obj; } /* * Allocate 1 object from a pool. * Return the address of the object. Panic on error. */ static inline void *pool_alloc(struct object_pool *pool) { return pool_alloc_n(pool, 1U); } #endif /* OBJECT_POOL_H */ trusted-firmware-a-2.2/include/lib/optee_utils.h000066400000000000000000000005371355360272700220140ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef OPTEE_UTILS_H #define OPTEE_UTILS_H #include int parse_optee_header(entry_point_info_t *header_ep, image_info_t *pager_image_info, image_info_t *paged_image_info); #endif /* OPTEE_UTILS_H */ trusted-firmware-a-2.2/include/lib/pmf/000077500000000000000000000000001355360272700200645ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/pmf/pmf.h000066400000000000000000000126371355360272700210300ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PMF_H #define PMF_H #include #include #include /* * Constants used for/by PMF services. */ #define PMF_ARM_TIF_IMPL_ID U(0x41) #define PMF_TID_SHIFT 0 #define PMF_TID_MASK (U(0xFF) << PMF_TID_SHIFT) #define PMF_SVC_ID_SHIFT 10 #define PMF_SVC_ID_MASK (U(0x3F) << PMF_SVC_ID_SHIFT) #define PMF_IMPL_ID_SHIFT 24 #define PMF_IMPL_ID_MASK (U(0xFF) << PMF_IMPL_ID_SHIFT) /* * Flags passed to PMF_REGISTER_SERVICE */ #define PMF_STORE_ENABLE (1 << 0) #define PMF_DUMP_ENABLE (1 << 1) /* * Flags passed to PMF_GET_TIMESTAMP_XXX * and PMF_CAPTURE_TIMESTAMP */ #define PMF_CACHE_MAINT (U(1) << 0) #define PMF_NO_CACHE_MAINT U(0) /* * Defines for PMF SMC function ids. */ #define PMF_SMC_GET_TIMESTAMP_32 U(0x82000010) #define PMF_SMC_GET_TIMESTAMP_64 U(0xC2000010) #define PMF_NUM_SMC_CALLS 2 /* * The macros below are used to identify * PMF calls from the SMC function ID. */ #define PMF_FID_MASK U(0xffe0) #define PMF_FID_VALUE U(0) #define is_pmf_fid(_fid) (((_fid) & PMF_FID_MASK) == PMF_FID_VALUE) /* Following are the supported PMF service IDs */ #define PMF_PSCI_STAT_SVC_ID 0 #define PMF_RT_INSTR_SVC_ID 1 #if ENABLE_PMF /* * Convenience macros for capturing time-stamp. */ #define PMF_DECLARE_CAPTURE_TIMESTAMP(_name) \ void pmf_capture_timestamp_with_cache_maint_ ## _name( \ unsigned int tid, \ unsigned long long ts); \ void pmf_capture_timestamp_ ## _name( \ unsigned int tid, \ unsigned long long ts); #define PMF_CAPTURE_TIMESTAMP(_name, _tid, _flags) \ do { \ unsigned long long ts = read_cntpct_el0(); \ if (((_flags) & PMF_CACHE_MAINT) != 0U) \ pmf_capture_timestamp_with_cache_maint_ ## _name((_tid), ts);\ else \ pmf_capture_timestamp_ ## _name((_tid), ts); \ } while (0) #define PMF_CAPTURE_AND_GET_TIMESTAMP(_name, _tid, _flags, _tsval) \ do { \ (_tsval) = read_cntpct_el0(); \ CASSERT(sizeof(_tsval) == sizeof(unsigned long long), invalid_tsval_size);\ if (((_flags) & PMF_CACHE_MAINT) != 0U) \ pmf_capture_timestamp_with_cache_maint_ ## _name((_tid), (_tsval));\ else \ pmf_capture_timestamp_ ## _name((_tid), (_tsval));\ } while (0) #define PMF_WRITE_TIMESTAMP(_name, _tid, _flags, _wrval) \ do { \ CASSERT(sizeof(_wrval) == sizeof(unsigned long long), invalid_wrval_size);\ if (((_flags) & PMF_CACHE_MAINT) != 0U) \ pmf_capture_timestamp_with_cache_maint_ ## _name((_tid), (_wrval));\ else \ pmf_capture_timestamp_ ## _name((_tid), (_wrval));\ } while (0) /* * Convenience macros for retrieving time-stamp. */ #define PMF_DECLARE_GET_TIMESTAMP(_name) \ unsigned long long pmf_get_timestamp_by_index_ ## _name(\ unsigned int tid, \ unsigned int cpuid, \ unsigned int flags); \ unsigned long long pmf_get_timestamp_by_mpidr_ ## _name(\ unsigned int tid, \ u_register_t mpidr, \ unsigned int flags); #define PMF_GET_TIMESTAMP_BY_MPIDR(_name, _tid, _mpidr, _flags, _tsval)\ _tsval = pmf_get_timestamp_by_mpidr_ ## _name(_tid, _mpidr, _flags) #define PMF_GET_TIMESTAMP_BY_INDEX(_name, _tid, _cpuid, _flags, _tsval)\ _tsval = pmf_get_timestamp_by_index_ ## _name(_tid, _cpuid, _flags) /* Convenience macros to register a PMF service.*/ /* * This macro is used to register a PMF Service. It allocates PMF memory * and defines default service-specific PMF functions. */ #define PMF_REGISTER_SERVICE(_name, _svcid, _totalid, _flags) \ PMF_ALLOCATE_TIMESTAMP_MEMORY(_name, _totalid) \ PMF_DEFINE_CAPTURE_TIMESTAMP(_name, _flags) \ PMF_DEFINE_GET_TIMESTAMP(_name) /* * This macro is used to register a PMF service, including an * SMC interface to that service. */ #define PMF_REGISTER_SERVICE_SMC(_name, _svcid, _totalid, _flags)\ PMF_REGISTER_SERVICE(_name, _svcid, _totalid, _flags) \ PMF_DEFINE_SERVICE_DESC(_name, PMF_ARM_TIF_IMPL_ID, \ _svcid, _totalid, NULL, \ pmf_get_timestamp_by_mpidr_ ## _name) /* * This macro is used to register a PMF service that has an SMC interface * but provides its own service-specific PMF functions. */ #define PMF_REGISTER_SERVICE_SMC_OWN(_name, _implid, _svcid, _totalid, \ _init, _getts) \ PMF_DEFINE_SERVICE_DESC(_name, _implid, _svcid, _totalid, \ _init, _getts) #else #define PMF_REGISTER_SERVICE(_name, _svcid, _totalid, _flags) #define PMF_REGISTER_SERVICE_SMC(_name, _svcid, _totalid, _flags) #define PMF_REGISTER_SERVICE_SMC_OWN(_name, _implid, _svcid, _totalid, \ _init, _getts) #define PMF_DECLARE_CAPTURE_TIMESTAMP(_name) #define PMF_DECLARE_GET_TIMESTAMP(_name) #define PMF_CAPTURE_TIMESTAMP(_name, _tid, _flags) #define PMF_GET_TIMESTAMP_BY_MPIDR(_name, _tid, _mpidr, _flags, _tsval) #define PMF_GET_TIMESTAMP_BY_INDEX(_name, _tid, _cpuid, _flags, _tsval) #endif /* ENABLE_PMF */ /******************************************************************************* * Function & variable prototypes ******************************************************************************/ /* PMF common functions */ int pmf_get_timestamp_smc(unsigned int tid, u_register_t mpidr, unsigned int flags, unsigned long long *ts_value); int pmf_setup(void); uintptr_t pmf_smc_handler(unsigned int 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); #endif /* PMF_H */ trusted-firmware-a-2.2/include/lib/pmf/pmf_asm_macros.S000066400000000000000000000012321355360272700231740ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PMF_ASM_MACROS_S #define PMF_ASM_MACROS_S #define PMF_TS_SIZE 8 /* * This macro calculates the address of the per-cpu timestamp * for the given service name and local timestamp id. * Clobbers: x0 - x9 */ .macro pmf_calc_timestamp_addr _name, _tid mov x9, x30 bl plat_my_core_pos mov x30, x9 adr x2, __PMF_PERCPU_TIMESTAMP_END__ adr x1, __PMF_TIMESTAMP_START__ sub x1, x2, x1 mov x2, #(\_tid * PMF_TS_SIZE) madd x0, x0, x1, x2 adr x1, pmf_ts_mem_\_name add x0, x0, x1 .endm #endif /* PMF_ASM_MACROS_S */ trusted-firmware-a-2.2/include/lib/pmf/pmf_helpers.h000066400000000000000000000117571355360272700225540ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PMF_HELPERS_H #define PMF_HELPERS_H #include #include #include #include #include #include /* * Prototype for PMF service functions. */ typedef int (*pmf_svc_init_t)(void); typedef unsigned long long (*pmf_svc_get_ts_t)(unsigned int tid, u_register_t mpidr, unsigned int flags); /* * This is the definition of PMF service desc. */ typedef struct pmf_svc_desc { /* Structure version information */ param_header_t h; /* Name of the PMF service */ const char *name; /* PMF service config: Implementer id, Service id and total id*/ unsigned int svc_config; /* PMF service initialization handler */ pmf_svc_init_t init; /* PMF service time-stamp retrieval handler */ pmf_svc_get_ts_t get_ts; } pmf_svc_desc_t; /* * Convenience macro to allocate memory for a PMF service. * * The extern declaration is there to satisfy MISRA C-2012 rule 8.4. */ #define PMF_ALLOCATE_TIMESTAMP_MEMORY(_name, _total_id) \ extern unsigned long long pmf_ts_mem_ ## _name[_total_id]; \ unsigned long long pmf_ts_mem_ ## _name[_total_id] \ __aligned(CACHE_WRITEBACK_GRANULE) \ __section("pmf_timestamp_array") \ __used; /* * Convenience macro to validate tid index for the given TS array. */ #define PMF_VALIDATE_TID(_name, _tid) \ assert((_tid & PMF_TID_MASK) < (ARRAY_SIZE(pmf_ts_mem_ ## _name))) /* * Convenience macros for capturing time-stamp. * * The extern declaration is there to satisfy MISRA C-2012 rule 8.4. */ #define PMF_DEFINE_CAPTURE_TIMESTAMP(_name, _flags) \ void pmf_capture_timestamp_ ## _name( \ unsigned int tid, \ unsigned long long ts); \ void pmf_capture_timestamp_ ## _name( \ unsigned int tid, \ unsigned long long ts) \ { \ CASSERT(_flags, select_proper_config); \ PMF_VALIDATE_TID(_name, tid); \ uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name; \ if (((_flags) & PMF_STORE_ENABLE) != 0) \ __pmf_store_timestamp(base_addr, tid, ts); \ if (((_flags) & PMF_DUMP_ENABLE) != 0) \ __pmf_dump_timestamp(tid, ts); \ } \ void pmf_capture_timestamp_with_cache_maint_ ## _name( \ unsigned int tid, \ unsigned long long ts); \ void pmf_capture_timestamp_with_cache_maint_ ## _name( \ unsigned int tid, \ unsigned long long ts) \ { \ CASSERT(_flags, select_proper_config); \ PMF_VALIDATE_TID(_name, tid); \ uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name; \ if (((_flags) & PMF_STORE_ENABLE) != 0) \ __pmf_store_timestamp_with_cache_maint(base_addr, tid, ts);\ if (((_flags) & PMF_DUMP_ENABLE) != 0) \ __pmf_dump_timestamp(tid, ts); \ } /* * Convenience macros for retrieving time-stamp. * * The extern declaration is there to satisfy MISRA C-2012 rule 8.4. */ #define PMF_DEFINE_GET_TIMESTAMP(_name) \ unsigned long long pmf_get_timestamp_by_index_ ## _name( \ unsigned int tid, unsigned int cpuid, unsigned int flags);\ unsigned long long pmf_get_timestamp_by_index_ ## _name( \ unsigned int tid, unsigned int cpuid, unsigned int flags)\ { \ PMF_VALIDATE_TID(_name, tid); \ uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name; \ return __pmf_get_timestamp(base_addr, tid, cpuid, flags);\ } \ unsigned long long pmf_get_timestamp_by_mpidr_ ## _name( \ unsigned int tid, u_register_t mpidr, unsigned int flags);\ unsigned long long pmf_get_timestamp_by_mpidr_ ## _name( \ unsigned int tid, u_register_t mpidr, unsigned int flags)\ { \ PMF_VALIDATE_TID(_name, tid); \ uintptr_t base_addr = (uintptr_t) pmf_ts_mem_ ## _name; \ return __pmf_get_timestamp(base_addr, tid, \ plat_core_pos_by_mpidr(mpidr), flags); \ } /* * Convenience macro to register a PMF service. * This is needed for services that require SMC handling. */ #define PMF_DEFINE_SERVICE_DESC(_name, _implid, _svcid, _totalid, \ _init, _getts_by_mpidr) \ static const pmf_svc_desc_t __pmf_desc_ ## _name \ __section("pmf_svc_descs") __used = { \ .h.type = PARAM_EP, \ .h.version = VERSION_1, \ .h.size = sizeof(pmf_svc_desc_t), \ .h.attr = 0, \ .name = #_name, \ .svc_config = ((((_implid) << PMF_IMPL_ID_SHIFT) & \ PMF_IMPL_ID_MASK) | \ (((_svcid) << PMF_SVC_ID_SHIFT) & \ PMF_SVC_ID_MASK) | \ (((_totalid) << PMF_TID_SHIFT) & \ PMF_TID_MASK)), \ .init = _init, \ .get_ts = _getts_by_mpidr \ }; /* PMF internal functions */ void __pmf_dump_timestamp(unsigned int tid, unsigned long long ts); void __pmf_store_timestamp(uintptr_t base_addr, unsigned int tid, unsigned long long ts); void __pmf_store_timestamp_with_cache_maint(uintptr_t base_addr, unsigned int tid, unsigned long long ts); unsigned long long __pmf_get_timestamp(uintptr_t base_addr, unsigned int tid, unsigned int cpuid, unsigned int flags); #endif /* PMF_HELPERS_H */ trusted-firmware-a-2.2/include/lib/psci/000077500000000000000000000000001355360272700202405ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/psci/psci.h000066400000000000000000000305401355360272700213510ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PSCI_H #define PSCI_H #include /* for PLAT_NUM_PWR_DOMAINS */ #include #include #include /* To maintain compatibility for SPDs */ #include /******************************************************************************* * Number of power domains whose state this PSCI implementation can track ******************************************************************************/ #ifdef PLAT_NUM_PWR_DOMAINS #define PSCI_NUM_PWR_DOMAINS PLAT_NUM_PWR_DOMAINS #else #define PSCI_NUM_PWR_DOMAINS (2 * PLATFORM_CORE_COUNT) #endif #define PSCI_NUM_NON_CPU_PWR_DOMAINS (PSCI_NUM_PWR_DOMAINS - \ PLATFORM_CORE_COUNT) /* This is the power level corresponding to a CPU */ #define PSCI_CPU_PWR_LVL U(0) /* * The maximum power level supported by PSCI. Since PSCI CPU_SUSPEND * uses the old power_state parameter format which has 2 bits to specify the * power level, this constant is defined to be 3. */ #define PSCI_MAX_PWR_LVL U(3) /******************************************************************************* * Defines for runtime services function ids ******************************************************************************/ #define PSCI_VERSION U(0x84000000) #define PSCI_CPU_SUSPEND_AARCH32 U(0x84000001) #define PSCI_CPU_SUSPEND_AARCH64 U(0xc4000001) #define PSCI_CPU_OFF U(0x84000002) #define PSCI_CPU_ON_AARCH32 U(0x84000003) #define PSCI_CPU_ON_AARCH64 U(0xc4000003) #define PSCI_AFFINITY_INFO_AARCH32 U(0x84000004) #define PSCI_AFFINITY_INFO_AARCH64 U(0xc4000004) #define PSCI_MIG_AARCH32 U(0x84000005) #define PSCI_MIG_AARCH64 U(0xc4000005) #define PSCI_MIG_INFO_TYPE U(0x84000006) #define PSCI_MIG_INFO_UP_CPU_AARCH32 U(0x84000007) #define PSCI_MIG_INFO_UP_CPU_AARCH64 U(0xc4000007) #define PSCI_SYSTEM_OFF U(0x84000008) #define PSCI_SYSTEM_RESET U(0x84000009) #define PSCI_FEATURES U(0x8400000A) #define PSCI_NODE_HW_STATE_AARCH32 U(0x8400000d) #define PSCI_NODE_HW_STATE_AARCH64 U(0xc400000d) #define PSCI_SYSTEM_SUSPEND_AARCH32 U(0x8400000E) #define PSCI_SYSTEM_SUSPEND_AARCH64 U(0xc400000E) #define PSCI_STAT_RESIDENCY_AARCH32 U(0x84000010) #define PSCI_STAT_RESIDENCY_AARCH64 U(0xc4000010) #define PSCI_STAT_COUNT_AARCH32 U(0x84000011) #define PSCI_STAT_COUNT_AARCH64 U(0xc4000011) #define PSCI_SYSTEM_RESET2_AARCH32 U(0x84000012) #define PSCI_SYSTEM_RESET2_AARCH64 U(0xc4000012) #define PSCI_MEM_PROTECT U(0x84000013) #define PSCI_MEM_CHK_RANGE_AARCH32 U(0x84000014) #define PSCI_MEM_CHK_RANGE_AARCH64 U(0xc4000014) /* * Number of PSCI calls (above) implemented */ #if ENABLE_PSCI_STAT #define PSCI_NUM_CALLS U(22) #else #define PSCI_NUM_CALLS U(18) #endif /* The macros below are used to identify PSCI calls from the SMC function ID */ #define PSCI_FID_MASK U(0xffe0) #define PSCI_FID_VALUE U(0) #define is_psci_fid(_fid) \ (((_fid) & PSCI_FID_MASK) == PSCI_FID_VALUE) /******************************************************************************* * PSCI Migrate and friends ******************************************************************************/ #define PSCI_TOS_UP_MIG_CAP 0 #define PSCI_TOS_NOT_UP_MIG_CAP 1 #define PSCI_TOS_NOT_PRESENT_MP 2 /******************************************************************************* * PSCI CPU_SUSPEND 'power_state' parameter specific defines ******************************************************************************/ #define PSTATE_ID_SHIFT U(0) #if PSCI_EXTENDED_STATE_ID #define PSTATE_VALID_MASK U(0xB0000000) #define PSTATE_TYPE_SHIFT U(30) #define PSTATE_ID_MASK U(0xfffffff) #else #define PSTATE_VALID_MASK U(0xFCFE0000) #define PSTATE_TYPE_SHIFT U(16) #define PSTATE_PWR_LVL_SHIFT U(24) #define PSTATE_ID_MASK U(0xffff) #define PSTATE_PWR_LVL_MASK U(0x3) #define psci_get_pstate_pwrlvl(pstate) (((pstate) >> PSTATE_PWR_LVL_SHIFT) & \ PSTATE_PWR_LVL_MASK) #define psci_make_powerstate(state_id, type, pwrlvl) \ (((state_id) & PSTATE_ID_MASK) << PSTATE_ID_SHIFT) |\ (((type) & PSTATE_TYPE_MASK) << PSTATE_TYPE_SHIFT) |\ (((pwrlvl) & PSTATE_PWR_LVL_MASK) << PSTATE_PWR_LVL_SHIFT) #endif /* __PSCI_EXTENDED_STATE_ID__ */ #define PSTATE_TYPE_STANDBY U(0x0) #define PSTATE_TYPE_POWERDOWN U(0x1) #define PSTATE_TYPE_MASK U(0x1) /******************************************************************************* * PSCI CPU_FEATURES feature flag specific defines ******************************************************************************/ /* Features flags for CPU SUSPEND power state parameter format. Bits [1:1] */ #define FF_PSTATE_SHIFT U(1) #define FF_PSTATE_ORIG U(0) #define FF_PSTATE_EXTENDED U(1) #if PSCI_EXTENDED_STATE_ID #define FF_PSTATE FF_PSTATE_EXTENDED #else #define FF_PSTATE FF_PSTATE_ORIG #endif /* Features flags for CPU SUSPEND OS Initiated mode support. Bits [0:0] */ #define FF_MODE_SUPPORT_SHIFT U(0) #define FF_SUPPORTS_OS_INIT_MODE U(1) /******************************************************************************* * PSCI version ******************************************************************************/ #define PSCI_MAJOR_VER (U(1) << 16) #define PSCI_MINOR_VER U(0x1) /******************************************************************************* * PSCI error codes ******************************************************************************/ #define PSCI_E_SUCCESS 0 #define PSCI_E_NOT_SUPPORTED -1 #define PSCI_E_INVALID_PARAMS -2 #define PSCI_E_DENIED -3 #define PSCI_E_ALREADY_ON -4 #define PSCI_E_ON_PENDING -5 #define PSCI_E_INTERN_FAIL -6 #define PSCI_E_NOT_PRESENT -7 #define PSCI_E_DISABLED -8 #define PSCI_E_INVALID_ADDRESS -9 #define PSCI_INVALID_MPIDR ~((u_register_t)0) /* * SYSTEM_RESET2 macros */ #define PSCI_RESET2_TYPE_VENDOR_SHIFT U(31) #define PSCI_RESET2_TYPE_VENDOR (U(1) << PSCI_RESET2_TYPE_VENDOR_SHIFT) #define PSCI_RESET2_TYPE_ARCH (U(0) << PSCI_RESET2_TYPE_VENDOR_SHIFT) #define PSCI_RESET2_SYSTEM_WARM_RESET (PSCI_RESET2_TYPE_ARCH | U(0)) #ifndef __ASSEMBLER__ #include /* Function to help build the psci capabilities bitfield */ static inline unsigned int define_psci_cap(unsigned int x) { return U(1) << (x & U(0x1f)); } /* Power state helper functions */ static inline unsigned int psci_get_pstate_id(unsigned int power_state) { return ((power_state) >> PSTATE_ID_SHIFT) & PSTATE_ID_MASK; } static inline unsigned int psci_get_pstate_type(unsigned int power_state) { return ((power_state) >> PSTATE_TYPE_SHIFT) & PSTATE_TYPE_MASK; } static inline unsigned int psci_check_power_state(unsigned int power_state) { return ((power_state) & PSTATE_VALID_MASK); } /* * These are the states reported by the PSCI_AFFINITY_INFO API for the specified * CPU. The definitions of these states can be found in Section 5.7.1 in the * PSCI specification (ARM DEN 0022C). */ typedef enum { AFF_STATE_ON = U(0), AFF_STATE_OFF = U(1), AFF_STATE_ON_PENDING = U(2) } aff_info_state_t; /* * These are the power states reported by PSCI_NODE_HW_STATE API for the * specified CPU. The definitions of these states can be found in Section 5.15.3 * of PSCI specification (ARM DEN 0022C). */ #define HW_ON 0 #define HW_OFF 1 #define HW_STANDBY 2 /* * Macro to represent invalid affinity level within PSCI. */ #define PSCI_INVALID_PWR_LVL (PLAT_MAX_PWR_LVL + U(1)) /* * Type for representing the local power state at a particular level. */ typedef uint8_t plat_local_state_t; /* The local state macro used to represent RUN state. */ #define PSCI_LOCAL_STATE_RUN U(0) /* * Function to test whether the plat_local_state is RUN state */ static inline int is_local_state_run(unsigned int plat_local_state) { return (plat_local_state == PSCI_LOCAL_STATE_RUN) ? 1 : 0; } /* * Function to test whether the plat_local_state is RETENTION state */ static inline int is_local_state_retn(unsigned int plat_local_state) { return ((plat_local_state > PSCI_LOCAL_STATE_RUN) && (plat_local_state <= PLAT_MAX_RET_STATE)) ? 1 : 0; } /* * Function to test whether the plat_local_state is OFF state */ static inline int is_local_state_off(unsigned int plat_local_state) { return ((plat_local_state > PLAT_MAX_RET_STATE) && (plat_local_state <= PLAT_MAX_OFF_STATE)) ? 1 : 0; } /***************************************************************************** * This data structure defines the representation of the power state parameter * for its exchange between the generic PSCI code and the platform port. For * example, it is used by the platform port to specify the requested power * states during a power management operation. It is used by the generic code to * inform the platform about the target power states that each level should * enter. ****************************************************************************/ typedef struct psci_power_state { /* * The pwr_domain_state[] stores the local power state at each level * for the CPU. */ plat_local_state_t pwr_domain_state[PLAT_MAX_PWR_LVL + U(1)]; } psci_power_state_t; /******************************************************************************* * Structure used to store per-cpu information relevant to the PSCI service. * It is populated in the per-cpu data array. In return we get a guarantee that * this information will not reside on a cache line shared with another cpu. ******************************************************************************/ typedef struct psci_cpu_data { /* State as seen by PSCI Affinity Info API */ aff_info_state_t aff_info_state; /* * Highest power level which takes part in a power management * operation. */ unsigned int target_pwrlvl; /* The local power state of this CPU */ plat_local_state_t local_state; } psci_cpu_data_t; /******************************************************************************* * Structure populated by platform specific code to export routines which * perform common low level power management functions ******************************************************************************/ typedef struct plat_psci_ops { void (*cpu_standby)(plat_local_state_t cpu_state); int (*pwr_domain_on)(u_register_t mpidr); void (*pwr_domain_off)(const psci_power_state_t *target_state); void (*pwr_domain_suspend_pwrdown_early)( const psci_power_state_t *target_state); void (*pwr_domain_suspend)(const psci_power_state_t *target_state); void (*pwr_domain_on_finish)(const psci_power_state_t *target_state); void (*pwr_domain_on_finish_late)( const psci_power_state_t *target_state); void (*pwr_domain_suspend_finish)( const psci_power_state_t *target_state); 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); void (*get_sys_suspend_power_state)( psci_power_state_t *req_state); int (*get_pwr_lvl_state_idx)(plat_local_state_t pwr_domain_state, int pwrlvl); int (*translate_power_state_by_mpidr)(u_register_t mpidr, unsigned int power_state, psci_power_state_t *output_state); int (*get_node_hw_state)(u_register_t mpidr, unsigned int power_level); int (*mem_protect_chk)(uintptr_t base, u_register_t length); int (*read_mem_protect)(int *val); int (*write_mem_protect)(int val); int (*system_reset2)(int is_vendor, int reset_type, u_register_t cookie); } plat_psci_ops_t; /******************************************************************************* * Function & Data prototypes ******************************************************************************/ unsigned int psci_version(void); int psci_cpu_on(u_register_t target_cpu, uintptr_t entrypoint, u_register_t context_id); int psci_cpu_suspend(unsigned int power_state, uintptr_t entrypoint, u_register_t context_id); int psci_system_suspend(uintptr_t entrypoint, u_register_t context_id); int psci_cpu_off(void); int psci_affinity_info(u_register_t target_affinity, unsigned int lowest_affinity_level); int psci_migrate(u_register_t target_cpu); int psci_migrate_info_type(void); u_register_t psci_migrate_info_up_cpu(void); int psci_node_hw_state(u_register_t target_cpu, unsigned int power_level); int psci_features(unsigned int psci_fid); void __dead2 psci_power_down_wfi(void); void psci_arch_setup(void); #endif /*__ASSEMBLER__*/ #endif /* PSCI_H */ trusted-firmware-a-2.2/include/lib/psci/psci_lib.h000066400000000000000000000064151355360272700222030ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PSCI_LIB_H #define PSCI_LIB_H #include #ifndef __ASSEMBLER__ #include #include /******************************************************************************* * Optional structure populated by the Secure Payload Dispatcher to be given a * chance to perform any bookkeeping before PSCI executes a power management * operation. It also allows PSCI to determine certain properties of the SP e.g. * migrate capability etc. ******************************************************************************/ typedef struct spd_pm_ops { void (*svc_on)(u_register_t target_cpu); int32_t (*svc_off)(u_register_t __unused unused); void (*svc_suspend)(u_register_t max_off_pwrlvl); void (*svc_on_finish)(u_register_t __unused unused); void (*svc_suspend_finish)(u_register_t max_off_pwrlvl); int32_t (*svc_migrate)(u_register_t from_cpu, u_register_t to_cpu); int32_t (*svc_migrate_info)(u_register_t *resident_cpu); void (*svc_system_off)(void); void (*svc_system_reset)(void); } spd_pm_ops_t; /* * Function prototype for the warmboot entrypoint function which will be * programmed in the mailbox by the platform. */ typedef void (*mailbox_entrypoint_t)(void); /****************************************************************************** * Structure to pass PSCI Library arguments. *****************************************************************************/ typedef struct psci_lib_args { /* The version information of PSCI Library Interface */ param_header_t h; /* The warm boot entrypoint function */ mailbox_entrypoint_t mailbox_ep; } psci_lib_args_t; /* Helper macro to set the psci_lib_args_t structure at runtime */ #define SET_PSCI_LIB_ARGS_V1(_p, _entry) do { \ SET_PARAM_HEAD(_p, PARAM_PSCI_LIB_ARGS, VERSION_1, 0); \ (_p)->mailbox_ep = (_entry); \ } while (0) /* Helper macro to define the psci_lib_args_t statically */ #define DEFINE_STATIC_PSCI_LIB_ARGS_V1(_name, _entry) \ static const psci_lib_args_t (_name) = { \ .h.type = (uint8_t)PARAM_PSCI_LIB_ARGS, \ .h.version = (uint8_t)VERSION_1, \ .h.size = (uint16_t)sizeof(_name), \ .h.attr = 0U, \ .mailbox_ep = (_entry) \ } /* Helper macro to verify the pointer to psci_lib_args_t structure */ #define VERIFY_PSCI_LIB_ARGS_V1(_p) (((_p) != NULL) \ && ((_p)->h.type == PARAM_PSCI_LIB_ARGS) \ && ((_p)->h.version == VERSION_1) \ && ((_p)->h.size == sizeof(*(_p))) \ && ((_p)->h.attr == 0) \ && ((_p)->mailbox_ep != NULL)) /****************************************************************************** * PSCI Library Interfaces *****************************************************************************/ u_register_t psci_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); int psci_setup(const psci_lib_args_t *lib_args); int psci_secondaries_brought_up(void); void psci_warmboot_entrypoint(void); void psci_register_spd_pm_hook(const spd_pm_ops_t *pm); void psci_prepare_next_non_secure_ctx( entry_point_info_t *next_image_info); #endif /* __ASSEMBLER__ */ #endif /* PSCI_LIB_H */ trusted-firmware-a-2.2/include/lib/runtime_instr.h000066400000000000000000000011541355360272700223560ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RUNTIME_INSTR_H #define RUNTIME_INSTR_H #include #define RT_INSTR_ENTER_PSCI U(0) #define RT_INSTR_EXIT_PSCI U(1) #define RT_INSTR_ENTER_HW_LOW_PWR U(2) #define RT_INSTR_EXIT_HW_LOW_PWR U(3) #define RT_INSTR_ENTER_CFLUSH U(4) #define RT_INSTR_EXIT_CFLUSH U(5) #define RT_INSTR_TOTAL_IDS U(6) #ifndef __ASSEMBLER__ PMF_DECLARE_CAPTURE_TIMESTAMP(rt_instr_svc) PMF_DECLARE_GET_TIMESTAMP(rt_instr_svc) #endif /* __ASSEMBLER__ */ #endif /* RUNTIME_INSTR_H */ trusted-firmware-a-2.2/include/lib/semihosting.h000066400000000000000000000036061355360272700220110ustar00rootroot00000000000000/* * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SEMIHOSTING_H #define SEMIHOSTING_H #include #include /* For ssize_t */ #define SEMIHOSTING_SYS_OPEN 0x01 #define SEMIHOSTING_SYS_CLOSE 0x02 #define SEMIHOSTING_SYS_WRITE0 0x04 #define SEMIHOSTING_SYS_WRITEC 0x03 #define SEMIHOSTING_SYS_WRITE 0x05 #define SEMIHOSTING_SYS_READ 0x06 #define SEMIHOSTING_SYS_READC 0x07 #define SEMIHOSTING_SYS_SEEK 0x0A #define SEMIHOSTING_SYS_FLEN 0x0C #define SEMIHOSTING_SYS_REMOVE 0x0E #define SEMIHOSTING_SYS_SYSTEM 0x12 #define SEMIHOSTING_SYS_ERRNO 0x13 #define FOPEN_MODE_R 0x0 #define FOPEN_MODE_RB 0x1 #define FOPEN_MODE_RPLUS 0x2 #define FOPEN_MODE_RPLUSB 0x3 #define FOPEN_MODE_W 0x4 #define FOPEN_MODE_WB 0x5 #define FOPEN_MODE_WPLUS 0x6 #define FOPEN_MODE_WPLUSB 0x7 #define FOPEN_MODE_A 0x8 #define FOPEN_MODE_AB 0x9 #define FOPEN_MODE_APLUS 0xa #define FOPEN_MODE_APLUSB 0xb long semihosting_connection_supported(void); long semihosting_file_open(const char *file_name, size_t mode); long semihosting_file_seek(long file_handle, ssize_t offset); long semihosting_file_read(long file_handle, size_t *length, uintptr_t buffer); long semihosting_file_write(long file_handle, size_t *length, const uintptr_t buffer); long semihosting_file_close(long file_handle); long semihosting_file_length(long file_handle); long semihosting_system(char *command_line); long semihosting_get_flen(const char *file_name); long semihosting_download_file(const char *file_name, size_t buf_size, uintptr_t buf); void semihosting_write_char(char character); void semihosting_write_string(char *string); char semihosting_read_char(void); #endif /* SEMIHOSTING_H */ trusted-firmware-a-2.2/include/lib/smccc.h000066400000000000000000000125311355360272700205450ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SMCCC_H #define SMCCC_H #include #define SMCCC_VERSION_MAJOR_SHIFT U(16) #define SMCCC_VERSION_MAJOR_MASK U(0x7FFF) #define SMCCC_VERSION_MINOR_SHIFT U(0) #define SMCCC_VERSION_MINOR_MASK U(0xFFFF) #define MAKE_SMCCC_VERSION(_major, _minor) \ ((((uint32_t)(_major) & SMCCC_VERSION_MAJOR_MASK) << \ SMCCC_VERSION_MAJOR_SHIFT) \ | (((uint32_t)(_minor) & SMCCC_VERSION_MINOR_MASK) << \ SMCCC_VERSION_MINOR_SHIFT)) #define SMCCC_MAJOR_VERSION U(1) #define SMCCC_MINOR_VERSION U(1) /******************************************************************************* * Bit definitions inside the function id as per the SMC calling convention ******************************************************************************/ #define FUNCID_TYPE_SHIFT U(31) #define FUNCID_TYPE_MASK U(0x1) #define FUNCID_TYPE_WIDTH U(1) #define FUNCID_CC_SHIFT U(30) #define FUNCID_CC_MASK U(0x1) #define FUNCID_CC_WIDTH U(1) #define FUNCID_OEN_SHIFT U(24) #define FUNCID_OEN_MASK U(0x3f) #define FUNCID_OEN_WIDTH U(6) #define FUNCID_NUM_SHIFT U(0) #define FUNCID_NUM_MASK U(0xffff) #define FUNCID_NUM_WIDTH U(16) #define GET_SMC_TYPE(id) (((id) >> FUNCID_TYPE_SHIFT) & \ FUNCID_TYPE_MASK) #define GET_SMC_CC(id) (((id) >> FUNCID_CC_SHIFT) & \ FUNCID_CC_MASK) #define GET_SMC_OEN(id) (((id) >> FUNCID_OEN_SHIFT) & \ FUNCID_OEN_MASK) /******************************************************************************* * Owning entity number definitions inside the function id as per the SMC * calling convention ******************************************************************************/ #define OEN_ARM_START U(0) #define OEN_ARM_END U(0) #define OEN_CPU_START U(1) #define OEN_CPU_END U(1) #define OEN_SIP_START U(2) #define OEN_SIP_END U(2) #define OEN_OEM_START U(3) #define OEN_OEM_END U(3) #define OEN_STD_START U(4) /* Standard Service Calls */ #define OEN_STD_END U(4) #define OEN_STD_HYP_START U(5) /* Standard Hypervisor Service calls */ #define OEN_STD_HYP_END U(5) #define OEN_VEN_HYP_START U(6) /* Vendor Hypervisor Service calls */ #define OEN_VEN_HYP_END U(6) #define OEN_TAP_START U(48) /* Trusted Applications */ #define OEN_TAP_END U(49) #define OEN_TOS_START U(50) /* Trusted OS */ #define OEN_TOS_END U(63) #define OEN_LIMIT U(64) /* Flags and error codes */ #define SMC_64 U(1) #define SMC_32 U(0) #define SMC_TYPE_FAST ULL(1) #define SMC_TYPE_YIELD ULL(0) #define SMC_OK ULL(0) #define SMC_UNK -1 #define SMC_PREEMPTED -2 /* Not defined by the SMCCC */ /* Various flags passed to SMC handlers */ #define SMC_FROM_SECURE (U(0) << 0) #define SMC_FROM_NON_SECURE (U(1) << 0) #ifndef __ASSEMBLER__ #include #include #define is_caller_non_secure(_f) (((_f) & SMC_FROM_NON_SECURE) != U(0)) #define is_caller_secure(_f) (!is_caller_non_secure(_f)) /* The macro below is used to identify a Standard Service SMC call */ #define is_std_svc_call(_fid) (GET_SMC_OEN(_fid) == OEN_STD_START) /* The macro below is used to identify a Arm Architectural Service SMC call */ #define is_arm_arch_svc_call(_fid) (GET_SMC_OEN(_fid) == OEN_ARM_START) /* The macro below is used to identify a valid Fast SMC call */ #define is_valid_fast_smc(_fid) ((!(((_fid) >> 16) & U(0xff))) && \ (GET_SMC_TYPE(_fid) == SMC_TYPE_FAST)) /* * Macro to define UUID for services. Apart from defining and initializing a * uuid_t structure, this macro verifies that the first word of the defined UUID * does not equal SMC_UNK. This is to ensure that the caller won't mistake the * returned UUID in x0 for an invalid SMC error return */ #define DEFINE_SVC_UUID2(_name, _tl, _tm, _th, _cl, _ch, \ _n0, _n1, _n2, _n3, _n4, _n5) \ CASSERT((uint32_t)(_tl) != (uint32_t) SMC_UNK, invalid_svc_uuid);\ static const uuid_t _name = { \ {(_tl >> 24) & 0xFF, \ (_tl >> 16) & 0xFF, \ (_tl >> 8) & 0xFF, \ (_tl & 0xFF)}, \ {(_tm >> 8) & 0xFF, \ (_tm & 0xFF)}, \ {(_th >> 8) & 0xFF, \ (_th & 0xFF)}, \ _cl, _ch, \ { _n0, _n1, _n2, _n3, _n4, _n5 } \ } /* * Return a UUID in the SMC return registers. * * Acccording to section 5.3 of the SMCCC, UUIDs are returned as a single * 128-bit value using the SMC32 calling convention. This value is mapped to * argument registers x0-x3 on AArch64 (resp. r0-r3 on AArch32). x0 for example * shall hold bytes 0 to 3, with byte 0 in the low-order bits. */ static inline uint32_t smc_uuid_word(uint8_t b0, uint8_t b1, uint8_t b2, uint8_t b3) { return ((uint32_t) b0) | (((uint32_t) b1) << 8) | (((uint32_t) b2) << 16) | (((uint32_t) b3) << 24); } #define SMC_UUID_RET(_h, _uuid) \ SMC_RET4(handle, \ smc_uuid_word((_uuid).time_low[0], (_uuid).time_low[1], \ (_uuid).time_low[2], (_uuid).time_low[3]), \ smc_uuid_word((_uuid).time_mid[0], (_uuid).time_mid[1], \ (_uuid).time_hi_and_version[0], \ (_uuid).time_hi_and_version[1]), \ smc_uuid_word((_uuid).clock_seq_hi_and_reserved, \ (_uuid).clock_seq_low, (_uuid).node[0], \ (_uuid).node[1]), \ smc_uuid_word((_uuid).node[2], (_uuid).node[3], \ (_uuid).node[4], (_uuid).node[5])) #endif /*__ASSEMBLER__*/ #endif /* SMCCC_H */ trusted-firmware-a-2.2/include/lib/spinlock.h000066400000000000000000000007601355360272700213000ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPINLOCK_H #define SPINLOCK_H #ifndef __ASSEMBLER__ #include typedef struct spinlock { volatile uint32_t lock; } spinlock_t; void spin_lock(spinlock_t *lock); void spin_unlock(spinlock_t *lock); #else /* Spin lock definitions for use in assembly */ #define SPINLOCK_ASM_ALIGN 2 #define SPINLOCK_ASM_SIZE 4 #endif #endif /* SPINLOCK_H */ trusted-firmware-a-2.2/include/lib/sprt/000077500000000000000000000000001355360272700202725ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/sprt/sprt_common.h000066400000000000000000000020161355360272700230020ustar00rootroot00000000000000/* * Copyright (c) 2018, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPRT_COMMON_H #define SPRT_COMMON_H #define SPRT_MAX_MSG_ARGS 6 /* * Message types supported. */ #define SPRT_MSG_TYPE_SERVICE_HANDLE_OPEN 1 #define SPRT_MSG_TYPE_SERVICE_HANDLE_CLOSE 2 /* TODO: Add other types of SPRT messages. */ #define SPRT_MSG_TYPE_SERVICE_TUN_REQUEST 10 /* * Struct that defines the layout of the fields corresponding to a request in * shared memory. */ struct __attribute__((__packed__)) sprt_queue_entry_message { uint32_t type; /* Type of message (result of an SPCI call). */ uint16_t client_id; /* SPCI client ID */ uint16_t service_handle;/* SPCI service handle */ uint32_t session_id; /* Optional SPCI session ID */ uint32_t token; /* SPCI request token */ uint64_t args[SPRT_MAX_MSG_ARGS]; }; #define SPRT_QUEUE_ENTRY_MSG_SIZE (sizeof(struct sprt_queue_entry_message)) #define SPRT_QUEUE_NUM_BLOCKING 0 #define SPRT_QUEUE_NUM_NON_BLOCKING 1 #endif /* SPRT_COMMON_H */ trusted-firmware-a-2.2/include/lib/sprt/sprt_host.h000066400000000000000000000011301355360272700224630ustar00rootroot00000000000000/* * Copyright (c) 2018, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPRT_HOST_H #define SPRT_HOST_H #include #include "sprt_common.h" /* * Initialize the specified buffer to be used by SPM. */ void sprt_initialize_queues(void *buffer_base, size_t buffer_size); /* * Push a message to the queue number `queue_num` in a buffer that has been * initialized by `sprt_initialize_queues`. */ int sprt_push_message(void *buffer_base, const struct sprt_queue_entry_message *message, int queue_num); #endif /* SPRT_HOST_H */ trusted-firmware-a-2.2/include/lib/utils.h000066400000000000000000000060031355360272700206120ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef UTILS_H #define UTILS_H /* * C code should be put in this part of the header to avoid breaking ASM files * or linker scripts including it. */ #if !(defined(__LINKER__) || defined(__ASSEMBLER__)) #include #include typedef struct mem_region { uintptr_t base; size_t nbytes; } mem_region_t; /* * zero_normalmem all the regions defined in tbl. */ void clear_mem_regions(mem_region_t *tbl, size_t nregions); /* * zero_normalmem all the regions defined in region. It dynamically * maps chunks of 'chunk_size' in 'va' virtual address and clears them. * For this reason memory regions must be multiple of chunk_size and * must be aligned to it as well. chunk_size and va can be selected * in a way that they minimize the number of entries used in the * translation tables. */ void clear_map_dyn_mem_regions(struct mem_region *regions, size_t nregions, uintptr_t va, size_t chunk); /* * checks that a region (addr + nbytes-1) of memory is totally covered by * one of the regions defined in tbl. Caller must ensure that (addr+nbytes-1) * doesn't overflow. */ int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions, uintptr_t addr, size_t nbytes); /* * Fill a region of normal memory of size "length" in bytes with zero bytes. * * WARNING: This function can only operate on normal memory. This means that * the MMU must be enabled when using this function. Otherwise, use * zeromem. */ void zero_normalmem(void *mem, u_register_t length); /* * Fill a region of memory of size "length" in bytes with null bytes. * * Unlike zero_normalmem, this function has no restriction on the type of * memory targeted and can be used for any device memory as well as normal * memory. This function must be used instead of zero_normalmem when MMU is * disabled. * * NOTE: When data cache and MMU are enabled, prefer zero_normalmem for faster * 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(__ASSEMBLER__)) */ #endif /* UTILS_H */ trusted-firmware-a-2.2/include/lib/utils_def.h000066400000000000000000000100751355360272700214340ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef UTILS_DEF_H #define UTILS_DEF_H #include /* Compute the number of elements in the given array */ #define ARRAY_SIZE(a) \ (sizeof(a) / sizeof((a)[0])) #define IS_POWER_OF_TWO(x) \ (((x) & ((x) - 1)) == 0) #define SIZE_FROM_LOG2_WORDS(n) (4 << (n)) #define BIT_32(nr) (U(1) << (nr)) #define BIT_64(nr) (ULL(1) << (nr)) #ifdef __aarch64__ #define BIT BIT_64 #else #define BIT BIT_32 #endif /* * Create a contiguous bitmask starting at bit position @l and ending at * position @h. For example * GENMASK_64(39, 21) gives us the 64bit vector 0x000000ffffe00000. */ #if defined(__LINKER__) || defined(__ASSEMBLER__) #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 __aarch64__ #define GENMASK GENMASK_64 #else #define GENMASK GENMASK_32 #endif /* * This variant of div_round_up can be used in macro definition but should not * be used in C code as the `div` parameter is evaluated twice. */ #define DIV_ROUND_UP_2EVAL(n, d) (((n) + (d) - 1) / (d)) #define div_round_up(val, div) __extension__ ({ \ __typeof__(div) _div = (div); \ ((val) + _div - (__typeof__(div)) 1) / _div; \ }) #define MIN(x, y) __extension__ ({ \ __typeof__(x) _x = (x); \ __typeof__(y) _y = (y); \ (void)(&_x == &_y); \ _x < _y ? _x : _y; \ }) #define MAX(x, y) __extension__ ({ \ __typeof__(x) _x = (x); \ __typeof__(y) _y = (y); \ (void)(&_x == &_y); \ _x > _y ? _x : _y; \ }) /* * The round_up() macro rounds up a value to the given boundary in a * type-agnostic yet type-safe manner. The boundary must be a power of two. * In other words, it computes the smallest multiple of boundary which is * greater than or equal to value. * * round_down() is similar but rounds the value down instead. */ #define round_boundary(value, boundary) \ ((__typeof__(value))((boundary) - 1)) #define round_up(value, boundary) \ ((((value) - 1) | round_boundary(value, boundary)) + 1) #define round_down(value, boundary) \ ((value) & ~round_boundary(value, boundary)) /* * Evaluates to 1 if (ptr + inc) overflows, 0 otherwise. * Both arguments must be unsigned pointer values (i.e. uintptr_t). */ #define check_uptr_overflow(_ptr, _inc) \ ((_ptr) > (UINTPTR_MAX - (_inc))) /* * Evaluates to 1 if (u32 + inc) overflows, 0 otherwise. * Both arguments must be 32-bit unsigned integers (i.e. effectively uint32_t). */ #define check_u32_overflow(_u32, _inc) \ ((_u32) > (UINT32_MAX - (_inc))) /* Register size of the current architecture. */ #ifdef __aarch64__ #define REGSZ U(8) #else #define REGSZ U(4) #endif /* * Test for the current architecture version to be at least the version * expected. */ #define ARM_ARCH_AT_LEAST(_maj, _min) \ ((ARM_ARCH_MAJOR > (_maj)) || \ ((ARM_ARCH_MAJOR == (_maj)) && (ARM_ARCH_MINOR >= (_min)))) /* * Import an assembly or linker symbol as a C expression with the specified * type */ #define IMPORT_SYM(type, sym, name) \ extern char sym[];\ static const __attribute__((unused)) type name = (type) sym; /* * When the symbol is used to hold a pointer, its alignment can be asserted * with this macro. For example, if there is a linker symbol that is going to * be used as a 64-bit pointer, the value of the linker symbol must also be * aligned to 64 bit. This macro makes sure this is the case. */ #define ASSERT_SYM_PTR_ALIGN(sym) assert(((size_t)(sym) % __alignof__(*(sym))) == 0) #define COMPILER_BARRIER() __asm__ volatile ("" ::: "memory") /* Compiler builtin of GCC >= 9 and planned in llvm */ #ifdef __HAVE_SPECULATION_SAFE_VALUE # define SPECULATION_SAFE_VALUE(var) __builtin_speculation_safe_value(var) #else # define SPECULATION_SAFE_VALUE(var) var #endif #endif /* UTILS_DEF_H */ trusted-firmware-a-2.2/include/lib/xlat_tables/000077500000000000000000000000001355360272700216045ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/xlat_tables/aarch32/000077500000000000000000000000001355360272700230275ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/xlat_tables/aarch32/xlat_tables_aarch32.h000066400000000000000000000046641355360272700270170ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef XLAT_TABLES_AARCH32_H #define XLAT_TABLES_AARCH32_H #include #include #include #if !defined(PAGE_SIZE) #error "PAGE_SIZE is not defined." #endif /* * In AArch32 state, the MMU only supports 4KB page granularity, which means * that the first translation table level is either 1 or 2. Both of them are * allowed to have block and table descriptors. See section G4.5.6 of the * ARMv8-A Architecture Reference Manual (DDI 0487A.k) for more information. * * The define below specifies the first table level that allows block * descriptors. */ #if PAGE_SIZE != PAGE_SIZE_4KB #error "Invalid granule size. AArch32 supports 4KB pages only." #endif #define MIN_LVL_BLOCK_DESC U(1) #define XLAT_TABLE_LEVEL_MIN U(1) /* * Define the architectural limits of the virtual address space in AArch32 * state. * * TTBCR.TxSZ is calculated as 32 minus the width of said address space. The * value of TTBCR.TxSZ must be in the range 0 to 7 [1], which means that the * virtual address space width must be in the range 32 to 25 bits. * * [1] See the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more * information, Section G4.6.5 */ #define MIN_VIRT_ADDR_SPACE_SIZE (ULL(1) << (U(32) - TTBCR_TxSZ_MAX)) #define MAX_VIRT_ADDR_SPACE_SIZE (ULL(1) << (U(32) - TTBCR_TxSZ_MIN)) /* * Here we calculate the initial lookup level from the value of the given * virtual address space size. For a 4 KB page size, * - level 1 supports virtual address spaces of widths 32 to 31 bits; * - level 2 from 30 to 25. * * Wider or narrower address spaces are not supported. As a result, level 3 * cannot be used as the initial lookup level with 4 KB granularity. * See the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more * information, Section G4.6.5 * * For example, for a 31-bit address space (i.e. virt_addr_space_size == * 1 << 31), TTBCR.TxSZ will be programmed to (32 - 31) = 1. According to Table * G4-5 in the ARM ARM, the initial lookup level for an address space like that * is 1. * * Note that this macro assumes that the given virtual address space size is * valid. */ #define GET_XLAT_TABLE_LEVEL_BASE(_virt_addr_space_sz) \ (((_virt_addr_space_sz) > (ULL(1) << L1_XLAT_ADDRESS_SHIFT)) ? \ U(1) : U(2)) #endif /* XLAT_TABLES_AARCH32_H */ trusted-firmware-a-2.2/include/lib/xlat_tables/aarch64/000077500000000000000000000000001355360272700230345ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/xlat_tables/aarch64/xlat_tables_aarch64.h000066400000000000000000000067321355360272700270270ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef XLAT_TABLES_AARCH64_H #define XLAT_TABLES_AARCH64_H #include #include #include #if !defined(PAGE_SIZE) #error "PAGE_SIZE is not defined." #endif /* * Encode a Physical Address Space size for its use in TCR_ELx. */ unsigned long long tcr_physical_addr_size_bits(unsigned long long max_addr); /* * In AArch64 state, the MMU may support 4 KB, 16 KB and 64 KB page * granularity. For 4KB granularity, a level 0 table descriptor doesn't support * block translation. For 16KB, the same thing happens to levels 0 and 1. For * 64KB, same for level 1. See section D4.3.1 of the ARMv8-A Architecture * Reference Manual (DDI 0487A.k) for more information. * * The define below specifies the first table level that allows block * descriptors. */ #if PAGE_SIZE == PAGE_SIZE_4KB # define MIN_LVL_BLOCK_DESC U(1) #elif (PAGE_SIZE == PAGE_SIZE_16KB) || (PAGE_SIZE == PAGE_SIZE_64KB) # define MIN_LVL_BLOCK_DESC U(2) #endif #define XLAT_TABLE_LEVEL_MIN U(0) /* * Define the architectural limits of the virtual address space in AArch64 * state. * * TCR.TxSZ is calculated as 64 minus the width of said address space. * The value of TCR.TxSZ must be in the range 16 to 39 [1] or 48 [2], * depending on Small Translation Table Support which means that * the virtual address space width must be in the range 48 to 25 or 16 bits. * * [1] See the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more * information: * Page 1730: 'Input address size', 'For all translation stages'. * [2] See section 12.2.55 in the ARMv8-A Architecture Reference Manual * (DDI 0487D.a) */ /* Maximum value of TCR_ELx.T(0,1)SZ is 39 */ #define MIN_VIRT_ADDR_SPACE_SIZE (ULL(1) << (U(64) - TCR_TxSZ_MAX)) /* Maximum value of TCR_ELx.T(0,1)SZ is 48 */ #define MIN_VIRT_ADDR_SPACE_SIZE_TTST \ (ULL(1) << (U(64) - TCR_TxSZ_MAX_TTST)) #define MAX_VIRT_ADDR_SPACE_SIZE (ULL(1) << (U(64) - TCR_TxSZ_MIN)) /* * Here we calculate the initial lookup level from the value of the given * virtual address space size. For a 4 KB page size, * - level 0 supports virtual address spaces of widths 48 to 40 bits; * - level 1 from 39 to 31; * - level 2 from 30 to 22. * - level 3 from 21 to 16. * * Small Translation Table (Armv8.4-TTST) support allows the starting level * of the translation table from 3 for 4KB granularity. See section 12.2.55 in * the ARMv8-A Architecture Reference Manual (DDI 0487D.a). In Armv8.3 and below * wider or narrower address spaces are not supported. As a result, level 3 * cannot be used as initial lookup level with 4 KB granularity. See section * D4.2.5 in the ARMv8-A Architecture Reference Manual (DDI 0487A.j) for more * information. * * For example, for a 35-bit address space (i.e. virt_addr_space_size == * 1 << 35), TCR.TxSZ will be programmed to (64 - 35) = 29. According to Table * D4-11 in the ARM ARM, the initial lookup level for an address space like that * is 1. * * Note that this macro assumes that the given virtual address space size is * valid. */ #define GET_XLAT_TABLE_LEVEL_BASE(_virt_addr_space_sz) \ (((_virt_addr_space_sz) > (ULL(1) << L0_XLAT_ADDRESS_SHIFT)) \ ? 0U \ : (((_virt_addr_space_sz) > (ULL(1) << L1_XLAT_ADDRESS_SHIFT)) \ ? 1U \ : (((_virt_addr_space_sz) > (ULL(1) << L2_XLAT_ADDRESS_SHIFT)) \ ? 2U : 3U))) #endif /* XLAT_TABLES_AARCH64_H */ trusted-firmware-a-2.2/include/lib/xlat_tables/xlat_mmu_helpers.h000066400000000000000000000060561355360272700253340ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef XLAT_MMU_HELPERS_H #define XLAT_MMU_HELPERS_H /* * The following flags are passed to enable_mmu_xxx() to override the default * values used to program system registers while enabling the MMU. */ /* * When this flag is used, all data access to Normal memory from this EL and all * Normal memory accesses to the translation tables of this EL are non-cacheable * for all levels of data and unified cache until the caches are enabled by * setting the bit SCTLR_ELx.C. */ #define DISABLE_DCACHE (U(1) << 0) /* * Mark the translation tables as non-cacheable for the MMU table walker, which * is a different observer from the PE/CPU. If the flag is not specified, the * tables are cacheable for the MMU table walker. * * Note that, as far as the PE/CPU observer is concerned, the attributes used * are the ones specified in the translation tables themselves. The MAIR * register specifies the cacheability through the field AttrIndx of the lower * attributes of the translation tables. The shareability is specified in the SH * field of the lower attributes. * * The MMU table walker uses the attributes specified in the fields ORGNn, IRGNn * and SHn of the TCR register to access the translation tables. * * The attributes specified in the TCR register and the tables can be different * as there are no checks to prevent that. Special care must be taken to ensure * that there aren't mismatches. The behaviour in that case is described in the * sections 'Mismatched memory attributes' in the ARMv8 ARM. */ #define XLAT_TABLE_NC (U(1) << 1) /* * Offsets into a mmu_cfg_params array generated by setup_mmu_cfg(). All * parameters are 64 bits wide. */ #define MMU_CFG_MAIR 0 #define MMU_CFG_TCR 1 #define MMU_CFG_TTBR0 2 #define MMU_CFG_PARAM_MAX 3 #ifndef __ASSEMBLER__ #include #include #include /* * Return the values that the MMU configuration registers must contain for the * specified translation context. `params` must be a pointer to array of size * MMU_CFG_PARAM_MAX. */ void setup_mmu_cfg(uint64_t *params, unsigned int flags, const uint64_t *base_table, unsigned long long max_pa, uintptr_t max_va, int xlat_regime); #ifdef __aarch64__ /* AArch64 specific translation table APIs */ void enable_mmu_el1(unsigned int flags); void enable_mmu_el2(unsigned int flags); void enable_mmu_el3(unsigned int flags); void enable_mmu_direct_el1(unsigned int flags); void enable_mmu_direct_el2(unsigned int flags); void enable_mmu_direct_el3(unsigned int flags); #else /* AArch32 specific translation table API */ void enable_mmu_svc_mon(unsigned int flags); void enable_mmu_hyp(unsigned int flags); void enable_mmu_direct_svc_mon(unsigned int flags); void enable_mmu_direct_hyp(unsigned int flags); #endif /* __aarch64__ */ bool xlat_arch_is_granule_size_supported(size_t size); size_t xlat_arch_get_max_supported_granule_size(void); #endif /* __ASSEMBLER__ */ #endif /* XLAT_MMU_HELPERS_H */ trusted-firmware-a-2.2/include/lib/xlat_tables/xlat_tables.h000066400000000000000000000051371355360272700242650ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef XLAT_TABLES_H #define XLAT_TABLES_H #include #ifndef __ASSEMBLER__ #include #include #include /* Helper macro to define entries for mmap_region_t. It creates * identity mappings for each region. */ #define MAP_REGION_FLAT(adr, sz, attr) MAP_REGION(adr, adr, sz, attr) /* Helper macro to define entries for mmap_region_t. It allows to * re-map address mappings from 'pa' to 'va' for each region. */ #define MAP_REGION(pa, va, sz, attr) {(pa), (va), (sz), (attr)} /* * Shifts and masks to access fields of an mmap attribute */ #define MT_TYPE_MASK U(0x7) #define MT_TYPE(_attr) ((_attr) & MT_TYPE_MASK) /* Access permissions (RO/RW) */ #define MT_PERM_SHIFT U(3) /* Security state (SECURE/NS) */ #define MT_SEC_SHIFT U(4) /* Access permissions for instruction execution (EXECUTE/EXECUTE_NEVER) */ #define MT_EXECUTE_SHIFT U(5) /* * Memory mapping attributes */ /* * Memory types supported. * These are organised so that, going down the list, the memory types are * getting weaker; conversely going up the list the memory types are getting * stronger. */ #define MT_DEVICE U(0) #define MT_NON_CACHEABLE U(1) #define MT_MEMORY U(2) /* Values up to 7 are reserved to add new memory types in the future */ #define MT_RO (U(0) << MT_PERM_SHIFT) #define MT_RW (U(1) << MT_PERM_SHIFT) #define MT_SECURE (U(0) << MT_SEC_SHIFT) #define MT_NS (U(1) << MT_SEC_SHIFT) /* * Access permissions for instruction execution are only relevant for normal * read-only memory, i.e. MT_MEMORY | MT_RO. They are ignored (and potentially * overridden) otherwise: * - Device memory is always marked as execute-never. * - Read-write normal memory is always marked as execute-never. */ #define MT_EXECUTE (U(0) << MT_EXECUTE_SHIFT) #define MT_EXECUTE_NEVER (U(1) << MT_EXECUTE_SHIFT) /* Compound attributes for most common usages */ #define MT_CODE (MT_MEMORY | MT_RO | MT_EXECUTE) #define MT_RO_DATA (MT_MEMORY | MT_RO | MT_EXECUTE_NEVER) /* * Structure for specifying a single region of memory. */ typedef struct mmap_region { unsigned long long base_pa; uintptr_t base_va; size_t size; unsigned int attr; } mmap_region_t; /* Generic translation table APIs */ void init_xlat_tables(void); void mmap_add_region(unsigned long long base_pa, uintptr_t base_va, size_t size, unsigned int attr); void mmap_add(const mmap_region_t *mm); #endif /*__ASSEMBLER__*/ #endif /* XLAT_TABLES_H */ trusted-firmware-a-2.2/include/lib/xlat_tables/xlat_tables_arch.h000066400000000000000000000014161355360272700252560ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef XLAT_TABLES_ARCH_H #define XLAT_TABLES_ARCH_H #ifdef __aarch64__ #include "aarch64/xlat_tables_aarch64.h" #else #include "aarch32/xlat_tables_aarch32.h" #endif /* * Evaluates to 1 if the given physical address space size is a power of 2, * or 0 if it's not. */ #define CHECK_PHY_ADDR_SPACE_SIZE(size) \ (IS_POWER_OF_TWO(size)) /* * Compute the number of entries required at the initial lookup level to address * the whole virtual address space. */ #define GET_NUM_BASE_LEVEL_ENTRIES(addr_space_size) \ ((addr_space_size) >> \ XLAT_ADDR_SHIFT(GET_XLAT_TABLE_LEVEL_BASE(addr_space_size))) #endif /* XLAT_TABLES_ARCH_H */ trusted-firmware-a-2.2/include/lib/xlat_tables/xlat_tables_compat.h000066400000000000000000000003671355360272700256300ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #if XLAT_TABLES_LIB_V2 #include #else #include #endif trusted-firmware-a-2.2/include/lib/xlat_tables/xlat_tables_defs.h000066400000000000000000000145151355360272700252660ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef XLAT_TABLES_DEFS_H #define XLAT_TABLES_DEFS_H #include #include #include /* Miscellaneous MMU related constants */ #define NUM_2MB_IN_GB (U(1) << 9) #define NUM_4K_IN_2MB (U(1) << 9) #define NUM_GB_IN_4GB (U(1) << 2) #define TWO_MB_SHIFT U(21) #define ONE_GB_SHIFT U(30) #define FOUR_KB_SHIFT U(12) #define ONE_GB_INDEX(x) ((x) >> ONE_GB_SHIFT) #define TWO_MB_INDEX(x) ((x) >> TWO_MB_SHIFT) #define FOUR_KB_INDEX(x) ((x) >> FOUR_KB_SHIFT) #define PAGE_SIZE_4KB U(4096) #define PAGE_SIZE_16KB U(16384) #define PAGE_SIZE_64KB U(65536) #define INVALID_DESC U(0x0) /* * A block descriptor points to a region of memory bigger than the granule size * (e.g. a 2MB region when the granule size is 4KB). */ #define BLOCK_DESC U(0x1) /* Table levels 0-2 */ /* A table descriptor points to the next level of translation table. */ #define TABLE_DESC U(0x3) /* Table levels 0-2 */ /* * A page descriptor points to a page, i.e. a memory region whose size is the * translation granule size (e.g. 4KB). */ #define PAGE_DESC U(0x3) /* Table level 3 */ #define DESC_MASK U(0x3) #define FIRST_LEVEL_DESC_N ONE_GB_SHIFT #define SECOND_LEVEL_DESC_N TWO_MB_SHIFT #define THIRD_LEVEL_DESC_N FOUR_KB_SHIFT /* XN: Translation regimes that support one VA range (EL2 and EL3). */ #define XN (ULL(1) << 2) /* UXN, PXN: Translation regimes that support two VA ranges (EL1&0). */ #define UXN (ULL(1) << 2) #define PXN (ULL(1) << 1) #define CONT_HINT (ULL(1) << 0) #define UPPER_ATTRS(x) (((x) & ULL(0x7)) << 52) #define NON_GLOBAL (U(1) << 9) #define ACCESS_FLAG (U(1) << 8) #define NSH (U(0x0) << 6) #define OSH (U(0x2) << 6) #define ISH (U(0x3) << 6) #ifdef __aarch64__ /* Guarded Page bit */ #define GP (ULL(1) << 50) #endif #define TABLE_ADDR_MASK ULL(0x0000FFFFFFFFF000) /* * The ARMv8-A architecture allows translation granule sizes of 4KB, 16KB or * 64KB. However, only 4KB are supported at the moment. */ #define PAGE_SIZE_SHIFT FOUR_KB_SHIFT #define PAGE_SIZE (U(1) << PAGE_SIZE_SHIFT) #define PAGE_SIZE_MASK (PAGE_SIZE - U(1)) #define IS_PAGE_ALIGNED(addr) (((addr) & PAGE_SIZE_MASK) == U(0)) #if (ARM_ARCH_MAJOR == 7) && !ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING #define XLAT_ENTRY_SIZE_SHIFT U(2) /* Each MMU table entry is 4 bytes */ #else #define XLAT_ENTRY_SIZE_SHIFT U(3) /* Each MMU table entry is 8 bytes */ #endif #define XLAT_ENTRY_SIZE (U(1) << XLAT_ENTRY_SIZE_SHIFT) #define XLAT_TABLE_SIZE_SHIFT PAGE_SIZE_SHIFT /* Size of one complete table */ #define XLAT_TABLE_SIZE (U(1) << XLAT_TABLE_SIZE_SHIFT) #define XLAT_TABLE_LEVEL_MAX U(3) /* Values for number of entries in each MMU translation table */ #define XLAT_TABLE_ENTRIES_SHIFT (XLAT_TABLE_SIZE_SHIFT - XLAT_ENTRY_SIZE_SHIFT) #define XLAT_TABLE_ENTRIES (U(1) << XLAT_TABLE_ENTRIES_SHIFT) #define XLAT_TABLE_ENTRIES_MASK (XLAT_TABLE_ENTRIES - U(1)) /* Values to convert a memory address to an index into a translation table */ #define L3_XLAT_ADDRESS_SHIFT PAGE_SIZE_SHIFT #define L2_XLAT_ADDRESS_SHIFT (L3_XLAT_ADDRESS_SHIFT + XLAT_TABLE_ENTRIES_SHIFT) #define L1_XLAT_ADDRESS_SHIFT (L2_XLAT_ADDRESS_SHIFT + XLAT_TABLE_ENTRIES_SHIFT) #define L0_XLAT_ADDRESS_SHIFT (L1_XLAT_ADDRESS_SHIFT + XLAT_TABLE_ENTRIES_SHIFT) #define XLAT_ADDR_SHIFT(level) (PAGE_SIZE_SHIFT + \ ((XLAT_TABLE_LEVEL_MAX - (level)) * XLAT_TABLE_ENTRIES_SHIFT)) #define XLAT_BLOCK_SIZE(level) (UL(1) << XLAT_ADDR_SHIFT(level)) /* Mask to get the bits used to index inside a block of a certain level */ #define XLAT_BLOCK_MASK(level) (XLAT_BLOCK_SIZE(level) - UL(1)) /* Mask to get the address bits common to a block of a certain table level*/ #define XLAT_ADDR_MASK(level) (~XLAT_BLOCK_MASK(level)) /* * Extract from the given virtual address the index into the given lookup level. * This macro assumes the system is using the 4KB translation granule. */ #define XLAT_TABLE_IDX(virtual_addr, level) \ (((virtual_addr) >> XLAT_ADDR_SHIFT(level)) & ULL(0x1FF)) /* * The ARMv8 translation table descriptor format defines AP[2:1] as the Access * Permissions bits, and does not define an AP[0] bit. * * AP[1] is valid only for a stage 1 translation that supports two VA ranges * (i.e. in the ARMv8A.0 architecture, that is the S-EL1&0 regime). It is RES1 * when stage 1 translations can only support one VA range. */ #define AP2_SHIFT U(0x7) #define AP2_RO ULL(0x1) #define AP2_RW ULL(0x0) #define AP1_SHIFT U(0x6) #define AP1_ACCESS_UNPRIVILEGED ULL(0x1) #define AP1_NO_ACCESS_UNPRIVILEGED ULL(0x0) #define AP1_RES1 ULL(0x1) /* * The following definitions must all be passed to the LOWER_ATTRS() macro to * get the right bitmask. */ #define AP_RO (AP2_RO << 5) #define AP_RW (AP2_RW << 5) #define AP_ACCESS_UNPRIVILEGED (AP1_ACCESS_UNPRIVILEGED << 4) #define AP_NO_ACCESS_UNPRIVILEGED (AP1_NO_ACCESS_UNPRIVILEGED << 4) #define AP_ONE_VA_RANGE_RES1 (AP1_RES1 << 4) #define NS (U(0x1) << 3) #define ATTR_NON_CACHEABLE_INDEX ULL(0x2) #define ATTR_DEVICE_INDEX ULL(0x1) #define ATTR_IWBWA_OWBWA_NTR_INDEX ULL(0x0) #define LOWER_ATTRS(x) (((x) & U(0xfff)) << 2) /* Normal Memory, Outer Write-Through non-transient, Inner Non-cacheable */ #define ATTR_NON_CACHEABLE MAKE_MAIR_NORMAL_MEMORY(MAIR_NORM_NC, MAIR_NORM_NC) /* Device-nGnRE */ #define ATTR_DEVICE MAIR_DEV_nGnRE /* Normal Memory, Outer Write-Back non-transient, Inner Write-Back non-transient */ #define ATTR_IWBWA_OWBWA_NTR MAKE_MAIR_NORMAL_MEMORY(MAIR_NORM_WB_NTR_RWA, MAIR_NORM_WB_NTR_RWA) #define MAIR_ATTR_SET(attr, index) ((attr) << ((index) << 3)) #define ATTR_INDEX_MASK U(0x3) #define ATTR_INDEX_GET(attr) (((attr) >> 2) & ATTR_INDEX_MASK) /* * Shift values for the attributes fields in a block or page descriptor. * See section D4.3.3 in the ARMv8-A ARM (issue B.a). */ /* Memory attributes index field, AttrIndx[2:0]. */ #define ATTR_INDEX_SHIFT 2 /* Non-secure bit, NS. */ #define NS_SHIFT 5 /* Shareability field, SH[1:0] */ #define SHAREABILITY_SHIFT 8 /* The Access Flag, AF. */ #define ACCESS_FLAG_SHIFT 10 /* The not global bit, nG. */ #define NOT_GLOBAL_SHIFT 11 /* Contiguous hint bit. */ #define CONT_HINT_SHIFT 52 /* Execute-never bits, XN. */ #define PXN_SHIFT 53 #define XN_SHIFT 54 #define UXN_SHIFT XN_SHIFT #endif /* XLAT_TABLES_DEFS_H */ trusted-firmware-a-2.2/include/lib/xlat_tables/xlat_tables_v2.h000066400000000000000000000322311355360272700246670ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef XLAT_TABLES_V2_H #define XLAT_TABLES_V2_H #include #include #ifndef __ASSEMBLER__ #include #include #include /* * Default granularity size for an mmap_region_t. * Useful when no specific granularity is required. * * By default, choose the biggest possible block size allowed by the * architectural state and granule size in order to minimize the number of page * tables required for the mapping. */ #define REGION_DEFAULT_GRANULARITY XLAT_BLOCK_SIZE(MIN_LVL_BLOCK_DESC) /* Helper macro to define an mmap_region_t. */ #define MAP_REGION(_pa, _va, _sz, _attr) \ MAP_REGION_FULL_SPEC(_pa, _va, _sz, _attr, REGION_DEFAULT_GRANULARITY) /* Helper macro to define an mmap_region_t with an identity mapping. */ #define MAP_REGION_FLAT(_adr, _sz, _attr) \ MAP_REGION(_adr, _adr, _sz, _attr) /* * Helper macro to define entries for mmap_region_t. It allows to define 'pa' * and sets 'va' to 0 for each region. To be used with mmap_add_alloc_va(). */ #define MAP_REGION_ALLOC_VA(pa, sz, attr) MAP_REGION(pa, 0, sz, attr) /* * Helper macro to define an mmap_region_t to map with the desired granularity * of translation tables. * * The granularity value passed to this macro must be a valid block or page * size. When using a 4KB translation granule, this might be 4KB, 2MB or 1GB. * Passing REGION_DEFAULT_GRANULARITY is also allowed and means that the library * is free to choose the granularity for this region. In this case, it is * equivalent to the MAP_REGION() macro. */ #define MAP_REGION2(_pa, _va, _sz, _attr, _gr) \ MAP_REGION_FULL_SPEC(_pa, _va, _sz, _attr, _gr) /* * Shifts and masks to access fields of an mmap attribute */ #define MT_TYPE_MASK U(0x7) #define MT_TYPE(_attr) ((_attr) & MT_TYPE_MASK) /* Access permissions (RO/RW) */ #define MT_PERM_SHIFT U(3) /* Security state (SECURE/NS) */ #define MT_SEC_SHIFT U(4) /* Access permissions for instruction execution (EXECUTE/EXECUTE_NEVER) */ #define MT_EXECUTE_SHIFT U(5) /* In the EL1&0 translation regime, User (EL0) or Privileged (EL1). */ #define MT_USER_SHIFT U(6) /* All other bits are reserved */ /* * Memory mapping attributes */ /* * Memory types supported. * These are organised so that, going down the list, the memory types are * getting weaker; conversely going up the list the memory types are getting * stronger. */ #define MT_DEVICE U(0) #define MT_NON_CACHEABLE U(1) #define MT_MEMORY U(2) /* Values up to 7 are reserved to add new memory types in the future */ #define MT_RO (U(0) << MT_PERM_SHIFT) #define MT_RW (U(1) << MT_PERM_SHIFT) #define MT_SECURE (U(0) << MT_SEC_SHIFT) #define MT_NS (U(1) << MT_SEC_SHIFT) /* * Access permissions for instruction execution are only relevant for normal * read-only memory, i.e. MT_MEMORY | MT_RO. They are ignored (and potentially * overridden) otherwise: * - Device memory is always marked as execute-never. * - Read-write normal memory is always marked as execute-never. */ #define MT_EXECUTE (U(0) << MT_EXECUTE_SHIFT) #define MT_EXECUTE_NEVER (U(1) << MT_EXECUTE_SHIFT) /* * When mapping a region at EL0 or EL1, this attribute will be used to determine * if a User mapping (EL0) will be created or a Privileged mapping (EL1). */ #define MT_USER (U(1) << MT_USER_SHIFT) #define MT_PRIVILEGED (U(0) << MT_USER_SHIFT) /* Compound attributes for most common usages */ #define MT_CODE (MT_MEMORY | MT_RO | MT_EXECUTE) #define MT_RO_DATA (MT_MEMORY | MT_RO | MT_EXECUTE_NEVER) #define MT_RW_DATA (MT_MEMORY | MT_RW | MT_EXECUTE_NEVER) /* * Structure for specifying a single region of memory. */ typedef struct mmap_region { unsigned long long base_pa; uintptr_t base_va; size_t size; unsigned int attr; /* Desired granularity. See the MAP_REGION2() macro for more details. */ size_t granularity; } mmap_region_t; /* * Translation regimes supported by this library. EL_REGIME_INVALID tells the * library to detect it at runtime. */ #define EL1_EL0_REGIME 1 #define EL2_REGIME 2 #define EL3_REGIME 3 #define EL_REGIME_INVALID -1 /* * Declare the translation context type. * Its definition is private. */ typedef struct xlat_ctx xlat_ctx_t; /* * Statically allocate a translation context and associated structures. Also * initialize them. * * _ctx_name: * Prefix for the translation context variable. * E.g. If _ctx_name is 'foo', the variable will be called 'foo_xlat_ctx'. * Useful to distinguish multiple contexts from one another. * * _mmap_count: * Number of mmap_region_t to allocate. * Would typically be MAX_MMAP_REGIONS for the translation context describing * the BL image currently executing. * * _xlat_tables_count: * Number of sub-translation tables to allocate. * Would typically be MAX_XLAT_TABLES for the translation context describing * the BL image currently executing. * Note that this is only for sub-tables ; at the initial lookup level, there * is always a single table. * * _virt_addr_space_size, _phy_addr_space_size: * Size (in bytes) of the virtual (resp. physical) address space. * Would typically be PLAT_VIRT_ADDR_SPACE_SIZE * (resp. PLAT_PHY_ADDR_SPACE_SIZE) for the translation context describing the * BL image currently executing. */ #define REGISTER_XLAT_CONTEXT(_ctx_name, _mmap_count, _xlat_tables_count, \ _virt_addr_space_size, _phy_addr_space_size) \ REGISTER_XLAT_CONTEXT_FULL_SPEC(_ctx_name, (_mmap_count), \ (_xlat_tables_count), \ (_virt_addr_space_size), \ (_phy_addr_space_size), \ EL_REGIME_INVALID, "xlat_table") /* * Same as REGISTER_XLAT_CONTEXT plus the additional parameters: * * _xlat_regime: * Specify the translation regime managed by this xlat_ctx_t instance. The * values are the one from the EL*_REGIME definitions. * * _section_name: * Specify the name of the section where the translation tables have to be * placed by the linker. */ #define REGISTER_XLAT_CONTEXT2(_ctx_name, _mmap_count, _xlat_tables_count, \ _virt_addr_space_size, _phy_addr_space_size, \ _xlat_regime, _section_name) \ REGISTER_XLAT_CONTEXT_FULL_SPEC(_ctx_name, (_mmap_count), \ (_xlat_tables_count), \ (_virt_addr_space_size), \ (_phy_addr_space_size), \ (_xlat_regime), (_section_name)) /****************************************************************************** * Generic translation table APIs. * Each API comes in 2 variants: * - one that acts on the current translation context for this BL image * - another that acts on the given translation context instead. This variant * is named after the 1st version, with an additional '_ctx' suffix. *****************************************************************************/ /* * Initialize translation tables from the current list of mmap regions. Calling * this function marks the transition point after which static regions can no * longer be added. */ void init_xlat_tables(void); void init_xlat_tables_ctx(xlat_ctx_t *ctx); /* * Fill all fields of a dynamic translation tables context. It must be done * either statically with REGISTER_XLAT_CONTEXT() or at runtime with this * function. */ void xlat_setup_dynamic_ctx(xlat_ctx_t *ctx, unsigned long long pa_max, uintptr_t va_max, struct mmap_region *mmap, unsigned int mmap_num, uint64_t **tables, unsigned int tables_num, uint64_t *base_table, int xlat_regime, int *mapped_regions); /* * Add a static region with defined base PA and base VA. This function can only * be used before initializing the translation tables. The region cannot be * removed afterwards. */ void mmap_add_region(unsigned long long base_pa, uintptr_t base_va, size_t size, unsigned int attr); void mmap_add_region_ctx(xlat_ctx_t *ctx, const mmap_region_t *mm); /* * Add an array of static regions with defined base PA and base VA. This * function can only be used before initializing the translation tables. The * regions cannot be removed afterwards. */ void mmap_add(const mmap_region_t *mm); void mmap_add_ctx(xlat_ctx_t *ctx, const mmap_region_t *mm); /* * Add a region with defined base PA. Returns base VA calculated using the * highest existing region in the mmap array even if it fails to allocate the * region. */ void mmap_add_region_alloc_va(unsigned long long base_pa, uintptr_t *base_va, size_t size, unsigned int attr); void mmap_add_region_alloc_va_ctx(xlat_ctx_t *ctx, mmap_region_t *mm); /* * Add an array of static regions with defined base PA, and fill the base VA * field on the array of structs. This function can only be used before * initializing the translation tables. The regions cannot be removed afterwards. */ void mmap_add_alloc_va(mmap_region_t *mm); #if PLAT_XLAT_TABLES_DYNAMIC /* * Add a dynamic region with defined base PA and base VA. This type of region * can be added and removed even after the translation tables are initialized. * * Returns: * 0: Success. * EINVAL: Invalid values were used as arguments. * ERANGE: Memory limits were surpassed. * ENOMEM: Not enough space in the mmap array or not enough free xlat tables. * EPERM: It overlaps another region in an invalid way. */ int mmap_add_dynamic_region(unsigned long long base_pa, uintptr_t base_va, size_t size, unsigned int attr); int mmap_add_dynamic_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm); /* * Add a dynamic region with defined base PA. Returns base VA calculated using * the highest existing region in the mmap array even if it fails to allocate * the region. * * mmap_add_dynamic_region_alloc_va() returns the allocated VA in 'base_va'. * mmap_add_dynamic_region_alloc_va_ctx() returns it in 'mm->base_va'. * * It returns the same error values as mmap_add_dynamic_region(). */ int mmap_add_dynamic_region_alloc_va(unsigned long long base_pa, uintptr_t *base_va, size_t size, unsigned int attr); int mmap_add_dynamic_region_alloc_va_ctx(xlat_ctx_t *ctx, mmap_region_t *mm); /* * Remove a region with the specified base VA and size. Only dynamic regions can * be removed, and they can be removed even if the translation tables are * initialized. * * Returns: * 0: Success. * EINVAL: The specified region wasn't found. * EPERM: Trying to remove a static region. */ int mmap_remove_dynamic_region(uintptr_t base_va, size_t size); int mmap_remove_dynamic_region_ctx(xlat_ctx_t *ctx, uintptr_t base_va, size_t size); #endif /* PLAT_XLAT_TABLES_DYNAMIC */ /* * Change the memory attributes of the memory region starting from a given * virtual address in a set of translation tables. * * This function can only be used after the translation tables have been * initialized. * * The base address of the memory region must be aligned on a page boundary. * The size of this memory region must be a multiple of a page size. * The memory region must be already mapped by the given translation tables * and it must be mapped at the granularity of a page. * * Return 0 on success, a negative value on error. * * In case of error, the memory attributes remain unchanged and this function * has no effect. * * ctx * Translation context to work on. * base_va: * Virtual address of the 1st page to change the attributes of. * size: * Size in bytes of the memory region. * attr: * New attributes of the page tables. The attributes that can be changed are * data access (MT_RO/MT_RW), instruction access (MT_EXECUTE_NEVER/MT_EXECUTE) * and user/privileged access (MT_USER/MT_PRIVILEGED) in the case of contexts * that are used in the EL1&0 translation regime. Also, note that this * function doesn't allow to remap a region as RW and executable, or to remap * device memory as executable. * * NOTE: The caller of this function must be able to write to the translation * tables, i.e. the memory where they are stored must be mapped with read-write * access permissions. This function assumes it is the case. If this is not * the case then this function might trigger a data abort exception. * * NOTE2: The caller is responsible for making sure that the targeted * translation tables are not modified by any other code while this function is * executing. */ int xlat_change_mem_attributes_ctx(const xlat_ctx_t *ctx, uintptr_t base_va, size_t size, uint32_t attr); int xlat_change_mem_attributes(uintptr_t base_va, size_t size, uint32_t attr); /* * Query the memory attributes of a memory page in a set of translation tables. * * Return 0 on success, a negative error code on error. * On success, the attributes are stored into *attr. * * ctx * Translation context to work on. * base_va * Virtual address of the page to get the attributes of. * There are no alignment restrictions on this address. The attributes of the * memory page it lies within are returned. * attr * Output parameter where to store the attributes of the targeted memory page. */ int xlat_get_mem_attributes_ctx(const xlat_ctx_t *ctx, uintptr_t base_va, uint32_t *attr); int xlat_get_mem_attributes(uintptr_t base_va, uint32_t *attr); #endif /*__ASSEMBLER__*/ #endif /* XLAT_TABLES_V2_H */ trusted-firmware-a-2.2/include/lib/xlat_tables/xlat_tables_v2_helpers.h000066400000000000000000000115721355360272700264160ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * This header file contains internal definitions that are not supposed to be * used outside of this library code. */ #ifndef XLAT_TABLES_V2_HELPERS_H #define XLAT_TABLES_V2_HELPERS_H #ifndef XLAT_TABLES_V2_H #error "Do not include this header file directly. Include xlat_tables_v2.h instead." #endif #ifndef __ASSEMBLER__ #include #include #include #include #include #include /* Forward declaration */ struct mmap_region; /* * Helper macro to define an mmap_region_t. This macro allows to specify all * the fields of the structure but its parameter list is not guaranteed to * remain stable as we add members to mmap_region_t. */ #define MAP_REGION_FULL_SPEC(_pa, _va, _sz, _attr, _gr) \ { \ .base_pa = (_pa), \ .base_va = (_va), \ .size = (_sz), \ .attr = (_attr), \ .granularity = (_gr), \ } /* Struct that holds all information about the translation tables. */ struct xlat_ctx { /* * Max allowed Virtual and Physical Addresses. */ unsigned long long pa_max_address; uintptr_t va_max_address; /* * Array of all memory regions stored in order of ascending end address * and ascending size to simplify the code that allows overlapping * regions. The list is terminated by the first entry with size == 0. * The max size of the list is stored in `mmap_num`. `mmap` points to an * array of mmap_num + 1 elements, so that there is space for the final * null entry. */ struct mmap_region *mmap; int mmap_num; /* * Array of finer-grain translation tables. * For example, if the initial lookup level is 1 then this array would * contain both level-2 and level-3 entries. */ uint64_t (*tables)[XLAT_TABLE_ENTRIES]; int tables_num; /* * Keep track of how many regions are mapped in each table. The base * table can't be unmapped so it isn't needed to keep track of it. */ #if PLAT_XLAT_TABLES_DYNAMIC int *tables_mapped_regions; #endif /* PLAT_XLAT_TABLES_DYNAMIC */ int next_table; /* * Base translation table. It doesn't need to have the same amount of * entries as the ones used for other levels. */ uint64_t *base_table; unsigned int base_table_entries; /* * Max Physical and Virtual addresses currently in use by the * translation tables. These might get updated as we map/unmap memory * regions but they will never go beyond pa/va_max_address. */ unsigned long long max_pa; uintptr_t max_va; /* Level of the base translation table. */ unsigned int base_level; /* Set to true when the translation tables are initialized. */ bool initialized; /* * Translation regime managed by this xlat_ctx_t. It should be one of * the EL*_REGIME defines. */ int xlat_regime; }; #if PLAT_XLAT_TABLES_DYNAMIC #define XLAT_ALLOC_DYNMAP_STRUCT(_ctx_name, _xlat_tables_count) \ static int _ctx_name##_mapped_regions[_xlat_tables_count]; #define XLAT_REGISTER_DYNMAP_STRUCT(_ctx_name) \ .tables_mapped_regions = _ctx_name##_mapped_regions, #else #define XLAT_ALLOC_DYNMAP_STRUCT(_ctx_name, _xlat_tables_count) \ /* do nothing */ #define XLAT_REGISTER_DYNMAP_STRUCT(_ctx_name) \ /* do nothing */ #endif /* PLAT_XLAT_TABLES_DYNAMIC */ #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)\ CASSERT(CHECK_PHY_ADDR_SPACE_SIZE(_phy_addr_space_size), \ assert_invalid_physical_addr_space_sizefor_##_ctx_name);\ \ 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_ALLOC_DYNMAP_STRUCT(_ctx_name, _xlat_tables_count) \ \ static xlat_ctx_t _ctx_name##_xlat_ctx = { \ .va_max_address = (_virt_addr_space_size) - 1UL, \ .pa_max_address = (_phy_addr_space_size) - 1ULL, \ .mmap = _ctx_name##_mmap, \ .mmap_num = (_mmap_count), \ .base_level = GET_XLAT_TABLE_LEVEL_BASE(_virt_addr_space_size),\ .base_table = _ctx_name##_base_xlat_table, \ .base_table_entries = \ GET_NUM_BASE_LEVEL_ENTRIES(_virt_addr_space_size),\ .tables = _ctx_name##_xlat_tables, \ .tables_num = _xlat_tables_count, \ XLAT_REGISTER_DYNMAP_STRUCT(_ctx_name) \ .xlat_regime = (_xlat_regime), \ .max_pa = 0U, \ .max_va = 0U, \ .next_table = 0, \ .initialized = false, \ } #endif /*__ASSEMBLER__*/ #endif /* XLAT_TABLES_V2_HELPERS_H */ trusted-firmware-a-2.2/include/lib/zlib/000077500000000000000000000000001355360272700202425ustar00rootroot00000000000000trusted-firmware-a-2.2/include/lib/zlib/tf_gunzip.h000066400000000000000000000005451355360272700224240ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TF_GUNZIP_H #define TF_GUNZIP_H #include #include int gunzip(uintptr_t *in_buf, size_t in_len, uintptr_t *out_buf, size_t out_len, uintptr_t work_buf, size_t work_len); #endif /* TF_GUNZIP_H */ trusted-firmware-a-2.2/include/plat/000077500000000000000000000000001355360272700174745ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/arm/000077500000000000000000000000001355360272700202535ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/arm/board/000077500000000000000000000000001355360272700213425ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/arm/board/common/000077500000000000000000000000001355360272700226325ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/arm/board/common/board_css_def.h000066400000000000000000000043431355360272700255640ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BOARD_CSS_DEF_H #define BOARD_CSS_DEF_H #include #include #include #include /* * Definitions common to all ARM CSS-based development platforms */ /* Platform ID address */ #define BOARD_CSS_PLAT_ID_REG_ADDR 0x7ffe00e0 /* Platform ID related accessors */ #define BOARD_CSS_PLAT_ID_REG_ID_MASK 0x0f #define BOARD_CSS_PLAT_ID_REG_ID_SHIFT 0x0 #define BOARD_CSS_PLAT_ID_REG_VERSION_MASK 0xf00 #define BOARD_CSS_PLAT_ID_REG_VERSION_SHIFT 0x8 #define BOARD_CSS_PLAT_TYPE_RTL 0x00 #define BOARD_CSS_PLAT_TYPE_FPGA 0x01 #define BOARD_CSS_PLAT_TYPE_EMULATOR 0x02 #define BOARD_CSS_PLAT_TYPE_FVP 0x03 #ifndef __ASSEMBLER__ #include #define BOARD_CSS_GET_PLAT_TYPE(addr) \ ((mmio_read_32(addr) & BOARD_CSS_PLAT_ID_REG_ID_MASK) \ >> BOARD_CSS_PLAT_ID_REG_ID_SHIFT) #endif /* __ASSEMBLER__ */ #define MAX_IO_DEVICES 3 #define MAX_IO_HANDLES 4 /* Reserve the last block of flash for PSCI MEM PROTECT flag */ #define PLAT_ARM_FIP_BASE V2M_FLASH0_BASE #define PLAT_ARM_FIP_MAX_SIZE (V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE) #define PLAT_ARM_NVM_BASE V2M_FLASH0_BASE #define PLAT_ARM_NVM_SIZE (V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE) /* * Required platform porting definitions common to all ARM CSS-based * development platforms */ #define PLAT_ARM_DRAM2_BASE ULL(0x880000000) #define PLAT_ARM_DRAM2_SIZE ULL(0x180000000) /* UART related constants */ #define PLAT_ARM_BOOT_UART_BASE SOC_CSS_UART0_BASE #define PLAT_ARM_BOOT_UART_CLK_IN_HZ SOC_CSS_UART0_CLK_IN_HZ #define PLAT_ARM_RUN_UART_BASE SOC_CSS_UART1_BASE #define PLAT_ARM_RUN_UART_CLK_IN_HZ SOC_CSS_UART1_CLK_IN_HZ #define PLAT_ARM_SP_MIN_RUN_UART_BASE SOC_CSS_UART1_BASE #define PLAT_ARM_SP_MIN_RUN_UART_CLK_IN_HZ SOC_CSS_UART1_CLK_IN_HZ #define PLAT_ARM_CRASH_UART_BASE PLAT_ARM_RUN_UART_BASE #define PLAT_ARM_CRASH_UART_CLK_IN_HZ PLAT_ARM_RUN_UART_CLK_IN_HZ #define PLAT_ARM_TSP_UART_BASE V2M_IOFPGA_UART0_BASE #define PLAT_ARM_TSP_UART_CLK_IN_HZ V2M_IOFPGA_UART0_CLK_IN_HZ #endif /* BOARD_CSS_DEF_H */ trusted-firmware-a-2.2/include/plat/arm/board/common/v2m_def.h000066400000000000000000000102521355360272700243250ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef V2M_DEF_H #define V2M_DEF_H #include /* V2M motherboard system registers & offsets */ #define V2M_SYSREGS_BASE UL(0x1c010000) #define V2M_SYS_ID UL(0x0) #define V2M_SYS_SWITCH UL(0x4) #define V2M_SYS_LED UL(0x8) #define V2M_SYS_NVFLAGS UL(0x38) #define V2M_SYS_NVFLAGSSET UL(0x38) #define V2M_SYS_NVFLAGSCLR UL(0x3c) #define V2M_SYS_CFGDATA UL(0xa0) #define V2M_SYS_CFGCTRL UL(0xa4) #define V2M_SYS_CFGSTATUS UL(0xa8) #define V2M_CFGCTRL_START BIT_32(31) #define V2M_CFGCTRL_RW BIT_32(30) #define V2M_CFGCTRL_FUNC_SHIFT 20 #define V2M_CFGCTRL_FUNC(fn) ((fn) << V2M_CFGCTRL_FUNC_SHIFT) #define V2M_FUNC_CLK_GEN U(0x01) #define V2M_FUNC_TEMP U(0x04) #define V2M_FUNC_DB_RESET U(0x05) #define V2M_FUNC_SCC_CFG U(0x06) #define V2M_FUNC_SHUTDOWN U(0x08) #define V2M_FUNC_REBOOT U(0x09) /* NVFLAGS in the V2M motherboard which is preserved after a watchdog reset */ #define V2M_SYS_NVFLAGS_ADDR (V2M_SYSREGS_BASE + V2M_SYS_NVFLAGS) /* * V2M sysled bit definitions. The values written to this * register are defined in arch.h & runtime_svc.h. Only * used by the primary cpu to diagnose any cold boot issues. * * SYS_LED[0] - Security state (S=0/NS=1) * SYS_LED[2:1] - Exception Level (EL3-EL0) * SYS_LED[7:3] - Exception Class (Sync/Async & origin) * */ #define V2M_SYS_LED_SS_SHIFT 0x0 #define V2M_SYS_LED_EL_SHIFT 0x1 #define V2M_SYS_LED_EC_SHIFT 0x3 #define V2M_SYS_LED_SS_MASK U(0x1) #define V2M_SYS_LED_EL_MASK U(0x3) #define V2M_SYS_LED_EC_MASK U(0x1f) /* V2M sysid register bits */ #define V2M_SYS_ID_REV_SHIFT 28 #define V2M_SYS_ID_HBI_SHIFT 16 #define V2M_SYS_ID_BLD_SHIFT 12 #define V2M_SYS_ID_ARCH_SHIFT 8 #define V2M_SYS_ID_FPGA_SHIFT 0 #define V2M_SYS_ID_REV_MASK U(0xf) #define V2M_SYS_ID_HBI_MASK U(0xfff) #define V2M_SYS_ID_BLD_MASK U(0xf) #define V2M_SYS_ID_ARCH_MASK U(0xf) #define V2M_SYS_ID_FPGA_MASK U(0xff) #define V2M_SYS_ID_BLD_LENGTH 4 /* NOR Flash */ #define V2M_FLASH0_BASE UL(0x08000000) #define V2M_FLASH0_SIZE UL(0x04000000) #define V2M_FLASH_BLOCK_SIZE UL(0x00040000) /* 256 KB */ #define V2M_IOFPGA_BASE UL(0x1c000000) #define V2M_IOFPGA_SIZE UL(0x03000000) /* PL011 UART related constants */ #define V2M_IOFPGA_UART0_BASE UL(0x1c090000) #define V2M_IOFPGA_UART1_BASE UL(0x1c0a0000) #define V2M_IOFPGA_UART2_BASE UL(0x1c0b0000) #define V2M_IOFPGA_UART3_BASE UL(0x1c0c0000) #define V2M_IOFPGA_UART0_CLK_IN_HZ 24000000 #define V2M_IOFPGA_UART1_CLK_IN_HZ 24000000 #define V2M_IOFPGA_UART2_CLK_IN_HZ 24000000 #define V2M_IOFPGA_UART3_CLK_IN_HZ 24000000 /* SP804 timer related constants */ #define V2M_SP804_TIMER0_BASE UL(0x1C110000) #define V2M_SP804_TIMER1_BASE UL(0x1C120000) /* SP810 controller */ #define V2M_SP810_BASE UL(0x1c020000) #define V2M_SP810_CTRL_TIM0_SEL BIT_32(15) #define V2M_SP810_CTRL_TIM1_SEL BIT_32(17) #define V2M_SP810_CTRL_TIM2_SEL BIT_32(19) #define V2M_SP810_CTRL_TIM3_SEL BIT_32(21) /* * The flash can be mapped either as read-only or read-write. * * If it is read-write then it should also be mapped as device memory because * NOR flash programming involves sending a fixed, ordered sequence of commands. * * If it is read-only then it should also be mapped as: * - Normal memory, because reading from NOR flash is transparent, it is like * reading from RAM. * - Non-executable by default. If some parts of the flash need to be executable * then platform code is responsible for re-mapping the appropriate portion * of it as executable. */ #define V2M_MAP_FLASH0_RW MAP_REGION_FLAT(V2M_FLASH0_BASE,\ V2M_FLASH0_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define V2M_MAP_FLASH0_RO MAP_REGION_FLAT(V2M_FLASH0_BASE,\ V2M_FLASH0_SIZE, \ MT_RO_DATA | MT_SECURE) #define V2M_MAP_IOFPGA MAP_REGION_FLAT(V2M_IOFPGA_BASE,\ V2M_IOFPGA_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) /* Region equivalent to V2M_MAP_IOFPGA suitable for mapping at EL0 */ #define V2M_MAP_IOFPGA_EL0 MAP_REGION_FLAT( \ V2M_IOFPGA_BASE, \ V2M_IOFPGA_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE | MT_USER) #endif /* V2M_DEF_H */ trusted-firmware-a-2.2/include/plat/arm/common/000077500000000000000000000000001355360272700215435ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/arm/common/aarch64/000077500000000000000000000000001355360272700227735ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/arm/common/aarch64/arm_macros.S000066400000000000000000000047151355360272700252510ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_MACROS_S #define ARM_MACROS_S #include #include #include #include .section .rodata.gic_reg_name, "aS" /* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */ gicc_regs: .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", "" /* Applicable only to GICv3 with SRE enabled */ icc_regs: .asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", "" /* Registers common to both GICv2 and GICv3 */ gicd_pend_reg: .asciz "gicd_ispendr regs (Offsets 0x200-0x278)\nOffset\t\t\tValue\n" newline: .asciz "\n" spacer: .asciz ":\t\t 0x" prefix: .asciz "0x" /* --------------------------------------------- * The below utility macro prints out relevant GIC * registers whenever an unhandled exception is * taken in BL31 on ARM standard platforms. * Expects: GICD base in x16, GICC base in x17 * Clobbers: x0 - x10, sp * --------------------------------------------- */ .macro arm_print_gic_regs /* Check for GICv3 system register access */ mrs x7, id_aa64pfr0_el1 ubfx x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH cmp x7, #1 b.ne print_gicv2 /* Check for SRE enable */ mrs x8, ICC_SRE_EL3 tst x8, #ICC_SRE_SRE_BIT b.eq print_gicv2 /* Load the icc reg list to x6 */ adr x6, icc_regs /* Load the icc regs to gp regs used by str_in_crash_buf_print */ mrs x8, ICC_HPPIR0_EL1 mrs x9, ICC_HPPIR1_EL1 mrs x10, ICC_CTLR_EL3 /* Store to the crash buf and print to console */ bl str_in_crash_buf_print b print_gic_common print_gicv2: /* Load the gicc reg list to x6 */ adr x6, gicc_regs /* Load the gicc regs to gp regs used by str_in_crash_buf_print */ ldr w8, [x17, #GICC_HPPIR] ldr w9, [x17, #GICC_AHPPIR] ldr w10, [x17, #GICC_CTLR] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print print_gic_common: /* Print the GICD_ISPENDR regs */ add x7, x16, #GICD_ISPENDR adr x4, gicd_pend_reg bl asm_print_str gicd_ispendr_loop: sub x4, x7, x16 cmp x4, #0x280 b.eq exit_print_gic_regs /* Print "0x" */ adr x4, prefix bl asm_print_str /* Print offset */ sub x4, x7, x16 mov x5, #12 bl asm_print_hex_bits adr x4, spacer bl asm_print_str ldr x4, [x7], #8 bl asm_print_hex adr x4, newline bl asm_print_str b gicd_ispendr_loop exit_print_gic_regs: .endm #endif /* ARM_MACROS_S */ trusted-firmware-a-2.2/include/plat/arm/common/aarch64/cci_macros.S000066400000000000000000000022051355360272700252200ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CCI_MACROS_S #define CCI_MACROS_S #include #include .section .rodata.cci_reg_name, "aS" cci_iface_regs: .asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , "" /* ------------------------------------------------ * The below required platform porting macro prints * out relevant interconnect registers whenever an * unhandled exception is taken in BL31. * Clobbers: x0 - x9, sp * ------------------------------------------------ */ .macro print_cci_regs adr x6, cci_iface_regs /* Store in x7 the base address of the first interface */ mov_imm x7, (PLAT_ARM_CCI_BASE + SLAVE_IFACE_OFFSET( \ PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX)) ldr w8, [x7, #SNOOP_CTRL_REG] /* Store in x7 the base address of the second interface */ mov_imm x7, (PLAT_ARM_CCI_BASE + SLAVE_IFACE_OFFSET( \ PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX)) ldr w9, [x7, #SNOOP_CTRL_REG] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print .endm #endif /* CCI_MACROS_S */ trusted-firmware-a-2.2/include/plat/arm/common/arm_config.h000066400000000000000000000016671355360272700240320ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_CONFIG_H #define ARM_CONFIG_H #include #include /* Whether Base memory map is in use */ #define ARM_CONFIG_BASE_MMAP BIT(1) /* Whether TZC should be configured */ #define ARM_CONFIG_HAS_TZC BIT(2) /* FVP model has shifted affinity */ #define ARM_CONFIG_FVP_SHIFTED_AFF BIT(3) /* FVP model has SMMUv3 affinity */ #define ARM_CONFIG_FVP_HAS_SMMUV3 BIT(4) /* FVP model has CCI (400 or 500/550) devices */ #define ARM_CONFIG_FVP_HAS_CCI400 BIT(5) #define ARM_CONFIG_FVP_HAS_CCI5XX BIT(6) typedef struct arm_config { unsigned long flags; } arm_config_t; /* If used, arm_config must be defined and populated in the platform port */ extern arm_config_t arm_config; static inline const arm_config_t *get_arm_config(void) { return &arm_config; } #endif /* ARM_CONFIG_H */ trusted-firmware-a-2.2/include/plat/arm/common/arm_def.h000066400000000000000000000464521355360272700233240ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_DEF_H #define ARM_DEF_H #include #include #include #include #include #include #include /****************************************************************************** * Definitions common to all ARM standard platforms *****************************************************************************/ /* Special value used to verify platform parameters from BL2 to BL31 */ #define ARM_BL31_PLAT_PARAM_VAL ULL(0x0f1e2d3c4b5a6978) #define ARM_SYSTEM_COUNT 1 #define ARM_CACHE_WRITEBACK_SHIFT 6 /* * Macros mapping the MPIDR Affinity levels to ARM Platform Power levels. The * power levels have a 1:1 mapping with the MPIDR affinity levels. */ #define ARM_PWR_LVL0 MPIDR_AFFLVL0 #define ARM_PWR_LVL1 MPIDR_AFFLVL1 #define ARM_PWR_LVL2 MPIDR_AFFLVL2 #define ARM_PWR_LVL3 MPIDR_AFFLVL3 /* * Macros for local power states in ARM platforms encoded by State-ID field * within the power-state parameter. */ /* Local power state for power domains in Run state. */ #define ARM_LOCAL_STATE_RUN U(0) /* Local power state for retention. Valid only for CPU power domains */ #define ARM_LOCAL_STATE_RET U(1) /* Local power state for OFF/power-down. Valid for CPU and cluster power domains */ #define ARM_LOCAL_STATE_OFF U(2) /* Memory location options for TSP */ #define ARM_TRUSTED_SRAM_ID 0 #define ARM_TRUSTED_DRAM_ID 1 #define ARM_DRAM_ID 2 /* The first 4KB of Trusted SRAM are used as shared memory */ #define ARM_TRUSTED_SRAM_BASE UL(0x04000000) #define ARM_SHARED_RAM_BASE ARM_TRUSTED_SRAM_BASE #define ARM_SHARED_RAM_SIZE UL(0x00001000) /* 4 KB */ /* The remaining Trusted SRAM is used to load the BL images */ #define ARM_BL_RAM_BASE (ARM_SHARED_RAM_BASE + \ ARM_SHARED_RAM_SIZE) #define ARM_BL_RAM_SIZE (PLAT_ARM_TRUSTED_SRAM_SIZE - \ ARM_SHARED_RAM_SIZE) /* * The top 16MB of DRAM1 is configured as secure access only using the TZC * - SCP TZC DRAM: If present, DRAM reserved for SCP use * - AP TZC DRAM: The remaining TZC secured DRAM reserved for AP use */ #define ARM_TZC_DRAM1_SIZE UL(0x01000000) #define ARM_SCP_TZC_DRAM1_BASE (ARM_DRAM1_BASE + \ ARM_DRAM1_SIZE - \ ARM_SCP_TZC_DRAM1_SIZE) #define ARM_SCP_TZC_DRAM1_SIZE PLAT_ARM_SCP_TZC_DRAM1_SIZE #define ARM_SCP_TZC_DRAM1_END (ARM_SCP_TZC_DRAM1_BASE + \ ARM_SCP_TZC_DRAM1_SIZE - 1) /* * Define a 2MB region within the TZC secured DRAM for use by EL3 runtime * firmware. This region is meant to be NOLOAD and will not be zero * initialized. Data sections with the attribute `arm_el3_tzc_dram` will be * placed here. */ #define ARM_EL3_TZC_DRAM1_BASE (ARM_SCP_TZC_DRAM1_BASE - ARM_EL3_TZC_DRAM1_SIZE) #define ARM_EL3_TZC_DRAM1_SIZE UL(0x00200000) /* 2 MB */ #define ARM_EL3_TZC_DRAM1_END (ARM_EL3_TZC_DRAM1_BASE + \ ARM_EL3_TZC_DRAM1_SIZE - 1) #define ARM_AP_TZC_DRAM1_BASE (ARM_DRAM1_BASE + \ ARM_DRAM1_SIZE - \ ARM_TZC_DRAM1_SIZE) #define ARM_AP_TZC_DRAM1_SIZE (ARM_TZC_DRAM1_SIZE - \ (ARM_SCP_TZC_DRAM1_SIZE + \ ARM_EL3_TZC_DRAM1_SIZE)) #define ARM_AP_TZC_DRAM1_END (ARM_AP_TZC_DRAM1_BASE + \ ARM_AP_TZC_DRAM1_SIZE - 1) /* Define the Access permissions for Secure peripherals to NS_DRAM */ #if ARM_CRYPTOCELL_INTEG /* * Allow Secure peripheral to read NS DRAM when integrated with CryptoCell. * This is required by CryptoCell to authenticate BL33 which is loaded * into the Non Secure DDR. */ #define ARM_TZC_NS_DRAM_S_ACCESS TZC_REGION_S_RD #else #define ARM_TZC_NS_DRAM_S_ACCESS TZC_REGION_S_NONE #endif #ifdef SPD_opteed /* * BL2 needs to map 4MB at the end of TZC_DRAM1 in order to * load/authenticate the trusted os extra image. The first 512KB of * TZC_DRAM1 are reserved for trusted os (OPTEE). The extra image loading * for OPTEE is paged image which only include the paging part using * virtual memory but without "init" data. OPTEE will copy the "init" data * (from pager image) to the first 512KB of TZC_DRAM, and then copy the * extra image behind the "init" data. */ #define ARM_OPTEE_PAGEABLE_LOAD_BASE (ARM_AP_TZC_DRAM1_BASE + \ ARM_AP_TZC_DRAM1_SIZE - \ ARM_OPTEE_PAGEABLE_LOAD_SIZE) #define ARM_OPTEE_PAGEABLE_LOAD_SIZE UL(0x400000) #define ARM_OPTEE_PAGEABLE_LOAD_MEM MAP_REGION_FLAT( \ ARM_OPTEE_PAGEABLE_LOAD_BASE, \ ARM_OPTEE_PAGEABLE_LOAD_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) /* * Map the memory for the OP-TEE core (also known as OP-TEE pager when paging * support is enabled). */ #define ARM_MAP_OPTEE_CORE_MEM MAP_REGION_FLAT( \ BL32_BASE, \ BL32_LIMIT - BL32_BASE, \ MT_MEMORY | MT_RW | MT_SECURE) #endif /* SPD_opteed */ #define ARM_NS_DRAM1_BASE ARM_DRAM1_BASE #define ARM_NS_DRAM1_SIZE (ARM_DRAM1_SIZE - \ ARM_TZC_DRAM1_SIZE) #define ARM_NS_DRAM1_END (ARM_NS_DRAM1_BASE + \ ARM_NS_DRAM1_SIZE - 1) #define ARM_DRAM1_BASE ULL(0x80000000) #define ARM_DRAM1_SIZE ULL(0x80000000) #define ARM_DRAM1_END (ARM_DRAM1_BASE + \ ARM_DRAM1_SIZE - 1) #define ARM_DRAM2_BASE PLAT_ARM_DRAM2_BASE #define ARM_DRAM2_SIZE PLAT_ARM_DRAM2_SIZE #define ARM_DRAM2_END (ARM_DRAM2_BASE + \ ARM_DRAM2_SIZE - 1) #define ARM_IRQ_SEC_PHY_TIMER 29 #define ARM_IRQ_SEC_SGI_0 8 #define ARM_IRQ_SEC_SGI_1 9 #define ARM_IRQ_SEC_SGI_2 10 #define ARM_IRQ_SEC_SGI_3 11 #define ARM_IRQ_SEC_SGI_4 12 #define ARM_IRQ_SEC_SGI_5 13 #define ARM_IRQ_SEC_SGI_6 14 #define ARM_IRQ_SEC_SGI_7 15 /* * Define a list of Group 1 Secure and Group 0 interrupt properties as per GICv3 * terminology. On a GICv2 system or mode, the lists will be merged and treated * as Group 0 interrupts. */ #define ARM_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE) #define ARM_G0_IRQ_PROPS(grp) \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, PLAT_SDEI_NORMAL_PRI, (grp), \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE) #define ARM_MAP_SHARED_RAM MAP_REGION_FLAT( \ ARM_SHARED_RAM_BASE, \ ARM_SHARED_RAM_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define ARM_MAP_NS_DRAM1 MAP_REGION_FLAT( \ ARM_NS_DRAM1_BASE, \ ARM_NS_DRAM1_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define ARM_MAP_DRAM2 MAP_REGION_FLAT( \ ARM_DRAM2_BASE, \ ARM_DRAM2_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define ARM_MAP_TSP_SEC_MEM MAP_REGION_FLAT( \ TSP_SEC_MEM_BASE, \ TSP_SEC_MEM_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #if ARM_BL31_IN_DRAM #define ARM_MAP_BL31_SEC_DRAM MAP_REGION_FLAT( \ BL31_BASE, \ PLAT_ARM_MAX_BL31_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #endif #define ARM_MAP_EL3_TZC_DRAM MAP_REGION_FLAT( \ ARM_EL3_TZC_DRAM1_BASE, \ ARM_EL3_TZC_DRAM1_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) /* * Mapping for the BL1 RW region. This mapping is needed by BL2 in order to * share the Mbed TLS heap. Since the heap is allocated inside BL1, it resides * in the BL1 RW region. Hence, BL2 needs access to the BL1 RW region in order * to be able to access the heap. */ #define ARM_MAP_BL1_RW MAP_REGION_FLAT( \ BL1_RW_BASE, \ BL1_RW_LIMIT - BL1_RW_BASE, \ MT_MEMORY | MT_RW | MT_SECURE) /* * If SEPARATE_CODE_AND_RODATA=1 we define a region for each section * otherwise one region is defined containing both. */ #if SEPARATE_CODE_AND_RODATA #define ARM_MAP_BL_RO MAP_REGION_FLAT( \ BL_CODE_BASE, \ BL_CODE_END - BL_CODE_BASE, \ MT_CODE | MT_SECURE), \ MAP_REGION_FLAT( \ BL_RO_DATA_BASE, \ BL_RO_DATA_END \ - BL_RO_DATA_BASE, \ MT_RO_DATA | MT_SECURE) #else #define ARM_MAP_BL_RO MAP_REGION_FLAT( \ BL_CODE_BASE, \ BL_CODE_END - BL_CODE_BASE, \ MT_CODE | MT_SECURE) #endif #if USE_COHERENT_MEM #define ARM_MAP_BL_COHERENT_RAM MAP_REGION_FLAT( \ BL_COHERENT_RAM_BASE, \ BL_COHERENT_RAM_END \ - BL_COHERENT_RAM_BASE, \ MT_DEVICE | MT_RW | MT_SECURE) #endif #if USE_ROMLIB #define ARM_MAP_ROMLIB_CODE MAP_REGION_FLAT( \ ROMLIB_RO_BASE, \ ROMLIB_RO_LIMIT - ROMLIB_RO_BASE,\ MT_CODE | MT_SECURE) #define ARM_MAP_ROMLIB_DATA MAP_REGION_FLAT( \ ROMLIB_RW_BASE, \ ROMLIB_RW_END - ROMLIB_RW_BASE,\ MT_MEMORY | MT_RW | MT_SECURE) #endif /* * Map mem_protect flash region with read and write permissions */ #define ARM_V2M_MAP_MEM_PROTECT MAP_REGION_FLAT(PLAT_ARM_MEM_PROT_ADDR, \ V2M_FLASH_BLOCK_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) /* * The max number of regions like RO(code), coherent and data required by * different BL stages which need to be mapped in the MMU. */ #define ARM_BL_REGIONS 5 #define MAX_MMAP_REGIONS (PLAT_ARM_MMAP_ENTRIES + \ ARM_BL_REGIONS) /* Memory mapped Generic timer interfaces */ #define ARM_SYS_CNTCTL_BASE UL(0x2a430000) #define ARM_SYS_CNTREAD_BASE UL(0x2a800000) #define ARM_SYS_TIMCTL_BASE UL(0x2a810000) #define ARM_SYS_CNT_BASE_S UL(0x2a820000) #define ARM_SYS_CNT_BASE_NS UL(0x2a830000) #define ARM_CONSOLE_BAUDRATE 115200 /* Trusted Watchdog constants */ #define ARM_SP805_TWDG_BASE UL(0x2a490000) #define ARM_SP805_TWDG_CLK_HZ 32768 /* The TBBR document specifies a watchdog timeout of 256 seconds. SP805 * asserts reset after two consecutive countdowns (2 x 128 = 256 sec) */ #define ARM_TWDG_TIMEOUT_SEC 128 #define ARM_TWDG_LOAD_VAL (ARM_SP805_TWDG_CLK_HZ * \ ARM_TWDG_TIMEOUT_SEC) /****************************************************************************** * Required platform porting definitions common to all ARM standard platforms *****************************************************************************/ /* * This macro defines the deepest retention state possible. A higher state * id will represent an invalid or a power down state. */ #define PLAT_MAX_RET_STATE ARM_LOCAL_STATE_RET /* * This macro defines the deepest power down states possible. Any state ID * higher than this is invalid. */ #define PLAT_MAX_OFF_STATE ARM_LOCAL_STATE_OFF /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. */ #define CACHE_WRITEBACK_GRANULE (U(1) << ARM_CACHE_WRITEBACK_SHIFT) /* * To enable TB_FW_CONFIG to be loaded by BL1, define the corresponding base * and limit. Leave enough space of BL2 meminfo. */ #define ARM_TB_FW_CONFIG_BASE (ARM_BL_RAM_BASE + sizeof(meminfo_t)) #define ARM_TB_FW_CONFIG_LIMIT (ARM_BL_RAM_BASE + (PAGE_SIZE / 2U)) /* * Boot parameters passed from BL2 to BL31/BL32 are stored here */ #define ARM_BL2_MEM_DESC_BASE ARM_TB_FW_CONFIG_LIMIT #define ARM_BL2_MEM_DESC_LIMIT (ARM_BL2_MEM_DESC_BASE + \ (PAGE_SIZE / 2U)) /* * Define limit of firmware configuration memory: * ARM_TB_FW_CONFIG + ARM_BL2_MEM_DESC memory */ #define ARM_FW_CONFIG_LIMIT (ARM_BL_RAM_BASE + PAGE_SIZE) /******************************************************************************* * BL1 specific defines. * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of * addresses. ******************************************************************************/ #define BL1_RO_BASE PLAT_ARM_TRUSTED_ROM_BASE #define BL1_RO_LIMIT (PLAT_ARM_TRUSTED_ROM_BASE \ + (PLAT_ARM_TRUSTED_ROM_SIZE - \ PLAT_ARM_MAX_ROMLIB_RO_SIZE)) /* * Put BL1 RW at the top of the Trusted SRAM. */ #define BL1_RW_BASE (ARM_BL_RAM_BASE + \ ARM_BL_RAM_SIZE - \ (PLAT_ARM_MAX_BL1_RW_SIZE +\ PLAT_ARM_MAX_ROMLIB_RW_SIZE)) #define BL1_RW_LIMIT (ARM_BL_RAM_BASE + \ (ARM_BL_RAM_SIZE - PLAT_ARM_MAX_ROMLIB_RW_SIZE)) #define ROMLIB_RO_BASE BL1_RO_LIMIT #define ROMLIB_RO_LIMIT (PLAT_ARM_TRUSTED_ROM_BASE + PLAT_ARM_TRUSTED_ROM_SIZE) #define ROMLIB_RW_BASE (BL1_RW_BASE + PLAT_ARM_MAX_BL1_RW_SIZE) #define ROMLIB_RW_END (ROMLIB_RW_BASE + PLAT_ARM_MAX_ROMLIB_RW_SIZE) /******************************************************************************* * BL2 specific defines. ******************************************************************************/ #if BL2_AT_EL3 /* Put BL2 towards the middle of the Trusted SRAM */ #define BL2_BASE (ARM_TRUSTED_SRAM_BASE + \ (PLAT_ARM_TRUSTED_SRAM_SIZE >> 1) + 0x2000) #define BL2_LIMIT (ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE) #else /* * Put BL2 just below BL1. */ #define BL2_BASE (BL1_RW_BASE - PLAT_ARM_MAX_BL2_SIZE) #define BL2_LIMIT BL1_RW_BASE #endif /******************************************************************************* * BL31 specific defines. ******************************************************************************/ #if ARM_BL31_IN_DRAM /* * Put BL31 at the bottom of TZC secured DRAM */ #define BL31_BASE ARM_AP_TZC_DRAM1_BASE #define BL31_LIMIT (ARM_AP_TZC_DRAM1_BASE + \ PLAT_ARM_MAX_BL31_SIZE) #elif (RESET_TO_BL31) # if ENABLE_PIE /* * Since this is PIE, we can define BL31_BASE to 0x0 since this macro is solely * used for building BL31 and not used for loading BL31. */ # define BL31_BASE 0x0 # define BL31_LIMIT PLAT_ARM_MAX_BL31_SIZE # else /* Put BL31_BASE in the middle of the Trusted SRAM.*/ # define BL31_BASE (ARM_TRUSTED_SRAM_BASE + \ (PLAT_ARM_TRUSTED_SRAM_SIZE >> 1)) # define BL31_LIMIT (ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE) # endif /* ENABLE_PIE */ #else /* Put BL31 below BL2 in the Trusted SRAM.*/ #define BL31_BASE ((ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)\ - PLAT_ARM_MAX_BL31_SIZE) #define BL31_PROGBITS_LIMIT BL2_BASE /* * For BL2_AT_EL3 make sure the BL31 can grow up until BL2_BASE. This is * because in the BL2_AT_EL3 configuration, BL2 is always resident. */ #if BL2_AT_EL3 #define BL31_LIMIT BL2_BASE #else #define BL31_LIMIT (ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE) #endif #endif #if !defined(__aarch64__) || JUNO_AARCH32_EL3_RUNTIME /******************************************************************************* * BL32 specific defines for EL3 runtime in AArch32 mode ******************************************************************************/ # if RESET_TO_SP_MIN && !JUNO_AARCH32_EL3_RUNTIME /* * SP_MIN is the only BL image in SRAM. Allocate the whole of SRAM (excluding * the page reserved for fw_configs) to BL32 */ # define BL32_BASE ARM_FW_CONFIG_LIMIT # define BL32_LIMIT (ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE) # else /* Put BL32 below BL2 in the Trusted SRAM.*/ # define BL32_BASE ((ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)\ - PLAT_ARM_MAX_BL32_SIZE) # define BL32_PROGBITS_LIMIT BL2_BASE # define BL32_LIMIT (ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE) # endif /* RESET_TO_SP_MIN && !JUNO_AARCH32_EL3_RUNTIME */ #else /******************************************************************************* * BL32 specific defines for EL3 runtime in AArch64 mode ******************************************************************************/ /* * On ARM standard platforms, the TSP can execute from Trusted SRAM, * Trusted DRAM (if available) or the DRAM region secured by the TrustZone * controller. */ # if ENABLE_SPM # define TSP_SEC_MEM_BASE (ARM_AP_TZC_DRAM1_BASE + ULL(0x200000)) # define TSP_SEC_MEM_SIZE (ARM_AP_TZC_DRAM1_SIZE - ULL(0x200000)) # define BL32_BASE (ARM_AP_TZC_DRAM1_BASE + ULL(0x200000)) # define BL32_LIMIT (ARM_AP_TZC_DRAM1_BASE + \ ARM_AP_TZC_DRAM1_SIZE) # elif ARM_BL31_IN_DRAM # define TSP_SEC_MEM_BASE (ARM_AP_TZC_DRAM1_BASE + \ PLAT_ARM_MAX_BL31_SIZE) # define TSP_SEC_MEM_SIZE (ARM_AP_TZC_DRAM1_SIZE - \ PLAT_ARM_MAX_BL31_SIZE) # define BL32_BASE (ARM_AP_TZC_DRAM1_BASE + \ PLAT_ARM_MAX_BL31_SIZE) # define BL32_LIMIT (ARM_AP_TZC_DRAM1_BASE + \ ARM_AP_TZC_DRAM1_SIZE) # elif ARM_TSP_RAM_LOCATION_ID == ARM_TRUSTED_SRAM_ID # define TSP_SEC_MEM_BASE ARM_BL_RAM_BASE # define TSP_SEC_MEM_SIZE ARM_BL_RAM_SIZE # define TSP_PROGBITS_LIMIT BL31_BASE # define BL32_BASE ARM_FW_CONFIG_LIMIT # define BL32_LIMIT BL31_BASE # elif ARM_TSP_RAM_LOCATION_ID == ARM_TRUSTED_DRAM_ID # define TSP_SEC_MEM_BASE PLAT_ARM_TRUSTED_DRAM_BASE # define TSP_SEC_MEM_SIZE PLAT_ARM_TRUSTED_DRAM_SIZE # define BL32_BASE PLAT_ARM_TRUSTED_DRAM_BASE # define BL32_LIMIT (PLAT_ARM_TRUSTED_DRAM_BASE \ + (UL(1) << 21)) # elif ARM_TSP_RAM_LOCATION_ID == ARM_DRAM_ID # define TSP_SEC_MEM_BASE ARM_AP_TZC_DRAM1_BASE # define TSP_SEC_MEM_SIZE ARM_AP_TZC_DRAM1_SIZE # define BL32_BASE ARM_AP_TZC_DRAM1_BASE # define BL32_LIMIT (ARM_AP_TZC_DRAM1_BASE + \ ARM_AP_TZC_DRAM1_SIZE) # else # error "Unsupported ARM_TSP_RAM_LOCATION_ID value" # endif #endif /* !__aarch64__ || JUNO_AARCH32_EL3_RUNTIME */ /* * BL32 is mandatory in AArch32. In AArch64, undefine BL32_BASE if there is no * SPD and no SPM, as they are the only ones that can be used as BL32. */ #if defined(__aarch64__) && !JUNO_AARCH32_EL3_RUNTIME # if defined(SPD_none) && !ENABLE_SPM # undef BL32_BASE # endif /* defined(SPD_none) && !ENABLE_SPM */ #endif /* defined(__aarch64__) && !JUNO_AARCH32_EL3_RUNTIME */ /******************************************************************************* * FWU Images: NS_BL1U, BL2U & NS_BL2U defines. ******************************************************************************/ #define BL2U_BASE BL2_BASE #define BL2U_LIMIT BL2_LIMIT #define NS_BL2U_BASE ARM_NS_DRAM1_BASE #define NS_BL1U_BASE (PLAT_ARM_NVM_BASE + UL(0x03EB8000)) /* * ID of the secure physical generic timer interrupt used by the TSP. */ #define TSP_IRQ_SEC_PHY_TIMER ARM_IRQ_SEC_PHY_TIMER /* * One cache line needed for bakery locks on ARM platforms */ #define PLAT_PERCPU_BAKERY_LOCK_SIZE (1 * CACHE_WRITEBACK_GRANULE) /* Priority levels for ARM platforms */ #define PLAT_RAS_PRI 0x10 #define PLAT_SDEI_CRITICAL_PRI 0x60 #define PLAT_SDEI_NORMAL_PRI 0x70 /* ARM platforms use 3 upper bits of secure interrupt priority */ #define ARM_PRI_BITS 3 /* SGI used for SDEI signalling */ #define ARM_SDEI_SGI ARM_IRQ_SEC_SGI_0 /* ARM SDEI dynamic private event numbers */ #define ARM_SDEI_DP_EVENT_0 1000 #define ARM_SDEI_DP_EVENT_1 1001 #define ARM_SDEI_DP_EVENT_2 1002 /* ARM SDEI dynamic shared event numbers */ #define ARM_SDEI_DS_EVENT_0 2000 #define ARM_SDEI_DS_EVENT_1 2001 #define ARM_SDEI_DS_EVENT_2 2002 #define ARM_SDEI_PRIVATE_EVENTS \ SDEI_DEFINE_EVENT_0(ARM_SDEI_SGI), \ SDEI_PRIVATE_EVENT(ARM_SDEI_DP_EVENT_0, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), \ SDEI_PRIVATE_EVENT(ARM_SDEI_DP_EVENT_1, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), \ SDEI_PRIVATE_EVENT(ARM_SDEI_DP_EVENT_2, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC) #define ARM_SDEI_SHARED_EVENTS \ SDEI_SHARED_EVENT(ARM_SDEI_DS_EVENT_0, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), \ SDEI_SHARED_EVENT(ARM_SDEI_DS_EVENT_1, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC), \ SDEI_SHARED_EVENT(ARM_SDEI_DS_EVENT_2, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC) #endif /* ARM_DEF_H */ trusted-firmware-a-2.2/include/plat/arm/common/arm_dyn_cfg_helpers.h000066400000000000000000000013051355360272700257050ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_DYN_CFG_HELPERS_H #define ARM_DYN_CFG_HELPERS_H #include #include /* Function declarations */ int arm_dyn_get_config_load_info(void *dtb, int node, unsigned int config_id, uint64_t *config_addr, uint32_t *config_size); int arm_dyn_tb_fw_cfg_init(void *dtb, int *node); int arm_dyn_get_disable_auth(void *dtb, int node, uint32_t *disable_auth); int arm_get_dtb_mbedtls_heap_info(void *dtb, void **heap_addr, size_t *heap_size); int arm_set_dtb_mbedtls_heap_info(void *dtb, void *heap_addr, size_t heap_size); #endif /* ARM_DYN_CFG_HELPERS_H */ trusted-firmware-a-2.2/include/plat/arm/common/arm_reclaim_init.ld.S000066400000000000000000000017751355360272700255750ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_RECLAIM_INIT_LD_S #define ARM_RECLAIM_INIT_LD_S SECTIONS { .init __STACKS_START__ : { . = . + PLATFORM_STACK_SIZE; . = ALIGN(PAGE_SIZE); __INIT_CODE_START__ = .; /* * Exclude PSCI initialization functions to ensure the init section * does not become larger than the overlaid stack region */ *(EXCLUDE_FILE (*psci_setup.o).text.init*) __INIT_CODE_UNALIGNED__ = .; . = ALIGN(PAGE_SIZE); __INIT_CODE_END__ = .; } >RAM #ifdef BL31_PROGBITS_LIMIT ASSERT(__INIT_CODE_END__ <= BL31_PROGBITS_LIMIT, "BL31 init has exceeded progbits limit.") #endif #if RECLAIM_INIT_CODE ASSERT(__INIT_CODE_END__ <= __STACKS_END__, "Init code ends past the end of the stacks") #endif } #endif /* ARM_RECLAIM_INIT_LD_S */ trusted-firmware-a-2.2/include/plat/arm/common/arm_sip_svc.h000066400000000000000000000012541355360272700242230ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_SIP_SVC_H #define ARM_SIP_SVC_H #include /* SMC function IDs for SiP Service queries */ #define ARM_SIP_SVC_CALL_COUNT U(0x8200ff00) #define ARM_SIP_SVC_UID U(0x8200ff01) /* U(0x8200ff02) is reserved */ #define ARM_SIP_SVC_VERSION U(0x8200ff03) /* Function ID for requesting state switch of lower EL */ #define ARM_SIP_SVC_EXE_STATE_SWITCH U(0x82000020) /* ARM SiP Service Calls version numbers */ #define ARM_SIP_SVC_VERSION_MAJOR U(0x0) #define ARM_SIP_SVC_VERSION_MINOR U(0x2) #endif /* ARM_SIP_SVC_H */ trusted-firmware-a-2.2/include/plat/arm/common/arm_spm_def.h000066400000000000000000000111251355360272700241700ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_SPM_DEF_H #define ARM_SPM_DEF_H #include #include /* * Reserve 4 MiB for binaries of Secure Partitions and Resource Description * blobs. */ #define PLAT_SP_PACKAGE_BASE BL32_BASE #define PLAT_SP_PACKAGE_SIZE ULL(0x400000) #define PLAT_MAP_SP_PACKAGE_MEM_RO MAP_REGION_FLAT( \ PLAT_SP_PACKAGE_BASE, \ PLAT_SP_PACKAGE_SIZE, \ MT_MEMORY | MT_RO | MT_SECURE) #define PLAT_MAP_SP_PACKAGE_MEM_RW MAP_REGION_FLAT( \ PLAT_SP_PACKAGE_BASE, \ PLAT_SP_PACKAGE_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) /* * The rest of the memory reserved for BL32 is free for SPM to use it as memory * pool to allocate memory regions requested in the resource description. */ #define PLAT_SPM_HEAP_BASE (PLAT_SP_PACKAGE_BASE + PLAT_SP_PACKAGE_SIZE) #define PLAT_SPM_HEAP_SIZE (BL32_LIMIT - BL32_BASE - PLAT_SP_PACKAGE_SIZE) #if SPM_MM /* * If BL31 is placed in DRAM, place the Secure Partition in DRAM right after the * region used by BL31. If BL31 it is placed in SRAM, put the Secure Partition * at the base of DRAM. */ #define ARM_SP_IMAGE_BASE BL32_BASE #define ARM_SP_IMAGE_LIMIT BL32_LIMIT /* The maximum size of the S-EL0 payload can be 3MB */ #define ARM_SP_IMAGE_SIZE ULL(0x300000) #ifdef IMAGE_BL2 /* SPM Payload memory. Mapped as RW in BL2. */ #define ARM_SP_IMAGE_MMAP MAP_REGION_FLAT( \ ARM_SP_IMAGE_BASE, \ ARM_SP_IMAGE_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #endif #ifdef IMAGE_BL31 /* SPM Payload memory. Mapped as code in S-EL1 */ #define ARM_SP_IMAGE_MMAP MAP_REGION2( \ ARM_SP_IMAGE_BASE, \ ARM_SP_IMAGE_BASE, \ ARM_SP_IMAGE_SIZE, \ MT_CODE | MT_SECURE | MT_USER, \ PAGE_SIZE) #endif /* * Memory shared between EL3 and S-EL0. It is used by EL3 to push data into * S-EL0, so it is mapped with RW permission from EL3 and with RO permission * from S-EL0. Placed after SPM Payload memory. */ #define PLAT_SPM_BUF_BASE (ARM_SP_IMAGE_BASE + ARM_SP_IMAGE_SIZE) #define PLAT_SPM_BUF_SIZE ULL(0x100000) #define ARM_SPM_BUF_EL3_MMAP MAP_REGION_FLAT( \ PLAT_SPM_BUF_BASE, \ PLAT_SPM_BUF_SIZE, \ MT_RW_DATA | MT_SECURE) #define ARM_SPM_BUF_EL0_MMAP MAP_REGION2( \ PLAT_SPM_BUF_BASE, \ PLAT_SPM_BUF_BASE, \ PLAT_SPM_BUF_SIZE, \ MT_RO_DATA | MT_SECURE | MT_USER,\ PAGE_SIZE) /* * Memory shared between Normal world and S-EL0 for passing data during service * requests. Mapped as RW and NS. Placed after the shared memory between EL3 and * S-EL0. */ #define PLAT_SP_IMAGE_NS_BUF_BASE (PLAT_SPM_BUF_BASE + PLAT_SPM_BUF_SIZE) #define PLAT_SP_IMAGE_NS_BUF_SIZE ULL(0x10000) #define ARM_SP_IMAGE_NS_BUF_MMAP MAP_REGION2( \ PLAT_SP_IMAGE_NS_BUF_BASE, \ PLAT_SP_IMAGE_NS_BUF_BASE, \ PLAT_SP_IMAGE_NS_BUF_SIZE, \ MT_RW_DATA | MT_NS | MT_USER, \ PAGE_SIZE) /* * RW memory, which uses the remaining Trusted DRAM. Placed after the memory * shared between Secure and Non-secure worlds, or after the platform specific * buffers, if defined. First there is the stack memory for all CPUs and then * there is the common heap memory. Both are mapped with RW permissions. */ #define PLAT_SP_IMAGE_STACK_BASE PLAT_ARM_SP_IMAGE_STACK_BASE #define PLAT_SP_IMAGE_STACK_PCPU_SIZE ULL(0x2000) #define ARM_SP_IMAGE_STACK_TOTAL_SIZE (PLATFORM_CORE_COUNT * \ PLAT_SP_IMAGE_STACK_PCPU_SIZE) #define ARM_SP_IMAGE_HEAP_BASE (PLAT_SP_IMAGE_STACK_BASE + \ ARM_SP_IMAGE_STACK_TOTAL_SIZE) #define ARM_SP_IMAGE_HEAP_SIZE (ARM_SP_IMAGE_LIMIT - ARM_SP_IMAGE_HEAP_BASE) #define ARM_SP_IMAGE_RW_MMAP MAP_REGION2( \ PLAT_SP_IMAGE_STACK_BASE, \ PLAT_SP_IMAGE_STACK_BASE, \ (ARM_SP_IMAGE_LIMIT - \ PLAT_SP_IMAGE_STACK_BASE), \ MT_RW_DATA | MT_SECURE | MT_USER,\ PAGE_SIZE) /* Total number of memory regions with distinct properties */ #define ARM_SP_IMAGE_NUM_MEM_REGIONS 6 #endif /* SPM_MM */ /* Cookies passed to the Secure Partition at boot. Not used by ARM platforms. */ #define PLAT_SPM_COOKIE_0 ULL(0) #define PLAT_SPM_COOKIE_1 ULL(0) /* * Max number of elements supported by SPM in this platform. The defines below * are used to allocate memory at compile time for different arrays in SPM. */ #define PLAT_SPM_MAX_PARTITIONS U(2) #define PLAT_SPM_MEM_REGIONS_MAX U(80) #define PLAT_SPM_NOTIFICATIONS_MAX U(30) #define PLAT_SPM_SERVICES_MAX U(30) #define PLAT_SPCI_HANDLES_MAX_NUM U(20) #define PLAT_SPM_RESPONSES_MAX U(30) #endif /* ARM_SPM_DEF_H */ trusted-firmware-a-2.2/include/plat/arm/common/arm_tzc_dram.ld.S000066400000000000000000000012771355360272700247360ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_TZC_DRAM_LD_S #define ARM_TZC_DRAM_LD_S #include MEMORY { EL3_SEC_DRAM (rw): ORIGIN = ARM_EL3_TZC_DRAM1_BASE, LENGTH = ARM_EL3_TZC_DRAM1_SIZE } SECTIONS { . = ARM_EL3_TZC_DRAM1_BASE; ASSERT(. == ALIGN(PAGE_SIZE), "ARM_EL3_TZC_DRAM_BASE address is not aligned on a page boundary.") el3_tzc_dram (NOLOAD) : ALIGN(PAGE_SIZE) { __EL3_SEC_DRAM_START__ = .; *(arm_el3_tzc_dram) __EL3_SEC_DRAM_UNALIGNED_END__ = .; . = ALIGN(PAGE_SIZE); __EL3_SEC_DRAM_END__ = .; } >EL3_SEC_DRAM } #endif /* ARM_TZC_DRAM_LD_S */ trusted-firmware-a-2.2/include/plat/arm/common/plat_arm.h000066400000000000000000000235671355360272700235300ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_ARM_H #define PLAT_ARM_H #include #include #include #include #include #include #include #include /******************************************************************************* * Forward declarations ******************************************************************************/ struct meminfo; struct image_info; struct bl_params; typedef struct arm_tzc_regions_info { unsigned long long base; unsigned long long end; unsigned int sec_attr; unsigned int nsaid_permissions; } arm_tzc_regions_info_t; /******************************************************************************* * Default mapping definition of the TrustZone Controller for ARM standard * platforms. * Configure: * - Region 0 with no access; * - Region 1 with secure access only; * - the remaining DRAM regions access from the given Non-Secure masters. ******************************************************************************/ #if ENABLE_SPM && SPM_MM #define ARM_TZC_REGIONS_DEF \ {ARM_AP_TZC_DRAM1_BASE, ARM_EL3_TZC_DRAM1_END, \ TZC_REGION_S_RDWR, 0}, \ {ARM_NS_DRAM1_BASE, ARM_NS_DRAM1_END, ARM_TZC_NS_DRAM_S_ACCESS, \ PLAT_ARM_TZC_NS_DEV_ACCESS}, \ {ARM_DRAM2_BASE, ARM_DRAM2_END, ARM_TZC_NS_DRAM_S_ACCESS, \ PLAT_ARM_TZC_NS_DEV_ACCESS}, \ {PLAT_SP_IMAGE_NS_BUF_BASE, (PLAT_SP_IMAGE_NS_BUF_BASE + \ PLAT_SP_IMAGE_NS_BUF_SIZE) - 1, TZC_REGION_S_NONE, \ PLAT_ARM_TZC_NS_DEV_ACCESS} #else #define ARM_TZC_REGIONS_DEF \ {ARM_AP_TZC_DRAM1_BASE, ARM_EL3_TZC_DRAM1_END, \ TZC_REGION_S_RDWR, 0}, \ {ARM_NS_DRAM1_BASE, ARM_NS_DRAM1_END, ARM_TZC_NS_DRAM_S_ACCESS, \ PLAT_ARM_TZC_NS_DEV_ACCESS}, \ {ARM_DRAM2_BASE, ARM_DRAM2_END, ARM_TZC_NS_DRAM_S_ACCESS, \ PLAT_ARM_TZC_NS_DEV_ACCESS} #endif #define ARM_CASSERT_MMAP \ CASSERT((ARRAY_SIZE(plat_arm_mmap) - 1) <= PLAT_ARM_MMAP_ENTRIES, \ assert_plat_arm_mmap_mismatch); \ CASSERT((PLAT_ARM_MMAP_ENTRIES + ARM_BL_REGIONS) \ <= MAX_MMAP_REGIONS, \ assert_max_mmap_regions); void arm_setup_romlib(void); #if defined(IMAGE_BL31) || (!defined(__aarch64__) && defined(IMAGE_BL32)) /* * Use this macro to instantiate lock before it is used in below * arm_lock_xxx() macros */ #define ARM_INSTANTIATE_LOCK static DEFINE_BAKERY_LOCK(arm_lock) #define ARM_LOCK_GET_INSTANCE (&arm_lock) #if !HW_ASSISTED_COHERENCY #define ARM_SCMI_INSTANTIATE_LOCK DEFINE_BAKERY_LOCK(arm_scmi_lock) #else #define ARM_SCMI_INSTANTIATE_LOCK spinlock_t arm_scmi_lock #endif #define ARM_SCMI_LOCK_GET_INSTANCE (&arm_scmi_lock) /* * These are wrapper macros to the Coherent Memory Bakery Lock API. */ #define arm_lock_init() bakery_lock_init(&arm_lock) #define arm_lock_get() bakery_lock_get(&arm_lock) #define arm_lock_release() bakery_lock_release(&arm_lock) #else /* * Empty macros for all other BL stages other than BL31 and BL32 */ #define ARM_INSTANTIATE_LOCK static int arm_lock __unused #define ARM_LOCK_GET_INSTANCE 0 #define arm_lock_init() #define arm_lock_get() #define arm_lock_release() #endif /* defined(IMAGE_BL31) || (!defined(__aarch64__) && defined(IMAGE_BL32)) */ #if ARM_RECOM_STATE_ID_ENC /* * Macros used to parse state information from State-ID if it is using the * recommended encoding for State-ID. */ #define ARM_LOCAL_PSTATE_WIDTH 4 #define ARM_LOCAL_PSTATE_MASK ((1 << ARM_LOCAL_PSTATE_WIDTH) - 1) /* Macros to construct the composite power state */ /* Make composite power state parameter till power level 0 */ #if PSCI_EXTENDED_STATE_ID #define arm_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ (((lvl0_state) << PSTATE_ID_SHIFT) | ((type) << PSTATE_TYPE_SHIFT)) #else #define arm_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ (((lvl0_state) << PSTATE_ID_SHIFT) | \ ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \ ((type) << PSTATE_TYPE_SHIFT)) #endif /* __PSCI_EXTENDED_STATE_ID__ */ /* Make composite power state parameter till power level 1 */ #define arm_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \ (((lvl1_state) << ARM_LOCAL_PSTATE_WIDTH) | \ arm_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type)) /* Make composite power state parameter till power level 2 */ #define arm_make_pwrstate_lvl2(lvl2_state, lvl1_state, lvl0_state, pwr_lvl, type) \ (((lvl2_state) << (ARM_LOCAL_PSTATE_WIDTH * 2)) | \ arm_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type)) #endif /* __ARM_RECOM_STATE_ID_ENC__ */ /* ARM State switch error codes */ #define STATE_SW_E_PARAM (-2) #define STATE_SW_E_DENIED (-3) /* IO storage utility functions */ void arm_io_setup(void); /* Security utility functions */ void arm_tzc400_setup(const arm_tzc_regions_info_t *tzc_regions); struct tzc_dmc500_driver_data; void arm_tzc_dmc500_setup(struct tzc_dmc500_driver_data *plat_driver_data, const arm_tzc_regions_info_t *tzc_regions); /* Console utility functions */ void arm_console_boot_init(void); void arm_console_boot_end(void); void arm_console_runtime_init(void); void arm_console_runtime_end(void); /* Systimer utility function */ void arm_configure_sys_timer(void); /* PM utility functions */ int arm_validate_power_state(unsigned int power_state, psci_power_state_t *req_state); int arm_validate_psci_entrypoint(uintptr_t entrypoint); int arm_validate_ns_entrypoint(uintptr_t entrypoint); void arm_system_pwr_domain_save(void); void arm_system_pwr_domain_resume(void); int arm_psci_read_mem_protect(int *enabled); int arm_nor_psci_write_mem_protect(int val); void arm_nor_psci_do_static_mem_protect(void); void arm_nor_psci_do_dyn_mem_protect(void); int arm_psci_mem_protect_chk(uintptr_t base, u_register_t length); /* Topology utility function */ int arm_check_mpidr(u_register_t mpidr); /* BL1 utility functions */ void arm_bl1_early_platform_setup(void); void arm_bl1_platform_setup(void); void arm_bl1_plat_arch_setup(void); /* BL2 utility functions */ void arm_bl2_early_platform_setup(uintptr_t tb_fw_config, struct meminfo *mem_layout); void arm_bl2_platform_setup(void); void arm_bl2_plat_arch_setup(void); uint32_t arm_get_spsr_for_bl32_entry(void); uint32_t arm_get_spsr_for_bl33_entry(void); int arm_bl2_plat_handle_post_image_load(unsigned int image_id); int arm_bl2_handle_post_image_load(unsigned int image_id); struct bl_params *arm_get_next_bl_params(void); /* BL2 at EL3 functions */ void arm_bl2_el3_early_platform_setup(void); void arm_bl2_el3_plat_arch_setup(void); /* BL2U utility functions */ void arm_bl2u_early_platform_setup(struct meminfo *mem_layout, void *plat_info); void arm_bl2u_platform_setup(void); void arm_bl2u_plat_arch_setup(void); /* BL31 utility functions */ void arm_bl31_early_platform_setup(void *from_bl2, uintptr_t soc_fw_config, uintptr_t hw_config, void *plat_params_from_bl2); void arm_bl31_platform_setup(void); void arm_bl31_plat_runtime_setup(void); void arm_bl31_plat_arch_setup(void); /* TSP utility functions */ void arm_tsp_early_platform_setup(void); /* SP_MIN utility functions */ void arm_sp_min_early_platform_setup(void *from_bl2, uintptr_t tos_fw_config, uintptr_t hw_config, void *plat_params_from_bl2); void arm_sp_min_plat_runtime_setup(void); /* FIP TOC validity check */ int arm_io_is_toc_valid(void); /* Utility functions for Dynamic Config */ void arm_load_tb_fw_config(void); void arm_bl2_set_tb_cfg_addr(void *dtb); void arm_bl2_dyn_cfg_init(void); void arm_bl1_set_mbedtls_heap(void); int arm_get_mbedtls_heap(void **heap_addr, size_t *heap_size); /* * Free the memory storing initialization code only used during an images boot * time so it can be reclaimed for runtime data */ void arm_free_init_memory(void); /* * Mandatory functions required in ARM standard platforms */ unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr); void plat_arm_gic_driver_init(void); void plat_arm_gic_init(void); void plat_arm_gic_cpuif_enable(void); void plat_arm_gic_cpuif_disable(void); void plat_arm_gic_redistif_on(void); void plat_arm_gic_redistif_off(void); void plat_arm_gic_pcpu_init(void); void plat_arm_gic_save(void); void plat_arm_gic_resume(void); void plat_arm_security_setup(void); void plat_arm_pwrc_setup(void); void plat_arm_interconnect_init(void); void plat_arm_interconnect_enter_coherency(void); void plat_arm_interconnect_exit_coherency(void); void plat_arm_program_trusted_mailbox(uintptr_t address); int plat_arm_bl1_fwu_needed(void); __dead2 void plat_arm_error_handler(int err); #if ARM_PLAT_MT unsigned int plat_arm_get_cpu_pe_count(u_register_t mpidr); #endif /* * This function is called after loading SCP_BL2 image and it is used to perform * any platform-specific actions required to handle the SCP firmware. */ int plat_arm_bl2_handle_scp_bl2(struct image_info *scp_bl2_image_info); /* * Optional functions required in ARM standard platforms */ void plat_arm_io_setup(void); int plat_arm_get_alt_image_source( unsigned int image_id, uintptr_t *dev_handle, uintptr_t *image_spec); unsigned int plat_arm_calc_core_pos(u_register_t mpidr); const mmap_region_t *plat_arm_get_mmap(void); /* Allow platform to override psci_pm_ops during runtime */ const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops); /* Execution state switch in ARM platforms */ int arm_execution_state_switch(unsigned int smc_fid, uint32_t pc_hi, uint32_t pc_lo, uint32_t cookie_hi, uint32_t cookie_lo, void *handle); /* Optional functions for SP_MIN */ void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3); /* global variables */ extern plat_psci_ops_t plat_arm_psci_pm_ops; extern const mmap_region_t plat_arm_mmap[]; extern const unsigned int arm_pm_idle_states[]; /* secure watchdog */ void plat_arm_secure_wdt_start(void); void plat_arm_secure_wdt_stop(void); #endif /* PLAT_ARM_H */ trusted-firmware-a-2.2/include/plat/arm/css/000077500000000000000000000000001355360272700210435ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/arm/css/common/000077500000000000000000000000001355360272700223335ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/arm/css/common/aarch64/000077500000000000000000000000001355360272700235635ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/arm/css/common/aarch64/css_macros.S000066400000000000000000000012061355360272700260420ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CSS_MACROS_S #define CSS_MACROS_S #include #include /* --------------------------------------------- * The below required platform porting macro * prints out relevant GIC registers whenever an * unhandled exception is taken in BL31. * Clobbers: x0 - x10, x16, x17, sp * --------------------------------------------- */ .macro css_print_gic_regs mov_imm x16, PLAT_ARM_GICD_BASE mov_imm x17, PLAT_ARM_GICC_BASE arm_print_gic_regs .endm #endif /* CSS_MACROS_S */ trusted-firmware-a-2.2/include/plat/arm/css/common/css_def.h000066400000000000000000000143721355360272700241210ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CSS_DEF_H #define CSS_DEF_H #include #include #include /************************************************************************* * Definitions common to all ARM Compute SubSystems (CSS) *************************************************************************/ #define NSROM_BASE 0x1f000000 #define NSROM_SIZE 0x00001000 /* Following covers CSS Peripherals excluding NSROM and NSRAM */ #define CSS_DEVICE_BASE 0x20000000 #define CSS_DEVICE_SIZE 0x0e000000 /* System Security Control Registers */ #define SSC_REG_BASE 0x2a420000 #define SSC_GPRETN (SSC_REG_BASE + 0x030) /* System ID Registers Unit */ #define SID_REG_BASE 0x2a4a0000 #define SID_SYSTEM_ID_OFFSET 0x40 #define SID_SYSTEM_CFG_OFFSET 0x70 /* The slave_bootsecure controls access to GPU, DMC and CS. */ #define CSS_NIC400_SLAVE_BOOTSECURE 8 /* Interrupt handling constants */ #define CSS_IRQ_MHU 69 #define CSS_IRQ_GPU_SMMU_0 71 #define CSS_IRQ_TZC 80 #define CSS_IRQ_TZ_WDOG 86 #define CSS_IRQ_SEC_SYS_TIMER 91 /* MHU register offsets */ #define MHU_CPU_INTR_S_SET_OFFSET 0x308 /* * Define a list of Group 1 Secure interrupt properties as per GICv3 * terminology. On a GICv2 system or mode, the interrupts will be treated as * Group 0 interrupts. */ #define CSS_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(CSS_IRQ_MHU, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(CSS_IRQ_GPU_SMMU_0, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(CSS_IRQ_TZC, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(CSS_IRQ_TZ_WDOG, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(CSS_IRQ_SEC_SYS_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL) #if CSS_USE_SCMI_SDS_DRIVER /* Memory region for shared data storage */ #define PLAT_ARM_SDS_MEM_BASE ARM_SHARED_RAM_BASE #define PLAT_ARM_SDS_MEM_SIZE_MAX 0xDC0 /* 3520 bytes */ /* * The SCMI Channel is placed right after the SDS region */ #define CSS_SCMI_PAYLOAD_BASE (PLAT_ARM_SDS_MEM_BASE + PLAT_ARM_SDS_MEM_SIZE_MAX) #define CSS_SCMI_MHU_DB_REG_OFF MHU_CPU_INTR_S_SET_OFFSET /* Trusted mailbox base address common to all CSS */ /* If SDS is present, then mailbox is at top of SRAM */ #define PLAT_ARM_TRUSTED_MAILBOX_BASE (ARM_SHARED_RAM_BASE + ARM_SHARED_RAM_SIZE - 0x8) /* Number of retries for SCP_RAM_READY flag */ #define CSS_SCP_READY_10US_RETRIES 1000000 /* Effective timeout of 10000 ms */ #else /* * SCP <=> AP boot configuration * * The SCP/AP boot configuration is a 32-bit word located at a known offset from * the start of the Trusted SRAM. * * Note that the value stored at this address is only valid at boot time, before * the SCP_BL2 image is transferred to SCP. */ #define SCP_BOOT_CFG_ADDR PLAT_CSS_SCP_COM_SHARED_MEM_BASE /* Trusted mailbox base address common to all CSS */ /* If SDS is not present, then the mailbox is at the bottom of SRAM */ #define PLAT_ARM_TRUSTED_MAILBOX_BASE ARM_TRUSTED_SRAM_BASE #endif /* CSS_USE_SCMI_SDS_DRIVER */ #define CSS_MAP_DEVICE MAP_REGION_FLAT( \ CSS_DEVICE_BASE, \ CSS_DEVICE_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define CSS_MAP_NSRAM MAP_REGION_FLAT( \ NSRAM_BASE, \ NSRAM_SIZE, \ MT_DEVICE | MT_RW | MT_NS) #if defined(IMAGE_BL2U) #define CSS_MAP_SCP_BL2U MAP_REGION_FLAT( \ SCP_BL2U_BASE, \ SCP_BL2U_LIMIT \ - SCP_BL2U_BASE,\ MT_RW_DATA | MT_SECURE) #endif /* Platform ID address */ #define SSC_VERSION_OFFSET 0x040 #define SSC_VERSION_CONFIG_SHIFT 28 #define SSC_VERSION_MAJOR_REV_SHIFT 24 #define SSC_VERSION_MINOR_REV_SHIFT 20 #define SSC_VERSION_DESIGNER_ID_SHIFT 12 #define SSC_VERSION_PART_NUM_SHIFT 0x0 #define SSC_VERSION_CONFIG_MASK 0xf #define SSC_VERSION_MAJOR_REV_MASK 0xf #define SSC_VERSION_MINOR_REV_MASK 0xf #define SSC_VERSION_DESIGNER_ID_MASK 0xff #define SSC_VERSION_PART_NUM_MASK 0xfff #define SID_SYSTEM_ID_PART_NUM_MASK 0xfff /* SSC debug configuration registers */ #define SSC_DBGCFG_SET 0x14 #define SSC_DBGCFG_CLR 0x18 #define SPIDEN_INT_CLR_SHIFT 6 #define SPIDEN_SEL_SET_SHIFT 7 #ifndef __ASSEMBLER__ /* SSC_VERSION related accessors */ /* Returns the part number of the platform */ #define GET_SSC_VERSION_PART_NUM(val) \ (((val) >> SSC_VERSION_PART_NUM_SHIFT) & \ SSC_VERSION_PART_NUM_MASK) /* Returns the configuration number of the platform */ #define GET_SSC_VERSION_CONFIG(val) \ (((val) >> SSC_VERSION_CONFIG_SHIFT) & \ SSC_VERSION_CONFIG_MASK) #endif /* __ASSEMBLER__ */ /************************************************************************* * Required platform porting definitions common to all * ARM Compute SubSystems (CSS) ************************************************************************/ /* * The loading of SCP images(SCP_BL2 or SCP_BL2U) is done if there * respective base addresses are defined (i.e SCP_BL2_BASE, SCP_BL2U_BASE). * Hence, `CSS_LOAD_SCP_IMAGES` needs to be set to 1 if BL2 needs to load * an SCP_BL2/SCP_BL2U image. */ #if CSS_LOAD_SCP_IMAGES #if ARM_BL31_IN_DRAM #error "SCP_BL2 is not expected to be loaded by BL2 for ARM_BL31_IN_DRAM config" #endif /* * Load address of SCP_BL2 in CSS platform ports * SCP_BL2 is loaded to the same place as BL31 but it shouldn't overwrite BL1 * rw data or BL2. Once SCP_BL2 is transferred to the SCP, it is discarded and * BL31 is loaded over the top. */ #define SCP_BL2_BASE (BL2_BASE - PLAT_CSS_MAX_SCP_BL2_SIZE) #define SCP_BL2_LIMIT BL2_BASE #define SCP_BL2U_BASE (BL2_BASE - PLAT_CSS_MAX_SCP_BL2U_SIZE) #define SCP_BL2U_LIMIT BL2_BASE #endif /* CSS_LOAD_SCP_IMAGES */ /* Load address of Non-Secure Image for CSS platform ports */ #define PLAT_ARM_NS_IMAGE_BASE U(0xE0000000) /* TZC related constants */ #define PLAT_ARM_TZC_FILTERS TZC_400_REGION_ATTR_FILTER_BIT_ALL /* * Parsing of CPU and Cluster states, as returned by 'Get CSS Power State' SCP * command */ #define CSS_CLUSTER_PWR_STATE_ON 0 #define CSS_CLUSTER_PWR_STATE_OFF 3 #define CSS_CPU_PWR_STATE_ON 1 #define CSS_CPU_PWR_STATE_OFF 0 #define CSS_CPU_PWR_STATE(state, n) (((state) >> (n)) & 1) #endif /* CSS_DEF_H */ trusted-firmware-a-2.2/include/plat/arm/css/common/css_pm.h000066400000000000000000000030051355360272700237660ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CSS_PM_H #define CSS_PM_H #include #include #include /* Macros to read the CSS power domain state */ #define CSS_CORE_PWR_STATE(state) (state)->pwr_domain_state[ARM_PWR_LVL0] #define CSS_CLUSTER_PWR_STATE(state) (state)->pwr_domain_state[ARM_PWR_LVL1] static inline unsigned int css_system_pwr_state(const psci_power_state_t *state) { #if (PLAT_MAX_PWR_LVL == CSS_SYSTEM_PWR_DMN_LVL) return state->pwr_domain_state[CSS_SYSTEM_PWR_DMN_LVL]; #else return 0; #endif } int css_pwr_domain_on(u_register_t mpidr); void css_pwr_domain_on_finish(const psci_power_state_t *target_state); void css_pwr_domain_on_finish_late(const psci_power_state_t *target_state); void css_pwr_domain_off(const psci_power_state_t *target_state); void css_pwr_domain_suspend(const psci_power_state_t *target_state); void css_pwr_domain_suspend_finish( const psci_power_state_t *target_state); void __dead2 css_system_off(void); void __dead2 css_system_reset(void); void css_cpu_standby(plat_local_state_t cpu_state); void css_get_sys_suspend_power_state(psci_power_state_t *req_state); int css_node_hw_state(u_register_t mpidr, unsigned int power_level); /* * This mapping array has to be exported by the platform. Each element at * a given index maps that core to an SCMI power domain. */ extern const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[]; #endif /* CSS_PM_H */ trusted-firmware-a-2.2/include/plat/arm/soc/000077500000000000000000000000001355360272700210375ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/arm/soc/common/000077500000000000000000000000001355360272700223275ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/arm/soc/common/soc_css.h000066400000000000000000000006111355360272700241320ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SOC_CSS_H #define SOC_CSS_H /* * Utility functions for ARM CSS SoCs */ void soc_css_init_nic400(void); void soc_css_init_pcie(void); static inline void soc_css_security_setup(void) { soc_css_init_nic400(); soc_css_init_pcie(); } #endif /* SOC_CSS_H */ trusted-firmware-a-2.2/include/plat/arm/soc/common/soc_css_def.h000066400000000000000000000045031355360272700247540ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SOC_CSS_DEF_H #define SOC_CSS_DEF_H #include #include /* * Definitions common to all ARM CSS SoCs */ /* Following covers ARM CSS SoC Peripherals and PCIe expansion area */ #define SOC_CSS_DEVICE_BASE 0x40000000 #define SOC_CSS_DEVICE_SIZE 0x40000000 #define SOC_CSS_PCIE_CONTROL_BASE 0x7ff20000 /* PL011 UART related constants */ #define SOC_CSS_UART0_BASE 0x7ff80000 #define SOC_CSS_UART1_BASE 0x7ff70000 #define SOC_CSS_UART0_CLK_IN_HZ 7372800 #define SOC_CSS_UART1_CLK_IN_HZ 7372800 /* SoC NIC-400 Global Programmers View (GPV) */ #define SOC_CSS_NIC400_BASE 0x7fd00000 #define SOC_CSS_NIC400_USB_EHCI 0 #define SOC_CSS_NIC400_TLX_MASTER 1 #define SOC_CSS_NIC400_USB_OHCI 2 #define SOC_CSS_NIC400_PL354_SMC 3 /* * The apb4_bridge controls access to: * - the PCIe configuration registers * - the MMU units for USB, HDLCD and DMA */ #define SOC_CSS_NIC400_APB4_BRIDGE 4 /* Non-volatile counters */ #define SOC_TRUSTED_NVCTR_BASE 0x7fe70000 #define TFW_NVCTR_BASE (SOC_TRUSTED_NVCTR_BASE + 0x0000) #define TFW_NVCTR_SIZE 4 #define NTFW_CTR_BASE (SOC_TRUSTED_NVCTR_BASE + 0x0004) #define NTFW_CTR_SIZE 4 /* Keys */ #define SOC_KEYS_BASE 0x7fe80000 #define TZ_PUB_KEY_HASH_BASE (SOC_KEYS_BASE + 0x0000) #define TZ_PUB_KEY_HASH_SIZE 32 #define HU_KEY_BASE (SOC_KEYS_BASE + 0x0020) #define HU_KEY_SIZE 16 #define END_KEY_BASE (SOC_KEYS_BASE + 0x0044) #define END_KEY_SIZE 32 #define SOC_CSS_MAP_DEVICE MAP_REGION_FLAT( \ SOC_CSS_DEVICE_BASE, \ SOC_CSS_DEVICE_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) /* * The bootsec_bridge controls access to a bunch of peripherals, e.g. the UARTs. */ #define SOC_CSS_NIC400_BOOTSEC_BRIDGE 5 #define SOC_CSS_NIC400_BOOTSEC_BRIDGE_UART1 (1 << 12) /* * Required platform porting definitions common to all ARM CSS SoCs */ #if JUNO_AARCH32_EL3_RUNTIME /* * Following change is required to initialize TZC * for enabling access to the HI_VECTOR (0xFFFF0000) * location needed for JUNO AARCH32 support. */ #define PLAT_ARM_SCP_TZC_DRAM1_SIZE ULL(0x8000) #else /* 2MB used for SCP DDR retraining */ #define PLAT_ARM_SCP_TZC_DRAM1_SIZE ULL(0x00200000) #endif #endif /* SOC_CSS_DEF_H */ trusted-firmware-a-2.2/include/plat/common/000077500000000000000000000000001355360272700207645ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/common/common_def.h000066400000000000000000000057501355360272700232520ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef COMMON_DEF_H #define COMMON_DEF_H #include #include #include #include /****************************************************************************** * Required platform porting definitions that are expected to be common to * all platforms *****************************************************************************/ /* * Platform binary types for linking */ #ifdef __aarch64__ #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 #else #define PLATFORM_LINKER_FORMAT "elf32-littlearm" #define PLATFORM_LINKER_ARCH arm #endif /* __aarch64__ */ /* * Generic platform constants */ #define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n" #define BL2_IMAGE_DESC { \ .image_id = BL2_IMAGE_ID, \ SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, \ VERSION_2, image_info_t, 0), \ .image_info.image_base = BL2_BASE, \ .image_info.image_max_size = BL2_LIMIT - BL2_BASE,\ SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, \ VERSION_2, entry_point_info_t, SECURE | EXECUTABLE),\ .ep_info.pc = BL2_BASE, \ } /* * The following constants identify the extents of the code & read-only data * regions. These addresses are used by the MMU setup code and therefore they * must be page-aligned. * * When the code and read-only data are mapped as a single atomic section * (i.e. when SEPARATE_CODE_AND_RODATA=0) then we treat the whole section as * code by specifying the read-only data section as empty. * * BL1 is different than the other images in the sense that its read-write data * originally lives in Trusted ROM and needs to be relocated in Trusted SRAM at * run-time. Therefore, the read-write data in ROM can be mapped with the same * memory attributes as the read-only data region. For this reason, BL1 uses * different macros. * * Note that BL1_ROM_END is not necessarily aligned on a page boundary as it * just points to the end of BL1's actual content in Trusted ROM. Therefore it * needs to be rounded up to the next page size in order to map the whole last * page of it with the right memory attributes. */ #if SEPARATE_CODE_AND_RODATA #define BL1_CODE_END BL_CODE_END #define BL1_RO_DATA_BASE BL_RO_DATA_BASE #define BL1_RO_DATA_END round_up(BL1_ROM_END, PAGE_SIZE) #if BL2_IN_XIP_MEM #define BL2_CODE_END BL_CODE_END #define BL2_RO_DATA_BASE BL_RO_DATA_BASE #define BL2_RO_DATA_END round_up(BL2_ROM_END, PAGE_SIZE) #endif /* BL2_IN_XIP_MEM */ #else #define BL_RO_DATA_BASE UL(0) #define BL_RO_DATA_END UL(0) #define BL1_CODE_END round_up(BL1_ROM_END, PAGE_SIZE) #if BL2_IN_XIP_MEM #define BL2_RO_DATA_BASE UL(0) #define BL2_RO_DATA_END UL(0) #define BL2_CODE_END round_up(BL2_ROM_END, PAGE_SIZE) #endif /* BL2_IN_XIP_MEM */ #endif /* SEPARATE_CODE_AND_RODATA */ #endif /* COMMON_DEF_H */ trusted-firmware-a-2.2/include/plat/common/platform.h000066400000000000000000000305471355360272700227720ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_H #define PLATFORM_H #include #include /******************************************************************************* * Forward declarations ******************************************************************************/ struct auth_img_desc_s; struct meminfo; struct image_info; struct entry_point_info; struct image_desc; struct bl_load_info; struct bl_params; struct mmap_region; struct secure_partition_boot_info; struct sp_res_desc; /******************************************************************************* * plat_get_rotpk_info() flags ******************************************************************************/ #define ROTPK_IS_HASH (1 << 0) /* Flag used to skip verification of the certificate ROTPK while the platform ROTPK is not deployed */ #define ROTPK_NOT_DEPLOYED (1 << 1) /******************************************************************************* * Function declarations ******************************************************************************/ /******************************************************************************* * Mandatory common functions ******************************************************************************/ unsigned int plat_get_syscnt_freq2(void); int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, uintptr_t *image_spec); uintptr_t plat_get_ns_image_entrypoint(void); unsigned int plat_my_core_pos(void); int plat_core_pos_by_mpidr(u_register_t mpidr); int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size); #if STACK_PROTECTOR_ENABLED /* * Return a new value to be used for the stack protection's canary. * * Ideally, this value is a random number that is impossible to predict by an * attacker. */ u_register_t plat_get_stack_protector_canary(void); #endif /* STACK_PROTECTOR_ENABLED */ /******************************************************************************* * Mandatory interrupt management functions ******************************************************************************/ uint32_t plat_ic_get_pending_interrupt_id(void); uint32_t plat_ic_get_pending_interrupt_type(void); uint32_t plat_ic_acknowledge_interrupt(void); uint32_t plat_ic_get_interrupt_type(uint32_t id); void plat_ic_end_of_interrupt(uint32_t id); uint32_t plat_interrupt_type_to_line(uint32_t type, uint32_t security_state); /******************************************************************************* * Optional interrupt management functions, depending on chosen EL3 components. ******************************************************************************/ unsigned int plat_ic_get_running_priority(void); int plat_ic_is_spi(unsigned int id); int plat_ic_is_ppi(unsigned int id); int plat_ic_is_sgi(unsigned int id); unsigned int plat_ic_get_interrupt_active(unsigned int id); void plat_ic_disable_interrupt(unsigned int id); void plat_ic_enable_interrupt(unsigned int id); int plat_ic_has_interrupt_type(unsigned int type); void plat_ic_set_interrupt_type(unsigned int id, unsigned int type); void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority); void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target); void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode, u_register_t mpidr); void plat_ic_set_interrupt_pending(unsigned int id); void plat_ic_clear_interrupt_pending(unsigned int id); unsigned int plat_ic_set_priority_mask(unsigned int mask); unsigned int plat_ic_get_interrupt_id(unsigned int raw); /******************************************************************************* * Optional common functions (may be overridden) ******************************************************************************/ uintptr_t plat_get_my_stack(void); void plat_report_exception(unsigned int exception_type); int plat_crash_console_init(void); int plat_crash_console_putc(int c); int plat_crash_console_flush(void); void plat_error_handler(int err) __dead2; void plat_panic_handler(void) __dead2; const char *plat_log_get_prefix(unsigned int log_level); void bl2_plat_preload_setup(void); int plat_try_next_boot_source(void); /******************************************************************************* * Mandatory BL1 functions ******************************************************************************/ void bl1_early_platform_setup(void); void bl1_plat_arch_setup(void); void bl1_platform_setup(void); struct meminfo *bl1_plat_sec_mem_layout(void); /******************************************************************************* * Optional EL3 component functions in BL31 ******************************************************************************/ /* SDEI platform functions */ #if SDEI_SUPPORT int plat_sdei_validate_entry_point(uintptr_t ep, unsigned int client_mode); void plat_sdei_handle_masked_trigger(uint64_t mpidr, unsigned int intr); #endif void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie, void *handle, uint64_t flags); /* * The following function is mandatory when the * firmware update feature is used. */ int bl1_plat_mem_check(uintptr_t mem_base, unsigned int mem_size, unsigned int flags); /******************************************************************************* * Optional BL1 functions (may be overridden) ******************************************************************************/ /* * The following functions are used for image loading process in BL1. */ void bl1_plat_set_ep_info(unsigned int image_id, struct entry_point_info *ep_info); /* * The following functions are mandatory when firmware update * feature is used and optional otherwise. */ unsigned int bl1_plat_get_next_image_id(void); struct image_desc *bl1_plat_get_image_desc(unsigned int image_id); /* * The following functions are used by firmware update * feature and may optionally be overridden. */ __dead2 void bl1_plat_fwu_done(void *client_cookie, void *reserved); /* * This BL1 function can be used by the platforms to update/use image * information for a given `image_id`. */ int bl1_plat_handle_pre_image_load(unsigned int image_id); int bl1_plat_handle_post_image_load(unsigned int image_id); /******************************************************************************* * Mandatory BL2 functions ******************************************************************************/ void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3); void bl2_plat_arch_setup(void); void bl2_platform_setup(void); struct meminfo *bl2_plat_sec_mem_layout(void); /* * This function can be used by the platforms to update/use image * information for given `image_id`. */ int bl2_plat_handle_pre_image_load(unsigned int image_id); int bl2_plat_handle_post_image_load(unsigned int image_id); /******************************************************************************* * Optional BL2 functions (may be overridden) ******************************************************************************/ /******************************************************************************* * Mandatory BL2 at EL3 functions: Must be implemented if BL2_AT_EL3 image is * supported ******************************************************************************/ void bl2_el3_early_platform_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3); void bl2_el3_plat_arch_setup(void); /******************************************************************************* * Optional BL2 at EL3 functions (may be overridden) ******************************************************************************/ void bl2_el3_plat_prepare_exit(void); /******************************************************************************* * Mandatory BL2U functions. ******************************************************************************/ void bl2u_early_platform_setup(struct meminfo *mem_layout, void *plat_info); void bl2u_plat_arch_setup(void); void bl2u_platform_setup(void); /******************************************************************************* * Conditionally mandatory BL2U functions for CSS platforms. ******************************************************************************/ /* * This function is used to perform any platform-specific actions required to * handle the BL2U_SCP firmware. */ int bl2u_plat_handle_scp_bl2u(void); /******************************************************************************* * Mandatory BL31 functions ******************************************************************************/ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3); void bl31_plat_arch_setup(void); void bl31_platform_setup(void); void bl31_plat_runtime_setup(void); struct entry_point_info *bl31_plat_get_next_image_ep_info(uint32_t type); /******************************************************************************* * Mandatory PSCI functions (BL31) ******************************************************************************/ int plat_setup_psci_ops(uintptr_t sec_entrypoint, const struct plat_psci_ops **psci_ops); const unsigned char *plat_get_power_domain_tree_desc(void); /******************************************************************************* * Optional PSCI functions (BL31). ******************************************************************************/ void plat_psci_stat_accounting_start(const psci_power_state_t *state_info); void plat_psci_stat_accounting_stop(const psci_power_state_t *state_info); u_register_t plat_psci_stat_get_residency(unsigned int lvl, const psci_power_state_t *state_info, int last_cpu_idx); plat_local_state_t plat_get_target_pwr_state(unsigned int lvl, const plat_local_state_t *states, unsigned int ncpu); /******************************************************************************* * Optional BL31 functions (may be overridden) ******************************************************************************/ void bl31_plat_enable_mmu(uint32_t flags); /******************************************************************************* * Optional BL32 functions (may be overridden) ******************************************************************************/ void bl32_plat_enable_mmu(uint32_t flags); /******************************************************************************* * Trusted Board Boot functions ******************************************************************************/ int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, unsigned int *flags); int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr); int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr); int plat_set_nv_ctr2(void *cookie, const struct auth_img_desc_s *img_desc, unsigned int nv_ctr); int get_mbedtls_heap_helper(void **heap_addr, size_t *heap_size); /******************************************************************************* * Secure Partitions functions ******************************************************************************/ const struct mmap_region *plat_get_secure_partition_mmap(void *cookie); const struct secure_partition_boot_info *plat_get_secure_partition_boot_info( void *cookie); int plat_spm_sp_rd_load(struct sp_res_desc *rd, const void *ptr, size_t size); int plat_spm_sp_get_next_address(void **sp_base, size_t *sp_size, void **rd_base, size_t *rd_size); /******************************************************************************* * Mandatory BL image load functions(may be overridden). ******************************************************************************/ /* * This function returns pointer to the list of images that the * platform has populated to load. */ struct bl_load_info *plat_get_bl_image_load_info(void); /* * This function returns a pointer to the shared memory that the * platform has kept aside to pass trusted firmware related * information that next BL image could need. */ struct bl_params *plat_get_next_bl_params(void); /* * This function flushes to main memory all the params that are * passed to next image. */ void plat_flush_next_bl_params(void); /* * The below function enable Trusted Firmware components like SPDs which * haven't migrated to the new platform API to compile on platforms which * have the compatibility layer disabled. */ unsigned int platform_core_pos_helper(unsigned long mpidr); #endif /* PLATFORM_H */ trusted-firmware-a-2.2/include/plat/marvell/000077500000000000000000000000001355360272700211365ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/marvell/a3700/000077500000000000000000000000001355360272700216705ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/marvell/a3700/common/000077500000000000000000000000001355360272700231605ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/marvell/a3700/common/armada_common.h000066400000000000000000000005221355360272700261250ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef ARMADA_COMMON_H #define ARMADA_COMMON_H #include #include int marvell_get_io_dec_win_conf(struct dec_win_config **win, uint32_t *size); #endif /* ARMADA_COMMON_H */ trusted-firmware-a-2.2/include/plat/marvell/a3700/common/board_marvell_def.h000066400000000000000000000030571355360272700267650ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef BOARD_MARVELL_DEF_H #define BOARD_MARVELL_DEF_H /* * Required platform porting definitions common to all ARM * development platforms */ /* Size of cacheable stacks */ #if IMAGE_BL1 #if TRUSTED_BOARD_BOOT # define PLATFORM_STACK_SIZE 0x1000 #else # define PLATFORM_STACK_SIZE 0x440 #endif #elif IMAGE_BL2 # if TRUSTED_BOARD_BOOT # define PLATFORM_STACK_SIZE 0x1000 # else # define PLATFORM_STACK_SIZE 0x400 # endif #elif IMAGE_BL31 # define PLATFORM_STACK_SIZE 0x400 #elif IMAGE_BL32 # define PLATFORM_STACK_SIZE 0x440 #endif /* * PLAT_MARVELL_MMAP_ENTRIES depends on the number of entries in the * plat_arm_mmap array defined for each BL stage. */ #if IMAGE_BLE # define PLAT_MARVELL_MMAP_ENTRIES 3 #endif #if IMAGE_BL1 # if TRUSTED_BOARD_BOOT # define PLAT_MARVELL_MMAP_ENTRIES 7 # else # define PLAT_MARVELL_MMAP_ENTRIES 6 # endif /* TRUSTED_BOARD_BOOT */ #endif #if IMAGE_BL2 # define PLAT_MARVELL_MMAP_ENTRIES 8 #endif #if IMAGE_BL31 #define PLAT_MARVELL_MMAP_ENTRIES 5 #endif /* * Platform specific page table and MMU setup constants */ #if IMAGE_BL1 #define MAX_XLAT_TABLES 4 #elif IMAGE_BLE # define MAX_XLAT_TABLES 4 #elif IMAGE_BL2 # define MAX_XLAT_TABLES 4 #elif IMAGE_BL31 # define MAX_XLAT_TABLES 4 #elif IMAGE_BL32 # define MAX_XLAT_TABLES 4 #endif #define MAX_IO_DEVICES 3 #define MAX_IO_HANDLES 4 #define PLAT_MARVELL_TRUSTED_SRAM_SIZE 0x80000 /* 512 KB */ #endif /* BOARD_MARVELL_DEF_H */ trusted-firmware-a-2.2/include/plat/marvell/a3700/common/marvell_def.h000066400000000000000000000127251355360272700256200ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MARVELL_DEF_H #define MARVELL_DEF_H #include #include #include #include #include /**************************************************************************** * Definitions common to all MARVELL standard platforms **************************************************************************** */ /* Special value used to verify platform parameters from BL2 to BL31 */ #define MARVELL_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL #define PLAT_MARVELL_NORTHB_COUNT 1 #define PLAT_MARVELL_CLUSTER_COUNT 1 #define MARVELL_CACHE_WRITEBACK_SHIFT 6 /* * Macros mapping the MPIDR Affinity levels to MARVELL Platform Power levels. * The power levels have a 1:1 mapping with the MPIDR affinity levels. */ #define MARVELL_PWR_LVL0 MPIDR_AFFLVL0 #define MARVELL_PWR_LVL1 MPIDR_AFFLVL1 #define MARVELL_PWR_LVL2 MPIDR_AFFLVL2 /* * Macros for local power states in Marvell platforms encoded by State-ID field * within the power-state parameter. */ /* Local power state for power domains in Run state. */ #define MARVELL_LOCAL_STATE_RUN 0 /* Local power state for retention. Valid only for CPU power domains */ #define MARVELL_LOCAL_STATE_RET 1 /* Local power state for OFF/power-down. * Valid for CPU and cluster power domains */ #define MARVELL_LOCAL_STATE_OFF 2 /* The first 4KB of Trusted SRAM are used as shared memory */ #define MARVELL_TRUSTED_SRAM_BASE PLAT_MARVELL_ATF_BASE #define MARVELL_SHARED_RAM_BASE MARVELL_TRUSTED_SRAM_BASE #define MARVELL_SHARED_RAM_SIZE 0x00001000 /* 4 KB */ /* The remaining Trusted SRAM is used to load the BL images */ #define MARVELL_BL_RAM_BASE (MARVELL_SHARED_RAM_BASE + \ MARVELL_SHARED_RAM_SIZE) #define MARVELL_BL_RAM_SIZE (PLAT_MARVELL_TRUSTED_SRAM_SIZE - \ MARVELL_SHARED_RAM_SIZE) #define MARVELL_DRAM_BASE ULL(0x0) #define MARVELL_DRAM_SIZE ULL(0x20000000) #define MARVELL_DRAM_END (MARVELL_DRAM_BASE + \ MARVELL_DRAM_SIZE - 1) #define MARVELL_IRQ_SEC_PHY_TIMER 29 #define MARVELL_IRQ_SEC_SGI_0 8 #define MARVELL_IRQ_SEC_SGI_1 9 #define MARVELL_IRQ_SEC_SGI_2 10 #define MARVELL_IRQ_SEC_SGI_3 11 #define MARVELL_IRQ_SEC_SGI_4 12 #define MARVELL_IRQ_SEC_SGI_5 13 #define MARVELL_IRQ_SEC_SGI_6 14 #define MARVELL_IRQ_SEC_SGI_7 15 #define MARVELL_MAP_SHARED_RAM MAP_REGION_FLAT( \ MARVELL_SHARED_RAM_BASE, \ MARVELL_SHARED_RAM_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #define MARVELL_MAP_DRAM MAP_REGION_FLAT( \ MARVELL_DRAM_BASE, \ MARVELL_DRAM_SIZE, \ MT_MEMORY | MT_RW | MT_NS) /* * The number of regions like RO(code), coherent and data required by * different BL stages which need to be mapped in the MMU. */ #if USE_COHERENT_MEM #define MARVELL_BL_REGIONS 3 #else #define MARVELL_BL_REGIONS 2 #endif #define MAX_MMAP_REGIONS (PLAT_MARVELL_MMAP_ENTRIES + \ MARVELL_BL_REGIONS) #define MARVELL_CONSOLE_BAUDRATE 115200 /**************************************************************************** * Required platform porting definitions common to all MARVELL std. platforms **************************************************************************** */ #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) /* * This macro defines the deepest retention state possible. A higher state * id will represent an invalid or a power down state. */ #define PLAT_MAX_RET_STATE MARVELL_LOCAL_STATE_RET /* * This macro defines the deepest power down states possible. Any state ID * higher than this is invalid. */ #define PLAT_MAX_OFF_STATE MARVELL_LOCAL_STATE_OFF #define PLATFORM_CORE_COUNT PLAT_MARVELL_CLUSTER_CORE_COUNT /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. */ #define CACHE_WRITEBACK_GRANULE (1 << MARVELL_CACHE_WRITEBACK_SHIFT) /***************************************************************************** * BL1 specific defines. * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of * addresses. ***************************************************************************** */ #define BL1_RO_BASE PLAT_MARVELL_TRUSTED_ROM_BASE #define BL1_RO_LIMIT (PLAT_MARVELL_TRUSTED_ROM_BASE \ + PLAT_MARVELL_TRUSTED_ROM_SIZE) /* * Put BL1 RW at the top of the Trusted SRAM. */ #define BL1_RW_BASE (MARVELL_BL_RAM_BASE + \ MARVELL_BL_RAM_SIZE - \ PLAT_MARVELL_MAX_BL1_RW_SIZE) #define BL1_RW_LIMIT (MARVELL_BL_RAM_BASE + MARVELL_BL_RAM_SIZE) /***************************************************************************** * BL2 specific defines. ***************************************************************************** */ /* * Put BL2 just below BL31. */ #define BL2_BASE (BL31_BASE - PLAT_MARVELL_MAX_BL2_SIZE) #define BL2_LIMIT BL31_BASE /***************************************************************************** * BL31 specific defines. ***************************************************************************** */ /* * Put BL31 at the top of the Trusted SRAM. */ #define BL31_BASE (MARVELL_BL_RAM_BASE + \ MARVELL_BL_RAM_SIZE - \ PLAT_MARVEL_MAX_BL31_SIZE) #define BL31_PROGBITS_LIMIT BL1_RW_BASE #define BL31_LIMIT (MARVELL_BL_RAM_BASE + \ MARVELL_BL_RAM_SIZE) #endif /* MARVELL_DEF_H */ trusted-firmware-a-2.2/include/plat/marvell/a3700/common/plat_marvell.h000066400000000000000000000052721355360272700260210ustar00rootroot00000000000000/* * Copyright (C) 2016 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef PLAT_MARVELL_H #define PLAT_MARVELL_H #include #include #include #include #include /* * Extern declarations common to Marvell standard platforms */ extern const mmap_region_t plat_marvell_mmap[]; #define MARVELL_CASSERT_MMAP \ CASSERT((ARRAY_SIZE(plat_marvell_mmap) + MARVELL_BL_REGIONS) \ <= MAX_MMAP_REGIONS, \ assert_max_mmap_regions) /* * Utility functions common to Marvell standard platforms */ void marvell_setup_page_tables(uintptr_t total_base, size_t total_size, uintptr_t code_start, uintptr_t code_limit, uintptr_t rodata_start, uintptr_t rodata_limit #if USE_COHERENT_MEM , uintptr_t coh_start, uintptr_t coh_limit #endif ); /* Console utility functions */ void marvell_console_boot_init(void); void marvell_console_boot_end(void); void marvell_console_runtime_init(void); void marvell_console_runtime_end(void); /* IO storage utility functions */ void marvell_io_setup(void); /* Systimer utility function */ void marvell_configure_sys_timer(void); /* Topology utility function */ int marvell_check_mpidr(u_register_t mpidr); /* BL1 utility functions */ void marvell_bl1_early_platform_setup(void); void marvell_bl1_platform_setup(void); void marvell_bl1_plat_arch_setup(void); /* BL2 utility functions */ void marvell_bl2_early_platform_setup(meminfo_t *mem_layout); void marvell_bl2_platform_setup(void); void marvell_bl2_plat_arch_setup(void); uint32_t marvell_get_spsr_for_bl32_entry(void); uint32_t marvell_get_spsr_for_bl33_entry(void); /* BL31 utility functions */ void marvell_bl31_early_platform_setup(void *from_bl2, uintptr_t soc_fw_config, uintptr_t hw_config, void *plat_params_from_bl2); void marvell_bl31_platform_setup(void); void marvell_bl31_plat_runtime_setup(void); void marvell_bl31_plat_arch_setup(void); /* FIP TOC validity check */ int marvell_io_is_toc_valid(void); /* * PSCI functionality */ void marvell_psci_arch_init(int idx); void plat_marvell_system_reset(void); /* * Optional functions required in Marvell standard platforms */ void plat_marvell_io_setup(void); int plat_marvell_get_alt_image_source( unsigned int image_id, uintptr_t *dev_handle, uintptr_t *image_spec); unsigned int plat_marvell_calc_core_pos(u_register_t mpidr); void plat_marvell_interconnect_init(void); void plat_marvell_interconnect_enter_coherency(void); const mmap_region_t *plat_marvell_get_mmap(void); #endif /* PLAT_MARVELL_H */ trusted-firmware-a-2.2/include/plat/marvell/a8k/000077500000000000000000000000001355360272700216215ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/marvell/a8k/common/000077500000000000000000000000001355360272700231115ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/marvell/a8k/common/armada_common.h000066400000000000000000000057571355360272700260750ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef ARMADA_COMMON_H #define ARMADA_COMMON_H #include #include #include #include /* * This struct supports skip image request * detection_method: the method used to detect the request "signal". * info: * GPIO: * detection_method: HIGH (pressed button), LOW (unpressed button), * num (button mpp number). * i2c: * i2c_addr: the address of the i2c chosen. * i2d_reg: the i2c register chosen. * test: * choose the DIE you picked the button in (AP or CP). * in case of CP(cp_index = 0 if CP0, cp_index = 1 if CP1) */ struct skip_image { enum { GPIO, I2C, USER_DEFINED } detection_method; struct { struct { int num; enum { HIGH, LOW } button_state; } gpio; struct { int i2c_addr; int i2c_reg; } i2c; struct { enum { CP, AP } cp_ap; int cp_index; } test; } info; }; /* * This struct supports SoC power off method * type: the method used to power off the SoC * cfg: * PMIC_GPIO: * pin_count: current GPIO pin number used for toggling the signal for * notifying external PMIC * info: holds the GPIOs information, CP GPIO should be used and * all GPIOs should be within same GPIO config. register * step_count: current step number to toggle the GPIO for PMIC * seq: GPIO toggling values in sequence, each bit represents a GPIO. * For example, bit0 represents first GPIO used for toggling * the GPIO the last step is used to trigger the power off * signal * delay_ms: transition interval for the GPIO setting to take effect * in unit of ms */ /* Max GPIO number used to notify PMIC to power off the SoC */ #define PMIC_GPIO_MAX_NUMBER 8 /* Max GPIO toggling steps in sequence to power off the SoC */ #define PMIC_GPIO_MAX_TOGGLE_STEP 8 enum gpio_output_state { GPIO_LOW = 0, GPIO_HIGH }; typedef struct gpio_info { int cp_index; int gpio_index; } gpio_info_t; struct power_off_method { enum { PMIC_GPIO, } type; struct { struct { int pin_count; struct gpio_info info[PMIC_GPIO_MAX_NUMBER]; int step_count; uint32_t seq[PMIC_GPIO_MAX_TOGGLE_STEP]; int delay_ms; } gpio; } cfg; }; int marvell_gpio_config(void); uint32_t marvell_get_io_win_gcr_target(int ap_idx); uint32_t marvell_get_ccu_gcr_target(int ap_idx); /* * The functions below are defined as Weak and may be overridden * in specific Marvell standard platform */ int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size, uintptr_t base); int marvell_get_io_win_memory_map(int ap_idx, struct addr_map_win **win, uint32_t *size); int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size, uintptr_t base); int marvell_get_ccu_memory_map(int ap_idx, struct addr_map_win **win, uint32_t *size); #endif /* ARMADA_COMMON_H */ trusted-firmware-a-2.2/include/plat/marvell/a8k/common/board_marvell_def.h000066400000000000000000000031031355360272700267060ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef BOARD_MARVELL_DEF_H #define BOARD_MARVELL_DEF_H /* * Required platform porting definitions common to all ARM * development platforms */ /* Size of cacheable stacks */ #if IMAGE_BL1 #if TRUSTED_BOARD_BOOT # define PLATFORM_STACK_SIZE 0x1000 #else # define PLATFORM_STACK_SIZE 0x440 #endif #elif IMAGE_BL2 # if TRUSTED_BOARD_BOOT # define PLATFORM_STACK_SIZE 0x1000 # else # define PLATFORM_STACK_SIZE 0x400 # endif #elif IMAGE_BL31 # define PLATFORM_STACK_SIZE 0x400 #elif IMAGE_BL32 # define PLATFORM_STACK_SIZE 0x440 #endif /* * PLAT_MARVELL_MMAP_ENTRIES depends on the number of entries in the * plat_arm_mmap array defined for each BL stage. */ #if IMAGE_BLE # define PLAT_MARVELL_MMAP_ENTRIES 3 #endif #if IMAGE_BL1 # if TRUSTED_BOARD_BOOT # define PLAT_MARVELL_MMAP_ENTRIES 7 # else # define PLAT_MARVELL_MMAP_ENTRIES 6 # endif /* TRUSTED_BOARD_BOOT */ #endif #if IMAGE_BL2 # define PLAT_MARVELL_MMAP_ENTRIES 8 #endif #if IMAGE_BL31 #define PLAT_MARVELL_MMAP_ENTRIES 5 #endif /* * Platform specific page table and MMU setup constants */ #if IMAGE_BL1 #define MAX_XLAT_TABLES 4 #elif IMAGE_BLE # define MAX_XLAT_TABLES 4 #elif IMAGE_BL2 # define MAX_XLAT_TABLES 4 #elif IMAGE_BL31 # define MAX_XLAT_TABLES 4 #elif IMAGE_BL32 # define MAX_XLAT_TABLES 4 #endif #define MAX_IO_DEVICES 3 #define MAX_IO_HANDLES 4 #define PLAT_MARVELL_TRUSTED_SRAM_SIZE 0x80000 /* 512 KB */ #endif /* BOARD_MARVELL_DEF_H */ trusted-firmware-a-2.2/include/plat/marvell/a8k/common/marvell_def.h000066400000000000000000000134521355360272700255470ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MARVELL_DEF_H #define MARVELL_DEF_H #include #include #include #include #include /****************************************************************************** * Definitions common to all MARVELL standard platforms *****************************************************************************/ /* Special value used to verify platform parameters from BL2 to BL31 */ #define MARVELL_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL #define MARVELL_CACHE_WRITEBACK_SHIFT 6 /* * Macros mapping the MPIDR Affinity levels to MARVELL Platform Power levels. * The power levels have a 1:1 mapping with the MPIDR affinity levels. */ #define MARVELL_PWR_LVL0 MPIDR_AFFLVL0 #define MARVELL_PWR_LVL1 MPIDR_AFFLVL1 #define MARVELL_PWR_LVL2 MPIDR_AFFLVL2 /* * Macros for local power states in Marvell platforms encoded by * State-ID field within the power-state parameter. */ /* Local power state for power domains in Run state. */ #define MARVELL_LOCAL_STATE_RUN 0 /* Local power state for retention. Valid only for CPU power domains */ #define MARVELL_LOCAL_STATE_RET 1 /* * Local power state for OFF/power-down. Valid for CPU * and cluster power domains */ #define MARVELL_LOCAL_STATE_OFF 2 /* The first 4KB of Trusted SRAM are used as shared memory */ #define MARVELL_TRUSTED_SRAM_BASE PLAT_MARVELL_ATF_BASE #define MARVELL_SHARED_RAM_BASE MARVELL_TRUSTED_SRAM_BASE #define MARVELL_SHARED_RAM_SIZE 0x00001000 /* 4 KB */ /* The remaining Trusted SRAM is used to load the BL images */ #define MARVELL_BL_RAM_BASE (MARVELL_SHARED_RAM_BASE + \ MARVELL_SHARED_RAM_SIZE) #define MARVELL_BL_RAM_SIZE (PLAT_MARVELL_TRUSTED_SRAM_SIZE - \ MARVELL_SHARED_RAM_SIZE) /* Non-shared DRAM */ #define MARVELL_DRAM_BASE ULL(0x0) #define MARVELL_DRAM_SIZE ULL(0x80000000) #define MARVELL_DRAM_END (MARVELL_DRAM_BASE + \ MARVELL_DRAM_SIZE - 1) #define MARVELL_IRQ_PIC0 28 #define MARVELL_IRQ_SEC_PHY_TIMER 29 #define MARVELL_IRQ_SEC_SGI_0 8 #define MARVELL_IRQ_SEC_SGI_1 9 #define MARVELL_IRQ_SEC_SGI_2 10 #define MARVELL_IRQ_SEC_SGI_3 11 #define MARVELL_IRQ_SEC_SGI_4 12 #define MARVELL_IRQ_SEC_SGI_5 13 #define MARVELL_IRQ_SEC_SGI_6 14 #define MARVELL_IRQ_SEC_SGI_7 15 #define MARVELL_MAP_SHARED_RAM MAP_REGION_FLAT( \ MARVELL_SHARED_RAM_BASE,\ MARVELL_SHARED_RAM_SIZE,\ MT_MEMORY | MT_RW | MT_SECURE) #define MARVELL_MAP_DRAM MAP_REGION_FLAT( \ MARVELL_DRAM_BASE, \ MARVELL_DRAM_SIZE, \ MT_MEMORY | MT_RW | MT_NS) /* * The number of regions like RO(code), coherent and data required by * different BL stages which need to be mapped in the MMU. */ #if USE_COHERENT_MEM #define MARVELL_BL_REGIONS 3 #else #define MARVELL_BL_REGIONS 2 #endif #define MAX_MMAP_REGIONS (PLAT_MARVELL_MMAP_ENTRIES + \ MARVELL_BL_REGIONS) #define MARVELL_CONSOLE_BAUDRATE 115200 /****************************************************************************** * Required platform porting definitions common to all MARVELL std. platforms *****************************************************************************/ #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) /* * This macro defines the deepest retention state possible. A higher state * id will represent an invalid or a power down state. */ #define PLAT_MAX_RET_STATE MARVELL_LOCAL_STATE_RET /* * This macro defines the deepest power down states possible. Any state ID * higher than this is invalid. */ #define PLAT_MAX_OFF_STATE MARVELL_LOCAL_STATE_OFF #define PLATFORM_CORE_COUNT PLAT_MARVELL_CORE_COUNT #define PLAT_NUM_PWR_DOMAINS (PLAT_MARVELL_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. */ #define CACHE_WRITEBACK_GRANULE (1 << MARVELL_CACHE_WRITEBACK_SHIFT) /******************************************************************************* * BL1 specific defines. * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of * addresses. ******************************************************************************/ #define BL1_RO_BASE PLAT_MARVELL_TRUSTED_ROM_BASE #define BL1_RO_LIMIT (PLAT_MARVELL_TRUSTED_ROM_BASE \ + PLAT_MARVELL_TRUSTED_ROM_SIZE) /* * Put BL1 RW at the top of the Trusted SRAM. */ #define BL1_RW_BASE (MARVELL_BL_RAM_BASE + \ MARVELL_BL_RAM_SIZE - \ PLAT_MARVELL_MAX_BL1_RW_SIZE) #define BL1_RW_LIMIT (MARVELL_BL_RAM_BASE + MARVELL_BL_RAM_SIZE) /******************************************************************************* * BLE specific defines. ******************************************************************************/ #define BLE_BASE PLAT_MARVELL_SRAM_BASE #define BLE_LIMIT PLAT_MARVELL_SRAM_END /******************************************************************************* * BL2 specific defines. ******************************************************************************/ /* * Put BL2 just below BL31. */ #define BL2_BASE (BL31_BASE - PLAT_MARVELL_MAX_BL2_SIZE) #define BL2_LIMIT BL31_BASE /******************************************************************************* * BL31 specific defines. ******************************************************************************/ /* * Put BL31 at the top of the Trusted SRAM. */ #define BL31_BASE (MARVELL_BL_RAM_BASE + \ MARVELL_BL_RAM_SIZE - \ PLAT_MARVEL_MAX_BL31_SIZE) #define BL31_PROGBITS_LIMIT BL1_RW_BASE #define BL31_LIMIT (MARVELL_BL_RAM_BASE + \ MARVELL_BL_RAM_SIZE) #endif /* MARVELL_DEF_H */ trusted-firmware-a-2.2/include/plat/marvell/a8k/common/plat_marvell.h000066400000000000000000000071711355360272700257520ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef PLAT_MARVELL_H #define PLAT_MARVELL_H #include #include #include #include #include /* * Extern declarations common to Marvell standard platforms */ extern const mmap_region_t plat_marvell_mmap[]; #define MARVELL_CASSERT_MMAP \ CASSERT((ARRAY_SIZE(plat_marvell_mmap) + MARVELL_BL_REGIONS) \ <= MAX_MMAP_REGIONS, \ assert_max_mmap_regions) struct marvell_bl31_params { param_header_t h; image_info_t *bl31_image_info; entry_point_info_t *bl32_ep_info; image_info_t *bl32_image_info; entry_point_info_t *bl33_ep_info; image_info_t *bl33_image_info; }; /* * Utility functions common to Marvell standard platforms */ void marvell_setup_page_tables(uintptr_t total_base, size_t total_size, uintptr_t code_start, uintptr_t code_limit, uintptr_t rodata_start, uintptr_t rodata_limit #if USE_COHERENT_MEM , uintptr_t coh_start, uintptr_t coh_limit #endif ); /* Console utility functions */ void marvell_console_boot_init(void); void marvell_console_boot_end(void); void marvell_console_runtime_init(void); void marvell_console_runtime_end(void); /* IO storage utility functions */ void marvell_io_setup(void); /* Systimer utility function */ void marvell_configure_sys_timer(void); /* Topology utility function */ int marvell_check_mpidr(u_register_t mpidr); /* BLE utility functions */ int ble_plat_setup(int *skip); void plat_marvell_dram_update_topology(void); void ble_plat_pcie_ep_setup(void); struct pci_hw_cfg *plat_get_pcie_hw_data(void); /* BL1 utility functions */ void marvell_bl1_early_platform_setup(void); void marvell_bl1_platform_setup(void); void marvell_bl1_plat_arch_setup(void); /* BL2 utility functions */ void marvell_bl2_early_platform_setup(meminfo_t *mem_layout); void marvell_bl2_platform_setup(void); void marvell_bl2_plat_arch_setup(void); uint32_t marvell_get_spsr_for_bl32_entry(void); uint32_t marvell_get_spsr_for_bl33_entry(void); /* BL31 utility functions */ void marvell_bl31_early_platform_setup(void *from_bl2, uintptr_t soc_fw_config, uintptr_t hw_config, void *plat_params_from_bl2); void marvell_bl31_platform_setup(void); void marvell_bl31_plat_runtime_setup(void); void marvell_bl31_plat_arch_setup(void); /* Power management config to power off the SoC */ void *plat_marvell_get_pm_cfg(void); /* Check if MSS AP CM3 firmware contains PM support */ _Bool is_pm_fw_running(void); /* Bootrom image recovery utility functions */ void *plat_marvell_get_skip_image_data(void); /* FIP TOC validity check */ int marvell_io_is_toc_valid(void); /* * PSCI functionality */ void marvell_psci_arch_init(int ap_idx); void plat_marvell_system_reset(void); /* * Miscellaneous platform SMC routines */ #ifdef MVEBU_PMU_IRQ_WA void mvebu_pmu_interrupt_enable(void); void mvebu_pmu_interrupt_disable(void); #endif /* * Optional functions required in Marvell standard platforms */ void plat_marvell_io_setup(void); int plat_marvell_get_alt_image_source( unsigned int image_id, uintptr_t *dev_handle, uintptr_t *image_spec); unsigned int plat_marvell_calc_core_pos(u_register_t mpidr); const mmap_region_t *plat_marvell_get_mmap(void); void marvell_ble_prepare_exit(void); void marvell_exit_bootrom(uintptr_t base); int plat_marvell_early_cpu_powerdown(void); int bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info); #endif /* PLAT_MARVELL_H */ trusted-firmware-a-2.2/include/plat/marvell/a8k/common/plat_pm_trace.h000066400000000000000000000056241355360272700261030ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef PLAT_PM_TRACE_H #define PLAT_PM_TRACE_H /* * PM Trace is for Debug purpose only!!! * It should not be enabled during System Run time */ #undef PM_TRACE_ENABLE /* trace entry time */ struct pm_trace_entry { /* trace entry time stamp */ unsigned int timestamp; /* trace info * [16-31] - API Trace Id * [00-15] - API Step Id */ unsigned int trace_info; }; struct pm_trace_ctrl { /* trace pointer - points to next free entry in trace cyclic queue */ unsigned int trace_pointer; /* trace count - number of entries in the queue, clear upon read */ unsigned int trace_count; }; /* trace size definition */ #define AP_MSS_ATF_CORE_INFO_SIZE (256) #define AP_MSS_ATF_CORE_ENTRY_SIZE (8) #define AP_MSS_ATF_TRACE_SIZE_MASK (0xFF) /* trace address definition */ #define AP_MSS_TIMER_BASE (MVEBU_REGS_BASE_MASK + 0x580110) #define AP_MSS_ATF_CORE_0_CTRL_BASE (MVEBU_REGS_BASE_MASK + 0x520140) #define AP_MSS_ATF_CORE_1_CTRL_BASE (MVEBU_REGS_BASE_MASK + 0x520150) #define AP_MSS_ATF_CORE_2_CTRL_BASE (MVEBU_REGS_BASE_MASK + 0x520160) #define AP_MSS_ATF_CORE_3_CTRL_BASE (MVEBU_REGS_BASE_MASK + 0x520170) #define AP_MSS_ATF_CORE_CTRL_BASE (AP_MSS_ATF_CORE_0_CTRL_BASE) #define AP_MSS_ATF_CORE_0_INFO_BASE (MVEBU_REGS_BASE_MASK + 0x5201C0) #define AP_MSS_ATF_CORE_0_INFO_TRACE (MVEBU_REGS_BASE_MASK + 0x5201C4) #define AP_MSS_ATF_CORE_1_INFO_BASE (MVEBU_REGS_BASE_MASK + 0x5209C0) #define AP_MSS_ATF_CORE_1_INFO_TRACE (MVEBU_REGS_BASE_MASK + 0x5209C4) #define AP_MSS_ATF_CORE_2_INFO_BASE (MVEBU_REGS_BASE_MASK + 0x5211C0) #define AP_MSS_ATF_CORE_2_INFO_TRACE (MVEBU_REGS_BASE_MASK + 0x5211C4) #define AP_MSS_ATF_CORE_3_INFO_BASE (MVEBU_REGS_BASE_MASK + 0x5219C0) #define AP_MSS_ATF_CORE_3_INFO_TRACE (MVEBU_REGS_BASE_MASK + 0x5219C4) #define AP_MSS_ATF_CORE_INFO_BASE (AP_MSS_ATF_CORE_0_INFO_BASE) /* trace info definition */ #define TRACE_PWR_DOMAIN_OFF (0x10000) #define TRACE_PWR_DOMAIN_SUSPEND (0x20000) #define TRACE_PWR_DOMAIN_SUSPEND_FINISH (0x30000) #define TRACE_PWR_DOMAIN_ON (0x40000) #define TRACE_PWR_DOMAIN_ON_FINISH (0x50000) #define TRACE_PWR_DOMAIN_ON_MASK (0xFF) #ifdef PM_TRACE_ENABLE /* trace API definition */ void pm_core_0_trace(unsigned int trace); void pm_core_1_trace(unsigned int trace); void pm_core_2_trace(unsigned int trace); void pm_core_3_trace(unsigned int trace); typedef void (*core_trace_func)(unsigned int); extern core_trace_func funcTbl[PLATFORM_CORE_COUNT]; #define PM_TRACE(trace) funcTbl[plat_my_core_pos()](trace) #else #define PM_TRACE(trace) #endif /******************************************************************************* * pm_trace_add * * DESCRIPTION: Add PM trace ****************************************************************************** */ void pm_trace_add(unsigned int trace, unsigned int core); #endif /* PLAT_PM_TRACE_H */ trusted-firmware-a-2.2/include/plat/marvell/common/000077500000000000000000000000001355360272700224265ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/marvell/common/aarch64/000077500000000000000000000000001355360272700236565ustar00rootroot00000000000000trusted-firmware-a-2.2/include/plat/marvell/common/aarch64/cci_macros.S000066400000000000000000000022361355360272700261070ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef CCI_MACROS_S #define CCI_MACROS_S #include #include .section .rodata.cci_reg_name, "aS" cci_iface_regs: .asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , "" /* ------------------------------------------------ * The below required platform porting macro prints * out relevant interconnect registers whenever an * unhandled exception is taken in BL31. * Clobbers: x0 - x9, sp * ------------------------------------------------ */ .macro print_cci_regs adr x6, cci_iface_regs /* Store in x7 the base address of the first interface */ mov_imm x7, (PLAT_MARVELL_CCI_BASE + SLAVE_IFACE_OFFSET( \ PLAT_MARVELL_CCI_CLUSTER0_SL_IFACE_IX)) ldr w8, [x7, #SNOOP_CTRL_REG] /* Store in x7 the base address of the second interface */ mov_imm x7, (PLAT_MARVELL_CCI_BASE + SLAVE_IFACE_OFFSET( \ PLAT_MARVELL_CCI_CLUSTER1_SL_IFACE_IX)) ldr w9, [x7, #SNOOP_CTRL_REG] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print .endm #endif /* CCI_MACROS_S */ trusted-firmware-a-2.2/include/plat/marvell/common/aarch64/marvell_macros.S000066400000000000000000000066201355360272700270140ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MARVELL_MACROS_S #define MARVELL_MACROS_S #include #include #include #include #include /* * These Macros are required by ATF */ .section .rodata.gic_reg_name, "aS" /* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */ gicc_regs: .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", "" #ifdef USE_CCI /* Applicable only to GICv3 with SRE enabled */ icc_regs: .asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", "" #endif /* Registers common to both GICv2 and GICv3 */ gicd_pend_reg: .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n" \ " Offset:\t\t\tvalue\n" newline: .asciz "\n" spacer: .asciz ":\t\t0x" /* --------------------------------------------- * The below utility macro prints out relevant GIC * registers whenever an unhandled exception is * taken in BL31 on ARM standard platforms. * Expects: GICD base in x16, GICC base in x17 * Clobbers: x0 - x10, sp * --------------------------------------------- */ .macro marvell_print_gic_regs /* Check for GICv3 system register access */ mrs x7, id_aa64pfr0_el1 ubfx x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH cmp x7, #1 b.ne print_gicv2 /* Check for SRE enable */ mrs x8, ICC_SRE_EL3 tst x8, #ICC_SRE_SRE_BIT b.eq print_gicv2 #ifdef USE_CCI /* Load the icc reg list to x6 */ adr x6, icc_regs /* Load the icc regs to gp regs used by str_in_crash_buf_print */ mrs x8, ICC_HPPIR0_EL1 mrs x9, ICC_HPPIR1_EL1 mrs x10, ICC_CTLR_EL3 /* Store to the crash buf and print to console */ bl str_in_crash_buf_print #endif b print_gic_common print_gicv2: /* Load the gicc reg list to x6 */ adr x6, gicc_regs /* Load the gicc regs to gp regs used by str_in_crash_buf_print */ ldr w8, [x17, #GICC_HPPIR] ldr w9, [x17, #GICC_AHPPIR] ldr w10, [x17, #GICC_CTLR] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print print_gic_common: /* Print the GICD_ISPENDR regs */ add x7, x16, #GICD_ISPENDR adr x4, gicd_pend_reg bl asm_print_str gicd_ispendr_loop: sub x4, x7, x16 cmp x4, #0x280 b.eq exit_print_gic_regs bl asm_print_hex adr x4, spacer bl asm_print_str ldr x4, [x7], #8 bl asm_print_hex adr x4, newline bl asm_print_str b gicd_ispendr_loop exit_print_gic_regs: .endm .section .rodata.cci_reg_name, "aS" cci_iface_regs: .asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , "" /* ------------------------------------------------ * The below required platform porting macro prints * out relevant interconnect registers whenever an * unhandled exception is taken in BL31. * Clobbers: x0 - x9, sp * ------------------------------------------------ */ .macro print_cci_regs #ifdef USE_CCI adr x6, cci_iface_regs /* Store in x7 the base address of the first interface */ mov_imm x7, (PLAT_MARVELL_CCI_BASE + SLAVE_IFACE_OFFSET( \ PLAT_MARVELL_CCI_CLUSTER0_SL_IFACE_IX)) ldr w8, [x7, #SNOOP_CTRL_REG] /* Store in x7 the base address of the second interface */ mov_imm x7, (PLAT_MARVELL_CCI_BASE + SLAVE_IFACE_OFFSET( \ PLAT_MARVELL_CCI_CLUSTER1_SL_IFACE_IX)) ldr w9, [x7, #SNOOP_CTRL_REG] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print #endif .endm #endif /* MARVELL_MACROS_S */ trusted-firmware-a-2.2/include/plat/marvell/common/marvell_plat_priv.h000066400000000000000000000017331355360272700263250ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MARVELL_PLAT_PRIV_H #define MARVELL_PLAT_PRIV_H #include /***************************************************************************** * Function and variable prototypes ***************************************************************************** */ void plat_delay_timer_init(void); uint64_t mvebu_get_dram_size(uint64_t ap_base_addr); /* * GIC operation, mandatory functions required in Marvell standard platforms */ void plat_marvell_gic_driver_init(void); void plat_marvell_gic_init(void); void plat_marvell_gic_cpuif_enable(void); void plat_marvell_gic_cpuif_disable(void); void plat_marvell_gic_pcpu_init(void); void plat_marvell_gic_irq_save(void); void plat_marvell_gic_irq_restore(void); void plat_marvell_gic_irq_pcpu_save(void); void plat_marvell_gic_irq_pcpu_restore(void); #endif /* MARVELL_PLAT_PRIV_H */ trusted-firmware-a-2.2/include/plat/marvell/common/marvell_pm.h000066400000000000000000000012641355360272700247400ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MARVELL_PM_H #define MARVELL_PM_H #define MVEBU_MAILBOX_MAGIC_NUM PLAT_MARVELL_MAILBOX_MAGIC_NUM #define MVEBU_MAILBOX_SUSPEND_STATE 0xb007de7c /* Mailbox entry indexes */ /* Magic number for validity check */ #define MBOX_IDX_MAGIC 0 /* Recovery from suspend entry point */ #define MBOX_IDX_SEC_ADDR 1 /* Suspend state magic number */ #define MBOX_IDX_SUSPEND_MAGIC 2 /* Recovery jump address for ROM bypass */ #define MBOX_IDX_ROM_EXIT_ADDR 3 /* BLE execution start counter value */ #define MBOX_IDX_START_CNT 4 #endif /* MARVELL_PM_H */ trusted-firmware-a-2.2/include/plat/marvell/common/mvebu.h000066400000000000000000000023651355360272700237230ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MVEBU_H #define MVEBU_H /* Use this functions only when printf is allowed */ #define debug_enter() VERBOSE("----> Enter %s\n", __func__) #define debug_exit() VERBOSE("<---- Exit %s\n", __func__) /* Macro for testing alignment. Positive if number is NOT aligned */ #define IS_NOT_ALIGN(number, align) ((number) & ((align) - 1)) /* Macro for alignment up. For example, ALIGN_UP(0x0330, 0x20) = 0x0340 */ #define ALIGN_UP(number, align) (((number) & ((align) - 1)) ? \ (((number) + (align)) & ~((align)-1)) : (number)) /* Macro for testing whether a number is a power of 2. Positive if so */ #define IS_POWER_OF_2(number) ((number) != 0 && \ (((number) & ((number) - 1)) == 0)) /* * Macro for ronding up to next power of 2 * it is done by count leading 0 (clz assembly opcode) and see msb set bit. * then you can shift it left and get number which power of 2 * Note: this Macro is for 32 bit number */ #define ROUND_UP_TO_POW_OF_2(number) (1 << \ (32 - __builtin_clz((number) - 1))) #define _1MB_ (1024ULL * 1024ULL) #define _1GB_ (_1MB_ * 1024ULL) #define _2GB_ (2 * _1GB_) #endif /* MVEBU_H */ trusted-firmware-a-2.2/include/services/000077500000000000000000000000001355360272700203575ustar00rootroot00000000000000trusted-firmware-a-2.2/include/services/arm_arch_svc.h000066400000000000000000000006361355360272700231640ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ARM_ARCH_SVC_H #define ARM_ARCH_SVC_H #define SMCCC_VERSION U(0x80000000) #define SMCCC_ARCH_FEATURES U(0x80000001) #define SMCCC_ARCH_WORKAROUND_1 U(0x80008000) #define SMCCC_ARCH_WORKAROUND_2 U(0x80007FFF) #define SMCCC_ARCH_NOT_REQUIRED -2 #endif /* ARM_ARCH_SVC_H */ trusted-firmware-a-2.2/include/services/mm_svc.h000066400000000000000000000016521355360272700220200ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MM_SVC_H #define MM_SVC_H #if SPM_MM #include #define MM_VERSION_MAJOR U(1) #define MM_VERSION_MAJOR_SHIFT 16 #define MM_VERSION_MAJOR_MASK U(0x7FFF) #define MM_VERSION_MINOR U(0) #define MM_VERSION_MINOR_SHIFT 0 #define MM_VERSION_MINOR_MASK U(0xFFFF) #define MM_VERSION_FORM(major, minor) ((major << MM_VERSION_MAJOR_SHIFT) | (minor)) #define MM_VERSION_COMPILED MM_VERSION_FORM(MM_VERSION_MAJOR, MM_VERSION_MINOR) /* * SMC IDs defined in [1] for accessing MM services from the Non-secure world. * These FIDs occupy the range 0x40 - 0x5f. * [1] DEN0060A_ARM_MM_Interface_Specification.pdf */ #define MM_VERSION_AARCH32 U(0x84000040) #define MM_COMMUNICATE_AARCH64 U(0xC4000041) #define MM_COMMUNICATE_AARCH32 U(0x84000041) #endif /* SPM_MM */ #endif /* MM_SVC_H */ trusted-firmware-a-2.2/include/services/sdei.h000066400000000000000000000130721355360272700214570ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SDEI_H #define SDEI_H #include #include /* Range 0xC4000020 - 0xC400003F reserved for SDE 64bit smc calls */ #define SDEI_VERSION 0xC4000020U #define SDEI_EVENT_REGISTER 0xC4000021U #define SDEI_EVENT_ENABLE 0xC4000022U #define SDEI_EVENT_DISABLE 0xC4000023U #define SDEI_EVENT_CONTEXT 0xC4000024U #define SDEI_EVENT_COMPLETE 0xC4000025U #define SDEI_EVENT_COMPLETE_AND_RESUME 0xC4000026U #define SDEI_EVENT_UNREGISTER 0xC4000027U #define SDEI_EVENT_STATUS 0xC4000028U #define SDEI_EVENT_GET_INFO 0xC4000029U #define SDEI_EVENT_ROUTING_SET 0xC400002AU #define SDEI_PE_MASK 0xC400002BU #define SDEI_PE_UNMASK 0xC400002CU #define SDEI_INTERRUPT_BIND 0xC400002DU #define SDEI_INTERRUPT_RELEASE 0xC400002EU #define SDEI_EVENT_SIGNAL 0xC400002FU #define SDEI_FEATURES 0xC4000030U #define SDEI_PRIVATE_RESET 0xC4000031U #define SDEI_SHARED_RESET 0xC4000032U /* SDEI_EVENT_REGISTER flags */ #define SDEI_REGF_RM_ANY 0ULL #define SDEI_REGF_RM_PE 1ULL /* SDEI_EVENT_COMPLETE status flags */ #define SDEI_EV_HANDLED 0U #define SDEI_EV_FAILED 1U /* Internal: SDEI flag bit positions */ #define SDEI_MAPF_DYNAMIC_SHIFT_ 1U #define SDEI_MAPF_BOUND_SHIFT_ 2U #define SDEI_MAPF_SIGNALABLE_SHIFT_ 3U #define SDEI_MAPF_PRIVATE_SHIFT_ 4U #define SDEI_MAPF_CRITICAL_SHIFT_ 5U #define SDEI_MAPF_EXPLICIT_SHIFT_ 6U /* SDEI event 0 */ #define SDEI_EVENT_0 0 /* Placeholder interrupt for dynamic mapping */ #define SDEI_DYN_IRQ 0U /* SDEI flags */ /* * These flags determine whether or not an event can be associated with an * interrupt. Static events are permanently associated with an interrupt, and * can't be changed at runtime. Association of dynamic events with interrupts * can be changed at run time using the SDEI_INTERRUPT_BIND and * SDEI_INTERRUPT_RELEASE calls. * * SDEI_MAPF_DYNAMIC only indicates run time configurability, where as * SDEI_MAPF_BOUND indicates interrupt association. For example: * * - Calling SDEI_INTERRUPT_BIND on a dynamic event will have both * SDEI_MAPF_DYNAMIC and SDEI_MAPF_BOUND set. * * - Statically-bound events will always have SDEI_MAPF_BOUND set, and neither * SDEI_INTERRUPT_BIND nor SDEI_INTERRUPT_RELEASE can be called on them. * * See also the is_map_bound() macro. */ #define SDEI_MAPF_DYNAMIC BIT(SDEI_MAPF_DYNAMIC_SHIFT_) #define SDEI_MAPF_BOUND BIT(SDEI_MAPF_BOUND_SHIFT_) #define SDEI_MAPF_EXPLICIT BIT(SDEI_MAPF_EXPLICIT_SHIFT_) #define SDEI_MAPF_SIGNALABLE BIT(SDEI_MAPF_SIGNALABLE_SHIFT_) #define SDEI_MAPF_PRIVATE BIT(SDEI_MAPF_PRIVATE_SHIFT_) #define SDEI_MAPF_NORMAL 0 #define SDEI_MAPF_CRITICAL BIT(SDEI_MAPF_CRITICAL_SHIFT_) /* Indices of private and shared mappings */ #define SDEI_MAP_IDX_PRIV_ 0U #define SDEI_MAP_IDX_SHRD_ 1U #define SDEI_MAP_IDX_MAX_ 2U /* The macros below are used to identify SDEI calls from the SMC function ID */ #define SDEI_FID_MASK U(0xffe0) #define SDEI_FID_VALUE U(0x20) #define is_sdei_fid(_fid) \ ((((_fid) & SDEI_FID_MASK) == SDEI_FID_VALUE) && \ (((_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_64)) #define SDEI_EVENT_MAP(_event, _intr, _flags) \ { \ .ev_num = (_event), \ .intr = (_intr), \ .map_flags = (_flags) \ } #define SDEI_SHARED_EVENT(_event, _intr, _flags) \ SDEI_EVENT_MAP(_event, _intr, _flags) #define SDEI_PRIVATE_EVENT(_event, _intr, _flags) \ SDEI_EVENT_MAP(_event, _intr, (_flags) | SDEI_MAPF_PRIVATE) #define SDEI_DEFINE_EVENT_0(_intr) \ SDEI_PRIVATE_EVENT(SDEI_EVENT_0, (_intr), SDEI_MAPF_SIGNALABLE) #define SDEI_EXPLICIT_EVENT(_event, _pri) \ SDEI_EVENT_MAP((_event), 0, (_pri) | SDEI_MAPF_EXPLICIT | SDEI_MAPF_PRIVATE) /* * Declare shared and private entries for each core. Also declare a global * structure containing private and share entries. * * This macro must be used in the same file as the platform SDEI mappings are * declared. Only then would ARRAY_SIZE() yield a meaningful value. */ #define REGISTER_SDEI_MAP(_private, _shared) \ sdei_entry_t sdei_private_event_table \ [PLATFORM_CORE_COUNT * ARRAY_SIZE(_private)]; \ sdei_entry_t sdei_shared_event_table[ARRAY_SIZE(_shared)]; \ const sdei_mapping_t sdei_global_mappings[] = { \ [SDEI_MAP_IDX_PRIV_] = { \ .map = (_private), \ .num_maps = ARRAY_SIZE(_private) \ }, \ [SDEI_MAP_IDX_SHRD_] = { \ .map = (_shared), \ .num_maps = ARRAY_SIZE(_shared) \ }, \ } typedef uint8_t sdei_state_t; /* Runtime data of SDEI event */ typedef struct sdei_entry { uint64_t ep; /* Entry point */ uint64_t arg; /* Entry point argument */ uint64_t affinity; /* Affinity of shared event */ unsigned int reg_flags; /* Registration flags */ /* Event handler states: registered, enabled, running */ sdei_state_t state; } sdei_entry_t; /* Mapping of SDEI events to interrupts, and associated data */ typedef struct sdei_ev_map { int32_t ev_num; /* Event number */ unsigned int intr; /* Physical interrupt number for a bound map */ unsigned int map_flags; /* Mapping flags, see SDEI_MAPF_* */ int reg_count; /* Registration count */ spinlock_t lock; /* Per-event lock */ } sdei_ev_map_t; typedef struct sdei_mapping { sdei_ev_map_t *map; size_t num_maps; } sdei_mapping_t; /* Handler to be called to handle SDEI smc calls */ uint64_t sdei_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, void *cookie, void *handle, uint64_t flags); void sdei_init(void); /* Public API to dispatch an event to Normal world */ int sdei_dispatch_event(int ev_num); #endif /* SDEI_H */ trusted-firmware-a-2.2/include/services/secure_partition.h000066400000000000000000000024051355360272700241100ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SECURE_PARTITION_H #define SECURE_PARTITION_H #if SPM_MM #include #include /* * Flags used by the secure_partition_mp_info structure to describe the * characteristics of a cpu. Only a single flag is defined at the moment to * indicate the primary cpu. */ #define MP_INFO_FLAG_PRIMARY_CPU U(0x00000001) /* * This structure is used to provide information required to initialise a S-EL0 * partition. */ typedef struct secure_partition_mp_info { uint64_t mpidr; uint32_t linear_id; uint32_t flags; } secure_partition_mp_info_t; typedef struct secure_partition_boot_info { param_header_t h; uint64_t sp_mem_base; uint64_t sp_mem_limit; uint64_t sp_image_base; uint64_t sp_stack_base; uint64_t sp_heap_base; uint64_t sp_ns_comm_buf_base; uint64_t sp_shared_buf_base; uint64_t sp_image_size; uint64_t sp_pcpu_stack_size; uint64_t sp_heap_size; uint64_t sp_ns_comm_buf_size; uint64_t sp_shared_buf_size; uint32_t num_sp_mem_regions; uint32_t num_cpus; secure_partition_mp_info_t *mp_info; } secure_partition_boot_info_t; #endif /* SPM_MM */ #endif /* SECURE_PARTITION_H */ trusted-firmware-a-2.2/include/services/sp_res_desc.h000066400000000000000000000132671355360272700230320ustar00rootroot00000000000000/* * Copyright (c) 2018, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPM_RES_DESC_H #define SPM_RES_DESC_H #include #include /******************************************************************************* * Attribute Section ******************************************************************************/ struct sp_rd_sect_attribute { /* * Version of the resource description. */ uint16_t version; /* * Type of the Secure Partition: * - bit[0]: SP Type * - b'0: UP SP * - b'1: MP SP * If UP SP: * - bit[1]: Type of UP SP * - b'0: Migratable UP SP * - b'1: Pinned UP SP */ uint16_t sp_type; /* * If this is a Pinned UP SP, PE on which the Pinned UP SP will run. */ uint32_t pe_mpidr; /* * Run-Time Exception Level: * - 0: SEL0 SP * - 1: SEL1 SP */ uint8_t runtime_el; /* * Type of Execution: * - 0: Init-time only * - 1: Run-time Execution */ uint8_t exec_type; /* * Expected behavior upon failure: * - 0: Restartable * - 1: One-Shot */ uint8_t panic_policy; /* * Translation Granule to use in the SP translation regime: * - 0: 4KB * - 1: 16KB * - 2: 64KB */ uint8_t xlat_granule; /* * Size of the SP binary in bytes. */ uint32_t binary_size; /* * - If SP is NOT PIE: * - VA Address where the SP expects to be loaded. * - If SP is PIE: * - Ignored. */ uint64_t load_address; /* * Initial execution address. This is a VA as the SP sees it. */ uint64_t entrypoint; }; /******************************************************************************* * Memory Region Section ******************************************************************************/ struct sp_rd_sect_mem_region { /* * Name of a Memory region, including null terminator. Reserved names: * - "Client Shared Memory Region": * Memory region where memory shared by clients shall be mapped. * - "Queue Memory Region": * Memory region shared with SPM for SP queue management. */ char name[RD_MEM_REGION_NAME_LEN]; /* * Memory Attributes: * - bits[3:0]: Type of memory * - 0: Device * - 1: Code * - 2: Data * - 3: BSS * - 4: Read-only Data * - 5: SPM-to-SP Shared Memory Region * - 6: Client Shared Memory Region * - 7: Miscellaneous * - If memory is { SPM-to-SP shared Memory, Client Shared Memory, * Miscellaneous } * - bits[4]: Position Independent * - b'0: Position Dependent * - b'1: Position Independent */ uint32_t attr; /* * Base address of the memory region. */ uint64_t base; /* * Size of the memory region. */ uint64_t size; /* * Pointer to next memory region (or NULL if this is the last one). */ struct sp_rd_sect_mem_region *next; }; /******************************************************************************* * Notification Section ******************************************************************************/ struct sp_rd_sect_notification { /* * Notification attributes: * - bit[31]: Notification Type * - b'0: Platform Notification * - b'1: Interrupt * If Notification Type == Platform Notification * - bits[15:0]: Implementation-defined Notification ID * If Notification Type == Interrupt * - bits[15:0]: IRQ number * - bits[23:16]: Interrupt Priority * - bit[24]: Trigger Type * - b'0: Edge Triggered * - b'1: Level Triggered * - bit[25]: Trigger Level * - b'0: Falling or Low * - b'1: Rising or High */ uint32_t attr; /* * Processing Element. * If Notification Type == Interrupt && IRQ number is { SGI, LPI } * - PE ID to which IRQ will be forwarded */ uint32_t pe; /* * Pointer to next notification (or NULL if this is the last one). */ struct sp_rd_sect_notification *next; }; /******************************************************************************* * Service Description Section ******************************************************************************/ struct sp_rd_sect_service { /* * Service identifier. */ uint32_t uuid[4]; /* * Accessibility Options: * - bit[0]: Accessibility by secure-world clients * - b'0: Not Accessible * - b'1: Accessible * - bit[1]: Accessible by EL3 * - b'0: Not Accessible * - b'1: Accessible * - bit[2]: Accessible by normal-world clients * - b'0: Not Accessible * - b'1: Accessible */ uint8_t accessibility; /* * Request type supported: * - bit[0]: Blocking request * - b'0: Not Enable * - b'1: Enable * - bit[1]: Non-blocking request * - b'0: Not Enable * - b'1: Enable */ uint8_t request_type; /* * Maximum number of client connections that the service can support. */ uint16_t connection_quota; /* * If the service requires secure world memory to be shared with its * clients: * - Maximum amount of secure world memory in bytes to reserve from the * secure world memory pool for the service. */ uint32_t secure_mem_size; /* * Interrupt number used to notify the SP for the service. * - Should also be enabled in the Notification Section. */ uint32_t interrupt_num; /* * Pointer to next service (or NULL if this is the last one). */ struct sp_rd_sect_service *next; }; /******************************************************************************* * Complete resource description struct ******************************************************************************/ struct sp_res_desc { /* Attribute Section */ struct sp_rd_sect_attribute attribute; /* System Resource Section */ struct sp_rd_sect_mem_region *mem_region; struct sp_rd_sect_notification *notification; /* Service Section */ struct sp_rd_sect_service *service; }; #endif /* SPM_RES_DESC_H */ trusted-firmware-a-2.2/include/services/sp_res_desc_def.h000066400000000000000000000055751355360272700236530ustar00rootroot00000000000000/* * Copyright (c) 2018, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPM_RES_DESC_DEFS_H #define SPM_RES_DESC_DEFS_H #include /******************************************************************************* * Attribute Section ******************************************************************************/ #define RD_ATTR_TYPE_UP_MIGRATABLE U(0) #define RD_ATTR_TYPE_UP_PINNED U(2) #define RD_ATTR_TYPE_MP U(1) #define RD_ATTR_RUNTIME_SEL0 U(0) #define RD_ATTR_RUNTIME_SEL1 U(1) #define RD_ATTR_INIT_ONLY U(0) #define RD_ATTR_RUNTIME U(1) #define RD_ATTR_PANIC_RESTART U(0) #define RD_ATTR_PANIC_ONESHOT U(1) #define RD_ATTR_XLAT_GRANULE_4KB U(0) #define RD_ATTR_XLAT_GRANULE_16KB U(1) #define RD_ATTR_XLAT_GRANULE_64KB U(2) /******************************************************************************* * Memory Region Section ******************************************************************************/ #define RD_MEM_REGION_NAME_LEN U(32) #define RD_MEM_DEVICE U(0) #define RD_MEM_NORMAL_CODE U(1) #define RD_MEM_NORMAL_DATA U(2) #define RD_MEM_NORMAL_BSS U(3) #define RD_MEM_NORMAL_RODATA U(4) #define RD_MEM_NORMAL_SPM_SP_SHARED_MEM U(5) #define RD_MEM_NORMAL_CLIENT_SHARED_MEM U(6) #define RD_MEM_NORMAL_MISCELLANEOUS U(7) #define RD_MEM_MASK U(15) #define RD_MEM_IS_PIE (U(1) << 4) /******************************************************************************* * Notification Section ******************************************************************************/ #define RD_NOTIF_TYPE_PLATFORM (U(0) << 31) #define RD_NOTIF_TYPE_INTERRUPT (U(1) << 31) #define RD_NOTIF_PLAT_ID_MASK U(0xFFFF) #define RD_NOTIF_PLAT_ID_SHIFT U(0) #define RD_NOTIF_PLATFORM(id) \ (RD_NOTIF_TYPE_PLATFORM \ | (((id) & RD_NOTIF_PLAT_ID_MASK) << RD_NOTIF_PLAT_ID_SHIFT)) #define RD_NOTIF_IRQ_NUM_MASK U(0xFFFF) #define RD_NOTIF_IRQ_NUM_SHIFT U(0) #define RD_NOTIF_IRQ_PRIO_MASK U(0xFF) #define RD_NOTIF_IRQ_PRIO_SHIFT U(16) #define RD_NOTIF_IRQ_EDGE_FALLING U(0) #define RD_NOTIF_IRQ_EDGE_RISING U(2) #define RD_NOTIF_IRQ_LEVEL_LOW U(1) #define RD_NOTIF_IRQ_LEVEL_HIGH U(3) #define RD_NOTIF_IRQ_TRIGGER_SHIFT U(24) #define RD_NOTIF_IRQ(num, prio, trig) \ (RD_NOTIF_TYPE_IRQ \ | (((num) & RD_NOTIF_IRQ_NUM_MASK) << RD_NOTIF_IRQ_NUM_SHIFT) \ | (((prio) & RD_NOTIF_IRQ_PRIO_MASK) << RD_NOTIF_IRQ_PRIO_SHIFT) \ | (((trig) << RD_NOTIF_IRQ_TRIGGER_SHIFT))) /******************************************************************************* * Service Description Section ******************************************************************************/ #define RD_SERV_ACCESS_SECURE (U(1) << 0) #define RD_SERV_ACCESS_EL3 (U(1) << 1) #define RD_SERV_ACCESS_NORMAL (U(1) << 2) #define RD_SERV_SUPPORT_BLOCKING (U(1) << 0) #define RD_SERV_SUPPORT_NON_BLOCKING (U(1) << 0) #endif /* SPM_RES_DESC_DEFS_H */ trusted-firmware-a-2.2/include/services/spci_svc.h000066400000000000000000000113001355360272700223340ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPCI_SVC_H #define SPCI_SVC_H #include #include /* SPCI_VERSION helpers */ #define SPCI_VERSION_MAJOR U(0) #define SPCI_VERSION_MAJOR_SHIFT 16 #define SPCI_VERSION_MAJOR_MASK U(0x7FFF) #define SPCI_VERSION_MINOR U(1) #define SPCI_VERSION_MINOR_SHIFT 0 #define SPCI_VERSION_MINOR_MASK U(0xFFFF) #define SPCI_VERSION_FORM(major, minor) ((((major) & SPCI_VERSION_MAJOR_MASK) \ << SPCI_VERSION_MAJOR_SHIFT) | \ ((minor) & SPCI_VERSION_MINOR_MASK)) #define SPCI_VERSION_COMPILED SPCI_VERSION_FORM(SPCI_VERSION_MAJOR, \ SPCI_VERSION_MINOR) /* Definitions to build the complete SMC ID */ #define SPCI_FID_MISC_FLAG (U(0) << 27) #define SPCI_FID_MISC_SHIFT U(20) #define SPCI_FID_MISC_MASK U(0x7F) #define SPCI_FID_TUN_FLAG (U(1) << 27) #define SPCI_FID_TUN_SHIFT U(24) #define SPCI_FID_TUN_MASK U(0x7) #define OEN_SPCI_START U(0x30) #define OEN_SPCI_END U(0x3F) #define SPCI_SMC(spci_fid) ((OEN_SPCI_START << FUNCID_OEN_SHIFT) | \ (U(1) << 31) | (spci_fid)) #define SPCI_MISC_32(misc_fid) ((SMC_32 << FUNCID_CC_SHIFT) | \ SPCI_FID_MISC_FLAG | \ SPCI_SMC((misc_fid) << SPCI_FID_MISC_SHIFT)) #define SPCI_MISC_64(misc_fid) ((SMC_64 << FUNCID_CC_SHIFT) | \ SPCI_FID_MISC_FLAG | \ SPCI_SMC((misc_fid) << SPCI_FID_MISC_SHIFT)) #define SPCI_TUN_32(tun_fid) ((SMC_32 << FUNCID_CC_SHIFT) | \ SPCI_FID_TUN_FLAG | \ SPCI_SMC((tun_fid) << SPCI_FID_TUN_SHIFT)) #define SPCI_TUN_64(tun_fid) ((SMC_64 << FUNCID_CC_SHIFT) | \ SPCI_FID_TUN_FLAG | \ SPCI_SMC((tun_fid) << SPCI_FID_TUN_SHIFT)) /* SPCI miscellaneous functions */ #define SPCI_FID_VERSION U(0x0) #define SPCI_FID_SERVICE_HANDLE_OPEN U(0x2) #define SPCI_FID_SERVICE_HANDLE_CLOSE U(0x3) #define SPCI_FID_SERVICE_MEM_REGISTER U(0x4) #define SPCI_FID_SERVICE_MEM_UNREGISTER U(0x5) #define SPCI_FID_SERVICE_MEM_PUBLISH U(0x6) #define SPCI_FID_SERVICE_REQUEST_BLOCKING U(0x7) #define SPCI_FID_SERVICE_REQUEST_START U(0x8) #define SPCI_FID_SERVICE_GET_RESPONSE U(0x9) #define SPCI_FID_SERVICE_RESET_CLIENT_STATE U(0xA) /* SPCI tunneling functions */ #define SPCI_FID_SERVICE_TUN_REQUEST_START U(0x0) #define SPCI_FID_SERVICE_REQUEST_RESUME U(0x1) #define SPCI_FID_SERVICE_TUN_REQUEST_BLOCKING U(0x2) /* Complete SMC IDs and associated values */ #define SPCI_VERSION SPCI_MISC_32(SPCI_FID_VERSION) #define SPCI_SERVICE_HANDLE_OPEN SPCI_MISC_32(SPCI_FID_SERVICE_HANDLE_OPEN) #define SPCI_SERVICE_HANDLE_OPEN_NOTIFY_BIT U(1) #define SPCI_SERVICE_HANDLE_CLOSE SPCI_MISC_32(SPCI_FID_SERVICE_HANDLE_CLOSE) #define SPCI_SERVICE_MEM_REGISTER_AARCH32 SPCI_MISC_32(SPCI_FID_SERVICE_MEM_REGISTER) #define SPCI_SERVICE_MEM_REGISTER_AARCH64 SPCI_MISC_64(SPCI_FID_SERVICE_MEM_REGISTER) #define SPCI_SERVICE_MEM_UNREGISTER_AARCH32 SPCI_MISC_32(SPCI_FID_SERVICE_MEM_UNREGISTER) #define SPCI_SERVICE_MEM_UNREGISTER_AARCH64 SPCI_MISC_64(SPCI_FID_SERVICE_MEM_UNREGISTER) #define SPCI_SERVICE_MEM_PUBLISH_AARCH32 SPCI_MISC_32(SPCI_FID_SERVICE_MEM_PUBLISH) #define SPCI_SERVICE_MEM_PUBLISH_AARCH64 SPCI_MISC_64(SPCI_FID_SERVICE_MEM_PUBLISH) #define SPCI_SERVICE_REQUEST_BLOCKING_AARCH32 SPCI_MISC_32(SPCI_FID_SERVICE_REQUEST_BLOCKING) #define SPCI_SERVICE_REQUEST_BLOCKING_AARCH64 SPCI_MISC_64(SPCI_FID_SERVICE_REQUEST_BLOCKING) #define SPCI_SERVICE_REQUEST_START_AARCH32 SPCI_MISC_32(SPCI_FID_SERVICE_REQUEST_START) #define SPCI_SERVICE_REQUEST_START_AARCH64 SPCI_MISC_64(SPCI_FID_SERVICE_REQUEST_START) #define SPCI_SERVICE_GET_RESPONSE_AARCH32 SPCI_MISC_32(SPCI_FID_SERVICE_GET_RESPONSE) #define SPCI_SERVICE_GET_RESPONSE_AARCH64 SPCI_MISC_64(SPCI_FID_SERVICE_GET_RESPONSE) #define SPCI_SERVICE_RESET_CLIENT_STATE_AARCH32 SPCI_MISC_32(SPCI_FID_SERVICE_RESET_CLIENT_STATE) #define SPCI_SERVICE_RESET_CLIENT_STATE_AARCH64 SPCI_MISC_64(SPCI_FID_SERVICE_RESET_CLIENT_STATE) #define SPCI_SERVICE_TUN_REQUEST_START_AARCH32 SPCI_TUN_32(SPCI_FID_SERVICE_TUN_REQUEST_START) #define SPCI_SERVICE_TUN_REQUEST_START_AARCH64 SPCI_TUN_64(SPCI_FID_SERVICE_TUN_REQUEST_START) #define SPCI_SERVICE_REQUEST_RESUME_AARCH32 SPCI_TUN_32(SPCI_FID_SERVICE_REQUEST_RESUME) #define SPCI_SERVICE_REQUEST_RESUME_AARCH64 SPCI_TUN_64(SPCI_FID_SERVICE_REQUEST_RESUME) #define SPCI_SERVICE_TUN_REQUEST_BLOCKING_AARCH32 SPCI_TUN_32(SPCI_FID_SERVICE_TUN_REQUEST_BLOCKING) #define SPCI_SERVICE_TUN_REQUEST_BLOCKING_AARCH64 SPCI_TUN_64(SPCI_FID_SERVICE_TUN_REQUEST_BLOCKING) /* SPCI error codes. */ #define SPCI_SUCCESS 0 #define SPCI_NOT_SUPPORTED -1 #define SPCI_INVALID_PARAMETER -2 #define SPCI_NO_MEMORY -3 #define SPCI_BUSY -4 #define SPCI_QUEUED -5 #define SPCI_DENIED -6 #define SPCI_NOT_PRESENT -7 #endif /* SPCI_SVC_H */ trusted-firmware-a-2.2/include/services/spm_svc.h000066400000000000000000000046071355360272700222110ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPM_SVC_H #define SPM_SVC_H #if SPM_MM #include #define SPM_VERSION_MAJOR U(0) #define SPM_VERSION_MAJOR_SHIFT 16 #define SPM_VERSION_MAJOR_MASK U(0x7FFF) #define SPM_VERSION_MINOR U(1) #define SPM_VERSION_MINOR_SHIFT 0 #define SPM_VERSION_MINOR_MASK U(0xFFFF) #define SPM_VERSION_FORM(major, minor) ((major << SPM_VERSION_MAJOR_SHIFT) | (minor)) #define SPM_VERSION_COMPILED SPM_VERSION_FORM(SPM_VERSION_MAJOR, SPM_VERSION_MINOR) /* The macros below are used to identify SPM calls from the SMC function ID */ #define SPM_FID_MASK U(0xffff) #define SPM_FID_MIN_VALUE U(0x40) #define SPM_FID_MAX_VALUE U(0x7f) #define is_spm_fid(_fid) \ ((((_fid) & SPM_FID_MASK) >= SPM_FID_MIN_VALUE) && \ (((_fid) & SPM_FID_MASK) <= SPM_FID_MAX_VALUE)) /* * SMC IDs defined for accessing services implemented by the Secure Partition * Manager from the Secure Partition(s). These services enable a partition to * handle delegated events and request privileged operations from the manager. * They occupy the range 0x60-0x7f. */ #define SPM_VERSION_AARCH32 U(0x84000060) #define SP_EVENT_COMPLETE_AARCH64 U(0xC4000061) #define SP_MEMORY_ATTRIBUTES_GET_AARCH64 U(0xC4000064) #define SP_MEMORY_ATTRIBUTES_SET_AARCH64 U(0xC4000065) /* * Macros used by SP_MEMORY_ATTRIBUTES_SET_AARCH64. */ #define SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS U(0) #define SP_MEMORY_ATTRIBUTES_ACCESS_RW U(1) /* Value U(2) is reserved. */ #define SP_MEMORY_ATTRIBUTES_ACCESS_RO U(3) #define SP_MEMORY_ATTRIBUTES_ACCESS_MASK U(3) #define SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT 0 #define SP_MEMORY_ATTRIBUTES_EXEC (U(0) << 2) #define SP_MEMORY_ATTRIBUTES_NON_EXEC (U(1) << 2) /* SPM error codes. */ #define SPM_SUCCESS 0 #define SPM_NOT_SUPPORTED -1 #define SPM_INVALID_PARAMETER -2 #define SPM_DENIED -3 #define SPM_NO_MEMORY -5 #endif /* SPM_MM */ #ifndef __ASSEMBLER__ #include int32_t spm_setup(void); #if SPM_MM uint64_t spm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, void *cookie, void *handle, uint64_t flags); /* Helper to enter a Secure Partition */ uint64_t spm_sp_call(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3); #endif /* SPM_MM */ #endif /* __ASSEMBLER__ */ #endif /* SPM_SVC_H */ trusted-firmware-a-2.2/include/services/sprt_svc.h000066400000000000000000000043621355360272700224000ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPRT_SVC_H #define SPRT_SVC_H #include #include /* SPRT_VERSION helpers */ #define SPRT_VERSION_MAJOR U(0) #define SPRT_VERSION_MAJOR_SHIFT 16 #define SPRT_VERSION_MAJOR_MASK U(0x7FFF) #define SPRT_VERSION_MINOR U(1) #define SPRT_VERSION_MINOR_SHIFT 0 #define SPRT_VERSION_MINOR_MASK U(0xFFFF) #define SPRT_VERSION_FORM(major, minor) ((((major) & SPRT_VERSION_MAJOR_MASK) \ << SPRT_VERSION_MAJOR_SHIFT) | \ ((minor) & SPRT_VERSION_MINOR_MASK)) #define SPRT_VERSION_COMPILED SPRT_VERSION_FORM(SPRT_VERSION_MAJOR, \ SPRT_VERSION_MINOR) /* SPRT function IDs */ #define SPRT_FID_VERSION U(0x0) #define SPRT_FID_PUT_RESPONSE U(0x1) #define SPRT_FID_YIELD U(0x5) #define SPRT_FID_PANIC U(0x7) #define SPRT_FID_MEMORY_PERM_ATTR_GET U(0xB) #define SPRT_FID_MEMORY_PERM_ATTR_SET U(0xC) #define SPRT_FID_MASK U(0xFF) /* Definitions to build the complete SMC ID */ #define OEN_SPRT_START U(0x20) #define OEN_SPRT_END U(0x2F) #define SPRT_SMC_64(sprt_fid) ((OEN_SPRT_START << FUNCID_OEN_SHIFT) | \ (U(1) << 31) | ((sprt_fid) & SPRT_FID_MASK) | \ (SMC_64 << FUNCID_CC_SHIFT)) #define SPRT_SMC_32(sprt_fid) ((OEN_SPRT_START << FUNCID_OEN_SHIFT) | \ (U(1) << 31) | ((sprt_fid) & SPRT_FID_MASK) | \ (SMC_32 << FUNCID_CC_SHIFT)) /* Complete SMC IDs */ #define SPRT_VERSION SPRT_SMC_32(SPRT_FID_VERSION) #define SPRT_PUT_RESPONSE_AARCH64 SPRT_SMC_64(SPRT_FID_PUT_RESPONSE) #define SPRT_YIELD_AARCH64 SPRT_SMC_64(SPRT_FID_YIELD) #define SPRT_PANIC_AARCH64 SPRT_SMC_64(SPRT_FID_PANIC) #define SPRT_MEMORY_PERM_ATTR_GET_AARCH64 SPRT_SMC_64(SPRT_FID_MEMORY_PERM_ATTR_GET) #define SPRT_MEMORY_PERM_ATTR_SET_AARCH64 SPRT_SMC_64(SPRT_FID_MEMORY_PERM_ATTR_SET) /* Defines used by SPRT_MEMORY_PERM_ATTR_{GET,SET}_AARCH64 */ #define SPRT_MEMORY_PERM_ATTR_RO U(0) #define SPRT_MEMORY_PERM_ATTR_RW U(1) #define SPRT_MEMORY_PERM_ATTR_RO_EXEC U(2) /* U(3) is reserved */ #define SPRT_MEMORY_PERM_ATTR_MASK U(3) #define SPRT_MEMORY_PERM_ATTR_SHIFT 3 /* SPRT error codes. */ #define SPRT_SUCCESS 0 #define SPRT_NOT_SUPPORTED -1 #define SPRT_INVALID_PARAMETER -2 #endif /* SPRT_SVC_H */ trusted-firmware-a-2.2/include/services/std_svc.h000066400000000000000000000015051355360272700221760ustar00rootroot00000000000000/* * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STD_SVC_H #define STD_SVC_H /* SMC function IDs for Standard Service queries */ #define ARM_STD_SVC_CALL_COUNT 0x8400ff00 #define ARM_STD_SVC_UID 0x8400ff01 /* 0x8400ff02 is reserved */ #define ARM_STD_SVC_VERSION 0x8400ff03 /* ARM Standard Service Calls version numbers */ #define STD_SVC_VERSION_MAJOR 0x0 #define STD_SVC_VERSION_MINOR 0x1 /* * Get the ARM Standard Service argument from EL3 Runtime. * This function must be implemented by EL3 Runtime and the * `svc_mask` identifies the service. `svc_mask` is a bit * mask identifying the range of SMC function IDs available * to the service. */ uintptr_t get_arm_std_svc_args(unsigned int svc_mask); #endif /* STD_SVC_H */ trusted-firmware-a-2.2/include/tools_share/000077500000000000000000000000001355360272700210565ustar00rootroot00000000000000trusted-firmware-a-2.2/include/tools_share/firmware_image_package.h000066400000000000000000000112111355360272700256540ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef FIRMWARE_IMAGE_PACKAGE_H #define FIRMWARE_IMAGE_PACKAGE_H #include #include "uuid.h" /* This is used as a signature to validate the blob header */ #define TOC_HEADER_NAME 0xAA640001 /* ToC Entry UUIDs */ #define UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U \ {{0x65, 0x92, 0x27, 0x03}, {0x2f, 0x74}, {0xe6, 0x44}, 0x8d, 0xff, {0x57, 0x9a, 0xc1, 0xff, 0x06, 0x10} } #define UUID_TRUSTED_UPDATE_FIRMWARE_BL2U \ {{0x60, 0xb3, 0xeb, 0x37}, {0xc1, 0xe5}, {0xea, 0x41}, 0x9d, 0xf3, {0x19, 0xed, 0xa1, 0x1f, 0x68, 0x01} } #define UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U \ {{0x4f, 0x51, 0x1d, 0x11}, {0x2b, 0xe5}, {0x4e, 0x49}, 0xb4, 0xc5, {0x83, 0xc2, 0xf7, 0x15, 0x84, 0x0a} } #define UUID_TRUSTED_FWU_CERT \ {{0x71, 0x40, 0x8a, 0xb2}, {0x18, 0xd6}, {0x87, 0x4c}, 0x8b, 0x2e, {0xc6, 0xdc, 0xcd, 0x50, 0xf0, 0x96} } #define UUID_TRUSTED_BOOT_FIRMWARE_BL2 \ {{0x5f, 0xf9, 0xec, 0x0b}, {0x4d, 0x22}, {0x3e, 0x4d}, 0xa5, 0x44, {0xc3, 0x9d, 0x81, 0xc7, 0x3f, 0x0a} } #define UUID_SCP_FIRMWARE_SCP_BL2 \ {{0x97, 0x66, 0xfd, 0x3d}, {0x89, 0xbe}, {0xe8, 0x49}, 0xae, 0x5d, {0x78, 0xa1, 0x40, 0x60, 0x82, 0x13} } #define UUID_EL3_RUNTIME_FIRMWARE_BL31 \ {{0x47, 0xd4, 0x08, 0x6d}, {0x4c, 0xfe}, {0x98, 0x46}, 0x9b, 0x95, {0x29, 0x50, 0xcb, 0xbd, 0x5a, 0x00} } #define UUID_SECURE_PAYLOAD_BL32 \ {{0x05, 0xd0, 0xe1, 0x89}, {0x53, 0xdc}, {0x13, 0x47}, 0x8d, 0x2b, {0x50, 0x0a, 0x4b, 0x7a, 0x3e, 0x38} } #define UUID_SECURE_PAYLOAD_BL32_EXTRA1 \ {{0x0b, 0x70, 0xc2, 0x9b}, {0x2a, 0x5a}, {0x78, 0x40}, 0x9f, 0x65, {0x0a, 0x56, 0x82, 0x73, 0x82, 0x88} } #define UUID_SECURE_PAYLOAD_BL32_EXTRA2 \ {{0x8e, 0xa8, 0x7b, 0xb1}, {0xcf, 0xa2}, {0x3f, 0x4d}, 0x85, 0xfd, {0xe7, 0xbb, 0xa5, 0x02, 0x20, 0xd9} } #define UUID_NON_TRUSTED_FIRMWARE_BL33 \ {{0xd6, 0xd0, 0xee, 0xa7}, {0xfc, 0xea}, {0xd5, 0x4b}, 0x97, 0x82, {0x99, 0x34, 0xf2, 0x34, 0xb6, 0xe4} } /* Key certificates */ #define UUID_ROT_KEY_CERT \ {{0x86, 0x2d, 0x1d, 0x72}, {0xf8, 0x60}, {0xe4, 0x11}, 0x92, 0x0b, {0x8b, 0xe7, 0x62, 0x16, 0x0f, 0x24} } #define UUID_TRUSTED_KEY_CERT \ {{0x82, 0x7e, 0xe8, 0x90}, {0xf8, 0x60}, {0xe4, 0x11}, 0xa1, 0xb4, {0x77, 0x7a, 0x21, 0xb4, 0xf9, 0x4c} } #define UUID_NON_TRUSTED_WORLD_KEY_CERT \ {{0x1c, 0x67, 0x87, 0x3d}, {0x5f, 0x63}, {0xe4, 0x11}, 0x97, 0x8d, {0x27, 0xc0, 0xc7, 0x14, 0x8a, 0xbd} } #define UUID_SCP_FW_KEY_CERT \ {{0x02, 0x42, 0x21, 0xa1}, {0xf8, 0x60}, {0xe4, 0x11}, 0x8d, 0x9b, {0xf3, 0x3c, 0x0e, 0x15, 0xa0, 0x14} } #define UUID_SOC_FW_KEY_CERT \ {{0x8a, 0xb8, 0xbe, 0xcc}, {0xf9, 0x60}, {0xe4, 0x11}, 0x9a, 0xd0, {0xeb, 0x48, 0x22, 0xd8, 0xdc, 0xf8} } #define UUID_TRUSTED_OS_FW_KEY_CERT \ {{0x94, 0x77, 0xd6, 0x03}, {0xfb, 0x60}, {0xe4, 0x11}, 0x85, 0xdd, {0xb7, 0x10, 0x5b, 0x8c, 0xee, 0x04} } #define UUID_NON_TRUSTED_FW_KEY_CERT \ {{0x8a, 0xd5, 0x83, 0x2a}, {0xfb, 0x60}, {0xe4, 0x11}, 0x8a, 0xaf, {0xdf, 0x30, 0xbb, 0xc4, 0x98, 0x59} } /* Content certificates */ #define UUID_TRUSTED_BOOT_FW_CERT \ {{0xd6, 0xe2, 0x69, 0xea}, {0x5d, 0x63}, {0xe4, 0x11}, 0x8d, 0x8c, {0x9f, 0xba, 0xbe, 0x99, 0x56, 0xa5} } #define UUID_SCP_FW_CONTENT_CERT \ {{0x44, 0xbe, 0x6f, 0x04}, {0x5e, 0x63}, {0xe4, 0x11}, 0xb2, 0x8b, {0x73, 0xd8, 0xea, 0xae, 0x96, 0x56} } #define UUID_SOC_FW_CONTENT_CERT \ {{0xe2, 0xb2, 0x0c, 0x20}, {0x5e, 0x63}, {0xe4, 0x11}, 0x9c, 0xe8, {0xab, 0xcc, 0xf9, 0x2b, 0xb6, 0x66} } #define UUID_TRUSTED_OS_FW_CONTENT_CERT \ {{0xa4, 0x9f, 0x44, 0x11}, {0x5e, 0x63}, {0xe4, 0x11}, 0x87, 0x28, {0x3f, 0x05, 0x72, 0x2a, 0xf3, 0x3d} } #define UUID_NON_TRUSTED_FW_CONTENT_CERT \ {{0x8e, 0xc4, 0xc1, 0xf3}, {0x5d, 0x63}, {0xe4, 0x11}, 0xa7, 0xa9, {0x87, 0xee, 0x40, 0xb2, 0x3f, 0xa7} } /* Dynamic configs */ #define UUID_HW_CONFIG \ {{0x08, 0xb8, 0xf1, 0xd9}, {0xc9, 0xcf}, {0x93, 0x49}, 0xa9, 0x62, {0x6f, 0xbc, 0x6b, 0x72, 0x65, 0xcc} } #define UUID_TB_FW_CONFIG \ {{0x6c, 0x04, 0x58, 0xff}, {0xaf, 0x6b}, {0x7d, 0x4f}, 0x82, 0xed, {0xaa, 0x27, 0xbc, 0x69, 0xbf, 0xd2} } #define UUID_SOC_FW_CONFIG \ {{0x99, 0x79, 0x81, 0x4b}, {0x03, 0x76}, {0xfb, 0x46}, 0x8c, 0x8e, {0x8d, 0x26, 0x7f, 0x78, 0x59, 0xe0} } #define UUID_TOS_FW_CONFIG \ {{0x26, 0x25, 0x7c, 0x1a}, {0xdb, 0xc6}, {0x7f, 0x47}, 0x8d, 0x96, {0xc4, 0xc4, 0xb0, 0x24, 0x80, 0x21} } #define UUID_NT_FW_CONFIG \ {{0x28, 0xda, 0x98, 0x15}, {0x93, 0xe8}, {0x7e, 0x44}, 0xac, 0x66, {0x1a, 0xaf, 0x80, 0x15, 0x50, 0xf9} } typedef struct fip_toc_header { uint32_t name; uint32_t serial_number; uint64_t flags; } fip_toc_header_t; typedef struct fip_toc_entry { uuid_t uuid; uint64_t offset_address; uint64_t size; uint64_t flags; } fip_toc_entry_t; #endif /* FIRMWARE_IMAGE_PACKAGE_H */ trusted-firmware-a-2.2/include/tools_share/sptool.h000066400000000000000000000010651355360272700225510ustar00rootroot00000000000000/* * Copyright (c) 2018, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPTOOL_H #define SPTOOL_H #include /* Header for a secure partition package. There is one per package. */ struct sp_pkg_header { uint64_t version; uint64_t number_of_sp; }; /* * Entry descriptor in a secure partition package. Each entry comprises a * secure partition and its resource description. */ struct sp_pkg_entry { uint64_t sp_offset; uint64_t sp_size; uint64_t rd_offset; uint64_t rd_size; }; #endif /* SPTOOL_H */ trusted-firmware-a-2.2/include/tools_share/tbbr_oid.h000066400000000000000000000076661355360272700230320ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TBBR_OID_H #define TBBR_OID_H /* * The following is a list of OID values defined and reserved by ARM, which * are used to define the extension fields of the certificate structure, as * defined in the Trusted Board Boot Requirements (TBBR) specification, * ARM DEN0006C-1. */ /* TrustedFirmwareNVCounter - Non-volatile counter extension */ #define TRUSTED_FW_NVCOUNTER_OID "1.3.6.1.4.1.4128.2100.1" /* NonTrustedFirmwareNVCounter - Non-volatile counter extension */ #define NON_TRUSTED_FW_NVCOUNTER_OID "1.3.6.1.4.1.4128.2100.2" /* * Non-Trusted Firmware Updater Certificate */ /* APFirmwareUpdaterConfigHash - BL2U */ #define AP_FWU_CFG_HASH_OID "1.3.6.1.4.1.4128.2100.101" /* SCPFirmwareUpdaterConfigHash - SCP_BL2U */ #define SCP_FWU_CFG_HASH_OID "1.3.6.1.4.1.4128.2100.102" /* FirmwareUpdaterHash - NS_BL2U */ #define FWU_HASH_OID "1.3.6.1.4.1.4128.2100.103" /* TrustedWatchdogRefreshTime */ #define TRUSTED_WATCHDOG_TIME_OID "1.3.6.1.4.1.4128.2100.104" /* * Trusted Boot Firmware Certificate */ /* TrustedBootFirmwareHash - BL2 */ #define TRUSTED_BOOT_FW_HASH_OID "1.3.6.1.4.1.4128.2100.201" #define TRUSTED_BOOT_FW_CONFIG_HASH_OID "1.3.6.1.4.1.4128.2100.202" #define HW_CONFIG_HASH_OID "1.3.6.1.4.1.4128.2100.203" /* * Trusted Key Certificate */ /* PrimaryDebugCertificatePK */ #define PRIMARY_DEBUG_PK_OID "1.3.6.1.4.1.4128.2100.301" /* TrustedWorldPK */ #define TRUSTED_WORLD_PK_OID "1.3.6.1.4.1.4128.2100.302" /* NonTrustedWorldPK */ #define NON_TRUSTED_WORLD_PK_OID "1.3.6.1.4.1.4128.2100.303" /* * Trusted Debug Certificate */ /* DebugScenario */ #define TRUSTED_DEBUG_SCENARIO_OID "1.3.6.1.4.1.4128.2100.401" /* SoC Specific */ #define TRUSTED_DEBUG_SOC_SPEC_OID "1.3.6.1.4.1.4128.2100.402" /* SecondaryDebugCertPK */ #define SECONDARY_DEBUG_PK_OID "1.3.6.1.4.1.4128.2100.403" /* * SoC Firmware Key Certificate */ /* SoCFirmwareContentCertPK */ #define SOC_FW_CONTENT_CERT_PK_OID "1.3.6.1.4.1.4128.2100.501" /* * SoC Firmware Content Certificate */ /* APRomPatchHash - BL1_PATCH */ #define APROM_PATCH_HASH_OID "1.3.6.1.4.1.4128.2100.601" /* SoCConfigHash */ #define SOC_CONFIG_HASH_OID "1.3.6.1.4.1.4128.2100.602" /* SoCAPFirmwareHash - BL31 */ #define SOC_AP_FW_HASH_OID "1.3.6.1.4.1.4128.2100.603" /* SoCFirmwareConfigHash = SOC_FW_CONFIG */ #define SOC_FW_CONFIG_HASH_OID "1.3.6.1.4.1.4128.2100.604" /* * SCP Firmware Key Certificate */ /* SCPFirmwareContentCertPK */ #define SCP_FW_CONTENT_CERT_PK_OID "1.3.6.1.4.1.4128.2100.701" /* * SCP Firmware Content Certificate */ /* SCPFirmwareHash - SCP_BL2 */ #define SCP_FW_HASH_OID "1.3.6.1.4.1.4128.2100.801" /* SCPRomPatchHash - SCP_BL1_PATCH */ #define SCP_ROM_PATCH_HASH_OID "1.3.6.1.4.1.4128.2100.802" /* * Trusted OS Firmware Key Certificate */ /* TrustedOSFirmwareContentCertPK */ #define TRUSTED_OS_FW_CONTENT_CERT_PK_OID "1.3.6.1.4.1.4128.2100.901" /* * Trusted OS Firmware Content Certificate */ /* TrustedOSFirmwareHash - BL32 */ #define TRUSTED_OS_FW_HASH_OID "1.3.6.1.4.1.4128.2100.1001" /* TrustedOSExtra1FirmwareHash - BL32 Extra1 */ #define TRUSTED_OS_FW_EXTRA1_HASH_OID "1.3.6.1.4.1.4128.2100.1002" /* TrustedOSExtra2FirmwareHash - BL32 Extra2 */ #define TRUSTED_OS_FW_EXTRA2_HASH_OID "1.3.6.1.4.1.4128.2100.1003" /* TrustedOSFirmwareConfigHash - TOS_FW_CONFIG */ #define TRUSTED_OS_FW_CONFIG_HASH_OID "1.3.6.1.4.1.4128.2100.1004" /* * Non-Trusted Firmware Key Certificate */ /* NonTrustedFirmwareContentCertPK */ #define NON_TRUSTED_FW_CONTENT_CERT_PK_OID "1.3.6.1.4.1.4128.2100.1101" /* * Non-Trusted Firmware Content Certificate */ /* NonTrustedWorldBootloaderHash - BL33 */ #define NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID "1.3.6.1.4.1.4128.2100.1201" /* NonTrustedFirmwareConfigHash - NT_FW_CONFIG */ #define NON_TRUSTED_FW_CONFIG_HASH_OID "1.3.6.1.4.1.4128.2100.1202" #endif /* TBBR_OID_H */ trusted-firmware-a-2.2/include/tools_share/uuid.h000066400000000000000000000040741355360272700222020ustar00rootroot00000000000000/*- * Copyright (c) 2002 Marcel Moolenaar * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * $FreeBSD$ */ /* * Portions copyright (c) 2014, ARM Limited and Contributors. * All rights reserved. */ #ifndef UUID_H #define UUID_H /* Length of a node address (an IEEE 802 address). */ #define _UUID_NODE_LEN 6 /* Length of UUID string including dashes. */ #define _UUID_STR_LEN 36 /* * See also: * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt * http://www.opengroup.org/onlinepubs/009629399/apdxa.htm * * A DCE 1.1 compatible source representation of UUIDs. */ struct uuid { uint8_t time_low[4]; uint8_t time_mid[2]; uint8_t time_hi_and_version[2]; uint8_t clock_seq_hi_and_reserved; uint8_t clock_seq_low; uint8_t node[_UUID_NODE_LEN]; }; /* XXX namespace pollution? */ typedef struct uuid uuid_t; #endif /* UUID_H */ trusted-firmware-a-2.2/lib/000077500000000000000000000000001355360272700156575ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/aarch32/000077500000000000000000000000001355360272700171025ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/aarch32/arm32_aeabi_divmod.c000066400000000000000000000102341355360272700226550ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * Form ABI specifications: * int __aeabi_idiv(int numerator, int denominator); * unsigned __aeabi_uidiv(unsigned numerator, unsigned denominator); * * typedef struct { int quot; int rem; } idiv_return; * typedef struct { unsigned quot; unsigned rem; } uidiv_return; * * __value_in_regs idiv_return __aeabi_idivmod(int numerator, * int *denominator); * __value_in_regs uidiv_return __aeabi_uidivmod(unsigned *numerator, * unsigned denominator); */ /* struct qr - stores quotient/remainder to handle divmod EABI interfaces. */ struct qr { unsigned int q; /* computed quotient */ unsigned int r; /* computed remainder */ unsigned int q_n; /* specifies if quotient shall be negative */ unsigned int r_n; /* specifies if remainder shall be negative */ }; static void uint_div_qr(unsigned int numerator, unsigned int denominator, struct qr *qr); /* returns in R0 and R1 by tail calling an asm function */ unsigned int __aeabi_uidivmod(unsigned int numerator, unsigned int denominator); unsigned int __aeabi_uidiv(unsigned int numerator, unsigned int denominator); /* returns in R0 and R1 by tail calling an asm function */ signed int __aeabi_idivmod(signed int numerator, signed int denominator); signed int __aeabi_idiv(signed int numerator, signed int denominator); /* * __ste_idivmod_ret_t __aeabi_idivmod(signed numerator, signed denominator) * Numerator and Denominator are received in R0 and R1. * Where __ste_idivmod_ret_t is returned in R0 and R1. * * __ste_uidivmod_ret_t __aeabi_uidivmod(unsigned numerator, * unsigned denominator) * Numerator and Denominator are received in R0 and R1. * Where __ste_uidivmod_ret_t is returned in R0 and R1. */ #ifdef __GNUC__ signed int ret_idivmod_values(signed int quotient, signed int remainder); unsigned int ret_uidivmod_values(unsigned int quotient, unsigned int remainder); #else #error "Compiler not supported" #endif static void division_qr(unsigned int n, unsigned int p, struct qr *qr) { unsigned int i = 1, q = 0; if (p == 0) { qr->r = 0xFFFFFFFF; /* division by 0 */ return; } while ((p >> 31) == 0) { i = i << 1; /* count the max division steps */ p = p << 1; /* increase p until it has maximum size*/ } while (i > 0) { q = q << 1; /* write bit in q at index (size-1) */ if (n >= p) { n -= p; q++; } p = p >> 1; /* decrease p */ i = i >> 1; /* decrease remaining size in q */ } qr->r = n; qr->q = q; } static void uint_div_qr(unsigned int numerator, unsigned int denominator, struct qr *qr) { division_qr(numerator, denominator, qr); /* negate quotient and/or remainder according to requester */ if (qr->q_n) qr->q = -qr->q; if (qr->r_n) qr->r = -qr->r; } unsigned int __aeabi_uidiv(unsigned int numerator, unsigned int denominator) { struct qr qr = { .q_n = 0, .r_n = 0 }; uint_div_qr(numerator, denominator, &qr); return qr.q; } unsigned int __aeabi_uidivmod(unsigned int numerator, unsigned int denominator) { struct qr qr = { .q_n = 0, .r_n = 0 }; uint_div_qr(numerator, denominator, &qr); return ret_uidivmod_values(qr.q, qr.r); } signed int __aeabi_idiv(signed int numerator, signed int denominator) { struct qr qr = { .q_n = 0, .r_n = 0 }; if (((numerator < 0) && (denominator > 0)) || ((numerator > 0) && (denominator < 0))) qr.q_n = 1; /* quotient shall be negate */ if (numerator < 0) { numerator = -numerator; qr.r_n = 1; /* remainder shall be negate */ } if (denominator < 0) denominator = -denominator; uint_div_qr(numerator, denominator, &qr); return qr.q; } signed int __aeabi_idivmod(signed int numerator, signed int denominator) { struct qr qr = { .q_n = 0, .r_n = 0 }; if (((numerator < 0) && (denominator > 0)) || ((numerator > 0) && (denominator < 0))) qr.q_n = 1; /* quotient shall be negate */ if (numerator < 0) { numerator = -numerator; qr.r_n = 1; /* remainder shall be negate */ } if (denominator < 0) denominator = -denominator; uint_div_qr(numerator, denominator, &qr); return ret_idivmod_values(qr.q, qr.r); } trusted-firmware-a-2.2/lib/aarch32/arm32_aeabi_divmod_a32.S000066400000000000000000000012221355360272700232770ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* * EABI wrappers from the udivmod and idivmod functions */ .globl ret_uidivmod_values .globl ret_idivmod_values /* * signed ret_idivmod_values(signed quot, signed rem); * return quotient and remaining the EABI way (regs r0,r1) */ func ret_idivmod_values bx lr endfunc ret_idivmod_values /* * unsigned ret_uidivmod_values(unsigned quot, unsigned rem); * return quotient and remaining the EABI way (regs r0,r1) */ func ret_uidivmod_values bx lr endfunc ret_uidivmod_values trusted-firmware-a-2.2/lib/aarch32/armclang_printf.S000066400000000000000000000004701355360272700223750ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* Symbols needed by armclang */ .globl __0printf .globl __1printf .globl __2printf func __0printf __1printf: __2printf: b printf endfunc __0printf trusted-firmware-a-2.2/lib/aarch32/cache_helpers.S000066400000000000000000000144751355360272700220260ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .globl flush_dcache_range .globl clean_dcache_range .globl inv_dcache_range .globl dcsw_op_louis .globl dcsw_op_all .globl dcsw_op_level1 .globl dcsw_op_level2 .globl dcsw_op_level3 /* * This macro can be used for implementing various data cache operations `op` */ .macro do_dcache_maintenance_by_mva op, coproc, opc1, CRn, CRm, opc2 /* Exit early if size is zero */ cmp r1, #0 beq exit_loop_\op dcache_line_size r2, r3 add r1, r0, r1 sub r3, r2, #1 bic r0, r0, r3 loop_\op: stcopr r0, \coproc, \opc1, \CRn, \CRm, \opc2 add r0, r0, r2 cmp r0, r1 blo loop_\op dsb sy exit_loop_\op: bx lr .endm /* ------------------------------------------ * Clean+Invalidate from base address till * size. 'r0' = addr, 'r1' = size * ------------------------------------------ */ func flush_dcache_range do_dcache_maintenance_by_mva cimvac, DCCIMVAC endfunc flush_dcache_range /* ------------------------------------------ * Clean from base address till size. * 'r0' = addr, 'r1' = size * ------------------------------------------ */ func clean_dcache_range do_dcache_maintenance_by_mva cmvac, DCCMVAC endfunc clean_dcache_range /* ------------------------------------------ * Invalidate from base address till * size. 'r0' = addr, 'r1' = size * ------------------------------------------ */ func inv_dcache_range do_dcache_maintenance_by_mva imvac, DCIMVAC endfunc inv_dcache_range /* ---------------------------------------------------------------- * Data cache operations by set/way to the level specified * * The main function, do_dcsw_op requires: * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW), * as defined in arch.h * r1: The cache level to begin operation from * r2: clidr_el1 * r3: The last cache level to operate on * and will carry out the operation on each data cache from level 0 * to the level in r3 in sequence * * The dcsw_op macro sets up the r2 and r3 parameters based on * clidr_el1 cache information before invoking the main function * ---------------------------------------------------------------- */ .macro dcsw_op shift, fw, ls ldcopr r2, CLIDR ubfx r3, r2, \shift, \fw lsl r3, r3, \ls mov r1, #0 b do_dcsw_op .endm func do_dcsw_op push {r4-r12, lr} adr r11, dcsw_loop_table // compute cache op based on the operation type add r6, r11, r0, lsl #3 // cache op is 2x32-bit instructions loop1: add r10, r1, r1, LSR #1 // Work out 3x current cache level mov r12, r2, LSR r10 // extract cache type bits from clidr and r12, r12, #7 // mask the bits for current cache only cmp r12, #2 // see what cache we have at this level blo level_done // no cache or only instruction cache at this level stcopr r1, CSSELR // select current cache level in csselr isb // isb to sych the new cssr&csidr ldcopr r12, CCSIDR // read the new ccsidr and r10, r12, #7 // extract the length of the cache lines add r10, r10, #4 // add 4 (r10 = line length offset) ubfx r4, r12, #3, #10 // r4 = maximum way number (right aligned) clz r5, r4 // r5 = the bit position of the way size increment mov r9, r4 // r9 working copy of the aligned max way number loop2: ubfx r7, r12, #13, #15 // r7 = max set number (right aligned) loop3: orr r0, r1, r9, LSL r5 // factor in the way number and cache level into r0 orr r0, r0, r7, LSL r10 // factor in the set number blx r6 subs r7, r7, #1 // decrement the set number bhs loop3 subs r9, r9, #1 // decrement the way number bhs loop2 level_done: add r1, r1, #2 // increment the cache number cmp r3, r1 // Ensure completion of previous cache maintenance instruction. Note // this also mitigates erratum 814220 on Cortex-A7 dsb sy bhi loop1 mov r6, #0 stcopr r6, CSSELR //select cache level 0 in csselr dsb sy isb pop {r4-r12, pc} dcsw_loop_table: stcopr r0, DCISW bx lr stcopr r0, DCCISW bx lr stcopr r0, DCCSW bx lr endfunc do_dcsw_op /* --------------------------------------------------------------- * Data cache operations by set/way till PoU. * * The function requires : * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW), * as defined in arch.h * --------------------------------------------------------------- */ func dcsw_op_louis dcsw_op #LOUIS_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT endfunc dcsw_op_louis /* --------------------------------------------------------------- * Data cache operations by set/way till PoC. * * The function requires : * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW), * as defined in arch.h * --------------------------------------------------------------- */ func dcsw_op_all dcsw_op #LOC_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT endfunc dcsw_op_all /* --------------------------------------------------------------- * Helper macro for data cache operations by set/way for the * level specified * --------------------------------------------------------------- */ .macro dcsw_op_level level ldcopr r2, CLIDR mov r3, \level sub r1, r3, #2 b do_dcsw_op .endm /* --------------------------------------------------------------- * Data cache operations by set/way for level 1 cache * * The main function, do_dcsw_op requires: * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW), * as defined in arch.h * --------------------------------------------------------------- */ func dcsw_op_level1 dcsw_op_level #(1 << LEVEL_SHIFT) endfunc dcsw_op_level1 /* --------------------------------------------------------------- * Data cache operations by set/way for level 2 cache * * The main function, do_dcsw_op requires: * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW), * as defined in arch.h * --------------------------------------------------------------- */ func dcsw_op_level2 dcsw_op_level #(2 << LEVEL_SHIFT) endfunc dcsw_op_level2 /* --------------------------------------------------------------- * Data cache operations by set/way for level 3 cache * * The main function, do_dcsw_op requires: * r0: The operation type (DC_OP_ISW, DC_OP_CISW, DC_OP_CSW), * as defined in arch.h * --------------------------------------------------------------- */ func dcsw_op_level3 dcsw_op_level #(3 << LEVEL_SHIFT) endfunc dcsw_op_level3 trusted-firmware-a-2.2/lib/aarch32/misc_helpers.S000066400000000000000000000106621355360272700217100ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl smc .globl zeromem .globl zero_normalmem .globl memcpy4 .globl disable_mmu_icache_secure .globl disable_mmu_secure func smc /* * For AArch32 only r0-r3 will be in the registers; * rest r4-r6 will be pushed on to the stack. So here, we'll * have to load them from the stack to registers r4-r6 explicitly. * Clobbers: r4-r6 */ ldm sp, {r4, r5, r6} smc #0 endfunc smc /* ----------------------------------------------------------------------- * void zeromem(void *mem, unsigned int length) * * Initialise a region in normal memory to 0. This functions complies with the * AAPCS and can be called from C code. * * ----------------------------------------------------------------------- */ func zeromem /* * Readable names for registers * * Registers r0, r1 and r2 are also set by zeromem which * branches into the fallback path directly, so cursor, length and * stop_address should not be retargeted to other registers. */ cursor .req r0 /* Start address and then current address */ length .req r1 /* Length in bytes of the region to zero out */ /* * Reusing the r1 register as length is only used at the beginning of * the function. */ stop_address .req r1 /* Address past the last zeroed byte */ zeroreg1 .req r2 /* Source register filled with 0 */ zeroreg2 .req r3 /* Source register filled with 0 */ tmp .req r12 /* Temporary scratch register */ mov zeroreg1, #0 /* stop_address is the address past the last to zero */ add stop_address, cursor, length /* * Length cannot be used anymore as it shares the same register with * stop_address. */ .unreq length /* * If the start address is already aligned to 8 bytes, skip this loop. */ tst cursor, #(8-1) beq .Lzeromem_8bytes_aligned /* Calculate the next address aligned to 8 bytes */ orr tmp, cursor, #(8-1) adds tmp, tmp, #1 /* If it overflows, fallback to byte per byte zeroing */ beq .Lzeromem_1byte_aligned /* If the next aligned address is after the stop address, fall back */ cmp tmp, stop_address bhs .Lzeromem_1byte_aligned /* zero byte per byte */ 1: strb zeroreg1, [cursor], #1 cmp cursor, tmp bne 1b /* zero 8 bytes at a time */ .Lzeromem_8bytes_aligned: /* Calculate the last 8 bytes aligned address. */ bic tmp, stop_address, #(8-1) cmp cursor, tmp bhs 2f mov zeroreg2, #0 1: stmia cursor!, {zeroreg1, zeroreg2} cmp cursor, tmp blo 1b 2: /* zero byte per byte */ .Lzeromem_1byte_aligned: cmp cursor, stop_address beq 2f 1: strb zeroreg1, [cursor], #1 cmp cursor, stop_address bne 1b 2: bx lr .unreq cursor /* * length is already unreq'ed to reuse the register for another * variable. */ .unreq stop_address .unreq zeroreg1 .unreq zeroreg2 .unreq tmp endfunc zeromem /* * AArch32 does not have special ways of zeroing normal memory as AArch64 does * using the DC ZVA instruction, so we just alias zero_normalmem to zeromem. */ .equ zero_normalmem, zeromem /* -------------------------------------------------------------------------- * void memcpy4(void *dest, const void *src, unsigned int length) * * Copy length bytes from memory area src to memory area dest. * The memory areas should not overlap. * Destination and source addresses must be 4-byte aligned. * -------------------------------------------------------------------------- */ func memcpy4 #if ENABLE_ASSERTIONS orr r3, r0, r1 tst r3, #0x3 ASM_ASSERT(eq) #endif /* copy 4 bytes at a time */ m_loop4: cmp r2, #4 blo m_loop1 ldr r3, [r1], #4 str r3, [r0], #4 sub r2, r2, #4 b m_loop4 /* copy byte per byte */ m_loop1: cmp r2,#0 beq m_end ldrb r3, [r1], #1 strb r3, [r0], #1 subs r2, r2, #1 bne m_loop1 m_end: bx lr endfunc memcpy4 /* --------------------------------------------------------------------------- * Disable the MMU in Secure State * --------------------------------------------------------------------------- */ func disable_mmu_secure mov r1, #(SCTLR_M_BIT | SCTLR_C_BIT) do_disable_mmu: #if ERRATA_A9_794073 stcopr r0, BPIALL dsb #endif ldcopr r0, SCTLR bic r0, r0, r1 stcopr r0, SCTLR isb // ensure MMU is off dsb sy bx lr endfunc disable_mmu_secure func disable_mmu_icache_secure ldr r1, =(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT) b do_disable_mmu endfunc disable_mmu_icache_secure trusted-firmware-a-2.2/lib/aarch64/000077500000000000000000000000001355360272700171075ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/aarch64/armclang_printf.S000066400000000000000000000005701355360272700224030ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* Symbols needed by armclang */ .globl __0printf .globl __1printf .globl __2printf func __0printf b printf endfunc __0printf func __1printf b printf endfunc __1printf func __2printf b printf endfunc __2printf trusted-firmware-a-2.2/lib/aarch64/cache_helpers.S000066400000000000000000000132731355360272700220260ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .globl flush_dcache_range .globl clean_dcache_range .globl inv_dcache_range .globl dcsw_op_louis .globl dcsw_op_all .globl dcsw_op_level1 .globl dcsw_op_level2 .globl dcsw_op_level3 /* * This macro can be used for implementing various data cache operations `op` */ .macro do_dcache_maintenance_by_mva op /* Exit early if size is zero */ cbz x1, exit_loop_\op dcache_line_size x2, x3 add x1, x0, x1 sub x3, x2, #1 bic x0, x0, x3 loop_\op: dc \op, x0 add x0, x0, x2 cmp x0, x1 b.lo loop_\op dsb sy exit_loop_\op: ret .endm /* ------------------------------------------ * Clean+Invalidate from base address till * size. 'x0' = addr, 'x1' = size * ------------------------------------------ */ func flush_dcache_range do_dcache_maintenance_by_mva civac endfunc flush_dcache_range /* ------------------------------------------ * Clean from base address till size. * 'x0' = addr, 'x1' = size * ------------------------------------------ */ func clean_dcache_range do_dcache_maintenance_by_mva cvac endfunc clean_dcache_range /* ------------------------------------------ * Invalidate from base address till * size. 'x0' = addr, 'x1' = size * ------------------------------------------ */ func inv_dcache_range do_dcache_maintenance_by_mva ivac endfunc inv_dcache_range /* --------------------------------------------------------------- * Data cache operations by set/way to the level specified * * The main function, do_dcsw_op requires: * x0: The operation type (0-2), as defined in arch.h * x3: The last cache level to operate on * x9: clidr_el1 * x10: The cache level to begin operation from * and will carry out the operation on each data cache from level 0 * to the level in x3 in sequence * * The dcsw_op macro sets up the x3 and x9 parameters based on * clidr_el1 cache information before invoking the main function * --------------------------------------------------------------- */ .macro dcsw_op shift, fw, ls mrs x9, clidr_el1 ubfx x3, x9, \shift, \fw lsl x3, x3, \ls mov x10, xzr b do_dcsw_op .endm func do_dcsw_op cbz x3, exit adr x14, dcsw_loop_table // compute inner loop address add x14, x14, x0, lsl #5 // inner loop is 8x32-bit instructions #if ENABLE_BTI add x14, x14, x0, lsl #2 // inner loop is + "bti j" instruction #endif mov x0, x9 mov w8, #1 loop1: add x2, x10, x10, lsr #1 // work out 3x current cache level lsr x1, x0, x2 // extract cache type bits from clidr and x1, x1, #7 // mask the bits for current cache only cmp x1, #2 // see what cache we have at this level b.lo level_done // nothing to do if no cache or icache msr csselr_el1, x10 // select current cache level in csselr isb // isb to sych the new cssr&csidr mrs x1, ccsidr_el1 // read the new ccsidr and x2, x1, #7 // extract the length of the cache lines add x2, x2, #4 // add 4 (line length offset) ubfx x4, x1, #3, #10 // maximum way number clz w5, w4 // bit position of way size increment lsl w9, w4, w5 // w9 = aligned max way number lsl w16, w8, w5 // w16 = way number loop decrement orr w9, w10, w9 // w9 = combine way and cache number ubfx w6, w1, #13, #15 // w6 = max set number lsl w17, w8, w2 // w17 = set number loop decrement dsb sy // barrier before we start this level br x14 // jump to DC operation specific loop .macro dcsw_loop _op #if ENABLE_BTI bti j #endif loop2_\_op: lsl w7, w6, w2 // w7 = aligned max set number loop3_\_op: orr w11, w9, w7 // combine cache, way and set number dc \_op, x11 subs w7, w7, w17 // decrement set number b.hs loop3_\_op subs x9, x9, x16 // decrement way number b.hs loop2_\_op b level_done .endm level_done: add x10, x10, #2 // increment cache number cmp x3, x10 b.hi loop1 msr csselr_el1, xzr // select cache level 0 in csselr dsb sy // barrier to complete final cache operation isb exit: ret endfunc do_dcsw_op dcsw_loop_table: dcsw_loop isw dcsw_loop cisw dcsw_loop csw func dcsw_op_louis dcsw_op #LOUIS_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT endfunc dcsw_op_louis func dcsw_op_all dcsw_op #LOC_SHIFT, #CLIDR_FIELD_WIDTH, #LEVEL_SHIFT endfunc dcsw_op_all /* --------------------------------------------------------------- * Helper macro for data cache operations by set/way for the * level specified * --------------------------------------------------------------- */ .macro dcsw_op_level level mrs x9, clidr_el1 mov x3, \level sub x10, x3, #2 b do_dcsw_op .endm /* --------------------------------------------------------------- * Data cache operations by set/way for level 1 cache * * The main function, do_dcsw_op requires: * x0: The operation type (0-2), as defined in arch.h * --------------------------------------------------------------- */ func dcsw_op_level1 dcsw_op_level #(1 << LEVEL_SHIFT) endfunc dcsw_op_level1 /* --------------------------------------------------------------- * Data cache operations by set/way for level 2 cache * * The main function, do_dcsw_op requires: * x0: The operation type (0-2), as defined in arch.h * --------------------------------------------------------------- */ func dcsw_op_level2 dcsw_op_level #(2 << LEVEL_SHIFT) endfunc dcsw_op_level2 /* --------------------------------------------------------------- * Data cache operations by set/way for level 3 cache * * The main function, do_dcsw_op requires: * x0: The operation type (0-2), as defined in arch.h * --------------------------------------------------------------- */ func dcsw_op_level3 dcsw_op_level #(3 << LEVEL_SHIFT) endfunc dcsw_op_level3 trusted-firmware-a-2.2/lib/aarch64/misc_helpers.S000066400000000000000000000407061355360272700217170ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include .globl smc .globl zero_normalmem .globl zeromem .globl memcpy16 .globl disable_mmu_el1 .globl disable_mmu_el3 .globl disable_mmu_icache_el1 .globl disable_mmu_icache_el3 .globl fixup_gdt_reloc #if SUPPORT_VFP .globl enable_vfp #endif func smc smc #0 endfunc smc /* ----------------------------------------------------------------------- * void zero_normalmem(void *mem, unsigned int length); * * Initialise a region in normal memory to 0. This functions complies with the * AAPCS and can be called from C code. * * NOTE: MMU must be enabled when using this function as it can only operate on * normal memory. It is intended to be mainly used from C code when MMU * is usually enabled. * ----------------------------------------------------------------------- */ .equ zero_normalmem, zeromem_dczva /* ----------------------------------------------------------------------- * void zeromem(void *mem, unsigned int length); * * Initialise a region of device memory to 0. This functions complies with the * AAPCS and can be called from C code. * * NOTE: When data caches and MMU are enabled, zero_normalmem can usually be * used instead for faster zeroing. * * ----------------------------------------------------------------------- */ func zeromem /* x2 is the address past the last zeroed address */ add x2, x0, x1 /* * Uses the fallback path that does not use DC ZVA instruction and * therefore does not need enabled MMU */ b .Lzeromem_dczva_fallback_entry endfunc zeromem /* ----------------------------------------------------------------------- * void zeromem_dczva(void *mem, unsigned int length); * * Fill a region of normal memory of size "length" in bytes with null bytes. * MMU must be enabled and the memory be of * normal type. This is because this function internally uses the DC ZVA * instruction, which generates an Alignment fault if used on any type of * Device memory (see section D3.4.9 of the ARMv8 ARM, issue k). When the MMU * is disabled, all memory behaves like Device-nGnRnE memory (see section * D4.2.8), hence the requirement on the MMU being enabled. * NOTE: The code assumes that the block size as defined in DCZID_EL0 * register is at least 16 bytes. * * ----------------------------------------------------------------------- */ func zeromem_dczva /* * The function consists of a series of loops that zero memory one byte * at a time, 16 bytes at a time or using the DC ZVA instruction to * zero aligned block of bytes, which is assumed to be more than 16. * In the case where the DC ZVA instruction cannot be used or if the * first 16 bytes loop would overflow, there is fallback path that does * not use DC ZVA. * Note: The fallback path is also used by the zeromem function that * branches to it directly. * * +---------+ zeromem_dczva * | entry | * +----+----+ * | * v * +---------+ * | checks |>o-------+ (If any check fails, fallback) * +----+----+ | * | |---------------+ * v | Fallback path | * +------+------+ |---------------+ * | 1 byte loop | | * +------+------+ .Lzeromem_dczva_initial_1byte_aligned_end * | | * v | * +-------+-------+ | * | 16 bytes loop | | * +-------+-------+ | * | | * v | * +------+------+ .Lzeromem_dczva_blocksize_aligned * | DC ZVA loop | | * +------+------+ | * +--------+ | | * | | | | * | v v | * | +-------+-------+ .Lzeromem_dczva_final_16bytes_aligned * | | 16 bytes loop | | * | +-------+-------+ | * | | | * | v | * | +------+------+ .Lzeromem_dczva_final_1byte_aligned * | | 1 byte loop | | * | +-------------+ | * | | | * | v | * | +---+--+ | * | | exit | | * | +------+ | * | | * | +--------------+ +------------------+ zeromem * | | +----------------| zeromem function | * | | | +------------------+ * | v v * | +-------------+ .Lzeromem_dczva_fallback_entry * | | 1 byte loop | * | +------+------+ * | | * +-----------+ */ /* * Readable names for registers * * Registers x0, x1 and x2 are also set by zeromem which * branches into the fallback path directly, so cursor, length and * stop_address should not be retargeted to other registers. */ cursor .req x0 /* Start address and then current address */ length .req x1 /* Length in bytes of the region to zero out */ /* Reusing x1 as length is never used after block_mask is set */ block_mask .req x1 /* Bitmask of the block size read in DCZID_EL0 */ stop_address .req x2 /* Address past the last zeroed byte */ block_size .req x3 /* Size of a block in bytes as read in DCZID_EL0 */ tmp1 .req x4 tmp2 .req x5 #if ENABLE_ASSERTIONS /* * Check for M bit (MMU enabled) of the current SCTLR_EL(1|3) * register value and panic if the MMU is disabled. */ #if defined(IMAGE_BL1) || defined(IMAGE_BL31) || (defined(IMAGE_BL2) && BL2_AT_EL3) mrs tmp1, sctlr_el3 #else mrs tmp1, sctlr_el1 #endif tst tmp1, #SCTLR_M_BIT ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ /* stop_address is the address past the last to zero */ add stop_address, cursor, length /* * Get block_size = (log2() >> 2) (see encoding of * dczid_el0 reg) */ mrs block_size, dczid_el0 /* * Select the 4 lowest bits and convert the extracted log2() to */ ubfx block_size, block_size, #0, #4 mov tmp2, #(1 << 2) lsl block_size, tmp2, block_size #if ENABLE_ASSERTIONS /* * Assumes block size is at least 16 bytes to avoid manual realignment * of the cursor at the end of the DCZVA loop. */ cmp block_size, #16 ASM_ASSERT(hs) #endif /* * Not worth doing all the setup for a region less than a block and * protects against zeroing a whole block when the area to zero is * smaller than that. Also, as it is assumed that the block size is at * least 16 bytes, this also protects the initial aligning loops from * trying to zero 16 bytes when length is less than 16. */ cmp length, block_size b.lo .Lzeromem_dczva_fallback_entry /* * Calculate the bitmask of the block alignment. It will never * underflow as the block size is between 4 bytes and 2kB. * block_mask = block_size - 1 */ sub block_mask, block_size, #1 /* * length alias should not be used after this point unless it is * defined as a register other than block_mask's. */ .unreq length /* * If the start address is already aligned to zero block size, go * straight to the cache zeroing loop. This is safe because at this * point, the length cannot be smaller than a block size. */ tst cursor, block_mask b.eq .Lzeromem_dczva_blocksize_aligned /* * Calculate the first block-size-aligned address. It is assumed that * the zero block size is at least 16 bytes. This address is the last * address of this initial loop. */ orr tmp1, cursor, block_mask add tmp1, tmp1, #1 /* * If the addition overflows, skip the cache zeroing loops. This is * quite unlikely however. */ cbz tmp1, .Lzeromem_dczva_fallback_entry /* * If the first block-size-aligned address is past the last address, * fallback to the simpler code. */ cmp tmp1, stop_address b.hi .Lzeromem_dczva_fallback_entry /* * If the start address is already aligned to 16 bytes, skip this loop. * It is safe to do this because tmp1 (the stop address of the initial * 16 bytes loop) will never be greater than the final stop address. */ tst cursor, #0xf b.eq .Lzeromem_dczva_initial_1byte_aligned_end /* Calculate the next address aligned to 16 bytes */ orr tmp2, cursor, #0xf add tmp2, tmp2, #1 /* If it overflows, fallback to the simple path (unlikely) */ cbz tmp2, .Lzeromem_dczva_fallback_entry /* * Next aligned address cannot be after the stop address because the * length cannot be smaller than 16 at this point. */ /* First loop: zero byte per byte */ 1: strb wzr, [cursor], #1 cmp cursor, tmp2 b.ne 1b .Lzeromem_dczva_initial_1byte_aligned_end: /* * Second loop: we need to zero 16 bytes at a time from cursor to tmp1 * before being able to use the code that deals with block-size-aligned * addresses. */ cmp cursor, tmp1 b.hs 2f 1: stp xzr, xzr, [cursor], #16 cmp cursor, tmp1 b.lo 1b 2: /* * Third loop: zero a block at a time using DC ZVA cache block zeroing * instruction. */ .Lzeromem_dczva_blocksize_aligned: /* * Calculate the last block-size-aligned address. If the result equals * to the start address, the loop will exit immediately. */ bic tmp1, stop_address, block_mask cmp cursor, tmp1 b.hs 2f 1: /* Zero the block containing the cursor */ dc zva, cursor /* Increment the cursor by the size of a block */ add cursor, cursor, block_size cmp cursor, tmp1 b.lo 1b 2: /* * Fourth loop: zero 16 bytes at a time and then byte per byte the * remaining area */ .Lzeromem_dczva_final_16bytes_aligned: /* * Calculate the last 16 bytes aligned address. It is assumed that the * block size will never be smaller than 16 bytes so that the current * cursor is aligned to at least 16 bytes boundary. */ bic tmp1, stop_address, #15 cmp cursor, tmp1 b.hs 2f 1: stp xzr, xzr, [cursor], #16 cmp cursor, tmp1 b.lo 1b 2: /* Fifth and final loop: zero byte per byte */ .Lzeromem_dczva_final_1byte_aligned: cmp cursor, stop_address b.eq 2f 1: strb wzr, [cursor], #1 cmp cursor, stop_address b.ne 1b 2: ret /* Fallback for unaligned start addresses */ .Lzeromem_dczva_fallback_entry: /* * If the start address is already aligned to 16 bytes, skip this loop. */ tst cursor, #0xf b.eq .Lzeromem_dczva_final_16bytes_aligned /* Calculate the next address aligned to 16 bytes */ orr tmp1, cursor, #15 add tmp1, tmp1, #1 /* If it overflows, fallback to byte per byte zeroing */ cbz tmp1, .Lzeromem_dczva_final_1byte_aligned /* If the next aligned address is after the stop address, fall back */ cmp tmp1, stop_address b.hs .Lzeromem_dczva_final_1byte_aligned /* Fallback entry loop: zero byte per byte */ 1: strb wzr, [cursor], #1 cmp cursor, tmp1 b.ne 1b b .Lzeromem_dczva_final_16bytes_aligned .unreq cursor /* * length is already unreq'ed to reuse the register for another * variable. */ .unreq stop_address .unreq block_size .unreq block_mask .unreq tmp1 .unreq tmp2 endfunc zeromem_dczva /* -------------------------------------------------------------------------- * void memcpy16(void *dest, const void *src, unsigned int length) * * Copy length bytes from memory area src to memory area dest. * The memory areas should not overlap. * Destination and source addresses must be 16-byte aligned. * -------------------------------------------------------------------------- */ func memcpy16 #if ENABLE_ASSERTIONS orr x3, x0, x1 tst x3, #0xf ASM_ASSERT(eq) #endif /* copy 16 bytes at a time */ m_loop16: cmp x2, #16 b.lo m_loop1 ldp x3, x4, [x1], #16 stp x3, x4, [x0], #16 sub x2, x2, #16 b m_loop16 /* copy byte per byte */ m_loop1: cbz x2, m_end ldrb w3, [x1], #1 strb w3, [x0], #1 subs x2, x2, #1 b.ne m_loop1 m_end: ret endfunc memcpy16 /* --------------------------------------------------------------------------- * Disable the MMU at EL3 * --------------------------------------------------------------------------- */ func disable_mmu_el3 mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT) do_disable_mmu_el3: mrs x0, sctlr_el3 bic x0, x0, x1 msr sctlr_el3, x0 isb /* ensure MMU is off */ dsb sy ret endfunc disable_mmu_el3 func disable_mmu_icache_el3 mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT) b do_disable_mmu_el3 endfunc disable_mmu_icache_el3 /* --------------------------------------------------------------------------- * Disable the MMU at EL1 * --------------------------------------------------------------------------- */ func disable_mmu_el1 mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT) do_disable_mmu_el1: mrs x0, sctlr_el1 bic x0, x0, x1 msr sctlr_el1, x0 isb /* ensure MMU is off */ dsb sy ret endfunc disable_mmu_el1 func disable_mmu_icache_el1 mov x1, #(SCTLR_M_BIT | SCTLR_C_BIT | SCTLR_I_BIT) b do_disable_mmu_el1 endfunc disable_mmu_icache_el1 /* --------------------------------------------------------------------------- * Enable the use of VFP at EL3 * --------------------------------------------------------------------------- */ #if SUPPORT_VFP func enable_vfp mrs x0, cpacr_el1 orr x0, x0, #CPACR_VFP_BITS msr cpacr_el1, x0 mrs x0, cptr_el3 mov x1, #AARCH64_CPTR_TFP bic x0, x0, x1 msr cptr_el3, x0 isb ret endfunc enable_vfp #endif /* --------------------------------------------------------------------------- * Helper to fixup Global Descriptor table (GDT) and dynamic relocations * (.rela.dyn) at runtime. * * This function is meant to be used when the firmware is compiled with -fpie * and linked with -pie options. We rely on the linker script exporting * appropriate markers for start and end of the section. For GOT, we * expect __GOT_START__ and __GOT_END__. Similarly for .rela.dyn, we expect * __RELA_START__ and __RELA_END__. * * The function takes the limits of the memory to apply fixups to as * arguments (which is usually the limits of the relocable BL image). * x0 - the start of the fixup region * x1 - the limit of the fixup region * These addresses have to be page (4KB aligned). * --------------------------------------------------------------------------- */ func fixup_gdt_reloc mov x6, x0 mov x7, x1 /* Test if the limits are 4K aligned */ #if ENABLE_ASSERTIONS orr x0, x0, x1 tst x0, #(PAGE_SIZE - 1) ASM_ASSERT(eq) #endif /* * Calculate the offset based on return address in x30. * Assume that this function is called within a page at the start of * fixup region. */ and x2, x30, #~(PAGE_SIZE - 1) sub x0, x2, x6 /* Diff(S) = Current Address - Compiled Address */ adrp x1, __GOT_START__ add x1, x1, :lo12:__GOT_START__ adrp x2, __GOT_END__ add x2, x2, :lo12:__GOT_END__ /* * GOT is an array of 64_bit addresses which must be fixed up as * new_addr = old_addr + Diff(S). * The new_addr is the address currently the binary is executing from * and old_addr is the address at compile time. */ 1: ldr x3, [x1] /* Skip adding offset if address is < lower limit */ cmp x3, x6 b.lo 2f /* Skip adding offset if address is >= upper limit */ cmp x3, x7 b.ge 2f add x3, x3, x0 str x3, [x1] 2: add x1, x1, #8 cmp x1, x2 b.lo 1b /* Starting dynamic relocations. Use adrp/adr to get RELA_START and END */ adrp x1, __RELA_START__ add x1, x1, :lo12:__RELA_START__ adrp x2, __RELA_END__ add x2, x2, :lo12:__RELA_END__ /* * According to ELF-64 specification, the RELA data structure is as * follows: * typedef struct * { * Elf64_Addr r_offset; * Elf64_Xword r_info; * Elf64_Sxword r_addend; * } Elf64_Rela; * * r_offset is address of reference * r_info is symbol index and type of relocation (in this case * 0x403 which corresponds to R_AARCH64_RELATIVE). * r_addend is constant part of expression. * * Size of Elf64_Rela structure is 24 bytes. */ 1: /* Assert that the relocation type is R_AARCH64_RELATIVE */ #if ENABLE_ASSERTIONS ldr x3, [x1, #8] cmp x3, #0x403 ASM_ASSERT(eq) #endif ldr x3, [x1] /* r_offset */ add x3, x0, x3 ldr x4, [x1, #16] /* r_addend */ /* Skip adding offset if r_addend is < lower limit */ cmp x4, x6 b.lo 2f /* Skip adding offset if r_addend entry is >= upper limit */ cmp x4, x7 b.ge 2f add x4, x0, x4 /* Diff(S) + r_addend */ str x4, [x3] 2: add x1, x1, #24 cmp x1, x2 b.lo 1b ret endfunc fixup_gdt_reloc trusted-firmware-a-2.2/lib/bl_aux_params/000077500000000000000000000000001355360272700204745ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/bl_aux_params/bl_aux_params.c000066400000000000000000000013241355360272700234550ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include void bl_aux_params_parse(u_register_t head, bl_aux_param_handler_t handler) { struct bl_aux_param_header *p; for (p = (void *)head; p; p = (void *)(uintptr_t)p->next) { if (handler && handler(p)) continue; switch (p->type) { #if COREBOOT case BL_AUX_PARAM_COREBOOT_TABLE: coreboot_table_setup((void *)(uintptr_t) ((struct bl_aux_param_uint64 *)p)->value); break; #endif default: ERROR("Ignoring unknown BL aux parameter: 0x%llx", p->type); break; } } } trusted-firmware-a-2.2/lib/compiler-rt/000077500000000000000000000000001355360272700201145ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/compiler-rt/LICENSE.TXT000066400000000000000000000103011355360272700215720ustar00rootroot00000000000000============================================================================== compiler_rt License ============================================================================== The compiler_rt library is dual licensed under both the University of Illinois "BSD-Like" license and the MIT license. As a user of this code you may choose to use it under either license. As a contributor, you agree to allow your code to be used under both. Full text of the relevant licenses is included below. ============================================================================== University of Illinois/NCSA Open Source License Copyright (c) 2009-2016 by the contributors listed in CREDITS.TXT All rights reserved. Developed by: LLVM Team University of Illinois at Urbana-Champaign http://llvm.org Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal with the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimers. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimers in the documentation and/or other materials provided with the distribution. * Neither the names of the LLVM Team, University of Illinois at Urbana-Champaign, nor the names of its contributors may be used to endorse or promote products derived from this Software without specific prior written permission. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. ============================================================================== Copyright (c) 2009-2015 by the contributors listed in CREDITS.TXT Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ============================================================================== Copyrights and Licenses for Third Party Software Distributed with LLVM: ============================================================================== The LLVM software contains code written by third parties. Such software will have its own individual LICENSE.TXT file in the directory in which it appears. This file will describe the copyrights, license, and restrictions which apply to that code. The disclaimer of warranty in the University of Illinois Open Source License applies to all code in the LLVM Distribution, and nothing in any of the other licenses gives permission to use the names of the LLVM Team or the University of Illinois to endorse or promote products derived from this Software. trusted-firmware-a-2.2/lib/compiler-rt/builtins/000077500000000000000000000000001355360272700217455ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/compiler-rt/builtins/arm/000077500000000000000000000000001355360272700225245ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/compiler-rt/builtins/arm/aeabi_uldivmod.S000066400000000000000000000023121355360272700256120ustar00rootroot00000000000000//===-- aeabi_uldivmod.S - EABI uldivmod implementation -------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "../assembly.h" // struct { uint64_t quot, uint64_t rem} // __aeabi_uldivmod(uint64_t numerator, uint64_t denominator) { // uint64_t rem, quot; // quot = __udivmoddi4(numerator, denominator, &rem); // return {quot, rem}; // } #if defined(__MINGW32__) #define __aeabi_uldivmod __rt_udiv64 #endif .syntax unified .p2align 2 DEFINE_COMPILERRT_FUNCTION(__aeabi_uldivmod) push {r6, lr} sub sp, sp, #16 add r6, sp, #8 str r6, [sp] #if defined(__MINGW32__) movs r6, r0 movs r0, r2 movs r2, r6 movs r6, r1 movs r1, r3 movs r3, r6 #endif bl SYMBOL_NAME(__udivmoddi4) ldr r2, [sp, #8] ldr r3, [sp, #12] add sp, sp, #16 pop {r6, pc} END_COMPILERRT_FUNCTION(__aeabi_uldivmod) NO_EXEC_STACK_DIRECTIVE trusted-firmware-a-2.2/lib/compiler-rt/builtins/assembly.h000066400000000000000000000133321355360272700237370ustar00rootroot00000000000000/* ===-- assembly.h - compiler-rt assembler support macros -----------------=== * * 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 defines macros for use in compiler-rt assembler source. * This file is not part of the interface of this library. * * ===----------------------------------------------------------------------=== */ #ifndef COMPILERRT_ASSEMBLY_H #define COMPILERRT_ASSEMBLY_H #if defined(__POWERPC__) || defined(__powerpc__) || defined(__ppc__) #define SEPARATOR @ #else #define SEPARATOR ; #endif #if defined(__APPLE__) #define HIDDEN(name) .private_extern name #define LOCAL_LABEL(name) L_##name // tell linker it can break up file at label boundaries #define FILE_LEVEL_DIRECTIVE .subsections_via_symbols #define SYMBOL_IS_FUNC(name) #define CONST_SECTION .const #define NO_EXEC_STACK_DIRECTIVE #elif defined(__ELF__) #define HIDDEN(name) .hidden name #define LOCAL_LABEL(name) .L_##name #define FILE_LEVEL_DIRECTIVE #if defined(__arm__) #define SYMBOL_IS_FUNC(name) .type name,%function #else #define SYMBOL_IS_FUNC(name) .type name,@function #endif #define CONST_SECTION .section .rodata #if defined(__GNU__) || defined(__ANDROID__) || defined(__FreeBSD__) #define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits #else #define NO_EXEC_STACK_DIRECTIVE #endif #else // !__APPLE__ && !__ELF__ #define HIDDEN(name) #define LOCAL_LABEL(name) .L ## name #define FILE_LEVEL_DIRECTIVE #define SYMBOL_IS_FUNC(name) \ .def name SEPARATOR \ .scl 2 SEPARATOR \ .type 32 SEPARATOR \ .endef #define CONST_SECTION .section .rdata,"rd" #define NO_EXEC_STACK_DIRECTIVE #endif #if defined(__arm__) #if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5 #define ARM_HAS_BX #endif #if !defined(__ARM_FEATURE_CLZ) && __ARM_ARCH_ISA_THUMB != 1 && \ (__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__))) #define __ARM_FEATURE_CLZ #endif #ifdef ARM_HAS_BX #define JMP(r) bx r #define JMPc(r, c) bx##c r #else #define JMP(r) mov pc, r #define JMPc(r, c) mov##c pc, r #endif // pop {pc} can't switch Thumb mode on ARMv4T #if __ARM_ARCH >= 5 #define POP_PC() pop {pc} #else #define POP_PC() \ pop {ip}; \ JMP(ip) #endif #if __ARM_ARCH_ISA_THUMB == 2 #define IT(cond) it cond #define ITT(cond) itt cond #else #define IT(cond) #define ITT(cond) #endif #if __ARM_ARCH_ISA_THUMB == 2 #define WIDE(op) op.w #else #define WIDE(op) op #endif #endif #define GLUE2(a, b) a##b #define GLUE(a, b) GLUE2(a, b) #define SYMBOL_NAME(name) GLUE(__USER_LABEL_PREFIX__, name) #ifdef VISIBILITY_HIDDEN #define DECLARE_SYMBOL_VISIBILITY(name) \ HIDDEN(SYMBOL_NAME(name)) SEPARATOR #else #define DECLARE_SYMBOL_VISIBILITY(name) #endif #define DEFINE_COMPILERRT_FUNCTION(name) \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ DECLARE_SYMBOL_VISIBILITY(name) \ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ DECLARE_SYMBOL_VISIBILITY(name) SEPARATOR \ .thumb_func SEPARATOR \ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \ FILE_LEVEL_DIRECTIVE SEPARATOR \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ HIDDEN(SYMBOL_NAME(name)) SEPARATOR \ SYMBOL_NAME(name): #define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \ .globl name SEPARATOR \ SYMBOL_IS_FUNC(name) SEPARATOR \ HIDDEN(name) SEPARATOR \ name: #define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \ .globl SYMBOL_NAME(name) SEPARATOR \ SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \ DECLARE_SYMBOL_VISIBILITY(SYMBOL_NAME(name)) SEPARATOR \ .set SYMBOL_NAME(name), SYMBOL_NAME(target) SEPARATOR #if defined(__ARM_EABI__) #define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) \ DEFINE_COMPILERRT_FUNCTION_ALIAS(aeabi_name, name) #else #define DEFINE_AEABI_FUNCTION_ALIAS(aeabi_name, name) #endif #ifdef __ELF__ #define END_COMPILERRT_FUNCTION(name) \ .size SYMBOL_NAME(name), . - SYMBOL_NAME(name) #else #define END_COMPILERRT_FUNCTION(name) #endif #endif /* COMPILERRT_ASSEMBLY_H */ trusted-firmware-a-2.2/lib/compiler-rt/builtins/ctzdi2.c000066400000000000000000000015041355360272700233100ustar00rootroot00000000000000/* ===-- ctzdi2.c - Implement __ctzdi2 -------------------------------------=== * * 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 __ctzdi2 for the compiler_rt library. * * ===----------------------------------------------------------------------=== */ #include "int_lib.h" /* Returns: the number of trailing 0-bits */ /* Precondition: a != 0 */ COMPILER_RT_ABI si_int __ctzdi2(di_int a) { dwords x; x.all = a; const si_int f = -(x.s.low == 0); return __builtin_ctz((x.s.high & f) | (x.s.low & ~f)) + (f & ((si_int)(sizeof(si_int) * CHAR_BIT))); } trusted-firmware-a-2.2/lib/compiler-rt/builtins/int_endianness.h000066400000000000000000000055431355360272700251260ustar00rootroot00000000000000/* ===-- int_endianness.h - configuration header for compiler-rt ------------=== * * 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 is a configuration header for compiler-rt. * This file is not part of the interface of this library. * * ===----------------------------------------------------------------------=== */ #ifndef INT_ENDIANNESS_H #define INT_ENDIANNESS_H #if defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ defined(__ORDER_LITTLE_ENDIAN__) /* Clang and GCC provide built-in endianness definitions. */ #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ #define _YUGA_LITTLE_ENDIAN 0 #define _YUGA_BIG_ENDIAN 1 #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ #define _YUGA_LITTLE_ENDIAN 1 #define _YUGA_BIG_ENDIAN 0 #endif /* __BYTE_ORDER__ */ #else /* Compilers other than Clang or GCC. */ #if defined(__SVR4) && defined(__sun) #include #if defined(_BIG_ENDIAN) #define _YUGA_LITTLE_ENDIAN 0 #define _YUGA_BIG_ENDIAN 1 #elif defined(_LITTLE_ENDIAN) #define _YUGA_LITTLE_ENDIAN 1 #define _YUGA_BIG_ENDIAN 0 #else /* !_LITTLE_ENDIAN */ #error "unknown endianness" #endif /* !_LITTLE_ENDIAN */ #endif /* Solaris and AuroraUX. */ /* .. */ #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ defined(__minix) #include #if _BYTE_ORDER == _BIG_ENDIAN #define _YUGA_LITTLE_ENDIAN 0 #define _YUGA_BIG_ENDIAN 1 #elif _BYTE_ORDER == _LITTLE_ENDIAN #define _YUGA_LITTLE_ENDIAN 1 #define _YUGA_BIG_ENDIAN 0 #endif /* _BYTE_ORDER */ #endif /* *BSD */ #if defined(__OpenBSD__) || defined(__Bitrig__) #include #if _BYTE_ORDER == _BIG_ENDIAN #define _YUGA_LITTLE_ENDIAN 0 #define _YUGA_BIG_ENDIAN 1 #elif _BYTE_ORDER == _LITTLE_ENDIAN #define _YUGA_LITTLE_ENDIAN 1 #define _YUGA_BIG_ENDIAN 0 #endif /* _BYTE_ORDER */ #endif /* OpenBSD and Bitrig. */ /* .. */ /* Mac OSX has __BIG_ENDIAN__ or __LITTLE_ENDIAN__ automatically set by the * compiler (at least with GCC) */ #if defined(__APPLE__) || defined(__ellcc__ ) #ifdef __BIG_ENDIAN__ #if __BIG_ENDIAN__ #define _YUGA_LITTLE_ENDIAN 0 #define _YUGA_BIG_ENDIAN 1 #endif #endif /* __BIG_ENDIAN__ */ #ifdef __LITTLE_ENDIAN__ #if __LITTLE_ENDIAN__ #define _YUGA_LITTLE_ENDIAN 1 #define _YUGA_BIG_ENDIAN 0 #endif #endif /* __LITTLE_ENDIAN__ */ #endif /* Mac OSX */ /* .. */ #if defined(_WIN32) #define _YUGA_LITTLE_ENDIAN 1 #define _YUGA_BIG_ENDIAN 0 #endif /* Windows */ #endif /* Clang or GCC. */ /* . */ #if !defined(_YUGA_LITTLE_ENDIAN) || !defined(_YUGA_BIG_ENDIAN) #error Unable to determine endian #endif /* Check we found an endianness correctly. */ #endif /* INT_ENDIANNESS_H */ trusted-firmware-a-2.2/lib/compiler-rt/builtins/int_lib.h000066400000000000000000000072701355360272700235440ustar00rootroot00000000000000/* ===-- int_lib.h - configuration header for compiler-rt -----------------=== * * 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 is a configuration header for compiler-rt. * This file is not part of the interface of this library. * * ===----------------------------------------------------------------------=== */ /* * Portions copyright (c) 2017-2018, ARM Limited and Contributors. * All rights reserved. */ #ifndef INT_LIB_H #define INT_LIB_H /* Assumption: Signed integral is 2's complement. */ /* Assumption: Right shift of signed negative is arithmetic shift. */ /* Assumption: Endianness is little or big (not mixed). */ #if defined(__ELF__) #define FNALIAS(alias_name, 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__ # ifdef COMPILER_RT_ARMHF_TARGET # define COMPILER_RT_ABI # else # define COMPILER_RT_ABI __attribute__((__pcs__("aapcs"))) # endif #else # define COMPILER_RT_ABI #endif #define AEABI_RTABI __attribute__((__pcs__("aapcs"))) #if defined(_MSC_VER) && !defined(__clang__) #define ALWAYS_INLINE __forceinline #define NOINLINE __declspec(noinline) #define NORETURN __declspec(noreturn) #define UNUSED #else #define ALWAYS_INLINE __attribute__((always_inline)) #define NOINLINE __attribute__((noinline)) #define NORETURN __attribute__((noreturn)) #define UNUSED __attribute__((unused)) #endif /* * Kernel and boot environment can't use normal headers, * so use the equivalent system headers. */ # include # include /* Include the commonly used internal type definitions. */ #include "int_types.h" COMPILER_RT_ABI si_int __paritysi2(si_int a); COMPILER_RT_ABI si_int __paritydi2(di_int a); COMPILER_RT_ABI di_int __divdi3(di_int a, di_int b); COMPILER_RT_ABI si_int __divsi3(si_int a, si_int b); COMPILER_RT_ABI su_int __udivsi3(su_int n, su_int d); COMPILER_RT_ABI su_int __udivmodsi4(su_int a, su_int b, su_int* rem); COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int* rem); #ifdef CRT_HAS_128BIT COMPILER_RT_ABI si_int __clzti2(ti_int a); COMPILER_RT_ABI tu_int __udivmodti4(tu_int a, tu_int b, tu_int* rem); #endif /* Definitions for builtins unavailable on MSVC */ #if defined(_MSC_VER) && !defined(__clang__) #include uint32_t __inline __builtin_ctz(uint32_t value) { unsigned long trailing_zero = 0; if (_BitScanForward(&trailing_zero, value)) return trailing_zero; return 32; } uint32_t __inline __builtin_clz(uint32_t value) { unsigned long leading_zero = 0; if (_BitScanReverse(&leading_zero, value)) return 31 - leading_zero; return 32; } #if defined(_M_ARM) || defined(_M_X64) uint32_t __inline __builtin_clzll(uint64_t value) { unsigned long leading_zero = 0; if (_BitScanReverse64(&leading_zero, value)) return 63 - leading_zero; return 64; } #else uint32_t __inline __builtin_clzll(uint64_t value) { if (value == 0) return 64; uint32_t msh = (uint32_t)(value >> 32); uint32_t lsh = (uint32_t)(value & 0xFFFFFFFF); if (msh != 0) return __builtin_clz(msh); return 32 + __builtin_clz(lsh); } #endif #define __builtin_clzl __builtin_clzll #endif /* defined(_MSC_VER) && !defined(__clang__) */ #endif /* INT_LIB_H */ trusted-firmware-a-2.2/lib/compiler-rt/builtins/int_math.h000066400000000000000000000071111355360272700237210ustar00rootroot00000000000000/* ===-- int_math.h - internal math inlines ---------------------------------=== * * 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 is not part of the interface of this library. * * This file defines substitutes for the libm functions used in some of the * compiler-rt implementations, defined in such a way that there is not a direct * dependency on libm or math.h. Instead, we use the compiler builtin versions * where available. This reduces our dependencies on the system SDK by foisting * the responsibility onto the compiler. * * ===-----------------------------------------------------------------------=== */ #ifndef INT_MATH_H #define INT_MATH_H #ifndef __has_builtin # define __has_builtin(x) 0 #endif #if defined(_MSC_VER) && !defined(__clang__) #include #include #include #endif #if defined(_MSC_VER) && !defined(__clang__) #define CRT_INFINITY INFINITY #else #define CRT_INFINITY __builtin_huge_valf() #endif #if defined(_MSC_VER) && !defined(__clang__) #define crt_isfinite(x) _finite((x)) #define crt_isinf(x) !_finite((x)) #define crt_isnan(x) _isnan((x)) #else /* Define crt_isfinite in terms of the builtin if available, otherwise provide * an alternate version in terms of our other functions. This supports some * versions of GCC which didn't have __builtin_isfinite. */ #if __has_builtin(__builtin_isfinite) # define crt_isfinite(x) __builtin_isfinite((x)) #elif defined(__GNUC__) # define crt_isfinite(x) \ __extension__(({ \ __typeof((x)) x_ = (x); \ !crt_isinf(x_) && !crt_isnan(x_); \ })) #else # error "Do not know how to check for infinity" #endif /* __has_builtin(__builtin_isfinite) */ #define crt_isinf(x) __builtin_isinf((x)) #define crt_isnan(x) __builtin_isnan((x)) #endif /* _MSC_VER */ #if defined(_MSC_VER) && !defined(__clang__) #define crt_copysign(x, y) copysign((x), (y)) #define crt_copysignf(x, y) copysignf((x), (y)) #define crt_copysignl(x, y) copysignl((x), (y)) #else #define crt_copysign(x, y) __builtin_copysign((x), (y)) #define crt_copysignf(x, y) __builtin_copysignf((x), (y)) #define crt_copysignl(x, y) __builtin_copysignl((x), (y)) #endif #if defined(_MSC_VER) && !defined(__clang__) #define crt_fabs(x) fabs((x)) #define crt_fabsf(x) fabsf((x)) #define crt_fabsl(x) fabs((x)) #else #define crt_fabs(x) __builtin_fabs((x)) #define crt_fabsf(x) __builtin_fabsf((x)) #define crt_fabsl(x) __builtin_fabsl((x)) #endif #if defined(_MSC_VER) && !defined(__clang__) #define crt_fmax(x, y) __max((x), (y)) #define crt_fmaxf(x, y) __max((x), (y)) #define crt_fmaxl(x, y) __max((x), (y)) #else #define crt_fmax(x, y) __builtin_fmax((x), (y)) #define crt_fmaxf(x, y) __builtin_fmaxf((x), (y)) #define crt_fmaxl(x, y) __builtin_fmaxl((x), (y)) #endif #if defined(_MSC_VER) && !defined(__clang__) #define crt_logb(x) logb((x)) #define crt_logbf(x) logbf((x)) #define crt_logbl(x) logbl((x)) #else #define crt_logb(x) __builtin_logb((x)) #define crt_logbf(x) __builtin_logbf((x)) #define crt_logbl(x) __builtin_logbl((x)) #endif #if defined(_MSC_VER) && !defined(__clang__) #define crt_scalbn(x, y) scalbn((x), (y)) #define crt_scalbnf(x, y) scalbnf((x), (y)) #define crt_scalbnl(x, y) scalbnl((x), (y)) #else #define crt_scalbn(x, y) __builtin_scalbn((x), (y)) #define crt_scalbnf(x, y) __builtin_scalbnf((x), (y)) #define crt_scalbnl(x, y) __builtin_scalbnl((x), (y)) #endif #endif /* INT_MATH_H */ trusted-firmware-a-2.2/lib/compiler-rt/builtins/int_types.h000066400000000000000000000061671355360272700241460ustar00rootroot00000000000000/* ===-- int_lib.h - configuration header for compiler-rt -----------------=== * * 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 is not part of the interface of this library. * * This file defines various standard types, most importantly a number of unions * used to access parts of larger types. * * ===----------------------------------------------------------------------=== */ #ifndef INT_TYPES_H #define INT_TYPES_H #include "int_endianness.h" /* si_int is defined in Linux sysroot's asm-generic/siginfo.h */ #ifdef si_int #undef si_int #endif typedef int si_int; typedef unsigned su_int; typedef long long di_int; typedef unsigned long long du_int; typedef union { di_int all; struct { #if _YUGA_LITTLE_ENDIAN su_int low; si_int high; #else si_int high; su_int low; #endif /* _YUGA_LITTLE_ENDIAN */ }s; } dwords; typedef union { du_int all; struct { #if _YUGA_LITTLE_ENDIAN su_int low; su_int high; #else su_int high; su_int low; #endif /* _YUGA_LITTLE_ENDIAN */ }s; } udwords; /* MIPS64 issue: PR 20098 */ #if (defined(__LP64__) || defined(__wasm__)) && \ !(defined(__mips__) && defined(__clang__)) #define CRT_HAS_128BIT #endif #ifdef CRT_HAS_128BIT typedef int ti_int __attribute__ ((mode (TI))); typedef unsigned tu_int __attribute__ ((mode (TI))); typedef union { ti_int all; struct { #if _YUGA_LITTLE_ENDIAN du_int low; di_int high; #else di_int high; du_int low; #endif /* _YUGA_LITTLE_ENDIAN */ }s; } twords; typedef union { tu_int all; struct { #if _YUGA_LITTLE_ENDIAN du_int low; du_int high; #else du_int high; du_int low; #endif /* _YUGA_LITTLE_ENDIAN */ }s; } utwords; static __inline ti_int make_ti(di_int h, di_int l) { twords r; r.s.high = h; r.s.low = l; return r.all; } static __inline tu_int make_tu(du_int h, du_int l) { utwords r; r.s.high = h; r.s.low = l; return r.all; } #endif /* CRT_HAS_128BIT */ typedef union { su_int u; float f; } float_bits; typedef union { udwords u; double f; } double_bits; typedef struct { #if _YUGA_LITTLE_ENDIAN udwords low; udwords high; #else udwords high; udwords low; #endif /* _YUGA_LITTLE_ENDIAN */ } uqwords; typedef union { uqwords u; long double f; } long_double_bits; #if __STDC_VERSION__ >= 199901L typedef float _Complex Fcomplex; typedef double _Complex Dcomplex; typedef long double _Complex Lcomplex; #define COMPLEX_REAL(x) __real__(x) #define COMPLEX_IMAGINARY(x) __imag__(x) #else typedef struct { float real, imaginary; } Fcomplex; typedef struct { double real, imaginary; } Dcomplex; typedef struct { long double real, imaginary; } Lcomplex; #define COMPLEX_REAL(x) (x).real #define COMPLEX_IMAGINARY(x) (x).imaginary #endif #endif /* INT_TYPES_H */ trusted-firmware-a-2.2/lib/compiler-rt/builtins/lshrdi3.c000066400000000000000000000024321355360272700234620ustar00rootroot00000000000000/* ===-- 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 trusted-firmware-a-2.2/lib/compiler-rt/builtins/udivmoddi4.c000066400000000000000000000147651355360272700241760ustar00rootroot00000000000000/* ===-- udivmoddi4.c - Implement __udivmoddi4 -----------------------------=== * * 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 __udivmoddi4 for the compiler_rt library. * * ===----------------------------------------------------------------------=== */ #include "int_lib.h" /* Effects: if rem != 0, *rem = a % b * Returns: a / b */ /* Translated from Figure 3-40 of The PowerPC Compiler Writer's Guide */ COMPILER_RT_ABI du_int __udivmoddi4(du_int a, du_int b, du_int* rem) { const unsigned n_uword_bits = sizeof(su_int) * CHAR_BIT; const unsigned n_udword_bits = sizeof(du_int) * CHAR_BIT; udwords n; n.all = a; udwords d; d.all = b; udwords q; udwords r; unsigned sr; /* special cases, X is unknown, K != 0 */ if (n.s.high == 0) { if (d.s.high == 0) { /* 0 X * --- * 0 X */ if (rem) *rem = n.s.low % d.s.low; return n.s.low / d.s.low; } /* 0 X * --- * K X */ if (rem) *rem = n.s.low; return 0; } /* n.s.high != 0 */ if (d.s.low == 0) { if (d.s.high == 0) { /* K X * --- * 0 0 */ if (rem) *rem = n.s.high % d.s.low; return n.s.high / d.s.low; } /* d.s.high != 0 */ if (n.s.low == 0) { /* K 0 * --- * K 0 */ if (rem) { r.s.high = n.s.high % d.s.high; r.s.low = 0; *rem = r.all; } return n.s.high / d.s.high; } /* K K * --- * K 0 */ if ((d.s.high & (d.s.high - 1)) == 0) /* if d is a power of 2 */ { if (rem) { r.s.low = n.s.low; r.s.high = n.s.high & (d.s.high - 1); *rem = r.all; } return n.s.high >> __builtin_ctz(d.s.high); } /* K K * --- * K 0 */ sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); /* 0 <= sr <= n_uword_bits - 2 or sr large */ if (sr > n_uword_bits - 2) { if (rem) *rem = n.all; return 0; } ++sr; /* 1 <= sr <= n_uword_bits - 1 */ /* q.all = n.all << (n_udword_bits - sr); */ q.s.low = 0; q.s.high = n.s.low << (n_uword_bits - sr); /* r.all = n.all >> sr; */ r.s.high = n.s.high >> sr; r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); } else /* d.s.low != 0 */ { if (d.s.high == 0) { /* K X * --- * 0 K */ if ((d.s.low & (d.s.low - 1)) == 0) /* if d is a power of 2 */ { if (rem) *rem = n.s.low & (d.s.low - 1); if (d.s.low == 1) return n.all; sr = __builtin_ctz(d.s.low); q.s.high = n.s.high >> sr; q.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); return q.all; } /* K X * --- * 0 K */ sr = 1 + n_uword_bits + __builtin_clz(d.s.low) - __builtin_clz(n.s.high); /* 2 <= sr <= n_udword_bits - 1 * q.all = n.all << (n_udword_bits - sr); * r.all = n.all >> sr; */ if (sr == n_uword_bits) { q.s.low = 0; q.s.high = n.s.low; r.s.high = 0; r.s.low = n.s.high; } else if (sr < n_uword_bits) // 2 <= sr <= n_uword_bits - 1 { q.s.low = 0; q.s.high = n.s.low << (n_uword_bits - sr); r.s.high = n.s.high >> sr; r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); } else // n_uword_bits + 1 <= sr <= n_udword_bits - 1 { q.s.low = n.s.low << (n_udword_bits - sr); q.s.high = (n.s.high << (n_udword_bits - sr)) | (n.s.low >> (sr - n_uword_bits)); r.s.high = 0; r.s.low = n.s.high >> (sr - n_uword_bits); } } else { /* K X * --- * K K */ sr = __builtin_clz(d.s.high) - __builtin_clz(n.s.high); /* 0 <= sr <= n_uword_bits - 1 or sr large */ if (sr > n_uword_bits - 1) { if (rem) *rem = n.all; return 0; } ++sr; /* 1 <= sr <= n_uword_bits */ /* q.all = n.all << (n_udword_bits - sr); */ q.s.low = 0; if (sr == n_uword_bits) { q.s.high = n.s.low; r.s.high = 0; r.s.low = n.s.high; } else { q.s.high = n.s.low << (n_uword_bits - sr); r.s.high = n.s.high >> sr; r.s.low = (n.s.high << (n_uword_bits - sr)) | (n.s.low >> sr); } } } /* Not a special case * q and r are initialized with: * q.all = n.all << (n_udword_bits - sr); * r.all = n.all >> sr; * 1 <= sr <= n_udword_bits - 1 */ su_int carry = 0; for (; sr > 0; --sr) { /* r:q = ((r:q) << 1) | carry */ r.s.high = (r.s.high << 1) | (r.s.low >> (n_uword_bits - 1)); r.s.low = (r.s.low << 1) | (q.s.high >> (n_uword_bits - 1)); q.s.high = (q.s.high << 1) | (q.s.low >> (n_uword_bits - 1)); q.s.low = (q.s.low << 1) | carry; /* carry = 0; * if (r.all >= d.all) * { * r.all -= d.all; * carry = 1; * } */ const di_int s = (di_int)(d.all - r.all - 1) >> (n_udword_bits - 1); carry = s & 1; r.all -= d.all & s; } q.all = (q.all << 1) | carry; if (rem) *rem = r.all; return q.all; } trusted-firmware-a-2.2/lib/compiler-rt/compiler-rt.mk000066400000000000000000000033261355360272700227060ustar00rootroot00000000000000# # Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # Redistributions of source code must retain the above copyright notice, this # list of conditions and the following disclaimer. # # Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # Neither the name of ARM nor the names of its contributors may be used # to endorse or promote products derived from this software without specific # prior written permission. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # 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/lshrdi3.c endif trusted-firmware-a-2.2/lib/coreboot/000077500000000000000000000000001355360272700174735ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/coreboot/coreboot.mk000066400000000000000000000007431355360272700216440ustar00rootroot00000000000000# # Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # COREBOOT := 0 $(eval $(call assert_boolean,COREBOOT)) $(eval $(call add_define,COREBOOT)) ifeq (${COREBOOT},1) ifneq (${ARCH},aarch64) $(error "coreboot only supports Trusted Firmware on AArch64.") endif BL31_SOURCES += $(addprefix lib/coreboot/, \ coreboot_table.c) BL31_SOURCES += drivers/coreboot/cbmem_console/${ARCH}/cbmem_console.S endif # COREBOOT trusted-firmware-a-2.2/lib/coreboot/coreboot_table.c000066400000000000000000000061431355360272700226260ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* * Structures describing coreboot's in-memory descriptor tables. See * /src/commonlib/include/commonlib/coreboot_tables.h for * canonical implementation. */ typedef struct { char signature[4]; uint32_t header_bytes; uint32_t header_checksum; uint32_t table_bytes; uint32_t table_checksum; uint32_t table_entries; } cb_header_t; typedef enum { CB_TAG_SERIAL = 0xf, CB_TAG_CBMEM_CONSOLE = 0x17, } cb_tag_t; typedef struct { uint32_t tag; uint32_t size; union { coreboot_serial_t serial; uint64_t uint64; }; } cb_entry_t; coreboot_serial_t coreboot_serial; /* * The coreboot table is parsed before the MMU is enabled (i.e. with strongly * ordered memory), so we cannot make unaligned accesses. The table entries * immediately follow one another without padding, so nothing after the header * is guaranteed to be naturally aligned. Therefore, we need to define safety * functions that can read unaligned integers. */ static uint32_t read_le32(uint32_t *p) { uintptr_t addr = (uintptr_t)p; return mmio_read_8(addr) | mmio_read_8(addr + 1) << 8 | mmio_read_8(addr + 2) << 16 | mmio_read_8(addr + 3) << 24; } static uint64_t read_le64(uint64_t *p) { return read_le32((void *)p) | (uint64_t)read_le32((void *)p + 4) << 32; } static void expand_and_mmap(uintptr_t baseaddr, size_t size) { uintptr_t pageaddr = round_down(baseaddr, PAGE_SIZE); size_t expanded = round_up(baseaddr - pageaddr + size, PAGE_SIZE); mmap_add_region(pageaddr, pageaddr, expanded, MT_MEMORY | MT_RW | MT_NS | MT_EXECUTE_NEVER); } static void setup_cbmem_console(uintptr_t baseaddr) { static console_cbmc_t console; assert(!console.base); /* should only have one CBMEM console */ /* CBMEM console structure stores its size in first header field. */ uint32_t size = *(uint32_t *)baseaddr; expand_and_mmap(baseaddr, size); console_cbmc_register(baseaddr, &console); console_set_scope(&console.console, CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH); } void coreboot_table_setup(void *base) { cb_header_t *header = base; void *ptr; int i; if (strncmp(header->signature, "LBIO", 4)) { ERROR("coreboot table signature corrupt!\n"); return; } ptr = base + header->header_bytes; for (i = 0; i < header->table_entries; i++) { cb_entry_t *entry = ptr; if (ptr - base >= header->header_bytes + header->table_bytes) { ERROR("coreboot table exceeds its bounds!\n"); break; } switch (read_le32(&entry->tag)) { case CB_TAG_SERIAL: memcpy(&coreboot_serial, &entry->serial, sizeof(coreboot_serial)); break; case CB_TAG_CBMEM_CONSOLE: setup_cbmem_console(read_le64(&entry->uint64)); break; default: /* There are many tags TF doesn't need to care about. */ break; } ptr += read_le32(&entry->size); } } trusted-firmware-a-2.2/lib/cpus/000077500000000000000000000000001355360272700166315ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/cpus/aarch32/000077500000000000000000000000001355360272700200545ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/cpus/aarch32/aem_generic.S000066400000000000000000000024031355360272700224350ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include func aem_generic_core_pwr_dwn /* Assert if cache is enabled */ #if ENABLE_ASSERTIONS ldcopr r0, SCTLR tst r0, #SCTLR_C_BIT ASM_ASSERT(eq) #endif /* --------------------------------------------- * Flush L1 cache to PoU. * --------------------------------------------- */ mov r0, #DC_OP_CISW b dcsw_op_louis endfunc aem_generic_core_pwr_dwn func aem_generic_cluster_pwr_dwn /* Assert if cache is enabled */ #if ENABLE_ASSERTIONS ldcopr r0, SCTLR tst r0, #SCTLR_C_BIT ASM_ASSERT(eq) #endif /* --------------------------------------------- * Flush L1 and L2 caches to PoC. * --------------------------------------------- */ mov r0, #DC_OP_CISW b dcsw_op_all endfunc aem_generic_cluster_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for AEM. Must follow AAPCS. */ func aem_generic_errata_report bx lr endfunc aem_generic_errata_report #endif /* cpu_ops for Base AEM FVP */ declare_cpu_ops aem_generic, BASE_AEM_MIDR, CPU_NO_RESET_FUNC, \ aem_generic_core_pwr_dwn, \ aem_generic_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch32/cortex_a12.S000066400000000000000000000030041355360272700221440ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include .macro assert_cache_enabled #if ENABLE_ASSERTIONS ldcopr r0, SCTLR tst r0, #SCTLR_C_BIT ASM_ASSERT(eq) #endif .endm func cortex_a12_disable_smp ldcopr r0, ACTLR bic r0, #CORTEX_A12_ACTLR_SMP_BIT stcopr r0, ACTLR isb dsb sy bx lr endfunc cortex_a12_disable_smp func cortex_a12_enable_smp ldcopr r0, ACTLR orr r0, #CORTEX_A12_ACTLR_SMP_BIT stcopr r0, ACTLR isb bx lr endfunc cortex_a12_enable_smp func cortex_a12_reset_func b cortex_a12_enable_smp endfunc cortex_a12_reset_func func cortex_a12_core_pwr_dwn push {r12, lr} assert_cache_enabled /* Flush L1 cache */ mov r0, #DC_OP_CISW bl dcsw_op_level1 /* Exit cluster coherency */ pop {r12, lr} b cortex_a12_disable_smp endfunc cortex_a12_core_pwr_dwn func cortex_a12_cluster_pwr_dwn push {r12, lr} assert_cache_enabled /* Flush L1 caches */ mov r0, #DC_OP_CISW bl dcsw_op_level1 bl plat_disable_acp /* Exit cluster coherency */ pop {r12, lr} b cortex_a12_disable_smp endfunc cortex_a12_cluster_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex-A12. Must follow AAPCS. */ func cortex_a12_errata_report bx lr endfunc cortex_a12_errata_report #endif declare_cpu_ops cortex_a12, CORTEX_A12_MIDR, \ cortex_a12_reset_func, \ cortex_a12_core_pwr_dwn, \ cortex_a12_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch32/cortex_a15.S000066400000000000000000000074401355360272700221570ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* * Cortex-A15 support LPAE and Virtualization Extensions. * Don't care if confiugration uses or not LPAE and VE. * Therefore, where we don't check ARCH_IS_ARMV7_WITH_LPAE/VE */ .macro assert_cache_enabled #if ENABLE_ASSERTIONS ldcopr r0, SCTLR tst r0, #SCTLR_C_BIT ASM_ASSERT(eq) #endif .endm func cortex_a15_disable_smp ldcopr r0, ACTLR bic r0, #CORTEX_A15_ACTLR_SMP_BIT stcopr r0, ACTLR isb #if ERRATA_A15_816470 /* * Invalidate any TLB address */ mov r0, #0 stcopr r0, TLBIMVA #endif dsb sy bx lr endfunc cortex_a15_disable_smp func cortex_a15_enable_smp ldcopr r0, ACTLR orr r0, #CORTEX_A15_ACTLR_SMP_BIT stcopr r0, ACTLR isb bx lr endfunc cortex_a15_enable_smp /* ---------------------------------------------------- * Errata Workaround for Cortex A15 Errata #816470. * This applies only to revision >= r3p0 of Cortex A15. * ---------------------------------------------------- */ func check_errata_816470 /* * Even though this is only needed for revision >= r3p0, it is always * applied because of the low cost of the workaround. */ mov r0, #ERRATA_APPLIES bx lr endfunc check_errata_816470 /* ---------------------------------------------------- * Errata Workaround for Cortex A15 Errata #827671. * This applies only to revision >= r3p0 of Cortex A15. * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * ---------------------------------------------------- */ func errata_a15_827671_wa /* * Compare r0 against revision r3p0 */ mov r2, lr bl check_errata_827671 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr r0, CORTEX_A15_ACTLR2 orr r0, #CORTEX_A15_ACTLR2_INV_DCC_BIT stcopr r0, CORTEX_A15_ACTLR2 isb 1: bx r2 endfunc errata_a15_827671_wa func check_errata_827671 mov r1, #0x30 b cpu_rev_var_hs endfunc check_errata_827671 func check_errata_cve_2017_5715 #if WORKAROUND_CVE_2017_5715 mov r0, #ERRATA_APPLIES #else mov r0, #ERRATA_MISSING #endif bx lr endfunc check_errata_cve_2017_5715 #if REPORT_ERRATA /* * Errata printing function for Cortex A15. Must follow AAPCS. */ func cortex_a15_errata_report push {r12, lr} bl cpu_get_rev_var mov r4, r0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata ERRATA_A15_816470, cortex_a15, 816470 report_errata ERRATA_A15_827671, cortex_a15, 827671 report_errata WORKAROUND_CVE_2017_5715, cortex_a15, cve_2017_5715 pop {r12, lr} bx lr endfunc cortex_a15_errata_report #endif func cortex_a15_reset_func mov r5, lr bl cpu_get_rev_var #if ERRATA_A15_827671 bl errata_a15_827671_wa #endif #if IMAGE_BL32 && WORKAROUND_CVE_2017_5715 ldcopr r0, ACTLR orr r0, #CORTEX_A15_ACTLR_INV_BTB_BIT stcopr r0, ACTLR ldr r0, =workaround_icache_inv_runtime_exceptions stcopr r0, VBAR stcopr r0, MVBAR /* isb will be applied in the course of the reset func */ #endif mov lr, r5 b cortex_a15_enable_smp endfunc cortex_a15_reset_func func cortex_a15_core_pwr_dwn push {r12, lr} assert_cache_enabled /* Flush L1 cache */ mov r0, #DC_OP_CISW bl dcsw_op_level1 /* Exit cluster coherency */ pop {r12, lr} b cortex_a15_disable_smp endfunc cortex_a15_core_pwr_dwn func cortex_a15_cluster_pwr_dwn push {r12, lr} assert_cache_enabled /* Flush L1 caches */ mov r0, #DC_OP_CISW bl dcsw_op_level1 bl plat_disable_acp /* Exit cluster coherency */ pop {r12, lr} b cortex_a15_disable_smp endfunc cortex_a15_cluster_pwr_dwn declare_cpu_ops cortex_a15, CORTEX_A15_MIDR, \ cortex_a15_reset_func, \ cortex_a15_core_pwr_dwn, \ cortex_a15_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch32/cortex_a17.S000066400000000000000000000073611355360272700221630ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include .macro assert_cache_enabled #if ENABLE_ASSERTIONS ldcopr r0, SCTLR tst r0, #SCTLR_C_BIT ASM_ASSERT(eq) #endif .endm func cortex_a17_disable_smp ldcopr r0, ACTLR bic r0, #CORTEX_A17_ACTLR_SMP_BIT stcopr r0, ACTLR isb dsb sy bx lr endfunc cortex_a17_disable_smp func cortex_a17_enable_smp ldcopr r0, ACTLR orr r0, #CORTEX_A17_ACTLR_SMP_BIT stcopr r0, ACTLR isb bx lr endfunc cortex_a17_enable_smp /* ---------------------------------------------------- * Errata Workaround for Cortex A17 Errata #852421. * This applies only to revision <= r1p2 of Cortex A17. * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * ---------------------------------------------------- */ func errata_a17_852421_wa /* * Compare r0 against revision r1p2 */ mov r2, lr bl check_errata_852421 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr r0, CORTEX_A17_IMP_DEF_REG1 orr r0, r0, #(1<<24) stcopr r0, CORTEX_A17_IMP_DEF_REG1 1: bx r2 endfunc errata_a17_852421_wa func check_errata_852421 mov r1, #0x12 b cpu_rev_var_ls endfunc check_errata_852421 /* ---------------------------------------------------- * Errata Workaround for Cortex A17 Errata #852423. * This applies only to revision <= r1p2 of Cortex A17. * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * ---------------------------------------------------- */ func errata_a17_852423_wa /* * Compare r0 against revision r1p2 */ mov r2, lr bl check_errata_852423 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr r0, CORTEX_A17_IMP_DEF_REG1 orr r0, r0, #(1<<12) stcopr r0, CORTEX_A17_IMP_DEF_REG1 1: bx r2 endfunc errata_a17_852423_wa func check_errata_852423 mov r1, #0x12 b cpu_rev_var_ls endfunc check_errata_852423 func check_errata_cve_2017_5715 #if WORKAROUND_CVE_2017_5715 mov r0, #ERRATA_APPLIES #else mov r0, #ERRATA_MISSING #endif bx lr endfunc check_errata_cve_2017_5715 #if REPORT_ERRATA /* * Errata printing function for Cortex A17. Must follow AAPCS. */ func cortex_a17_errata_report push {r12, lr} bl cpu_get_rev_var mov r4, r0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata ERRATA_A17_852421, cortex_a17, 852421 report_errata ERRATA_A17_852423, cortex_a17, 852423 report_errata WORKAROUND_CVE_2017_5715, cortex_a17, cve_2017_5715 pop {r12, lr} bx lr endfunc cortex_a17_errata_report #endif func cortex_a17_reset_func mov r5, lr bl cpu_get_rev_var mov r4, r0 #if ERRATA_A17_852421 mov r0, r4 bl errata_a17_852421_wa #endif #if ERRATA_A17_852423 mov r0, r4 bl errata_a17_852423_wa #endif #if IMAGE_BL32 && WORKAROUND_CVE_2017_5715 ldr r0, =workaround_bpiall_runtime_exceptions stcopr r0, VBAR stcopr r0, MVBAR /* isb will be applied in the course of the reset func */ #endif mov lr, r5 b cortex_a17_enable_smp endfunc cortex_a17_reset_func func cortex_a17_core_pwr_dwn push {r12, lr} assert_cache_enabled /* Flush L1 cache */ mov r0, #DC_OP_CISW bl dcsw_op_level1 /* Exit cluster coherency */ pop {r12, lr} b cortex_a17_disable_smp endfunc cortex_a17_core_pwr_dwn func cortex_a17_cluster_pwr_dwn push {r12, lr} assert_cache_enabled /* Flush L1 caches */ mov r0, #DC_OP_CISW bl dcsw_op_level1 bl plat_disable_acp /* Exit cluster coherency */ pop {r12, lr} b cortex_a17_disable_smp endfunc cortex_a17_cluster_pwr_dwn declare_cpu_ops cortex_a17, CORTEX_A17_MIDR, \ cortex_a17_reset_func, \ cortex_a17_core_pwr_dwn, \ cortex_a17_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch32/cortex_a32.S000066400000000000000000000064761355360272700221660ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* --------------------------------------------- * Disable intra-cluster coherency * Clobbers: r0-r1 * --------------------------------------------- */ func cortex_a32_disable_smp ldcopr16 r0, r1, CORTEX_A32_CPUECTLR_EL1 bic r0, r0, #CORTEX_A32_CPUECTLR_SMPEN_BIT stcopr16 r0, r1, CORTEX_A32_CPUECTLR_EL1 isb dsb sy bx lr endfunc cortex_a32_disable_smp /* ------------------------------------------------- * The CPU Ops reset function for Cortex-A32. * Clobbers: r0-r1 * ------------------------------------------------- */ func cortex_a32_reset_func /* --------------------------------------------- * Enable the SMP bit. * --------------------------------------------- */ ldcopr16 r0, r1, CORTEX_A32_CPUECTLR_EL1 orr r0, r0, #CORTEX_A32_CPUECTLR_SMPEN_BIT stcopr16 r0, r1, CORTEX_A32_CPUECTLR_EL1 isb bx lr endfunc cortex_a32_reset_func /* ---------------------------------------------------- * The CPU Ops core power down function for Cortex-A32. * Clobbers: r0-r3 * ---------------------------------------------------- */ func cortex_a32_core_pwr_dwn /* r12 is pushed to meet the 8 byte stack alignment requirement */ push {r12, lr} /* Assert if cache is enabled */ #if ENABLE_ASSERTIONS ldcopr r0, SCTLR tst r0, #SCTLR_C_BIT ASM_ASSERT(eq) #endif /* --------------------------------------------- * Flush L1 caches. * --------------------------------------------- */ mov r0, #DC_OP_CISW bl dcsw_op_level1 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ pop {r12, lr} b cortex_a32_disable_smp endfunc cortex_a32_core_pwr_dwn /* ------------------------------------------------------- * The CPU Ops cluster power down function for Cortex-A32. * Clobbers: r0-r3 * ------------------------------------------------------- */ func cortex_a32_cluster_pwr_dwn /* r12 is pushed to meet the 8 byte stack alignment requirement */ push {r12, lr} /* Assert if cache is enabled */ #if ENABLE_ASSERTIONS ldcopr r0, SCTLR tst r0, #SCTLR_C_BIT ASM_ASSERT(eq) #endif /* --------------------------------------------- * Flush L1 cache. * --------------------------------------------- */ mov r0, #DC_OP_CISW bl dcsw_op_level1 /* --------------------------------------------- * Disable the optional ACP. * --------------------------------------------- */ bl plat_disable_acp /* --------------------------------------------- * Flush L2 cache. * --------------------------------------------- */ mov r0, #DC_OP_CISW bl dcsw_op_level2 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ pop {r12, lr} b cortex_a32_disable_smp endfunc cortex_a32_cluster_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex-A32. Must follow AAPCS. */ func cortex_a32_errata_report bx lr endfunc cortex_a32_errata_report #endif declare_cpu_ops cortex_a32, CORTEX_A32_MIDR, \ cortex_a32_reset_func, \ cortex_a32_core_pwr_dwn, \ cortex_a32_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch32/cortex_a5.S000066400000000000000000000027541355360272700221010ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include .macro assert_cache_enabled #if ENABLE_ASSERTIONS ldcopr r0, SCTLR tst r0, #SCTLR_C_BIT ASM_ASSERT(eq) #endif .endm func cortex_a5_disable_smp ldcopr r0, ACTLR bic r0, #CORTEX_A5_ACTLR_SMP_BIT stcopr r0, ACTLR isb dsb sy bx lr endfunc cortex_a5_disable_smp func cortex_a5_enable_smp ldcopr r0, ACTLR orr r0, #CORTEX_A5_ACTLR_SMP_BIT stcopr r0, ACTLR isb bx lr endfunc cortex_a5_enable_smp func cortex_a5_reset_func b cortex_a5_enable_smp endfunc cortex_a5_reset_func func cortex_a5_core_pwr_dwn push {r12, lr} assert_cache_enabled /* Flush L1 cache */ mov r0, #DC_OP_CISW bl dcsw_op_level1 /* Exit cluster coherency */ pop {r12, lr} b cortex_a5_disable_smp endfunc cortex_a5_core_pwr_dwn func cortex_a5_cluster_pwr_dwn push {r12, lr} assert_cache_enabled /* Flush L1 caches */ mov r0, #DC_OP_CISW bl dcsw_op_level1 bl plat_disable_acp /* Exit cluster coherency */ pop {r12, lr} b cortex_a5_disable_smp endfunc cortex_a5_cluster_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex-A5. Must follow AAPCS. */ func cortex_a5_errata_report bx lr endfunc cortex_a5_errata_report #endif declare_cpu_ops cortex_a5, CORTEX_A5_MIDR, \ cortex_a5_reset_func, \ cortex_a5_core_pwr_dwn, \ cortex_a5_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch32/cortex_a53.S000066400000000000000000000203621355360272700221570ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #if A53_DISABLE_NON_TEMPORAL_HINT #undef ERRATA_A53_836870 #define ERRATA_A53_836870 1 #endif /* --------------------------------------------- * Disable intra-cluster coherency * --------------------------------------------- */ func cortex_a53_disable_smp ldcopr16 r0, r1, CORTEX_A53_ECTLR bic64_imm r0, r1, CORTEX_A53_ECTLR_SMP_BIT stcopr16 r0, r1, CORTEX_A53_ECTLR isb dsb sy bx lr endfunc cortex_a53_disable_smp /* --------------------------------------------------- * Errata Workaround for Cortex A53 Errata #819472. * This applies only to revision <= r0p1 of Cortex A53. * --------------------------------------------------- */ func check_errata_819472 /* * Even though this is only needed for revision <= r0p1, it * is always applied due to limitations of the current * errata framework. */ mov r0, #ERRATA_APPLIES bx lr endfunc check_errata_819472 /* --------------------------------------------------- * Errata Workaround for Cortex A53 Errata #824069. * This applies only to revision <= r0p2 of Cortex A53. * --------------------------------------------------- */ func check_errata_824069 /* * Even though this is only needed for revision <= r0p2, it * is always applied due to limitations of the current * errata framework. */ mov r0, #ERRATA_APPLIES bx lr endfunc check_errata_824069 /* -------------------------------------------------- * Errata Workaround for Cortex A53 Errata #826319. * This applies only to revision <= r0p2 of Cortex A53. * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * -------------------------------------------------- */ func errata_a53_826319_wa /* * Compare r0 against revision r0p2 */ mov r2, lr bl check_errata_826319 mov lr, r2 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr r0, CORTEX_A53_L2ACTLR bic r0, #CORTEX_A53_L2ACTLR_ENABLE_UNIQUECLEAN orr r0, #CORTEX_A53_L2ACTLR_DISABLE_CLEAN_PUSH stcopr r0, CORTEX_A53_L2ACTLR 1: bx lr endfunc errata_a53_826319_wa func check_errata_826319 mov r1, #0x02 b cpu_rev_var_ls endfunc check_errata_826319 /* --------------------------------------------------- * Errata Workaround for Cortex A53 Errata #827319. * This applies only to revision <= r0p2 of Cortex A53. * --------------------------------------------------- */ func check_errata_827319 /* * Even though this is only needed for revision <= r0p2, it * is always applied due to limitations of the current * errata framework. */ mov r0, #ERRATA_APPLIES bx lr endfunc check_errata_827319 /* --------------------------------------------------------------------- * Disable the cache non-temporal hint. * * This ignores the Transient allocation hint in the MAIR and treats * allocations the same as non-transient allocation types. As a result, * the LDNP and STNP instructions in AArch64 behave the same as the * equivalent LDP and STP instructions. * * This is relevant only for revisions <= r0p3 of Cortex-A53. * From r0p4 and onwards, the bit to disable the hint is enabled by * default at reset. * * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * --------------------------------------------------------------------- */ func a53_disable_non_temporal_hint /* * Compare r0 against revision r0p3 */ mov r2, lr bl check_errata_disable_non_temporal_hint mov lr, r2 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr16 r0, r1, CORTEX_A53_CPUACTLR orr64_imm r0, r1, CORTEX_A53_CPUACTLR_DTAH stcopr16 r0, r1, CORTEX_A53_CPUACTLR 1: bx lr endfunc a53_disable_non_temporal_hint func check_errata_disable_non_temporal_hint mov r1, #0x03 b cpu_rev_var_ls endfunc check_errata_disable_non_temporal_hint /* -------------------------------------------------- * Errata Workaround for Cortex A53 Errata #855873. * * This applies only to revisions >= r0p3 of Cortex A53. * Earlier revisions of the core are affected as well, but don't * have the chicken bit in the CPUACTLR register. It is expected that * the rich OS takes care of that, especially as the workaround is * shared with other erratas in those revisions of the CPU. * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * -------------------------------------------------- */ func errata_a53_855873_wa /* * Compare r0 against revision r0p3 and higher */ mov r2, lr bl check_errata_855873 mov lr, r2 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr16 r0, r1, CORTEX_A53_CPUACTLR orr64_imm r0, r1, CORTEX_A53_CPUACTLR_ENDCCASCI stcopr16 r0, r1, CORTEX_A53_CPUACTLR 1: bx lr endfunc errata_a53_855873_wa func check_errata_855873 mov r1, #0x03 b cpu_rev_var_hs endfunc check_errata_855873 /* ------------------------------------------------- * The CPU Ops reset function for Cortex-A53. * Shall clobber: r0-r6 * ------------------------------------------------- */ func cortex_a53_reset_func mov r5, lr bl cpu_get_rev_var mov r4, r0 #if ERRATA_A53_826319 mov r0, r4 bl errata_a53_826319_wa #endif #if ERRATA_A53_836870 mov r0, r4 bl a53_disable_non_temporal_hint #endif #if ERRATA_A53_855873 mov r0, r4 bl errata_a53_855873_wa #endif /* --------------------------------------------- * Enable the SMP bit. * --------------------------------------------- */ ldcopr16 r0, r1, CORTEX_A53_ECTLR orr64_imm r0, r1, CORTEX_A53_ECTLR_SMP_BIT stcopr16 r0, r1, CORTEX_A53_ECTLR isb bx r5 endfunc cortex_a53_reset_func /* ---------------------------------------------------- * The CPU Ops core power down function for Cortex-A53. * ---------------------------------------------------- */ func cortex_a53_core_pwr_dwn push {r12, lr} /* Assert if cache is enabled */ #if ENABLE_ASSERTIONS ldcopr r0, SCTLR tst r0, #SCTLR_C_BIT ASM_ASSERT(eq) #endif /* --------------------------------------------- * Flush L1 caches. * --------------------------------------------- */ mov r0, #DC_OP_CISW bl dcsw_op_level1 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ pop {r12, lr} b cortex_a53_disable_smp endfunc cortex_a53_core_pwr_dwn /* ------------------------------------------------------- * The CPU Ops cluster power down function for Cortex-A53. * Clobbers: r0-r3 * ------------------------------------------------------- */ func cortex_a53_cluster_pwr_dwn push {r12, lr} /* Assert if cache is enabled */ #if ENABLE_ASSERTIONS ldcopr r0, SCTLR tst r0, #SCTLR_C_BIT ASM_ASSERT(eq) #endif /* --------------------------------------------- * Flush L1 caches. * --------------------------------------------- */ mov r0, #DC_OP_CISW bl dcsw_op_level1 /* --------------------------------------------- * Disable the optional ACP. * --------------------------------------------- */ bl plat_disable_acp /* --------------------------------------------- * Flush L2 caches. * --------------------------------------------- */ mov r0, #DC_OP_CISW bl dcsw_op_level2 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ pop {r12, lr} b cortex_a53_disable_smp endfunc cortex_a53_cluster_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex A53. Must follow AAPCS. */ func cortex_a53_errata_report push {r12, lr} bl cpu_get_rev_var mov r4, r0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata ERRATA_A53_819472, cortex_a53, 819472 report_errata ERRATA_A53_824069, cortex_a53, 824069 report_errata ERRATA_A53_826319, cortex_a53, 826319 report_errata ERRATA_A53_827319, cortex_a53, 827319 report_errata ERRATA_A53_836870, cortex_a53, disable_non_temporal_hint report_errata ERRATA_A53_855873, cortex_a53, 855873 pop {r12, lr} bx lr endfunc cortex_a53_errata_report #endif declare_cpu_ops cortex_a53, CORTEX_A53_MIDR, \ cortex_a53_reset_func, \ cortex_a53_core_pwr_dwn, \ cortex_a53_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch32/cortex_a57.S000066400000000000000000000365231355360272700221710ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* --------------------------------------------- * Disable intra-cluster coherency * Clobbers: r0-r1 * --------------------------------------------- */ func cortex_a57_disable_smp ldcopr16 r0, r1, CORTEX_A57_ECTLR bic64_imm r0, r1, CORTEX_A57_ECTLR_SMP_BIT stcopr16 r0, r1, CORTEX_A57_ECTLR bx lr endfunc cortex_a57_disable_smp /* --------------------------------------------- * Disable all types of L2 prefetches. * Clobbers: r0-r2 * --------------------------------------------- */ func cortex_a57_disable_l2_prefetch ldcopr16 r0, r1, CORTEX_A57_ECTLR orr64_imm r0, r1, CORTEX_A57_ECTLR_DIS_TWD_ACC_PFTCH_BIT bic64_imm r0, r1, (CORTEX_A57_ECTLR_L2_IPFTCH_DIST_MASK | \ CORTEX_A57_ECTLR_L2_DPFTCH_DIST_MASK) stcopr16 r0, r1, CORTEX_A57_ECTLR isb dsb ish bx lr endfunc cortex_a57_disable_l2_prefetch /* --------------------------------------------- * Disable debug interfaces * --------------------------------------------- */ func cortex_a57_disable_ext_debug mov r0, #1 stcopr r0, DBGOSDLR isb #if ERRATA_A57_817169 /* * Invalidate any TLB address */ mov r0, #0 stcopr r0, TLBIMVA #endif dsb sy bx lr endfunc cortex_a57_disable_ext_debug /* -------------------------------------------------- * Errata Workaround for Cortex A57 Errata #806969. * This applies only to revision r0p0 of Cortex A57. * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * -------------------------------------------------- */ func errata_a57_806969_wa /* * Compare r0 against revision r0p0 */ mov r2, lr bl check_errata_806969 mov lr, r2 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr16 r0, r1, CORTEX_A57_CPUACTLR orr64_imm r0, r1, CORTEX_A57_CPUACTLR_NO_ALLOC_WBWA stcopr16 r0, r1, CORTEX_A57_CPUACTLR 1: bx lr endfunc errata_a57_806969_wa func check_errata_806969 mov r1, #0x00 b cpu_rev_var_ls endfunc check_errata_806969 /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #813419. * This applies only to revision r0p0 of Cortex A57. * --------------------------------------------------- */ func check_errata_813419 /* * Even though this is only needed for revision r0p0, it * is always applied due to limitations of the current * errata framework. */ mov r0, #ERRATA_APPLIES bx lr endfunc check_errata_813419 /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #813420. * This applies only to revision r0p0 of Cortex A57. * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * --------------------------------------------------- */ func errata_a57_813420_wa /* * Compare r0 against revision r0p0 */ mov r2, lr bl check_errata_813420 mov lr, r2 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr16 r0, r1, CORTEX_A57_CPUACTLR orr64_imm r0, r1, CORTEX_A57_CPUACTLR_DCC_AS_DCCI stcopr16 r0, r1, CORTEX_A57_CPUACTLR 1: bx lr endfunc errata_a57_813420_wa func check_errata_813420 mov r1, #0x00 b cpu_rev_var_ls endfunc check_errata_813420 /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #814670. * This applies only to revision r0p0 of Cortex A57. * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * --------------------------------------------------- */ func errata_a57_814670_wa /* * Compare r0 against revision r0p0 */ mov r2, lr bl check_errata_814670 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr16 r0, r1, CORTEX_A57_CPUACTLR orr64_imm r0, r1, CORTEX_A57_CPUACTLR_DIS_DMB_NULLIFICATION stcopr16 r0, r1, CORTEX_A57_CPUACTLR isb 1: bx r2 endfunc errata_a57_814670_wa func check_errata_814670 mov r1, #0x00 b cpu_rev_var_ls endfunc check_errata_814670 /* ---------------------------------------------------- * Errata Workaround for Cortex A57 Errata #817169. * This applies only to revision <= r0p1 of Cortex A57. * ---------------------------------------------------- */ func check_errata_817169 /* * Even though this is only needed for revision <= r0p1, it * is always applied because of the low cost of the workaround. */ mov r0, #ERRATA_APPLIES bx lr endfunc check_errata_817169 /* -------------------------------------------------------------------- * Disable the over-read from the LDNP instruction. * * This applies to all revisions <= r1p2. The performance degradation * observed with LDNP/STNP has been fixed on r1p3 and onwards. * * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * --------------------------------------------------------------------- */ func a57_disable_ldnp_overread /* * Compare r0 against revision r1p2 */ mov r2, lr bl check_errata_disable_ldnp_overread mov lr, r2 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr16 r0, r1, CORTEX_A57_CPUACTLR orr64_imm r0, r1, CORTEX_A57_CPUACTLR_DIS_OVERREAD stcopr16 r0, r1, CORTEX_A57_CPUACTLR 1: bx lr endfunc a57_disable_ldnp_overread func check_errata_disable_ldnp_overread mov r1, #0x12 b cpu_rev_var_ls endfunc check_errata_disable_ldnp_overread /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #826974. * This applies only to revision <= r1p1 of Cortex A57. * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * --------------------------------------------------- */ func errata_a57_826974_wa /* * Compare r0 against revision r1p1 */ mov r2, lr bl check_errata_826974 mov lr, r2 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr16 r0, r1, CORTEX_A57_CPUACTLR orr64_imm r0, r1, CORTEX_A57_CPUACTLR_DIS_LOAD_PASS_DMB stcopr16 r0, r1, CORTEX_A57_CPUACTLR 1: bx lr endfunc errata_a57_826974_wa func check_errata_826974 mov r1, #0x11 b cpu_rev_var_ls endfunc check_errata_826974 /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #826977. * This applies only to revision <= r1p1 of Cortex A57. * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * --------------------------------------------------- */ func errata_a57_826977_wa /* * Compare r0 against revision r1p1 */ mov r2, lr bl check_errata_826977 mov lr, r2 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr16 r0, r1, CORTEX_A57_CPUACTLR orr64_imm r0, r1, CORTEX_A57_CPUACTLR_GRE_NGRE_AS_NGNRE stcopr16 r0, r1, CORTEX_A57_CPUACTLR 1: bx lr endfunc errata_a57_826977_wa func check_errata_826977 mov r1, #0x11 b cpu_rev_var_ls endfunc check_errata_826977 /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #828024. * This applies only to revision <= r1p1 of Cortex A57. * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * --------------------------------------------------- */ func errata_a57_828024_wa /* * Compare r0 against revision r1p1 */ mov r2, lr bl check_errata_828024 mov lr, r2 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr16 r0, r1, CORTEX_A57_CPUACTLR /* * Setting the relevant bits in CORTEX_A57_CPUACTLR has to be done in 2 * instructions here because the resulting bitmask doesn't fit in a * 16-bit value so it cannot be encoded in a single instruction. */ orr64_imm r0, r1, CORTEX_A57_CPUACTLR_NO_ALLOC_WBWA orr64_imm r0, r1, (CORTEX_A57_CPUACTLR_DIS_L1_STREAMING | CORTEX_A57_CPUACTLR_DIS_STREAMING) stcopr16 r0, r1, CORTEX_A57_CPUACTLR 1: bx lr endfunc errata_a57_828024_wa func check_errata_828024 mov r1, #0x11 b cpu_rev_var_ls endfunc check_errata_828024 /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #829520. * This applies only to revision <= r1p2 of Cortex A57. * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * --------------------------------------------------- */ func errata_a57_829520_wa /* * Compare r0 against revision r1p2 */ mov r2, lr bl check_errata_829520 mov lr, r2 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr16 r0, r1, CORTEX_A57_CPUACTLR orr64_imm r0, r1, CORTEX_A57_CPUACTLR_DIS_INDIRECT_PREDICTOR stcopr16 r0, r1, CORTEX_A57_CPUACTLR 1: bx lr endfunc errata_a57_829520_wa func check_errata_829520 mov r1, #0x12 b cpu_rev_var_ls endfunc check_errata_829520 /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #833471. * This applies only to revision <= r1p2 of Cortex A57. * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * --------------------------------------------------- */ func errata_a57_833471_wa /* * Compare r0 against revision r1p2 */ mov r2, lr bl check_errata_833471 mov lr, r2 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr16 r0, r1, CORTEX_A57_CPUACTLR orr64_imm r1, r1, CORTEX_A57_CPUACTLR_FORCE_FPSCR_FLUSH stcopr16 r0, r1, CORTEX_A57_CPUACTLR 1: bx lr endfunc errata_a57_833471_wa func check_errata_833471 mov r1, #0x12 b cpu_rev_var_ls endfunc check_errata_833471 /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #859972. * This applies only to revision <= r1p3 of Cortex A57. * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * --------------------------------------------------- */ func errata_a57_859972_wa mov r2, lr bl check_errata_859972 mov lr, r2 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr16 r0, r1, CORTEX_A57_CPUACTLR orr64_imm r1, r1, CORTEX_A57_CPUACTLR_DIS_INSTR_PREFETCH stcopr16 r0, r1, CORTEX_A57_CPUACTLR 1: bx lr endfunc errata_a57_859972_wa func check_errata_859972 mov r1, #0x13 b cpu_rev_var_ls endfunc check_errata_859972 func check_errata_cve_2017_5715 mov r0, #ERRATA_MISSING bx lr endfunc check_errata_cve_2017_5715 func check_errata_cve_2018_3639 #if WORKAROUND_CVE_2018_3639 mov r0, #ERRATA_APPLIES #else mov r0, #ERRATA_MISSING #endif bx lr endfunc check_errata_cve_2018_3639 /* ------------------------------------------------- * The CPU Ops reset function for Cortex-A57. * Shall clobber: r0-r6 * ------------------------------------------------- */ func cortex_a57_reset_func mov r5, lr bl cpu_get_rev_var mov r4, r0 #if ERRATA_A57_806969 mov r0, r4 bl errata_a57_806969_wa #endif #if ERRATA_A57_813420 mov r0, r4 bl errata_a57_813420_wa #endif #if ERRATA_A57_814670 mov r0, r4 bl errata_a57_814670_wa #endif #if A57_DISABLE_NON_TEMPORAL_HINT mov r0, r4 bl a57_disable_ldnp_overread #endif #if ERRATA_A57_826974 mov r0, r4 bl errata_a57_826974_wa #endif #if ERRATA_A57_826977 mov r0, r4 bl errata_a57_826977_wa #endif #if ERRATA_A57_828024 mov r0, r4 bl errata_a57_828024_wa #endif #if ERRATA_A57_829520 mov r0, r4 bl errata_a57_829520_wa #endif #if ERRATA_A57_833471 mov r0, r4 bl errata_a57_833471_wa #endif #if ERRATA_A57_859972 mov r0, r4 bl errata_a57_859972_wa #endif #if WORKAROUND_CVE_2018_3639 ldcopr16 r0, r1, CORTEX_A57_CPUACTLR orr64_imm r0, r1, CORTEX_A57_CPUACTLR_DIS_LOAD_PASS_STORE stcopr16 r0, r1, CORTEX_A57_CPUACTLR isb dsb sy #endif /* --------------------------------------------- * Enable the SMP bit. * --------------------------------------------- */ ldcopr16 r0, r1, CORTEX_A57_ECTLR orr64_imm r0, r1, CORTEX_A57_ECTLR_SMP_BIT stcopr16 r0, r1, CORTEX_A57_ECTLR isb bx r5 endfunc cortex_a57_reset_func /* ---------------------------------------------------- * The CPU Ops core power down function for Cortex-A57. * ---------------------------------------------------- */ func cortex_a57_core_pwr_dwn push {r12, lr} /* Assert if cache is enabled */ #if ENABLE_ASSERTIONS ldcopr r0, SCTLR tst r0, #SCTLR_C_BIT ASM_ASSERT(eq) #endif /* --------------------------------------------- * Disable the L2 prefetches. * --------------------------------------------- */ bl cortex_a57_disable_l2_prefetch /* --------------------------------------------- * Flush L1 caches. * --------------------------------------------- */ mov r0, #DC_OP_CISW bl dcsw_op_level1 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ bl cortex_a57_disable_smp /* --------------------------------------------- * Force the debug interfaces to be quiescent * --------------------------------------------- */ pop {r12, lr} b cortex_a57_disable_ext_debug endfunc cortex_a57_core_pwr_dwn /* ------------------------------------------------------- * The CPU Ops cluster power down function for Cortex-A57. * Clobbers: r0-r3 * ------------------------------------------------------- */ func cortex_a57_cluster_pwr_dwn push {r12, lr} /* Assert if cache is enabled */ #if ENABLE_ASSERTIONS ldcopr r0, SCTLR tst r0, #SCTLR_C_BIT ASM_ASSERT(eq) #endif /* --------------------------------------------- * Disable the L2 prefetches. * --------------------------------------------- */ bl cortex_a57_disable_l2_prefetch /* --------------------------------------------- * Flush L1 caches. * --------------------------------------------- */ mov r0, #DC_OP_CISW bl dcsw_op_level1 /* --------------------------------------------- * Disable the optional ACP. * --------------------------------------------- */ bl plat_disable_acp /* --------------------------------------------- * Flush L2 caches. * --------------------------------------------- */ mov r0, #DC_OP_CISW bl dcsw_op_level2 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ bl cortex_a57_disable_smp /* --------------------------------------------- * Force the debug interfaces to be quiescent * --------------------------------------------- */ pop {r12, lr} b cortex_a57_disable_ext_debug endfunc cortex_a57_cluster_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex A57. Must follow AAPCS. */ func cortex_a57_errata_report push {r12, lr} bl cpu_get_rev_var mov r4, r0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata ERRATA_A57_806969, cortex_a57, 806969 report_errata ERRATA_A57_813419, cortex_a57, 813419 report_errata ERRATA_A57_813420, cortex_a57, 813420 report_errata ERRATA_A57_814670, cortex_a57, 814670 report_errata ERRATA_A57_817169, cortex_a57, 817169 report_errata A57_DISABLE_NON_TEMPORAL_HINT, cortex_a57, \ disable_ldnp_overread report_errata ERRATA_A57_826974, cortex_a57, 826974 report_errata ERRATA_A57_826977, cortex_a57, 826977 report_errata ERRATA_A57_828024, cortex_a57, 828024 report_errata ERRATA_A57_829520, cortex_a57, 829520 report_errata ERRATA_A57_833471, cortex_a57, 833471 report_errata ERRATA_A57_859972, cortex_a57, 859972 report_errata WORKAROUND_CVE_2017_5715, cortex_a57, cve_2017_5715 report_errata WORKAROUND_CVE_2018_3639, cortex_a57, cve_2018_3639 pop {r12, lr} bx lr endfunc cortex_a57_errata_report #endif declare_cpu_ops cortex_a57, CORTEX_A57_MIDR, \ cortex_a57_reset_func, \ cortex_a57_core_pwr_dwn, \ cortex_a57_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch32/cortex_a7.S000066400000000000000000000027541355360272700221030ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include .macro assert_cache_enabled #if ENABLE_ASSERTIONS ldcopr r0, SCTLR tst r0, #SCTLR_C_BIT ASM_ASSERT(eq) #endif .endm func cortex_a7_disable_smp ldcopr r0, ACTLR bic r0, #CORTEX_A7_ACTLR_SMP_BIT stcopr r0, ACTLR isb dsb sy bx lr endfunc cortex_a7_disable_smp func cortex_a7_enable_smp ldcopr r0, ACTLR orr r0, #CORTEX_A7_ACTLR_SMP_BIT stcopr r0, ACTLR isb bx lr endfunc cortex_a7_enable_smp func cortex_a7_reset_func b cortex_a7_enable_smp endfunc cortex_a7_reset_func func cortex_a7_core_pwr_dwn push {r12, lr} assert_cache_enabled /* Flush L1 cache */ mov r0, #DC_OP_CISW bl dcsw_op_level1 /* Exit cluster coherency */ pop {r12, lr} b cortex_a7_disable_smp endfunc cortex_a7_core_pwr_dwn func cortex_a7_cluster_pwr_dwn push {r12, lr} assert_cache_enabled /* Flush L1 caches */ mov r0, #DC_OP_CISW bl dcsw_op_level1 bl plat_disable_acp /* Exit cluster coherency */ pop {r12, lr} b cortex_a7_disable_smp endfunc cortex_a7_cluster_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex-A7. Must follow AAPCS. */ func cortex_a7_errata_report bx lr endfunc cortex_a7_errata_report #endif declare_cpu_ops cortex_a7, CORTEX_A7_MIDR, \ cortex_a7_reset_func, \ cortex_a7_core_pwr_dwn, \ cortex_a7_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch32/cortex_a72.S000066400000000000000000000156441355360272700221670ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* --------------------------------------------- * Disable all types of L2 prefetches. * --------------------------------------------- */ func cortex_a72_disable_l2_prefetch ldcopr16 r0, r1, CORTEX_A72_ECTLR orr64_imm r0, r1, CORTEX_A72_ECTLR_DIS_TWD_ACC_PFTCH_BIT bic64_imm r0, r1, (CORTEX_A72_ECTLR_L2_IPFTCH_DIST_MASK | \ CORTEX_A72_ECTLR_L2_DPFTCH_DIST_MASK) stcopr16 r0, r1, CORTEX_A72_ECTLR isb bx lr endfunc cortex_a72_disable_l2_prefetch /* --------------------------------------------- * Disable the load-store hardware prefetcher. * --------------------------------------------- */ func cortex_a72_disable_hw_prefetcher ldcopr16 r0, r1, CORTEX_A72_CPUACTLR orr64_imm r0, r1, CORTEX_A72_CPUACTLR_DISABLE_L1_DCACHE_HW_PFTCH stcopr16 r0, r1, CORTEX_A72_CPUACTLR isb dsb ish bx lr endfunc cortex_a72_disable_hw_prefetcher /* --------------------------------------------- * Disable intra-cluster coherency * Clobbers: r0-r1 * --------------------------------------------- */ func cortex_a72_disable_smp ldcopr16 r0, r1, CORTEX_A72_ECTLR bic64_imm r0, r1, CORTEX_A72_ECTLR_SMP_BIT stcopr16 r0, r1, CORTEX_A72_ECTLR bx lr endfunc cortex_a72_disable_smp /* --------------------------------------------- * Disable debug interfaces * --------------------------------------------- */ func cortex_a72_disable_ext_debug mov r0, #1 stcopr r0, DBGOSDLR isb dsb sy bx lr endfunc cortex_a72_disable_ext_debug /* --------------------------------------------------- * Errata Workaround for Cortex A72 Errata #859971. * This applies only to revision <= r0p3 of Cortex A72. * Inputs: * r0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: r0-r3 * --------------------------------------------------- */ func errata_a72_859971_wa mov r2,lr bl check_errata_859971 mov lr, r2 cmp r0, #ERRATA_NOT_APPLIES beq 1f ldcopr16 r0, r1, CORTEX_A72_CPUACTLR orr64_imm r1, r1, CORTEX_A72_CPUACTLR_DIS_INSTR_PREFETCH stcopr16 r0, r1, CORTEX_A72_CPUACTLR 1: bx lr endfunc errata_a72_859971_wa func check_errata_859971 mov r1, #0x03 b cpu_rev_var_ls endfunc check_errata_859971 func check_errata_cve_2017_5715 mov r0, #ERRATA_MISSING bx lr endfunc check_errata_cve_2017_5715 func check_errata_cve_2018_3639 #if WORKAROUND_CVE_2018_3639 mov r0, #ERRATA_APPLIES #else mov r0, #ERRATA_MISSING #endif bx lr endfunc check_errata_cve_2018_3639 /* ------------------------------------------------- * The CPU Ops reset function for Cortex-A72. * ------------------------------------------------- */ func cortex_a72_reset_func mov r5, lr bl cpu_get_rev_var mov r4, r0 #if ERRATA_A72_859971 mov r0, r4 bl errata_a72_859971_wa #endif #if WORKAROUND_CVE_2018_3639 ldcopr16 r0, r1, CORTEX_A72_CPUACTLR orr64_imm r0, r1, CORTEX_A72_CPUACTLR_DIS_LOAD_PASS_STORE stcopr16 r0, r1, CORTEX_A72_CPUACTLR isb dsb sy #endif /* --------------------------------------------- * Enable the SMP bit. * --------------------------------------------- */ ldcopr16 r0, r1, CORTEX_A72_ECTLR orr64_imm r0, r1, CORTEX_A72_ECTLR_SMP_BIT stcopr16 r0, r1, CORTEX_A72_ECTLR isb bx r5 endfunc cortex_a72_reset_func /* ---------------------------------------------------- * The CPU Ops core power down function for Cortex-A72. * ---------------------------------------------------- */ func cortex_a72_core_pwr_dwn push {r12, lr} /* Assert if cache is enabled */ #if ENABLE_ASSERTIONS ldcopr r0, SCTLR tst r0, #SCTLR_C_BIT ASM_ASSERT(eq) #endif /* --------------------------------------------- * Disable the L2 prefetches. * --------------------------------------------- */ bl cortex_a72_disable_l2_prefetch /* --------------------------------------------- * Disable the load-store hardware prefetcher. * --------------------------------------------- */ bl cortex_a72_disable_hw_prefetcher /* --------------------------------------------- * Flush L1 caches. * --------------------------------------------- */ mov r0, #DC_OP_CISW bl dcsw_op_level1 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ bl cortex_a72_disable_smp /* --------------------------------------------- * Force the debug interfaces to be quiescent * --------------------------------------------- */ pop {r12, lr} b cortex_a72_disable_ext_debug endfunc cortex_a72_core_pwr_dwn /* ------------------------------------------------------- * The CPU Ops cluster power down function for Cortex-A72. * ------------------------------------------------------- */ func cortex_a72_cluster_pwr_dwn push {r12, lr} /* Assert if cache is enabled */ #if ENABLE_ASSERTIONS ldcopr r0, SCTLR tst r0, #SCTLR_C_BIT ASM_ASSERT(eq) #endif /* --------------------------------------------- * Disable the L2 prefetches. * --------------------------------------------- */ bl cortex_a72_disable_l2_prefetch /* --------------------------------------------- * Disable the load-store hardware prefetcher. * --------------------------------------------- */ bl cortex_a72_disable_hw_prefetcher #if !SKIP_A72_L1_FLUSH_PWR_DWN /* --------------------------------------------- * Flush L1 caches. * --------------------------------------------- */ mov r0, #DC_OP_CISW bl dcsw_op_level1 #endif /* --------------------------------------------- * Disable the optional ACP. * --------------------------------------------- */ bl plat_disable_acp /* ------------------------------------------------- * Flush the L2 caches. * ------------------------------------------------- */ mov r0, #DC_OP_CISW bl dcsw_op_level2 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ bl cortex_a72_disable_smp /* --------------------------------------------- * Force the debug interfaces to be quiescent * --------------------------------------------- */ pop {r12, lr} b cortex_a72_disable_ext_debug endfunc cortex_a72_cluster_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex A72. Must follow AAPCS. */ func cortex_a72_errata_report push {r12, lr} bl cpu_get_rev_var mov r4, r0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata ERRATA_A72_859971, cortex_a72, 859971 report_errata WORKAROUND_CVE_2017_5715, cortex_a72, cve_2017_5715 report_errata WORKAROUND_CVE_2018_3639, cortex_a72, cve_2018_3639 pop {r12, lr} bx lr endfunc cortex_a72_errata_report #endif declare_cpu_ops cortex_a72, CORTEX_A72_MIDR, \ cortex_a72_reset_func, \ cortex_a72_core_pwr_dwn, \ cortex_a72_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch32/cortex_a9.S000066400000000000000000000044401355360272700220770ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include .macro assert_cache_enabled #if ENABLE_ASSERTIONS ldcopr r0, SCTLR tst r0, #SCTLR_C_BIT ASM_ASSERT(eq) #endif .endm func cortex_a9_disable_smp ldcopr r0, ACTLR bic r0, #CORTEX_A9_ACTLR_SMP_BIT stcopr r0, ACTLR isb dsb sy bx lr endfunc cortex_a9_disable_smp func cortex_a9_enable_smp ldcopr r0, ACTLR orr r0, #CORTEX_A9_ACTLR_SMP_BIT stcopr r0, ACTLR isb bx lr endfunc cortex_a9_enable_smp func check_errata_a9_794073 #if ERRATA_A9_794073 mov r0, #ERRATA_APPLIES #else mov r0, #ERRATA_MISSING #endif bx lr endfunc check_errata_cve_2017_5715 func check_errata_cve_2017_5715 #if WORKAROUND_CVE_2017_5715 mov r0, #ERRATA_APPLIES #else mov r0, #ERRATA_MISSING #endif bx lr endfunc check_errata_cve_2017_5715 #if REPORT_ERRATA /* * Errata printing function for Cortex A9. Must follow AAPCS. */ func cortex_a9_errata_report push {r12, lr} bl cpu_get_rev_var mov r4, r0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata WORKAROUND_CVE_2017_5715, cortex_a9, cve_2017_5715 report_errata ERRATA_A9_794073, cortex_a9, a9_79407 pop {r12, lr} bx lr endfunc cortex_a9_errata_report #endif func cortex_a9_reset_func #if IMAGE_BL32 && WORKAROUND_CVE_2017_5715 ldr r0, =workaround_bpiall_runtime_exceptions stcopr r0, VBAR stcopr r0, MVBAR /* isb will be applied in the course of the reset func */ #endif b cortex_a9_enable_smp endfunc cortex_a9_reset_func func cortex_a9_core_pwr_dwn push {r12, lr} assert_cache_enabled /* Flush L1 cache */ mov r0, #DC_OP_CISW bl dcsw_op_level1 /* Exit cluster coherency */ pop {r12, lr} b cortex_a9_disable_smp endfunc cortex_a9_core_pwr_dwn func cortex_a9_cluster_pwr_dwn push {r12, lr} assert_cache_enabled /* Flush L1 caches */ mov r0, #DC_OP_CISW bl dcsw_op_level1 bl plat_disable_acp /* Exit cluster coherency */ pop {r12, lr} b cortex_a9_disable_smp endfunc cortex_a9_cluster_pwr_dwn declare_cpu_ops cortex_a9, CORTEX_A9_MIDR, \ cortex_a9_reset_func, \ cortex_a9_core_pwr_dwn, \ cortex_a9_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch32/cpu_helpers.S000066400000000000000000000140371355360272700225160ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #if defined(IMAGE_BL1) || defined(IMAGE_BL32) || (defined(IMAGE_BL2) && BL2_AT_EL3) /* * The reset handler common to all platforms. After a matching * cpu_ops structure entry is found, the correponding reset_handler * in the cpu_ops is invoked. The reset handler is invoked very early * in the boot sequence and it is assumed that we can clobber r0 - r10 * without the need to follow AAPCS. * Clobbers: r0 - r10 */ .globl reset_handler func reset_handler mov r8, lr /* The plat_reset_handler can clobber r0 - r7 */ bl plat_reset_handler /* Get the matching cpu_ops pointer (clobbers: r0 - r5) */ bl get_cpu_ops_ptr #if ENABLE_ASSERTIONS cmp r0, #0 ASM_ASSERT(ne) #endif /* Get the cpu_ops reset handler */ ldr r1, [r0, #CPU_RESET_FUNC] cmp r1, #0 mov lr, r8 bxne r1 bx lr endfunc reset_handler #endif #ifdef IMAGE_BL32 /* The power down core and cluster is needed only in BL32 */ /* * void prepare_cpu_pwr_dwn(unsigned int power_level) * * Prepare CPU power down function for all platforms. The function takes * a domain level to be powered down as its parameter. After the cpu_ops * pointer is retrieved from cpu_data, the handler for requested power * level is called. */ .globl prepare_cpu_pwr_dwn func prepare_cpu_pwr_dwn /* * If the given power level exceeds CPU_MAX_PWR_DWN_OPS, we call the * power down handler for the last power level */ mov r2, #(CPU_MAX_PWR_DWN_OPS - 1) cmp r0, r2 movhi r0, r2 push {r0, lr} bl _cpu_data pop {r2, lr} ldr r0, [r0, #CPU_DATA_CPU_OPS_PTR] #if ENABLE_ASSERTIONS cmp r0, #0 ASM_ASSERT(ne) #endif /* Get the appropriate power down handler */ mov r1, #CPU_PWR_DWN_OPS add r1, r1, r2, lsl #2 ldr r1, [r0, r1] bx r1 endfunc prepare_cpu_pwr_dwn /* * Initializes the cpu_ops_ptr if not already initialized * in cpu_data. This must only be called after the data cache * is enabled. AAPCS is followed. */ .globl init_cpu_ops func init_cpu_ops push {r4 - r6, lr} bl _cpu_data mov r6, r0 ldr r1, [r0, #CPU_DATA_CPU_OPS_PTR] cmp r1, #0 bne 1f bl get_cpu_ops_ptr #if ENABLE_ASSERTIONS cmp r0, #0 ASM_ASSERT(ne) #endif str r0, [r6, #CPU_DATA_CPU_OPS_PTR]! 1: pop {r4 - r6, pc} endfunc init_cpu_ops #endif /* IMAGE_BL32 */ /* * The below function returns the cpu_ops structure matching the * midr of the core. It reads the MIDR and finds the matching * entry in cpu_ops entries. Only the implementation and part number * are used to match the entries. * Return : * r0 - The matching cpu_ops pointer on Success * r0 - 0 on failure. * Clobbers: r0 - r5 */ .globl get_cpu_ops_ptr func get_cpu_ops_ptr /* Get the cpu_ops start and end locations */ ldr r4, =(__CPU_OPS_START__ + CPU_MIDR) ldr r5, =(__CPU_OPS_END__ + CPU_MIDR) /* Initialize the return parameter */ mov r0, #0 /* Read the MIDR_EL1 */ ldcopr r2, MIDR ldr r3, =CPU_IMPL_PN_MASK /* Retain only the implementation and part number using mask */ and r2, r2, r3 1: /* Check if we have reached end of list */ cmp r4, r5 bhs error_exit /* load the midr from the cpu_ops */ ldr r1, [r4], #CPU_OPS_SIZE and r1, r1, r3 /* Check if midr matches to midr of this core */ cmp r1, r2 bne 1b /* Subtract the increment and offset to get the cpu-ops pointer */ sub r0, r4, #(CPU_OPS_SIZE + CPU_MIDR) error_exit: bx lr endfunc get_cpu_ops_ptr /* * Extract CPU revision and variant, and combine them into a single numeric for * easier comparison. */ .globl cpu_get_rev_var func cpu_get_rev_var ldcopr r1, MIDR /* * Extract the variant[23:20] and revision[3:0] from r1 and pack it in * r0[0:7] as variant[7:4] and revision[3:0]: * * First extract r1[23:16] to r0[7:0] and zero fill the rest. Then * extract r1[3:0] into r0[3:0] retaining other bits. */ ubfx r0, r1, #(MIDR_VAR_SHIFT - MIDR_REV_BITS), #(MIDR_REV_BITS + MIDR_VAR_BITS) bfi r0, r1, #MIDR_REV_SHIFT, #MIDR_REV_BITS bx lr endfunc cpu_get_rev_var /* * Compare the CPU's revision-variant (r0) with a given value (r1), for errata * application purposes. If the revision-variant is less than or same as a given * value, indicates that errata applies; otherwise not. */ .globl cpu_rev_var_ls func cpu_rev_var_ls cmp r0, r1 movls r0, #ERRATA_APPLIES movhi r0, #ERRATA_NOT_APPLIES bx lr endfunc cpu_rev_var_ls /* * Compare the CPU's revision-variant (r0) with a given value (r1), for errata * application purposes. If the revision-variant is higher than or same as a * given value, indicates that errata applies; otherwise not. */ .globl cpu_rev_var_hs func cpu_rev_var_hs cmp r0, r1 movge r0, #ERRATA_APPLIES movlt r0, #ERRATA_NOT_APPLIES bx lr endfunc cpu_rev_var_hs #if REPORT_ERRATA /* * void print_errata_status(void); * * Function to print errata status for CPUs of its class. Must be called only: * * - with MMU and data caches are enabled; * - after cpu_ops have been initialized in per-CPU data. */ .globl print_errata_status func print_errata_status /* r12 is pushed only for the sake of 8-byte stack alignment */ push {r4, r5, r12, lr} #ifdef IMAGE_BL1 /* * BL1 doesn't have per-CPU data. So retrieve the CPU operations * directly. */ bl get_cpu_ops_ptr ldr r0, [r0, #CPU_ERRATA_FUNC] cmp r0, #0 blxne r0 #else /* * Retrieve pointer to cpu_ops, and further, the errata printing * function. If it's non-NULL, jump to the function in turn. */ bl _cpu_data ldr r1, [r0, #CPU_DATA_CPU_OPS_PTR] ldr r0, [r1, #CPU_ERRATA_FUNC] cmp r0, #0 beq 1f mov r4, r0 /* * Load pointers to errata lock and printed flag. Call * errata_needs_reporting to check whether this CPU needs to report * errata status pertaining to its class. */ ldr r0, [r1, #CPU_ERRATA_LOCK] ldr r1, [r1, #CPU_ERRATA_PRINTED] bl errata_needs_reporting cmp r0, #0 blxne r4 1: #endif pop {r4, r5, r12, pc} endfunc print_errata_status #endif trusted-firmware-a-2.2/lib/cpus/aarch64/000077500000000000000000000000001355360272700200615ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/cpus/aarch64/aem_generic.S000066400000000000000000000056531355360272700224540ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include func aem_generic_core_pwr_dwn /* --------------------------------------------- * Disable the Data Cache. * --------------------------------------------- */ mrs x1, sctlr_el3 bic x1, x1, #SCTLR_C_BIT msr sctlr_el3, x1 isb /* --------------------------------------------- * AEM model supports L3 caches in which case L2 * will be private per core caches and flush * from L1 to L2 is not sufficient. * --------------------------------------------- */ mrs x1, clidr_el1 /* --------------------------------------------- * Check if L3 cache is implemented. * --------------------------------------------- */ tst x1, ((1 << CLIDR_FIELD_WIDTH) - 1) << CTYPE_SHIFT(3) /* --------------------------------------------- * There is no L3 cache, flush L1 to L2 only. * --------------------------------------------- */ mov x0, #DCCISW b.eq dcsw_op_level1 mov x18, x30 /* --------------------------------------------- * Flush L1 cache to L2. * --------------------------------------------- */ bl dcsw_op_level1 mov x30, x18 /* --------------------------------------------- * Flush L2 cache to L3. * --------------------------------------------- */ mov x0, #DCCISW b dcsw_op_level2 endfunc aem_generic_core_pwr_dwn func aem_generic_cluster_pwr_dwn /* --------------------------------------------- * Disable the Data Cache. * --------------------------------------------- */ mrs x1, sctlr_el3 bic x1, x1, #SCTLR_C_BIT msr sctlr_el3, x1 isb /* --------------------------------------------- * Flush all caches to PoC. * --------------------------------------------- */ mov x0, #DCCISW b dcsw_op_all endfunc aem_generic_cluster_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for AEM. Must follow AAPCS. */ func aem_generic_errata_report ret endfunc aem_generic_errata_report #endif /* --------------------------------------------- * This function provides cpu specific * register information for crash reporting. * It needs to return with x6 pointing to * a list of register names in ascii and * x8 - x15 having values of registers to be * reported. * --------------------------------------------- */ .section .rodata.aem_generic_regs, "aS" aem_generic_regs: /* The ascii list of register names to be reported */ .asciz "" /* no registers to report */ func aem_generic_cpu_reg_dump adr x6, aem_generic_regs ret endfunc aem_generic_cpu_reg_dump /* cpu_ops for Base AEM FVP */ declare_cpu_ops aem_generic, BASE_AEM_MIDR, CPU_NO_RESET_FUNC, \ aem_generic_core_pwr_dwn, \ aem_generic_cluster_pwr_dwn /* cpu_ops for Foundation FVP */ declare_cpu_ops aem_generic, FOUNDATION_AEM_MIDR, CPU_NO_RESET_FUNC, \ aem_generic_core_pwr_dwn, \ aem_generic_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/cortex_a35.S000066400000000000000000000113201355360272700221560ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* --------------------------------------------- * Disable L1 data cache and unified L2 cache * --------------------------------------------- */ func cortex_a35_disable_dcache mrs x1, sctlr_el3 bic x1, x1, #SCTLR_C_BIT msr sctlr_el3, x1 isb ret endfunc cortex_a35_disable_dcache /* --------------------------------------------- * Disable intra-cluster coherency * --------------------------------------------- */ func cortex_a35_disable_smp mrs x0, CORTEX_A35_CPUECTLR_EL1 bic x0, x0, #CORTEX_A35_CPUECTLR_SMPEN_BIT msr CORTEX_A35_CPUECTLR_EL1, x0 isb dsb sy ret endfunc cortex_a35_disable_smp /* --------------------------------------------------- * Errata Workaround for Cortex A35 Errata #855472. * This applies to revisions r0p0 of Cortex A35. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * --------------------------------------------------- */ func errata_a35_855472_wa /* * Compare x0 against revision r0p0 */ mov x17, x30 bl check_errata_855472 cbz x0, 1f mrs x1, CORTEX_A35_CPUACTLR_EL1 orr x1, x1, #CORTEX_A35_CPUACTLR_EL1_ENDCCASCI msr CORTEX_A35_CPUACTLR_EL1, x1 isb 1: ret x17 endfunc errata_a35_855472_wa func check_errata_855472 mov x1, #0x00 b cpu_rev_var_ls endfunc check_errata_855472 /* ------------------------------------------------- * The CPU Ops reset function for Cortex-A35. * Clobbers: x0 * ------------------------------------------------- */ func cortex_a35_reset_func mov x19, x30 bl cpu_get_rev_var #if ERRATA_A35_855472 bl errata_a35_855472_wa #endif /* --------------------------------------------- * Enable the SMP bit. * --------------------------------------------- */ mrs x0, CORTEX_A35_CPUECTLR_EL1 orr x0, x0, #CORTEX_A35_CPUECTLR_SMPEN_BIT msr CORTEX_A35_CPUECTLR_EL1, x0 isb ret x19 endfunc cortex_a35_reset_func func cortex_a35_core_pwr_dwn mov x18, x30 /* --------------------------------------------- * Turn off caches. * --------------------------------------------- */ bl cortex_a35_disable_dcache /* --------------------------------------------- * Flush L1 caches. * --------------------------------------------- */ mov x0, #DCCISW bl dcsw_op_level1 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ mov x30, x18 b cortex_a35_disable_smp endfunc cortex_a35_core_pwr_dwn func cortex_a35_cluster_pwr_dwn mov x18, x30 /* --------------------------------------------- * Turn off caches. * --------------------------------------------- */ bl cortex_a35_disable_dcache /* --------------------------------------------- * Flush L1 caches. * --------------------------------------------- */ mov x0, #DCCISW bl dcsw_op_level1 /* --------------------------------------------- * Disable the optional ACP. * --------------------------------------------- */ bl plat_disable_acp /* --------------------------------------------- * Flush L2 caches. * --------------------------------------------- */ mov x0, #DCCISW bl dcsw_op_level2 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ mov x30, x18 b cortex_a35_disable_smp endfunc cortex_a35_cluster_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex A35. Must follow AAPCS. */ func cortex_a35_errata_report stp x8, x30, [sp, #-16]! bl cpu_get_rev_var mov x8, x0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata ERRATA_A35_855472, cortex_a35, 855472 ldp x8, x30, [sp], #16 ret endfunc cortex_a35_errata_report #endif /* --------------------------------------------- * This function provides cortex_a35 specific * register information for crash reporting. * It needs to return with x6 pointing to * a list of register names in ascii and * x8 - x15 having values of registers to be * reported. * --------------------------------------------- */ .section .rodata.cortex_a35_regs, "aS" cortex_a35_regs: /* The ascii list of register names to be reported */ .asciz "cpuectlr_el1", "" func cortex_a35_cpu_reg_dump adr x6, cortex_a35_regs mrs x8, CORTEX_A35_CPUECTLR_EL1 ret endfunc cortex_a35_cpu_reg_dump declare_cpu_ops cortex_a35, CORTEX_A35_MIDR, \ cortex_a35_reset_func, \ cortex_a35_core_pwr_dwn, \ cortex_a35_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/cortex_a53.S000066400000000000000000000247161355360272700221730ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #if A53_DISABLE_NON_TEMPORAL_HINT #undef ERRATA_A53_836870 #define ERRATA_A53_836870 1 #endif /* --------------------------------------------- * Disable L1 data cache and unified L2 cache * --------------------------------------------- */ func cortex_a53_disable_dcache mrs x1, sctlr_el3 bic x1, x1, #SCTLR_C_BIT msr sctlr_el3, x1 isb ret endfunc cortex_a53_disable_dcache /* --------------------------------------------- * Disable intra-cluster coherency * --------------------------------------------- */ func cortex_a53_disable_smp mrs x0, CORTEX_A53_ECTLR_EL1 bic x0, x0, #CORTEX_A53_ECTLR_SMP_BIT msr CORTEX_A53_ECTLR_EL1, x0 isb dsb sy ret endfunc cortex_a53_disable_smp /* --------------------------------------------------- * Errata Workaround for Cortex A53 Errata #819472. * This applies only to revision <= r0p1 of Cortex A53. * Due to the nature of the errata it is applied unconditionally * when built in, report it as applicable in this case * --------------------------------------------------- */ func check_errata_819472 #if ERRATA_A53_819472 mov x0, #ERRATA_APPLIES ret #else mov x1, #0x01 b cpu_rev_var_ls #endif endfunc check_errata_819472 /* --------------------------------------------------- * Errata Workaround for Cortex A53 Errata #824069. * This applies only to revision <= r0p2 of Cortex A53. * Due to the nature of the errata it is applied unconditionally * when built in, report it as applicable in this case * --------------------------------------------------- */ func check_errata_824069 #if ERRATA_A53_824069 mov x0, #ERRATA_APPLIES ret #else mov x1, #0x02 b cpu_rev_var_ls #endif endfunc check_errata_824069 /* -------------------------------------------------- * Errata Workaround for Cortex A53 Errata #826319. * This applies only to revision <= r0p2 of Cortex A53. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_a53_826319_wa /* * Compare x0 against revision r0p2 */ mov x17, x30 bl check_errata_826319 cbz x0, 1f mrs x1, CORTEX_A53_L2ACTLR_EL1 bic x1, x1, #CORTEX_A53_L2ACTLR_ENABLE_UNIQUECLEAN orr x1, x1, #CORTEX_A53_L2ACTLR_DISABLE_CLEAN_PUSH msr CORTEX_A53_L2ACTLR_EL1, x1 1: ret x17 endfunc errata_a53_826319_wa func check_errata_826319 mov x1, #0x02 b cpu_rev_var_ls endfunc check_errata_826319 /* --------------------------------------------------- * Errata Workaround for Cortex A53 Errata #827319. * This applies only to revision <= r0p2 of Cortex A53. * Due to the nature of the errata it is applied unconditionally * when built in, report it as applicable in this case * --------------------------------------------------- */ func check_errata_827319 #if ERRATA_A53_827319 mov x0, #ERRATA_APPLIES ret #else mov x1, #0x02 b cpu_rev_var_ls #endif endfunc check_errata_827319 /* --------------------------------------------------------------------- * Disable the cache non-temporal hint. * * This ignores the Transient allocation hint in the MAIR and treats * allocations the same as non-transient allocation types. As a result, * the LDNP and STNP instructions in AArch64 behave the same as the * equivalent LDP and STP instructions. * * This is relevant only for revisions <= r0p3 of Cortex-A53. * From r0p4 and onwards, the bit to disable the hint is enabled by * default at reset. * * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * --------------------------------------------------------------------- */ func a53_disable_non_temporal_hint /* * Compare x0 against revision r0p3 */ mov x17, x30 bl check_errata_disable_non_temporal_hint cbz x0, 1f mrs x1, CORTEX_A53_CPUACTLR_EL1 orr x1, x1, #CORTEX_A53_CPUACTLR_EL1_DTAH msr CORTEX_A53_CPUACTLR_EL1, x1 1: ret x17 endfunc a53_disable_non_temporal_hint func check_errata_disable_non_temporal_hint mov x1, #0x03 b cpu_rev_var_ls endfunc check_errata_disable_non_temporal_hint /* -------------------------------------------------- * Errata Workaround for Cortex A53 Errata #855873. * * This applies only to revisions >= r0p3 of Cortex A53. * Earlier revisions of the core are affected as well, but don't * have the chicken bit in the CPUACTLR register. It is expected that * the rich OS takes care of that, especially as the workaround is * shared with other erratas in those revisions of the CPU. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_a53_855873_wa /* * Compare x0 against revision r0p3 and higher */ mov x17, x30 bl check_errata_855873 cbz x0, 1f mrs x1, CORTEX_A53_CPUACTLR_EL1 orr x1, x1, #CORTEX_A53_CPUACTLR_EL1_ENDCCASCI msr CORTEX_A53_CPUACTLR_EL1, x1 1: ret x17 endfunc errata_a53_855873_wa func check_errata_855873 mov x1, #0x03 b cpu_rev_var_hs endfunc check_errata_855873 /* * Errata workaround for Cortex A53 Errata #835769. * This applies to revisions <= r0p4 of Cortex A53. * This workaround is statically enabled at build time. */ func check_errata_835769 cmp x0, #0x04 b.hi errata_not_applies /* * Fix potentially available for revisions r0p2, r0p3 and r0p4. * If r0p2, r0p3 or r0p4; check for fix in REVIDR, else exit. */ cmp x0, #0x01 mov x0, #ERRATA_APPLIES b.ls exit_check_errata_835769 /* Load REVIDR. */ mrs x1, revidr_el1 /* If REVIDR[7] is set (fix exists) set ERRATA_NOT_APPLIES, else exit. */ tbz x1, #7, exit_check_errata_835769 errata_not_applies: mov x0, #ERRATA_NOT_APPLIES exit_check_errata_835769: ret endfunc check_errata_835769 /* * Errata workaround for Cortex A53 Errata #843419. * This applies to revisions <= r0p4 of Cortex A53. * This workaround is statically enabled at build time. */ func check_errata_843419 mov x1, #ERRATA_APPLIES mov x2, #ERRATA_NOT_APPLIES cmp x0, #0x04 csel x0, x1, x2, ls /* * Fix potentially available for revision r0p4. * If r0p4 check for fix in REVIDR, else exit. */ b.ne exit_check_errata_843419 /* Load REVIDR. */ mrs x3, revidr_el1 /* If REVIDR[8] is set (fix exists) set ERRATA_NOT_APPLIES, else exit. */ tbz x3, #8, exit_check_errata_843419 mov x0, x2 exit_check_errata_843419: ret endfunc check_errata_843419 /* ------------------------------------------------- * The CPU Ops reset function for Cortex-A53. * Shall clobber: x0-x19 * ------------------------------------------------- */ func cortex_a53_reset_func mov x19, x30 bl cpu_get_rev_var mov x18, x0 #if ERRATA_A53_826319 mov x0, x18 bl errata_a53_826319_wa #endif #if ERRATA_A53_836870 mov x0, x18 bl a53_disable_non_temporal_hint #endif #if ERRATA_A53_855873 mov x0, x18 bl errata_a53_855873_wa #endif /* --------------------------------------------- * Enable the SMP bit. * --------------------------------------------- */ mrs x0, CORTEX_A53_ECTLR_EL1 orr x0, x0, #CORTEX_A53_ECTLR_SMP_BIT msr CORTEX_A53_ECTLR_EL1, x0 isb ret x19 endfunc cortex_a53_reset_func func cortex_a53_core_pwr_dwn mov x18, x30 /* --------------------------------------------- * Turn off caches. * --------------------------------------------- */ bl cortex_a53_disable_dcache /* --------------------------------------------- * Flush L1 caches. * --------------------------------------------- */ mov x0, #DCCISW bl dcsw_op_level1 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ mov x30, x18 b cortex_a53_disable_smp endfunc cortex_a53_core_pwr_dwn func cortex_a53_cluster_pwr_dwn mov x18, x30 /* --------------------------------------------- * Turn off caches. * --------------------------------------------- */ bl cortex_a53_disable_dcache /* --------------------------------------------- * Flush L1 caches. * --------------------------------------------- */ mov x0, #DCCISW bl dcsw_op_level1 /* --------------------------------------------- * Disable the optional ACP. * --------------------------------------------- */ bl plat_disable_acp /* --------------------------------------------- * Flush L2 caches. * --------------------------------------------- */ mov x0, #DCCISW bl dcsw_op_level2 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ mov x30, x18 b cortex_a53_disable_smp endfunc cortex_a53_cluster_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex A53. Must follow AAPCS. */ func cortex_a53_errata_report stp x8, x30, [sp, #-16]! bl cpu_get_rev_var mov x8, x0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata ERRATA_A53_819472, cortex_a53, 819472 report_errata ERRATA_A53_824069, cortex_a53, 824069 report_errata ERRATA_A53_826319, cortex_a53, 826319 report_errata ERRATA_A53_827319, cortex_a53, 827319 report_errata ERRATA_A53_835769, cortex_a53, 835769 report_errata ERRATA_A53_836870, cortex_a53, disable_non_temporal_hint report_errata ERRATA_A53_843419, cortex_a53, 843419 report_errata ERRATA_A53_855873, cortex_a53, 855873 ldp x8, x30, [sp], #16 ret endfunc cortex_a53_errata_report #endif /* --------------------------------------------- * This function provides cortex_a53 specific * register information for crash reporting. * It needs to return with x6 pointing to * a list of register names in ascii and * x8 - x15 having values of registers to be * reported. * --------------------------------------------- */ .section .rodata.cortex_a53_regs, "aS" cortex_a53_regs: /* The ascii list of register names to be reported */ .asciz "cpuectlr_el1", "cpumerrsr_el1", "l2merrsr_el1", \ "cpuactlr_el1", "" func cortex_a53_cpu_reg_dump adr x6, cortex_a53_regs mrs x8, CORTEX_A53_ECTLR_EL1 mrs x9, CORTEX_A53_MERRSR_EL1 mrs x10, CORTEX_A53_L2MERRSR_EL1 mrs x11, CORTEX_A53_CPUACTLR_EL1 ret endfunc cortex_a53_cpu_reg_dump declare_cpu_ops cortex_a53, CORTEX_A53_MIDR, \ cortex_a53_reset_func, \ cortex_a53_core_pwr_dwn, \ cortex_a53_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/cortex_a55.S000066400000000000000000000202711355360272700221650ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* Hardware handled coherency */ #if HW_ASSISTED_COHERENCY == 0 #error "Cortex-A55 must be compiled with HW_ASSISTED_COHERENCY enabled" #endif /* -------------------------------------------------- * Errata Workaround for Cortex A55 Errata #768277. * This applies only to revision r0p0 of Cortex A55. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_a55_768277_wa /* * Compare x0 against revision r0p0 */ mov x17, x30 bl check_errata_768277 cbz x0, 1f mrs x1, CORTEX_A55_CPUACTLR_EL1 orr x1, x1, #CORTEX_A55_CPUACTLR_EL1_DISABLE_DUAL_ISSUE msr CORTEX_A55_CPUACTLR_EL1, x1 isb 1: ret x17 endfunc errata_a55_768277_wa func check_errata_768277 mov x1, #0x00 b cpu_rev_var_ls endfunc check_errata_768277 /* ------------------------------------------------------------------ * Errata Workaround for Cortex A55 Errata #778703. * This applies only to revision r0p0 of Cortex A55 where L2 cache is * not configured. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * ------------------------------------------------------------------ */ func errata_a55_778703_wa /* * Compare x0 against revision r0p0 and check that no private L2 cache * is configured */ mov x17, x30 bl check_errata_778703 cbz x0, 1f mrs x1, CORTEX_A55_CPUECTLR_EL1 orr x1, x1, #CORTEX_A55_CPUECTLR_EL1_L1WSCTL msr CORTEX_A55_CPUECTLR_EL1, x1 mrs x1, CORTEX_A55_CPUACTLR_EL1 orr x1, x1, #CORTEX_A55_CPUACTLR_EL1_DISABLE_WRITE_STREAMING msr CORTEX_A55_CPUACTLR_EL1, x1 isb 1: ret x17 endfunc errata_a55_778703_wa func check_errata_778703 mov x16, x30 mov x1, #0x00 bl cpu_rev_var_ls /* * Check that no private L2 cache is configured */ mrs x1, CORTEX_A55_CLIDR_EL1 and x1, x1, CORTEX_A55_CLIDR_EL1_CTYPE3 cmp x1, #0 mov x2, #ERRATA_NOT_APPLIES csel x0, x0, x2, eq ret x16 endfunc check_errata_778703 /* -------------------------------------------------- * Errata Workaround for Cortex A55 Errata #798797. * This applies only to revision r0p0 of Cortex A55. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_a55_798797_wa /* * Compare x0 against revision r0p0 */ mov x17, x30 bl check_errata_798797 cbz x0, 1f mrs x1, CORTEX_A55_CPUACTLR_EL1 orr x1, x1, #CORTEX_A55_CPUACTLR_EL1_DISABLE_L1_PAGEWALKS msr CORTEX_A55_CPUACTLR_EL1, x1 isb 1: ret x17 endfunc errata_a55_798797_wa func check_errata_798797 mov x1, #0x00 b cpu_rev_var_ls endfunc check_errata_798797 /* -------------------------------------------------------------------- * Errata Workaround for Cortex A55 Errata #846532. * This applies only to revisions <= r0p1 of Cortex A55. * Disabling dual-issue has a small impact on performance. Disabling a * power optimization feature is an alternate workaround with no impact * on performance but with an increase in power consumption (see errata * notice). * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------------------------- */ func errata_a55_846532_wa /* * Compare x0 against revision r0p1 */ mov x17, x30 bl check_errata_846532 cbz x0, 1f mrs x1, CORTEX_A55_CPUACTLR_EL1 orr x1, x1, #CORTEX_A55_CPUACTLR_EL1_DISABLE_DUAL_ISSUE msr CORTEX_A55_CPUACTLR_EL1, x1 isb 1: ret x17 endfunc errata_a55_846532_wa func check_errata_846532 mov x1, #0x01 b cpu_rev_var_ls endfunc check_errata_846532 /* ----------------------------------------------------- * Errata Workaround for Cortex A55 Errata #903758. * This applies only to revisions <= r0p1 of Cortex A55. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * ----------------------------------------------------- */ func errata_a55_903758_wa /* * Compare x0 against revision r0p1 */ mov x17, x30 bl check_errata_903758 cbz x0, 1f mrs x1, CORTEX_A55_CPUACTLR_EL1 orr x1, x1, #CORTEX_A55_CPUACTLR_EL1_DISABLE_L1_PAGEWALKS msr CORTEX_A55_CPUACTLR_EL1, x1 isb 1: ret x17 endfunc errata_a55_903758_wa func check_errata_903758 mov x1, #0x01 b cpu_rev_var_ls endfunc check_errata_903758 /* ----------------------------------------------------- * Errata Workaround for Cortex A55 Errata #1221012. * This applies only to revisions <= r1p0 of Cortex A55. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * ----------------------------------------------------- */ func errata_a55_1221012_wa /* * Compare x0 against revision r1p0 */ mov x17, x30 bl check_errata_1221012 cbz x0, 1f mov x0, #0x0020 movk x0, #0x0850, lsl #16 msr CPUPOR_EL3, x0 mov x0, #0x0000 movk x0, #0x1FF0, lsl #16 movk x0, #0x2, lsl #32 msr CPUPMR_EL3, x0 mov x0, #0x03fd movk x0, #0x0110, lsl #16 msr CPUPCR_EL3, x0 mov x0, #0x1 msr CPUPSELR_EL3, x0 mov x0, #0x0040 movk x0, #0x08D0, lsl #16 msr CPUPOR_EL3, x0 mov x0, #0x0040 movk x0, #0x1FF0, lsl #16 movk x0, #0x2, lsl #32 msr CPUPMR_EL3, x0 mov x0, #0x03fd movk x0, #0x0110, lsl #16 msr CPUPCR_EL3, x0 isb 1: ret x17 endfunc errata_a55_1221012_wa func check_errata_1221012 mov x1, #0x10 b cpu_rev_var_ls endfunc check_errata_1221012 func cortex_a55_reset_func mov x19, x30 #if ERRATA_DSU_798953 bl errata_dsu_798953_wa #endif #if ERRATA_DSU_936184 bl errata_dsu_936184_wa #endif bl cpu_get_rev_var mov x18, x0 #if ERRATA_A55_768277 mov x0, x18 bl errata_a55_768277_wa #endif #if ERRATA_A55_778703 mov x0, x18 bl errata_a55_778703_wa #endif #if ERRATA_A55_798797 mov x0, x18 bl errata_a55_798797_wa #endif #if ERRATA_A55_846532 mov x0, x18 bl errata_a55_846532_wa #endif #if ERRATA_A55_903758 mov x0, x18 bl errata_a55_903758_wa #endif #if ERRATA_A55_1221012 mov x0, x18 bl errata_a55_1221012_wa #endif ret x19 endfunc cortex_a55_reset_func /* --------------------------------------------- * HW will do the cache maintenance while powering down * --------------------------------------------- */ func cortex_a55_core_pwr_dwn /* --------------------------------------------- * Enable CPU power down bit in power control register * --------------------------------------------- */ mrs x0, CORTEX_A55_CPUPWRCTLR_EL1 orr x0, x0, #CORTEX_A55_CORE_PWRDN_EN_MASK msr CORTEX_A55_CPUPWRCTLR_EL1, x0 isb ret endfunc cortex_a55_core_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex A55. Must follow AAPCS & can use stack. */ func cortex_a55_errata_report stp x8, x30, [sp, #-16]! bl cpu_get_rev_var mov x8, x0 /* * Report all errata. The revision variant information is at x8, where * "report_errata" is expecting it and it doesn't corrupt it. */ report_errata ERRATA_DSU_798953, cortex_a55, dsu_798953 report_errata ERRATA_DSU_936184, cortex_a55, dsu_936184 report_errata ERRATA_A55_768277, cortex_a55, 768277 report_errata ERRATA_A55_778703, cortex_a55, 778703 report_errata ERRATA_A55_798797, cortex_a55, 798797 report_errata ERRATA_A55_846532, cortex_a55, 846532 report_errata ERRATA_A55_903758, cortex_a55, 903758 report_errata ERRATA_A55_1221012, cortex_a55, 1221012 ldp x8, x30, [sp], #16 ret endfunc cortex_a55_errata_report #endif /* --------------------------------------------- * This function provides cortex_a55 specific * register information for crash reporting. * It needs to return with x6 pointing to * a list of register names in ascii and * x8 - x15 having values of registers to be * reported. * --------------------------------------------- */ .section .rodata.cortex_a55_regs, "aS" cortex_a55_regs: /* The ascii list of register names to be reported */ .asciz "cpuectlr_el1", "" func cortex_a55_cpu_reg_dump adr x6, cortex_a55_regs mrs x8, CORTEX_A55_CPUECTLR_EL1 ret endfunc cortex_a55_cpu_reg_dump declare_cpu_ops cortex_a55, CORTEX_A55_MIDR, \ cortex_a55_reset_func, \ cortex_a55_core_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/cortex_a57.S000066400000000000000000000403061355360272700221700ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include /* --------------------------------------------- * Disable L1 data cache and unified L2 cache * --------------------------------------------- */ func cortex_a57_disable_dcache mrs x1, sctlr_el3 bic x1, x1, #SCTLR_C_BIT msr sctlr_el3, x1 isb ret endfunc cortex_a57_disable_dcache /* --------------------------------------------- * Disable all types of L2 prefetches. * --------------------------------------------- */ func cortex_a57_disable_l2_prefetch mrs x0, CORTEX_A57_ECTLR_EL1 orr x0, x0, #CORTEX_A57_ECTLR_DIS_TWD_ACC_PFTCH_BIT mov x1, #CORTEX_A57_ECTLR_L2_IPFTCH_DIST_MASK orr x1, x1, #CORTEX_A57_ECTLR_L2_DPFTCH_DIST_MASK bic x0, x0, x1 msr CORTEX_A57_ECTLR_EL1, x0 isb dsb ish ret endfunc cortex_a57_disable_l2_prefetch /* --------------------------------------------- * Disable intra-cluster coherency * --------------------------------------------- */ func cortex_a57_disable_smp mrs x0, CORTEX_A57_ECTLR_EL1 bic x0, x0, #CORTEX_A57_ECTLR_SMP_BIT msr CORTEX_A57_ECTLR_EL1, x0 ret endfunc cortex_a57_disable_smp /* --------------------------------------------- * Disable debug interfaces * --------------------------------------------- */ func cortex_a57_disable_ext_debug mov x0, #1 msr osdlr_el1, x0 isb #if ERRATA_A57_817169 /* * Invalidate any TLB address */ mov x0, #0 tlbi vae3, x0 #endif dsb sy ret endfunc cortex_a57_disable_ext_debug /* -------------------------------------------------- * Errata Workaround for Cortex A57 Errata #806969. * This applies only to revision r0p0 of Cortex A57. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_a57_806969_wa /* * Compare x0 against revision r0p0 */ mov x17, x30 bl check_errata_806969 cbz x0, 1f mrs x1, CORTEX_A57_CPUACTLR_EL1 orr x1, x1, #CORTEX_A57_CPUACTLR_EL1_NO_ALLOC_WBWA msr CORTEX_A57_CPUACTLR_EL1, x1 1: ret x17 endfunc errata_a57_806969_wa func check_errata_806969 mov x1, #0x00 b cpu_rev_var_ls endfunc check_errata_806969 /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #813419. * This applies only to revision r0p0 of Cortex A57. * --------------------------------------------------- */ func check_errata_813419 /* * Even though this is only needed for revision r0p0, it * is always applied due to limitations of the current * errata framework. */ mov x0, #ERRATA_APPLIES ret endfunc check_errata_813419 /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #813420. * This applies only to revision r0p0 of Cortex A57. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * --------------------------------------------------- */ func errata_a57_813420_wa /* * Compare x0 against revision r0p0 */ mov x17, x30 bl check_errata_813420 cbz x0, 1f mrs x1, CORTEX_A57_CPUACTLR_EL1 orr x1, x1, #CORTEX_A57_CPUACTLR_EL1_DCC_AS_DCCI msr CORTEX_A57_CPUACTLR_EL1, x1 1: ret x17 endfunc errata_a57_813420_wa func check_errata_813420 mov x1, #0x00 b cpu_rev_var_ls endfunc check_errata_813420 /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #814670. * This applies only to revision r0p0 of Cortex A57. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * --------------------------------------------------- */ func errata_a57_814670_wa /* * Compare x0 against revision r0p0 */ mov x17, x30 bl check_errata_814670 cbz x0, 1f mrs x1, CORTEX_A57_CPUACTLR_EL1 orr x1, x1, #CORTEX_A57_CPUACTLR_EL1_DIS_DMB_NULLIFICATION msr CORTEX_A57_CPUACTLR_EL1, x1 isb 1: ret x17 endfunc errata_a57_814670_wa func check_errata_814670 mov x1, #0x00 b cpu_rev_var_ls endfunc check_errata_814670 /* ---------------------------------------------------- * Errata Workaround for Cortex A57 Errata #817169. * This applies only to revision <= r0p1 of Cortex A57. * ---------------------------------------------------- */ func check_errata_817169 /* * Even though this is only needed for revision <= r0p1, it * is always applied because of the low cost of the workaround. */ mov x0, #ERRATA_APPLIES ret endfunc check_errata_817169 /* -------------------------------------------------------------------- * Disable the over-read from the LDNP instruction. * * This applies to all revisions <= r1p2. The performance degradation * observed with LDNP/STNP has been fixed on r1p3 and onwards. * * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * --------------------------------------------------------------------- */ func a57_disable_ldnp_overread /* * Compare x0 against revision r1p2 */ mov x17, x30 bl check_errata_disable_ldnp_overread cbz x0, 1f mrs x1, CORTEX_A57_CPUACTLR_EL1 orr x1, x1, #CORTEX_A57_CPUACTLR_EL1_DIS_OVERREAD msr CORTEX_A57_CPUACTLR_EL1, x1 1: ret x17 endfunc a57_disable_ldnp_overread func check_errata_disable_ldnp_overread mov x1, #0x12 b cpu_rev_var_ls endfunc check_errata_disable_ldnp_overread /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #826974. * This applies only to revision <= r1p1 of Cortex A57. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * --------------------------------------------------- */ func errata_a57_826974_wa /* * Compare x0 against revision r1p1 */ mov x17, x30 bl check_errata_826974 cbz x0, 1f mrs x1, CORTEX_A57_CPUACTLR_EL1 orr x1, x1, #CORTEX_A57_CPUACTLR_EL1_DIS_LOAD_PASS_DMB msr CORTEX_A57_CPUACTLR_EL1, x1 1: ret x17 endfunc errata_a57_826974_wa func check_errata_826974 mov x1, #0x11 b cpu_rev_var_ls endfunc check_errata_826974 /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #826977. * This applies only to revision <= r1p1 of Cortex A57. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * --------------------------------------------------- */ func errata_a57_826977_wa /* * Compare x0 against revision r1p1 */ mov x17, x30 bl check_errata_826977 cbz x0, 1f mrs x1, CORTEX_A57_CPUACTLR_EL1 orr x1, x1, #CORTEX_A57_CPUACTLR_EL1_GRE_NGRE_AS_NGNRE msr CORTEX_A57_CPUACTLR_EL1, x1 1: ret x17 endfunc errata_a57_826977_wa func check_errata_826977 mov x1, #0x11 b cpu_rev_var_ls endfunc check_errata_826977 /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #828024. * This applies only to revision <= r1p1 of Cortex A57. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * --------------------------------------------------- */ func errata_a57_828024_wa /* * Compare x0 against revision r1p1 */ mov x17, x30 bl check_errata_828024 cbz x0, 1f mrs x1, CORTEX_A57_CPUACTLR_EL1 /* * Setting the relevant bits in CPUACTLR_EL1 has to be done in 2 * instructions here because the resulting bitmask doesn't fit in a * 16-bit value so it cannot be encoded in a single instruction. */ orr x1, x1, #CORTEX_A57_CPUACTLR_EL1_NO_ALLOC_WBWA orr x1, x1, #(CORTEX_A57_CPUACTLR_EL1_DIS_L1_STREAMING | \ CORTEX_A57_CPUACTLR_EL1_DIS_STREAMING) msr CORTEX_A57_CPUACTLR_EL1, x1 1: ret x17 endfunc errata_a57_828024_wa func check_errata_828024 mov x1, #0x11 b cpu_rev_var_ls endfunc check_errata_828024 /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #829520. * This applies only to revision <= r1p2 of Cortex A57. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * --------------------------------------------------- */ func errata_a57_829520_wa /* * Compare x0 against revision r1p2 */ mov x17, x30 bl check_errata_829520 cbz x0, 1f mrs x1, CORTEX_A57_CPUACTLR_EL1 orr x1, x1, #CORTEX_A57_CPUACTLR_EL1_DIS_INDIRECT_PREDICTOR msr CORTEX_A57_CPUACTLR_EL1, x1 1: ret x17 endfunc errata_a57_829520_wa func check_errata_829520 mov x1, #0x12 b cpu_rev_var_ls endfunc check_errata_829520 /* --------------------------------------------------- * Errata Workaround for Cortex A57 Errata #833471. * This applies only to revision <= r1p2 of Cortex A57. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * --------------------------------------------------- */ func errata_a57_833471_wa /* * Compare x0 against revision r1p2 */ mov x17, x30 bl check_errata_833471 cbz x0, 1f mrs x1, CORTEX_A57_CPUACTLR_EL1 orr x1, x1, #CORTEX_A57_CPUACTLR_EL1_FORCE_FPSCR_FLUSH msr CORTEX_A57_CPUACTLR_EL1, x1 1: ret x17 endfunc errata_a57_833471_wa func check_errata_833471 mov x1, #0x12 b cpu_rev_var_ls endfunc check_errata_833471 /* -------------------------------------------------- * Errata Workaround for Cortex A57 Errata #859972. * This applies only to revision <= r1p3 of Cortex A57. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: * -------------------------------------------------- */ func errata_a57_859972_wa mov x17, x30 bl check_errata_859972 cbz x0, 1f mrs x1, CORTEX_A57_CPUACTLR_EL1 orr x1, x1, #CORTEX_A57_CPUACTLR_EL1_DIS_INSTR_PREFETCH msr CORTEX_A57_CPUACTLR_EL1, x1 1: ret x17 endfunc errata_a57_859972_wa func check_errata_859972 mov x1, #0x13 b cpu_rev_var_ls endfunc check_errata_859972 func check_errata_cve_2017_5715 #if WORKAROUND_CVE_2017_5715 mov x0, #ERRATA_APPLIES #else mov x0, #ERRATA_MISSING #endif ret endfunc check_errata_cve_2017_5715 func check_errata_cve_2018_3639 #if WORKAROUND_CVE_2018_3639 mov x0, #ERRATA_APPLIES #else mov x0, #ERRATA_MISSING #endif ret endfunc check_errata_cve_2018_3639 /* ------------------------------------------------- * The CPU Ops reset function for Cortex-A57. * Shall clobber: x0-x19 * ------------------------------------------------- */ func cortex_a57_reset_func mov x19, x30 bl cpu_get_rev_var mov x18, x0 #if ERRATA_A57_806969 mov x0, x18 bl errata_a57_806969_wa #endif #if ERRATA_A57_813420 mov x0, x18 bl errata_a57_813420_wa #endif #if ERRATA_A57_814670 mov x0, x18 bl errata_a57_814670_wa #endif #if A57_DISABLE_NON_TEMPORAL_HINT mov x0, x18 bl a57_disable_ldnp_overread #endif #if ERRATA_A57_826974 mov x0, x18 bl errata_a57_826974_wa #endif #if ERRATA_A57_826977 mov x0, x18 bl errata_a57_826977_wa #endif #if ERRATA_A57_828024 mov x0, x18 bl errata_a57_828024_wa #endif #if ERRATA_A57_829520 mov x0, x18 bl errata_a57_829520_wa #endif #if ERRATA_A57_833471 mov x0, x18 bl errata_a57_833471_wa #endif #if ERRATA_A57_859972 mov x0, x18 bl errata_a57_859972_wa #endif #if IMAGE_BL31 && WORKAROUND_CVE_2017_5715 adr x0, wa_cve_2017_5715_mmu_vbar msr vbar_el3, x0 /* isb will be performed before returning from this function */ #endif #if WORKAROUND_CVE_2018_3639 mrs x0, CORTEX_A57_CPUACTLR_EL1 orr x0, x0, #CORTEX_A57_CPUACTLR_EL1_DIS_LOAD_PASS_STORE msr CORTEX_A57_CPUACTLR_EL1, x0 isb dsb sy #endif /* --------------------------------------------- * Enable the SMP bit. * --------------------------------------------- */ mrs x0, CORTEX_A57_ECTLR_EL1 orr x0, x0, #CORTEX_A57_ECTLR_SMP_BIT msr CORTEX_A57_ECTLR_EL1, x0 isb ret x19 endfunc cortex_a57_reset_func /* ---------------------------------------------------- * The CPU Ops core power down function for Cortex-A57. * ---------------------------------------------------- */ func cortex_a57_core_pwr_dwn mov x18, x30 /* --------------------------------------------- * Turn off caches. * --------------------------------------------- */ bl cortex_a57_disable_dcache /* --------------------------------------------- * Disable the L2 prefetches. * --------------------------------------------- */ bl cortex_a57_disable_l2_prefetch /* --------------------------------------------- * Flush L1 caches. * --------------------------------------------- */ mov x0, #DCCISW bl dcsw_op_level1 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ bl cortex_a57_disable_smp /* --------------------------------------------- * Force the debug interfaces to be quiescent * --------------------------------------------- */ mov x30, x18 b cortex_a57_disable_ext_debug endfunc cortex_a57_core_pwr_dwn /* ------------------------------------------------------- * The CPU Ops cluster power down function for Cortex-A57. * ------------------------------------------------------- */ func cortex_a57_cluster_pwr_dwn mov x18, x30 /* --------------------------------------------- * Turn off caches. * --------------------------------------------- */ bl cortex_a57_disable_dcache /* --------------------------------------------- * Disable the L2 prefetches. * --------------------------------------------- */ bl cortex_a57_disable_l2_prefetch #if !SKIP_A57_L1_FLUSH_PWR_DWN /* ------------------------------------------------- * Flush the L1 caches. * ------------------------------------------------- */ mov x0, #DCCISW bl dcsw_op_level1 #endif /* --------------------------------------------- * Disable the optional ACP. * --------------------------------------------- */ bl plat_disable_acp /* ------------------------------------------------- * Flush the L2 caches. * ------------------------------------------------- */ mov x0, #DCCISW bl dcsw_op_level2 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ bl cortex_a57_disable_smp /* --------------------------------------------- * Force the debug interfaces to be quiescent * --------------------------------------------- */ mov x30, x18 b cortex_a57_disable_ext_debug endfunc cortex_a57_cluster_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex A57. Must follow AAPCS. */ func cortex_a57_errata_report stp x8, x30, [sp, #-16]! bl cpu_get_rev_var mov x8, x0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata ERRATA_A57_806969, cortex_a57, 806969 report_errata ERRATA_A57_813419, cortex_a57, 813419 report_errata ERRATA_A57_813420, cortex_a57, 813420 report_errata ERRATA_A57_814670, cortex_a57, 814670 report_errata ERRATA_A57_817169, cortex_a57, 817169 report_errata A57_DISABLE_NON_TEMPORAL_HINT, cortex_a57, \ disable_ldnp_overread report_errata ERRATA_A57_826974, cortex_a57, 826974 report_errata ERRATA_A57_826977, cortex_a57, 826977 report_errata ERRATA_A57_828024, cortex_a57, 828024 report_errata ERRATA_A57_829520, cortex_a57, 829520 report_errata ERRATA_A57_833471, cortex_a57, 833471 report_errata ERRATA_A57_859972, cortex_a57, 859972 report_errata WORKAROUND_CVE_2017_5715, cortex_a57, cve_2017_5715 report_errata WORKAROUND_CVE_2018_3639, cortex_a57, cve_2018_3639 ldp x8, x30, [sp], #16 ret endfunc cortex_a57_errata_report #endif /* --------------------------------------------- * This function provides cortex_a57 specific * register information for crash reporting. * It needs to return with x6 pointing to * a list of register names in ascii and * x8 - x15 having values of registers to be * reported. * --------------------------------------------- */ .section .rodata.cortex_a57_regs, "aS" cortex_a57_regs: /* The ascii list of register names to be reported */ .asciz "cpuectlr_el1", "cpumerrsr_el1", "l2merrsr_el1", "" func cortex_a57_cpu_reg_dump adr x6, cortex_a57_regs mrs x8, CORTEX_A57_ECTLR_EL1 mrs x9, CORTEX_A57_MERRSR_EL1 mrs x10, CORTEX_A57_L2MERRSR_EL1 ret endfunc cortex_a57_cpu_reg_dump declare_cpu_ops_wa cortex_a57, CORTEX_A57_MIDR, \ cortex_a57_reset_func, \ check_errata_cve_2017_5715, \ CPU_NO_EXTRA2_FUNC, \ cortex_a57_core_pwr_dwn, \ cortex_a57_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/cortex_a65.S000066400000000000000000000035021355360272700221640ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* Hardware handled coherency */ #if !HW_ASSISTED_COHERENCY #error "Cortex-A65 must be compiled with HW_ASSISTED_COHERENCY enabled" #endif /* 64-bit only core */ #if CTX_INCLUDE_AARCH32_REGS #error "Cortex-A65 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0" #endif /* ------------------------------------------------- * The CPU Ops reset function for Cortex-A65. * Shall clobber: x0-x19 * ------------------------------------------------- */ func cortex_a65_reset_func mov x19, x30 #if ERRATA_DSU_936184 bl errata_dsu_936184_wa #endif ret x19 endfunc cortex_a65_reset_func func cortex_a65_cpu_pwr_dwn mrs x0, CORTEX_A65_CPUPWRCTLR_EL1 orr x0, x0, #CORTEX_A65_CPUPWRCTLR_EL1_CORE_PWRDN_BIT msr CORTEX_A65_CPUPWRCTLR_EL1, x0 isb ret endfunc cortex_a65_cpu_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex-A65. Must follow AAPCS. */ func cortex_a65_errata_report stp x8, x30, [sp, #-16]! bl cpu_get_rev_var mov x8, x0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata ERRATA_DSU_936184, cortex_a65, dsu_936184 ldp x8, x30, [sp], #16 ret endfunc cortex_a65_errata_report #endif .section .rodata.cortex_a65_regs, "aS" cortex_a65_regs: /* The ascii list of register names to be reported */ .asciz "cpuectlr_el1", "" func cortex_a65_cpu_reg_dump adr x6, cortex_a65_regs mrs x8, CORTEX_A65_ECTLR_EL1 ret endfunc cortex_a65_cpu_reg_dump declare_cpu_ops cortex_a65, CORTEX_A65_MIDR, \ cortex_a65_reset_func, \ cortex_a65_cpu_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/cortex_a65ae.S000066400000000000000000000035621355360272700225000ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* Hardware handled coherency */ #if !HW_ASSISTED_COHERENCY #error "Cortex-A65AE must be compiled with HW_ASSISTED_COHERENCY enabled" #endif /* 64-bit only core */ #if CTX_INCLUDE_AARCH32_REGS #error "Cortex-A65AE supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0" #endif /* ------------------------------------------------- * The CPU Ops reset function for Cortex-A65. * Shall clobber: x0-x19 * ------------------------------------------------- */ func cortex_a65ae_reset_func mov x19, x30 #if ERRATA_DSU_936184 bl errata_dsu_936184_wa #endif ret x19 endfunc cortex_a65ae_reset_func func cortex_a65ae_cpu_pwr_dwn mrs x0, CORTEX_A65AE_CPUPWRCTLR_EL1 orr x0, x0, #CORTEX_A65AE_CPUPWRCTLR_EL1_CORE_PWRDN_BIT msr CORTEX_A65AE_CPUPWRCTLR_EL1, x0 isb ret endfunc cortex_a65ae_cpu_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex-A65AE. Must follow AAPCS. */ func cortex_a65ae_errata_report stp x8, x30, [sp, #-16]! bl cpu_get_rev_var mov x8, x0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata ERRATA_DSU_936184, cortex_a65ae, dsu_936184 ldp x8, x30, [sp], #16 ret endfunc cortex_a65ae_errata_report #endif .section .rodata.cortex_a65ae_regs, "aS" cortex_a65ae_regs: /* The ascii list of register names to be reported */ .asciz "cpuectlr_el1", "" func cortex_a65ae_cpu_reg_dump adr x6, cortex_a65ae_regs mrs x8, CORTEX_A65AE_ECTLR_EL1 ret endfunc cortex_a65ae_cpu_reg_dump declare_cpu_ops cortex_a65ae, CORTEX_A65AE_MIDR, \ cortex_a65ae_reset_func, \ cortex_a65ae_cpu_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/cortex_a72.S000066400000000000000000000202731355360272700221660ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* --------------------------------------------- * Disable L1 data cache and unified L2 cache * --------------------------------------------- */ func cortex_a72_disable_dcache mrs x1, sctlr_el3 bic x1, x1, #SCTLR_C_BIT msr sctlr_el3, x1 isb ret endfunc cortex_a72_disable_dcache /* --------------------------------------------- * Disable all types of L2 prefetches. * --------------------------------------------- */ func cortex_a72_disable_l2_prefetch mrs x0, CORTEX_A72_ECTLR_EL1 orr x0, x0, #CORTEX_A72_ECTLR_DIS_TWD_ACC_PFTCH_BIT mov x1, #CORTEX_A72_ECTLR_L2_IPFTCH_DIST_MASK orr x1, x1, #CORTEX_A72_ECTLR_L2_DPFTCH_DIST_MASK bic x0, x0, x1 msr CORTEX_A72_ECTLR_EL1, x0 isb ret endfunc cortex_a72_disable_l2_prefetch /* --------------------------------------------- * Disable the load-store hardware prefetcher. * --------------------------------------------- */ func cortex_a72_disable_hw_prefetcher mrs x0, CORTEX_A72_CPUACTLR_EL1 orr x0, x0, #CORTEX_A72_CPUACTLR_EL1_DISABLE_L1_DCACHE_HW_PFTCH msr CORTEX_A72_CPUACTLR_EL1, x0 isb dsb ish ret endfunc cortex_a72_disable_hw_prefetcher /* --------------------------------------------- * Disable intra-cluster coherency * --------------------------------------------- */ func cortex_a72_disable_smp mrs x0, CORTEX_A72_ECTLR_EL1 bic x0, x0, #CORTEX_A72_ECTLR_SMP_BIT msr CORTEX_A72_ECTLR_EL1, x0 ret endfunc cortex_a72_disable_smp /* --------------------------------------------- * Disable debug interfaces * --------------------------------------------- */ func cortex_a72_disable_ext_debug mov x0, #1 msr osdlr_el1, x0 isb dsb sy ret endfunc cortex_a72_disable_ext_debug /* -------------------------------------------------- * Errata Workaround for Cortex A72 Errata #859971. * This applies only to revision <= r0p3 of Cortex A72. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: * -------------------------------------------------- */ func errata_a72_859971_wa mov x17,x30 bl check_errata_859971 cbz x0, 1f mrs x1, CORTEX_A72_CPUACTLR_EL1 orr x1, x1, #CORTEX_A72_CPUACTLR_EL1_DIS_INSTR_PREFETCH msr CORTEX_A72_CPUACTLR_EL1, x1 1: ret x17 endfunc errata_a72_859971_wa func check_errata_859971 mov x1, #0x03 b cpu_rev_var_ls endfunc check_errata_859971 func check_errata_cve_2017_5715 cpu_check_csv2 x0, 1f #if WORKAROUND_CVE_2017_5715 mov x0, #ERRATA_APPLIES #else mov x0, #ERRATA_MISSING #endif ret 1: mov x0, #ERRATA_NOT_APPLIES ret endfunc check_errata_cve_2017_5715 func check_errata_cve_2018_3639 #if WORKAROUND_CVE_2018_3639 mov x0, #ERRATA_APPLIES #else mov x0, #ERRATA_MISSING #endif ret endfunc check_errata_cve_2018_3639 /* ------------------------------------------------- * The CPU Ops reset function for Cortex-A72. * ------------------------------------------------- */ func cortex_a72_reset_func mov x19, x30 bl cpu_get_rev_var mov x18, x0 #if ERRATA_A72_859971 mov x0, x18 bl errata_a72_859971_wa #endif #if IMAGE_BL31 && WORKAROUND_CVE_2017_5715 cpu_check_csv2 x0, 1f adr x0, wa_cve_2017_5715_mmu_vbar msr vbar_el3, x0 /* isb will be performed before returning from this function */ 1: #endif #if WORKAROUND_CVE_2018_3639 mrs x0, CORTEX_A72_CPUACTLR_EL1 orr x0, x0, #CORTEX_A72_CPUACTLR_EL1_DIS_LOAD_PASS_STORE msr CORTEX_A72_CPUACTLR_EL1, x0 isb dsb sy #endif /* --------------------------------------------- * Enable the SMP bit. * --------------------------------------------- */ mrs x0, CORTEX_A72_ECTLR_EL1 orr x0, x0, #CORTEX_A72_ECTLR_SMP_BIT msr CORTEX_A72_ECTLR_EL1, x0 isb ret x19 endfunc cortex_a72_reset_func /* ---------------------------------------------------- * The CPU Ops core power down function for Cortex-A72. * ---------------------------------------------------- */ func cortex_a72_core_pwr_dwn mov x18, x30 /* --------------------------------------------- * Turn off caches. * --------------------------------------------- */ bl cortex_a72_disable_dcache /* --------------------------------------------- * Disable the L2 prefetches. * --------------------------------------------- */ bl cortex_a72_disable_l2_prefetch /* --------------------------------------------- * Disable the load-store hardware prefetcher. * --------------------------------------------- */ bl cortex_a72_disable_hw_prefetcher /* --------------------------------------------- * Flush L1 caches. * --------------------------------------------- */ mov x0, #DCCISW bl dcsw_op_level1 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ bl cortex_a72_disable_smp /* --------------------------------------------- * Force the debug interfaces to be quiescent * --------------------------------------------- */ mov x30, x18 b cortex_a72_disable_ext_debug endfunc cortex_a72_core_pwr_dwn /* ------------------------------------------------------- * The CPU Ops cluster power down function for Cortex-A72. * ------------------------------------------------------- */ func cortex_a72_cluster_pwr_dwn mov x18, x30 /* --------------------------------------------- * Turn off caches. * --------------------------------------------- */ bl cortex_a72_disable_dcache /* --------------------------------------------- * Disable the L2 prefetches. * --------------------------------------------- */ bl cortex_a72_disable_l2_prefetch /* --------------------------------------------- * Disable the load-store hardware prefetcher. * --------------------------------------------- */ bl cortex_a72_disable_hw_prefetcher #if !SKIP_A72_L1_FLUSH_PWR_DWN /* --------------------------------------------- * Flush L1 caches. * --------------------------------------------- */ mov x0, #DCCISW bl dcsw_op_level1 #endif /* --------------------------------------------- * Disable the optional ACP. * --------------------------------------------- */ bl plat_disable_acp /* ------------------------------------------------- * Flush the L2 caches. * ------------------------------------------------- */ mov x0, #DCCISW bl dcsw_op_level2 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ bl cortex_a72_disable_smp /* --------------------------------------------- * Force the debug interfaces to be quiescent * --------------------------------------------- */ mov x30, x18 b cortex_a72_disable_ext_debug endfunc cortex_a72_cluster_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex A72. Must follow AAPCS. */ func cortex_a72_errata_report stp x8, x30, [sp, #-16]! bl cpu_get_rev_var mov x8, x0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata ERRATA_A72_859971, cortex_a72, 859971 report_errata WORKAROUND_CVE_2017_5715, cortex_a72, cve_2017_5715 report_errata WORKAROUND_CVE_2018_3639, cortex_a72, cve_2018_3639 ldp x8, x30, [sp], #16 ret endfunc cortex_a72_errata_report #endif /* --------------------------------------------- * This function provides cortex_a72 specific * register information for crash reporting. * It needs to return with x6 pointing to * a list of register names in ascii and * x8 - x15 having values of registers to be * reported. * --------------------------------------------- */ .section .rodata.cortex_a72_regs, "aS" cortex_a72_regs: /* The ascii list of register names to be reported */ .asciz "cpuectlr_el1", "cpumerrsr_el1", "l2merrsr_el1", "" func cortex_a72_cpu_reg_dump adr x6, cortex_a72_regs mrs x8, CORTEX_A72_ECTLR_EL1 mrs x9, CORTEX_A72_MERRSR_EL1 mrs x10, CORTEX_A72_L2MERRSR_EL1 ret endfunc cortex_a72_cpu_reg_dump declare_cpu_ops_wa cortex_a72, CORTEX_A72_MIDR, \ cortex_a72_reset_func, \ check_errata_cve_2017_5715, \ CPU_NO_EXTRA2_FUNC, \ cortex_a72_core_pwr_dwn, \ cortex_a72_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/cortex_a73.S000066400000000000000000000146701355360272700221730ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* --------------------------------------------- * Disable L1 data cache * --------------------------------------------- */ func cortex_a73_disable_dcache mrs x1, sctlr_el3 bic x1, x1, #SCTLR_C_BIT msr sctlr_el3, x1 isb ret endfunc cortex_a73_disable_dcache /* --------------------------------------------- * Disable intra-cluster coherency * --------------------------------------------- */ func cortex_a73_disable_smp mrs x0, CORTEX_A73_CPUECTLR_EL1 bic x0, x0, #CORTEX_A73_CPUECTLR_SMP_BIT msr CORTEX_A73_CPUECTLR_EL1, x0 isb dsb sy ret endfunc cortex_a73_disable_smp /* --------------------------------------------------- * Errata Workaround for Cortex A73 Errata #852427. * This applies only to revision r0p0 of Cortex A73. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * --------------------------------------------------- */ func errata_a73_852427_wa /* * Compare x0 against revision r0p0 */ mov x17, x30 bl check_errata_852427 cbz x0, 1f mrs x1, CORTEX_A73_DIAGNOSTIC_REGISTER orr x1, x1, #(1 << 12) msr CORTEX_A73_DIAGNOSTIC_REGISTER, x1 isb 1: ret x17 endfunc errata_a73_852427_wa func check_errata_852427 mov x1, #0x00 b cpu_rev_var_ls endfunc check_errata_852427 /* --------------------------------------------------- * Errata Workaround for Cortex A73 Errata #855423. * This applies only to revision <= r0p1 of Cortex A73. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * --------------------------------------------------- */ func errata_a73_855423_wa /* * Compare x0 against revision r0p1 */ mov x17, x30 bl check_errata_855423 cbz x0, 1f mrs x1, CORTEX_A73_IMP_DEF_REG2 orr x1, x1, #(1 << 7) msr CORTEX_A73_IMP_DEF_REG2, x1 isb 1: ret x17 endfunc errata_a73_855423_wa func check_errata_855423 mov x1, #0x01 b cpu_rev_var_ls endfunc check_errata_855423 /* ------------------------------------------------- * The CPU Ops reset function for Cortex-A73. * ------------------------------------------------- */ func cortex_a73_reset_func mov x19, x30 bl cpu_get_rev_var mov x18, x0 #if ERRATA_A73_852427 mov x0, x18 bl errata_a73_852427_wa #endif #if ERRATA_A73_855423 mov x0, x18 bl errata_a73_855423_wa #endif #if IMAGE_BL31 && WORKAROUND_CVE_2017_5715 cpu_check_csv2 x0, 1f adr x0, wa_cve_2017_5715_bpiall_vbar msr vbar_el3, x0 /* isb will be performed before returning from this function */ 1: #endif #if WORKAROUND_CVE_2018_3639 mrs x0, CORTEX_A73_IMP_DEF_REG1 orr x0, x0, #CORTEX_A73_IMP_DEF_REG1_DISABLE_LOAD_PASS_STORE msr CORTEX_A73_IMP_DEF_REG1, x0 isb #endif /* --------------------------------------------- * Enable the SMP bit. * Clobbers : x0 * --------------------------------------------- */ mrs x0, CORTEX_A73_CPUECTLR_EL1 orr x0, x0, #CORTEX_A73_CPUECTLR_SMP_BIT msr CORTEX_A73_CPUECTLR_EL1, x0 isb ret x19 endfunc cortex_a73_reset_func func cortex_a73_core_pwr_dwn mov x18, x30 /* --------------------------------------------- * Turn off caches. * --------------------------------------------- */ bl cortex_a73_disable_dcache /* --------------------------------------------- * Flush L1 caches. * --------------------------------------------- */ mov x0, #DCCISW bl dcsw_op_level1 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ mov x30, x18 b cortex_a73_disable_smp endfunc cortex_a73_core_pwr_dwn func cortex_a73_cluster_pwr_dwn mov x18, x30 /* --------------------------------------------- * Turn off caches. * --------------------------------------------- */ bl cortex_a73_disable_dcache /* --------------------------------------------- * Flush L1 caches. * --------------------------------------------- */ mov x0, #DCCISW bl dcsw_op_level1 /* --------------------------------------------- * Disable the optional ACP. * --------------------------------------------- */ bl plat_disable_acp /* --------------------------------------------- * Flush L2 caches. * --------------------------------------------- */ mov x0, #DCCISW bl dcsw_op_level2 /* --------------------------------------------- * Come out of intra cluster coherency * --------------------------------------------- */ mov x30, x18 b cortex_a73_disable_smp endfunc cortex_a73_cluster_pwr_dwn func check_errata_cve_2017_5715 cpu_check_csv2 x0, 1f #if WORKAROUND_CVE_2017_5715 mov x0, #ERRATA_APPLIES #else mov x0, #ERRATA_MISSING #endif ret 1: mov x0, #ERRATA_NOT_APPLIES ret endfunc check_errata_cve_2017_5715 func check_errata_cve_2018_3639 #if WORKAROUND_CVE_2018_3639 mov x0, #ERRATA_APPLIES #else mov x0, #ERRATA_MISSING #endif ret endfunc check_errata_cve_2018_3639 #if REPORT_ERRATA /* * Errata printing function for Cortex A75. Must follow AAPCS. */ func cortex_a73_errata_report stp x8, x30, [sp, #-16]! bl cpu_get_rev_var mov x8, x0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata ERRATA_A73_852427, cortex_a73, 852427 report_errata ERRATA_A73_855423, cortex_a73, 855423 report_errata WORKAROUND_CVE_2017_5715, cortex_a73, cve_2017_5715 report_errata WORKAROUND_CVE_2018_3639, cortex_a73, cve_2018_3639 ldp x8, x30, [sp], #16 ret endfunc cortex_a73_errata_report #endif /* --------------------------------------------- * This function provides cortex_a73 specific * register information for crash reporting. * It needs to return with x6 pointing to * a list of register names in ascii and * x8 - x15 having values of registers to be * reported. * --------------------------------------------- */ .section .rodata.cortex_a73_regs, "aS" cortex_a73_regs: /* The ascii list of register names to be reported */ .asciz "cpuectlr_el1", "l2merrsr_el1", "" func cortex_a73_cpu_reg_dump adr x6, cortex_a73_regs mrs x8, CORTEX_A73_CPUECTLR_EL1 mrs x9, CORTEX_A73_L2MERRSR_EL1 ret endfunc cortex_a73_cpu_reg_dump declare_cpu_ops_wa cortex_a73, CORTEX_A73_MIDR, \ cortex_a73_reset_func, \ check_errata_cve_2017_5715, \ CPU_NO_EXTRA2_FUNC, \ cortex_a73_core_pwr_dwn, \ cortex_a73_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/cortex_a75.S000066400000000000000000000124501355360272700221670ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* Hardware handled coherency */ #if HW_ASSISTED_COHERENCY == 0 #error "Cortex-A75 must be compiled with HW_ASSISTED_COHERENCY enabled" #endif /* -------------------------------------------------- * Errata Workaround for Cortex A75 Errata #764081. * This applies only to revision r0p0 of Cortex A75. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_a75_764081_wa /* * Compare x0 against revision r0p0 */ mov x17, x30 bl check_errata_764081 cbz x0, 1f mrs x1, sctlr_el3 orr x1, x1 ,#SCTLR_IESB_BIT msr sctlr_el3, x1 isb 1: ret x17 endfunc errata_a75_764081_wa func check_errata_764081 mov x1, #0x00 b cpu_rev_var_ls endfunc check_errata_764081 /* -------------------------------------------------- * Errata Workaround for Cortex A75 Errata #790748. * This applies only to revision r0p0 of Cortex A75. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_a75_790748_wa /* * Compare x0 against revision r0p0 */ mov x17, x30 bl check_errata_790748 cbz x0, 1f mrs x1, CORTEX_A75_CPUACTLR_EL1 orr x1, x1 ,#(1 << 13) msr CORTEX_A75_CPUACTLR_EL1, x1 isb 1: ret x17 endfunc errata_a75_790748_wa func check_errata_790748 mov x1, #0x00 b cpu_rev_var_ls endfunc check_errata_790748 /* ------------------------------------------------- * The CPU Ops reset function for Cortex-A75. * ------------------------------------------------- */ func cortex_a75_reset_func mov x19, x30 bl cpu_get_rev_var mov x18, x0 #if ERRATA_A75_764081 mov x0, x18 bl errata_a75_764081_wa #endif #if ERRATA_A75_790748 mov x0, x18 bl errata_a75_790748_wa #endif #if IMAGE_BL31 && WORKAROUND_CVE_2017_5715 cpu_check_csv2 x0, 1f adr x0, wa_cve_2017_5715_bpiall_vbar msr vbar_el3, x0 isb 1: #endif #if WORKAROUND_CVE_2018_3639 mrs x0, CORTEX_A75_CPUACTLR_EL1 orr x0, x0, #CORTEX_A75_CPUACTLR_EL1_DISABLE_LOAD_PASS_STORE msr CORTEX_A75_CPUACTLR_EL1, x0 isb #endif #if ERRATA_DSU_798953 bl errata_dsu_798953_wa #endif #if ERRATA_DSU_936184 bl errata_dsu_936184_wa #endif #if ENABLE_AMU /* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */ mrs x0, actlr_el3 orr x0, x0, #CORTEX_A75_ACTLR_AMEN_BIT msr actlr_el3, x0 isb /* Make sure accesses from EL0/EL1 are not trapped to EL2 */ mrs x0, actlr_el2 orr x0, x0, #CORTEX_A75_ACTLR_AMEN_BIT msr actlr_el2, x0 isb /* Enable group0 counters */ mov x0, #CORTEX_A75_AMU_GROUP0_MASK msr CPUAMCNTENSET_EL0, x0 isb /* Enable group1 counters */ mov x0, #CORTEX_A75_AMU_GROUP1_MASK msr CPUAMCNTENSET_EL0, x0 isb #endif ret x19 endfunc cortex_a75_reset_func func check_errata_cve_2017_5715 cpu_check_csv2 x0, 1f #if WORKAROUND_CVE_2017_5715 mov x0, #ERRATA_APPLIES #else mov x0, #ERRATA_MISSING #endif ret 1: mov x0, #ERRATA_NOT_APPLIES ret endfunc check_errata_cve_2017_5715 func check_errata_cve_2018_3639 #if WORKAROUND_CVE_2018_3639 mov x0, #ERRATA_APPLIES #else mov x0, #ERRATA_MISSING #endif ret endfunc check_errata_cve_2018_3639 /* --------------------------------------------- * HW will do the cache maintenance while powering down * --------------------------------------------- */ func cortex_a75_core_pwr_dwn /* --------------------------------------------- * Enable CPU power down bit in power control register * --------------------------------------------- */ mrs x0, CORTEX_A75_CPUPWRCTLR_EL1 orr x0, x0, #CORTEX_A75_CORE_PWRDN_EN_MASK msr CORTEX_A75_CPUPWRCTLR_EL1, x0 isb ret endfunc cortex_a75_core_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex A75. Must follow AAPCS. */ func cortex_a75_errata_report stp x8, x30, [sp, #-16]! bl cpu_get_rev_var mov x8, x0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata ERRATA_A75_764081, cortex_a75, 764081 report_errata ERRATA_A75_790748, cortex_a75, 790748 report_errata WORKAROUND_CVE_2017_5715, cortex_a75, cve_2017_5715 report_errata WORKAROUND_CVE_2018_3639, cortex_a75, cve_2018_3639 report_errata ERRATA_DSU_798953, cortex_a75, dsu_798953 report_errata ERRATA_DSU_936184, cortex_a75, dsu_936184 ldp x8, x30, [sp], #16 ret endfunc cortex_a75_errata_report #endif /* --------------------------------------------- * This function provides cortex_a75 specific * register information for crash reporting. * It needs to return with x6 pointing to * a list of register names in ascii and * x8 - x15 having values of registers to be * reported. * --------------------------------------------- */ .section .rodata.cortex_a75_regs, "aS" cortex_a75_regs: /* The ascii list of register names to be reported */ .asciz "cpuectlr_el1", "" func cortex_a75_cpu_reg_dump adr x6, cortex_a75_regs mrs x8, CORTEX_A75_CPUECTLR_EL1 ret endfunc cortex_a75_cpu_reg_dump declare_cpu_ops_wa cortex_a75, CORTEX_A75_MIDR, \ cortex_a75_reset_func, \ check_errata_cve_2017_5715, \ CPU_NO_EXTRA2_FUNC, \ cortex_a75_core_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/cortex_a75_pubsub.c000066400000000000000000000013111355360272700235610ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include static void *cortex_a75_context_save(const void *arg) { if (midr_match(CORTEX_A75_MIDR) != 0) cpuamu_context_save(CORTEX_A75_AMU_NR_COUNTERS); return (void *)0; } static void *cortex_a75_context_restore(const void *arg) { if (midr_match(CORTEX_A75_MIDR) != 0) cpuamu_context_restore(CORTEX_A75_AMU_NR_COUNTERS); return (void *)0; } SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, cortex_a75_context_save); SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, cortex_a75_context_restore); trusted-firmware-a-2.2/lib/cpus/aarch64/cortex_a76.S000066400000000000000000000364401355360272700221750ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include /* Hardware handled coherency */ #if HW_ASSISTED_COHERENCY == 0 #error "Cortex-A76 must be compiled with HW_ASSISTED_COHERENCY enabled" #endif /* 64-bit only core */ #if CTX_INCLUDE_AARCH32_REGS == 1 #error "Cortex-A76 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0" #endif #define ESR_EL3_A64_SMC0 0x5e000000 #define ESR_EL3_A32_SMC0 0x4e000000 #if DYNAMIC_WORKAROUND_CVE_2018_3639 /* * This macro applies the mitigation for CVE-2018-3639. * It implements a fast path where `SMCCC_ARCH_WORKAROUND_2` * SMC calls from a lower EL running in AArch32 or AArch64 * will go through the fast and return early. * * The macro saves x2-x3 to the context. In the fast path * x0-x3 registers do not need to be restored as the calling * context will have saved them. */ .macro apply_cve_2018_3639_wa _is_sync_exception _esr_el3_val stp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] .if \_is_sync_exception /* * Ensure SMC is coming from A64/A32 state on #0 * with W0 = SMCCC_ARCH_WORKAROUND_2 * * This sequence evaluates as: * (W0==SMCCC_ARCH_WORKAROUND_2) ? (ESR_EL3==SMC#0) : (NE) * allowing use of a single branch operation */ orr w2, wzr, #SMCCC_ARCH_WORKAROUND_2 cmp x0, x2 mrs x3, esr_el3 mov_imm w2, \_esr_el3_val ccmp w2, w3, #0, eq /* * Static predictor will predict a fall-through, optimizing * the `SMCCC_ARCH_WORKAROUND_2` fast path. */ bne 1f /* * The sequence below implements the `SMCCC_ARCH_WORKAROUND_2` * fast path. */ cmp x1, xzr /* enable/disable check */ /* * When the calling context wants mitigation disabled, * we program the mitigation disable function in the * CPU context, which gets invoked on subsequent exits from * EL3 via the `el3_exit` function. Otherwise NULL is * programmed in the CPU context, which results in caller's * inheriting the EL3 mitigation state (enabled) on subsequent * `el3_exit`. */ mov x0, xzr adr x1, cortex_a76_disable_wa_cve_2018_3639 csel x1, x1, x0, eq str x1, [sp, #CTX_CVE_2018_3639_OFFSET + CTX_CVE_2018_3639_DISABLE] mrs x2, CORTEX_A76_CPUACTLR2_EL1 orr x1, x2, #CORTEX_A76_CPUACTLR2_EL1_DISABLE_LOAD_PASS_STORE bic x3, x2, #CORTEX_A76_CPUACTLR2_EL1_DISABLE_LOAD_PASS_STORE csel x3, x3, x1, eq msr CORTEX_A76_CPUACTLR2_EL1, x3 eret /* ERET implies ISB */ .endif 1: /* * Always enable v4 mitigation during EL3 execution. This is not * required for the fast path above because it does not perform any * memory loads. */ mrs x2, CORTEX_A76_CPUACTLR2_EL1 orr x2, x2, #CORTEX_A76_CPUACTLR2_EL1_DISABLE_LOAD_PASS_STORE msr CORTEX_A76_CPUACTLR2_EL1, x2 isb /* * The caller may have passed arguments to EL3 via x2-x3. * Restore these registers from the context before jumping to the * main runtime vector table entry. */ ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] .endm vector_base cortex_a76_wa_cve_2018_3639_a76_vbar /* --------------------------------------------------------------------- * Current EL with SP_EL0 : 0x0 - 0x200 * --------------------------------------------------------------------- */ vector_entry cortex_a76_sync_exception_sp_el0 b sync_exception_sp_el0 end_vector_entry cortex_a76_sync_exception_sp_el0 vector_entry cortex_a76_irq_sp_el0 b irq_sp_el0 end_vector_entry cortex_a76_irq_sp_el0 vector_entry cortex_a76_fiq_sp_el0 b fiq_sp_el0 end_vector_entry cortex_a76_fiq_sp_el0 vector_entry cortex_a76_serror_sp_el0 b serror_sp_el0 end_vector_entry cortex_a76_serror_sp_el0 /* --------------------------------------------------------------------- * Current EL with SP_ELx: 0x200 - 0x400 * --------------------------------------------------------------------- */ vector_entry cortex_a76_sync_exception_sp_elx b sync_exception_sp_elx end_vector_entry cortex_a76_sync_exception_sp_elx vector_entry cortex_a76_irq_sp_elx b irq_sp_elx end_vector_entry cortex_a76_irq_sp_elx vector_entry cortex_a76_fiq_sp_elx b fiq_sp_elx end_vector_entry cortex_a76_fiq_sp_elx vector_entry cortex_a76_serror_sp_elx b serror_sp_elx end_vector_entry cortex_a76_serror_sp_elx /* --------------------------------------------------------------------- * Lower EL using AArch64 : 0x400 - 0x600 * --------------------------------------------------------------------- */ vector_entry cortex_a76_sync_exception_aarch64 apply_cve_2018_3639_wa _is_sync_exception=1 _esr_el3_val=ESR_EL3_A64_SMC0 b sync_exception_aarch64 end_vector_entry cortex_a76_sync_exception_aarch64 vector_entry cortex_a76_irq_aarch64 apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A64_SMC0 b irq_aarch64 end_vector_entry cortex_a76_irq_aarch64 vector_entry cortex_a76_fiq_aarch64 apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A64_SMC0 b fiq_aarch64 end_vector_entry cortex_a76_fiq_aarch64 vector_entry cortex_a76_serror_aarch64 apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A64_SMC0 b serror_aarch64 end_vector_entry cortex_a76_serror_aarch64 /* --------------------------------------------------------------------- * Lower EL using AArch32 : 0x600 - 0x800 * --------------------------------------------------------------------- */ vector_entry cortex_a76_sync_exception_aarch32 apply_cve_2018_3639_wa _is_sync_exception=1 _esr_el3_val=ESR_EL3_A32_SMC0 b sync_exception_aarch32 end_vector_entry cortex_a76_sync_exception_aarch32 vector_entry cortex_a76_irq_aarch32 apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A32_SMC0 b irq_aarch32 end_vector_entry cortex_a76_irq_aarch32 vector_entry cortex_a76_fiq_aarch32 apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A32_SMC0 b fiq_aarch32 end_vector_entry cortex_a76_fiq_aarch32 vector_entry cortex_a76_serror_aarch32 apply_cve_2018_3639_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A32_SMC0 b serror_aarch32 end_vector_entry cortex_a76_serror_aarch32 #endif /* DYNAMIC_WORKAROUND_CVE_2018_3639 */ /* -------------------------------------------------- * Errata Workaround for Cortex A76 Errata #1073348. * This applies only to revision <= r1p0 of Cortex A76. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_a76_1073348_wa /* * Compare x0 against revision r1p0 */ mov x17, x30 bl check_errata_1073348 cbz x0, 1f mrs x1, CORTEX_A76_CPUACTLR_EL1 orr x1, x1 ,#CORTEX_A76_CPUACTLR_EL1_DISABLE_STATIC_PREDICTION msr CORTEX_A76_CPUACTLR_EL1, x1 isb 1: ret x17 endfunc errata_a76_1073348_wa func check_errata_1073348 mov x1, #0x10 b cpu_rev_var_ls endfunc check_errata_1073348 /* -------------------------------------------------- * Errata Workaround for Cortex A76 Errata #1130799. * This applies only to revision <= r2p0 of Cortex A76. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_a76_1130799_wa /* * Compare x0 against revision r2p0 */ mov x17, x30 bl check_errata_1130799 cbz x0, 1f mrs x1, CORTEX_A76_CPUACTLR2_EL1 orr x1, x1 ,#(1 << 59) msr CORTEX_A76_CPUACTLR2_EL1, x1 isb 1: ret x17 endfunc errata_a76_1130799_wa func check_errata_1130799 mov x1, #0x20 b cpu_rev_var_ls endfunc check_errata_1130799 /* -------------------------------------------------- * Errata Workaround for Cortex A76 Errata #1220197. * This applies only to revision <= r2p0 of Cortex A76. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_a76_1220197_wa /* * Compare x0 against revision r2p0 */ mov x17, x30 bl check_errata_1220197 cbz x0, 1f mrs x1, CORTEX_A76_CPUECTLR_EL1 orr x1, x1, #CORTEX_A76_CPUECTLR_EL1_WS_THR_L2 msr CORTEX_A76_CPUECTLR_EL1, x1 isb 1: ret x17 endfunc errata_a76_1220197_wa func check_errata_1220197 mov x1, #0x20 b cpu_rev_var_ls endfunc check_errata_1220197 /* -------------------------------------------------- * Errata Workaround for Cortex A76 Errata #1257314. * This applies only to revision <= r3p0 of Cortex A76. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_a76_1257314_wa /* * Compare x0 against revision r3p0 */ mov x17, x30 bl check_errata_1257314 cbz x0, 1f mrs x1, CORTEX_A76_CPUACTLR3_EL1 orr x1, x1, CORTEX_A76_CPUACTLR3_EL1_BIT_10 msr CORTEX_A76_CPUACTLR3_EL1, x1 isb 1: ret x17 endfunc errata_a76_1257314_wa func check_errata_1257314 mov x1, #0x30 b cpu_rev_var_ls endfunc check_errata_1257314 /* -------------------------------------------------- * Errata Workaround for Cortex A76 Errata #1262888. * This applies only to revision <= r3p0 of Cortex A76. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_a76_1262888_wa /* * Compare x0 against revision r3p0 */ mov x17, x30 bl check_errata_1262888 cbz x0, 1f mrs x1, CORTEX_A76_CPUECTLR_EL1 orr x1, x1, CORTEX_A76_CPUECTLR_EL1_BIT_51 msr CORTEX_A76_CPUECTLR_EL1, x1 isb 1: ret x17 endfunc errata_a76_1262888_wa func check_errata_1262888 mov x1, #0x30 b cpu_rev_var_ls endfunc check_errata_1262888 /* -------------------------------------------------- * Errata Workaround for Cortex A76 Errata #1275112 * and Errata #1262606. * This applies only to revision <= r3p0 of Cortex A76. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_a76_1275112_1262606_wa /* * Compare x0 against revision r3p0 */ mov x17, x30 /* * Since both errata #1275112 and #1262606 have the same check, we can * invoke any one of them for the check here. */ bl check_errata_1275112 cbz x0, 1f mrs x1, CORTEX_A76_CPUACTLR_EL1 orr x1, x1, CORTEX_A76_CPUACTLR_EL1_BIT_13 msr CORTEX_A76_CPUACTLR_EL1, x1 isb 1: ret x17 endfunc errata_a76_1275112_1262606_wa func check_errata_1262606 mov x1, #0x30 b cpu_rev_var_ls endfunc check_errata_1262606 func check_errata_1275112 mov x1, #0x30 b cpu_rev_var_ls endfunc check_errata_1275112 /* --------------------------------------------------- * Errata Workaround for Cortex A76 Errata #1286807. * This applies only to revision <= r3p0 of Cortex A76. * Due to the nature of the errata it is applied unconditionally * when built in, report it as applicable in this case * --------------------------------------------------- */ func check_errata_1286807 #if ERRATA_A76_1286807 mov x0, #ERRATA_APPLIES ret #else mov x1, #0x30 b cpu_rev_var_ls #endif endfunc check_errata_1286807 func check_errata_cve_2018_3639 #if WORKAROUND_CVE_2018_3639 mov x0, #ERRATA_APPLIES #else mov x0, #ERRATA_MISSING #endif ret endfunc check_errata_cve_2018_3639 func cortex_a76_disable_wa_cve_2018_3639 mrs x0, CORTEX_A76_CPUACTLR2_EL1 bic x0, x0, #CORTEX_A76_CPUACTLR2_EL1_DISABLE_LOAD_PASS_STORE msr CORTEX_A76_CPUACTLR2_EL1, x0 isb ret endfunc cortex_a76_disable_wa_cve_2018_3639 /* ------------------------------------------------- * The CPU Ops reset function for Cortex-A76. * Shall clobber: x0-x19 * ------------------------------------------------- */ func cortex_a76_reset_func mov x19, x30 bl cpu_get_rev_var mov x18, x0 #if ERRATA_A76_1073348 mov x0, x18 bl errata_a76_1073348_wa #endif #if ERRATA_A76_1130799 mov x0, x18 bl errata_a76_1130799_wa #endif #if ERRATA_A76_1220197 mov x0, x18 bl errata_a76_1220197_wa #endif #if ERRATA_A76_1257314 mov x0, x18 bl errata_a76_1257314_wa #endif #if ERRATA_A76_1262606 || ERRATA_A76_1275112 mov x0, x18 bl errata_a76_1275112_1262606_wa #endif #if ERRATA_A76_1262888 mov x0, x18 bl errata_a76_1262888_wa #endif #if WORKAROUND_CVE_2018_3639 /* If the PE implements SSBS, we don't need the dynamic workaround */ mrs x0, id_aa64pfr1_el1 lsr x0, x0, #ID_AA64PFR1_EL1_SSBS_SHIFT and x0, x0, #ID_AA64PFR1_EL1_SSBS_MASK #if !DYNAMIC_WORKAROUND_CVE_2018_3639 && ENABLE_ASSERTIONS cmp x0, 0 ASM_ASSERT(ne) #endif #if DYNAMIC_WORKAROUND_CVE_2018_3639 cbnz x0, 1f mrs x0, CORTEX_A76_CPUACTLR2_EL1 orr x0, x0, #CORTEX_A76_CPUACTLR2_EL1_DISABLE_LOAD_PASS_STORE msr CORTEX_A76_CPUACTLR2_EL1, x0 isb #ifdef IMAGE_BL31 /* * The Cortex-A76 generic vectors are overwritten to use the vectors * defined above. This is required in order to apply mitigation * against CVE-2018-3639 on exception entry from lower ELs. */ adr x0, cortex_a76_wa_cve_2018_3639_a76_vbar msr vbar_el3, x0 isb #endif /* IMAGE_BL31 */ 1: #endif /* DYNAMIC_WORKAROUND_CVE_2018_3639 */ #endif /* WORKAROUND_CVE_2018_3639 */ #if ERRATA_DSU_798953 bl errata_dsu_798953_wa #endif #if ERRATA_DSU_936184 bl errata_dsu_936184_wa #endif ret x19 endfunc cortex_a76_reset_func /* --------------------------------------------- * HW will do the cache maintenance while powering down * --------------------------------------------- */ func cortex_a76_core_pwr_dwn /* --------------------------------------------- * Enable CPU power down bit in power control register * --------------------------------------------- */ mrs x0, CORTEX_A76_CPUPWRCTLR_EL1 orr x0, x0, #CORTEX_A76_CORE_PWRDN_EN_MASK msr CORTEX_A76_CPUPWRCTLR_EL1, x0 isb ret endfunc cortex_a76_core_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex A76. Must follow AAPCS. */ func cortex_a76_errata_report stp x8, x30, [sp, #-16]! bl cpu_get_rev_var mov x8, x0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata ERRATA_A76_1073348, cortex_a76, 1073348 report_errata ERRATA_A76_1130799, cortex_a76, 1130799 report_errata ERRATA_A76_1220197, cortex_a76, 1220197 report_errata ERRATA_A76_1257314, cortex_a76, 1257314 report_errata ERRATA_A76_1262606, cortex_a76, 1262606 report_errata ERRATA_A76_1262888, cortex_a76, 1262888 report_errata ERRATA_A76_1275112, cortex_a76, 1275112 report_errata ERRATA_A76_1286807, cortex_a76, 1286807 report_errata WORKAROUND_CVE_2018_3639, cortex_a76, cve_2018_3639 report_errata ERRATA_DSU_798953, cortex_a76, dsu_798953 report_errata ERRATA_DSU_936184, cortex_a76, dsu_936184 ldp x8, x30, [sp], #16 ret endfunc cortex_a76_errata_report #endif /* --------------------------------------------- * This function provides cortex_a76 specific * register information for crash reporting. * It needs to return with x6 pointing to * a list of register names in ascii and * x8 - x15 having values of registers to be * reported. * --------------------------------------------- */ .section .rodata.cortex_a76_regs, "aS" cortex_a76_regs: /* The ascii list of register names to be reported */ .asciz "cpuectlr_el1", "" func cortex_a76_cpu_reg_dump adr x6, cortex_a76_regs mrs x8, CORTEX_A76_CPUECTLR_EL1 ret endfunc cortex_a76_cpu_reg_dump declare_cpu_ops_wa cortex_a76, CORTEX_A76_MIDR, \ cortex_a76_reset_func, \ CPU_NO_EXTRA1_FUNC, \ cortex_a76_disable_wa_cve_2018_3639, \ cortex_a76_core_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/cortex_a76ae.S000066400000000000000000000035631355360272700225030ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /* Hardware handled coherency */ #if HW_ASSISTED_COHERENCY == 0 #error "Cortex-A76AE must be compiled with HW_ASSISTED_COHERENCY enabled" #endif /* 64-bit only core */ #if CTX_INCLUDE_AARCH32_REGS == 1 #error "Cortex-A76AE supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0" #endif /* --------------------------------------------- * HW will do the cache maintenance while powering down * --------------------------------------------- */ func cortex_a76ae_core_pwr_dwn /* --------------------------------------------- * Enable CPU power down bit in power control register * --------------------------------------------- */ mrs x0, CORTEX_A76AE_CPUPWRCTLR_EL1 orr x0, x0, #CORTEX_A76AE_CORE_PWRDN_EN_MASK msr CORTEX_A76AE_CPUPWRCTLR_EL1, x0 isb ret endfunc cortex_a76ae_core_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex-A76AE. Must follow AAPCS. */ func cortex_a76ae_errata_report ret endfunc cortex_a76ae_errata_report #endif /* REPORT_ERRATA */ /* --------------------------------------------- * This function provides cortex_a76ae specific * register information for crash reporting. * It needs to return with x6 pointing to * a list of register names in ascii and * x8 - x15 having values of registers to be * reported. * --------------------------------------------- */ .section .rodata.cortex_a76ae_regs, "aS" cortex_a76ae_regs: /* The ASCII list of register names to be reported */ .asciz "cpuectlr_el1", "" func cortex_a76ae_cpu_reg_dump adr x6, cortex_a76ae_regs mrs x8, CORTEX_A76AE_CPUECTLR_EL1 ret endfunc cortex_a76ae_cpu_reg_dump declare_cpu_ops cortex_a76ae, CORTEX_A76AE_MIDR, CPU_NO_RESET_FUNC, \ cortex_a76ae_core_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/cortex_a77.S000066400000000000000000000036431355360272700221750ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* Hardware handled coherency */ #if HW_ASSISTED_COHERENCY == 0 #error "Cortex-A77 must be compiled with HW_ASSISTED_COHERENCY enabled" #endif /* 64-bit only core */ #if CTX_INCLUDE_AARCH32_REGS == 1 #error "Cortex-A77 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0" #endif /* --------------------------------------------- * HW will do the cache maintenance while powering down * --------------------------------------------- */ func cortex_a77_core_pwr_dwn /* --------------------------------------------- * Enable CPU power down bit in power control register * --------------------------------------------- */ mrs x0, CORTEX_A77_CPUPWRCTLR_EL1 orr x0, x0, #CORTEX_A77_CPUPWRCTLR_EL1_CORE_PWRDN_BIT msr CORTEX_A77_CPUPWRCTLR_EL1, x0 isb ret endfunc cortex_a77_core_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Cortex-A77. Must follow AAPCS. */ func cortex_a77_errata_report ret endfunc cortex_a77_errata_report #endif /* --------------------------------------------- * This function provides Cortex-A77 specific * register information for crash reporting. * It needs to return with x6 pointing to * a list of register names in ascii and * x8 - x15 having values of registers to be * reported. * --------------------------------------------- */ .section .rodata.cortex_a77_regs, "aS" cortex_a77_regs: /* The ascii list of register names to be reported */ .asciz "cpuectlr_el1", "" func cortex_a77_cpu_reg_dump adr x6, cortex_a77_regs mrs x8, CORTEX_A77_CPUECTLR_EL1 ret endfunc cortex_a77_cpu_reg_dump declare_cpu_ops cortex_a77, CORTEX_A77_MIDR, \ CPU_NO_RESET_FUNC, \ cortex_a77_core_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/cortex_hercules.S000066400000000000000000000053551355360272700234130ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* Hardware handled coherency */ #if HW_ASSISTED_COHERENCY == 0 #error "cortex_hercules must be compiled with HW_ASSISTED_COHERENCY enabled" #endif /* ------------------------------------------------- * The CPU Ops reset function for Cortex-Hercules * ------------------------------------------------- */ #if ENABLE_AMU func cortex_hercules_reset_func /* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */ mrs x0, actlr_el3 bic x0, x0, #CORTEX_HERCULES_ACTLR_TAM_BIT msr actlr_el3, x0 /* Make sure accesses from non-secure EL0/EL1 are not trapped to EL2 */ mrs x0, actlr_el2 bic x0, x0, #CORTEX_HERCULES_ACTLR_TAM_BIT msr actlr_el2, x0 /* Enable group0 counters */ mov x0, #CORTEX_HERCULES_AMU_GROUP0_MASK msr CPUAMCNTENSET0_EL0, x0 /* Enable group1 counters */ mov x0, #CORTEX_HERCULES_AMU_GROUP1_MASK msr CPUAMCNTENSET1_EL0, x0 isb ret endfunc cortex_hercules_reset_func #endif /* --------------------------------------------- * HW will do the cache maintenance while powering down * --------------------------------------------- */ func cortex_hercules_core_pwr_dwn /* --------------------------------------------- * Enable CPU power down bit in power control register * --------------------------------------------- */ mrs x0, CORTEX_HERCULES_CPUPWRCTLR_EL1 orr x0, x0, #CORTEX_HERCULES_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT msr CORTEX_HERCULES_CPUPWRCTLR_EL1, x0 isb ret endfunc cortex_hercules_core_pwr_dwn /* * Errata printing function for cortex_hercules. Must follow AAPCS. */ #if REPORT_ERRATA func cortex_hercules_errata_report ret endfunc cortex_hercules_errata_report #endif /* --------------------------------------------- * This function provides cortex_hercules specific * register information for crash reporting. * It needs to return with x6 pointing to * a list of register names in ascii and * x8 - x15 having values of registers to be * reported. * --------------------------------------------- */ .section .rodata.cortex_hercules_regs, "aS" cortex_hercules_regs: /* The ascii list of register names to be reported */ .asciz "cpuectlr_el1", "" func cortex_hercules_cpu_reg_dump adr x6, cortex_hercules_regs mrs x8, CORTEX_HERCULES_CPUECTLR_EL1 ret endfunc cortex_hercules_cpu_reg_dump #if ENABLE_AMU #define HERCULES_RESET_FUNC cortex_hercules_reset_func #else #define HERCULES_RESET_FUNC CPU_NO_RESET_FUNC #endif declare_cpu_ops cortex_hercules, CORTEX_HERCULES_MIDR, \ HERCULES_RESET_FUNC, \ cortex_hercules_core_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/cortex_hercules_ae.S000066400000000000000000000055561355360272700240630ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* Hardware handled coherency */ #if HW_ASSISTED_COHERENCY == 0 #error "cortex_hercules_ae must be compiled with HW_ASSISTED_COHERENCY enabled" #endif /* ------------------------------------------------- * The CPU Ops reset function for Cortex-Hercules-AE * ------------------------------------------------- */ #if ENABLE_AMU func cortex_hercules_ae_reset_func /* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */ mrs x0, actlr_el3 bic x0, x0, #CORTEX_HERCULES_ACTLR_TAM_BIT msr actlr_el3, x0 /* Make sure accesses from non-secure EL0/EL1 are not trapped to EL2 */ mrs x0, actlr_el2 bic x0, x0, #CORTEX_HERCULES_ACTLR_TAM_BIT msr actlr_el2, x0 /* Enable group0 counters */ mov x0, #CORTEX_HERCULES_AMU_GROUP0_MASK msr CPUAMCNTENSET0_EL0, x0 /* Enable group1 counters */ mov x0, #CORTEX_HERCULES_AMU_GROUP1_MASK msr CPUAMCNTENSET1_EL0, x0 isb ret endfunc cortex_hercules_ae_reset_func #endif /* ------------------------------------------------------- * HW will do the cache maintenance while powering down * ------------------------------------------------------- */ func cortex_hercules_ae_core_pwr_dwn /* ------------------------------------------------------- * Enable CPU power down bit in power control register * ------------------------------------------------------- */ mrs x0, CORTEX_HERCULES_CPUPWRCTLR_EL1 orr x0, x0, #CORTEX_HERCULES_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT msr CORTEX_HERCULES_CPUPWRCTLR_EL1, x0 isb ret endfunc cortex_hercules_ae_core_pwr_dwn /* * Errata printing function for cortex_hercules_ae. Must follow AAPCS. */ #if REPORT_ERRATA func cortex_hercules_ae_errata_report ret endfunc cortex_hercules_ae_errata_report #endif /* ------------------------------------------------------- * This function provides cortex_hercules_ae specific * register information for crash reporting. * It needs to return with x6 pointing to * a list of register names in ascii and * x8 - x15 having values of registers to be * reported. * ------------------------------------------------------- */ .section .rodata.cortex_hercules_ae_regs, "aS" cortex_hercules_ae_regs: /* The ascii list of register names to be reported */ .asciz "cpuectlr_el1", "" func cortex_hercules_ae_cpu_reg_dump adr x6, cortex_hercules_ae_regs mrs x8, CORTEX_HERCULES_CPUECTLR_EL1 ret endfunc cortex_hercules_ae_cpu_reg_dump #if ENABLE_AMU #define HERCULES_AE_RESET_FUNC cortex_hercules_ae_reset_func #else #define HERCULES_AE_RESET_FUNC CPU_NO_RESET_FUNC #endif declare_cpu_ops cortex_hercules_ae, CORTEX_HERCULES_AE_MIDR, \ HERCULES_AE_RESET_FUNC, \ cortex_hercules_ae_core_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/cpu_helpers.S000066400000000000000000000215021355360272700225160ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include /* Reset fn is needed in BL at reset vector */ #if defined(IMAGE_BL1) || defined(IMAGE_BL31) || (defined(IMAGE_BL2) && BL2_AT_EL3) /* * The reset handler common to all platforms. After a matching * cpu_ops structure entry is found, the correponding reset_handler * in the cpu_ops is invoked. * Clobbers: x0 - x19, x30 */ .globl reset_handler func reset_handler mov x19, x30 /* The plat_reset_handler can clobber x0 - x18, x30 */ bl plat_reset_handler /* Get the matching cpu_ops pointer */ bl get_cpu_ops_ptr #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* Get the cpu_ops reset handler */ ldr x2, [x0, #CPU_RESET_FUNC] mov x30, x19 cbz x2, 1f /* The cpu_ops reset handler can clobber x0 - x19, x30 */ br x2 1: ret endfunc reset_handler #endif #ifdef IMAGE_BL31 /* The power down core and cluster is needed only in BL31 */ /* * void prepare_cpu_pwr_dwn(unsigned int power_level) * * Prepare CPU power down function for all platforms. The function takes * a domain level to be powered down as its parameter. After the cpu_ops * pointer is retrieved from cpu_data, the handler for requested power * level is called. */ .globl prepare_cpu_pwr_dwn func prepare_cpu_pwr_dwn /* * If the given power level exceeds CPU_MAX_PWR_DWN_OPS, we call the * power down handler for the last power level */ mov_imm x2, (CPU_MAX_PWR_DWN_OPS - 1) cmp x0, x2 csel x2, x2, x0, hi mrs x1, tpidr_el3 ldr x0, [x1, #CPU_DATA_CPU_OPS_PTR] #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* Get the appropriate power down handler */ mov x1, #CPU_PWR_DWN_OPS add x1, x1, x2, lsl #3 ldr x1, [x0, x1] br x1 endfunc prepare_cpu_pwr_dwn /* * Initializes the cpu_ops_ptr if not already initialized * in cpu_data. This can be called without a runtime stack, but may * only be called after the MMU is enabled. * clobbers: x0 - x6, x10 */ .globl init_cpu_ops func init_cpu_ops mrs x6, tpidr_el3 ldr x0, [x6, #CPU_DATA_CPU_OPS_PTR] cbnz x0, 1f mov x10, x30 bl get_cpu_ops_ptr #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif str x0, [x6, #CPU_DATA_CPU_OPS_PTR]! mov x30, x10 1: ret endfunc init_cpu_ops #endif /* IMAGE_BL31 */ #if defined(IMAGE_BL31) && CRASH_REPORTING /* * The cpu specific registers which need to be reported in a crash * are reported via cpu_ops cpu_reg_dump function. After a matching * cpu_ops structure entry is found, the correponding cpu_reg_dump * in the cpu_ops is invoked. */ .globl do_cpu_reg_dump func do_cpu_reg_dump mov x16, x30 /* Get the matching cpu_ops pointer */ bl get_cpu_ops_ptr cbz x0, 1f /* Get the cpu_ops cpu_reg_dump */ ldr x2, [x0, #CPU_REG_DUMP] cbz x2, 1f blr x2 1: mov x30, x16 ret endfunc do_cpu_reg_dump #endif /* * The below function returns the cpu_ops structure matching the * midr of the core. It reads the MIDR_EL1 and finds the matching * entry in cpu_ops entries. Only the implementation and part number * are used to match the entries. * Return : * x0 - The matching cpu_ops pointer on Success * x0 - 0 on failure. * Clobbers : x0 - x5 */ .globl get_cpu_ops_ptr func get_cpu_ops_ptr /* Get the cpu_ops start and end locations */ adr x4, (__CPU_OPS_START__ + CPU_MIDR) adr x5, (__CPU_OPS_END__ + CPU_MIDR) /* Initialize the return parameter */ mov x0, #0 /* Read the MIDR_EL1 */ mrs x2, midr_el1 mov_imm x3, CPU_IMPL_PN_MASK /* Retain only the implementation and part number using mask */ and w2, w2, w3 1: /* Check if we have reached end of list */ cmp x4, x5 b.eq error_exit /* load the midr from the cpu_ops */ ldr x1, [x4], #CPU_OPS_SIZE and w1, w1, w3 /* Check if midr matches to midr of this core */ cmp w1, w2 b.ne 1b /* Subtract the increment and offset to get the cpu-ops pointer */ sub x0, x4, #(CPU_OPS_SIZE + CPU_MIDR) error_exit: ret endfunc get_cpu_ops_ptr /* * Extract CPU revision and variant, and combine them into a single numeric for * easier comparison. */ .globl cpu_get_rev_var func cpu_get_rev_var mrs x1, midr_el1 /* * Extract the variant[23:20] and revision[3:0] from MIDR, and pack them * as variant[7:4] and revision[3:0] of x0. * * First extract x1[23:16] to x0[7:0] and zero fill the rest. Then * extract x1[3:0] into x0[3:0] retaining other bits. */ ubfx x0, x1, #(MIDR_VAR_SHIFT - MIDR_REV_BITS), #(MIDR_REV_BITS + MIDR_VAR_BITS) bfxil x0, x1, #MIDR_REV_SHIFT, #MIDR_REV_BITS ret endfunc cpu_get_rev_var /* * Compare the CPU's revision-variant (x0) with a given value (x1), for errata * application purposes. If the revision-variant is less than or same as a given * value, indicates that errata applies; otherwise not. * * Shall clobber: x0-x3 */ .globl cpu_rev_var_ls func cpu_rev_var_ls mov x2, #ERRATA_APPLIES mov x3, #ERRATA_NOT_APPLIES cmp x0, x1 csel x0, x2, x3, ls ret endfunc cpu_rev_var_ls /* * Compare the CPU's revision-variant (x0) with a given value (x1), for errata * application purposes. If the revision-variant is higher than or same as a * given value, indicates that errata applies; otherwise not. * * Shall clobber: x0-x3 */ .globl cpu_rev_var_hs func cpu_rev_var_hs mov x2, #ERRATA_APPLIES mov x3, #ERRATA_NOT_APPLIES cmp x0, x1 csel x0, x2, x3, hs ret endfunc cpu_rev_var_hs /* * Compare the CPU's revision-variant (x0) with a given range (x1 - x2), for errata * application purposes. If the revision-variant is between or includes the given * values, this indicates that errata applies; otherwise not. * * Shall clobber: x0-x4 */ .globl cpu_rev_var_range func cpu_rev_var_range mov x3, #ERRATA_APPLIES mov x4, #ERRATA_NOT_APPLIES cmp x0, x1 csel x1, x3, x4, hs cbz x1, 1f cmp x0, x2 csel x1, x3, x4, ls 1: mov x0, x1 ret endfunc cpu_rev_var_range #if REPORT_ERRATA /* * void print_errata_status(void); * * Function to print errata status for CPUs of its class. Must be called only: * * - with MMU and data caches are enabled; * - after cpu_ops have been initialized in per-CPU data. */ .globl print_errata_status func print_errata_status #ifdef IMAGE_BL1 /* * BL1 doesn't have per-CPU data. So retrieve the CPU operations * directly. */ stp xzr, x30, [sp, #-16]! bl get_cpu_ops_ptr ldp xzr, x30, [sp], #16 ldr x1, [x0, #CPU_ERRATA_FUNC] cbnz x1, .Lprint #else /* * Retrieve pointer to cpu_ops from per-CPU data, and further, the * errata printing function. If it's non-NULL, jump to the function in * turn. */ mrs x0, tpidr_el3 ldr x1, [x0, #CPU_DATA_CPU_OPS_PTR] ldr x0, [x1, #CPU_ERRATA_FUNC] cbz x0, .Lnoprint /* * Printing errata status requires atomically testing the printed flag. */ stp x19, x30, [sp, #-16]! mov x19, x0 /* * Load pointers to errata lock and printed flag. Call * errata_needs_reporting to check whether this CPU needs to report * errata status pertaining to its class. */ ldr x0, [x1, #CPU_ERRATA_LOCK] ldr x1, [x1, #CPU_ERRATA_PRINTED] bl errata_needs_reporting mov x1, x19 ldp x19, x30, [sp], #16 cbnz x0, .Lprint #endif .Lnoprint: ret .Lprint: /* Jump to errata reporting function for this CPU */ br x1 endfunc print_errata_status #endif /* * int check_wa_cve_2017_5715(void); * * This function returns: * - ERRATA_APPLIES when firmware mitigation is required. * - ERRATA_NOT_APPLIES when firmware mitigation is _not_ required. * - ERRATA_MISSING when firmware mitigation would be required but * is not compiled in. * * NOTE: Must be called only after cpu_ops have been initialized * in per-CPU data. */ .globl check_wa_cve_2017_5715 func check_wa_cve_2017_5715 mrs x0, tpidr_el3 #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif ldr x0, [x0, #CPU_DATA_CPU_OPS_PTR] ldr x0, [x0, #CPU_EXTRA1_FUNC] /* * If the reserved function pointer is NULL, this CPU * is unaffected by CVE-2017-5715 so bail out. */ cmp x0, #0 beq 1f br x0 1: mov x0, #ERRATA_NOT_APPLIES ret endfunc check_wa_cve_2017_5715 /* * void *wa_cve_2018_3639_get_disable_ptr(void); * * Returns a function pointer which is used to disable mitigation * for CVE-2018-3639. * The function pointer is only returned on cores that employ * dynamic mitigation. If the core uses static mitigation or is * unaffected by CVE-2018-3639 this function returns NULL. * * NOTE: Must be called only after cpu_ops have been initialized * in per-CPU data. */ .globl wa_cve_2018_3639_get_disable_ptr func wa_cve_2018_3639_get_disable_ptr mrs x0, tpidr_el3 #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif ldr x0, [x0, #CPU_DATA_CPU_OPS_PTR] ldr x0, [x0, #CPU_EXTRA2_FUNC] ret endfunc wa_cve_2018_3639_get_disable_ptr trusted-firmware-a-2.2/lib/cpus/aarch64/cpuamu.c000066400000000000000000000030601355360272700215160ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #define CPUAMU_NR_COUNTERS 5U struct cpuamu_ctx { uint64_t cnts[CPUAMU_NR_COUNTERS]; unsigned int mask; }; static struct cpuamu_ctx cpuamu_ctxs[PLATFORM_CORE_COUNT]; int midr_match(unsigned int cpu_midr) { unsigned int midr, midr_mask; midr = (unsigned int)read_midr(); midr_mask = (MIDR_IMPL_MASK << MIDR_IMPL_SHIFT) | (MIDR_PN_MASK << MIDR_PN_SHIFT); return ((midr & midr_mask) == (cpu_midr & midr_mask)); } void cpuamu_context_save(unsigned int nr_counters) { struct cpuamu_ctx *ctx = &cpuamu_ctxs[plat_my_core_pos()]; unsigned int i; assert(nr_counters <= CPUAMU_NR_COUNTERS); /* Save counter configuration */ ctx->mask = cpuamu_read_cpuamcntenset_el0(); /* Disable counters */ cpuamu_write_cpuamcntenclr_el0(ctx->mask); isb(); /* Save counters */ for (i = 0; i < nr_counters; i++) ctx->cnts[i] = cpuamu_cnt_read(i); } void cpuamu_context_restore(unsigned int nr_counters) { struct cpuamu_ctx *ctx = &cpuamu_ctxs[plat_my_core_pos()]; unsigned int i; assert(nr_counters <= CPUAMU_NR_COUNTERS); /* * Disable counters. They were enabled early in the * CPU reset function. */ cpuamu_write_cpuamcntenclr_el0(ctx->mask); isb(); /* Restore counters */ for (i = 0; i < nr_counters; i++) cpuamu_cnt_write(i, ctx->cnts[i]); isb(); /* Restore counter configuration */ cpuamu_write_cpuamcntenset_el0(ctx->mask); } trusted-firmware-a-2.2/lib/cpus/aarch64/cpuamu_helpers.S000066400000000000000000000043201355360272700232200ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl cpuamu_cnt_read .globl cpuamu_cnt_write .globl cpuamu_read_cpuamcntenset_el0 .globl cpuamu_read_cpuamcntenclr_el0 .globl cpuamu_write_cpuamcntenset_el0 .globl cpuamu_write_cpuamcntenclr_el0 /* * uint64_t cpuamu_cnt_read(unsigned int idx); * * Given `idx`, read the corresponding AMU counter * and return it in `x0`. */ func cpuamu_cnt_read adr x1, 1f add x1, x1, x0, lsl #3 /* each mrs/ret sequence is 8 bytes */ #if ENABLE_BTI add x1, x1, x0, lsl #2 /* + "bti j" instruction */ #endif br x1 1: read CPUAMEVCNTR0_EL0 read CPUAMEVCNTR1_EL0 read CPUAMEVCNTR2_EL0 read CPUAMEVCNTR3_EL0 read CPUAMEVCNTR4_EL0 endfunc cpuamu_cnt_read /* * void cpuamu_cnt_write(unsigned int idx, uint64_t val); * * Given `idx`, write `val` to the corresponding AMU counter. */ func cpuamu_cnt_write adr x2, 1f add x2, x2, x0, lsl #3 /* each msr/ret sequence is 8 bytes */ #if ENABLE_BTI add x2, x2, x0, lsl #2 /* + "bti j" instruction */ #endif br x2 1: write CPUAMEVCNTR0_EL0 write CPUAMEVCNTR1_EL0 write CPUAMEVCNTR2_EL0 write CPUAMEVCNTR3_EL0 write CPUAMEVCNTR4_EL0 endfunc cpuamu_cnt_write /* * unsigned int cpuamu_read_cpuamcntenset_el0(void); * * Read the `CPUAMCNTENSET_EL0` CPU register and return * it in `x0`. */ func cpuamu_read_cpuamcntenset_el0 mrs x0, CPUAMCNTENSET_EL0 ret endfunc cpuamu_read_cpuamcntenset_el0 /* * unsigned int cpuamu_read_cpuamcntenclr_el0(void); * * Read the `CPUAMCNTENCLR_EL0` CPU register and return * it in `x0`. */ func cpuamu_read_cpuamcntenclr_el0 mrs x0, CPUAMCNTENCLR_EL0 ret endfunc cpuamu_read_cpuamcntenclr_el0 /* * void cpuamu_write_cpuamcntenset_el0(unsigned int mask); * * Write `mask` to the `CPUAMCNTENSET_EL0` CPU register. */ func cpuamu_write_cpuamcntenset_el0 msr CPUAMCNTENSET_EL0, x0 ret endfunc cpuamu_write_cpuamcntenset_el0 /* * void cpuamu_write_cpuamcntenclr_el0(unsigned int mask); * * Write `mask` to the `CPUAMCNTENCLR_EL0` CPU register. */ func cpuamu_write_cpuamcntenclr_el0 msr CPUAMCNTENCLR_EL0, x0 ret endfunc cpuamu_write_cpuamcntenclr_el0 trusted-firmware-a-2.2/lib/cpus/aarch64/denver.S000066400000000000000000000236241355360272700214770ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* ------------------------------------------------- * CVE-2017-5715 mitigation * * Flush the indirect branch predictor and RSB on * entry to EL3 by issuing a newly added instruction * for Denver CPUs. * * To achieve this without performing any branch * instruction, a per-cpu vbar is installed which * executes the workaround and then branches off to * the corresponding vector entry in the main vector * table. * ------------------------------------------------- */ .globl workaround_bpflush_runtime_exceptions vector_base workaround_bpflush_runtime_exceptions .macro apply_workaround stp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] /* ------------------------------------------------- * A new write-only system register where a write of * 1 to bit 0 will cause the indirect branch predictor * and RSB to be flushed. * * A write of 0 to bit 0 will be ignored. A write of * 1 to any other bit will cause an MCA. * ------------------------------------------------- */ mov x0, #1 msr s3_0_c15_c0_6, x0 isb ldp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] .endm /* --------------------------------------------------------------------- * Current EL with SP_EL0 : 0x0 - 0x200 * --------------------------------------------------------------------- */ vector_entry workaround_bpflush_sync_exception_sp_el0 b sync_exception_sp_el0 end_vector_entry workaround_bpflush_sync_exception_sp_el0 vector_entry workaround_bpflush_irq_sp_el0 b irq_sp_el0 end_vector_entry workaround_bpflush_irq_sp_el0 vector_entry workaround_bpflush_fiq_sp_el0 b fiq_sp_el0 end_vector_entry workaround_bpflush_fiq_sp_el0 vector_entry workaround_bpflush_serror_sp_el0 b serror_sp_el0 end_vector_entry workaround_bpflush_serror_sp_el0 /* --------------------------------------------------------------------- * Current EL with SP_ELx: 0x200 - 0x400 * --------------------------------------------------------------------- */ vector_entry workaround_bpflush_sync_exception_sp_elx b sync_exception_sp_elx end_vector_entry workaround_bpflush_sync_exception_sp_elx vector_entry workaround_bpflush_irq_sp_elx b irq_sp_elx end_vector_entry workaround_bpflush_irq_sp_elx vector_entry workaround_bpflush_fiq_sp_elx b fiq_sp_elx end_vector_entry workaround_bpflush_fiq_sp_elx vector_entry workaround_bpflush_serror_sp_elx b serror_sp_elx end_vector_entry workaround_bpflush_serror_sp_elx /* --------------------------------------------------------------------- * Lower EL using AArch64 : 0x400 - 0x600 * --------------------------------------------------------------------- */ vector_entry workaround_bpflush_sync_exception_aarch64 apply_workaround b sync_exception_aarch64 end_vector_entry workaround_bpflush_sync_exception_aarch64 vector_entry workaround_bpflush_irq_aarch64 apply_workaround b irq_aarch64 end_vector_entry workaround_bpflush_irq_aarch64 vector_entry workaround_bpflush_fiq_aarch64 apply_workaround b fiq_aarch64 end_vector_entry workaround_bpflush_fiq_aarch64 vector_entry workaround_bpflush_serror_aarch64 apply_workaround b serror_aarch64 end_vector_entry workaround_bpflush_serror_aarch64 /* --------------------------------------------------------------------- * Lower EL using AArch32 : 0x600 - 0x800 * --------------------------------------------------------------------- */ vector_entry workaround_bpflush_sync_exception_aarch32 apply_workaround b sync_exception_aarch32 end_vector_entry workaround_bpflush_sync_exception_aarch32 vector_entry workaround_bpflush_irq_aarch32 apply_workaround b irq_aarch32 end_vector_entry workaround_bpflush_irq_aarch32 vector_entry workaround_bpflush_fiq_aarch32 apply_workaround b fiq_aarch32 end_vector_entry workaround_bpflush_fiq_aarch32 vector_entry workaround_bpflush_serror_aarch32 apply_workaround b serror_aarch32 end_vector_entry workaround_bpflush_serror_aarch32 .global denver_disable_dco /* --------------------------------------------- * Disable debug interfaces * --------------------------------------------- */ func denver_disable_ext_debug mov x0, #1 msr osdlr_el1, x0 isb dsb sy ret endfunc denver_disable_ext_debug /* ---------------------------------------------------- * Enable dynamic code optimizer (DCO) * ---------------------------------------------------- */ func denver_enable_dco mov x3, x30 bl plat_my_core_pos mov x1, #1 lsl x1, x1, x0 msr s3_0_c15_c0_2, x1 mov x30, x3 ret endfunc denver_enable_dco /* ---------------------------------------------------- * Disable dynamic code optimizer (DCO) * ---------------------------------------------------- */ func denver_disable_dco mov x3, x30 /* turn off background work */ bl plat_my_core_pos mov x1, #1 lsl x1, x1, x0 lsl x2, x1, #16 msr s3_0_c15_c0_2, x2 isb /* wait till the background work turns off */ 1: mrs x2, s3_0_c15_c0_2 lsr x2, x2, #32 and w2, w2, 0xFFFF and x2, x2, x1 cbnz x2, 1b mov x30, x3 ret endfunc denver_disable_dco func check_errata_cve_2017_5715 mov x0, #ERRATA_MISSING #if WORKAROUND_CVE_2017_5715 /* * Check if the CPU supports the special instruction * required to flush the indirect branch predictor and * RSB. Support for this operation can be determined by * comparing bits 19:16 of ID_AFR0_EL1 with 0b0001. */ mrs x1, id_afr0_el1 mov x2, #0x10000 and x1, x1, x2 cbz x1, 1f mov x0, #ERRATA_APPLIES 1: #endif ret endfunc check_errata_cve_2017_5715 func check_errata_cve_2018_3639 #if WORKAROUND_CVE_2018_3639 mov x0, #ERRATA_APPLIES #else mov x0, #ERRATA_MISSING #endif ret endfunc check_errata_cve_2018_3639 /* ------------------------------------------------- * The CPU Ops reset function for Denver. * ------------------------------------------------- */ func denver_reset_func mov x19, x30 #if IMAGE_BL31 && WORKAROUND_CVE_2017_5715 /* * Check if the CPU supports the special instruction * required to flush the indirect branch predictor and * RSB. Support for this operation can be determined by * comparing bits 19:16 of ID_AFR0_EL1 with 0b0001. */ mrs x0, id_afr0_el1 mov x1, #0x10000 and x0, x0, x1 cmp x0, #0 adr x1, workaround_bpflush_runtime_exceptions mrs x2, vbar_el3 csel x0, x1, x2, ne msr vbar_el3, x0 #endif #if WORKAROUND_CVE_2018_3639 /* * Denver CPUs with DENVER_MIDR_PN3 or earlier, use different * bits in the ACTLR_EL3 register to disable speculative * store buffer and memory disambiguation. */ mrs x0, midr_el1 mov_imm x1, DENVER_MIDR_PN4 cmp x0, x1 mrs x0, actlr_el3 mov x1, #(DENVER_CPU_DIS_MD_EL3 | DENVER_CPU_DIS_SSB_EL3) mov x2, #(DENVER_PN4_CPU_DIS_MD_EL3 | DENVER_PN4_CPU_DIS_SSB_EL3) csel x3, x1, x2, ne orr x0, x0, x3 msr actlr_el3, x0 isb dsb sy #endif /* ---------------------------------------------------- * Reset ACTLR.PMSTATE to C1 state * ---------------------------------------------------- */ mrs x0, actlr_el1 bic x0, x0, #DENVER_CPU_PMSTATE_MASK orr x0, x0, #DENVER_CPU_PMSTATE_C1 msr actlr_el1, x0 /* ---------------------------------------------------- * Enable dynamic code optimizer (DCO) * ---------------------------------------------------- */ bl denver_enable_dco ret x19 endfunc denver_reset_func /* ---------------------------------------------------- * The CPU Ops core power down function for Denver. * ---------------------------------------------------- */ func denver_core_pwr_dwn mov x19, x30 /* --------------------------------------------- * Force the debug interfaces to be quiescent * --------------------------------------------- */ bl denver_disable_ext_debug ret x19 endfunc denver_core_pwr_dwn /* ------------------------------------------------------- * The CPU Ops cluster power down function for Denver. * ------------------------------------------------------- */ func denver_cluster_pwr_dwn ret endfunc denver_cluster_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Denver. Must follow AAPCS. */ func denver_errata_report stp x8, x30, [sp, #-16]! bl cpu_get_rev_var mov x8, x0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata WORKAROUND_CVE_2017_5715, denver, cve_2017_5715 report_errata WORKAROUND_CVE_2018_3639, denver, cve_2018_3639 ldp x8, x30, [sp], #16 ret endfunc denver_errata_report #endif /* --------------------------------------------- * This function provides Denver specific * register information for crash reporting. * It needs to return with x6 pointing to * a list of register names in ascii and * x8 - x15 having values of registers to be * reported. * --------------------------------------------- */ .section .rodata.denver_regs, "aS" denver_regs: /* The ascii list of register names to be reported */ .asciz "actlr_el1", "" func denver_cpu_reg_dump adr x6, denver_regs mrs x8, ACTLR_EL1 ret endfunc denver_cpu_reg_dump declare_cpu_ops_wa denver, DENVER_MIDR_PN0, \ denver_reset_func, \ check_errata_cve_2017_5715, \ CPU_NO_EXTRA2_FUNC, \ denver_core_pwr_dwn, \ denver_cluster_pwr_dwn declare_cpu_ops_wa denver, DENVER_MIDR_PN1, \ denver_reset_func, \ check_errata_cve_2017_5715, \ CPU_NO_EXTRA2_FUNC, \ denver_core_pwr_dwn, \ denver_cluster_pwr_dwn declare_cpu_ops_wa denver, DENVER_MIDR_PN2, \ denver_reset_func, \ check_errata_cve_2017_5715, \ CPU_NO_EXTRA2_FUNC, \ denver_core_pwr_dwn, \ denver_cluster_pwr_dwn declare_cpu_ops_wa denver, DENVER_MIDR_PN3, \ denver_reset_func, \ check_errata_cve_2017_5715, \ CPU_NO_EXTRA2_FUNC, \ denver_core_pwr_dwn, \ denver_cluster_pwr_dwn declare_cpu_ops_wa denver, DENVER_MIDR_PN4, \ denver_reset_func, \ check_errata_cve_2017_5715, \ CPU_NO_EXTRA2_FUNC, \ denver_core_pwr_dwn, \ denver_cluster_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/dsu_helpers.S000066400000000000000000000064561355360272700225350ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /* ----------------------------------------------------------------------- * DSU erratum 798953 check function * Checks the DSU variant, revision and configuration to determine if * the erratum applies. Erratum applies on all configurations of the * DSU and if revision-variant is r0p0. * * The erratum was fixed in r0p1. * * This function is called from both assembly and C environment. So it * follows AAPCS. * * Clobbers: x0-x3 * ----------------------------------------------------------------------- */ .globl check_errata_dsu_798953 .globl errata_dsu_798953_wa func check_errata_dsu_798953 mov x2, #ERRATA_APPLIES mov x3, #ERRATA_NOT_APPLIES /* Check if DSU is equal to r0p0 */ mrs x1, CLUSTERIDR_EL1 /* DSU variant and revision bitfields in CLUSTERIDR are adjacent */ ubfx x0, x1, #CLUSTERIDR_REV_SHIFT,\ #(CLUSTERIDR_REV_BITS + CLUSTERIDR_VAR_BITS) mov x1, #(0x0 << CLUSTERIDR_REV_SHIFT) cmp x0, x1 csel x0, x2, x3, EQ ret endfunc check_errata_dsu_798953 /* -------------------------------------------------- * Errata Workaround for DSU erratum #798953. * * Can clobber only: x0-x17 * -------------------------------------------------- */ func errata_dsu_798953_wa mov x17, x30 bl check_errata_dsu_798953 cbz x0, 1f /* If erratum applies, disable high-level clock gating */ mrs x0, CLUSTERACTLR_EL1 orr x0, x0, #CLUSTERACTLR_EL1_DISABLE_CLOCK_GATING msr CLUSTERACTLR_EL1, x0 isb 1: ret x17 endfunc errata_dsu_798953_wa /* ----------------------------------------------------------------------- * DSU erratum 936184 check function * Checks the DSU variant, revision and configuration to determine if * the erratum applies. Erratum applies if ACP interface is present * in the DSU and revision-variant < r2p0. * * The erratum was fixed in r2p0. * * This function is called from both assembly and C environment. So it * follows AAPCS. * * Clobbers: x0-x3 * ----------------------------------------------------------------------- */ .globl check_errata_dsu_936184 .globl errata_dsu_936184_wa func check_errata_dsu_936184 mov x2, #ERRATA_NOT_APPLIES mov x3, #ERRATA_APPLIES /* Erratum applies only if DSU has the ACP interface */ mov x0, x2 mrs x1, CLUSTERCFR_EL1 ubfx x1, x1, #CLUSTERCFR_ACP_SHIFT, #1 cbz x1, 1f /* If ACP is present, check if DSU is older than r2p0 */ mrs x1, CLUSTERIDR_EL1 /* DSU variant and revision bitfields in CLUSTERIDR are adjacent */ ubfx x0, x1, #CLUSTERIDR_REV_SHIFT,\ #(CLUSTERIDR_REV_BITS + CLUSTERIDR_VAR_BITS) mov x1, #(0x2 << CLUSTERIDR_VAR_SHIFT) cmp x0, x1 csel x0, x2, x3, hs 1: ret endfunc check_errata_dsu_936184 /* -------------------------------------------------- * Errata Workaround for DSU erratum #936184. * * Can clobber only: x0-x17 * -------------------------------------------------- */ func errata_dsu_936184_wa mov x17, x30 bl check_errata_dsu_936184 cbz x0, 1f /* If erratum applies, we set a mask to a DSU control register */ mrs x0, CLUSTERACTLR_EL1 ldr x1, =DSU_ERRATA_936184_MASK orr x0, x0, x1 msr CLUSTERACTLR_EL1, x0 isb 1: ret x17 endfunc errata_dsu_936184_wa trusted-firmware-a-2.2/lib/cpus/aarch64/neoverse_e1.S000066400000000000000000000035771355360272700224340ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* Hardware handled coherency */ #if HW_ASSISTED_COHERENCY == 0 #error "Neoverse E1 must be compiled with HW_ASSISTED_COHERENCY enabled" #endif /* 64-bit only core */ #if CTX_INCLUDE_AARCH32_REGS == 1 #error "Neoverse-E1 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0" #endif /* ------------------------------------------------- * The CPU Ops reset function for Neoverse-E1. * Shall clobber: x0-x19 * ------------------------------------------------- */ func neoverse_e1_reset_func mov x19, x30 #if ERRATA_DSU_936184 bl errata_dsu_936184_wa #endif ret x19 endfunc neoverse_e1_reset_func func neoverse_e1_cpu_pwr_dwn mrs x0, NEOVERSE_E1_CPUPWRCTLR_EL1 orr x0, x0, #NEOVERSE_E1_CPUPWRCTLR_EL1_CORE_PWRDN_BIT msr NEOVERSE_E1_CPUPWRCTLR_EL1, x0 isb ret endfunc neoverse_e1_cpu_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Neoverse N1. Must follow AAPCS. */ func neoverse_e1_errata_report stp x8, x30, [sp, #-16]! bl cpu_get_rev_var mov x8, x0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata ERRATA_DSU_936184, neoverse_e1, dsu_936184 ldp x8, x30, [sp], #16 ret endfunc neoverse_e1_errata_report #endif .section .rodata.neoverse_e1_regs, "aS" neoverse_e1_regs: /* The ascii list of register names to be reported */ .asciz "cpuectlr_el1", "" func neoverse_e1_cpu_reg_dump adr x6, neoverse_e1_regs mrs x8, NEOVERSE_E1_ECTLR_EL1 ret endfunc neoverse_e1_cpu_reg_dump declare_cpu_ops neoverse_e1, NEOVERSE_E1_MIDR, \ neoverse_e1_reset_func, \ neoverse_e1_cpu_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/neoverse_n1.S000066400000000000000000000346241355360272700224420ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* Hardware handled coherency */ #if HW_ASSISTED_COHERENCY == 0 #error "Neoverse N1 must be compiled with HW_ASSISTED_COHERENCY enabled" #endif /* 64-bit only core */ #if CTX_INCLUDE_AARCH32_REGS == 1 #error "Neoverse-N1 supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0" #endif #if ERRATA_N1_IC_TRAP .global neoverse_n1_errata_ic_trap_handler #endif /* -------------------------------------------------- * Errata Workaround for Neoverse N1 Erratum 1043202. * This applies to revision r0p0 and r1p0 of Neoverse N1. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_n1_1043202_wa /* Compare x0 against revision r1p0 */ mov x17, x30 bl check_errata_1043202 cbz x0, 1f /* Apply instruction patching sequence */ ldr x0, =0x0 msr CPUPSELR_EL3, x0 ldr x0, =0xF3BF8F2F msr CPUPOR_EL3, x0 ldr x0, =0xFFFFFFFF msr CPUPMR_EL3, x0 ldr x0, =0x800200071 msr CPUPCR_EL3, x0 isb 1: ret x17 endfunc errata_n1_1043202_wa func check_errata_1043202 /* Applies to r0p0 and r1p0 */ mov x1, #0x10 b cpu_rev_var_ls endfunc check_errata_1043202 /* -------------------------------------------------- * Disable speculative loads if Neoverse N1 supports * SSBS. * * Shall clobber: x0. * -------------------------------------------------- */ func neoverse_n1_disable_speculative_loads /* Check if the PE implements SSBS */ mrs x0, id_aa64pfr1_el1 tst x0, #(ID_AA64PFR1_EL1_SSBS_MASK << ID_AA64PFR1_EL1_SSBS_SHIFT) b.eq 1f /* Disable speculative loads */ msr SSBS, xzr 1: ret endfunc neoverse_n1_disable_speculative_loads /* -------------------------------------------------- * Errata Workaround for Neoverse N1 Errata #1073348 * This applies to revision r0p0 and r1p0 of Neoverse N1. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_n1_1073348_wa /* Compare x0 against revision r1p0 */ mov x17, x30 bl check_errata_1073348 cbz x0, 1f mrs x1, NEOVERSE_N1_CPUACTLR_EL1 orr x1, x1, NEOVERSE_N1_CPUACTLR_EL1_BIT_6 msr NEOVERSE_N1_CPUACTLR_EL1, x1 1: ret x17 endfunc errata_n1_1073348_wa func check_errata_1073348 /* Applies to r0p0 and r1p0 */ mov x1, #0x10 b cpu_rev_var_ls endfunc check_errata_1073348 /* -------------------------------------------------- * Errata Workaround for Neoverse N1 Errata #1130799 * This applies to revision <=r2p0 of Neoverse N1. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_n1_1130799_wa /* Compare x0 against revision r2p0 */ mov x17, x30 bl check_errata_1130799 cbz x0, 1f mrs x1, NEOVERSE_N1_CPUACTLR2_EL1 orr x1, x1, NEOVERSE_N1_CPUACTLR2_EL1_BIT_59 msr NEOVERSE_N1_CPUACTLR2_EL1, x1 1: ret x17 endfunc errata_n1_1130799_wa func check_errata_1130799 /* Applies to <=r2p0 */ mov x1, #0x20 b cpu_rev_var_ls endfunc check_errata_1130799 /* -------------------------------------------------- * Errata Workaround for Neoverse N1 Errata #1165347 * This applies to revision <=r2p0 of Neoverse N1. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_n1_1165347_wa /* Compare x0 against revision r2p0 */ mov x17, x30 bl check_errata_1165347 cbz x0, 1f mrs x1, NEOVERSE_N1_CPUACTLR2_EL1 orr x1, x1, NEOVERSE_N1_CPUACTLR2_EL1_BIT_0 orr x1, x1, NEOVERSE_N1_CPUACTLR2_EL1_BIT_15 msr NEOVERSE_N1_CPUACTLR2_EL1, x1 1: ret x17 endfunc errata_n1_1165347_wa func check_errata_1165347 /* Applies to <=r2p0 */ mov x1, #0x20 b cpu_rev_var_ls endfunc check_errata_1165347 /* -------------------------------------------------- * Errata Workaround for Neoverse N1 Errata #1207823 * This applies to revision <=r2p0 of Neoverse N1. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_n1_1207823_wa /* Compare x0 against revision r2p0 */ mov x17, x30 bl check_errata_1207823 cbz x0, 1f mrs x1, NEOVERSE_N1_CPUACTLR2_EL1 orr x1, x1, NEOVERSE_N1_CPUACTLR2_EL1_BIT_11 msr NEOVERSE_N1_CPUACTLR2_EL1, x1 1: ret x17 endfunc errata_n1_1207823_wa func check_errata_1207823 /* Applies to <=r2p0 */ mov x1, #0x20 b cpu_rev_var_ls endfunc check_errata_1207823 /* -------------------------------------------------- * Errata Workaround for Neoverse N1 Errata #1220197 * This applies to revision <=r2p0 of Neoverse N1. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_n1_1220197_wa /* Compare x0 against revision r2p0 */ mov x17, x30 bl check_errata_1220197 cbz x0, 1f mrs x1, NEOVERSE_N1_CPUECTLR_EL1 orr x1, x1, NEOVERSE_N1_WS_THR_L2_MASK msr NEOVERSE_N1_CPUECTLR_EL1, x1 1: ret x17 endfunc errata_n1_1220197_wa func check_errata_1220197 /* Applies to <=r2p0 */ mov x1, #0x20 b cpu_rev_var_ls endfunc check_errata_1220197 /* -------------------------------------------------- * Errata Workaround for Neoverse N1 Errata #1257314 * This applies to revision <=r3p0 of Neoverse N1. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_n1_1257314_wa /* Compare x0 against revision r3p0 */ mov x17, x30 bl check_errata_1257314 cbz x0, 1f mrs x1, NEOVERSE_N1_CPUACTLR3_EL1 orr x1, x1, NEOVERSE_N1_CPUACTLR3_EL1_BIT_10 msr NEOVERSE_N1_CPUACTLR3_EL1, x1 1: ret x17 endfunc errata_n1_1257314_wa func check_errata_1257314 /* Applies to <=r3p0 */ mov x1, #0x30 b cpu_rev_var_ls endfunc check_errata_1257314 /* -------------------------------------------------- * Errata Workaround for Neoverse N1 Errata #1262606 * This applies to revision <=r3p0 of Neoverse N1. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_n1_1262606_wa /* Compare x0 against revision r3p0 */ mov x17, x30 bl check_errata_1262606 cbz x0, 1f mrs x1, NEOVERSE_N1_CPUACTLR_EL1 orr x1, x1, NEOVERSE_N1_CPUACTLR_EL1_BIT_13 msr NEOVERSE_N1_CPUACTLR_EL1, x1 1: ret x17 endfunc errata_n1_1262606_wa func check_errata_1262606 /* Applies to <=r3p0 */ mov x1, #0x30 b cpu_rev_var_ls endfunc check_errata_1262606 /* -------------------------------------------------- * Errata Workaround for Neoverse N1 Errata #1262888 * This applies to revision <=r3p0 of Neoverse N1. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_n1_1262888_wa /* Compare x0 against revision r3p0 */ mov x17, x30 bl check_errata_1262888 cbz x0, 1f mrs x1, NEOVERSE_N1_CPUECTLR_EL1 orr x1, x1, NEOVERSE_N1_CPUECTLR_EL1_MM_TLBPF_DIS_BIT msr NEOVERSE_N1_CPUECTLR_EL1, x1 1: ret x17 endfunc errata_n1_1262888_wa func check_errata_1262888 /* Applies to <=r3p0 */ mov x1, #0x30 b cpu_rev_var_ls endfunc check_errata_1262888 /* -------------------------------------------------- * Errata Workaround for Neoverse N1 Errata #1275112 * This applies to revision <=r3p0 of Neoverse N1. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_n1_1275112_wa /* Compare x0 against revision r3p0 */ mov x17, x30 bl check_errata_1275112 cbz x0, 1f mrs x1, NEOVERSE_N1_CPUACTLR_EL1 orr x1, x1, NEOVERSE_N1_CPUACTLR_EL1_BIT_13 msr NEOVERSE_N1_CPUACTLR_EL1, x1 1: ret x17 endfunc errata_n1_1275112_wa func check_errata_1275112 /* Applies to <=r3p0 */ mov x1, #0x30 b cpu_rev_var_ls endfunc check_errata_1275112 /* -------------------------------------------------- * Errata Workaround for Neoverse N1 Erratum 1315703. * This applies to revision <= r3p0 of Neoverse N1. * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_n1_1315703_wa /* Compare x0 against revision r3p1 */ mov x17, x30 bl check_errata_1315703 cbz x0, 1f mrs x0, NEOVERSE_N1_CPUACTLR2_EL1 orr x0, x0, #NEOVERSE_N1_CPUACTLR2_EL1_BIT_16 msr NEOVERSE_N1_CPUACTLR2_EL1, x0 1: ret x17 endfunc errata_n1_1315703_wa func check_errata_1315703 /* Applies to everything <= r3p0. */ mov x1, #0x30 b cpu_rev_var_ls endfunc check_errata_1315703 /* -------------------------------------------------- * Errata Workaround for Neoverse N1 Erratum 1542419. * This applies to revisions r3p0 - r4p0 of Neoverse N1 * Inputs: * x0: variant[4:7] and revision[0:3] of current cpu. * Shall clobber: x0-x17 * -------------------------------------------------- */ func errata_n1_1542419_wa /* Compare x0 against revision r3p0 and r4p0 */ mov x17, x30 bl check_errata_1542419 cbz x0, 1f /* Apply instruction patching sequence */ ldr x0, =0x0 msr CPUPSELR_EL3, x0 ldr x0, =0xEE670D35 msr CPUPOR_EL3, x0 ldr x0, =0xFFFF0FFF msr CPUPMR_EL3, x0 ldr x0, =0x08000020007D msr CPUPCR_EL3, x0 isb 1: ret x17 endfunc errata_n1_1542419_wa func check_errata_1542419 /* Applies to everything r3p0 - r4p0. */ mov x1, #0x30 mov x2, #0x40 b cpu_rev_var_range endfunc check_errata_1542419 func neoverse_n1_reset_func mov x19, x30 bl neoverse_n1_disable_speculative_loads /* Forces all cacheable atomic instructions to be near */ mrs x0, NEOVERSE_N1_CPUACTLR2_EL1 orr x0, x0, #NEOVERSE_N1_CPUACTLR2_EL1_BIT_2 msr NEOVERSE_N1_CPUACTLR2_EL1, x0 isb bl cpu_get_rev_var mov x18, x0 #if ERRATA_N1_1043202 mov x0, x18 bl errata_n1_1043202_wa #endif #if ERRATA_N1_1073348 mov x0, x18 bl errata_n1_1073348_wa #endif #if ERRATA_N1_1130799 mov x0, x18 bl errata_n1_1130799_wa #endif #if ERRATA_N1_1165347 mov x0, x18 bl errata_n1_1165347_wa #endif #if ERRATA_N1_1207823 mov x0, x18 bl errata_n1_1207823_wa #endif #if ERRATA_N1_1220197 mov x0, x18 bl errata_n1_1220197_wa #endif #if ERRATA_N1_1257314 mov x0, x18 bl errata_n1_1257314_wa #endif #if ERRATA_N1_1262606 mov x0, x18 bl errata_n1_1262606_wa #endif #if ERRATA_N1_1262888 mov x0, x18 bl errata_n1_1262888_wa #endif #if ERRATA_N1_1275112 mov x0, x18 bl errata_n1_1275112_wa #endif #if ERRATA_N1_1315703 mov x0, x18 bl errata_n1_1315703_wa #endif #if ERRATA_N1_1542419 mov x0, x18 bl errata_n1_1542419_wa #endif #if ENABLE_AMU /* Make sure accesses from EL0/EL1 and EL2 are not trapped to EL3 */ mrs x0, actlr_el3 orr x0, x0, #NEOVERSE_N1_ACTLR_AMEN_BIT msr actlr_el3, x0 /* Make sure accesses from EL0/EL1 are not trapped to EL2 */ mrs x0, actlr_el2 orr x0, x0, #NEOVERSE_N1_ACTLR_AMEN_BIT msr actlr_el2, x0 /* Enable group0 counters */ mov x0, #NEOVERSE_N1_AMU_GROUP0_MASK msr CPUAMCNTENSET_EL0, x0 #endif #if ERRATA_DSU_936184 bl errata_dsu_936184_wa #endif isb ret x19 endfunc neoverse_n1_reset_func /* --------------------------------------------- * HW will do the cache maintenance while powering down * --------------------------------------------- */ func neoverse_n1_core_pwr_dwn /* --------------------------------------------- * Enable CPU power down bit in power control register * --------------------------------------------- */ mrs x0, NEOVERSE_N1_CPUPWRCTLR_EL1 orr x0, x0, #NEOVERSE_N1_CORE_PWRDN_EN_MASK msr NEOVERSE_N1_CPUPWRCTLR_EL1, x0 isb ret endfunc neoverse_n1_core_pwr_dwn #if REPORT_ERRATA /* * Errata printing function for Neoverse N1. Must follow AAPCS. */ func neoverse_n1_errata_report stp x8, x30, [sp, #-16]! bl cpu_get_rev_var mov x8, x0 /* * Report all errata. The revision-variant information is passed to * checking functions of each errata. */ report_errata ERRATA_N1_1043202, neoverse_n1, 1043202 report_errata ERRATA_N1_1073348, neoverse_n1, 1073348 report_errata ERRATA_N1_1130799, neoverse_n1, 1130799 report_errata ERRATA_N1_1165347, neoverse_n1, 1165347 report_errata ERRATA_N1_1207823, neoverse_n1, 1207823 report_errata ERRATA_N1_1220197, neoverse_n1, 1220197 report_errata ERRATA_N1_1257314, neoverse_n1, 1257314 report_errata ERRATA_N1_1262606, neoverse_n1, 1262606 report_errata ERRATA_N1_1262888, neoverse_n1, 1262888 report_errata ERRATA_N1_1275112, neoverse_n1, 1275112 report_errata ERRATA_N1_1315703, neoverse_n1, 1315703 report_errata ERRATA_N1_1542419, neoverse_n1, 1542419 report_errata ERRATA_DSU_936184, neoverse_n1, dsu_936184 ldp x8, x30, [sp], #16 ret endfunc neoverse_n1_errata_report #endif /* * Handle trap of EL0 IC IVAU instructions to EL3 by executing a TLB * inner-shareable invalidation to an arbitrary address followed by a DSB. * * x1: Exception Syndrome */ func neoverse_n1_errata_ic_trap_handler cmp x1, #NEOVERSE_N1_EC_IC_TRAP b.ne 1f tlbi vae3is, xzr dsb sy # Skip the IC instruction itself mrs x3, elr_el3 add x3, x3, #4 msr elr_el3, x3 ldp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] ldp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4] ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] #if IMAGE_BL31 && RAS_EXTENSION /* * Issue Error Synchronization Barrier to synchronize SErrors before * exiting EL3. We're running with EAs unmasked, so any synchronized * errors would be taken immediately; therefore no need to inspect * DISR_EL1 register. */ esb #endif eret 1: ret endfunc neoverse_n1_errata_ic_trap_handler /* --------------------------------------------- * This function provides neoverse_n1 specific * register information for crash reporting. * It needs to return with x6 pointing to * a list of register names in ascii and * x8 - x15 having values of registers to be * reported. * --------------------------------------------- */ .section .rodata.neoverse_n1_regs, "aS" neoverse_n1_regs: /* The ascii list of register names to be reported */ .asciz "cpuectlr_el1", "" func neoverse_n1_cpu_reg_dump adr x6, neoverse_n1_regs mrs x8, NEOVERSE_N1_CPUECTLR_EL1 ret endfunc neoverse_n1_cpu_reg_dump declare_cpu_ops_eh neoverse_n1, NEOVERSE_N1_MIDR, \ neoverse_n1_reset_func, \ neoverse_n1_errata_ic_trap_handler, \ neoverse_n1_core_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/neoverse_n1_pubsub.c000066400000000000000000000013221355360272700240270ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include static void *neoverse_n1_context_save(const void *arg) { if (midr_match(NEOVERSE_N1_MIDR) != 0) cpuamu_context_save(NEOVERSE_N1_AMU_NR_COUNTERS); return (void *)0; } static void *neoverse_n1_context_restore(const void *arg) { if (midr_match(NEOVERSE_N1_MIDR) != 0) cpuamu_context_restore(NEOVERSE_N1_AMU_NR_COUNTERS); return (void *)0; } SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, neoverse_n1_context_save); SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, neoverse_n1_context_restore); trusted-firmware-a-2.2/lib/cpus/aarch64/neoverse_zeus.S000066400000000000000000000041431355360272700231030ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* Hardware handled coherency */ #if HW_ASSISTED_COHERENCY == 0 #error "Neoverse Zeus must be compiled with HW_ASSISTED_COHERENCY enabled" #endif /* 64-bit only core */ #if CTX_INCLUDE_AARCH32_REGS == 1 #error "Neoverse-Zeus supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0" #endif /* --------------------------------------------- * HW will do the cache maintenance while powering down * --------------------------------------------- */ func neoverse_zeus_core_pwr_dwn /* --------------------------------------------- * Enable CPU power down bit in power control register * --------------------------------------------- */ mrs x0, NEOVERSE_ZEUS_CPUPWRCTLR_EL1 orr x0, x0, #NEOVERSE_ZEUS_CPUPWRCTLR_EL1_CORE_PWRDN_BIT msr NEOVERSE_ZEUS_CPUPWRCTLR_EL1, x0 isb ret endfunc neoverse_zeus_core_pwr_dwn /* * Errata printing function for Neoverse Zeus. Must follow AAPCS. */ #if REPORT_ERRATA func neoverse_zeus_errata_report ret endfunc neoverse_zeus_errata_report #endif func neoverse_zeus_reset_func mov x19, x30 /* Disable speculative loads */ msr SSBS, xzr isb ret x19 endfunc neoverse_zeus_reset_func /* --------------------------------------------- * This function provides Neoverse-Zeus specific * register information for crash reporting. * It needs to return with x6 pointing to * a list of register names in ascii and * x8 - x15 having values of registers to be * reported. * --------------------------------------------- */ .section .rodata.neoverse_zeus_regs, "aS" neoverse_zeus_regs: /* The ascii list of register names to be reported */ .asciz "cpuectlr_el1", "" func neoverse_zeus_cpu_reg_dump adr x6, neoverse_zeus_regs mrs x8, NEOVERSE_ZEUS_CPUECTLR_EL1 ret endfunc neoverse_zeus_cpu_reg_dump declare_cpu_ops neoverse_zeus, NEOVERSE_ZEUS_MIDR, \ neoverse_zeus_reset_func, \ neoverse_zeus_core_pwr_dwn trusted-firmware-a-2.2/lib/cpus/aarch64/wa_cve_2017_5715_bpiall.S000066400000000000000000000261661355360272700241410ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl wa_cve_2017_5715_bpiall_vbar #define EMIT_BPIALL 0xee070fd5 #define EMIT_SMC 0xe1600070 #define ESR_EL3_A64_SMC0 0x5e000000 .macro apply_cve_2017_5715_wa _from_vector /* * Save register state to enable a call to AArch32 S-EL1 and return * Identify the original calling vector in w2 (==_from_vector) * Use w3-w6 for additional register state preservation while in S-EL1 */ /* Save GP regs */ stp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] stp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] stp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4] stp x6, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X6] stp x8, x9, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X8] stp x10, x11, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X10] stp x12, x13, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X12] stp x14, x15, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X14] stp x16, x17, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X16] stp x18, x19, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X18] stp x20, x21, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X20] stp x22, x23, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X22] stp x24, x25, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X24] stp x26, x27, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X26] stp x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28] /* Identify the original exception vector */ mov w2, \_from_vector /* Preserve 32-bit system registers in GP registers through the workaround */ mrs x3, esr_el3 mrs x4, spsr_el3 mrs x5, scr_el3 mrs x6, sctlr_el1 /* * Preserve LR and ELR_EL3 registers in the GP regs context. * Temporarily use the CTX_GPREG_SP_EL0 slot to preserve ELR_EL3 * through the workaround. This is OK because at this point the * current state for this context's SP_EL0 is in the live system * register, which is unmodified by the workaround. */ mrs x7, elr_el3 stp x30, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] /* * Load system registers for entry to S-EL1. */ /* Mask all interrupts and set AArch32 Supervisor mode */ movz w8, SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE, SPSR_AIF_MASK) /* Switch EL3 exception vectors while the workaround is executing. */ adr x9, wa_cve_2017_5715_bpiall_ret_vbar /* Setup SCTLR_EL1 with MMU off and I$ on */ ldr x10, stub_sel1_sctlr /* Land at the S-EL1 workaround stub */ adr x11, aarch32_stub /* * Setting SCR_EL3 to all zeroes means that the NS, RW * and SMD bits are configured as expected. */ msr scr_el3, xzr msr spsr_el3, x8 msr vbar_el3, x9 msr sctlr_el1, x10 msr elr_el3, x11 eret .endm /* --------------------------------------------------------------------- * This vector table is used at runtime to enter the workaround at * AArch32 S-EL1 for Sync/IRQ/FIQ/SError exceptions. If the workaround * is not enabled, the existing runtime exception vector table is used. * --------------------------------------------------------------------- */ vector_base wa_cve_2017_5715_bpiall_vbar /* --------------------------------------------------------------------- * Current EL with SP_EL0 : 0x0 - 0x200 * --------------------------------------------------------------------- */ vector_entry bpiall_sync_exception_sp_el0 b sync_exception_sp_el0 nop /* to force 8 byte alignment for the following stub */ /* * Since each vector table entry is 128 bytes, we can store the * stub context in the unused space to minimize memory footprint. */ stub_sel1_sctlr: .quad SCTLR_AARCH32_EL1_RES1 | SCTLR_I_BIT aarch32_stub: .word EMIT_BPIALL .word EMIT_SMC end_vector_entry bpiall_sync_exception_sp_el0 vector_entry bpiall_irq_sp_el0 b irq_sp_el0 end_vector_entry bpiall_irq_sp_el0 vector_entry bpiall_fiq_sp_el0 b fiq_sp_el0 end_vector_entry bpiall_fiq_sp_el0 vector_entry bpiall_serror_sp_el0 b serror_sp_el0 end_vector_entry bpiall_serror_sp_el0 /* --------------------------------------------------------------------- * Current EL with SP_ELx: 0x200 - 0x400 * --------------------------------------------------------------------- */ vector_entry bpiall_sync_exception_sp_elx b sync_exception_sp_elx end_vector_entry bpiall_sync_exception_sp_elx vector_entry bpiall_irq_sp_elx b irq_sp_elx end_vector_entry bpiall_irq_sp_elx vector_entry bpiall_fiq_sp_elx b fiq_sp_elx end_vector_entry bpiall_fiq_sp_elx vector_entry bpiall_serror_sp_elx b serror_sp_elx end_vector_entry bpiall_serror_sp_elx /* --------------------------------------------------------------------- * Lower EL using AArch64 : 0x400 - 0x600 * --------------------------------------------------------------------- */ vector_entry bpiall_sync_exception_aarch64 apply_cve_2017_5715_wa 1 end_vector_entry bpiall_sync_exception_aarch64 vector_entry bpiall_irq_aarch64 apply_cve_2017_5715_wa 2 end_vector_entry bpiall_irq_aarch64 vector_entry bpiall_fiq_aarch64 apply_cve_2017_5715_wa 4 end_vector_entry bpiall_fiq_aarch64 vector_entry bpiall_serror_aarch64 apply_cve_2017_5715_wa 8 end_vector_entry bpiall_serror_aarch64 /* --------------------------------------------------------------------- * Lower EL using AArch32 : 0x600 - 0x800 * --------------------------------------------------------------------- */ vector_entry bpiall_sync_exception_aarch32 apply_cve_2017_5715_wa 1 end_vector_entry bpiall_sync_exception_aarch32 vector_entry bpiall_irq_aarch32 apply_cve_2017_5715_wa 2 end_vector_entry bpiall_irq_aarch32 vector_entry bpiall_fiq_aarch32 apply_cve_2017_5715_wa 4 end_vector_entry bpiall_fiq_aarch32 vector_entry bpiall_serror_aarch32 apply_cve_2017_5715_wa 8 end_vector_entry bpiall_serror_aarch32 /* --------------------------------------------------------------------- * This vector table is used while the workaround is executing. It * installs a simple SMC handler to allow the Sync/IRQ/FIQ/SError * workaround stubs to enter EL3 from S-EL1. It restores the previous * EL3 state before proceeding with the normal runtime exception vector. * --------------------------------------------------------------------- */ vector_base wa_cve_2017_5715_bpiall_ret_vbar /* --------------------------------------------------------------------- * Current EL with SP_EL0 : 0x0 - 0x200 (UNUSED) * --------------------------------------------------------------------- */ vector_entry bpiall_ret_sync_exception_sp_el0 b report_unhandled_exception end_vector_entry bpiall_ret_sync_exception_sp_el0 vector_entry bpiall_ret_irq_sp_el0 b report_unhandled_interrupt end_vector_entry bpiall_ret_irq_sp_el0 vector_entry bpiall_ret_fiq_sp_el0 b report_unhandled_interrupt end_vector_entry bpiall_ret_fiq_sp_el0 vector_entry bpiall_ret_serror_sp_el0 b report_unhandled_exception end_vector_entry bpiall_ret_serror_sp_el0 /* --------------------------------------------------------------------- * Current EL with SP_ELx: 0x200 - 0x400 (UNUSED) * --------------------------------------------------------------------- */ vector_entry bpiall_ret_sync_exception_sp_elx b report_unhandled_exception end_vector_entry bpiall_ret_sync_exception_sp_elx vector_entry bpiall_ret_irq_sp_elx b report_unhandled_interrupt end_vector_entry bpiall_ret_irq_sp_elx vector_entry bpiall_ret_fiq_sp_elx b report_unhandled_interrupt end_vector_entry bpiall_ret_fiq_sp_elx vector_entry bpiall_ret_serror_sp_elx b report_unhandled_exception end_vector_entry bpiall_ret_serror_sp_elx /* --------------------------------------------------------------------- * Lower EL using AArch64 : 0x400 - 0x600 (UNUSED) * --------------------------------------------------------------------- */ vector_entry bpiall_ret_sync_exception_aarch64 b report_unhandled_exception end_vector_entry bpiall_ret_sync_exception_aarch64 vector_entry bpiall_ret_irq_aarch64 b report_unhandled_interrupt end_vector_entry bpiall_ret_irq_aarch64 vector_entry bpiall_ret_fiq_aarch64 b report_unhandled_interrupt end_vector_entry bpiall_ret_fiq_aarch64 vector_entry bpiall_ret_serror_aarch64 b report_unhandled_exception end_vector_entry bpiall_ret_serror_aarch64 /* --------------------------------------------------------------------- * Lower EL using AArch32 : 0x600 - 0x800 * --------------------------------------------------------------------- */ vector_entry bpiall_ret_sync_exception_aarch32 /* * w2 indicates which SEL1 stub was run and thus which original vector was used * w3-w6 contain saved system register state (esr_el3 in w3) * Restore LR and ELR_EL3 register state from the GP regs context */ ldp x30, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] /* Apply the restored system register state */ msr esr_el3, x3 msr spsr_el3, x4 msr scr_el3, x5 msr sctlr_el1, x6 msr elr_el3, x7 /* * Workaround is complete, so swap VBAR_EL3 to point * to workaround entry table in preparation for subsequent * Sync/IRQ/FIQ/SError exceptions. */ adr x0, wa_cve_2017_5715_bpiall_vbar msr vbar_el3, x0 /* * Restore all GP regs except x2 and x3 (esr). The value in x2 * indicates the type of the original exception. */ ldp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] ldp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4] ldp x6, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X6] ldp x8, x9, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X8] ldp x10, x11, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X10] ldp x12, x13, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X12] ldp x14, x15, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X14] ldp x16, x17, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X16] ldp x18, x19, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X18] ldp x20, x21, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X20] ldp x22, x23, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X22] ldp x24, x25, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X24] ldp x26, x27, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X26] ldp x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28] /* Fast path Sync exceptions. Static predictor will fall through. */ tbz w2, #0, workaround_not_sync /* * Check if SMC is coming from A64 state on #0 * with W0 = SMCCC_ARCH_WORKAROUND_1 * * This sequence evaluates as: * (W0==SMCCC_ARCH_WORKAROUND_1) ? (ESR_EL3==SMC#0) : (NE) * allowing use of a single branch operation */ orr w2, wzr, #SMCCC_ARCH_WORKAROUND_1 cmp w0, w2 mov_imm w2, ESR_EL3_A64_SMC0 ccmp w3, w2, #0, eq /* Static predictor will predict a fall through */ bne 1f eret 1: ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] b sync_exception_aarch64 end_vector_entry bpiall_ret_sync_exception_aarch32 vector_entry bpiall_ret_irq_aarch32 b report_unhandled_interrupt /* * Post-workaround fan-out for non-sync exceptions */ workaround_not_sync: tbnz w2, #3, bpiall_ret_serror tbnz w2, #2, bpiall_ret_fiq /* IRQ */ ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] b irq_aarch64 bpiall_ret_fiq: ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] b fiq_aarch64 bpiall_ret_serror: ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] b serror_aarch64 end_vector_entry bpiall_ret_irq_aarch32 vector_entry bpiall_ret_fiq_aarch32 b report_unhandled_interrupt end_vector_entry bpiall_ret_fiq_aarch32 vector_entry bpiall_ret_serror_aarch32 b report_unhandled_exception end_vector_entry bpiall_ret_serror_aarch32 trusted-firmware-a-2.2/lib/cpus/aarch64/wa_cve_2017_5715_mmu.S000066400000000000000000000102311355360272700234560ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl wa_cve_2017_5715_mmu_vbar #define ESR_EL3_A64_SMC0 0x5e000000 #define ESR_EL3_A32_SMC0 0x4e000000 vector_base wa_cve_2017_5715_mmu_vbar .macro apply_cve_2017_5715_wa _is_sync_exception _esr_el3_val stp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] mrs x1, sctlr_el3 /* Disable MMU */ bic x1, x1, #SCTLR_M_BIT msr sctlr_el3, x1 isb /* Enable MMU */ orr x1, x1, #SCTLR_M_BIT msr sctlr_el3, x1 /* * Defer ISB to avoid synchronizing twice in case we hit * the workaround SMC call which will implicitly synchronize * because of the ERET instruction. */ /* * Ensure SMC is coming from A64/A32 state on #0 * with W0 = SMCCC_ARCH_WORKAROUND_1 * * This sequence evaluates as: * (W0==SMCCC_ARCH_WORKAROUND_1) ? (ESR_EL3==SMC#0) : (NE) * allowing use of a single branch operation */ .if \_is_sync_exception orr w1, wzr, #SMCCC_ARCH_WORKAROUND_1 cmp w0, w1 mrs x0, esr_el3 mov_imm w1, \_esr_el3_val ccmp w0, w1, #0, eq /* Static predictor will predict a fall through */ bne 1f eret 1: .endif /* * Synchronize now to enable the MMU. This is required * to ensure the load pair below reads the data stored earlier. */ isb ldp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] .endm /* --------------------------------------------------------------------- * Current EL with SP_EL0 : 0x0 - 0x200 * --------------------------------------------------------------------- */ vector_entry mmu_sync_exception_sp_el0 b sync_exception_sp_el0 end_vector_entry mmu_sync_exception_sp_el0 vector_entry mmu_irq_sp_el0 b irq_sp_el0 end_vector_entry mmu_irq_sp_el0 vector_entry mmu_fiq_sp_el0 b fiq_sp_el0 end_vector_entry mmu_fiq_sp_el0 vector_entry mmu_serror_sp_el0 b serror_sp_el0 end_vector_entry mmu_serror_sp_el0 /* --------------------------------------------------------------------- * Current EL with SP_ELx: 0x200 - 0x400 * --------------------------------------------------------------------- */ vector_entry mmu_sync_exception_sp_elx b sync_exception_sp_elx end_vector_entry mmu_sync_exception_sp_elx vector_entry mmu_irq_sp_elx b irq_sp_elx end_vector_entry mmu_irq_sp_elx vector_entry mmu_fiq_sp_elx b fiq_sp_elx end_vector_entry mmu_fiq_sp_elx vector_entry mmu_serror_sp_elx b serror_sp_elx end_vector_entry mmu_serror_sp_elx /* --------------------------------------------------------------------- * Lower EL using AArch64 : 0x400 - 0x600 * --------------------------------------------------------------------- */ vector_entry mmu_sync_exception_aarch64 apply_cve_2017_5715_wa _is_sync_exception=1 _esr_el3_val=ESR_EL3_A64_SMC0 b sync_exception_aarch64 end_vector_entry mmu_sync_exception_aarch64 vector_entry mmu_irq_aarch64 apply_cve_2017_5715_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A64_SMC0 b irq_aarch64 end_vector_entry mmu_irq_aarch64 vector_entry mmu_fiq_aarch64 apply_cve_2017_5715_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A64_SMC0 b fiq_aarch64 end_vector_entry mmu_fiq_aarch64 vector_entry mmu_serror_aarch64 apply_cve_2017_5715_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A64_SMC0 b serror_aarch64 end_vector_entry mmu_serror_aarch64 /* --------------------------------------------------------------------- * Lower EL using AArch32 : 0x600 - 0x800 * --------------------------------------------------------------------- */ vector_entry mmu_sync_exception_aarch32 apply_cve_2017_5715_wa _is_sync_exception=1 _esr_el3_val=ESR_EL3_A32_SMC0 b sync_exception_aarch32 end_vector_entry mmu_sync_exception_aarch32 vector_entry mmu_irq_aarch32 apply_cve_2017_5715_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A32_SMC0 b irq_aarch32 end_vector_entry mmu_irq_aarch32 vector_entry mmu_fiq_aarch32 apply_cve_2017_5715_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A32_SMC0 b fiq_aarch32 end_vector_entry mmu_fiq_aarch32 vector_entry mmu_serror_aarch32 apply_cve_2017_5715_wa _is_sync_exception=0 _esr_el3_val=ESR_EL3_A32_SMC0 b serror_aarch32 end_vector_entry mmu_serror_aarch32 trusted-firmware-a-2.2/lib/cpus/cpu-ops.mk000066400000000000000000000442361355360272700205610ustar00rootroot00000000000000# # Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Cortex A57 specific optimisation to skip L1 cache flush when # cluster is powered down. SKIP_A57_L1_FLUSH_PWR_DWN ?=0 # Flag to disable the cache non-temporal hint. # It is enabled by default. A53_DISABLE_NON_TEMPORAL_HINT ?=1 # Flag to disable the cache non-temporal hint. # It is enabled by default. A57_DISABLE_NON_TEMPORAL_HINT ?=1 WORKAROUND_CVE_2017_5715 ?=1 WORKAROUND_CVE_2018_3639 ?=1 DYNAMIC_WORKAROUND_CVE_2018_3639 ?=0 # Process SKIP_A57_L1_FLUSH_PWR_DWN flag $(eval $(call assert_boolean,SKIP_A57_L1_FLUSH_PWR_DWN)) $(eval $(call add_define,SKIP_A57_L1_FLUSH_PWR_DWN)) # Process A53_DISABLE_NON_TEMPORAL_HINT flag $(eval $(call assert_boolean,A53_DISABLE_NON_TEMPORAL_HINT)) $(eval $(call add_define,A53_DISABLE_NON_TEMPORAL_HINT)) # Process A57_DISABLE_NON_TEMPORAL_HINT flag $(eval $(call assert_boolean,A57_DISABLE_NON_TEMPORAL_HINT)) $(eval $(call add_define,A57_DISABLE_NON_TEMPORAL_HINT)) # Process WORKAROUND_CVE_2017_5715 flag $(eval $(call assert_boolean,WORKAROUND_CVE_2017_5715)) $(eval $(call add_define,WORKAROUND_CVE_2017_5715)) # Process WORKAROUND_CVE_2018_3639 flag $(eval $(call assert_boolean,WORKAROUND_CVE_2018_3639)) $(eval $(call add_define,WORKAROUND_CVE_2018_3639)) $(eval $(call assert_boolean,DYNAMIC_WORKAROUND_CVE_2018_3639)) $(eval $(call add_define,DYNAMIC_WORKAROUND_CVE_2018_3639)) ifneq (${DYNAMIC_WORKAROUND_CVE_2018_3639},0) ifeq (${WORKAROUND_CVE_2018_3639},0) $(error "Error: WORKAROUND_CVE_2018_3639 must be 1 if DYNAMIC_WORKAROUND_CVE_2018_3639 is 1") endif endif # CPU Errata Build flags. # These should be enabled by the platform if the erratum workaround needs to be # applied. # Flag to apply erratum 794073 workaround when disabling mmu. ERRATA_A9_794073 ?=0 # Flag to apply erratum 816470 workaround during power down. This erratum # applies only to revision >= r3p0 of the Cortex A15 cpu. ERRATA_A15_816470 ?=0 # Flag to apply erratum 827671 workaround during reset. This erratum applies # only to revision >= r3p0 of the Cortex A15 cpu. ERRATA_A15_827671 ?=0 # Flag to apply erratum 852421 workaround during reset. This erratum applies # only to revision <= r1p2 of the Cortex A17 cpu. ERRATA_A17_852421 ?=0 # Flag to apply erratum 852423 workaround during reset. This erratum applies # only to revision <= r1p2 of the Cortex A17 cpu. ERRATA_A17_852423 ?=0 # Flag to apply erratum 855472 workaround during reset. This erratum applies # only to revision r0p0 of the Cortex A35 cpu. ERRATA_A35_855472 ?=0 # Flag to apply erratum 819472 workaround during reset. This erratum applies # only to revision <= r0p1 of the Cortex A53 cpu. ERRATA_A53_819472 ?=0 # Flag to apply erratum 824069 workaround during reset. This erratum applies # only to revision <= r0p2 of the Cortex A53 cpu. ERRATA_A53_824069 ?=0 # Flag to apply erratum 826319 workaround during reset. This erratum applies # only to revision <= r0p2 of the Cortex A53 cpu. ERRATA_A53_826319 ?=0 # Flag to apply erratum 827319 workaround during reset. This erratum applies # only to revision <= r0p2 of the Cortex A53 cpu. ERRATA_A53_827319 ?=0 # Flag to apply erratum 835769 workaround at compile and link time. This # erratum applies to revision <= r0p4 of the Cortex A53 cpu. Enabling this # workaround can lead the linker to create "*.stub" sections. ERRATA_A53_835769 ?=0 # Flag to apply erratum 836870 workaround during reset. This erratum applies # only to revision <= r0p3 of the Cortex A53 cpu. From r0p4 and onwards, this # erratum workaround is enabled by default in hardware. ERRATA_A53_836870 ?=0 # Flag to apply erratum 843419 workaround at link time. # This erratum applies to revision <= r0p4 of the Cortex A53 cpu. Enabling this # workaround could lead the linker to emit "*.stub" sections which are 4kB # aligned. ERRATA_A53_843419 ?=0 # Flag to apply errata 855873 during reset. This errata applies to all # revisions of the Cortex A53 CPU, but this firmware workaround only works # for revisions r0p3 and higher. Earlier revisions are taken care # of by the rich OS. ERRATA_A53_855873 ?=0 # Flag to apply erratum 768277 workaround during reset. This erratum applies # only to revision r0p0 of the Cortex A55 cpu. ERRATA_A55_768277 ?=0 # Flag to apply erratum 778703 workaround during reset. This erratum applies # only to revision r0p0 of the Cortex A55 cpu. ERRATA_A55_778703 ?=0 # Flag to apply erratum 798797 workaround during reset. This erratum applies # only to revision r0p0 of the Cortex A55 cpu. ERRATA_A55_798797 ?=0 # Flag to apply erratum 846532 workaround during reset. This erratum applies # only to revision <= r0p1 of the Cortex A55 cpu. ERRATA_A55_846532 ?=0 # Flag to apply erratum 903758 workaround during reset. This erratum applies # only to revision <= r0p1 of the Cortex A55 cpu. ERRATA_A55_903758 ?=0 # Flag to apply erratum 1221012 workaround during reset. This erratum applies # only to revision <= r1p0 of the Cortex A55 cpu. ERRATA_A55_1221012 ?=0 # Flag to apply erratum 806969 workaround during reset. This erratum applies # only to revision r0p0 of the Cortex A57 cpu. ERRATA_A57_806969 ?=0 # Flag to apply erratum 813419 workaround during reset. This erratum applies # only to revision r0p0 of the Cortex A57 cpu. ERRATA_A57_813419 ?=0 # Flag to apply erratum 813420 workaround during reset. This erratum applies # only to revision r0p0 of the Cortex A57 cpu. ERRATA_A57_813420 ?=0 # Flag to apply erratum 814670 workaround during reset. This erratum applies # only to revision r0p0 of the Cortex A57 cpu. ERRATA_A57_814670 ?=0 # Flag to apply erratum 817169 workaround during power down. This erratum # applies only to revision <= r0p1 of the Cortex A57 cpu. ERRATA_A57_817169 ?=0 # Flag to apply erratum 826974 workaround during reset. This erratum applies # only to revision <= r1p1 of the Cortex A57 cpu. ERRATA_A57_826974 ?=0 # Flag to apply erratum 826977 workaround during reset. This erratum applies # only to revision <= r1p1 of the Cortex A57 cpu. ERRATA_A57_826977 ?=0 # Flag to apply erratum 828024 workaround during reset. This erratum applies # only to revision <= r1p1 of the Cortex A57 cpu. ERRATA_A57_828024 ?=0 # Flag to apply erratum 829520 workaround during reset. This erratum applies # only to revision <= r1p2 of the Cortex A57 cpu. ERRATA_A57_829520 ?=0 # Flag to apply erratum 833471 workaround during reset. This erratum applies # only to revision <= r1p2 of the Cortex A57 cpu. ERRATA_A57_833471 ?=0 # Flag to apply erratum 855972 workaround during reset. This erratum applies # only to revision <= r1p3 of the Cortex A57 cpu. ERRATA_A57_859972 ?=0 # Flag to apply erratum 855971 workaround during reset. This erratum applies # only to revision <= r0p3 of the Cortex A72 cpu. ERRATA_A72_859971 ?=0 # Flag to apply erratum 852427 workaround during reset. This erratum applies # only to revision r0p0 of the Cortex A73 cpu. ERRATA_A73_852427 ?=0 # Flag to apply erratum 855423 workaround during reset. This erratum applies # only to revision <= r0p1 of the Cortex A73 cpu. ERRATA_A73_855423 ?=0 # Flag to apply erratum 764081 workaround during reset. This erratum applies # only to revision <= r0p0 of the Cortex A75 cpu. ERRATA_A75_764081 ?=0 # Flag to apply erratum 790748 workaround during reset. This erratum applies # only to revision <= r0p0 of the Cortex A75 cpu. ERRATA_A75_790748 ?=0 # Flag to apply erratum 1073348 workaround during reset. This erratum applies # only to revision <= r1p0 of the Cortex A76 cpu. ERRATA_A76_1073348 ?=0 # Flag to apply erratum 1130799 workaround during reset. This erratum applies # only to revision <= r2p0 of the Cortex A76 cpu. ERRATA_A76_1130799 ?=0 # Flag to apply erratum 1220197 workaround during reset. This erratum applies # only to revision <= r2p0 of the Cortex A76 cpu. ERRATA_A76_1220197 ?=0 # Flag to apply erratum 1257314 workaround during reset. This erratum applies # only to revision <= r3p0 of the Cortex A76 cpu. ERRATA_A76_1257314 ?=0 # Flag to apply erratum 1262606 workaround during reset. This erratum applies # only to revision <= r3p0 of the Cortex A76 cpu. ERRATA_A76_1262606 ?=0 # Flag to apply erratum 1262888 workaround during reset. This erratum applies # only to revision <= r3p0 of the Cortex A76 cpu. ERRATA_A76_1262888 ?=0 # Flag to apply erratum 1275112 workaround during reset. This erratum applies # only to revision <= r3p0 of the Cortex A76 cpu. ERRATA_A76_1275112 ?=0 # Flag to apply erratum 1286807 workaround during reset. This erratum applies # only to revision <= r3p0 of the Cortex A76 cpu. ERRATA_A76_1286807 ?=0 # Flag to apply T32 CLREX workaround during reset. This erratum applies # only to r0p0 and r1p0 of the Neoverse N1 cpu. ERRATA_N1_1043202 ?=1 # Flag to apply erratum 1073348 workaround during reset. This erratum applies # only to revision r0p0 and r1p0 of the Neoverse N1 cpu. ERRATA_N1_1073348 ?=0 # Flag to apply erratum 1130799 workaround during reset. This erratum applies # only to revision <= r2p0 of the Neoverse N1 cpu. ERRATA_N1_1130799 ?=0 # Flag to apply erratum 1165347 workaround during reset. This erratum applies # only to revision <= r2p0 of the Neoverse N1 cpu. ERRATA_N1_1165347 ?=0 # Flag to apply erratum 1207823 workaround during reset. This erratum applies # only to revision <= r2p0 of the Neoverse N1 cpu. ERRATA_N1_1207823 ?=0 # Flag to apply erratum 1220197 workaround during reset. This erratum applies # only to revision <= r2p0 of the Neoverse N1 cpu. ERRATA_N1_1220197 ?=0 # Flag to apply erratum 1257314 workaround during reset. This erratum applies # only to revision <= r3p0 of the Neoverse N1 cpu. ERRATA_N1_1257314 ?=0 # Flag to apply erratum 1262606 workaround during reset. This erratum applies # only to revision <= r3p0 of the Neoverse N1 cpu. ERRATA_N1_1262606 ?=0 # Flag to apply erratum 1262888 workaround during reset. This erratum applies # only to revision <= r3p0 of the Neoverse N1 cpu. ERRATA_N1_1262888 ?=0 # Flag to apply erratum 1275112 workaround during reset. This erratum applies # only to revision <= r3p0 of the Neoverse N1 cpu. ERRATA_N1_1275112 ?=0 # Flag to apply erratum 1315703 workaround during reset. This erratum applies # to revisions before r3p1 of the Neoverse N1 cpu. ERRATA_N1_1315703 ?=1 # Flag to apply erratum 1542419 workaround during reset. This erratum applies # to revisions r3p0 - r4p0 of the Neoverse N1 cpu. ERRATA_N1_1542419 ?=0 # Flag to apply DSU erratum 798953. This erratum applies to DSUs revision r0p0. # Applying the workaround results in higher DSU power consumption on idle. ERRATA_DSU_798953 ?=0 # Flag to apply DSU erratum 936184. This erratum applies to DSUs containing # the ACP interface and revision < r2p0. Applying the workaround results in # higher DSU power consumption on idle. ERRATA_DSU_936184 ?=0 # Process ERRATA_A9_794073 flag $(eval $(call assert_boolean,ERRATA_A9_794073)) $(eval $(call add_define,ERRATA_A9_794073)) # Process ERRATA_A15_816470 flag $(eval $(call assert_boolean,ERRATA_A15_816470)) $(eval $(call add_define,ERRATA_A15_816470)) # Process ERRATA_A15_827671 flag $(eval $(call assert_boolean,ERRATA_A15_827671)) $(eval $(call add_define,ERRATA_A15_827671)) # Process ERRATA_A17_852421 flag $(eval $(call assert_boolean,ERRATA_A17_852421)) $(eval $(call add_define,ERRATA_A17_852421)) # Process ERRATA_A17_852423 flag $(eval $(call assert_boolean,ERRATA_A17_852423)) $(eval $(call add_define,ERRATA_A17_852423)) # Process ERRATA_A35_855472 flag $(eval $(call assert_boolean,ERRATA_A35_855472)) $(eval $(call add_define,ERRATA_A35_855472)) # Process ERRATA_A53_819472 flag $(eval $(call assert_boolean,ERRATA_A53_819472)) $(eval $(call add_define,ERRATA_A53_819472)) # Process ERRATA_A53_824069 flag $(eval $(call assert_boolean,ERRATA_A53_824069)) $(eval $(call add_define,ERRATA_A53_824069)) # Process ERRATA_A53_826319 flag $(eval $(call assert_boolean,ERRATA_A53_826319)) $(eval $(call add_define,ERRATA_A53_826319)) # Process ERRATA_A53_827319 flag $(eval $(call assert_boolean,ERRATA_A53_827319)) $(eval $(call add_define,ERRATA_A53_827319)) # Process ERRATA_A53_835769 flag $(eval $(call assert_boolean,ERRATA_A53_835769)) $(eval $(call add_define,ERRATA_A53_835769)) # Process ERRATA_A53_836870 flag $(eval $(call assert_boolean,ERRATA_A53_836870)) $(eval $(call add_define,ERRATA_A53_836870)) # Process ERRATA_A53_843419 flag $(eval $(call assert_boolean,ERRATA_A53_843419)) $(eval $(call add_define,ERRATA_A53_843419)) # Process ERRATA_A53_855873 flag $(eval $(call assert_boolean,ERRATA_A53_855873)) $(eval $(call add_define,ERRATA_A53_855873)) # Process ERRATA_A55_768277 flag $(eval $(call assert_boolean,ERRATA_A55_768277)) $(eval $(call add_define,ERRATA_A55_768277)) # Process ERRATA_A55_778703 flag $(eval $(call assert_boolean,ERRATA_A55_778703)) $(eval $(call add_define,ERRATA_A55_778703)) # Process ERRATA_A55_798797 flag $(eval $(call assert_boolean,ERRATA_A55_798797)) $(eval $(call add_define,ERRATA_A55_798797)) # Process ERRATA_A55_846532 flag $(eval $(call assert_boolean,ERRATA_A55_846532)) $(eval $(call add_define,ERRATA_A55_846532)) # Process ERRATA_A55_903758 flag $(eval $(call assert_boolean,ERRATA_A55_903758)) $(eval $(call add_define,ERRATA_A55_903758)) # Process ERRATA_A55_1221012 flag $(eval $(call assert_boolean,ERRATA_A55_1221012)) $(eval $(call add_define,ERRATA_A55_1221012)) # Process ERRATA_A57_806969 flag $(eval $(call assert_boolean,ERRATA_A57_806969)) $(eval $(call add_define,ERRATA_A57_806969)) # Process ERRATA_A57_813419 flag $(eval $(call assert_boolean,ERRATA_A57_813419)) $(eval $(call add_define,ERRATA_A57_813419)) # Process ERRATA_A57_813420 flag $(eval $(call assert_boolean,ERRATA_A57_813420)) $(eval $(call add_define,ERRATA_A57_813420)) # Process ERRATA_A57_814670 flag $(eval $(call assert_boolean,ERRATA_A57_814670)) $(eval $(call add_define,ERRATA_A57_814670)) # Process ERRATA_A57_817169 flag $(eval $(call assert_boolean,ERRATA_A57_817169)) $(eval $(call add_define,ERRATA_A57_817169)) # Process ERRATA_A57_826974 flag $(eval $(call assert_boolean,ERRATA_A57_826974)) $(eval $(call add_define,ERRATA_A57_826974)) # Process ERRATA_A57_826977 flag $(eval $(call assert_boolean,ERRATA_A57_826977)) $(eval $(call add_define,ERRATA_A57_826977)) # Process ERRATA_A57_828024 flag $(eval $(call assert_boolean,ERRATA_A57_828024)) $(eval $(call add_define,ERRATA_A57_828024)) # Process ERRATA_A57_829520 flag $(eval $(call assert_boolean,ERRATA_A57_829520)) $(eval $(call add_define,ERRATA_A57_829520)) # Process ERRATA_A57_833471 flag $(eval $(call assert_boolean,ERRATA_A57_833471)) $(eval $(call add_define,ERRATA_A57_833471)) # Process ERRATA_A57_859972 flag $(eval $(call assert_boolean,ERRATA_A57_859972)) $(eval $(call add_define,ERRATA_A57_859972)) # Process ERRATA_A72_859971 flag $(eval $(call assert_boolean,ERRATA_A72_859971)) $(eval $(call add_define,ERRATA_A72_859971)) # Process ERRATA_A73_852427 flag $(eval $(call assert_boolean,ERRATA_A73_852427)) $(eval $(call add_define,ERRATA_A73_852427)) # Process ERRATA_A73_855423 flag $(eval $(call assert_boolean,ERRATA_A73_855423)) $(eval $(call add_define,ERRATA_A73_855423)) # Process ERRATA_A75_764081 flag $(eval $(call assert_boolean,ERRATA_A75_764081)) $(eval $(call add_define,ERRATA_A75_764081)) # Process ERRATA_A75_790748 flag $(eval $(call assert_boolean,ERRATA_A75_790748)) $(eval $(call add_define,ERRATA_A75_790748)) # Process ERRATA_A76_1073348 flag $(eval $(call assert_boolean,ERRATA_A76_1073348)) $(eval $(call add_define,ERRATA_A76_1073348)) # Process ERRATA_A76_1130799 flag $(eval $(call assert_boolean,ERRATA_A76_1130799)) $(eval $(call add_define,ERRATA_A76_1130799)) # Process ERRATA_A76_1220197 flag $(eval $(call assert_boolean,ERRATA_A76_1220197)) $(eval $(call add_define,ERRATA_A76_1220197)) # Process ERRATA_A76_1257314 flag $(eval $(call assert_boolean,ERRATA_A76_1257314)) $(eval $(call add_define,ERRATA_A76_1257314)) # Process ERRATA_A76_1262606 flag $(eval $(call assert_boolean,ERRATA_A76_1262606)) $(eval $(call add_define,ERRATA_A76_1262606)) # Process ERRATA_A76_1262888 flag $(eval $(call assert_boolean,ERRATA_A76_1262888)) $(eval $(call add_define,ERRATA_A76_1262888)) # Process ERRATA_A76_1275112 flag $(eval $(call assert_boolean,ERRATA_A76_1275112)) $(eval $(call add_define,ERRATA_A76_1275112)) # Process ERRATA_A76_1286807 flag $(eval $(call assert_boolean,ERRATA_A76_1286807)) $(eval $(call add_define,ERRATA_A76_1286807)) # Process ERRATA_N1_1043202 flag $(eval $(call assert_boolean,ERRATA_N1_1043202)) $(eval $(call add_define,ERRATA_N1_1043202)) # Process ERRATA_N1_1073348 flag $(eval $(call assert_boolean,ERRATA_N1_1073348)) $(eval $(call add_define,ERRATA_N1_1073348)) # Process ERRATA_N1_1130799 flag $(eval $(call assert_boolean,ERRATA_N1_1130799)) $(eval $(call add_define,ERRATA_N1_1130799)) # Process ERRATA_N1_1165347 flag $(eval $(call assert_boolean,ERRATA_N1_1165347)) $(eval $(call add_define,ERRATA_N1_1165347)) # Process ERRATA_N1_1207823 flag $(eval $(call assert_boolean,ERRATA_N1_1207823)) $(eval $(call add_define,ERRATA_N1_1207823)) # Process ERRATA_N1_1220197 flag $(eval $(call assert_boolean,ERRATA_N1_1220197)) $(eval $(call add_define,ERRATA_N1_1220197)) # Process ERRATA_N1_1257314 flag $(eval $(call assert_boolean,ERRATA_N1_1257314)) $(eval $(call add_define,ERRATA_N1_1257314)) # Process ERRATA_N1_1262606 flag $(eval $(call assert_boolean,ERRATA_N1_1262606)) $(eval $(call add_define,ERRATA_N1_1262606)) # Process ERRATA_N1_1262888 flag $(eval $(call assert_boolean,ERRATA_N1_1262888)) $(eval $(call add_define,ERRATA_N1_1262888)) # Process ERRATA_N1_1275112 flag $(eval $(call assert_boolean,ERRATA_N1_1275112)) $(eval $(call add_define,ERRATA_N1_1275112)) # Process ERRATA_N1_1315703 flag $(eval $(call assert_boolean,ERRATA_N1_1315703)) $(eval $(call add_define,ERRATA_N1_1315703)) # Process ERRATA_N1_1542419 flag $(eval $(call assert_boolean,ERRATA_N1_1542419)) $(eval $(call add_define,ERRATA_N1_1542419)) # Process ERRATA_DSU_798953 flag $(eval $(call assert_boolean,ERRATA_DSU_798953)) $(eval $(call add_define,ERRATA_DSU_798953)) # Process ERRATA_DSU_936184 flag $(eval $(call assert_boolean,ERRATA_DSU_936184)) $(eval $(call add_define,ERRATA_DSU_936184)) # Errata build flags ifneq (${ERRATA_A53_843419},0) TF_LDFLAGS_aarch64 += --fix-cortex-a53-843419 endif ifneq (${ERRATA_A53_835769},0) TF_CFLAGS_aarch64 += -mfix-cortex-a53-835769 TF_LDFLAGS_aarch64 += --fix-cortex-a53-835769 endif trusted-firmware-a-2.2/lib/cpus/errata_report.c000066400000000000000000000044001355360272700216440ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* Runtime firmware routines to report errata status for the current CPU. */ #include #include #include #include #include #include #include #include #ifdef IMAGE_BL1 # define BL_STRING "BL1" #elif defined(__aarch64__) && defined(IMAGE_BL31) # define BL_STRING "BL31" #elif !defined(__arch64__) && defined(IMAGE_BL32) # define BL_STRING "BL32" #elif defined(IMAGE_BL2) && BL2_AT_EL3 # define BL_STRING "BL2" #else # error This image should not be printing errata status #endif /* Errata format: BL stage, CPU, errata ID, message */ #define ERRATA_FORMAT "%s: %s: CPU workaround for %s was %s\n" /* * Returns whether errata needs to be reported. Passed arguments are private to * a CPU type. */ int errata_needs_reporting(spinlock_t *lock, uint32_t *reported) { bool report_now; /* If already reported, return false. */ if (*reported != 0U) return 0; /* * Acquire lock. Determine whether status needs reporting, and then mark * report status to true. */ spin_lock(lock); report_now = (*reported == 0U); if (report_now) *reported = 1; spin_unlock(lock); return report_now; } /* * Print errata status message. * * Unknown: WARN * Missing: WARN * Applied: INFO * Not applied: VERBOSE */ void errata_print_msg(unsigned int status, const char *cpu, const char *id) { /* Errata status strings */ static const char *const errata_status_str[] = { [ERRATA_NOT_APPLIES] = "not applied", [ERRATA_APPLIES] = "applied", [ERRATA_MISSING] = "missing!" }; static const char *const __unused bl_str = BL_STRING; const char *msg __unused; assert(status < ARRAY_SIZE(errata_status_str)); assert(cpu != NULL); assert(id != NULL); msg = errata_status_str[status]; switch (status) { case ERRATA_NOT_APPLIES: VERBOSE(ERRATA_FORMAT, bl_str, cpu, id, msg); break; case ERRATA_APPLIES: INFO(ERRATA_FORMAT, bl_str, cpu, id, msg); break; case ERRATA_MISSING: WARN(ERRATA_FORMAT, bl_str, cpu, id, msg); break; default: WARN(ERRATA_FORMAT, bl_str, cpu, id, "unknown"); break; } } trusted-firmware-a-2.2/lib/el3_runtime/000077500000000000000000000000001355360272700201055ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/el3_runtime/aarch32/000077500000000000000000000000001355360272700213305ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/el3_runtime/aarch32/context_mgmt.c000066400000000000000000000246631355360272700242170ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * Context management library initialisation routine. This library is used by * runtime services to share pointers to 'cpu_context' structures for the secure * and non-secure states. Management of the structures and their associated * memory is not done by the context management library e.g. the PSCI service * manages the cpu context used for entry from and exit to the non-secure state. * The Secure payload manages the context(s) corresponding to the secure state. * It also uses this library to get access to the non-secure * state cpu context pointers. ******************************************************************************/ void cm_init(void) { /* * The context management library has only global data to initialize, but * that will be done when the BSS is zeroed out */ } /******************************************************************************* * The following function initializes the cpu_context 'ctx' for * first use, and sets the initial entrypoint state as specified by the * entry_point_info structure. * * The security state to initialize is determined by the SECURE attribute * of the entry_point_info. * * The EE and ST attributes are used to configure the endianness and secure * timer availability for the new execution context. * * To prepare the register state for entry call cm_prepare_el3_exit() and * el3_exit(). For Secure-EL1 cm_prepare_el3_exit() is equivalent to * cm_e1_sysreg_context_restore(). ******************************************************************************/ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep) { unsigned int security_state; uint32_t scr, sctlr; regs_t *reg_ctx; assert(ctx != NULL); security_state = GET_SECURITY_STATE(ep->h.attr); /* Clear any residual register values from the context */ zeromem(ctx, sizeof(*ctx)); reg_ctx = get_regs_ctx(ctx); /* * Base the context SCR on the current value, adjust for entry point * specific requirements */ scr = read_scr(); scr &= ~(SCR_NS_BIT | SCR_HCE_BIT); if (security_state != SECURE) scr |= SCR_NS_BIT; if (security_state != SECURE) { /* * Set up SCTLR for the Non-secure context. * * SCTLR.EE: Endianness is taken from the entrypoint attributes. * * SCTLR.M, SCTLR.C and SCTLR.I: These fields must be zero (as * required by PSCI specification) * * Set remaining SCTLR fields to their architecturally defined * values. Some fields reset to an IMPLEMENTATION DEFINED value: * * SCTLR.TE: Set to zero so that exceptions to an Exception * Level executing at PL1 are taken to A32 state. * * SCTLR.V: Set to zero to select the normal exception vectors * with base address held in VBAR. */ assert(((ep->spsr >> SPSR_E_SHIFT) & SPSR_E_MASK) == (EP_GET_EE(ep->h.attr) >> EP_EE_SHIFT)); sctlr = (EP_GET_EE(ep->h.attr) != 0U) ? SCTLR_EE_BIT : 0U; sctlr |= (SCTLR_RESET_VAL & ~(SCTLR_TE_BIT | SCTLR_V_BIT)); write_ctx_reg(reg_ctx, CTX_NS_SCTLR, sctlr); } /* * The target exception level is based on the spsr mode requested. If * execution is requested to hyp mode, HVC is enabled via SCR.HCE. */ if (GET_M32(ep->spsr) == MODE32_hyp) scr |= SCR_HCE_BIT; /* * Store the initialised values for SCTLR and SCR in the cpu_context. * The Hyp mode registers are not part of the saved context and are * set-up in cm_prepare_el3_exit(). */ write_ctx_reg(reg_ctx, CTX_SCR, scr); write_ctx_reg(reg_ctx, CTX_LR, ep->pc); write_ctx_reg(reg_ctx, CTX_SPSR, ep->spsr); /* * Store the r0-r3 value from the entrypoint into the context * Use memcpy as we are in control of the layout of the structures */ memcpy((void *)reg_ctx, (void *)&ep->args, sizeof(aapcs32_params_t)); } /******************************************************************************* * Enable architecture extensions on first entry to Non-secure world. * When EL2 is implemented but unused `el2_unused` is non-zero, otherwise * it is zero. ******************************************************************************/ static void enable_extensions_nonsecure(bool el2_unused) { #if IMAGE_BL32 #if ENABLE_AMU amu_enable(el2_unused); #endif #endif } /******************************************************************************* * The following function initializes the cpu_context for a CPU specified by * its `cpu_idx` for first use, and sets the initial entrypoint state as * specified by the entry_point_info structure. ******************************************************************************/ void cm_init_context_by_index(unsigned int cpu_idx, const entry_point_info_t *ep) { cpu_context_t *ctx; ctx = cm_get_context_by_index(cpu_idx, GET_SECURITY_STATE(ep->h.attr)); cm_setup_context(ctx, ep); } /******************************************************************************* * The following function initializes the cpu_context for the current CPU * for first use, and sets the initial entrypoint state as specified by the * entry_point_info structure. ******************************************************************************/ void cm_init_my_context(const entry_point_info_t *ep) { cpu_context_t *ctx; ctx = cm_get_context(GET_SECURITY_STATE(ep->h.attr)); cm_setup_context(ctx, ep); } /******************************************************************************* * Prepare the CPU system registers for first entry into secure or normal world * * If execution is requested to hyp mode, HSCTLR is initialized * If execution is requested to non-secure PL1, and the CPU supports * HYP mode then HYP mode is disabled by configuring all necessary HYP mode * registers. ******************************************************************************/ void cm_prepare_el3_exit(uint32_t security_state) { uint32_t hsctlr, scr; cpu_context_t *ctx = cm_get_context(security_state); bool el2_unused = false; assert(ctx != NULL); if (security_state == NON_SECURE) { scr = read_ctx_reg(get_regs_ctx(ctx), CTX_SCR); if ((scr & SCR_HCE_BIT) != 0U) { /* Use SCTLR value to initialize HSCTLR */ hsctlr = read_ctx_reg(get_regs_ctx(ctx), CTX_NS_SCTLR); hsctlr |= HSCTLR_RES1; /* Temporarily set the NS bit to access HSCTLR */ write_scr(read_scr() | SCR_NS_BIT); /* * Make sure the write to SCR is complete so that * we can access HSCTLR */ isb(); write_hsctlr(hsctlr); isb(); write_scr(read_scr() & ~SCR_NS_BIT); isb(); } else if ((read_id_pfr1() & (ID_PFR1_VIRTEXT_MASK << ID_PFR1_VIRTEXT_SHIFT)) != 0U) { el2_unused = true; /* * Set the NS bit to access NS copies of certain banked * registers */ write_scr(read_scr() | SCR_NS_BIT); isb(); /* * Hyp / PL2 present but unused, need to disable safely. * HSCTLR can be ignored in this case. * * Set HCR to its architectural reset value so that * Non-secure operations do not trap to Hyp mode. */ write_hcr(HCR_RESET_VAL); /* * Set HCPTR to its architectural reset value so that * Non-secure access from EL1 or EL0 to trace and to * Advanced SIMD and floating point functionality does * not trap to Hyp mode. */ write_hcptr(HCPTR_RESET_VAL); /* * Initialise CNTHCTL. All fields are architecturally * UNKNOWN on reset and are set to zero except for * field(s) listed below. * * CNTHCTL.PL1PCEN: Disable traps to Hyp mode of * Non-secure EL0 and EL1 accessed to the physical * timer registers. * * CNTHCTL.PL1PCTEN: Disable traps to Hyp mode of * Non-secure EL0 and EL1 accessed to the physical * counter registers. */ write_cnthctl(CNTHCTL_RESET_VAL | PL1PCEN_BIT | PL1PCTEN_BIT); /* * Initialise CNTVOFF to zero as it resets to an * IMPLEMENTATION DEFINED value. */ write64_cntvoff(0); /* * Set VPIDR and VMPIDR to match MIDR_EL1 and MPIDR * respectively. */ write_vpidr(read_midr()); write_vmpidr(read_mpidr()); /* * Initialise VTTBR, setting all fields rather than * relying on the hw. Some fields are architecturally * UNKNOWN at reset. * * VTTBR.VMID: Set to zero which is the architecturally * defined reset value. Even though EL1&0 stage 2 * address translation is disabled, cache maintenance * operations depend on the VMID. * * VTTBR.BADDR: Set to zero as EL1&0 stage 2 address * translation is disabled. */ write64_vttbr(VTTBR_RESET_VAL & ~((VTTBR_VMID_MASK << VTTBR_VMID_SHIFT) | (VTTBR_BADDR_MASK << VTTBR_BADDR_SHIFT))); /* * Initialise HDCR, setting all the fields rather than * relying on hw. * * HDCR.HPMN: Set to value of PMCR.N which is the * architecturally-defined reset value. * * HDCR.HLP: Set to one so that event counter * overflow, that is recorded in PMOVSCLR[0-30], * occurs on the increment that changes * PMEVCNTR[63] from 1 to 0, when ARMv8.5-PMU is * implemented. This bit is RES0 in versions of the * architecture earlier than ARMv8.5, setting it to 1 * doesn't have any effect on them. * This bit is Reserved, UNK/SBZP in ARMv7. * * HDCR.HPME: Set to zero to disable EL2 Event * counters. */ #if (ARM_ARCH_MAJOR > 7) write_hdcr((HDCR_RESET_VAL | HDCR_HLP_BIT | ((read_pmcr() & PMCR_N_BITS) >> PMCR_N_SHIFT)) & ~HDCR_HPME_BIT); #else write_hdcr((HDCR_RESET_VAL | ((read_pmcr() & PMCR_N_BITS) >> PMCR_N_SHIFT)) & ~HDCR_HPME_BIT); #endif /* * Set HSTR to its architectural reset value so that * access to system registers in the cproc=1111 * encoding space do not trap to Hyp mode. */ write_hstr(HSTR_RESET_VAL); /* * Set CNTHP_CTL to its architectural reset value to * disable the EL2 physical timer and prevent timer * interrupts. Some fields are architecturally UNKNOWN * on reset and are set to zero. */ write_cnthp_ctl(CNTHP_CTL_RESET_VAL); isb(); write_scr(read_scr() & ~SCR_NS_BIT); isb(); } enable_extensions_nonsecure(el2_unused); } } trusted-firmware-a-2.2/lib/el3_runtime/aarch32/cpu_data.S000066400000000000000000000021341355360272700232340ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .globl _cpu_data .globl _cpu_data_by_index /* ----------------------------------------------------------------- * cpu_data_t *_cpu_data(void) * * Return the cpu_data structure for the current CPU. * ----------------------------------------------------------------- */ func _cpu_data /* r12 is pushed to meet the 8 byte stack alignment requirement */ push {r12, lr} bl plat_my_core_pos pop {r12, lr} b _cpu_data_by_index endfunc _cpu_data /* ----------------------------------------------------------------- * cpu_data_t *_cpu_data_by_index(uint32_t cpu_index) * * Return the cpu_data structure for the CPU with given linear index * * This can be called without a valid stack. * clobbers: r0, r1 * ----------------------------------------------------------------- */ func _cpu_data_by_index mov_imm r1, CPU_DATA_SIZE mul r0, r0, r1 ldr r1, =percpu_data add r0, r0, r1 bx lr endfunc _cpu_data_by_index trusted-firmware-a-2.2/lib/el3_runtime/aarch64/000077500000000000000000000000001355360272700213355ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/el3_runtime/aarch64/context.S000066400000000000000000000374751355360272700231650ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .global el1_sysregs_context_save .global el1_sysregs_context_restore #if CTX_INCLUDE_FPREGS .global fpregs_context_save .global fpregs_context_restore #endif .global save_gp_pmcr_pauth_regs .global restore_gp_pmcr_pauth_regs .global el3_exit /* ------------------------------------------------------------------ * The following function strictly follows the AArch64 PCS to use * x9-x17 (temporary caller-saved registers) to save EL1 system * register context. It assumes that 'x0' is pointing to a * 'el1_sys_regs' structure where the register context will be saved. * ------------------------------------------------------------------ */ func el1_sysregs_context_save mrs x9, spsr_el1 mrs x10, elr_el1 stp x9, x10, [x0, #CTX_SPSR_EL1] mrs x15, sctlr_el1 mrs x16, actlr_el1 stp x15, x16, [x0, #CTX_SCTLR_EL1] mrs x17, cpacr_el1 mrs x9, csselr_el1 stp x17, x9, [x0, #CTX_CPACR_EL1] mrs x10, sp_el1 mrs x11, esr_el1 stp x10, x11, [x0, #CTX_SP_EL1] mrs x12, ttbr0_el1 mrs x13, ttbr1_el1 stp x12, x13, [x0, #CTX_TTBR0_EL1] mrs x14, mair_el1 mrs x15, amair_el1 stp x14, x15, [x0, #CTX_MAIR_EL1] mrs x16, tcr_el1 mrs x17, tpidr_el1 stp x16, x17, [x0, #CTX_TCR_EL1] mrs x9, tpidr_el0 mrs x10, tpidrro_el0 stp x9, x10, [x0, #CTX_TPIDR_EL0] mrs x13, par_el1 mrs x14, far_el1 stp x13, x14, [x0, #CTX_PAR_EL1] mrs x15, afsr0_el1 mrs x16, afsr1_el1 stp x15, x16, [x0, #CTX_AFSR0_EL1] mrs x17, contextidr_el1 mrs x9, vbar_el1 stp x17, x9, [x0, #CTX_CONTEXTIDR_EL1] /* Save AArch32 system registers if the build has instructed so */ #if CTX_INCLUDE_AARCH32_REGS mrs x11, spsr_abt mrs x12, spsr_und stp x11, x12, [x0, #CTX_SPSR_ABT] mrs x13, spsr_irq mrs x14, spsr_fiq stp x13, x14, [x0, #CTX_SPSR_IRQ] mrs x15, dacr32_el2 mrs x16, ifsr32_el2 stp x15, x16, [x0, #CTX_DACR32_EL2] #endif /* Save NS timer registers if the build has instructed so */ #if NS_TIMER_SWITCH mrs x10, cntp_ctl_el0 mrs x11, cntp_cval_el0 stp x10, x11, [x0, #CTX_CNTP_CTL_EL0] mrs x12, cntv_ctl_el0 mrs x13, cntv_cval_el0 stp x12, x13, [x0, #CTX_CNTV_CTL_EL0] mrs x14, cntkctl_el1 str x14, [x0, #CTX_CNTKCTL_EL1] #endif /* Save MTE system registers if the build has instructed so */ #if CTX_INCLUDE_MTE_REGS mrs x15, TFSRE0_EL1 mrs x16, TFSR_EL1 stp x15, x16, [x0, #CTX_TFSRE0_EL1] mrs x9, RGSR_EL1 mrs x10, GCR_EL1 stp x9, x10, [x0, #CTX_RGSR_EL1] #endif ret endfunc el1_sysregs_context_save /* ------------------------------------------------------------------ * The following function strictly follows the AArch64 PCS to use * x9-x17 (temporary caller-saved registers) to restore EL1 system * register context. It assumes that 'x0' is pointing to a * 'el1_sys_regs' structure from where the register context will be * restored * ------------------------------------------------------------------ */ func el1_sysregs_context_restore ldp x9, x10, [x0, #CTX_SPSR_EL1] msr spsr_el1, x9 msr elr_el1, x10 ldp x15, x16, [x0, #CTX_SCTLR_EL1] msr sctlr_el1, x15 msr actlr_el1, x16 ldp x17, x9, [x0, #CTX_CPACR_EL1] msr cpacr_el1, x17 msr csselr_el1, x9 ldp x10, x11, [x0, #CTX_SP_EL1] msr sp_el1, x10 msr esr_el1, x11 ldp x12, x13, [x0, #CTX_TTBR0_EL1] msr ttbr0_el1, x12 msr ttbr1_el1, x13 ldp x14, x15, [x0, #CTX_MAIR_EL1] msr mair_el1, x14 msr amair_el1, x15 ldp x16, x17, [x0, #CTX_TCR_EL1] msr tcr_el1, x16 msr tpidr_el1, x17 ldp x9, x10, [x0, #CTX_TPIDR_EL0] msr tpidr_el0, x9 msr tpidrro_el0, x10 ldp x13, x14, [x0, #CTX_PAR_EL1] msr par_el1, x13 msr far_el1, x14 ldp x15, x16, [x0, #CTX_AFSR0_EL1] msr afsr0_el1, x15 msr afsr1_el1, x16 ldp x17, x9, [x0, #CTX_CONTEXTIDR_EL1] msr contextidr_el1, x17 msr vbar_el1, x9 /* Restore AArch32 system registers if the build has instructed so */ #if CTX_INCLUDE_AARCH32_REGS ldp x11, x12, [x0, #CTX_SPSR_ABT] msr spsr_abt, x11 msr spsr_und, x12 ldp x13, x14, [x0, #CTX_SPSR_IRQ] msr spsr_irq, x13 msr spsr_fiq, x14 ldp x15, x16, [x0, #CTX_DACR32_EL2] msr dacr32_el2, x15 msr ifsr32_el2, x16 #endif /* Restore NS timer registers if the build has instructed so */ #if NS_TIMER_SWITCH ldp x10, x11, [x0, #CTX_CNTP_CTL_EL0] msr cntp_ctl_el0, x10 msr cntp_cval_el0, x11 ldp x12, x13, [x0, #CTX_CNTV_CTL_EL0] msr cntv_ctl_el0, x12 msr cntv_cval_el0, x13 ldr x14, [x0, #CTX_CNTKCTL_EL1] msr cntkctl_el1, x14 #endif /* Restore MTE system registers if the build has instructed so */ #if CTX_INCLUDE_MTE_REGS ldp x11, x12, [x0, #CTX_TFSRE0_EL1] msr TFSRE0_EL1, x11 msr TFSR_EL1, x12 ldp x13, x14, [x0, #CTX_RGSR_EL1] msr RGSR_EL1, x13 msr GCR_EL1, x14 #endif /* No explict ISB required here as ERET covers it */ ret endfunc el1_sysregs_context_restore /* ------------------------------------------------------------------ * The following function follows the aapcs_64 strictly to use * x9-x17 (temporary caller-saved registers according to AArch64 PCS) * to save floating point register context. It assumes that 'x0' is * pointing to a 'fp_regs' structure where the register context will * be saved. * * Access to VFP registers will trap if CPTR_EL3.TFP is set. * However currently we don't use VFP registers nor set traps in * Trusted Firmware, and assume it's cleared. * * TODO: Revisit when VFP is used in secure world * ------------------------------------------------------------------ */ #if CTX_INCLUDE_FPREGS func fpregs_context_save stp q0, q1, [x0, #CTX_FP_Q0] stp q2, q3, [x0, #CTX_FP_Q2] stp q4, q5, [x0, #CTX_FP_Q4] stp q6, q7, [x0, #CTX_FP_Q6] stp q8, q9, [x0, #CTX_FP_Q8] stp q10, q11, [x0, #CTX_FP_Q10] stp q12, q13, [x0, #CTX_FP_Q12] stp q14, q15, [x0, #CTX_FP_Q14] stp q16, q17, [x0, #CTX_FP_Q16] stp q18, q19, [x0, #CTX_FP_Q18] stp q20, q21, [x0, #CTX_FP_Q20] stp q22, q23, [x0, #CTX_FP_Q22] stp q24, q25, [x0, #CTX_FP_Q24] stp q26, q27, [x0, #CTX_FP_Q26] stp q28, q29, [x0, #CTX_FP_Q28] stp q30, q31, [x0, #CTX_FP_Q30] mrs x9, fpsr str x9, [x0, #CTX_FP_FPSR] mrs x10, fpcr str x10, [x0, #CTX_FP_FPCR] #if CTX_INCLUDE_AARCH32_REGS mrs x11, fpexc32_el2 str x11, [x0, #CTX_FP_FPEXC32_EL2] #endif ret endfunc fpregs_context_save /* ------------------------------------------------------------------ * The following function follows the aapcs_64 strictly to use x9-x17 * (temporary caller-saved registers according to AArch64 PCS) to * restore floating point register context. It assumes that 'x0' is * pointing to a 'fp_regs' structure from where the register context * will be restored. * * Access to VFP registers will trap if CPTR_EL3.TFP is set. * However currently we don't use VFP registers nor set traps in * Trusted Firmware, and assume it's cleared. * * TODO: Revisit when VFP is used in secure world * ------------------------------------------------------------------ */ func fpregs_context_restore ldp q0, q1, [x0, #CTX_FP_Q0] ldp q2, q3, [x0, #CTX_FP_Q2] ldp q4, q5, [x0, #CTX_FP_Q4] ldp q6, q7, [x0, #CTX_FP_Q6] ldp q8, q9, [x0, #CTX_FP_Q8] ldp q10, q11, [x0, #CTX_FP_Q10] ldp q12, q13, [x0, #CTX_FP_Q12] ldp q14, q15, [x0, #CTX_FP_Q14] ldp q16, q17, [x0, #CTX_FP_Q16] ldp q18, q19, [x0, #CTX_FP_Q18] ldp q20, q21, [x0, #CTX_FP_Q20] ldp q22, q23, [x0, #CTX_FP_Q22] ldp q24, q25, [x0, #CTX_FP_Q24] ldp q26, q27, [x0, #CTX_FP_Q26] ldp q28, q29, [x0, #CTX_FP_Q28] ldp q30, q31, [x0, #CTX_FP_Q30] ldr x9, [x0, #CTX_FP_FPSR] msr fpsr, x9 ldr x10, [x0, #CTX_FP_FPCR] msr fpcr, x10 #if CTX_INCLUDE_AARCH32_REGS ldr x11, [x0, #CTX_FP_FPEXC32_EL2] msr fpexc32_el2, x11 #endif /* * No explict ISB required here as ERET to * switch to secure EL1 or non-secure world * covers it */ ret endfunc fpregs_context_restore #endif /* CTX_INCLUDE_FPREGS */ /* ------------------------------------------------------------------ * The following function is used to save and restore all the general * purpose and ARMv8.3-PAuth (if enabled) registers. * It also checks if Secure Cycle Counter is not disabled in MDCR_EL3 * when ARMv8.5-PMU is implemented, and if called from Non-secure * state saves PMCR_EL0 and disables Cycle Counter. * * Ideally we would only save and restore the callee saved registers * when a world switch occurs but that type of implementation is more * complex. So currently we will always save and restore these * registers on entry and exit of EL3. * These are not macros to ensure their invocation fits within the 32 * instructions per exception vector. * clobbers: x18 * ------------------------------------------------------------------ */ func save_gp_pmcr_pauth_regs stp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] stp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] stp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4] stp x6, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X6] stp x8, x9, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X8] stp x10, x11, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X10] stp x12, x13, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X12] stp x14, x15, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X14] stp x16, x17, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X16] stp x18, x19, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X18] stp x20, x21, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X20] stp x22, x23, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X22] stp x24, x25, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X24] stp x26, x27, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X26] stp x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28] mrs x18, sp_el0 str x18, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_SP_EL0] /* ---------------------------------------------------------- * Check if earlier initialization MDCR_EL3.SCCD to 1 failed, * meaning that ARMv8-PMU is not implemented and PMCR_EL0 * should be saved in non-secure context. * ---------------------------------------------------------- */ mrs x9, mdcr_el3 tst x9, #MDCR_SCCD_BIT bne 1f /* Secure Cycle Counter is not disabled */ mrs x9, pmcr_el0 /* Check caller's security state */ mrs x10, scr_el3 tst x10, #SCR_NS_BIT beq 2f /* Save PMCR_EL0 if called from Non-secure state */ str x9, [sp, #CTX_EL3STATE_OFFSET + CTX_PMCR_EL0] /* Disable cycle counter when event counting is prohibited */ 2: orr x9, x9, #PMCR_EL0_DP_BIT msr pmcr_el0, x9 isb 1: #if CTX_INCLUDE_PAUTH_REGS /* ---------------------------------------------------------- * Save the ARMv8.3-PAuth keys as they are not banked * by exception level * ---------------------------------------------------------- */ add x19, sp, #CTX_PAUTH_REGS_OFFSET mrs x20, APIAKeyLo_EL1 /* x21:x20 = APIAKey */ mrs x21, APIAKeyHi_EL1 mrs x22, APIBKeyLo_EL1 /* x23:x22 = APIBKey */ mrs x23, APIBKeyHi_EL1 mrs x24, APDAKeyLo_EL1 /* x25:x24 = APDAKey */ mrs x25, APDAKeyHi_EL1 mrs x26, APDBKeyLo_EL1 /* x27:x26 = APDBKey */ mrs x27, APDBKeyHi_EL1 mrs x28, APGAKeyLo_EL1 /* x29:x28 = APGAKey */ mrs x29, APGAKeyHi_EL1 stp x20, x21, [x19, #CTX_PACIAKEY_LO] stp x22, x23, [x19, #CTX_PACIBKEY_LO] stp x24, x25, [x19, #CTX_PACDAKEY_LO] stp x26, x27, [x19, #CTX_PACDBKEY_LO] stp x28, x29, [x19, #CTX_PACGAKEY_LO] #endif /* CTX_INCLUDE_PAUTH_REGS */ ret endfunc save_gp_pmcr_pauth_regs /* ------------------------------------------------------------------ * This function restores ARMv8.3-PAuth (if enabled) and all general * purpose registers except x30 from the CPU context. * x30 register must be explicitly restored by the caller. * ------------------------------------------------------------------ */ func restore_gp_pmcr_pauth_regs #if CTX_INCLUDE_PAUTH_REGS /* Restore the ARMv8.3 PAuth keys */ add x10, sp, #CTX_PAUTH_REGS_OFFSET ldp x0, x1, [x10, #CTX_PACIAKEY_LO] /* x1:x0 = APIAKey */ ldp x2, x3, [x10, #CTX_PACIBKEY_LO] /* x3:x2 = APIBKey */ ldp x4, x5, [x10, #CTX_PACDAKEY_LO] /* x5:x4 = APDAKey */ ldp x6, x7, [x10, #CTX_PACDBKEY_LO] /* x7:x6 = APDBKey */ ldp x8, x9, [x10, #CTX_PACGAKEY_LO] /* x9:x8 = APGAKey */ msr APIAKeyLo_EL1, x0 msr APIAKeyHi_EL1, x1 msr APIBKeyLo_EL1, x2 msr APIBKeyHi_EL1, x3 msr APDAKeyLo_EL1, x4 msr APDAKeyHi_EL1, x5 msr APDBKeyLo_EL1, x6 msr APDBKeyHi_EL1, x7 msr APGAKeyLo_EL1, x8 msr APGAKeyHi_EL1, x9 #endif /* CTX_INCLUDE_PAUTH_REGS */ /* ---------------------------------------------------------- * Restore PMCR_EL0 when returning to Non-secure state if * Secure Cycle Counter is not disabled in MDCR_EL3 when * ARMv8.5-PMU is implemented. * ---------------------------------------------------------- */ mrs x0, scr_el3 tst x0, #SCR_NS_BIT beq 2f /* ---------------------------------------------------------- * Back to Non-secure state. * Check if earlier initialization MDCR_EL3.SCCD to 1 failed, * meaning that ARMv8-PMU is not implemented and PMCR_EL0 * should be restored from non-secure context. * ---------------------------------------------------------- */ mrs x0, mdcr_el3 tst x0, #MDCR_SCCD_BIT bne 2f ldr x0, [sp, #CTX_EL3STATE_OFFSET + CTX_PMCR_EL0] msr pmcr_el0, x0 2: ldp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0] ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2] ldp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4] ldp x6, x7, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X6] ldp x8, x9, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X8] ldp x10, x11, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X10] ldp x12, x13, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X12] ldp x14, x15, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X14] ldp x16, x17, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X16] ldp x18, x19, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X18] ldp x20, x21, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X20] ldp x22, x23, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X22] ldp x24, x25, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X24] ldp x26, x27, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X26] ldr x28, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_SP_EL0] msr sp_el0, x28 ldp x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28] ret endfunc restore_gp_pmcr_pauth_regs /* ------------------------------------------------------------------ * This routine assumes that the SP_EL3 is pointing to a valid * context structure from where the gp regs and other special * registers can be retrieved. * ------------------------------------------------------------------ */ func el3_exit /* ---------------------------------------------------------- * Save the current SP_EL0 i.e. the EL3 runtime stack which * will be used for handling the next SMC. * Then switch to SP_EL3. * ---------------------------------------------------------- */ mov x17, sp msr spsel, #MODE_SP_ELX str x17, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP] /* ---------------------------------------------------------- * Restore SPSR_EL3, ELR_EL3 and SCR_EL3 prior to ERET * ---------------------------------------------------------- */ ldr x18, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3] ldp x16, x17, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3] msr scr_el3, x18 msr spsr_el3, x16 msr elr_el3, x17 #if IMAGE_BL31 && DYNAMIC_WORKAROUND_CVE_2018_3639 /* ---------------------------------------------------------- * Restore mitigation state as it was on entry to EL3 * ---------------------------------------------------------- */ ldr x17, [sp, #CTX_CVE_2018_3639_OFFSET + CTX_CVE_2018_3639_DISABLE] cbz x17, 1f blr x17 1: #endif /* ---------------------------------------------------------- * Restore general purpose (including x30), PMCR_EL0 and * ARMv8.3-PAuth registers. * Exit EL3 via ERET to a lower exception level. * ---------------------------------------------------------- */ bl restore_gp_pmcr_pauth_regs ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR] #if IMAGE_BL31 && RAS_EXTENSION /* ---------------------------------------------------------- * Issue Error Synchronization Barrier to synchronize SErrors * before exiting EL3. We're running with EAs unmasked, so * any synchronized errors would be taken immediately; * therefore no need to inspect DISR_EL1 register. * ---------------------------------------------------------- */ esb #endif eret endfunc el3_exit trusted-firmware-a-2.2/lib/el3_runtime/aarch64/context_mgmt.c000066400000000000000000000532121355360272700242140ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * Context management library initialisation routine. This library is used by * runtime services to share pointers to 'cpu_context' structures for the secure * and non-secure states. Management of the structures and their associated * memory is not done by the context management library e.g. the PSCI service * manages the cpu context used for entry from and exit to the non-secure state. * The Secure payload dispatcher service manages the context(s) corresponding to * the secure state. It also uses this library to get access to the non-secure * state cpu context pointers. * Lastly, this library provides the api to make SP_EL3 point to the cpu context * which will used for programming an entry into a lower EL. The same context * will used to save state upon exception entry from that EL. ******************************************************************************/ void __init cm_init(void) { /* * The context management library has only global data to intialize, but * that will be done when the BSS is zeroed out */ } /******************************************************************************* * The following function initializes the cpu_context 'ctx' for * first use, and sets the initial entrypoint state as specified by the * entry_point_info structure. * * The security state to initialize is determined by the SECURE attribute * of the entry_point_info. * * The EE and ST attributes are used to configure the endianness and secure * timer availability for the new execution context. * * To prepare the register state for entry call cm_prepare_el3_exit() and * el3_exit(). For Secure-EL1 cm_prepare_el3_exit() is equivalent to * cm_e1_sysreg_context_restore(). ******************************************************************************/ void cm_setup_context(cpu_context_t *ctx, const entry_point_info_t *ep) { unsigned int security_state; uint32_t scr_el3; el3_state_t *state; gp_regs_t *gp_regs; u_register_t sctlr_elx, actlr_elx; assert(ctx != NULL); security_state = GET_SECURITY_STATE(ep->h.attr); /* Clear any residual register values from the context */ zeromem(ctx, sizeof(*ctx)); /* * SCR_EL3 was initialised during reset sequence in macro * el3_arch_init_common. This code modifies the SCR_EL3 fields that * affect the next EL. * * The following fields are initially set to zero and then updated to * the required value depending on the state of the SPSR_EL3 and the * Security state and entrypoint attributes of the next EL. */ scr_el3 = (uint32_t)read_scr(); scr_el3 &= ~(SCR_NS_BIT | SCR_RW_BIT | SCR_FIQ_BIT | SCR_IRQ_BIT | SCR_ST_BIT | SCR_HCE_BIT); /* * SCR_NS: Set the security state of the next EL. */ if (security_state != SECURE) scr_el3 |= SCR_NS_BIT; /* * SCR_EL3.RW: Set the execution state, AArch32 or AArch64, for next * Exception level as specified by SPSR. */ if (GET_RW(ep->spsr) == MODE_RW_64) scr_el3 |= SCR_RW_BIT; /* * SCR_EL3.ST: Traps Secure EL1 accesses to the Counter-timer Physical * Secure timer registers to EL3, from AArch64 state only, if specified * by the entrypoint attributes. */ if (EP_GET_ST(ep->h.attr) != 0U) scr_el3 |= SCR_ST_BIT; #if !HANDLE_EA_EL3_FIRST /* * SCR_EL3.EA: Do not route External Abort and SError Interrupt External * to EL3 when executing at a lower EL. When executing at EL3, External * Aborts are taken to EL3. */ scr_el3 &= ~SCR_EA_BIT; #endif #if FAULT_INJECTION_SUPPORT /* Enable fault injection from lower ELs */ scr_el3 |= SCR_FIEN_BIT; #endif #if !CTX_INCLUDE_PAUTH_REGS /* * If the pointer authentication registers aren't saved during world * switches the value of the registers can be leaked from the Secure to * the Non-secure world. To prevent this, rather than enabling pointer * authentication everywhere, we only enable it in the Non-secure world. * * If the Secure world wants to use pointer authentication, * CTX_INCLUDE_PAUTH_REGS must be set to 1. */ if (security_state == NON_SECURE) scr_el3 |= SCR_API_BIT | SCR_APK_BIT; #endif /* !CTX_INCLUDE_PAUTH_REGS */ /* * Enable MTE support. Support is enabled unilaterally for the normal * world, and only for the secure world when CTX_INCLUDE_MTE_REGS is * set. */ #if CTX_INCLUDE_MTE_REGS assert(get_armv8_5_mte_support() == MTE_IMPLEMENTED_ELX); scr_el3 |= SCR_ATA_BIT; #else unsigned int mte = get_armv8_5_mte_support(); if (mte == MTE_IMPLEMENTED_EL0) { /* * Can enable MTE across both worlds as no MTE registers are * used */ scr_el3 |= SCR_ATA_BIT; } else if (mte == MTE_IMPLEMENTED_ELX && security_state == NON_SECURE) { /* * Can only enable MTE in Non-Secure world without register * saving */ scr_el3 |= SCR_ATA_BIT; } #endif #ifdef IMAGE_BL31 /* * SCR_EL3.IRQ, SCR_EL3.FIQ: Enable the physical FIQ and IRQ routing as * indicated by the interrupt routing model for BL31. */ scr_el3 |= get_scr_el3_from_routing_model(security_state); #endif /* * SCR_EL3.HCE: Enable HVC instructions if next execution state is * AArch64 and next EL is EL2, or if next execution state is AArch32 and * next mode is Hyp. */ if (((GET_RW(ep->spsr) == MODE_RW_64) && (GET_EL(ep->spsr) == MODE_EL2)) || ((GET_RW(ep->spsr) != MODE_RW_64) && (GET_M32(ep->spsr) == MODE32_hyp))) { scr_el3 |= SCR_HCE_BIT; } /* * Initialise SCTLR_EL1 to the reset value corresponding to the target * execution state setting all fields rather than relying of the hw. * Some fields have architecturally UNKNOWN reset values and these are * set to zero. * * SCTLR.EE: Endianness is taken from the entrypoint attributes. * * SCTLR.M, SCTLR.C and SCTLR.I: These fields must be zero (as * required by PSCI specification) */ sctlr_elx = (EP_GET_EE(ep->h.attr) != 0U) ? SCTLR_EE_BIT : 0U; if (GET_RW(ep->spsr) == MODE_RW_64) sctlr_elx |= SCTLR_EL1_RES1; else { /* * If the target execution state is AArch32 then the following * fields need to be set. * * SCTRL_EL1.nTWE: Set to one so that EL0 execution of WFE * instructions are not trapped to EL1. * * SCTLR_EL1.nTWI: Set to one so that EL0 execution of WFI * instructions are not trapped to EL1. * * SCTLR_EL1.CP15BEN: Set to one to enable EL0 execution of the * CP15DMB, CP15DSB, and CP15ISB instructions. */ sctlr_elx |= SCTLR_AARCH32_EL1_RES1 | SCTLR_CP15BEN_BIT | SCTLR_NTWI_BIT | SCTLR_NTWE_BIT; } #if ERRATA_A75_764081 /* * If workaround of errata 764081 for Cortex-A75 is used then set * SCTLR_EL1.IESB to enable Implicit Error Synchronization Barrier. */ sctlr_elx |= SCTLR_IESB_BIT; #endif /* * Store the initialised SCTLR_EL1 value in the cpu_context - SCTLR_EL2 * and other EL2 registers are set up by cm_prepare_ns_entry() as they * are not part of the stored cpu_context. */ write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_elx); /* * Base the context ACTLR_EL1 on the current value, as it is * implementation defined. The context restore process will write * the value from the context to the actual register and can cause * problems for processor cores that don't expect certain bits to * be zero. */ actlr_elx = read_actlr_el1(); write_ctx_reg((get_sysregs_ctx(ctx)), (CTX_ACTLR_EL1), (actlr_elx)); /* * Populate EL3 state so that we've the right context * before doing ERET */ state = get_el3state_ctx(ctx); write_ctx_reg(state, CTX_SCR_EL3, scr_el3); write_ctx_reg(state, CTX_ELR_EL3, ep->pc); write_ctx_reg(state, CTX_SPSR_EL3, ep->spsr); /* * Store the X0-X7 value from the entrypoint into the context * Use memcpy as we are in control of the layout of the structures */ gp_regs = get_gpregs_ctx(ctx); memcpy(gp_regs, (void *)&ep->args, sizeof(aapcs64_params_t)); } /******************************************************************************* * Enable architecture extensions on first entry to Non-secure world. * When EL2 is implemented but unused `el2_unused` is non-zero, otherwise * it is zero. ******************************************************************************/ static void enable_extensions_nonsecure(bool el2_unused) { #if IMAGE_BL31 #if ENABLE_SPE_FOR_LOWER_ELS spe_enable(el2_unused); #endif #if ENABLE_AMU amu_enable(el2_unused); #endif #if ENABLE_SVE_FOR_NS sve_enable(el2_unused); #endif #if ENABLE_MPAM_FOR_LOWER_ELS mpam_enable(el2_unused); #endif #endif } /******************************************************************************* * The following function initializes the cpu_context for a CPU specified by * its `cpu_idx` for first use, and sets the initial entrypoint state as * specified by the entry_point_info structure. ******************************************************************************/ void cm_init_context_by_index(unsigned int cpu_idx, const entry_point_info_t *ep) { cpu_context_t *ctx; ctx = cm_get_context_by_index(cpu_idx, GET_SECURITY_STATE(ep->h.attr)); cm_setup_context(ctx, ep); } /******************************************************************************* * The following function initializes the cpu_context for the current CPU * for first use, and sets the initial entrypoint state as specified by the * entry_point_info structure. ******************************************************************************/ void cm_init_my_context(const entry_point_info_t *ep) { cpu_context_t *ctx; ctx = cm_get_context(GET_SECURITY_STATE(ep->h.attr)); cm_setup_context(ctx, ep); } /******************************************************************************* * Prepare the CPU system registers for first entry into secure or normal world * * If execution is requested to EL2 or hyp mode, SCTLR_EL2 is initialized * If execution is requested to non-secure EL1 or svc mode, and the CPU supports * EL2 then EL2 is disabled by configuring all necessary EL2 registers. * For all entries, the EL1 registers are initialized from the cpu_context ******************************************************************************/ void cm_prepare_el3_exit(uint32_t security_state) { uint32_t sctlr_elx, scr_el3, mdcr_el2; cpu_context_t *ctx = cm_get_context(security_state); bool el2_unused = false; uint64_t hcr_el2 = 0U; assert(ctx != NULL); if (security_state == NON_SECURE) { scr_el3 = (uint32_t)read_ctx_reg(get_el3state_ctx(ctx), CTX_SCR_EL3); if ((scr_el3 & SCR_HCE_BIT) != 0U) { /* Use SCTLR_EL1.EE value to initialise sctlr_el2 */ sctlr_elx = (uint32_t)read_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1); sctlr_elx &= SCTLR_EE_BIT; sctlr_elx |= SCTLR_EL2_RES1; #if ERRATA_A75_764081 /* * If workaround of errata 764081 for Cortex-A75 is used * then set SCTLR_EL2.IESB to enable Implicit Error * Synchronization Barrier. */ sctlr_elx |= SCTLR_IESB_BIT; #endif write_sctlr_el2(sctlr_elx); } else if (el_implemented(2) != EL_IMPL_NONE) { el2_unused = true; /* * EL2 present but unused, need to disable safely. * SCTLR_EL2 can be ignored in this case. * * Set EL2 register width appropriately: Set HCR_EL2 * field to match SCR_EL3.RW. */ if ((scr_el3 & SCR_RW_BIT) != 0U) hcr_el2 |= HCR_RW_BIT; /* * For Armv8.3 pointer authentication feature, disable * traps to EL2 when accessing key registers or using * pointer authentication instructions from lower ELs. */ hcr_el2 |= (HCR_API_BIT | HCR_APK_BIT); write_hcr_el2(hcr_el2); /* * Initialise CPTR_EL2 setting all fields rather than * relying on the hw. All fields have architecturally * UNKNOWN reset values. * * CPTR_EL2.TCPAC: Set to zero so that Non-secure EL1 * accesses to the CPACR_EL1 or CPACR from both * Execution states do not trap to EL2. * * CPTR_EL2.TTA: Set to zero so that Non-secure System * register accesses to the trace registers from both * Execution states do not trap to EL2. * * CPTR_EL2.TFP: Set to zero so that Non-secure accesses * to SIMD and floating-point functionality from both * Execution states do not trap to EL2. */ write_cptr_el2(CPTR_EL2_RESET_VAL & ~(CPTR_EL2_TCPAC_BIT | CPTR_EL2_TTA_BIT | CPTR_EL2_TFP_BIT)); /* * Initialise CNTHCTL_EL2. All fields are * architecturally UNKNOWN on reset and are set to zero * except for field(s) listed below. * * CNTHCTL_EL2.EL1PCEN: Set to one to disable traps to * Hyp mode of Non-secure EL0 and EL1 accesses to the * physical timer registers. * * CNTHCTL_EL2.EL1PCTEN: Set to one to disable traps to * Hyp mode of Non-secure EL0 and EL1 accesses to the * physical counter registers. */ write_cnthctl_el2(CNTHCTL_RESET_VAL | EL1PCEN_BIT | EL1PCTEN_BIT); /* * Initialise CNTVOFF_EL2 to zero as it resets to an * architecturally UNKNOWN value. */ write_cntvoff_el2(0); /* * Set VPIDR_EL2 and VMPIDR_EL2 to match MIDR_EL1 and * MPIDR_EL1 respectively. */ write_vpidr_el2(read_midr_el1()); write_vmpidr_el2(read_mpidr_el1()); /* * Initialise VTTBR_EL2. All fields are architecturally * UNKNOWN on reset. * * VTTBR_EL2.VMID: Set to zero. Even though EL1&0 stage * 2 address translation is disabled, cache maintenance * operations depend on the VMID. * * VTTBR_EL2.BADDR: Set to zero as EL1&0 stage 2 address * translation is disabled. */ write_vttbr_el2(VTTBR_RESET_VAL & ~((VTTBR_VMID_MASK << VTTBR_VMID_SHIFT) | (VTTBR_BADDR_MASK << VTTBR_BADDR_SHIFT))); /* * Initialise MDCR_EL2, setting all fields rather than * relying on hw. Some fields are architecturally * UNKNOWN on reset. * * MDCR_EL2.HLP: Set to one so that event counter * overflow, that is recorded in PMOVSCLR_EL0[0-30], * occurs on the increment that changes * PMEVCNTR_EL0[63] from 1 to 0, when ARMv8.5-PMU is * implemented. This bit is RES0 in versions of the * architecture earlier than ARMv8.5, setting it to 1 * doesn't have any effect on them. * * MDCR_EL2.TTRF: Set to zero so that access to Trace * Filter Control register TRFCR_EL1 at EL1 is not * trapped to EL2. This bit is RES0 in versions of * the architecture earlier than ARMv8.4. * * MDCR_EL2.HPMD: Set to one so that event counting is * prohibited at EL2. This bit is RES0 in versions of * the architecture earlier than ARMv8.1, setting it * to 1 doesn't have any effect on them. * * MDCR_EL2.TPMS: Set to zero so that accesses to * Statistical Profiling control registers from EL1 * do not trap to EL2. This bit is RES0 when SPE is * not implemented. * * MDCR_EL2.TDRA: Set to zero so that Non-secure EL0 and * EL1 System register accesses to the Debug ROM * registers are not trapped to EL2. * * MDCR_EL2.TDOSA: Set to zero so that Non-secure EL1 * System register accesses to the powerdown debug * registers are not trapped to EL2. * * MDCR_EL2.TDA: Set to zero so that System register * accesses to the debug registers do not trap to EL2. * * MDCR_EL2.TDE: Set to zero so that debug exceptions * are not routed to EL2. * * MDCR_EL2.HPME: Set to zero to disable EL2 Performance * Monitors. * * MDCR_EL2.TPM: Set to zero so that Non-secure EL0 and * EL1 accesses to all Performance Monitors registers * are not trapped to EL2. * * MDCR_EL2.TPMCR: Set to zero so that Non-secure EL0 * and EL1 accesses to the PMCR_EL0 or PMCR are not * trapped to EL2. * * MDCR_EL2.HPMN: Set to value of PMCR_EL0.N which is the * architecturally-defined reset value. */ mdcr_el2 = ((MDCR_EL2_RESET_VAL | MDCR_EL2_HLP | MDCR_EL2_HPMD) | ((read_pmcr_el0() & PMCR_EL0_N_BITS) >> PMCR_EL0_N_SHIFT)) & ~(MDCR_EL2_TTRF | MDCR_EL2_TPMS | MDCR_EL2_TDRA_BIT | MDCR_EL2_TDOSA_BIT | MDCR_EL2_TDA_BIT | MDCR_EL2_TDE_BIT | MDCR_EL2_HPME_BIT | MDCR_EL2_TPM_BIT | MDCR_EL2_TPMCR_BIT); write_mdcr_el2(mdcr_el2); /* * Initialise HSTR_EL2. All fields are architecturally * UNKNOWN on reset. * * HSTR_EL2.T: Set all these fields to zero so that * Non-secure EL0 or EL1 accesses to System registers * do not trap to EL2. */ write_hstr_el2(HSTR_EL2_RESET_VAL & ~(HSTR_EL2_T_MASK)); /* * Initialise CNTHP_CTL_EL2. All fields are * architecturally UNKNOWN on reset. * * CNTHP_CTL_EL2:ENABLE: Set to zero to disable the EL2 * physical timer and prevent timer interrupts. */ write_cnthp_ctl_el2(CNTHP_CTL_RESET_VAL & ~(CNTHP_CTL_ENABLE_BIT)); } enable_extensions_nonsecure(el2_unused); } cm_el1_sysregs_context_restore(security_state); cm_set_next_eret_context(security_state); } /******************************************************************************* * The next four functions are used by runtime services to save and restore * EL1 context on the 'cpu_context' structure for the specified security * state. ******************************************************************************/ void cm_el1_sysregs_context_save(uint32_t security_state) { cpu_context_t *ctx; ctx = cm_get_context(security_state); assert(ctx != NULL); el1_sysregs_context_save(get_sysregs_ctx(ctx)); #if IMAGE_BL31 if (security_state == SECURE) PUBLISH_EVENT(cm_exited_secure_world); else PUBLISH_EVENT(cm_exited_normal_world); #endif } void cm_el1_sysregs_context_restore(uint32_t security_state) { cpu_context_t *ctx; ctx = cm_get_context(security_state); assert(ctx != NULL); el1_sysregs_context_restore(get_sysregs_ctx(ctx)); #if IMAGE_BL31 if (security_state == SECURE) PUBLISH_EVENT(cm_entering_secure_world); else PUBLISH_EVENT(cm_entering_normal_world); #endif } /******************************************************************************* * This function populates ELR_EL3 member of 'cpu_context' pertaining to the * given security state with the given entrypoint ******************************************************************************/ void cm_set_elr_el3(uint32_t security_state, uintptr_t entrypoint) { cpu_context_t *ctx; el3_state_t *state; ctx = cm_get_context(security_state); assert(ctx != NULL); /* Populate EL3 state so that ERET jumps to the correct entry */ state = get_el3state_ctx(ctx); write_ctx_reg(state, CTX_ELR_EL3, entrypoint); } /******************************************************************************* * This function populates ELR_EL3 and SPSR_EL3 members of 'cpu_context' * pertaining to the given security state ******************************************************************************/ void cm_set_elr_spsr_el3(uint32_t security_state, uintptr_t entrypoint, uint32_t spsr) { cpu_context_t *ctx; el3_state_t *state; ctx = cm_get_context(security_state); assert(ctx != NULL); /* Populate EL3 state so that ERET jumps to the correct entry */ state = get_el3state_ctx(ctx); write_ctx_reg(state, CTX_ELR_EL3, entrypoint); write_ctx_reg(state, CTX_SPSR_EL3, spsr); } /******************************************************************************* * This function updates a single bit in the SCR_EL3 member of the 'cpu_context' * pertaining to the given security state using the value and bit position * specified in the parameters. It preserves all other bits. ******************************************************************************/ void cm_write_scr_el3_bit(uint32_t security_state, uint32_t bit_pos, uint32_t value) { cpu_context_t *ctx; el3_state_t *state; uint32_t scr_el3; ctx = cm_get_context(security_state); assert(ctx != NULL); /* Ensure that the bit position is a valid one */ assert(((1U << bit_pos) & SCR_VALID_BIT_MASK) != 0U); /* Ensure that the 'value' is only a bit wide */ assert(value <= 1U); /* * Get the SCR_EL3 value from the cpu context, clear the desired bit * and set it to its new value. */ state = get_el3state_ctx(ctx); scr_el3 = (uint32_t)read_ctx_reg(state, CTX_SCR_EL3); scr_el3 &= ~(1U << bit_pos); scr_el3 |= value << bit_pos; write_ctx_reg(state, CTX_SCR_EL3, scr_el3); } /******************************************************************************* * This function retrieves SCR_EL3 member of 'cpu_context' pertaining to the * given security state. ******************************************************************************/ uint32_t cm_get_scr_el3(uint32_t security_state) { cpu_context_t *ctx; el3_state_t *state; ctx = cm_get_context(security_state); assert(ctx != NULL); /* Populate EL3 state so that ERET jumps to the correct entry */ state = get_el3state_ctx(ctx); return (uint32_t)read_ctx_reg(state, CTX_SCR_EL3); } /******************************************************************************* * This function is used to program the context that's used for exception * return. This initializes the SP_EL3 to a pointer to a 'cpu_context' set for * the required security state ******************************************************************************/ void cm_set_next_eret_context(uint32_t security_state) { cpu_context_t *ctx; ctx = cm_get_context(security_state); assert(ctx != NULL); cm_set_next_context(ctx); } trusted-firmware-a-2.2/lib/el3_runtime/aarch64/cpu_data.S000066400000000000000000000024321355360272700232420ustar00rootroot00000000000000/* * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .globl init_cpu_data_ptr .globl _cpu_data_by_index /* ----------------------------------------------------------------- * void init_cpu_data_ptr(void) * * Initialise the TPIDR_EL3 register to refer to the cpu_data_t * for the calling CPU. This must be called before cm_get_cpu_data() * * This can be called without a valid stack. It assumes that * plat_my_core_pos() does not clobber register x10. * clobbers: x0, x1, x10 * ----------------------------------------------------------------- */ func init_cpu_data_ptr mov x10, x30 bl plat_my_core_pos bl _cpu_data_by_index msr tpidr_el3, x0 ret x10 endfunc init_cpu_data_ptr /* ----------------------------------------------------------------- * cpu_data_t *_cpu_data_by_index(uint32_t cpu_index) * * Return the cpu_data structure for the CPU with given linear index * * This can be called without a valid stack. * clobbers: x0, x1 * ----------------------------------------------------------------- */ func _cpu_data_by_index mov_imm x1, CPU_DATA_SIZE mul x0, x0, x1 adr x1, percpu_data add x0, x0, x1 ret endfunc _cpu_data_by_index trusted-firmware-a-2.2/lib/el3_runtime/cpu_data_array.c000066400000000000000000000004721355360272700232320ustar00rootroot00000000000000/* * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /* The per_cpu_ptr_cache_t space allocation */ cpu_data_t percpu_data[PLATFORM_CORE_COUNT]; trusted-firmware-a-2.2/lib/extensions/000077500000000000000000000000001355360272700200565ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/extensions/amu/000077500000000000000000000000001355360272700206405ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/extensions/amu/aarch32/000077500000000000000000000000001355360272700220635ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/extensions/amu/aarch32/amu.c000066400000000000000000000075221355360272700230170ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #define AMU_GROUP0_NR_COUNTERS 4 struct amu_ctx { uint64_t group0_cnts[AMU_GROUP0_NR_COUNTERS]; uint64_t group1_cnts[AMU_GROUP1_NR_COUNTERS]; }; static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT]; bool amu_supported(void) { uint64_t features; features = read_id_pfr0() >> ID_PFR0_AMU_SHIFT; return (features & ID_PFR0_AMU_MASK) == 1U; } void amu_enable(bool el2_unused) { if (!amu_supported()) return; if (el2_unused) { uint64_t v; /* * Non-secure access from EL0 or EL1 to the Activity Monitor * registers do not trap to EL2. */ v = read_hcptr(); v &= ~TAM_BIT; write_hcptr(v); } /* Enable group 0 counters */ write_amcntenset0(AMU_GROUP0_COUNTERS_MASK); /* Enable group 1 counters */ write_amcntenset1(AMU_GROUP1_COUNTERS_MASK); } /* Read the group 0 counter identified by the given `idx`. */ uint64_t amu_group0_cnt_read(int idx) { assert(amu_supported()); assert((idx >= 0) && (idx < AMU_GROUP0_NR_COUNTERS)); return amu_group0_cnt_read_internal(idx); } /* Write the group 0 counter identified by the given `idx` with `val`. */ void amu_group0_cnt_write(int idx, uint64_t val) { assert(amu_supported()); assert((idx >= 0) && (idx < AMU_GROUP0_NR_COUNTERS)); amu_group0_cnt_write_internal(idx, val); isb(); } /* Read the group 1 counter identified by the given `idx`. */ uint64_t amu_group1_cnt_read(int idx) { assert(amu_supported()); assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS)); return amu_group1_cnt_read_internal(idx); } /* Write the group 1 counter identified by the given `idx` with `val`. */ void amu_group1_cnt_write(int idx, uint64_t val) { assert(amu_supported()); assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS)); amu_group1_cnt_write_internal(idx, val); isb(); } void amu_group1_set_evtype(int idx, unsigned int val) { assert(amu_supported()); assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS)); amu_group1_set_evtype_internal(idx, val); isb(); } static void *amu_context_save(const void *arg) { struct amu_ctx *ctx; int i; if (!amu_supported()) return (void *)-1; ctx = &amu_ctxs[plat_my_core_pos()]; /* Assert that group 0 counter configuration is what we expect */ assert(read_amcntenset0() == AMU_GROUP0_COUNTERS_MASK && read_amcntenset1() == AMU_GROUP1_COUNTERS_MASK); /* * Disable group 0 counters to avoid other observers like SCP sampling * counter values from the future via the memory mapped view. */ write_amcntenclr0(AMU_GROUP0_COUNTERS_MASK); write_amcntenclr1(AMU_GROUP1_COUNTERS_MASK); isb(); for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) ctx->group0_cnts[i] = amu_group0_cnt_read(i); for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++) ctx->group1_cnts[i] = amu_group1_cnt_read(i); return (void *)0; } static void *amu_context_restore(const void *arg) { struct amu_ctx *ctx; int i; if (!amu_supported()) return (void *)-1; ctx = &amu_ctxs[plat_my_core_pos()]; /* Counters were disabled in `amu_context_save()` */ assert((read_amcntenset0() == 0U) && (read_amcntenset1() == 0U)); /* Restore group 0 counters */ for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) amu_group0_cnt_write(i, ctx->group0_cnts[i]); for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++) amu_group1_cnt_write(i, ctx->group1_cnts[i]); /* Enable group 0 counters */ write_amcntenset0(AMU_GROUP0_COUNTERS_MASK); /* Enable group 1 counters */ write_amcntenset1(AMU_GROUP1_COUNTERS_MASK); return (void *)0; } SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save); SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore); trusted-firmware-a-2.2/lib/extensions/amu/aarch32/amu_helpers.S000066400000000000000000000140651355360272700245210ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl amu_group0_cnt_read_internal .globl amu_group0_cnt_write_internal .globl amu_group1_cnt_read_internal .globl amu_group1_cnt_write_internal .globl amu_group1_set_evtype_internal /* * uint64_t amu_group0_cnt_read_internal(int idx); * * Given `idx`, read the corresponding AMU counter * and return it in `r0` and `r1`. */ func amu_group0_cnt_read_internal #if ENABLE_ASSERTIONS /* `idx` should be between [0, 3] */ mov r1, r0 lsr r1, r1, #2 cmp r1, #0 ASM_ASSERT(eq) #endif /* * Given `idx` calculate address of ldcopr16/bx lr instruction pair * in the table below. */ adr r1, 1f lsl r0, r0, #3 /* each ldcopr16/bx lr sequence is 8 bytes */ add r1, r1, r0 bx r1 1: ldcopr16 r0, r1, AMEVCNTR00 /* index 0 */ bx lr ldcopr16 r0, r1, AMEVCNTR01 /* index 1 */ bx lr ldcopr16 r0, r1, AMEVCNTR02 /* index 2 */ bx lr ldcopr16 r0, r1, AMEVCNTR03 /* index 3 */ bx lr endfunc amu_group0_cnt_read_internal /* * void amu_group0_cnt_write_internal(int idx, uint64_t val); * * Given `idx`, write `val` to the corresponding AMU counter. * `idx` is passed in `r0` and `val` is passed in `r2` and `r3`. * `r1` is used as a scratch register. */ func amu_group0_cnt_write_internal #if ENABLE_ASSERTIONS /* `idx` should be between [0, 3] */ mov r1, r0 lsr r1, r1, #2 cmp r1, #0 ASM_ASSERT(eq) #endif /* * Given `idx` calculate address of stcopr16/bx lr instruction pair * in the table below. */ adr r1, 1f lsl r0, r0, #3 /* each stcopr16/bx lr sequence is 8 bytes */ add r1, r1, r0 bx r1 1: stcopr16 r2, r3, AMEVCNTR00 /* index 0 */ bx lr stcopr16 r2, r3, AMEVCNTR01 /* index 1 */ bx lr stcopr16 r2, r3, AMEVCNTR02 /* index 2 */ bx lr stcopr16 r2, r3, AMEVCNTR03 /* index 3 */ bx lr endfunc amu_group0_cnt_write_internal /* * uint64_t amu_group1_cnt_read_internal(int idx); * * Given `idx`, read the corresponding AMU counter * and return it in `r0` and `r1`. */ func amu_group1_cnt_read_internal #if ENABLE_ASSERTIONS /* `idx` should be between [0, 15] */ mov r1, r0 lsr r1, r1, #4 cmp r1, #0 ASM_ASSERT(eq) #endif /* * Given `idx` calculate address of ldcopr16/bx lr instruction pair * in the table below. */ adr r1, 1f lsl r0, r0, #3 /* each ldcopr16/bx lr sequence is 8 bytes */ add r1, r1, r0 bx r1 1: ldcopr16 r0, r1, AMEVCNTR10 /* index 0 */ bx lr ldcopr16 r0, r1, AMEVCNTR11 /* index 1 */ bx lr ldcopr16 r0, r1, AMEVCNTR12 /* index 2 */ bx lr ldcopr16 r0, r1, AMEVCNTR13 /* index 3 */ bx lr ldcopr16 r0, r1, AMEVCNTR14 /* index 4 */ bx lr ldcopr16 r0, r1, AMEVCNTR15 /* index 5 */ bx lr ldcopr16 r0, r1, AMEVCNTR16 /* index 6 */ bx lr ldcopr16 r0, r1, AMEVCNTR17 /* index 7 */ bx lr ldcopr16 r0, r1, AMEVCNTR18 /* index 8 */ bx lr ldcopr16 r0, r1, AMEVCNTR19 /* index 9 */ bx lr ldcopr16 r0, r1, AMEVCNTR1A /* index 10 */ bx lr ldcopr16 r0, r1, AMEVCNTR1B /* index 11 */ bx lr ldcopr16 r0, r1, AMEVCNTR1C /* index 12 */ bx lr ldcopr16 r0, r1, AMEVCNTR1D /* index 13 */ bx lr ldcopr16 r0, r1, AMEVCNTR1E /* index 14 */ bx lr ldcopr16 r0, r1, AMEVCNTR1F /* index 15 */ bx lr endfunc amu_group1_cnt_read_internal /* * void amu_group1_cnt_write_internal(int idx, uint64_t val); * * Given `idx`, write `val` to the corresponding AMU counter. * `idx` is passed in `r0` and `val` is passed in `r2` and `r3`. * `r1` is used as a scratch register. */ func amu_group1_cnt_write_internal #if ENABLE_ASSERTIONS /* `idx` should be between [0, 15] */ mov r1, r0 lsr r1, r1, #4 cmp r1, #0 ASM_ASSERT(eq) #endif /* * Given `idx` calculate address of ldcopr16/bx lr instruction pair * in the table below. */ adr r1, 1f lsl r0, r0, #3 /* each stcopr16/bx lr sequence is 8 bytes */ add r1, r1, r0 bx r1 1: stcopr16 r2, r3, AMEVCNTR10 /* index 0 */ bx lr stcopr16 r2, r3, AMEVCNTR11 /* index 1 */ bx lr stcopr16 r2, r3, AMEVCNTR12 /* index 2 */ bx lr stcopr16 r2, r3, AMEVCNTR13 /* index 3 */ bx lr stcopr16 r2, r3, AMEVCNTR14 /* index 4 */ bx lr stcopr16 r2, r3, AMEVCNTR15 /* index 5 */ bx lr stcopr16 r2, r3, AMEVCNTR16 /* index 6 */ bx lr stcopr16 r2, r3, AMEVCNTR17 /* index 7 */ bx lr stcopr16 r2, r3, AMEVCNTR18 /* index 8 */ bx lr stcopr16 r2, r3, AMEVCNTR19 /* index 9 */ bx lr stcopr16 r2, r3, AMEVCNTR1A /* index 10 */ bx lr stcopr16 r2, r3, AMEVCNTR1B /* index 11 */ bx lr stcopr16 r2, r3, AMEVCNTR1C /* index 12 */ bx lr stcopr16 r2, r3, AMEVCNTR1D /* index 13 */ bx lr stcopr16 r2, r3, AMEVCNTR1E /* index 14 */ bx lr stcopr16 r2, r3, AMEVCNTR1F /* index 15 */ bx lr endfunc amu_group1_cnt_write_internal /* * void amu_group1_set_evtype_internal(int idx, unsigned int val); * * Program the AMU event type register indexed by `idx` * with the value `val`. */ func amu_group1_set_evtype_internal #if ENABLE_ASSERTIONS /* `idx` should be between [0, 15] */ mov r2, r0 lsr r2, r2, #4 cmp r2, #0 ASM_ASSERT(eq) /* val should be between [0, 65535] */ mov r2, r1 lsr r2, r2, #16 cmp r2, #0 ASM_ASSERT(eq) #endif /* * Given `idx` calculate address of stcopr/bx lr instruction pair * in the table below. */ adr r2, 1f lsl r0, r0, #3 /* each stcopr/bx lr sequence is 8 bytes */ add r2, r2, r0 bx r2 1: stcopr r1, AMEVTYPER10 /* index 0 */ bx lr stcopr r1, AMEVTYPER11 /* index 1 */ bx lr stcopr r1, AMEVTYPER12 /* index 2 */ bx lr stcopr r1, AMEVTYPER13 /* index 3 */ bx lr stcopr r1, AMEVTYPER14 /* index 4 */ bx lr stcopr r1, AMEVTYPER15 /* index 5 */ bx lr stcopr r1, AMEVTYPER16 /* index 6 */ bx lr stcopr r1, AMEVTYPER17 /* index 7 */ bx lr stcopr r1, AMEVTYPER18 /* index 8 */ bx lr stcopr r1, AMEVTYPER19 /* index 9 */ bx lr stcopr r1, AMEVTYPER1A /* index 10 */ bx lr stcopr r1, AMEVTYPER1B /* index 11 */ bx lr stcopr r1, AMEVTYPER1C /* index 12 */ bx lr stcopr r1, AMEVTYPER1D /* index 13 */ bx lr stcopr r1, AMEVTYPER1E /* index 14 */ bx lr stcopr r1, AMEVTYPER1F /* index 15 */ bx lr endfunc amu_group1_set_evtype_internal trusted-firmware-a-2.2/lib/extensions/amu/aarch64/000077500000000000000000000000001355360272700220705ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/extensions/amu/aarch64/amu.c000066400000000000000000000112751355360272700230240ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #define AMU_GROUP0_NR_COUNTERS 4 struct amu_ctx { uint64_t group0_cnts[AMU_GROUP0_NR_COUNTERS]; uint64_t group1_cnts[AMU_GROUP1_NR_COUNTERS]; }; static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT]; bool amu_supported(void) { uint64_t features; features = read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT; return (features & ID_AA64PFR0_AMU_MASK) == 1U; } /* * Enable counters. This function is meant to be invoked * by the context management library before exiting from EL3. */ void amu_enable(bool el2_unused) { uint64_t v; if (!amu_supported()) return; if (el2_unused) { /* * CPTR_EL2.TAM: Set to zero so any accesses to * the Activity Monitor registers do not trap to EL2. */ v = read_cptr_el2(); v &= ~CPTR_EL2_TAM_BIT; write_cptr_el2(v); } /* * CPTR_EL3.TAM: Set to zero so that any accesses to * the Activity Monitor registers do not trap to EL3. */ v = read_cptr_el3(); v &= ~TAM_BIT; write_cptr_el3(v); /* Enable group 0 counters */ write_amcntenset0_el0(AMU_GROUP0_COUNTERS_MASK); /* Enable group 1 counters */ write_amcntenset1_el0(AMU_GROUP1_COUNTERS_MASK); } /* Read the group 0 counter identified by the given `idx`. */ uint64_t amu_group0_cnt_read(int idx) { assert(amu_supported()); assert((idx >= 0) && (idx < AMU_GROUP0_NR_COUNTERS)); return amu_group0_cnt_read_internal(idx); } /* Write the group 0 counter identified by the given `idx` with `val`. */ void amu_group0_cnt_write(int idx, uint64_t val) { assert(amu_supported()); assert((idx >= 0) && (idx < AMU_GROUP0_NR_COUNTERS)); amu_group0_cnt_write_internal(idx, val); isb(); } /* Read the group 1 counter identified by the given `idx`. */ uint64_t amu_group1_cnt_read(int idx) { assert(amu_supported()); assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS)); return amu_group1_cnt_read_internal(idx); } /* Write the group 1 counter identified by the given `idx` with `val`. */ void amu_group1_cnt_write(int idx, uint64_t val) { assert(amu_supported()); assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS)); amu_group1_cnt_write_internal(idx, val); isb(); } /* * Program the event type register for the given `idx` with * the event number `val`. */ void amu_group1_set_evtype(int idx, unsigned int val) { assert(amu_supported()); assert((idx >= 0) && (idx < AMU_GROUP1_NR_COUNTERS)); amu_group1_set_evtype_internal(idx, val); isb(); } static void *amu_context_save(const void *arg) { struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()]; int i; if (!amu_supported()) return (void *)-1; /* Assert that group 0/1 counter configuration is what we expect */ assert((read_amcntenset0_el0() == AMU_GROUP0_COUNTERS_MASK) && (read_amcntenset1_el0() == AMU_GROUP1_COUNTERS_MASK)); assert(((sizeof(int) * 8) - __builtin_clz(AMU_GROUP1_COUNTERS_MASK)) <= AMU_GROUP1_NR_COUNTERS); /* * Disable group 0/1 counters to avoid other observers like SCP sampling * counter values from the future via the memory mapped view. */ write_amcntenclr0_el0(AMU_GROUP0_COUNTERS_MASK); write_amcntenclr1_el0(AMU_GROUP1_COUNTERS_MASK); isb(); /* Save group 0 counters */ for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) ctx->group0_cnts[i] = amu_group0_cnt_read(i); /* Save group 1 counters */ for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++) ctx->group1_cnts[i] = amu_group1_cnt_read(i); return (void *)0; } static void *amu_context_restore(const void *arg) { struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()]; int i; if (!amu_supported()) return (void *)-1; /* Counters were disabled in `amu_context_save()` */ assert((read_amcntenset0_el0() == 0U) && (read_amcntenset1_el0() == 0U)); assert(((sizeof(int) * 8U) - __builtin_clz(AMU_GROUP1_COUNTERS_MASK)) <= AMU_GROUP1_NR_COUNTERS); /* Restore group 0 counters */ for (i = 0; i < AMU_GROUP0_NR_COUNTERS; i++) if ((AMU_GROUP0_COUNTERS_MASK & (1U << i)) != 0U) amu_group0_cnt_write(i, ctx->group0_cnts[i]); /* Restore group 1 counters */ for (i = 0; i < AMU_GROUP1_NR_COUNTERS; i++) if ((AMU_GROUP1_COUNTERS_MASK & (1U << i)) != 0U) amu_group1_cnt_write(i, ctx->group1_cnts[i]); /* Restore group 0/1 counter configuration */ write_amcntenset0_el0(AMU_GROUP0_COUNTERS_MASK); write_amcntenset1_el0(AMU_GROUP1_COUNTERS_MASK); return (void *)0; } SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save); SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore); trusted-firmware-a-2.2/lib/extensions/amu/aarch64/amu_helpers.S000066400000000000000000000131631355360272700245240ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl amu_group0_cnt_read_internal .globl amu_group0_cnt_write_internal .globl amu_group1_cnt_read_internal .globl amu_group1_cnt_write_internal .globl amu_group1_set_evtype_internal /* * uint64_t amu_group0_cnt_read_internal(int idx); * * Given `idx`, read the corresponding AMU counter * and return it in `x0`. */ func amu_group0_cnt_read_internal adr x1, 1f #if ENABLE_ASSERTIONS /* * It can be dangerous to call this function with an * out of bounds index. Ensure `idx` is valid. */ tst x0, #~3 ASM_ASSERT(eq) #endif /* * Given `idx` calculate address of mrs/ret instruction pair * in the table below. */ add x1, x1, x0, lsl #3 /* each mrs/ret sequence is 8 bytes */ #if ENABLE_BTI add x1, x1, x0, lsl #2 /* + "bti j" instruction */ #endif br x1 1: read AMEVCNTR00_EL0 /* index 0 */ read AMEVCNTR01_EL0 /* index 1 */ read AMEVCNTR02_EL0 /* index 2 */ read AMEVCNTR03_EL0 /* index 3 */ endfunc amu_group0_cnt_read_internal /* * void amu_group0_cnt_write_internal(int idx, uint64_t val); * * Given `idx`, write `val` to the corresponding AMU counter. */ func amu_group0_cnt_write_internal adr x2, 1f #if ENABLE_ASSERTIONS /* * It can be dangerous to call this function with an * out of bounds index. Ensure `idx` is valid. */ tst x0, #~3 ASM_ASSERT(eq) #endif /* * Given `idx` calculate address of mrs/ret instruction pair * in the table below. */ add x2, x2, x0, lsl #3 /* each msr/ret sequence is 8 bytes */ #if ENABLE_BTI add x2, x2, x0, lsl #2 /* + "bti j" instruction */ #endif br x2 1: write AMEVCNTR00_EL0 /* index 0 */ write AMEVCNTR01_EL0 /* index 1 */ write AMEVCNTR02_EL0 /* index 2 */ write AMEVCNTR03_EL0 /* index 3 */ endfunc amu_group0_cnt_write_internal /* * uint64_t amu_group1_cnt_read_internal(int idx); * * Given `idx`, read the corresponding AMU counter * and return it in `x0`. */ func amu_group1_cnt_read_internal adr x1, 1f #if ENABLE_ASSERTIONS /* * It can be dangerous to call this function with an * out of bounds index. Ensure `idx` is valid. */ tst x0, #~0xF ASM_ASSERT(eq) #endif /* * Given `idx` calculate address of mrs/ret instruction pair * in the table below. */ add x1, x1, x0, lsl #3 /* each mrs/ret sequence is 8 bytes */ #if ENABLE_BTI add x1, x1, x0, lsl #2 /* + "bti j" instruction */ #endif br x1 1: read AMEVCNTR10_EL0 /* index 0 */ read AMEVCNTR11_EL0 /* index 1 */ read AMEVCNTR12_EL0 /* index 2 */ read AMEVCNTR13_EL0 /* index 3 */ read AMEVCNTR14_EL0 /* index 4 */ read AMEVCNTR15_EL0 /* index 5 */ read AMEVCNTR16_EL0 /* index 6 */ read AMEVCNTR17_EL0 /* index 7 */ read AMEVCNTR18_EL0 /* index 8 */ read AMEVCNTR19_EL0 /* index 9 */ read AMEVCNTR1A_EL0 /* index 10 */ read AMEVCNTR1B_EL0 /* index 11 */ read AMEVCNTR1C_EL0 /* index 12 */ read AMEVCNTR1D_EL0 /* index 13 */ read AMEVCNTR1E_EL0 /* index 14 */ read AMEVCNTR1F_EL0 /* index 15 */ endfunc amu_group1_cnt_read_internal /* * void amu_group1_cnt_write_internal(int idx, uint64_t val); * * Given `idx`, write `val` to the corresponding AMU counter. */ func amu_group1_cnt_write_internal adr x2, 1f #if ENABLE_ASSERTIONS /* * It can be dangerous to call this function with an * out of bounds index. Ensure `idx` is valid. */ tst x0, #~0xF ASM_ASSERT(eq) #endif /* * Given `idx` calculate address of mrs/ret instruction pair * in the table below. */ add x2, x2, x0, lsl #3 /* each msr/ret sequence is 8 bytes */ #if ENABLE_BTI add x2, x2, x0, lsl #2 /* + "bti j" instruction */ #endif br x2 1: write AMEVCNTR10_EL0 /* index 0 */ write AMEVCNTR11_EL0 /* index 1 */ write AMEVCNTR12_EL0 /* index 2 */ write AMEVCNTR13_EL0 /* index 3 */ write AMEVCNTR14_EL0 /* index 4 */ write AMEVCNTR15_EL0 /* index 5 */ write AMEVCNTR16_EL0 /* index 6 */ write AMEVCNTR17_EL0 /* index 7 */ write AMEVCNTR18_EL0 /* index 8 */ write AMEVCNTR19_EL0 /* index 9 */ write AMEVCNTR1A_EL0 /* index 10 */ write AMEVCNTR1B_EL0 /* index 11 */ write AMEVCNTR1C_EL0 /* index 12 */ write AMEVCNTR1D_EL0 /* index 13 */ write AMEVCNTR1E_EL0 /* index 14 */ write AMEVCNTR1F_EL0 /* index 15 */ endfunc amu_group1_cnt_write_internal /* * void amu_group1_set_evtype_internal(int idx, unsigned int val); * * Program the AMU event type register indexed by `idx` * with the value `val`. */ func amu_group1_set_evtype_internal adr x2, 1f #if ENABLE_ASSERTIONS /* * It can be dangerous to call this function with an * out of bounds index. Ensure `idx` is valid. */ tst x0, #~0xF ASM_ASSERT(eq) /* val should be between [0, 65535] */ tst x1, #~0xFFFF ASM_ASSERT(eq) #endif /* * Given `idx` calculate address of msr/ret instruction pair * in the table below. */ add x2, x2, x0, lsl #3 /* each msr/ret sequence is 8 bytes */ #if ENABLE_BTI add x2, x2, x0, lsl #2 /* + "bti j" instruction */ #endif br x2 1: write AMEVTYPER10_EL0 /* index 0 */ write AMEVTYPER11_EL0 /* index 1 */ write AMEVTYPER12_EL0 /* index 2 */ write AMEVTYPER13_EL0 /* index 3 */ write AMEVTYPER14_EL0 /* index 4 */ write AMEVTYPER15_EL0 /* index 5 */ write AMEVTYPER16_EL0 /* index 6 */ write AMEVTYPER17_EL0 /* index 7 */ write AMEVTYPER18_EL0 /* index 8 */ write AMEVTYPER19_EL0 /* index 9 */ write AMEVTYPER1A_EL0 /* index 10 */ write AMEVTYPER1B_EL0 /* index 11 */ write AMEVTYPER1C_EL0 /* index 12 */ write AMEVTYPER1D_EL0 /* index 13 */ write AMEVTYPER1E_EL0 /* index 14 */ write AMEVTYPER1F_EL0 /* index 15 */ endfunc amu_group1_set_evtype_internal trusted-firmware-a-2.2/lib/extensions/mpam/000077500000000000000000000000001355360272700210105ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/extensions/mpam/mpam.c000066400000000000000000000021231355360272700221040ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include bool mpam_supported(void) { uint64_t features = read_id_aa64dfr0_el1() >> ID_AA64PFR0_MPAM_SHIFT; return ((features & ID_AA64PFR0_MPAM_MASK) != 0U); } void mpam_enable(bool el2_unused) { if (!mpam_supported()) return; /* * Enable MPAM, and disable trapping to EL3 when lower ELs access their * own MPAM registers. */ write_mpam3_el3(MPAM3_EL3_MPAMEN_BIT); /* * If EL2 is implemented but unused, disable trapping to EL2 when lower * ELs access their own MPAM registers. * If EL2 is implemented and used, enable trapping to EL2. */ if (el2_unused) { write_mpam2_el2(0); if ((read_mpamidr_el1() & MPAMIDR_HAS_HCR_BIT) != 0U) write_mpamhcr_el2(0); } else { write_mpam2_el2(MPAM2_EL2_TRAPMPAM0EL1 | MPAM2_EL2_TRAPMPAM1EL1); if ((read_mpamidr_el1() & MPAMIDR_HAS_HCR_BIT) != 0U) { write_mpamhcr_el2(MPAMHCR_EL2_TRAP_MPAMIDR_EL1); } } } trusted-firmware-a-2.2/lib/extensions/pauth/000077500000000000000000000000001355360272700211775ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/extensions/pauth/pauth_helpers.S000066400000000000000000000066261355360272700242000ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .global pauth_init_enable_el1 .global pauth_disable_el1 .global pauth_init_enable_el3 .global pauth_disable_el3 .globl pauth_load_bl31_apiakey .globl pauth_load_bl1_apiakey_enable /* ------------------------------------------------------------- * Program APIAKey_EL1 and enable pointer authentication in EL1 * ------------------------------------------------------------- */ func pauth_init_enable_el1 stp x29, x30, [sp, #-16]! /* Initialize platform key */ bl plat_init_apkey /* Program instruction key A used by the Trusted Firmware */ msr APIAKeyLo_EL1, x0 msr APIAKeyHi_EL1, x1 /* Enable pointer authentication */ mrs x0, sctlr_el1 orr x0, x0, #SCTLR_EnIA_BIT #if ENABLE_BTI /* Enable PAC branch type compatibility */ bic x0, x0, #(SCTLR_BT0_BIT | SCTLR_BT1_BIT) #endif msr sctlr_el1, x0 isb ldp x29, x30, [sp], #16 ret endfunc pauth_init_enable_el1 /* ------------------------------------------------------------- * Disable pointer authentication in EL3 * ------------------------------------------------------------- */ func pauth_disable_el1 mrs x0, sctlr_el1 bic x0, x0, #SCTLR_EnIA_BIT msr sctlr_el1, x0 isb ret endfunc pauth_disable_el1 /* ------------------------------------------------------------- * Program APIAKey_EL1 and enable pointer authentication in EL3 * ------------------------------------------------------------- */ func pauth_init_enable_el3 stp x29, x30, [sp, #-16]! /* Initialize platform key */ bl plat_init_apkey /* Program instruction key A used by the Trusted Firmware */ msr APIAKeyLo_EL1, x0 msr APIAKeyHi_EL1, x1 /* Enable pointer authentication */ mrs x0, sctlr_el3 orr x0, x0, #SCTLR_EnIA_BIT #if ENABLE_BTI /* Enable PAC branch type compatibility */ bic x0, x0, #SCTLR_BT_BIT #endif msr sctlr_el3, x0 isb ldp x29, x30, [sp], #16 ret endfunc pauth_init_enable_el3 /* ------------------------------------------------------------- * Disable pointer authentication in EL3 * ------------------------------------------------------------- */ func pauth_disable_el3 mrs x0, sctlr_el3 bic x0, x0, #SCTLR_EnIA_BIT msr sctlr_el3, x0 isb ret endfunc pauth_disable_el3 /* ------------------------------------------------------------- * The following functions strictly follow the AArch64 PCS * to use x9-x17 (temporary caller-saved registers) to load * the APIAKey_EL1 and enable pointer authentication. * ------------------------------------------------------------- */ func pauth_load_bl31_apiakey /* tpidr_el3 contains the address of cpu_data structure */ mrs x9, tpidr_el3 /* Load apiakey from cpu_data */ ldp x10, x11, [x9, #CPU_DATA_APIAKEY_OFFSET] /* Program instruction key A */ msr APIAKeyLo_EL1, x10 msr APIAKeyHi_EL1, x11 isb ret endfunc pauth_load_bl31_apiakey func pauth_load_bl1_apiakey_enable /* Load instruction key A used by the Trusted Firmware */ adrp x9, bl1_apiakey add x9, x9, :lo12:bl1_apiakey ldp x10, x11, [x9] /* Program instruction key A */ msr APIAKeyLo_EL1, x10 msr APIAKeyHi_EL1, x11 /* Enable pointer authentication */ mrs x9, sctlr_el3 orr x9, x9, #SCTLR_EnIA_BIT #if ENABLE_BTI /* Enable PAC branch type compatibility */ bic x9, x9, #SCTLR_BT_BIT #endif msr sctlr_el3, x9 isb ret endfunc pauth_load_bl1_apiakey_enable trusted-firmware-a-2.2/lib/extensions/ras/000077500000000000000000000000001355360272700206435ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/extensions/ras/ras_common.c000066400000000000000000000064421355360272700231520ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #ifndef PLAT_RAS_PRI # error Platform must define RAS priority value #endif /* Handler that receives External Aborts on RAS-capable systems */ int ras_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie, void *handle, uint64_t flags) { unsigned int i, n_handled = 0; int probe_data, ret; struct err_record_info *info; const struct err_handler_data err_data = { .version = ERR_HANDLER_VERSION, .ea_reason = ea_reason, .interrupt = 0, .syndrome = (uint32_t) syndrome, .flags = flags, .cookie = cookie, .handle = handle }; for_each_err_record_info(i, info) { assert(info->probe != NULL); assert(info->handler != NULL); /* Continue probing until the record group signals no error */ while (true) { if (info->probe(info, &probe_data) == 0) break; /* Handle error */ ret = info->handler(info, probe_data, &err_data); if (ret != 0) return ret; n_handled++; } } return (n_handled != 0U) ? 1 : 0; } #if ENABLE_ASSERTIONS static void assert_interrupts_sorted(void) { unsigned int i, last; struct ras_interrupt *start = ras_interrupt_mappings.intrs; if (ras_interrupt_mappings.num_intrs == 0UL) return; last = start[0].intr_number; for (i = 1; i < ras_interrupt_mappings.num_intrs; i++) { assert(start[i].intr_number > last); last = start[i].intr_number; } } #endif /* * Given an RAS interrupt number, locate the registered handler and call it. If * no handler was found for the interrupt number, this function panics. */ static int ras_interrupt_handler(uint32_t intr_raw, uint32_t flags, void *handle, void *cookie) { struct ras_interrupt *ras_inrs = ras_interrupt_mappings.intrs; struct ras_interrupt *selected = NULL; int probe_data = 0; int start, end, mid, ret __unused; const struct err_handler_data err_data = { .version = ERR_HANDLER_VERSION, .interrupt = intr_raw, .flags = flags, .cookie = cookie, .handle = handle }; assert(ras_interrupt_mappings.num_intrs > 0UL); start = 0; end = (int) ras_interrupt_mappings.num_intrs; while (start <= end) { mid = ((end + start) / 2); if (intr_raw == ras_inrs[mid].intr_number) { selected = &ras_inrs[mid]; break; } else if (intr_raw < ras_inrs[mid].intr_number) { /* Move left */ end = mid - 1; } else { /* Move right */ start = mid + 1; } } if (selected == NULL) { ERROR("RAS interrupt %u has no handler!\n", intr_raw); panic(); } if (selected->err_record->probe != NULL) { ret = selected->err_record->probe(selected->err_record, &probe_data); assert(ret != 0); } /* Call error handler for the record group */ assert(selected->err_record->handler != NULL); (void) selected->err_record->handler(selected->err_record, probe_data, &err_data); return 0; } void __init ras_init(void) { #if ENABLE_ASSERTIONS /* Check RAS interrupts are sorted */ assert_interrupts_sorted(); #endif /* Register RAS priority handler */ ehf_register_priority_handler(PLAT_RAS_PRI, ras_interrupt_handler); } trusted-firmware-a-2.2/lib/extensions/ras/std_err_record.c000066400000000000000000000042041355360272700240070ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /* * Probe for error in memory-mapped registers containing error records * implemented Standard Error Record format. Upon detecting an error, set probe * data to the index of the record in error, and return 1; otherwise, return 0. */ int ser_probe_memmap(uintptr_t base, unsigned int size_num_k, int *probe_data) { unsigned int num_records, num_group_regs, i; uint64_t gsr; assert(base != 0UL); /* Only 4K supported for now */ assert(size_num_k == STD_ERR_NODE_SIZE_NUM_K); num_records = (unsigned int) (mmio_read_32(ERR_DEVID(base, size_num_k)) & ERR_DEVID_MASK); /* A group register shows error status for 2^6 error records */ num_group_regs = (num_records >> 6U) + 1U; /* Iterate through group registers to find a record in error */ for (i = 0; i < num_group_regs; i++) { gsr = mmio_read_64(ERR_GSR(base, size_num_k, i)); if (gsr == 0ULL) continue; /* Return the index of the record in error */ if (probe_data != NULL) *probe_data = (((int) (i << 6U)) + __builtin_ctzll(gsr)); return 1; } return 0; } /* * Probe for error in System Registers where error records are implemented in * Standard Error Record format. Upon detecting an error, set probe data to the * index of the record in error, and return 1; otherwise, return 0. */ int ser_probe_sysreg(unsigned int idx_start, unsigned int num_idx, int *probe_data) { unsigned int i; uint64_t status; unsigned int max_idx __unused = ((unsigned int) read_erridr_el1()) & ERRIDR_MASK; assert(idx_start < max_idx); assert(check_u32_overflow(idx_start, num_idx) == 0); assert((idx_start + num_idx - 1U) < max_idx); for (i = 0; i < num_idx; i++) { /* Select the error record */ ser_sys_select_record(idx_start + i); /* Retrieve status register from the error record */ status = read_erxstatus_el1(); /* Check for valid field in status */ if (ERR_STATUS_GET_FIELD(status, V) != 0U) { if (probe_data != NULL) *probe_data = (int) i; return 1; } } return 0; } trusted-firmware-a-2.2/lib/extensions/spe/000077500000000000000000000000001355360272700206455ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/extensions/spe/spe.c000066400000000000000000000034431355360272700216040ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include static inline void psb_csync(void) { /* * The assembler does not yet understand the psb csync mnemonic * so use the equivalent hint instruction. */ __asm__ volatile("hint #17"); } bool spe_supported(void) { uint64_t features; features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT; return (features & ID_AA64DFR0_PMS_MASK) == 1U; } void spe_enable(bool el2_unused) { uint64_t v; if (!spe_supported()) return; if (el2_unused) { /* * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical * profiling controls to EL2. * * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure * state. Accesses to profiling buffer controls at * Non-secure EL1 are not trapped to EL2. */ v = read_mdcr_el2(); v &= ~MDCR_EL2_TPMS; v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1); write_mdcr_el2(v); } /* * MDCR_EL2.NSPB (ARM v8.2): SPE enabled in Non-secure state * and disabled in secure state. Accesses to SPE registers at * S-EL1 generate trap exceptions to EL3. */ v = read_mdcr_el3(); v |= MDCR_NSPB(MDCR_NSPB_EL1); write_mdcr_el3(v); } void spe_disable(void) { uint64_t v; if (!spe_supported()) return; /* Drain buffered data */ psb_csync(); dsbnsh(); /* Disable profiling buffer */ v = read_pmblimitr_el1(); v &= ~(1ULL << 0); write_pmblimitr_el1(v); isb(); } static void *spe_drain_buffers_hook(const void *arg) { if (!spe_supported()) return (void *)-1; /* Drain buffered data */ psb_csync(); dsbnsh(); return (void *)0; } SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook); trusted-firmware-a-2.2/lib/extensions/sve/000077500000000000000000000000001355360272700206535ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/extensions/sve/sve.c000066400000000000000000000057301355360272700216210ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include bool sve_supported(void) { uint64_t features; features = read_id_aa64pfr0_el1() >> ID_AA64PFR0_SVE_SHIFT; return (features & ID_AA64PFR0_SVE_MASK) == 1U; } static void *disable_sve_hook(const void *arg) { uint64_t cptr; if (!sve_supported()) return (void *)-1; /* * Disable SVE, SIMD and FP access for the Secure world. * As the SIMD/FP registers are part of the SVE Z-registers, any * use of SIMD/FP functionality will corrupt the SVE registers. * Therefore it is necessary to prevent use of SIMD/FP support * in the Secure world as well as SVE functionality. */ cptr = read_cptr_el3(); cptr = (cptr | TFP_BIT) & ~(CPTR_EZ_BIT); write_cptr_el3(cptr); /* * No explicit ISB required here as ERET to switch to Secure * world covers it */ return (void *)0; } static void *enable_sve_hook(const void *arg) { uint64_t cptr; if (!sve_supported()) return (void *)-1; /* * Enable SVE, SIMD and FP access for the Non-secure world. */ cptr = read_cptr_el3(); cptr = (cptr | CPTR_EZ_BIT) & ~(TFP_BIT); write_cptr_el3(cptr); /* * No explicit ISB required here as ERET to switch to Non-secure * world covers it */ return (void *)0; } void sve_enable(bool el2_unused) { uint64_t cptr; if (!sve_supported()) return; #if CTX_INCLUDE_FPREGS /* * CTX_INCLUDE_FPREGS is not supported on SVE enabled systems. */ assert(0); #endif /* * Update CPTR_EL3 to enable access to SVE functionality for the * Non-secure world. * NOTE - assumed that CPTR_EL3.TFP is set to allow access to * the SIMD, floating-point and SVE support. * * CPTR_EL3.EZ: Set to 1 to enable access to SVE functionality * in the Non-secure world. */ cptr = read_cptr_el3(); cptr |= CPTR_EZ_BIT; write_cptr_el3(cptr); /* * Need explicit ISB here to guarantee that update to ZCR_ELx * and CPTR_EL2.TZ do not result in trap to EL3. */ isb(); /* * Ensure lower ELs have access to full vector length. */ write_zcr_el3(ZCR_EL3_LEN_MASK); if (el2_unused) { /* * Update CPTR_EL2 to enable access to SVE functionality * for Non-secure world, EL2 and Non-secure EL1 and EL0. * NOTE - assumed that CPTR_EL2.TFP is set to allow * access to the SIMD, floating-point and SVE support. * * CPTR_EL2.TZ: Set to 0 to enable access to SVE support * for EL2 and Non-secure EL1 and EL0. */ cptr = read_cptr_el2(); cptr &= ~(CPTR_EL2_TZ_BIT); write_cptr_el2(cptr); /* * Ensure lower ELs have access to full vector length. */ write_zcr_el2(ZCR_EL2_LEN_MASK); } /* * No explicit ISB required here as ERET to switch to * Non-secure world covers it. */ } SUBSCRIBE_TO_EVENT(cm_exited_normal_world, disable_sve_hook); SUBSCRIBE_TO_EVENT(cm_entering_normal_world, enable_sve_hook); trusted-firmware-a-2.2/lib/libc/000077500000000000000000000000001355360272700165705ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/libc/aarch64/000077500000000000000000000000001355360272700200205ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/libc/aarch64/setjmp.S000066400000000000000000000022171355360272700214500ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl setjmp .globl longjmp /* * int setjmp(jmp_buf env); */ func setjmp mov x7, sp stp x19, x20, [x0, #JMP_CTX_X19] stp x21, x22, [x0, #JMP_CTX_X21] stp x23, x24, [x0, #JMP_CTX_X23] stp x25, x26, [x0, #JMP_CTX_X25] stp x27, x28, [x0, #JMP_CTX_X27] stp x29, x30, [x0, #JMP_CTX_X29] stp x7, xzr, [x0, #JMP_CTX_SP] mov x0, #0 ret endfunc setjmp /* * void longjmp(jmp_buf env, int val); */ func longjmp ldp x7, xzr, [x0, #JMP_CTX_SP] #if ENABLE_ASSERTIONS /* * Since we're unwinding the stack, assert that the stack being reset to * is shallower. */ mov x19, sp cmp x7, x19 ASM_ASSERT(ge) #endif ldp x19, x20, [x0, #JMP_CTX_X19] ldp x21, x22, [x0, #JMP_CTX_X21] ldp x23, x24, [x0, #JMP_CTX_X23] ldp x25, x26, [x0, #JMP_CTX_X25] ldp x27, x28, [x0, #JMP_CTX_X27] ldp x29, x30, [x0, #JMP_CTX_X29] mov sp, x7 ands x0, x1, x1 /* Move val to x0 and set flags */ cinc x0, x0, eq /* If val is 0, return 1 */ ret endfunc longjmp trusted-firmware-a-2.2/lib/libc/abort.c000066400000000000000000000003451355360272700200450ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include void abort(void) { ERROR("ABORT\n"); panic(); } trusted-firmware-a-2.2/lib/libc/assert.c000066400000000000000000000020031355360272700202300ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* * Only print the output if PLAT_LOG_LEVEL_ASSERT is higher or equal to * LOG_LEVEL_INFO, which is the default value for builds with DEBUG=1. */ #if PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_VERBOSE void __dead2 __assert(const char *file, unsigned int line, const char *assertion) { printf("ASSERT: %s:%d:%s\n", file, line, assertion); backtrace("assert"); (void)console_flush(); plat_panic_handler(); } #elif PLAT_LOG_LEVEL_ASSERT >= LOG_LEVEL_INFO void __dead2 __assert(const char *file, unsigned int line) { printf("ASSERT: %s:%d\n", file, line); backtrace("assert"); (void)console_flush(); plat_panic_handler(); } #else void __dead2 __assert(void) { backtrace("assert"); (void)console_flush(); plat_panic_handler(); } #endif trusted-firmware-a-2.2/lib/libc/exit.c000066400000000000000000000005471355360272700177130ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include static void (*exitfun)(void); void exit(int status) { if (exitfun != NULL) (*exitfun)(); for (;;) ; } int atexit(void (*fun)(void)) { if (exitfun != NULL) return -1; exitfun = fun; return 0; } trusted-firmware-a-2.2/lib/libc/libc.mk000066400000000000000000000011631355360272700200330ustar00rootroot00000000000000# # Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # LIBC_SRCS := $(addprefix lib/libc/, \ abort.c \ assert.c \ exit.c \ memchr.c \ memcmp.c \ memcpy.c \ memmove.c \ memset.c \ printf.c \ putchar.c \ puts.c \ snprintf.c \ strchr.c \ strcmp.c \ strlcpy.c \ strlen.c \ strncmp.c \ strnlen.c \ strrchr.c) ifeq (${ARCH},aarch64) LIBC_SRCS += $(addprefix lib/libc/aarch64/, \ setjmp.S) endif INCLUDES += -Iinclude/lib/libc \ -Iinclude/lib/libc/$(ARCH) \ trusted-firmware-a-2.2/lib/libc/memchr.c000066400000000000000000000005371355360272700202140ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include void *memchr(const void *src, int c, size_t len) { const unsigned char *s = src; while (len--) { if (*s == (unsigned char)c) return (void *) s; s++; } return NULL; } trusted-firmware-a-2.2/lib/libc/memcmp.c000066400000000000000000000006501355360272700202130ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include int memcmp(const void *s1, const void *s2, size_t len) { const unsigned char *s = s1; const unsigned char *d = s2; unsigned char sc; unsigned char dc; while (len--) { sc = *s++; dc = *d++; if (sc - dc) return (sc - dc); } return 0; } trusted-firmware-a-2.2/lib/libc/memcpy.c000066400000000000000000000004701355360272700202270ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include void *memcpy(void *dst, const void *src, size_t len) { const char *s = src; char *d = dst; while (len--) *d++ = *s++; return dst; } trusted-firmware-a-2.2/lib/libc/memmove.c000066400000000000000000000016371355360272700204100ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include void *memmove(void *dst, const void *src, size_t len) { /* * The following test makes use of unsigned arithmetic overflow to * more efficiently test the condition !(src <= dst && dst < str+len). * It also avoids the situation where the more explicit test would give * incorrect results were the calculation str+len to overflow (though * that issue is probably moot as such usage is probably undefined * behaviour and a bug anyway. */ if ((size_t)dst - (size_t)src >= len) { /* destination not in source data, so can safely use memcpy */ return memcpy(dst, src, len); } else { /* copy backwards... */ const char *end = dst; const char *s = (const char *)src + len; char *d = (char *)dst + len; while (d != end) *--d = *--s; } return dst; } trusted-firmware-a-2.2/lib/libc/memset.c000066400000000000000000000004411355360272700202250ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include void *memset(void *dst, int val, size_t count) { char *ptr = dst; while (count--) *ptr++ = val; return dst; } trusted-firmware-a-2.2/lib/libc/printf.c000066400000000000000000000101351355360272700202360ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #define get_num_va_args(_args, _lcount) \ (((_lcount) > 1) ? va_arg(_args, long long int) : \ (((_lcount) == 1) ? va_arg(_args, long int) : \ va_arg(_args, int))) #define get_unum_va_args(_args, _lcount) \ (((_lcount) > 1) ? va_arg(_args, unsigned long long int) : \ (((_lcount) == 1) ? va_arg(_args, unsigned long int) : \ va_arg(_args, unsigned int))) static int string_print(const char *str) { int count = 0; assert(str != NULL); for ( ; *str != '\0'; str++) { (void)putchar(*str); count++; } return count; } static int unsigned_num_print(unsigned long long int unum, unsigned int radix, char padc, int padn) { /* Just need enough space to store 64 bit decimal integer */ char num_buf[20]; int i = 0, count = 0; unsigned int rem; do { rem = unum % radix; if (rem < 0xa) num_buf[i] = '0' + rem; else num_buf[i] = 'a' + (rem - 0xa); i++; unum /= radix; } while (unum > 0U); if (padn > 0) { while (i < padn) { (void)putchar(padc); count++; padn--; } } while (--i >= 0) { (void)putchar(num_buf[i]); count++; } return count; } /******************************************************************* * Reduced format print for Trusted firmware. * The following type specifiers are supported by this print * %x - hexadecimal format * %s - string format * %d or %i - signed decimal format * %u - unsigned decimal format * %p - pointer format * * The following length specifiers are supported by this print * %l - long int (64-bit on AArch64) * %ll - long long int (64-bit on AArch64) * %z - size_t sized integer formats (64 bit on AArch64) * * The following padding specifiers are supported by this print * %0NN - Left-pad the number with 0s (NN is a decimal number) * * The print exits on all other formats specifiers other than valid * combinations of the above specifiers. *******************************************************************/ int vprintf(const char *fmt, va_list args) { int l_count; long long int num; unsigned long long int unum; char *str; char padc = '\0'; /* Padding character */ int padn; /* Number of characters to pad */ int count = 0; /* Number of printed characters */ while (*fmt != '\0') { l_count = 0; padn = 0; if (*fmt == '%') { fmt++; /* Check the format specifier */ loop: switch (*fmt) { case 'i': /* Fall through to next one */ case 'd': num = get_num_va_args(args, l_count); if (num < 0) { (void)putchar('-'); unum = (unsigned long long int)-num; padn--; } else unum = (unsigned long long int)num; count += unsigned_num_print(unum, 10, padc, padn); break; case 's': str = va_arg(args, char *); count += string_print(str); break; case 'p': unum = (uintptr_t)va_arg(args, void *); if (unum > 0U) { count += string_print("0x"); padn -= 2; } count += unsigned_num_print(unum, 16, padc, padn); break; case 'x': unum = get_unum_va_args(args, l_count); count += unsigned_num_print(unum, 16, padc, padn); break; case 'z': if (sizeof(size_t) == 8U) l_count = 2; fmt++; goto loop; case 'l': l_count++; fmt++; goto loop; case 'u': unum = get_unum_va_args(args, l_count); count += unsigned_num_print(unum, 10, padc, padn); break; case '0': padc = '0'; padn = 0; fmt++; for (;;) { char ch = *fmt; if ((ch < '0') || (ch > '9')) { goto loop; } padn = (padn * 10) + (ch - '0'); fmt++; } assert(0); /* Unreachable */ default: /* Exit on any other format specifier */ return -1; } fmt++; continue; } (void)putchar(*fmt); fmt++; count++; } return count; } int printf(const char *fmt, ...) { int count; va_list va; va_start(va, fmt); count = vprintf(fmt, va); va_end(va); return count; } trusted-firmware-a-2.2/lib/libc/putchar.c000066400000000000000000000004541355360272700204050ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include int putchar(int c) { int res; if (console_putc((unsigned char)c) >= 0) res = c; else res = EOF; return res; } trusted-firmware-a-2.2/lib/libc/puts.c000066400000000000000000000005261355360272700177320ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include int puts(const char *s) { int count = 0; while (*s != '\0') { if (putchar(*s) == EOF) return EOF; s++; count++; } if (putchar('\n') == EOF) return EOF; return count + 1; } trusted-firmware-a-2.2/lib/libc/snprintf.c000066400000000000000000000054711355360272700206060ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include static void string_print(char **s, size_t n, size_t *chars_printed, const char *str) { while (*str != '\0') { if (*chars_printed < n) { *(*s) = *str; (*s)++; } (*chars_printed)++; str++; } } static void unsigned_dec_print(char **s, size_t n, size_t *chars_printed, unsigned int unum) { /* Enough for a 32-bit unsigned decimal integer (4294967295). */ char num_buf[10]; int i = 0; unsigned int rem; do { rem = unum % 10U; num_buf[i++] = '0' + rem; unum /= 10U; } while (unum > 0U); while (--i >= 0) { if (*chars_printed < n) { *(*s) = num_buf[i]; (*s)++; } (*chars_printed)++; } } /******************************************************************* * Reduced snprintf to be used for Trusted firmware. * The following type specifiers are supported: * * %d or %i - signed decimal format * %s - string format * %u - unsigned decimal format * * The function panics on all other formats specifiers. * * It returns the number of characters that would be written if the * buffer was big enough. If it returns a value lower than n, the * whole string has been written. *******************************************************************/ int snprintf(char *s, size_t n, const char *fmt, ...) { va_list args; int num; unsigned int unum; char *str; size_t chars_printed = 0U; if (n == 0U) { /* There isn't space for anything. */ } else if (n == 1U) { /* Buffer is too small to actually write anything else. */ *s = '\0'; n = 0U; } else { /* Reserve space for the terminator character. */ n--; } va_start(args, fmt); while (*fmt != '\0') { if (*fmt == '%') { fmt++; /* Check the format specifier. */ switch (*fmt) { case 'i': case 'd': num = va_arg(args, int); if (num < 0) { if (chars_printed < n) { *s = '-'; s++; } chars_printed++; unum = (unsigned int)-num; } else { unum = (unsigned int)num; } unsigned_dec_print(&s, n, &chars_printed, unum); break; case 's': str = va_arg(args, char *); string_print(&s, n, &chars_printed, str); break; case 'u': unum = va_arg(args, unsigned int); unsigned_dec_print(&s, n, &chars_printed, unum); break; default: /* Panic on any other format specifier. */ ERROR("snprintf: specifier with ASCII code '%d' not supported.", *fmt); plat_panic_handler(); assert(0); /* Unreachable */ } fmt++; continue; } if (chars_printed < n) { *s = *fmt; s++; } fmt++; chars_printed++; } va_end(args); if (n > 0U) *s = '\0'; return (int)chars_printed; } trusted-firmware-a-2.2/lib/libc/strchr.c000066400000000000000000000036321355360272700202450ustar00rootroot00000000000000/*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Portions copyright (c) 2018, ARM Limited and Contributors. * All rights reserved. */ #include #include char * strchr(const char *p, int ch) { char c; c = ch; for (;; ++p) { if (*p == c) return ((char *)p); if (*p == '\0') return (NULL); } /* NOTREACHED */ } trusted-firmware-a-2.2/lib/libc/strcmp.c000066400000000000000000000037741355360272700202570ustar00rootroot00000000000000/*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Portions copyright (c) 2018, ARM Limited and Contributors. * All rights reserved. */ #include /* * Compare strings. */ int strcmp(const char *s1, const char *s2) { while (*s1 == *s2++) if (*s1++ == '\0') return (0); return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1)); } trusted-firmware-a-2.2/lib/libc/strlcpy.c000066400000000000000000000031411355360272700204330ustar00rootroot00000000000000/* $OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $ */ /* * SPDX-License-Identifier: ISC * * Copyright (c) 1998, 2015 Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include /* * Copy string src to buffer dst of size dsize. At most dsize-1 * chars will be copied. Always NUL terminates (unless dsize == 0). * Returns strlen(src); if retval >= dsize, truncation occurred. */ size_t strlcpy(char * dst, const char * src, size_t dsize) { const char *osrc = src; size_t nleft = dsize; /* Copy as many bytes as will fit. */ if (nleft != 0) { while (--nleft != 0) { if ((*dst++ = *src++) == '\0') break; } } /* Not enough room in dst, add NUL and traverse rest of src. */ if (nleft == 0) { if (dsize != 0) *dst = '\0'; /* NUL-terminate dst */ while (*src++) ; } return(src - osrc - 1); /* count does not include NUL */ } trusted-firmware-a-2.2/lib/libc/strlen.c000066400000000000000000000004001355360272700202350ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include size_t strlen(const char *s) { const char *cursor = s; while (*cursor) cursor++; return cursor - s; } trusted-firmware-a-2.2/lib/libc/strncmp.c000066400000000000000000000037331355360272700204300ustar00rootroot00000000000000/*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Portions copyright (c) 2018, ARM Limited and Contributors. * All rights reserved. */ #include int strncmp(const char *s1, const char *s2, size_t n) { if (n == 0) return (0); do { if (*s1 != *s2++) return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1)); if (*s1++ == '\0') break; } while (--n != 0); return (0); } trusted-firmware-a-2.2/lib/libc/strnlen.c000066400000000000000000000032261355360272700204240ustar00rootroot00000000000000/*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2009 David Schultz * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Portions copyright (c) 2018, ARM Limited and Contributors. * All rights reserved. */ #include size_t strnlen(const char *s, size_t maxlen) { size_t len; for (len = 0; len < maxlen; len++, s++) { if (!*s) break; } return (len); } trusted-firmware-a-2.2/lib/libc/strrchr.c000066400000000000000000000035231355360272700204260ustar00rootroot00000000000000/*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1988, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include char * strrchr(const char *p, int ch) { char *save; char c; c = ch; for (save = NULL;; ++p) { if (*p == c) save = (char *)p; if (*p == '\0') return (save); } /* NOTREACHED */ } trusted-firmware-a-2.2/lib/libfdt/000077500000000000000000000000001355360272700171235ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/libfdt/fdt.c000066400000000000000000000151571355360272700200550ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" int fdt_check_header(const void *fdt) { if (fdt_magic(fdt) == FDT_MAGIC) { /* Complete tree */ if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION) return -FDT_ERR_BADVERSION; if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION) return -FDT_ERR_BADVERSION; } else if (fdt_magic(fdt) == FDT_SW_MAGIC) { /* Unfinished sequential-write blob */ if (fdt_size_dt_struct(fdt) == 0) return -FDT_ERR_BADSTATE; } else { return -FDT_ERR_BADMAGIC; } return 0; } const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len) { unsigned absoffset = offset + fdt_off_dt_struct(fdt); if ((absoffset < offset) || ((absoffset + len) < absoffset) || (absoffset + len) > fdt_totalsize(fdt)) return NULL; if (fdt_version(fdt) >= 0x11) if (((offset + len) < offset) || ((offset + len) > fdt_size_dt_struct(fdt))) return NULL; return fdt_offset_ptr_(fdt, offset); } uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset) { const fdt32_t *tagp, *lenp; uint32_t tag; int offset = startoffset; const char *p; *nextoffset = -FDT_ERR_TRUNCATED; tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE); if (!tagp) return FDT_END; /* premature end */ tag = fdt32_to_cpu(*tagp); offset += FDT_TAGSIZE; *nextoffset = -FDT_ERR_BADSTRUCTURE; switch (tag) { case FDT_BEGIN_NODE: /* skip name */ do { p = fdt_offset_ptr(fdt, offset++, 1); } while (p && (*p != '\0')); if (!p) return FDT_END; /* premature end */ break; case FDT_PROP: lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp)); if (!lenp) return FDT_END; /* premature end */ /* skip-name offset, length and value */ offset += sizeof(struct fdt_property) - FDT_TAGSIZE + fdt32_to_cpu(*lenp); if (fdt_version(fdt) < 0x10 && fdt32_to_cpu(*lenp) >= 8 && ((offset - fdt32_to_cpu(*lenp)) % 8) != 0) offset += 4; break; case FDT_END: case FDT_END_NODE: case FDT_NOP: break; default: return FDT_END; } if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset)) return FDT_END; /* premature end */ *nextoffset = FDT_TAGALIGN(offset); return tag; } int fdt_check_node_offset_(const void *fdt, int offset) { if ((offset < 0) || (offset % FDT_TAGSIZE) || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE)) return -FDT_ERR_BADOFFSET; return offset; } int fdt_check_prop_offset_(const void *fdt, int offset) { if ((offset < 0) || (offset % FDT_TAGSIZE) || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP)) return -FDT_ERR_BADOFFSET; return offset; } int fdt_next_node(const void *fdt, int offset, int *depth) { int nextoffset = 0; uint32_t tag; if (offset >= 0) if ((nextoffset = fdt_check_node_offset_(fdt, offset)) < 0) return nextoffset; do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_PROP: case FDT_NOP: break; case FDT_BEGIN_NODE: if (depth) (*depth)++; break; case FDT_END_NODE: if (depth && ((--(*depth)) < 0)) return nextoffset; break; case FDT_END: if ((nextoffset >= 0) || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth)) return -FDT_ERR_NOTFOUND; else return nextoffset; } } while (tag != FDT_BEGIN_NODE); return offset; } int fdt_first_subnode(const void *fdt, int offset) { int depth = 0; offset = fdt_next_node(fdt, offset, &depth); if (offset < 0 || depth != 1) return -FDT_ERR_NOTFOUND; return offset; } int fdt_next_subnode(const void *fdt, int offset) { int depth = 1; /* * With respect to the parent, the depth of the next subnode will be * the same as the last. */ do { offset = fdt_next_node(fdt, offset, &depth); if (offset < 0 || depth < 1) return -FDT_ERR_NOTFOUND; } while (depth > 1); return offset; } const char *fdt_find_string_(const char *strtab, int tabsize, const char *s) { int len = strlen(s) + 1; const char *last = strtab + tabsize - len; const char *p; for (p = strtab; p <= last; p++) if (memcmp(p, s, len) == 0) return p; return NULL; } int fdt_move(const void *fdt, void *buf, int bufsize) { FDT_CHECK_HEADER(fdt); if (fdt_totalsize(fdt) > bufsize) return -FDT_ERR_NOSPACE; memmove(buf, fdt, fdt_totalsize(fdt)); return 0; } trusted-firmware-a-2.2/lib/libfdt/fdt_addresses.c000066400000000000000000000062311355360272700221030ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2014 David Gibson * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" int fdt_address_cells(const void *fdt, int nodeoffset) { const fdt32_t *ac; int val; int len; ac = fdt_getprop(fdt, nodeoffset, "#address-cells", &len); if (!ac) return 2; if (len != sizeof(*ac)) return -FDT_ERR_BADNCELLS; val = fdt32_to_cpu(*ac); if ((val <= 0) || (val > FDT_MAX_NCELLS)) return -FDT_ERR_BADNCELLS; return val; } int fdt_size_cells(const void *fdt, int nodeoffset) { const fdt32_t *sc; int val; int len; sc = fdt_getprop(fdt, nodeoffset, "#size-cells", &len); if (!sc) return 2; if (len != sizeof(*sc)) return -FDT_ERR_BADNCELLS; val = fdt32_to_cpu(*sc); if ((val < 0) || (val > FDT_MAX_NCELLS)) return -FDT_ERR_BADNCELLS; return val; } trusted-firmware-a-2.2/lib/libfdt/fdt_empty_tree.c000066400000000000000000000055261355360272700223110ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2012 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" int fdt_create_empty_tree(void *buf, int bufsize) { int err; err = fdt_create(buf, bufsize); if (err) return err; err = fdt_finish_reservemap(buf); if (err) return err; err = fdt_begin_node(buf, ""); if (err) return err; err = fdt_end_node(buf); if (err) return err; err = fdt_finish(buf); if (err) return err; return fdt_open_into(buf, buf, bufsize); } trusted-firmware-a-2.2/lib/libfdt/fdt_overlay.c000066400000000000000000000570211355360272700216120ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2016 Free Electrons * Copyright (C) 2016 NextThing Co. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" /** * overlay_get_target_phandle - retrieves the target phandle of a fragment * @fdto: pointer to the device tree overlay blob * @fragment: node offset of the fragment in the overlay * * overlay_get_target_phandle() retrieves the target phandle of an * overlay fragment when that fragment uses a phandle (target * property) instead of a path (target-path property). * * returns: * the phandle pointed by the target property * 0, if the phandle was not found * -1, if the phandle was malformed */ static uint32_t overlay_get_target_phandle(const void *fdto, int fragment) { const fdt32_t *val; int len; val = fdt_getprop(fdto, fragment, "target", &len); if (!val) return 0; if ((len != sizeof(*val)) || (fdt32_to_cpu(*val) == (uint32_t)-1)) return (uint32_t)-1; return fdt32_to_cpu(*val); } /** * overlay_get_target - retrieves the offset of a fragment's target * @fdt: Base device tree blob * @fdto: Device tree overlay blob * @fragment: node offset of the fragment in the overlay * @pathp: pointer which receives the path of the target (or NULL) * * overlay_get_target() retrieves the target offset in the base * device tree of a fragment, no matter how the actual targetting is * done (through a phandle or a path) * * returns: * the targetted node offset in the base device tree * Negative error code on error */ static int overlay_get_target(const void *fdt, const void *fdto, int fragment, char const **pathp) { uint32_t phandle; const char *path = NULL; int path_len = 0, ret; /* Try first to do a phandle based lookup */ phandle = overlay_get_target_phandle(fdto, fragment); if (phandle == (uint32_t)-1) return -FDT_ERR_BADPHANDLE; /* no phandle, try path */ if (!phandle) { /* And then a path based lookup */ path = fdt_getprop(fdto, fragment, "target-path", &path_len); if (path) ret = fdt_path_offset(fdt, path); else ret = path_len; } else ret = fdt_node_offset_by_phandle(fdt, phandle); /* * If we haven't found either a target or a * target-path property in a node that contains a * __overlay__ subnode (we wouldn't be called * otherwise), consider it a improperly written * overlay */ if (ret < 0 && path_len == -FDT_ERR_NOTFOUND) ret = -FDT_ERR_BADOVERLAY; /* return on error */ if (ret < 0) return ret; /* return pointer to path (if available) */ if (pathp) *pathp = path ? path : NULL; return ret; } /** * overlay_phandle_add_offset - Increases a phandle by an offset * @fdt: Base device tree blob * @node: Device tree overlay blob * @name: Name of the property to modify (phandle or linux,phandle) * @delta: offset to apply * * overlay_phandle_add_offset() increments a node phandle by a given * offset. * * returns: * 0 on success. * Negative error code on error */ static int overlay_phandle_add_offset(void *fdt, int node, const char *name, uint32_t delta) { const fdt32_t *val; uint32_t adj_val; int len; val = fdt_getprop(fdt, node, name, &len); if (!val) return len; if (len != sizeof(*val)) return -FDT_ERR_BADPHANDLE; adj_val = fdt32_to_cpu(*val); if ((adj_val + delta) < adj_val) return -FDT_ERR_NOPHANDLES; adj_val += delta; if (adj_val == (uint32_t)-1) return -FDT_ERR_NOPHANDLES; return fdt_setprop_inplace_u32(fdt, node, name, adj_val); } /** * overlay_adjust_node_phandles - Offsets the phandles of a node * @fdto: Device tree overlay blob * @node: Offset of the node we want to adjust * @delta: Offset to shift the phandles of * * overlay_adjust_node_phandles() adds a constant to all the phandles * of a given node. This is mainly use as part of the overlay * application process, when we want to update all the overlay * phandles to not conflict with the overlays of the base device tree. * * returns: * 0 on success * Negative error code on failure */ static int overlay_adjust_node_phandles(void *fdto, int node, uint32_t delta) { int child; int ret; ret = overlay_phandle_add_offset(fdto, node, "phandle", delta); if (ret && ret != -FDT_ERR_NOTFOUND) return ret; ret = overlay_phandle_add_offset(fdto, node, "linux,phandle", delta); if (ret && ret != -FDT_ERR_NOTFOUND) return ret; fdt_for_each_subnode(child, fdto, node) { ret = overlay_adjust_node_phandles(fdto, child, delta); if (ret) return ret; } return 0; } /** * overlay_adjust_local_phandles - Adjust the phandles of a whole overlay * @fdto: Device tree overlay blob * @delta: Offset to shift the phandles of * * overlay_adjust_local_phandles() adds a constant to all the * phandles of an overlay. This is mainly use as part of the overlay * application process, when we want to update all the overlay * phandles to not conflict with the overlays of the base device tree. * * returns: * 0 on success * Negative error code on failure */ static int overlay_adjust_local_phandles(void *fdto, uint32_t delta) { /* * Start adjusting the phandles from the overlay root */ return overlay_adjust_node_phandles(fdto, 0, delta); } /** * overlay_update_local_node_references - Adjust the overlay references * @fdto: Device tree overlay blob * @tree_node: Node offset of the node to operate on * @fixup_node: Node offset of the matching local fixups node * @delta: Offset to shift the phandles of * * overlay_update_local_nodes_references() update the phandles * pointing to a node within the device tree overlay by adding a * constant delta. * * This is mainly used as part of a device tree application process, * where you want the device tree overlays phandles to not conflict * with the ones from the base device tree before merging them. * * returns: * 0 on success * Negative error code on failure */ static int overlay_update_local_node_references(void *fdto, int tree_node, int fixup_node, uint32_t delta) { int fixup_prop; int fixup_child; int ret; fdt_for_each_property_offset(fixup_prop, fdto, fixup_node) { const fdt32_t *fixup_val; const char *tree_val; const char *name; int fixup_len; int tree_len; int i; fixup_val = fdt_getprop_by_offset(fdto, fixup_prop, &name, &fixup_len); if (!fixup_val) return fixup_len; if (fixup_len % sizeof(uint32_t)) return -FDT_ERR_BADOVERLAY; tree_val = fdt_getprop(fdto, tree_node, name, &tree_len); if (!tree_val) { if (tree_len == -FDT_ERR_NOTFOUND) return -FDT_ERR_BADOVERLAY; return tree_len; } for (i = 0; i < (fixup_len / sizeof(uint32_t)); i++) { fdt32_t adj_val; uint32_t poffset; poffset = fdt32_to_cpu(fixup_val[i]); /* * phandles to fixup can be unaligned. * * Use a memcpy for the architectures that do * not support unaligned accesses. */ memcpy(&adj_val, tree_val + poffset, sizeof(adj_val)); adj_val = cpu_to_fdt32(fdt32_to_cpu(adj_val) + delta); ret = fdt_setprop_inplace_namelen_partial(fdto, tree_node, name, strlen(name), poffset, &adj_val, sizeof(adj_val)); if (ret == -FDT_ERR_NOSPACE) return -FDT_ERR_BADOVERLAY; if (ret) return ret; } } fdt_for_each_subnode(fixup_child, fdto, fixup_node) { const char *fixup_child_name = fdt_get_name(fdto, fixup_child, NULL); int tree_child; tree_child = fdt_subnode_offset(fdto, tree_node, fixup_child_name); if (tree_child == -FDT_ERR_NOTFOUND) return -FDT_ERR_BADOVERLAY; if (tree_child < 0) return tree_child; ret = overlay_update_local_node_references(fdto, tree_child, fixup_child, delta); if (ret) return ret; } return 0; } /** * overlay_update_local_references - Adjust the overlay references * @fdto: Device tree overlay blob * @delta: Offset to shift the phandles of * * overlay_update_local_references() update all the phandles pointing * to a node within the device tree overlay by adding a constant * delta to not conflict with the base overlay. * * This is mainly used as part of a device tree application process, * where you want the device tree overlays phandles to not conflict * with the ones from the base device tree before merging them. * * returns: * 0 on success * Negative error code on failure */ static int overlay_update_local_references(void *fdto, uint32_t delta) { int fixups; fixups = fdt_path_offset(fdto, "/__local_fixups__"); if (fixups < 0) { /* There's no local phandles to adjust, bail out */ if (fixups == -FDT_ERR_NOTFOUND) return 0; return fixups; } /* * Update our local references from the root of the tree */ return overlay_update_local_node_references(fdto, 0, fixups, delta); } /** * overlay_fixup_one_phandle - Set an overlay phandle to the base one * @fdt: Base Device Tree blob * @fdto: Device tree overlay blob * @symbols_off: Node offset of the symbols node in the base device tree * @path: Path to a node holding a phandle in the overlay * @path_len: number of path characters to consider * @name: Name of the property holding the phandle reference in the overlay * @name_len: number of name characters to consider * @poffset: Offset within the overlay property where the phandle is stored * @label: Label of the node referenced by the phandle * * overlay_fixup_one_phandle() resolves an overlay phandle pointing to * a node in the base device tree. * * This is part of the device tree overlay application process, when * you want all the phandles in the overlay to point to the actual * base dt nodes. * * returns: * 0 on success * Negative error code on failure */ static int overlay_fixup_one_phandle(void *fdt, void *fdto, int symbols_off, const char *path, uint32_t path_len, const char *name, uint32_t name_len, int poffset, const char *label) { const char *symbol_path; uint32_t phandle; fdt32_t phandle_prop; int symbol_off, fixup_off; int prop_len; if (symbols_off < 0) return symbols_off; symbol_path = fdt_getprop(fdt, symbols_off, label, &prop_len); if (!symbol_path) return prop_len; symbol_off = fdt_path_offset(fdt, symbol_path); if (symbol_off < 0) return symbol_off; phandle = fdt_get_phandle(fdt, symbol_off); if (!phandle) return -FDT_ERR_NOTFOUND; fixup_off = fdt_path_offset_namelen(fdto, path, path_len); if (fixup_off == -FDT_ERR_NOTFOUND) return -FDT_ERR_BADOVERLAY; if (fixup_off < 0) return fixup_off; phandle_prop = cpu_to_fdt32(phandle); return fdt_setprop_inplace_namelen_partial(fdto, fixup_off, name, name_len, poffset, &phandle_prop, sizeof(phandle_prop)); }; /** * overlay_fixup_phandle - Set an overlay phandle to the base one * @fdt: Base Device Tree blob * @fdto: Device tree overlay blob * @symbols_off: Node offset of the symbols node in the base device tree * @property: Property offset in the overlay holding the list of fixups * * overlay_fixup_phandle() resolves all the overlay phandles pointed * to in a __fixups__ property, and updates them to match the phandles * in use in the base device tree. * * This is part of the device tree overlay application process, when * you want all the phandles in the overlay to point to the actual * base dt nodes. * * returns: * 0 on success * Negative error code on failure */ static int overlay_fixup_phandle(void *fdt, void *fdto, int symbols_off, int property) { const char *value; const char *label; int len; value = fdt_getprop_by_offset(fdto, property, &label, &len); if (!value) { if (len == -FDT_ERR_NOTFOUND) return -FDT_ERR_INTERNAL; return len; } do { const char *path, *name, *fixup_end; const char *fixup_str = value; uint32_t path_len, name_len; uint32_t fixup_len; char *sep, *endptr; int poffset, ret; fixup_end = memchr(value, '\0', len); if (!fixup_end) return -FDT_ERR_BADOVERLAY; fixup_len = fixup_end - fixup_str; len -= fixup_len + 1; value += fixup_len + 1; path = fixup_str; sep = memchr(fixup_str, ':', fixup_len); if (!sep || *sep != ':') return -FDT_ERR_BADOVERLAY; path_len = sep - path; if (path_len == (fixup_len - 1)) return -FDT_ERR_BADOVERLAY; fixup_len -= path_len + 1; name = sep + 1; sep = memchr(name, ':', fixup_len); if (!sep || *sep != ':') return -FDT_ERR_BADOVERLAY; name_len = sep - name; if (!name_len) return -FDT_ERR_BADOVERLAY; poffset = strtoul(sep + 1, &endptr, 10); if ((*endptr != '\0') || (endptr <= (sep + 1))) return -FDT_ERR_BADOVERLAY; ret = overlay_fixup_one_phandle(fdt, fdto, symbols_off, path, path_len, name, name_len, poffset, label); if (ret) return ret; } while (len > 0); return 0; } /** * overlay_fixup_phandles - Resolve the overlay phandles to the base * device tree * @fdt: Base Device Tree blob * @fdto: Device tree overlay blob * * overlay_fixup_phandles() resolves all the overlay phandles pointing * to nodes in the base device tree. * * This is one of the steps of the device tree overlay application * process, when you want all the phandles in the overlay to point to * the actual base dt nodes. * * returns: * 0 on success * Negative error code on failure */ static int overlay_fixup_phandles(void *fdt, void *fdto) { int fixups_off, symbols_off; int property; /* We can have overlays without any fixups */ fixups_off = fdt_path_offset(fdto, "/__fixups__"); if (fixups_off == -FDT_ERR_NOTFOUND) return 0; /* nothing to do */ if (fixups_off < 0) return fixups_off; /* And base DTs without symbols */ symbols_off = fdt_path_offset(fdt, "/__symbols__"); if ((symbols_off < 0 && (symbols_off != -FDT_ERR_NOTFOUND))) return symbols_off; fdt_for_each_property_offset(property, fdto, fixups_off) { int ret; ret = overlay_fixup_phandle(fdt, fdto, symbols_off, property); if (ret) return ret; } return 0; } /** * overlay_apply_node - Merges a node into the base device tree * @fdt: Base Device Tree blob * @target: Node offset in the base device tree to apply the fragment to * @fdto: Device tree overlay blob * @node: Node offset in the overlay holding the changes to merge * * overlay_apply_node() merges a node into a target base device tree * node pointed. * * This is part of the final step in the device tree overlay * application process, when all the phandles have been adjusted and * resolved and you just have to merge overlay into the base device * tree. * * returns: * 0 on success * Negative error code on failure */ static int overlay_apply_node(void *fdt, int target, void *fdto, int node) { int property; int subnode; fdt_for_each_property_offset(property, fdto, node) { const char *name; const void *prop; int prop_len; int ret; prop = fdt_getprop_by_offset(fdto, property, &name, &prop_len); if (prop_len == -FDT_ERR_NOTFOUND) return -FDT_ERR_INTERNAL; if (prop_len < 0) return prop_len; ret = fdt_setprop(fdt, target, name, prop, prop_len); if (ret) return ret; } fdt_for_each_subnode(subnode, fdto, node) { const char *name = fdt_get_name(fdto, subnode, NULL); int nnode; int ret; nnode = fdt_add_subnode(fdt, target, name); if (nnode == -FDT_ERR_EXISTS) { nnode = fdt_subnode_offset(fdt, target, name); if (nnode == -FDT_ERR_NOTFOUND) return -FDT_ERR_INTERNAL; } if (nnode < 0) return nnode; ret = overlay_apply_node(fdt, nnode, fdto, subnode); if (ret) return ret; } return 0; } /** * overlay_merge - Merge an overlay into its base device tree * @fdt: Base Device Tree blob * @fdto: Device tree overlay blob * * overlay_merge() merges an overlay into its base device tree. * * This is the next to last step in the device tree overlay application * process, when all the phandles have been adjusted and resolved and * you just have to merge overlay into the base device tree. * * returns: * 0 on success * Negative error code on failure */ static int overlay_merge(void *fdt, void *fdto) { int fragment; fdt_for_each_subnode(fragment, fdto, 0) { int overlay; int target; int ret; /* * Each fragments will have an __overlay__ node. If * they don't, it's not supposed to be merged */ overlay = fdt_subnode_offset(fdto, fragment, "__overlay__"); if (overlay == -FDT_ERR_NOTFOUND) continue; if (overlay < 0) return overlay; target = overlay_get_target(fdt, fdto, fragment, NULL); if (target < 0) return target; ret = overlay_apply_node(fdt, target, fdto, overlay); if (ret) return ret; } return 0; } static int get_path_len(const void *fdt, int nodeoffset) { int len = 0, namelen; const char *name; FDT_CHECK_HEADER(fdt); for (;;) { name = fdt_get_name(fdt, nodeoffset, &namelen); if (!name) return namelen; /* root? we're done */ if (namelen == 0) break; nodeoffset = fdt_parent_offset(fdt, nodeoffset); if (nodeoffset < 0) return nodeoffset; len += namelen + 1; } /* in case of root pretend it's "/" */ if (len == 0) len++; return len; } /** * overlay_symbol_update - Update the symbols of base tree after a merge * @fdt: Base Device Tree blob * @fdto: Device tree overlay blob * * overlay_symbol_update() updates the symbols of the base tree with the * symbols of the applied overlay * * This is the last step in the device tree overlay application * process, allowing the reference of overlay symbols by subsequent * overlay operations. * * returns: * 0 on success * Negative error code on failure */ static int overlay_symbol_update(void *fdt, void *fdto) { int root_sym, ov_sym, prop, path_len, fragment, target; int len, frag_name_len, ret, rel_path_len; const char *s, *e; const char *path; const char *name; const char *frag_name; const char *rel_path; const char *target_path; char *buf; void *p; ov_sym = fdt_subnode_offset(fdto, 0, "__symbols__"); /* if no overlay symbols exist no problem */ if (ov_sym < 0) return 0; root_sym = fdt_subnode_offset(fdt, 0, "__symbols__"); /* it no root symbols exist we should create them */ if (root_sym == -FDT_ERR_NOTFOUND) root_sym = fdt_add_subnode(fdt, 0, "__symbols__"); /* any error is fatal now */ if (root_sym < 0) return root_sym; /* iterate over each overlay symbol */ fdt_for_each_property_offset(prop, fdto, ov_sym) { path = fdt_getprop_by_offset(fdto, prop, &name, &path_len); if (!path) return path_len; /* verify it's a string property (terminated by a single \0) */ if (path_len < 1 || memchr(path, '\0', path_len) != &path[path_len - 1]) return -FDT_ERR_BADVALUE; /* keep end marker to avoid strlen() */ e = path + path_len; /* format: //__overlay__/ */ if (*path != '/') return -FDT_ERR_BADVALUE; /* get fragment name first */ s = strchr(path + 1, '/'); if (!s) return -FDT_ERR_BADOVERLAY; frag_name = path + 1; frag_name_len = s - path - 1; /* verify format; safe since "s" lies in \0 terminated prop */ len = sizeof("/__overlay__/") - 1; if ((e - s) < len || memcmp(s, "/__overlay__/", len)) return -FDT_ERR_BADOVERLAY; rel_path = s + len; rel_path_len = e - rel_path; /* find the fragment index in which the symbol lies */ ret = fdt_subnode_offset_namelen(fdto, 0, frag_name, frag_name_len); /* not found? */ if (ret < 0) return -FDT_ERR_BADOVERLAY; fragment = ret; /* an __overlay__ subnode must exist */ ret = fdt_subnode_offset(fdto, fragment, "__overlay__"); if (ret < 0) return -FDT_ERR_BADOVERLAY; /* get the target of the fragment */ ret = overlay_get_target(fdt, fdto, fragment, &target_path); if (ret < 0) return ret; target = ret; /* if we have a target path use */ if (!target_path) { ret = get_path_len(fdt, target); if (ret < 0) return ret; len = ret; } else { len = strlen(target_path); } ret = fdt_setprop_placeholder(fdt, root_sym, name, len + (len > 1) + rel_path_len + 1, &p); if (ret < 0) return ret; if (!target_path) { /* again in case setprop_placeholder changed it */ ret = overlay_get_target(fdt, fdto, fragment, &target_path); if (ret < 0) return ret; target = ret; } buf = p; if (len > 1) { /* target is not root */ if (!target_path) { ret = fdt_get_path(fdt, target, buf, len + 1); if (ret < 0) return ret; } else memcpy(buf, target_path, len + 1); } else len--; buf[len] = '/'; memcpy(buf + len + 1, rel_path, rel_path_len); buf[len + 1 + rel_path_len] = '\0'; } return 0; } int fdt_overlay_apply(void *fdt, void *fdto) { uint32_t delta = fdt_get_max_phandle(fdt); int ret; FDT_CHECK_HEADER(fdt); FDT_CHECK_HEADER(fdto); ret = overlay_adjust_local_phandles(fdto, delta); if (ret) goto err; ret = overlay_update_local_references(fdto, delta); if (ret) goto err; ret = overlay_fixup_phandles(fdt, fdto); if (ret) goto err; ret = overlay_merge(fdt, fdto); if (ret) goto err; ret = overlay_symbol_update(fdt, fdto); if (ret) goto err; /* * The overlay has been damaged, erase its magic. */ fdt_set_magic(fdto, ~0); return 0; err: /* * The overlay might have been damaged, erase its magic. */ fdt_set_magic(fdto, ~0); /* * The base device tree might have been damaged, erase its * magic. */ fdt_set_magic(fdt, ~0); return ret; } trusted-firmware-a-2.2/lib/libfdt/fdt_ro.c000066400000000000000000000433601355360272700205520ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" static int fdt_nodename_eq_(const void *fdt, int offset, const char *s, int len) { int olen; const char *p = fdt_get_name(fdt, offset, &olen); if (!p || olen < len) /* short match */ return 0; if (memcmp(p, s, len) != 0) return 0; if (p[len] == '\0') return 1; else if (!memchr(s, '@', len) && (p[len] == '@')) return 1; else return 0; } const char *fdt_string(const void *fdt, int stroffset) { return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; } static int fdt_string_eq_(const void *fdt, int stroffset, const char *s, int len) { const char *p = fdt_string(fdt, stroffset); return (strlen(p) == len) && (memcmp(p, s, len) == 0); } uint32_t fdt_get_max_phandle(const void *fdt) { uint32_t max_phandle = 0; int offset; for (offset = fdt_next_node(fdt, -1, NULL);; offset = fdt_next_node(fdt, offset, NULL)) { uint32_t phandle; if (offset == -FDT_ERR_NOTFOUND) return max_phandle; if (offset < 0) return (uint32_t)-1; phandle = fdt_get_phandle(fdt, offset); if (phandle == (uint32_t)-1) continue; if (phandle > max_phandle) max_phandle = phandle; } return 0; } int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) { FDT_CHECK_HEADER(fdt); *address = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->address); *size = fdt64_to_cpu(fdt_mem_rsv_(fdt, n)->size); return 0; } int fdt_num_mem_rsv(const void *fdt) { int i = 0; while (fdt64_to_cpu(fdt_mem_rsv_(fdt, i)->size) != 0) i++; return i; } static int nextprop_(const void *fdt, int offset) { uint32_t tag; int nextoffset; do { tag = fdt_next_tag(fdt, offset, &nextoffset); switch (tag) { case FDT_END: if (nextoffset >= 0) return -FDT_ERR_BADSTRUCTURE; else return nextoffset; case FDT_PROP: return offset; } offset = nextoffset; } while (tag == FDT_NOP); return -FDT_ERR_NOTFOUND; } int fdt_subnode_offset_namelen(const void *fdt, int offset, const char *name, int namelen) { int depth; FDT_CHECK_HEADER(fdt); for (depth = 0; (offset >= 0) && (depth >= 0); offset = fdt_next_node(fdt, offset, &depth)) if ((depth == 1) && fdt_nodename_eq_(fdt, offset, name, namelen)) return offset; if (depth < 0) return -FDT_ERR_NOTFOUND; return offset; /* error */ } int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name) { return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); } int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen) { const char *end = path + namelen; const char *p = path; int offset = 0; FDT_CHECK_HEADER(fdt); /* see if we have an alias */ if (*path != '/') { const char *q = memchr(path, '/', end - p); if (!q) q = end; p = fdt_get_alias_namelen(fdt, p, q - p); if (!p) return -FDT_ERR_BADPATH; offset = fdt_path_offset(fdt, p); p = q; } while (p < end) { const char *q; while (*p == '/') { p++; if (p == end) return offset; } q = memchr(p, '/', end - p); if (! q) q = end; offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); if (offset < 0) return offset; p = q; } return offset; } int fdt_path_offset(const void *fdt, const char *path) { return fdt_path_offset_namelen(fdt, path, strlen(path)); } const char *fdt_get_name(const void *fdt, int nodeoffset, int *len) { const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset); const char *nameptr; int err; if (((err = fdt_check_header(fdt)) != 0) || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0)) goto fail; nameptr = nh->name; if (fdt_version(fdt) < 0x10) { /* * For old FDT versions, match the naming conventions of V16: * give only the leaf name (after all /). The actual tree * contents are loosely checked. */ const char *leaf; leaf = strrchr(nameptr, '/'); if (leaf == NULL) { err = -FDT_ERR_BADSTRUCTURE; goto fail; } nameptr = leaf+1; } if (len) *len = strlen(nameptr); return nameptr; fail: if (len) *len = err; return NULL; } int fdt_first_property_offset(const void *fdt, int nodeoffset) { int offset; if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) return offset; return nextprop_(fdt, offset); } int fdt_next_property_offset(const void *fdt, int offset) { if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0) return offset; return nextprop_(fdt, offset); } static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt, int offset, int *lenp) { int err; const struct fdt_property *prop; if ((err = fdt_check_prop_offset_(fdt, offset)) < 0) { if (lenp) *lenp = err; return NULL; } prop = fdt_offset_ptr_(fdt, offset); if (lenp) *lenp = fdt32_to_cpu(prop->len); return prop; } const struct fdt_property *fdt_get_property_by_offset(const void *fdt, int offset, int *lenp) { /* Prior to version 16, properties may need realignment * and this API does not work. fdt_getprop_*() will, however. */ if (fdt_version(fdt) < 0x10) { if (lenp) *lenp = -FDT_ERR_BADVERSION; return NULL; } return fdt_get_property_by_offset_(fdt, offset, lenp); } static const struct fdt_property *fdt_get_property_namelen_(const void *fdt, int offset, const char *name, int namelen, int *lenp, int *poffset) { for (offset = fdt_first_property_offset(fdt, offset); (offset >= 0); (offset = fdt_next_property_offset(fdt, offset))) { const struct fdt_property *prop; if (!(prop = fdt_get_property_by_offset_(fdt, offset, lenp))) { offset = -FDT_ERR_INTERNAL; break; } if (fdt_string_eq_(fdt, fdt32_to_cpu(prop->nameoff), name, namelen)) { if (poffset) *poffset = offset; return prop; } } if (lenp) *lenp = offset; return NULL; } const struct fdt_property *fdt_get_property_namelen(const void *fdt, int offset, const char *name, int namelen, int *lenp) { /* Prior to version 16, properties may need realignment * and this API does not work. fdt_getprop_*() will, however. */ if (fdt_version(fdt) < 0x10) { if (lenp) *lenp = -FDT_ERR_BADVERSION; return NULL; } return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp, NULL); } const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset, const char *name, int *lenp) { return fdt_get_property_namelen(fdt, nodeoffset, name, strlen(name), lenp); } const void *fdt_getprop_namelen(const void *fdt, int nodeoffset, const char *name, int namelen, int *lenp) { int poffset; const struct fdt_property *prop; prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp, &poffset); if (!prop) return NULL; /* Handle realignment */ if (fdt_version(fdt) < 0x10 && (poffset + sizeof(*prop)) % 8 && fdt32_to_cpu(prop->len) >= 8) return prop->data + 4; return prop->data; } const void *fdt_getprop_by_offset(const void *fdt, int offset, const char **namep, int *lenp) { const struct fdt_property *prop; prop = fdt_get_property_by_offset_(fdt, offset, lenp); if (!prop) return NULL; if (namep) *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); /* Handle realignment */ if (fdt_version(fdt) < 0x10 && (offset + sizeof(*prop)) % 8 && fdt32_to_cpu(prop->len) >= 8) return prop->data + 4; return prop->data; } const void *fdt_getprop(const void *fdt, int nodeoffset, const char *name, int *lenp) { return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); } uint32_t fdt_get_phandle(const void *fdt, int nodeoffset) { const fdt32_t *php; int len; /* FIXME: This is a bit sub-optimal, since we potentially scan * over all the properties twice. */ php = fdt_getprop(fdt, nodeoffset, "phandle", &len); if (!php || (len != sizeof(*php))) { php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); if (!php || (len != sizeof(*php))) return 0; } return fdt32_to_cpu(*php); } const char *fdt_get_alias_namelen(const void *fdt, const char *name, int namelen) { int aliasoffset; aliasoffset = fdt_path_offset(fdt, "/aliases"); if (aliasoffset < 0) return NULL; return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); } const char *fdt_get_alias(const void *fdt, const char *name) { return fdt_get_alias_namelen(fdt, name, strlen(name)); } int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) { int pdepth = 0, p = 0; int offset, depth, namelen; const char *name; FDT_CHECK_HEADER(fdt); if (buflen < 2) return -FDT_ERR_NOSPACE; for (offset = 0, depth = 0; (offset >= 0) && (offset <= nodeoffset); offset = fdt_next_node(fdt, offset, &depth)) { while (pdepth > depth) { do { p--; } while (buf[p-1] != '/'); pdepth--; } if (pdepth >= depth) { name = fdt_get_name(fdt, offset, &namelen); if (!name) return namelen; if ((p + namelen + 1) <= buflen) { memcpy(buf + p, name, namelen); p += namelen; buf[p++] = '/'; pdepth++; } } if (offset == nodeoffset) { if (pdepth < (depth + 1)) return -FDT_ERR_NOSPACE; if (p > 1) /* special case so that root path is "/", not "" */ p--; buf[p] = '\0'; return 0; } } if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) return -FDT_ERR_BADOFFSET; else if (offset == -FDT_ERR_BADOFFSET) return -FDT_ERR_BADSTRUCTURE; return offset; /* error from fdt_next_node() */ } int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, int supernodedepth, int *nodedepth) { int offset, depth; int supernodeoffset = -FDT_ERR_INTERNAL; FDT_CHECK_HEADER(fdt); if (supernodedepth < 0) return -FDT_ERR_NOTFOUND; for (offset = 0, depth = 0; (offset >= 0) && (offset <= nodeoffset); offset = fdt_next_node(fdt, offset, &depth)) { if (depth == supernodedepth) supernodeoffset = offset; if (offset == nodeoffset) { if (nodedepth) *nodedepth = depth; if (supernodedepth > depth) return -FDT_ERR_NOTFOUND; else return supernodeoffset; } } if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) return -FDT_ERR_BADOFFSET; else if (offset == -FDT_ERR_BADOFFSET) return -FDT_ERR_BADSTRUCTURE; return offset; /* error from fdt_next_node() */ } int fdt_node_depth(const void *fdt, int nodeoffset) { int nodedepth; int err; err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); if (err) return (err < 0) ? err : -FDT_ERR_INTERNAL; return nodedepth; } int fdt_parent_offset(const void *fdt, int nodeoffset) { int nodedepth = fdt_node_depth(fdt, nodeoffset); if (nodedepth < 0) return nodedepth; return fdt_supernode_atdepth_offset(fdt, nodeoffset, nodedepth - 1, NULL); } int fdt_node_offset_by_prop_value(const void *fdt, int startoffset, const char *propname, const void *propval, int proplen) { int offset; const void *val; int len; FDT_CHECK_HEADER(fdt); /* FIXME: The algorithm here is pretty horrible: we scan each * property of a node in fdt_getprop(), then if that didn't * find what we want, we scan over them again making our way * to the next node. Still it's the easiest to implement * approach; performance can come later. */ for (offset = fdt_next_node(fdt, startoffset, NULL); offset >= 0; offset = fdt_next_node(fdt, offset, NULL)) { val = fdt_getprop(fdt, offset, propname, &len); if (val && (len == proplen) && (memcmp(val, propval, len) == 0)) return offset; } return offset; /* error from fdt_next_node() */ } int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) { int offset; if ((phandle == 0) || (phandle == -1)) return -FDT_ERR_BADPHANDLE; FDT_CHECK_HEADER(fdt); /* FIXME: The algorithm here is pretty horrible: we * potentially scan each property of a node in * fdt_get_phandle(), then if that didn't find what * we want, we scan over them again making our way to the next * node. Still it's the easiest to implement approach; * performance can come later. */ for (offset = fdt_next_node(fdt, -1, NULL); offset >= 0; offset = fdt_next_node(fdt, offset, NULL)) { if (fdt_get_phandle(fdt, offset) == phandle) return offset; } return offset; /* error from fdt_next_node() */ } int fdt_stringlist_contains(const char *strlist, int listlen, const char *str) { int len = strlen(str); const char *p; while (listlen >= len) { if (memcmp(str, strlist, len+1) == 0) return 1; p = memchr(strlist, '\0', listlen); if (!p) return 0; /* malformed strlist.. */ listlen -= (p-strlist) + 1; strlist = p + 1; } return 0; } int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property) { const char *list, *end; int length, count = 0; list = fdt_getprop(fdt, nodeoffset, property, &length); if (!list) return length; end = list + length; while (list < end) { length = strnlen(list, end - list) + 1; /* Abort if the last string isn't properly NUL-terminated. */ if (list + length > end) return -FDT_ERR_BADVALUE; list += length; count++; } return count; } int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property, const char *string) { int length, len, idx = 0; const char *list, *end; list = fdt_getprop(fdt, nodeoffset, property, &length); if (!list) return length; len = strlen(string) + 1; end = list + length; while (list < end) { length = strnlen(list, end - list) + 1; /* Abort if the last string isn't properly NUL-terminated. */ if (list + length > end) return -FDT_ERR_BADVALUE; if (length == len && memcmp(list, string, length) == 0) return idx; list += length; idx++; } return -FDT_ERR_NOTFOUND; } const char *fdt_stringlist_get(const void *fdt, int nodeoffset, const char *property, int idx, int *lenp) { const char *list, *end; int length; list = fdt_getprop(fdt, nodeoffset, property, &length); if (!list) { if (lenp) *lenp = length; return NULL; } end = list + length; while (list < end) { length = strnlen(list, end - list) + 1; /* Abort if the last string isn't properly NUL-terminated. */ if (list + length > end) { if (lenp) *lenp = -FDT_ERR_BADVALUE; return NULL; } if (idx == 0) { if (lenp) *lenp = length - 1; return list; } list += length; idx--; } if (lenp) *lenp = -FDT_ERR_NOTFOUND; return NULL; } int fdt_node_check_compatible(const void *fdt, int nodeoffset, const char *compatible) { const void *prop; int len; prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); if (!prop) return len; return !fdt_stringlist_contains(prop, len, compatible); } int fdt_node_offset_by_compatible(const void *fdt, int startoffset, const char *compatible) { int offset, err; FDT_CHECK_HEADER(fdt); /* FIXME: The algorithm here is pretty horrible: we scan each * property of a node in fdt_node_check_compatible(), then if * that didn't find what we want, we scan over them again * making our way to the next node. Still it's the easiest to * implement approach; performance can come later. */ for (offset = fdt_next_node(fdt, startoffset, NULL); offset >= 0; offset = fdt_next_node(fdt, offset, NULL)) { err = fdt_node_check_compatible(fdt, offset, compatible); if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) return err; else if (err == 0) return offset; } return offset; /* error from fdt_next_node() */ } trusted-firmware-a-2.2/lib/libfdt/fdt_rw.c000066400000000000000000000317641355360272700205670ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" static int fdt_blocks_misordered_(const void *fdt, int mem_rsv_size, int struct_size) { return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8)) || (fdt_off_dt_struct(fdt) < (fdt_off_mem_rsvmap(fdt) + mem_rsv_size)) || (fdt_off_dt_strings(fdt) < (fdt_off_dt_struct(fdt) + struct_size)) || (fdt_totalsize(fdt) < (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt))); } static int fdt_rw_check_header_(void *fdt) { FDT_CHECK_HEADER(fdt); if (fdt_version(fdt) < 17) return -FDT_ERR_BADVERSION; if (fdt_blocks_misordered_(fdt, sizeof(struct fdt_reserve_entry), fdt_size_dt_struct(fdt))) return -FDT_ERR_BADLAYOUT; if (fdt_version(fdt) > 17) fdt_set_version(fdt, 17); return 0; } #define FDT_RW_CHECK_HEADER(fdt) \ { \ int err_; \ if ((err_ = fdt_rw_check_header_(fdt)) != 0) \ return err_; \ } static inline int fdt_data_size_(void *fdt) { return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); } static int fdt_splice_(void *fdt, void *splicepoint, int oldlen, int newlen) { char *p = splicepoint; char *end = (char *)fdt + fdt_data_size_(fdt); if (((p + oldlen) < p) || ((p + oldlen) > end)) return -FDT_ERR_BADOFFSET; if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt)) return -FDT_ERR_BADOFFSET; if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt))) return -FDT_ERR_NOSPACE; memmove(p + newlen, p + oldlen, end - p - oldlen); return 0; } static int fdt_splice_mem_rsv_(void *fdt, struct fdt_reserve_entry *p, int oldn, int newn) { int delta = (newn - oldn) * sizeof(*p); int err; err = fdt_splice_(fdt, p, oldn * sizeof(*p), newn * sizeof(*p)); if (err) return err; fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta); fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); return 0; } static int fdt_splice_struct_(void *fdt, void *p, int oldlen, int newlen) { int delta = newlen - oldlen; int err; if ((err = fdt_splice_(fdt, p, oldlen, newlen))) return err; fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta); fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta); return 0; } static int fdt_splice_string_(void *fdt, int newlen) { void *p = (char *)fdt + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt); int err; if ((err = fdt_splice_(fdt, p, 0, newlen))) return err; fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen); return 0; } static int fdt_find_add_string_(void *fdt, const char *s) { char *strtab = (char *)fdt + fdt_off_dt_strings(fdt); const char *p; char *new; int len = strlen(s) + 1; int err; p = fdt_find_string_(strtab, fdt_size_dt_strings(fdt), s); if (p) /* found it */ return (p - strtab); new = strtab + fdt_size_dt_strings(fdt); err = fdt_splice_string_(fdt, len); if (err) return err; memcpy(new, s, len); return (new - strtab); } int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size) { struct fdt_reserve_entry *re; int err; FDT_RW_CHECK_HEADER(fdt); re = fdt_mem_rsv_w_(fdt, fdt_num_mem_rsv(fdt)); err = fdt_splice_mem_rsv_(fdt, re, 0, 1); if (err) return err; re->address = cpu_to_fdt64(address); re->size = cpu_to_fdt64(size); return 0; } int fdt_del_mem_rsv(void *fdt, int n) { struct fdt_reserve_entry *re = fdt_mem_rsv_w_(fdt, n); FDT_RW_CHECK_HEADER(fdt); if (n >= fdt_num_mem_rsv(fdt)) return -FDT_ERR_NOTFOUND; return fdt_splice_mem_rsv_(fdt, re, 1, 0); } static int fdt_resize_property_(void *fdt, int nodeoffset, const char *name, int len, struct fdt_property **prop) { int oldlen; int err; *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); if (!*prop) return oldlen; if ((err = fdt_splice_struct_(fdt, (*prop)->data, FDT_TAGALIGN(oldlen), FDT_TAGALIGN(len)))) return err; (*prop)->len = cpu_to_fdt32(len); return 0; } static int fdt_add_property_(void *fdt, int nodeoffset, const char *name, int len, struct fdt_property **prop) { int proplen; int nextoffset; int namestroff; int err; if ((nextoffset = fdt_check_node_offset_(fdt, nodeoffset)) < 0) return nextoffset; namestroff = fdt_find_add_string_(fdt, name); if (namestroff < 0) return namestroff; *prop = fdt_offset_ptr_w_(fdt, nextoffset); proplen = sizeof(**prop) + FDT_TAGALIGN(len); err = fdt_splice_struct_(fdt, *prop, 0, proplen); if (err) return err; (*prop)->tag = cpu_to_fdt32(FDT_PROP); (*prop)->nameoff = cpu_to_fdt32(namestroff); (*prop)->len = cpu_to_fdt32(len); return 0; } int fdt_set_name(void *fdt, int nodeoffset, const char *name) { char *namep; int oldlen, newlen; int err; FDT_RW_CHECK_HEADER(fdt); namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen); if (!namep) return oldlen; newlen = strlen(name); err = fdt_splice_struct_(fdt, namep, FDT_TAGALIGN(oldlen+1), FDT_TAGALIGN(newlen+1)); if (err) return err; memcpy(namep, name, newlen+1); return 0; } int fdt_setprop_placeholder(void *fdt, int nodeoffset, const char *name, int len, void **prop_data) { struct fdt_property *prop; int err; FDT_RW_CHECK_HEADER(fdt); err = fdt_resize_property_(fdt, nodeoffset, name, len, &prop); if (err == -FDT_ERR_NOTFOUND) err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); if (err) return err; *prop_data = prop->data; return 0; } int fdt_setprop(void *fdt, int nodeoffset, const char *name, const void *val, int len) { void *prop_data; int err; err = fdt_setprop_placeholder(fdt, nodeoffset, name, len, &prop_data); if (err) return err; if (len) memcpy(prop_data, val, len); return 0; } int fdt_appendprop(void *fdt, int nodeoffset, const char *name, const void *val, int len) { struct fdt_property *prop; int err, oldlen, newlen; FDT_RW_CHECK_HEADER(fdt); prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen); if (prop) { newlen = len + oldlen; err = fdt_splice_struct_(fdt, prop->data, FDT_TAGALIGN(oldlen), FDT_TAGALIGN(newlen)); if (err) return err; prop->len = cpu_to_fdt32(newlen); memcpy(prop->data + oldlen, val, len); } else { err = fdt_add_property_(fdt, nodeoffset, name, len, &prop); if (err) return err; memcpy(prop->data, val, len); } return 0; } int fdt_delprop(void *fdt, int nodeoffset, const char *name) { struct fdt_property *prop; int len, proplen; FDT_RW_CHECK_HEADER(fdt); prop = fdt_get_property_w(fdt, nodeoffset, name, &len); if (!prop) return len; proplen = sizeof(*prop) + FDT_TAGALIGN(len); return fdt_splice_struct_(fdt, prop, proplen, 0); } int fdt_add_subnode_namelen(void *fdt, int parentoffset, const char *name, int namelen) { struct fdt_node_header *nh; int offset, nextoffset; int nodelen; int err; uint32_t tag; fdt32_t *endtag; FDT_RW_CHECK_HEADER(fdt); offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen); if (offset >= 0) return -FDT_ERR_EXISTS; else if (offset != -FDT_ERR_NOTFOUND) return offset; /* Try to place the new node after the parent's properties */ fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */ do { offset = nextoffset; tag = fdt_next_tag(fdt, offset, &nextoffset); } while ((tag == FDT_PROP) || (tag == FDT_NOP)); nh = fdt_offset_ptr_w_(fdt, offset); nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE; err = fdt_splice_struct_(fdt, nh, 0, nodelen); if (err) return err; nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); memset(nh->name, 0, FDT_TAGALIGN(namelen+1)); memcpy(nh->name, name, namelen); endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE); *endtag = cpu_to_fdt32(FDT_END_NODE); return offset; } int fdt_add_subnode(void *fdt, int parentoffset, const char *name) { return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name)); } int fdt_del_node(void *fdt, int nodeoffset) { int endoffset; FDT_RW_CHECK_HEADER(fdt); endoffset = fdt_node_end_offset_(fdt, nodeoffset); if (endoffset < 0) return endoffset; return fdt_splice_struct_(fdt, fdt_offset_ptr_w_(fdt, nodeoffset), endoffset - nodeoffset, 0); } static void fdt_packblocks_(const char *old, char *new, int mem_rsv_size, int struct_size) { int mem_rsv_off, struct_off, strings_off; mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8); struct_off = mem_rsv_off + mem_rsv_size; strings_off = struct_off + struct_size; memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size); fdt_set_off_mem_rsvmap(new, mem_rsv_off); memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size); fdt_set_off_dt_struct(new, struct_off); fdt_set_size_dt_struct(new, struct_size); memmove(new + strings_off, old + fdt_off_dt_strings(old), fdt_size_dt_strings(old)); fdt_set_off_dt_strings(new, strings_off); fdt_set_size_dt_strings(new, fdt_size_dt_strings(old)); } int fdt_open_into(const void *fdt, void *buf, int bufsize) { int err; int mem_rsv_size, struct_size; int newsize; const char *fdtstart = fdt; const char *fdtend = fdtstart + fdt_totalsize(fdt); char *tmp; FDT_CHECK_HEADER(fdt); mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); if (fdt_version(fdt) >= 17) { struct_size = fdt_size_dt_struct(fdt); } else { struct_size = 0; while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END) ; if (struct_size < 0) return struct_size; } if (!fdt_blocks_misordered_(fdt, mem_rsv_size, struct_size)) { /* no further work necessary */ err = fdt_move(fdt, buf, bufsize); if (err) return err; fdt_set_version(buf, 17); fdt_set_size_dt_struct(buf, struct_size); fdt_set_totalsize(buf, bufsize); return 0; } /* Need to reorder */ newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size + struct_size + fdt_size_dt_strings(fdt); if (bufsize < newsize) return -FDT_ERR_NOSPACE; /* First attempt to build converted tree at beginning of buffer */ tmp = buf; /* But if that overlaps with the old tree... */ if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) { /* Try right after the old tree instead */ tmp = (char *)(uintptr_t)fdtend; if ((tmp + newsize) > ((char *)buf + bufsize)) return -FDT_ERR_NOSPACE; } fdt_packblocks_(fdt, tmp, mem_rsv_size, struct_size); memmove(buf, tmp, newsize); fdt_set_magic(buf, FDT_MAGIC); fdt_set_totalsize(buf, bufsize); fdt_set_version(buf, 17); fdt_set_last_comp_version(buf, 16); fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt)); return 0; } int fdt_pack(void *fdt) { int mem_rsv_size; FDT_RW_CHECK_HEADER(fdt); mem_rsv_size = (fdt_num_mem_rsv(fdt)+1) * sizeof(struct fdt_reserve_entry); fdt_packblocks_(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt)); fdt_set_totalsize(fdt, fdt_data_size_(fdt)); return 0; } trusted-firmware-a-2.2/lib/libfdt/fdt_strerror.c000066400000000000000000000070341355360272700220120ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" struct fdt_errtabent { const char *str; }; #define FDT_ERRTABENT(val) \ [(val)] = { .str = #val, } static struct fdt_errtabent fdt_errtable[] = { FDT_ERRTABENT(FDT_ERR_NOTFOUND), FDT_ERRTABENT(FDT_ERR_EXISTS), FDT_ERRTABENT(FDT_ERR_NOSPACE), FDT_ERRTABENT(FDT_ERR_BADOFFSET), FDT_ERRTABENT(FDT_ERR_BADPATH), FDT_ERRTABENT(FDT_ERR_BADPHANDLE), FDT_ERRTABENT(FDT_ERR_BADSTATE), FDT_ERRTABENT(FDT_ERR_TRUNCATED), FDT_ERRTABENT(FDT_ERR_BADMAGIC), FDT_ERRTABENT(FDT_ERR_BADVERSION), FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE), FDT_ERRTABENT(FDT_ERR_BADLAYOUT), FDT_ERRTABENT(FDT_ERR_INTERNAL), FDT_ERRTABENT(FDT_ERR_BADNCELLS), FDT_ERRTABENT(FDT_ERR_BADVALUE), FDT_ERRTABENT(FDT_ERR_BADOVERLAY), FDT_ERRTABENT(FDT_ERR_NOPHANDLES), }; #define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0])) const char *fdt_strerror(int errval) { if (errval > 0) return ""; else if (errval == 0) return ""; else if (errval > -FDT_ERRTABSIZE) { const char *s = fdt_errtable[-errval].str; if (s) return s; } return ""; } trusted-firmware-a-2.2/lib/libfdt/fdt_sw.c000066400000000000000000000176341355360272700205700ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" static int fdt_sw_check_header_(void *fdt) { if (fdt_magic(fdt) != FDT_SW_MAGIC) return -FDT_ERR_BADMAGIC; /* FIXME: should check more details about the header state */ return 0; } #define FDT_SW_CHECK_HEADER(fdt) \ { \ int err; \ if ((err = fdt_sw_check_header_(fdt)) != 0) \ return err; \ } static void *fdt_grab_space_(void *fdt, size_t len) { int offset = fdt_size_dt_struct(fdt); int spaceleft; spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt) - fdt_size_dt_strings(fdt); if ((offset + len < offset) || (offset + len > spaceleft)) return NULL; fdt_set_size_dt_struct(fdt, offset + len); return fdt_offset_ptr_w_(fdt, offset); } int fdt_create(void *buf, int bufsize) { void *fdt = buf; if (bufsize < sizeof(struct fdt_header)) return -FDT_ERR_NOSPACE; memset(buf, 0, bufsize); fdt_set_magic(fdt, FDT_SW_MAGIC); fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION); fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION); fdt_set_totalsize(fdt, bufsize); fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header), sizeof(struct fdt_reserve_entry))); fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt)); fdt_set_off_dt_strings(fdt, bufsize); return 0; } int fdt_resize(void *fdt, void *buf, int bufsize) { size_t headsize, tailsize; char *oldtail, *newtail; FDT_SW_CHECK_HEADER(fdt); headsize = fdt_off_dt_struct(fdt); tailsize = fdt_size_dt_strings(fdt); if ((headsize + tailsize) > bufsize) return -FDT_ERR_NOSPACE; oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize; newtail = (char *)buf + bufsize - tailsize; /* Two cases to avoid clobbering data if the old and new * buffers partially overlap */ if (buf <= fdt) { memmove(buf, fdt, headsize); memmove(newtail, oldtail, tailsize); } else { memmove(newtail, oldtail, tailsize); memmove(buf, fdt, headsize); } fdt_set_off_dt_strings(buf, bufsize); fdt_set_totalsize(buf, bufsize); return 0; } int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size) { struct fdt_reserve_entry *re; int offset; FDT_SW_CHECK_HEADER(fdt); if (fdt_size_dt_struct(fdt)) return -FDT_ERR_BADSTATE; offset = fdt_off_dt_struct(fdt); if ((offset + sizeof(*re)) > fdt_totalsize(fdt)) return -FDT_ERR_NOSPACE; re = (struct fdt_reserve_entry *)((char *)fdt + offset); re->address = cpu_to_fdt64(addr); re->size = cpu_to_fdt64(size); fdt_set_off_dt_struct(fdt, offset + sizeof(*re)); return 0; } int fdt_finish_reservemap(void *fdt) { return fdt_add_reservemap_entry(fdt, 0, 0); } int fdt_begin_node(void *fdt, const char *name) { struct fdt_node_header *nh; int namelen = strlen(name) + 1; FDT_SW_CHECK_HEADER(fdt); nh = fdt_grab_space_(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen)); if (! nh) return -FDT_ERR_NOSPACE; nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE); memcpy(nh->name, name, namelen); return 0; } int fdt_end_node(void *fdt) { fdt32_t *en; FDT_SW_CHECK_HEADER(fdt); en = fdt_grab_space_(fdt, FDT_TAGSIZE); if (! en) return -FDT_ERR_NOSPACE; *en = cpu_to_fdt32(FDT_END_NODE); return 0; } static int fdt_find_add_string_(void *fdt, const char *s) { char *strtab = (char *)fdt + fdt_totalsize(fdt); const char *p; int strtabsize = fdt_size_dt_strings(fdt); int len = strlen(s) + 1; int struct_top, offset; p = fdt_find_string_(strtab - strtabsize, strtabsize, s); if (p) return p - strtab; /* Add it */ offset = -strtabsize - len; struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); if (fdt_totalsize(fdt) + offset < struct_top) return 0; /* no more room :( */ memcpy(strtab + offset, s, len); fdt_set_size_dt_strings(fdt, strtabsize + len); return offset; } int fdt_property_placeholder(void *fdt, const char *name, int len, void **valp) { struct fdt_property *prop; int nameoff; FDT_SW_CHECK_HEADER(fdt); nameoff = fdt_find_add_string_(fdt, name); if (nameoff == 0) return -FDT_ERR_NOSPACE; prop = fdt_grab_space_(fdt, sizeof(*prop) + FDT_TAGALIGN(len)); if (! prop) return -FDT_ERR_NOSPACE; prop->tag = cpu_to_fdt32(FDT_PROP); prop->nameoff = cpu_to_fdt32(nameoff); prop->len = cpu_to_fdt32(len); *valp = prop->data; return 0; } int fdt_property(void *fdt, const char *name, const void *val, int len) { void *ptr; int ret; ret = fdt_property_placeholder(fdt, name, len, &ptr); if (ret) return ret; memcpy(ptr, val, len); return 0; } int fdt_finish(void *fdt) { char *p = (char *)fdt; fdt32_t *end; int oldstroffset, newstroffset; uint32_t tag; int offset, nextoffset; FDT_SW_CHECK_HEADER(fdt); /* Add terminator */ end = fdt_grab_space_(fdt, sizeof(*end)); if (! end) return -FDT_ERR_NOSPACE; *end = cpu_to_fdt32(FDT_END); /* Relocate the string table */ oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt); newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt); memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt)); fdt_set_off_dt_strings(fdt, newstroffset); /* Walk the structure, correcting string offsets */ offset = 0; while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) { if (tag == FDT_PROP) { struct fdt_property *prop = fdt_offset_ptr_w_(fdt, offset); int nameoff; nameoff = fdt32_to_cpu(prop->nameoff); nameoff += fdt_size_dt_strings(fdt); prop->nameoff = cpu_to_fdt32(nameoff); } offset = nextoffset; } if (nextoffset < 0) return nextoffset; /* Finally, adjust the header */ fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt)); fdt_set_magic(fdt, FDT_MAGIC); return 0; } trusted-firmware-a-2.2/lib/libfdt/fdt_wip.c000066400000000000000000000100751355360272700207260ustar00rootroot00000000000000/* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "libfdt_env.h" #include #include #include "libfdt_internal.h" int fdt_setprop_inplace_namelen_partial(void *fdt, int nodeoffset, const char *name, int namelen, uint32_t idx, const void *val, int len) { void *propval; int proplen; propval = fdt_getprop_namelen_w(fdt, nodeoffset, name, namelen, &proplen); if (!propval) return proplen; if (proplen < (len + idx)) return -FDT_ERR_NOSPACE; memcpy((char *)propval + idx, val, len); return 0; } int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name, const void *val, int len) { const void *propval; int proplen; propval = fdt_getprop(fdt, nodeoffset, name, &proplen); if (!propval) return proplen; if (proplen != len) return -FDT_ERR_NOSPACE; return fdt_setprop_inplace_namelen_partial(fdt, nodeoffset, name, strlen(name), 0, val, len); } static void fdt_nop_region_(void *start, int len) { fdt32_t *p; for (p = start; (char *)p < ((char *)start + len); p++) *p = cpu_to_fdt32(FDT_NOP); } int fdt_nop_property(void *fdt, int nodeoffset, const char *name) { struct fdt_property *prop; int len; prop = fdt_get_property_w(fdt, nodeoffset, name, &len); if (!prop) return len; fdt_nop_region_(prop, len + sizeof(*prop)); return 0; } int fdt_node_end_offset_(void *fdt, int offset) { int depth = 0; while ((offset >= 0) && (depth >= 0)) offset = fdt_next_node(fdt, offset, &depth); return offset; } int fdt_nop_node(void *fdt, int nodeoffset) { int endoffset; endoffset = fdt_node_end_offset_(fdt, nodeoffset); if (endoffset < 0) return endoffset; fdt_nop_region_(fdt_offset_ptr_w(fdt, nodeoffset, 0), endoffset - nodeoffset); return 0; } trusted-firmware-a-2.2/lib/libfdt/libfdt.mk000066400000000000000000000005661355360272700207270ustar00rootroot00000000000000# # Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # LIBFDT_SRCS := $(addprefix lib/libfdt/, \ fdt.c \ fdt_addresses.c \ fdt_empty_tree.c \ fdt_ro.c \ fdt_rw.c \ fdt_strerror.c \ fdt_sw.c \ fdt_wip.c) \ INCLUDES += -Iinclude/lib/libfdt $(eval $(call MAKE_LIB,fdt)) trusted-firmware-a-2.2/lib/libfdt/libfdt_internal.h000066400000000000000000000071241355360272700224400ustar00rootroot00000000000000#ifndef LIBFDT_INTERNAL_H #define LIBFDT_INTERNAL_H /* * libfdt - Flat Device Tree manipulation * Copyright (C) 2006 David Gibson, IBM Corporation. * * libfdt is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * * a) This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301 USA * * Alternatively, * * b) Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * 2. Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #define FDT_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) #define FDT_TAGALIGN(x) (FDT_ALIGN((x), FDT_TAGSIZE)) #define FDT_CHECK_HEADER(fdt) \ { \ int err_; \ if ((err_ = fdt_check_header(fdt)) != 0) \ return err_; \ } int fdt_check_node_offset_(const void *fdt, int offset); int fdt_check_prop_offset_(const void *fdt, int offset); const char *fdt_find_string_(const char *strtab, int tabsize, const char *s); int fdt_node_end_offset_(void *fdt, int nodeoffset); static inline const void *fdt_offset_ptr_(const void *fdt, int offset) { return (const char *)fdt + fdt_off_dt_struct(fdt) + offset; } static inline void *fdt_offset_ptr_w_(void *fdt, int offset) { return (void *)(uintptr_t)fdt_offset_ptr_(fdt, offset); } static inline const struct fdt_reserve_entry *fdt_mem_rsv_(const void *fdt, int n) { const struct fdt_reserve_entry *rsv_table = (const struct fdt_reserve_entry *) ((const char *)fdt + fdt_off_mem_rsvmap(fdt)); return rsv_table + n; } static inline struct fdt_reserve_entry *fdt_mem_rsv_w_(void *fdt, int n) { return (void *)(uintptr_t)fdt_mem_rsv_(fdt, n); } #define FDT_SW_MAGIC (~FDT_MAGIC) #endif /* LIBFDT_INTERNAL_H */ trusted-firmware-a-2.2/lib/locks/000077500000000000000000000000001355360272700167725ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/locks/bakery/000077500000000000000000000000001355360272700202475ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/locks/bakery/bakery_lock_coherent.c000066400000000000000000000124221355360272700245700ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* * Functions in this file implement Bakery Algorithm for mutual exclusion with the * bakery lock data structures in coherent memory. * * ARM architecture offers a family of exclusive access instructions to * efficiently implement mutual exclusion with hardware support. However, as * well as depending on external hardware, the these instructions have defined * behavior only on certain memory types (cacheable and Normal memory in * particular; see ARMv8 Architecture Reference Manual section B2.10). Use cases * in trusted firmware are such that mutual exclusion implementation cannot * expect that accesses to the lock have the specific type required by the * architecture for these primitives to function (for example, not all * contenders may have address translation enabled). * * This implementation does not use mutual exclusion primitives. It expects * memory regions where the locks reside to be fully ordered and coherent * (either by disabling address translation, or by assigning proper attributes * when translation is enabled). * * Note that the ARM architecture guarantees single-copy atomicity for aligned * accesses regardless of status of address translation. */ #define assert_bakery_entry_valid(_entry, _bakery) do { \ assert((_bakery) != NULL); \ assert((_entry) < BAKERY_LOCK_MAX_CPUS); \ } while (false) /* Obtain a ticket for a given CPU */ static unsigned int bakery_get_ticket(bakery_lock_t *bakery, unsigned int me) { unsigned int my_ticket, their_ticket; unsigned int they; /* Prevent recursive acquisition */ assert(bakery_ticket_number(bakery->lock_data[me]) == 0U); /* * Flag that we're busy getting our ticket. All CPUs are iterated in the * order of their ordinal position to decide the maximum ticket value * observed so far. Our priority is set to be greater than the maximum * observed priority * * Note that it's possible that more than one contender gets the same * ticket value. That's OK as the lock is acquired based on the priority * value, not the ticket value alone. */ my_ticket = 0U; bakery->lock_data[me] = make_bakery_data(CHOOSING_TICKET, my_ticket); for (they = 0U; they < BAKERY_LOCK_MAX_CPUS; they++) { their_ticket = bakery_ticket_number(bakery->lock_data[they]); if (their_ticket > my_ticket) my_ticket = their_ticket; } /* * Compute ticket; then signal to other contenders waiting for us to * finish calculating our ticket value that we're done */ ++my_ticket; bakery->lock_data[me] = make_bakery_data(CHOSEN_TICKET, my_ticket); return my_ticket; } /* * Acquire bakery lock * * Contending CPUs need first obtain a non-zero ticket and then calculate * priority value. A contending CPU iterate over all other CPUs in the platform, * which may be contending for the same lock, in the order of their ordinal * position (CPU0, CPU1 and so on). A non-contending CPU will have its ticket * (and priority) value as 0. The contending CPU compares its priority with that * of others'. The CPU with the highest priority (lowest numerical value) * acquires the lock */ void bakery_lock_get(bakery_lock_t *bakery) { unsigned int they, me; unsigned int my_ticket, my_prio, their_ticket; unsigned int their_bakery_data; me = plat_my_core_pos(); assert_bakery_entry_valid(me, bakery); /* Get a ticket */ my_ticket = bakery_get_ticket(bakery, me); /* * Now that we got our ticket, compute our priority value, then compare * with that of others, and proceed to acquire the lock */ my_prio = bakery_get_priority(my_ticket, me); for (they = 0U; they < BAKERY_LOCK_MAX_CPUS; they++) { if (me == they) continue; /* Wait for the contender to get their ticket */ do { their_bakery_data = bakery->lock_data[they]; } while (bakery_is_choosing(their_bakery_data)); /* * If the other party is a contender, they'll have non-zero * (valid) ticket value. If they do, compare priorities */ their_ticket = bakery_ticket_number(their_bakery_data); if ((their_ticket != 0U) && (bakery_get_priority(their_ticket, they) < my_prio)) { /* * They have higher priority (lower value). Wait for * their ticket value to change (either release the lock * to have it dropped to 0; or drop and probably content * again for the same lock to have an even higher value) */ do { wfe(); } while (their_ticket == bakery_ticket_number(bakery->lock_data[they])); } } /* * Lock acquired. Ensure that any reads from a shared resource in the * critical section read values after the lock is acquired. */ dmbld(); } /* Release the lock and signal contenders */ void bakery_lock_release(bakery_lock_t *bakery) { unsigned int me = plat_my_core_pos(); assert_bakery_entry_valid(me, bakery); assert(bakery_ticket_number(bakery->lock_data[me]) != 0U); /* * Ensure that other observers see any stores in the critical section * before releasing the lock. Release the lock by resetting ticket. * Then signal other waiting contenders. */ dmbst(); bakery->lock_data[me] = 0U; dsb(); sev(); } trusted-firmware-a-2.2/lib/locks/bakery/bakery_lock_normal.c000066400000000000000000000171231355360272700242540ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* * Functions in this file implement Bakery Algorithm for mutual exclusion with the * bakery lock data structures in cacheable and Normal memory. * * ARM architecture offers a family of exclusive access instructions to * efficiently implement mutual exclusion with hardware support. However, as * well as depending on external hardware, these instructions have defined * behavior only on certain memory types (cacheable and Normal memory in * particular; see ARMv8 Architecture Reference Manual section B2.10). Use cases * in trusted firmware are such that mutual exclusion implementation cannot * expect that accesses to the lock have the specific type required by the * architecture for these primitives to function (for example, not all * contenders may have address translation enabled). * * This implementation does not use mutual exclusion primitives. It expects * memory regions where the locks reside to be cacheable and Normal. * * Note that the ARM architecture guarantees single-copy atomicity for aligned * accesses regardless of status of address translation. */ #ifdef PLAT_PERCPU_BAKERY_LOCK_SIZE /* * Verify that the platform defined value for the per-cpu space for bakery locks is * a multiple of the cache line size, to prevent multiple CPUs writing to the same * bakery lock cache line * * Using this value, if provided, rather than the linker generated value results in * more efficient code */ CASSERT((PLAT_PERCPU_BAKERY_LOCK_SIZE & (CACHE_WRITEBACK_GRANULE - 1)) == 0, \ PLAT_PERCPU_BAKERY_LOCK_SIZE_not_cacheline_multiple); #define PERCPU_BAKERY_LOCK_SIZE (PLAT_PERCPU_BAKERY_LOCK_SIZE) #else /* * Use the linker defined symbol which has evaluated the size reqiurement. * This is not as efficient as using a platform defined constant */ IMPORT_SYM(uintptr_t, __PERCPU_BAKERY_LOCK_START__, BAKERY_LOCK_START); IMPORT_SYM(uintptr_t, __PERCPU_BAKERY_LOCK_END__, BAKERY_LOCK_END); #define PERCPU_BAKERY_LOCK_SIZE (BAKERY_LOCK_END - BAKERY_LOCK_START) #endif static inline bakery_lock_t *get_bakery_info(unsigned int cpu_ix, bakery_lock_t *lock) { return (bakery_info_t *)((uintptr_t)lock + cpu_ix * PERCPU_BAKERY_LOCK_SIZE); } static inline void write_cache_op(uintptr_t addr, bool cached) { if (cached) dccvac(addr); else dcivac(addr); dsbish(); } static inline void read_cache_op(uintptr_t addr, bool cached) { if (cached) dccivac(addr); } /* Helper function to check if the lock is acquired */ static inline bool is_lock_acquired(const bakery_info_t *my_bakery_info, int is_cached) { /* * Even though lock data is updated only by the owning cpu and * appropriate cache maintenance operations are performed, * if the previous update was done when the cpu was not participating * in coherency, then there is a chance that cache maintenance * operations were not propagated to all the caches in the system. * Hence do a `read_cache_op()` prior to read. */ read_cache_op((uintptr_t)my_bakery_info, is_cached); return bakery_ticket_number(my_bakery_info->lock_data) != 0U; } static unsigned int bakery_get_ticket(bakery_lock_t *lock, unsigned int me, int is_cached) { unsigned int my_ticket, their_ticket; unsigned int they; bakery_info_t *my_bakery_info, *their_bakery_info; /* * Obtain a reference to the bakery information for this cpu and ensure * it is not NULL. */ my_bakery_info = get_bakery_info(me, lock); assert(my_bakery_info != NULL); /* Prevent recursive acquisition.*/ assert(!is_lock_acquired(my_bakery_info, is_cached)); /* * Tell other contenders that we are through the bakery doorway i.e. * going to allocate a ticket for this cpu. */ my_ticket = 0U; my_bakery_info->lock_data = make_bakery_data(CHOOSING_TICKET, my_ticket); write_cache_op((uintptr_t)my_bakery_info, is_cached); /* * Iterate through the bakery information of each contender to allocate * the highest ticket number for this cpu. */ for (they = 0U; they < BAKERY_LOCK_MAX_CPUS; they++) { if (me == they) continue; /* * Get a reference to the other contender's bakery info and * ensure that a stale copy is not read. */ their_bakery_info = get_bakery_info(they, lock); assert(their_bakery_info != NULL); read_cache_op((uintptr_t)their_bakery_info, is_cached); /* * Update this cpu's ticket number if a higher ticket number is * seen */ their_ticket = bakery_ticket_number(their_bakery_info->lock_data); if (their_ticket > my_ticket) my_ticket = their_ticket; } /* * Compute ticket; then signal to other contenders waiting for us to * finish calculating our ticket value that we're done */ ++my_ticket; my_bakery_info->lock_data = make_bakery_data(CHOSEN_TICKET, my_ticket); write_cache_op((uintptr_t)my_bakery_info, is_cached); return my_ticket; } void bakery_lock_get(bakery_lock_t *lock) { unsigned int they, me, is_cached; unsigned int my_ticket, my_prio, their_ticket; bakery_info_t *their_bakery_info; unsigned int their_bakery_data; me = plat_my_core_pos(); #ifdef __aarch64__ is_cached = read_sctlr_el3() & SCTLR_C_BIT; #else is_cached = read_sctlr() & SCTLR_C_BIT; #endif /* Get a ticket */ my_ticket = bakery_get_ticket(lock, me, is_cached); /* * Now that we got our ticket, compute our priority value, then compare * with that of others, and proceed to acquire the lock */ my_prio = bakery_get_priority(my_ticket, me); for (they = 0U; they < BAKERY_LOCK_MAX_CPUS; they++) { if (me == they) continue; /* * Get a reference to the other contender's bakery info and * ensure that a stale copy is not read. */ their_bakery_info = get_bakery_info(they, lock); assert(their_bakery_info != NULL); /* Wait for the contender to get their ticket */ do { read_cache_op((uintptr_t)their_bakery_info, is_cached); their_bakery_data = their_bakery_info->lock_data; } while (bakery_is_choosing(their_bakery_data)); /* * If the other party is a contender, they'll have non-zero * (valid) ticket value. If they do, compare priorities */ their_ticket = bakery_ticket_number(their_bakery_data); if (their_ticket && (bakery_get_priority(their_ticket, they) < my_prio)) { /* * They have higher priority (lower value). Wait for * their ticket value to change (either release the lock * to have it dropped to 0; or drop and probably content * again for the same lock to have an even higher value) */ do { wfe(); read_cache_op((uintptr_t)their_bakery_info, is_cached); } while (their_ticket == bakery_ticket_number(their_bakery_info->lock_data)); } } /* * Lock acquired. Ensure that any reads from a shared resource in the * critical section read values after the lock is acquired. */ dmbld(); } void bakery_lock_release(bakery_lock_t *lock) { bakery_info_t *my_bakery_info; #ifdef __aarch64__ unsigned int is_cached = read_sctlr_el3() & SCTLR_C_BIT; #else unsigned int is_cached = read_sctlr() & SCTLR_C_BIT; #endif my_bakery_info = get_bakery_info(plat_my_core_pos(), lock); assert(is_lock_acquired(my_bakery_info, is_cached)); /* * Ensure that other observers see any stores in the critical section * before releasing the lock. Release the lock by resetting ticket. * Then signal other waiting contenders. */ dmbst(); my_bakery_info->lock_data = 0U; write_cache_op((uintptr_t)my_bakery_info, is_cached); sev(); } trusted-firmware-a-2.2/lib/locks/exclusive/000077500000000000000000000000001355360272700210015ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/locks/exclusive/aarch32/000077500000000000000000000000001355360272700222245ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/locks/exclusive/aarch32/spinlock.S000066400000000000000000000014421355360272700241730ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include .globl spin_lock .globl spin_unlock #if ARM_ARCH_AT_LEAST(8, 0) /* * According to the ARMv8-A Architecture Reference Manual, "when the global * monitor for a PE changes from Exclusive Access state to Open Access state, * an event is generated.". This applies to both AArch32 and AArch64 modes of * ARMv8-A. As a result, no explicit SEV with unlock is required. */ #define COND_SEV() #else #define COND_SEV() sev #endif func spin_lock mov r2, #1 1: ldrex r1, [r0] cmp r1, #0 wfene strexeq r1, r2, [r0] cmpeq r1, #0 bne 1b dmb bx lr endfunc spin_lock func spin_unlock mov r1, #0 stl r1, [r0] COND_SEV() bx lr endfunc spin_unlock trusted-firmware-a-2.2/lib/locks/exclusive/aarch64/000077500000000000000000000000001355360272700222315ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/locks/exclusive/aarch64/spinlock.S000066400000000000000000000026671355360272700242120ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include .globl spin_lock .globl spin_unlock #if USE_SPINLOCK_CAS #if !ARM_ARCH_AT_LEAST(8, 1) #error USE_SPINLOCK_CAS option requires at least an ARMv8.1 platform #endif /* * When compiled for ARMv8.1 or later, choose spin locks based on Compare and * Swap instruction. */ /* * Acquire lock using Compare and Swap instruction. * * Compare for 0 with acquire semantics, and swap 1. If failed to acquire, use * load exclusive semantics to monitor the address and enter WFE. * * void spin_lock(spinlock_t *lock); */ func spin_lock mov w2, #1 1: mov w1, wzr 2: casa w1, w2, [x0] cbz w1, 3f ldxr w1, [x0] cbz w1, 2b wfe b 1b 3: ret endfunc spin_lock #else /* !USE_SPINLOCK_CAS */ /* * Acquire lock using load-/store-exclusive instruction pair. * * void spin_lock(spinlock_t *lock); */ func spin_lock mov w2, #1 sevl l1: wfe l2: ldaxr w1, [x0] cbnz w1, l1 stxr w1, w2, [x0] cbnz w1, l2 ret endfunc spin_lock #endif /* USE_SPINLOCK_CAS */ /* * Release lock previously acquired by spin_lock. * * Use store-release to unconditionally clear the spinlock variable. * Store operation generates an event to all cores waiting in WFE * when address is monitored by the global monitor. * * void spin_unlock(spinlock_t *lock); */ func spin_unlock stlr wzr, [x0] ret endfunc spin_unlock trusted-firmware-a-2.2/lib/optee/000077500000000000000000000000001355360272700167735ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/optee/optee_utils.c000066400000000000000000000150761355360272700215040ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* * load_addr_hi and load_addr_lo: image load address. * image_id: 0 - pager, 1 - paged * size: image size in bytes. */ typedef struct optee_image { uint32_t load_addr_hi; uint32_t load_addr_lo; uint32_t image_id; uint32_t size; } optee_image_t; #define OPTEE_PAGER_IMAGE_ID 0 #define OPTEE_PAGED_IMAGE_ID 1 #define OPTEE_MAX_NUM_IMAGES 2u #define TEE_MAGIC_NUM_OPTEE 0x4554504f /* * magic: header magic number. * version: OPTEE header version: * 1 - not supported * 2 - supported * arch: OPTEE os architecture type: 0 - AARCH32, 1 - AARCH64. * flags: unused currently. * nb_images: number of images. */ typedef struct optee_header { uint32_t magic; uint8_t version; uint8_t arch; uint16_t flags; uint32_t nb_images; optee_image_t optee_image_list[]; } optee_header_t; /******************************************************************************* * Check if it is a valid tee header * Return 1 if valid * Return 0 if invalid ******************************************************************************/ static inline int tee_validate_header(optee_header_t *header) { int valid = 0; if ((header->magic == TEE_MAGIC_NUM_OPTEE) && (header->version == 2u) && (header->nb_images > 0u) && (header->nb_images <= OPTEE_MAX_NUM_IMAGES)) { valid = 1; } else { WARN("Not a known TEE, use default loading options.\n"); } return valid; } /******************************************************************************* * Parse the OPTEE image * Return 0 on success or a negative error code otherwise. ******************************************************************************/ static int parse_optee_image(image_info_t *image_info, optee_image_t *image) { uintptr_t init_load_addr, free_end, requested_end; size_t init_size; init_load_addr = ((uint64_t)image->load_addr_hi << 32) | image->load_addr_lo; init_size = image->size; /* * -1 indicates loader decided address; take our pre-mapped area * for current image since arm-tf could not allocate memory dynamically */ if (init_load_addr == -1) init_load_addr = image_info->image_base; /* Check that the default end address doesn't overflow */ if (check_uptr_overflow(image_info->image_base, image_info->image_max_size - 1)) return -1; free_end = image_info->image_base + (image_info->image_max_size - 1); /* Check that the image end address doesn't overflow */ if (check_uptr_overflow(init_load_addr, init_size - 1)) return -1; requested_end = init_load_addr + (init_size - 1); /* * Check that the requested RAM location is within reserved * space for OPTEE. */ if (!((init_load_addr >= image_info->image_base) && (requested_end <= free_end))) { WARN("The load address in optee header %p - %p is not in reserved area: %p - %p.\n", (void *)init_load_addr, (void *)(init_load_addr + init_size), (void *)image_info->image_base, (void *)(image_info->image_base + image_info->image_max_size)); return -1; } /* * Remove the skip attr from image_info, the image will be loaded. * The default attr in image_info is "IMAGE_ATTRIB_SKIP_LOADING", which * mean the image will not be loaded. Here, we parse the header image to * know that the extra image need to be loaded, so remove the skip attr. */ image_info->h.attr &= ~IMAGE_ATTRIB_SKIP_LOADING; /* Update image base and size of image_info */ image_info->image_base = init_load_addr; image_info->image_size = init_size; return 0; } /******************************************************************************* * Parse the OPTEE header * Return 0 on success or a negative error code otherwise. ******************************************************************************/ int parse_optee_header(entry_point_info_t *header_ep, image_info_t *pager_image_info, image_info_t *paged_image_info) { optee_header_t *header; int num, ret; assert(header_ep); header = (optee_header_t *)header_ep->pc; assert(header); /* Print the OPTEE header information */ INFO("OPTEE ep=0x%x\n", (unsigned int)header_ep->pc); INFO("OPTEE header info:\n"); INFO(" magic=0x%x\n", header->magic); INFO(" version=0x%x\n", header->version); INFO(" arch=0x%x\n", header->arch); INFO(" flags=0x%x\n", header->flags); INFO(" nb_images=0x%x\n", header->nb_images); /* * OPTEE image has 3 types: * * 1. Plain OPTEE bin without header. * Original bin without header, return directly, * BL32_EXTRA1_IMAGE_ID and BL32_EXTRA2_IMAGE_ID will be skipped. * * 2. OPTEE bin with header bin, but no paging. * Header available and nb_images = 1, remove skip attr for * BL32_EXTRA1_IMAGE_ID. BL32_EXTRA1_IMAGE_ID will be loaded, * and BL32_EXTRA2_IMAGE_ID be skipped. * * 3. OPTEE image with paging support. * Header available and nb_images = 2, there are 3 bins: header, * pager and pageable. Remove skip attr for BL32_EXTRA1_IMAGE_ID * and BL32_EXTRA2_IMAGE_ID to load pager and paged bin. */ if (!tee_validate_header(header)) { INFO("Invalid OPTEE header, set legacy mode.\n"); #ifdef __aarch64__ header_ep->args.arg0 = MODE_RW_64; #else header_ep->args.arg0 = MODE_RW_32; #endif return 0; } /* Parse OPTEE image */ for (num = 0; num < header->nb_images; num++) { if (header->optee_image_list[num].image_id == OPTEE_PAGER_IMAGE_ID) { ret = parse_optee_image(pager_image_info, &header->optee_image_list[num]); } else if (header->optee_image_list[num].image_id == OPTEE_PAGED_IMAGE_ID) { ret = parse_optee_image(paged_image_info, &header->optee_image_list[num]); } else { ERROR("Parse optee image failed.\n"); return -1; } if (ret != 0) return -1; } /* * Update "pc" value which should comes from pager image. After the * header image is parsed, it will be unuseful, and the actual * execution image after BL31 is pager image. */ header_ep->pc = pager_image_info->image_base; /* * The paged load address and size are populated in * header image arguments so that can be read by the * BL32 SPD. */ header_ep->args.arg1 = paged_image_info->image_base; header_ep->args.arg2 = paged_image_info->image_size; /* Set OPTEE runtime arch - aarch32/aarch64 */ if (header->arch == 0) { header_ep->args.arg0 = MODE_RW_32; } else { #ifdef __aarch64__ header_ep->args.arg0 = MODE_RW_64; #else ERROR("Cannot boot an AArch64 OP-TEE\n"); return -1; #endif } return 0; } trusted-firmware-a-2.2/lib/pmf/000077500000000000000000000000001355360272700164415ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/pmf/pmf_main.c000066400000000000000000000157421355360272700204040ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include /******************************************************************************* * The 'pmf_svc_descs' array holds the PMF service descriptors exported by * services by placing them in the 'pmf_svc_descs' linker section. * The 'pmf_svc_descs_indices' array holds the index of a descriptor in the * 'pmf_svc_descs' array. The TIF[15:10] bits in the time-stamp id are used * to get an index into the 'pmf_svc_descs_indices' array. This gives the * index of the descriptor in the 'pmf_svc_descs' array which contains the * service function pointers. ******************************************************************************/ IMPORT_SYM(uintptr_t, __PMF_SVC_DESCS_START__, PMF_SVC_DESCS_START); IMPORT_SYM(uintptr_t, __PMF_SVC_DESCS_END__, PMF_SVC_DESCS_END); IMPORT_SYM(uintptr_t, __PMF_PERCPU_TIMESTAMP_END__, PMF_PERCPU_TIMESTAMP_END); IMPORT_SYM(uintptr_t, __PMF_TIMESTAMP_START__, PMF_TIMESTAMP_ARRAY_START); #define PMF_PERCPU_TIMESTAMP_SIZE (PMF_PERCPU_TIMESTAMP_END - PMF_TIMESTAMP_ARRAY_START) #define PMF_SVC_DESCS_MAX 10 /* * This is used to traverse through registered PMF services. */ static pmf_svc_desc_t *pmf_svc_descs; /* * This array is used to store registered PMF services in sorted order. */ static int pmf_svc_descs_indices[PMF_SVC_DESCS_MAX]; /* * This is used to track total number of successfully registered PMF services. */ static int pmf_num_services; /* * This is the main PMF function that initialize registered * PMF services and also sort them in ascending order. */ int pmf_setup(void) { int rc, ii, jj = 0; int pmf_svc_descs_num, temp_val; /* If no PMF services are registered then simply bail out */ pmf_svc_descs_num = (PMF_SVC_DESCS_END - PMF_SVC_DESCS_START)/ sizeof(pmf_svc_desc_t); if (pmf_svc_descs_num == 0) return 0; assert(pmf_svc_descs_num < PMF_SVC_DESCS_MAX); pmf_svc_descs = (pmf_svc_desc_t *) PMF_SVC_DESCS_START; for (ii = 0; ii < pmf_svc_descs_num; ii++) { assert(pmf_svc_descs[ii].get_ts != NULL); /* * Call the initialization routine for this * PMF service, if it is defined. */ if (pmf_svc_descs[ii].init != NULL) { rc = pmf_svc_descs[ii].init(); if (rc != 0) { WARN("Could not initialize PMF" "service %s - skipping \n", pmf_svc_descs[ii].name); continue; } } /* Update the pmf_svc_descs_indices array */ pmf_svc_descs_indices[jj++] = ii; } pmf_num_services = jj; /* * Sort the successfully registered PMF services * according to service ID */ for (ii = 1; ii < pmf_num_services; ii++) { for (jj = 0; jj < (pmf_num_services - ii); jj++) { if ((pmf_svc_descs[jj].svc_config & PMF_SVC_ID_MASK) > (pmf_svc_descs[jj + 1].svc_config & PMF_SVC_ID_MASK)) { temp_val = pmf_svc_descs_indices[jj]; pmf_svc_descs_indices[jj] = pmf_svc_descs_indices[jj+1]; pmf_svc_descs_indices[jj+1] = temp_val; } } } return 0; } /* * This function implements binary search to find registered * PMF service based on Service ID provided in `tid` argument. */ static pmf_svc_desc_t *get_service(unsigned int tid) { int low = 0; int mid; int high = pmf_num_services; unsigned int svc_id = tid & PMF_SVC_ID_MASK; int index; unsigned int desc_svc_id; if (pmf_num_services == 0) return NULL; assert(pmf_svc_descs != NULL); do { mid = (low + high) / 2; index = pmf_svc_descs_indices[mid]; desc_svc_id = pmf_svc_descs[index].svc_config & PMF_SVC_ID_MASK; if (svc_id < desc_svc_id) high = mid - 1; if (svc_id > desc_svc_id) low = mid + 1; } while ((svc_id != desc_svc_id) && (low <= high)); /* * Make sure the Service found supports the tid range. */ if ((svc_id == desc_svc_id) && ((tid & PMF_TID_MASK) < (pmf_svc_descs[index].svc_config & PMF_TID_MASK))) return (pmf_svc_desc_t *)&pmf_svc_descs[index]; return NULL; } /* * This function gets the time-stamp value for the PMF services * registered for SMC interface based on `tid` and `mpidr`. */ int pmf_get_timestamp_smc(unsigned int tid, u_register_t mpidr, unsigned int flags, unsigned long long *ts_value) { pmf_svc_desc_t *svc_desc; assert(ts_value != NULL); /* Search for registered service. */ svc_desc = get_service(tid); if ((svc_desc == NULL) || (plat_core_pos_by_mpidr(mpidr) < 0)) { *ts_value = 0; return -EINVAL; } else { /* Call the service time-stamp handler. */ *ts_value = svc_desc->get_ts(tid, mpidr, flags); return 0; } } /* * This function can be used to dump `ts` value for given `tid`. * Assumption is that the console is already initialized. */ void __pmf_dump_timestamp(unsigned int tid, unsigned long long ts) { printf("PMF:cpu %u tid %u ts %llu\n", plat_my_core_pos(), tid, ts); } /* * This function calculate the address identified by * `base_addr`, `tid` and `cpuid`. */ static inline uintptr_t calc_ts_addr(uintptr_t base_addr, unsigned int tid, unsigned int cpuid) { assert(cpuid < PLATFORM_CORE_COUNT); assert(base_addr >= PMF_TIMESTAMP_ARRAY_START); assert(base_addr < ((PMF_TIMESTAMP_ARRAY_START + PMF_PERCPU_TIMESTAMP_SIZE) - ((tid & PMF_TID_MASK) * sizeof(unsigned long long)))); base_addr += ((cpuid * PMF_PERCPU_TIMESTAMP_SIZE) + ((tid & PMF_TID_MASK) * sizeof(unsigned long long))); return base_addr; } /* * This function stores the `ts` value to the storage identified by * `base_addr`, `tid` and current cpu id. * Note: The timestamp addresses are cache line aligned per cpu * and only the owning CPU would ever write into it. */ void __pmf_store_timestamp(uintptr_t base_addr, unsigned int tid, unsigned long long ts) { unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr, tid, plat_my_core_pos()); *ts_addr = ts; } /* * This is the cached version of `pmf_store_my_timestamp` * Note: The timestamp addresses are cache line aligned per cpu * and only the owning CPU would ever write into it. */ void __pmf_store_timestamp_with_cache_maint(uintptr_t base_addr, unsigned int tid, unsigned long long ts) { unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr, tid, plat_my_core_pos()); *ts_addr = ts; flush_dcache_range((uintptr_t)ts_addr, sizeof(unsigned long long)); } /* * This function retrieves the `ts` value from the storage identified by * `base_addr`, `tid` and `cpuid`. * Note: The timestamp addresses are cache line aligned per cpu. */ unsigned long long __pmf_get_timestamp(uintptr_t base_addr, unsigned int tid, unsigned int cpuid, unsigned int flags) { assert(cpuid < PLATFORM_CORE_COUNT); unsigned long long *ts_addr = (unsigned long long *)calc_ts_addr(base_addr, tid, cpuid); if ((flags & PMF_CACHE_MAINT) != 0U) inv_dcache_range((uintptr_t)ts_addr, sizeof(unsigned long long)); return *ts_addr; } trusted-firmware-a-2.2/lib/pmf/pmf_smc.c000066400000000000000000000026671355360272700202440ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* * This function is responsible for handling all PMF SMC calls. */ uintptr_t pmf_smc_handler(unsigned int 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) { int rc; unsigned long long ts_value; if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) { x1 = (uint32_t)x1; x2 = (uint32_t)x2; x3 = (uint32_t)x3; if (smc_fid == PMF_SMC_GET_TIMESTAMP_32) { /* * Return error code and the captured * time-stamp to the caller. * x0 --> error code. * x1 - x2 --> time-stamp value. */ rc = pmf_get_timestamp_smc((unsigned int)x1, x2, (unsigned int)x3, &ts_value); SMC_RET3(handle, rc, (uint32_t)ts_value, (uint32_t)(ts_value >> 32)); } } else { if (smc_fid == PMF_SMC_GET_TIMESTAMP_64) { /* * Return error code and the captured * time-stamp to the caller. * x0 --> error code. * x1 --> time-stamp value. */ rc = pmf_get_timestamp_smc((unsigned int)x1, x2, (unsigned int)x3, &ts_value); SMC_RET2(handle, rc, ts_value); } } WARN("Unimplemented PMF Call: 0x%x \n", smc_fid); SMC_RET1(handle, SMC_UNK); } trusted-firmware-a-2.2/lib/psci/000077500000000000000000000000001355360272700166155ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/psci/aarch32/000077500000000000000000000000001355360272700200405ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/psci/aarch32/psci_helpers.S000066400000000000000000000105531355360272700226500ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl psci_do_pwrdown_cache_maintenance .globl psci_do_pwrup_cache_maintenance .globl psci_power_down_wfi /* ----------------------------------------------------------------------- * void psci_do_pwrdown_cache_maintenance(unsigned int power level); * * This function performs cache maintenance for the specified power * level. The levels of cache affected are determined by the power * level which is passed as the argument i.e. level 0 results * in a flush of the L1 cache. Both the L1 and L2 caches are flushed * for a higher power level. * * Additionally, this function also ensures that stack memory is correctly * flushed out to avoid coherency issues due to a change in its memory * attributes after the data cache is disabled. * ----------------------------------------------------------------------- */ func psci_do_pwrdown_cache_maintenance push {r4, lr} /* ---------------------------------------------- * Turn OFF cache and do stack maintenance * prior to cpu operations . This sequence is * different from AArch64 because in AArch32 the * assembler routines for cpu operations utilize * the stack whereas in AArch64 it doesn't. * ---------------------------------------------- */ mov r4, r0 bl do_stack_maintenance /* --------------------------------------------- * Invoke CPU-specifc power down operations for * the appropriate level * --------------------------------------------- */ mov r0, r4 pop {r4, lr} b prepare_cpu_pwr_dwn endfunc psci_do_pwrdown_cache_maintenance /* ----------------------------------------------------------------------- * void psci_do_pwrup_cache_maintenance(void); * * This function performs cache maintenance after this cpu is powered up. * Currently, this involves managing the used stack memory before turning * on the data cache. * ----------------------------------------------------------------------- */ func psci_do_pwrup_cache_maintenance /* r12 is pushed to meet the 8 byte stack alignment requirement */ push {r12, lr} /* --------------------------------------------- * Ensure any inflight stack writes have made it * to main memory. * --------------------------------------------- */ dmb st /* --------------------------------------------- * Calculate and store the size of the used * stack memory in r1. Calculate and store the * stack base address in r0. * --------------------------------------------- */ bl plat_get_my_stack mov r1, sp sub r1, r0, r1 mov r0, sp bl inv_dcache_range /* --------------------------------------------- * Enable the data cache. * --------------------------------------------- */ ldcopr r0, SCTLR orr r0, r0, #SCTLR_C_BIT stcopr r0, SCTLR isb pop {r12, pc} endfunc psci_do_pwrup_cache_maintenance /* --------------------------------------------- * void do_stack_maintenance(void) * Do stack maintenance by flushing the used * stack to the main memory and invalidating the * remainder. * --------------------------------------------- */ func do_stack_maintenance push {r4, lr} bl plat_get_my_stack /* Turn off the D-cache */ ldcopr r1, SCTLR bic r1, #SCTLR_C_BIT stcopr r1, SCTLR isb /* --------------------------------------------- * Calculate and store the size of the used * stack memory in r1. * --------------------------------------------- */ mov r4, r0 mov r1, sp sub r1, r0, r1 mov r0, sp bl flush_dcache_range /* --------------------------------------------- * Calculate and store the size of the unused * stack memory in r1. Calculate and store the * stack base address in r0. * --------------------------------------------- */ sub r0, r4, #PLATFORM_STACK_SIZE sub r1, sp, r0 bl inv_dcache_range pop {r4, pc} endfunc do_stack_maintenance /* ----------------------------------------------------------------------- * This function is called to indicate to the power controller that it * is safe to power down this cpu. It should not exit the wfi and will * be released from reset upon power up. * ----------------------------------------------------------------------- */ func psci_power_down_wfi dsb sy // ensure write buffer empty wfi no_ret plat_panic_handler endfunc psci_power_down_wfi trusted-firmware-a-2.2/lib/psci/aarch64/000077500000000000000000000000001355360272700200455ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/psci/aarch64/psci_helpers.S000066400000000000000000000075751355360272700226670ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl psci_do_pwrdown_cache_maintenance .globl psci_do_pwrup_cache_maintenance .globl psci_power_down_wfi /* ----------------------------------------------------------------------- * void psci_do_pwrdown_cache_maintenance(unsigned int power level); * * This function performs cache maintenance for the specified power * level. The levels of cache affected are determined by the power * level which is passed as the argument i.e. level 0 results * in a flush of the L1 cache. Both the L1 and L2 caches are flushed * for a higher power level. * * Additionally, this function also ensures that stack memory is correctly * flushed out to avoid coherency issues due to a change in its memory * attributes after the data cache is disabled. * ----------------------------------------------------------------------- */ func psci_do_pwrdown_cache_maintenance stp x29, x30, [sp,#-16]! stp x19, x20, [sp,#-16]! /* --------------------------------------------- * Invoke CPU-specific power down operations for * the appropriate level * --------------------------------------------- */ bl prepare_cpu_pwr_dwn /* --------------------------------------------- * Do stack maintenance by flushing the used * stack to the main memory and invalidating the * remainder. * --------------------------------------------- */ bl plat_get_my_stack /* --------------------------------------------- * Calculate and store the size of the used * stack memory in x1. * --------------------------------------------- */ mov x19, x0 mov x1, sp sub x1, x0, x1 mov x0, sp bl flush_dcache_range /* --------------------------------------------- * Calculate and store the size of the unused * stack memory in x1. Calculate and store the * stack base address in x0. * --------------------------------------------- */ sub x0, x19, #PLATFORM_STACK_SIZE sub x1, sp, x0 bl inv_dcache_range ldp x19, x20, [sp], #16 ldp x29, x30, [sp], #16 ret endfunc psci_do_pwrdown_cache_maintenance /* ----------------------------------------------------------------------- * void psci_do_pwrup_cache_maintenance(void); * * This function performs cache maintenance after this cpu is powered up. * Currently, this involves managing the used stack memory before turning * on the data cache. * ----------------------------------------------------------------------- */ func psci_do_pwrup_cache_maintenance stp x29, x30, [sp,#-16]! /* --------------------------------------------- * Ensure any inflight stack writes have made it * to main memory. * --------------------------------------------- */ dmb st /* --------------------------------------------- * Calculate and store the size of the used * stack memory in x1. Calculate and store the * stack base address in x0. * --------------------------------------------- */ bl plat_get_my_stack mov x1, sp sub x1, x0, x1 mov x0, sp bl inv_dcache_range /* --------------------------------------------- * Enable the data cache. * --------------------------------------------- */ mrs x0, sctlr_el3 orr x0, x0, #SCTLR_C_BIT msr sctlr_el3, x0 isb ldp x29, x30, [sp], #16 ret endfunc psci_do_pwrup_cache_maintenance /* ----------------------------------------------------------------------- * void psci_power_down_wfi(void); * This function is called to indicate to the power controller that it * is safe to power down this cpu. It should not exit the wfi and will * be released from reset upon power up. * ----------------------------------------------------------------------- */ func psci_power_down_wfi dsb sy // ensure write buffer empty wfi no_ret plat_panic_handler endfunc psci_power_down_wfi trusted-firmware-a-2.2/lib/psci/psci_common.c000066400000000000000000001050601355360272700212710ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "psci_private.h" /* * SPD power management operations, expected to be supplied by the registered * SPD on successful SP initialization */ const spd_pm_ops_t *psci_spd_pm; /* * PSCI requested local power state map. This array is used to store the local * power states requested by a CPU for power levels from level 1 to * PLAT_MAX_PWR_LVL. It does not store the requested local power state for power * level 0 (PSCI_CPU_PWR_LVL) as the requested and the target power state for a * CPU are the same. * * During state coordination, the platform is passed an array containing the * local states requested for a particular non cpu power domain by each cpu * within the domain. * * TODO: Dense packing of the requested states will cause cache thrashing * when multiple power domains write to it. If we allocate the requested * states at each power level in a cache-line aligned per-domain memory, * the cache thrashing can be avoided. */ static plat_local_state_t psci_req_local_pwr_states[PLAT_MAX_PWR_LVL][PLATFORM_CORE_COUNT]; /******************************************************************************* * Arrays that hold the platform's power domain tree information for state * management of power domains. * Each node in the array 'psci_non_cpu_pd_nodes' corresponds to a power domain * which is an ancestor of a CPU power domain. * Each node in the array 'psci_cpu_pd_nodes' corresponds to a cpu power domain ******************************************************************************/ non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS] #if USE_COHERENT_MEM __section("tzfw_coherent_mem") #endif ; /* Lock for PSCI state coordination */ DEFINE_PSCI_LOCK(psci_locks[PSCI_NUM_NON_CPU_PWR_DOMAINS]); cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT]; /******************************************************************************* * Pointer to functions exported by the platform to complete power mgmt. ops ******************************************************************************/ const plat_psci_ops_t *psci_plat_pm_ops; /****************************************************************************** * Check that the maximum power level supported by the platform makes sense *****************************************************************************/ CASSERT((PLAT_MAX_PWR_LVL <= PSCI_MAX_PWR_LVL) && (PLAT_MAX_PWR_LVL >= PSCI_CPU_PWR_LVL), assert_platform_max_pwrlvl_check); /* * The plat_local_state used by the platform is one of these types: RUN, * RETENTION and OFF. The platform can define further sub-states for each type * apart from RUN. This categorization is done to verify the sanity of the * psci_power_state passed by the platform and to print debug information. The * categorization is done on the basis of the following conditions: * * 1. If (plat_local_state == 0) then the category is STATE_TYPE_RUN. * * 2. If (0 < plat_local_state <= PLAT_MAX_RET_STATE), then the category is * STATE_TYPE_RETN. * * 3. If (plat_local_state > PLAT_MAX_RET_STATE), then the category is * STATE_TYPE_OFF. */ typedef enum plat_local_state_type { STATE_TYPE_RUN = 0, STATE_TYPE_RETN, STATE_TYPE_OFF } plat_local_state_type_t; /* Function used to categorize plat_local_state. */ static plat_local_state_type_t find_local_state_type(plat_local_state_t state) { if (state != 0U) { if (state > PLAT_MAX_RET_STATE) { return STATE_TYPE_OFF; } else { return STATE_TYPE_RETN; } } else { return STATE_TYPE_RUN; } } /****************************************************************************** * Check that the maximum retention level supported by the platform is less * than the maximum off level. *****************************************************************************/ CASSERT(PLAT_MAX_RET_STATE < PLAT_MAX_OFF_STATE, assert_platform_max_off_and_retn_state_check); /****************************************************************************** * This function ensures that the power state parameter in a CPU_SUSPEND request * is valid. If so, it returns the requested states for each power level. *****************************************************************************/ int psci_validate_power_state(unsigned int power_state, psci_power_state_t *state_info) { /* Check SBZ bits in power state are zero */ if (psci_check_power_state(power_state) != 0U) return PSCI_E_INVALID_PARAMS; assert(psci_plat_pm_ops->validate_power_state != NULL); /* Validate the power_state using platform pm_ops */ return psci_plat_pm_ops->validate_power_state(power_state, state_info); } /****************************************************************************** * This function retrieves the `psci_power_state_t` for system suspend from * the platform. *****************************************************************************/ void psci_query_sys_suspend_pwrstate(psci_power_state_t *state_info) { /* * Assert that the required pm_ops hook is implemented to ensure that * the capability detected during psci_setup() is valid. */ assert(psci_plat_pm_ops->get_sys_suspend_power_state != NULL); /* * Query the platform for the power_state required for system suspend */ psci_plat_pm_ops->get_sys_suspend_power_state(state_info); } /******************************************************************************* * This function verifies that the all the other cores in the system have been * turned OFF and the current CPU is the last running CPU in the system. * Returns 1 (true) if the current CPU is the last ON CPU or 0 (false) * otherwise. ******************************************************************************/ unsigned int psci_is_last_on_cpu(void) { unsigned int cpu_idx, my_idx = plat_my_core_pos(); for (cpu_idx = 0; cpu_idx < (unsigned int)PLATFORM_CORE_COUNT; cpu_idx++) { if (cpu_idx == my_idx) { assert(psci_get_aff_info_state() == AFF_STATE_ON); continue; } if (psci_get_aff_info_state_by_idx(cpu_idx) != AFF_STATE_OFF) return 0; } return 1; } /******************************************************************************* * Routine to return the maximum power level to traverse to after a cpu has * been physically powered up. It is expected to be called immediately after * reset from assembler code. ******************************************************************************/ static unsigned int get_power_on_target_pwrlvl(void) { unsigned int pwrlvl; /* * Assume that this cpu was suspended and retrieve its target power * level. If it is invalid then it could only have been turned off * earlier. PLAT_MAX_PWR_LVL will be the highest power level a * cpu can be turned off to. */ pwrlvl = psci_get_suspend_pwrlvl(); if (pwrlvl == PSCI_INVALID_PWR_LVL) pwrlvl = PLAT_MAX_PWR_LVL; assert(pwrlvl < PSCI_INVALID_PWR_LVL); return pwrlvl; } /****************************************************************************** * Helper function to update the requested local power state array. This array * does not store the requested state for the CPU power level. Hence an * assertion is added to prevent us from accessing the CPU power level. *****************************************************************************/ static void psci_set_req_local_pwr_state(unsigned int pwrlvl, unsigned int cpu_idx, plat_local_state_t req_pwr_state) { assert(pwrlvl > PSCI_CPU_PWR_LVL); if ((pwrlvl > PSCI_CPU_PWR_LVL) && (pwrlvl <= PLAT_MAX_PWR_LVL) && (cpu_idx < (unsigned int) PLATFORM_CORE_COUNT)) { psci_req_local_pwr_states[pwrlvl - 1U][cpu_idx] = req_pwr_state; } } /****************************************************************************** * This function initializes the psci_req_local_pwr_states. *****************************************************************************/ void __init psci_init_req_local_pwr_states(void) { /* Initialize the requested state of all non CPU power domains as OFF */ unsigned int pwrlvl; int core; for (pwrlvl = 0U; pwrlvl < PLAT_MAX_PWR_LVL; pwrlvl++) { for (core = 0; core < PLATFORM_CORE_COUNT; core++) { psci_req_local_pwr_states[pwrlvl][core] = PLAT_MAX_OFF_STATE; } } } /****************************************************************************** * Helper function to return a reference to an array containing the local power * states requested by each cpu for a power domain at 'pwrlvl'. The size of the * array will be the number of cpu power domains of which this power domain is * an ancestor. These requested states will be used to determine a suitable * target state for this power domain during psci state coordination. An * assertion is added to prevent us from accessing the CPU power level. *****************************************************************************/ static plat_local_state_t *psci_get_req_local_pwr_states(unsigned int pwrlvl, unsigned int cpu_idx) { assert(pwrlvl > PSCI_CPU_PWR_LVL); if ((pwrlvl > PSCI_CPU_PWR_LVL) && (pwrlvl <= PLAT_MAX_PWR_LVL) && (cpu_idx < (unsigned int) PLATFORM_CORE_COUNT)) { return &psci_req_local_pwr_states[pwrlvl - 1U][cpu_idx]; } else return NULL; } /* * psci_non_cpu_pd_nodes can be placed either in normal memory or coherent * memory. * * With !USE_COHERENT_MEM, psci_non_cpu_pd_nodes is placed in normal memory, * it's accessed by both cached and non-cached participants. To serve the common * minimum, perform a cache flush before read and after write so that non-cached * participants operate on latest data in main memory. * * When USE_COHERENT_MEM is used, psci_non_cpu_pd_nodes is placed in coherent * memory. With HW_ASSISTED_COHERENCY, all PSCI participants are cache-coherent. * In both cases, no cache operations are required. */ /* * Retrieve local state of non-CPU power domain node from a non-cached CPU, * after any required cache maintenance operation. */ static plat_local_state_t get_non_cpu_pd_node_local_state( unsigned int parent_idx) { #if !(USE_COHERENT_MEM || HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY) flush_dcache_range( (uintptr_t) &psci_non_cpu_pd_nodes[parent_idx], sizeof(psci_non_cpu_pd_nodes[parent_idx])); #endif return psci_non_cpu_pd_nodes[parent_idx].local_state; } /* * Update local state of non-CPU power domain node from a cached CPU; perform * any required cache maintenance operation afterwards. */ static void set_non_cpu_pd_node_local_state(unsigned int parent_idx, plat_local_state_t state) { psci_non_cpu_pd_nodes[parent_idx].local_state = state; #if !(USE_COHERENT_MEM || HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY) flush_dcache_range( (uintptr_t) &psci_non_cpu_pd_nodes[parent_idx], sizeof(psci_non_cpu_pd_nodes[parent_idx])); #endif } /****************************************************************************** * Helper function to return the current local power state of each power domain * from the current cpu power domain to its ancestor at the 'end_pwrlvl'. This * function will be called after a cpu is powered on to find the local state * each power domain has emerged from. *****************************************************************************/ void psci_get_target_local_pwr_states(unsigned int end_pwrlvl, psci_power_state_t *target_state) { unsigned int parent_idx, lvl; plat_local_state_t *pd_state = target_state->pwr_domain_state; pd_state[PSCI_CPU_PWR_LVL] = psci_get_cpu_local_state(); parent_idx = psci_cpu_pd_nodes[plat_my_core_pos()].parent_node; /* Copy the local power state from node to state_info */ for (lvl = PSCI_CPU_PWR_LVL + 1U; lvl <= end_pwrlvl; lvl++) { pd_state[lvl] = get_non_cpu_pd_node_local_state(parent_idx); parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node; } /* Set the the higher levels to RUN */ for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) target_state->pwr_domain_state[lvl] = PSCI_LOCAL_STATE_RUN; } /****************************************************************************** * Helper function to set the target local power state that each power domain * from the current cpu power domain to its ancestor at the 'end_pwrlvl' will * enter. This function will be called after coordination of requested power * states has been done for each power level. *****************************************************************************/ static void psci_set_target_local_pwr_states(unsigned int end_pwrlvl, const psci_power_state_t *target_state) { unsigned int parent_idx, lvl; const plat_local_state_t *pd_state = target_state->pwr_domain_state; psci_set_cpu_local_state(pd_state[PSCI_CPU_PWR_LVL]); /* * Need to flush as local_state might be accessed with Data Cache * disabled during power on */ psci_flush_cpu_data(psci_svc_cpu_data.local_state); parent_idx = psci_cpu_pd_nodes[plat_my_core_pos()].parent_node; /* Copy the local_state from state_info */ for (lvl = 1U; lvl <= end_pwrlvl; lvl++) { set_non_cpu_pd_node_local_state(parent_idx, pd_state[lvl]); parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node; } } /******************************************************************************* * PSCI helper function to get the parent nodes corresponding to a cpu_index. ******************************************************************************/ void psci_get_parent_pwr_domain_nodes(unsigned int cpu_idx, unsigned int end_lvl, unsigned int *node_index) { unsigned int parent_node = psci_cpu_pd_nodes[cpu_idx].parent_node; unsigned int i; unsigned int *node = node_index; for (i = PSCI_CPU_PWR_LVL + 1U; i <= end_lvl; i++) { *node = parent_node; node++; parent_node = psci_non_cpu_pd_nodes[parent_node].parent_node; } } /****************************************************************************** * This function is invoked post CPU power up and initialization. It sets the * affinity info state, target power state and requested power state for the * current CPU and all its ancestor power domains to RUN. *****************************************************************************/ void psci_set_pwr_domains_to_run(unsigned int end_pwrlvl) { unsigned int parent_idx, cpu_idx = plat_my_core_pos(), lvl; parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node; /* Reset the local_state to RUN for the non cpu power domains. */ for (lvl = PSCI_CPU_PWR_LVL + 1U; lvl <= end_pwrlvl; lvl++) { set_non_cpu_pd_node_local_state(parent_idx, PSCI_LOCAL_STATE_RUN); psci_set_req_local_pwr_state(lvl, cpu_idx, PSCI_LOCAL_STATE_RUN); parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node; } /* Set the affinity info state to ON */ psci_set_aff_info_state(AFF_STATE_ON); psci_set_cpu_local_state(PSCI_LOCAL_STATE_RUN); psci_flush_cpu_data(psci_svc_cpu_data); } /****************************************************************************** * This function is passed the local power states requested for each power * domain (state_info) between the current CPU domain and its ancestors until * the target power level (end_pwrlvl). It updates the array of requested power * states with this information. * * Then, for each level (apart from the CPU level) until the 'end_pwrlvl', it * retrieves the states requested by all the cpus of which the power domain at * that level is an ancestor. It passes this information to the platform to * coordinate and return the target power state. If the target state for a level * is RUN then subsequent levels are not considered. At the CPU level, state * coordination is not required. Hence, the requested and the target states are * the same. * * The 'state_info' is updated with the target state for each level between the * CPU and the 'end_pwrlvl' and returned to the caller. * * This function will only be invoked with data cache enabled and while * powering down a core. *****************************************************************************/ void psci_do_state_coordination(unsigned int end_pwrlvl, psci_power_state_t *state_info) { unsigned int lvl, parent_idx, cpu_idx = plat_my_core_pos(); unsigned int start_idx; unsigned int ncpus; plat_local_state_t target_state, *req_states; assert(end_pwrlvl <= PLAT_MAX_PWR_LVL); parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node; /* For level 0, the requested state will be equivalent to target state */ for (lvl = PSCI_CPU_PWR_LVL + 1U; lvl <= end_pwrlvl; lvl++) { /* First update the requested power state */ psci_set_req_local_pwr_state(lvl, cpu_idx, state_info->pwr_domain_state[lvl]); /* Get the requested power states for this power level */ start_idx = psci_non_cpu_pd_nodes[parent_idx].cpu_start_idx; req_states = psci_get_req_local_pwr_states(lvl, start_idx); /* * Let the platform coordinate amongst the requested states at * this power level and return the target local power state. */ ncpus = psci_non_cpu_pd_nodes[parent_idx].ncpus; target_state = plat_get_target_pwr_state(lvl, req_states, ncpus); state_info->pwr_domain_state[lvl] = target_state; /* Break early if the negotiated target power state is RUN */ if (is_local_state_run(state_info->pwr_domain_state[lvl]) != 0) break; parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node; } /* * This is for cases when we break out of the above loop early because * the target power state is RUN at a power level < end_pwlvl. * We update the requested power state from state_info and then * set the target state as RUN. */ for (lvl = lvl + 1U; lvl <= end_pwrlvl; lvl++) { psci_set_req_local_pwr_state(lvl, cpu_idx, state_info->pwr_domain_state[lvl]); state_info->pwr_domain_state[lvl] = PSCI_LOCAL_STATE_RUN; } /* Update the target state in the power domain nodes */ psci_set_target_local_pwr_states(end_pwrlvl, state_info); } /****************************************************************************** * This function validates a suspend request by making sure that if a standby * state is requested then no power level is turned off and the highest power * level is placed in a standby/retention state. * * It also ensures that the state level X will enter is not shallower than the * state level X + 1 will enter. * * This validation will be enabled only for DEBUG builds as the platform is * expected to perform these validations as well. *****************************************************************************/ int psci_validate_suspend_req(const psci_power_state_t *state_info, unsigned int is_power_down_state) { unsigned int max_off_lvl, target_lvl, max_retn_lvl; plat_local_state_t state; plat_local_state_type_t req_state_type, deepest_state_type; int i; /* Find the target suspend power level */ target_lvl = psci_find_target_suspend_lvl(state_info); if (target_lvl == PSCI_INVALID_PWR_LVL) return PSCI_E_INVALID_PARAMS; /* All power domain levels are in a RUN state to begin with */ deepest_state_type = STATE_TYPE_RUN; for (i = (int) target_lvl; i >= (int) PSCI_CPU_PWR_LVL; i--) { state = state_info->pwr_domain_state[i]; req_state_type = find_local_state_type(state); /* * While traversing from the highest power level to the lowest, * the state requested for lower levels has to be the same or * deeper i.e. equal to or greater than the state at the higher * levels. If this condition is true, then the requested state * becomes the deepest state encountered so far. */ if (req_state_type < deepest_state_type) return PSCI_E_INVALID_PARAMS; deepest_state_type = req_state_type; } /* Find the highest off power level */ max_off_lvl = psci_find_max_off_lvl(state_info); /* The target_lvl is either equal to the max_off_lvl or max_retn_lvl */ max_retn_lvl = PSCI_INVALID_PWR_LVL; if (target_lvl != max_off_lvl) max_retn_lvl = target_lvl; /* * If this is not a request for a power down state then max off level * has to be invalid and max retention level has to be a valid power * level. */ if ((is_power_down_state == 0U) && ((max_off_lvl != PSCI_INVALID_PWR_LVL) || (max_retn_lvl == PSCI_INVALID_PWR_LVL))) return PSCI_E_INVALID_PARAMS; return PSCI_E_SUCCESS; } /****************************************************************************** * This function finds the highest power level which will be powered down * amongst all the power levels specified in the 'state_info' structure *****************************************************************************/ unsigned int psci_find_max_off_lvl(const psci_power_state_t *state_info) { int i; for (i = (int) PLAT_MAX_PWR_LVL; i >= (int) PSCI_CPU_PWR_LVL; i--) { if (is_local_state_off(state_info->pwr_domain_state[i]) != 0) return (unsigned int) i; } return PSCI_INVALID_PWR_LVL; } /****************************************************************************** * This functions finds the level of the highest power domain which will be * placed in a low power state during a suspend operation. *****************************************************************************/ unsigned int psci_find_target_suspend_lvl(const psci_power_state_t *state_info) { int i; for (i = (int) PLAT_MAX_PWR_LVL; i >= (int) PSCI_CPU_PWR_LVL; i--) { if (is_local_state_run(state_info->pwr_domain_state[i]) == 0) return (unsigned int) i; } return PSCI_INVALID_PWR_LVL; } /******************************************************************************* * This function is passed the highest level in the topology tree that the * operation should be applied to and a list of node indexes. It picks up locks * from the node index list in order of increasing power domain level in the * range specified. ******************************************************************************/ void psci_acquire_pwr_domain_locks(unsigned int end_pwrlvl, const unsigned int *parent_nodes) { unsigned int parent_idx; unsigned int level; /* No locking required for level 0. Hence start locking from level 1 */ for (level = PSCI_CPU_PWR_LVL + 1U; level <= end_pwrlvl; level++) { parent_idx = parent_nodes[level - 1U]; psci_lock_get(&psci_non_cpu_pd_nodes[parent_idx]); } } /******************************************************************************* * This function is passed the highest level in the topology tree that the * operation should be applied to and a list of node indexes. It releases the * locks in order of decreasing power domain level in the range specified. ******************************************************************************/ void psci_release_pwr_domain_locks(unsigned int end_pwrlvl, const unsigned int *parent_nodes) { unsigned int parent_idx; unsigned int level; /* Unlock top down. No unlocking required for level 0. */ for (level = end_pwrlvl; level >= PSCI_CPU_PWR_LVL + 1U; level--) { parent_idx = parent_nodes[level - 1U]; psci_lock_release(&psci_non_cpu_pd_nodes[parent_idx]); } } /******************************************************************************* * Simple routine to determine whether a mpidr is valid or not. ******************************************************************************/ int psci_validate_mpidr(u_register_t mpidr) { if (plat_core_pos_by_mpidr(mpidr) < 0) return PSCI_E_INVALID_PARAMS; return PSCI_E_SUCCESS; } /******************************************************************************* * This function determines the full entrypoint information for the requested * PSCI entrypoint on power on/resume and returns it. ******************************************************************************/ #ifdef __aarch64__ static int psci_get_ns_ep_info(entry_point_info_t *ep, uintptr_t entrypoint, u_register_t context_id) { u_register_t ep_attr, sctlr; unsigned int daif, ee, mode; u_register_t ns_scr_el3 = read_scr_el3(); u_register_t ns_sctlr_el1 = read_sctlr_el1(); sctlr = ((ns_scr_el3 & SCR_HCE_BIT) != 0U) ? read_sctlr_el2() : ns_sctlr_el1; ee = 0; ep_attr = NON_SECURE | EP_ST_DISABLE; if ((sctlr & SCTLR_EE_BIT) != 0U) { ep_attr |= EP_EE_BIG; ee = 1; } SET_PARAM_HEAD(ep, PARAM_EP, VERSION_1, ep_attr); ep->pc = entrypoint; zeromem(&ep->args, sizeof(ep->args)); ep->args.arg0 = context_id; /* * Figure out whether the cpu enters the non-secure address space * in aarch32 or aarch64 */ if ((ns_scr_el3 & SCR_RW_BIT) != 0U) { /* * Check whether a Thumb entry point has been provided for an * aarch64 EL */ if ((entrypoint & 0x1UL) != 0UL) return PSCI_E_INVALID_ADDRESS; mode = ((ns_scr_el3 & SCR_HCE_BIT) != 0U) ? MODE_EL2 : MODE_EL1; ep->spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); } else { mode = ((ns_scr_el3 & SCR_HCE_BIT) != 0U) ? MODE32_hyp : MODE32_svc; /* * TODO: Choose async. exception bits if HYP mode is not * implemented according to the values of SCR.{AW, FW} bits */ daif = DAIF_ABT_BIT | DAIF_IRQ_BIT | DAIF_FIQ_BIT; ep->spsr = SPSR_MODE32(mode, entrypoint & 0x1, ee, daif); } return PSCI_E_SUCCESS; } #else /* !__aarch64__ */ static int psci_get_ns_ep_info(entry_point_info_t *ep, uintptr_t entrypoint, u_register_t context_id) { u_register_t ep_attr; unsigned int aif, ee, mode; u_register_t scr = read_scr(); u_register_t ns_sctlr, sctlr; /* Switch to non secure state */ write_scr(scr | SCR_NS_BIT); isb(); ns_sctlr = read_sctlr(); sctlr = scr & SCR_HCE_BIT ? read_hsctlr() : ns_sctlr; /* Return to original state */ write_scr(scr); isb(); ee = 0; ep_attr = NON_SECURE | EP_ST_DISABLE; if (sctlr & SCTLR_EE_BIT) { ep_attr |= EP_EE_BIG; ee = 1; } SET_PARAM_HEAD(ep, PARAM_EP, VERSION_1, ep_attr); ep->pc = entrypoint; zeromem(&ep->args, sizeof(ep->args)); ep->args.arg0 = context_id; mode = scr & SCR_HCE_BIT ? MODE32_hyp : MODE32_svc; /* * TODO: Choose async. exception bits if HYP mode is not * implemented according to the values of SCR.{AW, FW} bits */ aif = SPSR_ABT_BIT | SPSR_IRQ_BIT | SPSR_FIQ_BIT; ep->spsr = SPSR_MODE32(mode, entrypoint & 0x1, ee, aif); return PSCI_E_SUCCESS; } #endif /* __aarch64__ */ /******************************************************************************* * This function validates the entrypoint with the platform layer if the * appropriate pm_ops hook is exported by the platform and returns the * 'entry_point_info'. ******************************************************************************/ int psci_validate_entry_point(entry_point_info_t *ep, uintptr_t entrypoint, u_register_t context_id) { int rc; /* Validate the entrypoint using platform psci_ops */ if (psci_plat_pm_ops->validate_ns_entrypoint != NULL) { rc = psci_plat_pm_ops->validate_ns_entrypoint(entrypoint); if (rc != PSCI_E_SUCCESS) return PSCI_E_INVALID_ADDRESS; } /* * Verify and derive the re-entry information for * the non-secure world from the non-secure state from * where this call originated. */ rc = psci_get_ns_ep_info(ep, entrypoint, context_id); return rc; } /******************************************************************************* * Generic handler which is called when a cpu is physically powered on. It * traverses the node information and finds the highest power level powered * off and performs generic, architectural, platform setup and state management * to power on that power level and power levels below it. * e.g. For a cpu that's been powered on, it will call the platform specific * code to enable the gic cpu interface and for a cluster it will enable * coherency at the interconnect level in addition to gic cpu interface. ******************************************************************************/ void psci_warmboot_entrypoint(void) { unsigned int end_pwrlvl; unsigned int cpu_idx = plat_my_core_pos(); unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0}; psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} }; /* * Verify that we have been explicitly turned ON or resumed from * suspend. */ if (psci_get_aff_info_state() == AFF_STATE_OFF) { ERROR("Unexpected affinity info state"); panic(); } /* * Get the maximum power domain level to traverse to after this cpu * has been physically powered up. */ end_pwrlvl = get_power_on_target_pwrlvl(); /* Get the parent nodes */ psci_get_parent_pwr_domain_nodes(cpu_idx, end_pwrlvl, parent_nodes); /* * This function acquires the lock corresponding to each power level so * that by the time all locks are taken, the system topology is snapshot * and state management can be done safely. */ psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes); psci_get_target_local_pwr_states(end_pwrlvl, &state_info); #if ENABLE_PSCI_STAT plat_psci_stat_accounting_stop(&state_info); #endif /* * This CPU could be resuming from suspend or it could have just been * turned on. To distinguish between these 2 cases, we examine the * affinity state of the CPU: * - If the affinity state is ON_PENDING then it has just been * turned on. * - Else it is resuming from suspend. * * Depending on the type of warm reset identified, choose the right set * of power management handler and perform the generic, architecture * and platform specific handling. */ if (psci_get_aff_info_state() == AFF_STATE_ON_PENDING) psci_cpu_on_finish(cpu_idx, &state_info); else psci_cpu_suspend_finish(cpu_idx, &state_info); /* * Set the requested and target state of this CPU and all the higher * power domains which are ancestors of this CPU to run. */ psci_set_pwr_domains_to_run(end_pwrlvl); #if ENABLE_PSCI_STAT /* * Update PSCI stats. * Caches are off when writing stats data on the power down path. * Since caches are now enabled, it's necessary to do cache * maintenance before reading that same data. */ psci_stats_update_pwr_up(end_pwrlvl, &state_info); #endif /* * This loop releases the lock corresponding to each power level * in the reverse order to which they were acquired. */ psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes); } /******************************************************************************* * This function initializes the set of hooks that PSCI invokes as part of power * management operation. The power management hooks are expected to be provided * by the SPD, after it finishes all its initialization ******************************************************************************/ void psci_register_spd_pm_hook(const spd_pm_ops_t *pm) { assert(pm != NULL); psci_spd_pm = pm; if (pm->svc_migrate != NULL) psci_caps |= define_psci_cap(PSCI_MIG_AARCH64); if (pm->svc_migrate_info != NULL) psci_caps |= define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64) | define_psci_cap(PSCI_MIG_INFO_TYPE); } /******************************************************************************* * This function invokes the migrate info hook in the spd_pm_ops. It performs * the necessary return value validation. If the Secure Payload is UP and * migrate capable, it returns the mpidr of the CPU on which the Secure payload * is resident through the mpidr parameter. Else the value of the parameter on * return is undefined. ******************************************************************************/ int psci_spd_migrate_info(u_register_t *mpidr) { int rc; if ((psci_spd_pm == NULL) || (psci_spd_pm->svc_migrate_info == NULL)) return PSCI_E_NOT_SUPPORTED; rc = psci_spd_pm->svc_migrate_info(mpidr); assert((rc == PSCI_TOS_UP_MIG_CAP) || (rc == PSCI_TOS_NOT_UP_MIG_CAP) || (rc == PSCI_TOS_NOT_PRESENT_MP) || (rc == PSCI_E_NOT_SUPPORTED)); return rc; } /******************************************************************************* * This function prints the state of all power domains present in the * system ******************************************************************************/ void psci_print_power_domain_map(void) { #if LOG_LEVEL >= LOG_LEVEL_INFO int idx; plat_local_state_t state; plat_local_state_type_t state_type; /* This array maps to the PSCI_STATE_X definitions in psci.h */ static const char * const psci_state_type_str[] = { "ON", "RETENTION", "OFF", }; INFO("PSCI Power Domain Map:\n"); for (idx = 0; idx < (PSCI_NUM_PWR_DOMAINS - PLATFORM_CORE_COUNT); idx++) { state_type = find_local_state_type( psci_non_cpu_pd_nodes[idx].local_state); INFO(" Domain Node : Level %u, parent_node %d," " State %s (0x%x)\n", psci_non_cpu_pd_nodes[idx].level, psci_non_cpu_pd_nodes[idx].parent_node, psci_state_type_str[state_type], psci_non_cpu_pd_nodes[idx].local_state); } for (idx = 0; idx < PLATFORM_CORE_COUNT; idx++) { state = psci_get_cpu_local_state_by_idx(idx); state_type = find_local_state_type(state); INFO(" CPU Node : MPID 0x%llx, parent_node %d," " State %s (0x%x)\n", (unsigned long long)psci_cpu_pd_nodes[idx].mpidr, psci_cpu_pd_nodes[idx].parent_node, psci_state_type_str[state_type], psci_get_cpu_local_state_by_idx(idx)); } #endif } /****************************************************************************** * Return whether any secondaries were powered up with CPU_ON call. A CPU that * have ever been powered up would have set its MPDIR value to something other * than PSCI_INVALID_MPIDR. Note that MPDIR isn't reset back to * PSCI_INVALID_MPIDR when a CPU is powered down later, so the return value is * meaningful only when called on the primary CPU during early boot. *****************************************************************************/ int psci_secondaries_brought_up(void) { unsigned int idx, n_valid = 0U; for (idx = 0U; idx < ARRAY_SIZE(psci_cpu_pd_nodes); idx++) { if (psci_cpu_pd_nodes[idx].mpidr != PSCI_INVALID_MPIDR) n_valid++; } assert(n_valid > 0U); return (n_valid > 1U) ? 1 : 0; } /******************************************************************************* * Initiate power down sequence, by calling power down operations registered for * this CPU. ******************************************************************************/ void psci_do_pwrdown_sequence(unsigned int power_level) { #if HW_ASSISTED_COHERENCY /* * With hardware-assisted coherency, the CPU drivers only initiate the * power down sequence, without performing cache-maintenance operations * in software. Data caches enabled both before and after this call. */ prepare_cpu_pwr_dwn(power_level); #else /* * Without hardware-assisted coherency, the CPU drivers disable data * caches, then perform cache-maintenance operations in software. * * This also calls prepare_cpu_pwr_dwn() to initiate power down * sequence, but that function will return with data caches disabled. * We must ensure that the stack memory is flushed out to memory before * we start popping from it again. */ psci_do_pwrdown_cache_maintenance(power_level); #endif } trusted-firmware-a-2.2/lib/psci/psci_lib.mk000066400000000000000000000017351355360272700207400ustar00rootroot00000000000000# # Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # PSCI_LIB_SOURCES := lib/el3_runtime/cpu_data_array.c \ lib/el3_runtime/${ARCH}/cpu_data.S \ lib/el3_runtime/${ARCH}/context_mgmt.c \ lib/cpus/${ARCH}/cpu_helpers.S \ lib/cpus/errata_report.c \ lib/locks/exclusive/${ARCH}/spinlock.S \ lib/psci/psci_off.c \ lib/psci/psci_on.c \ lib/psci/psci_suspend.c \ lib/psci/psci_common.c \ lib/psci/psci_main.c \ lib/psci/psci_setup.c \ lib/psci/psci_system_off.c \ lib/psci/psci_mem_protect.c \ lib/psci/${ARCH}/psci_helpers.S ifeq (${ARCH}, aarch64) PSCI_LIB_SOURCES += lib/el3_runtime/aarch64/context.S endif ifeq (${USE_COHERENT_MEM}, 1) PSCI_LIB_SOURCES += lib/locks/bakery/bakery_lock_coherent.c else PSCI_LIB_SOURCES += lib/locks/bakery/bakery_lock_normal.c endif ifeq (${ENABLE_PSCI_STAT}, 1) PSCI_LIB_SOURCES += lib/psci/psci_stat.c endif trusted-firmware-a-2.2/lib/psci/psci_main.c000066400000000000000000000331521355360272700207270ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "psci_private.h" /******************************************************************************* * PSCI frontend api for servicing SMCs. Described in the PSCI spec. ******************************************************************************/ int psci_cpu_on(u_register_t target_cpu, uintptr_t entrypoint, u_register_t context_id) { int rc; entry_point_info_t ep; /* Determine if the cpu exists of not */ rc = psci_validate_mpidr(target_cpu); if (rc != PSCI_E_SUCCESS) return PSCI_E_INVALID_PARAMS; /* Validate the entry point and get the entry_point_info */ rc = psci_validate_entry_point(&ep, entrypoint, context_id); if (rc != PSCI_E_SUCCESS) return rc; /* * To turn this cpu on, specify which power * levels need to be turned on */ return psci_cpu_on_start(target_cpu, &ep); } unsigned int psci_version(void) { return PSCI_MAJOR_VER | PSCI_MINOR_VER; } int psci_cpu_suspend(unsigned int power_state, uintptr_t entrypoint, u_register_t context_id) { int rc; unsigned int target_pwrlvl, is_power_down_state; entry_point_info_t ep; psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} }; plat_local_state_t cpu_pd_state; /* Validate the power_state parameter */ rc = psci_validate_power_state(power_state, &state_info); if (rc != PSCI_E_SUCCESS) { assert(rc == PSCI_E_INVALID_PARAMS); return rc; } /* * Get the value of the state type bit from the power state parameter. */ is_power_down_state = psci_get_pstate_type(power_state); /* Sanity check the requested suspend levels */ assert(psci_validate_suspend_req(&state_info, is_power_down_state) == PSCI_E_SUCCESS); target_pwrlvl = psci_find_target_suspend_lvl(&state_info); if (target_pwrlvl == PSCI_INVALID_PWR_LVL) { ERROR("Invalid target power level for suspend operation\n"); panic(); } /* Fast path for CPU standby.*/ if (is_cpu_standby_req(is_power_down_state, target_pwrlvl)) { if (psci_plat_pm_ops->cpu_standby == NULL) return PSCI_E_INVALID_PARAMS; /* * Set the state of the CPU power domain to the platform * specific retention state and enter the standby state. */ cpu_pd_state = state_info.pwr_domain_state[PSCI_CPU_PWR_LVL]; psci_set_cpu_local_state(cpu_pd_state); #if ENABLE_PSCI_STAT plat_psci_stat_accounting_start(&state_info); #endif #if ENABLE_RUNTIME_INSTRUMENTATION PMF_CAPTURE_TIMESTAMP(rt_instr_svc, RT_INSTR_ENTER_HW_LOW_PWR, PMF_NO_CACHE_MAINT); #endif psci_plat_pm_ops->cpu_standby(cpu_pd_state); /* Upon exit from standby, set the state back to RUN. */ psci_set_cpu_local_state(PSCI_LOCAL_STATE_RUN); #if ENABLE_RUNTIME_INSTRUMENTATION PMF_CAPTURE_TIMESTAMP(rt_instr_svc, RT_INSTR_EXIT_HW_LOW_PWR, PMF_NO_CACHE_MAINT); #endif #if ENABLE_PSCI_STAT plat_psci_stat_accounting_stop(&state_info); /* Update PSCI stats */ psci_stats_update_pwr_up(PSCI_CPU_PWR_LVL, &state_info); #endif return PSCI_E_SUCCESS; } /* * If a power down state has been requested, we need to verify entry * point and program entry information. */ if (is_power_down_state != 0U) { rc = psci_validate_entry_point(&ep, entrypoint, context_id); if (rc != PSCI_E_SUCCESS) return rc; } /* * Do what is needed to enter the power down state. Upon success, * enter the final wfi which will power down this CPU. This function * might return if the power down was abandoned for any reason, e.g. * arrival of an interrupt */ psci_cpu_suspend_start(&ep, target_pwrlvl, &state_info, is_power_down_state); return PSCI_E_SUCCESS; } int psci_system_suspend(uintptr_t entrypoint, u_register_t context_id) { int rc; psci_power_state_t state_info; entry_point_info_t ep; /* Check if the current CPU is the last ON CPU in the system */ if (psci_is_last_on_cpu() == 0U) return PSCI_E_DENIED; /* Validate the entry point and get the entry_point_info */ rc = psci_validate_entry_point(&ep, entrypoint, context_id); if (rc != PSCI_E_SUCCESS) return rc; /* Query the psci_power_state for system suspend */ psci_query_sys_suspend_pwrstate(&state_info); /* * Check if platform allows suspend to Highest power level * (System level) */ if (psci_find_target_suspend_lvl(&state_info) < PLAT_MAX_PWR_LVL) return PSCI_E_DENIED; /* Ensure that the psci_power_state makes sense */ assert(psci_validate_suspend_req(&state_info, PSTATE_TYPE_POWERDOWN) == PSCI_E_SUCCESS); assert(is_local_state_off( state_info.pwr_domain_state[PLAT_MAX_PWR_LVL]) != 0); /* * Do what is needed to enter the system suspend state. This function * might return if the power down was abandoned for any reason, e.g. * arrival of an interrupt */ psci_cpu_suspend_start(&ep, PLAT_MAX_PWR_LVL, &state_info, PSTATE_TYPE_POWERDOWN); return PSCI_E_SUCCESS; } int psci_cpu_off(void) { int rc; unsigned int target_pwrlvl = PLAT_MAX_PWR_LVL; /* * Do what is needed to power off this CPU and possible higher power * levels if it able to do so. Upon success, enter the final wfi * which will power down this CPU. */ rc = psci_do_cpu_off(target_pwrlvl); /* * The only error cpu_off can return is E_DENIED. So check if that's * indeed the case. */ assert(rc == PSCI_E_DENIED); return rc; } int psci_affinity_info(u_register_t target_affinity, unsigned int lowest_affinity_level) { int target_idx; /* We dont support level higher than PSCI_CPU_PWR_LVL */ if (lowest_affinity_level > PSCI_CPU_PWR_LVL) return PSCI_E_INVALID_PARAMS; /* Calculate the cpu index of the target */ target_idx = plat_core_pos_by_mpidr(target_affinity); if (target_idx == -1) return PSCI_E_INVALID_PARAMS; /* * Generic management: * Perform cache maintanence ahead of reading the target CPU state to * ensure that the data is not stale. * There is a theoretical edge case where the cache may contain stale * data for the target CPU data - this can occur under the following * conditions: * - the target CPU is in another cluster from the current * - the target CPU was the last CPU to shutdown on its cluster * - the cluster was removed from coherency as part of the CPU shutdown * * In this case the cache maintenace that was performed as part of the * target CPUs shutdown was not seen by the current CPU's cluster. And * so the cache may contain stale data for the target CPU. */ flush_cpu_data_by_index((unsigned int)target_idx, psci_svc_cpu_data.aff_info_state); return psci_get_aff_info_state_by_idx(target_idx); } int psci_migrate(u_register_t target_cpu) { int rc; u_register_t resident_cpu_mpidr; rc = psci_spd_migrate_info(&resident_cpu_mpidr); if (rc != PSCI_TOS_UP_MIG_CAP) return (rc == PSCI_TOS_NOT_UP_MIG_CAP) ? PSCI_E_DENIED : PSCI_E_NOT_SUPPORTED; /* * Migrate should only be invoked on the CPU where * the Secure OS is resident. */ if (resident_cpu_mpidr != read_mpidr_el1()) return PSCI_E_NOT_PRESENT; /* Check the validity of the specified target cpu */ rc = psci_validate_mpidr(target_cpu); if (rc != PSCI_E_SUCCESS) return PSCI_E_INVALID_PARAMS; assert((psci_spd_pm != NULL) && (psci_spd_pm->svc_migrate != NULL)); rc = psci_spd_pm->svc_migrate(read_mpidr_el1(), target_cpu); assert((rc == PSCI_E_SUCCESS) || (rc == PSCI_E_INTERN_FAIL)); return rc; } int psci_migrate_info_type(void) { u_register_t resident_cpu_mpidr; return psci_spd_migrate_info(&resident_cpu_mpidr); } u_register_t psci_migrate_info_up_cpu(void) { u_register_t resident_cpu_mpidr; int rc; /* * Return value of this depends upon what * psci_spd_migrate_info() returns. */ rc = psci_spd_migrate_info(&resident_cpu_mpidr); if ((rc != PSCI_TOS_NOT_UP_MIG_CAP) && (rc != PSCI_TOS_UP_MIG_CAP)) return (u_register_t)(register_t) PSCI_E_INVALID_PARAMS; return resident_cpu_mpidr; } int psci_node_hw_state(u_register_t target_cpu, unsigned int power_level) { int rc; /* Validate target_cpu */ rc = psci_validate_mpidr(target_cpu); if (rc != PSCI_E_SUCCESS) return PSCI_E_INVALID_PARAMS; /* Validate power_level against PLAT_MAX_PWR_LVL */ if (power_level > PLAT_MAX_PWR_LVL) return PSCI_E_INVALID_PARAMS; /* * Dispatch this call to platform to query power controller, and pass on * to the caller what it returns */ assert(psci_plat_pm_ops->get_node_hw_state != NULL); rc = psci_plat_pm_ops->get_node_hw_state(target_cpu, power_level); assert(((rc >= HW_ON) && (rc <= HW_STANDBY)) || (rc == PSCI_E_NOT_SUPPORTED) || (rc == PSCI_E_INVALID_PARAMS)); return rc; } int psci_features(unsigned int psci_fid) { unsigned int local_caps = psci_caps; if (psci_fid == SMCCC_VERSION) return PSCI_E_SUCCESS; /* Check if it is a 64 bit function */ if (((psci_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_64) local_caps &= PSCI_CAP_64BIT_MASK; /* Check for invalid fid */ if (!(is_std_svc_call(psci_fid) && is_valid_fast_smc(psci_fid) && is_psci_fid(psci_fid))) return PSCI_E_NOT_SUPPORTED; /* Check if the psci fid is supported or not */ if ((local_caps & define_psci_cap(psci_fid)) == 0U) return PSCI_E_NOT_SUPPORTED; /* Format the feature flags */ if ((psci_fid == PSCI_CPU_SUSPEND_AARCH32) || (psci_fid == PSCI_CPU_SUSPEND_AARCH64)) { /* * The trusted firmware does not support OS Initiated Mode. */ unsigned int ret = ((FF_PSTATE << FF_PSTATE_SHIFT) | (((FF_SUPPORTS_OS_INIT_MODE == 1U) ? 0U : 1U) << FF_MODE_SUPPORT_SHIFT)); return (int) ret; } /* Return 0 for all other fid's */ return PSCI_E_SUCCESS; } /******************************************************************************* * PSCI top level handler for servicing SMCs. ******************************************************************************/ u_register_t psci_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) { u_register_t ret; if (is_caller_secure(flags)) return (u_register_t)SMC_UNK; /* Check the fid against the capabilities */ if ((psci_caps & define_psci_cap(smc_fid)) == 0U) return (u_register_t)SMC_UNK; if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) { /* 32-bit PSCI function, clear top parameter bits */ uint32_t r1 = (uint32_t)x1; uint32_t r2 = (uint32_t)x2; uint32_t r3 = (uint32_t)x3; switch (smc_fid) { case PSCI_VERSION: ret = (u_register_t)psci_version(); break; case PSCI_CPU_OFF: ret = (u_register_t)psci_cpu_off(); break; case PSCI_CPU_SUSPEND_AARCH32: ret = (u_register_t)psci_cpu_suspend(r1, r2, r3); break; case PSCI_CPU_ON_AARCH32: ret = (u_register_t)psci_cpu_on(r1, r2, r3); break; case PSCI_AFFINITY_INFO_AARCH32: ret = (u_register_t)psci_affinity_info(r1, r2); break; case PSCI_MIG_AARCH32: ret = (u_register_t)psci_migrate(r1); break; case PSCI_MIG_INFO_TYPE: ret = (u_register_t)psci_migrate_info_type(); break; case PSCI_MIG_INFO_UP_CPU_AARCH32: ret = psci_migrate_info_up_cpu(); break; case PSCI_NODE_HW_STATE_AARCH32: ret = (u_register_t)psci_node_hw_state(r1, r2); break; case PSCI_SYSTEM_SUSPEND_AARCH32: ret = (u_register_t)psci_system_suspend(r1, r2); break; case PSCI_SYSTEM_OFF: psci_system_off(); /* We should never return from psci_system_off() */ break; case PSCI_SYSTEM_RESET: psci_system_reset(); /* We should never return from psci_system_reset() */ break; case PSCI_FEATURES: ret = (u_register_t)psci_features(r1); break; #if ENABLE_PSCI_STAT case PSCI_STAT_RESIDENCY_AARCH32: ret = psci_stat_residency(r1, r2); break; case PSCI_STAT_COUNT_AARCH32: ret = psci_stat_count(r1, r2); break; #endif case PSCI_MEM_PROTECT: ret = psci_mem_protect(r1); break; case PSCI_MEM_CHK_RANGE_AARCH32: ret = psci_mem_chk_range(r1, r2); break; case PSCI_SYSTEM_RESET2_AARCH32: /* We should never return from psci_system_reset2() */ ret = psci_system_reset2(r1, r2); break; default: WARN("Unimplemented PSCI Call: 0x%x\n", smc_fid); ret = (u_register_t)SMC_UNK; break; } } else { /* 64-bit PSCI function */ switch (smc_fid) { case PSCI_CPU_SUSPEND_AARCH64: ret = (u_register_t) psci_cpu_suspend((unsigned int)x1, x2, x3); break; case PSCI_CPU_ON_AARCH64: ret = (u_register_t)psci_cpu_on(x1, x2, x3); break; case PSCI_AFFINITY_INFO_AARCH64: ret = (u_register_t) psci_affinity_info(x1, (unsigned int)x2); break; case PSCI_MIG_AARCH64: ret = (u_register_t)psci_migrate(x1); break; case PSCI_MIG_INFO_UP_CPU_AARCH64: ret = psci_migrate_info_up_cpu(); break; case PSCI_NODE_HW_STATE_AARCH64: ret = (u_register_t)psci_node_hw_state( x1, (unsigned int) x2); break; case PSCI_SYSTEM_SUSPEND_AARCH64: ret = (u_register_t)psci_system_suspend(x1, x2); break; #if ENABLE_PSCI_STAT case PSCI_STAT_RESIDENCY_AARCH64: ret = psci_stat_residency(x1, (unsigned int) x2); break; case PSCI_STAT_COUNT_AARCH64: ret = psci_stat_count(x1, (unsigned int) x2); break; #endif case PSCI_MEM_CHK_RANGE_AARCH64: ret = psci_mem_chk_range(x1, x2); break; case PSCI_SYSTEM_RESET2_AARCH64: /* We should never return from psci_system_reset2() */ ret = psci_system_reset2((uint32_t) x1, x2); break; default: WARN("Unimplemented PSCI Call: 0x%x\n", smc_fid); ret = (u_register_t)SMC_UNK; break; } } return ret; } trusted-firmware-a-2.2/lib/psci/psci_mem_protect.c000066400000000000000000000017641355360272700223250ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "psci_private.h" u_register_t psci_mem_protect(unsigned int enable) { int val; assert(psci_plat_pm_ops->read_mem_protect != NULL); assert(psci_plat_pm_ops->write_mem_protect != NULL); if (psci_plat_pm_ops->read_mem_protect(&val) < 0) return (u_register_t) PSCI_E_NOT_SUPPORTED; if (psci_plat_pm_ops->write_mem_protect(enable) < 0) return (u_register_t) PSCI_E_NOT_SUPPORTED; return (val != 0) ? 1U : 0U; } u_register_t psci_mem_chk_range(uintptr_t base, u_register_t length) { int ret; assert(psci_plat_pm_ops->mem_protect_chk != NULL); if ((length == 0U) || check_uptr_overflow(base, length - 1U)) return (u_register_t) PSCI_E_DENIED; ret = psci_plat_pm_ops->mem_protect_chk(base, length); return (ret < 0) ? (u_register_t) PSCI_E_DENIED : (u_register_t) PSCI_E_SUCCESS; } trusted-firmware-a-2.2/lib/psci/psci_off.c000066400000000000000000000133711355360272700205560ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include "psci_private.h" /****************************************************************************** * Construct the psci_power_state to request power OFF at all power levels. ******************************************************************************/ static void psci_set_power_off_state(psci_power_state_t *state_info) { unsigned int lvl; for (lvl = PSCI_CPU_PWR_LVL; lvl <= PLAT_MAX_PWR_LVL; lvl++) state_info->pwr_domain_state[lvl] = PLAT_MAX_OFF_STATE; } /****************************************************************************** * Top level handler which is called when a cpu wants to power itself down. * It's assumed that along with turning the cpu power domain off, power * domains at higher levels will be turned off as far as possible. It finds * the highest level where a domain has to be powered off by traversing the * node information and then performs generic, architectural, platform setup * and state management required to turn OFF that power domain and domains * below it. e.g. For a cpu that's to be powered OFF, it could mean programming * the power controller whereas for a cluster that's to be powered off, it will * call the platform specific code which will disable coherency at the * interconnect level if the cpu is the last in the cluster and also the * program the power controller. ******************************************************************************/ int psci_do_cpu_off(unsigned int end_pwrlvl) { int rc = PSCI_E_SUCCESS; int idx = (int) plat_my_core_pos(); psci_power_state_t state_info; unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0}; /* * This function must only be called on platforms where the * CPU_OFF platform hooks have been implemented. */ assert(psci_plat_pm_ops->pwr_domain_off != NULL); /* Construct the psci_power_state for CPU_OFF */ psci_set_power_off_state(&state_info); /* * Get the parent nodes here, this is important to do before we * initiate the power down sequence as after that point the core may * have exited coherency and its cache may be disabled, any access to * shared memory after that (such as the parent node lookup in * psci_cpu_pd_nodes) can cause coherency issues on some platforms. */ psci_get_parent_pwr_domain_nodes(idx, end_pwrlvl, parent_nodes); /* * This function acquires the lock corresponding to each power * level so that by the time all locks are taken, the system topology * is snapshot and state management can be done safely. */ psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes); /* * Call the cpu off handler registered by the Secure Payload Dispatcher * to let it do any bookkeeping. Assume that the SPD always reports an * E_DENIED error if SP refuse to power down */ if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_off != NULL)) { rc = psci_spd_pm->svc_off(0); if (rc != 0) goto exit; } /* * This function is passed the requested state info and * it returns the negotiated state info for each power level upto * the end level specified. */ psci_do_state_coordination(end_pwrlvl, &state_info); #if ENABLE_PSCI_STAT /* Update the last cpu for each level till end_pwrlvl */ psci_stats_update_pwr_down(end_pwrlvl, &state_info); #endif #if ENABLE_RUNTIME_INSTRUMENTATION /* * Flush cache line so that even if CPU power down happens * the timestamp update is reflected in memory. */ PMF_CAPTURE_TIMESTAMP(rt_instr_svc, RT_INSTR_ENTER_CFLUSH, PMF_CACHE_MAINT); #endif /* * Arch. management. Initiate power down sequence. */ psci_do_pwrdown_sequence(psci_find_max_off_lvl(&state_info)); #if ENABLE_RUNTIME_INSTRUMENTATION PMF_CAPTURE_TIMESTAMP(rt_instr_svc, RT_INSTR_EXIT_CFLUSH, PMF_NO_CACHE_MAINT); #endif /* * Plat. management: Perform platform specific actions to turn this * cpu off e.g. exit cpu coherency, program the power controller etc. */ psci_plat_pm_ops->pwr_domain_off(&state_info); #if ENABLE_PSCI_STAT plat_psci_stat_accounting_start(&state_info); #endif exit: /* * Release the locks corresponding to each power level in the * reverse order to which they were acquired. */ psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes); /* * Check if all actions needed to safely power down this cpu have * successfully completed. */ if (rc == PSCI_E_SUCCESS) { /* * Set the affinity info state to OFF. When caches are disabled, * this writes directly to main memory, so cache maintenance is * required to ensure that later cached reads of aff_info_state * return AFF_STATE_OFF. A dsbish() ensures ordering of the * update to the affinity info state prior to cache line * invalidation. */ psci_flush_cpu_data(psci_svc_cpu_data.aff_info_state); psci_set_aff_info_state(AFF_STATE_OFF); psci_dsbish(); psci_inv_cpu_data(psci_svc_cpu_data.aff_info_state); #if ENABLE_RUNTIME_INSTRUMENTATION /* * Update the timestamp with cache off. We assume this * timestamp can only be read from the current CPU and the * timestamp cache line will be flushed before return to * normal world on wakeup. */ PMF_CAPTURE_TIMESTAMP(rt_instr_svc, RT_INSTR_ENTER_HW_LOW_PWR, PMF_NO_CACHE_MAINT); #endif if (psci_plat_pm_ops->pwr_domain_pwr_down_wfi != NULL) { /* This function must not return */ psci_plat_pm_ops->pwr_domain_pwr_down_wfi(&state_info); } else { /* * Enter a wfi loop which will allow the power * controller to physically power down this cpu. */ psci_power_down_wfi(); } } return rc; } trusted-firmware-a-2.2/lib/psci/psci_on.c000066400000000000000000000172751355360272700204270ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "psci_private.h" /* * Helper functions for the CPU level spinlocks */ static inline void psci_spin_lock_cpu(int idx) { spin_lock(&psci_cpu_pd_nodes[idx].cpu_lock); } static inline void psci_spin_unlock_cpu(int idx) { spin_unlock(&psci_cpu_pd_nodes[idx].cpu_lock); } /******************************************************************************* * This function checks whether a cpu which has been requested to be turned on * is OFF to begin with. ******************************************************************************/ static int cpu_on_validate_state(aff_info_state_t aff_state) { if (aff_state == AFF_STATE_ON) return PSCI_E_ALREADY_ON; if (aff_state == AFF_STATE_ON_PENDING) return PSCI_E_ON_PENDING; assert(aff_state == AFF_STATE_OFF); return PSCI_E_SUCCESS; } /******************************************************************************* * Generic handler which is called to physically power on a cpu identified by * its mpidr. It performs the generic, architectural, platform setup and state * management to power on the target cpu e.g. it will ensure that * enough information is stashed for it to resume execution in the non-secure * security state. * * The state of all the relevant power domains are changed after calling the * platform handler as it can return error. ******************************************************************************/ int psci_cpu_on_start(u_register_t target_cpu, const entry_point_info_t *ep) { int rc; aff_info_state_t target_aff_state; int target_idx = plat_core_pos_by_mpidr(target_cpu); /* Calling function must supply valid input arguments */ assert(target_idx >= 0); assert(ep != NULL); /* * This function must only be called on platforms where the * CPU_ON platform hooks have been implemented. */ assert((psci_plat_pm_ops->pwr_domain_on != NULL) && (psci_plat_pm_ops->pwr_domain_on_finish != NULL)); /* Protect against multiple CPUs trying to turn ON the same target CPU */ psci_spin_lock_cpu(target_idx); /* * Generic management: Ensure that the cpu is off to be * turned on. * Perform cache maintanence ahead of reading the target CPU state to * ensure that the data is not stale. * There is a theoretical edge case where the cache may contain stale * data for the target CPU data - this can occur under the following * conditions: * - the target CPU is in another cluster from the current * - the target CPU was the last CPU to shutdown on its cluster * - the cluster was removed from coherency as part of the CPU shutdown * * In this case the cache maintenace that was performed as part of the * target CPUs shutdown was not seen by the current CPU's cluster. And * so the cache may contain stale data for the target CPU. */ flush_cpu_data_by_index((unsigned int)target_idx, psci_svc_cpu_data.aff_info_state); rc = cpu_on_validate_state(psci_get_aff_info_state_by_idx(target_idx)); if (rc != PSCI_E_SUCCESS) goto exit; /* * Call the cpu on handler registered by the Secure Payload Dispatcher * to let it do any bookeeping. If the handler encounters an error, it's * expected to assert within */ if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_on != NULL)) psci_spd_pm->svc_on(target_cpu); /* * Set the Affinity info state of the target cpu to ON_PENDING. * Flush aff_info_state as it will be accessed with caches * turned OFF. */ psci_set_aff_info_state_by_idx(target_idx, AFF_STATE_ON_PENDING); flush_cpu_data_by_index((unsigned int)target_idx, psci_svc_cpu_data.aff_info_state); /* * The cache line invalidation by the target CPU after setting the * state to OFF (see psci_do_cpu_off()), could cause the update to * aff_info_state to be invalidated. Retry the update if the target * CPU aff_info_state is not ON_PENDING. */ target_aff_state = psci_get_aff_info_state_by_idx(target_idx); if (target_aff_state != AFF_STATE_ON_PENDING) { assert(target_aff_state == AFF_STATE_OFF); psci_set_aff_info_state_by_idx(target_idx, AFF_STATE_ON_PENDING); flush_cpu_data_by_index((unsigned int)target_idx, psci_svc_cpu_data.aff_info_state); assert(psci_get_aff_info_state_by_idx(target_idx) == AFF_STATE_ON_PENDING); } /* * Perform generic, architecture and platform specific handling. */ /* * Plat. management: Give the platform the current state * of the target cpu to allow it to perform the necessary * steps to power on. */ rc = psci_plat_pm_ops->pwr_domain_on(target_cpu); assert((rc == PSCI_E_SUCCESS) || (rc == PSCI_E_INTERN_FAIL)); if (rc == PSCI_E_SUCCESS) /* Store the re-entry information for the non-secure world. */ cm_init_context_by_index((unsigned int)target_idx, ep); else { /* Restore the state on error. */ psci_set_aff_info_state_by_idx(target_idx, AFF_STATE_OFF); flush_cpu_data_by_index((unsigned int)target_idx, psci_svc_cpu_data.aff_info_state); } exit: psci_spin_unlock_cpu(target_idx); return rc; } /******************************************************************************* * The following function finish an earlier power on request. They * are called by the common finisher routine in psci_common.c. The `state_info` * is the psci_power_state from which this CPU has woken up from. ******************************************************************************/ void psci_cpu_on_finish(int cpu_idx, const psci_power_state_t *state_info) { /* * Plat. management: Perform the platform specific actions * for this cpu e.g. enabling the gic or zeroing the mailbox * register. The actual state of this cpu has already been * changed. */ psci_plat_pm_ops->pwr_domain_on_finish(state_info); #if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY) /* * Arch. management: Enable data cache and manage stack memory */ psci_do_pwrup_cache_maintenance(); #endif /* * Plat. management: Perform any platform specific actions which * can only be done with the cpu and the cluster guaranteed to * be coherent. */ if (psci_plat_pm_ops->pwr_domain_on_finish_late != NULL) psci_plat_pm_ops->pwr_domain_on_finish_late(state_info); /* * All the platform specific actions for turning this cpu * on have completed. Perform enough arch.initialization * to run in the non-secure address space. */ psci_arch_setup(); /* * Lock the CPU spin lock to make sure that the context initialization * is done. Since the lock is only used in this function to create * a synchronization point with cpu_on_start(), it can be released * immediately. */ psci_spin_lock_cpu(cpu_idx); psci_spin_unlock_cpu(cpu_idx); /* Ensure we have been explicitly woken up by another cpu */ assert(psci_get_aff_info_state() == AFF_STATE_ON_PENDING); /* * Call the cpu on finish handler registered by the Secure Payload * Dispatcher to let it do any bookeeping. If the handler encounters an * error, it's expected to assert within */ if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_on_finish != NULL)) psci_spd_pm->svc_on_finish(0); PUBLISH_EVENT(psci_cpu_on_finish); /* Populate the mpidr field within the cpu node array */ /* This needs to be done only once */ psci_cpu_pd_nodes[cpu_idx].mpidr = read_mpidr() & MPIDR_AFFINITY_MASK; /* * Generic management: Now we just need to retrieve the * information that we had stashed away during the cpu_on * call to set this cpu on its way. */ cm_prepare_el3_exit(NON_SECURE); } trusted-firmware-a-2.2/lib/psci/psci_private.h000066400000000000000000000261631355360272700214660ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PSCI_PRIVATE_H #define PSCI_PRIVATE_H #include #include #include #include #include #include #include #include /* * The PSCI capability which are provided by the generic code but does not * depend on the platform or spd capabilities. */ #define PSCI_GENERIC_CAP \ (define_psci_cap(PSCI_VERSION) | \ define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) | \ define_psci_cap(PSCI_FEATURES)) /* * The PSCI capabilities mask for 64 bit functions. */ #define PSCI_CAP_64BIT_MASK \ (define_psci_cap(PSCI_CPU_SUSPEND_AARCH64) | \ define_psci_cap(PSCI_CPU_ON_AARCH64) | \ define_psci_cap(PSCI_AFFINITY_INFO_AARCH64) | \ define_psci_cap(PSCI_MIG_AARCH64) | \ define_psci_cap(PSCI_MIG_INFO_UP_CPU_AARCH64) | \ define_psci_cap(PSCI_NODE_HW_STATE_AARCH64) | \ define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64) | \ define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64) | \ define_psci_cap(PSCI_STAT_COUNT_AARCH64) | \ define_psci_cap(PSCI_SYSTEM_RESET2_AARCH64) | \ define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64)) /* * Helper functions to get/set the fields of PSCI per-cpu data. */ static inline void psci_set_aff_info_state(aff_info_state_t aff_state) { set_cpu_data(psci_svc_cpu_data.aff_info_state, aff_state); } static inline aff_info_state_t psci_get_aff_info_state(void) { return get_cpu_data(psci_svc_cpu_data.aff_info_state); } static inline aff_info_state_t psci_get_aff_info_state_by_idx(unsigned int idx) { return get_cpu_data_by_index(idx, psci_svc_cpu_data.aff_info_state); } static inline void psci_set_aff_info_state_by_idx(unsigned int idx, aff_info_state_t aff_state) { set_cpu_data_by_index(idx, psci_svc_cpu_data.aff_info_state, aff_state); } static inline unsigned int psci_get_suspend_pwrlvl(void) { return get_cpu_data(psci_svc_cpu_data.target_pwrlvl); } static inline void psci_set_suspend_pwrlvl(unsigned int target_lvl) { set_cpu_data(psci_svc_cpu_data.target_pwrlvl, target_lvl); } static inline void psci_set_cpu_local_state(plat_local_state_t state) { set_cpu_data(psci_svc_cpu_data.local_state, state); } static inline plat_local_state_t psci_get_cpu_local_state(void) { return get_cpu_data(psci_svc_cpu_data.local_state); } static inline plat_local_state_t psci_get_cpu_local_state_by_idx( unsigned int idx) { return get_cpu_data_by_index(idx, psci_svc_cpu_data.local_state); } /* Helper function to identify a CPU standby request in PSCI Suspend call */ static inline bool is_cpu_standby_req(unsigned int is_power_down_state, unsigned int retn_lvl) { return (is_power_down_state == 0U) && (retn_lvl == 0U); } /******************************************************************************* * The following two data structures implement the power domain tree. The tree * is used to track the state of all the nodes i.e. power domain instances * described by the platform. The tree consists of nodes that describe CPU power * domains i.e. leaf nodes and all other power domains which are parents of a * CPU power domain i.e. non-leaf nodes. ******************************************************************************/ typedef struct non_cpu_pwr_domain_node { /* * Index of the first CPU power domain node level 0 which has this node * as its parent. */ unsigned int cpu_start_idx; /* * Number of CPU power domains which are siblings of the domain indexed * by 'cpu_start_idx' i.e. all the domains in the range 'cpu_start_idx * -> cpu_start_idx + ncpus' have this node as their parent. */ unsigned int ncpus; /* * Index of the parent power domain node. * TODO: Figure out whether to whether using pointer is more efficient. */ unsigned int parent_node; plat_local_state_t local_state; unsigned char level; /* For indexing the psci_lock array*/ unsigned char lock_index; } non_cpu_pd_node_t; typedef struct cpu_pwr_domain_node { u_register_t mpidr; /* * Index of the parent power domain node. * TODO: Figure out whether to whether using pointer is more efficient. */ unsigned int parent_node; /* * A CPU power domain does not require state coordination like its * parent power domains. Hence this node does not include a bakery * lock. A spinlock is required by the CPU_ON handler to prevent a race * when multiple CPUs try to turn ON the same target CPU. */ spinlock_t cpu_lock; } cpu_pd_node_t; /******************************************************************************* * The following are helpers and declarations of locks. ******************************************************************************/ #if HW_ASSISTED_COHERENCY /* * On systems where participant CPUs are cache-coherent, we can use spinlocks * instead of bakery locks. */ #define DEFINE_PSCI_LOCK(_name) spinlock_t _name #define DECLARE_PSCI_LOCK(_name) extern DEFINE_PSCI_LOCK(_name) /* One lock is required per non-CPU power domain node */ DECLARE_PSCI_LOCK(psci_locks[PSCI_NUM_NON_CPU_PWR_DOMAINS]); /* * On systems with hardware-assisted coherency, make PSCI cache operations NOP, * as PSCI participants are cache-coherent, and there's no need for explicit * cache maintenance operations or barriers to coordinate their state. */ static inline void psci_flush_dcache_range(uintptr_t __unused addr, size_t __unused size) { /* Empty */ } #define psci_flush_cpu_data(member) #define psci_inv_cpu_data(member) static inline void psci_dsbish(void) { /* Empty */ } static inline void psci_lock_get(non_cpu_pd_node_t *non_cpu_pd_node) { spin_lock(&psci_locks[non_cpu_pd_node->lock_index]); } static inline void psci_lock_release(non_cpu_pd_node_t *non_cpu_pd_node) { spin_unlock(&psci_locks[non_cpu_pd_node->lock_index]); } #else /* if HW_ASSISTED_COHERENCY == 0 */ /* * Use bakery locks for state coordination as not all PSCI participants are * cache coherent. */ #define DEFINE_PSCI_LOCK(_name) DEFINE_BAKERY_LOCK(_name) #define DECLARE_PSCI_LOCK(_name) DECLARE_BAKERY_LOCK(_name) /* One lock is required per non-CPU power domain node */ DECLARE_PSCI_LOCK(psci_locks[PSCI_NUM_NON_CPU_PWR_DOMAINS]); /* * If not all PSCI participants are cache-coherent, perform cache maintenance * and issue barriers wherever required to coordinate state. */ static inline void psci_flush_dcache_range(uintptr_t addr, size_t size) { flush_dcache_range(addr, size); } #define psci_flush_cpu_data(member) flush_cpu_data(member) #define psci_inv_cpu_data(member) inv_cpu_data(member) static inline void psci_dsbish(void) { dsbish(); } static inline void psci_lock_get(non_cpu_pd_node_t *non_cpu_pd_node) { bakery_lock_get(&psci_locks[non_cpu_pd_node->lock_index]); } static inline void psci_lock_release(non_cpu_pd_node_t *non_cpu_pd_node) { bakery_lock_release(&psci_locks[non_cpu_pd_node->lock_index]); } #endif /* HW_ASSISTED_COHERENCY */ static inline void psci_lock_init(non_cpu_pd_node_t *non_cpu_pd_node, unsigned char idx) { non_cpu_pd_node[idx].lock_index = idx; } /******************************************************************************* * Data prototypes ******************************************************************************/ extern const plat_psci_ops_t *psci_plat_pm_ops; extern non_cpu_pd_node_t psci_non_cpu_pd_nodes[PSCI_NUM_NON_CPU_PWR_DOMAINS]; extern cpu_pd_node_t psci_cpu_pd_nodes[PLATFORM_CORE_COUNT]; extern unsigned int psci_caps; /******************************************************************************* * SPD's power management hooks registered with PSCI ******************************************************************************/ extern const spd_pm_ops_t *psci_spd_pm; /******************************************************************************* * Function prototypes ******************************************************************************/ /* Private exported functions from psci_common.c */ int psci_validate_power_state(unsigned int power_state, psci_power_state_t *state_info); void psci_query_sys_suspend_pwrstate(psci_power_state_t *state_info); int psci_validate_mpidr(u_register_t mpidr); void psci_init_req_local_pwr_states(void); void psci_get_target_local_pwr_states(unsigned int end_pwrlvl, psci_power_state_t *target_state); int psci_validate_entry_point(entry_point_info_t *ep, uintptr_t entrypoint, u_register_t context_id); void psci_get_parent_pwr_domain_nodes(unsigned int cpu_idx, unsigned int end_lvl, unsigned int *node_index); void psci_do_state_coordination(unsigned int end_pwrlvl, psci_power_state_t *state_info); void psci_acquire_pwr_domain_locks(unsigned int end_pwrlvl, const unsigned int *parent_nodes); void psci_release_pwr_domain_locks(unsigned int end_pwrlvl, const unsigned int *parent_nodes); int psci_validate_suspend_req(const psci_power_state_t *state_info, unsigned int is_power_down_state); unsigned int psci_find_max_off_lvl(const psci_power_state_t *state_info); unsigned int psci_find_target_suspend_lvl(const psci_power_state_t *state_info); void psci_set_pwr_domains_to_run(unsigned int end_pwrlvl); void psci_print_power_domain_map(void); unsigned int psci_is_last_on_cpu(void); int psci_spd_migrate_info(u_register_t *mpidr); void psci_do_pwrdown_sequence(unsigned int power_level); /* * CPU power down is directly called only when HW_ASSISTED_COHERENCY is * available. Otherwise, this needs post-call stack maintenance, which is * handled in assembly. */ void prepare_cpu_pwr_dwn(unsigned int power_level); /* Private exported functions from psci_on.c */ int psci_cpu_on_start(u_register_t target_cpu, const entry_point_info_t *ep); void psci_cpu_on_finish(int cpu_idx, const psci_power_state_t *state_info); /* Private exported functions from psci_off.c */ int psci_do_cpu_off(unsigned int end_pwrlvl); /* Private exported functions from psci_suspend.c */ void psci_cpu_suspend_start(const entry_point_info_t *ep, unsigned int end_pwrlvl, psci_power_state_t *state_info, unsigned int is_power_down_state); void psci_cpu_suspend_finish(int cpu_idx, const psci_power_state_t *state_info); /* Private exported functions from psci_helpers.S */ void psci_do_pwrdown_cache_maintenance(unsigned int pwr_level); void psci_do_pwrup_cache_maintenance(void); /* Private exported functions from psci_system_off.c */ void __dead2 psci_system_off(void); void __dead2 psci_system_reset(void); u_register_t psci_system_reset2(uint32_t reset_type, u_register_t cookie); /* Private exported functions from psci_stat.c */ void psci_stats_update_pwr_down(unsigned int end_pwrlvl, const psci_power_state_t *state_info); void psci_stats_update_pwr_up(unsigned int end_pwrlvl, const psci_power_state_t *state_info); u_register_t psci_stat_residency(u_register_t target_cpu, unsigned int power_state); u_register_t psci_stat_count(u_register_t target_cpu, unsigned int power_state); /* Private exported functions from psci_mem_protect.c */ u_register_t psci_mem_protect(unsigned int enable); u_register_t psci_mem_chk_range(uintptr_t base, u_register_t length); #endif /* PSCI_PRIVATE_H */ trusted-firmware-a-2.2/lib/psci/psci_setup.c000066400000000000000000000263731355360272700211520ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "psci_private.h" /******************************************************************************* * Per cpu non-secure contexts used to program the architectural state prior * return to the normal world. * TODO: Use the memory allocator to set aside memory for the contexts instead * of relying on platform defined constants. ******************************************************************************/ static cpu_context_t psci_ns_context[PLATFORM_CORE_COUNT]; /****************************************************************************** * Define the psci capability variable. *****************************************************************************/ unsigned int psci_caps; /******************************************************************************* * Function which initializes the 'psci_non_cpu_pd_nodes' or the * 'psci_cpu_pd_nodes' corresponding to the power level. ******************************************************************************/ static void __init psci_init_pwr_domain_node(unsigned char node_idx, unsigned int parent_idx, unsigned char level) { if (level > PSCI_CPU_PWR_LVL) { psci_non_cpu_pd_nodes[node_idx].level = level; psci_lock_init(psci_non_cpu_pd_nodes, node_idx); psci_non_cpu_pd_nodes[node_idx].parent_node = parent_idx; psci_non_cpu_pd_nodes[node_idx].local_state = PLAT_MAX_OFF_STATE; } else { psci_cpu_data_t *svc_cpu_data; psci_cpu_pd_nodes[node_idx].parent_node = parent_idx; /* Initialize with an invalid mpidr */ psci_cpu_pd_nodes[node_idx].mpidr = PSCI_INVALID_MPIDR; svc_cpu_data = &(_cpu_data_by_index(node_idx)->psci_svc_cpu_data); /* Set the Affinity Info for the cores as OFF */ svc_cpu_data->aff_info_state = AFF_STATE_OFF; /* Invalidate the suspend level for the cpu */ svc_cpu_data->target_pwrlvl = PSCI_INVALID_PWR_LVL; /* Set the power state to OFF state */ svc_cpu_data->local_state = PLAT_MAX_OFF_STATE; psci_flush_dcache_range((uintptr_t)svc_cpu_data, sizeof(*svc_cpu_data)); cm_set_context_by_index(node_idx, (void *) &psci_ns_context[node_idx], NON_SECURE); } } /******************************************************************************* * This functions updates cpu_start_idx and ncpus field for each of the node in * psci_non_cpu_pd_nodes[]. It does so by comparing the parent nodes of each of * the CPUs and check whether they match with the parent of the previous * CPU. The basic assumption for this work is that children of the same parent * are allocated adjacent indices. The platform should ensure this though proper * mapping of the CPUs to indices via plat_core_pos_by_mpidr() and * plat_my_core_pos() APIs. *******************************************************************************/ static void __init psci_update_pwrlvl_limits(void) { int j, cpu_idx; unsigned int nodes_idx[PLAT_MAX_PWR_LVL] = {0}; unsigned int temp_index[PLAT_MAX_PWR_LVL]; for (cpu_idx = 0; cpu_idx < PLATFORM_CORE_COUNT; cpu_idx++) { psci_get_parent_pwr_domain_nodes(cpu_idx, (unsigned int)PLAT_MAX_PWR_LVL, temp_index); for (j = (int) PLAT_MAX_PWR_LVL - 1; j >= 0; j--) { if (temp_index[j] != nodes_idx[j]) { nodes_idx[j] = temp_index[j]; psci_non_cpu_pd_nodes[nodes_idx[j]].cpu_start_idx = cpu_idx; } psci_non_cpu_pd_nodes[nodes_idx[j]].ncpus++; } } } /******************************************************************************* * Core routine to populate the power domain tree. The tree descriptor passed by * the platform is populated breadth-first and the first entry in the map * informs the number of root power domains. The parent nodes of the root nodes * will point to an invalid entry(-1). ******************************************************************************/ static void __init populate_power_domain_tree(const unsigned char *topology) { unsigned int i, j = 0U, num_nodes_at_lvl = 1U, num_nodes_at_next_lvl; unsigned int node_index = 0U, num_children; int parent_node_index = 0; int level = (int) PLAT_MAX_PWR_LVL; /* * For each level the inputs are: * - number of nodes at this level in plat_array i.e. num_nodes_at_level * This is the sum of values of nodes at the parent level. * - Index of first entry at this level in the plat_array i.e. * parent_node_index. * - Index of first free entry in psci_non_cpu_pd_nodes[] or * psci_cpu_pd_nodes[] i.e. node_index depending upon the level. */ while (level >= (int) PSCI_CPU_PWR_LVL) { num_nodes_at_next_lvl = 0U; /* * For each entry (parent node) at this level in the plat_array: * - Find the number of children * - Allocate a node in a power domain array for each child * - Set the parent of the child to the parent_node_index - 1 * - Increment parent_node_index to point to the next parent * - Accumulate the number of children at next level. */ for (i = 0U; i < num_nodes_at_lvl; i++) { assert(parent_node_index <= PSCI_NUM_NON_CPU_PWR_DOMAINS); num_children = topology[parent_node_index]; for (j = node_index; j < (node_index + num_children); j++) psci_init_pwr_domain_node((unsigned char)j, parent_node_index - 1, (unsigned char)level); node_index = j; num_nodes_at_next_lvl += num_children; parent_node_index++; } num_nodes_at_lvl = num_nodes_at_next_lvl; level--; /* Reset the index for the cpu power domain array */ if (level == (int) PSCI_CPU_PWR_LVL) node_index = 0; } /* Validate the sanity of array exported by the platform */ assert((int) j == PLATFORM_CORE_COUNT); } /******************************************************************************* * This function does the architectural setup and takes the warm boot * entry-point `mailbox_ep` as an argument. The function also initializes the * power domain topology tree by querying the platform. The power domain nodes * higher than the CPU are populated in the array psci_non_cpu_pd_nodes[] and * the CPU power domains are populated in psci_cpu_pd_nodes[]. The platform * exports its static topology map through the * populate_power_domain_topology_tree() API. The algorithm populates the * psci_non_cpu_pd_nodes and psci_cpu_pd_nodes iteratively by using this * topology map. On a platform that implements two clusters of 2 cpus each, * and supporting 3 domain levels, the populated psci_non_cpu_pd_nodes would * look like this: * * --------------------------------------------------- * | system node | cluster 0 node | cluster 1 node | * --------------------------------------------------- * * And populated psci_cpu_pd_nodes would look like this : * <- cpus cluster0 -><- cpus cluster1 -> * ------------------------------------------------ * | CPU 0 | CPU 1 | CPU 2 | CPU 3 | * ------------------------------------------------ ******************************************************************************/ int __init psci_setup(const psci_lib_args_t *lib_args) { const unsigned char *topology_tree; assert(VERIFY_PSCI_LIB_ARGS_V1(lib_args)); /* Do the Architectural initialization */ psci_arch_setup(); /* Query the topology map from the platform */ topology_tree = plat_get_power_domain_tree_desc(); /* Populate the power domain arrays using the platform topology map */ populate_power_domain_tree(topology_tree); /* Update the CPU limits for each node in psci_non_cpu_pd_nodes */ psci_update_pwrlvl_limits(); /* Populate the mpidr field of cpu node for this CPU */ psci_cpu_pd_nodes[plat_my_core_pos()].mpidr = read_mpidr() & MPIDR_AFFINITY_MASK; psci_init_req_local_pwr_states(); /* * Set the requested and target state of this CPU and all the higher * power domain levels for this CPU to run. */ psci_set_pwr_domains_to_run(PLAT_MAX_PWR_LVL); (void) plat_setup_psci_ops((uintptr_t)lib_args->mailbox_ep, &psci_plat_pm_ops); assert(psci_plat_pm_ops != NULL); /* * Flush `psci_plat_pm_ops` as it will be accessed by secondary CPUs * during warm boot, possibly before data cache is enabled. */ psci_flush_dcache_range((uintptr_t)&psci_plat_pm_ops, sizeof(psci_plat_pm_ops)); /* Initialize the psci capability */ psci_caps = PSCI_GENERIC_CAP; if (psci_plat_pm_ops->pwr_domain_off != NULL) psci_caps |= define_psci_cap(PSCI_CPU_OFF); if ((psci_plat_pm_ops->pwr_domain_on != NULL) && (psci_plat_pm_ops->pwr_domain_on_finish != NULL)) psci_caps |= define_psci_cap(PSCI_CPU_ON_AARCH64); if ((psci_plat_pm_ops->pwr_domain_suspend != NULL) && (psci_plat_pm_ops->pwr_domain_suspend_finish != NULL)) { psci_caps |= define_psci_cap(PSCI_CPU_SUSPEND_AARCH64); if (psci_plat_pm_ops->get_sys_suspend_power_state != NULL) psci_caps |= define_psci_cap(PSCI_SYSTEM_SUSPEND_AARCH64); } if (psci_plat_pm_ops->system_off != NULL) psci_caps |= define_psci_cap(PSCI_SYSTEM_OFF); if (psci_plat_pm_ops->system_reset != NULL) psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET); if (psci_plat_pm_ops->get_node_hw_state != NULL) psci_caps |= define_psci_cap(PSCI_NODE_HW_STATE_AARCH64); if ((psci_plat_pm_ops->read_mem_protect != NULL) && (psci_plat_pm_ops->write_mem_protect != NULL)) psci_caps |= define_psci_cap(PSCI_MEM_PROTECT); if (psci_plat_pm_ops->mem_protect_chk != NULL) psci_caps |= define_psci_cap(PSCI_MEM_CHK_RANGE_AARCH64); if (psci_plat_pm_ops->system_reset2 != NULL) psci_caps |= define_psci_cap(PSCI_SYSTEM_RESET2_AARCH64); #if ENABLE_PSCI_STAT psci_caps |= define_psci_cap(PSCI_STAT_RESIDENCY_AARCH64); psci_caps |= define_psci_cap(PSCI_STAT_COUNT_AARCH64); #endif return 0; } /******************************************************************************* * This duplicates what the primary cpu did after a cold boot in BL1. The same * needs to be done when a cpu is hotplugged in. This function could also over- * ride any EL3 setup done by BL1 as this code resides in rw memory. ******************************************************************************/ void psci_arch_setup(void) { #if (ARM_ARCH_MAJOR > 7) || defined(ARMV7_SUPPORTS_GENERIC_TIMER) /* Program the counter frequency */ write_cntfrq_el0(plat_get_syscnt_freq2()); #endif /* Initialize the cpu_ops pointer. */ init_cpu_ops(); /* Having initialized cpu_ops, we can now print errata status */ print_errata_status(); #if ENABLE_PAUTH /* Store APIAKey_EL1 key */ set_cpu_data(apiakey[0], read_apiakeylo_el1()); set_cpu_data(apiakey[1], read_apiakeyhi_el1()); #endif /* ENABLE_PAUTH */ } /****************************************************************************** * PSCI Library interface to initialize the cpu context for the next non * secure image during cold boot. The relevant registers in the cpu context * need to be retrieved and programmed on return from this interface. *****************************************************************************/ void psci_prepare_next_non_secure_ctx(entry_point_info_t *next_image_info) { assert(GET_SECURITY_STATE(next_image_info->h.attr) == NON_SECURE); cm_init_my_context(next_image_info); cm_prepare_el3_exit(NON_SECURE); } trusted-firmware-a-2.2/lib/psci/psci_stat.c000066400000000000000000000172361355360272700207630ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "psci_private.h" #ifndef PLAT_MAX_PWR_LVL_STATES #define PLAT_MAX_PWR_LVL_STATES 2U #endif /* Following structure is used for PSCI STAT */ typedef struct psci_stat { u_register_t residency; u_register_t count; } psci_stat_t; /* * Following is used to keep track of the last cpu * that goes to power down in non cpu power domains. */ static int last_cpu_in_non_cpu_pd[PSCI_NUM_NON_CPU_PWR_DOMAINS] = { [0 ... PSCI_NUM_NON_CPU_PWR_DOMAINS - 1] = -1}; /* * Following are used to store PSCI STAT values for * CPU and non CPU power domains. */ static psci_stat_t psci_cpu_stat[PLATFORM_CORE_COUNT] [PLAT_MAX_PWR_LVL_STATES]; static psci_stat_t psci_non_cpu_stat[PSCI_NUM_NON_CPU_PWR_DOMAINS] [PLAT_MAX_PWR_LVL_STATES]; /* * This functions returns the index into the `psci_stat_t` array given the * local power state and power domain level. If the platform implements the * `get_pwr_lvl_state_idx` pm hook, then that will be used to return the index. */ static int get_stat_idx(plat_local_state_t local_state, unsigned int pwr_lvl) { int idx; if (psci_plat_pm_ops->get_pwr_lvl_state_idx == NULL) { assert(PLAT_MAX_PWR_LVL_STATES == 2U); if (is_local_state_retn(local_state) != 0) return 0; assert(is_local_state_off(local_state) != 0); return 1; } idx = psci_plat_pm_ops->get_pwr_lvl_state_idx(local_state, pwr_lvl); assert((idx >= 0) && (idx < (int) PLAT_MAX_PWR_LVL_STATES)); return idx; } /******************************************************************************* * This function is passed the target local power states for each power * domain (state_info) between the current CPU domain and its ancestors until * the target power level (end_pwrlvl). * * Then, for each level (apart from the CPU level) until the 'end_pwrlvl', it * updates the `last_cpu_in_non_cpu_pd[]` with last power down cpu id. * * This function will only be invoked with data cache enabled and while * powering down a core. ******************************************************************************/ void psci_stats_update_pwr_down(unsigned int end_pwrlvl, const psci_power_state_t *state_info) { unsigned int lvl, parent_idx; int cpu_idx = (int) plat_my_core_pos(); assert(end_pwrlvl <= PLAT_MAX_PWR_LVL); assert(state_info != NULL); parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node; for (lvl = PSCI_CPU_PWR_LVL + 1U; lvl <= end_pwrlvl; lvl++) { /* Break early if the target power state is RUN */ if (is_local_state_run(state_info->pwr_domain_state[lvl]) != 0) break; /* * The power domain is entering a low power state, so this is * the last CPU for this power domain */ last_cpu_in_non_cpu_pd[parent_idx] = cpu_idx; parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node; } } /******************************************************************************* * This function updates the PSCI STATS(residency time and count) for CPU * and NON-CPU power domains. * It is called with caches enabled and locks acquired(for NON-CPU domain) ******************************************************************************/ void psci_stats_update_pwr_up(unsigned int end_pwrlvl, const psci_power_state_t *state_info) { unsigned int lvl, parent_idx; int cpu_idx = (int) plat_my_core_pos(); int stat_idx; plat_local_state_t local_state; u_register_t residency; assert(end_pwrlvl <= PLAT_MAX_PWR_LVL); assert(state_info != NULL); /* Get the index into the stats array */ local_state = state_info->pwr_domain_state[PSCI_CPU_PWR_LVL]; stat_idx = get_stat_idx(local_state, PSCI_CPU_PWR_LVL); /* Call into platform interface to calculate residency. */ residency = plat_psci_stat_get_residency(PSCI_CPU_PWR_LVL, state_info, cpu_idx); /* Update CPU stats. */ psci_cpu_stat[cpu_idx][stat_idx].residency += residency; psci_cpu_stat[cpu_idx][stat_idx].count++; /* * Check what power domains above CPU were off * prior to this CPU powering on. */ parent_idx = psci_cpu_pd_nodes[cpu_idx].parent_node; /* Return early if this is the first power up. */ if (last_cpu_in_non_cpu_pd[parent_idx] == -1) return; for (lvl = PSCI_CPU_PWR_LVL + 1U; lvl <= end_pwrlvl; lvl++) { local_state = state_info->pwr_domain_state[lvl]; if (is_local_state_run(local_state) != 0) { /* Break early */ break; } assert(last_cpu_in_non_cpu_pd[parent_idx] != -1); /* Call into platform interface to calculate residency. */ residency = plat_psci_stat_get_residency(lvl, state_info, last_cpu_in_non_cpu_pd[parent_idx]); /* Initialize back to reset value */ last_cpu_in_non_cpu_pd[parent_idx] = -1; /* Get the index into the stats array */ stat_idx = get_stat_idx(local_state, lvl); /* Update non cpu stats */ psci_non_cpu_stat[parent_idx][stat_idx].residency += residency; psci_non_cpu_stat[parent_idx][stat_idx].count++; parent_idx = psci_non_cpu_pd_nodes[parent_idx].parent_node; } } /******************************************************************************* * This function returns the appropriate count and residency time of the * local state for the highest power level expressed in the `power_state` * for the node represented by `target_cpu`. ******************************************************************************/ static int psci_get_stat(u_register_t target_cpu, unsigned int power_state, psci_stat_t *psci_stat) { int rc; unsigned int pwrlvl, lvl, parent_idx, target_idx; int stat_idx; psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} }; plat_local_state_t local_state; /* Validate the target_cpu parameter and determine the cpu index */ target_idx = (unsigned int) plat_core_pos_by_mpidr(target_cpu); if (target_idx == (unsigned int) -1) return PSCI_E_INVALID_PARAMS; /* Validate the power_state parameter */ if (psci_plat_pm_ops->translate_power_state_by_mpidr == NULL) rc = psci_validate_power_state(power_state, &state_info); else rc = psci_plat_pm_ops->translate_power_state_by_mpidr( target_cpu, power_state, &state_info); if (rc != PSCI_E_SUCCESS) return PSCI_E_INVALID_PARAMS; /* Find the highest power level */ pwrlvl = psci_find_target_suspend_lvl(&state_info); if (pwrlvl == PSCI_INVALID_PWR_LVL) { ERROR("Invalid target power level for PSCI statistics operation\n"); panic(); } /* Get the index into the stats array */ local_state = state_info.pwr_domain_state[pwrlvl]; stat_idx = get_stat_idx(local_state, pwrlvl); if (pwrlvl > PSCI_CPU_PWR_LVL) { /* Get the power domain index */ parent_idx = SPECULATION_SAFE_VALUE(psci_cpu_pd_nodes[target_idx].parent_node); for (lvl = PSCI_CPU_PWR_LVL + 1U; lvl < pwrlvl; lvl++) parent_idx = SPECULATION_SAFE_VALUE(psci_non_cpu_pd_nodes[parent_idx].parent_node); /* Get the non cpu power domain stats */ *psci_stat = psci_non_cpu_stat[parent_idx][stat_idx]; } else { /* Get the cpu power domain stats */ *psci_stat = psci_cpu_stat[target_idx][stat_idx]; } return PSCI_E_SUCCESS; } /* This is the top level function for PSCI_STAT_RESIDENCY SMC. */ u_register_t psci_stat_residency(u_register_t target_cpu, unsigned int power_state) { psci_stat_t psci_stat; int rc = psci_get_stat(target_cpu, power_state, &psci_stat); if (rc == PSCI_E_SUCCESS) return psci_stat.residency; else return 0; } /* This is the top level function for PSCI_STAT_COUNT SMC. */ u_register_t psci_stat_count(u_register_t target_cpu, unsigned int power_state) { psci_stat_t psci_stat; int rc = psci_get_stat(target_cpu, power_state, &psci_stat); if (rc == PSCI_E_SUCCESS) return psci_stat.count; else return 0; } trusted-firmware-a-2.2/lib/psci/psci_suspend.c000066400000000000000000000254361355360272700214720ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "psci_private.h" /******************************************************************************* * This function does generic and platform specific operations after a wake-up * from standby/retention states at multiple power levels. ******************************************************************************/ static void psci_suspend_to_standby_finisher(int cpu_idx, unsigned int end_pwrlvl) { unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0}; psci_power_state_t state_info; /* Get the parent nodes */ psci_get_parent_pwr_domain_nodes(cpu_idx, end_pwrlvl, parent_nodes); psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes); /* * Find out which retention states this CPU has exited from until the * 'end_pwrlvl'. The exit retention state could be deeper than the entry * state as a result of state coordination amongst other CPUs post wfi. */ psci_get_target_local_pwr_states(end_pwrlvl, &state_info); #if ENABLE_PSCI_STAT plat_psci_stat_accounting_stop(&state_info); psci_stats_update_pwr_up(end_pwrlvl, &state_info); #endif /* * Plat. management: Allow the platform to do operations * on waking up from retention. */ psci_plat_pm_ops->pwr_domain_suspend_finish(&state_info); /* * Set the requested and target state of this CPU and all the higher * power domain levels for this CPU to run. */ psci_set_pwr_domains_to_run(end_pwrlvl); psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes); } /******************************************************************************* * This function does generic and platform specific suspend to power down * operations. ******************************************************************************/ static void psci_suspend_to_pwrdown_start(unsigned int end_pwrlvl, const entry_point_info_t *ep, const psci_power_state_t *state_info) { unsigned int max_off_lvl = psci_find_max_off_lvl(state_info); PUBLISH_EVENT(psci_suspend_pwrdown_start); /* Save PSCI target power level for the suspend finisher handler */ psci_set_suspend_pwrlvl(end_pwrlvl); /* * Flush the target power level as it might be accessed on power up with * Data cache disabled. */ psci_flush_cpu_data(psci_svc_cpu_data.target_pwrlvl); /* * Call the cpu suspend handler registered by the Secure Payload * Dispatcher to let it do any book-keeping. If the handler encounters an * error, it's expected to assert within */ if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_suspend != NULL)) psci_spd_pm->svc_suspend(max_off_lvl); #if !HW_ASSISTED_COHERENCY /* * Plat. management: Allow the platform to perform any early * actions required to power down the CPU. This might be useful for * HW_ASSISTED_COHERENCY = 0 platforms that can safely perform these * actions with data caches enabled. */ if (psci_plat_pm_ops->pwr_domain_suspend_pwrdown_early != NULL) psci_plat_pm_ops->pwr_domain_suspend_pwrdown_early(state_info); #endif /* * Store the re-entry information for the non-secure world. */ cm_init_my_context(ep); #if ENABLE_RUNTIME_INSTRUMENTATION /* * Flush cache line so that even if CPU power down happens * the timestamp update is reflected in memory. */ PMF_CAPTURE_TIMESTAMP(rt_instr_svc, RT_INSTR_ENTER_CFLUSH, PMF_CACHE_MAINT); #endif /* * Arch. management. Initiate power down sequence. * TODO : Introduce a mechanism to query the cache level to flush * and the cpu-ops power down to perform from the platform. */ psci_do_pwrdown_sequence(max_off_lvl); #if ENABLE_RUNTIME_INSTRUMENTATION PMF_CAPTURE_TIMESTAMP(rt_instr_svc, RT_INSTR_EXIT_CFLUSH, PMF_NO_CACHE_MAINT); #endif } /******************************************************************************* * Top level handler which is called when a cpu wants to suspend its execution. * It is assumed that along with suspending the cpu power domain, power domains * at higher levels until the target power level will be suspended as well. It * coordinates with the platform to negotiate the target state for each of * the power domain level till the target power domain level. It then performs * generic, architectural, platform setup and state management required to * suspend that power domain level and power domain levels below it. * e.g. For a cpu that's to be suspended, it could mean programming the * power controller whereas for a cluster that's to be suspended, it will call * the platform specific code which will disable coherency at the interconnect * level if the cpu is the last in the cluster and also the program the power * controller. * * All the required parameter checks are performed at the beginning and after * the state transition has been done, no further error is expected and it is * not possible to undo any of the actions taken beyond that point. ******************************************************************************/ void psci_cpu_suspend_start(const entry_point_info_t *ep, unsigned int end_pwrlvl, psci_power_state_t *state_info, unsigned int is_power_down_state) { int skip_wfi = 0; int idx = (int) plat_my_core_pos(); unsigned int parent_nodes[PLAT_MAX_PWR_LVL] = {0}; /* * This function must only be called on platforms where the * CPU_SUSPEND platform hooks have been implemented. */ assert((psci_plat_pm_ops->pwr_domain_suspend != NULL) && (psci_plat_pm_ops->pwr_domain_suspend_finish != NULL)); /* Get the parent nodes */ psci_get_parent_pwr_domain_nodes(idx, end_pwrlvl, parent_nodes); /* * This function acquires the lock corresponding to each power * level so that by the time all locks are taken, the system topology * is snapshot and state management can be done safely. */ psci_acquire_pwr_domain_locks(end_pwrlvl, parent_nodes); /* * We check if there are any pending interrupts after the delay * introduced by lock contention to increase the chances of early * detection that a wake-up interrupt has fired. */ if (read_isr_el1() != 0U) { skip_wfi = 1; goto exit; } /* * This function is passed the requested state info and * it returns the negotiated state info for each power level upto * the end level specified. */ psci_do_state_coordination(end_pwrlvl, state_info); #if ENABLE_PSCI_STAT /* Update the last cpu for each level till end_pwrlvl */ psci_stats_update_pwr_down(end_pwrlvl, state_info); #endif if (is_power_down_state != 0U) psci_suspend_to_pwrdown_start(end_pwrlvl, ep, state_info); /* * Plat. management: Allow the platform to perform the * necessary actions to turn off this cpu e.g. set the * platform defined mailbox with the psci entrypoint, * program the power controller etc. */ psci_plat_pm_ops->pwr_domain_suspend(state_info); #if ENABLE_PSCI_STAT plat_psci_stat_accounting_start(state_info); #endif exit: /* * Release the locks corresponding to each power level in the * reverse order to which they were acquired. */ psci_release_pwr_domain_locks(end_pwrlvl, parent_nodes); if (skip_wfi == 1) return; if (is_power_down_state != 0U) { #if ENABLE_RUNTIME_INSTRUMENTATION /* * Update the timestamp with cache off. We assume this * timestamp can only be read from the current CPU and the * timestamp cache line will be flushed before return to * normal world on wakeup. */ PMF_CAPTURE_TIMESTAMP(rt_instr_svc, RT_INSTR_ENTER_HW_LOW_PWR, PMF_NO_CACHE_MAINT); #endif /* The function calls below must not return */ if (psci_plat_pm_ops->pwr_domain_pwr_down_wfi != NULL) psci_plat_pm_ops->pwr_domain_pwr_down_wfi(state_info); else psci_power_down_wfi(); } #if ENABLE_RUNTIME_INSTRUMENTATION PMF_CAPTURE_TIMESTAMP(rt_instr_svc, RT_INSTR_ENTER_HW_LOW_PWR, PMF_NO_CACHE_MAINT); #endif /* * We will reach here if only retention/standby states have been * requested at multiple power levels. This means that the cpu * context will be preserved. */ wfi(); #if ENABLE_RUNTIME_INSTRUMENTATION PMF_CAPTURE_TIMESTAMP(rt_instr_svc, RT_INSTR_EXIT_HW_LOW_PWR, PMF_NO_CACHE_MAINT); #endif /* * After we wake up from context retaining suspend, call the * context retaining suspend finisher. */ psci_suspend_to_standby_finisher(idx, end_pwrlvl); } /******************************************************************************* * The following functions finish an earlier suspend request. They * are called by the common finisher routine in psci_common.c. The `state_info` * is the psci_power_state from which this CPU has woken up from. ******************************************************************************/ void psci_cpu_suspend_finish(int cpu_idx, const psci_power_state_t *state_info) { unsigned int counter_freq; unsigned int max_off_lvl; /* Ensure we have been woken up from a suspended state */ assert((psci_get_aff_info_state() == AFF_STATE_ON) && (is_local_state_off( state_info->pwr_domain_state[PSCI_CPU_PWR_LVL]) != 0)); /* * Plat. management: Perform the platform specific actions * before we change the state of the cpu e.g. enabling the * gic or zeroing the mailbox register. If anything goes * wrong then assert as there is no way to recover from this * situation. */ psci_plat_pm_ops->pwr_domain_suspend_finish(state_info); #if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY) /* Arch. management: Enable the data cache, stack memory maintenance. */ psci_do_pwrup_cache_maintenance(); #endif /* Re-init the cntfrq_el0 register */ counter_freq = plat_get_syscnt_freq2(); write_cntfrq_el0(counter_freq); #if ENABLE_PAUTH /* Store APIAKey_EL1 key */ set_cpu_data(apiakey[0], read_apiakeylo_el1()); set_cpu_data(apiakey[1], read_apiakeyhi_el1()); #endif /* ENABLE_PAUTH */ /* * Call the cpu suspend finish handler registered by the Secure Payload * Dispatcher to let it do any bookeeping. If the handler encounters an * error, it's expected to assert within */ if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_suspend_finish != NULL)) { max_off_lvl = psci_find_max_off_lvl(state_info); assert(max_off_lvl != PSCI_INVALID_PWR_LVL); psci_spd_pm->svc_suspend_finish(max_off_lvl); } /* Invalidate the suspend level for the cpu */ psci_set_suspend_pwrlvl(PSCI_INVALID_PWR_LVL); PUBLISH_EVENT(psci_suspend_pwrdown_finish); /* * Generic management: Now we just need to retrieve the * information that we had stashed away during the suspend * call to set this cpu on its way. */ cm_prepare_el3_exit(NON_SECURE); } trusted-firmware-a-2.2/lib/psci/psci_system_off.c000066400000000000000000000040531355360272700221570ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "psci_private.h" void __dead2 psci_system_off(void) { psci_print_power_domain_map(); assert(psci_plat_pm_ops->system_off != NULL); /* Notify the Secure Payload Dispatcher */ if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_system_off != NULL)) { psci_spd_pm->svc_system_off(); } (void) console_flush(); /* Call the platform specific hook */ psci_plat_pm_ops->system_off(); /* This function does not return. We should never get here */ } void __dead2 psci_system_reset(void) { psci_print_power_domain_map(); assert(psci_plat_pm_ops->system_reset != NULL); /* Notify the Secure Payload Dispatcher */ if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_system_reset != NULL)) { psci_spd_pm->svc_system_reset(); } (void) console_flush(); /* Call the platform specific hook */ psci_plat_pm_ops->system_reset(); /* This function does not return. We should never get here */ } u_register_t psci_system_reset2(uint32_t reset_type, u_register_t cookie) { unsigned int is_vendor; psci_print_power_domain_map(); assert(psci_plat_pm_ops->system_reset2 != NULL); is_vendor = (reset_type >> PSCI_RESET2_TYPE_VENDOR_SHIFT) & 1U; if (is_vendor == 0U) { /* * Only WARM_RESET is allowed for architectural type resets. */ if (reset_type != PSCI_RESET2_SYSTEM_WARM_RESET) return (u_register_t) PSCI_E_INVALID_PARAMS; if ((psci_plat_pm_ops->write_mem_protect != NULL) && (psci_plat_pm_ops->write_mem_protect(0) < 0)) { return (u_register_t) PSCI_E_NOT_SUPPORTED; } } /* Notify the Secure Payload Dispatcher */ if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_system_reset != NULL)) { psci_spd_pm->svc_system_reset(); } (void) console_flush(); return (u_register_t) psci_plat_pm_ops->system_reset2((int) is_vendor, reset_type, cookie); } trusted-firmware-a-2.2/lib/romlib/000077500000000000000000000000001355360272700171435ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/romlib/Makefile000066400000000000000000000051541355360272700206100ustar00rootroot00000000000000# # Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # AS = $(CROSS_COMPILE)as AR = $(CROSS_COMPILE)ar LD = $(CROSS_COMPILE)ld OC = $(CROSS_COMPILE)objcopy CPP = $(CROSS_COMPILE)cpp ROMLIB_GEN = ./romlib_generator.py BUILD_DIR = ../../$(BUILD_PLAT)/romlib LIB_DIR = ../../$(BUILD_PLAT)/lib WRAPPER_DIR = ../../$(BUILD_PLAT)/libwrapper LIBS = -lmbedtls -lfdt -lc INC = $(INCLUDES:-I%=-I../../%) PPFLAGS = $(INC) $(DEFINES) -P -x assembler-with-cpp -D__LINKER__ -MD -MP -MT $(BUILD_DIR)/romlib.ld OBJS = $(BUILD_DIR)/jmptbl.o $(BUILD_DIR)/init.o MAPFILE = ../../$(BUILD_PLAT)/romlib/romlib.map ifneq ($(PLAT_DIR),) WRAPPER_SOURCES = $(shell $(ROMLIB_GEN) genwrappers -b $(WRAPPER_DIR) --list ../../$(PLAT_DIR)/jmptbl.i) WRAPPER_OBJS = $(WRAPPER_SOURCES:.s=.o) endif V ?= 0 ifeq ($(V),0) Q := @ else Q := endif LDFLAGS := --gc-sections -O1 ifeq ($(DEBUG),1) LDFLAGS += -Map=$(MAPFILE) endif ifeq (${ARM_ARCH_MINOR},0) ASFLAGS = -march=armv8-a else ASFLAGS = -march=armv8.${ARM_ARCH_MINOR}-a endif .PHONY: all clean distclean all: $(BUILD_DIR)/romlib.bin $(LIB_DIR)/libwrappers.a %.o: %.s @echo " AS $@" $(Q)$(AS) $(ASFLAGS) -o $@ $< $(BUILD_DIR)/%.o: %.s @echo " AS $@" $(Q)$(AS) $(ASFLAGS) -o $@ $< $(BUILD_DIR)/romlib.ld: romlib.ld.S @echo " PP $@" $(Q)$(CPP) $(PPFLAGS) -o $@ romlib.ld.S $(BUILD_DIR)/romlib.elf: $(OBJS) $(BUILD_DIR)/romlib.ld @echo " LD $@" $(Q)$(LD) -T $(BUILD_DIR)/romlib.ld -L$(LIB_DIR) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) $(BUILD_DIR)/romlib.bin: $(BUILD_DIR)/romlib.elf @echo " BIN $@" $(Q)$(OC) -O binary $(BUILD_DIR)/romlib.elf $@ $(WRAPPER_DIR)/jmpvar.s: $(BUILD_DIR)/romlib.elf @echo " VAR $@" $(Q)$(ROMLIB_GEN) genvar --output $@ $< $(LIB_DIR)/libwrappers.a: $(WRAPPER_DIR)/jmpvar.o $(WRAPPER_OBJS) @echo " AR $@" $(Q)$(AR) -rc $@ $(WRAPPER_DIR)/jmpvar.o $(WRAPPER_OBJS) $(BUILD_DIR)/jmptbl.i: ../../$(PLAT_DIR)/jmptbl.i @echo " PRE $@" $(Q)$(ROMLIB_GEN) pre --output $@ --deps $(BUILD_DIR)/jmptbl.d $< $(BUILD_DIR)/wrappers.stamp: $(BUILD_DIR)/jmptbl.i @echo " WRP $<" $(Q)$(ROMLIB_GEN) genwrappers --bti=$(ENABLE_BTI) -b $(WRAPPER_DIR) $< @touch $@ $(WRAPPER_SOURCES): $(BUILD_DIR)/wrappers.stamp $(WRAPPER_OBJS): $(WRAPPER_SOURCES) $(BUILD_DIR)/wrappers.stamp $(BUILD_DIR)/jmptbl.s: $(BUILD_DIR)/jmptbl.i @echo " TBL $@" $(Q)$(ROMLIB_GEN) gentbl --output $@ --bti=$(ENABLE_BTI) $< clean: @rm -f $(BUILD_DIR)/* -include $(BUILD_DIR)/romlib.d -include $(BUILD_DIR)/jmptbl.d trusted-firmware-a-2.2/lib/romlib/gen_combined_bl1_romlib.sh000077500000000000000000000021761355360272700242230ustar00rootroot00000000000000#!/bin/sh # Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause set -e output="bl1_romlib.bin" # Set trap for removing temporary file trap 'r=$?;rm -f $bin_path/$$.tmp;exit $r' EXIT HUP QUIT INT TERM # Read input parameters for i do case $i in -o) output=$2 shift 2 ;; --) shift break ;; -*) echo usage: gen_combined_bl1_romlib.sh [-o output] path_to_build_directory >&2 ;; esac done bin_path=$1 romlib_path=$1/romlib bl1_file="$1/bl1/bl1.elf" romlib_file="$1/romlib/romlib.elf" bl1_end="" romlib_begin="" # Get address of __BL1_ROM_END__ bl1_end=`nm -a "$bl1_file" | awk '$3 == "__BL1_ROM_END__" {print "0x"$1}'` # Get start address of romlib "text" section romlib_begin=`nm -a "$romlib_file" | awk '$3 == ".text" {print "0x"$1}'` # Character "U" will be read as "55" in hex when it is # concatenated with bl1.bin. Generate combined BL1 and ROMLIB # binary with filler bytes for juno (cat $bin_path/bl1.bin yes U | sed $(($romlib_begin - $bl1_end))q | tr -d '\n' cat $bin_path/romlib/romlib.bin) > $bin_path/$$.tmp && mv $bin_path/$$.tmp $bin_path/$output trusted-firmware-a-2.2/lib/romlib/init.s000066400000000000000000000012721355360272700202740ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ .globl rom_lib_init .extern __DATA_RAM_START__, __DATA_ROM_START__, __DATA_RAM_END__ .extern memset, memcpy rom_lib_init: cmp w0, #1 mov w0, #0 b.le 1f ret 1: stp x29, x30, [sp, #-16]! adrp x0, __DATA_RAM_START__ adrp x1, __DATA_ROM_START__ add x1, x1, :lo12:__DATA_ROM_START__ adrp x2, __DATA_RAM_END__ add x2, x2, :lo12:__DATA_RAM_END__ sub x2, x2, x0 bl memcpy adrp x0,__BSS_START__ add x0, x0, :lo12:__BSS_START__ mov x1, #0 adrp x2, __BSS_END__ add x2, x2, :lo12:__BSS_END__ sub x2, x2, x0 bl memset ldp x29, x30, [sp], #16 mov w0, #1 ret trusted-firmware-a-2.2/lib/romlib/jmptbl.i000066400000000000000000000024031355360272700206040ustar00rootroot00000000000000# # Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Format: # lib function [patch] # Add "patch" at the end of the line to patch a function. For example: # mbedtls mbedtls_memory_buffer_alloc_init patch # Holes can be introduced in the table by using a special keyword "reserved". # Example: # reserved reserved # The jump table will contain an invalid instruction instead of branch rom rom_lib_init fdt fdt_getprop_namelen fdt fdt_setprop_inplace fdt fdt_check_header fdt fdt_node_offset_by_compatible mbedtls mbedtls_asn1_get_alg mbedtls mbedtls_asn1_get_alg_null mbedtls mbedtls_asn1_get_bitstring_null mbedtls mbedtls_asn1_get_bool mbedtls mbedtls_asn1_get_int mbedtls mbedtls_asn1_get_tag mbedtls mbedtls_free mbedtls mbedtls_md mbedtls mbedtls_md_get_size mbedtls mbedtls_memory_buffer_alloc_init mbedtls mbedtls_oid_get_md_alg mbedtls mbedtls_oid_get_numeric_string mbedtls mbedtls_oid_get_pk_alg mbedtls mbedtls_oid_get_sig_alg mbedtls mbedtls_pk_free mbedtls mbedtls_pk_init mbedtls mbedtls_pk_parse_subpubkey mbedtls mbedtls_pk_verify_ext mbedtls mbedtls_platform_set_snprintf mbedtls mbedtls_x509_get_rsassa_pss_params mbedtls mbedtls_x509_get_sig_alg mbedtls mbedtls_md_info_from_type c exit c atexit trusted-firmware-a-2.2/lib/romlib/romlib.ld.S000066400000000000000000000014561355360272700211570ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include MEMORY { ROM (rx): ORIGIN = ROMLIB_RO_BASE, LENGTH = ROMLIB_RO_LIMIT - ROMLIB_RO_BASE RAM (rwx): ORIGIN = ROMLIB_RW_BASE, LENGTH = ROMLIB_RW_END - ROMLIB_RW_BASE } OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT) OUTPUT_ARCH(PLATFORM_LINKER_ARCH) ENTRY(jmptbl) SECTIONS { . = ROMLIB_RO_BASE; .text : { *jmptbl.o(.text) *(.text*) *(.rodata*) } >ROM __DATA_ROM_START__ = LOADADDR(.data); .data : { __DATA_RAM_START__ = .; *(.data*) __DATA_RAM_END__ = .; } >RAM AT>ROM __DATA_SIZE__ = SIZEOF(.data); .bss : { __BSS_START__ = .; *(.bss*) __BSS_END__ = .; } >RAM __BSS_SIZE__ = SIZEOF(.bss); } trusted-firmware-a-2.2/lib/romlib/romlib_generator.py000077500000000000000000000255071355360272700230630ustar00rootroot00000000000000#!/usr/bin/env python3 # Copyright (c) 2019, Arm Limited. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause """ This module contains a set of classes and a runner that can generate code for the romlib module based on the templates in the 'templates' directory. """ import argparse import os import re import subprocess import string import sys class IndexFileParser: """ Parses the contents of the index file into the items and dependencies variables. It also resolves included files in the index files recursively with circular inclusion detection. """ def __init__(self): self.items = [] self.dependencies = {} self.include_chain = [] def add_dependency(self, parent, dependency): """ Adds a dependency into the dependencies variable. """ if parent in self.dependencies: self.dependencies[parent].append(dependency) else: self.dependencies[parent] = [dependency] def get_dependencies(self, parent): """ Gets all the recursive dependencies of a parent file. """ parent = os.path.normpath(parent) if parent in self.dependencies: direct_deps = self.dependencies[parent] deps = direct_deps for direct_dep in direct_deps: deps += self.get_dependencies(direct_dep) return deps return [] def parse(self, file_name): """ Opens and parses index file. """ file_name = os.path.normpath(file_name) if file_name not in self.include_chain: self.include_chain.append(file_name) self.dependencies[file_name] = [] else: raise Exception("Circular dependency detected: " + file_name) with open(file_name, "r") as index_file: for line in index_file.readlines(): line_elements = line.split() if line.startswith("#") or not line_elements: # Comment or empty line continue if line_elements[0] == "reserved": # Reserved slot in the jump table self.items.append({"type": "reserved"}) elif line_elements[0] == "include" and len(line_elements) > 1: # Include other index file included_file = os.path.normpath(line_elements[1]) self.add_dependency(file_name, included_file) self.parse(included_file) elif len(line_elements) > 1: # Library function library_name = line_elements[0] function_name = line_elements[1] patch = bool(len(line_elements) > 2 and line_elements[2] == "patch") self.items.append({"type": "function", "library_name": library_name, "function_name": function_name, "patch": patch}) else: raise Exception("Invalid line: '" + line + "'") self.include_chain.pop() class RomlibApplication: """ Base class of romlib applications. """ TEMPLATE_DIR = os.path.dirname(os.path.realpath(__file__)) + "/templates/" def __init__(self, prog): self.args = argparse.ArgumentParser(prog=prog, description=self.__doc__) self.config = None def parse_arguments(self, argv): """ Parses the arguments that should come from the command line arguments. """ self.config = self.args.parse_args(argv) def build_template(self, name, mapping=None, remove_comment=False): """ Loads a template and builds it with the defined mapping. Template paths are always relative to this script. """ with open(self.TEMPLATE_DIR + name, "r") as template_file: if remove_comment: # Removing copyright comment to make the generated code more readable when the # template is inserted multiple times into the output. template_lines = template_file.readlines() end_of_comment_line = 0 for index, line in enumerate(template_lines): if line.find("*/") != -1: end_of_comment_line = index break template_data = "".join(template_lines[end_of_comment_line + 1:]) else: template_data = template_file.read() template = string.Template(template_data) return template.substitute(mapping) class IndexPreprocessor(RomlibApplication): """ Removes empty and comment lines from the index file and resolves includes. """ def __init__(self, prog): RomlibApplication.__init__(self, prog) self.args.add_argument("-o", "--output", help="Output file", metavar="output", default="jmpvar.s") self.args.add_argument("--deps", help="Dependency file") self.args.add_argument("file", help="Input file") def main(self): """ After parsing the input index file it generates a clean output with all includes resolved. Using --deps option it also outputs the dependencies in makefile format like gcc's with -M. """ index_file_parser = IndexFileParser() index_file_parser.parse(self.config.file) with open(self.config.output, "w") as output_file: for item in index_file_parser.items: if item["type"] == "function": patch = "\tpatch" if item["patch"] else "" output_file.write( item["library_name"] + "\t" + item["function_name"] + patch + "\n") else: output_file.write("reserved\n") if self.config.deps: with open(self.config.deps, "w") as deps_file: deps = [self.config.file] + index_file_parser.get_dependencies(self.config.file) deps_file.write(self.config.output + ": " + " \\\n".join(deps) + "\n") class TableGenerator(RomlibApplication): """ Generates the jump table by parsing the index file. """ def __init__(self, prog): RomlibApplication.__init__(self, prog) self.args.add_argument("-o", "--output", help="Output file", metavar="output", default="jmpvar.s") self.args.add_argument("--bti", help="Branch Target Identification", type=int) self.args.add_argument("file", help="Input file") def main(self): """ Inserts the jmptbl definition and the jump entries into the output file. Also can insert BTI related code before entries if --bti option set. It can output a dependency file of the included index files. This can be directly included in makefiles. """ index_file_parser = IndexFileParser() index_file_parser.parse(self.config.file) with open(self.config.output, "w") as output_file: output_file.write(self.build_template("jmptbl_header.S")) bti = "_bti" if self.config.bti == 1 else "" for item in index_file_parser.items: template_name = "jmptbl_entry_" + item["type"] + bti + ".S" output_file.write(self.build_template(template_name, item, True)) class WrapperGenerator(RomlibApplication): """ Generates a wrapper function for each entry in the index file except for the ones that contain the keyword patch. The generated wrapper file is called _.s. """ def __init__(self, prog): RomlibApplication.__init__(self, prog) self.args.add_argument("-b", help="Build directory", default=".", metavar="build") self.args.add_argument("--bti", help="Branch Target Identification", type=int) self.args.add_argument("--list", help="Only list assembly files", action="store_true") self.args.add_argument("file", help="Input file") def main(self): """ Iterates through the items in the parsed index file and builds the template for each entry. """ index_file_parser = IndexFileParser() index_file_parser.parse(self.config.file) bti = "_bti" if self.config.bti == 1 else "" function_offset = 0 files = [] for item_index in range(0, len(index_file_parser.items)): item = index_file_parser.items[item_index] if item["type"] == "reserved" or item["patch"]: continue asm = self.config.b + "/" + item["function_name"] + ".s" if self.config.list: # Only listing files files.append(asm) else: with open(asm, "w") as asm_file: # The jump instruction is 4 bytes but BTI requires and extra instruction so # this makes it 8 bytes per entry. function_offset = item_index * (8 if self.config.bti else 4) item["function_offset"] = function_offset asm_file.write(self.build_template("wrapper" + bti + ".S", item)) if self.config.list: print(" ".join(files)) class VariableGenerator(RomlibApplication): """ Generates the jump table global variable with the absolute address in ROM. """ def __init__(self, prog): RomlibApplication.__init__(self, prog) self.args.add_argument("-o", "--output", help="Output file", metavar="output", default="jmpvar.s") self.args.add_argument("file", help="Input file") def main(self): """ Runs nm -a command on the input file and inserts the address of the .text section into the template as the ROM address of the jmp_table. """ symbols = subprocess.check_output(["nm", "-a", self.config.file]) matching_symbol = re.search("([0-9A-Fa-f]+) . \\.text", str(symbols)) if not matching_symbol: raise Exception("No '.text' section was found in %s" % self.config.file) mapping = {"jmptbl_address": matching_symbol.group(1)} with open(self.config.output, "w") as output_file: output_file.write(self.build_template("jmptbl_glob_var.S", mapping)) if __name__ == "__main__": APPS = {"genvar": VariableGenerator, "pre": IndexPreprocessor, "gentbl": TableGenerator, "genwrappers": WrapperGenerator} if len(sys.argv) < 2 or sys.argv[1] not in APPS: print("usage: romlib_generator.py [%s] [args]" % "|".join(APPS.keys()), file=sys.stderr) sys.exit(1) APP = APPS[sys.argv[1]]("romlib_generator.py " + sys.argv[1]) APP.parse_arguments(sys.argv[2:]) try: APP.main() sys.exit(0) except FileNotFoundError as file_not_found_error: print(file_not_found_error, file=sys.stderr) except subprocess.CalledProcessError as called_process_error: print(called_process_error.output, file=sys.stderr) sys.exit(1) trusted-firmware-a-2.2/lib/romlib/templates/000077500000000000000000000000001355360272700211415ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/romlib/templates/jmptbl_entry_function.S000066400000000000000000000002001355360272700256730ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ b ${function_name} trusted-firmware-a-2.2/lib/romlib/templates/jmptbl_entry_function_bti.S000066400000000000000000000002071355360272700265400ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ bti j b ${function_name} trusted-firmware-a-2.2/lib/romlib/templates/jmptbl_entry_reserved.S000066400000000000000000000001611355360272700256730ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ b . trusted-firmware-a-2.2/lib/romlib/templates/jmptbl_entry_reserved_bti.S000066400000000000000000000001701355360272700265310ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ bti j b . trusted-firmware-a-2.2/lib/romlib/templates/jmptbl_glob_var.S000066400000000000000000000002561355360272700244330ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ .data .globl jmptbl .align 4 jmptbl: .quad 0x${jmptbl_address} trusted-firmware-a-2.2/lib/romlib/templates/jmptbl_header.S000066400000000000000000000002121355360272700240600ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ .text .globl jmptbl jmptbl: trusted-firmware-a-2.2/lib/romlib/templates/wrapper.S000066400000000000000000000003621355360272700227460ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ .globl ${function_name} ${function_name}: ldr x17, =jmptbl mov x16, #${function_offset} ldr x17, [x17] add x16, x16, x17 br x16 trusted-firmware-a-2.2/lib/romlib/templates/wrapper_bti.S000066400000000000000000000003721355360272700236050ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ .globl ${function_name} ${function_name}: bti jc ldr x17, =jmptbl mov x16, #${function_offset} ldr x17, [x17] add x16, x16, x17 br x16 trusted-firmware-a-2.2/lib/semihosting/000077500000000000000000000000001355360272700202105ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/semihosting/aarch32/000077500000000000000000000000001355360272700214335ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/semihosting/aarch32/semihosting_call.S000066400000000000000000000003661355360272700251100ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include .globl semihosting_call func semihosting_call svc #0x123456 bx lr endfunc semihosting_call trusted-firmware-a-2.2/lib/semihosting/aarch64/000077500000000000000000000000001355360272700214405ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/semihosting/aarch64/semihosting_call.S000066400000000000000000000003671355360272700251160ustar00rootroot00000000000000/* * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include .globl semihosting_call func semihosting_call hlt #0xf000 ret endfunc semihosting_call trusted-firmware-a-2.2/lib/semihosting/semihosting.c000066400000000000000000000111001355360272700226760ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #ifndef SEMIHOSTING_SUPPORTED #define SEMIHOSTING_SUPPORTED 1 #endif long semihosting_call(unsigned long operation, void *system_block_address); typedef struct { const char *file_name; unsigned long mode; size_t name_length; } smh_file_open_block_t; typedef struct { long handle; uintptr_t buffer; size_t length; } smh_file_read_write_block_t; typedef struct { long handle; ssize_t location; } smh_file_seek_block_t; typedef struct { char *command_line; size_t command_length; } smh_system_block_t; long semihosting_connection_supported(void) { return SEMIHOSTING_SUPPORTED; } long semihosting_file_open(const char *file_name, size_t mode) { smh_file_open_block_t open_block; open_block.file_name = file_name; open_block.mode = mode; open_block.name_length = strlen(file_name); return semihosting_call(SEMIHOSTING_SYS_OPEN, (void *) &open_block); } long semihosting_file_seek(long file_handle, ssize_t offset) { smh_file_seek_block_t seek_block; long result; seek_block.handle = file_handle; seek_block.location = offset; result = semihosting_call(SEMIHOSTING_SYS_SEEK, (void *) &seek_block); if (result) result = semihosting_call(SEMIHOSTING_SYS_ERRNO, 0); return result; } long semihosting_file_read(long file_handle, size_t *length, uintptr_t buffer) { smh_file_read_write_block_t read_block; long result = -EINVAL; if ((length == NULL) || (buffer == (uintptr_t)NULL)) return result; read_block.handle = file_handle; read_block.buffer = buffer; read_block.length = *length; result = semihosting_call(SEMIHOSTING_SYS_READ, (void *) &read_block); if (result == *length) { return -EINVAL; } else if (result < *length) { *length -= result; return 0; } else return result; } long semihosting_file_write(long file_handle, size_t *length, const uintptr_t buffer) { smh_file_read_write_block_t write_block; long result = -EINVAL; if ((length == NULL) || (buffer == (uintptr_t)NULL)) return -EINVAL; write_block.handle = file_handle; write_block.buffer = (uintptr_t)buffer; /* cast away const */ write_block.length = *length; result = semihosting_call(SEMIHOSTING_SYS_WRITE, (void *) &write_block); *length = result; return (result == 0) ? 0 : -EINVAL; } long semihosting_file_close(long file_handle) { return semihosting_call(SEMIHOSTING_SYS_CLOSE, (void *) &file_handle); } long semihosting_file_length(long file_handle) { return semihosting_call(SEMIHOSTING_SYS_FLEN, (void *) &file_handle); } char semihosting_read_char(void) { return semihosting_call(SEMIHOSTING_SYS_READC, NULL); } void semihosting_write_char(char character) { semihosting_call(SEMIHOSTING_SYS_WRITEC, (void *) &character); } void semihosting_write_string(char *string) { semihosting_call(SEMIHOSTING_SYS_WRITE0, (void *) string); } long semihosting_system(char *command_line) { smh_system_block_t system_block; system_block.command_line = command_line; system_block.command_length = strlen(command_line); return semihosting_call(SEMIHOSTING_SYS_SYSTEM, (void *) &system_block); } long semihosting_get_flen(const char *file_name) { long file_handle; long length; assert(semihosting_connection_supported()); file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB); if (file_handle == -1) return file_handle; /* Find the length of the file */ length = semihosting_file_length(file_handle); return semihosting_file_close(file_handle) ? -1 : length; } long semihosting_download_file(const char *file_name, size_t buf_size, uintptr_t buf) { long ret = -EINVAL; size_t length; long file_handle; /* Null pointer check */ if (!buf) return ret; assert(semihosting_connection_supported()); file_handle = semihosting_file_open(file_name, FOPEN_MODE_RB); if (file_handle == -1) return ret; /* Find the actual length of the file */ length = semihosting_file_length(file_handle); if (length == -1) goto semihosting_fail; /* Signal error if we do not have enough space for the file */ if (length > buf_size) goto semihosting_fail; /* * A successful read will return 0 in which case we pass back * the actual number of bytes read. Else we pass a negative * value indicating an error. */ ret = semihosting_file_read(file_handle, &length, buf); if (ret) goto semihosting_fail; else ret = length; semihosting_fail: semihosting_file_close(file_handle); return ret; } trusted-firmware-a-2.2/lib/sprt/000077500000000000000000000000001355360272700166475ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/sprt/sprt_host.c000066400000000000000000000024631355360272700210450ustar00rootroot00000000000000/* * Copyright (c) 2018, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "sprt_common.h" #include "sprt_queue.h" void sprt_initialize_queues(void *buffer_base, size_t buffer_size) { /* Initialize queue for blocking messages */ void *blocking_base = buffer_base; uint32_t blocking_num = 4U; size_t blocking_size = SPRT_QUEUE_HEADER_SIZE + SPRT_QUEUE_ENTRY_MSG_SIZE * blocking_num; sprt_queue_init(blocking_base, blocking_num, SPRT_QUEUE_ENTRY_MSG_SIZE); /* Initialize queue for non-blocking messages */ void *non_blocking_base = (void *)((uintptr_t)blocking_base + blocking_size); size_t non_blocking_size = buffer_size - blocking_size; uint32_t non_blocking_num = (non_blocking_size - SPRT_QUEUE_HEADER_SIZE) / SPRT_QUEUE_ENTRY_MSG_SIZE; sprt_queue_init(non_blocking_base, non_blocking_num, SPRT_QUEUE_ENTRY_MSG_SIZE); } int sprt_push_message(void *buffer_base, const struct sprt_queue_entry_message *message, int queue_num) { struct sprt_queue *q = buffer_base; while (queue_num-- > 0) { uintptr_t next_addr = (uintptr_t)q + sizeof(struct sprt_queue) + q->entry_num * q->entry_size; q = (struct sprt_queue *) next_addr; } return sprt_queue_push(q, message); } trusted-firmware-a-2.2/lib/sprt/sprt_host.mk000066400000000000000000000003501355360272700212230ustar00rootroot00000000000000# # Copyright (c) 2018, Arm Limited. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # SPRT_LIB_SOURCES := $(addprefix lib/sprt/, \ sprt_host.c \ sprt_queue.c) SPRT_LIB_INCLUDES := -Iinclude/lib/sprt/ trusted-firmware-a-2.2/lib/sprt/sprt_queue.c000066400000000000000000000044041355360272700212110ustar00rootroot00000000000000/* * Copyright (c) 2018, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "sprt_queue.h" void sprt_queue_init(void *queue_base, uint32_t entry_num, uint32_t entry_size) { assert(queue_base != NULL); assert(entry_size > 0U); assert(entry_num > 0U); struct sprt_queue *queue = (struct sprt_queue *)queue_base; queue->entry_num = entry_num; queue->entry_size = entry_size; queue->idx_write = 0U; queue->idx_read = 0U; memset(queue->data, 0, entry_num * entry_size); } int sprt_queue_is_empty(void *queue_base) { assert(queue_base != NULL); struct sprt_queue *queue = (struct sprt_queue *)queue_base; return (queue->idx_write == queue->idx_read); } int sprt_queue_is_full(void *queue_base) { assert(queue_base != NULL); struct sprt_queue *queue = (struct sprt_queue *)queue_base; uint32_t idx_next_write = (queue->idx_write + 1) % queue->entry_num; return (idx_next_write == queue->idx_read); } int sprt_queue_push(void *queue_base, const void *entry) { assert(entry != NULL); assert(queue_base != NULL); if (sprt_queue_is_full(queue_base) != 0) { return -ENOMEM; } struct sprt_queue *queue = (struct sprt_queue *)queue_base; uint8_t *dst_entry = &queue->data[queue->entry_size * queue->idx_write]; memcpy(dst_entry, entry, queue->entry_size); /* * Make sure that the message data is visible before increasing the * counter of available messages. */ __asm__ volatile("dmb st" ::: "memory"); queue->idx_write = (queue->idx_write + 1) % queue->entry_num; __asm__ volatile("dmb st" ::: "memory"); return 0; } int sprt_queue_pop(void *queue_base, void *entry) { assert(entry != NULL); assert(queue_base != NULL); if (sprt_queue_is_empty(queue_base) != 0) { return -ENOENT; } struct sprt_queue *queue = (struct sprt_queue *)queue_base; uint8_t *src_entry = &queue->data[queue->entry_size * queue->idx_read]; memcpy(entry, src_entry, queue->entry_size); /* * Make sure that the message data is visible before increasing the * counter of read messages. */ __asm__ volatile("dmb st" ::: "memory"); queue->idx_read = (queue->idx_read + 1) % queue->entry_num; __asm__ volatile("dmb st" ::: "memory"); return 0; } trusted-firmware-a-2.2/lib/sprt/sprt_queue.h000066400000000000000000000024321355360272700212150ustar00rootroot00000000000000/* * Copyright (c) 2018, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPRT_QUEUE_H #define SPRT_QUEUE_H #include /* Struct that defines a queue. Not to be used directly. */ struct __attribute__((__packed__)) sprt_queue { uint32_t entry_num; /* Number of entries */ uint32_t entry_size; /* Size of an entry */ uint32_t idx_write; /* Index of first empty entry */ uint32_t idx_read; /* Index of first entry to read */ uint8_t data[0]; /* Start of data */ }; #define SPRT_QUEUE_HEADER_SIZE (sizeof(struct sprt_queue)) /* * Initializes a memory region to be used as a queue of the given number of * entries with the specified size. */ void sprt_queue_init(void *queue_base, uint32_t entry_num, uint32_t entry_size); /* Returns 1 if the queue is empty, 0 otherwise */ int sprt_queue_is_empty(void *queue_base); /* Returns 1 if the queue is full, 0 otherwise */ int sprt_queue_is_full(void *queue_base); /* * Pushes a new entry intro the queue. Returns 0 on success, -ENOMEM if the * queue is full. */ int sprt_queue_push(void *queue_base, const void *entry); /* * Pops an entry from the queue. Returns 0 on success, -ENOENT if the queue is * empty. */ int sprt_queue_pop(void *queue_base, void *entry); #endif /* SPRT_QUEUE_H */ trusted-firmware-a-2.2/lib/stack_protector/000077500000000000000000000000001355360272700210655ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/stack_protector/aarch32/000077500000000000000000000000001355360272700223105ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/stack_protector/aarch32/asm_stack_protector.S000066400000000000000000000016651355360272700265120ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl update_stack_protector_canary /* ----------------------------------------------------------------------- * void update_stack_protector_canary(void) * * Change the value of the canary used for stack smashing attacks protection. * Note: This must be called when it is safe to call C code, but this cannot be * called by C code. Doing this will make the check fail when the calling * function returns. * ----------------------------------------------------------------------- */ func update_stack_protector_canary /* Use r4 as it is callee-saved */ mov r4, lr bl plat_get_stack_protector_canary /* Update the canary with the returned value */ ldr r1, =__stack_chk_guard str r0, [r1] bx r4 endfunc update_stack_protector_canary trusted-firmware-a-2.2/lib/stack_protector/aarch64/000077500000000000000000000000001355360272700223155ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/stack_protector/aarch64/asm_stack_protector.S000066400000000000000000000017241355360272700265130ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl update_stack_protector_canary /* ----------------------------------------------------------------------- * void update_stack_protector_canary(void) * * Change the value of the canary used for stack smashing attacks protection. * Note: This must be called when it is safe to call C code, but this cannot be * called by C code. Doing this will make the check fail when the calling * function returns. * ----------------------------------------------------------------------- */ func update_stack_protector_canary /* Use x19 as it is callee-saved */ mov x19, x30 bl plat_get_stack_protector_canary /* Update the canary with the returned value */ adrp x1, __stack_chk_guard str x0, [x1, #:lo12:__stack_chk_guard] ret x19 endfunc update_stack_protector_canary trusted-firmware-a-2.2/lib/stack_protector/stack_protector.c000066400000000000000000000013671355360272700244460ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /* * Canary value used by the compiler runtime checks to detect stack corruption. * * Force the canary to be in .data to allow predictable memory layout relatively * to the stacks. */ u_register_t __attribute__((section(".data.stack_protector_canary"))) __stack_chk_guard = (u_register_t) 3288484550995823360ULL; /* * Function called when the stack's canary check fails, which means the stack * was corrupted. It must not return. */ void __dead2 __stack_chk_fail(void) { #if DEBUG ERROR("Stack corruption detected\n"); #endif panic(); } trusted-firmware-a-2.2/lib/stack_protector/stack_protector.mk000066400000000000000000000012351355360272700246250ustar00rootroot00000000000000# # Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Boolean macro to be used in C code STACK_PROTECTOR_ENABLED := 0 ifeq (${ENABLE_STACK_PROTECTOR},0) ENABLE_STACK_PROTECTOR := none endif ifneq (${ENABLE_STACK_PROTECTOR},none) STACK_PROTECTOR_ENABLED := 1 BL_COMMON_SOURCES += lib/stack_protector/stack_protector.c \ lib/stack_protector/${ARCH}/asm_stack_protector.S ifeq (${ENABLE_STACK_PROTECTOR},default) TF_CFLAGS += -fstack-protector else TF_CFLAGS += -fstack-protector-${ENABLE_STACK_PROTECTOR} endif endif $(eval $(call add_define,STACK_PROTECTOR_ENABLED)) trusted-firmware-a-2.2/lib/utils/000077500000000000000000000000001355360272700170175ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/utils/mem_region.c000066400000000000000000000071031355360272700213050ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /* * All the regions defined in mem_region_t must have the following properties * * - Any contiguous regions must be merged into a single entry. * - The number of bytes of each region must be greater than zero. * - The calculation of the highest address within the region (base + nbytes-1) * doesn't produce an overflow. * * These conditions must be fulfilled by the caller and they aren't checked * at runtime. */ /* * zero_normalmem all the regions defined in tbl. * It assumes that MMU is enabled and the memory is Normal memory. * tbl must be a valid pointer to a memory mem_region_t array, * nregions is the size of the array. */ void clear_mem_regions(mem_region_t *tbl, size_t nregions) { size_t i; assert(tbl); assert(nregions > 0); for (i = 0; i < nregions; i++) { assert(tbl->nbytes > 0); assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1)); zero_normalmem((void *) (tbl->base), tbl->nbytes); tbl++; } } #if defined(PLAT_XLAT_TABLES_DYNAMIC) /* * zero_normalmem all the regions defined in regions. * It assumes that MMU is enabled and the memory is Normal memory. * regions must be a valid pointer to a memory mem_region_t array, * nregions is the size of the array. va is the virtual address * where we want to map the physical pages that are going to * be cleared, and chunk is the amount of memory mapped and * cleared in every iteration. */ void clear_map_dyn_mem_regions(struct mem_region *regions, size_t nregions, uintptr_t va, size_t chunk) { uintptr_t begin; int r; size_t size; const unsigned int attr = MT_MEMORY | MT_RW | MT_NS; assert(regions != NULL); assert(nregions > 0 && chunk > 0); for ( ; nregions--; regions++) { begin = regions->base; size = regions->nbytes; if ((begin & (chunk-1)) != 0 || (size & (chunk-1)) != 0) { INFO("PSCI: Not correctly aligned region\n"); panic(); } while (size > 0) { r = mmap_add_dynamic_region(begin, va, chunk, attr); if (r != 0) { INFO("PSCI: mmap_add_dynamic_region failed with %d\n", r); panic(); } zero_normalmem((void *) va, chunk); r = mmap_remove_dynamic_region(va, chunk); if (r != 0) { INFO("PSCI: mmap_remove_dynamic_region failed with %d\n", r); panic(); } begin += chunk; size -= chunk; } } } #endif /* * This function checks that a region (addr + nbytes-1) of memory is totally * covered by one of the regions defined in tbl. * tbl must be a valid pointer to a memory mem_region_t array, nregions * is the size of the array and the region described by addr and nbytes must * not generate an overflow. * Returns: * -1 means that the region is not covered by any of the regions * described in tbl. * 0 the region (addr + nbytes-1) is covered by one of the regions described * in tbl */ int mem_region_in_array_chk(mem_region_t *tbl, size_t nregions, uintptr_t addr, size_t nbytes) { uintptr_t region_start, region_end, start, end; size_t i; assert(tbl); assert(nbytes > 0); assert(!check_uptr_overflow(addr, nbytes-1)); region_start = addr; region_end = addr + (nbytes - 1); for (i = 0; i < nregions; i++) { assert(tbl->nbytes > 0); assert(!check_uptr_overflow(tbl->base, tbl->nbytes-1)); start = tbl->base; end = start + (tbl->nbytes - 1); if (region_start >= start && region_end <= end) return 0; tbl++; } return -1; } trusted-firmware-a-2.2/lib/xlat_tables/000077500000000000000000000000001355360272700201615ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/xlat_tables/aarch32/000077500000000000000000000000001355360272700214045ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/xlat_tables/aarch32/nonlpae_tables.c000066400000000000000000000364021355360272700245430ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, Linaro Limited. All rights reserved. * Copyright (c) 2014-2019, Arm Limited. All rights reserved. * Copyright (c) 2014, STMicroelectronics International N.V. * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "../xlat_tables_private.h" #ifdef ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING #error "ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING flag is set. \ This module is to be used when LPAE is not supported" #endif CASSERT(PLAT_VIRT_ADDR_SPACE_SIZE == (1ULL << 32), invalid_vaddr_space_size); CASSERT(PLAT_PHY_ADDR_SPACE_SIZE == (1ULL << 32), invalid_paddr_space_size); #define MMU32B_UNSET_DESC ~0ul #define MMU32B_INVALID_DESC 0ul #define MT_UNKNOWN ~0U /* * MMU related values */ /* Sharable */ #define MMU32B_TTB_S (1 << 1) /* Not Outer Sharable */ #define MMU32B_TTB_NOS (1 << 5) /* Normal memory, Inner Non-cacheable */ #define MMU32B_TTB_IRGN_NC 0 /* Normal memory, Inner Write-Back Write-Allocate Cacheable */ #define MMU32B_TTB_IRGN_WBWA (1 << 6) /* Normal memory, Inner Write-Through Cacheable */ #define MMU32B_TTB_IRGN_WT 1 /* Normal memory, Inner Write-Back no Write-Allocate Cacheable */ #define MMU32B_TTB_IRGN_WB (1 | (1 << 6)) /* Normal memory, Outer Write-Back Write-Allocate Cacheable */ #define MMU32B_TTB_RNG_WBWA (1 << 3) #define MMU32B_DEFAULT_ATTRS \ (MMU32B_TTB_S | MMU32B_TTB_NOS | \ MMU32B_TTB_IRGN_WBWA | MMU32B_TTB_RNG_WBWA) /* armv7 memory mapping attributes: section mapping */ #define SECTION_SECURE (0 << 19) #define SECTION_NOTSECURE (1 << 19) #define SECTION_SHARED (1 << 16) #define SECTION_NOTGLOBAL (1 << 17) #define SECTION_ACCESS_FLAG (1 << 10) #define SECTION_UNPRIV (1 << 11) #define SECTION_RO (1 << 15) #define SECTION_TEX(tex) ((((tex) >> 2) << 12) | \ ((((tex) >> 1) & 0x1) << 3) | \ (((tex) & 0x1) << 2)) #define SECTION_DEVICE SECTION_TEX(MMU32B_ATTR_DEVICE_INDEX) #define SECTION_NORMAL SECTION_TEX(MMU32B_ATTR_DEVICE_INDEX) #define SECTION_NORMAL_CACHED \ SECTION_TEX(MMU32B_ATTR_IWBWA_OWBWA_INDEX) #define SECTION_XN (1 << 4) #define SECTION_PXN (1 << 0) #define SECTION_SECTION (2 << 0) #define SECTION_PT_NOTSECURE (1 << 3) #define SECTION_PT_PT (1 << 0) #define SMALL_PAGE_SMALL_PAGE (1 << 1) #define SMALL_PAGE_SHARED (1 << 10) #define SMALL_PAGE_NOTGLOBAL (1 << 11) #define SMALL_PAGE_TEX(tex) ((((tex) >> 2) << 6) | \ ((((tex) >> 1) & 0x1) << 3) | \ (((tex) & 0x1) << 2)) #define SMALL_PAGE_DEVICE \ SMALL_PAGE_TEX(MMU32B_ATTR_DEVICE_INDEX) #define SMALL_PAGE_NORMAL \ SMALL_PAGE_TEX(MMU32B_ATTR_DEVICE_INDEX) #define SMALL_PAGE_NORMAL_CACHED \ SMALL_PAGE_TEX(MMU32B_ATTR_IWBWA_OWBWA_INDEX) #define SMALL_PAGE_ACCESS_FLAG (1 << 4) #define SMALL_PAGE_UNPRIV (1 << 5) #define SMALL_PAGE_RO (1 << 9) #define SMALL_PAGE_XN (1 << 0) /* The TEX, C and B bits concatenated */ #define MMU32B_ATTR_DEVICE_INDEX 0x0 #define MMU32B_ATTR_IWBWA_OWBWA_INDEX 0x1 #define MMU32B_PRRR_IDX(idx, tr, nos) (((tr) << (2 * (idx))) | \ ((uint32_t)(nos) << ((idx) + 24))) #define MMU32B_NMRR_IDX(idx, ir, or) (((ir) << (2 * (idx))) | \ ((uint32_t)(or) << (2 * (idx) + 16))) #define MMU32B_PRRR_DS0 (1 << 16) #define MMU32B_PRRR_DS1 (1 << 17) #define MMU32B_PRRR_NS0 (1 << 18) #define MMU32B_PRRR_NS1 (1 << 19) #define DACR_DOMAIN(num, perm) ((perm) << ((num) * 2)) #define DACR_DOMAIN_PERM_NO_ACCESS 0x0 #define DACR_DOMAIN_PERM_CLIENT 0x1 #define DACR_DOMAIN_PERM_MANAGER 0x3 #define NUM_1MB_IN_4GB (1U << 12) #define NUM_4K_IN_1MB (1U << 8) #define ONE_MB_SHIFT 20 /* mmu 32b integration */ #define MMU32B_L1_TABLE_SIZE (NUM_1MB_IN_4GB * 4) #define MMU32B_L2_TABLE_SIZE (NUM_4K_IN_1MB * 4) #define MMU32B_L1_TABLE_ALIGN (1 << 14) #define MMU32B_L2_TABLE_ALIGN (1 << 10) static unsigned int next_xlat; static unsigned long long xlat_max_pa; static uintptr_t xlat_max_va; static uint32_t mmu_l1_base[NUM_1MB_IN_4GB] __aligned(MMU32B_L1_TABLE_ALIGN) __attribute__((section("xlat_table"))); static uint32_t mmu_l2_base[MAX_XLAT_TABLES][NUM_4K_IN_1MB] __aligned(MMU32B_L2_TABLE_ALIGN) __attribute__((section("xlat_table"))); /* * Array of all memory regions stored in order of ascending base address. * The list is terminated by the first entry with size == 0. */ static mmap_region_t mmap[MAX_MMAP_REGIONS + 1]; void print_mmap(void) { #if LOG_LEVEL >= LOG_LEVEL_VERBOSE mmap_region_t *mm = mmap; printf("init xlat - l1:%p l2:%p (%d)\n", (void *)mmu_l1_base, (void *)mmu_l2_base, MAX_XLAT_TABLES); printf("mmap:\n"); while (mm->size) { printf(" VA:%p PA:0x%llx size:0x%zx attr:0x%x\n", (void *)mm->base_va, mm->base_pa, mm->size, mm->attr); ++mm; }; printf("\n"); #endif } void mmap_add(const mmap_region_t *mm) { const mmap_region_t *mm_cursor = mm; while ((mm_cursor->size != 0U) || (mm_cursor->attr != 0U)) { mmap_add_region(mm_cursor->base_pa, mm_cursor->base_va, mm_cursor->size, mm_cursor->attr); mm_cursor++; } } void mmap_add_region(unsigned long long base_pa, uintptr_t base_va, size_t size, unsigned int attr) { mmap_region_t *mm = mmap; const mmap_region_t *mm_last = mm + ARRAY_SIZE(mmap) - 1U; unsigned long long end_pa = base_pa + size - 1U; uintptr_t end_va = base_va + size - 1U; assert(IS_PAGE_ALIGNED(base_pa)); assert(IS_PAGE_ALIGNED(base_va)); assert(IS_PAGE_ALIGNED(size)); if (size == 0U) return; assert(base_pa < end_pa); /* Check for overflows */ assert(base_va < end_va); assert((base_va + (uintptr_t)size - (uintptr_t)1) <= (PLAT_VIRT_ADDR_SPACE_SIZE - 1U)); assert((base_pa + (unsigned long long)size - 1ULL) <= (PLAT_PHY_ADDR_SPACE_SIZE - 1U)); #if ENABLE_ASSERTIONS /* Check for PAs and VAs overlaps with all other regions */ for (mm = mmap; mm->size; ++mm) { uintptr_t mm_end_va = mm->base_va + mm->size - 1U; /* * Check if one of the regions is completely inside the other * one. */ bool fully_overlapped_va = ((base_va >= mm->base_va) && (end_va <= mm_end_va)) || ((mm->base_va >= base_va) && (mm_end_va <= end_va)); /* * Full VA overlaps are only allowed if both regions are * identity mapped (zero offset) or have the same VA to PA * offset. Also, make sure that it's not the exact same area. */ if (fully_overlapped_va) { assert((mm->base_va - mm->base_pa) == (base_va - base_pa)); assert((base_va != mm->base_va) || (size != mm->size)); } else { /* * If the regions do not have fully overlapping VAs, * then they must have fully separated VAs and PAs. * Partial overlaps are not allowed */ unsigned long long mm_end_pa = mm->base_pa + mm->size - 1; bool separated_pa = (end_pa < mm->base_pa) || (base_pa > mm_end_pa); bool separated_va = (end_va < mm->base_va) || (base_va > mm_end_va); assert(separated_va && separated_pa); } } mm = mmap; /* Restore pointer to the start of the array */ #endif /* ENABLE_ASSERTIONS */ /* Find correct place in mmap to insert new region */ while ((mm->base_va < base_va) && (mm->size != 0U)) ++mm; /* * If a section is contained inside another one with the same base * address, it must be placed after the one it is contained in: * * 1st |-----------------------| * 2nd |------------| * 3rd |------| * * This is required for mmap_region_attr() to get the attributes of the * small region correctly. */ while ((mm->base_va == base_va) && (mm->size > size)) ++mm; /* Make room for new region by moving other regions up by one place */ (void)memmove(mm + 1, mm, (uintptr_t)mm_last - (uintptr_t)mm); /* Check we haven't lost the empty sentinal from the end of the array */ assert(mm_last->size == 0U); mm->base_pa = base_pa; mm->base_va = base_va; mm->size = size; mm->attr = attr; if (end_pa > xlat_max_pa) xlat_max_pa = end_pa; if (end_va > xlat_max_va) xlat_max_va = end_va; } /* map all memory as shared/global/domain0/no-usr access */ static unsigned long mmap_desc(unsigned attr, unsigned long addr_pa, unsigned int level) { unsigned long desc; switch (level) { case 1: assert(!(addr_pa & (MMU32B_L1_TABLE_ALIGN - 1))); desc = SECTION_SECTION | SECTION_SHARED; desc |= attr & MT_NS ? SECTION_NOTSECURE : 0; desc |= SECTION_ACCESS_FLAG; desc |= attr & MT_RW ? 0 : SECTION_RO; desc |= attr & MT_MEMORY ? SECTION_NORMAL_CACHED : SECTION_DEVICE; if ((attr & MT_RW) || !(attr & MT_MEMORY)) desc |= SECTION_XN; break; case 2: assert(!(addr_pa & (MMU32B_L2_TABLE_ALIGN - 1))); desc = SMALL_PAGE_SMALL_PAGE | SMALL_PAGE_SHARED; desc |= SMALL_PAGE_ACCESS_FLAG; desc |= attr & MT_RW ? 0 : SMALL_PAGE_RO; desc |= attr & MT_MEMORY ? SMALL_PAGE_NORMAL_CACHED : SMALL_PAGE_DEVICE; if ((attr & MT_RW) || !(attr & MT_MEMORY)) desc |= SMALL_PAGE_XN; break; default: panic(); } #if LOG_LEVEL >= LOG_LEVEL_VERBOSE /* dump only the non-lpae level 2 tables */ if (level == 2) { printf(attr & MT_MEMORY ? "MEM" : "dev"); printf(attr & MT_RW ? "-rw" : "-RO"); printf(attr & MT_NS ? "-NS" : "-S"); } #endif return desc | addr_pa; } static unsigned int mmap_region_attr(const mmap_region_t *mm, uintptr_t base_va, size_t size, unsigned int *attr) { /* Don't assume that the area is contained in the first region */ unsigned int ret = MT_UNKNOWN; /* * Get attributes from last (innermost) region that contains the * requested area. Don't stop as soon as one region doesn't contain it * because there may be other internal regions that contain this area: * * |-----------------------------1-----------------------------| * |----2----| |-------3-------| |----5----| * |--4--| * * |---| <- Area we want the attributes of. * * In this example, the area is contained in regions 1, 3 and 4 but not * in region 2. The loop shouldn't stop at region 2 as inner regions * have priority over outer regions, it should stop at region 5. */ for ( ; ; ++mm) { if (mm->size == 0U) return ret; /* Reached end of list */ if (mm->base_va > (base_va + size - 1U)) return ret; /* Next region is after area so end */ if ((mm->base_va + mm->size - 1U) < base_va) continue; /* Next region has already been overtaken */ if ((ret == 0U) && (mm->attr == *attr)) continue; /* Region doesn't override attribs so skip */ if ((mm->base_va > base_va) || ((mm->base_va + mm->size - 1U) < (base_va + size - 1U))) return MT_UNKNOWN; /* Region doesn't fully cover area */ *attr = mm->attr; ret = 0U; } return ret; } static mmap_region_t *init_xlation_table_inner(mmap_region_t *mm, unsigned long base_va, unsigned long *table, unsigned int level) { unsigned int level_size_shift = (level == 1) ? ONE_MB_SHIFT : FOUR_KB_SHIFT; unsigned int level_size = 1 << level_size_shift; unsigned long level_index_mask = (level == 1) ? (NUM_1MB_IN_4GB - 1) << ONE_MB_SHIFT : (NUM_4K_IN_1MB - 1) << FOUR_KB_SHIFT; assert(level == 1 || level == 2); VERBOSE("init xlat table at %p (level%1d)\n", (void *)table, level); do { unsigned long desc = MMU32B_UNSET_DESC; if (mm->base_va + mm->size <= base_va) { /* Area now after the region so skip it */ ++mm; continue; } #if LOG_LEVEL >= LOG_LEVEL_VERBOSE /* dump only non-lpae level 2 tables content */ if (level == 2) printf(" 0x%lx %x " + 6 - 2 * level, base_va, level_size); #endif if (mm->base_va >= base_va + level_size) { /* Next region is after area so nothing to map yet */ desc = MMU32B_INVALID_DESC; } else if (mm->base_va <= base_va && mm->base_va + mm->size >= base_va + level_size) { /* Next region covers all of area */ unsigned int attr = mm->attr; unsigned int r = mmap_region_attr(mm, base_va, level_size, &attr); if (r == 0U) { desc = mmap_desc(attr, base_va - mm->base_va + mm->base_pa, level); } } if (desc == MMU32B_UNSET_DESC) { unsigned long xlat_table; /* * Area not covered by a region so need finer table * Reuse next level table if any (assert attrib matching). * Otherwise allocate a xlat table. */ if (*table) { assert((*table & 3) == SECTION_PT_PT); assert(!(*table & SECTION_PT_NOTSECURE) == !(mm->attr & MT_NS)); xlat_table = (*table) & ~(MMU32B_L1_TABLE_ALIGN - 1); desc = *table; } else { xlat_table = (unsigned long)mmu_l2_base + next_xlat * MMU32B_L2_TABLE_SIZE; next_xlat++; assert(next_xlat <= MAX_XLAT_TABLES); memset((char *)xlat_table, 0, MMU32B_L2_TABLE_SIZE); desc = xlat_table | SECTION_PT_PT; desc |= mm->attr & MT_NS ? SECTION_PT_NOTSECURE : 0; } /* Recurse to fill in new table */ mm = init_xlation_table_inner(mm, base_va, (unsigned long *)xlat_table, level + 1); } #if LOG_LEVEL >= LOG_LEVEL_VERBOSE /* dump only non-lpae level 2 tables content */ if (level == 2) printf("\n"); #endif *table++ = desc; base_va += level_size; } while (mm->size && (base_va & level_index_mask)); return mm; } void init_xlat_tables(void) { print_mmap(); assert(!((unsigned int)mmu_l1_base & (MMU32B_L1_TABLE_ALIGN - 1))); assert(!((unsigned int)mmu_l2_base & (MMU32B_L2_TABLE_ALIGN - 1))); memset(mmu_l1_base, 0, MMU32B_L1_TABLE_SIZE); init_xlation_table_inner(mmap, 0, (unsigned long *)mmu_l1_base, 1); VERBOSE("init xlat - max_va=%p, max_pa=%llx\n", (void *)xlat_max_va, xlat_max_pa); assert(xlat_max_va <= PLAT_VIRT_ADDR_SPACE_SIZE - 1); assert(xlat_max_pa <= PLAT_VIRT_ADDR_SPACE_SIZE - 1); } /******************************************************************************* * Function for enabling the MMU in Secure PL1, assuming that the * page-tables have already been created. ******************************************************************************/ void enable_mmu_svc_mon(unsigned int flags) { unsigned int prrr; unsigned int nmrr; unsigned int sctlr; assert(IS_IN_SECURE()); assert((read_sctlr() & SCTLR_M_BIT) == 0); /* Enable Access flag (simplified access permissions) and TEX remap */ write_sctlr(read_sctlr() | SCTLR_AFE_BIT | SCTLR_TRE_BIT); prrr = MMU32B_PRRR_IDX(MMU32B_ATTR_DEVICE_INDEX, 1, 0) \ | MMU32B_PRRR_IDX(MMU32B_ATTR_IWBWA_OWBWA_INDEX, 2, 1); nmrr = MMU32B_NMRR_IDX(MMU32B_ATTR_DEVICE_INDEX, 0, 0) \ | MMU32B_NMRR_IDX(MMU32B_ATTR_IWBWA_OWBWA_INDEX, 1, 1); prrr |= MMU32B_PRRR_NS1 | MMU32B_PRRR_DS1; write_prrr(prrr); write_nmrr(nmrr); /* Program Domain access control register: domain 0 only */ write_dacr(DACR_DOMAIN(0, DACR_DOMAIN_PERM_CLIENT)); /* Invalidate TLBs at the current exception level */ tlbiall(); /* set MMU base xlat table entry (use only TTBR0) */ write_ttbr0((uint32_t)mmu_l1_base | MMU32B_DEFAULT_ATTRS); write_ttbr1(0); /* * Ensure all translation table writes have drained * into memory, the TLB invalidation is complete, * and translation register writes are committed * before enabling the MMU */ dsb(); isb(); sctlr = read_sctlr(); sctlr |= SCTLR_M_BIT; #if ARMV7_SUPPORTS_VIRTUALIZATION sctlr |= SCTLR_WXN_BIT; #endif if (flags & DISABLE_DCACHE) sctlr &= ~SCTLR_C_BIT; else sctlr |= SCTLR_C_BIT; write_sctlr(sctlr); /* Ensure the MMU enable takes effect immediately */ isb(); } trusted-firmware-a-2.2/lib/xlat_tables/aarch32/xlat_tables.c000066400000000000000000000070121355360272700240520ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "../xlat_tables_private.h" #if (ARM_ARCH_MAJOR == 7) && !defined(ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING) #error ARMv7 target does not support LPAE MMU descriptors #endif #define XLAT_TABLE_LEVEL_BASE \ GET_XLAT_TABLE_LEVEL_BASE(PLAT_VIRT_ADDR_SPACE_SIZE) #define NUM_BASE_LEVEL_ENTRIES \ GET_NUM_BASE_LEVEL_ENTRIES(PLAT_VIRT_ADDR_SPACE_SIZE) static uint64_t base_xlation_table[NUM_BASE_LEVEL_ENTRIES] __aligned(NUM_BASE_LEVEL_ENTRIES * sizeof(uint64_t)); #if ENABLE_ASSERTIONS static unsigned long long get_max_supported_pa(void) { /* Physical address space size for long descriptor format. */ return (1ULL << 40) - 1ULL; } #endif /* ENABLE_ASSERTIONS */ unsigned int xlat_arch_current_el(void) { /* * If EL3 is in AArch32 mode, all secure PL1 modes (Monitor, System, * SVC, Abort, UND, IRQ and FIQ modes) execute at EL3. */ return 3U; } uint64_t xlat_arch_get_xn_desc(unsigned int el __unused) { return UPPER_ATTRS(XN); } void init_xlat_tables(void) { unsigned long long max_pa; uintptr_t max_va; assert(PLAT_VIRT_ADDR_SPACE_SIZE >= MIN_VIRT_ADDR_SPACE_SIZE); assert(PLAT_VIRT_ADDR_SPACE_SIZE <= MAX_VIRT_ADDR_SPACE_SIZE); assert(IS_POWER_OF_TWO(PLAT_VIRT_ADDR_SPACE_SIZE)); print_mmap(); init_xlation_table(0U, base_xlation_table, XLAT_TABLE_LEVEL_BASE, &max_va, &max_pa); assert(max_va <= (PLAT_VIRT_ADDR_SPACE_SIZE - 1U)); assert(max_pa <= (PLAT_PHY_ADDR_SPACE_SIZE - 1U)); assert((PLAT_PHY_ADDR_SPACE_SIZE - 1U) <= get_max_supported_pa()); } void enable_mmu_svc_mon(unsigned int flags) { unsigned int mair0, ttbcr, sctlr; uint64_t ttbr0; assert(IS_IN_SECURE()); assert((read_sctlr() & SCTLR_M_BIT) == 0U); /* Set attributes in the right indices of the MAIR */ mair0 = MAIR0_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX); mair0 |= MAIR0_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, ATTR_IWBWA_OWBWA_NTR_INDEX); mair0 |= MAIR0_ATTR_SET(ATTR_NON_CACHEABLE, ATTR_NON_CACHEABLE_INDEX); write_mair0(mair0); /* Invalidate TLBs at the current exception level */ tlbiall(); /* * Set TTBCR bits as well. Set TTBR0 table properties. Disable TTBR1. */ int t0sz = 32 - __builtin_ctzll(PLAT_VIRT_ADDR_SPACE_SIZE); if ((flags & XLAT_TABLE_NC) != 0U) { /* Inner & outer non-cacheable non-shareable. */ ttbcr = TTBCR_EAE_BIT | TTBCR_SH0_NON_SHAREABLE | TTBCR_RGN0_OUTER_NC | TTBCR_RGN0_INNER_NC | (uint32_t) t0sz; } else { /* Inner & outer WBWA & shareable. */ ttbcr = TTBCR_EAE_BIT | TTBCR_SH0_INNER_SHAREABLE | TTBCR_RGN0_OUTER_WBA | TTBCR_RGN0_INNER_WBA | (uint32_t) t0sz; } ttbcr |= TTBCR_EPD1_BIT; write_ttbcr(ttbcr); /* Set TTBR0 bits as well */ ttbr0 = (uintptr_t) base_xlation_table; write64_ttbr0(ttbr0); write64_ttbr1(0U); /* * Ensure all translation table writes have drained * into memory, the TLB invalidation is complete, * and translation register writes are committed * before enabling the MMU */ dsbish(); isb(); sctlr = read_sctlr(); sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT; if ((flags & DISABLE_DCACHE) != 0U) sctlr &= ~SCTLR_C_BIT; else sctlr |= SCTLR_C_BIT; write_sctlr(sctlr); /* Ensure the MMU enable takes effect immediately */ isb(); } void enable_mmu_direct_svc_mon(unsigned int flags) { enable_mmu_svc_mon(flags); } trusted-firmware-a-2.2/lib/xlat_tables/aarch64/000077500000000000000000000000001355360272700214115ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/xlat_tables/aarch64/xlat_tables.c000066400000000000000000000144641355360272700240700ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "../xlat_tables_private.h" #define XLAT_TABLE_LEVEL_BASE \ GET_XLAT_TABLE_LEVEL_BASE(PLAT_VIRT_ADDR_SPACE_SIZE) #define NUM_BASE_LEVEL_ENTRIES \ GET_NUM_BASE_LEVEL_ENTRIES(PLAT_VIRT_ADDR_SPACE_SIZE) static uint64_t base_xlation_table[NUM_BASE_LEVEL_ENTRIES] __aligned(NUM_BASE_LEVEL_ENTRIES * sizeof(uint64_t)); static unsigned long long tcr_ps_bits; static unsigned long long calc_physical_addr_size_bits( unsigned long long max_addr) { /* Physical address can't exceed 48 bits */ assert((max_addr & ADDR_MASK_48_TO_63) == 0U); /* 48 bits address */ if ((max_addr & ADDR_MASK_44_TO_47) != 0U) return TCR_PS_BITS_256TB; /* 44 bits address */ if ((max_addr & ADDR_MASK_42_TO_43) != 0U) return TCR_PS_BITS_16TB; /* 42 bits address */ if ((max_addr & ADDR_MASK_40_TO_41) != 0U) return TCR_PS_BITS_4TB; /* 40 bits address */ if ((max_addr & ADDR_MASK_36_TO_39) != 0U) return TCR_PS_BITS_1TB; /* 36 bits address */ if ((max_addr & ADDR_MASK_32_TO_35) != 0U) return TCR_PS_BITS_64GB; return TCR_PS_BITS_4GB; } #if ENABLE_ASSERTIONS /* * Physical Address ranges supported in the AArch64 Memory Model. Value 0b110 is * supported in ARMv8.2 onwards. */ static const unsigned int pa_range_bits_arr[] = { PARANGE_0000, PARANGE_0001, PARANGE_0010, PARANGE_0011, PARANGE_0100, PARANGE_0101, PARANGE_0110 }; static unsigned long long get_max_supported_pa(void) { u_register_t pa_range = read_id_aa64mmfr0_el1() & ID_AA64MMFR0_EL1_PARANGE_MASK; /* All other values are reserved */ assert(pa_range < ARRAY_SIZE(pa_range_bits_arr)); return (1ULL << pa_range_bits_arr[pa_range]) - 1ULL; } /* * Return minimum virtual address space size supported by the architecture */ static uintptr_t xlat_get_min_virt_addr_space_size(void) { uintptr_t ret; if (is_armv8_4_ttst_present()) ret = MIN_VIRT_ADDR_SPACE_SIZE_TTST; else ret = MIN_VIRT_ADDR_SPACE_SIZE; return ret; } #endif /* ENABLE_ASSERTIONS */ unsigned int xlat_arch_current_el(void) { unsigned int el = (unsigned int)GET_EL(read_CurrentEl()); assert(el > 0U); return el; } uint64_t xlat_arch_get_xn_desc(unsigned int el) { if (el == 3U) { return UPPER_ATTRS(XN); } else { assert(el == 1U); return UPPER_ATTRS(PXN); } } void init_xlat_tables(void) { unsigned long long max_pa; uintptr_t max_va; assert(PLAT_VIRT_ADDR_SPACE_SIZE >= (xlat_get_min_virt_addr_space_size() - 1U)); assert(PLAT_VIRT_ADDR_SPACE_SIZE <= MAX_VIRT_ADDR_SPACE_SIZE); assert(IS_POWER_OF_TWO(PLAT_VIRT_ADDR_SPACE_SIZE)); print_mmap(); init_xlation_table(0U, base_xlation_table, XLAT_TABLE_LEVEL_BASE, &max_va, &max_pa); assert(max_va <= (PLAT_VIRT_ADDR_SPACE_SIZE - 1U)); assert(max_pa <= (PLAT_PHY_ADDR_SPACE_SIZE - 1U)); assert((PLAT_PHY_ADDR_SPACE_SIZE - 1U) <= get_max_supported_pa()); tcr_ps_bits = calc_physical_addr_size_bits(max_pa); } /******************************************************************************* * Macro generating the code for the function enabling the MMU in the given * exception level, assuming that the pagetables have already been created. * * _el: Exception level at which the function will run * _tcr_extra: Extra bits to set in the TCR register. This mask will * be OR'ed with the default TCR value. * _tlbi_fct: Function to invalidate the TLBs at the current * exception level ******************************************************************************/ #define DEFINE_ENABLE_MMU_EL(_el, _tcr_extra, _tlbi_fct) \ void enable_mmu_el##_el(unsigned int flags) \ { \ uint64_t mair, tcr, ttbr; \ uint32_t sctlr; \ \ assert(IS_IN_EL(_el)); \ assert((read_sctlr_el##_el() & SCTLR_M_BIT) == 0U); \ \ /* Set attributes in the right indices of the MAIR */ \ mair = MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX); \ mair |= MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, \ ATTR_IWBWA_OWBWA_NTR_INDEX); \ mair |= MAIR_ATTR_SET(ATTR_NON_CACHEABLE, \ ATTR_NON_CACHEABLE_INDEX); \ write_mair_el##_el(mair); \ \ /* Invalidate TLBs at the current exception level */ \ _tlbi_fct(); \ \ /* Set TCR bits as well. */ \ /* Set T0SZ to (64 - width of virtual address space) */ \ int t0sz = 64 - __builtin_ctzll(PLAT_VIRT_ADDR_SPACE_SIZE);\ \ if ((flags & XLAT_TABLE_NC) != 0U) { \ /* Inner & outer non-cacheable non-shareable. */\ tcr = TCR_SH_NON_SHAREABLE | \ TCR_RGN_OUTER_NC | TCR_RGN_INNER_NC | \ ((uint64_t)t0sz << TCR_T0SZ_SHIFT); \ } else { \ /* Inner & outer WBWA & shareable. */ \ tcr = TCR_SH_INNER_SHAREABLE | \ TCR_RGN_OUTER_WBA | TCR_RGN_INNER_WBA | \ ((uint64_t)t0sz << TCR_T0SZ_SHIFT); \ } \ tcr |= _tcr_extra; \ write_tcr_el##_el(tcr); \ \ /* Set TTBR bits as well */ \ ttbr = (uint64_t) base_xlation_table; \ write_ttbr0_el##_el(ttbr); \ \ /* Ensure all translation table writes have drained */ \ /* into memory, the TLB invalidation is complete, */ \ /* and translation register writes are committed */ \ /* before enabling the MMU */ \ dsbish(); \ isb(); \ \ sctlr = read_sctlr_el##_el(); \ sctlr |= SCTLR_WXN_BIT | SCTLR_M_BIT; \ \ if ((flags & DISABLE_DCACHE) != 0U) \ sctlr &= ~SCTLR_C_BIT; \ else \ sctlr |= SCTLR_C_BIT; \ \ write_sctlr_el##_el(sctlr); \ \ /* Ensure the MMU enable takes effect immediately */ \ isb(); \ } \ \ void enable_mmu_direct_el##_el(unsigned int flags) \ { \ enable_mmu_el##_el(flags); \ } /* Define EL1 and EL3 variants of the function enabling the MMU */ DEFINE_ENABLE_MMU_EL(1, /* * TCR_EL1.EPD1: Disable translation table walk for addresses * that are translated using TTBR1_EL1. */ TCR_EPD1_BIT | (tcr_ps_bits << TCR_EL1_IPS_SHIFT), tlbivmalle1) DEFINE_ENABLE_MMU_EL(3, TCR_EL3_RES1 | (tcr_ps_bits << TCR_EL3_PS_SHIFT), tlbialle3) trusted-firmware-a-2.2/lib/xlat_tables/xlat_tables_common.c000066400000000000000000000275671355360272700242200ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include "xlat_tables_private.h" #if LOG_LEVEL >= LOG_LEVEL_VERBOSE #define LVL0_SPACER "" #define LVL1_SPACER " " #define LVL2_SPACER " " #define LVL3_SPACER " " #define get_level_spacer(level) \ (((level) == U(0)) ? LVL0_SPACER : \ (((level) == U(1)) ? LVL1_SPACER : \ (((level) == U(2)) ? LVL2_SPACER : LVL3_SPACER))) #define debug_print(...) printf(__VA_ARGS__) #else #define debug_print(...) ((void)0) #endif #define UNSET_DESC ~0ULL #define MT_UNKNOWN ~0U static uint64_t xlat_tables[MAX_XLAT_TABLES][XLAT_TABLE_ENTRIES] __aligned(XLAT_TABLE_SIZE) __section("xlat_table"); static unsigned int next_xlat; static unsigned long long xlat_max_pa; static uintptr_t xlat_max_va; static uint64_t execute_never_mask; static uint64_t ap1_mask; /* * Array of all memory regions stored in order of ascending base address. * The list is terminated by the first entry with size == 0. */ static mmap_region_t mmap[MAX_MMAP_REGIONS + 1]; void print_mmap(void) { #if LOG_LEVEL >= LOG_LEVEL_VERBOSE debug_print("mmap:\n"); mmap_region_t *mm = mmap; while (mm->size != 0U) { debug_print(" VA:%p PA:0x%llx size:0x%zx attr:0x%x\n", (void *)mm->base_va, mm->base_pa, mm->size, mm->attr); ++mm; }; debug_print("\n"); #endif } void mmap_add_region(unsigned long long base_pa, uintptr_t base_va, size_t size, unsigned int attr) { mmap_region_t *mm = mmap; const mmap_region_t *mm_last = mm + ARRAY_SIZE(mmap) - 1U; unsigned long long end_pa = base_pa + size - 1U; uintptr_t end_va = base_va + size - 1U; assert(IS_PAGE_ALIGNED(base_pa)); assert(IS_PAGE_ALIGNED(base_va)); assert(IS_PAGE_ALIGNED(size)); if (size == 0U) return; assert(base_pa < end_pa); /* Check for overflows */ assert(base_va < end_va); assert((base_va + (uintptr_t)size - (uintptr_t)1) <= (PLAT_VIRT_ADDR_SPACE_SIZE - 1U)); assert((base_pa + (unsigned long long)size - 1ULL) <= (PLAT_PHY_ADDR_SPACE_SIZE - 1U)); #if ENABLE_ASSERTIONS /* Check for PAs and VAs overlaps with all other regions */ for (mm = mmap; mm->size; ++mm) { uintptr_t mm_end_va = mm->base_va + mm->size - 1U; /* * Check if one of the regions is completely inside the other * one. */ bool fully_overlapped_va = ((base_va >= mm->base_va) && (end_va <= mm_end_va)) || ((mm->base_va >= base_va) && (mm_end_va <= end_va)); /* * Full VA overlaps are only allowed if both regions are * identity mapped (zero offset) or have the same VA to PA * offset. Also, make sure that it's not the exact same area. */ if (fully_overlapped_va) { assert((mm->base_va - mm->base_pa) == (base_va - base_pa)); assert((base_va != mm->base_va) || (size != mm->size)); } else { /* * If the regions do not have fully overlapping VAs, * then they must have fully separated VAs and PAs. * Partial overlaps are not allowed */ unsigned long long mm_end_pa = mm->base_pa + mm->size - 1; bool separated_pa = (end_pa < mm->base_pa) || (base_pa > mm_end_pa); bool separated_va = (end_va < mm->base_va) || (base_va > mm_end_va); assert(separated_va && separated_pa); } } mm = mmap; /* Restore pointer to the start of the array */ #endif /* ENABLE_ASSERTIONS */ /* Find correct place in mmap to insert new region */ while ((mm->base_va < base_va) && (mm->size != 0U)) ++mm; /* * If a section is contained inside another one with the same base * address, it must be placed after the one it is contained in: * * 1st |-----------------------| * 2nd |------------| * 3rd |------| * * This is required for mmap_region_attr() to get the attributes of the * small region correctly. */ while ((mm->base_va == base_va) && (mm->size > size)) ++mm; /* Make room for new region by moving other regions up by one place */ (void)memmove(mm + 1, mm, (uintptr_t)mm_last - (uintptr_t)mm); /* Check we haven't lost the empty sentinal from the end of the array */ assert(mm_last->size == 0U); mm->base_pa = base_pa; mm->base_va = base_va; mm->size = size; mm->attr = attr; if (end_pa > xlat_max_pa) xlat_max_pa = end_pa; if (end_va > xlat_max_va) xlat_max_va = end_va; } void mmap_add(const mmap_region_t *mm) { const mmap_region_t *mm_cursor = mm; while ((mm_cursor->size != 0U) || (mm_cursor->attr != 0U)) { mmap_add_region(mm_cursor->base_pa, mm_cursor->base_va, mm_cursor->size, mm_cursor->attr); mm_cursor++; } } static uint64_t mmap_desc(unsigned int attr, unsigned long long addr_pa, unsigned int level) { uint64_t desc; int mem_type; /* Make sure that the granularity is fine enough to map this address. */ assert((addr_pa & XLAT_BLOCK_MASK(level)) == 0U); desc = addr_pa; /* * There are different translation table descriptors for level 3 and the * rest. */ desc |= (level == XLAT_TABLE_LEVEL_MAX) ? PAGE_DESC : BLOCK_DESC; desc |= ((attr & MT_NS) != 0U) ? LOWER_ATTRS(NS) : 0U; desc |= ((attr & MT_RW) != 0U) ? LOWER_ATTRS(AP_RW) : LOWER_ATTRS(AP_RO); /* * Always set the access flag, as this library assumes access flag * faults aren't managed. */ desc |= LOWER_ATTRS(ACCESS_FLAG); desc |= ap1_mask; /* * Deduce shareability domain and executability of the memory region * from the memory type. * * Data accesses to device memory and non-cacheable normal memory are * coherent for all observers in the system, and correspondingly are * always treated as being Outer Shareable. Therefore, for these 2 types * of memory, it is not strictly needed to set the shareability field * in the translation tables. */ mem_type = MT_TYPE(attr); if (mem_type == MT_DEVICE) { desc |= LOWER_ATTRS(ATTR_DEVICE_INDEX | OSH); /* * Always map device memory as execute-never. * This is to avoid the possibility of a speculative instruction * fetch, which could be an issue if this memory region * corresponds to a read-sensitive peripheral. */ desc |= execute_never_mask; } else { /* Normal memory */ /* * Always map read-write normal memory as execute-never. * This library assumes that it is used by software that does * not self-modify its code, therefore R/W memory is reserved * for data storage, which must not be executable. * * Note that setting the XN bit here is for consistency only. * The function that enables the MMU sets the SCTLR_ELx.WXN bit, * which makes any writable memory region to be treated as * execute-never, regardless of the value of the XN bit in the * translation table. * * For read-only memory, rely on the MT_EXECUTE/MT_EXECUTE_NEVER * attribute to figure out the value of the XN bit. */ if (((attr & MT_RW) != 0U) || ((attr & MT_EXECUTE_NEVER) != 0U)) { desc |= execute_never_mask; } if (mem_type == MT_MEMORY) { desc |= LOWER_ATTRS(ATTR_IWBWA_OWBWA_NTR_INDEX | ISH); } else { assert(mem_type == MT_NON_CACHEABLE); desc |= LOWER_ATTRS(ATTR_NON_CACHEABLE_INDEX | OSH); } } debug_print((mem_type == MT_MEMORY) ? "MEM" : ((mem_type == MT_NON_CACHEABLE) ? "NC" : "DEV")); debug_print(((attr & MT_RW) != 0U) ? "-RW" : "-RO"); debug_print(((attr & MT_NS) != 0U) ? "-NS" : "-S"); debug_print(((attr & MT_EXECUTE_NEVER) != 0U) ? "-XN" : "-EXEC"); return desc; } /* * Look for the innermost region that contains the area at `base_va` with size * `size`. Populate *attr with the attributes of this region. * * On success, this function returns 0. * If there are partial overlaps (meaning that a smaller size is needed) or if * the region can't be found in the given area, it returns MT_UNKNOWN. In this * case the value pointed by attr should be ignored by the caller. */ static unsigned int mmap_region_attr(const mmap_region_t *mm, uintptr_t base_va, size_t size, unsigned int *attr) { /* Don't assume that the area is contained in the first region */ unsigned int ret = MT_UNKNOWN; /* * Get attributes from last (innermost) region that contains the * requested area. Don't stop as soon as one region doesn't contain it * because there may be other internal regions that contain this area: * * |-----------------------------1-----------------------------| * |----2----| |-------3-------| |----5----| * |--4--| * * |---| <- Area we want the attributes of. * * In this example, the area is contained in regions 1, 3 and 4 but not * in region 2. The loop shouldn't stop at region 2 as inner regions * have priority over outer regions, it should stop at region 5. */ for ( ; ; ++mm) { if (mm->size == 0U) return ret; /* Reached end of list */ if (mm->base_va > (base_va + size - 1U)) return ret; /* Next region is after area so end */ if ((mm->base_va + mm->size - 1U) < base_va) continue; /* Next region has already been overtaken */ if ((ret == 0U) && (mm->attr == *attr)) continue; /* Region doesn't override attribs so skip */ if ((mm->base_va > base_va) || ((mm->base_va + mm->size - 1U) < (base_va + size - 1U))) return MT_UNKNOWN; /* Region doesn't fully cover area */ *attr = mm->attr; ret = 0U; } return ret; } static mmap_region_t *init_xlation_table_inner(mmap_region_t *mm, uintptr_t base_va, uint64_t *table, unsigned int level) { assert((level >= XLAT_TABLE_LEVEL_MIN) && (level <= XLAT_TABLE_LEVEL_MAX)); unsigned int level_size_shift = L0_XLAT_ADDRESS_SHIFT - level * XLAT_TABLE_ENTRIES_SHIFT; u_register_t level_size = (u_register_t)1 << level_size_shift; u_register_t level_index_mask = ((u_register_t)XLAT_TABLE_ENTRIES_MASK) << level_size_shift; debug_print("New xlat table:\n"); do { uint64_t desc = UNSET_DESC; if (mm->size == 0U) { /* Done mapping regions; finish zeroing the table */ desc = INVALID_DESC; } else if ((mm->base_va + mm->size - 1U) < base_va) { /* This area is after the region so get next region */ ++mm; continue; } debug_print("%s VA:%p size:0x%llx ", get_level_spacer(level), (void *)base_va, (unsigned long long)level_size); if (mm->base_va > (base_va + level_size - 1U)) { /* Next region is after this area. Nothing to map yet */ desc = INVALID_DESC; /* Make sure that the current level allows block descriptors */ } else if (level >= XLAT_BLOCK_LEVEL_MIN) { /* * Try to get attributes of this area. It will fail if * there are partially overlapping regions. On success, * it will return the innermost region's attributes. */ unsigned int attr; unsigned int r = mmap_region_attr(mm, base_va, level_size, &attr); if (r == 0U) { desc = mmap_desc(attr, base_va - mm->base_va + mm->base_pa, level); } } if (desc == UNSET_DESC) { /* Area not covered by a region so need finer table */ uint64_t *new_table = xlat_tables[next_xlat]; next_xlat++; assert(next_xlat <= MAX_XLAT_TABLES); desc = TABLE_DESC | (uintptr_t)new_table; /* Recurse to fill in new table */ mm = init_xlation_table_inner(mm, base_va, new_table, level + 1U); } debug_print("\n"); *table++ = desc; base_va += level_size; } while ((base_va & level_index_mask) && ((base_va - 1U) < (PLAT_VIRT_ADDR_SPACE_SIZE - 1U))); return mm; } void init_xlation_table(uintptr_t base_va, uint64_t *table, unsigned int level, uintptr_t *max_va, unsigned long long *max_pa) { unsigned int el = xlat_arch_current_el(); execute_never_mask = xlat_arch_get_xn_desc(el); if (el == 3U) { ap1_mask = LOWER_ATTRS(AP_ONE_VA_RANGE_RES1); } else { assert(el == 1U); ap1_mask = 0ULL; } init_xlation_table_inner(mmap, base_va, table, level); *max_va = xlat_max_va; *max_pa = xlat_max_pa; } trusted-firmware-a-2.2/lib/xlat_tables/xlat_tables_private.h000066400000000000000000000021571355360272700243730ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef XLAT_TABLES_PRIVATE_H #define XLAT_TABLES_PRIVATE_H #include #include #include #if HW_ASSISTED_COHERENCY #error xlat tables v2 must be used with HW_ASSISTED_COHERENCY #endif CASSERT(CHECK_PHY_ADDR_SPACE_SIZE(PLAT_PHY_ADDR_SPACE_SIZE), assert_valid_phy_addr_space_size); /* Alias to retain compatibility with the old #define name */ #define XLAT_BLOCK_LEVEL_MIN MIN_LVL_BLOCK_DESC void print_mmap(void); /* Returns the current Exception Level. The returned EL must be 1 or higher. */ unsigned int xlat_arch_current_el(void); /* * Returns the bit mask that has to be ORed to the rest of a translation table * descriptor so that execution of code is prohibited at the given Exception * Level. */ uint64_t xlat_arch_get_xn_desc(unsigned int el); void init_xlation_table(uintptr_t base_va, uint64_t *table, unsigned int level, uintptr_t *max_va, unsigned long long *max_pa); #endif /* XLAT_TABLES_PRIVATE_H */ trusted-firmware-a-2.2/lib/xlat_tables_v2/000077500000000000000000000000001355360272700205705ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/xlat_tables_v2/aarch32/000077500000000000000000000000001355360272700220135ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/xlat_tables_v2/aarch32/enable_mmu.S000066400000000000000000000050001355360272700242360ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .global enable_mmu_direct_svc_mon .global enable_mmu_direct_hyp /* void enable_mmu_direct_svc_mon(unsigned int flags) */ func enable_mmu_direct_svc_mon /* Assert that MMU is turned off */ #if ENABLE_ASSERTIONS ldcopr r1, SCTLR tst r1, #SCTLR_M_BIT ASM_ASSERT(eq) #endif /* Invalidate TLB entries */ TLB_INVALIDATE(r0, TLBIALL) mov r3, r0 ldr r0, =mmu_cfg_params /* MAIR0. Only the lower 32 bits are used. */ ldr r1, [r0, #(MMU_CFG_MAIR << 3)] stcopr r1, MAIR0 /* TTBCR. Only the lower 32 bits are used. */ ldr r2, [r0, #(MMU_CFG_TCR << 3)] stcopr r2, TTBCR /* TTBR0 */ ldr r1, [r0, #(MMU_CFG_TTBR0 << 3)] ldr r2, [r0, #((MMU_CFG_TTBR0 << 3) + 4)] stcopr16 r1, r2, TTBR0_64 /* TTBR1 is unused right now; set it to 0. */ mov r1, #0 mov r2, #0 stcopr16 r1, r2, TTBR1_64 /* * Ensure all translation table writes have drained into memory, the TLB * invalidation is complete, and translation register writes are * committed before enabling the MMU */ dsb ish isb /* Enable enable MMU by honoring flags */ ldcopr r1, SCTLR ldr r2, =(SCTLR_WXN_BIT | SCTLR_C_BIT | SCTLR_M_BIT) orr r1, r1, r2 /* Clear C bit if requested */ tst r3, #DISABLE_DCACHE bicne r1, r1, #SCTLR_C_BIT stcopr r1, SCTLR isb bx lr endfunc enable_mmu_direct_svc_mon /* void enable_mmu_direct_hyp(unsigned int flags) */ func enable_mmu_direct_hyp /* Assert that MMU is turned off */ #if ENABLE_ASSERTIONS ldcopr r1, HSCTLR tst r1, #HSCTLR_M_BIT ASM_ASSERT(eq) #endif /* Invalidate TLB entries */ TLB_INVALIDATE(r0, TLBIALL) mov r3, r0 ldr r0, =mmu_cfg_params /* HMAIR0 */ ldr r1, [r0, #(MMU_CFG_MAIR << 3)] stcopr r1, HMAIR0 /* HTCR */ ldr r2, [r0, #(MMU_CFG_TCR << 3)] stcopr r2, HTCR /* HTTBR */ ldr r1, [r0, #(MMU_CFG_TTBR0 << 3)] ldr r2, [r0, #((MMU_CFG_TTBR0 << 3) + 4)] stcopr16 r1, r2, HTTBR_64 /* * Ensure all translation table writes have drained into memory, the TLB * invalidation is complete, and translation register writes are * committed before enabling the MMU */ dsb ish isb /* Enable enable MMU by honoring flags */ ldcopr r1, HSCTLR ldr r2, =(HSCTLR_WXN_BIT | HSCTLR_C_BIT | HSCTLR_M_BIT) orr r1, r1, r2 /* Clear C bit if requested */ tst r3, #DISABLE_DCACHE bicne r1, r1, #HSCTLR_C_BIT stcopr r1, HSCTLR isb bx lr endfunc enable_mmu_direct_hyp trusted-firmware-a-2.2/lib/xlat_tables_v2/aarch32/xlat_tables_arch.c000066400000000000000000000147251355360272700254670ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "../xlat_tables_private.h" #if (ARM_ARCH_MAJOR == 7) && !defined(ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING) #error ARMv7 target does not support LPAE MMU descriptors #endif /* * Returns true if the provided granule size is supported, false otherwise. */ bool xlat_arch_is_granule_size_supported(size_t size) { /* * The library uses the long descriptor translation table format, which * supports 4 KiB pages only. */ return size == PAGE_SIZE_4KB; } size_t xlat_arch_get_max_supported_granule_size(void) { return PAGE_SIZE_4KB; } #if ENABLE_ASSERTIONS unsigned long long xlat_arch_get_max_supported_pa(void) { /* Physical address space size for long descriptor format. */ return (1ULL << 40) - 1ULL; } /* * Return minimum virtual address space size supported by the architecture */ uintptr_t xlat_get_min_virt_addr_space_size(void) { return MIN_VIRT_ADDR_SPACE_SIZE; } #endif /* ENABLE_ASSERTIONS*/ bool is_mmu_enabled_ctx(const xlat_ctx_t *ctx) { if (ctx->xlat_regime == EL1_EL0_REGIME) { assert(xlat_arch_current_el() == 1U); return (read_sctlr() & SCTLR_M_BIT) != 0U; } else { assert(ctx->xlat_regime == EL2_REGIME); assert(xlat_arch_current_el() == 2U); return (read_hsctlr() & HSCTLR_M_BIT) != 0U; } } bool is_dcache_enabled(void) { if (IS_IN_EL2()) { return (read_hsctlr() & HSCTLR_C_BIT) != 0U; } else { return (read_sctlr() & SCTLR_C_BIT) != 0U; } } uint64_t xlat_arch_regime_get_xn_desc(int xlat_regime) { if (xlat_regime == EL1_EL0_REGIME) { return UPPER_ATTRS(XN) | UPPER_ATTRS(PXN); } else { assert(xlat_regime == EL2_REGIME); return UPPER_ATTRS(XN); } } void xlat_arch_tlbi_va(uintptr_t va, int xlat_regime) { /* * Ensure the translation table write has drained into memory before * invalidating the TLB entry. */ dsbishst(); if (xlat_regime == EL1_EL0_REGIME) { tlbimvaais(TLBI_ADDR(va)); } else { assert(xlat_regime == EL2_REGIME); tlbimvahis(TLBI_ADDR(va)); } } void xlat_arch_tlbi_va_sync(void) { /* Invalidate all entries from branch predictors. */ bpiallis(); /* * A TLB maintenance instruction can complete at any time after * it is issued, but is only guaranteed to be complete after the * execution of DSB by the PE that executed the TLB maintenance * instruction. After the TLB invalidate instruction is * complete, no new memory accesses using the invalidated TLB * entries will be observed by any observer of the system * domain. See section D4.8.2 of the ARMv8 (issue k), paragraph * "Ordering and completion of TLB maintenance instructions". */ dsbish(); /* * The effects of a completed TLB maintenance instruction are * only guaranteed to be visible on the PE that executed the * instruction after the execution of an ISB instruction by the * PE that executed the TLB maintenance instruction. */ isb(); } unsigned int xlat_arch_current_el(void) { if (IS_IN_HYP()) { return 2U; } else { assert(IS_IN_SVC() || IS_IN_MON()); /* * If EL3 is in AArch32 mode, all secure PL1 modes (Monitor, * System, SVC, Abort, UND, IRQ and FIQ modes) execute at EL3. * * The PL1&0 translation regime in AArch32 behaves like the * EL1&0 regime in AArch64 except for the XN bits, but we set * and unset them at the same time, so there's no difference in * practice. */ return 1U; } } /******************************************************************************* * Function for enabling the MMU in PL1 or PL2, assuming that the page tables * have already been created. ******************************************************************************/ void setup_mmu_cfg(uint64_t *params, unsigned int flags, const uint64_t *base_table, unsigned long long max_pa, uintptr_t max_va, __unused int xlat_regime) { uint64_t mair, ttbr0; uint32_t ttbcr; /* Set attributes in the right indices of the MAIR */ mair = MAIR0_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX); mair |= MAIR0_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, ATTR_IWBWA_OWBWA_NTR_INDEX); mair |= MAIR0_ATTR_SET(ATTR_NON_CACHEABLE, ATTR_NON_CACHEABLE_INDEX); /* * Configure the control register for stage 1 of the PL1&0 or EL2 * translation regimes. */ /* Use the Long-descriptor translation table format. */ ttbcr = TTBCR_EAE_BIT; if (xlat_regime == EL1_EL0_REGIME) { assert(IS_IN_SVC() || IS_IN_MON()); /* * Disable translation table walk for addresses that are * translated using TTBR1. Therefore, only TTBR0 is used. */ ttbcr |= TTBCR_EPD1_BIT; } else { assert(xlat_regime == EL2_REGIME); assert(IS_IN_HYP()); /* * Set HTCR bits as well. Set HTTBR table properties * as Inner & outer WBWA & shareable. */ ttbcr |= HTCR_RES1 | HTCR_SH0_INNER_SHAREABLE | HTCR_RGN0_OUTER_WBA | HTCR_RGN0_INNER_WBA; } /* * Limit the input address ranges and memory region sizes translated * using TTBR0 to the given virtual address space size, if smaller than * 32 bits. */ if (max_va != UINT32_MAX) { uintptr_t virtual_addr_space_size = max_va + 1U; assert(virtual_addr_space_size >= xlat_get_min_virt_addr_space_size()); assert(virtual_addr_space_size <= MAX_VIRT_ADDR_SPACE_SIZE); assert(IS_POWER_OF_TWO(virtual_addr_space_size)); /* * __builtin_ctzll(0) is undefined but here we are guaranteed * that virtual_addr_space_size is in the range [1, UINT32_MAX]. */ int t0sz = 32 - __builtin_ctzll(virtual_addr_space_size); ttbcr |= (uint32_t) t0sz; } /* * Set the cacheability and shareability attributes for memory * associated with translation table walks using TTBR0. */ if ((flags & XLAT_TABLE_NC) != 0U) { /* Inner & outer non-cacheable non-shareable. */ ttbcr |= TTBCR_SH0_NON_SHAREABLE | TTBCR_RGN0_OUTER_NC | TTBCR_RGN0_INNER_NC; } else { /* Inner & outer WBWA & shareable. */ ttbcr |= TTBCR_SH0_INNER_SHAREABLE | TTBCR_RGN0_OUTER_WBA | TTBCR_RGN0_INNER_WBA; } /* Set TTBR0 bits as well */ ttbr0 = (uint64_t)(uintptr_t) base_table; if (is_armv8_2_ttcnp_present()) { /* Enable CnP bit so as to share page tables with all PEs. */ ttbr0 |= TTBR_CNP_BIT; } /* Now populate MMU configuration */ params[MMU_CFG_MAIR] = mair; params[MMU_CFG_TCR] = (uint64_t) ttbcr; params[MMU_CFG_TTBR0] = ttbr0; } trusted-firmware-a-2.2/lib/xlat_tables_v2/aarch64/000077500000000000000000000000001355360272700220205ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/xlat_tables_v2/aarch64/enable_mmu.S000066400000000000000000000040721355360272700242530ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .global enable_mmu_direct_el1 .global enable_mmu_direct_el2 .global enable_mmu_direct_el3 /* Macros to read and write to system register for a given EL. */ .macro _msr reg_name, el, gp_reg msr \reg_name\()_el\()\el, \gp_reg .endm .macro _mrs gp_reg, reg_name, el mrs \gp_reg, \reg_name\()_el\()\el .endm .macro tlbi_invalidate_all el .if \el == 1 TLB_INVALIDATE(vmalle1) .elseif \el == 2 TLB_INVALIDATE(alle2) .elseif \el == 3 TLB_INVALIDATE(alle3) .else .error "EL must be 1, 2 or 3" .endif .endm /* void enable_mmu_direct_el(unsigned int flags) */ .macro define_mmu_enable_func el func enable_mmu_direct_\()el\el #if ENABLE_ASSERTIONS _mrs x1, sctlr, \el tst x1, #SCTLR_M_BIT ASM_ASSERT(eq) #endif /* Invalidate all TLB entries */ tlbi_invalidate_all \el mov x7, x0 adrp x0, mmu_cfg_params add x0, x0, :lo12:mmu_cfg_params /* MAIR */ ldr x1, [x0, #(MMU_CFG_MAIR << 3)] _msr mair, \el, x1 /* TCR */ ldr x2, [x0, #(MMU_CFG_TCR << 3)] _msr tcr, \el, x2 /* TTBR */ ldr x3, [x0, #(MMU_CFG_TTBR0 << 3)] _msr ttbr0, \el, x3 /* * Ensure all translation table writes have drained into memory, the TLB * invalidation is complete, and translation register writes are * committed before enabling the MMU */ dsb ish isb /* Set and clear required fields of SCTLR */ _mrs x4, sctlr, \el mov_imm x5, SCTLR_WXN_BIT | SCTLR_C_BIT | SCTLR_M_BIT orr x4, x4, x5 /* Additionally, amend SCTLR fields based on flags */ bic x5, x4, #SCTLR_C_BIT tst x7, #DISABLE_DCACHE csel x4, x5, x4, ne _msr sctlr, \el, x4 isb ret endfunc enable_mmu_direct_\()el\el .endm /* * Define MMU-enabling functions for EL1, EL2 and EL3: * * enable_mmu_direct_el1 * enable_mmu_direct_el2 * enable_mmu_direct_el3 */ define_mmu_enable_func 1 define_mmu_enable_func 2 define_mmu_enable_func 3 trusted-firmware-a-2.2/lib/xlat_tables_v2/aarch64/xlat_tables_arch.c000066400000000000000000000201111355360272700254560ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "../xlat_tables_private.h" /* * Returns true if the provided granule size is supported, false otherwise. */ bool xlat_arch_is_granule_size_supported(size_t size) { u_register_t id_aa64mmfr0_el1 = read_id_aa64mmfr0_el1(); if (size == PAGE_SIZE_4KB) { return ((id_aa64mmfr0_el1 >> ID_AA64MMFR0_EL1_TGRAN4_SHIFT) & ID_AA64MMFR0_EL1_TGRAN4_MASK) == ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED; } else if (size == PAGE_SIZE_16KB) { return ((id_aa64mmfr0_el1 >> ID_AA64MMFR0_EL1_TGRAN16_SHIFT) & ID_AA64MMFR0_EL1_TGRAN16_MASK) == ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED; } else if (size == PAGE_SIZE_64KB) { return ((id_aa64mmfr0_el1 >> ID_AA64MMFR0_EL1_TGRAN64_SHIFT) & ID_AA64MMFR0_EL1_TGRAN64_MASK) == ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED; } else { return 0; } } size_t xlat_arch_get_max_supported_granule_size(void) { if (xlat_arch_is_granule_size_supported(PAGE_SIZE_64KB)) { return PAGE_SIZE_64KB; } else if (xlat_arch_is_granule_size_supported(PAGE_SIZE_16KB)) { return PAGE_SIZE_16KB; } else { assert(xlat_arch_is_granule_size_supported(PAGE_SIZE_4KB)); return PAGE_SIZE_4KB; } } unsigned long long tcr_physical_addr_size_bits(unsigned long long max_addr) { /* Physical address can't exceed 48 bits */ assert((max_addr & ADDR_MASK_48_TO_63) == 0U); /* 48 bits address */ if ((max_addr & ADDR_MASK_44_TO_47) != 0U) return TCR_PS_BITS_256TB; /* 44 bits address */ if ((max_addr & ADDR_MASK_42_TO_43) != 0U) return TCR_PS_BITS_16TB; /* 42 bits address */ if ((max_addr & ADDR_MASK_40_TO_41) != 0U) return TCR_PS_BITS_4TB; /* 40 bits address */ if ((max_addr & ADDR_MASK_36_TO_39) != 0U) return TCR_PS_BITS_1TB; /* 36 bits address */ if ((max_addr & ADDR_MASK_32_TO_35) != 0U) return TCR_PS_BITS_64GB; return TCR_PS_BITS_4GB; } #if ENABLE_ASSERTIONS /* * Physical Address ranges supported in the AArch64 Memory Model. Value 0b110 is * supported in ARMv8.2 onwards. */ static const unsigned int pa_range_bits_arr[] = { PARANGE_0000, PARANGE_0001, PARANGE_0010, PARANGE_0011, PARANGE_0100, PARANGE_0101, PARANGE_0110 }; unsigned long long xlat_arch_get_max_supported_pa(void) { u_register_t pa_range = read_id_aa64mmfr0_el1() & ID_AA64MMFR0_EL1_PARANGE_MASK; /* All other values are reserved */ assert(pa_range < ARRAY_SIZE(pa_range_bits_arr)); return (1ULL << pa_range_bits_arr[pa_range]) - 1ULL; } /* * Return minimum virtual address space size supported by the architecture */ uintptr_t xlat_get_min_virt_addr_space_size(void) { uintptr_t ret; if (is_armv8_4_ttst_present()) ret = MIN_VIRT_ADDR_SPACE_SIZE_TTST; else ret = MIN_VIRT_ADDR_SPACE_SIZE; return ret; } #endif /* ENABLE_ASSERTIONS*/ bool is_mmu_enabled_ctx(const xlat_ctx_t *ctx) { if (ctx->xlat_regime == EL1_EL0_REGIME) { assert(xlat_arch_current_el() >= 1U); return (read_sctlr_el1() & SCTLR_M_BIT) != 0U; } else if (ctx->xlat_regime == EL2_REGIME) { assert(xlat_arch_current_el() >= 2U); return (read_sctlr_el2() & SCTLR_M_BIT) != 0U; } else { assert(ctx->xlat_regime == EL3_REGIME); assert(xlat_arch_current_el() >= 3U); return (read_sctlr_el3() & SCTLR_M_BIT) != 0U; } } bool is_dcache_enabled(void) { unsigned int el = (unsigned int)GET_EL(read_CurrentEl()); if (el == 1U) { return (read_sctlr_el1() & SCTLR_C_BIT) != 0U; } else if (el == 2U) { return (read_sctlr_el2() & SCTLR_C_BIT) != 0U; } else { return (read_sctlr_el3() & SCTLR_C_BIT) != 0U; } } uint64_t xlat_arch_regime_get_xn_desc(int xlat_regime) { if (xlat_regime == EL1_EL0_REGIME) { return UPPER_ATTRS(UXN) | UPPER_ATTRS(PXN); } else { assert((xlat_regime == EL2_REGIME) || (xlat_regime == EL3_REGIME)); return UPPER_ATTRS(XN); } } void xlat_arch_tlbi_va(uintptr_t va, int xlat_regime) { /* * Ensure the translation table write has drained into memory before * invalidating the TLB entry. */ dsbishst(); /* * This function only supports invalidation of TLB entries for the EL3 * and EL1&0 translation regimes. * * Also, it is architecturally UNDEFINED to invalidate TLBs of a higher * exception level (see section D4.9.2 of the ARM ARM rev B.a). */ if (xlat_regime == EL1_EL0_REGIME) { assert(xlat_arch_current_el() >= 1U); tlbivaae1is(TLBI_ADDR(va)); } else if (xlat_regime == EL2_REGIME) { assert(xlat_arch_current_el() >= 2U); tlbivae2is(TLBI_ADDR(va)); } else { assert(xlat_regime == EL3_REGIME); assert(xlat_arch_current_el() >= 3U); tlbivae3is(TLBI_ADDR(va)); } } void xlat_arch_tlbi_va_sync(void) { /* * A TLB maintenance instruction can complete at any time after * it is issued, but is only guaranteed to be complete after the * execution of DSB by the PE that executed the TLB maintenance * instruction. After the TLB invalidate instruction is * complete, no new memory accesses using the invalidated TLB * entries will be observed by any observer of the system * domain. See section D4.8.2 of the ARMv8 (issue k), paragraph * "Ordering and completion of TLB maintenance instructions". */ dsbish(); /* * The effects of a completed TLB maintenance instruction are * only guaranteed to be visible on the PE that executed the * instruction after the execution of an ISB instruction by the * PE that executed the TLB maintenance instruction. */ isb(); } unsigned int xlat_arch_current_el(void) { unsigned int el = (unsigned int)GET_EL(read_CurrentEl()); assert(el > 0U); return el; } void setup_mmu_cfg(uint64_t *params, unsigned int flags, const uint64_t *base_table, unsigned long long max_pa, uintptr_t max_va, int xlat_regime) { uint64_t mair, ttbr0, tcr; uintptr_t virtual_addr_space_size; /* Set attributes in the right indices of the MAIR. */ mair = MAIR_ATTR_SET(ATTR_DEVICE, ATTR_DEVICE_INDEX); mair |= MAIR_ATTR_SET(ATTR_IWBWA_OWBWA_NTR, ATTR_IWBWA_OWBWA_NTR_INDEX); mair |= MAIR_ATTR_SET(ATTR_NON_CACHEABLE, ATTR_NON_CACHEABLE_INDEX); /* * Limit the input address ranges and memory region sizes translated * using TTBR0 to the given virtual address space size. */ assert(max_va < ((uint64_t)UINTPTR_MAX)); virtual_addr_space_size = (uintptr_t)max_va + 1U; assert(virtual_addr_space_size >= xlat_get_min_virt_addr_space_size()); assert(virtual_addr_space_size <= MAX_VIRT_ADDR_SPACE_SIZE); assert(IS_POWER_OF_TWO(virtual_addr_space_size)); /* * __builtin_ctzll(0) is undefined but here we are guaranteed that * virtual_addr_space_size is in the range [1,UINTPTR_MAX]. */ int t0sz = 64 - __builtin_ctzll(virtual_addr_space_size); tcr = (uint64_t)t0sz << TCR_T0SZ_SHIFT; /* * Set the cacheability and shareability attributes for memory * associated with translation table walks. */ if ((flags & XLAT_TABLE_NC) != 0U) { /* Inner & outer non-cacheable non-shareable. */ tcr |= TCR_SH_NON_SHAREABLE | TCR_RGN_OUTER_NC | TCR_RGN_INNER_NC; } else { /* Inner & outer WBWA & shareable. */ tcr |= TCR_SH_INNER_SHAREABLE | TCR_RGN_OUTER_WBA | TCR_RGN_INNER_WBA; } /* * It is safer to restrict the max physical address accessible by the * hardware as much as possible. */ unsigned long long tcr_ps_bits = tcr_physical_addr_size_bits(max_pa); if (xlat_regime == EL1_EL0_REGIME) { /* * TCR_EL1.EPD1: Disable translation table walk for addresses * that are translated using TTBR1_EL1. */ tcr |= TCR_EPD1_BIT | (tcr_ps_bits << TCR_EL1_IPS_SHIFT); } else if (xlat_regime == EL2_REGIME) { tcr |= TCR_EL2_RES1 | (tcr_ps_bits << TCR_EL2_PS_SHIFT); } else { assert(xlat_regime == EL3_REGIME); tcr |= TCR_EL3_RES1 | (tcr_ps_bits << TCR_EL3_PS_SHIFT); } /* Set TTBR bits as well */ ttbr0 = (uint64_t) base_table; if (is_armv8_2_ttcnp_present()) { /* Enable CnP bit so as to share page tables with all PEs. */ ttbr0 |= TTBR_CNP_BIT; } params[MMU_CFG_MAIR] = mair; params[MMU_CFG_TCR] = tcr; params[MMU_CFG_TTBR0] = ttbr0; } trusted-firmware-a-2.2/lib/xlat_tables_v2/xlat_tables.mk000066400000000000000000000006201355360272700234210ustar00rootroot00000000000000# # Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # XLAT_TABLES_LIB_SRCS := $(addprefix lib/xlat_tables_v2/, \ ${ARCH}/enable_mmu.S \ ${ARCH}/xlat_tables_arch.c \ xlat_tables_context.c \ xlat_tables_core.c \ xlat_tables_utils.c) XLAT_TABLES_LIB_V2 := 1 $(eval $(call add_define,XLAT_TABLES_LIB_V2)) trusted-firmware-a-2.2/lib/xlat_tables_v2/xlat_tables_context.c000066400000000000000000000112701355360272700250030ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "xlat_tables_private.h" /* * MMU configuration register values for the active translation context. Used * from the MMU assembly helpers. */ uint64_t mmu_cfg_params[MMU_CFG_PARAM_MAX]; /* * Allocate and initialise the default translation context for the BL image * currently executing. */ REGISTER_XLAT_CONTEXT(tf, MAX_MMAP_REGIONS, MAX_XLAT_TABLES, PLAT_VIRT_ADDR_SPACE_SIZE, PLAT_PHY_ADDR_SPACE_SIZE); void mmap_add_region(unsigned long long base_pa, uintptr_t base_va, size_t size, unsigned int attr) { mmap_region_t mm = MAP_REGION(base_pa, base_va, size, attr); mmap_add_region_ctx(&tf_xlat_ctx, &mm); } void mmap_add(const mmap_region_t *mm) { mmap_add_ctx(&tf_xlat_ctx, mm); } void mmap_add_region_alloc_va(unsigned long long base_pa, uintptr_t *base_va, size_t size, unsigned int attr) { mmap_region_t mm = MAP_REGION_ALLOC_VA(base_pa, size, attr); mmap_add_region_alloc_va_ctx(&tf_xlat_ctx, &mm); *base_va = mm.base_va; } void mmap_add_alloc_va(mmap_region_t *mm) { while (mm->granularity != 0U) { assert(mm->base_va == 0U); mmap_add_region_alloc_va_ctx(&tf_xlat_ctx, mm); mm++; } } #if PLAT_XLAT_TABLES_DYNAMIC int mmap_add_dynamic_region(unsigned long long base_pa, uintptr_t base_va, size_t size, unsigned int attr) { mmap_region_t mm = MAP_REGION(base_pa, base_va, size, attr); return mmap_add_dynamic_region_ctx(&tf_xlat_ctx, &mm); } int mmap_add_dynamic_region_alloc_va(unsigned long long base_pa, uintptr_t *base_va, size_t size, unsigned int attr) { mmap_region_t mm = MAP_REGION_ALLOC_VA(base_pa, size, attr); int rc = mmap_add_dynamic_region_alloc_va_ctx(&tf_xlat_ctx, &mm); *base_va = mm.base_va; return rc; } int mmap_remove_dynamic_region(uintptr_t base_va, size_t size) { return mmap_remove_dynamic_region_ctx(&tf_xlat_ctx, base_va, size); } #endif /* PLAT_XLAT_TABLES_DYNAMIC */ void __init init_xlat_tables(void) { assert(tf_xlat_ctx.xlat_regime == EL_REGIME_INVALID); unsigned int current_el = xlat_arch_current_el(); if (current_el == 1U) { tf_xlat_ctx.xlat_regime = EL1_EL0_REGIME; } else if (current_el == 2U) { tf_xlat_ctx.xlat_regime = EL2_REGIME; } else { assert(current_el == 3U); tf_xlat_ctx.xlat_regime = EL3_REGIME; } init_xlat_tables_ctx(&tf_xlat_ctx); } int xlat_get_mem_attributes(uintptr_t base_va, uint32_t *attr) { return xlat_get_mem_attributes_ctx(&tf_xlat_ctx, base_va, attr); } int xlat_change_mem_attributes(uintptr_t base_va, size_t size, uint32_t attr) { return xlat_change_mem_attributes_ctx(&tf_xlat_ctx, base_va, size, attr); } /* * If dynamic allocation of new regions is disabled then by the time we call the * function enabling the MMU, we'll have registered all the memory regions to * map for the system's lifetime. Therefore, at this point we know the maximum * physical address that will ever be mapped. * * If dynamic allocation is enabled then we can't make any such assumption * because the maximum physical address could get pushed while adding a new * region. Therefore, in this case we have to assume that the whole address * space size might be mapped. */ #ifdef PLAT_XLAT_TABLES_DYNAMIC #define MAX_PHYS_ADDR tf_xlat_ctx.pa_max_address #else #define MAX_PHYS_ADDR tf_xlat_ctx.max_pa #endif #ifdef __aarch64__ void enable_mmu_el1(unsigned int flags) { setup_mmu_cfg((uint64_t *)&mmu_cfg_params, flags, tf_xlat_ctx.base_table, MAX_PHYS_ADDR, tf_xlat_ctx.va_max_address, EL1_EL0_REGIME); enable_mmu_direct_el1(flags); } void enable_mmu_el2(unsigned int flags) { setup_mmu_cfg((uint64_t *)&mmu_cfg_params, flags, tf_xlat_ctx.base_table, MAX_PHYS_ADDR, tf_xlat_ctx.va_max_address, EL2_REGIME); enable_mmu_direct_el2(flags); } void enable_mmu_el3(unsigned int flags) { setup_mmu_cfg((uint64_t *)&mmu_cfg_params, flags, tf_xlat_ctx.base_table, MAX_PHYS_ADDR, tf_xlat_ctx.va_max_address, EL3_REGIME); enable_mmu_direct_el3(flags); } #else /* !__aarch64__ */ void enable_mmu_svc_mon(unsigned int flags) { setup_mmu_cfg((uint64_t *)&mmu_cfg_params, flags, tf_xlat_ctx.base_table, MAX_PHYS_ADDR, tf_xlat_ctx.va_max_address, EL1_EL0_REGIME); enable_mmu_direct_svc_mon(flags); } void enable_mmu_hyp(unsigned int flags) { setup_mmu_cfg((uint64_t *)&mmu_cfg_params, flags, tf_xlat_ctx.base_table, MAX_PHYS_ADDR, tf_xlat_ctx.va_max_address, EL2_REGIME); enable_mmu_direct_hyp(flags); } #endif /* __aarch64__ */ trusted-firmware-a-2.2/lib/xlat_tables_v2/xlat_tables_core.c000066400000000000000000001037521355360272700242560ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include "xlat_tables_private.h" /* Helper function that cleans the data cache only if it is enabled. */ static inline __attribute__((unused)) void xlat_clean_dcache_range(uintptr_t addr, size_t size) { if (is_dcache_enabled()) clean_dcache_range(addr, size); } #if PLAT_XLAT_TABLES_DYNAMIC /* * The following functions assume that they will be called using subtables only. * The base table can't be unmapped, so it is not needed to do any special * handling for it. */ /* * Returns the index of the array corresponding to the specified translation * table. */ static int xlat_table_get_index(const xlat_ctx_t *ctx, const uint64_t *table) { for (int i = 0; i < ctx->tables_num; i++) if (ctx->tables[i] == table) return i; /* * Maybe we were asked to get the index of the base level table, which * should never happen. */ assert(false); return -1; } /* Returns a pointer to an empty translation table. */ static uint64_t *xlat_table_get_empty(const xlat_ctx_t *ctx) { for (int i = 0; i < ctx->tables_num; i++) if (ctx->tables_mapped_regions[i] == 0) return ctx->tables[i]; return NULL; } /* Increments region count for a given table. */ static void xlat_table_inc_regions_count(const xlat_ctx_t *ctx, const uint64_t *table) { int idx = xlat_table_get_index(ctx, table); ctx->tables_mapped_regions[idx]++; } /* Decrements region count for a given table. */ static void xlat_table_dec_regions_count(const xlat_ctx_t *ctx, const uint64_t *table) { int idx = xlat_table_get_index(ctx, table); ctx->tables_mapped_regions[idx]--; } /* Returns 0 if the specified table isn't empty, otherwise 1. */ static bool xlat_table_is_empty(const xlat_ctx_t *ctx, const uint64_t *table) { return ctx->tables_mapped_regions[xlat_table_get_index(ctx, table)] == 0; } #else /* PLAT_XLAT_TABLES_DYNAMIC */ /* Returns a pointer to the first empty translation table. */ static uint64_t *xlat_table_get_empty(xlat_ctx_t *ctx) { assert(ctx->next_table < ctx->tables_num); return ctx->tables[ctx->next_table++]; } #endif /* PLAT_XLAT_TABLES_DYNAMIC */ /* * Returns a block/page table descriptor for the given level and attributes. */ uint64_t xlat_desc(const xlat_ctx_t *ctx, uint32_t attr, unsigned long long addr_pa, unsigned int level) { uint64_t desc; uint32_t mem_type; /* Make sure that the granularity is fine enough to map this address. */ assert((addr_pa & XLAT_BLOCK_MASK(level)) == 0U); desc = addr_pa; /* * There are different translation table descriptors for level 3 and the * rest. */ desc |= (level == XLAT_TABLE_LEVEL_MAX) ? PAGE_DESC : BLOCK_DESC; /* * Always set the access flag, as this library assumes access flag * faults aren't managed. */ desc |= LOWER_ATTRS(ACCESS_FLAG); /* * Deduce other fields of the descriptor based on the MT_NS and MT_RW * memory region attributes. */ desc |= ((attr & MT_NS) != 0U) ? LOWER_ATTRS(NS) : 0U; desc |= ((attr & MT_RW) != 0U) ? LOWER_ATTRS(AP_RW) : LOWER_ATTRS(AP_RO); /* * Do not allow unprivileged access when the mapping is for a privileged * EL. For translation regimes that do not have mappings for access for * lower exception levels, set AP[2] to AP_NO_ACCESS_UNPRIVILEGED. */ if (ctx->xlat_regime == EL1_EL0_REGIME) { if ((attr & MT_USER) != 0U) { /* EL0 mapping requested, so we give User access */ desc |= LOWER_ATTRS(AP_ACCESS_UNPRIVILEGED); } else { /* EL1 mapping requested, no User access granted */ desc |= LOWER_ATTRS(AP_NO_ACCESS_UNPRIVILEGED); } } else { assert((ctx->xlat_regime == EL2_REGIME) || (ctx->xlat_regime == EL3_REGIME)); desc |= LOWER_ATTRS(AP_ONE_VA_RANGE_RES1); } /* * Deduce shareability domain and executability of the memory region * from the memory type of the attributes (MT_TYPE). * * Data accesses to device memory and non-cacheable normal memory are * coherent for all observers in the system, and correspondingly are * always treated as being Outer Shareable. Therefore, for these 2 types * of memory, it is not strictly needed to set the shareability field * in the translation tables. */ mem_type = MT_TYPE(attr); if (mem_type == MT_DEVICE) { desc |= LOWER_ATTRS(ATTR_DEVICE_INDEX | OSH); /* * Always map device memory as execute-never. * This is to avoid the possibility of a speculative instruction * fetch, which could be an issue if this memory region * corresponds to a read-sensitive peripheral. */ desc |= xlat_arch_regime_get_xn_desc(ctx->xlat_regime); } else { /* Normal memory */ /* * Always map read-write normal memory as execute-never. * This library assumes that it is used by software that does * not self-modify its code, therefore R/W memory is reserved * for data storage, which must not be executable. * * Note that setting the XN bit here is for consistency only. * The function that enables the MMU sets the SCTLR_ELx.WXN bit, * which makes any writable memory region to be treated as * execute-never, regardless of the value of the XN bit in the * translation table. * * For read-only memory, rely on the MT_EXECUTE/MT_EXECUTE_NEVER * attribute to figure out the value of the XN bit. The actual * XN bit(s) to set in the descriptor depends on the context's * translation regime and the policy applied in * xlat_arch_regime_get_xn_desc(). */ if (((attr & MT_RW) != 0U) || ((attr & MT_EXECUTE_NEVER) != 0U)) { desc |= xlat_arch_regime_get_xn_desc(ctx->xlat_regime); } if (mem_type == MT_MEMORY) { desc |= LOWER_ATTRS(ATTR_IWBWA_OWBWA_NTR_INDEX | ISH); /* Check if Branch Target Identification is enabled */ #if ENABLE_BTI /* Set GP bit for block and page code entries * if BTI mechanism is implemented. */ if (is_armv8_5_bti_present() && ((attr & (MT_TYPE_MASK | MT_RW | MT_EXECUTE_NEVER)) == MT_CODE)) { desc |= GP; } #endif } else { assert(mem_type == MT_NON_CACHEABLE); desc |= LOWER_ATTRS(ATTR_NON_CACHEABLE_INDEX | OSH); } } return desc; } /* * Enumeration of actions that can be made when mapping table entries depending * on the previous value in that entry and information about the region being * mapped. */ typedef enum { /* Do nothing */ ACTION_NONE, /* Write a block (or page, if in level 3) entry. */ ACTION_WRITE_BLOCK_ENTRY, /* * Create a new table and write a table entry pointing to it. Recurse * into it for further processing. */ ACTION_CREATE_NEW_TABLE, /* * There is a table descriptor in this entry, read it and recurse into * that table for further processing. */ ACTION_RECURSE_INTO_TABLE, } action_t; /* * Function that returns the first VA of the table affected by the specified * mmap region. */ static uintptr_t xlat_tables_find_start_va(mmap_region_t *mm, const uintptr_t table_base_va, const unsigned int level) { uintptr_t table_idx_va; if (mm->base_va > table_base_va) { /* Find the first index of the table affected by the region. */ table_idx_va = mm->base_va & ~XLAT_BLOCK_MASK(level); } else { /* Start from the beginning of the table. */ table_idx_va = table_base_va; } return table_idx_va; } /* * Function that returns table index for the given VA and level arguments. */ static inline unsigned int xlat_tables_va_to_index(const uintptr_t table_base_va, const uintptr_t va, const unsigned int level) { return (unsigned int)((va - table_base_va) >> XLAT_ADDR_SHIFT(level)); } #if PLAT_XLAT_TABLES_DYNAMIC /* * From the given arguments, it decides which action to take when unmapping the * specified region. */ static action_t xlat_tables_unmap_region_action(const mmap_region_t *mm, const uintptr_t table_idx_va, const uintptr_t table_idx_end_va, const unsigned int level, const uint64_t desc_type) { action_t action; uintptr_t region_end_va = mm->base_va + mm->size - 1U; if ((mm->base_va <= table_idx_va) && (region_end_va >= table_idx_end_va)) { /* Region covers all block */ if (level == 3U) { /* * Last level, only page descriptors allowed, * erase it. */ assert(desc_type == PAGE_DESC); action = ACTION_WRITE_BLOCK_ENTRY; } else { /* * Other levels can have table descriptors. If * so, recurse into it and erase descriptors * inside it as needed. If there is a block * descriptor, just erase it. If an invalid * descriptor is found, this table isn't * actually mapped, which shouldn't happen. */ if (desc_type == TABLE_DESC) { action = ACTION_RECURSE_INTO_TABLE; } else { assert(desc_type == BLOCK_DESC); action = ACTION_WRITE_BLOCK_ENTRY; } } } else if ((mm->base_va <= table_idx_end_va) || (region_end_va >= table_idx_va)) { /* * Region partially covers block. * * It can't happen in level 3. * * There must be a table descriptor here, if not there * was a problem when mapping the region. */ assert(level < 3U); assert(desc_type == TABLE_DESC); action = ACTION_RECURSE_INTO_TABLE; } else { /* The region doesn't cover the block at all */ action = ACTION_NONE; } return action; } /* * Recursive function that writes to the translation tables and unmaps the * specified region. */ static void xlat_tables_unmap_region(xlat_ctx_t *ctx, mmap_region_t *mm, const uintptr_t table_base_va, uint64_t *const table_base, const unsigned int table_entries, const unsigned int level) { assert((level >= ctx->base_level) && (level <= XLAT_TABLE_LEVEL_MAX)); uint64_t *subtable; uint64_t desc; uintptr_t table_idx_va; uintptr_t table_idx_end_va; /* End VA of this entry */ uintptr_t region_end_va = mm->base_va + mm->size - 1U; unsigned int table_idx; table_idx_va = xlat_tables_find_start_va(mm, table_base_va, level); table_idx = xlat_tables_va_to_index(table_base_va, table_idx_va, level); while (table_idx < table_entries) { table_idx_end_va = table_idx_va + XLAT_BLOCK_SIZE(level) - 1U; desc = table_base[table_idx]; uint64_t desc_type = desc & DESC_MASK; action_t action = xlat_tables_unmap_region_action(mm, table_idx_va, table_idx_end_va, level, desc_type); if (action == ACTION_WRITE_BLOCK_ENTRY) { table_base[table_idx] = INVALID_DESC; xlat_arch_tlbi_va(table_idx_va, ctx->xlat_regime); } else if (action == ACTION_RECURSE_INTO_TABLE) { subtable = (uint64_t *)(uintptr_t)(desc & TABLE_ADDR_MASK); /* Recurse to write into subtable */ xlat_tables_unmap_region(ctx, mm, table_idx_va, subtable, XLAT_TABLE_ENTRIES, level + 1U); #if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY) xlat_clean_dcache_range((uintptr_t)subtable, XLAT_TABLE_ENTRIES * sizeof(uint64_t)); #endif /* * If the subtable is now empty, remove its reference. */ if (xlat_table_is_empty(ctx, subtable)) { table_base[table_idx] = INVALID_DESC; xlat_arch_tlbi_va(table_idx_va, ctx->xlat_regime); } } else { assert(action == ACTION_NONE); } table_idx++; table_idx_va += XLAT_BLOCK_SIZE(level); /* If reached the end of the region, exit */ if (region_end_va <= table_idx_va) break; } if (level > ctx->base_level) xlat_table_dec_regions_count(ctx, table_base); } #endif /* PLAT_XLAT_TABLES_DYNAMIC */ /* * From the given arguments, it decides which action to take when mapping the * specified region. */ static action_t xlat_tables_map_region_action(const mmap_region_t *mm, unsigned int desc_type, unsigned long long dest_pa, uintptr_t table_entry_base_va, unsigned int level) { uintptr_t mm_end_va = mm->base_va + mm->size - 1U; uintptr_t table_entry_end_va = table_entry_base_va + XLAT_BLOCK_SIZE(level) - 1U; /* * The descriptor types allowed depend on the current table level. */ if ((mm->base_va <= table_entry_base_va) && (mm_end_va >= table_entry_end_va)) { /* * Table entry is covered by region * -------------------------------- * * This means that this table entry can describe the whole * translation with this granularity in principle. */ if (level == 3U) { /* * Last level, only page descriptors are allowed. */ if (desc_type == PAGE_DESC) { /* * There's another region mapped here, don't * overwrite. */ return ACTION_NONE; } else { assert(desc_type == INVALID_DESC); return ACTION_WRITE_BLOCK_ENTRY; } } else { /* * Other levels. Table descriptors are allowed. Block * descriptors too, but they have some limitations. */ if (desc_type == TABLE_DESC) { /* There's already a table, recurse into it. */ return ACTION_RECURSE_INTO_TABLE; } else if (desc_type == INVALID_DESC) { /* * There's nothing mapped here, create a new * entry. * * Check if the destination granularity allows * us to use a block descriptor or we need a * finer table for it. * * Also, check if the current level allows block * descriptors. If not, create a table instead. */ if (((dest_pa & XLAT_BLOCK_MASK(level)) != 0U) || (level < MIN_LVL_BLOCK_DESC) || (mm->granularity < XLAT_BLOCK_SIZE(level))) return ACTION_CREATE_NEW_TABLE; else return ACTION_WRITE_BLOCK_ENTRY; } else { /* * There's another region mapped here, don't * overwrite. */ assert(desc_type == BLOCK_DESC); return ACTION_NONE; } } } else if ((mm->base_va <= table_entry_end_va) || (mm_end_va >= table_entry_base_va)) { /* * Region partially covers table entry * ----------------------------------- * * This means that this table entry can't describe the whole * translation, a finer table is needed. * There cannot be partial block overlaps in level 3. If that * happens, some of the preliminary checks when adding the * mmap region failed to detect that PA and VA must at least be * aligned to PAGE_SIZE. */ assert(level < 3U); if (desc_type == INVALID_DESC) { /* * The block is not fully covered by the region. Create * a new table, recurse into it and try to map the * region with finer granularity. */ return ACTION_CREATE_NEW_TABLE; } else { assert(desc_type == TABLE_DESC); /* * The block is not fully covered by the region, but * there is already a table here. Recurse into it and * try to map with finer granularity. * * PAGE_DESC for level 3 has the same value as * TABLE_DESC, but this code can't run on a level 3 * table because there can't be overlaps in level 3. */ return ACTION_RECURSE_INTO_TABLE; } } else { /* * This table entry is outside of the region specified in the * arguments, don't write anything to it. */ return ACTION_NONE; } } /* * Recursive function that writes to the translation tables and maps the * specified region. On success, it returns the VA of the last byte that was * successfully mapped. On error, it returns the VA of the next entry that * should have been mapped. */ static uintptr_t xlat_tables_map_region(xlat_ctx_t *ctx, mmap_region_t *mm, uintptr_t table_base_va, uint64_t *const table_base, unsigned int table_entries, unsigned int level) { assert((level >= ctx->base_level) && (level <= XLAT_TABLE_LEVEL_MAX)); uintptr_t mm_end_va = mm->base_va + mm->size - 1U; uintptr_t table_idx_va; unsigned long long table_idx_pa; uint64_t *subtable; uint64_t desc; unsigned int table_idx; table_idx_va = xlat_tables_find_start_va(mm, table_base_va, level); table_idx = xlat_tables_va_to_index(table_base_va, table_idx_va, level); #if PLAT_XLAT_TABLES_DYNAMIC if (level > ctx->base_level) xlat_table_inc_regions_count(ctx, table_base); #endif while (table_idx < table_entries) { desc = table_base[table_idx]; table_idx_pa = mm->base_pa + table_idx_va - mm->base_va; action_t action = xlat_tables_map_region_action(mm, (uint32_t)(desc & DESC_MASK), table_idx_pa, table_idx_va, level); if (action == ACTION_WRITE_BLOCK_ENTRY) { table_base[table_idx] = xlat_desc(ctx, (uint32_t)mm->attr, table_idx_pa, level); } else if (action == ACTION_CREATE_NEW_TABLE) { uintptr_t end_va; subtable = xlat_table_get_empty(ctx); if (subtable == NULL) { /* Not enough free tables to map this region */ return table_idx_va; } /* Point to new subtable from this one. */ table_base[table_idx] = TABLE_DESC | (unsigned long)subtable; /* Recurse to write into subtable */ end_va = xlat_tables_map_region(ctx, mm, table_idx_va, subtable, XLAT_TABLE_ENTRIES, level + 1U); #if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY) xlat_clean_dcache_range((uintptr_t)subtable, XLAT_TABLE_ENTRIES * sizeof(uint64_t)); #endif if (end_va != (table_idx_va + XLAT_BLOCK_SIZE(level) - 1U)) return end_va; } else if (action == ACTION_RECURSE_INTO_TABLE) { uintptr_t end_va; subtable = (uint64_t *)(uintptr_t)(desc & TABLE_ADDR_MASK); /* Recurse to write into subtable */ end_va = xlat_tables_map_region(ctx, mm, table_idx_va, subtable, XLAT_TABLE_ENTRIES, level + 1U); #if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY) xlat_clean_dcache_range((uintptr_t)subtable, XLAT_TABLE_ENTRIES * sizeof(uint64_t)); #endif if (end_va != (table_idx_va + XLAT_BLOCK_SIZE(level) - 1U)) return end_va; } else { assert(action == ACTION_NONE); } table_idx++; table_idx_va += XLAT_BLOCK_SIZE(level); /* If reached the end of the region, exit */ if (mm_end_va <= table_idx_va) break; } return table_idx_va - 1U; } /* * Function that verifies that a region can be mapped. * Returns: * 0: Success, the mapping is allowed. * EINVAL: Invalid values were used as arguments. * ERANGE: The memory limits were surpassed. * ENOMEM: There is not enough memory in the mmap array. * EPERM: Region overlaps another one in an invalid way. */ static int mmap_add_region_check(const xlat_ctx_t *ctx, const mmap_region_t *mm) { unsigned long long base_pa = mm->base_pa; uintptr_t base_va = mm->base_va; size_t size = mm->size; size_t granularity = mm->granularity; unsigned long long end_pa = base_pa + size - 1U; uintptr_t end_va = base_va + size - 1U; if (!IS_PAGE_ALIGNED(base_pa) || !IS_PAGE_ALIGNED(base_va) || !IS_PAGE_ALIGNED(size)) return -EINVAL; if ((granularity != XLAT_BLOCK_SIZE(1U)) && (granularity != XLAT_BLOCK_SIZE(2U)) && (granularity != XLAT_BLOCK_SIZE(3U))) { return -EINVAL; } /* Check for overflows */ if ((base_pa > end_pa) || (base_va > end_va)) return -ERANGE; if ((base_va + (uintptr_t)size - (uintptr_t)1) > ctx->va_max_address) return -ERANGE; if ((base_pa + (unsigned long long)size - 1ULL) > ctx->pa_max_address) return -ERANGE; /* Check that there is space in the ctx->mmap array */ if (ctx->mmap[ctx->mmap_num - 1].size != 0U) return -ENOMEM; /* Check for PAs and VAs overlaps with all other regions */ for (const mmap_region_t *mm_cursor = ctx->mmap; mm_cursor->size != 0U; ++mm_cursor) { uintptr_t mm_cursor_end_va = mm_cursor->base_va + mm_cursor->size - 1U; /* * Check if one of the regions is completely inside the other * one. */ bool fully_overlapped_va = ((base_va >= mm_cursor->base_va) && (end_va <= mm_cursor_end_va)) || ((mm_cursor->base_va >= base_va) && (mm_cursor_end_va <= end_va)); /* * Full VA overlaps are only allowed if both regions are * identity mapped (zero offset) or have the same VA to PA * offset. Also, make sure that it's not the exact same area. * This can only be done with static regions. */ if (fully_overlapped_va) { #if PLAT_XLAT_TABLES_DYNAMIC if (((mm->attr & MT_DYNAMIC) != 0U) || ((mm_cursor->attr & MT_DYNAMIC) != 0U)) return -EPERM; #endif /* PLAT_XLAT_TABLES_DYNAMIC */ if ((mm_cursor->base_va - mm_cursor->base_pa) != (base_va - base_pa)) return -EPERM; if ((base_va == mm_cursor->base_va) && (size == mm_cursor->size)) return -EPERM; } else { /* * If the regions do not have fully overlapping VAs, * then they must have fully separated VAs and PAs. * Partial overlaps are not allowed */ unsigned long long mm_cursor_end_pa = mm_cursor->base_pa + mm_cursor->size - 1U; bool separated_pa = (end_pa < mm_cursor->base_pa) || (base_pa > mm_cursor_end_pa); bool separated_va = (end_va < mm_cursor->base_va) || (base_va > mm_cursor_end_va); if (!separated_va || !separated_pa) return -EPERM; } } return 0; } void mmap_add_region_ctx(xlat_ctx_t *ctx, const mmap_region_t *mm) { mmap_region_t *mm_cursor = ctx->mmap, *mm_destination; const mmap_region_t *mm_end = ctx->mmap + ctx->mmap_num; const mmap_region_t *mm_last; unsigned long long end_pa = mm->base_pa + mm->size - 1U; uintptr_t end_va = mm->base_va + mm->size - 1U; int ret; /* Ignore empty regions */ if (mm->size == 0U) return; /* Static regions must be added before initializing the xlat tables. */ assert(!ctx->initialized); ret = mmap_add_region_check(ctx, mm); if (ret != 0) { ERROR("mmap_add_region_check() failed. error %d\n", ret); assert(false); return; } /* * Find correct place in mmap to insert new region. * * 1 - Lower region VA end first. * 2 - Smaller region size first. * * VA 0 0xFF * * 1st |------| * 2nd |------------| * 3rd |------| * 4th |---| * 5th |---| * 6th |----------| * 7th |-------------------------------------| * * This is required for overlapping regions only. It simplifies adding * regions with the loop in xlat_tables_init_internal because the outer * ones won't overwrite block or page descriptors of regions added * previously. * * Overlapping is only allowed for static regions. */ while (((mm_cursor->base_va + mm_cursor->size - 1U) < end_va) && (mm_cursor->size != 0U)) { ++mm_cursor; } while (((mm_cursor->base_va + mm_cursor->size - 1U) == end_va) && (mm_cursor->size != 0U) && (mm_cursor->size < mm->size)) { ++mm_cursor; } /* * Find the last entry marker in the mmap */ mm_last = ctx->mmap; while ((mm_last->size != 0U) && (mm_last < mm_end)) { ++mm_last; } /* * Check if we have enough space in the memory mapping table. * This shouldn't happen as we have checked in mmap_add_region_check * that there is free space. */ assert(mm_last->size == 0U); /* Make room for new region by moving other regions up by one place */ mm_destination = mm_cursor + 1; (void)memmove(mm_destination, mm_cursor, (uintptr_t)mm_last - (uintptr_t)mm_cursor); /* * Check we haven't lost the empty sentinel from the end of the array. * This shouldn't happen as we have checked in mmap_add_region_check * that there is free space. */ assert(mm_end->size == 0U); *mm_cursor = *mm; if (end_pa > ctx->max_pa) ctx->max_pa = end_pa; if (end_va > ctx->max_va) ctx->max_va = end_va; } /* * Determine the table level closest to the initial lookup level that * can describe this translation. Then, align base VA to the next block * at the determined level. */ static void mmap_alloc_va_align_ctx(xlat_ctx_t *ctx, mmap_region_t *mm) { /* * By or'ing the size and base PA the alignment will be the one * corresponding to the smallest boundary of the two of them. * * There are three different cases. For example (for 4 KiB page size): * * +--------------+------------------++--------------+ * | PA alignment | Size multiple of || VA alignment | * +--------------+------------------++--------------+ * | 2 MiB | 2 MiB || 2 MiB | (1) * | 2 MiB | 4 KiB || 4 KiB | (2) * | 4 KiB | 2 MiB || 4 KiB | (3) * +--------------+------------------++--------------+ * * - In (1), it is possible to take advantage of the alignment of the PA * and the size of the region to use a level 2 translation table * instead of a level 3 one. * * - In (2), the size is smaller than a block entry of level 2, so it is * needed to use a level 3 table to describe the region or the library * will map more memory than the desired one. * * - In (3), even though the region has the size of one level 2 block * entry, it isn't possible to describe the translation with a level 2 * block entry because of the alignment of the base PA. * * Only bits 47:21 of a level 2 block descriptor are used by the MMU, * bits 20:0 of the resulting address are 0 in this case. Because of * this, the PA generated as result of this translation is aligned to * 2 MiB. The PA that was requested to be mapped is aligned to 4 KiB, * though, which means that the resulting translation is incorrect. * The only way to prevent this is by using a finer granularity. */ unsigned long long align_check; align_check = mm->base_pa | (unsigned long long)mm->size; /* * Assume it is always aligned to level 3. There's no need to check that * level because its block size is PAGE_SIZE. The checks to verify that * the addresses and size are aligned to PAGE_SIZE are inside * mmap_add_region. */ for (unsigned int level = ctx->base_level; level <= 2U; ++level) { if ((align_check & XLAT_BLOCK_MASK(level)) != 0U) continue; mm->base_va = round_up(mm->base_va, XLAT_BLOCK_SIZE(level)); return; } } void mmap_add_region_alloc_va_ctx(xlat_ctx_t *ctx, mmap_region_t *mm) { mm->base_va = ctx->max_va + 1UL; assert(mm->size > 0U); mmap_alloc_va_align_ctx(ctx, mm); /* Detect overflows. More checks are done in mmap_add_region_check(). */ assert(mm->base_va > ctx->max_va); mmap_add_region_ctx(ctx, mm); } void mmap_add_ctx(xlat_ctx_t *ctx, const mmap_region_t *mm) { const mmap_region_t *mm_cursor = mm; while (mm_cursor->granularity != 0U) { mmap_add_region_ctx(ctx, mm_cursor); mm_cursor++; } } #if PLAT_XLAT_TABLES_DYNAMIC int mmap_add_dynamic_region_ctx(xlat_ctx_t *ctx, mmap_region_t *mm) { mmap_region_t *mm_cursor = ctx->mmap; const mmap_region_t *mm_last = mm_cursor + ctx->mmap_num; unsigned long long end_pa = mm->base_pa + mm->size - 1U; uintptr_t end_va = mm->base_va + mm->size - 1U; int ret; /* Nothing to do */ if (mm->size == 0U) return 0; /* Now this region is a dynamic one */ mm->attr |= MT_DYNAMIC; ret = mmap_add_region_check(ctx, mm); if (ret != 0) return ret; /* * Find the adequate entry in the mmap array in the same way done for * static regions in mmap_add_region_ctx(). */ while (((mm_cursor->base_va + mm_cursor->size - 1U) < end_va) && (mm_cursor->size != 0U)) { ++mm_cursor; } while (((mm_cursor->base_va + mm_cursor->size - 1U) == end_va) && (mm_cursor->size != 0U) && (mm_cursor->size < mm->size)) { ++mm_cursor; } /* Make room for new region by moving other regions up by one place */ (void)memmove(mm_cursor + 1U, mm_cursor, (uintptr_t)mm_last - (uintptr_t)mm_cursor); /* * Check we haven't lost the empty sentinal from the end of the array. * This shouldn't happen as we have checked in mmap_add_region_check * that there is free space. */ assert(mm_last->size == 0U); *mm_cursor = *mm; /* * Update the translation tables if the xlat tables are initialized. If * not, this region will be mapped when they are initialized. */ if (ctx->initialized) { end_va = xlat_tables_map_region(ctx, mm_cursor, 0U, ctx->base_table, ctx->base_table_entries, ctx->base_level); #if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY) xlat_clean_dcache_range((uintptr_t)ctx->base_table, ctx->base_table_entries * sizeof(uint64_t)); #endif /* Failed to map, remove mmap entry, unmap and return error. */ if (end_va != (mm_cursor->base_va + mm_cursor->size - 1U)) { (void)memmove(mm_cursor, mm_cursor + 1U, (uintptr_t)mm_last - (uintptr_t)mm_cursor); /* * Check if the mapping function actually managed to map * anything. If not, just return now. */ if (mm->base_va >= end_va) return -ENOMEM; /* * Something went wrong after mapping some table * entries, undo every change done up to this point. */ mmap_region_t unmap_mm = { .base_pa = 0U, .base_va = mm->base_va, .size = end_va - mm->base_va, .attr = 0U }; xlat_tables_unmap_region(ctx, &unmap_mm, 0U, ctx->base_table, ctx->base_table_entries, ctx->base_level); #if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY) xlat_clean_dcache_range((uintptr_t)ctx->base_table, ctx->base_table_entries * sizeof(uint64_t)); #endif return -ENOMEM; } /* * Make sure that all entries are written to the memory. There * is no need to invalidate entries when mapping dynamic regions * because new table/block/page descriptors only replace old * invalid descriptors, that aren't TLB cached. */ dsbishst(); } if (end_pa > ctx->max_pa) ctx->max_pa = end_pa; if (end_va > ctx->max_va) ctx->max_va = end_va; return 0; } int mmap_add_dynamic_region_alloc_va_ctx(xlat_ctx_t *ctx, mmap_region_t *mm) { mm->base_va = ctx->max_va + 1UL; if (mm->size == 0U) return 0; mmap_alloc_va_align_ctx(ctx, mm); /* Detect overflows. More checks are done in mmap_add_region_check(). */ if (mm->base_va < ctx->max_va) { return -ENOMEM; } return mmap_add_dynamic_region_ctx(ctx, mm); } /* * Removes the region with given base Virtual Address and size from the given * context. * * Returns: * 0: Success. * EINVAL: Invalid values were used as arguments (region not found). * EPERM: Tried to remove a static region. */ int mmap_remove_dynamic_region_ctx(xlat_ctx_t *ctx, uintptr_t base_va, size_t size) { mmap_region_t *mm = ctx->mmap; const mmap_region_t *mm_last = mm + ctx->mmap_num; int update_max_va_needed = 0; int update_max_pa_needed = 0; /* Check sanity of mmap array. */ assert(mm[ctx->mmap_num].size == 0U); while (mm->size != 0U) { if ((mm->base_va == base_va) && (mm->size == size)) break; ++mm; } /* Check that the region was found */ if (mm->size == 0U) return -EINVAL; /* If the region is static it can't be removed */ if ((mm->attr & MT_DYNAMIC) == 0U) return -EPERM; /* Check if this region is using the top VAs or PAs. */ if ((mm->base_va + mm->size - 1U) == ctx->max_va) update_max_va_needed = 1; if ((mm->base_pa + mm->size - 1U) == ctx->max_pa) update_max_pa_needed = 1; /* Update the translation tables if needed */ if (ctx->initialized) { xlat_tables_unmap_region(ctx, mm, 0U, ctx->base_table, ctx->base_table_entries, ctx->base_level); #if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY) xlat_clean_dcache_range((uintptr_t)ctx->base_table, ctx->base_table_entries * sizeof(uint64_t)); #endif xlat_arch_tlbi_va_sync(); } /* Remove this region by moving the rest down by one place. */ (void)memmove(mm, mm + 1U, (uintptr_t)mm_last - (uintptr_t)mm); /* Check if we need to update the max VAs and PAs */ if (update_max_va_needed == 1) { ctx->max_va = 0U; mm = ctx->mmap; while (mm->size != 0U) { if ((mm->base_va + mm->size - 1U) > ctx->max_va) ctx->max_va = mm->base_va + mm->size - 1U; ++mm; } } if (update_max_pa_needed == 1) { ctx->max_pa = 0U; mm = ctx->mmap; while (mm->size != 0U) { if ((mm->base_pa + mm->size - 1U) > ctx->max_pa) ctx->max_pa = mm->base_pa + mm->size - 1U; ++mm; } } return 0; } void xlat_setup_dynamic_ctx(xlat_ctx_t *ctx, unsigned long long pa_max, uintptr_t va_max, struct mmap_region *mmap, unsigned int mmap_num, uint64_t **tables, unsigned int tables_num, uint64_t *base_table, int xlat_regime, int *mapped_regions) { ctx->xlat_regime = xlat_regime; ctx->pa_max_address = pa_max; ctx->va_max_address = va_max; ctx->mmap = mmap; ctx->mmap_num = mmap_num; memset(ctx->mmap, 0, sizeof(struct mmap_region) * mmap_num); ctx->tables = (void *) tables; ctx->tables_num = tables_num; uintptr_t va_space_size = va_max + 1; ctx->base_level = GET_XLAT_TABLE_LEVEL_BASE(va_space_size); ctx->base_table = base_table; ctx->base_table_entries = GET_NUM_BASE_LEVEL_ENTRIES(va_space_size); ctx->tables_mapped_regions = mapped_regions; ctx->max_pa = 0; ctx->max_va = 0; ctx->initialized = 0; } #endif /* PLAT_XLAT_TABLES_DYNAMIC */ void __init init_xlat_tables_ctx(xlat_ctx_t *ctx) { assert(ctx != NULL); assert(!ctx->initialized); assert((ctx->xlat_regime == EL3_REGIME) || (ctx->xlat_regime == EL2_REGIME) || (ctx->xlat_regime == EL1_EL0_REGIME)); assert(!is_mmu_enabled_ctx(ctx)); mmap_region_t *mm = ctx->mmap; assert(ctx->va_max_address >= (xlat_get_min_virt_addr_space_size() - 1U)); assert(ctx->va_max_address <= (MAX_VIRT_ADDR_SPACE_SIZE - 1U)); assert(IS_POWER_OF_TWO(ctx->va_max_address + 1U)); xlat_mmap_print(mm); /* All tables must be zeroed before mapping any region. */ for (unsigned int i = 0U; i < ctx->base_table_entries; i++) ctx->base_table[i] = INVALID_DESC; for (int j = 0; j < ctx->tables_num; j++) { #if PLAT_XLAT_TABLES_DYNAMIC ctx->tables_mapped_regions[j] = 0; #endif for (unsigned int i = 0U; i < XLAT_TABLE_ENTRIES; i++) ctx->tables[j][i] = INVALID_DESC; } while (mm->size != 0U) { uintptr_t end_va = xlat_tables_map_region(ctx, mm, 0U, ctx->base_table, ctx->base_table_entries, ctx->base_level); #if !(HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY) xlat_clean_dcache_range((uintptr_t)ctx->base_table, ctx->base_table_entries * sizeof(uint64_t)); #endif if (end_va != (mm->base_va + mm->size - 1U)) { ERROR("Not enough memory to map region:\n" " VA:0x%lx PA:0x%llx size:0x%zx attr:0x%x\n", mm->base_va, mm->base_pa, mm->size, mm->attr); panic(); } mm++; } assert(ctx->pa_max_address <= xlat_arch_get_max_supported_pa()); assert(ctx->max_va <= ctx->va_max_address); assert(ctx->max_pa <= ctx->pa_max_address); ctx->initialized = true; xlat_tables_print(ctx); } trusted-firmware-a-2.2/lib/xlat_tables_v2/xlat_tables_private.h000066400000000000000000000060461355360272700250030ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef XLAT_TABLES_PRIVATE_H #define XLAT_TABLES_PRIVATE_H #include #include #include #if PLAT_XLAT_TABLES_DYNAMIC /* * Private shifts and masks to access fields of an mmap attribute */ /* Dynamic or static */ #define MT_DYN_SHIFT U(31) /* * Memory mapping private attributes * * Private attributes not exposed in the public header. */ /* * Regions mapped before the MMU can't be unmapped dynamically (they are * static) and regions mapped with MMU enabled can be unmapped. This * behaviour can't be overridden. * * Static regions can overlap each other, dynamic regions can't. */ #define MT_STATIC (U(0) << MT_DYN_SHIFT) #define MT_DYNAMIC (U(1) << MT_DYN_SHIFT) #endif /* PLAT_XLAT_TABLES_DYNAMIC */ extern uint64_t mmu_cfg_params[MMU_CFG_PARAM_MAX]; /* * Return the execute-never mask that will prevent instruction fetch at the * given translation regime. */ uint64_t xlat_arch_regime_get_xn_desc(int xlat_regime); /* * Invalidate all TLB entries that match the given virtual address. This * operation applies to all PEs in the same Inner Shareable domain as the PE * that executes this function. This functions must be called for every * translation table entry that is modified. It only affects the specified * translation regime. * * Note, however, that it is architecturally UNDEFINED to invalidate TLB entries * pertaining to a higher exception level, e.g. invalidating EL3 entries from * S-EL1. */ void xlat_arch_tlbi_va(uintptr_t va, int xlat_regime); /* * This function has to be called at the end of any code that uses the function * xlat_arch_tlbi_va(). */ void xlat_arch_tlbi_va_sync(void); /* Print VA, PA, size and attributes of all regions in the mmap array. */ void xlat_mmap_print(const mmap_region_t *mmap); /* * Print the current state of the translation tables by reading them from * memory. */ void xlat_tables_print(xlat_ctx_t *ctx); /* * Returns a block/page table descriptor for the given level and attributes. */ uint64_t xlat_desc(const xlat_ctx_t *ctx, uint32_t attr, unsigned long long addr_pa, unsigned int level); /* * Architecture-specific initialization code. */ /* Returns the current Exception Level. The returned EL must be 1 or higher. */ unsigned int xlat_arch_current_el(void); /* * Return the maximum physical address supported by the hardware. * This value depends on the execution state (AArch32/AArch64). */ unsigned long long xlat_arch_get_max_supported_pa(void); /* * Returns true if the MMU of the translation regime managed by the given * xlat_ctx_t is enabled, false otherwise. */ bool is_mmu_enabled_ctx(const xlat_ctx_t *ctx); /* Returns true if the data cache is enabled at the current EL. */ bool is_dcache_enabled(void); /* * Returns minimum virtual address space size supported by the architecture */ uintptr_t xlat_get_min_virt_addr_space_size(void); #endif /* XLAT_TABLES_PRIVATE_H */ trusted-firmware-a-2.2/lib/xlat_tables_v2/xlat_tables_utils.c000066400000000000000000000347631355360272700244730ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include "xlat_tables_private.h" #if LOG_LEVEL < LOG_LEVEL_VERBOSE void xlat_mmap_print(__unused const mmap_region_t *mmap) { /* Empty */ } void xlat_tables_print(__unused xlat_ctx_t *ctx) { /* Empty */ } #else /* if LOG_LEVEL >= LOG_LEVEL_VERBOSE */ void xlat_mmap_print(const mmap_region_t *mmap) { printf("mmap:\n"); const mmap_region_t *mm = mmap; while (mm->size != 0U) { printf(" VA:0x%lx PA:0x%llx size:0x%zx attr:0x%x granularity:0x%zx\n", mm->base_va, mm->base_pa, mm->size, mm->attr, mm->granularity); ++mm; }; printf("\n"); } /* Print the attributes of the specified block descriptor. */ static void xlat_desc_print(const xlat_ctx_t *ctx, uint64_t desc) { uint64_t mem_type_index = ATTR_INDEX_GET(desc); int xlat_regime = ctx->xlat_regime; if (mem_type_index == ATTR_IWBWA_OWBWA_NTR_INDEX) { printf("MEM"); } else if (mem_type_index == ATTR_NON_CACHEABLE_INDEX) { printf("NC"); } else { assert(mem_type_index == ATTR_DEVICE_INDEX); printf("DEV"); } if ((xlat_regime == EL3_REGIME) || (xlat_regime == EL2_REGIME)) { /* For EL3 and EL2 only check the AP[2] and XN bits. */ printf(((desc & LOWER_ATTRS(AP_RO)) != 0ULL) ? "-RO" : "-RW"); printf(((desc & UPPER_ATTRS(XN)) != 0ULL) ? "-XN" : "-EXEC"); } else { assert(xlat_regime == EL1_EL0_REGIME); /* * For EL0 and EL1: * - In AArch64 PXN and UXN can be set independently but in * AArch32 there is no UXN (XN affects both privilege levels). * For consistency, we set them simultaneously in both cases. * - RO and RW permissions must be the same in EL1 and EL0. If * EL0 can access that memory region, so can EL1, with the * same permissions. */ #if ENABLE_ASSERTIONS uint64_t xn_mask = xlat_arch_regime_get_xn_desc(EL1_EL0_REGIME); uint64_t xn_perm = desc & xn_mask; assert((xn_perm == xn_mask) || (xn_perm == 0ULL)); #endif printf(((desc & LOWER_ATTRS(AP_RO)) != 0ULL) ? "-RO" : "-RW"); /* Only check one of PXN and UXN, the other one is the same. */ printf(((desc & UPPER_ATTRS(PXN)) != 0ULL) ? "-XN" : "-EXEC"); /* * Privileged regions can only be accessed from EL1, user * regions can be accessed from EL1 and EL0. */ printf(((desc & LOWER_ATTRS(AP_ACCESS_UNPRIVILEGED)) != 0ULL) ? "-USER" : "-PRIV"); } printf(((LOWER_ATTRS(NS) & desc) != 0ULL) ? "-NS" : "-S"); #ifdef __aarch64__ /* Check Guarded Page bit */ if ((desc & GP) != 0ULL) { printf("-GP"); } #endif } static const char * const level_spacers[] = { "[LV0] ", " [LV1] ", " [LV2] ", " [LV3] " }; static const char *invalid_descriptors_ommited = "%s(%d invalid descriptors omitted)\n"; /* * Recursive function that reads the translation tables passed as an argument * and prints their status. */ static void xlat_tables_print_internal(xlat_ctx_t *ctx, uintptr_t table_base_va, const uint64_t *table_base, unsigned int table_entries, unsigned int level) { assert(level <= XLAT_TABLE_LEVEL_MAX); uint64_t desc; uintptr_t table_idx_va = table_base_va; unsigned int table_idx = 0U; size_t level_size = XLAT_BLOCK_SIZE(level); /* * Keep track of how many invalid descriptors are counted in a row. * Whenever multiple invalid descriptors are found, only the first one * is printed, and a line is added to inform about how many descriptors * have been omitted. */ int invalid_row_count = 0; while (table_idx < table_entries) { desc = table_base[table_idx]; if ((desc & DESC_MASK) == INVALID_DESC) { if (invalid_row_count == 0) { printf("%sVA:0x%lx size:0x%zx\n", level_spacers[level], table_idx_va, level_size); } invalid_row_count++; } else { if (invalid_row_count > 1) { printf(invalid_descriptors_ommited, level_spacers[level], invalid_row_count - 1); } invalid_row_count = 0; /* * Check if this is a table or a block. Tables are only * allowed in levels other than 3, but DESC_PAGE has the * same value as DESC_TABLE, so we need to check. */ if (((desc & DESC_MASK) == TABLE_DESC) && (level < XLAT_TABLE_LEVEL_MAX)) { /* * Do not print any PA for a table descriptor, * as it doesn't directly map physical memory * but instead points to the next translation * table in the translation table walk. */ printf("%sVA:0x%lx size:0x%zx\n", level_spacers[level], table_idx_va, level_size); uintptr_t addr_inner = desc & TABLE_ADDR_MASK; xlat_tables_print_internal(ctx, table_idx_va, (uint64_t *)addr_inner, XLAT_TABLE_ENTRIES, level + 1U); } else { printf("%sVA:0x%lx PA:0x%llx size:0x%zx ", level_spacers[level], table_idx_va, (uint64_t)(desc & TABLE_ADDR_MASK), level_size); xlat_desc_print(ctx, desc); printf("\n"); } } table_idx++; table_idx_va += level_size; } if (invalid_row_count > 1) { printf(invalid_descriptors_ommited, level_spacers[level], invalid_row_count - 1); } } void xlat_tables_print(xlat_ctx_t *ctx) { const char *xlat_regime_str; int used_page_tables; if (ctx->xlat_regime == EL1_EL0_REGIME) { xlat_regime_str = "1&0"; } else if (ctx->xlat_regime == EL2_REGIME) { xlat_regime_str = "2"; } else { assert(ctx->xlat_regime == EL3_REGIME); xlat_regime_str = "3"; } VERBOSE("Translation tables state:\n"); VERBOSE(" Xlat regime: EL%s\n", xlat_regime_str); VERBOSE(" Max allowed PA: 0x%llx\n", ctx->pa_max_address); VERBOSE(" Max allowed VA: 0x%lx\n", ctx->va_max_address); VERBOSE(" Max mapped PA: 0x%llx\n", ctx->max_pa); VERBOSE(" Max mapped VA: 0x%lx\n", ctx->max_va); VERBOSE(" Initial lookup level: %u\n", ctx->base_level); VERBOSE(" Entries @initial lookup level: %u\n", ctx->base_table_entries); #if PLAT_XLAT_TABLES_DYNAMIC used_page_tables = 0; for (int i = 0; i < ctx->tables_num; ++i) { if (ctx->tables_mapped_regions[i] != 0) ++used_page_tables; } #else used_page_tables = ctx->next_table; #endif VERBOSE(" Used %d sub-tables out of %d (spare: %d)\n", used_page_tables, ctx->tables_num, ctx->tables_num - used_page_tables); xlat_tables_print_internal(ctx, 0U, ctx->base_table, ctx->base_table_entries, ctx->base_level); } #endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */ /* * Do a translation table walk to find the block or page descriptor that maps * virtual_addr. * * On success, return the address of the descriptor within the translation * table. Its lookup level is stored in '*out_level'. * On error, return NULL. * * xlat_table_base * Base address for the initial lookup level. * xlat_table_base_entries * Number of entries in the translation table for the initial lookup level. * virt_addr_space_size * Size in bytes of the virtual address space. */ static uint64_t *find_xlat_table_entry(uintptr_t virtual_addr, void *xlat_table_base, unsigned int xlat_table_base_entries, unsigned long long virt_addr_space_size, unsigned int *out_level) { unsigned int start_level; uint64_t *table; unsigned int entries; start_level = GET_XLAT_TABLE_LEVEL_BASE(virt_addr_space_size); table = xlat_table_base; entries = xlat_table_base_entries; for (unsigned int level = start_level; level <= XLAT_TABLE_LEVEL_MAX; ++level) { uint64_t idx, desc, desc_type; idx = XLAT_TABLE_IDX(virtual_addr, level); if (idx >= entries) { WARN("Missing xlat table entry at address 0x%lx\n", virtual_addr); return NULL; } desc = table[idx]; desc_type = desc & DESC_MASK; if (desc_type == INVALID_DESC) { VERBOSE("Invalid entry (memory not mapped)\n"); return NULL; } if (level == XLAT_TABLE_LEVEL_MAX) { /* * Only page descriptors allowed at the final lookup * level. */ assert(desc_type == PAGE_DESC); *out_level = level; return &table[idx]; } if (desc_type == BLOCK_DESC) { *out_level = level; return &table[idx]; } assert(desc_type == TABLE_DESC); table = (uint64_t *)(uintptr_t)(desc & TABLE_ADDR_MASK); entries = XLAT_TABLE_ENTRIES; } /* * This shouldn't be reached, the translation table walk should end at * most at level XLAT_TABLE_LEVEL_MAX and return from inside the loop. */ assert(false); return NULL; } static int xlat_get_mem_attributes_internal(const xlat_ctx_t *ctx, uintptr_t base_va, uint32_t *attributes, uint64_t **table_entry, unsigned long long *addr_pa, unsigned int *table_level) { uint64_t *entry; uint64_t desc; unsigned int level; unsigned long long virt_addr_space_size; /* * Sanity-check arguments. */ assert(ctx != NULL); assert(ctx->initialized); assert((ctx->xlat_regime == EL1_EL0_REGIME) || (ctx->xlat_regime == EL2_REGIME) || (ctx->xlat_regime == EL3_REGIME)); virt_addr_space_size = (unsigned long long)ctx->va_max_address + 1ULL; assert(virt_addr_space_size > 0U); entry = find_xlat_table_entry(base_va, ctx->base_table, ctx->base_table_entries, virt_addr_space_size, &level); if (entry == NULL) { WARN("Address 0x%lx is not mapped.\n", base_va); return -EINVAL; } if (addr_pa != NULL) { *addr_pa = *entry & TABLE_ADDR_MASK; } if (table_entry != NULL) { *table_entry = entry; } if (table_level != NULL) { *table_level = level; } desc = *entry; #if LOG_LEVEL >= LOG_LEVEL_VERBOSE VERBOSE("Attributes: "); xlat_desc_print(ctx, desc); printf("\n"); #endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */ assert(attributes != NULL); *attributes = 0U; uint64_t attr_index = (desc >> ATTR_INDEX_SHIFT) & ATTR_INDEX_MASK; if (attr_index == ATTR_IWBWA_OWBWA_NTR_INDEX) { *attributes |= MT_MEMORY; } else if (attr_index == ATTR_NON_CACHEABLE_INDEX) { *attributes |= MT_NON_CACHEABLE; } else { assert(attr_index == ATTR_DEVICE_INDEX); *attributes |= MT_DEVICE; } uint64_t ap2_bit = (desc >> AP2_SHIFT) & 1U; if (ap2_bit == AP2_RW) *attributes |= MT_RW; if (ctx->xlat_regime == EL1_EL0_REGIME) { uint64_t ap1_bit = (desc >> AP1_SHIFT) & 1U; if (ap1_bit == AP1_ACCESS_UNPRIVILEGED) *attributes |= MT_USER; } uint64_t ns_bit = (desc >> NS_SHIFT) & 1U; if (ns_bit == 1U) *attributes |= MT_NS; uint64_t xn_mask = xlat_arch_regime_get_xn_desc(ctx->xlat_regime); if ((desc & xn_mask) == xn_mask) { *attributes |= MT_EXECUTE_NEVER; } else { assert((desc & xn_mask) == 0U); } return 0; } int xlat_get_mem_attributes_ctx(const xlat_ctx_t *ctx, uintptr_t base_va, uint32_t *attr) { return xlat_get_mem_attributes_internal(ctx, base_va, attr, NULL, NULL, NULL); } int xlat_change_mem_attributes_ctx(const xlat_ctx_t *ctx, uintptr_t base_va, size_t size, uint32_t attr) { /* Note: This implementation isn't optimized. */ assert(ctx != NULL); assert(ctx->initialized); unsigned long long virt_addr_space_size = (unsigned long long)ctx->va_max_address + 1U; assert(virt_addr_space_size > 0U); if (!IS_PAGE_ALIGNED(base_va)) { WARN("%s: Address 0x%lx is not aligned on a page boundary.\n", __func__, base_va); return -EINVAL; } if (size == 0U) { WARN("%s: Size is 0.\n", __func__); return -EINVAL; } if ((size % PAGE_SIZE) != 0U) { WARN("%s: Size 0x%zx is not a multiple of a page size.\n", __func__, size); return -EINVAL; } if (((attr & MT_EXECUTE_NEVER) == 0U) && ((attr & MT_RW) != 0U)) { WARN("%s: Mapping memory as read-write and executable not allowed.\n", __func__); return -EINVAL; } size_t pages_count = size / PAGE_SIZE; VERBOSE("Changing memory attributes of %zu pages starting from address 0x%lx...\n", pages_count, base_va); uintptr_t base_va_original = base_va; /* * Sanity checks. */ for (size_t i = 0U; i < pages_count; ++i) { const uint64_t *entry; uint64_t desc, attr_index; unsigned int level; entry = find_xlat_table_entry(base_va, ctx->base_table, ctx->base_table_entries, virt_addr_space_size, &level); if (entry == NULL) { WARN("Address 0x%lx is not mapped.\n", base_va); return -EINVAL; } desc = *entry; /* * Check that all the required pages are mapped at page * granularity. */ if (((desc & DESC_MASK) != PAGE_DESC) || (level != XLAT_TABLE_LEVEL_MAX)) { WARN("Address 0x%lx is not mapped at the right granularity.\n", base_va); WARN("Granularity is 0x%llx, should be 0x%x.\n", (unsigned long long)XLAT_BLOCK_SIZE(level), PAGE_SIZE); return -EINVAL; } /* * If the region type is device, it shouldn't be executable. */ attr_index = (desc >> ATTR_INDEX_SHIFT) & ATTR_INDEX_MASK; if (attr_index == ATTR_DEVICE_INDEX) { if ((attr & MT_EXECUTE_NEVER) == 0U) { WARN("Setting device memory as executable at address 0x%lx.", base_va); return -EINVAL; } } base_va += PAGE_SIZE; } /* Restore original value. */ base_va = base_va_original; for (unsigned int i = 0U; i < pages_count; ++i) { uint32_t old_attr = 0U, new_attr; uint64_t *entry = NULL; unsigned int level = 0U; unsigned long long addr_pa = 0ULL; (void) xlat_get_mem_attributes_internal(ctx, base_va, &old_attr, &entry, &addr_pa, &level); /* * From attr, only MT_RO/MT_RW, MT_EXECUTE/MT_EXECUTE_NEVER and * MT_USER/MT_PRIVILEGED are taken into account. Any other * information is ignored. */ /* Clean the old attributes so that they can be rebuilt. */ new_attr = old_attr & ~(MT_RW | MT_EXECUTE_NEVER | MT_USER); /* * Update attributes, but filter out the ones this function * isn't allowed to change. */ new_attr |= attr & (MT_RW | MT_EXECUTE_NEVER | MT_USER); /* * The break-before-make sequence requires writing an invalid * descriptor and making sure that the system sees the change * before writing the new descriptor. */ *entry = INVALID_DESC; #if !HW_ASSISTED_COHERENCY dccvac((uintptr_t)entry); #endif /* Invalidate any cached copy of this mapping in the TLBs. */ xlat_arch_tlbi_va(base_va, ctx->xlat_regime); /* Ensure completion of the invalidation. */ xlat_arch_tlbi_va_sync(); /* Write new descriptor */ *entry = xlat_desc(ctx, new_attr, addr_pa, level); #if !HW_ASSISTED_COHERENCY dccvac((uintptr_t)entry); #endif base_va += PAGE_SIZE; } /* Ensure that the last descriptor writen is seen by the system. */ dsbish(); return 0; } trusted-firmware-a-2.2/lib/zlib/000077500000000000000000000000001355360272700166175ustar00rootroot00000000000000trusted-firmware-a-2.2/lib/zlib/adler32.c000066400000000000000000000121241355360272700202170ustar00rootroot00000000000000/* adler32.c -- compute the Adler-32 checksum of a data stream * Copyright (C) 1995-2011, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); #define BASE 65521U /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ #define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); /* use NO_DIVIDE if your processor does not do division in hardware -- try it both ways to see which is faster */ #ifdef NO_DIVIDE /* note that this assumes BASE is 65521, where 65536 % 65521 == 15 (thank you to John Reiser for pointing this out) */ # define CHOP(a) \ do { \ unsigned long tmp = a >> 16; \ a &= 0xffffUL; \ a += (tmp << 4) - tmp; \ } while (0) # define MOD28(a) \ do { \ CHOP(a); \ if (a >= BASE) a -= BASE; \ } while (0) # define MOD(a) \ do { \ CHOP(a); \ MOD28(a); \ } while (0) # define MOD63(a) \ do { /* this assumes a is not negative */ \ z_off64_t tmp = a >> 32; \ a &= 0xffffffffL; \ a += (tmp << 8) - (tmp << 5) + tmp; \ tmp = a >> 16; \ a &= 0xffffL; \ a += (tmp << 4) - tmp; \ tmp = a >> 16; \ a &= 0xffffL; \ a += (tmp << 4) - tmp; \ if (a >= BASE) a -= BASE; \ } while (0) #else # define MOD(a) a %= BASE # define MOD28(a) a %= BASE # define MOD63(a) a %= BASE #endif /* ========================================================================= */ uLong ZEXPORT adler32_z(adler, buf, len) uLong adler; const Bytef *buf; z_size_t len; { unsigned long sum2; unsigned n; /* split Adler-32 into component sums */ sum2 = (adler >> 16) & 0xffff; adler &= 0xffff; /* in case user likes doing a byte at a time, keep it fast */ if (len == 1) { adler += buf[0]; if (adler >= BASE) adler -= BASE; sum2 += adler; if (sum2 >= BASE) sum2 -= BASE; return adler | (sum2 << 16); } /* initial Adler-32 value (deferred check for len == 1 speed) */ if (buf == Z_NULL) return 1L; /* in case short lengths are provided, keep it somewhat fast */ if (len < 16) { while (len--) { adler += *buf++; sum2 += adler; } if (adler >= BASE) adler -= BASE; MOD28(sum2); /* only added so many BASE's */ return adler | (sum2 << 16); } /* do length NMAX blocks -- requires just one modulo operation */ while (len >= NMAX) { len -= NMAX; n = NMAX / 16; /* NMAX is divisible by 16 */ do { DO16(buf); /* 16 sums unrolled */ buf += 16; } while (--n); MOD(adler); MOD(sum2); } /* do remaining bytes (less than NMAX, still just one modulo) */ if (len) { /* avoid modulos if none remaining */ while (len >= 16) { len -= 16; DO16(buf); buf += 16; } while (len--) { adler += *buf++; sum2 += adler; } MOD(adler); MOD(sum2); } /* return recombined sums */ return adler | (sum2 << 16); } /* ========================================================================= */ uLong ZEXPORT adler32(adler, buf, len) uLong adler; const Bytef *buf; uInt len; { return adler32_z(adler, buf, len); } /* ========================================================================= */ local uLong adler32_combine_(adler1, adler2, len2) uLong adler1; uLong adler2; z_off64_t len2; { unsigned long sum1; unsigned long sum2; unsigned rem; /* for negative len, return invalid adler32 as a clue for debugging */ if (len2 < 0) return 0xffffffffUL; /* the derivation of this formula is left as an exercise for the reader */ MOD63(len2); /* assumes len2 >= 0 */ rem = (unsigned)len2; sum1 = adler1 & 0xffff; sum2 = rem * sum1; MOD(sum2); sum1 += (adler2 & 0xffff) + BASE - 1; sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; if (sum1 >= BASE) sum1 -= BASE; if (sum1 >= BASE) sum1 -= BASE; if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); if (sum2 >= BASE) sum2 -= BASE; return sum1 | (sum2 << 16); } /* ========================================================================= */ uLong ZEXPORT adler32_combine(adler1, adler2, len2) uLong adler1; uLong adler2; z_off_t len2; { return adler32_combine_(adler1, adler2, len2); } uLong ZEXPORT adler32_combine64(adler1, adler2, len2) uLong adler1; uLong adler2; z_off64_t len2; { return adler32_combine_(adler1, adler2, len2); } trusted-firmware-a-2.2/lib/zlib/crc32.c000066400000000000000000000333451355360272700177070ustar00rootroot00000000000000/* crc32.c -- compute the CRC-32 of a data stream * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Thanks to Rodney Brown for his contribution of faster * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing * tables for updating the shift register in one step with three exclusive-ors * instead of four steps with four exclusive-ors. This results in about a * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. */ /* @(#) $Id$ */ /* Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore protection on the static variables used to control the first-use generation of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should first call get_crc_table() to initialize the tables before allowing more than one thread to use crc32(). DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. */ #ifdef MAKECRCH # include # ifndef DYNAMIC_CRC_TABLE # define DYNAMIC_CRC_TABLE # endif /* !DYNAMIC_CRC_TABLE */ #endif /* MAKECRCH */ #include "zutil.h" /* for STDC and FAR definitions */ /* Definitions for doing the crc four data bytes at a time. */ #if !defined(NOBYFOUR) && defined(Z_U4) # define BYFOUR #endif #ifdef BYFOUR local unsigned long crc32_little OF((unsigned long, const unsigned char FAR *, z_size_t)); local unsigned long crc32_big OF((unsigned long, const unsigned char FAR *, z_size_t)); # define TBLS 8 #else # define TBLS 1 #endif /* BYFOUR */ /* Local functions for crc concatenation */ local unsigned long gf2_matrix_times OF((unsigned long *mat, unsigned long vec)); local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); #ifdef DYNAMIC_CRC_TABLE local volatile int crc_table_empty = 1; local z_crc_t FAR crc_table[TBLS][256]; local void make_crc_table OF((void)); #ifdef MAKECRCH local void write_table OF((FILE *, const z_crc_t FAR *)); #endif /* MAKECRCH */ /* Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. Polynomials over GF(2) are represented in binary, one bit per coefficient, with the lowest powers in the most significant bit. Then adding polynomials is just exclusive-or, and multiplying a polynomial by x is a right shift by one. If we call the above polynomial p, and represent a byte as the polynomial q, also with the lowest power in the most significant bit (so the byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, where a mod b means the remainder after dividing a by b. This calculation is done using the shift-register method of multiplying and taking the remainder. The register is initialized to zero, and for each incoming bit, x^32 is added mod p to the register if the bit is a one (where x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by x (which is shifting right by one and adding x^32 mod p if the bit shifted out is a one). We start with the highest power (least significant bit) of q and repeat for all eight bits of q. The first table is simply the CRC of all possible eight bit values. This is all the information needed to generate CRCs on data a byte at a time for all combinations of CRC register values and incoming bytes. The remaining tables allow for word-at-a-time CRC calculation for both big-endian and little- endian machines, where a word is four bytes. */ local void make_crc_table() { z_crc_t c; int n, k; z_crc_t poly; /* polynomial exclusive-or pattern */ /* terms of polynomial defining this crc (except x^32): */ static volatile int first = 1; /* flag to limit concurrent making */ static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; /* See if another task is already doing this (not thread-safe, but better than nothing -- significantly reduces duration of vulnerability in case the advice about DYNAMIC_CRC_TABLE is ignored) */ if (first) { first = 0; /* make exclusive-or pattern from polynomial (0xedb88320UL) */ poly = 0; for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) poly |= (z_crc_t)1 << (31 - p[n]); /* generate a crc for every 8-bit value */ for (n = 0; n < 256; n++) { c = (z_crc_t)n; for (k = 0; k < 8; k++) c = c & 1 ? poly ^ (c >> 1) : c >> 1; crc_table[0][n] = c; } #ifdef BYFOUR /* generate crc for each value followed by one, two, and three zeros, and then the byte reversal of those as well as the first table */ for (n = 0; n < 256; n++) { c = crc_table[0][n]; crc_table[4][n] = ZSWAP32(c); for (k = 1; k < 4; k++) { c = crc_table[0][c & 0xff] ^ (c >> 8); crc_table[k][n] = c; crc_table[k + 4][n] = ZSWAP32(c); } } #endif /* BYFOUR */ crc_table_empty = 0; } else { /* not first */ /* wait for the other guy to finish (not efficient, but rare) */ while (crc_table_empty) ; } #ifdef MAKECRCH /* write out CRC tables to crc32.h */ { FILE *out; out = fopen("crc32.h", "w"); if (out == NULL) return; fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); fprintf(out, "local const z_crc_t FAR "); fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); write_table(out, crc_table[0]); # ifdef BYFOUR fprintf(out, "#ifdef BYFOUR\n"); for (k = 1; k < 8; k++) { fprintf(out, " },\n {\n"); write_table(out, crc_table[k]); } fprintf(out, "#endif\n"); # endif /* BYFOUR */ fprintf(out, " }\n};\n"); fclose(out); } #endif /* MAKECRCH */ } #ifdef MAKECRCH local void write_table(out, table) FILE *out; const z_crc_t FAR *table; { int n; for (n = 0; n < 256; n++) fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", (unsigned long)(table[n]), n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); } #endif /* MAKECRCH */ #else /* !DYNAMIC_CRC_TABLE */ /* ======================================================================== * Tables of CRC-32s of all single-byte values, made by make_crc_table(). */ #include "crc32.h" #endif /* DYNAMIC_CRC_TABLE */ /* ========================================================================= * This function can be used by asm versions of crc32() */ const z_crc_t FAR * ZEXPORT get_crc_table() { #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ return (const z_crc_t FAR *)crc_table; } /* ========================================================================= */ #define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) #define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 /* ========================================================================= */ unsigned long ZEXPORT crc32_z(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; z_size_t len; { if (buf == Z_NULL) return 0UL; #ifdef DYNAMIC_CRC_TABLE if (crc_table_empty) make_crc_table(); #endif /* DYNAMIC_CRC_TABLE */ #ifdef BYFOUR if (sizeof(void *) == sizeof(ptrdiff_t)) { z_crc_t endian; endian = 1; if (*((unsigned char *)(&endian))) return crc32_little(crc, buf, len); else return crc32_big(crc, buf, len); } #endif /* BYFOUR */ crc = crc ^ 0xffffffffUL; while (len >= 8) { DO8; len -= 8; } if (len) do { DO1; } while (--len); return crc ^ 0xffffffffUL; } /* ========================================================================= */ unsigned long ZEXPORT crc32(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; uInt len; { return crc32_z(crc, buf, len); } #ifdef BYFOUR /* This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit integer pointer type. This violates the strict aliasing rule, where a compiler can assume, for optimization purposes, that two pointers to fundamentally different types won't ever point to the same memory. This can manifest as a problem only if one of the pointers is written to. This code only reads from those pointers. So long as this code remains isolated in this compilation unit, there won't be a problem. For this reason, this code should not be copied and pasted into a compilation unit in which other code writes to the buffer that is passed to these routines. */ /* ========================================================================= */ #define DOLIT4 c ^= *buf4++; \ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] #define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 /* ========================================================================= */ local unsigned long crc32_little(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; z_size_t len; { register z_crc_t c; register const z_crc_t FAR *buf4; c = (z_crc_t)crc; c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); len--; } buf4 = (const z_crc_t FAR *)(const void FAR *)buf; while (len >= 32) { DOLIT32; len -= 32; } while (len >= 4) { DOLIT4; len -= 4; } buf = (const unsigned char FAR *)buf4; if (len) do { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); } while (--len); c = ~c; return (unsigned long)c; } /* ========================================================================= */ #define DOBIG4 c ^= *buf4++; \ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] #define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 /* ========================================================================= */ local unsigned long crc32_big(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; z_size_t len; { register z_crc_t c; register const z_crc_t FAR *buf4; c = ZSWAP32((z_crc_t)crc); c = ~c; while (len && ((ptrdiff_t)buf & 3)) { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); len--; } buf4 = (const z_crc_t FAR *)(const void FAR *)buf; while (len >= 32) { DOBIG32; len -= 32; } while (len >= 4) { DOBIG4; len -= 4; } buf = (const unsigned char FAR *)buf4; if (len) do { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); } while (--len); c = ~c; return (unsigned long)(ZSWAP32(c)); } #endif /* BYFOUR */ #define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ /* ========================================================================= */ local unsigned long gf2_matrix_times(mat, vec) unsigned long *mat; unsigned long vec; { unsigned long sum; sum = 0; while (vec) { if (vec & 1) sum ^= *mat; vec >>= 1; mat++; } return sum; } /* ========================================================================= */ local void gf2_matrix_square(square, mat) unsigned long *square; unsigned long *mat; { int n; for (n = 0; n < GF2_DIM; n++) square[n] = gf2_matrix_times(mat, mat[n]); } /* ========================================================================= */ local uLong crc32_combine_(crc1, crc2, len2) uLong crc1; uLong crc2; z_off64_t len2; { int n; unsigned long row; unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ /* degenerate case (also disallow negative lengths) */ if (len2 <= 0) return crc1; /* put operator for one zero bit in odd */ odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ row = 1; for (n = 1; n < GF2_DIM; n++) { odd[n] = row; row <<= 1; } /* put operator for two zero bits in even */ gf2_matrix_square(even, odd); /* put operator for four zero bits in odd */ gf2_matrix_square(odd, even); /* apply len2 zeros to crc1 (first square will put the operator for one zero byte, eight zero bits, in even) */ do { /* apply zeros operator for this bit of len2 */ gf2_matrix_square(even, odd); if (len2 & 1) crc1 = gf2_matrix_times(even, crc1); len2 >>= 1; /* if no more bits set, then done */ if (len2 == 0) break; /* another iteration of the loop with odd and even swapped */ gf2_matrix_square(odd, even); if (len2 & 1) crc1 = gf2_matrix_times(odd, crc1); len2 >>= 1; /* if no more bits set, then done */ } while (len2 != 0); /* return combined crc */ crc1 ^= crc2; return crc1; } /* ========================================================================= */ uLong ZEXPORT crc32_combine(crc1, crc2, len2) uLong crc1; uLong crc2; z_off_t len2; { return crc32_combine_(crc1, crc2, len2); } uLong ZEXPORT crc32_combine64(crc1, crc2, len2) uLong crc1; uLong crc2; z_off64_t len2; { return crc32_combine_(crc1, crc2, len2); } trusted-firmware-a-2.2/lib/zlib/crc32.h000066400000000000000000000735421355360272700177170ustar00rootroot00000000000000/* crc32.h -- tables for rapid CRC calculation * Generated automatically by crc32.c */ local const z_crc_t FAR crc_table[TBLS][256] = { { 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, 0x2d02ef8dUL #ifdef BYFOUR }, { 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, 0x9324fd72UL }, { 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, 0xbe9834edUL }, { 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, 0xde0506f1UL }, { 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, 0x8def022dUL }, { 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, 0x72fd2493UL }, { 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, 0xed3498beUL }, { 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, 0xf10605deUL #endif } }; trusted-firmware-a-2.2/lib/zlib/inffast.c000066400000000000000000000312621355360272700204210ustar00rootroot00000000000000/* inffast.c -- fast decoding * Copyright (C) 1995-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" #ifdef ASMINF # pragma message("Assembler code may have bugs -- use at your own risk") #else /* Decode literal, length, and distance codes and write out the resulting literal and match bytes until either not enough input or output is available, an end-of-block is encountered, or a data error is encountered. When large enough input and output buffers are supplied to inflate(), for example, a 16K input buffer and a 64K output buffer, more than 95% of the inflate execution time is spent in this routine. Entry assumptions: state->mode == LEN strm->avail_in >= 6 strm->avail_out >= 258 start >= strm->avail_out state->bits < 8 On return, state->mode is one of: LEN -- ran out of enough output space or enough available input TYPE -- reached end of block code, inflate() to interpret next block BAD -- error in block data Notes: - The maximum input bits used by a length/distance pair is 15 bits for the length code, 5 bits for the length extra, 15 bits for the distance code, and 13 bits for the distance extra. This totals 48 bits, or six bytes. Therefore if strm->avail_in >= 6, then there is enough input to avoid checking for available input while decoding. - The maximum bytes that a single length/distance pair can output is 258 bytes, which is the maximum length that can be coded. inflate_fast() requires strm->avail_out >= 258 for each loop to avoid checking for output space. */ void ZLIB_INTERNAL inflate_fast(strm, start) z_streamp strm; unsigned start; /* inflate()'s starting value for strm->avail_out */ { struct inflate_state FAR *state; z_const unsigned char FAR *in; /* local strm->next_in */ z_const unsigned char FAR *last; /* have enough input while in < last */ unsigned char FAR *out; /* local strm->next_out */ unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ unsigned char FAR *end; /* while out < end, enough space available */ #ifdef INFLATE_STRICT unsigned dmax; /* maximum distance from zlib header */ #endif unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ unsigned long hold; /* local strm->hold */ unsigned bits; /* local strm->bits */ code const FAR *lcode; /* local strm->lencode */ code const FAR *dcode; /* local strm->distcode */ unsigned lmask; /* mask for first level of length codes */ unsigned dmask; /* mask for first level of distance codes */ code here; /* retrieved table entry */ unsigned op; /* code bits, operation, extra bits, or */ /* window position, window bytes to copy */ unsigned len; /* match length, unused bytes */ unsigned dist; /* match distance */ unsigned char FAR *from; /* where to copy match from */ /* copy state to local variables */ state = (struct inflate_state FAR *)strm->state; in = strm->next_in; last = in + (strm->avail_in - 5); out = strm->next_out; beg = out - (start - strm->avail_out); end = out + (strm->avail_out - 257); #ifdef INFLATE_STRICT dmax = state->dmax; #endif wsize = state->wsize; whave = state->whave; wnext = state->wnext; window = state->window; hold = state->hold; bits = state->bits; lcode = state->lencode; dcode = state->distcode; lmask = (1U << state->lenbits) - 1; dmask = (1U << state->distbits) - 1; /* decode literals and length/distances until end-of-block or not enough input data or output space */ do { if (bits < 15) { hold += (unsigned long)(*in++) << bits; bits += 8; hold += (unsigned long)(*in++) << bits; bits += 8; } here = lcode[hold & lmask]; dolen: op = (unsigned)(here.bits); hold >>= op; bits -= op; op = (unsigned)(here.op); if (op == 0) { /* literal */ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); *out++ = (unsigned char)(here.val); } else if (op & 16) { /* length base */ len = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (op) { if (bits < op) { hold += (unsigned long)(*in++) << bits; bits += 8; } len += (unsigned)hold & ((1U << op) - 1); hold >>= op; bits -= op; } Tracevv((stderr, "inflate: length %u\n", len)); if (bits < 15) { hold += (unsigned long)(*in++) << bits; bits += 8; hold += (unsigned long)(*in++) << bits; bits += 8; } here = dcode[hold & dmask]; dodist: op = (unsigned)(here.bits); hold >>= op; bits -= op; op = (unsigned)(here.op); if (op & 16) { /* distance base */ dist = (unsigned)(here.val); op &= 15; /* number of extra bits */ if (bits < op) { hold += (unsigned long)(*in++) << bits; bits += 8; if (bits < op) { hold += (unsigned long)(*in++) << bits; bits += 8; } } dist += (unsigned)hold & ((1U << op) - 1); #ifdef INFLATE_STRICT if (dist > dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif hold >>= op; bits -= op; Tracevv((stderr, "inflate: distance %u\n", dist)); op = (unsigned)(out - beg); /* max distance in output */ if (dist > op) { /* see if copy from window */ op = dist - op; /* distance back in window */ if (op > whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR if (len <= op - whave) { do { *out++ = 0; } while (--len); continue; } len -= op - whave; do { *out++ = 0; } while (--op > whave); if (op == 0) { from = out - dist; do { *out++ = *from++; } while (--len); continue; } #endif } from = window; if (wnext == 0) { /* very common case */ from += wsize - op; if (op < len) { /* some from window */ len -= op; do { *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } } else if (wnext < op) { /* wrap around window */ from += wsize + wnext - op; op -= wnext; if (op < len) { /* some from end of window */ len -= op; do { *out++ = *from++; } while (--op); from = window; if (wnext < len) { /* some from start of window */ op = wnext; len -= op; do { *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } } } else { /* contiguous in window */ from += wnext - op; if (op < len) { /* some from window */ len -= op; do { *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } } while (len > 2) { *out++ = *from++; *out++ = *from++; *out++ = *from++; len -= 3; } if (len) { *out++ = *from++; if (len > 1) *out++ = *from++; } } else { from = out - dist; /* copy direct from output */ do { /* minimum length is three */ *out++ = *from++; *out++ = *from++; *out++ = *from++; len -= 3; } while (len > 2); if (len) { *out++ = *from++; if (len > 1) *out++ = *from++; } } } else if ((op & 64) == 0) { /* 2nd level distance code */ here = dcode[here.val + (hold & ((1U << op) - 1))]; goto dodist; } else { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } } else if ((op & 64) == 0) { /* 2nd level length code */ here = lcode[here.val + (hold & ((1U << op) - 1))]; goto dolen; } else if (op & 32) { /* end-of-block */ Tracevv((stderr, "inflate: end of block\n")); state->mode = TYPE; break; } else { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } } while (in < last && out < end); /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ len = bits >> 3; in -= len; bits -= len << 3; hold &= (1U << bits) - 1; /* update state and return */ strm->next_in = in; strm->next_out = out; strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); strm->avail_out = (unsigned)(out < end ? 257 + (end - out) : 257 - (out - end)); state->hold = hold; state->bits = bits; return; } /* inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - Using bit fields for code structure - Different op definition to avoid & for extra bits (do & for table bits) - Three separate decoding do-loops for direct, window, and wnext == 0 - Special case for distance > 1 copies to do overlapped load and store copy - Explicit branch predictions (based on measured branch probabilities) - Deferring match copy and interspersed it with decoding subsequent codes - Swapping literal/length else - Swapping window/direct else - Larger unrolled copy loops (three is about right) - Moving len -= 3 statement into middle of loop */ #endif /* !ASMINF */ trusted-firmware-a-2.2/lib/zlib/inffast.h000066400000000000000000000006531355360272700204260ustar00rootroot00000000000000/* inffast.h -- header to use inffast.c * Copyright (C) 1995-2003, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); trusted-firmware-a-2.2/lib/zlib/inffixed.h000066400000000000000000000142741355360272700205740ustar00rootroot00000000000000 /* inffixed.h -- table for decoding fixed codes * Generated automatically by makefixed(). */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of this library and is subject to change. Applications should only use zlib.h. */ static const code lenfix[512] = { {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, {0,9,255} }; static const code distfix[32] = { {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, {22,5,193},{64,5,0} }; trusted-firmware-a-2.2/lib/zlib/inflate.c000066400000000000000000001530201355360272700204060ustar00rootroot00000000000000/* inflate.c -- zlib decompression * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* * Change history: * * 1.2.beta0 24 Nov 2002 * - First version -- complete rewrite of inflate to simplify code, avoid * creation of window when not needed, minimize use of window when it is * needed, make inffast.c even faster, implement gzip decoding, and to * improve code readability and style over the previous zlib inflate code * * 1.2.beta1 25 Nov 2002 * - Use pointers for available input and output checking in inffast.c * - Remove input and output counters in inffast.c * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 * - Remove unnecessary second byte pull from length extra in inffast.c * - Unroll direct copy to three copies per loop in inffast.c * * 1.2.beta2 4 Dec 2002 * - Change external routine names to reduce potential conflicts * - Correct filename to inffixed.h for fixed tables in inflate.c * - Make hbuf[] unsigned char to match parameter type in inflate.c * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) * to avoid negation problem on Alphas (64 bit) in inflate.c * * 1.2.beta3 22 Dec 2002 * - Add comments on state->bits assertion in inffast.c * - Add comments on op field in inftrees.h * - Fix bug in reuse of allocated window after inflateReset() * - Remove bit fields--back to byte structure for speed * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths * - Change post-increments to pre-increments in inflate_fast(), PPC biased? * - Add compile time option, POSTINC, to use post-increments instead (Intel?) * - Make MATCH copy in inflate() much faster for when inflate_fast() not used * - Use local copies of stream next and avail values, as well as local bit * buffer and bit count in inflate()--for speed when inflate_fast() not used * * 1.2.beta4 1 Jan 2003 * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings * - Move a comment on output buffer sizes from inffast.c to inflate.c * - Add comments in inffast.c to introduce the inflate_fast() routine * - Rearrange window copies in inflate_fast() for speed and simplification * - Unroll last copy for window match in inflate_fast() * - Use local copies of window variables in inflate_fast() for speed * - Pull out common wnext == 0 case for speed in inflate_fast() * - Make op and len in inflate_fast() unsigned for consistency * - Add FAR to lcode and dcode declarations in inflate_fast() * - Simplified bad distance check in inflate_fast() * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new * source file infback.c to provide a call-back interface to inflate for * programs like gzip and unzip -- uses window as output buffer to avoid * window copying * * 1.2.beta5 1 Jan 2003 * - Improved inflateBack() interface to allow the caller to provide initial * input in strm. * - Fixed stored blocks bug in inflateBack() * * 1.2.beta6 4 Jan 2003 * - Added comments in inffast.c on effectiveness of POSTINC * - Typecasting all around to reduce compiler warnings * - Changed loops from while (1) or do {} while (1) to for (;;), again to * make compilers happy * - Changed type of window in inflateBackInit() to unsigned char * * * 1.2.beta7 27 Jan 2003 * - Changed many types to unsigned or unsigned short to avoid warnings * - Added inflateCopy() function * * 1.2.0 9 Mar 2003 * - Changed inflateBack() interface to provide separate opaque descriptors * for the in() and out() functions * - Changed inflateBack() argument and in_func typedef to swap the length * and buffer address return values for the input function * - Check next_in and next_out for Z_NULL on entry to inflate() * * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. */ #include "zutil.h" #include "inftrees.h" #include "inflate.h" #include "inffast.h" #ifdef MAKEFIXED # ifndef BUILDFIXED # define BUILDFIXED # endif #endif /* function prototypes */ local int inflateStateCheck OF((z_streamp strm)); local void fixedtables OF((struct inflate_state FAR *state)); local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, unsigned copy)); #ifdef BUILDFIXED void makefixed OF((void)); #endif local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, unsigned len)); local int inflateStateCheck(strm) z_streamp strm; { struct inflate_state FAR *state; if (strm == Z_NULL || strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) return 1; state = (struct inflate_state FAR *)strm->state; if (state == Z_NULL || state->strm != strm || state->mode < HEAD || state->mode > SYNC) return 1; return 0; } int ZEXPORT inflateResetKeep(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; strm->total_in = strm->total_out = state->total = 0; strm->msg = Z_NULL; if (state->wrap) /* to support ill-conceived Java test suite */ strm->adler = state->wrap & 1; state->mode = HEAD; state->last = 0; state->havedict = 0; state->dmax = 32768U; state->head = Z_NULL; state->hold = 0; state->bits = 0; state->lencode = state->distcode = state->next = state->codes; state->sane = 1; state->back = -1; Tracev((stderr, "inflate: reset\n")); return Z_OK; } int ZEXPORT inflateReset(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; state->wsize = 0; state->whave = 0; state->wnext = 0; return inflateResetKeep(strm); } int ZEXPORT inflateReset2(strm, windowBits) z_streamp strm; int windowBits; { int wrap; struct inflate_state FAR *state; /* get the state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* extract wrap request from windowBits parameter */ if (windowBits < 0) { wrap = 0; windowBits = -windowBits; } else { wrap = (windowBits >> 4) + 5; #ifdef GUNZIP if (windowBits < 48) windowBits &= 15; #endif } /* set number of window bits, free window if different */ if (windowBits && (windowBits < 8 || windowBits > 15)) return Z_STREAM_ERROR; if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { ZFREE(strm, state->window); state->window = Z_NULL; } /* update state and reset the rest of it */ state->wrap = wrap; state->wbits = (unsigned)windowBits; return inflateReset(strm); } int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) z_streamp strm; int windowBits; const char *version; int stream_size; { int ret; struct inflate_state FAR *state; if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || stream_size != (int)(sizeof(z_stream))) return Z_VERSION_ERROR; if (strm == Z_NULL) return Z_STREAM_ERROR; strm->msg = Z_NULL; /* in case we return an error */ if (strm->zalloc == (alloc_func)0) { #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zalloc = zcalloc; strm->opaque = (voidpf)0; #endif } if (strm->zfree == (free_func)0) #ifdef Z_SOLO return Z_STREAM_ERROR; #else strm->zfree = zcfree; #endif state = (struct inflate_state FAR *) ZALLOC(strm, 1, sizeof(struct inflate_state)); if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; state->strm = strm; state->window = Z_NULL; state->mode = HEAD; /* to pass state test in inflateReset2() */ ret = inflateReset2(strm, windowBits); if (ret != Z_OK) { ZFREE(strm, state); strm->state = Z_NULL; } return ret; } int ZEXPORT inflateInit_(strm, version, stream_size) z_streamp strm; const char *version; int stream_size; { return inflateInit2_(strm, DEF_WBITS, version, stream_size); } int ZEXPORT inflatePrime(strm, bits, value) z_streamp strm; int bits; int value; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; state->bits = 0; return Z_OK; } if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; value &= (1L << bits) - 1; state->hold += (unsigned)value << state->bits; state->bits += (uInt)bits; return Z_OK; } /* Return state with length and distance decoding tables and index sizes set to fixed code decoding. Normally this returns fixed tables from inffixed.h. If BUILDFIXED is defined, then instead this routine builds the tables the first time it's called, and returns those tables the first time and thereafter. This reduces the size of the code by about 2K bytes, in exchange for a little execution time. However, BUILDFIXED should not be used for threaded applications, since the rewriting of the tables and virgin may not be thread-safe. */ local void fixedtables(state) struct inflate_state FAR *state; { #ifdef BUILDFIXED static int virgin = 1; static code *lenfix, *distfix; static code fixed[544]; /* build fixed huffman tables if first call (may not be thread safe) */ if (virgin) { unsigned sym, bits; static code *next; /* literal/length table */ sym = 0; while (sym < 144) state->lens[sym++] = 8; while (sym < 256) state->lens[sym++] = 9; while (sym < 280) state->lens[sym++] = 7; while (sym < 288) state->lens[sym++] = 8; next = fixed; lenfix = next; bits = 9; inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); /* distance table */ sym = 0; while (sym < 32) state->lens[sym++] = 5; distfix = next; bits = 5; inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); /* do this just once */ virgin = 0; } #else /* !BUILDFIXED */ # include "inffixed.h" #endif /* BUILDFIXED */ state->lencode = lenfix; state->lenbits = 9; state->distcode = distfix; state->distbits = 5; } #ifdef MAKEFIXED #include /* Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also defines BUILDFIXED, so the tables are built on the fly. makefixed() writes those tables to stdout, which would be piped to inffixed.h. A small program can simply call makefixed to do this: void makefixed(void); int main(void) { makefixed(); return 0; } Then that can be linked with zlib built with MAKEFIXED defined and run: a.out > inffixed.h */ void makefixed() { unsigned low, size; struct inflate_state state; fixedtables(&state); puts(" /* inffixed.h -- table for decoding fixed codes"); puts(" * Generated automatically by makefixed()."); puts(" */"); puts(""); puts(" /* WARNING: this file should *not* be used by applications."); puts(" It is part of the implementation of this library and is"); puts(" subject to change. Applications should only use zlib.h."); puts(" */"); puts(""); size = 1U << 9; printf(" static const code lenfix[%u] = {", size); low = 0; for (;;) { if ((low % 7) == 0) printf("\n "); printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, state.lencode[low].bits, state.lencode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); size = 1U << 5; printf("\n static const code distfix[%u] = {", size); low = 0; for (;;) { if ((low % 6) == 0) printf("\n "); printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, state.distcode[low].val); if (++low == size) break; putchar(','); } puts("\n };"); } #endif /* MAKEFIXED */ /* Update the window with the last wsize (normally 32K) bytes written before returning. If window does not exist yet, create it. This is only called when a window is already in use, or when output has been written during this inflate call, but the end of the deflate stream has not been reached yet. It is also called to create a window for dictionary data when a dictionary is loaded. Providing output buffers larger than 32K to inflate() should provide a speed advantage, since only the last 32K of output is copied to the sliding window upon return from inflate(), and since all distances after the first 32K of output will fall in the output data, making match copies simpler and faster. The advantage may be dependent on the size of the processor's data caches. */ local int updatewindow(strm, end, copy) z_streamp strm; const Bytef *end; unsigned copy; { struct inflate_state FAR *state; unsigned dist; state = (struct inflate_state FAR *)strm->state; /* if it hasn't been done already, allocate space for the window */ if (state->window == Z_NULL) { state->window = (unsigned char FAR *) ZALLOC(strm, 1U << state->wbits, sizeof(unsigned char)); if (state->window == Z_NULL) return 1; } /* if window not in use yet, initialize */ if (state->wsize == 0) { state->wsize = 1U << state->wbits; state->wnext = 0; state->whave = 0; } /* copy state->wsize or less output bytes into the circular window */ if (copy >= state->wsize) { zmemcpy(state->window, end - state->wsize, state->wsize); state->wnext = 0; state->whave = state->wsize; } else { dist = state->wsize - state->wnext; if (dist > copy) dist = copy; zmemcpy(state->window + state->wnext, end - copy, dist); copy -= dist; if (copy) { zmemcpy(state->window, end - copy, copy); state->wnext = copy; state->whave = state->wsize; } else { state->wnext += dist; if (state->wnext == state->wsize) state->wnext = 0; if (state->whave < state->wsize) state->whave += dist; } } return 0; } /* Macros for inflate(): */ /* check function to use adler32() for zlib or crc32() for gzip */ #ifdef GUNZIP # define UPDATE(check, buf, len) \ (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) #else # define UPDATE(check, buf, len) adler32(check, buf, len) #endif /* check macros for header crc */ #ifdef GUNZIP # define CRC2(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ check = crc32(check, hbuf, 2); \ } while (0) # define CRC4(check, word) \ do { \ hbuf[0] = (unsigned char)(word); \ hbuf[1] = (unsigned char)((word) >> 8); \ hbuf[2] = (unsigned char)((word) >> 16); \ hbuf[3] = (unsigned char)((word) >> 24); \ check = crc32(check, hbuf, 4); \ } while (0) #endif /* Load registers with state in inflate() for speed */ #define LOAD() \ do { \ put = strm->next_out; \ left = strm->avail_out; \ next = strm->next_in; \ have = strm->avail_in; \ hold = state->hold; \ bits = state->bits; \ } while (0) /* Restore state from registers in inflate() */ #define RESTORE() \ do { \ strm->next_out = put; \ strm->avail_out = left; \ strm->next_in = next; \ strm->avail_in = have; \ state->hold = hold; \ state->bits = bits; \ } while (0) /* Clear the input bit accumulator */ #define INITBITS() \ do { \ hold = 0; \ bits = 0; \ } while (0) /* Get a byte of input into the bit accumulator, or return from inflate() if there is no input available. */ #define PULLBYTE() \ do { \ if (have == 0) goto inf_leave; \ have--; \ hold += (unsigned long)(*next++) << bits; \ bits += 8; \ } while (0) /* Assure that there are at least n bits in the bit accumulator. If there is not enough available input to do that, then return from inflate(). */ #define NEEDBITS(n) \ do { \ while (bits < (unsigned)(n)) \ PULLBYTE(); \ } while (0) /* Return the low n bits of the bit accumulator (n < 16) */ #define BITS(n) \ ((unsigned)hold & ((1U << (n)) - 1)) /* Remove n bits from the bit accumulator */ #define DROPBITS(n) \ do { \ hold >>= (n); \ bits -= (unsigned)(n); \ } while (0) /* Remove zero to seven bits as needed to go to a byte boundary */ #define BYTEBITS() \ do { \ hold >>= bits & 7; \ bits -= bits & 7; \ } while (0) /* inflate() uses a state machine to process as much input data and generate as much output data as possible before returning. The state machine is structured roughly as follows: for (;;) switch (state) { ... case STATEn: if (not enough input data or output space to make progress) return; ... make progress ... state = STATEm; break; ... } so when inflate() is called again, the same case is attempted again, and if the appropriate resources are provided, the machine proceeds to the next state. The NEEDBITS() macro is usually the way the state evaluates whether it can proceed or should return. NEEDBITS() does the return if the requested bits are not available. The typical use of the BITS macros is: NEEDBITS(n); ... do something with BITS(n) ... DROPBITS(n); where NEEDBITS(n) either returns from inflate() if there isn't enough input left to load n bits into the accumulator, or it continues. BITS(n) gives the low n bits in the accumulator. When done, DROPBITS(n) drops the low n bits off the accumulator. INITBITS() clears the accumulator and sets the number of available bits to zero. BYTEBITS() discards just enough bits to put the accumulator on a byte boundary. After BYTEBITS() and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return if there is no input available. The decoding of variable length codes uses PULLBYTE() directly in order to pull just enough bytes to decode the next code, and no more. Some states loop until they get enough input, making sure that enough state information is maintained to continue the loop where it left off if NEEDBITS() returns in the loop. For example, want, need, and keep would all have to actually be part of the saved state in case NEEDBITS() returns: case STATEw: while (want < need) { NEEDBITS(n); keep[want++] = BITS(n); DROPBITS(n); } state = STATEx; case STATEx: As shown above, if the next state is also the next case, then the break is omitted. A state may also return if there is not enough output space available to complete that state. Those states are copying stored data, writing a literal byte, and copying a matching string. When returning, a "goto inf_leave" is used to update the total counters, update the check value, and determine whether any progress has been made during that inflate() call in order to return the proper return code. Progress is defined as a change in either strm->avail_in or strm->avail_out. When there is a window, goto inf_leave will update the window with the last output written. If a goto inf_leave occurs in the middle of decompression and there is no window currently, goto inf_leave will create one and copy output to the window for the next call of inflate(). In this implementation, the flush parameter of inflate() only affects the return code (per zlib.h). inflate() always writes as much as possible to strm->next_out, given the space available and the provided input--the effect documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers the allocation of and copying into a sliding window until necessary, which provides the effect documented in zlib.h for Z_FINISH when the entire input stream available. So the only thing the flush parameter actually does is: when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it will return Z_BUF_ERROR if it has not reached the end of the stream. */ int ZEXPORT inflate(strm, flush) z_streamp strm; int flush; { struct inflate_state FAR *state; z_const unsigned char FAR *next; /* next input */ unsigned char FAR *put; /* next output */ unsigned have, left; /* available input and output */ unsigned long hold; /* bit buffer */ unsigned bits; /* bits in bit buffer */ unsigned in, out; /* save starting available input and output */ unsigned copy; /* number of stored or match bytes to copy */ unsigned char FAR *from; /* where to copy match bytes from */ code here; /* current decoding table entry */ code last; /* parent table entry */ unsigned len; /* length to copy for repeats, bits to drop */ int ret; /* return code */ #ifdef GUNZIP unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ #endif static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; if (inflateStateCheck(strm) || strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ LOAD(); in = have; out = left; ret = Z_OK; for (;;) switch (state->mode) { case HEAD: if (state->wrap == 0) { state->mode = TYPEDO; break; } NEEDBITS(16); #ifdef GUNZIP if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ if (state->wbits == 0) state->wbits = 15; state->check = crc32(0L, Z_NULL, 0); CRC2(state->check, hold); INITBITS(); state->mode = FLAGS; break; } state->flags = 0; /* expect zlib header */ if (state->head != Z_NULL) state->head->done = -1; if (!(state->wrap & 1) || /* check if zlib header allowed */ #else if ( #endif ((BITS(8) << 8) + (hold >> 8)) % 31) { strm->msg = (char *)"incorrect header check"; state->mode = BAD; break; } if (BITS(4) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } DROPBITS(4); len = BITS(4) + 8; if (state->wbits == 0) state->wbits = len; if (len > 15 || len > state->wbits) { strm->msg = (char *)"invalid window size"; state->mode = BAD; break; } state->dmax = 1U << len; Tracev((stderr, "inflate: zlib header ok\n")); strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = hold & 0x200 ? DICTID : TYPE; INITBITS(); break; #ifdef GUNZIP case FLAGS: NEEDBITS(16); state->flags = (int)(hold); if ((state->flags & 0xff) != Z_DEFLATED) { strm->msg = (char *)"unknown compression method"; state->mode = BAD; break; } if (state->flags & 0xe000) { strm->msg = (char *)"unknown header flags set"; state->mode = BAD; break; } if (state->head != Z_NULL) state->head->text = (int)((hold >> 8) & 1); if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); state->mode = TIME; case TIME: NEEDBITS(32); if (state->head != Z_NULL) state->head->time = hold; if ((state->flags & 0x0200) && (state->wrap & 4)) CRC4(state->check, hold); INITBITS(); state->mode = OS; case OS: NEEDBITS(16); if (state->head != Z_NULL) { state->head->xflags = (int)(hold & 0xff); state->head->os = (int)(hold >> 8); } if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; case EXLEN: if (state->flags & 0x0400) { NEEDBITS(16); state->length = (unsigned)(hold); if (state->head != Z_NULL) state->head->extra_len = (unsigned)hold; if ((state->flags & 0x0200) && (state->wrap & 4)) CRC2(state->check, hold); INITBITS(); } else if (state->head != Z_NULL) state->head->extra = Z_NULL; state->mode = EXTRA; case EXTRA: if (state->flags & 0x0400) { copy = state->length; if (copy > have) copy = have; if (copy) { if (state->head != Z_NULL && state->head->extra != Z_NULL) { len = state->head->extra_len - state->length; zmemcpy(state->head->extra + len, next, len + copy > state->head->extra_max ? state->head->extra_max - len : copy); } if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; state->length -= copy; } if (state->length) goto inf_leave; } state->length = 0; state->mode = NAME; case NAME: if (state->flags & 0x0800) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->name != Z_NULL && state->length < state->head->name_max) state->head->name[state->length++] = (Bytef)len; } while (len && copy < have); if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->name = Z_NULL; state->length = 0; state->mode = COMMENT; case COMMENT: if (state->flags & 0x1000) { if (have == 0) goto inf_leave; copy = 0; do { len = (unsigned)(next[copy++]); if (state->head != Z_NULL && state->head->comment != Z_NULL && state->length < state->head->comm_max) state->head->comment[state->length++] = (Bytef)len; } while (len && copy < have); if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; if (len) goto inf_leave; } else if (state->head != Z_NULL) state->head->comment = Z_NULL; state->mode = HCRC; case HCRC: if (state->flags & 0x0200) { NEEDBITS(16); if ((state->wrap & 4) && hold != (state->check & 0xffff)) { strm->msg = (char *)"header crc mismatch"; state->mode = BAD; break; } INITBITS(); } if (state->head != Z_NULL) { state->head->hcrc = (int)((state->flags >> 9) & 1); state->head->done = 1; } strm->adler = state->check = crc32(0L, Z_NULL, 0); state->mode = TYPE; break; #endif case DICTID: NEEDBITS(32); strm->adler = state->check = ZSWAP32(hold); INITBITS(); state->mode = DICT; case DICT: if (state->havedict == 0) { RESTORE(); return Z_NEED_DICT; } strm->adler = state->check = adler32(0L, Z_NULL, 0); state->mode = TYPE; case TYPE: if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; case TYPEDO: if (state->last) { BYTEBITS(); state->mode = CHECK; break; } NEEDBITS(3); state->last = BITS(1); DROPBITS(1); switch (BITS(2)) { case 0: /* stored block */ Tracev((stderr, "inflate: stored block%s\n", state->last ? " (last)" : "")); state->mode = STORED; break; case 1: /* fixed block */ fixedtables(state); Tracev((stderr, "inflate: fixed codes block%s\n", state->last ? " (last)" : "")); state->mode = LEN_; /* decode codes */ if (flush == Z_TREES) { DROPBITS(2); goto inf_leave; } break; case 2: /* dynamic block */ Tracev((stderr, "inflate: dynamic codes block%s\n", state->last ? " (last)" : "")); state->mode = TABLE; break; case 3: strm->msg = (char *)"invalid block type"; state->mode = BAD; } DROPBITS(2); break; case STORED: BYTEBITS(); /* go to byte boundary */ NEEDBITS(32); if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { strm->msg = (char *)"invalid stored block lengths"; state->mode = BAD; break; } state->length = (unsigned)hold & 0xffff; Tracev((stderr, "inflate: stored length %u\n", state->length)); INITBITS(); state->mode = COPY_; if (flush == Z_TREES) goto inf_leave; case COPY_: state->mode = COPY; case COPY: copy = state->length; if (copy) { if (copy > have) copy = have; if (copy > left) copy = left; if (copy == 0) goto inf_leave; zmemcpy(put, next, copy); have -= copy; next += copy; left -= copy; put += copy; state->length -= copy; break; } Tracev((stderr, "inflate: stored end\n")); state->mode = TYPE; break; case TABLE: NEEDBITS(14); state->nlen = BITS(5) + 257; DROPBITS(5); state->ndist = BITS(5) + 1; DROPBITS(5); state->ncode = BITS(4) + 4; DROPBITS(4); #ifndef PKZIP_BUG_WORKAROUND if (state->nlen > 286 || state->ndist > 30) { strm->msg = (char *)"too many length or distance symbols"; state->mode = BAD; break; } #endif Tracev((stderr, "inflate: table sizes ok\n")); state->have = 0; state->mode = LENLENS; case LENLENS: while (state->have < state->ncode) { NEEDBITS(3); state->lens[order[state->have++]] = (unsigned short)BITS(3); DROPBITS(3); } while (state->have < 19) state->lens[order[state->have++]] = 0; state->next = state->codes; state->lencode = (const code FAR *)(state->next); state->lenbits = 7; ret = inflate_table(CODES, state->lens, 19, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid code lengths set"; state->mode = BAD; break; } Tracev((stderr, "inflate: code lengths ok\n")); state->have = 0; state->mode = CODELENS; case CODELENS: while (state->have < state->nlen + state->ndist) { for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.val < 16) { DROPBITS(here.bits); state->lens[state->have++] = here.val; } else { if (here.val == 16) { NEEDBITS(here.bits + 2); DROPBITS(here.bits); if (state->have == 0) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } len = state->lens[state->have - 1]; copy = 3 + BITS(2); DROPBITS(2); } else if (here.val == 17) { NEEDBITS(here.bits + 3); DROPBITS(here.bits); len = 0; copy = 3 + BITS(3); DROPBITS(3); } else { NEEDBITS(here.bits + 7); DROPBITS(here.bits); len = 0; copy = 11 + BITS(7); DROPBITS(7); } if (state->have + copy > state->nlen + state->ndist) { strm->msg = (char *)"invalid bit length repeat"; state->mode = BAD; break; } while (copy--) state->lens[state->have++] = (unsigned short)len; } } /* handle error breaks in while */ if (state->mode == BAD) break; /* check for end-of-block code (better have one) */ if (state->lens[256] == 0) { strm->msg = (char *)"invalid code -- missing end-of-block"; state->mode = BAD; break; } /* build code tables -- note: do not change the lenbits or distbits values here (9 and 6) without reading the comments in inftrees.h concerning the ENOUGH constants, which depend on those values */ state->next = state->codes; state->lencode = (const code FAR *)(state->next); state->lenbits = 9; ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), &(state->lenbits), state->work); if (ret) { strm->msg = (char *)"invalid literal/lengths set"; state->mode = BAD; break; } state->distcode = (const code FAR *)(state->next); state->distbits = 6; ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, &(state->next), &(state->distbits), state->work); if (ret) { strm->msg = (char *)"invalid distances set"; state->mode = BAD; break; } Tracev((stderr, "inflate: codes ok\n")); state->mode = LEN_; if (flush == Z_TREES) goto inf_leave; case LEN_: state->mode = LEN; case LEN: if (have >= 6 && left >= 258) { RESTORE(); inflate_fast(strm, out); LOAD(); if (state->mode == TYPE) state->back = -1; break; } state->back = 0; for (;;) { here = state->lencode[BITS(state->lenbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if (here.op && (here.op & 0xf0) == 0) { last = here; for (;;) { here = state->lencode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; state->length = (unsigned)here.val; if ((int)(here.op) == 0) { Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? "inflate: literal '%c'\n" : "inflate: literal 0x%02x\n", here.val)); state->mode = LIT; break; } if (here.op & 32) { Tracevv((stderr, "inflate: end of block\n")); state->back = -1; state->mode = TYPE; break; } if (here.op & 64) { strm->msg = (char *)"invalid literal/length code"; state->mode = BAD; break; } state->extra = (unsigned)(here.op) & 15; state->mode = LENEXT; case LENEXT: if (state->extra) { NEEDBITS(state->extra); state->length += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } Tracevv((stderr, "inflate: length %u\n", state->length)); state->was = state->length; state->mode = DIST; case DIST: for (;;) { here = state->distcode[BITS(state->distbits)]; if ((unsigned)(here.bits) <= bits) break; PULLBYTE(); } if ((here.op & 0xf0) == 0) { last = here; for (;;) { here = state->distcode[last.val + (BITS(last.bits + last.op) >> last.bits)]; if ((unsigned)(last.bits + here.bits) <= bits) break; PULLBYTE(); } DROPBITS(last.bits); state->back += last.bits; } DROPBITS(here.bits); state->back += here.bits; if (here.op & 64) { strm->msg = (char *)"invalid distance code"; state->mode = BAD; break; } state->offset = (unsigned)here.val; state->extra = (unsigned)(here.op) & 15; state->mode = DISTEXT; case DISTEXT: if (state->extra) { NEEDBITS(state->extra); state->offset += BITS(state->extra); DROPBITS(state->extra); state->back += state->extra; } #ifdef INFLATE_STRICT if (state->offset > state->dmax) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #endif Tracevv((stderr, "inflate: distance %u\n", state->offset)); state->mode = MATCH; case MATCH: if (left == 0) goto inf_leave; copy = out - left; if (state->offset > copy) { /* copy from window */ copy = state->offset - copy; if (copy > state->whave) { if (state->sane) { strm->msg = (char *)"invalid distance too far back"; state->mode = BAD; break; } #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR Trace((stderr, "inflate.c too far\n")); copy -= state->whave; if (copy > state->length) copy = state->length; if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = 0; } while (--copy); if (state->length == 0) state->mode = LEN; break; #endif } if (copy > state->wnext) { copy -= state->wnext; from = state->window + (state->wsize - copy); } else from = state->window + (state->wnext - copy); if (copy > state->length) copy = state->length; } else { /* copy from output */ from = put - state->offset; copy = state->length; } if (copy > left) copy = left; left -= copy; state->length -= copy; do { *put++ = *from++; } while (--copy); if (state->length == 0) state->mode = LEN; break; case LIT: if (left == 0) goto inf_leave; *put++ = (unsigned char)(state->length); left--; state->mode = LEN; break; case CHECK: if (state->wrap) { NEEDBITS(32); out -= left; strm->total_out += out; state->total += out; if ((state->wrap & 4) && out) strm->adler = state->check = UPDATE(state->check, put - out, out); out = left; if ((state->wrap & 4) && ( #ifdef GUNZIP state->flags ? hold : #endif ZSWAP32(hold)) != state->check) { strm->msg = (char *)"incorrect data check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: check matches trailer\n")); } #ifdef GUNZIP state->mode = LENGTH; case LENGTH: if (state->wrap && state->flags) { NEEDBITS(32); if (hold != (state->total & 0xffffffffUL)) { strm->msg = (char *)"incorrect length check"; state->mode = BAD; break; } INITBITS(); Tracev((stderr, "inflate: length matches trailer\n")); } #endif state->mode = DONE; case DONE: ret = Z_STREAM_END; goto inf_leave; case BAD: ret = Z_DATA_ERROR; goto inf_leave; case MEM: return Z_MEM_ERROR; case SYNC: default: return Z_STREAM_ERROR; } /* Return from inflate(), updating the total counts and the check value. If there was no progress during the inflate() call, return a buffer error. Call updatewindow() to create and/or update the window state. Note: a memory error from inflate() is non-recoverable. */ inf_leave: RESTORE(); if (state->wsize || (out != strm->avail_out && state->mode < BAD && (state->mode < CHECK || flush != Z_FINISH))) if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { state->mode = MEM; return Z_MEM_ERROR; } in -= strm->avail_in; out -= strm->avail_out; strm->total_in += in; strm->total_out += out; state->total += out; if ((state->wrap & 4) && out) strm->adler = state->check = UPDATE(state->check, strm->next_out - out, out); strm->data_type = (int)state->bits + (state->last ? 64 : 0) + (state->mode == TYPE ? 128 : 0) + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) ret = Z_BUF_ERROR; return ret; } int ZEXPORT inflateEnd(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->window != Z_NULL) ZFREE(strm, state->window); ZFREE(strm, strm->state); strm->state = Z_NULL; Tracev((stderr, "inflate: end\n")); return Z_OK; } int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) z_streamp strm; Bytef *dictionary; uInt *dictLength; { struct inflate_state FAR *state; /* check state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* copy dictionary */ if (state->whave && dictionary != Z_NULL) { zmemcpy(dictionary, state->window + state->wnext, state->whave - state->wnext); zmemcpy(dictionary + state->whave - state->wnext, state->window, state->wnext); } if (dictLength != Z_NULL) *dictLength = state->whave; return Z_OK; } int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) z_streamp strm; const Bytef *dictionary; uInt dictLength; { struct inflate_state FAR *state; unsigned long dictid; int ret; /* check state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->wrap != 0 && state->mode != DICT) return Z_STREAM_ERROR; /* check for correct dictionary identifier */ if (state->mode == DICT) { dictid = adler32(0L, Z_NULL, 0); dictid = adler32(dictid, dictionary, dictLength); if (dictid != state->check) return Z_DATA_ERROR; } /* copy dictionary to window using updatewindow(), which will amend the existing dictionary if appropriate */ ret = updatewindow(strm, dictionary + dictLength, dictLength); if (ret) { state->mode = MEM; return Z_MEM_ERROR; } state->havedict = 1; Tracev((stderr, "inflate: dictionary set\n")); return Z_OK; } int ZEXPORT inflateGetHeader(strm, head) z_streamp strm; gz_headerp head; { struct inflate_state FAR *state; /* check state */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; /* save header structure */ state->head = head; head->done = 0; return Z_OK; } /* Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found or when out of input. When called, *have is the number of pattern bytes found in order so far, in 0..3. On return *have is updated to the new state. If on return *have equals four, then the pattern was found and the return value is how many bytes were read including the last byte of the pattern. If *have is less than four, then the pattern has not been found yet and the return value is len. In the latter case, syncsearch() can be called again with more data and the *have state. *have is initialized to zero for the first call. */ local unsigned syncsearch(have, buf, len) unsigned FAR *have; const unsigned char FAR *buf; unsigned len; { unsigned got; unsigned next; got = *have; next = 0; while (next < len && got < 4) { if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) got++; else if (buf[next]) got = 0; else got = 4 - got; next++; } *have = got; return next; } int ZEXPORT inflateSync(strm) z_streamp strm; { unsigned len; /* number of bytes to look at or looked at */ unsigned long in, out; /* temporary to save total_in and total_out */ unsigned char buf[4]; /* to restore bit buffer to byte string */ struct inflate_state FAR *state; /* check parameters */ if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; /* if first time, start search in bit buffer */ if (state->mode != SYNC) { state->mode = SYNC; state->hold <<= state->bits & 7; state->bits -= state->bits & 7; len = 0; while (state->bits >= 8) { buf[len++] = (unsigned char)(state->hold); state->hold >>= 8; state->bits -= 8; } state->have = 0; syncsearch(&(state->have), buf, len); } /* search available input */ len = syncsearch(&(state->have), strm->next_in, strm->avail_in); strm->avail_in -= len; strm->next_in += len; strm->total_in += len; /* return no joy or set up to restart inflate() on a new block */ if (state->have != 4) return Z_DATA_ERROR; in = strm->total_in; out = strm->total_out; inflateReset(strm); strm->total_in = in; strm->total_out = out; state->mode = TYPE; return Z_OK; } /* Returns true if inflate is currently at the end of a block generated by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored block. When decompressing, PPP checks that at the end of input packet, inflate is waiting for these length bytes. */ int ZEXPORT inflateSyncPoint(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; return state->mode == STORED && state->bits == 0; } int ZEXPORT inflateCopy(dest, source) z_streamp dest; z_streamp source; { struct inflate_state FAR *state; struct inflate_state FAR *copy; unsigned char FAR *window; unsigned wsize; /* check input */ if (inflateStateCheck(source) || dest == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)source->state; /* allocate space */ copy = (struct inflate_state FAR *) ZALLOC(source, 1, sizeof(struct inflate_state)); if (copy == Z_NULL) return Z_MEM_ERROR; window = Z_NULL; if (state->window != Z_NULL) { window = (unsigned char FAR *) ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); if (window == Z_NULL) { ZFREE(source, copy); return Z_MEM_ERROR; } } /* copy state */ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); copy->strm = dest; if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { copy->lencode = copy->codes + (state->lencode - state->codes); copy->distcode = copy->codes + (state->distcode - state->codes); } copy->next = copy->codes + (state->next - state->codes); if (window != Z_NULL) { wsize = 1U << state->wbits; zmemcpy(window, state->window, wsize); } copy->window = window; dest->state = (struct internal_state FAR *)copy; return Z_OK; } int ZEXPORT inflateUndermine(strm, subvert) z_streamp strm; int subvert; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR state->sane = !subvert; return Z_OK; #else (void)subvert; state->sane = 1; return Z_DATA_ERROR; #endif } int ZEXPORT inflateValidate(strm, check) z_streamp strm; int check; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (check) state->wrap |= 4; else state->wrap &= ~4; return Z_OK; } long ZEXPORT inflateMark(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return -(1L << 16); state = (struct inflate_state FAR *)strm->state; return (long)(((unsigned long)((long)state->back)) << 16) + (state->mode == COPY ? state->length : (state->mode == MATCH ? state->was - state->length : 0)); } unsigned long ZEXPORT inflateCodesUsed(strm) z_streamp strm; { struct inflate_state FAR *state; if (inflateStateCheck(strm)) return (unsigned long)-1; state = (struct inflate_state FAR *)strm->state; return (unsigned long)(state->next - state->codes); } trusted-firmware-a-2.2/lib/zlib/inflate.h000066400000000000000000000147321355360272700204210ustar00rootroot00000000000000/* inflate.h -- internal inflate state definition * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* define NO_GZIP when compiling if you want to disable gzip header and trailer decoding by inflate(). NO_GZIP would be used to avoid linking in the crc code when it is not needed. For shared libraries, gzip decoding should be left enabled. */ #ifndef NO_GZIP # define GUNZIP #endif /* Possible inflate modes between inflate() calls */ typedef enum { HEAD = 16180, /* i: waiting for magic header */ FLAGS, /* i: waiting for method and flags (gzip) */ TIME, /* i: waiting for modification time (gzip) */ OS, /* i: waiting for extra flags and operating system (gzip) */ EXLEN, /* i: waiting for extra length (gzip) */ EXTRA, /* i: waiting for extra bytes (gzip) */ NAME, /* i: waiting for end of file name (gzip) */ COMMENT, /* i: waiting for end of comment (gzip) */ HCRC, /* i: waiting for header crc (gzip) */ DICTID, /* i: waiting for dictionary check value */ DICT, /* waiting for inflateSetDictionary() call */ TYPE, /* i: waiting for type bits, including last-flag bit */ TYPEDO, /* i: same, but skip check to exit inflate on new block */ STORED, /* i: waiting for stored size (length and complement) */ COPY_, /* i/o: same as COPY below, but only first time in */ COPY, /* i/o: waiting for input or output to copy stored block */ TABLE, /* i: waiting for dynamic block table lengths */ LENLENS, /* i: waiting for code length code lengths */ CODELENS, /* i: waiting for length/lit and distance code lengths */ LEN_, /* i: same as LEN below, but only first time in */ LEN, /* i: waiting for length/lit/eob code */ LENEXT, /* i: waiting for length extra bits */ DIST, /* i: waiting for distance code */ DISTEXT, /* i: waiting for distance extra bits */ MATCH, /* o: waiting for output space to copy string */ LIT, /* o: waiting for output space to write literal */ CHECK, /* i: waiting for 32-bit check value */ LENGTH, /* i: waiting for 32-bit length (gzip) */ DONE, /* finished check, done -- remain here until reset */ BAD, /* got a data error -- remain here until reset */ MEM, /* got an inflate() memory error -- remain here until reset */ SYNC /* looking for synchronization bytes to restart inflate() */ } inflate_mode; /* State transitions between above modes - (most modes can go to BAD or MEM on error -- not shown for clarity) Process header: HEAD -> (gzip) or (zlib) or (raw) (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> HCRC -> TYPE (zlib) -> DICTID or TYPE DICTID -> DICT -> TYPE (raw) -> TYPEDO Read deflate blocks: TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK STORED -> COPY_ -> COPY -> TYPE TABLE -> LENLENS -> CODELENS -> LEN_ LEN_ -> LEN Read deflate codes in fixed or dynamic block: LEN -> LENEXT or LIT or TYPE LENEXT -> DIST -> DISTEXT -> MATCH -> LEN LIT -> LEN Process trailer: CHECK -> LENGTH -> DONE */ /* State maintained between inflate() calls -- approximately 7K bytes, not including the allocated sliding window, which is up to 32K bytes. */ struct inflate_state { z_streamp strm; /* pointer back to this zlib stream */ inflate_mode mode; /* current inflate mode */ int last; /* true if processing last block */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip, bit 2 true to validate check value */ int havedict; /* true if dictionary provided */ int flags; /* gzip header method and flags (0 if zlib) */ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ unsigned long check; /* protected copy of check value */ unsigned long total; /* protected copy of output count */ gz_headerp head; /* where to save gzip header information */ /* sliding window */ unsigned wbits; /* log base 2 of requested window size */ unsigned wsize; /* window size or zero if not using window */ unsigned whave; /* valid bytes in the window */ unsigned wnext; /* window write index */ unsigned char FAR *window; /* allocated sliding window, if needed */ /* bit accumulator */ unsigned long hold; /* input bit accumulator */ unsigned bits; /* number of bits in "in" */ /* for string and stored block copying */ unsigned length; /* literal or length of data to copy */ unsigned offset; /* distance back to copy string from */ /* for table and code decoding */ unsigned extra; /* extra bits needed */ /* fixed and dynamic code tables */ code const FAR *lencode; /* starting table for length/literal codes */ code const FAR *distcode; /* starting table for distance codes */ unsigned lenbits; /* index bits for lencode */ unsigned distbits; /* index bits for distcode */ /* dynamic table building */ unsigned ncode; /* number of code length code lengths */ unsigned nlen; /* number of length code lengths */ unsigned ndist; /* number of distance code lengths */ unsigned have; /* number of code lengths in lens[] */ code FAR *next; /* next available space in codes[] */ unsigned short lens[320]; /* temporary storage for code lengths */ unsigned short work[288]; /* work area for code table building */ code codes[ENOUGH]; /* space for code tables */ int sane; /* if false, allow invalid distance too far */ int back; /* bits back of last unprocessed length/lit */ unsigned was; /* initial length of match */ }; trusted-firmware-a-2.2/lib/zlib/inftrees.c000066400000000000000000000313071355360272700206060ustar00rootroot00000000000000/* inftrees.c -- generate Huffman trees for efficient decoding * Copyright (C) 1995-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ #include "zutil.h" #include "inftrees.h" #define MAXBITS 15 const char inflate_copyright[] = " inflate 1.2.11 Copyright 1995-2017 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. */ /* Build a set of tables to decode the provided canonical Huffman code. The code lengths are lens[0..codes-1]. The result starts at *table, whose indices are 0..2^bits-1. work is a writable array of at least lens shorts, which is used as a work area. type is the type of code to be generated, CODES, LENS, or DISTS. On return, zero is success, -1 is an invalid code, and +1 means that ENOUGH isn't enough. table on return points to the next available entry's address. bits is the requested root table index bits, and on return it is the actual root table index bits. It will differ if the request is greater than the longest code or if it is less than the shortest code. */ int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) codetype type; unsigned short FAR *lens; unsigned codes; code FAR * FAR *table; unsigned FAR *bits; unsigned short FAR *work; { unsigned len; /* a code's length in bits */ unsigned sym; /* index of code symbols */ unsigned min, max; /* minimum and maximum code lengths */ unsigned root; /* number of index bits for root table */ unsigned curr; /* number of index bits for current table */ unsigned drop; /* code bits to drop for sub-table */ int left; /* number of prefix codes available */ unsigned used; /* code entries in table used */ unsigned huff; /* Huffman code */ unsigned incr; /* for incrementing code, index */ unsigned fill; /* index for replicating entries */ unsigned low; /* low bits for current root entry */ unsigned mask; /* mask for low root bits */ code here; /* table entry for duplication */ code FAR *next; /* next available space in table */ const unsigned short FAR *base; /* base value table to use */ const unsigned short FAR *extra; /* extra bits table to use */ unsigned match; /* use base and extra for symbol >= match */ unsigned short count[MAXBITS+1]; /* number of codes of each length */ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ static const unsigned short lbase[31] = { /* Length codes 257..285 base */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 64, 64}; /* Process a set of code lengths to create a canonical Huffman code. The code lengths are lens[0..codes-1]. Each length corresponds to the symbols 0..codes-1. The Huffman code is generated by first sorting the symbols by length from short to long, and retaining the symbol order for codes with equal lengths. Then the code starts with all zero bits for the first code of the shortest length, and the codes are integer increments for the same length, and zeros are appended as the length increases. For the deflate format, these bits are stored backwards from their more natural integer increment ordering, and so when the decoding tables are built in the large loop below, the integer codes are incremented backwards. This routine assumes, but does not check, that all of the entries in lens[] are in the range 0..MAXBITS. The caller must assure this. 1..MAXBITS is interpreted as that code length. zero means that that symbol does not occur in this code. The codes are sorted by computing a count of codes for each length, creating from that a table of starting indices for each length in the sorted table, and then entering the symbols in order in the sorted table. The sorted table is work[], with that space being provided by the caller. The length counts are used for other purposes as well, i.e. finding the minimum and maximum length codes, determining if there are any codes at all, checking for a valid set of lengths, and looking ahead at length counts to determine sub-table sizes when building the decoding tables. */ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ for (len = 0; len <= MAXBITS; len++) count[len] = 0; for (sym = 0; sym < codes; sym++) count[lens[sym]]++; /* bound code lengths, force root to be within code lengths */ root = *bits; for (max = MAXBITS; max >= 1; max--) if (count[max] != 0) break; if (root > max) root = max; if (max == 0) { /* no symbols to code at all */ here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)1; here.val = (unsigned short)0; *(*table)++ = here; /* make a table to force an error */ *(*table)++ = here; *bits = 1; return 0; /* no symbols, but wait for decoding to report error */ } for (min = 1; min < max; min++) if (count[min] != 0) break; if (root < min) root = min; /* check for an over-subscribed or incomplete set of lengths */ left = 1; for (len = 1; len <= MAXBITS; len++) { left <<= 1; left -= count[len]; if (left < 0) return -1; /* over-subscribed */ } if (left > 0 && (type == CODES || max != 1)) return -1; /* incomplete set */ /* generate offsets into symbol table for each length for sorting */ offs[1] = 0; for (len = 1; len < MAXBITS; len++) offs[len + 1] = offs[len] + count[len]; /* sort symbols by length, by symbol order within each length */ for (sym = 0; sym < codes; sym++) if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; /* Create and fill in decoding tables. In this loop, the table being filled is at next and has curr index bits. The code being used is huff with length len. That code is converted to an index by dropping drop bits off of the bottom. For codes where len is less than drop + curr, those top drop + curr - len bits are incremented through all values to fill the table with replicated entries. root is the number of index bits for the root table. When len exceeds root, sub-tables are created pointed to by the root entry with an index of the low root bits of huff. This is saved in low to check for when a new sub-table should be started. drop is zero when the root table is being filled, and drop is root when sub-tables are being filled. When a new sub-table is needed, it is necessary to look ahead in the code lengths to determine what size sub-table is needed. The length counts are used for this, and so count[] is decremented as codes are entered in the tables. used keeps track of how many table entries have been allocated from the provided *table space. It is checked for LENS and DIST tables against the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in the initial root table size constants. See the comments in inftrees.h for more information. sym increments through all symbols, and the loop terminates when all codes of length max, i.e. all codes, have been processed. This routine permits incomplete codes, so another loop after this one fills in the rest of the decoding tables with invalid code markers. */ /* set up for code type */ switch (type) { case CODES: base = extra = work; /* dummy value--not used */ match = 20; break; case LENS: base = lbase; extra = lext; match = 257; break; default: /* DISTS */ base = dbase; extra = dext; match = 0; } /* initialize state for loop */ huff = 0; /* starting code */ sym = 0; /* starting code symbol */ len = min; /* starting code length */ next = *table; /* current table to fill in */ curr = root; /* current table index bits */ drop = 0; /* current bits to drop from code for index */ low = (unsigned)(-1); /* trigger new sub-table when len > root */ used = 1U << root; /* use root table entries */ mask = used - 1; /* mask for comparing low */ /* check available table space */ if ((type == LENS && used > ENOUGH_LENS) || (type == DISTS && used > ENOUGH_DISTS)) return 1; /* process all codes and make table entries */ for (;;) { /* create table entry */ here.bits = (unsigned char)(len - drop); if (work[sym] + 1U < match) { here.op = (unsigned char)0; here.val = work[sym]; } else if (work[sym] >= match) { here.op = (unsigned char)(extra[work[sym] - match]); here.val = base[work[sym] - match]; } else { here.op = (unsigned char)(32 + 64); /* end of block */ here.val = 0; } /* replicate for those indices with low len bits equal to huff */ incr = 1U << (len - drop); fill = 1U << curr; min = fill; /* save offset to next table */ do { fill -= incr; next[(huff >> drop) + fill] = here; } while (fill != 0); /* backwards increment the len-bit code huff */ incr = 1U << (len - 1); while (huff & incr) incr >>= 1; if (incr != 0) { huff &= incr - 1; huff += incr; } else huff = 0; /* go to next symbol, update count, len */ sym++; if (--(count[len]) == 0) { if (len == max) break; len = lens[work[sym]]; } /* create new sub-table if needed */ if (len > root && (huff & mask) != low) { /* if first time, transition to sub-tables */ if (drop == 0) drop = root; /* increment past last table */ next += min; /* here min is 1 << curr */ /* determine length of next table */ curr = len - drop; left = (int)(1 << curr); while (curr + drop < max) { left -= count[curr + drop]; if (left <= 0) break; curr++; left <<= 1; } /* check for enough space */ used += 1U << curr; if ((type == LENS && used > ENOUGH_LENS) || (type == DISTS && used > ENOUGH_DISTS)) return 1; /* point entry in root table to sub-table */ low = huff & mask; (*table)[low].op = (unsigned char)curr; (*table)[low].bits = (unsigned char)root; (*table)[low].val = (unsigned short)(next - *table); } } /* fill in remaining table entry if code is incomplete (guaranteed to have at most one remaining entry, since if the code is incomplete, the maximum code length that was allowed to get this far is one bit) */ if (huff != 0) { here.op = (unsigned char)64; /* invalid code marker */ here.bits = (unsigned char)(len - drop); here.val = (unsigned short)0; next[huff] = here; } /* set return parameters */ *table += used; *bits = root; return 0; } trusted-firmware-a-2.2/lib/zlib/inftrees.h000066400000000000000000000055601355360272700206150ustar00rootroot00000000000000/* inftrees.h -- header to use inftrees.c * Copyright (C) 1995-2005, 2010 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* Structure for decoding tables. Each entry provides either the information needed to do the operation requested by the code that indexed that table entry, or it provides a pointer to another table that indexes more bits of the code. op indicates whether the entry is a pointer to another table, a literal, a length or distance, an end-of-block, or an invalid code. For a table pointer, the low four bits of op is the number of index bits of that table. For a length or distance, the low four bits of op is the number of extra bits to get after the code. bits is the number of bits in this code or part of the code to drop off of the bit buffer. val is the actual byte to output in the case of a literal, the base length or distance, or the offset from the current table to the next table. Each entry is four bytes. */ typedef struct { unsigned char op; /* operation, extra bits, table bits */ unsigned char bits; /* bits in this part of the code */ unsigned short val; /* offset in table or code value */ } code; /* op values as set by inflate_table(): 00000000 - literal 0000tttt - table link, tttt != 0 is the number of table index bits 0001eeee - length or distance, eeee is the number of extra bits 01100000 - end of block 01000000 - invalid code */ /* Maximum size of the dynamic table. The maximum number of code structures is 1444, which is the sum of 852 for literal/length codes and 592 for distance codes. These values were found by exhaustive searches using the program examples/enough.c found in the zlib distribtution. The arguments to that program are the number of symbols, the initial root table size, and the maximum bit length of a code. "enough 286 9 15" for literal/length codes returns returns 852, and "enough 30 6 15" for distance codes returns 592. The initial root table size (9 or 6) is found in the fifth argument of the inflate_table() calls in inflate.c and infback.c. If the root table size is changed, then these maximum sizes would be need to be recalculated and updated. */ #define ENOUGH_LENS 852 #define ENOUGH_DISTS 592 #define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) /* Type of code to build for inflate_table() */ typedef enum { CODES, LENS, DISTS } codetype; int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, unsigned codes, code FAR * FAR *table, unsigned FAR *bits, unsigned short FAR *work)); trusted-firmware-a-2.2/lib/zlib/tf_gunzip.c000066400000000000000000000044121355360272700207710ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "zutil.h" /* * memory allocated by malloc() is supposed to be aligned for any built-in type */ #define ZALLOC_ALIGNMENT sizeof(void *) static uintptr_t zalloc_start; static uintptr_t zalloc_end; static uintptr_t zalloc_current; static void * ZLIB_INTERNAL zcalloc(void *opaque, unsigned int items, unsigned int size) { uintptr_t p, p_end; size *= items; p = round_up(zalloc_current, ZALLOC_ALIGNMENT); p_end = p + size; if (p_end > zalloc_end) return NULL; memset((void *)p, 0, size); zalloc_current = p_end; return (void *)p; } static void ZLIB_INTERNAL zfree(void *opaque, void *ptr) { } /* * gunzip - decompress gzip data * @in_buf: source of compressed input. Upon exit, the end of input. * @in_len: length of in_buf * @out_buf: destination of decompressed output. Upon exit, the end of output. * @out_len: length of out_buf * @work_buf: workspace * @work_len: length of workspace */ int gunzip(uintptr_t *in_buf, size_t in_len, uintptr_t *out_buf, size_t out_len, uintptr_t work_buf, size_t work_len) { z_stream stream; int zret, ret; zalloc_start = work_buf; zalloc_end = work_buf + work_len; zalloc_current = zalloc_start; stream.next_in = (typeof(stream.next_in))*in_buf; stream.avail_in = in_len; stream.next_out = (typeof(stream.next_out))*out_buf; stream.avail_out = out_len; stream.zalloc = zcalloc; stream.zfree = zfree; stream.opaque = (voidpf)0; zret = inflateInit(&stream); if (zret != Z_OK) { ERROR("zlib: inflate init failed (ret = %d)\n", zret); return (zret == Z_MEM_ERROR) ? -ENOMEM : -EIO; } zret = inflate(&stream, Z_NO_FLUSH); if (zret == Z_STREAM_END) { ret = 0; } else { if (stream.msg) ERROR("%s\n", stream.msg); ERROR("zlib: inflate failed (ret = %d)\n", zret); ret = (zret == Z_MEM_ERROR) ? -ENOMEM : -EIO; } VERBOSE("zlib: %lu byte input\n", stream.total_in); VERBOSE("zlib: %lu byte output\n", stream.total_out); *in_buf = (uintptr_t)stream.next_in; *out_buf = (uintptr_t)stream.next_out; inflateEnd(&stream); return ret; } trusted-firmware-a-2.2/lib/zlib/zconf.h000066400000000000000000000376521355360272700201240ustar00rootroot00000000000000/* zconf.h -- configuration of the zlib compression library * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #ifndef ZCONF_H #define ZCONF_H /* * If you *really* need a unique prefix for all types and library functions, * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. * Even better than compiling with -DZ_PREFIX would be to use configure to set * this permanently in zconf.h using "./configure --zprefix". */ #ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ # define Z_PREFIX_SET /* all linked symbols and init macros */ # define _dist_code z__dist_code # define _length_code z__length_code # define _tr_align z__tr_align # define _tr_flush_bits z__tr_flush_bits # define _tr_flush_block z__tr_flush_block # define _tr_init z__tr_init # define _tr_stored_block z__tr_stored_block # define _tr_tally z__tr_tally # define adler32 z_adler32 # define adler32_combine z_adler32_combine # define adler32_combine64 z_adler32_combine64 # define adler32_z z_adler32_z # ifndef Z_SOLO # define compress z_compress # define compress2 z_compress2 # define compressBound z_compressBound # endif # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 # define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd # define deflateGetDictionary z_deflateGetDictionary # define deflateInit z_deflateInit # define deflateInit2 z_deflateInit2 # define deflateInit2_ z_deflateInit2_ # define deflateInit_ z_deflateInit_ # define deflateParams z_deflateParams # define deflatePending z_deflatePending # define deflatePrime z_deflatePrime # define deflateReset z_deflateReset # define deflateResetKeep z_deflateResetKeep # define deflateSetDictionary z_deflateSetDictionary # define deflateSetHeader z_deflateSetHeader # define deflateTune z_deflateTune # define deflate_copyright z_deflate_copyright # define get_crc_table z_get_crc_table # ifndef Z_SOLO # define gz_error z_gz_error # define gz_intmax z_gz_intmax # define gz_strwinerror z_gz_strwinerror # define gzbuffer z_gzbuffer # define gzclearerr z_gzclearerr # define gzclose z_gzclose # define gzclose_r z_gzclose_r # define gzclose_w z_gzclose_w # define gzdirect z_gzdirect # define gzdopen z_gzdopen # define gzeof z_gzeof # define gzerror z_gzerror # define gzflush z_gzflush # define gzfread z_gzfread # define gzfwrite z_gzfwrite # define gzgetc z_gzgetc # define gzgetc_ z_gzgetc_ # define gzgets z_gzgets # define gzoffset z_gzoffset # define gzoffset64 z_gzoffset64 # define gzopen z_gzopen # define gzopen64 z_gzopen64 # ifdef _WIN32 # define gzopen_w z_gzopen_w # endif # define gzprintf z_gzprintf # define gzputc z_gzputc # define gzputs z_gzputs # define gzread z_gzread # define gzrewind z_gzrewind # define gzseek z_gzseek # define gzseek64 z_gzseek64 # define gzsetparams z_gzsetparams # define gztell z_gztell # define gztell64 z_gztell64 # define gzungetc z_gzungetc # define gzvprintf z_gzvprintf # define gzwrite z_gzwrite # endif # define inflate z_inflate # define inflateBack z_inflateBack # define inflateBackEnd z_inflateBackEnd # define inflateBackInit z_inflateBackInit # define inflateBackInit_ z_inflateBackInit_ # define inflateCodesUsed z_inflateCodesUsed # define inflateCopy z_inflateCopy # define inflateEnd z_inflateEnd # define inflateGetDictionary z_inflateGetDictionary # define inflateGetHeader z_inflateGetHeader # define inflateInit z_inflateInit # define inflateInit2 z_inflateInit2 # define inflateInit2_ z_inflateInit2_ # define inflateInit_ z_inflateInit_ # define inflateMark z_inflateMark # define inflatePrime z_inflatePrime # define inflateReset z_inflateReset # define inflateReset2 z_inflateReset2 # define inflateResetKeep z_inflateResetKeep # define inflateSetDictionary z_inflateSetDictionary # define inflateSync z_inflateSync # define inflateSyncPoint z_inflateSyncPoint # define inflateUndermine z_inflateUndermine # define inflateValidate z_inflateValidate # define inflate_copyright z_inflate_copyright # define inflate_fast z_inflate_fast # define inflate_table z_inflate_table # ifndef Z_SOLO # define uncompress z_uncompress # define uncompress2 z_uncompress2 # endif # define zError z_zError # ifndef Z_SOLO # define zcalloc z_zcalloc # define zcfree z_zcfree # endif # define zlibCompileFlags z_zlibCompileFlags # define zlibVersion z_zlibVersion /* all zlib typedefs in zlib.h and zconf.h */ # define Byte z_Byte # define Bytef z_Bytef # define alloc_func z_alloc_func # define charf z_charf # define free_func z_free_func # ifndef Z_SOLO # define gzFile z_gzFile # endif # define gz_header z_gz_header # define gz_headerp z_gz_headerp # define in_func z_in_func # define intf z_intf # define out_func z_out_func # define uInt z_uInt # define uIntf z_uIntf # define uLong z_uLong # define uLongf z_uLongf # define voidp z_voidp # define voidpc z_voidpc # define voidpf z_voidpf /* all zlib structs in zlib.h and zconf.h */ # define gz_header_s z_gz_header_s # define internal_state z_internal_state #endif #if defined(__MSDOS__) && !defined(MSDOS) # define MSDOS #endif #if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) # define OS2 #endif #if defined(_WINDOWS) && !defined(WINDOWS) # define WINDOWS #endif #if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) # ifndef WIN32 # define WIN32 # endif #endif #if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) # if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) # ifndef SYS16BIT # define SYS16BIT # endif # endif #endif /* * Compile with -DMAXSEG_64K if the alloc function cannot allocate more * than 64k bytes at a time (needed on systems with 16-bit int). */ #ifdef SYS16BIT # define MAXSEG_64K #endif #ifdef MSDOS # define UNALIGNED_OK #endif #ifdef __STDC_VERSION__ # ifndef STDC # define STDC # endif # if __STDC_VERSION__ >= 199901L # ifndef STDC99 # define STDC99 # endif # endif #endif #if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) # define STDC #endif #if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) # define STDC #endif #if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) # define STDC #endif #if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) # define STDC #endif #if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ # define STDC #endif #ifndef STDC # ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ # define const /* note: need a more gentle solution here */ # endif #endif #if defined(ZLIB_CONST) && !defined(z_const) # define z_const const #else # define z_const #endif #ifdef Z_SOLO typedef unsigned long z_size_t; #else # define z_longlong long long # if defined(NO_SIZE_T) typedef unsigned NO_SIZE_T z_size_t; # elif defined(STDC) # include typedef size_t z_size_t; # else typedef unsigned long z_size_t; # endif # undef z_longlong #endif /* Maximum value for memLevel in deflateInit2 */ #ifndef MAX_MEM_LEVEL # ifdef MAXSEG_64K # define MAX_MEM_LEVEL 8 # else # define MAX_MEM_LEVEL 9 # endif #endif /* Maximum value for windowBits in deflateInit2 and inflateInit2. * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files * created by gzip. (Files created by minigzip can still be extracted by * gzip.) */ #ifndef MAX_WBITS # define MAX_WBITS 15 /* 32K LZ77 window */ #endif /* The memory requirements for deflate are (in bytes): (1 << (windowBits+2)) + (1 << (memLevel+9)) that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) plus a few kilobytes for small objects. For example, if you want to reduce the default memory requirements from 256K to 128K, compile with make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" Of course this will generally degrade compression (there's no free lunch). The memory requirements for inflate are (in bytes) 1 << windowBits that is, 32K for windowBits=15 (default value) plus about 7 kilobytes for small objects. */ /* Type declarations */ #ifndef OF /* function prototypes */ # ifdef STDC # define OF(args) args # else # define OF(args) () # endif #endif #ifndef Z_ARG /* function prototypes for stdarg */ # if defined(STDC) || defined(Z_HAVE_STDARG_H) # define Z_ARG(args) args # else # define Z_ARG(args) () # endif #endif /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, * just define FAR to be empty. */ #ifdef SYS16BIT # if defined(M_I86SM) || defined(M_I86MM) /* MSC small or medium model */ # define SMALL_MEDIUM # ifdef _MSC_VER # define FAR _far # else # define FAR far # endif # endif # if (defined(__SMALL__) || defined(__MEDIUM__)) /* Turbo C small or medium model */ # define SMALL_MEDIUM # ifdef __BORLANDC__ # define FAR _far # else # define FAR far # endif # endif #endif #if defined(WINDOWS) || defined(WIN32) /* If building or using zlib as a DLL, define ZLIB_DLL. * This is not mandatory, but it offers a little performance increase. */ # ifdef ZLIB_DLL # if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) # ifdef ZLIB_INTERNAL # define ZEXTERN extern __declspec(dllexport) # else # define ZEXTERN extern __declspec(dllimport) # endif # endif # endif /* ZLIB_DLL */ /* If building or using zlib with the WINAPI/WINAPIV calling convention, * define ZLIB_WINAPI. * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. */ # ifdef ZLIB_WINAPI # ifdef FAR # undef FAR # endif # include /* No need for _export, use ZLIB.DEF instead. */ /* For complete Windows compatibility, use WINAPI, not __stdcall. */ # define ZEXPORT WINAPI # ifdef WIN32 # define ZEXPORTVA WINAPIV # else # define ZEXPORTVA FAR CDECL # endif # endif #endif #if defined (__BEOS__) # ifdef ZLIB_DLL # ifdef ZLIB_INTERNAL # define ZEXPORT __declspec(dllexport) # define ZEXPORTVA __declspec(dllexport) # else # define ZEXPORT __declspec(dllimport) # define ZEXPORTVA __declspec(dllimport) # endif # endif #endif #ifndef ZEXTERN # define ZEXTERN extern #endif #ifndef ZEXPORT # define ZEXPORT #endif #ifndef ZEXPORTVA # define ZEXPORTVA #endif #ifndef FAR # define FAR #endif #if !defined(__MACTYPES__) typedef unsigned char Byte; /* 8 bits */ #endif typedef unsigned int uInt; /* 16 bits or more */ typedef unsigned long uLong; /* 32 bits or more */ #ifdef SMALL_MEDIUM /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ # define Bytef Byte FAR #else typedef Byte FAR Bytef; #endif typedef char FAR charf; typedef int FAR intf; typedef uInt FAR uIntf; typedef uLong FAR uLongf; #ifdef STDC typedef void const *voidpc; typedef void FAR *voidpf; typedef void *voidp; #else typedef Byte const *voidpc; typedef Byte FAR *voidpf; typedef Byte *voidp; #endif #if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) # include # if (UINT_MAX == 0xffffffffUL) # define Z_U4 unsigned # elif (ULONG_MAX == 0xffffffffUL) # define Z_U4 unsigned long # elif (USHRT_MAX == 0xffffffffUL) # define Z_U4 unsigned short # endif #endif #ifdef Z_U4 typedef Z_U4 z_crc_t; #else typedef unsigned long z_crc_t; #endif #ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_UNISTD_H #endif #ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ # define Z_HAVE_STDARG_H #endif #ifdef STDC # ifndef Z_SOLO # include /* for off_t */ # endif #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO # include /* for va_list */ # endif #endif #ifdef _WIN32 # ifndef Z_SOLO # include /* for wchar_t */ # endif #endif /* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even * though the former does not conform to the LFS document), but considering * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as * equivalently requesting no 64-bit operations */ #if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 # undef _LARGEFILE64_SOURCE #endif #if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) # define Z_HAVE_UNISTD_H #endif #ifndef Z_SOLO # if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) # include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ # ifdef VMS # include /* for off_t */ # endif # ifndef z_off_t # define z_off_t off_t # endif # endif #endif #if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 # define Z_LFS64 #endif #if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) # define Z_LARGE64 #endif #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) # define Z_WANT64 #endif #if !defined(SEEK_SET) && !defined(Z_SOLO) # define SEEK_SET 0 /* Seek from beginning of file. */ # define SEEK_CUR 1 /* Seek from current position. */ # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ #endif #ifndef z_off_t # define z_off_t long #endif #if !defined(_WIN32) && defined(Z_LARGE64) # define z_off64_t off64_t #else # if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) # define z_off64_t __int64 # else # define z_off64_t z_off_t # endif #endif /* MVS linker does not support external names larger than 8 bytes */ #if defined(__MVS__) #pragma map(deflateInit_,"DEIN") #pragma map(deflateInit2_,"DEIN2") #pragma map(deflateEnd,"DEEND") #pragma map(deflateBound,"DEBND") #pragma map(inflateInit_,"ININ") #pragma map(inflateInit2_,"ININ2") #pragma map(inflateEnd,"INEND") #pragma map(inflateSync,"INSY") #pragma map(inflateSetDictionary,"INSEDI") #pragma map(compressBound,"CMBND") #pragma map(inflate_table,"INTABL") #pragma map(inflate_fast,"INFA") #pragma map(inflate_copyright,"INCOPY") #endif #endif /* ZCONF_H */ trusted-firmware-a-2.2/lib/zlib/zlib.h000066400000000000000000002737571355360272700177550ustar00rootroot00000000000000/* zlib.h -- interface of the 'zlib' general purpose compression library version 1.2.11, January 15th, 2017 Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). */ #ifndef ZLIB_H #define ZLIB_H #include "zconf.h" #ifdef __cplusplus extern "C" { #endif #define ZLIB_VERSION "1.2.11" #define ZLIB_VERNUM 0x12b0 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 #define ZLIB_VER_REVISION 11 #define ZLIB_VER_SUBREVISION 0 /* The 'zlib' compression library provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method (deflation) but other algorithms will be added later and will have the same stream interface. Compression can be done in a single step if the buffers are large enough, or can be done by repeated calls of the compression function. In the latter case, the application must provide more input and/or consume the output (providing more output space) before each call. The compressed data format used by default by the in-memory functions is the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped around a deflate stream, which is itself documented in RFC 1951. The library also supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. This library can optionally read and write gzip and raw deflate streams in memory as well. The zlib format was designed to be compact and fast for use in memory and on communications channels. The gzip format was designed for single- file compression on file systems, has a larger header than zlib to maintain directory information, and uses a different, slower check method than zlib. The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash even in the case of corrupted input. */ typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); typedef void (*free_func) OF((voidpf opaque, voidpf address)); struct internal_state; typedef struct z_stream_s { z_const Bytef *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total number of input bytes read so far */ Bytef *next_out; /* next output byte will go here */ uInt avail_out; /* remaining free space at next_out */ uLong total_out; /* total number of bytes output so far */ z_const char *msg; /* last error message, NULL if no error */ struct internal_state FAR *state; /* not visible by applications */ alloc_func zalloc; /* used to allocate the internal state */ free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ int data_type; /* best guess about the data type: binary or text for deflate, or the decoding state for inflate */ uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream; typedef z_stream FAR *z_streamp; /* gzip header information passed to and from zlib routines. See RFC 1952 for more details on the meanings of these fields. */ typedef struct gz_header_s { int text; /* true if compressed data believed to be text */ uLong time; /* modification time */ int xflags; /* extra flags (not used when writing a gzip file) */ int os; /* operating system */ Bytef *extra; /* pointer to extra field or Z_NULL if none */ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ uInt extra_max; /* space at extra (only when reading header) */ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ uInt name_max; /* space at name (only when reading header) */ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ uInt comm_max; /* space at comment (only when reading header) */ int hcrc; /* true if there was or will be a header crc */ int done; /* true when done reading gzip header (not used when writing a gzip file) */ } gz_header; typedef gz_header FAR *gz_headerp; /* The application must update next_in and avail_in when avail_in has dropped to zero. It must update next_out and avail_out when avail_out has dropped to zero. The application must initialize zalloc, zfree and opaque before calling the init function. All other fields are set by the compression library and must not be updated by the application. The opaque value provided by the application will be passed as the first parameter for calls of zalloc and zfree. This can be useful for custom memory management. The compression library attaches no meaning to the opaque value. zalloc must return Z_NULL if there is not enough memory for the object. If zlib is used in a multi-threaded application, zalloc and zfree must be thread safe. In that case, zlib is thread-safe. When zalloc and zfree are Z_NULL on entry to the initialization function, they are set to internal routines that use the standard library functions malloc() and free(). On 16-bit systems, the functions zalloc and zfree must be able to allocate exactly 65536 bytes, but will not be required to allocate more than this if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers returned by zalloc for objects of exactly 65536 bytes *must* have their offset normalized to zero. The default allocation function provided by this library ensures this (see zutil.c). To reduce memory requirements and avoid any allocation of 64K objects, at the expense of compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). The fields total_in and total_out can be used for statistics or progress reports. After compression, total_in holds the total size of the uncompressed data and may be saved for use by the decompressor (particularly if the decompressor wants to decompress everything in a single step). */ /* constants */ #define Z_NO_FLUSH 0 #define Z_PARTIAL_FLUSH 1 #define Z_SYNC_FLUSH 2 #define Z_FULL_FLUSH 3 #define Z_FINISH 4 #define Z_BLOCK 5 #define Z_TREES 6 /* Allowed flush values; see deflate() and inflate() below for details */ #define Z_OK 0 #define Z_STREAM_END 1 #define Z_NEED_DICT 2 #define Z_ERRNO (-1) #define Z_STREAM_ERROR (-2) #define Z_DATA_ERROR (-3) #define Z_MEM_ERROR (-4) #define Z_BUF_ERROR (-5) #define Z_VERSION_ERROR (-6) /* Return codes for the compression/decompression functions. Negative values * are errors, positive values are used for special but normal events. */ #define Z_NO_COMPRESSION 0 #define Z_BEST_SPEED 1 #define Z_BEST_COMPRESSION 9 #define Z_DEFAULT_COMPRESSION (-1) /* compression levels */ #define Z_FILTERED 1 #define Z_HUFFMAN_ONLY 2 #define Z_RLE 3 #define Z_FIXED 4 #define Z_DEFAULT_STRATEGY 0 /* compression strategy; see deflateInit2() below for details */ #define Z_BINARY 0 #define Z_TEXT 1 #define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ #define Z_UNKNOWN 2 /* Possible values of the data_type field for deflate() */ #define Z_DEFLATED 8 /* The deflate compression method (the only one supported in this version) */ #define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ #define zlib_version zlibVersion() /* for compatibility with versions < 1.0.2 */ /* basic functions */ ZEXTERN const char * ZEXPORT zlibVersion OF((void)); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check is automatically made by deflateInit and inflateInit. */ /* ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, deflateInit updates them to use default allocation functions. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6). deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if level is not a valid compression level, or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); /* deflate compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. deflate performs one or both of the following actions: - Compress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in and avail_in are updated and processing will resume at this point for the next call of deflate(). - Generate more output starting at next_out and update next_out and avail_out accordingly. This action is forced if the parameter flush is non zero. Forcing flush frequently degrades the compression ratio, so this parameter should be set only when necessary. Some output may be provided even if flush is zero. Before the call of deflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating avail_in or avail_out accordingly; avail_out should never be zero before the call. The application can consume the compressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. See deflatePending(), which can be used if desired to determine whether or not there is more ouput in that case. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to decide how much data to accumulate before producing output, in order to maximize compression. If the parameter flush is set to Z_SYNC_FLUSH, all pending output is flushed to the output buffer and the output is aligned on a byte boundary, so that the decompressor can get all input data available so far. (In particular avail_in is zero after the call if enough output space has been provided before the call.) Flushing may degrade compression for some compression algorithms and so it should be used only when necessary. This completes the current deflate block and follows it with an empty stored block that is three bits plus filler bits to the next byte, followed by four bytes (00 00 ff ff). If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the output buffer, but the output is not aligned to a byte boundary. All of the input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. This completes the current deflate block and follows it with an empty fixed codes block that is 10 bits long. This assures that enough bytes are output in order for the decompressor to finish the block before the empty fixed codes block. If flush is set to Z_BLOCK, a deflate block is completed and emitted, as for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to seven bits of the current block are held to be written as the next byte after the next deflate block is completed. In this case, the decompressor may not be provided enough bits at this point in order to complete decompression of the data provided so far to the compressor. It may need to wait for the next block to be emitted. This is for advanced applications that need to control the emission of deflate blocks. If flush is set to Z_FULL_FLUSH, all output is flushed as with Z_SYNC_FLUSH, and the compression state is reset so that decompression can restart from this point if previous compressed data has been damaged or if random access is desired. Using Z_FULL_FLUSH too often can seriously degrade compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out is greater than six to avoid repeated flush markers due to avail_out == 0 on return. If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this function must be called again with Z_FINISH and more output space (updated avail_out) but no more input data, until it returns with Z_STREAM_END or an error. After deflate has returned Z_STREAM_END, the only possible operations on the stream are deflateReset or deflateEnd. Z_FINISH can be used in the first deflate call after deflateInit if all the compression is to be done in a single step. In order to complete in one call, avail_out must be at least the value returned by deflateBound (see below). Then deflate is guaranteed to return Z_STREAM_END. If not enough output space is provided, deflate will not return Z_STREAM_END, and it must be called again as described above. deflate() sets strm->adler to the Adler-32 checksum of all input read so far (that is, total_in bytes). If a gzip stream is being generated, then strm->adler will be the CRC-32 checksum of the input read so far. (See deflateInit2 below.) deflate() may update strm->data_type if it can make a good guess about the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is considered binary. This field is only for information purposes and does not affect the compression algorithm in any manner. deflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if all input has been consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example if next_in or next_out was Z_NULL or the state was inadvertently written over by the application), or Z_BUF_ERROR if no progress is possible (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and deflate() can be called again with more input and more output space to continue compressing. */ ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent, Z_DATA_ERROR if the stream was freed prematurely (some input or output was discarded). In the error case, msg may be set but then points to a static string (which must not be deallocated). */ /* ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. In the current version of inflate, the provided input is not read or consumed. The allocation of a sliding window will be deferred to the first call of inflate (if the decompression does not complete on the first call). If zalloc and zfree are set to Z_NULL, inflateInit updates them to use default allocation functions. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit does not perform any decompression. Actual decompression will be done by inflate(). So next_in, and avail_in, next_out, and avail_out are unused and unchanged. The current implementation of inflateInit() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. inflate performs one or both of the following actions: - Decompress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), then next_in and avail_in are updated accordingly, and processing will resume at this point for the next call of inflate(). - Generate more output starting at next_out and update next_out and avail_out accordingly. inflate() provides as much output as possible, until there is no more input data or no more space in the output buffer (see below about the flush parameter). Before the call of inflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating the next_* and avail_* values accordingly. If the caller of inflate() does not provide both available input and available output space, it is possible that there will be no progress made. The application can consume the uncompressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of inflate(). If inflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much output as possible to the output buffer. Z_BLOCK requests that inflate() stop if and when it gets to the next deflate block boundary. When decoding the zlib or gzip format, this will cause inflate() to return immediately after the header and before the first block. When doing a raw inflate, inflate() will go ahead and process the first block, and will return when it gets to the end of that block, or when it runs out of data. The Z_BLOCK option assists in appending to or combining deflate streams. To assist in this, on return inflate() always sets strm->data_type to the number of unused bits in the last byte taken from strm->next_in, plus 64 if inflate() is currently decoding the last block in the deflate stream, plus 128 if inflate() returned immediately after decoding an end-of-block code or decoding the complete header up to just before the first byte of the deflate stream. The end-of-block will not be indicated until all of the uncompressed data from that block has been written to strm->next_out. The number of unused bits may in general be greater than seven, except when bit 7 of data_type is set, in which case the number of unused bits will be less than eight. data_type is set as noted here every time inflate() returns for all flush options, and so can be used to determine the amount of currently consumed input in bits. The Z_TREES option behaves as Z_BLOCK does, but it also returns when the end of each deflate block header is reached, before any actual data in that block is decoded. This allows the caller to determine the length of the deflate block header for later use in random access within a deflate block. 256 is added to the value of strm->data_type when inflate() returns immediately after reaching the end of the deflate block header. inflate() should normally be called until it returns Z_STREAM_END or an error. However if all decompression is to be performed in a single step (a single call of inflate), the parameter flush should be set to Z_FINISH. In this case all pending input is processed and all pending output is flushed; avail_out must be large enough to hold all of the uncompressed data for the operation to complete. (The size of the uncompressed data may have been saved by the compressor for this purpose.) The use of Z_FINISH is not required to perform an inflation in one step. However it may be used to inform inflate that a faster approach can be used for the single inflate() call. Z_FINISH also informs inflate to not maintain a sliding window if the stream completes, which reduces inflate's memory footprint. If the stream does not complete, either because not all of the stream is provided or not enough output space is provided, then a sliding window will be allocated and inflate() can be called again to continue the operation as if Z_NO_FLUSH had been used. In this implementation, inflate() always flushes as much output as possible to the output buffer, and always uses the faster approach on the first call. So the effects of the flush parameter in this implementation are on the return value of inflate() as noted below, when inflate() returns early when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of memory for a sliding window when Z_FINISH is used. If a preset dictionary is needed after this call (see inflateSetDictionary below), inflate sets strm->adler to the Adler-32 checksum of the dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise it sets strm->adler to the Adler-32 checksum of all output produced so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described below. At the end of the stream, inflate() checks that its computed Adler-32 checksum is equal to that saved by the compressor and returns Z_STREAM_END only if the checksum is correct. inflate() can decompress and check either zlib-wrapped or gzip-wrapped deflate data. The header type is detected automatically, if requested when initializing with inflateInit2(). Any information contained in the gzip header is not retained unless inflateGetHeader() is used. When processing gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output produced so far. The CRC-32 is checked against the gzip trailer, as is the uncompressed length, modulo 2^32. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was corrupted (input stream not conforming to the zlib format or incorrect check value, in which case strm->msg points to a string with a more specific error), Z_STREAM_ERROR if the stream structure was inconsistent (for example next_in or next_out was Z_NULL, or the state was inadvertently written over by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no progress was possible or if there was not enough room in the output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and inflate() can be called again with more input and more output space to continue decompressing. If Z_DATA_ERROR is returned, the application may then call inflateSync() to look for a good compression block if a partial recovery of the data is to be attempted. */ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state was inconsistent. */ /* Advanced functions */ /* The following functions are needed only in some special applications. */ /* ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy)); This is another version of deflateInit with more compression options. The fields next_in, zalloc, zfree and opaque must be initialized before by the caller. The method parameter is the compression method. It must be Z_DEFLATED in this version of the library. The windowBits parameter is the base two logarithm of the window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. Larger values of this parameter result in better compression at the expense of memory usage. The default value is 15 if deflateInit is used instead. For the current implementation of deflate(), a windowBits value of 8 (a window size of 256 bytes) is not supported. As a result, a request for 8 will result in 9 (a 512-byte window). In that case, providing 8 to inflateInit2() will result in an error when the zlib header with 9 is checked against the initialization of inflate(). The remedy is to not use 8 with deflateInit2() with this initialization, or at least in that case use 9 with inflateInit2(). windowBits can also be -8..-15 for raw deflate. In this case, -windowBits determines the window size. deflate() will then generate raw deflate data with no zlib header or trailer, and will not compute a check value. windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper. The gzip header will have no file name, no extra data, no comment, no modification time (set to zero), no header crc, and the operating system will be set to the appropriate value, if the operating system was determined at compile time. If a gzip stream is being written, strm->adler is a CRC-32 instead of an Adler-32. For raw deflate or gzip encoding, a request for a 256-byte window is rejected as invalid, since only the zlib header provides a means of transmitting the window size to the decompressor. The memLevel parameter specifies how much memory should be allocated for the internal compression state. memLevel=1 uses minimum memory but is slow and reduces compression ratio; memLevel=9 uses maximum memory for optimal speed. The default value is 8. See zconf.h for total memory usage as a function of windowBits and memLevel. The strategy parameter is used to tune the compression algorithm. Use the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no string match), or Z_RLE to limit match distances to one (run-length encoding). Filtered data consists mostly of small values with a somewhat random distribution. In this case, the compression algorithm is tuned to compress them better. The effect of Z_FILTERED is to force more Huffman coding and less string matching; it is somewhat intermediate between Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The strategy parameter only affects the compression ratio but not the correctness of the compressed output even if it is not set appropriately. Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler decoder for special applications. deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit2 does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the compression dictionary from the given byte sequence without producing any compressed output. When using the zlib format, this function must be called immediately after deflateInit, deflateInit2 or deflateReset, and before any call of deflate. When doing raw deflate, this function must be called either before any call of deflate, or immediately after the completion of a deflate block, i.e. after all input has been consumed and all output has been delivered when using any of the flush options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The compressor and decompressor must use exactly the same dictionary (see inflateSetDictionary). The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly used strings preferably put towards the end of the dictionary. Using a dictionary is most useful when the data to be compressed is short and can be predicted with good accuracy; the data can then be compressed better than with the default empty dictionary. Depending on the size of the compression data structures selected by deflateInit or deflateInit2, a part of the dictionary may in effect be discarded, for example if the dictionary is larger than the window size provided in deflateInit or deflateInit2. Thus the strings most likely to be useful should be put at the end of the dictionary, not at the front. In addition, the current implementation of deflate will use at most the window size minus 262 bytes of the provided dictionary. Upon return of this function, strm->adler is set to the Adler-32 value of the dictionary; the decompressor may later use this value to determine which dictionary has been used by the compressor. (The Adler-32 value applies to the whole dictionary even if only a subset of the dictionary is actually used by the compressor.) If a raw deflate was requested, then the Adler-32 value is not computed and strm->adler is not set. deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent (for example if deflate has already been called for this stream or if not at a block boundary for raw deflate). deflateSetDictionary does not perform any compression: this will be done by deflate(). */ ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, Bytef *dictionary, uInt *dictLength)); /* Returns the sliding dictionary being maintained by deflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If deflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. Similary, if dictLength is Z_NULL, then it is not set. deflateGetDictionary() may return a length less than the window size, even when more than the window size in input has been provided. It may return up to 258 bytes less in that case, due to how zlib's implementation of deflate manages the sliding window and lookahead for matches, where matches can be up to 258 bytes long. If the application needs the last window-size bytes of input, then that would need to be saved by the application outside of zlib. deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. */ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when several compression strategies will be tried, for example when there are several ways of pre-processing the input data with a filter. The streams that will be discarded should then be freed by calling deflateEnd. Note that deflateCopy duplicates the internal compression state which can be quite large, so this strategy is slow and can consume lots of memory. deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate the internal compression state. The stream will leave the compression level and any other attributes that may have been set unchanged. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, int level, int strategy)); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2(). This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. If the compression approach (which is a function of the level) or the strategy is changed, and if any input has been consumed in a previous deflate() call, then the input available so far is compressed with the old level and strategy using deflate(strm, Z_BLOCK). There are three approaches for the compression levels 0, 1..3, and 4..9 respectively. The new level and strategy will take effect at the next call of deflate(). If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does not have enough output space to complete, then the parameter change will not take effect. In this case, deflateParams() can be called again with the same parameters and more output space to try again. In order to assure a change in the parameters on the first try, the deflate stream should be flushed using deflate() with Z_BLOCK or other flush request until strm.avail_out is not zero, before calling deflateParams(). Then no more input data should be provided before the deflateParams() call. If this is done, the old level and strategy will be applied to the data compressed before deflateParams(), and the new level and strategy will be applied to the the data compressed after deflateParams(). deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if there was not enough output space to complete the compression of the available input data before a change in the strategy or approach. Note that in the case of a Z_BUF_ERROR, the parameters are not changed. A return value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be retried with more output space. */ ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, int good_length, int max_lazy, int nice_length, int max_chain)); /* Fine tune deflate's internal compression parameters. This should only be used by someone who understands the algorithm used by zlib's deflate for searching for the best matching string, and even then only by the most fanatic optimizer trying to squeeze out the last compressed bit for their specific input data. Read the deflate.c source code for the meaning of the max_lazy, good_length, nice_length, and max_chain parameters. deflateTune() can be called after deflateInit() or deflateInit2(), and returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. */ ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, uLong sourceLen)); /* deflateBound() returns an upper bound on the compressed size after deflation of sourceLen bytes. It must be called after deflateInit() or deflateInit2(), and after deflateSetHeader(), if used. This would be used to allocate an output buffer for deflation in a single pass, and so would be called before deflate(). If that first deflate() call is provided the sourceLen input bytes, an output buffer allocated to the size returned by deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed to return Z_STREAM_END. Note that it is possible for the compressed size to be larger than the value returned by deflateBound() if flush options other than Z_FINISH or Z_NO_FLUSH are used. */ ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, unsigned *pending, int *bits)); /* deflatePending() returns the number of bytes and bits of output that have been generated, but not yet provided in the available output. The bytes not provided would be due to the available output space having being consumed. The number of bits of output not provided are between 0 and 7, where they await more bits to join them in order to fill out a full byte. If pending or bits are Z_NULL, then those values are not set. deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, int bits, int value)); /* deflatePrime() inserts bits in the deflate output stream. The intent is that this function is used to start off the deflate output with the bits leftover from a previous deflate stream when appending to it. As such, this function can only be used for raw deflate, and must be used before the first deflate() call after a deflateInit2() or deflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the output. deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, gz_headerp head)); /* deflateSetHeader() provides gzip header information for when a gzip stream is requested by deflateInit2(). deflateSetHeader() may be called after deflateInit2() or deflateReset() and before the first call of deflate(). The text, time, os, extra field, name, and comment information in the provided gz_header structure are written to the gzip header (xflag is ignored -- the extra flags are set according to the compression level). The caller must assure that, if not Z_NULL, name and comment are terminated with a zero byte, and that if extra is not Z_NULL, that extra_len bytes are available there. If hcrc is true, a gzip header crc is included. Note that the current versions of the command-line version of gzip (up through version 1.3.x) do not support header crc's, and will report that it is a "multi-part gzip file" and give up. If deflateSetHeader is not used, the default gzip header has text false, the time set to zero, and os set to 255, with no extra, name, or comment fields. The gzip header is returned to the default state by deflateReset(). deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, int windowBits)); This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. The default value is 15 if inflateInit is used instead. windowBits must be greater than or equal to the windowBits value provided to deflateInit2() while compressing, or it must be equal to 15 if deflateInit2() was not used. If a compressed stream with a larger window size is given as input, inflate() will return with the error code Z_DATA_ERROR instead of trying to allocate a larger window. windowBits can also be zero to request that inflate use the window size in the zlib header of the compressed stream. windowBits can also be -8..-15 for raw inflate. In this case, -windowBits determines the window size. inflate() will then process raw deflate data, not looking for a zlib or gzip header, not generating a check value, and not looking for any check values for comparison at the end of the stream. This is for use with other formats that use the deflate compressed data format such as zip. Those formats provide their own check values. If a custom format is developed using the raw deflate format for compressed data, it is recommended that a check value such as an Adler-32 or a CRC-32 be applied to the uncompressed data as is done in the zlib, gzip, and zip formats. For most applications, the zlib format should be used as is. Note that comments above on the use in deflateInit2() applies to the magnitude of windowBits. windowBits can also be greater than 15 for optional gzip decoding. Add 32 to windowBits to enable zlib and gzip decoding with automatic header detection, or add 16 to decode only the gzip format (the zlib format will return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see below), inflate() will not automatically decode concatenated gzip streams. inflate() will return Z_STREAM_END at the end of the gzip stream. The state would need to be reset to continue decoding a subsequent gzip stream. inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if there is no error message. inflateInit2 does not perform any decompression apart from possibly reading the zlib header if present: actual decompression will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unused and unchanged.) The current implementation of inflateInit2() does not process any header information -- that is deferred until inflate() is called. */ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, const Bytef *dictionary, uInt dictLength)); /* Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the Adler-32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see deflateSetDictionary). For raw inflate, this function can be called at any time to set the dictionary. If the provided dictionary is smaller than the window and there is already data in the window, then the provided dictionary will amend what's there. The application must insure that the dictionary that was used for compression is provided. inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the expected one (incorrect Adler-32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, Bytef *dictionary, uInt *dictLength)); /* Returns the sliding dictionary being maintained by inflate. dictLength is set to the number of bytes in the dictionary, and that many bytes are copied to dictionary. dictionary must have enough space, where 32768 bytes is always enough. If inflateGetDictionary() is called with dictionary equal to Z_NULL, then only the dictionary length is returned, and nothing is copied. Similary, if dictLength is Z_NULL, then it is not set. inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the stream state is inconsistent. */ ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); /* Skips invalid compressed data until a possible full flush point (see above for the description of deflate with Z_FULL_FLUSH) can be found, or until all available input is skipped. No output is provided. inflateSync searches for a 00 00 FF FF pattern in the compressed data. All full flush points have this pattern, but not all occurrences of this pattern are full flush points. inflateSync returns Z_OK if a possible full flush point has been found, Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the success case, the application may save the current current value of total_in which indicates where valid compressed data was found. In the error case, the application may repeatedly call inflateSync, providing more input each time, until success or end of the input data. */ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, z_streamp source)); /* Sets the destination stream as a complete copy of the source stream. This function can be useful when randomly accessing a large stream. The first pass through the stream can periodically record the inflate state, allowing restarting inflate at those points when randomly accessing the stream. inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being Z_NULL). msg is left unchanged in both source and destination. */ ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). */ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, int windowBits)); /* This function is the same as inflateReset, but it also permits changing the wrap and window size requests. The windowBits parameter is interpreted the same as it is for inflateInit2. If the window size is changed, then the memory allocated for the window is freed, and the window will be reallocated by inflate() if needed. inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL), or if the windowBits parameter is invalid. */ ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, int bits, int value)); /* This function inserts bits in the inflate input stream. The intent is that this function is used to start inflating at a bit position in the middle of a byte. The provided bits will be used before any bytes are used from next_in. This function should only be used with raw inflate, and should be used before the first inflate() call after inflateInit2() or inflateReset(). bits must be less than or equal to 16, and that many of the least significant bits of value will be inserted in the input. If bits is negative, then the input stream bit buffer is emptied. Then inflatePrime() can be called again to put bits in the buffer. This is used to clear out bits leftover after feeding inflate a block description prior to feeding inflate codes. inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); /* This function returns two values, one in the lower 16 bits of the return value, and the other in the remaining upper bits, obtained by shifting the return value down 16 bits. If the upper value is -1 and the lower value is zero, then inflate() is currently decoding information outside of a block. If the upper value is -1 and the lower value is non-zero, then inflate is in the middle of a stored block, with the lower value equaling the number of bytes from the input remaining to copy. If the upper value is not -1, then it is the number of bits back from the current bit position in the input of the code (literal or length/distance pair) currently being processed. In that case the lower value is the number of bytes already emitted for that code. A code is being processed if inflate is waiting for more input to complete decoding of the code, or if it has completed decoding but is waiting for more output space to write the literal or match data. inflateMark() is used to mark locations in the input data for random access, which may be at bit positions, and to note those cases where the output of a code may span boundaries of random access blocks. The current location in the input stream can be determined from avail_in and data_type as noted in the description for the Z_BLOCK flush parameter for inflate. inflateMark returns the value noted above, or -65536 if the provided source stream state was inconsistent. */ ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, gz_headerp head)); /* inflateGetHeader() requests that gzip header information be stored in the provided gz_header structure. inflateGetHeader() may be called after inflateInit2() or inflateReset(), and before the first call of inflate(). As inflate() processes the gzip stream, head->done is zero until the header is completed, at which time head->done is set to one. If a zlib stream is being decoded, then head->done is set to -1 to indicate that there will be no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be used to force inflate() to return immediately after header processing is complete and before any actual data is decompressed. The text, time, xflags, and os fields are filled in with the gzip header contents. hcrc is set to true if there is a header CRC. (The header CRC was valid if done is set to one.) If extra is not Z_NULL, then extra_max contains the maximum number of bytes to write to extra. Once done is true, extra_len contains the actual extra field length, and extra contains the extra field, or that field truncated if extra_max is less than extra_len. If name is not Z_NULL, then up to name_max characters are written there, terminated with a zero unless the length is greater than name_max. If comment is not Z_NULL, then up to comm_max characters are written there, terminated with a zero unless the length is greater than comm_max. When any of extra, name, or comment are not Z_NULL and the respective field is not present in the header, then that field is set to Z_NULL to signal its absence. This allows the use of deflateSetHeader() with the returned structure to duplicate the header. However if those fields are set to allocated memory, then the application will need to save those pointers elsewhere so that they can be eventually freed. If inflateGetHeader is not used, then the header information is simply discarded. The header is always checked for validity, including the header CRC if present. inflateReset() will reset the process to discard the header information. The application would need to call inflateGetHeader() again to retrieve the header from the next gzip stream. inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent. */ /* ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, unsigned char FAR *window)); Initialize the internal stream state for decompression using inflateBack() calls. The fields zalloc, zfree and opaque in strm must be initialized before the call. If zalloc and zfree are Z_NULL, then the default library- derived memory allocation routines are used. windowBits is the base two logarithm of the window size, in the range 8..15. window is a caller supplied buffer of that size. Except for special applications where it is assured that deflate was used with small window sizes, windowBits must be 15 and a 32K byte window must be supplied to be able to decompress general deflate streams. See inflateBack() for the usage of these routines. inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of the parameters are invalid, Z_MEM_ERROR if the internal state could not be allocated, or Z_VERSION_ERROR if the version of the library does not match the version of the header file. */ typedef unsigned (*in_func) OF((void FAR *, z_const unsigned char FAR * FAR *)); typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, in_func in, void FAR *in_desc, out_func out, void FAR *out_desc)); /* inflateBack() does a raw inflate with a single call using a call-back interface for input and output. This is potentially more efficient than inflate() for file i/o applications, in that it avoids copying between the output and the sliding window by simply making the window itself the output buffer. inflate() can be faster on modern CPUs when used with large buffers. inflateBack() trusts the application to not change the output buffer passed by the output function, at least until inflateBack() returns. inflateBackInit() must be called first to allocate the internal state and to initialize the state with the user-provided window buffer. inflateBack() may then be used multiple times to inflate a complete, raw deflate stream with each call. inflateBackEnd() is then called to free the allocated state. A raw deflate stream is one with no zlib or gzip header or trailer. This routine would normally be used in a utility that reads zip or gzip files and writes out uncompressed files. The utility would decode the header and process the trailer on its own, hence this routine expects only the raw deflate stream to decompress. This is different from the default behavior of inflate(), which expects a zlib header and trailer around the deflate stream. inflateBack() uses two subroutines supplied by the caller that are then called by inflateBack() for input and output. inflateBack() calls those routines until it reads a complete deflate stream and writes out all of the uncompressed data, or until it encounters an error. The function's parameters and return types are defined above in the in_func and out_func typedefs. inflateBack() will call in(in_desc, &buf) which should return the number of bytes of provided input, and a pointer to that input in buf. If there is no input available, in() must return zero -- buf is ignored in that case -- and inflateBack() will return a buffer error. inflateBack() will call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() should return zero on success, or non-zero on failure. If out() returns non-zero, inflateBack() will return with an error. Neither in() nor out() are permitted to change the contents of the window provided to inflateBackInit(), which is also the buffer that out() uses to write from. The length written by out() will be at most the window size. Any non-zero amount of input may be provided by in(). For convenience, inflateBack() can be provided input on the first call by setting strm->next_in and strm->avail_in. If that input is exhausted, then in() will be called. Therefore strm->next_in must be initialized before calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in must also be initialized, and then if strm->avail_in is not zero, input will initially be taken from strm->next_in[0 .. strm->avail_in - 1]. The in_desc and out_desc parameters of inflateBack() is passed as the first parameter of in() and out() respectively when they are called. These descriptors can be optionally used to pass any information that the caller- supplied in() and out() functions need to do their job. On return, inflateBack() will set strm->next_in and strm->avail_in to pass back any unused input that was provided by the last in() call. The return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR if in() or out() returned an error, Z_DATA_ERROR if there was a format error in the deflate stream (in which case strm->msg is set to indicate the nature of the error), or Z_STREAM_ERROR if the stream was not properly initialized. In the case of Z_BUF_ERROR, an input or output error can be distinguished using strm->next_in which will be Z_NULL only if in() returned an error. If strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning non-zero. (in() will always be called before out(), so strm->next_in is assured to be defined if out() returns non-zero.) Note that inflateBack() cannot return Z_OK. */ ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); /* All memory allocated by inflateBackInit() is freed. inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream state was inconsistent. */ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); /* Return flags indicating compile-time options. Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: 1.0: size of uInt 3.2: size of uLong 5.4: size of voidpf (pointer) 7.6: size of z_off_t Compiler, assembler, and debug options: 8: ZLIB_DEBUG 9: ASMV or ASMINF -- use ASM code 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention 11: 0 (reserved) One-time table building (smaller code, but not thread-safe if true): 12: BUILDFIXED -- build static block decoding tables when needed 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed 14,15: 0 (reserved) Library content (indicates missing functionality): 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking deflate code when not needed) 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect and decode gzip streams (to avoid linking crc code) 18-19: 0 (reserved) Operation variations (changes in library functionality): 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate 21: FASTEST -- deflate algorithm with only one, lowest compression level 22,23: 0 (reserved) The sprintf variant used by gzprintf (zero is best): 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! 26: 0 = returns value, 1 = void -- 1 means inferred string length returned Remainder: 27-31: 0 (reserved) */ #ifndef Z_SOLO /* utility functions */ /* The following utility functions are implemented on top of the basic stream-oriented functions. To simplify the interface, some default options are assumed (compression level and memory usage, standard memory allocation functions). The source code of these utility functions can be modified if you need special options. */ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Compresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed data. compress() is equivalent to compress2() with a level parameter of Z_DEFAULT_COMPRESSION. compress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer. */ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen, int level)); /* Compresses the source buffer into the destination buffer. The level parameter has the same meaning as in deflateInit. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the compressed data. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, Z_STREAM_ERROR if the level parameter is invalid. */ ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); /* compressBound() returns an upper bound on the compressed size after compress() or compress2() on sourceLen bytes. It would be used before a compress() or compress2() call to allocate the destination buffer. */ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen)); /* Decompresses the source buffer into the destination buffer. sourceLen is the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be large enough to hold the entire uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen is the actual size of the uncompressed data. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In the case where there is not enough room, uncompress() will fill the output buffer with the uncompressed data up to that point. */ ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, const Bytef *source, uLong *sourceLen)); /* Same as uncompress, except that sourceLen is a pointer, where the length of the source is *sourceLen. On return, *sourceLen is the number of source bytes consumed. */ /* gzip file access functions */ /* This library supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio, using the functions that start with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. */ typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ /* ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); Opens a gzip (.gz) file for reading or writing. The mode parameter is as in fopen ("rb" or "wb") but can also include a compression level ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression as in "wb9F". (See the description of deflateInit2 for more information about the strategy parameter.) 'T' will request transparent writing or appending with no compression and not using the gzip format. "a" can be used instead of "w" to request that the gzip stream that will be written be appended to the file. "+" will result in an error, since reading and writing to the same gzip file is not supported. The addition of "x" when writing will create the file exclusively, which fails if the file already exists. On systems that support it, the addition of "e" when reading or writing will set the flag to close the file on an execve() call. These functions, as well as gzip, will read and decode a sequence of gzip streams in a file. The append function of gzopen() can be used to create such a file. (Also see gzflush() for another way to do this.) When appending, gzopen does not test whether the file begins with a gzip stream, nor does it look for the end of the gzip streams to begin appending. gzopen will simply append a gzip stream to the existing file. gzopen can be used to read a file which is not in gzip format; in this case gzread will directly read from the file without decompression. When reading, this will be detected automatically by looking for the magic two- byte gzip header. gzopen returns NULL if the file could not be opened, if there was insufficient memory to allocate the gzFile state, or if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). errno can be checked to determine if the reason gzopen failed was that the file could not be opened. */ ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); /* gzdopen associates a gzFile with the file descriptor fd. File descriptors are obtained from calls like open, dup, creat, pipe or fileno (if the file has been previously opened with fopen). The mode parameter is as in gzopen. The next call of gzclose on the returned gzFile will also close the file descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, mode);. The duplicated descriptor should be saved to avoid a leak, since gzdopen does not close fd if it fails. If you are using fileno() to get the file descriptor from a FILE *, then you will have to use dup() to avoid double-close()ing the file descriptor. Both gzclose() and fclose() will close the associated file descriptor, so they need to have different file descriptors. gzdopen returns NULL if there was insufficient memory to allocate the gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not provided, or '+' was provided), or if fd is -1. The file descriptor is not used until the next gz* read, write, seek, or close operation, so gzdopen will not detect if fd is invalid (unless fd is -1). */ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); /* Set the internal buffer size used by this library's functions. The default buffer size is 8192 bytes. This function must be called after gzopen() or gzdopen(), and before any other calls that read or write the file. The buffer memory allocation is always deferred to the first read or write. Three times that size in buffer space is allocated. A larger buffer size of, for example, 64K or 128K bytes will noticeably increase the speed of decompression (reading). The new buffer size also affects the maximum length for gzprintf(). gzbuffer() returns 0 on success, or -1 on failure, such as being called too late. */ ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); /* Dynamically update the compression level or strategy. See the description of deflateInit2 for the meaning of these parameters. Previously provided data is flushed before the parameter change. gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not opened for writing, Z_ERRNO if there is an error writing the flushed data, or Z_MEM_ERROR if there is a memory allocation error. */ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); /* Reads the given number of uncompressed bytes from the compressed file. If the input file is not in gzip format, gzread copies the given number of bytes into the buffer directly from the file. After reaching the end of a gzip stream in the input, gzread will continue to read, looking for another gzip stream. Any number of gzip streams may be concatenated in the input file, and will all be decompressed by gzread(). If something other than a gzip stream is encountered after a gzip stream, that remaining trailing garbage is ignored (and no error is returned). gzread can be used to read a gzip file that is being concurrently written. Upon reaching the end of the input, gzread will return with the available data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then gzclearerr can be used to clear the end of file indicator in order to permit gzread to be tried again. Z_OK indicates that a gzip stream was completed on the last gzread. Z_BUF_ERROR indicates that the input file ended in the middle of a gzip stream. Note that gzread does not return -1 in the event of an incomplete gzip stream. This error is deferred until gzclose(), which will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip stream. Alternatively, gzerror can be used before gzclose to detect this case. gzread returns the number of uncompressed bytes actually read, less than len for end of file, or -1 for error. If len is too large to fit in an int, then nothing is read, -1 is returned, and the error state is set to Z_STREAM_ERROR. */ ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, gzFile file)); /* Read up to nitems items of size size from file to buf, otherwise operating as gzread() does. This duplicates the interface of stdio's fread(), with size_t request and return types. If the library defines size_t, then z_size_t is identical to size_t. If not, then z_size_t is an unsigned integer type that can contain a pointer. gzfread() returns the number of full items read of size size, or zero if the end of the file was reached and a full item could not be read, or if there was an error. gzerror() must be consulted if zero is returned in order to determine if there was an error. If the multiplication of size and nitems overflows, i.e. the product does not fit in a z_size_t, then nothing is read, zero is returned, and the error state is set to Z_STREAM_ERROR. In the event that the end of file is reached and only a partial item is available at the end, i.e. the remaining uncompressed data length is not a multiple of size, then the final partial item is nevetheless read into buf and the end-of-file flag is set. The length of the partial item read is not provided, but could be inferred from the result of gztell(). This behavior is the same as the behavior of fread() implementations in common libraries, but it prevents the direct use of gzfread() to read a concurrently written file, reseting and retrying on end-of-file, when size is not 1. */ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, voidpc buf, unsigned len)); /* Writes the given number of uncompressed bytes into the compressed file. gzwrite returns the number of uncompressed bytes written or 0 in case of error. */ ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, z_size_t nitems, gzFile file)); /* gzfwrite() writes nitems items of size size from buf to file, duplicating the interface of stdio's fwrite(), with size_t request and return types. If the library defines size_t, then z_size_t is identical to size_t. If not, then z_size_t is an unsigned integer type that can contain a pointer. gzfwrite() returns the number of full items written of size size, or zero if there was an error. If the multiplication of size and nitems overflows, i.e. the product does not fit in a z_size_t, then nothing is written, zero is returned, and the error state is set to Z_STREAM_ERROR. */ ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); /* Converts, formats, and writes the arguments to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of uncompressed bytes actually written, or a negative zlib error code in case of error. The number of uncompressed bytes written is limited to 8191, or one less than the buffer size given to gzbuffer(). The caller should assure that this limit is not exceeded. If it is exceeded, then gzprintf() will return an error (0) with nothing written. In this case, there may also be a buffer overflow with unpredictable consequences, which is possible only if zlib was compiled with the insecure functions sprintf() or vsprintf() because the secure snprintf() or vsnprintf() functions were not available. This can be determined using zlibCompileFlags(). */ ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); /* Writes the given null-terminated string to the compressed file, excluding the terminating null character. gzputs returns the number of characters written, or -1 in case of error. */ ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); /* Reads bytes from the compressed file until len-1 characters are read, or a newline character is read and transferred to buf, or an end-of-file condition is encountered. If any characters are read or if len == 1, the string is terminated with a null character. If no characters are read due to an end-of-file or len < 1, then the buffer is left untouched. gzgets returns buf which is a null-terminated string, or it returns NULL for end-of-file or in case of error. If there was an error, the contents at buf are indeterminate. */ ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); /* Writes c, converted to an unsigned char, into the compressed file. gzputc returns the value that was written, or -1 in case of error. */ ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); /* Reads one byte from the compressed file. gzgetc returns this byte or -1 in case of end of file or error. This is implemented as a macro for speed. As such, it does not do all of the checking the other functions do. I.e. it does not check to see if file is NULL, nor whether the structure file points to has been clobbered or not. */ ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); /* Push one character back onto the stream to be read as the first character on the next read. At least one character of push-back is allowed. gzungetc() returns the character pushed, or -1 on failure. gzungetc() will fail if c is -1, and may fail if a character has been pushed but not read yet. If gzungetc is used immediately after gzopen or gzdopen, at least the output buffer size of pushed characters is allowed. (See gzbuffer above.) The pushed character will be discarded if the stream is repositioned with gzseek() or gzrewind(). */ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); /* Flushes all pending output into the compressed file. The parameter flush is as in the deflate() function. The return value is the zlib error number (see function gzerror below). gzflush is only permitted when writing. If the flush parameter is Z_FINISH, the remaining data is written and the gzip stream is completed in the output. If gzwrite() is called again, a new gzip stream will be started in the output. gzread() is able to read such concatenated gzip streams. gzflush should be called only when strictly necessary because it will degrade compression if called too often. */ /* ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, z_off_t offset, int whence)); Sets the starting position for the next gzread or gzwrite on the given compressed file. The offset represents a number of bytes in the uncompressed data stream. The whence parameter is defined as in lseek(2); the value SEEK_END is not supported. If the file is opened for reading, this function is emulated but can be extremely slow. If the file is opened for writing, only forward seeks are supported; gzseek then compresses a sequence of zeroes up to the new starting position. gzseek returns the resulting offset location as measured in bytes from the beginning of the uncompressed stream, or -1 in case of error, in particular if the file is opened for writing and the new starting position would be before the current position. */ ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); /* Rewinds the given file. This function is supported only for reading. gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) */ /* ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); Returns the starting position for the next gzread or gzwrite on the given compressed file. This position represents a number of bytes in the uncompressed data stream, and is zero when starting, even if appending or reading a gzip stream from the middle of a file using gzdopen(). gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) */ /* ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); Returns the current offset in the file being read or written. This offset includes the count of bytes that precede the gzip stream, for example when appending or when using gzdopen() for reading. When reading, the offset does not include as yet unused buffered input. This information can be used for a progress indicator. On error, gzoffset() returns -1. */ ZEXTERN int ZEXPORT gzeof OF((gzFile file)); /* Returns true (1) if the end-of-file indicator has been set while reading, false (0) otherwise. Note that the end-of-file indicator is set only if the read tried to go past the end of the input, but came up short. Therefore, just like feof(), gzeof() may return false even if there is no more data to read, in the event that the last read request was for the exact number of bytes remaining in the input file. This will happen if the input file size is an exact multiple of the buffer size. If gzeof() returns true, then the read functions will return no more data, unless the end-of-file indicator is reset by gzclearerr() and the input file has grown since the previous end of file was detected. */ ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); /* Returns true (1) if file is being copied directly while reading, or false (0) if file is a gzip stream being decompressed. If the input file is empty, gzdirect() will return true, since the input does not contain a gzip stream. If gzdirect() is used immediately after gzopen() or gzdopen() it will cause buffers to be allocated to allow reading the file to determine if it is a gzip file. Therefore if gzbuffer() is used, it should be called before gzdirect(). When writing, gzdirect() returns true (1) if transparent writing was requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: gzdirect() is not needed when writing. Transparent writing must be explicitly requested, so the application already knows the answer. When linking statically, using gzdirect() will include all of the zlib code for gzip file reading and decompression, which may not be desired.) */ ZEXTERN int ZEXPORT gzclose OF((gzFile file)); /* Flushes all pending output if necessary, closes the compressed file and deallocates the (de)compression state. Note that once file is closed, you cannot call gzerror with file, since its structures have been deallocated. gzclose must not be called more than once on the same file, just as free must not be called more than once on the same allocation. gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the last read ended in the middle of a gzip stream, or Z_OK on success. */ ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); /* Same as gzclose(), but gzclose_r() is only for use when reading, and gzclose_w() is only for use when writing or appending. The advantage to using these instead of gzclose() is that they avoid linking in zlib compression or decompression code that is not used when only reading or only writing respectively. If gzclose() is used, then both compression and decompression code will be included the application when linking to a static zlib library. */ ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); /* Returns the error message for the last error which occurred on the given compressed file. errnum is set to zlib error number. If an error occurred in the file system and not in the compression library, errnum is set to Z_ERRNO and the application may consult errno to get the exact error code. The application must not modify the returned string. Future calls to this function may invalidate the previously returned string. If file is closed, then the string previously returned by gzerror will no longer be available. gzerror() should be used to distinguish errors from end-of-file for those functions above that do not distinguish those cases in their return values. */ ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); /* Clears the error and end-of-file flags for file. This is analogous to the clearerr() function in stdio. This is useful for continuing to read a gzip file that is being written concurrently. */ #endif /* !Z_SOLO */ /* checksum functions */ /* These functions are not related to compression but are exported anyway because they might be useful in applications using the compression library. */ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); /* Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. If buf is Z_NULL, this function returns the required initial value for the checksum. An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed much faster. Usage example: uLong adler = adler32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { adler = adler32(adler, buffer, length); } if (adler != original_adler) error(); */ ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, z_size_t len)); /* Same as adler32(), but with a size_t length. */ /* ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, z_off_t len2)); Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note that the z_off_t type (like off_t) is a signed integer. If len2 is negative, the result has no meaning or utility. */ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); /* Update a running CRC-32 with the bytes buf[0..len-1] and return the updated CRC-32. If buf is Z_NULL, this function returns the required initial value for the crc. Pre- and post-conditioning (one's complement) is performed within this function so it shouldn't be done by the application. Usage example: uLong crc = crc32(0L, Z_NULL, 0); while (read_buffer(buffer, length) != EOF) { crc = crc32(crc, buffer, length); } if (crc != original_crc) error(); */ ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf, z_size_t len)); /* Same as crc32(), but with a size_t length. */ /* ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); Combine two CRC-32 check values into one. For two sequences of bytes, seq1 and seq2 with lengths len1 and len2, CRC-32 check values were calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and len2. */ /* various hacks, don't look :) */ /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, const char *version, int stream_size)); ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, const char *version, int stream_size)); ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size)); #ifdef Z_PREFIX_SET # define z_deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) # define z_inflateInit(strm) \ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) # define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) # define z_inflateInit2(strm, windowBits) \ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ (int)sizeof(z_stream)) # define z_inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \ ZLIB_VERSION, (int)sizeof(z_stream)) #else # define deflateInit(strm, level) \ deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) # define inflateInit(strm) \ inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) # define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) # define inflateInit2(strm, windowBits) \ inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ (int)sizeof(z_stream)) # define inflateBackInit(strm, windowBits, window) \ inflateBackInit_((strm), (windowBits), (window), \ ZLIB_VERSION, (int)sizeof(z_stream)) #endif #ifndef Z_SOLO /* gzgetc() macro and its supporting function and exposed data structure. Note * that the real internal state is much larger than the exposed structure. * This abbreviated structure exposes just enough for the gzgetc() macro. The * user should not mess with these exposed elements, since their names or * behavior could change in the future, perhaps even capriciously. They can * only be used by the gzgetc() macro. You have been warned. */ struct gzFile_s { unsigned have; unsigned char *next; z_off64_t pos; }; ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ #ifdef Z_PREFIX_SET # undef z_gzgetc # define z_gzgetc(g) \ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) #else # define gzgetc(g) \ ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) #endif /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if * both are true, the application gets the *64 functions, and the regular * functions are changed to 64 bits) -- in case these are set on systems * without large file support, _LFS64_LARGEFILE must also be true */ #ifdef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); #endif #if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) # ifdef Z_PREFIX_SET # define z_gzopen z_gzopen64 # define z_gzseek z_gzseek64 # define z_gztell z_gztell64 # define z_gzoffset z_gzoffset64 # define z_adler32_combine z_adler32_combine64 # define z_crc32_combine z_crc32_combine64 # else # define gzopen gzopen64 # define gzseek gzseek64 # define gztell gztell64 # define gzoffset gzoffset64 # define adler32_combine adler32_combine64 # define crc32_combine crc32_combine64 # endif # ifndef Z_LARGE64 ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); # endif #else ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); #endif #else /* Z_SOLO */ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); #endif /* !Z_SOLO */ /* undocumented functions */ ZEXTERN const char * ZEXPORT zError OF((int)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); #if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO) ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, const char *mode)); #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifndef Z_SOLO ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, const char *format, va_list va)); # endif #endif #ifdef __cplusplus } #endif #endif /* ZLIB_H */ trusted-firmware-a-2.2/lib/zlib/zlib.mk000066400000000000000000000010451355360272700201100ustar00rootroot00000000000000# # Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ZLIB_PATH := lib/zlib # Imported from zlib 1.2.11 (do not modify them) ZLIB_SOURCES := $(addprefix $(ZLIB_PATH)/, \ adler32.c \ crc32.c \ inffast.c \ inflate.c \ inftrees.c \ zutil.c) # Implemented for TF ZLIB_SOURCES += $(addprefix $(ZLIB_PATH)/, \ tf_gunzip.c) INCLUDES += -Iinclude/lib/zlib # REVISIT: the following flags need not be given globally TF_CFLAGS += -DZ_SOLO -DDEF_WBITS=31 trusted-firmware-a-2.2/lib/zlib/zutil.c000066400000000000000000000162101355360272700201320ustar00rootroot00000000000000/* zutil.c -- target dependent utility functions for the compression library * Copyright (C) 1995-2017 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ /* @(#) $Id$ */ #include "zutil.h" #ifndef Z_SOLO # include "gzguts.h" #endif z_const char * const z_errmsg[10] = { (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ (z_const char *)"stream end", /* Z_STREAM_END 1 */ (z_const char *)"", /* Z_OK 0 */ (z_const char *)"file error", /* Z_ERRNO (-1) */ (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ (z_const char *)"" }; const char * ZEXPORT zlibVersion() { return ZLIB_VERSION; } uLong ZEXPORT zlibCompileFlags() { uLong flags; flags = 0; switch ((int)(sizeof(uInt))) { case 2: break; case 4: flags += 1; break; case 8: flags += 2; break; default: flags += 3; } switch ((int)(sizeof(uLong))) { case 2: break; case 4: flags += 1 << 2; break; case 8: flags += 2 << 2; break; default: flags += 3 << 2; } switch ((int)(sizeof(voidpf))) { case 2: break; case 4: flags += 1 << 4; break; case 8: flags += 2 << 4; break; default: flags += 3 << 4; } switch ((int)(sizeof(z_off_t))) { case 2: break; case 4: flags += 1 << 6; break; case 8: flags += 2 << 6; break; default: flags += 3 << 6; } #ifdef ZLIB_DEBUG flags += 1 << 8; #endif #if defined(ASMV) || defined(ASMINF) flags += 1 << 9; #endif #ifdef ZLIB_WINAPI flags += 1 << 10; #endif #ifdef BUILDFIXED flags += 1 << 12; #endif #ifdef DYNAMIC_CRC_TABLE flags += 1 << 13; #endif #ifdef NO_GZCOMPRESS flags += 1L << 16; #endif #ifdef NO_GZIP flags += 1L << 17; #endif #ifdef PKZIP_BUG_WORKAROUND flags += 1L << 20; #endif #ifdef FASTEST flags += 1L << 21; #endif #if defined(STDC) || defined(Z_HAVE_STDARG_H) # ifdef NO_vsnprintf flags += 1L << 25; # ifdef HAS_vsprintf_void flags += 1L << 26; # endif # else # ifdef HAS_vsnprintf_void flags += 1L << 26; # endif # endif #else flags += 1L << 24; # ifdef NO_snprintf flags += 1L << 25; # ifdef HAS_sprintf_void flags += 1L << 26; # endif # else # ifdef HAS_snprintf_void flags += 1L << 26; # endif # endif #endif return flags; } #ifdef ZLIB_DEBUG #include # ifndef verbose # define verbose 0 # endif int ZLIB_INTERNAL z_verbose = verbose; void ZLIB_INTERNAL z_error (m) char *m; { fprintf(stderr, "%s\n", m); exit(1); } #endif /* exported to allow conversion of error code to string for compress() and * uncompress() */ const char * ZEXPORT zError(err) int err; { return ERR_MSG(err); } #if defined(_WIN32_WCE) /* The Microsoft C Run-Time Library for Windows CE doesn't have * errno. We define it as a global variable to simplify porting. * Its value is always 0 and should not be used. */ int errno = 0; #endif #ifndef HAVE_MEMCPY void ZLIB_INTERNAL zmemcpy(dest, source, len) Bytef* dest; const Bytef* source; uInt len; { if (len == 0) return; do { *dest++ = *source++; /* ??? to be unrolled */ } while (--len != 0); } int ZLIB_INTERNAL zmemcmp(s1, s2, len) const Bytef* s1; const Bytef* s2; uInt len; { uInt j; for (j = 0; j < len; j++) { if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; } return 0; } void ZLIB_INTERNAL zmemzero(dest, len) Bytef* dest; uInt len; { if (len == 0) return; do { *dest++ = 0; /* ??? to be unrolled */ } while (--len != 0); } #endif #ifndef Z_SOLO #ifdef SYS16BIT #ifdef __TURBOC__ /* Turbo C in 16-bit mode */ # define MY_ZCALLOC /* Turbo C malloc() does not allow dynamic allocation of 64K bytes * and farmalloc(64K) returns a pointer with an offset of 8, so we * must fix the pointer. Warning: the pointer must be put back to its * original form in order to free it, use zcfree(). */ #define MAX_PTR 10 /* 10*64K = 640K */ local int next_ptr = 0; typedef struct ptr_table_s { voidpf org_ptr; voidpf new_ptr; } ptr_table; local ptr_table table[MAX_PTR]; /* This table is used to remember the original form of pointers * to large buffers (64K). Such pointers are normalized with a zero offset. * Since MSDOS is not a preemptive multitasking OS, this table is not * protected from concurrent access. This hack doesn't work anyway on * a protected system like OS/2. Use Microsoft C instead. */ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) { voidpf buf; ulg bsize = (ulg)items*size; (void)opaque; /* If we allocate less than 65520 bytes, we assume that farmalloc * will return a usable pointer which doesn't have to be normalized. */ if (bsize < 65520L) { buf = farmalloc(bsize); if (*(ush*)&buf != 0) return buf; } else { buf = farmalloc(bsize + 16L); } if (buf == NULL || next_ptr >= MAX_PTR) return NULL; table[next_ptr].org_ptr = buf; /* Normalize the pointer to seg:0 */ *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; *(ush*)&buf = 0; table[next_ptr++].new_ptr = buf; return buf; } void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { int n; (void)opaque; if (*(ush*)&ptr != 0) { /* object < 64K */ farfree(ptr); return; } /* Find the original pointer */ for (n = 0; n < next_ptr; n++) { if (ptr != table[n].new_ptr) continue; farfree(table[n].org_ptr); while (++n < next_ptr) { table[n-1] = table[n]; } next_ptr--; return; } Assert(0, "zcfree: ptr not found"); } #endif /* __TURBOC__ */ #ifdef M_I86 /* Microsoft C in 16-bit mode */ # define MY_ZCALLOC #if (!defined(_MSC_VER) || (_MSC_VER <= 600)) # define _halloc halloc # define _hfree hfree #endif voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) { (void)opaque; return _halloc((long)items, size); } void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { (void)opaque; _hfree(ptr); } #endif /* M_I86 */ #endif /* SYS16BIT */ #ifndef MY_ZCALLOC /* Any system without a special alloc function */ #ifndef STDC extern voidp malloc OF((uInt size)); extern voidp calloc OF((uInt items, uInt size)); extern void free OF((voidpf ptr)); #endif voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) voidpf opaque; unsigned items; unsigned size; { (void)opaque; return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : (voidpf)calloc(items, size); } void ZLIB_INTERNAL zcfree (opaque, ptr) voidpf opaque; voidpf ptr; { (void)opaque; free(ptr); } #endif /* MY_ZCALLOC */ #endif /* !Z_SOLO */ trusted-firmware-a-2.2/lib/zlib/zutil.h000066400000000000000000000157271355360272700201530ustar00rootroot00000000000000/* zutil.h -- internal interface and configuration of the compression library * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ /* WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Applications should only use zlib.h. */ /* @(#) $Id$ */ #ifndef ZUTIL_H #define ZUTIL_H #ifdef HAVE_HIDDEN # define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) #else # define ZLIB_INTERNAL #endif #include "zlib.h" #if defined(STDC) && !defined(Z_SOLO) # if !(defined(_WIN32_WCE) && defined(_MSC_VER)) # include # endif # include # include #endif #ifdef Z_SOLO typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ #endif #ifndef local # define local static #endif /* since "static" is used to mean two completely different things in C, we define "local" for the non-static meaning of "static", for readability (compile with -Dlocal if your debugger can't find static symbols) */ typedef unsigned char uch; typedef uch FAR uchf; typedef unsigned short ush; typedef ush FAR ushf; typedef unsigned long ulg; extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* (size given to avoid silly warnings with Visual C++) */ #define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] #define ERR_RETURN(strm,err) \ return (strm->msg = ERR_MSG(err), (err)) /* To be used only when the state is known to be valid */ /* common constants */ #ifndef DEF_WBITS # define DEF_WBITS MAX_WBITS #endif /* default windowBits for decompression. MAX_WBITS is for compression only */ #if MAX_MEM_LEVEL >= 8 # define DEF_MEM_LEVEL 8 #else # define DEF_MEM_LEVEL MAX_MEM_LEVEL #endif /* default memLevel */ #define STORED_BLOCK 0 #define STATIC_TREES 1 #define DYN_TREES 2 /* The three kinds of block type */ #define MIN_MATCH 3 #define MAX_MATCH 258 /* The minimum and maximum match lengths */ #define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ /* target dependencies */ #if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) # define OS_CODE 0x00 # ifndef Z_SOLO # if defined(__TURBOC__) || defined(__BORLANDC__) # if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) /* Allow compilation with ANSI keywords only enabled */ void _Cdecl farfree( void *block ); void *_Cdecl farmalloc( unsigned long nbytes ); # else # include # endif # else /* MSC or DJGPP */ # include # endif # endif #endif #ifdef AMIGA # define OS_CODE 1 #endif #if defined(VAXC) || defined(VMS) # define OS_CODE 2 # define F_OPEN(name, mode) \ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") #endif #ifdef __370__ # if __TARGET_LIB__ < 0x20000000 # define OS_CODE 4 # elif __TARGET_LIB__ < 0x40000000 # define OS_CODE 11 # else # define OS_CODE 8 # endif #endif #if defined(ATARI) || defined(atarist) # define OS_CODE 5 #endif #ifdef OS2 # define OS_CODE 6 # if defined(M_I86) && !defined(Z_SOLO) # include # endif #endif #if defined(MACOS) || defined(TARGET_OS_MAC) # define OS_CODE 7 # ifndef Z_SOLO # if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os # include /* for fdopen */ # else # ifndef fdopen # define fdopen(fd,mode) NULL /* No fdopen() */ # endif # endif # endif #endif #ifdef __acorn # define OS_CODE 13 #endif #if defined(WIN32) && !defined(__CYGWIN__) # define OS_CODE 10 #endif #ifdef _BEOS_ # define OS_CODE 16 #endif #ifdef __TOS_OS400__ # define OS_CODE 18 #endif #ifdef __APPLE__ # define OS_CODE 19 #endif #if defined(_BEOS_) || defined(RISCOS) # define fdopen(fd,mode) NULL /* No fdopen() */ #endif #if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX # if defined(_WIN32_WCE) # define fdopen(fd,mode) NULL /* No fdopen() */ # ifndef _PTRDIFF_T_DEFINED typedef int ptrdiff_t; # define _PTRDIFF_T_DEFINED # endif # else # define fdopen(fd,type) _fdopen(fd,type) # endif #endif #if defined(__BORLANDC__) && !defined(MSDOS) #pragma warn -8004 #pragma warn -8008 #pragma warn -8066 #endif /* provide prototypes for these when building zlib without LFS */ #if !defined(_WIN32) && \ (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); #endif /* common defaults */ #ifndef OS_CODE # define OS_CODE 3 /* assume Unix */ #endif #ifndef F_OPEN # define F_OPEN(name, mode) fopen((name), (mode)) #endif /* functions */ #if defined(pyr) || defined(Z_SOLO) # define NO_MEMCPY #endif #if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) /* Use our own functions for small and medium model with MSC <= 5.0. * You may have to use the same strategy for Borland C (untested). * The __SC__ check is for Symantec. */ # define NO_MEMCPY #endif #if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) # define HAVE_MEMCPY #endif #ifdef HAVE_MEMCPY # ifdef SMALL_MEDIUM /* MSDOS small or medium model */ # define zmemcpy _fmemcpy # define zmemcmp _fmemcmp # define zmemzero(dest, len) _fmemset(dest, 0, len) # else # define zmemcpy memcpy # define zmemcmp memcmp # define zmemzero(dest, len) memset(dest, 0, len) # endif #else void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); #endif /* Diagnostic functions */ #ifdef ZLIB_DEBUG # include extern int ZLIB_INTERNAL z_verbose; extern void ZLIB_INTERNAL z_error OF((char *m)); # define Assert(cond,msg) {if(!(cond)) z_error(msg);} # define Trace(x) {if (z_verbose>=0) fprintf x ;} # define Tracev(x) {if (z_verbose>0) fprintf x ;} # define Tracevv(x) {if (z_verbose>1) fprintf x ;} # define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} # define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} #else # define Assert(cond,msg) # define Trace(x) # define Tracev(x) # define Tracevv(x) # define Tracec(c,x) # define Tracecv(c,x) #endif #ifndef Z_SOLO voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, unsigned size)); void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); #endif #define ZALLOC(strm, items, size) \ (*((strm)->zalloc))((strm)->opaque, (items), (size)) #define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) #define TRY_FREE(s, p) {if (p) ZFREE(s, p);} /* Reverse the bytes in a 32-bit value */ #define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) #endif /* ZUTIL_H */ trusted-firmware-a-2.2/license.rst000066400000000000000000000000251355360272700172620ustar00rootroot00000000000000See docs/license.rst trusted-firmware-a-2.2/make_helpers/000077500000000000000000000000001355360272700175505ustar00rootroot00000000000000trusted-firmware-a-2.2/make_helpers/armv7-a-cpus.mk000066400000000000000000000035401355360272700223250ustar00rootroot00000000000000# # Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ifneq (${ARCH},aarch32) $(error ARM_ARCH_MAJOR=7 mandates ARCH=aarch32) endif # For ARMv7, set march32 from platform directive ARMV7_CORTEX_Ax=yes # and ARM_WITH_NEON=yes/no. # # GCC and Clang require -march=armv7-a for C-A9 and -march=armv7ve for C-A15. # armClang requires -march=armv7-a for all ARMv7 Cortex-A. To comply with # all, just drop -march and supply only -mcpu. # Platform can override march32-directive through MARCH32_DIRECTIVE ifdef MARCH32_DIRECTIVE march32-directive := $(MARCH32_DIRECTIVE) else march32-set-${ARM_CORTEX_A5} := -mcpu=cortex-a5 march32-set-${ARM_CORTEX_A7} := -mcpu=cortex-a7 march32-set-${ARM_CORTEX_A9} := -mcpu=cortex-a9 march32-set-${ARM_CORTEX_A12} := -mcpu=cortex-a12 march32-set-${ARM_CORTEX_A15} := -mcpu=cortex-a15 march32-set-${ARM_CORTEX_A17} := -mcpu=cortex-a17 march32-neon-$(ARM_WITH_NEON) := -mfpu=neon # default to -march=armv7-a as target directive march32-set-yes ?= -march=armv7-a march32-directive := ${march32-set-yes} ${march32-neon-yes} endif # Platform may override these extension support directives: # # ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING # Defined if core supports the Large Page Addressing extension. # # ARMV7_SUPPORTS_VIRTUALIZATION # Defined if ARMv7 core supports the Virtualization extension. # # ARMV7_SUPPORTS_GENERIC_TIMER # Defined if ARMv7 core supports the Generic Timer extension. ifeq ($(filter yes,$(ARM_CORTEX_A7) $(ARM_CORTEX_A12) $(ARM_CORTEX_A15) $(ARM_CORTEX_A17)),yes) $(eval $(call add_define,ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING)) $(eval $(call add_define,ARMV7_SUPPORTS_VIRTUALIZATION)) $(eval $(call add_define,ARMV7_SUPPORTS_GENERIC_TIMER)) $(eval $(call add_define,ARMV7_SUPPORTS_VFP)) endif ifeq ($(ARM_CORTEX_A5),yes) $(eval $(call add_define,ARM_CORTEX_A5)) endif trusted-firmware-a-2.2/make_helpers/build_env.mk000066400000000000000000000054471355360272700220620ustar00rootroot00000000000000# # Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # This file contains the logic to identify and include any relevant # build environment specific make include files. ifndef BUILD_ENV_MK BUILD_ENV_MK := $(lastword $(MAKEFILE_LIST)) # Block possible built-in command definitions that are not fully portable. # This traps occurences that need replacing with our OS portable macros COPY := $$(error "Replace COPY with call to SHELL_COPY or SHELL_COPY_TREE.") CP := $$(error "Replace CP with call to SHELL_COPY or SHELL_COPY_TREE.") DEL := $$(error "Replace DEL with call to SHELL_DELETE.") MD := $$(error "Replace MD with call to MAKE_PREREQ_DIR.") MKDIR := $$(error "Replace MKDIR with call to MAKE_PREREQ_DIR.") RD := $$(error "Replace RD with call to SHELL_REMOVE_DIR.") RM := $$(error "Replace RM with call to SHELL_DELETE.") RMDIR := $$(error "Replace RMDIR with call to SHELL_REMOVE_DIR.") ENV_FILE_TO_INCLUDE := unix.mk ifdef OSTYPE ifneq ($(findstring ${OSTYPE}, cygwin),) ENV_FILE_TO_INCLUDE := cygwin.mk else ifneq ($(findstring ${OSTYPE}, MINGW32 mingw msys),) ENV_FILE_TO_INCLUDE := msys.mk endif endif else ifdef MSYSTEM # Although the MINGW MSYS shell sets OSTYPE as msys in its environment, # it does not appear in the GNU make view of environment variables. # We use MSYSTEM as an alternative, as that is seen by make ifneq ($(findstring ${MSYSTEM}, MINGW32 mingw msys),) OSTYPE ?= msys ENV_FILE_TO_INCLUDE := msys.mk endif else ifdef OS ifneq ($(findstring ${OS}, Windows_NT),) ENV_FILE_TO_INCLUDE := windows.mk endif endif endif endif include ${MAKE_HELPERS_DIRECTORY}${ENV_FILE_TO_INCLUDE} ENV_FILE_TO_INCLUDE := ifndef SHELL_COPY $(error "SHELL_COPY not defined for build environment.") endif ifndef SHELL_COPY_TREE $(error "SHELL_COPY_TREE not defined for build environment.") endif ifndef SHELL_DELETE_ALL $(error "SHELL_DELETE_ALL not defined for build environment.") endif ifndef SHELL_DELETE $(error "SHELL_DELETE not defined for build environment.") endif ifndef MAKE_PREREQ_DIR $(error "MAKE_PREREQ_DIR not defined for build environment.") endif ifndef SHELL_REMOVE_DIR $(error "SHELL_REMOVE_DIR not defined for build environment.") endif endif trusted-firmware-a-2.2/make_helpers/build_macros.mk000066400000000000000000000434441355360272700225550ustar00rootroot00000000000000# # Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Report an error if the eval make function is not available. $(eval eval_available := T) ifneq (${eval_available},T) $(error This makefile only works with a Make program that supports $$(eval)) endif # Some utility macros for manipulating awkward (whitespace) characters. blank := space :=${blank} ${blank} # A user defined function to recursively search for a filename below a directory # $1 is the directory root of the recursive search (blank for current directory). # $2 is the file name to search for. define rwildcard $(strip $(foreach d,$(wildcard ${1}*),$(call rwildcard,${d}/,${2}) $(filter $(subst *,%,%${2}),${d}))) endef # This table is used in converting lower case to upper case. uppercase_table:=a,A b,B c,C d,D e,E f,F g,G h,H i,I j,J k,K l,L m,M n,N o,O p,P q,Q r,R s,S t,T u,U v,V w,W x,X y,Y z,Z # Internal macro used for converting lower case to upper case. # $(1) = upper case table # $(2) = String to convert define uppercase_internal $(if $(1),$$(subst $(firstword $(1)),$(call uppercase_internal,$(wordlist 2,$(words $(1)),$(1)),$(2))),$(2)) endef # A macro for converting a string to upper case # $(1) = String to convert define uppercase $(eval uppercase_result:=$(call uppercase_internal,$(uppercase_table),$(1)))$(uppercase_result) endef # Convenience function for adding build definitions # $(eval $(call add_define,FOO)) will have: # -DFOO if $(FOO) is empty; -DFOO=$(FOO) otherwise define add_define DEFINES += -D$(1)$(if $(value $(1)),=$(value $(1)),) endef # Convenience function for adding build definitions # $(eval $(call add_define_val,FOO,BAR)) will have: # -DFOO=BAR define add_define_val DEFINES += -D$(1)=$(2) endef # Convenience function for verifying option has a boolean value # $(eval $(call assert_boolean,FOO)) will assert FOO is 0 or 1 define assert_boolean $(if $(filter-out 0 1,$($1)),$(error $1 must be boolean)) endef 0-9 := 0 1 2 3 4 5 6 7 8 9 # Function to verify that a given option $(1) contains a numeric value define assert_numeric $(if $($(1)),,$(error $(1) must not be empty)) $(eval __numeric := $($(1))) $(foreach d,$(0-9),$(eval __numeric := $(subst $(d),,$(__numeric)))) $(if $(__numeric),$(error $(1) must be numeric)) endef # IMG_LINKERFILE defines the linker script corresponding to a BL stage # $(1) = BL stage (2, 30, 31, 32, 33) define IMG_LINKERFILE ${BUILD_DIR}/bl$(1).ld endef # IMG_MAPFILE defines the output file describing the memory map corresponding # to a BL stage # $(1) = BL stage (2, 30, 31, 32, 33) define IMG_MAPFILE ${BUILD_DIR}/bl$(1).map endef # IMG_ELF defines the elf file corresponding to a BL stage # $(1) = BL stage (2, 30, 31, 32, 33) define IMG_ELF ${BUILD_DIR}/bl$(1).elf endef # IMG_DUMP defines the symbols dump file corresponding to a BL stage # $(1) = BL stage (2, 30, 31, 32, 33) define IMG_DUMP ${BUILD_DIR}/bl$(1).dump endef # IMG_BIN defines the default image file corresponding to a BL stage # $(1) = BL stage (2, 30, 31, 32, 33) define IMG_BIN ${BUILD_PLAT}/bl$(1).bin endef # TOOL_ADD_PAYLOAD appends the command line arguments required by fiptool to # package a new payload and/or by cert_create to generate certificate. # Optionally, it adds the dependency on this payload # $(1) = payload filename (i.e. bl31.bin) # $(2) = command line option for the specified payload (i.e. --soc-fw) # $(3) = tool target dependency (optional) (ex. build/fvp/release/bl31.bin) # $(4) = FIP prefix (optional) (if FWU_, target is fwu_fip instead of fip) define TOOL_ADD_PAYLOAD $(4)FIP_ARGS += $(2) $(1) $(if $(3),$(4)FIP_DEPS += $(3)) $(4)CRT_ARGS += $(2) $(1) $(if $(3),$(4)CRT_DEPS += $(3)) endef # TOOL_ADD_IMG_PAYLOAD works like TOOL_ADD_PAYLOAD, but applies image filters # before passing them to host tools if BL*_PRE_TOOL_FILTER is defined. # $(1) = image_type (scp_bl2, bl33, etc.) # $(2) = payload filepath (ex. build/fvp/release/bl31.bin) # $(3) = command line option for the specified payload (ex. --soc-fw) # $(4) = tool target dependency (optional) (ex. build/fvp/release/bl31.bin) # $(5) = FIP prefix (optional) (if FWU_, target is fwu_fip instead of fip) define TOOL_ADD_IMG_PAYLOAD $(eval PRE_TOOL_FILTER := $($(call uppercase,$(1))_PRE_TOOL_FILTER)) ifneq ($(PRE_TOOL_FILTER),) $(eval PROCESSED_PATH := $(BUILD_PLAT)/$(1).bin$($(PRE_TOOL_FILTER)_SUFFIX)) $(call $(PRE_TOOL_FILTER)_RULE,$(PROCESSED_PATH),$(2)) $(PROCESSED_PATH): $(4) $(call TOOL_ADD_PAYLOAD,$(PROCESSED_PATH),$(3),$(PROCESSED_PATH),$(5)) else $(call TOOL_ADD_PAYLOAD,$(2),$(3),$(4),$(5)) endif endef # CERT_ADD_CMD_OPT adds a new command line option to the cert_create invocation # $(1) = parameter filename # $(2) = cert_create command line option for the specified parameter # $(3) = FIP prefix (optional) (if FWU_, target is fwu_fip instead of fip) define CERT_ADD_CMD_OPT $(3)CRT_ARGS += $(2) $(1) endef # TOOL_ADD_IMG allows the platform to specify an external image to be packed # in the FIP and/or for which certificate is generated. It also adds a # dependency on the image file, aborting the build if the file does not exist. # $(1) = image_type (scp_bl2, bl33, etc.) # $(2) = command line option for fiptool (--scp-fw, --nt-fw, etc) # $(3) = FIP prefix (optional) (if FWU_, target is fwu_fip instead of fip) # Example: # $(eval $(call TOOL_ADD_IMG,bl33,--nt-fw)) define TOOL_ADD_IMG # Build option to specify the image filename (SCP_BL2, BL33, etc) # This is the uppercase form of the first parameter $(eval _V := $(call uppercase,$(1))) $(3)CRT_DEPS += check_$(1) $(3)FIP_DEPS += check_$(1) $(call TOOL_ADD_IMG_PAYLOAD,$(1),$(value $(_V)),$(2),,$(3)) .PHONY: check_$(1) check_$(1): $$(if $(value $(_V)),,$$(error "Platform '${PLAT}' requires $(_V). Please set $(_V) to point to the right file")) $$(if $(wildcard $(value $(_V))),,$$(error '$(_V)=$(value $(_V))' was specified, but '$(value $(_V))' does not exist)) endef ################################################################################ # Generic image processing filters ################################################################################ # GZIP define GZIP_RULE $(1): $(2) $(ECHO) " GZIP $$@" $(Q)gzip -n -f -9 $$< --stdout > $$@ endef GZIP_SUFFIX := .gz ################################################################################ # Auxiliary macros to build TF images from sources ################################################################################ MAKE_DEP = -Wp,-MD,$(DEP) -MT $$@ -MP # MAKE_C_LIB builds a C source file and generates the dependency file # $(1) = output directory # $(2) = source file (%.c) # $(3) = library name define MAKE_C_LIB $(eval OBJ := $(1)/$(patsubst %.c,%.o,$(notdir $(2)))) $(eval DEP := $(patsubst %.o,%.d,$(OBJ))) $(OBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | lib$(3)_dirs $$(ECHO) " CC $$<" $$(Q)$$(CC) $$(TF_CFLAGS) $$(CFLAGS) $(MAKE_DEP) -c $$< -o $$@ -include $(DEP) endef # MAKE_S_LIB builds an assembly source file and generates the dependency file # $(1) = output directory # $(2) = source file (%.S) # $(3) = library name define MAKE_S_LIB $(eval OBJ := $(1)/$(patsubst %.S,%.o,$(notdir $(2)))) $(eval DEP := $(patsubst %.o,%.d,$(OBJ))) $(OBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | lib$(3)_dirs $$(ECHO) " AS $$<" $$(Q)$$(AS) $$(ASFLAGS) $(MAKE_DEP) -c $$< -o $$@ -include $(DEP) endef # MAKE_C builds a C source file and generates the dependency file # $(1) = output directory # $(2) = source file (%.c) # $(3) = BL stage (2, 2u, 30, 31, 32, 33) define MAKE_C $(eval OBJ := $(1)/$(patsubst %.c,%.o,$(notdir $(2)))) $(eval DEP := $(patsubst %.o,%.d,$(OBJ))) $(eval IMAGE := IMAGE_BL$(call uppercase,$(3))) $(eval BL_CFLAGS := $(BL$(call uppercase,$(3))_CFLAGS)) $(OBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | bl$(3)_dirs $$(ECHO) " CC $$<" $$(Q)$$(CC) $$(TF_CFLAGS) $$(CFLAGS) $(BL_CFLAGS) -D$(IMAGE) $(MAKE_DEP) -c $$< -o $$@ -include $(DEP) endef # MAKE_S builds an assembly source file and generates the dependency file # $(1) = output directory # $(2) = assembly file (%.S) # $(3) = BL stage (2, 2u, 30, 31, 32, 33) define MAKE_S $(eval OBJ := $(1)/$(patsubst %.S,%.o,$(notdir $(2)))) $(eval DEP := $(patsubst %.o,%.d,$(OBJ))) $(eval IMAGE := IMAGE_BL$(call uppercase,$(3))) $(OBJ): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | bl$(3)_dirs $$(ECHO) " AS $$<" $$(Q)$$(AS) $$(ASFLAGS) -D$(IMAGE) $(MAKE_DEP) -c $$< -o $$@ -include $(DEP) endef # MAKE_LD generate the linker script using the C preprocessor # $(1) = output linker script # $(2) = input template # $(3) = BL stage (2, 2u, 30, 31, 32, 33) define MAKE_LD $(eval DEP := $(1).d) $(eval IMAGE := IMAGE_BL$(call uppercase,$(3))) $(1): $(2) $(filter-out %.d,$(MAKEFILE_LIST)) | bl$(3)_dirs $$(ECHO) " PP $$<" $$(Q)$$(CPP) $$(CPPFLAGS) $(TF_CFLAGS_$(ARCH)) -P -x assembler-with-cpp -D__LINKER__ $(MAKE_DEP) -D$(IMAGE) -o $$@ $$< -include $(DEP) endef # MAKE_LIB_OBJS builds both C and assembly source files # $(1) = output directory # $(2) = list of source files # $(3) = name of the library define MAKE_LIB_OBJS $(eval C_OBJS := $(filter %.c,$(2))) $(eval REMAIN := $(filter-out %.c,$(2))) $(eval $(foreach obj,$(C_OBJS),$(call MAKE_C_LIB,$(1),$(obj),$(3)))) $(eval S_OBJS := $(filter %.S,$(REMAIN))) $(eval REMAIN := $(filter-out %.S,$(REMAIN))) $(eval $(foreach obj,$(S_OBJS),$(call MAKE_S_LIB,$(1),$(obj),$(3)))) $(and $(REMAIN),$(error Unexpected source files present: $(REMAIN))) endef # MAKE_OBJS builds both C and assembly source files # $(1) = output directory # $(2) = list of source files (both C and assembly) # $(3) = BL stage (2, 30, 31, 32, 33) define MAKE_OBJS $(eval C_OBJS := $(filter %.c,$(2))) $(eval REMAIN := $(filter-out %.c,$(2))) $(eval $(foreach obj,$(C_OBJS),$(call MAKE_C,$(1),$(obj),$(3)))) $(eval S_OBJS := $(filter %.S,$(REMAIN))) $(eval REMAIN := $(filter-out %.S,$(REMAIN))) $(eval $(foreach obj,$(S_OBJS),$(call MAKE_S,$(1),$(obj),$(3)))) $(and $(REMAIN),$(error Unexpected source files present: $(REMAIN))) endef # NOTE: The line continuation '\' is required in the next define otherwise we # end up with a line-feed characer at the end of the last c filename. # Also bear this issue in mind if extending the list of supported filetypes. define SOURCES_TO_OBJS $(notdir $(patsubst %.c,%.o,$(filter %.c,$(1)))) \ $(notdir $(patsubst %.S,%.o,$(filter %.S,$(1)))) endef # Allow overriding the timestamp, for example for reproducible builds, or to # synchronize timestamps across multiple projects. # This must be set to a C string (including quotes where applicable). BUILD_MESSAGE_TIMESTAMP ?= __TIME__", "__DATE__ .PHONY: libraries # MAKE_LIB_DIRS macro defines the target for the directory where # libraries are created define MAKE_LIB_DIRS $(eval LIB_DIR := ${BUILD_PLAT}/lib) $(eval ROMLIB_DIR := ${BUILD_PLAT}/romlib) $(eval LIBWRAPPER_DIR := ${BUILD_PLAT}/libwrapper) $(eval $(call MAKE_PREREQ_DIR,${LIB_DIR},${BUILD_PLAT})) $(eval $(call MAKE_PREREQ_DIR,${ROMLIB_DIR},${BUILD_PLAT})) $(eval $(call MAKE_PREREQ_DIR,${LIBWRAPPER_DIR},${BUILD_PLAT})) endef # MAKE_LIB macro defines the targets and options to build each BL image. # Arguments: # $(1) = Library name define MAKE_LIB $(eval BUILD_DIR := ${BUILD_PLAT}/lib$(1)) $(eval LIB_DIR := ${BUILD_PLAT}/lib) $(eval ROMLIB_DIR := ${BUILD_PLAT}/romlib) $(eval SOURCES := $(LIB$(call uppercase,$(1))_SRCS)) $(eval OBJS := $(addprefix $(BUILD_DIR)/,$(call SOURCES_TO_OBJS,$(SOURCES)))) $(eval $(call MAKE_PREREQ_DIR,${BUILD_DIR},${BUILD_PLAT})) $(eval $(call MAKE_LIB_OBJS,$(BUILD_DIR),$(SOURCES),$(1))) .PHONY : lib${1}_dirs lib${1}_dirs: | ${BUILD_DIR} ${LIB_DIR} ${ROMLIB_DIR} ${LIBWRAPPER_DIR} libraries: ${LIB_DIR}/lib$(1).a ifneq ($(findstring armlink,$(notdir $(LD))),) LDPATHS = --userlibpath=${LIB_DIR} LDLIBS += --library=$(1) else LDPATHS = -L${LIB_DIR} LDLIBS += -l$(1) endif ifeq ($(USE_ROMLIB),1) LIBWRAPPER = -lwrappers endif all: ${LIB_DIR}/lib$(1).a ${LIB_DIR}/lib$(1).a: $(OBJS) $$(ECHO) " AR $$@" $$(Q)$$(AR) cr $$@ $$? endef # MAKE_BL macro defines the targets and options to build each BL image. # Arguments: # $(1) = BL stage (2, 2u, 30, 31, 32, 33) # $(2) = FIP command line option (if empty, image will not be included in the FIP) # $(3) = FIP prefix (optional) (if FWU_, target is fwu_fip instead of fip) define MAKE_BL $(eval BUILD_DIR := ${BUILD_PLAT}/bl$(1)) $(eval BL_SOURCES := $(BL$(call uppercase,$(1))_SOURCES)) $(eval SOURCES := $(BL_SOURCES) $(BL_COMMON_SOURCES) $(PLAT_BL_COMMON_SOURCES)) $(eval OBJS := $(addprefix $(BUILD_DIR)/,$(call SOURCES_TO_OBJS,$(SOURCES)))) $(eval LINKERFILE := $(call IMG_LINKERFILE,$(1))) $(eval MAPFILE := $(call IMG_MAPFILE,$(1))) $(eval ELF := $(call IMG_ELF,$(1))) $(eval DUMP := $(call IMG_DUMP,$(1))) $(eval BIN := $(call IMG_BIN,$(1))) $(eval BL_LINKERFILE := $(BL$(call uppercase,$(1))_LINKERFILE)) $(eval BL_LIBS := $(BL$(call uppercase,$(1))_LIBS)) # We use sort only to get a list of unique object directory names. # ordering is not relevant but sort removes duplicates. $(eval TEMP_OBJ_DIRS := $(sort $(dir ${OBJS} ${LINKERFILE}))) # The $(dir ) function leaves a trailing / on the directory names # Rip off the / to match directory names with make rule targets. $(eval OBJ_DIRS := $(patsubst %/,%,$(TEMP_OBJ_DIRS))) # Create generators for object directory structure $(eval $(call MAKE_PREREQ_DIR,${BUILD_DIR},${BUILD_PLAT})) $(eval $(foreach objd,${OBJ_DIRS},$(call MAKE_PREREQ_DIR,${objd},${BUILD_DIR}))) .PHONY : bl${1}_dirs # We use order-only prerequisites to ensure that directories are created, # but do not cause re-builds every time a file is written. bl${1}_dirs: | ${OBJ_DIRS} $(eval $(call MAKE_OBJS,$(BUILD_DIR),$(SOURCES),$(1))) $(eval $(call MAKE_LD,$(LINKERFILE),$(BL_LINKERFILE),$(1))) ifeq ($(USE_ROMLIB),1) $(ELF): romlib.bin endif $(ELF): $(OBJS) $(LINKERFILE) | bl$(1)_dirs libraries $(BL_LIBS) $$(ECHO) " LD $$@" ifdef MAKE_BUILD_STRINGS $(call MAKE_BUILD_STRINGS, $(BUILD_DIR)/build_message.o) else @echo 'const char build_message[] = "Built : "$(BUILD_MESSAGE_TIMESTAMP); \ const char version_string[] = "${VERSION_STRING}";' | \ $$(CC) $$(TF_CFLAGS) $$(CFLAGS) -xc -c - -o $(BUILD_DIR)/build_message.o endif ifneq ($(findstring armlink,$(notdir $(LD))),) $$(Q)$$(LD) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) --entry=bl${1}_entrypoint \ --predefine="-D__LINKER__=$(__LINKER__)" \ --predefine="-DTF_CFLAGS=$(TF_CFLAGS)" \ --map --list="$(MAPFILE)" --scatter=${PLAT_DIR}/scat/bl${1}.scat \ $(LDPATHS) $(LIBWRAPPER) $(LDLIBS) $(BL_LIBS) \ $(BUILD_DIR)/build_message.o $(OBJS) else $$(Q)$$(LD) -o $$@ $$(TF_LDFLAGS) $$(LDFLAGS) -Map=$(MAPFILE) \ --script $(LINKERFILE) $(BUILD_DIR)/build_message.o \ $(OBJS) $(LDPATHS) $(LIBWRAPPER) $(LDLIBS) $(BL_LIBS) endif ifeq ($(DISABLE_BIN_GENERATION),1) @${ECHO_BLANK_LINE} @echo "Built $$@ successfully" @${ECHO_BLANK_LINE} endif $(DUMP): $(ELF) $${ECHO} " OD $$@" $${Q}$${OD} -dx $$< > $$@ $(BIN): $(ELF) $${ECHO} " BIN $$@" $$(Q)$$(OC) -O binary $$< $$@ @${ECHO_BLANK_LINE} @echo "Built $$@ successfully" @${ECHO_BLANK_LINE} .PHONY: bl$(1) ifeq ($(DISABLE_BIN_GENERATION),1) bl$(1): $(ELF) $(DUMP) else bl$(1): $(BIN) $(DUMP) endif all: bl$(1) $(if $(2),$(call TOOL_ADD_IMG_PAYLOAD,bl$(1),$(BIN),--$(2),$(BIN),$(3))) endef # Convert device tree source file names to matching blobs # $(1) = input dts define SOURCES_TO_DTBS $(notdir $(patsubst %.dts,%.dtb,$(filter %.dts,$(1)))) endef # MAKE_FDT_DIRS macro creates the prerequisite directories that host the # FDT binaries # $(1) = output directory # $(2) = input dts define MAKE_FDT_DIRS $(eval DTBS := $(addprefix $(1)/,$(call SOURCES_TO_DTBS,$(2)))) $(eval TEMP_DTB_DIRS := $(sort $(dir ${DTBS}))) # The $(dir ) function leaves a trailing / on the directory names # Rip off the / to match directory names with make rule targets. $(eval DTB_DIRS := $(patsubst %/,%,$(TEMP_DTB_DIRS))) $(eval $(foreach objd,${DTB_DIRS},$(call MAKE_PREREQ_DIR,${objd},${BUILD_DIR}))) fdt_dirs: ${DTB_DIRS} endef # MAKE_DTB generate the Flattened device tree binary # $(1) = output directory # $(2) = input dts define MAKE_DTB # List of DTB file(s) to generate, based on DTS file basename list $(eval 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))))) # 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 $$<" $(eval DTBS := $(addprefix $(1)/,$(call SOURCES_TO_DTBS,$(2)))) $$(Q)$$(PP) $$(DTC_CPPFLAGS) -MT $(DTBS) -MMD -MF $(DTSDEP) -o $(DPRE) $$< $${ECHO} " DTC $$<" $$(Q)$$(DTC) $$(DTC_FLAGS) -i fdts -d $(DTBDEP) -o $$@ $(DPRE) -include $(DTBDEP) -include $(DTSDEP) endef # MAKE_DTBS builds flattened device tree sources # $(1) = output directory # $(2) = list of flattened device tree source files define MAKE_DTBS $(eval DOBJS := $(filter %.dts,$(2))) $(eval REMAIN := $(filter-out %.dts,$(2))) $(and $(REMAIN),$(error FDT_SOURCES contain non-DTS files: $(REMAIN))) $(eval $(foreach obj,$(DOBJS),$(call MAKE_DTB,$(1),$(obj)))) $(eval $(call MAKE_FDT_DIRS,$(1),$(2))) dtbs: $(DTBS) all: dtbs endef trusted-firmware-a-2.2/make_helpers/cygwin.mk000066400000000000000000000007161355360272700214050ustar00rootroot00000000000000# # Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # # OS specific definitions for builds in a Cygwin environment. # Cygwin allows us to use unix style commands on a windows platform. ifndef CYGWIN_MK CYGWIN_MK := $(lastword $(MAKEFILE_LIST)) include ${MAKE_HELPERS_DIRECTORY}unix.mk # In cygwin executable files have the Windows .exe extension type. BIN_EXT := .exe endif trusted-firmware-a-2.2/make_helpers/defaults.mk000066400000000000000000000152471355360272700217210ustar00rootroot00000000000000# # Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Default, static values for build variables, listed in alphabetic order. # Dependencies between build options, if any, are handled in the top-level # Makefile, after this file is included. This ensures that the former is better # poised to handle dependencies, as all build variables would have a default # value by then. # Use T32 by default AARCH32_INSTRUCTION_SET := T32 # The AArch32 Secure Payload to be built as BL32 image AARCH32_SP := none # The Target build architecture. Supported values are: aarch64, aarch32. ARCH := aarch64 # ARM Architecture major and minor versions: 8.0 by default. ARM_ARCH_MAJOR := 8 ARM_ARCH_MINOR := 0 # Base commit to perform code check on BASE_COMMIT := origin/master # Execute BL2 at EL3 BL2_AT_EL3 := 0 # BL2 image is stored in XIP memory, for now, this option is only supported # when BL2_AT_EL3 is 1. BL2_IN_XIP_MEM := 0 # Do dcache invalidate upon BL2 entry at EL3 BL2_INV_DCACHE := 1 # Select the branch protection features to use. BRANCH_PROTECTION := 0 # By default, consider that the platform may release several CPUs out of reset. # The platform Makefile is free to override this value. COLD_BOOT_SINGLE_CPU := 0 # Flag to compile in coreboot support code. Exclude by default. The coreboot # Makefile system will set this when compiling TF as part of a coreboot image. COREBOOT := 0 # For Chain of Trust CREATE_KEYS := 1 # Build flag to include AArch32 registers in cpu context save and restore during # world switch. This flag must be set to 0 for AArch64-only platforms. CTX_INCLUDE_AARCH32_REGS := 1 # Include FP registers in cpu context CTX_INCLUDE_FPREGS := 0 # Include pointer authentication (ARMv8.3-PAuth) registers in cpu context. This # must be set to 1 if the platform wants to use this feature in the Secure # world. It is not needed to use it in the Non-secure world. CTX_INCLUDE_PAUTH_REGS := 0 # Debug build DEBUG := 0 # Build platform DEFAULT_PLAT := fvp # Disable the generation of the binary image (ELF only). DISABLE_BIN_GENERATION := 0 # Enable capability to disable authentication dynamically. Only meant for # development platforms. DYN_DISABLE_AUTH := 0 # Build option to enable MPAM for lower ELs ENABLE_MPAM_FOR_LOWER_ELS := 0 # Flag to Enable Position Independant support (PIE) ENABLE_PIE := 0 # Flag to enable Performance Measurement Framework ENABLE_PMF := 0 # Flag to enable PSCI STATs functionality ENABLE_PSCI_STAT := 0 # Flag to enable runtime instrumentation using PMF ENABLE_RUNTIME_INSTRUMENTATION := 0 # Flag to enable stack corruption protection ENABLE_STACK_PROTECTOR := 0 # Flag to enable exception handling in EL3 EL3_EXCEPTION_HANDLING := 0 # Flag to enable Branch Target Identification. # Internal flag not meant for direct setting. # Use BRANCH_PROTECTION to enable BTI. ENABLE_BTI := 0 # Flag to enable Pointer Authentication. # Internal flag not meant for direct setting. # Use BRANCH_PROTECTION to enable PAUTH. ENABLE_PAUTH := 0 # Build flag to treat usage of deprecated platform and framework APIs as error. ERROR_DEPRECATED := 0 # Fault injection support FAULT_INJECTION_SUPPORT := 0 # Byte alignment that each component in FIP is aligned to FIP_ALIGN := 0 # Default FIP file name FIP_NAME := fip.bin # Default FWU_FIP file name FWU_FIP_NAME := fwu_fip.bin # For Chain of Trust GENERATE_COT := 0 # Hint platform interrupt control layer that Group 0 interrupts are for EL3. By # default, they are for Secure EL1. GICV2_G0_FOR_EL3 := 0 # Route External Aborts to EL3. Disabled by default; External Aborts are handled # by lower ELs. HANDLE_EA_EL3_FIRST := 0 # Whether system coherency is managed in hardware, without explicit software # operations. HW_ASSISTED_COHERENCY := 0 # Set the default algorithm for the generation of Trusted Board Boot keys KEY_ALG := rsa # NS timer register save and restore NS_TIMER_SWITCH := 0 # Include lib/libc in the final image OVERRIDE_LIBC := 0 # Build PL011 UART driver in minimal generic UART mode PL011_GENERIC_UART := 0 # By default, consider that the platform's reset address is not programmable. # The platform Makefile is free to override this value. PROGRAMMABLE_RESET_ADDRESS := 0 # Flag used to choose the power state format: Extended State-ID or Original PSCI_EXTENDED_STATE_ID := 0 # Enable RAS support RAS_EXTENSION := 0 # By default, BL1 acts as the reset handler, not BL31 RESET_TO_BL31 := 0 # For Chain of Trust SAVE_KEYS := 0 # Software Delegated Exception support SDEI_SUPPORT := 0 # Whether code and read-only data should be put on separate memory pages. The # platform Makefile is free to override this value. SEPARATE_CODE_AND_RODATA := 0 # If the BL31 image initialisation code is recalimed after use for the secondary # cores stack RECLAIM_INIT_CODE := 0 # SPD choice SPD := none # For including the Secure Partition Manager ENABLE_SPM := 0 # Use the SPM based on MM SPM_MM := 1 # Flag to introduce an infinite loop in BL1 just before it exits into the next # image. This is meant to help debugging the post-BL2 phase. SPIN_ON_BL1_EXIT := 0 # Flags to build TF with Trusted Boot support TRUSTED_BOARD_BOOT := 0 # Build option to choose whether Trusted Firmware uses Coherent memory or not. USE_COHERENT_MEM := 1 # Build option to choose whether Trusted Firmware uses library at ROM USE_ROMLIB := 0 # Use tbbr_oid.h instead of platform_oid.h USE_TBBR_DEFS := 1 # Build verbosity V := 0 # Whether to enable D-Cache early during warm boot. This is usually # applicable for platforms wherein interconnect programming is not # required to enable cache coherency after warm reset (eg: single cluster # platforms). WARMBOOT_ENABLE_DCACHE_EARLY := 0 # Build option to enable/disable the Statistical Profiling Extensions ENABLE_SPE_FOR_LOWER_ELS := 1 # SPE is only supported on AArch64 so disable it on AArch32. ifeq (${ARCH},aarch32) override ENABLE_SPE_FOR_LOWER_ELS := 0 endif # Include Memory Tagging Extension registers in cpu context. This must be set # to 1 if the platform wants to use this feature in the Secure world and MTE is # enabled at ELX. CTX_INCLUDE_MTE_REGS := 0 ENABLE_AMU := 0 # By default, enable Scalable Vector Extension if implemented for Non-secure # lower ELs # Note SVE is only supported on AArch64 - therefore do not enable in AArch32 ifneq (${ARCH},aarch32) ENABLE_SVE_FOR_NS := 1 else override ENABLE_SVE_FOR_NS := 0 endif SANITIZE_UB := off # For ARMv8.1 (AArch64) platforms, enabling this option selects the spinlock # implementation variant using the ARMv8.1-LSE compare-and-swap instruction. # Default: disabled USE_SPINLOCK_CAS := 0 trusted-firmware-a-2.2/make_helpers/msys.mk000066400000000000000000000007251355360272700211000ustar00rootroot00000000000000# # Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # # OS specific definitions for builds in a Mingw32 MSYS environment. # Mingw32 allows us to use some unix style commands on a windows platform. ifndef MSYS_MK MSYS_MK := $(lastword $(MAKEFILE_LIST)) include ${MAKE_HELPERS_DIRECTORY}unix.mk # In MSYS executable files have the Windows .exe extension type. BIN_EXT := .exe endif trusted-firmware-a-2.2/make_helpers/plat_helpers.mk000066400000000000000000000031151355360272700225630ustar00rootroot00000000000000# # Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ################################################################################ # Helpers for finding and referencing platform directories ################################################################################ ifndef PLAT_HELPERS_MK PLAT_HELPERS_MK := $(lastword $(MAKEFILE_LIST)) ifeq (${PLAT},) $(error "Error: Unknown platform. Please use PLAT= to specify the platform") endif # TF_PLATFORM_ROOT can be overridden for when building tools directly TF_PLATFORM_ROOT ?= plat/ PLAT_MAKEFILE := platform.mk # Generate the platforms list by recursively searching for all directories # under /plat containing a PLAT_MAKEFILE. Append each platform with a `|` # char and strip out the final '|'. ALL_PLATFORM_MK_FILES := $(call rwildcard,${TF_PLATFORM_ROOT},${PLAT_MAKEFILE}) ALL_PLATFORM_DIRS := $(patsubst %/,%,$(dir ${ALL_PLATFORM_MK_FILES})) ALL_PLATFORMS := $(sort $(notdir ${ALL_PLATFORM_DIRS})) PLAT_MAKEFILE_FULL := $(filter %/${PLAT}/${PLAT_MAKEFILE},${ALL_PLATFORM_MK_FILES}) PLATFORM_LIST := $(subst ${space},|,${ALL_PLATFORMS}) ifeq ($(PLAT_MAKEFILE_FULL),) $(error "Error: Invalid platform. The following platforms are available: ${PLATFORM_LIST}") endif # Record the directory where the platform make file was found. PLAT_DIR := $(dir ${PLAT_MAKEFILE_FULL}) endif trusted-firmware-a-2.2/make_helpers/tbbr/000077500000000000000000000000001355360272700205015ustar00rootroot00000000000000trusted-firmware-a-2.2/make_helpers/tbbr/tbbr_tools.mk000066400000000000000000000075441355360272700232150ustar00rootroot00000000000000# # Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # This file defines the keys and certificates that must be created to establish # a Chain of Trust following the TBBR document. These definitions include the # command line options passed to the cert_create and fiptool commands. # # Expected environment: # # BUILD_PLAT: output directory # NEED_BL32: indicates whether BL32 is needed by the platform # BL2: image filename (optional). Default is IMG_BIN(2) (see macro IMG_BIN) # SCP_BL2: image filename (optional). Default is IMG_BIN(30) # BL31: image filename (optional). Default is IMG_BIN(31) # BL32: image filename (optional). Default is IMG_BIN(32) # BL33: image filename (optional). Default is IMG_BIN(33) # # Build options added by this file: # # KEY_ALG # KEY_SIZE # ROT_KEY # TRUSTED_WORLD_KEY # NON_TRUSTED_WORLD_KEY # SCP_BL2_KEY # BL31_KEY # BL32_KEY # BL33_KEY # # Certificate generation tool default parameters TRUSTED_KEY_CERT := ${BUILD_PLAT}/trusted_key.crt FWU_CERT := ${BUILD_PLAT}/fwu_cert.crt # Default non-volatile counter values (overridable by the platform) TFW_NVCTR_VAL ?= 0 NTFW_NVCTR_VAL ?= 0 # Pass the non-volatile counters to the cert_create tool $(eval $(call CERT_ADD_CMD_OPT,${TFW_NVCTR_VAL},--tfw-nvctr)) $(eval $(call CERT_ADD_CMD_OPT,${NTFW_NVCTR_VAL},--ntfw-nvctr)) # Add Trusted Key certificate to the fiptool and cert_create command line options $(eval $(call TOOL_ADD_PAYLOAD,${TRUSTED_KEY_CERT},--trusted-key-cert)) # Add fwu certificate to the fiptool and cert_create command line options $(eval $(call TOOL_ADD_PAYLOAD,${FWU_CERT},--fwu-cert,,FWU_)) # Add the keys to the cert_create command line options (private keys are NOT # packed in the FIP). Developers can use their own keys by specifying the proper # build option in the command line when building the Trusted Firmware $(if ${KEY_ALG},$(eval $(call CERT_ADD_CMD_OPT,${KEY_ALG},--key-alg))) $(if ${KEY_SIZE},$(eval $(call CERT_ADD_CMD_OPT,${KEY_SIZE},--key-size))) $(if ${HASH_ALG},$(eval $(call CERT_ADD_CMD_OPT,${HASH_ALG},--hash-alg))) $(if ${ROT_KEY},$(eval $(call CERT_ADD_CMD_OPT,${ROT_KEY},--rot-key))) $(if ${ROT_KEY},$(eval $(call CERT_ADD_CMD_OPT,${ROT_KEY},--rot-key,FWU_))) $(if ${TRUSTED_WORLD_KEY},$(eval $(call CERT_ADD_CMD_OPT,${TRUSTED_WORLD_KEY},--trusted-world-key))) $(if ${NON_TRUSTED_WORLD_KEY},$(eval $(call CERT_ADD_CMD_OPT,${NON_TRUSTED_WORLD_KEY},--non-trusted-world-key))) # Add the BL2 CoT (image cert) ifeq (${BL2_AT_EL3}, 0) $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/tb_fw.crt,--tb-fw-cert)) endif # Add the SCP_BL2 CoT (key cert + img cert) ifneq (${SCP_BL2},) $(if ${SCP_BL2_KEY},$(eval $(call CERT_ADD_CMD_OPT,${SCP_BL2_KEY},--scp-fw-key))) $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/scp_fw_content.crt,--scp-fw-cert)) $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/scp_fw_key.crt,--scp-fw-key-cert)) endif ifeq (${ARCH},aarch64) ifeq (${NEED_BL31},yes) # Add the BL31 CoT (key cert + img cert) $(if ${BL31_KEY},$(eval $(call CERT_ADD_CMD_OPT,${BL31_KEY},--soc-fw-key))) $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/soc_fw_content.crt,--soc-fw-cert)) $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/soc_fw_key.crt,--soc-fw-key-cert)) endif endif # Add the BL32 CoT (key cert + img cert) ifeq (${NEED_BL32},yes) $(if ${BL32_KEY},$(eval $(call CERT_ADD_CMD_OPT,${BL32_KEY},--tos-fw-key))) $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/tos_fw_content.crt,--tos-fw-cert)) $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/tos_fw_key.crt,--tos-fw-key-cert)) endif # Add the BL33 CoT (key cert + img cert) ifneq (${BL33},) $(if ${BL33_KEY},$(eval $(call CERT_ADD_CMD_OPT,${BL33_KEY},--nt-fw-key))) $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/nt_fw_content.crt,--nt-fw-cert)) $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/nt_fw_key.crt,--nt-fw-key-cert)) endif trusted-firmware-a-2.2/make_helpers/unix.mk000066400000000000000000000026051355360272700210670ustar00rootroot00000000000000# # Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Trusted Firmware shell command definitions for a Unix style environment. ifndef UNIX_MK UNIX_MK := $(lastword $(MAKEFILE_LIST)) ECHO_BLANK_LINE := echo ECHO_QUIET := @\# DIR_DELIM := / PATH_SEP := : # These defines provide Unix style equivalents of the shell commands # required by the Trusted Firmware build environment. # ${1} is the file to be copied. # ${2} is the destination file name. define SHELL_COPY ${Q}cp -f "${1}" "${2}" endef # ${1} is the directory to be copied. # ${2} is the destination directory path. define SHELL_COPY_TREE ${Q}cp -rf "${1}" "${2}" endef # ${1} is the file to be deleted. define SHELL_DELETE -${Q}rm -f "${1}" endef # ${1} is a space delimited list of files to be deleted. # Note that we do not quote ${1}, as multiple parameters may be passed. define SHELL_DELETE_ALL -${Q}rm -rf ${1} endef # ${1} is the directory to be generated. # ${2} is optional, and allows a prerequisite to be specified. # Do nothing if $1 == $2, to ignore self dependencies. define MAKE_PREREQ_DIR ifneq (${1},${2}) ${1} : ${2} ${Q}mkdir -p "${1}" endif endef define SHELL_REMOVE_DIR -${Q}rm -rf "${1}" endef endif trusted-firmware-a-2.2/make_helpers/windows.mk000066400000000000000000000054561355360272700216050ustar00rootroot00000000000000# # Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # OS specific parts for builds in a Windows_NT environment. The # environment variable OS is set to Windows_NT on all modern Windows platforms # Include generic windows command definitions. ifndef WINDOWS_MK WINDOWS_MK := $(lastword $(MAKEFILE_LIST)) ECHO_BLANK_LINE := @cmd /c echo. ECHO_QUIET := @rem DIR_DELIM := $(strip \) BIN_EXT := .exe PATH_SEP := ; # For some Windows native commands there is a problem with the directory delimiter. # Make uses / (slash) and the commands expect \ (backslash) # We have to provide a means of translating these, so we define local functions. # ${1} is the file to be copied. # ${2} is the destination file name. define SHELL_COPY $(eval tmp_from_file:=$(subst /,\,${1})) $(eval tmp_to_file:=$(subst /,\,${2})) copy "${tmp_from_file}" "${tmp_to_file}" endef # ${1} is the directory to be copied. # ${2} is the destination directory path. define SHELL_COPY_TREE $(eval tmp_from_dir:=$(subst /,\,${1})) $(eval tmp_to_dir:=$(subst /,\,${2})) xcopy /HIVE "${tmp_from_dir}" "${tmp_to_dir}" endef # ${1} is the file to be deleted. define SHELL_DELETE $(eval tmp_del_file:=$(subst /,\,${*})) -@if exist $(tmp_del_file) del /Q $(tmp_del_file) endef # ${1} is a space delimited list of files to be deleted. define SHELL_DELETE_ALL $(eval $(foreach filename,$(wildcard ${1}),$(call DELETE_IF_THERE,${filename}))) endef # ${1} is the directory to be generated. # ${2} is optional, and allows prerequisites to be specified. # Do nothing if $1 == $2, to ignore self dependencies. define MAKE_PREREQ_DIR ifneq (${1},${2}) ${1} : ${2} $(eval tmp_dir:=$(subst /,\,${1})) -@if not exist "$(tmp_dir)" mkdir "${tmp_dir}" endif endef # ${1} is the directory to be removed. define SHELL_REMOVE_DIR $(eval tmp_dir:=$(subst /,\,${1})) -@if exist "$(tmp_dir)" rd /Q /S "$(tmp_dir)" endef endif # Because git is not available from CMD.EXE, we need to avoid # the BUILD_STRING generation which uses git. # For now we use "development build". # This can be overridden from the command line or environment. BUILD_STRING ?= development build # The DOS echo shell command does not strip ' characters from the command # parameters before printing. We therefore use an alternative method invoked # by defining the MAKE_BUILD_STRINGS macro. BUILT_TIME_DATE_STRING = const char build_message[] = "Built : "${BUILD_MESSAGE_TIMESTAMP}; VERSION_STRING_MESSAGE = const char version_string[] = "${VERSION_STRING}"; define MAKE_BUILD_STRINGS @echo $$(BUILT_TIME_DATE_STRING) $$(VERSION_STRING_MESSAGE) | \ $$(CC) $$(TF_CFLAGS) $$(CFLAGS) -x c -c - -o $1 endef trusted-firmware-a-2.2/plat/000077500000000000000000000000001355360272700160515ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/allwinner/000077500000000000000000000000001355360272700200445ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/allwinner/common/000077500000000000000000000000001355360272700213345ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/allwinner/common/allwinner-common.mk000066400000000000000000000036711355360272700251550ustar00rootroot00000000000000# # Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # include lib/xlat_tables_v2/xlat_tables.mk AW_PLAT := plat/allwinner PLAT_INCLUDES := -Iinclude/plat/arm/common \ -Iinclude/plat/arm/common/aarch64 \ -I${AW_PLAT}/common/include \ -I${AW_PLAT}/${PLAT}/include include lib/libfdt/libfdt.mk PLAT_BL_COMMON_SOURCES := drivers/ti/uart/${ARCH}/16550_console.S \ ${XLAT_TABLES_LIB_SRCS} \ ${AW_PLAT}/common/plat_helpers.S \ ${AW_PLAT}/common/sunxi_common.c BL31_SOURCES += drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_helpers.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ lib/cpus/${ARCH}/cortex_a53.S \ plat/common/plat_gicv2.c \ plat/common/plat_psci_common.c \ ${AW_PLAT}/common/sunxi_bl31_setup.c \ ${AW_PLAT}/common/sunxi_cpu_ops.c \ ${AW_PLAT}/common/sunxi_pm.c \ ${AW_PLAT}/${PLAT}/sunxi_power.c \ ${AW_PLAT}/common/sunxi_security.c \ ${AW_PLAT}/common/sunxi_topology.c # The bootloader is guaranteed to only run on CPU 0 by the boot ROM. COLD_BOOT_SINGLE_CPU := 1 # Do not enable SPE (not supported on ARM v8.0). ENABLE_SPE_FOR_LOWER_ELS := 0 # Do not enable SVE (not supported on ARM v8.0). ENABLE_SVE_FOR_NS := 0 # Enable workarounds for Cortex-A53 errata. Allwinner uses at least r0p4. ERRATA_A53_835769 := 1 ERRATA_A53_843419 := 1 ERRATA_A53_855873 := 1 # The reset vector can be changed for each CPU. PROGRAMMABLE_RESET_ADDRESS := 1 # Allow mapping read-only data as execute-never. SEPARATE_CODE_AND_RODATA := 1 # BL31 gets loaded alongside BL33 (U-Boot) by U-Boot's SPL RESET_TO_BL31 := 1 # We are short on memory, so save 3.5KB by not having an extra coherent page. USE_COHERENT_MEM := 0 # This platform is single-cluster and does not require coherency setup. WARMBOOT_ENABLE_DCACHE_EARLY := 1 trusted-firmware-a-2.2/plat/allwinner/common/arisc_off.S000066400000000000000000000106231355360272700234150ustar00rootroot00000000000000# turn_off_core.S # # Copyright (c) 2018, Andre Przywara # SPDX-License-Identifier: BSD-3-Clause # # OpenRISC assembly to turn off an ARM core on an Allwinner SoC from # the arisc management controller. # Generate a binary representation with: # $ or1k-elf-as -c -o turn_off_core.o turn_off_core.S # $ or1k-elf-objcopy -O binary --reverse-bytes=4 turn_off_core.o \ # turn_off_core.bin # The encoded instructions go into an array defined in # plat/allwinner/sun50i_*/include/core_off_arisc.h, to be handed off to # the arisc processor. # # This routine is meant to be called directly from arisc reset (put the # start address in the reset vector), to be actually triggered by that # very ARM core to be turned off. # It expects the core number presented as a mask in the upper half of # r3, so to be patched in the lower 16 bits of the first instruction, # overwriting the 0 in this code here. # The code will do the following: # - Read the C_CPU_STATUS register, which contains the status of the WFI # lines of each of the four A53 cores. # - Loop until the core in question reaches WFI. # - Using that mask, activate the core output clamps by setting the # respective core bit in CPUX_PWROFF_GATING_REG (0x1f01500). # Note that the clamp for core 0 covers more than just the core, activating # it hangs the whole system. So we skip this step for core 0. # - Using the negated mask, assert the core's reset line by clearing the # respective bit in C_RST_CTRL (0x1f01c30). # - Finally turn off the core's power switch by writing 0xff to the # respective CPUx_PWR_SWITCH_REG (0x1f01540 ff.) # - Assert the arisc's own reset to end execution. # This also signals other arisc users that the chip is free again. # So in C this would look like: # while (!(readl(0x1700030) & (1U << core_nr))) # ; # if (core_nr != 0) # writel(readl(0x1f01500) | (1U << core_nr), 0x1f01500); # writel(readl(0x1f01c30) & ~(1U << core_nr), 0x1f01c30); # writel(0xff, 0x1f01540 + (core_nr * 4)); # (using A64/H5 addresses) .text _start: l.movhi r3, 0 # FIXUP! with core mask l.movhi r0, 0 # clear r0 l.movhi r13, 0x170 # r13: CPU_CFG_BASE=0x01700000 wait_wfi: l.lwz r5, 0x30(r13) # load C_CPU_STATUS l.and r5, r5, r3 # mask requested core l.sfeq r5, r0 # is it not yet in WFI? l.bf wait_wfi # try again l.srli r6, r3, 16 # move mask to lower 16 bits l.sfeqi r6, 1 # core 0 is special l.bf 1f # don't touch the bit for core 0 l.movhi r13, 0x1f0 # address of R_CPUCFG (delay) l.lwz r5, 0x1500(r13) # core output clamps l.or r5, r5, r6 # set bit to ... l.sw 0x1500(r13), r5 # ... activate for our core 1: l.lwz r5, 0x1c30(r13) # CPU power-on reset l.xori r6, r6, -1 # negate core mask l.and r5, r5, r6 # clear bit to ... l.sw 0x1c30(r13), r5 # ... assert for our core l.ff1 r6, r3 # get core number from high mask l.addi r6, r6, -17 # convert to 0-3 l.slli r6, r6, 2 # r5: core number*4 (0-12) l.add r6, r6, r13 # add to base address l.ori r5, r0, 0xff # 0xff means all switches off l.sw 0x1540(r6), r5 # core power switch registers reset: l.sw 0x1c00(r13),r0 # pull down our own reset line l.j reset # just in case .... l.nop 0x0 # (delay slot) # same as above, but with the MMIO addresses matching the H6 SoC _start_h6: l.movhi r3, 0 # FIXUP! with core mask l.movhi r0, 0 # clear r0 l.movhi r13, 0x901 # r13: CPU_CFG_BASE=0x09010000 1: l.lwz r5, 0x80(r13) # load C_CPU_STATUS l.and r5, r5, r3 # mask requested core l.sfeq r5, r0 # is it not yet in WFI? l.bf 1b # try again l.srli r6, r3, 16 # move mask to lower 16 bits(ds) l.sfeqi r6, 1 # core 0 is special l.bf 1f # don't touch the bit for core 0 l.movhi r13, 0x700 # address of R_CPUCFG (ds) l.lwz r5, 0x0444(r13) # core output clamps l.or r5, r5, r6 # set bit to ... l.sw 0x0444(r13), r5 # ... activate for our core 1: l.lwz r5, 0x0440(r13) # CPU power-on reset l.xori r6, r6, -1 # negate core mask l.and r5, r5, r6 # clear bit to ... l.sw 0x0440(r13), r5 # ... assert for our core l.ff1 r6, r3 # get core number from high mask l.addi r6, r6, -17 # convert to 0-3 l.slli r6, r6, 2 # r5: core number*4 (0-12) l.add r6, r6, r13 # add to base address l.ori r5, r0, 0xff # 0xff means all switches off l.sw 0x0450(r6), r5 # core power switch registers 1: l.sw 0x0400(r13),r0 # pull down our own reset line l.j 1b # just in case ... l.nop 0x0 # (delay slot) trusted-firmware-a-2.2/plat/allwinner/common/include/000077500000000000000000000000001355360272700227575ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/allwinner/common/include/mentor_i2c_plat.h000066400000000000000000000011371355360272700262130ustar00rootroot00000000000000/* * Copyright (C) 2018 Icenowy Zheng * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* This driver provides I2C support for Allwinner sunXi SoCs */ #ifndef MENTOR_I2C_PLAT_H #define MENTOR_I2C_PLAT_H #define CONFIG_SYS_TCLK 24000000 #define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_SYS_I2C_SLAVE 0 #define I2C_INTERRUPT_CLEAR_INVERTED struct mentor_i2c_regs { uint32_t slave_address; uint32_t xtnd_slave_addr; uint32_t data; uint32_t control; uint32_t status; uint32_t baudrate; uint32_t soft_reset; }; #endif /* MENTOR_I2C_PLAT_H */ trusted-firmware-a-2.2/plat/allwinner/common/include/plat_macros.S000066400000000000000000000012261355360272700254100ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S #include #include /* --------------------------------------------- * The below required platform porting macro * prints out relevant GIC and CCI registers * whenever an unhandled exception is taken in * BL31. * Clobbers: x0 - x10, x16, x17, sp * --------------------------------------------- */ .macro plat_crash_print_regs mov_imm x17, SUNXI_GICC_BASE mov_imm x16, SUNXI_GICD_BASE arm_print_gic_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/allwinner/common/include/platform_def.h000066400000000000000000000032011355360272700255660ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include #define BL31_BASE SUNXI_SRAM_A2_BASE #define BL31_LIMIT (SUNXI_SRAM_A2_BASE + SUNXI_SRAM_A2_SIZE) /* The traditional U-Boot load address is 160MB into DRAM, so at 0x4a000000 */ #define PLAT_SUNXI_NS_IMAGE_OFFSET (SUNXI_DRAM_BASE + (160U << 20)) /* How much memory to reserve as secure for BL32, if configured */ #define SUNXI_DRAM_SEC_SIZE (32U << 20) /* How much DRAM to map (to map BL33, for fetching the DTB from U-Boot) */ #define SUNXI_DRAM_MAP_SIZE (64U << 20) #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) #define MAX_MMAP_REGIONS (3 + PLATFORM_MMAP_REGIONS) #define MAX_XLAT_TABLES 1 #define PLAT_MAX_PWR_LVL_STATES U(2) #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE U(2) #define PLAT_MAX_PWR_LVL U(2) #define PLAT_NUM_PWR_DOMAINS (1 + \ PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 28) #define PLATFORM_CLUSTER_COUNT 1 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \ PLATFORM_MAX_CPUS_PER_CLUSTER) #define PLATFORM_MAX_CPUS_PER_CLUSTER 4 #define PLATFORM_MMAP_REGIONS 4 #define PLATFORM_STACK_SIZE (0x1000 / PLATFORM_CORE_COUNT) #ifndef SPD_none #ifndef BL32_BASE #define BL32_BASE SUNXI_DRAM_BASE #endif #endif #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/allwinner/common/include/sunxi_def.h000066400000000000000000000007321355360272700251160ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SUNXI_DEF_H #define SUNXI_DEF_H /* Clock configuration */ #define SUNXI_OSC24M_CLK_IN_HZ 24000000 /* UART configuration */ #define SUNXI_UART0_BAUDRATE 115200 #define SUNXI_UART0_CLK_IN_HZ SUNXI_OSC24M_CLK_IN_HZ #define SUNXI_SOC_A64 0x1689 #define SUNXI_SOC_H5 0x1718 #define SUNXI_SOC_H6 0x1728 #endif /* SUNXI_DEF_H */ trusted-firmware-a-2.2/plat/allwinner/common/include/sunxi_private.h000066400000000000000000000014151355360272700260310ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SUNXI_PRIVATE_H #define SUNXI_PRIVATE_H void sunxi_configure_mmu_el3(int flags); void sunxi_cpu_on(u_register_t mpidr); void sunxi_cpu_off(u_register_t mpidr); void sunxi_disable_secondary_cpus(u_register_t primary_mpidr); void __dead2 sunxi_power_down(void); int sunxi_pmic_setup(uint16_t socid, const void *fdt); void sunxi_security_setup(void); uint16_t sunxi_read_soc_id(void); void sunxi_set_gpio_out(char port, int pin, bool level_high); int sunxi_init_platform_r_twi(uint16_t socid, bool use_rsb); void sunxi_execute_arisc_code(uint32_t *code, size_t size, int patch_offset, uint16_t param); #endif /* SUNXI_PRIVATE_H */ trusted-firmware-a-2.2/plat/allwinner/common/plat_helpers.S000066400000000000000000000020331355360272700241400ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush .globl plat_my_core_pos .globl platform_mem_init .globl plat_report_exception func plat_crash_console_init mov_imm x0, SUNXI_UART0_BASE mov_imm x1, SUNXI_UART0_CLK_IN_HZ mov_imm x2, SUNXI_UART0_BAUDRATE b console_16550_core_init endfunc plat_crash_console_init func plat_crash_console_putc mov_imm x1, SUNXI_UART0_BASE b console_16550_core_putc endfunc plat_crash_console_putc func plat_crash_console_flush ret endfunc plat_crash_console_flush func plat_my_core_pos mrs x0, mpidr_el1 and x1, x0, #MPIDR_CLUSTER_MASK and x0, x0, #MPIDR_CPU_MASK add x0, x0, x1, LSR #6 ret endfunc plat_my_core_pos func platform_mem_init ret endfunc platform_mem_init func plat_report_exception ret endfunc plat_report_exception trusted-firmware-a-2.2/plat/allwinner/common/sunxi_bl31_setup.c000066400000000000000000000117261355360272700247160ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; static console_16550_t console; static const gicv2_driver_data_t sunxi_gic_data = { .gicd_base = SUNXI_GICD_BASE, .gicc_base = SUNXI_GICC_BASE, }; /* * Try to find a DTB loaded in memory by previous stages. * * At the moment we implement a heuristic to find the DTB attached to U-Boot: * U-Boot appends its DTB to the end of the image. Assuming that BL33 is * U-Boot, try to find the size of the U-Boot image to learn the DTB address. * The generic ARMv8 U-Boot image contains the load address and its size * as u64 variables at the beginning of the image. There might be padding * or other headers before that data, so scan the first 2KB after the BL33 * entry point to find the load address, which should be followed by the * size. Adding those together gives us the address of the DTB. */ static void *sunxi_find_dtb(void) { uint64_t *u_boot_base; int i; u_boot_base = (void *)(SUNXI_DRAM_VIRT_BASE + SUNXI_DRAM_SEC_SIZE); for (i = 0; i < 2048 / sizeof(uint64_t); i++) { uint32_t *dtb_base; if (u_boot_base[i] != PLAT_SUNXI_NS_IMAGE_OFFSET) continue; /* Does the suspected U-Boot size look anyhow reasonable? */ if (u_boot_base[i + 1] >= 256 * 1024 * 1024) continue; /* end of the image: base address + size */ dtb_base = (void *)((char *)u_boot_base + u_boot_base[i + 1]); if (fdt_check_header(dtb_base) != 0) continue; return dtb_base; } return NULL; } void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { /* Initialize the debug console as soon as possible */ console_16550_register(SUNXI_UART0_BASE, SUNXI_UART0_CLK_IN_HZ, SUNXI_UART0_BAUDRATE, &console); #ifdef BL32_BASE /* Populate entry point information for BL32 */ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0); SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); bl32_image_ep_info.pc = BL32_BASE; #endif /* Populate entry point information for BL33 */ SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); /* * Tell BL31 where the non-trusted software image * is located and the entry state information */ bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); /* Turn off all secondary CPUs */ sunxi_disable_secondary_cpus(read_mpidr()); } void bl31_plat_arch_setup(void) { sunxi_configure_mmu_el3(0); } void bl31_platform_setup(void) { const char *soc_name; uint16_t soc_id = sunxi_read_soc_id(); void *fdt; switch (soc_id) { case SUNXI_SOC_A64: soc_name = "A64/H64/R18"; break; case SUNXI_SOC_H5: soc_name = "H5"; break; case SUNXI_SOC_H6: soc_name = "H6"; break; default: soc_name = "unknown"; break; } NOTICE("BL31: Detected Allwinner %s SoC (%04x)\n", soc_name, soc_id); generic_delay_timer_init(); fdt = sunxi_find_dtb(); if (fdt) { const char *model; int length; model = fdt_getprop(fdt, 0, "model", &length); NOTICE("BL31: Found U-Boot DTB at %p, model: %s\n", fdt, model ?: "unknown"); } else { NOTICE("BL31: No DTB found.\n"); } /* Configure the interrupt controller */ gicv2_driver_init(&sunxi_gic_data); gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); sunxi_security_setup(); /* * On the A64 U-Boot's SPL sets the bus clocks to some conservative * values, to work around FEL mode instabilities with SRAM C accesses. * FEL mode is gone when we reach ATF, so bring the AHB1 bus * (the "main" bus) clock frequency back to the recommended 200MHz, * for improved performance. */ if (soc_id == SUNXI_SOC_A64) mmio_write_32(SUNXI_CCU_BASE + 0x54, 0x00003180); /* * U-Boot or the kernel don't setup AHB2, which leaves it at the * AHB1 frequency (200 MHz, see above). However Allwinner recommends * 300 MHz, for improved Ethernet and USB performance. Switch the * clock to use "PLL_PERIPH0 / 2". */ if (soc_id == SUNXI_SOC_A64 || soc_id == SUNXI_SOC_H5) mmio_write_32(SUNXI_CCU_BASE + 0x5c, 0x1); sunxi_pmic_setup(soc_id, fdt); INFO("BL31: Platform setup done\n"); } entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { assert(sec_state_is_valid(type) != 0); if (type == NON_SECURE) return &bl33_image_ep_info; if ((type == SECURE) && bl32_image_ep_info.pc) return &bl32_image_ep_info; return NULL; } trusted-firmware-a-2.2/plat/allwinner/common/sunxi_common.c000066400000000000000000000133741355360272700242260ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include static const mmap_region_t sunxi_mmap[PLATFORM_MMAP_REGIONS + 1] = { MAP_REGION_FLAT(SUNXI_SRAM_BASE, SUNXI_SRAM_SIZE, MT_MEMORY | MT_RW | MT_SECURE), MAP_REGION_FLAT(SUNXI_DEV_BASE, SUNXI_DEV_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION(SUNXI_DRAM_BASE, SUNXI_DRAM_VIRT_BASE, SUNXI_DRAM_SEC_SIZE, MT_MEMORY | MT_RW | MT_SECURE), MAP_REGION(PLAT_SUNXI_NS_IMAGE_OFFSET, SUNXI_DRAM_VIRT_BASE + SUNXI_DRAM_SEC_SIZE, SUNXI_DRAM_MAP_SIZE, MT_MEMORY | MT_RO | MT_NS), {}, }; unsigned int plat_get_syscnt_freq2(void) { return SUNXI_OSC24M_CLK_IN_HZ; } uintptr_t plat_get_ns_image_entrypoint(void) { #ifdef PRELOADED_BL33_BASE return PRELOADED_BL33_BASE; #else return PLAT_SUNXI_NS_IMAGE_OFFSET; #endif } void sunxi_configure_mmu_el3(int flags) { mmap_add_region(BL31_BASE, BL31_BASE, BL31_LIMIT - BL31_BASE, MT_MEMORY | MT_RW | MT_SECURE); mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, MT_CODE | MT_SECURE); mmap_add_region(BL_RO_DATA_BASE, BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE, MT_RO_DATA | MT_SECURE); mmap_add(sunxi_mmap); init_xlat_tables(); enable_mmu_el3(0); } #define SRAM_VER_REG (SUNXI_SYSCON_BASE + 0x24) uint16_t sunxi_read_soc_id(void) { uint32_t reg = mmio_read_32(SRAM_VER_REG); /* Set bit 15 to prepare for the SOCID read. */ mmio_write_32(SRAM_VER_REG, reg | BIT(15)); reg = mmio_read_32(SRAM_VER_REG); /* deactivate the SOCID access again */ mmio_write_32(SRAM_VER_REG, reg & ~BIT(15)); return reg >> 16; } /* * Configure a given pin to the GPIO-OUT function and sets its level. * The port is given as a capital letter, the pin is the number within * this port group. * So to set pin PC7 to high, use: sunxi_set_gpio_out('C', 7, true); */ void sunxi_set_gpio_out(char port, int pin, bool level_high) { uintptr_t port_base; if (port < 'A' || port > 'L') return; if (port == 'L') port_base = SUNXI_R_PIO_BASE; else port_base = SUNXI_PIO_BASE + (port - 'A') * 0x24; /* Set the new level first before configuring the pin. */ if (level_high) mmio_setbits_32(port_base + 0x10, BIT(pin)); else mmio_clrbits_32(port_base + 0x10, BIT(pin)); /* configure pin as GPIO out (4(3) bits per pin, 1: GPIO out */ mmio_clrsetbits_32(port_base + (pin / 8) * 4, 0x7 << ((pin % 8) * 4), 0x1 << ((pin % 8) * 4)); } int sunxi_init_platform_r_twi(uint16_t socid, bool use_rsb) { uint32_t pin_func = 0x77; uint32_t device_bit; unsigned int reset_offset = 0xb0; switch (socid) { case SUNXI_SOC_H5: if (use_rsb) return -ENODEV; pin_func = 0x22; device_bit = BIT(6); break; case SUNXI_SOC_H6: if (use_rsb) return -ENODEV; pin_func = 0x33; device_bit = BIT(16); reset_offset = 0x19c; break; case SUNXI_SOC_A64: pin_func = use_rsb ? 0x22 : 0x33; device_bit = use_rsb ? BIT(3) : BIT(6); break; default: INFO("R_I2C/RSB on Allwinner 0x%x SoC not supported\n", socid); return -ENODEV; } /* un-gate R_PIO clock */ if (socid != SUNXI_SOC_H6) mmio_setbits_32(SUNXI_R_PRCM_BASE + 0x28, BIT(0)); /* switch pins PL0 and PL1 to the desired function */ mmio_clrsetbits_32(SUNXI_R_PIO_BASE + 0x00, 0xffU, pin_func); /* level 2 drive strength */ mmio_clrsetbits_32(SUNXI_R_PIO_BASE + 0x14, 0x0fU, 0xaU); /* set both pins to pull-up */ mmio_clrsetbits_32(SUNXI_R_PIO_BASE + 0x1c, 0x0fU, 0x5U); /* assert, then de-assert reset of I2C/RSB controller */ mmio_clrbits_32(SUNXI_R_PRCM_BASE + reset_offset, device_bit); mmio_setbits_32(SUNXI_R_PRCM_BASE + reset_offset, device_bit); /* un-gate clock */ if (socid != SUNXI_SOC_H6) mmio_setbits_32(SUNXI_R_PRCM_BASE + 0x28, device_bit); else mmio_setbits_32(SUNXI_R_PRCM_BASE + 0x19c, device_bit | BIT(0)); return 0; } /* This lock synchronises access to the arisc management processor. */ DEFINE_BAKERY_LOCK(arisc_lock); /* * Tell the "arisc" SCP core (an OpenRISC core) to execute some code. * We don't have any service running there, so we place some OpenRISC code * in SRAM, put the address of that into the reset vector and release the * arisc reset line. The SCP will execute that code and pull the line up again. */ void sunxi_execute_arisc_code(uint32_t *code, size_t size, int patch_offset, uint16_t param) { uintptr_t arisc_reset_vec = SUNXI_SRAM_A2_BASE - 0x4000 + 0x100; do { bakery_lock_get(&arisc_lock); /* Wait until the arisc is in reset state. */ if (!(mmio_read_32(SUNXI_R_CPUCFG_BASE) & BIT(0))) break; bakery_lock_release(&arisc_lock); } while (1); /* Patch up the code to feed in an input parameter. */ if (patch_offset >= 0 && patch_offset <= (size - 4)) code[patch_offset] = (code[patch_offset] & ~0xffff) | param; clean_dcache_range((uintptr_t)code, size); /* * The OpenRISC unconditional branch has opcode 0, the branch offset * is in the lower 26 bits, containing the distance to the target, * in instruction granularity (32 bits). */ mmio_write_32(arisc_reset_vec, ((uintptr_t)code - arisc_reset_vec) / 4); clean_dcache_range(arisc_reset_vec, 4); /* De-assert the arisc reset line to let it run. */ mmio_setbits_32(SUNXI_R_CPUCFG_BASE, BIT(0)); /* * We release the lock here, although the arisc is still busy. * But as long as it runs, the reset line is high, so other users * won't leave the loop above. * Once it has finished, the code is supposed to clear the reset line, * to signal this to other users. */ bakery_lock_release(&arisc_lock); } trusted-firmware-a-2.2/plat/allwinner/common/sunxi_cpu_ops.c000066400000000000000000000073751355360272700244120ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include static void sunxi_cpu_disable_power(unsigned int cluster, unsigned int core) { if (mmio_read_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core)) == 0xff) return; VERBOSE("PSCI: Disabling power to cluster %d core %d\n", cluster, core); mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xff); } static void sunxi_cpu_enable_power(unsigned int cluster, unsigned int core) { if (mmio_read_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core)) == 0) return; VERBOSE("PSCI: Enabling power to cluster %d core %d\n", cluster, core); /* Power enable sequence from original Allwinner sources */ mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xfe); mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xf8); mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0xe0); mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0x80); mmio_write_32(SUNXI_CPU_POWER_CLAMP_REG(cluster, core), 0x00); } void sunxi_cpu_off(u_register_t mpidr) { unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr); unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); VERBOSE("PSCI: Powering off cluster %d core %d\n", cluster, core); /* Deassert DBGPWRDUP */ mmio_clrbits_32(SUNXI_CPUCFG_DBG_REG0, BIT(core)); /* We can't turn ourself off like this, but it works for other cores. */ if (read_mpidr() != mpidr) { /* Activate the core output clamps, but not for core 0. */ if (core != 0) mmio_setbits_32(SUNXI_POWEROFF_GATING_REG(cluster), BIT(core)); /* Assert CPU power-on reset */ mmio_clrbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core)); /* Remove power from the CPU */ sunxi_cpu_disable_power(cluster, core); return; } /* Simplifies assembly, all SoCs so far are single cluster anyway. */ assert(cluster == 0); /* * If we are supposed to turn ourself off, tell the arisc SCP * to do that work for us. The code expects the core mask to be * patched into the first instruction. */ sunxi_execute_arisc_code(arisc_core_off, sizeof(arisc_core_off), 0, BIT_32(core)); } void sunxi_cpu_on(u_register_t mpidr) { unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr); unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); VERBOSE("PSCI: Powering on cluster %d core %d\n", cluster, core); /* Assert CPU core reset */ mmio_clrbits_32(SUNXI_CPUCFG_RST_CTRL_REG(cluster), BIT(core)); /* Assert CPU power-on reset */ mmio_clrbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core)); /* Set CPU to start in AArch64 mode */ mmio_setbits_32(SUNXI_CPUCFG_CLS_CTRL_REG0(cluster), BIT(24 + core)); /* Apply power to the CPU */ sunxi_cpu_enable_power(cluster, core); /* Release the core output clamps */ mmio_clrbits_32(SUNXI_POWEROFF_GATING_REG(cluster), BIT(core)); /* Deassert CPU power-on reset */ mmio_setbits_32(SUNXI_POWERON_RST_REG(cluster), BIT(core)); /* Deassert CPU core reset */ mmio_setbits_32(SUNXI_CPUCFG_RST_CTRL_REG(cluster), BIT(core)); /* Assert DBGPWRDUP */ mmio_setbits_32(SUNXI_CPUCFG_DBG_REG0, BIT(core)); } void sunxi_disable_secondary_cpus(u_register_t primary_mpidr) { unsigned int cluster; unsigned int core; for (cluster = 0; cluster < PLATFORM_CLUSTER_COUNT; ++cluster) { for (core = 0; core < PLATFORM_MAX_CPUS_PER_CLUSTER; ++core) { u_register_t mpidr = (cluster << MPIDR_AFF1_SHIFT) | (core << MPIDR_AFF0_SHIFT) | BIT(31); if (mpidr != primary_mpidr) sunxi_cpu_off(mpidr); } } } trusted-firmware-a-2.2/plat/allwinner/common/sunxi_pm.c000066400000000000000000000055321355360272700233470ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #define SUNXI_WDOG0_CTRL_REG (SUNXI_R_WDOG_BASE + 0x0010) #define SUNXI_WDOG0_CFG_REG (SUNXI_R_WDOG_BASE + 0x0014) #define SUNXI_WDOG0_MODE_REG (SUNXI_R_WDOG_BASE + 0x0018) #define mpidr_is_valid(mpidr) ( \ MPIDR_AFFLVL3_VAL(mpidr) == 0 && \ MPIDR_AFFLVL2_VAL(mpidr) == 0 && \ MPIDR_AFFLVL1_VAL(mpidr) < PLATFORM_CLUSTER_COUNT && \ MPIDR_AFFLVL0_VAL(mpidr) < PLATFORM_MAX_CPUS_PER_CLUSTER) static int sunxi_pwr_domain_on(u_register_t mpidr) { if (mpidr_is_valid(mpidr) == 0) return PSCI_E_INTERN_FAIL; sunxi_cpu_on(mpidr); return PSCI_E_SUCCESS; } static void sunxi_pwr_domain_off(const psci_power_state_t *target_state) { gicv2_cpuif_disable(); } static void __dead2 sunxi_pwr_down_wfi(const psci_power_state_t *target_state) { sunxi_cpu_off(read_mpidr()); while (1) wfi(); } static void sunxi_pwr_domain_on_finish(const psci_power_state_t *target_state) { gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } static void __dead2 sunxi_system_off(void) { /* Turn off all secondary CPUs */ sunxi_disable_secondary_cpus(read_mpidr()); sunxi_power_down(); } static void __dead2 sunxi_system_reset(void) { /* Reset the whole system when the watchdog times out */ mmio_write_32(SUNXI_WDOG0_CFG_REG, 1); /* Enable the watchdog with the shortest timeout (0.5 seconds) */ mmio_write_32(SUNXI_WDOG0_MODE_REG, (0 << 4) | 1); /* Wait for twice the watchdog timeout before panicking */ mdelay(1000); ERROR("PSCI: System reset failed\n"); wfi(); panic(); } static int sunxi_validate_ns_entrypoint(uintptr_t ns_entrypoint) { /* The non-secure entry point must be in DRAM */ if (ns_entrypoint >= SUNXI_DRAM_BASE) return PSCI_E_SUCCESS; return PSCI_E_INVALID_ADDRESS; } static plat_psci_ops_t sunxi_psci_ops = { .pwr_domain_on = sunxi_pwr_domain_on, .pwr_domain_off = sunxi_pwr_domain_off, .pwr_domain_pwr_down_wfi = sunxi_pwr_down_wfi, .pwr_domain_on_finish = sunxi_pwr_domain_on_finish, .system_off = sunxi_system_off, .system_reset = sunxi_system_reset, .validate_ns_entrypoint = sunxi_validate_ns_entrypoint, }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { assert(psci_ops); for (int cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu += 1) { mmio_write_32(SUNXI_CPUCFG_RVBAR_LO_REG(cpu), sec_entrypoint & 0xffffffff); mmio_write_32(SUNXI_CPUCFG_RVBAR_HI_REG(cpu), sec_entrypoint >> 32); } *psci_ops = &sunxi_psci_ops; return 0; } trusted-firmware-a-2.2/plat/allwinner/common/sunxi_security.c000066400000000000000000000025201355360272700245740ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #ifdef SUNXI_SPC_BASE #define SPC_DECPORT_STA_REG(p) (SUNXI_SPC_BASE + ((p) * 0x0c) + 0x4) #define SPC_DECPORT_SET_REG(p) (SUNXI_SPC_BASE + ((p) * 0x0c) + 0x8) #define SPC_DECPORT_CLR_REG(p) (SUNXI_SPC_BASE + ((p) * 0x0c) + 0xc) #endif #define R_PRCM_SEC_SWITCH_REG 0x1d0 #define DMA_SEC_REG 0x20 /* * Setup the peripherals to be accessible by non-secure world. * This will not work for the Secure Peripherals Controller (SPC) unless * a fuse it burnt (seems to be an erratum), but we do it nevertheless, * to allow booting on boards using secure boot. */ void sunxi_security_setup(void) { #ifdef SUNXI_SPC_BASE int i; INFO("Configuring SPC Controller\n"); /* SPC setup: set all devices to non-secure */ for (i = 0; i < 6; i++) mmio_write_32(SPC_DECPORT_SET_REG(i), 0xff); #endif /* set MBUS clocks, bus clocks (AXI/AHB/APB) and PLLs to non-secure */ mmio_write_32(SUNXI_CCU_SEC_SWITCH_REG, 0x7); /* set R_PRCM clocks to non-secure */ mmio_write_32(SUNXI_R_PRCM_BASE + R_PRCM_SEC_SWITCH_REG, 0x7); /* Set all DMA channels (16 max.) to non-secure */ mmio_write_32(SUNXI_DMA_BASE + DMA_SEC_REG, 0xffff); } trusted-firmware-a-2.2/plat/allwinner/common/sunxi_topology.c000066400000000000000000000016571355360272700246130ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include static const unsigned char plat_power_domain_tree_desc[PLAT_MAX_PWR_LVL + 1] = { /* One root node for the SoC */ 1, /* One node for each cluster */ PLATFORM_CLUSTER_COUNT, /* One set of CPUs per cluster */ PLATFORM_MAX_CPUS_PER_CLUSTER, }; int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr); unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); if (MPIDR_AFFLVL3_VAL(mpidr) > 0 || MPIDR_AFFLVL2_VAL(mpidr) > 0 || cluster >= PLATFORM_CLUSTER_COUNT || core >= PLATFORM_MAX_CPUS_PER_CLUSTER) { return -1; } return cluster * PLATFORM_MAX_CPUS_PER_CLUSTER + core; } const unsigned char *plat_get_power_domain_tree_desc(void) { return plat_power_domain_tree_desc; } trusted-firmware-a-2.2/plat/allwinner/sun50i_a64/000077500000000000000000000000001355360272700216415ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/allwinner/sun50i_a64/include/000077500000000000000000000000001355360272700232645ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/allwinner/sun50i_a64/include/core_off_arisc.h000066400000000000000000000021711355360272700264010ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint32_t arisc_core_off[] = { 0x18600000, /* l.movhi r3, */ 0x18000000, /* l.movhi r0, 0x0 */ 0x19a00170, /* l.movhi r13, 0x170 */ 0x84ad0030, /* l.lwz r5, 0x30(r13) */ 0xe0a51803, /* l.and r5, r5, r3 */ 0xe4050000, /* l.sfeq r5, r0 */ 0x13fffffd, /* l.bf -12 */ 0xb8c30050, /* l.srli r6, r3, 16 */ 0xbc060001, /* l.sfeqi r6, 1 */ 0x10000005, /* l.bf +20 */ 0x19a001f0, /* l.movhi r13, 0x1f0 */ 0x84ad1500, /* l.lwz r5, 0x1500(r13) */ 0xe0a53004, /* l.or r5, r5, r6 */ 0xd44d2d00, /* l.sw 0x1500(r13), r5 */ 0x84ad1c30, /* l.lwz r5, 0x1c30(r13) */ 0xacc6ffff, /* l.xori r6, r6, -1 */ 0xe0a53003, /* l.and r5, r5, r6 */ 0xd46d2c30, /* l.sw 0x1c30(r13), r5 */ 0xe0c3000f, /* l.ff1 r6, r3 */ 0x9cc6ffef, /* l.addi r6, r6, -17 */ 0xb8c60002, /* l.slli r6, r6, 2 */ 0xe0c66800, /* l.add r6, r6, r13 */ 0xa8a000ff, /* l.ori r5, r0, 0xff */ 0xd4462d40, /* l.sw 0x1540(r6), r5 */ 0xd46d0400, /* l.sw 0x1c00(r13), r0 */ 0x03ffffff, /* l.j -1 */ 0x15000000, /* l.nop */ }; trusted-firmware-a-2.2/plat/allwinner/sun50i_a64/include/sunxi_cpucfg.h000066400000000000000000000032231355360272700261320ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SUNXI_CPUCFG_H #define SUNXI_CPUCFG_H #include /* c = cluster, n = core */ #define SUNXI_CPUCFG_CLS_CTRL_REG0(c) (SUNXI_CPUCFG_BASE + 0x0000 + (c) * 16) #define SUNXI_CPUCFG_CLS_CTRL_REG1(c) (SUNXI_CPUCFG_BASE + 0x0004 + (c) * 16) #define SUNXI_CPUCFG_CACHE_CFG_REG0 (SUNXI_CPUCFG_BASE + 0x0008) #define SUNXI_CPUCFG_CACHE_CFG_REG1 (SUNXI_CPUCFG_BASE + 0x000c) #define SUNXI_CPUCFG_DBG_REG0 (SUNXI_CPUCFG_BASE + 0x0020) #define SUNXI_CPUCFG_GLB_CTRL_REG (SUNXI_CPUCFG_BASE + 0x0028) #define SUNXI_CPUCFG_CPU_STS_REG(c) (SUNXI_CPUCFG_BASE + 0x0030 + (c) * 4) #define SUNXI_CPUCFG_L2_STS_REG (SUNXI_CPUCFG_BASE + 0x003c) #define SUNXI_CPUCFG_RST_CTRL_REG(c) (SUNXI_CPUCFG_BASE + 0x0080 + (c) * 4) #define SUNXI_CPUCFG_RVBAR_LO_REG(n) (SUNXI_CPUCFG_BASE + 0x00a0 + (n) * 8) #define SUNXI_CPUCFG_RVBAR_HI_REG(n) (SUNXI_CPUCFG_BASE + 0x00a4 + (n) * 8) #define SUNXI_CPU_POWER_CLAMP_REG(c, n) (SUNXI_R_PRCM_BASE + 0x0140 + \ (c) * 16 + (n) * 4) #define SUNXI_POWEROFF_GATING_REG(c) (SUNXI_R_PRCM_BASE + 0x0100 + (c) * 4) #define SUNXI_R_CPUCFG_CPUS_RST_REG (SUNXI_R_CPUCFG_BASE + 0x0000) #define SUNXI_POWERON_RST_REG(c) (SUNXI_R_CPUCFG_BASE + 0x0030 + (c) * 4) #define SUNXI_R_CPUCFG_SYS_RST_REG (SUNXI_R_CPUCFG_BASE + 0x0140) #define SUNXI_R_CPUCFG_SS_FLAG_REG (SUNXI_R_CPUCFG_BASE + 0x01a0) #define SUNXI_R_CPUCFG_CPU_ENTRY_REG (SUNXI_R_CPUCFG_BASE + 0x01a4) #define SUNXI_R_CPUCFG_SS_ENTRY_REG (SUNXI_R_CPUCFG_BASE + 0x01a8) #define SUNXI_R_CPUCFG_HP_FLAG_REG (SUNXI_R_CPUCFG_BASE + 0x01ac) #endif /* SUNXI_CPUCFG_H */ trusted-firmware-a-2.2/plat/allwinner/sun50i_a64/include/sunxi_mmap.h000066400000000000000000000047301355360272700256210ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SUNXI_MMAP_H #define SUNXI_MMAP_H /* Memory regions */ #define SUNXI_ROM_BASE 0x00000000 #define SUNXI_ROM_SIZE 0x00010000 #define SUNXI_SRAM_BASE 0x00010000 #define SUNXI_SRAM_SIZE 0x00044000 #define SUNXI_SRAM_A1_BASE 0x00010000 #define SUNXI_SRAM_A1_SIZE 0x00008000 #define SUNXI_SRAM_A2_BASE 0x00044000 #define SUNXI_SRAM_A2_SIZE 0x00010000 #define SUNXI_SRAM_C_BASE 0x00018000 #define SUNXI_SRAM_C_SIZE 0x0001c000 #define SUNXI_DEV_BASE 0x01000000 #define SUNXI_DEV_SIZE 0x01000000 #define SUNXI_DRAM_BASE 0x40000000 #define SUNXI_DRAM_VIRT_BASE 0x02000000 /* Memory-mapped devices */ #define SUNXI_CPU_MBIST_BASE 0x01502000 #define SUNXI_CPUCFG_BASE 0x01700000 #define SUNXI_SYSCON_BASE 0x01c00000 #define SUNXI_DMA_BASE 0x01c02000 #define SUNXI_KEYMEM_BASE 0x01c0b000 #define SUNXI_SMHC0_BASE 0x01c0f000 #define SUNXI_SMHC1_BASE 0x01c10000 #define SUNXI_SMHC2_BASE 0x01c11000 #define SUNXI_SID_BASE 0x01c14000 #define SUNXI_MSGBOX_BASE 0x01c17000 #define SUNXI_SPINLOCK_BASE 0x01c18000 #define SUNXI_CCU_BASE 0x01c20000 #define SUNXI_CCU_SEC_SWITCH_REG (SUNXI_CCU_BASE + 0x2f0) #define SUNXI_PIO_BASE 0x01c20800 #define SUNXI_TIMER_BASE 0x01c20c00 #define SUNXI_WDOG_BASE 0x01c20ca0 #define SUNXI_SPC_BASE 0x01c23400 #define SUNXI_THS_BASE 0x01c25000 #define SUNXI_UART0_BASE 0x01c28000 #define SUNXI_UART1_BASE 0x01c28400 #define SUNXI_UART2_BASE 0x01c28800 #define SUNXI_UART3_BASE 0x01c28c00 #define SUNXI_I2C0_BASE 0x01c2ac00 #define SUNXI_I2C1_BASE 0x01c2b000 #define SUNXI_I2C2_BASE 0x01c2b400 #define SUNXI_DRAMCOM_BASE 0x01c62000 #define SUNXI_DRAMCTL_BASE 0x01c63000 #define SUNXI_DRAMPHY_BASE 0x01c65000 #define SUNXI_SPI0_BASE 0x01c68000 #define SUNXI_SPI1_BASE 0x01c69000 #define SUNXI_SCU_BASE 0x01c80000 #define SUNXI_GICD_BASE 0x01c81000 #define SUNXI_GICC_BASE 0x01c82000 #define SUNXI_RTC_BASE 0x01f00000 #define SUNXI_R_TIMER_BASE 0x01f00800 #define SUNXI_R_INTC_BASE 0x01f00c00 #define SUNXI_R_WDOG_BASE 0x01f01000 #define SUNXI_R_PRCM_BASE 0x01f01400 #define SUNXI_R_TWD_BASE 0x01f01800 #define SUNXI_R_CPUCFG_BASE 0x01f01c00 #define SUNXI_R_CIR_BASE 0x01f02000 #define SUNXI_R_I2C_BASE 0x01f02400 #define SUNXI_R_UART_BASE 0x01f02800 #define SUNXI_R_PIO_BASE 0x01f02c00 #define SUNXI_R_RSB_BASE 0x01f03400 #define SUNXI_R_PWM_BASE 0x01f03800 #endif /* SUNXI_MMAP_H */ trusted-firmware-a-2.2/plat/allwinner/sun50i_a64/platform.mk000066400000000000000000000004611355360272700240170ustar00rootroot00000000000000# # Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # The differences between the platform are covered by the include files. include plat/allwinner/common/allwinner-common.mk PLAT_BL_COMMON_SOURCES += drivers/allwinner/sunxi_rsb.c trusted-firmware-a-2.2/plat/allwinner/sun50i_a64/sunxi_power.c000066400000000000000000000224301355360272700243700ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2018, Icenowy Zheng * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include static enum pmic_type { GENERIC_H5, GENERIC_A64, REF_DESIGN_H5, /* regulators controlled by GPIO pins on port L */ AXP803_RSB, /* PMIC connected via RSB on most A64 boards */ } pmic; #define AXP803_HW_ADDR 0x3a3 #define AXP803_RT_ADDR 0x2d /* * On boards without a proper PMIC we struggle to turn off the system properly. * Try to turn off as much off the system as we can, to reduce power * consumption. This should be entered with only one core running and SMP * disabled. * This function only cares about peripherals. */ void sunxi_turn_off_soc(uint16_t socid) { int i; /** Turn off most peripherals, most importantly DRAM users. **/ /* Keep DRAM controller running for now. */ mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, ~BIT_32(14)); mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, ~BIT_32(14)); /* Contains msgbox (bit 21) and spinlock (bit 22) */ mmio_write_32(SUNXI_CCU_BASE + 0x2c4, 0); mmio_write_32(SUNXI_CCU_BASE + 0x64, 0); mmio_write_32(SUNXI_CCU_BASE + 0x2c8, 0); /* Keep PIO controller running for now. */ mmio_clrbits_32(SUNXI_CCU_BASE + 0x68, ~(BIT_32(5))); mmio_write_32(SUNXI_CCU_BASE + 0x2d0, 0); /* Contains UART0 (bit 16) */ mmio_write_32(SUNXI_CCU_BASE + 0x2d8, 0); mmio_write_32(SUNXI_CCU_BASE + 0x6c, 0); mmio_write_32(SUNXI_CCU_BASE + 0x70, 0); /** Turn off DRAM controller. **/ mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c0, BIT_32(14)); mmio_clrbits_32(SUNXI_CCU_BASE + 0x60, BIT_32(14)); /** Migrate CPU and bus clocks away from the PLLs. **/ /* AHB1: use OSC24M/1, APB1 = AHB1 / 2 */ mmio_write_32(SUNXI_CCU_BASE + 0x54, 0x1000); /* APB2: use OSC24M */ mmio_write_32(SUNXI_CCU_BASE + 0x58, 0x1000000); /* AHB2: use AHB1 clock */ mmio_write_32(SUNXI_CCU_BASE + 0x5c, 0); /* CPU: use OSC24M */ mmio_write_32(SUNXI_CCU_BASE + 0x50, 0x10000); /** Turn off PLLs. **/ for (i = 0; i < 6; i++) mmio_clrbits_32(SUNXI_CCU_BASE + i * 8, BIT(31)); switch (socid) { case SUNXI_SOC_H5: mmio_clrbits_32(SUNXI_CCU_BASE + 0x44, BIT(31)); break; case SUNXI_SOC_A64: mmio_clrbits_32(SUNXI_CCU_BASE + 0x2c, BIT(31)); mmio_clrbits_32(SUNXI_CCU_BASE + 0x4c, BIT(31)); break; } } static int rsb_init(void) { int ret; ret = rsb_init_controller(); if (ret) return ret; /* Start with 400 KHz to issue the I2C->RSB switch command. */ ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 400000); if (ret) return ret; /* * Initiate an I2C transaction to write 0x7c into register 0x3e, * switching the PMIC to RSB mode. */ ret = rsb_set_device_mode(0x7c3e00); if (ret) return ret; /* Now in RSB mode, switch to the recommended 3 MHz. */ ret = rsb_set_bus_speed(SUNXI_OSC24M_CLK_IN_HZ, 3000000); if (ret) return ret; /* Associate the 8-bit runtime address with the 12-bit bus address. */ return rsb_assign_runtime_address(AXP803_HW_ADDR, AXP803_RT_ADDR); } static int axp_write(uint8_t reg, uint8_t val) { return rsb_write(AXP803_RT_ADDR, reg, val); } static int axp_clrsetbits(uint8_t reg, uint8_t clr_mask, uint8_t set_mask) { uint8_t regval; int ret; ret = rsb_read(AXP803_RT_ADDR, reg); if (ret < 0) return ret; regval = (ret & ~clr_mask) | set_mask; return rsb_write(AXP803_RT_ADDR, reg, regval); } #define axp_clrbits(reg, clr_mask) axp_clrsetbits(reg, clr_mask, 0) #define axp_setbits(reg, set_mask) axp_clrsetbits(reg, 0, set_mask) static bool should_enable_regulator(const void *fdt, int node) { if (fdt_getprop(fdt, node, "phandle", NULL) != NULL) return true; if (fdt_getprop(fdt, node, "regulator-always-on", NULL) != NULL) return true; return false; } /* * Retrieve the voltage from a given regulator DTB node. * Both the regulator-{min,max}-microvolt properties must be present and * have the same value. Return that value in millivolts. */ static int fdt_get_regulator_millivolt(const void *fdt, int node) { const fdt32_t *prop; uint32_t min_volt; prop = fdt_getprop(fdt, node, "regulator-min-microvolt", NULL); if (prop == NULL) return -EINVAL; min_volt = fdt32_to_cpu(*prop); prop = fdt_getprop(fdt, node, "regulator-max-microvolt", NULL); if (prop == NULL) return -EINVAL; if (fdt32_to_cpu(*prop) != min_volt) return -EINVAL; return min_volt / 1000; } #define NO_SPLIT 0xff static const struct axp_regulator { char *dt_name; uint16_t min_volt; uint16_t max_volt; uint16_t step; unsigned char split; unsigned char volt_reg; unsigned char switch_reg; unsigned char switch_bit; } regulators[] = { {"dcdc1", 1600, 3400, 100, NO_SPLIT, 0x20, 0x10, 0}, {"dcdc5", 800, 1840, 10, 32, 0x24, 0x10, 4}, {"dcdc6", 600, 1520, 10, 50, 0x25, 0x10, 5}, {"dldo1", 700, 3300, 100, NO_SPLIT, 0x15, 0x12, 3}, {"dldo2", 700, 4200, 100, 27, 0x16, 0x12, 4}, {"dldo3", 700, 3300, 100, NO_SPLIT, 0x17, 0x12, 5}, {"fldo1", 700, 1450, 50, NO_SPLIT, 0x1c, 0x13, 2}, {} }; static int setup_regulator(const void *fdt, int node, const struct axp_regulator *reg) { int mvolt; uint8_t regval; if (!should_enable_regulator(fdt, node)) return -ENOENT; mvolt = fdt_get_regulator_millivolt(fdt, node); if (mvolt < reg->min_volt || mvolt > reg->max_volt) return -EINVAL; regval = (mvolt / reg->step) - (reg->min_volt / reg->step); if (regval > reg->split) regval = ((regval - reg->split) / 2) + reg->split; axp_write(reg->volt_reg, regval); if (reg->switch_reg < 0xff) axp_setbits(reg->switch_reg, BIT(reg->switch_bit)); INFO("PMIC: AXP803: %s voltage: %d.%03dV\n", reg->dt_name, mvolt / 1000, mvolt % 1000); return 0; } static void setup_axp803_rails(const void *fdt) { int node; bool dc1sw = false; /* locate the PMIC DT node, bail out if not found */ node = fdt_node_offset_by_compatible(fdt, -1, "x-powers,axp803"); if (node < 0) { WARN("BL31: PMIC: Cannot find AXP803 DT node, skipping initial setup.\n"); return; } if (fdt_getprop(fdt, node, "x-powers,drive-vbus-en", NULL)) { axp_clrbits(0x8f, BIT(4)); axp_setbits(0x30, BIT(2)); INFO("PMIC: AXP803: Enabling DRIVEVBUS\n"); } /* descend into the "regulators" subnode */ node = fdt_subnode_offset(fdt, node, "regulators"); if (node < 0) { WARN("BL31: PMIC: Cannot find regulators subnode, skipping initial setup.\n"); return; } /* iterate over all regulators to find used ones */ for (node = fdt_first_subnode(fdt, node); node >= 0; node = fdt_next_subnode(fdt, node)) { const struct axp_regulator *reg; const char *name; int length; /* We only care if it's always on or referenced. */ if (!should_enable_regulator(fdt, node)) continue; name = fdt_get_name(fdt, node, &length); for (reg = regulators; reg->dt_name; reg++) { if (!strncmp(name, reg->dt_name, length)) { setup_regulator(fdt, node, reg); break; } } if (!strncmp(name, "dc1sw", length)) { /* Delay DC1SW enablement to avoid overheating. */ dc1sw = true; continue; } } /* * If DLDO2 is enabled after DC1SW, the PMIC overheats and shuts * down. So always enable DC1SW as the very last regulator. */ if (dc1sw) { INFO("PMIC: AXP803: Enabling DC1SW\n"); axp_setbits(0x12, BIT(7)); } } int sunxi_pmic_setup(uint16_t socid, const void *fdt) { int ret; switch (socid) { case SUNXI_SOC_H5: pmic = REF_DESIGN_H5; NOTICE("BL31: PMIC: Defaulting to PortL GPIO according to H5 reference design.\n"); break; case SUNXI_SOC_A64: pmic = GENERIC_A64; ret = sunxi_init_platform_r_twi(socid, true); if (ret) return ret; ret = rsb_init(); if (ret) return ret; pmic = AXP803_RSB; NOTICE("BL31: PMIC: Detected AXP803 on RSB.\n"); if (fdt) setup_axp803_rails(fdt); break; default: NOTICE("BL31: PMIC: No support for Allwinner %x SoC.\n", socid); return -ENODEV; } return 0; } void __dead2 sunxi_power_down(void) { switch (pmic) { case GENERIC_H5: /* Turn off as many peripherals and clocks as we can. */ sunxi_turn_off_soc(SUNXI_SOC_H5); /* Turn off the pin controller now. */ mmio_write_32(SUNXI_CCU_BASE + 0x68, 0); break; case GENERIC_A64: /* Turn off as many peripherals and clocks as we can. */ sunxi_turn_off_soc(SUNXI_SOC_A64); /* Turn off the pin controller now. */ mmio_write_32(SUNXI_CCU_BASE + 0x68, 0); break; case REF_DESIGN_H5: sunxi_turn_off_soc(SUNXI_SOC_H5); /* * Switch PL pins to power off the board: * - PL5 (VCC_IO) -> high * - PL8 (PWR-STB = CPU power supply) -> low * - PL9 (PWR-DRAM) ->low * - PL10 (power LED) -> low * Note: Clearing PL8 will reset the board, so keep it up. */ sunxi_set_gpio_out('L', 5, 1); sunxi_set_gpio_out('L', 9, 0); sunxi_set_gpio_out('L', 10, 0); /* Turn off pin controller now. */ mmio_write_32(SUNXI_CCU_BASE + 0x68, 0); break; case AXP803_RSB: /* (Re-)init RSB in case the rich OS has disabled it. */ sunxi_init_platform_r_twi(SUNXI_SOC_A64, true); rsb_init(); /* Set "power disable control" bit */ axp_setbits(0x32, BIT(7)); break; default: break; } udelay(1000); ERROR("PSCI: Cannot turn off system, halting.\n"); wfi(); panic(); } trusted-firmware-a-2.2/plat/allwinner/sun50i_h6/000077500000000000000000000000001355360272700215645ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/allwinner/sun50i_h6/include/000077500000000000000000000000001355360272700232075ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/allwinner/sun50i_h6/include/core_off_arisc.h000066400000000000000000000021711355360272700263240ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static uint32_t arisc_core_off[] = { 0x18600000, /* l.movhi r3, */ 0x18000000, /* l.movhi r0, 0x0 */ 0x19a00901, /* l.movhi r13, 0x901 */ 0x84ad0080, /* l.lwz r5, 0x80(r13) */ 0xe0a51803, /* l.and r5, r5, r3 */ 0xe4050000, /* l.sfeq r5, r0 */ 0x13fffffd, /* l.bf -12 */ 0xb8c30050, /* l.srli r6, r3, 16 */ 0xbc060001, /* l.sfeqi r6, 1 */ 0x10000005, /* l.bf +20 */ 0x19a00700, /* l.movhi r13, 0x700 */ 0x84ad0444, /* l.lwz r5, 0x0444(r13) */ 0xe0a53004, /* l.or r5, r5, r6 */ 0xd40d2c44, /* l.sw 0x0444(r13), r5 */ 0x84ad0440, /* l.lwz r5, 0x0440(r13) */ 0xacc6ffff, /* l.xori r6, r6, -1 */ 0xe0a53003, /* l.and r5, r5, r6 */ 0xd40d2c40, /* l.sw 0x0440(r13), r5 */ 0xe0c3000f, /* l.ff1 r6, r3 */ 0x9cc6ffef, /* l.addi r6, r6, -17 */ 0xb8c60002, /* l.slli r6, r6, 2 */ 0xe0c66800, /* l.add r6, r6, r13 */ 0xa8a000ff, /* l.ori r5, r0, 0xff */ 0xd4062c50, /* l.sw 0x0450(r6), r5 */ 0xd40d0400, /* l.sw 0x0400(r13), r0 */ 0x03ffffff, /* l.j -1 */ 0x15000000, /* l.nop */ }; trusted-firmware-a-2.2/plat/allwinner/sun50i_h6/include/sunxi_cpucfg.h000066400000000000000000000020031355360272700260500ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SUNXI_CPUCFG_H #define SUNXI_CPUCFG_H #include /* c = cluster, n = core */ #define SUNXI_CPUCFG_CLS_CTRL_REG0(c) (SUNXI_CPUCFG_BASE + 0x0010 + (c) * 0x10) #define SUNXI_CPUCFG_CLS_CTRL_REG1(c) (SUNXI_CPUCFG_BASE + 0x0014 + (c) * 0x10) #define SUNXI_CPUCFG_CACHE_CFG_REG (SUNXI_CPUCFG_BASE + 0x0024) #define SUNXI_CPUCFG_DBG_REG0 (SUNXI_CPUCFG_BASE + 0x00c0) #define SUNXI_CPUCFG_RST_CTRL_REG(c) (SUNXI_CPUCFG_BASE + 0x0000 + (c) * 4) #define SUNXI_CPUCFG_RVBAR_LO_REG(n) (SUNXI_CPUCFG_BASE + 0x0040 + (n) * 8) #define SUNXI_CPUCFG_RVBAR_HI_REG(n) (SUNXI_CPUCFG_BASE + 0x0044 + (n) * 8) #define SUNXI_POWERON_RST_REG(c) (SUNXI_R_CPUCFG_BASE + 0x0040 + (c) * 4) #define SUNXI_POWEROFF_GATING_REG(c) (SUNXI_R_CPUCFG_BASE + 0x0044 + (c) * 4) #define SUNXI_CPU_POWER_CLAMP_REG(c, n) (SUNXI_R_CPUCFG_BASE + 0x0050 + \ (c) * 0x10 + (n) * 4) #endif /* SUNXI_CPUCFG_H */ trusted-firmware-a-2.2/plat/allwinner/sun50i_h6/include/sunxi_mmap.h000066400000000000000000000037531355360272700255500ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SUNXI_MMAP_H #define SUNXI_MMAP_H /* Memory regions */ #define SUNXI_ROM_BASE 0x00000000 #define SUNXI_ROM_SIZE 0x00010000 #define SUNXI_SRAM_BASE 0x00020000 #define SUNXI_SRAM_SIZE 0x000f8000 #define SUNXI_SRAM_A1_BASE 0x00020000 #define SUNXI_SRAM_A1_SIZE 0x00008000 #define SUNXI_SRAM_A2_BASE 0x00104000 #define SUNXI_SRAM_A2_SIZE 0x00014000 #define SUNXI_SRAM_C_BASE 0x00028000 #define SUNXI_SRAM_C_SIZE 0x0001e000 #define SUNXI_DEV_BASE 0x01000000 #define SUNXI_DEV_SIZE 0x09000000 #define SUNXI_DRAM_BASE 0x40000000 #define SUNXI_DRAM_VIRT_BASE 0x0a000000 /* Memory-mapped devices */ #define SUNXI_SYSCON_BASE 0x03000000 #define SUNXI_CPUCFG_BASE 0x09010000 #define SUNXI_SID_BASE 0x03006000 #define SUNXI_DMA_BASE 0x03002000 #define SUNXI_MSGBOX_BASE 0x03003000 #define SUNXI_CCU_BASE 0x03010000 #define SUNXI_CCU_SEC_SWITCH_REG (SUNXI_CCU_BASE + 0xf00) #define SUNXI_PIO_BASE 0x030b0000 #define SUNXI_TIMER_BASE 0x03009000 #define SUNXI_WDOG_BASE 0x030090a0 #define SUNXI_THS_BASE 0x05070400 #define SUNXI_UART0_BASE 0x05000000 #define SUNXI_UART1_BASE 0x05000400 #define SUNXI_UART2_BASE 0x05000800 #define SUNXI_UART3_BASE 0x05000c00 #define SUNXI_I2C0_BASE 0x05002000 #define SUNXI_I2C1_BASE 0x05002400 #define SUNXI_I2C2_BASE 0x05002800 #define SUNXI_I2C3_BASE 0x05002c00 #define SUNXI_SPI0_BASE 0x05010000 #define SUNXI_SPI1_BASE 0x05011000 #define SUNXI_SCU_BASE 0x03020000 #define SUNXI_GICD_BASE 0x03021000 #define SUNXI_GICC_BASE 0x03022000 #define SUNXI_R_TIMER_BASE 0x07020000 #define SUNXI_R_INTC_BASE 0x07021000 #define SUNXI_R_WDOG_BASE 0x07020400 #define SUNXI_R_PRCM_BASE 0x07010000 #define SUNXI_R_TWD_BASE 0x07020800 #define SUNXI_R_CPUCFG_BASE 0x07000400 #define SUNXI_R_I2C_BASE 0x07081400 #define SUNXI_R_UART_BASE 0x07080000 #define SUNXI_R_PIO_BASE 0x07022000 #endif /* SUNXI_MMAP_H */ trusted-firmware-a-2.2/plat/allwinner/sun50i_h6/platform.mk000066400000000000000000000004561355360272700237460ustar00rootroot00000000000000# # Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # The differences between the platform are covered by the include files. include plat/allwinner/common/allwinner-common.mk PLAT_BL_COMMON_SOURCES += drivers/mentor/i2c/mi2cv.c trusted-firmware-a-2.2/plat/allwinner/sun50i_h6/sunxi_power.c000066400000000000000000000041441355360272700243150ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2018, Icenowy Zheng * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #define AXP805_ADDR 0x36 #define AXP805_ID 0x03 enum pmic_type { NO_PMIC, AXP805, }; enum pmic_type pmic; int axp_i2c_read(uint8_t chip, uint8_t reg, uint8_t *val) { int ret; ret = i2c_write(chip, 0, 0, ®, 1); if (ret) return ret; return i2c_read(chip, 0, 0, val, 1); } int axp_i2c_write(uint8_t chip, uint8_t reg, uint8_t val) { return i2c_write(chip, reg, 1, &val, 1); } static int axp805_probe(void) { int ret; uint8_t val; ret = axp_i2c_write(AXP805_ADDR, 0xff, 0x0); if (ret) { ERROR("PMIC: Cannot put AXP805 to master mode.\n"); return -EPERM; } ret = axp_i2c_read(AXP805_ADDR, AXP805_ID, &val); if (!ret && ((val & 0xcf) == 0x40)) NOTICE("PMIC: AXP805 detected\n"); else if (ret) { ERROR("PMIC: Cannot communicate with AXP805.\n"); return -EPERM; } else { ERROR("PMIC: Non-AXP805 chip attached at AXP805's address.\n"); return -EINVAL; } return 0; } int sunxi_pmic_setup(uint16_t socid, const void *fdt) { int ret; sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); /* initialise mi2cv driver */ i2c_init((void *)SUNXI_R_I2C_BASE); NOTICE("PMIC: Probing AXP805\n"); pmic = AXP805; ret = axp805_probe(); if (ret) pmic = NO_PMIC; else pmic = AXP805; return 0; } void __dead2 sunxi_power_down(void) { uint8_t val; switch (pmic) { case AXP805: /* Re-initialise after rich OS might have used it. */ sunxi_init_platform_r_twi(SUNXI_SOC_H6, false); /* initialise mi2cv driver */ i2c_init((void *)SUNXI_R_I2C_BASE); axp_i2c_read(AXP805_ADDR, 0x32, &val); axp_i2c_write(AXP805_ADDR, 0x32, val | 0x80); break; default: break; } udelay(1000); ERROR("PSCI: Cannot communicate with PMIC, halting\n"); wfi(); panic(); } trusted-firmware-a-2.2/plat/amlogic/000077500000000000000000000000001355360272700174645ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/amlogic/common/000077500000000000000000000000001355360272700207545ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/amlogic/common/aarch64/000077500000000000000000000000001355360272700222045ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/amlogic/common/aarch64/aml_helpers.S000066400000000000000000000051421355360272700246250ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl plat_crash_console_flush .globl plat_crash_console_init .globl plat_crash_console_putc .globl platform_mem_init .globl plat_is_my_cpu_primary .globl plat_my_core_pos .globl plat_reset_handler .globl plat_calc_core_pos /* ----------------------------------------------------- * unsigned int plat_my_core_pos(void); * ----------------------------------------------------- */ func plat_my_core_pos mrs x0, mpidr_el1 b plat_calc_core_pos endfunc plat_my_core_pos /* ----------------------------------------------------- * unsigned int plat_calc_core_pos(u_register_t mpidr); * ----------------------------------------------------- */ func plat_calc_core_pos and x0, x0, #MPIDR_CPU_MASK ret endfunc plat_calc_core_pos /* ----------------------------------------------------- * unsigned int plat_is_my_cpu_primary(void); * ----------------------------------------------------- */ func plat_is_my_cpu_primary mrs x0, mpidr_el1 and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) cmp x0, #AML_PRIMARY_CPU cset w0, eq ret endfunc plat_is_my_cpu_primary /* --------------------------------------------- * void platform_mem_init(void); * --------------------------------------------- */ func platform_mem_init ret endfunc platform_mem_init /* --------------------------------------------- * int plat_crash_console_init(void) * --------------------------------------------- */ func plat_crash_console_init mov_imm x0, AML_UART0_AO_BASE mov_imm x1, AML_UART0_AO_CLK_IN_HZ mov_imm x2, AML_UART_BAUDRATE b console_meson_init endfunc plat_crash_console_init /* --------------------------------------------- * int plat_crash_console_putc(int c) * Clobber list : x1, x2 * --------------------------------------------- */ func plat_crash_console_putc mov_imm x1, AML_UART0_AO_BASE b console_meson_core_putc endfunc plat_crash_console_putc /* --------------------------------------------- * int plat_crash_console_flush() * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func plat_crash_console_flush mov_imm x0, AML_UART0_AO_BASE b console_meson_core_flush endfunc plat_crash_console_flush /* --------------------------------------------- * void plat_reset_handler(void); * --------------------------------------------- */ func plat_reset_handler ret endfunc plat_reset_handler trusted-firmware-a-2.2/plat/amlogic/common/aml_console.c000066400000000000000000000015711355360272700234170ustar00rootroot00000000000000/* * Copyright (c) 2019, Carlo Caione * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /******************************************************************************* * Function that sets up the console ******************************************************************************/ static console_meson_t aml_console; void aml_console_init(void) { int rc = console_meson_register(AML_UART0_AO_BASE, AML_UART0_AO_CLK_IN_HZ, AML_UART_BAUDRATE, &aml_console); if (rc == 0) { /* * The crash console doesn't use the multi console API, it uses * the core console functions directly. It is safe to call panic * and let it print debug information. */ panic(); } console_set_scope(&aml_console.console, CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME); } trusted-firmware-a-2.2/plat/amlogic/common/aml_efuse.c000066400000000000000000000007471355360272700230700ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "aml_private.h" #define EFUSE_BASE 0x140 #define EFUSE_SIZE 0xC0 uint64_t aml_efuse_read(void *dst, uint32_t offset, uint32_t size) { if ((uint64_t)(offset + size) > (uint64_t)EFUSE_SIZE) return 0; return aml_scpi_efuse_read(dst, offset + EFUSE_BASE, size); } uint64_t aml_efuse_user_max(void) { return EFUSE_SIZE; } trusted-firmware-a-2.2/plat/amlogic/common/aml_mhu.c000066400000000000000000000016351355360272700225470ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include static DEFINE_BAKERY_LOCK(mhu_lock); void aml_mhu_secure_message_start(void) { bakery_lock_get(&mhu_lock); while (mmio_read_32(AML_HIU_MAILBOX_STAT_3) != 0) ; } void aml_mhu_secure_message_send(uint32_t msg) { mmio_write_32(AML_HIU_MAILBOX_SET_3, msg); while (mmio_read_32(AML_HIU_MAILBOX_STAT_3) != 0) ; } uint32_t aml_mhu_secure_message_wait(void) { uint32_t val; do { val = mmio_read_32(AML_HIU_MAILBOX_STAT_0); } while (val == 0); return val; } void aml_mhu_secure_message_end(void) { mmio_write_32(AML_HIU_MAILBOX_CLR_0, 0xFFFFFFFF); bakery_lock_release(&mhu_lock); } void aml_mhu_secure_init(void) { bakery_lock_init(&mhu_lock); mmio_write_32(AML_HIU_MAILBOX_CLR_3, 0xFFFFFFFF); } trusted-firmware-a-2.2/plat/amlogic/common/aml_scpi.c000066400000000000000000000141601355360272700227110ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "aml_private.h" #define SIZE_SHIFT 20 #define SIZE_MASK 0x1FF #define SIZE_FWBLK 0x200UL /* * Note: The Amlogic SCP firmware uses the legacy SCPI protocol. */ #define SCPI_CMD_SET_CSS_POWER_STATE 0x04 #define SCPI_CMD_SET_SYS_POWER_STATE 0x08 #define SCPI_CMD_JTAG_SET_STATE 0xC0 #define SCPI_CMD_EFUSE_READ 0xC2 #define SCPI_CMD_CHIP_ID 0xC6 #define SCPI_CMD_COPY_FW 0xd4 #define SCPI_CMD_SET_FW_ADDR 0xd3 #define SCPI_CMD_FW_SIZE 0xd2 static inline uint32_t aml_scpi_cmd(uint32_t command, uint32_t size) { return command | (size << SIZE_SHIFT); } static void aml_scpi_secure_message_send(uint32_t command, uint32_t size) { aml_mhu_secure_message_send(aml_scpi_cmd(command, size)); } static uint32_t aml_scpi_secure_message_receive(void **message_out, size_t *size_out) { uint32_t response = aml_mhu_secure_message_wait(); size_t size = (response >> SIZE_SHIFT) & SIZE_MASK; response &= ~(SIZE_MASK << SIZE_SHIFT); if (size_out != NULL) *size_out = size; if (message_out != NULL) *message_out = (void *)AML_MHU_SECURE_SCP_TO_AP_PAYLOAD; return response; } void aml_scpi_set_css_power_state(u_register_t mpidr, uint32_t cpu_state, uint32_t cluster_state, uint32_t css_state) { uint32_t state = (mpidr & 0x0F) | /* CPU ID */ ((mpidr & 0xF00) >> 4) | /* Cluster ID */ (cpu_state << 8) | (cluster_state << 12) | (css_state << 16); aml_mhu_secure_message_start(); mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD, state); aml_mhu_secure_message_send(aml_scpi_cmd(SCPI_CMD_SET_CSS_POWER_STATE, 4)); aml_mhu_secure_message_wait(); aml_mhu_secure_message_end(); } uint32_t aml_scpi_sys_power_state(uint64_t system_state) { uint32_t *response; size_t size; aml_mhu_secure_message_start(); mmio_write_8(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD, system_state); aml_mhu_secure_message_send(aml_scpi_cmd(SCPI_CMD_SET_SYS_POWER_STATE, 1)); aml_scpi_secure_message_receive((void *)&response, &size); aml_mhu_secure_message_end(); return *response; } void aml_scpi_jtag_set_state(uint32_t state, uint8_t select) { assert(state <= AML_JTAG_STATE_OFF); if (select > AML_JTAG_A53_EE) { WARN("BL31: Invalid JTAG select (0x%x).\n", select); return; } aml_mhu_secure_message_start(); mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD, (state << 8) | (uint32_t)select); aml_mhu_secure_message_send(aml_scpi_cmd(SCPI_CMD_JTAG_SET_STATE, 4)); aml_mhu_secure_message_wait(); aml_mhu_secure_message_end(); } uint32_t aml_scpi_efuse_read(void *dst, uint32_t base, uint32_t size) { uint32_t *response; size_t resp_size; if (size > 0x1FC) return 0; aml_mhu_secure_message_start(); mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD, base); mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD + 4, size); aml_mhu_secure_message_send(aml_scpi_cmd(SCPI_CMD_EFUSE_READ, 8)); aml_scpi_secure_message_receive((void *)&response, &resp_size); aml_mhu_secure_message_end(); /* * response[0] is the size of the response message. * response[1 ... N] are the contents. */ if (*response != 0) memcpy(dst, response + 1, *response); return *response; } void aml_scpi_unknown_thermal(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3) { aml_mhu_secure_message_start(); mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0x0, arg0); mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0x4, arg1); mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0x8, arg2); mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD + 0xC, arg3); aml_mhu_secure_message_send(aml_scpi_cmd(0xC3, 16)); aml_mhu_secure_message_wait(); aml_mhu_secure_message_end(); } uint32_t aml_scpi_get_chip_id(uint8_t *obuff, uint32_t osize) { uint32_t *response; size_t resp_size; if ((osize != 16) && (osize != 12)) return 0; aml_mhu_secure_message_start(); aml_mhu_secure_message_send(aml_scpi_cmd(SCPI_CMD_CHIP_ID, osize)); aml_scpi_secure_message_receive((void *)&response, &resp_size); aml_mhu_secure_message_end(); if (!((resp_size == 16) && (osize == 16)) && !((resp_size == 0) && (osize == 12))) return 0; memcpy((void *)obuff, (const void *)response, osize); return osize; } static inline void aml_scpi_copy_scp_data(uint8_t *data, size_t len) { void *dst = (void *)AML_MHU_SECURE_AP_TO_SCP_PAYLOAD; size_t sz; mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD, len); aml_scpi_secure_message_send(SCPI_CMD_FW_SIZE, len); aml_mhu_secure_message_wait(); for (sz = 0; sz < len; sz += SIZE_FWBLK) { memcpy(dst, data + sz, MIN(SIZE_FWBLK, len - sz)); aml_mhu_secure_message_send(SCPI_CMD_COPY_FW); } } static inline void aml_scpi_set_scp_addr(uint64_t addr, size_t len) { volatile uint64_t *dst = (uint64_t *)AML_MHU_SECURE_AP_TO_SCP_PAYLOAD; /* * It is ok as AML_MHU_SECURE_AP_TO_SCP_PAYLOAD is mapped as * non cachable */ *dst = addr; aml_scpi_secure_message_send(SCPI_CMD_SET_FW_ADDR, sizeof(addr)); aml_mhu_secure_message_wait(); mmio_write_32(AML_MHU_SECURE_AP_TO_SCP_PAYLOAD, len); aml_scpi_secure_message_send(SCPI_CMD_FW_SIZE, len); aml_mhu_secure_message_wait(); } static inline void aml_scpi_send_fw_hash(uint8_t hash[], size_t len) { void *dst = (void *)AML_MHU_SECURE_AP_TO_SCP_PAYLOAD; memcpy(dst, hash, len); aml_mhu_secure_message_send(0xd0); aml_mhu_secure_message_send(0xd1); aml_mhu_secure_message_send(0xd5); aml_mhu_secure_message_end(); } /** * Upload a FW to SCP. * * @param addr: firmware data address * @param size: size of firmware * @param send: If set, actually copy the firmware in SCP memory otherwise only * send the firmware address. */ void aml_scpi_upload_scp_fw(uintptr_t addr, size_t size, int send) { struct asd_ctx ctx; asd_sha_init(&ctx, ASM_SHA256); asd_sha_update(&ctx, (void *)addr, size); asd_sha_finalize(&ctx); aml_mhu_secure_message_start(); if (send == 0) aml_scpi_set_scp_addr(addr, size); else aml_scpi_copy_scp_data((void *)addr, size); aml_scpi_send_fw_hash(ctx.digest, sizeof(ctx.digest)); } trusted-firmware-a-2.2/plat/amlogic/common/aml_sip_svc.c000066400000000000000000000040561355360272700234240ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "aml_private.h" struct aml_cpu_info { uint32_t version; uint8_t chip_id[16]; }; static int aml_sip_get_chip_id(uint64_t version) { struct aml_cpu_info *info = (void *)AML_SHARE_MEM_OUTPUT_BASE; uint32_t size; if (version > 2) return -1; memset(info, 0, sizeof(struct aml_cpu_info)); if (version == 2) { info->version = 2; size = 16; } else { info->version = 1; size = 12; } if (aml_scpi_get_chip_id(info->chip_id, size) == 0) return -1; return 0; } /******************************************************************************* * This function is responsible for handling all SiP calls ******************************************************************************/ static uintptr_t aml_sip_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) { switch (smc_fid) { case AML_SM_GET_SHARE_MEM_INPUT_BASE: SMC_RET1(handle, AML_SHARE_MEM_INPUT_BASE); case AML_SM_GET_SHARE_MEM_OUTPUT_BASE: SMC_RET1(handle, AML_SHARE_MEM_OUTPUT_BASE); case AML_SM_EFUSE_READ: { void *dst = (void *)AML_SHARE_MEM_OUTPUT_BASE; uint64_t ret = aml_efuse_read(dst, (uint32_t)x1, x2); SMC_RET1(handle, ret); } case AML_SM_EFUSE_USER_MAX: SMC_RET1(handle, aml_efuse_user_max()); case AML_SM_JTAG_ON: aml_scpi_jtag_set_state(AML_JTAG_STATE_ON, x1); SMC_RET1(handle, 0); case AML_SM_JTAG_OFF: aml_scpi_jtag_set_state(AML_JTAG_STATE_OFF, x1); SMC_RET1(handle, 0); case AML_SM_GET_CHIP_ID: SMC_RET1(handle, aml_sip_get_chip_id(x1)); default: ERROR("BL31: Unhandled SIP SMC: 0x%08x\n", smc_fid); break; } SMC_RET1(handle, SMC_UNK); } DECLARE_RT_SVC( aml_sip_handler, OEN_SIP_START, OEN_SIP_END, SMC_TYPE_FAST, NULL, aml_sip_handler ); trusted-firmware-a-2.2/plat/amlogic/common/aml_thermal.c000066400000000000000000000012361355360272700234070ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "aml_private.h" static int32_t modules_initialized = -1; /******************************************************************************* * Unknown commands related to something thermal-related ******************************************************************************/ void aml_thermal_unknown(void) { uint16_t ret; if (modules_initialized == -1) { aml_scpi_efuse_read(&ret, 0, 2); modules_initialized = ret; } aml_scpi_unknown_thermal(10, 2, /* thermal */ 13, 1); /* thermalver */ } trusted-firmware-a-2.2/plat/amlogic/common/aml_topology.c000066400000000000000000000031741355360272700236320ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "aml_private.h" /* The power domain tree descriptor */ static unsigned char power_domain_tree_desc[] = { /* Number of root nodes */ PLATFORM_CLUSTER_COUNT, /* Number of children for the first node */ PLATFORM_CLUSTER0_CORE_COUNT }; /******************************************************************************* * This function returns the ARM default topology tree information. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { return power_domain_tree_desc; } /******************************************************************************* * This function implements a part of the critical interface between the psci * generic layer and the platform that allows the former to query the platform * to convert an MPIDR to a unique linear index. An error code (-1) is returned * in case the MPIDR is invalid. ******************************************************************************/ int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; mpidr &= MPIDR_AFFINITY_MASK; if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) return -1; cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; if (cluster_id >= PLATFORM_CLUSTER_COUNT) return -1; if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER) return -1; return plat_calc_core_pos(mpidr); } trusted-firmware-a-2.2/plat/amlogic/common/include/000077500000000000000000000000001355360272700223775ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/amlogic/common/include/aml_private.h000066400000000000000000000024651355360272700250620ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef AML_PRIVATE_H #define AML_PRIVATE_H #include #include /* Utility functions */ unsigned int plat_calc_core_pos(u_register_t mpidr); void aml_console_init(void); void aml_setup_page_tables(void); /* MHU functions */ void aml_mhu_secure_message_start(void); void aml_mhu_secure_message_send(uint32_t msg); uint32_t aml_mhu_secure_message_wait(void); void aml_mhu_secure_message_end(void); void aml_mhu_secure_init(void); /* SCPI functions */ void aml_scpi_set_css_power_state(u_register_t mpidr, uint32_t cpu_state, uint32_t cluster_state, uint32_t css_state); uint32_t aml_scpi_sys_power_state(uint64_t system_state); void aml_scpi_jtag_set_state(uint32_t state, uint8_t select); uint32_t aml_scpi_efuse_read(void *dst, uint32_t base, uint32_t size); void aml_scpi_unknown_thermal(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3); void aml_scpi_upload_scp_fw(uintptr_t addr, size_t size, int send); uint32_t aml_scpi_get_chip_id(uint8_t *obuff, uint32_t osize); /* Peripherals */ void aml_thermal_unknown(void); uint64_t aml_efuse_read(void *dst, uint32_t offset, uint32_t size); uint64_t aml_efuse_user_max(void); #endif /* AML_PRIVATE_H */ trusted-firmware-a-2.2/plat/amlogic/common/include/plat_macros.S000066400000000000000000000025511355360272700250320ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S #include #include .section .rodata.gic_reg_name, "aS" gicc_regs: .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", "" gicd_pend_reg: .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n" newline: .asciz "\n" spacer: .asciz ":\t\t0x" /* --------------------------------------------- * The below required platform porting macro * prints out relevant GIC and CCI registers * whenever an unhandled exception is taken in * BL31. * Clobbers: x0 - x10, x16, x17, sp * --------------------------------------------- */ .macro plat_crash_print_regs /* GICC registers */ mov_imm x17, AML_GICC_BASE adr x6, gicc_regs ldr w8, [x17, #GICC_HPPIR] ldr w9, [x17, #GICC_AHPPIR] ldr w10, [x17, #GICC_CTLR] bl str_in_crash_buf_print /* GICD registers */ mov_imm x16, AML_GICD_BASE add x7, x16, #GICD_ISPENDR adr x4, gicd_pend_reg bl asm_print_str gicd_ispendr_loop: sub x4, x7, x16 cmp x4, #0x280 b.eq exit_print_gic_regs bl asm_print_hex adr x4, spacer bl asm_print_str ldr x4, [x7], #8 bl asm_print_hex adr x4, newline bl asm_print_str b gicd_ispendr_loop exit_print_gic_regs: .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/amlogic/g12a/000077500000000000000000000000001355360272700202165ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/amlogic/g12a/g12a_bl31_setup.c000066400000000000000000000112441355360272700231570ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include "aml_private.h" /* * Placeholder variables for copying the arguments that have been passed to * BL31 from BL2. */ static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; static image_info_t bl30_image_info; static image_info_t bl301_image_info; /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for * the security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. ******************************************************************************/ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; next_image_info = (type == NON_SECURE) ? &bl33_image_ep_info : &bl32_image_ep_info; /* None of the images can have 0x0 as the entrypoint. */ if (next_image_info->pc != 0U) return next_image_info; return NULL; } /******************************************************************************* * Perform any BL31 early platform setup. Here is an opportunity to copy * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before * they are lost (potentially). This needs to be done before the MMU is * initialized so that the memory layout can be used while creating page * tables. BL2 has flushed this information to memory, so we are guaranteed * to pick up good data. ******************************************************************************/ struct g12a_bl31_param { param_header_t h; image_info_t *bl31_image_info; entry_point_info_t *bl32_ep_info; image_info_t *bl32_image_info; entry_point_info_t *bl33_ep_info; image_info_t *bl33_image_info; image_info_t *scp_image_info[]; }; void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { struct g12a_bl31_param *from_bl2; /* Initialize the console to provide early debug support */ aml_console_init(); from_bl2 = (struct g12a_bl31_param *)arg0; /* Check params passed from BL2 are not NULL. */ assert(from_bl2 != NULL); assert(from_bl2->h.type == PARAM_BL31); assert(from_bl2->h.version >= VERSION_1); /* * Copy BL32 and BL33 entry point information. It is stored in Secure * RAM, in BL2's address space. */ bl32_image_ep_info = *from_bl2->bl32_ep_info; bl33_image_ep_info = *from_bl2->bl33_ep_info; if (bl33_image_ep_info.pc == 0U) { ERROR("BL31: BL33 entrypoint not obtained from BL2\n"); panic(); } bl30_image_info = *from_bl2->scp_image_info[0]; bl301_image_info = *from_bl2->scp_image_info[1]; } void bl31_plat_arch_setup(void) { aml_setup_page_tables(); enable_mmu_el3(0); } /******************************************************************************* * GICv2 driver setup information ******************************************************************************/ static const interrupt_prop_t g12a_interrupt_props[] = { INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL) }; static const gicv2_driver_data_t g12a_gic_data = { .gicd_base = AML_GICD_BASE, .gicc_base = AML_GICC_BASE, .interrupt_props = g12a_interrupt_props, .interrupt_props_num = ARRAY_SIZE(g12a_interrupt_props) }; void bl31_platform_setup(void) { aml_mhu_secure_init(); gicv2_driver_init(&g12a_gic_data); gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } trusted-firmware-a-2.2/plat/amlogic/g12a/g12a_common.c000066400000000000000000000070571355360272700224750ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include /******************************************************************************* * Platform memory map regions ******************************************************************************/ #define MAP_NSDRAM0 MAP_REGION_FLAT(AML_NSDRAM0_BASE, \ AML_NSDRAM0_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define MAP_NS_SHARE_MEM MAP_REGION_FLAT(AML_NS_SHARE_MEM_BASE, \ AML_NS_SHARE_MEM_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define MAP_SEC_SHARE_MEM MAP_REGION_FLAT(AML_SEC_SHARE_MEM_BASE, \ AML_SEC_SHARE_MEM_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #define MAP_SEC_DEVICE0 MAP_REGION_FLAT(AML_SEC_DEVICE0_BASE, \ AML_SEC_DEVICE0_SIZE, \ MT_DEVICE | MT_RW) #define MAP_HDCP_RX MAP_REGION_FLAT(AML_HDCP_RX_BASE, \ AML_HDCP_RX_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_HDCP_TX MAP_REGION_FLAT(AML_HDCP_TX_BASE, \ AML_HDCP_TX_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_GIC_DEVICE MAP_REGION_FLAT(AML_GIC_DEVICE_BASE, \ AML_GIC_DEVICE_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_SEC_DEVICE1 MAP_REGION_FLAT(AML_SEC_DEVICE1_BASE, \ AML_SEC_DEVICE1_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_SEC_DEVICE2 MAP_REGION_FLAT(AML_SEC_DEVICE2_BASE, \ AML_SEC_DEVICE2_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_TZRAM MAP_REGION_FLAT(AML_TZRAM_BASE, \ AML_TZRAM_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) static const mmap_region_t g12a_mmap[] = { MAP_NSDRAM0, MAP_NS_SHARE_MEM, MAP_SEC_SHARE_MEM, MAP_SEC_DEVICE0, MAP_HDCP_RX, MAP_HDCP_TX, MAP_GIC_DEVICE, MAP_SEC_DEVICE1, MAP_SEC_DEVICE2, MAP_TZRAM, {0} }; /******************************************************************************* * Per-image regions ******************************************************************************/ #define MAP_BL31 MAP_REGION_FLAT(BL31_BASE, \ BL31_END - BL31_BASE, \ MT_MEMORY | MT_RW | MT_SECURE) #define MAP_BL_CODE MAP_REGION_FLAT(BL_CODE_BASE, \ BL_CODE_END - BL_CODE_BASE, \ MT_CODE | MT_SECURE) #define MAP_BL_RO_DATA MAP_REGION_FLAT(BL_RO_DATA_BASE, \ BL_RO_DATA_END - BL_RO_DATA_BASE, \ MT_RO_DATA | MT_SECURE) #define MAP_BL_COHERENT MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, \ BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, \ MT_DEVICE | MT_RW | MT_SECURE) /******************************************************************************* * Function that sets up the translation tables. ******************************************************************************/ void aml_setup_page_tables(void) { #if IMAGE_BL31 const mmap_region_t g12a_bl_mmap[] = { MAP_BL31, MAP_BL_CODE, MAP_BL_RO_DATA, #if USE_COHERENT_MEM MAP_BL_COHERENT, #endif {0} }; #endif mmap_add(g12a_bl_mmap); mmap_add(g12a_mmap); init_xlat_tables(); } /******************************************************************************* * Function that returns the system counter frequency ******************************************************************************/ unsigned int plat_get_syscnt_freq2(void) { mmio_clrbits_32(AML_SYS_CPU_CFG7, ~0xFDFFFFFF); mmio_clrbits_32(AML_AO_TIMESTAMP_CNTL, ~0xFFFFFE00); return AML_OSC24M_CLK_IN_HZ; } trusted-firmware-a-2.2/plat/amlogic/g12a/g12a_def.h000066400000000000000000000110321355360272700217340ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef G12A_DEF_H #define G12A_DEF_H #include /******************************************************************************* * System oscillator ******************************************************************************/ #define AML_OSC24M_CLK_IN_HZ ULL(24000000) /* 24 MHz */ /******************************************************************************* * Memory regions ******************************************************************************/ #define AML_HDCP_RX_BASE UL(0xFFE0D000) #define AML_HDCP_RX_SIZE UL(0x00002000) #define AML_HDCP_TX_BASE UL(0xFFE01000) #define AML_HDCP_TX_SIZE UL(0x00001000) #define AML_NS_SHARE_MEM_BASE UL(0x05000000) #define AML_NS_SHARE_MEM_SIZE UL(0x00100000) #define AML_SEC_SHARE_MEM_BASE UL(0x05200000) #define AML_SEC_SHARE_MEM_SIZE UL(0x00100000) #define AML_GIC_DEVICE_BASE UL(0xFFC00000) #define AML_GIC_DEVICE_SIZE UL(0x00008000) #define AML_NSDRAM0_BASE UL(0x01000000) #define AML_NSDRAM0_SIZE UL(0x0F000000) #define BL31_BASE UL(0x05100000) #define BL31_SIZE UL(0x00100000) #define BL31_LIMIT (BL31_BASE + BL31_SIZE) /* Shared memory used for SMC services */ #define AML_SHARE_MEM_INPUT_BASE UL(0x050FE000) #define AML_SHARE_MEM_OUTPUT_BASE UL(0x050FF000) #define AML_SEC_DEVICE0_BASE UL(0xFFD00000) #define AML_SEC_DEVICE0_SIZE UL(0x00026000) #define AML_SEC_DEVICE1_BASE UL(0xFF800000) #define AML_SEC_DEVICE1_SIZE UL(0x0000A000) #define AML_TZRAM_BASE UL(0xFFFA0000) #define AML_TZRAM_SIZE UL(0x00048000) /* Mailboxes */ #define AML_MHU_SECURE_SCP_TO_AP_PAYLOAD UL(0xFFFE7800) #define AML_MHU_SECURE_AP_TO_SCP_PAYLOAD UL(0xFFFE7A00) #define AML_PSCI_MAILBOX_BASE UL(0xFFFE7F00) #define AML_SEC_DEVICE2_BASE UL(0xFF620000) #define AML_SEC_DEVICE2_SIZE UL(0x00028000) /******************************************************************************* * GIC-400 and interrupt handling related constants ******************************************************************************/ #define AML_GICD_BASE UL(0xFFC01000) #define AML_GICC_BASE UL(0xFFC02000) #define IRQ_SEC_PHY_TIMER 29 #define IRQ_SEC_SGI_0 8 #define IRQ_SEC_SGI_1 9 #define IRQ_SEC_SGI_2 10 #define IRQ_SEC_SGI_3 11 #define IRQ_SEC_SGI_4 12 #define IRQ_SEC_SGI_5 13 #define IRQ_SEC_SGI_6 14 #define IRQ_SEC_SGI_7 15 #define IRQ_SEC_SGI_8 16 /******************************************************************************* * UART definitions ******************************************************************************/ #define AML_UART0_AO_BASE UL(0xFF803000) #define AML_UART0_AO_CLK_IN_HZ AML_OSC24M_CLK_IN_HZ #define AML_UART_BAUDRATE U(115200) /******************************************************************************* * Memory-mapped I/O Registers ******************************************************************************/ #define AML_AO_TIMESTAMP_CNTL UL(0xFF8000B4) #define AML_SYS_CPU_CFG7 UL(0xFF634664) #define AML_AO_RTI_STATUS_REG3 UL(0xFF80001C) #define AML_AO_RTI_SCP_STAT UL(0xFF80023C) #define AML_AO_RTI_SCP_READY_OFF U(0x14) #define AML_A0_RTI_SCP_READY_MASK U(3) #define AML_AO_RTI_SCP_IS_READY(v) \ ((((v) >> AML_AO_RTI_SCP_READY_OFF) & \ AML_A0_RTI_SCP_READY_MASK) == AML_A0_RTI_SCP_READY_MASK) #define AML_HIU_MAILBOX_SET_0 UL(0xFF63C404) #define AML_HIU_MAILBOX_STAT_0 UL(0xFF63C408) #define AML_HIU_MAILBOX_CLR_0 UL(0xFF63C40C) #define AML_HIU_MAILBOX_SET_3 UL(0xFF63C428) #define AML_HIU_MAILBOX_STAT_3 UL(0xFF63C42C) #define AML_HIU_MAILBOX_CLR_3 UL(0xFF63C430) #define AML_SHA_DMA_BASE UL(0xFF63E000) #define AML_SHA_DMA_DESC (AML_SHA_DMA_BASE + 0x08) #define AML_SHA_DMA_STATUS (AML_SHA_DMA_BASE + 0x28) /******************************************************************************* * System Monitor Call IDs and arguments ******************************************************************************/ #define AML_SM_GET_SHARE_MEM_INPUT_BASE U(0x82000020) #define AML_SM_GET_SHARE_MEM_OUTPUT_BASE U(0x82000021) #define AML_SM_EFUSE_READ U(0x82000030) #define AML_SM_EFUSE_USER_MAX U(0x82000033) #define AML_SM_JTAG_ON U(0x82000040) #define AML_SM_JTAG_OFF U(0x82000041) #define AML_SM_GET_CHIP_ID U(0x82000044) #define AML_JTAG_STATE_ON U(0) #define AML_JTAG_STATE_OFF U(1) #define AML_JTAG_M3_AO U(0) #define AML_JTAG_M3_EE U(1) #define AML_JTAG_A53_AO U(2) #define AML_JTAG_A53_EE U(3) #endif /* G12A_DEF_H */ trusted-firmware-a-2.2/plat/amlogic/g12a/g12a_pm.c000066400000000000000000000114731355360272700216160ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "aml_private.h" #define SCPI_POWER_ON 0 #define SCPI_POWER_RETENTION 1 #define SCPI_POWER_OFF 3 #define SCPI_SYSTEM_SHUTDOWN 0 #define SCPI_SYSTEM_REBOOT 1 static uintptr_t g12a_sec_entrypoint; static volatile uint32_t g12a_cpu0_go; static void g12a_pm_set_reset_addr(u_register_t mpidr, uint64_t value) { unsigned int core = plat_calc_core_pos(mpidr); uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4); mmio_write_64(cpu_mailbox_addr, value); } static void g12a_pm_reset(u_register_t mpidr) { unsigned int core = plat_calc_core_pos(mpidr); uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4) + 8; mmio_write_32(cpu_mailbox_addr, 0); } static void __dead2 g12a_system_reset(void) { INFO("BL31: PSCI_SYSTEM_RESET\n"); u_register_t mpidr = read_mpidr_el1(); uint32_t status = mmio_read_32(AML_AO_RTI_STATUS_REG3); int ret; NOTICE("BL31: Reboot reason: 0x%x\n", status); status &= 0xFFFF0FF0; console_flush(); mmio_write_32(AML_AO_RTI_STATUS_REG3, status); ret = aml_scpi_sys_power_state(SCPI_SYSTEM_REBOOT); if (ret != 0) { ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %i\n", ret); panic(); } g12a_pm_reset(mpidr); wfi(); ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n"); panic(); } static void __dead2 g12a_system_off(void) { INFO("BL31: PSCI_SYSTEM_OFF\n"); u_register_t mpidr = read_mpidr_el1(); int ret; ret = aml_scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN); if (ret != 0) { ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %i\n", ret); panic(); } g12a_pm_set_reset_addr(mpidr, 0); g12a_pm_reset(mpidr); wfi(); ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n"); panic(); } static int32_t g12a_pwr_domain_on(u_register_t mpidr) { unsigned int core = plat_calc_core_pos(mpidr); /* CPU0 can't be turned OFF */ if (core == AML_PRIMARY_CPU) { VERBOSE("BL31: Releasing CPU0 from wait loop...\n"); g12a_cpu0_go = 1; flush_dcache_range((uintptr_t)&g12a_cpu0_go, sizeof(g12a_cpu0_go)); dsb(); isb(); sev(); return PSCI_E_SUCCESS; } g12a_pm_set_reset_addr(mpidr, g12a_sec_entrypoint); aml_scpi_set_css_power_state(mpidr, SCPI_POWER_ON, SCPI_POWER_ON, SCPI_POWER_ON); dmbsy(); sev(); return PSCI_E_SUCCESS; } static void g12a_pwr_domain_on_finish(const psci_power_state_t *target_state) { unsigned int core = plat_calc_core_pos(read_mpidr_el1()); assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == PLAT_LOCAL_STATE_OFF); if (core == AML_PRIMARY_CPU) { g12a_cpu0_go = 0; flush_dcache_range((uintptr_t)&g12a_cpu0_go, sizeof(g12a_cpu0_go)); dsb(); isb(); } gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } static void g12a_pwr_domain_off(const psci_power_state_t *target_state) { u_register_t mpidr = read_mpidr_el1(); unsigned int core = plat_calc_core_pos(mpidr); gicv2_cpuif_disable(); /* CPU0 can't be turned OFF */ if (core == AML_PRIMARY_CPU) return; aml_scpi_set_css_power_state(mpidr, SCPI_POWER_OFF, SCPI_POWER_ON, SCPI_POWER_ON); } static void __dead2 g12a_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state) { u_register_t mpidr = read_mpidr_el1(); unsigned int core = plat_calc_core_pos(mpidr); /* CPU0 can't be turned OFF, emulate it with a WFE loop */ if (core == AML_PRIMARY_CPU) { VERBOSE("BL31: CPU0 entering wait loop...\n"); while (g12a_cpu0_go == 0) wfe(); VERBOSE("BL31: CPU0 resumed.\n"); /* * Because setting CPU0's warm reset entrypoint through PSCI * mailbox and/or mmio mapped RVBAR (0xda834650) does not seem * to work, jump to it manually. * In order to avoid an assert, MMU has to be disabled. */ disable_mmu_el3(); ((void(*)(void))g12a_sec_entrypoint)(); } dsbsy(); g12a_pm_set_reset_addr(mpidr, 0); g12a_pm_reset(mpidr); for (;;) wfi(); } /******************************************************************************* * Platform handlers and setup function. ******************************************************************************/ static const plat_psci_ops_t g12a_ops = { .pwr_domain_on = g12a_pwr_domain_on, .pwr_domain_on_finish = g12a_pwr_domain_on_finish, .pwr_domain_off = g12a_pwr_domain_off, .pwr_domain_pwr_down_wfi = g12a_pwr_domain_pwr_down_wfi, .system_off = g12a_system_off, .system_reset = g12a_system_reset }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { g12a_sec_entrypoint = sec_entrypoint; *psci_ops = &g12a_ops; g12a_cpu0_go = 0; return 0; } trusted-firmware-a-2.2/plat/amlogic/g12a/include/000077500000000000000000000000001355360272700216415ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/amlogic/g12a/include/platform_def.h000066400000000000000000000035061355360272700244600ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include "../g12a_def.h" #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 #define PLATFORM_STACK_SIZE UL(0x1000) #define PLATFORM_MAX_CPUS_PER_CLUSTER U(4) #define PLATFORM_CLUSTER_COUNT U(1) #define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER #define PLATFORM_CORE_COUNT PLATFORM_CLUSTER0_CORE_COUNT #define AML_PRIMARY_CPU U(0) #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1 #define PLAT_NUM_PWR_DOMAINS (PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE U(2) /* Local power state for power domains in Run state. */ #define PLAT_LOCAL_STATE_RUN U(0) /* Local power state for retention. Valid only for CPU power domains */ #define PLAT_LOCAL_STATE_RET U(1) /* Local power state for power-down. Valid for CPU and cluster power domains. */ #define PLAT_LOCAL_STATE_OFF U(2) /* * Macros used to parse state information from State-ID if it is using the * recommended encoding for State-ID. */ #define PLAT_LOCAL_PSTATE_WIDTH U(4) #define PLAT_LOCAL_PSTATE_MASK ((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1) /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. */ #define CACHE_WRITEBACK_SHIFT U(6) #define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT) /* Memory-related defines */ #define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32) #define MAX_MMAP_REGIONS 16 #define MAX_XLAT_TABLES 8 #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/amlogic/g12a/platform.mk000066400000000000000000000045301355360272700223750ustar00rootroot00000000000000# # Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # include lib/xlat_tables_v2/xlat_tables.mk AML_PLAT := plat/amlogic AML_PLAT_SOC := ${AML_PLAT}/${PLAT} AML_PLAT_COMMON := ${AML_PLAT}/common DOIMAGEPATH ?= tools/amlogic DOIMAGETOOL ?= ${DOIMAGEPATH}/doimage PLAT_INCLUDES := -Iinclude/drivers/amlogic/ \ -I${AML_PLAT_SOC}/include \ -I${AML_PLAT_COMMON}/include GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \ plat/common/plat_psci_common.c \ drivers/amlogic/console/aarch64/meson_console.S \ ${AML_PLAT_SOC}/${PLAT}_bl31_setup.c \ ${AML_PLAT_SOC}/${PLAT}_pm.c \ ${AML_PLAT_SOC}/${PLAT}_common.c \ ${AML_PLAT_COMMON}/aarch64/aml_helpers.S \ ${AML_PLAT_COMMON}/aml_efuse.c \ ${AML_PLAT_COMMON}/aml_mhu.c \ ${AML_PLAT_COMMON}/aml_scpi.c \ ${AML_PLAT_COMMON}/aml_sip_svc.c \ ${AML_PLAT_COMMON}/aml_thermal.c \ ${AML_PLAT_COMMON}/aml_topology.c \ ${AML_PLAT_COMMON}/aml_console.c \ drivers/amlogic/crypto/sha_dma.c \ ${XLAT_TABLES_LIB_SRCS} \ ${GIC_SOURCES} # Tune compiler for Cortex-A53 ifeq ($(notdir $(CC)),armclang) TF_CFLAGS_aarch64 += -mcpu=cortex-a53 else ifneq ($(findstring clang,$(notdir $(CC))),) TF_CFLAGS_aarch64 += -mcpu=cortex-a53 else TF_CFLAGS_aarch64 += -mtune=cortex-a53 endif # Build config flags # ------------------ # Enable all errata workarounds for Cortex-A53 ERRATA_A53_855873 := 1 ERRATA_A53_819472 := 1 ERRATA_A53_824069 := 1 ERRATA_A53_827319 := 1 WORKAROUND_CVE_2017_5715 := 0 # Have different sections for code and rodata SEPARATE_CODE_AND_RODATA := 1 # Use Coherent memory USE_COHERENT_MEM := 1 # Verify build config # ------------------- ifneq (${RESET_TO_BL31}, 0) $(error Error: ${PLAT} needs RESET_TO_BL31=0) endif ifeq (${ARCH},aarch32) $(error Error: AArch32 not supported on ${PLAT}) endif all: ${BUILD_PLAT}/bl31.img distclean realclean clean: cleanimage cleanimage: ${Q}${MAKE} -C ${DOIMAGEPATH} clean ${DOIMAGETOOL}: ${Q}${MAKE} -C ${DOIMAGEPATH} ${BUILD_PLAT}/bl31.img: ${BUILD_PLAT}/bl31.bin ${DOIMAGETOOL} ${DOIMAGETOOL} ${BUILD_PLAT}/bl31.bin ${BUILD_PLAT}/bl31.img trusted-firmware-a-2.2/plat/amlogic/gxbb/000077500000000000000000000000001355360272700204065ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/amlogic/gxbb/gxbb_bl31_setup.c000066400000000000000000000111531355360272700235360ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "aml_private.h" /* * Placeholder variables for copying the arguments that have been passed to * BL31 from BL2. */ static entry_point_info_t bl33_image_ep_info; /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for * the security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. ******************************************************************************/ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; assert(type == NON_SECURE); next_image_info = &bl33_image_ep_info; /* None of the images can have 0x0 as the entrypoint. */ if (next_image_info->pc != 0U) { return next_image_info; } else { return NULL; } } /******************************************************************************* * Perform any BL31 early platform setup. Here is an opportunity to copy * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before * they are lost (potentially). This needs to be done before the MMU is * initialized so that the memory layout can be used while creating page * tables. BL2 has flushed this information to memory, so we are guaranteed * to pick up good data. ******************************************************************************/ struct gxbb_bl31_param { param_header_t h; image_info_t *bl31_image_info; entry_point_info_t *bl32_ep_info; image_info_t *bl32_image_info; entry_point_info_t *bl33_ep_info; image_info_t *bl33_image_info; }; void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { struct gxbb_bl31_param *from_bl2; /* Initialize the console to provide early debug support */ aml_console_init(); /* * In debug builds, we pass a special value in 'arg1' to verify platform * parameters from BL2 to BL31. In release builds it's not used. */ assert(arg1 == AML_BL31_PLAT_PARAM_VAL); /* Check that params passed from BL2 are not NULL. */ from_bl2 = (struct gxbb_bl31_param *) arg0; /* Check params passed from BL2 are not NULL. */ assert(from_bl2 != NULL); assert(from_bl2->h.type == PARAM_BL31); assert(from_bl2->h.version >= VERSION_1); /* * Copy BL33 entry point information. It is stored in Secure RAM, in * BL2's address space. */ bl33_image_ep_info = *from_bl2->bl33_ep_info; if (bl33_image_ep_info.pc == 0U) { ERROR("BL31: BL33 entrypoint not obtained from BL2\n"); panic(); } } void bl31_plat_arch_setup(void) { aml_setup_page_tables(); enable_mmu_el3(0); } /******************************************************************************* * GICv2 driver setup information ******************************************************************************/ static const interrupt_prop_t gxbb_interrupt_props[] = { INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), }; static const gicv2_driver_data_t gxbb_gic_data = { .gicd_base = AML_GICD_BASE, .gicc_base = AML_GICC_BASE, .interrupt_props = gxbb_interrupt_props, .interrupt_props_num = ARRAY_SIZE(gxbb_interrupt_props), }; void bl31_platform_setup(void) { aml_mhu_secure_init(); gicv2_driver_init(&gxbb_gic_data); gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); aml_thermal_unknown(); } trusted-firmware-a-2.2/plat/amlogic/gxbb/gxbb_common.c000066400000000000000000000063161355360272700230520ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include /******************************************************************************* * Platform memory map regions ******************************************************************************/ #define MAP_NSDRAM0 MAP_REGION_FLAT(AML_NSDRAM0_BASE, \ AML_NSDRAM0_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define MAP_NSDRAM1 MAP_REGION_FLAT(AML_NSDRAM1_BASE, \ AML_NSDRAM1_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define MAP_SEC_DEVICE0 MAP_REGION_FLAT(AML_SEC_DEVICE0_BASE, \ AML_SEC_DEVICE0_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_SEC_DEVICE1 MAP_REGION_FLAT(AML_SEC_DEVICE1_BASE, \ AML_SEC_DEVICE1_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_TZRAM MAP_REGION_FLAT(AML_TZRAM_BASE, \ AML_TZRAM_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_SEC_DEVICE2 MAP_REGION_FLAT(AML_SEC_DEVICE2_BASE, \ AML_SEC_DEVICE2_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_SEC_DEVICE3 MAP_REGION_FLAT(AML_SEC_DEVICE3_BASE, \ AML_SEC_DEVICE3_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) static const mmap_region_t gxbb_mmap[] = { MAP_NSDRAM0, MAP_NSDRAM1, MAP_SEC_DEVICE0, MAP_SEC_DEVICE1, MAP_TZRAM, MAP_SEC_DEVICE2, MAP_SEC_DEVICE3, {0} }; /******************************************************************************* * Per-image regions ******************************************************************************/ #define MAP_BL31 MAP_REGION_FLAT(BL31_BASE, \ BL31_END - BL31_BASE, \ MT_MEMORY | MT_RW | MT_SECURE) #define MAP_BL_CODE MAP_REGION_FLAT(BL_CODE_BASE, \ BL_CODE_END - BL_CODE_BASE, \ MT_CODE | MT_SECURE) #define MAP_BL_RO_DATA MAP_REGION_FLAT(BL_RO_DATA_BASE, \ BL_RO_DATA_END - BL_RO_DATA_BASE, \ MT_RO_DATA | MT_SECURE) #define MAP_BL_COHERENT MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, \ BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, \ MT_DEVICE | MT_RW | MT_SECURE) /******************************************************************************* * Function that sets up the translation tables. ******************************************************************************/ void aml_setup_page_tables(void) { #if IMAGE_BL31 const mmap_region_t gxbb_bl_mmap[] = { MAP_BL31, MAP_BL_CODE, MAP_BL_RO_DATA, #if USE_COHERENT_MEM MAP_BL_COHERENT, #endif {0} }; #endif mmap_add(gxbb_bl_mmap); mmap_add(gxbb_mmap); init_xlat_tables(); } /******************************************************************************* * Function that returns the system counter frequency ******************************************************************************/ unsigned int plat_get_syscnt_freq2(void) { uint32_t val; val = mmio_read_32(AML_SYS_CPU_CFG7); val &= 0xFDFFFFFF; mmio_write_32(AML_SYS_CPU_CFG7, val); val = mmio_read_32(AML_AO_TIMESTAMP_CNTL); val &= 0xFFFFFE00; mmio_write_32(AML_AO_TIMESTAMP_CNTL, val); return AML_OSC24M_CLK_IN_HZ; } trusted-firmware-a-2.2/plat/amlogic/gxbb/gxbb_def.h000066400000000000000000000101531355360272700223170ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef GXBB_DEF_H #define GXBB_DEF_H #include /******************************************************************************* * System oscillator ******************************************************************************/ #define AML_OSC24M_CLK_IN_HZ ULL(24000000) /* 24 MHz */ /******************************************************************************* * Memory regions ******************************************************************************/ #define AML_NSDRAM0_BASE UL(0x01000000) #define AML_NSDRAM0_SIZE UL(0x0F000000) #define AML_NSDRAM1_BASE UL(0x10000000) #define AML_NSDRAM1_SIZE UL(0x00100000) #define BL31_BASE UL(0x10100000) #define BL31_SIZE UL(0x000C0000) #define BL31_LIMIT (BL31_BASE + BL31_SIZE) /* Shared memory used for SMC services */ #define AML_SHARE_MEM_INPUT_BASE UL(0x100FE000) #define AML_SHARE_MEM_OUTPUT_BASE UL(0x100FF000) #define AML_SEC_DEVICE0_BASE UL(0xC0000000) #define AML_SEC_DEVICE0_SIZE UL(0x09000000) #define AML_SEC_DEVICE1_BASE UL(0xD0040000) #define AML_SEC_DEVICE1_SIZE UL(0x00008000) #define AML_TZRAM_BASE UL(0xD9000000) #define AML_TZRAM_SIZE UL(0x00014000) /* Top 0xC000 bytes (up to 0xD9020000) used by BL2 */ /* Mailboxes */ #define AML_MHU_SECURE_SCP_TO_AP_PAYLOAD UL(0xD9013800) #define AML_MHU_SECURE_AP_TO_SCP_PAYLOAD UL(0xD9013A00) #define AML_PSCI_MAILBOX_BASE UL(0xD9013F00) #define AML_TZROM_BASE UL(0xD9040000) #define AML_TZROM_SIZE UL(0x00010000) #define AML_SEC_DEVICE2_BASE UL(0xDA000000) #define AML_SEC_DEVICE2_SIZE UL(0x00200000) #define AML_SEC_DEVICE3_BASE UL(0xDA800000) #define AML_SEC_DEVICE3_SIZE UL(0x00200000) /******************************************************************************* * GIC-400 and interrupt handling related constants ******************************************************************************/ #define AML_GICD_BASE UL(0xC4301000) #define AML_GICC_BASE UL(0xC4302000) #define IRQ_SEC_PHY_TIMER 29 #define IRQ_SEC_SGI_0 8 #define IRQ_SEC_SGI_1 9 #define IRQ_SEC_SGI_2 10 #define IRQ_SEC_SGI_3 11 #define IRQ_SEC_SGI_4 12 #define IRQ_SEC_SGI_5 13 #define IRQ_SEC_SGI_6 14 #define IRQ_SEC_SGI_7 15 /******************************************************************************* * UART definitions ******************************************************************************/ #define AML_UART0_AO_BASE UL(0xC81004C0) #define AML_UART0_AO_CLK_IN_HZ AML_OSC24M_CLK_IN_HZ #define AML_UART_BAUDRATE U(115200) /******************************************************************************* * Memory-mapped I/O Registers ******************************************************************************/ #define AML_AO_TIMESTAMP_CNTL UL(0xC81000B4) #define AML_SYS_CPU_CFG7 UL(0xC8834664) #define AML_AO_RTI_STATUS_REG3 UL(0xDA10001C) #define AML_HIU_MAILBOX_SET_0 UL(0xDA83C404) #define AML_HIU_MAILBOX_STAT_0 UL(0xDA83C408) #define AML_HIU_MAILBOX_CLR_0 UL(0xDA83C40C) #define AML_HIU_MAILBOX_SET_3 UL(0xDA83C428) #define AML_HIU_MAILBOX_STAT_3 UL(0xDA83C42C) #define AML_HIU_MAILBOX_CLR_3 UL(0xDA83C430) #define AML_SHA_DMA_BASE UL(0xC883E000) #define AML_SHA_DMA_DESC (AML_SHA_DMA_BASE + 0x08) #define AML_SHA_DMA_STATUS (AML_SHA_DMA_BASE + 0x18) /******************************************************************************* * System Monitor Call IDs and arguments ******************************************************************************/ #define AML_SM_GET_SHARE_MEM_INPUT_BASE U(0x82000020) #define AML_SM_GET_SHARE_MEM_OUTPUT_BASE U(0x82000021) #define AML_SM_EFUSE_READ U(0x82000030) #define AML_SM_EFUSE_USER_MAX U(0x82000033) #define AML_SM_JTAG_ON U(0x82000040) #define AML_SM_JTAG_OFF U(0x82000041) #define AML_SM_GET_CHIP_ID U(0x82000044) #define AML_JTAG_STATE_ON U(0) #define AML_JTAG_STATE_OFF U(1) #define AML_JTAG_M3_AO U(0) #define AML_JTAG_M3_EE U(1) #define AML_JTAG_A53_AO U(2) #define AML_JTAG_A53_EE U(3) #endif /* GXBB_DEF_H */ trusted-firmware-a-2.2/plat/amlogic/gxbb/gxbb_pm.c000066400000000000000000000106241355360272700221730ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "aml_private.h" #define SCPI_POWER_ON 0 #define SCPI_POWER_RETENTION 1 #define SCPI_POWER_OFF 3 #define SCPI_SYSTEM_SHUTDOWN 0 #define SCPI_SYSTEM_REBOOT 1 static uintptr_t gxbb_sec_entrypoint; static volatile uint32_t gxbb_cpu0_go; static void gxbb_program_mailbox(u_register_t mpidr, uint64_t value) { unsigned int core = plat_calc_core_pos(mpidr); uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4); mmio_write_64(cpu_mailbox_addr, value); flush_dcache_range(cpu_mailbox_addr, sizeof(uint64_t)); } static void __dead2 gxbb_system_reset(void) { INFO("BL31: PSCI_SYSTEM_RESET\n"); uint32_t status = mmio_read_32(AML_AO_RTI_STATUS_REG3); NOTICE("BL31: Reboot reason: 0x%x\n", status); status &= 0xFFFF0FF0; console_flush(); mmio_write_32(AML_AO_RTI_STATUS_REG3, status); int ret = aml_scpi_sys_power_state(SCPI_SYSTEM_REBOOT); if (ret != 0) { ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %u\n", ret); panic(); } wfi(); ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n"); panic(); } static void __dead2 gxbb_system_off(void) { INFO("BL31: PSCI_SYSTEM_OFF\n"); unsigned int ret = aml_scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN); if (ret != 0) { ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %u\n", ret); panic(); } gxbb_program_mailbox(read_mpidr_el1(), 0); wfi(); ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n"); panic(); } static int32_t gxbb_pwr_domain_on(u_register_t mpidr) { unsigned int core = plat_calc_core_pos(mpidr); /* CPU0 can't be turned OFF, emulate it with a WFE loop */ if (core == AML_PRIMARY_CPU) { VERBOSE("BL31: Releasing CPU0 from wait loop...\n"); gxbb_cpu0_go = 1; flush_dcache_range((uintptr_t)&gxbb_cpu0_go, sizeof(gxbb_cpu0_go)); dsb(); isb(); sev(); return PSCI_E_SUCCESS; } gxbb_program_mailbox(mpidr, gxbb_sec_entrypoint); aml_scpi_set_css_power_state(mpidr, SCPI_POWER_ON, SCPI_POWER_ON, SCPI_POWER_ON); dmbsy(); sev(); return PSCI_E_SUCCESS; } static void gxbb_pwr_domain_on_finish(const psci_power_state_t *target_state) { unsigned int core = plat_calc_core_pos(read_mpidr_el1()); assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == PLAT_LOCAL_STATE_OFF); if (core == AML_PRIMARY_CPU) { gxbb_cpu0_go = 0; flush_dcache_range((uintptr_t)&gxbb_cpu0_go, sizeof(gxbb_cpu0_go)); dsb(); isb(); } gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } static void gxbb_pwr_domain_off(const psci_power_state_t *target_state) { u_register_t mpidr = read_mpidr_el1(); unsigned int core = plat_calc_core_pos(mpidr); uintptr_t addr = AML_PSCI_MAILBOX_BASE + 8 + (core << 4); mmio_write_32(addr, 0xFFFFFFFF); flush_dcache_range(addr, sizeof(uint32_t)); gicv2_cpuif_disable(); /* CPU0 can't be turned OFF, emulate it with a WFE loop */ if (core == AML_PRIMARY_CPU) return; aml_scpi_set_css_power_state(mpidr, SCPI_POWER_OFF, SCPI_POWER_ON, SCPI_POWER_ON); } static void __dead2 gxbb_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state) { unsigned int core = plat_calc_core_pos(read_mpidr_el1()); /* CPU0 can't be turned OFF, emulate it with a WFE loop */ if (core == AML_PRIMARY_CPU) { VERBOSE("BL31: CPU0 entering wait loop...\n"); while (gxbb_cpu0_go == 0) wfe(); VERBOSE("BL31: CPU0 resumed.\n"); write_rmr_el3(RMR_EL3_RR_BIT | RMR_EL3_AA64_BIT); } dsbsy(); for (;;) wfi(); } /******************************************************************************* * Platform handlers and setup function. ******************************************************************************/ static const plat_psci_ops_t gxbb_ops = { .pwr_domain_on = gxbb_pwr_domain_on, .pwr_domain_on_finish = gxbb_pwr_domain_on_finish, .pwr_domain_off = gxbb_pwr_domain_off, .pwr_domain_pwr_down_wfi = gxbb_pwr_domain_pwr_down_wfi, .system_off = gxbb_system_off, .system_reset = gxbb_system_reset, }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { gxbb_sec_entrypoint = sec_entrypoint; *psci_ops = &gxbb_ops; gxbb_cpu0_go = 0; return 0; } trusted-firmware-a-2.2/plat/amlogic/gxbb/include/000077500000000000000000000000001355360272700220315ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/amlogic/gxbb/include/platform_def.h000066400000000000000000000037141355360272700246510ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include "../gxbb_def.h" #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 /* Special value used to verify platform parameters from BL2 to BL31 */ #define AML_BL31_PLAT_PARAM_VAL ULL(0x0F1E2D3C4B5A6978) #define PLATFORM_STACK_SIZE UL(0x1000) #define PLATFORM_MAX_CPUS_PER_CLUSTER U(4) #define PLATFORM_CLUSTER_COUNT U(1) #define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER #define PLATFORM_CORE_COUNT PLATFORM_CLUSTER0_CORE_COUNT #define AML_PRIMARY_CPU U(0) #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1 #define PLAT_NUM_PWR_DOMAINS (PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE U(2) /* Local power state for power domains in Run state. */ #define PLAT_LOCAL_STATE_RUN U(0) /* Local power state for retention. Valid only for CPU power domains */ #define PLAT_LOCAL_STATE_RET U(1) /* Local power state for power-down. Valid for CPU and cluster power domains. */ #define PLAT_LOCAL_STATE_OFF U(2) /* * Macros used to parse state information from State-ID if it is using the * recommended encoding for State-ID. */ #define PLAT_LOCAL_PSTATE_WIDTH U(4) #define PLAT_LOCAL_PSTATE_MASK ((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1) /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. */ #define CACHE_WRITEBACK_SHIFT U(6) #define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT) /* Memory-related defines */ #define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32) #define MAX_MMAP_REGIONS 12 #define MAX_XLAT_TABLES 5 #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/amlogic/gxbb/platform.mk000066400000000000000000000037441355360272700225730ustar00rootroot00000000000000# # Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # include lib/xlat_tables_v2/xlat_tables.mk AML_PLAT := plat/amlogic AML_PLAT_SOC := ${AML_PLAT}/${PLAT} AML_PLAT_COMMON := ${AML_PLAT}/common PLAT_INCLUDES := -Iinclude/drivers/amlogic/ \ -I${AML_PLAT_SOC}/include \ -I${AML_PLAT_COMMON}/include GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \ plat/common/plat_psci_common.c \ drivers/amlogic/console/aarch64/meson_console.S \ ${AML_PLAT_SOC}/${PLAT}_bl31_setup.c \ ${AML_PLAT_SOC}/${PLAT}_pm.c \ ${AML_PLAT_SOC}/${PLAT}_common.c \ ${AML_PLAT_COMMON}/aarch64/aml_helpers.S \ ${AML_PLAT_COMMON}/aml_efuse.c \ ${AML_PLAT_COMMON}/aml_mhu.c \ ${AML_PLAT_COMMON}/aml_scpi.c \ ${AML_PLAT_COMMON}/aml_sip_svc.c \ ${AML_PLAT_COMMON}/aml_thermal.c \ ${AML_PLAT_COMMON}/aml_topology.c \ ${AML_PLAT_COMMON}/aml_console.c \ ${XLAT_TABLES_LIB_SRCS} \ ${GIC_SOURCES} # Tune compiler for Cortex-A53 ifeq ($(notdir $(CC)),armclang) TF_CFLAGS_aarch64 += -mcpu=cortex-a53 else ifneq ($(findstring clang,$(notdir $(CC))),) TF_CFLAGS_aarch64 += -mcpu=cortex-a53 else TF_CFLAGS_aarch64 += -mtune=cortex-a53 endif # Build config flags # ------------------ # Enable all errata workarounds for Cortex-A53 ERRATA_A53_826319 := 1 ERRATA_A53_835769 := 1 ERRATA_A53_836870 := 1 ERRATA_A53_843419 := 1 ERRATA_A53_855873 := 1 WORKAROUND_CVE_2017_5715 := 0 # Have different sections for code and rodata SEPARATE_CODE_AND_RODATA := 1 # Use Coherent memory USE_COHERENT_MEM := 1 # Verify build config # ------------------- ifneq (${RESET_TO_BL31}, 0) $(error Error: ${PLAT} needs RESET_TO_BL31=0) endif ifeq (${ARCH},aarch32) $(error Error: AArch32 not supported on ${PLAT}) endif trusted-firmware-a-2.2/plat/amlogic/gxl/000077500000000000000000000000001355360272700202565ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/amlogic/gxl/gxl_bl31_setup.c000066400000000000000000000120221355360272700232520ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include "aml_private.h" /* * Placeholder variables for copying the arguments that have been passed to * BL31 from BL2. */ static entry_point_info_t bl33_image_ep_info; static image_info_t bl30_image_info; static image_info_t bl301_image_info; /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for * the security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. ******************************************************************************/ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; assert(type == NON_SECURE); next_image_info = &bl33_image_ep_info; /* None of the images can have 0x0 as the entrypoint. */ if (next_image_info->pc != 0U) { return next_image_info; } else { return NULL; } } /******************************************************************************* * Perform any BL31 early platform setup. Here is an opportunity to copy * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before * they are lost (potentially). This needs to be done before the MMU is * initialized so that the memory layout can be used while creating page * tables. BL2 has flushed this information to memory, so we are guaranteed * to pick up good data. ******************************************************************************/ struct gxl_bl31_param { param_header_t h; image_info_t *bl31_image_info; entry_point_info_t *bl32_ep_info; image_info_t *bl32_image_info; entry_point_info_t *bl33_ep_info; image_info_t *bl33_image_info; image_info_t *scp_image_info[]; }; void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { struct gxl_bl31_param *from_bl2; /* Initialize the console to provide early debug support */ aml_console_init(); /* Check that params passed from BL2 are not NULL. */ from_bl2 = (struct gxl_bl31_param *) arg0; /* Check params passed from BL2 are not NULL. */ assert(from_bl2 != NULL); assert(from_bl2->h.type == PARAM_BL31); assert(from_bl2->h.version >= VERSION_1); /* * Copy BL33 entry point information. It is stored in Secure RAM, in * BL2's address space. */ bl33_image_ep_info = *from_bl2->bl33_ep_info; if (bl33_image_ep_info.pc == 0U) { ERROR("BL31: BL33 entrypoint not obtained from BL2\n"); panic(); } bl30_image_info = *from_bl2->scp_image_info[0]; bl301_image_info = *from_bl2->scp_image_info[1]; } void bl31_plat_arch_setup(void) { aml_setup_page_tables(); enable_mmu_el3(0); } static inline bool gxl_scp_ready(void) { return AML_AO_RTI_SCP_IS_READY(mmio_read_32(AML_AO_RTI_SCP_STAT)); } static inline void gxl_scp_boot(void) { aml_scpi_upload_scp_fw(bl30_image_info.image_base, bl30_image_info.image_size, 0); aml_scpi_upload_scp_fw(bl301_image_info.image_base, bl301_image_info.image_size, 1); while (!gxl_scp_ready()) ; } /******************************************************************************* * GICv2 driver setup information ******************************************************************************/ static const interrupt_prop_t gxl_interrupt_props[] = { INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), }; static const gicv2_driver_data_t gxl_gic_data = { .gicd_base = AML_GICD_BASE, .gicc_base = AML_GICC_BASE, .interrupt_props = gxl_interrupt_props, .interrupt_props_num = ARRAY_SIZE(gxl_interrupt_props), }; void bl31_platform_setup(void) { aml_mhu_secure_init(); gicv2_driver_init(&gxl_gic_data); gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); gxl_scp_boot(); aml_thermal_unknown(); } trusted-firmware-a-2.2/plat/amlogic/gxl/gxl_common.c000066400000000000000000000063121355360272700225660ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include /******************************************************************************* * Platform memory map regions ******************************************************************************/ #define MAP_NSDRAM0 MAP_REGION_FLAT(AML_NSDRAM0_BASE, \ AML_NSDRAM0_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define MAP_NSDRAM1 MAP_REGION_FLAT(AML_NSDRAM1_BASE, \ AML_NSDRAM1_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define MAP_SEC_DEVICE0 MAP_REGION_FLAT(AML_SEC_DEVICE0_BASE, \ AML_SEC_DEVICE0_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_SEC_DEVICE1 MAP_REGION_FLAT(AML_SEC_DEVICE1_BASE, \ AML_SEC_DEVICE1_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_TZRAM MAP_REGION_FLAT(AML_TZRAM_BASE, \ AML_TZRAM_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_SEC_DEVICE2 MAP_REGION_FLAT(AML_SEC_DEVICE2_BASE, \ AML_SEC_DEVICE2_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_SEC_DEVICE3 MAP_REGION_FLAT(AML_SEC_DEVICE3_BASE, \ AML_SEC_DEVICE3_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) static const mmap_region_t gxl_mmap[] = { MAP_NSDRAM0, MAP_NSDRAM1, MAP_SEC_DEVICE0, MAP_SEC_DEVICE1, MAP_TZRAM, MAP_SEC_DEVICE2, MAP_SEC_DEVICE3, {0} }; /******************************************************************************* * Per-image regions ******************************************************************************/ #define MAP_BL31 MAP_REGION_FLAT(BL31_BASE, \ BL31_END - BL31_BASE, \ MT_MEMORY | MT_RW | MT_SECURE) #define MAP_BL_CODE MAP_REGION_FLAT(BL_CODE_BASE, \ BL_CODE_END - BL_CODE_BASE, \ MT_CODE | MT_SECURE) #define MAP_BL_RO_DATA MAP_REGION_FLAT(BL_RO_DATA_BASE, \ BL_RO_DATA_END - BL_RO_DATA_BASE, \ MT_RO_DATA | MT_SECURE) #define MAP_BL_COHERENT MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, \ BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, \ MT_DEVICE | MT_RW | MT_SECURE) /******************************************************************************* * Function that sets up the translation tables. ******************************************************************************/ void aml_setup_page_tables(void) { #if IMAGE_BL31 const mmap_region_t gxl_bl_mmap[] = { MAP_BL31, MAP_BL_CODE, MAP_BL_RO_DATA, #if USE_COHERENT_MEM MAP_BL_COHERENT, #endif {0} }; #endif mmap_add(gxl_bl_mmap); mmap_add(gxl_mmap); init_xlat_tables(); } /******************************************************************************* * Function that returns the system counter frequency ******************************************************************************/ unsigned int plat_get_syscnt_freq2(void) { uint32_t val; val = mmio_read_32(AML_SYS_CPU_CFG7); val &= 0xFDFFFFFF; mmio_write_32(AML_SYS_CPU_CFG7, val); val = mmio_read_32(AML_AO_TIMESTAMP_CNTL); val &= 0xFFFFFE00; mmio_write_32(AML_AO_TIMESTAMP_CNTL, val); return AML_OSC24M_CLK_IN_HZ; } trusted-firmware-a-2.2/plat/amlogic/gxl/gxl_def.h000066400000000000000000000110361355360272700220400ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef GXL_DEF_H #define GXL_DEF_H #include /******************************************************************************* * System oscillator ******************************************************************************/ #define AML_OSC24M_CLK_IN_HZ ULL(24000000) /* 24 MHz */ /******************************************************************************* * Memory regions ******************************************************************************/ #define AML_NSDRAM0_BASE UL(0x01000000) #define AML_NSDRAM0_SIZE UL(0x0F000000) #define AML_NSDRAM1_BASE UL(0x10000000) #define AML_NSDRAM1_SIZE UL(0x00100000) #define BL31_BASE UL(0x05100000) #define BL31_SIZE UL(0x000C0000) #define BL31_LIMIT (BL31_BASE + BL31_SIZE) /* Shared memory used for SMC services */ #define AML_SHARE_MEM_INPUT_BASE UL(0x050FE000) #define AML_SHARE_MEM_OUTPUT_BASE UL(0x050FF000) #define AML_SEC_DEVICE0_BASE UL(0xC0000000) #define AML_SEC_DEVICE0_SIZE UL(0x09000000) #define AML_SEC_DEVICE1_BASE UL(0xD0040000) #define AML_SEC_DEVICE1_SIZE UL(0x00008000) #define AML_TZRAM_BASE UL(0xD9000000) #define AML_TZRAM_SIZE UL(0x00014000) /* Top 0xC000 bytes (up to 0xD9020000) used by BL2 */ /* Mailboxes */ #define AML_MHU_SECURE_SCP_TO_AP_PAYLOAD UL(0xD9013800) #define AML_MHU_SECURE_AP_TO_SCP_PAYLOAD UL(0xD9013A00) #define AML_PSCI_MAILBOX_BASE UL(0xD9013F00) // * [ 1K] 0xD901_3800 - 0xD901_3BFF Secure Mailbox (3) // * [ 1K] 0xD901_3400 - 0xD901_37FF High Mailbox (2) * // * [ 1K] 0xD901_3000 - 0xD901_33FF High Mailbox (1) * #define AML_TZROM_BASE UL(0xD9040000) #define AML_TZROM_SIZE UL(0x00010000) #define AML_SEC_DEVICE2_BASE UL(0xDA000000) #define AML_SEC_DEVICE2_SIZE UL(0x00200000) #define AML_SEC_DEVICE3_BASE UL(0xDA800000) #define AML_SEC_DEVICE3_SIZE UL(0x00200000) /******************************************************************************* * GIC-400 and interrupt handling related constants ******************************************************************************/ #define AML_GICD_BASE UL(0xC4301000) #define AML_GICC_BASE UL(0xC4302000) #define IRQ_SEC_PHY_TIMER 29 #define IRQ_SEC_SGI_0 8 #define IRQ_SEC_SGI_1 9 #define IRQ_SEC_SGI_2 10 #define IRQ_SEC_SGI_3 11 #define IRQ_SEC_SGI_4 12 #define IRQ_SEC_SGI_5 13 #define IRQ_SEC_SGI_6 14 #define IRQ_SEC_SGI_7 15 /******************************************************************************* * UART definitions ******************************************************************************/ #define AML_UART0_AO_BASE UL(0xC81004C0) #define AML_UART0_AO_CLK_IN_HZ AML_OSC24M_CLK_IN_HZ #define AML_UART_BAUDRATE U(115200) /******************************************************************************* * Memory-mapped I/O Registers ******************************************************************************/ #define AML_AO_TIMESTAMP_CNTL UL(0xC81000B4) #define AML_SYS_CPU_CFG7 UL(0xC8834664) #define AML_AO_RTI_STATUS_REG3 UL(0xDA10001C) #define AML_AO_RTI_SCP_STAT UL(0xDA10023C) #define AML_AO_RTI_SCP_READY_OFF U(0x14) #define AML_A0_RTI_SCP_READY_MASK U(3) #define AML_AO_RTI_SCP_IS_READY(v) \ ((((v) >> AML_AO_RTI_SCP_READY_OFF) & \ AML_A0_RTI_SCP_READY_MASK) == AML_A0_RTI_SCP_READY_MASK) #define AML_HIU_MAILBOX_SET_0 UL(0xDA83C404) #define AML_HIU_MAILBOX_STAT_0 UL(0xDA83C408) #define AML_HIU_MAILBOX_CLR_0 UL(0xDA83C40C) #define AML_HIU_MAILBOX_SET_3 UL(0xDA83C428) #define AML_HIU_MAILBOX_STAT_3 UL(0xDA83C42C) #define AML_HIU_MAILBOX_CLR_3 UL(0xDA83C430) #define AML_SHA_DMA_BASE UL(0xC883E000) #define AML_SHA_DMA_DESC (AML_SHA_DMA_BASE + 0x08) #define AML_SHA_DMA_STATUS (AML_SHA_DMA_BASE + 0x18) /******************************************************************************* * System Monitor Call IDs and arguments ******************************************************************************/ #define AML_SM_GET_SHARE_MEM_INPUT_BASE U(0x82000020) #define AML_SM_GET_SHARE_MEM_OUTPUT_BASE U(0x82000021) #define AML_SM_EFUSE_READ U(0x82000030) #define AML_SM_EFUSE_USER_MAX U(0x82000033) #define AML_SM_JTAG_ON U(0x82000040) #define AML_SM_JTAG_OFF U(0x82000041) #define AML_SM_GET_CHIP_ID U(0x82000044) #define AML_JTAG_STATE_ON U(0) #define AML_JTAG_STATE_OFF U(1) #define AML_JTAG_M3_AO U(0) #define AML_JTAG_M3_EE U(1) #define AML_JTAG_A53_AO U(2) #define AML_JTAG_A53_EE U(3) #endif /* GXL_DEF_H */ trusted-firmware-a-2.2/plat/amlogic/gxl/gxl_pm.c000066400000000000000000000115151355360272700217130ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "aml_private.h" #define SCPI_POWER_ON 0 #define SCPI_POWER_RETENTION 1 #define SCPI_POWER_OFF 3 #define SCPI_SYSTEM_SHUTDOWN 0 #define SCPI_SYSTEM_REBOOT 1 static uintptr_t gxl_sec_entrypoint; static volatile uint32_t gxl_cpu0_go; static void gxl_pm_set_reset_addr(u_register_t mpidr, uint64_t value) { unsigned int core = plat_calc_core_pos(mpidr); uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4); mmio_write_64(cpu_mailbox_addr, value); } static void gxl_pm_reset(u_register_t mpidr) { unsigned int core = plat_calc_core_pos(mpidr); uintptr_t cpu_mailbox_addr = AML_PSCI_MAILBOX_BASE + (core << 4) + 8; mmio_write_32(cpu_mailbox_addr, 0); } static void __dead2 gxl_system_reset(void) { INFO("BL31: PSCI_SYSTEM_RESET\n"); u_register_t mpidr = read_mpidr_el1(); uint32_t status = mmio_read_32(AML_AO_RTI_STATUS_REG3); int ret; NOTICE("BL31: Reboot reason: 0x%x\n", status); status &= 0xFFFF0FF0; console_flush(); mmio_write_32(AML_AO_RTI_STATUS_REG3, status); ret = aml_scpi_sys_power_state(SCPI_SYSTEM_REBOOT); if (ret != 0) { ERROR("BL31: PSCI_SYSTEM_RESET: SCP error: %i\n", ret); panic(); } gxl_pm_reset(mpidr); wfi(); ERROR("BL31: PSCI_SYSTEM_RESET: Operation not handled\n"); panic(); } static void __dead2 gxl_system_off(void) { INFO("BL31: PSCI_SYSTEM_OFF\n"); u_register_t mpidr = read_mpidr_el1(); int ret; ret = aml_scpi_sys_power_state(SCPI_SYSTEM_SHUTDOWN); if (ret != 0) { ERROR("BL31: PSCI_SYSTEM_OFF: SCP error %i\n", ret); panic(); } gxl_pm_set_reset_addr(mpidr, 0); gxl_pm_reset(mpidr); wfi(); ERROR("BL31: PSCI_SYSTEM_OFF: Operation not handled\n"); panic(); } static int32_t gxl_pwr_domain_on(u_register_t mpidr) { unsigned int core = plat_calc_core_pos(mpidr); /* CPU0 can't be turned OFF, emulate it with a WFE loop */ if (core == AML_PRIMARY_CPU) { VERBOSE("BL31: Releasing CPU0 from wait loop...\n"); gxl_cpu0_go = 1; flush_dcache_range((uintptr_t)&gxl_cpu0_go, sizeof(gxl_cpu0_go)); dsb(); isb(); sev(); return PSCI_E_SUCCESS; } gxl_pm_set_reset_addr(mpidr, gxl_sec_entrypoint); aml_scpi_set_css_power_state(mpidr, SCPI_POWER_ON, SCPI_POWER_ON, SCPI_POWER_ON); dmbsy(); sev(); return PSCI_E_SUCCESS; } static void gxl_pwr_domain_on_finish(const psci_power_state_t *target_state) { unsigned int core = plat_calc_core_pos(read_mpidr_el1()); assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == PLAT_LOCAL_STATE_OFF); if (core == AML_PRIMARY_CPU) { gxl_cpu0_go = 0; flush_dcache_range((uintptr_t)&gxl_cpu0_go, sizeof(gxl_cpu0_go)); dsb(); isb(); } gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } static void gxl_pwr_domain_off(const psci_power_state_t *target_state) { u_register_t mpidr = read_mpidr_el1(); unsigned int core = plat_calc_core_pos(mpidr); gicv2_cpuif_disable(); /* CPU0 can't be turned OFF, emulate it with a WFE loop */ if (core == AML_PRIMARY_CPU) return; aml_scpi_set_css_power_state(mpidr, SCPI_POWER_OFF, SCPI_POWER_ON, SCPI_POWER_ON); } static void __dead2 gxl_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state) { u_register_t mpidr = read_mpidr_el1(); unsigned int core = plat_calc_core_pos(mpidr); /* CPU0 can't be turned OFF, emulate it with a WFE loop */ if (core == AML_PRIMARY_CPU) { VERBOSE("BL31: CPU0 entering wait loop...\n"); while (gxl_cpu0_go == 0) wfe(); VERBOSE("BL31: CPU0 resumed.\n"); /* * Because setting CPU0's warm reset entrypoint through PSCI * mailbox and/or mmio mapped RVBAR (0xda834650) does not seem * to work, jump to it manually. * In order to avoid an assert, mmu has to be disabled. */ disable_mmu_el3(); ((void(*)(void))gxl_sec_entrypoint)(); } dsbsy(); gxl_pm_set_reset_addr(mpidr, 0); gxl_pm_reset(mpidr); for (;;) wfi(); } /******************************************************************************* * Platform handlers and setup function. ******************************************************************************/ static const plat_psci_ops_t gxl_ops = { .pwr_domain_on = gxl_pwr_domain_on, .pwr_domain_on_finish = gxl_pwr_domain_on_finish, .pwr_domain_off = gxl_pwr_domain_off, .pwr_domain_pwr_down_wfi = gxl_pwr_domain_pwr_down_wfi, .system_off = gxl_system_off, .system_reset = gxl_system_reset, }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { gxl_sec_entrypoint = sec_entrypoint; *psci_ops = &gxl_ops; gxl_cpu0_go = 0; return 0; } trusted-firmware-a-2.2/plat/amlogic/gxl/include/000077500000000000000000000000001355360272700217015ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/amlogic/gxl/include/platform_def.h000066400000000000000000000035121355360272700245150ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include "../gxl_def.h" #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 #define PLATFORM_STACK_SIZE UL(0x1000) #define PLATFORM_MAX_CPUS_PER_CLUSTER U(4) #define PLATFORM_CLUSTER_COUNT U(1) #define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER #define PLATFORM_CORE_COUNT PLATFORM_CLUSTER0_CORE_COUNT #define AML_PRIMARY_CPU U(0) #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1 #define PLAT_NUM_PWR_DOMAINS (PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE U(2) /* Local power state for power domains in Run state. */ #define PLAT_LOCAL_STATE_RUN U(0) /* Local power state for retention. Valid only for CPU power domains */ #define PLAT_LOCAL_STATE_RET U(1) /* Local power state for power-down. Valid for CPU and cluster power domains. */ #define PLAT_LOCAL_STATE_OFF U(2) /* * Macros used to parse state information from State-ID if it is using the * recommended encoding for State-ID. */ #define PLAT_LOCAL_PSTATE_WIDTH U(4) #define PLAT_LOCAL_PSTATE_MASK ((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1) /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. */ #define CACHE_WRITEBACK_SHIFT U(6) #define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT) /* Memory-related defines */ #define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32) #define MAX_MMAP_REGIONS 12 #define MAX_XLAT_TABLES 6 #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/amlogic/gxl/platform.mk000066400000000000000000000045351355360272700224420ustar00rootroot00000000000000# # Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # include lib/xlat_tables_v2/xlat_tables.mk AML_PLAT := plat/amlogic AML_PLAT_SOC := ${AML_PLAT}/${PLAT} AML_PLAT_COMMON := ${AML_PLAT}/common DOIMAGEPATH ?= tools/amlogic DOIMAGETOOL ?= ${DOIMAGEPATH}/doimage PLAT_INCLUDES := -Iinclude/drivers/amlogic/ \ -I${AML_PLAT_SOC}/include \ -I${AML_PLAT_COMMON}/include GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \ plat/common/plat_psci_common.c \ drivers/amlogic/console/aarch64/meson_console.S \ ${AML_PLAT_SOC}/${PLAT}_bl31_setup.c \ ${AML_PLAT_SOC}/${PLAT}_pm.c \ ${AML_PLAT_SOC}/${PLAT}_common.c \ ${AML_PLAT_COMMON}/aarch64/aml_helpers.S \ ${AML_PLAT_COMMON}/aml_efuse.c \ ${AML_PLAT_COMMON}/aml_mhu.c \ ${AML_PLAT_COMMON}/aml_scpi.c \ ${AML_PLAT_COMMON}/aml_sip_svc.c \ ${AML_PLAT_COMMON}/aml_thermal.c \ ${AML_PLAT_COMMON}/aml_topology.c \ ${AML_PLAT_COMMON}/aml_console.c \ drivers/amlogic/crypto/sha_dma.c \ ${XLAT_TABLES_LIB_SRCS} \ ${GIC_SOURCES} # Tune compiler for Cortex-A53 ifeq ($(notdir $(CC)),armclang) TF_CFLAGS_aarch64 += -mcpu=cortex-a53 else ifneq ($(findstring clang,$(notdir $(CC))),) TF_CFLAGS_aarch64 += -mcpu=cortex-a53 else TF_CFLAGS_aarch64 += -mtune=cortex-a53 endif # Build config flags # ------------------ # Enable all errata workarounds for Cortex-A53 ERRATA_A53_855873 := 1 ERRATA_A53_819472 := 1 ERRATA_A53_824069 := 1 ERRATA_A53_827319 := 1 WORKAROUND_CVE_2017_5715 := 0 # Have different sections for code and rodata SEPARATE_CODE_AND_RODATA := 1 # Use Coherent memory USE_COHERENT_MEM := 1 # Verify build config # ------------------- ifneq (${RESET_TO_BL31}, 0) $(error Error: ${PLAT} needs RESET_TO_BL31=0) endif ifeq (${ARCH},aarch32) $(error Error: AArch32 not supported on ${PLAT}) endif all: ${BUILD_PLAT}/bl31.img distclean realclean clean: cleanimage cleanimage: ${Q}${MAKE} -C ${DOIMAGEPATH} clean ${DOIMAGETOOL}: ${Q}${MAKE} -C ${DOIMAGEPATH} ${BUILD_PLAT}/bl31.img: ${BUILD_PLAT}/bl31.bin ${DOIMAGETOOL} ${DOIMAGETOOL} ${BUILD_PLAT}/bl31.bin ${BUILD_PLAT}/bl31.img trusted-firmware-a-2.2/plat/arm/000077500000000000000000000000001355360272700166305ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/000077500000000000000000000000001355360272700177175ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/a5ds/000077500000000000000000000000001355360272700205535ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/a5ds/a5ds_bl1_setup.c000066400000000000000000000007531355360272700235360ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /******************************************************************************* * Perform any BL1 specific platform actions. ******************************************************************************/ void bl1_early_platform_setup(void) { arm_bl1_early_platform_setup(); } void bl1_platform_setup(void) { arm_bl1_platform_setup(); } trusted-firmware-a-2.2/plat/arm/board/a5ds/a5ds_bl2_setup.c000066400000000000000000000006461355360272700235400ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { arm_bl2_early_platform_setup((uintptr_t)arg0, (meminfo_t *)arg1); } void bl2_platform_setup(void) { arm_bl2_platform_setup(); } trusted-firmware-a-2.2/plat/arm/board/a5ds/a5ds_common.c000066400000000000000000000020501355360272700231200ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #define MAP_PERIPHBASE MAP_REGION_FLAT(PERIPHBASE,\ PERIPH_SIZE,\ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_A5_PERIPHERALS MAP_REGION_FLAT(A5_PERIPHERALS_BASE,\ A5_PERIPHERALS_SIZE,\ MT_DEVICE | MT_RW | MT_SECURE) #ifdef IMAGE_BL1 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, MAP_FLASH1_RW, MAP_PERIPHBASE, MAP_A5_PERIPHERALS, {0} }; #endif #ifdef IMAGE_BL2 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, MAP_FLASH1_RW, MAP_PERIPHBASE, MAP_A5_PERIPHERALS, ARM_MAP_NS_DRAM1, {0} }; #endif #ifdef IMAGE_BL32 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, MAP_PERIPHBASE, MAP_A5_PERIPHERALS, {0} }; #endif ARM_CASSERT_MMAP unsigned int plat_get_syscnt_freq2(void) { return A5DS_TIMER_BASE_FREQUENCY; } trusted-firmware-a-2.2/plat/arm/board/a5ds/a5ds_err.c000066400000000000000000000003731355360272700224260ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* * a5ds error handler */ void __dead2 plat_arm_error_handler(int err) { while (1) { wfi(); } } trusted-firmware-a-2.2/plat/arm/board/a5ds/a5ds_pm.c000066400000000000000000000051411355360272700222500ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /******************************************************************************* * Platform handler called when a power domain is about to be turned on. The * mpidr determines the CPU to be turned on. ******************************************************************************/ static int a5ds_pwr_domain_on(u_register_t mpidr) { unsigned int pos = plat_core_pos_by_mpidr(mpidr); uint64_t *hold_base = (uint64_t *)A5DS_HOLD_BASE; hold_base[pos] = A5DS_HOLD_STATE_GO; dsbish(); sev(); return PSCI_E_SUCCESS; } /******************************************************************************* * Platform handler called when a power domain has just been powered on after * being turned off earlier. The target_state encodes the low power state that * each level has woken up from. ******************************************************************************/ void a5ds_pwr_domain_on_finish(const psci_power_state_t *target_state) { /* TODO: This setup is needed only after a cold boot*/ gicv2_pcpu_distif_init(); /* Enable the gic cpu interface */ gicv2_cpuif_enable(); } /******************************************************************************* * Platform handler called when a power domain is about to be turned off. The * target_state encodes the power state that each level should transition to. * a5ds only has always-on power domain and there is no power control present. ******************************************************************************/ void a5ds_pwr_domain_off(const psci_power_state_t *target_state) { ERROR("CPU_OFF not supported on this platform\n"); assert(false); panic(); } /******************************************************************************* * Export the platform handlers via a5ds_psci_pm_ops. The ARM Standard * platform layer will take care of registering the handlers with PSCI. ******************************************************************************/ plat_psci_ops_t a5ds_psci_pm_ops = { /* dummy struct */ .validate_ns_entrypoint = NULL, .pwr_domain_on = a5ds_pwr_domain_on, .pwr_domain_on_finish = a5ds_pwr_domain_on_finish, .pwr_domain_off = a5ds_pwr_domain_off }; int __init plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { uintptr_t *mailbox = (void *)A5DS_TRUSTED_MAILBOX_BASE; *mailbox = sec_entrypoint; *psci_ops = &a5ds_psci_pm_ops; return 0; } trusted-firmware-a-2.2/plat/arm/board/a5ds/a5ds_private.h000066400000000000000000000006351355360272700233160ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef A5DS_PRIVATE_H #define A5DS_PRIVATE_H /******************************************************************************* * Function and variable prototypes ******************************************************************************/ void a5ds_config_setup(void); #endif /* A5DS_PRIVATE_H */ trusted-firmware-a-2.2/plat/arm/board/a5ds/a5ds_security.c000066400000000000000000000005201355360272700234770ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* * We assume that all security programming is done by the primary core. */ void plat_arm_security_setup(void) { /* * The platform currently does not have any security setup. */ } trusted-firmware-a-2.2/plat/arm/board/a5ds/a5ds_topology.c000066400000000000000000000027161355360272700235150ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* The A5DS power domain tree descriptor */ static const unsigned char a5ds_power_domain_tree_desc[] = { 1, /* No of children for the root node */ A5DS_CLUSTER_COUNT, /* No of children for the first cluster node */ A5DS_CORE_COUNT, }; /******************************************************************************* * This function returns the topology according to A5DS_CLUSTER_COUNT. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { return a5ds_power_domain_tree_desc; } /******************************************************************************* * Get core position using mpidr ******************************************************************************/ int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; mpidr &= MPIDR_AFFINITY_MASK; if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) return -1; cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; if (cluster_id >= A5DS_CLUSTER_COUNT) return -1; /* * Validate cpu_id by checking whether it represents a CPU in * one of the two clusters present on the platform. */ if (cpu_id >= A5DS_MAX_CPUS_PER_CLUSTER) return -1; return (cpu_id + (cluster_id * 4)); } trusted-firmware-a-2.2/plat/arm/board/a5ds/aarch32/000077500000000000000000000000001355360272700217765ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/a5ds/aarch32/a5ds_helpers.S000066400000000000000000000065471355360272700245140ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl plat_secondary_cold_boot_setup .globl plat_get_my_entrypoint .globl plat_is_my_cpu_primary /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions * needed for a secondary cpu after a cold reset e.g * mark the cpu's presence, mechanism to place it in a * holding pen etc. * ----------------------------------------------------- */ func plat_secondary_cold_boot_setup /* Calculate address of our hold entry */ bl plat_my_core_pos lsl r0, r0, #A5DS_HOLD_ENTRY_SHIFT mov_imm r2, A5DS_HOLD_BASE /* Clear the value stored in the hold address for the specific core */ mov_imm r3, A5DS_HOLD_STATE_WAIT str r3, [r2, r0] dmb ish /* Wait until we have a go */ poll_mailbox: ldr r1, [r2, r0] cmp r1, #A5DS_HOLD_STATE_WAIT beq 1f mov_imm r0, A5DS_TRUSTED_MAILBOX_BASE ldr r1, [r0] bx r1 1: wfe b poll_mailbox endfunc plat_secondary_cold_boot_setup /* --------------------------------------------------------------------- * unsigned long plat_get_my_entrypoint (void); * * Main job of this routine is to distinguish between a cold and warm * boot. * --------------------------------------------------------------------- */ func plat_get_my_entrypoint /* TODO support warm boot */ /* Cold reset */ mov r0, #0 bx lr endfunc plat_get_my_entrypoint /* ----------------------------------------------------- * unsigned int plat_is_my_cpu_primary (void); * * Find out whether the current cpu is the primary * cpu. * ----------------------------------------------------- */ func plat_is_my_cpu_primary ldcopr r0, MPIDR ldr r1, =MPIDR_AFFINITY_MASK and r0, r1 cmp r0, #0 moveq r0, #1 movne r0, #0 bx lr endfunc plat_is_my_cpu_primary /* --------------------------------------------------------------------- * Loads MPIDR in r0 and calls plat_arm_calc_core_pos * --------------------------------------------------------------------- */ func plat_my_core_pos ldcopr r0, MPIDR b plat_arm_calc_core_pos endfunc plat_my_core_pos /* --------------------------------------------------------------------- * unsigned int plat_arm_calc_core_pos(u_register_t mpidr) * * Function to calculate the core position on A5DS. * * (ClusterId * A5DS_MAX_CPUS_PER_CLUSTER * A5DS_MAX_PE_PER_CPU) + * (CPUId * A5DS_MAX_PE_PER_CPU) + * ThreadId * * which can be simplified as: * * ((ClusterId * A5DS_MAX_CPUS_PER_CLUSTER + CPUId) * A5DS_MAX_PE_PER_CPU) * + ThreadId * --------------------------------------------------------------------- */ func plat_arm_calc_core_pos mov r3, r0 /* * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it * look as if in a multi-threaded implementation */ tst r0, #MPIDR_MT_MASK lsleq r3, r0, #MPIDR_AFFINITY_BITS /* Extract individual affinity fields from MPIDR */ ubfx r0, r3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS ubfx r1, r3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS ubfx r2, r3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS /* Compute linear position */ mov r3, #A5DS_MAX_CPUS_PER_CLUSTER mla r1, r2, r3, r1 mov r3, #A5DS_MAX_PE_PER_CPU mla r0, r1, r3, r0 bx lr endfunc plat_arm_calc_core_pos trusted-firmware-a-2.2/plat/arm/board/a5ds/fdts/000077500000000000000000000000001355360272700215135ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/a5ds/fdts/a5ds_tb_fw_config.dts000066400000000000000000000005271355360272700255750ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { /* Platform Config */ plat_arm_bl2 { compatible = "arm,tb_fw"; hw_config_addr = <0x0 0x82000000>; hw_config_max_size = <0x01000000>; /* Disable authentication for development */ disable_auth = <0x0>; }; }; trusted-firmware-a-2.2/plat/arm/board/a5ds/include/000077500000000000000000000000001355360272700221765ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/a5ds/include/platform_def.h000066400000000000000000000244361355360272700250220ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include #include /* Memory location options for TSP */ #define ARM_DRAM_ID 2 #define ARM_DRAM1_BASE UL(0x80000000) #define ARM_DRAM1_SIZE UL(0x80000000) #define ARM_DRAM1_END (ARM_DRAM1_BASE + \ ARM_DRAM1_SIZE - 1) #define ARM_NS_DRAM1_BASE ARM_DRAM1_BASE /* * The last 2MB is meant to be NOLOAD and will not be zero * initialized. */ #define ARM_NS_DRAM1_SIZE (ARM_DRAM1_SIZE - \ 0x00200000) #define SRAM_BASE 0x2000000 #define SRAM_SIZE 0x200000 /* The first 4KB of NS DRAM1 are used as shared memory */ #define A5DS_SHARED_RAM_BASE SRAM_BASE #define A5DS_SHARED_RAM_SIZE UL(0x00001000) /* 4 KB */ /* The next 252 kB of NS DRAM is used to load the BL images */ #define ARM_BL_RAM_BASE (A5DS_SHARED_RAM_BASE + \ A5DS_SHARED_RAM_SIZE) #define ARM_BL_RAM_SIZE (PLAT_ARM_BL_PLUS_SHARED_RAM_SIZE - \ A5DS_SHARED_RAM_SIZE) #define PERIPHBASE 0x1a000000 #define PERIPH_SIZE 0x00240000 #define A5_PERIPHERALS_BASE 0x1c000000 #define A5_PERIPHERALS_SIZE 0x10000 #define ARM_CACHE_WRITEBACK_SHIFT 6 #define ARM_IRQ_SEC_PHY_TIMER 29 #define ARM_IRQ_SEC_SGI_0 8 #define ARM_IRQ_SEC_SGI_1 9 #define ARM_IRQ_SEC_SGI_2 10 #define ARM_IRQ_SEC_SGI_3 11 #define ARM_IRQ_SEC_SGI_4 12 #define ARM_IRQ_SEC_SGI_5 13 #define ARM_IRQ_SEC_SGI_6 14 #define ARM_IRQ_SEC_SGI_7 15 /* * Define a list of Group 1 Secure and Group 0 interrupt properties as per GICv3 * terminology. On a GICv2 system or mode, the lists will be merged and treated * as Group 0 interrupts. */ #define ARM_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE) #define ARM_G0_IRQ_PROPS(grp) \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE) #define A5DS_IRQ_TZ_WDOG 56 #define A5DS_IRQ_SEC_SYS_TIMER 57 /* Default cluster count for A5DS */ #define A5DS_CLUSTER_COUNT 1 /* Default number of CPUs per cluster on A5DS */ #define A5DS_MAX_CPUS_PER_CLUSTER 4 /* Default number of threads per CPU on A5DS */ #define A5DS_MAX_PE_PER_CPU 1 #define A5DS_CORE_COUNT 4 #define A5DS_PRIMARY_CPU 0x0 #define FLASH1_BASE UL(0x8000000) #define FLASH1_SIZE UL(0x2800000) #define MAP_FLASH1_RW MAP_REGION_FLAT(FLASH1_BASE,\ FLASH1_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_FLASH1_RO MAP_REGION_FLAT(FLASH1_BASE,\ FLASH1_SIZE, \ MT_RO_DATA | MT_SECURE) #define ARM_MAP_SHARED_RAM MAP_REGION_FLAT( \ A5DS_SHARED_RAM_BASE, \ A5DS_SHARED_RAM_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #define ARM_MAP_NS_DRAM1 MAP_REGION_FLAT( \ ARM_NS_DRAM1_BASE, \ ARM_NS_DRAM1_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define ARM_MAP_SRAM MAP_REGION_FLAT( \ SRAM_BASE, \ SRAM_SIZE, \ MT_MEMORY | MT_RW | MT_NS) /* * Mapping for the BL1 RW region. This mapping is needed by BL2 in order to * share the Mbed TLS heap. Since the heap is allocated inside BL1, it resides * in the BL1 RW region. Hence, BL2 needs access to the BL1 RW region in order * to be able to access the heap. */ #define ARM_MAP_BL_RO MAP_REGION_FLAT(\ BL_CODE_BASE,\ BL_CODE_END - BL_CODE_BASE,\ MT_CODE | MT_SECURE),\ MAP_REGION_FLAT(\ BL_RO_DATA_BASE,\ BL_RO_DATA_END\ - BL_RO_DATA_BASE, \ MT_RO_DATA | MT_SECURE) #if USE_COHERENT_MEM #define ARM_MAP_BL_COHERENT_RAM MAP_REGION_FLAT(\ BL_COHERENT_RAM_BASE,\ BL_COHERENT_RAM_END \ - BL_COHERENT_RAM_BASE, \ MT_DEVICE | MT_RW | MT_SECURE) #endif /* * The max number of regions like RO(code), coherent and data required by * different BL stages which need to be mapped in the MMU. */ #define ARM_BL_REGIONS 5 #define MAX_MMAP_REGIONS (PLAT_ARM_MMAP_ENTRIES + \ ARM_BL_REGIONS) /* Memory mapped Generic timer interfaces */ #define A5DS_TIMER_BASE_FREQUENCY UL(24000000) #define ARM_CONSOLE_BAUDRATE 115200 #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) /* * This macro defines the deepest retention state possible. A higher state * id will represent an invalid or a power down state. */ #define PLAT_MAX_RET_STATE 1 /* * This macro defines the deepest power down states possible. Any state ID * higher than this is invalid. */ #define PLAT_MAX_OFF_STATE 2 /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. */ #define CACHE_WRITEBACK_GRANULE (U(1) << ARM_CACHE_WRITEBACK_SHIFT) /* * To enable TB_FW_CONFIG to be loaded by BL1, define the corresponding base * and limit. Leave enough space of BL2 meminfo. */ #define ARM_TB_FW_CONFIG_BASE (ARM_BL_RAM_BASE + sizeof(meminfo_t)) #define ARM_TB_FW_CONFIG_LIMIT (ARM_BL_RAM_BASE + PAGE_SIZE) /******************************************************************************* * BL1 specific defines. * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of * addresses. ******************************************************************************/ #define BL1_RO_BASE 0x00000000 #define BL1_RO_LIMIT PLAT_ARM_TRUSTED_ROM_SIZE /* * Put BL1 RW at the top of the memory allocated for BL images in NS DRAM. */ #define BL1_RW_BASE (ARM_BL_RAM_BASE + \ ARM_BL_RAM_SIZE - \ (PLAT_ARM_MAX_BL1_RW_SIZE)) #define BL1_RW_LIMIT (ARM_BL_RAM_BASE + \ (ARM_BL_RAM_SIZE)) /******************************************************************************* * BL2 specific defines. ******************************************************************************/ /* * Put BL2 just below BL1. */ #define BL2_BASE (BL1_RW_BASE - A5DS_MAX_BL2_SIZE) #define BL2_LIMIT BL1_RW_BASE /* Put BL32 below BL2 in NS DRAM.*/ #define ARM_BL2_MEM_DESC_BASE ARM_TB_FW_CONFIG_LIMIT #define BL32_BASE ((ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)\ - PLAT_ARM_MAX_BL32_SIZE) #define BL32_PROGBITS_LIMIT BL2_BASE #define BL32_LIMIT (ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE) /* Required platform porting definitions */ #define PLATFORM_CORE_COUNT A5DS_CORE_COUNT #define PLAT_NUM_PWR_DOMAINS (A5DS_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) + 1 #define PLAT_MAX_PWR_LVL 2 /* * Other platform porting definitions are provided by included headers */ /* * Required ARM standard platform porting definitions */ #define PLAT_ARM_BL_PLUS_SHARED_RAM_SIZE 0x00040000 /* 256 KB */ #define PLAT_ARM_TRUSTED_ROM_BASE 0x00000000 #define PLAT_ARM_TRUSTED_ROM_SIZE 0x10000 /* 64KB */ #define PLAT_ARM_DRAM2_SIZE ULL(0x80000000) /* * Load address of BL33 for this platform port */ #define PLAT_ARM_NS_IMAGE_BASE (ARM_DRAM1_BASE + U(0x8000000)) /* * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the * plat_arm_mmap array defined for each BL stage. */ #if defined(IMAGE_BL32) # define PLAT_ARM_MMAP_ENTRIES 8 # define MAX_XLAT_TABLES 6 #else # define PLAT_ARM_MMAP_ENTRIES 12 # define MAX_XLAT_TABLES 6 #endif /* * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size * plus a little space for growth. */ #define PLAT_ARM_MAX_BL1_RW_SIZE 0xB000 /* * A5DS_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a * little space for growth. */ #define A5DS_MAX_BL2_SIZE 0x11000 /* * Since BL32 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL32_SIZE is * calculated using the current SP_MIN PROGBITS debug size plus the sizes of * BL2 and BL1-RW */ #define PLAT_ARM_MAX_BL32_SIZE 0x3B000 /* * Size of cacheable stacks */ #if defined(IMAGE_BL1) # define PLATFORM_STACK_SIZE 0x440 #elif defined(IMAGE_BL2) # define PLATFORM_STACK_SIZE 0x400 #elif defined(IMAGE_BL32) # define PLATFORM_STACK_SIZE 0x440 #endif #define MAX_IO_DEVICES 3 #define MAX_IO_HANDLES 4 /* Reserve the last block of flash for PSCI MEM PROTECT flag */ #define PLAT_ARM_FIP_BASE FLASH1_BASE #define PLAT_ARM_FIP_MAX_SIZE (FLASH1_SIZE - V2M_FLASH_BLOCK_SIZE) #define PLAT_ARM_NVM_BASE FLASH1_BASE #define PLAT_ARM_NVM_SIZE (FLASH1_SIZE - V2M_FLASH_BLOCK_SIZE) /* * PL011 related constants */ #define PLAT_ARM_BOOT_UART_BASE 0x1A200000 #define PLAT_ARM_BOOT_UART_CLK_IN_HZ 24000000 #define PLAT_ARM_RUN_UART_BASE 0x1A210000 #define PLAT_ARM_RUN_UART_CLK_IN_HZ 24000000 #define PLAT_ARM_CRASH_UART_BASE PLAT_ARM_RUN_UART_BASE #define PLAT_ARM_CRASH_UART_CLK_IN_HZ PLAT_ARM_RUN_UART_CLK_IN_HZ #define A5DS_TIMER_BASE_FREQUENCY UL(24000000) /* System timer related constants */ #define PLAT_ARM_NSTIMER_FRAME_ID 1 /* Mailbox base address */ #define A5DS_TRUSTED_MAILBOX_BASE A5DS_SHARED_RAM_BASE #define A5DS_TRUSTED_MAILBOX_SIZE (8 + A5DS_HOLD_SIZE) #define A5DS_HOLD_BASE (A5DS_TRUSTED_MAILBOX_BASE + 8) #define A5DS_HOLD_SIZE (PLATFORM_CORE_COUNT * \ A5DS_HOLD_ENTRY_SIZE) #define A5DS_HOLD_ENTRY_SHIFT 3 #define A5DS_HOLD_ENTRY_SIZE (1 << A5DS_HOLD_ENTRY_SHIFT) #define A5DS_HOLD_STATE_WAIT 0 #define A5DS_HOLD_STATE_GO 1 /* * GIC related constants to cater for GICv2 */ #define PLAT_ARM_GICD_BASE 0x1C001000 #define PLAT_ARM_GICC_BASE 0x1C000100 /* * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 * terminology. On a GICv2 system or mode, the lists will be merged and treated * as Group 0 interrupts. */ #define PLAT_ARM_G1S_IRQ_PROPS(grp) \ ARM_G1S_IRQ_PROPS(grp), \ INTR_PROP_DESC(A5DS_IRQ_TZ_WDOG, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(A5DS_IRQ_SEC_SYS_TIMER,\ GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_LEVEL) #define PLAT_ARM_G0_IRQ_PROPS(grp) ARM_G0_IRQ_PROPS(grp) #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/arm/board/a5ds/platform.mk000066400000000000000000000062101355360272700227270ustar00rootroot00000000000000# # Copyright (c) 2019, Arm Limited. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Add `libfdt` and Arm common helpers required for Dynamic Config include lib/libfdt/libfdt.mk DYN_CFG_SOURCES += plat/arm/common/arm_dyn_cfg.c \ plat/arm/common/arm_dyn_cfg_helpers.c \ common/fdt_wrappers.c A5DS_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c \ plat/arm/common/arm_gicv2.c A5DS_SECURITY_SOURCES := plat/arm/board/a5ds/a5ds_security.c PLAT_INCLUDES := -Iplat/arm/board/a5ds/include PLAT_BL_COMMON_SOURCES := drivers/arm/pl011/${ARCH}/pl011_console.S \ plat/arm/board/a5ds/a5ds_common.c \ plat/arm/common/${ARCH}/arm_helpers.S \ plat/arm/common/arm_common.c \ plat/arm/common/arm_console.c \ plat/arm/board/common/${ARCH}/board_arm_helpers.S A5DS_CPU_LIBS := lib/cpus/aarch32/cortex_a5.S BL1_SOURCES += drivers/io/io_fip.c \ drivers/io/io_memmap.c \ drivers/io/io_storage.c \ drivers/cfi/v2m/v2m_flash.c \ plat/arm/common/arm_bl1_setup.c \ plat/arm/common/arm_err.c \ plat/arm/board/a5ds/a5ds_err.c \ plat/arm/common/arm_io_storage.c \ plat/arm/board/a5ds/${ARCH}/a5ds_helpers.S \ plat/arm/board/a5ds/a5ds_bl1_setup.c \ lib/aarch32/arm32_aeabi_divmod.c \ lib/aarch32/arm32_aeabi_divmod_a32.S \ ${A5DS_CPU_LIBS} \ ${DYN_CFG_SOURCES} BL2_SOURCES += lib/aarch32/arm32_aeabi_divmod.c \ lib/aarch32/arm32_aeabi_divmod_a32.S \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/cfi/v2m/v2m_flash.c \ drivers/io/io_fip.c \ drivers/io/io_memmap.c \ drivers/io/io_storage.c \ plat/arm/board/a5ds/a5ds_bl2_setup.c \ plat/arm/common/arm_bl2_setup.c \ plat/arm/common/arm_err.c \ plat/arm/board/a5ds/a5ds_err.c \ plat/arm/common/arm_io_storage.c \ plat/arm/common/${ARCH}/arm_bl2_mem_params_desc.c \ plat/arm/common/arm_image_load.c \ common/desc_image_load.c \ ${DYN_CFG_SOURCES} \ ${A5DS_SECURITY_SOURCES} # Add the FDT_SOURCES and options for Dynamic Config (only for Unix env) ifdef UNIX_MK FVP_TB_FW_CONFIG := ${BUILD_PLAT}/fdts/a5ds_tb_fw_config.dtb # Add the TB_FW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${FVP_TB_FW_CONFIG},--tb-fw-config)) $(eval FVP_HW_CONFIG := ${BUILD_PLAT}/$(patsubst %.dts,%.dtb, \ fdts/$(notdir ${FVP_HW_CONFIG_DTS}))) # Add the HW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${FVP_HW_CONFIG},--hw-config)) FDT_SOURCES += plat/arm/board/a5ds/fdts/a5ds_tb_fw_config.dts \ ${FVP_HW_CONFIG_DTS} endif NEED_BL32 := yes MULTI_CONSOLE_API := 1 PLAT_BL_COMMON_SOURCES += lib/xlat_tables/aarch32/nonlpae_tables.c # Use translation tables library v1 when using Cortex-A5 ARM_XLAT_TABLES_LIB_V1 := 1 $(eval $(call assert_boolean,ARM_XLAT_TABLES_LIB_V1)) $(eval $(call add_define,ARM_XLAT_TABLES_LIB_V1)) $(eval $(call assert_boolean,ARM_DISABLE_TRUSTED_WDOG)) $(eval $(call add_define,ARM_DISABLE_TRUSTED_WDOG)) trusted-firmware-a-2.2/plat/arm/board/a5ds/sp_min/000077500000000000000000000000001355360272700220405ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c000066400000000000000000000007431355360272700256310ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { arm_sp_min_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3); } /* * A5DS will only have one always-on power domain and there * is no power control present. */ void plat_arm_pwrc_setup(void) { } trusted-firmware-a-2.2/plat/arm/board/a5ds/sp_min/sp_min-a5ds.mk000066400000000000000000000012771355360272700245170ustar00rootroot00000000000000# # Copyright (c) 2019, ARM Limited. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # SP_MIN source files specific to A5DS platform BL32_SOURCES += drivers/cfi/v2m/v2m_flash.c \ lib/utils/mem_region.c \ lib/aarch32/arm32_aeabi_divmod.c \ lib/aarch32/arm32_aeabi_divmod_a32.S \ plat/arm/board/a5ds/aarch32/a5ds_helpers.S \ plat/arm/board/a5ds/a5ds_pm.c \ plat/arm/board/a5ds/a5ds_topology.c \ plat/arm/board/a5ds/sp_min/a5ds_sp_min_setup.c \ plat/arm/common/sp_min/arm_sp_min_setup.c \ plat/common/aarch32/platform_mp_stack.S \ plat/common/plat_psci_common.c \ ${A5DS_CPU_LIBS} \ ${A5DS_GIC_SOURCES} \ ${A5DS_SECURITY_SOURCES} trusted-firmware-a-2.2/plat/arm/board/common/000077500000000000000000000000001355360272700212075ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/common/aarch32/000077500000000000000000000000001355360272700224325ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/common/aarch32/board_arm_helpers.S000066400000000000000000000015011355360272700262230ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl plat_report_exception /* ------------------------------------------------------- * void plat_report_exception(unsigned int type) * Function to report an unhandled exception * with platform-specific means. * On FVP platform, it updates the LEDs * to indicate where we are. * SYS_LED[0] - 0x0 * SYS_LED[2:1] - 0x0 * SYS_LED[7:3] - Exception Mode. * Clobbers: r0-r1 * ------------------------------------------------------- */ func plat_report_exception lsl r0, r0, #V2M_SYS_LED_EC_SHIFT ldr r1, =V2M_SYSREGS_BASE add r1, r1, #V2M_SYS_LED str r0, [r1] bx lr endfunc plat_report_exception trusted-firmware-a-2.2/plat/arm/board/common/aarch64/000077500000000000000000000000001355360272700224375ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/common/aarch64/board_arm_helpers.S000066400000000000000000000015421355360272700262350ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl plat_report_exception /* --------------------------------------------- * void plat_report_exception(unsigned int type) * Function to report an unhandled exception * with platform-specific means. * On FVP platform, it updates the LEDs * to indicate where we are * --------------------------------------------- */ func plat_report_exception mrs x1, CurrentEl lsr x1, x1, #MODE_EL_SHIFT lsl x1, x1, #V2M_SYS_LED_EL_SHIFT lsl x0, x0, #V2M_SYS_LED_EC_SHIFT mov x2, #(SECURE << V2M_SYS_LED_SS_SHIFT) orr x0, x0, x2 orr x0, x0, x1 mov x1, #V2M_SYSREGS_BASE add x1, x1, #V2M_SYS_LED str w0, [x1] ret endfunc plat_report_exception trusted-firmware-a-2.2/plat/arm/board/common/board_arm_trusted_boot.c000066400000000000000000000152431355360272700261030ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* SHA256 algorithm */ #define SHA256_BYTES 32 /* ROTPK locations */ #define ARM_ROTPK_REGS_ID 1 #define ARM_ROTPK_DEVEL_RSA_ID 2 #define ARM_ROTPK_DEVEL_ECDSA_ID 3 static const unsigned char rotpk_hash_hdr[] = \ "\x30\x31\x30\x0D\x06\x09\x60\x86\x48" \ "\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20"; static const unsigned int rotpk_hash_hdr_len = sizeof(rotpk_hash_hdr) - 1; static unsigned char rotpk_hash_der[sizeof(rotpk_hash_hdr) - 1 + SHA256_BYTES]; /* Use the cryptocell variants if Cryptocell is present */ #if !ARM_CRYPTOCELL_INTEG #if !ARM_ROTPK_LOCATION_ID #error "ARM_ROTPK_LOCATION_ID not defined" #endif /* Weak definition may be overridden in specific platform */ #pragma weak plat_get_nv_ctr #pragma weak plat_set_nv_ctr #if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID) static const unsigned char arm_devel_rotpk_hash[] = \ "\xB0\xF3\x82\x09\x12\x97\xD8\x3A" \ "\x37\x7A\x72\x47\x1B\xEC\x32\x73" \ "\xE9\x92\x32\xE2\x49\x59\xF6\x5E" \ "\x8B\x4A\x4A\x46\xD8\x22\x9A\xDA"; #elif (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_ECDSA_ID) static const unsigned char arm_devel_rotpk_hash[] = \ "\x2E\x40\xBF\x6E\xF9\x12\xBB\x98" \ "\x31\x71\x09\x0E\x1E\x15\x3D\x0B" \ "\xFD\xD1\xCC\x69\x4A\x98\xEB\x8B" \ "\xA0\xB0\x20\x86\x4E\x6C\x07\x17"; #endif /* * Return the ROTPK hash in the following ASN.1 structure in DER format: * * AlgorithmIdentifier ::= SEQUENCE { * algorithm OBJECT IDENTIFIER, * parameters ANY DEFINED BY algorithm OPTIONAL * } * * DigestInfo ::= SEQUENCE { * digestAlgorithm AlgorithmIdentifier, * digest OCTET STRING * } */ int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, unsigned int *flags) { uint8_t *dst; assert(key_ptr != NULL); assert(key_len != NULL); assert(flags != NULL); /* Copy the DER header */ memcpy(rotpk_hash_der, rotpk_hash_hdr, rotpk_hash_hdr_len); dst = (uint8_t *)&rotpk_hash_der[rotpk_hash_hdr_len]; #if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID) \ || (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_ECDSA_ID) memcpy(dst, arm_devel_rotpk_hash, SHA256_BYTES); #elif (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_REGS_ID) uint32_t *src, tmp; unsigned int words, i; /* * Append the hash from Trusted Root-Key Storage registers. The hash has * not been written linearly into the registers, so we have to do a bit * of byte swapping: * * 0x00 0x04 0x08 0x0C 0x10 0x14 0x18 0x1C * +---------------------------------------------------------------+ * | Reg0 | Reg1 | Reg2 | Reg3 | Reg4 | Reg5 | Reg6 | Reg7 | * +---------------------------------------------------------------+ * | ... ... | | ... ... | * | +--------------------+ | +-------+ * | | | | * +----------------------------+ +----------------------------+ * | | | | * +-------+ | +--------------------+ | * | | | | * v v v v * +---------------------------------------------------------------+ * | | | * +---------------------------------------------------------------+ * 0 15 16 31 * * Additionally, we have to access the registers in 32-bit words */ words = SHA256_BYTES >> 3; /* Swap bytes 0-15 (first four registers) */ src = (uint32_t *)TZ_PUB_KEY_HASH_BASE; for (i = 0 ; i < words ; i++) { tmp = src[words - 1 - i]; /* Words are read in little endian */ *dst++ = (uint8_t)((tmp >> 24) & 0xFF); *dst++ = (uint8_t)((tmp >> 16) & 0xFF); *dst++ = (uint8_t)((tmp >> 8) & 0xFF); *dst++ = (uint8_t)(tmp & 0xFF); } /* Swap bytes 16-31 (last four registers) */ src = (uint32_t *)(TZ_PUB_KEY_HASH_BASE + SHA256_BYTES / 2); for (i = 0 ; i < words ; i++) { tmp = src[words - 1 - i]; *dst++ = (uint8_t)((tmp >> 24) & 0xFF); *dst++ = (uint8_t)((tmp >> 16) & 0xFF); *dst++ = (uint8_t)((tmp >> 8) & 0xFF); *dst++ = (uint8_t)(tmp & 0xFF); } #endif /* (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID) \ || (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_ECDSA_ID) */ *key_ptr = (void *)rotpk_hash_der; *key_len = (unsigned int)sizeof(rotpk_hash_der); *flags = ROTPK_IS_HASH; return 0; } /* * Return the non-volatile counter value stored in the platform. The cookie * will contain the OID of the counter in the certificate. * * Return: 0 = success, Otherwise = error */ int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr) { const char *oid; uint32_t *nv_ctr_addr; assert(cookie != NULL); assert(nv_ctr != NULL); oid = (const char *)cookie; if (strcmp(oid, TRUSTED_FW_NVCOUNTER_OID) == 0) { nv_ctr_addr = (uint32_t *)TFW_NVCTR_BASE; } else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) { nv_ctr_addr = (uint32_t *)NTFW_CTR_BASE; } else { return 1; } *nv_ctr = (unsigned int)(*nv_ctr_addr); return 0; } /* * Store a new non-volatile counter value. By default on ARM development * platforms, the non-volatile counters are RO and cannot be modified. We expect * the values in the certificates to always match the RO values so that this * function is never called. * * Return: 0 = success, Otherwise = error */ int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr) { return 1; } #else /* ARM_CRYPTOCELL_INTEG */ #include /* * Return the ROTPK hash in the following ASN.1 structure in DER format: * * AlgorithmIdentifier ::= SEQUENCE { * algorithm OBJECT IDENTIFIER, * parameters ANY DEFINED BY algorithm OPTIONAL * } * * DigestInfo ::= SEQUENCE { * digestAlgorithm AlgorithmIdentifier, * digest OCTET STRING * } */ int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, unsigned int *flags) { unsigned char *dst; assert(key_ptr != NULL); assert(key_len != NULL); assert(flags != NULL); /* Copy the DER header */ memcpy(rotpk_hash_der, rotpk_hash_hdr, rotpk_hash_hdr_len); dst = &rotpk_hash_der[rotpk_hash_hdr_len]; *key_ptr = rotpk_hash_der; *key_len = sizeof(rotpk_hash_der); return cc_get_rotpk_hash(dst, SHA256_BYTES, flags); } #endif /* ARM_CRYPTOCELL_INTEG */ trusted-firmware-a-2.2/plat/arm/board/common/board_common.mk000066400000000000000000000026011355360272700241760ustar00rootroot00000000000000# # Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # PLAT_BL_COMMON_SOURCES += drivers/arm/pl011/${ARCH}/pl011_console.S \ plat/arm/board/common/${ARCH}/board_arm_helpers.S BL1_SOURCES += drivers/cfi/v2m/v2m_flash.c BL2_SOURCES += drivers/cfi/v2m/v2m_flash.c ifneq (${TRUSTED_BOARD_BOOT},0) ifneq (${ARM_CRYPTOCELL_INTEG}, 1) # ROTPK hash location ifeq (${ARM_ROTPK_LOCATION}, regs) ARM_ROTPK_LOCATION_ID = ARM_ROTPK_REGS_ID else ifeq (${ARM_ROTPK_LOCATION}, devel_rsa) KEY_ALG := rsa ARM_ROTPK_LOCATION_ID = ARM_ROTPK_DEVEL_RSA_ID else ifeq (${ARM_ROTPK_LOCATION}, devel_ecdsa) KEY_ALG := ecdsa ARM_ROTPK_LOCATION_ID = ARM_ROTPK_DEVEL_ECDSA_ID else $(error "Unsupported ARM_ROTPK_LOCATION value") endif $(eval $(call add_define,ARM_ROTPK_LOCATION_ID)) # Certificate NV-Counters. Use values corresponding to tied off values in # ARM development platforms TFW_NVCTR_VAL ?= 31 NTFW_NVCTR_VAL ?= 223 else # Certificate NV-Counters when CryptoCell is integrated. For development # platforms we set the counter to first valid value. TFW_NVCTR_VAL ?= 0 NTFW_NVCTR_VAL ?= 0 endif BL1_SOURCES += plat/arm/board/common/board_arm_trusted_boot.c BL2_SOURCES += plat/arm/board/common/board_arm_trusted_boot.c endif trusted-firmware-a-2.2/plat/arm/board/common/rotpk/000077500000000000000000000000001355360272700223465ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/common/rotpk/arm_rotpk_ecdsa.der000066400000000000000000000001331355360272700261740ustar00rootroot000000000000000Y0*†HÎ=*†HÎ=B›æH½48ᢤópáT»/°ZJ ÿ‡ÛÀûéùù•}~   ÔàbJ”_ìR}DcÈŸaúÆË~kS­,Å” †‘trusted-firmware-a-2.2/plat/arm/board/common/rotpk/arm_rotpk_ecdsa_sha256.bin000066400000000000000000000000401355360272700272570ustar00rootroot00000000000000.@¿nù»˜1q = ýÑÌiJ˜ë‹ ° †Nltrusted-firmware-a-2.2/plat/arm/board/common/rotpk/arm_rotpk_rsa.der000066400000000000000000000004461355360272700257110ustar00rootroot000000000000000‚"0  *†H†÷ ‚0‚ ‚Ë,`ÕcÔy~Ç–½M$N¬†æ·qãÅT ç½)Á?z¶ª«6ÄÙ6ilâeÛ±¿=¨V&Ëýº¬>T2Êy^»²êXòtºáô‡À fw„ƒ¡ïÿ(YçÃh}& CëVcó91Ø+Q©¼OÐöÞ•Ü_[Áíoì(‘~íxô`§ÄÇOPí]:!+pÅa{!e:Í‚VŒzG¬‰è¥HH1ÙFå…†˜ åÀ¦j½ä’Wa}ZMÊ®6¹Vòl¾ö;l€>¾£MÇÔ~§IÔòÒ¼Ï0¨çtdß¼\GhÌ@LøƒÌË@5`ʳ¤ŸÊZúѯ!WÓtrusted-firmware-a-2.2/plat/arm/board/common/rotpk/arm_rotpk_rsa_sha256.bin000066400000000000000000000000401355360272700267650ustar00rootroot00000000000000°ó‚ —Ø:7zrGì2sé’2âIYö^‹JJFØ"šÚtrusted-firmware-a-2.2/plat/arm/board/common/rotpk/arm_rotprivk_ecdsa.pem000066400000000000000000000003431355360272700267270ustar00rootroot00000000000000-----BEGIN EC PRIVATE KEY----- MHcCAQEEINSaX6nvzS3teiBJA7WlTLRKJOajpy29o2cArLbUXoZBoAoGCCqGSM49 AwEHoUQDQgAEm+ZIvTQ44aKk83DhVLsvsFpKDP/Ch9vA+4Hp+fmVfX6gDH8K1OBi SpRf7FJ9RGPIn2H6xst+a1OtLMWUDRqGkQ== -----END EC PRIVATE KEY----- trusted-firmware-a-2.2/plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem000066400000000000000000000032501355360272700264350ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDLLGDVjWPUB3l+ xxaWvU0kTqyG5rdx48VUC+cUHL0pGsE/erYCqqs2xNk2aWziZcObsb89qFYmy/0E AbqsPlQyynleu7IF6gZY8nS64fSHwBkKH2YHd4SDoRzv/yhZ58NofSYgQ+tWY/M5 MdgrUam8T9D23pXcX1vB7ZBv7CiRfhfteJD0YKfEx09Q7V0TOiErcMVhewghZTrN glaMekesieilSEgx2R1G5YWGmKDlwKZqvQfkkldhB499Wk3Krja5VgQQ8my+9jts gD6+DqNNx9R+p0nU8tK8zzCo53SPZN+8XEdozEBM+IPMy0A1BGDKs6QXnwPKHVr6 0a8hVxDTAgMBAAECggEAfwsc8ewbhDW4TwIGqfNtDUr0rtYN13VpqohW0ki2L8G/ HQaKUViO/wxQFqoNn/OqQO0AfHmKhXAAokTCiXngBHJ/OjF7vB7+IRhazZEE6u2/ uoivr/OYNQbFpXyTqsQ1eFzpPju6KKcPK7BzT4Mc89ek/vloFAi8w6LdMl8lbvOg LBWqX+5A+UQoenPUTvYM4U22YNcEAWubkpsYAmViiWiac+a+uPRk39aKyfOedDNu +ty9MtCwekivoUTfP/1+O+jFlDnPMJUOEkBmcBqxseYYAHu7blBpdHxYpAItC2pv YwJJSvsE+HLBLPk177Jahg7sOUqcP0F/X+T65yuvIQKBgQDxdjXdJT5K8j7rG2fv 2bvF2H1GPaHaTYRk0EGI2Ql6Nn+ddfeCE6gaT7aPPgg87wAhNu93coFuYHw0p/sc ZkXMJ+BmlstPV555cWXmwcxZLsni0fOXrt4YxwWkZwmh74m0NVM/cSFw56PU0oj1 yDNeq3fgmsJocmuNTe1eG9qA7QKBgQDXaAGrNA5Xel5mqqMYTHHQWI6l2uzdNtt7 eDn3K9+Eh3ywTqrwP845MAjKDU2Lq61I6t2H89dEifHq823VIcLCHd9BF04MrAH7 qDPzrmPP2iB9g+YFmGBKe+K0HFE1t1KrTlo9VV6ZAC6RJNLAgwD4kvfIVYNkCGwe +hoZBdhgvwKBgBrOsPQ4ak4PzwRzKnrqhXpVqrLdrNZ7vLMkm+IBlpfG7SwiKLR8 UjF5oB8PGAML1cvaOYPdZplGhQOjkrF4eU9NLhC1tSS96Y46FMIlyfYsx6UzAgRZ GbdOgUXbWqpr2bH0KaXlfXz3eqzqIuKGs41TJB//jo3iBibN/AhytzORAoGAeGov 5KDpE4XYl9Pz8HVremjG9Xh4yQENmOwQm1fvT4rd7UFM1ZkVk2qCv1DIdLe32vdQ d9ucDzh+ADWsxGRnF1TTpPN+Mh9FzISu5h4qtdreJsxBHgecbIbsqHrb+wdMM29N itPaWfV8Eq9fETcqp8qgsWD8XkNHDdoKFMrrtskCgYAoSt/Je1D3ZE/3HEjez7bq fenS3J6KG2SEn2PNFn+R0R5vBo4DaV/cQysKh44GD2+sh0QDyh6nuWJufyhPzROP DU6DCLbwNePj/yaGuzi36oLt6bBgfPWCiJY7jIdK8DmTLW25m7fRtCC5pxZlSzgl KBf7R6cbaTvaFe05Y2FJXA== -----END PRIVATE KEY----- trusted-firmware-a-2.2/plat/arm/board/corstone700/000077500000000000000000000000001355360272700220025ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/corstone700/corstone700_helpers.S000066400000000000000000000056471355360272700257470ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl plat_secondary_cold_boot_setup .globl plat_get_my_entrypoint .globl plat_is_my_cpu_primary .globl plat_arm_calc_core_pos /* -------------------------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * For AArch32, cold-booting secondary CPUs is not yet * implemented and they panic. * -------------------------------------------------------------------- */ func plat_secondary_cold_boot_setup cb_panic: b cb_panic endfunc plat_secondary_cold_boot_setup /* --------------------------------------------------------------------- * unsigned long plat_get_my_entrypoint (void); * * Main job of this routine is to distinguish between a cold and warm * boot. On Corstone700, this information can be queried from the power * controller. The Power Control SYS Status Register (PSYSR) indicates * the wake-up reason for the CPU. * * For a cold boot, return 0. * For a warm boot, Not yet supported. * * TODO: PSYSR is a common register and should be * accessed using locks. Since it is not possible * to use locks immediately after a cold reset * we are relying on the fact that after a cold * reset all cpus will read the same WK field * --------------------------------------------------------------------- */ func plat_get_my_entrypoint /* TODO support warm boot */ /* Cold reset */ mov r0, #0 bx lr endfunc plat_get_my_entrypoint /* ----------------------------------------------------- * unsigned int plat_is_my_cpu_primary (void); * * Find out whether the current CPU is the primary * CPU. * ----------------------------------------------------- */ func plat_is_my_cpu_primary ldcopr r0, MPIDR ldr r1, =MPIDR_AFFINITY_MASK and r0, r1 cmp r0, #0 moveq r0, #1 movne r0, #0 bx lr endfunc plat_is_my_cpu_primary /* --------------------------------------------------------------------- * unsigned int plat_arm_calc_core_pos(u_register_t mpidr) * * Function to calculate the core position on Corstone700. * * (ClusterId * MAX_CPUS_PER_CLUSTER * MAX_PE_PER_CPU) + * (CPUId * MAX_PE_PER_CPU) + * ThreadId * * which can be simplified as: * * ((ClusterId * MAX_CPUS_PER_CLUSTER + CPUId) * MAX_PE_PER_CPU) * + ThreadId * --------------------------------------------------------------------- */ func plat_arm_calc_core_pos mov r3, r0 /* Extract individual affinity fields from MPIDR */ ubfx r0, r3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS ubfx r1, r3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS ubfx r2, r3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS /* Compute linear position */ mov r3, #CORSTONE700_MAX_CPUS_PER_CLUSTER mla r1, r2, r3, r1 mov r3, #CORSTONE700_MAX_PE_PER_CPU mla r0, r1, r3, r0 bx lr endfunc plat_arm_calc_core_pos trusted-firmware-a-2.2/plat/arm/board/corstone700/corstone700_plat.c000066400000000000000000000012701355360272700252510ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /* * Table of regions to map using the MMU. * Replace or extend the below regions as required */ const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, ARM_MAP_NS_DRAM1, CORSTONE700_MAP_DEVICE, {0} }; /* Corstone700 only has one always-on power domain and there * is no power control present */ void __init plat_arm_pwrc_setup(void) { } unsigned int plat_get_syscnt_freq2(void) { return CORSTONE700_TIMER_BASE_FREQUENCY; } trusted-firmware-a-2.2/plat/arm/board/corstone700/corstone700_pm.c000066400000000000000000000012621355360272700247260ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /******************************************************************************* * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard * platform layer will take care of registering the handlers with PSCI. ******************************************************************************/ plat_psci_ops_t plat_arm_psci_pm_ops = { /* dummy struct */ .validate_ns_entrypoint = NULL }; const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops) { return ops; } trusted-firmware-a-2.2/plat/arm/board/corstone700/corstone700_security.c000066400000000000000000000005611355360272700261620ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * We assume that all security programming is done by the primary core. */ void plat_arm_security_setup(void) { /* * If the platform had additional peripheral specific security * configurations, those would be configured here. */ } trusted-firmware-a-2.2/plat/arm/board/corstone700/corstone700_topology.c000066400000000000000000000030631355360272700261670ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /* The Corstone700 power domain tree descriptor */ static unsigned char corstone700_power_domain_tree_desc [PLAT_ARM_CLUSTER_COUNT + 2]; /******************************************************************************* * This function dynamically constructs the topology according to * CLUSTER_COUNT and returns it. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { int i; /* * The highest level is the system level. The next level is constituted * by clusters and then cores in clusters. */ corstone700_power_domain_tree_desc[0] = 1; corstone700_power_domain_tree_desc[1] = PLAT_ARM_CLUSTER_COUNT; for (i = 0; i < PLAT_ARM_CLUSTER_COUNT; i++) corstone700_power_domain_tree_desc[i + 2] = PLATFORM_CORE_COUNT; return corstone700_power_domain_tree_desc; } /****************************************************************************** * This function implements a part of the critical interface between the PSCI * generic layer and the platform that allows the former to query the platform * to convert an MPIDR to a unique linear index. An error code (-1) is * returned in case the MPIDR is invalid. *****************************************************************************/ int plat_core_pos_by_mpidr(u_register_t mpidr) { return plat_arm_calc_core_pos(mpidr); } trusted-firmware-a-2.2/plat/arm/board/corstone700/include/000077500000000000000000000000001355360272700234255ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/corstone700/include/platform_def.h000066400000000000000000000170201355360272700262400ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include #include /* Core/Cluster/Thread counts for Corstone700 */ #define CORSTONE700_CLUSTER_COUNT 1 #define CORSTONE700_MAX_CPUS_PER_CLUSTER 4 #define CORSTONE700_MAX_PE_PER_CPU 1 #define CORSTONE700_CORE_COUNT (CORSTONE700_CLUSTER_COUNT * \ CORSTONE700_MAX_CPUS_PER_CLUSTER * \ CORSTONE700_MAX_PE_PER_CPU) #define PLATFORM_CORE_COUNT CORSTONE700_CORE_COUNT #define PLAT_ARM_CLUSTER_COUNT CORSTONE700_CLUSTER_COUNT /* UART related constants */ #define PLAT_ARM_BOOT_UART_BASE 0x1a510000 #define PLAT_ARM_BOOT_UART_CLK_IN_HZ V2M_IOFPGA_UART0_CLK_IN_HZ #define PLAT_ARM_RUN_UART_BASE 0x1a520000 #define PLAT_ARM_RUN_UART_CLK_IN_HZ V2M_IOFPGA_UART1_CLK_IN_HZ #define ARM_CONSOLE_BAUDRATE 115200 #define PLAT_ARM_CRASH_UART_BASE PLAT_ARM_RUN_UART_BASE #define PLAT_ARM_CRASH_UART_CLK_IN_HZ PLAT_ARM_RUN_UART_CLK_IN_HZ /* Memory related constants */ #define ARM_DRAM1_BASE UL(0x80000000) #define ARM_DRAM1_SIZE UL(0x80000000) #define ARM_DRAM1_END (ARM_DRAM1_BASE + \ ARM_DRAM1_SIZE - 1) #define ARM_NS_DRAM1_BASE ARM_DRAM1_BASE #define ARM_NS_DRAM1_SIZE ARM_DRAM1_SIZE #define ARM_NS_DRAM1_END (ARM_NS_DRAM1_BASE + \ ARM_NS_DRAM1_SIZE - 1) #define ARM_TRUSTED_SRAM_BASE UL(0x02000000) #define ARM_SHARED_RAM_BASE ARM_TRUSTED_SRAM_BASE #define ARM_SHARED_RAM_SIZE UL(0x00001000) /* 4 KB */ #define PLAT_ARM_TRUSTED_SRAM_SIZE 0x00040000 /* 256 KB */ /* The remaining Trusted SRAM is used to load the BL images */ #define ARM_BL_RAM_BASE (ARM_SHARED_RAM_BASE + \ ARM_SHARED_RAM_SIZE) #define ARM_BL_RAM_SIZE (PLAT_ARM_TRUSTED_SRAM_SIZE - \ ARM_SHARED_RAM_SIZE) /* * SP_MIN is the only BL image in SRAM. Allocate the whole of SRAM (excluding * the page reserved for fw_configs) to BL32 */ #define BL32_BASE (ARM_BL_RAM_BASE + PAGE_SIZE) #define BL32_LIMIT (ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE) /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. */ #define CACHE_WRITEBACK_GRANULE (U(1) << ARM_CACHE_WRITEBACK_SHIFT) #define ARM_CACHE_WRITEBACK_SHIFT 6 /* * To enable TB_FW_CONFIG to be loaded by BL1, define the corresponding base * and limit. Leave enough space for BL2 meminfo. */ #define ARM_TB_FW_CONFIG_BASE (ARM_BL_RAM_BASE + sizeof(meminfo_t)) #define ARM_TB_FW_CONFIG_LIMIT (ARM_BL_RAM_BASE + (PAGE_SIZE / 2U)) /* * The max number of regions like RO(code), coherent and data required by * different BL stages which need to be mapped in the MMU. */ #define ARM_BL_REGIONS 2 #define PLAT_ARM_MMAP_ENTRIES 8 #define MAX_XLAT_TABLES 5 #define MAX_MMAP_REGIONS (PLAT_ARM_MMAP_ENTRIES + \ ARM_BL_REGIONS) /* GIC related constants */ #define PLAT_ARM_GICD_BASE 0x1C010000 #define PLAT_ARM_GICC_BASE 0x1C02F000 /* Timer/watchdog related constants */ #define ARM_SYS_CNTCTL_BASE UL(0x1a200000) #define ARM_SYS_CNTREAD_BASE UL(0x1a210000) #define ARM_SYS_TIMCTL_BASE UL(0x1a220000) #define CORSTONE700_TIMER_BASE_FREQUENCY UL(24000000) #define CORSTONE700_IRQ_TZ_WDOG 32 #define CORSTONE700_IRQ_SEC_SYS_TIMER 34 #define PLAT_MAX_PWR_LVL 2 /* * Macros mapping the MPIDR Affinity levels to ARM Platform Power levels. The * power levels have a 1:1 mapping with the MPIDR affinity levels. */ #define ARM_PWR_LVL0 MPIDR_AFFLVL0 #define ARM_PWR_LVL1 MPIDR_AFFLVL1 #define ARM_PWR_LVL2 MPIDR_AFFLVL2 /* * Macros for local power states in ARM platforms encoded by State-ID field * within the power-state parameter. */ /* Local power state for power domains in Run state. */ #define ARM_LOCAL_STATE_RUN U(0) /* Local power state for retention. Valid only for CPU power domains */ #define ARM_LOCAL_STATE_RET U(1) /* Local power state for OFF/power-down. Valid for CPU and cluster * power domains */ #define ARM_LOCAL_STATE_OFF U(2) #define PLAT_ARM_TRUSTED_MAILBOX_BASE ARM_TRUSTED_SRAM_BASE #define PLAT_ARM_NSTIMER_FRAME_ID U(1) #define PLAT_ARM_NS_IMAGE_OFFSET (ARM_DRAM1_BASE + UL(0x8000000)) #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) /* * This macro defines the deepest retention state possible. A higher state * ID will represent an invalid or a power down state. */ #define PLAT_MAX_RET_STATE 1 /* * This macro defines the deepest power down states possible. Any state ID * higher than this is invalid. */ #define PLAT_MAX_OFF_STATE 2 #define PLATFORM_STACK_SIZE UL(0x440) #define ARM_MAP_SHARED_RAM MAP_REGION_FLAT( \ ARM_SHARED_RAM_BASE, \ ARM_SHARED_RAM_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define ARM_MAP_NS_DRAM1 MAP_REGION_FLAT( \ ARM_NS_DRAM1_BASE, \ ARM_NS_DRAM1_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define ARM_MAP_BL_RO MAP_REGION_FLAT( \ BL_CODE_BASE, \ BL_CODE_END \ - BL_CODE_BASE, \ MT_CODE | MT_SECURE), \ MAP_REGION_FLAT( \ BL_RO_DATA_BASE, \ BL_RO_DATA_END \ - BL_RO_DATA_BASE, \ MT_RO_DATA | MT_SECURE) #if USE_COHERENT_MEM #define ARM_MAP_BL_COHERENT_RAM MAP_REGION_FLAT( \ BL_COHERENT_RAM_BASE, \ BL_COHERENT_RAM_END \ - BL_COHERENT_RAM_BASE, \ MT_DEVICE | MT_RW | MT_SECURE) #endif #define CORSTONE700_DEVICE_BASE (0x1A000000) #define CORSTONE700_DEVICE_SIZE (0x26000000) #define CORSTONE700_MAP_DEVICE MAP_REGION_FLAT( \ CORSTONE700_DEVICE_BASE, \ CORSTONE700_DEVICE_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define ARM_IRQ_SEC_PHY_TIMER 29 #define ARM_IRQ_SEC_SGI_0 8 #define ARM_IRQ_SEC_SGI_1 9 #define ARM_IRQ_SEC_SGI_2 10 #define ARM_IRQ_SEC_SGI_3 11 #define ARM_IRQ_SEC_SGI_4 12 #define ARM_IRQ_SEC_SGI_5 13 #define ARM_IRQ_SEC_SGI_6 14 #define ARM_IRQ_SEC_SGI_7 15 /* * Define a list of Group 1 Secure and Group 0 interrupt properties as per GICv3 * terminology. On a GICv2 system or mode, the lists will be merged and treated * as Group 0 interrupts. */ #define ARM_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, \ (grp), GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, \ (grp), GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, \ (grp), GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, \ (grp), GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, \ (grp), GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, \ (grp), GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, \ (grp), GIC_INTR_CFG_EDGE) #define ARM_G0_IRQ_PROPS(grp) \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE) /* * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 * terminology. On a GICv2 system or mode, the lists will be merged and treated * as Group 0 interrupts. */ #define PLAT_ARM_G1S_IRQ_PROPS(grp) \ ARM_G1S_IRQ_PROPS(grp), \ INTR_PROP_DESC(CORSTONE700_IRQ_TZ_WDOG, \ GIC_HIGHEST_SEC_PRIORITY, (grp), GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(CORSTONE700_IRQ_SEC_SYS_TIMER, \ GIC_HIGHEST_SEC_PRIORITY, (grp), GIC_INTR_CFG_LEVEL) \ #define PLAT_ARM_G0_IRQ_PROPS(grp) ARM_G0_IRQ_PROPS(grp) #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/arm/board/corstone700/platform.mk000066400000000000000000000032111355360272700241540ustar00rootroot00000000000000# # Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # CORSTONE700_CPU_LIBS += lib/cpus/aarch32/cortex_a32.S BL32_SOURCES += plat/arm/common/aarch32/arm_helpers.S \ plat/arm/common/arm_console.c \ plat/arm/common/arm_common.c \ lib/xlat_tables/aarch32/xlat_tables.c \ lib/xlat_tables/xlat_tables_common.c \ ${CORSTONE700_CPU_LIBS} PLAT_INCLUDES := -Iplat/arm/board/corstone700/include NEED_BL32 := yes CORSTONE700_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c \ plat/arm/common/arm_gicv2.c # BL1/BL2 Image not a part of the capsule Image for Corstone700 override NEED_BL1 := no override NEED_BL2 := no override NEED_BL2U := no #TFA for Corstone700 starts from BL32 override RESET_TO_SP_MIN := 1 #Device tree CORSTONE700_HW_CONFIG_DTS := fdts/corstone700.dts CORSTONE700_HW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}.dtb FDT_SOURCES += ${CORSTONE700_HW_CONFIG_DTS} $(eval CORSTONE700_HW_CONFIG := ${BUILD_PLAT}/$(patsubst %.dts,%.dtb,$(CORSTONE700_HW_CONFIG_DTS))) # Add the HW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${CORSTONE700_HW_CONFIG},--hw-config)) # Check for Linux kernel as a BL33 image by default $(eval $(call add_define,ARM_LINUX_KERNEL_AS_BL33)) ifndef ARM_PRELOADED_DTB_BASE $(error "ARM_PRELOADED_DTB_BASE must be set if ARM_LINUX_KERNEL_AS_BL33 is used.") endif $(eval $(call add_define,ARM_PRELOADED_DTB_BASE)) include plat/arm/board/common/board_common.mk trusted-firmware-a-2.2/plat/arm/board/corstone700/sp_min/000077500000000000000000000000001355360272700232675ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/corstone700/sp_min/corstone700_sp_min_setup.c000066400000000000000000000005541355360272700303070ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { arm_sp_min_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3); } trusted-firmware-a-2.2/plat/arm/board/corstone700/sp_min/sp_min-corstone700.mk000066400000000000000000000012201355360272700271610ustar00rootroot00000000000000# # Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # SP_MIN source files specific to FVP platform BL32_SOURCES += drivers/cfi/v2m/v2m_flash.c \ lib/utils/mem_region.c \ plat/arm/board/corstone700/corstone700_helpers.S \ plat/arm/board/corstone700/corstone700_topology.c \ plat/arm/board/corstone700/corstone700_security.c \ plat/arm/board/corstone700/corstone700_plat.c \ plat/arm/board/corstone700/corstone700_pm.c \ plat/arm/board/corstone700/sp_min/corstone700_sp_min_setup.c \ ${CORSTONE700_GIC_SOURCES} include plat/arm/common/sp_min/arm_sp_min.mk trusted-firmware-a-2.2/plat/arm/board/fvp/000077500000000000000000000000001355360272700205125ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/fvp/aarch32/000077500000000000000000000000001355360272700217355ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/fvp/aarch32/fvp_helpers.S000066400000000000000000000105101355360272700243730ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl plat_secondary_cold_boot_setup .globl plat_get_my_entrypoint .globl plat_is_my_cpu_primary .globl plat_arm_calc_core_pos /* -------------------------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * For AArch32, cold-booting secondary CPUs is not yet * implemented and they panic. * -------------------------------------------------------------------- */ func plat_secondary_cold_boot_setup cb_panic: b cb_panic endfunc plat_secondary_cold_boot_setup /* --------------------------------------------------------------------- * unsigned long plat_get_my_entrypoint (void); * * Main job of this routine is to distinguish between a cold and warm * boot. On FVP, this information can be queried from the power * controller. The Power Control SYS Status Register (PSYSR) indicates * the wake-up reason for the CPU. * * For a cold boot, return 0. * For a warm boot, read the mailbox and return the address it contains. * * TODO: PSYSR is a common register and should be * accessed using locks. Since it is not possible * to use locks immediately after a cold reset * we are relying on the fact that after a cold * reset all cpus will read the same WK field * --------------------------------------------------------------------- */ func plat_get_my_entrypoint /* --------------------------------------------------------------------- * When bit PSYSR.WK indicates either "Wake by PPONR" or "Wake by GIC * WakeRequest signal" then it is a warm boot. * --------------------------------------------------------------------- */ ldcopr r2, MPIDR ldr r1, =PWRC_BASE str r2, [r1, #PSYSR_OFF] ldr r2, [r1, #PSYSR_OFF] ubfx r2, r2, #PSYSR_WK_SHIFT, #PSYSR_WK_WIDTH cmp r2, #WKUP_PPONR beq warm_reset cmp r2, #WKUP_GICREQ beq warm_reset /* Cold reset */ mov r0, #0 bx lr warm_reset: /* --------------------------------------------------------------------- * A mailbox is maintained in the trusted SRAM. It is flushed out of the * caches after every update using normal memory so it is safe to read * it here with SO attributes. * --------------------------------------------------------------------- */ ldr r0, =PLAT_ARM_TRUSTED_MAILBOX_BASE ldr r0, [r0] cmp r0, #0 beq _panic bx lr /* --------------------------------------------------------------------- * The power controller indicates this is a warm reset but the mailbox * is empty. This should never happen! * --------------------------------------------------------------------- */ _panic: b _panic endfunc plat_get_my_entrypoint /* ----------------------------------------------------- * unsigned int plat_is_my_cpu_primary (void); * * Find out whether the current cpu is the primary * cpu. * ----------------------------------------------------- */ func plat_is_my_cpu_primary ldcopr r0, MPIDR ldr r1, =MPIDR_AFFINITY_MASK and r0, r1 cmp r0, #FVP_PRIMARY_CPU moveq r0, #1 movne r0, #0 bx lr endfunc plat_is_my_cpu_primary /* --------------------------------------------------------------------- * unsigned int plat_arm_calc_core_pos(u_register_t mpidr) * * Function to calculate the core position on FVP. * * (ClusterId * FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU) + * (CPUId * FVP_MAX_PE_PER_CPU) + * ThreadId * * which can be simplified as: * * ((ClusterId * FVP_MAX_CPUS_PER_CLUSTER + CPUId) * FVP_MAX_PE_PER_CPU) * + ThreadId * --------------------------------------------------------------------- */ func plat_arm_calc_core_pos mov r3, r0 /* * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it * look as if in a multi-threaded implementation */ tst r0, #MPIDR_MT_MASK lsleq r3, r0, #MPIDR_AFFINITY_BITS /* Extract individual affinity fields from MPIDR */ ubfx r0, r3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS ubfx r1, r3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS ubfx r2, r3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS /* Compute linear position */ mov r3, #FVP_MAX_CPUS_PER_CLUSTER mla r1, r2, r3, r1 mov r3, #FVP_MAX_PE_PER_CPU mla r0, r1, r3, r0 bx lr endfunc plat_arm_calc_core_pos trusted-firmware-a-2.2/plat/arm/board/fvp/aarch64/000077500000000000000000000000001355360272700217425ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/fvp/aarch64/fvp_helpers.S000066400000000000000000000126411355360272700244070ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include .globl plat_secondary_cold_boot_setup .globl plat_get_my_entrypoint .globl plat_is_my_cpu_primary .globl plat_arm_calc_core_pos /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions * needed for a secondary cpu after a cold reset e.g * mark the cpu's presence, mechanism to place it in a * holding pen etc. * TODO: Should we read the PSYS register to make sure * that the request has gone through. * ----------------------------------------------------- */ func plat_secondary_cold_boot_setup #ifndef EL3_PAYLOAD_BASE /* --------------------------------------------- * Power down this cpu. * TODO: Do we need to worry about powering the * cluster down as well here. That will need * locks which we won't have unless an elf- * loader zeroes out the zi section. * --------------------------------------------- */ mrs x0, mpidr_el1 mov_imm x1, PWRC_BASE str w0, [x1, #PPOFFR_OFF] /* --------------------------------------------- * There is no sane reason to come out of this * wfi so panic if we do. This cpu will be pow- * ered on and reset by the cpu_on pm api * --------------------------------------------- */ dsb sy wfi no_ret plat_panic_handler #else mov_imm x0, PLAT_ARM_TRUSTED_MAILBOX_BASE /* Wait until the entrypoint gets populated */ poll_mailbox: ldr x1, [x0] cbz x1, 1f br x1 1: wfe b poll_mailbox #endif /* EL3_PAYLOAD_BASE */ endfunc plat_secondary_cold_boot_setup /* --------------------------------------------------------------------- * uintptr_t plat_get_my_entrypoint (void); * * Main job of this routine is to distinguish between a cold and warm * boot. On FVP, this information can be queried from the power * controller. The Power Control SYS Status Register (PSYSR) indicates * the wake-up reason for the CPU. * * For a cold boot, return 0. * For a warm boot, read the mailbox and return the address it contains. * * TODO: PSYSR is a common register and should be * accessed using locks. Since it is not possible * to use locks immediately after a cold reset * we are relying on the fact that after a cold * reset all cpus will read the same WK field * --------------------------------------------------------------------- */ func plat_get_my_entrypoint /* --------------------------------------------------------------------- * When bit PSYSR.WK indicates either "Wake by PPONR" or "Wake by GIC * WakeRequest signal" then it is a warm boot. * --------------------------------------------------------------------- */ mrs x2, mpidr_el1 mov_imm x1, PWRC_BASE str w2, [x1, #PSYSR_OFF] ldr w2, [x1, #PSYSR_OFF] ubfx w2, w2, #PSYSR_WK_SHIFT, #PSYSR_WK_WIDTH cmp w2, #WKUP_PPONR beq warm_reset cmp w2, #WKUP_GICREQ beq warm_reset /* Cold reset */ mov x0, #0 ret warm_reset: /* --------------------------------------------------------------------- * A mailbox is maintained in the trusted SRAM. It is flushed out of the * caches after every update using normal memory so it is safe to read * it here with SO attributes. * --------------------------------------------------------------------- */ mov_imm x0, PLAT_ARM_TRUSTED_MAILBOX_BASE ldr x0, [x0] cbz x0, _panic_handler ret /* --------------------------------------------------------------------- * The power controller indicates this is a warm reset but the mailbox * is empty. This should never happen! * --------------------------------------------------------------------- */ _panic_handler: no_ret plat_panic_handler endfunc plat_get_my_entrypoint /* ----------------------------------------------------- * unsigned int plat_is_my_cpu_primary (void); * * Find out whether the current cpu is the primary * cpu. * ----------------------------------------------------- */ func plat_is_my_cpu_primary mrs x0, mpidr_el1 mov_imm x1, MPIDR_AFFINITY_MASK and x0, x0, x1 cmp x0, #FVP_PRIMARY_CPU cset w0, eq ret endfunc plat_is_my_cpu_primary /* --------------------------------------------------------------------- * unsigned int plat_arm_calc_core_pos(u_register_t mpidr) * * Function to calculate the core position on FVP. * * (ClusterId * FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU) + * (CPUId * FVP_MAX_PE_PER_CPU) + * ThreadId * * which can be simplified as: * * ((ClusterId * FVP_MAX_CPUS_PER_CLUSTER + CPUId) * FVP_MAX_PE_PER_CPU) * + ThreadId * --------------------------------------------------------------------- */ func plat_arm_calc_core_pos /* * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it * look as if in a multi-threaded implementation. */ tst x0, #MPIDR_MT_MASK lsl x3, x0, #MPIDR_AFFINITY_BITS csel x3, x3, x0, eq /* Extract individual affinity fields from MPIDR */ ubfx x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS ubfx x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS ubfx x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS /* Compute linear position */ mov x4, #FVP_MAX_CPUS_PER_CLUSTER madd x1, x2, x4, x1 mov x5, #FVP_MAX_PE_PER_CPU madd x0, x1, x5, x0 ret endfunc plat_arm_calc_core_pos trusted-firmware-a-2.2/plat/arm/board/fvp/aarch64/fvp_ras.c000066400000000000000000000005321355360272700235460ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include struct ras_interrupt fvp_ras_interrupts[] = { }; struct err_record_info fvp_err_records[] = { }; REGISTER_ERR_RECORD_INFO(fvp_err_records); REGISTER_RAS_INTERRUPTS(fvp_ras_interrupts); trusted-firmware-a-2.2/plat/arm/board/fvp/fdts/000077500000000000000000000000001355360272700214525ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/fvp/fdts/fvp_nt_fw_config.dts000066400000000000000000000002211355360272700254760ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { }; trusted-firmware-a-2.2/plat/arm/board/fvp/fdts/fvp_soc_fw_config.dts000066400000000000000000000002211355360272700256410ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { }; trusted-firmware-a-2.2/plat/arm/board/fvp/fdts/fvp_tb_fw_config.dts000066400000000000000000000023721355360272700254730ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { /* Platform Config */ plat_arm_bl2 { compatible = "arm,tb_fw"; hw_config_addr = <0x0 0x82000000>; hw_config_max_size = <0x01000000>; /* Disable authentication for development */ disable_auth = <0x0>; /* * Load SoC and TOS firmware configs at the base of * non shared SRAM. The runtime checks ensure we don't * overlap BL2, BL31 or BL32. The NT firmware config * is loaded at base of DRAM. */ soc_fw_config_addr = <0x0 0x04001000>; soc_fw_config_max_size = <0x200>; tos_fw_config_addr = <0x0 0x04001200>; tos_fw_config_max_size = <0x200>; nt_fw_config_addr = <0x0 0x80000000>; nt_fw_config_max_size = <0x200>; /* * The following two entries are placeholders for Mbed TLS * heap information. The default values don't matter since * they will be overwritten by BL1. * In case of having shared Mbed TLS heap between BL1 and BL2, * BL1 will populate these two properties with the respective * info about the shared heap. This info will be available for * BL2 in order to locate and re-use the heap. */ mbedtls_heap_addr = <0x0 0x0>; mbedtls_heap_size = <0x0>; }; }; trusted-firmware-a-2.2/plat/arm/board/fvp/fdts/fvp_tsp_fw_config.dts000066400000000000000000000002211355360272700256630ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { }; trusted-firmware-a-2.2/plat/arm/board/fvp/fvp_bl1_setup.c000066400000000000000000000032211355360272700234250ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "fvp_private.h" /******************************************************************************* * Perform any BL1 specific platform actions. ******************************************************************************/ void bl1_early_platform_setup(void) { arm_bl1_early_platform_setup(); /* Initialize the platform config for future decision making */ fvp_config_setup(); /* * Initialize Interconnect for this cluster during cold boot. * No need for locks as no other CPU is active. */ fvp_interconnect_init(); /* * Enable coherency in Interconnect for the primary CPU's cluster. */ fvp_interconnect_enable(); } void plat_arm_secure_wdt_start(void) { sp805_start(ARM_SP805_TWDG_BASE, ARM_TWDG_LOAD_VAL); } void plat_arm_secure_wdt_stop(void) { sp805_stop(ARM_SP805_TWDG_BASE); } void bl1_platform_setup(void) { arm_bl1_platform_setup(); /* Initialize System level generic or SP804 timer */ fvp_timer_init(); /* On FVP RevC, initialize SMMUv3 */ if ((arm_config.flags & ARM_CONFIG_FVP_HAS_SMMUV3) != 0U) smmuv3_security_init(PLAT_FVP_SMMUV3_BASE); } __dead2 void bl1_plat_fwu_done(void *client_cookie, void *reserved) { /* Setup the watchdog to reset the system as soon as possible */ sp805_refresh(ARM_SP805_TWDG_BASE, 1U); while (1) wfi(); } trusted-firmware-a-2.2/plat/arm/board/fvp/fvp_bl2_el3_setup.c000066400000000000000000000013401355360272700241710ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "fvp_private.h" void bl2_el3_early_platform_setup(u_register_t arg0 __unused, u_register_t arg1 __unused, u_register_t arg2 __unused, u_register_t arg3 __unused) { arm_bl2_el3_early_platform_setup(); /* Initialize the platform config for future decision making */ fvp_config_setup(); /* * Initialize Interconnect for this cluster during cold boot. * No need for locks as no other CPU is active. */ fvp_interconnect_init(); /* * Enable coherency in Interconnect for the primary CPU's cluster. */ fvp_interconnect_enable(); } trusted-firmware-a-2.2/plat/arm/board/fvp/fvp_bl2_setup.c000066400000000000000000000013731355360272700234340ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "fvp_private.h" void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { arm_bl2_early_platform_setup((uintptr_t)arg0, (meminfo_t *)arg1); /* Initialize the platform config for future decision making */ fvp_config_setup(); } void bl2_platform_setup(void) { arm_bl2_platform_setup(); /* Initialize System level generic or SP804 timer */ fvp_timer_init(); } trusted-firmware-a-2.2/plat/arm/board/fvp/fvp_bl2u_setup.c000066400000000000000000000010501355360272700236110ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "fvp_private.h" void bl2u_early_platform_setup(struct meminfo *mem_layout, void *plat_info) { arm_bl2u_early_platform_setup(mem_layout, plat_info); /* Initialize System level generic or SP804 timer */ fvp_timer_init(); /* Initialize the platform config for future decision making */ fvp_config_setup(); } trusted-firmware-a-2.2/plat/arm/board/fvp/fvp_bl31_setup.c000066400000000000000000000024161355360272700235150ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "fvp_private.h" void __init bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3); /* Initialize the platform config for future decision making */ fvp_config_setup(); /* * Initialize the correct interconnect for this cluster during cold * boot. No need for locks as no other CPU is active. */ fvp_interconnect_init(); /* * Enable coherency in interconnect for the primary CPU's cluster. * Earlier bootloader stages might already do this (e.g. Trusted * Firmware's BL1 does it) but we can't assume so. There is no harm in * executing this code twice anyway. * FVP PSCI code will enable coherency for other clusters. */ fvp_interconnect_enable(); /* Initialize System level generic or SP804 timer */ fvp_timer_init(); /* On FVP RevC, initialize SMMUv3 */ if ((arm_config.flags & ARM_CONFIG_FVP_HAS_SMMUV3) != 0U) smmuv3_init(PLAT_FVP_SMMUV3_BASE); } trusted-firmware-a-2.2/plat/arm/board/fvp/fvp_common.c000066400000000000000000000261101355360272700230210ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fvp_private.h" /* Defines for GIC Driver build time selection */ #define FVP_GICV2 1 #define FVP_GICV3 2 /******************************************************************************* * arm_config holds the characteristics of the differences between the three FVP * platforms (Base, A53_A57 & Foundation). It will be populated during cold boot * at each boot stage by the primary before enabling the MMU (to allow * interconnect configuration) & used thereafter. Each BL will have its own copy * to allow independent operation. ******************************************************************************/ arm_config_t arm_config; #define MAP_DEVICE0 MAP_REGION_FLAT(DEVICE0_BASE, \ DEVICE0_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_DEVICE1 MAP_REGION_FLAT(DEVICE1_BASE, \ DEVICE1_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) /* * Need to be mapped with write permissions in order to set a new non-volatile * counter value. */ #define MAP_DEVICE2 MAP_REGION_FLAT(DEVICE2_BASE, \ DEVICE2_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) /* * Table of memory regions for various BL stages to map using the MMU. * This doesn't include Trusted SRAM as setup_page_tables() already takes care * of mapping it. * * The flash needs to be mapped as writable in order to erase the FIP's Table of * Contents in case of unrecoverable error (see plat_error_handler()). */ #ifdef IMAGE_BL1 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, V2M_MAP_FLASH0_RW, V2M_MAP_IOFPGA, MAP_DEVICE0, MAP_DEVICE1, #if TRUSTED_BOARD_BOOT /* To access the Root of Trust Public Key registers. */ MAP_DEVICE2, /* Map DRAM to authenticate NS_BL2U image. */ ARM_MAP_NS_DRAM1, #endif {0} }; #endif #ifdef IMAGE_BL2 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, V2M_MAP_FLASH0_RW, V2M_MAP_IOFPGA, MAP_DEVICE0, MAP_DEVICE1, ARM_MAP_NS_DRAM1, #ifdef __aarch64__ ARM_MAP_DRAM2, #endif #ifdef SPD_tspd ARM_MAP_TSP_SEC_MEM, #endif #if TRUSTED_BOARD_BOOT /* To access the Root of Trust Public Key registers. */ MAP_DEVICE2, #if !BL2_AT_EL3 ARM_MAP_BL1_RW, #endif #endif /* TRUSTED_BOARD_BOOT */ #if ENABLE_SPM && SPM_MM ARM_SP_IMAGE_MMAP, #endif #if ENABLE_SPM && !SPM_MM PLAT_MAP_SP_PACKAGE_MEM_RW, #endif #if ARM_BL31_IN_DRAM ARM_MAP_BL31_SEC_DRAM, #endif #ifdef SPD_opteed ARM_MAP_OPTEE_CORE_MEM, ARM_OPTEE_PAGEABLE_LOAD_MEM, #endif {0} }; #endif #ifdef IMAGE_BL2U const mmap_region_t plat_arm_mmap[] = { MAP_DEVICE0, V2M_MAP_IOFPGA, {0} }; #endif #ifdef IMAGE_BL31 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, ARM_MAP_EL3_TZC_DRAM, V2M_MAP_IOFPGA, MAP_DEVICE0, MAP_DEVICE1, ARM_V2M_MAP_MEM_PROTECT, #if ENABLE_SPM && SPM_MM ARM_SPM_BUF_EL3_MMAP, #endif #if ENABLE_SPM && !SPM_MM PLAT_MAP_SP_PACKAGE_MEM_RO, #endif {0} }; #if ENABLE_SPM && defined(IMAGE_BL31) && SPM_MM const mmap_region_t plat_arm_secure_partition_mmap[] = { V2M_MAP_IOFPGA_EL0, /* for the UART */ MAP_REGION_FLAT(DEVICE0_BASE, \ DEVICE0_SIZE, \ MT_DEVICE | MT_RO | MT_SECURE | MT_USER), ARM_SP_IMAGE_MMAP, ARM_SP_IMAGE_NS_BUF_MMAP, ARM_SP_IMAGE_RW_MMAP, ARM_SPM_BUF_EL0_MMAP, {0} }; #endif #endif #ifdef IMAGE_BL32 const mmap_region_t plat_arm_mmap[] = { #ifndef __aarch64__ ARM_MAP_SHARED_RAM, ARM_V2M_MAP_MEM_PROTECT, #endif V2M_MAP_IOFPGA, MAP_DEVICE0, MAP_DEVICE1, {0} }; #endif ARM_CASSERT_MMAP #if FVP_INTERCONNECT_DRIVER != FVP_CCN static const int fvp_cci400_map[] = { PLAT_FVP_CCI400_CLUS0_SL_PORT, PLAT_FVP_CCI400_CLUS1_SL_PORT, }; static const int fvp_cci5xx_map[] = { PLAT_FVP_CCI5XX_CLUS0_SL_PORT, PLAT_FVP_CCI5XX_CLUS1_SL_PORT, }; static unsigned int get_interconnect_master(void) { unsigned int master; u_register_t mpidr; mpidr = read_mpidr_el1(); master = ((arm_config.flags & ARM_CONFIG_FVP_SHIFTED_AFF) != 0U) ? MPIDR_AFFLVL2_VAL(mpidr) : MPIDR_AFFLVL1_VAL(mpidr); assert(master < FVP_CLUSTER_COUNT); return master; } #endif #if ENABLE_SPM && defined(IMAGE_BL31) && SPM_MM /* * Boot information passed to a secure partition during initialisation. Linear * indices in MP information will be filled at runtime. */ static secure_partition_mp_info_t sp_mp_info[] = { [0] = {0x80000000, 0}, [1] = {0x80000001, 0}, [2] = {0x80000002, 0}, [3] = {0x80000003, 0}, [4] = {0x80000100, 0}, [5] = {0x80000101, 0}, [6] = {0x80000102, 0}, [7] = {0x80000103, 0}, }; const secure_partition_boot_info_t plat_arm_secure_partition_boot_info = { .h.type = PARAM_SP_IMAGE_BOOT_INFO, .h.version = VERSION_1, .h.size = sizeof(secure_partition_boot_info_t), .h.attr = 0, .sp_mem_base = ARM_SP_IMAGE_BASE, .sp_mem_limit = ARM_SP_IMAGE_LIMIT, .sp_image_base = ARM_SP_IMAGE_BASE, .sp_stack_base = PLAT_SP_IMAGE_STACK_BASE, .sp_heap_base = ARM_SP_IMAGE_HEAP_BASE, .sp_ns_comm_buf_base = PLAT_SP_IMAGE_NS_BUF_BASE, .sp_shared_buf_base = PLAT_SPM_BUF_BASE, .sp_image_size = ARM_SP_IMAGE_SIZE, .sp_pcpu_stack_size = PLAT_SP_IMAGE_STACK_PCPU_SIZE, .sp_heap_size = ARM_SP_IMAGE_HEAP_SIZE, .sp_ns_comm_buf_size = PLAT_SP_IMAGE_NS_BUF_SIZE, .sp_shared_buf_size = PLAT_SPM_BUF_SIZE, .num_sp_mem_regions = ARM_SP_IMAGE_NUM_MEM_REGIONS, .num_cpus = PLATFORM_CORE_COUNT, .mp_info = &sp_mp_info[0], }; const struct mmap_region *plat_get_secure_partition_mmap(void *cookie) { return plat_arm_secure_partition_mmap; } const struct secure_partition_boot_info *plat_get_secure_partition_boot_info( void *cookie) { return &plat_arm_secure_partition_boot_info; } #endif /******************************************************************************* * A single boot loader stack is expected to work on both the Foundation FVP * models and the two flavours of the Base FVP models (AEMv8 & Cortex). The * SYS_ID register provides a mechanism for detecting the differences between * these platforms. This information is stored in a per-BL array to allow the * code to take the correct path.Per BL platform configuration. ******************************************************************************/ void __init fvp_config_setup(void) { unsigned int rev, hbi, bld, arch, sys_id; sys_id = mmio_read_32(V2M_SYSREGS_BASE + V2M_SYS_ID); rev = (sys_id >> V2M_SYS_ID_REV_SHIFT) & V2M_SYS_ID_REV_MASK; hbi = (sys_id >> V2M_SYS_ID_HBI_SHIFT) & V2M_SYS_ID_HBI_MASK; bld = (sys_id >> V2M_SYS_ID_BLD_SHIFT) & V2M_SYS_ID_BLD_MASK; arch = (sys_id >> V2M_SYS_ID_ARCH_SHIFT) & V2M_SYS_ID_ARCH_MASK; if (arch != ARCH_MODEL) { ERROR("This firmware is for FVP models\n"); panic(); } /* * The build field in the SYS_ID tells which variant of the GIC * memory is implemented by the model. */ switch (bld) { case BLD_GIC_VE_MMAP: ERROR("Legacy Versatile Express memory map for GIC peripheral" " is not supported\n"); panic(); break; case BLD_GIC_A53A57_MMAP: break; default: ERROR("Unsupported board build %x\n", bld); panic(); } /* * The hbi field in the SYS_ID is 0x020 for the Base FVP & 0x010 * for the Foundation FVP. */ switch (hbi) { case HBI_FOUNDATION_FVP: arm_config.flags = 0; /* * Check for supported revisions of Foundation FVP * Allow future revisions to run but emit warning diagnostic */ switch (rev) { case REV_FOUNDATION_FVP_V2_0: case REV_FOUNDATION_FVP_V2_1: case REV_FOUNDATION_FVP_v9_1: case REV_FOUNDATION_FVP_v9_6: break; default: WARN("Unrecognized Foundation FVP revision %x\n", rev); break; } break; case HBI_BASE_FVP: arm_config.flags |= (ARM_CONFIG_BASE_MMAP | ARM_CONFIG_HAS_TZC); /* * Check for supported revisions * Allow future revisions to run but emit warning diagnostic */ switch (rev) { case REV_BASE_FVP_V0: arm_config.flags |= ARM_CONFIG_FVP_HAS_CCI400; break; case REV_BASE_FVP_REVC: arm_config.flags |= (ARM_CONFIG_FVP_HAS_SMMUV3 | ARM_CONFIG_FVP_HAS_CCI5XX); break; default: WARN("Unrecognized Base FVP revision %x\n", rev); break; } break; default: ERROR("Unsupported board HBI number 0x%x\n", hbi); panic(); } /* * We assume that the presence of MT bit, and therefore shifted * affinities, is uniform across the platform: either all CPUs, or no * CPUs implement it. */ if ((read_mpidr_el1() & MPIDR_MT_MASK) != 0U) arm_config.flags |= ARM_CONFIG_FVP_SHIFTED_AFF; } void __init fvp_interconnect_init(void) { #if FVP_INTERCONNECT_DRIVER == FVP_CCN if (ccn_get_part0_id(PLAT_ARM_CCN_BASE) != CCN_502_PART0_ID) { ERROR("Unrecognized CCN variant detected. Only CCN-502 is supported"); panic(); } plat_arm_interconnect_init(); #else uintptr_t cci_base = 0U; const int *cci_map = NULL; unsigned int map_size = 0U; /* Initialize the right interconnect */ if ((arm_config.flags & ARM_CONFIG_FVP_HAS_CCI5XX) != 0U) { cci_base = PLAT_FVP_CCI5XX_BASE; cci_map = fvp_cci5xx_map; map_size = ARRAY_SIZE(fvp_cci5xx_map); } else if ((arm_config.flags & ARM_CONFIG_FVP_HAS_CCI400) != 0U) { cci_base = PLAT_FVP_CCI400_BASE; cci_map = fvp_cci400_map; map_size = ARRAY_SIZE(fvp_cci400_map); } else { return; } assert(cci_base != 0U); assert(cci_map != NULL); cci_init(cci_base, cci_map, map_size); #endif } void fvp_interconnect_enable(void) { #if FVP_INTERCONNECT_DRIVER == FVP_CCN plat_arm_interconnect_enter_coherency(); #else unsigned int master; if ((arm_config.flags & (ARM_CONFIG_FVP_HAS_CCI400 | ARM_CONFIG_FVP_HAS_CCI5XX)) != 0U) { master = get_interconnect_master(); cci_enable_snoop_dvm_reqs(master); } #endif } void fvp_interconnect_disable(void) { #if FVP_INTERCONNECT_DRIVER == FVP_CCN plat_arm_interconnect_exit_coherency(); #else unsigned int master; if ((arm_config.flags & (ARM_CONFIG_FVP_HAS_CCI400 | ARM_CONFIG_FVP_HAS_CCI5XX)) != 0U) { master = get_interconnect_master(); cci_disable_snoop_dvm_reqs(master); } #endif } #if TRUSTED_BOARD_BOOT int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size) { assert(heap_addr != NULL); assert(heap_size != NULL); return arm_get_mbedtls_heap(heap_addr, heap_size); } #endif void fvp_timer_init(void) { #if FVP_USE_SP804_TIMER /* Enable the clock override for SP804 timer 0, which means that no * clock dividers are applied and the raw (35MHz) clock will be used. */ mmio_write_32(V2M_SP810_BASE, FVP_SP810_CTRL_TIM0_OV); /* Initialize delay timer driver using SP804 dual timer 0 */ sp804_timer_init(V2M_SP804_TIMER0_BASE, SP804_TIMER_CLKMULT, SP804_TIMER_CLKDIV); #else generic_delay_timer_init(); /* Enable System level generic timer */ mmio_write_32(ARM_SYS_CNTCTL_BASE + CNTCR_OFF, CNTCR_FCREQ(0U) | CNTCR_EN); #endif /* FVP_USE_SP804_TIMER */ } trusted-firmware-a-2.2/plat/arm/board/fvp/fvp_def.h000066400000000000000000000114461355360272700223020ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef FVP_DEF_H #define FVP_DEF_H #include #ifndef FVP_CLUSTER_COUNT #define FVP_CLUSTER_COUNT 2 #endif #ifndef FVP_MAX_CPUS_PER_CLUSTER #define FVP_MAX_CPUS_PER_CLUSTER 4 #endif #ifndef FVP_MAX_PE_PER_CPU # define FVP_MAX_PE_PER_CPU 1 #endif #define FVP_PRIMARY_CPU 0x0 /* Defines for the Interconnect build selection */ #define FVP_CCI 1 #define FVP_CCN 2 /******************************************************************************* * FVP memory map related constants ******************************************************************************/ #define FLASH1_BASE UL(0x0c000000) #define FLASH1_SIZE UL(0x04000000) #define PSRAM_BASE UL(0x14000000) #define PSRAM_SIZE UL(0x04000000) #define VRAM_BASE UL(0x18000000) #define VRAM_SIZE UL(0x02000000) /* Aggregate of all devices in the first GB */ #define DEVICE0_BASE UL(0x20000000) #define DEVICE0_SIZE UL(0x0c200000) /* * In case of FVP models with CCN, the CCN register space overlaps into * the NSRAM area. */ #if FVP_INTERCONNECT_DRIVER == FVP_CCN #define DEVICE1_BASE UL(0x2e000000) #define DEVICE1_SIZE UL(0x1A00000) #else #define DEVICE1_BASE UL(0x2f000000) #define DEVICE1_SIZE UL(0x200000) #define NSRAM_BASE UL(0x2e000000) #define NSRAM_SIZE UL(0x10000) #endif /* Devices in the second GB */ #define DEVICE2_BASE UL(0x7fe00000) #define DEVICE2_SIZE UL(0x00200000) #define PCIE_EXP_BASE UL(0x40000000) #define TZRNG_BASE UL(0x7fe60000) /* Non-volatile counters */ #define TRUSTED_NVCTR_BASE UL(0x7fe70000) #define TFW_NVCTR_BASE (TRUSTED_NVCTR_BASE + UL(0x0000)) #define TFW_NVCTR_SIZE UL(4) #define NTFW_CTR_BASE (TRUSTED_NVCTR_BASE + UL(0x0004)) #define NTFW_CTR_SIZE UL(4) /* Keys */ #define SOC_KEYS_BASE UL(0x7fe80000) #define TZ_PUB_KEY_HASH_BASE (SOC_KEYS_BASE + UL(0x0000)) #define TZ_PUB_KEY_HASH_SIZE UL(32) #define HU_KEY_BASE (SOC_KEYS_BASE + UL(0x0020)) #define HU_KEY_SIZE UL(16) #define END_KEY_BASE (SOC_KEYS_BASE + UL(0x0044)) #define END_KEY_SIZE UL(32) /* Constants to distinguish FVP type */ #define HBI_BASE_FVP U(0x020) #define REV_BASE_FVP_V0 U(0x0) #define REV_BASE_FVP_REVC U(0x2) #define HBI_FOUNDATION_FVP U(0x010) #define REV_FOUNDATION_FVP_V2_0 U(0x0) #define REV_FOUNDATION_FVP_V2_1 U(0x1) #define REV_FOUNDATION_FVP_v9_1 U(0x2) #define REV_FOUNDATION_FVP_v9_6 U(0x3) #define BLD_GIC_VE_MMAP U(0x0) #define BLD_GIC_A53A57_MMAP U(0x1) #define ARCH_MODEL U(0x1) /* FVP Power controller base address*/ #define PWRC_BASE UL(0x1c100000) /* FVP SP804 timer frequency is 35 MHz*/ #define SP804_TIMER_CLKMULT 1 #define SP804_TIMER_CLKDIV 35 /* SP810 controller. FVP specific flags */ #define FVP_SP810_CTRL_TIM0_OV BIT_32(16) #define FVP_SP810_CTRL_TIM1_OV BIT_32(18) #define FVP_SP810_CTRL_TIM2_OV BIT_32(20) #define FVP_SP810_CTRL_TIM3_OV BIT_32(22) /******************************************************************************* * GIC-400 & interrupt handling related constants ******************************************************************************/ /* VE compatible GIC memory map */ #define VE_GICD_BASE UL(0x2c001000) #define VE_GICC_BASE UL(0x2c002000) #define VE_GICH_BASE UL(0x2c004000) #define VE_GICV_BASE UL(0x2c006000) /* Base FVP compatible GIC memory map */ #define BASE_GICD_BASE UL(0x2f000000) #define BASE_GICR_BASE UL(0x2f100000) #define BASE_GICC_BASE UL(0x2c000000) #define BASE_GICH_BASE UL(0x2c010000) #define BASE_GICV_BASE UL(0x2c02f000) #define FVP_IRQ_TZ_WDOG 56 #define FVP_IRQ_SEC_SYS_TIMER 57 /******************************************************************************* * TrustZone address space controller related constants ******************************************************************************/ /* NSAIDs used by devices in TZC filter 0 on FVP */ #define FVP_NSAID_DEFAULT 0 #define FVP_NSAID_PCI 1 #define FVP_NSAID_VIRTIO 8 /* from FVP v5.6 onwards */ #define FVP_NSAID_AP 9 /* Application Processors */ #define FVP_NSAID_VIRTIO_OLD 15 /* until FVP v5.5 */ /* NSAIDs used by devices in TZC filter 2 on FVP */ #define FVP_NSAID_HDLCD0 2 #define FVP_NSAID_CLCD 7 /******************************************************************************* * Memprotect definitions ******************************************************************************/ /* PSCI memory protect definitions: * This variable is stored in a non-secure flash because some ARM reference * platforms do not have secure NVRAM. Real systems that provided MEM_PROTECT * support must use a secure NVRAM to store the PSCI MEM_PROTECT definitions. */ #define PLAT_ARM_MEM_PROT_ADDR (V2M_FLASH0_BASE + \ V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE) #endif /* FVP_DEF_H */ trusted-firmware-a-2.2/plat/arm/board/fvp/fvp_err.c000066400000000000000000000016461355360272700223300ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* * FVP error handler */ __dead2 void plat_arm_error_handler(int err) { int ret; switch (err) { case -ENOENT: case -EAUTH: /* Image load or authentication error. Erase the ToC */ INFO("Erasing FIP ToC from flash...\n"); (void)nor_unlock(PLAT_ARM_FIP_BASE); ret = nor_word_program(PLAT_ARM_FIP_BASE, 0); if (ret != 0) { ERROR("Cannot erase ToC\n"); } else { INFO("Done\n"); } break; default: /* Unexpected error */ break; } (void)console_flush(); /* Setup the watchdog to reset the system as soon as possible */ sp805_refresh(ARM_SP805_TWDG_BASE, 1U); for (;;) wfi(); } trusted-firmware-a-2.2/plat/arm/board/fvp/fvp_io_storage.c000066400000000000000000000072041355360272700236670ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include /* Semihosting filenames */ #define BL2_IMAGE_NAME "bl2.bin" #define BL31_IMAGE_NAME "bl31.bin" #define BL32_IMAGE_NAME "bl32.bin" #define BL33_IMAGE_NAME "bl33.bin" #define TB_FW_CONFIG_NAME "fvp_tb_fw_config.dtb" #define HW_CONFIG_NAME "hw_config.dtb" #if TRUSTED_BOARD_BOOT #define TRUSTED_BOOT_FW_CERT_NAME "tb_fw.crt" #define TRUSTED_KEY_CERT_NAME "trusted_key.crt" #define SOC_FW_KEY_CERT_NAME "soc_fw_key.crt" #define TOS_FW_KEY_CERT_NAME "tos_fw_key.crt" #define NT_FW_KEY_CERT_NAME "nt_fw_key.crt" #define SOC_FW_CONTENT_CERT_NAME "soc_fw_content.crt" #define TOS_FW_CONTENT_CERT_NAME "tos_fw_content.crt" #define NT_FW_CONTENT_CERT_NAME "nt_fw_content.crt" #endif /* TRUSTED_BOARD_BOOT */ /* IO devices */ static const io_dev_connector_t *sh_dev_con; static uintptr_t sh_dev_handle; static const io_file_spec_t sh_file_spec[] = { [BL2_IMAGE_ID] = { .path = BL2_IMAGE_NAME, .mode = FOPEN_MODE_RB }, [BL31_IMAGE_ID] = { .path = BL31_IMAGE_NAME, .mode = FOPEN_MODE_RB }, [BL32_IMAGE_ID] = { .path = BL32_IMAGE_NAME, .mode = FOPEN_MODE_RB }, [BL33_IMAGE_ID] = { .path = BL33_IMAGE_NAME, .mode = FOPEN_MODE_RB }, [TB_FW_CONFIG_ID] = { .path = TB_FW_CONFIG_NAME, .mode = FOPEN_MODE_RB }, [HW_CONFIG_ID] = { .path = HW_CONFIG_NAME, .mode = FOPEN_MODE_RB }, #if TRUSTED_BOARD_BOOT [TRUSTED_BOOT_FW_CERT_ID] = { .path = TRUSTED_BOOT_FW_CERT_NAME, .mode = FOPEN_MODE_RB }, [TRUSTED_KEY_CERT_ID] = { .path = TRUSTED_KEY_CERT_NAME, .mode = FOPEN_MODE_RB }, [SOC_FW_KEY_CERT_ID] = { .path = SOC_FW_KEY_CERT_NAME, .mode = FOPEN_MODE_RB }, [TRUSTED_OS_FW_KEY_CERT_ID] = { .path = TOS_FW_KEY_CERT_NAME, .mode = FOPEN_MODE_RB }, [NON_TRUSTED_FW_KEY_CERT_ID] = { .path = NT_FW_KEY_CERT_NAME, .mode = FOPEN_MODE_RB }, [SOC_FW_CONTENT_CERT_ID] = { .path = SOC_FW_CONTENT_CERT_NAME, .mode = FOPEN_MODE_RB }, [TRUSTED_OS_FW_CONTENT_CERT_ID] = { .path = TOS_FW_CONTENT_CERT_NAME, .mode = FOPEN_MODE_RB }, [NON_TRUSTED_FW_CONTENT_CERT_ID] = { .path = NT_FW_CONTENT_CERT_NAME, .mode = FOPEN_MODE_RB }, #endif /* TRUSTED_BOARD_BOOT */ }; static int open_semihosting(const uintptr_t spec) { int result; uintptr_t local_image_handle; /* See if the file exists on semi-hosting.*/ result = io_dev_init(sh_dev_handle, (uintptr_t)NULL); if (result == 0) { result = io_open(sh_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using Semi-hosting IO\n"); io_close(local_image_handle); } } return result; } void plat_arm_io_setup(void) { int io_result; arm_io_setup(); /* Register the additional IO devices on this platform */ io_result = register_io_dev_sh(&sh_dev_con); assert(io_result == 0); /* Open connections to devices and cache the handles */ io_result = io_dev_open(sh_dev_con, (uintptr_t)NULL, &sh_dev_handle); assert(io_result == 0); /* Ignore improbable errors in release builds */ (void)io_result; } /* * FVP provides semihosting as an alternative to load images */ int plat_arm_get_alt_image_source(unsigned int image_id, uintptr_t *dev_handle, uintptr_t *image_spec) { int result = open_semihosting((const uintptr_t)&sh_file_spec[image_id]); if (result == 0) { *dev_handle = sh_dev_handle; *image_spec = (uintptr_t)&sh_file_spec[image_id]; } return result; } trusted-firmware-a-2.2/plat/arm/board/fvp/fvp_pm.c000066400000000000000000000345151355360272700221550ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fvp_private.h" #include "../drivers/arm/gic/v3/gicv3_private.h" #if ARM_RECOM_STATE_ID_ENC /* * The table storing the valid idle power states. Ensure that the * array entries are populated in ascending order of state-id to * enable us to use binary search during power state validation. * The table must be terminated by a NULL entry. */ const unsigned int arm_pm_idle_states[] = { /* State-id - 0x01 */ arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RET, ARM_PWR_LVL0, PSTATE_TYPE_STANDBY), /* State-id - 0x02 */ arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF, ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN), /* State-id - 0x22 */ arm_make_pwrstate_lvl1(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN), /* State-id - 0x222 */ arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN), 0, }; #endif /******************************************************************************* * Function which implements the common FVP specific operations to power down a * cluster in response to a CPU_OFF or CPU_SUSPEND request. ******************************************************************************/ static void fvp_cluster_pwrdwn_common(void) { uint64_t mpidr = read_mpidr_el1(); #if ENABLE_SPE_FOR_LOWER_ELS /* * On power down we need to disable statistical profiling extensions * before exiting coherency. */ spe_disable(); #endif /* Disable coherency if this cluster is to be turned off */ fvp_interconnect_disable(); /* Program the power controller to turn the cluster off */ fvp_pwrc_write_pcoffr(mpidr); } /* * Empty implementation of these hooks avoid setting the GICR_WAKER.Sleep bit * on ARM GICv3 implementations on FVP. This is required, because FVP does not * support SYSTEM_SUSPEND and it is `faked` in firmware. Hence, for wake up * from `fake` system suspend the GIC must not be powered off. */ void arm_gicv3_distif_pre_save(unsigned int rdist_proc_num) {} void arm_gicv3_distif_post_restore(unsigned int rdist_proc_num) {} static void fvp_power_domain_on_finish_common(const psci_power_state_t *target_state) { unsigned long mpidr; assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == ARM_LOCAL_STATE_OFF); /* Get the mpidr for this cpu */ mpidr = read_mpidr_el1(); /* Perform the common cluster specific operations */ if (target_state->pwr_domain_state[ARM_PWR_LVL1] == ARM_LOCAL_STATE_OFF) { /* * This CPU might have woken up whilst the cluster was * attempting to power down. In this case the FVP power * controller will have a pending cluster power off request * which needs to be cleared by writing to the PPONR register. * This prevents the power controller from interpreting a * subsequent entry of this cpu into a simple wfi as a power * down request. */ fvp_pwrc_write_pponr(mpidr); /* Enable coherency if this cluster was off */ fvp_interconnect_enable(); } /* Perform the common system specific operations */ if (target_state->pwr_domain_state[ARM_PWR_LVL2] == ARM_LOCAL_STATE_OFF) arm_system_pwr_domain_resume(); /* * Clear PWKUPR.WEN bit to ensure interrupts do not interfere * with a cpu power down unless the bit is set again */ fvp_pwrc_clr_wen(mpidr); } /******************************************************************************* * FVP handler called when a CPU is about to enter standby. ******************************************************************************/ static void fvp_cpu_standby(plat_local_state_t cpu_state) { assert(cpu_state == ARM_LOCAL_STATE_RET); /* * Enter standby state * dsb is good practice before using wfi to enter low power states */ dsb(); wfi(); } /******************************************************************************* * FVP handler called when a power domain is about to be turned on. The * mpidr determines the CPU to be turned on. ******************************************************************************/ static int fvp_pwr_domain_on(u_register_t mpidr) { int rc = PSCI_E_SUCCESS; unsigned int psysr; /* * Ensure that we do not cancel an inflight power off request for the * target cpu. That would leave it in a zombie wfi. Wait for it to power * off and then program the power controller to turn that CPU on. */ do { psysr = fvp_pwrc_read_psysr(mpidr); } while ((psysr & PSYSR_AFF_L0) != 0U); fvp_pwrc_write_pponr(mpidr); return rc; } /******************************************************************************* * FVP handler called when a power domain is about to be turned off. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ static void fvp_pwr_domain_off(const psci_power_state_t *target_state) { assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == ARM_LOCAL_STATE_OFF); /* * If execution reaches this stage then this power domain will be * suspended. Perform at least the cpu specific actions followed * by the cluster specific operations if applicable. */ /* Prevent interrupts from spuriously waking up this cpu */ plat_arm_gic_cpuif_disable(); /* Turn redistributor off */ plat_arm_gic_redistif_off(); /* Program the power controller to power off this cpu. */ fvp_pwrc_write_ppoffr(read_mpidr_el1()); if (target_state->pwr_domain_state[ARM_PWR_LVL1] == ARM_LOCAL_STATE_OFF) fvp_cluster_pwrdwn_common(); } /******************************************************************************* * FVP handler called when a power domain is about to be suspended. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ static void fvp_pwr_domain_suspend(const psci_power_state_t *target_state) { unsigned long mpidr; /* * FVP has retention only at cpu level. Just return * as nothing is to be done for retention. */ if (target_state->pwr_domain_state[ARM_PWR_LVL0] == ARM_LOCAL_STATE_RET) return; assert(target_state->pwr_domain_state[ARM_PWR_LVL0] == ARM_LOCAL_STATE_OFF); /* Get the mpidr for this cpu */ mpidr = read_mpidr_el1(); /* Program the power controller to enable wakeup interrupts. */ fvp_pwrc_set_wen(mpidr); /* Prevent interrupts from spuriously waking up this cpu */ plat_arm_gic_cpuif_disable(); /* * The Redistributor is not powered off as it can potentially prevent * wake up events reaching the CPUIF and/or might lead to losing * register context. */ /* Perform the common cluster specific operations */ if (target_state->pwr_domain_state[ARM_PWR_LVL1] == ARM_LOCAL_STATE_OFF) fvp_cluster_pwrdwn_common(); /* Perform the common system specific operations */ if (target_state->pwr_domain_state[ARM_PWR_LVL2] == ARM_LOCAL_STATE_OFF) arm_system_pwr_domain_save(); /* Program the power controller to power off this cpu. */ fvp_pwrc_write_ppoffr(read_mpidr_el1()); } /******************************************************************************* * FVP handler called when a power domain has just been powered on after * being turned off earlier. The target_state encodes the low power state that * each level has woken up from. ******************************************************************************/ static void fvp_pwr_domain_on_finish(const psci_power_state_t *target_state) { fvp_power_domain_on_finish_common(target_state); } /******************************************************************************* * FVP handler called when a power domain has just been powered on and the cpu * and its cluster are fully participating in coherent transaction on the * interconnect. Data cache must be enabled for CPU at this point. ******************************************************************************/ static void fvp_pwr_domain_on_finish_late(const psci_power_state_t *target_state) { /* Program GIC per-cpu distributor or re-distributor interface */ plat_arm_gic_pcpu_init(); /* Enable GIC CPU interface */ plat_arm_gic_cpuif_enable(); } /******************************************************************************* * FVP handler called when a power domain has just been powered on after * having been suspended earlier. The target_state encodes the low power state * that each level has woken up from. * TODO: At the moment we reuse the on finisher and reinitialize the secure * context. Need to implement a separate suspend finisher. ******************************************************************************/ static void fvp_pwr_domain_suspend_finish(const psci_power_state_t *target_state) { /* * Nothing to be done on waking up from retention from CPU level. */ if (target_state->pwr_domain_state[ARM_PWR_LVL0] == ARM_LOCAL_STATE_RET) return; fvp_power_domain_on_finish_common(target_state); /* Enable GIC CPU interface */ plat_arm_gic_cpuif_enable(); } /******************************************************************************* * FVP handlers to shutdown/reboot the system ******************************************************************************/ static void __dead2 fvp_system_off(void) { /* Write the System Configuration Control Register */ mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL, V2M_CFGCTRL_START | V2M_CFGCTRL_RW | V2M_CFGCTRL_FUNC(V2M_FUNC_SHUTDOWN)); wfi(); ERROR("FVP System Off: operation not handled.\n"); panic(); } static void __dead2 fvp_system_reset(void) { /* Write the System Configuration Control Register */ mmio_write_32(V2M_SYSREGS_BASE + V2M_SYS_CFGCTRL, V2M_CFGCTRL_START | V2M_CFGCTRL_RW | V2M_CFGCTRL_FUNC(V2M_FUNC_REBOOT)); wfi(); ERROR("FVP System Reset: operation not handled.\n"); panic(); } static int fvp_node_hw_state(u_register_t target_cpu, unsigned int power_level) { unsigned int psysr; int ret; /* * The format of 'power_level' is implementation-defined, but 0 must * mean a CPU. We also allow 1 to denote the cluster */ if ((power_level != ARM_PWR_LVL0) && (power_level != ARM_PWR_LVL1)) return PSCI_E_INVALID_PARAMS; /* * Read the status of the given MPDIR from FVP power controller. The * power controller only gives us on/off status, so map that to expected * return values of the PSCI call */ psysr = fvp_pwrc_read_psysr(target_cpu); if (psysr == PSYSR_INVALID) return PSCI_E_INVALID_PARAMS; if (power_level == ARM_PWR_LVL0) { ret = ((psysr & PSYSR_AFF_L0) != 0U) ? HW_ON : HW_OFF; } else { /* power_level == ARM_PWR_LVL1 */ ret = ((psysr & PSYSR_AFF_L1) != 0U) ? HW_ON : HW_OFF; } return ret; } /* * The FVP doesn't truly support power management at SYSTEM power domain. The * SYSTEM_SUSPEND will be down-graded to the cluster level within the platform * layer. The `fake` SYSTEM_SUSPEND allows us to validate some of the driver * save and restore sequences on FVP. */ #if !ARM_BL31_IN_DRAM static void fvp_get_sys_suspend_power_state(psci_power_state_t *req_state) { unsigned int i; for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF; } #endif /******************************************************************************* * Handler to filter PSCI requests. ******************************************************************************/ /* * The system power domain suspend is only supported only via * PSCI SYSTEM_SUSPEND API. PSCI CPU_SUSPEND request to system power domain * will be downgraded to the lower level. */ static int fvp_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { int rc; rc = arm_validate_power_state(power_state, req_state); /* * Ensure that the system power domain level is never suspended * via PSCI CPU SUSPEND API. Currently system suspend is only * supported via PSCI SYSTEM SUSPEND API. */ req_state->pwr_domain_state[ARM_PWR_LVL2] = ARM_LOCAL_STATE_RUN; return rc; } /* * Custom `translate_power_state_by_mpidr` handler for FVP. Unlike in the * `fvp_validate_power_state`, we do not downgrade the system power * domain level request in `power_state` as it will be used to query the * PSCI_STAT_COUNT/RESIDENCY at the system power domain level. */ static int fvp_translate_power_state_by_mpidr(u_register_t mpidr, unsigned int power_state, psci_power_state_t *output_state) { return arm_validate_power_state(power_state, output_state); } /******************************************************************************* * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard * platform layer will take care of registering the handlers with PSCI. ******************************************************************************/ plat_psci_ops_t plat_arm_psci_pm_ops = { .cpu_standby = fvp_cpu_standby, .pwr_domain_on = fvp_pwr_domain_on, .pwr_domain_off = fvp_pwr_domain_off, .pwr_domain_suspend = fvp_pwr_domain_suspend, .pwr_domain_on_finish = fvp_pwr_domain_on_finish, .pwr_domain_on_finish_late = fvp_pwr_domain_on_finish_late, .pwr_domain_suspend_finish = fvp_pwr_domain_suspend_finish, .system_off = fvp_system_off, .system_reset = fvp_system_reset, .validate_power_state = fvp_validate_power_state, .validate_ns_entrypoint = arm_validate_psci_entrypoint, .translate_power_state_by_mpidr = fvp_translate_power_state_by_mpidr, .get_node_hw_state = fvp_node_hw_state, #if !ARM_BL31_IN_DRAM /* * The TrustZone Controller is set up during the warmboot sequence after * resuming the CPU from a SYSTEM_SUSPEND. If BL31 is located in SRAM * this is not a problem but, if it is in TZC-secured DRAM, it tries to * reconfigure the same memory it is running on, causing an exception. */ .get_sys_suspend_power_state = fvp_get_sys_suspend_power_state, #endif .mem_protect_chk = arm_psci_mem_protect_chk, .read_mem_protect = arm_psci_read_mem_protect, .write_mem_protect = arm_nor_psci_write_mem_protect, }; const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops) { return ops; } trusted-firmware-a-2.2/plat/arm/board/fvp/fvp_private.h000066400000000000000000000012031355360272700232040ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef FVP_PRIVATE_H #define FVP_PRIVATE_H #include /******************************************************************************* * Function and variable prototypes ******************************************************************************/ void fvp_config_setup(void); void fvp_interconnect_init(void); void fvp_interconnect_enable(void); void fvp_interconnect_disable(void); void fvp_timer_init(void); void tsp_early_platform_setup(void); #endif /* FVP_PRIVATE_H */ trusted-firmware-a-2.2/plat/arm/board/fvp/fvp_security.c000066400000000000000000000013071355360272700234010ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /* * We assume that all security programming is done by the primary core. */ void plat_arm_security_setup(void) { /* * The Base FVP has a TrustZone address space controller, the Foundation * FVP does not. Trying to program the device on the foundation FVP will * cause an abort. * * If the platform had additional peripheral specific security * configurations, those would be configured here. */ if ((get_arm_config()->flags & ARM_CONFIG_HAS_TZC) != 0U) arm_tzc400_setup(NULL); } trusted-firmware-a-2.2/plat/arm/board/fvp/fvp_stack_protector.c000066400000000000000000000012031355360272700247330ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #define RANDOM_CANARY_VALUE ((u_register_t) 3288484550995823360ULL) u_register_t plat_get_stack_protector_canary(void) { /* * Ideally, a random number should be returned instead of the * combination of a timer's value and a compile-time constant. As the * FVP does not have any random number generator, this is better than * nothing but not necessarily really secure. */ return RANDOM_CANARY_VALUE ^ read_cntpct_el0(); } trusted-firmware-a-2.2/plat/arm/board/fvp/fvp_topology.c000066400000000000000000000062301355360272700234060ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* The FVP power domain tree descriptor */ static unsigned char fvp_power_domain_tree_desc[FVP_CLUSTER_COUNT + 2]; CASSERT(((FVP_CLUSTER_COUNT > 0) && (FVP_CLUSTER_COUNT <= 256)), assert_invalid_fvp_cluster_count); /******************************************************************************* * This function dynamically constructs the topology according to * FVP_CLUSTER_COUNT and returns it. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { int i; /* * The highest level is the system level. The next level is constituted * by clusters and then cores in clusters. */ fvp_power_domain_tree_desc[0] = 1; fvp_power_domain_tree_desc[1] = FVP_CLUSTER_COUNT; for (i = 0; i < FVP_CLUSTER_COUNT; i++) fvp_power_domain_tree_desc[i + 2] = FVP_MAX_CPUS_PER_CLUSTER; return fvp_power_domain_tree_desc; } /******************************************************************************* * This function returns the core count within the cluster corresponding to * `mpidr`. ******************************************************************************/ unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr) { return FVP_MAX_CPUS_PER_CLUSTER; } /******************************************************************************* * This function implements a part of the critical interface between the psci * generic layer and the platform that allows the former to query the platform * to convert an MPIDR to a unique linear index. An error code (-1) is returned * in case the MPIDR is invalid. ******************************************************************************/ int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int clus_id, cpu_id, thread_id; /* Validate affinity fields */ if ((arm_config.flags & ARM_CONFIG_FVP_SHIFTED_AFF) != 0U) { thread_id = MPIDR_AFFLVL0_VAL(mpidr); cpu_id = MPIDR_AFFLVL1_VAL(mpidr); clus_id = MPIDR_AFFLVL2_VAL(mpidr); } else { thread_id = 0; cpu_id = MPIDR_AFFLVL0_VAL(mpidr); clus_id = MPIDR_AFFLVL1_VAL(mpidr); } if (clus_id >= FVP_CLUSTER_COUNT) return -1; if (cpu_id >= FVP_MAX_CPUS_PER_CLUSTER) return -1; if (thread_id >= FVP_MAX_PE_PER_CPU) return -1; if (fvp_pwrc_read_psysr(mpidr) == PSYSR_INVALID) return -1; /* * Core position calculation for FVP platform depends on the MT bit in * MPIDR. This function cannot assume that the supplied MPIDR has the MT * bit set even if the implementation has. For example, PSCI clients * might supply MPIDR values without the MT bit set. Therefore, we * inject the current PE's MT bit so as to get the calculation correct. * This of course assumes that none or all CPUs on the platform has MT * bit set. */ mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK); return (int) plat_arm_calc_core_pos(mpidr); } trusted-firmware-a-2.2/plat/arm/board/fvp/fvp_trusted_boot.c000066400000000000000000000021211355360272700242420ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* * Store a new non-volatile counter value. * * On some FVP versions, the non-volatile counters are read-only so this * function will always fail. * * Return: 0 = success, Otherwise = error */ int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr) { const char *oid; uintptr_t nv_ctr_addr; assert(cookie != NULL); oid = (const char *)cookie; if (strcmp(oid, TRUSTED_FW_NVCOUNTER_OID) == 0) { nv_ctr_addr = TFW_NVCTR_BASE; } else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) { nv_ctr_addr = NTFW_CTR_BASE; } else { return 1; } mmio_write_32(nv_ctr_addr, nv_ctr); /* * If the FVP models a locked counter then its value cannot be updated * and the above write operation has been silently ignored. */ return (mmio_read_32(nv_ctr_addr) == nv_ctr) ? 0 : 1; } trusted-firmware-a-2.2/plat/arm/board/fvp/include/000077500000000000000000000000001355360272700221355ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/fvp/include/plat.ld.S000066400000000000000000000004301355360272700236140ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_LD_S #define PLAT_LD_S #include #include #endif /* PLAT_LD_S */ trusted-firmware-a-2.2/plat/arm/board/fvp/include/plat_macros.S000066400000000000000000000021051355360272700245630ustar00rootroot00000000000000/* * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S #include #include /* --------------------------------------------- * The below required platform porting macro * prints out relevant GIC registers whenever an * unhandled exception is taken in BL31. * Clobbers: x0 - x10, x16, x17, sp * --------------------------------------------- */ .macro plat_crash_print_regs /* * Detect if we're using the base memory map or * the legacy VE memory map */ mov_imm x0, (V2M_SYSREGS_BASE + V2M_SYS_ID) ldr w16, [x0] /* Extract BLD (12th - 15th bits) from the SYS_ID */ ubfx x16, x16, #V2M_SYS_ID_BLD_SHIFT, #4 /* Check if VE mmap */ cmp w16, #BLD_GIC_VE_MMAP b.eq use_ve_mmap /* Assume Base Cortex mmap */ mov_imm x17, BASE_GICC_BASE mov_imm x16, BASE_GICD_BASE b print_gic_regs use_ve_mmap: mov_imm x17, VE_GICC_BASE mov_imm x16, VE_GICD_BASE print_gic_regs: arm_print_gic_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/arm/board/fvp/include/platform_def.h000066400000000000000000000174011355360272700247530ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include #include #include #include "../fvp_def.h" /* Required platform porting definitions */ #define PLATFORM_CORE_COUNT \ (FVP_CLUSTER_COUNT * FVP_MAX_CPUS_PER_CLUSTER * FVP_MAX_PE_PER_CPU) #define PLAT_NUM_PWR_DOMAINS (FVP_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) + 1 #define PLAT_MAX_PWR_LVL ARM_PWR_LVL2 /* * Other platform porting definitions are provided by included headers */ /* * Required ARM standard platform porting definitions */ #define PLAT_ARM_CLUSTER_COUNT FVP_CLUSTER_COUNT #define PLAT_ARM_TRUSTED_SRAM_SIZE UL(0x00040000) /* 256 KB */ #define PLAT_ARM_TRUSTED_ROM_BASE UL(0x00000000) #define PLAT_ARM_TRUSTED_ROM_SIZE UL(0x04000000) /* 64 MB */ #define PLAT_ARM_TRUSTED_DRAM_BASE UL(0x06000000) #define PLAT_ARM_TRUSTED_DRAM_SIZE UL(0x02000000) /* 32 MB */ /* virtual address used by dynamic mem_protect for chunk_base */ #define PLAT_ARM_MEM_PROTEC_VA_FRAME UL(0xc0000000) /* No SCP in FVP */ #define PLAT_ARM_SCP_TZC_DRAM1_SIZE UL(0x0) #define PLAT_ARM_DRAM2_BASE ULL(0x880000000) #define PLAT_ARM_DRAM2_SIZE UL(0x80000000) /* * Load address of BL33 for this platform port */ #define PLAT_ARM_NS_IMAGE_BASE (ARM_DRAM1_BASE + UL(0x8000000)) /* * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the * plat_arm_mmap array defined for each BL stage. */ #if defined(IMAGE_BL31) # if ENABLE_SPM # define PLAT_ARM_MMAP_ENTRIES 9 # define MAX_XLAT_TABLES 9 # define PLAT_SP_IMAGE_MMAP_REGIONS 30 # define PLAT_SP_IMAGE_MAX_XLAT_TABLES 10 # else # define PLAT_ARM_MMAP_ENTRIES 8 # define MAX_XLAT_TABLES 5 # endif #elif defined(IMAGE_BL32) # define PLAT_ARM_MMAP_ENTRIES 8 # define MAX_XLAT_TABLES 5 #elif !USE_ROMLIB # define PLAT_ARM_MMAP_ENTRIES 11 # define MAX_XLAT_TABLES 5 #else # define PLAT_ARM_MMAP_ENTRIES 12 # define MAX_XLAT_TABLES 6 #endif /* * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size * plus a little space for growth. */ #define PLAT_ARM_MAX_BL1_RW_SIZE UL(0xB000) /* * PLAT_ARM_MAX_ROMLIB_RW_SIZE is define to use a full page */ #if USE_ROMLIB #define PLAT_ARM_MAX_ROMLIB_RW_SIZE UL(0x1000) #define PLAT_ARM_MAX_ROMLIB_RO_SIZE UL(0xe000) #else #define PLAT_ARM_MAX_ROMLIB_RW_SIZE UL(0) #define PLAT_ARM_MAX_ROMLIB_RO_SIZE UL(0) #endif /* * PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a * little space for growth. */ #if TRUSTED_BOARD_BOOT # define PLAT_ARM_MAX_BL2_SIZE UL(0x1D000) #else # define PLAT_ARM_MAX_BL2_SIZE UL(0x11000) #endif /* * Since BL31 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL31_SIZE is * calculated using the current BL31 PROGBITS debug size plus the sizes of * BL2 and BL1-RW */ #if ENABLE_SPM && !SPM_MM #define PLAT_ARM_MAX_BL31_SIZE UL(0x60000) #else #define PLAT_ARM_MAX_BL31_SIZE UL(0x3B000) #endif #ifndef __aarch64__ /* * Since BL32 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL32_SIZE is * calculated using the current SP_MIN PROGBITS debug size plus the sizes of * BL2 and BL1-RW */ # define PLAT_ARM_MAX_BL32_SIZE UL(0x3B000) #endif /* * Size of cacheable stacks */ #if defined(IMAGE_BL1) # if TRUSTED_BOARD_BOOT # define PLATFORM_STACK_SIZE UL(0x1000) # else # define PLATFORM_STACK_SIZE UL(0x440) # endif #elif defined(IMAGE_BL2) # if TRUSTED_BOARD_BOOT # define PLATFORM_STACK_SIZE UL(0x1000) # else # define PLATFORM_STACK_SIZE UL(0x400) # endif #elif defined(IMAGE_BL2U) # define PLATFORM_STACK_SIZE UL(0x400) #elif defined(IMAGE_BL31) # define PLATFORM_STACK_SIZE UL(0x800) #elif defined(IMAGE_BL32) # define PLATFORM_STACK_SIZE UL(0x440) #endif #define MAX_IO_DEVICES 3 #define MAX_IO_HANDLES 4 /* Reserve the last block of flash for PSCI MEM PROTECT flag */ #define PLAT_ARM_FIP_BASE V2M_FLASH0_BASE #define PLAT_ARM_FIP_MAX_SIZE (V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE) #define PLAT_ARM_NVM_BASE V2M_FLASH0_BASE #define PLAT_ARM_NVM_SIZE (V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE) /* * PL011 related constants */ #define PLAT_ARM_BOOT_UART_BASE V2M_IOFPGA_UART0_BASE #define PLAT_ARM_BOOT_UART_CLK_IN_HZ V2M_IOFPGA_UART0_CLK_IN_HZ #define PLAT_ARM_RUN_UART_BASE V2M_IOFPGA_UART1_BASE #define PLAT_ARM_RUN_UART_CLK_IN_HZ V2M_IOFPGA_UART1_CLK_IN_HZ #define PLAT_ARM_CRASH_UART_BASE PLAT_ARM_RUN_UART_BASE #define PLAT_ARM_CRASH_UART_CLK_IN_HZ PLAT_ARM_RUN_UART_CLK_IN_HZ #define PLAT_ARM_TSP_UART_BASE V2M_IOFPGA_UART2_BASE #define PLAT_ARM_TSP_UART_CLK_IN_HZ V2M_IOFPGA_UART2_CLK_IN_HZ #define PLAT_FVP_SMMUV3_BASE UL(0x2b400000) /* CCI related constants */ #define PLAT_FVP_CCI400_BASE UL(0x2c090000) #define PLAT_FVP_CCI400_CLUS0_SL_PORT 3 #define PLAT_FVP_CCI400_CLUS1_SL_PORT 4 /* CCI-500/CCI-550 on Base platform */ #define PLAT_FVP_CCI5XX_BASE UL(0x2a000000) #define PLAT_FVP_CCI5XX_CLUS0_SL_PORT 5 #define PLAT_FVP_CCI5XX_CLUS1_SL_PORT 6 /* CCN related constants. Only CCN 502 is currently supported */ #define PLAT_ARM_CCN_BASE UL(0x2e000000) #define PLAT_ARM_CLUSTER_TO_CCN_ID_MAP 1, 5, 7, 11 /* System timer related constants */ #define PLAT_ARM_NSTIMER_FRAME_ID U(1) /* Mailbox base address */ #define PLAT_ARM_TRUSTED_MAILBOX_BASE ARM_TRUSTED_SRAM_BASE /* TrustZone controller related constants * * Currently only filters 0 and 2 are connected on Base FVP. * Filter 0 : CPU clusters (no access to DRAM by default) * Filter 1 : not connected * Filter 2 : LCDs (access to VRAM allowed by default) * Filter 3 : not connected * Programming unconnected filters will have no effect at the * moment. These filter could, however, be connected in future. * So care should be taken not to configure the unused filters. * * Allow only non-secure access to all DRAM to supported devices. * Give access to the CPUs and Virtio. Some devices * would normally use the default ID so allow that too. */ #define PLAT_ARM_TZC_BASE UL(0x2a4a0000) #define PLAT_ARM_TZC_FILTERS TZC_400_REGION_ATTR_FILTER_BIT(0) #define PLAT_ARM_TZC_NS_DEV_ACCESS ( \ TZC_REGION_ACCESS_RDWR(FVP_NSAID_DEFAULT) | \ TZC_REGION_ACCESS_RDWR(FVP_NSAID_PCI) | \ TZC_REGION_ACCESS_RDWR(FVP_NSAID_AP) | \ TZC_REGION_ACCESS_RDWR(FVP_NSAID_VIRTIO) | \ TZC_REGION_ACCESS_RDWR(FVP_NSAID_VIRTIO_OLD)) /* * GIC related constants to cater for both GICv2 and GICv3 instances of an * FVP. They could be overriden at runtime in case the FVP implements the legacy * VE memory map. */ #define PLAT_ARM_GICD_BASE BASE_GICD_BASE #define PLAT_ARM_GICR_BASE BASE_GICR_BASE #define PLAT_ARM_GICC_BASE BASE_GICC_BASE /* * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 * terminology. On a GICv2 system or mode, the lists will be merged and treated * as Group 0 interrupts. */ #define PLAT_ARM_G1S_IRQ_PROPS(grp) \ ARM_G1S_IRQ_PROPS(grp), \ INTR_PROP_DESC(FVP_IRQ_TZ_WDOG, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(FVP_IRQ_SEC_SYS_TIMER, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_LEVEL) #define PLAT_ARM_G0_IRQ_PROPS(grp) ARM_G0_IRQ_PROPS(grp) #define PLAT_ARM_PRIVATE_SDEI_EVENTS ARM_SDEI_PRIVATE_EVENTS #define PLAT_ARM_SHARED_SDEI_EVENTS ARM_SDEI_SHARED_EVENTS #define PLAT_ARM_SP_IMAGE_STACK_BASE (PLAT_SP_IMAGE_NS_BUF_BASE + \ PLAT_SP_IMAGE_NS_BUF_SIZE) #define PLAT_SP_PRI PLAT_RAS_PRI /* * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes */ #ifdef __aarch64__ #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 36) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 36) #else #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #endif #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/arm/board/fvp/jmptbl.i000066400000000000000000000024421355360272700221560ustar00rootroot00000000000000# # Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Platform specific romlib functions can be added or included here. # The index in the output file will be generated cumulatively in the same # order as it is given in this file. # Output file can be found at: $BUILD_DIR/jmptbl.i # # Format: # lib function [patch] # Example: # rom rom_lib_init # fdt fdt_getprop_namelen patch rom rom_lib_init fdt fdt_getprop_namelen fdt fdt_setprop_inplace fdt fdt_check_header fdt fdt_node_offset_by_compatible mbedtls mbedtls_asn1_get_alg mbedtls mbedtls_asn1_get_alg_null mbedtls mbedtls_asn1_get_bitstring_null mbedtls mbedtls_asn1_get_bool mbedtls mbedtls_asn1_get_int mbedtls mbedtls_asn1_get_tag mbedtls mbedtls_free mbedtls mbedtls_md mbedtls mbedtls_md_get_size mbedtls mbedtls_memory_buffer_alloc_init mbedtls mbedtls_oid_get_md_alg mbedtls mbedtls_oid_get_numeric_string mbedtls mbedtls_oid_get_pk_alg mbedtls mbedtls_oid_get_sig_alg mbedtls mbedtls_pk_free mbedtls mbedtls_pk_init mbedtls mbedtls_pk_parse_subpubkey mbedtls mbedtls_pk_verify_ext mbedtls mbedtls_platform_set_snprintf mbedtls mbedtls_x509_get_rsassa_pss_params mbedtls mbedtls_x509_get_sig_alg mbedtls mbedtls_md_info_from_type c exit c atexit trusted-firmware-a-2.2/plat/arm/board/fvp/platform.mk000066400000000000000000000226471355360272700227020ustar00rootroot00000000000000# # Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Use the GICv3 driver on the FVP by default FVP_USE_GIC_DRIVER := FVP_GICV3 # Use the SP804 timer instead of the generic one FVP_USE_SP804_TIMER := 0 # Default cluster count for FVP FVP_CLUSTER_COUNT := 2 # Default number of CPUs per cluster on FVP FVP_MAX_CPUS_PER_CLUSTER := 4 # Default number of threads per CPU on FVP FVP_MAX_PE_PER_CPU := 1 FVP_DT_PREFIX := fvp-base-gicv3-psci $(eval $(call assert_boolean,FVP_USE_SP804_TIMER)) $(eval $(call add_define,FVP_USE_SP804_TIMER)) # The FVP platform depends on this macro to build with correct GIC driver. $(eval $(call add_define,FVP_USE_GIC_DRIVER)) # Pass FVP_CLUSTER_COUNT to the build system. $(eval $(call add_define,FVP_CLUSTER_COUNT)) # Pass FVP_MAX_CPUS_PER_CLUSTER to the build system. $(eval $(call add_define,FVP_MAX_CPUS_PER_CLUSTER)) # Pass FVP_MAX_PE_PER_CPU to the build system. $(eval $(call add_define,FVP_MAX_PE_PER_CPU)) # Sanity check the cluster count and if FVP_CLUSTER_COUNT <= 2, # choose the CCI driver , else the CCN driver ifeq ($(FVP_CLUSTER_COUNT), 0) $(error "Incorrect cluster count specified for FVP port") else ifeq ($(FVP_CLUSTER_COUNT),$(filter $(FVP_CLUSTER_COUNT),1 2)) FVP_INTERCONNECT_DRIVER := FVP_CCI else FVP_INTERCONNECT_DRIVER := FVP_CCN endif $(eval $(call add_define,FVP_INTERCONNECT_DRIVER)) FVP_GICV3_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v3/gicv3_main.c \ drivers/arm/gic/v3/gicv3_helpers.c \ plat/common/plat_gicv3.c \ plat/arm/common/arm_gicv3.c # Choose the GIC sources depending upon the how the FVP will be invoked ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV3) FVP_GIC_SOURCES := ${FVP_GICV3_SOURCES} \ drivers/arm/gic/v3/gic500.c else ifeq (${FVP_USE_GIC_DRIVER},FVP_GIC600) FVP_GIC_SOURCES := ${FVP_GICV3_SOURCES} \ drivers/arm/gic/v3/gic600.c else ifeq (${FVP_USE_GIC_DRIVER}, FVP_GICV2) FVP_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c \ plat/arm/common/arm_gicv2.c FVP_DT_PREFIX := fvp-base-gicv2-psci else $(error "Incorrect GIC driver chosen on FVP port") endif ifeq (${FVP_INTERCONNECT_DRIVER}, FVP_CCI) FVP_INTERCONNECT_SOURCES := drivers/arm/cci/cci.c else ifeq (${FVP_INTERCONNECT_DRIVER}, FVP_CCN) FVP_INTERCONNECT_SOURCES := drivers/arm/ccn/ccn.c \ plat/arm/common/arm_ccn.c else $(error "Incorrect CCN driver chosen on FVP port") endif FVP_SECURITY_SOURCES := drivers/arm/tzc/tzc400.c \ plat/arm/board/fvp/fvp_security.c \ plat/arm/common/arm_tzc400.c PLAT_INCLUDES := -Iplat/arm/board/fvp/include PLAT_BL_COMMON_SOURCES := plat/arm/board/fvp/fvp_common.c FVP_CPU_LIBS := lib/cpus/${ARCH}/aem_generic.S ifeq (${ARCH}, aarch64) # select a different set of CPU files, depending on whether we compile for # hardware assisted coherency cores or not ifeq (${HW_ASSISTED_COHERENCY}, 0) # Cores used without DSU FVP_CPU_LIBS += lib/cpus/aarch64/cortex_a35.S \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S \ lib/cpus/aarch64/cortex_a72.S \ lib/cpus/aarch64/cortex_a73.S else # Cores used with DSU only ifeq (${CTX_INCLUDE_AARCH32_REGS}, 0) # AArch64-only cores FVP_CPU_LIBS += lib/cpus/aarch64/cortex_a76.S \ lib/cpus/aarch64/cortex_a76ae.S \ lib/cpus/aarch64/cortex_a77.S \ lib/cpus/aarch64/neoverse_n1.S \ lib/cpus/aarch64/neoverse_e1.S \ lib/cpus/aarch64/neoverse_zeus.S \ lib/cpus/aarch64/cortex_hercules.S \ lib/cpus/aarch64/cortex_hercules_ae.S \ lib/cpus/aarch64/cortex_a65.S \ lib/cpus/aarch64/cortex_a65ae.S endif # AArch64/AArch32 cores FVP_CPU_LIBS += lib/cpus/aarch64/cortex_a55.S \ lib/cpus/aarch64/cortex_a75.S endif else FVP_CPU_LIBS += lib/cpus/aarch32/cortex_a32.S endif BL1_SOURCES += drivers/arm/smmu/smmu_v3.c \ drivers/arm/sp805/sp805.c \ drivers/delay_timer/delay_timer.c \ drivers/io/io_semihosting.c \ lib/semihosting/semihosting.c \ lib/semihosting/${ARCH}/semihosting_call.S \ plat/arm/board/fvp/${ARCH}/fvp_helpers.S \ plat/arm/board/fvp/fvp_bl1_setup.c \ plat/arm/board/fvp/fvp_err.c \ plat/arm/board/fvp/fvp_io_storage.c \ plat/arm/board/fvp/fvp_trusted_boot.c \ ${FVP_CPU_LIBS} \ ${FVP_INTERCONNECT_SOURCES} ifeq (${FVP_USE_SP804_TIMER},1) BL1_SOURCES += drivers/arm/sp804/sp804_delay_timer.c else BL1_SOURCES += drivers/delay_timer/generic_delay_timer.c endif BL2_SOURCES += drivers/arm/sp805/sp805.c \ drivers/io/io_semihosting.c \ lib/utils/mem_region.c \ lib/semihosting/semihosting.c \ lib/semihosting/${ARCH}/semihosting_call.S \ plat/arm/board/fvp/fvp_bl2_setup.c \ plat/arm/board/fvp/fvp_err.c \ plat/arm/board/fvp/fvp_io_storage.c \ plat/arm/board/fvp/fvp_trusted_boot.c \ plat/arm/common/arm_nor_psci_mem_protect.c \ ${FVP_SECURITY_SOURCES} ifeq (${BL2_AT_EL3},1) BL2_SOURCES += plat/arm/board/fvp/${ARCH}/fvp_helpers.S \ plat/arm/board/fvp/fvp_bl2_el3_setup.c \ ${FVP_CPU_LIBS} \ ${FVP_INTERCONNECT_SOURCES} endif ifeq (${FVP_USE_SP804_TIMER},1) BL2_SOURCES += drivers/arm/sp804/sp804_delay_timer.c endif BL2U_SOURCES += plat/arm/board/fvp/fvp_bl2u_setup.c \ ${FVP_SECURITY_SOURCES} ifeq (${FVP_USE_SP804_TIMER},1) BL2U_SOURCES += drivers/arm/sp804/sp804_delay_timer.c endif BL31_SOURCES += drivers/arm/fvp/fvp_pwrc.c \ drivers/arm/smmu/smmu_v3.c \ drivers/delay_timer/delay_timer.c \ drivers/cfi/v2m/v2m_flash.c \ lib/utils/mem_region.c \ plat/arm/board/fvp/fvp_bl31_setup.c \ plat/arm/board/fvp/fvp_pm.c \ plat/arm/board/fvp/fvp_topology.c \ plat/arm/board/fvp/aarch64/fvp_helpers.S \ plat/arm/common/arm_nor_psci_mem_protect.c \ ${FVP_CPU_LIBS} \ ${FVP_GIC_SOURCES} \ ${FVP_INTERCONNECT_SOURCES} \ ${FVP_SECURITY_SOURCES} ifeq (${FVP_USE_SP804_TIMER},1) BL31_SOURCES += drivers/arm/sp804/sp804_delay_timer.c else BL31_SOURCES += drivers/delay_timer/generic_delay_timer.c endif # Add the FDT_SOURCES and options for Dynamic Config (only for Unix env) ifdef UNIX_MK FVP_HW_CONFIG_DTS := fdts/${FVP_DT_PREFIX}.dts FDT_SOURCES += $(addprefix plat/arm/board/fvp/fdts/, \ ${PLAT}_tb_fw_config.dts \ ${PLAT}_soc_fw_config.dts \ ${PLAT}_nt_fw_config.dts \ ) FVP_TB_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb FVP_SOC_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_soc_fw_config.dtb FVP_NT_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_nt_fw_config.dtb ifeq (${SPD},tspd) FDT_SOURCES += plat/arm/board/fvp/fdts/${PLAT}_tsp_fw_config.dts FVP_TOS_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_tsp_fw_config.dtb # Add the TOS_FW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${FVP_TOS_FW_CONFIG},--tos-fw-config)) endif # Add the TB_FW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${FVP_TB_FW_CONFIG},--tb-fw-config)) # Add the SOC_FW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${FVP_SOC_FW_CONFIG},--soc-fw-config)) # Add the NT_FW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${FVP_NT_FW_CONFIG},--nt-fw-config)) FDT_SOURCES += ${FVP_HW_CONFIG_DTS} $(eval FVP_HW_CONFIG := ${BUILD_PLAT}/$(patsubst %.dts,%.dtb,$(FVP_HW_CONFIG_DTS))) # Add the HW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${FVP_HW_CONFIG},--hw-config)) endif # Enable Activity Monitor Unit extensions by default ENABLE_AMU := 1 # Enable dynamic mitigation support by default DYNAMIC_WORKAROUND_CVE_2018_3639 := 1 ifneq (${RESET_TO_BL31},1) # Enable reclaiming of BL31 initialisation code for secondary cores stacks for # FVP. We cannot enable PIE for this case because the overlayed init section # creates some dynamic relocations which cannot be handled by the fixup # logic currently. RECLAIM_INIT_CODE := 1 else # Enable PIE support when RESET_TO_BL31=1 ENABLE_PIE := 1 endif ifeq (${ENABLE_AMU},1) BL31_SOURCES += lib/cpus/aarch64/cpuamu.c \ lib/cpus/aarch64/cpuamu_helpers.S ifeq (${HW_ASSISTED_COHERENCY}, 1) BL31_SOURCES += lib/cpus/aarch64/cortex_a75_pubsub.c \ lib/cpus/aarch64/neoverse_n1_pubsub.c endif endif ifeq (${RAS_EXTENSION},1) BL31_SOURCES += plat/arm/board/fvp/aarch64/fvp_ras.c endif ifneq (${ENABLE_STACK_PROTECTOR},0) PLAT_BL_COMMON_SOURCES += plat/arm/board/fvp/fvp_stack_protector.c endif ifeq (${ARCH},aarch32) NEED_BL32 := yes endif # Enable the dynamic translation tables library. ifeq (${ARCH},aarch32) ifeq (${RESET_TO_SP_MIN},1) BL32_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1 endif else # if AArch64 ifeq (${RESET_TO_BL31},1) BL31_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1 endif ifeq (${ENABLE_SPM},1) ifeq (${SPM_MM},0) BL31_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1 endif endif ifeq (${SPD},trusty) BL31_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1 endif endif # Add support for platform supplied linker script for BL31 build $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) ifneq (${BL2_AT_EL3}, 0) override BL1_SOURCES = endif include plat/arm/board/common/board_common.mk include plat/arm/common/arm_common.mk # FVP being a development platform, enable capability to disable Authentication # dynamically if TRUSTED_BOARD_BOOT is set. ifeq (${TRUSTED_BOARD_BOOT}, 1) DYN_DISABLE_AUTH := 1 endif trusted-firmware-a-2.2/plat/arm/board/fvp/sp_min/000077500000000000000000000000001355360272700217775ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c000066400000000000000000000017331355360272700255270ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "../fvp_private.h" void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { arm_sp_min_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3); /* Initialize the platform config for future decision making */ fvp_config_setup(); /* * Initialize the correct interconnect for this cluster during cold * boot. No need for locks as no other CPU is active. */ fvp_interconnect_init(); /* * Enable coherency in interconnect for the primary CPU's cluster. * Earlier bootloader stages might already do this (e.g. Trusted * Firmware's BL1 does it) but we can't assume so. There is no harm in * executing this code twice anyway. * FVP PSCI code will enable coherency for other clusters. */ fvp_interconnect_enable(); } trusted-firmware-a-2.2/plat/arm/board/fvp/sp_min/sp_min-fvp.mk000066400000000000000000000012441355360272700244070ustar00rootroot00000000000000# # Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # SP_MIN source files specific to FVP platform BL32_SOURCES += drivers/arm/fvp/fvp_pwrc.c \ drivers/cfi/v2m/v2m_flash.c \ lib/utils/mem_region.c \ plat/arm/board/fvp/aarch32/fvp_helpers.S \ plat/arm/board/fvp/fvp_pm.c \ plat/arm/board/fvp/fvp_topology.c \ plat/arm/board/fvp/sp_min/fvp_sp_min_setup.c \ plat/arm/common/arm_nor_psci_mem_protect.c \ ${FVP_CPU_LIBS} \ ${FVP_GIC_SOURCES} \ ${FVP_INTERCONNECT_SOURCES} \ ${FVP_SECURITY_SOURCES} include plat/arm/common/sp_min/arm_sp_min.mk trusted-firmware-a-2.2/plat/arm/board/fvp/tsp/000077500000000000000000000000001355360272700213205ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/fvp/tsp/fvp_tsp_setup.c000066400000000000000000000005471355360272700243730ustar00rootroot00000000000000/* * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "../fvp_private.h" void tsp_early_platform_setup(void) { arm_tsp_early_platform_setup(); /* Initialize the platform config for future decision making */ fvp_config_setup(); } trusted-firmware-a-2.2/plat/arm/board/fvp/tsp/tsp-fvp.mk000066400000000000000000000006361355360272700232550ustar00rootroot00000000000000# # Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # TSP source files specific to FVP platform BL32_SOURCES += drivers/arm/fvp/fvp_pwrc.c \ plat/arm/board/fvp/aarch64/fvp_helpers.S \ plat/arm/board/fvp/fvp_topology.c \ plat/arm/board/fvp/tsp/fvp_tsp_setup.c \ ${FVP_GIC_SOURCES} include plat/arm/common/tsp/arm_tsp.mk trusted-firmware-a-2.2/plat/arm/board/fvp_ve/000077500000000000000000000000001355360272700212045ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/fvp_ve/aarch32/000077500000000000000000000000001355360272700224275ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/fvp_ve/aarch32/fvp_ve_helpers.S000066400000000000000000000035561355360272700255730ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl plat_secondary_cold_boot_setup .globl plat_get_my_entrypoint .globl plat_is_my_cpu_primary /* -------------------------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * For AArch32, cold-booting secondary CPUs is not yet * implemented and they panic. * -------------------------------------------------------------------- */ func plat_secondary_cold_boot_setup cb_panic: b cb_panic endfunc plat_secondary_cold_boot_setup /* --------------------------------------------------------------------- * unsigned long plat_get_my_entrypoint (void); * * Main job of this routine is to distinguish between a cold and warm * boot. On FVP, this information can be queried from the power * controller. The Power Control SYS Status Register (PSYSR) indicates * the wake-up reason for the CPU. * * For a cold boot, return 0. * For a warm boot, read the mailbox and return the address it contains. * * TODO: PSYSR is a common register and should be * accessed using locks. Since it is not possible * to use locks immediately after a cold reset * we are relying on the fact that after a cold * reset all cpus will read the same WK field * --------------------------------------------------------------------- */ func plat_get_my_entrypoint /* TODO support warm boot */ /* Cold reset */ mov r0, #0 bx lr endfunc plat_get_my_entrypoint /* ----------------------------------------------------- * unsigned int plat_is_my_cpu_primary (void); * * Currently configured for a sigle CPU * ----------------------------------------------------- */ func plat_is_my_cpu_primary mov r0, #1 bx lr endfunc plat_is_my_cpu_primary trusted-firmware-a-2.2/plat/arm/board/fvp_ve/fdts/000077500000000000000000000000001355360272700221445ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/fvp_ve/fdts/fvp_ve_tb_fw_config.dts000066400000000000000000000005271355360272700266570ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { /* Platform Config */ plat_arm_bl2 { compatible = "arm,tb_fw"; hw_config_addr = <0x0 0x82000000>; hw_config_max_size = <0x01000000>; /* Disable authentication for development */ disable_auth = <0x0>; }; }; trusted-firmware-a-2.2/plat/arm/board/fvp_ve/fvp_ve_bl1_setup.c000066400000000000000000000013611355360272700246140ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /******************************************************************************* * Perform any BL1 specific platform actions. ******************************************************************************/ void bl1_early_platform_setup(void) { arm_bl1_early_platform_setup(); } void plat_arm_secure_wdt_start(void) { sp805_start(ARM_SP805_TWDG_BASE, ARM_TWDG_LOAD_VAL); } void plat_arm_secure_wdt_stop(void) { sp805_stop(ARM_SP805_TWDG_BASE); } void bl1_platform_setup(void) { arm_bl1_platform_setup(); } trusted-firmware-a-2.2/plat/arm/board/fvp_ve/fvp_ve_bl2_setup.c000066400000000000000000000021511355360272700246130ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "fvp_ve_private.h" void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { arm_bl2_early_platform_setup((uintptr_t)arg0, (meminfo_t *)arg1); /* Initialize the platform config for future decision making */ fvp_ve_config_setup(); } void bl2_platform_setup(void) { arm_bl2_platform_setup(); #ifdef FVP_VE_USE_SP804_TIMER /* * Enable the clock override for SP804 timer 0, which means that no * clock dividers are applied and the raw (35 MHz) clock will be used */ mmio_write_32(V2M_SP810_BASE, FVP_SP810_CTRL_TIM0_OV); /* Initialize delay timer driver using SP804 dual timer 0 */ sp804_timer_init(V2M_SP804_TIMER0_BASE, SP804_TIMER_CLKMULT, SP804_TIMER_CLKDIV); #else generic_delay_timer_init(); #endif /* FVP_VE_USE_SP804_TIMER */ } trusted-firmware-a-2.2/plat/arm/board/fvp_ve/fvp_ve_common.c000066400000000000000000000022451355360272700242100ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #define MAP_DEVICE0 MAP_REGION_FLAT(DEVICE0_BASE, \ DEVICE0_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #ifdef IMAGE_BL1 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, V2M_MAP_FLASH1_RW, V2M_MAP_IOFPGA, {0} }; #endif #ifdef IMAGE_BL2 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, V2M_MAP_FLASH1_RW, V2M_MAP_IOFPGA, ARM_MAP_NS_DRAM1, {0} }; #endif #ifdef IMAGE_BL32 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, V2M_MAP_IOFPGA, MAP_DEVICE0, {0} }; #endif ARM_CASSERT_MMAP void __init fvp_ve_config_setup(void) { unsigned int sys_id, arch; sys_id = mmio_read_32(V2M_SYSREGS_BASE + V2M_SYS_ID); arch = (sys_id >> V2M_SYS_ID_ARCH_SHIFT) & V2M_SYS_ID_ARCH_MASK; if (arch != ARCH_MODEL_VE) { ERROR("This firmware is for FVP VE models\n"); panic(); } } unsigned int plat_get_syscnt_freq2(void) { return FVP_VE_TIMER_BASE_FREQUENCY; } trusted-firmware-a-2.2/plat/arm/board/fvp_ve/fvp_ve_def.h000066400000000000000000000043631355360272700234660ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef FVP_VE_DEF_H #define FVP_VE_DEF_H #include /* Default cluster count for FVP VE */ #define FVP_VE_CLUSTER_COUNT 1 /* Default number of CPUs per cluster on FVP VE */ #define FVP_VE_MAX_CPUS_PER_CLUSTER 1 /* Default number of threads per CPU on FVP VE */ #define FVP_VE_MAX_PE_PER_CPU 1 #define FVP_VE_CORE_COUNT 1 #define FVP_VE_PRIMARY_CPU 0x0 /******************************************************************************* * FVP memory map related constants ******************************************************************************/ #define FLASH1_BASE 0x0c000000 #define FLASH1_SIZE 0x04000000 /* Aggregate of all devices in the first GB */ #define DEVICE0_BASE 0x20000000 #define DEVICE0_SIZE 0x0c200000 #define NSRAM_BASE 0x2e000000 #define NSRAM_SIZE 0x10000 #define PCIE_EXP_BASE 0x40000000 #define TZRNG_BASE 0x7fe60000 #define ARCH_MODEL_VE 0x5 /* FVP Power controller base address*/ #define PWRC_BASE UL(0x1c100000) /* FVP SP804 timer frequency is 35 MHz*/ #define SP804_TIMER_CLKMULT 1 #define SP804_TIMER_CLKDIV 35 /* SP810 controller. FVP specific flags */ #define FVP_SP810_CTRL_TIM0_OV (1 << 16) #define FVP_SP810_CTRL_TIM1_OV (1 << 18) #define FVP_SP810_CTRL_TIM2_OV (1 << 20) #define FVP_SP810_CTRL_TIM3_OV (1 << 22) /******************************************************************************* * GIC-400 & interrupt handling related constants ******************************************************************************/ /* VE compatible GIC memory map */ #define VE_GICD_BASE 0x2c001000 #ifdef ARM_CORTEX_A5 #define VE_GICC_BASE 0x2c000100 #else #define VE_GICC_BASE 0x2c002000 #endif #define VE_GICH_BASE 0x2c004000 #define VE_GICV_BASE 0x2c006000 #define FVP_VE_IRQ_TZ_WDOG 56 #define FVP_VE_IRQ_SEC_SYS_TIMER 57 #define V2M_FLASH1_BASE UL(0x0C000000) #define V2M_FLASH1_SIZE UL(0x04000000) #define V2M_MAP_FLASH1_RW MAP_REGION_FLAT(V2M_FLASH1_BASE,\ V2M_FLASH1_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define V2M_MAP_FLASH1_RO MAP_REGION_FLAT(V2M_FLASH1_BASE,\ V2M_FLASH1_SIZE, \ MT_RO_DATA | MT_SECURE) #endif /* FVP_VE_DEF_H */ trusted-firmware-a-2.2/plat/arm/board/fvp_ve/fvp_ve_err.c000066400000000000000000000003751355360272700235120ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* * FVP VE error handler */ void __dead2 plat_arm_error_handler(int err) { while (1) { wfi(); } } trusted-firmware-a-2.2/plat/arm/board/fvp_ve/fvp_ve_pm.c000066400000000000000000000013171355360272700233330ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /******************************************************************************* * Export the platform handlers via fvp_ve_psci_pm_ops. The ARM Standard * platform layer will take care of registering the handlers with PSCI. ******************************************************************************/ plat_psci_ops_t fvp_ve_psci_pm_ops = { /* dummy struct */ .validate_ns_entrypoint = NULL, }; int __init plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { *psci_ops = &fvp_ve_psci_pm_ops; return 0; } trusted-firmware-a-2.2/plat/arm/board/fvp_ve/fvp_ve_private.h000066400000000000000000000007151355360272700243770ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef FVP_VE_PRIVATE_H #define FVP_VE_PRIVATE_H #include /******************************************************************************* * Function and variable prototypes ******************************************************************************/ void fvp_ve_config_setup(void); #endif /* FVP_VE_PRIVATE_H */ trusted-firmware-a-2.2/plat/arm/board/fvp_ve/fvp_ve_security.c000066400000000000000000000010261355360272700245630ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * We assume that all security programming is done by the primary core. */ void plat_arm_security_setup(void) { /* * The Base FVP has a TrustZone address space controller, the Foundation * FVP does not. Trying to program the device on the foundation FVP will * cause an abort. * * If the platform had additional peripheral specific security * configurations, those would be configured here. */ return; } trusted-firmware-a-2.2/plat/arm/board/fvp_ve/fvp_ve_topology.c000066400000000000000000000022331355360272700245710ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* The FVP VE power domain tree descriptor */ static const unsigned char fvp_ve_power_domain_tree_desc[] = { 1, /* No of children for the root node */ FVP_VE_CLUSTER_COUNT, /* No of children for the first cluster node */ FVP_VE_CORE_COUNT, }; /******************************************************************************* * This function returns the topology according to FVP_VE_CLUSTER_COUNT. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { return fvp_ve_power_domain_tree_desc; } /******************************************************************************* * Currently FVP VE has only been tested with one core, therefore 0 is returned. ******************************************************************************/ int plat_core_pos_by_mpidr(u_register_t mpidr) { return 0; } trusted-firmware-a-2.2/plat/arm/board/fvp_ve/include/000077500000000000000000000000001355360272700226275ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/fvp_ve/include/platform_def.h000066400000000000000000000237741355360272700254570ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include #include #include "../fvp_ve_def.h" #define ARM_CACHE_WRITEBACK_SHIFT 6 /* Memory location options for TSP */ #define ARM_DRAM_ID 2 #define ARM_DRAM1_BASE UL(0x80000000) #define ARM_DRAM1_SIZE UL(0x80000000) #define ARM_DRAM1_END (ARM_DRAM1_BASE + \ ARM_DRAM1_SIZE - 1) #define ARM_DRAM2_BASE PLAT_ARM_DRAM2_BASE #define ARM_DRAM2_SIZE PLAT_ARM_DRAM2_SIZE #define ARM_DRAM2_END (ARM_DRAM2_BASE + \ ARM_DRAM2_SIZE - 1) #define ARM_NS_DRAM1_BASE ARM_DRAM1_BASE /* * The last 2MB is meant to be NOLOAD and will not be zero * initialized. */ #define ARM_NS_DRAM1_SIZE (ARM_DRAM1_SIZE - \ 0x00200000) /* The first 4KB of NS DRAM1 are used as shared memory */ #define FVP_VE_SHARED_RAM_BASE ARM_NS_DRAM1_BASE #define FVP_VE_SHARED_RAM_SIZE UL(0x00001000) /* 4 KB */ /* The next 252 kB of NS DRAM is used to load the BL images */ #define ARM_BL_RAM_BASE (FVP_VE_SHARED_RAM_BASE + \ FVP_VE_SHARED_RAM_SIZE) #define ARM_BL_RAM_SIZE (PLAT_ARM_BL_PLUS_SHARED_RAM_SIZE - \ FVP_VE_SHARED_RAM_SIZE) #define ARM_IRQ_SEC_PHY_TIMER 29 #define ARM_IRQ_SEC_SGI_0 8 #define ARM_IRQ_SEC_SGI_1 9 #define ARM_IRQ_SEC_SGI_2 10 #define ARM_IRQ_SEC_SGI_3 11 #define ARM_IRQ_SEC_SGI_4 12 #define ARM_IRQ_SEC_SGI_5 13 #define ARM_IRQ_SEC_SGI_6 14 #define ARM_IRQ_SEC_SGI_7 15 /* * Define a list of Group 1 Secure and Group 0 interrupt properties as per GICv3 * terminology. On a GICv2 system or mode, the lists will be merged and treated * as Group 0 interrupts. */ #define ARM_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE) #define ARM_G0_IRQ_PROPS(grp) \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_EDGE) #define ARM_MAP_SHARED_RAM MAP_REGION_FLAT( \ FVP_VE_SHARED_RAM_BASE, \ FVP_VE_SHARED_RAM_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define ARM_MAP_NS_DRAM1 MAP_REGION_FLAT( \ ARM_NS_DRAM1_BASE, \ ARM_NS_DRAM1_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define ARM_MAP_DRAM2 MAP_REGION_FLAT( \ ARM_DRAM2_BASE, \ ARM_DRAM2_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define ARM_MAP_BL_RO MAP_REGION_FLAT( \ BL_CODE_BASE, \ BL_CODE_END - BL_CODE_BASE, \ MT_CODE | MT_SECURE), \ MAP_REGION_FLAT( \ BL_RO_DATA_BASE, \ BL_RO_DATA_END \ - BL_RO_DATA_BASE, \ MT_RO_DATA | MT_SECURE) #if USE_COHERENT_MEM #define ARM_MAP_BL_COHERENT_RAM MAP_REGION_FLAT( \ BL_COHERENT_RAM_BASE, \ BL_COHERENT_RAM_END \ - BL_COHERENT_RAM_BASE, \ MT_DEVICE | MT_RW | MT_SECURE) #endif /* * The max number of regions like RO(code), coherent and data required by * different BL stages which need to be mapped in the MMU. */ #define ARM_BL_REGIONS 5 #define MAX_MMAP_REGIONS (PLAT_ARM_MMAP_ENTRIES + \ ARM_BL_REGIONS) /* Memory mapped Generic timer interfaces */ #define FVP_VE_TIMER_BASE_FREQUENCY UL(24000000) #define ARM_SYS_CNTREAD_BASE UL(0x2a800000) #define ARM_SYS_CNT_BASE_S UL(0x2a820000) #define ARM_SYS_CNT_BASE_NS UL(0x2a830000) #define ARM_CONSOLE_BAUDRATE 115200 /* Trusted Watchdog constants */ #define ARM_SP805_TWDG_BASE UL(0x1C0F0000) #define ARM_SP805_TWDG_CLK_HZ 32768 /* The TBBR document specifies a watchdog timeout of 256 seconds. SP805 * asserts reset after two consecutive countdowns (2 x 128 = 256 sec) */ #define ARM_TWDG_TIMEOUT_SEC 128 #define ARM_TWDG_LOAD_VAL (ARM_SP805_TWDG_CLK_HZ * \ ARM_TWDG_TIMEOUT_SEC) #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) /* * This macro defines the deepest retention state possible. A higher state * id will represent an invalid or a power down state. */ #define PLAT_MAX_RET_STATE 1 /* * This macro defines the deepest power down states possible. Any state ID * higher than this is invalid. */ #define PLAT_MAX_OFF_STATE 2 /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. */ #define CACHE_WRITEBACK_GRANULE (U(1) << ARM_CACHE_WRITEBACK_SHIFT) /* * To enable TB_FW_CONFIG to be loaded by BL1, define the corresponding base * and limit. Leave enough space of BL2 meminfo. */ #define ARM_TB_FW_CONFIG_BASE (ARM_BL_RAM_BASE + sizeof(meminfo_t)) #define ARM_TB_FW_CONFIG_LIMIT (ARM_BL_RAM_BASE + PAGE_SIZE) /******************************************************************************* * BL1 specific defines. * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of * addresses. ******************************************************************************/ #define BL1_RO_BASE 0x00000000 #define BL1_RO_LIMIT PLAT_ARM_TRUSTED_ROM_SIZE /* * Put BL1 RW at the top of the memory allocated for BL images in NS DRAM. */ #define BL1_RW_BASE (ARM_BL_RAM_BASE + \ ARM_BL_RAM_SIZE - \ (PLAT_ARM_MAX_BL1_RW_SIZE)) #define BL1_RW_LIMIT (ARM_BL_RAM_BASE + \ (ARM_BL_RAM_SIZE)) /******************************************************************************* * BL2 specific defines. ******************************************************************************/ /* * Put BL2 just below BL1. */ #define BL2_BASE (BL1_RW_BASE - FVP_VE_MAX_BL2_SIZE) #define BL2_LIMIT BL1_RW_BASE /* Put BL32 below BL2 in NS DRAM.*/ #define ARM_BL2_MEM_DESC_BASE ARM_TB_FW_CONFIG_LIMIT #define BL32_BASE ((ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE)\ - PLAT_ARM_MAX_BL32_SIZE) #define BL32_PROGBITS_LIMIT BL2_BASE #define BL32_LIMIT (ARM_BL_RAM_BASE + ARM_BL_RAM_SIZE) /* Required platform porting definitions */ #define PLATFORM_CORE_COUNT 1 #define PLAT_NUM_PWR_DOMAINS ((FVP_VE_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) + 1) #define PLAT_MAX_PWR_LVL 2 /* * Other platform porting definitions are provided by included headers */ /* * Required ARM standard platform porting definitions */ #define PLAT_ARM_BL_PLUS_SHARED_RAM_SIZE 0x00040000 /* 256 KB */ #define PLAT_ARM_TRUSTED_ROM_BASE 0x00000000 #define PLAT_ARM_TRUSTED_ROM_SIZE 0x04000000 /* 64 MB */ #define PLAT_ARM_DRAM2_BASE ULL(0x880000000) #define PLAT_ARM_DRAM2_SIZE ULL(0x80000000) /* * Load address of BL33 for this platform port */ #define PLAT_ARM_NS_IMAGE_BASE (ARM_DRAM1_BASE + U(0x8000000)) /* * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the * plat_arm_mmap array defined for each BL stage. */ #if defined(IMAGE_BL32) # define PLAT_ARM_MMAP_ENTRIES 8 # define MAX_XLAT_TABLES 6 #else # define PLAT_ARM_MMAP_ENTRIES 12 # define MAX_XLAT_TABLES 6 #endif /* * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size * plus a little space for growth. */ #define PLAT_ARM_MAX_BL1_RW_SIZE 0xB000 /* * FVP_VE_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a * little space for growth. */ #define FVP_VE_MAX_BL2_SIZE 0x11000 /* * Since BL32 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL32_SIZE is * calculated using the current SP_MIN PROGBITS debug size plus the sizes of * BL2 and BL1-RW */ #define PLAT_ARM_MAX_BL32_SIZE 0x3B000 /* * Size of cacheable stacks */ #if defined(IMAGE_BL1) # define PLATFORM_STACK_SIZE 0x440 #elif defined(IMAGE_BL2) # define PLATFORM_STACK_SIZE 0x400 #elif defined(IMAGE_BL32) # define PLATFORM_STACK_SIZE 0x440 #endif #define MAX_IO_DEVICES 3 #define MAX_IO_HANDLES 4 /* Reserve the last block of flash for PSCI MEM PROTECT flag */ #define PLAT_ARM_FIP_BASE V2M_FLASH1_BASE #define PLAT_ARM_FIP_MAX_SIZE (V2M_FLASH1_SIZE - V2M_FLASH_BLOCK_SIZE) #define PLAT_ARM_NVM_BASE V2M_FLASH1_BASE #define PLAT_ARM_NVM_SIZE (V2M_FLASH1_SIZE - V2M_FLASH_BLOCK_SIZE) /* * PL011 related constants */ #define PLAT_ARM_BOOT_UART_BASE V2M_IOFPGA_UART0_BASE #define PLAT_ARM_BOOT_UART_CLK_IN_HZ V2M_IOFPGA_UART0_CLK_IN_HZ #define PLAT_ARM_RUN_UART_BASE V2M_IOFPGA_UART1_BASE #define PLAT_ARM_RUN_UART_CLK_IN_HZ V2M_IOFPGA_UART1_CLK_IN_HZ #define PLAT_ARM_CRASH_UART_BASE PLAT_ARM_RUN_UART_BASE #define PLAT_ARM_CRASH_UART_CLK_IN_HZ PLAT_ARM_RUN_UART_CLK_IN_HZ /* System timer related constants */ #define PLAT_ARM_NSTIMER_FRAME_ID 1 /* Mailbox base address */ #define FVP_VE_TRUSTED_MAILBOX_BASE FVP_VE_SHARED_RAM_BASE /* * GIC related constants to cater for GICv2 */ #define PLAT_ARM_GICD_BASE VE_GICD_BASE #define PLAT_ARM_GICC_BASE VE_GICC_BASE /* * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 * terminology. On a GICv2 system or mode, the lists will be merged and treated * as Group 0 interrupts. */ #define PLAT_ARM_G1S_IRQ_PROPS(grp) \ ARM_G1S_IRQ_PROPS(grp), \ INTR_PROP_DESC(FVP_VE_IRQ_TZ_WDOG, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(FVP_VE_IRQ_SEC_SYS_TIMER, GIC_HIGHEST_SEC_PRIORITY, (grp), \ GIC_INTR_CFG_LEVEL) #define PLAT_ARM_G0_IRQ_PROPS(grp) ARM_G0_IRQ_PROPS(grp) /* * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes */ #ifdef __aarch64__ #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 36) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 36) #else #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #endif #endif /* PLATFORM_H */ trusted-firmware-a-2.2/plat/arm/board/fvp_ve/platform.mk000066400000000000000000000077451355360272700233760ustar00rootroot00000000000000# # Copyright (c) 2019, Arm Limited. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ifdef ARM_CORTEX_A5 # Use the SP804 timer instead of the generic one FVP_VE_USE_SP804_TIMER := 1 $(eval $(call add_define,FVP_VE_USE_SP804_TIMER)) BL2_SOURCES += drivers/arm/sp804/sp804_delay_timer.c endif FVP_VE_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c \ plat/arm/common/arm_gicv2.c FVP_VE_SECURITY_SOURCES := plat/arm/board/fvp_ve/fvp_ve_security.c PLAT_INCLUDES := -Iplat/arm/board/fvp_ve/include PLAT_BL_COMMON_SOURCES := plat/arm/board/fvp_ve/fvp_ve_common.c \ plat/arm/common/${ARCH}/arm_helpers.S \ plat/arm/common/arm_common.c \ plat/arm/common/arm_console.c \ drivers/arm/pl011/${ARCH}/pl011_console.S \ plat/arm/board/common/${ARCH}/board_arm_helpers.S ifdef ARM_CORTEX_A5 FVP_VE_CPU_LIBS := lib/cpus/aarch32/cortex_a5.S else FVP_VE_CPU_LIBS := lib/cpus/aarch32/cortex_a7.S endif BL1_SOURCES += drivers/arm/sp805/sp805.c \ drivers/io/io_fip.c \ drivers/io/io_memmap.c \ drivers/io/io_storage.c \ plat/arm/common/arm_bl1_setup.c \ plat/arm/common/arm_err.c \ plat/arm/board/fvp_ve/fvp_ve_err.c \ plat/arm/common/arm_io_storage.c \ drivers/cfi/v2m/v2m_flash.c \ plat/arm/board/fvp_ve/${ARCH}/fvp_ve_helpers.S \ plat/arm/board/fvp_ve/fvp_ve_bl1_setup.c \ lib/aarch32/arm32_aeabi_divmod.c \ lib/aarch32/arm32_aeabi_divmod_a32.S \ ${FVP_VE_CPU_LIBS} \ ${DYN_CFG_SOURCES} BL2_SOURCES += plat/arm/board/fvp_ve/fvp_ve_bl2_setup.c \ lib/aarch32/arm32_aeabi_divmod.c \ lib/aarch32/arm32_aeabi_divmod_a32.S \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/cfi/v2m/v2m_flash.c \ drivers/io/io_fip.c \ drivers/io/io_memmap.c \ drivers/io/io_storage.c \ plat/arm/common/arm_bl2_setup.c \ plat/arm/common/arm_err.c \ plat/arm/board/fvp_ve/fvp_ve_err.c \ plat/arm/common/arm_io_storage.c \ plat/arm/common/${ARCH}/arm_bl2_mem_params_desc.c \ plat/arm/common/arm_image_load.c \ common/desc_image_load.c \ ${DYN_CFG_SOURCES} \ ${FVP_VE_SECURITY_SOURCES} # Add the FDT_SOURCES and options for Dynamic Config (only for Unix env) ifdef UNIX_MK FDT_SOURCES += plat/arm/board/fvp_ve/fdts/fvp_ve_tb_fw_config.dts FVP_TB_FW_CONFIG := ${BUILD_PLAT}/fdts/fvp_ve_tb_fw_config.dtb # Add the TB_FW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${FVP_TB_FW_CONFIG},--tb-fw-config)) FDT_SOURCES += ${FVP_HW_CONFIG_DTS} $(eval FVP_HW_CONFIG := ${BUILD_PLAT}/$(patsubst %.dts,%.dtb, \ fdts/$(notdir ${FVP_HW_CONFIG_DTS}))) # Add the HW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${FVP_HW_CONFIG},--hw-config)) endif NEED_BL32 := yes # Modification of arm_common.mk # Process ARM_DISABLE_TRUSTED_WDOG flag # By default, Trusted Watchdog is always enabled unless SPIN_ON_BL1_EXIT is set ARM_DISABLE_TRUSTED_WDOG := 0 ifeq (${SPIN_ON_BL1_EXIT}, 1) ARM_DISABLE_TRUSTED_WDOG := 1 endif $(eval $(call assert_boolean,ARM_DISABLE_TRUSTED_WDOG)) $(eval $(call add_define,ARM_DISABLE_TRUSTED_WDOG)) # Use translation tables library v1 if using Cortex-A5 ifdef ARM_CORTEX_A5 ARM_XLAT_TABLES_LIB_V1 := 1 else ARM_XLAT_TABLES_LIB_V1 := 0 endif $(eval $(call assert_boolean,ARM_XLAT_TABLES_LIB_V1)) $(eval $(call add_define,ARM_XLAT_TABLES_LIB_V1)) ifeq (${ARM_XLAT_TABLES_LIB_V1}, 1) # Only use nonlpae version of xlatv1 otherwise use xlat v2 PLAT_BL_COMMON_SOURCES += lib/xlat_tables/${ARCH}/nonlpae_tables.c else include lib/xlat_tables_v2/xlat_tables.mk PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} endif # Add `libfdt` and Arm common helpers required for Dynamic Config include lib/libfdt/libfdt.mk DYN_CFG_SOURCES += plat/arm/common/arm_dyn_cfg.c \ plat/arm/common/arm_dyn_cfg_helpers.c \ common/fdt_wrappers.c trusted-firmware-a-2.2/plat/arm/board/fvp_ve/sp_min/000077500000000000000000000000001355360272700224715ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/fvp_ve/sp_min/fvp_ve_sp_min_setup.c000066400000000000000000000005601355360272700267100ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { arm_sp_min_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3); } trusted-firmware-a-2.2/plat/arm/board/fvp_ve/sp_min/sp_min-fvp_ve.mk000066400000000000000000000014041355360272700255710ustar00rootroot00000000000000# # Copyright (c) 2019, Arm Limited. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # SP_MIN source files specific to FVP platform BL32_SOURCES += drivers/cfi/v2m/v2m_flash.c \ lib/utils/mem_region.c \ plat/arm/board/fvp_ve/aarch32/fvp_ve_helpers.S \ drivers/arm/fvp/fvp_pwrc.c \ plat/arm/board/fvp_ve/fvp_ve_pm.c \ plat/arm/board/fvp_ve/fvp_ve_topology.c \ plat/arm/board/fvp_ve/sp_min/fvp_ve_sp_min_setup.c \ lib/aarch32/arm32_aeabi_divmod.c \ lib/aarch32/arm32_aeabi_divmod_a32.S \ plat/arm/common/sp_min/arm_sp_min_setup.c \ plat/common/aarch32/platform_mp_stack.S \ plat/common/plat_psci_common.c \ ${FVP_VE_CPU_LIBS} \ ${FVP_VE_GIC_SOURCES} \ ${FVP_VE_SECURITY_SOURCES} trusted-firmware-a-2.2/plat/arm/board/juno/000077500000000000000000000000001355360272700206725ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/juno/aarch32/000077500000000000000000000000001355360272700221155ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/juno/aarch32/juno_helpers.S000066400000000000000000000135451355360272700247460ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include .globl plat_reset_handler .globl plat_arm_calc_core_pos #define JUNO_REVISION(rev) REV_JUNO_R##rev #define JUNO_HANDLER(rev) plat_reset_handler_juno_r##rev #define JUMP_TO_HANDLER_IF_JUNO_R(revision) \ jump_to_handler JUNO_REVISION(revision), JUNO_HANDLER(revision) /* -------------------------------------------------------------------- * Helper macro to jump to the given handler if the board revision * matches. * Expects the Juno board revision in x0. * -------------------------------------------------------------------- */ .macro jump_to_handler _revision, _handler cmp r0, #\_revision beq \_handler .endm /* -------------------------------------------------------------------- * Platform reset handler for Juno R0. * * Juno R0 has the following topology: * - Quad core Cortex-A53 processor cluster; * - Dual core Cortex-A57 processor cluster. * * This handler does the following: * - Implement workaround for defect id 831273 by enabling an event * stream every 65536 cycles. * - Set the L2 Data RAM latency to 2 (i.e. 3 cycles) for Cortex-A57 * - Set the L2 Tag RAM latency to 2 (i.e. 3 cycles) for Cortex-A57 * -------------------------------------------------------------------- */ func JUNO_HANDLER(0) /* -------------------------------------------------------------------- * Enable the event stream every 65536 cycles * -------------------------------------------------------------------- */ mov r0, #(0xf << EVNTI_SHIFT) orr r0, r0, #EVNTEN_BIT stcopr r0, CNTKCTL /* -------------------------------------------------------------------- * Nothing else to do on Cortex-A53. * -------------------------------------------------------------------- */ jump_if_cpu_midr CORTEX_A53_MIDR, 1f /* -------------------------------------------------------------------- * Cortex-A57 specific settings * -------------------------------------------------------------------- */ mov r0, #((CORTEX_A57_L2_DATA_RAM_LATENCY_3_CYCLES << CORTEX_A57_L2CTLR_DATA_RAM_LATENCY_SHIFT) | \ (CORTEX_A57_L2_TAG_RAM_LATENCY_3_CYCLES << CORTEX_A57_L2CTLR_TAG_RAM_LATENCY_SHIFT)) stcopr r0, CORTEX_A57_L2CTLR 1: isb bx lr endfunc JUNO_HANDLER(0) /* -------------------------------------------------------------------- * Platform reset handler for Juno R1. * * Juno R1 has the following topology: * - Quad core Cortex-A53 processor cluster; * - Dual core Cortex-A57 processor cluster. * * This handler does the following: * - Set the L2 Data RAM latency to 2 (i.e. 3 cycles) for Cortex-A57 * * Note that: * - The default value for the L2 Tag RAM latency for Cortex-A57 is * suitable. * - Defect #831273 doesn't affect Juno R1. * -------------------------------------------------------------------- */ func JUNO_HANDLER(1) /* -------------------------------------------------------------------- * Nothing to do on Cortex-A53. * -------------------------------------------------------------------- */ jump_if_cpu_midr CORTEX_A57_MIDR, A57 bx lr A57: /* -------------------------------------------------------------------- * Cortex-A57 specific settings * -------------------------------------------------------------------- */ mov r0, #(CORTEX_A57_L2_DATA_RAM_LATENCY_3_CYCLES << CORTEX_A57_L2CTLR_DATA_RAM_LATENCY_SHIFT) stcopr r0, CORTEX_A57_L2CTLR isb bx lr endfunc JUNO_HANDLER(1) /* -------------------------------------------------------------------- * Platform reset handler for Juno R2. * * Juno R2 has the following topology: * - Quad core Cortex-A53 processor cluster; * - Dual core Cortex-A72 processor cluster. * * This handler does the following: * - Set the L2 Data RAM latency to 2 (i.e. 3 cycles) for Cortex-A72 * - Set the L2 Tag RAM latency to 1 (i.e. 2 cycles) for Cortex-A72 * * Note that: * - Defect #831273 doesn't affect Juno R2. * -------------------------------------------------------------------- */ func JUNO_HANDLER(2) /* -------------------------------------------------------------------- * Nothing to do on Cortex-A53. * -------------------------------------------------------------------- */ jump_if_cpu_midr CORTEX_A72_MIDR, A72 bx lr A72: /* -------------------------------------------------------------------- * Cortex-A72 specific settings * -------------------------------------------------------------------- */ mov r0, #((CORTEX_A72_L2_DATA_RAM_LATENCY_3_CYCLES << CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT) | \ (CORTEX_A72_L2_TAG_RAM_LATENCY_2_CYCLES << CORTEX_A72_L2CTLR_TAG_RAM_LATENCY_SHIFT)) stcopr r0, CORTEX_A72_L2CTLR isb bx lr endfunc JUNO_HANDLER(2) /* -------------------------------------------------------------------- * void plat_reset_handler(void); * * Determine the Juno board revision and call the appropriate reset * handler. * -------------------------------------------------------------------- */ func plat_reset_handler /* Read the V2M SYS_ID register */ ldr r0, =(V2M_SYSREGS_BASE + V2M_SYS_ID) ldr r1, [r0] /* Extract board revision from the SYS_ID */ ubfx r0, r1, #V2M_SYS_ID_REV_SHIFT, #4 JUMP_TO_HANDLER_IF_JUNO_R(0) JUMP_TO_HANDLER_IF_JUNO_R(1) JUMP_TO_HANDLER_IF_JUNO_R(2) /* Board revision is not supported */ no_ret plat_panic_handler endfunc plat_reset_handler /* ----------------------------------------------------- * unsigned int plat_arm_calc_core_pos(u_register_t mpidr) * Helper function to calculate the core position. * ----------------------------------------------------- */ func plat_arm_calc_core_pos b css_calc_core_pos_swap_cluster endfunc plat_arm_calc_core_pos trusted-firmware-a-2.2/plat/arm/board/juno/aarch64/000077500000000000000000000000001355360272700221225ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/juno/aarch64/juno_helpers.S000066400000000000000000000215471355360272700247540ustar00rootroot00000000000000/* * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include .globl plat_reset_handler .globl plat_arm_calc_core_pos #if JUNO_AARCH32_EL3_RUNTIME .globl plat_get_my_entrypoint .globl juno_reset_to_aarch32_state #endif #define JUNO_REVISION(rev) REV_JUNO_R##rev #define JUNO_HANDLER(rev) plat_reset_handler_juno_r##rev #define JUMP_TO_HANDLER_IF_JUNO_R(revision) \ jump_to_handler JUNO_REVISION(revision), JUNO_HANDLER(revision) /* -------------------------------------------------------------------- * Helper macro to jump to the given handler if the board revision * matches. * Expects the Juno board revision in x0. * -------------------------------------------------------------------- */ .macro jump_to_handler _revision, _handler cmp x0, #\_revision b.eq \_handler .endm /* -------------------------------------------------------------------- * Platform reset handler for Juno R0. * * Juno R0 has the following topology: * - Quad core Cortex-A53 processor cluster; * - Dual core Cortex-A57 processor cluster. * * This handler does the following: * - Implement workaround for defect id 831273 by enabling an event * stream every 65536 cycles. * - Set the L2 Data RAM latency to 2 (i.e. 3 cycles) for Cortex-A57 * - Set the L2 Tag RAM latency to 2 (i.e. 3 cycles) for Cortex-A57 * -------------------------------------------------------------------- */ func JUNO_HANDLER(0) /* -------------------------------------------------------------------- * Enable the event stream every 65536 cycles * -------------------------------------------------------------------- */ mov x0, #(0xf << EVNTI_SHIFT) orr x0, x0, #EVNTEN_BIT msr CNTKCTL_EL1, x0 /* -------------------------------------------------------------------- * Nothing else to do on Cortex-A53. * -------------------------------------------------------------------- */ jump_if_cpu_midr CORTEX_A53_MIDR, 1f /* -------------------------------------------------------------------- * Cortex-A57 specific settings * -------------------------------------------------------------------- */ mov x0, #((CORTEX_A57_L2_DATA_RAM_LATENCY_3_CYCLES << CORTEX_A57_L2CTLR_DATA_RAM_LATENCY_SHIFT) | \ (CORTEX_A57_L2_TAG_RAM_LATENCY_3_CYCLES << CORTEX_A57_L2CTLR_TAG_RAM_LATENCY_SHIFT)) msr CORTEX_A57_L2CTLR_EL1, x0 1: isb ret endfunc JUNO_HANDLER(0) /* -------------------------------------------------------------------- * Platform reset handler for Juno R1. * * Juno R1 has the following topology: * - Quad core Cortex-A53 processor cluster; * - Dual core Cortex-A57 processor cluster. * * This handler does the following: * - Set the L2 Data RAM latency to 2 (i.e. 3 cycles) for Cortex-A57 * * Note that: * - The default value for the L2 Tag RAM latency for Cortex-A57 is * suitable. * - Defect #831273 doesn't affect Juno R1. * -------------------------------------------------------------------- */ func JUNO_HANDLER(1) /* -------------------------------------------------------------------- * Nothing to do on Cortex-A53. * -------------------------------------------------------------------- */ jump_if_cpu_midr CORTEX_A57_MIDR, A57 ret A57: /* -------------------------------------------------------------------- * Cortex-A57 specific settings * -------------------------------------------------------------------- */ mov x0, #(CORTEX_A57_L2_DATA_RAM_LATENCY_3_CYCLES << CORTEX_A57_L2CTLR_DATA_RAM_LATENCY_SHIFT) msr CORTEX_A57_L2CTLR_EL1, x0 isb ret endfunc JUNO_HANDLER(1) /* -------------------------------------------------------------------- * Platform reset handler for Juno R2. * * Juno R2 has the following topology: * - Quad core Cortex-A53 processor cluster; * - Dual core Cortex-A72 processor cluster. * * This handler does the following: * - Set the L2 Data RAM latency to 2 (i.e. 3 cycles) for Cortex-A72 * - Set the L2 Tag RAM latency to 1 (i.e. 2 cycles) for Cortex-A72 * * Note that: * - Defect #831273 doesn't affect Juno R2. * -------------------------------------------------------------------- */ func JUNO_HANDLER(2) /* -------------------------------------------------------------------- * Nothing to do on Cortex-A53. * -------------------------------------------------------------------- */ jump_if_cpu_midr CORTEX_A72_MIDR, A72 ret A72: /* -------------------------------------------------------------------- * Cortex-A72 specific settings * -------------------------------------------------------------------- */ mov x0, #((CORTEX_A72_L2_DATA_RAM_LATENCY_3_CYCLES << CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT) | \ (CORTEX_A72_L2_TAG_RAM_LATENCY_2_CYCLES << CORTEX_A72_L2CTLR_TAG_RAM_LATENCY_SHIFT)) msr CORTEX_A57_L2CTLR_EL1, x0 isb ret endfunc JUNO_HANDLER(2) /* -------------------------------------------------------------------- * void plat_reset_handler(void); * * Determine the Juno board revision and call the appropriate reset * handler. * -------------------------------------------------------------------- */ func plat_reset_handler /* Read the V2M SYS_ID register */ mov_imm x0, (V2M_SYSREGS_BASE + V2M_SYS_ID) ldr w1, [x0] /* Extract board revision from the SYS_ID */ ubfx x0, x1, #V2M_SYS_ID_REV_SHIFT, #4 JUMP_TO_HANDLER_IF_JUNO_R(0) JUMP_TO_HANDLER_IF_JUNO_R(1) JUMP_TO_HANDLER_IF_JUNO_R(2) /* Board revision is not supported */ no_ret plat_panic_handler endfunc plat_reset_handler /* ----------------------------------------------------- * void juno_do_reset_to_aarch32_state(void); * * Request warm reset to AArch32 mode. * ----------------------------------------------------- */ func juno_do_reset_to_aarch32_state mov x0, #RMR_EL3_RR_BIT dsb sy msr rmr_el3, x0 isb wfi b plat_panic_handler endfunc juno_do_reset_to_aarch32_state /* ----------------------------------------------------- * unsigned int plat_arm_calc_core_pos(u_register_t mpidr) * Helper function to calculate the core position. * ----------------------------------------------------- */ func plat_arm_calc_core_pos b css_calc_core_pos_swap_cluster endfunc plat_arm_calc_core_pos #if JUNO_AARCH32_EL3_RUNTIME /* --------------------------------------------------------------------- * uintptr_t plat_get_my_entrypoint (void); * * Main job of this routine is to distinguish between a cold and a warm * boot. On JUNO platform, this distinction is based on the contents of * the Trusted Mailbox. It is initialised to zero by the SCP before the * AP cores are released from reset. Therefore, a zero mailbox means * it's a cold reset. If it is a warm boot then a request to reset to * AArch32 state is issued. This is the only way to reset to AArch32 * in EL3 on Juno. A trampoline located at the high vector address * has already been prepared by BL1. * * This functions returns the contents of the mailbox, i.e.: * - 0 for a cold boot; * - request warm reset in AArch32 state for warm boot case; * --------------------------------------------------------------------- */ func plat_get_my_entrypoint mov_imm x0, PLAT_ARM_TRUSTED_MAILBOX_BASE ldr x0, [x0] cbz x0, return b juno_do_reset_to_aarch32_state return: ret endfunc plat_get_my_entrypoint /* * Emit a "movw r0, #imm16" which moves the lower * 16 bits of `_val` into r0. */ .macro emit_movw _reg_d, _val mov_imm \_reg_d, (0xe3000000 | \ ((\_val & 0xfff) | \ ((\_val & 0xf000) << 4))) .endm /* * Emit a "movt r0, #imm16" which moves the upper * 16 bits of `_val` into r0. */ .macro emit_movt _reg_d, _val mov_imm \_reg_d, (0xe3400000 | \ (((\_val & 0x0fff0000) >> 16) | \ ((\_val & 0xf0000000) >> 12))) .endm /* * This function writes the trampoline code at HI-VEC (0xFFFF0000) * address which loads r0 with the entrypoint address for * BL32 (a.k.a SP_MIN) when EL3 is in AArch32 mode. A warm reset * to AArch32 mode is then requested by writing into RMR_EL3. */ func juno_reset_to_aarch32_state /* * Invalidate all caches before the warm reset to AArch32 state. * This is required on the Juno AArch32 boot flow because the L2 * unified cache may contain code and data from when the processor * was still executing in AArch64 state. This code only runs on * the primary core, all other cores are powered down. */ mov x0, #DCISW bl dcsw_op_all emit_movw w0, BL32_BASE emit_movt w1, BL32_BASE /* opcode "bx r0" to branch using r0 in AArch32 mode */ mov_imm w2, 0xe12fff10 /* Write the above opcodes at HI-VECTOR location */ mov_imm x3, HI_VECTOR_BASE str w0, [x3], #4 str w1, [x3], #4 str w2, [x3] b juno_do_reset_to_aarch32_state endfunc juno_reset_to_aarch32_state #endif /* JUNO_AARCH32_EL3_RUNTIME */ trusted-firmware-a-2.2/plat/arm/board/juno/fdts/000077500000000000000000000000001355360272700216325ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/juno/fdts/juno_tb_fw_config.dts000066400000000000000000000013301355360272700260240ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { /* Platform Config */ compatible = "arm,tb_fw"; /* Disable authentication for development */ disable_auth = <0x0>; /* * The following two entries are placeholders for Mbed TLS * heap information. The default values don't matter since * they will be overwritten by BL1. * In case of having shared Mbed TLS heap between BL1 and BL2, * BL1 will populate these two properties with the respective * info about the shared heap. This info will be available for * BL2 in order to locate and re-use the heap. */ mbedtls_heap_addr = <0x0 0x0>; mbedtls_heap_size = <0x0>; }; trusted-firmware-a-2.2/plat/arm/board/juno/include/000077500000000000000000000000001355360272700223155ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/juno/include/plat_macros.S000066400000000000000000000011011355360272700247360ustar00rootroot00000000000000/* * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S #include #include /* --------------------------------------------- * The below required platform porting macro * prints out relevant platform registers * whenever an unhandled exception is taken in * BL31. * --------------------------------------------- */ .macro plat_crash_print_regs css_print_gic_regs print_cci_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/arm/board/juno/include/platform_def.h000066400000000000000000000213571355360272700251400ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #if TRUSTED_BOARD_BOOT #include #endif #include #include #include #include #include #include #include "../juno_def.h" /* Required platform porting definitions */ /* Juno supports system power domain */ #define PLAT_MAX_PWR_LVL ARM_PWR_LVL2 #define PLAT_NUM_PWR_DOMAINS (ARM_SYSTEM_COUNT + \ JUNO_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLATFORM_CORE_COUNT (JUNO_CLUSTER0_CORE_COUNT + \ JUNO_CLUSTER1_CORE_COUNT) /* Cryptocell HW Base address */ #define PLAT_CRYPTOCELL_BASE UL(0x60050000) /* * Other platform porting definitions are provided by included headers */ /* * Required ARM standard platform porting definitions */ #define PLAT_ARM_CLUSTER_COUNT JUNO_CLUSTER_COUNT #define PLAT_ARM_TRUSTED_SRAM_SIZE UL(0x00040000) /* 256 KB */ /* Use the bypass address */ #define PLAT_ARM_TRUSTED_ROM_BASE (V2M_FLASH0_BASE + \ BL1_ROM_BYPASS_OFFSET) #define NSRAM_BASE UL(0x2e000000) #define NSRAM_SIZE UL(0x00008000) /* 32KB */ /* virtual address used by dynamic mem_protect for chunk_base */ #define PLAT_ARM_MEM_PROTEC_VA_FRAME UL(0xc0000000) /* * PLAT_ARM_MAX_ROMLIB_RW_SIZE is define to use a full page */ #if USE_ROMLIB #define PLAT_ARM_MAX_ROMLIB_RW_SIZE UL(0x1000) #define PLAT_ARM_MAX_ROMLIB_RO_SIZE UL(0xe000) #else #define PLAT_ARM_MAX_ROMLIB_RW_SIZE UL(0) #define PLAT_ARM_MAX_ROMLIB_RO_SIZE UL(0) #endif /* * Actual ROM size on Juno is 64 KB, but TBB currently requires at least 80 KB * in debug mode. We can test TBB on Juno bypassing the ROM and using 128 KB of * flash */ #if TRUSTED_BOARD_BOOT #define PLAT_ARM_TRUSTED_ROM_SIZE UL(0x00020000) #else #define PLAT_ARM_TRUSTED_ROM_SIZE UL(0x00010000) #endif /* TRUSTED_BOARD_BOOT */ /* * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the * plat_arm_mmap array defined for each BL stage. */ #ifdef IMAGE_BL1 # define PLAT_ARM_MMAP_ENTRIES 7 # define MAX_XLAT_TABLES 4 #endif #ifdef IMAGE_BL2 #ifdef SPD_opteed # define PLAT_ARM_MMAP_ENTRIES 11 # define MAX_XLAT_TABLES 5 #else # define PLAT_ARM_MMAP_ENTRIES 10 # define MAX_XLAT_TABLES 4 #endif #endif #ifdef IMAGE_BL2U # define PLAT_ARM_MMAP_ENTRIES 5 # define MAX_XLAT_TABLES 3 #endif #ifdef IMAGE_BL31 # define PLAT_ARM_MMAP_ENTRIES 7 # define MAX_XLAT_TABLES 3 #endif #ifdef IMAGE_BL32 # define PLAT_ARM_MMAP_ENTRIES 6 # define MAX_XLAT_TABLES 4 #endif /* * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size * plus a little space for growth. */ #if TRUSTED_BOARD_BOOT # define PLAT_ARM_MAX_BL1_RW_SIZE UL(0xB000) #else # define PLAT_ARM_MAX_BL1_RW_SIZE UL(0x6000) #endif /* * PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a * little space for growth. */ #if TRUSTED_BOARD_BOOT #if TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_RSA_AND_ECDSA # define PLAT_ARM_MAX_BL2_SIZE UL(0x1F000) #elif TF_MBEDTLS_KEY_ALG_ID == TF_MBEDTLS_ECDSA # define PLAT_ARM_MAX_BL2_SIZE UL(0x1D000) #else # define PLAT_ARM_MAX_BL2_SIZE UL(0x1D000) #endif #else # define PLAT_ARM_MAX_BL2_SIZE UL(0xF000) #endif /* * Since BL31 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL31_SIZE is * calculated using the current BL31 PROGBITS debug size plus the sizes of * BL2 and BL1-RW. SCP_BL2 image is loaded into the space BL31 -> BL2_BASE. * Hence the BL31 PROGBITS size should be >= PLAT_CSS_MAX_SCP_BL2_SIZE. */ #define PLAT_ARM_MAX_BL31_SIZE UL(0x3E000) #if JUNO_AARCH32_EL3_RUNTIME /* * Since BL32 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL32_SIZE is * calculated using the current BL32 PROGBITS debug size plus the sizes of * BL2 and BL1-RW. SCP_BL2 image is loaded into the space BL32 -> BL2_BASE. * Hence the BL32 PROGBITS size should be >= PLAT_CSS_MAX_SCP_BL2_SIZE. */ #define PLAT_ARM_MAX_BL32_SIZE UL(0x3E000) #endif /* * Size of cacheable stacks */ #if defined(IMAGE_BL1) # if TRUSTED_BOARD_BOOT # define PLATFORM_STACK_SIZE UL(0x1000) # else # define PLATFORM_STACK_SIZE UL(0x440) # endif #elif defined(IMAGE_BL2) # if TRUSTED_BOARD_BOOT # define PLATFORM_STACK_SIZE UL(0x1000) # else # define PLATFORM_STACK_SIZE UL(0x400) # endif #elif defined(IMAGE_BL2U) # define PLATFORM_STACK_SIZE UL(0x400) #elif defined(IMAGE_BL31) # if PLAT_XLAT_TABLES_DYNAMIC # define PLATFORM_STACK_SIZE UL(0x800) # else # define PLATFORM_STACK_SIZE UL(0x400) # endif #elif defined(IMAGE_BL32) # define PLATFORM_STACK_SIZE UL(0x440) #endif /* * Since free SRAM space is scant, enable the ASSERTION message size * optimization by fixing the PLAT_LOG_LEVEL_ASSERT to LOG_LEVEL_INFO (40). */ #define PLAT_LOG_LEVEL_ASSERT 40 /* CCI related constants */ #define PLAT_ARM_CCI_BASE UL(0x2c090000) #define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX 4 #define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX 3 /* System timer related constants */ #define PLAT_ARM_NSTIMER_FRAME_ID U(1) /* TZC related constants */ #define PLAT_ARM_TZC_BASE UL(0x2a4a0000) #define PLAT_ARM_TZC_NS_DEV_ACCESS ( \ TZC_REGION_ACCESS_RDWR(TZC400_NSAID_CCI400) | \ TZC_REGION_ACCESS_RDWR(TZC400_NSAID_PCIE) | \ TZC_REGION_ACCESS_RDWR(TZC400_NSAID_HDLCD0) | \ TZC_REGION_ACCESS_RDWR(TZC400_NSAID_HDLCD1) | \ TZC_REGION_ACCESS_RDWR(TZC400_NSAID_USB) | \ TZC_REGION_ACCESS_RDWR(TZC400_NSAID_DMA330) | \ TZC_REGION_ACCESS_RDWR(TZC400_NSAID_THINLINKS) | \ TZC_REGION_ACCESS_RDWR(TZC400_NSAID_AP) | \ TZC_REGION_ACCESS_RDWR(TZC400_NSAID_GPU) | \ TZC_REGION_ACCESS_RDWR(TZC400_NSAID_CORESIGHT)) /* * Required ARM CSS based platform porting definitions */ /* GIC related constants (no GICR in GIC-400) */ #define PLAT_ARM_GICD_BASE UL(0x2c010000) #define PLAT_ARM_GICC_BASE UL(0x2c02f000) #define PLAT_ARM_GICH_BASE UL(0x2c04f000) #define PLAT_ARM_GICV_BASE UL(0x2c06f000) /* MHU related constants */ #define PLAT_CSS_MHU_BASE UL(0x2b1f0000) #define PLAT_MHUV2_BASE PLAT_CSS_MHU_BASE /* * Base address of the first memory region used for communication between AP * and SCP. Used by the BOM and SCPI protocols. */ #if !CSS_USE_SCMI_SDS_DRIVER /* * Note that this is located at the same address as SCP_BOOT_CFG_ADDR, which * means the SCP/AP configuration data gets overwritten when the AP initiates * communication with the SCP. The configuration data is expected to be a * 32-bit word on all CSS platforms. On Juno, part of this configuration is * which CPU is the primary, according to the shift and mask definitions below. */ #define PLAT_CSS_SCP_COM_SHARED_MEM_BASE (ARM_TRUSTED_SRAM_BASE + UL(0x80)) #define PLAT_CSS_PRIMARY_CPU_SHIFT 8 #define PLAT_CSS_PRIMARY_CPU_BIT_WIDTH 4 #endif /* * PLAT_CSS_MAX_SCP_BL2_SIZE is calculated using the current * SCP_BL2 size plus a little space for growth. */ #define PLAT_CSS_MAX_SCP_BL2_SIZE UL(0x14000) /* * PLAT_CSS_MAX_SCP_BL2U_SIZE is calculated using the current * SCP_BL2U size plus a little space for growth. */ #define PLAT_CSS_MAX_SCP_BL2U_SIZE UL(0x14000) #define PLAT_ARM_G1S_IRQ_PROPS(grp) \ CSS_G1S_IRQ_PROPS(grp), \ ARM_G1S_IRQ_PROPS(grp), \ INTR_PROP_DESC(JUNO_IRQ_DMA_SMMU, GIC_HIGHEST_SEC_PRIORITY, \ (grp), GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(JUNO_IRQ_HDLCD0_SMMU, GIC_HIGHEST_SEC_PRIORITY, \ (grp), GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(JUNO_IRQ_HDLCD1_SMMU, GIC_HIGHEST_SEC_PRIORITY, \ (grp), GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(JUNO_IRQ_USB_SMMU, GIC_HIGHEST_SEC_PRIORITY, \ (grp), GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(JUNO_IRQ_THIN_LINKS_SMMU, GIC_HIGHEST_SEC_PRIORITY, \ (grp), GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(JUNO_IRQ_SEC_I2C, GIC_HIGHEST_SEC_PRIORITY, \ (grp), GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(JUNO_IRQ_GPU_SMMU_1, GIC_HIGHEST_SEC_PRIORITY, \ (grp), GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(JUNO_IRQ_ETR_SMMU, GIC_HIGHEST_SEC_PRIORITY, \ (grp), GIC_INTR_CFG_LEVEL) #define PLAT_ARM_G0_IRQ_PROPS(grp) ARM_G0_IRQ_PROPS(grp) /* * Required ARM CSS SoC based platform porting definitions */ /* CSS SoC NIC-400 Global Programmers View (GPV) */ #define PLAT_SOC_CSS_NIC400_BASE UL(0x2a000000) #define PLAT_ARM_PRIVATE_SDEI_EVENTS ARM_SDEI_PRIVATE_EVENTS #define PLAT_ARM_SHARED_SDEI_EVENTS ARM_SDEI_SHARED_EVENTS /* System power domain level */ #define CSS_SYSTEM_PWR_DMN_LVL ARM_PWR_LVL2 /* * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes */ #ifdef __aarch64__ #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 36) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 36) #else #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #endif #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/arm/board/juno/jmptbl.i000066400000000000000000000024421355360272700223360ustar00rootroot00000000000000# # Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Platform specific romlib functions can be added or included here. # The index in the output file will be generated cumulatively in the same # order as it is given in this file. # Output file can be found at: $BUILD_DIR/jmptbl.i # # Format: # lib function [patch] # Example: # rom rom_lib_init # fdt fdt_getprop_namelen patch rom rom_lib_init fdt fdt_getprop_namelen fdt fdt_setprop_inplace fdt fdt_check_header fdt fdt_node_offset_by_compatible mbedtls mbedtls_asn1_get_alg mbedtls mbedtls_asn1_get_alg_null mbedtls mbedtls_asn1_get_bitstring_null mbedtls mbedtls_asn1_get_bool mbedtls mbedtls_asn1_get_int mbedtls mbedtls_asn1_get_tag mbedtls mbedtls_free mbedtls mbedtls_md mbedtls mbedtls_md_get_size mbedtls mbedtls_memory_buffer_alloc_init mbedtls mbedtls_oid_get_md_alg mbedtls mbedtls_oid_get_numeric_string mbedtls mbedtls_oid_get_pk_alg mbedtls mbedtls_oid_get_sig_alg mbedtls mbedtls_pk_free mbedtls mbedtls_pk_init mbedtls mbedtls_pk_parse_subpubkey mbedtls mbedtls_pk_verify_ext mbedtls mbedtls_platform_set_snprintf mbedtls mbedtls_x509_get_rsassa_pss_params mbedtls mbedtls_x509_get_sig_alg mbedtls mbedtls_md_info_from_type c exit c atexit trusted-firmware-a-2.2/plat/arm/board/juno/juno_bl1_setup.c000066400000000000000000000067141355360272700237770ustar00rootroot00000000000000/* * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include void juno_reset_to_aarch32_state(void); static int is_watchdog_reset(void) { #if !CSS_USE_SCMI_SDS_DRIVER #define RESET_REASON_WDOG_RESET (0x2) const uint32_t *reset_flags_ptr = (const uint32_t *)SSC_GPRETN; if ((*reset_flags_ptr & RESET_REASON_WDOG_RESET) != 0) return 1; return 0; #else int ret; uint32_t scp_reset_synd_flags; ret = sds_init(); if (ret != SDS_OK) { ERROR("SCP SDS initialization failed\n"); panic(); } ret = sds_struct_read(SDS_RESET_SYNDROME_STRUCT_ID, SDS_RESET_SYNDROME_OFFSET, &scp_reset_synd_flags, SDS_RESET_SYNDROME_SIZE, SDS_ACCESS_MODE_NON_CACHED); if (ret != SDS_OK) { ERROR("Getting reset reason from SDS failed\n"); panic(); } /* Check if the WATCHDOG_RESET_BIT is set in the reset syndrome */ if (scp_reset_synd_flags & SDS_RESET_SYNDROME_AP_WD_RESET_BIT) return 1; return 0; #endif } /******************************************************************************* * The following function checks if Firmware update is needed, * by checking if TOC in FIP image is valid or watchdog reset happened. ******************************************************************************/ int plat_arm_bl1_fwu_needed(void) { const int32_t *nv_flags_ptr = (const int32_t *)V2M_SYS_NVFLAGS_ADDR; /* Check if TOC is invalid or watchdog reset happened. */ if ((arm_io_is_toc_valid() != 1) || (((*nv_flags_ptr == -EAUTH) || (*nv_flags_ptr == -ENOENT)) && is_watchdog_reset())) return 1; return 0; } /******************************************************************************* * On JUNO update the arg2 with address of SCP_BL2U image info. ******************************************************************************/ void bl1_plat_set_ep_info(unsigned int image_id, entry_point_info_t *ep_info) { if (image_id == BL2U_IMAGE_ID) { image_desc_t *image_desc = bl1_plat_get_image_desc(SCP_BL2U_IMAGE_ID); ep_info->args.arg2 = (unsigned long)&image_desc->image_info; } } /******************************************************************************* * On Juno clear SYS_NVFLAGS and wait for watchdog reset. ******************************************************************************/ __dead2 void bl1_plat_fwu_done(void *client_cookie, void *reserved) { unsigned int *nv_flags_clr = (unsigned int *) (V2M_SYSREGS_BASE + V2M_SYS_NVFLAGSCLR); unsigned int *nv_flags_ptr = (unsigned int *) (V2M_SYSREGS_BASE + V2M_SYS_NVFLAGS); /* Clear the NV flags register. */ *nv_flags_clr = *nv_flags_ptr; /* Setup the watchdog to reset the system as soon as possible */ sp805_refresh(ARM_SP805_TWDG_BASE, 1U); while (1) wfi(); } #if JUNO_AARCH32_EL3_RUNTIME void bl1_plat_prepare_exit(entry_point_info_t *ep_info) { #if !ARM_DISABLE_TRUSTED_WDOG /* Disable watchdog before leaving BL1 */ sp805_stop(ARM_SP805_TWDG_BASE); #endif juno_reset_to_aarch32_state(); } #endif /* JUNO_AARCH32_EL3_RUNTIME */ void plat_arm_secure_wdt_start(void) { sp805_start(ARM_SP805_TWDG_BASE, ARM_TWDG_LOAD_VAL); } void plat_arm_secure_wdt_stop(void) { sp805_stop(ARM_SP805_TWDG_BASE); } trusted-firmware-a-2.2/plat/arm/board/juno/juno_bl2_setup.c000066400000000000000000000021311355360272700237650ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #if JUNO_AARCH32_EL3_RUNTIME /******************************************************************************* * This function changes the spsr for BL32 image to bypass * the check in BL1 AArch64 exception handler. This is needed in the aarch32 * boot flow as the core comes up in aarch64 and to enter the BL32 image a warm * reset in aarch32 state is required. ******************************************************************************/ int arm_bl2_plat_handle_post_image_load(unsigned int image_id) { int err = arm_bl2_handle_post_image_load(image_id); if (!err && (image_id == BL32_IMAGE_ID)) { bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id); assert(bl_mem_params); bl_mem_params->ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); } return err; } #endif /* JUNO_AARCH32_EL3_RUNTIME */ trusted-firmware-a-2.2/plat/arm/board/juno/juno_common.c000066400000000000000000000033311355360272700233610ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /* * Table of memory regions for different BL stages to map using the MMU. * This doesn't include Trusted SRAM as setup_page_tables() already takes care * of mapping it. */ #ifdef IMAGE_BL1 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, V2M_MAP_FLASH0_RW, V2M_MAP_IOFPGA, CSS_MAP_DEVICE, SOC_CSS_MAP_DEVICE, #if TRUSTED_BOARD_BOOT /* Map DRAM to authenticate NS_BL2U image. */ ARM_MAP_NS_DRAM1, #endif {0} }; #endif #ifdef IMAGE_BL2 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, V2M_MAP_FLASH0_RW, #ifdef PLAT_ARM_MEM_PROT_ADDR ARM_V2M_MAP_MEM_PROTECT, #endif V2M_MAP_IOFPGA, CSS_MAP_DEVICE, SOC_CSS_MAP_DEVICE, ARM_MAP_NS_DRAM1, #ifdef __aarch64__ ARM_MAP_DRAM2, #endif #ifdef SPD_tspd ARM_MAP_TSP_SEC_MEM, #endif #ifdef SPD_opteed ARM_MAP_OPTEE_CORE_MEM, ARM_OPTEE_PAGEABLE_LOAD_MEM, #endif #if TRUSTED_BOARD_BOOT && !BL2_AT_EL3 ARM_MAP_BL1_RW, #endif {0} }; #endif #ifdef IMAGE_BL2U const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, CSS_MAP_DEVICE, CSS_MAP_SCP_BL2U, V2M_MAP_IOFPGA, SOC_CSS_MAP_DEVICE, {0} }; #endif #ifdef IMAGE_BL31 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, V2M_MAP_IOFPGA, CSS_MAP_DEVICE, #ifdef PLAT_ARM_MEM_PROT_ADDR ARM_V2M_MAP_MEM_PROTECT, #endif SOC_CSS_MAP_DEVICE, {0} }; #endif #ifdef IMAGE_BL32 const mmap_region_t plat_arm_mmap[] = { #ifndef __aarch64__ ARM_MAP_SHARED_RAM, #ifdef PLAT_ARM_MEM_PROT_ADDR ARM_V2M_MAP_MEM_PROTECT, #endif #endif V2M_MAP_IOFPGA, CSS_MAP_DEVICE, SOC_CSS_MAP_DEVICE, {0} }; #endif ARM_CASSERT_MMAP trusted-firmware-a-2.2/plat/arm/board/juno/juno_decl.h000066400000000000000000000003551355360272700230100ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef JUNO_DECL_H #define JUNO_DECL_H int juno_getentropy(void *buf, size_t len); #endif /* JUNO_DECL_H */ trusted-firmware-a-2.2/plat/arm/board/juno/juno_def.h000066400000000000000000000065401355360272700226410ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef JUNO_DEF_H #define JUNO_DEF_H #include /******************************************************************************* * Juno memory map related constants ******************************************************************************/ /* Board revisions */ #define REV_JUNO_R0 U(0x1) /* Rev B */ #define REV_JUNO_R1 U(0x2) /* Rev C */ #define REV_JUNO_R2 U(0x3) /* Rev D */ /* Bypass offset from start of NOR flash */ #define BL1_ROM_BYPASS_OFFSET UL(0x03EC0000) #define EMMC_BASE UL(0x0c000000) #define EMMC_SIZE UL(0x04000000) #define PSRAM_BASE UL(0x14000000) #define PSRAM_SIZE UL(0x02000000) #define JUNO_SSC_VER_PART_NUM U(0x030) /******************************************************************************* * Juno topology related constants ******************************************************************************/ #define JUNO_CLUSTER_COUNT 2 #define JUNO_CLUSTER0_CORE_COUNT 2 #define JUNO_CLUSTER1_CORE_COUNT 4 /******************************************************************************* * TZC-400 related constants ******************************************************************************/ #define TZC400_NSAID_CCI400 0 /* Note: Same as default NSAID!! */ #define TZC400_NSAID_PCIE 1 #define TZC400_NSAID_HDLCD0 2 #define TZC400_NSAID_HDLCD1 3 #define TZC400_NSAID_USB 4 #define TZC400_NSAID_DMA330 5 #define TZC400_NSAID_THINLINKS 6 #define TZC400_NSAID_AP 9 #define TZC400_NSAID_GPU 10 #define TZC400_NSAID_SCP 11 #define TZC400_NSAID_CORESIGHT 12 /******************************************************************************* * TRNG related constants ******************************************************************************/ #define TRNG_BASE UL(0x7FE60000) #define TRNG_NOUTPUTS 4 #define TRNG_STATUS UL(0x10) #define TRNG_INTMASK UL(0x14) #define TRNG_CONFIG UL(0x18) #define TRNG_CONTROL UL(0x1C) #define TRNG_NBYTES 16 /* Number of bytes generated per round. */ /******************************************************************************* * MMU-401 related constants ******************************************************************************/ #define MMU401_SSD_OFFSET UL(0x4000) #define MMU401_DMA330_BASE UL(0x7fb00000) /******************************************************************************* * Interrupt handling constants ******************************************************************************/ #define JUNO_IRQ_DMA_SMMU 126 #define JUNO_IRQ_HDLCD0_SMMU 128 #define JUNO_IRQ_HDLCD1_SMMU 130 #define JUNO_IRQ_USB_SMMU 132 #define JUNO_IRQ_THIN_LINKS_SMMU 134 #define JUNO_IRQ_SEC_I2C 137 #define JUNO_IRQ_GPU_SMMU_1 73 #define JUNO_IRQ_ETR_SMMU 75 /******************************************************************************* * Memprotect definitions ******************************************************************************/ /* PSCI memory protect definitions: * This variable is stored in a non-secure flash because some ARM reference * platforms do not have secure NVRAM. Real systems that provided MEM_PROTECT * support must use a secure NVRAM to store the PSCI MEM_PROTECT definitions. */ #define PLAT_ARM_MEM_PROT_ADDR (V2M_FLASH0_BASE + \ V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE) #endif /* JUNO_DEF_H */ trusted-firmware-a-2.2/plat/arm/board/juno/juno_err.c000066400000000000000000000012051355360272700226570ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* * Juno error handler */ void __dead2 plat_arm_error_handler(int err) { uint32_t *flags_ptr = (uint32_t *)V2M_SYS_NVFLAGS_ADDR; /* Propagate the err code in the NV-flags register */ *flags_ptr = err; /* Setup the watchdog to reset the system as soon as possible */ sp805_refresh(ARM_SP805_TWDG_BASE, 1U); for (;;) wfi(); } trusted-firmware-a-2.2/plat/arm/board/juno/juno_pm.c000066400000000000000000000006261355360272700225110ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops) { #if CSS_USE_SCMI_SDS_DRIVER return css_scmi_override_pm_ops(ops); #else return ops; #endif /* CSS_USE_SCMI_SDS_DRIVER */ } trusted-firmware-a-2.2/plat/arm/board/juno/juno_security.c000066400000000000000000000131071355360272700237420ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include "juno_tzmp1_def.h" #ifdef JUNO_TZMP1 /* * Protect buffer for VPU/GPU/DPU memory usage with hardware protection * enabled. Propose 224MB video output, 96 MB video input and 32MB video * private. * * Ind Memory Range Caption S_ATTR NS_ATTR * 1 0x080000000 - 0x0E7FFFFFF ARM_NS_DRAM1 NONE RDWR | MEDIA_RW * 2 0x0E8000000 - 0x0F5FFFFFF JUNO_MEDIA_TZC_PROT_DRAM1 NONE MEDIA_RW | AP_WR * 3 0x0F6000000 - 0x0FBFFFFFF JUNO_VPU_TZC_PROT_DRAM1 RDWR VPU_PROT_RW * 4 0x0FC000000 - 0x0FDFFFFFF JUNO_VPU_TZC_PRIV_DRAM1 RDWR VPU_PRIV_RW * 5 0x0FE000000 - 0x0FEFFFFFF JUNO_AP_TZC_SHARE_DRAM1 NONE RDWR | MEDIA_RW * 6 0x0FF000000 - 0x0FFFFFFFF ARM_AP_TZC_DRAM1 RDWR NONE * 7 0x880000000 - 0x9FFFFFFFF ARM_DRAM2 NONE RDWR | MEDIA_RW * * Memory regions are neighbored to save limited TZC regions. Calculation * started from ARM_TZC_SHARE_DRAM1 since it is known and fixed for both * protected-enabled and protected-disabled settings. * * Video private buffer aheads of ARM_TZC_SHARE_DRAM1 */ static const arm_tzc_regions_info_t juno_tzmp1_tzc_regions[] = { {ARM_AP_TZC_DRAM1_BASE, ARM_AP_TZC_DRAM1_END, TZC_REGION_S_RDWR, 0}, {JUNO_NS_DRAM1_PT1_BASE, JUNO_NS_DRAM1_PT1_END, TZC_REGION_S_NONE, JUNO_MEDIA_TZC_NS_DEV_ACCESS}, {JUNO_MEDIA_TZC_PROT_DRAM1_BASE, JUNO_MEDIA_TZC_PROT_DRAM1_END, TZC_REGION_S_NONE, JUNO_MEDIA_TZC_PROT_ACCESS}, {JUNO_VPU_TZC_PROT_DRAM1_BASE, JUNO_VPU_TZC_PROT_DRAM1_END, TZC_REGION_S_RDWR, JUNO_VPU_TZC_PROT_ACCESS}, {JUNO_VPU_TZC_PRIV_DRAM1_BASE, JUNO_VPU_TZC_PRIV_DRAM1_END, TZC_REGION_S_RDWR, JUNO_VPU_TZC_PRIV_ACCESS}, {JUNO_AP_TZC_SHARE_DRAM1_BASE, JUNO_AP_TZC_SHARE_DRAM1_END, TZC_REGION_S_NONE, JUNO_MEDIA_TZC_NS_DEV_ACCESS}, {ARM_DRAM2_BASE, ARM_DRAM2_END, TZC_REGION_S_NONE, JUNO_MEDIA_TZC_NS_DEV_ACCESS}, {}, }; /******************************************************************************* * Program dp650 to configure NSAID value for protected mode. ******************************************************************************/ static void init_dp650(void) { mmio_write_32(DP650_BASE + DP650_PROT_NSAID_OFFSET, DP650_PROT_NSAID_CONFIG); } /******************************************************************************* * Program v550 to configure NSAID value for protected mode. ******************************************************************************/ static void init_v550(void) { /* * bits[31:28] is for PRIVATE, * bits[27:24] is for OUTBUF, * bits[23:20] is for PROTECTED. */ mmio_write_32(V550_BASE + V550_PROTCTRL_OFFSET, V550_PROTCTRL_CONFIG); } #endif /* JUNO_TZMP1 */ /******************************************************************************* * Set up the MMU-401 SSD tables. The power-on configuration has all stream IDs * assigned to Non-Secure except some for the DMA-330. Assign those back to the * Non-Secure world as well, otherwise EL1 may end up erroneously generating * (untranslated) Secure transactions if it turns the SMMU on. ******************************************************************************/ static void init_mmu401(void) { uint32_t reg = mmio_read_32(MMU401_DMA330_BASE + MMU401_SSD_OFFSET); reg |= 0x1FF; mmio_write_32(MMU401_DMA330_BASE + MMU401_SSD_OFFSET, reg); } /******************************************************************************* * Program CSS-NIC400 to allow non-secure access to some CSS regions. ******************************************************************************/ static void css_init_nic400(void) { /* Note: This is the NIC-400 device on the CSS */ mmio_write_32(PLAT_SOC_CSS_NIC400_BASE + NIC400_ADDR_CTRL_SECURITY_REG(CSS_NIC400_SLAVE_BOOTSECURE), ~0); } /******************************************************************************* * Initialize debug configuration. ******************************************************************************/ static void init_debug_cfg(void) { #if !DEBUG /* Set internal drive selection for SPIDEN. */ mmio_write_32(SSC_REG_BASE + SSC_DBGCFG_SET, 1U << SPIDEN_SEL_SET_SHIFT); /* Drive SPIDEN LOW to disable invasive debug of secure state. */ mmio_write_32(SSC_REG_BASE + SSC_DBGCFG_CLR, 1U << SPIDEN_INT_CLR_SHIFT); #endif } /******************************************************************************* * Initialize the secure environment. ******************************************************************************/ void plat_arm_security_setup(void) { /* Initialize debug configuration */ init_debug_cfg(); /* Initialize the TrustZone Controller */ #ifdef JUNO_TZMP1 arm_tzc400_setup(juno_tzmp1_tzc_regions); INFO("TZC protected shared memory base address for TZMP usecase: %p\n", (void *)JUNO_AP_TZC_SHARE_DRAM1_BASE); INFO("TZC protected shared memory end address for TZMP usecase: %p\n", (void *)JUNO_AP_TZC_SHARE_DRAM1_END); #else arm_tzc400_setup(NULL); #endif /* Do ARM CSS internal NIC setup */ css_init_nic400(); /* Do ARM CSS SoC security setup */ soc_css_security_setup(); /* Initialize the SMMU SSD tables */ init_mmu401(); #ifdef JUNO_TZMP1 init_dp650(); init_v550(); #endif } #if TRUSTED_BOARD_BOOT int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size) { assert(heap_addr != NULL); assert(heap_size != NULL); return arm_get_mbedtls_heap(heap_addr, heap_size); } #endif trusted-firmware-a-2.2/plat/arm/board/juno/juno_stack_protector.c000066400000000000000000000012611355360272700252770ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "juno_decl.h" u_register_t plat_get_stack_protector_canary(void) { u_register_t c[TRNG_NBYTES / sizeof(u_register_t)]; u_register_t ret = 0; size_t i; if (juno_getentropy(c, sizeof(c)) != 0) { ERROR("Not enough entropy to initialize canary value\n"); panic(); } /* * On Juno we get 128-bits of entropy in one round. * Fuse the values together to form the canary. */ for (i = 0; i < ARRAY_SIZE(c); i++) ret ^= c[i]; return ret; } trusted-firmware-a-2.2/plat/arm/board/juno/juno_topology.c000066400000000000000000000051651355360272700237540ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #if CSS_USE_SCMI_SDS_DRIVER static scmi_channel_plat_info_t juno_scmi_plat_info = { .scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE, .db_reg_addr = PLAT_CSS_MHU_BASE + CSS_SCMI_MHU_DB_REG_OFF, .db_preserve_mask = 0xfffffffe, .db_modify_mask = 0x1, .ring_doorbell = &mhu_ring_doorbell, }; scmi_channel_plat_info_t *plat_css_get_scmi_info(void) { return &juno_scmi_plat_info; } #endif /* * On Juno, the system power level is the highest power level. * The first entry in the power domain descriptor specifies the * number of system power domains i.e. 1. */ #define JUNO_PWR_DOMAINS_AT_MAX_PWR_LVL ARM_SYSTEM_COUNT /* * The Juno power domain tree descriptor. The cluster power domains * are arranged so that when the PSCI generic code creates the power * domain tree, the indices of the CPU power domain nodes it allocates * match the linear indices returned by plat_core_pos_by_mpidr() * i.e. CLUSTER1 CPUs are allocated indices from 0 to 3 and the higher * indices for CLUSTER0 CPUs. */ static const unsigned char juno_power_domain_tree_desc[] = { /* No of root nodes */ JUNO_PWR_DOMAINS_AT_MAX_PWR_LVL, /* No of children for the root node */ JUNO_CLUSTER_COUNT, /* No of children for the first cluster node */ JUNO_CLUSTER1_CORE_COUNT, /* No of children for the second cluster node */ JUNO_CLUSTER0_CORE_COUNT }; /******************************************************************************* * This function returns the Juno topology tree information. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { return juno_power_domain_tree_desc; } /******************************************************************************* * This function returns the core count within the cluster corresponding to * `mpidr`. ******************************************************************************/ unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr) { return (((mpidr & (u_register_t) 0x100) != 0U) ? JUNO_CLUSTER1_CORE_COUNT : JUNO_CLUSTER0_CORE_COUNT); } /* * The array mapping platform core position (implemented by plat_my_core_pos()) * to the SCMI power domain ID implemented by SCP. */ const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[PLATFORM_CORE_COUNT] = { 2, 3, 4, 5, 0, 1 }; trusted-firmware-a-2.2/plat/arm/board/juno/juno_trng.c000066400000000000000000000032231355360272700230430ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "juno_decl.h" #define NSAMPLE_CLOCKS 1 /* min 1 cycle, max 231 cycles */ #define NRETRIES 5 static inline int output_valid(void) { int i; for (i = 0; i < NRETRIES; i++) { uint32_t val; val = mmio_read_32(TRNG_BASE + TRNG_STATUS); if (val & 1U) break; } if (i >= NRETRIES) return 0; /* No output data available. */ return 1; } /* * This function fills `buf` with `len` bytes of entropy. * It uses the Trusted Entropy Source peripheral on Juno. * Returns 0 when the buffer has been filled with entropy * successfully and -1 otherwise. */ int juno_getentropy(void *buf, size_t len) { uint8_t *bp = buf; assert(buf); assert(len); assert(!check_uptr_overflow((uintptr_t)bp, len)); /* Disable interrupt mode. */ mmio_write_32(TRNG_BASE + TRNG_INTMASK, 0); /* Program TRNG to sample for `NSAMPLE_CLOCKS`. */ mmio_write_32(TRNG_BASE + TRNG_CONFIG, NSAMPLE_CLOCKS); while (len > 0) { int i; /* Start TRNG. */ mmio_write_32(TRNG_BASE + TRNG_CONTROL, 1); /* Check if output is valid. */ if (!output_valid()) return -1; /* Fill entropy buffer. */ for (i = 0; i < TRNG_NOUTPUTS; i++) { size_t n; uint32_t val; val = mmio_read_32(TRNG_BASE + i * sizeof(uint32_t)); n = MIN(len, sizeof(uint32_t)); memcpy(bp, &val, n); bp += n; len -= n; if (len == 0) break; } /* Reset TRNG outputs. */ mmio_write_32(TRNG_BASE + TRNG_STATUS, 1); } return 0; } trusted-firmware-a-2.2/plat/arm/board/juno/juno_tzmp1_def.h000066400000000000000000000063251355360272700237750ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef JUNO_TZMP1_DEF_H #define JUNO_TZMP1_DEF_H /* * Public memory regions for both protected and non-protected mode * * OPTEE shared memory 0xFEE00000 - 0xFEFFFFFF */ #define JUNO_AP_TZC_SHARE_DRAM1_SIZE ULL(0x02000000) #define JUNO_AP_TZC_SHARE_DRAM1_BASE (ARM_AP_TZC_DRAM1_BASE - \ JUNO_AP_TZC_SHARE_DRAM1_SIZE) #define JUNO_AP_TZC_SHARE_DRAM1_END (ARM_AP_TZC_DRAM1_BASE - 1) /* ARM_MEDIA_FEATURES for MEDIA GPU Protect Mode Test */ #define JUNO_TZC400_NSAID_FPGA_MEDIA_SECURE 8 /* GPU/DPU protected, VPU outbuf */ #define JUNO_TZC400_NSAID_FPGA_VIDEO_PROTECTED 7 /* VPU protected */ #define JUNO_TZC400_NSAID_FPGA_VIDEO_PRIVATE 10 /* VPU private (firmware) */ #define JUNO_VPU_TZC_PRIV_DRAM1_SIZE ULL(0x02000000) #define JUNO_VPU_TZC_PRIV_DRAM1_BASE (JUNO_AP_TZC_SHARE_DRAM1_BASE - \ JUNO_VPU_TZC_PRIV_DRAM1_SIZE) #define JUNO_VPU_TZC_PRIV_DRAM1_END (JUNO_AP_TZC_SHARE_DRAM1_BASE - 1) /* Video input protected buffer follows upper item */ #define JUNO_VPU_TZC_PROT_DRAM1_SIZE ULL(0x06000000) #define JUNO_VPU_TZC_PROT_DRAM1_BASE (JUNO_VPU_TZC_PRIV_DRAM1_BASE - \ JUNO_VPU_TZC_PROT_DRAM1_SIZE) #define JUNO_VPU_TZC_PROT_DRAM1_END (JUNO_VPU_TZC_PRIV_DRAM1_BASE - 1) /* Video, graphics and display shares same NSAID and same protected buffer */ #define JUNO_MEDIA_TZC_PROT_DRAM1_SIZE ULL(0x0e000000) #define JUNO_MEDIA_TZC_PROT_DRAM1_BASE (JUNO_VPU_TZC_PROT_DRAM1_BASE - \ JUNO_MEDIA_TZC_PROT_DRAM1_SIZE) #define JUNO_MEDIA_TZC_PROT_DRAM1_END (JUNO_VPU_TZC_PROT_DRAM1_BASE - 1) /* Rest of DRAM1 are Non-Secure public buffer */ #define JUNO_NS_DRAM1_PT1_BASE ARM_DRAM1_BASE #define JUNO_NS_DRAM1_PT1_END (JUNO_MEDIA_TZC_PROT_DRAM1_BASE - 1) #define JUNO_NS_DRAM1_PT1_SIZE (JUNO_NS_DRAM1_PT1_END - \ JUNO_NS_DRAM1_PT1_BASE + 1) /* TZC filter flags */ #define JUNO_MEDIA_TZC_NS_DEV_ACCESS (PLAT_ARM_TZC_NS_DEV_ACCESS | \ TZC_REGION_ACCESS_RD(JUNO_TZC400_NSAID_FPGA_MEDIA_SECURE)) /* VPU / GPU /DPU protected access */ #define JUNO_MEDIA_TZC_PROT_ACCESS \ (TZC_REGION_ACCESS_RDWR(JUNO_TZC400_NSAID_FPGA_MEDIA_SECURE) | \ TZC_REGION_ACCESS_WR(TZC400_NSAID_AP)) #define JUNO_VPU_TZC_PROT_ACCESS \ (TZC_REGION_ACCESS_RDWR(JUNO_TZC400_NSAID_FPGA_VIDEO_PROTECTED)) #define JUNO_VPU_TZC_PRIV_ACCESS \ (TZC_REGION_ACCESS_RDWR(JUNO_TZC400_NSAID_FPGA_VIDEO_PRIVATE)) /******************************************************************************* * Mali-DP650 related constants ******************************************************************************/ /* Base address of DP650 */ #define DP650_BASE 0x6f200000 /* offset to PROT_NSAID register */ #define DP650_PROT_NSAID_OFFSET 0x10004 /* config to PROT_NSAID register */ #define DP650_PROT_NSAID_CONFIG 0x08008888 /******************************************************************************* * Mali-V550 related constants ******************************************************************************/ /* Base address of V550 */ #define V550_BASE 0x6f030000 /* offset to PROTCTRL register */ #define V550_PROTCTRL_OFFSET 0x0040 /* config to PROTCTRL register */ #define V550_PROTCTRL_CONFIG 0xa8700000 #endif /* JUNO_TZMP1_DEF_H */ trusted-firmware-a-2.2/plat/arm/board/juno/platform.mk000066400000000000000000000112031355360272700230440ustar00rootroot00000000000000# # Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # JUNO_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c \ plat/arm/common/arm_gicv2.c JUNO_INTERCONNECT_SOURCES := drivers/arm/cci/cci.c \ plat/arm/common/arm_cci.c JUNO_SECURITY_SOURCES := drivers/arm/tzc/tzc400.c \ plat/arm/board/juno/juno_security.c \ plat/arm/board/juno/juno_trng.c \ plat/arm/common/arm_tzc400.c ifneq (${ENABLE_STACK_PROTECTOR}, 0) JUNO_SECURITY_SOURCES += plat/arm/board/juno/juno_stack_protector.c endif # Select SCMI/SDS drivers instead of SCPI/BOM driver for communicating with the # SCP during power management operations and for SCP RAM Firmware transfer. CSS_USE_SCMI_SDS_DRIVER := 1 PLAT_INCLUDES := -Iplat/arm/board/juno/include PLAT_BL_COMMON_SOURCES := plat/arm/board/juno/${ARCH}/juno_helpers.S \ plat/arm/board/juno/juno_common.c # Flag to enable support for AArch32 state on JUNO JUNO_AARCH32_EL3_RUNTIME := 0 $(eval $(call assert_boolean,JUNO_AARCH32_EL3_RUNTIME)) $(eval $(call add_define,JUNO_AARCH32_EL3_RUNTIME)) # Flag to enable support for TZMP1 on JUNO JUNO_TZMP1 := 0 $(eval $(call assert_boolean,JUNO_TZMP1)) ifeq (${JUNO_TZMP1}, 1) $(eval $(call add_define,JUNO_TZMP1)) endif ifeq (${JUNO_AARCH32_EL3_RUNTIME}, 1) # Include BL32 in FIP NEED_BL32 := yes # BL31 is not required override BL31_SOURCES = # The BL32 needs to be built separately invoking the AARCH32 compiler and # be specifed via `BL32` build option. ifneq (${ARCH}, aarch32) override BL32_SOURCES = endif endif ifeq (${ARCH},aarch64) BL1_SOURCES += lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S \ lib/cpus/aarch64/cortex_a72.S \ plat/arm/board/juno/juno_err.c \ plat/arm/board/juno/juno_bl1_setup.c \ drivers/arm/sp805/sp805.c \ ${JUNO_INTERCONNECT_SOURCES} \ ${JUNO_SECURITY_SOURCES} BL2_SOURCES += drivers/arm/sp805/sp805.c \ lib/utils/mem_region.c \ plat/arm/board/juno/juno_err.c \ plat/arm/board/juno/juno_bl2_setup.c \ plat/arm/common/arm_nor_psci_mem_protect.c \ ${JUNO_SECURITY_SOURCES} BL2U_SOURCES += ${JUNO_SECURITY_SOURCES} BL31_SOURCES += drivers/cfi/v2m/v2m_flash.c \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S \ lib/cpus/aarch64/cortex_a72.S \ lib/utils/mem_region.c \ plat/arm/board/juno/juno_pm.c \ plat/arm/board/juno/juno_topology.c \ plat/arm/common/arm_nor_psci_mem_protect.c \ ${JUNO_GIC_SOURCES} \ ${JUNO_INTERCONNECT_SOURCES} \ ${JUNO_SECURITY_SOURCES} ifeq (${CSS_USE_SCMI_SDS_DRIVER},1) BL1_SOURCES += drivers/arm/css/sds/sds.c endif endif ifneq (${RESET_TO_BL31},0) $(error "Using BL31 as the reset vector is not supported on ${PLAT} platform. \ Please set RESET_TO_BL31 to 0.") endif ifeq ($(USE_ROMLIB),1) all : bl1_romlib.bin endif bl1_romlib.bin : $(BUILD_PLAT)/bl1.bin $(BUILD_PLAT)/romlib/romlib.bin @echo "Building combined BL1 and ROMLIB binary for Juno $@" ./lib/romlib/gen_combined_bl1_romlib.sh -o bl1_romlib.bin $(BUILD_PLAT) # Errata workarounds for Cortex-A53: ERRATA_A53_819472 := 1 ERRATA_A53_824069 := 1 ERRATA_A53_826319 := 1 ERRATA_A53_827319 := 1 ERRATA_A53_835769 := 1 ERRATA_A53_836870 := 1 ERRATA_A53_843419 := 1 ERRATA_A53_855873 := 1 # Errata workarounds for Cortex-A57: ERRATA_A57_806969 := 0 ERRATA_A57_813419 := 1 ERRATA_A57_813420 := 1 ERRATA_A57_814670 := 1 ERRATA_A57_817169 := 1 ERRATA_A57_826974 := 1 ERRATA_A57_826977 := 1 ERRATA_A57_828024 := 1 ERRATA_A57_829520 := 1 ERRATA_A57_833471 := 1 ERRATA_A57_859972 := 0 # Errata workarounds for Cortex-A72: ERRATA_A72_859971 := 0 # Enable option to skip L1 data cache flush during the Cortex-A57 cluster # power down sequence SKIP_A57_L1_FLUSH_PWR_DWN := 1 # Do not enable SVE ENABLE_SVE_FOR_NS := 0 # Enable the dynamic translation tables library. ifeq (${ARCH},aarch32) ifeq (${RESET_TO_SP_MIN},1) BL32_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1 endif else ifeq (${RESET_TO_BL31},1) BL31_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1 endif endif # Add the FDT_SOURCES and options for Dynamic Config FDT_SOURCES += plat/arm/board/juno/fdts/${PLAT}_tb_fw_config.dts TB_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb # Add the TB_FW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config)) include plat/arm/board/common/board_common.mk include plat/arm/common/arm_common.mk include plat/arm/soc/common/soc_css.mk include plat/arm/css/common/css_common.mk trusted-firmware-a-2.2/plat/arm/board/juno/sp_min/000077500000000000000000000000001355360272700221575ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/juno/sp_min/sp_min-juno.mk000066400000000000000000000013101355360272700247410ustar00rootroot00000000000000# # Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # SP_MIN source files specific to JUNO platform BL32_SOURCES += drivers/cfi/v2m/v2m_flash.c \ lib/cpus/aarch32/cortex_a53.S \ lib/cpus/aarch32/cortex_a57.S \ lib/cpus/aarch32/cortex_a72.S \ lib/utils/mem_region.c \ plat/arm/board/juno/juno_pm.c \ plat/arm/board/juno/juno_topology.c \ plat/arm/common/arm_nor_psci_mem_protect.c \ plat/arm/soc/common/soc_css_security.c \ ${JUNO_GIC_SOURCES} \ ${JUNO_INTERCONNECT_SOURCES} \ ${JUNO_SECURITY_SOURCES} include plat/arm/common/sp_min/arm_sp_min.mk include plat/arm/css/common/sp_min/css_sp_min.mk trusted-firmware-a-2.2/plat/arm/board/juno/tsp/000077500000000000000000000000001355360272700215005ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/juno/tsp/tsp-juno.mk000066400000000000000000000004761355360272700236170ustar00rootroot00000000000000# # Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # BL32_SOURCES += plat/arm/board/juno/juno_topology.c \ plat/arm/css/common/css_topology.c \ ${JUNO_GIC_SOURCES} \ ${JUNO_SECURITY_SOURCES} include plat/arm/common/tsp/arm_tsp.mk trusted-firmware-a-2.2/plat/arm/board/n1sdp/000077500000000000000000000000001355360272700207445ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/n1sdp/aarch64/000077500000000000000000000000001355360272700221745ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/n1sdp/aarch64/n1sdp_helper.S000066400000000000000000000037161355360272700247130ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include .globl plat_arm_calc_core_pos .globl plat_reset_handler /* ----------------------------------------------------- * unsigned int plat_arm_calc_core_pos(u_register_t mpidr) * * Helper function to calculate the core position. * (ClusterId * N1SDP_MAX_CPUS_PER_CLUSTER * N1SDP_MAX_PE_PER_CPU) + * (CPUId * N1SDP_MAX_PE_PER_CPU) + * ThreadId * * which can be simplified as: * * ((ClusterId * N1SDP_MAX_CPUS_PER_CLUSTER + CPUId) * * N1SDP_MAX_PE_PER_CPU) + ThreadId * ------------------------------------------------------ */ func plat_arm_calc_core_pos mov x3, x0 /* * The MT bit in MPIDR is always set for n1sdp and the * affinity level 0 corresponds to thread affinity level. */ /* Extract individual affinity fields from MPIDR */ ubfx x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS ubfx x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS ubfx x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS /* Compute linear position */ mov x4, #N1SDP_MAX_CPUS_PER_CLUSTER madd x1, x2, x4, x1 mov x5, #N1SDP_MAX_PE_PER_CPU madd x0, x1, x5, x0 ret endfunc plat_arm_calc_core_pos /* ----------------------------------------------------- * void plat_reset_handler(void); * * Determine the CPU MIDR and disable power down bit for * that CPU. * ----------------------------------------------------- */ func plat_reset_handler jump_if_cpu_midr NEOVERSE_N1_MIDR, N1 ret /* ----------------------------------------------------- * Disable CPU power down bit in power control register * ----------------------------------------------------- */ N1: mrs x0, NEOVERSE_N1_CPUPWRCTLR_EL1 bic x0, x0, #NEOVERSE_N1_CORE_PWRDN_EN_MASK msr NEOVERSE_N1_CPUPWRCTLR_EL1, x0 isb ret endfunc plat_reset_handler trusted-firmware-a-2.2/plat/arm/board/n1sdp/include/000077500000000000000000000000001355360272700223675ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/n1sdp/include/plat_macros.S000066400000000000000000000010721355360272700250170ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S #include /* --------------------------------------------- * The below required platform porting macro * prints out relevant platform registers * whenever an unhandled exception is taken in * BL31. * * There are currently no platform specific regs * to print. * --------------------------------------------- */ .macro plat_crash_print_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/arm/board/n1sdp/include/platform_def.h000066400000000000000000000065571355360272700252170ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include /* UART related constants */ #define PLAT_ARM_BOOT_UART_BASE 0x2A400000 #define PLAT_ARM_BOOT_UART_CLK_IN_HZ 50000000 #define PLAT_ARM_RUN_UART_BASE 0x2A410000 #define PLAT_ARM_RUN_UART_CLK_IN_HZ 50000000 #define PLAT_ARM_SP_MIN_RUN_UART_BASE 0x2A410000 #define PLAT_ARM_SP_MIN_RUN_UART_CLK_IN_HZ 50000000 #define PLAT_ARM_CRASH_UART_BASE PLAT_ARM_RUN_UART_BASE #define PLAT_ARM_CRASH_UART_CLK_IN_HZ PLAT_ARM_RUN_UART_CLK_IN_HZ #define PLAT_ARM_DRAM2_BASE ULL(0x8080000000) #define PLAT_ARM_DRAM2_SIZE ULL(0xF80000000) /* * N1SDP platform supports RDIMMs with ECC capability. To use the ECC * capability, the entire DDR memory space has to be zeroed out before * enabling the ECC bits in DMC620. The access the complete DDR memory * space the physical & virtual address space limits are extended to * 40-bits. */ #ifdef __aarch64__ #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 40) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 40) #else #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #endif #if CSS_USE_SCMI_SDS_DRIVER #define N1SDP_SCMI_PAYLOAD_BASE 0x45400000 #else #define PLAT_CSS_SCP_COM_SHARED_MEM_BASE 0x45400000 #endif #define PLAT_ARM_TRUSTED_SRAM_SIZE 0x00080000 /* 512 KB */ #define PLAT_ARM_MAX_BL31_SIZE 0X20000 /******************************************************************************* * N1SDP topology related constants ******************************************************************************/ #define N1SDP_MAX_CPUS_PER_CLUSTER 2 #define PLAT_ARM_CLUSTER_COUNT 2 #define N1SDP_MAX_PE_PER_CPU 1 #define PLATFORM_CORE_COUNT (PLAT_ARM_CLUSTER_COUNT * \ N1SDP_MAX_CPUS_PER_CLUSTER * \ N1SDP_MAX_PE_PER_CPU) /* System power domain level */ #define CSS_SYSTEM_PWR_DMN_LVL ARM_PWR_LVL2 /* * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the * plat_arm_mmap array defined for each BL stage. */ #define PLAT_ARM_MMAP_ENTRIES 6 #define MAX_XLAT_TABLES 7 #define PLATFORM_STACK_SIZE 0x400 #define PLAT_ARM_NSTIMER_FRAME_ID 0 #define PLAT_CSS_MHU_BASE 0x45000000 #define PLAT_MHUV2_BASE PLAT_CSS_MHU_BASE #define PLAT_MAX_PWR_LVL 1 #define PLAT_ARM_G1S_IRQS ARM_G1S_IRQS, \ CSS_IRQ_MHU #define PLAT_ARM_G0_IRQS ARM_G0_IRQS #define PLAT_ARM_G1S_IRQ_PROPS(grp) CSS_G1S_IRQ_PROPS(grp) #define PLAT_ARM_G0_IRQ_PROPS(grp) ARM_G0_IRQ_PROPS(grp) #define N1SDP_DEVICE_BASE (0x08000000) #define N1SDP_DEVICE_SIZE (0x48000000) #define N1SDP_MAP_DEVICE MAP_REGION_FLAT( \ N1SDP_DEVICE_BASE, \ N1SDP_DEVICE_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define ARM_MAP_DRAM1 MAP_REGION_FLAT( \ ARM_DRAM1_BASE, \ ARM_DRAM1_SIZE, \ MT_MEMORY | MT_RW | MT_NS) /* GIC related constants */ #define PLAT_ARM_GICD_BASE 0x30000000 #define PLAT_ARM_GICC_BASE 0x2C000000 #define PLAT_ARM_GICR_BASE 0x300C0000 /* Platform ID address */ #define SSC_VERSION (SSC_REG_BASE + SSC_VERSION_OFFSET) /* Secure Watchdog Constants */ #define SBSA_SECURE_WDOG_BASE UL(0x2A480000) #define SBSA_SECURE_WDOG_TIMEOUT UL(100) #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/arm/board/n1sdp/n1sdp_bl31_setup.c000066400000000000000000000106301355360272700241760ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include "n1sdp_def.h" /* * Memory information structure stored in SDS. * This structure holds the total DDR memory size which will be * used when zeroing out the entire DDR memory before enabling * the ECC capability in DMCs. */ struct n1sdp_mem_info { uint32_t ddr_size_gb; }; /* * BL33 image information structure stored in SDS. * This structure holds the source & destination addresses and * the size of the BL33 image which will be loaded by BL31. */ struct n1sdp_bl33_info { uint32_t bl33_src_addr; uint32_t bl33_dst_addr; uint32_t bl33_size; }; static scmi_channel_plat_info_t n1sdp_scmi_plat_info = { .scmi_mbx_mem = N1SDP_SCMI_PAYLOAD_BASE, .db_reg_addr = PLAT_CSS_MHU_BASE + CSS_SCMI_MHU_DB_REG_OFF, .db_preserve_mask = 0xfffffffe, .db_modify_mask = 0x1, .ring_doorbell = &mhu_ring_doorbell, }; scmi_channel_plat_info_t *plat_css_get_scmi_info() { return &n1sdp_scmi_plat_info; } const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops) { return css_scmi_override_pm_ops(ops); } /* * N1SDP platform supports RDIMMs with ECC capability. To use the ECC * capability, the entire DDR memory space has to be zeroed out before * enabling the ECC bits in DMC620. Zeroing out several gigabytes of * memory from SCP is quite time consuming so the following function * is added to zero out the DDR memory from application processor which is * much faster compared to SCP. BL33 binary cannot be copied to DDR memory * before enabling ECC so copy_bl33 function is added to copy BL33 binary * from IOFPGA-DDR3 memory to main DDR4 memory. */ void dmc_ecc_setup(uint32_t ddr_size_gb) { uint64_t dram2_size; dram2_size = (ddr_size_gb * 1024UL * 1024UL * 1024UL) - ARM_DRAM1_SIZE; INFO("Zeroing DDR memories\n"); zero_normalmem((void *)ARM_DRAM1_BASE, ARM_DRAM1_SIZE); flush_dcache_range(ARM_DRAM1_BASE, ARM_DRAM1_SIZE); zero_normalmem((void *)ARM_DRAM2_BASE, dram2_size); flush_dcache_range(ARM_DRAM2_BASE, dram2_size); INFO("Enabling ECC on DMCs\n"); /* Set DMCs to CONFIG state before writing ERR0CTLR0 register */ mmio_write_32(N1SDP_DMC0_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_CONFIG); mmio_write_32(N1SDP_DMC1_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_CONFIG); /* Enable ECC in DMCs */ mmio_setbits_32(N1SDP_DMC0_ERR0CTLR0_REG, N1SDP_DMC_ERR0CTLR0_ECC_EN); mmio_setbits_32(N1SDP_DMC1_ERR0CTLR0_REG, N1SDP_DMC_ERR0CTLR0_ECC_EN); /* Set DMCs to READY state */ mmio_write_32(N1SDP_DMC0_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY); mmio_write_32(N1SDP_DMC1_MEMC_CMD_REG, N1SDP_DMC_MEMC_CMD_READY); } void copy_bl33(uint32_t src, uint32_t dst, uint32_t size) { uint32_t i; INFO("Copying BL33 to DDR memory\n"); for (i = 0; i < size; i = i + 8) mmio_write_64((dst + i), mmio_read_64(src + i)); for (i = 0; i < size; i = i + 8) { if (mmio_read_64(src + i) != mmio_read_64(dst + i)) { ERROR("Copy failed!\n"); panic(); } } } void bl31_platform_setup(void) { int ret; struct n1sdp_mem_info mem_info; struct n1sdp_bl33_info bl33_info; arm_bl31_platform_setup(); ret = sds_init(); if (ret != SDS_OK) { ERROR("SDS initialization failed\n"); panic(); } ret = sds_struct_read(N1SDP_SDS_MEM_INFO_STRUCT_ID, N1SDP_SDS_MEM_INFO_OFFSET, &mem_info, N1SDP_SDS_MEM_INFO_SIZE, SDS_ACCESS_MODE_NON_CACHED); if (ret != SDS_OK) { ERROR("Error getting memory info from SDS\n"); panic(); } dmc_ecc_setup(mem_info.ddr_size_gb); ret = sds_struct_read(N1SDP_SDS_BL33_INFO_STRUCT_ID, N1SDP_SDS_BL33_INFO_OFFSET, &bl33_info, N1SDP_SDS_BL33_INFO_SIZE, SDS_ACCESS_MODE_NON_CACHED); if (ret != SDS_OK) { ERROR("Error getting BL33 info from SDS\n"); panic(); } copy_bl33(bl33_info.bl33_src_addr, bl33_info.bl33_dst_addr, bl33_info.bl33_size); /* * Pass DDR memory size info to BL33. This method is followed as * currently there is no BL1/BL2 involved in boot flow of N1SDP. * When TBBR is implemented for N1SDP, this method should be removed * and DDR memory size shoule be passed to BL33 using NT_FW_CONFIG * passing mechanism. */ mmio_write_32(N1SDP_DDR_MEM_INFO_BASE, mem_info.ddr_size_gb); } trusted-firmware-a-2.2/plat/arm/board/n1sdp/n1sdp_def.h000066400000000000000000000024511355360272700227620ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef N1SDP_DEF_H #define N1SDP_DEF_H /* Non-secure SRAM MMU mapping */ #define N1SDP_NS_SRAM_BASE (0x06000000) #define N1SDP_NS_SRAM_SIZE (0x00010000) #define N1SDP_MAP_NS_SRAM MAP_REGION_FLAT( \ N1SDP_NS_SRAM_BASE, \ N1SDP_NS_SRAM_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) /* SDS memory information defines */ #define N1SDP_SDS_MEM_INFO_STRUCT_ID 8 #define N1SDP_SDS_MEM_INFO_OFFSET 0 #define N1SDP_SDS_MEM_INFO_SIZE 4 /* SDS BL33 image information defines */ #define N1SDP_SDS_BL33_INFO_STRUCT_ID 9 #define N1SDP_SDS_BL33_INFO_OFFSET 0 #define N1SDP_SDS_BL33_INFO_SIZE 12 /* DMC memory command registers */ #define N1SDP_DMC0_MEMC_CMD_REG 0x4E000008 #define N1SDP_DMC1_MEMC_CMD_REG 0x4E100008 /* DMC ERR0CTLR0 registers */ #define N1SDP_DMC0_ERR0CTLR0_REG 0x4E000708 #define N1SDP_DMC1_ERR0CTLR0_REG 0x4E100708 /* DMC memory commands */ #define N1SDP_DMC_MEMC_CMD_CONFIG 0 #define N1SDP_DMC_MEMC_CMD_READY 3 /* DMC ECC enable bit in ERR0CTLR0 register */ #define N1SDP_DMC_ERR0CTLR0_ECC_EN 0x1 /* Base address of non-secure SRAM where DDR memory size will be filled */ #define N1SDP_DDR_MEM_INFO_BASE 0x06008000 #endif /* N1SDP_DEF_H */ trusted-firmware-a-2.2/plat/arm/board/n1sdp/n1sdp_interconnect.c000066400000000000000000000021571355360272700247150ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * For N1SDP which support FCM (with automatic interconnect enter/exit), * we should not do anything in these interface functions. * They are used to override the weak functions in cci drivers. */ /****************************************************************************** * Helper function to initialize ARM interconnect driver. *****************************************************************************/ void plat_arm_interconnect_init(void) { } /****************************************************************************** * Helper function to place current master into coherency *****************************************************************************/ void plat_arm_interconnect_enter_coherency(void) { } /****************************************************************************** * Helper function to remove current master from coherency *****************************************************************************/ void plat_arm_interconnect_exit_coherency(void) { } trusted-firmware-a-2.2/plat/arm/board/n1sdp/n1sdp_plat.c000066400000000000000000000013771355360272700231650ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "n1sdp_def.h" /* * Table of regions to map using the MMU. * Replace or extend the below regions as required */ const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, N1SDP_MAP_DEVICE, N1SDP_MAP_NS_SRAM, ARM_MAP_DRAM1, ARM_MAP_DRAM2, {0} }; void plat_arm_secure_wdt_start(void) { sbsa_wdog_start(SBSA_SECURE_WDOG_BASE, SBSA_SECURE_WDOG_TIMEOUT); } void plat_arm_secure_wdt_stop(void) { sbsa_wdog_stop(SBSA_SECURE_WDOG_BASE); } trusted-firmware-a-2.2/plat/arm/board/n1sdp/n1sdp_security.c000066400000000000000000000003261355360272700240650ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * TZC programming is currently not done. */ void plat_arm_security_setup(void) { } trusted-firmware-a-2.2/plat/arm/board/n1sdp/n1sdp_topology.c000066400000000000000000000036451355360272700241010ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* Topology */ typedef struct n1sdp_topology { const unsigned char *power_tree; unsigned int plat_cluster_core_count; } n1sdp_topology_t; /* * The power domain tree descriptor. The cluster power domains are * arranged so that when the PSCI generic code creates the power domain tree, * the indices of the CPU power domain nodes it allocates match the linear * indices returned by plat_core_pos_by_mpidr(). */ const unsigned char n1sdp_pd_tree_desc[] = { PLAT_ARM_CLUSTER_COUNT, N1SDP_MAX_CPUS_PER_CLUSTER, N1SDP_MAX_CPUS_PER_CLUSTER }; /* Topology configuration for n1sdp */ const n1sdp_topology_t n1sdp_topology = { .power_tree = n1sdp_pd_tree_desc, .plat_cluster_core_count = N1SDP_MAX_CPUS_PER_CLUSTER }; /******************************************************************************* * This function returns the topology tree information. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { return n1sdp_topology.power_tree; } /******************************************************************************* * This function returns the core count within the cluster corresponding to * `mpidr`. ******************************************************************************/ unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr) { return n1sdp_topology.plat_cluster_core_count; } /******************************************************************************* * The array mapping platform core position (implemented by plat_my_core_pos()) * to the SCMI power domain ID implemented by SCP. ******************************************************************************/ const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[PLATFORM_CORE_COUNT] = { 0, 1, 2, 3}; trusted-firmware-a-2.2/plat/arm/board/n1sdp/platform.mk000066400000000000000000000036351355360272700231300ustar00rootroot00000000000000# # Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # N1SDP_BASE := plat/arm/board/n1sdp INTERCONNECT_SOURCES := ${N1SDP_BASE}/n1sdp_interconnect.c PLAT_INCLUDES := -I${N1SDP_BASE}/include N1SDP_CPU_SOURCES := lib/cpus/aarch64/neoverse_n1.S N1SDP_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v3/gicv3_main.c \ drivers/arm/gic/v3/gicv3_helpers.c \ plat/common/plat_gicv3.c \ plat/arm/common/arm_gicv3.c \ drivers/arm/gic/v3/gic600.c PLAT_BL_COMMON_SOURCES := ${N1SDP_BASE}/n1sdp_plat.c \ ${N1SDP_BASE}/aarch64/n1sdp_helper.S BL1_SOURCES += drivers/arm/sbsa/sbsa.c BL31_SOURCES := ${N1SDP_CPU_SOURCES} \ ${INTERCONNECT_SOURCES} \ ${N1SDP_GIC_SOURCES} \ ${N1SDP_BASE}/n1sdp_bl31_setup.c \ ${N1SDP_BASE}/n1sdp_topology.c \ ${N1SDP_BASE}/n1sdp_security.c \ drivers/arm/css/sds/sds.c # TF-A not required to load the SCP Images override CSS_LOAD_SCP_IMAGES := 0 # BL1/BL2 Image not a part of the capsule Image for n1sdp override NEED_BL1 := no override NEED_BL2 := no override NEED_BL2U := no #TFA for n1sdp starts from BL31 override RESET_TO_BL31 := 1 # 32 bit mode not supported override CTX_INCLUDE_AARCH32_REGS := 0 override ARM_PLAT_MT := 1 # Select SCMI/SDS drivers instead of SCPI/BOM driver for communicating with the # SCP during power management operations and for SCP RAM Firmware transfer. CSS_USE_SCMI_SDS_DRIVER := 1 # System coherency is managed in hardware HW_ASSISTED_COHERENCY := 1 # When building for systems with hardware-assisted coherency, there's no need to # use USE_COHERENT_MEM. Require that USE_COHERENT_MEM must be set to 0 too. USE_COHERENT_MEM := 0 include plat/arm/common/arm_common.mk include plat/arm/css/common/css_common.mk include plat/arm/board/common/board_common.mk trusted-firmware-a-2.2/plat/arm/board/rde1edge/000077500000000000000000000000001355360272700213775ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/rde1edge/fdts/000077500000000000000000000000001355360272700223375ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/rde1edge/fdts/rde1edge_nt_fw_config.dts000066400000000000000000000006531355360272700272610ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { /* compatible string */ compatible = "arm,rd-e1edge"; /* * Place holder for system-id node with default values. The * value of platform-id and config-id will be set to the * correct values during the BL2 stage of boot. */ system-id { platform-id = <0x0>; config-id = <0x0>; }; }; trusted-firmware-a-2.2/plat/arm/board/rde1edge/fdts/rde1edge_tb_fw_config.dts000066400000000000000000000013171355360272700272430ustar00rootroot00000000000000/* * Copyright (c) 2018, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { /* Platform Config */ compatible = "arm,tb_fw"; nt_fw_config_addr = <0x0 0xFEF00000>; nt_fw_config_max_size = <0x0100000>; /* * The following two entries are placeholders for Mbed TLS * heap information. The default values don't matter since * they will be overwritten by BL1. * In case of having shared Mbed TLS heap between BL1 and BL2, * BL1 will populate these two properties with the respective * info about the shared heap. This info will be available for * BL2 in order to locate and re-use the heap. */ mbedtls_heap_addr = <0x0 0x0>; mbedtls_heap_size = <0x0>; }; trusted-firmware-a-2.2/plat/arm/board/rde1edge/include/000077500000000000000000000000001355360272700230225ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/rde1edge/include/platform_def.h000066400000000000000000000017151355360272700256410ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #define PLAT_ARM_CLUSTER_COUNT 2 #define CSS_SGI_MAX_CPUS_PER_CLUSTER 8 #define CSS_SGI_MAX_PE_PER_CPU 2 #define PLAT_CSS_MHU_BASE UL(0x45400000) #define PLAT_MHUV2_BASE PLAT_CSS_MHU_BASE /* Base address of DMC-620 instances */ #define RDE1EDGE_DMC620_BASE0 UL(0x4e000000) #define RDE1EDGE_DMC620_BASE1 UL(0x4e100000) #define PLAT_MAX_PWR_LVL ARM_PWR_LVL2 #define CSS_SYSTEM_PWR_DMN_LVL ARM_PWR_LVL3 /* * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes */ #ifdef __aarch64__ #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 36) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 36) #else #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #endif #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/arm/board/rde1edge/platform.mk000066400000000000000000000025741355360272700235640ustar00rootroot00000000000000# # Copyright (c) 2018-2019, Arm Limited. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # include plat/arm/css/sgi/sgi-common.mk RDE1EDGE_BASE = plat/arm/board/rde1edge PLAT_INCLUDES += -I${RDE1EDGE_BASE}/include/ SGI_CPU_SOURCES := lib/cpus/aarch64/neoverse_e1.S BL1_SOURCES += ${SGI_CPU_SOURCES} \ ${RDE1EDGE_BASE}/rde1edge_err.c BL2_SOURCES += ${RDE1EDGE_BASE}/rde1edge_plat.c \ ${RDE1EDGE_BASE}/rde1edge_security.c \ ${RDE1EDGE_BASE}/rde1edge_err.c \ drivers/arm/tzc/tzc_dmc620.c \ lib/utils/mem_region.c \ plat/arm/common/arm_nor_psci_mem_protect.c BL31_SOURCES += ${SGI_CPU_SOURCES} \ ${RDE1EDGE_BASE}/rde1edge_plat.c \ drivers/cfi/v2m/v2m_flash.c \ lib/utils/mem_region.c \ plat/arm/common/arm_nor_psci_mem_protect.c # Add the FDT_SOURCES and options for Dynamic Config FDT_SOURCES += ${RDE1EDGE_BASE}/fdts/${PLAT}_tb_fw_config.dts TB_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb # Add the TB_FW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config)) FDT_SOURCES += ${RDE1EDGE_BASE}/fdts/${PLAT}_nt_fw_config.dts NT_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_nt_fw_config.dtb # Add the NT_FW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${NT_FW_CONFIG},--nt-fw-config)) override CTX_INCLUDE_AARCH32_REGS := 0 trusted-firmware-a-2.2/plat/arm/board/rde1edge/rde1edge_err.c000066400000000000000000000003771355360272700241020ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* * rde1edge error handler */ void __dead2 plat_arm_error_handler(int err) { while (1) { wfi(); } } trusted-firmware-a-2.2/plat/arm/board/rde1edge/rde1edge_plat.c000066400000000000000000000006201355360272700242410ustar00rootroot00000000000000/* * Copyright (c) 2018, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include unsigned int plat_arm_sgi_get_platform_id(void) { return mmio_read_32(SID_REG_BASE + SID_SYSTEM_ID_OFFSET) & SID_SYSTEM_ID_PART_NUM_MASK; } unsigned int plat_arm_sgi_get_config_id(void) { return mmio_read_32(SID_REG_BASE + SID_SYSTEM_CFG_OFFSET); } trusted-firmware-a-2.2/plat/arm/board/rde1edge/rde1edge_security.c000066400000000000000000000017531355360272700251600ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include uintptr_t rde1edge_dmc_base[] = { RDE1EDGE_DMC620_BASE0, RDE1EDGE_DMC620_BASE1 }; static const tzc_dmc620_driver_data_t rde1edge_plat_driver_data = { .dmc_base = rde1edge_dmc_base, .dmc_count = ARRAY_SIZE(rde1edge_dmc_base) }; static const tzc_dmc620_acc_addr_data_t rde1edge_acc_addr_data[] = { { .region_base = ARM_AP_TZC_DRAM1_BASE, .region_top = ARM_AP_TZC_DRAM1_BASE + ARM_TZC_DRAM1_SIZE - 1, .sec_attr = TZC_DMC620_REGION_S_RDWR } }; static const tzc_dmc620_config_data_t rde1edge_plat_config_data = { .plat_drv_data = &rde1edge_plat_driver_data, .plat_acc_addr_data = rde1edge_acc_addr_data, .acc_addr_count = ARRAY_SIZE(rde1edge_acc_addr_data) }; /* Initialize the secure environment */ void plat_arm_security_setup(void) { arm_tzc_dmc620_setup(&rde1edge_plat_config_data); } trusted-firmware-a-2.2/plat/arm/board/rdn1edge/000077500000000000000000000000001355360272700214105ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/rdn1edge/fdts/000077500000000000000000000000001355360272700223505ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/rdn1edge/fdts/rdn1edge_nt_fw_config.dts000066400000000000000000000006731355360272700273050ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { /* compatible string */ compatible = "arm,rd-n1edge"; /* * Place holder for system-id node with default values. The * value of platform-id and config-id will be set to the * correct values during the BL2 stage of boot. */ system-id { platform-id = <0x0>; config-id = <0x0>; }; }; trusted-firmware-a-2.2/plat/arm/board/rdn1edge/fdts/rdn1edge_tb_fw_config.dts000066400000000000000000000013401355360272700272610ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { /* Platform Config */ compatible = "arm,tb_fw"; nt_fw_config_addr = <0x0 0xFEF00000>; nt_fw_config_max_size = <0x0100000>; /* * The following two entries are placeholders for Mbed TLS * heap information. The default values don't matter since * they will be overwritten by BL1. * In case of having shared Mbed TLS heap between BL1 and BL2, * BL1 will populate these two properties with the respective * info about the shared heap. This info will be available for * BL2 in order to locate and re-use the heap. */ mbedtls_heap_addr = <0x0 0x0>; mbedtls_heap_size = <0x0>; }; trusted-firmware-a-2.2/plat/arm/board/rdn1edge/include/000077500000000000000000000000001355360272700230335ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/rdn1edge/include/platform_def.h000066400000000000000000000017761355360272700256610ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #define PLAT_ARM_CLUSTER_COUNT 2 #define CSS_SGI_MAX_CPUS_PER_CLUSTER 4 #define CSS_SGI_MAX_PE_PER_CPU 1 #define PLAT_CSS_MHU_BASE UL(0x45400000) #define PLAT_MHUV2_BASE PLAT_CSS_MHU_BASE /* Base address of DMC-620 instances */ #define RDN1EDGE_DMC620_BASE0 UL(0x4e000000) #define RDN1EDGE_DMC620_BASE1 UL(0x4e100000) /* System power domain level */ #define CSS_SYSTEM_PWR_DMN_LVL ARM_PWR_LVL2 #define PLAT_MAX_PWR_LVL ARM_PWR_LVL1 /* * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes */ #ifdef __aarch64__ #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 36) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 36) #else #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #endif #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/arm/board/rdn1edge/platform.mk000066400000000000000000000026151355360272700235710ustar00rootroot00000000000000# # Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # include plat/arm/css/sgi/sgi-common.mk RDN1EDGE_BASE = plat/arm/board/rdn1edge PLAT_INCLUDES += -I${RDN1EDGE_BASE}/include/ SGI_CPU_SOURCES := lib/cpus/aarch64/neoverse_n1.S BL1_SOURCES += ${SGI_CPU_SOURCES} \ ${RDN1EDGE_BASE}/rdn1edge_err.c BL2_SOURCES += ${RDN1EDGE_BASE}/rdn1edge_plat.c \ ${RDN1EDGE_BASE}/rdn1edge_security.c \ ${RDN1EDGE_BASE}/rdn1edge_err.c \ drivers/arm/tzc/tzc_dmc620.c \ lib/utils/mem_region.c \ plat/arm/common/arm_nor_psci_mem_protect.c BL31_SOURCES += ${SGI_CPU_SOURCES} \ ${RDN1EDGE_BASE}/rdn1edge_plat.c \ drivers/cfi/v2m/v2m_flash.c \ lib/utils/mem_region.c \ plat/arm/common/arm_nor_psci_mem_protect.c # Add the FDT_SOURCES and options for Dynamic Config FDT_SOURCES += ${RDN1EDGE_BASE}/fdts/${PLAT}_tb_fw_config.dts TB_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb # Add the TB_FW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config)) FDT_SOURCES += ${RDN1EDGE_BASE}/fdts/${PLAT}_nt_fw_config.dts NT_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_nt_fw_config.dtb # Add the NT_FW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${NT_FW_CONFIG},--nt-fw-config)) override CTX_INCLUDE_AARCH32_REGS := 0 trusted-firmware-a-2.2/plat/arm/board/rdn1edge/rdn1edge_err.c000066400000000000000000000003771355360272700241240ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* * rdn1edge error handler */ void __dead2 plat_arm_error_handler(int err) { while (1) { wfi(); } } trusted-firmware-a-2.2/plat/arm/board/rdn1edge/rdn1edge_plat.c000066400000000000000000000006411355360272700242660ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include unsigned int plat_arm_sgi_get_platform_id(void) { return mmio_read_32(SID_REG_BASE + SID_SYSTEM_ID_OFFSET) & SID_SYSTEM_ID_PART_NUM_MASK; } unsigned int plat_arm_sgi_get_config_id(void) { return mmio_read_32(SID_REG_BASE + SID_SYSTEM_CFG_OFFSET); } trusted-firmware-a-2.2/plat/arm/board/rdn1edge/rdn1edge_security.c000066400000000000000000000017531355360272700252020ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include uintptr_t rdn1edge_dmc_base[] = { RDN1EDGE_DMC620_BASE0, RDN1EDGE_DMC620_BASE1 }; static const tzc_dmc620_driver_data_t rdn1edge_plat_driver_data = { .dmc_base = rdn1edge_dmc_base, .dmc_count = ARRAY_SIZE(rdn1edge_dmc_base) }; static const tzc_dmc620_acc_addr_data_t rdn1edge_acc_addr_data[] = { { .region_base = ARM_AP_TZC_DRAM1_BASE, .region_top = ARM_AP_TZC_DRAM1_BASE + ARM_TZC_DRAM1_SIZE - 1, .sec_attr = TZC_DMC620_REGION_S_RDWR } }; static const tzc_dmc620_config_data_t rdn1edge_plat_config_data = { .plat_drv_data = &rdn1edge_plat_driver_data, .plat_acc_addr_data = rdn1edge_acc_addr_data, .acc_addr_count = ARRAY_SIZE(rdn1edge_acc_addr_data) }; /* Initialize the secure environment */ void plat_arm_security_setup(void) { arm_tzc_dmc620_setup(&rdn1edge_plat_config_data); } trusted-firmware-a-2.2/plat/arm/board/sgi575/000077500000000000000000000000001355360272700207425ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/sgi575/fdts/000077500000000000000000000000001355360272700217025ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/sgi575/fdts/sgi575_nt_fw_config.dts000066400000000000000000000006631355360272700261700ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { /* compatible string */ compatible = "arm,sgi575"; /* * Place holder for system-id node with default values. The * value of platform-id and config-id will be set to the * correct values during the BL2 stage of boot. */ system-id { platform-id = <0x0>; config-id = <0x0>; }; }; trusted-firmware-a-2.2/plat/arm/board/sgi575/fdts/sgi575_tb_fw_config.dts000066400000000000000000000013401355360272700261450ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { /* Platform Config */ compatible = "arm,tb_fw"; nt_fw_config_addr = <0x0 0xFEF00000>; nt_fw_config_max_size = <0x0100000>; /* * The following two entries are placeholders for Mbed TLS * heap information. The default values don't matter since * they will be overwritten by BL1. * In case of having shared Mbed TLS heap between BL1 and BL2, * BL1 will populate these two properties with the respective * info about the shared heap. This info will be available for * BL2 in order to locate and re-use the heap. */ mbedtls_heap_addr = <0x0 0x0>; mbedtls_heap_size = <0x0>; }; trusted-firmware-a-2.2/plat/arm/board/sgi575/include/000077500000000000000000000000001355360272700223655ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/sgi575/include/platform_def.h000066400000000000000000000017651355360272700252110ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #define PLAT_ARM_CLUSTER_COUNT 2 #define CSS_SGI_MAX_CPUS_PER_CLUSTER 4 #define CSS_SGI_MAX_PE_PER_CPU 1 #define PLAT_CSS_MHU_BASE UL(0x45000000) #define PLAT_MHUV2_BASE PLAT_CSS_MHU_BASE /* Base address of DMC-620 instances */ #define SGI575_DMC620_BASE0 UL(0x4e000000) #define SGI575_DMC620_BASE1 UL(0x4e100000) /* System power domain level */ #define CSS_SYSTEM_PWR_DMN_LVL ARM_PWR_LVL2 #define PLAT_MAX_PWR_LVL ARM_PWR_LVL1 /* * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes */ #ifdef __aarch64__ #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 36) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 36) #else #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #endif #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/arm/board/sgi575/platform.mk000066400000000000000000000025101355360272700231150ustar00rootroot00000000000000# # Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # include plat/arm/css/sgi/sgi-common.mk SGI575_BASE = plat/arm/board/sgi575 PLAT_INCLUDES += -I${SGI575_BASE}/include/ SGI_CPU_SOURCES := lib/cpus/aarch64/cortex_a75.S BL1_SOURCES += ${SGI_CPU_SOURCES} \ ${SGI575_BASE}/sgi575_err.c BL2_SOURCES += ${SGI575_BASE}/sgi575_plat.c \ ${SGI575_BASE}/sgi575_security.c \ ${SGI575_BASE}/sgi575_err.c \ drivers/arm/tzc/tzc_dmc620.c \ lib/utils/mem_region.c \ plat/arm/common/arm_nor_psci_mem_protect.c BL31_SOURCES += ${SGI_CPU_SOURCES} \ ${SGI575_BASE}/sgi575_plat.c \ drivers/cfi/v2m/v2m_flash.c \ lib/utils/mem_region.c \ plat/arm/common/arm_nor_psci_mem_protect.c # Add the FDT_SOURCES and options for Dynamic Config FDT_SOURCES += ${SGI575_BASE}/fdts/${PLAT}_tb_fw_config.dts TB_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_tb_fw_config.dtb # Add the TB_FW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${TB_FW_CONFIG},--tb-fw-config)) FDT_SOURCES += ${SGI575_BASE}/fdts/${PLAT}_nt_fw_config.dts NT_FW_CONFIG := ${BUILD_PLAT}/fdts/${PLAT}_nt_fw_config.dtb # Add the NT_FW_CONFIG to FIP and specify the same to certtool $(eval $(call TOOL_ADD_PAYLOAD,${NT_FW_CONFIG},--nt-fw-config)) trusted-firmware-a-2.2/plat/arm/board/sgi575/sgi575_err.c000066400000000000000000000003751355360272700230060ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* * sgi575 error handler */ void __dead2 plat_arm_error_handler(int err) { while (1) { wfi(); } } trusted-firmware-a-2.2/plat/arm/board/sgi575/sgi575_plat.c000066400000000000000000000007041355360272700231520ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include unsigned int plat_arm_sgi_get_platform_id(void) { return mmio_read_32(SSC_VERSION) & SSC_VERSION_PART_NUM_MASK; } unsigned int plat_arm_sgi_get_config_id(void) { return (mmio_read_32(SSC_VERSION) >> SSC_VERSION_CONFIG_SHIFT) & SSC_VERSION_CONFIG_MASK; } trusted-firmware-a-2.2/plat/arm/board/sgi575/sgi575_security.c000066400000000000000000000020171355360272700240600ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include uintptr_t sgi575_dmc_base[] = { SGI575_DMC620_BASE0, SGI575_DMC620_BASE1 }; static const tzc_dmc620_driver_data_t sgi575_plat_driver_data = { .dmc_base = sgi575_dmc_base, .dmc_count = ARRAY_SIZE(sgi575_dmc_base) }; static const tzc_dmc620_acc_addr_data_t sgi575_acc_addr_data[] = { { .region_base = ARM_AP_TZC_DRAM1_BASE, .region_top = ARM_AP_TZC_DRAM1_BASE + ARM_TZC_DRAM1_SIZE - 1, .sec_attr = TZC_DMC620_REGION_S_RDWR } }; static const tzc_dmc620_config_data_t sgi575_plat_config_data = { .plat_drv_data = &sgi575_plat_driver_data, .plat_acc_addr_data = sgi575_acc_addr_data, .acc_addr_count = ARRAY_SIZE(sgi575_acc_addr_data) }; /* Initialize the secure environment */ void plat_arm_security_setup(void) { arm_tzc_dmc620_setup(&sgi575_plat_config_data); } trusted-firmware-a-2.2/plat/arm/board/sgm775/000077500000000000000000000000001355360272700207505ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/sgm775/fdts/000077500000000000000000000000001355360272700217105ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/sgm775/fdts/sgm775_tb_fw_config.dts000066400000000000000000000004411355360272700261620ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { /* Platform Config */ plat_arm_bl2 { compatible = "arm,tb_fw"; hw_config_addr = <0x0 0x83000000>; hw_config_max_size = <0x01000000>; }; }; trusted-firmware-a-2.2/plat/arm/board/sgm775/include/000077500000000000000000000000001355360272700223735ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/sgm775/include/platform_def.h000066400000000000000000000011431355360272700252050ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #define PLAT_MAX_CPUS_PER_CLUSTER 8 #define PLAT_MAX_PE_PER_CPU 1 /* * Physical and virtual address space limits for MMU in AARCH64 & AARCH32 modes */ #ifdef __aarch64__ #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 36) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 36) #else #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #endif #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/arm/board/sgm775/platform.mk000066400000000000000000000011501355360272700231220ustar00rootroot00000000000000# # Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # include plat/arm/css/sgm/sgm-common.mk SGM775_BASE= plat/arm/board/sgm775 FDT_SOURCES += ${SGM775_BASE}/fdts/sgm775_tb_fw_config.dts PLAT_INCLUDES +=-I${SGM775_BASE}/include/ BL1_SOURCES += ${SGM775_BASE}/sgm775_err.c BL2_SOURCES += lib/utils/mem_region.c \ ${SGM775_BASE}/sgm775_err.c \ plat/arm/common/arm_nor_psci_mem_protect.c BL31_SOURCES += drivers/cfi/v2m/v2m_flash.c \ lib/utils/mem_region.c \ plat/arm/common/arm_nor_psci_mem_protect.c trusted-firmware-a-2.2/plat/arm/board/sgm775/sgm775_err.c000066400000000000000000000003751355360272700230220ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* * sgm775 error handler */ void __dead2 plat_arm_error_handler(int err) { while (1) { wfi(); } } trusted-firmware-a-2.2/plat/arm/board/sgm775/tsp/000077500000000000000000000000001355360272700215565ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/board/sgm775/tsp/tsp-sgm775.mk000066400000000000000000000002371355360272700237460ustar00rootroot00000000000000# # Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # include plat/arm/css/sgm/tsp/tsp-sgm.mktrusted-firmware-a-2.2/plat/arm/common/000077500000000000000000000000001355360272700201205ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/common/aarch32/000077500000000000000000000000001355360272700213435ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/common/aarch32/arm_bl2_mem_params_desc.c000066400000000000000000000061101355360272700262220ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /******************************************************************************* * Following descriptor provides BL image/ep information that gets used * by BL2 to load the images and also subset of this information is * passed to next BL image. The image loading sequence is managed by * populating the images in required loading order. The image execution * sequence is managed by populating the `next_handoff_image_id` with * the next executable image id. ******************************************************************************/ static bl_mem_params_node_t bl2_mem_params_descs[] = { #ifdef SCP_BL2_BASE /* Fill SCP_BL2 related information if it exists */ { .image_id = SCP_BL2_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE), SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, VERSION_2, image_info_t, 0), .image_info.image_base = SCP_BL2_BASE, .image_info.image_max_size = PLAT_CSS_MAX_SCP_BL2_SIZE, .next_handoff_image_id = INVALID_IMAGE_ID, }, #endif /* SCP_BL2_BASE */ /* Fill BL32 related information */ { .image_id = BL32_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = BL32_BASE, .ep_info.spsr = SPSR_MODE32(MODE32_mon, SPSR_T_ARM, SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS), SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP), .image_info.image_base = BL32_BASE, .image_info.image_max_size = BL32_LIMIT - BL32_BASE, .next_handoff_image_id = BL33_IMAGE_ID, }, /* Fill HW_CONFIG related information if it exists */ { .image_id = HW_CONFIG_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, VERSION_2, entry_point_info_t, NON_SECURE | NON_EXECUTABLE), SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), .next_handoff_image_id = INVALID_IMAGE_ID, }, /* Fill BL33 related information */ { .image_id = BL33_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), #ifdef PRELOADED_BL33_BASE .ep_info.pc = PRELOADED_BL33_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), #else .ep_info.pc = PLAT_ARM_NS_IMAGE_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = PLAT_ARM_NS_IMAGE_BASE, .image_info.image_max_size = ARM_DRAM1_BASE + ARM_DRAM1_SIZE - PLAT_ARM_NS_IMAGE_BASE, #endif /* PRELOADED_BL33_BASE */ .next_handoff_image_id = INVALID_IMAGE_ID, } }; REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) trusted-firmware-a-2.2/plat/arm/common/aarch32/arm_helpers.S000066400000000000000000000045301355360272700237720ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .weak plat_arm_calc_core_pos .weak plat_my_core_pos .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush /* ----------------------------------------------------- * unsigned int plat_my_core_pos(void) * This function uses the plat_arm_calc_core_pos() * definition to get the index of the calling CPU. * ----------------------------------------------------- */ func plat_my_core_pos ldcopr r0, MPIDR b plat_arm_calc_core_pos endfunc plat_my_core_pos /* ----------------------------------------------------- * unsigned int plat_arm_calc_core_pos(uint64_t mpidr) * Helper function to calculate the core position. * With this function: CorePos = (ClusterId * 4) + * CoreId * ----------------------------------------------------- */ func plat_arm_calc_core_pos and r1, r0, #MPIDR_CPU_MASK and r0, r0, #MPIDR_CLUSTER_MASK add r0, r1, r0, LSR #6 bx lr endfunc plat_arm_calc_core_pos /* --------------------------------------------- * int plat_crash_console_init(void) * Function to initialize the crash console * without a C Runtime to print crash report. * Clobber list : r0 - r3 * --------------------------------------------- */ 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_pl011_core_init endfunc plat_crash_console_init /* --------------------------------------------- * int plat_crash_console_putc(int c) * Function to print a character on the crash * console without a C Runtime. * Clobber list : r1 - r2 * --------------------------------------------- */ func plat_crash_console_putc ldr r1, =PLAT_ARM_CRASH_UART_BASE b console_pl011_core_putc endfunc plat_crash_console_putc /* --------------------------------------------- * int plat_crash_console_flush() * Function to force a write of all buffered * data that hasn't been output. * Out : return -1 on error else return 0. * Clobber list : r0 * --------------------------------------------- */ func plat_crash_console_flush ldr r0, =PLAT_ARM_CRASH_UART_BASE b console_pl011_core_flush endfunc plat_crash_console_flush trusted-firmware-a-2.2/plat/arm/common/aarch64/000077500000000000000000000000001355360272700213505ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/common/aarch64/arm_bl2_mem_params_desc.c000066400000000000000000000150271355360272700262360ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /******************************************************************************* * Following descriptor provides BL image/ep information that gets used * by BL2 to load the images and also subset of this information is * passed to next BL image. The image loading sequence is managed by * populating the images in required loading order. The image execution * sequence is managed by populating the `next_handoff_image_id` with * the next executable image id. ******************************************************************************/ static bl_mem_params_node_t bl2_mem_params_descs[] = { #ifdef SCP_BL2_BASE /* Fill SCP_BL2 related information if it exists */ { .image_id = SCP_BL2_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE), SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, VERSION_2, image_info_t, 0), .image_info.image_base = SCP_BL2_BASE, .image_info.image_max_size = PLAT_CSS_MAX_SCP_BL2_SIZE, .next_handoff_image_id = INVALID_IMAGE_ID, }, #endif /* SCP_BL2_BASE */ #ifdef EL3_PAYLOAD_BASE /* Fill EL3 payload related information (BL31 is EL3 payload)*/ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = EL3_PAYLOAD_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING), .next_handoff_image_id = INVALID_IMAGE_ID, }, #else /* EL3_PAYLOAD_BASE */ /* Fill BL31 related information */ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = BL31_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), #if DEBUG .ep_info.args.arg3 = ARM_BL31_PLAT_PARAM_VAL, #endif SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP), .image_info.image_base = BL31_BASE, .image_info.image_max_size = BL31_LIMIT - BL31_BASE, # ifdef BL32_BASE .next_handoff_image_id = BL32_IMAGE_ID, # else .next_handoff_image_id = BL33_IMAGE_ID, # endif }, /* Fill HW_CONFIG related information */ { .image_id = HW_CONFIG_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, VERSION_2, entry_point_info_t, NON_SECURE | NON_EXECUTABLE), SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), .next_handoff_image_id = INVALID_IMAGE_ID, }, /* Fill SOC_FW_CONFIG related information */ { .image_id = SOC_FW_CONFIG_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE), SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), .next_handoff_image_id = INVALID_IMAGE_ID, }, # ifdef BL32_BASE /* Fill BL32 related information */ { .image_id = BL32_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE), .ep_info.pc = BL32_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = BL32_BASE, .image_info.image_max_size = BL32_LIMIT - BL32_BASE, .next_handoff_image_id = BL33_IMAGE_ID, }, /* * Fill BL32 external 1 related information. * A typical use for extra1 image is with OP-TEE where it is the pager image. */ { .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), .image_info.image_base = BL32_BASE, .image_info.image_max_size = BL32_LIMIT - BL32_BASE, .next_handoff_image_id = INVALID_IMAGE_ID, }, /* * Fill BL32 external 2 related information. * A typical use for extra2 image is with OP-TEE where it is the paged image. */ { .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), #ifdef SPD_opteed .image_info.image_base = ARM_OPTEE_PAGEABLE_LOAD_BASE, .image_info.image_max_size = ARM_OPTEE_PAGEABLE_LOAD_SIZE, #endif .next_handoff_image_id = INVALID_IMAGE_ID, }, /* Fill TOS_FW_CONFIG related information */ { .image_id = TOS_FW_CONFIG_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE), SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), .next_handoff_image_id = INVALID_IMAGE_ID, }, # endif /* BL32_BASE */ /* Fill BL33 related information */ { .image_id = BL33_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), # ifdef PRELOADED_BL33_BASE .ep_info.pc = PRELOADED_BL33_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), # else .ep_info.pc = PLAT_ARM_NS_IMAGE_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = PLAT_ARM_NS_IMAGE_BASE, .image_info.image_max_size = ARM_DRAM1_BASE + ARM_DRAM1_SIZE - PLAT_ARM_NS_IMAGE_BASE, # endif /* PRELOADED_BL33_BASE */ .next_handoff_image_id = INVALID_IMAGE_ID, }, /* Fill NT_FW_CONFIG related information */ { .image_id = NT_FW_CONFIG_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, VERSION_2, entry_point_info_t, NON_SECURE | NON_EXECUTABLE), SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), .next_handoff_image_id = INVALID_IMAGE_ID, } #endif /* EL3_PAYLOAD_BASE */ }; REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) trusted-firmware-a-2.2/plat/arm/common/aarch64/arm_ehf.c000066400000000000000000000013751355360272700231230ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /* * Enumeration of priority levels on ARM platforms. */ ehf_pri_desc_t arm_exceptions[] = { #if RAS_EXTENSION /* RAS Priority */ EHF_PRI_DESC(ARM_PRI_BITS, PLAT_RAS_PRI), #endif #if SDEI_SUPPORT /* Critical priority SDEI */ EHF_PRI_DESC(ARM_PRI_BITS, PLAT_SDEI_CRITICAL_PRI), /* Normal priority SDEI */ EHF_PRI_DESC(ARM_PRI_BITS, PLAT_SDEI_NORMAL_PRI), #endif #if ENABLE_SPM EHF_PRI_DESC(ARM_PRI_BITS, PLAT_SP_PRI), #endif }; /* Plug in ARM exceptions to Exception Handling Framework. */ EHF_REGISTER_PRIORITIES(arm_exceptions, ARRAY_SIZE(arm_exceptions), ARM_PRI_BITS); trusted-firmware-a-2.2/plat/arm/common/aarch64/arm_helpers.S000066400000000000000000000103531355360272700237770ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .weak plat_arm_calc_core_pos .weak plat_my_core_pos .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush .globl platform_mem_init /* ----------------------------------------------------- * unsigned int plat_my_core_pos(void) * This function uses the plat_arm_calc_core_pos() * definition to get the index of the calling CPU. * ----------------------------------------------------- */ func plat_my_core_pos mrs x0, mpidr_el1 b plat_arm_calc_core_pos endfunc plat_my_core_pos /* ----------------------------------------------------- * unsigned int plat_arm_calc_core_pos(u_register_t mpidr) * Helper function to calculate the core position. * With this function: CorePos = (ClusterId * 4) + * CoreId * ----------------------------------------------------- */ func plat_arm_calc_core_pos and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 ret endfunc plat_arm_calc_core_pos /* --------------------------------------------- * int plat_crash_console_init(void) * Function to initialize the crash console * without a C Runtime to print crash report. * Clobber list : x0 - x4 * --------------------------------------------- */ func plat_crash_console_init mov_imm x0, PLAT_ARM_CRASH_UART_BASE mov_imm x1, PLAT_ARM_CRASH_UART_CLK_IN_HZ mov_imm x2, ARM_CONSOLE_BAUDRATE b console_pl011_core_init endfunc plat_crash_console_init /* --------------------------------------------- * int plat_crash_console_putc(int c) * Function to print a character on the crash * console without a C Runtime. * Clobber list : x1, x2 * --------------------------------------------- */ func plat_crash_console_putc mov_imm x1, PLAT_ARM_CRASH_UART_BASE b console_pl011_core_putc endfunc plat_crash_console_putc /* --------------------------------------------- * int plat_crash_console_flush() * Function to force a write of all buffered * data that hasn't been output. * Out : return -1 on error else return 0. * Clobber list : r0 * --------------------------------------------- */ func plat_crash_console_flush mov_imm x0, PLAT_ARM_CRASH_UART_BASE b console_pl011_core_flush endfunc plat_crash_console_flush /* --------------------------------------------------------------------- * We don't need to carry out any memory initialization on ARM * platforms. The Secure RAM is accessible straight away. * --------------------------------------------------------------------- */ func platform_mem_init ret endfunc platform_mem_init /* * Need to use coherent stack when ARM Cryptocell is used to autheticate images * since Cryptocell uses DMA to transfer data and it is not coherent with the * AP CPU. */ #if ARM_CRYPTOCELL_INTEG #if defined(IMAGE_BL1) || defined(IMAGE_BL2) .globl plat_get_my_stack .globl plat_set_my_stack .local platform_coherent_stacks /* ------------------------------------------------------- * uintptr_t plat_get_my_stack () * * For cold-boot BL images, only the primary CPU needs a * stack. This function returns the stack pointer for a * stack allocated in coherent memory. * ------------------------------------------------------- */ func plat_get_my_stack get_up_stack platform_coherent_stacks, PLATFORM_STACK_SIZE ret endfunc plat_get_my_stack /* ------------------------------------------------------- * void plat_set_my_stack () * * For cold-boot BL images, only the primary CPU needs a * stack. This function sets the stack pointer to a stack * allocated in coherent memory. * ------------------------------------------------------- */ func plat_set_my_stack get_up_stack platform_coherent_stacks, PLATFORM_STACK_SIZE mov sp, x0 ret endfunc plat_set_my_stack /* ---------------------------------------------------- * Single cpu stack in coherent memory. * ---------------------------------------------------- */ declare_stack platform_coherent_stacks, tzfw_coherent_mem, \ PLATFORM_STACK_SIZE, 1, CACHE_WRITEBACK_GRANULE #endif /* defined(IMAGE_BL1) || defined(IMAGE_BL2) */ #endif /* ARM_CRYPTOCELL_INTEG */ trusted-firmware-a-2.2/plat/arm/common/aarch64/arm_pauth.c000066400000000000000000000014531355360272700234770ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /* * This is only a toy implementation to generate a seemingly random * 128-bit key from sp, x30 and cntpct_el0 values. * A production system must re-implement this function to generate * keys from a reliable randomness source. */ uint128_t plat_init_apkey(void) { uint64_t return_addr = (uint64_t)__builtin_return_address(0U); uint64_t frame_addr = (uint64_t)__builtin_frame_address(0U); uint64_t cntpct = read_cntpct_el0(); /* Generate 128-bit key */ uint64_t key_lo = (return_addr << 13) ^ frame_addr ^ cntpct; uint64_t key_hi = (frame_addr << 15) ^ return_addr ^ cntpct; return ((uint128_t)(key_hi) << 64) | key_lo; } trusted-firmware-a-2.2/plat/arm/common/aarch64/arm_sdei.c000066400000000000000000000010351355360272700232760ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* SDEI configuration for ARM platforms */ #include #include #include /* Private event mappings */ static sdei_ev_map_t arm_sdei_private[] = { PLAT_ARM_PRIVATE_SDEI_EVENTS }; /* Shared event mappings */ static sdei_ev_map_t arm_sdei_shared[] = { PLAT_ARM_SHARED_SDEI_EVENTS }; /* Export ARM SDEI events */ REGISTER_SDEI_MAP(arm_sdei_private, arm_sdei_shared); trusted-firmware-a-2.2/plat/arm/common/arm_bl1_fwu.c000066400000000000000000000042111355360272700224600ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include /* Struct to keep track of usable memory */ typedef struct bl1_mem_info { uintptr_t mem_base; unsigned int mem_size; } bl1_mem_info_t; static bl1_mem_info_t fwu_addr_map_secure[] = { { .mem_base = ARM_SHARED_RAM_BASE, .mem_size = ARM_SHARED_RAM_SIZE }, { .mem_size = 0 } }; static bl1_mem_info_t fwu_addr_map_non_secure[] = { { .mem_base = ARM_NS_DRAM1_BASE, .mem_size = ARM_NS_DRAM1_SIZE }, { .mem_base = PLAT_ARM_NVM_BASE, .mem_size = PLAT_ARM_NVM_SIZE }, { .mem_size = 0 } }; int bl1_plat_mem_check(uintptr_t mem_base, unsigned int mem_size, unsigned int flags) { unsigned int index = 0; bl1_mem_info_t *mmap; assert(mem_base); assert(mem_size); /* * The caller of this function is responsible for checking upfront that * the end address doesn't overflow. We double-check this in debug * builds. */ assert(!check_uptr_overflow(mem_base, mem_size - 1)); /* * Check the given image source and size. */ if (GET_SECURITY_STATE(flags) == SECURE) mmap = fwu_addr_map_secure; else mmap = fwu_addr_map_non_secure; while (mmap[index].mem_size) { if ((mem_base >= mmap[index].mem_base) && ((mem_base + mem_size) <= (mmap[index].mem_base + mmap[index].mem_size))) return 0; index++; } return -ENOMEM; } /******************************************************************************* * This function does linear search for image_id and returns image_desc. ******************************************************************************/ image_desc_t *bl1_plat_get_image_desc(unsigned int image_id) { unsigned int index = 0; while (bl1_tbbr_image_descs[index].image_id != INVALID_IMAGE_ID) { if (bl1_tbbr_image_descs[index].image_id == image_id) return &bl1_tbbr_image_descs[index]; index++; } return NULL; } trusted-firmware-a-2.2/plat/arm/common/arm_bl1_setup.c000066400000000000000000000123621355360272700230250ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include /* Weak definitions may be overridden in specific ARM standard platform */ #pragma weak bl1_early_platform_setup #pragma weak bl1_plat_arch_setup #pragma weak bl1_plat_sec_mem_layout #pragma weak bl1_plat_prepare_exit #pragma weak bl1_plat_get_next_image_id #pragma weak plat_arm_bl1_fwu_needed #define MAP_BL1_TOTAL MAP_REGION_FLAT( \ bl1_tzram_layout.total_base, \ bl1_tzram_layout.total_size, \ MT_MEMORY | MT_RW | MT_SECURE) /* * If SEPARATE_CODE_AND_RODATA=1 we define a region for each section * otherwise one region is defined containing both */ #if SEPARATE_CODE_AND_RODATA #define MAP_BL1_RO MAP_REGION_FLAT( \ BL_CODE_BASE, \ BL1_CODE_END - BL_CODE_BASE, \ MT_CODE | MT_SECURE), \ MAP_REGION_FLAT( \ BL1_RO_DATA_BASE, \ BL1_RO_DATA_END \ - BL_RO_DATA_BASE, \ MT_RO_DATA | MT_SECURE) #else #define MAP_BL1_RO MAP_REGION_FLAT( \ BL_CODE_BASE, \ BL1_CODE_END - BL_CODE_BASE, \ MT_CODE | MT_SECURE) #endif /* Data structure which holds the extents of the trusted SRAM for BL1*/ static meminfo_t bl1_tzram_layout; struct meminfo *bl1_plat_sec_mem_layout(void) { return &bl1_tzram_layout; } /******************************************************************************* * BL1 specific platform actions shared between ARM standard platforms. ******************************************************************************/ void arm_bl1_early_platform_setup(void) { #if !ARM_DISABLE_TRUSTED_WDOG /* Enable watchdog */ plat_arm_secure_wdt_start(); #endif /* Initialize the console to provide early debug support */ arm_console_boot_init(); /* Allow BL1 to see the whole Trusted RAM */ bl1_tzram_layout.total_base = ARM_BL_RAM_BASE; bl1_tzram_layout.total_size = ARM_BL_RAM_SIZE; } void bl1_early_platform_setup(void) { arm_bl1_early_platform_setup(); /* * Initialize Interconnect for this cluster during cold boot. * No need for locks as no other CPU is active. */ plat_arm_interconnect_init(); /* * Enable Interconnect coherency for the primary CPU's cluster. */ plat_arm_interconnect_enter_coherency(); } /****************************************************************************** * Perform the very early platform specific architecture setup shared between * ARM standard platforms. This only does basic initialization. Later * architectural setup (bl1_arch_setup()) does not do anything platform * specific. *****************************************************************************/ void arm_bl1_plat_arch_setup(void) { #if USE_COHERENT_MEM && !ARM_CRYPTOCELL_INTEG /* * Ensure ARM platforms don't use coherent memory in BL1 unless * cryptocell integration is enabled. */ assert((BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE) == 0U); #endif const mmap_region_t bl_regions[] = { MAP_BL1_TOTAL, MAP_BL1_RO, #if USE_ROMLIB ARM_MAP_ROMLIB_CODE, ARM_MAP_ROMLIB_DATA, #endif #if ARM_CRYPTOCELL_INTEG ARM_MAP_BL_COHERENT_RAM, #endif {0} }; setup_page_tables(bl_regions, plat_arm_get_mmap()); #ifdef __aarch64__ enable_mmu_el3(0); #else enable_mmu_svc_mon(0); #endif /* __aarch64__ */ arm_setup_romlib(); } void bl1_plat_arch_setup(void) { arm_bl1_plat_arch_setup(); } /* * Perform the platform specific architecture setup shared between * ARM standard platforms. */ void arm_bl1_platform_setup(void) { /* Initialise the IO layer and register platform IO devices */ plat_arm_io_setup(); arm_load_tb_fw_config(); #if TRUSTED_BOARD_BOOT /* Share the Mbed TLS heap info with other images */ arm_bl1_set_mbedtls_heap(); #endif /* TRUSTED_BOARD_BOOT */ /* * Allow access to the System counter timer module and program * counter frequency for non secure images during FWU */ #ifdef ARM_SYS_TIMCTL_BASE arm_configure_sys_timer(); #endif #if (ARM_ARCH_MAJOR > 7) || defined(ARMV7_SUPPORTS_GENERIC_TIMER) write_cntfrq_el0(plat_get_syscnt_freq2()); #endif } void bl1_plat_prepare_exit(entry_point_info_t *ep_info) { #if !ARM_DISABLE_TRUSTED_WDOG /* Disable watchdog before leaving BL1 */ plat_arm_secure_wdt_stop(); #endif #ifdef EL3_PAYLOAD_BASE /* * Program the EL3 payload's entry point address into the CPUs mailbox * in order to release secondary CPUs from their holding pen and make * them jump there. */ plat_arm_program_trusted_mailbox(ep_info->pc); dsbsy(); sev(); #endif } /* * On Arm platforms, the FWU process is triggered when the FIP image has * been tampered with. */ int plat_arm_bl1_fwu_needed(void) { return (arm_io_is_toc_valid() != 1); } /******************************************************************************* * The following function checks if Firmware update is needed, * by checking if TOC in FIP image is valid or not. ******************************************************************************/ unsigned int bl1_plat_get_next_image_id(void) { if (plat_arm_bl1_fwu_needed() != 0) return NS_BL1U_IMAGE_ID; return BL2_IMAGE_ID; } trusted-firmware-a-2.2/plat/arm/common/arm_bl2_el3_setup.c000066400000000000000000000050241355360272700235660ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #pragma weak bl2_el3_early_platform_setup #pragma weak bl2_el3_plat_arch_setup #pragma weak bl2_el3_plat_prepare_exit #define MAP_BL2_EL3_TOTAL MAP_REGION_FLAT( \ bl2_el3_tzram_layout.total_base, \ bl2_el3_tzram_layout.total_size, \ MT_MEMORY | MT_RW | MT_SECURE) static meminfo_t bl2_el3_tzram_layout; /* * Perform arm specific early platform setup. At this moment we only initialize * the console and the memory layout. */ void arm_bl2_el3_early_platform_setup(void) { /* Initialize the console to provide early debug support */ arm_console_boot_init(); /* * Allow BL2 to see the whole Trusted RAM. This is determined * statically since we cannot rely on BL1 passing this information * in the BL2_AT_EL3 case. */ bl2_el3_tzram_layout.total_base = ARM_BL_RAM_BASE; bl2_el3_tzram_layout.total_size = ARM_BL_RAM_SIZE; /* Initialise the IO layer and register platform IO devices */ plat_arm_io_setup(); } void bl2_el3_early_platform_setup(u_register_t arg0 __unused, u_register_t arg1 __unused, u_register_t arg2 __unused, u_register_t arg3 __unused) { arm_bl2_el3_early_platform_setup(); /* * Initialize Interconnect for this cluster during cold boot. * No need for locks as no other CPU is active. */ plat_arm_interconnect_init(); /* * Enable Interconnect coherency for the primary CPU's cluster. */ plat_arm_interconnect_enter_coherency(); generic_delay_timer_init(); } /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this is only initializes the mmu in a quick and dirty way. ******************************************************************************/ void arm_bl2_el3_plat_arch_setup(void) { #if USE_COHERENT_MEM /* Ensure ARM platforms dont use coherent memory in BL2_AT_EL3 */ assert(BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE == 0U); #endif const mmap_region_t bl_regions[] = { MAP_BL2_EL3_TOTAL, ARM_MAP_BL_RO, {0} }; setup_page_tables(bl_regions, plat_arm_get_mmap()); #ifdef __aarch64__ enable_mmu_el3(0); #else enable_mmu_svc_mon(0); #endif } void bl2_el3_plat_arch_setup(void) { arm_bl2_el3_plat_arch_setup(); } void bl2_el3_plat_prepare_exit(void) { } trusted-firmware-a-2.2/plat/arm/common/arm_bl2_setup.c000066400000000000000000000130721355360272700230250ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #ifdef SPD_opteed #include #endif #include #include #include /* Data structure which holds the extents of the trusted SRAM for BL2 */ static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE); /* * Check that BL2_BASE is above ARM_TB_FW_CONFIG_LIMIT. This reserved page is * for `meminfo_t` data structure and fw_configs passed from BL1. */ CASSERT(BL2_BASE >= ARM_TB_FW_CONFIG_LIMIT, assert_bl2_base_overflows); /* Weak definitions may be overridden in specific ARM standard platform */ #pragma weak bl2_early_platform_setup2 #pragma weak bl2_platform_setup #pragma weak bl2_plat_arch_setup #pragma weak bl2_plat_sec_mem_layout #define MAP_BL2_TOTAL MAP_REGION_FLAT( \ bl2_tzram_layout.total_base, \ bl2_tzram_layout.total_size, \ MT_MEMORY | MT_RW | MT_SECURE) #pragma weak arm_bl2_plat_handle_post_image_load /******************************************************************************* * BL1 has passed the extents of the trusted SRAM that should be visible to BL2 * in x0. This memory layout is sitting at the base of the free trusted SRAM. * Copy it to a safe location before its reclaimed by later BL2 functionality. ******************************************************************************/ void arm_bl2_early_platform_setup(uintptr_t tb_fw_config, struct meminfo *mem_layout) { /* Initialize the console to provide early debug support */ arm_console_boot_init(); /* Setup the BL2 memory layout */ bl2_tzram_layout = *mem_layout; /* Initialise the IO layer and register platform IO devices */ plat_arm_io_setup(); if (tb_fw_config != 0U) arm_bl2_set_tb_cfg_addr((void *)tb_fw_config); } void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { arm_bl2_early_platform_setup((uintptr_t)arg0, (meminfo_t *)arg1); generic_delay_timer_init(); } /* * Perform BL2 preload setup. Currently we initialise the dynamic * configuration here. */ void bl2_plat_preload_setup(void) { arm_bl2_dyn_cfg_init(); } /* * Perform ARM standard platform setup. */ void arm_bl2_platform_setup(void) { /* Initialize the secure environment */ plat_arm_security_setup(); #if defined(PLAT_ARM_MEM_PROT_ADDR) arm_nor_psci_do_static_mem_protect(); #endif } void bl2_platform_setup(void) { arm_bl2_platform_setup(); } /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this is only initializes the mmu in a quick and dirty way. ******************************************************************************/ void arm_bl2_plat_arch_setup(void) { #if USE_COHERENT_MEM && !ARM_CRYPTOCELL_INTEG /* * Ensure ARM platforms don't use coherent memory in BL2 unless * cryptocell integration is enabled. */ assert((BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE) == 0U); #endif const mmap_region_t bl_regions[] = { MAP_BL2_TOTAL, ARM_MAP_BL_RO, #if USE_ROMLIB ARM_MAP_ROMLIB_CODE, ARM_MAP_ROMLIB_DATA, #endif #if ARM_CRYPTOCELL_INTEG ARM_MAP_BL_COHERENT_RAM, #endif {0} }; setup_page_tables(bl_regions, plat_arm_get_mmap()); #ifdef __aarch64__ enable_mmu_el1(0); #else enable_mmu_svc_mon(0); #endif arm_setup_romlib(); } void bl2_plat_arch_setup(void) { arm_bl2_plat_arch_setup(); } int arm_bl2_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); #ifdef SPD_opteed bl_mem_params_node_t *pager_mem_params = NULL; bl_mem_params_node_t *paged_mem_params = NULL; #endif assert(bl_mem_params); switch (image_id) { #ifdef __aarch64__ case BL32_IMAGE_ID: #ifdef SPD_opteed 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); err = parse_optee_header(&bl_mem_params->ep_info, &pager_mem_params->image_info, &paged_mem_params->image_info); if (err != 0) { WARN("OPTEE header parse error.\n"); } #endif bl_mem_params->ep_info.spsr = arm_get_spsr_for_bl32_entry(); break; #endif case BL33_IMAGE_ID: /* BL33 expects to receive the primary CPU MPID (through r0) */ bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr(); bl_mem_params->ep_info.spsr = arm_get_spsr_for_bl33_entry(); break; #ifdef SCP_BL2_BASE case SCP_BL2_IMAGE_ID: /* The subsequent handling of SCP_BL2 is platform specific */ err = plat_arm_bl2_handle_scp_bl2(&bl_mem_params->image_info); if (err) { WARN("Failure in platform-specific handling of SCP_BL2 image.\n"); } break; #endif default: /* Do nothing in default case */ break; } return err; } /******************************************************************************* * This function can be used by the platforms to update/use image * information for given `image_id`. ******************************************************************************/ int arm_bl2_plat_handle_post_image_load(unsigned int image_id) { return arm_bl2_handle_post_image_load(image_id); } int bl2_plat_handle_post_image_load(unsigned int image_id) { return arm_bl2_plat_handle_post_image_load(image_id); } trusted-firmware-a-2.2/plat/arm/common/arm_bl2u_setup.c000066400000000000000000000050261355360272700232120ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include /* Weak definitions may be overridden in specific ARM standard platform */ #pragma weak bl2u_platform_setup #pragma weak bl2u_early_platform_setup #pragma weak bl2u_plat_arch_setup #define MAP_BL2U_TOTAL MAP_REGION_FLAT( \ BL2U_BASE, \ BL2U_LIMIT - BL2U_BASE, \ MT_MEMORY | MT_RW | MT_SECURE) /* * Perform ARM standard platform setup for BL2U */ void arm_bl2u_platform_setup(void) { /* Initialize the secure environment */ plat_arm_security_setup(); } void bl2u_platform_setup(void) { arm_bl2u_platform_setup(); } void arm_bl2u_early_platform_setup(struct meminfo *mem_layout, void *plat_info) { /* Initialize the console to provide early debug support */ arm_console_boot_init(); generic_delay_timer_init(); } /******************************************************************************* * BL1 can pass platform dependent information to BL2U in x1. * In case of ARM CSS platforms x1 contains SCP_BL2U image info. * In case of ARM FVP platforms x1 is not used. * In both cases, x0 contains the extents of the memory available to BL2U ******************************************************************************/ void bl2u_early_platform_setup(struct meminfo *mem_layout, void *plat_info) { arm_bl2u_early_platform_setup(mem_layout, plat_info); } /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this is only initializes the mmu in a quick and dirty way. * The memory that is used by BL2U is only mapped. ******************************************************************************/ void arm_bl2u_plat_arch_setup(void) { #if USE_COHERENT_MEM /* Ensure ARM platforms dont use coherent memory in BL2U */ assert((BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE) == 0U); #endif const mmap_region_t bl_regions[] = { MAP_BL2U_TOTAL, ARM_MAP_BL_RO, #if USE_ROMLIB ARM_MAP_ROMLIB_CODE, ARM_MAP_ROMLIB_DATA, #endif {0} }; setup_page_tables(bl_regions, plat_arm_get_mmap()); #ifdef __aarch64__ enable_mmu_el1(0); #else enable_mmu_svc_mon(0); #endif arm_setup_romlib(); } void bl2u_plat_arch_setup(void) { arm_bl2u_plat_arch_setup(); } trusted-firmware-a-2.2/plat/arm/common/arm_bl31_setup.c000066400000000000000000000221301355360272700231020ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Placeholder variables for copying the arguments that have been passed to * BL31 from BL2. */ static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; #if !RESET_TO_BL31 /* * Check that BL31_BASE is above ARM_TB_FW_CONFIG_LIMIT. The reserved page * is required for SOC_FW_CONFIG/TOS_FW_CONFIG passed from BL2. */ CASSERT(BL31_BASE >= ARM_TB_FW_CONFIG_LIMIT, assert_bl31_base_overflows); #endif /* Weak definitions may be overridden in specific ARM standard platform */ #pragma weak bl31_early_platform_setup2 #pragma weak bl31_platform_setup #pragma weak bl31_plat_arch_setup #pragma weak bl31_plat_get_next_image_ep_info #define MAP_BL31_TOTAL MAP_REGION_FLAT( \ BL31_START, \ BL31_END - BL31_START, \ MT_MEMORY | MT_RW | MT_SECURE) #if RECLAIM_INIT_CODE IMPORT_SYM(unsigned long, __INIT_CODE_START__, BL_INIT_CODE_BASE); IMPORT_SYM(unsigned long, __INIT_CODE_END__, BL_INIT_CODE_END); #define MAP_BL_INIT_CODE MAP_REGION_FLAT( \ BL_INIT_CODE_BASE, \ BL_INIT_CODE_END \ - BL_INIT_CODE_BASE, \ MT_CODE | MT_SECURE) #endif /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for the * security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. ******************************************************************************/ struct entry_point_info *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; assert(sec_state_is_valid(type)); next_image_info = (type == NON_SECURE) ? &bl33_image_ep_info : &bl32_image_ep_info; /* * None of the images on the ARM development platforms can have 0x0 * as the entrypoint */ if (next_image_info->pc) return next_image_info; else return NULL; } /******************************************************************************* * Perform any BL31 early platform setup common to ARM standard platforms. * Here is an opportunity to copy parameters passed by the calling EL (S-EL1 * in BL2 & EL3 in BL1) before they are lost (potentially). This needs to be * done before the MMU is initialized so that the memory layout can be used * while creating page tables. BL2 has flushed this information to memory, so * we are guaranteed to pick up good data. ******************************************************************************/ void __init arm_bl31_early_platform_setup(void *from_bl2, uintptr_t soc_fw_config, uintptr_t hw_config, void *plat_params_from_bl2) { /* Initialize the console to provide early debug support */ arm_console_boot_init(); #if RESET_TO_BL31 /* There are no parameters from BL2 if BL31 is a reset vector */ assert(from_bl2 == NULL); assert(plat_params_from_bl2 == NULL); # ifdef BL32_BASE /* Populate entry point information for BL32 */ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0); SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); bl32_image_ep_info.pc = BL32_BASE; bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry(); # endif /* BL32_BASE */ /* Populate entry point information for BL33 */ SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); /* * Tell BL31 where the non-trusted software image * is located and the entry state information */ bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); bl33_image_ep_info.spsr = arm_get_spsr_for_bl33_entry(); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); # if ARM_LINUX_KERNEL_AS_BL33 /* * According to the file ``Documentation/arm64/booting.txt`` of the * Linux kernel tree, Linux expects the physical address of the device * tree blob (DTB) in x0, while x1-x3 are reserved for future use and * must be 0. */ bl33_image_ep_info.args.arg0 = (u_register_t)ARM_PRELOADED_DTB_BASE; bl33_image_ep_info.args.arg1 = 0U; bl33_image_ep_info.args.arg2 = 0U; bl33_image_ep_info.args.arg3 = 0U; # endif #else /* RESET_TO_BL31 */ /* * In debug builds, we pass a special value in 'plat_params_from_bl2' * to verify platform parameters from BL2 to BL31. * In release builds, it's not used. */ assert(((unsigned long long)plat_params_from_bl2) == ARM_BL31_PLAT_PARAM_VAL); /* * Check params passed from BL2 should not be NULL, */ bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2; assert(params_from_bl2 != NULL); assert(params_from_bl2->h.type == PARAM_BL_PARAMS); assert(params_from_bl2->h.version >= VERSION_2); bl_params_node_t *bl_params = params_from_bl2->head; /* * Copy BL33 and BL32 (if present), entry point information. * They are stored in Secure RAM, in BL2's address space. */ while (bl_params != NULL) { if (bl_params->image_id == BL32_IMAGE_ID) bl32_image_ep_info = *bl_params->ep_info; if (bl_params->image_id == BL33_IMAGE_ID) bl33_image_ep_info = *bl_params->ep_info; bl_params = bl_params->next_params_info; } if (bl33_image_ep_info.pc == 0U) panic(); #endif /* RESET_TO_BL31 */ } void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3); /* * Initialize Interconnect for this cluster during cold boot. * No need for locks as no other CPU is active. */ plat_arm_interconnect_init(); /* * Enable Interconnect coherency for the primary CPU's cluster. * Earlier bootloader stages might already do this (e.g. Trusted * Firmware's BL1 does it) but we can't assume so. There is no harm in * executing this code twice anyway. * Platform specific PSCI code will enable coherency for other * clusters. */ plat_arm_interconnect_enter_coherency(); } /******************************************************************************* * Perform any BL31 platform setup common to ARM standard platforms ******************************************************************************/ void arm_bl31_platform_setup(void) { /* Initialize the GIC driver, cpu and distributor interfaces */ plat_arm_gic_driver_init(); plat_arm_gic_init(); #if RESET_TO_BL31 /* * Do initial security configuration to allow DRAM/device access * (if earlier BL has not already done so). */ plat_arm_security_setup(); #if defined(PLAT_ARM_MEM_PROT_ADDR) arm_nor_psci_do_dyn_mem_protect(); #endif /* PLAT_ARM_MEM_PROT_ADDR */ #endif /* RESET_TO_BL31 */ /* Enable and initialize the System level generic timer */ mmio_write_32(ARM_SYS_CNTCTL_BASE + CNTCR_OFF, CNTCR_FCREQ(0U) | CNTCR_EN); /* Allow access to the System counter timer module */ arm_configure_sys_timer(); /* Initialize power controller before setting up topology */ plat_arm_pwrc_setup(); #if RAS_EXTENSION ras_init(); #endif } /******************************************************************************* * Perform any BL31 platform runtime setup prior to BL31 exit common to ARM * standard platforms * Perform BL31 platform setup ******************************************************************************/ void arm_bl31_plat_runtime_setup(void) { console_switch_state(CONSOLE_FLAG_RUNTIME); /* Initialize the runtime console */ arm_console_runtime_init(); #if RECLAIM_INIT_CODE arm_free_init_memory(); #endif } #if RECLAIM_INIT_CODE /* * Zero out and make RW memory used to store image boot time code so it can * be reclaimed during runtime */ void arm_free_init_memory(void) { int ret = xlat_change_mem_attributes(BL_INIT_CODE_BASE, BL_INIT_CODE_END - BL_INIT_CODE_BASE, MT_RW_DATA); if (ret != 0) { ERROR("Could not reclaim initialization code"); panic(); } } #endif void __init bl31_platform_setup(void) { arm_bl31_platform_setup(); } void bl31_plat_runtime_setup(void) { arm_bl31_plat_runtime_setup(); } /******************************************************************************* * Perform the very early platform specific architectural setup shared between * ARM standard platforms. This only does basic initialization. Later * architectural setup (bl31_arch_setup()) does not do anything platform * specific. ******************************************************************************/ void __init arm_bl31_plat_arch_setup(void) { const mmap_region_t bl_regions[] = { MAP_BL31_TOTAL, #if RECLAIM_INIT_CODE MAP_BL_INIT_CODE, #endif ARM_MAP_BL_RO, #if USE_ROMLIB ARM_MAP_ROMLIB_CODE, ARM_MAP_ROMLIB_DATA, #endif #if USE_COHERENT_MEM ARM_MAP_BL_COHERENT_RAM, #endif {0} }; setup_page_tables(bl_regions, plat_arm_get_mmap()); enable_mmu_el3(0); arm_setup_romlib(); } void __init bl31_plat_arch_setup(void) { arm_bl31_plat_arch_setup(); } trusted-firmware-a-2.2/plat/arm/common/arm_cci.c000066400000000000000000000034071355360272700216650ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include static const int cci_map[] = { PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX, PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX }; /****************************************************************************** * The following functions are defined as weak to allow a platform to override * the way ARM CCI driver is initialised and used. *****************************************************************************/ #pragma weak plat_arm_interconnect_init #pragma weak plat_arm_interconnect_enter_coherency #pragma weak plat_arm_interconnect_exit_coherency /****************************************************************************** * Helper function to initialize ARM CCI driver. *****************************************************************************/ void __init plat_arm_interconnect_init(void) { cci_init(PLAT_ARM_CCI_BASE, cci_map, ARRAY_SIZE(cci_map)); } /****************************************************************************** * Helper function to place current master into coherency *****************************************************************************/ void plat_arm_interconnect_enter_coherency(void) { cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); } /****************************************************************************** * Helper function to remove current master from coherency *****************************************************************************/ void plat_arm_interconnect_exit_coherency(void) { cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); } trusted-firmware-a-2.2/plat/arm/common/arm_ccn.c000066400000000000000000000037501355360272700216730ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include static const unsigned char master_to_rn_id_map[] = { PLAT_ARM_CLUSTER_TO_CCN_ID_MAP }; static const ccn_desc_t arm_ccn_desc = { .periphbase = PLAT_ARM_CCN_BASE, .num_masters = ARRAY_SIZE(master_to_rn_id_map), .master_to_rn_id_map = master_to_rn_id_map }; CASSERT(PLAT_ARM_CLUSTER_COUNT == ARRAY_SIZE(master_to_rn_id_map), assert_invalid_cluster_count_for_ccn_variant); /****************************************************************************** * The following functions are defined as weak to allow a platform to override * the way ARM CCN driver is initialised and used. *****************************************************************************/ #pragma weak plat_arm_interconnect_init #pragma weak plat_arm_interconnect_enter_coherency #pragma weak plat_arm_interconnect_exit_coherency /****************************************************************************** * Helper function to initialize ARM CCN driver. *****************************************************************************/ void __init plat_arm_interconnect_init(void) { ccn_init(&arm_ccn_desc); } /****************************************************************************** * Helper function to place current master into coherency *****************************************************************************/ void plat_arm_interconnect_enter_coherency(void) { ccn_enter_snoop_dvm_domain(1 << MPIDR_AFFLVL1_VAL(read_mpidr_el1())); } /****************************************************************************** * Helper function to remove current master from coherency *****************************************************************************/ void plat_arm_interconnect_exit_coherency(void) { ccn_exit_snoop_dvm_domain(1 << MPIDR_AFFLVL1_VAL(read_mpidr_el1())); } trusted-firmware-a-2.2/plat/arm/common/arm_common.c000066400000000000000000000137201355360272700224160ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include /* Weak definitions may be overridden in specific ARM standard platform */ #pragma weak plat_get_ns_image_entrypoint #pragma weak plat_arm_get_mmap /* Conditionally provide a weak definition of plat_get_syscnt_freq2 to avoid * conflicts with the definition in plat/common. */ #pragma weak plat_get_syscnt_freq2 void arm_setup_romlib(void) { #if USE_ROMLIB if (!rom_lib_init(ROMLIB_VERSION)) panic(); #endif } uintptr_t plat_get_ns_image_entrypoint(void) { #ifdef PRELOADED_BL33_BASE return PRELOADED_BL33_BASE; #else return PLAT_ARM_NS_IMAGE_BASE; #endif } /******************************************************************************* * Gets SPSR for BL32 entry ******************************************************************************/ uint32_t arm_get_spsr_for_bl32_entry(void) { /* * The Secure Payload Dispatcher service is responsible for * setting the SPSR prior to entry into the BL32 image. */ return 0; } /******************************************************************************* * Gets SPSR for BL33 entry ******************************************************************************/ #ifdef __aarch64__ uint32_t arm_get_spsr_for_bl33_entry(void) { unsigned int mode; uint32_t spsr; /* Figure out what mode we enter the non-secure world in */ mode = (el_implemented(2) != EL_IMPL_NONE) ? MODE_EL2 : MODE_EL1; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; } #else /******************************************************************************* * Gets SPSR for BL33 entry ******************************************************************************/ uint32_t arm_get_spsr_for_bl33_entry(void) { unsigned int hyp_status, mode, spsr; hyp_status = GET_VIRT_EXT(read_id_pfr1()); mode = (hyp_status) ? MODE32_hyp : MODE32_svc; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_MODE32(mode, plat_get_ns_image_entrypoint() & 0x1, SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS); return spsr; } #endif /* __aarch64__ */ /******************************************************************************* * Configures access to the system counter timer module. ******************************************************************************/ #ifdef ARM_SYS_TIMCTL_BASE void arm_configure_sys_timer(void) { unsigned int reg_val; /* Read the frequency of the system counter */ unsigned int freq_val = plat_get_syscnt_freq2(); #if ARM_CONFIG_CNTACR reg_val = (1U << CNTACR_RPCT_SHIFT) | (1U << CNTACR_RVCT_SHIFT); reg_val |= (1U << CNTACR_RFRQ_SHIFT) | (1U << CNTACR_RVOFF_SHIFT); reg_val |= (1U << CNTACR_RWVT_SHIFT) | (1U << CNTACR_RWPT_SHIFT); mmio_write_32(ARM_SYS_TIMCTL_BASE + CNTACR_BASE(PLAT_ARM_NSTIMER_FRAME_ID), reg_val); #endif /* ARM_CONFIG_CNTACR */ reg_val = (1U << CNTNSAR_NS_SHIFT(PLAT_ARM_NSTIMER_FRAME_ID)); mmio_write_32(ARM_SYS_TIMCTL_BASE + CNTNSAR, reg_val); /* * Initialize CNTFRQ register in CNTCTLBase frame. The CNTFRQ * system register initialized during psci_arch_setup() is different * from this and has to be updated independently. */ mmio_write_32(ARM_SYS_TIMCTL_BASE + CNTCTLBASE_CNTFRQ, freq_val); #if defined(PLAT_juno) || defined(PLAT_n1sdp) /* * Initialize CNTFRQ register in Non-secure CNTBase frame. * This is only required for Juno and N1SDP, because they do not * follow ARM ARM in that the value updated in CNTFRQ is not * reflected in CNTBASEN_CNTFRQ. Hence update the value manually. */ mmio_write_32(ARM_SYS_CNT_BASE_NS + CNTBASEN_CNTFRQ, freq_val); #endif } #endif /* ARM_SYS_TIMCTL_BASE */ /******************************************************************************* * Returns ARM platform specific memory map regions. ******************************************************************************/ const mmap_region_t *plat_arm_get_mmap(void) { return plat_arm_mmap; } #ifdef ARM_SYS_CNTCTL_BASE unsigned int plat_get_syscnt_freq2(void) { unsigned int counter_base_frequency; /* Read the frequency from Frequency modes table */ counter_base_frequency = mmio_read_32(ARM_SYS_CNTCTL_BASE + CNTFID_OFF); /* The first entry of the frequency modes table must not be 0 */ if (counter_base_frequency == 0U) panic(); return counter_base_frequency; } #endif /* ARM_SYS_CNTCTL_BASE */ #if SDEI_SUPPORT /* * Translate SDEI entry point to PA, and perform standard ARM entry point * validation on it. */ int plat_sdei_validate_entry_point(uintptr_t ep, unsigned int client_mode) { uint64_t par, pa; uint32_t scr_el3; /* Doing Non-secure address translation requires SCR_EL3.NS set */ scr_el3 = read_scr_el3(); write_scr_el3(scr_el3 | SCR_NS_BIT); isb(); assert((client_mode == MODE_EL2) || (client_mode == MODE_EL1)); if (client_mode == MODE_EL2) { /* * Translate entry point to Physical Address using the EL2 * translation regime. */ ats1e2r(ep); } else { /* * Translate entry point to Physical Address using the EL1&0 * translation regime, including stage 2. */ ats12e1r(ep); } isb(); par = read_par_el1(); /* Restore original SCRL_EL3 */ write_scr_el3(scr_el3); isb(); /* If the translation resulted in fault, return failure */ if ((par & PAR_F_MASK) != 0) return -1; /* Extract Physical Address from PAR */ pa = (par & (PAR_ADDR_MASK << PAR_ADDR_SHIFT)); /* Perform NS entry point validation on the physical address */ return arm_validate_ns_entrypoint(pa); } #endif trusted-firmware-a-2.2/plat/arm/common/arm_common.mk000066400000000000000000000211551355360272700226040ustar00rootroot00000000000000# # Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ifeq (${ARCH}, aarch64) # On ARM standard platorms, the TSP can execute from Trusted SRAM, Trusted # DRAM (if available) or the TZC secured area of DRAM. # TZC secured DRAM is the default. ARM_TSP_RAM_LOCATION ?= dram ifeq (${ARM_TSP_RAM_LOCATION}, tsram) ARM_TSP_RAM_LOCATION_ID = ARM_TRUSTED_SRAM_ID else ifeq (${ARM_TSP_RAM_LOCATION}, tdram) ARM_TSP_RAM_LOCATION_ID = ARM_TRUSTED_DRAM_ID else ifeq (${ARM_TSP_RAM_LOCATION}, dram) ARM_TSP_RAM_LOCATION_ID = ARM_DRAM_ID else $(error "Unsupported ARM_TSP_RAM_LOCATION value") endif # Process flags # Process ARM_BL31_IN_DRAM flag ARM_BL31_IN_DRAM := 0 $(eval $(call assert_boolean,ARM_BL31_IN_DRAM)) $(eval $(call add_define,ARM_BL31_IN_DRAM)) else ARM_TSP_RAM_LOCATION_ID = ARM_TRUSTED_SRAM_ID endif $(eval $(call add_define,ARM_TSP_RAM_LOCATION_ID)) # For the original power-state parameter format, the State-ID can be encoded # according to the recommended encoding or zero. This flag determines which # State-ID encoding to be parsed. ARM_RECOM_STATE_ID_ENC := 0 # If the PSCI_EXTENDED_STATE_ID is set, then ARM_RECOM_STATE_ID_ENC need to # be set. Else throw a build error. ifeq (${PSCI_EXTENDED_STATE_ID}, 1) ifeq (${ARM_RECOM_STATE_ID_ENC}, 0) $(error Build option ARM_RECOM_STATE_ID_ENC needs to be set if \ PSCI_EXTENDED_STATE_ID is set for ARM platforms) endif endif # Process ARM_RECOM_STATE_ID_ENC flag $(eval $(call assert_boolean,ARM_RECOM_STATE_ID_ENC)) $(eval $(call add_define,ARM_RECOM_STATE_ID_ENC)) # Process ARM_DISABLE_TRUSTED_WDOG flag # By default, Trusted Watchdog is always enabled unless SPIN_ON_BL1_EXIT is set ARM_DISABLE_TRUSTED_WDOG := 0 ifeq (${SPIN_ON_BL1_EXIT}, 1) ARM_DISABLE_TRUSTED_WDOG := 1 endif $(eval $(call assert_boolean,ARM_DISABLE_TRUSTED_WDOG)) $(eval $(call add_define,ARM_DISABLE_TRUSTED_WDOG)) # Process ARM_CONFIG_CNTACR ARM_CONFIG_CNTACR := 1 $(eval $(call assert_boolean,ARM_CONFIG_CNTACR)) $(eval $(call add_define,ARM_CONFIG_CNTACR)) # Process ARM_BL31_IN_DRAM flag ARM_BL31_IN_DRAM := 0 $(eval $(call assert_boolean,ARM_BL31_IN_DRAM)) $(eval $(call add_define,ARM_BL31_IN_DRAM)) # Process ARM_PLAT_MT flag ARM_PLAT_MT := 0 $(eval $(call assert_boolean,ARM_PLAT_MT)) $(eval $(call add_define,ARM_PLAT_MT)) # Use translation tables library v2 by default ARM_XLAT_TABLES_LIB_V1 := 0 $(eval $(call assert_boolean,ARM_XLAT_TABLES_LIB_V1)) $(eval $(call add_define,ARM_XLAT_TABLES_LIB_V1)) # Don't have the Linux kernel as a BL33 image by default ARM_LINUX_KERNEL_AS_BL33 := 0 $(eval $(call assert_boolean,ARM_LINUX_KERNEL_AS_BL33)) $(eval $(call add_define,ARM_LINUX_KERNEL_AS_BL33)) ifeq (${ARM_LINUX_KERNEL_AS_BL33},1) ifeq (${ARCH},aarch64) ifneq (${RESET_TO_BL31},1) $(error "ARM_LINUX_KERNEL_AS_BL33 is only available if RESET_TO_BL31=1.") endif else ifneq (${RESET_TO_SP_MIN},1) $(error "ARM_LINUX_KERNEL_AS_BL33 is only available if RESET_TO_SP_MIN=1.") endif endif ifndef PRELOADED_BL33_BASE $(error "PRELOADED_BL33_BASE must be set if ARM_LINUX_KERNEL_AS_BL33 is used.") endif ifndef ARM_PRELOADED_DTB_BASE $(error "ARM_PRELOADED_DTB_BASE must be set if ARM_LINUX_KERNEL_AS_BL33 is used.") endif $(eval $(call add_define,ARM_PRELOADED_DTB_BASE)) endif # Use an implementation of SHA-256 with a smaller memory footprint but reduced # speed. $(eval $(call add_define,MBEDTLS_SHA256_SMALLER)) # Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images # in the FIP if the platform requires. ifneq ($(BL32_EXTRA1),) $(eval $(call TOOL_ADD_IMG,bl32_extra1,--tos-fw-extra1)) endif ifneq ($(BL32_EXTRA2),) $(eval $(call TOOL_ADD_IMG,bl32_extra2,--tos-fw-extra2)) endif # Enable PSCI_STAT_COUNT/RESIDENCY APIs on ARM platforms ENABLE_PSCI_STAT := 1 ENABLE_PMF := 1 # On ARM platforms, separate the code and read-only data sections to allow # mapping the former as executable and the latter as execute-never. SEPARATE_CODE_AND_RODATA := 1 # Disable ARM Cryptocell by default ARM_CRYPTOCELL_INTEG := 0 $(eval $(call assert_boolean,ARM_CRYPTOCELL_INTEG)) $(eval $(call add_define,ARM_CRYPTOCELL_INTEG)) # CryptoCell integration relies on coherent buffers for passing data from # the AP CPU to the CryptoCell ifeq (${ARM_CRYPTOCELL_INTEG},1) ifeq (${USE_COHERENT_MEM},0) $(error "ARM_CRYPTOCELL_INTEG needs USE_COHERENT_MEM to be set.") endif endif ifeq (${ARCH}, aarch64) PLAT_INCLUDES += -Iinclude/plat/arm/common/aarch64 endif PLAT_BL_COMMON_SOURCES += plat/arm/common/${ARCH}/arm_helpers.S \ plat/arm/common/arm_common.c \ plat/arm/common/arm_console.c ifeq (${ARM_XLAT_TABLES_LIB_V1}, 1) PLAT_BL_COMMON_SOURCES += lib/xlat_tables/xlat_tables_common.c \ lib/xlat_tables/${ARCH}/xlat_tables.c else include lib/xlat_tables_v2/xlat_tables.mk PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} endif BL1_SOURCES += drivers/io/io_fip.c \ drivers/io/io_memmap.c \ drivers/io/io_storage.c \ plat/arm/common/arm_bl1_setup.c \ plat/arm/common/arm_err.c \ plat/arm/common/arm_io_storage.c ifdef EL3_PAYLOAD_BASE # Need the plat_arm_program_trusted_mailbox() function to release secondary CPUs from # their holding pen BL1_SOURCES += plat/arm/common/arm_pm.c endif BL2_SOURCES += drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/io/io_fip.c \ drivers/io/io_memmap.c \ drivers/io/io_storage.c \ plat/arm/common/arm_bl2_setup.c \ plat/arm/common/arm_err.c \ plat/arm/common/arm_io_storage.c # Add `libfdt` and Arm common helpers required for Dynamic Config include lib/libfdt/libfdt.mk DYN_CFG_SOURCES += plat/arm/common/arm_dyn_cfg.c \ plat/arm/common/arm_dyn_cfg_helpers.c \ common/fdt_wrappers.c BL1_SOURCES += ${DYN_CFG_SOURCES} BL2_SOURCES += ${DYN_CFG_SOURCES} ifeq (${BL2_AT_EL3},1) BL2_SOURCES += plat/arm/common/arm_bl2_el3_setup.c endif # Because BL1/BL2 execute in AArch64 mode but BL32 in AArch32 we need to use # the AArch32 descriptors. ifeq (${JUNO_AARCH32_EL3_RUNTIME},1) BL2_SOURCES += plat/arm/common/aarch32/arm_bl2_mem_params_desc.c else BL2_SOURCES += plat/arm/common/${ARCH}/arm_bl2_mem_params_desc.c endif BL2_SOURCES += plat/arm/common/arm_image_load.c \ common/desc_image_load.c ifeq (${SPD},opteed) BL2_SOURCES += lib/optee/optee_utils.c endif BL2U_SOURCES += drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ plat/arm/common/arm_bl2u_setup.c BL31_SOURCES += plat/arm/common/arm_bl31_setup.c \ plat/arm/common/arm_pm.c \ plat/arm/common/arm_topology.c \ plat/arm/common/execution_state_switch.c \ plat/common/plat_psci_common.c ifeq (${ENABLE_PMF}, 1) BL31_SOURCES += plat/arm/common/arm_sip_svc.c \ lib/pmf/pmf_smc.c endif ifeq (${EL3_EXCEPTION_HANDLING},1) BL31_SOURCES += plat/arm/common/aarch64/arm_ehf.c endif ifeq (${SDEI_SUPPORT},1) BL31_SOURCES += plat/arm/common/aarch64/arm_sdei.c endif # RAS sources ifeq (${RAS_EXTENSION},1) BL31_SOURCES += lib/extensions/ras/std_err_record.c \ lib/extensions/ras/ras_common.c endif # Pointer Authentication sources ifeq (${ENABLE_PAUTH}, 1) PLAT_BL_COMMON_SOURCES += plat/arm/common/aarch64/arm_pauth.c \ lib/extensions/pauth/pauth_helpers.S endif # SPM uses libfdt in Arm platforms ifeq (${SPM_MM},0) ifeq (${ENABLE_SPM},1) BL31_SOURCES += common/fdt_wrappers.c \ plat/common/plat_spm_rd.c \ plat/common/plat_spm_sp.c \ ${LIBFDT_SRCS} endif endif ifneq (${TRUSTED_BOARD_BOOT},0) # Include common TBB sources AUTH_SOURCES := drivers/auth/auth_mod.c \ drivers/auth/crypto_mod.c \ drivers/auth/img_parser_mod.c \ drivers/auth/tbbr/tbbr_cot.c \ BL1_SOURCES += ${AUTH_SOURCES} \ bl1/tbbr/tbbr_img_desc.c \ plat/arm/common/arm_bl1_fwu.c \ plat/common/tbbr/plat_tbbr.c BL2_SOURCES += ${AUTH_SOURCES} \ plat/common/tbbr/plat_tbbr.c $(eval $(call TOOL_ADD_IMG,ns_bl2u,--fwu,FWU_)) # We expect to locate the *.mk files under the directories specified below ifeq (${ARM_CRYPTOCELL_INTEG},0) CRYPTO_LIB_MK := drivers/auth/mbedtls/mbedtls_crypto.mk else CRYPTO_LIB_MK := drivers/auth/cryptocell/cryptocell_crypto.mk endif IMG_PARSER_LIB_MK := drivers/auth/mbedtls/mbedtls_x509.mk $(info Including ${CRYPTO_LIB_MK}) include ${CRYPTO_LIB_MK} $(info Including ${IMG_PARSER_LIB_MK}) include ${IMG_PARSER_LIB_MK} endif ifeq (${RECLAIM_INIT_CODE}, 1) ifeq (${ARM_XLAT_TABLES_LIB_V1}, 1) $(error "To reclaim init code xlat tables v2 must be used") endif endif trusted-firmware-a-2.2/plat/arm/common/arm_console.c000066400000000000000000000031251355360272700225660ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /******************************************************************************* * Functions that set up the console ******************************************************************************/ static console_pl011_t arm_boot_console; static console_pl011_t arm_runtime_console; /* Initialize the console to provide early debug support */ void __init arm_console_boot_init(void) { int rc = console_pl011_register(PLAT_ARM_BOOT_UART_BASE, PLAT_ARM_BOOT_UART_CLK_IN_HZ, ARM_CONSOLE_BAUDRATE, &arm_boot_console); if (rc == 0) { /* * The crash console doesn't use the multi console API, it uses * the core console functions directly. It is safe to call panic * and let it print debug information. */ panic(); } console_set_scope(&arm_boot_console.console, CONSOLE_FLAG_BOOT); } void arm_console_boot_end(void) { (void)console_flush(); (void)console_unregister(&arm_boot_console.console); } /* Initialize the runtime console */ void arm_console_runtime_init(void) { int rc = console_pl011_register(PLAT_ARM_RUN_UART_BASE, PLAT_ARM_RUN_UART_CLK_IN_HZ, ARM_CONSOLE_BAUDRATE, &arm_runtime_console); if (rc == 0) panic(); console_set_scope(&arm_runtime_console.console, CONSOLE_FLAG_RUNTIME); } void arm_console_runtime_end(void) { (void)console_flush(); } trusted-firmware-a-2.2/plat/arm/common/arm_dyn_cfg.c000066400000000000000000000170411355360272700225370ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #if TRUSTED_BOARD_BOOT #include #endif #include #include #include /* Variable to store the address to TB_FW_CONFIG passed from BL1 */ static void *tb_fw_cfg_dtb; static size_t tb_fw_cfg_dtb_size; #if TRUSTED_BOARD_BOOT static void *mbedtls_heap_addr; static size_t mbedtls_heap_size; /* * This function is the implementation of the shared Mbed TLS heap between * BL1 and BL2 for Arm platforms. The shared heap address is passed from BL1 * to BL2 with a pointer. This pointer resides inside the TB_FW_CONFIG file * which is a DTB. * * This function is placed inside an #if directive for the below reasons: * - To allocate space for the Mbed TLS heap --only if-- Trusted Board Boot * is enabled. * - This implementation requires the DTB to be present so that BL1 has a * mechanism to pass the pointer to BL2. */ int arm_get_mbedtls_heap(void **heap_addr, size_t *heap_size) { assert(heap_addr != NULL); assert(heap_size != NULL); #if defined(IMAGE_BL1) || BL2_AT_EL3 /* If in BL1 or BL2_AT_EL3 define a heap */ static unsigned char heap[TF_MBEDTLS_HEAP_SIZE]; *heap_addr = heap; *heap_size = sizeof(heap); mbedtls_heap_addr = heap; mbedtls_heap_size = sizeof(heap); #elif defined(IMAGE_BL2) int err; /* If in BL2, retrieve the already allocated heap's info from DTB */ if (tb_fw_cfg_dtb != NULL) { err = arm_get_dtb_mbedtls_heap_info(tb_fw_cfg_dtb, heap_addr, heap_size); if (err < 0) { ERROR("BL2: unable to retrieve shared Mbed TLS heap information from DTB\n"); panic(); } } else { ERROR("BL2: DTB missing, cannot get Mbed TLS heap\n"); panic(); } #endif return 0; } /* * Puts the shared Mbed TLS heap information to the DTB. * Executed only from BL1. */ void arm_bl1_set_mbedtls_heap(void) { int err; /* * If tb_fw_cfg_dtb==NULL then DTB is not present for the current * platform. As such, we don't attempt to write to the DTB at all. * * If mbedtls_heap_addr==NULL, then it means we are using the default * heap implementation. As such, BL2 will have its own heap for sure * and hence there is no need to pass any information to the DTB. * * In the latter case, if we still wanted to write in the DTB the heap * information, we would need to call plat_get_mbedtls_heap to retrieve * the default heap's address and size. */ if ((tb_fw_cfg_dtb != NULL) && (mbedtls_heap_addr != NULL)) { err = arm_set_dtb_mbedtls_heap_info(tb_fw_cfg_dtb, mbedtls_heap_addr, mbedtls_heap_size); if (err < 0) { ERROR("BL1: unable to write shared Mbed TLS heap information to DTB\n"); panic(); } /* * Ensure that the info written to the DTB is visible to other * images. It's critical because BL2 won't be able to proceed * without the heap info. */ flush_dcache_range((uintptr_t)tb_fw_cfg_dtb, tb_fw_cfg_dtb_size); } } #endif /* TRUSTED_BOARD_BOOT */ /* * Helper function to load TB_FW_CONFIG and populate the load information to * arg0 of BL2 entrypoint info. */ void arm_load_tb_fw_config(void) { int err; uintptr_t config_base = 0UL; image_desc_t *desc; image_desc_t arm_tb_fw_info = { .image_id = TB_FW_CONFIG_ID, SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, VERSION_2, image_info_t, 0), .image_info.image_base = ARM_TB_FW_CONFIG_BASE, .image_info.image_max_size = ARM_TB_FW_CONFIG_LIMIT - ARM_TB_FW_CONFIG_BASE }; VERBOSE("BL1: Loading TB_FW_CONFIG\n"); err = load_auth_image(TB_FW_CONFIG_ID, &arm_tb_fw_info.image_info); if (err != 0) { /* Return if TB_FW_CONFIG is not loaded */ VERBOSE("Failed to load TB_FW_CONFIG\n"); return; } /* At this point we know that a DTB is indeed available */ config_base = arm_tb_fw_info.image_info.image_base; tb_fw_cfg_dtb = (void *)config_base; tb_fw_cfg_dtb_size = (size_t)arm_tb_fw_info.image_info.image_max_size; /* The BL2 ep_info arg0 is modified to point to TB_FW_CONFIG */ desc = bl1_plat_get_image_desc(BL2_IMAGE_ID); assert(desc != NULL); desc->ep_info.args.arg0 = config_base; INFO("BL1: TB_FW_CONFIG loaded at address = 0x%lx\n", config_base); #if TRUSTED_BOARD_BOOT && defined(DYN_DISABLE_AUTH) int tb_fw_node; uint32_t disable_auth = 0; err = arm_dyn_tb_fw_cfg_init((void *)config_base, &tb_fw_node); if (err < 0) { ERROR("Invalid TB_FW_CONFIG loaded\n"); panic(); } err = arm_dyn_get_disable_auth((void *)config_base, tb_fw_node, &disable_auth); if (err < 0) return; if (disable_auth == 1) dyn_disable_auth(); #endif } /* * BL2 utility function to set the address of TB_FW_CONFIG passed from BL1. */ void arm_bl2_set_tb_cfg_addr(void *dtb) { assert(dtb != NULL); tb_fw_cfg_dtb = dtb; } /* * BL2 utility function to initialize dynamic configuration specified by * TB_FW_CONFIG. Populate the bl_mem_params_node_t of other FW_CONFIGs if * specified in TB_FW_CONFIG. */ void arm_bl2_dyn_cfg_init(void) { int err = 0, tb_fw_node; unsigned int i; bl_mem_params_node_t *cfg_mem_params = NULL; uint64_t image_base; uint32_t image_size; const unsigned int config_ids[] = { HW_CONFIG_ID, SOC_FW_CONFIG_ID, NT_FW_CONFIG_ID, #ifdef SPD_tspd /* Currently tos_fw_config is only present for TSP */ TOS_FW_CONFIG_ID #endif }; if (tb_fw_cfg_dtb == NULL) { VERBOSE("No TB_FW_CONFIG specified\n"); return; } err = arm_dyn_tb_fw_cfg_init(tb_fw_cfg_dtb, &tb_fw_node); if (err < 0) { ERROR("Invalid TB_FW_CONFIG passed from BL1\n"); panic(); } /* Iterate through all the fw config IDs */ for (i = 0; i < ARRAY_SIZE(config_ids); i++) { /* Get the config load address and size from TB_FW_CONFIG */ cfg_mem_params = get_bl_mem_params_node(config_ids[i]); if (cfg_mem_params == NULL) { VERBOSE("Couldn't find HW_CONFIG in bl_mem_params_node\n"); continue; } err = arm_dyn_get_config_load_info(tb_fw_cfg_dtb, tb_fw_node, config_ids[i], &image_base, &image_size); if (err < 0) { VERBOSE("Couldn't find config_id %d load info in TB_FW_CONFIG\n", config_ids[i]); continue; } /* * Do some runtime checks on the load addresses of soc_fw_config, * tos_fw_config, nt_fw_config. This is not a comprehensive check * of all invalid addresses but to prevent trivial porting errors. */ if (config_ids[i] != HW_CONFIG_ID) { if (check_uptr_overflow(image_base, image_size)) continue; #ifdef BL31_BASE /* Ensure the configs don't overlap with BL31 */ if ((image_base > BL31_BASE) || ((image_base + image_size) > BL31_BASE)) continue; #endif /* Ensure the configs are loaded in a valid address */ if (image_base < ARM_BL_RAM_BASE) continue; #ifdef BL32_BASE /* * If BL32 is present, ensure that the configs don't * overlap with it. */ if (image_base >= BL32_BASE && image_base <= BL32_LIMIT) continue; #endif } cfg_mem_params->image_info.image_base = (uintptr_t)image_base; cfg_mem_params->image_info.image_max_size = image_size; /* Remove the IMAGE_ATTRIB_SKIP_LOADING attribute from HW_CONFIG node */ cfg_mem_params->image_info.h.attr &= ~IMAGE_ATTRIB_SKIP_LOADING; } #if TRUSTED_BOARD_BOOT && defined(DYN_DISABLE_AUTH) uint32_t disable_auth = 0; err = arm_dyn_get_disable_auth(tb_fw_cfg_dtb, tb_fw_node, &disable_auth); if (err < 0) return; if (disable_auth == 1) dyn_disable_auth(); #endif } trusted-firmware-a-2.2/plat/arm/common/arm_dyn_cfg_helpers.c000066400000000000000000000175031355360272700242640ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #define DTB_PROP_MBEDTLS_HEAP_ADDR "mbedtls_heap_addr" #define DTB_PROP_MBEDTLS_HEAP_SIZE "mbedtls_heap_size" typedef struct config_load_info_prop { unsigned int config_id; const char *config_addr; const char *config_max_size; } config_load_info_prop_t; static const config_load_info_prop_t prop_names[] = { {HW_CONFIG_ID, "hw_config_addr", "hw_config_max_size"}, {SOC_FW_CONFIG_ID, "soc_fw_config_addr", "soc_fw_config_max_size"}, {TOS_FW_CONFIG_ID, "tos_fw_config_addr", "tos_fw_config_max_size"}, {NT_FW_CONFIG_ID, "nt_fw_config_addr", "nt_fw_config_max_size"} }; /******************************************************************************* * Helper to read the load information corresponding to the `config_id` in * TB_FW_CONFIG. This function expects the following properties to be defined : * _addr size : 2 cells * _max_size size : 1 cell * * Arguments: * void *dtb - pointer to the TB_FW_CONFIG in memory * int node - The node offset to appropriate node in the * DTB. * unsigned int config_id - The configuration id * uint64_t *config_addr - Returns the `config` load address if read * is successful. * uint32_t *config_size - Returns the `config` size if read is * successful. * * Returns 0 on success and -1 on error. ******************************************************************************/ int arm_dyn_get_config_load_info(void *dtb, int node, unsigned int config_id, uint64_t *config_addr, uint32_t *config_size) { int err; unsigned int i; assert(dtb != NULL); assert(config_addr != NULL); assert(config_size != NULL); for (i = 0; i < ARRAY_SIZE(prop_names); i++) { if (prop_names[i].config_id == config_id) break; } if (i == ARRAY_SIZE(prop_names)) { WARN("Invalid config id %d\n", config_id); return -1; } /* Check if the pointer to DT is correct */ assert(fdt_check_header(dtb) == 0); /* Assert the node offset point to "arm,tb_fw" compatible property */ assert(node == fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw")); err = fdtw_read_cells(dtb, node, prop_names[i].config_addr, 2, (void *) config_addr); if (err < 0) { WARN("Read cell failed for %s\n", prop_names[i].config_addr); return -1; } err = fdtw_read_cells(dtb, node, prop_names[i].config_max_size, 1, (void *) config_size); if (err < 0) { WARN("Read cell failed for %s\n", prop_names[i].config_max_size); return -1; } VERBOSE("Dyn cfg: Read config_id %d load info from TB_FW_CONFIG 0x%llx 0x%x\n", config_id, (unsigned long long)*config_addr, *config_size); return 0; } /******************************************************************************* * Helper to read the `disable_auth` property in config DTB. This function * expects the following properties to be present in the config DTB. * name : disable_auth size : 1 cell * * Arguments: * void *dtb - pointer to the TB_FW_CONFIG in memory * int node - The node offset to appropriate node in the * DTB. * uint64_t *disable_auth - The value of `disable_auth` property on * successful read. Must be 0 or 1. * * Returns 0 on success and -1 on error. ******************************************************************************/ int arm_dyn_get_disable_auth(void *dtb, int node, uint32_t *disable_auth) { int err; assert(dtb != NULL); assert(disable_auth != NULL); /* Check if the pointer to DT is correct */ assert(fdt_check_header(dtb) == 0); /* Assert the node offset point to "arm,tb_fw" compatible property */ assert(node == fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw")); /* Locate the disable_auth cell and read the value */ err = fdtw_read_cells(dtb, node, "disable_auth", 1, disable_auth); if (err < 0) { WARN("Read cell failed for `disable_auth`\n"); return -1; } /* Check if the value is boolean */ if ((*disable_auth != 0U) && (*disable_auth != 1U)) { WARN("Invalid value for `disable_auth` cell %d\n", *disable_auth); return -1; } VERBOSE("Dyn cfg: `disable_auth` cell found with value = %d\n", *disable_auth); return 0; } /******************************************************************************* * Validate the tb_fw_config is a valid DTB file and returns the node offset * to "arm,tb_fw" property. * Arguments: * void *dtb - pointer to the TB_FW_CONFIG in memory * int *node - Returns the node offset to "arm,tb_fw" property if found. * * Returns 0 on success and -1 on error. ******************************************************************************/ int arm_dyn_tb_fw_cfg_init(void *dtb, int *node) { assert(dtb != NULL); assert(node != NULL); /* Check if the pointer to DT is correct */ if (fdt_check_header(dtb) != 0) { WARN("Invalid DTB file passed as TB_FW_CONFIG\n"); return -1; } /* Assert the node offset point to "arm,tb_fw" compatible property */ *node = fdt_node_offset_by_compatible(dtb, -1, "arm,tb_fw"); if (*node < 0) { WARN("The compatible property `arm,tb_fw` not found in the config\n"); return -1; } VERBOSE("Dyn cfg: Found \"arm,tb_fw\" in the config\n"); return 0; } /* * Reads and returns the Mbed TLS shared heap information from the DTB. * This function is supposed to be called *only* when a DTB is present. * This function is supposed to be called only by BL2. * * Returns: * 0 = success * -1 = error. In this case the values of heap_addr, heap_size should be * considered as garbage by the caller. */ int arm_get_dtb_mbedtls_heap_info(void *dtb, void **heap_addr, size_t *heap_size) { int err, dtb_root; /* Verify the DTB is valid and get the root node */ err = arm_dyn_tb_fw_cfg_init(dtb, &dtb_root); if (err < 0) { ERROR("Invalid TB_FW_CONFIG. Cannot retrieve Mbed TLS heap information from DTB\n"); return -1; } /* Retrieve the Mbed TLS heap details from the DTB */ err = fdtw_read_cells(dtb, dtb_root, DTB_PROP_MBEDTLS_HEAP_ADDR, 2, heap_addr); if (err < 0) { ERROR("Error while reading %s from DTB\n", DTB_PROP_MBEDTLS_HEAP_ADDR); return -1; } err = fdtw_read_cells(dtb, dtb_root, DTB_PROP_MBEDTLS_HEAP_SIZE, 1, heap_size); if (err < 0) { ERROR("Error while reading %s from DTB\n", DTB_PROP_MBEDTLS_HEAP_SIZE); return -1; } return 0; } /* * This function writes the Mbed TLS heap address and size in the DTB. When it * is called, it is guaranteed that a DTB is available. However it is not * guaranteed that the shared Mbed TLS heap implementation is used. Thus we * return error code from here and it's the responsibility of the caller to * determine the action upon error. * * This function is supposed to be called only by BL1. * * Returns: * 0 = success * 1 = error */ int arm_set_dtb_mbedtls_heap_info(void *dtb, void *heap_addr, size_t heap_size) { int err, dtb_root; /* * Verify that the DTB is valid, before attempting to write to it, * and get the DTB root node. */ err = arm_dyn_tb_fw_cfg_init(dtb, &dtb_root); if (err < 0) { ERROR("Invalid TB_FW_CONFIG loaded. Unable to get root node\n"); return -1; } /* * Write the heap address and size in the DTB. * * NOTE: The variables heap_addr and heap_size are corrupted * by the "fdtw_write_inplace_cells" function. After the * function calls they must NOT be reused. */ err = fdtw_write_inplace_cells(dtb, dtb_root, DTB_PROP_MBEDTLS_HEAP_ADDR, 2, &heap_addr); if (err < 0) { ERROR("Unable to write DTB property %s\n", DTB_PROP_MBEDTLS_HEAP_ADDR); return -1; } err = fdtw_write_inplace_cells(dtb, dtb_root, DTB_PROP_MBEDTLS_HEAP_SIZE, 1, &heap_size); if (err < 0) { ERROR("Unable to write DTB property %s\n", DTB_PROP_MBEDTLS_HEAP_SIZE); return -1; } return 0; } trusted-firmware-a-2.2/plat/arm/common/arm_err.c000066400000000000000000000004531355360272700217150ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include void __dead2 plat_error_handler(int err) { plat_arm_error_handler(err); } trusted-firmware-a-2.2/plat/arm/common/arm_gicv2.c000066400000000000000000000073701355360272700221440ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /****************************************************************************** * The following functions are defined as weak to allow a platform to override * the way the GICv2 driver is initialised and used. *****************************************************************************/ #pragma weak plat_arm_gic_driver_init #pragma weak plat_arm_gic_init #pragma weak plat_arm_gic_cpuif_enable #pragma weak plat_arm_gic_cpuif_disable #pragma weak plat_arm_gic_pcpu_init /****************************************************************************** * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0 * interrupts. *****************************************************************************/ static const interrupt_prop_t arm_interrupt_props[] = { PLAT_ARM_G1S_IRQ_PROPS(GICV2_INTR_GROUP0), PLAT_ARM_G0_IRQ_PROPS(GICV2_INTR_GROUP0) }; static unsigned int target_mask_array[PLATFORM_CORE_COUNT]; static const gicv2_driver_data_t arm_gic_data = { .gicd_base = PLAT_ARM_GICD_BASE, .gicc_base = PLAT_ARM_GICC_BASE, .interrupt_props = arm_interrupt_props, .interrupt_props_num = ARRAY_SIZE(arm_interrupt_props), .target_masks = target_mask_array, .target_masks_num = ARRAY_SIZE(target_mask_array), }; /****************************************************************************** * ARM common helper to initialize the GICv2 only driver. *****************************************************************************/ void plat_arm_gic_driver_init(void) { gicv2_driver_init(&arm_gic_data); } void plat_arm_gic_init(void) { gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_set_pe_target_mask(plat_my_core_pos()); gicv2_cpuif_enable(); } /****************************************************************************** * ARM common helper to enable the GICv2 CPU interface *****************************************************************************/ void plat_arm_gic_cpuif_enable(void) { gicv2_cpuif_enable(); } /****************************************************************************** * ARM common helper to disable the GICv2 CPU interface *****************************************************************************/ void plat_arm_gic_cpuif_disable(void) { gicv2_cpuif_disable(); } /****************************************************************************** * ARM common helper to initialize the per cpu distributor interface in GICv2 *****************************************************************************/ void plat_arm_gic_pcpu_init(void) { gicv2_pcpu_distif_init(); gicv2_set_pe_target_mask(plat_my_core_pos()); } /****************************************************************************** * Stubs for Redistributor power management. Although GICv2 doesn't have * Redistributor interface, these are provided for the sake of uniform GIC API *****************************************************************************/ void plat_arm_gic_redistif_on(void) { return; } void plat_arm_gic_redistif_off(void) { return; } /****************************************************************************** * ARM common helper to save & restore the GICv3 on resume from system suspend. * The normal world currently takes care of saving and restoring the GICv2 * registers due to legacy reasons. Hence we just initialize the Distributor * on resume from system suspend. *****************************************************************************/ void plat_arm_gic_save(void) { return; } void plat_arm_gic_resume(void) { gicv2_distif_init(); gicv2_pcpu_distif_init(); } trusted-firmware-a-2.2/plat/arm/common/arm_gicv3.c000066400000000000000000000164401355360272700221430ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /****************************************************************************** * The following functions are defined as weak to allow a platform to override * the way the GICv3 driver is initialised and used. *****************************************************************************/ #pragma weak plat_arm_gic_driver_init #pragma weak plat_arm_gic_init #pragma weak plat_arm_gic_cpuif_enable #pragma weak plat_arm_gic_cpuif_disable #pragma weak plat_arm_gic_pcpu_init #pragma weak plat_arm_gic_redistif_on #pragma weak plat_arm_gic_redistif_off /* The GICv3 driver only needs to be initialized in EL3 */ static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT]; static const interrupt_prop_t arm_interrupt_props[] = { PLAT_ARM_G1S_IRQ_PROPS(INTR_GROUP1S), PLAT_ARM_G0_IRQ_PROPS(INTR_GROUP0) }; /* * We save and restore the GICv3 context on system suspend. Allocate the * data in the designated EL3 Secure carve-out memory. The `volatile` * is used to prevent the compiler from removing the gicv3 contexts even * though the DEFINE_LOAD_SYM_ADDR creates a dummy reference to it. */ static volatile gicv3_redist_ctx_t rdist_ctx __section("arm_el3_tzc_dram"); static volatile gicv3_dist_ctx_t dist_ctx __section("arm_el3_tzc_dram"); /* Define accessor function to get reference to the GICv3 context */ DEFINE_LOAD_SYM_ADDR(rdist_ctx) DEFINE_LOAD_SYM_ADDR(dist_ctx) /* * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register * to core position. * * Calculating core position is dependent on MPIDR_EL1.MT bit. However, affinity * values read from GICR_TYPER don't have an MT field. To reuse the same * translation used for CPUs, we insert MT bit read from the PE's MPIDR into * that read from GICR_TYPER. * * Assumptions: * * - All CPUs implemented in the system have MPIDR_EL1.MT bit set; * - No CPUs implemented in the system use affinity level 3. */ static unsigned int arm_gicv3_mpidr_hash(u_register_t mpidr) { mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK); return plat_arm_calc_core_pos(mpidr); } static const gicv3_driver_data_t arm_gic_data __unused = { .gicd_base = PLAT_ARM_GICD_BASE, .gicr_base = 0U, .interrupt_props = arm_interrupt_props, .interrupt_props_num = ARRAY_SIZE(arm_interrupt_props), .rdistif_num = PLATFORM_CORE_COUNT, .rdistif_base_addrs = rdistif_base_addrs, .mpidr_to_core_pos = arm_gicv3_mpidr_hash }; void __init plat_arm_gic_driver_init(void) { /* * The GICv3 driver is initialized in EL3 and does not need * to be initialized again in SEL1. This is because the S-EL1 * can use GIC system registers to manage interrupts and does * not need GIC interface base addresses to be configured. */ #if (!defined(__aarch64__) && defined(IMAGE_BL32)) || \ (defined(__aarch64__) && defined(IMAGE_BL31)) gicv3_driver_init(&arm_gic_data); if (gicv3_rdistif_probe(PLAT_ARM_GICR_BASE) == -1) { ERROR("No GICR base frame found for Primary CPU\n"); panic(); } #endif } /****************************************************************************** * ARM common helper to initialize the GIC. Only invoked by BL31 *****************************************************************************/ void __init plat_arm_gic_init(void) { gicv3_distif_init(); gicv3_rdistif_init(plat_my_core_pos()); gicv3_cpuif_enable(plat_my_core_pos()); } /****************************************************************************** * ARM common helper to enable the GIC CPU interface *****************************************************************************/ void plat_arm_gic_cpuif_enable(void) { gicv3_cpuif_enable(plat_my_core_pos()); } /****************************************************************************** * ARM common helper to disable the GIC CPU interface *****************************************************************************/ void plat_arm_gic_cpuif_disable(void) { gicv3_cpuif_disable(plat_my_core_pos()); } /****************************************************************************** * ARM common helper function to iterate over all GICR frames and discover the * corresponding per-cpu redistributor frame as well as initialize the * corresponding interface in GICv3. At the moment, Arm platforms do not have * non-contiguous GICR frames. *****************************************************************************/ void plat_arm_gic_pcpu_init(void) { int result; result = gicv3_rdistif_probe(PLAT_ARM_GICR_BASE); if (result == -1) { ERROR("No GICR base frame found for CPU 0x%lx\n", read_mpidr()); panic(); } gicv3_rdistif_init(plat_my_core_pos()); } /****************************************************************************** * ARM common helpers to power GIC redistributor interface *****************************************************************************/ void plat_arm_gic_redistif_on(void) { gicv3_rdistif_on(plat_my_core_pos()); } void plat_arm_gic_redistif_off(void) { gicv3_rdistif_off(plat_my_core_pos()); } /****************************************************************************** * ARM common helper to save & restore the GICv3 on resume from system suspend *****************************************************************************/ void plat_arm_gic_save(void) { gicv3_redist_ctx_t * const rdist_context = (gicv3_redist_ctx_t *)LOAD_ADDR_OF(rdist_ctx); gicv3_dist_ctx_t * const dist_context = (gicv3_dist_ctx_t *)LOAD_ADDR_OF(dist_ctx); /* * If an ITS is available, save its context before * the Redistributor using: * gicv3_its_save_disable(gits_base, &its_ctx[i]) * Additionally, an implementation-defined sequence may * be required to save the whole ITS state. */ /* * Save the GIC Redistributors and ITS contexts before the * Distributor context. As we only handle SYSTEM SUSPEND API, * we only need to save the context of the CPU that is issuing * the SYSTEM SUSPEND call, i.e. the current CPU. */ gicv3_rdistif_save(plat_my_core_pos(), rdist_context); /* Save the GIC Distributor context */ gicv3_distif_save(dist_context); /* * From here, all the components of the GIC can be safely powered down * as long as there is an alternate way to handle wakeup interrupt * sources. */ } void plat_arm_gic_resume(void) { const gicv3_redist_ctx_t *rdist_context = (gicv3_redist_ctx_t *)LOAD_ADDR_OF(rdist_ctx); const gicv3_dist_ctx_t *dist_context = (gicv3_dist_ctx_t *)LOAD_ADDR_OF(dist_ctx); /* Restore the GIC Distributor context */ gicv3_distif_init_restore(dist_context); /* * Restore the GIC Redistributor and ITS contexts after the * Distributor context. As we only handle SYSTEM SUSPEND API, * we only need to restore the context of the CPU that issued * the SYSTEM SUSPEND call. */ gicv3_rdistif_init_restore(plat_my_core_pos(), rdist_context); /* * If an ITS is available, restore its context after * the Redistributor using: * gicv3_its_restore(gits_base, &its_ctx[i]) * An implementation-defined sequence may be required to * restore the whole ITS state. The ITS must also be * re-enabled after this sequence has been executed. */ } trusted-firmware-a-2.2/plat/arm/common/arm_image_load.c000066400000000000000000000057251355360272700232150ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #pragma weak plat_flush_next_bl_params #pragma weak plat_get_bl_image_load_info #pragma weak plat_get_next_bl_params static bl_params_t *next_bl_params_cpy_ptr; /******************************************************************************* * This function flushes the data structures so that they are visible * in memory for the next BL image. ******************************************************************************/ void plat_flush_next_bl_params(void) { assert(next_bl_params_cpy_ptr != NULL); flush_bl_params_desc_args(bl_mem_params_desc_ptr, bl_mem_params_desc_num, next_bl_params_cpy_ptr); } /******************************************************************************* * This function returns the list of loadable images. ******************************************************************************/ struct bl_load_info *plat_get_bl_image_load_info(void) { return get_bl_load_info_from_mem_params_desc(); } /******************************************************************************* * ARM helper function to return the list of executable images.Since the default * descriptors are allocated within BL2 RW memory, this prevents BL31/BL32 * overlay of BL2 memory. Hence this function also copies the descriptors to a * pre-allocated memory indicated by ARM_BL2_MEM_DESC_BASE. ******************************************************************************/ struct bl_params *arm_get_next_bl_params(void) { bl_mem_params_node_t *bl2_mem_params_descs_cpy = (bl_mem_params_node_t *)ARM_BL2_MEM_DESC_BASE; const bl_params_t *next_bl_params; next_bl_params_cpy_ptr = (bl_params_t *)(ARM_BL2_MEM_DESC_BASE + (bl_mem_params_desc_num * sizeof(bl_mem_params_node_t))); /* * Copy the memory descriptors to ARM_BL2_MEM_DESC_BASE area. */ (void) memcpy(bl2_mem_params_descs_cpy, bl_mem_params_desc_ptr, (bl_mem_params_desc_num * sizeof(bl_mem_params_node_t))); /* * Modify the global 'bl_mem_params_desc_ptr' to point to the * copied location. */ bl_mem_params_desc_ptr = bl2_mem_params_descs_cpy; next_bl_params = get_next_bl_params_from_mem_params_desc(); assert(next_bl_params != NULL); /* * Copy 'next_bl_params' to the reserved location after the copied * memory descriptors. */ (void) memcpy(next_bl_params_cpy_ptr, next_bl_params, (sizeof(bl_params_t))); populate_next_bl_params_config(next_bl_params_cpy_ptr); return next_bl_params_cpy_ptr; } /******************************************************************************* * This function returns the list of executable images ******************************************************************************/ struct bl_params *plat_get_next_bl_params(void) { return arm_get_next_bl_params(); } trusted-firmware-a-2.2/plat/arm/common/arm_io_storage.c000066400000000000000000000176161355360272700232710ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include /* IO devices */ static const io_dev_connector_t *fip_dev_con; static uintptr_t fip_dev_handle; static const io_dev_connector_t *memmap_dev_con; static uintptr_t memmap_dev_handle; static const io_block_spec_t fip_block_spec = { .offset = PLAT_ARM_FIP_BASE, .length = PLAT_ARM_FIP_MAX_SIZE }; static const io_uuid_spec_t bl2_uuid_spec = { .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2, }; static const io_uuid_spec_t scp_bl2_uuid_spec = { .uuid = UUID_SCP_FIRMWARE_SCP_BL2, }; static const io_uuid_spec_t bl31_uuid_spec = { .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31, }; static const io_uuid_spec_t bl32_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32, }; static const io_uuid_spec_t bl32_extra1_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1, }; static const io_uuid_spec_t bl32_extra2_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2, }; static const io_uuid_spec_t bl33_uuid_spec = { .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33, }; static const io_uuid_spec_t tb_fw_config_uuid_spec = { .uuid = UUID_TB_FW_CONFIG, }; static const io_uuid_spec_t hw_config_uuid_spec = { .uuid = UUID_HW_CONFIG, }; static const io_uuid_spec_t soc_fw_config_uuid_spec = { .uuid = UUID_SOC_FW_CONFIG, }; static const io_uuid_spec_t tos_fw_config_uuid_spec = { .uuid = UUID_TOS_FW_CONFIG, }; static const io_uuid_spec_t nt_fw_config_uuid_spec = { .uuid = UUID_NT_FW_CONFIG, }; #if TRUSTED_BOARD_BOOT static const io_uuid_spec_t tb_fw_cert_uuid_spec = { .uuid = UUID_TRUSTED_BOOT_FW_CERT, }; static const io_uuid_spec_t trusted_key_cert_uuid_spec = { .uuid = UUID_TRUSTED_KEY_CERT, }; static const io_uuid_spec_t scp_fw_key_cert_uuid_spec = { .uuid = UUID_SCP_FW_KEY_CERT, }; static const io_uuid_spec_t soc_fw_key_cert_uuid_spec = { .uuid = UUID_SOC_FW_KEY_CERT, }; static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = { .uuid = UUID_TRUSTED_OS_FW_KEY_CERT, }; static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = { .uuid = UUID_NON_TRUSTED_FW_KEY_CERT, }; static const io_uuid_spec_t scp_fw_cert_uuid_spec = { .uuid = UUID_SCP_FW_CONTENT_CERT, }; static const io_uuid_spec_t soc_fw_cert_uuid_spec = { .uuid = UUID_SOC_FW_CONTENT_CERT, }; static const io_uuid_spec_t tos_fw_cert_uuid_spec = { .uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT, }; static const io_uuid_spec_t nt_fw_cert_uuid_spec = { .uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT, }; #endif /* TRUSTED_BOARD_BOOT */ static int open_fip(const uintptr_t spec); static int open_memmap(const uintptr_t spec); struct plat_io_policy { uintptr_t *dev_handle; uintptr_t image_spec; int (*check)(const uintptr_t spec); }; /* By default, ARM platforms load images from the FIP */ static const struct plat_io_policy policies[] = { [FIP_IMAGE_ID] = { &memmap_dev_handle, (uintptr_t)&fip_block_spec, open_memmap }, [BL2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl2_uuid_spec, open_fip }, [SCP_BL2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&scp_bl2_uuid_spec, open_fip }, [BL31_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl31_uuid_spec, open_fip }, [BL32_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_uuid_spec, open_fip }, [BL32_EXTRA1_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_extra1_uuid_spec, open_fip }, [BL32_EXTRA2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_extra2_uuid_spec, open_fip }, [BL33_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl33_uuid_spec, open_fip }, [TB_FW_CONFIG_ID] = { &fip_dev_handle, (uintptr_t)&tb_fw_config_uuid_spec, open_fip }, [HW_CONFIG_ID] = { &fip_dev_handle, (uintptr_t)&hw_config_uuid_spec, open_fip }, [SOC_FW_CONFIG_ID] = { &fip_dev_handle, (uintptr_t)&soc_fw_config_uuid_spec, open_fip }, [TOS_FW_CONFIG_ID] = { &fip_dev_handle, (uintptr_t)&tos_fw_config_uuid_spec, open_fip }, [NT_FW_CONFIG_ID] = { &fip_dev_handle, (uintptr_t)&nt_fw_config_uuid_spec, open_fip }, #if TRUSTED_BOARD_BOOT [TRUSTED_BOOT_FW_CERT_ID] = { &fip_dev_handle, (uintptr_t)&tb_fw_cert_uuid_spec, open_fip }, [TRUSTED_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&trusted_key_cert_uuid_spec, open_fip }, [SCP_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&scp_fw_key_cert_uuid_spec, open_fip }, [SOC_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&soc_fw_key_cert_uuid_spec, open_fip }, [TRUSTED_OS_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&tos_fw_key_cert_uuid_spec, open_fip }, [NON_TRUSTED_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&nt_fw_key_cert_uuid_spec, open_fip }, [SCP_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&scp_fw_cert_uuid_spec, open_fip }, [SOC_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&soc_fw_cert_uuid_spec, open_fip }, [TRUSTED_OS_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&tos_fw_cert_uuid_spec, open_fip }, [NON_TRUSTED_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&nt_fw_cert_uuid_spec, open_fip }, #endif /* TRUSTED_BOARD_BOOT */ }; /* Weak definitions may be overridden in specific ARM standard platform */ #pragma weak plat_arm_io_setup #pragma weak plat_arm_get_alt_image_source static int open_fip(const uintptr_t spec) { int result; uintptr_t local_image_handle; /* See if a Firmware Image Package is available */ result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); if (result == 0) { result = io_open(fip_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using FIP\n"); io_close(local_image_handle); } } return result; } static int open_memmap(const uintptr_t spec) { int result; uintptr_t local_image_handle; result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL); if (result == 0) { result = io_open(memmap_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using Memmap\n"); io_close(local_image_handle); } } return result; } void arm_io_setup(void) { int io_result; io_result = register_io_dev_fip(&fip_dev_con); assert(io_result == 0); io_result = register_io_dev_memmap(&memmap_dev_con); assert(io_result == 0); /* Open connections to devices and cache the handles */ io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle); assert(io_result == 0); io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL, &memmap_dev_handle); assert(io_result == 0); /* Ignore improbable errors in release builds */ (void)io_result; } void plat_arm_io_setup(void) { arm_io_setup(); } int plat_arm_get_alt_image_source( unsigned int image_id __unused, uintptr_t *dev_handle __unused, uintptr_t *image_spec __unused) { /* By default do not try an alternative */ return -ENOENT; } /* 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 result; const struct plat_io_policy *policy; assert(image_id < ARRAY_SIZE(policies)); policy = &policies[image_id]; result = policy->check(policy->image_spec); if (result == 0) { *image_spec = policy->image_spec; *dev_handle = *(policy->dev_handle); } else { VERBOSE("Trying alternative IO\n"); result = plat_arm_get_alt_image_source(image_id, dev_handle, image_spec); } return result; } /* * See if a Firmware Image Package is available, * by checking if TOC is valid or not. */ int arm_io_is_toc_valid(void) { int result; result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); return (result == 0); } trusted-firmware-a-2.2/plat/arm/common/arm_nor_psci_mem_protect.c000066400000000000000000000106751355360272700253460ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* * DRAM1 is used also to load the NS boot loader. For this reason we * cannot clear the full DRAM1, because in that case we would clear * the NS images (especially for RESET_TO_BL31 and RESET_TO_SPMIN cases). * For this reason we reserve 64 MB for the NS images and protect the RAM * until the end of DRAM1. * We limit the size of DRAM2 to 1 GB to avoid big delays while booting */ #define DRAM1_NS_IMAGE_LIMIT (PLAT_ARM_NS_IMAGE_BASE + (32 << TWO_MB_SHIFT)) #define DRAM1_PROTECTED_SIZE (ARM_NS_DRAM1_END+1u - DRAM1_NS_IMAGE_LIMIT) static mem_region_t arm_ram_ranges[] = { {DRAM1_NS_IMAGE_LIMIT, DRAM1_PROTECTED_SIZE}, #ifdef __aarch64__ {ARM_DRAM2_BASE, 1u << ONE_GB_SHIFT}, #endif }; /******************************************************************************* * Function that reads the content of the memory protect variable that * enables clearing of non secure memory when system boots. This variable * should be stored in a secure NVRAM. ******************************************************************************/ int arm_psci_read_mem_protect(int *enabled) { int tmp; tmp = *(int *) PLAT_ARM_MEM_PROT_ADDR; *enabled = (tmp == 1) ? 1 : 0; return 0; } /******************************************************************************* * Function that writes the content of the memory protect variable that * enables overwritten of non secure memory when system boots. ******************************************************************************/ int arm_nor_psci_write_mem_protect(int val) { unsigned long enable = (val != 0) ? 1UL : 0UL; if (nor_unlock(PLAT_ARM_MEM_PROT_ADDR) != 0) { ERROR("unlocking memory protect variable\n"); return -1; } if (enable == 1UL) { /* * If we want to write a value different than 0 * then we have to erase the full block because * otherwise we cannot ensure that the value programmed * into the flash is going to be the same than the value * requested by the caller */ if (nor_erase(PLAT_ARM_MEM_PROT_ADDR) != 0) { ERROR("erasing block containing memory protect variable\n"); return -1; } } if (nor_word_program(PLAT_ARM_MEM_PROT_ADDR, enable) != 0) { ERROR("programming memory protection variable\n"); return -1; } return 0; } /******************************************************************************* * Function used for required psci operations performed when * system boots ******************************************************************************/ /* * PLAT_MEM_PROTECT_VA_FRAME is a address specifically * selected in a way that is not needed an additional * translation table for memprotect. It happens because * we use a chunk of size 2MB and it means that it can * be mapped in a level 2 table and the level 2 table * for 0xc0000000 is already used and the entry for * 0xc0000000 is not used. */ #if defined(PLAT_XLAT_TABLES_DYNAMIC) void arm_nor_psci_do_dyn_mem_protect(void) { int enable; arm_psci_read_mem_protect(&enable); if (enable == 0) return; INFO("PSCI: Overwriting non secure memory\n"); clear_map_dyn_mem_regions(arm_ram_ranges, ARRAY_SIZE(arm_ram_ranges), PLAT_ARM_MEM_PROTEC_VA_FRAME, 1 << TWO_MB_SHIFT); } #endif /******************************************************************************* * Function used for required psci operations performed when * system boots and dynamic memory is not used. ******************************************************************************/ void arm_nor_psci_do_static_mem_protect(void) { int enable; (void) arm_psci_read_mem_protect(&enable); if (enable == 0) return; INFO("PSCI: Overwriting non secure memory\n"); clear_mem_regions(arm_ram_ranges, ARRAY_SIZE(arm_ram_ranges)); (void) arm_nor_psci_write_mem_protect(0); } /******************************************************************************* * Function that checks if a region is protected by the memory protect * mechanism ******************************************************************************/ int arm_psci_mem_protect_chk(uintptr_t base, u_register_t length) { return mem_region_in_array_chk(arm_ram_ranges, ARRAY_SIZE(arm_ram_ranges), base, length); } trusted-firmware-a-2.2/plat/arm/common/arm_pm.c000066400000000000000000000146411355360272700215450ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* Allow ARM Standard platforms to override these functions */ #pragma weak plat_arm_program_trusted_mailbox #if !ARM_RECOM_STATE_ID_ENC /******************************************************************************* * ARM standard platform handler called to check the validity of the power state * parameter. ******************************************************************************/ int arm_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { unsigned int pstate = psci_get_pstate_type(power_state); unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state); unsigned int i; assert(req_state != NULL); if (pwr_lvl > PLAT_MAX_PWR_LVL) return PSCI_E_INVALID_PARAMS; /* Sanity check the requested state */ if (pstate == PSTATE_TYPE_STANDBY) { /* * It's possible to enter standby only on power level 0 * Ignore any other power level. */ if (pwr_lvl != ARM_PWR_LVL0) return PSCI_E_INVALID_PARAMS; req_state->pwr_domain_state[ARM_PWR_LVL0] = ARM_LOCAL_STATE_RET; } else { for (i = ARM_PWR_LVL0; i <= pwr_lvl; i++) req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF; } /* * We expect the 'state id' to be zero. */ if (psci_get_pstate_id(power_state) != 0U) return PSCI_E_INVALID_PARAMS; return PSCI_E_SUCCESS; } #else /******************************************************************************* * ARM standard platform handler called to check the validity of the power * state parameter. The power state parameter has to be a composite power * state. ******************************************************************************/ int arm_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { unsigned int state_id; int i; assert(req_state != NULL); /* * Currently we are using a linear search for finding the matching * entry in the idle power state array. This can be made a binary * search if the number of entries justify the additional complexity. */ for (i = 0; !!arm_pm_idle_states[i]; i++) { if (power_state == arm_pm_idle_states[i]) break; } /* Return error if entry not found in the idle state array */ if (!arm_pm_idle_states[i]) return PSCI_E_INVALID_PARAMS; i = 0; state_id = psci_get_pstate_id(power_state); /* Parse the State ID and populate the state info parameter */ while (state_id) { req_state->pwr_domain_state[i++] = state_id & ARM_LOCAL_PSTATE_MASK; state_id >>= ARM_LOCAL_PSTATE_WIDTH; } return PSCI_E_SUCCESS; } #endif /* __ARM_RECOM_STATE_ID_ENC__ */ /******************************************************************************* * ARM standard platform handler called to check the validity of the non secure * entrypoint. Returns 0 if the entrypoint is valid, or -1 otherwise. ******************************************************************************/ int arm_validate_ns_entrypoint(uintptr_t entrypoint) { /* * Check if the non secure entrypoint lies within the non * secure DRAM. */ if ((entrypoint >= ARM_NS_DRAM1_BASE) && (entrypoint < (ARM_NS_DRAM1_BASE + ARM_NS_DRAM1_SIZE))) { return 0; } #ifdef __aarch64__ if ((entrypoint >= ARM_DRAM2_BASE) && (entrypoint < (ARM_DRAM2_BASE + ARM_DRAM2_SIZE))) { return 0; } #endif return -1; } int arm_validate_psci_entrypoint(uintptr_t entrypoint) { return (arm_validate_ns_entrypoint(entrypoint) == 0) ? PSCI_E_SUCCESS : PSCI_E_INVALID_ADDRESS; } /****************************************************************************** * Helper function to save the platform state before a system suspend. Save the * state of the system components which are not in the Always ON power domain. *****************************************************************************/ void arm_system_pwr_domain_save(void) { /* Assert system power domain is available on the platform */ assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2); plat_arm_gic_save(); /* * Unregister console now so that it is not registered for a second * time during resume. */ arm_console_runtime_end(); /* * All the other peripheral which are configured by ARM TF are * re-initialized on resume from system suspend. Hence we * don't save their state here. */ } /****************************************************************************** * Helper function to resume the platform from system suspend. Reinitialize * the system components which are not in the Always ON power domain. * TODO: Unify the platform setup when waking up from cold boot and system * resume in arm_bl31_platform_setup(). *****************************************************************************/ void arm_system_pwr_domain_resume(void) { /* Initialize the console */ arm_console_runtime_init(); /* Assert system power domain is available on the platform */ assert(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL2); plat_arm_gic_resume(); plat_arm_security_setup(); arm_configure_sys_timer(); } /******************************************************************************* * ARM platform function to program the mailbox for a cpu before it is released * from reset. This function assumes that the Trusted mail box base is within * the ARM_SHARED_RAM region ******************************************************************************/ void plat_arm_program_trusted_mailbox(uintptr_t address) { uintptr_t *mailbox = (void *) PLAT_ARM_TRUSTED_MAILBOX_BASE; *mailbox = address; /* * Ensure that the PLAT_ARM_TRUSTED_MAILBOX_BASE is within * ARM_SHARED_RAM region. */ assert((PLAT_ARM_TRUSTED_MAILBOX_BASE >= ARM_SHARED_RAM_BASE) && ((PLAT_ARM_TRUSTED_MAILBOX_BASE + sizeof(*mailbox)) <= \ (ARM_SHARED_RAM_BASE + ARM_SHARED_RAM_SIZE))); } /******************************************************************************* * The ARM Standard platform definition of platform porting API * `plat_setup_psci_ops`. ******************************************************************************/ int __init plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { *psci_ops = plat_arm_psci_override_pm_ops(&plat_arm_psci_pm_ops); /* Setup mailbox with entry point. */ plat_arm_program_trusted_mailbox(sec_entrypoint); return 0; } trusted-firmware-a-2.2/plat/arm/common/arm_sip_svc.c000066400000000000000000000044141355360272700225740ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* ARM SiP Service UUID */ DEFINE_SVC_UUID2(arm_sip_svc_uid, 0x556d75e2, 0x6033, 0xb54b, 0xb5, 0x75, 0x62, 0x79, 0xfd, 0x11, 0x37, 0xff); static int arm_sip_setup(void) { if (pmf_setup() != 0) return 1; return 0; } /* * This function handles ARM defined SiP Calls */ static uintptr_t arm_sip_handler(unsigned int 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) { int call_count = 0; /* * Dispatch PMF calls to PMF SMC handler and return its return * value */ if (is_pmf_fid(smc_fid)) { return pmf_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); } switch (smc_fid) { case ARM_SIP_SVC_EXE_STATE_SWITCH: { u_register_t pc; /* Allow calls from non-secure only */ if (!is_caller_non_secure(flags)) SMC_RET1(handle, STATE_SW_E_DENIED); /* Validate supplied entry point */ pc = (u_register_t) ((x1 << 32) | (uint32_t) x2); if (arm_validate_ns_entrypoint(pc) != 0) SMC_RET1(handle, STATE_SW_E_PARAM); /* * Pointers used in execution state switch are all 32 bits wide */ return (uintptr_t) arm_execution_state_switch(smc_fid, (uint32_t) x1, (uint32_t) x2, (uint32_t) x3, (uint32_t) x4, handle); } case ARM_SIP_SVC_CALL_COUNT: /* PMF calls */ call_count += PMF_NUM_SMC_CALLS; /* State switch call */ call_count += 1; SMC_RET1(handle, call_count); case ARM_SIP_SVC_UID: /* Return UID to the caller */ SMC_UUID_RET(handle, arm_sip_svc_uid); case ARM_SIP_SVC_VERSION: /* Return the version of current implementation */ SMC_RET2(handle, ARM_SIP_SVC_VERSION_MAJOR, ARM_SIP_SVC_VERSION_MINOR); default: WARN("Unimplemented ARM SiP Service Call: 0x%x \n", smc_fid); SMC_RET1(handle, SMC_UNK); } } /* Define a runtime service descriptor for fast SMC calls */ DECLARE_RT_SVC( arm_sip_svc, OEN_SIP_START, OEN_SIP_END, SMC_TYPE_FAST, arm_sip_setup, arm_sip_handler ); trusted-firmware-a-2.2/plat/arm/common/arm_topology.c000066400000000000000000000032161355360272700230010ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /******************************************************************************* * This function validates an MPIDR by checking whether it falls within the * acceptable bounds. An error code (-1) is returned if an incorrect mpidr * is passed. ******************************************************************************/ int arm_check_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; uint64_t valid_mask; #if ARM_PLAT_MT unsigned int pe_id; valid_mask = ~(MPIDR_AFFLVL_MASK | (MPIDR_AFFLVL_MASK << MPIDR_AFF1_SHIFT) | (MPIDR_AFFLVL_MASK << MPIDR_AFF2_SHIFT)); cluster_id = (mpidr >> MPIDR_AFF2_SHIFT) & MPIDR_AFFLVL_MASK; cpu_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; pe_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; #else valid_mask = ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK); cluster_id = (unsigned int) ((mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK); cpu_id = (unsigned int) ((mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK); #endif /* ARM_PLAT_MT */ mpidr &= MPIDR_AFFINITY_MASK; if ((mpidr & valid_mask) != 0U) return -1; if (cluster_id >= PLAT_ARM_CLUSTER_COUNT) return -1; /* Validate cpu_id by checking whether it represents a CPU in one of the two clusters present on the platform. */ if (cpu_id >= plat_arm_get_cluster_core_count(mpidr)) return -1; #if ARM_PLAT_MT if (pe_id >= plat_arm_get_cpu_pe_count(mpidr)) return -1; #endif /* ARM_PLAT_MT */ return 0; } trusted-firmware-a-2.2/plat/arm/common/arm_tzc400.c000066400000000000000000000040361355360272700221520ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /* Weak definitions may be overridden in specific ARM standard platform */ #pragma weak plat_arm_security_setup /******************************************************************************* * Initialize the TrustZone Controller for ARM standard platforms. * When booting an EL3 payload, this is simplified: we configure region 0 with * secure access only and do not enable any other region. ******************************************************************************/ void arm_tzc400_setup(const arm_tzc_regions_info_t *tzc_regions) { #ifndef EL3_PAYLOAD_BASE unsigned int region_index = 1U; const arm_tzc_regions_info_t *p; const arm_tzc_regions_info_t init_tzc_regions[] = { ARM_TZC_REGIONS_DEF, {0} }; #endif INFO("Configuring TrustZone Controller\n"); tzc400_init(PLAT_ARM_TZC_BASE); /* Disable filters. */ tzc400_disable_filters(); #ifndef EL3_PAYLOAD_BASE if (tzc_regions == NULL) p = init_tzc_regions; else p = tzc_regions; /* Region 0 set to no access by default */ tzc400_configure_region0(TZC_REGION_S_NONE, 0); /* Rest Regions set according to tzc_regions array */ for (; p->base != 0ULL; p++) { tzc400_configure_region(PLAT_ARM_TZC_FILTERS, region_index, p->base, p->end, p->sec_attr, p->nsaid_permissions); region_index++; } INFO("Total %u regions set.\n", region_index); #else /* if defined(EL3_PAYLOAD_BASE) */ /* Allow Secure and Non-secure access to DRAM for EL3 payloads */ tzc400_configure_region0(TZC_REGION_S_RDWR, PLAT_ARM_TZC_NS_DEV_ACCESS); #endif /* EL3_PAYLOAD_BASE */ /* * Raise an exception if a NS device tries to access secure memory * TODO: Add interrupt handling support. */ tzc400_set_action(TZC_ACTION_ERR); /* Enable filters. */ tzc400_enable_filters(); } void plat_arm_security_setup(void) { arm_tzc400_setup(NULL); } trusted-firmware-a-2.2/plat/arm/common/arm_tzc_dmc500.c000066400000000000000000000041301355360272700227710ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /******************************************************************************* * Initialize the DMC500-TrustZone Controller for ARM standard platforms. * When booting an EL3 payload, this is simplified: we configure region 0 with * secure access only and do not enable any other region. ******************************************************************************/ void arm_tzc_dmc500_setup(tzc_dmc500_driver_data_t *plat_driver_data, const arm_tzc_regions_info_t *tzc_regions) { #ifndef EL3_PAYLOAD_BASE unsigned int region_index = 1U; const arm_tzc_regions_info_t *p; const arm_tzc_regions_info_t init_tzc_regions[] = { ARM_TZC_REGIONS_DEF, {0} }; #endif assert(plat_driver_data); INFO("Configuring DMC-500 TZ Settings\n"); tzc_dmc500_driver_init(plat_driver_data); #ifndef EL3_PAYLOAD_BASE if (tzc_regions == NULL) p = init_tzc_regions; else p = tzc_regions; /* Region 0 set to no access by default */ tzc_dmc500_configure_region0(TZC_REGION_S_NONE, 0); /* Rest Regions set according to tzc_regions array */ for (; p->base != 0ULL; p++) { tzc_dmc500_configure_region(region_index, p->base, p->end, p->sec_attr, p->nsaid_permissions); region_index++; } INFO("Total %u regions set.\n", region_index); #else /* Allow secure access only to DRAM for EL3 payloads */ tzc_dmc500_configure_region0(TZC_REGION_S_RDWR, 0); #endif /* * Raise an exception if a NS device tries to access secure memory * TODO: Add interrupt handling support. */ tzc_dmc500_set_action(TZC_ACTION_RV_LOWERR); /* * Flush the configuration settings to have an affect. Validate * flush by checking FILTER_EN is set on region 1 attributes * register. */ tzc_dmc500_config_complete(); /* * Wait for the flush to complete. * TODO: Have a timeout for this loop */ while (tzc_dmc500_verify_complete()) ; } trusted-firmware-a-2.2/plat/arm/common/execution_state_switch.c000066400000000000000000000121071355360272700250510ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include /* * Handle SMC from a lower exception level to switch its execution state * (either from AArch64 to AArch32, or vice versa). * * smc_fid: * SMC function ID - either ARM_SIP_SVC_STATE_SWITCH_64 or * ARM_SIP_SVC_STATE_SWITCH_32. * pc_hi, pc_lo: * PC upon re-entry to the calling exception level; width dependent on the * calling exception level. * cookie_hi, cookie_lo: * Opaque pointer pairs received from the caller to pass it back, upon * re-entry. * handle: * Handle to saved context. */ int arm_execution_state_switch(unsigned int smc_fid, uint32_t pc_hi, uint32_t pc_lo, uint32_t cookie_hi, uint32_t cookie_lo, void *handle) { /* Execution state can be switched only if EL3 is AArch64 */ #ifdef __aarch64__ bool caller_64, thumb = false, from_el2; unsigned int el, endianness; u_register_t spsr, pc, scr, sctlr; entry_point_info_t ep; cpu_context_t *ctx = (cpu_context_t *) handle; el3_state_t *el3_ctx = get_el3state_ctx(ctx); /* That the SMC originated from NS is already validated by the caller */ /* * Disallow state switch if any of the secondaries have been brought up. */ if (psci_secondaries_brought_up() != 0) goto exec_denied; spsr = read_ctx_reg(el3_ctx, CTX_SPSR_EL3); caller_64 = (GET_RW(spsr) == MODE_RW_64); if (caller_64) { /* * If the call originated from AArch64, expect 32-bit pointers when * switching to AArch32. */ if ((pc_hi != 0U) || (cookie_hi != 0U)) goto invalid_param; pc = pc_lo; /* Instruction state when entering AArch32 */ thumb = (pc & 1U) != 0U; } else { /* Construct AArch64 PC */ pc = (((u_register_t) pc_hi) << 32) | pc_lo; } /* Make sure PC is 4-byte aligned, except for Thumb */ if (((pc & 0x3U) != 0U) && !thumb) goto invalid_param; /* * EL3 controls register width of the immediate lower EL only. Expect * this request from EL2/Hyp unless: * * - EL2 is not implemented; * - EL2 is implemented, but was disabled. This can be inferred from * SCR_EL3.HCE. */ from_el2 = caller_64 ? (GET_EL(spsr) == MODE_EL2) : (GET_M32(spsr) == MODE32_hyp); scr = read_ctx_reg(el3_ctx, CTX_SCR_EL3); if (!from_el2) { /* The call is from NS privilege level other than HYP */ /* * Disallow switching state if there's a Hypervisor in place; * this request must be taken up with the Hypervisor instead. */ if ((scr & SCR_HCE_BIT) != 0U) goto exec_denied; } /* * Return to the caller using the same endianness. Extract * endianness bit from the respective system control register * directly. */ sctlr = from_el2 ? read_sctlr_el2() : read_sctlr_el1(); endianness = ((sctlr & SCTLR_EE_BIT) != 0U) ? 1U : 0U; /* Construct SPSR for the exception state we're about to switch to */ if (caller_64) { unsigned long long impl; /* * Switching from AArch64 to AArch32. Ensure this CPU implements * the target EL in AArch32. */ impl = from_el2 ? el_implemented(2) : el_implemented(1); if (impl != EL_IMPL_A64_A32) goto exec_denied; /* Return to the equivalent AArch32 privilege level */ el = from_el2 ? MODE32_hyp : MODE32_svc; spsr = SPSR_MODE32((u_register_t) el, thumb ? SPSR_T_THUMB : SPSR_T_ARM, endianness, DISABLE_ALL_EXCEPTIONS); } else { /* * Switching from AArch32 to AArch64. Since it's not possible to * implement an EL as AArch32-only (from which this call was * raised), it's safe to assume AArch64 is also implemented. */ el = from_el2 ? MODE_EL2 : MODE_EL1; spsr = SPSR_64((u_register_t) el, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); } /* * Use the context management library to re-initialize the existing * context with the execution state flipped. Since the library takes * entry_point_info_t pointer as the argument, construct a dummy one * with PC, state width, endianness, security etc. appropriately set. * Other entries in the entry point structure are irrelevant for * purpose. */ zeromem(&ep, sizeof(ep)); ep.pc = pc; ep.spsr = (uint32_t) spsr; SET_PARAM_HEAD(&ep, PARAM_EP, VERSION_1, ((unsigned int) ((endianness != 0U) ? EP_EE_BIG : EP_EE_LITTLE) | NON_SECURE | EP_ST_DISABLE)); /* * Re-initialize the system register context, and exit EL3 as if for the * first time. State switch is effectively a soft reset of the * calling EL. */ cm_init_my_context(&ep); cm_prepare_el3_exit(NON_SECURE); /* * State switch success. The caller of SMC wouldn't see the SMC * returning. Instead, execution starts at the supplied entry point, * with context pointers populated in registers 0 and 1. */ SMC_RET2(handle, cookie_hi, cookie_lo); invalid_param: SMC_RET1(handle, STATE_SW_E_PARAM); exec_denied: #endif /* __aarch64__ */ /* State switch denied */ SMC_RET1(handle, STATE_SW_E_DENIED); } trusted-firmware-a-2.2/plat/arm/common/sp_min/000077500000000000000000000000001355360272700214055ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/common/sp_min/arm_sp_min.mk000066400000000000000000000010501355360272700240560ustar00rootroot00000000000000# # Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # SP MIN source files common to ARM standard platforms # Skip building BL1, BL2 and BL2U if RESET_TO_SP_MIN flag is set. ifeq (${RESET_TO_SP_MIN},1) BL1_SOURCES = BL2_SOURCES = BL2U_SOURCES = endif BL32_SOURCES += plat/arm/common/arm_pm.c \ plat/arm/common/arm_topology.c \ plat/arm/common/sp_min/arm_sp_min_setup.c \ plat/common/aarch32/platform_mp_stack.S \ plat/common/plat_psci_common.c trusted-firmware-a-2.2/plat/arm/common/sp_min/arm_sp_min_setup.c000066400000000000000000000156211355360272700251220ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include static entry_point_info_t bl33_image_ep_info; /* Weak definitions may be overridden in specific ARM standard platform */ #pragma weak sp_min_platform_setup #pragma weak sp_min_plat_arch_setup #pragma weak plat_arm_sp_min_early_platform_setup #define MAP_BL_SP_MIN_TOTAL MAP_REGION_FLAT( \ BL32_BASE, \ BL32_END - BL32_BASE, \ MT_MEMORY | MT_RW | MT_SECURE) /* * Check that BL32_BASE is above ARM_TB_FW_CONFIG_LIMIT. The reserved page * is required for SOC_FW_CONFIG/TOS_FW_CONFIG passed from BL2. */ CASSERT(BL32_BASE >= ARM_TB_FW_CONFIG_LIMIT, assert_bl32_base_overflows); /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for the * security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. ******************************************************************************/ entry_point_info_t *sp_min_plat_get_bl33_ep_info(void) { entry_point_info_t *next_image_info; next_image_info = &bl33_image_ep_info; /* * None of the images on the ARM development platforms can have 0x0 * as the entrypoint */ if (next_image_info->pc) return next_image_info; else return NULL; } /******************************************************************************* * Utility function to perform early platform setup. ******************************************************************************/ 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 */ arm_console_boot_init(); #if RESET_TO_SP_MIN /* There are no parameters from BL2 if SP_MIN is a reset vector */ assert(from_bl2 == NULL); assert(plat_params_from_bl2 == NULL); /* Populate entry point information for BL33 */ SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); /* * Tell SP_MIN where the non-trusted software image * is located and the entry state information */ bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); bl33_image_ep_info.spsr = arm_get_spsr_for_bl33_entry(); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); # if ARM_LINUX_KERNEL_AS_BL33 /* * According to the file ``Documentation/arm/Booting`` of the Linux * kernel tree, Linux expects: * r0 = 0 * r1 = machine type number, optional in DT-only platforms (~0 if so) * r2 = Physical address of the device tree blob */ bl33_image_ep_info.args.arg0 = 0U; bl33_image_ep_info.args.arg1 = ~0U; bl33_image_ep_info.args.arg2 = (u_register_t)ARM_PRELOADED_DTB_BASE; # endif #else /* RESET_TO_SP_MIN */ /* * Check params passed from BL2 should not be NULL, */ bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2; assert(params_from_bl2 != NULL); assert(params_from_bl2->h.type == PARAM_BL_PARAMS); assert(params_from_bl2->h.version >= VERSION_2); bl_params_node_t *bl_params = params_from_bl2->head; /* * Copy BL33 entry point information. * They are stored in Secure RAM, in BL2's address space. */ while (bl_params) { if (bl_params->image_id == BL33_IMAGE_ID) { bl33_image_ep_info = *bl_params->ep_info; break; } bl_params = bl_params->next_params_info; } if (bl33_image_ep_info.pc == 0) panic(); #endif /* RESET_TO_SP_MIN */ } /******************************************************************************* * Default implementation for sp_min_platform_setup2() for ARM platforms ******************************************************************************/ void plat_arm_sp_min_early_platform_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { arm_sp_min_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3); /* * Initialize Interconnect for this cluster during cold boot. * No need for locks as no other CPU is active. */ plat_arm_interconnect_init(); /* * Enable Interconnect coherency for the primary CPU's cluster. * Earlier bootloader stages might already do this (e.g. Trusted * Firmware's BL1 does it) but we can't assume so. There is no harm in * executing this code twice anyway. * Platform specific PSCI code will enable coherency for other * clusters. */ plat_arm_interconnect_enter_coherency(); } void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { plat_arm_sp_min_early_platform_setup(arg0, arg1, arg2, arg3); } /******************************************************************************* * Perform any SP_MIN platform runtime setup prior to SP_MIN exit. * Common to ARM standard platforms. ******************************************************************************/ void arm_sp_min_plat_runtime_setup(void) { /* Initialize the runtime console */ arm_console_runtime_init(); } /******************************************************************************* * Perform platform specific setup for SP_MIN ******************************************************************************/ void sp_min_platform_setup(void) { /* Initialize the GIC driver, cpu and distributor interfaces */ plat_arm_gic_driver_init(); plat_arm_gic_init(); /* * Do initial security configuration to allow DRAM/device access * (if earlier BL has not already done so). */ #if RESET_TO_SP_MIN plat_arm_security_setup(); #if defined(PLAT_ARM_MEM_PROT_ADDR) arm_nor_psci_do_dyn_mem_protect(); #endif /* PLAT_ARM_MEM_PROT_ADDR */ #endif /* Enable and initialize the System level generic timer */ #ifdef ARM_SYS_CNTCTL_BASE mmio_write_32(ARM_SYS_CNTCTL_BASE + CNTCR_OFF, CNTCR_FCREQ(0U) | CNTCR_EN); #endif #ifdef ARM_SYS_TIMCTL_BASE /* Allow access to the System counter timer module */ arm_configure_sys_timer(); #endif /* Initialize power controller before setting up topology */ plat_arm_pwrc_setup(); } void sp_min_plat_runtime_setup(void) { arm_sp_min_plat_runtime_setup(); } /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this only initializes the MMU ******************************************************************************/ void sp_min_plat_arch_setup(void) { const mmap_region_t bl_regions[] = { MAP_BL_SP_MIN_TOTAL, ARM_MAP_BL_RO, #if USE_COHERENT_MEM ARM_MAP_BL_COHERENT_RAM, #endif {0} }; setup_page_tables(bl_regions, plat_arm_get_mmap()); enable_mmu_svc_mon(0); } trusted-firmware-a-2.2/plat/arm/common/tsp/000077500000000000000000000000001355360272700207265ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/common/tsp/arm_tsp.mk000066400000000000000000000004671355360272700227330ustar00rootroot00000000000000# # Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # TSP source files common to ARM standard platforms BL32_SOURCES += plat/arm/common/arm_topology.c \ plat/arm/common/tsp/arm_tsp_setup.c \ plat/common/aarch64/platform_mp_stack.S trusted-firmware-a-2.2/plat/arm/common/tsp/arm_tsp_setup.c000066400000000000000000000044031355360272700237600ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include /* Weak definitions may be overridden in specific ARM standard platform */ #pragma weak tsp_early_platform_setup #pragma weak tsp_platform_setup #pragma weak tsp_plat_arch_setup #define MAP_BL_TSP_TOTAL MAP_REGION_FLAT( \ BL32_BASE, \ BL32_END - BL32_BASE, \ MT_MEMORY | MT_RW | MT_SECURE) /******************************************************************************* * Initialize the UART ******************************************************************************/ static console_pl011_t arm_tsp_runtime_console; void arm_tsp_early_platform_setup(void) { /* * Initialize a different console than already in use to display * messages from TSP */ int rc = console_pl011_register(PLAT_ARM_TSP_UART_BASE, PLAT_ARM_TSP_UART_CLK_IN_HZ, ARM_CONSOLE_BAUDRATE, &arm_tsp_runtime_console); if (rc == 0) panic(); console_set_scope(&arm_tsp_runtime_console.console, CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME); } void tsp_early_platform_setup(void) { arm_tsp_early_platform_setup(); } /******************************************************************************* * Perform platform specific setup placeholder ******************************************************************************/ void tsp_platform_setup(void) { plat_arm_gic_driver_init(); } /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this is only intializes the MMU ******************************************************************************/ void tsp_plat_arch_setup(void) { #if USE_COHERENT_MEM /* Ensure ARM platforms don't use coherent memory in TSP */ assert((BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE) == 0U); #endif const mmap_region_t bl_regions[] = { MAP_BL_TSP_TOTAL, ARM_MAP_BL_RO, {0} }; setup_page_tables(bl_regions, plat_arm_get_mmap()); enable_mmu_el1(0); } trusted-firmware-a-2.2/plat/arm/css/000077500000000000000000000000001355360272700174205ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/css/common/000077500000000000000000000000001355360272700207105ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/css/common/aarch32/000077500000000000000000000000001355360272700221335ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/css/common/aarch32/css_helpers.S000066400000000000000000000060501355360272700245720ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .weak plat_secondary_cold_boot_setup .weak plat_get_my_entrypoint .globl css_calc_core_pos_swap_cluster .weak plat_is_my_cpu_primary /* --------------------------------------------------------------------- * void plat_secondary_cold_boot_setup(void); * In the normal boot flow, cold-booting secondary * CPUs is not yet implemented and they panic. * --------------------------------------------------------------------- */ func plat_secondary_cold_boot_setup /* TODO: Implement secondary CPU cold boot setup on CSS platforms */ cb_panic: b cb_panic endfunc plat_secondary_cold_boot_setup /* --------------------------------------------------------------------- * uintptr_t plat_get_my_entrypoint (void); * * Main job of this routine is to distinguish between a cold and a warm * boot. On CSS platforms, this distinction is based on the contents of * the Trusted Mailbox. It is initialised to zero by the SCP before the * AP cores are released from reset. Therefore, a zero mailbox means * it's a cold reset. * * This functions returns the contents of the mailbox, i.e.: * - 0 for a cold boot; * - the warm boot entrypoint for a warm boot. * --------------------------------------------------------------------- */ func plat_get_my_entrypoint ldr r0, =PLAT_ARM_TRUSTED_MAILBOX_BASE ldr r0, [r0] bx lr endfunc plat_get_my_entrypoint /* ----------------------------------------------------------- * unsigned int css_calc_core_pos_swap_cluster(u_register_t mpidr) * Utility function to calculate the core position by * swapping the cluster order. This is necessary in order to * match the format of the boot information passed by the SCP * and read in plat_is_my_cpu_primary below. * ----------------------------------------------------------- */ func css_calc_core_pos_swap_cluster and r1, r0, #MPIDR_CPU_MASK and r0, r0, #MPIDR_CLUSTER_MASK eor r0, r0, #(1 << MPIDR_AFFINITY_BITS) // swap cluster order add r0, r1, r0, LSR #6 bx lr endfunc css_calc_core_pos_swap_cluster /* ----------------------------------------------------- * unsigned int plat_is_my_cpu_primary (void); * * Find out whether the current cpu is the primary * cpu (applicable ony after a cold boot) * ----------------------------------------------------- */ #if CSS_USE_SCMI_SDS_DRIVER func plat_is_my_cpu_primary mov r10, lr bl plat_my_core_pos mov r4, r0 bl sds_get_primary_cpu_id /* Check for error */ mov r1, #0xffffffff cmp r0, r1 beq 1f cmp r0, r4 moveq r0, #1 movne r0, #0 bx r10 1: no_ret plat_panic_handler endfunc plat_is_my_cpu_primary #else func plat_is_my_cpu_primary mov r10, lr bl plat_my_core_pos ldr r1, =SCP_BOOT_CFG_ADDR ldr r1, [r1] ubfx r1, r1, #PLAT_CSS_PRIMARY_CPU_SHIFT, \ #PLAT_CSS_PRIMARY_CPU_BIT_WIDTH cmp r0, r1 moveq r0, #1 movne r0, #0 bx r10 endfunc plat_is_my_cpu_primary #endif trusted-firmware-a-2.2/plat/arm/css/common/aarch64/000077500000000000000000000000001355360272700221405ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/css/common/aarch64/css_helpers.S000066400000000000000000000071251355360272700246030ustar00rootroot00000000000000/* * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .weak plat_secondary_cold_boot_setup .weak plat_get_my_entrypoint .globl css_calc_core_pos_swap_cluster .weak plat_is_my_cpu_primary /* --------------------------------------------------------------------- * void plat_secondary_cold_boot_setup(void); * * In the normal boot flow, cold-booting secondary CPUs is not yet * implemented and they panic. * * When booting an EL3 payload, secondary CPUs are placed in a holding * pen, waiting for their mailbox to be populated. Note that all CPUs * share the same mailbox ; therefore, populating it will release all * CPUs from their holding pen. If finer-grained control is needed then * this should be handled in the code that secondary CPUs jump to. * --------------------------------------------------------------------- */ func plat_secondary_cold_boot_setup #ifndef EL3_PAYLOAD_BASE /* TODO: Implement secondary CPU cold boot setup on CSS platforms */ cb_panic: b cb_panic #else mov_imm x0, PLAT_ARM_TRUSTED_MAILBOX_BASE /* Wait until the mailbox gets populated */ poll_mailbox: ldr x1, [x0] cbz x1, 1f br x1 1: wfe b poll_mailbox #endif /* EL3_PAYLOAD_BASE */ endfunc plat_secondary_cold_boot_setup /* --------------------------------------------------------------------- * uintptr_t plat_get_my_entrypoint (void); * * Main job of this routine is to distinguish between a cold and a warm * boot. On CSS platforms, this distinction is based on the contents of * the Trusted Mailbox. It is initialised to zero by the SCP before the * AP cores are released from reset. Therefore, a zero mailbox means * it's a cold reset. * * This functions returns the contents of the mailbox, i.e.: * - 0 for a cold boot; * - the warm boot entrypoint for a warm boot. * --------------------------------------------------------------------- */ func plat_get_my_entrypoint mov_imm x0, PLAT_ARM_TRUSTED_MAILBOX_BASE ldr x0, [x0] ret endfunc plat_get_my_entrypoint /* ----------------------------------------------------------- * unsigned int css_calc_core_pos_swap_cluster(u_register_t mpidr) * Utility function to calculate the core position by * swapping the cluster order. This is necessary in order to * match the format of the boot information passed by the SCP * and read in plat_is_my_cpu_primary below. * ----------------------------------------------------------- */ func css_calc_core_pos_swap_cluster and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK eor x0, x0, #(1 << MPIDR_AFFINITY_BITS) // swap cluster order add x0, x1, x0, LSR #6 ret endfunc css_calc_core_pos_swap_cluster /* ----------------------------------------------------- * unsigned int plat_is_my_cpu_primary (void); * * Find out whether the current cpu is the primary * cpu (applicable ony after a cold boot) * ----------------------------------------------------- */ #if CSS_USE_SCMI_SDS_DRIVER func plat_is_my_cpu_primary mov x9, x30 bl plat_my_core_pos mov x4, x0 bl sds_get_primary_cpu_id /* Check for error */ mov x1, #0xffffffff cmp x0, x1 b.eq 1f cmp x0, x4 cset w0, eq ret x9 1: no_ret plat_panic_handler endfunc plat_is_my_cpu_primary #else func plat_is_my_cpu_primary mov x9, x30 bl plat_my_core_pos mov_imm x1, SCP_BOOT_CFG_ADDR ldr x1, [x1] ubfx x1, x1, #PLAT_CSS_PRIMARY_CPU_SHIFT, \ #PLAT_CSS_PRIMARY_CPU_BIT_WIDTH cmp x0, x1 cset w0, eq ret x9 endfunc plat_is_my_cpu_primary #endif trusted-firmware-a-2.2/plat/arm/css/common/css_bl1_setup.c000066400000000000000000000007511355360272700236250ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include void bl1_platform_setup(void) { arm_bl1_platform_setup(); /* * Do ARM CSS SoC security setup. * BL1 needs to enable normal world access to memory. */ soc_css_security_setup(); } trusted-firmware-a-2.2/plat/arm/css/common/css_bl2_setup.c000066400000000000000000000051321355360272700236240ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include /* Weak definition may be overridden in specific CSS based platform */ #pragma weak plat_arm_bl2_handle_scp_bl2 /******************************************************************************* * Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol. * Return 0 on success, -1 otherwise. ******************************************************************************/ int plat_arm_bl2_handle_scp_bl2(image_info_t *scp_bl2_image_info) { int ret; INFO("BL2: Initiating SCP_BL2 transfer to SCP\n"); ret = css_scp_boot_image_xfer((void *)scp_bl2_image_info->image_base, scp_bl2_image_info->image_size); if (ret == 0) ret = css_scp_boot_ready(); if (ret == 0) INFO("BL2: SCP_BL2 transferred to SCP\n"); else ERROR("BL2: SCP_BL2 transfer failure\n"); return ret; } #if !CSS_USE_SCMI_SDS_DRIVER # if defined(EL3_PAYLOAD_BASE) || JUNO_AARCH32_EL3_RUNTIME /* * We need to override some of the platform functions when booting an EL3 * payload or SP_MIN on Juno AArch32. This needs to be done only for * SCPI/BOM SCP systems as in case of SDS, the structures remain in memory and * don't need to be overwritten. */ static unsigned int scp_boot_config; void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { arm_bl2_early_platform_setup((uintptr_t)arg0, (meminfo_t *)arg1); /* Save SCP Boot config before it gets overwritten by SCP_BL2 loading */ scp_boot_config = mmio_read_32(SCP_BOOT_CFG_ADDR); VERBOSE("BL2: Saved SCP Boot config = 0x%x\n", scp_boot_config); } void bl2_platform_setup(void) { arm_bl2_platform_setup(); /* * Before releasing the AP cores out of reset, the SCP writes some data * at the beginning of the Trusted SRAM. It is is overwritten before * reaching this function. We need to restore this data, as if the * target had just come out of reset. This implies: * - zeroing the first 128 bytes of Trusted SRAM using zeromem instead * of zero_normalmem since this is device memory. * - restoring the SCP boot configuration. */ VERBOSE("BL2: Restoring SCP reset data in Trusted SRAM\n"); zeromem((void *) ARM_SHARED_RAM_BASE, 128); mmio_write_32(SCP_BOOT_CFG_ADDR, scp_boot_config); } # endif /* EL3_PAYLOAD_BASE */ #endif /* CSS_USE_SCMI_SDS_DRIVER */ trusted-firmware-a-2.2/plat/arm/css/common/css_bl2u_setup.c000066400000000000000000000033371355360272700240160ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* Weak definition may be overridden in specific CSS based platform */ #pragma weak bl2u_plat_handle_scp_bl2u /* Data structure which holds the SCP_BL2U image info for BL2U */ static image_info_t scp_bl2u_image_info; /******************************************************************************* * BL1 can pass platform dependent information to BL2U in x1. * In case of ARM CSS platforms x1 contains SCP_BL2U image info. * In case of ARM FVP platforms x1 is not used. * In both cases, x0 contains the extents of the memory available to BL2U ******************************************************************************/ void bl2u_early_platform_setup(meminfo_t *mem_layout, void *plat_info) { if (!plat_info) panic(); arm_bl2u_early_platform_setup(mem_layout, plat_info); scp_bl2u_image_info = *(image_info_t *)plat_info; } /******************************************************************************* * Transfer SCP_BL2U from Trusted RAM using the SCP Download protocol. ******************************************************************************/ int bl2u_plat_handle_scp_bl2u(void) { int ret; INFO("BL2U: Initiating SCP_BL2U transfer to SCP\n"); ret = css_scp_boot_image_xfer((void *)scp_bl2u_image_info.image_base, scp_bl2u_image_info.image_size); if (ret == 0) ret = css_scp_boot_ready(); if (ret == 0) INFO("BL2U: SCP_BL2U transferred to SCP\n"); else ERROR("BL2U: SCP_BL2U transfer failure\n"); return ret; } trusted-firmware-a-2.2/plat/arm/css/common/css_common.mk000066400000000000000000000054171355360272700234100ustar00rootroot00000000000000# # Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # By default, SCP images are needed by CSS platforms. CSS_LOAD_SCP_IMAGES ?= 1 # By default, SCMI driver is disabled for CSS platforms CSS_USE_SCMI_SDS_DRIVER ?= 0 PLAT_INCLUDES += -Iinclude/plat/arm/css/common/aarch64 PLAT_BL_COMMON_SOURCES += plat/arm/css/common/${ARCH}/css_helpers.S BL1_SOURCES += plat/arm/css/common/css_bl1_setup.c BL2_SOURCES += plat/arm/css/common/css_bl2_setup.c BL2U_SOURCES += plat/arm/css/common/css_bl2u_setup.c BL31_SOURCES += plat/arm/css/common/css_pm.c \ plat/arm/css/common/css_topology.c ifeq (${CSS_USE_SCMI_SDS_DRIVER},0) BL31_SOURCES += drivers/arm/css/mhu/css_mhu.c \ drivers/arm/css/scp/css_pm_scpi.c \ drivers/arm/css/scpi/css_scpi.c else BL31_SOURCES += drivers/arm/css/mhu/css_mhu_doorbell.c \ drivers/arm/css/scmi/scmi_ap_core_proto.c \ drivers/arm/css/scmi/scmi_common.c \ drivers/arm/css/scmi/scmi_pwr_dmn_proto.c \ drivers/arm/css/scmi/scmi_sys_pwr_proto.c \ drivers/arm/css/scp/css_pm_scmi.c endif # Process CSS_LOAD_SCP_IMAGES flag $(eval $(call assert_boolean,CSS_LOAD_SCP_IMAGES)) $(eval $(call add_define,CSS_LOAD_SCP_IMAGES)) ifeq (${CSS_LOAD_SCP_IMAGES},1) NEED_SCP_BL2 := yes ifneq (${TRUSTED_BOARD_BOOT},0) $(eval $(call TOOL_ADD_IMG,scp_bl2u,--scp-fwu-cfg,FWU_)) endif ifeq (${CSS_USE_SCMI_SDS_DRIVER},1) BL2U_SOURCES += drivers/arm/css/scp/css_sds.c \ drivers/arm/css/sds/sds.c BL2_SOURCES += drivers/arm/css/scp/css_sds.c \ drivers/arm/css/sds/sds.c else BL2U_SOURCES += drivers/arm/css/mhu/css_mhu.c \ drivers/arm/css/scp/css_bom_bootloader.c \ drivers/arm/css/scpi/css_scpi.c BL2_SOURCES += drivers/arm/css/mhu/css_mhu.c \ drivers/arm/css/scp/css_bom_bootloader.c \ drivers/arm/css/scpi/css_scpi.c # Enable option to detect whether the SCP ROM firmware in use predates version # 1.7.0 and therefore, is incompatible. CSS_DETECT_PRE_1_7_0_SCP := 1 # Process CSS_DETECT_PRE_1_7_0_SCP flag $(eval $(call assert_boolean,CSS_DETECT_PRE_1_7_0_SCP)) $(eval $(call add_define,CSS_DETECT_PRE_1_7_0_SCP)) endif endif ifeq (${CSS_USE_SCMI_SDS_DRIVER},1) PLAT_BL_COMMON_SOURCES += drivers/arm/css/sds/${ARCH}/sds_helpers.S endif # Process CSS_USE_SCMI_SDS_DRIVER flag $(eval $(call assert_boolean,CSS_USE_SCMI_SDS_DRIVER)) $(eval $(call add_define,CSS_USE_SCMI_SDS_DRIVER)) # Process CSS_NON_SECURE_UART flag # This undocumented build option is only to enable debug access to the UART # from non secure code, which is useful on some platforms. # Default (obviously) is off. CSS_NON_SECURE_UART := 0 $(eval $(call assert_boolean,CSS_NON_SECURE_UART)) $(eval $(call add_define,CSS_NON_SECURE_UART)) trusted-firmware-a-2.2/plat/arm/css/common/css_pm.c000066400000000000000000000302301355360272700223360ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include /* Allow CSS platforms to override `plat_arm_psci_pm_ops` */ #pragma weak plat_arm_psci_pm_ops #if ARM_RECOM_STATE_ID_ENC /* * The table storing the valid idle power states. Ensure that the * array entries are populated in ascending order of state-id to * enable us to use binary search during power state validation. * The table must be terminated by a NULL entry. */ const unsigned int arm_pm_idle_states[] = { /* State-id - 0x001 */ arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RET, ARM_PWR_LVL0, PSTATE_TYPE_STANDBY), /* State-id - 0x002 */ arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF, ARM_PWR_LVL0, PSTATE_TYPE_POWERDOWN), /* State-id - 0x022 */ arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_RUN, ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, ARM_PWR_LVL1, PSTATE_TYPE_POWERDOWN), #if PLAT_MAX_PWR_LVL > ARM_PWR_LVL1 /* State-id - 0x222 */ arm_make_pwrstate_lvl2(ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, ARM_LOCAL_STATE_OFF, ARM_PWR_LVL2, PSTATE_TYPE_POWERDOWN), #endif 0, }; #endif /* __ARM_RECOM_STATE_ID_ENC__ */ /* * All the power management helpers in this file assume at least cluster power * level is supported. */ CASSERT(PLAT_MAX_PWR_LVL >= ARM_PWR_LVL1, assert_max_pwr_lvl_supported_mismatch); /* * Ensure that the PLAT_MAX_PWR_LVL is not greater than CSS_SYSTEM_PWR_DMN_LVL * assumed by the CSS layer. */ CASSERT(PLAT_MAX_PWR_LVL <= CSS_SYSTEM_PWR_DMN_LVL, assert_max_pwr_lvl_higher_than_css_sys_lvl); /******************************************************************************* * Handler called when a power domain is about to be turned on. The * level and mpidr determine the affinity instance. ******************************************************************************/ int css_pwr_domain_on(u_register_t mpidr) { css_scp_on(mpidr); return PSCI_E_SUCCESS; } static void css_pwr_domain_on_finisher_common( const psci_power_state_t *target_state) { assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF); /* * Perform the common cluster specific operations i.e enable coherency * if this cluster was off. */ if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) plat_arm_interconnect_enter_coherency(); } /******************************************************************************* * Handler called when a power level has just been powered on after * being turned off earlier. The target_state encodes the low power state that * each level has woken up from. This handler would never be invoked with * the system power domain uninitialized as either the primary would have taken * care of it as part of cold boot or the first core awakened from system * suspend would have already initialized it. ******************************************************************************/ void css_pwr_domain_on_finish(const psci_power_state_t *target_state) { /* Assert that the system power domain need not be initialized */ assert(css_system_pwr_state(target_state) == ARM_LOCAL_STATE_RUN); css_pwr_domain_on_finisher_common(target_state); } /******************************************************************************* * Handler called when a power domain has just been powered on and the cpu * and its cluster are fully participating in coherent transaction on the * interconnect. Data cache must be enabled for CPU at this point. ******************************************************************************/ void css_pwr_domain_on_finish_late(const psci_power_state_t *target_state) { /* Program the gic per-cpu distributor or re-distributor interface */ plat_arm_gic_pcpu_init(); /* Enable the gic cpu interface */ plat_arm_gic_cpuif_enable(); } /******************************************************************************* * Common function called while turning a cpu off or suspending it. It is called * from css_off() or css_suspend() when these functions in turn are called for * power domain at the highest power level which will be powered down. It * performs the actions common to the OFF and SUSPEND calls. ******************************************************************************/ static void css_power_down_common(const psci_power_state_t *target_state) { /* Prevent interrupts from spuriously waking up this cpu */ plat_arm_gic_cpuif_disable(); /* Cluster is to be turned off, so disable coherency */ if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) plat_arm_interconnect_exit_coherency(); } /******************************************************************************* * Handler called when a power domain is about to be turned off. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ void css_pwr_domain_off(const psci_power_state_t *target_state) { assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF); css_power_down_common(target_state); css_scp_off(target_state); } /******************************************************************************* * Handler called when a power domain is about to be suspended. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ void css_pwr_domain_suspend(const psci_power_state_t *target_state) { /* * CSS currently supports retention only at cpu level. Just return * as nothing is to be done for retention. */ if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET) return; assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF); css_power_down_common(target_state); /* Perform system domain state saving if issuing system suspend */ if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF) { arm_system_pwr_domain_save(); /* Power off the Redistributor after having saved its context */ plat_arm_gic_redistif_off(); } css_scp_suspend(target_state); } /******************************************************************************* * Handler called when a power domain has just been powered on after * having been suspended earlier. The target_state encodes the low power state * that each level has woken up from. * TODO: At the moment we reuse the on finisher and reinitialize the secure * context. Need to implement a separate suspend finisher. ******************************************************************************/ void css_pwr_domain_suspend_finish( const psci_power_state_t *target_state) { /* Return as nothing is to be done on waking up from retention. */ if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET) return; /* Perform system domain restore if woken up from system suspend */ if (css_system_pwr_state(target_state) == ARM_LOCAL_STATE_OFF) /* * At this point, the Distributor must be powered on to be ready * to have its state restored. The Redistributor will be powered * on as part of gicv3_rdistif_init_restore. */ arm_system_pwr_domain_resume(); css_pwr_domain_on_finisher_common(target_state); /* Enable the gic cpu interface */ plat_arm_gic_cpuif_enable(); } /******************************************************************************* * Handlers to shutdown/reboot the system ******************************************************************************/ void __dead2 css_system_off(void) { css_scp_sys_shutdown(); } void __dead2 css_system_reset(void) { css_scp_sys_reboot(); } /******************************************************************************* * Handler called when the CPU power domain is about to enter standby. ******************************************************************************/ void css_cpu_standby(plat_local_state_t cpu_state) { unsigned int scr; assert(cpu_state == ARM_LOCAL_STATE_RET); scr = read_scr_el3(); /* * Enable the Non secure interrupt to wake the CPU. * In GICv3 affinity routing mode, the non secure group1 interrupts use * the PhysicalFIQ at EL3 whereas in GICv2, it uses the PhysicalIRQ. * Enabling both the bits works for both GICv2 mode and GICv3 affinity * routing mode. */ write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT); isb(); dsb(); wfi(); /* * Restore SCR to the original value, synchronisation of scr_el3 is * done by eret while el3_exit to save some execution cycles. */ write_scr_el3(scr); } /******************************************************************************* * Handler called to return the 'req_state' for system suspend. ******************************************************************************/ void css_get_sys_suspend_power_state(psci_power_state_t *req_state) { unsigned int i; /* * System Suspend is supported only if the system power domain node * is implemented. */ assert(PLAT_MAX_PWR_LVL == CSS_SYSTEM_PWR_DMN_LVL); for (i = ARM_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = ARM_LOCAL_STATE_OFF; } /******************************************************************************* * Handler to query CPU/cluster power states from SCP ******************************************************************************/ int css_node_hw_state(u_register_t mpidr, unsigned int power_level) { return css_scp_get_power_state(mpidr, power_level); } /* * The system power domain suspend is only supported only via * PSCI SYSTEM_SUSPEND API. PSCI CPU_SUSPEND request to system power domain * will be downgraded to the lower level. */ static int css_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { int rc; rc = arm_validate_power_state(power_state, req_state); /* * Ensure that we don't overrun the pwr_domain_state array in the case * where the platform supported max power level is less than the system * power level */ #if (PLAT_MAX_PWR_LVL == CSS_SYSTEM_PWR_DMN_LVL) /* * Ensure that the system power domain level is never suspended * via PSCI CPU SUSPEND API. Currently system suspend is only * supported via PSCI SYSTEM SUSPEND API. */ req_state->pwr_domain_state[CSS_SYSTEM_PWR_DMN_LVL] = ARM_LOCAL_STATE_RUN; #endif return rc; } /* * Custom `translate_power_state_by_mpidr` handler for CSS. Unlike in the * `css_validate_power_state`, we do not downgrade the system power * domain level request in `power_state` as it will be used to query the * PSCI_STAT_COUNT/RESIDENCY at the system power domain level. */ static int css_translate_power_state_by_mpidr(u_register_t mpidr, unsigned int power_state, psci_power_state_t *output_state) { return arm_validate_power_state(power_state, output_state); } /******************************************************************************* * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard * platform will take care of registering the handlers with PSCI. ******************************************************************************/ plat_psci_ops_t plat_arm_psci_pm_ops = { .pwr_domain_on = css_pwr_domain_on, .pwr_domain_on_finish = css_pwr_domain_on_finish, .pwr_domain_on_finish_late = css_pwr_domain_on_finish_late, .pwr_domain_off = css_pwr_domain_off, .cpu_standby = css_cpu_standby, .pwr_domain_suspend = css_pwr_domain_suspend, .pwr_domain_suspend_finish = css_pwr_domain_suspend_finish, .system_off = css_system_off, .system_reset = css_system_reset, .validate_power_state = css_validate_power_state, .validate_ns_entrypoint = arm_validate_psci_entrypoint, .translate_power_state_by_mpidr = css_translate_power_state_by_mpidr, .get_node_hw_state = css_node_hw_state, .get_sys_suspend_power_state = css_get_sys_suspend_power_state, #if defined(PLAT_ARM_MEM_PROT_ADDR) .mem_protect_chk = arm_psci_mem_protect_chk, .read_mem_protect = arm_psci_read_mem_protect, .write_mem_protect = arm_nor_psci_write_mem_protect, #endif #if CSS_USE_SCMI_SDS_DRIVER .system_reset2 = css_system_reset2, #endif }; trusted-firmware-a-2.2/plat/arm/css/common/css_topology.c000066400000000000000000000027521355360272700236060ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #if ARM_PLAT_MT #pragma weak plat_arm_get_cpu_pe_count #endif /****************************************************************************** * This function implements a part of the critical interface between the psci * generic layer and the platform that allows the former to query the platform * to convert an MPIDR to a unique linear index. An error code (-1) is * returned in case the MPIDR is invalid. *****************************************************************************/ int plat_core_pos_by_mpidr(u_register_t mpidr) { if (arm_check_mpidr(mpidr) == 0) { #if ARM_PLAT_MT assert((read_mpidr_el1() & MPIDR_MT_MASK) != 0); /* * The DTB files don't provide the MT bit in the mpidr argument * so set it manually before calculating core position */ mpidr |= MPIDR_MT_MASK; #endif return plat_arm_calc_core_pos(mpidr); } return -1; } #if ARM_PLAT_MT /****************************************************************************** * This function returns the PE count within the physical cpu corresponding to * `mpidr`. Now one cpu only have one thread, so just return 1. *****************************************************************************/ unsigned int plat_arm_get_cpu_pe_count(u_register_t mpidr) { return 1; } #endif /* ARM_PLAT_MT */ trusted-firmware-a-2.2/plat/arm/css/common/sp_min/000077500000000000000000000000001355360272700221755ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/css/common/sp_min/css_sp_min.mk000066400000000000000000000012401355360272700246600ustar00rootroot00000000000000# # Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # SP MIN source files common to CSS platforms BL32_SOURCES += plat/arm/css/common/css_pm.c \ plat/arm/css/common/css_topology.c ifeq (${CSS_USE_SCMI_SDS_DRIVER},0) BL32_SOURCES += drivers/arm/css/mhu/css_mhu.c \ drivers/arm/css/scp/css_pm_scpi.c \ drivers/arm/css/scpi/css_scpi.c else BL32_SOURCES += drivers/arm/css/mhu/css_mhu_doorbell.c \ drivers/arm/css/scp/css_pm_scmi.c \ drivers/arm/css/scmi/scmi_common.c \ drivers/arm/css/scmi/scmi_pwr_dmn_proto.c \ drivers/arm/css/scmi/scmi_sys_pwr_proto.c endif trusted-firmware-a-2.2/plat/arm/css/sgi/000077500000000000000000000000001355360272700202025ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/css/sgi/aarch64/000077500000000000000000000000001355360272700214325ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/css/sgi/aarch64/sgi_helper.S000066400000000000000000000042731355360272700237050ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include .globl plat_arm_calc_core_pos .globl plat_reset_handler /* ----------------------------------------------------- * unsigned int plat_arm_calc_core_pos(u_register_t mpidr) * * Helper function to calculate the core position. * (ClusterId * CSS_SGI_MAX_CPUS_PER_CLUSTER * CSS_SGI_MAX_PE_PER_CPU) + * (CPUId * CSS_SGI_MAX_PE_PER_CPU) + * ThreadId * * which can be simplified as: * * ((ClusterId * CSS_SGI_MAX_CPUS_PER_CLUSTER + CPUId) * * CSS_SGI_MAX_PE_PER_CPU) + ThreadId * ------------------------------------------------------ */ func plat_arm_calc_core_pos mov x3, x0 /* * The MT bit in MPIDR is always set for SGI platforms * and the affinity level 0 corresponds to thread affinity level. */ /* Extract individual affinity fields from MPIDR */ ubfx x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS ubfx x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS ubfx x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS /* Compute linear position */ mov x4, #CSS_SGI_MAX_CPUS_PER_CLUSTER madd x1, x2, x4, x1 mov x5, #CSS_SGI_MAX_PE_PER_CPU madd x0, x1, x5, x0 ret endfunc plat_arm_calc_core_pos /* ----------------------------------------------------- * void plat_reset_handler(void); * * Determine the CPU MIDR and disable power down bit for * that CPU. * ----------------------------------------------------- */ func plat_reset_handler jump_if_cpu_midr CORTEX_A75_MIDR, A75 jump_if_cpu_midr NEOVERSE_N1_MIDR, N1 ret /* ----------------------------------------------------- * Disable CPU power down bit in power control register * ----------------------------------------------------- */ A75: mrs x0, CORTEX_A75_CPUPWRCTLR_EL1 bic x0, x0, #CORTEX_A75_CORE_PWRDN_EN_MASK msr CORTEX_A75_CPUPWRCTLR_EL1, x0 isb ret N1: mrs x0, NEOVERSE_N1_CPUPWRCTLR_EL1 bic x0, x0, #NEOVERSE_N1_CORE_PWRDN_EN_MASK msr NEOVERSE_N1_CPUPWRCTLR_EL1, x0 isb ret endfunc plat_reset_handler trusted-firmware-a-2.2/plat/arm/css/sgi/include/000077500000000000000000000000001355360272700216255ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/css/sgi/include/plat_macros.S000066400000000000000000000010721355360272700242550ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S #include /* --------------------------------------------- * The below required platform porting macro * prints out relevant platform registers * whenever an unhandled exception is taken in * BL31. * * There are currently no platform specific regs * to print. * --------------------------------------------- */ .macro plat_crash_print_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/arm/css/sgi/include/sgi_base_platform_def.h000066400000000000000000000144231355360272700263000ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SGI_BASE_PLATFORM_DEF_H #define SGI_BASE_PLATFORM_DEF_H #include #include #include #include #include #include #include #include #include #define PLATFORM_CORE_COUNT (PLAT_ARM_CLUSTER_COUNT * \ CSS_SGI_MAX_CPUS_PER_CLUSTER * \ CSS_SGI_MAX_PE_PER_CPU) #define PLAT_ARM_TRUSTED_SRAM_SIZE 0x00040000 /* 256 KB */ /* * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the * plat_arm_mmap array defined for each BL stage. */ #if defined(IMAGE_BL31) # if ENABLE_SPM # define PLAT_ARM_MMAP_ENTRIES 9 # define MAX_XLAT_TABLES 7 # define PLAT_SP_IMAGE_MMAP_REGIONS 7 # define PLAT_SP_IMAGE_MAX_XLAT_TABLES 10 # else # define PLAT_ARM_MMAP_ENTRIES 8 # define MAX_XLAT_TABLES 5 # endif #elif defined(IMAGE_BL32) # define PLAT_ARM_MMAP_ENTRIES 8 # define MAX_XLAT_TABLES 5 #elif !USE_ROMLIB # define PLAT_ARM_MMAP_ENTRIES 11 # define MAX_XLAT_TABLES 5 #else # define PLAT_ARM_MMAP_ENTRIES 12 # define MAX_XLAT_TABLES 6 #endif /* * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size * plus a little space for growth. */ #define PLAT_ARM_MAX_BL1_RW_SIZE 0xB000 /* * PLAT_ARM_MAX_ROMLIB_RW_SIZE is define to use a full page */ #if USE_ROMLIB #define PLAT_ARM_MAX_ROMLIB_RW_SIZE 0x1000 #define PLAT_ARM_MAX_ROMLIB_RO_SIZE 0xe000 #else #define PLAT_ARM_MAX_ROMLIB_RW_SIZE 0 #define PLAT_ARM_MAX_ROMLIB_RO_SIZE 0 #endif /* * PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a * little space for growth. */ #if TRUSTED_BOARD_BOOT # define PLAT_ARM_MAX_BL2_SIZE 0x1D000 #else # define PLAT_ARM_MAX_BL2_SIZE 0x11000 #endif /* * Since BL31 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL31_SIZE is * calculated using the current BL31 PROGBITS debug size plus the sizes of * BL2 and BL1-RW */ #define PLAT_ARM_MAX_BL31_SIZE 0x3B000 /* * Size of cacheable stacks */ #if defined(IMAGE_BL1) # if TRUSTED_BOARD_BOOT # define PLATFORM_STACK_SIZE 0x1000 # else # define PLATFORM_STACK_SIZE 0x440 # endif #elif defined(IMAGE_BL2) # if TRUSTED_BOARD_BOOT # define PLATFORM_STACK_SIZE 0x1000 # else # define PLATFORM_STACK_SIZE 0x400 # endif #elif defined(IMAGE_BL2U) # define PLATFORM_STACK_SIZE 0x400 #elif defined(IMAGE_BL31) # if ENABLE_SPM # define PLATFORM_STACK_SIZE 0x500 # else # define PLATFORM_STACK_SIZE 0x400 # endif #elif defined(IMAGE_BL32) # define PLATFORM_STACK_SIZE 0x440 #endif #define PLAT_ARM_NSTIMER_FRAME_ID 0 #define PLAT_ARM_TRUSTED_ROM_BASE 0x0 #define PLAT_ARM_TRUSTED_ROM_SIZE 0x00080000 /* 512KB */ #define PLAT_ARM_NSRAM_BASE 0x06000000 #define PLAT_ARM_NSRAM_SIZE 0x00080000 /* 512KB */ #define PLAT_ARM_G1S_IRQ_PROPS(grp) CSS_G1S_IRQ_PROPS(grp) #define PLAT_ARM_G0_IRQ_PROPS(grp) ARM_G0_IRQ_PROPS(grp) #define CSS_SGI_DEVICE_BASE (0x20000000) #define CSS_SGI_DEVICE_SIZE (0x20000000) #define CSS_SGI_MAP_DEVICE MAP_REGION_FLAT( \ CSS_SGI_DEVICE_BASE, \ CSS_SGI_DEVICE_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) /* GIC related constants */ #define PLAT_ARM_GICD_BASE 0x30000000 #define PLAT_ARM_GICC_BASE 0x2C000000 #define PLAT_ARM_GICR_BASE 0x300C0000 /* Map the secure region for access from S-EL0 */ #define PLAT_ARM_SECURE_MAP_DEVICE MAP_REGION_FLAT( \ SOC_CSS_DEVICE_BASE, \ SOC_CSS_DEVICE_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE | MT_USER) #define PLAT_SP_PRI PLAT_RAS_PRI #if RAS_EXTENSION /* Allocate 128KB for CPER buffers */ #define PLAT_SP_BUF_BASE ULL(0x20000) #define PLAT_ARM_SP_IMAGE_STACK_BASE (PLAT_SP_IMAGE_NS_BUF_BASE + \ PLAT_SP_IMAGE_NS_BUF_SIZE + \ PLAT_SP_BUF_BASE) /* Platform specific SMC FID's used for RAS */ #define SP_DMC_ERROR_INJECT_EVENT_AARCH64 0xC4000042 #define SP_DMC_ERROR_INJECT_EVENT_AARCH32 0x84000042 #define SP_DMC_ERROR_OVERFLOW_EVENT_AARCH64 0xC4000043 #define SP_DMC_ERROR_OVERFLOW_EVENT_AARCH32 0x84000043 #define SP_DMC_ERROR_ECC_EVENT_AARCH64 0xC4000044 #define SP_DMC_ERROR_ECC_EVENT_AARCH32 0x84000044 /* ARM SDEI dynamic shared event numbers */ #define SGI_SDEI_DS_EVENT_0 804 #define SGI_SDEI_DS_EVENT_1 805 #define PLAT_ARM_PRIVATE_SDEI_EVENTS \ SDEI_DEFINE_EVENT_0(ARM_SDEI_SGI), \ SDEI_EXPLICIT_EVENT(SGI_SDEI_DS_EVENT_0, SDEI_MAPF_CRITICAL), \ SDEI_EXPLICIT_EVENT(SGI_SDEI_DS_EVENT_1, SDEI_MAPF_CRITICAL), #define PLAT_ARM_SHARED_SDEI_EVENTS #define ARM_SP_CPER_BUF_BASE (PLAT_SP_IMAGE_NS_BUF_BASE + \ PLAT_SP_IMAGE_NS_BUF_SIZE) #define ARM_SP_CPER_BUF_SIZE ULL(0x20000) #define ARM_SP_CPER_BUF_MMAP MAP_REGION2( \ ARM_SP_CPER_BUF_BASE, \ ARM_SP_CPER_BUF_BASE, \ ARM_SP_CPER_BUF_SIZE, \ MT_RW_DATA | MT_NS | MT_USER, \ PAGE_SIZE) #else #define PLAT_ARM_SP_IMAGE_STACK_BASE (PLAT_SP_IMAGE_NS_BUF_BASE + \ PLAT_SP_IMAGE_NS_BUF_SIZE) #endif /* RAS_EXTENSION */ /* Platform ID address */ #define SSC_VERSION (SSC_REG_BASE + SSC_VERSION_OFFSET) #ifndef __ASSEMBLER__ /* SSC_VERSION related accessors */ /* Returns the part number of the platform */ #define GET_SGI_PART_NUM \ GET_SSC_VERSION_PART_NUM(mmio_read_32(SSC_VERSION)) /* Returns the configuration number of the platform */ #define GET_SGI_CONFIG_NUM \ GET_SSC_VERSION_CONFIG(mmio_read_32(SSC_VERSION)) #endif /* __ASSEMBLER__ */ /******************************************************************************* * Memprotect definitions ******************************************************************************/ /* PSCI memory protect definitions: * This variable is stored in a non-secure flash because some ARM reference * platforms do not have secure NVRAM. Real systems that provided MEM_PROTECT * support must use a secure NVRAM to store the PSCI MEM_PROTECT definitions. */ #define PLAT_ARM_MEM_PROT_ADDR (V2M_FLASH0_BASE + \ V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE) /*Secure Watchdog Constants */ #define SBSA_SECURE_WDOG_BASE UL(0x2A480000) #define SBSA_SECURE_WDOG_TIMEOUT UL(100) #endif /* SGI_BASE_PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/arm/css/sgi/include/sgi_ras.h000066400000000000000000000007431355360272700234310ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SGI_RAS_H #define SGI_RAS_H /* * Mapping the RAS interrupt with SDEI event number and the event * id used with Standalone MM code */ struct sgi_ras_ev_map { int ras_ev_num; /* RAS Event number */ int sdei_ev_num; /* SDEI Event number */ int intr; /* Physical intr number */ }; int sgi_ras_intr_handler_setup(void); #endif /* SGI_RAS_H */ trusted-firmware-a-2.2/plat/arm/css/sgi/include/sgi_variant.h000066400000000000000000000015571355360272700243140ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SGI_VARIANT_H #define SGI_VARIANT_H /* SSC_VERSION values for SGI575 */ #define SGI575_SSC_VER_PART_NUM 0x0783 /* SID Version values for RD-N1E1-Edge */ #define RD_N1E1_EDGE_SID_VER_PART_NUM 0x0786 #define RD_E1_EDGE_CONFIG_ID 0x2 /* Structure containing SGI platform variant information */ typedef struct sgi_platform_info { unsigned int platform_id; /* Part Number of the platform */ unsigned int config_id; /* Config Id of the platform */ } sgi_platform_info_t; extern sgi_platform_info_t sgi_plat_info; /* returns the part number of the platform*/ unsigned int plat_arm_sgi_get_platform_id(void); /* returns the configuration id of the platform */ unsigned int plat_arm_sgi_get_config_id(void); #endif /* SGI_VARIANT_H */ trusted-firmware-a-2.2/plat/arm/css/sgi/sgi-common.mk000066400000000000000000000034271355360272700226110ustar00rootroot00000000000000# # Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # CSS_USE_SCMI_SDS_DRIVER := 1 CSS_ENT_BASE := plat/arm/css/sgi RAS_EXTENSION := 0 ENABLE_SPM := 0 SDEI_SUPPORT := 0 EL3_EXCEPTION_HANDLING := 0 HANDLE_EA_EL3_FIRST := 0 INTERCONNECT_SOURCES := ${CSS_ENT_BASE}/sgi_interconnect.c PLAT_INCLUDES += -I${CSS_ENT_BASE}/include ENT_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v3/gicv3_main.c \ drivers/arm/gic/v3/gicv3_helpers.c \ plat/common/plat_gicv3.c \ plat/arm/common/arm_gicv3.c \ drivers/arm/gic/v3/gic600.c PLAT_BL_COMMON_SOURCES += ${CSS_ENT_BASE}/sgi_plat.c \ ${CSS_ENT_BASE}/aarch64/sgi_helper.S BL1_SOURCES += ${INTERCONNECT_SOURCES} \ drivers/arm/sbsa/sbsa.c BL2_SOURCES += ${CSS_ENT_BASE}/sgi_image_load.c BL31_SOURCES += ${INTERCONNECT_SOURCES} \ ${ENT_GIC_SOURCES} \ ${CSS_ENT_BASE}/sgi_bl31_setup.c \ ${CSS_ENT_BASE}/sgi_topology.c ifeq (${RAS_EXTENSION},1) BL31_SOURCES += ${CSS_ENT_BASE}/sgi_ras.c endif ifneq (${RESET_TO_BL31},0) $(error "Using BL31 as the reset vector is not supported on ${PLAT} platform. \ Please set RESET_TO_BL31 to 0.") endif $(eval $(call add_define,SGI_PLAT)) override CSS_LOAD_SCP_IMAGES := 0 override NEED_BL2U := no override ARM_BL31_IN_DRAM := 1 override ARM_PLAT_MT := 1 # System coherency is managed in hardware HW_ASSISTED_COHERENCY := 1 # When building for systems with hardware-assisted coherency, there's no need to # use USE_COHERENT_MEM. Require that USE_COHERENT_MEM must be set to 0 too. USE_COHERENT_MEM := 0 include plat/arm/common/arm_common.mk include plat/arm/css/common/css_common.mk include plat/arm/soc/common/soc_css.mk include plat/arm/board/common/board_common.mk trusted-firmware-a-2.2/plat/arm/css/sgi/sgi_bl31_setup.c000066400000000000000000000042401355360272700231710ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include sgi_platform_info_t sgi_plat_info; static scmi_channel_plat_info_t sgi575_scmi_plat_info = { .scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE, .db_reg_addr = PLAT_CSS_MHU_BASE + CSS_SCMI_MHU_DB_REG_OFF, .db_preserve_mask = 0xfffffffe, .db_modify_mask = 0x1, .ring_doorbell = &mhu_ring_doorbell, }; static scmi_channel_plat_info_t rd_n1e1_edge_scmi_plat_info = { .scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE, .db_reg_addr = PLAT_CSS_MHU_BASE + SENDER_REG_SET(0), .db_preserve_mask = 0xfffffffe, .db_modify_mask = 0x1, .ring_doorbell = &mhuv2_ring_doorbell, }; scmi_channel_plat_info_t *plat_css_get_scmi_info(void) { if (sgi_plat_info.platform_id == RD_N1E1_EDGE_SID_VER_PART_NUM) return &rd_n1e1_edge_scmi_plat_info; else if (sgi_plat_info.platform_id == SGI575_SSC_VER_PART_NUM) return &sgi575_scmi_plat_info; else panic(); } void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { sgi_plat_info.platform_id = plat_arm_sgi_get_platform_id(); sgi_plat_info.config_id = plat_arm_sgi_get_config_id(); arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3); } void bl31_platform_setup(void) { arm_bl31_platform_setup(); #if RAS_EXTENSION sgi_ras_intr_handler_setup(); #endif } const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops) { /* For RD-E1-Edge platform only CPU ON/OFF is supported */ if ((sgi_plat_info.platform_id == RD_N1E1_EDGE_SID_VER_PART_NUM) && (sgi_plat_info.config_id == RD_E1_EDGE_CONFIG_ID)) { ops->cpu_standby = NULL; ops->system_off = NULL; ops->system_reset = NULL; ops->get_sys_suspend_power_state = NULL; ops->pwr_domain_suspend = NULL; ops->pwr_domain_suspend_finish = NULL; } return css_scmi_override_pm_ops(ops); } trusted-firmware-a-2.2/plat/arm/css/sgi/sgi_image_load.c000066400000000000000000000040471355360272700232760ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /******************************************************************************* * This function inserts Platform information via device tree nodes as, * system-id { * platform-id = <0>; * config-id = <0>; * } ******************************************************************************/ static int plat_sgi_append_config_node(void) { bl_mem_params_node_t *mem_params; void *fdt; int nodeoffset, err; unsigned int platid = 0, platcfg = 0; mem_params = get_bl_mem_params_node(NT_FW_CONFIG_ID); if (mem_params == NULL) { ERROR("NT_FW CONFIG base address is NULL"); return -1; } fdt = (void *)(mem_params->image_info.image_base); /* Check the validity of the fdt */ if (fdt_check_header(fdt) != 0) { ERROR("Invalid NT_FW_CONFIG DTB passed\n"); return -1; } nodeoffset = fdt_subnode_offset(fdt, 0, "system-id"); if (nodeoffset < 0) { ERROR("Failed to get system-id node offset\n"); return -1; } platid = plat_arm_sgi_get_platform_id(); err = fdt_setprop_u32(fdt, nodeoffset, "platform-id", platid); if (err < 0) { ERROR("Failed to set platform-id\n"); return -1; } platcfg = plat_arm_sgi_get_config_id(); err = fdt_setprop_u32(fdt, nodeoffset, "config-id", platcfg); if (err < 0) { ERROR("Failed to set config-id\n"); return -1; } flush_dcache_range((uintptr_t)fdt, mem_params->image_info.image_size); return 0; } /******************************************************************************* * This function returns the list of executable images. ******************************************************************************/ bl_params_t *plat_get_next_bl_params(void) { int ret; ret = plat_sgi_append_config_node(); if (ret != 0) panic(); return arm_get_next_bl_params(); } trusted-firmware-a-2.2/plat/arm/css/sgi/sgi_interconnect.c000066400000000000000000000023261355360272700237060ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /* * For SGI575 which support FCM (with automatic interconnect enter/exit), * we should not do anything in these interface functions. * They are used to override the weak functions in cci drivers. */ /****************************************************************************** * Helper function to initialize ARM interconnect driver. *****************************************************************************/ void __init plat_arm_interconnect_init(void) { } /****************************************************************************** * Helper function to place current master into coherency *****************************************************************************/ void plat_arm_interconnect_enter_coherency(void) { } /****************************************************************************** * Helper function to remove current master from coherency *****************************************************************************/ void plat_arm_interconnect_exit_coherency(void) { } trusted-firmware-a-2.2/plat/arm/css/sgi/sgi_plat.c000066400000000000000000000074751355360272700221650ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #define SGI_MAP_FLASH0_RO MAP_REGION_FLAT(V2M_FLASH0_BASE,\ V2M_FLASH0_SIZE, \ MT_DEVICE | MT_RO | MT_SECURE) /* * Table of regions for different BL stages to map using the MMU. * This doesn't include Trusted RAM as the 'mem_layout' argument passed to * arm_configure_mmu_elx() will give the available subset of that. * * Replace or extend the below regions as required */ #if IMAGE_BL1 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, SGI_MAP_FLASH0_RO, CSS_SGI_MAP_DEVICE, SOC_CSS_MAP_DEVICE, {0} }; #endif #if IMAGE_BL2 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, SGI_MAP_FLASH0_RO, CSS_SGI_MAP_DEVICE, SOC_CSS_MAP_DEVICE, ARM_MAP_NS_DRAM1, #if ARM_BL31_IN_DRAM ARM_MAP_BL31_SEC_DRAM, #endif #if ENABLE_SPM ARM_SP_IMAGE_MMAP, #endif #if TRUSTED_BOARD_BOOT && !BL2_AT_EL3 ARM_MAP_BL1_RW, #endif {0} }; #endif #if IMAGE_BL31 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, V2M_MAP_IOFPGA, CSS_SGI_MAP_DEVICE, SOC_CSS_MAP_DEVICE, #if ENABLE_SPM ARM_SPM_BUF_EL3_MMAP, #endif {0} }; #if ENABLE_SPM && defined(IMAGE_BL31) const mmap_region_t plat_arm_secure_partition_mmap[] = { PLAT_ARM_SECURE_MAP_DEVICE, ARM_SP_IMAGE_MMAP, ARM_SP_IMAGE_NS_BUF_MMAP, ARM_SP_CPER_BUF_MMAP, ARM_SP_IMAGE_RW_MMAP, ARM_SPM_BUF_EL0_MMAP, {0} }; #endif /* ENABLE_SPM && defined(IMAGE_BL31) */ #endif ARM_CASSERT_MMAP #if ENABLE_SPM && defined(IMAGE_BL31) /* * Boot information passed to a secure partition during initialisation. Linear * indices in MP information will be filled at runtime. */ static secure_partition_mp_info_t sp_mp_info[] = { [0] = {0x81000000, 0}, [1] = {0x81000100, 0}, [2] = {0x81000200, 0}, [3] = {0x81000300, 0}, [4] = {0x81010000, 0}, [5] = {0x81010100, 0}, [6] = {0x81010200, 0}, [7] = {0x81010300, 0}, }; const secure_partition_boot_info_t plat_arm_secure_partition_boot_info = { .h.type = PARAM_SP_IMAGE_BOOT_INFO, .h.version = VERSION_1, .h.size = sizeof(secure_partition_boot_info_t), .h.attr = 0, .sp_mem_base = ARM_SP_IMAGE_BASE, .sp_mem_limit = ARM_SP_IMAGE_LIMIT, .sp_image_base = ARM_SP_IMAGE_BASE, .sp_stack_base = PLAT_SP_IMAGE_STACK_BASE, .sp_heap_base = ARM_SP_IMAGE_HEAP_BASE, .sp_ns_comm_buf_base = PLAT_SP_IMAGE_NS_BUF_BASE, .sp_shared_buf_base = PLAT_SPM_BUF_BASE, .sp_image_size = ARM_SP_IMAGE_SIZE, .sp_pcpu_stack_size = PLAT_SP_IMAGE_STACK_PCPU_SIZE, .sp_heap_size = ARM_SP_IMAGE_HEAP_SIZE, .sp_ns_comm_buf_size = PLAT_SP_IMAGE_NS_BUF_SIZE, .sp_shared_buf_size = PLAT_SPM_BUF_SIZE, .num_sp_mem_regions = ARM_SP_IMAGE_NUM_MEM_REGIONS, .num_cpus = PLATFORM_CORE_COUNT, .mp_info = &sp_mp_info[0], }; const struct mmap_region *plat_get_secure_partition_mmap(void *cookie) { return plat_arm_secure_partition_mmap; } const struct secure_partition_boot_info *plat_get_secure_partition_boot_info( void *cookie) { return &plat_arm_secure_partition_boot_info; } #endif /* ENABLE_SPM && defined(IMAGE_BL31) */ #if TRUSTED_BOARD_BOOT int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size) { assert(heap_addr != NULL); assert(heap_size != NULL); return arm_get_mbedtls_heap(heap_addr, heap_size); } #endif void plat_arm_secure_wdt_start(void) { sbsa_wdog_start(SBSA_SECURE_WDOG_BASE, SBSA_SECURE_WDOG_TIMEOUT); } void plat_arm_secure_wdt_stop(void) { sbsa_wdog_stop(SBSA_SECURE_WDOG_BASE); } trusted-firmware-a-2.2/plat/arm/css/sgi/sgi_ras.c000066400000000000000000000103031355360272700217720ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include static int sgi_ras_intr_handler(const struct err_record_info *err_rec, int probe_data, const struct err_handler_data *const data); struct efi_guid { uint32_t data1; uint16_t data2; uint16_t data3; uint8_t data4[8]; }; typedef struct mm_communicate_header { struct efi_guid header_guid; size_t message_len; uint8_t data[8]; } mm_communicate_header_t; struct sgi_ras_ev_map sgi575_ras_map[] = { /* DMC620 error overflow interrupt*/ {SP_DMC_ERROR_OVERFLOW_EVENT_AARCH64, SGI_SDEI_DS_EVENT_1, 33}, /* DMC620 error ECC error interrupt*/ {SP_DMC_ERROR_ECC_EVENT_AARCH64, SGI_SDEI_DS_EVENT_0, 35}, }; #define SGI575_RAS_MAP_SIZE ARRAY_SIZE(sgi575_ras_map) struct err_record_info sgi_err_records[] = { { .handler = &sgi_ras_intr_handler, }, }; struct ras_interrupt sgi_ras_interrupts[] = { { .intr_number = 33, .err_record = &sgi_err_records[0], }, { .intr_number = 35, .err_record = &sgi_err_records[0], } }; REGISTER_ERR_RECORD_INFO(sgi_err_records); REGISTER_RAS_INTERRUPTS(sgi_ras_interrupts); static struct sgi_ras_ev_map *plat_sgi_get_ras_ev_map(void) { return sgi575_ras_map; } static int plat_sgi_get_ras_ev_map_size(void) { return SGI575_RAS_MAP_SIZE; } /* * Find event mapping for a given interrupt number: On success, returns pointer * to the event mapping. On error, returns NULL. */ static struct sgi_ras_ev_map *find_ras_event_map_by_intr(uint32_t intr_num) { struct sgi_ras_ev_map *map = plat_sgi_get_ras_ev_map(); int i; int size = plat_sgi_get_ras_ev_map_size(); for (i = 0; i < size; i++) { if (map->intr == intr_num) return map; map++; } return NULL; } static void sgi_ras_intr_configure(int intr) { plat_ic_set_interrupt_type(intr, INTR_TYPE_EL3); plat_ic_set_interrupt_priority(intr, PLAT_RAS_PRI); plat_ic_clear_interrupt_pending(intr); plat_ic_set_spi_routing(intr, INTR_ROUTING_MODE_ANY, (u_register_t)read_mpidr_el1()); plat_ic_enable_interrupt(intr); } static int sgi_ras_intr_handler(const struct err_record_info *err_rec, int probe_data, const struct err_handler_data *const data) { struct sgi_ras_ev_map *ras_map; mm_communicate_header_t *header; uint32_t intr; cm_el1_sysregs_context_save(NON_SECURE); intr = data->interrupt; /* * Find if this is a RAS interrupt. There must be an event against * this interrupt */ ras_map = find_ras_event_map_by_intr(intr); assert(ras_map); /* * Populate the MM_COMMUNICATE payload to share the * event info with StandaloneMM code. This allows us to use * MM_COMMUNICATE as a common entry mechanism into S-EL0. The * header data will be parsed in StandaloneMM to process the * corresponding event. * * TBD - Currently, the buffer allocated by SPM for communication * between EL3 and S-EL0 is being used(PLAT_SPM_BUF_BASE). But this * should happen via a dynamic mem allocation, which should be * managed by SPM -- the individual platforms then call the mem * alloc api to get memory for the payload. */ header = (void *) PLAT_SPM_BUF_BASE; memset(header, 0, sizeof(*header)); memcpy(&header->data, &ras_map->ras_ev_num, sizeof(ras_map->ras_ev_num)); header->message_len = 4; spm_sp_call(MM_COMMUNICATE_AARCH64, (uint64_t)header, 0, plat_my_core_pos()); /* * Do an EOI of the RAS interuupt. This allows the * sdei event to be dispatched at the SDEI event's * priority. */ plat_ic_end_of_interrupt(intr); /* Dispatch the event to the SDEI client */ sdei_dispatch_event(ras_map->sdei_ev_num); return 0; } int sgi_ras_intr_handler_setup(void) { int i; struct sgi_ras_ev_map *map = plat_sgi_get_ras_ev_map(); int size = plat_sgi_get_ras_ev_map_size(); for (i = 0; i < size; i++) { sgi_ras_intr_configure(map->intr); map++; } INFO("SGI: RAS Interrupt Handler successfully registered\n"); return 0; } trusted-firmware-a-2.2/plat/arm/css/sgi/sgi_topology.c000066400000000000000000000054751355360272700230770ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /* Topology */ /* * The power domain tree descriptor. The cluster power domains are * arranged so that when the PSCI generic code creates the power domain tree, * the indices of the CPU power domain nodes it allocates match the linear * indices returned by plat_core_pos_by_mpidr(). */ const unsigned char sgi_pd_tree_desc[] = { PLAT_ARM_CLUSTER_COUNT, CSS_SGI_MAX_CPUS_PER_CLUSTER, CSS_SGI_MAX_CPUS_PER_CLUSTER }; /* RD-E1-Edge platform consists of 16 physical CPUS and 32 threads */ const unsigned char rd_e1_edge_pd_tree_desc[] = { PLAT_ARM_CLUSTER_COUNT, CSS_SGI_MAX_CPUS_PER_CLUSTER, CSS_SGI_MAX_CPUS_PER_CLUSTER, CSS_SGI_MAX_PE_PER_CPU, CSS_SGI_MAX_PE_PER_CPU, CSS_SGI_MAX_PE_PER_CPU, CSS_SGI_MAX_PE_PER_CPU, CSS_SGI_MAX_PE_PER_CPU, CSS_SGI_MAX_PE_PER_CPU, CSS_SGI_MAX_PE_PER_CPU, CSS_SGI_MAX_PE_PER_CPU, CSS_SGI_MAX_PE_PER_CPU, CSS_SGI_MAX_PE_PER_CPU, CSS_SGI_MAX_PE_PER_CPU, CSS_SGI_MAX_PE_PER_CPU, CSS_SGI_MAX_PE_PER_CPU, CSS_SGI_MAX_PE_PER_CPU, CSS_SGI_MAX_PE_PER_CPU, CSS_SGI_MAX_PE_PER_CPU }; /******************************************************************************* * This function returns the topology tree information. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { if (sgi_plat_info.platform_id == RD_N1E1_EDGE_SID_VER_PART_NUM && sgi_plat_info.config_id == RD_E1_EDGE_CONFIG_ID) return rd_e1_edge_pd_tree_desc; else return sgi_pd_tree_desc; } /******************************************************************************* * This function returns the core count within the cluster corresponding to * `mpidr`. ******************************************************************************/ unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr) { return CSS_SGI_MAX_CPUS_PER_CLUSTER; } /******************************************************************************* * The array mapping platform core position (implemented by plat_my_core_pos()) * to the SCMI power domain ID implemented by SCP. ******************************************************************************/ const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[32] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, \ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; /****************************************************************************** * Return the number of PE's supported by the CPU. *****************************************************************************/ unsigned int plat_arm_get_cpu_pe_count(u_register_t mpidr) { return CSS_SGI_MAX_PE_PER_CPU; } trusted-firmware-a-2.2/plat/arm/css/sgm/000077500000000000000000000000001355360272700202065ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/css/sgm/aarch64/000077500000000000000000000000001355360272700214365ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/css/sgm/aarch64/css_sgm_helpers.S000066400000000000000000000043231355360272700247440ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include .globl plat_arm_calc_core_pos .globl plat_reset_handler /* --------------------------------------------------------------------- * unsigned int plat_arm_calc_core_pos(u_register_t mpidr) * * Function to calculate the core position on FVP. * * (ClusterId * MAX_CPUS_PER_CLUSTER * MAX_PE_PER_CPU) + * (CPUId * MAX_PE_PER_CPU) + * ThreadId * * which can be simplified as: * * ((ClusterId * MAX_CPUS_PER_CLUSTER + CPUId) * MAX_PE_PER_CPU) * + ThreadId * --------------------------------------------------------------------- */ func plat_arm_calc_core_pos /* * Check for MT bit in MPIDR. If not set, shift MPIDR to left to make it * look as if in a multi-threaded implementation. */ tst x0, #MPIDR_MT_MASK lsr x3, x0, #MPIDR_AFFINITY_BITS csel x3, x3, x0, eq /* Extract individual affinity fields from MPIDR */ ubfx x0, x3, #MPIDR_AFF0_SHIFT, #MPIDR_AFFINITY_BITS ubfx x1, x3, #MPIDR_AFF1_SHIFT, #MPIDR_AFFINITY_BITS ubfx x2, x3, #MPIDR_AFF2_SHIFT, #MPIDR_AFFINITY_BITS /* Compute linear position */ mov x4, #PLAT_MAX_CPUS_PER_CLUSTER madd x1, x2, x4, x1 mov x5, #PLAT_MAX_PE_PER_CPU madd x0, x1, x5, x0 ret endfunc plat_arm_calc_core_pos /* ----------------------------------------------------- * void plat_reset_handler(void); * * Determine the CPU MIDR and disable power down bit for * that CPU. * ----------------------------------------------------- */ func plat_reset_handler jump_if_cpu_midr CORTEX_A75_MIDR, A75 jump_if_cpu_midr CORTEX_A55_MIDR, A55 ret /* ----------------------------------------------------- * Disable CPU power down bit in power control register * ----------------------------------------------------- */ A75: mrs x0, CORTEX_A75_CPUPWRCTLR_EL1 bic x0, x0, #CORTEX_A75_CORE_PWRDN_EN_MASK msr CORTEX_A75_CPUPWRCTLR_EL1, x0 isb ret A55: mrs x0, CORTEX_A55_CPUPWRCTLR_EL1 bic x0, x0, #CORTEX_A55_CORE_PWRDN_EN_MASK msr CORTEX_A55_CPUPWRCTLR_EL1, x0 isb ret endfunc plat_reset_handler trusted-firmware-a-2.2/plat/arm/css/sgm/fdts/000077500000000000000000000000001355360272700211465ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/css/sgm/fdts/sgm_tb_fw_config.dts000066400000000000000000000013751355360272700251640ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /dts-v1/; / { /* Platform Config */ plat_arm_bl2 { compatible = "arm,tb_fw"; hw_config_addr = <0x0 0x83000000>; hw_config_max_size = <0x01000000>; /* * The following two entries are placeholders for Mbed TLS * heap information. The default values don't matter since * they will be overwritten by BL1. * In case of having shared Mbed TLS heap between BL1 and BL2, * BL1 will populate these two properties with the respective * info about the shared heap. This info will be available for * BL2 in order to locate and re-use the heap. */ mbedtls_heap_addr = <0x0 0x0>; mbedtls_heap_size = <0x0>; }; }; trusted-firmware-a-2.2/plat/arm/css/sgm/include/000077500000000000000000000000001355360272700216315ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/css/sgm/include/plat_macros.S000066400000000000000000000010611355360272700242570ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S #include #include /* --------------------------------------------- * The below required platform porting macro * prints out relevant platform registers * whenever an unhandled exception is taken in * BL31. * --------------------------------------------- */ .macro plat_crash_print_regs css_print_gic_regs print_cci_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/arm/css/sgm/include/sgm_base_platform_def.h000066400000000000000000000164371355360272700263170ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SGM_BASE_PLATFORM_DEF_H #define SGM_BASE_PLATFORM_DEF_H #include #include #include #include #include #include #include #include /* CPU topology */ #define PLAT_ARM_CLUSTER_COUNT 1 #define PLAT_ARM_CLUSTER_CORE_COUNT 8 #define PLATFORM_CORE_COUNT PLAT_ARM_CLUSTER_CORE_COUNT #define PLAT_MAX_PWR_LVL ARM_PWR_LVL2 #define PLAT_NUM_PWR_DOMAINS (ARM_SYSTEM_COUNT + \ PLAT_ARM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) /* * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 * terminology. On a GICv2 system or mode, the lists will be merged and treated * as Group 0 interrupts. */ #define PLAT_ARM_G1S_IRQ_PROPS(grp) \ CSS_G1S_IRQ_PROPS(grp), \ ARM_G1S_IRQ_PROPS(grp) #define PLAT_ARM_G0_IRQ_PROPS(grp) ARM_G0_IRQ_PROPS(grp) /* GIC related constants */ #define PLAT_ARM_GICD_BASE 0x30000000 #define PLAT_ARM_GICR_BASE 0x300C0000 #define PLAT_ARM_GICC_BASE 0x2c000000 #define CSS_GIC_SIZE 0x00200000 #define CSS_MAP_GIC_DEVICE MAP_REGION_FLAT( \ PLAT_ARM_GICD_BASE, \ CSS_GIC_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) /* Platform ID address */ #define SSC_VERSION (SSC_REG_BASE + SSC_VERSION_OFFSET) #ifndef __ASSEMBLER__ /* SSC_VERSION related accessors */ /* Returns the part number of the platform */ #define GET_PLAT_PART_NUM \ GET_SSC_VERSION_PART_NUM(mmio_read_32(SSC_VERSION)) /* Returns the configuration number of the platform */ #define GET_PLAT_CONFIG_NUM \ GET_SSC_VERSION_CONFIG(mmio_read_32(SSC_VERSION)) #endif /* __ASSEMBLER__ */ /************************************************************************* * Definitions common to all SGM CSS based platforms *************************************************************************/ /* TZC-400 related constants */ #define PLAT_ARM_TZC_BASE 0x2a500000 #define TZC_NSAID_ALL_AP 0 /* Note: Same as default NSAID!! */ #define TZC_NSAID_HDLCD0 2 #define TZC_NSAID_HDLCD1 3 #define TZC_NSAID_GPU 9 #define TZC_NSAID_VIDEO 10 #define TZC_NSAID_DISP0 11 #define TZC_NSAID_DISP1 12 /************************************************************************* * Required platform porting definitions common to all SGM CSS based * platforms *************************************************************************/ #define PLAT_ARM_TRUSTED_SRAM_SIZE 0x00040000 /* 256 KB */ /* MHU related constants */ #define PLAT_CSS_MHU_BASE 0x2b1f0000 #define PLAT_MHUV2_BASE PLAT_CSS_MHU_BASE #define PLAT_ARM_TRUSTED_ROM_BASE 0x00000000 #define PLAT_ARM_TRUSTED_ROM_SIZE 0x00080000 #define PLAT_ARM_CCI_BASE 0x2a000000 /* Cluster to CCI slave mapping */ #define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX 6 #define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX 5 /* System timer related constants */ #define PLAT_ARM_NSTIMER_FRAME_ID 0 /* TZC related constants */ #define PLAT_ARM_TZC_NS_DEV_ACCESS ( \ TZC_REGION_ACCESS_RDWR(TZC_NSAID_ALL_AP) | \ TZC_REGION_ACCESS_RDWR(TZC_NSAID_HDLCD0) | \ TZC_REGION_ACCESS_RDWR(TZC_NSAID_HDLCD1) | \ TZC_REGION_ACCESS_RDWR(TZC_NSAID_GPU) | \ TZC_REGION_ACCESS_RDWR(TZC_NSAID_VIDEO) | \ TZC_REGION_ACCESS_RDWR(TZC_NSAID_DISP0) | \ TZC_REGION_ACCESS_RDWR(TZC_NSAID_DISP1)) /* Display Processor register definitions to setup the NSAIDs */ #define MALI_DP_BASE 0x2cc00000 #define DP_NPROT_NSAID_OFFSET 0x1000c #define W_NPROT_NSAID_SHIFT 24 #define LS_NPORT_NSAID_SHIFT 12 /* * Base address of the first memory region used for communication between AP * and SCP. Used by the BootOverMHU and SCPI protocols. */ #if !CSS_USE_SCMI_SDS_DRIVER /* * Note that this is located at the same address as SCP_BOOT_CFG_ADDR, which * means the SCP/AP configuration data gets overwritten when the AP initiates * communication with the SCP. The configuration data is expected to be a * 32-bit word on all CSS platforms. Part of this configuration is * which CPU is the primary, according to the shift and mask definitions below. */ #define PLAT_CSS_SCP_COM_SHARED_MEM_BASE (ARM_TRUSTED_SRAM_BASE + 0x80) #define PLAT_CSS_PRIMARY_CPU_SHIFT 8 #define PLAT_CSS_PRIMARY_CPU_BIT_WIDTH 4 #endif /* * PLAT_CSS_MAX_SCP_BL2_SIZE is calculated using the current * SCP_BL2 size plus a little space for growth. */ #define PLAT_CSS_MAX_SCP_BL2_SIZE 0x15000 /* * PLAT_CSS_MAX_SCP_BL2U_SIZE is calculated using the current * SCP_BL2U size plus a little space for growth. */ #define PLAT_CSS_MAX_SCP_BL2U_SIZE 0x15000 /* * Most platform porting definitions provided by included headers */ /* * PLAT_ARM_MMAP_ENTRIES depends on the number of entries in the * plat_arm_mmap array defined for each BL stage. */ #if defined(IMAGE_BL31) # define PLAT_ARM_MMAP_ENTRIES 8 # define MAX_XLAT_TABLES 5 #elif defined(IMAGE_BL32) # define PLAT_ARM_MMAP_ENTRIES 8 # define MAX_XLAT_TABLES 5 #elif !USE_ROMLIB # define PLAT_ARM_MMAP_ENTRIES 11 # define MAX_XLAT_TABLES 5 #else # define PLAT_ARM_MMAP_ENTRIES 12 # define MAX_XLAT_TABLES 6 #endif /* * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size * plus a little space for growth. */ #define PLAT_ARM_MAX_BL1_RW_SIZE 0xB000 /* * PLAT_ARM_MAX_ROMLIB_RW_SIZE is define to use a full page */ #if USE_ROMLIB #define PLAT_ARM_MAX_ROMLIB_RW_SIZE 0x1000 #define PLAT_ARM_MAX_ROMLIB_RO_SIZE 0xe000 #else #define PLAT_ARM_MAX_ROMLIB_RW_SIZE 0 #define PLAT_ARM_MAX_ROMLIB_RO_SIZE 0 #endif /* * PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a * little space for growth. */ #if TRUSTED_BOARD_BOOT # define PLAT_ARM_MAX_BL2_SIZE 0x1D000 #else # define PLAT_ARM_MAX_BL2_SIZE 0x11000 #endif /* * Since BL31 NOBITS overlays BL2 and BL1-RW, PLAT_ARM_MAX_BL31_SIZE is * calculated using the current BL31 PROGBITS debug size plus the sizes of * BL2 and BL1-RW */ #define PLAT_ARM_MAX_BL31_SIZE 0x3B000 /* * Size of cacheable stacks */ #if defined(IMAGE_BL1) # if TRUSTED_BOARD_BOOT # define PLATFORM_STACK_SIZE 0x1000 # else # define PLATFORM_STACK_SIZE 0x440 # endif #elif defined(IMAGE_BL2) # if TRUSTED_BOARD_BOOT # define PLATFORM_STACK_SIZE 0x1000 # else # define PLATFORM_STACK_SIZE 0x400 # endif #elif defined(IMAGE_BL2U) # define PLATFORM_STACK_SIZE 0x400 #elif defined(IMAGE_BL31) # define PLATFORM_STACK_SIZE 0x400 #elif defined(IMAGE_BL32) # define PLATFORM_STACK_SIZE 0x440 #endif /******************************************************************************* * Memprotect definitions ******************************************************************************/ /* PSCI memory protect definitions: * This variable is stored in a non-secure flash because some ARM reference * platforms do not have secure NVRAM. Real systems that provided MEM_PROTECT * support must use a secure NVRAM to store the PSCI MEM_PROTECT definitions. */ #define PLAT_ARM_MEM_PROT_ADDR (V2M_FLASH0_BASE + \ V2M_FLASH0_SIZE - V2M_FLASH_BLOCK_SIZE) /* System power domain level */ #define CSS_SYSTEM_PWR_DMN_LVL ARM_PWR_LVL2 #endif /* SGM_BASE_PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/arm/css/sgm/include/sgm_plat_config.h000066400000000000000000000017141355360272700251400ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SGM_PLAT_CONFIG_H #define SGM_PLAT_CONFIG_H #include #include /* The type of interconnect */ typedef enum { ARM_CCI = 0, ARM_CCN, ARM_CMN } css_inteconn_type_t; typedef ccn_desc_t inteconn_desc_t; /* Interconnect configurations */ typedef struct css_inteconn_config { css_inteconn_type_t ip_type; const inteconn_desc_t *plat_inteconn_desc; } css_inteconn_config_t; /* Topology configurations */ typedef struct css_topology { const unsigned char *power_tree; unsigned int plat_cluster_core_count; } css_topology_t; typedef struct css_plat_config { const gicv3_driver_data_t *gic_data; const css_inteconn_config_t *inteconn; const css_topology_t *topology; } css_plat_config_t; void plat_config_init(void); css_plat_config_t *get_plat_config(void); #endif /* SGM_PLAT_CONFIG_H */ trusted-firmware-a-2.2/plat/arm/css/sgm/include/sgm_variant.h000066400000000000000000000005541355360272700243200ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SGM_VARIANT_H #define SGM_VARIANT_H /* SSC_VERSION values for sgm */ #define SGM775_SSC_VER_PART_NUM 0x0790 /* DMC configuration for sgm */ #define SGM_DMC_SIZE 0x40000 #define SGM775_DMC_COUNT 4 #endif /* SGM_VARIANT_H */ trusted-firmware-a-2.2/plat/arm/css/sgm/sgm-common.mk000066400000000000000000000041101355360272700226070ustar00rootroot00000000000000# # Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # CSS_SGM_BASE := plat/arm/css/sgm PLAT_INCLUDES := -I${CSS_SGM_BASE}/include PLAT_BL_COMMON_SOURCES := ${CSS_SGM_BASE}/sgm_mmap_config.c \ ${CSS_SGM_BASE}/aarch64/css_sgm_helpers.S SECURITY_SOURCES := drivers/arm/tzc/tzc_dmc500.c \ plat/arm/common/arm_tzc_dmc500.c \ ${CSS_SGM_BASE}/sgm_security.c SGM_CPU_SOURCES := lib/cpus/aarch64/cortex_a55.S \ lib/cpus/aarch64/cortex_a75.S INTERCONNECT_SOURCES := ${CSS_SGM_BASE}/sgm_interconnect.c SGM_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v3/gicv3_main.c \ drivers/arm/gic/v3/gicv3_helpers.c \ plat/common/plat_gicv3.c \ plat/arm/common/arm_gicv3.c \ drivers/arm/gic/v3/gic600.c \ drivers/arm/gic/v3/arm_gicv3_common.c BL1_SOURCES += $(SGM_CPU_SOURCES) \ ${INTERCONNECT_SOURCES} \ ${CSS_SGM_BASE}/sgm_bl1_setup.c \ ${CSS_SGM_BASE}/sgm_plat_config.c \ drivers/arm/sp805/sp805.c BL2_SOURCES += ${SECURITY_SOURCES} \ ${CSS_SGM_BASE}/sgm_plat_config.c BL2U_SOURCES += ${SECURITY_SOURCES} BL31_SOURCES += $(SGM_CPU_SOURCES) \ ${INTERCONNECT_SOURCES} \ ${SECURITY_SOURCES} \ ${SGM_GIC_SOURCES} \ ${CSS_SGM_BASE}/sgm_topology.c \ ${CSS_SGM_BASE}/sgm_bl31_setup.c \ ${CSS_SGM_BASE}/sgm_plat_config.c ifneq (${RESET_TO_BL31},0) $(error "Using BL31 as the reset vector is not supported on ${PLAT} platform. \ Please set RESET_TO_BL31 to 0.") endif # sgm uses CCI-500 as Cache Coherent Interconnect ARM_CCI_PRODUCT_ID := 500 # System coherency is managed in hardware HW_ASSISTED_COHERENCY := 1 # When building for systems with hardware-assisted coherency, there's no need to # use USE_COHERENT_MEM. Require that USE_COHERENT_MEM must be set to 0 too. USE_COHERENT_MEM := 0 override ARM_PLAT_MT := 1 $(eval $(call add_define,SGM_PLAT)) include plat/arm/common/arm_common.mk include plat/arm/board/common/board_common.mk include plat/arm/css/common/css_common.mk include plat/arm/soc/common/soc_css.mk trusted-firmware-a-2.2/plat/arm/css/sgm/sgm_bl1_setup.c000066400000000000000000000020131355360272700231120ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include void bl1_early_platform_setup(void) { /* Initialize the console before anything else */ arm_bl1_early_platform_setup(); /* Initialize the platform configuration structure */ plat_config_init(); #if !HW_ASSISTED_COHERENCY /* * Initialize Interconnect for this cluster during cold boot. * No need for locks as no other CPU is active. */ plat_arm_interconnect_init(); /* * Enable Interconnect coherency for the primary CPU's cluster. */ plat_arm_interconnect_enter_coherency(); #endif } void plat_arm_secure_wdt_start(void) { sp805_start(ARM_SP805_TWDG_BASE, ARM_TWDG_LOAD_VAL); } void plat_arm_secure_wdt_stop(void) { sp805_stop(ARM_SP805_TWDG_BASE); } trusted-firmware-a-2.2/plat/arm/css/sgm/sgm_bl31_setup.c000066400000000000000000000025531355360272700232060ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include static scmi_channel_plat_info_t sgm775_scmi_plat_info = { .scmi_mbx_mem = CSS_SCMI_PAYLOAD_BASE, .db_reg_addr = PLAT_CSS_MHU_BASE + CSS_SCMI_MHU_DB_REG_OFF, .db_preserve_mask = 0xfffffffe, .db_modify_mask = 0x1, .ring_doorbell = &mhu_ring_doorbell, }; scmi_channel_plat_info_t *plat_css_get_scmi_info() { return &sgm775_scmi_plat_info; } void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { uint32_t plat_version; bl_params_node_t *bl_params; bl_params = ((bl_params_t *)arg0)->head; /* Initialize the platform configuration structure */ plat_config_init(); while (bl_params) { if (bl_params->image_id == BL33_IMAGE_ID) { plat_version = mmio_read_32(SSC_VERSION); bl_params->ep_info->args.arg2 = plat_version; break; } bl_params = bl_params->next_params_info; } arm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3); } const plat_psci_ops_t *plat_arm_psci_override_pm_ops(plat_psci_ops_t *ops) { return css_scmi_override_pm_ops(ops); } trusted-firmware-a-2.2/plat/arm/css/sgm/sgm_interconnect.c000066400000000000000000000022161355360272700237140ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* * As the SGM platform supports FCM (with automatic interconnect * enter/exit), we should not do anything in these interface functions. * They are used to override the weak functions in cci drivers. */ /****************************************************************************** * Helper function to initialize ARM interconnect driver. *****************************************************************************/ void __init plat_arm_interconnect_init(void) { } /****************************************************************************** * Helper function to place current master into coherency *****************************************************************************/ void plat_arm_interconnect_enter_coherency(void) { } /****************************************************************************** * Helper function to remove current master from coherency *****************************************************************************/ void plat_arm_interconnect_exit_coherency(void) { } trusted-firmware-a-2.2/plat/arm/css/sgm/sgm_mmap_config.c000066400000000000000000000031551355360272700235030ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* * Table of regions for different BL stages to map using the MMU. * This doesn't include Trusted RAM as the 'mem_layout' argument passed to * arm_configure_mmu_elx() will give the available subset of that. */ #if IMAGE_BL1 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, V2M_MAP_FLASH0_RO, V2M_MAP_IOFPGA, CSS_MAP_DEVICE, CSS_MAP_GIC_DEVICE, SOC_CSS_MAP_DEVICE, #if TRUSTED_BOARD_BOOT ARM_MAP_NS_DRAM1, #endif {0} }; #endif #if IMAGE_BL2 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, V2M_MAP_FLASH0_RO, V2M_MAP_IOFPGA, CSS_MAP_DEVICE, CSS_MAP_GIC_DEVICE, SOC_CSS_MAP_DEVICE, ARM_MAP_NS_DRAM1, #ifdef SPD_tspd ARM_MAP_TSP_SEC_MEM, #endif #ifdef SPD_opteed ARM_OPTEE_PAGEABLE_LOAD_MEM, #endif #if TRUSTED_BOARD_BOOT && !BL2_AT_EL3 ARM_MAP_BL1_RW, #endif {0} }; #endif #if IMAGE_BL2U const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, CSS_MAP_DEVICE, CSS_MAP_GIC_DEVICE, SOC_CSS_MAP_DEVICE, {0} }; #endif #if IMAGE_BL31 const mmap_region_t plat_arm_mmap[] = { ARM_MAP_SHARED_RAM, V2M_MAP_IOFPGA, CSS_MAP_DEVICE, CSS_MAP_GIC_DEVICE, SOC_CSS_MAP_DEVICE, {0} }; #endif #if IMAGE_BL32 const mmap_region_t plat_arm_mmap[] = { V2M_MAP_IOFPGA, CSS_MAP_DEVICE, CSS_MAP_GIC_DEVICE, SOC_CSS_MAP_DEVICE, {0} }; #endif ARM_CASSERT_MMAP const mmap_region_t *plat_arm_get_mmap(void) { return plat_arm_mmap; } trusted-firmware-a-2.2/plat/arm/css/sgm/sgm_plat_config.c000066400000000000000000000040001355360272700234770ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include static css_plat_config_t *css_plat_info; /* Interconnect */ const css_inteconn_config_t sgm_inteconn = { .ip_type = ARM_CCI, .plat_inteconn_desc = NULL }; /* Special definition for SGM775 */ /* Topology configuration for SGM775 */ const unsigned char sgm775_power_domain_tree_desc[] = { /* No of root nodes */ ARM_SYSTEM_COUNT, /* No of children for the root node */ PLAT_ARM_CLUSTER_COUNT, /* No of children for the first cluster node */ PLAT_ARM_CLUSTER_CORE_COUNT, }; const css_topology_t sgm775_topology = { .power_tree = sgm775_power_domain_tree_desc, .plat_cluster_core_count = PLAT_ARM_CLUSTER_CORE_COUNT }; /* Configuration structure for SGM775 */ css_plat_config_t sgm775_config = { .inteconn = &sgm_inteconn, .topology = &sgm775_topology }; /******************************************************************************* * This function initializes the platform structure. ******************************************************************************/ void plat_config_init(void) { /* Get the platform configurations */ switch (GET_PLAT_PART_NUM) { case SGM775_SSC_VER_PART_NUM: css_plat_info = &sgm775_config; break; default: ERROR("Not a valid sgm variant!\n"); panic(); } } /******************************************************************************* * This function returns the platform structure pointer. ******************************************************************************/ css_plat_config_t *get_plat_config(void) { assert(css_plat_info != NULL); return css_plat_info; } #if TRUSTED_BOARD_BOOT int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size) { return get_mbedtls_heap_helper(heap_addr, heap_size); } #endif trusted-firmware-a-2.2/plat/arm/css/sgm/sgm_security.c000066400000000000000000000033071355360272700230720ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* Is populated with the DMC-500 controllers base addresses */ static tzc_dmc500_driver_data_t plat_driver_data; void plat_sgm_dp_security_setup(void) { unsigned int nprot_nsaid; /* * At reset the Mali display processors start with NSAIDs set to zero * so the firmware must set them up to the expected values for ARM sgm * platforms. */ nprot_nsaid = mmio_read_32(MALI_DP_BASE + DP_NPROT_NSAID_OFFSET); nprot_nsaid &= ~((0xF << W_NPROT_NSAID_SHIFT) | (0xF << LS_NPORT_NSAID_SHIFT)); nprot_nsaid |= ((TZC_NSAID_DISP1 << W_NPROT_NSAID_SHIFT) | (TZC_NSAID_DISP0 << LS_NPORT_NSAID_SHIFT)); mmio_write_32(MALI_DP_BASE + DP_NPROT_NSAID_OFFSET, nprot_nsaid); } void plat_arm_security_setup(void) { unsigned int i; unsigned int part_num = GET_PLAT_PART_NUM; INFO("part_num: 0x%x\n", part_num); /* * Initialise plat_driver_data with platform specific DMC_BASE * addresses */ switch (part_num) { case SGM775_SSC_VER_PART_NUM: for (i = 0; i < SGM775_DMC_COUNT; i++) plat_driver_data.dmc_base[i] = PLAT_ARM_TZC_BASE + SGM_DMC_SIZE * i; plat_driver_data.dmc_count = SGM775_DMC_COUNT; break; default: /* Unexpected platform */ ERROR("Unexpected platform\n"); panic(); } /* Initialize the TrustZone Controller in DMC-500 */ arm_tzc_dmc500_setup(&plat_driver_data, NULL); /* Do DP NSAID setup */ plat_sgm_dp_security_setup(); /* Do ARM CSS SoC security setup */ soc_css_security_setup(); } trusted-firmware-a-2.2/plat/arm/css/sgm/sgm_topology.c000066400000000000000000000022001355360272700230660ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /******************************************************************************* * This function returns the topology tree information. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { return get_plat_config()->topology->power_tree; } /******************************************************************************* * This function returns the core count within the cluster corresponding to * `mpidr`. ******************************************************************************/ unsigned int plat_arm_get_cluster_core_count(u_register_t mpidr) { return get_plat_config()->topology->plat_cluster_core_count; } /* * The array mapping platform core position (implemented by plat_my_core_pos()) * to the SCMI power domain ID implemented by SCP. */ const uint32_t plat_css_core_pos_to_scmi_dmn_id_map[PLATFORM_CORE_COUNT] = { 0, 1, 2, 3, 4, 5, 6, 7 }; trusted-firmware-a-2.2/plat/arm/css/sgm/tsp/000077500000000000000000000000001355360272700210145ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/css/sgm/tsp/sgm_tsp_setup.c000066400000000000000000000005311355360272700240530ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include void tsp_early_platform_setup(void) { /* Initialize the platform configuration structure */ plat_config_init(); arm_tsp_early_platform_setup(); } trusted-firmware-a-2.2/plat/arm/css/sgm/tsp/tsp-sgm.mk000066400000000000000000000004321355360272700227360ustar00rootroot00000000000000# # Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # BL32_SOURCES += ${SGM_GIC_SOURCES} \ ${CSS_SGM_BASE}/sgm_plat_config.c \ plat/arm/css/sgm/tsp/sgm_tsp_setup.c include plat/arm/common/tsp/arm_tsp.mk trusted-firmware-a-2.2/plat/arm/soc/000077500000000000000000000000001355360272700174145ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/soc/common/000077500000000000000000000000001355360272700207045ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/arm/soc/common/soc_css.mk000066400000000000000000000005651355360272700226770ustar00rootroot00000000000000# # Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # #PLAT_BL_COMMON_SOURCES += BL1_SOURCES += plat/arm/soc/common/soc_css_security.c BL2_SOURCES += plat/arm/soc/common/soc_css_security.c BL2U_SOURCES += plat/arm/soc/common/soc_css_security.c BL31_SOURCES += plat/arm/soc/common/soc_css_security.c trusted-firmware-a-2.2/plat/arm/soc/common/soc_css_security.c000066400000000000000000000041131355360272700244320ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include void soc_css_init_nic400(void) { /* * NIC-400 Access Control Initialization * * Define access privileges by setting each corresponding bit to: * 0 = Secure access only * 1 = Non-secure access allowed */ /* * Allow non-secure access to some SOC regions, excluding UART1, which * remains secure (unless CSS_NON_SECURE_UART is set). * Note: This is the NIC-400 device on the SOC */ mmio_write_32(SOC_CSS_NIC400_BASE + NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_USB_EHCI), ~0); mmio_write_32(SOC_CSS_NIC400_BASE + NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_TLX_MASTER), ~0); mmio_write_32(SOC_CSS_NIC400_BASE + NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_USB_OHCI), ~0); mmio_write_32(SOC_CSS_NIC400_BASE + NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_PL354_SMC), ~0); mmio_write_32(SOC_CSS_NIC400_BASE + NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_APB4_BRIDGE), ~0); #if CSS_NON_SECURE_UART /* Configure UART for non-secure access */ mmio_write_32(SOC_CSS_NIC400_BASE + NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_BOOTSEC_BRIDGE), ~0); #else mmio_write_32(SOC_CSS_NIC400_BASE + NIC400_ADDR_CTRL_SECURITY_REG(SOC_CSS_NIC400_BOOTSEC_BRIDGE), ~SOC_CSS_NIC400_BOOTSEC_BRIDGE_UART1); #endif /* CSS_NON_SECURE_UART */ } #define PCIE_SECURE_REG 0x3000 /* Mask uses REG and MEM access bits */ #define PCIE_SEC_ACCESS_MASK ((1 << 0) | (1 << 1)) void soc_css_init_pcie(void) { #if !PLAT_juno /* * Do not initialize PCIe in emulator environment. * Platform ID register not supported on Juno */ if (BOARD_CSS_GET_PLAT_TYPE(BOARD_CSS_PLAT_ID_REG_ADDR) == BOARD_CSS_PLAT_TYPE_EMULATOR) return; #endif /* PLAT_juno */ /* * PCIE Root Complex Security settings to enable non-secure * access to config registers. */ mmio_write_32(SOC_CSS_PCIE_CONTROL_BASE + PCIE_SECURE_REG, PCIE_SEC_ACCESS_MASK); } trusted-firmware-a-2.2/plat/common/000077500000000000000000000000001355360272700173415ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/common/aarch32/000077500000000000000000000000001355360272700205645ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/common/aarch32/crash_console_helpers.S000066400000000000000000000042561355360272700252630ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * If a platform wishes to use the functions in this file it has to be added to * the Makefile of the platform. It is not included in the common Makefile. */ #include #include .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush /* ----------------------------------------------------- * 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 trusted-firmware-a-2.2/plat/common/aarch32/plat_common.c000066400000000000000000000010221355360272700232330ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /* * The following platform setup functions are weakly defined. They * provide typical implementations that may be re-used by multiple * platforms but may also be overridden by a platform if required. */ #pragma weak bl32_plat_enable_mmu void bl32_plat_enable_mmu(uint32_t flags) { enable_mmu_svc_mon(flags); } trusted-firmware-a-2.2/plat/common/aarch32/plat_sp_min_common.c000066400000000000000000000012361355360272700246070ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /* * The following platform setup functions are weakly defined. They * provide typical implementations that may be re-used by multiple * platforms but may also be overridden by a platform if required. */ #pragma weak sp_min_plat_runtime_setup 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. */ console_switch_state(CONSOLE_FLAG_RUNTIME); } trusted-firmware-a-2.2/plat/common/aarch32/platform_helpers.S000066400000000000000000000036261355360272700242650ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .weak plat_report_exception .weak plat_reset_handler .weak plat_disable_acp .weak bl1_plat_prepare_exit .weak platform_mem_init .weak plat_panic_handler /* ----------------------------------------------------- * Placeholder function which should be redefined by * each platform. * ----------------------------------------------------- */ func plat_report_exception bx lr endfunc plat_report_exception /* ----------------------------------------------------- * Placeholder function which should be redefined by * each platform. * ----------------------------------------------------- */ func plat_reset_handler bx lr endfunc plat_reset_handler /* ----------------------------------------------------- * Placeholder function which should be redefined by * each platform. * ----------------------------------------------------- */ func plat_disable_acp bx lr endfunc plat_disable_acp /* --------------------------------------------------------------------- * Placeholder function which should be redefined by * each platform. * --------------------------------------------------------------------- */ func platform_mem_init bx lr endfunc platform_mem_init /* ----------------------------------------------------- * void bl1_plat_prepare_exit(entry_point_info_t *ep_info); * Called before exiting BL1. Default: do nothing * ----------------------------------------------------- */ func bl1_plat_prepare_exit bx lr endfunc bl1_plat_prepare_exit /* ----------------------------------------------------- * void plat_panic_handler(void) __dead2; * Endless loop by default. * ----------------------------------------------------- */ func plat_panic_handler b plat_panic_handler endfunc plat_panic_handler trusted-firmware-a-2.2/plat/common/aarch32/platform_mp_stack.S000066400000000000000000000025611355360272700244210ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .weak plat_get_my_stack .weak plat_set_my_stack /* ----------------------------------------------------- * uintptr_t plat_get_my_stack (u_register_t mpidr) * * For a given CPU, this function returns the stack * pointer for a stack allocated in device memory. * ----------------------------------------------------- */ func plat_get_my_stack push {r4, lr} get_my_mp_stack platform_normal_stacks, PLATFORM_STACK_SIZE pop {r4, pc} endfunc plat_get_my_stack /* ----------------------------------------------------- * void plat_set_my_stack () * * For the current CPU, this function sets the stack * pointer to a stack allocated in normal memory. * ----------------------------------------------------- */ func plat_set_my_stack mov r4, lr get_my_mp_stack platform_normal_stacks, PLATFORM_STACK_SIZE mov sp, r0 bx r4 endfunc plat_set_my_stack /* ----------------------------------------------------- * Per-cpu stacks in normal memory. Each cpu gets a * stack of PLATFORM_STACK_SIZE bytes. * ----------------------------------------------------- */ declare_stack platform_normal_stacks, tzfw_normal_stacks, \ PLATFORM_STACK_SIZE, PLATFORM_CORE_COUNT trusted-firmware-a-2.2/plat/common/aarch32/platform_up_stack.S000066400000000000000000000026361355360272700244340ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .weak plat_get_my_stack .weak plat_set_my_stack /* ----------------------------------------------------- * unsigned long plat_get_my_stack () * * For cold-boot BL images, only the primary CPU needs * a stack. This function returns the stack pointer for * a stack allocated in normal memory. * ----------------------------------------------------- */ func plat_get_my_stack get_up_stack platform_normal_stacks, PLATFORM_STACK_SIZE bx lr endfunc plat_get_my_stack /* ----------------------------------------------------- * void plat_set_my_stack () * * For cold-boot BL images, only the primary CPU needs * a stack. This function sets the stack pointer to a * stack allocated in normal memory. * ----------------------------------------------------- */ func plat_set_my_stack get_up_stack platform_normal_stacks, PLATFORM_STACK_SIZE mov sp, r0 bx lr endfunc plat_set_my_stack /* ----------------------------------------------------- * Per-cpu stacks in normal memory. Each cpu gets a * stack of PLATFORM_STACK_SIZE bytes. * ----------------------------------------------------- */ declare_stack platform_normal_stacks, tzfw_normal_stacks, \ PLATFORM_STACK_SIZE, 1, CACHE_WRITEBACK_GRANULE trusted-firmware-a-2.2/plat/common/aarch64/000077500000000000000000000000001355360272700205715ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/common/aarch64/crash_console_helpers.S000066400000000000000000000137621355360272700252720ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * If a platform wishes to use the functions in this file it has to be added to * the Makefile of the platform. It is not included in the common Makefile. */ #include #include .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush /* * Spinlock to syncronize access to crash_console_triggered. We cannot * acquire spinlocks when the cache is disabled, so in some cases (like * late during CPU suspend) some risk remains. */ .section .data.crash_console_spinlock define_asm_spinlock crash_console_spinlock /* * Flag to make sure that only one CPU can write a crash dump even if * multiple crash at the same time. Interleaving crash dumps on the same * console would just make the output unreadable, so it's better to only * get a single but uncorrupted dump. This also means that we don't have * to duplicate the reg_stash below for each CPU. */ .section .data.crash_console_triggered crash_console_triggered: .byte 0 /* * Space to stash away some register values while we're calling into * console drivers and don't have a real stack available. We need x14, * x15 and x30 for bookkeeping within the plat_crash_console functions * themselves, and some console drivers use x16 and x17 as additional * scratch space that is not preserved by the main crash reporting * framework. (Note that x16 and x17 should really never be expected to * retain their values across any function call, even between carefully * designed assembly functions, since the linker is always free to * insert a function call veneer that uses these registers as scratch * space at any time. The current crash reporting framework doesn't * really respect that, but since TF is usually linked as a single * contiguous binary of less than 128MB, it seems to work in practice.) */ .section .data.crash_console_reg_stash .align 3 crash_console_reg_stash: .quad 0, 0, 0, 0, 0 /* -------------------------------------------------------------------- * int plat_crash_console_init(void) * Takes the crash console spinlock (if possible) and checks the trigger * flag to make sure we're the first CPU to dump. If not, return an * error (so crash dumping will fail but the CPU will still call * plat_panic_handler() which may do important platform-specific tasks * that may be needed on all crashing CPUs). In either case, the lock * will be released so other CPUs can make forward progress on this. * Clobbers: x0 - x4, x30 * -------------------------------------------------------------------- */ func plat_crash_console_init #if defined(IMAGE_BL31) mov x4, x30 /* x3 and x4 are not clobbered by spin_lock() */ mov x3, #0 /* return value */ mrs x1, sctlr_el3 tst x1, #SCTLR_C_BIT beq skip_spinlock /* can't synchronize when cache disabled */ adrp x0, crash_console_spinlock add x0, x0, :lo12:crash_console_spinlock bl spin_lock skip_spinlock: adrp x1, crash_console_triggered add x1, x1, :lo12:crash_console_triggered ldarb w2, [x1] cmp w2, #0 bne init_error mov x3, #1 /* set return value to success */ stlrb w3, [x1] init_error: bl spin_unlock /* harmless if we didn't acquire the lock */ mov x0, x3 ret x4 #else /* Only one CPU in BL1/BL2, no need to synchronize anything */ mov x0, #1 ret #endif endfunc plat_crash_console_init /* -------------------------------------------------------------------- * int plat_crash_console_putc(char c) * Prints the character on all consoles registered with the console * framework that have CONSOLE_FLAG_CRASH set. Note that this is only * helpful for crashes that occur after the platform intialization code * has registered a console. Platforms using this implementation need to * ensure that all console drivers they use that have the CRASH flag set * support this (i.e. are written in assembly and comply to the register * clobber requirements of plat_crash_console_putc(). * -------------------------------------------------------------------- */ func plat_crash_console_putc adrp x1, crash_console_reg_stash add x1, x1, :lo12:crash_console_reg_stash stp x14, x15, [x1] stp x16, x17, [x1, #16] str x30, [x1, #32] mov w14, w0 /* W14 = character to print */ adrp x15, console_list ldr x15, [x15, :lo12:console_list] /* X15 = first console struct */ putc_loop: cbz x15, putc_done ldr w1, [x15, #CONSOLE_T_FLAGS] tst w1, #CONSOLE_FLAG_CRASH b.eq putc_continue ldr x2, [x15, #CONSOLE_T_PUTC] cbz x2, putc_continue cmp w14, #'\n' b.ne putc tst w1, #CONSOLE_FLAG_TRANSLATE_CRLF b.eq putc mov x1, x15 mov w0, #'\r' blr x2 ldr x2, [x15, #CONSOLE_T_PUTC] putc: mov x1, x15 mov w0, w14 blr x2 putc_continue: ldr x15, [x15] /* X15 = next struct */ b putc_loop putc_done: adrp x1, crash_console_reg_stash add x1, x1, :lo12:crash_console_reg_stash ldp x14, x15, [x1] ldp x16, x17, [x1, #16] ldr x30, [x1, #32] ret endfunc plat_crash_console_putc /* -------------------------------------------------------------------- * int plat_crash_console_flush(char c) * Flushes all consoles registered with the console framework that have * CONSOLE_FLAG_CRASH set. Same requirements as putc(). * -------------------------------------------------------------------- */ func plat_crash_console_flush adrp x1, crash_console_reg_stash add x1, x1, :lo12:crash_console_reg_stash stp x30, x15, [x1] stp x16, x17, [x1, #16] adrp x15, console_list ldr x15, [x15, :lo12:console_list] /* X15 = first console struct */ flush_loop: cbz x15, flush_done ldr w1, [x15, #CONSOLE_T_FLAGS] tst w1, #CONSOLE_FLAG_CRASH b.eq flush_continue ldr x2, [x15, #CONSOLE_T_FLUSH] cbz x2, flush_continue mov x0, x15 blr x2 flush_continue: ldr x15, [x15] /* X15 = next struct */ b flush_loop flush_done: adrp x1, crash_console_reg_stash add x1, x1, :lo12:crash_console_reg_stash ldp x30, x15, [x1] ldp x16, x17, [x1, #16] ret endfunc plat_crash_console_flush trusted-firmware-a-2.2/plat/common/aarch64/plat_common.c000066400000000000000000000040741355360272700232520ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #if RAS_EXTENSION #include #endif #include #include /* * The following platform setup functions are weakly defined. They * provide typical implementations that may be re-used by multiple * platforms but may also be overridden by a platform if required. */ #pragma weak bl31_plat_runtime_setup #if SDEI_SUPPORT #pragma weak plat_sdei_handle_masked_trigger #pragma weak plat_sdei_validate_entry_point #endif #pragma weak plat_ea_handler void bl31_plat_runtime_setup(void) { console_switch_state(CONSOLE_FLAG_RUNTIME); } /* * Helper function for platform_get_pos() when platform compatibility is * disabled. This is to enable SPDs using the older platform API to continue * to work. */ unsigned int platform_core_pos_helper(unsigned long mpidr) { int idx = plat_core_pos_by_mpidr(mpidr); assert(idx >= 0); return idx; } #if SDEI_SUPPORT /* * Function that handles spurious SDEI interrupts while events are masked. */ void plat_sdei_handle_masked_trigger(uint64_t mpidr, unsigned int intr) { WARN("Spurious SDEI interrupt %u on masked PE %llx\n", intr, mpidr); } /* * Default Function to validate SDEI entry point, which returns success. * Platforms may override this with their own validation mechanism. */ int plat_sdei_validate_entry_point(uintptr_t ep, unsigned int client_mode) { return 0; } #endif /* RAS functions common to AArch64 ARM platforms */ void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie, void *handle, uint64_t flags) { #if RAS_EXTENSION /* Call RAS EA handler */ int handled = ras_ea_handler(ea_reason, syndrome, cookie, handle, flags); if (handled != 0) return; #endif ERROR("Unhandled External Abort received on 0x%lx at EL3!\n", read_mpidr_el1()); ERROR(" exception reason=%u syndrome=0x%llx\n", ea_reason, syndrome); panic(); } trusted-firmware-a-2.2/plat/common/aarch64/platform_helpers.S000066400000000000000000000065001355360272700242640ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .weak plat_report_exception .weak plat_reset_handler .weak plat_disable_acp .weak bl1_plat_prepare_exit .weak plat_panic_handler .weak bl31_plat_enable_mmu .weak bl32_plat_enable_mmu .weak plat_handle_uncontainable_ea .weak plat_handle_double_fault .weak plat_handle_el3_ea #define MPIDR_RES_BIT_MASK 0xff000000 /* ----------------------------------------------------- * Placeholder function which should be redefined by * each platform. * ----------------------------------------------------- */ func plat_report_exception ret endfunc plat_report_exception /* ----------------------------------------------------- * Placeholder function which should be redefined by * each platform. This function should preserve x19 - x29. * ----------------------------------------------------- */ func plat_reset_handler ret endfunc plat_reset_handler /* ----------------------------------------------------- * Placeholder function which should be redefined by * each platform. This function is allowed to use * registers x0 - x17. * ----------------------------------------------------- */ func plat_disable_acp ret endfunc plat_disable_acp /* ----------------------------------------------------- * void bl1_plat_prepare_exit(entry_point_info_t *ep_info); * Called before exiting BL1. Default: do nothing * ----------------------------------------------------- */ func bl1_plat_prepare_exit ret endfunc bl1_plat_prepare_exit /* ----------------------------------------------------- * void plat_panic_handler(void) __dead2; * Endless loop by default. * ----------------------------------------------------- */ func plat_panic_handler wfi b plat_panic_handler endfunc plat_panic_handler /* ----------------------------------------------------- * void bl31_plat_enable_mmu(uint32_t flags); * * Enable MMU in BL31. * ----------------------------------------------------- */ func bl31_plat_enable_mmu b enable_mmu_direct_el3 endfunc bl31_plat_enable_mmu /* ----------------------------------------------------- * void bl32_plat_enable_mmu(uint32_t flags); * * Enable MMU in BL32. * ----------------------------------------------------- */ func bl32_plat_enable_mmu b enable_mmu_direct_el1 endfunc bl32_plat_enable_mmu /* ----------------------------------------------------- * Platform handler for Uncontainable External Abort. * * x0: EA reason * x1: EA syndrome * ----------------------------------------------------- */ func plat_handle_uncontainable_ea b report_unhandled_exception endfunc plat_handle_uncontainable_ea /* ----------------------------------------------------- * Platform handler for Double Fault. * * x0: EA reason * x1: EA syndrome * ----------------------------------------------------- */ func plat_handle_double_fault b report_unhandled_exception endfunc plat_handle_double_fault /* ----------------------------------------------------- * Platform handler for EL3 External Abort. * ----------------------------------------------------- */ func plat_handle_el3_ea b report_unhandled_exception endfunc plat_handle_el3_ea trusted-firmware-a-2.2/plat/common/aarch64/platform_mp_stack.S000066400000000000000000000037631355360272700244330ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .local platform_normal_stacks .weak plat_get_my_stack .weak plat_set_my_stack /* --------------------------------------------------------------------- * When the compatility layer is disabled, the platform APIs * plat_get_my_stack() and plat_set_my_stack() are supported by the * platform and the previous APIs platform_get_stack() and * platform_set_stack() are defined in terms of new APIs making use of * the fact that they are only ever invoked for the current CPU. This * is to enable components of Trusted Firmware like SPDs using the old * platform APIs to continue to work. * -------------------------------------------------------------------- */ /* ----------------------------------------------------- * uintptr_t plat_get_my_stack () * * For the current CPU, this function returns the stack * pointer for a stack allocated in device memory. * ----------------------------------------------------- */ func plat_get_my_stack mov x10, x30 // lr get_my_mp_stack platform_normal_stacks, PLATFORM_STACK_SIZE ret x10 endfunc plat_get_my_stack /* ----------------------------------------------------- * void plat_set_my_stack () * * For the current CPU, this function sets the stack * pointer to a stack allocated in normal memory. * ----------------------------------------------------- */ func plat_set_my_stack mov x9, x30 // lr bl plat_get_my_stack mov sp, x0 ret x9 endfunc plat_set_my_stack /* ----------------------------------------------------- * Per-cpu stacks in normal memory. Each cpu gets a * stack of PLATFORM_STACK_SIZE bytes. * ----------------------------------------------------- */ declare_stack platform_normal_stacks, tzfw_normal_stacks, \ PLATFORM_STACK_SIZE, PLATFORM_CORE_COUNT, \ CACHE_WRITEBACK_GRANULE trusted-firmware-a-2.2/plat/common/aarch64/platform_up_stack.S000066400000000000000000000027151355360272700244370ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .local platform_normal_stacks .weak plat_set_my_stack .weak plat_get_my_stack /* ----------------------------------------------------- * uintptr_t plat_get_my_stack () * * For cold-boot BL images, only the primary CPU needs a * stack. This function returns the stack pointer for a * stack allocated in device memory. * ----------------------------------------------------- */ func plat_get_my_stack get_up_stack platform_normal_stacks, PLATFORM_STACK_SIZE ret endfunc plat_get_my_stack /* ----------------------------------------------------- * void plat_set_my_stack () * * For cold-boot BL images, only the primary CPU needs a * stack. This function sets the stack pointer to a stack * allocated in normal memory. * ----------------------------------------------------- */ func plat_set_my_stack get_up_stack platform_normal_stacks, PLATFORM_STACK_SIZE mov sp, x0 ret endfunc plat_set_my_stack /* ----------------------------------------------------- * Single cpu stack in normal memory. * Used for C code during boot, PLATFORM_STACK_SIZE bytes * are allocated * ----------------------------------------------------- */ declare_stack platform_normal_stacks, tzfw_normal_stacks, \ PLATFORM_STACK_SIZE, 1, CACHE_WRITEBACK_GRANULE trusted-firmware-a-2.2/plat/common/plat_bl1_common.c000066400000000000000000000055441355360272700225630ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include /* * The following platform functions are weakly defined. They * are default implementations that allow BL1 to compile in * absence of real definitions. The Platforms may override * with more complex definitions. */ #pragma weak bl1_plat_get_next_image_id #pragma weak bl1_plat_set_ep_info #pragma weak bl1_plat_get_image_desc #pragma weak bl1_plat_fwu_done #pragma weak bl1_plat_handle_pre_image_load #pragma weak bl1_plat_handle_post_image_load unsigned int bl1_plat_get_next_image_id(void) { /* BL2 load will be done by default. */ return BL2_IMAGE_ID; } void bl1_plat_set_ep_info(unsigned int image_id, struct entry_point_info *ep_info) { } int bl1_plat_handle_pre_image_load(unsigned int image_id) { return 0; } /* * Following is the default definition that always * returns BL2 image details. */ struct image_desc *bl1_plat_get_image_desc(unsigned int image_id) { static image_desc_t bl2_img_desc = BL2_IMAGE_DESC; return &bl2_img_desc; } __dead2 void bl1_plat_fwu_done(void *client_cookie, void *reserved) { while (1) wfi(); } /* * The Platforms must override with real definition. */ #pragma weak bl1_plat_mem_check int bl1_plat_mem_check(uintptr_t mem_base, unsigned int mem_size, unsigned int flags) { assert(0); return -ENOMEM; } /* * Default implementation for bl1_plat_handle_post_image_load(). This function * populates the default arguments to BL2. The BL2 memory layout structure * is allocated and the calculated layout is populated in arg1 to BL2. */ int bl1_plat_handle_post_image_load(unsigned int image_id) { meminfo_t *bl2_tzram_layout; meminfo_t *bl1_tzram_layout; image_desc_t *image_desc; entry_point_info_t *ep_info; if (image_id != BL2_IMAGE_ID) return 0; /* Get the image descriptor */ image_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID); assert(image_desc != NULL); /* Get the entry point info */ ep_info = &image_desc->ep_info; /* Find out how much free trusted ram remains after BL1 load */ bl1_tzram_layout = bl1_plat_sec_mem_layout(); /* * Create a new layout of memory for BL2 as seen by BL1 i.e. * tell it the amount of total and free memory available. * This layout is created at the first free address visible * to BL2. BL2 will read the memory layout before using its * memory for other purposes. */ bl2_tzram_layout = (meminfo_t *) bl1_tzram_layout->total_base; bl1_calc_bl2_mem_layout(bl1_tzram_layout, bl2_tzram_layout); ep_info->args.arg1 = (uintptr_t)bl2_tzram_layout; VERBOSE("BL1: BL2 memory layout address = %p\n", (void *) bl2_tzram_layout); return 0; } trusted-firmware-a-2.2/plat/common/plat_bl_common.c000066400000000000000000000041021355360272700224670ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* * The following platform functions are weakly defined. The Platforms * may redefine with strong definition. */ #pragma weak bl2_el3_plat_prepare_exit #pragma weak plat_error_handler #pragma weak bl2_plat_preload_setup #pragma weak bl2_plat_handle_pre_image_load #pragma weak bl2_plat_handle_post_image_load #pragma weak plat_try_next_boot_source void bl2_el3_plat_prepare_exit(void) { } void __dead2 plat_error_handler(int err) { while (1) wfi(); } void bl2_plat_preload_setup(void) { } int bl2_plat_handle_pre_image_load(unsigned int image_id) { return 0; } int bl2_plat_handle_post_image_load(unsigned int image_id) { return 0; } int plat_try_next_boot_source(void) { return 0; } /* * Set up the page tables for the generic and platform-specific memory regions. * The size of the Trusted SRAM seen by the BL image must be specified as well * as an array specifying the generic memory regions which can be; * - Code section; * - Read-only data section; * - Init code section, if applicable * - Coherent memory region, if applicable. */ void __init setup_page_tables(const mmap_region_t *bl_regions, const mmap_region_t *plat_regions) { #if LOG_LEVEL >= LOG_LEVEL_VERBOSE const mmap_region_t *regions = bl_regions; while (regions->size != 0U) { VERBOSE("Region: 0x%lx - 0x%lx has attributes 0x%x\n", regions->base_va, regions->base_va + regions->size, regions->attr); regions++; } #endif /* * Map the Trusted SRAM with appropriate memory attributes. * Subsequent mappings will adjust the attributes for specific regions. */ mmap_add(bl_regions); /* Now (re-)map the platform-specific memory regions */ mmap_add(plat_regions); /* Create the page tables to reflect the above mappings */ init_xlat_tables(); } trusted-firmware-a-2.2/plat/common/plat_gicv2.c000066400000000000000000000160701355360272700215430ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* * The following platform GIC functions are weakly defined. They * provide typical implementations that may be re-used by multiple * platforms but may also be overridden by a platform if required. */ #pragma weak plat_ic_get_pending_interrupt_id #pragma weak plat_ic_get_pending_interrupt_type #pragma weak plat_ic_acknowledge_interrupt #pragma weak plat_ic_get_interrupt_type #pragma weak plat_ic_end_of_interrupt #pragma weak plat_interrupt_type_to_line #pragma weak plat_ic_get_running_priority #pragma weak plat_ic_is_spi #pragma weak plat_ic_is_ppi #pragma weak plat_ic_is_sgi #pragma weak plat_ic_get_interrupt_active #pragma weak plat_ic_enable_interrupt #pragma weak plat_ic_disable_interrupt #pragma weak plat_ic_set_interrupt_priority #pragma weak plat_ic_set_interrupt_type #pragma weak plat_ic_raise_el3_sgi #pragma weak plat_ic_set_spi_routing /* * This function returns the highest priority pending interrupt at * the Interrupt controller */ uint32_t plat_ic_get_pending_interrupt_id(void) { unsigned int id; id = gicv2_get_pending_interrupt_id(); if (id == GIC_SPURIOUS_INTERRUPT) return INTR_ID_UNAVAILABLE; return id; } /* * This function returns the type of the highest priority pending interrupt * at the Interrupt controller. In the case of GICv2, the Highest Priority * Pending interrupt register (`GICC_HPPIR`) is read to determine the id of * the pending interrupt. The type of interrupt depends upon the id value * as follows. * 1. id < PENDING_G1_INTID (1022) is reported as a S-EL1 interrupt * 2. id = PENDING_G1_INTID (1022) is reported as a Non-secure interrupt. * 3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt * type. */ uint32_t plat_ic_get_pending_interrupt_type(void) { unsigned int id; id = gicv2_get_pending_interrupt_type(); /* Assume that all secure interrupts are S-EL1 interrupts */ if (id < PENDING_G1_INTID) { #if GICV2_G0_FOR_EL3 return INTR_TYPE_EL3; #else return INTR_TYPE_S_EL1; #endif } if (id == GIC_SPURIOUS_INTERRUPT) return INTR_TYPE_INVAL; return INTR_TYPE_NS; } /* * This function returns the highest priority pending interrupt at * the Interrupt controller and indicates to the Interrupt controller * that the interrupt processing has started. */ uint32_t plat_ic_acknowledge_interrupt(void) { return gicv2_acknowledge_interrupt(); } /* * This function returns the type of the interrupt `id`, depending on how * the interrupt has been configured in the interrupt controller */ uint32_t plat_ic_get_interrupt_type(uint32_t id) { unsigned int type; type = gicv2_get_interrupt_group(id); /* Assume that all secure interrupts are S-EL1 interrupts */ return (type == GICV2_INTR_GROUP1) ? INTR_TYPE_NS : #if GICV2_G0_FOR_EL3 INTR_TYPE_EL3; #else INTR_TYPE_S_EL1; #endif } /* * This functions is used to indicate to the interrupt controller that * the processing of the interrupt corresponding to the `id` has * finished. */ void plat_ic_end_of_interrupt(uint32_t id) { gicv2_end_of_interrupt(id); } /* * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins. * The interrupt controller knows which pin/line it uses to signal a type of * interrupt. It lets the interrupt management framework determine * for a type of interrupt and security state, which line should be used in the * SCR_EL3 to control its routing to EL3. The interrupt line is represented * as the bit position of the IRQ or FIQ bit in the SCR_EL3. */ uint32_t plat_interrupt_type_to_line(uint32_t type, uint32_t security_state) { assert((type == INTR_TYPE_S_EL1) || (type == INTR_TYPE_EL3) || (type == INTR_TYPE_NS)); assert(sec_state_is_valid(security_state)); /* Non-secure interrupts are signaled on the IRQ line always */ if (type == INTR_TYPE_NS) return __builtin_ctz(SCR_IRQ_BIT); /* * Secure interrupts are signaled using the IRQ line if the FIQ is * not enabled else they are signaled using the FIQ line. */ return ((gicv2_is_fiq_enabled() != 0U) ? __builtin_ctz(SCR_FIQ_BIT) : __builtin_ctz(SCR_IRQ_BIT)); } unsigned int plat_ic_get_running_priority(void) { return gicv2_get_running_priority(); } int plat_ic_is_spi(unsigned int id) { return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID); } int plat_ic_is_ppi(unsigned int id) { return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID); } int plat_ic_is_sgi(unsigned int id) { return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID); } unsigned int plat_ic_get_interrupt_active(unsigned int id) { return gicv2_get_interrupt_active(id); } void plat_ic_enable_interrupt(unsigned int id) { gicv2_enable_interrupt(id); } void plat_ic_disable_interrupt(unsigned int id) { gicv2_disable_interrupt(id); } void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority) { gicv2_set_interrupt_priority(id, priority); } int plat_ic_has_interrupt_type(unsigned int type) { int has_interrupt_type = 0; switch (type) { #if GICV2_G0_FOR_EL3 case INTR_TYPE_EL3: #else case INTR_TYPE_S_EL1: #endif case INTR_TYPE_NS: has_interrupt_type = 1; break; default: /* Do nothing in default case */ break; } return has_interrupt_type; } void plat_ic_set_interrupt_type(unsigned int id, unsigned int type) { unsigned int gicv2_type = 0U; /* Map canonical interrupt type to GICv2 type */ switch (type) { #if GICV2_G0_FOR_EL3 case INTR_TYPE_EL3: #else case INTR_TYPE_S_EL1: #endif gicv2_type = GICV2_INTR_GROUP0; break; case INTR_TYPE_NS: gicv2_type = GICV2_INTR_GROUP1; break; default: assert(0); /* Unreachable */ break; } gicv2_set_interrupt_type(id, gicv2_type); } void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target) { #if GICV2_G0_FOR_EL3 int id; /* Target must be a valid MPIDR in the system */ id = plat_core_pos_by_mpidr(target); assert(id >= 0); /* Verify that this is a secure SGI */ assert(plat_ic_get_interrupt_type(sgi_num) == INTR_TYPE_EL3); gicv2_raise_sgi(sgi_num, id); #else assert(false); #endif } void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode, u_register_t mpidr) { int proc_num = 0; switch (routing_mode) { case INTR_ROUTING_MODE_PE: proc_num = plat_core_pos_by_mpidr(mpidr); assert(proc_num >= 0); break; case INTR_ROUTING_MODE_ANY: /* Bit mask selecting all 8 CPUs as candidates */ proc_num = -1; break; default: assert(0); /* Unreachable */ break; } gicv2_set_spi_routing(id, proc_num); } void plat_ic_set_interrupt_pending(unsigned int id) { gicv2_set_interrupt_pending(id); } void plat_ic_clear_interrupt_pending(unsigned int id) { gicv2_clear_interrupt_pending(id); } unsigned int plat_ic_set_priority_mask(unsigned int mask) { return gicv2_set_pmr(mask); } unsigned int plat_ic_get_interrupt_id(unsigned int raw) { unsigned int id = (raw & INT_ID_MASK); if (id == GIC_SPURIOUS_INTERRUPT) id = INTR_ID_UNAVAILABLE; return id; } trusted-firmware-a-2.2/plat/common/plat_gicv3.c000066400000000000000000000213371355360272700215460ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #ifdef IMAGE_BL31 /* * The following platform GIC functions are weakly defined. They * provide typical implementations that may be re-used by multiple * platforms but may also be overridden by a platform if required. */ #pragma weak plat_ic_get_pending_interrupt_id #pragma weak plat_ic_get_pending_interrupt_type #pragma weak plat_ic_acknowledge_interrupt #pragma weak plat_ic_get_interrupt_type #pragma weak plat_ic_end_of_interrupt #pragma weak plat_interrupt_type_to_line #pragma weak plat_ic_get_running_priority #pragma weak plat_ic_is_spi #pragma weak plat_ic_is_ppi #pragma weak plat_ic_is_sgi #pragma weak plat_ic_get_interrupt_active #pragma weak plat_ic_enable_interrupt #pragma weak plat_ic_disable_interrupt #pragma weak plat_ic_set_interrupt_priority #pragma weak plat_ic_set_interrupt_type #pragma weak plat_ic_raise_el3_sgi #pragma weak plat_ic_set_spi_routing #pragma weak plat_ic_set_interrupt_pending #pragma weak plat_ic_clear_interrupt_pending CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) && (INTR_TYPE_NS == INTR_GROUP1NS) && (INTR_TYPE_EL3 == INTR_GROUP0), assert_interrupt_type_mismatch); /* * This function returns the highest priority pending interrupt at * the Interrupt controller */ uint32_t plat_ic_get_pending_interrupt_id(void) { unsigned int irqnr; assert(IS_IN_EL3()); irqnr = gicv3_get_pending_interrupt_id(); return gicv3_is_intr_id_special_identifier(irqnr) ? INTR_ID_UNAVAILABLE : irqnr; } /* * This function returns the type of the highest priority pending interrupt * at the Interrupt controller. In the case of GICv3, the Highest Priority * Pending interrupt system register (`ICC_HPPIR0_EL1`) is read to determine * the id of the pending interrupt. The type of interrupt depends upon the * id value as follows. * 1. id = PENDING_G1S_INTID (1020) is reported as a S-EL1 interrupt * 2. id = PENDING_G1NS_INTID (1021) is reported as a Non-secure interrupt. * 3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt * type. * 4. All other interrupt id's are reported as EL3 interrupt. */ uint32_t plat_ic_get_pending_interrupt_type(void) { unsigned int irqnr; uint32_t type; assert(IS_IN_EL3()); irqnr = gicv3_get_pending_interrupt_type(); switch (irqnr) { case PENDING_G1S_INTID: type = INTR_TYPE_S_EL1; break; case PENDING_G1NS_INTID: type = INTR_TYPE_NS; break; case GIC_SPURIOUS_INTERRUPT: type = INTR_TYPE_INVAL; break; default: type = INTR_TYPE_EL3; break; } return type; } /* * This function returns the highest priority pending interrupt at * the Interrupt controller and indicates to the Interrupt controller * that the interrupt processing has started. */ uint32_t plat_ic_acknowledge_interrupt(void) { assert(IS_IN_EL3()); return gicv3_acknowledge_interrupt(); } /* * This function returns the type of the interrupt `id`, depending on how * the interrupt has been configured in the interrupt controller */ uint32_t plat_ic_get_interrupt_type(uint32_t id) { assert(IS_IN_EL3()); return gicv3_get_interrupt_type(id, plat_my_core_pos()); } /* * This functions is used to indicate to the interrupt controller that * the processing of the interrupt corresponding to the `id` has * finished. */ void plat_ic_end_of_interrupt(uint32_t id) { assert(IS_IN_EL3()); gicv3_end_of_interrupt(id); } /* * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins. * The interrupt controller knows which pin/line it uses to signal a type of * interrupt. It lets the interrupt management framework determine for a type of * interrupt and security state, which line should be used in the SCR_EL3 to * control its routing to EL3. The interrupt line is represented as the bit * position of the IRQ or FIQ bit in the SCR_EL3. */ uint32_t plat_interrupt_type_to_line(uint32_t type, uint32_t security_state) { assert((type == INTR_TYPE_S_EL1) || (type == INTR_TYPE_EL3) || (type == INTR_TYPE_NS)); assert(sec_state_is_valid(security_state)); assert(IS_IN_EL3()); switch (type) { case INTR_TYPE_S_EL1: /* * The S-EL1 interrupts are signaled as IRQ in S-EL0/1 contexts * and as FIQ in the NS-EL0/1/2 contexts */ if (security_state == SECURE) return __builtin_ctz(SCR_IRQ_BIT); else return __builtin_ctz(SCR_FIQ_BIT); assert(0); /* Unreachable */ case INTR_TYPE_NS: /* * The Non secure interrupts will be signaled as FIQ in S-EL0/1 * contexts and as IRQ in the NS-EL0/1/2 contexts. */ if (security_state == SECURE) return __builtin_ctz(SCR_FIQ_BIT); else return __builtin_ctz(SCR_IRQ_BIT); assert(0); /* Unreachable */ case INTR_TYPE_EL3: /* * The EL3 interrupts are signaled as FIQ in both S-EL0/1 and * NS-EL0/1/2 contexts */ return __builtin_ctz(SCR_FIQ_BIT); default: panic(); } } unsigned int plat_ic_get_running_priority(void) { return gicv3_get_running_priority(); } int plat_ic_is_spi(unsigned int id) { return (id >= MIN_SPI_ID) && (id <= MAX_SPI_ID); } int plat_ic_is_ppi(unsigned int id) { return (id >= MIN_PPI_ID) && (id < MIN_SPI_ID); } int plat_ic_is_sgi(unsigned int id) { return (id >= MIN_SGI_ID) && (id < MIN_PPI_ID); } unsigned int plat_ic_get_interrupt_active(unsigned int id) { return gicv3_get_interrupt_active(id, plat_my_core_pos()); } void plat_ic_enable_interrupt(unsigned int id) { gicv3_enable_interrupt(id, plat_my_core_pos()); } void plat_ic_disable_interrupt(unsigned int id) { gicv3_disable_interrupt(id, plat_my_core_pos()); } void plat_ic_set_interrupt_priority(unsigned int id, unsigned int priority) { gicv3_set_interrupt_priority(id, plat_my_core_pos(), priority); } int plat_ic_has_interrupt_type(unsigned int type) { assert((type == INTR_TYPE_EL3) || (type == INTR_TYPE_S_EL1) || (type == INTR_TYPE_NS)); return 1; } void plat_ic_set_interrupt_type(unsigned int id, unsigned int type) { gicv3_set_interrupt_type(id, plat_my_core_pos(), type); } void plat_ic_raise_el3_sgi(int sgi_num, u_register_t target) { /* Target must be a valid MPIDR in the system */ assert(plat_core_pos_by_mpidr(target) >= 0); /* Verify that this is a secure EL3 SGI */ assert(plat_ic_get_interrupt_type((unsigned int)sgi_num) == INTR_TYPE_EL3); gicv3_raise_secure_g0_sgi((unsigned int)sgi_num, target); } void plat_ic_set_spi_routing(unsigned int id, unsigned int routing_mode, u_register_t mpidr) { unsigned int irm = 0; switch (routing_mode) { case INTR_ROUTING_MODE_PE: assert(plat_core_pos_by_mpidr(mpidr) >= 0); irm = GICV3_IRM_PE; break; case INTR_ROUTING_MODE_ANY: irm = GICV3_IRM_ANY; break; default: assert(0); /* Unreachable */ break; } gicv3_set_spi_routing(id, irm, mpidr); } void plat_ic_set_interrupt_pending(unsigned int id) { /* Disallow setting SGIs pending */ assert(id >= MIN_PPI_ID); gicv3_set_interrupt_pending(id, plat_my_core_pos()); } void plat_ic_clear_interrupt_pending(unsigned int id) { /* Disallow setting SGIs pending */ assert(id >= MIN_PPI_ID); gicv3_clear_interrupt_pending(id, plat_my_core_pos()); } unsigned int plat_ic_set_priority_mask(unsigned int mask) { return gicv3_set_pmr(mask); } unsigned int plat_ic_get_interrupt_id(unsigned int raw) { unsigned int id = raw & INT_ID_MASK; return gicv3_is_intr_id_special_identifier(id) ? INTR_ID_UNAVAILABLE : id; } #endif #ifdef IMAGE_BL32 #pragma weak plat_ic_get_pending_interrupt_id #pragma weak plat_ic_acknowledge_interrupt #pragma weak plat_ic_end_of_interrupt /* In AArch32, the secure group1 interrupts are targeted to Secure PL1 */ #ifndef __aarch64__ #define IS_IN_EL1() IS_IN_SECURE() #endif /* * This function returns the highest priority pending interrupt at * the Interrupt controller */ uint32_t plat_ic_get_pending_interrupt_id(void) { unsigned int irqnr; assert(IS_IN_EL1()); irqnr = gicv3_get_pending_interrupt_id_sel1(); return (irqnr == GIC_SPURIOUS_INTERRUPT) ? INTR_ID_UNAVAILABLE : irqnr; } /* * This function returns the highest priority pending interrupt at * the Interrupt controller and indicates to the Interrupt controller * that the interrupt processing has started. */ uint32_t plat_ic_acknowledge_interrupt(void) { assert(IS_IN_EL1()); return gicv3_acknowledge_interrupt_sel1(); } /* * This functions is used to indicate to the interrupt controller that * the processing of the interrupt corresponding to the `id` has * finished. */ void plat_ic_end_of_interrupt(uint32_t id) { assert(IS_IN_EL1()); gicv3_end_of_interrupt_sel1(id); } #endif trusted-firmware-a-2.2/plat/common/plat_log_common.c000066400000000000000000000012621355360272700226570ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /* Allow platforms to override the log prefix string */ #pragma weak plat_log_get_prefix static const char *plat_prefix_str[] = { "ERROR: ", "NOTICE: ", "WARNING: ", "INFO: ", "VERBOSE: "}; const char *plat_log_get_prefix(unsigned int log_level) { unsigned int level; if (log_level < LOG_LEVEL_ERROR) { level = LOG_LEVEL_ERROR; } else if (log_level > LOG_LEVEL_VERBOSE) { level = LOG_LEVEL_VERBOSE; } else { level = log_level; } return plat_prefix_str[(level / 10U) - 1U]; } trusted-firmware-a-2.2/plat/common/plat_psci_common.c000066400000000000000000000112131355360272700230310ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #if ENABLE_PSCI_STAT && ENABLE_PMF #pragma weak plat_psci_stat_accounting_start #pragma weak plat_psci_stat_accounting_stop #pragma weak plat_psci_stat_get_residency /* Ticks elapsed in one second by a signal of 1 MHz */ #define MHZ_TICKS_PER_SEC 1000000U /* Maximum time-stamp value read from architectural counters */ #ifdef __aarch64__ #define MAX_TS UINT64_MAX #else #define MAX_TS UINT32_MAX #endif /* Following are used as ID's to capture time-stamp */ #define PSCI_STAT_ID_ENTER_LOW_PWR 0 #define PSCI_STAT_ID_EXIT_LOW_PWR 1 #define PSCI_STAT_TOTAL_IDS 2 PMF_REGISTER_SERVICE(psci_svc, PMF_PSCI_STAT_SVC_ID, PSCI_STAT_TOTAL_IDS, PMF_STORE_ENABLE) /* * This function calculates the stats residency in microseconds, * taking in account the wrap around condition. */ static u_register_t calc_stat_residency(unsigned long long pwrupts, unsigned long long pwrdnts) { /* The divisor to use to convert raw timestamp into microseconds. */ u_register_t residency_div; u_register_t res; /* * Calculate divisor so that it can be directly used to * convert time-stamp into microseconds. */ residency_div = read_cntfrq_el0() / MHZ_TICKS_PER_SEC; assert(residency_div > 0U); if (pwrupts < pwrdnts) res = MAX_TS - pwrdnts + pwrupts; else res = pwrupts - pwrdnts; return res / residency_div; } /* * Capture timestamp before entering a low power state. * No cache maintenance is required when capturing the timestamp. * Cache maintenance may be needed when reading these timestamps. */ void plat_psci_stat_accounting_start( __unused const psci_power_state_t *state_info) { assert(state_info != NULL); PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR, PMF_NO_CACHE_MAINT); } /* * Capture timestamp after exiting a low power state. * No cache maintenance is required when capturing the timestamp. * Cache maintenance may be needed when reading these timestamps. */ void plat_psci_stat_accounting_stop( __unused const psci_power_state_t *state_info) { assert(state_info != NULL); PMF_CAPTURE_TIMESTAMP(psci_svc, PSCI_STAT_ID_EXIT_LOW_PWR, PMF_NO_CACHE_MAINT); } /* * Calculate the residency for the given level and power state * information. */ u_register_t plat_psci_stat_get_residency(unsigned int lvl, const psci_power_state_t *state_info, int last_cpu_idx) { plat_local_state_t state; unsigned long long pwrup_ts = 0, pwrdn_ts = 0; unsigned int pmf_flags; assert((lvl >= PSCI_CPU_PWR_LVL) && (lvl <= PLAT_MAX_PWR_LVL)); assert(state_info != NULL); assert(last_cpu_idx <= PLATFORM_CORE_COUNT); if (lvl == PSCI_CPU_PWR_LVL) assert((unsigned int)last_cpu_idx == plat_my_core_pos()); /* * If power down is requested, then timestamp capture will * be with caches OFF. Hence we have to do cache maintenance * when reading the timestamp. */ state = state_info->pwr_domain_state[PSCI_CPU_PWR_LVL]; if (is_local_state_off(state) != 0) { pmf_flags = PMF_CACHE_MAINT; } else { assert(is_local_state_retn(state) == 1); pmf_flags = PMF_NO_CACHE_MAINT; } PMF_GET_TIMESTAMP_BY_INDEX(psci_svc, PSCI_STAT_ID_ENTER_LOW_PWR, last_cpu_idx, pmf_flags, pwrdn_ts); PMF_GET_TIMESTAMP_BY_INDEX(psci_svc, PSCI_STAT_ID_EXIT_LOW_PWR, plat_my_core_pos(), pmf_flags, pwrup_ts); return calc_stat_residency(pwrup_ts, pwrdn_ts); } #endif /* ENABLE_PSCI_STAT && ENABLE_PMF */ /* * The PSCI generic code uses this API to let the platform participate in state * coordination during a power management operation. It compares the platform * specific local power states requested by each cpu for a given power domain * and returns the coordinated target power state that the domain should * enter. A platform assigns a number to a local power state. This default * implementation assumes that the platform assigns these numbers in order of * increasing depth of the power state i.e. for two power states X & Y, if X < Y * then X represents a shallower power state than Y. As a result, the * coordinated target local power state for a power domain will be the minimum * of the requested local power states. */ plat_local_state_t plat_get_target_pwr_state(unsigned int lvl, const plat_local_state_t *states, unsigned int ncpu) { plat_local_state_t target = PLAT_MAX_OFF_STATE, temp; const plat_local_state_t *st = states; unsigned int n = ncpu; assert(ncpu > 0U); do { temp = *st; st++; if (temp < target) target = temp; n--; } while (n > 0U); return target; } trusted-firmware-a-2.2/plat/common/plat_spm_rd.c000066400000000000000000000230461355360272700220160ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include /******************************************************************************* * Resource pool ******************************************************************************/ static struct sp_rd_sect_mem_region rd_mem_regions[PLAT_SPM_MEM_REGIONS_MAX]; static OBJECT_POOL_ARRAY(rd_mem_regions_pool, rd_mem_regions); static struct sp_rd_sect_notification rd_notifs[PLAT_SPM_NOTIFICATIONS_MAX]; static OBJECT_POOL_ARRAY(rd_notifs_pool, rd_notifs); static struct sp_rd_sect_service rd_services[PLAT_SPM_SERVICES_MAX]; static OBJECT_POOL_ARRAY(rd_services_pool, rd_services); /******************************************************************************* * Attribute section handler ******************************************************************************/ static void rd_parse_attribute(struct sp_rd_sect_attribute *attr, const void *fdt, int node) { int rc = 0; /* The minimum size that can be read from the DTB is 32-bit. */ uint32_t version, sp_type, runtime_el, exec_type; uint32_t panic_policy, xlat_granule; rc |= fdtw_read_cells(fdt, node, "version", 1, &version); if (version != 1) { ERROR("Unsupported resource description version: 0x%x\n", version); panic(); } rc |= fdtw_read_cells(fdt, node, "sp_type", 1, &sp_type); rc |= fdtw_read_cells(fdt, node, "pe_mpidr", 1, &attr->pe_mpidr); rc |= fdtw_read_cells(fdt, node, "runtime_el", 1, &runtime_el); rc |= fdtw_read_cells(fdt, node, "exec_type", 1, &exec_type); rc |= fdtw_read_cells(fdt, node, "panic_policy", 1, &panic_policy); rc |= fdtw_read_cells(fdt, node, "xlat_granule", 1, &xlat_granule); rc |= fdtw_read_cells(fdt, node, "binary_size", 1, &attr->binary_size); rc |= fdtw_read_cells(fdt, node, "load_address", 2, &attr->load_address); rc |= fdtw_read_cells(fdt, node, "entrypoint", 2, &attr->entrypoint); attr->version = version; attr->sp_type = sp_type; attr->runtime_el = runtime_el; attr->exec_type = exec_type; attr->panic_policy = panic_policy; attr->xlat_granule = xlat_granule; VERBOSE(" Attribute Section:\n"); VERBOSE(" version: 0x%x\n", version); VERBOSE(" sp_type: 0x%x\n", sp_type); VERBOSE(" pe_mpidr: 0x%x\n", attr->pe_mpidr); VERBOSE(" runtime_el: 0x%x\n", runtime_el); VERBOSE(" exec_type: 0x%x\n", exec_type); VERBOSE(" panic_policy: 0x%x\n", panic_policy); VERBOSE(" xlat_granule: 0x%x\n", xlat_granule); VERBOSE(" binary_size: 0x%x\n", attr->binary_size); VERBOSE(" load_address: 0x%llx\n", attr->load_address); VERBOSE(" entrypoint: 0x%llx\n", attr->entrypoint); if (rc) { ERROR("Failed to read attribute node elements.\n"); panic(); } } /******************************************************************************* * Memory regions section handlers ******************************************************************************/ static void rd_parse_memory_region(struct sp_rd_sect_mem_region *rdmem, const void *fdt, int node) { int rc = 0; char name[RD_MEM_REGION_NAME_LEN]; rc |= fdtw_read_string(fdt, node, "str", (char *)&name, sizeof(name)); rc |= fdtw_read_cells(fdt, node, "attr", 1, &rdmem->attr); rc |= fdtw_read_cells(fdt, node, "base", 2, &rdmem->base); rc |= fdtw_read_cells(fdt, node, "size", 2, &rdmem->size); size_t len = strlcpy(rdmem->name, name, RD_MEM_REGION_NAME_LEN); if (len >= RD_MEM_REGION_NAME_LEN) { WARN("Memory region name truncated: '%s'\n", name); } VERBOSE(" Memory Region:\n"); VERBOSE(" name: '%s'\n", rdmem->name); VERBOSE(" attr: 0x%x\n", rdmem->attr); VERBOSE(" base: 0x%llx\n", rdmem->base); VERBOSE(" size: 0x%llx\n", rdmem->size); if (rc) { ERROR("Failed to read mem_region node elements.\n"); panic(); } } static void rd_parse_memory_regions(struct sp_res_desc *rd, const void *fdt, int node) { int child; struct sp_rd_sect_mem_region *rdmem, *old_rdmem; fdt_for_each_subnode(child, fdt, node) { rdmem = pool_alloc(&rd_mem_regions_pool); /* Add element to the start of the list */ old_rdmem = rd->mem_region; rd->mem_region = rdmem; rdmem->next = old_rdmem; rd_parse_memory_region(rdmem, fdt, child); } if ((child < 0) && (child != -FDT_ERR_NOTFOUND)) { ERROR("%d: fdt_for_each_subnode(): %d\n", __LINE__, node); panic(); } } /******************************************************************************* * Notifications section handlers ******************************************************************************/ static void rd_parse_notification(struct sp_rd_sect_notification *rdnot, const void *fdt, int node) { int rc = 0; rc |= fdtw_read_cells(fdt, node, "attr", 1, &rdnot->attr); rc |= fdtw_read_cells(fdt, node, "pe", 1, &rdnot->pe); VERBOSE(" Notification:\n"); VERBOSE(" attr: 0x%x\n", rdnot->attr); VERBOSE(" pe: 0x%x\n", rdnot->pe); if (rc) { ERROR("Failed to read notification node elements.\n"); panic(); } } static void rd_parse_notifications(struct sp_res_desc *rd, const void *fdt, int node) { int child; struct sp_rd_sect_notification *rdnot, *old_rdnot; fdt_for_each_subnode(child, fdt, node) { rdnot = pool_alloc(&rd_notifs_pool); /* Add element to the start of the list */ old_rdnot = rd->notification; rd->notification = rdnot; rdnot->next = old_rdnot; rd_parse_notification(rdnot, fdt, child); } if ((child < 0) && (child != -FDT_ERR_NOTFOUND)) { ERROR("%d: fdt_for_each_subnode(): %d\n", __LINE__, child); panic(); } } /******************************************************************************* * Services section handlers ******************************************************************************/ static void rd_parse_service(struct sp_rd_sect_service *rdsvc, const void *fdt, int node) { int rc = 0; /* The minimum size that can be read from the DTB is 32-bit. */ uint32_t accessibility, request_type, connection_quota; rc |= fdtw_read_array(fdt, node, "uuid", 4, &rdsvc->uuid); rc |= fdtw_read_cells(fdt, node, "accessibility", 1, &accessibility); rc |= fdtw_read_cells(fdt, node, "request_type", 1, &request_type); rc |= fdtw_read_cells(fdt, node, "connection_quota", 1, &connection_quota); rc |= fdtw_read_cells(fdt, node, "sec_mem_size", 1, &rdsvc->secure_mem_size); rc |= fdtw_read_cells(fdt, node, "interrupt_num", 1, &rdsvc->interrupt_num); rdsvc->accessibility = accessibility; rdsvc->request_type = request_type; rdsvc->connection_quota = connection_quota; VERBOSE(" Service:\n"); VERBOSE(" uuid: 0x%08x 0x%08x 0x%08x 0x%08x\n", rdsvc->uuid[0], rdsvc->uuid[1], rdsvc->uuid[2], rdsvc->uuid[3]); VERBOSE(" accessibility: 0x%x\n", accessibility); VERBOSE(" request_type: 0x%x\n", request_type); VERBOSE(" connection_quota: 0x%x\n", connection_quota); VERBOSE(" secure_memory_size: 0x%x\n", rdsvc->secure_mem_size); VERBOSE(" interrupt_num: 0x%x\n", rdsvc->interrupt_num); if (rc) { ERROR("Failed to read attribute node elements.\n"); panic(); } } static void rd_parse_services(struct sp_res_desc *rd, const void *fdt, int node) { int child; struct sp_rd_sect_service *rdsvc, *old_rdsvc; fdt_for_each_subnode(child, fdt, node) { rdsvc = pool_alloc(&rd_services_pool); /* Add element to the start of the list */ old_rdsvc = rd->service; rd->service = rdsvc; rdsvc->next = old_rdsvc; rd_parse_service(rdsvc, fdt, child); } if ((child < 0) && (child != -FDT_ERR_NOTFOUND)) { ERROR("%d: fdt_for_each_subnode(): %d\n", __LINE__, node); panic(); } } /******************************************************************************* * Root node handler ******************************************************************************/ static void rd_parse_root(struct sp_res_desc *rd, const void *fdt, int root) { int node; char *str; str = "attribute"; node = fdt_subnode_offset_namelen(fdt, root, str, strlen(str)); if (node < 0) { ERROR("Root node doesn't contain subnode '%s'\n", str); panic(); } else { rd_parse_attribute(&rd->attribute, fdt, node); } str = "memory_regions"; node = fdt_subnode_offset_namelen(fdt, root, str, strlen(str)); if (node < 0) { ERROR("Root node doesn't contain subnode '%s'\n", str); panic(); } else { rd_parse_memory_regions(rd, fdt, node); } str = "notifications"; node = fdt_subnode_offset_namelen(fdt, root, str, strlen(str)); if (node < 0) { WARN("Root node doesn't contain subnode '%s'\n", str); } else { rd_parse_notifications(rd, fdt, node); } str = "services"; node = fdt_subnode_offset_namelen(fdt, root, str, strlen(str)); if (node < 0) { WARN("Root node doesn't contain subnode '%s'\n", str); } else { rd_parse_services(rd, fdt, node); } } /******************************************************************************* * Platform handler to load resource descriptor blobs into the active Secure * Partition context. ******************************************************************************/ int plat_spm_sp_rd_load(struct sp_res_desc *rd, const void *ptr, size_t size) { int rc; int root_node; assert(rd != NULL); assert(ptr != NULL); INFO("Reading RD blob at address %p\n", ptr); rc = fdt_check_header(ptr); if (rc != 0) { ERROR("Wrong format for resource descriptor blob (%d).\n", rc); return -1; } root_node = fdt_node_offset_by_compatible(ptr, -1, "arm,sp_rd"); if (root_node < 0) { ERROR("Unrecognized resource descriptor blob (%d)\n", rc); return -1; } rd_parse_root(rd, ptr, root_node); return 0; } trusted-firmware-a-2.2/plat/common/plat_spm_sp.c000066400000000000000000000050701355360272700220300ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include static unsigned int sp_next; /******************************************************************************* * Platform handler get the address of a Secure Partition and its resource * description blob. It iterates through all SPs detected by the platform. If * there is information for another SP, it returns 0. If there are no more SPs, * it returns -1. ******************************************************************************/ int plat_spm_sp_get_next_address(void **sp_base, size_t *sp_size, void **rd_base, size_t *rd_size) { assert((sp_base != NULL) && (sp_size != NULL)); assert((rd_base != NULL) && (rd_base != NULL)); const uint64_t *pkg_base = (uint64_t *)PLAT_SP_PACKAGE_BASE; struct sp_pkg_header *pkg_header = (struct sp_pkg_header *)pkg_base; if (sp_next == 0) { if (pkg_header->version != 0x1) { ERROR("SP package has an unsupported version 0x%llx\n", pkg_header->version); panic(); } } if (sp_next >= pkg_header->number_of_sp) { /* No more partitions in the package */ return -1; } const struct sp_pkg_entry *entry_list = (const struct sp_pkg_entry *)((uintptr_t)pkg_base + sizeof(struct sp_pkg_header)); const struct sp_pkg_entry *entry = &(entry_list[sp_next]); uint64_t sp_offset = entry->sp_offset; uint64_t rd_offset = entry->rd_offset; uintptr_t pkg_sp_base = ((uintptr_t)PLAT_SP_PACKAGE_BASE + sp_offset); uintptr_t pkg_rd_base = ((uintptr_t)PLAT_SP_PACKAGE_BASE + rd_offset); uint64_t pkg_sp_size = entry->sp_size; uint64_t pkg_rd_size = entry->rd_size; uintptr_t pkg_end = (uintptr_t)PLAT_SP_PACKAGE_BASE + (uintptr_t)PLAT_SP_PACKAGE_SIZE - 1U; /* * Check for overflows. The package header isn't trusted, so assert() * can't be used here. */ uintptr_t pkg_sp_end = pkg_sp_base + pkg_sp_size - 1U; uintptr_t pkg_rd_end = pkg_rd_base + pkg_rd_size - 1U; if ((pkg_sp_end > pkg_end) || (pkg_sp_end < pkg_sp_base)) { ERROR("Invalid Secure Partition size (0x%llx)\n", pkg_sp_size); panic(); } if ((pkg_rd_end > pkg_end) || (pkg_rd_end < pkg_rd_base)) { ERROR("Invalid Resource Description blob size (0x%llx)\n", pkg_rd_size); panic(); } /* Return location of the binaries. */ *sp_base = (void *)pkg_sp_base; *sp_size = pkg_sp_size; *rd_base = (void *)pkg_rd_base; *rd_size = pkg_rd_size; sp_next++; return 0; } trusted-firmware-a-2.2/plat/common/tbbr/000077500000000000000000000000001355360272700202725ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/common/tbbr/plat_tbbr.c000066400000000000000000000026261355360272700224150ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #if USE_TBBR_DEFS #include #else #include #endif /* * Store a new non-volatile counter value. This implementation * only allows updating of the platform's Trusted NV counter when a * certificate protected by the Trusted NV counter is signed with * the ROT key. This avoids a compromised secondary certificate from * updating the platform's Trusted NV counter, which could lead to the * platform becoming unusable. The function is suitable for all TBBR * compliant platforms. * * Return: 0 = success, Otherwise = error */ int plat_set_nv_ctr2(void *cookie, const auth_img_desc_t *img_desc, unsigned int nv_ctr) { int trusted_nv_ctr; assert(cookie != NULL); assert(img_desc != NULL); trusted_nv_ctr = strcmp(cookie, TRUSTED_FW_NVCOUNTER_OID) == 0; /* * Only update the Trusted NV Counter if the certificate * has been signed with the ROT key. Non Trusted NV counter * updates are unconditional. */ if (!trusted_nv_ctr || img_desc->parent == NULL) return plat_set_nv_ctr(cookie, nv_ctr); /* * Trusted certificates not signed with the ROT key are not * allowed to update the Trusted NV Counter. */ return 1; } trusted-firmware-a-2.2/plat/common/ubsan.c000066400000000000000000000135051355360272700206210ustar00rootroot00000000000000/* * Copyright (c) 2016, Linaro Limited * Copyright (c) 2019, ARM Limited. All rights reserved. * * SPDX-License-Identifier: BSD-2-Clause */ #include #include #include #include struct source_location { const char *file_name; uint32_t line; uint32_t column; }; struct type_descriptor { uint16_t type_kind; uint16_t type_info; char type_name[1]; }; struct type_mismatch_data { struct source_location loc; struct type_descriptor *type; unsigned long alignment; unsigned char type_check_kind; }; struct overflow_data { struct source_location loc; struct type_descriptor *type; }; struct shift_out_of_bounds_data { struct source_location loc; struct type_descriptor *lhs_type; struct type_descriptor *rhs_type; }; struct out_of_bounds_data { struct source_location loc; struct type_descriptor *array_type; struct type_descriptor *index_type; }; struct unreachable_data { struct source_location loc; }; struct vla_bound_data { struct source_location loc; struct type_descriptor *type; }; struct invalid_value_data { struct source_location loc; struct type_descriptor *type; }; struct nonnull_arg_data { struct source_location loc; }; /* * When compiling with -fsanitize=undefined the compiler expects functions * with the following signatures. The functions are never called directly, * only when undefined behavior is detected in instrumented code. */ void __ubsan_handle_type_mismatch_abort(struct type_mismatch_data *data, unsigned long ptr); void __ubsan_handle_type_mismatch_v1_abort(struct type_mismatch_data *data, unsigned long ptr); void __ubsan_handle_add_overflow_abort(struct overflow_data *data, unsigned long lhs, unsigned long rhs); void __ubsan_handle_sub_overflow_abort(struct overflow_data *data, unsigned long lhs, unsigned long rhs); void __ubsan_handle_mul_overflow_abort(struct overflow_data *data, unsigned long lhs, unsigned long rhs); void __ubsan_handle_negate_overflow_abort(struct overflow_data *data, unsigned long old_val); void __ubsan_handle_pointer_overflow_abort(struct overflow_data *data, unsigned long old_val); void __ubsan_handle_divrem_overflow_abort(struct overflow_data *data, unsigned long lhs, unsigned long rhs); void __ubsan_handle_shift_out_of_bounds_abort(struct shift_out_of_bounds_data *data, unsigned long lhs, unsigned long rhs); void __ubsan_handle_out_of_bounds_abort(struct out_of_bounds_data *data, unsigned long idx); void __ubsan_handle_unreachable_abort(struct unreachable_data *data); void __ubsan_handle_missing_return_abort(struct unreachable_data *data); void __ubsan_handle_vla_bound_not_positive_abort(struct vla_bound_data *data, unsigned long bound); void __ubsan_handle_load_invalid_value_abort(struct invalid_value_data *data, unsigned long val); void __ubsan_handle_nonnull_arg_abort(struct nonnull_arg_data *data #if __GCC_VERSION < 60000 , size_t arg_no #endif ); static void print_loc(const char *func, struct source_location *loc) { ERROR("Undefined behavior at %s:%d col %d (%s)", loc->file_name, loc->line, loc->column, func); } void __ubsan_handle_type_mismatch_abort(struct type_mismatch_data *data, unsigned long ptr __unused) { print_loc(__func__, &data->loc); plat_panic_handler(); } void __ubsan_handle_type_mismatch_v1_abort(struct type_mismatch_data *data, unsigned long ptr __unused) { print_loc(__func__, &data->loc); plat_panic_handler(); } void __ubsan_handle_add_overflow_abort(struct overflow_data *data, unsigned long lhs __unused, unsigned long rhs __unused) { print_loc(__func__, &data->loc); plat_panic_handler(); } void __ubsan_handle_sub_overflow_abort(struct overflow_data *data, unsigned long lhs __unused, unsigned long rhs __unused) { print_loc(__func__, &data->loc); plat_panic_handler(); } void __ubsan_handle_mul_overflow_abort(struct overflow_data *data, unsigned long lhs __unused, unsigned long rhs __unused) { print_loc(__func__, &data->loc); plat_panic_handler(); } void __ubsan_handle_negate_overflow_abort(struct overflow_data *data, unsigned long old_val __unused) { print_loc(__func__, &data->loc); plat_panic_handler(); } void __ubsan_handle_pointer_overflow_abort(struct overflow_data *data, unsigned long old_val __unused) { print_loc(__func__, &data->loc); plat_panic_handler(); } void __ubsan_handle_divrem_overflow_abort(struct overflow_data *data, unsigned long lhs __unused, unsigned long rhs __unused) { print_loc(__func__, &data->loc); plat_panic_handler(); } void __ubsan_handle_shift_out_of_bounds_abort(struct shift_out_of_bounds_data *data, unsigned long lhs __unused, unsigned long rhs __unused) { print_loc(__func__, &data->loc); plat_panic_handler(); } void __ubsan_handle_out_of_bounds_abort(struct out_of_bounds_data *data, unsigned long idx __unused) { print_loc(__func__, &data->loc); plat_panic_handler(); } void __ubsan_handle_unreachable_abort(struct unreachable_data *data) { print_loc(__func__, &data->loc); plat_panic_handler(); } void __ubsan_handle_missing_return_abort(struct unreachable_data *data) { print_loc(__func__, &data->loc); plat_panic_handler(); } void __ubsan_handle_vla_bound_not_positive_abort(struct vla_bound_data *data, unsigned long bound __unused) { print_loc(__func__, &data->loc); plat_panic_handler(); } void __ubsan_handle_load_invalid_value_abort(struct invalid_value_data *data, unsigned long val __unused) { print_loc(__func__, &data->loc); plat_panic_handler(); } void __ubsan_handle_nonnull_arg_abort(struct nonnull_arg_data *data #if __GCC_VERSION < 60000 , size_t arg_no __unused #endif ) { print_loc(__func__, &data->loc); plat_panic_handler(); } trusted-firmware-a-2.2/plat/hisilicon/000077500000000000000000000000001355360272700200325ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/hisilicon/hikey/000077500000000000000000000000001355360272700211435ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/hisilicon/hikey/aarch64/000077500000000000000000000000001355360272700223735ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/hisilicon/hikey/aarch64/hikey_common.c000066400000000000000000000060441355360272700252240ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #define MAP_DDR MAP_REGION_FLAT(DDR_BASE, \ DDR_SIZE - DDR_SEC_SIZE, \ MT_DEVICE | MT_RW | MT_NS) #define MAP_DEVICE MAP_REGION_FLAT(DEVICE_BASE, \ DEVICE_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_TSP_MEM MAP_REGION_FLAT(TSP_SEC_MEM_BASE, \ TSP_SEC_MEM_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #define MAP_ROM_PARAM MAP_REGION_FLAT(XG2RAM0_BASE, \ BL1_XG2RAM0_OFFSET, \ MT_DEVICE | MT_RO | MT_SECURE) #define MAP_SRAM MAP_REGION_FLAT(SRAM_BASE, \ SRAM_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) /* * BL1 needs to access the areas of MMC_SRAM. * BL1 loads BL2 from eMMC into SRAM before DDR initialized. */ #define MAP_MMC_SRAM MAP_REGION_FLAT(HIKEY_BL1_MMC_DESC_BASE, \ HIKEY_BL1_MMC_DESC_SIZE + \ HIKEY_BL1_MMC_DATA_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) /* * Table of regions for different BL stages to map using the MMU. * This doesn't include Trusted RAM as the 'mem_layout' argument passed to * hikey_init_mmu_elx() will give the available subset of that, */ #ifdef IMAGE_BL1 static const mmap_region_t hikey_mmap[] = { MAP_DEVICE, MAP_ROM_PARAM, MAP_MMC_SRAM, {0} }; #endif #ifdef IMAGE_BL2 static const mmap_region_t hikey_mmap[] = { MAP_DDR, MAP_DEVICE, MAP_TSP_MEM, MAP_SRAM, {0} }; #endif #ifdef IMAGE_BL31 static const mmap_region_t hikey_mmap[] = { MAP_DEVICE, MAP_SRAM, MAP_TSP_MEM, {0} }; #endif #ifdef IMAGE_BL32 static const mmap_region_t hikey_mmap[] = { MAP_DEVICE, MAP_DDR, {0} }; #endif /* * Macro generating the code for the function setting up the pagetables as per * the platform memory map & initialize the mmu, for the given exception level */ #define HIKEY_CONFIGURE_MMU_EL(_el) \ void hikey_init_mmu_el##_el(unsigned long total_base, \ unsigned long total_size, \ unsigned long ro_start, \ unsigned long ro_limit, \ unsigned long coh_start, \ unsigned long coh_limit) \ { \ mmap_add_region(total_base, total_base, \ total_size, \ MT_MEMORY | MT_RW | MT_SECURE); \ mmap_add_region(ro_start, ro_start, \ ro_limit - ro_start, \ MT_MEMORY | MT_RO | MT_SECURE); \ mmap_add_region(coh_start, coh_start, \ coh_limit - coh_start, \ MT_DEVICE | MT_RW | MT_SECURE); \ mmap_add(hikey_mmap); \ init_xlat_tables(); \ \ enable_mmu_el##_el(0); \ } /* Define EL1 and EL3 variants of the function initialising the MMU */ HIKEY_CONFIGURE_MMU_EL(1) HIKEY_CONFIGURE_MMU_EL(3) unsigned long plat_get_ns_image_entrypoint(void) { return HIKEY_NS_IMAGE_OFFSET; } unsigned int plat_get_syscnt_freq2(void) { return 1200000; } trusted-firmware-a-2.2/plat/hisilicon/hikey/aarch64/hikey_helpers.S000066400000000000000000000071621355360272700253600ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl plat_my_core_pos .globl platform_mem_init .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush .globl plat_report_exception .globl plat_reset_handler func plat_my_core_pos mrs x0, mpidr_el1 and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 ret endfunc plat_my_core_pos /* ----------------------------------------------------- * void platform_mem_init(void); * * We don't need to carry out any memory initialization * on HIKEY. The Secure RAM is accessible straight away. * ----------------------------------------------------- */ func platform_mem_init ret endfunc platform_mem_init /* --------------------------------------------- * int plat_crash_console_init(void) * Function to initialize the crash console * without a C Runtime to print crash report. * Clobber list : x0, x1, x2 * --------------------------------------------- */ func plat_crash_console_init mov_imm x0, CRASH_CONSOLE_BASE mov_imm x1, PL011_UART_CLK_IN_HZ mov_imm x2, PL011_BAUDRATE b console_pl011_core_init endfunc plat_crash_console_init /* --------------------------------------------- * int plat_crash_console_putc(int c) * Function to print a character on the crash * console without a C Runtime. * Clobber list : x1, x2 * --------------------------------------------- */ func plat_crash_console_putc mov_imm x1, CRASH_CONSOLE_BASE b console_pl011_core_putc endfunc plat_crash_console_putc /* --------------------------------------------- * int plat_crash_console_flush() * Function to force a write of all buffered * data that hasn't been output. * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func plat_crash_console_flush mov_imm x0, CRASH_CONSOLE_BASE b console_pl011_core_flush endfunc plat_crash_console_flush /* --------------------------------------------- * void plat_report_exception(unsigned int type) * Function to report an unhandled exception * with platform-specific means. * On HIKEY platform, it updates the LEDs * to indicate where we are * --------------------------------------------- */ func plat_report_exception mov x8, x30 /* Turn on LED according to x0 (0 -- f) */ ldr x2, =0xf7020000 and x1, x0, #1 str w1, [x2, #4] and x1, x0, #2 str w1, [x2, #8] and x1, x0, #4 str w1, [x2, #16] and x1, x0, #8 str w1, [x2, #32] mrs x2, currentel and x2, x2, #0xc0 /* Check EL1 */ cmp x2, #0x04 beq plat_report_el1 adr x4, plat_err_str bl asm_print_str adr x4, esr_el3_str bl asm_print_str mrs x4, esr_el3 bl asm_print_hex adr x4, elr_el3_str bl asm_print_str mrs x4, elr_el3 bl asm_print_hex b plat_report_end plat_report_el1: adr x4, plat_err_str bl asm_print_str adr x4, esr_el1_str bl asm_print_str mrs x4, esr_el1 bl asm_print_hex adr x4, elr_el1_str bl asm_print_str mrs x4, elr_el1 bl asm_print_hex plat_report_end: mov x30, x8 ret endfunc plat_report_exception /* ----------------------------------------------------- * void plat_reset_handler(void); * ----------------------------------------------------- */ func plat_reset_handler ret endfunc plat_reset_handler .section .rodata.rev_err_str, "aS" plat_err_str: .asciz "\nPlatform exception reporting:" esr_el3_str: .asciz "\nESR_EL3: " elr_el3_str: .asciz "\nELR_EL3: " esr_el1_str: .asciz "\nESR_EL1: " elr_el1_str: .asciz "\nELR_EL1: " trusted-firmware-a-2.2/plat/hisilicon/hikey/hikey_bl1_setup.c000066400000000000000000000075761355360272700244150ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hikey_private.h" /* Data structure which holds the extents of the trusted RAM for BL1 */ static meminfo_t bl1_tzram_layout; static console_pl011_t console; enum { BOOT_NORMAL = 0, BOOT_USB_DOWNLOAD, BOOT_UART_DOWNLOAD, }; meminfo_t *bl1_plat_sec_mem_layout(void) { return &bl1_tzram_layout; } /* * Perform any BL1 specific platform actions. */ void bl1_early_platform_setup(void) { /* Initialize the console to provide early debug support */ console_pl011_register(CONSOLE_BASE, PL011_UART_CLK_IN_HZ, PL011_BAUDRATE, &console); /* Allow BL1 to see the whole Trusted RAM */ bl1_tzram_layout.total_base = BL1_RW_BASE; bl1_tzram_layout.total_size = BL1_RW_SIZE; INFO("BL1: 0x%lx - 0x%lx [size = %lu]\n", BL1_RAM_BASE, BL1_RAM_LIMIT, BL1_RAM_LIMIT - BL1_RAM_BASE); /* bl1_size */ } /* * Perform the very early platform specific architecture setup here. At the * moment this only does basic initialization. Later architectural setup * (bl1_arch_setup()) does not do anything platform specific. */ void bl1_plat_arch_setup(void) { hikey_init_mmu_el3(bl1_tzram_layout.total_base, bl1_tzram_layout.total_size, BL1_RO_BASE, BL1_RO_LIMIT, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); } /* * Function which will perform any remaining platform-specific setup that can * occur after the MMU and data cache have been enabled. */ void bl1_platform_setup(void) { dw_mmc_params_t params; struct mmc_device_info info; assert((HIKEY_BL1_MMC_DESC_BASE >= SRAM_BASE) && ((SRAM_BASE + SRAM_SIZE) >= (HIKEY_BL1_MMC_DATA_BASE + HIKEY_BL1_MMC_DATA_SIZE))); hikey_sp804_init(); hikey_gpio_init(); hikey_pmussi_init(); hikey_hi6553_init(); hikey_rtc_init(); hikey_mmc_pll_init(); memset(¶ms, 0, sizeof(dw_mmc_params_t)); params.reg_base = DWMMC0_BASE; params.desc_base = HIKEY_BL1_MMC_DESC_BASE; params.desc_size = 1 << 20; params.clk_rate = 24 * 1000 * 1000; params.bus_width = MMC_BUS_WIDTH_8; params.flags = MMC_FLAG_CMD23; info.mmc_dev_type = MMC_IS_EMMC; dw_mmc_init(¶ms, &info); hikey_io_setup(); } /* * The following function checks if Firmware update is needed, * by checking if TOC in FIP image is valid or not. */ unsigned int bl1_plat_get_next_image_id(void) { int32_t boot_mode; unsigned int ret; boot_mode = mmio_read_32(ONCHIPROM_PARAM_BASE); switch (boot_mode) { case BOOT_USB_DOWNLOAD: case BOOT_UART_DOWNLOAD: ret = NS_BL1U_IMAGE_ID; break; default: WARN("Invalid boot mode is found:%d\n", boot_mode); panic(); } return ret; } image_desc_t *bl1_plat_get_image_desc(unsigned int image_id) { unsigned int index = 0; while (bl1_tbbr_image_descs[index].image_id != INVALID_IMAGE_ID) { if (bl1_tbbr_image_descs[index].image_id == image_id) return &bl1_tbbr_image_descs[index]; index++; } return NULL; } void bl1_plat_set_ep_info(unsigned int image_id, entry_point_info_t *ep_info) { uint64_t data = 0; if (image_id == BL2_IMAGE_ID) panic(); inv_dcache_range(NS_BL1U_BASE, NS_BL1U_SIZE); __asm__ volatile ("mrs %0, cpacr_el1" : "=r"(data)); do { data |= 3 << 20; __asm__ volatile ("msr cpacr_el1, %0" : : "r"(data)); __asm__ volatile ("mrs %0, cpacr_el1" : "=r"(data)); } while ((data & (3 << 20)) != (3 << 20)); INFO("cpacr_el1:0x%llx\n", data); ep_info->args.arg0 = 0xffff & read_mpidr(); ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); } trusted-firmware-a-2.2/plat/hisilicon/hikey/hikey_bl2_mem_params_desc.c000066400000000000000000000121001355360272700263500ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /* also includes hikey_def.h and hikey_layout.h*/ #include #include #include /******************************************************************************* * Following descriptor provides BL image/ep information that gets used * by BL2 to load the images and also subset of this information is * passed to next BL image. The image loading sequence is managed by * populating the images in required loading order. The image execution * sequence is managed by populating the `next_handoff_image_id` with * the next executable image id. ******************************************************************************/ static bl_mem_params_node_t bl2_mem_params_descs[] = { #ifdef SCP_BL2_BASE /* Fill SCP_BL2 related information if it exists */ { .image_id = SCP_BL2_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE), SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP), .image_info.image_base = SCP_BL2_BASE, .image_info.image_max_size = SCP_BL2_SIZE, .next_handoff_image_id = INVALID_IMAGE_ID, }, #endif /* SCP_BL2_BASE */ #ifdef EL3_PAYLOAD_BASE /* Fill EL3 payload related information (BL31 is EL3 payload)*/ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = EL3_PAYLOAD_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING), .next_handoff_image_id = INVALID_IMAGE_ID, }, #else /* EL3_PAYLOAD_BASE */ /* Fill BL31 related information */ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = BL31_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), #if DEBUG .ep_info.args.arg1 = HIKEY_BL31_PLAT_PARAM_VAL, #endif SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP), .image_info.image_base = BL31_BASE, .image_info.image_max_size = BL31_LIMIT - BL31_BASE, # ifdef BL32_BASE .next_handoff_image_id = BL32_IMAGE_ID, # else .next_handoff_image_id = BL33_IMAGE_ID, # endif }, # ifdef BL32_BASE /* Fill BL32 related information */ { .image_id = BL32_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE), .ep_info.pc = BL32_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = BL32_BASE, .image_info.image_max_size = BL32_LIMIT - BL32_BASE, .next_handoff_image_id = BL33_IMAGE_ID, }, /* * Fill BL32 external 1 related information. * A typical use for extra1 image is with OP-TEE where it is the pager image. */ { .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), .image_info.image_base = BL32_BASE, .image_info.image_max_size = BL32_LIMIT - BL32_BASE, .next_handoff_image_id = INVALID_IMAGE_ID, }, /* * Fill BL32 external 2 related information. * A typical use for extra2 image is with OP-TEE where it is the paged image. */ { .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), #ifdef SPD_opteed .image_info.image_base = HIKEY_OPTEE_PAGEABLE_LOAD_BASE, .image_info.image_max_size = HIKEY_OPTEE_PAGEABLE_LOAD_SIZE, #endif .next_handoff_image_id = INVALID_IMAGE_ID, }, # endif /* BL32_BASE */ /* Fill BL33 related information */ { .image_id = BL33_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), # ifdef PRELOADED_BL33_BASE .ep_info.pc = PRELOADED_BL33_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), # else .ep_info.pc = HIKEY_NS_IMAGE_OFFSET, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = HIKEY_NS_IMAGE_OFFSET, .image_info.image_max_size = 0x200000 /* 2MB */, # endif /* PRELOADED_BL33_BASE */ .next_handoff_image_id = INVALID_IMAGE_ID, } #endif /* EL3_PAYLOAD_BASE */ }; REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) trusted-firmware-a-2.2/plat/hisilicon/hikey/hikey_bl2_setup.c000066400000000000000000000213511355360272700244010ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /* also includes hikey_def.h and hikey_layout.h*/ #include #include #include #include #include #include #include #include #include #ifdef SPD_opteed #include #endif #include #include #include #include #include "hikey_private.h" #define BL2_RW_BASE (BL_CODE_END) static meminfo_t bl2_el3_tzram_layout; static console_pl011_t console; enum { BOOT_MODE_RECOVERY = 0, BOOT_MODE_NORMAL, BOOT_MODE_MASK = 1, }; /******************************************************************************* * Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol. * Return 0 on success, -1 otherwise. ******************************************************************************/ int plat_hikey_bl2_handle_scp_bl2(image_info_t *scp_bl2_image_info) { /* Enable MCU SRAM */ hisi_mcu_enable_sram(); /* Load MCU binary into SRAM */ hisi_mcu_load_image(scp_bl2_image_info->image_base, scp_bl2_image_info->image_size); /* Let MCU running */ hisi_mcu_start_run(); INFO("%s: MCU PC is at 0x%x\n", __func__, mmio_read_32(AO_SC_MCU_SUBSYS_STAT2)); INFO("%s: AO_SC_PERIPH_CLKSTAT4 is 0x%x\n", __func__, mmio_read_32(AO_SC_PERIPH_CLKSTAT4)); return 0; } /******************************************************************************* * Gets SPSR for BL32 entry ******************************************************************************/ uint32_t hikey_get_spsr_for_bl32_entry(void) { /* * The Secure Payload Dispatcher service is responsible for * setting the SPSR prior to entry into the BL3-2 image. */ return 0; } /******************************************************************************* * Gets SPSR for BL33 entry ******************************************************************************/ #ifdef __aarch64__ uint32_t hikey_get_spsr_for_bl33_entry(void) { unsigned int mode; uint32_t spsr; /* Figure out what mode we enter the non-secure world in */ mode = (el_implemented(2) != EL_IMPL_NONE) ? MODE_EL2 : MODE_EL1; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; } #else uint32_t hikey_get_spsr_for_bl33_entry(void) { unsigned int hyp_status, mode, spsr; hyp_status = GET_VIRT_EXT(read_id_pfr1()); mode = (hyp_status) ? MODE32_hyp : MODE32_svc; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_MODE32(mode, plat_get_ns_image_entrypoint() & 0x1, SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS); return spsr; } #endif /* __aarch64__ */ int bl2_plat_handle_pre_image_load(unsigned int image_id) { return hikey_set_fip_addr(image_id, "fastboot"); } int hikey_bl2_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); #ifdef SPD_opteed bl_mem_params_node_t *pager_mem_params = NULL; bl_mem_params_node_t *paged_mem_params = NULL; #endif assert(bl_mem_params); switch (image_id) { #ifdef __aarch64__ case BL32_IMAGE_ID: #ifdef SPD_opteed 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); err = parse_optee_header(&bl_mem_params->ep_info, &pager_mem_params->image_info, &paged_mem_params->image_info); if (err != 0) { WARN("OPTEE header parse error.\n"); } #endif bl_mem_params->ep_info.spsr = hikey_get_spsr_for_bl32_entry(); break; #endif case BL33_IMAGE_ID: /* BL33 expects to receive the primary CPU MPID (through r0) */ bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr(); bl_mem_params->ep_info.spsr = hikey_get_spsr_for_bl33_entry(); break; #ifdef SCP_BL2_BASE case SCP_BL2_IMAGE_ID: /* The subsequent handling of SCP_BL2 is platform specific */ err = plat_hikey_bl2_handle_scp_bl2(&bl_mem_params->image_info); if (err) { WARN("Failure in platform-specific handling of SCP_BL2 image.\n"); } break; #endif default: /* Do nothing in default case */ break; } return err; } /******************************************************************************* * 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) { return hikey_bl2_handle_post_image_load(image_id); } static void reset_dwmmc_clk(void) { unsigned int data; /* disable mmc0 bus clock */ mmio_write_32(PERI_SC_PERIPH_CLKDIS0, PERI_CLK0_MMC0); do { data = mmio_read_32(PERI_SC_PERIPH_CLKSTAT0); } while (data & PERI_CLK0_MMC0); /* enable mmc0 bus clock */ mmio_write_32(PERI_SC_PERIPH_CLKEN0, PERI_CLK0_MMC0); do { data = mmio_read_32(PERI_SC_PERIPH_CLKSTAT0); } while (!(data & PERI_CLK0_MMC0)); /* reset mmc0 clock domain */ mmio_write_32(PERI_SC_PERIPH_RSTEN0, PERI_RST0_MMC0); /* bypass mmc0 clock phase */ data = mmio_read_32(PERI_SC_PERIPH_CTRL2); data |= 3; mmio_write_32(PERI_SC_PERIPH_CTRL2, data); /* disable low power */ data = mmio_read_32(PERI_SC_PERIPH_CTRL13); data |= 1 << 3; mmio_write_32(PERI_SC_PERIPH_CTRL13, data); do { data = mmio_read_32(PERI_SC_PERIPH_RSTSTAT0); } while (!(data & PERI_RST0_MMC0)); /* unreset mmc0 clock domain */ mmio_write_32(PERI_SC_PERIPH_RSTDIS0, PERI_RST0_MMC0); do { data = mmio_read_32(PERI_SC_PERIPH_RSTSTAT0); } while (data & PERI_RST0_MMC0); } static void hikey_boardid_init(void) { u_register_t midr; midr = read_midr(); mmio_write_32(MEMORY_AXI_CHIP_ADDR, midr); INFO("[BDID] [%x] midr: 0x%x\n", MEMORY_AXI_CHIP_ADDR, (unsigned int)midr); mmio_write_32(MEMORY_AXI_BOARD_TYPE_ADDR, 0); mmio_write_32(MEMORY_AXI_BOARD_ID_ADDR, 0x2b); mmio_write_32(ACPU_ARM64_FLAGA, 0x1234); mmio_write_32(ACPU_ARM64_FLAGB, 0x5678); } static void hikey_sd_init(void) { /* switch pinmux to SD */ mmio_write_32(IOMG_SD_CLK, IOMG_MUX_FUNC0); mmio_write_32(IOMG_SD_CMD, IOMG_MUX_FUNC0); mmio_write_32(IOMG_SD_DATA0, IOMG_MUX_FUNC0); mmio_write_32(IOMG_SD_DATA1, IOMG_MUX_FUNC0); mmio_write_32(IOMG_SD_DATA2, IOMG_MUX_FUNC0); mmio_write_32(IOMG_SD_DATA3, IOMG_MUX_FUNC0); mmio_write_32(IOCG_SD_CLK, IOCG_INPUT_16MA); mmio_write_32(IOCG_SD_CMD, IOCG_INPUT_12MA); mmio_write_32(IOCG_SD_DATA0, IOCG_INPUT_12MA); mmio_write_32(IOCG_SD_DATA1, IOCG_INPUT_12MA); mmio_write_32(IOCG_SD_DATA2, IOCG_INPUT_12MA); mmio_write_32(IOCG_SD_DATA3, IOCG_INPUT_12MA); /* set SD Card detect as nopull */ mmio_write_32(IOCG_GPIO8, 0); } static void hikey_jumper_init(void) { /* set jumper detect as nopull */ mmio_write_32(IOCG_GPIO24, 0); /* set jumper detect as GPIO */ mmio_write_32(IOMG_GPIO24, IOMG_MUX_FUNC0); } void bl2_el3_early_platform_setup(u_register_t arg1, u_register_t arg2, u_register_t arg3, u_register_t arg4) { /* Initialize the console to provide early debug support */ console_pl011_register(CONSOLE_BASE, PL011_UART_CLK_IN_HZ, PL011_BAUDRATE, &console); /* * Allow BL2 to see the whole Trusted RAM. */ bl2_el3_tzram_layout.total_base = BL2_RW_BASE; bl2_el3_tzram_layout.total_size = BL31_LIMIT - BL2_RW_BASE; } void bl2_el3_plat_arch_setup(void) { hikey_init_mmu_el3(bl2_el3_tzram_layout.total_base, bl2_el3_tzram_layout.total_size, BL_CODE_BASE, BL_CODE_END, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); } void bl2_platform_setup(void) { dw_mmc_params_t params; struct mmc_device_info info; hikey_sp804_init(); hikey_gpio_init(); hikey_pmussi_init(); hikey_hi6553_init(); /* Clear SRAM since it'll be used by MCU right now. */ memset((void *)SRAM_BASE, 0, SRAM_SIZE); dsb(); hikey_ddr_init(DDR_FREQ_800M); hikey_security_setup(); hikey_boardid_init(); init_acpu_dvfs(); hikey_rtc_init(); hikey_sd_init(); hikey_jumper_init(); hikey_mmc_pll_init(); /* Clean SRAM before MCU used */ clean_dcache_range(SRAM_BASE, SRAM_SIZE); reset_dwmmc_clk(); memset(¶ms, 0, sizeof(dw_mmc_params_t)); params.reg_base = DWMMC0_BASE; params.desc_base = HIKEY_MMC_DESC_BASE; params.desc_size = 1 << 20; params.clk_rate = 24 * 1000 * 1000; params.bus_width = MMC_BUS_WIDTH_8; params.flags = MMC_FLAG_CMD23; info.mmc_dev_type = MMC_IS_EMMC; dw_mmc_init(¶ms, &info); hikey_io_setup(); } trusted-firmware-a-2.2/plat/hisilicon/hikey/hikey_bl31_setup.c000066400000000000000000000077131355360272700244710ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hikey_private.h" static entry_point_info_t bl32_ep_info; static entry_point_info_t bl33_ep_info; static console_pl011_t console; /****************************************************************************** * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0 * interrupts. *****************************************************************************/ static const interrupt_prop_t g0_interrupt_props[] = { INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), }; /* * Ideally `arm_gic_data` structure definition should be a `const` but it is * kept as modifiable for overwriting with different GICD and GICC base when * running on FVP with VE memory map. */ gicv2_driver_data_t hikey_gic_data = { .gicd_base = PLAT_ARM_GICD_BASE, .gicc_base = PLAT_ARM_GICC_BASE, .interrupt_props = g0_interrupt_props, .interrupt_props_num = ARRAY_SIZE(g0_interrupt_props), }; static const int cci_map[] = { CCI400_SL_IFACE3_CLUSTER_IX, CCI400_SL_IFACE4_CLUSTER_IX }; entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; next_image_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info; /* None of the images on this platform can have 0x0 as the entrypoint */ if (next_image_info->pc) return next_image_info; return NULL; } void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { void *from_bl2; from_bl2 = (void *) arg0; /* Initialize the console to provide early debug support */ console_pl011_register(CONSOLE_BASE, PL011_UART_CLK_IN_HZ, PL011_BAUDRATE, &console); /* Initialize CCI driver */ cci_init(CCI400_BASE, cci_map, ARRAY_SIZE(cci_map)); cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); /* * Check params passed from BL2 should not be NULL, */ bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2; assert(params_from_bl2 != NULL); assert(params_from_bl2->h.type == PARAM_BL_PARAMS); assert(params_from_bl2->h.version >= VERSION_2); bl_params_node_t *bl_params = params_from_bl2->head; /* * Copy BL33 and BL32 (if present), entry point information. * They are stored in Secure RAM, in BL2's address space. */ while (bl_params) { if (bl_params->image_id == BL32_IMAGE_ID) bl32_ep_info = *bl_params->ep_info; if (bl_params->image_id == BL33_IMAGE_ID) bl33_ep_info = *bl_params->ep_info; bl_params = bl_params->next_params_info; } if (bl33_ep_info.pc == 0) panic(); } void bl31_plat_arch_setup(void) { hikey_init_mmu_el3(BL31_BASE, BL31_LIMIT - BL31_BASE, BL_CODE_BASE, BL_CODE_END, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); } /* Initialize EDMAC controller with non-secure mode. */ static void hikey_edma_init(void) { int i; uint32_t non_secure; non_secure = EDMAC_SEC_CTRL_INTR_SEC | EDMAC_SEC_CTRL_GLOBAL_SEC; mmio_write_32(EDMAC_SEC_CTRL, non_secure); for (i = 0; i < EDMAC_CHANNEL_NUMS; i++) { mmio_write_32(EDMAC_AXI_CONF(i), (1 << 6) | (1 << 18)); } } void bl31_platform_setup(void) { /* Initialize the GIC driver, cpu and distributor interfaces */ gicv2_driver_init(&hikey_gic_data); gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); hikey_edma_init(); hisi_ipc_init(); hisi_pwrc_setup(); } void bl31_plat_runtime_setup(void) { } trusted-firmware-a-2.2/plat/hisilicon/hikey/hikey_bl_common.c000066400000000000000000000247551355360272700244620ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "hikey_private.h" void hikey_sp804_init(void) { uint32_t data; /* select the clock of dual timer0 */ data = mmio_read_32(AO_SC_TIMER_EN0); while (data & 3) { data &= ~3; data |= 3 << 16; mmio_write_32(AO_SC_TIMER_EN0, data); data = mmio_read_32(AO_SC_TIMER_EN0); } /* enable the pclk of dual timer0 */ data = mmio_read_32(AO_SC_PERIPH_CLKSTAT4); while (!(data & PCLK_TIMER1) || !(data & PCLK_TIMER0)) { mmio_write_32(AO_SC_PERIPH_CLKEN4, PCLK_TIMER1 | PCLK_TIMER0); data = mmio_read_32(AO_SC_PERIPH_CLKSTAT4); } /* reset dual timer0 */ data = mmio_read_32(AO_SC_PERIPH_RSTSTAT4); mmio_write_32(AO_SC_PERIPH_RSTEN4, PCLK_TIMER1 | PCLK_TIMER0); do { data = mmio_read_32(AO_SC_PERIPH_RSTSTAT4); } while (!(data & PCLK_TIMER1) || !(data & PCLK_TIMER0)); /* unreset dual timer0 */ mmio_write_32(AO_SC_PERIPH_RSTDIS4, PCLK_TIMER1 | PCLK_TIMER0); do { data = mmio_read_32(AO_SC_PERIPH_RSTSTAT4); } while ((data & PCLK_TIMER1) || (data & PCLK_TIMER0)); sp804_timer_init(SP804_TIMER0_BASE, 10, 192); } void hikey_gpio_init(void) { pl061_gpio_init(); pl061_gpio_register(GPIO0_BASE, 0); pl061_gpio_register(GPIO1_BASE, 1); pl061_gpio_register(GPIO2_BASE, 2); pl061_gpio_register(GPIO3_BASE, 3); pl061_gpio_register(GPIO4_BASE, 4); pl061_gpio_register(GPIO5_BASE, 5); pl061_gpio_register(GPIO6_BASE, 6); pl061_gpio_register(GPIO7_BASE, 7); pl061_gpio_register(GPIO8_BASE, 8); pl061_gpio_register(GPIO9_BASE, 9); pl061_gpio_register(GPIO10_BASE, 10); pl061_gpio_register(GPIO11_BASE, 11); pl061_gpio_register(GPIO12_BASE, 12); pl061_gpio_register(GPIO13_BASE, 13); pl061_gpio_register(GPIO14_BASE, 14); pl061_gpio_register(GPIO15_BASE, 15); pl061_gpio_register(GPIO16_BASE, 16); pl061_gpio_register(GPIO17_BASE, 17); pl061_gpio_register(GPIO18_BASE, 18); pl061_gpio_register(GPIO19_BASE, 19); /* Power on indicator LED (USER_LED1). */ gpio_set_direction(32, GPIO_DIR_OUT); /* LED1 */ gpio_set_value(32, GPIO_LEVEL_HIGH); gpio_set_direction(33, GPIO_DIR_OUT); /* LED2 */ gpio_set_value(33, GPIO_LEVEL_LOW); gpio_set_direction(34, GPIO_DIR_OUT); /* LED3 */ gpio_set_direction(35, GPIO_DIR_OUT); /* LED4 */ } void hikey_pmussi_init(void) { uint32_t data; /* Initialize PWR_HOLD GPIO */ gpio_set_direction(0, GPIO_DIR_OUT); gpio_set_value(0, GPIO_LEVEL_LOW); /* * After reset, PMUSSI stays in reset mode. * Now make it out of reset. */ mmio_write_32(AO_SC_PERIPH_RSTDIS4, AO_SC_PERIPH_RSTDIS4_PRESET_PMUSSI_N); do { data = mmio_read_32(AO_SC_PERIPH_RSTSTAT4); } while (data & AO_SC_PERIPH_RSTDIS4_PRESET_PMUSSI_N); /* Set PMUSSI clock latency for read operation. */ data = mmio_read_32(AO_SC_MCU_SUBSYS_CTRL3); data &= ~AO_SC_MCU_SUBSYS_CTRL3_RCLK_MASK; data |= AO_SC_MCU_SUBSYS_CTRL3_RCLK_3; mmio_write_32(AO_SC_MCU_SUBSYS_CTRL3, data); /* enable PMUSSI clock */ data = AO_SC_PERIPH_CLKEN5_PCLK_PMUSSI_CCPU | AO_SC_PERIPH_CLKEN5_PCLK_PMUSSI_MCU; mmio_write_32(AO_SC_PERIPH_CLKEN5, data); data = AO_SC_PERIPH_CLKEN4_PCLK_PMUSSI; mmio_write_32(AO_SC_PERIPH_CLKEN4, data); gpio_set_value(0, GPIO_LEVEL_HIGH); } void hikey_hi6553_init(void) { uint8_t data; mmio_write_8(HI6553_PERI_EN_MARK, 0x1e); mmio_write_8(HI6553_NP_REG_ADJ1, 0); data = DISABLE6_XO_CLK_CONN | DISABLE6_XO_CLK_NFC | DISABLE6_XO_CLK_RF1 | DISABLE6_XO_CLK_RF2; mmio_write_8(HI6553_DISABLE6_XO_CLK, data); /* configure BUCK0 & BUCK1 */ mmio_write_8(HI6553_BUCK01_CTRL2, 0x5e); mmio_write_8(HI6553_BUCK0_CTRL7, 0x10); mmio_write_8(HI6553_BUCK1_CTRL7, 0x10); mmio_write_8(HI6553_BUCK0_CTRL5, 0x1e); mmio_write_8(HI6553_BUCK1_CTRL5, 0x1e); mmio_write_8(HI6553_BUCK0_CTRL1, 0xfc); mmio_write_8(HI6553_BUCK1_CTRL1, 0xfc); /* configure BUCK2 */ mmio_write_8(HI6553_BUCK2_REG1, 0x4f); mmio_write_8(HI6553_BUCK2_REG5, 0x99); mmio_write_8(HI6553_BUCK2_REG6, 0x45); mdelay(1); mmio_write_8(HI6553_VSET_BUCK2_ADJ, 0x22); mdelay(1); /* configure BUCK3 */ mmio_write_8(HI6553_BUCK3_REG3, 0x02); mmio_write_8(HI6553_BUCK3_REG5, 0x99); mmio_write_8(HI6553_BUCK3_REG6, 0x41); mmio_write_8(HI6553_VSET_BUCK3_ADJ, 0x02); mdelay(1); /* configure BUCK4 */ mmio_write_8(HI6553_BUCK4_REG2, 0x9a); mmio_write_8(HI6553_BUCK4_REG5, 0x99); mmio_write_8(HI6553_BUCK4_REG6, 0x45); /* configure LDO20 */ mmio_write_8(HI6553_LDO20_REG_ADJ, 0x50); mmio_write_8(HI6553_NP_REG_CHG, 0x0f); mmio_write_8(HI6553_CLK_TOP0, 0x06); mmio_write_8(HI6553_CLK_TOP3, 0xc0); mmio_write_8(HI6553_CLK_TOP4, 0x00); /* configure LDO7 & LDO10 for SD slot */ /* enable LDO7 */ data = mmio_read_8(HI6553_LDO7_REG_ADJ); data = (data & 0xf8) | 0x2; mmio_write_8(HI6553_LDO7_REG_ADJ, data); mdelay(5); mmio_write_8(HI6553_ENABLE2_LDO1_8, 1 << 6); mdelay(5); /* enable LDO10 */ data = mmio_read_8(HI6553_LDO10_REG_ADJ); data = (data & 0xf8) | 0x5; mmio_write_8(HI6553_LDO10_REG_ADJ, data); mdelay(5); mmio_write_8(HI6553_ENABLE3_LDO9_16, 1 << 1); mdelay(5); /* enable LDO15 */ data = mmio_read_8(HI6553_LDO15_REG_ADJ); data = (data & 0xf8) | 0x4; mmio_write_8(HI6553_LDO15_REG_ADJ, data); mmio_write_8(HI6553_ENABLE3_LDO9_16, 1 << 6); mdelay(5); /* enable LDO19 */ data = mmio_read_8(HI6553_LDO19_REG_ADJ); data |= 0x7; mmio_write_8(HI6553_LDO19_REG_ADJ, data); mmio_write_8(HI6553_ENABLE4_LDO17_22, 1 << 2); mdelay(5); /* enable LDO21 */ data = mmio_read_8(HI6553_LDO21_REG_ADJ); data = (data & 0xf8) | 0x3; mmio_write_8(HI6553_LDO21_REG_ADJ, data); mmio_write_8(HI6553_ENABLE4_LDO17_22, 1 << 4); mdelay(5); /* enable LDO22 */ data = mmio_read_8(HI6553_LDO22_REG_ADJ); data = (data & 0xf8) | 0x7; mmio_write_8(HI6553_LDO22_REG_ADJ, data); mmio_write_8(HI6553_ENABLE4_LDO17_22, 1 << 5); mdelay(5); /* select 32.764KHz */ mmio_write_8(HI6553_CLK19M2_600_586_EN, 0x01); /* Disable vbus_det interrupts */ data = mmio_read_8(HI6553_IRQ2_MASK); data = data | 0x3; mmio_write_8(HI6553_IRQ2_MASK, data); } void init_mmc0_pll(void) { unsigned int data; /* select SYSPLL as the source of MMC0 */ /* select SYSPLL as the source of MUX1 (SC_CLK_SEL0) */ mmio_write_32(PERI_SC_CLK_SEL0, 1 << 5 | 1 << 21); do { data = mmio_read_32(PERI_SC_CLK_SEL0); } while (!(data & (1 << 5))); /* select MUX1 as the source of MUX2 (SC_CLK_SEL0) */ mmio_write_32(PERI_SC_CLK_SEL0, 1 << 29); do { data = mmio_read_32(PERI_SC_CLK_SEL0); } while (data & (1 << 13)); mmio_write_32(PERI_SC_PERIPH_CLKEN0, (1 << 0)); do { data = mmio_read_32(PERI_SC_PERIPH_CLKSTAT0); } while (!(data & (1 << 0))); data = mmio_read_32(PERI_SC_PERIPH_CLKEN12); data |= 1 << 1; mmio_write_32(PERI_SC_PERIPH_CLKEN12, data); do { mmio_write_32(PERI_SC_CLKCFG8BIT1, (1 << 7) | 0xb); data = mmio_read_32(PERI_SC_CLKCFG8BIT1); } while ((data & 0xb) != 0xb); } void reset_mmc0_clk(void) { unsigned int data; /* disable mmc0 bus clock */ mmio_write_32(PERI_SC_PERIPH_CLKDIS0, PERI_CLK0_MMC0); do { data = mmio_read_32(PERI_SC_PERIPH_CLKSTAT0); } while (data & PERI_CLK0_MMC0); /* enable mmc0 bus clock */ mmio_write_32(PERI_SC_PERIPH_CLKEN0, PERI_CLK0_MMC0); do { data = mmio_read_32(PERI_SC_PERIPH_CLKSTAT0); } while (!(data & PERI_CLK0_MMC0)); /* reset mmc0 clock domain */ mmio_write_32(PERI_SC_PERIPH_RSTEN0, PERI_RST0_MMC0); /* bypass mmc0 clock phase */ data = mmio_read_32(PERI_SC_PERIPH_CTRL2); data |= 3; mmio_write_32(PERI_SC_PERIPH_CTRL2, data); /* disable low power */ data = mmio_read_32(PERI_SC_PERIPH_CTRL13); data |= 1 << 3; mmio_write_32(PERI_SC_PERIPH_CTRL13, data); do { data = mmio_read_32(PERI_SC_PERIPH_RSTSTAT0); } while (!(data & PERI_RST0_MMC0)); /* unreset mmc0 clock domain */ mmio_write_32(PERI_SC_PERIPH_RSTDIS0, PERI_RST0_MMC0); do { data = mmio_read_32(PERI_SC_PERIPH_RSTSTAT0); } while (data & PERI_RST0_MMC0); } void init_media_clk(void) { unsigned int data, value; data = mmio_read_32(PMCTRL_MEDPLLCTRL); data |= 1; mmio_write_32(PMCTRL_MEDPLLCTRL, data); for (;;) { data = mmio_read_32(PMCTRL_MEDPLLCTRL); value = 1 << 28; if ((data & value) == value) break; } data = mmio_read_32(PERI_SC_PERIPH_CLKEN12); data = 1 << 10; mmio_write_32(PERI_SC_PERIPH_CLKEN12, data); } void init_mmc1_pll(void) { uint32_t data; /* select SYSPLL as the source of MMC1 */ /* select SYSPLL as the source of MUX1 (SC_CLK_SEL0) */ mmio_write_32(PERI_SC_CLK_SEL0, 1 << 11 | 1 << 27); do { data = mmio_read_32(PERI_SC_CLK_SEL0); } while (!(data & (1 << 11))); /* select MUX1 as the source of MUX2 (SC_CLK_SEL0) */ mmio_write_32(PERI_SC_CLK_SEL0, 1 << 30); do { data = mmio_read_32(PERI_SC_CLK_SEL0); } while (data & (1 << 14)); mmio_write_32(PERI_SC_PERIPH_CLKEN0, (1 << 1)); do { data = mmio_read_32(PERI_SC_PERIPH_CLKSTAT0); } while (!(data & (1 << 1))); data = mmio_read_32(PERI_SC_PERIPH_CLKEN12); data |= 1 << 2; mmio_write_32(PERI_SC_PERIPH_CLKEN12, data); do { /* 1.2GHz / 50 = 24MHz */ mmio_write_32(PERI_SC_CLKCFG8BIT2, 0x31 | (1 << 7)); data = mmio_read_32(PERI_SC_CLKCFG8BIT2); } while ((data & 0x31) != 0x31); } void reset_mmc1_clk(void) { unsigned int data; /* disable mmc1 bus clock */ mmio_write_32(PERI_SC_PERIPH_CLKDIS0, PERI_CLK0_MMC1); do { data = mmio_read_32(PERI_SC_PERIPH_CLKSTAT0); } while (data & PERI_CLK0_MMC1); /* enable mmc1 bus clock */ mmio_write_32(PERI_SC_PERIPH_CLKEN0, PERI_CLK0_MMC1); do { data = mmio_read_32(PERI_SC_PERIPH_CLKSTAT0); } while (!(data & PERI_CLK0_MMC1)); /* reset mmc1 clock domain */ mmio_write_32(PERI_SC_PERIPH_RSTEN0, PERI_RST0_MMC1); /* bypass mmc1 clock phase */ data = mmio_read_32(PERI_SC_PERIPH_CTRL2); data |= 3 << 2; mmio_write_32(PERI_SC_PERIPH_CTRL2, data); /* disable low power */ data = mmio_read_32(PERI_SC_PERIPH_CTRL13); data |= 1 << 4; mmio_write_32(PERI_SC_PERIPH_CTRL13, data); do { data = mmio_read_32(PERI_SC_PERIPH_RSTSTAT0); } while (!(data & PERI_RST0_MMC1)); /* unreset mmc0 clock domain */ mmio_write_32(PERI_SC_PERIPH_RSTDIS0, PERI_RST0_MMC1); do { data = mmio_read_32(PERI_SC_PERIPH_RSTSTAT0); } while (data & PERI_RST0_MMC1); } /* Initialize PLL of both eMMC and SD controllers. */ void hikey_mmc_pll_init(void) { init_mmc0_pll(); reset_mmc0_clk(); init_media_clk(); dsb(); init_mmc1_pll(); reset_mmc1_clk(); } void hikey_rtc_init(void) { uint32_t data; data = mmio_read_32(AO_SC_PERIPH_CLKEN4); data |= AO_SC_PERIPH_RSTDIS4_RESET_RTC0_N; mmio_write_32(AO_SC_PERIPH_CLKEN4, data); } trusted-firmware-a-2.2/plat/hisilicon/hikey/hikey_ddr.c000066400000000000000000001247241355360272700232630ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "hikey_private.h" static void init_pll(void) { unsigned int data; data = mmio_read_32((0xf7032000 + 0x000)); data |= 0x1; mmio_write_32((0xf7032000 + 0x000), data); do { data = mmio_read_32((0xf7032000 + 0x000)); } while (!(data & (1 << 28))); data = mmio_read_32((0xf7800000 + 0x000)); data &= ~0x007; data |= 0x004; mmio_write_32((0xf7800000 + 0x000), data); do { data = mmio_read_32((0xf7800000 + 0x014)); data &= 0x007; } while (data != 0x004); mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2101); dsb(); isb(); udelay(10); mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2001); dsb(); isb(); udelay(10); mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2201); dsb(); isb(); udelay(10); mmio_write_32(0xf7032000 + 0x02c, 0x5110103e); dsb(); isb(); udelay(10); data = mmio_read_32(0xf7032000 + 0x050); data |= 1 << 28; mmio_write_32(0xf7032000 + 0x050, data); dsb(); isb(); udelay(10); mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2101); dsb(); isb(); udelay(10); mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2001); dsb(); isb(); udelay(10); mmio_write_32(PERI_SC_PERIPH_CTRL14, 0x2201); dsb(); isb(); udelay(10); } static void init_freq(void) { unsigned int data, tmp; unsigned int cpuext_cfg, ddr_cfg; mmio_write_32((0xf7032000 + 0x374), 0x4a); mmio_write_32((0xf7032000 + 0x368), 0xda); mmio_write_32((0xf7032000 + 0x36c), 0x01); mmio_write_32((0xf7032000 + 0x370), 0x01); mmio_write_32((0xf7032000 + 0x360), 0x60); mmio_write_32((0xf7032000 + 0x364), 0x60); mmio_write_32((0xf7032000 + 0x114), 0x1000); data = mmio_read_32((0xf7032000 + 0x110)); data |= (3 << 12); mmio_write_32((0xf7032000 + 0x110), data); data = mmio_read_32((0xf7032000 + 0x110)); data |= (1 << 4); mmio_write_32((0xf7032000 + 0x110), data); data = mmio_read_32((0xf7032000 + 0x110)); data &= ~0x7; data |= 0x5; mmio_write_32((0xf7032000 + 0x110), data); dsb(); mdelay(10); do { data = mmio_read_32((0xf6504000 + 0x008)); data &= (3 << 20); } while (data != (3 << 20)); dsb(); mdelay(10); data = mmio_read_32((0xf6504000 + 0x054)); data &= ~((1 << 0) | (1 << 11)); mmio_write_32((0xf6504000 + 0x054), data); mdelay(10); data = mmio_read_32((0xf7032000 + 0x104)); data &= ~(3 << 8); data |= (1 << 8); mmio_write_32((0xf7032000 + 0x104), data); data = mmio_read_32((0xf7032000 + 0x100)); data |= (1 << 0); mmio_write_32((0xf7032000 + 0x100), data); dsb(); do { data = mmio_read_32((0xf7032000 + 0x100)); data &= (1 << 2); } while (data != (1 << 2)); data = mmio_read_32((0xf6504000 + 0x06c)); data &= ~0xffff; data |= 0x56; mmio_write_32((0xf6504000 + 0x06c), data); data = mmio_read_32((0xf6504000 + 0x06c)); data &= ~(0xffffffu << 8); data |= 0xc7a << 8; mmio_write_32((0xf6504000 + 0x06c), data); data = mmio_read_32((0xf6504000 + 0x058)); data &= ((1 << 13) - 1); data |= 0xccb; mmio_write_32((0xf6504000 + 0x058), data); mmio_write_32((0xf6504000 + 0x060), 0x1fff); mmio_write_32((0xf6504000 + 0x064), 0x1ffffff); mmio_write_32((0xf6504000 + 0x068), 0x7fffffff); mmio_write_32((0xf6504000 + 0x05c), 0x1); data = mmio_read_32((0xf6504000 + 0x054)); data &= ~(0xf << 12); data |= 1 << 12; mmio_write_32((0xf6504000 + 0x054), data); dsb(); data = mmio_read_32((0xf7032000 + 0x000)); data &= ~(1 << 0); mmio_write_32((0xf7032000 + 0x000), data); mmio_write_32((0xf7032000 + 0x004), 0x5110207d); mmio_write_32((0xf7032000 + 0x134), 0x10000005); data = mmio_read_32((0xf7032000 + 0x134)); data = mmio_read_32((0xf7032000 + 0x000)); data |= (1 << 0); mmio_write_32((0xf7032000 + 0x000), data); mmio_write_32((0xf7032000 + 0x368), 0x100da); data = mmio_read_32((0xf7032000 + 0x378)); data &= ~((1 << 7) - 1); data |= 0x6b; mmio_write_32((0xf7032000 + 0x378), data); dsb(); do { data = mmio_read_32((0xf7032000 + 0x378)); tmp = data & 0x7f; data = (data & (0x7f << 8)) >> 8; if (data != tmp) continue; data = mmio_read_32((0xf7032000 + 0x37c)); } while (!(data & 1)); data = mmio_read_32((0xf7032000 + 0x104)); data &= ~((3 << 0) | (3 << 8)); cpuext_cfg = 1; ddr_cfg = 1; data |= cpuext_cfg | (ddr_cfg << 8); mmio_write_32((0xf7032000 + 0x104), data); dsb(); do { data = mmio_read_32((0xf7032000 + 0x104)); tmp = (data & (3 << 16)) >> 16; if (cpuext_cfg != tmp) continue; tmp = (data & (3 << 24)) >> 24; if (ddr_cfg != tmp) continue; data = mmio_read_32((0xf7032000 + 0x000)); data &= 1 << 28; } while (!data); data = mmio_read_32((0xf7032000 + 0x100)); data &= ~(1 << 0); mmio_write_32((0xf7032000 + 0x100), data); dsb(); do { data = mmio_read_32((0xf7032000 + 0x100)); data &= (1 << 1); } while (data != (1 << 1)); mdelay(1000); data = mmio_read_32((0xf6504000 + 0x054)); data &= ~(1 << 28); mmio_write_32((0xf6504000 + 0x054), data); dsb(); data = mmio_read_32((0xf7032000 + 0x110)); data &= ~((1 << 4) | (3 << 12)); mmio_write_32((0xf7032000 + 0x110), data); } int cat_533mhz_800mhz(void) { unsigned int data, i; unsigned int bdl[5]; data = mmio_read_32((0xf712c000 + 0x1c8)); data &= 0xfffff0f0; data |= 0x100f01; mmio_write_32((0xf712c000 + 0x1c8), data); for (i = 0; i < 0x20; i++) { mmio_write_32((0xf712c000 + 0x1d4), 0xc0000); data = (i << 0x10) + i; mmio_write_32((0xf712c000 + 0x140), data); mmio_write_32((0xf712c000 + 0x144), data); mmio_write_32((0xf712c000 + 0x148), data); mmio_write_32((0xf712c000 + 0x14c), data); mmio_write_32((0xf712c000 + 0x150), data); data = mmio_read_32((0xf712c000 + 0x070)); data |= 0x80000; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x070)); data &= 0xfff7ffff; mmio_write_32((0xf712c000 + 0x070), data); mmio_write_32((0xf712c000 + 0x004), 0x8000); mmio_write_32((0xf712c000 + 0x004), 0x0); mmio_write_32((0xf712c000 + 0x004), 0x801); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if ((data & 0x400) == 0) { mdelay(10); return 0; } WARN("lpddr3 cat fail\n"); data = mmio_read_32((0xf712c000 + 0x1d4)); if ((data & 0x1f00) && ((data & 0x1f) == 0)) { bdl[0] = mmio_read_32((0xf712c000 + 0x140)); bdl[1] = mmio_read_32((0xf712c000 + 0x144)); bdl[2] = mmio_read_32((0xf712c000 + 0x148)); bdl[3] = mmio_read_32((0xf712c000 + 0x14c)); bdl[4] = mmio_read_32((0xf712c000 + 0x150)); if ((!(bdl[0] & 0x1f001f)) || (!(bdl[1] & 0x1f001f)) || (!(bdl[2] & 0x1f001f)) || (!(bdl[3] & 0x1f001f)) || (!(bdl[4] & 0x1f001f))) { WARN("lpddr3 cat deskew error\n"); if (i == 0x1f) { WARN("addrnbdl is max\n"); return -EINVAL; } mmio_write_32((0xf712c000 + 0x008), 0x400); } else { WARN("lpddr3 cat other error1\n"); return -EINVAL; } } else { WARN("lpddr3 cat other error2\n"); return -EINVAL; } } return -EINVAL; } static void ddrx_rdet(void) { unsigned int data, rdet, bdl[4]; data = mmio_read_32((0xf712c000 + 0x0d0)); data &= 0xf800ffff; data |= 0x8f0000; mmio_write_32((0xf712c000 + 0x0d0), data); data = mmio_read_32((0xf712c000 + 0x0dc)); data &= 0xfffffff0; data |= 0xf; mmio_write_32((0xf712c000 + 0x0dc), data); data = mmio_read_32((0xf712c000 + 0x070)); data |= 0x80000; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x070)); data &= 0xfff7ffff; mmio_write_32((0xf712c000 + 0x070), data); mmio_write_32((0xf712c000 + 0x004), 0x8000); mmio_write_32((0xf712c000 + 0x004), 0); data = mmio_read_32((0xf712c000 + 0x0d0)); data &= ~0xf0000000; data |= 0x80000000; mmio_write_32((0xf712c000 + 0x0d0), data); mmio_write_32((0xf712c000 + 0x004), 0x101); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (!(data & 1)); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x100) WARN("rdet lbs fail\n"); bdl[0] = mmio_read_32((0xf712c000 + 0x22c)) & 0x7f; bdl[1] = mmio_read_32((0xf712c000 + 0x2ac)) & 0x7f; bdl[2] = mmio_read_32((0xf712c000 + 0x32c)) & 0x7f; bdl[3] = mmio_read_32((0xf712c000 + 0x3ac)) & 0x7f; do { data = mmio_read_32((0xf712c000 + 0x22c)); data &= ~0x7f; data |= bdl[0]; mmio_write_32((0xf712c000 + 0x22c), data); data = mmio_read_32((0xf712c000 + 0x2ac)); data &= ~0x7f; data |= bdl[1]; mmio_write_32((0xf712c000 + 0x2ac), data); data = mmio_read_32((0xf712c000 + 0x32c)); data &= ~0x7f; data |= bdl[2]; mmio_write_32((0xf712c000 + 0x32c), data); data = mmio_read_32((0xf712c000 + 0x3ac)); data &= ~0x7f; data |= bdl[3]; mmio_write_32((0xf712c000 + 0x3ac), data); data = mmio_read_32((0xf712c000 + 0x070)); data |= 0x80000; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x070)); data &= 0xfff7ffff; mmio_write_32((0xf712c000 + 0x070), data); mmio_write_32((0xf712c000 + 0x004), 0x8000); mmio_write_32((0xf712c000 + 0x004), 0); data = mmio_read_32((0xf712c000 + 0x0d0)); data &= ~0xf0000000; data |= 0x40000000; mmio_write_32((0xf712c000 + 0x0d0), data); mmio_write_32((0xf712c000 + 0x004), 0x101); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); rdet = data & 0x100; if (rdet) { INFO("rdet ds fail\n"); mmio_write_32((0xf712c000 + 0x008), 0x100); } bdl[0]++; bdl[1]++; bdl[2]++; bdl[3]++; } while (rdet); data = mmio_read_32((0xf712c000 + 0x0d0)); data &= ~0xf0000000; data |= 0x30000000; mmio_write_32((0xf712c000 + 0x0d0), data); mmio_write_32((0xf712c000 + 0x004), 0x101); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x100) INFO("rdet rbs av fail\n"); } static void ddrx_wdet(void) { unsigned int data, wdet, zero_bdl = 0, dq[4]; int i; data = mmio_read_32((0xf712c000 + 0x0d0)); data &= ~0xf; data |= 0xf; mmio_write_32((0xf712c000 + 0x0d0), data); data = mmio_read_32((0xf712c000 + 0x070)); data |= 0x80000; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x070)); data &= ~0x80000; mmio_write_32((0xf712c000 + 0x070), data); mmio_write_32((0xf712c000 + 0x004), 0x8000); mmio_write_32((0xf712c000 + 0x004), 0); data = mmio_read_32((0xf712c000 + 0x0d0)); data &= ~0xf000; data |= 0x8000; mmio_write_32((0xf712c000 + 0x0d0), data); mmio_write_32((0xf712c000 + 0x004), 0x201); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x200) INFO("wdet lbs fail\n"); dq[0] = mmio_read_32((0xf712c000 + 0x234)) & 0x1f00; dq[1] = mmio_read_32((0xf712c000 + 0x2b4)) & 0x1f00; dq[2] = mmio_read_32((0xf712c000 + 0x334)) & 0x1f00; dq[3] = mmio_read_32((0xf712c000 + 0x3b4)) & 0x1f00; do { mmio_write_32((0xf712c000 + 0x234), dq[0]); mmio_write_32((0xf712c000 + 0x2b4), dq[1]); mmio_write_32((0xf712c000 + 0x334), dq[2]); mmio_write_32((0xf712c000 + 0x3b4), dq[3]); data = mmio_read_32((0xf712c000 + 0x070)); data |= 0x80000; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x070)); data &= ~0x80000; mmio_write_32((0xf712c000 + 0x070), data); mmio_write_32((0xf712c000 + 0x004), 0x8000); mmio_write_32((0xf712c000 + 0x004), 0); data = mmio_read_32((0xf712c000 + 0x0d0)); data &= ~0xf000; data |= 0x4000; mmio_write_32((0xf712c000 + 0x0d0), data); mmio_write_32((0xf712c000 + 0x004), 0x201); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); wdet = data & 0x200; if (wdet) { INFO("wdet ds fail\n"); mmio_write_32((0xf712c000 + 0x008), 0x200); } mdelay(10); for (i = 0; i < 4; i++) { data = mmio_read_32((0xf712c000 + 0x210 + i * 0x80)); if ((!(data & 0x1f)) || (!(data & 0x1f00)) || (!(data & 0x1f0000)) || (!(data & 0x1f000000))) zero_bdl = 1; data = mmio_read_32((0xf712c000 + 0x214 + i * 0x80)); if ((!(data & 0x1f)) || (!(data & 0x1f00)) || (!(data & 0x1f0000)) || (!(data & 0x1f000000))) zero_bdl = 1; data = mmio_read_32((0xf712c000 + 0x218 + i * 0x80)); if (!(data & 0x1f)) zero_bdl = 1; if (zero_bdl) { if (i == 0) dq[0] = dq[0] - 0x100; if (i == 1) dq[1] = dq[1] - 0x100; if (i == 2) dq[2] = dq[2] - 0x100; if (i == 3) dq[3] = dq[3] - 0x100; } } } while (wdet); data = mmio_read_32((0xf712c000 + 0x0d0)); data &= ~0xf000; data |= 0x3000; mmio_write_32((0xf712c000 + 0x0d0), data); mmio_write_32((0xf712c000 + 0x004), 0x201); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x200) INFO("wdet rbs av fail\n"); } void set_ddrc_150mhz(void) { unsigned int data; mmio_write_32((0xf7032000 + 0x580), 0x1); mmio_write_32((0xf7032000 + 0x5a8), 0x7); data = mmio_read_32((0xf7032000 + 0x104)); data &= 0xfffffcff; mmio_write_32((0xf7032000 + 0x104), data); mmio_write_32((0xf7030000 + 0x050), 0x31); mmio_write_32((0xf7030000 + 0x240), 0x5ffff); mmio_write_32((0xf7030000 + 0x344), 0xf5ff); mmio_write_32((0xf712c000 + 0x00c), 0x80000f0f); mmio_write_32((0xf712c000 + 0x00c), 0xf0f); mmio_write_32((0xf712c000 + 0x018), 0x7); mmio_write_32((0xf712c000 + 0x090), 0x7200000); mmio_write_32((0xf712c000 + 0x258), 0x720); mmio_write_32((0xf712c000 + 0x2d8), 0x720); mmio_write_32((0xf712c000 + 0x358), 0x720); mmio_write_32((0xf712c000 + 0x3d8), 0x720); mmio_write_32((0xf712c000 + 0x018), 0x7); mmio_write_32((0xf712c000 + 0x0b0), 0xf00000f); mmio_write_32((0xf712c000 + 0x0b4), 0xf); mmio_write_32((0xf712c000 + 0x088), 0x3fff801); mmio_write_32((0xf712c000 + 0x070), 0x8940000); data = mmio_read_32((0xf712c000 + 0x078)); data |= 4; mmio_write_32((0xf712c000 + 0x078), data); mmio_write_32((0xf712c000 + 0x01c), 0x8000080); data = mmio_read_32((0xf712c000 + 0x020)); data &= 0xfffffffe; mmio_write_32((0xf712c000 + 0x020), data); mmio_write_32((0xf712c000 + 0x1d4), 0xc0000); mmio_write_32((0xf712c000 + 0x010), 0x500000f); mmio_write_32((0xf712c000 + 0x014), 0x10); data = mmio_read_32((0xf712c000 + 0x1e4)); data &= 0xffffff00; mmio_write_32((0xf712c000 + 0x1e4), data); mmio_write_32((0xf712c000 + 0x030), 0x30c82355); mmio_write_32((0xf712c000 + 0x034), 0x62112bb); mmio_write_32((0xf712c000 + 0x038), 0x20041022); mmio_write_32((0xf712c000 + 0x03c), 0x63177497); mmio_write_32((0xf712c000 + 0x040), 0x3008407); mmio_write_32((0xf712c000 + 0x064), 0x10483); mmio_write_32((0xf712c000 + 0x068), 0xff0a0000); data = mmio_read_32((0xf712c000 + 0x070)); data &= 0xffff0000; data |= 0x184; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x048)); data &= 0xbfffffff; mmio_write_32((0xf712c000 + 0x048), data); data = mmio_read_32((0xf712c000 + 0x020)); data &= ~0x10; mmio_write_32((0xf712c000 + 0x020), data); data = mmio_read_32((0xf712c000 + 0x080)); data &= ~0x2000; mmio_write_32((0xf712c000 + 0x080), data); mmio_write_32((0xf712c000 + 0x270), 0x3); mmio_write_32((0xf712c000 + 0x2f0), 0x3); mmio_write_32((0xf712c000 + 0x370), 0x3); mmio_write_32((0xf712c000 + 0x3f0), 0x3); mmio_write_32((0xf712c000 + 0x048), 0x90420880); mmio_write_32((0xf7128000 + 0x040), 0x0); mmio_write_32((0xf712c000 + 0x004), 0x146d); mmio_write_32((0xf7128000 + 0x050), 0x100123); mmio_write_32((0xf7128000 + 0x060), 0x133); mmio_write_32((0xf7128000 + 0x064), 0x133); mmio_write_32((0xf7128000 + 0x200), 0xa1000); mmio_write_32((0xf7128000 + 0x100), 0xb3290d08); mmio_write_32((0xf7128000 + 0x104), 0x9621821); mmio_write_32((0xf7128000 + 0x108), 0x45009023); mmio_write_32((0xf7128000 + 0x10c), 0xaf44c145); mmio_write_32((0xf7128000 + 0x110), 0x10b00000); mmio_write_32((0xf7128000 + 0x114), 0x11080806); mmio_write_32((0xf7128000 + 0x118), 0x44); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 8) { NOTICE("fail to init ddr3 rank0\n"); return; } data = mmio_read_32((0xf712c000 + 0x048)); data |= 1; mmio_write_32((0xf712c000 + 0x048), data); mmio_write_32((0xf712c000 + 0x004), 0x21); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x8) NOTICE("ddr3 rank1 init failure\n"); else INFO("ddr3 rank1 init pass\n"); data = mmio_read_32((0xf712c000 + 0x048)); data &= ~0xf; mmio_write_32((0xf712c000 + 0x048), data); INFO("succeed to set ddrc 150mhz\n"); } void set_ddrc_266mhz(void) { unsigned int data; mmio_write_32((0xf7032000 + 0x580), 0x3); mmio_write_32((0xf7032000 + 0x5a8), 0x1003); data = mmio_read_32((0xf7032000 + 0x104)); data &= 0xfffffcff; mmio_write_32((0xf7032000 + 0x104), data); mmio_write_32((0xf7030000 + 0x050), 0x31); mmio_write_32((0xf7030000 + 0x240), 0x5ffff); mmio_write_32((0xf7030000 + 0x344), 0xf5ff); mmio_write_32((0xf712c000 + 0x00c), 0x80000f0f); mmio_write_32((0xf712c000 + 0x00c), 0xf0f); mmio_write_32((0xf712c000 + 0x018), 0x7); mmio_write_32((0xf712c000 + 0x090), 0x7200000); mmio_write_32((0xf712c000 + 0x258), 0x720); mmio_write_32((0xf712c000 + 0x2d8), 0x720); mmio_write_32((0xf712c000 + 0x358), 0x720); mmio_write_32((0xf712c000 + 0x3d8), 0x720); mmio_write_32((0xf712c000 + 0x018), 0x7); mmio_write_32((0xf712c000 + 0x0b0), 0xf00000f); mmio_write_32((0xf712c000 + 0x0b4), 0xf); mmio_write_32((0xf712c000 + 0x088), 0x3fff801); mmio_write_32((0xf712c000 + 0x070), 0x8940000); data = mmio_read_32((0xf712c000 + 0x078)); data |= 4; mmio_write_32((0xf712c000 + 0x078), data); mmio_write_32((0xf712c000 + 0x01c), 0x8000080); data = mmio_read_32((0xf712c000 + 0x020)); data &= 0xfffffffe; mmio_write_32((0xf712c000 + 0x020), data); mmio_write_32((0xf712c000 + 0x1d4), 0xc0000); mmio_write_32((0xf712c000 + 0x010), 0x500000f); mmio_write_32((0xf712c000 + 0x014), 0x10); data = mmio_read_32((0xf712c000 + 0x1e4)); data &= 0xffffff00; mmio_write_32((0xf712c000 + 0x1e4), data); mmio_write_32((0xf712c000 + 0x030), 0x510d4455); mmio_write_32((0xf712c000 + 0x034), 0x8391ebb); mmio_write_32((0xf712c000 + 0x038), 0x2005103c); mmio_write_32((0xf712c000 + 0x03c), 0x6329950b); mmio_write_32((0xf712c000 + 0x040), 0x300858c); mmio_write_32((0xf712c000 + 0x064), 0x10483); mmio_write_32((0xf712c000 + 0x068), 0xff0a0000); data = mmio_read_32((0xf712c000 + 0x070)); data &= 0xffff0000; data |= 0x184; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x048)); data &= 0xbfffffff; mmio_write_32((0xf712c000 + 0x048), data); data = mmio_read_32((0xf712c000 + 0x020)); data &= ~0x10; mmio_write_32((0xf712c000 + 0x020), data); data = mmio_read_32((0xf712c000 + 0x080)); data &= ~0x2000; mmio_write_32((0xf712c000 + 0x080), data); mmio_write_32((0xf712c000 + 0x270), 0x3); mmio_write_32((0xf712c000 + 0x2f0), 0x3); mmio_write_32((0xf712c000 + 0x370), 0x3); mmio_write_32((0xf712c000 + 0x3f0), 0x3); mmio_write_32((0xf712c000 + 0x048), 0x90420880); mmio_write_32((0xf7128000 + 0x040), 0x0); mmio_write_32((0xf712c000 + 0x004), 0x146d); mmio_write_32((0xf7128000 + 0x050), 0x100123); mmio_write_32((0xf7128000 + 0x060), 0x133); mmio_write_32((0xf7128000 + 0x064), 0x133); mmio_write_32((0xf7128000 + 0x200), 0xa1000); mmio_write_32((0xf7128000 + 0x100), 0xb441d50d); mmio_write_32((0xf7128000 + 0x104), 0xf721839); mmio_write_32((0xf7128000 + 0x108), 0x5500f03f); mmio_write_32((0xf7128000 + 0x10c), 0xaf486145); mmio_write_32((0xf7128000 + 0x110), 0x10b00000); mmio_write_32((0xf7128000 + 0x114), 0x12080d06); mmio_write_32((0xf7128000 + 0x118), 0x44); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 8) { NOTICE("fail to init ddr3 rank0\n"); return; } data = mmio_read_32((0xf712c000 + 0x048)); data |= 1; mmio_write_32((0xf712c000 + 0x048), data); mmio_write_32((0xf712c000 + 0x004), 0x21); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x8) NOTICE("ddr3 rank1 init failure\n"); else INFO("ddr3 rank1 init pass\n"); data = mmio_read_32((0xf712c000 + 0x048)); data &= ~0xf; mmio_write_32((0xf712c000 + 0x048), data); INFO("succeed to set ddrc 266mhz\n"); } void set_ddrc_400mhz(void) { unsigned int data; mmio_write_32((0xf7032000 + 0x580), 0x2); mmio_write_32((0xf7032000 + 0x5a8), 0x1003); data = mmio_read_32((0xf7032000 + 0x104)); data &= 0xfffffcff; mmio_write_32((0xf7032000 + 0x104), data); mmio_write_32((0xf7030000 + 0x050), 0x31); mmio_write_32((0xf7030000 + 0x240), 0x5ffff); mmio_write_32((0xf7030000 + 0x344), 0xf5ff); mmio_write_32((0xf712c000 + 0x00c), 0x80000f0f); mmio_write_32((0xf712c000 + 0x00c), 0xf0f); mmio_write_32((0xf712c000 + 0x018), 0x7); mmio_write_32((0xf712c000 + 0x090), 0x7200000); mmio_write_32((0xf712c000 + 0x258), 0x720); mmio_write_32((0xf712c000 + 0x2d8), 0x720); mmio_write_32((0xf712c000 + 0x358), 0x720); mmio_write_32((0xf712c000 + 0x3d8), 0x720); mmio_write_32((0xf712c000 + 0x018), 0x7); mmio_write_32((0xf712c000 + 0x0b0), 0xf00000f); mmio_write_32((0xf712c000 + 0x0b4), 0xf); mmio_write_32((0xf712c000 + 0x088), 0x3fff801); mmio_write_32((0xf712c000 + 0x070), 0x8940000); data = mmio_read_32((0xf712c000 + 0x078)); data |= 4; mmio_write_32((0xf712c000 + 0x078), data); mmio_write_32((0xf712c000 + 0x01c), 0x8000080); data = mmio_read_32((0xf712c000 + 0x020)); data &= 0xfffffffe; mmio_write_32((0xf712c000 + 0x020), data); mmio_write_32((0xf712c000 + 0x1d4), 0xc0000); mmio_write_32((0xf712c000 + 0x010), 0x500000f); mmio_write_32((0xf712c000 + 0x014), 0x10); data = mmio_read_32((0xf712c000 + 0x1e4)); data &= 0xffffff00; mmio_write_32((0xf712c000 + 0x1e4), data); mmio_write_32((0xf712c000 + 0x030), 0x75525655); mmio_write_32((0xf712c000 + 0x034), 0xa552abb); mmio_write_32((0xf712c000 + 0x038), 0x20071059); mmio_write_32((0xf712c000 + 0x03c), 0x633e8591); mmio_write_32((0xf712c000 + 0x040), 0x3008691); mmio_write_32((0xf712c000 + 0x064), 0x10483); mmio_write_32((0xf712c000 + 0x068), 0xff0a0000); data = mmio_read_32((0xf712c000 + 0x070)); data &= 0xffff0000; data |= 0x184; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x048)); data &= 0xbfffffff; mmio_write_32((0xf712c000 + 0x048), data); data = mmio_read_32((0xf712c000 + 0x020)); data &= ~0x10; mmio_write_32((0xf712c000 + 0x020), data); data = mmio_read_32((0xf712c000 + 0x080)); data &= ~0x2000; mmio_write_32((0xf712c000 + 0x080), data); mmio_write_32((0xf712c000 + 0x270), 0x3); mmio_write_32((0xf712c000 + 0x2f0), 0x3); mmio_write_32((0xf712c000 + 0x370), 0x3); mmio_write_32((0xf712c000 + 0x3f0), 0x3); mmio_write_32((0xf712c000 + 0x048), 0x90420880); mmio_write_32((0xf7128000 + 0x040), 0x0); mmio_write_32((0xf712c000 + 0x004), 0x146d); mmio_write_32((0xf7128000 + 0x050), 0x100123); mmio_write_32((0xf7128000 + 0x060), 0x133); mmio_write_32((0xf7128000 + 0x064), 0x133); mmio_write_32((0xf7128000 + 0x200), 0xa1000); mmio_write_32((0xf7128000 + 0x100), 0xb55a9d12); mmio_write_32((0xf7128000 + 0x104), 0x17721855); mmio_write_32((0xf7128000 + 0x108), 0x7501505f); mmio_write_32((0xf7128000 + 0x10c), 0xaf4ca245); mmio_write_32((0xf7128000 + 0x110), 0x10b00000); mmio_write_32((0xf7128000 + 0x114), 0x13081306); mmio_write_32((0xf7128000 + 0x118), 0x44); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 8) { NOTICE("fail to init ddr3 rank0\n"); return; } data = mmio_read_32((0xf712c000 + 0x048)); data |= 1; mmio_write_32((0xf712c000 + 0x048), data); mmio_write_32((0xf712c000 + 0x004), 0x21); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x8) NOTICE("ddr3 rank1 init failure\n"); else INFO("ddr3 rank1 init pass\n"); data = mmio_read_32((0xf712c000 + 0x048)); data &= ~0xf; mmio_write_32((0xf712c000 + 0x048), data); INFO("succeed to set ddrc 400mhz\n"); } void set_ddrc_533mhz(void) { unsigned int data; mmio_write_32((0xf7032000 + 0x580), 0x3); mmio_write_32((0xf7032000 + 0x5a8), 0x11111); data = mmio_read_32((0xf7032000 + 0x104)); data |= 0x100; mmio_write_32((0xf7032000 + 0x104), data); mmio_write_32((0xf7030000 + 0x050), 0x30); mmio_write_32((0xf7030000 + 0x240), 0x5ffff); mmio_write_32((0xf7030000 + 0x344), 0xf5ff); mmio_write_32((0xf712c000 + 0x00c), 0x400); mmio_write_32((0xf712c000 + 0x00c), 0x400); mmio_write_32((0xf712c000 + 0x018), 0x7); mmio_write_32((0xf712c000 + 0x090), 0x6400000); mmio_write_32((0xf712c000 + 0x258), 0x640); mmio_write_32((0xf712c000 + 0x2d8), 0x640); mmio_write_32((0xf712c000 + 0x358), 0x640); mmio_write_32((0xf712c000 + 0x3d8), 0x640); mmio_write_32((0xf712c000 + 0x018), 0x0); mmio_write_32((0xf712c000 + 0x0b0), 0xf00000f); mmio_write_32((0xf712c000 + 0x0b4), 0xf); mmio_write_32((0xf712c000 + 0x088), 0x3fff801); mmio_write_32((0xf712c000 + 0x070), 0x8940000); data = mmio_read_32((0xf712c000 + 0x078)); data |= 4; mmio_write_32((0xf712c000 + 0x078), data); mmio_write_32((0xf712c000 + 0x01c), 0x8000080); data = mmio_read_32((0xf712c000 + 0x020)); data &= 0xfffffffe; mmio_write_32((0xf712c000 + 0x020), data); mmio_write_32((0xf712c000 + 0x1d4), 0xc0000); mmio_write_32((0xf712c000 + 0x010), 0x500000f); mmio_write_32((0xf712c000 + 0x014), 0x10); data = mmio_read_32((0xf712c000 + 0x1e4)); data &= 0xffffff00; mmio_write_32((0xf712c000 + 0x1e4), data); mmio_write_32((0xf712c000 + 0x030), 0x9dd87855); mmio_write_32((0xf712c000 + 0x034), 0xa7138bb); mmio_write_32((0xf712c000 + 0x038), 0x20091477); mmio_write_32((0xf712c000 + 0x03c), 0x84534e16); mmio_write_32((0xf712c000 + 0x040), 0x3008817); mmio_write_32((0xf712c000 + 0x064), 0x106c3); mmio_write_32((0xf712c000 + 0x068), 0xff0a0000); data = mmio_read_32((0xf712c000 + 0x070)); data &= 0xffff0000; data |= 0x305; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x048)); data |= 0x40000000; mmio_write_32((0xf712c000 + 0x048), data); data = mmio_read_32((0xf712c000 + 0x020)); data &= ~0x10; mmio_write_32((0xf712c000 + 0x020), data); data = mmio_read_32((0xf712c000 + 0x080)); data &= ~0x2000; mmio_write_32((0xf712c000 + 0x080), data); mmio_write_32((0xf712c000 + 0x270), 0x3); mmio_write_32((0xf712c000 + 0x2f0), 0x3); mmio_write_32((0xf712c000 + 0x370), 0x3); mmio_write_32((0xf712c000 + 0x3f0), 0x3); mmio_write_32((0xf712c000 + 0x048), 0xd0420900); mmio_write_32((0xf7128000 + 0x040), 0x0); mmio_write_32((0xf712c000 + 0x004), 0x140f); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x7fe) { NOTICE("failed to init lpddr3 rank0 dram phy\n"); return; } cat_533mhz_800mhz(); mmio_write_32((0xf712c000 + 0x004), 0xf1); mmio_write_32((0xf7128000 + 0x050), 0x100123); mmio_write_32((0xf7128000 + 0x060), 0x133); mmio_write_32((0xf7128000 + 0x064), 0x133); mmio_write_32((0xf7128000 + 0x200), 0xa1000); mmio_write_32((0xf7128000 + 0x100), 0xb77b6718); mmio_write_32((0xf7128000 + 0x104), 0x1e82a071); mmio_write_32((0xf7128000 + 0x108), 0x9501c07e); mmio_write_32((0xf7128000 + 0x10c), 0xaf50c255); mmio_write_32((0xf7128000 + 0x110), 0x10b00000); mmio_write_32((0xf7128000 + 0x114), 0x13181908); mmio_write_32((0xf7128000 + 0x118), 0x44); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x7fe) { NOTICE("fail to init ddr3 rank0\n"); return; } ddrx_rdet(); ddrx_wdet(); data = mmio_read_32((0xf712c000 + 0x048)); data |= 1; mmio_write_32((0xf712c000 + 0x048), data); mmio_write_32((0xf712c000 + 0x004), 0x21); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x7fe) NOTICE("ddr3 rank1 init failure\n"); else INFO("ddr3 rank1 init pass\n"); data = mmio_read_32((0xf712c000 + 0x048)); data &= ~0xf; mmio_write_32((0xf712c000 + 0x048), data); INFO("succeed to set ddrc 533mhz\n"); } void set_ddrc_800mhz(void) { unsigned int data; mmio_write_32((0xf7032000 + 0x580), 0x2); mmio_write_32((0xf7032000 + 0x5a8), 0x1003); data = mmio_read_32((0xf7032000 + 0x104)); data &= 0xfffffcff; mmio_write_32((0xf7032000 + 0x104), data); mmio_write_32((0xf7030000 + 0x050), 0x30); mmio_write_32((0xf7030000 + 0x240), 0x5ffff); mmio_write_32((0xf7030000 + 0x344), 0xf5ff); mmio_write_32((0xf712c000 + 0x00c), 0x400); mmio_write_32((0xf712c000 + 0x00c), 0x400); mmio_write_32((0xf712c000 + 0x018), 0x7); mmio_write_32((0xf712c000 + 0x090), 0x5400000); mmio_write_32((0xf712c000 + 0x258), 0x540); mmio_write_32((0xf712c000 + 0x2d8), 0x540); mmio_write_32((0xf712c000 + 0x358), 0x540); mmio_write_32((0xf712c000 + 0x3d8), 0x540); mmio_write_32((0xf712c000 + 0x018), 0x0); mmio_write_32((0xf712c000 + 0x0b0), 0xf00000f); mmio_write_32((0xf712c000 + 0x0b4), 0xf); mmio_write_32((0xf712c000 + 0x088), 0x3fff801); mmio_write_32((0xf712c000 + 0x070), 0x8940000); data = mmio_read_32((0xf712c000 + 0x078)); data |= 4; mmio_write_32((0xf712c000 + 0x078), data); mmio_write_32((0xf712c000 + 0x01c), 0x8000080); data = mmio_read_32((0xf712c000 + 0x020)); data &= 0xfffffffe; mmio_write_32((0xf712c000 + 0x020), data); mmio_write_32((0xf712c000 + 0x1d4), 0xc0000); mmio_write_32((0xf712c000 + 0x010), 0x500000f); mmio_write_32((0xf712c000 + 0x014), 0x10); data = mmio_read_32((0xf712c000 + 0x1e4)); data &= 0xffffff00; mmio_write_32((0xf712c000 + 0x1e4), data); mmio_write_32((0xf712c000 + 0x030), 0xe663ab77); mmio_write_32((0xf712c000 + 0x034), 0xea952db); mmio_write_32((0xf712c000 + 0x038), 0x200d1cb1); mmio_write_32((0xf712c000 + 0x03c), 0xc67d0721); mmio_write_32((0xf712c000 + 0x040), 0x3008aa1); mmio_write_32((0xf712c000 + 0x064), 0x11a43); mmio_write_32((0xf712c000 + 0x068), 0xff0a0000); data = mmio_read_32((0xf712c000 + 0x070)); data &= 0xffff0000; data |= 0x507; mmio_write_32((0xf712c000 + 0x070), data); data = mmio_read_32((0xf712c000 + 0x048)); data |= 0x40000000; mmio_write_32((0xf712c000 + 0x048), data); data = mmio_read_32((0xf712c000 + 0x020)); data &= 0xffffffef; mmio_write_32((0xf712c000 + 0x020), data); data = mmio_read_32((0xf712c000 + 0x080)); data &= 0xffffdfff; mmio_write_32((0xf712c000 + 0x080), data); mmio_write_32((0xf712c000 + 0x270), 0x3); mmio_write_32((0xf712c000 + 0x2f0), 0x3); mmio_write_32((0xf712c000 + 0x370), 0x3); mmio_write_32((0xf712c000 + 0x3f0), 0x3); mmio_write_32((0xf712c000 + 0x048), 0xd0420900); mmio_write_32((0xf7128000 + 0x040), 0x2001); mmio_write_32((0xf712c000 + 0x004), 0x140f); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x7fe) { WARN("failed to init lpddr3 rank0 dram phy\n"); return; } cat_533mhz_800mhz(); mmio_write_32((0xf712c000 + 0x004), 0xf1); mmio_write_32((0xf7128000 + 0x050), 0x100023); mmio_write_32((0xf7128000 + 0x060), 0x133); mmio_write_32((0xf7128000 + 0x064), 0x133); mmio_write_32((0xf7128000 + 0x200), 0xa1000); mmio_write_32((0xf7128000 + 0x100), 0x755a9d12); mmio_write_32((0xf7128000 + 0x104), 0x1753b055); mmio_write_32((0xf7128000 + 0x108), 0x7401505f); mmio_write_32((0xf7128000 + 0x10c), 0x578ca244); mmio_write_32((0xf7128000 + 0x110), 0x10700000); mmio_write_32((0xf7128000 + 0x114), 0x13141306); mmio_write_32((0xf7128000 + 0x118), 0x44); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x7fe) { NOTICE("fail to init ddr3 rank0\n"); return; } ddrx_rdet(); ddrx_wdet(); data = mmio_read_32((0xf712c000 + 0x048)); data |= 1; mmio_write_32((0xf712c000 + 0x048), data); mmio_write_32((0xf712c000 + 0x004), 0x21); do { data = mmio_read_32((0xf712c000 + 0x004)); } while (data & 1); data = mmio_read_32((0xf712c000 + 0x008)); if (data & 0x7fe) NOTICE("ddr3 rank1 init failure\n"); else INFO("ddr3 rank1 init pass\n"); data = mmio_read_32((0xf712c000 + 0x048)); data &= ~0xf; mmio_write_32((0xf712c000 + 0x048), data); INFO("succeed to set ddrc 800mhz\n"); } static void ddrc_common_init(int freq) { unsigned int data; mmio_write_32((0xf7120000 + 0x020), 0x1); mmio_write_32((0xf7120000 + 0x100), 0x1700); mmio_write_32((0xf7120000 + 0x104), 0x71040004); mmio_write_32((0xf7121400 + 0x104), 0xf); mmio_write_32((0xf7121800 + 0x104), 0xf); mmio_write_32((0xf7121c00 + 0x104), 0xf); mmio_write_32((0xf7122000 + 0x104), 0xf); mmio_write_32((0xf7128000 + 0x02c), 0x6); mmio_write_32((0xf7128000 + 0x020), 0x30003); mmio_write_32((0xf7128000 + 0x028), 0x310201); mmio_write_32((0xf712c000 + 0x1e4), 0xfe007600); mmio_write_32((0xf7128000 + 0x01c), 0xaf001); data = mmio_read_32((0xf7128000 + 0x280)); data |= 1 << 7; mmio_write_32((0xf7128000 + 0x280), data); mmio_write_32((0xf7128000 + 0x244), 0x3); if (freq == DDR_FREQ_800M) mmio_write_32((0xf7128000 + 0x240), 167 * (freq / 2) / 1024); else mmio_write_32((0xf7128000 + 0x240), 167 * freq / 1024); data = mmio_read_32((0xf712c000 + 0x080)); data &= 0xffff; data |= 0x4002000; mmio_write_32((0xf712c000 + 0x080), data); mmio_write_32((0xf7128000 + 0x000), 0x0); do { data = mmio_read_32((0xf7128000 + 0x294)); } while (data & 1); mmio_write_32((0xf7128000 + 0x000), 0x2); } static int dienum_det_and_rowcol_cfg(void) { unsigned int data; mmio_write_32((0xf7128000 + 0x210), 0x87); mmio_write_32((0xf7128000 + 0x218), 0x10000); mmio_write_32((0xf7128000 + 0x00c), 0x1); do { data = mmio_read_32((0xf7128000 + 0x00c)); } while (data & 1); data = mmio_read_32((0xf7128000 + 0x4a8)) & 0xfc; switch (data) { case 0x18: mmio_write_32((0xf7128000 + 0x060), 0x132); mmio_write_32((0xf7128000 + 0x064), 0x132); mmio_write_32((0xf7120000 + 0x100), 0x1600); mmio_write_32((0xf7120000 + 0x104), 0x71040004); mmio_write_32(MEMORY_AXI_DDR_CAPACITY_ADDR, 0x40000000); break; case 0x1c: mmio_write_32((0xf7128000 + 0x060), 0x142); mmio_write_32((0xf7128000 + 0x064), 0x142); mmio_write_32((0xf7120000 + 0x100), 0x1700); mmio_write_32((0xf7120000 + 0x104), 0x71040004); mmio_write_32(MEMORY_AXI_DDR_CAPACITY_ADDR, 0x80000000); break; case 0x58: mmio_write_32((0xf7128000 + 0x060), 0x133); mmio_write_32((0xf7128000 + 0x064), 0x133); mmio_write_32((0xf7120000 + 0x100), 0x1700); mmio_write_32((0xf7120000 + 0x104), 0x71040004); mmio_write_32(MEMORY_AXI_DDR_CAPACITY_ADDR, 0x80000000); break; default: mmio_write_32(MEMORY_AXI_DDR_CAPACITY_ADDR, 0x80000000); break; } if (!data) return -EINVAL; return 0; } static int detect_ddr_chip_info(void) { unsigned int data, mr5, mr6, mr7; mmio_write_32((0xf7128000 + 0x210), 0x57); mmio_write_32((0xf7128000 + 0x218), 0x10000); mmio_write_32((0xf7128000 + 0x00c), 0x1); do { data = mmio_read_32((0xf7128000 + 0x00c)); } while (data & 1); data = mmio_read_32((0xf7128000 + 0x4a8)); mr5 = data & 0xff; switch (mr5) { case 1: INFO("Samsung DDR\n"); break; case 6: INFO("Hynix DDR\n"); break; case 3: INFO("Elpida DDR\n"); break; default: INFO("DDR from other vendors\n"); break; } mmio_write_32((0xf7128000 + 0x210), 0x67); mmio_write_32((0xf7128000 + 0x218), 0x10000); mmio_write_32((0xf7128000 + 0x00c), 0x1); do { data = mmio_read_32((0xf7128000 + 0x00c)); } while (data & 1); data = mmio_read_32((0xf7128000 + 0x4a8)); mr6 = data & 0xff; mmio_write_32((0xf7128000 + 0x210), 0x77); mmio_write_32((0xf7128000 + 0x218), 0x10000); mmio_write_32((0xf7128000 + 0x00c), 0x1); do { data = mmio_read_32((0xf7128000 + 0x00c)); } while (data & 1); data = mmio_read_32((0xf7128000 + 0x4a8)); mr7 = data & 0xff; data = mr5 + (mr6 << 8) + (mr7 << 16); return data; } void ddr_phy_reset(void) { mmio_write_32(0xf7030340, 0xa000); mmio_write_32(0xf7030344, 0xa000); } void lpddrx_save_ddl_para_bypass(uint32_t *ddr_ddl_para, unsigned int index) { uint32_t value; uint32_t cnt = index; uint32_t i; for (i = 0; i < 4; i++) { value = mmio_read_32(0xf712c000 + 0x22c + i * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x23c + i * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x240 + i * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x640 + i * 0x80); ddr_ddl_para[cnt++] = value; } } void lpddrx_save_ddl_para_mission(uint32_t *ddr_ddl_para, unsigned int index) { uint32_t value; uint32_t cnt = index; uint32_t i; value = mmio_read_32(0xf712c000 + 0x140); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x144); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x148); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x14c); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x150); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x1d4); ddr_ddl_para[cnt++] = value; for (i = 0; i < 4; i++) { value = mmio_read_32(0xf712c000 + 0x210 + i * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x214 + i * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x218 + i * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x21c + i * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x220 + i * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x224 + i * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x228 + i * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x22c + i * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x230 + i * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x234 + i * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x238 + i * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x23c + i * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x240 + i * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x640 + i * 0x80); ddr_ddl_para[cnt++] = value; } value = mmio_read_32(0xf712c000 + 0x168); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x24c + 0 * 0x80); ddr_ddl_para[cnt++] = value; value = mmio_read_32(0xf712c000 + 0x24c + 2 * 0x80); ddr_ddl_para[cnt++] = value; } int lpddr3_freq_init(int freq) { set_ddrc_150mhz(); lpddrx_save_ddl_para_bypass((uint32_t *)MEMORY_AXI_DDR_DDL_ADDR, 0); if (freq > DDR_FREQ_150M) { ddr_phy_reset(); set_ddrc_266mhz(); lpddrx_save_ddl_para_bypass((uint32_t *)MEMORY_AXI_DDR_DDL_ADDR, 16); } if (freq > DDR_FREQ_266M) { ddr_phy_reset(); set_ddrc_400mhz(); lpddrx_save_ddl_para_bypass((uint32_t *)MEMORY_AXI_DDR_DDL_ADDR, 16 * 2); } if (freq > DDR_FREQ_400M) { ddr_phy_reset(); set_ddrc_533mhz(); lpddrx_save_ddl_para_mission((uint32_t *)MEMORY_AXI_DDR_DDL_ADDR, 16 * 3); } if (freq > DDR_FREQ_533M) { ddr_phy_reset(); set_ddrc_800mhz(); lpddrx_save_ddl_para_mission((uint32_t *)MEMORY_AXI_DDR_DDL_ADDR, 16 * 3 + 61); } return 0; } static void init_ddr(int freq) { unsigned int data; int ret; data = mmio_read_32((0xf7032000 + 0x030)); data |= 1; mmio_write_32((0xf7032000 + 0x030), data); data = mmio_read_32((0xf7032000 + 0x010)); data |= 1; mmio_write_32((0xf7032000 + 0x010), data); udelay(300); do { data = mmio_read_32((0xf7032000 + 0x030)); data &= 3 << 28; } while (data != (3 << 28)); do { data = mmio_read_32((0xf7032000 + 0x010)); data &= 3 << 28; } while (data != (3 << 28)); ret = lpddr3_freq_init(freq); if (ret) return; } static void init_ddrc_qos(void) { unsigned int port, data; mmio_write_32((0xf7124000 + 0x088), 1); port = 0; mmio_write_32((0xf7120000 + 0x200 + port * 0x10), 0x1210); mmio_write_32((0xf7120000 + 0x204 + port * 0x10), 0x11111111); mmio_write_32((0xf7120000 + 0x208 + port * 0x10), 0x11111111); mmio_write_32((0xf7120000 + 0x400 + 0 * 0x10), 0x001d0007); for (port = 3; port <= 4; port++) { mmio_write_32((0xf7120000 + 0x200 + port * 0x10), 0x1210); mmio_write_32((0xf7120000 + 0x204 + port * 0x10), 0x77777777); mmio_write_32((0xf7120000 + 0x208 + port * 0x10), 0x77777777); } port = 1; mmio_write_32((0xf7120000 + 0x200 + port * 0x10), 0x30000); mmio_write_32((0xf7120000 + 0x204 + port * 0x10), 0x1234567); mmio_write_32((0xf7120000 + 0x208 + port * 0x10), 0x1234567); mmio_write_32((0xf7124000 + 0x1f0), 0); mmio_write_32((0xf7124000 + 0x0bc), 0x3020100); mmio_write_32((0xf7124000 + 0x0d0), 0x3020100); mmio_write_32((0xf7124000 + 0x1f4), 0x01000100); mmio_write_32((0xf7124000 + 0x08c + 0 * 4), 0xd0670402); mmio_write_32((0xf7124000 + 0x068 + 0 * 4), 0x31); mmio_write_32((0xf7124000 + 0x000), 0x7); data = mmio_read_32((0xf7124000 + 0x09c)); data &= ~0xff0000; data |= 0x400000; mmio_write_32((0xf7124000 + 0x09c), data); data = mmio_read_32((0xf7124000 + 0x0ac)); data &= ~0xff0000; data |= 0x400000; mmio_write_32((0xf7124000 + 0x0ac), data); port = 2; mmio_write_32((0xf7120000 + 0x200 + port * 0x10), 0x30000); mmio_write_32((0xf7120000 + 0x204 + port * 0x10), 0x1234567); mmio_write_32((0xf7120000 + 0x208 + port * 0x10), 0x1234567); mmio_write_32((0xf7124000 + 0x09c), 0xff7fff); mmio_write_32((0xf7124000 + 0x0a0), 0xff); mmio_write_32((0xf7124000 + 0x0ac), 0xff7fff); mmio_write_32((0xf7124000 + 0x0b0), 0xff); mmio_write_32((0xf7124000 + 0x0bc), 0x3020100); mmio_write_32((0xf7124000 + 0x0d0), 0x3020100); } void hikey_ddr_init(unsigned int ddr_freq) { uint32_t data; assert((ddr_freq == DDR_FREQ_150M) || (ddr_freq == DDR_FREQ_266M) || (ddr_freq == DDR_FREQ_400M) || (ddr_freq == DDR_FREQ_533M) || (ddr_freq == DDR_FREQ_800M)); init_pll(); init_freq(); init_ddr(ddr_freq); ddrc_common_init(ddr_freq); dienum_det_and_rowcol_cfg(); detect_ddr_chip_info(); if ((ddr_freq == DDR_FREQ_400M) || (ddr_freq == DDR_FREQ_800M)) { data = mmio_read_32(0xf7032000 + 0x010); data &= ~0x1; mmio_write_32(0xf7032000 + 0x010, data); } else if ((ddr_freq == DDR_FREQ_266M) || (ddr_freq == DDR_FREQ_533M)) { data = mmio_read_32(0xf7032000 + 0x030); data &= ~0x1; mmio_write_32(0xf7032000 + 0x030, data); } else { data = mmio_read_32(0xf7032000 + 0x010); data &= ~0x1; mmio_write_32(0xf7032000 + 0x010, data); data = mmio_read_32(0xf7032000 + 0x030); data &= ~0x1; mmio_write_32(0xf7032000 + 0x030, data); } dsb(); isb(); /* * Test memory access. Do not use address 0x0 because the compiler * may assume it is not a valid address and generate incorrect code * (GCC 4.9.1 without -fno-delete-null-pointer-checks for instance). */ mmio_write_32(0x4, 0xa5a55a5a); INFO("ddr test value:0x%x\n", mmio_read_32(0x4)); init_ddrc_qos(); } trusted-firmware-a-2.2/plat/hisilicon/hikey/hikey_image_load.c000066400000000000000000000022561355360272700245660ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /******************************************************************************* * This function flushes the data structures so that they are visible * in memory for the next BL image. ******************************************************************************/ void plat_flush_next_bl_params(void) { flush_bl_params_desc(); } /******************************************************************************* * This function returns the list of loadable images. ******************************************************************************/ bl_load_info_t *plat_get_bl_image_load_info(void) { return get_bl_load_info_from_mem_params_desc(); } /******************************************************************************* * This function returns the list of executable images. ******************************************************************************/ bl_params_t *plat_get_next_bl_params(void) { return get_next_bl_params_from_mem_params_desc(); } trusted-firmware-a-2.2/plat/hisilicon/hikey/hikey_io_storage.c000066400000000000000000000156361355360272700246460ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hikey_private.h" #define EMMC_BLOCK_SHIFT 9 /* Page 1024, since only a few pages before 2048 are used as partition table */ #define SERIALNO_EMMC_OFFSET (1024 * 512) struct plat_io_policy { uintptr_t *dev_handle; uintptr_t image_spec; int (*check)(const uintptr_t spec); }; static const io_dev_connector_t *emmc_dev_con; static uintptr_t emmc_dev_handle; static const io_dev_connector_t *fip_dev_con; static uintptr_t fip_dev_handle; static int check_emmc(const uintptr_t spec); static int check_fip(const uintptr_t spec); static io_block_spec_t emmc_fip_spec; static const io_block_spec_t emmc_gpt_spec = { .offset = 0, .length = PLAT_PARTITION_BLOCK_SIZE * (PLAT_PARTITION_MAX_ENTRIES / 4 + 2), }; static const io_block_dev_spec_t emmc_dev_spec = { /* It's used as temp buffer in block driver. */ #ifdef IMAGE_BL1 .buffer = { .offset = HIKEY_BL1_MMC_DATA_BASE, .length = HIKEY_BL1_MMC_DATA_SIZE, }, #else .buffer = { .offset = HIKEY_MMC_DATA_BASE, .length = HIKEY_MMC_DATA_SIZE, }, #endif .ops = { .read = mmc_read_blocks, .write = mmc_write_blocks, }, .block_size = MMC_BLOCK_SIZE, }; static const io_uuid_spec_t bl31_uuid_spec = { .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31, }; static const io_uuid_spec_t bl32_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32, }; static const io_uuid_spec_t bl32_extra1_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1, }; static const io_uuid_spec_t bl32_extra2_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2, }; static const io_uuid_spec_t bl33_uuid_spec = { .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33, }; static const io_uuid_spec_t scp_bl2_uuid_spec = { .uuid = UUID_SCP_FIRMWARE_SCP_BL2, }; #if TRUSTED_BOARD_BOOT static const io_uuid_spec_t trusted_key_cert_uuid_spec = { .uuid = UUID_TRUSTED_KEY_CERT, }; static const io_uuid_spec_t scp_fw_key_cert_uuid_spec = { .uuid = UUID_SCP_FW_KEY_CERT, }; static const io_uuid_spec_t soc_fw_key_cert_uuid_spec = { .uuid = UUID_SOC_FW_KEY_CERT, }; static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = { .uuid = UUID_TRUSTED_OS_FW_KEY_CERT, }; static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = { .uuid = UUID_NON_TRUSTED_FW_KEY_CERT, }; static const io_uuid_spec_t scp_fw_cert_uuid_spec = { .uuid = UUID_SCP_FW_CONTENT_CERT, }; static const io_uuid_spec_t soc_fw_cert_uuid_spec = { .uuid = UUID_SOC_FW_CONTENT_CERT, }; static const io_uuid_spec_t tos_fw_cert_uuid_spec = { .uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT, }; static const io_uuid_spec_t nt_fw_cert_uuid_spec = { .uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT, }; #endif /* TRUSTED_BOARD_BOOT */ static const struct plat_io_policy policies[] = { [FIP_IMAGE_ID] = { &emmc_dev_handle, (uintptr_t)&emmc_fip_spec, check_emmc }, [SCP_BL2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&scp_bl2_uuid_spec, check_fip }, [BL31_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl31_uuid_spec, check_fip }, [BL32_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_uuid_spec, check_fip }, [BL32_EXTRA1_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_extra1_uuid_spec, check_fip }, [BL32_EXTRA2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_extra2_uuid_spec, check_fip }, [BL33_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl33_uuid_spec, check_fip }, #if TRUSTED_BOARD_BOOT [TRUSTED_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&trusted_key_cert_uuid_spec, check_fip }, [SCP_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&scp_fw_key_cert_uuid_spec, check_fip }, [SOC_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&soc_fw_key_cert_uuid_spec, check_fip }, [TRUSTED_OS_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&tos_fw_key_cert_uuid_spec, check_fip }, [NON_TRUSTED_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&nt_fw_key_cert_uuid_spec, check_fip }, [SCP_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&scp_fw_cert_uuid_spec, check_fip }, [SOC_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&soc_fw_cert_uuid_spec, check_fip }, [TRUSTED_OS_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&tos_fw_cert_uuid_spec, check_fip }, [NON_TRUSTED_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&nt_fw_cert_uuid_spec, check_fip }, #endif /* TRUSTED_BOARD_BOOT */ [GPT_IMAGE_ID] = { &emmc_dev_handle, (uintptr_t)&emmc_gpt_spec, check_emmc }, }; static int check_emmc(const uintptr_t spec) { int result; uintptr_t local_handle; result = io_dev_init(emmc_dev_handle, (uintptr_t)NULL); if (result == 0) { result = io_open(emmc_dev_handle, spec, &local_handle); if (result == 0) io_close(local_handle); } return result; } static int check_fip(const uintptr_t spec) { int result; uintptr_t local_image_handle; /* See if a Firmware Image Package is available */ result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); if (result == 0) { result = io_open(fip_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using FIP\n"); io_close(local_image_handle); } } return result; } void hikey_io_setup(void) { int result; result = register_io_dev_block(&emmc_dev_con); assert(result == 0); result = register_io_dev_fip(&fip_dev_con); assert(result == 0); result = io_dev_open(emmc_dev_con, (uintptr_t)&emmc_dev_spec, &emmc_dev_handle); assert(result == 0); result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle); assert(result == 0); /* Ignore improbable errors in release builds */ (void)result; } int hikey_set_fip_addr(unsigned int image_id, const char *name) { const partition_entry_t *entry; if (emmc_fip_spec.length == 0) { partition_init(GPT_IMAGE_ID); entry = get_partition_entry(name); if (entry == NULL) { ERROR("Could NOT find the %s partition!\n", name); return -ENOENT; } emmc_fip_spec.offset = entry->start; emmc_fip_spec.length = entry->length; } return 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 result; const struct plat_io_policy *policy; assert(image_id < ARRAY_SIZE(policies)); policy = &policies[image_id]; result = policy->check(policy->image_spec); assert(result == 0); *image_spec = policy->image_spec; *dev_handle = *(policy->dev_handle); return result; } trusted-firmware-a-2.2/plat/hisilicon/hikey/hikey_pm.c000066400000000000000000000170321355360272700231170ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define CORE_PWR_STATE(state) \ ((state)->pwr_domain_state[MPIDR_AFFLVL0]) #define CLUSTER_PWR_STATE(state) \ ((state)->pwr_domain_state[MPIDR_AFFLVL1]) #define SYSTEM_PWR_STATE(state) \ ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) static uintptr_t hikey_sec_entrypoint; static int hikey_pwr_domain_on(u_register_t mpidr) { int cpu, cluster; int curr_cluster; cluster = MPIDR_AFFLVL1_VAL(mpidr); cpu = MPIDR_AFFLVL0_VAL(mpidr); curr_cluster = MPIDR_AFFLVL1_VAL(read_mpidr()); if (cluster != curr_cluster) hisi_ipc_cluster_on(cpu, cluster); hisi_pwrc_set_core_bx_addr(cpu, cluster, hikey_sec_entrypoint); hisi_pwrc_enable_debug(cpu, cluster); hisi_ipc_cpu_on(cpu, cluster); return 0; } static void hikey_pwr_domain_on_finish(const psci_power_state_t *target_state) { unsigned long mpidr; int cpu, cluster; mpidr = read_mpidr(); cluster = MPIDR_AFFLVL1_VAL(mpidr); cpu = MPIDR_AFFLVL0_VAL(mpidr); /* * Enable CCI coherency for this cluster. * No need for locks as no other cpu is active at the moment. */ if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); /* Zero the jump address in the mailbox for this cpu */ hisi_pwrc_set_core_bx_addr(cpu, cluster, 0); /* Program the GIC per-cpu distributor or re-distributor interface */ gicv2_pcpu_distif_init(); /* Enable the GIC cpu interface */ gicv2_cpuif_enable(); } void hikey_pwr_domain_off(const psci_power_state_t *target_state) { unsigned long mpidr; int cpu, cluster; mpidr = read_mpidr(); cluster = MPIDR_AFFLVL1_VAL(mpidr); cpu = MPIDR_AFFLVL0_VAL(mpidr); gicv2_cpuif_disable(); hisi_ipc_cpu_off(cpu, cluster); if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); hisi_ipc_cluster_off(cpu, cluster); } } static void hikey_pwr_domain_suspend(const psci_power_state_t *target_state) { u_register_t mpidr = read_mpidr_el1(); unsigned int cpu = mpidr & MPIDR_CPU_MASK; unsigned int cluster = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS; if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) return; if (CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { /* Program the jump address for the target cpu */ hisi_pwrc_set_core_bx_addr(cpu, cluster, hikey_sec_entrypoint); gicv2_cpuif_disable(); if (SYSTEM_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) hisi_ipc_cpu_suspend(cpu, cluster); } /* Perform the common cluster specific operations */ if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { hisi_pwrc_set_cluster_wfi(1); hisi_pwrc_set_cluster_wfi(0); hisi_ipc_psci_system_off(); } else hisi_ipc_cluster_suspend(cpu, cluster); } } static void hikey_pwr_domain_suspend_finish(const psci_power_state_t *target_state) { unsigned long mpidr; unsigned int cluster, cpu; /* Nothing to be done on waking up from retention from CPU level */ if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) return; /* Get the mpidr for this cpu */ mpidr = read_mpidr_el1(); cluster = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFF1_SHIFT; cpu = mpidr & MPIDR_CPU_MASK; /* Enable CCI coherency for cluster */ if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); hisi_pwrc_set_core_bx_addr(cpu, cluster, 0); if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } else { gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } } static void hikey_get_sys_suspend_power_state(psci_power_state_t *req_state) { int i; for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; } static void __dead2 hikey_system_off(void) { NOTICE("%s: off system\n", __func__); /* Pull down GPIO_0_0 to trigger PMIC shutdown */ mmio_write_32(0xF8001810, 0x2); /* Pinmux */ mmio_write_8(0xF8011400, 1); /* Pin direction */ mmio_write_8(0xF8011004, 0); /* Pin output value */ /* Wait for 2s to power off system by PMIC */ sp804_timer_init(SP804_TIMER0_BASE, 10, 192); mdelay(2000); /* * PMIC shutdown depends on two conditions: GPIO_0_0 (PWR_HOLD) low, * and VBUS_DET < 3.6V. For HiKey, VBUS_DET is connected to VDD_4V2 * through Jumper 1-2. So, to complete shutdown, user needs to manually * remove Jumper 1-2. */ NOTICE("+------------------------------------------+\n"); NOTICE("| IMPORTANT: Remove Jumper 1-2 to shutdown |\n"); NOTICE("| DANGER: SoC is still burning. DANGER! |\n"); NOTICE("| Board will be reboot to avoid overheat |\n"); NOTICE("+------------------------------------------+\n"); /* Send the system reset request */ mmio_write_32(AO_SC_SYS_STAT0, 0x48698284); wfi(); panic(); } static void __dead2 hikey_system_reset(void) { /* Send the system reset request */ mmio_write_32(AO_SC_SYS_STAT0, 0x48698284); isb(); dsb(); wfi(); panic(); } int hikey_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { int pstate = psci_get_pstate_type(power_state); int pwr_lvl = psci_get_pstate_pwrlvl(power_state); int i; assert(req_state); if (pwr_lvl > PLAT_MAX_PWR_LVL) return PSCI_E_INVALID_PARAMS; /* Sanity check the requested state */ if (pstate == PSTATE_TYPE_STANDBY) { /* * It's possible to enter standby only on power level 0 * Ignore any other power level. */ if (pwr_lvl != MPIDR_AFFLVL0) return PSCI_E_INVALID_PARAMS; req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE; } else { for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++) req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; } /* * We expect the 'state id' to be zero. */ if (psci_get_pstate_id(power_state)) return PSCI_E_INVALID_PARAMS; return PSCI_E_SUCCESS; } static int hikey_validate_ns_entrypoint(uintptr_t entrypoint) { /* * Check if the non secure entrypoint lies within the non * secure DRAM. */ if ((entrypoint > DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE))) return PSCI_E_SUCCESS; return PSCI_E_INVALID_ADDRESS; } static const plat_psci_ops_t hikey_psci_ops = { .cpu_standby = NULL, .pwr_domain_on = hikey_pwr_domain_on, .pwr_domain_on_finish = hikey_pwr_domain_on_finish, .pwr_domain_off = hikey_pwr_domain_off, .pwr_domain_suspend = hikey_pwr_domain_suspend, .pwr_domain_suspend_finish = hikey_pwr_domain_suspend_finish, .system_off = hikey_system_off, .system_reset = hikey_system_reset, .validate_power_state = hikey_validate_power_state, .validate_ns_entrypoint = hikey_validate_ns_entrypoint, .get_sys_suspend_power_state = hikey_get_sys_suspend_power_state, }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { hikey_sec_entrypoint = sec_entrypoint; /* * Initialize PSCI ops struct */ *psci_ops = &hikey_psci_ops; return 0; } trusted-firmware-a-2.2/plat/hisilicon/hikey/hikey_private.h000066400000000000000000000036061355360272700241640ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HIKEY_PRIVATE_H #define HIKEY_PRIVATE_H #include #define RANDOM_MAX 0x7fffffffffffffff #define RANDOM_MAGIC 0x9a4dbeaf enum { DDR_FREQ_150M = 150 * 1000, DDR_FREQ_266M = 266 * 1000, DDR_FREQ_400M = 400 * 1000, DDR_FREQ_533M = 533 * 1000, DDR_FREQ_800M = 800 * 1000 }; struct random_serial_num { uint64_t magic; uint64_t data; char serialno[32]; }; /* * Function and variable prototypes */ void hikey_init_mmu_el1(unsigned long total_base, unsigned long total_size, unsigned long ro_start, unsigned long ro_limit, unsigned long coh_start, unsigned long coh_limit); void hikey_init_mmu_el3(unsigned long total_base, unsigned long total_size, unsigned long ro_start, unsigned long ro_limit, unsigned long coh_start, unsigned long coh_limit); void hikey_ddr_init(unsigned int ddr_freq); void hikey_io_setup(void); void hikey_sp804_init(void); void hikey_gpio_init(void); void hikey_pmussi_init(void); void hikey_hi6553_init(void); void init_mmc0_pll(void); void reset_mmc0_clk(void); void init_media_clk(void); void init_mmc1_pll(void); void reset_mmc1_clk(void); void hikey_mmc_pll_init(void); void hikey_rtc_init(void); int hikey_get_partition_size(const char *arg, int left, char *response); int hikey_get_partition_type(const char *arg, int left, char *response); int hikey_erase(const char *arg); int hikey_flash(const char *arg); int hikey_oem(const char *arg); int hikey_reboot(const char *arg); void hikey_security_setup(void); const char *hikey_init_serialno(void); int hikey_read_serialno(struct random_serial_num *serialno); int hikey_write_serialno(struct random_serial_num *serialno); void init_acpu_dvfs(void); int hikey_set_fip_addr(unsigned int image_id, const char *name); #endif /* HIKEY_PRIVATE_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey/hikey_rotpk.S000066400000000000000000000006701355360272700236220ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ .global hikey_rotpk_hash .global hikey_rotpk_hash_end .section .rodata.hikey_rotpk_hash, "a" hikey_rotpk_hash: /* DER header */ .byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48 .byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 /* SHA256 */ .incbin ROTPK_HASH hikey_rotpk_hash_end: trusted-firmware-a-2.2/plat/hisilicon/hikey/hikey_security.c000066400000000000000000000054241355360272700243540ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "hikey_private.h" #define PORTNUM_MAX 5 #define MDDRC_SECURITY_BASE 0xF7121000 struct int_en_reg { unsigned in_en:1; unsigned reserved:31; }; struct rgn_map_reg { unsigned rgn_base_addr:24; unsigned rgn_size:6; unsigned reserved:1; unsigned rgn_en:1; }; struct rgn_attr_reg { unsigned sp:4; unsigned security_inv:1; unsigned reserved_0:3; unsigned mid_en:1; unsigned mid_inv:1; unsigned reserved_1:6; unsigned rgn_en:1; unsigned subrgn_disable:16; }; static volatile struct int_en_reg *get_int_en_reg(uint32_t base) { uint64_t addr = base + 0x20; return (struct int_en_reg *)addr; } static volatile struct rgn_map_reg *get_rgn_map_reg(uint32_t base, int region, int port) { uint64_t addr = base + 0x100 + 0x10 * region + 0x400 * (uint64_t)port; return (struct rgn_map_reg *)addr; } static volatile struct rgn_attr_reg *get_rgn_attr_reg(uint32_t base, int region, int port) { uint64_t addr = base + 0x104 + 0x10 * region + 0x400 * (uint64_t)port; return (struct rgn_attr_reg *)addr; } /* * Configure secure memory region * region_size must be a power of 2 and at least 64KB * region_base must be region_size aligned */ static void sec_protect(uint32_t region_base, uint32_t region_size, int region) { volatile struct int_en_reg *int_en; volatile struct rgn_map_reg *rgn_map; volatile struct rgn_attr_reg *rgn_attr; uint32_t i = 0; /* ensure secure region number is between 1-15 */ assert(region > 0 && region < 16); /* ensure secure region size is a power of 2 >= 64KB */ assert(IS_POWER_OF_TWO(region_size) && region_size >= 0x10000); /* ensure secure region address is aligned to region size */ assert(!(region_base & (region_size - 1))); INFO("BL2: TrustZone: protecting %u bytes of memory at 0x%x\n", region_size, region_base); int_en = get_int_en_reg(MDDRC_SECURITY_BASE); int_en->in_en = 0x1; for (i = 0; i < PORTNUM_MAX; i++) { rgn_map = get_rgn_map_reg(MDDRC_SECURITY_BASE, region, i); rgn_attr = get_rgn_attr_reg(MDDRC_SECURITY_BASE, region, i); rgn_map->rgn_base_addr = region_base >> 16; rgn_attr->subrgn_disable = 0x0; rgn_attr->sp = (i == 3) ? 0xC : 0x0; rgn_map->rgn_size = __builtin_ffs(region_size) - 2; rgn_map->rgn_en = 0x1; } } /******************************************************************************* * Initialize the secure environment. ******************************************************************************/ void hikey_security_setup(void) { sec_protect(DDR_SEC_BASE, DDR_SEC_SIZE, 1); sec_protect(DDR_SDP_BASE, DDR_SDP_SIZE, 2); } trusted-firmware-a-2.2/plat/hisilicon/hikey/hikey_tbbr.c000066400000000000000000000013311355360272700234270ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include extern char hikey_rotpk_hash[], hikey_rotpk_hash_end[]; int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, unsigned int *flags) { *key_ptr = hikey_rotpk_hash; *key_len = hikey_rotpk_hash_end - hikey_rotpk_hash; *flags = ROTPK_IS_HASH; return 0; } int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr) { *nv_ctr = 0; return 0; } int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr) { return 1; } int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size) { return get_mbedtls_heap_helper(heap_addr, heap_size); } trusted-firmware-a-2.2/plat/hisilicon/hikey/hikey_topology.c000066400000000000000000000041411355360272700243540ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /* * The HiKey power domain tree descriptor. The cluster power domains * are arranged so that when the PSCI generic code creates the power * domain tree, the indices of the CPU power domain nodes it allocates * match the linear indices returned by plat_core_pos_by_mpidr(). */ const unsigned char hikey_power_domain_tree_desc[] = { /* Number of root nodes */ 1, /* Number of clusters */ PLATFORM_CLUSTER_COUNT, /* Number of children for the first cluster node */ PLATFORM_CORE_COUNT_PER_CLUSTER, /* Number of children for the second cluster node */ PLATFORM_CORE_COUNT_PER_CLUSTER, }; /******************************************************************************* * This function returns the HiKey topology tree information. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { return hikey_power_domain_tree_desc; } /******************************************************************************* * This function implements a part of the critical interface between the psci * generic layer and the platform that allows the former to query the platform * to convert an MPIDR to a unique linear index. An error code (-1) is returned * in case the MPIDR is invalid. ******************************************************************************/ int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; mpidr &= MPIDR_AFFINITY_MASK; if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) return -1; cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; if (cluster_id >= PLATFORM_CLUSTER_COUNT) return -1; /* * Validate cpu_id by checking whether it represents a CPU in * one of the two clusters present on the platform. */ if (cpu_id >= PLATFORM_CORE_COUNT_PER_CLUSTER) return -1; return (cpu_id + (cluster_id * 4)); } trusted-firmware-a-2.2/plat/hisilicon/hikey/hisi_dvfs.c000066400000000000000000000530471355360272700232760ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #define ACPU_FREQ_MAX_NUM 5 #define ACPU_OPP_NUM 7 #define ACPU_VALID_VOLTAGE_MAGIC (0x5A5AC5C5) #define ACPU_WAIT_TIMEOUT (200) #define ACPU_WAIT_FOR_WFI_TIMOUT (2000) #define ACPU_DFS_STATE_CNT (0x10000) struct acpu_dvfs_sram_stru { unsigned int magic; unsigned int support_freq_num; unsigned int support_freq_max; unsigned int start_prof; unsigned int vol[ACPU_OPP_NUM]; }; struct acpu_volt_cal_para { unsigned int freq; unsigned int ul_vol; unsigned int dl_vol; unsigned int core_ref_hpm; }; struct ddr_volt_cal_para { unsigned int freq; unsigned int ul_vol; unsigned int dl_vol; unsigned int ddr_ref_hpm; }; struct acpu_dvfs_opp_para { unsigned int freq; unsigned int acpu_clk_profile0; unsigned int acpu_clk_profile1; unsigned int acpu_vol_profile; unsigned int acpu_pll_freq; unsigned int acpu_pll_frac; }; unsigned int efuse_acpu_freq[] = { 1200000, 1250000, 1300000, 1350000, 1400000, 1450000, 1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000, 1900000, 1950000, }; struct acpu_dvfs_opp_para hi6220_acpu_profile[] = { { 208000, 0x61E5, 0x022, 0x3A, 0x5220102B, 0x05555555 }, { 432000, 0x10A6, 0x121, 0x3A, 0x5120102D, 0x10000005 }, { 729000, 0x2283, 0x100, 0x4A, 0x51101026, 0x10000005 }, { 960000, 0x1211, 0x100, 0x5B, 0x51101032, 0x10000005 }, { 1200000, 0x1211, 0x100, 0x6B, 0x5110207D, 0x10000005 }, { 1400000, 0x1211, 0x100, 0x6B, 0x51101049, 0x10000005 }, { 1500000, 0x1211, 0x100, 0x6B, 0x51101049, 0x10000005 }, }; struct acpu_dvfs_opp_para *acpu_dvfs_profile = hi6220_acpu_profile; struct acpu_dvfs_sram_stru *acpu_dvfs_sram_buf = (struct acpu_dvfs_sram_stru *)MEMORY_AXI_ACPU_FREQ_VOL_ADDR; static inline void write_reg_mask(uintptr_t addr, uint32_t val, uint32_t mask) { uint32_t reg; reg = mmio_read_32(addr); reg = (reg & ~(mask)) | val; mmio_write_32(addr, reg); } static inline uint32_t read_reg_mask(uintptr_t addr, uint32_t mask, uint32_t offset) { uint32_t reg; reg = mmio_read_32(addr); reg &= (mask << offset); return (reg >> offset); } static int acpu_dvfs_syspll_cfg(unsigned int prof_id) { uint32_t reg0 = 0; uint32_t count = 0; uint32_t clk_div_status = 0; /* * step 1: * - ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x3; * - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x1; */ write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x3 << 12, 0x3 << 12); write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x1 << 4, 0x1 << 4); /* * step 2: * - ACPUSYSPLLCFG.acpu_syspll_div_cfg: * 208MHz, set to 0x5; * 500MHz, set to 0x2; * other opps set to 0x1 */ if (prof_id == 0) write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x5 << 0, 0x7 << 0); else if (prof_id == 1) write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x2 << 0, 0x7 << 0); else write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x1 << 0, 0x7 << 0); /* * step 3: * - Polling ACPU_SC_CPU_STAT.clk_div_status_vd == 0x3; * - ACPU_SC_VD_CTRL.tune_en_dif = 0 * - ACPU_SC_VD_CTRL.tune_en_int = 0 * - PMCTRL_ACPUCLKDIV.acpu_ddr_clk_div_cfg = 0x1 * - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x1 */ clk_div_status = 0x3; do { reg0 = read_reg_mask(ACPU_SC_CPU_STAT, 0x3, 20); if ((count++) > ACPU_DFS_STATE_CNT) { ERROR("%s: clk div status timeout!\n", __func__); return -1; } } while (clk_div_status != reg0); write_reg_mask(ACPU_SC_VD_CTRL, 0x0, (0x1 << 0) | (0x1 << 11)); write_reg_mask(PMCTRL_ACPUCLKDIV, 0x1 << 8, 0x3 << 8); write_reg_mask(PMCTRL_ACPUPLLSEL, 0x1 << 0, 0x1 << 0); return 0; } static void acpu_dvfs_clk_div_cfg(unsigned int prof_id, unsigned int *cpuext_cfg, unsigned int *acpu_ddr_cfg) { if (prof_id == 0) { write_reg_mask(PMCTRL_ACPUCLKDIV, (0x1 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) | (0x1 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START), (0x3 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) | (0x3 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START)); *cpuext_cfg = 0x1; *acpu_ddr_cfg = 0x1; } else if (prof_id == 1) { write_reg_mask(PMCTRL_ACPUCLKDIV, (0x1 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) | (0x1 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START), (0x3 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) | (0x3 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START)); *cpuext_cfg = 0x1; *acpu_ddr_cfg = 0x1; } else { /* ddr has not been inited */ write_reg_mask(PMCTRL_ACPUCLKDIV, (0x1 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) | (0x0 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START), (0x3 << SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START) | (0x3 << SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START)); *cpuext_cfg = 0x1; *acpu_ddr_cfg = 0x0; } } static int acpu_dvfs_freq_ascend(unsigned int cur_prof, unsigned int tar_prof) { unsigned int reg0 = 0; unsigned int reg1 = 0; unsigned int reg2 = 0; unsigned int count = 0; unsigned int cpuext_cfg_val = 0; unsigned int acpu_ddr_cfg_val = 0; int ret = 0; /* * step 1: * - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x3; * - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x1; * * step 2: * - PMCTRL_ACPUSYSPLLCFG.acpu_syspll_div_cfg = 0x5 (208MHz) * - PMCTRL_ACPUSYSPLLCFG.acpu_syspll_div_cfg = 0x2 (500MHz) * - PMCTRL_ACPUSYSPLLCFG.acpu_syspll_div_cfg = 0x1 (Other OPPs) * * step 3: * - ACPU_SC_CPU_STAT.clk_div_status_vd = 0x3; * - ACPU_SC_VD_CTRL.tune_en_dif = 0x0; * - ACPU_SC_VD_CTRL.tune_en_int = 0x0; * - PMCTRL_ACPUCLKDIV.acpu_ddr_clk_div_cfg = 0x1; * - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x1 */ ret = acpu_dvfs_syspll_cfg(cur_prof); if (ret) return -1; /* * step 4: * - Polling PMCTRL_ACPUPLLSEL.syspll_sw_stat == 0x1 */ count = 0; do { reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1, SOC_PMCTRL_ACPUPLLSEL_syspll_sw_stat_START); if ((count++) > ACPU_DFS_STATE_CNT) { ERROR("%s: syspll sw status timeout\n", __func__); return -1; } } while (reg0 != 0x1); /* Enable VD functionality if > 800MHz */ if (acpu_dvfs_profile[tar_prof].freq > 800000) { write_reg_mask(ACPU_SC_VD_HPM_CTRL, HPM_OSC_DIV_VAL, HPM_OSC_DIV_MASK); /* * step 5: * - ACPU_SC_VD_HPM_CTRL.hpm_dly_exp = 0xC7A; * - ACPU_SC_VD_MASK_PATTERN_CTRL[12:0] = 0xCCB; */ write_reg_mask(ACPU_SC_VD_HPM_CTRL, HPM_DLY_EXP_VAL, HPM_DLY_EXP_MASK); write_reg_mask(ACPU_SC_VD_MASK_PATTERN_CTRL, ACPU_SC_VD_MASK_PATTERN_VAL, ACPU_SC_VD_MASK_PATTERN_MASK); /* * step 6: * - ACPU_SC_VD_DLY_TABLE0_CTRL = 0x1FFF; * - ACPU_SC_VD_DLY_TABLE1_CTRL = 0x1FFFFFF; * - ACPU_SC_VD_DLY_TABLE2_CTRL = 0x7FFFFFFF; * - ACPU_SC_VD_DLY_FIXED_CTRL = 0x1; */ mmio_write_32(ACPU_SC_VD_DLY_TABLE0_CTRL, 0x1FFF); mmio_write_32(ACPU_SC_VD_DLY_TABLE1_CTRL, 0x1FFFFFF); mmio_write_32(ACPU_SC_VD_DLY_TABLE2_CTRL, 0x7FFFFFFF); mmio_write_32(ACPU_SC_VD_DLY_FIXED_CTRL, 0x1); /* * step 7: * - ACPU_SC_VD_CTRL.shift_table0 = 0x1; * - ACPU_SC_VD_CTRL.shift_table1 = 0x3; * - ACPU_SC_VD_CTRL.shift_table2 = 0x5; * - ACPU_SC_VD_CTRL.shift_table3 = 0x6; * * step 8: * - ACPU_SC_VD_CTRL.tune = 0x7; */ write_reg_mask(ACPU_SC_VD_CTRL, ACPU_SC_VD_SHIFT_TABLE_TUNE_VAL, ACPU_SC_VD_SHIFT_TABLE_TUNE_MASK); } /* step 9: ACPUPLLCTRL.acpupll_en_cfg = 0x0 */ write_reg_mask(PMCTRL_ACPUPLLCTRL, 0x0, 0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START); /* step 10: set PMCTRL_ACPUPLLFREQ and PMCTRL_ACPUPLLFRAC */ mmio_write_32(PMCTRL_ACPUPLLFREQ, acpu_dvfs_profile[tar_prof].acpu_pll_freq); mmio_write_32(PMCTRL_ACPUPLLFRAC, acpu_dvfs_profile[tar_prof].acpu_pll_frac); /* * step 11: * - wait for 1us; * - PMCTRL_ACPUPLLCTRL.acpupll_en_cfg = 0x1 */ count = 0; while (count < ACPU_WAIT_TIMEOUT) count++; write_reg_mask(PMCTRL_ACPUPLLCTRL, 0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START, 0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START); /* step 12: PMCTRL_ACPUVOLPMUADDR = 0x100da */ mmio_write_32(PMCTRL_ACPUVOLPMUADDR, 0x100da); /* * step 13: * - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x13 (208MHz); * - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x13 (500MHz); * - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x20 (798MHz); * - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x3A (1300MHz); * - PMCTRL_ACPUDESTVOL.acpu_dest_vol = 0x3A (1500MHz); */ write_reg_mask(PMCTRL_ACPUDESTVOL, acpu_dvfs_profile[tar_prof].acpu_vol_profile, ((0x1 << (SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_END + 1)) - 1)); /* * step 14: * - Polling PMCTRL_ACPUDESTVOL.acpu_vol_using == ACPUDESTVOL.acpu_dest_vol * - Polling ACPUVOLTIMEOUT.acpu_vol_timeout == 0x1 * - Config PMCTRL_ACPUCLKDIV.acpu_ddr_clk_div_cfg * - Config ACPUCLKDIV.cpuext_clk_div_cfg; */ count = 0; do { reg0 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F, SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_START); reg1 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F, SOC_PMCTRL_ACPUDESTVOL_acpu_vol_using_START); reg2 = read_reg_mask(PMCTRL_ACPUVOLTTIMEOUT, 0x1, SOC_PMCTRL_ACPUVOLTIMEOUT_acpu_vol_timeout_START); if ((count++) > ACPU_DFS_STATE_CNT) { ERROR("%s: acpu destvol cfg timeout.\n", __func__); return -1; } } while ((reg0 != reg1) || (reg2 != 0x1)); acpu_dvfs_clk_div_cfg(tar_prof, &cpuext_cfg_val, &acpu_ddr_cfg_val); /* * step 15: * - Polling PMCTRL_ACPUCLKDIV.cpuext_clk_div_stat; * - Polling ACPUCLKDIV.acpu_ddr_clk_div_stat; * - ACPUPLLCTRL.acpupll_timeout = 0x1; * - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x0; */ count = 0; do { reg0 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3, SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_stat_START); reg1 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3, SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_stat_START); reg2 = read_reg_mask(PMCTRL_ACPUPLLCTRL, 0x1, SOC_PMCTRL_ACPUPLLCTRL_acpupll_timeout_START); if ((count++) > ACPU_DFS_STATE_CNT) { ERROR("%s: acpu clk div cfg timeout.\n", __func__); return -1; } } while ((reg1 != cpuext_cfg_val) || (reg0 != acpu_ddr_cfg_val) || (reg2 != 0x1)); write_reg_mask(PMCTRL_ACPUPLLSEL, 0x0, 0x1 << SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_cfg_START); /* * step 16: * - Polling PMCTRL_ACPUPLLSEL.acpupll_sw_stat == 0x1; * - ACPU_SC_VD_CTRL.force_clk_en = 0x0; * - ACPU_SC_VD_CTRL.clk_dis_cnt_en = 0x0; * - ACPU_SC_VD_CTRL.calibrate_en_ini = 0x0; * - ACPU_SC_VD_CTRL.calibrate_en_dif = 0x0; * - ACPU_SC_VD_CTRL.div_en_dif = 0x1; * - ACPU_SC_VD_CTRL.tune_en_int = 0x1; * - ACPU_SC_VD_CTRL.tune_en_dif = 0x1; * - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x0; * - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x0; */ count = 0; do { reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1, SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_stat_START); if ((count++) > ACPU_DFS_STATE_CNT) { ERROR("%s: acpu pll sw status timeout.\n", __func__); return -1; } } while (reg0 != 0x1); if (acpu_dvfs_profile[tar_prof].freq > 800000) write_reg_mask(ACPU_SC_VD_CTRL, ACPU_SC_VD_EN_ASIC_VAL, ACPU_SC_VD_EN_MASK); write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x0, (0x3 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_subsys_clk_div_sw_START) | (0x1 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_cfg_START)); return 0; } static int acpu_dvfs_freq_descend(unsigned int cur_prof, unsigned int tar_prof) { unsigned int reg0 = 0; unsigned int reg1 = 0; unsigned int reg2 = 0; unsigned int count = 0; unsigned int cpuext_cfg_val = 0; unsigned int acpu_ddr_cfg_val = 0; int ret = 0; ret = acpu_dvfs_syspll_cfg(tar_prof); if (ret) return -1; /* * step 4: * - Polling PMCTRL_ACPUPLLSEL.syspll_sw_stat == 0x1 */ count = 0; do { reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1, 2); if ((count++) > ACPU_DFS_STATE_CNT) { ERROR("%s: syspll sw status timeout.\n", __func__); return -1; } } while (reg0 != 0x1); /* * Step 5: * - PMCTRL_ACPUPLLCTRL.acpupll_en_cfg = 0x0 */ write_reg_mask(PMCTRL_ACPUPLLCTRL, 0x0, 0x1 << 0); /* * step 6 * - Config PMCTRL_ACPUPLLFREQ and ACPUPLLFRAC */ mmio_write_32(PMCTRL_ACPUPLLFREQ, acpu_dvfs_profile[tar_prof].acpu_pll_freq); mmio_write_32(PMCTRL_ACPUPLLFRAC, acpu_dvfs_profile[tar_prof].acpu_pll_frac); /* * step 7: * - Wait 1us; * - Config PMCTRL_ACPUPLLCTRL.acpupll_en_cfg = 0x1 */ count = 0; while (count < ACPU_WAIT_TIMEOUT) count++; write_reg_mask(PMCTRL_ACPUPLLCTRL, 0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START, 0x1 << SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START); /* Enable VD functionality if > 800MHz */ if (acpu_dvfs_profile[tar_prof].freq > 800000) { write_reg_mask(ACPU_SC_VD_HPM_CTRL, HPM_OSC_DIV_VAL, HPM_OSC_DIV_MASK); /* * step 9: * - ACPU_SC_VD_HPM_CTRL.hpm_dly_exp = 0xC7A; * - ACPU_SC_VD_MASK_PATTERN_CTRL[12:0] = 0xCCB; */ write_reg_mask(ACPU_SC_VD_HPM_CTRL, HPM_DLY_EXP_VAL, HPM_DLY_EXP_MASK); write_reg_mask(ACPU_SC_VD_MASK_PATTERN_CTRL, ACPU_SC_VD_MASK_PATTERN_VAL, ACPU_SC_VD_MASK_PATTERN_MASK); /* * step 10: * - ACPU_SC_VD_DLY_TABLE0_CTRL = 0x1FFF; * - ACPU_SC_VD_DLY_TABLE1_CTRL = 0x1FFFFFF; * - ACPU_SC_VD_DLY_TABLE2_CTRL = 0x7FFFFFFF; * - ACPU_SC_VD_DLY_FIXED_CTRL = 0x1; */ mmio_write_32(ACPU_SC_VD_DLY_TABLE0_CTRL, 0x1FFF); mmio_write_32(ACPU_SC_VD_DLY_TABLE1_CTRL, 0x1FFFFFF); mmio_write_32(ACPU_SC_VD_DLY_TABLE2_CTRL, 0x7FFFFFFF); mmio_write_32(ACPU_SC_VD_DLY_FIXED_CTRL, 0x1); /* * step 11: * - ACPU_SC_VD_CTRL.shift_table0 = 0x1; * - ACPU_SC_VD_CTRL.shift_table1 = 0x3; * - ACPU_SC_VD_CTRL.shift_table2 = 0x5; * - ACPU_SC_VD_CTRL.shift_table3 = 0x6; * * step 12: * - ACPU_SC_VD_CTRL.tune = 0x7; */ write_reg_mask(ACPU_SC_VD_CTRL, ACPU_SC_VD_SHIFT_TABLE_TUNE_VAL, ACPU_SC_VD_SHIFT_TABLE_TUNE_MASK); } /* * step 13: * - Pollig PMCTRL_ACPUPLLCTRL.acpupll_timeout == 0x1; * - PMCTRL_ACPUPLLSEL.acpu_pllsw_cfg = 0x0; */ count = 0; do { reg0 = read_reg_mask(PMCTRL_ACPUPLLCTRL, 0x1, SOC_PMCTRL_ACPUPLLCTRL_acpupll_timeout_START); if ((count++) > ACPU_DFS_STATE_CNT) { ERROR("%s: acpupll timeout.\n", __func__); return -1; } } while (reg0 != 0x1); write_reg_mask(PMCTRL_ACPUPLLSEL, 0x0, 0x1 << SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_cfg_START); /* * step 14: * - Polling PMCTRL_ACPUPLLSEL.acpupll_sw_stat == 0x1; * - ACPU_SC_VD_CTRL.force_clk_en = 0x0; * - ACPU_SC_VD_CTRL.clk_dis_cnt_en = 0x0; * - ACPU_SC_VD_CTRL.calibrate_en_ini = 0x0; * - ACPU_SC_VD_CTRL.calibrate_en_dif = 0x0; * - ACPU_SC_VD_CTRL.div_en_dif = 0x1; * - ACPU_SC_VD_CTRL.tune_en_int = 0x1; * - ACPU_SC_VD_CTRL.tune_en_dif = 0x1; */ count = 0; do { reg0 = read_reg_mask(PMCTRL_ACPUPLLSEL, 0x1, SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_stat_START); if ((count++) > ACPU_DFS_STATE_CNT) { ERROR("%s: acpupll sw status timeout.\n", __func__); return -1; } } while (reg0 != 0x1); if (acpu_dvfs_profile[tar_prof].freq > 800000) write_reg_mask(ACPU_SC_VD_CTRL, ACPU_SC_VD_EN_ASIC_VAL, ACPU_SC_VD_EN_MASK); /* * step 15: * - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x0; * - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x0; */ write_reg_mask(PMCTRL_ACPUSYSPLLCFG, 0x0, (0x3 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_subsys_clk_div_sw_START) | (0x1 << SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_cfg_START)); /* * step 16: * - Polling ACPU_SC_CPU_STAT.clk_div_status_vd == 0x0; */ count = 0; do { reg0 = read_reg_mask(ACPU_SC_CPU_STAT, 0x3, ACPU_SC_CPU_STAT_CLK_DIV_STATUS_VD_SHIFT); if ((count++) > ACPU_DFS_STATE_CNT) { ERROR("%s: clk div status timeout.\n", __func__); return -1; } } while (reg0 != 0x0); acpu_dvfs_clk_div_cfg(tar_prof, &cpuext_cfg_val, &acpu_ddr_cfg_val); /* * step 17: * - Polling PMCTRL_ACPUCLKDIV.cpuext_clk_div_stat; * - Polling ACPUCLKDIV.acpu_ddr_clk_div_stat; * - PMCTRL_ACPUVOLPMUADDR = 0x1006C; */ count = 0; do { reg0 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3, SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_stat_START); reg1 = read_reg_mask(PMCTRL_ACPUCLKDIV, 0x3, SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_stat_START); if ((count++) > ACPU_DFS_STATE_CNT) { ERROR("%s: acpu clk div cfg timeout.\n", __func__); return -1; } } while ((reg0 != cpuext_cfg_val) || (reg1 != acpu_ddr_cfg_val)); mmio_write_32(PMCTRL_ACPUVOLPMUADDR, 0x100da); /* * step 16: * - Polling PMCTRL_ACPUPLLSEL.acpupll_sw_stat == 0x1; * - ACPU_SC_VD_CTRL.force_clk_en = 0x0; * - ACPU_SC_VD_CTRL.clk_dis_cnt_en = 0x0; * - ACPU_SC_VD_CTRL.calibrate_en_ini = 0x0; * - ACPU_SC_VD_CTRL.calibrate_en_dif = 0x0; * - ACPU_SC_VD_CTRL.div_en_dif = 0x1; * - ACPU_SC_VD_CTRL.tune_en_int = 0x1; * - ACPU_SC_VD_CTRL.tune_en_dif = 0x1; * - PMCTRL_ACPUSYSPLLCFG.acpu_subsys_clk_div_sw = 0x0; * - ACPUSYSPLLCFG.acpu_syspll_clken_cfg = 0x0; */ write_reg_mask(PMCTRL_ACPUDESTVOL, acpu_dvfs_profile[tar_prof].acpu_vol_profile, ((0x1 << (SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_END + 1)) - 1)); /* * step 19: * - Polling PMCTRL_ACPUDESTVOL.acpu_vol_using == ACPUDESTVOL.acpu_dest_vol * - ACPUVOLTIMEOUT.acpu_vol_timeout = 0x1; */ count = 0; do { reg0 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F, SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_START); reg1 = read_reg_mask(PMCTRL_ACPUDESTVOL, 0x7F, SOC_PMCTRL_ACPUDESTVOL_acpu_vol_using_START); reg2 = read_reg_mask(PMCTRL_ACPUVOLTTIMEOUT, 0x1, SOC_PMCTRL_ACPUVOLTIMEOUT_acpu_vol_timeout_START); if ((count++) > ACPU_DFS_STATE_CNT) { ERROR("%s: acpu destvol cfg timeout.\n", __func__); return -1; } } while ((reg0 != reg1) || (reg2 != 0x1)); return 0; } int acpu_dvfs_target(unsigned int curr_prof, unsigned int target_prof) { int ret = 0; if (curr_prof == target_prof) { INFO("%s: target_prof is equal curr_prof: is %d!\n", __func__, curr_prof); return 0; } if ((curr_prof >= ACPU_FREQ_MAX_NUM) || (target_prof >= ACPU_FREQ_MAX_NUM)) { INFO("%s: invalid parameter %d %d\n", __func__, curr_prof, target_prof); return -1; } if (target_prof > acpu_dvfs_sram_buf->support_freq_num) target_prof = acpu_dvfs_sram_buf->support_freq_num; if (target_prof < curr_prof) ret = acpu_dvfs_freq_descend(curr_prof, target_prof); else if (target_prof > curr_prof) ret = acpu_dvfs_freq_ascend(curr_prof, target_prof); if (ret) { ERROR("%s: acpu_dvfs_target failed!\n", __func__); return -1; } /* Complete acpu dvfs setting and set magic number */ acpu_dvfs_sram_buf->start_prof = target_prof; acpu_dvfs_sram_buf->magic = ACPU_VALID_VOLTAGE_MAGIC; mmio_write_32(DDR_DFS_FREQ_ADDR, 800000); return 0; } static int acpu_dvfs_set_freq(void) { unsigned int i; unsigned int curr_prof; unsigned int target_prof; unsigned int max_freq = 0; max_freq = acpu_dvfs_sram_buf->support_freq_max; for (i = 0; i < acpu_dvfs_sram_buf->support_freq_num; i++) { if (max_freq == hi6220_acpu_profile[i].freq) { target_prof = i; break; } } if (i == acpu_dvfs_sram_buf->support_freq_num) { ERROR("%s: cannot found max freq profile\n", __func__); return -1; } curr_prof = 0; target_prof = i; /* if max freq is 208MHz, do nothing */ if (curr_prof == target_prof) return 0; if (acpu_dvfs_target(curr_prof, target_prof)) { ERROR("%s: set acpu freq failed!", __func__); return -1; } INFO("%s: support freq num is %d\n", __func__, acpu_dvfs_sram_buf->support_freq_num); INFO("%s: start prof is 0x%x\n", __func__, acpu_dvfs_sram_buf->start_prof); INFO("%s: magic is 0x%x\n", __func__, acpu_dvfs_sram_buf->magic); INFO("%s: voltage:\n", __func__); for (i = 0; i < acpu_dvfs_sram_buf->support_freq_num; i++) INFO(" - %d: 0x%x\n", i, acpu_dvfs_sram_buf->vol[i]); NOTICE("%s: set acpu freq success!", __func__); return 0; } struct acpu_dvfs_volt_setting { unsigned int magic; unsigned int support_freq_num; unsigned int support_freq_max; unsigned int start_prof; unsigned int vol[7]; unsigned int hmp_dly_threshold[7]; }; static void acpu_dvfs_volt_init(void) { struct acpu_dvfs_volt_setting *volt; /* * - set default voltage; * - set pmu address; * - set voltage up and down step; * - set voltage stable time; */ mmio_write_32(PMCTRL_ACPUDFTVOL, 0x4a); mmio_write_32(PMCTRL_ACPUVOLPMUADDR, 0xda); mmio_write_32(PMCTRL_ACPUVOLUPSTEP, 0x1); mmio_write_32(PMCTRL_ACPUVOLDNSTEP, 0x1); mmio_write_32(PMCTRL_ACPUPMUVOLUPTIME, 0x60); mmio_write_32(PMCTRL_ACPUPMUVOLDNTIME, 0x60); mmio_write_32(PMCTRL_ACPUCLKOFFCFG, 0x1000); volt = (void *)MEMORY_AXI_ACPU_FREQ_VOL_ADDR; volt->magic = 0x5a5ac5c5; volt->support_freq_num = 5; volt->support_freq_max = 1200000; volt->start_prof = 4; volt->vol[0] = 0x49; volt->vol[1] = 0x49; volt->vol[2] = 0x50; volt->vol[3] = 0x60; volt->vol[4] = 0x78; volt->vol[5] = 0x78; volt->vol[6] = 0x78; volt->hmp_dly_threshold[0] = 0x0; volt->hmp_dly_threshold[1] = 0x0; volt->hmp_dly_threshold[2] = 0x0; volt->hmp_dly_threshold[3] = 0x0e8b0e45; volt->hmp_dly_threshold[4] = 0x10691023; volt->hmp_dly_threshold[5] = 0x10691023; volt->hmp_dly_threshold[6] = 0x10691023; INFO("%s: success!\n", __func__); } void init_acpu_dvfs(void) { unsigned int i = 0; INFO("%s: pmic version %d\n", __func__, mmio_read_8(HI6553_VERSION_REG)); /* init parameters */ mmio_write_32(ACPU_CHIP_MAX_FREQ, efuse_acpu_freq[8]); INFO("%s: ACPU_CHIP_MAX_FREQ=0x%x.\n", __func__, mmio_read_32(ACPU_CHIP_MAX_FREQ)); /* set maximum support frequency to 1.2GHz */ for (i = 0; i < ACPU_FREQ_MAX_NUM; i++) acpu_dvfs_sram_buf->vol[i] = hi6220_acpu_profile[i].acpu_vol_profile; acpu_dvfs_sram_buf->support_freq_num = ACPU_FREQ_MAX_NUM; acpu_dvfs_sram_buf->support_freq_max = 1200000; /* init acpu dvfs */ acpu_dvfs_volt_init(); acpu_dvfs_set_freq(); } trusted-firmware-a-2.2/plat/hisilicon/hikey/hisi_ipc.c000066400000000000000000000106631355360272700231040ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include static int ipc_init; static unsigned int cpu_ipc_num[PLATFORM_CLUSTER_COUNT][PLATFORM_CORE_COUNT_PER_CLUSTER] = { { HISI_IPC_MCU_INT_SRC_ACPU0_PD, HISI_IPC_MCU_INT_SRC_ACPU1_PD, HISI_IPC_MCU_INT_SRC_ACPU2_PD, HISI_IPC_MCU_INT_SRC_ACPU3_PD, }, { HISI_IPC_MCU_INT_SRC_ACPU4_PD, HISI_IPC_MCU_INT_SRC_ACPU5_PD, HISI_IPC_MCU_INT_SRC_ACPU6_PD, HISI_IPC_MCU_INT_SRC_ACPU7_PD, } }; int hisi_cpus_pd_in_cluster_besides_curr(unsigned int cpu, unsigned int cluster) { unsigned int val = 0, cpu_val = 0; int i; val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR); val = val >> (cluster * 16); for (i = 0; i < PLATFORM_CORE_COUNT_PER_CLUSTER; i++) { if (cpu == i) continue; cpu_val = (val >> (i * 4)) & 0xF; if (cpu_val == 0x8) return 0; } return 1; } int hisi_cpus_powered_off_besides_curr(unsigned int cpu) { unsigned int val; val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR); return (val == (0x8 << (cpu * 4))); } static void hisi_ipc_send(unsigned int ipc_num) { if (!ipc_init) { printf("error ipc base is null!!!\n"); return; } mmio_write_32(HISI_IPC_CPU_RAW_INT_ADDR, 1 << ipc_num); } void hisi_ipc_spin_lock(unsigned int signal) { unsigned int hs_ctrl; if (signal >= HISI_IPC_INT_SRC_NUM) return; do { hs_ctrl = mmio_read_32(HISI_IPC_ACPU_CTRL(signal)); } while (hs_ctrl); } void hisi_ipc_spin_unlock(unsigned int signal) { if (signal >= HISI_IPC_INT_SRC_NUM) return; mmio_write_32(HISI_IPC_ACPU_CTRL(signal), 0); } void hisi_ipc_cpu_on_off(unsigned int cpu, unsigned int cluster, unsigned int mode) { unsigned int val = 0; unsigned int offset; if (mode == HISI_IPC_PM_ON) offset = cluster * 16 + cpu * 4; else offset = cluster * 16 + cpu * 4 + 1; hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR); val |= (0x01 << offset); mmio_write_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR, val); isb(); dsb(); hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); hisi_ipc_send(cpu_ipc_num[cluster][cpu]); } void hisi_ipc_cpu_on(unsigned int cpu, unsigned int cluster) { hisi_ipc_cpu_on_off(cpu, cluster, HISI_IPC_PM_ON); } void hisi_ipc_cpu_off(unsigned int cpu, unsigned int cluster) { hisi_ipc_cpu_on_off(cpu, cluster, HISI_IPC_PM_OFF); } void hisi_ipc_cluster_on_off(unsigned int cpu, unsigned int cluster, unsigned int mode) { unsigned int val = 0; unsigned int offset; if (mode == HISI_IPC_PM_ON) offset = cluster * 4; else offset = cluster * 4 + 1; hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); val = mmio_read_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR); val |= (0x01 << offset); mmio_write_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR, val); isb(); dsb(); hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); hisi_ipc_send(cpu_ipc_num[cluster][cpu]); } void hisi_ipc_cluster_on(unsigned int cpu, unsigned int cluster) { hisi_ipc_cluster_on_off(cpu, cluster, HISI_IPC_PM_ON); } void hisi_ipc_cluster_off(unsigned int cpu, unsigned int cluster) { hisi_ipc_cluster_on_off(cpu, cluster, HISI_IPC_PM_OFF); } void hisi_ipc_cpu_suspend(unsigned int cpu, unsigned int cluster) { unsigned int val = 0; unsigned int offset; offset = cluster * 16 + cpu * 4 + 2; hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); val = mmio_read_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR); val |= (0x01 << offset); mmio_write_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR, val); hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); hisi_ipc_send(cpu_ipc_num[cluster][cpu]); } void hisi_ipc_cluster_suspend(unsigned int cpu, unsigned int cluster) { unsigned int val; unsigned int offset; offset = cluster * 4 + 1; hisi_ipc_spin_lock(HISI_IPC_SEM_CPUIDLE); if (hisi_cpus_pd_in_cluster_besides_curr(cpu, cluster)) { val = mmio_read_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR); val |= (0x01 << offset); mmio_write_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR, val); } hisi_ipc_spin_unlock(HISI_IPC_SEM_CPUIDLE); hisi_ipc_send(cpu_ipc_num[cluster][cpu]); } void hisi_ipc_psci_system_off(void) { hisi_ipc_send(HISI_IPC_MCU_INT_SRC_ACPU_PD); } int hisi_ipc_init(void) { ipc_init = 1; mmio_write_32(ACPU_CORE_POWERDOWN_FLAGS_ADDR, 0x8); mmio_write_32(ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR, 0x8); return 0; } trusted-firmware-a-2.2/plat/hisilicon/hikey/hisi_mcu.c000066400000000000000000000124051355360272700231110ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #define MCU_SECTION_MAX 30 enum MCU_IMAGE_SEC_TYPE_ENUM { MCU_IMAGE_SEC_TYPE_TEXT = 0, /* text section */ MCU_IMAGE_SEC_TYPE_DATA, /* data section */ MCU_IMAGE_SEC_TYPE_BUTT }; enum MCU_IMAGE_SEC_LOAD_ENUM { MCU_IMAGE_SEC_LOAD_STATIC = 0, MCU_IMAGE_SEC_LOAD_DYNAMIC, MCU_IMAGE_SEC_LOAD_BUFFER, MCU_IMAGE_SEC_LOAD_MODEM_ENTRY, MCU_IMAGE_SEC_LOAD_BUTT }; struct mcu_image_sec { unsigned short serial; char type; char load_attr; uint32_t src_offset; /* offset in image */ uint32_t dst_offset; /* offset in memory */ uint32_t size; }; struct mcu_image_head { char time_stamp[24]; uint32_t image_size; uint32_t secs_num; struct mcu_image_sec secs[MCU_SECTION_MAX]; }; #define SOC_SRAM_M3_BASE_ADDR (0xF6000000) #define MCU_SRAM_SIZE (0x0000C000) #define MCU_CACHE_SIZE (0x00004000) #define MCU_CODE_SIZE (MCU_SRAM_SIZE - MCU_CACHE_SIZE) #define MCU_SYS_MEM_ADDR (0x05E00000) #define MCU_SYS_MEM_SIZE (0x00100000) static uint32_t mcu2ap_addr(uint32_t mcu_addr) { if (mcu_addr < MCU_CODE_SIZE) return (mcu_addr + SOC_SRAM_M3_BASE_ADDR); else if ((mcu_addr >= MCU_SRAM_SIZE) && (mcu_addr < MCU_SRAM_SIZE + MCU_SYS_MEM_SIZE)) return mcu_addr - MCU_SRAM_SIZE + MCU_SYS_MEM_ADDR; else return mcu_addr; } static int is_binary_header_invalid(struct mcu_image_head *head, unsigned int length) { /* invalid cases */ if ((head->image_size == 0) || (head->image_size > length) || (head->secs_num > MCU_SECTION_MAX) || (head->secs_num == 0)) return 1; return 0; } static int is_binary_section_invalid(struct mcu_image_sec *sec, struct mcu_image_head *head) { unsigned long ap_dst_offset = 0; if ((sec->serial >= head->secs_num) || (sec->src_offset + sec->size > head->image_size)) return 1; if ((sec->type >= MCU_IMAGE_SEC_TYPE_BUTT) || (sec->load_attr >= MCU_IMAGE_SEC_LOAD_BUTT)) return 1; ap_dst_offset = mcu2ap_addr(sec->dst_offset); if ((ap_dst_offset >= SOC_SRAM_M3_BASE_ADDR) && (ap_dst_offset < SOC_SRAM_M3_BASE_ADDR + 0x20000 - sec->size)) return 0; else if ((ap_dst_offset >= MCU_SYS_MEM_ADDR) && (ap_dst_offset < MCU_SYS_MEM_ADDR + MCU_SYS_MEM_SIZE - sec->size)) return 0; else if ((ap_dst_offset >= 0xfff8e000) && (ap_dst_offset < 0xfff91c00 - sec->size)) return 0; ERROR("%s: mcu destination address invalid.\n", __func__); ERROR("%s: number=%d, dst offset=%d size=%d\n", __func__, sec->serial, sec->dst_offset, sec->size); return 1; } void hisi_mcu_enable_sram(void) { mmio_write_32(AO_SC_PERIPH_CLKEN4, AO_SC_PERIPH_CLKEN4_HCLK_IPC_S | AO_SC_PERIPH_CLKEN4_HCLK_IPC_NS); /* set register to enable dvfs which is used by mcu */ mmio_write_32(PERI_SC_RESERVED8_ADDR, 0x0A001022); /* mcu mem is powered on, need de-assert reset */ mmio_write_32(AO_SC_PERIPH_RSTDIS4, AO_SC_PERIPH_RSTDIS4_RESET_MCU_ECTR_N); /* enable mcu hclk */ mmio_write_32(AO_SC_PERIPH_CLKEN4, AO_SC_PERIPH_CLKEN4_HCLK_MCU | AO_SC_PERIPH_CLKEN4_CLK_MCU_DAP); } void hisi_mcu_start_run(void) { unsigned int val; /* set mcu ddr remap configuration */ mmio_write_32(AO_SC_MCU_SUBSYS_CTRL2, MCU_SYS_MEM_ADDR); /* de-assert reset for mcu and to run */ mmio_write_32(AO_SC_PERIPH_RSTDIS4, AO_SC_PERIPH_RSTDIS4_RESET_MCU_ECTR_N | AO_SC_PERIPH_RSTDIS4_RESET_MCU_SYS_N | AO_SC_PERIPH_RSTDIS4_RESET_MCU_POR_N | AO_SC_PERIPH_RSTDIS4_RESET_MCU_DAP_N); val = mmio_read_32(AO_SC_SYS_CTRL2); mmio_write_32(AO_SC_SYS_CTRL2, val | AO_SC_SYS_CTRL2_GLB_SRST_STAT_CLEAR); INFO("%s: AO_SC_SYS_CTRL2=%x\n", __func__, mmio_read_32(AO_SC_SYS_CTRL2)); } int hisi_mcu_load_image(uintptr_t image_base, uint32_t image_size) { unsigned int i; struct mcu_image_head *head; char *buf; head = (struct mcu_image_head *)image_base; if (is_binary_header_invalid(head, image_size)) { ERROR("Invalid %s image header.\n", head->time_stamp); return -1; } buf = (char *)head; for (i = 0; i < head->secs_num; i++) { int *src, *dst; /* check the sections */ if (is_binary_section_invalid(&head->secs[i], head)) { ERROR("Invalid mcu section.\n"); return -1; } /* check if the section is static-loaded */ if (head->secs[i].load_attr != MCU_IMAGE_SEC_LOAD_STATIC) continue; /* copy the sections */ src = (int *)(intptr_t)(buf + head->secs[i].src_offset); dst = (int *)(intptr_t)mcu2ap_addr(head->secs[i].dst_offset); memcpy((void *)dst, (void *)src, head->secs[i].size); INFO("%s: mcu sections %d:\n", __func__, i); INFO("%s: src = 0x%x\n", __func__, (unsigned int)(uintptr_t)src); INFO("%s: dst = 0x%x\n", __func__, (unsigned int)(uintptr_t)dst); INFO("%s: size = %d\n", __func__, head->secs[i].size); INFO("%s: [SRC 0x%x] 0x%x 0x%x 0x%x 0x%x\n", __func__, (unsigned int)(uintptr_t)src, src[0], src[1], src[2], src[3]); INFO("%s: [DST 0x%x] 0x%x 0x%x 0x%x 0x%x\n", __func__, (unsigned int)(uintptr_t)dst, dst[0], dst[1], dst[2], dst[3]); } return 0; } trusted-firmware-a-2.2/plat/hisilicon/hikey/hisi_pwrc.c000066400000000000000000000055231355360272700233030ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #define CLUSTER_CORE_COUNT (4) #define CLUSTER_CORE_MASK ((1 << CLUSTER_CORE_COUNT) - 1) void hisi_pwrc_set_core_bx_addr(unsigned int core, unsigned int cluster, uintptr_t entry_point) { uintptr_t *core_entry = (uintptr_t *)PWRCTRL_ACPU_ASM_D_ARM_PARA_AD; unsigned int i; if (!core_entry) { INFO("%s: core entry point is null!\n", __func__); return; } i = cluster * CLUSTER_CORE_COUNT + core; mmio_write_64((uintptr_t)(core_entry + i), entry_point); } void hisi_pwrc_set_cluster_wfi(unsigned int cluster) { unsigned int reg = 0; if (cluster == 0) { reg = mmio_read_32(ACPU_SC_SNOOP_PWD); reg |= PD_DETECT_START0; mmio_write_32(ACPU_SC_SNOOP_PWD, reg); } else if (cluster == 1) { reg = mmio_read_32(ACPU_SC_SNOOP_PWD); reg |= PD_DETECT_START1; mmio_write_32(ACPU_SC_SNOOP_PWD, reg); } } void hisi_pwrc_enable_debug(unsigned int core, unsigned int cluster) { unsigned int val, enable; enable = 1U << (core + PDBGUP_CLUSTER1_SHIFT * cluster); /* Enable debug module */ val = mmio_read_32(ACPU_SC_PDBGUP_MBIST); mmio_write_32(ACPU_SC_PDBGUP_MBIST, val | enable); do { /* RAW barrier */ val = mmio_read_32(ACPU_SC_PDBGUP_MBIST); } while (!(val & enable)); } int hisi_pwrc_setup(void) { unsigned int reg, sec_entrypoint; extern char pm_asm_code[], pm_asm_code_end[]; extern char v7_asm[], v7_asm_end[]; sec_entrypoint = PWRCTRL_ACPU_ASM_CODE_BASE; mmio_write_32(ACPU_SC_CPUx_RVBARADDR(0), sec_entrypoint >> 2); mmio_write_32(ACPU_SC_CPUx_RVBARADDR(1), sec_entrypoint >> 2); mmio_write_32(ACPU_SC_CPUx_RVBARADDR(2), sec_entrypoint >> 2); mmio_write_32(ACPU_SC_CPUx_RVBARADDR(3), sec_entrypoint >> 2); mmio_write_32(ACPU_SC_CPUx_RVBARADDR(4), sec_entrypoint >> 2); mmio_write_32(ACPU_SC_CPUx_RVBARADDR(5), sec_entrypoint >> 2); mmio_write_32(ACPU_SC_CPUx_RVBARADDR(6), sec_entrypoint >> 2); mmio_write_32(ACPU_SC_CPUx_RVBARADDR(7), sec_entrypoint >> 2); memset((void *)PWRCTRL_ACPU_ASM_SPACE_ADDR, 0, 0x400); memcpy((void *)PWRCTRL_ACPU_ASM_SPACE_ADDR, (void *)v7_asm, v7_asm_end - v7_asm); memcpy((void *)PWRCTRL_ACPU_ASM_CODE_BASE, (void *)pm_asm_code, pm_asm_code_end - pm_asm_code); reg = mmio_read_32(AO_SC_SYS_CTRL1); /* Remap SRAM address for ACPU */ reg |= AO_SC_SYS_CTRL1_REMAP_SRAM_AARM | AO_SC_SYS_CTRL1_REMAP_SRAM_AARM_MSK; /* Enable reset signal for watchdog */ reg |= AO_SC_SYS_CTRL1_AARM_WD_RST_CFG | AO_SC_SYS_CTRL1_AARM_WD_RST_CFG_MSK; mmio_write_32(AO_SC_SYS_CTRL1, reg); return 0; } trusted-firmware-a-2.2/plat/hisilicon/hikey/hisi_pwrc_sram.S000066400000000000000000000025571355360272700243110ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include .global pm_asm_code .global pm_asm_code_end .global v7_asm .global v7_asm_end func pm_asm_code _align=3 mov x0, 0 msr oslar_el1, x0 mrs x0, CORTEX_A53_CPUACTLR_EL1 bic x0, x0, #(CORTEX_A53_CPUACTLR_EL1_RADIS | \ CORTEX_A53_CPUACTLR_EL1_L1RADIS) orr x0, x0, #0x180000 orr x0, x0, #0xe000 msr CORTEX_A53_CPUACTLR_EL1, x0 mrs x3, actlr_el3 orr x3, x3, #ACTLR_EL3_L2ECTLR_BIT msr actlr_el3, x3 mrs x3, actlr_el2 orr x3, x3, #ACTLR_EL2_L2ECTLR_BIT msr actlr_el2, x3 ldr x3, =PWRCTRL_ACPU_ASM_D_ARM_PARA_AD mrs x0, mpidr_el1 and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 pen: ldr x4, [x3, x0, LSL #3] cbz x4, pen mov x0, #0x0 mov x1, #0x0 mov x2, #0x0 mov x3, #0x0 br x4 .ltorg pm_asm_code_end: endfunc pm_asm_code /* * By default, all cores in Hi6220 reset with aarch32 mode. * Now hardcode ARMv7 instructions to execute warm reset for * switching aarch64 mode. */ .align 3 .section .rodata.v7_asm, "aS" v7_asm: .word 0xE1A00000 // nop .word 0xE3A02003 // mov r2, #3 .word 0xEE0C2F50 // mcr 15, 0, r2, cr12, cr0, {2} .word 0xE320F003 // wfi .ltorg v7_asm_end: trusted-firmware-a-2.2/plat/hisilicon/hikey/hisi_sip_svc.c000066400000000000000000000032621355360272700237740ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* Hisi SiP Service UUID */ DEFINE_SVC_UUID2(hisi_sip_svc_uid, 0x74df99e5, 0x8276, 0xaa40, 0x9f, 0xf8, 0xc0, 0x85, 0x52, 0xbc, 0x39, 0x3f); static int hisi_sip_setup(void) { if (pmf_setup() != 0) return 1; return 0; } /* * This function handles Hisi defined SiP Calls */ static uintptr_t hisi_sip_handler(unsigned int 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) { int call_count = 0; /* * Dispatch PMF calls to PMF SMC handler and return its return * value */ if (is_pmf_fid(smc_fid)) { return pmf_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); } switch (smc_fid) { case HISI_SIP_SVC_CALL_COUNT: /* PMF calls */ call_count += PMF_NUM_SMC_CALLS; /* State switch call */ call_count += 1; SMC_RET1(handle, call_count); case HISI_SIP_SVC_UID: /* Return UID to the caller */ SMC_UUID_RET(handle, hisi_sip_svc_uid); case HISI_SIP_SVC_VERSION: /* Return the version of current implementation */ SMC_RET2(handle, HISI_SIP_SVC_VERSION_MAJOR, HISI_SIP_SVC_VERSION_MINOR); default: WARN("Unimplemented HISI SiP Service Call: 0x%x \n", smc_fid); SMC_RET1(handle, SMC_UNK); } } /* Define a runtime service descriptor for fast SMC calls */ DECLARE_RT_SVC( hisi_sip_svc, OEN_SIP_START, OEN_SIP_END, SMC_TYPE_FAST, hisi_sip_setup, hisi_sip_handler ); trusted-firmware-a-2.2/plat/hisilicon/hikey/include/000077500000000000000000000000001355360272700225665ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/hisilicon/hikey/include/hi6220.h000066400000000000000000000047601355360272700236600ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HI6220_H #define HI6220_H #include #include #include #include #include /******************************************************************************* * Implementation defined ACTLR_EL2 bit definitions ******************************************************************************/ #define ACTLR_EL2_L2ACTLR_BIT (1 << 6) #define ACTLR_EL2_L2ECTLR_BIT (1 << 5) #define ACTLR_EL2_L2CTLR_BIT (1 << 4) #define ACTLR_EL2_CPUECTLR_BIT (1 << 1) #define ACTLR_EL2_CPUACTLR_BIT (1 << 0) /******************************************************************************* * Implementation defined ACTLR_EL3 bit definitions ******************************************************************************/ #define ACTLR_EL3_L2ACTLR_BIT (1 << 6) #define ACTLR_EL3_L2ECTLR_BIT (1 << 5) #define ACTLR_EL3_L2CTLR_BIT (1 << 4) #define ACTLR_EL3_CPUECTLR_BIT (1 << 1) #define ACTLR_EL3_CPUACTLR_BIT (1 << 0) /******************************************************************************* * CCI-400 related constants ******************************************************************************/ #define CCI400_BASE 0xF6E90000 #define CCI400_SL_IFACE3_CLUSTER_IX 3 #define CCI400_SL_IFACE4_CLUSTER_IX 4 #define DWMMC0_BASE 0xF723D000 #define DWUSB_BASE 0xF72C0000 #define EDMAC_BASE 0xf7370000 #define EDMAC_SEC_CTRL (EDMAC_BASE + 0x694) #define EDMAC_AXI_CONF(x) (EDMAC_BASE + 0x820 + (x << 6)) #define EDMAC_SEC_CTRL_INTR_SEC (1 << 1) #define EDMAC_SEC_CTRL_GLOBAL_SEC (1 << 0) #define EDMAC_CHANNEL_NUMS 16 #define PMUSSI_BASE 0xF8000000 #define SP804_TIMER0_BASE 0xF8008000 #define GPIO0_BASE 0xF8011000 #define GPIO1_BASE 0xF8012000 #define GPIO2_BASE 0xF8013000 #define GPIO3_BASE 0xF8014000 #define GPIO4_BASE 0xF7020000 #define GPIO5_BASE 0xF7021000 #define GPIO6_BASE 0xF7022000 #define GPIO7_BASE 0xF7023000 #define GPIO8_BASE 0xF7024000 #define GPIO9_BASE 0xF7025000 #define GPIO10_BASE 0xF7026000 #define GPIO11_BASE 0xF7027000 #define GPIO12_BASE 0xF7028000 #define GPIO13_BASE 0xF7029000 #define GPIO14_BASE 0xF702A000 #define GPIO15_BASE 0xF702B000 #define GPIO16_BASE 0xF702C000 #define GPIO17_BASE 0xF702D000 #define GPIO18_BASE 0xF702E000 #define GPIO19_BASE 0xF702F000 #endif /* HI6220_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey/include/hi6220_regs_acpu.h000066400000000000000000000335461355360272700257140ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HI6220_REGS_ACPU_H #define HI6220_REGS_ACPU_H #define ACPU_CTRL_BASE 0xF6504000 #define ACPU_SC_CPU_CTRL (ACPU_CTRL_BASE + 0x000) #define ACPU_SC_CPU_STAT (ACPU_CTRL_BASE + 0x008) #define ACPU_SC_CPU_STAT_SC_STANDBYWFIL2 (1 << 0) #define ACPU_SC_CPU_STAT_SC_STANDBYWFIL2_SHIFT (0) #define ACPU_SC_CPU_STAT_SC_STANDBYWFI0 (1 << 1) #define ACPU_SC_CPU_STAT_SC_STANDBYWFI0_SHIFT (1) #define ACPU_SC_CPU_STAT_SC_STANDBYWFI1 (1 << 2) #define ACPU_SC_CPU_STAT_SC_STANDBYWFI1_SHIFT (2) #define ACPU_SC_CPU_STAT_SC_STANDBYWFI2 (1 << 3) #define ACPU_SC_CPU_STAT_SC_STANDBYWFI2_SHIFT (3) #define ACPU_SC_CPU_STAT_SC_STANDBYWFI3 (1 << 4) #define ACPU_SC_CPU_STAT_SC_STANDBYWFI3_SHIFT (4) #define ACPU_SC_CPU_STAT_A53_1_STANDBYWFIL2 (1 << 8) #define ACPU_SC_CPU_STAT_A53_1_STANDBYWFIL2_SHIFT (8) #define ACPU_SC_CPU_STAT_A53_1_STANDBYWFI (1 << 9) #define ACPU_SC_CPU_STAT_A53_1_STANDBYWFI_SHIFT (9) #define ACPU_SC_CPU_STAT_L2FLSHUDONE0 (1 << 16) #define ACPU_SC_CPU_STAT_L2FLSHUDONE0_SHIFT (16) #define ACPU_SC_CPU_STAT_L2FLSHUDONE1 (1 << 17) #define ACPU_SC_CPU_STAT_L2FLSHUDONE1_SHIFT (17) #define ACPU_SC_CPU_STAT_CCI400_ACTIVE (1 << 18) #define ACPU_SC_CPU_STAT_CCI400_ACTIVE_SHIFT (18) #define ACPU_SC_CPU_STAT_CLK_DIV_STATUS_VD (1 << 20) #define ACPU_SC_CPU_STAT_CLK_DIV_STATUS_VD_SHIFT (20) #define ACPU_SC_CLKEN (ACPU_CTRL_BASE + 0x00c) #define HPM_L2_1_CLKEN (1 << 9) #define G_CPU_1_CLKEN (1 << 8) #define HPM_L2_CLKEN (1 << 1) #define G_CPU_CLKEN (1 << 0) #define ACPU_SC_CLKDIS (ACPU_CTRL_BASE + 0x010) #define ACPU_SC_CLK_STAT (ACPU_CTRL_BASE + 0x014) #define ACPU_SC_RSTEN (ACPU_CTRL_BASE + 0x018) #define SRST_PRESET1_RSTEN (1 << 11) #define SRST_PRESET0_RSTEN (1 << 10) #define SRST_CLUSTER1_RSTEN (1 << 9) #define SRST_CLUSTER0_RSTEN (1 << 8) #define SRST_L2_HPM_1_RSTEN (1 << 5) #define SRST_AARM_L2_1_RSTEN (1 << 4) #define SRST_L2_HPM_0_RSTEN (1 << 3) #define SRST_AARM_L2_0_RSTEN (1 << 1) #define SRST_CLUSTER1 (SRST_PRESET1_RSTEN | \ SRST_CLUSTER1_RSTEN | \ SRST_L2_HPM_1_RSTEN | \ SRST_AARM_L2_1_RSTEN) #define SRST_CLUSTER0 (SRST_PRESET0_RSTEN | \ SRST_CLUSTER0_RSTEN | \ SRST_L2_HPM_0_RSTEN | \ SRST_AARM_L2_0_RSTEN) #define ACPU_SC_RSTDIS (ACPU_CTRL_BASE + 0x01c) #define ACPU_SC_RST_STAT (ACPU_CTRL_BASE + 0x020) #define ACPU_SC_PDBGUP_MBIST (ACPU_CTRL_BASE + 0x02c) #define PDBGUP_CLUSTER1_SHIFT 8 #define ACPU_SC_VD_CTRL (ACPU_CTRL_BASE + 0x054) #define ACPU_SC_VD_MASK_PATTERN_CTRL (ACPU_CTRL_BASE + 0x058) #define ACPU_SC_VD_MASK_PATTERN_VAL (0xCCB << 12) #define ACPU_SC_VD_MASK_PATTERN_MASK ((0x1 << 13) - 1) #define ACPU_SC_VD_DLY_FIXED_CTRL (ACPU_CTRL_BASE + 0x05c) #define ACPU_SC_VD_DLY_TABLE0_CTRL (ACPU_CTRL_BASE + 0x060) #define ACPU_SC_VD_DLY_TABLE1_CTRL (ACPU_CTRL_BASE + 0x064) #define ACPU_SC_VD_DLY_TABLE2_CTRL (ACPU_CTRL_BASE + 0x068) #define ACPU_SC_VD_HPM_CTRL (ACPU_CTRL_BASE + 0x06c) #define ACPU_SC_A53_CLUSTER_MTCMOS_EN (ACPU_CTRL_BASE + 0x088) #define PW_MTCMOS_EN_A53_1_EN (1 << 1) #define PW_MTCMOS_EN_A53_0_EN (1 << 0) #define ACPU_SC_A53_CLUSTER_MTCMOS_STA (ACPU_CTRL_BASE + 0x090) #define ACPU_SC_A53_CLUSTER_ISO_EN (ACPU_CTRL_BASE + 0x098) #define PW_ISO_A53_1_EN (1 << 1) #define PW_ISO_A53_0_EN (1 << 0) #define ACPU_SC_A53_CLUSTER_ISO_DIS (ACPU_CTRL_BASE + 0x09c) #define ACPU_SC_A53_CLUSTER_ISO_STA (ACPU_CTRL_BASE + 0x0a0) #define ACPU_SC_A53_1_MTCMOS_TIMER (ACPU_CTRL_BASE + 0x0b4) #define ACPU_SC_A53_0_MTCMOS_TIMER (ACPU_CTRL_BASE + 0x0bc) #define ACPU_SC_A53_x_MTCMOS_TIMER(x) ((x) ? ACPU_SC_A53_1_MTCMOS_TIMER : ACPU_SC_A53_0_MTCMOS_TIMER) #define ACPU_SC_SNOOP_PWD (ACPU_CTRL_BASE + 0xe4) #define PD_DETECT_START1 (1 << 16) #define PD_DETECT_START0 (1 << 0) #define ACPU_SC_CPU0_CTRL (ACPU_CTRL_BASE + 0x100) #define CPU_CTRL_AARCH64_MODE (1 << 7) #define ACPU_SC_CPU0_STAT (ACPU_CTRL_BASE + 0x104) #define ACPU_SC_CPU0_CLKEN (ACPU_CTRL_BASE + 0x108) #define CPU_CLKEN_HPM (1 << 1) #define ACPU_SC_CPU0_CLK_STAT (ACPU_CTRL_BASE + 0x110) #define ACPU_SC_CPU0_RSTEN (ACPU_CTRL_BASE + 0x114) #define ACPU_SC_CPU0_RSTDIS (ACPU_CTRL_BASE + 0x118) #define ACPU_SC_CPU0_MTCMOS_EN (ACPU_CTRL_BASE + 0x120) #define CPU_MTCMOS_PW (1 << 0) #define ACPU_SC_CPU0_PW_ISOEN (ACPU_CTRL_BASE + 0x130) #define CPU_PW_ISO (1 << 0) #define ACPU_SC_CPU0_PW_ISODIS (ACPU_CTRL_BASE + 0x134) #define ACPU_SC_CPU0_PW_ISO_STAT (ACPU_CTRL_BASE + 0x138) #define ACPU_SC_CPU0_MTCMOS_TIMER_STAT (ACPU_CTRL_BASE + 0x154) #define CPU_MTCMOS_TIMER_STA (1 << 0) #define ACPU_SC_CPU0_RVBARADDR (ACPU_CTRL_BASE + 0x158) #define ACPU_SC_CPU1_CTRL (ACPU_CTRL_BASE + 0x200) #define ACPU_SC_CPU1_STAT (ACPU_CTRL_BASE + 0x204) #define ACPU_SC_CPU1_CLKEN (ACPU_CTRL_BASE + 0x208) #define ACPU_SC_CPU1_CLK_STAT (ACPU_CTRL_BASE + 0x210) #define ACPU_SC_CPU1_RSTEN (ACPU_CTRL_BASE + 0x214) #define ACPU_SC_CPU1_RSTDIS (ACPU_CTRL_BASE + 0x218) #define ACPU_SC_CPU1_MTCMOS_EN (ACPU_CTRL_BASE + 0x220) #define ACPU_SC_CPU1_PW_ISODIS (ACPU_CTRL_BASE + 0x234) #define ACPU_SC_CPU1_PW_ISO_STAT (ACPU_CTRL_BASE + 0x238) #define ACPU_SC_CPU1_MTCMOS_TIMER_STAT (ACPU_CTRL_BASE + 0x254) #define ACPU_SC_CPU1_RVBARADDR (ACPU_CTRL_BASE + 0x258) #define ACPU_SC_CPU2_CTRL (ACPU_CTRL_BASE + 0x300) #define ACPU_SC_CPU2_STAT (ACPU_CTRL_BASE + 0x304) #define ACPU_SC_CPU2_CLKEN (ACPU_CTRL_BASE + 0x308) #define ACPU_SC_CPU2_CLK_STAT (ACPU_CTRL_BASE + 0x310) #define ACPU_SC_CPU2_RSTEN (ACPU_CTRL_BASE + 0x314) #define ACPU_SC_CPU2_RSTDIS (ACPU_CTRL_BASE + 0x318) #define ACPU_SC_CPU2_MTCMOS_EN (ACPU_CTRL_BASE + 0x320) #define ACPU_SC_CPU2_PW_ISODIS (ACPU_CTRL_BASE + 0x334) #define ACPU_SC_CPU2_PW_ISO_STAT (ACPU_CTRL_BASE + 0x338) #define ACPU_SC_CPU2_MTCMOS_TIMER_STAT (ACPU_CTRL_BASE + 0x354) #define ACPU_SC_CPU2_RVBARADDR (ACPU_CTRL_BASE + 0x358) #define ACPU_SC_CPU3_CTRL (ACPU_CTRL_BASE + 0x400) #define ACPU_SC_CPU3_STAT (ACPU_CTRL_BASE + 0x404) #define ACPU_SC_CPU3_CLKEN (ACPU_CTRL_BASE + 0x408) #define ACPU_SC_CPU3_CLK_STAT (ACPU_CTRL_BASE + 0x410) #define ACPU_SC_CPU3_RSTEN (ACPU_CTRL_BASE + 0x414) #define ACPU_SC_CPU3_RSTDIS (ACPU_CTRL_BASE + 0x418) #define ACPU_SC_CPU3_MTCMOS_EN (ACPU_CTRL_BASE + 0x420) #define ACPU_SC_CPU3_PW_ISODIS (ACPU_CTRL_BASE + 0x434) #define ACPU_SC_CPU3_PW_ISO_STAT (ACPU_CTRL_BASE + 0x438) #define ACPU_SC_CPU3_MTCMOS_TIMER_STAT (ACPU_CTRL_BASE + 0x454) #define ACPU_SC_CPU3_RVBARADDR (ACPU_CTRL_BASE + 0x458) #define ACPU_SC_CPU4_CTRL (ACPU_CTRL_BASE + 0x500) #define ACPU_SC_CPU4_STAT (ACPU_CTRL_BASE + 0x504) #define ACPU_SC_CPU4_CLKEN (ACPU_CTRL_BASE + 0x508) #define ACPU_SC_CPU4_CLK_STAT (ACPU_CTRL_BASE + 0x510) #define ACPU_SC_CPU4_RSTEN (ACPU_CTRL_BASE + 0x514) #define ACPU_SC_CPU4_RSTDIS (ACPU_CTRL_BASE + 0x518) #define ACPU_SC_CPU4_MTCMOS_EN (ACPU_CTRL_BASE + 0x520) #define ACPU_SC_CPU4_PW_ISODIS (ACPU_CTRL_BASE + 0x534) #define ACPU_SC_CPU4_PW_ISO_STAT (ACPU_CTRL_BASE + 0x538) #define ACPU_SC_CPU4_MTCMOS_TIMER_STAT (ACPU_CTRL_BASE + 0x554) #define ACPU_SC_CPU4_RVBARADDR (ACPU_CTRL_BASE + 0x558) #define ACPU_SC_CPU5_CTRL (ACPU_CTRL_BASE + 0x600) #define ACPU_SC_CPU5_STAT (ACPU_CTRL_BASE + 0x604) #define ACPU_SC_CPU5_CLKEN (ACPU_CTRL_BASE + 0x608) #define ACPU_SC_CPU5_CLK_STAT (ACPU_CTRL_BASE + 0x610) #define ACPU_SC_CPU5_RSTEN (ACPU_CTRL_BASE + 0x614) #define ACPU_SC_CPU5_RSTDIS (ACPU_CTRL_BASE + 0x618) #define ACPU_SC_CPU5_MTCMOS_EN (ACPU_CTRL_BASE + 0x620) #define ACPU_SC_CPU5_PW_ISODIS (ACPU_CTRL_BASE + 0x634) #define ACPU_SC_CPU5_PW_ISO_STAT (ACPU_CTRL_BASE + 0x638) #define ACPU_SC_CPU5_MTCMOS_TIMER_STAT (ACPU_CTRL_BASE + 0x654) #define ACPU_SC_CPU5_RVBARADDR (ACPU_CTRL_BASE + 0x658) #define ACPU_SC_CPU6_CTRL (ACPU_CTRL_BASE + 0x700) #define ACPU_SC_CPU6_STAT (ACPU_CTRL_BASE + 0x704) #define ACPU_SC_CPU6_CLKEN (ACPU_CTRL_BASE + 0x708) #define ACPU_SC_CPU6_CLK_STAT (ACPU_CTRL_BASE + 0x710) #define ACPU_SC_CPU6_RSTEN (ACPU_CTRL_BASE + 0x714) #define ACPU_SC_CPU6_RSTDIS (ACPU_CTRL_BASE + 0x718) #define ACPU_SC_CPU6_MTCMOS_EN (ACPU_CTRL_BASE + 0x720) #define ACPU_SC_CPU6_PW_ISODIS (ACPU_CTRL_BASE + 0x734) #define ACPU_SC_CPU6_PW_ISO_STAT (ACPU_CTRL_BASE + 0x738) #define ACPU_SC_CPU6_MTCMOS_TIMER_STAT (ACPU_CTRL_BASE + 0x754) #define ACPU_SC_CPU6_RVBARADDR (ACPU_CTRL_BASE + 0x758) #define ACPU_SC_CPU7_CTRL (ACPU_CTRL_BASE + 0x800) #define ACPU_SC_CPU7_STAT (ACPU_CTRL_BASE + 0x804) #define ACPU_SC_CPU7_CLKEN (ACPU_CTRL_BASE + 0x808) #define ACPU_SC_CPU7_CLK_STAT (ACPU_CTRL_BASE + 0x810) #define ACPU_SC_CPU7_RSTEN (ACPU_CTRL_BASE + 0x814) #define ACPU_SC_CPU7_RSTDIS (ACPU_CTRL_BASE + 0x818) #define ACPU_SC_CPU7_MTCMOS_EN (ACPU_CTRL_BASE + 0x820) #define ACPU_SC_CPU7_PW_ISODIS (ACPU_CTRL_BASE + 0x834) #define ACPU_SC_CPU7_PW_ISO_STAT (ACPU_CTRL_BASE + 0x838) #define ACPU_SC_CPU7_MTCMOS_TIMER_STAT (ACPU_CTRL_BASE + 0x854) #define ACPU_SC_CPU7_RVBARADDR (ACPU_CTRL_BASE + 0x858) #define ACPU_SC_CPUx_CTRL(x) ((x < 8) ? (ACPU_SC_CPU0_CTRL + 0x100 * x) : ACPU_SC_CPU0_CTRL) #define ACPU_SC_CPUx_STAT(x) ((x < 8) ? (ACPU_SC_CPU0_STAT + 0x100 * x) : ACPU_SC_CPU0_STAT) #define ACPU_SC_CPUx_CLKEN(x) ((x < 8) ? (ACPU_SC_CPU0_CLKEN + 0x100 * x) : ACPU_SC_CPU0_CLKEN) #define ACPU_SC_CPUx_CLK_STAT(x) ((x < 8) ? (ACPU_SC_CPU0_CLK_STAT + 0x100 * x) : ACPU_SC_CPU0_CLK_STAT) #define ACPU_SC_CPUx_RSTEN(x) ((x < 8) ? (ACPU_SC_CPU0_RSTEN + 0x100 * x) : ACPU_SC_CPU0_RSTEN) #define ACPU_SC_CPUx_RSTDIS(x) ((x < 8) ? (ACPU_SC_CPU0_RSTDIS + 0x100 * x) : ACPU_SC_CPU0_RSTDIS) #define ACPU_SC_CPUx_MTCMOS_EN(x) ((x < 8) ? (ACPU_SC_CPU0_MTCMOS_EN + 0x100 * x) : ACPU_SC_CPU0_MTCMOS_EN) #define ACPU_SC_CPUx_PW_ISODIS(x) ((x < 8) ? (ACPU_SC_CPU0_PW_ISODIS + 0x100 * x) : ACPU_SC_CPU0_PW_ISODIS) #define ACPU_SC_CPUx_PW_ISO_STAT(x) ((x < 8) ? (ACPU_SC_CPU0_PW_ISO_STAT + 0x100 * x) : ACPU_SC_CPU0_PW_ISO_STAT) #define ACPU_SC_CPUx_MTCMOS_TIMER_STAT(x) ((x < 8) ? (ACPU_SC_CPU0_MTCMOS_TIMER_STAT + 0x100 * x) : ACPU_SC_CPU0_MTCMOS_TIMER_STAT) #define ACPU_SC_CPUx_RVBARADDR(x) ((x < 8) ? (ACPU_SC_CPU0_RVBARADDR + 0x100 * x) : ACPU_SC_CPU0_RVBARADDR) #define ACPU_SC_CPU_STAT_CLKDIV_VD_MASK (3 << 20) #define ACPU_SC_VD_CTRL_TUNE_EN_DIF (1 << 0) #define ACPU_SC_VD_CTRL_TUNE_EN_DIF_SHIFT (0) #define ACPU_SC_VD_CTRL_TUNE (1 << 1) #define ACPU_SC_VD_CTRL_TUNE_SHIFT (1) #define ACPU_SC_VD_CTRL_CALIBRATE_EN_DIF (1 << 7) #define ACPU_SC_VD_CTRL_CALIBRATE_EN_DIF_SHIFT (7) #define ACPU_SC_VD_CTRL_CALIBRATE_EN_INI (1 << 8) #define ACPU_SC_VD_CTRL_CALIBRATE_EN_INI_SHIFT (8) #define ACPU_SC_VD_CTRL_CLK_DIS_CNT_CLR (1 << 9) #define ACPU_SC_VD_CTRL_CLK_DIS_CNT_CLR_SHIFT (9) #define ACPU_SC_VD_CTRL_CLK_DIS_CNT_EN (1 << 10) #define ACPU_SC_VD_CTRL_CLK_DIS_CNT_EN_SHIFT (10) #define ACPU_SC_VD_CTRL_TUNE_EN_INT (1 << 11) #define ACPU_SC_VD_CTRL_TUNE_EN_INT_SHIFT (11) #define ACPU_SC_VD_CTRL_SHIFT_TABLE0 (1 << 12) #define ACPU_SC_VD_CTRL_SHIFT_TABLE0_MASK (0xf << 12) #define ACPU_SC_VD_CTRL_SHIFT_TABLE0_SHIFT (12) #define ACPU_SC_VD_CTRL_SHIFT_TABLE1 (1 << 16) #define ACPU_SC_VD_CTRL_SHIFT_TABLE1_MASK (0xf << 16) #define ACPU_SC_VD_CTRL_SHIFT_TABLE1_SHIFT (16) #define ACPU_SC_VD_CTRL_SHIFT_TABLE2 (1 << 20) #define ACPU_SC_VD_CTRL_SHIFT_TABLE2_MASK (0xf << 20) #define ACPU_SC_VD_CTRL_SHIFT_TABLE2_SHIFT (20) #define ACPU_SC_VD_CTRL_SHIFT_TABLE3 (1 << 24) #define ACPU_SC_VD_CTRL_SHIFT_TABLE3_MASK (0xf << 24) #define ACPU_SC_VD_CTRL_SHIFT_TABLE3_SHIFT (24) #define ACPU_SC_VD_CTRL_FORCE_CLK_EN (1 << 28) #define ACPU_SC_VD_CTRL_FORCE_CLK_EN_SHIFT (28) #define ACPU_SC_VD_CTRL_DIV_EN_DIF (1 << 29) #define ACPU_SC_VD_CTRL_DIV_EN_DIF_SHIFT (29) #define ACPU_SC_VD_SHIFT_TABLE_TUNE_VAL \ ((0x1 << ACPU_SC_VD_CTRL_SHIFT_TABLE0_SHIFT) | \ (0x3 << ACPU_SC_VD_CTRL_SHIFT_TABLE1_SHIFT) | \ (0x5 << ACPU_SC_VD_CTRL_SHIFT_TABLE2_SHIFT) | \ (0x6 << ACPU_SC_VD_CTRL_SHIFT_TABLE3_SHIFT) | \ (0x7 << ACPU_SC_VD_CTRL_TUNE_SHIFT)) #define ACPU_SC_VD_SHIFT_TABLE_TUNE_MASK \ ((0xF << ACPU_SC_VD_CTRL_SHIFT_TABLE0_SHIFT) | \ (0xF << ACPU_SC_VD_CTRL_SHIFT_TABLE1_SHIFT) | \ (0xF << ACPU_SC_VD_CTRL_SHIFT_TABLE2_SHIFT) | \ (0xF << ACPU_SC_VD_CTRL_SHIFT_TABLE3_SHIFT) | \ (0x3F << ACPU_SC_VD_CTRL_TUNE_SHIFT)) #define ACPU_SC_VD_HPM_CTRL_OSC_DIV (1 << 0) #define ACPU_SC_VD_HPM_CTRL_OSC_DIV_SHIFT (0) #define ACPU_SC_VD_HPM_CTRL_OSC_DIV_MASK (0x000000FF) #define ACPU_SC_VD_HPM_CTRL_DLY_EXP (1 << 8) #define ACPU_SC_VD_HPM_CTRL_DLY_EXP_SHIFT (8) #define ACPU_SC_VD_HPM_CTRL_DLY_EXP_MASK (0x001FFF00) #define HPM_OSC_DIV_VAL \ (0x56 << ACPU_SC_VD_HPM_CTRL_OSC_DIV_SHIFT) #define HPM_OSC_DIV_MASK \ (ACPU_SC_VD_HPM_CTRL_OSC_DIV_MASK) #define HPM_DLY_EXP_VAL \ (0xC7A << ACPU_SC_VD_HPM_CTRL_DLY_EXP_SHIFT) #define HPM_DLY_EXP_MASK \ (ACPU_SC_VD_HPM_CTRL_DLY_EXP_MASK) #define ACPU_SC_VD_EN_ASIC_VAL \ ((0x0 << ACPU_SC_VD_CTRL_FORCE_CLK_EN_SHIFT) | \ (0x0 << ACPU_SC_VD_CTRL_CLK_DIS_CNT_EN_SHIFT) | \ (0x0 << ACPU_SC_VD_CTRL_CALIBRATE_EN_INI_SHIFT) | \ (0x0 << ACPU_SC_VD_CTRL_CALIBRATE_EN_DIF_SHIFT) | \ (0X0 << ACPU_SC_VD_CTRL_DIV_EN_DIF_SHIFT) | \ (0X0 << ACPU_SC_VD_CTRL_TUNE_EN_INT_SHIFT) | \ (0x0 << ACPU_SC_VD_CTRL_TUNE_EN_DIF_SHIFT)) #define ACPU_SC_VD_EN_SFT_VAL \ ((0x0 << ACPU_SC_VD_CTRL_FORCE_CLK_EN_SHIFT) | \ (0x0 << ACPU_SC_VD_CTRL_CLK_DIS_CNT_EN_SHIFT) | \ (0x0 << ACPU_SC_VD_CTRL_CALIBRATE_EN_INI_SHIFT) | \ (0x0 << ACPU_SC_VD_CTRL_CALIBRATE_EN_DIF_SHIFT) | \ (0x0 << ACPU_SC_VD_CTRL_DIV_EN_DIF_SHIFT) | \ (0x0 << ACPU_SC_VD_CTRL_TUNE_EN_INT_SHIFT) | \ (0x0 << ACPU_SC_VD_CTRL_TUNE_EN_DIF_SHIFT)) #define ACPU_SC_VD_EN_MASK \ ((0x1 << ACPU_SC_VD_CTRL_FORCE_CLK_EN_SHIFT) | \ (0x1 << ACPU_SC_VD_CTRL_CLK_DIS_CNT_EN_SHIFT) | \ (0x1 << ACPU_SC_VD_CTRL_CALIBRATE_EN_INI_SHIFT) | \ (0x1 << ACPU_SC_VD_CTRL_CALIBRATE_EN_DIF_SHIFT) | \ (0x1 << ACPU_SC_VD_CTRL_DIV_EN_DIF_SHIFT) | \ (0x1 << ACPU_SC_VD_CTRL_TUNE_EN_INT_SHIFT) | \ (0x1 << ACPU_SC_VD_CTRL_TUNE_EN_DIF_SHIFT)) #endif /* HI6220_REGS_ACPU_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey/include/hi6220_regs_ao.h000066400000000000000000000411621355360272700253540ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HI6220_REGS_AO_H #define HI6220_REGS_AO_H #define AO_CTRL_BASE 0xF7800000 #define AO_SC_SYS_CTRL0 (AO_CTRL_BASE + 0x000) #define AO_SC_SYS_CTRL1 (AO_CTRL_BASE + 0x004) #define AO_SC_SYS_CTRL2 (AO_CTRL_BASE + 0x008) #define AO_SC_SYS_STAT0 (AO_CTRL_BASE + 0x010) #define AO_SC_SYS_STAT1 (AO_CTRL_BASE + 0x014) #define AO_SC_MCU_IMCTRL (AO_CTRL_BASE + 0x018) #define AO_SC_MCU_IMSTAT (AO_CTRL_BASE + 0x01C) #define AO_SC_SECONDRY_INT_EN0 (AO_CTRL_BASE + 0x044) #define AO_SC_SECONDRY_INT_STATR0 (AO_CTRL_BASE + 0x048) #define AO_SC_SECONDRY_INT_STATM0 (AO_CTRL_BASE + 0x04C) #define AO_SC_MCU_WKUP_INT_EN6 (AO_CTRL_BASE + 0x054) #define AO_SC_MCU_WKUP_INT_STATR6 (AO_CTRL_BASE + 0x058) #define AO_SC_MCU_WKUP_INT_STATM6 (AO_CTRL_BASE + 0x05C) #define AO_SC_MCU_WKUP_INT_EN5 (AO_CTRL_BASE + 0x064) #define AO_SC_MCU_WKUP_INT_STATR5 (AO_CTRL_BASE + 0x068) #define AO_SC_MCU_WKUP_INT_STATM5 (AO_CTRL_BASE + 0x06C) #define AO_SC_MCU_WKUP_INT_EN4 (AO_CTRL_BASE + 0x094) #define AO_SC_MCU_WKUP_INT_STATR4 (AO_CTRL_BASE + 0x098) #define AO_SC_MCU_WKUP_INT_STATM4 (AO_CTRL_BASE + 0x09C) #define AO_SC_MCU_WKUP_INT_EN0 (AO_CTRL_BASE + 0x0A8) #define AO_SC_MCU_WKUP_INT_STATR0 (AO_CTRL_BASE + 0x0AC) #define AO_SC_MCU_WKUP_INT_STATM0 (AO_CTRL_BASE + 0x0B0) #define AO_SC_MCU_WKUP_INT_EN1 (AO_CTRL_BASE + 0x0B4) #define AO_SC_MCU_WKUP_INT_STATR1 (AO_CTRL_BASE + 0x0B8) #define AO_SC_MCU_WKUP_INT_STATM1 (AO_CTRL_BASE + 0x0BC) #define AO_SC_INT_STATR (AO_CTRL_BASE + 0x0C4) #define AO_SC_INT_STATM (AO_CTRL_BASE + 0x0C8) #define AO_SC_INT_CLEAR (AO_CTRL_BASE + 0x0CC) #define AO_SC_INT_EN_SET (AO_CTRL_BASE + 0x0D0) #define AO_SC_INT_EN_DIS (AO_CTRL_BASE + 0x0D4) #define AO_SC_INT_EN_STAT (AO_CTRL_BASE + 0x0D8) #define AO_SC_INT_STATR1 (AO_CTRL_BASE + 0x0E4) #define AO_SC_INT_STATM1 (AO_CTRL_BASE + 0x0E8) #define AO_SC_INT_CLEAR1 (AO_CTRL_BASE + 0x0EC) #define AO_SC_INT_EN_SET1 (AO_CTRL_BASE + 0x0F0) #define AO_SC_INT_EN_DIS1 (AO_CTRL_BASE + 0x0F4) #define AO_SC_INT_EN_STAT1 (AO_CTRL_BASE + 0x0F8) #define AO_SC_TIMER_EN0 (AO_CTRL_BASE + 0x1D0) #define AO_SC_TIMER_EN1 (AO_CTRL_BASE + 0x1D4) #define AO_SC_TIMER_EN4 (AO_CTRL_BASE + 0x1F0) #define AO_SC_TIMER_EN5 (AO_CTRL_BASE + 0x1F4) #define AO_SC_MCU_SUBSYS_CTRL0 (AO_CTRL_BASE + 0x400) #define AO_SC_MCU_SUBSYS_CTRL1 (AO_CTRL_BASE + 0x404) #define AO_SC_MCU_SUBSYS_CTRL2 (AO_CTRL_BASE + 0x408) #define AO_SC_MCU_SUBSYS_CTRL3 (AO_CTRL_BASE + 0x40C) #define AO_SC_MCU_SUBSYS_CTRL4 (AO_CTRL_BASE + 0x410) #define AO_SC_MCU_SUBSYS_CTRL5 (AO_CTRL_BASE + 0x414) #define AO_SC_MCU_SUBSYS_CTRL6 (AO_CTRL_BASE + 0x418) #define AO_SC_MCU_SUBSYS_CTRL7 (AO_CTRL_BASE + 0x41C) #define AO_SC_MCU_SUBSYS_STAT0 (AO_CTRL_BASE + 0x440) #define AO_SC_MCU_SUBSYS_STAT1 (AO_CTRL_BASE + 0x444) #define AO_SC_MCU_SUBSYS_STAT2 (AO_CTRL_BASE + 0x448) #define AO_SC_MCU_SUBSYS_STAT3 (AO_CTRL_BASE + 0x44C) #define AO_SC_MCU_SUBSYS_STAT4 (AO_CTRL_BASE + 0x450) #define AO_SC_MCU_SUBSYS_STAT5 (AO_CTRL_BASE + 0x454) #define AO_SC_MCU_SUBSYS_STAT6 (AO_CTRL_BASE + 0x458) #define AO_SC_MCU_SUBSYS_STAT7 (AO_CTRL_BASE + 0x45C) #define AO_SC_PERIPH_CLKEN4 (AO_CTRL_BASE + 0x630) #define AO_SC_PERIPH_CLKDIS4 (AO_CTRL_BASE + 0x634) #define AO_SC_PERIPH_CLKSTAT4 (AO_CTRL_BASE + 0x638) #define AO_SC_PERIPH_CLKEN5 (AO_CTRL_BASE + 0x63C) #define AO_SC_PERIPH_CLKDIS5 (AO_CTRL_BASE + 0x640) #define AO_SC_PERIPH_CLKSTAT5 (AO_CTRL_BASE + 0x644) #define AO_SC_PERIPH_RSTEN4 (AO_CTRL_BASE + 0x6F0) #define AO_SC_PERIPH_RSTDIS4 (AO_CTRL_BASE + 0x6F4) #define AO_SC_PERIPH_RSTSTAT4 (AO_CTRL_BASE + 0x6F8) #define AO_SC_PERIPH_RSTEN5 (AO_CTRL_BASE + 0x6FC) #define AO_SC_PERIPH_RSTDIS5 (AO_CTRL_BASE + 0x700) #define AO_SC_PERIPH_RSTSTAT5 (AO_CTRL_BASE + 0x704) #define AO_SC_PW_CLKEN0 (AO_CTRL_BASE + 0x800) #define AO_SC_PW_CLKDIS0 (AO_CTRL_BASE + 0x804) #define AO_SC_PW_CLK_STAT0 (AO_CTRL_BASE + 0x808) #define AO_SC_PW_RSTEN0 (AO_CTRL_BASE + 0x810) #define AO_SC_PW_RSTDIS0 (AO_CTRL_BASE + 0x814) #define AO_SC_PW_RST_STAT0 (AO_CTRL_BASE + 0x818) #define AO_SC_PW_ISOEN0 (AO_CTRL_BASE + 0x820) #define AO_SC_PW_ISODIS0 (AO_CTRL_BASE + 0x824) #define AO_SC_PW_ISO_STAT0 (AO_CTRL_BASE + 0x828) #define AO_SC_PW_MTCMOS_EN0 (AO_CTRL_BASE + 0x830) #define AO_SC_PW_MTCMOS_DIS0 (AO_CTRL_BASE + 0x834) #define AO_SC_PW_MTCMOS_STAT0 (AO_CTRL_BASE + 0x838) #define AO_SC_PW_MTCMOS_ACK_STAT0 (AO_CTRL_BASE + 0x83C) #define AO_SC_PW_MTCMOS_TIMEOUT_STAT0 (AO_CTRL_BASE + 0x840) #define AO_SC_PW_STAT0 (AO_CTRL_BASE + 0x850) #define AO_SC_PW_STAT1 (AO_CTRL_BASE + 0x854) #define AO_SC_SYSTEST_STAT (AO_CTRL_BASE + 0x880) #define AO_SC_SYSTEST_SLICER_CNT0 (AO_CTRL_BASE + 0x890) #define AO_SC_SYSTEST_SLICER_CNT1 (AO_CTRL_BASE + 0x894) #define AO_SC_PW_CTRL1 (AO_CTRL_BASE + 0x8C8) #define AO_SC_PW_CTRL (AO_CTRL_BASE + 0x8CC) #define AO_SC_MCPU_VOTEEN (AO_CTRL_BASE + 0x8D0) #define AO_SC_MCPU_VOTEDIS (AO_CTRL_BASE + 0x8D4) #define AO_SC_MCPU_VOTESTAT (AO_CTRL_BASE + 0x8D8) #define AO_SC_MCPU_VOTE_MSK0 (AO_CTRL_BASE + 0x8E0) #define AO_SC_MCPU_VOTE_MSK1 (AO_CTRL_BASE + 0x8E4) #define AO_SC_MCPU_VOTESTAT0_MSK (AO_CTRL_BASE + 0x8E8) #define AO_SC_MCPU_VOTESTAT1_MSK (AO_CTRL_BASE + 0x8EC) #define AO_SC_PERI_VOTEEN (AO_CTRL_BASE + 0x8F0) #define AO_SC_PERI_VOTEDIS (AO_CTRL_BASE + 0x8F4) #define AO_SC_PERI_VOTESTAT (AO_CTRL_BASE + 0x8F8) #define AO_SC_PERI_VOTE_MSK0 (AO_CTRL_BASE + 0x900) #define AO_SC_PERI_VOTE_MSK1 (AO_CTRL_BASE + 0x904) #define AO_SC_PERI_VOTESTAT0_MSK (AO_CTRL_BASE + 0x908) #define AO_SC_PERI_VOTESTAT1_MSK (AO_CTRL_BASE + 0x90C) #define AO_SC_ACPU_VOTEEN (AO_CTRL_BASE + 0x910) #define AO_SC_ACPU_VOTEDIS (AO_CTRL_BASE + 0x914) #define AO_SC_ACPU_VOTESTAT (AO_CTRL_BASE + 0x918) #define AO_SC_ACPU_VOTE_MSK0 (AO_CTRL_BASE + 0x920) #define AO_SC_ACPU_VOTE_MSK1 (AO_CTRL_BASE + 0x924) #define AO_SC_ACPU_VOTESTAT0_MSK (AO_CTRL_BASE + 0x928) #define AO_SC_ACPU_VOTESTAT1_MSK (AO_CTRL_BASE + 0x92C) #define AO_SC_MCU_VOTEEN (AO_CTRL_BASE + 0x930) #define AO_SC_MCU_VOTEDIS (AO_CTRL_BASE + 0x934) #define AO_SC_MCU_VOTESTAT (AO_CTRL_BASE + 0x938) #define AO_SC_MCU_VOTE_MSK0 (AO_CTRL_BASE + 0x940) #define AO_SC_MCU_VOTE_MSK1 (AO_CTRL_BASE + 0x944) #define AO_SC_MCU_VOTESTAT0_MSK (AO_CTRL_BASE + 0x948) #define AO_SC_MCU_VOTESTAT1_MSK (AO_CTRL_BASE + 0x94C) #define AO_SC_MCU_VOTE1EN (AO_CTRL_BASE + 0x960) #define AO_SC_MCU_VOTE1DIS (AO_CTRL_BASE + 0x964) #define AO_SC_MCU_VOTE1STAT (AO_CTRL_BASE + 0x968) #define AO_SC_MCU_VOTE1_MSK0 (AO_CTRL_BASE + 0x970) #define AO_SC_MCU_VOTE1_MSK1 (AO_CTRL_BASE + 0x974) #define AO_SC_MCU_VOTE1STAT0_MSK (AO_CTRL_BASE + 0x978) #define AO_SC_MCU_VOTE1STAT1_MSK (AO_CTRL_BASE + 0x97C) #define AO_SC_MCU_VOTE2EN (AO_CTRL_BASE + 0x980) #define AO_SC_MCU_VOTE2DIS (AO_CTRL_BASE + 0x984) #define AO_SC_MCU_VOTE2STAT (AO_CTRL_BASE + 0x988) #define AO_SC_MCU_VOTE2_MSK0 (AO_CTRL_BASE + 0x990) #define AO_SC_MCU_VOTE2_MSK1 (AO_CTRL_BASE + 0x994) #define AO_SC_MCU_VOTE2STAT0_MSK (AO_CTRL_BASE + 0x998) #define AO_SC_MCU_VOTE2STAT1_MSK (AO_CTRL_BASE + 0x99C) #define AO_SC_VOTE_CTRL (AO_CTRL_BASE + 0x9A0) #define AO_SC_VOTE_STAT (AO_CTRL_BASE + 0x9A4) #define AO_SC_ECONUM (AO_CTRL_BASE + 0xF00) #define AO_SCCHIPID (AO_CTRL_BASE + 0xF10) #define AO_SCSOCID (AO_CTRL_BASE + 0xF1C) #define AO_SC_SOC_FPGA_RTL_DEF (AO_CTRL_BASE + 0xFE0) #define AO_SC_SOC_FPGA_PR_DEF (AO_CTRL_BASE + 0xFE4) #define AO_SC_SOC_FPGA_RES_DEF0 (AO_CTRL_BASE + 0xFE8) #define AO_SC_SOC_FPGA_RES_DEF1 (AO_CTRL_BASE + 0xFEC) #define AO_SC_XTAL_CTRL0 (AO_CTRL_BASE + 0x102) #define AO_SC_XTAL_CTRL1 (AO_CTRL_BASE + 0x102) #define AO_SC_XTAL_CTRL3 (AO_CTRL_BASE + 0x103) #define AO_SC_XTAL_CTRL5 (AO_CTRL_BASE + 0x103) #define AO_SC_XTAL_STAT0 (AO_CTRL_BASE + 0x106) #define AO_SC_XTAL_STAT1 (AO_CTRL_BASE + 0x107) #define AO_SC_EFUSE_CHIPID0 (AO_CTRL_BASE + 0x108) #define AO_SC_EFUSE_CHIPID1 (AO_CTRL_BASE + 0x108) #define AO_SC_EFUSE_SYS_CTRL (AO_CTRL_BASE + 0x108) #define AO_SC_DEBUG_CTRL1 (AO_CTRL_BASE + 0x128) #define AO_SC_DBG_STAT (AO_CTRL_BASE + 0x12B) #define AO_SC_ARM_DBG_KEY0 (AO_CTRL_BASE + 0x12B) #define AO_SC_RESERVED31 (AO_CTRL_BASE + 0x13A) #define AO_SC_RESERVED32 (AO_CTRL_BASE + 0x13A) #define AO_SC_RESERVED33 (AO_CTRL_BASE + 0x13A) #define AO_SC_RESERVED34 (AO_CTRL_BASE + 0x13A) #define AO_SC_RESERVED35 (AO_CTRL_BASE + 0x13B) #define AO_SC_RESERVED36 (AO_CTRL_BASE + 0x13B) #define AO_SC_RESERVED37 (AO_CTRL_BASE + 0x13B) #define AO_SC_RESERVED38 (AO_CTRL_BASE + 0x13B) #define AO_SC_ALWAYSON_SYS_CTRL0 (AO_CTRL_BASE + 0x148) #define AO_SC_ALWAYSON_SYS_CTRL1 (AO_CTRL_BASE + 0x148) #define AO_SC_ALWAYSON_SYS_CTRL2 (AO_CTRL_BASE + 0x148) #define AO_SC_ALWAYSON_SYS_CTRL3 (AO_CTRL_BASE + 0x148) #define AO_SC_ALWAYSON_SYS_CTRL10 (AO_CTRL_BASE + 0x14A) #define AO_SC_ALWAYSON_SYS_CTRL11 (AO_CTRL_BASE + 0x14A) #define AO_SC_ALWAYSON_SYS_STAT0 (AO_CTRL_BASE + 0x14C) #define AO_SC_ALWAYSON_SYS_STAT1 (AO_CTRL_BASE + 0x14C) #define AO_SC_ALWAYSON_SYS_STAT2 (AO_CTRL_BASE + 0x14C) #define AO_SC_ALWAYSON_SYS_STAT3 (AO_CTRL_BASE + 0x14C) #define AO_SC_PWUP_TIME0 (AO_CTRL_BASE + 0x188) #define AO_SC_PWUP_TIME1 (AO_CTRL_BASE + 0x188) #define AO_SC_PWUP_TIME2 (AO_CTRL_BASE + 0x188) #define AO_SC_PWUP_TIME3 (AO_CTRL_BASE + 0x188) #define AO_SC_PWUP_TIME4 (AO_CTRL_BASE + 0x189) #define AO_SC_PWUP_TIME5 (AO_CTRL_BASE + 0x189) #define AO_SC_PWUP_TIME6 (AO_CTRL_BASE + 0x189) #define AO_SC_PWUP_TIME7 (AO_CTRL_BASE + 0x189) #define AO_SC_SECURITY_CTRL1 (AO_CTRL_BASE + 0x1C0) #define AO_SC_SYSTEST_SLICER_CNT0 (AO_CTRL_BASE + 0x890) #define AO_SC_SYSTEST_SLICER_CNT1 (AO_CTRL_BASE + 0x894) #define AO_SC_SYS_CTRL0_MODE_NORMAL 0x004 #define AO_SC_SYS_CTRL0_MODE_MASK 0x007 #define AO_SC_SYS_CTRL1_AARM_WD_RST_CFG (1 << 0) #define AO_SC_SYS_CTRL1_REMAP_SRAM_AARM (1 << 1) #define AO_SC_SYS_CTRL1_EFUSEC_REMAP (1 << 2) #define AO_SC_SYS_CTRL1_EXT_PLL_SEL (1 << 3) #define AO_SC_SYS_CTRL1_MCU_WDG0_RSTMCU_CFG (1 << 4) #define AO_SC_SYS_CTRL1_USIM0_HPD_DE_BOUNCE_CFG (1 << 6) #define AO_SC_SYS_CTRL1_USIM0_HPD_OE_CFG (1 << 7) #define AO_SC_SYS_CTRL1_USIM1_HPD_DE_BOUNCE_CFG (1 << 8) #define AO_SC_SYS_CTRL1_USIM1_HPD_OE_CFG (1 << 9) #define AO_SC_SYS_CTRL1_BUS_DFS_FORE_HD_CFG (1 << 10) #define AO_SC_SYS_CTRL1_BUS_DFS_FORE_HD_CFG1 (1 << 11) #define AO_SC_SYS_CTRL1_USIM0_HPD_OE_SFT (1 << 12) #define AO_SC_SYS_CTRL1_USIM1_HPD_OE_SFT (1 << 13) #define AO_SC_SYS_CTRL1_MCU_CLKEN_HARDCFG (1 << 15) #define AO_SC_SYS_CTRL1_AARM_WD_RST_CFG_MSK (1 << 16) #define AO_SC_SYS_CTRL1_REMAP_SRAM_AARM_MSK (1 << 17) #define AO_SC_SYS_CTRL1_EFUSEC_REMAP_MSK (1 << 18) #define AO_SC_SYS_CTRL1_EXT_PLL_SEL_MSK (1 << 19) #define AO_SC_SYS_CTRL1_MCU_WDG0_RSTMCU_CFG_MSK (1 << 20) #define AO_SC_SYS_CTRL1_USIM0_HPD_DE_BOUNCE_CFG_MSK (1 << 22) #define AO_SC_SYS_CTRL1_USIM0_HPD_OE_CFG_MSK (1 << 23) #define AO_SC_SYS_CTRL1_USIM1_HPD_DE_BOUNCE_CFG_MSK (1 << 24) #define AO_SC_SYS_CTRL1_USIM1_HPD_OE_CFG_MSK (1 << 25) #define AO_SC_SYS_CTRL1_BUS_DFS_FORE_HD_CFG_MSK (1 << 26) #define AO_SC_SYS_CTRL1_BUS_DFS_FORE_HD_CFG1_MSK (1 << 27) #define AO_SC_SYS_CTRL1_USIM0_HPD_OE_SFT_MSK (1 << 28) #define AO_SC_SYS_CTRL1_USIM1_HPD_OE_SFT_MSK (1 << 29) #define AO_SC_SYS_CTRL1_MCU_CLKEN_HARDCFG_MSK (1U << 31) #define AO_SC_SYS_CTRL2_MCU_SFT_RST_STAT_CLEAR (1 << 26) #define AO_SC_SYS_CTRL2_MCU_WDG0_RST_STAT_CLEAR (1 << 27) #define AO_SC_SYS_CTRL2_TSENSOR_RST_STAT_CLEAR (1 << 28) #define AO_SC_SYS_CTRL2_ACPU_WDG_RST_STAT_CLEAR (1 << 29) #define AO_SC_SYS_CTRL2_MCU_WDG1_RST_STAT_CLEAR (1 << 30) #define AO_SC_SYS_CTRL2_GLB_SRST_STAT_CLEAR (1U << 31) #define AO_SC_SYS_STAT0_MCU_RST_STAT (1 << 25) #define AO_SC_SYS_STAT0_MCU_SOFTRST_STAT (1 << 26) #define AO_SC_SYS_STAT0_MCU_WDGRST_STAT (1 << 27) #define AO_SC_SYS_STAT0_TSENSOR_HARDRST_STAT (1 << 28) #define AO_SC_SYS_STAT0_ACPU_WD_GLB_RST_STAT (1 << 29) #define AO_SC_SYS_STAT0_CM3_WDG1_RST_STAT (1 << 30) #define AO_SC_SYS_STAT0_GLB_SRST_STAT (1U << 31) #define AO_SC_SYS_STAT1_MODE_STATUS (1 << 0) #define AO_SC_SYS_STAT1_BOOT_SEL_LOCK (1 << 16) #define AO_SC_SYS_STAT1_FUNC_MODE_LOCK (1 << 17) #define AO_SC_SYS_STAT1_BOOT_MODE_LOCK (1 << 19) #define AO_SC_SYS_STAT1_FUN_JTAG_MODE_OUT (1 << 20) #define AO_SC_SYS_STAT1_SECURITY_BOOT_FLG (1 << 27) #define AO_SC_SYS_STAT1_EFUSE_NANDBOOT_MSK (1 << 28) #define AO_SC_SYS_STAT1_EFUSE_NAND_BITWIDE (1 << 29) #define AO_SC_PERIPH_RSTDIS4_RESET_MCU_ECTR_N (1 << 0) #define AO_SC_PERIPH_RSTDIS4_RESET_MCU_SYS_N (1 << 1) #define AO_SC_PERIPH_RSTDIS4_RESET_MCU_POR_N (1 << 2) #define AO_SC_PERIPH_RSTDIS4_RESET_MCU_DAP_N (1 << 3) #define AO_SC_PERIPH_RSTDIS4_PRESET_CM3_TIMER0_N (1 << 4) #define AO_SC_PERIPH_RSTDIS4_PRESET_CM3_TIMER1_N (1 << 5) #define AO_SC_PERIPH_RSTDIS4_PRESET_CM3_WDT0_N (1 << 6) #define AO_SC_PERIPH_RSTDIS4_PRESET_CM3_WDT1_N (1 << 7) #define AO_SC_PERIPH_RSTDIS4_HRESET_IPC_S_N (1 << 8) #define AO_SC_PERIPH_RSTDIS4_HRESET_IPC_NS_N (1 << 9) #define AO_SC_PERIPH_RSTDIS4_PRESET_EFUSEC_N (1 << 10) #define AO_SC_PERIPH_RSTDIS4_PRESET_WDT0_N (1 << 12) #define AO_SC_PERIPH_RSTDIS4_PRESET_WDT1_N (1 << 13) #define AO_SC_PERIPH_RSTDIS4_PRESET_WDT2_N (1 << 14) #define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER0_N (1 << 15) #define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER1_N (1 << 16) #define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER2_N (1 << 17) #define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER3_N (1 << 18) #define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER4_N (1 << 19) #define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER5_N (1 << 20) #define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER6_N (1 << 21) #define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER7_N (1 << 22) #define AO_SC_PERIPH_RSTDIS4_PRESET_TIMER8_N (1 << 23) #define AO_SC_PERIPH_RSTDIS4_PRESET_UART0_N (1 << 24) #define AO_SC_PERIPH_RSTDIS4_RESET_RTC0_N (1 << 25) #define AO_SC_PERIPH_RSTDIS4_RESET_RTC1_N (1 << 26) #define AO_SC_PERIPH_RSTDIS4_PRESET_PMUSSI_N (1 << 27) #define AO_SC_PERIPH_RSTDIS4_RESET_JTAG_AUTH_N (1 << 28) #define AO_SC_PERIPH_RSTDIS4_RESET_CS_DAPB_ON_N (1 << 29) #define AO_SC_PERIPH_RSTDIS4_MDM_SUBSYS_GLB (1 << 30) #define AO_SC_PERIPH_CLKEN4_HCLK_MCU (1 << 0) #define AO_SC_PERIPH_CLKEN4_CLK_MCU_DAP (1 << 3) #define AO_SC_PERIPH_CLKEN4_PCLK_CM3_TIMER0 (1 << 4) #define AO_SC_PERIPH_CLKEN4_PCLK_CM3_TIMER1 (1 << 5) #define AO_SC_PERIPH_CLKEN4_PCLK_CM3_WDT0 (1 << 6) #define AO_SC_PERIPH_CLKEN4_PCLK_CM3_WDT1 (1 << 7) #define AO_SC_PERIPH_CLKEN4_HCLK_IPC_S (1 << 8) #define AO_SC_PERIPH_CLKEN4_HCLK_IPC_NS (1 << 9) #define AO_SC_PERIPH_CLKEN4_PCLK_EFUSEC (1 << 10) #define AO_SC_PERIPH_CLKEN4_PCLK_TZPC (1 << 11) #define AO_SC_PERIPH_CLKEN4_PCLK_WDT0 (1 << 12) #define AO_SC_PERIPH_CLKEN4_PCLK_WDT1 (1 << 13) #define AO_SC_PERIPH_CLKEN4_PCLK_WDT2 (1 << 14) #define AO_SC_PERIPH_CLKEN4_PCLK_TIMER0 (1 << 15) #define AO_SC_PERIPH_CLKEN4_PCLK_TIMER1 (1 << 16) #define AO_SC_PERIPH_CLKEN4_PCLK_TIMER2 (1 << 17) #define AO_SC_PERIPH_CLKEN4_PCLK_TIMER3 (1 << 18) #define AO_SC_PERIPH_CLKEN4_PCLK_TIMER4 (1 << 19) #define AO_SC_PERIPH_CLKEN4_PCLK_TIMER5 (1 << 20) #define AO_SC_PERIPH_CLKEN4_PCLK_TIMER6 (1 << 21) #define AO_SC_PERIPH_CLKEN4_PCLK_TIMER7 (1 << 22) #define AO_SC_PERIPH_CLKEN4_PCLK_TIMER8 (1 << 23) #define AO_SC_PERIPH_CLKEN4_CLK_UART0 (1 << 24) #define AO_SC_PERIPH_CLKEN4_CLK_RTC0 (1 << 25) #define AO_SC_PERIPH_CLKEN4_CLK_RTC1 (1 << 26) #define AO_SC_PERIPH_CLKEN4_PCLK_PMUSSI (1 << 27) #define AO_SC_PERIPH_CLKEN4_CLK_JTAG_AUTH (1 << 28) #define AO_SC_PERIPH_CLKEN4_CLK_CS_DAPB_ON (1 << 29) #define AO_SC_PERIPH_CLKEN4_CLK_PDM (1 << 30) #define AO_SC_PERIPH_CLKEN4_CLK_SSI_PAD (1U << 31) #define AO_SC_PERIPH_CLKEN5_PCLK_PMUSSI_CCPU (1 << 0) #define AO_SC_PERIPH_CLKEN5_PCLK_EFUSEC_CCPU (1 << 1) #define AO_SC_PERIPH_CLKEN5_HCLK_IPC_CCPU (1 << 2) #define AO_SC_PERIPH_CLKEN5_HCLK_IPC_NS_CCPU (1 << 3) #define AO_SC_PERIPH_CLKEN5_PCLK_PMUSSI_MCU (1 << 16) #define AO_SC_PERIPH_CLKEN5_PCLK_EFUSEC_MCU (1 << 17) #define AO_SC_PERIPH_CLKEN5_HCLK_IPC_MCU (1 << 18) #define AO_SC_PERIPH_CLKEN5_HCLK_IPC_NS_MCU (1 << 19) #define AO_SC_MCU_SUBSYS_CTRL3_RCLK_3 0x003 #define AO_SC_MCU_SUBSYS_CTRL3_RCLK_MASK 0x007 #define AO_SC_MCU_SUBSYS_CTRL3_CSSYS_CTRL_PROT (1 << 3) #define AO_SC_MCU_SUBSYS_CTRL3_TCXO_AFC_OEN_CRG (1 << 4) #define AO_SC_MCU_SUBSYS_CTRL3_AOB_IO_SEL18_USIM1 (1 << 8) #define AO_SC_MCU_SUBSYS_CTRL3_AOB_IO_SEL18_USIM0 (1 << 9) #define AO_SC_MCU_SUBSYS_CTRL3_AOB_IO_SEL18_SD (1 << 10) #define AO_SC_MCU_SUBSYS_CTRL3_MCU_SUBSYS_CTRL3_RESERVED (1 << 11) #define PCLK_TIMER1 (1 << 16) #define PCLK_TIMER0 (1 << 15) #endif /* HI6220_REGS_AO_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey/include/hi6220_regs_peri.h000066400000000000000000000317411355360272700257160ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HI6220_REGS_PERI_H #define HI6220_REGS_PERI_H #define PERI_BASE 0xF7030000 #define PERI_SC_PERIPH_CTRL1 (PERI_BASE + 0x000) #define PERI_SC_PERIPH_CTRL2 (PERI_BASE + 0x004) #define PERI_SC_PERIPH_CTRL3 (PERI_BASE + 0x008) #define PERI_SC_PERIPH_CTRL4 (PERI_BASE + 0x00c) #define PERI_SC_PERIPH_CTRL5 (PERI_BASE + 0x010) #define PERI_SC_PERIPH_CTRL6 (PERI_BASE + 0x014) #define PERI_SC_PERIPH_CTRL8 (PERI_BASE + 0x018) #define PERI_SC_PERIPH_CTRL9 (PERI_BASE + 0x01c) #define PERI_SC_PERIPH_CTRL10 (PERI_BASE + 0x020) #define PERI_SC_PERIPH_CTRL12 (PERI_BASE + 0x024) #define PERI_SC_PERIPH_CTRL13 (PERI_BASE + 0x028) #define PERI_SC_PERIPH_CTRL14 (PERI_BASE + 0x02c) #define PERI_SC_DDR_CTRL0 (PERI_BASE + 0x050) #define PERI_SC_PERIPH_STAT1 (PERI_BASE + 0x094) #define PERI_SC_PERIPH_CLKEN0 (PERI_BASE + 0x200) #define PERI_SC_PERIPH_CLKDIS0 (PERI_BASE + 0x204) #define PERI_SC_PERIPH_CLKSTAT0 (PERI_BASE + 0x208) #define PERI_SC_PERIPH_CLKEN1 (PERI_BASE + 0x210) #define PERI_SC_PERIPH_CLKDIS1 (PERI_BASE + 0x214) #define PERI_SC_PERIPH_CLKSTAT1 (PERI_BASE + 0x218) #define PERI_SC_PERIPH_CLKEN2 (PERI_BASE + 0x220) #define PERI_SC_PERIPH_CLKDIS2 (PERI_BASE + 0x224) #define PERI_SC_PERIPH_CLKSTAT2 (PERI_BASE + 0x228) #define PERI_SC_PERIPH_CLKEN3 (PERI_BASE + 0x230) #define PERI_SC_PERIPH_CLKDIS3 (PERI_BASE + 0x234) #define PERI_SC_PERIPH_CLKSTAT3 (PERI_BASE + 0x238) #define PERI_SC_PERIPH_CLKEN8 (PERI_BASE + 0x240) #define PERI_SC_PERIPH_CLKDIS8 (PERI_BASE + 0x244) #define PERI_SC_PERIPH_CLKSTAT8 (PERI_BASE + 0x248) #define PERI_SC_PERIPH_CLKEN9 (PERI_BASE + 0x250) #define PERI_SC_PERIPH_CLKDIS9 (PERI_BASE + 0x254) #define PERI_SC_PERIPH_CLKSTAT9 (PERI_BASE + 0x258) #define PERI_SC_PERIPH_CLKEN10 (PERI_BASE + 0x260) #define PERI_SC_PERIPH_CLKDIS10 (PERI_BASE + 0x264) #define PERI_SC_PERIPH_CLKSTAT10 (PERI_BASE + 0x268) #define PERI_SC_PERIPH_CLKEN12 (PERI_BASE + 0x270) #define PERI_SC_PERIPH_CLKDIS12 (PERI_BASE + 0x274) #define PERI_SC_PERIPH_CLKSTAT12 (PERI_BASE + 0x278) #define PERI_SC_PERIPH_RSTEN0 (PERI_BASE + 0x300) #define PERI_SC_PERIPH_RSTDIS0 (PERI_BASE + 0x304) #define PERI_SC_PERIPH_RSTSTAT0 (PERI_BASE + 0x308) #define PERI_SC_PERIPH_RSTEN1 (PERI_BASE + 0x310) #define PERI_SC_PERIPH_RSTDIS1 (PERI_BASE + 0x314) #define PERI_SC_PERIPH_RSTSTAT1 (PERI_BASE + 0x318) #define PERI_SC_PERIPH_RSTEN2 (PERI_BASE + 0x320) #define PERI_SC_PERIPH_RSTDIS2 (PERI_BASE + 0x324) #define PERI_SC_PERIPH_RSTSTAT2 (PERI_BASE + 0x328) #define PERI_SC_PERIPH_RSTEN3 (PERI_BASE + 0x330) #define PERI_SC_PERIPH_RSTDIS3 (PERI_BASE + 0x334) #define PERI_SC_PERIPH_RSTSTAT3 (PERI_BASE + 0x338) #define PERI_SC_PERIPH_RSTEN8 (PERI_BASE + 0x340) #define PERI_SC_PERIPH_RSTDIS8 (PERI_BASE + 0x344) #define PERI_SC_PERIPH_RSTSTAT8 (PERI_BASE + 0x338) #define PERI_SC_CLK_SEL0 (PERI_BASE + 0x400) #define PERI_SC_CLKCFG8BIT1 (PERI_BASE + 0x494) #define PERI_SC_CLKCFG8BIT2 (PERI_BASE + 0x498) #define PERI_SC_RESERVED8_ADDR (PERI_BASE + 0xd04) /* PERI_SC_PERIPH_CTRL1 */ #define PERI_CTRL1_ETR_AXI_CSYSREQ_N (1 << 0) #define PERI_CTRL1_ETR_AXI_CSYSREQ_N (1 << 0) #define PERI_CTRL1_HIFI_INT_MASK (1 << 1) #define PERI_CTRL1_HIFI_ALL_INT_MASK (1 << 2) #define PERI_CTRL1_ETR_AXI_CSYSREQ_N_MSK (1 << 16) #define PERI_CTRL1_HIFI_INT_MASK_MSK (1 << 17) #define PERI_CTRL1_HIFI_ALL_INT_MASK_MSK (1 << 18) /* PERI_SC_PERIPH_CTRL2 */ #define PERI_CTRL2_MMC_CLK_PHASE_BYPASS_EN_MMC0 (1 << 0) #define PERI_CTRL2_MMC_CLK_PHASE_BYPASS_EN_MMC1 (1 << 2) #define PERI_CTRL2_NAND_SYS_MEM_SEL (1 << 6) #define PERI_CTRL2_G3D_DDRT_AXI_SEL (1 << 7) #define PERI_CTRL2_GU_MDM_BBP_TESTPIN_SEL (1 << 8) #define PERI_CTRL2_CODEC_SSI_MASTER_CHECK (1 << 9) #define PERI_CTRL2_FUNC_TEST_SOFT (1 << 12) #define PERI_CTRL2_CSSYS_TS_ENABLE (1 << 15) #define PERI_CTRL2_HIFI_RAMCTRL_S_EMA (1 << 16) #define PERI_CTRL2_HIFI_RAMCTRL_S_EMAW (1 << 20) #define PERI_CTRL2_HIFI_RAMCTRL_S_EMAS (1 << 22) #define PERI_CTRL2_HIFI_RAMCTRL_S_RET1N (1 << 26) #define PERI_CTRL2_HIFI_RAMCTRL_S_RET2N (1 << 27) #define PERI_CTRL2_HIFI_RAMCTRL_S_PGEN (1 << 28) /* PERI_SC_PERIPH_CTRL3 */ #define PERI_CTRL3_HIFI_DDR_HARQMEM_ADDR (1 << 0) #define PERI_CTRL3_HIFI_HARQMEMRMP_EN (1 << 12) #define PERI_CTRL3_HARQMEM_SYS_MED_SEL (1 << 13) #define PERI_CTRL3_SOC_AP_OCCUPY_GRP1 (1 << 14) #define PERI_CTRL3_SOC_AP_OCCUPY_GRP2 (1 << 16) #define PERI_CTRL3_SOC_AP_OCCUPY_GRP3 (1 << 18) #define PERI_CTRL3_SOC_AP_OCCUPY_GRP4 (1 << 20) #define PERI_CTRL3_SOC_AP_OCCUPY_GRP5 (1 << 22) #define PERI_CTRL3_SOC_AP_OCCUPY_GRP6 (1 << 24) /* PERI_SC_PERIPH_CTRL4 */ #define PERI_CTRL4_PICO_FSELV (1 << 0) #define PERI_CTRL4_FPGA_EXT_PHY_SEL (1 << 3) #define PERI_CTRL4_PICO_REFCLKSEL (1 << 4) #define PERI_CTRL4_PICO_SIDDQ (1 << 6) #define PERI_CTRL4_PICO_SUSPENDM_SLEEPM (1 << 7) #define PERI_CTRL4_PICO_OGDISABLE (1 << 8) #define PERI_CTRL4_PICO_COMMONONN (1 << 9) #define PERI_CTRL4_PICO_VBUSVLDEXT (1 << 10) #define PERI_CTRL4_PICO_VBUSVLDEXTSEL (1 << 11) #define PERI_CTRL4_PICO_VATESTENB (1 << 12) #define PERI_CTRL4_PICO_SUSPENDM (1 << 14) #define PERI_CTRL4_PICO_SLEEPM (1 << 15) #define PERI_CTRL4_BC11_C (1 << 16) #define PERI_CTRL4_BC11_B (1 << 17) #define PERI_CTRL4_BC11_A (1 << 18) #define PERI_CTRL4_BC11_GND (1 << 19) #define PERI_CTRL4_BC11_FLOAT (1 << 20) #define PERI_CTRL4_OTG_PHY_SEL (1 << 21) #define PERI_CTRL4_USB_OTG_SS_SCALEDOWN_MODE (1 << 22) #define PERI_CTRL4_OTG_DM_PULLDOWN (1 << 24) #define PERI_CTRL4_OTG_DP_PULLDOWN (1 << 25) #define PERI_CTRL4_OTG_IDPULLUP (1 << 26) #define PERI_CTRL4_OTG_DRVBUS (1 << 27) #define PERI_CTRL4_OTG_SESSEND (1 << 28) #define PERI_CTRL4_OTG_BVALID (1 << 29) #define PERI_CTRL4_OTG_AVALID (1 << 30) #define PERI_CTRL4_OTG_VBUSVALID (1U << 31) /* PERI_SC_PERIPH_CTRL5 */ #define PERI_CTRL5_USBOTG_RES_SEL (1 << 3) #define PERI_CTRL5_PICOPHY_ACAENB (1 << 4) #define PERI_CTRL5_PICOPHY_BC_MODE (1 << 5) #define PERI_CTRL5_PICOPHY_CHRGSEL (1 << 6) #define PERI_CTRL5_PICOPHY_VDATSRCEND (1 << 7) #define PERI_CTRL5_PICOPHY_VDATDETENB (1 << 8) #define PERI_CTRL5_PICOPHY_DCDENB (1 << 9) #define PERI_CTRL5_PICOPHY_IDDIG (1 << 10) #define PERI_CTRL5_DBG_MUX (1 << 11) /* PERI_SC_PERIPH_CTRL6 */ #define PERI_CTRL6_CSSYSOFF_RAMCTRL_S_EMA (1 << 0) #define PERI_CTRL6_CSSYSOFF_RAMCTRL_S_EMAW (1 << 4) #define PERI_CTRL6_CSSYSOFF_RAMCTRL_S_EMAS (1 << 6) #define PERI_CTRL6_CSSYSOFF_RAMCTRL_S_RET1N (1 << 10) #define PERI_CTRL6_CSSYSOFF_RAMCTRL_S_RET2N (1 << 11) #define PERI_CTRL6_CSSYSOFF_RAMCTRL_S_PGEN (1 << 12) /* PERI_SC_PERIPH_CTRL8 */ #define PERI_CTRL8_PICOPHY_TXRISETUNE0 (1 << 0) #define PERI_CTRL8_PICOPHY_TXPREEMPAMPTUNE0 (1 << 2) #define PERI_CTRL8_PICOPHY_TXRESTUNE0 (1 << 4) #define PERI_CTRL8_PICOPHY_TXHSSVTUNE0 (1 << 6) #define PERI_CTRL8_PICOPHY_COMPDISTUNE0 (1 << 8) #define PERI_CTRL8_PICOPHY_TXPREEMPPULSETUNE0 (1 << 11) #define PERI_CTRL8_PICOPHY_OTGTUNE0 (1 << 12) #define PERI_CTRL8_PICOPHY_SQRXTUNE0 (1 << 16) #define PERI_CTRL8_PICOPHY_TXVREFTUNE0 (1 << 20) #define PERI_CTRL8_PICOPHY_TXFSLSTUNE0 (1 << 28) /* PERI_SC_PERIPH_CTRL9 */ #define PERI_CTRL9_PICOPLY_TESTCLKEN (1 << 0) #define PERI_CTRL9_PICOPLY_TESTDATAOUTSEL (1 << 1) #define PERI_CTRL9_PICOPLY_TESTADDR (1 << 4) #define PERI_CTRL9_PICOPLY_TESTDATAIN (1 << 8) /* * PERI_SC_PERIPH_CLKEN0 * PERI_SC_PERIPH_CLKDIS0 * PERI_SC_PERIPH_CLKSTAT0 */ #define PERI_CLK0_MMC0 (1 << 0) #define PERI_CLK0_MMC1 (1 << 1) #define PERI_CLK0_MMC2 (1 << 2) #define PERI_CLK0_NANDC (1 << 3) #define PERI_CLK0_USBOTG (1 << 4) #define PERI_CLK0_PICOPHY (1 << 5) #define PERI_CLK0_PLL (1 << 6) /* * PERI_SC_PERIPH_CLKEN1 * PERI_SC_PERIPH_CLKDIS1 * PERI_SC_PERIPH_CLKSTAT1 */ #define PERI_CLK1_HIFI (1 << 0) #define PERI_CLK1_DIGACODEC (1 << 5) /* * PERI_SC_PERIPH_CLKEN2 * PERI_SC_PERIPH_CLKDIS2 * PERI_SC_PERIPH_CLKSTAT2 */ #define PERI_CLK2_IPF (1 << 0) #define PERI_CLK2_SOCP (1 << 1) #define PERI_CLK2_DMAC (1 << 2) #define PERI_CLK2_SECENG (1 << 3) #define PERI_CLK2_HPM0 (1 << 5) #define PERI_CLK2_HPM1 (1 << 6) #define PERI_CLK2_HPM2 (1 << 7) #define PERI_CLK2_HPM3 (1 << 8) /* * PERI_SC_PERIPH_CLKEN3 * PERI_SC_PERIPH_CLKDIS3 * PERI_SC_PERIPH_CLKSTAT3 */ #define PERI_CLK3_CSSYS (1 << 0) #define PERI_CLK3_I2C0 (1 << 1) #define PERI_CLK3_I2C1 (1 << 2) #define PERI_CLK3_I2C2 (1 << 3) #define PERI_CLK3_I2C3 (1 << 4) #define PERI_CLK3_UART1 (1 << 5) #define PERI_CLK3_UART2 (1 << 6) #define PERI_CLK3_UART3 (1 << 7) #define PERI_CLK3_UART4 (1 << 8) #define PERI_CLK3_SSP (1 << 9) #define PERI_CLK3_PWM (1 << 10) #define PERI_CLK3_BLPWM (1 << 11) #define PERI_CLK3_TSENSOR (1 << 12) #define PERI_CLK3_GPS (1 << 15) #define PERI_CLK3_TCXO_PAD0 (1 << 16) #define PERI_CLK3_TCXO_PAD1 (1 << 17) #define PERI_CLK3_DAPB (1 << 18) #define PERI_CLK3_HKADC (1 << 19) #define PERI_CLK3_CODEC_SSI (1 << 20) #define PERI_CLK3_TZPC_DEP (1 << 21) /* * PERI_SC_PERIPH_CLKEN8 * PERI_SC_PERIPH_CLKDIS8 * PERI_SC_PERIPH_CLKSTAT8 */ #define PERI_CLK8_RS0 (1 << 0) #define PERI_CLK8_RS2 (1 << 1) #define PERI_CLK8_RS3 (1 << 2) #define PERI_CLK8_MS0 (1 << 3) #define PERI_CLK8_MS2 (1 << 5) #define PERI_CLK8_XG2RAM0 (1 << 6) #define PERI_CLK8_X2SRAM (1 << 7) #define PERI_CLK8_SRAM (1 << 8) #define PERI_CLK8_ROM (1 << 9) #define PERI_CLK8_HARQ (1 << 10) #define PERI_CLK8_MMU (1 << 11) #define PERI_CLK8_DDRC (1 << 12) #define PERI_CLK8_DDRPHY (1 << 13) #define PERI_CLK8_DDRPHY_REF (1 << 14) #define PERI_CLK8_X2X_SYSNOC (1 << 15) #define PERI_CLK8_X2X_CCPU (1 << 16) #define PERI_CLK8_DDRT (1 << 17) #define PERI_CLK8_DDRPACK_RS (1 << 18) /* * PERI_SC_PERIPH_CLKEN9 * PERI_SC_PERIPH_CLKDIS9 * PERI_SC_PERIPH_CLKSTAT9 */ #define PERI_CLK9_CARM_DAP (1 << 0) #define PERI_CLK9_CARM_ATB (1 << 1) #define PERI_CLK9_CARM_LBUS (1 << 2) #define PERI_CLK9_CARM_KERNEL (1 << 3) /* * PERI_SC_PERIPH_CLKEN10 * PERI_SC_PERIPH_CLKDIS10 * PERI_SC_PERIPH_CLKSTAT10 */ #define PERI_CLK10_IPF_CCPU (1 << 0) #define PERI_CLK10_SOCP_CCPU (1 << 1) #define PERI_CLK10_SECENG_CCPU (1 << 2) #define PERI_CLK10_HARQ_CCPU (1 << 3) #define PERI_CLK10_IPF_MCU (1 << 16) #define PERI_CLK10_SOCP_MCU (1 << 17) #define PERI_CLK10_SECENG_MCU (1 << 18) #define PERI_CLK10_HARQ_MCU (1 << 19) /* * PERI_SC_PERIPH_CLKEN12 * PERI_SC_PERIPH_CLKDIS12 * PERI_SC_PERIPH_CLKSTAT12 */ #define PERI_CLK12_HIFI_SRC (1 << 0) #define PERI_CLK12_MMC0_SRC (1 << 1) #define PERI_CLK12_MMC1_SRC (1 << 2) #define PERI_CLK12_MMC2_SRC (1 << 3) #define PERI_CLK12_SYSPLL_DIV (1 << 4) #define PERI_CLK12_TPIU_SRC (1 << 5) #define PERI_CLK12_MMC0_HF (1 << 6) #define PERI_CLK12_MMC1_HF (1 << 7) #define PERI_CLK12_PLL_TEST_SRC (1 << 8) #define PERI_CLK12_CODEC_SOC (1 << 9) #define PERI_CLK12_MEDIA (1 << 10) /* * PERI_SC_PERIPH_RSTEN0 * PERI_SC_PERIPH_RSTDIS0 * PERI_SC_PERIPH_RSTSTAT0 */ #define PERI_RST0_MMC0 (1 << 0) #define PERI_RST0_MMC1 (1 << 1) #define PERI_RST0_MMC2 (1 << 2) #define PERI_RST0_NANDC (1 << 3) #define PERI_RST0_USBOTG_BUS (1 << 4) #define PERI_RST0_POR_PICOPHY (1 << 5) #define PERI_RST0_USBOTG (1 << 6) #define PERI_RST0_USBOTG_32K (1 << 7) /* * PERI_SC_PERIPH_RSTEN1 * PERI_SC_PERIPH_RSTDIS1 * PERI_SC_PERIPH_RSTSTAT1 */ #define PERI_RST1_HIFI (1 << 0) #define PERI_RST1_DIGACODEC (1 << 5) /* * PERI_SC_PERIPH_RSTEN2 * PERI_SC_PERIPH_RSTDIS2 * PERI_SC_PERIPH_RSTSTAT2 */ #define PERI_RST2_IPF (1 << 0) #define PERI_RST2_SOCP (1 << 1) #define PERI_RST2_DMAC (1 << 2) #define PERI_RST2_SECENG (1 << 3) #define PERI_RST2_ABB (1 << 4) #define PERI_RST2_HPM0 (1 << 5) #define PERI_RST2_HPM1 (1 << 6) #define PERI_RST2_HPM2 (1 << 7) #define PERI_RST2_HPM3 (1 << 8) /* * PERI_SC_PERIPH_RSTEN3 * PERI_SC_PERIPH_RSTDIS3 * PERI_SC_PERIPH_RSTSTAT3 */ #define PERI_RST3_CSSYS (1 << 0) #define PERI_RST3_I2C0 (1 << 1) #define PERI_RST3_I2C1 (1 << 2) #define PERI_RST3_I2C2 (1 << 3) #define PERI_RST3_I2C3 (1 << 4) #define PERI_RST3_UART1 (1 << 5) #define PERI_RST3_UART2 (1 << 6) #define PERI_RST3_UART3 (1 << 7) #define PERI_RST3_UART4 (1 << 8) #define PERI_RST3_SSP (1 << 9) #define PERI_RST3_PWM (1 << 10) #define PERI_RST3_BLPWM (1 << 11) #define PERI_RST3_TSENSOR (1 << 12) #define PERI_RST3_DAPB (1 << 18) #define PERI_RST3_HKADC (1 << 19) #define PERI_RST3_CODEC (1 << 20) /* * PERI_SC_PERIPH_RSTEN8 * PERI_SC_PERIPH_RSTDIS8 * PERI_SC_PERIPH_RSTSTAT8 */ #define PERI_RST8_RS0 (1 << 0) #define PERI_RST8_RS2 (1 << 1) #define PERI_RST8_RS3 (1 << 2) #define PERI_RST8_MS0 (1 << 3) #define PERI_RST8_MS2 (1 << 5) #define PERI_RST8_XG2RAM0 (1 << 6) #define PERI_RST8_X2SRAM_TZMA (1 << 7) #define PERI_RST8_SRAM (1 << 8) #define PERI_RST8_HARQ (1 << 10) #define PERI_RST8_DDRC (1 << 12) #define PERI_RST8_DDRC_APB (1 << 13) #define PERI_RST8_DDRPACK_APB (1 << 14) #define PERI_RST8_DDRT (1 << 17) #endif /* HI6220_REGS_PERI_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey/include/hi6220_regs_pin.h000066400000000000000000000023461355360272700255440ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HI6220_REGS_PIN_H #define HI6220_REGS_PIN_H #define IOMG_BASE 0xF7010000 #define IOMG_SD_CLK (IOMG_BASE + 0x0C) #define IOMG_SD_CMD (IOMG_BASE + 0x10) #define IOMG_SD_DATA0 (IOMG_BASE + 0x14) #define IOMG_SD_DATA1 (IOMG_BASE + 0x18) #define IOMG_SD_DATA2 (IOMG_BASE + 0x1C) #define IOMG_SD_DATA3 (IOMG_BASE + 0x20) #define IOMG_GPIO24 (IOMG_BASE + 0x140) #define IOMG_MUX_FUNC0 0 #define IOMG_MUX_FUNC1 1 #define IOMG_MUX_FUNC2 2 #define IOCG1_BASE 0xF7010800 #define IOCG2_BASE 0xF8001800 #define IOCG_SD_CLK (IOCG1_BASE + 0x0C) #define IOCG_SD_CMD (IOCG1_BASE + 0x10) #define IOCG_SD_DATA0 (IOCG1_BASE + 0x14) #define IOCG_SD_DATA1 (IOCG1_BASE + 0x18) #define IOCG_SD_DATA2 (IOCG1_BASE + 0x1C) #define IOCG_SD_DATA3 (IOCG1_BASE + 0x20) #define IOCG_GPIO24 (IOCG1_BASE + 0x150) #define IOCG_GPIO8 (IOCG2_BASE + 0x30) #define IOCG_DRIVE_8MA (2 << 4) #define IOCG_DRIVE_10MA (3 << 4) #define IOCG_INPUT_16MA 0x64 #define IOCG_INPUT_12MA 0x54 #define IOCG_PULLDOWN (1 << 1) #define IOCG_PULLUP (1 << 0) #endif /* HI6220_REGS_PIN_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey/include/hi6220_regs_pmctrl.h000066400000000000000000000107001355360272700262500ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HI6220_REGS_PMCTRL_H #define HI6220_REGS_PMCTRL_H #define PMCTRL_BASE 0xF7032000 #define PMCTRL_ACPUPLLCTRL (PMCTRL_BASE + 0x000) #define PMCTRL_ACPUPLLFREQ (PMCTRL_BASE + 0x004) #define PMCTRL_DDRPLL1CTRL (PMCTRL_BASE + 0x010) #define PMCTRL_DDRPLL0CTRL (PMCTRL_BASE + 0x030) #define PMCTRL_MEDPLLCTRL (PMCTRL_BASE + 0x038) #define PMCTRL_ACPUPLLSEL (PMCTRL_BASE + 0x100) #define PMCTRL_ACPUCLKDIV (PMCTRL_BASE + 0x104) #define PMCTRL_ACPUSYSPLLCFG (PMCTRL_BASE + 0x110) #define PMCTRL_ACPUCLKOFFCFG (PMCTRL_BASE + 0x114) #define PMCTRL_ACPUPLLFRAC (PMCTRL_BASE + 0x134) #define PMCTRL_ACPUPMUVOLUPTIME (PMCTRL_BASE + 0x360) #define PMCTRL_ACPUPMUVOLDNTIME (PMCTRL_BASE + 0x364) #define PMCTRL_ACPUVOLPMUADDR (PMCTRL_BASE + 0x368) #define PMCTRL_ACPUVOLUPSTEP (PMCTRL_BASE + 0x36c) #define PMCTRL_ACPUVOLDNSTEP (PMCTRL_BASE + 0x370) #define PMCTRL_ACPUDFTVOL (PMCTRL_BASE + 0x374) #define PMCTRL_ACPUDESTVOL (PMCTRL_BASE + 0x378) #define PMCTRL_ACPUVOLTTIMEOUT (PMCTRL_BASE + 0x37c) #define PMCTRL_ACPUPLLCTRL_EN_CFG (1 << 0) #define PMCTRL_ACPUCLKDIV_CPUEXT_CFG_MASK (3 << 0) #define PMCTRL_ACPUCLKDIV_DDR_CFG_MASK (3 << 8) #define PMCTRL_ACPUCLKDIV_CPUEXT_STAT_MASK (3 << 16) #define PMCTRL_ACPUCLKDIV_DDR_STAT_MASK (3 << 24) #define PMCTRL_ACPUPLLSEL_ACPUPLL_CFG (1 << 0) #define PMCTRL_ACPUPLLSEL_ACPUPLL_STAT (1 << 1) #define PMCTRL_ACPUPLLSEL_SYSPLL_STAT (1 << 2) #define PMCTRL_ACPUSYSPLL_CLKDIV_CFG_MASK 0x7 #define PMCTRL_ACPUSYSPLL_CLKEN_CFG (1 << 4) #define PMCTRL_ACPUSYSPLL_CLKDIV_SW (3 << 12) #define PMCTRL_ACPUSYSPLLCFG_SYSPLL_CLKEN (1 << 4) #define PMCTRL_ACPUSYSPLLCFG_CLKDIV_MASK (3 << 12) #define PMCTRL_ACPUDESTVOL_DEST_VOL_MASK 0x7f #define PMCTRL_ACPUDESTVOL_CURR_VOL_MASK (0x7f << 8) #define SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_START (0) #define SOC_PMCTRL_ACPUPLLCTRL_acpupll_en_cfg_END (0) #define SOC_PMCTRL_ACPUPLLCTRL_acpupll_rst_START (2) #define SOC_PMCTRL_ACPUPLLCTRL_acpupll_rst_END (2) #define SOC_PMCTRL_ACPUPLLCTRL_acpupll_time_START (4) #define SOC_PMCTRL_ACPUPLLCTRL_acpupll_time_END (27) #define SOC_PMCTRL_ACPUPLLCTRL_acpupll_timeout_START (28) #define SOC_PMCTRL_ACPUPLLCTRL_acpupll_timeout_END (28) #define SOC_PMCTRL_ACPUPLLCTRL_acpupll_lock_START (29) #define SOC_PMCTRL_ACPUPLLCTRL_acpupll_lock_END (29) #define SOC_PMCTRL_ACPUPLLFRAC_ADDR(base) ((base) + (0x134)) #define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_subsys_clk_div_sw_START (12) #define SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_cfg_START (0) #define SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_cfg_END (0) #define SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_stat_START (1) #define SOC_PMCTRL_ACPUPLLSEL_acpu_pllsw_stat_END (1) #define SOC_PMCTRL_ACPUPLLSEL_syspll_sw_stat_START (2) #define SOC_PMCTRL_ACPUPLLSEL_syspll_sw_stat_END (2) #define SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_START (0) #define SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_cfg_END (1) #define SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_START (8) #define SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_cfg_END (9) #define SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_stat_START (16) #define SOC_PMCTRL_ACPUCLKDIV_cpuext_clk_div_stat_END (17) #define SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_stat_START (24) #define SOC_PMCTRL_ACPUCLKDIV_acpu_ddr_clk_div_stat_END (25) #define SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_START (0) #define SOC_PMCTRL_ACPUDESTVOL_acpu_dest_vol_END (6) #define SOC_PMCTRL_ACPUDESTVOL_acpu_vol_using_START (8) #define SOC_PMCTRL_ACPUDESTVOL_acpu_vol_using_END (14) #define SOC_PMCTRL_ACPUVOLTIMEOUT_acpu_vol_timeout_START (0) #define SOC_PMCTRL_ACPUVOLTIMEOUT_acpu_vol_timeout_END (0) #define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_div_cfg_START (0) #define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_div_cfg_END (2) #define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_cfg_START (4) #define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_cfg_END (4) #define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_subsys_clk_div_cfg_START (8) #define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_subsys_clk_div_cfg_END (9) #define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_div_stat_START (16) #define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_div_stat_END (19) #define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_stat_START (20) #define SOC_PMCTRL_ACPUSYSPLLCFG_acpu_syspll_clken_stat_END (20) #endif /* HI6220_REGS_PMCTRL_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey/include/hi6553.h000066400000000000000000000071421355360272700236660ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HI6553_H #define HI6553_H #include #include #define HI6553_DISABLE6_XO_CLK (PMUSSI_BASE + (0x036 << 2)) #define DISABLE6_XO_CLK_BB (1 << 0) #define DISABLE6_XO_CLK_CONN (1 << 1) #define DISABLE6_XO_CLK_NFC (1 << 2) #define DISABLE6_XO_CLK_RF1 (1 << 3) #define DISABLE6_XO_CLK_RF2 (1 << 4) #define HI6553_VERSION_REG (PMUSSI_BASE + (0x000 << 2)) #define HI6553_IRQ2_MASK (PMUSSI_BASE + (0x008 << 2)) #define HI6553_ENABLE2_LDO1_8 (PMUSSI_BASE + (0x029 << 2)) #define HI6553_DISABLE2_LDO1_8 (PMUSSI_BASE + (0x02a << 2)) #define HI6553_ONOFF_STATUS2_LDO1_8 (PMUSSI_BASE + (0x02b << 2)) #define HI6553_ENABLE3_LDO9_16 (PMUSSI_BASE + (0x02c << 2)) #define HI6553_DISABLE3_LDO9_16 (PMUSSI_BASE + (0x02d << 2)) #define HI6553_ONOFF_STATUS3_LDO9_16 (PMUSSI_BASE + (0x02e << 2)) #define HI6553_ENABLE4_LDO17_22 (PMUSSI_BASE + (0x02f << 2)) #define HI6553_DISABLE4_LDO17_22 (PMUSSI_BASE + (0x030 << 2)) #define HI6553_ONOFF_STATUS4_LDO17_22 (PMUSSI_BASE + (0x031 << 2)) #define HI6553_PERI_EN_MARK (PMUSSI_BASE + (0x040 << 2)) #define HI6553_BUCK2_REG1 (PMUSSI_BASE + (0x04a << 2)) #define HI6553_BUCK2_REG5 (PMUSSI_BASE + (0x04e << 2)) #define HI6553_BUCK2_REG6 (PMUSSI_BASE + (0x04f << 2)) #define HI6553_BUCK3_REG3 (PMUSSI_BASE + (0x054 << 2)) #define HI6553_BUCK3_REG5 (PMUSSI_BASE + (0x056 << 2)) #define HI6553_BUCK3_REG6 (PMUSSI_BASE + (0x057 << 2)) #define HI6553_BUCK4_REG2 (PMUSSI_BASE + (0x05b << 2)) #define HI6553_BUCK4_REG5 (PMUSSI_BASE + (0x05e << 2)) #define HI6553_BUCK4_REG6 (PMUSSI_BASE + (0x05f << 2)) #define HI6553_CLK_TOP0 (PMUSSI_BASE + (0x063 << 2)) #define HI6553_CLK_TOP3 (PMUSSI_BASE + (0x066 << 2)) #define HI6553_CLK_TOP4 (PMUSSI_BASE + (0x067 << 2)) #define HI6553_VSET_BUCK2_ADJ (PMUSSI_BASE + (0x06d << 2)) #define HI6553_VSET_BUCK3_ADJ (PMUSSI_BASE + (0x06e << 2)) #define HI6553_LDO7_REG_ADJ (PMUSSI_BASE + (0x078 << 2)) #define HI6553_LDO10_REG_ADJ (PMUSSI_BASE + (0x07b << 2)) #define HI6553_LDO15_REG_ADJ (PMUSSI_BASE + (0x080 << 2)) #define HI6553_LDO19_REG_ADJ (PMUSSI_BASE + (0x084 << 2)) #define HI6553_LDO20_REG_ADJ (PMUSSI_BASE + (0x085 << 2)) #define HI6553_LDO21_REG_ADJ (PMUSSI_BASE + (0x086 << 2)) #define HI6553_LDO22_REG_ADJ (PMUSSI_BASE + (0x087 << 2)) #define HI6553_DR_LED_CTRL (PMUSSI_BASE + (0x098 << 2)) #define HI6553_DR_OUT_CTRL (PMUSSI_BASE + (0x099 << 2)) #define HI6553_DR3_ISET (PMUSSI_BASE + (0x09a << 2)) #define HI6553_DR3_START_DEL (PMUSSI_BASE + (0x09b << 2)) #define HI6553_DR4_ISET (PMUSSI_BASE + (0x09c << 2)) #define HI6553_DR4_START_DEL (PMUSSI_BASE + (0x09d << 2)) #define HI6553_DR345_TIM_CONF0 (PMUSSI_BASE + (0x0a0 << 2)) #define HI6553_NP_REG_ADJ1 (PMUSSI_BASE + (0x0be << 2)) #define HI6553_NP_REG_CHG (PMUSSI_BASE + (0x0c0 << 2)) #define HI6553_BUCK01_CTRL2 (PMUSSI_BASE + (0x0d9 << 2)) #define HI6553_BUCK0_CTRL1 (PMUSSI_BASE + (0x0dd << 2)) #define HI6553_BUCK0_CTRL5 (PMUSSI_BASE + (0x0e1 << 2)) #define HI6553_BUCK0_CTRL7 (PMUSSI_BASE + (0x0e3 << 2)) #define HI6553_BUCK1_CTRL1 (PMUSSI_BASE + (0x0e8 << 2)) #define HI6553_BUCK1_CTRL5 (PMUSSI_BASE + (0x0ec << 2)) #define HI6553_BUCK1_CTRL7 (PMUSSI_BASE + (0x0ef << 2)) #define HI6553_CLK19M2_600_586_EN (PMUSSI_BASE + (0x0fe << 2)) #define LED_START_DELAY_TIME 0x00 #define LED_ELEC_VALUE 0x07 #define LED_LIGHT_TIME 0xf0 #define LED_GREEN_ENABLE (1 << 1) #define LED_OUT_CTRL 0x00 #define PMU_HI6552_V300 0x30 #define PMU_HI6552_V310 0x31 #endif /* HI6553_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey/include/hikey_def.h000066400000000000000000000066261355360272700247000ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HIKEY_DEF_H #define HIKEY_DEF_H /* Always assume DDR is 1GB size. */ #define DDR_BASE 0x0 #define DDR_SIZE 0x40000000 #define DEVICE_BASE 0xF4000000 #define DEVICE_SIZE 0x05800000 /* Memory location options for TSP */ #define HIKEY_SRAM_ID 0 #define HIKEY_DRAM_ID 1 /* * DDR for OP-TEE (32MB from 0x3E00000-0x3FFFFFFF) is divided in several * regions * - Secure DDR (default is the top 16MB) used by OP-TEE * - Non-secure DDR used by OP-TEE (shared memory and padding) (4MB) * - Secure DDR (4MB aligned on 4MB) for OP-TEE's "Secure Data Path" feature * - Non-secure DDR (8MB) reserved for OP-TEE's future use */ #define DDR_SEC_SIZE 0x01000000 #define DDR_SEC_BASE (DDR_BASE + DDR_SIZE - DDR_SEC_SIZE) /* 0x3F000000 */ #define DDR_SDP_SIZE 0x00400000 #define DDR_SDP_BASE (DDR_SEC_BASE - 0x400000 /* align */ - \ DDR_SDP_SIZE) #define SRAM_BASE 0xFFF80000 #define SRAM_SIZE 0x00012000 /* * PL011 related constants */ #define PL011_UART0_BASE 0xF8015000 #define PL011_UART2_BASE 0xF7112000 #define PL011_UART3_BASE 0xF7113000 #define PL011_BAUDRATE 115200 #define PL011_UART_CLK_IN_HZ 19200000 #define HIKEY_USB_DESC_BASE (DDR_BASE + 0x00800000) #define HIKEY_USB_DESC_SIZE 0x00100000 #define HIKEY_USB_DATA_BASE (DDR_BASE + 0x10000000) #define HIKEY_USB_DATA_SIZE 0x10000000 #define HIKEY_FB_BUFFER_BASE (HIKEY_USB_DATA_BASE) #define HIKEY_FB_BUFFER_SIZE HIKEY_USB_DATA_SIZE #define HIKEY_FB_DOWNLOAD_BASE (HIKEY_FB_BUFFER_BASE + \ HIKEY_FB_BUFFER_SIZE) #define HIKEY_FB_DOWNLOAD_SIZE HIKEY_USB_DATA_SIZE #define HIKEY_USB_DESC_IN_BASE (DDR_BASE + 0x00800000) #define HIKEY_USB_DESC_IN_SIZE 0x00040000 #define HIKEY_USB_DESC_EP0_OUT_BASE (HIKEY_USB_DESC_IN_BASE + \ HIKEY_USB_DESC_IN_SIZE) #define HIKEY_USB_DESC_EP0_OUT_SIZE 0x00040000 #define HIKEY_USB_DESC_EPX_OUT_BASE (HIKEY_USB_DESC_EP0_OUT_BASE + \ HIKEY_USB_DESC_EP0_OUT_SIZE) #define HIKEY_USB_DESC_EPX_OUT_SIZE 0x00080000 #define HIKEY_MMC_DESC_BASE (DDR_BASE + 0x03000000) #define HIKEY_MMC_DESC_SIZE 0x00100000 /* * HIKEY_MMC_DATA_BASE & HIKEY_MMC_DATA_SIZE are shared between fastboot * and eMMC driver. Since it could avoid to memory copy. * So this SRAM region is used twice. First, it's used in BL1 as temporary * buffer in eMMC driver. Second, it's used by MCU in BL2. The SRAM region * needs to be clear before used in BL2. */ #define HIKEY_MMC_DATA_BASE (DDR_BASE + 0x10000000) #define HIKEY_MMC_DATA_SIZE 0x20000000 #define HIKEY_NS_IMAGE_OFFSET (DDR_BASE + 0x35000000) #define HIKEY_BL1_MMC_DESC_BASE (SRAM_BASE) #define HIKEY_BL1_MMC_DESC_SIZE 0x00001000 #define HIKEY_BL1_MMC_DATA_BASE (HIKEY_BL1_MMC_DESC_BASE + \ HIKEY_BL1_MMC_DESC_SIZE) #define HIKEY_BL1_MMC_DATA_SIZE 0x0000B000 #define EMMC_BASE 0 #define HIKEY_EMMC_RPMB_BASE (EMMC_BASE + 0) #define HIKEY_EMMC_RPMB_MAX_SIZE (128 << 10) #define HIKEY_EMMC_USERDATA_BASE (EMMC_BASE + 0) #define HIKEY_EMMC_USERDATA_MAX_SIZE (4 << 30) /* * GIC400 interrupt handling related constants */ #define IRQ_SEC_PHY_TIMER 29 #define IRQ_SEC_SGI_0 8 #define IRQ_SEC_SGI_1 9 #define IRQ_SEC_SGI_2 10 #define IRQ_SEC_SGI_3 11 #define IRQ_SEC_SGI_4 12 #define IRQ_SEC_SGI_5 13 #define IRQ_SEC_SGI_6 14 #define IRQ_SEC_SGI_7 15 #define IRQ_SEC_SGI_8 16 #endif /* HIKEY_DEF_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey/include/hikey_layout.h000066400000000000000000000064261355360272700254550ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HIKEY_LAYOUT_H #define HIKEY_LAYOUT_H /* * Platform memory map related constants */ #define XG2RAM0_BASE 0xF9800000 #define XG2RAM0_SIZE 0x00400000 /* * BL1 is stored in XG2RAM0_HIRQ that is 784KB large (0xF980_0000~0xF98C_4000). */ #define ONCHIPROM_PARAM_BASE (XG2RAM0_BASE + 0x700) #define LOADER_RAM_BASE (XG2RAM0_BASE + 0x800) #define BL1_XG2RAM0_OFFSET 0x1000 /* * BL1 specific defines. * * Both loader and BL1_RO region stay in SRAM since they are used to simulate * ROM. * Loader is used to switch Hi6220 SoC from 32-bit to 64-bit mode. * * ++++++++++ 0xF980_0000 * + loader + * ++++++++++ 0xF980_1000 * + BL1_RO + * ++++++++++ 0xF981_8000 * + BL1_RW + * ++++++++++ 0xF989_8000 */ #define BL1_RO_BASE (XG2RAM0_BASE + BL1_XG2RAM0_OFFSET) #define BL1_RO_LIMIT (XG2RAM0_BASE + 0x18000) #define BL1_RW_BASE (BL1_RO_LIMIT) /* 0xf981_8000 */ #define BL1_RW_SIZE (0x00080000) #define BL1_RW_LIMIT (0xF9898000) /* * Non-Secure BL1U specific defines. */ #define NS_BL1U_BASE (0xf9828000) #define NS_BL1U_SIZE (0x00010000) #define NS_BL1U_LIMIT (NS_BL1U_BASE + NS_BL1U_SIZE) /* * BL2 specific defines. * * Both loader and BL2 region stay in SRAM. * Loader is used to switch Hi6220 SoC from 32-bit to 64-bit mode. * * ++++++++++ 0xF980_0000 * + loader + * ++++++++++ 0xF980_1000 * + BL2 + * ++++++++++ 0xF983_0000 */ #define BL2_BASE (BL1_RO_BASE) /* 0xf980_1000 */ #define BL2_LIMIT (0xF9830000) /* 0xf983_0000 */ /* * SCP_BL2 specific defines. * In HiKey, SCP_BL2 means MCU firmware. It's loaded into the temporary buffer * at 0x0100_0000. Then BL2 will parse the sections and loaded them into * predefined separated buffers. */ #define SCP_BL2_BASE (DDR_BASE + 0x01000000) #define SCP_BL2_LIMIT (SCP_BL2_BASE + 0x00100000) #define SCP_BL2_SIZE (SCP_BL2_LIMIT - SCP_BL2_BASE) /* * BL31 specific defines. */ #define BL31_BASE (0xF9858000) /* 0xf985_8000 */ #define BL31_LIMIT (0xF9898000) /* * BL3-2 specific defines. */ /* * The TSP currently executes from TZC secured area of DRAM or SRAM. */ #define BL32_SRAM_BASE BL31_LIMIT #define BL32_SRAM_LIMIT (BL31_LIMIT+0x80000) /* 512K */ #define BL32_DRAM_BASE DDR_SEC_BASE #define BL32_DRAM_LIMIT (DDR_SEC_BASE+DDR_SEC_SIZE) #ifdef SPD_opteed /* Load pageable part of OP-TEE at end of allocated DRAM space for BL32 */ #define HIKEY_OPTEE_PAGEABLE_LOAD_BASE (BL32_DRAM_LIMIT - HIKEY_OPTEE_PAGEABLE_LOAD_SIZE) /* 0x3FC0_0000 */ #define HIKEY_OPTEE_PAGEABLE_LOAD_SIZE 0x400000 /* 4MB */ #endif #if (HIKEY_TSP_RAM_LOCATION_ID == HIKEY_DRAM_ID) #define TSP_SEC_MEM_BASE BL32_DRAM_BASE #define TSP_SEC_MEM_SIZE (BL32_DRAM_LIMIT - BL32_DRAM_BASE) #define BL32_BASE BL32_DRAM_BASE #define BL32_LIMIT BL32_DRAM_LIMIT #elif (HIKEY_TSP_RAM_LOCATION_ID == HIKEY_SRAM_ID) #define TSP_SEC_MEM_BASE BL32_SRAM_BASE #define TSP_SEC_MEM_SIZE (BL32_SRAM_LIMIT - BL32_SRAM_BASE) #define BL32_BASE BL32_SRAM_BASE #define BL32_LIMIT BL32_SRAM_LIMIT #else #error "Currently unsupported HIKEY_TSP_LOCATION_ID value" #endif /* BL32 is mandatory in AArch32 */ #ifdef __aarch64__ #ifdef SPD_none #undef BL32_BASE #endif /* SPD_none */ #endif #endif /* HIKEY_LAYOUT_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey/include/hisi_ipc.h000066400000000000000000000026741355360272700245370ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HISI_IPC_H #define HISI_IPC_H #define HISI_IPC_CORE_ACPU 0x0 #define HISI_IPC_MCU_INT_SRC_ACPU0_PD 10 #define HISI_IPC_MCU_INT_SRC_ACPU1_PD 11 #define HISI_IPC_MCU_INT_SRC_ACPU2_PD 12 #define HISI_IPC_MCU_INT_SRC_ACPU3_PD 13 #define HISI_IPC_MCU_INT_SRC_ACPU_PD 16 #define HISI_IPC_MCU_INT_SRC_ACPU4_PD 26 #define HISI_IPC_MCU_INT_SRC_ACPU5_PD 27 #define HISI_IPC_MCU_INT_SRC_ACPU6_PD 28 #define HISI_IPC_MCU_INT_SRC_ACPU7_PD 29 #define HISI_IPC_SEM_CPUIDLE 27 #define HISI_IPC_INT_SRC_NUM 32 #define HISI_IPC_PM_ON 0 #define HISI_IPC_PM_OFF 1 #define HISI_IPC_OK (0) #define HISI_IPC_ERROR (-1) #define HISI_IPC_BASE_ADDR (0xF7510000) #define HISI_IPC_CPU_RAW_INT_ADDR (0xF7510420) #define HISI_IPC_ACPU_CTRL(i) (0xF7510800 + (i << 3)) void hisi_ipc_spin_lock(unsigned int signal); void hisi_ipc_spin_unlock(unsigned int signal); void hisi_ipc_cpu_on(unsigned int cpu, unsigned int cluster); void hisi_ipc_cpu_off(unsigned int cpu, unsigned int cluster); void hisi_ipc_cpu_suspend(unsigned int cpu, unsigned int cluster); void hisi_ipc_cluster_on(unsigned int cpu, unsigned int cluster); void hisi_ipc_cluster_off(unsigned int cpu, unsigned int cluster); void hisi_ipc_cluster_suspend(unsigned int cpu, unsigned int cluster); void hisi_ipc_psci_system_off(void); int hisi_ipc_init(void); #endif /* HISI_IPC_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey/include/hisi_mcu.h000066400000000000000000000005541355360272700245430ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HISI_MCU_H #define HISI_MCU_H #include extern void hisi_mcu_enable_sram(void); extern void hisi_mcu_start_run(void); extern int hisi_mcu_load_image(uintptr_t image_base, uint32_t image_size); #endif /* HISI_MCU_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey/include/hisi_pwrc.h000066400000000000000000000007641355360272700247350ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HISI_PWRC_H #define HISI_PWRC_H #ifndef __ASSEMBLER__ void hisi_pwrc_set_cluster_wfi(unsigned int id); void hisi_pwrc_set_core_bx_addr(unsigned int core, unsigned int cluster, uintptr_t entry_point); void hisi_pwrc_enable_debug(unsigned int core, unsigned int cluster); int hisi_pwrc_setup(void); #endif /*__ASSEMBLER__*/ #endif /* HISI_PWRC_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey/include/hisi_sip_svc.h000066400000000000000000000010321355360272700254150ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HISI_SIP_SVC_H #define HISI_SIP_SVC_H /* SMC function IDs for SiP Service queries */ #define HISI_SIP_SVC_CALL_COUNT 0x8200ff00 #define HISI_SIP_SVC_UID 0x8200ff01 /* 0x8200ff02 is reserved */ #define HISI_SIP_SVC_VERSION 0x8200ff03 /* HISI SiP Service Calls version numbers */ #define HISI_SIP_SVC_VERSION_MAJOR 0x0 #define HISI_SIP_SVC_VERSION_MINOR 0x1 #endif /* HISI_SIP_SVC_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey/include/hisi_sram_map.h000066400000000000000000000314331355360272700255560ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HISI_SRAM_MAP_H #define HISI_SRAM_MAP_H /* * SRAM Memory Region Layout * * +-----------------------+ * | Low Power Mode | 7KB * +-----------------------+ * | Secure OS | 64KB * +-----------------------+ * | Software Flag | 1KB * +-----------------------+ * */ #define SOC_SRAM_OFF_BASE_ADDR (0xFFF80000) /* PM Section: 7KB */ #define SRAM_PM_ADDR (SOC_SRAM_OFF_BASE_ADDR) #define SRAM_PM_SIZE (0x00001C00) /* TEE OS Section: 64KB */ #define SRAM_TEEOS_ADDR (SRAM_PM_ADDR + SRAM_PM_SIZE) #define SRAM_TEEOS_SIZE (0x00010000) /* General Use Section: 1KB */ #define SRAM_GENERAL_ADDR (SRAM_TEEOS_ADDR + SRAM_TEEOS_SIZE) #define SRAM_GENERAL_SIZE (0x00000400) /* * General Usage Section Layout: * * +-----------------------+ * | AP boot flag | 64B * +-----------------------+ * | DICC flag | 32B * +-----------------------+ * | Soft flag | 256B * +-----------------------+ * | Thermal flag | 128B * +-----------------------+ * | CSHELL | 4B * +-----------------------+ * | Uart Switching | 4B * +-----------------------+ * | ICC | 1024B * +-----------------------+ * | Memory Management | 1024B * +-----------------------+ * | IFC | 32B * +-----------------------+ * | HIFI | 32B * +-----------------------+ * | DDR capacity | 4B * +-----------------------+ * | Reserved | * +-----------------------+ * */ /* App Core Boot Flags */ #define MEMORY_AXI_ACPU_START_ADDR (SRAM_GENERAL_ADDR) #define MEMORY_AXI_ACPU_START_SIZE (64) #define MEMORY_AXI_SRESET_FLAG_ADDR (MEMORY_AXI_ACPU_START_ADDR + 0x0000) #define MEMORY_AXI_SECOND_CPU_BOOT_ADDR (MEMORY_AXI_ACPU_START_ADDR + 0x0004) #define MEMORY_AXI_READY_FLAG_ADDR (MEMORY_AXI_ACPU_START_ADDR + 0x0008) #define MEMORY_AXI_FASTBOOT_ENTRY_ADDR (MEMORY_AXI_ACPU_START_ADDR + 0x000C) #define MEMORY_AXI_PD_CHARGE_ADDR (MEMORY_AXI_ACPU_START_ADDR + 0x0010) #define MEMORY_AXI_DBG_ALARM_ADDR (MEMORY_AXI_ACPU_START_ADDR + 0x0014) #define MEMORY_AXI_CHIP_ADDR (MEMORY_AXI_ACPU_START_ADDR + 0x0018) #define MEMORY_AXI_BOARD_TYPE_ADDR (MEMORY_AXI_ACPU_START_ADDR + 0x001C) #define MEMORY_AXI_BOARD_ID_ADDR (MEMORY_AXI_ACPU_START_ADDR + 0x0020) #define MEMORY_AXI_CHARGETYPE_FLAG_ADDR (MEMORY_AXI_ACPU_START_ADDR + 0x0024) #define MEMORY_AXI_COLD_START_ADDR (MEMORY_AXI_ACPU_START_ADDR + 0x0028) #define MEMORY_AXI_ANDROID_REBOOT_FLAG_ADDR (MEMORY_AXI_ACPU_START_ADDR + 0x002C) #define MEMORY_AXI_ACPU_WDTRST_REBOOT_FLAG_ADDR (MEMORY_AXI_ACPU_START_ADDR + 0x0030) #define MEMORY_AXI_ABNRST_BITMAP_ADDR (MEMORY_AXI_ACPU_START_ADDR + 0x0034) #define MEMORY_AXI_32K_CLK_TYPE_ADDR (MEMORY_AXI_ACPU_START_ADDR + 0x0038) #define AXI_MODEM_PANIC_FLAG_ADDR (MEMORY_AXI_ACPU_START_ADDR + 0x003C) #define AXI_MODEM_PANIC_FLAG (0x68697369) #define MEMORY_AXI_ACPU_END_ADDR (AXI_MODEM_PANIC_FLAG_ADDR + 4) /* DICC Flags */ #define MEMORY_AXI_DICC_ADDR (MEMORY_AXI_ACPU_START_ADDR + MEMORY_AXI_ACPU_START_SIZE) #define MEMORY_AXI_DICC_SIZE (32) #define MEMORY_AXI_SOFT_FLAG_ADDR (MEMORY_AXI_DICC_ADDR + MEMORY_AXI_DICC_SIZE) #define MEMORY_AXI_SOFT_FLAG_SIZE (256) /* Thermal Flags */ #define MEMORY_AXI_TEMP_PROTECT_ADDR (MEMORY_AXI_SOFT_FLAG_ADDR + MEMORY_AXI_SOFT_FLAG_SIZE) #define MEMORY_AXI_TEMP_PROTECT_SIZE (128) /* CSHELL */ #define MEMORY_AXI_USB_CSHELL_ADDR (MEMORY_AXI_TEMP_PROTECT_ADDR + MEMORY_AXI_TEMP_PROTECT_SIZE) #define MEMORY_AXI_USB_CSHELL_SIZE (4) /* Uart and A/C Shell Switch Flags */ #define MEMORY_AXI_UART_INOUT_ADDR (MEMORY_AXI_USB_CSHELL_ADDR + MEMORY_AXI_USB_CSHELL_SIZE) #define MEMORY_AXI_UART_INOUT_SIZE (4) /* IFC Flags */ #define MEMORY_AXI_IFC_ADDR (MEMORY_AXI_UART_INOUT_ADDR + MEMORY_AXI_UART_INOUT_SIZE) #define MEMORY_AXI_IFC_SIZE (32) /* HIFI Data */ #define MEMORY_AXI_HIFI_ADDR (MEMORY_AXI_IFC_ADDR + MEMORY_AXI_IFC_SIZE) #define MEMORY_AXI_HIFI_SIZE (32) /* CONFIG Flags */ #define MEMORY_AXI_CONFIG_ADDR (MEMORY_AXI_HIFI_ADDR + MEMORY_AXI_HIFI_SIZE) #define MEMORY_AXI_CONFIG_SIZE (32) /* DDR Capacity Flags */ #define MEMORY_AXI_DDR_CAPACITY_ADDR (MEMORY_AXI_CONFIG_ADDR + MEMORY_AXI_CONFIG_SIZE) #define MEMORY_AXI_DDR_CAPACITY_SIZE (4) /* USB Shell Flags */ #define MEMORY_AXI_USB_SHELL_FLAG_ADDR (MEMORY_AXI_DDR_CAPACITY_ADDR + MEMORY_AXI_DDR_CAPACITY_SIZE) #define MEMORY_AXI_USB_SHELL_FLAG_SIZE (4) /* MCU WDT Switch Flag */ #define MEMORY_AXI_MCU_WDT_FLAG_ADDR (MEMORY_AXI_USB_SHELL_FLAG_ADDR + MEMORY_AXI_USB_SHELL_FLAG_SIZE) #define MEMORY_AXI_MCU_WDT_FLAG_SIZE (4) /* TLDSP Mailbox MNTN */ #define SRAM_DSP_MNTN_INFO_ADDR (MEMORY_AXI_MCU_WDT_FLAG_ADDR + MEMORY_AXI_MCU_WDT_FLAG_SIZE) #define SRAM_DSP_MNTN_SIZE (32) /* TLDSP ARM Mailbox Protect Flag */ #define SRAM_DSP_ARM_MAILBOX_PROTECT_FLAG_ADDR (SRAM_DSP_MNTN_INFO_ADDR + SRAM_DSP_MNTN_SIZE) #define SRAM_DSP_ARM_MAILBOX_PROTECT_FLAG_SIZE (4) /* RTT Sleep Flag */ #define SRAM_RTT_SLEEP_FLAG_ADDR (SRAM_DSP_ARM_MAILBOX_PROTECT_FLAG_ADDR + SRAM_DSP_ARM_MAILBOX_PROTECT_FLAG_SIZE) #define SRAM_RTT_SLEEP_FLAG_SIZE (32) /* LDSP Awake Flag */ #define MEMORY_AXI_LDSP_AWAKE_ADDR (SRAM_RTT_SLEEP_FLAG_ADDR + SRAM_RTT_SLEEP_FLAG_SIZE) #define MEMORY_AXI_LDSP_AWAKE_SIZE (4) #define NVUPDATE_SUCCESS 0x5555AAAA #define NVUPDATE_FAILURE 0xAAAA5555 /* * Low Power Mode Region */ #define PWRCTRL_ACPU_ASM_SPACE_ADDR (SRAM_PM_ADDR) #define PWRCTRL_ACPU_ASM_SPACE_SIZE (SRAM_PM_SIZE) #define PWRCTRL_ACPU_ASM_MEM_BASE (PWRCTRL_ACPU_ASM_SPACE_ADDR) #define PWRCTRL_ACPU_ASM_MEM_SIZE (PWRCTRL_ACPU_ASM_SPACE_SIZE) #define PWRCTRL_ACPU_ASM_CODE_BASE (PWRCTRL_ACPU_ASM_MEM_BASE + 0x200) #define PWRCTRL_ACPU_ASM_DATA_BASE (PWRCTRL_ACPU_ASM_MEM_BASE + 0xE00) #define PWRCTRL_ACPU_ASM_DATA_SIZE (0xE00) #define PWRCTRL_ACPU_ASM_D_C0_ADDR (PWRCTRL_ACPU_ASM_DATA_BASE) #define PWRCTRL_ACPU_ASM_D_C0_MMU_PARA_AD (PWRCTRL_ACPU_ASM_DATA_BASE + 0) #define PWRCTRL_ACPU_ASM_D_ARM_PARA_AD (PWRCTRL_ACPU_ASM_DATA_BASE + 0x20) #define PWRCTRL_ACPU_ASM_D_COMM_ADDR (PWRCTRL_ACPU_ASM_DATA_BASE + 0x700) #define PWRCTRL_ACPU_REBOOT (PWRCTRL_ACPU_ASM_D_COMM_ADDR) #define PWRCTRL_ACPU_REBOOT_SIZE (0x200) #define PWRCTRL_ACPU_ASM_SLICE_BAK_ADDR (PWRCTRL_ACPU_REBOOT + PWRCTRL_ACPU_REBOOT_SIZE) #define PWRCTRL_ACPU_ASM_SLICE_BAK_SIZE (4) #define PWRCTRL_ACPU_ASM_DEBUG_FLAG_ADDR (PWRCTRL_ACPU_ASM_SLICE_BAK_ADDR + PWRCTRL_ACPU_ASM_SLICE_BAK_SIZE) #define PWRCTRL_ACPU_ASM_DEBUG_FLAG_SIZE (4) #define EXCH_A_CORE_POWRCTRL_CONV_ADDR (PWRCTRL_ACPU_ASM_DEBUG_FLAG_ADDR + PWRCTRL_ACPU_ASM_DEBUG_FLAG_SIZE) #define EXCH_A_CORE_POWRCTRL_CONV_SIZE (4) /* * Below region memory mapping is: * 4 + 12 + 16 + 28 + 28 + 16 + 28 + 12 + 24 + 20 + 64 + * 4 + 4 + 4 + 4 + 12 + 4 + 4 + 4 + 4 + 16 + 4 + 0x2BC + * 24 + 20 + 12 + 16 */ #define MEMORY_AXI_CPU_IDLE_ADDR (EXCH_A_CORE_POWRCTRL_CONV_ADDR + EXCH_A_CORE_POWRCTRL_CONV_SIZE) #define MEMORY_AXI_CPU_IDLE_SIZE (4) #define MEMORY_AXI_CUR_FREQ_ADDR (MEMORY_AXI_CPU_IDLE_ADDR + MEMORY_AXI_CPU_IDLE_SIZE) #define MEMORY_AXI_CUR_FREQ_SIZE (12) #define MEMORY_AXI_ACPU_FREQ_VOL_ADDR (MEMORY_AXI_CUR_FREQ_ADDR + MEMORY_AXI_CUR_FREQ_SIZE) #define MEMORY_AXI_ACPU_FREQ_VOL_SIZE (16 + 28 + 28) #define MEMORY_AXI_DDR_FREQ_VOL_ADDR (MEMORY_AXI_ACPU_FREQ_VOL_ADDR + MEMORY_AXI_ACPU_FREQ_VOL_SIZE) #define MEMORY_AXI_DDR_FREQ_VOL_SIZE (16 + 28) #define MEMORY_AXI_ACPU_FIQ_TEST_ADDR (MEMORY_AXI_DDR_FREQ_VOL_ADDR + MEMORY_AXI_DDR_FREQ_VOL_SIZE) #define MEMORY_AXI_ACPU_FIQ_TEST_SIZE (12) #define MEMORY_AXI_ACPU_FIQ_CPU_INFO_ADDR (MEMORY_AXI_ACPU_FIQ_TEST_ADDR + MEMORY_AXI_ACPU_FIQ_TEST_SIZE) #define MEMORY_AXI_ACPU_FIQ_CPU_INFO_SIZE (24) #define MEMORY_AXI_ACPU_FIQ_DEBUG_INFO_ADDR (MEMORY_AXI_ACPU_FIQ_CPU_INFO_ADDR + MEMORY_AXI_ACPU_FIQ_CPU_INFO_SIZE) #define MEMORY_AXI_ACPU_FIQ_DEBUG_INFO_SIZE (20) #define MEMORY_FREQDUMP_ADDR (MEMORY_AXI_ACPU_FIQ_DEBUG_INFO_ADDR + MEMORY_AXI_ACPU_FIQ_DEBUG_INFO_SIZE) #define MEMORY_FREQDUMP_SIZE (64) #define MEMORY_AXI_CCPU_LOG_ADDR (MEMORY_FREQDUMP_ADDR + MEMORY_FREQDUMP_SIZE) #define MEMORY_AXI_CCPU_LOG_SIZE (4) #define MEMORY_AXI_MCU_LOG_ADDR (MEMORY_AXI_CCPU_LOG_ADDR + MEMORY_AXI_CCPU_LOG_SIZE) #define MEMORY_AXI_MCU_LOG_SIZE (4) #define MEMORY_AXI_SEC_CORE_BOOT_ADDR (MEMORY_AXI_MCU_LOG_ADDR + MEMORY_AXI_MCU_LOG_SIZE) #define MEMORY_AXI_SEC_CORE_BOOT_SIZE (4) #define MEMORY_AXI_BBP_PS_VOTE_FLAG_ADDR (MEMORY_AXI_SEC_CORE_BOOT_ADDR + MEMORY_AXI_SEC_CORE_BOOT_SIZE) #define MEMORY_AXI_BBP_PS_VOTE_FLAG_SIZE (0x4) #define POLICY_AREA_RESERVED (MEMORY_AXI_BBP_PS_VOTE_FLAG_ADDR + MEMORY_AXI_BBP_PS_VOTE_FLAG_SIZE) #define POLICY_AREA_RESERVED_SIZE (12) #define DDR_POLICY_VALID_MAGIC (POLICY_AREA_RESERVED + POLICY_AREA_RESERVED_SIZE) #define DDR_POLICY_VALID_MAGIC_SIZE (4) #define DDR_POLICY_MAX_NUM (DDR_POLICY_VALID_MAGIC + DDR_POLICY_VALID_MAGIC_SIZE) #define DDR_POLICY_MAX_NUM_SIZE (4) #define DDR_POLICY_SUPPORT_NUM (DDR_POLICY_MAX_NUM + DDR_POLICY_MAX_NUM_SIZE) #define DDR_POLICY_SUPPORT_NUM_SIZE (4) #define DDR_POLICY_CUR_POLICY (DDR_POLICY_SUPPORT_NUM + DDR_POLICY_SUPPORT_NUM_SIZE) #define DDR_POLICY_CUR_POLICY_SIZE (4) #define ACPU_POLICY_VALID_MAGIC (DDR_POLICY_CUR_POLICY + DDR_POLICY_CUR_POLICY_SIZE) #define ACPU_POLICY_VALID_MAGIC_SIZE (4) #define ACPU_POLICY_MAX_NUM (ACPU_POLICY_VALID_MAGIC + ACPU_POLICY_VALID_MAGIC_SIZE) #define ACPU_POLICY_MAX_NUM_SIZE (4) #define ACPU_POLICY_SUPPORT_NUM (ACPU_POLICY_MAX_NUM + ACPU_POLICY_MAX_NUM_SIZE) #define ACPU_POLICY_SUPPORT_NUM_SIZE (4) #define ACPU_POLICY_CUR_POLICY (ACPU_POLICY_SUPPORT_NUM + ACPU_POLICY_SUPPORT_NUM_SIZE) #define ACPU_POLICY_CUR_POLICY_SIZE (4) #define LPDDR_OPTION_ADDR (ACPU_POLICY_CUR_POLICY + ACPU_POLICY_CUR_POLICY_SIZE) #define LPDDR_OPTION_SIZE (4) #define MEMORY_AXI_DDR_DDL_ADDR (LPDDR_OPTION_ADDR + LPDDR_OPTION_SIZE) #define MEMORY_AXI_DDR_DDL_SIZE (0x2BC) #define DDR_TEST_DFS_ADDR (MEMORY_AXI_DDR_DDL_ADDR + MEMORY_AXI_DDR_DDL_SIZE) #define DDR_TEST_DFS_ADDR_SIZE (4) #define DDR_TEST_DFS_TIMES_ADDR (DDR_TEST_DFS_ADDR + DDR_TEST_DFS_ADDR_SIZE) #define DDR_TEST_DFS_TIMES_ADDR_SIZE (4) #define DDR_TEST_QOS_ADDR (DDR_TEST_DFS_TIMES_ADDR + DDR_TEST_DFS_TIMES_ADDR_SIZE) #define DDR_TEST_QOS_ADDR_SIZE (4) #define DDR_TEST_FUN_ADDR (DDR_TEST_QOS_ADDR + DDR_TEST_QOS_ADDR_SIZE) #define DDR_TEST_FUN_ADDR_SIZE (4) #define BOARD_TYPE_ADDR (DDR_TEST_FUN_ADDR + DDR_TEST_FUN_ADDR_SIZE) #define BOARD_ADDR_SIZE (4) #define DDR_DFS_FREQ_ADDR (BOARD_TYPE_ADDR + BOARD_ADDR_SIZE) #define DDR_DFS_FREQ_SIZE (4) #define DDR_PASR_ADDR (DDR_DFS_FREQ_ADDR + DDR_DFS_FREQ_SIZE) #define DDR_PASR_SIZE (20) #define ACPU_DFS_FREQ_ADDR (DDR_PASR_ADDR + DDR_PASR_SIZE) #define ACPU_DFS_FREQ_ADDR_SIZE (12) #define ACPU_CHIP_MAX_FREQ (ACPU_DFS_FREQ_ADDR + ACPU_DFS_FREQ_ADDR_SIZE) #define ACPU_CHIP_MAX_FREQ_SIZE (4) #define MEMORY_MEDPLL_STATE_ADDR (ACPU_CHIP_MAX_FREQ + ACPU_CHIP_MAX_FREQ_SIZE) #define MEMORY_MEDPLL_STATE_SIZE (8) #define MEMORY_CCPU_LOAD_FLAG_ADDR (MEMORY_MEDPLL_STATE_ADDR + MEMORY_MEDPLL_STATE_SIZE) #define MEMORY_CCPU_LOAD_FLAG_SIZE (4) #define ACPU_CORE_BITS_ADDR (MEMORY_CCPU_LOAD_FLAG_ADDR + MEMORY_CCPU_LOAD_FLAG_SIZE) #define ACPU_CORE_BITS_SIZE (4) #define ACPU_CLUSTER_IDLE_ADDR (ACPU_CORE_BITS_ADDR + ACPU_CORE_BITS_SIZE) #define ACPU_CLUSTER_IDLE_SIZE (4) #define ACPU_A53_FLAGS_ADDR (ACPU_CLUSTER_IDLE_ADDR + ACPU_CLUSTER_IDLE_SIZE) #define ACPU_A53_FLAGS_SIZE (4) #define ACPU_POWER_STATE_QOS_ADDR (ACPU_A53_FLAGS_ADDR+ACPU_A53_FLAGS_SIZE) #define ACPU_POWER_STATE_QOS_SIZE (4) #define ACPU_UNLOCK_CORE_FLAGS_ADDR (ACPU_POWER_STATE_QOS_ADDR+ACPU_POWER_STATE_QOS_SIZE) #define ACPU_UNLOCK_CORE_FLAGS_SIZE (8) #define ACPU_SUBSYS_POWERDOWN_FLAGS_ADDR (ACPU_UNLOCK_CORE_FLAGS_ADDR + ACPU_UNLOCK_CORE_FLAGS_SIZE) #define ACPU_SUBSYS_POWERDOWN_FLAGS_SIZE (4) #define ACPU_CORE_POWERDOWN_FLAGS_ADDR (ACPU_SUBSYS_POWERDOWN_FLAGS_ADDR + ACPU_SUBSYS_POWERDOWN_FLAGS_SIZE) #define ACPU_CORE_POWERDOWN_FLAGS_SIZE (4) #define ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR (ACPU_CORE_POWERDOWN_FLAGS_ADDR + ACPU_CORE_POWERDOWN_FLAGS_SIZE) #define ACPU_CLUSTER_POWERDOWN_FLAGS_SIZE (4) #define ACPU_ARM64_FLAGA (ACPU_CLUSTER_POWERDOWN_FLAGS_ADDR + ACPU_CLUSTER_POWERDOWN_FLAGS_SIZE) #define ACPU_ARM64_FLAGA_SIZE (4) #define ACPU_ARM64_FLAGB (ACPU_ARM64_FLAGA + ACPU_ARM64_FLAGA_SIZE) #define ACPU_ARM64_FLAGB_SIZE (4) #define MCU_EXCEPTION_FLAGS_ADDR (ACPU_ARM64_FLAGB + ACPU_ARM64_FLAGB_SIZE) #define MCU_EXCEPTION_FLAGS_SIZE (4) #define ACPU_MASTER_CORE_STATE_ADDR (MCU_EXCEPTION_FLAGS_ADDR + MCU_EXCEPTION_FLAGS_SIZE) #define ACPU_MASTER_CORE_STATE_SIZE (4) #define PWRCTRL_AXI_RESERVED_ADDR (ACPU_MASTER_CORE_STATE_ADDR + ACPU_MASTER_CORE_STATE_SIZE) #endif /* HISI_SRAM_MAP_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey/include/plat_macros.S000066400000000000000000000037111355360272700252200ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S #include #include #include #include .section .rodata.gic_reg_name, "aS" gicc_regs: .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", "" gicd_pend_reg: .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n" newline: .asciz "\n" spacer: .asciz ":\t\t0x" .section .rodata.cci_reg_name, "aS" cci_iface_regs: .asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , "" /* --------------------------------------------- * The below macro prints out relevant GIC * registers whenever an unhandled exception is * taken in BL31. * --------------------------------------------- */ .macro plat_crash_print_regs mov_imm x16, PLAT_ARM_GICD_BASE mov_imm x17, PLAT_ARM_GICC_BASE /* Load the gicc reg list to x6 */ adr x6, gicc_regs /* Load the gicc regs to gp regs used by str_in_crash_buf_print */ ldr w8, [x17, #GICC_HPPIR] ldr w9, [x17, #GICC_AHPPIR] ldr w10, [x17, #GICC_CTLR] /* Store to the crash buf and print to cosole */ bl str_in_crash_buf_print /* Print the GICD_ISPENDR regs */ add x7, x16, #GICD_ISPENDR adr x4, gicd_pend_reg bl asm_print_str 2: sub x4, x7, x16 cmp x4, #0x280 b.eq 1f bl asm_print_hex adr x4, spacer bl asm_print_str ldr x4, [x7], #8 bl asm_print_hex adr x4, newline bl asm_print_str b 2b 1: adr x6, cci_iface_regs /* Store in x7 the base address of the first interface */ mov_imm x7, (CCI400_BASE + SLAVE_IFACE_OFFSET( \ CCI400_SL_IFACE3_CLUSTER_IX)) ldr w8, [x7, #SNOOP_CTRL_REG] /* Store in x7 the base address of the second interface */ mov_imm x7, (CCI400_BASE + SLAVE_IFACE_OFFSET( \ CCI400_SL_IFACE4_CLUSTER_IX)) ldr w9, [x7, #SNOOP_CTRL_REG] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/hisilicon/hikey/include/platform_def.h000066400000000000000000000045701355360272700254070ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include #include #include /* BL memory region sizes, etc */ /* Special value used to verify platform parameters from BL2 to BL3-1 */ #define HIKEY_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL /* * Generic platform constants */ /* Size of cacheable stacks */ #define PLATFORM_STACK_SIZE 0x1000 #define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n" #define PLATFORM_CACHE_LINE_SIZE 64 #define PLATFORM_CLUSTER_COUNT 2 #define PLATFORM_CORE_COUNT_PER_CLUSTER 4 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \ PLATFORM_CORE_COUNT_PER_CLUSTER) #define PLAT_MAX_PWR_LVL (MPIDR_AFFLVL2) #define PLAT_NUM_PWR_DOMAINS (PLATFORM_CORE_COUNT + \ PLATFORM_CLUSTER_COUNT + 1) #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE U(2) #define MAX_IO_DEVICES 3 #define MAX_IO_HANDLES 4 /* eMMC RPMB and eMMC User Data */ #define MAX_IO_BLOCK_DEVICES U(2) /* GIC related constants (no GICR in GIC-400) */ #define PLAT_ARM_GICD_BASE 0xF6801000 #define PLAT_ARM_GICC_BASE 0xF6802000 #define PLAT_ARM_GICH_BASE 0xF6804000 #define PLAT_ARM_GICV_BASE 0xF6806000 /* * Platform specific page table and MMU setup constants */ #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #if defined(IMAGE_BL1) || defined(IMAGE_BL32) #define MAX_XLAT_TABLES 3 #endif #ifdef IMAGE_BL31 #define MAX_XLAT_TABLES 4 #endif #ifdef IMAGE_BL2 #define MAX_XLAT_TABLES 4 #endif #define MAX_MMAP_REGIONS 16 /* * Declarations and constants to access the mailboxes safely. Each mailbox is * aligned on the biggest cache line size in the platform. This is known only * to the platform as it might have a combination of integrated and external * caches. Such alignment ensures that two maiboxes do not sit on the same cache * line at any cache level. They could belong to different cpus/clusters & * get written while being protected by different locks causing corruption of * a valid mailbox address. */ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey/platform.mk000066400000000000000000000121131355360272700233160ustar00rootroot00000000000000# # Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Non-TF Boot ROM BL2_AT_EL3 := 1 # On Hikey, the TSP can execute from TZC secure area in DRAM (default) # or SRAM. HIKEY_TSP_RAM_LOCATION ?= dram ifeq (${HIKEY_TSP_RAM_LOCATION}, dram) HIKEY_TSP_RAM_LOCATION_ID = HIKEY_DRAM_ID else ifeq (${HIKEY_TSP_RAM_LOCATION}, sram) HIKEY_TSP_RAM_LOCATION_ID = HIKEY_SRAM_ID else $(error "Currently unsupported HIKEY_TSP_RAM_LOCATION value") endif CONSOLE_BASE := PL011_UART3_BASE CRASH_CONSOLE_BASE := PL011_UART3_BASE PLAT_PARTITION_MAX_ENTRIES := 12 PLAT_PL061_MAX_GPIOS := 160 COLD_BOOT_SINGLE_CPU := 1 PROGRAMMABLE_RESET_ADDRESS := 1 ENABLE_SVE_FOR_NS := 0 # Process flags $(eval $(call add_define,HIKEY_TSP_RAM_LOCATION_ID)) $(eval $(call add_define,CONSOLE_BASE)) $(eval $(call add_define,CRASH_CONSOLE_BASE)) $(eval $(call add_define,PLAT_PL061_MAX_GPIOS)) $(eval $(call add_define,PLAT_PARTITION_MAX_ENTRIES)) # Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images # in the FIP if the platform requires. ifneq ($(BL32_EXTRA1),) $(eval $(call TOOL_ADD_IMG,bl32_extra1,--tos-fw-extra1)) endif ifneq ($(BL32_EXTRA2),) $(eval $(call TOOL_ADD_IMG,bl32_extra2,--tos-fw-extra2)) endif USE_COHERENT_MEM := 1 PLAT_INCLUDES := -Iplat/hisilicon/hikey/include PLAT_BL_COMMON_SOURCES := drivers/arm/pl011/aarch64/pl011_console.S \ lib/xlat_tables/aarch64/xlat_tables.c \ lib/xlat_tables/xlat_tables_common.c \ plat/hisilicon/hikey/aarch64/hikey_common.c BL1_SOURCES += bl1/tbbr/tbbr_img_desc.c \ drivers/arm/pl061/pl061_gpio.c \ drivers/arm/sp804/sp804_delay_timer.c \ drivers/delay_timer/delay_timer.c \ drivers/gpio/gpio.c \ drivers/io/io_block.c \ drivers/io/io_fip.c \ drivers/io/io_storage.c \ drivers/mmc/mmc.c \ drivers/synopsys/emmc/dw_mmc.c \ lib/cpus/aarch64/cortex_a53.S \ plat/hisilicon/hikey/aarch64/hikey_helpers.S \ plat/hisilicon/hikey/hikey_bl1_setup.c \ plat/hisilicon/hikey/hikey_bl_common.c \ plat/hisilicon/hikey/hikey_io_storage.c BL2_SOURCES += common/desc_image_load.c \ drivers/arm/pl061/pl061_gpio.c \ drivers/arm/sp804/sp804_delay_timer.c \ drivers/delay_timer/delay_timer.c \ drivers/gpio/gpio.c \ drivers/io/io_block.c \ drivers/io/io_fip.c \ drivers/io/io_storage.c \ drivers/mmc/mmc.c \ drivers/partition/gpt.c \ drivers/partition/partition.c \ drivers/synopsys/emmc/dw_mmc.c \ lib/cpus/aarch64/cortex_a53.S \ plat/hisilicon/hikey/aarch64/hikey_helpers.S \ plat/hisilicon/hikey/hikey_bl2_mem_params_desc.c \ plat/hisilicon/hikey/hikey_bl2_setup.c \ plat/hisilicon/hikey/hikey_bl_common.c \ plat/hisilicon/hikey/hikey_security.c \ plat/hisilicon/hikey/hikey_ddr.c \ plat/hisilicon/hikey/hikey_image_load.c \ plat/hisilicon/hikey/hikey_io_storage.c \ plat/hisilicon/hikey/hisi_dvfs.c \ plat/hisilicon/hikey/hisi_mcu.c ifeq (${SPD},opteed) BL2_SOURCES += lib/optee/optee_utils.c endif HIKEY_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c BL31_SOURCES += drivers/arm/cci/cci.c \ drivers/arm/sp804/sp804_delay_timer.c \ drivers/delay_timer/delay_timer.c \ lib/cpus/aarch64/cortex_a53.S \ plat/common/plat_psci_common.c \ plat/hisilicon/hikey/aarch64/hikey_helpers.S \ plat/hisilicon/hikey/hikey_bl31_setup.c \ plat/hisilicon/hikey/hikey_pm.c \ plat/hisilicon/hikey/hikey_topology.c \ plat/hisilicon/hikey/hisi_ipc.c \ plat/hisilicon/hikey/hisi_pwrc.c \ plat/hisilicon/hikey/hisi_pwrc_sram.S \ ${HIKEY_GIC_SOURCES} ifeq (${ENABLE_PMF}, 1) BL31_SOURCES += plat/hisilicon/hikey/hisi_sip_svc.c \ lib/pmf/pmf_smc.c endif ifneq (${TRUSTED_BOARD_BOOT},0) include drivers/auth/mbedtls/mbedtls_crypto.mk include drivers/auth/mbedtls/mbedtls_x509.mk AUTH_SOURCES := drivers/auth/auth_mod.c \ drivers/auth/crypto_mod.c \ drivers/auth/img_parser_mod.c \ drivers/auth/tbbr/tbbr_cot.c BL1_SOURCES += ${AUTH_SOURCES} \ plat/common/tbbr/plat_tbbr.c \ plat/hisilicon/hikey/hikey_tbbr.c \ plat/hisilicon/hikey/hikey_rotpk.S BL2_SOURCES += ${AUTH_SOURCES} \ plat/common/tbbr/plat_tbbr.c \ plat/hisilicon/hikey/hikey_tbbr.c \ plat/hisilicon/hikey/hikey_rotpk.S ROT_KEY = $(BUILD_PLAT)/rot_key.pem ROTPK_HASH = $(BUILD_PLAT)/rotpk_sha256.bin $(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"')) $(BUILD_PLAT)/bl1/hikey_rotpk.o: $(ROTPK_HASH) $(BUILD_PLAT)/bl2/hikey_rotpk.o: $(ROTPK_HASH) certificates: $(ROT_KEY) $(ROT_KEY): | $(BUILD_PLAT) @echo " OPENSSL $@" $(Q)openssl genrsa 2048 > $@ 2>/dev/null $(ROTPK_HASH): $(ROT_KEY) @echo " OPENSSL $@" $(Q)openssl rsa -in $< -pubout -outform DER 2>/dev/null |\ openssl dgst -sha256 -binary > $@ 2>/dev/null endif # Enable workarounds for selected Cortex-A53 errata. ERRATA_A53_836870 := 1 ERRATA_A53_843419 := 1 ERRATA_A53_855873 := 1 WORKAROUND_CVE_2017_5715 := 0 FIP_ALIGN := 512 trusted-firmware-a-2.2/plat/hisilicon/hikey960/000077500000000000000000000000001355360272700214025ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/hisilicon/hikey960/aarch64/000077500000000000000000000000001355360272700226325ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/hisilicon/hikey960/aarch64/hikey960_common.c000066400000000000000000000057431355360272700257270ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include "../hikey960_def.h" #include "../hikey960_private.h" #define MAP_DDR MAP_REGION_FLAT(DDR_BASE, \ DDR_SIZE - DDR_SEC_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define MAP_DEVICE MAP_REGION_FLAT(DEVICE_BASE, \ DEVICE_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_BL1_RW MAP_REGION_FLAT(BL1_RW_BASE, \ BL1_RW_LIMIT - BL1_RW_BASE, \ MT_MEMORY | MT_RW | MT_NS) #define MAP_UFS_DATA MAP_REGION_FLAT(HIKEY960_UFS_DATA_BASE, \ HIKEY960_UFS_DATA_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define MAP_UFS_DESC MAP_REGION_FLAT(HIKEY960_UFS_DESC_BASE, \ HIKEY960_UFS_DESC_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define MAP_TSP_MEM MAP_REGION_FLAT(TSP_SEC_MEM_BASE, \ TSP_SEC_MEM_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) /* * Table of regions for different BL stages to map using the MMU. * This doesn't include Trusted RAM as the 'mem_layout' argument passed to * hikey960_init_mmu_elx() will give the available subset of that, */ #ifdef IMAGE_BL1 static const mmap_region_t hikey960_mmap[] = { MAP_UFS_DATA, MAP_BL1_RW, MAP_UFS_DESC, MAP_DEVICE, {0} }; #endif #ifdef IMAGE_BL2 static const mmap_region_t hikey960_mmap[] = { MAP_DDR, MAP_DEVICE, MAP_TSP_MEM, {0} }; #endif #ifdef IMAGE_BL31 static const mmap_region_t hikey960_mmap[] = { MAP_DEVICE, MAP_TSP_MEM, {0} }; #endif #ifdef IMAGE_BL32 static const mmap_region_t hikey960_mmap[] = { MAP_DEVICE, MAP_DDR, {0} }; #endif /* * Macro generating the code for the function setting up the pagetables as per * the platform memory map & initialize the mmu, for the given exception level */ #define HIKEY960_CONFIGURE_MMU_EL(_el) \ void hikey960_init_mmu_el##_el(unsigned long total_base, \ unsigned long total_size, \ unsigned long ro_start, \ unsigned long ro_limit, \ unsigned long coh_start, \ unsigned long coh_limit) \ { \ mmap_add_region(total_base, total_base, \ total_size, \ MT_MEMORY | MT_RW | MT_SECURE); \ mmap_add_region(ro_start, ro_start, \ ro_limit - ro_start, \ MT_MEMORY | MT_RO | MT_SECURE); \ mmap_add_region(coh_start, coh_start, \ coh_limit - coh_start, \ MT_DEVICE | MT_RW | MT_SECURE); \ mmap_add(hikey960_mmap); \ init_xlat_tables(); \ \ enable_mmu_el##_el(0); \ } /* Define EL1 and EL3 variants of the function initialising the MMU */ HIKEY960_CONFIGURE_MMU_EL(1) HIKEY960_CONFIGURE_MMU_EL(3) unsigned long plat_get_ns_image_entrypoint(void) { return NS_BL1U_BASE; } unsigned int plat_get_syscnt_freq2(void) { return 1920000; } trusted-firmware-a-2.2/plat/hisilicon/hikey960/aarch64/hikey960_helpers.S000066400000000000000000000100471355360272700260520ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "../hikey960_def.h" .globl plat_my_core_pos .globl platform_mem_init .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush .globl plat_report_exception .globl plat_reset_handler .globl clr_ex .globl nop func plat_my_core_pos mrs x0, mpidr_el1 and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 ret endfunc plat_my_core_pos /* ----------------------------------------------------- * void platform_mem_init(void); * * We don't need to carry out any memory initialization * on HIKEY. The Secure RAM is accessible straight away. * ----------------------------------------------------- */ func platform_mem_init ret endfunc platform_mem_init /* --------------------------------------------- * int plat_crash_console_init(void) * Function to initialize the crash console * without a C Runtime to print crash report. * Clobber list : x0, x1, x2 * --------------------------------------------- */ func plat_crash_console_init mov_imm x0, CRASH_CONSOLE_BASE mov_imm x1, PL011_UART_CLK_IN_HZ mov_imm x2, PL011_BAUDRATE b console_pl011_core_init endfunc plat_crash_console_init /* --------------------------------------------- * int plat_crash_console_putc(int c) * Function to print a character on the crash * console without a C Runtime. * Clobber list : x1, x2 * --------------------------------------------- */ func plat_crash_console_putc mov_imm x1, CRASH_CONSOLE_BASE b console_pl011_core_putc endfunc plat_crash_console_putc /* --------------------------------------------- * int plat_crash_console_flush() * Function to force a write of all buffered * data that hasn't been output. * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func plat_crash_console_flush mov_imm x0, CRASH_CONSOLE_BASE b console_pl011_core_flush endfunc plat_crash_console_flush /* --------------------------------------------- * void plat_report_exception(unsigned int type) * Function to report an unhandled exception * with platform-specific means. * On HIKEY platform, it updates the LEDs * to indicate where we are * --------------------------------------------- */ func plat_report_exception mov x8, x30 /* Turn on LED according to x0 (0 -- f) */ ldr x2, =0xf7020000 and x1, x0, #1 str w1, [x2, #4] and x1, x0, #2 str w1, [x2, #8] and x1, x0, #4 str w1, [x2, #16] and x1, x0, #8 str w1, [x2, #32] mrs x2, currentel and x2, x2, #0x0c /* Check EL1 */ cmp x2, #0x04 beq plat_report_el1 adr x4, plat_err_str bl asm_print_str adr x4, esr_el3_str bl asm_print_str mrs x4, esr_el3 bl asm_print_hex adr x4, elr_el3_str bl asm_print_str mrs x4, elr_el3 bl asm_print_hex b plat_report_end plat_report_el1: adr x4, plat_err_str bl asm_print_str adr x4, esr_el1_str bl asm_print_str mrs x4, esr_el1 bl asm_print_hex adr x4, elr_el1_str bl asm_print_str mrs x4, elr_el1 bl asm_print_hex plat_report_end: mov x30, x8 ret endfunc plat_report_exception /* ----------------------------------------------------- * void plat_reset_handler(void); * ----------------------------------------------------- */ func plat_reset_handler ret endfunc plat_reset_handler /* ----------------------------------------------------- * void clrex(void); * ----------------------------------------------------- */ func clr_ex clrex ret endfunc clr_ex /* ----------------------------------------------------- * void nop(void); * ----------------------------------------------------- */ func nop nop ret endfunc nop .section .rodata.rev_err_str, "aS" plat_err_str: .asciz "\nPlatform exception reporting:" esr_el3_str: .asciz "\nESR_EL3: " elr_el3_str: .asciz "\nELR_EL3: " esr_el1_str: .asciz "\nESR_EL1: " elr_el1_str: .asciz "\nELR_EL1: " trusted-firmware-a-2.2/plat/hisilicon/hikey960/drivers/000077500000000000000000000000001355360272700230605ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/hisilicon/hikey960/drivers/ipc/000077500000000000000000000000001355360272700236335ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c000066400000000000000000000127101355360272700255670ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include "../../hikey960_private.h" #define IPC_MBX_SOURCE_REG(m) (IPC_BASE + ((m) << 6)) #define IPC_MBX_DSET_REG(m) (IPC_BASE + ((m) << 6) + 0x04) #define IPC_MBX_DCLEAR_REG(m) (IPC_BASE + ((m) << 6) + 0x08) #define IPC_MBX_DSTATUS_REG(m) (IPC_BASE + ((m) << 6) + 0x0C) #define IPC_MBX_MODE_REG(m) (IPC_BASE + ((m) << 6) + 0x10) #define IPC_MBX_IMASK_REG(m) (IPC_BASE + ((m) << 6) + 0x14) #define IPC_MBX_ICLR_REG(m) (IPC_BASE + ((m) << 6) + 0x18) #define IPC_MBX_SEND_REG(m) (IPC_BASE + ((m) << 6) + 0x1C) #define IPC_MBX_DATA_REG(m, d) (IPC_BASE + ((m) << 6) + 0x20 + \ ((d) * 4)) #define IPC_CPU_IMST_REG(m) (IPC_BASE + ((m) << 3)) #define IPC_LOCK_REG (IPC_BASE + 0xA00) #define IPC_ACK_BIT_SHIFT (1 << 7) #define IPC_UNLOCK_VALUE (0x1ACCE551) /********************************************************* *bit[31:24]:0~AP *bit[23:16]:0x1~A15, 0x2~A7 *bit[15:8]:0~ON, 1~OFF *bit[7:0]:0x3 cpu power mode *********************************************************/ #define IPC_CMD_TYPE(src_obj, cluster_obj, is_off, mode) \ ((src_obj << 24) | (((cluster_obj) + 1) << 16) | (is_off << 8) | (mode)) /********************************************************* *bit[15:8]:0~no idle, 1~idle *bit[7:0]:cpux *********************************************************/ #define IPC_CMD_PARA(is_idle, cpu) \ ((is_idle << 8) | (cpu)) #define IPC_STATE_IDLE 0x10 enum src_id { SRC_IDLE = 0, SRC_A15 = 1 << 0, SRC_A7 = 1 << 1, SRC_IOM3 = 1 << 2, SRC_LPM3 = 1 << 3 }; /*lpm3's mailboxs are 13~17*/ enum lpm3_mbox_id { LPM3_MBX0 = 13, LPM3_MBX1, LPM3_MBX2, LPM3_MBX3, LPM3_MBX4, }; static void cpu_relax(void) { volatile int i; for (i = 0; i < 10; i++) nop(); } static inline void hisi_ipc_clear_ack(enum src_id source, enum lpm3_mbox_id mbox) { unsigned int int_status = 0; do { int_status = mmio_read_32(IPC_MBX_MODE_REG(mbox)); int_status &= 0xF0; cpu_relax(); } while (int_status != IPC_ACK_BIT_SHIFT); mmio_write_32(IPC_MBX_ICLR_REG(mbox), source); } static void hisi_ipc_send_cmd_with_ack(enum src_id source, enum lpm3_mbox_id mbox, unsigned int cmdtype, unsigned int cmdpara) { unsigned int regval; unsigned int mask; unsigned int state; mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE); /* wait for idle and occupy */ do { state = mmio_read_32(IPC_MBX_MODE_REG(mbox)); if (state == IPC_STATE_IDLE) { mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source); regval = mmio_read_32(IPC_MBX_SOURCE_REG(mbox)); if (regval == source) break; } cpu_relax(); } while (1); /* auto answer */ mmio_write_32(IPC_MBX_MODE_REG(mbox), 0x1); mask = (~((int)source | SRC_LPM3) & 0x3F); /* mask the other cpus */ mmio_write_32(IPC_MBX_IMASK_REG(mbox), mask); /* set data */ mmio_write_32(IPC_MBX_DATA_REG(mbox, 0), cmdtype); mmio_write_32(IPC_MBX_DATA_REG(mbox, 1), cmdpara); /* send cmd */ mmio_write_32(IPC_MBX_SEND_REG(mbox), source); /* wait ack and clear */ hisi_ipc_clear_ack(source, mbox); /* release mailbox */ mmio_write_32(IPC_MBX_SOURCE_REG(mbox), source); } void hisi_ipc_pm_on_off(unsigned int core, unsigned int cluster, enum pm_mode mode) { unsigned int cmdtype = 0; unsigned int cmdpara = 0; enum src_id source = SRC_IDLE; enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core); cmdtype = IPC_CMD_TYPE(0, cluster, mode, 0x3); cmdpara = IPC_CMD_PARA(0, core); source = cluster ? SRC_A7 : SRC_A15; hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara); } void hisi_ipc_pm_suspend(unsigned int core, unsigned int cluster, unsigned int affinity_level) { unsigned int cmdtype = 0; unsigned int cmdpara = 0; enum src_id source = SRC_IDLE; enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core); if (affinity_level == 0x3) cmdtype = IPC_CMD_TYPE(0, -1, 0x1, 0x3 + affinity_level); else cmdtype = IPC_CMD_TYPE(0, cluster, 0x1, 0x3 + affinity_level); cmdpara = IPC_CMD_PARA(1, core); source = cluster ? SRC_A7 : SRC_A15; hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara); } void hisi_ipc_psci_system_off(unsigned int core, unsigned int cluster) { unsigned int cmdtype = 0; unsigned int cmdpara = 0; enum src_id source = SRC_IDLE; enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core); cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x1, 0x0); cmdpara = IPC_CMD_PARA(0, 0); source = cluster ? SRC_A7 : SRC_A15; hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara); } void hisi_ipc_psci_system_reset(unsigned int core, unsigned int cluster, unsigned int cmd_id) { unsigned int cmdtype = 0; unsigned int cmdpara = 0; enum src_id source = SRC_IDLE; enum lpm3_mbox_id mailbox = (enum lpm3_mbox_id)(LPM3_MBX0 + core); cmdtype = IPC_CMD_TYPE(0, (0x10 - 1), 0x0, 0x0); cmdpara = cmd_id; source = cluster ? SRC_A7 : SRC_A15; hisi_ipc_send_cmd_with_ack(source, mailbox, cmdtype, cmdpara); } int hisi_ipc_init(void) { int ret = 0; enum lpm3_mbox_id i = LPM3_MBX0; mmio_write_32(IPC_LOCK_REG, IPC_UNLOCK_VALUE); for (i = LPM3_MBX0; i <= LPM3_MBX4; i++) { mmio_write_32(IPC_MBX_MODE_REG(i), 1); mmio_write_32(IPC_MBX_IMASK_REG(i), ((int)SRC_IOM3 | (int)SRC_A15 | (int)SRC_A7)); mmio_write_32(IPC_MBX_ICLR_REG(i), SRC_A7); } return ret; } trusted-firmware-a-2.2/plat/hisilicon/hikey960/drivers/pwrc/000077500000000000000000000000001355360272700240335ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c000066400000000000000000000237561355360272700262030ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include <../hikey960_def.h> #include #include "hisi_pwrc.h" /* resource lock api */ #define RES0_LOCK_BASE (SOC_PCTRL_RESOURCE0_LOCK_ADDR(PCTRL_BASE)) #define RES1_LOCK_BASE (SOC_PCTRL_RESOURCE1_LOCK_ADDR(PCTRL_BASE)) #define RES2_LOCK_BASE (SOC_PCTRL_RESOURCE2_LOCK_ADDR(PCTRL_BASE)) #define LOCK_BIT (0x1 << 28) #define LOCK_ID_MASK (0x7u << 29) #define CPUIDLE_LOCK_ID(core) (0x6 - (core)) #define LOCK_UNLOCK_OFFSET 0x4 #define LOCK_STAT_OFFSET 0x8 #define CLUSTER0_CPUS_ONLINE_MASK (0xF << 16) #define CLUSTER1_CPUS_ONLINE_MASK (0xF << 20) /* cpu hotplug flag api */ #define SCTRL_BASE (SOC_ACPU_SCTRL_BASE_ADDR) #define REG_SCBAKDATA3_OFFSET (SOC_SCTRL_SCBAKDATA3_ADDR(SCTRL_BASE)) #define REG_SCBAKDATA8_OFFSET (SOC_SCTRL_SCBAKDATA8_ADDR(SCTRL_BASE)) #define REG_SCBAKDATA9_OFFSET (SOC_SCTRL_SCBAKDATA9_ADDR(SCTRL_BASE)) #define CPUIDLE_FLAG_REG(cluster) \ ((cluster == 0) ? REG_SCBAKDATA8_OFFSET : \ REG_SCBAKDATA9_OFFSET) #define CLUSTER_IDLE_BIT BIT(8) #define CLUSTER_IDLE_MASK (CLUSTER_IDLE_BIT | 0x0F) #define AP_SUSPEND_FLAG (1 << 16) #define CLUSTER_PWDN_IDLE (0<<28) #define CLUSTER_PWDN_HOTPLUG (1<<28) #define CLUSTER_PWDN_SR (2<<28) #define CLUSTER0_PDC_OFFSET 0x260 #define CLUSTER1_PDC_OFFSET 0x300 #define PDC_EN_OFFSET 0x0 #define PDC_COREPWRINTEN_OFFSET 0x4 #define PDC_COREPWRINTSTAT_OFFSET 0x8 #define PDC_COREGICMASK_OFFSET 0xc #define PDC_COREPOWERUP_OFFSET 0x10 #define PDC_COREPOWERDN_OFFSET 0x14 #define PDC_COREPOWERSTAT_OFFSET 0x18 #define PDC_COREPWRSTAT_MASK (0XFFFF) enum pdc_gic_mask { PDC_MASK_GIC_WAKE_IRQ, PDC_UNMASK_GIC_WAKE_IRQ }; enum pdc_finish_int_mask { PDC_DISABLE_FINISH_INT, PDC_ENABLE_FINISH_INT }; static void hisi_resource_lock(unsigned int lockid, unsigned int offset) { unsigned int lock_id = (lockid << 29); unsigned int lock_val = lock_id | LOCK_BIT; unsigned int lock_state; do { mmio_write_32(offset, lock_val); lock_state = mmio_read_32(LOCK_STAT_OFFSET + (uintptr_t)offset); } while ((lock_state & LOCK_ID_MASK) != lock_id); } static void hisi_resource_unlock(unsigned int lockid, unsigned int offset) { unsigned int lock_val = (lockid << 29) | LOCK_BIT; mmio_write_32((LOCK_UNLOCK_OFFSET + (uintptr_t)offset), lock_val); } static void hisi_cpuhotplug_lock(unsigned int cluster, unsigned int core) { unsigned int lock_id; lock_id = (cluster << 2) + core; hisi_resource_lock(lock_id, RES2_LOCK_BASE); } static void hisi_cpuhotplug_unlock(unsigned int cluster, unsigned int core) { unsigned int lock_id; lock_id = (cluster << 2) + core; hisi_resource_unlock(lock_id, RES2_LOCK_BASE); } /* get the resource lock */ void hisi_cpuidle_lock(unsigned int cluster, unsigned int core) { unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE); hisi_resource_lock(CPUIDLE_LOCK_ID(core), offset); } /* release the resource lock */ void hisi_cpuidle_unlock(unsigned int cluster, unsigned int core) { unsigned int offset = (cluster == 0 ? RES0_LOCK_BASE : RES1_LOCK_BASE); hisi_resource_unlock(CPUIDLE_LOCK_ID(core), offset); } unsigned int hisi_get_cpuidle_flag(unsigned int cluster) { unsigned int val; val = mmio_read_32(CPUIDLE_FLAG_REG(cluster)); val &= 0xF; return val; } void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core) { mmio_setbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core)); } void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core) { mmio_clrbits_32(CPUIDLE_FLAG_REG(cluster), BIT(core)); } int hisi_test_ap_suspend_flag(void) { unsigned int val1; unsigned int val2; val1 = mmio_read_32(CPUIDLE_FLAG_REG(0)); val1 &= AP_SUSPEND_FLAG; val2 = mmio_read_32(CPUIDLE_FLAG_REG(1)); val2 &= AP_SUSPEND_FLAG; val1 |= val2; return (val1 != 0); } void hisi_set_cluster_pwdn_flag(unsigned int cluster, unsigned int core, unsigned int value) { unsigned int val; hisi_cpuhotplug_lock(cluster, core); val = mmio_read_32(REG_SCBAKDATA3_OFFSET); val &= ~(0x3U << ((2 * cluster) + 28)); val |= (value << (2 * cluster)); mmio_write_32(REG_SCBAKDATA3_OFFSET, val); hisi_cpuhotplug_unlock(cluster, core); } unsigned int hisi_get_cpu_boot_flag(unsigned int cluster, unsigned int core) { unsigned int val; hisi_cpuhotplug_lock(cluster, core); val = mmio_read_32(REG_SCBAKDATA3_OFFSET); val = val >> (16 + (cluster << 2)); val &= 0xF; hisi_cpuhotplug_unlock(cluster, core); return val; } unsigned int hisi_test_cpu_down(unsigned int cluster, unsigned int core) { unsigned int val; hisi_cpuhotplug_lock(cluster, core); val = mmio_read_32(REG_SCBAKDATA3_OFFSET); val = val >> (16 + (cluster << 2)); val &= 0xF; hisi_cpuhotplug_unlock(cluster, core); if (val) return 0; else return 1; } void hisi_set_cpu_boot_flag(unsigned int cluster, unsigned int core) { unsigned int flag = BIT((cluster<<2) + core + 16); hisi_cpuhotplug_lock(cluster, core); mmio_setbits_32(REG_SCBAKDATA3_OFFSET, flag); hisi_cpuhotplug_unlock(cluster, core); } void hisi_clear_cpu_boot_flag(unsigned int cluster, unsigned int core) { unsigned int flag = BIT((cluster<<2) + core + 16); hisi_cpuhotplug_lock(cluster, core); mmio_clrbits_32(REG_SCBAKDATA3_OFFSET, flag); hisi_cpuhotplug_unlock(cluster, core); } int cluster_is_powered_on(unsigned int cluster) { unsigned int val = mmio_read_32(REG_SCBAKDATA3_OFFSET); int ret; if (cluster == 0) ret = val & CLUSTER0_CPUS_ONLINE_MASK; else ret = val & CLUSTER1_CPUS_ONLINE_MASK; return !!ret; } static void *hisi_get_pdc_addr(unsigned int cluster) { void *pdc_base_addr; uintptr_t addr; if (cluster == 0) addr = SOC_CRGPERIPH_A53_PDCEN_ADDR(CRG_BASE); else addr = SOC_CRGPERIPH_MAIA_PDCEN_ADDR(CRG_BASE); pdc_base_addr = (void *)addr; return pdc_base_addr; } static unsigned int hisi_get_pdc_stat(unsigned int cluster) { void *pdc_base_addr = hisi_get_pdc_addr(cluster); unsigned int val; val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPOWERSTAT_OFFSET); return val; } static int check_hotplug(unsigned int cluster, unsigned int boot_flag) { unsigned int mask = 0xF; if (hisi_test_ap_suspend_flag() || ((boot_flag & mask) == mask)) return 0; return 1; } int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core) { unsigned int mask = 0xf << (core * 4); unsigned int pdc_stat = hisi_get_pdc_stat(cluster); unsigned int boot_flag = hisi_get_cpu_boot_flag(cluster, core); unsigned int cpuidle_flag = hisi_get_cpuidle_flag(cluster); mask = (PDC_COREPWRSTAT_MASK & (~mask)); pdc_stat &= mask; if ((boot_flag ^ cpuidle_flag) || pdc_stat || check_hotplug(cluster, boot_flag)) return 0; else return 1; } void hisi_disable_pdc(unsigned int cluster) { void *pdc_base_addr = hisi_get_pdc_addr(cluster); mmio_write_32((uintptr_t)pdc_base_addr, 0x0); } void hisi_enable_pdc(unsigned int cluster) { void *pdc_base_addr = hisi_get_pdc_addr(cluster); mmio_write_32((uintptr_t)pdc_base_addr, 0x1); } void hisi_pdc_set_intmask(void *pdc_base_addr, unsigned int core, enum pdc_finish_int_mask intmask) { unsigned int val; val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET); if (intmask == PDC_ENABLE_FINISH_INT) val |= BIT(core); else val &= ~BIT(core); mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET, val); } static inline void hisi_pdc_set_gicmask(void *pdc_base_addr, unsigned int core, enum pdc_gic_mask gicmask) { unsigned int val; val = mmio_read_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET); if (gicmask == PDC_MASK_GIC_WAKE_IRQ) val |= BIT(core); else val &= ~BIT(core); mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREGICMASK_OFFSET, val); } void hisi_pdc_mask_cluster_wakeirq(unsigned int cluster) { int i; void *pdc_base_addr = hisi_get_pdc_addr(cluster); for (i = 0; i < 4; i++) hisi_pdc_set_gicmask(pdc_base_addr, i, PDC_MASK_GIC_WAKE_IRQ); } static void hisi_pdc_powerup_core(unsigned int cluster, unsigned int core, enum pdc_gic_mask gicmask, enum pdc_finish_int_mask intmask) { void *pdc_base_addr = hisi_get_pdc_addr(cluster); mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERUP_OFFSET, BIT(core)); } static void hisi_pdc_powerdn_core(unsigned int cluster, unsigned int core, enum pdc_gic_mask gicmask, enum pdc_finish_int_mask intmask) { void *pdc_base_addr = hisi_get_pdc_addr(cluster); mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET, BIT(core)); } void hisi_powerup_core(unsigned int cluster, unsigned int core) { hisi_pdc_powerup_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ, PDC_DISABLE_FINISH_INT); } void hisi_powerdn_core(unsigned int cluster, unsigned int core) { hisi_pdc_powerdn_core(cluster, core, PDC_MASK_GIC_WAKE_IRQ, PDC_DISABLE_FINISH_INT); } void hisi_powerup_cluster(unsigned int cluster, unsigned int core) { hisi_ipc_pm_on_off(core, cluster, PM_ON); } void hisi_powerdn_cluster(unsigned int cluster, unsigned int core) { void *pdc_base_addr = hisi_get_pdc_addr(cluster); hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_HOTPLUG); mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET, (0x10001 << core)); mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET, BIT(core)); } void hisi_enter_core_idle(unsigned int cluster, unsigned int core) { hisi_pdc_powerdn_core(cluster, core, PDC_UNMASK_GIC_WAKE_IRQ, PDC_DISABLE_FINISH_INT); } void hisi_enter_cluster_idle(unsigned int cluster, unsigned int core) { void *pdc_base_addr = hisi_get_pdc_addr(cluster); hisi_set_cluster_pwdn_flag(cluster, core, CLUSTER_PWDN_IDLE); mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPWRINTEN_OFFSET, (0x10001 << core)); mmio_write_32((uintptr_t)pdc_base_addr + PDC_COREPOWERDN_OFFSET, BIT(core)); } void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core) { hisi_ipc_pm_suspend(core, cluster, 0x3); } trusted-firmware-a-2.2/plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.h000066400000000000000000000045611355360272700262010ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HISI_PWRC_H #define HISI_PWRC_H #include #include #define PCTRL_BASE (PCTRL_REG_BASE) #define CRG_BASE (CRG_REG_BASE) #define SOC_CRGPERIPH_A53_PDCEN_ADDR(base) ((base) + (0x260)) #define SOC_CRGPERIPH_MAIA_PDCEN_ADDR(base) ((base) + (0x300)) #define SOC_PCTRL_RESOURCE0_LOCK_ADDR(base) ((base) + (0x400)) #define SOC_PCTRL_RESOURCE0_UNLOCK_ADDR(base) ((base) + (0x404)) #define SOC_PCTRL_RESOURCE0_LOCK_ST_ADDR(base) ((base) + (0x408)) #define SOC_PCTRL_RESOURCE1_LOCK_ADDR(base) ((base) + (0x40C)) #define SOC_PCTRL_RESOURCE1_UNLOCK_ADDR(base) ((base) + (0x410)) #define SOC_PCTRL_RESOURCE1_LOCK_ST_ADDR(base) ((base) + (0x414)) #define SOC_PCTRL_RESOURCE2_LOCK_ADDR(base) ((base) + (0x418)) #define SOC_SCTRL_SCBAKDATA3_ADDR(base) ((base) + (0x418)) #define SOC_SCTRL_SCBAKDATA8_ADDR(base) ((base) + (0x42C)) #define SOC_SCTRL_SCBAKDATA9_ADDR(base) ((base) + (0x430)) #define SOC_ACPU_SCTRL_BASE_ADDR (0xFFF0A000) void hisi_cpuidle_lock(unsigned int cluster, unsigned int core); void hisi_cpuidle_unlock(unsigned int cluster, unsigned int core); void hisi_set_cpuidle_flag(unsigned int cluster, unsigned int core); void hisi_clear_cpuidle_flag(unsigned int cluster, unsigned int core); void hisi_set_cpu_boot_flag(unsigned int cluster, unsigned int core); void hisi_clear_cpu_boot_flag(unsigned int cluster, unsigned int core); int cluster_is_powered_on(unsigned int cluster); void hisi_enter_core_idle(unsigned int cluster, unsigned int core); void hisi_enter_cluster_idle(unsigned int cluster, unsigned int core); int hisi_test_ap_suspend_flag(void); void hisi_enter_ap_suspend(unsigned int cluster, unsigned int core); /* pdc api */ void hisi_pdc_mask_cluster_wakeirq(unsigned int cluster); int hisi_test_pwrdn_allcores(unsigned int cluster, unsigned int core); void hisi_disable_pdc(unsigned int cluster); void hisi_enable_pdc(unsigned int cluster); void hisi_powerup_core(unsigned int cluster, unsigned int core); void hisi_powerdn_core(unsigned int cluster, unsigned int core); void hisi_powerup_cluster(unsigned int cluster, unsigned int core); void hisi_powerdn_cluster(unsigned int cluster, unsigned int core); unsigned int hisi_test_cpu_down(unsigned int cluster, unsigned int core); #endif /* HISI_PWRC_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey960/hikey960_bl1_setup.c000066400000000000000000000170231355360272700250770ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hikey960_def.h" #include "hikey960_private.h" enum { BOOT_MODE_RECOVERY = 0, BOOT_MODE_NORMAL, BOOT_MODE_MASK = 1, }; /* * Declarations of linker defined symbols which will help us find the layout * of trusted RAM */ /* Data structure which holds the extents of the trusted RAM for BL1 */ static meminfo_t bl1_tzram_layout; static console_pl011_t console; /****************************************************************************** * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0 * interrupts. *****************************************************************************/ static const interrupt_prop_t g0_interrupt_props[] = { INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), }; const gicv2_driver_data_t hikey960_gic_data = { .gicd_base = GICD_REG_BASE, .gicc_base = GICC_REG_BASE, .interrupt_props = g0_interrupt_props, .interrupt_props_num = ARRAY_SIZE(g0_interrupt_props), }; meminfo_t *bl1_plat_sec_mem_layout(void) { return &bl1_tzram_layout; } /* * Perform any BL1 specific platform actions. */ void bl1_early_platform_setup(void) { unsigned int id, uart_base; generic_delay_timer_init(); hikey960_read_boardid(&id); if (id == 5300) uart_base = PL011_UART5_BASE; else uart_base = PL011_UART6_BASE; /* Initialize the console to provide early debug support */ console_pl011_register(uart_base, PL011_UART_CLK_IN_HZ, PL011_BAUDRATE, &console); /* Allow BL1 to see the whole Trusted RAM */ bl1_tzram_layout.total_base = BL1_RW_BASE; bl1_tzram_layout.total_size = BL1_RW_SIZE; INFO("BL1: 0x%lx - 0x%lx [size = %lu]\n", BL1_RAM_BASE, BL1_RAM_LIMIT, BL1_RAM_LIMIT - BL1_RAM_BASE); /* bl1_size */ } /* * Perform the very early platform specific architecture setup here. At the * moment this only does basic initialization. Later architectural setup * (bl1_arch_setup()) does not do anything platform specific. */ void bl1_plat_arch_setup(void) { hikey960_init_mmu_el3(bl1_tzram_layout.total_base, bl1_tzram_layout.total_size, BL1_RO_BASE, BL1_RO_LIMIT, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); } static void hikey960_ufs_reset(void) { unsigned int data, mask; mmio_write_32(CRG_PERDIS7_REG, 1 << 14); mmio_clrbits_32(UFS_SYS_PHY_CLK_CTRL_REG, BIT_SYSCTRL_REF_CLOCK_EN); do { data = mmio_read_32(UFS_SYS_PHY_CLK_CTRL_REG); } while (data & BIT_SYSCTRL_REF_CLOCK_EN); /* use abb clk */ mmio_clrbits_32(UFS_SYS_UFS_SYSCTRL_REG, BIT_UFS_REFCLK_SRC_SE1); mmio_clrbits_32(UFS_SYS_PHY_ISO_EN_REG, BIT_UFS_REFCLK_ISO_EN); mmio_write_32(PCTRL_PERI_CTRL3_REG, (1 << 0) | (1 << 16)); mdelay(1); mmio_write_32(CRG_PEREN7_REG, 1 << 14); mmio_setbits_32(UFS_SYS_PHY_CLK_CTRL_REG, BIT_SYSCTRL_REF_CLOCK_EN); mmio_write_32(CRG_PERRSTEN3_REG, PERI_UFS_BIT); do { data = mmio_read_32(CRG_PERRSTSTAT3_REG); } while ((data & PERI_UFS_BIT) == 0); mmio_setbits_32(UFS_SYS_PSW_POWER_CTRL_REG, BIT_UFS_PSW_MTCMOS_EN); mdelay(1); mmio_setbits_32(UFS_SYS_HC_LP_CTRL_REG, BIT_SYSCTRL_PWR_READY); mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG, MASK_UFS_DEVICE_RESET); /* clear SC_DIV_UFS_PERIBUS */ mask = SC_DIV_UFS_PERIBUS << 16; mmio_write_32(CRG_CLKDIV17_REG, mask); /* set SC_DIV_UFSPHY_CFG(3) */ mask = SC_DIV_UFSPHY_CFG_MASK << 16; data = SC_DIV_UFSPHY_CFG(3); mmio_write_32(CRG_CLKDIV16_REG, mask | data); data = mmio_read_32(UFS_SYS_PHY_CLK_CTRL_REG); data &= ~MASK_SYSCTRL_CFG_CLOCK_FREQ; data |= 0x39; mmio_write_32(UFS_SYS_PHY_CLK_CTRL_REG, data); mmio_clrbits_32(UFS_SYS_PHY_CLK_CTRL_REG, MASK_SYSCTRL_REF_CLOCK_SEL); mmio_setbits_32(UFS_SYS_CLOCK_GATE_BYPASS_REG, MASK_UFS_CLK_GATE_BYPASS); mmio_setbits_32(UFS_SYS_UFS_SYSCTRL_REG, MASK_UFS_SYSCTRL_BYPASS); mmio_setbits_32(UFS_SYS_PSW_CLK_CTRL_REG, BIT_SYSCTRL_PSW_CLK_EN); mmio_clrbits_32(UFS_SYS_PSW_POWER_CTRL_REG, BIT_UFS_PSW_ISO_CTRL); mmio_clrbits_32(UFS_SYS_PHY_ISO_EN_REG, BIT_UFS_PHY_ISO_CTRL); mmio_clrbits_32(UFS_SYS_HC_LP_CTRL_REG, BIT_SYSCTRL_LP_ISOL_EN); mmio_write_32(CRG_PERRSTDIS3_REG, PERI_ARST_UFS_BIT); mmio_setbits_32(UFS_SYS_RESET_CTRL_EN_REG, BIT_SYSCTRL_LP_RESET_N); mdelay(1); mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG, MASK_UFS_DEVICE_RESET | BIT_UFS_DEVICE_RESET); mdelay(20); mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG, 0x03300330); mmio_write_32(CRG_PERRSTDIS3_REG, PERI_UFS_BIT); do { data = mmio_read_32(CRG_PERRSTSTAT3_REG); } while (data & PERI_UFS_BIT); } static void hikey960_ufs_init(void) { dw_ufs_params_t ufs_params; memset(&ufs_params, 0, sizeof(ufs_params)); ufs_params.reg_base = UFS_REG_BASE; ufs_params.desc_base = HIKEY960_UFS_DESC_BASE; ufs_params.desc_size = HIKEY960_UFS_DESC_SIZE; if ((ufs_params.flags & UFS_FLAGS_SKIPINIT) == 0) hikey960_ufs_reset(); dw_ufs_init(&ufs_params); } /* * Function which will perform any remaining platform-specific setup that can * occur after the MMU and data cache have been enabled. */ void bl1_platform_setup(void) { hikey960_clk_init(); hikey960_pmu_init(); hikey960_regulator_enable(); hikey960_tzc_init(); hikey960_peri_init(); hikey960_ufs_init(); hikey960_pinmux_init(); hikey960_gpio_init(); hikey960_io_setup(); } /* * The following function checks if Firmware update is needed, * by checking if TOC in FIP image is valid or not. */ unsigned int bl1_plat_get_next_image_id(void) { unsigned int mode, ret; mode = mmio_read_32(SCTRL_BAK_DATA0_REG); switch (mode & BOOT_MODE_MASK) { case BOOT_MODE_RECOVERY: ret = NS_BL1U_IMAGE_ID; break; default: WARN("Invalid boot mode is found:%d\n", mode); panic(); } return ret; } image_desc_t *bl1_plat_get_image_desc(unsigned int image_id) { unsigned int index = 0; while (bl1_tbbr_image_descs[index].image_id != INVALID_IMAGE_ID) { if (bl1_tbbr_image_descs[index].image_id == image_id) return &bl1_tbbr_image_descs[index]; index++; } return NULL; } void bl1_plat_set_ep_info(unsigned int image_id, entry_point_info_t *ep_info) { unsigned int data = 0; uintptr_t tmp = HIKEY960_NS_TMP_OFFSET; if (image_id != NS_BL1U_IMAGE_ID) panic(); /* Copy NS BL1U from 0x1AC1_8000 to 0x1AC9_8000 */ memcpy((void *)tmp, (void *)HIKEY960_NS_IMAGE_OFFSET, NS_BL1U_SIZE); memcpy((void *)NS_BL1U_BASE, (void *)tmp, NS_BL1U_SIZE); inv_dcache_range(NS_BL1U_BASE, NS_BL1U_SIZE); /* Initialize the GIC driver, cpu and distributor interfaces */ gicv2_driver_init(&hikey960_gic_data); gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); /* CNTFRQ is read-only in EL1 */ write_cntfrq_el0(plat_get_syscnt_freq2()); data = read_cpacr_el1(); do { data |= 3 << 20; write_cpacr_el1(data); data = read_cpacr_el1(); } while ((data & (3 << 20)) != (3 << 20)); INFO("cpacr_el1:0x%x\n", data); ep_info->args.arg0 = 0xffff & read_mpidr(); ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); } trusted-firmware-a-2.2/plat/hisilicon/hikey960/hikey960_bl2_mem_params_desc.c000066400000000000000000000120051355360272700270520ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /******************************************************************************* * Following descriptor provides BL image/ep information that gets used * by BL2 to load the images and also subset of this information is * passed to next BL image. The image loading sequence is managed by * populating the images in required loading order. The image execution * sequence is managed by populating the `next_handoff_image_id` with * the next executable image id. ******************************************************************************/ static bl_mem_params_node_t bl2_mem_params_descs[] = { #ifdef SCP_BL2_BASE /* Fill SCP_BL2 related information if it exists */ { .image_id = SCP_BL2_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE), SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP), .image_info.image_base = SCP_BL2_BASE, .image_info.image_max_size = SCP_BL2_SIZE, .next_handoff_image_id = INVALID_IMAGE_ID, }, #endif /* SCP_BL2_BASE */ #ifdef EL3_PAYLOAD_BASE /* Fill EL3 payload related information (BL31 is EL3 payload)*/ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = EL3_PAYLOAD_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING), .next_handoff_image_id = INVALID_IMAGE_ID, }, #else /* EL3_PAYLOAD_BASE */ /* Fill BL31 related information */ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = BL31_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), #if DEBUG .ep_info.args.arg1 = HIKEY960_BL31_PLAT_PARAM_VAL, #endif SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP), .image_info.image_base = BL31_BASE, .image_info.image_max_size = BL31_LIMIT - BL31_BASE, # ifdef BL32_BASE .next_handoff_image_id = BL32_IMAGE_ID, # else .next_handoff_image_id = BL33_IMAGE_ID, # endif }, # ifdef BL32_BASE /* Fill BL32 related information */ { .image_id = BL32_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE), .ep_info.pc = BL32_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = BL32_BASE, .image_info.image_max_size = BL32_LIMIT - BL32_BASE, .next_handoff_image_id = BL33_IMAGE_ID, }, /* * Fill BL32 external 1 related information. * A typical use for extra1 image is with OP-TEE where it is the pager image. */ { .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), .image_info.image_base = BL32_BASE, .image_info.image_max_size = BL32_LIMIT - BL32_BASE, .next_handoff_image_id = INVALID_IMAGE_ID, }, /* * Fill BL32 external 2 related information. * A typical use for extra2 image is with OP-TEE where it is the paged image. */ { .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), #ifdef SPD_opteed .image_info.image_base = HIKEY960_OPTEE_PAGEABLE_LOAD_BASE, .image_info.image_max_size = HIKEY960_OPTEE_PAGEABLE_LOAD_SIZE, #endif .next_handoff_image_id = INVALID_IMAGE_ID, }, # endif /* BL32_BASE */ /* Fill BL33 related information */ { .image_id = BL33_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), # ifdef PRELOADED_BL33_BASE .ep_info.pc = PRELOADED_BL33_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), # else .ep_info.pc = NS_BL1U_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = NS_BL1U_BASE, .image_info.image_max_size = 0x200000 /* 2MB */, # endif /* PRELOADED_BL33_BASE */ .next_handoff_image_id = INVALID_IMAGE_ID, } #endif /* EL3_PAYLOAD_BASE */ }; REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) trusted-firmware-a-2.2/plat/hisilicon/hikey960/hikey960_bl2_setup.c000066400000000000000000000223221355360272700250760ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef SPD_opteed #include #endif #include #include "hikey960_def.h" #include "hikey960_private.h" #define BL2_RW_BASE (BL_CODE_END) static meminfo_t bl2_el3_tzram_layout; static console_pl011_t console; extern int load_lpm3(void); enum { BOOT_MODE_RECOVERY = 0, BOOT_MODE_NORMAL, BOOT_MODE_MASK = 1, }; /******************************************************************************* * Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol. * Return 0 on success, -1 otherwise. ******************************************************************************/ int plat_hikey960_bl2_handle_scp_bl2(image_info_t *scp_bl2_image_info) { int i; int *buf; assert(scp_bl2_image_info->image_size < SCP_BL2_SIZE); INFO("BL2: Initiating SCP_BL2 transfer to SCP\n"); INFO("BL2: SCP_BL2: 0x%lx@0x%x\n", scp_bl2_image_info->image_base, scp_bl2_image_info->image_size); buf = (int *)scp_bl2_image_info->image_base; INFO("BL2: SCP_BL2 HEAD:\n"); for (i = 0; i < 64; i += 4) INFO("BL2: SCP_BL2 0x%x 0x%x 0x%x 0x%x\n", buf[i], buf[i+1], buf[i+2], buf[i+3]); buf = (int *)(scp_bl2_image_info->image_base + scp_bl2_image_info->image_size - 256); INFO("BL2: SCP_BL2 TAIL:\n"); for (i = 0; i < 64; i += 4) INFO("BL2: SCP_BL2 0x%x 0x%x 0x%x 0x%x\n", buf[i], buf[i+1], buf[i+2], buf[i+3]); INFO("BL2: SCP_BL2 transferred to SCP\n"); load_lpm3(); (void)buf; return 0; } static void hikey960_ufs_reset(void) { unsigned int data, mask; mmio_write_32(CRG_PERDIS7_REG, 1 << 14); mmio_clrbits_32(UFS_SYS_PHY_CLK_CTRL_REG, BIT_SYSCTRL_REF_CLOCK_EN); do { data = mmio_read_32(UFS_SYS_PHY_CLK_CTRL_REG); } while (data & BIT_SYSCTRL_REF_CLOCK_EN); /* use abb clk */ mmio_clrbits_32(UFS_SYS_UFS_SYSCTRL_REG, BIT_UFS_REFCLK_SRC_SE1); mmio_clrbits_32(UFS_SYS_PHY_ISO_EN_REG, BIT_UFS_REFCLK_ISO_EN); mmio_write_32(PCTRL_PERI_CTRL3_REG, (1 << 0) | (1 << 16)); mdelay(1); mmio_write_32(CRG_PEREN7_REG, 1 << 14); mmio_setbits_32(UFS_SYS_PHY_CLK_CTRL_REG, BIT_SYSCTRL_REF_CLOCK_EN); mmio_write_32(CRG_PERRSTEN3_REG, PERI_UFS_BIT); do { data = mmio_read_32(CRG_PERRSTSTAT3_REG); } while ((data & PERI_UFS_BIT) == 0); mmio_setbits_32(UFS_SYS_PSW_POWER_CTRL_REG, BIT_UFS_PSW_MTCMOS_EN); mdelay(1); mmio_setbits_32(UFS_SYS_HC_LP_CTRL_REG, BIT_SYSCTRL_PWR_READY); mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG, MASK_UFS_DEVICE_RESET); /* clear SC_DIV_UFS_PERIBUS */ mask = SC_DIV_UFS_PERIBUS << 16; mmio_write_32(CRG_CLKDIV17_REG, mask); /* set SC_DIV_UFSPHY_CFG(3) */ mask = SC_DIV_UFSPHY_CFG_MASK << 16; data = SC_DIV_UFSPHY_CFG(3); mmio_write_32(CRG_CLKDIV16_REG, mask | data); data = mmio_read_32(UFS_SYS_PHY_CLK_CTRL_REG); data &= ~MASK_SYSCTRL_CFG_CLOCK_FREQ; data |= 0x39; mmio_write_32(UFS_SYS_PHY_CLK_CTRL_REG, data); mmio_clrbits_32(UFS_SYS_PHY_CLK_CTRL_REG, MASK_SYSCTRL_REF_CLOCK_SEL); mmio_setbits_32(UFS_SYS_CLOCK_GATE_BYPASS_REG, MASK_UFS_CLK_GATE_BYPASS); mmio_setbits_32(UFS_SYS_UFS_SYSCTRL_REG, MASK_UFS_SYSCTRL_BYPASS); mmio_setbits_32(UFS_SYS_PSW_CLK_CTRL_REG, BIT_SYSCTRL_PSW_CLK_EN); mmio_clrbits_32(UFS_SYS_PSW_POWER_CTRL_REG, BIT_UFS_PSW_ISO_CTRL); mmio_clrbits_32(UFS_SYS_PHY_ISO_EN_REG, BIT_UFS_PHY_ISO_CTRL); mmio_clrbits_32(UFS_SYS_HC_LP_CTRL_REG, BIT_SYSCTRL_LP_ISOL_EN); mmio_write_32(CRG_PERRSTDIS3_REG, PERI_ARST_UFS_BIT); mmio_setbits_32(UFS_SYS_RESET_CTRL_EN_REG, BIT_SYSCTRL_LP_RESET_N); mdelay(1); mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG, MASK_UFS_DEVICE_RESET | BIT_UFS_DEVICE_RESET); mdelay(20); mmio_write_32(UFS_SYS_UFS_DEVICE_RESET_CTRL_REG, 0x03300330); mmio_write_32(CRG_PERRSTDIS3_REG, PERI_UFS_BIT); do { data = mmio_read_32(CRG_PERRSTSTAT3_REG); } while (data & PERI_UFS_BIT); } static void hikey960_init_ufs(void) { dw_ufs_params_t ufs_params; memset(&ufs_params, 0, sizeof(ufs_params_t)); ufs_params.reg_base = UFS_REG_BASE; ufs_params.desc_base = HIKEY960_UFS_DESC_BASE; ufs_params.desc_size = HIKEY960_UFS_DESC_SIZE; hikey960_ufs_reset(); dw_ufs_init(&ufs_params); } /******************************************************************************* * Gets SPSR for BL32 entry ******************************************************************************/ uint32_t hikey960_get_spsr_for_bl32_entry(void) { /* * The Secure Payload Dispatcher service is responsible for * setting the SPSR prior to entry into the BL3-2 image. */ return 0; } /******************************************************************************* * Gets SPSR for BL33 entry ******************************************************************************/ #ifdef __aarch64__ uint32_t hikey960_get_spsr_for_bl33_entry(void) { unsigned int mode; uint32_t spsr; /* Figure out what mode we enter the non-secure world in */ mode = (el_implemented(2) != EL_IMPL_NONE) ? MODE_EL2 : MODE_EL1; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; } #else uint32_t hikey960_get_spsr_for_bl33_entry(void) { unsigned int hyp_status, mode, spsr; hyp_status = GET_VIRT_EXT(read_id_pfr1()); mode = (hyp_status) ? MODE32_hyp : MODE32_svc; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_MODE32(mode, plat_get_ns_image_entrypoint() & 0x1, SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS); return spsr; } #endif /* __aarch64__ */ int hikey960_bl2_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); #ifdef SPD_opteed bl_mem_params_node_t *pager_mem_params = NULL; bl_mem_params_node_t *paged_mem_params = NULL; #endif assert(bl_mem_params); switch (image_id) { #ifdef __aarch64__ case BL32_IMAGE_ID: #ifdef SPD_opteed 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); err = parse_optee_header(&bl_mem_params->ep_info, &pager_mem_params->image_info, &paged_mem_params->image_info); if (err != 0) { WARN("OPTEE header parse error.\n"); } #endif bl_mem_params->ep_info.spsr = hikey960_get_spsr_for_bl32_entry(); break; #endif case BL33_IMAGE_ID: /* BL33 expects to receive the primary CPU MPID (through r0) */ bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr(); bl_mem_params->ep_info.spsr = hikey960_get_spsr_for_bl33_entry(); break; #ifdef SCP_BL2_BASE case SCP_BL2_IMAGE_ID: /* The subsequent handling of SCP_BL2 is platform specific */ err = plat_hikey960_bl2_handle_scp_bl2(&bl_mem_params->image_info); if (err) { WARN("Failure in platform-specific handling of SCP_BL2 image.\n"); } break; #endif default: /* Do nothing in default case */ break; } return err; } /******************************************************************************* * This function can be used by the platforms to update/use image * information for given `image_id`. ******************************************************************************/ int bl2_plat_handle_pre_image_load(unsigned int image_id) { return hikey960_set_fip_addr(image_id, "fip"); } int bl2_plat_handle_post_image_load(unsigned int image_id) { return hikey960_bl2_handle_post_image_load(image_id); } void bl2_el3_early_platform_setup(u_register_t arg1, u_register_t arg2, u_register_t arg3, u_register_t arg4) { unsigned int id, uart_base; generic_delay_timer_init(); hikey960_read_boardid(&id); if (id == 5300) uart_base = PL011_UART5_BASE; else uart_base = PL011_UART6_BASE; /* Initialize the console to provide early debug support */ console_pl011_register(uart_base, PL011_UART_CLK_IN_HZ, PL011_BAUDRATE, &console); /* * Allow BL2 to see the whole Trusted RAM. */ bl2_el3_tzram_layout.total_base = BL2_RW_BASE; bl2_el3_tzram_layout.total_size = BL31_LIMIT - BL2_RW_BASE; } void bl2_el3_plat_arch_setup(void) { hikey960_init_mmu_el3(bl2_el3_tzram_layout.total_base, bl2_el3_tzram_layout.total_size, BL_CODE_BASE, BL_CODE_END, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); } void bl2_platform_setup(void) { /* disable WDT0 */ if (mmio_read_32(WDT0_REG_BASE + WDT_LOCK_OFFSET) == WDT_LOCKED) { mmio_write_32(WDT0_REG_BASE + WDT_LOCK_OFFSET, WDT_UNLOCK); mmio_write_32(WDT0_REG_BASE + WDT_CONTROL_OFFSET, 0); mmio_write_32(WDT0_REG_BASE + WDT_LOCK_OFFSET, 0); } hikey960_clk_init(); hikey960_pmu_init(); hikey960_regulator_enable(); hikey960_tzc_init(); hikey960_peri_init(); hikey960_pinmux_init(); hikey960_gpio_init(); hikey960_init_ufs(); hikey960_io_setup(); } trusted-firmware-a-2.2/plat/hisilicon/hikey960/hikey960_bl31_setup.c000066400000000000000000000120241355360272700251560ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hikey960_def.h" #include "hikey960_private.h" static entry_point_info_t bl32_ep_info; static entry_point_info_t bl33_ep_info; static console_pl011_t console; /****************************************************************************** * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0 * interrupts. *****************************************************************************/ static const interrupt_prop_t g0_interrupt_props[] = { INTR_PROP_DESC(IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), }; const gicv2_driver_data_t hikey960_gic_data = { .gicd_base = GICD_REG_BASE, .gicc_base = GICC_REG_BASE, .interrupt_props = g0_interrupt_props, .interrupt_props_num = ARRAY_SIZE(g0_interrupt_props), }; static const int cci_map[] = { CCI400_SL_IFACE3_CLUSTER_IX, CCI400_SL_IFACE4_CLUSTER_IX }; entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; next_image_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info; /* None of the images on this platform can have 0x0 as the entrypoint */ if (next_image_info->pc) return next_image_info; return NULL; } void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { unsigned int id, uart_base; void *from_bl2; from_bl2 = (void *) arg0; generic_delay_timer_init(); hikey960_read_boardid(&id); if (id == 5300) uart_base = PL011_UART5_BASE; else uart_base = PL011_UART6_BASE; /* Initialize the console to provide early debug support */ console_pl011_register(uart_base, PL011_UART_CLK_IN_HZ, PL011_BAUDRATE, &console); /* Initialize CCI driver */ cci_init(CCI400_REG_BASE, cci_map, ARRAY_SIZE(cci_map)); cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); /* * Check params passed from BL2 should not be NULL, */ bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2; assert(params_from_bl2 != NULL); assert(params_from_bl2->h.type == PARAM_BL_PARAMS); assert(params_from_bl2->h.version >= VERSION_2); bl_params_node_t *bl_params = params_from_bl2->head; /* * Copy BL33 and BL32 (if present), entry point information. * They are stored in Secure RAM, in BL2's address space. */ while (bl_params) { if (bl_params->image_id == BL32_IMAGE_ID) bl32_ep_info = *bl_params->ep_info; if (bl_params->image_id == BL33_IMAGE_ID) bl33_ep_info = *bl_params->ep_info; bl_params = bl_params->next_params_info; } if (bl33_ep_info.pc == 0) panic(); } void bl31_plat_arch_setup(void) { hikey960_init_mmu_el3(BL31_BASE, BL31_LIMIT - BL31_BASE, BL_CODE_BASE, BL_CODE_END, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); } static void hikey960_edma_init(void) { int i; uint32_t non_secure; non_secure = EDMAC_SEC_CTRL_INTR_SEC | EDMAC_SEC_CTRL_GLOBAL_SEC; mmio_write_32(EDMAC_SEC_CTRL, non_secure); /* Channel 0 is reserved for LPM3, keep secure */ for (i = 1; i < EDMAC_CHANNEL_NUMS; i++) { mmio_write_32(EDMAC_AXI_CONF(i), (1 << 6) | (1 << 18)); } } static void hikey960_iomcu_dma_init(void) { int i; uint32_t non_secure; non_secure = IOMCU_DMAC_SEC_CTRL_INTR_SEC | IOMCU_DMAC_SEC_CTRL_GLOBAL_SEC; mmio_write_32(IOMCU_DMAC_SEC_CTRL, non_secure); /* channels 0-3 are reserved */ for (i = 4; i < IOMCU_DMAC_CHANNEL_NUMS; i++) { mmio_write_32(IOMCU_DMAC_AXI_CONF(i), IOMCU_DMAC_AXI_CONF_ARPROT_NS | IOMCU_DMAC_AXI_CONF_AWPROT_NS); } } void bl31_platform_setup(void) { /* Initialize the GIC driver, cpu and distributor interfaces */ gicv2_driver_init(&hikey960_gic_data); gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); hikey960_edma_init(); hikey960_iomcu_dma_init(); hisi_ipc_init(); } #ifdef SPD_none static uint64_t hikey_debug_fiq_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { int intr, intr_raw; /* Acknowledge interrupt */ intr_raw = plat_ic_acknowledge_interrupt(); intr = plat_ic_get_interrupt_id(intr_raw); ERROR("Invalid interrupt: intr=%d\n", intr); console_flush(); panic(); return 0; } #endif void bl31_plat_runtime_setup(void) { #ifdef SPD_none uint32_t flags; int32_t rc; flags = 0; set_interrupt_rm_flag(flags, NON_SECURE); rc = register_interrupt_type_handler(INTR_TYPE_S_EL1, hikey_debug_fiq_handler, flags); if (rc != 0) panic(); #endif } trusted-firmware-a-2.2/plat/hisilicon/hikey960/hikey960_bl_common.c000066400000000000000000000316311355360272700251470ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "hikey960_private.h" void hikey960_clk_init(void) { /* change ldi0 sel to ppll2 */ mmio_write_32(0xfff350b4, 0xf0002000); /* ldi0 20' */ mmio_write_32(0xfff350bc, 0xfc004c00); } void hikey960_pmu_init(void) { /* clear np_xo_abb_dig_START bit in PMIC_CLK_TOP_CTRL7 register */ mmio_clrbits_32(PMU_SSI0_CLK_TOP_CTRL7_REG, NP_XO_ABB_DIG); } static void hikey960_enable_ppll3(void) { /* enable ppll3 */ mmio_write_32(PMC_PPLL3_CTRL0_REG, 0x4904305); mmio_write_32(PMC_PPLL3_CTRL1_REG, 0x2300000); mmio_write_32(PMC_PPLL3_CTRL1_REG, 0x6300000); } static void bus_idle_clear(unsigned int value) { unsigned int pmc_value, value1, value2; int timeout = 100; pmc_value = value << 16; pmc_value &= ~value; mmio_write_32(PMC_NOC_POWER_IDLEREQ_REG, pmc_value); for (;;) { value1 = (unsigned int)mmio_read_32(PMC_NOC_POWER_IDLEACK_REG); value2 = (unsigned int)mmio_read_32(PMC_NOC_POWER_IDLE_REG); if (((value1 & value) == 0) && ((value2 & value) == 0)) break; udelay(1); timeout--; if (timeout <= 0) { WARN("%s timeout\n", __func__); break; } } } static void set_vivobus_power_up(void) { /* clk enable */ mmio_write_32(CRG_CLKDIV20_REG, 0x00020002); mmio_write_32(CRG_PEREN0_REG, 0x00001000); } static void set_dss_power_up(void) { /* set edc0 133MHz = 1600MHz / 12 */ mmio_write_32(CRG_CLKDIV5_REG, 0x003f000b); /* set ldi0 ppl0 */ mmio_write_32(CRG_CLKDIV3_REG, 0xf0001000); /* set ldi0 133MHz, 1600MHz / 12 */ mmio_write_32(CRG_CLKDIV5_REG, 0xfc002c00); /* mtcmos on */ mmio_write_32(CRG_PERPWREN_REG, 0x00000020); udelay(100); /* DISP CRG */ mmio_write_32(CRG_PERRSTDIS4_REG, 0x00000010); /* clk enable */ mmio_write_32(CRG_CLKDIV18_REG, 0x01400140); mmio_write_32(CRG_PEREN0_REG, 0x00002000); mmio_write_32(CRG_PEREN3_REG, 0x0003b000); udelay(1); /* clk disable */ mmio_write_32(CRG_PERDIS3_REG, 0x0003b000); mmio_write_32(CRG_PERDIS0_REG, 0x00002000); mmio_write_32(CRG_CLKDIV18_REG, 0x01400000); udelay(1); /* iso disable */ mmio_write_32(CRG_ISODIS_REG, 0x00000040); /* unreset */ mmio_write_32(CRG_PERRSTDIS4_REG, 0x00000006); mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000c00); /* clk enable */ mmio_write_32(CRG_CLKDIV18_REG, 0x01400140); mmio_write_32(CRG_PEREN0_REG, 0x00002000); mmio_write_32(CRG_PEREN3_REG, 0x0003b000); /* bus idle clear */ bus_idle_clear(PMC_NOC_POWER_IDLEREQ_DSS); /* set edc0 400MHz for 2K 1600MHz / 4 */ mmio_write_32(CRG_CLKDIV5_REG, 0x003f0003); /* set ldi 266MHz, 1600MHz / 6 */ mmio_write_32(CRG_CLKDIV5_REG, 0xfc001400); } static void set_vcodec_power_up(void) { /* clk enable */ mmio_write_32(CRG_CLKDIV20_REG, 0x00040004); mmio_write_32(CRG_PEREN0_REG, 0x00000060); mmio_write_32(CRG_PEREN2_REG, 0x10000000); /* unreset */ mmio_write_32(CRG_PERRSTDIS0_REG, 0x00000018); /* bus idle clear */ bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VCODEC); } static void set_vdec_power_up(void) { /* mtcmos on */ mmio_write_32(CRG_PERPWREN_REG, 0x00000004); udelay(100); /* clk enable */ mmio_write_32(CRG_CLKDIV18_REG, 0x80008000); mmio_write_32(CRG_PEREN2_REG, 0x20080000); mmio_write_32(CRG_PEREN3_REG, 0x00000800); udelay(1); /* clk disable */ mmio_write_32(CRG_PERDIS3_REG, 0x00000800); mmio_write_32(CRG_PERDIS2_REG, 0x20080000); mmio_write_32(CRG_CLKDIV18_REG, 0x80000000); udelay(1); /* iso disable */ mmio_write_32(CRG_ISODIS_REG, 0x00000004); /* unreset */ mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000200); /* clk enable */ mmio_write_32(CRG_CLKDIV18_REG, 0x80008000); mmio_write_32(CRG_PEREN2_REG, 0x20080000); mmio_write_32(CRG_PEREN3_REG, 0x00000800); /* bus idle clear */ bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VDEC); } static void set_venc_power_up(void) { /* set venc ppll3 */ mmio_write_32(CRG_CLKDIV8_REG, 0x18001000); /* set venc 258MHz, 1290MHz / 5 */ mmio_write_32(CRG_CLKDIV8_REG, 0x07c00100); /* mtcmos on */ mmio_write_32(CRG_PERPWREN_REG, 0x00000002); udelay(100); /* clk enable */ mmio_write_32(CRG_CLKDIV19_REG, 0x00010001); mmio_write_32(CRG_PEREN2_REG, 0x40000100); mmio_write_32(CRG_PEREN3_REG, 0x00000400); udelay(1); /* clk disable */ mmio_write_32(CRG_PERDIS3_REG, 0x00000400); mmio_write_32(CRG_PERDIS2_REG, 0x40000100); mmio_write_32(CRG_CLKDIV19_REG, 0x00010000); udelay(1); /* iso disable */ mmio_write_32(CRG_ISODIS_REG, 0x00000002); /* unreset */ mmio_write_32(CRG_PERRSTDIS3_REG, 0x00000100); /* clk enable */ mmio_write_32(CRG_CLKDIV19_REG, 0x00010001); mmio_write_32(CRG_PEREN2_REG, 0x40000100); mmio_write_32(CRG_PEREN3_REG, 0x00000400); /* bus idle clear */ bus_idle_clear(PMC_NOC_POWER_IDLEREQ_VENC); /* set venc 645MHz, 1290MHz / 2 */ mmio_write_32(CRG_CLKDIV8_REG, 0x07c00040); } static void set_isp_power_up(void) { /* mtcmos on */ mmio_write_32(CRG_PERPWREN_REG, 0x00000001); udelay(100); /* clk enable */ mmio_write_32(CRG_CLKDIV18_REG, 0x70007000); mmio_write_32(CRG_CLKDIV20_REG, 0x00100010); mmio_write_32(CRG_PEREN5_REG, 0x01000010); mmio_write_32(CRG_PEREN3_REG, 0x0bf00000); udelay(1); /* clk disable */ mmio_write_32(CRG_PERDIS5_REG, 0x01000010); mmio_write_32(CRG_PERDIS3_REG, 0x0bf00000); mmio_write_32(CRG_CLKDIV18_REG, 0x70000000); mmio_write_32(CRG_CLKDIV20_REG, 0x00100000); udelay(1); /* iso disable */ mmio_write_32(CRG_ISODIS_REG, 0x00000001); /* unreset */ mmio_write_32(CRG_ISP_SEC_RSTDIS_REG, 0x0000002f); /* clk enable */ mmio_write_32(CRG_CLKDIV18_REG, 0x70007000); mmio_write_32(CRG_CLKDIV20_REG, 0x00100010); mmio_write_32(CRG_PEREN5_REG, 0x01000010); mmio_write_32(CRG_PEREN3_REG, 0x0bf00000); /* bus idle clear */ bus_idle_clear(PMC_NOC_POWER_IDLEREQ_ISP); /* csi clk enable */ mmio_write_32(CRG_PEREN3_REG, 0x00700000); } static void set_ivp_power_up(void) { /* set ivp ppll0 */ mmio_write_32(CRG_CLKDIV0_REG, 0xc0000000); /* set ivp 267MHz, 1600MHz / 6 */ mmio_write_32(CRG_CLKDIV0_REG, 0x3c001400); /* mtcmos on */ mmio_write_32(CRG_PERPWREN_REG, 0x00200000); udelay(100); /* IVP CRG unreset */ mmio_write_32(CRG_IVP_SEC_RSTDIS_REG, 0x00000001); /* clk enable */ mmio_write_32(CRG_CLKDIV20_REG, 0x02000200); mmio_write_32(CRG_PEREN4_REG, 0x000000a8); udelay(1); /* clk disable */ mmio_write_32(CRG_PERDIS4_REG, 0x000000a8); mmio_write_32(CRG_CLKDIV20_REG, 0x02000000); udelay(1); /* iso disable */ mmio_write_32(CRG_ISODIS_REG, 0x01000000); /* unreset */ mmio_write_32(CRG_IVP_SEC_RSTDIS_REG, 0x00000002); /* clk enable */ mmio_write_32(CRG_CLKDIV20_REG, 0x02000200); mmio_write_32(CRG_PEREN4_REG, 0x000000a8); /* bus idle clear */ bus_idle_clear(PMC_NOC_POWER_IDLEREQ_IVP); /* set ivp 533MHz, 1600MHz / 3 */ mmio_write_32(CRG_CLKDIV0_REG, 0x3c000800); } static void set_audio_power_up(void) { unsigned int ret; int timeout = 100; /* mtcmos on */ mmio_write_32(SCTRL_SCPWREN_REG, 0x00000001); udelay(100); /* clk enable */ mmio_write_32(CRG_CLKDIV19_REG, 0x80108010); mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010001); mmio_write_32(SCTRL_SCPEREN0_REG, 0x0c000000); mmio_write_32(CRG_PEREN0_REG, 0x04000000); mmio_write_32(CRG_PEREN5_REG, 0x00000080); mmio_write_32(SCTRL_SCPEREN1_REG, 0x0000000f); udelay(1); /* clk disable */ mmio_write_32(SCTRL_SCPERDIS1_REG, 0x0000000f); mmio_write_32(SCTRL_SCPERDIS0_REG, 0x0c000000); mmio_write_32(CRG_PERDIS5_REG, 0x00000080); mmio_write_32(CRG_PERDIS0_REG, 0x04000000); mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010000); mmio_write_32(CRG_CLKDIV19_REG, 0x80100000); udelay(1); /* iso disable */ mmio_write_32(SCTRL_SCISODIS_REG, 0x00000001); udelay(1); /* unreset */ mmio_write_32(SCTRL_PERRSTDIS1_SEC_REG, 0x00000001); mmio_write_32(SCTRL_SCPERRSTDIS0_REG, 0x00000780); /* clk enable */ mmio_write_32(CRG_CLKDIV19_REG, 0x80108010); mmio_write_32(SCTRL_SCCLKDIV2_REG, 0x00010001); mmio_write_32(SCTRL_SCPEREN0_REG, 0x0c000000); mmio_write_32(CRG_PEREN0_REG, 0x04000000); mmio_write_32(CRG_PEREN5_REG, 0x00000080); mmio_write_32(SCTRL_SCPEREN1_REG, 0x0000000f); /* bus idle clear */ mmio_write_32(SCTRL_SCPERCTRL7_REG, 0x00040000); for (;;) { ret = mmio_read_32(SCTRL_SCPERSTAT6_REG); if (((ret & (1 << 5)) == 0) && ((ret & (1 << 8)) == 0)) break; udelay(1); timeout--; if (timeout <= 0) { WARN("%s timeout\n", __func__); break; } } mmio_write_32(ASP_CFG_MMBUF_CTRL_REG, 0x00ff0000); } static void set_pcie_power_up(void) { /* mtcmos on */ mmio_write_32(SCTRL_SCPWREN_REG, 0x00000010); udelay(100); /* clk enable */ mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000800); mmio_write_32(SCTRL_SCPEREN2_REG, 0x00104000); mmio_write_32(CRG_PEREN7_REG, 0x000003a0); udelay(1); /* clk disable */ mmio_write_32(SCTRL_SCPERDIS2_REG, 0x00104000); mmio_write_32(CRG_PERDIS7_REG, 0x000003a0); mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000000); udelay(1); /* iso disable */ mmio_write_32(SCTRL_SCISODIS_REG, 0x00000030); /* unreset */ mmio_write_32(CRG_PERRSTDIS3_REG, 0x8c000000); /* clk enable */ mmio_write_32(SCTRL_SCCLKDIV6_REG, 0x08000800); mmio_write_32(SCTRL_SCPEREN2_REG, 0x00104000); mmio_write_32(CRG_PEREN7_REG, 0x000003a0); } static void ispfunc_enable(void) { /* enable ispfunc. Otherwise powerup isp_srt causes exception. */ mmio_write_32(0xfff35000, 0x00000008); mmio_write_32(0xfff35460, 0xc004ffff); mmio_write_32(0xfff35030, 0x02000000); mdelay(10); } static void isps_control_clock(int flag) { unsigned int ret; /* flag: 0 -- disable clock, 1 -- enable clock */ if (flag) { ret = mmio_read_32(0xe8420364); ret |= 1; mmio_write_32(0xe8420364, ret); } else { ret = mmio_read_32(0xe8420364); ret &= ~1; mmio_write_32(0xe8420364, ret); } } static void set_isp_srt_power_up(void) { unsigned int ret; ispfunc_enable(); /* reset */ mmio_write_32(0xe8420374, 0x00000001); mmio_write_32(0xe8420350, 0x00000000); mmio_write_32(0xe8420358, 0x00000000); /* mtcmos on */ mmio_write_32(0xfff35150, 0x00400000); udelay(100); /* clk enable */ isps_control_clock(1); udelay(1); isps_control_clock(0); udelay(1); /* iso disable */ mmio_write_32(0xfff35148, 0x08000000); /* unreset */ ret = mmio_read_32(0xe8420374); ret &= ~0x1; mmio_write_32(0xe8420374, ret); /* clk enable */ isps_control_clock(1); /* enable clock gating for accessing csi registers */ mmio_write_32(0xe8420010, ~0); } void hikey960_regulator_enable(void) { set_vivobus_power_up(); hikey960_enable_ppll3(); set_dss_power_up(); set_vcodec_power_up(); set_vdec_power_up(); set_venc_power_up(); set_isp_power_up(); set_ivp_power_up(); set_audio_power_up(); set_pcie_power_up(); set_isp_srt_power_up(); /* set ISP_CORE_CTRL_S to unsecure mode */ mmio_write_32(0xe8583800, 0x7); /* set ISP_SUB_CTRL_S to unsecure mode */ mmio_write_32(0xe8583804, 0xf); } void hikey960_tzc_init(void) { mmio_write_32(TZC_EN0_REG, 0x7fbff066); mmio_write_32(TZC_EN1_REG, 0xfffff5fc); mmio_write_32(TZC_EN2_REG, 0x0007005c); mmio_write_32(TZC_EN3_REG, 0x37030700); mmio_write_32(TZC_EN4_REG, 0xf63fefae); mmio_write_32(TZC_EN5_REG, 0x000410fd); mmio_write_32(TZC_EN6_REG, 0x0063ff68); mmio_write_32(TZC_EN7_REG, 0x030000f3); mmio_write_32(TZC_EN8_REG, 0x00000007); } void hikey960_peri_init(void) { /* unreset */ mmio_setbits_32(CRG_PERRSTDIS4_REG, 1); } void hikey960_pinmux_init(void) { unsigned int id; hikey960_read_boardid(&id); if (id == 5301) { /* hikey960 hardware v2 */ /* GPIO150: LED */ mmio_write_32(IOMG_FIX_006_REG, 0); /* GPIO151: LED */ mmio_write_32(IOMG_FIX_007_REG, 0); /* GPIO189: LED */ mmio_write_32(IOMG_AO_011_REG, 0); /* GPIO190: LED */ mmio_write_32(IOMG_AO_012_REG, 0); /* GPIO46 */ mmio_write_32(IOMG_044_REG, 0); /* GPIO202 */ mmio_write_32(IOMG_AO_023_REG, 0); /* GPIO206 */ mmio_write_32(IOMG_AO_026_REG, 0); /* GPIO219 - PD pullup */ mmio_write_32(IOMG_AO_039_REG, 0); mmio_write_32(IOCG_AO_043_REG, 1 << 0); } /* GPIO005 - PMU SSI, 10mA */ mmio_write_32(IOCG_006_REG, 2 << 4); /* GPIO213 - PCIE_CLKREQ_N */ mmio_write_32(IOMG_AO_033_REG, 1); } void hikey960_gpio_init(void) { pl061_gpio_init(); pl061_gpio_register(GPIO0_BASE, 0); pl061_gpio_register(GPIO1_BASE, 1); pl061_gpio_register(GPIO2_BASE, 2); pl061_gpio_register(GPIO3_BASE, 3); pl061_gpio_register(GPIO4_BASE, 4); pl061_gpio_register(GPIO5_BASE, 5); pl061_gpio_register(GPIO6_BASE, 6); pl061_gpio_register(GPIO7_BASE, 7); pl061_gpio_register(GPIO8_BASE, 8); pl061_gpio_register(GPIO9_BASE, 9); pl061_gpio_register(GPIO10_BASE, 10); pl061_gpio_register(GPIO11_BASE, 11); pl061_gpio_register(GPIO12_BASE, 12); pl061_gpio_register(GPIO13_BASE, 13); pl061_gpio_register(GPIO14_BASE, 14); pl061_gpio_register(GPIO15_BASE, 15); pl061_gpio_register(GPIO16_BASE, 16); pl061_gpio_register(GPIO17_BASE, 17); pl061_gpio_register(GPIO18_BASE, 18); pl061_gpio_register(GPIO19_BASE, 19); pl061_gpio_register(GPIO20_BASE, 20); pl061_gpio_register(GPIO21_BASE, 21); /* PCIE_PERST_N output low */ gpio_set_direction(89, GPIO_DIR_OUT); gpio_set_value(89, GPIO_LEVEL_LOW); } trusted-firmware-a-2.2/plat/hisilicon/hikey960/hikey960_boardid.c000066400000000000000000000104051355360272700246020ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "hikey960_private.h" #define ADC_ADCIN0 0 #define ADC_ADCIN1 1 #define ADC_ADCIN2 2 #define HKADC_DATA_GRADE0 0 #define HKADC_DATA_GRADE1 100 #define HKADC_DATA_GRADE2 300 #define HKADC_DATA_GRADE3 500 #define HKADC_DATA_GRADE4 700 #define HKADC_DATA_GRADE5 900 #define HKADC_DATA_GRADE6 1100 #define HKADC_DATA_GRADE7 1300 #define HKADC_DATA_GRADE8 1500 #define HKADC_DATA_GRADE9 1700 #define HKADC_DATA_GRADE10 1800 #define BOARDID_VALUE0 0 #define BOARDID_VALUE1 1 #define BOARDID_VALUE2 2 #define BOARDID_VALUE3 3 #define BOARDID_VALUE4 4 #define BOARDID_VALUE5 5 #define BOARDID_VALUE6 6 #define BOARDID_VALUE7 7 #define BOARDID_VALUE8 8 #define BOARDID_VALUE9 9 #define BOARDID_UNKNOWN 0xF #define BOARDID3_BASE 5 static void init_adc(void) { /* reset hkadc */ mmio_write_32(CRG_PERRSTEN2_REG, PERRSTEN2_HKADCSSI); /* wait a few clock cycles */ udelay(2); mmio_write_32(CRG_PERRSTDIS2_REG, PERRSTEN2_HKADCSSI); udelay(2); /* enable hkadc clock */ mmio_write_32(CRG_PERDIS2_REG, PEREN2_HKADCSSI); udelay(2); mmio_write_32(CRG_PEREN2_REG, PEREN2_HKADCSSI); udelay(2); } static int get_adc(unsigned int channel, unsigned int *value) { unsigned int data, value1, value0; if (channel > HKADC_CHANNEL_MAX) { WARN("invalid channel:%d\n", channel); return -EFAULT; } /* configure the read/write operation for external HKADC */ mmio_write_32(HKADC_WR01_DATA_REG, HKADC_WR01_VALUE | channel); mmio_write_32(HKADC_WR23_DATA_REG, HKADC_WR23_VALUE); mmio_write_32(HKADC_WR45_DATA_REG, HKADC_WR45_VALUE); /* configure the number of accessing registers */ mmio_write_32(HKADC_WR_NUM_REG, HKADC_WR_NUM_VALUE); /* configure delay of accessing registers */ mmio_write_32(HKADC_DELAY01_REG, HKADC_CHANNEL0_DELAY01_VALUE); mmio_write_32(HKADC_DELAY23_REG, HKADC_DELAY23_VALUE); /* start HKADC */ mmio_write_32(HKADC_DSP_START_REG, 1); do { data = mmio_read_32(HKADC_DSP_START_REG); } while (data & 1); /* convert AD result */ value1 = mmio_read_32(HKADC_DSP_RD2_DATA_REG) & 0xffff; value0 = mmio_read_32(HKADC_DSP_RD3_DATA_REG) & 0xffff; data = ((value1 << 4) & HKADC_VALUE_HIGH) | ((value0 >> 4) & HKADC_VALUE_LOW); *value = data; return 0; } static int get_value(unsigned int channel, unsigned int *value) { int ret; ret = get_adc(channel, value); if (ret) return ret; /* convert ADC value to micro-volt */ ret = ((*value & HKADC_VALID_VALUE) * HKADC_VREF_1V8) / HKADC_ACCURACY; *value = ret; return 0; } static int adcin_data_remap(unsigned int adcin_value) { int ret; if (adcin_value < HKADC_DATA_GRADE1) ret = BOARDID_VALUE0; else if (adcin_value < HKADC_DATA_GRADE2) ret = BOARDID_VALUE1; else if (adcin_value < HKADC_DATA_GRADE3) ret = BOARDID_VALUE2; else if (adcin_value < HKADC_DATA_GRADE4) ret = BOARDID_VALUE3; else if (adcin_value < HKADC_DATA_GRADE5) ret = BOARDID_VALUE4; else if (adcin_value < HKADC_DATA_GRADE6) ret = BOARDID_VALUE5; else if (adcin_value < HKADC_DATA_GRADE7) ret = BOARDID_VALUE6; else if (adcin_value < HKADC_DATA_GRADE8) ret = BOARDID_VALUE7; else if (adcin_value < HKADC_DATA_GRADE9) ret = BOARDID_VALUE8; else if (adcin_value < HKADC_DATA_GRADE10) ret = BOARDID_VALUE9; else ret = BOARDID_UNKNOWN; return ret; } int hikey960_read_boardid(unsigned int *id) { unsigned int adcin0, adcin1, adcin2; unsigned int adcin0_remap, adcin1_remap, adcin2_remap; assert(id != NULL); init_adc(); /* read ADC channel0 data */ get_value(ADC_ADCIN0, &adcin0); adcin0_remap = adcin_data_remap(adcin0); if (adcin0_remap == BOARDID_UNKNOWN) return -EINVAL; /* read ADC channel1 data */ get_value(ADC_ADCIN1, &adcin1); adcin1_remap = adcin_data_remap(adcin1); if (adcin1_remap == BOARDID_UNKNOWN) return -EINVAL; /* read ADC channel2 data */ get_value(ADC_ADCIN2, &adcin2); adcin2_remap = adcin_data_remap(adcin2); if (adcin2_remap == BOARDID_UNKNOWN) return -EINVAL; *id = BOARDID3_BASE * 1000 + (adcin2_remap * 100) + (adcin1_remap * 10) + adcin0_remap; return 0; } trusted-firmware-a-2.2/plat/hisilicon/hikey960/hikey960_def.h000066400000000000000000000026341355360272700237460ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HIKEY960_DEF_H #define HIKEY960_DEF_H #include #include #define DDR_BASE 0x0 #define DDR_SIZE 0xE0000000 #define DEVICE_BASE 0xE0000000 #define DEVICE_SIZE 0x20000000 /* Memory location options for TSP */ #define HIKEY960_SRAM_ID 0 #define HIKEY960_DRAM_ID 1 /* * DDR for OP-TEE (32MB from 0x3E00000-0x3FFFFFFF) is divided in several * regions: * - Secure DDR (default is the top 16MB) used by OP-TEE * - Non-secure DDR used by OP-TEE (shared memory and padding) (4MB) * - Secure DDR (4MB aligned on 4MB) for OP-TEE's "Secure Data Path" feature * - Non-secure DDR (8MB) reserved for OP-TEE's future use */ #define DDR_SEC_SIZE 0x01000000 #define DDR_SEC_BASE 0x3F000000 #define DDR_SDP_SIZE 0x00400000 #define DDR_SDP_BASE (DDR_SEC_BASE - 0x400000 /* align */ - \ DDR_SDP_SIZE) /* * PL011 related constants */ #define PL011_UART5_BASE 0xFDF05000 #define PL011_UART6_BASE 0xFFF32000 #define PL011_BAUDRATE 115200 #define PL011_UART_CLK_IN_HZ 19200000 #define UFS_BASE 0 #define HIKEY960_UFS_DESC_BASE 0x20000000 #define HIKEY960_UFS_DESC_SIZE 0x00200000 /* 2MB */ #define HIKEY960_UFS_DATA_BASE 0x10000000 #define HIKEY960_UFS_DATA_SIZE 0x0A000000 /* 160MB */ #endif /* HIKEY960_DEF_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey960/hikey960_image_load.c000066400000000000000000000022631355360272700252620ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /******************************************************************************* * This function flushes the data structures so that they are visible * in memory for the next BL image. ******************************************************************************/ void plat_flush_next_bl_params(void) { flush_bl_params_desc(); } /******************************************************************************* * This function returns the list of loadable images. ******************************************************************************/ bl_load_info_t *plat_get_bl_image_load_info(void) { return get_bl_load_info_from_mem_params_desc(); } /******************************************************************************* * This function returns the list of executable images. ******************************************************************************/ bl_params_t *plat_get_next_bl_params(void) { return get_next_bl_params_from_mem_params_desc(); } trusted-firmware-a-2.2/plat/hisilicon/hikey960/hikey960_io_storage.c000066400000000000000000000156471355360272700253460ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct plat_io_policy { uintptr_t *dev_handle; uintptr_t image_spec; int (*check)(const uintptr_t spec); }; static const io_dev_connector_t *ufs_dev_con, *fip_dev_con; static uintptr_t ufs_dev_handle, fip_dev_handle; static int check_ufs(const uintptr_t spec); static int check_fip(const uintptr_t spec); size_t ufs_read_lun3_blks(int lba, uintptr_t buf, size_t size); size_t ufs_write_lun3_blks(int lba, const uintptr_t buf, size_t size); static io_block_spec_t ufs_fip_spec; static const io_block_spec_t ufs_gpt_spec = { .offset = 0, .length = PLAT_PARTITION_BLOCK_SIZE * (PLAT_PARTITION_MAX_ENTRIES / 4 + 2), }; static const io_block_dev_spec_t ufs_dev_spec = { /* It's used as temp buffer in block driver. */ .buffer = { .offset = HIKEY960_UFS_DATA_BASE, .length = HIKEY960_UFS_DATA_SIZE, }, .ops = { .read = ufs_read_lun3_blks, .write = ufs_write_lun3_blks, }, .block_size = UFS_BLOCK_SIZE, }; static const io_uuid_spec_t scp_bl2_uuid_spec = { .uuid = UUID_SCP_FIRMWARE_SCP_BL2, }; static const io_uuid_spec_t bl31_uuid_spec = { .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31, }; static const io_uuid_spec_t bl32_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32, }; static const io_uuid_spec_t bl32_extra1_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1, }; static const io_uuid_spec_t bl32_extra2_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2, }; static const io_uuid_spec_t bl33_uuid_spec = { .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33, }; #if TRUSTED_BOARD_BOOT static const io_uuid_spec_t trusted_key_cert_uuid_spec = { .uuid = UUID_TRUSTED_KEY_CERT, }; static const io_uuid_spec_t scp_fw_key_cert_uuid_spec = { .uuid = UUID_SCP_FW_KEY_CERT, }; static const io_uuid_spec_t soc_fw_key_cert_uuid_spec = { .uuid = UUID_SOC_FW_KEY_CERT, }; static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = { .uuid = UUID_TRUSTED_OS_FW_KEY_CERT, }; static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = { .uuid = UUID_NON_TRUSTED_FW_KEY_CERT, }; static const io_uuid_spec_t scp_fw_cert_uuid_spec = { .uuid = UUID_SCP_FW_CONTENT_CERT, }; static const io_uuid_spec_t soc_fw_cert_uuid_spec = { .uuid = UUID_SOC_FW_CONTENT_CERT, }; static const io_uuid_spec_t tos_fw_cert_uuid_spec = { .uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT, }; static const io_uuid_spec_t nt_fw_cert_uuid_spec = { .uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT, }; #endif /* TRUSTED_BOARD_BOOT */ static const struct plat_io_policy policies[] = { [FIP_IMAGE_ID] = { &ufs_dev_handle, (uintptr_t)&ufs_fip_spec, check_ufs }, [SCP_BL2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&scp_bl2_uuid_spec, check_fip }, [BL31_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl31_uuid_spec, check_fip }, [BL32_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_uuid_spec, check_fip }, [BL32_EXTRA1_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_extra1_uuid_spec, check_fip }, [BL32_EXTRA2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_extra2_uuid_spec, check_fip }, [BL33_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl33_uuid_spec, check_fip }, #if TRUSTED_BOARD_BOOT [TRUSTED_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&trusted_key_cert_uuid_spec, check_fip }, [SCP_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&scp_fw_key_cert_uuid_spec, check_fip }, [SOC_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&soc_fw_key_cert_uuid_spec, check_fip }, [TRUSTED_OS_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&tos_fw_key_cert_uuid_spec, check_fip }, [NON_TRUSTED_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&nt_fw_key_cert_uuid_spec, check_fip }, [SCP_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&scp_fw_cert_uuid_spec, check_fip }, [SOC_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&soc_fw_cert_uuid_spec, check_fip }, [TRUSTED_OS_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&tos_fw_cert_uuid_spec, check_fip }, [NON_TRUSTED_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&nt_fw_cert_uuid_spec, check_fip }, #endif /* TRUSTED_BOARD_BOOT */ [GPT_IMAGE_ID] = { &ufs_dev_handle, (uintptr_t)&ufs_gpt_spec, check_ufs }, }; static int check_ufs(const uintptr_t spec) { int result; uintptr_t local_handle; result = io_dev_init(ufs_dev_handle, (uintptr_t)NULL); if (result == 0) { result = io_open(ufs_dev_handle, spec, &local_handle); if (result == 0) io_close(local_handle); } return result; } static int check_fip(const uintptr_t spec) { int result; uintptr_t local_image_handle; /* See if a Firmware Image Package is available */ result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); if (result == 0) { result = io_open(fip_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using FIP\n"); io_close(local_image_handle); } } return result; } void hikey960_io_setup(void) { int result; result = register_io_dev_block(&ufs_dev_con); assert(result == 0); result = register_io_dev_fip(&fip_dev_con); assert(result == 0); result = io_dev_open(ufs_dev_con, (uintptr_t)&ufs_dev_spec, &ufs_dev_handle); assert(result == 0); result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle); assert(result == 0); /* Ignore improbable errors in release builds */ (void)result; } int hikey960_set_fip_addr(unsigned int image_id, const char *name) { const partition_entry_t *entry; if (ufs_fip_spec.length == 0) { partition_init(GPT_IMAGE_ID); entry = get_partition_entry(name); if (entry == NULL) { ERROR("Could NOT find the %s partition!\n", name); return -ENOENT; } ufs_fip_spec.offset = entry->start; ufs_fip_spec.length = entry->length; } return 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 result; const struct plat_io_policy *policy; assert(image_id < ARRAY_SIZE(policies)); policy = &policies[image_id]; result = policy->check(policy->image_spec); assert(result == 0); *image_spec = policy->image_spec; *dev_handle = *(policy->dev_handle); return result; } size_t ufs_read_lun3_blks(int lba, uintptr_t buf, size_t size) { return ufs_read_blocks(3, lba, buf, size); } size_t ufs_write_lun3_blks(int lba, const uintptr_t buf, size_t size) { return ufs_write_blocks(3, lba, buf, size); } trusted-firmware-a-2.2/plat/hisilicon/hikey960/hikey960_mcu_load.c000066400000000000000000000021701355360272700247610ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #define ADDR_CONVERT(addr) ((addr) < 0x40000 ? \ (addr) + 0xFFF30000 : \ (addr) + 0x40000000) static void fw_data_init(void) { unsigned long data_head_addr; unsigned int *data_addr; data_head_addr = mmio_read_32((uintptr_t) HISI_DATA_HEAD_BASE) + 0x14; data_addr = (unsigned int *) ADDR_CONVERT(data_head_addr); memcpy((void *)HISI_DATA0_BASE, (const void *)(unsigned long)ADDR_CONVERT(data_addr[0]), HISI_DATA0_SIZE); memcpy((void *)HISI_DATA1_BASE, (const void *)(unsigned long)ADDR_CONVERT(data_addr[1]), HISI_DATA1_SIZE); } int load_lpm3(void) { INFO("start fw loading\n"); fw_data_init(); flush_dcache_range((uintptr_t)HISI_RESERVED_MEM_BASE, HISI_RESERVED_MEM_SIZE); sev(); sev(); INFO("fw load success\n"); return 0; } trusted-firmware-a-2.2/plat/hisilicon/hikey960/hikey960_pm.c000066400000000000000000000176351355360272700236260ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include "drivers/pwrc/hisi_pwrc.h" #include "hikey960_def.h" #include "hikey960_private.h" #define CORE_PWR_STATE(state) \ ((state)->pwr_domain_state[MPIDR_AFFLVL0]) #define CLUSTER_PWR_STATE(state) \ ((state)->pwr_domain_state[MPIDR_AFFLVL1]) #define SYSTEM_PWR_STATE(state) \ ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) #define DMAC_GLB_REG_SEC 0x694 #define AXI_CONF_BASE 0x820 static unsigned int uart_base; static console_pl011_t console; static uintptr_t hikey960_sec_entrypoint; static void hikey960_pwr_domain_standby(plat_local_state_t cpu_state) { unsigned long scr; scr = read_scr_el3(); /* Enable Physical IRQ and FIQ to wake the CPU */ write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT); /* Add barrier before CPU enter WFI state */ isb(); dsb(); wfi(); /* * Restore SCR to the original value, synchronisazion of * scr_el3 is done by eret while el3_exit to save some * execution cycles. */ write_scr_el3(scr); } static int hikey960_pwr_domain_on(u_register_t mpidr) { unsigned int core = mpidr & MPIDR_CPU_MASK; unsigned int cluster = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS; int cluster_stat = cluster_is_powered_on(cluster); hisi_set_cpu_boot_flag(cluster, core); mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core), hikey960_sec_entrypoint >> 2); if (cluster_stat) hisi_powerup_core(cluster, core); else hisi_powerup_cluster(cluster, core); return PSCI_E_SUCCESS; } static void hikey960_pwr_domain_on_finish(const psci_power_state_t *target_state) { if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } void hikey960_pwr_domain_off(const psci_power_state_t *target_state) { unsigned long mpidr = read_mpidr_el1(); unsigned int core = mpidr & MPIDR_CPU_MASK; unsigned int cluster = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS; clr_ex(); isb(); dsbsy(); gicv2_cpuif_disable(); hisi_clear_cpu_boot_flag(cluster, core); hisi_powerdn_core(cluster, core); /* check if any core is powered up */ if (hisi_test_cpu_down(cluster, core)) { cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); isb(); dsbsy(); hisi_powerdn_cluster(cluster, core); } } static void __dead2 hikey960_system_reset(void) { dsb(); isb(); mdelay(2000); mmio_write_32(SCTRL_SCPEREN1_REG, SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS); mmio_write_32(SCTRL_SCSYSSTAT_REG, 0xdeadbeef); panic(); } int hikey960_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { unsigned int pstate = psci_get_pstate_type(power_state); unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state); int i; assert(req_state); if (pwr_lvl > PLAT_MAX_PWR_LVL) return PSCI_E_INVALID_PARAMS; /* Sanity check the requested state */ if (pstate == PSTATE_TYPE_STANDBY) { /* * It's possible to enter standby only on power level 0 * Ignore any other power level. */ if (pwr_lvl != MPIDR_AFFLVL0) return PSCI_E_INVALID_PARAMS; req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE; } else { for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++) req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; } /* * We expect the 'state id' to be zero. */ if (psci_get_pstate_id(power_state)) return PSCI_E_INVALID_PARAMS; return PSCI_E_SUCCESS; } static int hikey960_validate_ns_entrypoint(uintptr_t entrypoint) { /* * Check if the non secure entrypoint lies within the non * secure DRAM. */ if ((entrypoint > DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE))) return PSCI_E_SUCCESS; return PSCI_E_INVALID_ADDRESS; } static void hikey960_pwr_domain_suspend(const psci_power_state_t *target_state) { u_register_t mpidr = read_mpidr_el1(); unsigned int core = mpidr & MPIDR_CPU_MASK; unsigned int cluster = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS; if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) return; if (CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { clr_ex(); isb(); dsbsy(); gicv2_cpuif_disable(); hisi_cpuidle_lock(cluster, core); hisi_set_cpuidle_flag(cluster, core); hisi_cpuidle_unlock(cluster, core); mmio_write_32(CRG_REG_BASE + CRG_RVBAR(cluster, core), hikey960_sec_entrypoint >> 2); hisi_enter_core_idle(cluster, core); } /* Perform the common cluster specific operations */ if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { hisi_cpuidle_lock(cluster, core); hisi_disable_pdc(cluster); /* check if any core is powered up */ if (hisi_test_pwrdn_allcores(cluster, core)) { cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); isb(); dsbsy(); /* mask the pdc wakeup irq, then * enable pdc to power down the core */ hisi_pdc_mask_cluster_wakeirq(cluster); hisi_enable_pdc(cluster); hisi_cpuidle_unlock(cluster, core); /* check the SR flag bit to determine * CLUSTER_IDLE_IPC or AP_SR_IPC to send */ if (hisi_test_ap_suspend_flag()) hisi_enter_ap_suspend(cluster, core); else hisi_enter_cluster_idle(cluster, core); } else { /* enable pdc */ hisi_enable_pdc(cluster); hisi_cpuidle_unlock(cluster, core); } } } static void hikey960_sr_dma_reinit(void) { unsigned int ctr = 0; mmio_write_32(DMAC_BASE + DMAC_GLB_REG_SEC, 0x3); /* 1~15 channel is set non_secure */ for (ctr = 1; ctr <= 15; ctr++) mmio_write_32(DMAC_BASE + AXI_CONF_BASE + ctr * (0x40), (1 << 6) | (1 << 18)); } static void hikey960_pwr_domain_suspend_finish(const psci_power_state_t *target_state) { unsigned long mpidr = read_mpidr_el1(); unsigned int core = mpidr & MPIDR_CPU_MASK; unsigned int cluster = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS; /* Nothing to be done on waking up from retention from CPU level */ if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) return; hisi_cpuidle_lock(cluster, core); hisi_clear_cpuidle_flag(cluster, core); hisi_cpuidle_unlock(cluster, core); if (hisi_test_ap_suspend_flag()) { hikey960_sr_dma_reinit(); gicv2_cpuif_enable(); console_pl011_register(uart_base, PL011_UART_CLK_IN_HZ, PL011_BAUDRATE, &console); } hikey960_pwr_domain_on_finish(target_state); } static void hikey960_get_sys_suspend_power_state(psci_power_state_t *req_state) { int i; for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; } static const plat_psci_ops_t hikey960_psci_ops = { .cpu_standby = hikey960_pwr_domain_standby, .pwr_domain_on = hikey960_pwr_domain_on, .pwr_domain_on_finish = hikey960_pwr_domain_on_finish, .pwr_domain_off = hikey960_pwr_domain_off, .pwr_domain_suspend = hikey960_pwr_domain_suspend, .pwr_domain_suspend_finish = hikey960_pwr_domain_suspend_finish, .system_off = NULL, .system_reset = hikey960_system_reset, .validate_power_state = hikey960_validate_power_state, .validate_ns_entrypoint = hikey960_validate_ns_entrypoint, .get_sys_suspend_power_state = hikey960_get_sys_suspend_power_state, }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { unsigned int id = 0; int ret; ret = hikey960_read_boardid(&id); if (ret == 0) { if (id == 5300U) uart_base = PL011_UART5_BASE; else uart_base = PL011_UART6_BASE; } else { uart_base = PL011_UART6_BASE; } hikey960_sec_entrypoint = sec_entrypoint; INFO("%s: sec_entrypoint=0x%lx\n", __func__, (unsigned long)hikey960_sec_entrypoint); /* * Initialize PSCI ops struct */ *psci_ops = &hikey960_psci_ops; return 0; } trusted-firmware-a-2.2/plat/hisilicon/hikey960/hikey960_private.h000066400000000000000000000022131355360272700246530ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HIKEY960_PRIVATE_H #define HIKEY960_PRIVATE_H #include /* * Function and variable prototypes */ void hikey960_init_mmu_el1(unsigned long total_base, unsigned long total_size, unsigned long ro_start, unsigned long ro_limit, unsigned long coh_start, unsigned long coh_limit); void hikey960_init_mmu_el3(unsigned long total_base, unsigned long total_size, unsigned long ro_start, unsigned long ro_limit, unsigned long coh_start, unsigned long coh_limit); void hikey960_io_setup(void); int hikey960_read_boardid(unsigned int *id); int hikey960_set_fip_addr(unsigned int image_id, const char *name); void hikey960_clk_init(void); void hikey960_pmu_init(void); void hikey960_regulator_enable(void); void hikey960_tzc_init(void); void hikey960_peri_init(void); void hikey960_pinmux_init(void); void hikey960_gpio_init(void); void set_retention_ticks(unsigned int val); void clr_retention_ticks(unsigned int val); void clr_ex(void); void nop(void); #endif /* HIKEY960_PRIVATE_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey960/hikey960_rotpk.S000066400000000000000000000007071355360272700243210ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ .global hikey960_rotpk_hash .global hikey960_rotpk_hash_end .section .rodata.hikey960_rotpk_hash, "a" hikey960_rotpk_hash: /* DER header */ .byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48 .byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 /* SHA256 */ .incbin ROTPK_HASH hikey960_rotpk_hash_end: trusted-firmware-a-2.2/plat/hisilicon/hikey960/hikey960_tbbr.c000066400000000000000000000013501355360272700241260ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include extern char hikey960_rotpk_hash[], hikey960_rotpk_hash_end[]; int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, unsigned int *flags) { *key_ptr = hikey960_rotpk_hash; *key_len = hikey960_rotpk_hash_end - hikey960_rotpk_hash; *flags = ROTPK_IS_HASH; return 0; } int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr) { *nv_ctr = 0; return 0; } int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr) { return 1; } int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size) { return get_mbedtls_heap_helper(heap_addr, heap_size); } trusted-firmware-a-2.2/plat/hisilicon/hikey960/hikey960_topology.c000066400000000000000000000041471355360272700250600ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /* * The HiKey power domain tree descriptor. The cluster power domains * are arranged so that when the PSCI generic code creates the power * domain tree, the indices of the CPU power domain nodes it allocates * match the linear indices returned by plat_core_pos_by_mpidr(). */ const unsigned char hikey960_power_domain_tree_desc[] = { /* Number of root nodes */ 1, /* Number of clusters */ PLATFORM_CLUSTER_COUNT, /* Number of children for the first cluster node */ PLATFORM_CORE_COUNT_PER_CLUSTER, /* Number of children for the second cluster node */ PLATFORM_CORE_COUNT_PER_CLUSTER, }; /******************************************************************************* * This function returns the HiKey topology tree information. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { return hikey960_power_domain_tree_desc; } /******************************************************************************* * This function implements a part of the critical interface between the psci * generic layer and the platform that allows the former to query the platform * to convert an MPIDR to a unique linear index. An error code (-1) is returned * in case the MPIDR is invalid. ******************************************************************************/ int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; mpidr &= MPIDR_AFFINITY_MASK; if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) return -1; cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; if (cluster_id >= PLATFORM_CLUSTER_COUNT) return -1; /* * Validate cpu_id by checking whether it represents a CPU in * one of the two clusters present on the platform. */ if (cpu_id >= PLATFORM_CORE_COUNT_PER_CLUSTER) return -1; return (cpu_id + (cluster_id * 4)); } trusted-firmware-a-2.2/plat/hisilicon/hikey960/include/000077500000000000000000000000001355360272700230255ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/hisilicon/hikey960/include/hi3660.h000066400000000000000000000325411355360272700241220ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HI3660_H #define HI3660_H #include #include #include #define ASP_CFG_REG_BASE 0xE804E000 #define ASP_CFG_MMBUF_CTRL_REG (ASP_CFG_REG_BASE + 0x148) #define LP_RAM_BASE 0xFFF50000 #define SCTRL_REG_BASE 0xFFF0A000 #define SCTRL_CONTROL_REG (SCTRL_REG_BASE + 0x000) #define SCTRL_CONTROL_SYS_MODE(x) (((x) & 0xf) << 3) #define SCTRL_CONTROL_SYS_MODE_NORMAL ((1 << 2) << 3) #define SCTRL_CONTROL_SYS_MODE_SLOW ((1 << 1) << 3) #define SCTRL_CONTROL_SYS_MODE_MASK (0xf << 3) #define SCTRL_CONTROL_MODE_CTRL_NORMAL (1 << 2) #define SCTRL_CONTROL_MODE_CTRL_SLOW (1 << 1) #define SCTRL_CONTROL_MODE_CTRL_MASK 0x7 #define SCTRL_SCSYSSTAT_REG (SCTRL_REG_BASE + 0x004) #define SCTRL_DEEPSLEEPED_REG (SCTRL_REG_BASE + 0x008) #define SCTRL_EFUSE_USB_MASK (1 << 30) #define SCTRL_EFUSE_USB_PLL (1 << 30) #define SCTRL_EFUSE_USB_ABB (0 << 30) #define SCTRL_EFUSE_UFS_MASK (3 << 6) #define SCTRL_EFUSE_UFS_PLL (1 << 6) #define SCTRL_EFUSE_UFS_ABB (0 << 6) #define SCTRL_SCISOEN_REG (SCTRL_REG_BASE + 0x040) #define SCTRL_SCISODIS_REG (SCTRL_REG_BASE + 0x044) #define SCISO_MMBUFISO (1 << 3) #define SCTRL_SCPWREN_REG (SCTRL_REG_BASE + 0x060) #define SCPWREN_MMBUFPWREN (1 << 3) #define SCTRL_PLL_CTRL0_REG (SCTRL_REG_BASE + 0x100) #define SCTRL_PLL0_POSTDIV2(x) (((x) & 0x7) << 23) #define SCTRL_PLL0_POSTDIV1(x) (((x) & 0x7) << 20) #define SCTRL_PLL0_FBDIV(x) (((x) & 0xfff) << 8) #define SCTRL_PLL0_REFDIV(x) (((x) & 0x3f) << 2) #define SCTRL_PLL0_EN (1 << 0) #define SCTRL_PLL_CTRL1_REG (SCTRL_REG_BASE + 0x104) #define SCTRL_PLL0_CLK_NO_GATE (1 << 26) #define SCTRL_PLL0_CFG_VLD (1 << 25) #define SCTRL_PLL0_FRACDIV(x) ((x) & 0xFFFFFF) #define SCTRL_PLL_STAT_REG (SCTRL_REG_BASE + 0x10C) #define SCTRL_PLL0_STAT (1 << 0) #define SCTRL_SCPEREN0_REG (SCTRL_REG_BASE + 0x160) #define SCTRL_SCPERDIS0_REG (SCTRL_REG_BASE + 0x164) #define SCTRL_SCPERSTAT0_REG (SCTRL_REG_BASE + 0x168) #define SCTRL_SCPEREN1_REG (SCTRL_REG_BASE + 0x170) #define SCTRL_SCPERDIS1_REG (SCTRL_REG_BASE + 0x174) #define SCTRL_SCPEREN1_REG (SCTRL_REG_BASE + 0x170) #define SCTRL_SCPERDIS1_REG (SCTRL_REG_BASE + 0x174) #define SCPEREN1_WAIT_DDR_SELFREFRESH_DONE_BYPASS (1u << 31) #define SCPEREN_GT_PCLK_MMBUFCFG (1 << 25) #define SCPEREN_GT_PCLK_MMBUF (1 << 23) #define SCPEREN_GT_ACLK_MMBUF (1 << 22) #define SCPEREN_GT_CLK_NOC_AOBUS2MMBUF (1 << 6) #define SCTRL_SCPEREN2_REG (SCTRL_REG_BASE + 0x190) #define SCTRL_SCPERDIS2_REG (SCTRL_REG_BASE + 0x194) #define SCTRL_SCPERSTAT2_REG (SCTRL_REG_BASE + 0x198) #define SCTRL_SCPERRSTEN0_REG (SCTRL_REG_BASE + 0x200) #define SCTRL_SCPERRSTDIS0_REG (SCTRL_REG_BASE + 0x204) #define SCTRL_SCPERRSTSTAT0_REG (SCTRL_REG_BASE + 0x208) #define SCTRL_SCPERRSTEN1_REG (SCTRL_REG_BASE + 0x20C) #define SCTRL_SCPERRSTDIS1_REG (SCTRL_REG_BASE + 0x210) #define SCTRL_SCPERRSTSTAT1_REG (SCTRL_REG_BASE + 0x214) #define IP_RST_MMBUFCFG (1 << 12) #define IP_RST_MMBUF (1 << 11) #define SCTRL_SCPERRSTEN2_REG (SCTRL_REG_BASE + 0x218) #define SCTRL_SCPERRSTDIS2_REG (SCTRL_REG_BASE + 0x21C) #define SCTRL_SCPERRSTSTAT2_REG (SCTRL_REG_BASE + 0x220) #define SCTRL_SCCLKDIV2_REG (SCTRL_REG_BASE + 0x258) #define SEL_CLK_MMBUF_MASK (0x3 << 8) #define SEL_CLK_MMBUF_PLL0 (0x3 << 8) #define SCCLKDIV2_GT_PCLK_MMBUF (1 << 7) #define SCTRL_SCCLKDIV4_REG (SCTRL_REG_BASE + 0x260) #define GT_MMBUF_SYS (1 << 13) #define GT_MMBUF_FLL (1 << 12) #define GT_PLL_CLK_MMBUF (1 << 11) #define SCTRL_SCCLKDIV6_REG (SCTRL_REG_BASE + 0x268) #define SCTRL_SCPERCTRL7_REG (SCTRL_REG_BASE + 0x31C) #define SCTRL_SCPERSTAT6_REG (SCTRL_REG_BASE + 0x378) #define SCTRL_SCINNERSTAT_REG (SCTRL_REG_BASE + 0x3A0) #define EMMC_UFS_SEL (1 << 15) #define SCTRL_BAK_DATA0_REG (SCTRL_REG_BASE + 0x40C) #define SCTRL_BAK_DATA4_REG (SCTRL_REG_BASE + 0x41C) #define SCTRL_LPMCU_CLKEN_REG (SCTRL_REG_BASE + 0x480) #define SCTRL_LPMCU_CLKDIS_REG (SCTRL_REG_BASE + 0x484) #define SCTRL_LPMCU_RSTEN_REG (SCTRL_REG_BASE + 0x500) #define SCTRL_LPMCU_RSTDIS_REG (SCTRL_REG_BASE + 0x504) #define DDRC_SOFT_BIT (1 << 6) #define DDRC_CLK_BIT (1 << 5) #define SCTRL_SCPEREN0_SEC_REG (SCTRL_REG_BASE + 0x900) #define SCTRL_SCPERDIS0_SEC_REG (SCTRL_REG_BASE + 0x904) #define MMBUF_SEC_CTRL_MASK (0xfff << 20) #define MMBUF_SEC_CTRL(x) (((x) & 0xfff) << 20) #define SCTRL_PERRSTEN1_SEC_REG (SCTRL_REG_BASE + 0xA50) #define SCTRL_PERRSTDIS1_SEC_REG (SCTRL_REG_BASE + 0xA54) #define SCTRL_PERRSTSTAT1_SEC_REG (SCTRL_REG_BASE + 0xA58) #define RST_ASP_SUBSYS_BIT (1 << 0) #define SCTRL_PERRSTEN2_SEC_REG (SCTRL_REG_BASE + 0xB50) #define SCTRL_PERRSTDIS2_SEC_REG (SCTRL_REG_BASE + 0xB54) #define SCTRL_PERRSTSTAT2_SEC_REG (SCTRL_REG_BASE + 0xB58) #define SCTRL_HISEECLKDIV_REG (SCTRL_REG_BASE + 0xC28) #define SC_SEL_HISEE_PLL_MASK (1 << 4) #define SC_SEL_HISEE_PLL0 (1 << 4) #define SC_SEL_HISEE_PLL2 (0 << 4) #define SC_DIV_HISEE_PLL_MASK (7 << 16) #define SC_DIV_HISEE_PLL(x) ((x) & 0x7) #define SCTRL_SCSOCID0_REG (SCTRL_REG_BASE + 0xE00) #define PMC_REG_BASE 0xFFF31000 #define PMC_PPLL1_CTRL0_REG (PMC_REG_BASE + 0x038) #define PMC_PPLL1_CTRL1_REG (PMC_REG_BASE + 0x03C) #define PMC_PPLL2_CTRL0_REG (PMC_REG_BASE + 0x040) #define PMC_PPLL2_CTRL1_REG (PMC_REG_BASE + 0x044) #define PMC_PPLL3_CTRL0_REG (PMC_REG_BASE + 0x048) #define PMC_PPLL3_CTRL1_REG (PMC_REG_BASE + 0x04C) #define PPLLx_LOCK (1 << 26) #define PPLLx_WITHOUT_CLK_GATE (1 << 26) #define PPLLx_CFG_VLD (1 << 25) #define PPLLx_INT_MOD (1 << 24) #define PPLLx_POSTDIV2_MASK (0x7 << 23) #define PPLLx_POSTDIV2(x) (((x) & 0x7) << 23) #define PPLLx_POSTDIV1_MASK (0x7 << 20) #define PPLLx_POSTDIV1(x) (((x) & 0x7) << 20) #define PPLLx_FRACDIV_MASK (0x00FFFFFF) #define PPLLx_FRACDIV(x) ((x) & 0x00FFFFFF) #define PPLLx_FBDIV_MASK (0xfff << 8) #define PPLLx_FBDIV(x) (((x) & 0xfff) << 8) #define PPLLx_REFDIV_MASK (0x3f << 2) #define PPLLx_REFDIV(x) (((x) & 0x3f) << 2) #define PPLLx_BP (1 << 1) #define PPLLx_EN (1 << 0) #define PMC_DDRLP_CTRL_REG (PMC_REG_BASE + 0x30C) #define DDRC_CSYSREQ_CFG(x) ((x) & 0xF) #define PMC_NOC_POWER_IDLEREQ_REG (PMC_REG_BASE + 0x380) #define PMC_NOC_POWER_IDLEREQ_IVP (1 << 14) #define PMC_NOC_POWER_IDLEREQ_DSS (1 << 13) #define PMC_NOC_POWER_IDLEREQ_VENC (1 << 11) #define PMC_NOC_POWER_IDLEREQ_VDEC (1 << 10) #define PMC_NOC_POWER_IDLEREQ_ISP (1 << 5) #define PMC_NOC_POWER_IDLEREQ_VCODEC (1 << 4) #define DDRPHY_BYPASS_MODE (1 << 0) #define PMC_NOC_POWER_IDLEACK_REG (PMC_REG_BASE + 0x384) #define PMC_NOC_POWER_IDLE_REG (PMC_REG_BASE + 0x388) #define PMU_SSI0_REG_BASE 0xFFF34000 #define PMU_SSI0_LDO8_CTRL0_REG (PMU_SSI0_REG_BASE + (0x68 << 2)) #define LDO8_CTRL0_EN_1_8V 0x02 #define PMU_SSI0_CLK_TOP_CTRL7_REG (PMU_SSI0_REG_BASE + (0x10C << 2)) #define NP_XO_ABB_DIG (1 << 1) #define LP_CONFIG_REG_BASE 0xFFF3F000 #define DMAC_BASE 0xFDF30000 #define CCI400_REG_BASE 0xE8100000 #define CCI400_SL_IFACE3_CLUSTER_IX 0 #define CCI400_SL_IFACE4_CLUSTER_IX 1 #define GICD_REG_BASE 0xE82B1000 #define GICC_REG_BASE 0xE82B2000 /* * GIC400 interrupt handling related constants */ #define IRQ_SEC_PHY_TIMER 29 #define IRQ_SEC_SGI_0 8 #define IRQ_SEC_SGI_1 9 #define IRQ_SEC_SGI_2 10 #define IRQ_SEC_SGI_3 11 #define IRQ_SEC_SGI_4 12 #define IRQ_SEC_SGI_5 13 #define IRQ_SEC_SGI_6 14 #define IRQ_SEC_SGI_7 15 #define IRQ_SEC_SGI_8 16 #define IPC_REG_BASE 0xE896A000 #define IPC_BASE (IPC_REG_BASE) #define IOMG_REG_BASE 0xE896C000 /* GPIO46: HUB 3.3V enable. active low */ #define IOMG_044_REG (IOMG_REG_BASE + 0x0B0) #define IOMG_UART5_RX_REG (IOMG_REG_BASE + 0x0BC) #define IOMG_UART5_TX_REG (IOMG_REG_BASE + 0x0C0) #define IOCG_REG_BASE 0xE896C800 /* GPIO005: PMIC SSI. (2 << 4) */ #define IOCG_006_REG (IOCG_REG_BASE + 0x018) #define TIMER9_REG_BASE 0xE8A00000 #define WDT0_REG_BASE 0xE8A06000 #define WDT1_REG_BASE 0xE8A07000 #define WDT_CONTROL_OFFSET 0x008 #define WDT_LOCK_OFFSET 0xC00 #define WDT_UNLOCK 0x1ACCE551 #define WDT_LOCKED 1 #define PCTRL_REG_BASE 0xE8A09000 #define PCTRL_PERI_CTRL3_REG (PCTRL_REG_BASE + 0x010) #define PCTRL_PERI_CTRL24_REG (PCTRL_REG_BASE + 0x064) #define GPIO0_BASE UL(0xE8A0B000) #define GPIO1_BASE UL(0xE8A0C000) #define GPIO2_BASE UL(0xE8A0D000) #define GPIO3_BASE UL(0xE8A0E000) #define GPIO4_BASE UL(0xE8A0F000) #define GPIO5_BASE UL(0xE8A10000) #define GPIO6_BASE UL(0xE8A11000) #define GPIO7_BASE UL(0xE8A12000) #define GPIO8_BASE UL(0xE8A13000) #define GPIO9_BASE UL(0xE8A14000) #define GPIO10_BASE UL(0xE8A15000) #define GPIO11_BASE UL(0xE8A16000) #define GPIO12_BASE UL(0xE8A17000) #define GPIO13_BASE UL(0xE8A18000) #define GPIO14_BASE UL(0xE8A19000) #define GPIO15_BASE UL(0xE8A1A000) #define GPIO16_BASE UL(0xE8A1B000) #define GPIO17_BASE UL(0xE8A1C000) #define GPIO20_BASE UL(0xE8A1F000) #define GPIO21_BASE UL(0xE8A20000) #define TZC_REG_BASE 0xE8A21000 #define TZC_STAT0_REG (TZC_REG_BASE + 0x800) #define TZC_EN0_REG (TZC_REG_BASE + 0x804) #define TZC_DIS0_REG (TZC_REG_BASE + 0x808) #define TZC_STAT1_REG (TZC_REG_BASE + 0x80C) #define TZC_EN1_REG (TZC_REG_BASE + 0x810) #define TZC_DIS1_REG (TZC_REG_BASE + 0x814) #define TZC_STAT2_REG (TZC_REG_BASE + 0x818) #define TZC_EN2_REG (TZC_REG_BASE + 0x81C) #define TZC_DIS2_REG (TZC_REG_BASE + 0x820) #define TZC_STAT3_REG (TZC_REG_BASE + 0x824) #define TZC_EN3_REG (TZC_REG_BASE + 0x828) #define TZC_DIS3_REG (TZC_REG_BASE + 0x82C) #define TZC_STAT4_REG (TZC_REG_BASE + 0x830) #define TZC_EN4_REG (TZC_REG_BASE + 0x834) #define TZC_DIS4_REG (TZC_REG_BASE + 0x838) #define TZC_STAT5_REG (TZC_REG_BASE + 0x83C) #define TZC_EN5_REG (TZC_REG_BASE + 0x840) #define TZC_DIS5_REG (TZC_REG_BASE + 0x844) #define TZC_STAT6_REG (TZC_REG_BASE + 0x848) #define TZC_EN6_REG (TZC_REG_BASE + 0x84C) #define TZC_DIS6_REG (TZC_REG_BASE + 0x850) #define TZC_STAT7_REG (TZC_REG_BASE + 0x854) #define TZC_EN7_REG (TZC_REG_BASE + 0x858) #define TZC_DIS7_REG (TZC_REG_BASE + 0x85C) #define TZC_STAT8_REG (TZC_REG_BASE + 0x860) #define TZC_EN8_REG (TZC_REG_BASE + 0x864) #define TZC_DIS8_REG (TZC_REG_BASE + 0x868) #define MMBUF_BASE 0xEA800000 #define ACPU_DMCPACK0_BASE 0xEA900000 #define ACPU_DMCPACK1_BASE 0xEA920000 #define ACPU_DMCPACK2_BASE 0xEA940000 #define ACPU_DMCPACK3_BASE 0xEA960000 #define UART5_REG_BASE 0xFDF05000 #define USB3OTG_REG_BASE 0xFF100000 #define UFS_REG_BASE 0xFF3B0000 #define UFS_SYS_REG_BASE 0xFF3B1000 #define UFS_SYS_PSW_POWER_CTRL_REG (UFS_SYS_REG_BASE + 0x004) #define UFS_SYS_PHY_ISO_EN_REG (UFS_SYS_REG_BASE + 0x008) #define UFS_SYS_HC_LP_CTRL_REG (UFS_SYS_REG_BASE + 0x00C) #define UFS_SYS_PHY_CLK_CTRL_REG (UFS_SYS_REG_BASE + 0x010) #define UFS_SYS_PSW_CLK_CTRL_REG (UFS_SYS_REG_BASE + 0x014) #define UFS_SYS_CLOCK_GATE_BYPASS_REG (UFS_SYS_REG_BASE + 0x018) #define UFS_SYS_RESET_CTRL_EN_REG (UFS_SYS_REG_BASE + 0x01C) #define UFS_SYS_MONITOR_HH_REG (UFS_SYS_REG_BASE + 0x03C) #define UFS_SYS_UFS_SYSCTRL_REG (UFS_SYS_REG_BASE + 0x05C) #define UFS_SYS_UFS_DEVICE_RESET_CTRL_REG (UFS_SYS_REG_BASE + 0x060) #define UFS_SYS_UFS_APB_ADDR_MASK_REG (UFS_SYS_REG_BASE + 0x064) #define BIT_UFS_PSW_ISO_CTRL (1 << 16) #define BIT_UFS_PSW_MTCMOS_EN (1 << 0) #define BIT_UFS_REFCLK_ISO_EN (1 << 16) #define BIT_UFS_PHY_ISO_CTRL (1 << 0) #define BIT_SYSCTRL_LP_ISOL_EN (1 << 16) #define BIT_SYSCTRL_PWR_READY (1 << 8) #define BIT_SYSCTRL_REF_CLOCK_EN (1 << 24) #define MASK_SYSCTRL_REF_CLOCK_SEL (3 << 8) #define MASK_SYSCTRL_CFG_CLOCK_FREQ (0xFF) #define BIT_SYSCTRL_PSW_CLK_EN (1 << 4) #define MASK_UFS_CLK_GATE_BYPASS (0x3F) #define BIT_SYSCTRL_LP_RESET_N (1 << 0) #define BIT_UFS_REFCLK_SRC_SE1 (1 << 0) #define MASK_UFS_SYSCTRL_BYPASS (0x3F << 16) #define MASK_UFS_DEVICE_RESET (1 << 16) #define BIT_UFS_DEVICE_RESET (1 << 0) #define GPIO18_BASE UL(0xFF3B4000) #define GPIO19_BASE UL(0xFF3B5000) #define IOMG_FIX_REG_BASE 0xFF3B6000 /* GPIO150: LED */ #define IOMG_FIX_006_REG (IOMG_FIX_REG_BASE + 0x018) /* GPIO151: LED */ #define IOMG_FIX_007_REG (IOMG_FIX_REG_BASE + 0x01C) #define IOMG_AO_REG_BASE 0xFFF11000 /* GPIO189: LED */ #define IOMG_AO_011_REG (IOMG_AO_REG_BASE + 0x02C) /* GPIO190: LED */ #define IOMG_AO_012_REG (IOMG_AO_REG_BASE + 0x030) /* GPIO202: type C enable. active low */ #define IOMG_AO_023_REG (IOMG_AO_REG_BASE + 0x05C) /* GPIO206: USB switch. active low */ #define IOMG_AO_026_REG (IOMG_AO_REG_BASE + 0x068) /* GPIO219: PD interrupt. pull up */ #define IOMG_AO_039_REG (IOMG_AO_REG_BASE + 0x09C) /* GPIO213: PCIE_CLKREQ_N */ #define IOMG_AO_033_REG (IOMG_AO_REG_BASE + 0x084) #define IOCG_AO_REG_BASE 0xFFF1187C /* GPIO219: PD interrupt. pull up */ #define IOCG_AO_043_REG (IOCG_AO_REG_BASE + 0x030) #define EDMAC_BASE 0xfdf30000 #define EDMAC_SEC_CTRL (EDMAC_BASE + 0x694) #define EDMAC_AXI_CONF(x) (EDMAC_BASE + 0x820 + (x << 6)) #define EDMAC_SEC_CTRL_INTR_SEC (1 << 1) #define EDMAC_SEC_CTRL_GLOBAL_SEC (1 << 0) #define EDMAC_CHANNEL_NUMS 16 #define IOMCU_DMAC_BASE 0xffd77000 #define IOMCU_DMAC_SEC_CTRL (IOMCU_DMAC_BASE + 0x694) #define IOMCU_DMAC_AXI_CONF(x) (IOMCU_DMAC_BASE + 0x820 + ((x) << 6)) #define IOMCU_DMAC_AXI_CONF_ARPROT_NS (1 << 6) #define IOMCU_DMAC_AXI_CONF_AWPROT_NS (1 << 18) #define IOMCU_DMAC_SEC_CTRL_INTR_SEC (1 << 1) #define IOMCU_DMAC_SEC_CTRL_GLOBAL_SEC (1 << 0) #define IOMCU_DMAC_CHANNEL_NUMS 8 #endif /* HI3660_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey960/include/hi3660_crg.h000066400000000000000000000145501355360272700247550ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HI3660_CRG_H #define HI3660_CRG_H #define CRG_REG_BASE 0xFFF35000 #define CRG_PEREN0_REG (CRG_REG_BASE + 0x000) #define CRG_PERDIS0_REG (CRG_REG_BASE + 0x004) #define CRG_PERSTAT0_REG (CRG_REG_BASE + 0x008) #define PEREN0_GT_CLK_AOMM (1U << 31) #define CRG_PEREN1_REG (CRG_REG_BASE + 0x010) #define CRG_PERDIS1_REG (CRG_REG_BASE + 0x014) #define CRG_PERSTAT1_REG (CRG_REG_BASE + 0x018) #define CRG_PEREN2_REG (CRG_REG_BASE + 0x020) #define CRG_PERDIS2_REG (CRG_REG_BASE + 0x024) #define CRG_PERSTAT2_REG (CRG_REG_BASE + 0x028) #define PEREN2_HKADCSSI (1 << 24) #define CRG_PEREN3_REG (CRG_REG_BASE + 0x030) #define CRG_PERDIS3_REG (CRG_REG_BASE + 0x034) #define CRG_PEREN4_REG (CRG_REG_BASE + 0x040) #define CRG_PERDIS4_REG (CRG_REG_BASE + 0x044) #define CRG_PERCLKEN4_REG (CRG_REG_BASE + 0x048) #define CRG_PERSTAT4_REG (CRG_REG_BASE + 0x04C) #define GT_ACLK_USB3OTG (1 << 1) #define GT_CLK_USB3OTG_REF (1 << 0) #define CRG_PEREN5_REG (CRG_REG_BASE + 0x050) #define CRG_PERDIS5_REG (CRG_REG_BASE + 0x054) #define CRG_PERSTAT5_REG (CRG_REG_BASE + 0x058) #define CRG_PERRSTEN0_REG (CRG_REG_BASE + 0x060) #define CRG_PERRSTDIS0_REG (CRG_REG_BASE + 0x064) #define CRG_PERRSTSTAT0_REG (CRG_REG_BASE + 0x068) #define CRG_PERRSTEN1_REG (CRG_REG_BASE + 0x06C) #define CRG_PERRSTDIS1_REG (CRG_REG_BASE + 0x070) #define CRG_PERRSTSTAT1_REG (CRG_REG_BASE + 0x074) #define CRG_PERRSTEN2_REG (CRG_REG_BASE + 0x078) #define CRG_PERRSTDIS2_REG (CRG_REG_BASE + 0x07C) #define CRG_PERRSTSTAT2_REG (CRG_REG_BASE + 0x080) #define PERRSTEN2_HKADCSSI (1 << 24) #define CRG_PERRSTEN3_REG (CRG_REG_BASE + 0x084) #define CRG_PERRSTDIS3_REG (CRG_REG_BASE + 0x088) #define CRG_PERRSTSTAT3_REG (CRG_REG_BASE + 0x08C) #define CRG_PERRSTEN4_REG (CRG_REG_BASE + 0x090) #define CRG_PERRSTDIS4_REG (CRG_REG_BASE + 0x094) #define CRG_PERRSTSTAT4_REG (CRG_REG_BASE + 0x098) #define IP_RST_USB3OTG_MUX (1 << 8) #define IP_RST_USB3OTG_AHBIF (1 << 7) #define IP_RST_USB3OTG_32K (1 << 6) #define IP_RST_USB3OTG (1 << 5) #define IP_RST_USB3OTGPHY_POR (1 << 3) #define CRG_PERRSTEN5_REG (CRG_REG_BASE + 0x09C) #define CRG_PERRSTDIS5_REG (CRG_REG_BASE + 0x0A0) #define CRG_PERRSTSTAT5_REG (CRG_REG_BASE + 0x0A4) /* bit fields in CRG_PERI */ #define PERI_PCLK_PCTRL_BIT (1U << 31) #define PERI_TIMER12_BIT (1 << 25) #define PERI_TIMER11_BIT (1 << 24) #define PERI_TIMER10_BIT (1 << 23) #define PERI_TIMER9_BIT (1 << 22) #define PERI_UART5_BIT (1 << 15) #define PERI_UFS_BIT (1 << 12) #define PERI_ARST_UFS_BIT (1 << 7) #define PERI_PPLL2_EN_CPU (1 << 3) #define PERI_PWM_BIT (1 << 0) #define PERI_DDRC_BIT (1 << 0) #define PERI_DDRC_D_BIT (1 << 4) #define PERI_DDRC_C_BIT (1 << 3) #define PERI_DDRC_B_BIT (1 << 2) #define PERI_DDRC_A_BIT (1 << 1) #define PERI_DDRC_DMUX_BIT (1 << 0) #define CRG_CLKDIV0_REG (CRG_REG_BASE + 0x0A0) #define SC_DIV_LPMCU_MASK ((0x1F << 5) << 16) #define SC_DIV_LPMCU(x) (((x) & 0x1F) << 5) #define CRG_CLKDIV1_REG (CRG_REG_BASE + 0x0B0) #define SEL_LPMCU_PLL_MASK ((1 << 1) << 16) #define SEL_SYSBUS_MASK ((1 << 0) << 16) #define SEL_LPMCU_PLL1 (1 << 1) #define SEL_LPMCU_PLL0 (0 << 1) #define SEL_SYSBUS_PLL0 (1 << 0) #define SEL_SYSBUS_PLL1 (0 << 0) #define CRG_CLKDIV3_REG (CRG_REG_BASE + 0x0B4) #define CRG_CLKDIV5_REG (CRG_REG_BASE + 0x0BC) #define CRG_CLKDIV8_REG (CRG_REG_BASE + 0x0C8) #define CRG_CLKDIV12_REG (CRG_REG_BASE + 0x0D8) #define SC_DIV_A53HPM_MASK (0x7 << 13) #define SC_DIV_A53HPM(x) (((x) & 0x7) << 13) #define CRG_CLKDIV16_REG (CRG_REG_BASE + 0x0E8) #define DDRC_CLK_SW_REQ_CFG_MASK (0x3 << 12) #define DDRC_CLK_SW_REQ_CFG(x) (((x) & 0x3) << 12) #define SC_DIV_UFSPHY_CFG_MASK (0x3 << 9) #define SC_DIV_UFSPHY_CFG(x) (((x) & 0x3) << 9) #define DDRCPLL_SW (1 << 8) #define CRG_CLKDIV17_REG (CRG_REG_BASE + 0x0EC) #define SC_DIV_UFS_PERIBUS (1 << 14) #define CRG_CLKDIV18_REG (CRG_REG_BASE + 0x0F0) #define CRG_CLKDIV19_REG (CRG_REG_BASE + 0x0F4) #define CRG_CLKDIV20_REG (CRG_REG_BASE + 0x0F8) #define CLKDIV20_GT_CLK_AOMM (1 << 3) #define CRG_CLKDIV22_REG (CRG_REG_BASE + 0x100) #define SEL_PLL_320M_MASK (1 << 16) #define SEL_PLL2_320M (1 << 0) #define SEL_PLL0_320M (0 << 0) #define CRG_CLKDIV23_REG (CRG_REG_BASE + 0x104) #define PERI_DDRC_SW_BIT (1 << 13) #define DIV_CLK_DDRSYS_MASK (0x3 << 10) #define DIV_CLK_DDRSYS(x) (((x) & 0x3) << 10) #define GET_DIV_CLK_DDRSYS(x) (((x) & DIV_CLK_DDRSYS_MASK) >> 10) #define DIV_CLK_DDRCFG_MASK (0x6 << 5) #define DIV_CLK_DDRCFG(x) (((x) & 0x6) << 5) #define GET_DIV_CLK_DDRCFG(x) (((x) & DIV_CLK_DDRCFG_MASK) >> 5) #define DIV_CLK_DDRC_MASK 0x1F #define DIV_CLK_DDRC(x) ((x) & DIV_CLK_DDRC_MASK) #define GET_DIV_CLK_DDRC(x) ((x) & DIV_CLK_DDRC_MASK) #define CRG_CLKDIV25_REG (CRG_REG_BASE + 0x10C) #define DIV_SYSBUS_PLL_MASK (0xF << 16) #define DIV_SYSBUS_PLL(x) ((x) & 0xF) #define CRG_PERI_CTRL2_REG (CRG_REG_BASE + 0x128) #define PERI_TIME_STAMP_CLK_MASK (0x7 << 28) #define PERI_TIME_STAMP_CLK_DIV(x) (((x) & 0x7) << 22) #define CRG_ISODIS_REG (CRG_REG_BASE + 0x148) #define CRG_PERPWREN_REG (CRG_REG_BASE + 0x150) #define CRG_PEREN7_REG (CRG_REG_BASE + 0x420) #define CRG_PERDIS7_REG (CRG_REG_BASE + 0x424) #define CRG_PERSTAT7_REG (CRG_REG_BASE + 0x428) #define GT_CLK_UFSPHY_CFG (1 << 14) #define CRG_PEREN8_REG (CRG_REG_BASE + 0x430) #define CRG_PERDIS8_REG (CRG_REG_BASE + 0x434) #define CRG_PERSTAT8_REG (CRG_REG_BASE + 0x438) #define PERI_DMC_D_BIT (1 << 22) #define PERI_DMC_C_BIT (1 << 21) #define PERI_DMC_B_BIT (1 << 20) #define PERI_DMC_A_BIT (1 << 19) #define PERI_DMC_BIT (1 << 18) #define CRG_PEREN11_REG (CRG_REG_BASE + 0x460) #define PPLL1_GATE_CPU (1 << 18) #define CRG_PERSTAT11_REG (CRG_REG_BASE + 0x46C) #define PPLL3_EN_STAT (1 << 21) #define PPLL2_EN_STAT (1 << 20) #define PPLL1_EN_STAT (1 << 19) #define CRG_IVP_SEC_RSTDIS_REG (CRG_REG_BASE + 0xC04) #define CRG_ISP_SEC_RSTDIS_REG (CRG_REG_BASE + 0xC84) #define CRG_RVBAR(c, n) (0xE00 + (0x10 * c) + (0x4 * n)) #define CRG_GENERAL_SEC_RSTEN_REG (CRG_REG_BASE + 0xE20) #define CRG_GENERAL_SEC_RSTDIS_REG (CRG_REG_BASE + 0xE24) #define IP_RST_GPIO0_SEC (1 << 2) #define CRG_GENERAL_SEC_CLKDIV0_REG (CRG_REG_BASE + 0xE90) #define SC_DIV_AO_HISE_MASK 3 #define SC_DIV_AO_HISE(x) ((x) & 0x3) #endif /* HI3660_CRG_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey960/include/hi3660_hkadc.h000066400000000000000000000041141355360272700252470ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HI3660_HKADC_H #define HI3660_HKADC_H #define HKADC_SSI_REG_BASE 0xE82B8000 #define HKADC_DSP_START_REG (HKADC_SSI_REG_BASE + 0x000) #define HKADC_WR_NUM_REG (HKADC_SSI_REG_BASE + 0x008) #define HKADC_DSP_START_CLR_REG (HKADC_SSI_REG_BASE + 0x01C) #define HKADC_WR01_DATA_REG (HKADC_SSI_REG_BASE + 0x020) #define WR1_WRITE_MODE (1U << 31) #define WR1_READ_MODE (0 << 31) #define WR1_ADDR(x) (((x) & 0x7F) << 24) #define WR1_DATA(x) (((x) & 0xFF) << 16) #define WR0_WRITE_MODE (1 << 15) #define WR0_READ_MODE (0 << 15) #define WR0_ADDR(x) (((x) & 0x7F) << 8) #define WR0_DATA(x) ((x) & 0xFF) #define HKADC_WR23_DATA_REG (HKADC_SSI_REG_BASE + 0x024) #define HKADC_WR45_DATA_REG (HKADC_SSI_REG_BASE + 0x028) #define HKADC_DELAY01_REG (HKADC_SSI_REG_BASE + 0x030) #define HKADC_DELAY23_REG (HKADC_SSI_REG_BASE + 0x034) #define HKADC_DELAY45_REG (HKADC_SSI_REG_BASE + 0x038) #define HKADC_DSP_RD2_DATA_REG (HKADC_SSI_REG_BASE + 0x048) #define HKADC_DSP_RD3_DATA_REG (HKADC_SSI_REG_BASE + 0x04C) /* HKADC Internal Registers */ #define HKADC_CTRL_ADDR 0x00 #define HKADC_START_ADDR 0x01 #define HKADC_DATA1_ADDR 0x03 /* high 8 bits */ #define HKADC_DATA0_ADDR 0x04 /* low 8 bits */ #define HKADC_MODE_CFG 0x0A #define HKADC_VALUE_HIGH 0x0FF0 #define HKADC_VALUE_LOW 0x000F #define HKADC_VALID_VALUE 0x0FFF #define HKADC_CHANNEL_MAX 15 #define HKADC_VREF_1V8 1800 #define HKADC_ACCURACY 0x0FFF #define HKADC_WR01_VALUE ((HKADC_START_ADDR << 24) | \ (0x1 << 16)) #define HKADC_WR23_VALUE ((0x1u << 31) | \ (HKADC_DATA0_ADDR << 24) | \ (1 << 15) | \ (HKADC_DATA1_ADDR << 8)) #define HKADC_WR45_VALUE (0x80) #define HKADC_CHANNEL0_DELAY01_VALUE ((0x0700 << 16) | 0xFFFF) #define HKADC_DELAY01_VALUE ((0x0700 << 16) | 0x0200) #define HKADC_DELAY23_VALUE ((0x00C8 << 16) | 0x00C8) #define START_DELAY_TIMEOUT 2000 #define HKADC_WR_NUM_VALUE 4 #endif /* HI3660_HKADC_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey960/include/hi3660_mem_map.h000066400000000000000000000007621355360272700256150ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HI3660_MEM_MAP_H #define HI3660_MEM_MAP_H #define HISI_DATA_HEAD_BASE (0x89C44400) #define HISI_RESERVED_MEM_BASE (0x89C80000) #define HISI_RESERVED_MEM_SIZE (0x00040000) #define HISI_DATA0_BASE (0x89C96180) #define HISI_DATA0_SIZE (0x000003A0) #define HISI_DATA1_BASE (0x89C93480) #define HISI_DATA1_SIZE (0x00002D00) #endif /* HI3660_MEM_MAP_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey960/include/hisi_ipc.h000066400000000000000000000011461355360272700247670ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HISI_IPC_H #define HISI_IPC_H enum pm_mode { PM_ON = 0, PM_OFF, }; void hisi_ipc_pm_on_off(unsigned int core, unsigned int cluster, enum pm_mode mode); void hisi_ipc_pm_suspend(unsigned int core, unsigned int cluster, unsigned int affinity_level); void hisi_ipc_psci_system_off(unsigned int core, unsigned int cluster); void hisi_ipc_psci_system_reset(unsigned int core, unsigned int cluster, unsigned int cmd_id); int hisi_ipc_init(void); #endif /* HISI_IPC_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey960/include/plat_macros.S000066400000000000000000000037431355360272700254640ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S #include #include #include #include .section .rodata.gic_reg_name, "aS" gicc_regs: .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", "" gicd_pend_reg: .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n" newline: .asciz "\n" spacer: .asciz ":\t\t0x" .section .rodata.cci_reg_name, "aS" cci_iface_regs: .asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , "" /* --------------------------------------------- * The below macro prints out relevant GIC * registers whenever an unhandled exception is * taken in BL31. * --------------------------------------------- */ .macro plat_crash_print_regs mov_imm x16, GICD_REG_BASE mov_imm x17, GICC_REG_BASE /* Load the gicc reg list to x6 */ adr x6, gicc_regs /* Load the gicc regs to gp regs used by str_in_crash_buf_print */ ldr w8, [x17, #GICC_HPPIR] ldr w9, [x17, #GICC_AHPPIR] ldr w10, [x17, #GICC_CTLR] /* Store to the crash buf and print to cosole */ bl str_in_crash_buf_print /* Print the GICD_ISPENDR regs */ add x7, x16, #GICD_ISPENDR adr x4, gicd_pend_reg bl asm_print_str 2: sub x4, x7, x16 cmp x4, #0x280 b.eq 1f bl asm_print_hex adr x4, spacer bl asm_print_str ldr x4, [x7], #8 bl asm_print_hex adr x4, newline bl asm_print_str b 2b 1: adr x6, cci_iface_regs /* Store in x7 the base address of the first interface */ mov_imm x7, (CCI400_REG_BASE + SLAVE_IFACE_OFFSET( \ CCI400_SL_IFACE3_CLUSTER_IX)) ldr w8, [x7, #SNOOP_CTRL_REG] /* Store in x7 the base address of the second interface */ mov_imm x7, (CCI400_REG_BASE + SLAVE_IFACE_OFFSET( \ CCI400_SL_IFACE4_CLUSTER_IX)) ldr w9, [x7, #SNOOP_CTRL_REG] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/hisilicon/hikey960/include/platform_def.h000066400000000000000000000076231355360272700256500ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include "../hikey960_def.h" /* Special value used to verify platform parameters from BL2 to BL3-1 */ #define HIKEY960_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL /* * Generic platform constants */ /* Size of cacheable stacks */ #define PLATFORM_STACK_SIZE 0x1000 #define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n" #define PLATFORM_CACHE_LINE_SIZE 64 #define PLATFORM_CLUSTER_COUNT 2 #define PLATFORM_CORE_COUNT_PER_CLUSTER 4 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \ PLATFORM_CORE_COUNT_PER_CLUSTER) #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2 #define PLAT_NUM_PWR_DOMAINS (PLATFORM_CORE_COUNT + \ PLATFORM_CLUSTER_COUNT + 1) #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE U(2) #define MAX_IO_DEVICES 3 #define MAX_IO_HANDLES 4 /* UFS RPMB and UFS User Data */ #define MAX_IO_BLOCK_DEVICES U(2) /* * Platform memory map related constants */ /* * BL1 specific defines. */ #define BL1_RO_BASE (0x1AC00000) #define BL1_RO_LIMIT (BL1_RO_BASE + 0x20000) #define BL1_RW_BASE (BL1_RO_LIMIT) /* 1AC2_0000 */ #define BL1_RW_SIZE (0x00188000) #define BL1_RW_LIMIT (0x1B000000) /* * BL2 specific defines. */ #define BL2_BASE (0x1AC00000) #define BL2_LIMIT (BL2_BASE + 0x58000) /* 1AC5_8000 */ /* * BL31 specific defines. */ #define BL31_BASE (BL2_LIMIT) /* 1AC5_8000 */ #define BL31_LIMIT (BL31_BASE + 0x40000) /* 1AC9_8000 */ /* * BL3-2 specific defines. */ /* * The TSP currently executes from TZC secured area of DRAM. */ #define BL32_DRAM_BASE DDR_SEC_BASE #define BL32_DRAM_LIMIT (DDR_SEC_BASE+DDR_SEC_SIZE) #ifdef SPD_opteed /* Load pageable part of OP-TEE at end of allocated DRAM space for BL32 */ #define HIKEY960_OPTEE_PAGEABLE_LOAD_BASE (BL32_DRAM_LIMIT - HIKEY960_OPTEE_PAGEABLE_LOAD_SIZE) /* 0x3FC0_0000 */ #define HIKEY960_OPTEE_PAGEABLE_LOAD_SIZE 0x400000 /* 4MB */ #endif #if (HIKEY960_TSP_RAM_LOCATION_ID == HIKEY960_DRAM_ID) #define TSP_SEC_MEM_BASE BL32_DRAM_BASE #define TSP_SEC_MEM_SIZE (BL32_DRAM_LIMIT - BL32_DRAM_BASE) #define BL32_BASE BL32_DRAM_BASE #define BL32_LIMIT BL32_DRAM_LIMIT #elif (HIKEY960_TSP_RAM_LOCATION_ID == HIKEY960_SRAM_ID) #error "SRAM storage of TSP payload is currently unsupported" #else #error "Currently unsupported HIKEY960_TSP_LOCATION_ID value" #endif /* BL32 is mandatory in AArch32 */ #ifdef __aarch64__ #ifdef SPD_none #undef BL32_BASE #endif /* SPD_none */ #endif #define NS_BL1U_BASE (BL31_LIMIT) /* 1AC9_8000 */ #define NS_BL1U_SIZE (0x00100000) #define NS_BL1U_LIMIT (NS_BL1U_BASE + NS_BL1U_SIZE) #define HIKEY960_NS_IMAGE_OFFSET (0x1AC28000) /* offset in l-loader */ #define HIKEY960_NS_TMP_OFFSET (0x1AE00000) #define SCP_BL2_BASE (0x89C80000) #define SCP_BL2_SIZE (0x00040000) /* * Platform specific page table and MMU setup constants */ #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #if defined(IMAGE_BL1) || defined(IMAGE_BL31) || defined(IMAGE_BL32) #define MAX_XLAT_TABLES 3 #endif #ifdef IMAGE_BL2 #define MAX_XLAT_TABLES 4 #endif #define MAX_MMAP_REGIONS 16 /* * Declarations and constants to access the mailboxes safely. Each mailbox is * aligned on the biggest cache line size in the platform. This is known only * to the platform as it might have a combination of integrated and external * caches. Such alignment ensures that two maiboxes do not sit on the same cache * line at any cache level. They could belong to different cpus/clusters & * get written while being protected by different locks causing corruption of * a valid mailbox address. */ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/hisilicon/hikey960/platform.mk000066400000000000000000000115761355360272700235710ustar00rootroot00000000000000# # Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Non-TF Boot ROM BL2_AT_EL3 := 1 # On Hikey960, the TSP can execute from TZC secure area in DRAM. HIKEY960_TSP_RAM_LOCATION ?= dram ifeq (${HIKEY960_TSP_RAM_LOCATION}, dram) HIKEY960_TSP_RAM_LOCATION_ID = HIKEY960_DRAM_ID else ifeq (${HIKEY960_TSP_RAM_LOCATION}, sram) HIKEY960_TSP_RAM_LOCATION_ID = HIKEY960_SRAM_ID else $(error "Currently unsupported HIKEY960_TSP_RAM_LOCATION value") endif CRASH_CONSOLE_BASE := PL011_UART6_BASE COLD_BOOT_SINGLE_CPU := 1 PLAT_PL061_MAX_GPIOS := 176 PROGRAMMABLE_RESET_ADDRESS := 1 ENABLE_SVE_FOR_NS := 0 PLAT_PARTITION_BLOCK_SIZE := 4096 # Process flags $(eval $(call add_define,HIKEY960_TSP_RAM_LOCATION_ID)) $(eval $(call add_define,CRASH_CONSOLE_BASE)) $(eval $(call add_define,PLAT_PL061_MAX_GPIOS)) $(eval $(call add_define,PLAT_PARTITION_BLOCK_SIZE)) # Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images # in the FIP if the platform requires. ifneq ($(BL32_EXTRA1),) $(eval $(call TOOL_ADD_IMG,bl32_extra1,--tos-fw-extra1)) endif ifneq ($(BL32_EXTRA2),) $(eval $(call TOOL_ADD_IMG,bl32_extra2,--tos-fw-extra2)) endif USE_COHERENT_MEM := 1 PLAT_INCLUDES := -Iplat/hisilicon/hikey960/include PLAT_BL_COMMON_SOURCES := drivers/arm/pl011/aarch64/pl011_console.S \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ lib/xlat_tables/aarch64/xlat_tables.c \ lib/xlat_tables/xlat_tables_common.c \ plat/hisilicon/hikey960/aarch64/hikey960_common.c \ plat/hisilicon/hikey960/hikey960_boardid.c HIKEY960_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c BL1_SOURCES += bl1/tbbr/tbbr_img_desc.c \ drivers/arm/pl061/pl061_gpio.c \ drivers/gpio/gpio.c \ drivers/io/io_block.c \ drivers/io/io_fip.c \ drivers/io/io_storage.c \ drivers/synopsys/ufs/dw_ufs.c \ drivers/ufs/ufs.c \ lib/cpus/aarch64/cortex_a53.S \ plat/hisilicon/hikey960/aarch64/hikey960_helpers.S \ plat/hisilicon/hikey960/hikey960_bl1_setup.c \ plat/hisilicon/hikey960/hikey960_bl_common.c \ plat/hisilicon/hikey960/hikey960_io_storage.c \ ${HIKEY960_GIC_SOURCES} BL2_SOURCES += common/desc_image_load.c \ drivers/arm/pl061/pl061_gpio.c \ drivers/gpio/gpio.c \ drivers/io/io_block.c \ drivers/io/io_fip.c \ drivers/io/io_storage.c \ drivers/partition/gpt.c \ drivers/partition/partition.c \ drivers/synopsys/ufs/dw_ufs.c \ drivers/ufs/ufs.c \ lib/cpus/aarch64/cortex_a53.S \ plat/hisilicon/hikey960/aarch64/hikey960_helpers.S \ plat/hisilicon/hikey960/hikey960_bl2_mem_params_desc.c \ plat/hisilicon/hikey960/hikey960_bl2_setup.c \ plat/hisilicon/hikey960/hikey960_bl_common.c \ plat/hisilicon/hikey960/hikey960_image_load.c \ plat/hisilicon/hikey960/hikey960_io_storage.c \ plat/hisilicon/hikey960/hikey960_mcu_load.c ifeq (${SPD},opteed) BL2_SOURCES += lib/optee/optee_utils.c endif BL31_SOURCES += drivers/arm/cci/cci.c \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a72.S \ lib/cpus/aarch64/cortex_a73.S \ plat/common/plat_psci_common.c \ plat/hisilicon/hikey960/aarch64/hikey960_helpers.S \ plat/hisilicon/hikey960/hikey960_bl31_setup.c \ plat/hisilicon/hikey960/hikey960_pm.c \ plat/hisilicon/hikey960/hikey960_topology.c \ plat/hisilicon/hikey960/drivers/pwrc/hisi_pwrc.c \ plat/hisilicon/hikey960/drivers/ipc/hisi_ipc.c \ ${HIKEY960_GIC_SOURCES} ifneq (${TRUSTED_BOARD_BOOT},0) include drivers/auth/mbedtls/mbedtls_crypto.mk include drivers/auth/mbedtls/mbedtls_x509.mk AUTH_SOURCES := drivers/auth/auth_mod.c \ drivers/auth/crypto_mod.c \ drivers/auth/img_parser_mod.c \ drivers/auth/tbbr/tbbr_cot.c BL1_SOURCES += ${AUTH_SOURCES} \ plat/common/tbbr/plat_tbbr.c \ plat/hisilicon/hikey960/hikey960_tbbr.c \ plat/hisilicon/hikey960/hikey960_rotpk.S BL2_SOURCES += ${AUTH_SOURCES} \ plat/common/tbbr/plat_tbbr.c \ plat/hisilicon/hikey960/hikey960_tbbr.c \ plat/hisilicon/hikey960/hikey960_rotpk.S ROT_KEY = $(BUILD_PLAT)/rot_key.pem ROTPK_HASH = $(BUILD_PLAT)/rotpk_sha256.bin $(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"')) $(BUILD_PLAT)/bl1/hikey960_rotpk.o: $(ROTPK_HASH) $(BUILD_PLAT)/bl2/hikey960_rotpk.o: $(ROTPK_HASH) certificates: $(ROT_KEY) $(ROT_KEY): | $(BUILD_PLAT) @echo " OPENSSL $@" $(Q)openssl genrsa 2048 > $@ 2>/dev/null $(ROTPK_HASH): $(ROT_KEY) @echo " OPENSSL $@" $(Q)openssl rsa -in $< -pubout -outform DER 2>/dev/null |\ openssl dgst -sha256 -binary > $@ 2>/dev/null endif # Enable workarounds for selected Cortex-A53 errata. ERRATA_A53_836870 := 1 ERRATA_A53_843419 := 1 ERRATA_A53_855873 := 1 FIP_ALIGN := 512 trusted-firmware-a-2.2/plat/hisilicon/poplar/000077500000000000000000000000001355360272700213275ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/hisilicon/poplar/aarch64/000077500000000000000000000000001355360272700225575ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/hisilicon/poplar/aarch64/platform_common.c000066400000000000000000000036231355360272700261230ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "hi3798cv200.h" #include "platform_def.h" #define MAP_DDR MAP_REGION_FLAT(DDR_BASE, \ DDR_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define MAP_DEVICE MAP_REGION_FLAT(DEVICE_BASE, \ DEVICE_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_TSP_MEM MAP_REGION_FLAT(TSP_SEC_MEM_BASE, \ TSP_SEC_MEM_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #ifdef SPD_opteed #define MAP_OPTEE_PAGEABLE MAP_REGION_FLAT( \ POPLAR_OPTEE_PAGEABLE_LOAD_BASE, \ POPLAR_OPTEE_PAGEABLE_LOAD_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #endif static const mmap_region_t poplar_mmap[] = { MAP_DDR, MAP_DEVICE, MAP_TSP_MEM, #ifdef SPD_opteed MAP_OPTEE_PAGEABLE, #endif {0} }; #define DEFINE_CONFIGURE_MMU_EL(_el) \ void plat_configure_mmu_el##_el(unsigned long total_base, \ unsigned long total_size, \ unsigned long ro_start, \ unsigned long ro_limit, \ unsigned long coh_start, \ unsigned long coh_limit) \ { \ mmap_add_region(total_base, total_base, \ total_size, \ MT_MEMORY | MT_RW | MT_SECURE); \ mmap_add_region(ro_start, ro_start, \ ro_limit - ro_start, \ MT_MEMORY | MT_RO | MT_SECURE); \ mmap_add_region(coh_start, coh_start, \ coh_limit - coh_start, \ MT_DEVICE | MT_RW | MT_SECURE); \ mmap_add(poplar_mmap); \ init_xlat_tables(); \ \ enable_mmu_el##_el(0); \ } DEFINE_CONFIGURE_MMU_EL(3) DEFINE_CONFIGURE_MMU_EL(1) unsigned int plat_get_syscnt_freq2(void) { return SYS_COUNTER_FREQ_IN_TICKS; } trusted-firmware-a-2.2/plat/hisilicon/poplar/aarch64/poplar_helpers.S000066400000000000000000000052661355360272700257330ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .globl plat_my_core_pos .globl poplar_calc_core_pos .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush .globl platform_mem_init /* ----------------------------------------------------- * unsigned int plat_my_core_pos(void) * This function uses poplar_calc_core_pos() * definition to get the index of the calling CPU. * ----------------------------------------------------- */ func plat_my_core_pos mrs x0, mpidr_el1 b poplar_calc_core_pos endfunc plat_my_core_pos /* ----------------------------------------------------- * unsigned int poplar_calc_core_pos(u_register_t mpidr) * Helper function to calculate the core position. * With this function: CorePos = (ClusterId * 4) + * CoreId * ----------------------------------------------------- */ func poplar_calc_core_pos and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 ret endfunc poplar_calc_core_pos /* --------------------------------------------- * int plat_crash_console_init(void) * Function to initialize the crash console * without a C Runtime to print crash report. * Clobber list : x0 - x4 * --------------------------------------------- */ func plat_crash_console_init mov_imm x0, POPLAR_CRASH_UART_BASE mov_imm x1, POPLAR_CRASH_UART_CLK_IN_HZ mov_imm x2, POPLAR_CONSOLE_BAUDRATE b console_pl011_core_init endfunc plat_crash_console_init /* --------------------------------------------- * int plat_crash_console_putc(int c) * Function to print a character on the crash * console without a C Runtime. * Clobber list : x1, x2 * --------------------------------------------- */ func plat_crash_console_putc mov_imm x1, POPLAR_CRASH_UART_BASE b console_pl011_core_putc endfunc plat_crash_console_putc /* --------------------------------------------- * int plat_crash_console_flush() * Function to force a write of all buffered * data that hasn't been output. * Out : return -1 on error else return 0. * Clobber list : r0 * --------------------------------------------- */ func plat_crash_console_flush mov_imm x0, POPLAR_CRASH_UART_BASE b console_pl011_core_flush endfunc plat_crash_console_flush /* --------------------------------------------------------------------- * We don't need to carry out any memory initialization on ARM * platforms. The Secure RAM is accessible straight away. * --------------------------------------------------------------------- */ func platform_mem_init ret endfunc platform_mem_init trusted-firmware-a-2.2/plat/hisilicon/poplar/bl1_plat_setup.c000066400000000000000000000054721355360272700244210ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hi3798cv200.h" #include "plat_private.h" /* Data structure which holds the extents of the trusted RAM for BL1 */ static meminfo_t bl1_tzram_layout; static meminfo_t bl2_tzram_layout; static console_pl011_t console; /* * Cannot use default weak implementation in bl1_main.c because BL1 RW data is * not at the top of the secure memory. */ int bl1_plat_handle_post_image_load(unsigned int image_id) { image_desc_t *image_desc; entry_point_info_t *ep_info; if (image_id != BL2_IMAGE_ID) return 0; /* Get the image descriptor */ image_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID); assert(image_desc != NULL); /* Get the entry point info */ ep_info = &image_desc->ep_info; bl2_tzram_layout.total_base = BL2_BASE; bl2_tzram_layout.total_size = BL32_LIMIT - BL2_BASE; flush_dcache_range((uintptr_t)&bl2_tzram_layout, sizeof(meminfo_t)); ep_info->args.arg1 = (uintptr_t)&bl2_tzram_layout; VERBOSE("BL1: BL2 memory layout address = %p\n", (void *)&bl2_tzram_layout); return 0; } void bl1_early_platform_setup(void) { /* Initialize the console to provide early debug support */ console_pl011_register(PL011_UART0_BASE, PL011_UART0_CLK_IN_HZ, PL011_BAUDRATE, &console); /* Allow BL1 to see the whole Trusted RAM */ bl1_tzram_layout.total_base = BL1_RW_BASE; bl1_tzram_layout.total_size = BL1_RW_SIZE; INFO("BL1: 0x%lx - 0x%lx [size = %zu]\n", BL1_RAM_BASE, BL1_RAM_LIMIT, BL1_RAM_LIMIT - BL1_RAM_BASE); } void bl1_plat_arch_setup(void) { plat_configure_mmu_el3(bl1_tzram_layout.total_base, bl1_tzram_layout.total_size, BL1_RO_BASE, /* l-loader and BL1 ROM */ BL1_RO_LIMIT, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); } void bl1_platform_setup(void) { int i; #if !POPLAR_RECOVERY struct mmc_device_info info; dw_mmc_params_t params = EMMC_INIT_PARAMS(POPLAR_EMMC_DESC_BASE); #endif generic_delay_timer_init(); pl061_gpio_init(); for (i = 0; i < GPIO_MAX; i++) pl061_gpio_register(GPIO_BASE(i), i); #if !POPLAR_RECOVERY /* SoC-specific emmc register are initialized/configured by bootrom */ INFO("BL1: initializing emmc\n"); info.mmc_dev_type = MMC_IS_EMMC; dw_mmc_init(¶ms, &info); #endif plat_io_setup(); } unsigned int bl1_plat_get_next_image_id(void) { return BL2_IMAGE_ID; } trusted-firmware-a-2.2/plat/hisilicon/poplar/bl2_plat_mem_params_desc.c000066400000000000000000000120011355360272700263630ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /******************************************************************************* * Following descriptor provides BL image/ep information that gets used * by BL2 to load the images and also subset of this information is * passed to next BL image. The image loading sequence is managed by * populating the images in required loading order. The image execution * sequence is managed by populating the `next_handoff_image_id` with * the next executable image id. ******************************************************************************/ static bl_mem_params_node_t bl2_mem_params_descs[] = { #ifdef SCP_BL2_BASE /* Fill SCP_BL2 related information if it exists */ { .image_id = SCP_BL2_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE), SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, VERSION_2, image_info_t, 0), .image_info.image_base = SCP_BL2_BASE, .image_info.image_max_size = SCP_BL2_SIZE, .next_handoff_image_id = INVALID_IMAGE_ID, }, #endif /* SCP_BL2_BASE */ #ifdef EL3_PAYLOAD_BASE /* Fill EL3 payload related information (BL31 is EL3 payload)*/ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = EL3_PAYLOAD_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING), .next_handoff_image_id = INVALID_IMAGE_ID, }, #else /* EL3_PAYLOAD_BASE */ /* Fill BL31 related information */ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = BL31_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), #if DEBUG .ep_info.args.arg1 = POPLAR_BL31_PLAT_PARAM_VAL, #endif SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP), .image_info.image_base = BL31_BASE, .image_info.image_max_size = BL31_LIMIT - BL31_BASE, # ifdef BL32_BASE .next_handoff_image_id = BL32_IMAGE_ID, # else .next_handoff_image_id = BL33_IMAGE_ID, # endif }, # ifdef BL32_BASE /* Fill BL32 related information */ { .image_id = BL32_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE), .ep_info.pc = BL32_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = BL32_BASE, .image_info.image_max_size = BL32_LIMIT - BL32_BASE, .next_handoff_image_id = BL33_IMAGE_ID, }, /* * Fill BL32 external 1 related information. * A typical use for extra1 image is with OP-TEE where it is the pager image. */ { .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), .image_info.image_base = BL32_BASE, .image_info.image_max_size = BL32_LIMIT - BL32_BASE, .next_handoff_image_id = INVALID_IMAGE_ID, }, /* * Fill BL32 external 2 related information. * A typical use for extra2 image is with OP-TEE where it is the paged image. */ { .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), #ifdef SPD_opteed .image_info.image_base = POPLAR_OPTEE_PAGEABLE_LOAD_BASE, .image_info.image_max_size = POPLAR_OPTEE_PAGEABLE_LOAD_SIZE, #endif .next_handoff_image_id = INVALID_IMAGE_ID, }, # endif /* BL32_BASE */ /* Fill BL33 related information */ { .image_id = BL33_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), # ifdef PRELOADED_BL33_BASE .ep_info.pc = PRELOADED_BL33_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), # else .ep_info.pc = PLAT_POPLAR_NS_IMAGE_OFFSET, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = PLAT_POPLAR_NS_IMAGE_OFFSET, .image_info.image_max_size = DDR_BASE + DDR_SIZE - PLAT_POPLAR_NS_IMAGE_OFFSET, # endif /* PRELOADED_BL33_BASE */ .next_handoff_image_id = INVALID_IMAGE_ID, } #endif /* EL3_PAYLOAD_BASE */ }; REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) trusted-firmware-a-2.2/plat/hisilicon/poplar/bl2_plat_setup.c000066400000000000000000000133501355360272700244140ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hi3798cv200.h" #include "plat_private.h" static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE); static console_pl011_t console; /******************************************************************************* * Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol. * Return 0 on success, -1 otherwise. ******************************************************************************/ int plat_poplar_bl2_handle_scp_bl2(image_info_t *scp_bl2_image_info) { /* * This platform has no SCP_BL2 yet */ return 0; } /******************************************************************************* * Gets SPSR for BL32 entry ******************************************************************************/ uint32_t poplar_get_spsr_for_bl32_entry(void) { /* * The Secure Payload Dispatcher service is responsible for * setting the SPSR prior to entry into the BL3-2 image. */ return 0; } /******************************************************************************* * Gets SPSR for BL33 entry ******************************************************************************/ #ifdef __aarch64__ uint32_t poplar_get_spsr_for_bl33_entry(void) { unsigned long el_status; unsigned int mode; uint32_t spsr; /* Figure out what mode we enter the non-secure world in */ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; el_status &= ID_AA64PFR0_ELX_MASK; mode = (el_status) ? MODE_EL2 : MODE_EL1; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; } #else uint32_t poplar_get_spsr_for_bl33_entry(void) { unsigned int hyp_status, mode, spsr; hyp_status = GET_VIRT_EXT(read_id_pfr1()); mode = (hyp_status) ? MODE32_hyp : MODE32_svc; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_MODE32(mode, plat_get_ns_image_entrypoint() & 0x1, SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS); return spsr; } #endif /* __aarch64__ */ int poplar_bl2_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); #ifdef SPD_opteed bl_mem_params_node_t *pager_mem_params = NULL; bl_mem_params_node_t *paged_mem_params = NULL; #endif assert(bl_mem_params); switch (image_id) { #ifdef __aarch64__ case BL32_IMAGE_ID: #ifdef SPD_opteed 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); err = parse_optee_header(&bl_mem_params->ep_info, &pager_mem_params->image_info, &paged_mem_params->image_info); if (err != 0) { WARN("OPTEE header parse error.\n"); } /* * OP-TEE expect to receive DTB address in x2. * This will be copied into x2 by dispatcher. * Set this (arg3) if necessary */ /* bl_mem_params->ep_info.args.arg3 = PLAT_HIKEY_DT_BASE; */ #endif bl_mem_params->ep_info.spsr = poplar_get_spsr_for_bl32_entry(); break; #endif case BL33_IMAGE_ID: /* BL33 expects to receive the primary CPU MPID (through r0) */ bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr(); bl_mem_params->ep_info.spsr = poplar_get_spsr_for_bl33_entry(); break; #ifdef SCP_BL2_BASE case SCP_BL2_IMAGE_ID: /* The subsequent handling of SCP_BL2 is platform specific */ err = plat_poplar_bl2_handle_scp_bl2(&bl_mem_params->image_info); if (err) { WARN("Failure in platform-specific handling of SCP_BL2 image.\n"); } break; #endif default: /* Do nothing in default case */ break; } return err; } /******************************************************************************* * 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) { return poplar_bl2_handle_post_image_load(image_id); } void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { struct meminfo *mem_layout = (struct meminfo *)arg1; #if !POPLAR_RECOVERY struct mmc_device_info info; dw_mmc_params_t params = EMMC_INIT_PARAMS(POPLAR_EMMC_DESC_BASE); #endif console_pl011_register(PL011_UART0_BASE, PL011_UART0_CLK_IN_HZ, PL011_BAUDRATE, &console); /* Enable arch timer */ generic_delay_timer_init(); bl2_tzram_layout = *mem_layout; #if !POPLAR_RECOVERY /* SoC-specific emmc register are initialized/configured by bootrom */ INFO("BL2: initializing emmc\n"); info.mmc_dev_type = MMC_IS_EMMC; dw_mmc_init(¶ms, &info); #endif plat_io_setup(); } void bl2_plat_arch_setup(void) { plat_configure_mmu_el1(bl2_tzram_layout.total_base, bl2_tzram_layout.total_size, BL_CODE_BASE, BL_CODE_END, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); } void bl2_platform_setup(void) { } uintptr_t plat_get_ns_image_entrypoint(void) { #ifdef PRELOADED_BL33_BASE return PRELOADED_BL33_BASE; #else return PLAT_POPLAR_NS_IMAGE_OFFSET; #endif } trusted-firmware-a-2.2/plat/hisilicon/poplar/bl31_plat_setup.c000066400000000000000000000067311355360272700245030ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hi3798cv200.h" #include "plat_private.h" #define TZPC_SEC_ATTR_CTRL_VALUE (0x9DB98D45) static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; static console_pl011_t console; static void hisi_tzpc_sec_init(void) { mmio_write_32(HISI_TZPC_SEC_ATTR_CTRL, TZPC_SEC_ATTR_CTRL_VALUE); } entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; assert(sec_state_is_valid(type)); next_image_info = (type == NON_SECURE) ? &bl33_image_ep_info : &bl32_image_ep_info; /* * None of the images on the ARM development platforms can have 0x0 * as the entrypoint */ if (next_image_info->pc) return next_image_info; else return NULL; } /******************************************************************************* * Perform any BL31 early platform setup common to ARM standard platforms. * Here is an opportunity to copy parameters passed by the calling EL (S-EL1 * in BL2 & EL3 in BL1) before they are lost (potentially). This needs to be * done before the MMU is initialized so that the memory layout can be used * while creating page tables. BL2 has flushed this information to memory, so * we are guaranteed to pick up good data. ******************************************************************************/ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { void *from_bl2; from_bl2 = (void *) arg0; console_pl011_register(PL011_UART0_BASE, PL011_UART0_CLK_IN_HZ, PL011_BAUDRATE, &console); /* Init console for crash report */ plat_crash_console_init(); /* * Check params passed from BL2 should not be NULL, */ bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2; assert(params_from_bl2 != NULL); assert(params_from_bl2->h.type == PARAM_BL_PARAMS); assert(params_from_bl2->h.version >= VERSION_2); bl_params_node_t *bl_params = params_from_bl2->head; /* * Copy BL33 and BL32 (if present), entry point information. * They are stored in Secure RAM, in BL2's address space. */ while (bl_params) { if (bl_params->image_id == BL32_IMAGE_ID) bl32_image_ep_info = *bl_params->ep_info; if (bl_params->image_id == BL33_IMAGE_ID) bl33_image_ep_info = *bl_params->ep_info; bl_params = bl_params->next_params_info; } if (bl33_image_ep_info.pc == 0) panic(); } void bl31_platform_setup(void) { /* Init arch timer */ generic_delay_timer_init(); /* Init GIC distributor and CPU interface */ poplar_gic_driver_init(); poplar_gic_init(); /* Init security properties of IP blocks */ hisi_tzpc_sec_init(); } void bl31_plat_runtime_setup(void) { /* do nothing */ } void bl31_plat_arch_setup(void) { plat_configure_mmu_el3(BL31_BASE, (BL31_LIMIT - BL31_BASE), BL_CODE_BASE, BL_CODE_END, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); INFO("Boot BL33 from 0x%lx for %llu Bytes\n", bl33_image_ep_info.pc, bl33_image_ep_info.args.arg2); } trusted-firmware-a-2.2/plat/hisilicon/poplar/include/000077500000000000000000000000001355360272700227525ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/hisilicon/poplar/include/hi3798cv200.h000066400000000000000000000054331355360272700246360ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HI3798CV200_H #define HI3798CV200_H #include /* PL011 */ #define PL011_UART0_BASE (0xF8B00000) #define PL011_BAUDRATE (115200) #define PL011_UART0_CLK_IN_HZ (75000000) /* Sys Counter */ #define SYS_COUNTER_FREQ_IN_TICKS (24000000) #define SYS_COUNTER_FREQ_IN_MHZ (24) /* Timer */ #define SEC_TIMER0_BASE (0xF8008000) #define TIMER00_LOAD (SEC_TIMER0_BASE + 0x000) #define TIMER00_VALUE (SEC_TIMER0_BASE + 0x004) #define TIMER00_CONTROL (SEC_TIMER0_BASE + 0x008) #define TIMER00_BGLOAD (SEC_TIMER0_BASE + 0x018) #define SEC_TIMER2_BASE (0xF8009000) #define TIMER20_LOAD (SEC_TIMER2_BASE + 0x000) #define TIMER20_VALUE (SEC_TIMER2_BASE + 0x004) #define TIMER20_CONTROL (SEC_TIMER2_BASE + 0x008) #define TIMER20_BGLOAD (SEC_TIMER2_BASE + 0x018) /* GPIO */ #define GPIO_MAX (13) #define GPIO_BASE(x) (x != 5 ? \ 0xf820000 + x * 0x1000 : 0xf8004000) /* SCTL */ #define REG_BASE_SCTL (0xF8000000) #define REG_SC_GEN12 (0x00B0) /* CRG */ #define REG_BASE_CRG (0xF8A22000) #define REG_CPU_LP (0x48) #define REG_CPU_RST (0x50) #define REG_PERI_CRG39 (0x9C) #define REG_PERI_CRG40 (0xA0) /* MCI */ #define REG_BASE_MCI (0xF9830000) #define MCI_CDETECT (0x50) #define MCI_VERID (0x6C) #define MCI_VERID_VALUE (0x5342250A) #define MCI_VERID_VALUE2 (0x5342270A) /* EMMC */ #define REG_EMMC_PERI_CRG REG_PERI_CRG40 #define REG_SDCARD_PERI_CRG REG_PERI_CRG39 #define EMMC_CLK_MASK (0x7 << 8) #define EMMC_SRST_REQ (0x1 << 4) #define EMMC_CKEN (0x1 << 1) #define EMMC_BUS_CKEN (0x1 << 0) #define EMMC_CLK_100M (0 << 8) #define EMMC_CLK_50M (1 << 8) #define EMMC_CLK_25M (2 << 8) #define EMMC_DESC_SIZE U(0x00100000) /* 1MB */ #define EMMC_INIT_PARAMS(base) \ { .bus_width = MMC_BUS_WIDTH_8, \ .clk_rate = 25 * 1000 * 1000, \ .desc_base = (base), \ .desc_size = EMMC_DESC_SIZE, \ .flags = MMC_FLAG_CMD23, \ .reg_base = REG_BASE_MCI, \ } /* GIC-400 */ #define GICD_BASE (0xF1001000) #define GICC_BASE (0xF1002000) #define GICR_BASE (0xF1000000) /* FIQ platform related define */ #define HISI_IRQ_SEC_SGI_0 8 #define HISI_IRQ_SEC_SGI_1 9 #define HISI_IRQ_SEC_SGI_2 10 #define HISI_IRQ_SEC_SGI_3 11 #define HISI_IRQ_SEC_SGI_4 12 #define HISI_IRQ_SEC_SGI_5 13 #define HISI_IRQ_SEC_SGI_6 14 #define HISI_IRQ_SEC_SGI_7 15 #define HISI_IRQ_SEC_PPI_0 29 #define HISI_IRQ_SEC_TIMER0 60 #define HISI_IRQ_SEC_TIMER1 50 #define HISI_IRQ_SEC_TIMER2 52 #define HISI_IRQ_SEC_TIMER3 88 #define HISI_IRQ_SEC_AXI 110 /* Watchdog */ #define HISI_WDG0_BASE (0xF8A2C000) #define HISI_TZPC_BASE (0xF8A80000) #define HISI_TZPC_SEC_ATTR_CTRL (HISI_TZPC_BASE + 0x10) #endif /* HI3798CV200_H */ trusted-firmware-a-2.2/plat/hisilicon/poplar/include/plat_macros.S000066400000000000000000000003141355360272700254000ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ .section .rodata.gic_reg_name, "aS" .macro plat_crash_print_regs nop .endm trusted-firmware-a-2.2/plat/hisilicon/poplar/include/plat_private.h000066400000000000000000000016151355360272700256200ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_PRIVATE_H #define PLAT_PRIVATE_H #include #include "hi3798cv200.h" void plat_configure_mmu_el3(unsigned long total_base, unsigned long total_size, unsigned long ro_start, unsigned long ro_limit, unsigned long coh_start, unsigned long coh_limit); void plat_configure_mmu_el1(unsigned long total_base, unsigned long total_size, unsigned long ro_start, unsigned long ro_limit, unsigned long coh_start, unsigned long coh_limit); void plat_io_setup(void); unsigned int poplar_calc_core_pos(u_register_t mpidr); void poplar_gic_driver_init(void); void poplar_gic_init(void); void poplar_gic_cpuif_enable(void); void poplar_gic_pcpu_init(void); #endif /* PLAT_PRIVATE_H */ trusted-firmware-a-2.2/plat/hisilicon/poplar/include/platform_def.h000066400000000000000000000124741355360272700255750ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include #include #include #include "hi3798cv200.h" #include "poplar_layout.h" /* BL memory region sizes, etc */ /* Special value used to verify platform parameters from BL2 to BL3-1 */ #define POPLAR_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 #define POPLAR_CRASH_UART_BASE PL011_UART0_BASE #define POPLAR_CRASH_UART_CLK_IN_HZ PL011_UART0_CLK_IN_HZ #define POPLAR_CONSOLE_BAUDRATE PL011_BAUDRATE /* Generic platform constants */ #define PLATFORM_STACK_SIZE (0x800) #define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n" #define BOOT_EMMC_NAME "l-loader.bin" #define PLATFORM_CACHE_LINE_SIZE (64) #define PLATFORM_CLUSTER_COUNT (1) #define PLATFORM_CORE_COUNT (4) #define PLATFORM_MAX_CPUS_PER_CLUSTER (4) /* IO framework user */ #define MAX_IO_DEVICES (4) #define MAX_IO_HANDLES (4) #define MAX_IO_BLOCK_DEVICES U(2) /* Memory size options */ #define POPLAR_DRAM_SIZE_1G 0 #define POPLAR_DRAM_SIZE_2G 1 /* Memory map related constants */ #define DDR_BASE (0x00000000) #if (POPLAR_DRAM_SIZE_ID == POPLAR_DRAM_SIZE_2G) #define DDR_SIZE (0x80000000) #elif (POPLAR_DRAM_SIZE_ID == POPLAR_DRAM_SIZE_1G) #define DDR_SIZE (0x40000000) #else #error "Currently unsupported POPLAR_DRAM_SIZE_ID value" #endif #define DEVICE_BASE (0xF0000000) #define DEVICE_SIZE (0x0F000000) #define TEE_SEC_MEM_BASE (0x70000000) #define TEE_SEC_MEM_SIZE (0x10000000) /* Memory location options for TSP */ #define POPLAR_SRAM_ID 0 #define POPLAR_DRAM_ID 1 /* * DDR for OP-TEE (26MB from 0x02400000 -0x04000000) is divided in several * regions: * - Secure DDR (default is the top 16MB) used by OP-TEE * - Non-secure DDR (4MB) reserved for OP-TEE's future use * - Secure DDR (4MB aligned on 4MB) for OP-TEE's "Secure Data Path" feature * - Non-secure DDR used by OP-TEE (shared memory and padding) (4MB) */ #define DDR_SEC_SIZE 0x01000000 #define DDR_SEC_BASE 0x03000000 /* * BL3-2 specific defines. */ /* * The TSP currently executes from TZC secured area of DRAM. */ #define BL32_DRAM_BASE 0x03000000 #define BL32_DRAM_LIMIT 0x04000000 #ifdef SPD_opteed /* Load pageable part of OP-TEE at end of allocated DRAM space for BL32 */ #define POPLAR_OPTEE_PAGEABLE_LOAD_SIZE 0x400000 /* 4MB */ #define POPLAR_OPTEE_PAGEABLE_LOAD_BASE (BL32_DRAM_LIMIT - POPLAR_OPTEE_PAGEABLE_LOAD_SIZE) /* 0x03C0_0000 */ #endif #if (POPLAR_TSP_RAM_LOCATION_ID == POPLAR_DRAM_ID) #define TSP_SEC_MEM_BASE BL32_DRAM_BASE #define TSP_SEC_MEM_SIZE (BL32_DRAM_LIMIT - BL32_DRAM_BASE) #define BL32_BASE BL32_DRAM_BASE #define BL32_LIMIT BL32_DRAM_LIMIT #elif (POPLAR_TSP_RAM_LOCATION_ID == POPLAR_SRAM_ID) #error "SRAM storage of TSP payload is currently unsupported" #else #error "Currently unsupported POPLAR_TSP_LOCATION_ID value" #endif /* BL32 is mandatory in AArch32 */ #ifdef __aarch64__ #ifdef SPD_none #undef BL32_BASE #endif /* SPD_none */ #endif #define POPLAR_EMMC_DATA_BASE U(0x02200000) #define POPLAR_EMMC_DATA_SIZE EMMC_DESC_SIZE #define POPLAR_EMMC_DESC_BASE (POPLAR_EMMC_DATA_BASE + POPLAR_EMMC_DATA_SIZE) #define POPLAR_EMMC_DESC_SIZE EMMC_DESC_SIZE #define PLAT_POPLAR_NS_IMAGE_OFFSET 0x37000000 /* Page table and MMU setup constants */ #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define MAX_XLAT_TABLES (4) #define MAX_MMAP_REGIONS (16) #define CACHE_WRITEBACK_SHIFT (6) #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) /* Power states */ #define PLAT_MAX_PWR_LVL (MPIDR_AFFLVL1) #define PLAT_MAX_OFF_STATE U(2) #define PLAT_MAX_RET_STATE U(1) /* Interrupt controller */ #define POPLAR_GICD_BASE GICD_BASE #define POPLAR_GICC_BASE GICC_BASE #define POPLAR_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(HISI_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(HISI_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(HISI_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(HISI_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(HISI_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(HISI_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(HISI_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(HISI_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(HISI_IRQ_SEC_TIMER0, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(HISI_IRQ_SEC_TIMER1, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(HISI_IRQ_SEC_TIMER2, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(HISI_IRQ_SEC_TIMER3, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(HISI_IRQ_SEC_AXI, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL) #define POPLAR_G0_IRQ_PROPS(grp) #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/hisilicon/poplar/include/poplar_layout.h000066400000000000000000000115431355360272700260210ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef POPLAR_LAYOUT_H #define POPLAR_LAYOUT_H /* * Boot memory layout definitions for the HiSilicon Poplar board */ /* * When Poplar is powered on, boot ROM verifies the initial content of * boot media, loads it into low memory, and begins executing it * in 32-bit mode. The image loaded is "l-loader.bin", which contains * a small amount code along with an embedded ARM Trusted Firmware * BL1 image. The main purpose of "l-loader" is to prepare the * processor to execute the BL1 image in 64-bit mode, and to trigger * that execution. * * Also embedded in "l-loader.bin" is a FIP image that contains * other ARM Trusted Firmware images: BL2; BL31; and for BL33, * U-Boot. When BL1 executes, it unpacks the BL2 image from the FIP * image into a region of memory set aside to hold it. Similarly, * BL2 unpacks BL31 into memory reserved for it, and unpacks U-Boot * into high memory. * * Because the BL1 code is embedded in "l-loader", its base address * in memory is derived from the base address of the "l-loader" * text section, together with an offset. Memory space for BL2 is * reserved immediately following BL1, and memory space is reserved * for BL31 after that. ARM Trusted Firmware requires each of these * memory regions to be aligned on page boundaries, so the size of * each region is a multiple of a page size (ending in 000). Note * that ARM Trusted Firmware requires the read-only and read-write * regions of memory used for BL1 to be defined separately. * * --------------------- * | (unused memory) | * +-------------------+ - - - - - * | (l-loader text) | \ * +-------------------+ \ * | BL1 (read-only) | \ \ * |- - - - - - - - - -| | | * | BL1 (read-write) | | | * +-------------------+ > BL Memory | * | Reserved for BL2 | | > "l-loader.bin" image * +-------------------+ | | * | Reserved for BL31 | / | * +-------------------+ | * . . . / * +-------------------+ / * | FIP | / * +-------------------+ - - - - - * . . . * | (unused memory) | * . . . * +-------------------+ * |Reserved for U-Boot| * +-------------------+ * . . . * | (unused memory) | * --------------------- * * The size of each of these regions is defined below. The base * address of the "l-loader" TEXT section and the offset of the BL1 * image within that serve as anchors for defining the positions of * all other regions. The FIP is placed in a section of its own. * * A "BASE" is the memory address of the start of a region; a "LIMIT" * marks its end. A "SIZE" is the size of a region (in bytes). An * "OFFSET" is an offset to the start of a region relative to the * base of the "l-loader" TEXT section (also a multiple of page size). */ #define LLOADER_TEXT_BASE 0x02001000 /* page aligned */ #define BL1_OFFSET 0x0000D000 /* page multiple */ #define FIP_BASE 0x02040000 /* * FIP_BASE_EMMC = 0x40000 - 0x1000 * = fip.bin offset - l-loader text offset * in l-loader.bin */ #define FIP_BASE_EMMC 0x0003f000 #define BL1_RO_SIZE 0x00008000 /* page multiple */ #define BL1_RW_SIZE 0x00008000 /* page multiple */ #define BL1_SIZE (BL1_RO_SIZE + BL1_RW_SIZE) #define BL2_SIZE 0x0000d000 /* page multiple */ #define BL31_SIZE 0x00014000 #if !POPLAR_RECOVERY /* * emmc partition1 4096KB * - l-loader.bin 1984KB * |- l-loader + bl1.bin 256KB * |- fip.bin 1728KB (0x001b0000) * - u-boot persistent data 64KB * - uefi persistent data 2048KB */ #define FIP_SIZE 0x001b0000 /* absolute max */ #else /* * same as above, but bootrom can only load an image (l-loader.bin) of * 1024KB max, so after deducting the size of l-loader + bl1.bin (256KB), * that leaves 768KB (0x000c0000) for fip.bin */ #define FIP_SIZE 0x000c0000 /* absolute max */ #endif /* BL1_OFFSET */ /* (Defined above) */ #define BL1_BASE (LLOADER_TEXT_BASE + BL1_OFFSET) #define BL1_LIMIT (BL1_BASE + BL1_SIZE) #define BL1_RO_OFFSET (BL1_OFFSET) #define BL1_RO_BASE (LLOADER_TEXT_BASE + BL1_RO_OFFSET) #define BL1_RO_LIMIT (BL1_RO_BASE + BL1_RO_SIZE) #define BL1_RW_OFFSET (BL1_RO_OFFSET + BL1_RO_SIZE) #define BL1_RW_BASE (LLOADER_TEXT_BASE + BL1_RW_OFFSET) #define BL1_RW_LIMIT (BL1_RW_BASE + BL1_RW_SIZE) #define BL2_OFFSET (BL1_OFFSET + BL1_SIZE) #define BL2_BASE (LLOADER_TEXT_BASE + BL2_OFFSET) #define BL2_LIMIT (BL2_BASE + BL2_SIZE) #define BL31_OFFSET (BL2_OFFSET + BL2_SIZE) #define BL31_BASE (LLOADER_TEXT_BASE + BL31_OFFSET) #define BL31_LIMIT (BL31_BASE + BL31_SIZE) #endif /* POPLAR_LAYOUT_H */ trusted-firmware-a-2.2/plat/hisilicon/poplar/plat_pm.c000066400000000000000000000113071355360272700231310ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "hi3798cv200.h" #include "plat_private.h" #define REG_PERI_CPU_RVBARADDR 0xF8A80034 #define REG_PERI_CPU_AARCH_MODE 0xF8A80030 #define REG_CPU_LP_CPU_SW_BEGIN 10 #define CPU_REG_COREPO_SRST 12 #define CPU_REG_CORE_SRST 8 static void poplar_cpu_standby(plat_local_state_t cpu_state) { dsb(); wfi(); } static int poplar_pwr_domain_on(u_register_t mpidr) { unsigned int cpu = plat_core_pos_by_mpidr(mpidr); unsigned int regval, regval_bak; /* Select 400MHz before start slave cores */ regval_bak = mmio_read_32((uintptr_t)(REG_BASE_CRG + REG_CPU_LP)); mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_LP), 0x206); mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_LP), 0x606); /* Clear the slave cpu arm_por_srst_req reset */ regval = mmio_read_32((uintptr_t)(REG_BASE_CRG + REG_CPU_RST)); regval &= ~(1 << (cpu + CPU_REG_COREPO_SRST)); mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_RST), regval); /* Clear the slave cpu reset */ regval = mmio_read_32((uintptr_t)(REG_BASE_CRG + REG_CPU_RST)); regval &= ~(1 << (cpu + CPU_REG_CORE_SRST)); mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_RST), regval); /* Restore cpu frequency */ regval = regval_bak & (~(1 << REG_CPU_LP_CPU_SW_BEGIN)); mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_LP), regval); mmio_write_32((uintptr_t)(REG_BASE_CRG + REG_CPU_LP), regval_bak); return PSCI_E_SUCCESS; } static void poplar_pwr_domain_off(const psci_power_state_t *target_state) { assert(0); } static void poplar_pwr_domain_suspend(const psci_power_state_t *target_state) { assert(0); } static void poplar_pwr_domain_on_finish(const psci_power_state_t *target_state) { assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == PLAT_MAX_OFF_STATE); /* Enable the gic cpu interface */ poplar_gic_pcpu_init(); /* Program the gic per-cpu distributor or re-distributor interface */ poplar_gic_cpuif_enable(); } static void poplar_pwr_domain_suspend_finish( const psci_power_state_t *target_state) { assert(0); } static void __dead2 poplar_system_off(void) { ERROR("Poplar System Off: operation not handled.\n"); panic(); } static void __dead2 poplar_system_reset(void) { mmio_write_32((uintptr_t)(HISI_WDG0_BASE + 0xc00), 0x1ACCE551); mmio_write_32((uintptr_t)(HISI_WDG0_BASE + 0x0), 0x00000100); mmio_write_32((uintptr_t)(HISI_WDG0_BASE + 0x8), 0x00000003); wfi(); ERROR("Poplar System Reset: operation not handled.\n"); panic(); } static int32_t poplar_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); int pstate = psci_get_pstate_type(power_state); assert(req_state); /* Sanity check the requested state */ if (pstate == PSTATE_TYPE_STANDBY) req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE; else req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE; /* We expect the 'state id' to be zero */ if (psci_get_pstate_id(power_state)) return PSCI_E_INVALID_PARAMS; return PSCI_E_SUCCESS; } static int poplar_validate_ns_entrypoint(uintptr_t entrypoint) { /* * Check if the non secure entrypoint lies within the non * secure DRAM. */ if ((entrypoint >= DDR_BASE) && (entrypoint < (DDR_BASE + DDR_SIZE))) return PSCI_E_SUCCESS; return PSCI_E_INVALID_ADDRESS; } static void poplar_get_sys_suspend_power_state(psci_power_state_t *req_state) { int i; for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; } static const plat_psci_ops_t poplar_plat_psci_ops = { .cpu_standby = poplar_cpu_standby, .pwr_domain_on = poplar_pwr_domain_on, .pwr_domain_off = poplar_pwr_domain_off, .pwr_domain_suspend = poplar_pwr_domain_suspend, .pwr_domain_on_finish = poplar_pwr_domain_on_finish, .pwr_domain_suspend_finish = poplar_pwr_domain_suspend_finish, .system_off = poplar_system_off, .system_reset = poplar_system_reset, .validate_power_state = poplar_validate_power_state, .validate_ns_entrypoint = poplar_validate_ns_entrypoint, .get_sys_suspend_power_state = poplar_get_sys_suspend_power_state, }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { *psci_ops = &poplar_plat_psci_ops; mmio_write_32((uintptr_t)REG_PERI_CPU_AARCH_MODE, 0xF); mmio_write_32((uintptr_t)REG_PERI_CPU_RVBARADDR, sec_entrypoint); return 0; } trusted-firmware-a-2.2/plat/hisilicon/poplar/plat_storage.c000066400000000000000000000124121355360272700241570ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if !POPLAR_RECOVERY static const io_dev_connector_t *emmc_dev_con; static uintptr_t emmc_dev_handle; static int open_emmc(const uintptr_t spec); static const io_block_spec_t emmc_fip_spec = { .offset = FIP_BASE_EMMC, .length = FIP_SIZE }; static const io_block_dev_spec_t emmc_dev_spec = { .buffer = { .offset = POPLAR_EMMC_DATA_BASE, .length = POPLAR_EMMC_DATA_SIZE, }, .ops = { .read = mmc_read_blocks, .write = mmc_write_blocks, }, .block_size = MMC_BLOCK_SIZE, }; #else static const io_dev_connector_t *mmap_dev_con; static uintptr_t mmap_dev_handle; static int open_mmap(const uintptr_t spec); static const io_block_spec_t loader_fip_spec = { .offset = FIP_BASE, .length = FIP_SIZE }; #endif static const io_dev_connector_t *fip_dev_con; static uintptr_t fip_dev_handle; static int open_fip(const uintptr_t spec); static const io_uuid_spec_t bl2_uuid_spec = { .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2, }; static const io_uuid_spec_t bl31_uuid_spec = { .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31, }; static const io_uuid_spec_t bl32_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32, }; static const io_uuid_spec_t bl32_extra1_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1, }; static const io_uuid_spec_t bl32_extra2_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2, }; static const io_uuid_spec_t bl33_uuid_spec = { .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33, }; 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[] = { #if !POPLAR_RECOVERY [FIP_IMAGE_ID] = { &emmc_dev_handle, (uintptr_t)&emmc_fip_spec, open_emmc }, #else [FIP_IMAGE_ID] = { &mmap_dev_handle, (uintptr_t)&loader_fip_spec, open_mmap }, #endif [BL2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl2_uuid_spec, open_fip }, [BL31_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl31_uuid_spec, open_fip }, [BL32_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_uuid_spec, open_fip }, [BL32_EXTRA1_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_extra1_uuid_spec, open_fip }, [BL32_EXTRA2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_extra2_uuid_spec, open_fip }, [BL33_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl33_uuid_spec, open_fip }, }; #if !POPLAR_RECOVERY static int open_emmc(const uintptr_t spec) { int result; uintptr_t local_image_handle; result = io_dev_init(emmc_dev_handle, (uintptr_t)NULL); if (result == 0) { result = io_open(emmc_dev_handle, spec, &local_image_handle); if (result == 0) { INFO("Using eMMC\n"); io_close(local_image_handle); } else { ERROR("error opening emmc\n"); } } else { ERROR("error initializing emmc\n"); } return result; } #else static int open_mmap(const uintptr_t spec) { int result; uintptr_t local_image_handle; result = io_dev_init(mmap_dev_handle, (uintptr_t)NULL); if (result == 0) { result = io_open(mmap_dev_handle, spec, &local_image_handle); if (result == 0) { INFO("Using mmap\n"); io_close(local_image_handle); } else { ERROR("error opening mmap\n"); } } else { ERROR("error initializing mmap\n"); } return result; } #endif static int open_fip(const uintptr_t spec) { uintptr_t local_image_handle; int result; result = io_dev_init(fip_dev_handle, (uintptr_t) FIP_IMAGE_ID); if (result == 0) { result = io_open(fip_dev_handle, spec, &local_image_handle); if (result == 0) { INFO("Using FIP\n"); io_close(local_image_handle); } else { ERROR("error opening fip\n"); } } else { ERROR("error initializing fip\n"); } return result; } int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, uintptr_t *image_spec) { const struct plat_io_policy *policy; int result; assert(image_id < ARRAY_SIZE(policies)); policy = &policies[image_id]; result = policy->check(policy->image_spec); assert(result == 0); *image_spec = policy->image_spec; *dev_handle = *(policy->dev_handle); return result; } void plat_io_setup(void) { int result; #if !POPLAR_RECOVERY result = register_io_dev_block(&emmc_dev_con); #else result = register_io_dev_memmap(&mmap_dev_con); #endif assert(result == 0); result = register_io_dev_fip(&fip_dev_con); assert(result == 0); #if !POPLAR_RECOVERY result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle); #else result = io_dev_open(fip_dev_con, (uintptr_t)&loader_fip_spec, &fip_dev_handle); #endif assert(result == 0); #if !POPLAR_RECOVERY result = io_dev_open(emmc_dev_con, (uintptr_t)&emmc_dev_spec, &emmc_dev_handle); #else result = io_dev_open(mmap_dev_con, (uintptr_t)NULL, &mmap_dev_handle); #endif assert(result == 0); (void) result; } trusted-firmware-a-2.2/plat/hisilicon/poplar/plat_topology.c000066400000000000000000000012001355360272700243600ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "plat_private.h" const unsigned char hisi_power_domain_tree_desc[] = { PLATFORM_CLUSTER_COUNT, PLATFORM_CORE_COUNT, }; const unsigned char *plat_get_power_domain_tree_desc(void) { return hisi_power_domain_tree_desc; } int plat_core_pos_by_mpidr(u_register_t mpidr) { if (mpidr & MPIDR_CLUSTER_MASK) return -1; if ((mpidr & MPIDR_CPU_MASK) >= PLATFORM_CORE_COUNT) return -1; return poplar_calc_core_pos(mpidr); } trusted-firmware-a-2.2/plat/hisilicon/poplar/platform.mk000066400000000000000000000064741355360272700235170ustar00rootroot00000000000000# # Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # On Poplar, the TSP can execute from TZC secure area in DRAM. POPLAR_TSP_RAM_LOCATION ?= dram ifeq (${POPLAR_TSP_RAM_LOCATION}, dram) POPLAR_TSP_RAM_LOCATION_ID = POPLAR_DRAM_ID else ifeq (${POPLAR_TSP_RAM_LOCATION}, sram) POPLAR_TSP_RAM_LOCATION_ID = POPLAR_SRAM_ID else $(error "Currently unsupported POPLAR_TSP_RAM_LOCATION value") endif $(eval $(call add_define,POPLAR_TSP_RAM_LOCATION_ID)) POPLAR_DRAM_SIZE ?= two_gig ifeq (${POPLAR_DRAM_SIZE}, two_gig) POPLAR_DRAM_SIZE_ID = POPLAR_DRAM_SIZE_2G else ifeq (${POPLAR_DRAM_SIZE}, one_gig) POPLAR_DRAM_SIZE_ID = POPLAR_DRAM_SIZE_1G else $(error "Currently unsupported POPLAR_DRAM_SIZE value") endif $(eval $(call add_define,POPLAR_DRAM_SIZE_ID)) POPLAR_RECOVERY := 0 $(eval $(call add_define,POPLAR_RECOVERY)) # Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images # in the FIP if the platform requires. ifneq ($(BL32_EXTRA1),) $(eval $(call TOOL_ADD_IMG,BL32_EXTRA1,--tos-fw-extra1)) endif ifneq ($(BL32_EXTRA2),) $(eval $(call TOOL_ADD_IMG,BL32_EXTRA2,--tos-fw-extra2)) endif NEED_BL33 := yes COLD_BOOT_SINGLE_CPU := 1 PROGRAMMABLE_RESET_ADDRESS := 1 CTX_INCLUDE_FPREGS := 1 ERRATA_A53_855873 := 1 ERRATA_A53_835769 := 1 ERRATA_A53_843419 := 1 ENABLE_SVE_FOR_NS := 0 WORKAROUND_CVE_2017_5715 := 0 PLAT_PL061_MAX_GPIOS := 104 $(eval $(call add_define,PLAT_PL061_MAX_GPIOS)) PLAT_INCLUDES := -Iplat/hisilicon/poplar/include \ -Iplat/hisilicon/poplar PLAT_BL_COMMON_SOURCES := \ lib/xlat_tables/aarch64/xlat_tables.c \ lib/xlat_tables/xlat_tables_common.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_helpers.c \ drivers/delay_timer/delay_timer.c \ drivers/arm/pl011/aarch64/pl011_console.S \ drivers/arm/gic/v2/gicv2_main.c \ plat/common/plat_gicv2.c \ plat/hisilicon/poplar/aarch64/platform_common.c \ plat/hisilicon/poplar/aarch64/poplar_helpers.S \ plat/hisilicon/poplar/poplar_gicv2.c BL1_SOURCES += \ lib/cpus/aarch64/cortex_a53.S \ drivers/arm/pl061/pl061_gpio.c \ drivers/mmc/mmc.c \ drivers/synopsys/emmc/dw_mmc.c \ drivers/io/io_storage.c \ drivers/io/io_block.c \ drivers/gpio/gpio.c \ drivers/io/io_fip.c \ drivers/io/io_memmap.c \ plat/hisilicon/poplar/bl1_plat_setup.c \ plat/hisilicon/poplar/plat_storage.c BL2_SOURCES += \ drivers/arm/pl061/pl061_gpio.c \ drivers/mmc/mmc.c \ drivers/synopsys/emmc/dw_mmc.c \ drivers/io/io_storage.c \ drivers/io/io_block.c \ drivers/io/io_fip.c \ drivers/gpio/gpio.c \ drivers/io/io_memmap.c \ plat/hisilicon/poplar/bl2_plat_setup.c \ plat/hisilicon/poplar/plat_storage.c BL2_SOURCES += \ plat/hisilicon/poplar/bl2_plat_mem_params_desc.c \ plat/hisilicon/poplar/poplar_image_load.c \ common/desc_image_load.c ifeq (${SPD},opteed) BL2_SOURCES += \ lib/optee/optee_utils.c endif BL31_SOURCES += \ lib/cpus/aarch64/aem_generic.S \ lib/cpus/aarch64/cortex_a53.S \ plat/common/plat_psci_common.c \ plat/hisilicon/poplar/bl31_plat_setup.c \ plat/hisilicon/poplar/plat_topology.c \ plat/hisilicon/poplar/plat_pm.c trusted-firmware-a-2.2/plat/hisilicon/poplar/poplar_gicv2.c000066400000000000000000000037601355360272700240700ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /****************************************************************************** * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0 * interrupts. *****************************************************************************/ static const interrupt_prop_t poplar_interrupt_props[] = { POPLAR_G1S_IRQ_PROPS(GICV2_INTR_GROUP0), POPLAR_G0_IRQ_PROPS(GICV2_INTR_GROUP0) }; static unsigned int target_mask_array[PLATFORM_CORE_COUNT]; static const gicv2_driver_data_t poplar_gic_data = { .gicd_base = POPLAR_GICD_BASE, .gicc_base = POPLAR_GICC_BASE, .interrupt_props = poplar_interrupt_props, .interrupt_props_num = ARRAY_SIZE(poplar_interrupt_props), .target_masks = target_mask_array, .target_masks_num = ARRAY_SIZE(target_mask_array), }; /****************************************************************************** * Helper to initialize the GICv2 only driver. *****************************************************************************/ void poplar_gic_driver_init(void) { gicv2_driver_init(&poplar_gic_data); } void poplar_gic_init(void) { gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_set_pe_target_mask(plat_my_core_pos()); gicv2_cpuif_enable(); } /****************************************************************************** * Helper to enable the GICv2 CPU interface *****************************************************************************/ void poplar_gic_cpuif_enable(void) { gicv2_cpuif_enable(); } /****************************************************************************** * Helper to initialize the per cpu distributor interface in GICv2 *****************************************************************************/ void poplar_gic_pcpu_init(void) { gicv2_pcpu_distif_init(); gicv2_set_pe_target_mask(plat_my_core_pos()); } trusted-firmware-a-2.2/plat/hisilicon/poplar/poplar_image_load.c000066400000000000000000000022561355360272700251360ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /******************************************************************************* * This function flushes the data structures so that they are visible * in memory for the next BL image. ******************************************************************************/ void plat_flush_next_bl_params(void) { flush_bl_params_desc(); } /******************************************************************************* * This function returns the list of loadable images. ******************************************************************************/ bl_load_info_t *plat_get_bl_image_load_info(void) { return get_bl_load_info_from_mem_params_desc(); } /******************************************************************************* * This function returns the list of executable images. ******************************************************************************/ bl_params_t *plat_get_next_bl_params(void) { return get_next_bl_params_from_mem_params_desc(); } trusted-firmware-a-2.2/plat/imx/000077500000000000000000000000001355360272700166465ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/000077500000000000000000000000001355360272700201365ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/aarch32/000077500000000000000000000000001355360272700213615ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/aarch32/imx_uart_console.S000066400000000000000000000020711355360272700250570ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "imx_uart.h" .globl console_imx_uart_register .globl console_imx_uart_putc .globl console_imx_uart_getc .globl console_imx_uart_flush func console_imx_uart_register push {r4, lr} mov r4, r3 cmp r4, #0 beq register_fail str r0, [r4, #CONSOLE_T_DRVDATA] bl console_imx_uart_core_init cmp r0, #0 bne register_fail mov r0, r4 pop {r4, lr} finish_console_register imx_uart putc=1, getc=1, flush=1 register_fail: pop {r4, pc} endfunc console_imx_uart_register func console_imx_uart_putc ldr r1, [r1, #CONSOLE_T_DRVDATA] b console_imx_uart_core_putc endfunc console_imx_uart_putc func console_imx_uart_getc ldr r0, [r0, #CONSOLE_T_DRVDATA] b console_imx_uart_core_getc endfunc console_imx_uart_getc func console_imx_uart_flush ldr r0, [r0, #CONSOLE_T_DRVDATA] b console_imx_uart_core_flush endfunc console_imx_uart_flush trusted-firmware-a-2.2/plat/imx/common/imx7_clock.c000066400000000000000000000023511355360272700223420ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include static void imx7_clock_uart_init(void) { unsigned int i; for (i = 0; i < MXC_MAX_UART_NUM; i++) imx_clock_disable_uart(i); } static void imx7_clock_wdog_init(void) { unsigned int i; for (i = 0; i < MXC_MAX_WDOG_NUM; i++) imx_clock_disable_wdog(i); } static void imx7_clock_usb_init(void) { /* Disable the clock root */ imx_clock_target_clr(CCM_TRT_ID_USB_HSIC_CLK_ROOT, 0xFFFFFFFF); } void imx_clock_init(void) { /* * The BootROM hands off to the next stage with the internal 24 MHz XTAL * crystal already clocking the main PLL, which is very handy. * Here we should enable whichever peripherals are required for ATF and * OPTEE. * * Subsequent stages in the boot process such as u-boot and Linux * already have a significant and mature code-base around clocks, so our * objective should be to enable what we need for ATF/OPTEE without * breaking any existing upstream code in Linux and u-boot. */ /* Initialize UART clocks */ imx7_clock_uart_init(); /* Watchdog clocks */ imx7_clock_wdog_init(); /* USB clocks */ imx7_clock_usb_init(); } trusted-firmware-a-2.2/plat/imx/common/imx8_helpers.S000066400000000000000000000061601355360272700226740ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl plat_is_my_cpu_primary .globl plat_my_core_pos .globl plat_calc_core_pos .globl plat_reset_handler .globl plat_get_my_entrypoint .globl plat_secondary_cold_boot_setup .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush .globl platform_mem_init .globl imx_mailbox_init /* -------------------------------------------------------------------- * Helper macro that reads the part number of the current CPU and jumps * to the given label if it matches the CPU MIDR provided. * * Clobbers x0. * -------------------------------------------------------------------- */ .macro jump_if_cpu_midr _cpu_midr, _label mrs x0, midr_el1 ubfx x0, x0, MIDR_PN_SHIFT, #12 cmp w0, #((\_cpu_midr >> MIDR_PN_SHIFT) & MIDR_PN_MASK) b.eq \_label .endm /* ---------------------------------------------- * The mailbox_base is used to distinguish warm/cold * reset. The mailbox_base is in the data section, not * in .bss, this allows function to start using this * variable before the runtime memory is initialized. * ---------------------------------------------- */ .section .data.mailbox_base .align 3 mailbox_base: .quad 0x0 /* ---------------------------------------------- * unsigned int plat_is_my_cpu_primary(void); * This function checks if this is the primary CPU * ---------------------------------------------- */ func plat_is_my_cpu_primary mrs x0, mpidr_el1 and x0, x0, #(MPIDR_CPU_MASK) cmp x0, #PLAT_PRIMARY_CPU cset x0, eq ret endfunc plat_is_my_cpu_primary /* ---------------------------------------------- * unsigned int plat_my_core_pos(void) * This Function uses the plat_calc_core_pos() * to get the index of the calling CPU. * ---------------------------------------------- */ func plat_my_core_pos mrs x0, mpidr_el1 and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 ret endfunc plat_my_core_pos /* * unsigned int plat_calc_core_pos(uint64_t mpidr) * helper function to calculate the core position. * With this function. */ func plat_calc_core_pos and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 ret endfunc plat_calc_core_pos /* --------------------------------------------- * function to get the entrypoint. * --------------------------------------------- */ func plat_get_my_entrypoint adrp x1, mailbox_base ldr x0, [x1, :lo12:mailbox_base] ret endfunc plat_get_my_entrypoint func imx_mailbox_init adrp x1, mailbox_base str x0, [x1, :lo12:mailbox_base] ret endfunc imx_mailbox_init func plat_secondary_cold_boot_setup b . endfunc plat_secondary_cold_boot_setup func plat_crash_console_init mov x0, #1 ret endfunc plat_crash_console_init func plat_crash_console_putc ret endfunc plat_crash_console_putc func plat_crash_console_flush mov x0, #0 ret endfunc plat_crash_console_flush func platform_mem_init ret endfunc platform_mem_init trusted-firmware-a-2.2/plat/imx/common/imx8_psci.c000066400000000000000000000027051355360272700222110ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include void __dead2 imx_system_off(void) { sc_pm_set_sys_power_mode(ipc_handle, SC_PM_PW_MODE_OFF); wfi(); ERROR("power off failed.\n"); panic(); } void __dead2 imx_system_reset(void) { sc_pm_reset(ipc_handle, SC_PM_RESET_TYPE_BOARD); wfi(); ERROR("system reset failed.\n"); panic(); } int imx_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { int pwr_lvl = psci_get_pstate_pwrlvl(power_state); int pwr_type = psci_get_pstate_type(power_state); int state_id = psci_get_pstate_id(power_state); if (pwr_lvl > PLAT_MAX_PWR_LVL) return PSCI_E_INVALID_PARAMS; if (pwr_type == PSTATE_TYPE_POWERDOWN) { req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE; if (!state_id) req_state->pwr_domain_state[MPIDR_AFFLVL1] = PLAT_MAX_RET_STATE; else req_state->pwr_domain_state[MPIDR_AFFLVL1] = PLAT_MAX_OFF_STATE; } return PSCI_E_SUCCESS; } void imx_get_sys_suspend_power_state(psci_power_state_t *req_state) { unsigned int i; /* CPU & cluster off, system in retention */ for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE; } trusted-firmware-a-2.2/plat/imx/common/imx8_topology.c000066400000000000000000000015541355360272700231300ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include const unsigned char imx_power_domain_tree_desc[] = { PWR_DOMAIN_AT_MAX_LVL, PLATFORM_CLUSTER_COUNT, PLATFORM_CLUSTER0_CORE_COUNT, PLATFORM_CLUSTER1_CORE_COUNT, }; const unsigned char *plat_get_power_domain_tree_desc(void) { return imx_power_domain_tree_desc; } int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; mpidr &= MPIDR_AFFINITY_MASK; if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) return -1; cluster_id = MPIDR_AFFLVL1_VAL(mpidr); cpu_id = MPIDR_AFFLVL0_VAL(mpidr); if (cluster_id > PLATFORM_CLUSTER_COUNT || cpu_id > PLATFORM_MAX_CPU_PER_CLUSTER) return -1; return (cpu_id + (cluster_id * 4)); } trusted-firmware-a-2.2/plat/imx/common/imx_aips.c000066400000000000000000000031751355360272700221210ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include static void imx_aips_set_default_access(struct aipstz_regs *aips_regs) { int i; uintptr_t addr; /* * See section 4.7.7.1 AIPSTZ_MPR field descriptions * i.MX 7Solo Applications Processor Reference Manual, Rev. 0.1, 08/2016 * 0111 -> * 0: Write Access from master not buffered * 1: Master is trusted for read access * 1: Master is trsuted for write access * 1: Access from master is not forced to user mode */ addr = (uintptr_t)&aips_regs->aipstz_mpr; mmio_write_32(addr, 0x77777777); /* * Helpfully the OPACR registers have the logical inversion of the above * See section 4.7.7.1 AIPSTZ_MPR field descriptions * i.MX 7Solo Applications Processor Reference Manual, Rev. 0.1, 08/2016 * 0000 -> * 0: Write Access to the peripheral is not buffered by AIPSTZ * 0: The peripheral does not require supervisor priv to access * 0: Master is trsuted for write access * 0: Access from master is not forced to user mode */ for (i = 0; i < AIPSTZ_OAPCR_COUNT; i++) { addr = (uintptr_t)&aips_regs->aipstz_opacr[i]; mmio_write_32(addr, 0x00000000); } } void imx_aips_init(void) { int i; struct aipstz_regs *aips_regs[] = { (struct aipstz_regs *)(AIPS1_BASE + AIPSTZ_CONFIG_OFFSET), (struct aipstz_regs *)(AIPS2_BASE + AIPSTZ_CONFIG_OFFSET), (struct aipstz_regs *)(AIPS3_BASE + AIPSTZ_CONFIG_OFFSET), }; for (i = 0; i < ARRAY_SIZE(aips_regs); i++) imx_aips_set_default_access(aips_regs[i]); } trusted-firmware-a-2.2/plat/imx/common/imx_caam.c000066400000000000000000000007641355360272700220670ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include void imx_caam_init(void) { struct caam_ctrl *caam = (struct caam_ctrl *)CAAM_AIPS_BASE; uint32_t reg; int i; for (i = 0; i < CAAM_NUM_JOB_RINGS; i++) { reg = mmio_read_32((uintptr_t)&caam->jr[i].jrmidr_ms); reg |= JROWN_NS | JROWN_MID; mmio_write_32((uintptr_t)&caam->jr[i].jrmidr_ms, reg); } } trusted-firmware-a-2.2/plat/imx/common/imx_clock.c000066400000000000000000000072441355360272700222610ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include void imx_clock_target_set(unsigned int id, uint32_t val) { struct ccm *ccm = ((struct ccm *)CCM_BASE); uintptr_t addr; if (id > CCM_ROOT_CTRL_NUM) return; addr = (uintptr_t)&ccm->ccm_root_ctrl[id].ccm_target_root; mmio_write_32(addr, val); } void imx_clock_target_clr(unsigned int id, uint32_t val) { struct ccm *ccm = ((struct ccm *)CCM_BASE); uintptr_t addr; if (id > CCM_ROOT_CTRL_NUM) return; addr = (uintptr_t)&ccm->ccm_root_ctrl[id].ccm_target_root_clr; mmio_write_32(addr, val); } void imx_clock_gate_enable(unsigned int id, bool enable) { struct ccm *ccm = ((struct ccm *)CCM_BASE); uintptr_t addr; if (id > CCM_CLK_GATE_CTRL_NUM) return; /* TODO: add support for more than DOMAIN0 clocks */ if (enable) addr = (uintptr_t)&ccm->ccm_clk_gate_ctrl[id].ccm_ccgr_set; else addr = (uintptr_t)&ccm->ccm_clk_gate_ctrl[id].ccm_ccgr_clr; mmio_write_32(addr, CCM_CCGR_SETTING0_DOM_CLK_ALWAYS); } void imx_clock_enable_uart(unsigned int uart_id, uint32_t uart_clk_en_bits) { unsigned int ccm_trgt_id = CCM_TRT_ID_UART1_CLK_ROOT + uart_id; unsigned int ccm_ccgr_id = CCM_CCGR_ID_UART1 + uart_id; /* Check for error */ if (uart_id > MXC_MAX_UART_NUM) return; /* Set target register values */ imx_clock_target_set(ccm_trgt_id, uart_clk_en_bits); /* Enable the clock gate */ imx_clock_gate_enable(ccm_ccgr_id, true); } void imx_clock_disable_uart(unsigned int uart_id) { unsigned int ccm_trgt_id = CCM_TRT_ID_UART1_CLK_ROOT + uart_id; unsigned int ccm_ccgr_id = CCM_CCGR_ID_UART1 + uart_id; /* Check for error */ if (uart_id > MXC_MAX_UART_NUM) return; /* Disable the clock gate */ imx_clock_gate_enable(ccm_ccgr_id, false); /* Clear the target */ imx_clock_target_clr(ccm_trgt_id, 0xFFFFFFFF); } void imx_clock_enable_usdhc(unsigned int usdhc_id, uint32_t usdhc_clk_en_bits) { unsigned int ccm_trgt_id = CCM_TRT_ID_USDHC1_CLK_ROOT + usdhc_id; unsigned int ccm_ccgr_id = CCM_CCGR_ID_USBHDC1 + usdhc_id; /* Check for error */ if (usdhc_id > MXC_MAX_USDHC_NUM) return; /* Set target register values */ imx_clock_target_set(ccm_trgt_id, usdhc_clk_en_bits); /* Enable the clock gate */ imx_clock_gate_enable(ccm_ccgr_id, true); } void imx_clock_enable_wdog(unsigned int wdog_id) { unsigned int ccm_ccgr_id = CCM_CCGR_ID_WDOG1 + wdog_id; /* Check for error */ if (wdog_id > MXC_MAX_WDOG_NUM) return; /* Enable the clock gate */ imx_clock_gate_enable(ccm_ccgr_id, true); } void imx_clock_disable_wdog(unsigned int wdog_id) { unsigned int ccm_trgt_id = CCM_TRT_ID_WDOG_CLK_ROOT; unsigned int ccm_ccgr_id = CCM_CCGR_ID_WDOG1 + wdog_id; /* Check for error */ if (wdog_id > MXC_MAX_WDOG_NUM) return; /* Disable the clock gate */ imx_clock_gate_enable(ccm_ccgr_id, false); /* Clear the target */ imx_clock_target_clr(ccm_trgt_id, 0xFFFFFFFF); } void imx_clock_set_wdog_clk_root_bits(uint32_t wdog_clk_root_en_bits) { /* Enable the common clock root just once */ imx_clock_target_set(CCM_TRT_ID_WDOG_CLK_ROOT, wdog_clk_root_en_bits); } void imx_clock_enable_usb(unsigned int ccm_ccgr_usb_id) { /* Enable the clock gate */ imx_clock_gate_enable(ccm_ccgr_usb_id, true); } void imx_clock_disable_usb(unsigned int ccm_ccgr_usb_id) { /* Disable the clock gate */ imx_clock_gate_enable(ccm_ccgr_usb_id, false); } void imx_clock_set_usb_clk_root_bits(uint32_t usb_clk_root_en_bits) { /* Enable the common clock root just once */ imx_clock_target_set(CCM_TRT_ID_USB_HSIC_CLK_ROOT, usb_clk_root_en_bits); } trusted-firmware-a-2.2/plat/imx/common/imx_csu.c000066400000000000000000000006001355360272700217450ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include void imx_csu_init(void) { int i; uintptr_t *csl_reg = (uintptr_t *)CSU_BASE; for (i = 0; i < MXC_MAX_CSU_REGS; i++, csl_reg++) mmio_write_32((uintptr_t)csl_reg, CSU_CSL_OPEN_ACCESS); } trusted-firmware-a-2.2/plat/imx/common/imx_io_mux.c000066400000000000000000000011131355360272700224530ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include void imx_io_muxc_set_pad_alt_function(uint32_t pad_mux_offset, uint32_t alt_function) { uintptr_t addr = (uintptr_t)(MXC_IO_MUXC_BASE + pad_mux_offset); mmio_write_32(addr, alt_function); } void imx_io_muxc_set_pad_features(uint32_t pad_feature_offset, uint32_t pad_features) { uintptr_t addr = (uintptr_t)(MXC_IO_MUXC_BASE + pad_feature_offset); mmio_write_32(addr, pad_features); } trusted-firmware-a-2.2/plat/imx/common/imx_sip_handler.c000066400000000000000000000066661355360272700234650ustar00rootroot00000000000000/* * Copyright 2019 NXP * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #if defined(PLAT_imx8qm) || defined(PLAT_imx8qx) #ifdef PLAT_imx8qm const static int ap_cluster_index[PLATFORM_CLUSTER_COUNT] = { SC_R_A53, SC_R_A72, }; #endif static int imx_srtc_set_time(uint32_t year_mon, unsigned long day_hour, unsigned long min_sec) { return sc_timer_set_rtc_time(ipc_handle, year_mon >> 16, year_mon & 0xffff, day_hour >> 16, day_hour & 0xffff, min_sec >> 16, min_sec & 0xffff); } int imx_srtc_handler(uint32_t smc_fid, void *handle, u_register_t x1, u_register_t x2, u_register_t x3, u_register_t x4) { int ret; switch (x1) { case IMX_SIP_SRTC_SET_TIME: ret = imx_srtc_set_time(x2, x3, x4); break; default: ret = SMC_UNK; } SMC_RET1(handle, ret); } static void imx_cpufreq_set_target(uint32_t cluster_id, unsigned long freq) { sc_pm_clock_rate_t rate = (sc_pm_clock_rate_t)freq; #ifdef PLAT_imx8qm sc_pm_set_clock_rate(ipc_handle, ap_cluster_index[cluster_id], SC_PM_CLK_CPU, &rate); #endif #ifdef PLAT_imx8qx sc_pm_set_clock_rate(ipc_handle, SC_R_A35, SC_PM_CLK_CPU, &rate); #endif } int imx_cpufreq_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3) { switch (x1) { case IMX_SIP_SET_CPUFREQ: imx_cpufreq_set_target(x2, x3); break; default: return SMC_UNK; } return 0; } static bool wakeup_src_irqsteer; bool imx_is_wakeup_src_irqsteer(void) { return wakeup_src_irqsteer; } int imx_wakeup_src_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3) { switch (x1) { case IMX_SIP_WAKEUP_SRC_IRQSTEER: wakeup_src_irqsteer = true; break; case IMX_SIP_WAKEUP_SRC_SCU: wakeup_src_irqsteer = false; break; default: return SMC_UNK; } return SMC_OK; } int imx_otp_handler(uint32_t smc_fid, void *handle, u_register_t x1, u_register_t x2) { int ret; uint32_t fuse; switch (smc_fid) { case IMX_SIP_OTP_READ: ret = sc_misc_otp_fuse_read(ipc_handle, x1, &fuse); SMC_RET2(handle, ret, fuse); break; case IMX_SIP_OTP_WRITE: ret = sc_misc_otp_fuse_write(ipc_handle, x1, x2); SMC_RET1(handle, ret); break; default: ret = SMC_UNK; SMC_RET1(handle, ret); break; } return ret; } int imx_misc_set_temp_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3, u_register_t x4) { return sc_misc_set_temp(ipc_handle, x1, x2, x3, x4); } #endif /* defined(PLAT_imx8qm) || defined(PLAT_imx8qx) */ static uint64_t imx_get_commit_hash(u_register_t x2, u_register_t x3, u_register_t x4) { /* Parse the version_string */ char *parse = (char *)version_string; uint64_t hash = 0; do { parse = strchr(parse, '-'); if (parse) { parse += 1; if (*(parse) == 'g') { /* Default is 7 hexadecimal digits */ memcpy((void *)&hash, (void *)(parse + 1), 7); break; } } } while (parse != NULL); return hash; } uint64_t imx_buildinfo_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3, u_register_t x4) { uint64_t ret; switch (x1) { case IMX_SIP_BUILDINFO_GET_COMMITHASH: ret = imx_get_commit_hash(x2, x3, x4); break; default: return SMC_UNK; } return ret; } trusted-firmware-a-2.2/plat/imx/common/imx_sip_svc.c000066400000000000000000000031051355360272700226240ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include static int32_t imx_sip_setup(void) { return 0; } static uintptr_t imx_sip_handler(unsigned int 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) { switch (smc_fid) { #if defined(PLAT_imx8mq) case IMX_SIP_GET_SOC_INFO: SMC_RET1(handle, imx_soc_info_handler(smc_fid, x1, x2, x3)); break; #endif #if (defined(PLAT_imx8qm) || defined(PLAT_imx8qx)) case IMX_SIP_SRTC: return imx_srtc_handler(smc_fid, handle, x1, x2, x3, x4); case IMX_SIP_CPUFREQ: SMC_RET1(handle, imx_cpufreq_handler(smc_fid, x1, x2, x3)); break; case IMX_SIP_WAKEUP_SRC: SMC_RET1(handle, imx_wakeup_src_handler(smc_fid, x1, x2, x3)); case IMX_SIP_OTP_READ: case IMX_SIP_OTP_WRITE: return imx_otp_handler(smc_fid, handle, x1, x2); case IMX_SIP_MISC_SET_TEMP: SMC_RET1(handle, imx_misc_set_temp_handler(smc_fid, x1, x2, x3, x4)); #endif case IMX_SIP_BUILDINFO: SMC_RET1(handle, imx_buildinfo_handler(smc_fid, x1, x2, x3, x4)); default: WARN("Unimplemented i.MX SiP Service Call: 0x%x\n", smc_fid); SMC_RET1(handle, SMC_UNK); break; } } /* Define a runtime service descriptor for fast SMC calls */ DECLARE_RT_SVC( imx_sip_svc, OEN_SIP_START, OEN_SIP_END, SMC_TYPE_FAST, imx_sip_setup, imx_sip_handler ); trusted-firmware-a-2.2/plat/imx/common/imx_snvs.c000066400000000000000000000006401355360272700221500ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include void imx_snvs_init(void) { struct snvs *snvs = (struct snvs *)SNVS_BASE; uintptr_t addr; uint32_t val; addr = (uintptr_t)&snvs->hpcomr; val = mmio_read_32(addr); val |= HPCOMR_NPSWA_EN; mmio_write_32(addr, val); } trusted-firmware-a-2.2/plat/imx/common/imx_uart_console.S000066400000000000000000000032331355360272700236350ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "imx_uart.h" #define URXD 0x0 /* Receiver Register */ #define UTXD 0x40 /* Transmitter Register */ #define UTS 0xb4 /* UART Test Register (mx31) */ #define URXD_RX_DATA (0xFF) .globl console_imx_uart_register .globl console_imx_uart_init .globl console_imx_uart_putc .globl console_imx_uart_getc .globl console_imx_uart_flush func console_imx_uart_register mov x7, x30 mov x6, x3 cbz x6, register_fail str x0, [x6, #CONSOLE_T_DRVDATA] bl console_imx_uart_init cbz x0, register_fail mov x0, x6 mov x30, x7 finish_console_register imx_uart putc=1, getc=1, flush=1 register_fail: ret x7 endfunc console_imx_uart_register func console_imx_uart_init mov w0, #1 ret endfunc console_imx_uart_init func console_imx_uart_putc ldr x1, [x1, #CONSOLE_T_DRVDATA] cbz x1, putc_error /* Prepare '\r' to '\n' */ cmp w0, #0xA b.ne 2f 1: /* Check if the transmit FIFO is full */ ldr w2, [x1, #UTS] tbz w2, #6, 1b mov w2, #0xD str w2, [x1, #UTXD] 2: /* Check if the transmit FIFO is full */ ldr w2, [x1, #UTS] tbz w2, #6, 2b str w0, [x1, #UTXD] ret putc_error: mov w0, #-1 ret endfunc console_imx_uart_putc func console_imx_uart_getc ldr x0, [x0, #CONSOLE_T_DRVDATA] cbz x0, getc_error 1: ldr w1, [x0, #UTS] tbnz w1, #5, 1b ldr w1, [x0, #URXD] and w0, w1, #URXD_RX_DATA ret getc_error: mov w0, #-1 ret endfunc console_imx_uart_getc func console_imx_uart_flush mov x0, #0 ret endfunc console_imx_uart_flush trusted-firmware-a-2.2/plat/imx/common/imx_wdog.c000066400000000000000000000010001355360272700221060ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include static void imx_wdog_power_down(unsigned long base) { struct wdog_regs *wdog = (struct wdog_regs *)base; mmio_write_16((uintptr_t)&wdog->wmcr, 0); } void imx_wdog_init(void) { imx_wdog_power_down(WDOG1_BASE); imx_wdog_power_down(WDOG2_BASE); imx_wdog_power_down(WDOG3_BASE); imx_wdog_power_down(WDOG4_BASE); } trusted-firmware-a-2.2/plat/imx/common/include/000077500000000000000000000000001355360272700215615ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/include/imx8_iomux.h000066400000000000000000000014761355360272700240500ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX8_IOMUX_H #define IMX8_IOMUX_H #define PADRING_IFMUX_EN_SHIFT 31 #define PADRING_IFMUX_EN_MASK (1 << PADRING_IFMUX_EN_SHIFT) #define PADRING_GP_EN_SHIFT 30 #define PADRING_GP_EN_MASK (1 << PADRING_GP_EN_SHIFT) #define PADRING_IFMUX_SHIFT 27 #define PADRING_IFMUX_MASK (0x7 << PADRING_IFMUX_SHIFT) #define PADRING_CONFIG_SHIFT 25 #define PADRING_CONFIG_MASK (0x3 << PADRING_CONFIG_SHIFT) #define PADRING_LPCONFIG_SHIFT 23 #define PADRING_LPCONFIG_MASK (0x3 << PADRING_LPCONFIG_SHIFT) #define PADRING_PULL_SHIFT 5 #define PADRING_PULL_MASK (0x3 << PADRING_PULL_SHIFT) #define PADRING_DSE_SHIFT 0 #define PADRING_DSE_MASK (0x7 << PADRING_DSE_SHIFT) #endif /* IMX8_IOMUX_H */ trusted-firmware-a-2.2/plat/imx/common/include/imx8_lpuart.h000066400000000000000000000032431355360272700242100ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX8_LPUART_H #define IMX8_LPUART_H #include #define VERID 0x0 #define PARAM 0x4 #define GLOBAL 0x8 #define PINCFG 0xC #define BAUD 0x10 #define STAT 0x14 #define CTRL 0x18 #define DATA 0x1C #define MATCH 0x20 #define MODIR 0x24 #define FIFO 0x28 #define WATER 0x2c #define US1_TDRE (1 << 23) #define US1_RDRF (1 << 21) #define CTRL_TE (1 << 19) #define CTRL_RE (1 << 18) #define FIFO_TXFE 0x80 #define FIFO_RXFE 0x40 #define WATER_TXWATER_OFF 1 #define WATER_RXWATER_OFF 16 #define LPUART_CTRL_PT_MASK 0x1 #define LPUART_CTRL_PE_MASK 0x2 #define LPUART_CTRL_M_MASK 0x10 #define LPUART_BAUD_OSR_MASK (0x1F000000U) #define LPUART_BAUD_OSR_SHIFT (24U) #define LPUART_BAUD_OSR(x) (((uint32_t)(((uint32_t)(x)) << LPUART_BAUD_OSR_SHIFT)) & LPUART_BAUD_OSR_MASK) #define LPUART_BAUD_SBR_MASK (0x1FFFU) #define LPUART_BAUD_SBR_SHIFT (0U) #define LPUART_BAUD_SBR(x) (((uint32_t)(((uint32_t)(x)) << LPUART_BAUD_SBR_SHIFT)) & LPUART_BAUD_SBR_MASK) #define LPUART_BAUD_SBNS_MASK (0x2000U) #define LPUART_BAUD_BOTHEDGE_MASK (0x20000U) #define LPUART_BAUD_M10_MASK (0x20000000U) #ifndef __ASSEMBLER__ #include typedef struct { console_t console; uintptr_t base; } console_lpuart_t; int console_lpuart_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, console_lpuart_t *console); #endif /*__ASSEMBLER__*/ #endif /* IMX8_LPUART_H */ trusted-firmware-a-2.2/plat/imx/common/include/imx8qm_pads.h000066400000000000000000000654141355360272700241760ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /*! * Header file used to configure SoC pad list. */ #ifndef IMX8QM_PADS_H #define IMX8QM_PADS_H /* Includes */ /* Defines */ /*! * @name Pad Definitions */ /*@{*/ #define SC_P_SIM0_CLK 0 /* DMA.SIM0.CLK, LSIO.GPIO0.IO00 */ #define SC_P_SIM0_RST 1 /* DMA.SIM0.RST, LSIO.GPIO0.IO01 */ #define SC_P_SIM0_IO 2 /* DMA.SIM0.IO, LSIO.GPIO0.IO02 */ #define SC_P_SIM0_PD 3 /* DMA.SIM0.PD, DMA.I2C3.SCL, LSIO.GPIO0.IO03 */ #define SC_P_SIM0_POWER_EN 4 /* DMA.SIM0.POWER_EN, DMA.I2C3.SDA, LSIO.GPIO0.IO04 */ #define SC_P_SIM0_GPIO0_00 5 /* DMA.SIM0.POWER_EN, LSIO.GPIO0.IO05 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_SIM 6 /* */ #define SC_P_M40_I2C0_SCL 7 /* M40.I2C0.SCL, M40.UART0.RX, M40.GPIO0.IO02, LSIO.GPIO0.IO06 */ #define SC_P_M40_I2C0_SDA 8 /* M40.I2C0.SDA, M40.UART0.TX, M40.GPIO0.IO03, LSIO.GPIO0.IO07 */ #define SC_P_M40_GPIO0_00 9 /* M40.GPIO0.IO00, M40.TPM0.CH0, DMA.UART4.RX, LSIO.GPIO0.IO08 */ #define SC_P_M40_GPIO0_01 10 /* M40.GPIO0.IO01, M40.TPM0.CH1, DMA.UART4.TX, LSIO.GPIO0.IO09 */ #define SC_P_M41_I2C0_SCL 11 /* M41.I2C0.SCL, M41.UART0.RX, M41.GPIO0.IO02, LSIO.GPIO0.IO10 */ #define SC_P_M41_I2C0_SDA 12 /* M41.I2C0.SDA, M41.UART0.TX, M41.GPIO0.IO03, LSIO.GPIO0.IO11 */ #define SC_P_M41_GPIO0_00 13 /* M41.GPIO0.IO00, M41.TPM0.CH0, DMA.UART3.RX, LSIO.GPIO0.IO12 */ #define SC_P_M41_GPIO0_01 14 /* M41.GPIO0.IO01, M41.TPM0.CH1, DMA.UART3.TX, LSIO.GPIO0.IO13 */ #define SC_P_GPT0_CLK 15 /* LSIO.GPT0.CLK, DMA.I2C1.SCL, LSIO.KPP0.COL4, LSIO.GPIO0.IO14 */ #define SC_P_GPT0_CAPTURE 16 /* LSIO.GPT0.CAPTURE, DMA.I2C1.SDA, LSIO.KPP0.COL5, LSIO.GPIO0.IO15 */ #define SC_P_GPT0_COMPARE 17 /* LSIO.GPT0.COMPARE, LSIO.PWM3.OUT, LSIO.KPP0.COL6, LSIO.GPIO0.IO16 */ #define SC_P_GPT1_CLK 18 /* LSIO.GPT1.CLK, DMA.I2C2.SCL, LSIO.KPP0.COL7, LSIO.GPIO0.IO17 */ #define SC_P_GPT1_CAPTURE 19 /* LSIO.GPT1.CAPTURE, DMA.I2C2.SDA, LSIO.KPP0.ROW4, LSIO.GPIO0.IO18 */ #define SC_P_GPT1_COMPARE 20 /* LSIO.GPT1.COMPARE, LSIO.PWM2.OUT, LSIO.KPP0.ROW5, LSIO.GPIO0.IO19 */ #define SC_P_UART0_RX 21 /* DMA.UART0.RX, SCU.UART0.RX, LSIO.GPIO0.IO20 */ #define SC_P_UART0_TX 22 /* DMA.UART0.TX, SCU.UART0.TX, LSIO.GPIO0.IO21 */ #define SC_P_UART0_RTS_B 23 /* DMA.UART0.RTS_B, LSIO.PWM0.OUT, DMA.UART2.RX, LSIO.GPIO0.IO22 */ #define SC_P_UART0_CTS_B 24 /* DMA.UART0.CTS_B, LSIO.PWM1.OUT, DMA.UART2.TX, LSIO.GPIO0.IO23 */ #define SC_P_UART1_TX 25 /* DMA.UART1.TX, DMA.SPI3.SCK, LSIO.GPIO0.IO24 */ #define SC_P_UART1_RX 26 /* DMA.UART1.RX, DMA.SPI3.SDO, LSIO.GPIO0.IO25 */ #define SC_P_UART1_RTS_B 27 /* DMA.UART1.RTS_B, DMA.SPI3.SDI, DMA.UART1.CTS_B, LSIO.GPIO0.IO26 */ #define SC_P_UART1_CTS_B 28 /* DMA.UART1.CTS_B, DMA.SPI3.CS0, DMA.UART1.RTS_B, LSIO.GPIO0.IO27 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOLH 29 /* */ #define SC_P_SCU_PMIC_MEMC_ON 30 /* SCU.GPIO0.IOXX_PMIC_MEMC_ON */ #define SC_P_SCU_WDOG_OUT 31 /* SCU.WDOG0.WDOG_OUT */ #define SC_P_PMIC_I2C_SDA 32 /* SCU.PMIC_I2C.SDA */ #define SC_P_PMIC_I2C_SCL 33 /* SCU.PMIC_I2C.SCL */ #define SC_P_PMIC_EARLY_WARNING 34 /* SCU.PMIC_EARLY_WARNING */ #define SC_P_PMIC_INT_B 35 /* SCU.DSC.PMIC_INT_B */ #define SC_P_SCU_GPIO0_00 36 /* SCU.GPIO0.IO00, SCU.UART0.RX, LSIO.GPIO0.IO28 */ #define SC_P_SCU_GPIO0_01 37 /* SCU.GPIO0.IO01, SCU.UART0.TX, LSIO.GPIO0.IO29 */ #define SC_P_SCU_GPIO0_02 38 /* SCU.GPIO0.IO02, SCU.GPIO0.IOXX_PMIC_GPU0_ON, LSIO.GPIO0.IO30 */ #define SC_P_SCU_GPIO0_03 39 /* SCU.GPIO0.IO03, SCU.GPIO0.IOXX_PMIC_GPU1_ON, LSIO.GPIO0.IO31 */ #define SC_P_SCU_GPIO0_04 40 /* SCU.GPIO0.IO04, SCU.GPIO0.IOXX_PMIC_A72_ON, LSIO.GPIO1.IO00 */ #define SC_P_SCU_GPIO0_05 41 /* SCU.GPIO0.IO05, SCU.GPIO0.IOXX_PMIC_A53_ON, LSIO.GPIO1.IO01 */ #define SC_P_SCU_GPIO0_06 42 /* SCU.GPIO0.IO06, SCU.TPM0.CH0, LSIO.GPIO1.IO02 */ #define SC_P_SCU_GPIO0_07 43 /* SCU.GPIO0.IO07, SCU.TPM0.CH1, SCU.DSC.RTC_CLOCK_OUTPUT_32K, LSIO.GPIO1.IO03 */ #define SC_P_SCU_BOOT_MODE0 44 /* SCU.DSC.BOOT_MODE0 */ #define SC_P_SCU_BOOT_MODE1 45 /* SCU.DSC.BOOT_MODE1 */ #define SC_P_SCU_BOOT_MODE2 46 /* SCU.DSC.BOOT_MODE2 */ #define SC_P_SCU_BOOT_MODE3 47 /* SCU.DSC.BOOT_MODE3 */ #define SC_P_SCU_BOOT_MODE4 48 /* SCU.DSC.BOOT_MODE4, SCU.PMIC_I2C.SCL */ #define SC_P_SCU_BOOT_MODE5 49 /* SCU.DSC.BOOT_MODE5, SCU.PMIC_I2C.SDA */ #define SC_P_LVDS0_GPIO00 50 /* LVDS0.GPIO0.IO00, LVDS0.PWM0.OUT, LSIO.GPIO1.IO04 */ #define SC_P_LVDS0_GPIO01 51 /* LVDS0.GPIO0.IO01, LSIO.GPIO1.IO05 */ #define SC_P_LVDS0_I2C0_SCL 52 /* LVDS0.I2C0.SCL, LVDS0.GPIO0.IO02, LSIO.GPIO1.IO06 */ #define SC_P_LVDS0_I2C0_SDA 53 /* LVDS0.I2C0.SDA, LVDS0.GPIO0.IO03, LSIO.GPIO1.IO07 */ #define SC_P_LVDS0_I2C1_SCL 54 /* LVDS0.I2C1.SCL, DMA.UART2.TX, LSIO.GPIO1.IO08 */ #define SC_P_LVDS0_I2C1_SDA 55 /* LVDS0.I2C1.SDA, DMA.UART2.RX, LSIO.GPIO1.IO09 */ #define SC_P_LVDS1_GPIO00 56 /* LVDS1.GPIO0.IO00, LVDS1.PWM0.OUT, LSIO.GPIO1.IO10 */ #define SC_P_LVDS1_GPIO01 57 /* LVDS1.GPIO0.IO01, LSIO.GPIO1.IO11 */ #define SC_P_LVDS1_I2C0_SCL 58 /* LVDS1.I2C0.SCL, LVDS1.GPIO0.IO02, LSIO.GPIO1.IO12 */ #define SC_P_LVDS1_I2C0_SDA 59 /* LVDS1.I2C0.SDA, LVDS1.GPIO0.IO03, LSIO.GPIO1.IO13 */ #define SC_P_LVDS1_I2C1_SCL 60 /* LVDS1.I2C1.SCL, DMA.UART3.TX, LSIO.GPIO1.IO14 */ #define SC_P_LVDS1_I2C1_SDA 61 /* LVDS1.I2C1.SDA, DMA.UART3.RX, LSIO.GPIO1.IO15 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_LVDSGPIO 62 /* */ #define SC_P_MIPI_DSI0_I2C0_SCL 63 /* MIPI_DSI0.I2C0.SCL, LSIO.GPIO1.IO16 */ #define SC_P_MIPI_DSI0_I2C0_SDA 64 /* MIPI_DSI0.I2C0.SDA, LSIO.GPIO1.IO17 */ #define SC_P_MIPI_DSI0_GPIO0_00 65 /* MIPI_DSI0.GPIO0.IO00, MIPI_DSI0.PWM0.OUT, LSIO.GPIO1.IO18 */ #define SC_P_MIPI_DSI0_GPIO0_01 66 /* MIPI_DSI0.GPIO0.IO01, LSIO.GPIO1.IO19 */ #define SC_P_MIPI_DSI1_I2C0_SCL 67 /* MIPI_DSI1.I2C0.SCL, LSIO.GPIO1.IO20 */ #define SC_P_MIPI_DSI1_I2C0_SDA 68 /* MIPI_DSI1.I2C0.SDA, LSIO.GPIO1.IO21 */ #define SC_P_MIPI_DSI1_GPIO0_00 69 /* MIPI_DSI1.GPIO0.IO00, MIPI_DSI1.PWM0.OUT, LSIO.GPIO1.IO22 */ #define SC_P_MIPI_DSI1_GPIO0_01 70 /* MIPI_DSI1.GPIO0.IO01, LSIO.GPIO1.IO23 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_MIPIDSIGPIO 71 /* */ #define SC_P_MIPI_CSI0_MCLK_OUT 72 /* MIPI_CSI0.ACM.MCLK_OUT, LSIO.GPIO1.IO24 */ #define SC_P_MIPI_CSI0_I2C0_SCL 73 /* MIPI_CSI0.I2C0.SCL, LSIO.GPIO1.IO25 */ #define SC_P_MIPI_CSI0_I2C0_SDA 74 /* MIPI_CSI0.I2C0.SDA, LSIO.GPIO1.IO26 */ #define SC_P_MIPI_CSI0_GPIO0_00 75 /* MIPI_CSI0.GPIO0.IO00, DMA.I2C0.SCL, MIPI_CSI1.I2C0.SCL, LSIO.GPIO1.IO27 */ #define SC_P_MIPI_CSI0_GPIO0_01 76 /* MIPI_CSI0.GPIO0.IO01, DMA.I2C0.SDA, MIPI_CSI1.I2C0.SDA, LSIO.GPIO1.IO28 */ #define SC_P_MIPI_CSI1_MCLK_OUT 77 /* MIPI_CSI1.ACM.MCLK_OUT, LSIO.GPIO1.IO29 */ #define SC_P_MIPI_CSI1_GPIO0_00 78 /* MIPI_CSI1.GPIO0.IO00, DMA.UART4.RX, LSIO.GPIO1.IO30 */ #define SC_P_MIPI_CSI1_GPIO0_01 79 /* MIPI_CSI1.GPIO0.IO01, DMA.UART4.TX, LSIO.GPIO1.IO31 */ #define SC_P_MIPI_CSI1_I2C0_SCL 80 /* MIPI_CSI1.I2C0.SCL, LSIO.GPIO2.IO00 */ #define SC_P_MIPI_CSI1_I2C0_SDA 81 /* MIPI_CSI1.I2C0.SDA, LSIO.GPIO2.IO01 */ #define SC_P_HDMI_TX0_TS_SCL 82 /* HDMI_TX0.I2C0.SCL, DMA.I2C0.SCL, LSIO.GPIO2.IO02 */ #define SC_P_HDMI_TX0_TS_SDA 83 /* HDMI_TX0.I2C0.SDA, DMA.I2C0.SDA, LSIO.GPIO2.IO03 */ #define SC_P_COMP_CTL_GPIO_3V3_HDMIGPIO 84 /* */ #define SC_P_ESAI1_FSR 85 /* AUD.ESAI1.FSR, LSIO.GPIO2.IO04 */ #define SC_P_ESAI1_FST 86 /* AUD.ESAI1.FST, AUD.SPDIF0.EXT_CLK, LSIO.GPIO2.IO05 */ #define SC_P_ESAI1_SCKR 87 /* AUD.ESAI1.SCKR, LSIO.GPIO2.IO06 */ #define SC_P_ESAI1_SCKT 88 /* AUD.ESAI1.SCKT, AUD.SAI2.RXC, AUD.SPDIF0.EXT_CLK, LSIO.GPIO2.IO07 */ #define SC_P_ESAI1_TX0 89 /* AUD.ESAI1.TX0, AUD.SAI2.RXD, AUD.SPDIF0.RX, LSIO.GPIO2.IO08 */ #define SC_P_ESAI1_TX1 90 /* AUD.ESAI1.TX1, AUD.SAI2.RXFS, AUD.SPDIF0.TX, LSIO.GPIO2.IO09 */ #define SC_P_ESAI1_TX2_RX3 91 /* AUD.ESAI1.TX2_RX3, AUD.SPDIF0.RX, LSIO.GPIO2.IO10 */ #define SC_P_ESAI1_TX3_RX2 92 /* AUD.ESAI1.TX3_RX2, AUD.SPDIF0.TX, LSIO.GPIO2.IO11 */ #define SC_P_ESAI1_TX4_RX1 93 /* AUD.ESAI1.TX4_RX1, LSIO.GPIO2.IO12 */ #define SC_P_ESAI1_TX5_RX0 94 /* AUD.ESAI1.TX5_RX0, LSIO.GPIO2.IO13 */ #define SC_P_SPDIF0_RX 95 /* AUD.SPDIF0.RX, AUD.MQS.R, AUD.ACM.MCLK_IN1, LSIO.GPIO2.IO14 */ #define SC_P_SPDIF0_TX 96 /* AUD.SPDIF0.TX, AUD.MQS.L, AUD.ACM.MCLK_OUT1, LSIO.GPIO2.IO15 */ #define SC_P_SPDIF0_EXT_CLK 97 /* AUD.SPDIF0.EXT_CLK, DMA.DMA0.REQ_IN0, LSIO.GPIO2.IO16 */ #define SC_P_SPI3_SCK 98 /* DMA.SPI3.SCK, LSIO.GPIO2.IO17 */ #define SC_P_SPI3_SDO 99 /* DMA.SPI3.SDO, DMA.FTM.CH0, LSIO.GPIO2.IO18 */ #define SC_P_SPI3_SDI 100 /* DMA.SPI3.SDI, DMA.FTM.CH1, LSIO.GPIO2.IO19 */ #define SC_P_SPI3_CS0 101 /* DMA.SPI3.CS0, DMA.FTM.CH2, LSIO.GPIO2.IO20 */ #define SC_P_SPI3_CS1 102 /* DMA.SPI3.CS1, LSIO.GPIO2.IO21 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHB 103 /* */ #define SC_P_ESAI0_FSR 104 /* AUD.ESAI0.FSR, LSIO.GPIO2.IO22 */ #define SC_P_ESAI0_FST 105 /* AUD.ESAI0.FST, LSIO.GPIO2.IO23 */ #define SC_P_ESAI0_SCKR 106 /* AUD.ESAI0.SCKR, LSIO.GPIO2.IO24 */ #define SC_P_ESAI0_SCKT 107 /* AUD.ESAI0.SCKT, LSIO.GPIO2.IO25 */ #define SC_P_ESAI0_TX0 108 /* AUD.ESAI0.TX0, LSIO.GPIO2.IO26 */ #define SC_P_ESAI0_TX1 109 /* AUD.ESAI0.TX1, LSIO.GPIO2.IO27 */ #define SC_P_ESAI0_TX2_RX3 110 /* AUD.ESAI0.TX2_RX3, LSIO.GPIO2.IO28 */ #define SC_P_ESAI0_TX3_RX2 111 /* AUD.ESAI0.TX3_RX2, LSIO.GPIO2.IO29 */ #define SC_P_ESAI0_TX4_RX1 112 /* AUD.ESAI0.TX4_RX1, LSIO.GPIO2.IO30 */ #define SC_P_ESAI0_TX5_RX0 113 /* AUD.ESAI0.TX5_RX0, LSIO.GPIO2.IO31 */ #define SC_P_MCLK_IN0 114 /* AUD.ACM.MCLK_IN0, AUD.ESAI0.RX_HF_CLK, AUD.ESAI1.RX_HF_CLK, LSIO.GPIO3.IO00 */ #define SC_P_MCLK_OUT0 115 /* AUD.ACM.MCLK_OUT0, AUD.ESAI0.TX_HF_CLK, AUD.ESAI1.TX_HF_CLK, LSIO.GPIO3.IO01 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHC 116 /* */ #define SC_P_SPI0_SCK 117 /* DMA.SPI0.SCK, AUD.SAI0.RXC, LSIO.GPIO3.IO02 */ #define SC_P_SPI0_SDO 118 /* DMA.SPI0.SDO, AUD.SAI0.TXD, LSIO.GPIO3.IO03 */ #define SC_P_SPI0_SDI 119 /* DMA.SPI0.SDI, AUD.SAI0.RXD, LSIO.GPIO3.IO04 */ #define SC_P_SPI0_CS0 120 /* DMA.SPI0.CS0, AUD.SAI0.RXFS, LSIO.GPIO3.IO05 */ #define SC_P_SPI0_CS1 121 /* DMA.SPI0.CS1, AUD.SAI0.TXC, LSIO.GPIO3.IO06 */ #define SC_P_SPI2_SCK 122 /* DMA.SPI2.SCK, LSIO.GPIO3.IO07 */ #define SC_P_SPI2_SDO 123 /* DMA.SPI2.SDO, LSIO.GPIO3.IO08 */ #define SC_P_SPI2_SDI 124 /* DMA.SPI2.SDI, LSIO.GPIO3.IO09 */ #define SC_P_SPI2_CS0 125 /* DMA.SPI2.CS0, LSIO.GPIO3.IO10 */ #define SC_P_SPI2_CS1 126 /* DMA.SPI2.CS1, AUD.SAI0.TXFS, LSIO.GPIO3.IO11 */ #define SC_P_SAI1_RXC 127 /* AUD.SAI1.RXC, AUD.SAI0.TXD, LSIO.GPIO3.IO12 */ #define SC_P_SAI1_RXD 128 /* AUD.SAI1.RXD, AUD.SAI0.TXFS, LSIO.GPIO3.IO13 */ #define SC_P_SAI1_RXFS 129 /* AUD.SAI1.RXFS, AUD.SAI0.RXD, LSIO.GPIO3.IO14 */ #define SC_P_SAI1_TXC 130 /* AUD.SAI1.TXC, AUD.SAI0.TXC, LSIO.GPIO3.IO15 */ #define SC_P_SAI1_TXD 131 /* AUD.SAI1.TXD, AUD.SAI1.RXC, LSIO.GPIO3.IO16 */ #define SC_P_SAI1_TXFS 132 /* AUD.SAI1.TXFS, AUD.SAI1.RXFS, LSIO.GPIO3.IO17 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHT 133 /* */ #define SC_P_ADC_IN7 134 /* DMA.ADC1.IN3, DMA.SPI1.CS1, LSIO.KPP0.ROW3, LSIO.GPIO3.IO25 */ #define SC_P_ADC_IN6 135 /* DMA.ADC1.IN2, DMA.SPI1.CS0, LSIO.KPP0.ROW2, LSIO.GPIO3.IO24 */ #define SC_P_ADC_IN5 136 /* DMA.ADC1.IN1, DMA.SPI1.SDI, LSIO.KPP0.ROW1, LSIO.GPIO3.IO23 */ #define SC_P_ADC_IN4 137 /* DMA.ADC1.IN0, DMA.SPI1.SDO, LSIO.KPP0.ROW0, LSIO.GPIO3.IO22 */ #define SC_P_ADC_IN3 138 /* DMA.ADC0.IN3, DMA.SPI1.SCK, LSIO.KPP0.COL3, LSIO.GPIO3.IO21 */ #define SC_P_ADC_IN2 139 /* DMA.ADC0.IN2, LSIO.KPP0.COL2, LSIO.GPIO3.IO20 */ #define SC_P_ADC_IN1 140 /* DMA.ADC0.IN1, LSIO.KPP0.COL1, LSIO.GPIO3.IO19 */ #define SC_P_ADC_IN0 141 /* DMA.ADC0.IN0, LSIO.KPP0.COL0, LSIO.GPIO3.IO18 */ #define SC_P_MLB_SIG 142 /* CONN.MLB.SIG, AUD.SAI3.RXC, LSIO.GPIO3.IO26 */ #define SC_P_MLB_CLK 143 /* CONN.MLB.CLK, AUD.SAI3.RXFS, LSIO.GPIO3.IO27 */ #define SC_P_MLB_DATA 144 /* CONN.MLB.DATA, AUD.SAI3.RXD, LSIO.GPIO3.IO28 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOLHT 145 /* */ #define SC_P_FLEXCAN0_RX 146 /* DMA.FLEXCAN0.RX, LSIO.GPIO3.IO29 */ #define SC_P_FLEXCAN0_TX 147 /* DMA.FLEXCAN0.TX, LSIO.GPIO3.IO30 */ #define SC_P_FLEXCAN1_RX 148 /* DMA.FLEXCAN1.RX, LSIO.GPIO3.IO31 */ #define SC_P_FLEXCAN1_TX 149 /* DMA.FLEXCAN1.TX, LSIO.GPIO4.IO00 */ #define SC_P_FLEXCAN2_RX 150 /* DMA.FLEXCAN2.RX, LSIO.GPIO4.IO01 */ #define SC_P_FLEXCAN2_TX 151 /* DMA.FLEXCAN2.TX, LSIO.GPIO4.IO02 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOTHR 152 /* */ #define SC_P_USB_SS3_TC0 153 /* DMA.I2C1.SCL, CONN.USB_OTG1.PWR, LSIO.GPIO4.IO03 */ #define SC_P_USB_SS3_TC1 154 /* DMA.I2C1.SCL, CONN.USB_OTG2.PWR, LSIO.GPIO4.IO04 */ #define SC_P_USB_SS3_TC2 155 /* DMA.I2C1.SDA, CONN.USB_OTG1.OC, LSIO.GPIO4.IO05 */ #define SC_P_USB_SS3_TC3 156 /* DMA.I2C1.SDA, CONN.USB_OTG2.OC, LSIO.GPIO4.IO06 */ #define SC_P_COMP_CTL_GPIO_3V3_USB3IO 157 /* */ #define SC_P_USDHC1_RESET_B 158 /* CONN.USDHC1.RESET_B, LSIO.GPIO4.IO07 */ #define SC_P_USDHC1_VSELECT 159 /* CONN.USDHC1.VSELECT, LSIO.GPIO4.IO08 */ #define SC_P_USDHC2_RESET_B 160 /* CONN.USDHC2.RESET_B, LSIO.GPIO4.IO09 */ #define SC_P_USDHC2_VSELECT 161 /* CONN.USDHC2.VSELECT, LSIO.GPIO4.IO10 */ #define SC_P_USDHC2_WP 162 /* CONN.USDHC2.WP, LSIO.GPIO4.IO11 */ #define SC_P_USDHC2_CD_B 163 /* CONN.USDHC2.CD_B, LSIO.GPIO4.IO12 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_VSELSEP 164 /* */ #define SC_P_ENET0_MDIO 165 /* CONN.ENET0.MDIO, DMA.I2C4.SDA, LSIO.GPIO4.IO13 */ #define SC_P_ENET0_MDC 166 /* CONN.ENET0.MDC, DMA.I2C4.SCL, LSIO.GPIO4.IO14 */ #define SC_P_ENET0_REFCLK_125M_25M 167 /* CONN.ENET0.REFCLK_125M_25M, CONN.ENET0.PPS, LSIO.GPIO4.IO15 */ #define SC_P_ENET1_REFCLK_125M_25M 168 /* CONN.ENET1.REFCLK_125M_25M, CONN.ENET1.PPS, LSIO.GPIO4.IO16 */ #define SC_P_ENET1_MDIO 169 /* CONN.ENET1.MDIO, DMA.I2C4.SDA, LSIO.GPIO4.IO17 */ #define SC_P_ENET1_MDC 170 /* CONN.ENET1.MDC, DMA.I2C4.SCL, LSIO.GPIO4.IO18 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOCT 171 /* */ #define SC_P_QSPI1A_SS0_B 172 /* LSIO.QSPI1A.SS0_B, LSIO.GPIO4.IO19 */ #define SC_P_QSPI1A_SS1_B 173 /* LSIO.QSPI1A.SS1_B, LSIO.QSPI1A.SCLK2, LSIO.GPIO4.IO20 */ #define SC_P_QSPI1A_SCLK 174 /* LSIO.QSPI1A.SCLK, LSIO.GPIO4.IO21 */ #define SC_P_QSPI1A_DQS 175 /* LSIO.QSPI1A.DQS, LSIO.GPIO4.IO22 */ #define SC_P_QSPI1A_DATA3 176 /* LSIO.QSPI1A.DATA3, DMA.I2C1.SDA, CONN.USB_OTG1.OC, LSIO.GPIO4.IO23 */ #define SC_P_QSPI1A_DATA2 177 /* LSIO.QSPI1A.DATA2, DMA.I2C1.SCL, CONN.USB_OTG2.PWR, LSIO.GPIO4.IO24 */ #define SC_P_QSPI1A_DATA1 178 /* LSIO.QSPI1A.DATA1, DMA.I2C1.SDA, CONN.USB_OTG2.OC, LSIO.GPIO4.IO25 */ #define SC_P_QSPI1A_DATA0 179 /* LSIO.QSPI1A.DATA0, LSIO.GPIO4.IO26 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_QSPI1 180 /* */ #define SC_P_QSPI0A_DATA0 181 /* LSIO.QSPI0A.DATA0 */ #define SC_P_QSPI0A_DATA1 182 /* LSIO.QSPI0A.DATA1 */ #define SC_P_QSPI0A_DATA2 183 /* LSIO.QSPI0A.DATA2 */ #define SC_P_QSPI0A_DATA3 184 /* LSIO.QSPI0A.DATA3 */ #define SC_P_QSPI0A_DQS 185 /* LSIO.QSPI0A.DQS */ #define SC_P_QSPI0A_SS0_B 186 /* LSIO.QSPI0A.SS0_B */ #define SC_P_QSPI0A_SS1_B 187 /* LSIO.QSPI0A.SS1_B, LSIO.QSPI0A.SCLK2 */ #define SC_P_QSPI0A_SCLK 188 /* LSIO.QSPI0A.SCLK */ #define SC_P_QSPI0B_SCLK 189 /* LSIO.QSPI0B.SCLK */ #define SC_P_QSPI0B_DATA0 190 /* LSIO.QSPI0B.DATA0 */ #define SC_P_QSPI0B_DATA1 191 /* LSIO.QSPI0B.DATA1 */ #define SC_P_QSPI0B_DATA2 192 /* LSIO.QSPI0B.DATA2 */ #define SC_P_QSPI0B_DATA3 193 /* LSIO.QSPI0B.DATA3 */ #define SC_P_QSPI0B_DQS 194 /* LSIO.QSPI0B.DQS */ #define SC_P_QSPI0B_SS0_B 195 /* LSIO.QSPI0B.SS0_B */ #define SC_P_QSPI0B_SS1_B 196 /* LSIO.QSPI0B.SS1_B, LSIO.QSPI0B.SCLK2 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_QSPI0 197 /* */ #define SC_P_PCIE_CTRL0_CLKREQ_B 198 /* HSIO.PCIE0.CLKREQ_B, LSIO.GPIO4.IO27 */ #define SC_P_PCIE_CTRL0_WAKE_B 199 /* HSIO.PCIE0.WAKE_B, LSIO.GPIO4.IO28 */ #define SC_P_PCIE_CTRL0_PERST_B 200 /* HSIO.PCIE0.PERST_B, LSIO.GPIO4.IO29 */ #define SC_P_PCIE_CTRL1_CLKREQ_B 201 /* HSIO.PCIE1.CLKREQ_B, DMA.I2C1.SDA, CONN.USB_OTG2.OC, LSIO.GPIO4.IO30 */ #define SC_P_PCIE_CTRL1_WAKE_B 202 /* HSIO.PCIE1.WAKE_B, DMA.I2C1.SCL, CONN.USB_OTG2.PWR, LSIO.GPIO4.IO31 */ #define SC_P_PCIE_CTRL1_PERST_B 203 /* HSIO.PCIE1.PERST_B, DMA.I2C1.SCL, CONN.USB_OTG1.PWR, LSIO.GPIO5.IO00 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_PCIESEP 204 /* */ #define SC_P_USB_HSIC0_DATA 205 /* CONN.USB_HSIC0.DATA, DMA.I2C1.SDA, LSIO.GPIO5.IO01 */ #define SC_P_USB_HSIC0_STROBE 206 /* CONN.USB_HSIC0.STROBE, DMA.I2C1.SCL, LSIO.GPIO5.IO02 */ #define SC_P_CALIBRATION_0_HSIC 207 /* */ #define SC_P_CALIBRATION_1_HSIC 208 /* */ #define SC_P_EMMC0_CLK 209 /* CONN.EMMC0.CLK, CONN.NAND.READY_B */ #define SC_P_EMMC0_CMD 210 /* CONN.EMMC0.CMD, CONN.NAND.DQS, AUD.MQS.R, LSIO.GPIO5.IO03 */ #define SC_P_EMMC0_DATA0 211 /* CONN.EMMC0.DATA0, CONN.NAND.DATA00, LSIO.GPIO5.IO04 */ #define SC_P_EMMC0_DATA1 212 /* CONN.EMMC0.DATA1, CONN.NAND.DATA01, LSIO.GPIO5.IO05 */ #define SC_P_EMMC0_DATA2 213 /* CONN.EMMC0.DATA2, CONN.NAND.DATA02, LSIO.GPIO5.IO06 */ #define SC_P_EMMC0_DATA3 214 /* CONN.EMMC0.DATA3, CONN.NAND.DATA03, LSIO.GPIO5.IO07 */ #define SC_P_EMMC0_DATA4 215 /* CONN.EMMC0.DATA4, CONN.NAND.DATA04, LSIO.GPIO5.IO08 */ #define SC_P_EMMC0_DATA5 216 /* CONN.EMMC0.DATA5, CONN.NAND.DATA05, LSIO.GPIO5.IO09 */ #define SC_P_EMMC0_DATA6 217 /* CONN.EMMC0.DATA6, CONN.NAND.DATA06, LSIO.GPIO5.IO10 */ #define SC_P_EMMC0_DATA7 218 /* CONN.EMMC0.DATA7, CONN.NAND.DATA07, LSIO.GPIO5.IO11 */ #define SC_P_EMMC0_STROBE 219 /* CONN.EMMC0.STROBE, CONN.NAND.CLE, LSIO.GPIO5.IO12 */ #define SC_P_EMMC0_RESET_B 220 /* CONN.EMMC0.RESET_B, CONN.NAND.WP_B, CONN.USDHC1.VSELECT, LSIO.GPIO5.IO13 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_SD1FIX 221 /* */ #define SC_P_USDHC1_CLK 222 /* CONN.USDHC1.CLK, AUD.MQS.R */ #define SC_P_USDHC1_CMD 223 /* CONN.USDHC1.CMD, AUD.MQS.L, LSIO.GPIO5.IO14 */ #define SC_P_USDHC1_DATA0 224 /* CONN.USDHC1.DATA0, CONN.NAND.RE_N, LSIO.GPIO5.IO15 */ #define SC_P_USDHC1_DATA1 225 /* CONN.USDHC1.DATA1, CONN.NAND.RE_P, LSIO.GPIO5.IO16 */ #define SC_P_CTL_NAND_RE_P_N 226 /* */ #define SC_P_USDHC1_DATA2 227 /* CONN.USDHC1.DATA2, CONN.NAND.DQS_N, LSIO.GPIO5.IO17 */ #define SC_P_USDHC1_DATA3 228 /* CONN.USDHC1.DATA3, CONN.NAND.DQS_P, LSIO.GPIO5.IO18 */ #define SC_P_CTL_NAND_DQS_P_N 229 /* */ #define SC_P_USDHC1_DATA4 230 /* CONN.USDHC1.DATA4, CONN.NAND.CE0_B, AUD.MQS.R, LSIO.GPIO5.IO19 */ #define SC_P_USDHC1_DATA5 231 /* CONN.USDHC1.DATA5, CONN.NAND.RE_B, AUD.MQS.L, LSIO.GPIO5.IO20 */ #define SC_P_USDHC1_DATA6 232 /* CONN.USDHC1.DATA6, CONN.NAND.WE_B, CONN.USDHC1.WP, LSIO.GPIO5.IO21 */ #define SC_P_USDHC1_DATA7 233 /* CONN.USDHC1.DATA7, CONN.NAND.ALE, CONN.USDHC1.CD_B, LSIO.GPIO5.IO22 */ #define SC_P_USDHC1_STROBE 234 /* CONN.USDHC1.STROBE, CONN.NAND.CE1_B, CONN.USDHC1.RESET_B, LSIO.GPIO5.IO23 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_VSEL2 235 /* */ #define SC_P_USDHC2_CLK 236 /* CONN.USDHC2.CLK, AUD.MQS.R, LSIO.GPIO5.IO24 */ #define SC_P_USDHC2_CMD 237 /* CONN.USDHC2.CMD, AUD.MQS.L, LSIO.GPIO5.IO25 */ #define SC_P_USDHC2_DATA0 238 /* CONN.USDHC2.DATA0, DMA.UART4.RX, LSIO.GPIO5.IO26 */ #define SC_P_USDHC2_DATA1 239 /* CONN.USDHC2.DATA1, DMA.UART4.TX, LSIO.GPIO5.IO27 */ #define SC_P_USDHC2_DATA2 240 /* CONN.USDHC2.DATA2, DMA.UART4.CTS_B, LSIO.GPIO5.IO28 */ #define SC_P_USDHC2_DATA3 241 /* CONN.USDHC2.DATA3, DMA.UART4.RTS_B, LSIO.GPIO5.IO29 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_VSEL3 242 /* */ #define SC_P_ENET0_RGMII_TXC 243 /* CONN.ENET0.RGMII_TXC, CONN.ENET0.RCLK50M_OUT, CONN.ENET0.RCLK50M_IN, LSIO.GPIO5.IO30 */ #define SC_P_ENET0_RGMII_TX_CTL 244 /* CONN.ENET0.RGMII_TX_CTL, LSIO.GPIO5.IO31 */ #define SC_P_ENET0_RGMII_TXD0 245 /* CONN.ENET0.RGMII_TXD0, LSIO.GPIO6.IO00 */ #define SC_P_ENET0_RGMII_TXD1 246 /* CONN.ENET0.RGMII_TXD1, LSIO.GPIO6.IO01 */ #define SC_P_ENET0_RGMII_TXD2 247 /* CONN.ENET0.RGMII_TXD2, DMA.UART3.TX, VPU.TSI_S1.VID, LSIO.GPIO6.IO02 */ #define SC_P_ENET0_RGMII_TXD3 248 /* CONN.ENET0.RGMII_TXD3, DMA.UART3.RTS_B, VPU.TSI_S1.SYNC, LSIO.GPIO6.IO03 */ #define SC_P_ENET0_RGMII_RXC 249 /* CONN.ENET0.RGMII_RXC, DMA.UART3.CTS_B, VPU.TSI_S1.DATA, LSIO.GPIO6.IO04 */ #define SC_P_ENET0_RGMII_RX_CTL 250 /* CONN.ENET0.RGMII_RX_CTL, VPU.TSI_S0.VID, LSIO.GPIO6.IO05 */ #define SC_P_ENET0_RGMII_RXD0 251 /* CONN.ENET0.RGMII_RXD0, VPU.TSI_S0.SYNC, LSIO.GPIO6.IO06 */ #define SC_P_ENET0_RGMII_RXD1 252 /* CONN.ENET0.RGMII_RXD1, VPU.TSI_S0.DATA, LSIO.GPIO6.IO07 */ #define SC_P_ENET0_RGMII_RXD2 253 /* CONN.ENET0.RGMII_RXD2, CONN.ENET0.RMII_RX_ER, VPU.TSI_S0.CLK, LSIO.GPIO6.IO08 */ #define SC_P_ENET0_RGMII_RXD3 254 /* CONN.ENET0.RGMII_RXD3, DMA.UART3.RX, VPU.TSI_S1.CLK, LSIO.GPIO6.IO09 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_ENET_ENETB 255 /* */ #define SC_P_ENET1_RGMII_TXC 256 /* CONN.ENET1.RGMII_TXC, CONN.ENET1.RCLK50M_OUT, CONN.ENET1.RCLK50M_IN, LSIO.GPIO6.IO10 */ #define SC_P_ENET1_RGMII_TX_CTL 257 /* CONN.ENET1.RGMII_TX_CTL, LSIO.GPIO6.IO11 */ #define SC_P_ENET1_RGMII_TXD0 258 /* CONN.ENET1.RGMII_TXD0, LSIO.GPIO6.IO12 */ #define SC_P_ENET1_RGMII_TXD1 259 /* CONN.ENET1.RGMII_TXD1, LSIO.GPIO6.IO13 */ #define SC_P_ENET1_RGMII_TXD2 260 /* CONN.ENET1.RGMII_TXD2, DMA.UART3.TX, VPU.TSI_S1.VID, LSIO.GPIO6.IO14 */ #define SC_P_ENET1_RGMII_TXD3 261 /* CONN.ENET1.RGMII_TXD3, DMA.UART3.RTS_B, VPU.TSI_S1.SYNC, LSIO.GPIO6.IO15 */ #define SC_P_ENET1_RGMII_RXC 262 /* CONN.ENET1.RGMII_RXC, DMA.UART3.CTS_B, VPU.TSI_S1.DATA, LSIO.GPIO6.IO16 */ #define SC_P_ENET1_RGMII_RX_CTL 263 /* CONN.ENET1.RGMII_RX_CTL, VPU.TSI_S0.VID, LSIO.GPIO6.IO17 */ #define SC_P_ENET1_RGMII_RXD0 264 /* CONN.ENET1.RGMII_RXD0, VPU.TSI_S0.SYNC, LSIO.GPIO6.IO18 */ #define SC_P_ENET1_RGMII_RXD1 265 /* CONN.ENET1.RGMII_RXD1, VPU.TSI_S0.DATA, LSIO.GPIO6.IO19 */ #define SC_P_ENET1_RGMII_RXD2 266 /* CONN.ENET1.RGMII_RXD2, CONN.ENET1.RMII_RX_ER, VPU.TSI_S0.CLK, LSIO.GPIO6.IO20 */ #define SC_P_ENET1_RGMII_RXD3 267 /* CONN.ENET1.RGMII_RXD3, DMA.UART3.RX, VPU.TSI_S1.CLK, LSIO.GPIO6.IO21 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_ENET_ENETA 268 /* */ /*@}*/ #endif /* IMX8QM_PADS_H */ trusted-firmware-a-2.2/plat/imx/common/include/imx8qx_pads.h000066400000000000000000000470201355360272700242020ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /*! * Header file used to configure SoC pad list. */ #ifndef IMX8QX_PADS_H #define IMX8QX_PADS_H /* Includes */ /* Defines */ /*! * @name Pad Definitions */ /*@{*/ #define SC_P_PCIE_CTRL0_PERST_B 0 /* HSIO.PCIE0.PERST_B, LSIO.GPIO4.IO00 */ #define SC_P_PCIE_CTRL0_CLKREQ_B 1 /* HSIO.PCIE0.CLKREQ_B, LSIO.GPIO4.IO01 */ #define SC_P_PCIE_CTRL0_WAKE_B 2 /* HSIO.PCIE0.WAKE_B, LSIO.GPIO4.IO02 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_PCIESEP 3 /* */ #define SC_P_USB_SS3_TC0 4 /* ADMA.I2C1.SCL, CONN.USB_OTG1.PWR, CONN.USB_OTG2.PWR, LSIO.GPIO4.IO03 */ #define SC_P_USB_SS3_TC1 5 /* ADMA.I2C1.SCL, CONN.USB_OTG2.PWR, LSIO.GPIO4.IO04 */ #define SC_P_USB_SS3_TC2 6 /* ADMA.I2C1.SDA, CONN.USB_OTG1.OC, CONN.USB_OTG2.OC, LSIO.GPIO4.IO05 */ #define SC_P_USB_SS3_TC3 7 /* ADMA.I2C1.SDA, CONN.USB_OTG2.OC, LSIO.GPIO4.IO06 */ #define SC_P_COMP_CTL_GPIO_3V3_USB3IO 8 /* */ #define SC_P_EMMC0_CLK 9 /* CONN.EMMC0.CLK, CONN.NAND.READY_B, LSIO.GPIO4.IO07 */ #define SC_P_EMMC0_CMD 10 /* CONN.EMMC0.CMD, CONN.NAND.DQS, LSIO.GPIO4.IO08 */ #define SC_P_EMMC0_DATA0 11 /* CONN.EMMC0.DATA0, CONN.NAND.DATA00, LSIO.GPIO4.IO09 */ #define SC_P_EMMC0_DATA1 12 /* CONN.EMMC0.DATA1, CONN.NAND.DATA01, LSIO.GPIO4.IO10 */ #define SC_P_EMMC0_DATA2 13 /* CONN.EMMC0.DATA2, CONN.NAND.DATA02, LSIO.GPIO4.IO11 */ #define SC_P_EMMC0_DATA3 14 /* CONN.EMMC0.DATA3, CONN.NAND.DATA03, LSIO.GPIO4.IO12 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_SD1FIX0 15 /* */ #define SC_P_EMMC0_DATA4 16 /* CONN.EMMC0.DATA4, CONN.NAND.DATA04, CONN.EMMC0.WP, LSIO.GPIO4.IO13 */ #define SC_P_EMMC0_DATA5 17 /* CONN.EMMC0.DATA5, CONN.NAND.DATA05, CONN.EMMC0.VSELECT, LSIO.GPIO4.IO14 */ #define SC_P_EMMC0_DATA6 18 /* CONN.EMMC0.DATA6, CONN.NAND.DATA06, CONN.MLB.CLK, LSIO.GPIO4.IO15 */ #define SC_P_EMMC0_DATA7 19 /* CONN.EMMC0.DATA7, CONN.NAND.DATA07, CONN.MLB.SIG, LSIO.GPIO4.IO16 */ #define SC_P_EMMC0_STROBE 20 /* CONN.EMMC0.STROBE, CONN.NAND.CLE, CONN.MLB.DATA, LSIO.GPIO4.IO17 */ #define SC_P_EMMC0_RESET_B 21 /* CONN.EMMC0.RESET_B, CONN.NAND.WP_B, LSIO.GPIO4.IO18 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_SD1FIX1 22 /* */ #define SC_P_USDHC1_RESET_B 23 /* CONN.USDHC1.RESET_B, CONN.NAND.RE_N, ADMA.SPI2.SCK, LSIO.GPIO4.IO19 */ #define SC_P_USDHC1_VSELECT 24 /* CONN.USDHC1.VSELECT, CONN.NAND.RE_P, ADMA.SPI2.SDO, CONN.NAND.RE_B, LSIO.GPIO4.IO20 */ #define SC_P_CTL_NAND_RE_P_N 25 /* */ #define SC_P_USDHC1_WP 26 /* CONN.USDHC1.WP, CONN.NAND.DQS_N, ADMA.SPI2.SDI, LSIO.GPIO4.IO21 */ #define SC_P_USDHC1_CD_B 27 /* CONN.USDHC1.CD_B, CONN.NAND.DQS_P, ADMA.SPI2.CS0, CONN.NAND.DQS, LSIO.GPIO4.IO22 */ #define SC_P_CTL_NAND_DQS_P_N 28 /* */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_VSELSEP 29 /* */ #define SC_P_USDHC1_CLK 30 /* CONN.USDHC1.CLK, ADMA.UART3.RX, LSIO.GPIO4.IO23 */ #define SC_P_USDHC1_CMD 31 /* CONN.USDHC1.CMD, CONN.NAND.CE0_B, ADMA.MQS.R, LSIO.GPIO4.IO24 */ #define SC_P_USDHC1_DATA0 32 /* CONN.USDHC1.DATA0, CONN.NAND.CE1_B, ADMA.MQS.L, LSIO.GPIO4.IO25 */ #define SC_P_USDHC1_DATA1 33 /* CONN.USDHC1.DATA1, CONN.NAND.RE_B, ADMA.UART3.TX, LSIO.GPIO4.IO26 */ #define SC_P_USDHC1_DATA2 34 /* CONN.USDHC1.DATA2, CONN.NAND.WE_B, ADMA.UART3.CTS_B, LSIO.GPIO4.IO27 */ #define SC_P_USDHC1_DATA3 35 /* CONN.USDHC1.DATA3, CONN.NAND.ALE, ADMA.UART3.RTS_B, LSIO.GPIO4.IO28 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_VSEL3 36 /* */ #define SC_P_ENET0_RGMII_TXC 37 /* CONN.ENET0.RGMII_TXC, CONN.ENET0.RCLK50M_OUT, CONN.ENET0.RCLK50M_IN, CONN.NAND.CE1_B, LSIO.GPIO4.IO29 */ #define SC_P_ENET0_RGMII_TX_CTL 38 /* CONN.ENET0.RGMII_TX_CTL, CONN.USDHC1.RESET_B, LSIO.GPIO4.IO30 */ #define SC_P_ENET0_RGMII_TXD0 39 /* CONN.ENET0.RGMII_TXD0, CONN.USDHC1.VSELECT, LSIO.GPIO4.IO31 */ #define SC_P_ENET0_RGMII_TXD1 40 /* CONN.ENET0.RGMII_TXD1, CONN.USDHC1.WP, LSIO.GPIO5.IO00 */ #define SC_P_ENET0_RGMII_TXD2 41 /* CONN.ENET0.RGMII_TXD2, CONN.MLB.CLK, CONN.NAND.CE0_B, CONN.USDHC1.CD_B, LSIO.GPIO5.IO01 */ #define SC_P_ENET0_RGMII_TXD3 42 /* CONN.ENET0.RGMII_TXD3, CONN.MLB.SIG, CONN.NAND.RE_B, LSIO.GPIO5.IO02 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_ENET_ENETB0 43 /* */ #define SC_P_ENET0_RGMII_RXC 44 /* CONN.ENET0.RGMII_RXC, CONN.MLB.DATA, CONN.NAND.WE_B, CONN.USDHC1.CLK, LSIO.GPIO5.IO03 */ #define SC_P_ENET0_RGMII_RX_CTL 45 /* CONN.ENET0.RGMII_RX_CTL, CONN.USDHC1.CMD, LSIO.GPIO5.IO04 */ #define SC_P_ENET0_RGMII_RXD0 46 /* CONN.ENET0.RGMII_RXD0, CONN.USDHC1.DATA0, LSIO.GPIO5.IO05 */ #define SC_P_ENET0_RGMII_RXD1 47 /* CONN.ENET0.RGMII_RXD1, CONN.USDHC1.DATA1, LSIO.GPIO5.IO06 */ #define SC_P_ENET0_RGMII_RXD2 48 /* CONN.ENET0.RGMII_RXD2, CONN.ENET0.RMII_RX_ER, CONN.USDHC1.DATA2, LSIO.GPIO5.IO07 */ #define SC_P_ENET0_RGMII_RXD3 49 /* CONN.ENET0.RGMII_RXD3, CONN.NAND.ALE, CONN.USDHC1.DATA3, LSIO.GPIO5.IO08 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_ENET_ENETB1 50 /* */ #define SC_P_ENET0_REFCLK_125M_25M 51 /* CONN.ENET0.REFCLK_125M_25M, CONN.ENET0.PPS, CONN.ENET1.PPS, LSIO.GPIO5.IO09 */ #define SC_P_ENET0_MDIO 52 /* CONN.ENET0.MDIO, ADMA.I2C3.SDA, CONN.ENET1.MDIO, LSIO.GPIO5.IO10 */ #define SC_P_ENET0_MDC 53 /* CONN.ENET0.MDC, ADMA.I2C3.SCL, CONN.ENET1.MDC, LSIO.GPIO5.IO11 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOCT 54 /* */ #define SC_P_ESAI0_FSR 55 /* ADMA.ESAI0.FSR, CONN.ENET1.RCLK50M_OUT, ADMA.LCDIF.D00, CONN.ENET1.RGMII_TXC, CONN.ENET1.RCLK50M_IN */ #define SC_P_ESAI0_FST 56 /* ADMA.ESAI0.FST, CONN.MLB.CLK, ADMA.LCDIF.D01, CONN.ENET1.RGMII_TXD2, LSIO.GPIO0.IO01 */ #define SC_P_ESAI0_SCKR 57 /* ADMA.ESAI0.SCKR, ADMA.LCDIF.D02, CONN.ENET1.RGMII_TX_CTL, LSIO.GPIO0.IO02 */ #define SC_P_ESAI0_SCKT 58 /* ADMA.ESAI0.SCKT, CONN.MLB.SIG, ADMA.LCDIF.D03, CONN.ENET1.RGMII_TXD3, LSIO.GPIO0.IO03 */ #define SC_P_ESAI0_TX0 59 /* ADMA.ESAI0.TX0, CONN.MLB.DATA, ADMA.LCDIF.D04, CONN.ENET1.RGMII_RXC, LSIO.GPIO0.IO04 */ #define SC_P_ESAI0_TX1 60 /* ADMA.ESAI0.TX1, ADMA.LCDIF.D05, CONN.ENET1.RGMII_RXD3, LSIO.GPIO0.IO05 */ #define SC_P_ESAI0_TX2_RX3 61 /* ADMA.ESAI0.TX2_RX3, CONN.ENET1.RMII_RX_ER, ADMA.LCDIF.D06, CONN.ENET1.RGMII_RXD2, LSIO.GPIO0.IO06 */ #define SC_P_ESAI0_TX3_RX2 62 /* ADMA.ESAI0.TX3_RX2, ADMA.LCDIF.D07, CONN.ENET1.RGMII_RXD1, LSIO.GPIO0.IO07 */ #define SC_P_ESAI0_TX4_RX1 63 /* ADMA.ESAI0.TX4_RX1, ADMA.LCDIF.D08, CONN.ENET1.RGMII_TXD0, LSIO.GPIO0.IO08 */ #define SC_P_ESAI0_TX5_RX0 64 /* ADMA.ESAI0.TX5_RX0, ADMA.LCDIF.D09, CONN.ENET1.RGMII_TXD1, LSIO.GPIO0.IO09 */ #define SC_P_SPDIF0_RX 65 /* ADMA.SPDIF0.RX, ADMA.MQS.R, ADMA.LCDIF.D10, CONN.ENET1.RGMII_RXD0, LSIO.GPIO0.IO10 */ #define SC_P_SPDIF0_TX 66 /* ADMA.SPDIF0.TX, ADMA.MQS.L, ADMA.LCDIF.D11, CONN.ENET1.RGMII_RX_CTL, LSIO.GPIO0.IO11 */ #define SC_P_SPDIF0_EXT_CLK 67 /* ADMA.SPDIF0.EXT_CLK, ADMA.LCDIF.D12, CONN.ENET1.REFCLK_125M_25M, LSIO.GPIO0.IO12 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHB 68 /* */ #define SC_P_SPI3_SCK 69 /* ADMA.SPI3.SCK, ADMA.LCDIF.D13, LSIO.GPIO0.IO13 */ #define SC_P_SPI3_SDO 70 /* ADMA.SPI3.SDO, ADMA.LCDIF.D14, LSIO.GPIO0.IO14 */ #define SC_P_SPI3_SDI 71 /* ADMA.SPI3.SDI, ADMA.LCDIF.D15, LSIO.GPIO0.IO15 */ #define SC_P_SPI3_CS0 72 /* ADMA.SPI3.CS0, ADMA.ACM.MCLK_OUT1, ADMA.LCDIF.HSYNC, LSIO.GPIO0.IO16 */ #define SC_P_SPI3_CS1 73 /* ADMA.SPI3.CS1, ADMA.I2C3.SCL, ADMA.LCDIF.RESET, ADMA.SPI2.CS0, ADMA.LCDIF.D16 */ #define SC_P_MCLK_IN1 74 /* ADMA.ACM.MCLK_IN1, ADMA.I2C3.SDA, ADMA.LCDIF.EN, ADMA.SPI2.SCK, ADMA.LCDIF.D17 */ #define SC_P_MCLK_IN0 75 /* ADMA.ACM.MCLK_IN0, ADMA.ESAI0.RX_HF_CLK, ADMA.LCDIF.VSYNC, ADMA.SPI2.SDI, LSIO.GPIO0.IO19 */ #define SC_P_MCLK_OUT0 76 /* ADMA.ACM.MCLK_OUT0, ADMA.ESAI0.TX_HF_CLK, ADMA.LCDIF.CLK, ADMA.SPI2.SDO, LSIO.GPIO0.IO20 */ #define SC_P_UART1_TX 77 /* ADMA.UART1.TX, LSIO.PWM0.OUT, LSIO.GPT0.CAPTURE, LSIO.GPIO0.IO21 */ #define SC_P_UART1_RX 78 /* ADMA.UART1.RX, LSIO.PWM1.OUT, LSIO.GPT0.COMPARE, LSIO.GPT1.CLK, LSIO.GPIO0.IO22 */ #define SC_P_UART1_RTS_B 79 /* ADMA.UART1.RTS_B, LSIO.PWM2.OUT, ADMA.LCDIF.D16, LSIO.GPT1.CAPTURE, LSIO.GPT0.CLK */ #define SC_P_UART1_CTS_B 80 /* ADMA.UART1.CTS_B, LSIO.PWM3.OUT, ADMA.LCDIF.D17, LSIO.GPT1.COMPARE, LSIO.GPIO0.IO24 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHK 81 /* */ #define SC_P_SAI0_TXD 82 /* ADMA.SAI0.TXD, ADMA.SAI1.RXC, ADMA.SPI1.SDO, ADMA.LCDIF.D18, LSIO.GPIO0.IO25 */ #define SC_P_SAI0_TXC 83 /* ADMA.SAI0.TXC, ADMA.SAI1.TXD, ADMA.SPI1.SDI, ADMA.LCDIF.D19, LSIO.GPIO0.IO26 */ #define SC_P_SAI0_RXD 84 /* ADMA.SAI0.RXD, ADMA.SAI1.RXFS, ADMA.SPI1.CS0, ADMA.LCDIF.D20, LSIO.GPIO0.IO27 */ #define SC_P_SAI0_TXFS 85 /* ADMA.SAI0.TXFS, ADMA.SPI2.CS1, ADMA.SPI1.SCK, LSIO.GPIO0.IO28 */ #define SC_P_SAI1_RXD 86 /* ADMA.SAI1.RXD, ADMA.SAI0.RXFS, ADMA.SPI1.CS1, ADMA.LCDIF.D21, LSIO.GPIO0.IO29 */ #define SC_P_SAI1_RXC 87 /* ADMA.SAI1.RXC, ADMA.SAI1.TXC, ADMA.LCDIF.D22, LSIO.GPIO0.IO30 */ #define SC_P_SAI1_RXFS 88 /* ADMA.SAI1.RXFS, ADMA.SAI1.TXFS, ADMA.LCDIF.D23, LSIO.GPIO0.IO31 */ #define SC_P_SPI2_CS0 89 /* ADMA.SPI2.CS0, LSIO.GPIO1.IO00 */ #define SC_P_SPI2_SDO 90 /* ADMA.SPI2.SDO, LSIO.GPIO1.IO01 */ #define SC_P_SPI2_SDI 91 /* ADMA.SPI2.SDI, LSIO.GPIO1.IO02 */ #define SC_P_SPI2_SCK 92 /* ADMA.SPI2.SCK, LSIO.GPIO1.IO03 */ #define SC_P_SPI0_SCK 93 /* ADMA.SPI0.SCK, ADMA.SAI0.TXC, M40.I2C0.SCL, M40.GPIO0.IO00, LSIO.GPIO1.IO04 */ #define SC_P_SPI0_SDI 94 /* ADMA.SPI0.SDI, ADMA.SAI0.TXD, M40.TPM0.CH0, M40.GPIO0.IO02, LSIO.GPIO1.IO05 */ #define SC_P_SPI0_SDO 95 /* ADMA.SPI0.SDO, ADMA.SAI0.TXFS, M40.I2C0.SDA, M40.GPIO0.IO01, LSIO.GPIO1.IO06 */ #define SC_P_SPI0_CS1 96 /* ADMA.SPI0.CS1, ADMA.SAI0.RXC, ADMA.SAI1.TXD, ADMA.LCD_PWM0.OUT, LSIO.GPIO1.IO07 */ #define SC_P_SPI0_CS0 97 /* ADMA.SPI0.CS0, ADMA.SAI0.RXD, M40.TPM0.CH1, M40.GPIO0.IO03, LSIO.GPIO1.IO08 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHT 98 /* */ #define SC_P_ADC_IN1 99 /* ADMA.ADC.IN1, M40.I2C0.SDA, M40.GPIO0.IO01, LSIO.GPIO1.IO09 */ #define SC_P_ADC_IN0 100 /* ADMA.ADC.IN0, M40.I2C0.SCL, M40.GPIO0.IO00, LSIO.GPIO1.IO10 */ #define SC_P_ADC_IN3 101 /* ADMA.ADC.IN3, M40.UART0.TX, M40.GPIO0.IO03, ADMA.ACM.MCLK_OUT0, LSIO.GPIO1.IO11 */ #define SC_P_ADC_IN2 102 /* ADMA.ADC.IN2, M40.UART0.RX, M40.GPIO0.IO02, ADMA.ACM.MCLK_IN0, LSIO.GPIO1.IO12 */ #define SC_P_ADC_IN5 103 /* ADMA.ADC.IN5, M40.TPM0.CH1, M40.GPIO0.IO05, LSIO.GPIO1.IO13 */ #define SC_P_ADC_IN4 104 /* ADMA.ADC.IN4, M40.TPM0.CH0, M40.GPIO0.IO04, LSIO.GPIO1.IO14 */ #define SC_P_FLEXCAN0_RX 105 /* ADMA.FLEXCAN0.RX, ADMA.SAI2.RXC, ADMA.UART0.RTS_B, ADMA.SAI1.TXC, LSIO.GPIO1.IO15 */ #define SC_P_FLEXCAN0_TX 106 /* ADMA.FLEXCAN0.TX, ADMA.SAI2.RXD, ADMA.UART0.CTS_B, ADMA.SAI1.TXFS, LSIO.GPIO1.IO16 */ #define SC_P_FLEXCAN1_RX 107 /* ADMA.FLEXCAN1.RX, ADMA.SAI2.RXFS, ADMA.FTM.CH2, ADMA.SAI1.TXD, LSIO.GPIO1.IO17 */ #define SC_P_FLEXCAN1_TX 108 /* ADMA.FLEXCAN1.TX, ADMA.SAI3.RXC, ADMA.DMA0.REQ_IN0, ADMA.SAI1.RXD, LSIO.GPIO1.IO18 */ #define SC_P_FLEXCAN2_RX 109 /* ADMA.FLEXCAN2.RX, ADMA.SAI3.RXD, ADMA.UART3.RX, ADMA.SAI1.RXFS, LSIO.GPIO1.IO19 */ #define SC_P_FLEXCAN2_TX 110 /* ADMA.FLEXCAN2.TX, ADMA.SAI3.RXFS, ADMA.UART3.TX, ADMA.SAI1.RXC, LSIO.GPIO1.IO20 */ #define SC_P_UART0_RX 111 /* ADMA.UART0.RX, ADMA.MQS.R, ADMA.FLEXCAN0.RX, SCU.UART0.RX, LSIO.GPIO1.IO21 */ #define SC_P_UART0_TX 112 /* ADMA.UART0.TX, ADMA.MQS.L, ADMA.FLEXCAN0.TX, SCU.UART0.TX, LSIO.GPIO1.IO22 */ #define SC_P_UART2_TX 113 /* ADMA.UART2.TX, ADMA.FTM.CH1, ADMA.FLEXCAN1.TX, LSIO.GPIO1.IO23 */ #define SC_P_UART2_RX 114 /* ADMA.UART2.RX, ADMA.FTM.CH0, ADMA.FLEXCAN1.RX, LSIO.GPIO1.IO24 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIOLH 115 /* */ #define SC_P_MIPI_DSI0_I2C0_SCL 116 /* MIPI_DSI0.I2C0.SCL, MIPI_DSI1.GPIO0.IO02, LSIO.GPIO1.IO25 */ #define SC_P_MIPI_DSI0_I2C0_SDA 117 /* MIPI_DSI0.I2C0.SDA, MIPI_DSI1.GPIO0.IO03, LSIO.GPIO1.IO26 */ #define SC_P_MIPI_DSI0_GPIO0_00 118 /* MIPI_DSI0.GPIO0.IO00, ADMA.I2C1.SCL, MIPI_DSI0.PWM0.OUT, LSIO.GPIO1.IO27 */ #define SC_P_MIPI_DSI0_GPIO0_01 119 /* MIPI_DSI0.GPIO0.IO01, ADMA.I2C1.SDA, LSIO.GPIO1.IO28 */ #define SC_P_MIPI_DSI1_I2C0_SCL 120 /* MIPI_DSI1.I2C0.SCL, MIPI_DSI0.GPIO0.IO02, LSIO.GPIO1.IO29 */ #define SC_P_MIPI_DSI1_I2C0_SDA 121 /* MIPI_DSI1.I2C0.SDA, MIPI_DSI0.GPIO0.IO03, LSIO.GPIO1.IO30 */ #define SC_P_MIPI_DSI1_GPIO0_00 122 /* MIPI_DSI1.GPIO0.IO00, ADMA.I2C2.SCL, MIPI_DSI1.PWM0.OUT, LSIO.GPIO1.IO31 */ #define SC_P_MIPI_DSI1_GPIO0_01 123 /* MIPI_DSI1.GPIO0.IO01, ADMA.I2C2.SDA, LSIO.GPIO2.IO00 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_MIPIDSIGPIO 124 /* */ #define SC_P_JTAG_TRST_B 125 /* SCU.JTAG.TRST_B, SCU.WDOG0.WDOG_OUT */ #define SC_P_PMIC_I2C_SCL 126 /* SCU.PMIC_I2C.SCL, SCU.GPIO0.IOXX_PMIC_A35_ON, LSIO.GPIO2.IO01 */ #define SC_P_PMIC_I2C_SDA 127 /* SCU.PMIC_I2C.SDA, SCU.GPIO0.IOXX_PMIC_GPU_ON, LSIO.GPIO2.IO02 */ #define SC_P_PMIC_INT_B 128 /* SCU.DSC.PMIC_INT_B */ #define SC_P_SCU_GPIO0_00 129 /* SCU.GPIO0.IO00, SCU.UART0.RX, M40.UART0.RX, ADMA.UART3.RX, LSIO.GPIO2.IO03 */ #define SC_P_SCU_GPIO0_01 130 /* SCU.GPIO0.IO01, SCU.UART0.TX, M40.UART0.TX, ADMA.UART3.TX, SCU.WDOG0.WDOG_OUT */ #define SC_P_SCU_PMIC_STANDBY 131 /* SCU.DSC.PMIC_STANDBY */ #define SC_P_SCU_BOOT_MODE0 132 /* SCU.DSC.BOOT_MODE0 */ #define SC_P_SCU_BOOT_MODE1 133 /* SCU.DSC.BOOT_MODE1 */ #define SC_P_SCU_BOOT_MODE2 134 /* SCU.DSC.BOOT_MODE2, SCU.PMIC_I2C.SDA */ #define SC_P_SCU_BOOT_MODE3 135 /* SCU.DSC.BOOT_MODE3, SCU.PMIC_I2C.SCL, SCU.DSC.RTC_CLOCK_OUTPUT_32K */ #define SC_P_CSI_D00 136 /* CI_PI.D02, ADMA.SAI0.RXC */ #define SC_P_CSI_D01 137 /* CI_PI.D03, ADMA.SAI0.RXD */ #define SC_P_CSI_D02 138 /* CI_PI.D04, ADMA.SAI0.RXFS */ #define SC_P_CSI_D03 139 /* CI_PI.D05, ADMA.SAI2.RXC */ #define SC_P_CSI_D04 140 /* CI_PI.D06, ADMA.SAI2.RXD */ #define SC_P_CSI_D05 141 /* CI_PI.D07, ADMA.SAI2.RXFS */ #define SC_P_CSI_D06 142 /* CI_PI.D08, ADMA.SAI3.RXC */ #define SC_P_CSI_D07 143 /* CI_PI.D09, ADMA.SAI3.RXD */ #define SC_P_CSI_HSYNC 144 /* CI_PI.HSYNC, CI_PI.D00, ADMA.SAI3.RXFS */ #define SC_P_CSI_VSYNC 145 /* CI_PI.VSYNC, CI_PI.D01 */ #define SC_P_CSI_PCLK 146 /* CI_PI.PCLK, MIPI_CSI0.I2C0.SCL, ADMA.SPI1.SCK, LSIO.GPIO3.IO00 */ #define SC_P_CSI_MCLK 147 /* CI_PI.MCLK, MIPI_CSI0.I2C0.SDA, ADMA.SPI1.SDO, LSIO.GPIO3.IO01 */ #define SC_P_CSI_EN 148 /* CI_PI.EN, CI_PI.I2C.SCL, ADMA.I2C3.SCL, ADMA.SPI1.SDI, LSIO.GPIO3.IO02 */ #define SC_P_CSI_RESET 149 /* CI_PI.RESET, CI_PI.I2C.SDA, ADMA.I2C3.SDA, ADMA.SPI1.CS0, LSIO.GPIO3.IO03 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_GPIORHD 150 /* */ #define SC_P_MIPI_CSI0_MCLK_OUT 151 /* MIPI_CSI0.ACM.MCLK_OUT, LSIO.GPIO3.IO04 */ #define SC_P_MIPI_CSI0_I2C0_SCL 152 /* MIPI_CSI0.I2C0.SCL, MIPI_CSI0.GPIO0.IO02, LSIO.GPIO3.IO05 */ #define SC_P_MIPI_CSI0_I2C0_SDA 153 /* MIPI_CSI0.I2C0.SDA, MIPI_CSI0.GPIO0.IO03, LSIO.GPIO3.IO06 */ #define SC_P_MIPI_CSI0_GPIO0_01 154 /* MIPI_CSI0.GPIO0.IO01, ADMA.I2C0.SDA, LSIO.GPIO3.IO07 */ #define SC_P_MIPI_CSI0_GPIO0_00 155 /* MIPI_CSI0.GPIO0.IO00, ADMA.I2C0.SCL, LSIO.GPIO3.IO08 */ #define SC_P_QSPI0A_DATA0 156 /* LSIO.QSPI0A.DATA0, LSIO.GPIO3.IO09 */ #define SC_P_QSPI0A_DATA1 157 /* LSIO.QSPI0A.DATA1, LSIO.GPIO3.IO10 */ #define SC_P_QSPI0A_DATA2 158 /* LSIO.QSPI0A.DATA2, LSIO.GPIO3.IO11 */ #define SC_P_QSPI0A_DATA3 159 /* LSIO.QSPI0A.DATA3, LSIO.GPIO3.IO12 */ #define SC_P_QSPI0A_DQS 160 /* LSIO.QSPI0A.DQS, LSIO.GPIO3.IO13 */ #define SC_P_QSPI0A_SS0_B 161 /* LSIO.QSPI0A.SS0_B, LSIO.GPIO3.IO14 */ #define SC_P_QSPI0A_SS1_B 162 /* LSIO.QSPI0A.SS1_B, LSIO.GPIO3.IO15 */ #define SC_P_QSPI0A_SCLK 163 /* LSIO.QSPI0A.SCLK, LSIO.GPIO3.IO16 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_QSPI0A 164 /* */ #define SC_P_QSPI0B_SCLK 165 /* LSIO.QSPI0B.SCLK, LSIO.QSPI1A.SCLK, LSIO.KPP0.COL0, LSIO.GPIO3.IO17 */ #define SC_P_QSPI0B_DATA0 166 /* LSIO.QSPI0B.DATA0, LSIO.QSPI1A.DATA0, LSIO.KPP0.COL1, LSIO.GPIO3.IO18 */ #define SC_P_QSPI0B_DATA1 167 /* LSIO.QSPI0B.DATA1, LSIO.QSPI1A.DATA1, LSIO.KPP0.COL2, LSIO.GPIO3.IO19 */ #define SC_P_QSPI0B_DATA2 168 /* LSIO.QSPI0B.DATA2, LSIO.QSPI1A.DATA2, LSIO.KPP0.COL3, LSIO.GPIO3.IO20 */ #define SC_P_QSPI0B_DATA3 169 /* LSIO.QSPI0B.DATA3, LSIO.QSPI1A.DATA3, LSIO.KPP0.ROW0, LSIO.GPIO3.IO21 */ #define SC_P_QSPI0B_DQS 170 /* LSIO.QSPI0B.DQS, LSIO.QSPI1A.DQS, LSIO.KPP0.ROW1, LSIO.GPIO3.IO22 */ #define SC_P_QSPI0B_SS0_B 171 /* LSIO.QSPI0B.SS0_B, LSIO.QSPI1A.SS0_B, LSIO.KPP0.ROW2, LSIO.GPIO3.IO23 */ #define SC_P_QSPI0B_SS1_B 172 /* LSIO.QSPI0B.SS1_B, LSIO.QSPI1A.SS1_B, LSIO.KPP0.ROW3, LSIO.GPIO3.IO24 */ #define SC_P_COMP_CTL_GPIO_1V8_3V3_QSPI0B 173 /* */ /*@}*/ #endif /* IMX8QX_PADS_H */ trusted-firmware-a-2.2/plat/imx/common/include/imx_aips.h000066400000000000000000000005741355360272700235510ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX_AIPS_H #define IMX_AIPS_H #include #define AIPSTZ_OAPCR_COUNT 0x05 struct aipstz_regs { uint32_t aipstz_mpr; uint32_t res[15]; uint32_t aipstz_opacr[AIPSTZ_OAPCR_COUNT]; }; void imx_aips_init(void); #endif /* IMX_AIPS_H */ trusted-firmware-a-2.2/plat/imx/common/include/imx_caam.h000066400000000000000000000027071355360272700235160ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX_CAAM_H #define IMX_CAAM_H #include #include #include struct caam_job_ring { uint32_t jrmidr_ms; uint32_t jrmidr_ls; }; struct caam_rtic_mid { uint32_t rticmidr_ms; uint32_t rticmidr_ls; }; struct caam_deco { uint32_t deco_mid_ms; uint32_t deco_mid_ls; }; #define JOB_RING_OFFSET 0x10 #define DEBUGCTL_OFFSET 0x58 #define RES2_SIZE (DEBUGCTL_OFFSET - JOB_RING_OFFSET - \ (sizeof(struct caam_job_ring) * CAAM_NUM_JOB_RINGS)) #define RTIC_MID_OFFSET 0x60 #define DECORR_OFFSET 0x9C #define RES3_SIZE (DECORR_OFFSET - RTIC_MID_OFFSET - \ (sizeof(struct caam_rtic_mid) * CAAM_NUM_RTIC)) #define DECO_MID_OFFSET 0xA0 #define DAR_OFFSET 0x120 #define RES4_SIZE (DAR_OFFSET - DECO_MID_OFFSET - \ (sizeof(struct caam_deco) * CAAM_NUM_DECO)) struct caam_ctrl { uint32_t res0; uint32_t mcfgr; uint32_t res1; uint32_t scfgr; struct caam_job_ring jr[CAAM_NUM_JOB_RINGS]; uint8_t res2[RES2_SIZE]; uint32_t debuctl; uint32_t jrstartr; struct caam_rtic_mid mid[CAAM_NUM_RTIC]; uint8_t res3[RES3_SIZE]; uint32_t decorr; struct caam_deco deco[CAAM_NUM_DECO]; uint8_t res4[RES4_SIZE]; uint32_t dar; uint32_t drr; } __packed; /* Job ring control bits */ #define JROWN_NS BIT(3) #define JROWN_MID 0x01 /* Declare CAAM API */ void imx_caam_init(void); #endif /* IMX_CAAM_H */ trusted-firmware-a-2.2/plat/imx/common/include/imx_clock.h000066400000000000000000001241601355360272700237060ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX_CLOCK_H #define IMX_CLOCK_H #include #include struct ccm_pll_ctrl { uint32_t ccm_pll_ctrl; uint32_t ccm_pll_ctrl_set; uint32_t ccm_pll_ctrl_clr; uint32_t ccm_pll_ctrl_tog; }; /* Clock gate control */ struct ccm_clk_gate_ctrl { uint32_t ccm_ccgr; uint32_t ccm_ccgr_set; uint32_t ccm_ccgr_clr; uint32_t ccm_ccgr_tog; }; #define CCM_CCGR_SETTING0_DOM_CLK_NONE 0 #define CCM_CCGR_SETTING0_DOM_CLK_RUN BIT(0) #define CCM_CCGR_SETTING0_DOM_CLK_RUN_WAIT BIT(1) #define CCM_CCGR_SETTING0_DOM_CLK_ALWAYS (BIT(1) | BIT(0)) #define CCM_CCGR_SETTING1_DOM_CLK_NONE 0 #define CCM_CCGR_SETTING1_DOM_CLK_RUN BIT(4) #define CCM_CCGR_SETTING1_DOM_CLK_RUN_WAIT BIT(5) #define CCM_CCGR_SETTING1_DOM_CLK_ALWAYS (BIT(5) | BIT(4)) #define CCM_CCGR_SETTING2_DOM_CLK_NONE 0 #define CCM_CCGR_SETTING2_DOM_CLK_RUN BIT(8) #define CCM_CCGR_SETTING2_DOM_CLK_RUN_WAIT BIT(9) #define CCM_CCGR_SETTING2_DOM_CLK_ALWAYS (BIT(9) | BIT(8)) #define CCM_CCGR_SETTING3_DOM_CLK_NONE 0 #define CCM_CCGR_SETTING3_DOM_CLK_RUN BIT(12) #define CCM_CCGR_SETTING3_DOM_CLK_RUN_WAIT BIT(13) #define CCM_CCGR_SETTING3_DOM_CLK_ALWAYS (BIT(13) | BIT(12)) enum { CCM_CCGR_ID_ADC = 32, CCM_CCGR_ID_AIPS1TZ = 10, CCM_CCGR_ID_AIPS2TZ = 11, CCM_CCGR_ID_AIPS3TZ = 12, CCM_CCGR_ID_APBHDMA = 20, CCM_CCGR_ID_CAAM = 36, CCM_CCGR_ID_CM4 = 1, CCM_CCGR_ID_CSI = 73, CCM_CCGR_ID_CSU = 45, CCM_CCGR_ID_DAP = 47, CCM_CCGR_ID_DBGMON = 46, CCM_CCGR_ID_DDRC = 19, CCM_CCGR_ID_ECSPI1 = 120, CCM_CCGR_ID_ECSPI2 = 121, CCM_CCGR_ID_ECSPI3 = 122, CCM_CCGR_ID_ECSPI4 = 123, CCM_CCGR_ID_EIM = 22, CCM_CCGR_ID_ENET1 = 112, CCM_CCGR_ID_ENET2 = 113, CCM_CCGR_ID_EPDC = 74, CCM_CCGR_ID_FLEXCAN1 = 116, CCM_CCGR_ID_FLEXCAN2 = 117, CCM_CCGR_ID_FLEXTIMER1 = 128, CCM_CCGR_ID_FLEXTIMER2 = 129, CCM_CCGR_ID_GPIO1 = 160, CCM_CCGR_ID_GPIO2 = 161, CCM_CCGR_ID_GPIO3 = 162, CCM_CCGR_ID_GPIO4 = 163, CCM_CCGR_ID_GPIO5 = 164, CCM_CCGR_ID_GPIO6 = 165, CCM_CCGR_ID_GPIO7 = 166, CCM_CCGR_ID_GPT1 = 124, CCM_CCGR_ID_GPT2 = 125, CCM_CCGR_ID_GPT3 = 126, CCM_CCGR_ID_GPT4 = 127, CCM_CCGR_ID_I2C1 = 136, CCM_CCGR_ID_I2C2 = 137, CCM_CCGR_ID_I2C3 = 138, CCM_CCGR_ID_I2C4 = 139, CCM_CCGR_ID_IOMUXC1 = 168, CCM_CCGR_ID_IOMUXC2 = 169, CCM_CCGR_ID_KPP = 120, CCM_CCGR_ID_LCDIF = 75, CCM_CCGR_ID_MIPI_CSI = 100, CCM_CCGR_ID_MIPI_DSI = 101, CCM_CCGR_ID_MIPI_PHY = 102, CCM_CCGR_ID_MU = 39, CCM_CCGR_ID_OCOTP = 35, CCM_CCGR_ID_OCRAM = 17, CCM_CCGR_ID_OCRAM_S = 18, CCM_CCGR_ID_PCIE = 96, CCM_CCGR_ID_PCIE_PHY = 96, CCM_CCGR_ID_PERFMON1 = 68, CCM_CCGR_ID_PERFMON2 = 69, CCM_CCGR_ID_PWM1 = 132, CCM_CCGR_ID_PWM2 = 133, CCM_CCGR_ID_PWM3 = 134, CCM_CCGR_ID_PMM4 = 135, CCM_CCGR_ID_PXP = 76, CCM_CCGR_ID_QOS1 = 42, CCM_CCGR_ID_QOS2 = 43, CCM_CCGR_ID_QOS3 = 44, CCM_CCGR_ID_QUADSPI = 21, CCM_CCGR_ID_RDC = 38, CCM_CCGR_ID_ROMCP = 16, CCM_CCGR_ID_SAI1 = 140, CCM_CCGR_ID_SAI2 = 141, CCM_CCGR_ID_SAI3 = 142, CCM_CCGR_ID_SCTR = 34, CCM_CCGR_ID_SDMA = 72, CCM_CCGR_ID_SEC = 49, CCM_CCGR_ID_SEMA42_1 = 64, CCM_CCGR_ID_SEMA42_2 = 65, CCM_CCGR_ID_SIM_DISPLAY = 5, CCM_CCGR_ID_SIM_ENET = 6, CCM_CCGR_ID_SIM_M = 7, CCM_CCGR_ID_SIM_MAIN = 4, CCM_CCGR_ID_SIM_S = 8, CCM_CCGR_ID_SIM_WAKEUP = 9, CCM_CCGR_ID_SIM1 = 144, CCM_CCGR_ID_SIM2 = 145, CCM_CCGR_ID_SIM_NAND = 20, CCM_CCGR_ID_DISPLAY_CM4 = 1, CCM_CCGR_ID_DRAM = 19, CCM_CCGR_ID_SNVS = 37, CCM_CCGR_ID_SPBA = 12, CCM_CCGR_ID_TRACE = 48, CCM_CCGR_ID_TZASC = 19, CCM_CCGR_ID_UART1 = 148, CCM_CCGR_ID_UART2 = 149, CCM_CCGR_ID_UART3 = 150, CCM_CCGR_ID_UART4 = 151, CCM_CCGR_ID_UART5 = 152, CCM_CCGR_ID_UART6 = 153, CCM_CCGR_ID_UART7 = 154, CCM_CCGR_ID_USB_HS = 40, CCM_CCGR_ID_USB_IPG = 104, CCM_CCGR_ID_USB_PHY_480MCLK = 105, CCM_CCGR_ID_USB_OTG1_PHY = 106, CCM_CCGR_ID_USB_OTG2_PHY = 107, CCM_CCGR_ID_USBHDC1 = 108, CCM_CCGR_ID_USBHDC2 = 109, CCM_CCGR_ID_USBHDC3 = 110, CCM_CCGR_ID_WDOG1 = 156, CCM_CCGR_ID_WDOG2 = 157, CCM_CCGR_ID_WDOG3 = 158, CCM_CCGR_ID_WDOG4 = 159, }; /* Clock target block */ struct ccm_target_root_ctrl { uint32_t ccm_target_root; uint32_t ccm_target_root_set; uint32_t ccm_target_root_clr; uint32_t ccm_target_root_tog; uint32_t ccm_misc; uint32_t ccm_misc_set; uint32_t ccm_misc_clr; uint32_t ccm_misc_tog; uint32_t ccm_post; uint32_t ccm_post_set; uint32_t ccm_post_clr; uint32_t ccm_post_tog; uint32_t ccm_pre; uint32_t ccm_pre_set; uint32_t ccm_pre_clr; uint32_t ccm_pre_tog; uint32_t reserved[0x0c]; uint32_t ccm_access_ctrl; uint32_t ccm_access_ctrl_set; uint32_t ccm_access_ctrl_clr; uint32_t ccm_access_ctrl_tog; }; #define CCM_TARGET_ROOT_ENABLE BIT(28) #define CCM_TARGET_MUX(x) (((x) - 1) << 24) #define CCM_TARGET_PRE_PODF(x) (((x) - 1) << 16) #define CCM_TARGET_POST_PODF(x) ((x) - 1) /* Target root MUX values - selects the clock source for a block */ /* ARM_A7_CLK_ROOT */ #define CCM_TRGT_MUX_ARM_A7_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_ARM_A7_CLK_ROOT_ARM_PLL BIT(24) #define CCM_TRGT_MUX_ARM_A7_CLK_ROOT_ENET_PLL_DIV2 BIT(25) #define CCM_TRGT_MUX_ARM_A7_CLK_ROOT_DDR_PLL (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_ARM_A7_CLK_ROOT_SYS_PLL BIT(26) #define CCM_TRGT_MUX_ARM_A7_CLK_ROOT_SYS_PLL_PFD0 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_ARM_A7_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_ARM_A7_CLK_ROOT_USB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* ARM_M4_CLK_ROOT */ #define CCM_TRGT_MUX_ARM_M4_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_ARM_M4_CLK_ROOT_SYS_PLL_DIV2 BIT(24) #define CCM_TRGT_MUX_ARM_M4_CLK_ROOT_ENET_PLL_DIV4 BIT(25) #define CCM_TRGT_MUX_ARM_M4_CLK_ROOT_SYS_PLL_PFD2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_ARM_M4_CLK_ROOT_DDR_PLL_DIV2 BIT(26) #define CCM_TRGT_MUX_ARM_M4_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_ARM_M4_CLK_ROOTV_IDEO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_ARM_M4_CLK_ROOTUSB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* MAIN_AXI_CLK_ROOT */ #define CCM_TRGT_MUX_MAIN_AXI_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_MAIN_AXI_CLK_ROOT_SYS_PLL_PFD1 BIT(24) #define CCM_TRGT_MUX_MAIN_AXI_CLK_ROOT_DDR_PLL_DIV2 BIT(25) #define CCM_TRGT_MUX_MAIN_AXI_CLK_ROOT_ENET_PLL_DIV4 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_MAIN_AXI_CLK_ROOT_SYS_PLL_PFD5 BIT(26) #define CCM_TRGT_MUX_MAIN_AXI_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_MAIN_AXI_CLK_ROOT_VIDEO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_MAIN_AXI_CLK_ROOT_SYS_PLL_PFD7 ((BIT(26) | BIT(25) | BIT(24)) /* DISP_AXI_CLK_ROOT */ #define CCM_TRGT_MUX_DISP_AXI_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_DISP_AXI_CLK_ROOT_SYS_PLL_PFD1 BIT(24) #define CCM_TRGT_MUX_DISP_AXI_CLK_ROOT_DDR_PLL_DIV2 BIT(25) #define CCM_TRGT_MUX_DISP_AXI_CLK_ROOT_ENET_PLL_DIV4 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_DISP_AXI_CLK_ROOT_SYS_PLL_PFD6 BIT(26) #define CCM_TRGT_MUX_DISP_AXI_CLK_ROOT_SYS_PLL_PFD7 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_DISP_AXI_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_DISP_AXI_CLK_ROOT_VIDEO_PLL ((BIT(26) | BIT(25) | BIT(24)) /* ENET_AXI_CLK_ROOT */ #define CCM_TRGT_MUX_ENET_AXI_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_ENET_AXI_CLK_ROOT_SYS_PLL_PFD2 BIT(24) #define CCM_TRGT_MUX_ENET_AXI_CLK_ROOT_DDR_PLL_DIV2 BIT(25) #define CCM_TRGT_MUX_ENET_AXI_CLK_ROOT_ENET_PLL_DIV4 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_ENET_AXI_CLK_ROOT_SYS_PLL_DIV2 BIT(26) #define CCM_TRGT_MUX_ENET_AXI_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_ENET_AXI_CLK_ROOT_VIDEO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_ENET_AXI_CLK_ROOT_SYS_PLL_PFD4 ((BIT(26) | BIT(25) | BIT(24)) /* NAND_USDHC_BUS_CLK_ROOT */ #define CM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_AHB BIT(24) #define CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_DDR_PLL_DIV2 BIT(25) #define CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_SYS_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_SYS_PLL_PFD2_DIV2 BIT(26) #define CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_SYS_PLL_PFD6 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_ENET_PLL_DIV4 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_AUDIO_PLL ((BIT(26) | BIT(25) | BIT(24)) /* AHB_CLK_ROOT */ #define CCM_TRGT_MUX_AHB_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_AHB_CLK_ROOT_SYS_PLL_PFD2 BIT(24) #define CCM_TRGT_MUX_AHB_CLK_ROOT_DDR_PLL_DIV2 BIT(25) #define CCM_TRGT_MUX_AHB_CLK_ROOT_SYS_PLL_PFD0 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_AHB_CLK_ROOT_ENET_PLL_DIV8 BIT(26) #define CCM_TRGT_MUX_AHB_CLK_ROOT_USB_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_AHB_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_AHB_CLK_ROOT_VIDEO_PLL ((BIT(26) | BIT(25) | BIT(24)) /* IPG_CLK_ROOT */ #define CCM_TRGT_MUX_IPG_CLK_ROOT_AHB_CLK_ROOT 0 /* DRAM_PHYM_CLK_ROOT */ #define CCM_TRGT_MUX_DRAM_PHYM_CLK_ROOT_DDR_PLL 0 #define CCM_TRGT_MUX_DRAM_PHYM_CLK_ROOT_DRAM_PHYM_ALT_CLK_ROOT BIT(24) /* DRAM_CLK_ROOT */ #define CCM_TRGT_MUX_DRAM_CLK_ROOT_DDR_PLL 0 #define CCM_TRGT_MUX_DRAM_CLK_ROOT_DRAM_ALT_CLK_ROOT BIT(24) /* DRAM_PHYM_ALT_CLK_ROOT */ #define CCM_TRGT_MUX_DRAM_PHYM_ALT_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_DRAM_PHYM_ALT_CLK_ROOT_DDR_PLL_DIV2 BIT(24) #define CCM_TRGT_MUX_DRAM_PHYM_ALT_CLK_ROOT_SYS_PLL BIT(25) #define CCM_TRGT_MUX_DRAM_PHYM_ALT_CLK_ROOT_ENET_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_DRAM_PHYM_ALT_CLK_ROOT_USB_PLL BIT(26) #define CCM_TRGT_MUX_DRAM_PHYM_ALT_CLK_ROOT_SYS_PLL_PFD7 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_DRAM_PHYM_ALT_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_DRAM_PHYM_ALT_CLK_ROOT_VIDEO_PLL ((BIT(26) | BIT(25) | BIT(24)) /* DRAM_ALT_CLK_ROOT */ #define CCM_TRGT_MUX_DRAM_ALT_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_DRAM_ALT_CLK_ROOT_DDR_PLL_DIV2 BIT(24) #define CCM_TRGT_MUX_DRAM_ALT_CLK_ROOT_SYS_PLL BIT(25) #define CCM_TRGT_MUX_DRAM_ALT_CLK_ROOT_ENET_PLL_DIV4 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_DRAM_ALT_CLK_ROOT_USB_PLL BIT(26) #define CCM_TRGT_MUX_DRAM_ALT_CLK_ROOT_SYS_PLL_PFD0 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_DRAM_ALT_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_DRAM_ALT_CLK_ROOT_SYS_PLL_PFD2 ((BIT(26) | BIT(25) | BIT(24)) /* USB_HSIC_CLK_ROOT */ #define CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_SYS_PLL BIT(24) #define CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_USB_PLL BIT(25) #define CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_SYS_PLL_PFD3 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_SYS_PLL_PFD4 BIT(26) #define CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_SYS_PLL_PFD5 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_SYS_PLL_PFD6 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_SYS_PLL_PFD7 ((BIT(26) | BIT(25) | BIT(24)) /* LCDIF_PIXEL_CLK_ROOT */ #define CCM_TRGT_MUX_LCDIF_PIXEL_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_LCDIF_PIXEL_CLK_ROOT_SYS_PLL_PFD5 BIT(24) #define CCM_TRGT_MUX_LCDIF_PIXEL_CLK_ROOT_DDR_PLL_DIV2 BIT(25) #define CCM_TRGT_MUX_LCDIF_PIXEL_CLK_ROOT_EXT_CLK3 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_LCDIF_PIXEL_CLK_ROOT_SYS_PLL_PFD4 BIT(26) #define CCM_TRGT_MUX_LCDIF_PIXEL_CLK_ROOT_SYS_PLL_PFD2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_LCDIF_PIXEL_CLK_ROOT_VIDEO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_LCDIF_PIXEL_CLK_ROOT_USB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* MIPI_DSI_CLK_ROOT */ #define CCM_TRGT_MUX_MIPI_DSI_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_MIPI_DSI_CLK_ROOT_SYS_PLL_PFD5 BIT(24) #define CCM_TRGT_MUX_MIPI_DSI_CLK_ROOT_SYS_PLL_PFD3 BIT(25) #define CCM_TRGT_MUX_MIPI_DSI_CLK_ROOT_SYS_PLL (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_MIPI_DSI_CLK_ROOT_SYS_PLL_PFD0_DIV2 BIT(26) #define CCM_TRGT_MUX_MIPI_DSI_CLK_ROOT_DDR_PLL_DIV2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_MIPI_DSI_CLK_ROOT_VIDEO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_MIPI_DSI_CLK_ROOT_AUDIO_PLL ((BIT(26) | BIT(25) | BIT(24)) /* MIPI_CSI_CLK_ROOT */ #define CCM_TRGT_MUX_MIPI_CSI_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_MIPI_CSI_CLK_ROOT_SYS_PLL_PFD4 BIT(24) #define CCM_TRGT_MUX_MIPI_CSI_CLK_ROOT_SYS_PLL_PFD3 BIT(25) #define CCM_TRGT_MUX_MIPI_CSI_CLK_ROOT_SYS_PLL (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_MIPI_CSI_CLK_ROOT_SYS_PLL_PFD0_DIV2 BIT(26) #define CCM_TRGT_MUX_MIPI_CSI_CLK_ROOT_DDR_PLL_DIV2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_MIPI_CSI_CLK_ROOT_VIDEO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_MIPI_CSI_CLK_ROOT_AUDIO_PLL ((BIT(26) | BIT(25) | BIT(24)) /* MIPI_DPHY_REF_CLK_ROOT */ #define CCM_TRGT_MUX_MIPI_DPHY_REF_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_MIPI_DPHY_REF_CLK_ROOT_SYS_PLL_DIV4 BIT(24) #define CCM_TRGT_MUX_MIPI_DPHY_REF_CLK_ROOT_DDR_PLL_DIV2 BIT(25) #define CCM_TRGT_MUX_MIPI_DPHY_REF_CLK_ROOT_SYS_PLL_PFD5 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_MIPI_DPHY_REF_CLK_ROOT_REF_1M BIT(26) #define CCM_TRGT_MUX_MIPI_DPHY_REF_CLK_ROOT_EXT_CLK2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_MIPI_DPHY_REF_CLK_ROOT_VIDEO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_MIPI_DPHY_REF_CLK_ROOT_EXT_CLK3 ((BIT(26) | BIT(25) | BIT(24)) /* SAI1_CLK_ROOT */ #define CCM_TRGT_MUX_SAI1_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_SAI1_CLK_ROOT_SYS_PLL_PFD2_DIV2 BIT(24) #define CCM_TRGT_MUX_SAI1_CLK_ROOT_AUDIO_PLL BIT(25) #define CCM_TRGT_MUX_SAI1_CLK_ROOT_DDR_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_SAI1_CLK_ROOT_VIDEO_PLL BIT(26) #define CCM_TRGT_MUX_SAI1_CLK_ROOT_SYS_PLL_PFD4 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_SAI1_CLK_ROOT_ENET_PLL_DIV8 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_SAI1_CLK_ROOT_EXT_CLK2 ((BIT(26) | BIT(25) | BIT(24)) /* SAI2_CLK_ROOT */ #define CCM_TRGT_MUX_SAI2_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_SAI2_CLK_ROOT_SYS_PLL_PFD2_DIV2 BIT(24) #define CCM_TRGT_MUX_SAI2_CLK_ROOT_AUDIO_PLL BIT(25) #define CCM_TRGT_MUX_SAI2_CLK_ROOT_DDR_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_SAI2_CLK_ROOT_VIDEO_PLL BIT(26) #define CCM_TRGT_MUX_SAI2_CLK_ROOT_SYS_PLL_PFD4 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_SAI2_CLK_ROOT_ENET_PLL_DIV8 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_SAI2_CLK_ROOT_EXT_CLK2 ((BIT(26) | BIT(25) | BIT(24)) /* SAI3_CLK_ROOT */ #define CCM_TRGT_MUX_SAI3_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_SAI3_CLK_ROOT_SYS_PLL_PFD2_DIV2 BIT(24) #define CCM_TRGT_MUX_SAI3_CLK_ROOT_AUDIO_PLL BIT(25) #define CCM_TRGT_MUX_SAI3_CLK_ROOT_DDR_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_SAI3_CLK_ROOT_VIDEO_PLL BIT(26) #define CCM_TRGT_MUX_SAI3_CLK_ROOT_SYS_PLL_PFD4 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_SAI3_CLK_ROOT_ENET_PLL_DIV8 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_SAI3_CLK_ROOT_EXT_CLK3 ((BIT(26) | BIT(25) | BIT(24)) /* ENET1_REF_CLK_ROOT */ #define CCM_TRGT_MUX_ENET1_REF_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_ENET1_REF_CLK_ROOT_ENET_PLL_DIV8 BIT(24) #define CCM_TRGT_MUX_ENET1_REF_CLK_ROOT_ENET_PLL_DIV20 BIT(25) #define CCM_TRGT_MUX_ENET1_REF_CLK_ROOT_ENET_PLL_DIV40 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_ENET1_REF_CLK_ROOT_SYS_PLL_DIV4 BIT(26) #define CCM_TRGT_MUX_ENET1_REF_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_ENET1_REF_CLK_ROOT_VIDEO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_ENET1_REF_CLK_ROOT_EXT_CLK4 ((BIT(26) | BIT(25) | BIT(24)) /* ENET1_TIME_CLK_ROOT */ #define CCM_TRGT_MUX_ENET1_TIME_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_ENET1_TIME_CLK_ROOT_ENET_PLL_DIV10 BIT(24) #define CCM_TRGT_MUX_ENET1_TIME_CLK_ROOT_AUDIO_PLL BIT(25) #define CCM_TRGT_MUX_ENET1_TIME_CLK_ROOT_EXT_CLK1 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_ENET1_TIME_CLK_ROOT_EXT_CLK2 BIT(26) #define CCM_TRGT_MUX_ENET1_TIME_CLK_ROOT_EXT_CLK3 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_ENET1_TIME_CLK_ROOT_EXT_CLK4 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_ENET1_TIME_CLK_ROOT_VIDEO_PLL ((BIT(26) | BIT(25) | BIT(24)) /* ENET_PHY_REF_CLK_ROOT */ #define CCM_TRGT_MUX_ENET_PHY_REF_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_ENET_PHY_REF_CLK_ROOT_ENET_PLL_DIV40 BIT(24) #define CCM_TRGT_MUX_ENET_PHY_REF_CLK_ROOT_ENET_PLL_DIV20 BIT(25) #define CCM_TRGT_MUX_ENET_PHY_REF_CLK_ROOT_ENET_PLL_DIV8 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_ENET_PHY_REF_CLK_ROOT_DDR_PLL_DIV2 BIT(26) #define CCM_TRGT_MUX_ENET_PHY_REF_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_ENET_PHY_REF_CLK_ROOT_VIDEO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_ENET_PHY_REF_CLK_ROOT_SYS_PLL_PFD3 ((BIT(26) | BIT(25) | BIT(24)) /* EIM_CLK_ROOT */ #define CCM_TRGT_MUX_EIM_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_EIM_CLK_ROOT_SYS_PLL_PFD2_DIV2 BIT(24) #define CCM_TRGT_MUX_EIM_CLK_ROOT_SYS_PLL_DIV4 BIT(25) #define CCM_TRGT_MUX_EIM_CLK_ROOT_DDR_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_EIM_CLK_ROOT_SYS_PLL_PFD2 BIT(26) #define CCM_TRGT_MUX_EIM_CLK_ROOT_SYS_PLL_PFD3 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_EIM_CLK_ROOT_ENET_PLL_DIV8 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_EIM_CLK_ROOT_USB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* NAND_CLK_ROOT */ #define CCM_TRGT_MUX_NAND_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_NAND_CLK_ROOT_SYS_PLL BIT(24) #define CCM_TRGT_MUX_NAND_CLK_ROOT_DDR_PLL_DIV2 BIT(25) #define CCM_TRGT_MUX_NAND_CLK_ROOT_SYS_PLL_PFD0 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_NAND_CLK_ROOT_SYS_PLL_PFD3 BIT(26) #define CCM_TRGT_MUX_NAND_CLK_ROOT_ENET_PLL_DIV2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_NAND_CLK_ROOT_ENET_PLL_DIV4 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_NAND_CLK_ROOT_VIDEO_PLL ((BIT(26) | BIT(25) | BIT(24)) /* QSPI_CLK_ROOT */ #define CCM_TRGT_MUX_QSPI_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_QSPI_CLK_ROOT_SYS_PLL_PFD4 BIT(24) #define CCM_TRGT_MUX_QSPI_CLK_ROOT_DDR_PLL_DIV2 BIT(25) #define CCM_TRGT_MUX_QSPI_CLK_ROOT_ENET_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_QSPI_CLK_ROOT_SYS_PLL_PFD3 BIT(26) #define CCM_TRGT_MUX_QSPI_CLK_ROOT_SYS_PLL_PFD2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_QSPI_CLK_ROOT_SYS_PLL_PFD6 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_QSPI_CLK_ROOT_SYS_PLL_PFD7 ((BIT(26) | BIT(25) | BIT(24)) /* USDHC1_CLK_ROOT */ #define CM_TRGT_MUX_USDHC1_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_USDHC1_CLK_ROOT_SYS_PLL_PFD0 BIT(24) #define CCM_TRGT_MUX_USDHC1_CLK_ROOT_DDR_PLL_DIV2 BIT(25) #define CCM_TRGT_MUX_USDHC1_CLK_ROOT_ENET_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_USDHC1_CLK_ROOT_SYS_PLL_PFD4 BIT(26) #define CCM_TRGT_MUX_USDHC1_CLK_ROOT_SYS_PLL_PFD2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_USDHC1_CLK_ROOT_SYS_PLL_PFD6 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_USDHC1_CLK_ROOT_SYS_PLL_PFD7 ((BIT(26) | BIT(25) | BIT(24)) /* USDHC2_CLK_ROOT */ #define CCM_TRGT_MUX_USDHC2_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_USDHC2_CLK_ROOT_SYS_PLL_PFD0 BIT(24) #define CCM_TRGT_MUX_USDHC2_CLK_ROOT_DDR_PLL_DIV2 BIT(25) #define CCM_TRGT_MUX_USDHC2_CLK_ROOT_ENET_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_USDHC2_CLK_ROOT_SYS_PLL_PFD4 BIT(26) #define CCM_TRGT_MUX_USDHC2_CLK_ROOT_SYS_PLL_PFD2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_USDHC2_CLK_ROOT_SYS_PLL_PFD6 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_USDHC2_CLK_ROOT_SYS_PLL_PFD7 ((BIT(26) | BIT(25) | BIT(24)) /* USDHC3_CLK_ROOT */ #define CCM_TRGT_MUX_USDHC3_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_USDHC3_CLK_ROOT_SYS_PLL_PFD0 BIT(24) #define CCM_TRGT_MUX_USDHC3_CLK_ROOT_DDR_PLL_DIV2 BIT(25) #define CCM_TRGT_MUX_USDHC3_CLK_ROOT_ENET_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_USDHC3_CLK_ROOT_SYS_PLL_PFD4 BIT(26) #define CCM_TRGT_MUX_USDHC3_CLK_ROOT_SYS_PLL_PFD2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_USDHC3_CLK_ROOT_SYS_PLL_PFD6 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_USDHC3_CLK_ROOT_SYS_PLL_PFD7 ((BIT(26) | BIT(25) | BIT(24)) /* CAN1_CLK_ROOT */ #define CCM_TRGT_MUX_CAN1_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_CAN1_CLK_ROOT_SYS_PLL_DIV4 BIT(24) #define CCM_TRGT_MUX_CAN1_CLK_ROOT_DDR_PLL_DIV2 BIT(25) #define CCM_TRGT_MUX_CAN1_CLK_ROOT_SYS_PLL (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_CAN1_CLK_ROOT_ENET_PLL_DIV25 BIT(26) #define CCM_TRGT_MUX_CAN1_CLK_ROOT_USB_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_CAN1_CLK_ROOT_EXT_CLK1 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_CAN1_CLK_ROOT_EXT_CLK4 ((BIT(26) | BIT(25) | BIT(24)) /* CAN2_CLK_ROOT */ #define CCM_TRGT_MUX_CAN2_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_CAN2_CLK_ROOT_SYS_PLL_DIV4 BIT(24) #define CCM_TRGT_MUX_CAN2_CLK_ROOT_DDR_PLL_DIV2 BIT(25) #define CCM_TRGT_MUX_CAN2_CLK_ROOT_SYS_PLL (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_CAN2_CLK_ROOT_ENET_PLL_DIV25 BIT(26) #define CCM_TRGT_MUX_CAN2_CLK_ROOT_USB_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_CAN2_CLK_ROOT_EXT_CLK1 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_CAN2_CLK_ROOT_EXT_CLK3 ((BIT(26) | BIT(25) | BIT(24)) /* I2C1_CLK_ROOT */ #define CCM_TRGT_MUX_I2C1_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_I2C1_CLK_ROOT_SYS_PLL_DIV4 BIT(24) #define CCM_TRGT_MUX_I2C1_CLK_ROOT_ENET_PLL_DIV20 BIT(25) #define CCM_TRGT_MUX_I2C1_CLK_ROOT_DDR_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_I2C1_CLK_ROOT_AUDIO_PLL BIT(26) #define CCM_TRGT_MUX_I2C1_CLK_ROOT_VIDEO_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_I2C1_CLK_ROOT_USB_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_I2C1_CLK_ROOT_SYS_PLL_PFD2_DIV2 ((BIT(26) | BIT(25) | BIT(24)) /* I2C2_CLK_ROOT */ #define CCM_TRGT_MUX_I2C2_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_I2C2_CLK_ROOT_SYS_PLL_DIV4 BIT(24) #define CCM_TRGT_MUX_I2C2_CLK_ROOT_ENET_PLL_DIV20 BIT(25) #define CCM_TRGT_MUX_I2C2_CLK_ROOT_DDR_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_I2C2_CLK_ROOT_AUDIO_PLL BIT(26) #define CCM_TRGT_MUX_I2C2_CLK_ROOT_VIDEO_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_I2C2_CLK_ROOT_USB_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_I2C2_CLK_ROOT_SYS_PLL_PFD2_DIV2 ((BIT(26) | BIT(25) | BIT(24)) /* I2C3_CLK_ROOT */ #define CCM_TRGT_MUX_I2C3_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_I2C3_CLK_ROOT_SYS_PLL_DIV4 BIT(24) #define CCM_TRGT_MUX_I2C3_CLK_ROOT_ENET_PLL_DIV20 BIT(25) #define CCM_TRGT_MUX_I2C3_CLK_ROOT_DDR_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_I2C3_CLK_ROOT_AUDIO_PLL BIT(26) #define CCM_TRGT_MUX_I2C3_CLK_ROOT_VIDEO_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_I2C3_CLK_ROOT_USB_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_I2C3_CLK_ROOT_SYS_PLL_PFD2_DIV2 ((BIT(26) | BIT(25) | BIT(24)) /* I2C4_CLK_ROOT */ #define CCM_TRGT_MUX_I2C4_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_I2C4_CLK_ROOT_SYS_PLL_DIV4 BIT(24) #define CCM_TRGT_MUX_I2C4_CLK_ROOT_ENET_PLL_DIV20 BIT(25) #define CCM_TRGT_MUX_I2C4_CLK_ROOT_DDR_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_I2C4_CLK_ROOT_AUDIO_PLL BIT(26) #define CCM_TRGT_MUX_I2C4_CLK_ROOT_VIDEO_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_I2C4_CLK_ROOT_USB_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_I2C4_CLK_ROOT_SYS_PLL_PFD2_DIV2 ((BIT(26) | BIT(25) | BIT(24)) /* UART1_CLK_ROOT */ #define CCM_TRGT_MUX_UART1_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_UART1_CLK_ROOT_SYS_PLL_DIV2 BIT(24) #define CCM_TRGT_MUX_UART1_CLK_ROOT_ENET_PLL_DIV25 BIT(25) #define CCM_TRGT_MUX_UART1_CLK_ROOT_ENET_PLL_DIV10 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_UART1_CLK_ROOT_SYS_PLL BIT(26) #define CCM_TRGT_MUX_UART1_CLK_ROOT_EXT_CLK2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_UART1_CLK_ROOT_EXT_CLK4 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_UART1_CLK_ROOT_USB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* UART2_CLK_ROOT */ #define CCM_TRGT_MUX_UART2_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_UART2_CLK_ROOT_SYS_PLL_DIV2 BIT(24) #define CCM_TRGT_MUX_UART2_CLK_ROOT_ENET_PLL_DIV25 BIT(25) #define CCM_TRGT_MUX_UART2_CLK_ROOT_ENET_PLL_DIV10 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_UART2_CLK_ROOT_SYS_PLL BIT(26) #define CCM_TRGT_MUX_UART2_CLK_ROOT_EXT_CLK2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_UART2_CLK_ROOT_EXT_CLK3 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_UART2_CLK_ROOT_USB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* UART3_CLK_ROOT */ #define CCM_TRGT_MUX_UART3_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_UART3_CLK_ROOT_SYS_PLL_DIV2 BIT(24) #define CCM_TRGT_MUX_UART3_CLK_ROOT_ENET_PLL_DIV25 BIT(25) #define CCM_TRGT_MUX_UART3_CLK_ROOT_ENET_PLL_DIV10 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_UART3_CLK_ROOT_SYS_PLL BIT(26) #define CCM_TRGT_MUX_UART3_CLK_ROOT_EXT_CLK2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_UART3_CLK_ROOT_EXT_CLK4 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_UART3_CLK_ROOT_USB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* UART4_CLK_ROOT */ #define CCM_TRGT_MUX_UART4_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_UART4_CLK_ROOT_SYS_PLL_DIV2 BIT(24) #define CCM_TRGT_MUX_UART4_CLK_ROOT_ENET_PLL_DIV25 BIT(25) #define CCM_TRGT_MUX_UART4_CLK_ROOT_ENET_PLL_DIV10 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_UART4_CLK_ROOT_SYS_PLL BIT(26) #define CCM_TRGT_MUX_UART4_CLK_ROOT_EXT_CLK2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_UART4_CLK_ROOT_EXT_CLK3 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_UART4_CLK_ROOT_USB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* UART5_CLK_ROOT */ #define CCM_TRGT_MUX_UART5_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_UART5_CLK_ROOT_SYS_PLL_DIV2 BIT(24) #define CCM_TRGT_MUX_UART5_CLK_ROOT_ENET_PLL_DIV25 BIT(25) #define CCM_TRGT_MUX_UART5_CLK_ROOT_ENET_PLL_DIV10 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_UART5_CLK_ROOT_SYS_PLL BIT(26) #define CCM_TRGT_MUX_UART5_CLK_ROOT_EXT_CLK2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_UART5_CLK_ROOT_EXT_CLK4 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_UART5_CLK_ROOT_USB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* UART6_CLK_ROOT */ #define CCM_TRGT_MUX_UART6_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_UART6_CLK_ROOT_SYS_PLL_DIV2 BIT(24) #define CCM_TRGT_MUX_UART6_CLK_ROOT_ENET_PLL_DIV25 BIT(25) #define CCM_TRGT_MUX_UART6_CLK_ROOT_ENET_PLL_DIV10 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_UART6_CLK_ROOT_SYS_PLL BIT(26) #define CCM_TRGT_MUX_UART6_CLK_ROOT_EXT_CLK2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_UART6_CLK_ROOT_EXT_CLK3 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_UART6_CLK_ROOT_USB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* UART7_CLK_ROOT */ #define CCM_TRGT_MUX_UART7_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_UART7_CLK_ROOT_SYS_PLL_DIV2 BIT(24) #define CCM_TRGT_MUX_UART7_CLK_ROOT_ENET_PLL_DIV25 BIT(25) #define CCM_TRGT_MUX_UART7_CLK_ROOT_ENET_PLL_DIV10 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_UART7_CLK_ROOT_SYS_PLL BIT(26) #define CCM_TRGT_MUX_UART7_CLK_ROOT_EXT_CLK2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_UART7_CLK_ROOT_EXT_CLK4 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_UART7_CLK_ROOT_USB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* ECSPI1_CLK_ROOT */ #define CCM_TRGT_MUX_ECSPI1_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_ECSPI1_CLK_ROOT_SYS_PLL_DIV2 BIT(24) #define CCM_TRGT_MUX_ECSPI1_CLK_ROOT_ENET_PLL_DIV25 BIT(25) #define CCM_TRGT_MUX_ECSPI1_CLK_ROOT_SYS_PLL_DIV4 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_ECSPI1_CLK_ROOT_SYS_PLL BIT(26) #define CCM_TRGT_MUX_ECSPI1_CLK_ROOT_SYS_PLL_PFD4 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_ECSPI1_CLK_ROOT_ENET_PLL_DIV4 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_ECSPI1_CLK_ROOT_USB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* ECSPI2_CLK_ROOT */ #define CCM_TRGT_MUX_ECSPI2_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_ECSPI2_CLK_ROOT_SYS_PLL_DIV2 BIT(24) #define CCM_TRGT_MUX_ECSPI2_CLK_ROOT_ENET_PLL_DIV25 BIT(25) #define CCM_TRGT_MUX_ECSPI2_CLK_ROOT_SYS_PLL_DIV4 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_ECSPI2_CLK_ROOT_SYS_PLL BIT(26) #define CCM_TRGT_MUX_ECSPI2_CLK_ROOT_SYS_PLL_PFD4 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_ECSPI2_CLK_ROOT_ENET_PLL_DIV4 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_ECSPI2_CLK_ROOT_USB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* ECSPI3_CLK_ROOT */ #define CCM_TRGT_MUX_ECSPI3_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_ECSPI3_CLK_ROOT_SYS_PLL_DIV2 BIT(24) #define CCM_TRGT_MUX_ECSPI3_CLK_ROOT_ENET_PLL_DIV25 BIT(25) #define CCM_TRGT_MUX_ECSPI3_CLK_ROOT_SYS_PLL_DIV4 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_ECSPI3_CLK_ROOT_SYS_PLL BIT(26) #define CCM_TRGT_MUX_ECSPI3_CLK_ROOT_SYS_PLL_PFD4 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_ECSPI3_CLK_ROOT_ENET_PLL_DIV4 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_ECSPI3_CLK_ROOT_USB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* ECSPI4_CLK_ROOT */ #define CCM_TRGT_MUX_ECSPI4_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_ECSPI4_CLK_ROOT_SYS_PLL_DIV2 BIT(24) #define CCM_TRGT_MUX_ECSPI4_CLK_ROOT_ENET_PLL_DIV25 BIT(25) #define CCM_TRGT_MUX_ECSPI4_CLK_ROOT_SYS_PLL_DIV4 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_ECSPI4_CLK_ROOT_SYS_PLL BIT(26) #define CCM_TRGT_MUX_ECSPI4_CLK_ROOT_SYS_PLL_PFD4 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_ECSPI4_CLK_ROOT_ENET_PLL_DIV4 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_ECSPI4_CLK_ROOT_USB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* PWM1_CLK_ROOT */ #define CCM_TRGT_MUX_PWM1_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_PWM1_CLK_ROOT_ENET_PLL_DIV10 BIT(24) #define CCM_TRGT_MUX_PWM1_CLK_ROOT_SYS_PLL_DIV4 BIT(25) #define CCM_TRGT_MUX_PWM1_CLK_ROOT_ENET_PLL_DIV25 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_PWM1_CLK_ROOT_AUDIO_PLL BIT(26) #define CCM_TRGT_MUX_PWM1_CLK_ROOT_EXT_CLK1 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_PWM1_CLK_ROOT_REF_1M (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_PWM1_CLK_ROOT_VIDEO_PLL ((BIT(26) | BIT(25) | BIT(24)) /* PWM2_CLK_ROOT */ #define CCM_TRGT_MUX_PWM2_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_PWM2_CLK_ROOT_ENET_PLL_DIV10 BIT(24) #define CCM_TRGT_MUX_PWM2_CLK_ROOT_SYS_PLL_DIV4 BIT(25) #define CCM_TRGT_MUX_PWM2_CLK_ROOT_ENET_PLL_DIV25 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_PWM2_CLK_ROOT_AUDIO_PLL BIT(26) #define CCM_TRGT_MUX_PWM2_CLK_ROOT_EXT_CLK1 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_PWM2_CLK_ROOT_REF_1M (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_PWM2_CLK_ROOT_VIDEO_PLL ((BIT(26) | BIT(25) | BIT(24)) /* PWM3_CLK_ROOT */ #define CCM_TRGT_MUX_PWM3_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_PWM3_CLK_ROOT_ENET_PLL_DIV10 BIT(24) #define CCM_TRGT_MUX_PWM3_CLK_ROOT_SYS_PLL_DIV4 BIT(25) #define CCM_TRGT_MUX_PWM3_CLK_ROOT_ENET_PLL_DIV25 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_PWM3_CLK_ROOT_AUDIO_PLL BIT(26) #define CCM_TRGT_MUX_PWM3_CLK_ROOT_EXT_CLK2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_PWM3_CLK_ROOT_REF_1M (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_PWM3_CLK_ROOT_VIDEO_PLL ((BIT(26) | BIT(25) | BIT(24)) /* PWM4_CLK_ROOT */ #define CCM_TRGT_MUX_PWM4_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_PWM4_CLK_ROOT_ENET_PLL_DIV10 BIT(24) #define CCM_TRGT_MUX_PWM4_CLK_ROOT_SYS_PLL_DIV4 BIT(25) #define CCM_TRGT_MUX_PWM4_CLK_ROOT_ENET_PLL_DIV25 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_PWM4_CLK_ROOT_AUDIO_PLL BIT(26) #define CCM_TRGT_MUX_PWM4_CLK_ROOT_EXT_CLK2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_PWM4_CLK_ROOT_REF_1M (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_PWM4_CLK_ROOT_VIDEO_PLL ((BIT(26) | BIT(25) | BIT(24)) /* FLEXTIMER1_CLK_ROOT */ #define CCM_TRGT_MUX_FLEXTIMER1_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_FLEXTIMER1_CLK_ROOT_ENET_PLL_DIV10 BIT(24) #define CCM_TRGT_MUX_FLEXTIMER1_CLK_ROOT_SYS_PLL_DIV4 BIT(25) #define CCM_TRGT_MUX_FLEXTIMER1_CLK_ROOT_ENET_PLL_DIV25 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_FLEXTIMER1_CLK_ROOT_AUDIO_PLL BIT(26) #define CCM_TRGT_MUX_FLEXTIMER1_CLK_ROOT_EXT_CLK3 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_FLEXTIMER1_CLK_ROOT_REF_1M (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_FLEXTIMER1_CLK_ROOT_VIDEO_PLL ((BIT(26) | BIT(25) | BIT(24)) /* FLEXTIMER2_CLK_ROOT */ #define CCM_TRGT_MUX_FLEXTIMER2_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_FLEXTIMER2_CLK_ROOT_ENET_PLL_DIV10 BIT(24) #define CCM_TRGT_MUX_FLEXTIMER2_CLK_ROOT_SYS_PLL_DIV4 BIT(25) #define CCM_TRGT_MUX_FLEXTIMER2_CLK_ROOT_ENET_PLL_DIV25 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_FLEXTIMER2_CLK_ROOT_AUDIO_PLL BIT(26) #define CCM_TRGT_MUX_FLEXTIMER2_CLK_ROOT_EXT_CLK3 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_FLEXTIMER2_CLK_ROOT_REF_1M (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_FLEXTIMER2_CLK_ROOT_VIDEO_PLL ((BIT(26) | BIT(25) | BIT(24)) /* Target SIM1_CLK_ROOT */ #define CCM_TRGT_MUX_SIM1_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_SIM1_CLK_ROOT_SYS_PLL_PFD2_DIV2 BIT(24) #define CCM_TRGT_MUX_SIM1_CLK_ROOT_SYS_PLL_DIV4 BIT(25) #define CCM_TRGT_MUX_SIM1_CLK_ROOT_DDR_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_SIM1_CLK_ROOT_USB_PLL BIT(26) #define CCM_TRGT_MUX_SIM1_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_SIM1_CLK_ROOT_ENET_PLL_DIV8 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_SIM1_CLK_ROOT_SYS_PLL_PFD7 ((BIT(26) | BIT(25) | BIT(24)) /* Target SIM2_CLK_ROOT */ #define CCM_TRGT_MUX_SIM2_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_SIM2_CLK_ROOT_SYS_PLL_PFD2_DIV2 BIT(24) #define CCM_TRGT_MUX_SIM2_CLK_ROOT_SYS_PLL_DIV4 BIT(25) #define CCM_TRGT_MUX_SIM2_CLK_ROOT_DDR_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_SIM2_CLK_ROOT_USB_PLL BIT(26) #define CCM_TRGT_MUX_SIM2_CLK_ROOT_VIDEO_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_SIM2_CLK_ROOT_ENET_PLL_DIV8 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_SIM2_CLK_ROOT_SYS_PLL_PFD7 ((BIT(26) | BIT(25) | BIT(24)) /* Target GPT1_CLK_ROOT */ #define CCM_TRGT_MUX_GPT1_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_GPT1_CLK_ROOT_ENET_PLL_DIV10 BIT(24) #define CCM_TRGT_MUX_GPT1_CLK_ROOT_SYS_PLL_PFD0 BIT(25) #define CCM_TRGT_MUX_GPT1_CLK_ROOT_ENET_PLL_DIV25 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_GPT1_CLK_ROOT_VIDEO_PLL BIT(26) #define CCM_TRGT_MUX_GPT1_CLK_ROOT_REF_1M (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_GPT1_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_GPT1_CLK_ROOT_EXT_CLK1 ((BIT(26) | BIT(25) | BIT(24)) /* Target GPT2_CLK_ROOT */ #define CCM_TRGT_MUX_GPT2_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_GPT2_CLK_ROOT_ENET_PLL_DIV10 BIT(24) #define CCM_TRGT_MUX_GPT2_CLK_ROOT_SYS_PLL_PFD0 BIT(25) #define CCM_TRGT_MUX_GPT2_CLK_ROOT_ENET_PLL_DIV25 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_GPT2_CLK_ROOT_VIDEO_PLL BIT(26) #define CCM_TRGT_MUX_GPT2_CLK_ROOT_REF_1M (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_GPT2_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_GPT2_CLK_ROOT_EXT_CLK2 ((BIT(26) | BIT(25) | BIT(24)) /* Target GPT3_CLK_ROOT */ #define CCM_TRGT_MUX_GPT3_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_GPT3_CLK_ROOT_ENET_PLL_DIV10 BIT(24) #define CCM_TRGT_MUX_GPT3_CLK_ROOT_SYS_PLL_PFD0 BIT(25) #define CCM_TRGT_MUX_GPT3_CLK_ROOT_ENET_PLL_DIV25 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_GPT3_CLK_ROOT_VIDEO_PLL BIT(26) #define CCM_TRGT_MUX_GPT3_CLK_ROOT_REF_1M (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_GPT3_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_GPT3_CLK_ROOT_EXT_CLK3 ((BIT(26) | BIT(25) | BIT(24)) /*Target GPT4_CLK_ROOT */ #define CCM_TRGT_MUX_GPT4_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_GPT4_CLK_ROOT_ENET_PLL_DIV10 BIT(24) #define CCM_TRGT_MUX_GPT4_CLK_ROOT_SYS_PLL_PFD0 BIT(25) #define CCM_TRGT_MUX_GPT4_CLK_ROOT_ENET_PLL_DIV25 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_GPT4_CLK_ROOT_VIDEO_PLL BIT(26) #define CCM_TRGT_MUX_GPT4_CLK_ROOT_REF_1M (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_GPT4_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_GPT4_CLK_ROOT_EXT_CLK4 ((BIT(26) | BIT(25) | BIT(24)) /* Target TRACE_CLK_ROOT */ #define CCM_TRGT_MUX_TRACE_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_TRACE_CLK_ROOT_SYS_PLL_PFD2_DIV2 BIT(24) #define CCM_TRGT_MUX_TRACE_CLK_ROOT_SYS_PLL_DIV4 BIT(25) #define CCM_TRGT_MUX_TRACE_CLK_ROOT_DDR_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_TRACE_CLK_ROOT_ENET_PLL_DIV8 BIT(26) #define CCM_TRGT_MUX_TRACE_CLK_ROOT_USB_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_TRACE_CLK_ROOT_EXT_CLK2 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_TRACE_CLK_ROOT_EXT_CLK3 ((BIT(26) | BIT(25) | BIT(24)) /* Target WDOG_CLK_ROOT */ #define CCM_TRGT_MUX_WDOG_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_WDOG_CLK_ROOT_SYS_PLL_PFD2_DIV2 BIT(24) #define CCM_TRGT_MUX_WDOG_CLK_ROOT_SYS_PLL_DIV4 BIT(25) #define CCM_TRGT_MUX_WDOG_CLK_ROOT_DDR_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_WDOG_CLK_ROOT_ENET_PLL_DIV8 BIT(26) #define CCM_TRGT_MUX_WDOG_CLK_ROOT_USB_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_WDOG_CLK_ROOT_REF_1M (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_WDOG_CLK_ROOT_SYS_PLL_PFD1_DIV2 ((BIT(26) | BIT(25) | BIT(24)) #define WDOG_DEFAULT_CLK_SELECT (CCM_TARGET_ROOT_ENABLE |\ CCM_TRGT_MUX_WDOG_CLK_ROOT_OSC_24M) /* Target CSI_MCLK_CLK_ROOT */ #define CCM_TRGT_MUX_CSI_MCLK_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_CSI_MCLK_CLK_ROOT_SYS_PLL_PFD2_DIV2 BIT(24) #define CCM_TRGT_MUX_CSI_MCLK_CLK_ROOT_SYS_PLL_DIV4 BIT(25) #define CCM_TRGT_MUX_CSI_MCLK_CLK_ROOT_DDR_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_CSI_MCLK_CLK_ROOT_ENET_PLL_DIV8 BIT(26) #define CCM_TRGT_MUX_CSI_MCLK_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_CSI_MCLK_CLK_ROOT_VIDEO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_CSI_MCLK_CLK_ROOT_USB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* Target AUDIO_MCLK_CLK_ROOT */ #define CCM_TRGT_MUX_AUDIO_MCLK_CLK_ROOT_OSC_24M 0 #define CCM_TRGT_MUX_AUDIO_MCLK_CLK_ROOT_SYS_PLL_PFD2_DIV2 BIT(24) #define CCM_TRGT_MUX_AUDIO_MCLK_CLK_ROOT_SYS_PLL_DIV4 BIT(25) #define CCM_TRGT_MUX_AUDIO_MCLK_CLK_ROOT_DDR_PLL_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_AUDIO_MCLK_CLK_ROOT_ENET_PLL_DIV8 BIT(26) #define CCM_TRGT_MUX_AUDIO_MCLK_CLK_ROOT_AUDIO_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_AUDIO_MCLK_CLK_ROOT_VIDEO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_AUDIO_MCLK_CLK_ROOT_USB_PLL ((BIT(26) | BIT(25) | BIT(24)) /* Target CCM_CLKO1 */ #define CCM_TRGT_MUX_CCM_CLKO1_OSC_24M 0 #define CCM_TRGT_MUX_CCM_CLKO1_SYS_PLL BIT(24) #define CCM_TRGT_MUX_CCM_CLKO1_SYS_PLL_DIV2 BIT(25) #define CCM_TRGT_MUX_CCM_CLKO1_SYS_PLL_PFD0_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_CCM_CLKO1_SYS_PLL_PFD3 BIT(26) #define CCM_TRGT_MUX_CCM_CLKO1_ENET_PLL_DIV2 (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_CCM_CLKO1_DDR_PLL_DIV2 (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_CCM_CLKO1_REF_1M ((BIT(26) | BIT(25) | BIT(24)) /* Target CCM_CLKO2 */ #define CCM_TRGT_MUX_CCM_CLKO2_OSC_24M 0 #define CCM_TRGT_MUX_CCM_CLKO2_SYS_PLL_DIV2 BIT(24) #define CCM_TRGT_MUX_CCM_CLKO2_SYS_PLL_PFD0 BIT(25) #define CCM_TRGT_MUX_CCM_CLKO2_SYS_PLL_PFD1_DIV2 (BIT(25) | BIT(24)) #define CCM_TRGT_MUX_CCM_CLKO2_SYS_PLL_PFD4 BIT(26) #define CCM_TRGT_MUX_CCM_CLKO2_AUDIO_PLL (BIT(26) | BIT(24)) #define CCM_TRGT_MUX_CCM_CLKO2_VIDEO_PLL (BIT(26) | BIT(25)) #define CCM_TRGT_MUX_CCM_CLKO2_OSC_32K ((BIT(26) | BIT(25) | BIT(24)) /* * See Table 5-11 in i.MX7 Solo Reference manual rev 0.1 * The indices must be calculated by dividing the offset by * sizeof (struct ccm_target_root_ctrl) => 0x80 bytes for each index */ enum { CCM_TRT_ID_ARM_A7_CLK_ROOT = 0, CCM_TRT_ID_ARM_M4_CLK_ROOT = 1, CCM_TRT_ID_MAIN_AXI_CLK_ROOT = 16, CCM_TRT_ID_DISP_AXI_CLK_ROOT = 17, CCM_TRT_ID_ENET_AXI_CLK_ROOT = 18, CCM_TRT_ID_NAND_USDHC_BUS_CLK_ROOT = 19, CCM_TRT_ID_AHB_CLK_ROOT = 32, CCM_TRT_ID_IPG_CLK_ROOT = 33, CCM_TRT_ID_DRAM_PHYM_CLK_ROOT = 48, CCM_TRT_ID_DRAM_CLK_ROOT = 49, CCM_TRT_ID_DRAM_PHYM_ALT_CLK_ROOT = 64, CCM_TRT_ID_DRAM_ALT_CLK_ROOT = 65, CCM_TRT_ID_USB_HSIC_CLK_ROOT = 66, CCM_TRT_ID_LCDIF_PIXEL_CLK_ROOT = 70, CCM_TRT_ID_MIPI_DSI_CLK_ROOT = 71, CCM_TRT_ID_MIPI_CSI_CLK_ROOT = 72, CCM_TRT_ID_MIPI_DPHY_REF_CLK_ROOT = 73, CCM_TRT_ID_SAI1_CLK_ROOT = 74, CCM_TRT_ID_SAI2_CLK_ROOT = 75, CCM_TRT_ID_SAI3_CLK_ROOT = 76, CCM_TRT_ID_ENET1_REF_CLK_ROOT = 78, CCM_TRT_ID_ENET1_TIME_CLK_ROOT = 79, CCM_TRT_ID_ENET_PHY_REF_CLK_ROOT = 82, CCM_TRT_ID_EIM_CLK_ROOT = 83, CCM_TRT_ID_NAND_CLK_ROOT = 84, CCM_TRT_ID_QSPI_CLK_ROOT = 85, CCM_TRT_ID_USDHC1_CLK_ROOT = 86, CCM_TRT_ID_USDHC2_CLK_ROOT = 87, CCM_TRT_ID_USDHC3_CLK_ROOT = 88, CCM_TRT_ID_CAN1_CLK_ROOT = 89, CCM_TRT_ID_CAN2_CLK_ROOT = 90, CCM_TRT_ID_I2C1_CLK_ROOT = 91, CCM_TRT_ID_I2C2_CLK_ROOT = 92, CCM_TRT_ID_I2C3_CLK_ROOT = 93, CCM_TRT_ID_I2C4_CLK_ROOT = 94, CCM_TRT_ID_UART1_CLK_ROOT = 95, CCM_TRT_ID_UART2_CLK_ROOT = 96, CCM_TRT_ID_UART3_CLK_ROOT = 97, CCM_TRT_ID_UART4_CLK_ROOT = 98, CCM_TRT_ID_UART5_CLK_ROOT = 99, CCM_TRT_ID_UART6_CLK_ROOT = 100, CCM_TRT_ID_UART7_CLK_ROOT = 101, CCM_TRT_ID_ECSPI1_CLK_ROOT = 102, CCM_TRT_ID_ECSPI2_CLK_ROOT = 103, CCM_TRT_ID_ECSPI3_CLK_ROOT = 104, CCM_TRT_ID_ECSPI4_CLK_ROOT = 105, CCM_TRT_ID_PWM1_CLK_ROOT = 106, CCM_TRT_ID_PWM2_CLK_ROOT = 107, CCM_TRT_ID_PWM3_CLK_ROOT = 108, CCM_TRT_ID_PWM4_CLK_ROOT = 109, CCM_TRT_ID_FLEXTIMER1_CLK_ROOT = 110, CCM_TRT_ID_FLEXTIMER2_CLK_ROOT = 111, CCM_TRT_ID_SIM1_CLK_ROOT = 112, CCM_TRT_ID_SIM2_CLK_ROOT = 113, CCM_TRT_ID_GPT1_CLK_ROOT = 114, CCM_TRT_ID_GPT2_CLK_ROOT = 115, CCM_TRT_ID_GPT3_CLK_ROOT = 116, CCM_TRT_ID_GPT4_CLK_ROOT = 117, CCM_TRT_ID_TRACE_CLK_ROOT = 118, CCM_TRT_ID_WDOG_CLK_ROOT = 119, CCM_TRT_ID_CSI_MCLK_CLK_ROOT = 120, CCM_TRT_ID_AUDIO_MCLK_CLK_ROOT = 121, CCM_TRT_ID_CCM_CLKO1 = 123, CCM_TRT_ID_CCM_CLKO2 = 124, }; #define CCM_MISC_VIOLATE BIT(8) #define CCM_MISC_TIMEOUT BIT(4) #define CCM_MISC_AUTHEN_FAIL BIT(0) #define CCM_POST_BUSY2 BIT(31) #define CCM_POST_SELECT_BRANCH_A BIT(28) #define CCM_POST_BUSY1 BIT(7) #define CCM_POST_POST_PODF(x) ((x) - 1) #define CCM_PRE_BUSY4 BIT(31) #define CCM_PRE_ENABLE_A BIT(28) #define CCM_PRE_MUX_A(x) (((x) - 1) << 24) #define CCM_PRE_BUSY3 BIT(19) #define CCM_PRE_PODF_A(x) (((x) - 1) << 16) #define CCM_PRE_BUSY1 BIT(15) #define CCM_PRE_ENABLE_B BIT(12) #define CCM_PRE_MUX_B(x) (((x) - 1) << 8) #define CCM_PRE_BUSY0 BIT(3) #define CCM_PRE_POST_PODF(x) ((x) - 1) #define CCM_ACCESS_CTRL_LOCK BIT(31) #define CCM_ACCESS_SEMA_ENABLE BIT(28) #define CCM_ACCESS_DOM3_WHITELIST BIT(27) #define CCM_ACCESS_DOM2_WHITELIST BIT(26) #define CCM_ACCESS_DOM1_WHITELIST BIT(25) #define CCM_ACCESS_DOM0_WHITELIST BIT(24) #define CCM_ACCESS_MUTEX BIT(20) #define CCM_ACCESS_OWNER_ID(x) ((x) << 16) #define CCM_ACCESS_DOM3_INFO(x) ((x) << 12) #define CCM_ACCESS_DOM2_INFO(x) ((x) << 8) #define CCM_ACCESS_DOM1_INFO(x) ((x) << 4) #define CCM_ACCESS_DOM0_INFO(x) (x) #define CCM_PLL_CTRL_NUM 0x21 #define CCM_CLK_GATE_CTRL_NUM 0xbf #define CCM_ROOT_CTRL_NUM 0x79 struct ccm { uint32_t ccm_gpr0; uint32_t ccm_gpr0_set; uint32_t ccm_gpr0_clr; uint32_t ccm_grp0_tog; uint32_t reserved[0x1fc]; struct ccm_pll_ctrl ccm_pll_ctrl[CCM_PLL_CTRL_NUM]; uint32_t reserved1[0xd7c]; struct ccm_clk_gate_ctrl ccm_clk_gate_ctrl[CCM_CLK_GATE_CTRL_NUM]; uint32_t reserved2[0xd04]; struct ccm_target_root_ctrl ccm_root_ctrl[CCM_ROOT_CTRL_NUM]; }; void imx_clock_target_set(unsigned int id, uint32_t val); void imx_clock_target_clr(unsigned int id, uint32_t val); void imx_clock_gate_enable(unsigned int id, bool enable); void imx_clock_init(void); void imx_clock_enable_uart(unsigned int uart_id, uint32_t uart_clk_en_bits); void imx_clock_disable_uart(unsigned int uart_id); void imx_clock_enable_usdhc(unsigned int usdhc_id, uint32_t usdhc_clk_en_bits); void imx_clock_set_wdog_clk_root_bits(uint32_t wdog_clk_root_en_bits); void imx_clock_enable_wdog(unsigned int wdog_id); void imx_clock_disable_wdog(unsigned int wdog_id); void imx_clock_enable_usb(unsigned int usb_id); void imx_clock_disable_usb(unsigned int usb_id); void imx_clock_set_usb_clk_root_bits(uint32_t usb_clk_root_en_bits); #endif /* IMX_CLOCK_H */ trusted-firmware-a-2.2/plat/imx/common/include/imx_csu.h000066400000000000000000000024441355360272700234050ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX_CSU_H #define IMX_CSU_H #include /* * Security Reference Manual for i.MX 7Dual and 7Solo Applications Processors, * Rev. 0, 03/2017 Section 3.3.1 * * Config secure level register (CSU_CSLn) */ #define CSU_CSL_LOCK_S1 BIT(24) #define CSU_CSL_NSW_S1 BIT(23) #define CSU_CSL_NUW_S1 BIT(22) #define CSU_CSL_SSW_S1 BIT(21) #define CSU_CSL_SUW_S1 BIT(20) #define CSU_CSL_NSR_S1 BIT(19) #define CSU_CSL_NUR_S1 BIT(18) #define CSU_CSL_SSR_S1 BIT(17) #define CSU_CSL_SUR_S1 BIT(16) #define CSU_CSL_LOCK_S2 BIT(8) #define CSU_CSL_NSW_S2 BIT(7) #define CSU_CSL_NUW_S2 BIT(6) #define CSU_CSL_SSW_S2 BIT(5) #define CSU_CSL_SUW_S2 BIT(4) #define CSU_CSL_NSR_S2 BIT(3) #define CSU_CSL_NUR_S2 BIT(2) #define CSU_CSL_SSR_S2 BIT(1) #define CSU_CSL_SUR_S2 BIT(0) #define CSU_CSL_OPEN_ACCESS (CSU_CSL_NSW_S1 | CSU_CSL_NUW_S1 | CSU_CSL_SSW_S1 |\ CSU_CSL_SUW_S1 | CSU_CSL_NSR_S1 | CSU_CSL_NUR_S1 |\ CSU_CSL_SSR_S1 | CSU_CSL_SUR_S1 | CSU_CSL_NSW_S2 |\ CSU_CSL_NUW_S2 | CSU_CSL_SSW_S2 | CSU_CSL_SUW_S2 |\ CSU_CSL_NSR_S2 | CSU_CSL_NUR_S2 | CSU_CSL_SSR_S2 |\ CSU_CSL_SUR_S2) void imx_csu_init(void); #endif /* IMX_CSU_H */ trusted-firmware-a-2.2/plat/imx/common/include/imx_hab.h000066400000000000000000000023631355360272700233450ustar00rootroot00000000000000/* * Copyright (C) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX_HAB_H #define IMX_HAB_H #include #include #define HAB_ROM_VECTOR_BASE\ (BOOTROM_BASE + HAB_CALLBACK_OFFSET) /* * Section 4.5 of the High Assurance Boot Version 4 Application Programming * Interface Reference Manual defines the ROM Vector table as coming after a 4 * byte header * * A series of function pointers are enumerated at fixed addresses, which are * described below */ #define HAB_ROM_VECTOR_TABLE_ENTRY (HAB_ROM_VECTOR_BASE + 0x04) #define HAB_ROM_VECTOR_TABLE_EXIT (HAB_ROM_VECTOR_BASE + 0x08) #define HAB_ROM_VECTOR_TABLE_CHECK_TARGET (HAB_ROM_VECTOR_BASE + 0x0C) #define HAB_ROM_VECTOR_TABLE_AUTHENTICATE_IMAGE (HAB_ROM_VECTOR_BASE + 0x10) #define HAB_ROM_VECTOR_TABLE_RUN_DCD (HAB_ROM_VECTOR_BASE + 0x14) #define HAB_ROM_VECTOR_TABLE_RUN_CSF (HAB_ROM_VECTOR_BASE + 0x18) #define HAB_ROM_VECTOR_TABLE_ASSERT (HAB_ROM_VECTOR_BASE + 0x1C) #define HAB_ROM_VECTOR_TABLE_REPORT_EVENT (HAB_ROM_VECTOR_BASE + 0x20) #define HAB_ROM_VECTOR_TABLE_REPORT_STATUS (HAB_ROM_VECTOR_BASE + 0x24) #define HAB_ROM_VECTOR_TABLE_FAILSAFE (HAB_ROM_VECTOR_BASE + 0x28) #endif /* IMX_HAB_H */ trusted-firmware-a-2.2/plat/imx/common/include/imx_io_mux.h000066400000000000000000001014311355360272700241070ustar00rootroot00000000000000/* * Copyright 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX_IO_MUX_H #define IMX_IO_MUX_H #include #include /* * i.MX 7Solo Applications Processor Reference Manual, Rev. 0.1, 08/2016 * Section 8.2.7 IOMUXC Memory Map/Register Definition */ #define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO08_OFFSET 0x0014 #define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO09_OFFSET 0x0018 #define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO10_OFFSET 0x001C #define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO11_OFFSET 0x0020 #define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO12_OFFSET 0x0024 #define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO13_OFFSET 0x0028 #define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO14_OFFSET 0x002C #define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO14_ALT1_SD3_CD_B BIT(0) #define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO15_OFFSET 0x0030 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA00_OFFSET 0x0034 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA01_OFFSET 0x0038 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA02_OFFSET 0x003C #define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA03_OFFSET 0x0040 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA04_OFFSET 0x0044 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA05_OFFSET 0x0048 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA06_OFFSET 0x004C #define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA07_OFFSET 0x0050 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA08_OFFSET 0x0054 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA09_OFFSET 0x0058 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA10_OFFSET 0x005C #define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA11_OFFSET 0x0060 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA12_OFFSET 0x0064 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA13_OFFSET 0x0068 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA14_OFFSET 0x006C #define IOMUXC_SW_MUX_CTL_PAD_EPDC_DATA15_OFFSET 0x0070 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_SDCLK_OFFSET 0x0074 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_SDLE_OFFSET 0x0078 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_SDOE_OFFSET 0x007C #define IOMUXC_SW_MUX_CTL_PAD_EPDC_SDSHR_OFFSET 0x0080 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_SDCE0_OFFSET 0x0084 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_SDCE1_OFFSET 0x0088 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_SDCE2_OFFSET 0x008C #define IOMUXC_SW_MUX_CTL_PAD_EPDC_SDCE3_OFFSET 0x0090 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_GDCLK_OFFSET 0x0094 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_GDOE_OFFSET 0x0098 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_GDRL_OFFSET 0x009C #define IOMUXC_SW_MUX_CTL_PAD_EPDC_GDSP_OFFSET 0x00A0 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_BDR0_OFFSET 0x00A4 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_BDR1_OFFSET 0x00A8 #define IOMUXC_SW_MUX_CTL_PAD_EPDC_PWR_COM_OFFSET 0x00AC #define IOMUXC_SW_MUX_CTL_PAD_EPDC_PWR_STAT_OFFSET 0x00B0 #define IOMUXC_SW_MUX_CTL_PAD_LCD_CLK_OFFSET 0x00B4 #define IOMUXC_SW_MUX_CTL_PAD_LCD_ENABLE_OFFSET 0x00B8 #define IOMUXC_SW_MUX_CTL_PAD_LCD_HSYNC_OFFSET 0x00BC #define IOMUXC_SW_MUX_CTL_PAD_LCD_VSYNC_OFFSET 0x00C0 #define IOMUXC_SW_MUX_CTL_PAD_LCD_RESET_OFFSET 0x00C4 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA00_OFFSET 0x00C8 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA01_OFFSET 0x00CC #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA02_OFFSET 0x00D0 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA03_OFFSET 0x00D4 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA04_OFFSET 0x00D8 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA05_OFFSET 0x00DC #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA06_OFFSET 0x00E0 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA07_OFFSET 0x00E4 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA08_OFFSET 0x00E8 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA09_OFFSET 0x00EC #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA10_OFFSET 0x00F0 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA11_OFFSET 0x00F4 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA12_OFFSET 0x00F8 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA13_OFFSET 0x00FC #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA14_OFFSET 0x0100 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA15_OFFSET 0x0104 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA16_OFFSET 0x0108 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA17_OFFSET 0x010C #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA18_OFFSET 0x0110 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA19_OFFSET 0x0114 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA20_OFFSET 0x0118 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA21_OFFSET 0x011C #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA22_OFFSET 0x0120 #define IOMUXC_SW_MUX_CTL_PAD_LCD_DATA23_OFFSET 0x0124 #define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_OFFSET 0x0128 #define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_ALT0_UART1_RX_DATA 0x00 #define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_ALT1_I2C1_SCL BIT(0) #define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_ALT2_PMIC_READY BIT(1) #define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_ALT3_ECSPI1_SS1 (BIT(1) | BIT(0)) #define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_ALT4_ENET2_1588_EVENT0_IN BIT(3) #define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_ALT5_GPIO4_IO0 (BIT(2) | BIT(0)) #define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_ALT6_ENET1_MDIO (BIT(2) | BIT(1)) #define IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_SION BIT(3) #define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_OFFSET 0x012C #define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_ALT0_UART1_TX_DATA 0x00 #define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_ALT1_I2C1_SDA BIT(0) #define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_ALT2_SAI3_MCLK BIT(1) #define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_ALT3_ECSPI1_SS2 (BIT(1) | BIT(0)) #define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_ALT4_ENET2_1588_EVENT0_OUT BIT(3) #define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_ALT5_GPIO4_IO1 (BIT(2) | BIT(0)) #define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_ALT6_ENET1_MDC (BIT(2) | BIT(1)) #define IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_SION BIT(3) #define IOMUXC_SW_MUX_CTL_PAD_UART2_RX_DATA_OFFSET 0x0130 #define IOMUXC_SW_MUX_CTL_PAD_UART2_TX_DATA_OFFSET 0x0134 #define IOMUXC_SW_MUX_CTL_PAD_UART3_RX_DATA_OFFSET 0x0138 #define IOMUXC_SW_MUX_CTL_PAD_UART3_TX_DATA_OFFSET 0x013C #define IOMUXC_SW_MUX_CTL_PAD_UART3_RTS_B_OFFSET 0x0140 #define IOMUXC_SW_MUX_CTL_PAD_UART3_CTS_B_OFFSET 0x0144 #define IOMUXC_SW_MUX_CTL_PAD_I2C1_SCL_OFFSET 0x0148 #define IOMUXC_SW_MUX_CTL_PAD_I2C1_SDA_OFFSET 0x014C #define IOMUXC_SW_MUX_CTL_PAD_I2C2_SCL_OFFSET 0x0150 #define IOMUXC_SW_MUX_CTL_PAD_I2C2_SDA_OFFSET 0x0154 #define IOMUXC_SW_MUX_CTL_PAD_I2C3_SCL_OFFSET 0x0158 #define IOMUXC_SW_MUX_CTL_PAD_I2C3_SDA_OFFSET 0x015C #define IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_OFFSET 0x0160 #define IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_ALT0_I2C4_SCL 0x0 #define IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_ALT1_UART5_RX_DATA BIT(0) #define IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_ALT2_WDOG4_WDOG_B BIT(1) #define IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_ALT3_CSI_PIXCLK (BIT(1) | BIT(0)) #define IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_ALT4_USB_OTG1_ID BIT(2) #define IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_ALT5_GPIO4_IO14 (BIT(2) | BIT(0)) #define IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_ALT6_EPDC_VCOM0 (BIT(2) | BIT(1)) #define IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_OFFSET 0x0164 #define IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_ALT0_I2C4_SDA 0x0 #define IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_ALT1_UART5_TX_DATA BIT(0) #define IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_ALT2_WDOG4_WDOG_RST_B_DEB BIT(1) #define IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_ALT3_CSI_MCLK (BIT(1) | BIT(0)) #define IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_ALT4_USB_OTG2_ID BIT(2) #define IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_ALT5_GPIO4_IO15 (BIT(1) | BIT(0)) #define IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_ALT6_EPDC_VCOM1 (BIT(2) | BIT(1)) #define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_OFFSET 0x0168 #define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_ALT0_ECSPI1_SCLK 0x00 #define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_ALT1_UART6_RX_DATA BIT(0) #define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_ALT2_SD2_DATA4 BIT(1) #define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_ALT3_CSI_DATA2 (BIT(1) | BIT(0)) #define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_ALT5_GPIO4_IO16 (BIT(2) | BIT(0)) #define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_ALT6_EPDC_PWR_COM (BIT(2) | (BIT(1)) #define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_OFFSET 0x016C #define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_ALT0_ECSPI1_MOSI 0x00 #define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_ALT1_UART6_TX_DATA BIT(0) #define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_ALT2_SD2_DATA5 BIT(1) #define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_ALT3_CSI_DATA3 (BIT(1) | BIT(0)) #define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_ALT5_GPIO4_IO17 (BIT(2) | BIT(0)) #define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_ALT6_EPDC_PWR_STAT (BIT(2) | (BIT(1)) #define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MISO_OFFSET 0x0170 #define IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SS0_OFFSET 0x0174 #define IOMUXC_SW_MUX_CTL_PAD_ECSPI2_SCLK_OFFSET 0x0178 #define IOMUXC_SW_MUX_CTL_PAD_ECSPI2_MOSI_OFFSET 0x017C #define IOMUXC_SW_MUX_CTL_PAD_ECSPI2_MISO_OFFSET 0x0180 #define IOMUXC_SW_MUX_CTL_PAD_ECSPI2_SS0_OFFSET 0x0184 #define IOMUXC_SW_MUX_CTL_PAD_SD1_CD_B_OFFSET 0x0188 #define IOMUXC_SW_MUX_CTL_PAD_SD1_WP_OFFSET 0x018C #define IOMUXC_SW_MUX_CTL_PAD_SD1_RESET_B_OFFSET 0x0190 #define IOMUXC_SW_MUX_CTL_PAD_SD1_CLK_OFFSET 0x0194 #define IOMUXC_SW_MUX_CTL_PAD_SD1_CMD_OFFSET 0x0198 #define IOMUXC_SW_MUX_CTL_PAD_SD1_DATA0_OFFSET 0x019C #define IOMUXC_SW_MUX_CTL_PAD_SD1_DATA1_OFFSET 0x01A0 #define IOMUXC_SW_MUX_CTL_PAD_SD1_DATA2_OFFSET 0x01A4 #define IOMUXC_SW_MUX_CTL_PAD_SD1_DATA3_OFFSET 0x01A8 #define IOMUXC_SW_MUX_CTL_PAD_SD2_CD_B_OFFSET 0x01AC #define IOMUXC_SW_MUX_CTL_PAD_SD2_WP_OFFSET 0x01B0 #define IOMUXC_SW_MUX_CTL_PAD_SD2_RESET_B_OFFSET 0x01B4 #define IOMUXC_SW_MUX_CTL_PAD_SD2_CLK_OFFSET 0x01B8 #define IOMUXC_SW_MUX_CTL_PAD_SD2_CMD_OFFSET 0x01BC #define IOMUXC_SW_MUX_CTL_PAD_SD2_DATA0_OFFSET 0x01C0 #define IOMUXC_SW_MUX_CTL_PAD_SD2_DATA1_OFFSET 0x01C4 #define IOMUXC_SW_MUX_CTL_PAD_SD2_DATA2_OFFSET 0x01C8 #define IOMUXC_SW_MUX_CTL_PAD_SD2_DATA3_OFFSET 0x01CC #define IOMUXC_SW_MUX_CTL_PAD_SD3_CLK_OFFSET 0x01D0 #define IOMUXC_SW_MUX_CTL_PAD_SD3_CMD_OFFSET 0x01D4 #define IOMUXC_SW_MUX_CTL_PAD_SD3_DATA0_OFFSET 0x01D8 #define IOMUXC_SW_MUX_CTL_PAD_SD3_DATA1_OFFSET 0x01DC #define IOMUXC_SW_MUX_CTL_PAD_SD3_DATA2_OFFSET 0x01E0 #define IOMUXC_SW_MUX_CTL_PAD_SD3_DATA3_OFFSET 0x01E4 #define IOMUXC_SW_MUX_CTL_PAD_SD3_DATA4_OFFSET 0x01E8 #define IOMUXC_SW_MUX_CTL_PAD_SD3_DATA5_OFFSET 0x01EC #define IOMUXC_SW_MUX_CTL_PAD_SD3_DATA6_OFFSET 0x01F0 #define IOMUXC_SW_MUX_CTL_PAD_SD3_DATA7_OFFSET 0x01F4 #define IOMUXC_SW_MUX_CTL_PAD_SD3_STROBE_OFFSET 0x01F8 #define IOMUXC_SW_MUX_CTL_PAD_SD3_RESET_B_OFFSET 0x01FC #define IOMUXC_SW_MUX_CTL_PAD_SAI1_RX_DATA_OFFSET 0x0200 #define IOMUXC_SW_MUX_CTL_PAD_SAI1_TX_BCLK_OFFSET 0x0204 #define IOMUXC_SW_MUX_CTL_PAD_SAI1_TX_SYNC_OFFSET 0x0208 #define IOMUXC_SW_MUX_CTL_PAD_SAI1_TX_DATA_OFFSET 0x020C #define IOMUXC_SW_MUX_CTL_PAD_SAI1_RX_SYNC_OFFSET 0x0210 #define IOMUXC_SW_MUX_CTL_PAD_SAI1_RX_BCLK_OFFSET 0x0214 #define IOMUXC_SW_MUX_CTL_PAD_SAI1_MCLK_OFFSET 0x0218 #define IOMUXC_SW_MUX_CTL_PAD_SAI2_TX_SYNC_OFFSET 0x021C #define IOMUXC_SW_MUX_CTL_PAD_SAI2_TX_BCLK_OFFSET 0x0220 #define IOMUXC_SW_MUX_CTL_PAD_SAI2_RX_DATA_OFFSET 0x0224 #define IOMUXC_SW_MUX_CTL_PAD_SAI2_TX_DATA_OFFSET 0x0228 #define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_RD0_OFFSET 0x022C #define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_RD1_OFFSET 0x0230 #define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_RD2_OFFSET 0x0234 #define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_RD3_OFFSET 0x0238 #define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_RX_CTL_OFFSET 0x023C #define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_RXC_OFFSET 0x0240 #define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_TD0_OFFSET 0x0244 #define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_TD1_OFFSET 0x0248 #define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_TD2_OFFSET 0x024C #define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_TD3_OFFSET 0x0250 #define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_TX_CTL_OFFSET 0x0254 #define IOMUXC_SW_MUX_CTL_PAD_ENET1_RGMII_TXC_OFFSET 0x0258 #define IOMUXC_SW_MUX_CTL_PAD_ENET1_TX_CLK_OFFSET 0x025C #define IOMUXC_SW_MUX_CTL_PAD_ENET1_RX_CLK_OFFSET 0x0260 #define IOMUXC_SW_MUX_CTL_PAD_ENET1_CRS_OFFSET 0x0264 #define IOMUXC_SW_MUX_CTL_PAD_ENET1_COL_OFFSET 0x0268 #define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO08_OFFSET 0x026C #define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO09_OFFSET 0x0270 #define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO10_OFFSET 0x0274 #define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO11_OFFSET 0x0278 #define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO12_OFFSET 0x027C #define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO13_OFFSET 0x0280 #define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO14_OFFSET 0x0284 #define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO15_OFFSET 0x0288 #define IOMUXC_SW_PAD_CTL_PAD_JTAG_MOD_OFFSET 0x028C #define IOMUXC_SW_PAD_CTL_PAD_JTAG_TCK_OFFSET 0x0290 #define IOMUXC_SW_PAD_CTL_PAD_JTAG_TDI_OFFSET 0x0294 #define IOMUXC_SW_PAD_CTL_PAD_JTAG_TDO_OFFSET 0x0298 #define IOMUXC_SW_PAD_CTL_PAD_JTAG_TMS_OFFSET 0x029C #define IOMUXC_SW_PAD_CTL_PAD_JTAG_TRST_B_OFFSET 0x02A0 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA00_OFFSET 0x02A4 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA01_OFFSET 0x02A8 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA02_OFFSET 0x02AC #define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA03_OFFSET 0x02B0 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA04_OFFSET 0x02B4 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA05_OFFSET 0x02B8 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA06_OFFSET 0x02BC #define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA07_OFFSET 0x02C0 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA08_OFFSET 0x02C4 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA09_OFFSET 0x02C8 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA10_OFFSET 0x02CC #define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA11_OFFSET 0x02D0 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA12_OFFSET 0x02D4 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA13_OFFSET 0x02D8 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA14_OFFSET 0x02DC #define IOMUXC_SW_PAD_CTL_PAD_EPDC_DATA15_OFFSET 0x02E0 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_SDCLK_OFFSET 0x02E4 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_SDLE_OFFSET 0x02E8 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_SDOE_OFFSET 0x02EC #define IOMUXC_SW_PAD_CTL_PAD_EPDC_SDSHR_OFFSET 0x02F0 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_SDCE0_OFFSET 0x02F4 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_SDCE1_OFFSET 0x02F8 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_SDCE2_OFFSET 0x02FC #define IOMUXC_SW_PAD_CTL_PAD_EPDC_SDCE3_OFFSET 0x0300 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_GDCLK_OFFSET 0x0304 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_GDOE_OFFSET 0x0308 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_GDRL_OFFSET 0x030C #define IOMUXC_SW_PAD_CTL_PAD_EPDC_GDSP_OFFSET 0x0310 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_BDR0_OFFSET 0x0314 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_BDR1_OFFSET 0x0318 #define IOMUXC_SW_PAD_CTL_PAD_EPDC_PWR_COM_OFFSET 0x031C #define IOMUXC_SW_PAD_CTL_PAD_EPDC_PWR_STAT_OFFSET 0x0320 #define IOMUXC_SW_PAD_CTL_PAD_LCD_CLK_OFFSET 0x0324 #define IOMUXC_SW_PAD_CTL_PAD_LCD_ENABLE_OFFSET 0x0328 #define IOMUXC_SW_PAD_CTL_PAD_LCD_HSYNC_OFFSET 0x032C #define IOMUXC_SW_PAD_CTL_PAD_LCD_VSYNC_OFFSET 0x0330 #define IOMUXC_SW_PAD_CTL_PAD_LCD_RESET_OFFSET 0x0334 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA00_OFFSET 0x0338 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA01_OFFSET 0x033C #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA02_OFFSET 0x0340 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA03_OFFSET 0x0344 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA04_OFFSET 0x0348 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA05_OFFSET 0x034C #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA06_OFFSET 0x0350 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA07_OFFSET 0x0354 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA08_OFFSET 0x0358 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA09_OFFSET 0x035C #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA10_OFFSET 0x0360 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA11_OFFSET 0x0364 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA12_OFFSET 0x0368 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA13_OFFSET 0x036C #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA14_OFFSET 0x0370 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA15_OFFSET 0x0374 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA16_OFFSET 0x0378 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA17_OFFSET 0x037C #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA18_OFFSET 0x0380 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA19_OFFSET 0x0384 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA20_OFFSET 0x0388 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA21_OFFSET 0x038C #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA22_OFFSET 0x0390 #define IOMUXC_SW_PAD_CTL_PAD_LCD_DATA23_OFFSET 0x0394 #define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_OFFSET 0x0398 #define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_DSE_0_X1 0 #define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_DSE_1_X4 BIT(0) #define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_DSE_2_X2 BIT(1) #define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_DSE_3_X6 (BIT(1) | BIT(0)) #define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_SRE_FAST 0 #define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_SRE_SLOW BIT(2) #define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_HYS_DIS 0 #define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_HYS_EN BIT(3) #define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_PE_DIS 0 #define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_PE_EN BIT(4) #define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_PS_0_100K_PD 0 #define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_PS_1_5K_PU BIT(5) #define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_PS_2_47K_PU BIT(6) #define IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_PS_3_100K_PU (BIT(6) | BIT(5)) #define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_OFFSET 0x039C #define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_DSE_0_X1 0 #define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_DSE_1_X4 BIT(0) #define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_DSE_2_X2 BIT(1) #define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_DSE_3_X6 (BIT(1) | BIT(0)) #define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_SRE_FAST 0 #define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_SRE_SLOW BIT(2) #define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_HYS_DIS 0 #define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_HYS_EN BIT(3) #define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_PE_DIS 0 #define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_PE_EN BIT(4) #define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_PS_0_100K_PD 0 #define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_PS_1_5K_PU BIT(5) #define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_PS_2_47K_PU BIT(6) #define IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_PS_3_100K_PU (BIT(6) | BIT(5)) #define IOMUXC_SW_PAD_CTL_PAD_UART2_RX_DATA_OFFSET 0x03A0 #define IOMUXC_SW_PAD_CTL_PAD_UART2_TX_DATA_OFFSET 0x03A4 #define IOMUXC_SW_PAD_CTL_PAD_UART3_RX_DATA_OFFSET 0x03A8 #define IOMUXC_SW_PAD_CTL_PAD_UART3_TX_DATA_OFFSET 0x03AC #define IOMUXC_SW_PAD_CTL_PAD_UART3_RTS_B_OFFSET 0x03B0 #define IOMUXC_SW_PAD_CTL_PAD_UART3_CTS_B_OFFSET 0x03B4 #define IOMUXC_SW_PAD_CTL_PAD_I2C1_SCL_OFFSET 0x03B8 #define IOMUXC_SW_PAD_CTL_PAD_I2C1_SDA_OFFSET 0x03BC #define IOMUXC_SW_PAD_CTL_PAD_I2C2_SCL_OFFSET 0x03C0 #define IOMUXC_SW_PAD_CTL_PAD_I2C2_SDA_OFFSET 0x03C4 #define IOMUXC_SW_PAD_CTL_PAD_I2C3_SCL_OFFSET 0x03C8 #define IOMUXC_SW_PAD_CTL_PAD_I2C3_SDA_OFFSET 0x03CC #define IOMUXC_SW_PAD_CTL_PAD_I2C4_SCL_OFFSET 0x03D0 #define IOMUXC_SW_PAD_CTL_PAD_I2C4_SDA_OFFSET 0x03D4 #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_OFFSET 0x03D8 #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_DSE_0_X1 0 #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_DSE_1_X4 BIT(0) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_DSE_2_X2 BIT(1) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_DSE_3_X6 (BIT(1) | BIT(0)) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_SRE_FAST 0 #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_SRE_SLOW BIT(2) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_HYS_DIS 0 #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_HYS_EN BIT(3) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_PE_DIS 0 #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_PE_EN BIT(4) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_PS_0_100K_PD 0 #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_PS_1_5K_PU BIT(5) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_PS_2_47K_PU BIT(6) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_PS_3_100K_PU (BIT(6) | BIT(5)) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_OFFSET 0x03DC #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_DSE_0_X1 0 #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_DSE_1_X4 BIT(0) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_DSE_2_X2 BIT(1) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_DSE_3_X6 (BIT(1) | BIT(0)) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_SRE_FAST 0 #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_SRE_SLOW BIT(2) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_HYS_DIS 0 #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_HYS_EN BIT(3) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_PE_DIS 0 #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_PE_EN BIT(4) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_PS_0_100K_PD 0 #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_PS_1_5K_PU BIT(5) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_PS_2_47K_PU BIT(6) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_PS_3_100K_PU (BIT(6) | BIT(5)) #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MISO_OFFSET 0x03E0 #define IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SS0_OFFSET 0x03E4 #define IOMUXC_SW_PAD_CTL_PAD_ECSPI2_SCLK_OFFSET 0x03E8 #define IOMUXC_SW_PAD_CTL_PAD_ECSPI2_MOSI_OFFSET 0x03EC #define IOMUXC_SW_PAD_CTL_PAD_ECSPI2_MISO_OFFSET 0x03F0 #define IOMUXC_SW_PAD_CTL_PAD_ECSPI2_SS0_OFFSET 0x03F4 #define IOMUXC_SW_PAD_CTL_PAD_SD1_CD_B_OFFSET 0x03F8 #define IOMUXC_SW_PAD_CTL_PAD_SD1_WP_OFFSET 0x03FC #define IOMUXC_SW_PAD_CTL_PAD_SD1_RESET_B_OFFSET 0x0400 #define IOMUXC_SW_PAD_CTL_PAD_SD1_CLK_OFFSET 0x0404 #define IOMUXC_SW_PAD_CTL_PAD_SD1_CMD_OFFSET 0x0408 #define IOMUXC_SW_PAD_CTL_PAD_SD1_DATA0_OFFSET 0x040C #define IOMUXC_SW_PAD_CTL_PAD_SD1_DATA1_OFFSET 0x0410 #define IOMUXC_SW_PAD_CTL_PAD_SD1_DATA2_OFFSET 0x0414 #define IOMUXC_SW_PAD_CTL_PAD_SD1_DATA3_OFFSET 0x0418 #define IOMUXC_SW_PAD_CTL_PAD_SD2_CD_B_OFFSET 0x041C #define IOMUXC_SW_PAD_CTL_PAD_SD2_WP_OFFSET 0x0420 #define IOMUXC_SW_PAD_CTL_PAD_SD2_RESET_B_OFFSET 0x0424 #define IOMUXC_SW_PAD_CTL_PAD_SD2_CLK_OFFSET 0x0428 #define IOMUXC_SW_PAD_CTL_PAD_SD2_CMD_OFFSET 0x042C #define IOMUXC_SW_PAD_CTL_PAD_SD2_DATA0_OFFSET 0x0430 #define IOMUXC_SW_PAD_CTL_PAD_SD2_DATA1_OFFSET 0x0434 #define IOMUXC_SW_PAD_CTL_PAD_SD2_DATA2_OFFSET 0x0438 #define IOMUXC_SW_PAD_CTL_PAD_SD2_DATA3_OFFSET 0x043C #define IOMUXC_SW_PAD_CTL_PAD_SD3_CLK_OFFSET 0x0440 #define IOMUXC_SW_PAD_CTL_PAD_SD3_CMD_OFFSET 0x0444 #define IOMUXC_SW_PAD_CTL_PAD_SD3_DATA0_OFFSET 0x0448 #define IOMUXC_SW_PAD_CTL_PAD_SD3_DATA1_OFFSET 0x044C #define IOMUXC_SW_PAD_CTL_PAD_SD3_DATA2_OFFSET 0x0450 #define IOMUXC_SW_PAD_CTL_PAD_SD3_DATA3_OFFSET 0x0454 #define IOMUXC_SW_PAD_CTL_PAD_SD3_DATA4_OFFSET 0x0458 #define IOMUXC_SW_PAD_CTL_PAD_SD3_DATA5_OFFSET 0x045C #define IOMUXC_SW_PAD_CTL_PAD_SD3_DATA6_OFFSET 0x0460 #define IOMUXC_SW_PAD_CTL_PAD_SD3_DATA7_OFFSET 0x0464 #define IOMUXC_SW_PAD_CTL_PAD_SD3_STROBE_OFFSET 0x0468 #define IOMUXC_SW_PAD_CTL_PAD_SD3_RESET_B_OFFSET 0x046C #define IOMUXC_SW_PAD_CTL_PAD_SD3_DSE_0_X1 0 #define IOMUXC_SW_PAD_CTL_PAD_SD3_DSE_1_X4 BIT(0) #define IOMUXC_SW_PAD_CTL_PAD_SD3_DSE_2_X2 BIT(1) #define IOMUXC_SW_PAD_CTL_PAD_SD3_DSE_3_X6 (BIT(1) | BIT(0)) #define IOMUXC_SW_PAD_CTL_PAD_SD3_DSE_1_X4 BIT(0) #define IOMUXC_SW_PAD_CTL_PAD_SD3_SLEW_SLOW BIT(2) #define IOMUXC_SW_PAD_CTL_PAD_SD3_SLEW_FAST 0 #define IOMUXC_SW_PAD_CTL_PAD_SD3_HYS BIT(3) #define IOMUXC_SW_PAD_CTL_PAD_SD3_PE BIT(4) #define IOMUXC_SW_PAD_CTL_PAD_SD3_PD_100K (0 << 5) #define IOMUXC_SW_PAD_CTL_PAD_SD3_PU_5K (1 << 5) #define IOMUXC_SW_PAD_CTL_PAD_SD3_PU_47K (2 << 5) #define IOMUXC_SW_PAD_CTL_PAD_SD3_PU_100K (3 << 5) #define IOMUXC_SW_PAD_CTL_PAD_SAI1_RX_DATA_OFFSET 0x0470 #define IOMUXC_SW_PAD_CTL_PAD_SAI1_TX_BCLK_OFFSET 0x0474 #define IOMUXC_SW_PAD_CTL_PAD_SAI1_TX_SYNC_OFFSET 0x0478 #define IOMUXC_SW_PAD_CTL_PAD_SAI1_TX_DATA_OFFSET 0x047C #define IOMUXC_SW_PAD_CTL_PAD_SAI1_RX_SYNC_OFFSET 0x0480 #define IOMUXC_SW_PAD_CTL_PAD_SAI1_RX_BCLK_OFFSET 0x0484 #define IOMUXC_SW_PAD_CTL_PAD_SAI1_MCLK_OFFSET 0x0488 #define IOMUXC_SW_PAD_CTL_PAD_SAI2_TX_SYNC_OFFSET 0x048C #define IOMUXC_SW_PAD_CTL_PAD_SAI2_TX_BCLK_OFFSET 0x0490 #define IOMUXC_SW_PAD_CTL_PAD_SAI2_RX_DATA_OFFSET 0x0494 #define IOMUXC_SW_PAD_CTL_PAD_SAI2_TX_DATA_OFFSET 0x0498 #define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_RD0_OFFSET 0x049C #define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_RD1_OFFSET 0x04A0 #define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_RD2_OFFSET 0x04A4 #define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_RD3_OFFSET 0x04A8 #define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_RX_CTL_OFFSET 0x04AC #define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_RXC_OFFSET 0x04B0 #define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_TD0_OFFSET 0x04B4 #define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_TD1_OFFSET 0x04B8 #define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_TD2_OFFSET 0x04BC #define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_TD3_OFFSET 0x04C0 #define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_TX_CTL_OFFSET 0x04C4 #define IOMUXC_SW_PAD_CTL_PAD_ENET1_RGMII_TXC_OFFSET 0x04C8 #define IOMUXC_SW_PAD_CTL_PAD_ENET1_TX_CLK_OFFSET 0x04CC #define IOMUXC_SW_PAD_CTL_PAD_ENET1_RX_CLK_OFFSET 0x04D0 #define IOMUXC_SW_PAD_CTL_PAD_ENET1_CRS_OFFSET 0x04D4 #define IOMUXC_SW_PAD_CTL_PAD_ENET1_COL_OFFSET 0x04D8 #define IOMUXC_FLEXCAN1_RX_SELECT_INPUT_OFFSET 0x04DC #define IOMUXC_FLEXCAN2_RX_SELECT_INPUT_OFFSET 0x04E0 #define IOMUXC_CCM_EXT_CLK_1_SELECT_INPUT_OFFSET 0x04E4 #define IOMUXC_CCM_EXT_CLK_2_SELECT_INPUT_OFFSET 0x04E8 #define IOMUXC_CCM_EXT_CLK_3_SELECT_INPUT_OFFSET 0x04EC #define IOMUXC_CCM_EXT_CLK_4_SELECT_INPUT_OFFSET 0x04F0 #define IOMUXC_CCM_PMIC_READY_SELECT_INPUT_OFFSET 0x04F4 #define IOMUXC_CSI_DATA2_SELECT_INPUT_OFFSET 0x04F8 #define IOMUXC_CSI_DATA3_SELECT_INPUT_OFFSET 0x04FC #define IOMUXC_CSI_DATA4_SELECT_INPUT_OFFSET 0x0500 #define IOMUXC_CSI_DATA5_SELECT_INPUT_OFFSET 0x0504 #define IOMUXC_CSI_DATA6_SELECT_INPUT_OFFSET 0x0508 #define IOMUXC_CSI_DATA7_SELECT_INPUT_OFFSET 0x050C #define IOMUXC_CSI_DATA8_SELECT_INPUT_OFFSET 0x0510 #define IOMUXC_CSI_DATA9_SELECT_INPUT_OFFSET 0x0514 #define IOMUXC_CSI_HSYNC_SELECT_INPUT_OFFSET 0x0518 #define IOMUXC_CSI_PIXCLK_SELECT_INPUT_OFFSET 0x051C #define IOMUXC_CSI_VSYNC_SELECT_INPUT_OFFSET 0x0520 #define IOMUXC_ECSPI1_SCLK_SELECT_INPUT_OFFSET 0x0524 #define IOMUXC_ECSPI1_MISO_SELECT_INPUT_OFFSET 0x0528 #define IOMUXC_ECSPI1_MOSI_SELECT_INPUT_OFFSET 0x052C #define IOMUXC_ECSPI1_SS0_B_SELECT_INPUT_OFFSET 0x0530 #define IOMUXC_ECSPI2_SCLK_SELECT_INPUT_OFFSET 0x0534 #define IOMUXC_ECSPI2_MISO_SELECT_INPUT_OFFSET 0x0538 #define IOMUXC_ECSPI2_MOSI_SELECT_INPUT_OFFSET 0x053C #define IOMUXC_ECSPI2_SS0_B_SELECT_INPUT_OFFSET 0x0540 #define IOMUXC_ECSPI3_SCLK_SELECT_INPUT_OFFSET 0x0544 #define IOMUXC_ECSPI3_MISO_SELECT_INPUT_OFFSET 0x0548 #define IOMUXC_ECSPI3_MOSI_SELECT_INPUT_OFFSET 0x054C #define IOMUXC_ECSPI3_SS0_B_SELECT_INPUT_OFFSET 0x0550 #define IOMUXC_ECSPI4_SCLK_SELECT_INPUT_OFFSET 0x0554 #define IOMUXC_ECSPI4_MISO_SELECT_INPUT_OFFSET 0x0558 #define IOMUXC_ECSPI4_MOSI_SELECT_INPUT_OFFSET 0x055C #define IOMUXC_ECSPI4_SS0_B_SELECT_INPUT_OFFSET 0x0560 #define IOMUXC_CCM_ENET1_REF_CLK_SELECT_INPUT_OFFSET 0x0564 #define IOMUXC_ENET1_MDIO_SELECT_INPUT_OFFSET 0x0568 #define IOMUXC_ENET1_RX_CLK_SELECT_INPUT_OFFSET 0x056C #define IOMUXC_CCM_ENET2_REF_CLK_SELECT_INPUT_OFFSET 0x0570 #define IOMUXC_ENET2_MDIO_SELECT_INPUT_OFFSET 0x0574 #define IOMUXC_ENET2_RX_CLK_SELECT_INPUT_OFFSET 0x0578 #define IOMUXC_EPDC_PWR_IRQ_SELECT_INPUT_OFFSET 0x057C #define IOMUXC_EPDC_PWR_STAT_SELECT_INPUT_OFFSET 0x0580 #define IOMUXC_FLEXTIMER1_CH0_SELECT_INPUT_OFFSET 0x0584 #define IOMUXC_FLEXTIMER1_CH1_SELECT_INPUT_OFFSET 0x0588 #define IOMUXC_FLEXTIMER1_CH2_SELECT_INPUT_OFFSET 0x058C #define IOMUXC_FLEXTIMER1_CH3_SELECT_INPUT_OFFSET 0x0590 #define IOMUXC_FLEXTIMER1_CH4_SELECT_INPUT_OFFSET 0x0594 #define IOMUXC_FLEXTIMER1_CH5_SELECT_INPUT_OFFSET 0x0598 #define IOMUXC_FLEXTIMER1_CH6_SELECT_INPUT_OFFSET 0x059C #define IOMUXC_FLEXTIMER1_CH7_SELECT_INPUT_OFFSET 0x05A0 #define IOMUXC_FLEXTIMER1_PHA_SELECT_INPUT_OFFSET 0x05A4 #define IOMUXC_FLEXTIMER1_PHB_SELECT_INPUT_OFFSET 0x05A8 #define IOMUXC_FLEXTIMER2_CH0_SELECT_INPUT_OFFSET 0x05AC #define IOMUXC_FLEXTIMER2_CH1_SELECT_INPUT_OFFSET 0x05B0 #define IOMUXC_FLEXTIMER2_CH2_SELECT_INPUT_OFFSET 0x05B4 #define IOMUXC_FLEXTIMER2_CH3_SELECT_INPUT_OFFSET 0x05B8 #define IOMUXC_FLEXTIMER2_CH4_SELECT_INPUT_OFFSET 0x05BC #define IOMUXC_FLEXTIMER2_CH5_SELECT_INPUT_OFFSET 0x05C0 #define IOMUXC_FLEXTIMER2_CH6_SELECT_INPUT_OFFSET 0x05C4 #define IOMUXC_FLEXTIMER2_CH7_SELECT_INPUT_OFFSET 0x05C8 #define IOMUXC_FLEXTIMER2_PHA_SELECT_INPUT_OFFSET 0x05CC #define IOMUXC_FLEXTIMER2_PHB_SELECT_INPUT_OFFSET 0x05D0 #define IOMUXC_I2C1_SCL_SELECT_INPUT_OFFSET 0x05D4 #define IOMUXC_I2C1_SDA_SELECT_INPUT_OFFSET 0x05D8 #define IOMUXC_I2C2_SCL_SELECT_INPUT_OFFSET 0x05DC #define IOMUXC_I2C2_SDA_SELECT_INPUT_OFFSET 0x05E0 #define IOMUXC_I2C3_SCL_SELECT_INPUT_OFFSET 0x05E4 #define IOMUXC_I2C3_SDA_SELECT_INPUT_OFFSET 0x05E8 #define IOMUXC_I2C4_SCL_SELECT_INPUT_OFFSET 0x05EC #define IOMUXC_I2C4_SDA_SELECT_INPUT_OFFSET 0x05F0 #define IOMUXC_KPP_COL0_SELECT_INPUT_OFFSET 0x05F4 #define IOMUXC_KPP_COL1_SELECT_INPUT_OFFSET 0x05F8 #define IOMUXC_KPP_COL2_SELECT_INPUT_OFFSET 0x05FC #define IOMUXC_KPP_COL3_SELECT_INPUT_OFFSET 0x0600 #define IOMUXC_KPP_COL4_SELECT_INPUT_OFFSET 0x0604 #define IOMUXC_KPP_COL5_SELECT_INPUT_OFFSET 0x0608 #define IOMUXC_KPP_COL6_SELECT_INPUT_OFFSET 0x060C #define IOMUXC_KPP_COL7_SELECT_INPUT_OFFSET 0x0610 #define IOMUXC_KPP_ROW0_SELECT_INPUT_OFFSET 0x0614 #define IOMUXC_KPP_ROW1_SELECT_INPUT_OFFSET 0x0618 #define IOMUXC_KPP_ROW2_SELECT_INPUT_OFFSET 0x061C #define IOMUXC_KPP_ROW3_SELECT_INPUT_OFFSET 0x0620 #define IOMUXC_KPP_ROW4_SELECT_INPUT_OFFSET 0x0624 #define IOMUXC_KPP_ROW5_SELECT_INPUT_OFFSET 0x0628 #define IOMUXC_KPP_ROW6_SELECT_INPUT_OFFSET 0x062C #define IOMUXC_KPP_ROW7_SELECT_INPUT_OFFSET 0x0630 #define IOMUXC_LCD_BUSY_SELECT_INPUT_OFFSET 0x0634 #define IOMUXC_LCD_DATA00_SELECT_INPUT_OFFSET 0x0638 #define IOMUXC_LCD_DATA01_SELECT_INPUT_OFFSET 0x063C #define IOMUXC_LCD_DATA02_SELECT_INPUT_OFFSET 0x0640 #define IOMUXC_LCD_DATA03_SELECT_INPUT_OFFSET 0x0644 #define IOMUXC_LCD_DATA04_SELECT_INPUT_OFFSET 0x0648 #define IOMUXC_LCD_DATA05_SELECT_INPUT_OFFSET 0x064C #define IOMUXC_LCD_DATA06_SELECT_INPUT_OFFSET 0x0650 #define IOMUXC_LCD_DATA07_SELECT_INPUT_OFFSET 0x0654 #define IOMUXC_LCD_DATA08_SELECT_INPUT_OFFSET 0x0658 #define IOMUXC_LCD_DATA09_SELECT_INPUT_OFFSET 0x065C #define IOMUXC_LCD_DATA10_SELECT_INPUT_OFFSET 0x0660 #define IOMUXC_LCD_DATA11_SELECT_INPUT_OFFSET 0x0664 #define IOMUXC_LCD_DATA12_SELECT_INPUT_OFFSET 0x0668 #define IOMUXC_LCD_DATA13_SELECT_INPUT_OFFSET 0x066C #define IOMUXC_LCD_DATA14_SELECT_INPUT_OFFSET 0x0670 #define IOMUXC_LCD_DATA15_SELECT_INPUT_OFFSET 0x0674 #define IOMUXC_LCD_DATA16_SELECT_INPUT_OFFSET 0x0678 #define IOMUXC_LCD_DATA17_SELECT_INPUT_OFFSET 0x067C #define IOMUXC_LCD_DATA18_SELECT_INPUT_OFFSET 0x0680 #define IOMUXC_LCD_DATA19_SELECT_INPUT_OFFSET 0x0684 #define IOMUXC_LCD_DATA20_SELECT_INPUT_OFFSET 0x0688 #define IOMUXC_LCD_DATA21_SELECT_INPUT_OFFSET 0x068C #define IOMUXC_LCD_DATA22_SELECT_INPUT_OFFSET 0x0690 #define IOMUXC_LCD_DATA23_SELECT_INPUT_OFFSET 0x0694 #define IOMUXC_LCD_VSYNC_SELECT_INPUT_OFFSET 0x0698 #define IOMUXC_SAI1_RX_BCLK_SELECT_INPUT_OFFSET 0x069C #define IOMUXC_SAI1_RX_DATA_SELECT_INPUT_OFFSET 0x06A0 #define IOMUXC_SAI1_RX_SYNC_SELECT_INPUT_OFFSET 0x06A4 #define IOMUXC_SAI1_TX_BCLK_SELECT_INPUT_OFFSET 0x06A8 #define IOMUXC_SAI1_TX_SYNC_SELECT_INPUT_OFFSET 0x06AC #define IOMUXC_SAI2_RX_BCLK_SELECT_INPUT_OFFSET 0x06B0 #define IOMUXC_SAI2_RX_DATA_SELECT_INPUT_OFFSET 0x06B4 #define IOMUXC_SAI2_RX_SYNC_SELECT_INPUT_OFFSET 0x06B8 #define IOMUXC_SAI2_TX_BCLK_SELECT_INPUT_OFFSET 0x06BC #define IOMUXC_SAI2_TX_SYNC_SELECT_INPUT_OFFSET 0x06C0 #define IOMUXC_SAI3_RX_BCLK_SELECT_INPUT_OFFSET 0x06C4 #define IOMUXC_SAI3_RX_DATA_SELECT_INPUT_OFFSET 0x06C8 #define IOMUXC_SAI3_RX_SYNC_SELECT_INPUT_OFFSET 0x06CC #define IOMUXC_SAI3_TX_BCLK_SELECT_INPUT_OFFSET 0x06D0 #define IOMUXC_SAI3_TX_SYNC_SELECT_INPUT_OFFSET 0x06D4 #define IOMUXC_SDMA_EVENTS0_SELECT_INPUT_OFFSET 0x06D8 #define IOMUXC_SDMA_EVENTS1_SELECT_INPUT_OFFSET 0x06DC #define IOMUXC_SIM1_PORT1_PD_SELECT_INPUT_OFFSET 0x06E0 #define IOMUXC_SIM1_PORT1_TRXD_SELECT_INPUT_OFFSET 0x06E4 #define IOMUXC_SIM2_PORT1_PD_SELECT_INPUT_OFFSET 0x06E8 #define IOMUXC_SIM2_PORT1_TRXD_SELECT_INPUT_OFFSET 0x06EC #define IOMUXC_UART1_RTS_B_SELECT_INPUT_OFFSET 0x06F0 #define IOMUXC_UART1_RX_DATA_SELECT_INPUT_OFFSET 0x06F4 #define IOMUXC_UART2_RTS_B_SELECT_INPUT_OFFSET 0x06F8 #define IOMUXC_UART2_RX_DATA_SELECT_INPUT_OFFSET 0x06FC #define IOMUXC_UART3_RTS_B_SELECT_INPUT_OFFSET 0x0700 #define IOMUXC_UART3_RX_DATA_SELECT_INPUT_OFFSET 0x0704 #define IOMUXC_UART4_RTS_B_SELECT_INPUT_OFFSET 0x0708 #define IOMUXC_UART4_RX_DATA_SELECT_INPUT_OFFSET 0x070C #define IOMUXC_UART5_RTS_B_SELECT_INPUT_OFFSET 0x0710 #define IOMUXC_UART5_RX_DATA_SELECT_INPUT_OFFSET 0x0714 #define IOMUXC_UART5_RX_DATA_SELECT_INPUT_I2C4_SCL_ALT1 0x00 #define IOMUXC_UART5_RX_DATA_SELECT_INPUT_I2C4_SDA_ALT1 BIT(0) #define IOMUXC_UART5_RX_DATA_SELECT_INPUT_SAI1_RX_DATA_ALT2 BIT(1) #define IOMUXC_UART5_RX_DATA_SELECT_INPUT_SAI1_TX_BCLK_ALT2 (BIT(1) | BIT(0)) #define IOMUXC_UART5_RX_DATA_SELECT_INPUT_GPIO1_IO06_ALT3 BIT(2) #define IOMUXC_UART5_RX_DATA_SELECT_INPUT_GPIO1_IO07_ALT3 (BIT(2) | BIT(1)) #define IOMUXC_UART6_RTS_B_SELECT_INPUT_OFFSET 0x0718 #define IOMUXC_UART6_RX_DATA_SELECT_INPUT_OFFSET 0x071C #define IOMUXC_UART7_RTS_B_SELECT_INPUT_OFFSET 0x0720 #define IOMUXC_UART7_RX_DATA_SELECT_INPUT_OFFSET 0x0724 #define IOMUXC_USB_OTG2_OC_SELECT_INPUT_OFFSET 0x0728 #define IOMUXC_USB_OTG1_OC_SELECT_INPUT_OFFSET 0x072C #define IOMUXC_USB_OTG2_ID_SELECT_INPUT_OFFSET 0x0730 #define IOMUXC_USB_OTG1_ID_SELECT_INPUT_OFFSET 0x0734 #define IOMUXC_SD3_CD_B_SELECT_INPUT_OFFSET 0x0738 #define IOMUXC_SD3_WP_SELECT_INPUT_OFFSET 0x073C /* Pad mux/feature set routines */ void imx_io_muxc_set_pad_alt_function(uint32_t pad_mux_offset, uint32_t alt_function); void imx_io_muxc_set_pad_features(uint32_t pad_feature_offset, uint32_t pad_features); #endif /* IMX_IO_MUX_H */ trusted-firmware-a-2.2/plat/imx/common/include/imx_sip_svc.h000066400000000000000000000031661355360272700242630ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __IMX_SIP_SVC_H__ #define __IMX_SIP_SVC_H__ /* SMC function IDs for SiP Service queries */ #define IMX_SIP_CPUFREQ 0xC2000001 #define IMX_SIP_SET_CPUFREQ 0x00 #define IMX_SIP_SRTC 0xC2000002 #define IMX_SIP_SRTC_SET_TIME 0x00 #define IMX_SIP_BUILDINFO 0xC2000003 #define IMX_SIP_BUILDINFO_GET_COMMITHASH 0x00 #define IMX_SIP_GET_SOC_INFO 0xC2000006 #define IMX_SIP_WAKEUP_SRC 0xC2000009 #define IMX_SIP_WAKEUP_SRC_SCU 0x1 #define IMX_SIP_WAKEUP_SRC_IRQSTEER 0x2 #define IMX_SIP_OTP_READ 0xC200000A #define IMX_SIP_OTP_WRITE 0xC200000B #define IMX_SIP_MISC_SET_TEMP 0xC200000C #if defined(PLAT_imx8mq) int imx_soc_info_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3); #endif #if (defined(PLAT_imx8qm) || defined(PLAT_imx8qx)) int imx_cpufreq_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3); int imx_srtc_handler(uint32_t smc_fid, void *handle, u_register_t x1, u_register_t x2, u_register_t x3, u_register_t x4); int imx_wakeup_src_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3); int imx_otp_handler(uint32_t smc_fid, void *handle, u_register_t x1, u_register_t x2); int imx_misc_set_temp_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3, u_register_t x4); #endif uint64_t imx_buildinfo_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3, u_register_t x4); #endif /* __IMX_SIP_SVC_H__ */ trusted-firmware-a-2.2/plat/imx/common/include/imx_snvs.h000066400000000000000000000032311355360272700235770ustar00rootroot00000000000000/* * Copyright (C) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX_SNVS_H #define IMX_SNVS_H #include #include struct snvs { uint32_t hplr; uint32_t hpcomr; uint32_t hpcr; uint32_t hpsicr; uint32_t hpsvcr; uint32_t hpsr; uint32_t hpsvsr; uint32_t hphacivr; uint32_t hphacr; uint32_t hprtcmr; uint32_t hprtclr; uint32_t hptamr; uint32_t hptalr; uint32_t lplr; uint32_t lpcr; uint32_t lpmkcr; uint32_t lpsvcr; uint32_t lptgfcr; uint32_t lptdcr; uint32_t lpsr; uint32_t lpsrtcmr; uint32_t lpsrtclr; uint32_t lptar; uint32_t lpsmcmr; uint32_t lpsmclr; uint32_t lppgdr; uint32_t lpgpr0_alias; uint8_t lpzmkr[32]; uint16_t res0; uint32_t lpgpr0[4]; uint32_t lptdc2r; uint32_t lptdsr; uint32_t lptgf1cr; uint32_t lptgf2cr; uint32_t res1[4]; uint32_t lpat1cr; uint32_t lpat2cr; uint32_t lpat3cr; uint32_t lpat4cr; uint32_t lpat5cr; uint32_t res2[3]; uint32_t lpatctlr; uint32_t lpatclkr; uint32_t lpatrc1r; uint32_t lpatrc2r; uint32_t res3[706]; uint32_t hpvidr1; uint32_t hpvidr2; } __packed; /* Define the HPCOMR bits */ #define HPCOMR_NPSWA_EN BIT(31) #define HPCOMR_HAC_STOP BIT(19) #define HPCOMR_HAC_CLEAR BIT(18) #define HPCOMR_HAC_LOAD BIT(17) #define HPCOMR_HAC_EN BIT(16) #define HPCOMR_MKS_EN BIT(13) #define HPCOMR_PROG_ZMK BIT(12) #define HPCOMR_SW_LPSV BIT(10) #define HPCOMR_SW_FSV BIT(9) #define HPCOMR_SW_SV BIT(8) #define HPCOMR_LP_SWR_DIS BIT(5) #define HPCOMR_LP_SWR BIT(4) #define HPCOMR_SSM_SFNS_DIS BIT(2) #define HPCOMR_SSM_ST_DIS BIT(1) #define HPCOMR_SSM_ST BIT(0) void imx_snvs_init(void); #endif /* IMX_SNVS_H */ trusted-firmware-a-2.2/plat/imx/common/include/imx_uart.h000066400000000000000000000007141355360272700235640ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX_UART_H #define IMX_UART_H #include #ifndef __ASSEMBLER__ typedef struct { console_t console; uintptr_t base; } console_uart_t; int console_imx_uart_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, console_uart_t *console); #endif /*__ASSEMBLER__*/ #endif /* IMX_UART_H */ trusted-firmware-a-2.2/plat/imx/common/include/imx_wdog.h000066400000000000000000000020751355360272700235530ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX_WDOG_H #define IMX_WDOG_H #include #include struct wdog_regs { uint16_t wcr; uint16_t wsr; uint16_t wrsr; uint16_t wicr; uint16_t wmcr; }; /* WCR bits */ #define WCR_WDZST BIT(0) #define WCR_WDBG BIT(1) #define WCR_WDE BIT(2) #define WCR_WDT BIT(3) #define WCR_SRS BIT(4) #define WCR_WDA BIT(5) #define WCR_SRE BIT(6) #define WCR_WDW BIT(7) #define WCR_WT(x) ((x) << 8) /* WSR bits */ #define WSR_FIRST 0x5555 #define WSR_SECOND 0xAAAA /* WRSR bits */ #define WRSR_SFTW BIT(0) #define WRSR_TOUT BIT(1) #define WRSR_POR BIT(4) /* WICR bits */ static inline int wicr_calc_wict(int sec, int half_sec) { int wict_bits; /* Represents WICR bits 7 - 0 */ wict_bits = ((sec << 1) | (half_sec ? 1 : 0)); return wict_bits; } #define WICR_WTIS BIT(14) #define WICR_WIE BIT(15) /* WMCR bits */ #define WMCR_PDE BIT(0) /* External facing API */ void imx_wdog_init(void); #endif /* IMX_WDOG_H */ trusted-firmware-a-2.2/plat/imx/common/include/plat_imx8.h000066400000000000000000000020031355360272700236320ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_IMX8_H #define PLAT_IMX8_H #include #include struct plat_gic_ctx { gicv3_redist_ctx_t rdist_ctx[PLATFORM_CORE_COUNT]; gicv3_dist_ctx_t dist_ctx; }; unsigned int plat_calc_core_pos(uint64_t mpidr); void imx_mailbox_init(uintptr_t base_addr); void plat_gic_driver_init(void); void plat_gic_init(void); void plat_gic_cpuif_enable(void); void plat_gic_cpuif_disable(void); void plat_gic_pcpu_init(void); void __dead2 imx_system_off(void); void __dead2 imx_system_reset(void); int imx_validate_power_state(unsigned int power_state, psci_power_state_t *req_state); void imx_get_sys_suspend_power_state(psci_power_state_t *req_state); bool imx_is_wakeup_src_irqsteer(void); void plat_gic_save(unsigned int proc_num, struct plat_gic_ctx *ctx); void plat_gic_restore(unsigned int proc_num, struct plat_gic_ctx *ctx); #endif /* PLAT_IMX8_H */ trusted-firmware-a-2.2/plat/imx/common/include/plat_macros.S000066400000000000000000000014021355360272700242060ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * the below macros print out relevant GIC * registers whenever an unhandled exception is * taken in BL3-1 */ .macro plat_print_gic_regs /* TODO */ .endm /* * the below macros print out relevant interconnect * registers whenever an unhandled exception is * taken in BL3-1 */ .macro plat_print_interconnect_regs /* TODO */ .endm /* --------------------------------------------- * The below required platform porting macro * prints out relevant platform registers * whenever an unhandled exception is taken in * BL31. * --------------------------------------------- */ .macro plat_crash_print_regs /* TODO */ .endm trusted-firmware-a-2.2/plat/imx/common/include/sci/000077500000000000000000000000001355360272700223375ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/include/sci/sci.h000066400000000000000000000006471355360272700232750ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SCI_H #define SCI_H /* Defines */ /* Includes */ #include #include #include #include #include #include #endif /* SCI_H */ trusted-firmware-a-2.2/plat/imx/common/include/sci/sci_ipc.h000066400000000000000000000027611355360272700241270ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /*! * Header file for the IPC implementation. */ #ifndef SCI_IPC_H #define SCI_IPC_H /* Includes */ #include /* Defines */ /* Types */ /* Functions */ /*! * This function opens an IPC channel. * * @param[out] ipc return pointer for ipc handle * @param[in] id id of channel to open * * @return Returns an error code (SC_ERR_NONE = success, SC_ERR_IPC * otherwise). * * The \a id parameter is implementation specific. Could be an MU * address, pointer to a driver path, channel index, etc. */ sc_err_t sc_ipc_open(sc_ipc_t *ipc, sc_ipc_id_t id); /*! * This function closes an IPC channel. * * @param[in] ipc id of channel to close */ void sc_ipc_close(sc_ipc_t ipc); /*! * This function reads a message from an IPC channel. * * @param[in] ipc id of channel read from * @param[out] data pointer to message buffer to read * * This function will block if no message is available to be read. */ void sc_ipc_read(sc_ipc_t ipc, void *data); /*! * This function writes a message to an IPC channel. * * @param[in] ipc id of channel to write to * @param[in] data pointer to message buffer to write * * This function will block if the outgoing buffer is full. */ void sc_ipc_write(sc_ipc_t ipc, void *data); sc_ipc_t ipc_handle; #endif /* SCI_IPC_H */ trusted-firmware-a-2.2/plat/imx/common/include/sci/sci_rpc.h000066400000000000000000000071121355360272700241330ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /*! * Header file for the RPC implementation. */ #ifndef SCI_RPC_H #define SCI_RPC_H /* Includes */ #include #include #include /* Defines */ #define SC_RPC_VERSION 1U #define SC_RPC_MAX_MSG 8U #define RPC_VER(MSG) ((MSG)->version) #define RPC_SIZE(MSG) ((MSG)->size) #define RPC_SVC(MSG) ((MSG)->svc) #define RPC_FUNC(MSG) ((MSG)->func) #define RPC_R8(MSG) ((MSG)->func) #define RPC_I32(MSG, IDX) ((MSG)->DATA.i32[(IDX) / 4U]) #define RPC_I16(MSG, IDX) ((MSG)->DATA.i16[(IDX) / 2U]) #define RPC_I8(MSG, IDX) ((MSG)->DATA.i8[(IDX)]) #define RPC_U32(MSG, IDX) ((MSG)->DATA.u32[(IDX) / 4U]) #define RPC_U16(MSG, IDX) ((MSG)->DATA.u16[(IDX) / 2U]) #define RPC_U8(MSG, IDX) ((MSG)->DATA.u8[(IDX)]) #define SC_RPC_SVC_UNKNOWN 0U #define SC_RPC_SVC_RETURN 1U #define SC_RPC_SVC_PM 2U #define SC_RPC_SVC_RM 3U #define SC_RPC_SVC_TIMER 5U #define SC_RPC_SVC_PAD 6U #define SC_RPC_SVC_MISC 7U #define SC_RPC_SVC_IRQ 8U #define SC_RPC_SVC_ABORT 9U #define SC_RPC_ASYNC_STATE_RD_START 0U #define SC_RPC_ASYNC_STATE_RD_ACTIVE 1U #define SC_RPC_ASYNC_STATE_RD_DONE 2U #define SC_RPC_ASYNC_STATE_WR_START 3U #define SC_RPC_ASYNC_STATE_WR_ACTIVE 4U #define SC_RPC_ASYNC_STATE_WR_DONE 5U #define SC_RPC_MU_GIR_SVC 0x1U #define SC_RPC_MU_GIR_DBG 0x8U /* Types */ typedef uint8_t sc_rpc_svc_t; typedef struct sc_rpc_msg_s { uint8_t version; uint8_t size; uint8_t svc; uint8_t func; union { int32_t i32[(SC_RPC_MAX_MSG - 1U)]; int16_t i16[(SC_RPC_MAX_MSG - 1U) * 2U]; int8_t i8[(SC_RPC_MAX_MSG - 1U) * 4U]; uint32_t u32[(SC_RPC_MAX_MSG - 1U)]; uint16_t u16[(SC_RPC_MAX_MSG - 1U) * 2U]; uint8_t u8[(SC_RPC_MAX_MSG - 1U) * 4U]; } DATA; } sc_rpc_msg_t; typedef uint8_t sc_rpc_async_state_t; typedef struct sc_rpc_async_msg_s { sc_rpc_async_state_t state; uint8_t wordIdx; sc_rpc_msg_t msg; uint32_t timeStamp; } sc_rpc_async_msg_t; /* Functions */ /*! * This is an internal function to send an RPC message over an IPC * channel. It is called by client-side SCFW API function shims. * * @param[in] ipc IPC handle * @param[in,out] msg handle to a message * @param[in] no_resp response flag * * If \a no_resp is SC_FALSE then this function waits for a response * and returns the result in \a msg. */ void sc_call_rpc(sc_ipc_t ipc, sc_rpc_msg_t *msg, bool no_resp); /*! * This is an internal function to dispath an RPC call that has * arrived via IPC over an MU. It is called by server-side SCFW. * * @param[in] mu MU message arrived on * @param[in,out] msg handle to a message * * The function result is returned in \a msg. */ void sc_rpc_dispatch(sc_rsrc_t mu, sc_rpc_msg_t *msg); /*! * This function translates an RPC message and forwards on to the * normal RPC API. It is used only by hypervisors. * * @param[in] ipc IPC handle * @param[in,out] msg handle to a message * * This function decodes a message, calls macros to translate the * resources, pads, addresses, partitions, memory regions, etc. and * then forwards on to the hypervisors SCFW API.Return results are * translated back abd placed back into the message to be returned * to the original API. */ void sc_rpc_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg); #endif /* SCI_RPC_H */ trusted-firmware-a-2.2/plat/imx/common/include/sci/sci_scfw.h000066400000000000000000000020061355360272700243060ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SCI_SCFW_H #define SCI_SCFW_H /* Includes */ #include #ifdef __cplusplus #define __I volatile /*!< Defines 'read only' permissions */ #else #define __I volatile const /*!< Defines 'read only' permissions */ #endif #define __O volatile /*!< Defines 'write only' permissions */ #define __IO volatile /*!< Defines 'read / write' permissions */ /*! * This type is used to declare a handle for an IPC communication * channel. Its meaning is specific to the IPC implementation. */ typedef uint64_t sc_ipc_t; /*! * This type is used to declare an ID for an IPC communication * channel. For the reference IPC implementation, this ID * selects the base address of the MU used for IPC. */ typedef uint64_t sc_ipc_id_t; #endif /* SCI_SCFW_H */ trusted-firmware-a-2.2/plat/imx/common/include/sci/sci_types.h000066400000000000000000000746141355360272700245260ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /*! * Header file containing types used across multiple service APIs. */ #ifndef SCI_TYPES_H #define SCI_TYPES_H /* Includes */ #include /* Defines */ /*! * @name Defines for common frequencies */ /*@{*/ #define SC_32KHZ 32768U /* 32KHz */ #define SC_10MHZ 10000000U /* 10MHz */ #define SC_20MHZ 20000000U /* 20MHz */ #define SC_25MHZ 25000000U /* 25MHz */ #define SC_27MHZ 27000000U /* 27MHz */ #define SC_40MHZ 40000000U /* 40MHz */ #define SC_45MHZ 45000000U /* 45MHz */ #define SC_50MHZ 50000000U /* 50MHz */ #define SC_60MHZ 60000000U /* 60MHz */ #define SC_66MHZ 66666666U /* 66MHz */ #define SC_74MHZ 74250000U /* 74.25MHz */ #define SC_80MHZ 80000000U /* 80MHz */ #define SC_83MHZ 83333333U /* 83MHz */ #define SC_84MHZ 84375000U /* 84.37MHz */ #define SC_100MHZ 100000000U /* 100MHz */ #define SC_125MHZ 125000000U /* 125MHz */ #define SC_133MHZ 133333333U /* 133MHz */ #define SC_135MHZ 135000000U /* 135MHz */ #define SC_150MHZ 150000000U /* 150MHz */ #define SC_160MHZ 160000000U /* 160MHz */ #define SC_166MHZ 166666666U /* 166MHz */ #define SC_175MHZ 175000000U /* 175MHz */ #define SC_180MHZ 180000000U /* 180MHz */ #define SC_200MHZ 200000000U /* 200MHz */ #define SC_250MHZ 250000000U /* 250MHz */ #define SC_266MHZ 266666666U /* 266MHz */ #define SC_300MHZ 300000000U /* 300MHz */ #define SC_312MHZ 312500000U /* 312.5MHZ */ #define SC_320MHZ 320000000U /* 320MHz */ #define SC_325MHZ 325000000U /* 325MHz */ #define SC_333MHZ 333333333U /* 333MHz */ #define SC_350MHZ 350000000U /* 350MHz */ #define SC_372MHZ 372000000U /* 372MHz */ #define SC_375MHZ 375000000U /* 375MHz */ #define SC_400MHZ 400000000U /* 400MHz */ #define SC_500MHZ 500000000U /* 500MHz */ #define SC_594MHZ 594000000U /* 594MHz */ #define SC_625MHZ 625000000U /* 625MHz */ #define SC_640MHZ 640000000U /* 640MHz */ #define SC_650MHZ 650000000U /* 650MHz */ #define SC_667MHZ 666666667U /* 667MHz */ #define SC_675MHZ 675000000U /* 675MHz */ #define SC_700MHZ 700000000U /* 700MHz */ #define SC_720MHZ 720000000U /* 720MHz */ #define SC_750MHZ 750000000U /* 750MHz */ #define SC_800MHZ 800000000U /* 800MHz */ #define SC_850MHZ 850000000U /* 850MHz */ #define SC_900MHZ 900000000U /* 900MHz */ #define SC_1000MHZ 1000000000U /* 1GHz */ #define SC_1056MHZ 1056000000U /* 1.056GHz */ #define SC_1188MHZ 1188000000U /* 1.188GHz */ #define SC_1260MHZ 1260000000U /* 1.26GHz */ #define SC_1280MHZ 1280000000U /* 1.28GHz */ #define SC_1300MHZ 1300000000U /* 1.3GHz */ #define SC_1400MHZ 1400000000U /* 1.4GHz */ #define SC_1500MHZ 1500000000U /* 1.5GHz */ #define SC_1600MHZ 1600000000U /* 1.6GHz */ #define SC_1800MHZ 1800000000U /* 1.8GHz */ #define SC_2000MHZ 2000000000U /* 2.0GHz */ #define SC_2112MHZ 2112000000U /* 2.12GHz */ /*@}*/ /*! * @name Defines for 24M related frequencies */ /*@{*/ #define SC_8MHZ 8000000U /* 8MHz */ #define SC_12MHZ 12000000U /* 12MHz */ #define SC_19MHZ 19800000U /* 19.8MHz */ #define SC_24MHZ 24000000U /* 24MHz */ #define SC_48MHZ 48000000U /* 48MHz */ #define SC_120MHZ 120000000U /* 120MHz */ #define SC_132MHZ 132000000U /* 132MHz */ #define SC_144MHZ 144000000U /* 144MHz */ #define SC_192MHZ 192000000U /* 192MHz */ #define SC_211MHZ 211200000U /* 211.2MHz */ #define SC_240MHZ 240000000U /* 240MHz */ #define SC_264MHZ 264000000U /* 264MHz */ #define SC_352MHZ 352000000U /* 352MHz */ #define SC_360MHZ 360000000U /* 360MHz */ #define SC_384MHZ 384000000U /* 384MHz */ #define SC_396MHZ 396000000U /* 396MHz */ #define SC_432MHZ 432000000U /* 432MHz */ #define SC_480MHZ 480000000U /* 480MHz */ #define SC_600MHZ 600000000U /* 600MHz */ #define SC_744MHZ 744000000U /* 744MHz */ #define SC_792MHZ 792000000U /* 792MHz */ #define SC_864MHZ 864000000U /* 864MHz */ #define SC_960MHZ 960000000U /* 960MHz */ #define SC_1056MHZ 1056000000U /* 1056MHz */ #define SC_1200MHZ 1200000000U /* 1.2GHz */ #define SC_1464MHZ 1464000000U /* 1.464GHz */ #define SC_2400MHZ 2400000000U /* 2.4GHz */ /*@}*/ /*! * @name Defines for A/V related frequencies */ /*@{*/ #define SC_62MHZ 62937500U /* 62.9375MHz */ #define SC_755MHZ 755250000U /* 755.25MHz */ /*@}*/ /*! * @name Defines for type widths */ /*@{*/ #define SC_FADDR_W 36U /* Width of sc_faddr_t */ #define SC_BOOL_W 1U /* Width of sc_bool_t */ #define SC_ERR_W 4U /* Width of sc_err_t */ #define SC_RSRC_W 10U /* Width of sc_rsrc_t */ #define SC_CTRL_W 6U /* Width of sc_ctrl_t */ /*@}*/ /*! * @name Defines for sc_bool_t */ /*@{*/ #define SC_FALSE ((sc_bool_t) 0U) /* True */ #define SC_TRUE ((sc_bool_t) 1U) /* False */ /*@}*/ /*! * @name Defines for sc_err_t. */ /*@{*/ #define SC_ERR_NONE 0U /* Success */ #define SC_ERR_VERSION 1U /* Incompatible API version */ #define SC_ERR_CONFIG 2U /* Configuration error */ #define SC_ERR_PARM 3U /* Bad parameter */ #define SC_ERR_NOACCESS 4U /* Permission error (no access) */ #define SC_ERR_LOCKED 5U /* Permission error (locked) */ #define SC_ERR_UNAVAILABLE 6U /* Unavailable (out of resources) */ #define SC_ERR_NOTFOUND 7U /* Not found */ #define SC_ERR_NOPOWER 8U /* No power */ #define SC_ERR_IPC 9U /* Generic IPC error */ #define SC_ERR_BUSY 10U /* Resource is currently busy/active */ #define SC_ERR_FAIL 11U /* General I/O failure */ #define SC_ERR_LAST 12U /*@}*/ /*! * @name Defines for sc_rsrc_t. */ /*@{*/ #define SC_R_A53 0U #define SC_R_A53_0 1U #define SC_R_A53_1 2U #define SC_R_A53_2 3U #define SC_R_A53_3 4U #define SC_R_A72 5U #define SC_R_A72_0 6U #define SC_R_A72_1 7U #define SC_R_A72_2 8U #define SC_R_A72_3 9U #define SC_R_CCI 10U #define SC_R_DB 11U #define SC_R_DRC_0 12U #define SC_R_DRC_1 13U #define SC_R_GIC_SMMU 14U #define SC_R_IRQSTR_M4_0 15U #define SC_R_IRQSTR_M4_1 16U #define SC_R_SMMU 17U #define SC_R_GIC 18U #define SC_R_DC_0_BLIT0 19U #define SC_R_DC_0_BLIT1 20U #define SC_R_DC_0_BLIT2 21U #define SC_R_DC_0_BLIT_OUT 22U #define SC_R_DC_0_CAPTURE0 23U #define SC_R_DC_0_CAPTURE1 24U #define SC_R_DC_0_WARP 25U #define SC_R_DC_0_INTEGRAL0 26U #define SC_R_DC_0_INTEGRAL1 27U #define SC_R_DC_0_VIDEO0 28U #define SC_R_DC_0_VIDEO1 29U #define SC_R_DC_0_FRAC0 30U #define SC_R_DC_0_FRAC1 31U #define SC_R_DC_0 32U #define SC_R_GPU_2_PID0 33U #define SC_R_DC_0_PLL_0 34U #define SC_R_DC_0_PLL_1 35U #define SC_R_DC_1_BLIT0 36U #define SC_R_DC_1_BLIT1 37U #define SC_R_DC_1_BLIT2 38U #define SC_R_DC_1_BLIT_OUT 39U #define SC_R_DC_1_CAPTURE0 40U #define SC_R_DC_1_CAPTURE1 41U #define SC_R_DC_1_WARP 42U #define SC_R_DC_1_INTEGRAL0 43U #define SC_R_DC_1_INTEGRAL1 44U #define SC_R_DC_1_VIDEO0 45U #define SC_R_DC_1_VIDEO1 46U #define SC_R_DC_1_FRAC0 47U #define SC_R_DC_1_FRAC1 48U #define SC_R_DC_1 49U #define SC_R_GPU_3_PID0 50U #define SC_R_DC_1_PLL_0 51U #define SC_R_DC_1_PLL_1 52U #define SC_R_SPI_0 53U #define SC_R_SPI_1 54U #define SC_R_SPI_2 55U #define SC_R_SPI_3 56U #define SC_R_UART_0 57U #define SC_R_UART_1 58U #define SC_R_UART_2 59U #define SC_R_UART_3 60U #define SC_R_UART_4 61U #define SC_R_EMVSIM_0 62U #define SC_R_EMVSIM_1 63U #define SC_R_DMA_0_CH0 64U #define SC_R_DMA_0_CH1 65U #define SC_R_DMA_0_CH2 66U #define SC_R_DMA_0_CH3 67U #define SC_R_DMA_0_CH4 68U #define SC_R_DMA_0_CH5 69U #define SC_R_DMA_0_CH6 70U #define SC_R_DMA_0_CH7 71U #define SC_R_DMA_0_CH8 72U #define SC_R_DMA_0_CH9 73U #define SC_R_DMA_0_CH10 74U #define SC_R_DMA_0_CH11 75U #define SC_R_DMA_0_CH12 76U #define SC_R_DMA_0_CH13 77U #define SC_R_DMA_0_CH14 78U #define SC_R_DMA_0_CH15 79U #define SC_R_DMA_0_CH16 80U #define SC_R_DMA_0_CH17 81U #define SC_R_DMA_0_CH18 82U #define SC_R_DMA_0_CH19 83U #define SC_R_DMA_0_CH20 84U #define SC_R_DMA_0_CH21 85U #define SC_R_DMA_0_CH22 86U #define SC_R_DMA_0_CH23 87U #define SC_R_DMA_0_CH24 88U #define SC_R_DMA_0_CH25 89U #define SC_R_DMA_0_CH26 90U #define SC_R_DMA_0_CH27 91U #define SC_R_DMA_0_CH28 92U #define SC_R_DMA_0_CH29 93U #define SC_R_DMA_0_CH30 94U #define SC_R_DMA_0_CH31 95U #define SC_R_I2C_0 96U #define SC_R_I2C_1 97U #define SC_R_I2C_2 98U #define SC_R_I2C_3 99U #define SC_R_I2C_4 100U #define SC_R_ADC_0 101U #define SC_R_ADC_1 102U #define SC_R_FTM_0 103U #define SC_R_FTM_1 104U #define SC_R_CAN_0 105U #define SC_R_CAN_1 106U #define SC_R_CAN_2 107U #define SC_R_DMA_1_CH0 108U #define SC_R_DMA_1_CH1 109U #define SC_R_DMA_1_CH2 110U #define SC_R_DMA_1_CH3 111U #define SC_R_DMA_1_CH4 112U #define SC_R_DMA_1_CH5 113U #define SC_R_DMA_1_CH6 114U #define SC_R_DMA_1_CH7 115U #define SC_R_DMA_1_CH8 116U #define SC_R_DMA_1_CH9 117U #define SC_R_DMA_1_CH10 118U #define SC_R_DMA_1_CH11 119U #define SC_R_DMA_1_CH12 120U #define SC_R_DMA_1_CH13 121U #define SC_R_DMA_1_CH14 122U #define SC_R_DMA_1_CH15 123U #define SC_R_DMA_1_CH16 124U #define SC_R_DMA_1_CH17 125U #define SC_R_DMA_1_CH18 126U #define SC_R_DMA_1_CH19 127U #define SC_R_DMA_1_CH20 128U #define SC_R_DMA_1_CH21 129U #define SC_R_DMA_1_CH22 130U #define SC_R_DMA_1_CH23 131U #define SC_R_DMA_1_CH24 132U #define SC_R_DMA_1_CH25 133U #define SC_R_DMA_1_CH26 134U #define SC_R_DMA_1_CH27 135U #define SC_R_DMA_1_CH28 136U #define SC_R_DMA_1_CH29 137U #define SC_R_DMA_1_CH30 138U #define SC_R_DMA_1_CH31 139U #define SC_R_UNUSED1 140U #define SC_R_UNUSED2 141U #define SC_R_UNUSED3 142U #define SC_R_UNUSED4 143U #define SC_R_GPU_0_PID0 144U #define SC_R_GPU_0_PID1 145U #define SC_R_GPU_0_PID2 146U #define SC_R_GPU_0_PID3 147U #define SC_R_GPU_1_PID0 148U #define SC_R_GPU_1_PID1 149U #define SC_R_GPU_1_PID2 150U #define SC_R_GPU_1_PID3 151U #define SC_R_PCIE_A 152U #define SC_R_SERDES_0 153U #define SC_R_MATCH_0 154U #define SC_R_MATCH_1 155U #define SC_R_MATCH_2 156U #define SC_R_MATCH_3 157U #define SC_R_MATCH_4 158U #define SC_R_MATCH_5 159U #define SC_R_MATCH_6 160U #define SC_R_MATCH_7 161U #define SC_R_MATCH_8 162U #define SC_R_MATCH_9 163U #define SC_R_MATCH_10 164U #define SC_R_MATCH_11 165U #define SC_R_MATCH_12 166U #define SC_R_MATCH_13 167U #define SC_R_MATCH_14 168U #define SC_R_PCIE_B 169U #define SC_R_SATA_0 170U #define SC_R_SERDES_1 171U #define SC_R_HSIO_GPIO 172U #define SC_R_MATCH_15 173U #define SC_R_MATCH_16 174U #define SC_R_MATCH_17 175U #define SC_R_MATCH_18 176U #define SC_R_MATCH_19 177U #define SC_R_MATCH_20 178U #define SC_R_MATCH_21 179U #define SC_R_MATCH_22 180U #define SC_R_MATCH_23 181U #define SC_R_MATCH_24 182U #define SC_R_MATCH_25 183U #define SC_R_MATCH_26 184U #define SC_R_MATCH_27 185U #define SC_R_MATCH_28 186U #define SC_R_LCD_0 187U #define SC_R_LCD_0_PWM_0 188U #define SC_R_LCD_0_I2C_0 189U #define SC_R_LCD_0_I2C_1 190U #define SC_R_PWM_0 191U #define SC_R_PWM_1 192U #define SC_R_PWM_2 193U #define SC_R_PWM_3 194U #define SC_R_PWM_4 195U #define SC_R_PWM_5 196U #define SC_R_PWM_6 197U #define SC_R_PWM_7 198U #define SC_R_GPIO_0 199U #define SC_R_GPIO_1 200U #define SC_R_GPIO_2 201U #define SC_R_GPIO_3 202U #define SC_R_GPIO_4 203U #define SC_R_GPIO_5 204U #define SC_R_GPIO_6 205U #define SC_R_GPIO_7 206U #define SC_R_GPT_0 207U #define SC_R_GPT_1 208U #define SC_R_GPT_2 209U #define SC_R_GPT_3 210U #define SC_R_GPT_4 211U #define SC_R_KPP 212U #define SC_R_MU_0A 213U #define SC_R_MU_1A 214U #define SC_R_MU_2A 215U #define SC_R_MU_3A 216U #define SC_R_MU_4A 217U #define SC_R_MU_5A 218U #define SC_R_MU_6A 219U #define SC_R_MU_7A 220U #define SC_R_MU_8A 221U #define SC_R_MU_9A 222U #define SC_R_MU_10A 223U #define SC_R_MU_11A 224U #define SC_R_MU_12A 225U #define SC_R_MU_13A 226U #define SC_R_MU_5B 227U #define SC_R_MU_6B 228U #define SC_R_MU_7B 229U #define SC_R_MU_8B 230U #define SC_R_MU_9B 231U #define SC_R_MU_10B 232U #define SC_R_MU_11B 233U #define SC_R_MU_12B 234U #define SC_R_MU_13B 235U #define SC_R_ROM_0 236U #define SC_R_FSPI_0 237U #define SC_R_FSPI_1 238U #define SC_R_IEE 239U #define SC_R_IEE_R0 240U #define SC_R_IEE_R1 241U #define SC_R_IEE_R2 242U #define SC_R_IEE_R3 243U #define SC_R_IEE_R4 244U #define SC_R_IEE_R5 245U #define SC_R_IEE_R6 246U #define SC_R_IEE_R7 247U #define SC_R_SDHC_0 248U #define SC_R_SDHC_1 249U #define SC_R_SDHC_2 250U #define SC_R_ENET_0 251U #define SC_R_ENET_1 252U #define SC_R_MLB_0 253U #define SC_R_DMA_2_CH0 254U #define SC_R_DMA_2_CH1 255U #define SC_R_DMA_2_CH2 256U #define SC_R_DMA_2_CH3 257U #define SC_R_DMA_2_CH4 258U #define SC_R_USB_0 259U #define SC_R_USB_1 260U #define SC_R_USB_0_PHY 261U #define SC_R_USB_2 262U #define SC_R_USB_2_PHY 263U #define SC_R_DTCP 264U #define SC_R_NAND 265U #define SC_R_LVDS_0 266U #define SC_R_LVDS_0_PWM_0 267U #define SC_R_LVDS_0_I2C_0 268U #define SC_R_LVDS_0_I2C_1 269U #define SC_R_LVDS_1 270U #define SC_R_LVDS_1_PWM_0 271U #define SC_R_LVDS_1_I2C_0 272U #define SC_R_LVDS_1_I2C_1 273U #define SC_R_LVDS_2 274U #define SC_R_LVDS_2_PWM_0 275U #define SC_R_LVDS_2_I2C_0 276U #define SC_R_LVDS_2_I2C_1 277U #define SC_R_M4_0_PID0 278U #define SC_R_M4_0_PID1 279U #define SC_R_M4_0_PID2 280U #define SC_R_M4_0_PID3 281U #define SC_R_M4_0_PID4 282U #define SC_R_M4_0_RGPIO 283U #define SC_R_M4_0_SEMA42 284U #define SC_R_M4_0_TPM 285U #define SC_R_M4_0_PIT 286U #define SC_R_M4_0_UART 287U #define SC_R_M4_0_I2C 288U #define SC_R_M4_0_INTMUX 289U #define SC_R_M4_0_SIM 290U #define SC_R_M4_0_WDOG 291U #define SC_R_M4_0_MU_0B 292U #define SC_R_M4_0_MU_0A0 293U #define SC_R_M4_0_MU_0A1 294U #define SC_R_M4_0_MU_0A2 295U #define SC_R_M4_0_MU_0A3 296U #define SC_R_M4_0_MU_1A 297U #define SC_R_M4_1_PID0 298U #define SC_R_M4_1_PID1 299U #define SC_R_M4_1_PID2 300U #define SC_R_M4_1_PID3 301U #define SC_R_M4_1_PID4 302U #define SC_R_M4_1_RGPIO 303U #define SC_R_M4_1_SEMA42 304U #define SC_R_M4_1_TPM 305U #define SC_R_M4_1_PIT 306U #define SC_R_M4_1_UART 307U #define SC_R_M4_1_I2C 308U #define SC_R_M4_1_INTMUX 309U #define SC_R_M4_1_SIM 310U #define SC_R_M4_1_WDOG 311U #define SC_R_M4_1_MU_0B 312U #define SC_R_M4_1_MU_0A0 313U #define SC_R_M4_1_MU_0A1 314U #define SC_R_M4_1_MU_0A2 315U #define SC_R_M4_1_MU_0A3 316U #define SC_R_M4_1_MU_1A 317U #define SC_R_SAI_0 318U #define SC_R_SAI_1 319U #define SC_R_SAI_2 320U #define SC_R_IRQSTR_SCU2 321U #define SC_R_IRQSTR_DSP 322U #define SC_R_UNUSED5 323U #define SC_R_OCRAM 324U #define SC_R_AUDIO_PLL_0 325U #define SC_R_PI_0 326U #define SC_R_PI_0_PWM_0 327U #define SC_R_PI_0_PWM_1 328U #define SC_R_PI_0_I2C_0 329U #define SC_R_PI_0_PLL 330U #define SC_R_PI_1 331U #define SC_R_PI_1_PWM_0 332U #define SC_R_PI_1_PWM_1 333U #define SC_R_PI_1_I2C_0 334U #define SC_R_PI_1_PLL 335U #define SC_R_SC_PID0 336U #define SC_R_SC_PID1 337U #define SC_R_SC_PID2 338U #define SC_R_SC_PID3 339U #define SC_R_SC_PID4 340U #define SC_R_SC_SEMA42 341U #define SC_R_SC_TPM 342U #define SC_R_SC_PIT 343U #define SC_R_SC_UART 344U #define SC_R_SC_I2C 345U #define SC_R_SC_MU_0B 346U #define SC_R_SC_MU_0A0 347U #define SC_R_SC_MU_0A1 348U #define SC_R_SC_MU_0A2 349U #define SC_R_SC_MU_0A3 350U #define SC_R_SC_MU_1A 351U #define SC_R_SYSCNT_RD 352U #define SC_R_SYSCNT_CMP 353U #define SC_R_DEBUG 354U #define SC_R_SYSTEM 355U #define SC_R_SNVS 356U #define SC_R_OTP 357U #define SC_R_VPU_PID0 358U #define SC_R_VPU_PID1 359U #define SC_R_VPU_PID2 360U #define SC_R_VPU_PID3 361U #define SC_R_VPU_PID4 362U #define SC_R_VPU_PID5 363U #define SC_R_VPU_PID6 364U #define SC_R_VPU_PID7 365U #define SC_R_VPU_UART 366U #define SC_R_VPUCORE 367U #define SC_R_VPUCORE_0 368U #define SC_R_VPUCORE_1 369U #define SC_R_VPUCORE_2 370U #define SC_R_VPUCORE_3 371U #define SC_R_DMA_4_CH0 372U #define SC_R_DMA_4_CH1 373U #define SC_R_DMA_4_CH2 374U #define SC_R_DMA_4_CH3 375U #define SC_R_DMA_4_CH4 376U #define SC_R_ISI_CH0 377U #define SC_R_ISI_CH1 378U #define SC_R_ISI_CH2 379U #define SC_R_ISI_CH3 380U #define SC_R_ISI_CH4 381U #define SC_R_ISI_CH5 382U #define SC_R_ISI_CH6 383U #define SC_R_ISI_CH7 384U #define SC_R_MJPEG_DEC_S0 385U #define SC_R_MJPEG_DEC_S1 386U #define SC_R_MJPEG_DEC_S2 387U #define SC_R_MJPEG_DEC_S3 388U #define SC_R_MJPEG_ENC_S0 389U #define SC_R_MJPEG_ENC_S1 390U #define SC_R_MJPEG_ENC_S2 391U #define SC_R_MJPEG_ENC_S3 392U #define SC_R_MIPI_0 393U #define SC_R_MIPI_0_PWM_0 394U #define SC_R_MIPI_0_I2C_0 395U #define SC_R_MIPI_0_I2C_1 396U #define SC_R_MIPI_1 397U #define SC_R_MIPI_1_PWM_0 398U #define SC_R_MIPI_1_I2C_0 399U #define SC_R_MIPI_1_I2C_1 400U #define SC_R_CSI_0 401U #define SC_R_CSI_0_PWM_0 402U #define SC_R_CSI_0_I2C_0 403U #define SC_R_CSI_1 404U #define SC_R_CSI_1_PWM_0 405U #define SC_R_CSI_1_I2C_0 406U #define SC_R_HDMI 407U #define SC_R_HDMI_I2S 408U #define SC_R_HDMI_I2C_0 409U #define SC_R_HDMI_PLL_0 410U #define SC_R_HDMI_RX 411U #define SC_R_HDMI_RX_BYPASS 412U #define SC_R_HDMI_RX_I2C_0 413U #define SC_R_ASRC_0 414U #define SC_R_ESAI_0 415U #define SC_R_SPDIF_0 416U #define SC_R_SPDIF_1 417U #define SC_R_SAI_3 418U #define SC_R_SAI_4 419U #define SC_R_SAI_5 420U #define SC_R_GPT_5 421U #define SC_R_GPT_6 422U #define SC_R_GPT_7 423U #define SC_R_GPT_8 424U #define SC_R_GPT_9 425U #define SC_R_GPT_10 426U #define SC_R_DMA_2_CH5 427U #define SC_R_DMA_2_CH6 428U #define SC_R_DMA_2_CH7 429U #define SC_R_DMA_2_CH8 430U #define SC_R_DMA_2_CH9 431U #define SC_R_DMA_2_CH10 432U #define SC_R_DMA_2_CH11 433U #define SC_R_DMA_2_CH12 434U #define SC_R_DMA_2_CH13 435U #define SC_R_DMA_2_CH14 436U #define SC_R_DMA_2_CH15 437U #define SC_R_DMA_2_CH16 438U #define SC_R_DMA_2_CH17 439U #define SC_R_DMA_2_CH18 440U #define SC_R_DMA_2_CH19 441U #define SC_R_DMA_2_CH20 442U #define SC_R_DMA_2_CH21 443U #define SC_R_DMA_2_CH22 444U #define SC_R_DMA_2_CH23 445U #define SC_R_DMA_2_CH24 446U #define SC_R_DMA_2_CH25 447U #define SC_R_DMA_2_CH26 448U #define SC_R_DMA_2_CH27 449U #define SC_R_DMA_2_CH28 450U #define SC_R_DMA_2_CH29 451U #define SC_R_DMA_2_CH30 452U #define SC_R_DMA_2_CH31 453U #define SC_R_ASRC_1 454U #define SC_R_ESAI_1 455U #define SC_R_SAI_6 456U #define SC_R_SAI_7 457U #define SC_R_AMIX 458U #define SC_R_MQS_0 459U #define SC_R_DMA_3_CH0 460U #define SC_R_DMA_3_CH1 461U #define SC_R_DMA_3_CH2 462U #define SC_R_DMA_3_CH3 463U #define SC_R_DMA_3_CH4 464U #define SC_R_DMA_3_CH5 465U #define SC_R_DMA_3_CH6 466U #define SC_R_DMA_3_CH7 467U #define SC_R_DMA_3_CH8 468U #define SC_R_DMA_3_CH9 469U #define SC_R_DMA_3_CH10 470U #define SC_R_DMA_3_CH11 471U #define SC_R_DMA_3_CH12 472U #define SC_R_DMA_3_CH13 473U #define SC_R_DMA_3_CH14 474U #define SC_R_DMA_3_CH15 475U #define SC_R_DMA_3_CH16 476U #define SC_R_DMA_3_CH17 477U #define SC_R_DMA_3_CH18 478U #define SC_R_DMA_3_CH19 479U #define SC_R_DMA_3_CH20 480U #define SC_R_DMA_3_CH21 481U #define SC_R_DMA_3_CH22 482U #define SC_R_DMA_3_CH23 483U #define SC_R_DMA_3_CH24 484U #define SC_R_DMA_3_CH25 485U #define SC_R_DMA_3_CH26 486U #define SC_R_DMA_3_CH27 487U #define SC_R_DMA_3_CH28 488U #define SC_R_DMA_3_CH29 489U #define SC_R_DMA_3_CH30 490U #define SC_R_DMA_3_CH31 491U #define SC_R_AUDIO_PLL_1 492U #define SC_R_AUDIO_CLK_0 493U #define SC_R_AUDIO_CLK_1 494U #define SC_R_MCLK_OUT_0 495U #define SC_R_MCLK_OUT_1 496U #define SC_R_PMIC_0 497U #define SC_R_PMIC_1 498U #define SC_R_SECO 499U #define SC_R_CAAM_JR1 500U #define SC_R_CAAM_JR2 501U #define SC_R_CAAM_JR3 502U #define SC_R_SECO_MU_2 503U #define SC_R_SECO_MU_3 504U #define SC_R_SECO_MU_4 505U #define SC_R_HDMI_RX_PWM_0 506U #define SC_R_A35 507U #define SC_R_A35_0 508U #define SC_R_A35_1 509U #define SC_R_A35_2 510U #define SC_R_A35_3 511U #define SC_R_DSP 512U #define SC_R_DSP_RAM 513U #define SC_R_CAAM_JR1_OUT 514U #define SC_R_CAAM_JR2_OUT 515U #define SC_R_CAAM_JR3_OUT 516U #define SC_R_VPU_DEC_0 517U #define SC_R_VPU_ENC_0 518U #define SC_R_CAAM_JR0 519U #define SC_R_CAAM_JR0_OUT 520U #define SC_R_PMIC_2 521U #define SC_R_DBLOGIC 522U #define SC_R_HDMI_PLL_1 523U #define SC_R_BOARD_R0 524U #define SC_R_BOARD_R1 525U #define SC_R_BOARD_R2 526U #define SC_R_BOARD_R3 527U #define SC_R_BOARD_R4 528U #define SC_R_BOARD_R5 529U #define SC_R_BOARD_R6 530U #define SC_R_BOARD_R7 531U #define SC_R_MJPEG_DEC_MP 532U #define SC_R_MJPEG_ENC_MP 533U #define SC_R_VPU_TS_0 534U #define SC_R_VPU_MU_0 535U #define SC_R_VPU_MU_1 536U #define SC_R_VPU_MU_2 537U #define SC_R_VPU_MU_3 538U #define SC_R_VPU_ENC_1 539U #define SC_R_VPU 540U #define SC_R_LAST 541U #define SC_R_ALL ((sc_rsrc_t) UINT16_MAX) /* All resources */ /*@}*/ /* NOTE - please add by replacing some of the UNUSED from above! */ /*! * Defnes for sc_ctrl_t. */ #define SC_C_TEMP 0U #define SC_C_TEMP_HI 1U #define SC_C_TEMP_LOW 2U #define SC_C_PXL_LINK_MST1_ADDR 3U #define SC_C_PXL_LINK_MST2_ADDR 4U #define SC_C_PXL_LINK_MST_ENB 5U #define SC_C_PXL_LINK_MST1_ENB 6U #define SC_C_PXL_LINK_MST2_ENB 7U #define SC_C_PXL_LINK_SLV1_ADDR 8U #define SC_C_PXL_LINK_SLV2_ADDR 9U #define SC_C_PXL_LINK_MST_VLD 10U #define SC_C_PXL_LINK_MST1_VLD 11U #define SC_C_PXL_LINK_MST2_VLD 12U #define SC_C_SINGLE_MODE 13U #define SC_C_ID 14U #define SC_C_PXL_CLK_POLARITY 15U #define SC_C_LINESTATE 16U #define SC_C_PCIE_G_RST 17U #define SC_C_PCIE_BUTTON_RST 18U #define SC_C_PCIE_PERST 19U #define SC_C_PHY_RESET 20U #define SC_C_PXL_LINK_RATE_CORRECTION 21U #define SC_C_PANIC 22U #define SC_C_PRIORITY_GROUP 23U #define SC_C_TXCLK 24U #define SC_C_CLKDIV 25U #define SC_C_DISABLE_50 26U #define SC_C_DISABLE_125 27U #define SC_C_SEL_125 28U #define SC_C_MODE 29U #define SC_C_SYNC_CTRL0 30U #define SC_C_KACHUNK_CNT 31U #define SC_C_KACHUNK_SEL 32U #define SC_C_SYNC_CTRL1 33U #define SC_C_DPI_RESET 34U #define SC_C_MIPI_RESET 35U #define SC_C_DUAL_MODE 36U #define SC_C_VOLTAGE 37U #define SC_C_PXL_LINK_SEL 38U #define SC_C_OFS_SEL 39U #define SC_C_OFS_AUDIO 40U #define SC_C_OFS_PERIPH 41U #define SC_C_OFS_IRQ 42U #define SC_C_RST0 43U #define SC_C_RST1 44U #define SC_C_SEL0 45U #define SC_C_LAST 46U #define SC_P_ALL ((sc_pad_t) UINT16_MAX) /* All pads */ /* Types */ /*! * This type is used to store a boolean */ typedef uint8_t sc_bool_t; /*! * This type is used to store a system (full-size) address. */ typedef uint64_t sc_faddr_t; /*! * This type is used to indicate error response for most functions. */ typedef uint8_t sc_err_t; /*! * This type is used to indicate a resource. Resources include peripherals * and bus masters (but not memory regions). Note items from list should * never be changed or removed (only added to at the end of the list). */ typedef uint16_t sc_rsrc_t; /*! * This type is used to indicate a control. */ typedef uint8_t sc_ctrl_t; /*! * This type is used to indicate a pad. Valid values are SoC specific. * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. */ typedef uint16_t sc_pad_t; /* Extra documentation of standard types */ #ifdef DOXYGEN /*! * Type used to declare an 8-bit integer. */ typedef __INT8_TYPE__ int8_t; /*! * Type used to declare a 16-bit integer. */ typedef __INT16_TYPE__ int16_t; /*! * Type used to declare a 32-bit integer. */ typedef __INT32_TYPE__ int32_t; /*! * Type used to declare a 64-bit integer. */ typedef __INT64_TYPE__ int64_t; /*! * Type used to declare an 8-bit unsigned integer. */ typedef __UINT8_TYPE__ uint8_t; /*! * Type used to declare a 16-bit unsigned integer. */ typedef __UINT16_TYPE__ uint16_t; /*! * Type used to declare a 32-bit unsigned integer. */ typedef __UINT32_TYPE__ uint32_t; /*! * Type used to declare a 64-bit unsigned integer. */ typedef __UINT64_TYPE__ uint64_t; #endif #endif /* SCI_TYPES_H */ trusted-firmware-a-2.2/plat/imx/common/include/sci/svc/000077500000000000000000000000001355360272700231325ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/include/sci/svc/misc/000077500000000000000000000000001355360272700240655ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/include/sci/svc/misc/sci_misc_api.h000066400000000000000000000367231355360272700266730ustar00rootroot00000000000000/* * Copyright (C) 2016 Freescale Semiconductor, Inc. * Copyright 2017-2019 NXP * * SPDX-License-Identifier: BSD-3-Clause */ /*! * Header file containing the public API for the System Controller (SC) * Miscellaneous (MISC) function. * * @addtogroup MISC_SVC (SVC) Miscellaneous Service * * Module for the Miscellaneous (MISC) service. * * @{ */ #ifndef SC_MISC_API_H #define SC_MISC_API_H /* Includes */ #include #include /* Defines */ /*! * @name Defines for type widths */ /*@{*/ #define SC_MISC_DMA_GRP_W 5U /* Width of sc_misc_dma_group_t */ /*@}*/ /*! Max DMA channel priority group */ #define SC_MISC_DMA_GRP_MAX 31U /*! * @name Defines for sc_misc_boot_status_t */ /*@{*/ #define SC_MISC_BOOT_STATUS_SUCCESS 0U /* Success */ #define SC_MISC_BOOT_STATUS_SECURITY 1U /* Security violation */ /*@}*/ /*! * @name Defines for sc_misc_seco_auth_cmd_t */ /*@{*/ #define SC_MISC_SECO_AUTH_SECO_FW 0U /* SECO Firmware */ #define SC_MISC_SECO_AUTH_HDMI_TX_FW 1U /* HDMI TX Firmware */ #define SC_MISC_SECO_AUTH_HDMI_RX_FW 2U /* HDMI RX Firmware */ /*@}*/ /*! * @name Defines for sc_misc_temp_t */ /*@{*/ #define SC_MISC_TEMP 0U /* Temp sensor */ #define SC_MISC_TEMP_HIGH 1U /* Temp high alarm */ #define SC_MISC_TEMP_LOW 2U /* Temp low alarm */ /*@}*/ /*! * @name Defines for sc_misc_seco_auth_cmd_t */ /*@{*/ #define SC_MISC_AUTH_CONTAINER 0U /* Authenticate container */ #define SC_MISC_VERIFY_IMAGE 1U /* Verify image */ #define SC_MISC_REL_CONTAINER 2U /* Release container */ /*@}*/ /* Types */ /*! * This type is used to store a DMA channel priority group. */ typedef uint8_t sc_misc_dma_group_t; /*! * This type is used report boot status. */ typedef uint8_t sc_misc_boot_status_t; /*! * This type is used to issue SECO authenticate commands. */ typedef uint8_t sc_misc_seco_auth_cmd_t; /*! * This type is used report boot status. */ typedef uint8_t sc_misc_temp_t; /* Functions */ /*! * @name Control Functions * @{ */ /*! * This function sets a miscellaneous control value. * * @param[in] ipc IPC handle * @param[in] resource resource the control is associated with * @param[in] ctrl control to change * @param[in] val value to apply to the control * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the resource owner or parent * of the owner * * Refer to the [Control List](@ref CONTROLS) for valid control values. */ sc_err_t sc_misc_set_control(sc_ipc_t ipc, sc_rsrc_t resource, sc_ctrl_t ctrl, uint32_t val); /*! * This function gets a miscellaneous control value. * * @param[in] ipc IPC handle * @param[in] resource resource the control is associated with * @param[in] ctrl control to get * @param[out] val pointer to return the control value * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the resource owner or parent * of the owner * * Refer to the [Control List](@ref CONTROLS) for valid control values. */ sc_err_t sc_misc_get_control(sc_ipc_t ipc, sc_rsrc_t resource, sc_ctrl_t ctrl, uint32_t *val); /* @} */ /*! * @name DMA Functions * @{ */ /*! * This function configures the max DMA channel priority group for a * partition. * * @param[in] ipc IPC handle * @param[in] pt handle of partition to assign \a max * @param[in] max max priority group (0-31) * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the parent * of the affected partition * * Valid \a max range is 0-31 with 0 being the lowest and 31 the highest. * Default is the max priority group for the parent partition of \a pt. */ sc_err_t sc_misc_set_max_dma_group(sc_ipc_t ipc, sc_rm_pt_t pt, sc_misc_dma_group_t max); /*! * This function configures the priority group for a DMA channel. * * @param[in] ipc IPC handle * @param[in] resource DMA channel resource * @param[in] group priority group (0-31) * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the owner or parent * of the owner of the DMA channel * * Valid \a group range is 0-31 with 0 being the lowest and 31 the highest. * The max value of \a group is limited by the partition max set using * sc_misc_set_max_dma_group(). */ sc_err_t sc_misc_set_dma_group(sc_ipc_t ipc, sc_rsrc_t resource, sc_misc_dma_group_t group); /* @} */ /*! * @name Security Functions * @{ */ /*! * This function loads a SECO image. * * @param[in] ipc IPC handle * @param[in] addr_src address of image source * @param[in] addr_dst address of image destination * @param[in] len length of image to load * @param[in] fw SC_TRUE = firmware load * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors codes: * - SC_ERR_PARM if word fuse index param out of range or invalid * - SC_ERR_UNAVAILABLE if SECO not available * * This is used to load images via the SECO. Examples include SECO * Firmware and IVT/CSF data used for authentication. These are usually * loaded into SECO TCM. \a addr_src is in secure memory. * * See the Security Reference Manual (SRM) for more info. */ sc_err_t sc_misc_seco_image_load(sc_ipc_t ipc, sc_faddr_t addr_src, sc_faddr_t addr_dst, uint32_t len, sc_bool_t fw); /*! * This function is used to authenticate a SECO image or command. * * @param[in] ipc IPC handle * @param[in] cmd authenticate command * @param[in] addr address of/or metadata * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors codes: * - SC_ERR_PARM if word fuse index param out of range or invalid * - SC_ERR_UNAVAILABLE if SECO not available * * This is used to authenticate a SECO image or issue a security * command. \a addr often points to an container. It is also * just data (or even unused) for some commands. * * See the Security Reference Manual (SRM) for more info. */ sc_err_t sc_misc_seco_authenticate(sc_ipc_t ipc, sc_misc_seco_auth_cmd_t cmd, sc_faddr_t addr); /*! * This function securely writes a group of fuse words. * * @param[in] ipc IPC handle * @param[in] addr address of message block * * @return Returns and error code (SC_ERR_NONE = success). * * Return errors codes: * - SC_ERR_UNAVAILABLE if SECO not available * * Note \a addr must be a pointer to a signed message block. * * See the Security Reference Manual (SRM) for more info. */ sc_err_t sc_misc_seco_fuse_write(sc_ipc_t ipc, sc_faddr_t addr); /*! * This function securely enables debug. * * @param[in] ipc IPC handle * @param[in] addr address of message block * * @return Returns and error code (SC_ERR_NONE = success). * * Return errors codes: * - SC_ERR_UNAVAILABLE if SECO not available * * Note \a addr must be a pointer to a signed message block. * * See the Security Reference Manual (SRM) for more info. */ sc_err_t sc_misc_seco_enable_debug(sc_ipc_t ipc, sc_faddr_t addr); /*! * This function updates the lifecycle of the device. * * @param[in] ipc IPC handle * @param[in] lifecycle new lifecycle * * @return Returns and error code (SC_ERR_NONE = success). * * Return errors codes: * - SC_ERR_UNAVAILABLE if SECO not available * * This message is used for going from Open to NXP Closed to OEM Closed. * * See the Security Reference Manual (SRM) for more info. */ sc_err_t sc_misc_seco_forward_lifecycle(sc_ipc_t ipc, uint32_t lifecycle); /*! * This function updates the lifecycle to one of the return lifecycles. * * @param[in] ipc IPC handle * @param[in] addr address of message block * * @return Returns and error code (SC_ERR_NONE = success). * * Return errors codes: * - SC_ERR_UNAVAILABLE if SECO not available * * Note \a addr must be a pointer to a signed message block. * * To switch back to NXP states (Full Field Return), message must be signed * by NXP SRK. For OEM States (Partial Field Return), must be signed by OEM * SRK. * * See the Security Reference Manual (SRM) for more info. */ sc_err_t sc_misc_seco_return_lifecycle(sc_ipc_t ipc, sc_faddr_t addr); /*! * This function is used to return the SECO FW build info. * * @param[in] ipc IPC handle * @param[out] version pointer to return build number * @param[out] commit pointer to return commit ID (git SHA-1) */ void sc_misc_seco_build_info(sc_ipc_t ipc, uint32_t *version, uint32_t *commit); /*! * This function is used to return SECO chip info. * * @param[in] ipc IPC handle * @param[out] lc pointer to return lifecycle * @param[out] monotonic pointer to return monotonic counter * @param[out] uid_l pointer to return UID (lower 32 bits) * @param[out] uid_h pointer to return UID (upper 32 bits) */ sc_err_t sc_misc_seco_chip_info(sc_ipc_t ipc, uint16_t *lc, uint16_t *monotonic, uint32_t *uid_l, uint32_t *uid_h); /* @} */ /*! * @name Debug Functions * @{ */ /*! * This function is used output a debug character from the SCU UART. * * @param[in] ipc IPC handle * @param[in] ch character to output */ void sc_misc_debug_out(sc_ipc_t ipc, uint8_t ch); /*! * This function starts/stops emulation waveform capture. * * @param[in] ipc IPC handle * @param[in] enable flag to enable/disable capture * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_UNAVAILABLE if not running on emulation */ sc_err_t sc_misc_waveform_capture(sc_ipc_t ipc, sc_bool_t enable); /*! * This function is used to return the SCFW build info. * * @param[in] ipc IPC handle * @param[out] build pointer to return build number * @param[out] commit pointer to return commit ID (git SHA-1) */ void sc_misc_build_info(sc_ipc_t ipc, uint32_t *build, uint32_t *commit); /*! * This function is used to return the device's unique ID. * * @param[in] ipc IPC handle * @param[out] id_l pointer to return lower 32-bit of ID [31:0] * @param[out] id_h pointer to return upper 32-bits of ID [63:32] */ void sc_misc_unique_id(sc_ipc_t ipc, uint32_t *id_l, uint32_t *id_h); /* @} */ /*! * @name Other Functions * @{ */ /*! * This function configures the ARI match value for PCIe/SATA resources. * * @param[in] ipc IPC handle * @param[in] resource match resource * @param[in] resource_mst PCIe/SATA master to match * @param[in] ari ARI to match * @param[in] enable enable match or not * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the owner or parent * of the owner of the resource and translation * * For PCIe, the ARI is the 16-bit value that includes the bus number, * device number, and function number. For SATA, this value includes the * FISType and PM_Port. */ sc_err_t sc_misc_set_ari(sc_ipc_t ipc, sc_rsrc_t resource, sc_rsrc_t resource_mst, uint16_t ari, sc_bool_t enable); /*! * This function reports boot status. * * @param[in] ipc IPC handle * @param[in] status boot status * * This is used by SW partitions to report status of boot. This is * normally used to report a boot failure. */ void sc_misc_boot_status(sc_ipc_t ipc, sc_misc_boot_status_t status); /*! * This function tells the SCFW that a CPU is done booting. * * @param[in] ipc IPC handle * @param[in] cpu CPU that is done booting * * This is called by early booting CPUs to report they are done with * initialization. After starting early CPUs, the SCFW halts the * booting process until they are done. During this time, early * CPUs can call the SCFW with lower latency as the SCFW is idle. * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the CPU owner */ sc_err_t sc_misc_boot_done(sc_ipc_t ipc, sc_rsrc_t cpu); /*! * This function reads a given fuse word index. * * @param[in] ipc IPC handle * @param[in] word fuse word index * @param[out] val fuse read value * * @return Returns and error code (SC_ERR_NONE = success). * * Return errors codes: * - SC_ERR_PARM if word fuse index param out of range or invalid * - SC_ERR_NOACCESS if read operation failed * - SC_ERR_LOCKED if read operation is locked */ sc_err_t sc_misc_otp_fuse_read(sc_ipc_t ipc, uint32_t word, uint32_t *val); /*! * This function writes a given fuse word index. * * @param[in] ipc IPC handle * @param[in] word fuse word index * @param[in] val fuse write value * * @return Returns and error code (SC_ERR_NONE = success). * * Return errors codes: * - SC_ERR_PARM if word fuse index param out of range or invalid * - SC_ERR_NOACCESS if write operation failed * - SC_ERR_LOCKED if write operation is locked */ sc_err_t sc_misc_otp_fuse_write(sc_ipc_t ipc, uint32_t word, uint32_t val); /*! * This function sets a temp sensor alarm. * * @param[in] ipc IPC handle * @param[in] resource resource with sensor * @param[in] temp alarm to set * @param[in] celsius whole part of temp to set * @param[in] tenths fractional part of temp to set * * @return Returns and error code (SC_ERR_NONE = success). * * This function will enable the alarm interrupt if the temp requested is * not the min/max temp. This enable automatically clears when the alarm * occurs and this function has to be called again to re-enable. * * Return errors codes: * - SC_ERR_PARM if parameters invalid */ sc_err_t sc_misc_set_temp(sc_ipc_t ipc, sc_rsrc_t resource, sc_misc_temp_t temp, int16_t celsius, int8_t tenths); /*! * This function gets a temp sensor value. * * @param[in] ipc IPC handle * @param[in] resource resource with sensor * @param[in] temp value to get (sensor or alarm) * @param[out] celsius whole part of temp to get * @param[out] tenths fractional part of temp to get * * @return Returns and error code (SC_ERR_NONE = success). * * Return errors codes: * - SC_ERR_PARM if parameters invalid */ sc_err_t sc_misc_get_temp(sc_ipc_t ipc, sc_rsrc_t resource, sc_misc_temp_t temp, int16_t *celsius, int8_t *tenths); /*! * This function returns the boot device. * * @param[in] ipc IPC handle * @param[out] dev pointer to return boot device */ void sc_misc_get_boot_dev(sc_ipc_t ipc, sc_rsrc_t *dev); /*! * This function returns the current status of the ON/OFF button. * * @param[in] ipc IPC handle * @param[out] status pointer to return button status */ void sc_misc_get_button_status(sc_ipc_t ipc, sc_bool_t *status); /* @} */ #endif /* SC_MISC_API_H */ /**@}*/ trusted-firmware-a-2.2/plat/imx/common/include/sci/svc/pad/000077500000000000000000000000001355360272700236765ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/include/sci/svc/pad/sci_pad_api.h000066400000000000000000000457541355360272700263210ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /*! * Header file containing the public API for the System Controller (SC) * Pad Control (PAD) function. * * @addtogroup PAD_SVC (SVC) Pad Service * * Module for the Pad Control (PAD) service. * * @details * * Pad configuration is managed by SC firmware. The pad configuration * features supported by the SC firmware include: * * - Configuring the mux, input/output connection, and low-power isolation mode. * - Configuring the technology-specific pad setting such as drive strength, * pullup/pulldown, etc. * - Configuring compensation for pad groups with dual voltage capability. * * Pad functions fall into one of three categories. Generic functions are * common to all SoCs and all process technologies. SoC functions are raw * low-level functions. Technology-specific functions are specific to the * process technology. * * The list of pads is SoC specific. Refer to the SoC [Pad List](@ref PADS) * for valid pad values. Note that all pads exist on a die but may or * may not be brought out by the specific package. Mapping of pads to * package pins/balls is documented in the associated Data Sheet. Some pads * may not be brought out because the part (die+package) is defeatured and * some pads may connect to the substrate in the package. * * Some pads (SC_P_COMP_*) that can be specified are not individual pads * but are in fact pad groups. These groups have additional configuration * that can be done using the sc_pad_set_gp_28fdsoi_comp() function. More * info on these can be found in the associated Reference Manual. * * Pads are managed as a resource by the Resource Manager (RM). They have * assigned owners and only the owners can configure the pads. Some of the * pads are reserved for use by the SCFW itself and this can be overriden * with the implementation of board_config_sc(). Additionally, pads may * be assigned to various other partitions via the implementation of * board_system_config(). * * Note muxing two input pads to the same IP functional signal will * result in undefined behavior. * @{ */ #ifndef SCI_PAD_API_H #define SCI_PAD_API_H /* Includes */ #include #include /* Defines */ /*! * @name Defines for type widths */ /*@{*/ #define SC_PAD_MUX_W 3 /* Width of mux parameter */ /*@}*/ /*! * @name Defines for sc_pad_config_t */ /*@{*/ #define SC_PAD_CONFIG_NORMAL 0U /* Normal */ #define SC_PAD_CONFIG_OD 1U /* Open Drain */ #define SC_PAD_CONFIG_OD_IN 2U /* Open Drain and input */ #define SC_PAD_CONFIG_OUT_IN 3U /* Output and input */ /*@}*/ /*! * @name Defines for sc_pad_iso_t */ /*@{*/ #define SC_PAD_ISO_OFF 0U /* ISO latch is transparent */ #define SC_PAD_ISO_EARLY 1U /* Follow EARLY_ISO */ #define SC_PAD_ISO_LATE 2U /* Follow LATE_ISO */ #define SC_PAD_ISO_ON 3U /* ISO latched data is held */ /*@}*/ /*! * @name Defines for sc_pad_28fdsoi_dse_t */ /*@{*/ #define SC_PAD_28FDSOI_DSE_18V_1MA 0U /* Drive strength of 1mA for 1.8v */ #define SC_PAD_28FDSOI_DSE_18V_2MA 1U /* Drive strength of 2mA for 1.8v */ #define SC_PAD_28FDSOI_DSE_18V_4MA 2U /* Drive strength of 4mA for 1.8v */ #define SC_PAD_28FDSOI_DSE_18V_6MA 3U /* Drive strength of 6mA for 1.8v */ #define SC_PAD_28FDSOI_DSE_18V_8MA 4U /* Drive strength of 8mA for 1.8v */ #define SC_PAD_28FDSOI_DSE_18V_10MA 5U /* Drive strength of 10mA for 1.8v */ #define SC_PAD_28FDSOI_DSE_18V_12MA 6U /* Drive strength of 12mA for 1.8v */ #define SC_PAD_28FDSOI_DSE_18V_HS 7U /* High-speed drive strength for 1.8v */ #define SC_PAD_28FDSOI_DSE_33V_2MA 0U /* Drive strength of 2mA for 3.3v */ #define SC_PAD_28FDSOI_DSE_33V_4MA 1U /* Drive strength of 4mA for 3.3v */ #define SC_PAD_28FDSOI_DSE_33V_8MA 2U /* Drive strength of 8mA for 3.3v */ #define SC_PAD_28FDSOI_DSE_33V_12MA 3U /* Drive strength of 12mA for 3.3v */ #define SC_PAD_28FDSOI_DSE_DV_HIGH 0U /* High drive strength for dual volt */ #define SC_PAD_28FDSOI_DSE_DV_LOW 1U /* Low drive strength for dual volt */ /*@}*/ /*! * @name Defines for sc_pad_28fdsoi_ps_t */ /*@{*/ #define SC_PAD_28FDSOI_PS_KEEPER 0U /* Bus-keeper (only valid for 1.8v) */ #define SC_PAD_28FDSOI_PS_PU 1U /* Pull-up */ #define SC_PAD_28FDSOI_PS_PD 2U /* Pull-down */ #define SC_PAD_28FDSOI_PS_NONE 3U /* No pull (disabled) */ /*@}*/ /*! * @name Defines for sc_pad_28fdsoi_pus_t */ /*@{*/ #define SC_PAD_28FDSOI_PUS_30K_PD 0U /* 30K pull-down */ #define SC_PAD_28FDSOI_PUS_100K_PU 1U /* 100K pull-up */ #define SC_PAD_28FDSOI_PUS_3K_PU 2U /* 3K pull-up */ #define SC_PAD_28FDSOI_PUS_30K_PU 3U /* 30K pull-up */ /*@}*/ /*! * @name Defines for sc_pad_wakeup_t */ /*@{*/ #define SC_PAD_WAKEUP_OFF 0U /* Off */ #define SC_PAD_WAKEUP_CLEAR 1U /* Clears pending flag */ #define SC_PAD_WAKEUP_LOW_LVL 4U /* Low level */ #define SC_PAD_WAKEUP_FALL_EDGE 5U /* Falling edge */ #define SC_PAD_WAKEUP_RISE_EDGE 6U /* Rising edge */ #define SC_PAD_WAKEUP_HIGH_LVL 7U /* High-level */ /*@}*/ /* Types */ /*! * This type is used to declare a pad config. It determines how the * output data is driven, pull-up is controlled, and input signal is * connected. Normal and OD are typical and only connect the input * when the output is not driven. The IN options are less common and * force an input connection even when driving the output. */ typedef uint8_t sc_pad_config_t; /*! * This type is used to declare a pad low-power isolation config. * ISO_LATE is the most common setting. ISO_EARLY is only used when * an output pad is directly determined by another input pad. The * other two are only used when SW wants to directly contol isolation. */ typedef uint8_t sc_pad_iso_t; /*! * This type is used to declare a drive strength. Note it is specific * to 28FDSOI. Also note that valid values depend on the pad type. */ typedef uint8_t sc_pad_28fdsoi_dse_t; /*! * This type is used to declare a pull select. Note it is specific * to 28FDSOI. */ typedef uint8_t sc_pad_28fdsoi_ps_t; /*! * This type is used to declare a pull-up select. Note it is specific * to 28FDSOI HSIC pads. */ typedef uint8_t sc_pad_28fdsoi_pus_t; /*! * This type is used to declare a wakeup mode of a pad. */ typedef uint8_t sc_pad_wakeup_t; /* Functions */ /*! * @name Generic Functions * @{ */ /*! * This function configures the mux settings for a pad. This includes * the signal mux, pad config, and low-power isolation mode. * * @param[in] ipc IPC handle * @param[in] pad pad to configure * @param[in] mux mux setting * @param[in] config pad config * @param[in] iso low-power isolation mode * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner * * Note muxing two input pads to the same IP functional signal will * result in undefined behavior. * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. */ sc_err_t sc_pad_set_mux(sc_ipc_t ipc, sc_pad_t pad, uint8_t mux, sc_pad_config_t config, sc_pad_iso_t iso); /*! * This function gets the mux settings for a pad. This includes * the signal mux, pad config, and low-power isolation mode. * * @param[in] ipc IPC handle * @param[in] pad pad to query * @param[out] mux pointer to return mux setting * @param[out] config pointer to return pad config * @param[out] iso pointer to return low-power isolation mode * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. */ sc_err_t sc_pad_get_mux(sc_ipc_t ipc, sc_pad_t pad, uint8_t *mux, sc_pad_config_t *config, sc_pad_iso_t *iso); /*! * This function configures the general purpose pad control. This * is technology dependent and includes things like drive strength, * slew rate, pull up/down, etc. Refer to the SoC Reference Manual * for bit field details. * * @param[in] ipc IPC handle * @param[in] pad pad to configure * @param[in] ctrl control value to set * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. */ sc_err_t sc_pad_set_gp(sc_ipc_t ipc, sc_pad_t pad, uint32_t ctrl); /*! * This function gets the general purpose pad control. This * is technology dependent and includes things like drive strength, * slew rate, pull up/down, etc. Refer to the SoC Reference Manual * for bit field details. * * @param[in] ipc IPC handle * @param[in] pad pad to query * @param[out] ctrl pointer to return control value * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. */ sc_err_t sc_pad_get_gp(sc_ipc_t ipc, sc_pad_t pad, uint32_t *ctrl); /*! * This function configures the wakeup mode of the pad. * * @param[in] ipc IPC handle * @param[in] pad pad to configure * @param[in] wakeup wakeup to set * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. */ sc_err_t sc_pad_set_wakeup(sc_ipc_t ipc, sc_pad_t pad, sc_pad_wakeup_t wakeup); /*! * This function gets the wakeup mode of a pad. * * @param[in] ipc IPC handle * @param[in] pad pad to query * @param[out] wakeup pointer to return wakeup * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. */ sc_err_t sc_pad_get_wakeup(sc_ipc_t ipc, sc_pad_t pad, sc_pad_wakeup_t *wakeup); /*! * This function configures a pad. * * @param[in] ipc IPC handle * @param[in] pad pad to configure * @param[in] mux mux setting * @param[in] config pad config * @param[in] iso low-power isolation mode * @param[in] ctrl control value * @param[in] wakeup wakeup to set * * @see sc_pad_set_mux(). * @see sc_pad_set_gp(). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner * * @return Returns an error code (SC_ERR_NONE = success). * * Note muxing two input pads to the same IP functional signal will * result in undefined behavior. * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. */ sc_err_t sc_pad_set_all(sc_ipc_t ipc, sc_pad_t pad, uint8_t mux, sc_pad_config_t config, sc_pad_iso_t iso, uint32_t ctrl, sc_pad_wakeup_t wakeup); /*! * This function gets a pad's config. * * @param[in] ipc IPC handle * @param[in] pad pad to query * @param[out] mux pointer to return mux setting * @param[out] config pointer to return pad config * @param[out] iso pointer to return low-power isolation mode * @param[out] ctrl pointer to return control value * @param[out] wakeup pointer to return wakeup to set * * @see sc_pad_set_mux(). * @see sc_pad_set_gp(). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner * * @return Returns an error code (SC_ERR_NONE = success). * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. */ sc_err_t sc_pad_get_all(sc_ipc_t ipc, sc_pad_t pad, uint8_t *mux, sc_pad_config_t *config, sc_pad_iso_t *iso, uint32_t *ctrl, sc_pad_wakeup_t *wakeup); /* @} */ /*! * @name SoC Specific Functions * @{ */ /*! * This function configures the settings for a pad. This setting is SoC * specific. * * @param[in] ipc IPC handle * @param[in] pad pad to configure * @param[in] val value to set * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. */ sc_err_t sc_pad_set(sc_ipc_t ipc, sc_pad_t pad, uint32_t val); /*! * This function gets the settings for a pad. This setting is SoC * specific. * * @param[in] ipc IPC handle * @param[in] pad pad to query * @param[out] val pointer to return setting * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. */ sc_err_t sc_pad_get(sc_ipc_t ipc, sc_pad_t pad, uint32_t *val); /* @} */ /*! * @name Technology Specific Functions * @{ */ /*! * This function configures the pad control specific to 28FDSOI. * * @param[in] ipc IPC handle * @param[in] pad pad to configure * @param[in] dse drive strength * @param[in] ps pull select * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner, * - SC_ERR_UNAVAILABLE if process not applicable * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. */ sc_err_t sc_pad_set_gp_28fdsoi(sc_ipc_t ipc, sc_pad_t pad, sc_pad_28fdsoi_dse_t dse, sc_pad_28fdsoi_ps_t ps); /*! * This function gets the pad control specific to 28FDSOI. * * @param[in] ipc IPC handle * @param[in] pad pad to query * @param[out] dse pointer to return drive strength * @param[out] ps pointer to return pull select * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner, * - SC_ERR_UNAVAILABLE if process not applicable * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. */ sc_err_t sc_pad_get_gp_28fdsoi(sc_ipc_t ipc, sc_pad_t pad, sc_pad_28fdsoi_dse_t *dse, sc_pad_28fdsoi_ps_t *ps); /*! * This function configures the pad control specific to 28FDSOI. * * @param[in] ipc IPC handle * @param[in] pad pad to configure * @param[in] dse drive strength * @param[in] hys hysteresis * @param[in] pus pull-up select * @param[in] pke pull keeper enable * @param[in] pue pull-up enable * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner, * - SC_ERR_UNAVAILABLE if process not applicable * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. */ sc_err_t sc_pad_set_gp_28fdsoi_hsic(sc_ipc_t ipc, sc_pad_t pad, sc_pad_28fdsoi_dse_t dse, sc_bool_t hys, sc_pad_28fdsoi_pus_t pus, sc_bool_t pke, sc_bool_t pue); /*! * This function gets the pad control specific to 28FDSOI. * * @param[in] ipc IPC handle * @param[in] pad pad to query * @param[out] dse pointer to return drive strength * @param[out] hys pointer to return hysteresis * @param[out] pus pointer to return pull-up select * @param[out] pke pointer to return pull keeper enable * @param[out] pue pointer to return pull-up enable * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner, * - SC_ERR_UNAVAILABLE if process not applicable * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. */ sc_err_t sc_pad_get_gp_28fdsoi_hsic(sc_ipc_t ipc, sc_pad_t pad, sc_pad_28fdsoi_dse_t *dse, sc_bool_t *hys, sc_pad_28fdsoi_pus_t *pus, sc_bool_t *pke, sc_bool_t *pue); /*! * This function configures the compensation control specific to 28FDSOI. * * @param[in] ipc IPC handle * @param[in] pad pad to configure * @param[in] compen compensation/freeze mode * @param[in] fastfrz fast freeze * @param[in] rasrcp compensation code for PMOS * @param[in] rasrcn compensation code for NMOS * @param[in] nasrc_sel NASRC read select * @param[in] psw_ovr 2.5v override * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner, * - SC_ERR_UNAVAILABLE if process not applicable * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. * * Note \a psw_ovr is only applicable to pads supporting 2.5 volt * operation (e.g. some Ethernet pads). */ sc_err_t sc_pad_set_gp_28fdsoi_comp(sc_ipc_t ipc, sc_pad_t pad, uint8_t compen, sc_bool_t fastfrz, uint8_t rasrcp, uint8_t rasrcn, sc_bool_t nasrc_sel, sc_bool_t psw_ovr); /*! * This function gets the compensation control specific to 28FDSOI. * * @param[in] ipc IPC handle * @param[in] pad pad to query * @param[out] compen pointer to return compensation/freeze mode * @param[out] fastfrz pointer to return fast freeze * @param[out] rasrcp pointer to return compensation code for PMOS * @param[out] rasrcn pointer to return compensation code for NMOS * @param[out] nasrc_sel pointer to return NASRC read select * @param[out] compok pointer to return compensation status * @param[out] nasrc pointer to return NASRCP/NASRCN * @param[out] psw_ovr pointer to return the 2.5v override * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner, * - SC_ERR_UNAVAILABLE if process not applicable * * Refer to the SoC [Pad List](@ref PADS) for valid pad values. */ sc_err_t sc_pad_get_gp_28fdsoi_comp(sc_ipc_t ipc, sc_pad_t pad, uint8_t *compen, sc_bool_t *fastfrz, uint8_t *rasrcp, uint8_t *rasrcn, sc_bool_t *nasrc_sel, sc_bool_t *compok, uint8_t *nasrc, sc_bool_t *psw_ovr); /* @} */ #endif /* SCI_PAD_API_H */ /**@}*/ trusted-firmware-a-2.2/plat/imx/common/include/sci/svc/pm/000077500000000000000000000000001355360272700235465ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/include/sci/svc/pm/sci_pm_api.h000066400000000000000000000550741355360272700260350ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /*! * Header file containing the public API for the System Controller (SC) * Power Management (PM) function. This includes functions for power state * control, clock control, reset control, and wake-up event control. * * @addtogroup PM_SVC (SVC) Power Management Service * * Module for the Power Management (PM) service. * * @{ */ #ifndef SCI_PM_API_H #define SCI_PM_API_H /* Includes */ #include #include /* Defines */ /*! * @name Defines for type widths */ /*@{*/ #define SC_PM_POWER_MODE_W 2 /* Width of sc_pm_power_mode_t */ #define SC_PM_CLOCK_MODE_W 3 /* Width of sc_pm_clock_mode_t */ #define SC_PM_RESET_TYPE_W 2 /* Width of sc_pm_reset_type_t */ #define SC_PM_RESET_REASON_W 3 /* Width of sc_pm_reset_reason_t */ /*@}*/ /*! * @name Defines for clock indexes (sc_pm_clk_t) */ /*@{*/ /*@}*/ /*! * @name Defines for ALL parameters */ /*@{*/ #define SC_PM_CLK_ALL UINT8_MAX /* All clocks */ /*@}*/ /*! * @name Defines for sc_pm_power_mode_t */ /*@{*/ #define SC_PM_PW_MODE_OFF 0U /* Power off */ #define SC_PM_PW_MODE_STBY 1U /* Power in standby */ #define SC_PM_PW_MODE_LP 2U /* Power in low-power */ #define SC_PM_PW_MODE_ON 3U /* Power on */ /*@}*/ /*! * @name Defines for sc_pm_clk_t */ /*@{*/ #define SC_PM_CLK_SLV_BUS 0U /* Slave bus clock */ #define SC_PM_CLK_MST_BUS 1U /* Master bus clock */ #define SC_PM_CLK_PER 2U /* Peripheral clock */ #define SC_PM_CLK_PHY 3U /* Phy clock */ #define SC_PM_CLK_MISC 4U /* Misc clock */ #define SC_PM_CLK_MISC0 0U /* Misc 0 clock */ #define SC_PM_CLK_MISC1 1U /* Misc 1 clock */ #define SC_PM_CLK_MISC2 2U /* Misc 2 clock */ #define SC_PM_CLK_MISC3 3U /* Misc 3 clock */ #define SC_PM_CLK_MISC4 4U /* Misc 4 clock */ #define SC_PM_CLK_CPU 2U /* CPU clock */ #define SC_PM_CLK_PLL 4U /* PLL */ #define SC_PM_CLK_BYPASS 4U /* Bypass clock */ /*@}*/ /*! * @name Defines for sc_pm_clk_mode_t */ /*@{*/ #define SC_PM_CLK_MODE_ROM_INIT 0U /* Clock is initialized by ROM. */ #define SC_PM_CLK_MODE_OFF 1U /* Clock is disabled */ #define SC_PM_CLK_MODE_ON 2U /* Clock is enabled. */ #define SC_PM_CLK_MODE_AUTOGATE_SW 3U /* Clock is in SW autogate mode */ #define SC_PM_CLK_MODE_AUTOGATE_HW 4U /* Clock is in HW autogate mode */ #define SC_PM_CLK_MODE_AUTOGATE_SW_HW 5U /* Clock is in SW-HW autogate mode */ /*@}*/ /*! * @name Defines for sc_pm_clk_parent_t */ /*@{*/ #define SC_PM_PARENT_XTAL 0U /* Parent is XTAL. */ #define SC_PM_PARENT_PLL0 1U /* Parent is PLL0 */ #define SC_PM_PARENT_PLL1 2U /* Parent is PLL1 or PLL0/2 */ #define SC_PM_PARENT_PLL2 3U /* Parent in PLL2 or PLL0/4 */ #define SC_PM_PARENT_BYPS 4U /* Parent is a bypass clock. */ /*@}*/ /*! * @name Defines for sc_pm_reset_type_t */ /*@{*/ #define SC_PM_RESET_TYPE_COLD 0U /* Cold reset */ #define SC_PM_RESET_TYPE_WARM 1U /* Warm reset */ #define SC_PM_RESET_TYPE_BOARD 2U /* Board reset */ /*@}*/ /*! * @name Defines for sc_pm_reset_cause_t */ /*@{*/ #define SC_PM_RESET_CAUSE_TEMP 0U /* Reset due to temp panic alarm */ #define SC_PM_RESET_CAUSE_FAULT 1U /* Reset due to fault exception */ #define SC_PM_RESET_CAUSE_IRQ 2U /* Reset due to SCU reset IRQ */ #define SC_PM_RESET_CAUSE_WDOG 3U /* Reset due to SW WDOG */ #define SC_PM_RESET_CAUSE_API 4U /* Reset due to pm_reset() or monitor */ /*@}*/ /*! * @name Defines for sc_pm_reset_reason_t */ /*@{*/ #define SC_PM_RESET_REASON_POR 0U /* Power on reset */ #define SC_PM_RESET_REASON_WARM 1U /* Warm reset */ #define SC_PM_RESET_REASON_SW 2U /* Software reset */ #define SC_PM_RESET_REASON_WDOG 3U /* Watchdog reset */ #define SC_PM_RESET_REASON_LOCKUP 4U /* Lockup reset */ #define SC_PM_RESET_REASON_TAMPER 5U /* Tamper reset */ #define SC_PM_RESET_REASON_TEMP 6U /* Temp reset */ #define SC_PM_RESET_REASON_LOW_VOLT 7U /* Low voltage reset */ /*@}*/ /*! * @name Defines for sc_pm_sys_if_t */ /*@{*/ #define SC_PM_SYS_IF_INTERCONNECT 0U /* System interconnect */ #define SC_PM_SYS_IF_MU 1U /* AP -> SCU message units */ #define SC_PM_SYS_IF_OCMEM 2U /* On-chip memory (ROM/OCRAM) */ #define SC_PM_SYS_IF_DDR 3U /* DDR memory */ /*@}*/ /*! * @name Defines for sc_pm_wake_src_t */ /*@{*/ #define SC_PM_WAKE_SRC_NONE 0U /* No wake source, used for self-kill */ #define SC_PM_WAKE_SRC_SCU 1U /* Wakeup from SCU to resume CPU (IRQSTEER & GIC powered down) */ #define SC_PM_WAKE_SRC_IRQSTEER 2U /* Wakeup from IRQSTEER to resume CPU (GIC powered down) */ #define SC_PM_WAKE_SRC_IRQSTEER_GIC 3U /* Wakeup from IRQSTEER+GIC to wake CPU (GIC clock gated) */ #define SC_PM_WAKE_SRC_GIC 4U /* Wakeup from GIC to wake CPU */ /*@}*/ /* Types */ /*! * This type is used to declare a power mode. Note resources only use * SC_PM_PW_MODE_OFF and SC_PM_PW_MODE_ON. The other modes are used only * as system power modes. */ typedef uint8_t sc_pm_power_mode_t; /*! * This type is used to declare a clock. */ typedef uint8_t sc_pm_clk_t; /*! * This type is used to declare a clock mode. */ typedef uint8_t sc_pm_clk_mode_t; /*! * This type is used to declare the clock parent. */ typedef uint8_t sc_pm_clk_parent_t; /*! * This type is used to declare clock rates. */ typedef uint32_t sc_pm_clock_rate_t; /*! * This type is used to declare a desired reset type. */ typedef uint8_t sc_pm_reset_type_t; /*! * This type is used to declare a desired reset type. */ typedef uint8_t sc_pm_reset_cause; /*! * This type is used to declare a reason for a reset. */ typedef uint8_t sc_pm_reset_reason_t; /*! * This type is used to specify a system-level interface to be power managed. */ typedef uint8_t sc_pm_sys_if_t; /*! * This type is used to specify a wake source for CPU resources. */ typedef uint8_t sc_pm_wake_src_t; /* Functions */ /*! * @name Power Functions * @{ */ /*! * This function sets the system power mode. Only the owner of the * SC_R_SYSTEM resource can do this. * * @param[in] ipc IPC handle * @param[in] mode power mode to apply * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid mode, * - SC_ERR_NOACCESS if caller not the owner of SC_R_SYSTEM * * @see sc_pm_set_sys_power_mode(). */ sc_err_t sc_pm_set_sys_power_mode(sc_ipc_t ipc, sc_pm_power_mode_t mode); /*! * This function sets the power mode of a partition. * * @param[in] ipc IPC handle * @param[in] pt handle of partition * @param[in] mode power mode to apply * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid partition or mode, * - SC_ERR_NOACCESS if caller's partition is not the owner or * parent of \a pt * * The power mode of the partitions is a max power any resource will * be set to. Calling this will result in all resources owned * by \a pt to have their power changed to the lower of \a mode or the * individual resource mode set using sc_pm_set_resource_power_mode(). */ sc_err_t sc_pm_set_partition_power_mode(sc_ipc_t ipc, sc_rm_pt_t pt, sc_pm_power_mode_t mode); /*! * This function gets the power mode of a partition. * * @param[in] ipc IPC handle * @param[in] pt handle of partition * @param[out] mode pointer to return power mode * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid partition */ sc_err_t sc_pm_get_sys_power_mode(sc_ipc_t ipc, sc_rm_pt_t pt, sc_pm_power_mode_t *mode); /*! * This function sets the power mode of a resource. * * @param[in] ipc IPC handle * @param[in] resource ID of the resource * @param[in] mode power mode to apply * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid resource or mode, * - SC_ERR_NOACCESS if caller's partition is not the resource owner * or parent of the owner * * This function will record the individual resource power mode * and change it if the requested mode is lower than or equal to the * partition power mode set with sc_pm_set_partition_power_mode(). * In other words, the power mode of the resource will be the minimum * of the resource power mode and the partition power mode. * * Note some resources are still not accessible even when powered up if bus * transactions go through a fabric not powered up. Examples of this are * resources in display and capture subsystems which require the display * controller or the imaging subsytem to be powered up first. * * Not that resources are grouped into power domains by the underlying * hardware. If any resource in the domain is on, the entire power domain * will be on. Other power domains required to access the resource will * also be turned on. Clocks required to access the peripheral will be * turned on. Refer to the SoC RM for more info on power domains and access * infrastructure (bus fabrics, clock domains, etc.). */ sc_err_t sc_pm_set_resource_power_mode(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_power_mode_t mode); /*! * This function gets the power mode of a resource. * * @param[in] ipc IPC handle * @param[in] resource ID of the resource * @param[out] mode pointer to return power mode * * @return Returns an error code (SC_ERR_NONE = success). * * Note only SC_PM_PW_MODE_OFF and SC_PM_PW_MODE_ON are valid. The value * returned does not reflect the power mode of the partition.. */ sc_err_t sc_pm_get_resource_power_mode(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_power_mode_t *mode); /*! * This function requests the low power mode some of the resources * can enter based on their state. This API is only valid for the * following resources : SC_R_A53, SC_R_A53_0, SC_R_A53_1, SC_A53_2, * SC_A53_3, SC_R_A72, SC_R_A72_0, SC_R_A72_1, SC_R_CC1, SC_R_A35, * SC_R_A35_0, SC_R_A35_1, SC_R_A35_2, SC_R_A35_3. * For all other resources it will return SC_ERR_PARAM. * This function will set the low power mode the cores, cluster * and cluster associated resources will enter when all the cores * in a given cluster execute WFI * * @param[in] ipc IPC handle * @param[in] resource ID of the resource * @param[in] mode power mode to apply * * @return Returns an error code (SC_ERR_NONE = success). * */ sc_err_t sc_pm_req_low_power_mode(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_power_mode_t mode); /*! * This function requests low-power mode entry for CPU/cluster * resources. This API is only valid for the following resources: * SC_R_A53, SC_R_A53_x, SC_R_A72, SC_R_A72_x, SC_R_A35, SC_R_A35_x, * SC_R_CCI. For all other resources it will return SC_ERR_PARAM. * For individual core resources, the specified power mode * and wake source will be applied after the core has entered * WFI. For cluster resources, the specified power mode is * applied after all cores in the cluster have entered low-power mode. * For multicluster resources, the specified power mode is applied * after all clusters have reached low-power mode. * * @param[in] ipc IPC handle * @param[in] resource ID of the resource * @param[in] mode power mode to apply * @param[in] wake_src wake source for low-power exit * * @return Returns an error code (SC_ERR_NONE = success). * */ sc_err_t sc_pm_req_cpu_low_power_mode(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_power_mode_t mode, sc_pm_wake_src_t wake_src); /*! * This function is used to set the resume address of a CPU. * * @param[in] ipc IPC handle * @param[in] resource ID of the CPU resource * @param[in] address 64-bit resume address * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid resource or address, * - SC_ERR_NOACCESS if caller's partition is not the parent of the * resource (CPU) owner */ sc_err_t sc_pm_set_cpu_resume_addr(sc_ipc_t ipc, sc_rsrc_t resource, sc_faddr_t address); /*! * This function is used to set parameters for CPU resume from * low-power mode. * * @param[in] ipc IPC handle * @param[in] resource ID of the CPU resource * @param[in] isPrimary set SC_TRUE if primary wake CPU * @param[in] address 64-bit resume address * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid resource or address, * - SC_ERR_NOACCESS if caller's partition is not the parent of the * resource (CPU) owner */ sc_err_t sc_pm_set_cpu_resume(sc_ipc_t ipc, sc_rsrc_t resource, sc_bool_t isPrimary, sc_faddr_t address); /*! * This function requests the power mode configuration for system-level * interfaces including messaging units, interconnect, and memories. This API * is only valid for the following resources : SC_R_A53, SC_R_A72, and * SC_R_M4_x_PID_y. For all other resources, it will return SC_ERR_PARAM. * The requested power mode will be captured and applied to system-level * resources as system conditions allow. * * @param[in] ipc IPC handle * @param[in] resource ID of the resource * @param[in] sys_if system-level interface to be configured * @param[in] hpm high-power mode for the system interface * @param[in] lpm low-power mode for the system interface * * @return Returns an error code (SC_ERR_NONE = success). * */ sc_err_t sc_pm_req_sys_if_power_mode(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_sys_if_t sys_if, sc_pm_power_mode_t hpm, sc_pm_power_mode_t lpm); /* @} */ /*! * @name Clock/PLL Functions * @{ */ /*! * This function sets the rate of a resource's clock/PLL. * * @param[in] ipc IPC handle * @param[in] resource ID of the resource * @param[in] clk clock/PLL to affect * @param[in,out] rate pointer to rate to set, * return actual rate * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid resource or clock/PLL, * - SC_ERR_NOACCESS if caller's partition is not the resource owner * or parent of the owner, * - SC_ERR_UNAVAILABLE if clock/PLL not applicable to this resource, * - SC_ERR_LOCKED if rate locked (usually because shared clock/PLL) * * Refer to the [Clock List](@ref CLOCKS) for valid clock/PLL values. */ sc_err_t sc_pm_set_clock_rate(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_clk_t clk, sc_pm_clock_rate_t *rate); /*! * This function gets the rate of a resource's clock/PLL. * * @param[in] ipc IPC handle * @param[in] resource ID of the resource * @param[in] clk clock/PLL to affect * @param[out] rate pointer to return rate * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid resource or clock/PLL, * - SC_ERR_NOACCESS if caller's partition is not the resource owner * or parent of the owner, * - SC_ERR_UNAVAILABLE if clock/PLL not applicable to this resource * * Refer to the [Clock List](@ref CLOCKS) for valid clock/PLL values. */ sc_err_t sc_pm_get_clock_rate(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_clk_t clk, sc_pm_clock_rate_t *rate); /*! * This function enables/disables a resource's clock. * * @param[in] ipc IPC handle * @param[in] resource ID of the resource * @param[in] clk clock to affect * @param[in] enable enable if SC_TRUE; otherwise disabled * @param[in] autog HW auto clock gating * * If \a resource is SC_R_ALL then all resources owned will be affected. * No error will be returned. * * If \a clk is SC_PM_CLK_ALL, then an error will be returned if any * of the available clocks returns an error. * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid resource or clock, * - SC_ERR_NOACCESS if caller's partition is not the resource owner * or parent of the owner, * - SC_ERR_UNAVAILABLE if clock not applicable to this resource * * Refer to the [Clock List](@ref CLOCKS) for valid clock values. */ sc_err_t sc_pm_clock_enable(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_clk_t clk, sc_bool_t enable, sc_bool_t autog); /*! * This function sets the parent of a resource's clock. * This function should only be called when the clock is disabled. * * @param[in] ipc IPC handle * @param[in] resource ID of the resource * @param[in] clk clock to affect * @param[in] parent New parent of the clock. * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid resource or clock, * - SC_ERR_NOACCESS if caller's partition is not the resource owner * or parent of the owner, * - SC_ERR_UNAVAILABLE if clock not applicable to this resource * - SC_ERR_BUSY if clock is currently enabled. * - SC_ERR_NOPOWER if resource not powered * * Refer to the [Clock List](@ref CLOCKS) for valid clock values. */ sc_err_t sc_pm_set_clock_parent(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_clk_t clk, sc_pm_clk_parent_t parent); /*! * This function gets the parent of a resource's clock. * * @param[in] ipc IPC handle * @param[in] resource ID of the resource * @param[in] clk clock to affect * @param[out] parent pointer to return parent of clock. * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid resource or clock, * - SC_ERR_NOACCESS if caller's partition is not the resource owner * or parent of the owner, * - SC_ERR_UNAVAILABLE if clock not applicable to this resource * * Refer to the [Clock List](@ref CLOCKS) for valid clock values. */ sc_err_t sc_pm_get_clock_parent(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_clk_t clk, sc_pm_clk_parent_t *parent); /* @} */ /*! * @name Reset Functions * @{ */ /*! * This function is used to reset the system. Only the owner of the * SC_R_SYSTEM resource can do this. * * @param[in] ipc IPC handle * @param[in] type reset type * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid type, * - SC_ERR_NOACCESS if caller not the owner of SC_R_SYSTEM * * If this function returns, then the reset did not occur due to an * invalid parameter. */ sc_err_t sc_pm_reset(sc_ipc_t ipc, sc_pm_reset_type_t type); /*! * This function gets a caller's reset reason. * * @param[in] ipc IPC handle * @param[out] reason pointer to return reset reason * * @return Returns an error code (SC_ERR_NONE = success). */ sc_err_t sc_pm_reset_reason(sc_ipc_t ipc, sc_pm_reset_reason_t *reason); /*! * This function is used to boot a partition. * * @param[in] ipc IPC handle * @param[in] pt handle of partition to boot * @param[in] resource_cpu ID of the CPU resource to start * @param[in] boot_addr 64-bit boot address * @param[in] resource_mu ID of the MU that must be powered * @param[in] resource_dev ID of the boot device that must be powered * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid partition, resource, or addr, * - SC_ERR_NOACCESS if caller's partition is not the parent of the * partition to boot */ sc_err_t sc_pm_boot(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rsrc_t resource_cpu, sc_faddr_t boot_addr, sc_rsrc_t resource_mu, sc_rsrc_t resource_dev); /*! * This function is used to reboot the caller's partition. * * @param[in] ipc IPC handle * @param[in] type reset type * * If \a type is SC_PM_RESET_TYPE_COLD, then most peripherals owned by * the calling partition will be reset if possible. SC state (partitions, * power, clocks, etc.) is reset. The boot SW of the booting CPU must be * able to handle peripherals that that are not reset. * * If \a type is SC_PM_RESET_TYPE_WARM, then only the boot CPU is reset. * SC state (partitions, power, clocks, etc.) are NOT reset. The boot SW * of the booting CPU must be able to handle peripherals and SC state that * that are not reset. * * If \a type is SC_PM_RESET_TYPE_BOARD, then return with no action. * * If this function returns, then the reset did not occur due to an * invalid parameter. */ void sc_pm_reboot(sc_ipc_t ipc, sc_pm_reset_type_t type); /*! * This function is used to reboot a partition. * * @param[in] ipc IPC handle * @param[in] pt handle of partition to reboot * @param[in] type reset type * * If \a type is SC_PM_RESET_TYPE_COLD, then most peripherals owned by * the calling partition will be reset if possible. SC state (partitions, * power, clocks, etc.) is reset. The boot SW of the booting CPU must be * able to handle peripherals that that are not reset. * * If \a type is SC_PM_RESET_TYPE_WARM, then only the boot CPU is reset. * SC state (partitions, power, clocks, etc.) are NOT reset. The boot SW * of the booting CPU must be able to handle peripherals and SC state that * that are not reset. * * If \a type is SC_PM_RESET_TYPE_BOARD, then return with no action. * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid partition or type * - SC_ERR_NOACCESS if caller's partition is not the parent of \a pt, * * Most peripherals owned by the partition will be reset if * possible. SC state (partitions, power, clocks, etc.) is reset. The * boot SW of the booting CPU must be able to handle peripherals that * that are not reset. */ sc_err_t sc_pm_reboot_partition(sc_ipc_t ipc, sc_rm_pt_t pt, sc_pm_reset_type_t type); /*! * This function is used to start/stop a CPU. * * @param[in] ipc IPC handle * @param[in] resource ID of the CPU resource * @param[in] enable start if SC_TRUE; otherwise stop * @param[in] address 64-bit boot address * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid resource or address, * - SC_ERR_NOACCESS if caller's partition is not the parent of the * resource (CPU) owner */ sc_err_t sc_pm_cpu_start(sc_ipc_t ipc, sc_rsrc_t resource, sc_bool_t enable, sc_faddr_t address); /* @} */ #endif /* SCI_PM_API_H */ /**@}*/ trusted-firmware-a-2.2/plat/imx/common/include/sci/svc/rm/000077500000000000000000000000001355360272700235505ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/include/sci/svc/rm/sci_rm_api.h000066400000000000000000000632571355360272700260430ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /*! * Header file containing the public API for the System Controller (SC) * Resource Management (RM) function. This includes functions for * partitioning resources, pads, and memory regions. * * @addtogroup RM_SVC (SVC) Resource Management Service * * Module for the Resource Management (RM) service. * * @includedoc rm/details.dox * * @{ */ #ifndef SCI_RM_API_H #define SCI_RM_API_H /* Includes */ #include /* Defines */ /*! * @name Defines for type widths */ /*@{*/ #define SC_RM_PARTITION_W 5 /* Width of sc_rm_pt_t */ #define SC_RM_MEMREG_W 6 /* Width of sc_rm_mr_t */ #define SC_RM_DID_W 4 /* Width of sc_rm_did_t */ #define SC_RM_SID_W 6 /* Width of sc_rm_sid_t */ #define SC_RM_SPA_W 2 /* Width of sc_rm_spa_t */ #define SC_RM_PERM_W 3 /* Width of sc_rm_perm_t */ /*@}*/ /*! * @name Defines for ALL parameters */ /*@{*/ #define SC_RM_PT_ALL ((sc_rm_pt_t) UINT8_MAX) /* All partitions */ #define SC_RM_MR_ALL ((sc_rm_mr_t) UINT8_MAX) /* All memory regions */ /*@}*/ /*! * @name Defines for sc_rm_spa_t */ /*@{*/ #define SC_RM_SPA_PASSTHRU 0U /* Pass through (attribute driven by master) */ #define SC_RM_SPA_PASSSID 1U /* Pass through and output on SID */ #define SC_RM_SPA_ASSERT 2U /* Assert (force to be secure/privileged) */ #define SC_RM_SPA_NEGATE 3U /* Negate (force to be non-secure/user) */ /*@}*/ /*! * @name Defines for sc_rm_perm_t */ /*@{*/ #define SC_RM_PERM_NONE 0U /* No access */ #define SC_RM_PERM_SEC_R 1U /* Secure RO */ #define SC_RM_PERM_SECPRIV_RW 2U /* Secure privilege R/W */ #define SC_RM_PERM_SEC_RW 3U /* Secure R/W */ #define SC_RM_PERM_NSPRIV_R 4U /* Secure R/W, non-secure privilege RO */ #define SC_RM_PERM_NS_R 5U /* Secure R/W, non-secure RO */ #define SC_RM_PERM_NSPRIV_RW 6U /* Secure R/W, non-secure privilege R/W */ #define SC_RM_PERM_FULL 7U /* Full access */ /*@}*/ /* Types */ /*! * This type is used to declare a resource partition. */ typedef uint8_t sc_rm_pt_t; /*! * This type is used to declare a memory region. */ typedef uint8_t sc_rm_mr_t; /*! * This type is used to declare a resource domain ID used by the * isolation HW. */ typedef uint8_t sc_rm_did_t; /*! * This type is used to declare an SMMU StreamID. */ typedef uint16_t sc_rm_sid_t; /*! * This type is a used to declare master transaction attributes. */ typedef uint8_t sc_rm_spa_t; /*! * This type is used to declare a resource/memory region access permission. * Refer to the XRDC2 Block Guide for more information. */ typedef uint8_t sc_rm_perm_t; /* Functions */ /*! * @name Partition Functions * @{ */ /*! * This function requests that the SC create a new resource partition. * * @param[in] ipc IPC handle * @param[out] pt return handle for partition; used for subsequent function * calls associated with this partition * @param[in] secure boolean indicating if this partition should be secure; only * valid if caller is secure * @param[in] isolated boolean indicating if this partition should be HW isolated * via XRDC; set SC_TRUE if new DID is desired * @param[in] restricted boolean indicating if this partition should be restricted; set * SC_TRUE if masters in this partition cannot create new partitions * @param[in] grant boolean indicating if this partition should always grant * access and control to the parent * @param[in] coherent boolean indicating if this partition is coherent; * set SC_TRUE if only this partition will contain both AP clusters * and they will be coherent via the CCI * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_NOACCESS if caller's partition is restricted, * - SC_ERR_PARM if caller's partition is not secure but a new secure partition is requested, * - SC_ERR_LOCKED if caller's partition is locked, * - SC_ERR_UNAVAILABLE if partition table is full (no more allocation space) * * Marking as non-secure prevents subsequent functions from configuring masters in this * partition to assert the secure signal. If restricted then the new partition is limited * in what functions it can call, especially those associated with managing partitions. * * The grant option is usually used to isolate a bus master's traffic to specific * memory without isolating the peripheral interface of the master or the API * controls of that master. */ sc_err_t sc_rm_partition_alloc(sc_ipc_t ipc, sc_rm_pt_t *pt, sc_bool_t secure, sc_bool_t isolated, sc_bool_t restricted, sc_bool_t grant, sc_bool_t coherent); /*! * This function makes a partition confidential. * * @param[in] ipc IPC handle * @param[in] pt handle of partition that is granting * @param[in] retro retroactive * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if \a pt out of range, * - SC_ERR_NOACCESS if caller's not allowed to change \a pt * - SC_ERR_LOCKED if partition \a pt is locked * * Call to make a partition confidential. Confidential means only this * partition should be able to grant access permissions to this partition. * * If retroactive, then all resources owned by other partitions will have * access rights for this partition removed, even if locked. */ sc_err_t sc_rm_set_confidential(sc_ipc_t ipc, sc_rm_pt_t pt, sc_bool_t retro); /*! * This function frees a partition and assigns all resources to the caller. * * @param[in] ipc IPC handle * @param[in] pt handle of partition to free * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_NOACCESS if caller's partition is restricted, * - SC_PARM if \a pt out of range or invalid, * - SC_ERR_NOACCESS if \a pt is the SC partition, * - SC_ERR_NOACCESS if caller's partition is not the parent of \a pt, * - SC_ERR_LOCKED if \a pt or caller's partition is locked * * All resources, memory regions, and pads are assigned to the caller/parent. * The partition watchdog is disabled (even if locked). DID is freed. */ sc_err_t sc_rm_partition_free(sc_ipc_t ipc, sc_rm_pt_t pt); /*! * This function returns the DID of a partition. * * @param[in] ipc IPC handle * * @return Returns the domain ID (DID) of the caller's partition. * * The DID is a SoC-specific internal ID used by the HW resource * protection mechanism. It is only required by clients when using the * SEMA42 module as the DID is sometimes connected to the master ID. */ sc_rm_did_t sc_rm_get_did(sc_ipc_t ipc); /*! * This function forces a partition to use a specific static DID. * * @param[in] ipc IPC handle * @param[in] pt handle of partition to assign \a did * @param[in] did static DID to assign * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_NOACCESS if caller's partition is restricted, * - SC_PARM if \a pt or \a did out of range, * - SC_ERR_NOACCESS if caller's partition is not the parent of \a pt, * - SC_ERR_LOCKED if \a pt is locked * * Assumes no assigned resources or memory regions yet! The number of static * DID is fixed by the SC at boot. */ sc_err_t sc_rm_partition_static(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rm_did_t did); /*! * This function locks a partition. * * @param[in] ipc IPC handle * @param[in] pt handle of partition to lock * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if \a pt out of range, * - SC_ERR_NOACCESS if caller's partition is not the parent of \a pt * * If a partition is locked it cannot be freed, have resources/pads assigned * to/from it, memory regions created/assigned, DID changed, or parent changed. */ sc_err_t sc_rm_partition_lock(sc_ipc_t ipc, sc_rm_pt_t pt); /*! * This function gets the partition handle of the caller. * * @param[in] ipc IPC handle * @param[out] pt return handle for caller's partition * * @return Returns an error code (SC_ERR_NONE = success). */ sc_err_t sc_rm_get_partition(sc_ipc_t ipc, sc_rm_pt_t *pt); /*! * This function sets a new parent for a partition. * * @param[in] ipc IPC handle * @param[in] pt handle of partition for which parent is to be * changed * @param[in] pt_parent handle of partition to set as parent * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_NOACCESS if caller's partition is restricted, * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the parent of \a pt, * - SC_ERR_LOCKED if either partition is locked */ sc_err_t sc_rm_set_parent(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rm_pt_t pt_parent); /*! * This function moves all movable resources/pads owned by a source partition * to a destination partition. It can be used to more quickly set up a new * partition if a majority of the caller's resources are to be moved to a * new partition. * * @param[in] ipc IPC handle * @param[in] pt_src handle of partition from which resources should * be moved from * @param[in] pt_dst handle of partition to which resources should be * moved to * @param[in] move_rsrc boolean to indicate if resources should be moved * @param[in] move_pads boolean to indicate if pads should be moved * * @return Returns an error code (SC_ERR_NONE = success). * * By default, all resources are movable. This can be changed using the * sc_rm_set_resource_movable() function. Note all masters defaulted to SMMU * bypass. * * Return errors: * - SC_ERR_NOACCESS if caller's partition is restricted, * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not \a pt_src or the * parent of \a pt_src, * - SC_ERR_LOCKED if either partition is locked */ sc_err_t sc_rm_move_all(sc_ipc_t ipc, sc_rm_pt_t pt_src, sc_rm_pt_t pt_dst, sc_bool_t move_rsrc, sc_bool_t move_pads); /* @} */ /*! * @name Resource Functions * @{ */ /*! * This function assigns ownership of a resource to a partition. * * @param[in] ipc IPC handle * @param[in] pt handle of partition to which resource should be * assigned * @param[in] resource resource to assign * * @return Returns an error code (SC_ERR_NONE = success). * * This action resets the resource's master and peripheral attributes. * Privilege attribute will be PASSTHRU, security attribute will be * ASSERT if the partition si secure and NEGATE if it is not, and * masters will defaulted to SMMU bypass. Access permissions will reset * to SEC_RW for the owning partition only for secure partitions, FULL for * non-secure. DEfault is no access by other partitions. * * Return errors: * - SC_ERR_NOACCESS if caller's partition is restricted, * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the resource owner or parent * of the owner, * - SC_ERR_LOCKED if the owning partition or \a pt is locked */ sc_err_t sc_rm_assign_resource(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rsrc_t resource); /*! * This function flags resources as movable or not. * * @param[in] ipc IPC handle * @param[in] resource_fst first resource for which flag should be set * @param[in] resource_lst last resource for which flag should be set * @param[in] movable movable flag (SC_TRUE is movable) * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if resources are out of range, * - SC_ERR_NOACCESS if caller's partition is not a parent of a resource owner, * - SC_ERR_LOCKED if the owning partition is locked * * This function is used to determine the set of resources that will be * moved using the sc_rm_move_all() function. All resources are movable * by default so this function is normally used to prevent a set of * resources from moving. */ sc_err_t sc_rm_set_resource_movable(sc_ipc_t ipc, sc_rsrc_t resource_fst, sc_rsrc_t resource_lst, sc_bool_t movable); /*! * This function flags all of a subsystem's resources as movable * or not. * * @param[in] ipc IPC handle * @param[in] resource resource to use to identify subsystem * @param[in] movable movable flag (SC_TRUE is movable) * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if a function argument is out of range * * Note \a resource is used to find the associated subsystem. Only * resources owned by the caller are set. */ sc_err_t sc_rm_set_subsys_rsrc_movable(sc_ipc_t ipc, sc_rsrc_t resource, sc_bool_t movable); /*! * This function sets attributes for a resource which is a bus master (i.e. * capable of DMA). * * @param[in] ipc IPC handle * @param[in] resource master resource for which attributes should apply * @param[in] sa security attribute * @param[in] pa privilege attribute * @param[in] smmu_bypass SMMU bypass mode * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_NOACCESS if caller's partition is restricted, * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not a parent of the resource owner, * - SC_ERR_LOCKED if the owning partition is locked * * This function configures how the HW isolation will see bus transactions * from the specified master. Note the security attribute will only be * changed if the caller's partition is secure. */ sc_err_t sc_rm_set_master_attributes(sc_ipc_t ipc, sc_rsrc_t resource, sc_rm_spa_t sa, sc_rm_spa_t pa, sc_bool_t smmu_bypass); /*! * This function sets the StreamID for a resource which is a bus master (i.e. * capable of DMA). * * @param[in] ipc IPC handle * @param[in] resource master resource for which attributes should apply * @param[in] sid StreamID * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_NOACCESS if caller's partition is restricted, * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the resource owner or parent * of the owner, * - SC_ERR_LOCKED if the owning partition is locked * * This function configures the SID attribute associated with all bus transactions * from this master. Note 0 is not a valid SID as it is reserved to indicate * bypass. */ sc_err_t sc_rm_set_master_sid(sc_ipc_t ipc, sc_rsrc_t resource, sc_rm_sid_t sid); /*! * This function sets access permissions for a peripheral resource. * * @param[in] ipc IPC handle * @param[in] resource peripheral resource for which permissions should apply * @param[in] pt handle of partition \a perm should by applied for * @param[in] perm permissions to apply to \a resource for \a pt * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the resource owner or parent * of the owner, * - SC_ERR_LOCKED if the owning partition is locked * - SC_ERR_LOCKED if the \a pt is confidential and the caller isn't \a pt * * This function configures how the HW isolation will restrict access to a * peripheral based on the attributes of a transaction from bus master. */ sc_err_t sc_rm_set_peripheral_permissions(sc_ipc_t ipc, sc_rsrc_t resource, sc_rm_pt_t pt, sc_rm_perm_t perm); /*! * This function gets ownership status of a resource. * * @param[in] ipc IPC handle * @param[in] resource resource to check * * @return Returns a boolean (SC_TRUE if caller's partition owns the resource). * * If \a resource is out of range then SC_FALSE is returned. */ sc_bool_t sc_rm_is_resource_owned(sc_ipc_t ipc, sc_rsrc_t resource); /*! * This function is used to test if a resource is a bus master. * * @param[in] ipc IPC handle * @param[in] resource resource to check * * @return Returns a boolean (SC_TRUE if the resource is a bus master). * * If \a resource is out of range then SC_FALSE is returned. */ sc_bool_t sc_rm_is_resource_master(sc_ipc_t ipc, sc_rsrc_t resource); /*! * This function is used to test if a resource is a peripheral. * * @param[in] ipc IPC handle * @param[in] resource resource to check * * @return Returns a boolean (SC_TRUE if the resource is a peripheral). * * If \a resource is out of range then SC_FALSE is returned. */ sc_bool_t sc_rm_is_resource_peripheral(sc_ipc_t ipc, sc_rsrc_t resource); /*! * This function is used to obtain info about a resource. * * @param[in] ipc IPC handle * @param[in] resource resource to inquire about * @param[out] sid pointer to return StreamID * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if \a resource is out of range */ sc_err_t sc_rm_get_resource_info(sc_ipc_t ipc, sc_rsrc_t resource, sc_rm_sid_t *sid); /* @} */ /*! * @name Memory Region Functions * @{ */ /*! * This function requests that the SC create a new memory region. * * @param[in] ipc IPC handle * @param[out] mr return handle for region; used for * subsequent function calls * associated with this region * @param[in] addr_start start address of region (physical) * @param[in] addr_end end address of region (physical) * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if the new memory region is misaligned, * - SC_ERR_LOCKED if caller's partition is locked, * - SC_ERR_PARM if the new memory region spans multiple existing regions, * - SC_ERR_NOACCESS if caller's partition does not own the memory containing * the new region, * - SC_ERR_UNAVAILABLE if memory region table is full (no more allocation * space) * * The area covered by the memory region must currently be owned by the caller. * By default, the new region will have access permission set to allow the * caller to access. */ sc_err_t sc_rm_memreg_alloc(sc_ipc_t ipc, sc_rm_mr_t *mr, sc_faddr_t addr_start, sc_faddr_t addr_end); /*! * This function requests that the SC split a memory region. * * @param[in] ipc IPC handle * @param[in] mr handle of memory region to split * @param[out] mr_ret return handle for new region; used for * subsequent function calls * associated with this region * @param[in] addr_start start address of region (physical) * @param[in] addr_end end address of region (physical) * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if the new memory region is not start/end part of mr, * - SC_ERR_LOCKED if caller's partition is locked, * - SC_ERR_PARM if the new memory region spans multiple existing regions, * - SC_ERR_NOACCESS if caller's partition does not own the memory containing * the new region, * - SC_ERR_UNAVAILABLE if memory region table is full (no more allocation * space) * * Note the new region must start or end on the split region. */ sc_err_t sc_rm_memreg_split(sc_ipc_t ipc, sc_rm_mr_t mr, sc_rm_mr_t *mr_ret, sc_faddr_t addr_start, sc_faddr_t addr_end); /*! * This function frees a memory region. * * @param[in] ipc IPC handle * @param[in] mr handle of memory region to free * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if \a mr out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not a parent of \a mr, * - SC_ERR_LOCKED if the owning partition of \a mr is locked */ sc_err_t sc_rm_memreg_free(sc_ipc_t ipc, sc_rm_mr_t mr); /*! * Internal SC function to find a memory region. * * @see sc_rm_find_memreg(). */ /*! * This function finds a memory region. * * @param[in] ipc IPC handle * @param[out] mr return handle for region; used for * subsequent function calls * associated with this region * @param[in] addr_start start address of region to search for * @param[in] addr_end end address of region to search for * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_NOTFOUND if region not found, * * Searches only for regions owned by the caller. Finds first * region containing the range specified. */ sc_err_t sc_rm_find_memreg(sc_ipc_t ipc, sc_rm_mr_t *mr, sc_faddr_t addr_start, sc_faddr_t addr_end); /*! * This function assigns ownership of a memory region. * * @param[in] ipc IPC handle * @param[in] pt handle of partition to which memory region * should be assigned * @param[in] mr handle of memory region to assign * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the \a mr owner or parent * of the owner, * - SC_ERR_LOCKED if the owning partition or \a pt is locked */ sc_err_t sc_rm_assign_memreg(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rm_mr_t mr); /*! * This function sets access permissions for a memory region. * * @param[in] ipc IPC handle * @param[in] mr handle of memory region for which permissions * should apply * @param[in] pt handle of partition \a perm should by * applied for * @param[in] perm permissions to apply to \a mr for \a pt * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the region owner or parent * of the owner, * - SC_ERR_LOCKED if the owning partition is locked * - SC_ERR_LOCKED if the \a pt is confidential and the caller isn't \a pt * * This function configures how the HW isolation will restrict access to a * memory region based on the attributes of a transaction from bus master. */ sc_err_t sc_rm_set_memreg_permissions(sc_ipc_t ipc, sc_rm_mr_t mr, sc_rm_pt_t pt, sc_rm_perm_t perm); /*! * This function gets ownership status of a memory region. * * @param[in] ipc IPC handle * @param[in] mr handle of memory region to check * * @return Returns a boolean (SC_TRUE if caller's partition owns the * memory region). * * If \a mr is out of range then SC_FALSE is returned. */ sc_bool_t sc_rm_is_memreg_owned(sc_ipc_t ipc, sc_rm_mr_t mr); /*! * This function is used to obtain info about a memory region. * * @param[in] ipc IPC handle * @param[in] mr handle of memory region to inquire about * @param[out] addr_start pointer to return start address * @param[out] addr_end pointer to return end address * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if \a mr is out of range */ sc_err_t sc_rm_get_memreg_info(sc_ipc_t ipc, sc_rm_mr_t mr, sc_faddr_t *addr_start, sc_faddr_t *addr_end); /* @} */ /*! * @name Pad Functions * @{ */ /*! * This function assigns ownership of a pad to a partition. * * @param[in] ipc IPC handle * @param[in] pt handle of partition to which pad should * be assigned * @param[in] pad pad to assign * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_NOACCESS if caller's partition is restricted, * - SC_PARM if arguments out of range or invalid, * - SC_ERR_NOACCESS if caller's partition is not the pad owner or parent * of the owner, * - SC_ERR_LOCKED if the owning partition or \a pt is locked */ sc_err_t sc_rm_assign_pad(sc_ipc_t ipc, sc_rm_pt_t pt, sc_pad_t pad); /*! * This function flags pads as movable or not. * * @param[in] ipc IPC handle * @param[in] pad_fst first pad for which flag should be set * @param[in] pad_lst last pad for which flag should be set * @param[in] movable movable flag (SC_TRUE is movable) * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_PARM if pads are out of range, * - SC_ERR_NOACCESS if caller's partition is not a parent of a pad owner, * - SC_ERR_LOCKED if the owning partition is locked * * This function is used to determine the set of pads that will be * moved using the sc_rm_move_all() function. All pads are movable * by default so this function is normally used to prevent a set of * pads from moving. */ sc_err_t sc_rm_set_pad_movable(sc_ipc_t ipc, sc_pad_t pad_fst, sc_pad_t pad_lst, sc_bool_t movable); /*! * This function gets ownership status of a pad. * * @param[in] ipc IPC handle * @param[in] pad pad to check * * @return Returns a boolean (SC_TRUE if caller's partition owns the pad). * * If \a pad is out of range then SC_FALSE is returned. */ sc_bool_t sc_rm_is_pad_owned(sc_ipc_t ipc, sc_pad_t pad); /* @} */ /*! * @name Debug Functions * @{ */ /*! * This function dumps the RM state for debug. * * @param[in] ipc IPC handle */ void sc_rm_dump(sc_ipc_t ipc); /* @} */ #endif /* SCI_RM_API_H */ /**@}*/ trusted-firmware-a-2.2/plat/imx/common/include/sci/svc/timer/000077500000000000000000000000001355360272700242525ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/include/sci/svc/timer/sci_timer_api.h000066400000000000000000000241421355360272700272350ustar00rootroot00000000000000/* * Copyright (C) 2016 Freescale Semiconductor, Inc. * Copyright 2017-2019 NXP * * SPDX-License-Identifier: BSD-3-Clause */ /*! * Header file containing the public API for the System Controller (SC) * Timer function. * * @addtogroup TIMER_SVC (SVC) Timer Service * * Module for the Timer service. This includes support for the watchdog, RTC, * and system counter. Note every resource partition has a watchdog it can * use. * * @{ */ #ifndef SC_TIMER_API_H #define SC_TIMER_API_H /* Includes */ #include /* Defines */ /*! * @name Defines for type widths */ /*@{*/ #define SC_TIMER_ACTION_W 3U /* Width of sc_timer_wdog_action_t */ /*@}*/ /*! * @name Defines for sc_timer_wdog_action_t */ /*@{*/ #define SC_TIMER_WDOG_ACTION_PARTITION 0U /* Reset partition */ #define SC_TIMER_WDOG_ACTION_WARM 1U /* Warm reset system */ #define SC_TIMER_WDOG_ACTION_COLD 2U /* Cold reset system */ #define SC_TIMER_WDOG_ACTION_BOARD 3U /* Reset board */ #define SC_TIMER_WDOG_ACTION_IRQ 4U /* Only generate IRQs */ /*@}*/ /* Types */ /*! * This type is used to configure the watchdog action. */ typedef uint8_t sc_timer_wdog_action_t; /*! * This type is used to declare a watchdog time value in milliseconds. */ typedef uint32_t sc_timer_wdog_time_t; /* Functions */ /*! * @name Watchdog Functions * @{ */ /*! * This function sets the watchdog timeout in milliseconds. If not * set then the timeout defaults to the max. Once locked this value * cannot be changed. * * @param[in] ipc IPC handle * @param[in] timeout timeout period for the watchdog * * @return Returns an error code (SC_ERR_NONE = success, SC_ERR_LOCKED * = locked). */ sc_err_t sc_timer_set_wdog_timeout(sc_ipc_t ipc, sc_timer_wdog_time_t timeout); /*! * This function sets the watchdog pre-timeout in milliseconds. If not * set then the pre-timeout defaults to the max. Once locked this value * cannot be changed. * * @param[in] ipc IPC handle * @param[in] pre_timeout pre-timeout period for the watchdog * * When the pre-timeout expires an IRQ will be generated. Note this timeout * clears when the IRQ is triggered. An IRQ is generated for the failing * partition and all of its child partitions. * * @return Returns an error code (SC_ERR_NONE = success). */ sc_err_t sc_timer_set_wdog_pre_timeout(sc_ipc_t ipc, sc_timer_wdog_time_t pre_timeout); /*! * This function starts the watchdog. * * @param[in] ipc IPC handle * @param[in] lock boolean indicating the lock status * * @return Returns an error code (SC_ERR_NONE = success). * * If \a lock is set then the watchdog cannot be stopped or the timeout * period changed. */ sc_err_t sc_timer_start_wdog(sc_ipc_t ipc, sc_bool_t lock); /*! * This function stops the watchdog if it is not locked. * * @param[in] ipc IPC handle * * @return Returns an error code (SC_ERR_NONE = success, SC_ERR_LOCKED * = locked). */ sc_err_t sc_timer_stop_wdog(sc_ipc_t ipc); /*! * This function pings (services, kicks) the watchdog resetting the time * before expiration back to the timeout. * * @param[in] ipc IPC handle * * @return Returns an error code (SC_ERR_NONE = success). */ sc_err_t sc_timer_ping_wdog(sc_ipc_t ipc); /*! * This function gets the status of the watchdog. All arguments are * in milliseconds. * * @param[in] ipc IPC handle * @param[out] timeout pointer to return the timeout * @param[out] max_timeout pointer to return the max timeout * @param[out] remaining_time pointer to return the time remaining * until trigger * * @return Returns an error code (SC_ERR_NONE = success). */ sc_err_t sc_timer_get_wdog_status(sc_ipc_t ipc, sc_timer_wdog_time_t *timeout, sc_timer_wdog_time_t *max_timeout, sc_timer_wdog_time_t *remaining_time); /*! * This function gets the status of the watchdog of a partition. All * arguments are in milliseconds. * * @param[in] ipc IPC handle * @param[in] pt partition to query * @param[out] enb pointer to return enable status * @param[out] timeout pointer to return the timeout * @param[out] remaining_time pointer to return the time remaining * until trigger * * @return Returns an error code (SC_ERR_NONE = success). */ sc_err_t sc_timer_pt_get_wdog_status(sc_ipc_t ipc, sc_rm_pt_t pt, sc_bool_t *enb, sc_timer_wdog_time_t *timeout, sc_timer_wdog_time_t *remaining_time); /*! * This function configures the action to be taken when a watchdog * expires. * * @param[in] ipc IPC handle * @param[in] pt partition to affect * @param[in] action action to take * * Default action is inherited from the parent. * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid parameters, * - SC_ERR_NOACCESS if caller's partition is not the SYSTEM owner, * - SC_ERR_LOCKED if the watchdog is locked */ sc_err_t sc_timer_set_wdog_action(sc_ipc_t ipc, sc_rm_pt_t pt, sc_timer_wdog_action_t action); /* @} */ /*! * @name Real-Time Clock (RTC) Functions * @{ */ /*! * This function sets the RTC time. Only the owner of the SC_R_SYSTEM * resource can set the time. * * @param[in] ipc IPC handle * @param[in] year year (min 1970) * @param[in] mon month (1-12) * @param[in] day day of the month (1-31) * @param[in] hour hour (0-23) * @param[in] min minute (0-59) * @param[in] sec second (0-59) * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid time/date parameters, * - SC_ERR_NOACCESS if caller's partition is not the SYSTEM owner */ sc_err_t sc_timer_set_rtc_time(sc_ipc_t ipc, uint16_t year, uint8_t mon, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec); /*! * This function gets the RTC time. * * @param[in] ipc IPC handle * @param[out] year pointer to return year (min 1970) * @param[out] mon pointer to return month (1-12) * @param[out] day pointer to return day of the month (1-31) * @param[out] hour pointer to return hour (0-23) * @param[out] min pointer to return minute (0-59) * @param[out] sec pointer to return second (0-59) * * @return Returns an error code (SC_ERR_NONE = success). */ sc_err_t sc_timer_get_rtc_time(sc_ipc_t ipc, uint16_t *year, uint8_t *mon, uint8_t *day, uint8_t *hour, uint8_t *min, uint8_t *sec); /*! * This function gets the RTC time in seconds since 1/1/1970. * * @param[in] ipc IPC handle * @param[out] sec pointer to return second * * @return Returns an error code (SC_ERR_NONE = success). */ sc_err_t sc_timer_get_rtc_sec1970(sc_ipc_t ipc, uint32_t *sec); /*! * This function sets the RTC alarm. * * @param[in] ipc IPC handle * @param[in] year year (min 1970) * @param[in] mon month (1-12) * @param[in] day day of the month (1-31) * @param[in] hour hour (0-23) * @param[in] min minute (0-59) * @param[in] sec second (0-59) * * Note this alarm setting clears when the alarm is triggered. * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid time/date parameters */ sc_err_t sc_timer_set_rtc_alarm(sc_ipc_t ipc, uint16_t year, uint8_t mon, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec); /*! * This function sets the RTC alarm (periodic mode). * * @param[in] ipc IPC handle * @param[in] sec period in seconds * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid time/date parameters */ sc_err_t sc_timer_set_rtc_periodic_alarm(sc_ipc_t ipc, uint32_t sec); /*! * This function cancels the RTC alarm. * * @param[in] ipc IPC handle * * Note this alarm setting clears when the alarm is triggered. * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid time/date parameters */ sc_err_t sc_timer_cancel_rtc_alarm(sc_ipc_t ipc); /*! * This function sets the RTC calibration value. Only the owner of the SC_R_SYSTEM * resource can set the calibration. * * @param[in] ipc IPC handle * @param[in] count calbration count (-16 to 15) * * The calibration value is a 5-bit value including the sign bit, which is * implemented in 2's complement. It is added or subtracted from the RTC on * a perdiodic basis, once per 32768 cycles of the RTC clock. * * @return Returns an error code (SC_ERR_NONE = success). */ sc_err_t sc_timer_set_rtc_calb(sc_ipc_t ipc, int8_t count); /* @} */ /*! * @name System Counter (SYSCTR) Functions * @{ */ /*! * This function sets the SYSCTR alarm. * * @param[in] ipc IPC handle * @param[in] ticks number of 8MHz cycles * * Note this alarm setting clears when the alarm is triggered. * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid time/date parameters */ sc_err_t sc_timer_set_sysctr_alarm(sc_ipc_t ipc, uint64_t ticks); /*! * This function sets the SYSCTR alarm (periodic mode). * * @param[in] ipc IPC handle * @param[in] ticks number of 8MHz cycles * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid time/date parameters */ sc_err_t sc_timer_set_sysctr_periodic_alarm(sc_ipc_t ipc, uint64_t ticks); /*! * This function cancels the SYSCTR alarm. * * @param[in] ipc IPC handle * * Note this alarm setting clears when the alarm is triggered. * * @return Returns an error code (SC_ERR_NONE = success). * * Return errors: * - SC_ERR_PARM if invalid time/date parameters */ sc_err_t sc_timer_cancel_sysctr_alarm(sc_ipc_t ipc); /* @} */ #endif /* SC_TIMER_API_H */ /**@}*/ trusted-firmware-a-2.2/plat/imx/common/lpuart_console.S000066400000000000000000000026371355360272700233230ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "imx8_lpuart.h" .globl console_lpuart_register .globl console_lpuart_init .globl console_lpuart_putc .globl console_lpuart_getc .globl console_lpuart_flush func console_lpuart_register mov x7, x30 mov x6, x3 cbz x6, register_fail str x0, [x6, #CONSOLE_T_DRVDATA] bl console_lpuart_init cbz x0, register_fail mov x0, x6 mov x30, x7 finish_console_register lpuart putc=1, getc=1, flush=1 register_fail: ret x7 endfunc console_lpuart_register func console_lpuart_init mov w0, #1 ret endfunc console_lpuart_init func console_lpuart_putc ldr x1, [x1, #CONSOLE_T_DRVDATA] cbz x1, putc_error /* Prepare '\r' to '\n' */ cmp w0, #0xA b.ne 2f 1: /* Check if the transmit FIFO is full */ ldr w2, [x1, #STAT] tbz w2, #23, 1b mov w2, #0xD str w2, [x1, #DATA] 2: /* Check if the transmit FIFO is full */ ldr w2, [x1, #STAT] tbz w2, #23, 2b str w0, [x1, #DATA] ret putc_error: mov w0, #-1 ret endfunc console_lpuart_putc func console_lpuart_getc ldr x0, [x0, #CONSOLE_T_DRVDATA] cbz x0, getc_error /* Check if the receive FIFO state */ ret getc_error: mov w0, #-1 ret endfunc console_lpuart_getc func console_lpuart_flush mov x0, #0 ret endfunc console_lpuart_flush trusted-firmware-a-2.2/plat/imx/common/plat_imx8_gic.c000066400000000000000000000057071355360272700230420ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include /* the GICv3 driver only needs to be initialized in EL3 */ uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT]; static const interrupt_prop_t g01s_interrupt_props[] = { INTR_PROP_DESC(6, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(7, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0, GIC_INTR_CFG_LEVEL), }; static unsigned int plat_imx_mpidr_to_core_pos(unsigned long mpidr) { return (unsigned int)plat_core_pos_by_mpidr(mpidr); } const gicv3_driver_data_t arm_gic_data = { .gicd_base = PLAT_GICD_BASE, .gicr_base = PLAT_GICR_BASE, .interrupt_props = g01s_interrupt_props, .interrupt_props_num = ARRAY_SIZE(g01s_interrupt_props), .rdistif_num = PLATFORM_CORE_COUNT, .rdistif_base_addrs = rdistif_base_addrs, .mpidr_to_core_pos = plat_imx_mpidr_to_core_pos, }; void plat_gic_driver_init(void) { /* * the GICv3 driver is initialized in EL3 and does not need * to be initialized again in S-EL1. This is because the S-EL1 * can use GIC system registers to manage interrupts and does * not need GIC interface base addresses to be configured. */ #if IMAGE_BL31 gicv3_driver_init(&arm_gic_data); #endif } static __inline void plat_gicr_exit_sleep(void) { unsigned int val = mmio_read_32(PLAT_GICR_BASE + GICR_WAKER); /* * ProcessorSleep bit can ONLY be set to zero when * Quiescent bit and Sleep bit are both zero, so * need to make sure Quiescent bit and Sleep bit * are zero before clearing ProcessorSleep bit. */ if (val & WAKER_QSC_BIT) { mmio_write_32(PLAT_GICR_BASE + GICR_WAKER, val & ~WAKER_SL_BIT); /* Wait till the WAKER_QSC_BIT changes to 0 */ while ((mmio_read_32(PLAT_GICR_BASE + GICR_WAKER) & WAKER_QSC_BIT) != 0U) ; } } void plat_gic_init(void) { plat_gicr_exit_sleep(); gicv3_distif_init(); gicv3_rdistif_init(plat_my_core_pos()); gicv3_cpuif_enable(plat_my_core_pos()); } void plat_gic_cpuif_enable(void) { gicv3_cpuif_enable(plat_my_core_pos()); } void plat_gic_cpuif_disable(void) { gicv3_cpuif_disable(plat_my_core_pos()); } void plat_gic_pcpu_init(void) { gicv3_rdistif_init(plat_my_core_pos()); } void plat_gic_save(unsigned int proc_num, struct plat_gic_ctx *ctx) { /* save the gic rdist/dist context */ for (int i = 0; i < PLATFORM_CORE_COUNT; i++) gicv3_rdistif_save(i, &ctx->rdist_ctx[i]); gicv3_distif_save(&ctx->dist_ctx); } void plat_gic_restore(unsigned int proc_num, struct plat_gic_ctx *ctx) { /* restore the gic rdist/dist context */ gicv3_distif_init_restore(&ctx->dist_ctx); for (int i = 0; i < PLATFORM_CORE_COUNT; i++) gicv3_rdistif_init_restore(i, &ctx->rdist_ctx[i]); } trusted-firmware-a-2.2/plat/imx/common/sci/000077500000000000000000000000001355360272700207145ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/sci/imx8_mu.c000066400000000000000000000035461355360272700224560ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "imx8_mu.h" void MU_Resume(uint32_t base) { uint32_t reg, i; reg = mmio_read_32(base + MU_ACR_OFFSET1); /* Clear GIEn, RIEn, TIEn, GIRn and ABFn. */ reg &= ~(MU_CR_GIEn_MASK1 | MU_CR_RIEn_MASK1 | MU_CR_TIEn_MASK1 | MU_CR_GIRn_MASK1 | MU_CR_Fn_MASK1); mmio_write_32(base + MU_ACR_OFFSET1, reg); /* Enable all RX interrupts */ for (i = 0; i < MU_RR_COUNT; i++) MU_EnableRxFullInt(base, i); } void MU_EnableRxFullInt(uint32_t base, uint32_t index) { uint32_t reg = mmio_read_32(base + MU_ACR_OFFSET1); reg &= ~(MU_CR_GIRn_MASK1 | MU_CR_NMI_MASK1); reg |= MU_CR_RIE0_MASK1 >> index; mmio_write_32(base + MU_ACR_OFFSET1, reg); } void MU_EnableGeneralInt(uint32_t base, uint32_t index) { uint32_t reg = mmio_read_32(base + MU_ACR_OFFSET1); reg &= ~(MU_CR_GIRn_MASK1 | MU_CR_NMI_MASK1); reg |= MU_CR_GIE0_MASK1 >> index; mmio_write_32(base + MU_ACR_OFFSET1, reg); } void MU_SendMessage(uint32_t base, uint32_t regIndex, uint32_t msg) { uint32_t mask = MU_SR_TE0_MASK1 >> regIndex; /* Wait TX register to be empty. */ while (!(mmio_read_32(base + MU_ASR_OFFSET1) & mask)) ; mmio_write_32(base + MU_ATR0_OFFSET1 + (regIndex * 4), msg); } void MU_ReceiveMsg(uint32_t base, uint32_t regIndex, uint32_t *msg) { uint32_t mask = MU_SR_RF0_MASK1 >> regIndex; /* Wait RX register to be full. */ while (!(mmio_read_32(base + MU_ASR_OFFSET1) & mask)) ; *msg = mmio_read_32(base + MU_ARR0_OFFSET1 + (regIndex * 4)); } void MU_Init(uint32_t base) { uint32_t reg; reg = mmio_read_32(base + MU_ACR_OFFSET1); /* Clear GIEn, RIEn, TIEn, GIRn and ABFn. */ reg &= ~(MU_CR_GIEn_MASK1 | MU_CR_RIEn_MASK1 | MU_CR_TIEn_MASK1 | MU_CR_GIRn_MASK1 | MU_CR_Fn_MASK1); mmio_write_32(base + MU_ACR_OFFSET1, reg); } trusted-firmware-a-2.2/plat/imx/common/sci/imx8_mu.h000066400000000000000000000020101355360272700224440ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #define MU_ATR0_OFFSET1 0x0 #define MU_ARR0_OFFSET1 0x10 #define MU_ASR_OFFSET1 0x20 #define MU_ACR_OFFSET1 0x24 #define MU_TR_COUNT1 4 #define MU_RR_COUNT1 4 #define MU_CR_GIEn_MASK1 (0xFu << 28) #define MU_CR_RIEn_MASK1 (0xF << 24) #define MU_CR_TIEn_MASK1 (0xF << 20) #define MU_CR_GIRn_MASK1 (0xF << 16) #define MU_CR_NMI_MASK1 (1 << 3) #define MU_CR_Fn_MASK1 0x7 #define MU_SR_TE0_MASK1 (1 << 23) #define MU_SR_RF0_MASK1 (1 << 27) #define MU_CR_RIE0_MASK1 (1 << 27) #define MU_CR_GIE0_MASK1 (1U << 31) #define MU_TR_COUNT 4 #define MU_RR_COUNT 4 void MU_Init(uint32_t base); void MU_SendMessage(uint32_t base, uint32_t regIndex, uint32_t msg); void MU_ReceiveMsg(uint32_t base, uint32_t regIndex, uint32_t *msg); void MU_EnableGeneralInt(uint32_t base, uint32_t index); void MU_EnableRxFullInt(uint32_t base, uint32_t index); void MU_Resume(uint32_t base); trusted-firmware-a-2.2/plat/imx/common/sci/ipc.c000066400000000000000000000042521355360272700216360ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "imx8_mu.h" DEFINE_BAKERY_LOCK(sc_ipc_bakery_lock); #define sc_ipc_lock_init() bakery_lock_init(&sc_ipc_bakery_lock) #define sc_ipc_lock() bakery_lock_get(&sc_ipc_bakery_lock) #define sc_ipc_unlock() bakery_lock_release(&sc_ipc_bakery_lock) void sc_call_rpc(sc_ipc_t ipc, sc_rpc_msg_t *msg, bool no_resp) { sc_ipc_lock(); sc_ipc_write(ipc, msg); if (!no_resp) sc_ipc_read(ipc, msg); sc_ipc_unlock(); } sc_err_t sc_ipc_open(sc_ipc_t *ipc, sc_ipc_id_t id) { uint32_t base = id; uint32_t i; /* Get MU base associated with IPC channel */ if ((ipc == NULL) || (base == 0)) return SC_ERR_IPC; sc_ipc_lock_init(); /* Init MU */ MU_Init(base); /* Enable all RX interrupts */ for (i = 0; i < MU_RR_COUNT; i++) { MU_EnableRxFullInt(base, i); } /* Return MU address as handle */ *ipc = (sc_ipc_t) id; return SC_ERR_NONE; } void sc_ipc_close(sc_ipc_t ipc) { uint32_t base = ipc; if (base != 0) MU_Init(base); } void sc_ipc_read(sc_ipc_t ipc, void *data) { uint32_t base = ipc; sc_rpc_msg_t *msg = (sc_rpc_msg_t *) data; uint8_t count = 0; /* Check parms */ if ((base == 0) || (msg == NULL)) return; /* Read first word */ MU_ReceiveMsg(base, 0, (uint32_t *) msg); count++; /* Check size */ if (msg->size > SC_RPC_MAX_MSG) { *((uint32_t *) msg) = 0; return; } /* Read remaining words */ while (count < msg->size) { MU_ReceiveMsg(base, count % MU_RR_COUNT, &(msg->DATA.u32[count - 1])); count++; } } void sc_ipc_write(sc_ipc_t ipc, void *data) { sc_rpc_msg_t *msg = (sc_rpc_msg_t *) data; uint32_t base = ipc; uint8_t count = 0; /* Check parms */ if ((base == 0) || (msg == NULL)) return; /* Check size */ if (msg->size > SC_RPC_MAX_MSG) return; /* Write first word */ MU_SendMessage(base, 0, *((uint32_t *) msg)); count++; /* Write remaining words */ while (count < msg->size) { MU_SendMessage(base, count % MU_TR_COUNT, msg->DATA.u32[count - 1]); count++; } } trusted-firmware-a-2.2/plat/imx/common/sci/sci_api.mk000066400000000000000000000007001355360272700226510ustar00rootroot00000000000000# # Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # BL31_SOURCES += plat/imx/common/sci/ipc.c \ plat/imx/common/sci/imx8_mu.c \ plat/imx/common/sci/svc/pad/pad_rpc_clnt.c \ plat/imx/common/sci/svc/pm/pm_rpc_clnt.c \ plat/imx/common/sci/svc/rm/rm_rpc_clnt.c \ plat/imx/common/sci/svc/timer/timer_rpc_clnt.c \ plat/imx/common/sci/svc/misc/misc_rpc_clnt.c trusted-firmware-a-2.2/plat/imx/common/sci/svc/000077500000000000000000000000001355360272700215075ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/sci/svc/misc/000077500000000000000000000000001355360272700224425ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/sci/svc/misc/misc_rpc_clnt.c000066400000000000000000000266021355360272700254330ustar00rootroot00000000000000/* * Copyright (C) 2016 Freescale Semiconductor, Inc. * Copyright 2017-2018 NXP * * SPDX-License-Identifier: BSD-3-Clause */ /*! * File containing client-side RPC functions for the MISC service. These * functions are ported to clients that communicate to the SC. * * @addtogroup MISC_SVC * @{ */ /* Includes */ #include #include #include #include #include #include "sci_misc_rpc.h" /* Local Defines */ /* Local Types */ /* Local Functions */ sc_err_t sc_misc_set_control(sc_ipc_t ipc, sc_rsrc_t resource, sc_ctrl_t ctrl, uint32_t val) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SET_CONTROL; RPC_U32(&msg, 0U) = (uint32_t)ctrl; RPC_U32(&msg, 4U) = (uint32_t)val; RPC_U16(&msg, 8U) = (uint16_t)resource; RPC_SIZE(&msg) = 4U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_misc_get_control(sc_ipc_t ipc, sc_rsrc_t resource, sc_ctrl_t ctrl, uint32_t *val) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_GET_CONTROL; RPC_U32(&msg, 0U) = (uint32_t)ctrl; RPC_U16(&msg, 4U) = (uint16_t)resource; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); if (val != NULL) *val = RPC_U32(&msg, 0U); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_misc_set_max_dma_group(sc_ipc_t ipc, sc_rm_pt_t pt, sc_misc_dma_group_t max) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SET_MAX_DMA_GROUP; RPC_U8(&msg, 0U) = (uint8_t)pt; RPC_U8(&msg, 1U) = (uint8_t)max; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_misc_set_dma_group(sc_ipc_t ipc, sc_rsrc_t resource, sc_misc_dma_group_t group) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SET_DMA_GROUP; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_U8(&msg, 2U) = (uint8_t)group; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_misc_seco_image_load(sc_ipc_t ipc, sc_faddr_t addr_src, sc_faddr_t addr_dst, uint32_t len, sc_bool_t fw) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_IMAGE_LOAD; RPC_U32(&msg, 0U) = (uint32_t)(addr_src >> 32U); RPC_U32(&msg, 4U) = (uint32_t)addr_src; RPC_U32(&msg, 8U) = (uint32_t)(addr_dst >> 32U); RPC_U32(&msg, 12U) = (uint32_t)addr_dst; RPC_U32(&msg, 16U) = (uint32_t)len; RPC_U8(&msg, 20U) = (uint8_t)fw; RPC_SIZE(&msg) = 7U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_misc_seco_authenticate(sc_ipc_t ipc, sc_misc_seco_auth_cmd_t cmd, sc_faddr_t addr) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_AUTHENTICATE; RPC_U32(&msg, 0U) = (uint32_t)(addr >> 32U); RPC_U32(&msg, 4U) = (uint32_t)addr; RPC_U8(&msg, 8U) = (uint8_t)cmd; RPC_SIZE(&msg) = 4U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_misc_seco_fuse_write(sc_ipc_t ipc, sc_faddr_t addr) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_FUSE_WRITE; RPC_U32(&msg, 0U) = (uint32_t)(addr >> 32U); RPC_U32(&msg, 4U) = (uint32_t)addr; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_misc_seco_enable_debug(sc_ipc_t ipc, sc_faddr_t addr) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_ENABLE_DEBUG; RPC_U32(&msg, 0U) = (uint32_t)(addr >> 32U); RPC_U32(&msg, 4U) = (uint32_t)addr; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_misc_seco_forward_lifecycle(sc_ipc_t ipc, uint32_t lifecycle) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_FORWARD_LIFECYCLE; RPC_U32(&msg, 0U) = (uint32_t)lifecycle; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_misc_seco_return_lifecycle(sc_ipc_t ipc, sc_faddr_t addr) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_RETURN_LIFECYCLE; RPC_U32(&msg, 0U) = (uint32_t)(addr >> 32U); RPC_U32(&msg, 4U) = (uint32_t)addr; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } void sc_misc_seco_build_info(sc_ipc_t ipc, uint32_t *version, uint32_t *commit) { sc_rpc_msg_t msg; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_BUILD_INFO; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); if (version != NULL) *version = RPC_U32(&msg, 0U); if (commit != NULL) *commit = RPC_U32(&msg, 4U); } sc_err_t sc_misc_seco_chip_info(sc_ipc_t ipc, uint16_t *lc, uint16_t *monotonic, uint32_t *uid_l, uint32_t *uid_h) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SECO_CHIP_INFO; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); if (uid_l != NULL) *uid_l = RPC_U32(&msg, 0U); if (uid_h != NULL) *uid_h = RPC_U32(&msg, 4U); if (lc != NULL) *lc = RPC_U16(&msg, 8U); if (monotonic != NULL) *monotonic = RPC_U16(&msg, 10U); result = RPC_R8(&msg); return (sc_err_t)result; } void sc_misc_debug_out(sc_ipc_t ipc, uint8_t ch) { sc_rpc_msg_t msg; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_DEBUG_OUT; RPC_U8(&msg, 0U) = (uint8_t)ch; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); } sc_err_t sc_misc_waveform_capture(sc_ipc_t ipc, sc_bool_t enable) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_WAVEFORM_CAPTURE; RPC_U8(&msg, 0U) = (uint8_t)enable; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } void sc_misc_build_info(sc_ipc_t ipc, uint32_t *build, uint32_t *commit) { sc_rpc_msg_t msg; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_BUILD_INFO; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); if (build != NULL) *build = RPC_U32(&msg, 0U); if (commit != NULL) *commit = RPC_U32(&msg, 4U); } void sc_misc_unique_id(sc_ipc_t ipc, uint32_t *id_l, uint32_t *id_h) { sc_rpc_msg_t msg; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_UNIQUE_ID; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); if (id_l != NULL) *id_l = RPC_U32(&msg, 0U); if (id_h != NULL) *id_h = RPC_U32(&msg, 4U); } sc_err_t sc_misc_set_ari(sc_ipc_t ipc, sc_rsrc_t resource, sc_rsrc_t resource_mst, uint16_t ari, sc_bool_t enable) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SET_ARI; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_U16(&msg, 2U) = (uint16_t)resource_mst; RPC_U16(&msg, 4U) = (uint16_t)ari; RPC_U8(&msg, 6U) = (uint8_t)enable; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } void sc_misc_boot_status(sc_ipc_t ipc, sc_misc_boot_status_t status) { sc_rpc_msg_t msg; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_BOOT_STATUS; RPC_U8(&msg, 0U) = (uint8_t)status; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_TRUE); } sc_err_t sc_misc_boot_done(sc_ipc_t ipc, sc_rsrc_t cpu) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_BOOT_DONE; RPC_U16(&msg, 0U) = (uint16_t)cpu; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_misc_otp_fuse_read(sc_ipc_t ipc, uint32_t word, uint32_t *val) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_OTP_FUSE_READ; RPC_U32(&msg, 0U) = (uint32_t)word; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); if (val != NULL) *val = RPC_U32(&msg, 0U); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_misc_otp_fuse_write(sc_ipc_t ipc, uint32_t word, uint32_t val) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_OTP_FUSE_WRITE; RPC_U32(&msg, 0U) = (uint32_t)word; RPC_U32(&msg, 4U) = (uint32_t)val; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_misc_set_temp(sc_ipc_t ipc, sc_rsrc_t resource, sc_misc_temp_t temp, int16_t celsius, int8_t tenths) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_SET_TEMP; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_I16(&msg, 2U) = (int16_t) celsius; RPC_U8(&msg, 4U) = (uint8_t)temp; RPC_I8(&msg, 5U) = (int8_t) tenths; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_misc_get_temp(sc_ipc_t ipc, sc_rsrc_t resource, sc_misc_temp_t temp, int16_t *celsius, int8_t *tenths) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_GET_TEMP; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_U8(&msg, 2U) = (uint8_t)temp; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); if (celsius != NULL) *celsius = RPC_I16(&msg, 0U); result = RPC_R8(&msg); if (tenths != NULL) *tenths = RPC_I8(&msg, 2U); return (sc_err_t)result; } void sc_misc_get_boot_dev(sc_ipc_t ipc, sc_rsrc_t *dev) { sc_rpc_msg_t msg; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_GET_BOOT_DEV; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); if (dev != NULL) *dev = RPC_U16(&msg, 0U); } void sc_misc_get_button_status(sc_ipc_t ipc, sc_bool_t *status) { sc_rpc_msg_t msg; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_MISC; RPC_FUNC(&msg) = (uint8_t)MISC_FUNC_GET_BUTTON_STATUS; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); if (status != NULL) *status = RPC_U8(&msg, 0U); } /**@}*/ trusted-firmware-a-2.2/plat/imx/common/sci/svc/misc/sci_misc_rpc.h000066400000000000000000000056551355360272700252630ustar00rootroot00000000000000/* * Copyright (C) 2016 Freescale Semiconductor, Inc. * Copyright 2017-2019 NXP * * SPDX-License-Identifier: BSD-3-Clause */ /*! * Header file for the MISC RPC implementation. * * @addtogroup MISC_SVC * @{ */ #ifndef SC_MISC_RPC_H #define SC_MISC_RPC_H /* Includes */ /* Defines */ /*! * @name Defines for RPC MISC function calls */ /*@{*/ #define MISC_FUNC_UNKNOWN 0 /* Unknown function */ #define MISC_FUNC_SET_CONTROL 1U /* Index for misc_set_control() RPC call */ #define MISC_FUNC_GET_CONTROL 2U /* Index for misc_get_control() RPC call */ #define MISC_FUNC_SET_MAX_DMA_GROUP 4U /* Index for misc_set_max_dma_group() RPC call */ #define MISC_FUNC_SET_DMA_GROUP 5U /* Index for misc_set_dma_group() RPC call */ #define MISC_FUNC_SECO_IMAGE_LOAD 8U /* Index for misc_seco_image_load() RPC call */ #define MISC_FUNC_SECO_AUTHENTICATE 9U /* Index for misc_seco_authenticate() RPC call */ #define MISC_FUNC_SECO_FUSE_WRITE 20U /* Index for misc_seco_fuse_write() RPC call */ #define MISC_FUNC_SECO_ENABLE_DEBUG 21U /* Index for misc_seco_enable_debug() RPC call */ #define MISC_FUNC_SECO_FORWARD_LIFECYCLE 22U /* Index for misc_seco_forward_lifecycle() RPC call */ #define MISC_FUNC_SECO_RETURN_LIFECYCLE 23U /* Index for misc_seco_return_lifecycle() RPC call */ #define MISC_FUNC_SECO_BUILD_INFO 24U /* Index for misc_seco_build_info() RPC call */ #define MISC_FUNC_SECO_CHIP_INFO 25U /* Index for misc_seco_chip_info() RPC call */ #define MISC_FUNC_DEBUG_OUT 10U /* Index for misc_debug_out() RPC call */ #define MISC_FUNC_WAVEFORM_CAPTURE 6U /* Index for misc_waveform_capture() RPC call */ #define MISC_FUNC_BUILD_INFO 15U /* Index for misc_build_info() RPC call */ #define MISC_FUNC_UNIQUE_ID 19U /* Index for misc_unique_id() RPC call */ #define MISC_FUNC_SET_ARI 3U /* Index for misc_set_ari() RPC call */ #define MISC_FUNC_BOOT_STATUS 7U /* Index for misc_boot_status() RPC call */ #define MISC_FUNC_BOOT_DONE 14U /* Index for misc_boot_done() RPC call */ #define MISC_FUNC_OTP_FUSE_READ 11U /* Index for misc_otp_fuse_read() RPC call */ #define MISC_FUNC_OTP_FUSE_WRITE 17U /* Index for misc_otp_fuse_write() RPC call */ #define MISC_FUNC_SET_TEMP 12U /* Index for misc_set_temp() RPC call */ #define MISC_FUNC_GET_TEMP 13U /* Index for misc_get_temp() RPC call */ #define MISC_FUNC_GET_BOOT_DEV 16U /* Index for misc_get_boot_dev() RPC call */ #define MISC_FUNC_GET_BUTTON_STATUS 18U /* Index for misc_get_button_status() RPC call */ /*@}*/ /* Types */ /* Functions */ /*! * This function dispatches an incoming MISC RPC request. * * @param[in] caller_pt caller partition * @param[in] msg pointer to RPC message */ void misc_dispatch(sc_rm_pt_t caller_pt, sc_rpc_msg_t *msg); /*! * This function translates and dispatches an MISC RPC request. * * @param[in] ipc IPC handle * @param[in] msg pointer to RPC message */ void misc_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg); #endif /* SC_MISC_RPC_H */ /**@}*/ trusted-firmware-a-2.2/plat/imx/common/sci/svc/pad/000077500000000000000000000000001355360272700222535ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/sci/svc/pad/pad_rpc_clnt.c000066400000000000000000000231341355360272700250520ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /*! * File containing client-side RPC functions for the PAD service. These * functions are ported to clients that communicate to the SC. * * @addtogroup PAD_SVC * @{ */ /* Includes */ #include #include #include #include #include #include "sci_pad_rpc.h" /* Local Defines */ /* Local Types */ /* Local Functions */ sc_err_t sc_pad_set_mux(sc_ipc_t ipc, sc_pad_t pad, uint8_t mux, sc_pad_config_t config, sc_pad_iso_t iso) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD; RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_MUX; RPC_U16(&msg, 0U) = (uint16_t)pad; RPC_U8(&msg, 2U) = (uint8_t)mux; RPC_U8(&msg, 3U) = (uint8_t)config; RPC_U8(&msg, 4U) = (uint8_t)iso; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pad_get_mux(sc_ipc_t ipc, sc_pad_t pad, uint8_t *mux, sc_pad_config_t *config, sc_pad_iso_t *iso) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD; RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_MUX; RPC_U16(&msg, 0U) = (uint16_t)pad; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); if (mux != NULL) { *mux = RPC_U8(&msg, 0U); } if (config != NULL) { *config = RPC_U8(&msg, 1U); } if (iso != NULL) { *iso = RPC_U8(&msg, 2U); } return (sc_err_t)result; } sc_err_t sc_pad_set_gp(sc_ipc_t ipc, sc_pad_t pad, uint32_t ctrl) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD; RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_GP; RPC_U32(&msg, 0U) = (uint32_t)ctrl; RPC_U16(&msg, 4U) = (uint16_t)pad; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pad_get_gp(sc_ipc_t ipc, sc_pad_t pad, uint32_t *ctrl) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD; RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_GP; RPC_U16(&msg, 0U) = (uint16_t)pad; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); if (ctrl != NULL) { *ctrl = RPC_U32(&msg, 0U); } result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pad_set_wakeup(sc_ipc_t ipc, sc_pad_t pad, sc_pad_wakeup_t wakeup) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD; RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_WAKEUP; RPC_U16(&msg, 0U) = (uint16_t)pad; RPC_U8(&msg, 2U) = (uint8_t)wakeup; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pad_get_wakeup(sc_ipc_t ipc, sc_pad_t pad, sc_pad_wakeup_t *wakeup) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD; RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_WAKEUP; RPC_U16(&msg, 0U) = (uint16_t)pad; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); if (wakeup != NULL) { *wakeup = RPC_U8(&msg, 0U); } return (sc_err_t)result; } sc_err_t sc_pad_set_all(sc_ipc_t ipc, sc_pad_t pad, uint8_t mux, sc_pad_config_t config, sc_pad_iso_t iso, uint32_t ctrl, sc_pad_wakeup_t wakeup) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD; RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_ALL; RPC_U32(&msg, 0U) = (uint32_t)ctrl; RPC_U16(&msg, 4U) = (uint16_t)pad; RPC_U8(&msg, 6U) = (uint8_t)mux; RPC_U8(&msg, 7U) = (uint8_t)config; RPC_U8(&msg, 8U) = (uint8_t)iso; RPC_U8(&msg, 9U) = (uint8_t)wakeup; RPC_SIZE(&msg) = 4U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pad_get_all(sc_ipc_t ipc, sc_pad_t pad, uint8_t *mux, sc_pad_config_t *config, sc_pad_iso_t *iso, uint32_t *ctrl, sc_pad_wakeup_t *wakeup) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD; RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_ALL; RPC_U16(&msg, 0U) = (uint16_t)pad; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); if (ctrl != NULL) { *ctrl = RPC_U32(&msg, 0U); } result = RPC_R8(&msg); if (mux != NULL) { *mux = RPC_U8(&msg, 4U); } if (config != NULL) { *config = RPC_U8(&msg, 5U); } if (iso != NULL) { *iso = RPC_U8(&msg, 6U); } if (wakeup != NULL) { *wakeup = RPC_U8(&msg, 7U); } return (sc_err_t)result; } sc_err_t sc_pad_set(sc_ipc_t ipc, sc_pad_t pad, uint32_t val) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD; RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET; RPC_U32(&msg, 0U) = (uint32_t)val; RPC_U16(&msg, 4U) = (uint16_t)pad; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pad_get(sc_ipc_t ipc, sc_pad_t pad, uint32_t *val) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD; RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET; RPC_U16(&msg, 0U) = (uint16_t)pad; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); if (val != NULL) { *val = RPC_U32(&msg, 0U); } result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pad_set_gp_28fdsoi(sc_ipc_t ipc, sc_pad_t pad, sc_pad_28fdsoi_dse_t dse, sc_pad_28fdsoi_ps_t ps) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD; RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_GP_28FDSOI; RPC_U16(&msg, 0U) = (uint16_t)pad; RPC_U8(&msg, 2U) = (uint8_t)dse; RPC_U8(&msg, 3U) = (uint8_t)ps; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pad_get_gp_28fdsoi(sc_ipc_t ipc, sc_pad_t pad, sc_pad_28fdsoi_dse_t *dse, sc_pad_28fdsoi_ps_t *ps) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD; RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_GP_28FDSOI; RPC_U16(&msg, 0U) = (uint16_t)pad; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); if (dse != NULL) { *dse = RPC_U8(&msg, 0U); } if (ps != NULL) { *ps = RPC_U8(&msg, 1U); } return (sc_err_t)result; } sc_err_t sc_pad_set_gp_28fdsoi_hsic(sc_ipc_t ipc, sc_pad_t pad, sc_pad_28fdsoi_dse_t dse, sc_bool_t hys, sc_pad_28fdsoi_pus_t pus, sc_bool_t pke, sc_bool_t pue) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD; RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_GP_28FDSOI_HSIC; RPC_U16(&msg, 0U) = (uint16_t)pad; RPC_U8(&msg, 2U) = (uint8_t)dse; RPC_U8(&msg, 3U) = (uint8_t)pus; RPC_U8(&msg, 4U) = (uint8_t)hys; RPC_U8(&msg, 5U) = (uint8_t)pke; RPC_U8(&msg, 6U) = (uint8_t)pue; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pad_get_gp_28fdsoi_hsic(sc_ipc_t ipc, sc_pad_t pad, sc_pad_28fdsoi_dse_t *dse, sc_bool_t *hys, sc_pad_28fdsoi_pus_t *pus, sc_bool_t *pke, sc_bool_t *pue) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD; RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_GP_28FDSOI_HSIC; RPC_U16(&msg, 0U) = (uint16_t)pad; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); if (dse != NULL) { *dse = RPC_U8(&msg, 0U); } if (pus != NULL) { *pus = RPC_U8(&msg, 1U); } if (hys != NULL) { *hys = RPC_U8(&msg, 2U); } if (pke != NULL) { *pke = RPC_U8(&msg, 3U); } if (pue != NULL) { *pue = RPC_U8(&msg, 4U); } return (sc_err_t)result; } sc_err_t sc_pad_set_gp_28fdsoi_comp(sc_ipc_t ipc, sc_pad_t pad, uint8_t compen, sc_bool_t fastfrz, uint8_t rasrcp, uint8_t rasrcn, sc_bool_t nasrc_sel, sc_bool_t psw_ovr) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD; RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_SET_GP_28FDSOI_COMP; RPC_U16(&msg, 0U) = (uint16_t)pad; RPC_U8(&msg, 2U) = (uint8_t)compen; RPC_U8(&msg, 3U) = (uint8_t)rasrcp; RPC_U8(&msg, 4U) = (uint8_t)rasrcn; RPC_U8(&msg, 5U) = (uint8_t)fastfrz; RPC_U8(&msg, 6U) = (uint8_t)nasrc_sel; RPC_U8(&msg, 7U) = (uint8_t)psw_ovr; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pad_get_gp_28fdsoi_comp(sc_ipc_t ipc, sc_pad_t pad, uint8_t *compen, sc_bool_t *fastfrz, uint8_t *rasrcp, uint8_t *rasrcn, sc_bool_t *nasrc_sel, sc_bool_t *compok, uint8_t *nasrc, sc_bool_t *psw_ovr) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PAD; RPC_FUNC(&msg) = (uint8_t)PAD_FUNC_GET_GP_28FDSOI_COMP; RPC_U16(&msg, 0U) = (uint16_t)pad; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); if (compen != NULL) { *compen = RPC_U8(&msg, 0U); } if (rasrcp != NULL) { *rasrcp = RPC_U8(&msg, 1U); } if (rasrcn != NULL) { *rasrcn = RPC_U8(&msg, 2U); } if (nasrc != NULL) { *nasrc = RPC_U8(&msg, 3U); } if (fastfrz != NULL) { *fastfrz = RPC_U8(&msg, 4U); } if (nasrc_sel != NULL) { *nasrc_sel = RPC_U8(&msg, 5U); } if (compok != NULL) { *compok = RPC_U8(&msg, 6U); } if (psw_ovr != NULL) { *psw_ovr = RPC_U8(&msg, 7U); } return (sc_err_t)result; } /**@}*/ trusted-firmware-a-2.2/plat/imx/common/sci/svc/pad/sci_pad_rpc.h000066400000000000000000000041101355360272700246660ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /*! * Header file for the PAD RPC implementation. * * @addtogroup PAD_SVC * @{ */ #ifndef SCI_PAD_RPC_H #define SCI_PAD_RPC_H /* Includes */ /* Defines */ /*! * @name Defines for RPC PAD function calls */ /*@{*/ #define PAD_FUNC_UNKNOWN 0 /* Unknown function */ #define PAD_FUNC_SET_MUX 1U /* Index for pad_set_mux() RPC call */ #define PAD_FUNC_GET_MUX 6U /* Index for pad_get_mux() RPC call */ #define PAD_FUNC_SET_GP 2U /* Index for pad_set_gp() RPC call */ #define PAD_FUNC_GET_GP 7U /* Index for pad_get_gp() RPC call */ #define PAD_FUNC_SET_WAKEUP 4U /* Index for pad_set_wakeup() RPC call */ #define PAD_FUNC_GET_WAKEUP 9U /* Index for pad_get_wakeup() RPC call */ #define PAD_FUNC_SET_ALL 5U /* Index for pad_set_all() RPC call */ #define PAD_FUNC_GET_ALL 10U /* Index for pad_get_all() RPC call */ #define PAD_FUNC_SET 15U /* Index for pad_set() RPC call */ #define PAD_FUNC_GET 16U /* Index for pad_get() RPC call */ #define PAD_FUNC_SET_GP_28FDSOI 11U /* Index for pad_set_gp_28fdsoi() RPC call */ #define PAD_FUNC_GET_GP_28FDSOI 12U /* Index for pad_get_gp_28fdsoi() RPC call */ #define PAD_FUNC_SET_GP_28FDSOI_HSIC 3U /* Index for pad_set_gp_28fdsoi_hsic() RPC call */ #define PAD_FUNC_GET_GP_28FDSOI_HSIC 8U /* Index for pad_get_gp_28fdsoi_hsic() RPC call */ #define PAD_FUNC_SET_GP_28FDSOI_COMP 13U /* Index for pad_set_gp_28fdsoi_comp() RPC call */ #define PAD_FUNC_GET_GP_28FDSOI_COMP 14U /* Index for pad_get_gp_28fdsoi_comp() RPC call */ /*@}*/ /* Types */ /* Functions */ /*! * This function dispatches an incoming PAD RPC request. * * @param[in] caller_pt caller partition * @param[in] msg pointer to RPC message */ void pad_dispatch(sc_rm_pt_t caller_pt, sc_rpc_msg_t *msg); /*! * This function translates and dispatches an PAD RPC request. * * @param[in] ipc IPC handle * @param[in] msg pointer to RPC message */ void pad_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg); #endif /* SCI_PAD_RPC_H */ /**@}*/ trusted-firmware-a-2.2/plat/imx/common/sci/svc/pm/000077500000000000000000000000001355360272700221235ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/sci/svc/pm/pm_rpc_clnt.c000066400000000000000000000251271355360272700245760ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /*! * File containing client-side RPC functions for the PM service. These * functions are ported to clients that communicate to the SC. * * @addtogroup PM_SVC * @{ */ /* Includes */ #include #include #include #include #include #include "sci_pm_rpc.h" /* Local Defines */ /* Local Types */ /* Local Functions */ sc_err_t sc_pm_set_sys_power_mode(sc_ipc_t ipc, sc_pm_power_mode_t mode) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_SYS_POWER_MODE; RPC_U8(&msg, 0U) = (uint8_t)mode; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pm_set_partition_power_mode(sc_ipc_t ipc, sc_rm_pt_t pt, sc_pm_power_mode_t mode) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_PARTITION_POWER_MODE; RPC_U8(&msg, 0U) = (uint8_t)pt; RPC_U8(&msg, 1U) = (uint8_t)mode; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pm_get_sys_power_mode(sc_ipc_t ipc, sc_rm_pt_t pt, sc_pm_power_mode_t *mode) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_GET_SYS_POWER_MODE; RPC_U8(&msg, 0U) = (uint8_t)pt; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); if (mode != NULL) { *mode = RPC_U8(&msg, 0U); } return (sc_err_t)result; } sc_err_t sc_pm_set_resource_power_mode(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_power_mode_t mode) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_RESOURCE_POWER_MODE; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_U8(&msg, 2U) = (uint8_t)mode; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pm_get_resource_power_mode(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_power_mode_t *mode) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_GET_RESOURCE_POWER_MODE; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); if (mode != NULL) { *mode = RPC_U8(&msg, 0U); } return (sc_err_t)result; } sc_err_t sc_pm_req_low_power_mode(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_power_mode_t mode) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_REQ_LOW_POWER_MODE; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_U8(&msg, 2U) = (uint8_t)mode; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pm_req_cpu_low_power_mode(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_power_mode_t mode, sc_pm_wake_src_t wake_src) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_REQ_CPU_LOW_POWER_MODE; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_U8(&msg, 2U) = (uint8_t)mode; RPC_U8(&msg, 3U) = (uint8_t)wake_src; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pm_set_cpu_resume_addr(sc_ipc_t ipc, sc_rsrc_t resource, sc_faddr_t address) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_CPU_RESUME_ADDR; RPC_U32(&msg, 0U) = (uint32_t)(address >> 32U); RPC_U32(&msg, 4U) = (uint32_t)address; RPC_U16(&msg, 8U) = (uint16_t)resource; RPC_SIZE(&msg) = 4U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pm_set_cpu_resume(sc_ipc_t ipc, sc_rsrc_t resource, sc_bool_t isPrimary, sc_faddr_t address) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_CPU_RESUME; RPC_U32(&msg, 0U) = (uint32_t)(address >> 32U); RPC_U32(&msg, 4U) = (uint32_t)address; RPC_U16(&msg, 8U) = (uint16_t)resource; RPC_U8(&msg, 10U) = (uint8_t)isPrimary; RPC_SIZE(&msg) = 4U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pm_req_sys_if_power_mode(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_sys_if_t sys_if, sc_pm_power_mode_t hpm, sc_pm_power_mode_t lpm) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_REQ_SYS_IF_POWER_MODE; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_U8(&msg, 2U) = (uint8_t)sys_if; RPC_U8(&msg, 3U) = (uint8_t)hpm; RPC_U8(&msg, 4U) = (uint8_t)lpm; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pm_set_clock_rate(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_clk_t clk, sc_pm_clock_rate_t *rate) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_CLOCK_RATE; RPC_U32(&msg, 0U) = *(uint32_t *)rate; RPC_U16(&msg, 4U) = (uint16_t)resource; RPC_U8(&msg, 6U) = (uint8_t)clk; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); *rate = RPC_U32(&msg, 0U); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pm_get_clock_rate(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_clk_t clk, sc_pm_clock_rate_t *rate) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_GET_CLOCK_RATE; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_U8(&msg, 2U) = (uint8_t)clk; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); if (rate != NULL) { *rate = RPC_U32(&msg, 0U); } result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pm_clock_enable(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_clk_t clk, sc_bool_t enable, sc_bool_t autog) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_CLOCK_ENABLE; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_U8(&msg, 2U) = (uint8_t)clk; RPC_U8(&msg, 3U) = (uint8_t)enable; RPC_U8(&msg, 4U) = (uint8_t)autog; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pm_set_clock_parent(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_clk_t clk, sc_pm_clk_parent_t parent) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_SET_CLOCK_PARENT; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_U8(&msg, 2U) = (uint8_t)clk; RPC_U8(&msg, 3U) = (uint8_t)parent; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pm_get_clock_parent(sc_ipc_t ipc, sc_rsrc_t resource, sc_pm_clk_t clk, sc_pm_clk_parent_t *parent) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_GET_CLOCK_PARENT; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_U8(&msg, 2U) = (uint8_t)clk; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); if (parent != NULL) { *parent = RPC_U8(&msg, 0U); } return (sc_err_t)result; } sc_err_t sc_pm_reset(sc_ipc_t ipc, sc_pm_reset_type_t type) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_RESET; RPC_U8(&msg, 0U) = (uint8_t)type; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pm_reset_reason(sc_ipc_t ipc, sc_pm_reset_reason_t *reason) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_RESET_REASON; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); if (reason != NULL) { *reason = RPC_U8(&msg, 0U); } return (sc_err_t)result; } sc_err_t sc_pm_boot(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rsrc_t resource_cpu, sc_faddr_t boot_addr, sc_rsrc_t resource_mu, sc_rsrc_t resource_dev) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_BOOT; RPC_U32(&msg, 0U) = (uint32_t)(boot_addr >> 32U); RPC_U32(&msg, 4U) = (uint32_t)boot_addr; RPC_U16(&msg, 8U) = (uint16_t)resource_cpu; RPC_U16(&msg, 10U) = (uint16_t)resource_mu; RPC_U16(&msg, 12U) = (uint16_t)resource_dev; RPC_U8(&msg, 14U) = (uint8_t)pt; RPC_SIZE(&msg) = 5U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } void sc_pm_reboot(sc_ipc_t ipc, sc_pm_reset_type_t type) { sc_rpc_msg_t msg; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_REBOOT; RPC_U8(&msg, 0U) = (uint8_t)type; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_TRUE); return; } sc_err_t sc_pm_reboot_partition(sc_ipc_t ipc, sc_rm_pt_t pt, sc_pm_reset_type_t type) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_REBOOT_PARTITION; RPC_U8(&msg, 0U) = (uint8_t)pt; RPC_U8(&msg, 1U) = (uint8_t)type; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_pm_cpu_start(sc_ipc_t ipc, sc_rsrc_t resource, sc_bool_t enable, sc_faddr_t address) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_PM; RPC_FUNC(&msg) = (uint8_t)PM_FUNC_CPU_START; RPC_U32(&msg, 0U) = (uint32_t)(address >> 32U); RPC_U32(&msg, 4U) = (uint32_t)address; RPC_U16(&msg, 8U) = (uint16_t)resource; RPC_U8(&msg, 10U) = (uint8_t)enable; RPC_SIZE(&msg) = 4U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } /**@}*/ trusted-firmware-a-2.2/plat/imx/common/sci/svc/pm/sci_pm_rpc.h000066400000000000000000000051261355360272700244160ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /*! * Header file for the PM RPC implementation. * * @addtogroup PM_SVC * @{ */ #ifndef SCI_PM_RPC_H #define SCI_PM_RPC_H /* Includes */ /* Defines */ /*! * @name Defines for RPC PM function calls */ /*@{*/ #define PM_FUNC_UNKNOWN 0 /* Unknown function */ #define PM_FUNC_SET_SYS_POWER_MODE 19U /* Index for pm_set_sys_power_mode() RPC call */ #define PM_FUNC_SET_PARTITION_POWER_MODE 1U /* Index for pm_set_partition_power_mode() RPC call */ #define PM_FUNC_GET_SYS_POWER_MODE 2U /* Index for pm_get_sys_power_mode() RPC call */ #define PM_FUNC_SET_RESOURCE_POWER_MODE 3U /* Index for pm_set_resource_power_mode() RPC call */ #define PM_FUNC_GET_RESOURCE_POWER_MODE 4U /* Index for pm_get_resource_power_mode() RPC call */ #define PM_FUNC_REQ_LOW_POWER_MODE 16U /* Index for pm_req_low_power_mode() RPC call */ #define PM_FUNC_REQ_CPU_LOW_POWER_MODE 20U /* Index for pm_req_cpu_low_power_mode() RPC call */ #define PM_FUNC_SET_CPU_RESUME_ADDR 17U /* Index for pm_set_cpu_resume_addr() RPC call */ #define PM_FUNC_SET_CPU_RESUME 21U /* Index for pm_set_cpu_resume() RPC call */ #define PM_FUNC_REQ_SYS_IF_POWER_MODE 18U /* Index for pm_req_sys_if_power_mode() RPC call */ #define PM_FUNC_SET_CLOCK_RATE 5U /* Index for pm_set_clock_rate() RPC call */ #define PM_FUNC_GET_CLOCK_RATE 6U /* Index for pm_get_clock_rate() RPC call */ #define PM_FUNC_CLOCK_ENABLE 7U /* Index for pm_clock_enable() RPC call */ #define PM_FUNC_SET_CLOCK_PARENT 14U /* Index for pm_set_clock_parent() RPC call */ #define PM_FUNC_GET_CLOCK_PARENT 15U /* Index for pm_get_clock_parent() RPC call */ #define PM_FUNC_RESET 13U /* Index for pm_reset() RPC call */ #define PM_FUNC_RESET_REASON 10U /* Index for pm_reset_reason() RPC call */ #define PM_FUNC_BOOT 8U /* Index for pm_boot() RPC call */ #define PM_FUNC_REBOOT 9U /* Index for pm_reboot() RPC call */ #define PM_FUNC_REBOOT_PARTITION 12U /* Index for pm_reboot_partition() RPC call */ #define PM_FUNC_CPU_START 11U /* Index for pm_cpu_start() RPC call */ /*@}*/ /* Types */ /* Functions */ /*! * This function dispatches an incoming PM RPC request. * * @param[in] caller_pt caller partition * @param[in] msg pointer to RPC message */ void pm_dispatch(sc_rm_pt_t caller_pt, sc_rpc_msg_t *msg); /*! * This function translates and dispatches an PM RPC request. * * @param[in] ipc IPC handle * @param[in] msg pointer to RPC message */ void pm_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg); #endif /* SCI_PM_RPC_H */ /**@}*/ trusted-firmware-a-2.2/plat/imx/common/sci/svc/rm/000077500000000000000000000000001355360272700221255ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/sci/svc/rm/rm_rpc_clnt.c000066400000000000000000000347171355360272700246070ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /*! * File containing client-side RPC functions for the RM service. These * functions are ported to clients that communicate to the SC. * * @addtogroup RM_SVC * @{ */ /* Includes */ #include #include #include #include #include "sci_rm_rpc.h" /* Local Defines */ /* Local Types */ /* Local Functions */ sc_err_t sc_rm_partition_alloc(sc_ipc_t ipc, sc_rm_pt_t *pt, sc_bool_t secure, sc_bool_t isolated, sc_bool_t restricted, sc_bool_t grant, sc_bool_t coherent) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_PARTITION_ALLOC; RPC_U8(&msg, 0U) = (uint8_t)secure; RPC_U8(&msg, 1U) = (uint8_t)isolated; RPC_U8(&msg, 2U) = (uint8_t)restricted; RPC_U8(&msg, 3U) = (uint8_t)grant; RPC_U8(&msg, 4U) = (uint8_t)coherent; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); if (pt != NULL) { *pt = RPC_U8(&msg, 0U); } return (sc_err_t)result; } sc_err_t sc_rm_set_confidential(sc_ipc_t ipc, sc_rm_pt_t pt, sc_bool_t retro) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_CONFIDENTIAL; RPC_U8(&msg, 0U) = (uint8_t)pt; RPC_U8(&msg, 1U) = (uint8_t)retro; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_rm_partition_free(sc_ipc_t ipc, sc_rm_pt_t pt) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_PARTITION_FREE; RPC_U8(&msg, 0U) = (uint8_t)pt; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_rm_did_t sc_rm_get_did(sc_ipc_t ipc) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_GET_DID; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_rm_did_t) result; } sc_err_t sc_rm_partition_static(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rm_did_t did) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_PARTITION_STATIC; RPC_U8(&msg, 0U) = (uint8_t)pt; RPC_U8(&msg, 1U) = (uint8_t)did; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_rm_partition_lock(sc_ipc_t ipc, sc_rm_pt_t pt) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_PARTITION_LOCK; RPC_U8(&msg, 0U) = (uint8_t)pt; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_rm_get_partition(sc_ipc_t ipc, sc_rm_pt_t *pt) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_GET_PARTITION; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); if (pt != NULL) { *pt = RPC_U8(&msg, 0U); } return (sc_err_t)result; } sc_err_t sc_rm_set_parent(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rm_pt_t pt_parent) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_PARENT; RPC_U8(&msg, 0U) = (uint8_t)pt; RPC_U8(&msg, 1U) = (uint8_t)pt_parent; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_rm_move_all(sc_ipc_t ipc, sc_rm_pt_t pt_src, sc_rm_pt_t pt_dst, sc_bool_t move_rsrc, sc_bool_t move_pads) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_MOVE_ALL; RPC_U8(&msg, 0U) = (uint8_t)pt_src; RPC_U8(&msg, 1U) = (uint8_t)pt_dst; RPC_U8(&msg, 2U) = (uint8_t)move_rsrc; RPC_U8(&msg, 3U) = (uint8_t)move_pads; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_rm_assign_resource(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rsrc_t resource) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_ASSIGN_RESOURCE; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_U8(&msg, 2U) = (uint8_t)pt; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_rm_set_resource_movable(sc_ipc_t ipc, sc_rsrc_t resource_fst, sc_rsrc_t resource_lst, sc_bool_t movable) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_RESOURCE_MOVABLE; RPC_U16(&msg, 0U) = (uint16_t)resource_fst; RPC_U16(&msg, 2U) = (uint16_t)resource_lst; RPC_U8(&msg, 4U) = (uint8_t)movable; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_rm_set_subsys_rsrc_movable(sc_ipc_t ipc, sc_rsrc_t resource, sc_bool_t movable) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_SUBSYS_RSRC_MOVABLE; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_U8(&msg, 2U) = (uint8_t)movable; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_rm_set_master_attributes(sc_ipc_t ipc, sc_rsrc_t resource, sc_rm_spa_t sa, sc_rm_spa_t pa, sc_bool_t smmu_bypass) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_MASTER_ATTRIBUTES; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_U8(&msg, 2U) = (uint8_t)sa; RPC_U8(&msg, 3U) = (uint8_t)pa; RPC_U8(&msg, 4U) = (uint8_t)smmu_bypass; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_rm_set_master_sid(sc_ipc_t ipc, sc_rsrc_t resource, sc_rm_sid_t sid) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_MASTER_SID; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_U16(&msg, 2U) = (uint16_t)sid; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_rm_set_peripheral_permissions(sc_ipc_t ipc, sc_rsrc_t resource, sc_rm_pt_t pt, sc_rm_perm_t perm) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_PERIPHERAL_PERMISSIONS; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_U8(&msg, 2U) = (uint8_t)pt; RPC_U8(&msg, 3U) = (uint8_t)perm; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_bool_t sc_rm_is_resource_owned(sc_ipc_t ipc, sc_rsrc_t resource) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_IS_RESOURCE_OWNED; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_bool_t)result; } sc_bool_t sc_rm_is_resource_master(sc_ipc_t ipc, sc_rsrc_t resource) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_IS_RESOURCE_MASTER; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_bool_t)result; } sc_bool_t sc_rm_is_resource_peripheral(sc_ipc_t ipc, sc_rsrc_t resource) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_IS_RESOURCE_PERIPHERAL; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_bool_t)result; } sc_err_t sc_rm_get_resource_info(sc_ipc_t ipc, sc_rsrc_t resource, sc_rm_sid_t *sid) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_GET_RESOURCE_INFO; RPC_U16(&msg, 0U) = (uint16_t)resource; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); if (sid != NULL) { *sid = RPC_U16(&msg, 0U); } result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_rm_memreg_alloc(sc_ipc_t ipc, sc_rm_mr_t *mr, sc_faddr_t addr_start, sc_faddr_t addr_end) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_MEMREG_ALLOC; RPC_U32(&msg, 0U) = (uint32_t)(addr_start >> 32U); RPC_U32(&msg, 4U) = (uint32_t)addr_start; RPC_U32(&msg, 8U) = (uint32_t)(addr_end >> 32U); RPC_U32(&msg, 12U) = (uint32_t)addr_end; RPC_SIZE(&msg) = 5U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); if (mr != NULL) { *mr = RPC_U8(&msg, 0U); } return (sc_err_t)result; } sc_err_t sc_rm_memreg_split(sc_ipc_t ipc, sc_rm_mr_t mr, sc_rm_mr_t *mr_ret, sc_faddr_t addr_start, sc_faddr_t addr_end) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_MEMREG_SPLIT; RPC_U32(&msg, 0U) = (uint32_t)(addr_start >> 32U); RPC_U32(&msg, 4U) = (uint32_t)addr_start; RPC_U32(&msg, 8U) = (uint32_t)(addr_end >> 32U); RPC_U32(&msg, 12U) = (uint32_t)addr_end; RPC_U8(&msg, 16U) = (uint8_t)mr; RPC_SIZE(&msg) = 6U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); if (mr_ret != NULL) { *mr_ret = RPC_U8(&msg, 0U); } return (sc_err_t)result; } sc_err_t sc_rm_memreg_free(sc_ipc_t ipc, sc_rm_mr_t mr) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_MEMREG_FREE; RPC_U8(&msg, 0U) = (uint8_t)mr; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_rm_find_memreg(sc_ipc_t ipc, sc_rm_mr_t *mr, sc_faddr_t addr_start, sc_faddr_t addr_end) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_FIND_MEMREG; RPC_U32(&msg, 0U) = (uint32_t)(addr_start >> 32U); RPC_U32(&msg, 4U) = (uint32_t)addr_start; RPC_U32(&msg, 8U) = (uint32_t)(addr_end >> 32U); RPC_U32(&msg, 12U) = (uint32_t)addr_end; RPC_SIZE(&msg) = 5U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); if (mr != NULL) { *mr = RPC_U8(&msg, 0U); } return (sc_err_t)result; } sc_err_t sc_rm_assign_memreg(sc_ipc_t ipc, sc_rm_pt_t pt, sc_rm_mr_t mr) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_ASSIGN_MEMREG; RPC_U8(&msg, 0U) = (uint8_t)pt; RPC_U8(&msg, 1U) = (uint8_t)mr; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_rm_set_memreg_permissions(sc_ipc_t ipc, sc_rm_mr_t mr, sc_rm_pt_t pt, sc_rm_perm_t perm) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_MEMREG_PERMISSIONS; RPC_U8(&msg, 0U) = (uint8_t)mr; RPC_U8(&msg, 1U) = (uint8_t)pt; RPC_U8(&msg, 2U) = (uint8_t)perm; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_bool_t sc_rm_is_memreg_owned(sc_ipc_t ipc, sc_rm_mr_t mr) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_IS_MEMREG_OWNED; RPC_U8(&msg, 0U) = (uint8_t)mr; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_bool_t)result; } sc_err_t sc_rm_get_memreg_info(sc_ipc_t ipc, sc_rm_mr_t mr, sc_faddr_t *addr_start, sc_faddr_t *addr_end) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_GET_MEMREG_INFO; RPC_U8(&msg, 0U) = (uint8_t)mr; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); if (addr_start != NULL) { *addr_start = ((uint64_t) RPC_U32(&msg, 0U) << 32U) | RPC_U32(&msg, 4U); } if (addr_end != NULL) { *addr_end = ((uint64_t) RPC_U32(&msg, 8U) << 32U) | RPC_U32(&msg, 12U); } result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_rm_assign_pad(sc_ipc_t ipc, sc_rm_pt_t pt, sc_pad_t pad) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_ASSIGN_PAD; RPC_U16(&msg, 0U) = (uint16_t)pad; RPC_U8(&msg, 2U) = (uint8_t)pt; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_rm_set_pad_movable(sc_ipc_t ipc, sc_pad_t pad_fst, sc_pad_t pad_lst, sc_bool_t movable) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_SET_PAD_MOVABLE; RPC_U16(&msg, 0U) = (uint16_t)pad_fst; RPC_U16(&msg, 2U) = (uint16_t)pad_lst; RPC_U8(&msg, 4U) = (uint8_t)movable; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_bool_t sc_rm_is_pad_owned(sc_ipc_t ipc, sc_pad_t pad) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_IS_PAD_OWNED; RPC_U8(&msg, 0U) = (uint8_t)pad; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_bool_t)result; } void sc_rm_dump(sc_ipc_t ipc) { sc_rpc_msg_t msg; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_RM; RPC_FUNC(&msg) = (uint8_t)RM_FUNC_DUMP; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); return; } /**@}*/ trusted-firmware-a-2.2/plat/imx/common/sci/svc/rm/sci_rm_rpc.h000066400000000000000000000065511355360272700244250ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /*! * Header file for the RM RPC implementation. * * @addtogroup RM_SVC * @{ */ #ifndef SCI_RM_RPC_H #define SCI_RM_RPC_H /* Includes */ /* Defines */ /*! * @name Defines for RPC RM function calls */ /*@{*/ #define RM_FUNC_UNKNOWN 0 /* Unknown function */ #define RM_FUNC_PARTITION_ALLOC 1U /* Index for rm_partition_alloc() RPC call */ #define RM_FUNC_SET_CONFIDENTIAL 31U /* Index for rm_set_confidential() RPC call */ #define RM_FUNC_PARTITION_FREE 2U /* Index for rm_partition_free() RPC call */ #define RM_FUNC_GET_DID 26U /* Index for rm_get_did() RPC call */ #define RM_FUNC_PARTITION_STATIC 3U /* Index for rm_partition_static() RPC call */ #define RM_FUNC_PARTITION_LOCK 4U /* Index for rm_partition_lock() RPC call */ #define RM_FUNC_GET_PARTITION 5U /* Index for rm_get_partition() RPC call */ #define RM_FUNC_SET_PARENT 6U /* Index for rm_set_parent() RPC call */ #define RM_FUNC_MOVE_ALL 7U /* Index for rm_move_all() RPC call */ #define RM_FUNC_ASSIGN_RESOURCE 8U /* Index for rm_assign_resource() RPC call */ #define RM_FUNC_SET_RESOURCE_MOVABLE 9U /* Index for rm_set_resource_movable() RPC call */ #define RM_FUNC_SET_SUBSYS_RSRC_MOVABLE 28U /* Index for rm_set_subsys_rsrc_movable() RPC call */ #define RM_FUNC_SET_MASTER_ATTRIBUTES 10U /* Index for rm_set_master_attributes() RPC call */ #define RM_FUNC_SET_MASTER_SID 11U /* Index for rm_set_master_sid() RPC call */ #define RM_FUNC_SET_PERIPHERAL_PERMISSIONS 12U /* Index for rm_set_peripheral_permissions() RPC call */ #define RM_FUNC_IS_RESOURCE_OWNED 13U /* Index for rm_is_resource_owned() RPC call */ #define RM_FUNC_IS_RESOURCE_MASTER 14U /* Index for rm_is_resource_master() RPC call */ #define RM_FUNC_IS_RESOURCE_PERIPHERAL 15U /* Index for rm_is_resource_peripheral() RPC call */ #define RM_FUNC_GET_RESOURCE_INFO 16U /* Index for rm_get_resource_info() RPC call */ #define RM_FUNC_MEMREG_ALLOC 17U /* Index for rm_memreg_alloc() RPC call */ #define RM_FUNC_MEMREG_SPLIT 29U /* Index for rm_memreg_split() RPC call */ #define RM_FUNC_MEMREG_FREE 18U /* Index for rm_memreg_free() RPC call */ #define RM_FUNC_FIND_MEMREG 30U /* Index for rm_find_memreg() RPC call */ #define RM_FUNC_ASSIGN_MEMREG 19U /* Index for rm_assign_memreg() RPC call */ #define RM_FUNC_SET_MEMREG_PERMISSIONS 20U /* Index for rm_set_memreg_permissions() RPC call */ #define RM_FUNC_IS_MEMREG_OWNED 21U /* Index for rm_is_memreg_owned() RPC call */ #define RM_FUNC_GET_MEMREG_INFO 22U /* Index for rm_get_memreg_info() RPC call */ #define RM_FUNC_ASSIGN_PAD 23U /* Index for rm_assign_pad() RPC call */ #define RM_FUNC_SET_PAD_MOVABLE 24U /* Index for rm_set_pad_movable() RPC call */ #define RM_FUNC_IS_PAD_OWNED 25U /* Index for rm_is_pad_owned() RPC call */ #define RM_FUNC_DUMP 27U /* Index for rm_dump() RPC call */ /*@}*/ /* Types */ /* Functions */ /*! * This function dispatches an incoming RM RPC request. * * @param[in] caller_pt caller partition * @param[in] msg pointer to RPC message */ void rm_dispatch(sc_rm_pt_t caller_pt, sc_rpc_msg_t *msg); /*! * This function translates and dispatches an RM RPC request. * * @param[in] ipc IPC handle * @param[in] msg pointer to RPC message */ void rm_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg); #endif /* SCI_RM_RPC_H */ /**@}*/ trusted-firmware-a-2.2/plat/imx/common/sci/svc/timer/000077500000000000000000000000001355360272700226275ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/common/sci/svc/timer/sci_timer_rpc.h000066400000000000000000000047421355360272700256310ustar00rootroot00000000000000/* * Copyright (C) 2016 Freescale Semiconductor, Inc. * Copyright 2017-2019 NXP * * SPDX-License-Identifier: BSD-3-Clause */ /*! * Header file for the TIMER RPC implementation. * * @addtogroup TIMER_SVC * @{ */ #ifndef SC_TIMER_RPC_H #define SC_TIMER_RPC_H /* Includes */ /* Defines */ /*! * @name Defines for RPC TIMER function calls */ /*@{*/ #define TIMER_FUNC_UNKNOWN 0 /* Unknown function */ #define TIMER_FUNC_SET_WDOG_TIMEOUT 1U /* Index for timer_set_wdog_timeout() RPC call */ #define TIMER_FUNC_SET_WDOG_PRE_TIMEOUT 12U /* Index for timer_set_wdog_pre_timeout() RPC call */ #define TIMER_FUNC_START_WDOG 2U /* Index for timer_start_wdog() RPC call */ #define TIMER_FUNC_STOP_WDOG 3U /* Index for timer_stop_wdog() RPC call */ #define TIMER_FUNC_PING_WDOG 4U /* Index for timer_ping_wdog() RPC call */ #define TIMER_FUNC_GET_WDOG_STATUS 5U /* Index for timer_get_wdog_status() RPC call */ #define TIMER_FUNC_PT_GET_WDOG_STATUS 13U /* Index for timer_pt_get_wdog_status() RPC call */ #define TIMER_FUNC_SET_WDOG_ACTION 10U /* Index for timer_set_wdog_action() RPC call */ #define TIMER_FUNC_SET_RTC_TIME 6U /* Index for timer_set_rtc_time() RPC call */ #define TIMER_FUNC_GET_RTC_TIME 7U /* Index for timer_get_rtc_time() RPC call */ #define TIMER_FUNC_GET_RTC_SEC1970 9U /* Index for timer_get_rtc_sec1970() RPC call */ #define TIMER_FUNC_SET_RTC_ALARM 8U /* Index for timer_set_rtc_alarm() RPC call */ #define TIMER_FUNC_SET_RTC_PERIODIC_ALARM 14U /* Index for timer_set_rtc_periodic_alarm() RPC call */ #define TIMER_FUNC_CANCEL_RTC_ALARM 15U /* Index for timer_cancel_rtc_alarm() RPC call */ #define TIMER_FUNC_SET_RTC_CALB 11U /* Index for timer_set_rtc_calb() RPC call */ #define TIMER_FUNC_SET_SYSCTR_ALARM 16U /* Index for timer_set_sysctr_alarm() RPC call */ #define TIMER_FUNC_SET_SYSCTR_PERIODIC_ALARM 17U /* Index for timer_set_sysctr_periodic_alarm() RPC call */ #define TIMER_FUNC_CANCEL_SYSCTR_ALARM 18U /* Index for timer_cancel_sysctr_alarm() RPC call */ /*@}*/ /* Types */ /* Functions */ /*! * This function dispatches an incoming TIMER RPC request. * * @param[in] caller_pt caller partition * @param[in] msg pointer to RPC message */ void timer_dispatch(sc_rm_pt_t caller_pt, sc_rpc_msg_t *msg); /*! * This function translates and dispatches an TIMER RPC request. * * @param[in] ipc IPC handle * @param[in] msg pointer to RPC message */ void timer_xlate(sc_ipc_t ipc, sc_rpc_msg_t *msg); #endif /* SC_TIMER_RPC_H */ /**@}*/ trusted-firmware-a-2.2/plat/imx/common/sci/svc/timer/timer_rpc_clnt.c000066400000000000000000000212451355360272700260030ustar00rootroot00000000000000/* * Copyright (C) 2016 Freescale Semiconductor, Inc. * Copyright 2017-2019 NXP * * SPDX-License-Identifier: BSD-3-Clause */ /*! * File containing client-side RPC functions for the TIMER service. These * functions are ported to clients that communicate to the SC. * * @addtogroup TIMER_SVC * @{ */ /* Includes */ #include #include #include #include #include #include "sci_timer_rpc.h" /* Local Defines */ /* Local Types */ /* Local Functions */ sc_err_t sc_timer_set_wdog_timeout(sc_ipc_t ipc, sc_timer_wdog_time_t timeout) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_WDOG_TIMEOUT; RPC_U32(&msg, 0U) = (uint32_t)timeout; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_timer_set_wdog_pre_timeout(sc_ipc_t ipc, sc_timer_wdog_time_t pre_timeout) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_WDOG_PRE_TIMEOUT; RPC_U32(&msg, 0U) = (uint32_t)pre_timeout; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_timer_start_wdog(sc_ipc_t ipc, sc_bool_t lock) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_START_WDOG; RPC_U8(&msg, 0U) = (uint8_t)lock; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_timer_stop_wdog(sc_ipc_t ipc) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_STOP_WDOG; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_timer_ping_wdog(sc_ipc_t ipc) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_PING_WDOG; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_timer_get_wdog_status(sc_ipc_t ipc, sc_timer_wdog_time_t *timeout, sc_timer_wdog_time_t *max_timeout, sc_timer_wdog_time_t *remaining_time) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_GET_WDOG_STATUS; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); if (timeout != NULL) *timeout = RPC_U32(&msg, 0U); if (max_timeout != NULL) *max_timeout = RPC_U32(&msg, 4U); if (remaining_time != NULL) *remaining_time = RPC_U32(&msg, 8U); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_timer_pt_get_wdog_status(sc_ipc_t ipc, sc_rm_pt_t pt, sc_bool_t *enb, sc_timer_wdog_time_t *timeout, sc_timer_wdog_time_t *remaining_time) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_PT_GET_WDOG_STATUS; RPC_U8(&msg, 0U) = (uint8_t)pt; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); if (timeout != NULL) *timeout = RPC_U32(&msg, 0U); if (remaining_time != NULL) *remaining_time = RPC_U32(&msg, 4U); result = RPC_R8(&msg); if (enb != NULL) *enb = RPC_U8(&msg, 8U); return (sc_err_t)result; } sc_err_t sc_timer_set_wdog_action(sc_ipc_t ipc, sc_rm_pt_t pt, sc_timer_wdog_action_t action) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_WDOG_ACTION; RPC_U8(&msg, 0U) = (uint8_t)pt; RPC_U8(&msg, 1U) = (uint8_t)action; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_timer_set_rtc_time(sc_ipc_t ipc, uint16_t year, uint8_t mon, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_RTC_TIME; RPC_U16(&msg, 0U) = (uint16_t)year; RPC_U8(&msg, 2U) = (uint8_t)mon; RPC_U8(&msg, 3U) = (uint8_t)day; RPC_U8(&msg, 4U) = (uint8_t)hour; RPC_U8(&msg, 5U) = (uint8_t)min; RPC_U8(&msg, 6U) = (uint8_t)sec; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_timer_get_rtc_time(sc_ipc_t ipc, uint16_t *year, uint8_t *mon, uint8_t *day, uint8_t *hour, uint8_t *min, uint8_t *sec) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_GET_RTC_TIME; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); if (year != NULL) *year = RPC_U16(&msg, 0U); result = RPC_R8(&msg); if (mon != NULL) *mon = RPC_U8(&msg, 2U); if (day != NULL) *day = RPC_U8(&msg, 3U); if (hour != NULL) *hour = RPC_U8(&msg, 4U); if (min != NULL) *min = RPC_U8(&msg, 5U); if (sec != NULL) *sec = RPC_U8(&msg, 6U); return (sc_err_t)result; } sc_err_t sc_timer_get_rtc_sec1970(sc_ipc_t ipc, uint32_t *sec) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_GET_RTC_SEC1970; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); if (sec != NULL) *sec = RPC_U32(&msg, 0U); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_timer_set_rtc_alarm(sc_ipc_t ipc, uint16_t year, uint8_t mon, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_RTC_ALARM; RPC_U16(&msg, 0U) = (uint16_t)year; RPC_U8(&msg, 2U) = (uint8_t)mon; RPC_U8(&msg, 3U) = (uint8_t)day; RPC_U8(&msg, 4U) = (uint8_t)hour; RPC_U8(&msg, 5U) = (uint8_t)min; RPC_U8(&msg, 6U) = (uint8_t)sec; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_timer_set_rtc_periodic_alarm(sc_ipc_t ipc, uint32_t sec) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_RTC_PERIODIC_ALARM; RPC_U32(&msg, 0U) = (uint32_t)sec; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_timer_cancel_rtc_alarm(sc_ipc_t ipc) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_CANCEL_RTC_ALARM; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_timer_set_rtc_calb(sc_ipc_t ipc, int8_t count) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_RTC_CALB; RPC_I8(&msg, 0U) = (int8_t) count; RPC_SIZE(&msg) = 2U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_timer_set_sysctr_alarm(sc_ipc_t ipc, uint64_t ticks) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_SYSCTR_ALARM; RPC_U32(&msg, 0U) = (uint32_t)(ticks >> 32U); RPC_U32(&msg, 4U) = (uint32_t)ticks; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_timer_set_sysctr_periodic_alarm(sc_ipc_t ipc, uint64_t ticks) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_SET_SYSCTR_PERIODIC_ALARM; RPC_U32(&msg, 0U) = (uint32_t)(ticks >> 32U); RPC_U32(&msg, 4U) = (uint32_t)ticks; RPC_SIZE(&msg) = 3U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } sc_err_t sc_timer_cancel_sysctr_alarm(sc_ipc_t ipc) { sc_rpc_msg_t msg; uint8_t result; RPC_VER(&msg) = SC_RPC_VERSION; RPC_SVC(&msg) = (uint8_t)SC_RPC_SVC_TIMER; RPC_FUNC(&msg) = (uint8_t)TIMER_FUNC_CANCEL_SYSCTR_ALARM; RPC_SIZE(&msg) = 1U; sc_call_rpc(ipc, &msg, SC_FALSE); result = RPC_R8(&msg); return (sc_err_t)result; } /**@}*/ trusted-firmware-a-2.2/plat/imx/imx7/000077500000000000000000000000001355360272700175325ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx7/common/000077500000000000000000000000001355360272700210225ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx7/common/imx7.mk000066400000000000000000000061401355360272700222400ustar00rootroot00000000000000# # Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Architecture $(eval $(call add_define,ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING)) TF_CFLAGS += -mfpu=neon ASFLAGS += -mfpu=neon # Platform PLAT_INCLUDES := -Idrivers/imx/uart \ -Iplat/imx/common/include \ -Iplat/imx/imx7/include \ -Idrivers/imx/timer \ -Idrivers/imx/usdhc \ # Translation tables library include lib/xlat_tables_v2/xlat_tables.mk BL2_SOURCES += common/desc_image_load.c \ drivers/delay_timer/delay_timer.c \ drivers/mmc/mmc.c \ drivers/io/io_block.c \ drivers/io/io_fip.c \ drivers/io/io_memmap.c \ drivers/io/io_storage.c \ drivers/imx/timer/imx_gpt.c \ drivers/imx/uart/imx_uart.c \ drivers/imx/uart/imx_crash_uart.S \ lib/aarch32/arm32_aeabi_divmod.c \ lib/aarch32/arm32_aeabi_divmod_a32.S \ lib/cpus/aarch32/cortex_a7.S \ lib/optee/optee_utils.c \ plat/imx/common/imx_aips.c \ plat/imx/common/imx_caam.c \ plat/imx/common/imx_clock.c \ plat/imx/common/imx_csu.c \ plat/imx/common/imx_io_mux.c \ plat/imx/common/imx_snvs.c \ plat/imx/common/imx_wdog.c \ plat/imx/common/imx7_clock.c \ plat/imx/imx7/common/imx7_bl2_mem_params_desc.c \ plat/imx/imx7/common/imx7_bl2_el3_common.c \ plat/imx/imx7/common/imx7_helpers.S \ plat/imx/imx7/common/imx7_image_load.c \ plat/imx/imx7/common/imx7_io_storage.c \ plat/imx/common/aarch32/imx_uart_console.S \ ${XLAT_TABLES_LIB_SRCS} ifneq (${TRUSTED_BOARD_BOOT},0) include drivers/auth/mbedtls/mbedtls_crypto.mk include drivers/auth/mbedtls/mbedtls_x509.mk AUTH_SOURCES := drivers/auth/auth_mod.c \ drivers/auth/crypto_mod.c \ drivers/auth/img_parser_mod.c \ drivers/auth/tbbr/tbbr_cot.c BL2_SOURCES += ${AUTH_SOURCES} \ plat/common/tbbr/plat_tbbr.c \ plat/imx/imx7/common/imx7_trusted_boot.c \ plat/imx/imx7/common/imx7_rotpk.S ROT_KEY = $(BUILD_PLAT)/rot_key.pem ROTPK_HASH = $(BUILD_PLAT)/rotpk_sha256.bin $(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"')) $(eval $(call MAKE_LIB_DIRS)) $(BUILD_PLAT)/bl2/imx7_rotpk.o: $(ROTPK_HASH) certificates: $(ROT_KEY) $(ROT_KEY): | $(BUILD_PLAT) @echo " OPENSSL $@" @if [ ! -f $(ROT_KEY) ]; then \ openssl genrsa 2048 > $@ 2>/dev/null; \ fi $(ROTPK_HASH): $(ROT_KEY) @echo " OPENSSL $@" $(Q)openssl rsa -in $< -pubout -outform DER 2>/dev/null |\ openssl dgst -sha256 -binary > $@ 2>/dev/null endif # Add the build options to pack BLx images and kernel device tree # in the FIP if the platform requires. ifneq ($(BL2),) $(eval $(call TOOL_ADD_PAYLOAD,${BUILD_PLAT}/tb_fw.crt,--tb-fw-cert)) endif ifneq ($(BL32_EXTRA1),) $(eval $(call TOOL_ADD_IMG,BL32_EXTRA1,--tos-fw-extra1)) endif ifneq ($(BL32_EXTRA2),) $(eval $(call TOOL_ADD_IMG,BL32_EXTRA2,--tos-fw-extra2)) endif ifneq ($(HW_CONFIG),) $(eval $(call TOOL_ADD_IMG,HW_CONFIG,--hw-config)) endif # Verify build config # ------------------- ifeq (${ARCH},aarch64) $(error Error: AArch64 not supported on i.mx7) endif trusted-firmware-a-2.2/plat/imx/imx7/common/imx7_bl2_el3_common.c000066400000000000000000000124201355360272700247230ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef AARCH32_SP_OPTEE #error "Must build with OPTEE support included" #endif uintptr_t plat_get_ns_image_entrypoint(void) { return IMX7_UBOOT_BASE; } static uint32_t imx7_get_spsr_for_bl32_entry(void) { return SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS); } static uint32_t imx7_get_spsr_for_bl33_entry(void) { return SPSR_MODE32(MODE32_svc, plat_get_ns_image_entrypoint() & 0x1, SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS); } 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); bl_mem_params_node_t *hw_cfg_mem_params = NULL; bl_mem_params_node_t *pager_mem_params = NULL; bl_mem_params_node_t *paged_mem_params = NULL; assert(bl_mem_params); switch (image_id) { case BL32_IMAGE_ID: 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); err = parse_optee_header(&bl_mem_params->ep_info, &pager_mem_params->image_info, &paged_mem_params->image_info); if (err != 0) WARN("OPTEE header parse error.\n"); /* * When ATF loads the DTB the address of the DTB is passed in * arg2, if an hw config image is present use the base address * as DTB address an pass it as arg2 */ hw_cfg_mem_params = get_bl_mem_params_node(HW_CONFIG_ID); bl_mem_params->ep_info.args.arg0 = bl_mem_params->ep_info.args.arg1; bl_mem_params->ep_info.args.arg1 = 0; if (hw_cfg_mem_params) bl_mem_params->ep_info.args.arg2 = hw_cfg_mem_params->image_info.image_base; else bl_mem_params->ep_info.args.arg2 = 0; bl_mem_params->ep_info.args.arg3 = 0; bl_mem_params->ep_info.spsr = imx7_get_spsr_for_bl32_entry(); break; case BL33_IMAGE_ID: /* AArch32 only core: OP-TEE expects NSec EP in register LR */ pager_mem_params = get_bl_mem_params_node(BL32_IMAGE_ID); assert(pager_mem_params); pager_mem_params->ep_info.lr_svc = bl_mem_params->ep_info.pc; /* BL33 expects to receive the primary CPU MPID (through r0) */ bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr(); bl_mem_params->ep_info.spsr = imx7_get_spsr_for_bl33_entry(); break; default: /* Do nothing in default case */ break; } return err; } void bl2_el3_plat_arch_setup(void) { /* Setup the MMU here */ } static void imx7_setup_system_counter(void) { unsigned long freq = SYS_COUNTER_FREQ_IN_TICKS; /* Set the frequency table index to our target frequency */ write_cntfrq(freq); /* Enable system counter @ frequency table index 0, halt on debug */ mmio_write_32(SYS_CNTCTL_BASE + CNTCR_OFF, CNTCR_FCREQ(0) | CNTCR_HDBG | CNTCR_EN); } static void imx7_setup_wdog_clocks(void) { uint32_t wdog_en_bits = (uint32_t)WDOG_DEFAULT_CLK_SELECT; imx_clock_set_wdog_clk_root_bits(wdog_en_bits); imx_clock_enable_wdog(0); imx_clock_enable_wdog(1); imx_clock_enable_wdog(2); imx_clock_enable_wdog(3); } /* * bl2_el3_early_platform_setup() * MMU off */ void bl2_el3_early_platform_setup(u_register_t arg1, u_register_t arg2, u_register_t arg3, u_register_t arg4) { static console_imx_uart_t console; int console_scope = CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME; /* Initialize common components */ imx_aips_init(); imx_csu_init(); imx_snvs_init(); imx_gpt_ops_init(GPT1_BASE_ADDR); imx_clock_init(); imx7_setup_system_counter(); imx7_setup_wdog_clocks(); /* Platform specific setup */ imx7_platform_setup(arg1, arg2, arg3, arg4); /* Init UART, clock should be enabled in imx7_platform_setup() */ console_imx_uart_register(PLAT_IMX7_BOOT_UART_BASE, PLAT_IMX7_BOOT_UART_CLK_IN_HZ, PLAT_IMX7_CONSOLE_BAUDRATE, &console); console_set_scope(&console.console, console_scope); /* Open handles to persistent storage */ plat_imx7_io_setup(); /* Setup higher-level functionality CAAM, RTC etc */ imx_caam_init(); imx_wdog_init(); /* Print out the expected memory map */ VERBOSE("\tOPTEE 0x%08x-0x%08x\n", IMX7_OPTEE_BASE, IMX7_OPTEE_LIMIT); VERBOSE("\tATF/BL2 0x%08x-0x%08x\n", BL2_RAM_BASE, BL2_RAM_LIMIT); VERBOSE("\tSHRAM 0x%08x-0x%08x\n", SHARED_RAM_BASE, SHARED_RAM_LIMIT); VERBOSE("\tFIP 0x%08x-0x%08x\n", IMX7_FIP_BASE, IMX7_FIP_LIMIT); VERBOSE("\tDTB-OVERLAY 0x%08x-0x%08x\n", IMX7_DTB_OVERLAY_BASE, IMX7_DTB_OVERLAY_LIMIT); VERBOSE("\tDTB 0x%08x-0x%08x\n", IMX7_DTB_BASE, IMX7_DTB_LIMIT); VERBOSE("\tUBOOT/BL33 0x%08x-0x%08x\n", IMX7_UBOOT_BASE, IMX7_UBOOT_LIMIT); } /* * bl2_platform_setup() * MMU on - enabled by bl2_el3_plat_arch_setup() */ void bl2_platform_setup(void) { } trusted-firmware-a-2.2/plat/imx/imx7/common/imx7_bl2_mem_params_desc.c000066400000000000000000000042721355360272700260150ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include static bl_mem_params_node_t bl2_mem_params_descs[] = { { .image_id = BL32_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = BL32_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = IMX7_OPTEE_BASE, .image_info.image_max_size = IMX7_OPTEE_SIZE, .next_handoff_image_id = BL33_IMAGE_ID, }, { .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), .image_info.image_base = IMX7_OPTEE_BASE, .image_info.image_max_size = IMX7_OPTEE_SIZE, .next_handoff_image_id = INVALID_IMAGE_ID, }, { /* This is a zero sized image so we don't set base or size */ .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, }, { .image_id = BL33_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), # ifdef PRELOADED_BL33_BASE .ep_info.pc = PRELOADED_BL33_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), # else .ep_info.pc = BL33_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = IMX7_UBOOT_BASE, .image_info.image_max_size = IMX7_UBOOT_SIZE, # endif /* PRELOADED_BL33_BASE */ .next_handoff_image_id = INVALID_IMAGE_ID, } }; REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs); trusted-firmware-a-2.2/plat/imx/imx7/common/imx7_helpers.S000066400000000000000000000025771355360272700235670ustar00rootroot00000000000000/* * Copyright (c) Linaro 2018-2019 Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include .globl platform_mem_init .globl plat_get_my_entrypoint .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush .globl plat_panic_handler /* --------------------------------------------- * int plat_mem_init(void) * Function to initialize memory. * The HAB hands off the DDR controller already * setup and ready to use. * Implement the mandatory function as a NOP * --------------------------------------------- */ func platform_mem_init bx lr endfunc platform_mem_init func plat_get_my_entrypoint mov r0, #0 bx lr endfunc plat_get_my_entrypoint func plat_crash_console_init mov_imm r0, PLAT_IMX7_BOOT_UART_BASE mov_imm r1, PLAT_IMX7_BOOT_UART_CLK_IN_HZ mov_imm r2, PLAT_IMX7_CONSOLE_BAUDRATE b imx_crash_uart_init endfunc plat_crash_console_init func plat_crash_console_putc mov_imm r1, PLAT_IMX7_BOOT_UART_BASE b imx_crash_uart_putc endfunc plat_crash_console_putc func plat_crash_console_flush /* Placeholder */ mov r0, #0 bx lr endfunc plat_crash_console_flush func plat_panic_handler mov r3, #HAB_ROM_VECTOR_TABLE_FAILSAFE ldr r3, [r3, #0] blx r3 endfunc plat_panic_handler trusted-firmware-a-2.2/plat/imx/imx7/common/imx7_image_load.c000066400000000000000000000007601355360272700242160ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include void plat_flush_next_bl_params(void) { flush_bl_params_desc(); } bl_load_info_t *plat_get_bl_image_load_info(void) { return get_bl_load_info_from_mem_params_desc(); } bl_params_t *plat_get_next_bl_params(void) { return get_next_bl_params_from_mem_params_desc(); } trusted-firmware-a-2.2/plat/imx/imx7/common/imx7_io_storage.c000066400000000000000000000134601355360272700242710ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include static const io_dev_connector_t *fip_dev_con; static uintptr_t fip_dev_handle; #ifndef IMX7_FIP_MMAP static const io_dev_connector_t *mmc_dev_con; static uintptr_t mmc_dev_handle; static const io_block_spec_t mmc_fip_spec = { .offset = IMX7_FIP_MMC_BASE, .length = IMX7_FIP_SIZE }; static const io_block_dev_spec_t mmc_dev_spec = { /* It's used as temp buffer in block driver. */ .buffer = { .offset = IMX7_FIP_BASE, /* do we need a new value? */ .length = IMX7_FIP_SIZE }, .ops = { .read = mmc_read_blocks, .write = mmc_write_blocks, }, .block_size = MMC_BLOCK_SIZE, }; static int open_mmc(const uintptr_t spec); #else static const io_dev_connector_t *memmap_dev_con; static uintptr_t memmap_dev_handle; static const io_block_spec_t fip_block_spec = { .offset = IMX7_FIP_BASE, .length = IMX7_FIP_SIZE }; static int open_memmap(const uintptr_t spec); #endif static int open_fip(const uintptr_t spec); static const io_uuid_spec_t bl32_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32, }; static const io_uuid_spec_t bl32_extra1_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1, }; static const io_uuid_spec_t bl32_extra2_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2, }; static const io_uuid_spec_t bl33_uuid_spec = { .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33, }; #if TRUSTED_BOARD_BOOT static const io_uuid_spec_t tb_fw_cert_uuid_spec = { .uuid = UUID_TRUSTED_BOOT_FW_CERT, }; static const io_uuid_spec_t trusted_key_cert_uuid_spec = { .uuid = UUID_TRUSTED_KEY_CERT, }; static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = { .uuid = UUID_TRUSTED_OS_FW_KEY_CERT, }; static const io_uuid_spec_t tos_fw_cert_uuid_spec = { .uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT, }; static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = { .uuid = UUID_NON_TRUSTED_FW_KEY_CERT, }; static const io_uuid_spec_t nt_fw_cert_uuid_spec = { .uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT, }; #endif /* TRUSTED_BOARD_BOOT */ /* TODO: this structure is replicated multiple times. rationalize it ! */ 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[] = { #ifndef IMX7_FIP_MMAP [FIP_IMAGE_ID] = { &mmc_dev_handle, (uintptr_t)&mmc_fip_spec, open_mmc }, #else [FIP_IMAGE_ID] = { &memmap_dev_handle, (uintptr_t)&fip_block_spec, open_memmap }, #endif [BL32_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_uuid_spec, open_fip }, [BL32_EXTRA1_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_extra1_uuid_spec, open_fip }, [BL32_EXTRA2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_extra2_uuid_spec, open_fip }, [BL33_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl33_uuid_spec, open_fip }, #if TRUSTED_BOARD_BOOT [TRUSTED_BOOT_FW_CERT_ID] = { &fip_dev_handle, (uintptr_t)&tb_fw_cert_uuid_spec, open_fip }, [TRUSTED_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&trusted_key_cert_uuid_spec, open_fip }, [TRUSTED_OS_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&tos_fw_key_cert_uuid_spec, open_fip }, [NON_TRUSTED_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&nt_fw_key_cert_uuid_spec, open_fip }, [TRUSTED_OS_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&tos_fw_cert_uuid_spec, open_fip }, [NON_TRUSTED_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&nt_fw_cert_uuid_spec, open_fip }, #endif /* TRUSTED_BOARD_BOOT */ }; static int open_fip(const uintptr_t spec) { int result; uintptr_t local_image_handle; /* See if a Firmware Image Package is available */ result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); if (result == 0) { result = io_open(fip_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using FIP\n"); io_close(local_image_handle); } } return result; } #ifndef IMX7_FIP_MMAP static int open_mmc(const uintptr_t spec) { int result; uintptr_t local_handle; result = io_dev_init(mmc_dev_handle, (uintptr_t)NULL); if (result == 0) { result = io_open(mmc_dev_handle, spec, &local_handle); if (result == 0) io_close(local_handle); } return result; } #else static int open_memmap(const uintptr_t spec) { int result; uintptr_t local_image_handle; result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL); if (result == 0) { result = io_open(memmap_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using Memmap\n"); io_close(local_image_handle); } } return result; } #endif int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, uintptr_t *image_spec) { int result; const struct plat_io_policy *policy; assert(image_id < ARRAY_SIZE(policies)); policy = &policies[image_id]; result = policy->check(policy->image_spec); assert(result == 0); *image_spec = policy->image_spec; *dev_handle = *policy->dev_handle; return result; } void plat_imx7_io_setup(void) { int result __unused; #ifndef IMX7_FIP_MMAP result = register_io_dev_block(&mmc_dev_con); assert(result == 0); result = io_dev_open(mmc_dev_con, (uintptr_t)&mmc_dev_spec, &mmc_dev_handle); assert(result == 0); #else result = register_io_dev_memmap(&memmap_dev_con); assert(result == 0); result = io_dev_open(memmap_dev_con, (uintptr_t)NULL, &memmap_dev_handle); assert(result == 0); #endif result = register_io_dev_fip(&fip_dev_con); assert(result == 0); result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle); assert(result == 0); } trusted-firmware-a-2.2/plat/imx/imx7/common/imx7_rotpk.S000066400000000000000000000006211355360272700232500ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ .global imx7_rotpk_hash .global imx7_rotpk_hash_end imx7_rotpk_hash: /* DER header */ .byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48 .byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 /* SHA256 */ .incbin ROTPK_HASH imx7_rotpk_hash_end: trusted-firmware-a-2.2/plat/imx/imx7/common/imx7_trusted_boot.c000066400000000000000000000013241355360272700246470ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include extern char imx7_rotpk_hash[], imx7_rotpk_hash_end[]; int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, unsigned int *flags) { *key_ptr = imx7_rotpk_hash; *key_len = imx7_rotpk_hash_end - imx7_rotpk_hash; *flags = ROTPK_IS_HASH; return 0; } int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr) { *nv_ctr = 0; return 0; } int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr) { return 1; } int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size) { return get_mbedtls_heap_helper(heap_addr, heap_size); } trusted-firmware-a-2.2/plat/imx/imx7/include/000077500000000000000000000000001355360272700211555ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx7/include/imx7_def.h000066400000000000000000000010471355360272700230320ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX7_DEF_H #define IMX7_DEF_H #include /******************************************************************************* * Function and variable prototypes ******************************************************************************/ void plat_imx7_io_setup(void); void imx7_platform_setup(u_register_t arg1, u_register_t arg2, u_register_t arg3, u_register_t arg4); #endif /*IMX7_DEF_H */ trusted-firmware-a-2.2/plat/imx/imx7/include/imx_hab_arch.h000066400000000000000000000004601355360272700237320ustar00rootroot00000000000000/* * Copyright (C) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX_HAB_ARCH_H #define IMX_HAB_ARCH_H /* Define the offset the High Assurance Boot callback table is at */ #define HAB_CALLBACK_OFFSET 0x100 #endif /* IMX_HAB_ARCH_H */ trusted-firmware-a-2.2/plat/imx/imx7/include/imx_regs.h000066400000000000000000000071311355360272700231450ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX_REGS_H #define IMX_REGS_H /* Define the processor memory map */ #define OCRAM_S_ALIAS_BASE 0x00000000 /* CM4 Alias Code */ #define ROM_HIGH_BASE 0x00008000 /* ROM high 64k */ #define ROM_HIGH_PROT_BASE 0x00017000 /* ROM high 64k protected */ #define CAAM_BASE 0x00020000 /* CAAM block base address */ #define OCRAM_S_BASE 0x00180000 /* OCRAM_S */ #define ROM_LOW_BASE 0x007f8000 /* ROM low 64k */ #define OCRAM_BASE 0x00900000 /* OCRAM base */ #define CM4_ALIAS_CODE_BASE 0x04000000 /* CM4 alias code */ #define TCM_BASE 0x1fff0000 /* TCM */ #define BOOTROM_CP_BASE 0x20020000 /* Boot ROM (all 96KB) */ #define CM4_ALIAS_SYSTEM_BASE 0x20100000 /* CM4 Alias system */ #define EIM_BASE 0x28000000 /* EIM */ /* BootROM absolute base address */ #define BOOTROM_BASE 0x00000000 /* BootROM */ /* Peripherals like GPIO live in the AIPS range */ #define AIPS1_BASE 0x30000000 /* AIPS1 */ #define AIPS2_BASE 0x30400000 /* AIPS2 */ #define AIPS3_BASE 0x30800000 /* AIPS3 */ #define AIPS4_BASE 0x30c00000 /* AIPS4 */ /* ARM peripherals like GIC */ #define ARM_PERIPHERAL_GIC_BASE 0x31000000 /* GIC */ /* Configuration ports */ #define GPV0_BASE 0x32000000 /* Main config port */ #define GPV1_BASE 0x32100000 /* Wakeup config port */ #define GPV2_BASE 0x32200000 /* Per_s config port */ #define GPV3_BASE 0x32300000 /* Per_m config port */ #define GPV4_BASE 0x32400000 /* Enet config port */ #define GPV5_BASE 0x32500000 /* Display config port */ #define GPV6_BASE 0x32600000 /* M4 conig port */ /* MMAP peripherals - like APBH DMA */ #define APBH_DMA_BASE 0x33000000 /* APBH DMA block */ /* QSPI RX BUFFERS */ #define QSPI_RX_BUFFER_BASE 0x34000000 /* QSPI RX buffers */ /* QSPI1 FLASH */ #define QSPI_FLASH_BASE 0x60000000 /* QSPI1 flash */ /* AIPS1 block addresses */ #define AIPSTZ_CONFIG_OFFSET 0x001f0000 #define CCM_BASE (AIPS1_BASE + 0x380000) /* Define the maximum number of UART blocks on this SoC */ #define MXC_UART1_BASE (AIPS3_BASE + 0x060000) #define MXC_UART2_BASE (AIPS3_BASE + 0x070000) #define MXC_UART3_BASE (AIPS3_BASE + 0x080000) #define MXC_UART4_BASE (AIPS3_BASE + 0x260000) #define MXC_UART5_BASE (AIPS3_BASE + 0x270000) #define MXC_UART6_BASE (AIPS3_BASE + 0x280000) #define MXC_UART7_BASE (AIPS3_BASE + 0x290000) #define MXC_MAX_UART_NUM 0x07 /* Define the maximum number of USDHCI blocks on this SoC */ #define MXC_MAX_USDHC_NUM 3 /* Define the number of CSU registers for this SoC */ #define MXC_MAX_CSU_REGS 0x40 #define CSU_BASE (AIPS1_BASE + 0x3E0000) /* IO Mux block base */ #define MXC_IO_MUXC_BASE (AIPS1_BASE + 0x330000) /* SNVS base */ #define SNVS_BASE (AIPS1_BASE + 0x370000) /* GP Timer base */ #define GPT1_BASE_ADDR (AIPS1_BASE + 0x2d0000) /* MMC base */ #define USDHC1_BASE (AIPS1_BASE + 0xb40000) #define USDHC2_BASE (AIPS1_BASE + 0xb50000) #define USDHC3_BASE (AIPS1_BASE + 0xb60000) /* Arm optional memory mapped counter module base address */ #define SYS_CNTCTL_BASE (AIPS2_BASE + 0x2c0000) /* Define CAAM AIPS offset */ #define CAAM_AIPS_BASE (AIPS3_BASE + 0x100000) #define CAAM_NUM_JOB_RINGS 0x03 #define CAAM_NUM_RTIC 0x04 #define CAAM_NUM_DECO 0x01 /* Define watchdog base addresses */ #define WDOG1_BASE (AIPS1_BASE + 0x280000) #define WDOG2_BASE (AIPS1_BASE + 0x290000) #define WDOG3_BASE (AIPS1_BASE + 0x2A0000) #define WDOG4_BASE (AIPS1_BASE + 0x280000) /* Define the maximum number of WDOG blocks on this SoC */ #define MXC_MAX_WDOG_NUM 0x04 #endif /* IMX_REGS_H */ trusted-firmware-a-2.2/plat/imx/imx7/picopi/000077500000000000000000000000001355360272700210155ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx7/picopi/include/000077500000000000000000000000001355360272700224405ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx7/picopi/include/platform_def.h000066400000000000000000000142051355360272700252550ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #define PLATFORM_STACK_SIZE 0x1000 #define PLATFORM_MAX_CPUS_PER_CLUSTER 2 #define PLATFORM_CLUSTER_COUNT 1 #define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER #define PLATFORM_CORE_COUNT PLATFORM_CLUSTER0_CORE_COUNT #define PICOPI_PRIMARY_CPU 0 #define PLAT_NUM_PWR_DOMAINS (PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1 #define PLAT_MAX_RET_STATE 1 #define PLAT_MAX_OFF_STATE 2 /* Local power state for power domains in Run state. */ #define PLAT_LOCAL_STATE_RUN 0 /* Local power state for retention. Valid only for CPU power domains */ #define PLAT_LOCAL_STATE_RET 1 /* * Local power state for OFF/power-down. Valid for CPU and cluster power * domains. */ #define PLAT_LOCAL_STATE_OFF 2 /* * Macros used to parse state information from State-ID if it is using the * recommended encoding for State-ID. */ #define PLAT_LOCAL_PSTATE_WIDTH 4 #define PLAT_LOCAL_PSTATE_MASK ((1 << PLAT_LOCAL_PSTATE_WIDTH) - 1) /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. * i.MX7 has a 32 byte cacheline size * i.MX 7Dual Applications Processor Reference Manual, Rev. 1, 01/2018 pg 298 */ #define CACHE_WRITEBACK_SHIFT 4 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) /* * Partition memory into secure BootROM, OCRAM_S, non-secure DRAM, secure DRAM */ #define BOOT_ROM_BASE 0x00000000 #define BOOT_ROM_SIZE 0x00020000 #define OCRAM_S_BASE 0x00180000 #define OCRAM_S_SIZE 0x00008000 /* Controller maps 2GB, board contains 512 MB. 0x80000000 - 0xa0000000 */ #define DRAM_BASE 0x80000000 #define DRAM_SIZE 0x20000000 #define DRAM_LIMIT (DRAM_BASE + DRAM_SIZE) /* Place OPTEE at minus 32 MB from the end of memory. 0x9e000000 - 0xa0000000 */ #define IMX7_OPTEE_SIZE 0x02000000 #define IMX7_OPTEE_BASE (DRAM_LIMIT - IMX7_OPTEE_SIZE) #define IMX7_OPTEE_LIMIT (IMX7_OPTEE_BASE + IMX7_OPTEE_SIZE) /* Place ATF directly beneath OPTEE. 0x9df00000 - 0x9e000000 */ #define BL2_RAM_SIZE 0x00100000 #define BL2_RAM_BASE (IMX7_OPTEE_BASE - BL2_RAM_SIZE) #define BL2_RAM_LIMIT (BL2_RAM_BASE + BL2_RAM_SIZE) /* Optional Mailbox. Only relevant on i.MX7D. 0x9deff000 - 0x9df00000*/ #define SHARED_RAM_SIZE 0x00001000 #define SHARED_RAM_BASE (BL2_RAM_BASE - SHARED_RAM_SIZE) #define SHARED_RAM_LIMIT (SHARED_RAM_BASE + SHARED_RAM_SIZE) /* Define the absolute location of u-boot 0x87800000 - 0x87900000 */ #define IMX7_UBOOT_SIZE 0x00100000 #define IMX7_UBOOT_BASE (DRAM_BASE + 0x7800000) #define IMX7_UBOOT_LIMIT (IMX7_UBOOT_BASE + IMX7_UBOOT_SIZE) /* Define FIP image absolute location 0x80000000 - 0x80100000 */ #define IMX7_FIP_SIZE 0x00100000 #define IMX7_FIP_BASE (DRAM_BASE) #define IMX7_FIP_LIMIT (IMX7_FIP_BASE + IMX7_FIP_SIZE) /* Define FIP image location at 1MB offset */ #define IMX7_FIP_MMC_BASE (1024 * 1024) /* Define the absolute location of DTB 0x83000000 - 0x83100000 */ #define IMX7_DTB_SIZE 0x00100000 #define IMX7_DTB_BASE (DRAM_BASE + 0x03000000) #define IMX7_DTB_LIMIT (IMX7_DTB_BASE + IMX7_DTB_SIZE) /* Define the absolute location of DTB Overlay 0x83100000 - 0x83101000 */ #define IMX7_DTB_OVERLAY_SIZE 0x00001000 #define IMX7_DTB_OVERLAY_BASE IMX7_DTB_LIMIT #define IMX7_DTB_OVERLAY_LIMIT (IMX7_DTB_OVERLAY_BASE + \ IMX7_DTB_OVERLAY_SIZE) /* * BL2 specific defines. * * 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 BL2_RAM_BASE #define BL2_LIMIT (BL2_RAM_BASE + BL2_RAM_SIZE) /* * BL3-2/OPTEE */ # define BL32_BASE IMX7_OPTEE_BASE # define BL32_LIMIT (IMX7_OPTEE_BASE + IMX7_OPTEE_SIZE) /* * BL3-3/U-BOOT */ #define BL33_BASE IMX7_UBOOT_BASE #define BL33_LIMIT (IMX7_UBOOT_BASE + IMX7_UBOOT_SIZE) /* * ATF's view of memory * * 0xa0000000 +-----------------+ * | DDR | BL32/OPTEE * 0x9e000000 +-----------------+ * | DDR | BL23 ATF * 0x9df00000 +-----------------+ * | DDR | Shared MBOX RAM * 0x9de00000 +-----------------+ * | DDR | Unallocated * 0x87900000 +-----------------+ * | DDR | BL33/U-BOOT * 0x87800000 +-----------------+ * | DDR | Unallocated * 0x83100000 +-----------------+ * | DDR | DTB * 0x83000000 +-----------------+ * | DDR | Unallocated * 0x80100000 +-----------------+ * | DDR | FIP * 0x80000000 +-----------------+ * | SOC I/0 | * 0x00a00000 +-----------------+ * | OCRAM | Not used * 0x00900000 +-----------------+ * | SOC I/0 | * 0x00188000 +-----------------+ * | OCRAM_S | Not used * 0x00180000 +-----------------+ * | SOC I/0 | * 0x00020000 +-----------------+ * | BootROM | BL1 * 0x00000000 +-----------------+ */ #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #define MAX_MMAP_REGIONS 10 #define MAX_XLAT_TABLES 6 #define MAX_IO_DEVICES 2 #define MAX_IO_HANDLES 3 #define MAX_IO_BLOCK_DEVICES 1 /* UART defines */ #define PLAT_IMX7_BOOT_UART_BASE MXC_UART5_BASE #define PLAT_IMX7_BOOT_UART_CLK_IN_HZ 24000000 #define PLAT_IMX7_CONSOLE_BAUDRATE 115200 /* MMC defines */ #ifndef PLAT_PICOPI_SD #define PLAT_PICOPI_SD 3 #endif #if PLAT_PICOPI_SD == 1 #define PLAT_PICOPI_BOOT_MMC_BASE USDHC1_BASE #endif /* PLAT_PICOPI_SD == 1 */ #if PLAT_PICOPI_SD == 2 #define PLAT_PICOPI_BOOT_MMC_BASE USDHC2_BASE #endif /* PLAT_PICOPI_SD == 2 */ #if PLAT_PICOPI_SD == 3 #define PLAT_PICOPI_BOOT_MMC_BASE USDHC3_BASE #endif /* PLAT_PICOPI_SD == 3 */ /* * System counter */ #define SYS_COUNTER_FREQ_IN_TICKS 8000000 /* 8 MHz */ #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/imx/imx7/picopi/picopi_bl2_el3_setup.c000066400000000000000000000110151355360272700251640ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #define UART5_CLK_SELECT (CCM_TARGET_ROOT_ENABLE |\ CCM_TRGT_MUX_UART5_CLK_ROOT_OSC_24M) #define USDHC_CLK_SELECT (CCM_TARGET_ROOT_ENABLE |\ CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_AHB |\ CCM_TARGET_POST_PODF(2)) #define USB_CLK_SELECT (CCM_TARGET_ROOT_ENABLE |\ CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_SYS_PLL) #define PICOPI_UART5_RX_MUX \ IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_ALT1_UART5_RX_DATA #define PICOPI_UART5_TX_MUX \ IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_ALT1_UART5_TX_DATA #define PICOPI_SD3_FEATURES \ (IOMUXC_SW_PAD_CTL_PAD_SD3_PU_47K | \ IOMUXC_SW_PAD_CTL_PAD_SD3_PE | \ IOMUXC_SW_PAD_CTL_PAD_SD3_HYS | \ IOMUXC_SW_PAD_CTL_PAD_SD3_SLEW_SLOW | \ IOMUXC_SW_PAD_CTL_PAD_SD3_DSE_3_X6) static void picopi_setup_pinmux(void) { /* Configure UART5 TX */ imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_I2C4_SDA_OFFSET, PICOPI_UART5_TX_MUX); /* Configure UART5 RX */ imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_I2C4_SCL_OFFSET, PICOPI_UART5_RX_MUX); /* Configure USDHC3 */ imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_CLK_OFFSET, 0); imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_CMD_OFFSET, 0); imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_DATA0_OFFSET, 0); imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_DATA1_OFFSET, 0); imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_DATA2_OFFSET, 0); imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_DATA3_OFFSET, 0); imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_DATA4_OFFSET, 0); imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_DATA5_OFFSET, 0); imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_DATA6_OFFSET, 0); imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_SD3_DATA7_OFFSET, 0); imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO14_OFFSET, IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO14_ALT1_SD3_CD_B); imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_CLK_OFFSET, PICOPI_SD3_FEATURES); imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_CMD_OFFSET, PICOPI_SD3_FEATURES); imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_DATA0_OFFSET, PICOPI_SD3_FEATURES); imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_DATA1_OFFSET, PICOPI_SD3_FEATURES); imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_DATA2_OFFSET, PICOPI_SD3_FEATURES); imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_DATA3_OFFSET, PICOPI_SD3_FEATURES); imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_DATA4_OFFSET, PICOPI_SD3_FEATURES); imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_DATA5_OFFSET, PICOPI_SD3_FEATURES); imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_DATA6_OFFSET, PICOPI_SD3_FEATURES); imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_SD3_DATA7_OFFSET, PICOPI_SD3_FEATURES); imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO14_OFFSET, PICOPI_SD3_FEATURES); } static void picopi_usdhc_setup(void) { imx_usdhc_params_t params; struct mmc_device_info info; zeromem(¶ms, sizeof(imx_usdhc_params_t)); params.reg_base = PLAT_PICOPI_BOOT_MMC_BASE; params.clk_rate = 25000000; params.bus_width = MMC_BUS_WIDTH_8; info.mmc_dev_type = MMC_IS_EMMC; imx_usdhc_init(¶ms, &info); } static void picopi_setup_usb_clocks(void) { uint32_t usb_en_bits = (uint32_t)USB_CLK_SELECT; imx_clock_set_usb_clk_root_bits(usb_en_bits); imx_clock_enable_usb(CCM_CCGR_ID_USB_IPG); imx_clock_enable_usb(CCM_CCGR_ID_USB_PHY_480MCLK); imx_clock_enable_usb(CCM_CCGR_ID_USB_OTG1_PHY); imx_clock_enable_usb(CCM_CCGR_ID_USB_OTG2_PHY); } void imx7_platform_setup(u_register_t arg1, u_register_t arg2, u_register_t arg3, u_register_t arg4) { uint32_t uart5_en_bits = (uint32_t)UART5_CLK_SELECT; uint32_t usdhc_clock_sel = PLAT_PICOPI_SD - 1; /* Initialize clocks etc */ imx_clock_enable_uart(4, uart5_en_bits); imx_clock_enable_usdhc(usdhc_clock_sel, USDHC_CLK_SELECT); picopi_setup_usb_clocks(); /* Setup pin-muxes */ picopi_setup_pinmux(); picopi_usdhc_setup(); } trusted-firmware-a-2.2/plat/imx/imx7/picopi/platform.mk000066400000000000000000000014421355360272700231730ustar00rootroot00000000000000# # Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Include imx7 common include plat/imx/imx7/common/imx7.mk # Platform PLAT_INCLUDES += -Iplat/imx/imx7/picopi/include \ BL2_SOURCES += drivers/imx/usdhc/imx_usdhc.c \ plat/imx/imx7/picopi/picopi_bl2_el3_setup.c \ # Build config flags # ------------------ ARM_CORTEX_A7 := yes WORKAROUND_CVE_2017_5715 := 0 RESET_TO_BL31 := 0 # Non-TF Boot ROM BL2_AT_EL3 := 1 # Indicate single-core COLD_BOOT_SINGLE_CPU := 1 # Have different sections for code and rodata SEPARATE_CODE_AND_RODATA := 1 # Use Coherent memory USE_COHERENT_MEM := 1 # Use multi console API MULTI_CONSOLE_API := 1 PLAT_PICOPI_UART :=5 $(eval $(call add_define,PLAT_PICOPI_UART)) trusted-firmware-a-2.2/plat/imx/imx7/warp7/000077500000000000000000000000001355360272700205725ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx7/warp7/include/000077500000000000000000000000001355360272700222155ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx7/warp7/include/platform_def.h000066400000000000000000000150131355360272700250300ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #define PLATFORM_STACK_SIZE 0x1000 #define PLATFORM_MAX_CPUS_PER_CLUSTER 2 #define PLATFORM_CLUSTER_COUNT 1 #define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER #define PLATFORM_CLUSTER1_CORE_COUNT 0 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT + \ PLATFORM_CLUSTER1_CORE_COUNT) #define WARP7_PRIMARY_CPU 0 #define PLAT_NUM_PWR_DOMAINS (PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1 #define PLAT_MAX_RET_STATE 1 #define PLAT_MAX_OFF_STATE 2 /* Local power state for power domains in Run state. */ #define PLAT_LOCAL_STATE_RUN 0 /* Local power state for retention. Valid only for CPU power domains */ #define PLAT_LOCAL_STATE_RET 1 /* * Local power state for OFF/power-down. Valid for CPU and cluster power * domains. */ #define PLAT_LOCAL_STATE_OFF 2 /* * Macros used to parse state information from State-ID if it is using the * recommended encoding for State-ID. */ #define PLAT_LOCAL_PSTATE_WIDTH 4 #define PLAT_LOCAL_PSTATE_MASK ((1 << PLAT_LOCAL_PSTATE_WIDTH) - 1) /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. * i.MX7 has a 32 byte cacheline size * i.MX 7Solo Applications Processor Reference Manual, Rev. 0.1, 08/2016 pg 244 */ #define CACHE_WRITEBACK_SHIFT 4 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) /* * Partition memory into secure BootROM, OCRAM_S, non-secure DRAM, secure DRAM */ #define BOOT_ROM_BASE 0x00000000 #define BOOT_ROM_SIZE 0x00020000 #define OCRAM_S_BASE 0x00180000 #define OCRAM_S_SIZE 0x00008000 /* Controller maps 2GB, board contains 512 MB. 0x80000000 - 0xa0000000 */ #define DRAM_BASE 0x80000000 #define DRAM_SIZE 0x20000000 #define DRAM_LIMIT (DRAM_BASE + DRAM_SIZE) /* Place OPTEE at minus 32 MB from the end of memory. 0x9e000000 - 0xa0000000 */ #define IMX7_OPTEE_SIZE 0x02000000 #define IMX7_OPTEE_BASE (DRAM_LIMIT - IMX7_OPTEE_SIZE) #define IMX7_OPTEE_LIMIT (IMX7_OPTEE_BASE + IMX7_OPTEE_SIZE) /* Place ATF directly beneath OPTEE. 0x9df00000 - 0x9e000000 */ #define BL2_RAM_SIZE 0x00100000 #define BL2_RAM_BASE (IMX7_OPTEE_BASE - BL2_RAM_SIZE) #define BL2_RAM_LIMIT (BL2_RAM_BASE + BL2_RAM_SIZE) /* Optional Mailbox. Only relevant on i.MX7D. 0x9deff000 - 0x9df00000*/ #define SHARED_RAM_SIZE 0x00001000 #define SHARED_RAM_BASE (BL2_RAM_BASE - SHARED_RAM_SIZE) #define SHARED_RAM_LIMIT (SHARED_RAM_BASE + SHARED_RAM_SIZE) /* Define the absolute location of u-boot 0x87800000 - 0x87900000 */ #define IMX7_UBOOT_SIZE 0x00100000 #define IMX7_UBOOT_BASE (DRAM_BASE + 0x7800000) #define IMX7_UBOOT_LIMIT (IMX7_UBOOT_BASE + IMX7_UBOOT_SIZE) /* Define FIP image absolute location 0x80000000 - 0x80100000 */ #define IMX7_FIP_SIZE 0x00100000 #define IMX7_FIP_BASE (DRAM_BASE) #define IMX7_FIP_LIMIT (IMX7_FIP_BASE + IMX7_FIP_SIZE) /* Define FIP image location at 1MB offset */ #define IMX7_FIP_MMC_BASE (1024 * 1024) /* Define the absolute location of DTB 0x83000000 - 0x83100000 */ #define IMX7_DTB_SIZE 0x00100000 #define IMX7_DTB_BASE (DRAM_BASE + 0x03000000) #define IMX7_DTB_LIMIT (IMX7_DTB_BASE + IMX7_DTB_SIZE) /* Define the absolute location of DTB Overlay 0x83100000 - 0x83101000 */ #define IMX7_DTB_OVERLAY_SIZE 0x00001000 #define IMX7_DTB_OVERLAY_BASE IMX7_DTB_LIMIT #define IMX7_DTB_OVERLAY_LIMIT (IMX7_DTB_OVERLAY_BASE + \ IMX7_DTB_OVERLAY_SIZE) /* * BL2 specific defines. * * 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 BL2_RAM_BASE #define BL2_LIMIT (BL2_RAM_BASE + BL2_RAM_SIZE) /* * BL3-2/OPTEE */ # define BL32_BASE IMX7_OPTEE_BASE # define BL32_LIMIT (IMX7_OPTEE_BASE + IMX7_OPTEE_SIZE) /* * BL3-3/U-BOOT */ #define BL33_BASE IMX7_UBOOT_BASE #define BL33_LIMIT (IMX7_UBOOT_BASE + IMX7_UBOOT_SIZE) /* * ATF's view of memory * * 0xa0000000 +-----------------+ * | DDR | BL32/OPTEE * 0x9e000000 +-----------------+ * | DDR | BL23 ATF * 0x9df00000 +-----------------+ * | DDR | Shared MBOX RAM * 0x9de00000 +-----------------+ * | DDR | Unallocated * 0x87900000 +-----------------+ * | DDR | BL33/U-BOOT * 0x87800000 +-----------------+ * | DDR | Unallocated * 0x83101000 +-----------------+ * | DDR | DTB Overlay * 0x83100000 +-----------------+ * | DDR | DTB * 0x83000000 +-----------------+ * | DDR | Unallocated * 0x80100000 +-----------------+ * | DDR | FIP * 0x80000000 +-----------------+ * | SOC I/0 | * 0x00a00000 +-----------------+ * | OCRAM | Not used * 0x00900000 +-----------------+ * | SOC I/0 | * 0x00188000 +-----------------+ * | OCRAM_S | Not used * 0x00180000 +-----------------+ * | SOC I/0 | * 0x00020000 +-----------------+ * | BootROM | BL1 * 0x00000000 +-----------------+ */ #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #define MAX_MMAP_REGIONS 10 #define MAX_XLAT_TABLES 6 #define MAX_IO_DEVICES 2 #define MAX_IO_HANDLES 3 #define MAX_IO_BLOCK_DEVICES 1U /* UART defines */ #if PLAT_WARP7_UART == 1 #define PLAT_WARP7_UART_BASE MXC_UART1_BASE #elif PLAT_WARP7_UART == 6 #define IMX_UART_DTE #define PLAT_WARP7_UART_BASE MXC_UART6_BASE #else #error "define PLAT_WARP7_UART=1 or PLAT_WARP7_UART=6" #endif #define PLAT_IMX7_BOOT_UART_BASE PLAT_WARP7_UART_BASE #define PLAT_IMX7_BOOT_UART_CLK_IN_HZ 24000000 #define PLAT_IMX7_CONSOLE_BAUDRATE 115200 /* MMC defines */ #ifndef PLAT_WARP7_SD #define PLAT_WARP7_SD 3 #endif #if PLAT_WARP7_SD == 1 #define PLAT_WARP7_BOOT_MMC_BASE USDHC1_BASE #endif /* PLAT_WARP7_SD == 1 */ #if PLAT_WARP7_SD == 2 #define PLAT_WARP7_BOOT_MMC_BASE USDHC2_BASE #endif /* PLAT_WARP7_SD == 2 */ #if PLAT_WARP7_SD == 3 #define PLAT_WARP7_BOOT_MMC_BASE USDHC3_BASE #endif /* PLAT_WARP7_SD == 3 */ /* * System counter */ #define SYS_COUNTER_FREQ_IN_TICKS 8000000 /* 8 MHz */ #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/imx/imx7/warp7/platform.mk000066400000000000000000000013411355360272700227460ustar00rootroot00000000000000# # Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Include imx7 common include plat/imx/imx7/common/imx7.mk # Platform PLAT_INCLUDES += -Iplat/imx/imx7/warp7/include BL2_SOURCES += drivers/imx/usdhc/imx_usdhc.c \ plat/imx/imx7/warp7/warp7_bl2_el3_setup.c # Build config flags # ------------------ ARM_CORTEX_A7 := yes WORKAROUND_CVE_2017_5715 := 0 RESET_TO_BL31 := 0 # Non-TF Boot ROM BL2_AT_EL3 := 1 # Indicate single-core COLD_BOOT_SINGLE_CPU := 1 # Have different sections for code and rodata SEPARATE_CODE_AND_RODATA := 1 # Use Coherent memory USE_COHERENT_MEM := 1 PLAT_WARP7_UART :=1 $(eval $(call add_define,PLAT_WARP7_UART)) trusted-firmware-a-2.2/plat/imx/imx7/warp7/warp7_bl2_el3_setup.c000066400000000000000000000103231355360272700245170ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #define UART1_CLK_SELECT (CCM_TARGET_ROOT_ENABLE |\ CCM_TRGT_MUX_UART1_CLK_ROOT_OSC_24M) #define UART6_CLK_SELECT (CCM_TARGET_ROOT_ENABLE |\ CCM_TRGT_MUX_UART6_CLK_ROOT_OSC_24M) #define USDHC_CLK_SELECT (CCM_TARGET_ROOT_ENABLE |\ CCM_TRGT_MUX_NAND_USDHC_BUS_CLK_ROOT_AHB |\ CCM_TARGET_POST_PODF(2)) #define USB_CLK_SELECT (CCM_TARGET_ROOT_ENABLE |\ CCM_TRGT_MUX_USB_HSIC_CLK_ROOT_SYS_PLL) #define WARP7_UART1_TX_MUX \ IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_ALT0_UART1_TX_DATA #define WARP7_UART1_TX_FEATURES \ (IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_PS_3_100K_PU | \ IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_PE_EN | \ IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_HYS_EN | \ IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_DSE_1_X4) #define WARP7_UART1_RX_MUX \ IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_ALT0_UART1_RX_DATA #define WARP7_UART1_RX_FEATURES \ (IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_PS_3_100K_PU | \ IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_PE_EN | \ IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_HYS_EN | \ IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_DSE_1_X4) #define WARP7_UART6_TX_MUX \ IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_ALT1_UART6_TX_DATA #define WARP7_UART6_TX_FEATURES \ (IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_PS_3_100K_PU | \ IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_PE_EN | \ IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_HYS_EN | \ IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_DSE_1_X4) #define WARP7_UART6_RX_MUX \ IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_ALT1_UART6_RX_DATA #define WARP7_UART6_RX_FEATURES \ (IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_PS_3_100K_PU | \ IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_PE_EN | \ IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_HYS_EN | \ IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_DSE_1_X4) static void warp7_setup_pinmux(void) { /* Configure UART1 TX */ imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_UART1_TX_DATA_OFFSET, WARP7_UART1_TX_MUX); imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_UART1_TX_DATA_OFFSET, WARP7_UART1_TX_FEATURES); /* Configure UART1 RX */ imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_UART1_RX_DATA_OFFSET, WARP7_UART1_RX_MUX); imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_UART1_RX_DATA_OFFSET, WARP7_UART1_RX_FEATURES); /* Configure UART6 TX */ imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_ECSPI1_MOSI_OFFSET, WARP7_UART6_TX_MUX); imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_ECSPI1_MOSI_OFFSET, WARP7_UART6_TX_FEATURES); /* Configure UART6 RX */ imx_io_muxc_set_pad_alt_function(IOMUXC_SW_MUX_CTL_PAD_ECSPI1_SCLK_OFFSET, WARP7_UART6_RX_MUX); imx_io_muxc_set_pad_features(IOMUXC_SW_PAD_CTL_PAD_ECSPI1_SCLK_OFFSET, WARP7_UART6_RX_FEATURES); } static void warp7_usdhc_setup(void) { imx_usdhc_params_t params; struct mmc_device_info info; zeromem(¶ms, sizeof(imx_usdhc_params_t)); params.reg_base = PLAT_WARP7_BOOT_MMC_BASE; params.clk_rate = 25000000; params.bus_width = MMC_BUS_WIDTH_8; info.mmc_dev_type = MMC_IS_EMMC; imx_usdhc_init(¶ms, &info); } static void warp7_setup_usb_clocks(void) { uint32_t usb_en_bits = (uint32_t)USB_CLK_SELECT; imx_clock_set_usb_clk_root_bits(usb_en_bits); imx_clock_enable_usb(CCM_CCGR_ID_USB_IPG); imx_clock_enable_usb(CCM_CCGR_ID_USB_PHY_480MCLK); imx_clock_enable_usb(CCM_CCGR_ID_USB_OTG1_PHY); imx_clock_enable_usb(CCM_CCGR_ID_USB_OTG2_PHY); } void imx7_platform_setup(u_register_t arg1, u_register_t arg2, u_register_t arg3, u_register_t arg4) { uint32_t uart1_en_bits = (uint32_t)UART1_CLK_SELECT; uint32_t uart6_en_bits = (uint32_t)UART6_CLK_SELECT; uint32_t usdhc_clock_sel = PLAT_WARP7_SD - 1; /* Initialize clocks etc */ imx_clock_enable_uart(0, uart1_en_bits); imx_clock_enable_uart(5, uart6_en_bits); imx_clock_enable_usdhc(usdhc_clock_sel, USDHC_CLK_SELECT); warp7_setup_usb_clocks(); /* Setup pin-muxes */ warp7_setup_pinmux(); warp7_usdhc_setup(); } trusted-firmware-a-2.2/plat/imx/imx8m/000077500000000000000000000000001355360272700177105ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx8m/gpc_common.c000066400000000000000000000155241355360272700222040ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include static uint32_t gpc_imr_offset[] = { 0x30, 0x40, 0x1c0, 0x1d0, }; #pragma weak imx_set_cpu_pwr_off #pragma weak imx_set_cpu_pwr_on #pragma weak imx_set_cpu_lpm #pragma weak imx_set_cluster_powerdown void imx_set_cpu_secure_entry(unsigned int core_id, uintptr_t sec_entrypoint) { uint64_t temp_base; temp_base = (uint64_t) sec_entrypoint; temp_base >>= 2; mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3), ((uint32_t)(temp_base >> 22) & 0xffff)); mmio_write_32(IMX_SRC_BASE + SRC_GPR1_OFFSET + (core_id << 3) + 4, ((uint32_t)temp_base & 0x003fffff)); } void imx_set_cpu_pwr_off(unsigned int core_id) { /* enable the wfi power down of the core */ mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id)); /* assert the pcg pcr bit of the core */ mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); } void imx_set_cpu_pwr_on(unsigned int core_id) { /* clear the wfi power down bit of the core */ mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id)); /* assert the ncpuporeset */ mmio_clrbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id)); /* assert the pcg pcr bit of the core */ mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); /* sw power up the core */ mmio_setbits_32(IMX_GPC_BASE + CPU_PGC_UP_TRG, (1 << core_id)); /* wait for the power up finished */ while ((mmio_read_32(IMX_GPC_BASE + CPU_PGC_UP_TRG) & (1 << core_id)) != 0) ; /* deassert the pcg pcr bit of the core */ mmio_clrbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); /* deassert the ncpuporeset */ mmio_setbits_32(IMX_SRC_BASE + SRC_A53RCR1, (1 << core_id)); } void imx_set_cpu_lpm(unsigned int core_id, bool pdn) { if (pdn) { /* enable the core WFI PDN & IRQ PUP */ mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | COREx_IRQ_WUP(core_id)); /* assert the pcg pcr bit of the core */ mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); } else { /* disbale CORE WFI PDN & IRQ PUP */ mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | COREx_IRQ_WUP(core_id)); /* deassert the pcg pcr bit of the core */ mmio_clrbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); } } /* * the plat and noc can only be power up & down by slot method, * slot0: plat power down; slot1: noc power down; slot2: noc power up; * slot3: plat power up. plat's pup&pdn ack is used by default. if * noc is config to power down, then noc's pdn ack should be used. */ static void imx_a53_plat_slot_config(bool pdn) { if (pdn) { mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(0), PLAT_PDN_SLT_CTRL); mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(3), PLAT_PUP_SLT_CTRL); mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_PLAT_PDN_ACK | A53_PLAT_PUP_ACK); mmio_setbits_32(IMX_GPC_BASE + PLAT_PGC_PCR, 0x1); } else { mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(0), PLAT_PDN_SLT_CTRL); mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(3), PLAT_PUP_SLT_CTRL); mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_DUMMY_PUP_ACK | A53_DUMMY_PDN_ACK); mmio_clrbits_32(IMX_GPC_BASE + PLAT_PGC_PCR, 0x1); } } void imx_set_cluster_standby(bool enter) { /* * Enable BIT 6 of A53 AD register to make sure system * don't enter LPM mode. */ if (enter) mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6)); else mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, (1 << 6)); } /* i.mx8mq need to override it */ void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state) { uint32_t val; if (!is_local_state_run(power_state)) { /* config C0~1's LPM, enable a53 clock off in LPM */ mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_BSC, A53_CLK_ON_LPM, LPM_MODE(power_state)); /* config C2-3's LPM */ mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, LPM_MODE(power_state)); /* enable PLAT/SCU power down */ val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD); val &= ~EN_L2_WFI_PDN; /* L2 cache memory is on in WAIT mode */ if (is_local_state_off(power_state)) val |= (L2PGE | EN_PLAT_PDN); else val |= EN_PLAT_PDN; mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); imx_a53_plat_slot_config(true); } else { /* clear the slot and ack for cluster power down */ imx_a53_plat_slot_config(false); /* reverse the cluster level setting */ mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_BSC, 0xf, A53_CLK_ON_LPM); mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, 0xf); /* clear PLAT/SCU power down */ mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_AD, (L2PGE | EN_PLAT_PDN), EN_L2_WFI_PDN); } } static unsigned int gicd_read_isenabler(uintptr_t base, unsigned int id) { unsigned int n = id >> ISENABLER_SHIFT; return mmio_read_32(base + GICD_ISENABLER + (n << 2)); } /* * gic's clock will be gated in system suspend, so gic has no ability to * to wakeup the system, we need to config the imr based on the irq * enable status in gic, then gpc will monitor the wakeup irq */ void imx_set_sys_wakeup(unsigned int last_core, bool pdn) { uint32_t irq_mask; uintptr_t gicd_base = PLAT_GICD_BASE; if (pdn) mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_BSC, A53_CORE_WUP_SRC(last_core), IRQ_SRC_A53_WUP); else mmio_clrsetbits_32(IMX_GPC_BASE + LPCR_A53_BSC, IRQ_SRC_A53_WUP, A53_CORE_WUP_SRC(last_core)); /* clear last core's IMR based on GIC's mask setting */ for (int i = 0; i < IRQ_IMR_NUM; i++) { if (pdn) /* set the wakeup irq base GIC */ irq_mask = ~gicd_read_isenabler(gicd_base, 32 * (i + 1)); else irq_mask = IMR_MASK_ALL; mmio_write_32(IMX_GPC_BASE + gpc_imr_offset[last_core] + i * 4, irq_mask); } } #pragma weak imx_noc_slot_config /* * this function only need to be override by platform * that support noc power down, for example: imx8mm. * otherwize, keep it empty. */ void imx_noc_slot_config(bool pdn) { } /* this is common for all imx8m soc */ void imx_set_sys_lpm(unsigned int last_core, bool retention) { uint32_t val; val = mmio_read_32(IMX_GPC_BASE + SLPCR); val &= ~(SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS | SLPCR_BYPASS_PMIC_READY | SLPCR_A53_FASTWUP_STOP_MODE); if (retention) val |= (SLPCR_EN_DSM | SLPCR_VSTBY | SLPCR_SBYOS | SLPCR_BYPASS_PMIC_READY | SLPCR_A53_FASTWUP_STOP_MODE); mmio_write_32(IMX_GPC_BASE + SLPCR, val); /* config the noc power down */ imx_noc_slot_config(retention); /* config wakeup irqs' mask in gpc */ imx_set_sys_wakeup(last_core, retention); } void imx_set_rbc_count(void) { mmio_setbits_32(IMX_GPC_BASE + SLPCR, SLPCR_RBC_EN | (0x8 << SLPCR_RBC_COUNT_SHIFT)); } void imx_clear_rbc_count(void) { mmio_clrbits_32(IMX_GPC_BASE + SLPCR, SLPCR_RBC_EN | (0x3f << SLPCR_RBC_COUNT_SHIFT)); } trusted-firmware-a-2.2/plat/imx/imx8m/imx8m_caam.c000066400000000000000000000020201355360272700220710ustar00rootroot00000000000000/* * Copyright (c) 2019, NXP. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include void imx8m_caam_init(void) { uint32_t sm_cmd; /* Dealloc part 0 and 2 with current DID */ sm_cmd = (0 << SMC_PART_SHIFT | SMC_CMD_DEALLOC_PART); mmio_write_32(SM_CMD, sm_cmd); sm_cmd = (2 << SMC_PART_SHIFT | SMC_CMD_DEALLOC_PART); mmio_write_32(SM_CMD, sm_cmd); /* config CAAM JRaMID set MID to Cortex A */ mmio_write_32(CAAM_JR0MID, CAAM_NS_MID); mmio_write_32(CAAM_JR1MID, CAAM_NS_MID); mmio_write_32(CAAM_JR2MID, CAAM_NS_MID); /* Alloc partition 0 writing SMPO and SMAGs */ mmio_write_32(SM_P0_PERM, 0xff); mmio_write_32(SM_P0_SMAG2, 0xffffffff); mmio_write_32(SM_P0_SMAG1, 0xffffffff); /* Allocate page 0 and 1 to partition 0 with DID set */ sm_cmd = (0 << SMC_PAGE_SHIFT | 0 << SMC_PART_SHIFT | SMC_CMD_ALLOC_PAGE); mmio_write_32(SM_CMD, sm_cmd); sm_cmd = (1 << SMC_PAGE_SHIFT | 0 << SMC_PART_SHIFT | SMC_CMD_ALLOC_PAGE); mmio_write_32(SM_CMD, sm_cmd); } trusted-firmware-a-2.2/plat/imx/imx8m/imx8m_psci_common.c000066400000000000000000000115031355360272700235040ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include /* * below callback functions need to be override by i.mx8mq, * for other i.mx8m soc, if no special requirement, * reuse below ones. */ #pragma weak imx_validate_power_state #pragma weak imx_domain_suspend #pragma weak imx_domain_suspend_finish #pragma weak imx_get_sys_suspend_power_state int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) { /* The non-secure entrypoint should be in RAM space */ if (ns_entrypoint < PLAT_NS_IMAGE_OFFSET) return PSCI_E_INVALID_PARAMS; return PSCI_E_SUCCESS; } int imx_pwr_domain_on(u_register_t mpidr) { unsigned int core_id; uint64_t base_addr = BL31_BASE; core_id = MPIDR_AFFLVL0_VAL(mpidr); imx_set_cpu_secure_entry(core_id, base_addr); imx_set_cpu_pwr_on(core_id); return PSCI_E_SUCCESS; } void imx_pwr_domain_on_finish(const psci_power_state_t *target_state) { plat_gic_pcpu_init(); plat_gic_cpuif_enable(); } void imx_pwr_domain_off(const psci_power_state_t *target_state) { uint64_t mpidr = read_mpidr_el1(); unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); plat_gic_cpuif_disable(); imx_set_cpu_pwr_off(core_id); } int imx_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { int pwr_lvl = psci_get_pstate_pwrlvl(power_state); int pwr_type = psci_get_pstate_type(power_state); int state_id = psci_get_pstate_id(power_state); if (pwr_lvl > PLAT_MAX_PWR_LVL) return PSCI_E_INVALID_PARAMS; if (pwr_type == PSTATE_TYPE_STANDBY) { CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; } if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) { CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE; CLUSTER_PWR_STATE(req_state) = PLAT_WAIT_RET_STATE; } return PSCI_E_SUCCESS; } void imx_cpu_standby(plat_local_state_t cpu_state) { dsb(); write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); isb(); wfi(); write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT)); isb(); } void imx_domain_suspend(const psci_power_state_t *target_state) { uint64_t base_addr = BL31_BASE; uint64_t mpidr = read_mpidr_el1(); unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); if (is_local_state_off(CORE_PWR_STATE(target_state))) { plat_gic_cpuif_disable(); imx_set_cpu_secure_entry(core_id, base_addr); imx_set_cpu_lpm(core_id, true); } else { dsb(); write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); isb(); } if (!is_local_state_run(CLUSTER_PWR_STATE(target_state))) imx_set_cluster_powerdown(core_id, CLUSTER_PWR_STATE(target_state)); if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) imx_set_sys_lpm(core_id, true); } void imx_domain_suspend_finish(const psci_power_state_t *target_state) { uint64_t mpidr = read_mpidr_el1(); unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); if (is_local_state_off(SYSTEM_PWR_STATE(target_state))) imx_set_sys_lpm(core_id, false); if (!is_local_state_run(CLUSTER_PWR_STATE(target_state))) { imx_clear_rbc_count(); imx_set_cluster_powerdown(core_id, PSCI_LOCAL_STATE_RUN); } if (is_local_state_off(CORE_PWR_STATE(target_state))) { imx_set_cpu_lpm(core_id, false); plat_gic_cpuif_enable(); } else { write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT)); isb(); } } void imx_get_sys_suspend_power_state(psci_power_state_t *req_state) { unsigned int i; for (i = IMX_PWR_LVL0; i <= PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE; } void __dead2 imx_system_reset(void) { uintptr_t wdog_base = IMX_WDOG_BASE; unsigned int val; /* WDOG_B reset */ val = mmio_read_16(wdog_base); #ifdef IMX_WDOG_B_RESET val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_WDE | WDOG_WCR_WDT | WDOG_WCR_SRS; #else val = (val & 0x00FF) | WDOG_WCR_WDZST | WDOG_WCR_SRS; #endif mmio_write_16(wdog_base, val); mmio_write_16(wdog_base + WDOG_WSR, 0x5555); mmio_write_16(wdog_base + WDOG_WSR, 0xaaaa); while (1) ; } void __dead2 imx_system_off(void) { mmio_write_32(IMX_SNVS_BASE + SNVS_LPCR, SNVS_LPCR_SRTC_ENV | SNVS_LPCR_DP_EN | SNVS_LPCR_TOP); while (1) ; } void __dead2 imx_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state) { /* * before enter WAIT or STOP mode with PLAT(SCU) power down, * rbc count need to be enabled to make sure PLAT is * power down successfully even if the the wakeup IRQ is pending * early before the power down sequence. the RBC counter is * drived by the 32K OSC, so delay 30us to make sure the counter * is really running. */ if (!is_local_state_run(CLUSTER_PWR_STATE(target_state))) { imx_set_rbc_count(); udelay(30); } while (1) wfi(); } trusted-firmware-a-2.2/plat/imx/imx8m/imx8mm/000077500000000000000000000000001355360272700211275ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx8m/imx8mm/gpc.c000066400000000000000000000054701355360272700220520ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include void imx_gpc_init(void) { unsigned int val; int i; /* mask all the wakeup irq by default */ for (i = 0; i < 4; i++) { mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_A53 + i * 4, ~0x0); mmio_write_32(IMX_GPC_BASE + IMR1_CORE1_A53 + i * 4, ~0x0); mmio_write_32(IMX_GPC_BASE + IMR1_CORE2_A53 + i * 4, ~0x0); mmio_write_32(IMX_GPC_BASE + IMR1_CORE3_A53 + i * 4, ~0x0); mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_M4 + i * 4, ~0x0); } val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); /* use GIC wake_request to wakeup C0~C3 from LPM */ val |= 0x30c00000; /* clear the MASTER0 LPM handshake */ val &= ~(1 << 6); mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); /* clear MASTER1 & MASTER2 mapping in CPU0(A53) */ mmio_clrbits_32(IMX_GPC_BASE + MST_CPU_MAPPING, (MASTER1_MAPPING | MASTER2_MAPPING)); /* set all mix/PU in A53 domain */ mmio_write_32(IMX_GPC_BASE + PGC_CPU_0_1_MAPPING, 0xffff); /* * Set the CORE & SCU power up timing: * SW = 0x1, SW2ISO = 0x1; * the CPU CORE and SCU power up timming counter * is drived by 32K OSC, each domain's power up * latency is (SW + SW2ISO) / 32768 */ mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(0) + 0x4, 0x81); mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(1) + 0x4, 0x81); mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(2) + 0x4, 0x81); mmio_write_32(IMX_GPC_BASE + COREx_PGC_PCR(3) + 0x4, 0x81); mmio_write_32(IMX_GPC_BASE + PLAT_PGC_PCR + 0x4, 0x81); mmio_write_32(IMX_GPC_BASE + PGC_SCU_TIMING, (0x59 << 10) | 0x5B | (0x2 << 20)); /* set DUMMY PDN/PUP ACK by default for A53 domain */ mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_DUMMY_PUP_ACK | A53_DUMMY_PDN_ACK); /* clear DSM by default */ val = mmio_read_32(IMX_GPC_BASE + SLPCR); val &= ~SLPCR_EN_DSM; /* enable the fast wakeup wait mode */ val |= SLPCR_A53_FASTWUP_WAIT_MODE; /* clear the RBC */ val &= ~(0x3f << SLPCR_RBC_COUNT_SHIFT); /* set the STBY_COUNT to 0x5, (128 * 30)us */ val &= ~(0x7 << SLPCR_STBY_COUNT_SHFT); val |= (0x5 << SLPCR_STBY_COUNT_SHFT); mmio_write_32(IMX_GPC_BASE + SLPCR, val); /* * USB PHY power up needs to make sure RESET bit in SRC is clear, * otherwise, the PU power up bit in GPC will NOT self-cleared. * only need to do it once. */ mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG1PHY_SCR, 0x1); mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG2PHY_SCR, 0x1); /* enable all the power domain by default */ mmio_write_32(IMX_GPC_BASE + PU_PGC_UP_TRG, 0x3fcf); } trusted-firmware-a-2.2/plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c000066400000000000000000000101711355360272700245530ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const mmap_region_t imx_mmap[] = { MAP_REGION_FLAT(IMX_GIC_BASE, IMX_GIC_SIZE, MT_DEVICE | MT_RW), MAP_REGION_FLAT(IMX_AIPS_BASE, IMX_AIPS_SIZE, MT_DEVICE | MT_RW), /* AIPS map */ {0}, }; static const struct aipstz_cfg aipstz[] = { {IMX_AIPSTZ1, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, }, {IMX_AIPSTZ2, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, }, {IMX_AIPSTZ3, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, }, {IMX_AIPSTZ4, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, }, {0}, }; static const struct imx_rdc_cfg rdc[] = { /* Master domain assignment */ RDC_MDAn(0x1, DID1), /* peripherals domain permission */ /* memory region */ /* Sentinel */ {0}, }; static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; /* get SPSR for BL33 entry */ static uint32_t get_spsr_for_bl33_entry(void) { unsigned long el_status; unsigned long mode; uint32_t spsr; /* figure out what mode we enter the non-secure world */ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; el_status &= ID_AA64PFR0_ELX_MASK; mode = (el_status) ? MODE_EL2 : MODE_EL1; spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; } void bl31_tzc380_setup(void) { unsigned int val; val = mmio_read_32(IMX_IOMUX_GPR_BASE + 0x28); if ((val & GPR_TZASC_EN) != GPR_TZASC_EN) return; tzc380_init(IMX_TZASC_BASE); /* * Need to substact offset 0x40000000 from CPU address when * programming tzasc region for i.mx8mm. */ /* Enable 1G-5G S/NS RW */ tzc380_configure_region(0, 0x00000000, TZC_ATTR_REGION_SIZE(TZC_REGION_SIZE_4G) | TZC_ATTR_REGION_EN_MASK | TZC_ATTR_SP_ALL); } void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { static console_uart_t console; int i; /* Enable CSU NS access permission */ for (i = 0; i < 64; i++) { mmio_write_32(IMX_CSU_BASE + i * 4, 0x00ff00ff); } imx_aipstz_init(aipstz); imx_rdc_init(rdc); imx8m_caam_init(); console_imx_uart_register(IMX_BOOT_UART_BASE, IMX_BOOT_UART_CLK_IN_HZ, IMX_CONSOLE_BAUDRATE, &console); /* This console is only used for boot stage */ console_set_scope(&console.console, CONSOLE_FLAG_BOOT); /* * tell BL3-1 where the non-secure software image is located * and the entry state information. */ bl33_image_ep_info.pc = PLAT_NS_IMAGE_OFFSET; bl33_image_ep_info.spsr = get_spsr_for_bl33_entry(); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); bl31_tzc380_setup(); } void bl31_plat_arch_setup(void) { mmap_add_region(BL31_BASE, BL31_BASE, (BL31_LIMIT - BL31_BASE), MT_MEMORY | MT_RW | MT_SECURE); mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, (BL_CODE_END - BL_CODE_BASE), MT_MEMORY | MT_RO | MT_SECURE); #if USE_COHERENT_MEM mmap_add_region(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_BASE, (BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE), MT_DEVICE | MT_RW | MT_SECURE); #endif mmap_add(imx_mmap); init_xlat_tables(); enable_mmu_el3(0); } void bl31_platform_setup(void) { generic_delay_timer_init(); /* select the CKIL source to 32K OSC */ mmio_write_32(IMX_ANAMIX_BASE + ANAMIX_MISC_CTL, 0x1); plat_gic_driver_init(); plat_gic_init(); imx_gpc_init(); } entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type) { if (type == NON_SECURE) return &bl33_image_ep_info; if (type == SECURE) return &bl32_image_ep_info; return NULL; } unsigned int plat_get_syscnt_freq2(void) { return COUNTER_FREQUENCY; } trusted-firmware-a-2.2/plat/imx/imx8m/imx8mm/imx8mm_psci.c000066400000000000000000000022631355360272700235330ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include static const plat_psci_ops_t imx_plat_psci_ops = { .pwr_domain_on = imx_pwr_domain_on, .pwr_domain_on_finish = imx_pwr_domain_on_finish, .pwr_domain_off = imx_pwr_domain_off, .validate_ns_entrypoint = imx_validate_ns_entrypoint, .validate_power_state = imx_validate_power_state, .cpu_standby = imx_cpu_standby, .pwr_domain_suspend = imx_domain_suspend, .pwr_domain_suspend_finish = imx_domain_suspend_finish, .pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi, .get_sys_suspend_power_state = imx_get_sys_suspend_power_state, .system_reset = imx_system_reset, .system_off = imx_system_off, }; /* export the platform specific psci ops */ int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { /* sec_entrypoint is used for warm reset */ imx_mailbox_init(sec_entrypoint); *psci_ops = &imx_plat_psci_ops; return 0; } trusted-firmware-a-2.2/plat/imx/imx8m/imx8mm/include/000077500000000000000000000000001355360272700225525ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx8m/imx8mm/include/platform_def.h000066400000000000000000000070411355360272700253670ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 #define PLATFORM_STACK_SIZE 0xB00 #define CACHE_WRITEBACK_GRANULE 64 #define PLAT_PRIMARY_CPU 0x0 #define PLATFORM_MAX_CPU_PER_CLUSTER 4 #define PLATFORM_CLUSTER_COUNT 1 #define PLATFORM_CLUSTER0_CORE_COUNT 4 #define PLATFORM_CLUSTER1_CORE_COUNT 0 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT) #define IMX_PWR_LVL0 MPIDR_AFFLVL0 #define IMX_PWR_LVL1 MPIDR_AFFLVL1 #define IMX_PWR_LVL2 MPIDR_AFFLVL2 #define PWR_DOMAIN_AT_MAX_LVL U(1) #define PLAT_MAX_PWR_LVL U(2) #define PLAT_MAX_OFF_STATE U(4) #define PLAT_MAX_RET_STATE U(2) #define PLAT_WAIT_RET_STATE U(1) #define PLAT_STOP_OFF_STATE U(3) #define BL31_BASE U(0x920000) #define BL31_LIMIT U(0x940000) #define BL32_BASE U(0xbe000000) /* non-secure uboot base */ #define PLAT_NS_IMAGE_OFFSET U(0x40200000) /* GICv3 base address */ #define PLAT_GICD_BASE U(0x38800000) #define PLAT_GICR_BASE U(0x38880000) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32) #define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32) #define MAX_XLAT_TABLES 8 #define MAX_MMAP_REGIONS 16 #define HAB_RVT_BASE U(0x00000900) /* HAB_RVT for i.MX8MM */ #define IMX_BOOT_UART_BASE U(0x30890000) #define IMX_BOOT_UART_CLK_IN_HZ 24000000 /* Select 24MHz oscillator */ #define PLAT_CRASH_UART_BASE IMX_BOOT_UART_BASE #define PLAT_CRASH_UART_CLK_IN_HZ 24000000 #define IMX_CONSOLE_BAUDRATE 115200 #define IMX_AIPSTZ1 U(0x301f0000) #define IMX_AIPSTZ2 U(0x305f0000) #define IMX_AIPSTZ3 U(0x309f0000) #define IMX_AIPSTZ4 U(0x32df0000) #define IMX_AIPS_BASE U(0x30000000) #define IMX_AIPS_SIZE U(0xC00000) #define IMX_GPV_BASE U(0x32000000) #define IMX_GPV_SIZE U(0x800000) #define IMX_AIPS1_BASE U(0x30200000) #define IMX_AIPS4_BASE U(0x32c00000) #define IMX_ANAMIX_BASE U(0x30360000) #define IMX_CCM_BASE U(0x30380000) #define IMX_SRC_BASE U(0x30390000) #define IMX_GPC_BASE U(0x303a0000) #define IMX_RDC_BASE U(0x303d0000) #define IMX_CSU_BASE U(0x303e0000) #define IMX_WDOG_BASE U(0x30280000) #define IMX_SNVS_BASE U(0x30370000) #define IMX_NOC_BASE U(0x32700000) #define IMX_TZASC_BASE U(0x32F80000) #define IMX_IOMUX_GPR_BASE U(0x30340000) #define IMX_CAAM_BASE U(0x30900000) #define IMX_DDRC_BASE U(0x3d400000) #define IMX_DDRPHY_BASE U(0x3c000000) #define IMX_DDR_IPS_BASE U(0x3d000000) #define IMX_ROM_BASE U(0x0) #define GPV_BASE U(0x32000000) #define GPV_SIZE U(0x800000) #define IMX_GIC_BASE PLAT_GICD_BASE #define IMX_GIC_SIZE U(0x200000) #define WDOG_WSR U(0x2) #define WDOG_WCR_WDZST BIT(0) #define WDOG_WCR_WDBG BIT(1) #define WDOG_WCR_WDE BIT(2) #define WDOG_WCR_WDT BIT(3) #define WDOG_WCR_SRS BIT(4) #define WDOG_WCR_WDA BIT(5) #define WDOG_WCR_SRE BIT(6) #define WDOG_WCR_WDW BIT(7) #define SRC_A53RCR0 U(0x4) #define SRC_A53RCR1 U(0x8) #define SRC_OTG1PHY_SCR U(0x20) #define SRC_OTG2PHY_SCR U(0x24) #define SRC_GPR1_OFFSET U(0x74) #define SNVS_LPCR U(0x38) #define SNVS_LPCR_SRTC_ENV BIT(0) #define SNVS_LPCR_DP_EN BIT(5) #define SNVS_LPCR_TOP BIT(6) #define IOMUXC_GPR10 U(0x28) #define GPR_TZASC_EN BIT(0) #define GPR_TZASC_EN_LOCK BIT(16) #define ANAMIX_MISC_CTL U(0x124) #define MAX_CSU_NUM U(64) #define OCRAM_S_BASE U(0x00180000) #define OCRAM_S_SIZE U(0x8000) #define OCRAM_S_LIMIT (OCRAM_S_BASE + OCRAM_S_SIZE) #define COUNTER_FREQUENCY 8000000 /* 8MHz */ #define IMX_WDOG_B_RESET trusted-firmware-a-2.2/plat/imx/imx8m/imx8mm/platform.mk000066400000000000000000000027541355360272700233140ustar00rootroot00000000000000# # Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # PLAT_INCLUDES := -Iplat/imx/common/include \ -Iplat/imx/imx8m/include \ -Iplat/imx/imx8m/imx8mm/include IMX_GIC_SOURCES := drivers/arm/gic/v3/gicv3_helpers.c \ drivers/arm/gic/v3/arm_gicv3_common.c \ drivers/arm/gic/v3/gic500.c \ drivers/arm/gic/v3/gicv3_main.c \ drivers/arm/gic/common/gic_common.c \ plat/common/plat_gicv3.c \ plat/common/plat_psci_common.c \ plat/imx/common/plat_imx8_gic.c BL31_SOURCES += plat/imx/common/imx8_helpers.S \ plat/imx/imx8m/gpc_common.c \ plat/imx/imx8m/imx_aipstz.c \ plat/imx/imx8m/imx_rdc.c \ plat/imx/imx8m/imx8m_caam.c \ plat/imx/imx8m/imx8m_psci_common.c \ plat/imx/imx8m/imx8mm/imx8mm_bl31_setup.c \ plat/imx/imx8m/imx8mm/imx8mm_psci.c \ plat/imx/imx8m/imx8mm/gpc.c \ plat/imx/common/imx8_topology.c \ plat/imx/common/imx_sip_handler.c \ plat/imx/common/imx_sip_svc.c \ plat/imx/common/imx_uart_console.S \ lib/xlat_tables/aarch64/xlat_tables.c \ lib/xlat_tables/xlat_tables_common.c \ lib/cpus/aarch64/cortex_a53.S \ drivers/arm/tzc/tzc380.c \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ ${IMX_GIC_SOURCES} USE_COHERENT_MEM := 1 RESET_TO_BL31 := 1 A53_DISABLE_NON_TEMPORAL_HINT := 0 ERRATA_A53_835769 := 1 ERRATA_A53_843419 := 1 ERRATA_A53_855873 := 1 trusted-firmware-a-2.2/plat/imx/imx8m/imx8mq/000077500000000000000000000000001355360272700211335ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx8m/imx8mq/gpc.c000066400000000000000000000133061355360272700220530ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include /* use wfi power down the core */ void imx_set_cpu_pwr_off(unsigned int core_id) { /* enable the wfi power down of the core */ mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | (1 << (core_id + 20))); /* assert the pcg pcr bit of the core */ mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); }; /* if out of lpm, we need to do reverse steps */ void imx_set_cpu_lpm(unsigned int core_id, bool pdn) { if (pdn) { /* enable the core WFI PDN & IRQ PUP */ mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | (1 << (core_id + 20)) | COREx_IRQ_WUP(core_id)); /* assert the pcg pcr bit of the core */ mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); } else { /* disable CORE WFI PDN & IRQ PUP */ mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_AD, COREx_WFI_PDN(core_id) | COREx_IRQ_WUP(core_id)); /* deassert the pcg pcr bit of the core */ mmio_setbits_32(IMX_GPC_BASE + COREx_PGC_PCR(core_id), 0x1); } } void imx_pup_pdn_slot_config(int last_core, bool pdn) { if (pdn) { /* SLOT0 for A53 PLAT power down */ mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(0), SLT_PLAT_PDN); /* SLOT1 for A53 PLAT power up */ mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(1), SLT_PLAT_PUP); /* SLOT2 for A53 primary core power up */ mmio_setbits_32(IMX_GPC_BASE + SLTx_CFG(2), SLT_COREx_PUP(last_core)); /* ACK setting: PLAT ACK for PDN, CORE ACK for PUP */ mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF, A53_PLAT_PDN_ACK | A53_PLAT_PUP_ACK); } else { mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(0), 0xFFFFFFFF); mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(1), 0xFFFFFFFF); mmio_clrbits_32(IMX_GPC_BASE + SLTx_CFG(2), 0xFFFFFFFF); mmio_clrsetbits_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, 0xFFFFFFFF, A53_DUMMY_PDN_ACK | A53_DUMMY_PUP_ACK); } } void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state) { uint32_t val; if (is_local_state_off(power_state)) { val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); val |= A53_LPM_STOP; /* enable C0-C1's STOP mode */ val &= ~CPU_CLOCK_ON_LPM; /* disable CPU clock in LPM mode */ mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); /* enable C2-3's STOP mode */ mmio_setbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_STOP); /* enable PLAT/SCU power down */ val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD); val &= ~EN_L2_WFI_PDN; val |= L2PGE | EN_PLAT_PDN; val &= ~COREx_IRQ_WUP(last_core); /* disable IRQ PUP for last core */ val |= COREx_LPM_PUP(last_core); /* enable LPM PUP for last core */ mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); imx_pup_pdn_slot_config(last_core, true); /* enable PLAT PGC */ mmio_setbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1); } else { /* clear PLAT PGC */ mmio_clrbits_32(IMX_GPC_BASE + A53_PLAT_PGC, 0x1); /* clear the slot and ack for cluster power down */ imx_pup_pdn_slot_config(last_core, false); val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); val &= ~A53_LPM_MASK; /* clear the C0~1 LPM */ val |= CPU_CLOCK_ON_LPM; /* disable cpu clock in LPM */ mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); /* set A53 LPM to RUN mode */ mmio_clrbits_32(IMX_GPC_BASE + LPCR_A53_BSC2, A53_LPM_MASK); /* clear PLAT/SCU power down */ val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_AD); val |= EN_L2_WFI_PDN; val &= ~(L2PGE | EN_PLAT_PDN); val &= ~COREx_LPM_PUP(last_core); /* disable C0's LPM PUP */ mmio_write_32(IMX_GPC_BASE + LPCR_A53_AD, val); } } void imx_gpc_init(void) { uint32_t val; int i; /* mask all the interrupt by default */ for (i = 0; i < 4; i++) { mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_A53 + i * 4, ~0x0); mmio_write_32(IMX_GPC_BASE + IMR1_CORE1_A53 + i * 4, ~0x0); mmio_write_32(IMX_GPC_BASE + IMR1_CORE2_A53 + i * 4, ~0x0); mmio_write_32(IMX_GPC_BASE + IMR1_CORE3_A53 + i * 4, ~0x0); mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_M4 + i * 4, ~0x0); } /* Due to the hardware design requirement, need to make * sure GPR interrupt(#32) is unmasked during RUN mode to * avoid entering DSM mode by mistake. */ mmio_write_32(IMX_GPC_BASE + IMR1_CORE0_A53, 0xFFFFFFFE); mmio_write_32(IMX_GPC_BASE + IMR1_CORE1_A53, 0xFFFFFFFE); mmio_write_32(IMX_GPC_BASE + IMR1_CORE2_A53, 0xFFFFFFFE); mmio_write_32(IMX_GPC_BASE + IMR1_CORE3_A53, 0xFFFFFFFE); /* use external IRQs to wakeup C0~C3 from LPM */ val = mmio_read_32(IMX_GPC_BASE + LPCR_A53_BSC); val |= IRQ_SRC_A53_WUP; /* clear the MASTER0 LPM handshake */ val &= ~MASTER0_LPM_HSK; mmio_write_32(IMX_GPC_BASE + LPCR_A53_BSC, val); /* mask M4 DSM trigger if M4 is NOT enabled */ mmio_setbits_32(IMX_GPC_BASE + LPCR_M4, DSM_MODE_MASK); /* set all mix/PU in A53 domain */ mmio_write_32(IMX_GPC_BASE + PGC_CPU_0_1_MAPPING, 0xfffd); /* set SCU timming */ mmio_write_32(IMX_GPC_BASE + PGC_SCU_TIMING, (0x59 << 10) | 0x5B | (0x2 << 20)); /* set DUMMY PDN/PUP ACK by default for A53 domain */ mmio_write_32(IMX_GPC_BASE + PGC_ACK_SEL_A53, A53_DUMMY_PUP_ACK | A53_DUMMY_PDN_ACK); /* disable DSM mode by default */ mmio_clrbits_32(IMX_GPC_BASE + SLPCR, DSM_MODE_MASK); /* * USB PHY power up needs to make sure RESET bit in SRC is clear, * otherwise, the PU power up bit in GPC will NOT self-cleared. * only need to do it once. */ mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG1PHY_SCR, 0x1); mmio_clrbits_32(IMX_SRC_BASE + SRC_OTG2PHY_SCR, 0x1); /* enable all the power domain by default */ mmio_write_32(IMX_GPC_BASE + PU_PGC_UP_TRG, 0x3fcf); } trusted-firmware-a-2.2/plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c000066400000000000000000000120171355360272700245640ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static const mmap_region_t imx_mmap[] = { MAP_REGION_FLAT(GPV_BASE, GPV_SIZE, MT_DEVICE | MT_RW), /* GPV map */ MAP_REGION_FLAT(IMX_ROM_BASE, IMX_ROM_SIZE, MT_MEMORY | MT_RO), /* ROM map */ MAP_REGION_FLAT(IMX_AIPS_BASE, IMX_AIPS_SIZE, MT_DEVICE | MT_RW), /* AIPS map */ MAP_REGION_FLAT(IMX_GIC_BASE, IMX_GIC_SIZE, MT_DEVICE | MT_RW), /* GIC map */ {0}, }; static const struct aipstz_cfg aipstz[] = { {AIPSTZ1_BASE, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, }, {AIPSTZ2_BASE, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, }, {AIPSTZ3_BASE, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, }, {AIPSTZ4_BASE, 0x77777777, 0x77777777, .opacr = {0x0, 0x0, 0x0, 0x0, 0x0}, }, {0}, }; static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; static uint32_t imx_soc_revision; int imx_soc_info_handler(uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3) { return imx_soc_revision; } #define ANAMIX_DIGPROG 0x6c #define ROM_SOC_INFO_A0 0x800 #define ROM_SOC_INFO_B0 0x83C #define OCOTP_SOC_INFO_B1 0x40 static void imx8mq_soc_info_init(void) { uint32_t rom_version; uint32_t ocotp_val; imx_soc_revision = mmio_read_32(IMX_ANAMIX_BASE + ANAMIX_DIGPROG); rom_version = mmio_read_8(IMX_ROM_BASE + ROM_SOC_INFO_A0); if (rom_version == 0x10) return; rom_version = mmio_read_8(IMX_ROM_BASE + ROM_SOC_INFO_B0); if (rom_version == 0x20) { imx_soc_revision &= ~0xff; imx_soc_revision |= rom_version; return; } /* 0xff0055aa is magic number for B1 */ ocotp_val = mmio_read_32(IMX_OCOTP_BASE + OCOTP_SOC_INFO_B1); if (ocotp_val == 0xff0055aa) { imx_soc_revision &= ~0xff; imx_soc_revision |= 0x21; return; } } /* get SPSR for BL33 entry */ static uint32_t get_spsr_for_bl33_entry(void) { unsigned long el_status; unsigned long mode; uint32_t spsr; /* figure out what mode we enter the non-secure world */ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; el_status &= ID_AA64PFR0_ELX_MASK; mode = (el_status) ? MODE_EL2 : MODE_EL1; spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; } static void bl31_tz380_setup(void) { unsigned int val; val = mmio_read_32(IMX_IOMUX_GPR_BASE + IOMUXC_GPR10); if ((val & GPR_TZASC_EN) != GPR_TZASC_EN) return; tzc380_init(IMX_TZASC_BASE); /* * Need to substact offset 0x40000000 from CPU address when * programming tzasc region for i.mx8mq. Enable 1G-5G S/NS RW */ tzc380_configure_region(0, 0x00000000, TZC_ATTR_REGION_SIZE(TZC_REGION_SIZE_4G) | TZC_ATTR_REGION_EN_MASK | TZC_ATTR_SP_ALL); } void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { int i; /* enable CSU NS access permission */ for (i = 0; i < 64; i++) { mmio_write_32(IMX_CSU_BASE + i * 4, 0xffffffff); } imx_aipstz_init(aipstz); imx8m_caam_init(); #if DEBUG_CONSOLE static console_uart_t console; console_imx_uart_register(IMX_BOOT_UART_BASE, IMX_BOOT_UART_CLK_IN_HZ, IMX_CONSOLE_BAUDRATE, &console); #endif /* * tell BL3-1 where the non-secure software image is located * and the entry state information. */ bl33_image_ep_info.pc = PLAT_NS_IMAGE_OFFSET; bl33_image_ep_info.spsr = get_spsr_for_bl33_entry(); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); bl31_tz380_setup(); } void bl31_plat_arch_setup(void) { mmap_add_region(BL31_BASE, BL31_BASE, (BL31_LIMIT - BL31_BASE), MT_MEMORY | MT_RW | MT_SECURE); mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, (BL_CODE_END - BL_CODE_BASE), MT_MEMORY | MT_RO | MT_SECURE); mmap_add(imx_mmap); #if USE_COHERENT_MEM mmap_add_region(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, MT_DEVICE | MT_RW | MT_SECURE); #endif /* setup xlat table */ init_xlat_tables(); /* enable the MMU */ enable_mmu_el3(0); } void bl31_platform_setup(void) { generic_delay_timer_init(); /* init the GICv3 cpu and distributor interface */ plat_gic_driver_init(); plat_gic_init(); /* determine SOC revision for erratas */ imx8mq_soc_info_init(); /* gpc init */ imx_gpc_init(); } entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type) { if (type == NON_SECURE) return &bl33_image_ep_info; if (type == SECURE) return &bl32_image_ep_info; return NULL; } unsigned int plat_get_syscnt_freq2(void) { return COUNTER_FREQUENCY; } void bl31_plat_runtime_setup(void) { return; } trusted-firmware-a-2.2/plat/imx/imx8m/imx8mq/imx8mq_psci.c000066400000000000000000000070701355360272700235440ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include int imx_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { int pwr_lvl = psci_get_pstate_pwrlvl(power_state); int pwr_type = psci_get_pstate_type(power_state); int state_id = psci_get_pstate_id(power_state); if (pwr_lvl > PLAT_MAX_PWR_LVL) return PSCI_E_INVALID_PARAMS; if (pwr_type == PSTATE_TYPE_STANDBY) { CORE_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; } if (pwr_type == PSTATE_TYPE_POWERDOWN && state_id == 0x33) { CORE_PWR_STATE(req_state) = PLAT_MAX_OFF_STATE; CLUSTER_PWR_STATE(req_state) = PLAT_MAX_RET_STATE; } return PSCI_E_SUCCESS; } void imx_domain_suspend(const psci_power_state_t *target_state) { uint64_t base_addr = BL31_BASE; uint64_t mpidr = read_mpidr_el1(); unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); if (is_local_state_off(CORE_PWR_STATE(target_state))) { /* disable the cpu interface */ plat_gic_cpuif_disable(); imx_set_cpu_secure_entry(core_id, base_addr); imx_set_cpu_lpm(core_id, true); } else { dsb(); write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); isb(); } if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) imx_set_cluster_powerdown(core_id, true); else imx_set_cluster_standby(true); if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) { imx_set_sys_lpm(core_id, true); } } void imx_domain_suspend_finish(const psci_power_state_t *target_state) { uint64_t mpidr = read_mpidr_el1(); unsigned int core_id = MPIDR_AFFLVL0_VAL(mpidr); /* check the system level status */ if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) { imx_set_sys_lpm(core_id, false); imx_clear_rbc_count(); } /* check the cluster level power status */ if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) imx_set_cluster_powerdown(core_id, false); else imx_set_cluster_standby(false); /* check the core level power status */ if (is_local_state_off(CORE_PWR_STATE(target_state))) { /* clear the core lpm setting */ imx_set_cpu_lpm(core_id, false); /* enable the gic cpu interface */ plat_gic_cpuif_enable(); } else { write_scr_el3(read_scr_el3() & (~0x4)); isb(); } } void imx_get_sys_suspend_power_state(psci_power_state_t *req_state) { unsigned int i; for (i = IMX_PWR_LVL0; i < PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = PLAT_STOP_OFF_STATE; req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_MAX_RET_STATE; } static const plat_psci_ops_t imx_plat_psci_ops = { .pwr_domain_on = imx_pwr_domain_on, .pwr_domain_on_finish = imx_pwr_domain_on_finish, .pwr_domain_off = imx_pwr_domain_off, .validate_ns_entrypoint = imx_validate_ns_entrypoint, .validate_power_state = imx_validate_power_state, .cpu_standby = imx_cpu_standby, .pwr_domain_suspend = imx_domain_suspend, .pwr_domain_suspend_finish = imx_domain_suspend_finish, .pwr_domain_pwr_down_wfi = imx_pwr_domain_pwr_down_wfi, .get_sys_suspend_power_state = imx_get_sys_suspend_power_state, .system_reset = imx_system_reset, .system_off = imx_system_off, }; /* export the platform specific psci ops */ int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { imx_mailbox_init(sec_entrypoint); /* sec_entrypoint is used for warm reset */ *psci_ops = &imx_plat_psci_ops; return 0; } trusted-firmware-a-2.2/plat/imx/imx8m/imx8mq/include/000077500000000000000000000000001355360272700225565ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx8m/imx8mq/include/platform_def.h000066400000000000000000000070771355360272700254040ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 #define PLATFORM_STACK_SIZE 0x800 #define CACHE_WRITEBACK_GRANULE 64 #define PLAT_PRIMARY_CPU 0x0 #define PLATFORM_MAX_CPU_PER_CLUSTER 4 #define PLATFORM_CLUSTER_COUNT 1 #define PLATFORM_CLUSTER0_CORE_COUNT 4 #define PLATFORM_CLUSTER1_CORE_COUNT 0 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT) #define IMX_PWR_LVL0 MPIDR_AFFLVL0 #define IMX_PWR_LVL1 MPIDR_AFFLVL1 #define IMX_PWR_LVL2 MPIDR_AFFLVL2 #define PWR_DOMAIN_AT_MAX_LVL U(1) #define PLAT_MAX_PWR_LVL U(2) #define PLAT_MAX_OFF_STATE U(4) #define PLAT_MAX_RET_STATE U(1) #define PLAT_WAIT_RET_STATE PLAT_MAX_RET_STATE #define PLAT_WAIT_OFF_STATE U(2) #define PLAT_STOP_OFF_STATE U(3) #define BL31_BASE U(0x910000) #define BL31_LIMIT U(0x920000) #define BL32_BASE U(0xfe000000) /* non-secure uboot base */ #define PLAT_NS_IMAGE_OFFSET U(0x40200000) /* GICv3 base address */ #define PLAT_GICD_BASE U(0x38800000) #define PLAT_GICR_BASE U(0x38880000) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32) #define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32) #define MAX_XLAT_TABLES 4 #define MAX_MMAP_REGIONS 14 #define HAB_RVT_BASE U(0x00000880) /* HAB_RVT for i.MX8MQ */ #define IMX_BOOT_UART_BASE U(0x30860000) #define IMX_BOOT_UART_CLK_IN_HZ 25000000 /* Select 25Mhz oscillator */ #define PLAT_CRASH_UART_BASE IMX_BOOT_UART_BASE #define PLAT_CRASH_UART_CLK_IN_HZ 25000000 #define IMX_CONSOLE_BAUDRATE 115200 #define IMX_AIPS_BASE U(0x30200000) #define IMX_AIPS_SIZE U(0xC00000) #define IMX_AIPS1_BASE U(0x30200000) #define IMX_AIPS3_ARB_BASE U(0x30800000) #define IMX_OCOTP_BASE U(0x30350000) #define IMX_ANAMIX_BASE U(0x30360000) #define IMX_CCM_BASE U(0x30380000) #define IMX_SRC_BASE U(0x30390000) #define IMX_GPC_BASE U(0x303a0000) #define IMX_RDC_BASE U(0x303d0000) #define IMX_CSU_BASE U(0x303e0000) #define IMX_WDOG_BASE U(0x30280000) #define IMX_SNVS_BASE U(0x30370000) #define IMX_NOC_BASE U(0x32700000) #define IMX_TZASC_BASE U(0x32F80000) #define IMX_CAAM_BASE U(0x30900000) #define IMX_IOMUX_GPR_BASE U(0x30340000) #define IMX_DDRC_BASE U(0x3d400000) #define IMX_DDRPHY_BASE U(0x3c000000) #define IMX_DDR_IPS_BASE U(0x3d000000) #define IMX_ROM_BASE U(0x00000000) #define IMX_ROM_SIZE U(0x20000) #define AIPSTZ1_BASE U(0x301f0000) #define AIPSTZ2_BASE U(0x305f0000) #define AIPSTZ3_BASE U(0x309f0000) #define AIPSTZ4_BASE U(0x32df0000) #define GPV_BASE U(0x32000000) #define GPV_SIZE U(0x800000) #define IMX_GIC_BASE PLAT_GICD_BASE #define IMX_GIC_SIZE U(0x200000) #define WDOG_WSR U(0x2) #define WDOG_WCR_WDZST BIT(0) #define WDOG_WCR_WDBG BIT(1) #define WDOG_WCR_WDE BIT(2) #define WDOG_WCR_WDT BIT(3) #define WDOG_WCR_SRS BIT(4) #define WDOG_WCR_WDA BIT(5) #define WDOG_WCR_SRE BIT(6) #define WDOG_WCR_WDW BIT(7) #define SRC_A53RCR0 U(0x4) #define SRC_A53RCR1 U(0x8) #define SRC_OTG1PHY_SCR U(0x20) #define SRC_OTG2PHY_SCR U(0x24) #define SRC_GPR1_OFFSET U(0x74) #define SNVS_LPCR U(0x38) #define SNVS_LPCR_SRTC_ENV BIT(0) #define SNVS_LPCR_DP_EN BIT(5) #define SNVS_LPCR_TOP BIT(6) #define IOMUXC_GPR10 U(0x28) #define GPR_TZASC_EN BIT(0) #define GPR_TZASC_EN_LOCK BIT(16) #define OCRAM_S_BASE U(0x00180000) #define OCRAM_S_SIZE U(0x8000) #define OCRAM_S_LIMIT (OCRAM_S_BASE + OCRAM_S_SIZE) #define COUNTER_FREQUENCY 8000000 /* 8MHz */ #define DEBUG_CONSOLE 0 #define IMX_WDOG_B_RESET trusted-firmware-a-2.2/plat/imx/imx8m/imx8mq/platform.mk000066400000000000000000000027201355360272700233110ustar00rootroot00000000000000# # Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # PLAT_INCLUDES := -Iplat/imx/common/include \ -Iplat/imx/imx8m/include \ -Iplat/imx/imx8m/imx8mq/include IMX_GIC_SOURCES := drivers/arm/gic/v3/gicv3_helpers.c \ drivers/arm/gic/v3/arm_gicv3_common.c \ drivers/arm/gic/v3/gic500.c \ drivers/arm/gic/v3/gicv3_main.c \ drivers/arm/gic/common/gic_common.c \ plat/common/plat_gicv3.c \ plat/common/plat_psci_common.c \ plat/imx/common/plat_imx8_gic.c BL31_SOURCES += plat/imx/common/imx8_helpers.S \ plat/imx/imx8m/imx8mq/imx8mq_bl31_setup.c \ plat/imx/imx8m/imx8mq/imx8mq_psci.c \ plat/imx/imx8m/gpc_common.c \ plat/imx/imx8m/imx_aipstz.c \ plat/imx/imx8m/imx8m_caam.c \ plat/imx/imx8m/imx8m_psci_common.c \ plat/imx/imx8m/imx8mq/gpc.c \ plat/imx/common/imx8_topology.c \ plat/imx/common/imx_sip_handler.c \ plat/imx/common/imx_sip_svc.c \ plat/imx/common/imx_uart_console.S \ lib/xlat_tables/aarch64/xlat_tables.c \ lib/xlat_tables/xlat_tables_common.c \ lib/cpus/aarch64/cortex_a53.S \ drivers/arm/tzc/tzc380.c \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ ${IMX_GIC_SOURCES} USE_COHERENT_MEM := 1 RESET_TO_BL31 := 1 A53_DISABLE_NON_TEMPORAL_HINT := 0 ERRATA_A53_835769 := 1 ERRATA_A53_843419 := 1 ERRATA_A53_855873 := 1 trusted-firmware-a-2.2/plat/imx/imx8m/imx_aipstz.c000066400000000000000000000010621355360272700222420ustar00rootroot00000000000000/* * Copyright (c) 2019, Arm Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include void imx_aipstz_init(const struct aipstz_cfg *aipstz_cfg) { const struct aipstz_cfg *aipstz = aipstz_cfg; while (aipstz->base != 0U) { mmio_write_32(aipstz->base + AIPSTZ_MPR0, aipstz->mpr0); mmio_write_32(aipstz->base + AIPSTZ_MPR1, aipstz->mpr1); for (int i = 0; i < AIPSTZ_OPACR_NUM; i++) mmio_write_32(aipstz->base + OPACR_OFFSET(i), aipstz->opacr[i]); aipstz++; } } trusted-firmware-a-2.2/plat/imx/imx8m/imx_rdc.c000066400000000000000000000015421355360272700215030ustar00rootroot00000000000000/* * Copyright (c) 2019, NXP. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include void imx_rdc_init(const struct imx_rdc_cfg *rdc_cfg) { const struct imx_rdc_cfg *rdc = rdc_cfg; while (rdc->type != RDC_INVALID) { switch (rdc->type) { case RDC_MDA: /* MDA config */ mmio_write_32(MDAn(rdc->index), rdc->setting.rdc_mda); break; case RDC_PDAP: /* peripheral access permission config */ mmio_write_32(PDAPn(rdc->index), rdc->setting.rdc_pdap); break; case RDC_MEM_REGION: /* memory region access permission config */ mmio_write_32(MRSAn(rdc->index), rdc->setting.rdc_mem_region[0]); mmio_write_32(MREAn(rdc->index), rdc->setting.rdc_mem_region[1]); mmio_write_32(MRCn(rdc->index), rdc->setting.rdc_mem_region[2]); break; default: break; } rdc++; } } trusted-firmware-a-2.2/plat/imx/imx8m/include/000077500000000000000000000000001355360272700213335ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx8m/include/gpc.h000066400000000000000000000065521355360272700222650ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX8M_GPC_H #define IMX8M_GPC_H #define LPCR_A53_BSC 0x0 #define LPCR_A53_BSC2 0x108 #define LPCR_A53_AD 0x4 #define LPCR_M4 0x8 #define SLPCR 0x14 #define MST_CPU_MAPPING 0x18 #define MLPCR 0x20 #define PGC_ACK_SEL_A53 0x24 #define IMR1_CORE0_A53 0x30 #define IMR1_CORE1_A53 0x40 #define IMR1_CORE2_A53 0x1C0 #define IMR1_CORE3_A53 0x1D0 #define IMR1_CORE0_M4 0x50 #define SLT0_CFG 0xB0 #define GPC_PU_PWRHSK 0x1FC #define PGC_CPU_0_1_MAPPING 0xEC #define CPU_PGC_UP_TRG 0xF0 #define PU_PGC_UP_TRG 0xF8 #define CPU_PGC_DN_TRG 0xFC #define PU_PGC_DN_TRG 0x104 #define A53_CORE0_PGC 0x800 #define A53_PLAT_PGC 0x900 #define PLAT_PGC_PCR 0x900 #define PGC_SCU_TIMING 0x910 #define MASK_DSM_TRIGGER_A53 BIT(31) #define IRQ_SRC_A53_WUP BIT(30) #define IRQ_SRC_A53_WUP_SHIFT 30 #define IRQ_SRC_C1 BIT(29) #define IRQ_SRC_C0 BIT(28) #define IRQ_SRC_C3 BIT(23) #define IRQ_SRC_C2 BIT(22) #define CPU_CLOCK_ON_LPM BIT(14) #define A53_CLK_ON_LPM BIT(14) #define MASTER0_LPM_HSK BIT(6) #define L2PGE BIT(31) #define EN_L2_WFI_PDN BIT(5) #define EN_PLAT_PDN BIT(4) #define SLPCR_EN_DSM BIT(31) #define SLPCR_RBC_EN BIT(30) #define SLPCR_A53_FASTWUP_STOP_MODE BIT(17) #define SLPCR_A53_FASTWUP_WAIT_MODE BIT(16) #define SLPCR_VSTBY BIT(2) #define SLPCR_SBYOS BIT(1) #define SLPCR_BYPASS_PMIC_READY BIT(0) #define SLPCR_RBC_COUNT_SHIFT 24 #define SLPCR_STBY_COUNT_SHFT 3 #define A53_DUMMY_PDN_ACK BIT(15) #define A53_DUMMY_PUP_ACK BIT(31) #define A53_PLAT_PDN_ACK BIT(2) #define A53_PLAT_PUP_ACK BIT(18) #define PLAT_PUP_SLT_CTRL BIT(9) #define PLAT_PDN_SLT_CTRL BIT(8) #define SLT_PLAT_PDN BIT(8) #define SLT_PLAT_PUP BIT(9) #define MASTER1_MAPPING BIT(1) #define MASTER2_MAPPING BIT(2) /* helper macro */ #define A53_LPM_MASK U(0xF) #define A53_LPM_WAIT U(0x5) #define A53_LPM_STOP U(0xA) #define LPM_MODE(local_state) ((local_state) == PLAT_WAIT_RET_STATE ? A53_LPM_WAIT : A53_LPM_STOP) #define DSM_MODE_MASK BIT(31) #define A53_CORE_WUP_SRC(core_id) (1 << ((core_id) < 2 ? 28 + (core_id) : 22 + (core_id) - 2)) #define COREx_PGC_PCR(core_id) (0x800 + (core_id) * 0x40) #define COREx_WFI_PDN(core_id) (1 << ((core_id) < 2 ? (core_id) * 2 : ((core_id) - 2) * 2 + 16)) #define COREx_IRQ_WUP(core_id) ((core_id) < 2 ? (1 << ((core_id) * 2 + 8)) : (1 << ((core_id) * 2 + 20))) #define COREx_LPM_PUP(core_id) ((core_id) < 2 ? (1 << ((core_id) * 2 + 9)) : (1 << ((core_id) * 2 + 21))) #define SLTx_CFG(n) ((SLT0_CFG + ((n) * 4))) #define SLT_COREx_PUP(core_id) (0x2 << ((core_id) * 2)) #define IRQ_IMR_NUM 4 #define IMR_MASK_ALL 0xffffffff /* function declare */ void imx_gpc_init(void); void imx_set_cpu_secure_entry(unsigned int core_index, uintptr_t sec_entrypoint); void imx_set_cpu_pwr_off(unsigned int core_index); void imx_set_cpu_pwr_on(unsigned int core_index); void imx_set_cpu_lpm(unsigned int core_index, bool pdn); void imx_set_cluster_standby(bool retention); void imx_set_cluster_powerdown(unsigned int last_core, uint8_t power_state); void imx_noc_slot_config(bool pdn); void imx_set_sys_wakeup(unsigned int last_core, bool pdn); void imx_set_sys_lpm(unsigned last_core, bool retention); void imx_set_rbc_count(void); void imx_clear_rbc_count(void); #endif /*IMX8M_GPC_H */ trusted-firmware-a-2.2/plat/imx/imx8m/include/imx8m_caam.h000066400000000000000000000014741355360272700235350ustar00rootroot00000000000000/* * Copyright (c) 2019, NXP. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX8M_CAAM_H #define IMX8M_CAAM_H #include #include #define CAAM_JR0MID (IMX_CAAM_BASE + 0x10) #define CAAM_JR1MID (IMX_CAAM_BASE + 0x18) #define CAAM_JR2MID (IMX_CAAM_BASE + 0x20) #define CAAM_NS_MID (0x1) #define JR0_BASE (IMX_CAAM_BASE + 0x1000) #define SM_P0_PERM (JR0_BASE + 0xa04) #define SM_P0_SMAG2 (JR0_BASE + 0xa08) #define SM_P0_SMAG1 (JR0_BASE + 0xa0c) #define SM_CMD (JR0_BASE + 0xbe4) /* secure memory command */ #define SMC_PAGE_SHIFT 16 #define SMC_PART_SHIFT 8 #define SMC_CMD_ALLOC_PAGE 0x01 /* allocate page to this partition */ #define SMC_CMD_DEALLOC_PART 0x03 /* deallocate partition */ void imx8m_caam_init(void); #endif /* IMX8M_CAAM_H */ trusted-firmware-a-2.2/plat/imx/imx8m/include/imx8m_psci.h000066400000000000000000000022061355360272700235640ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX8M_PSCI_H #define IMX8M_PSCI_H #define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0]) #define CLUSTER_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL1]) #define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) int imx_pwr_domain_on(u_register_t mpidr); void imx_pwr_domain_on_finish(const psci_power_state_t *target_state); void imx_pwr_domain_off(const psci_power_state_t *target_state); int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint); int imx_validate_power_state(unsigned int power_state, psci_power_state_t *rq_state); void imx_cpu_standby(plat_local_state_t cpu_state); void imx_domain_suspend(const psci_power_state_t *target_state); void imx_domain_suspend_finish(const psci_power_state_t *target_state); void imx_get_sys_suspend_power_state(psci_power_state_t *req_state); void __dead2 imx_system_reset(void); void __dead2 imx_system_off(void); void __dead2 imx_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state); #endif /* IMX8M_PSCI_H */ trusted-firmware-a-2.2/plat/imx/imx8m/include/imx_aipstz.h000066400000000000000000000010141355360272700236670ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX_AIPSTZ_H #define IMX_AIPSTZ_H #include #define AIPSTZ_MPR0 U(0x0) #define AIPSTZ_MPR1 U(0x4) #define AIPSTZ_OPACR_NUM U(0x5) #define OPACR_OFFSET(i) U((i) * 4 + 0x40) struct aipstz_cfg { uintptr_t base; uint32_t mpr0; uint32_t mpr1; uint32_t opacr[AIPSTZ_OPACR_NUM]; }; void imx_aipstz_init(const struct aipstz_cfg *aipstz_cfg); #endif /* IMX_AIPSTZ_H */ trusted-firmware-a-2.2/plat/imx/imx8m/include/imx_rdc.h000066400000000000000000000030671355360272700231370ustar00rootroot00000000000000/* * Copyright (c) 2019, NXP. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IMX_RDC_H #define IMX_RDC_H #include #include #define MDAn(x) (IMX_RDC_BASE + 0x200 + (x) * 4) #define PDAPn(x) (IMX_RDC_BASE + 0x400 + (x) * 4) #define MRSAn(x) (IMX_RDC_BASE + 0x800 + (x) * 4) #define MREAn(x) (IMX_RDC_BASE + 0x804 + (x) * 4) #define MRCn(x) (IMX_RDC_BASE + 0x808 + (x) * 4) #define LCK BIT(31) #define SREQ BIT(30) #define ENA BIT(30) #define DID0 U(0x0) #define DID1 U(0x1) #define DID2 U(0x2) #define DID3 U(0x3) #define D3R BIT(7) #define D3W BIT(6) #define D2R BIT(5) #define D2W BIT(4) #define D1R BIT(3) #define D1W BIT(2) #define D0R BIT(1) #define D0W BIT(0) union rdc_setting { uint32_t rdc_mda; /* Master Domain Assignment */ uint32_t rdc_pdap; /* Peripheral Domain Access Permissions */ uint32_t rdc_mem_region[3]; /* Memory Region Access Control */ }; enum rdc_type { RDC_INVALID, RDC_MDA, RDC_PDAP, RDC_MEM_REGION, }; struct imx_rdc_cfg { enum rdc_type type; /* config type Master, Peripheral or Memory region */ int index; union rdc_setting setting; }; #define RDC_MDAn(i, mda) \ {RDC_MDA, (i), .setting.rdc_mda = (mda), } #define RDC_PDAPn(i, pdap) \ {RDC_PDAP, (i), .setting.rdc_pdap = (pdap), } #define RDC_MEM_REGIONn(i, msa, mea, mrc) \ { RDC_MEM_REGION, (i), \ .setting.rdc_mem_region[0] = (msa), \ .setting.rdc_mem_region[1] = (mea), \ .setting.rdc_mem_region[2] = (mrc), \ } void imx_rdc_init(const struct imx_rdc_cfg *cfg); #endif /* IMX_RDC_H */ trusted-firmware-a-2.2/plat/imx/imx8qm/000077500000000000000000000000001355360272700200715ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx8qm/imx8qm_bl31_setup.c000066400000000000000000000260321355360272700235240ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include IMPORT_SYM(unsigned long, __COHERENT_RAM_START__, BL31_COHERENT_RAM_START); IMPORT_SYM(unsigned long, __COHERENT_RAM_END__, BL31_COHERENT_RAM_END); IMPORT_SYM(unsigned long, __RO_START__, BL31_RO_START); IMPORT_SYM(unsigned long, __RO_END__, BL31_RO_END); IMPORT_SYM(unsigned long, __RW_START__, BL31_RW_START); IMPORT_SYM(unsigned long, __RW_END__, BL31_RW_END); static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; #define UART_PAD_CTRL (PADRING_IFMUX_EN_MASK | PADRING_GP_EN_MASK | \ (SC_PAD_CONFIG_OUT_IN << PADRING_CONFIG_SHIFT) | \ (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \ (SC_PAD_28FDSOI_DSE_DV_LOW << PADRING_DSE_SHIFT) | \ (SC_PAD_28FDSOI_PS_PD << PADRING_PULL_SHIFT)) const static int imx8qm_cci_map[] = { CLUSTER0_CCI_SLVAE_IFACE, CLUSTER1_CCI_SLVAE_IFACE }; static const mmap_region_t imx_mmap[] = { MAP_REGION_FLAT(IMX_REG_BASE, IMX_REG_SIZE, MT_DEVICE | MT_RW), {0} }; static uint32_t get_spsr_for_bl33_entry(void) { unsigned long el_status; unsigned long mode; uint32_t spsr; /* figure out what mode we enter the non-secure world */ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; el_status &= ID_AA64PFR0_ELX_MASK; mode = (el_status) ? MODE_EL2 : MODE_EL1; spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; } #if DEBUG_CONSOLE_A53 static void lpuart32_serial_setbrg(unsigned int base, int baudrate) { unsigned int sbr, osr, baud_diff, tmp_osr, tmp_sbr; unsigned int diff1, diff2, tmp, rate; if (baudrate == 0) panic(); sc_pm_get_clock_rate(ipc_handle, SC_R_UART_0, 2, &rate); baud_diff = baudrate; osr = 0; sbr = 0; for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) { tmp_sbr = (rate / (baudrate * tmp_osr)); if (tmp_sbr == 0) tmp_sbr = 1; /* calculate difference in actual baud w/ current values */ diff1 = rate / (tmp_osr * tmp_sbr) - baudrate; diff2 = rate / (tmp_osr * (tmp_sbr + 1)); /* select best values between sbr and sbr+1 */ if (diff1 > (baudrate - diff2)) { diff1 = baudrate - diff2; tmp_sbr++; } if (diff1 <= baud_diff) { baud_diff = diff1; osr = tmp_osr; sbr = tmp_sbr; } } tmp = mmio_read_32(IMX_BOOT_UART_BASE + BAUD); if ((osr > 3) && (osr < 8)) tmp |= LPUART_BAUD_BOTHEDGE_MASK; tmp &= ~LPUART_BAUD_OSR_MASK; tmp |= LPUART_BAUD_OSR(osr - 1); tmp &= ~LPUART_BAUD_SBR_MASK; tmp |= LPUART_BAUD_SBR(sbr); /* explicitly disable 10 bit mode & set 1 stop bit */ tmp &= ~(LPUART_BAUD_M10_MASK | LPUART_BAUD_SBNS_MASK); mmio_write_32(IMX_BOOT_UART_BASE + BAUD, tmp); } static int lpuart32_serial_init(unsigned int base) { unsigned int tmp; /* disable TX & RX before enabling clocks */ tmp = mmio_read_32(IMX_BOOT_UART_BASE + CTRL); tmp &= ~(CTRL_TE | CTRL_RE); mmio_write_32(IMX_BOOT_UART_BASE + CTRL, tmp); mmio_write_32(IMX_BOOT_UART_BASE + MODIR, 0); mmio_write_32(IMX_BOOT_UART_BASE + FIFO, ~(FIFO_TXFE | FIFO_RXFE)); mmio_write_32(IMX_BOOT_UART_BASE + MATCH, 0); /* provide data bits, parity, stop bit, etc */ lpuart32_serial_setbrg(base, IMX_BOOT_UART_BAUDRATE); /* eight data bits no parity bit */ tmp = mmio_read_32(IMX_BOOT_UART_BASE + CTRL); tmp &= ~(LPUART_CTRL_PE_MASK | LPUART_CTRL_PT_MASK | LPUART_CTRL_M_MASK); mmio_write_32(IMX_BOOT_UART_BASE + CTRL, tmp); mmio_write_32(IMX_BOOT_UART_BASE + CTRL, CTRL_RE | CTRL_TE); mmio_write_32(IMX_BOOT_UART_BASE + DATA, 0x55); mmio_write_32(IMX_BOOT_UART_BASE + DATA, 0x55); mmio_write_32(IMX_BOOT_UART_BASE + DATA, 0x0A); return 0; } #endif void mx8_partition_resources(void) { sc_rm_pt_t secure_part, os_part; sc_rm_mr_t mr, mr_record = 64; sc_faddr_t start, end; bool owned, owned2; sc_err_t err; int i; err = sc_rm_get_partition(ipc_handle, &secure_part); err = sc_rm_partition_alloc(ipc_handle, &os_part, false, false, false, false, false); err = sc_rm_set_parent(ipc_handle, os_part, secure_part); /* set secure resources to NOT-movable */ for (i = 0; i < ARRAY_SIZE(secure_rsrcs); i++) { err = sc_rm_set_resource_movable(ipc_handle, secure_rsrcs[i], secure_rsrcs[i], false); if (err) ERROR("sc_rm_set_resource_movable: rsrc %u, ret %u\n", secure_rsrcs[i], err); } owned = sc_rm_is_resource_owned(ipc_handle, SC_R_M4_0_PID0); if (owned) { err = sc_rm_set_resource_movable(ipc_handle, SC_R_M4_0_PID0, SC_R_M4_0_PID0, false); if (err) ERROR("sc_rm_set_resource_movable: rsrc %u, ret %u\n", SC_R_M4_0_PID0, err); } owned2 = sc_rm_is_resource_owned(ipc_handle, SC_R_M4_1_PID0); if (owned2) { err = sc_rm_set_resource_movable(ipc_handle, SC_R_M4_1_PID0, SC_R_M4_1_PID0, false); if (err) ERROR("sc_rm_set_resource_movable: rsrc %u, ret %u\n", SC_R_M4_1_PID0, err); } /* move all movable resources and pins to non-secure partition */ err = sc_rm_move_all(ipc_handle, secure_part, os_part, true, true); if (err) ERROR("sc_rm_move_all: %u\n", err); /* iterate through peripherals to give NS OS part access */ for (i = 0; i < ARRAY_SIZE(ns_access_allowed); i++) { err = sc_rm_set_peripheral_permissions(ipc_handle, ns_access_allowed[i], os_part, SC_RM_PERM_FULL); if (err) ERROR("sc_rm_set_peripheral_permissions: rsrc %u, \ ret %u\n", ns_access_allowed[i], err); } if (owned) { err = sc_rm_set_resource_movable(ipc_handle, SC_R_M4_0_PID0, SC_R_M4_0_PID0, true); if (err) ERROR("sc_rm_set_resource_movable: rsrc %u, ret %u\n", SC_R_M4_0_PID0, err); err = sc_rm_assign_resource(ipc_handle, os_part, SC_R_M4_0_PID0); if (err) ERROR("sc_rm_assign_resource: rsrc %u, ret %u\n", SC_R_M4_0_PID0, err); } if (owned2) { err = sc_rm_set_resource_movable(ipc_handle, SC_R_M4_1_PID0, SC_R_M4_1_PID0, true); if (err) ERROR("sc_rm_set_resource_movable: rsrc %u, ret %u\n", SC_R_M4_1_PID0, err); err = sc_rm_assign_resource(ipc_handle, os_part, SC_R_M4_1_PID0); if (err) ERROR("sc_rm_assign_resource: rsrc %u, ret %u\n", SC_R_M4_1_PID0, err); } /* * sc_rm_set_peripheral_permissions * sc_rm_set_memreg_permissions * sc_rm_set_pin_movable */ for (mr = 0; mr < 64; mr++) { owned = sc_rm_is_memreg_owned(ipc_handle, mr); if (owned) { err = sc_rm_get_memreg_info(ipc_handle, mr, &start, &end); if (err) ERROR("Memreg get info failed, %u\n", mr); NOTICE("Memreg %u 0x%llx -- 0x%llx\n", mr, start, end); if (BL31_BASE >= start && (BL31_LIMIT - 1) <= end) { mr_record = mr; /* Record the mr for ATF running */ } else { err = sc_rm_assign_memreg(ipc_handle, os_part, mr); if (err) ERROR("Memreg assign failed, 0x%llx -- 0x%llx, \ err %d\n", start, end, err); } } } if (mr_record != 64) { err = sc_rm_get_memreg_info(ipc_handle, mr_record, &start, &end); if (err) ERROR("Memreg get info failed, %u\n", mr_record); if ((BL31_LIMIT - 1) < end) { err = sc_rm_memreg_alloc(ipc_handle, &mr, BL31_LIMIT, end); if (err) ERROR("sc_rm_memreg_alloc failed, 0x%llx -- 0x%llx\n", (sc_faddr_t)BL31_LIMIT, end); err = sc_rm_assign_memreg(ipc_handle, os_part, mr); if (err) ERROR("Memreg assign failed, 0x%llx -- 0x%llx\n", (sc_faddr_t)BL31_LIMIT, end); } if (start < (BL31_BASE - 1)) { err = sc_rm_memreg_alloc(ipc_handle, &mr, start, BL31_BASE - 1); if (err) ERROR("sc_rm_memreg_alloc failed, 0x%llx -- 0x%llx\n", start, (sc_faddr_t)BL31_BASE - 1); err = sc_rm_assign_memreg(ipc_handle, os_part, mr); if (err) ERROR("Memreg assign failed, 0x%llx -- 0x%llx\n", start, (sc_faddr_t)BL31_BASE - 1); } } if (err) NOTICE("Partitioning Failed\n"); else NOTICE("Non-secure Partitioning Succeeded\n"); } void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { #if DEBUG_CONSOLE static console_lpuart_t console; #endif if (sc_ipc_open(&ipc_handle, SC_IPC_BASE) != SC_ERR_NONE) panic(); #if DEBUG_CONSOLE_A53 sc_pm_set_resource_power_mode(ipc_handle, SC_R_UART_0, SC_PM_PW_MODE_ON); sc_pm_clock_rate_t rate = 80000000; sc_pm_set_clock_rate(ipc_handle, SC_R_UART_0, 2, &rate); sc_pm_clock_enable(ipc_handle, SC_R_UART_0, 2, true, false); /* configure UART pads */ sc_pad_set(ipc_handle, SC_P_UART0_RX, UART_PAD_CTRL); sc_pad_set(ipc_handle, SC_P_UART0_TX, UART_PAD_CTRL); sc_pad_set(ipc_handle, SC_P_UART0_RTS_B, UART_PAD_CTRL); sc_pad_set(ipc_handle, SC_P_UART0_CTS_B, UART_PAD_CTRL); lpuart32_serial_init(IMX_BOOT_UART_BASE); #endif #if DEBUG_CONSOLE console_lpuart_register(IMX_BOOT_UART_BASE, IMX_BOOT_UART_CLK_IN_HZ, IMX_CONSOLE_BAUDRATE, &console); #endif /* turn on MU1 for non-secure OS/Hypervisor */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_MU_1A, SC_PM_PW_MODE_ON); /* Turn on GPT_0's power & clock for non-secure OS/Hypervisor */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON); sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0); mmio_write_32(IMX_GPT_LPCG_BASE, mmio_read_32(IMX_GPT_LPCG_BASE) | (1 << 25)); /* * create new partition for non-secure OS/Hypervisor * uses global structs defined in sec_rsrc.h */ mx8_partition_resources(); bl33_image_ep_info.pc = PLAT_NS_IMAGE_OFFSET; bl33_image_ep_info.spsr = get_spsr_for_bl33_entry(); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); /* init the first cluster's cci slave interface */ cci_init(PLAT_CCI_BASE, imx8qm_cci_map, PLATFORM_CLUSTER_COUNT); cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); } void bl31_plat_arch_setup(void) { unsigned long ro_start = BL31_RO_START; unsigned long ro_size = BL31_RO_END - BL31_RO_START; unsigned long rw_start = BL31_RW_START; unsigned long rw_size = BL31_RW_END - BL31_RW_START; #if USE_COHERENT_MEM unsigned long coh_start = BL31_COHERENT_RAM_START; unsigned long coh_size = BL31_COHERENT_RAM_END - BL31_COHERENT_RAM_START; #endif mmap_add_region(ro_start, ro_start, ro_size, MT_RO | MT_MEMORY | MT_SECURE); mmap_add_region(rw_start, rw_start, rw_size, MT_RW | MT_MEMORY | MT_SECURE); mmap_add(imx_mmap); #if USE_COHERENT_MEM mmap_add_region(coh_start, coh_start, coh_size, MT_DEVICE | MT_RW | MT_SECURE); #endif /* setup xlat table */ init_xlat_tables(); /* enable the MMU */ enable_mmu_el3(0); } void bl31_platform_setup(void) { plat_gic_driver_init(); plat_gic_init(); } entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type) { if (type == NON_SECURE) return &bl33_image_ep_info; if (type == SECURE) return &bl32_image_ep_info; return NULL; } unsigned int plat_get_syscnt_freq2(void) { return COUNTER_FREQUENCY; } void bl31_plat_runtime_setup(void) { return; } trusted-firmware-a-2.2/plat/imx/imx8qm/imx8qm_psci.c000066400000000000000000000263641355360272700225110ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "../../common/sci/imx8_mu.h" #define CORE_PWR_STATE(state) \ ((state)->pwr_domain_state[MPIDR_AFFLVL0]) #define CLUSTER_PWR_STATE(state) \ ((state)->pwr_domain_state[MPIDR_AFFLVL1]) #define SYSTEM_PWR_STATE(state) \ ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) const static int ap_core_index[PLATFORM_CORE_COUNT] = { SC_R_A53_0, SC_R_A53_1, SC_R_A53_2, SC_R_A53_3, SC_R_A72_0, SC_R_A72_1, }; /* save gic dist/redist context when GIC is poewr down */ static struct plat_gic_ctx imx_gicv3_ctx; static unsigned int gpt_lpcg, gpt_reg[2]; static void imx_enable_irqstr_wakeup(void) { uint32_t irq_mask; gicv3_dist_ctx_t *dist_ctx = &imx_gicv3_ctx.dist_ctx; /* put IRQSTR into ON mode */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON); /* enable the irqsteer to handle wakeup irq */ mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x1); for (int i = 0; i < 15; i++) { irq_mask = dist_ctx->gicd_isenabler[i]; mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x3c - 0x4 * i, irq_mask); } /* set IRQSTR low power mode */ if (imx_is_wakeup_src_irqsteer()) sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_STBY); else sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF); } static void imx_disable_irqstr_wakeup(void) { /* put IRQSTR into ON from STBY mode */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON); /* disable the irqsteer */ mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x0); for (int i = 0; i < 16; i++) mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x4 + 0x4 * i, 0x0); /* put IRQSTR into OFF mode */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF); } int imx_pwr_domain_on(u_register_t mpidr) { int ret = PSCI_E_SUCCESS; unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); sc_pm_set_resource_power_mode(ipc_handle, cluster_id == 0 ? SC_R_A53 : SC_R_A72, SC_PM_PW_MODE_ON); if (cluster_id == 1) sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON); if (sc_pm_set_resource_power_mode(ipc_handle, ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], SC_PM_PW_MODE_ON) != SC_ERR_NONE) { ERROR("core %d power on failed!\n", cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id); ret = PSCI_E_INTERN_FAIL; } if (sc_pm_cpu_start(ipc_handle, ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], true, BL31_BASE) != SC_ERR_NONE) { ERROR("boot core %d failed!\n", cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id); ret = PSCI_E_INTERN_FAIL; } return ret; } void imx_pwr_domain_on_finish(const psci_power_state_t *target_state) { uint64_t mpidr = read_mpidr_el1(); if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); plat_gic_pcpu_init(); plat_gic_cpuif_enable(); } void imx_pwr_domain_off(const psci_power_state_t *target_state) { u_register_t mpidr = read_mpidr_el1(); unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); plat_gic_cpuif_disable(); sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_NONE); if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) { cci_disable_snoop_dvm_reqs(cluster_id); if (cluster_id == 1) sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF); } printf("turn off cluster:%d core:%d\n", cluster_id, cpu_id); } void imx_domain_suspend(const psci_power_state_t *target_state) { u_register_t mpidr = read_mpidr_el1(); unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); if (is_local_state_off(CORE_PWR_STATE(target_state))) { plat_gic_cpuif_disable(); sc_pm_set_cpu_resume(ipc_handle, ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], true, BL31_BASE); sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC); } else { dsb(); write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); isb(); } if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) { cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); if (cluster_id == 1) sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF); } if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) { plat_gic_cpuif_disable(); /* save gic context */ plat_gic_save(cpu_id, &imx_gicv3_ctx); /* enable the irqsteer for wakeup */ imx_enable_irqstr_wakeup(); cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); /* Put GIC in LP mode. */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_OFF); /* Save GPT clock and registers, then turn off its power */ gpt_lpcg = mmio_read_32(IMX_GPT_LPCG_BASE); gpt_reg[0] = mmio_read_32(IMX_GPT_BASE); gpt_reg[1] = mmio_read_32(IMX_GPT_BASE + 0x4); sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_OFF); sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_OFF); sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_OFF); sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_OFF); sc_pm_set_cpu_resume(ipc_handle, ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], true, BL31_BASE); if (imx_is_wakeup_src_irqsteer()) sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_IRQSTEER); else sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU); } } void imx_domain_suspend_finish(const psci_power_state_t *target_state) { u_register_t mpidr = read_mpidr_el1(); unsigned int cluster_id = MPIDR_AFFLVL1_VAL(mpidr); unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); /* check the system level status */ if (is_local_state_retn(SYSTEM_PWR_STATE(target_state))) { MU_Resume(SC_IPC_BASE); sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC); /* Put GIC/IRQSTR back to high power mode. */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_ON); /* Turn GPT power and restore its clock and registers */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON); sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0); mmio_write_32(IMX_GPT_BASE, gpt_reg[0]); mmio_write_32(IMX_GPT_BASE + 0x4, gpt_reg[1]); mmio_write_32(IMX_GPT_LPCG_BASE, gpt_lpcg); sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_ON); sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON); sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON); cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); /* restore gic context */ plat_gic_restore(cpu_id, &imx_gicv3_ctx); /* disable the irqsteer wakeup */ imx_disable_irqstr_wakeup(); plat_gic_cpuif_enable(); } /* check the cluster level power status */ if (is_local_state_off(CLUSTER_PWR_STATE(target_state))) { cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(mpidr)); if (cluster_id == 1) sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON); } /* check the core level power status */ if (is_local_state_off(CORE_PWR_STATE(target_state))) { sc_pm_set_cpu_resume(ipc_handle, ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], false, BL31_BASE); sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id + PLATFORM_CLUSTER0_CORE_COUNT * cluster_id], SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC); plat_gic_cpuif_enable(); } else { write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT)); isb(); } } int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) { return PSCI_E_SUCCESS; } static const plat_psci_ops_t imx_plat_psci_ops = { .pwr_domain_on = imx_pwr_domain_on, .pwr_domain_on_finish = imx_pwr_domain_on_finish, .pwr_domain_off = imx_pwr_domain_off, .pwr_domain_suspend = imx_domain_suspend, .pwr_domain_suspend_finish = imx_domain_suspend_finish, .get_sys_suspend_power_state = imx_get_sys_suspend_power_state, .validate_power_state = imx_validate_power_state, .validate_ns_entrypoint = imx_validate_ns_entrypoint, .system_off = imx_system_off, .system_reset = imx_system_reset, }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { imx_mailbox_init(sec_entrypoint); *psci_ops = &imx_plat_psci_ops; /* make sure system sources power ON in low power mode by default */ sc_pm_req_low_power_mode(ipc_handle, SC_R_A53, SC_PM_PW_MODE_ON); sc_pm_req_low_power_mode(ipc_handle, SC_R_A72, SC_PM_PW_MODE_ON); sc_pm_req_low_power_mode(ipc_handle, SC_R_CCI, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A53, SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A72, SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); return 0; } trusted-firmware-a-2.2/plat/imx/imx8qm/include/000077500000000000000000000000001355360272700215145ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx8qm/include/platform_def.h000066400000000000000000000036441355360272700243360ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 #define PLATFORM_STACK_SIZE 0X400 #define CACHE_WRITEBACK_GRANULE 64 #define PLAT_PRIMARY_CPU 0x0 #define PLATFORM_MAX_CPU_PER_CLUSTER 4 #define PLATFORM_CLUSTER_COUNT 2 #define PLATFORM_CLUSTER0_CORE_COUNT 4 #define PLATFORM_CLUSTER1_CORE_COUNT 2 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT + \ PLATFORM_CLUSTER1_CORE_COUNT) #define IMX_PWR_LVL0 MPIDR_AFFLVL0 #define IMX_PWR_LVL1 MPIDR_AFFLVL1 #define IMX_PWR_LVL2 MPIDR_AFFLVL2 #define PWR_DOMAIN_AT_MAX_LVL U(1) #define PLAT_MAX_PWR_LVL U(2) #define PLAT_MAX_OFF_STATE U(2) #define PLAT_MAX_RET_STATE U(1) #define BL31_BASE 0x80000000 #define BL31_LIMIT 0x80020000 #define PLAT_GICD_BASE 0x51a00000 #define PLAT_GICR_BASE 0x51b00000 #define PLAT_CCI_BASE 0x52090000 #define CLUSTER0_CCI_SLVAE_IFACE 3 #define CLUSTER1_CCI_SLVAE_IFACE 4 #define IMX_BOOT_UART_BASE 0x5a060000 #define IMX_BOOT_UART_BAUDRATE 115200 #define IMX_BOOT_UART_CLK_IN_HZ 24000000 #define PLAT_CRASH_UART_BASE IMX_BOOT_UART_BASE #define PLAT__CRASH_UART_CLK_IN_HZ 24000000 #define IMX_CONSOLE_BAUDRATE 115200 #define SC_IPC_BASE 0x5d1b0000 #define IMX_GPT_LPCG_BASE 0x5d540000 #define IMX_GPT_BASE 0x5d140000 #define IMX_WUP_IRQSTR_BASE 0x51090000 #define IMX_REG_BASE 0x50000000 #define IMX_REG_SIZE 0x10000000 #define COUNTER_FREQUENCY 8000000 /* 8MHz */ /* non-secure uboot base */ #define PLAT_NS_IMAGE_OFFSET 0x80020000 #define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32) #define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32) #define MAX_XLAT_TABLES 8 #define MAX_MMAP_REGIONS 12 #define DEBUG_CONSOLE 0 #define DEBUG_CONSOLE_A53 0 #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/imx/imx8qm/include/sec_rsrc.h000066400000000000000000000010721355360272700234700ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* resources that are going to stay in secure partition */ sc_rsrc_t secure_rsrcs[] = { SC_R_MU_0A, SC_R_A53, SC_R_A53_0, SC_R_A53_1, SC_R_A53_2, SC_R_A53_3, SC_R_A72, SC_R_A72_0, SC_R_A72_1, SC_R_GIC, SC_R_GIC_SMMU, SC_R_CCI, SC_R_SYSTEM, SC_R_IRQSTR_SCU2, SC_R_GPT_0 }; /* resources that have register access for non-secure domain */ sc_rsrc_t ns_access_allowed[] = { SC_R_GIC, SC_R_GIC_SMMU, SC_R_CCI, SC_R_GPT_0 }; trusted-firmware-a-2.2/plat/imx/imx8qm/platform.mk000066400000000000000000000024221355360272700222460ustar00rootroot00000000000000# # Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # PLAT_INCLUDES := -Iplat/imx/imx8qm/include \ -Iplat/imx/common/include \ IMX_GIC_SOURCES := drivers/arm/gic/v3/gicv3_helpers.c \ drivers/arm/gic/v3/arm_gicv3_common.c \ drivers/arm/gic/v3/gic500.c \ drivers/arm/gic/v3/gicv3_main.c \ drivers/arm/gic/common/gic_common.c \ plat/common/plat_gicv3.c \ plat/common/plat_psci_common.c \ plat/imx/common/plat_imx8_gic.c BL31_SOURCES += plat/imx/common/lpuart_console.S \ plat/imx/common/imx8_helpers.S \ plat/imx/imx8qm/imx8qm_bl31_setup.c \ plat/imx/imx8qm/imx8qm_psci.c \ plat/imx/common/imx8_topology.c \ plat/imx/common/imx8_psci.c \ plat/imx/common/imx_sip_svc.c \ plat/imx/common/imx_sip_handler.c \ lib/xlat_tables/aarch64/xlat_tables.c \ lib/xlat_tables/xlat_tables_common.c \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a72.S \ drivers/arm/cci/cci.c \ ${IMX_GIC_SOURCES} \ include plat/imx/common/sci/sci_api.mk USE_COHERENT_MEM := 1 RESET_TO_BL31 := 1 A53_DISABLE_NON_TEMPORAL_HINT := 0 ERRATA_A72_859971 := 1 ERRATA_A53_835769 := 1 ERRATA_A53_843419 := 1 ERRATA_A53_855873 := 1 trusted-firmware-a-2.2/plat/imx/imx8qx/000077500000000000000000000000001355360272700201045ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx8qx/imx8qx_bl31_setup.c000066400000000000000000000230411355360272700235470ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include IMPORT_SYM(unsigned long, __COHERENT_RAM_START__, BL31_COHERENT_RAM_START); IMPORT_SYM(unsigned long, __COHERENT_RAM_END__, BL31_COHERENT_RAM_END); IMPORT_SYM(unsigned long, __RO_START__, BL31_RO_START); IMPORT_SYM(unsigned long, __RO_END__, BL31_RO_END); IMPORT_SYM(unsigned long, __RW_START__, BL31_RW_START); IMPORT_SYM(unsigned long, __RW_END__, BL31_RW_END); static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; #define UART_PAD_CTRL (PADRING_IFMUX_EN_MASK | PADRING_GP_EN_MASK | \ (SC_PAD_CONFIG_OUT_IN << PADRING_CONFIG_SHIFT) | \ (SC_PAD_ISO_OFF << PADRING_LPCONFIG_SHIFT) | \ (SC_PAD_28FDSOI_DSE_DV_LOW << PADRING_DSE_SHIFT) | \ (SC_PAD_28FDSOI_PS_PD << PADRING_PULL_SHIFT)) static const mmap_region_t imx_mmap[] = { MAP_REGION_FLAT(IMX_REG_BASE, IMX_REG_SIZE, MT_DEVICE | MT_RW), {0} }; static uint32_t get_spsr_for_bl33_entry(void) { unsigned long el_status; unsigned long mode; uint32_t spsr; /* figure out what mode we enter the non-secure world */ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; el_status &= ID_AA64PFR0_ELX_MASK; mode = (el_status) ? MODE_EL2 : MODE_EL1; spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; } #if DEBUG_CONSOLE_A35 static void lpuart32_serial_setbrg(unsigned int base, int baudrate) { unsigned int sbr, osr, baud_diff, tmp_osr, tmp_sbr; unsigned int diff1, diff2, tmp, rate; if (baudrate == 0) panic(); sc_pm_get_clock_rate(ipc_handle, SC_R_UART_0, 2, &rate); baud_diff = baudrate; osr = 0; sbr = 0; for (tmp_osr = 4; tmp_osr <= 32; tmp_osr++) { tmp_sbr = (rate / (baudrate * tmp_osr)); if (tmp_sbr == 0) tmp_sbr = 1; /* calculate difference in actual baud w/ current values */ diff1 = rate / (tmp_osr * tmp_sbr) - baudrate; diff2 = rate / (tmp_osr * (tmp_sbr + 1)); /* select best values between sbr and sbr+1 */ if (diff1 > (baudrate - diff2)) { diff1 = baudrate - diff2; tmp_sbr++; } if (diff1 <= baud_diff) { baud_diff = diff1; osr = tmp_osr; sbr = tmp_sbr; } } tmp = mmio_read_32(IMX_BOOT_UART_BASE + BAUD); if ((osr > 3) && (osr < 8)) tmp |= LPUART_BAUD_BOTHEDGE_MASK; tmp &= ~LPUART_BAUD_OSR_MASK; tmp |= LPUART_BAUD_OSR(osr - 1); tmp &= ~LPUART_BAUD_SBR_MASK; tmp |= LPUART_BAUD_SBR(sbr); /* explicitly disable 10 bit mode & set 1 stop bit */ tmp &= ~(LPUART_BAUD_M10_MASK | LPUART_BAUD_SBNS_MASK); mmio_write_32(IMX_BOOT_UART_BASE + BAUD, tmp); } static int lpuart32_serial_init(unsigned int base) { unsigned int tmp; /* disable TX & RX before enabling clocks */ tmp = mmio_read_32(IMX_BOOT_UART_BASE + CTRL); tmp &= ~(CTRL_TE | CTRL_RE); mmio_write_32(IMX_BOOT_UART_BASE + CTRL, tmp); mmio_write_32(IMX_BOOT_UART_BASE + MODIR, 0); mmio_write_32(IMX_BOOT_UART_BASE + FIFO, ~(FIFO_TXFE | FIFO_RXFE)); mmio_write_32(IMX_BOOT_UART_BASE + MATCH, 0); /* provide data bits, parity, stop bit, etc */ lpuart32_serial_setbrg(base, IMX_BOOT_UART_BAUDRATE); /* eight data bits no parity bit */ tmp = mmio_read_32(IMX_BOOT_UART_BASE + CTRL); tmp &= ~(LPUART_CTRL_PE_MASK | LPUART_CTRL_PT_MASK | LPUART_CTRL_M_MASK); mmio_write_32(IMX_BOOT_UART_BASE + CTRL, tmp); mmio_write_32(IMX_BOOT_UART_BASE + CTRL, CTRL_RE | CTRL_TE); mmio_write_32(IMX_BOOT_UART_BASE + DATA, 0x55); mmio_write_32(IMX_BOOT_UART_BASE + DATA, 0x55); mmio_write_32(IMX_BOOT_UART_BASE + DATA, 0x0A); return 0; } #endif void imx8_partition_resources(void) { sc_rm_pt_t secure_part, os_part; sc_rm_mr_t mr, mr_record = 64; sc_faddr_t start, end; sc_err_t err; bool owned; int i; err = sc_rm_get_partition(ipc_handle, &secure_part); if (err) ERROR("sc_rm_get_partition failed: %u\n", err); err = sc_rm_partition_alloc(ipc_handle, &os_part, false, false, false, false, false); if (err) ERROR("sc_rm_partition_alloc failed: %u\n", err); err = sc_rm_set_parent(ipc_handle, os_part, secure_part); if (err) ERROR("sc_rm_set_parent: %u\n", err); /* set secure resources to NOT-movable */ for (i = 0; i < (ARRAY_SIZE(secure_rsrcs)); i++) { err = sc_rm_set_resource_movable(ipc_handle, secure_rsrcs[i], secure_rsrcs[i], false); if (err) ERROR("sc_rm_set_resource_movable: rsrc %u, ret %u\n", secure_rsrcs[i], err); } /* move all movable resources and pins to non-secure partition */ err = sc_rm_move_all(ipc_handle, secure_part, os_part, true, true); if (err) ERROR("sc_rm_move_all: %u\n", err); /* iterate through peripherals to give NS OS part access */ for (i = 0; i < ARRAY_SIZE(ns_access_allowed); i++) { err = sc_rm_set_peripheral_permissions(ipc_handle, ns_access_allowed[i], os_part, SC_RM_PERM_FULL); if (err) ERROR("sc_rm_set_peripheral_permissions: rsrc %u, \ ret %u\n", ns_access_allowed[i], err); } /* * sc_rm_set_peripheral_permissions * sc_rm_set_memreg_permissions * sc_rm_set_pin_movable */ for (mr = 0; mr < 64; mr++) { owned = sc_rm_is_memreg_owned(ipc_handle, mr); if (owned) { err = sc_rm_get_memreg_info(ipc_handle, mr, &start, &end); if (err) ERROR("Memreg get info failed, %u\n", mr); NOTICE("Memreg %u 0x%llx -- 0x%llx\n", mr, start, end); if (BL31_BASE >= start && (BL31_LIMIT - 1) <= end) { mr_record = mr; /* Record the mr for ATF running */ } else { err = sc_rm_assign_memreg(ipc_handle, os_part, mr); if (err) ERROR("Memreg assign failed, 0x%llx -- 0x%llx, \ err %d\n", start, end, err); } } } if (mr_record != 64) { err = sc_rm_get_memreg_info(ipc_handle, mr_record, &start, &end); if (err) ERROR("Memreg get info failed, %u\n", mr_record); if ((BL31_LIMIT - 1) < end) { err = sc_rm_memreg_alloc(ipc_handle, &mr, BL31_LIMIT, end); if (err) ERROR("sc_rm_memreg_alloc failed, 0x%llx -- 0x%llx\n", (sc_faddr_t)BL31_LIMIT, end); err = sc_rm_assign_memreg(ipc_handle, os_part, mr); if (err) ERROR("Memreg assign failed, 0x%llx -- 0x%llx\n", (sc_faddr_t)BL31_LIMIT, end); } if (start < (BL31_BASE - 1)) { err = sc_rm_memreg_alloc(ipc_handle, &mr, start, BL31_BASE - 1); if (err) ERROR("sc_rm_memreg_alloc failed, 0x%llx -- 0x%llx\n", start, (sc_faddr_t)BL31_BASE - 1); err = sc_rm_assign_memreg(ipc_handle, os_part, mr); if (err) ERROR("Memreg assign failed, 0x%llx -- 0x%llx\n", start, (sc_faddr_t)BL31_BASE - 1); } } if (err) NOTICE("Partitioning Failed\n"); else NOTICE("Non-secure Partitioning Succeeded\n"); } void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { #if DEBUG_CONSOLE static console_lpuart_t console; #endif if (sc_ipc_open(&ipc_handle, SC_IPC_BASE) != SC_ERR_NONE) panic(); #if DEBUG_CONSOLE_A35 sc_pm_set_resource_power_mode(ipc_handle, SC_R_UART_0, SC_PM_PW_MODE_ON); sc_pm_clock_rate_t rate = 80000000; sc_pm_set_clock_rate(ipc_handle, SC_R_UART_0, 2, &rate); sc_pm_clock_enable(ipc_handle, SC_R_UART_0, 2, true, false); /* Configure UART pads */ sc_pad_set(ipc_handle, SC_P_UART0_RX, UART_PAD_CTRL); sc_pad_set(ipc_handle, SC_P_UART0_TX, UART_PAD_CTRL); lpuart32_serial_init(IMX_BOOT_UART_BASE); #endif #if DEBUG_CONSOLE console_lpuart_register(IMX_BOOT_UART_BASE, IMX_BOOT_UART_CLK_IN_HZ, IMX_CONSOLE_BAUDRATE, &console); #endif /* Turn on MU1 for non-secure OS/Hypervisor */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_MU_1A, SC_PM_PW_MODE_ON); /* Turn on GPT_0's power & clock for non-secure OS/Hypervisor */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON); sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0); mmio_write_32(IMX_GPT0_LPCG_BASE, mmio_read_32(IMX_GPT0_LPCG_BASE) | (1 << 25)); /* * create new partition for non-secure OS/Hypervisor * uses global structs defined in sec_rsrc.h */ imx8_partition_resources(); bl33_image_ep_info.pc = PLAT_NS_IMAGE_OFFSET; bl33_image_ep_info.spsr = get_spsr_for_bl33_entry(); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); } void bl31_plat_arch_setup(void) { unsigned long ro_start = BL31_RO_START; unsigned long ro_size = BL31_RO_END - BL31_RO_START; unsigned long rw_start = BL31_RW_START; unsigned long rw_size = BL31_RW_END - BL31_RW_START; #if USE_COHERENT_MEM unsigned long coh_start = BL31_COHERENT_RAM_START; unsigned long coh_size = BL31_COHERENT_RAM_END - BL31_COHERENT_RAM_START; #endif mmap_add_region(ro_start, ro_start, ro_size, MT_RO | MT_MEMORY | MT_SECURE); mmap_add_region(rw_start, rw_start, rw_size, MT_RW | MT_MEMORY | MT_SECURE); mmap_add(imx_mmap); #if USE_COHERENT_MEM mmap_add_region(coh_start, coh_start, coh_size, MT_DEVICE | MT_RW | MT_SECURE); #endif init_xlat_tables(); enable_mmu_el3(0); } void bl31_platform_setup(void) { plat_gic_driver_init(); plat_gic_init(); } entry_point_info_t *bl31_plat_get_next_image_ep_info(unsigned int type) { if (type == NON_SECURE) return &bl33_image_ep_info; if (type == SECURE) return &bl32_image_ep_info; return NULL; } unsigned int plat_get_syscnt_freq2(void) { return COUNTER_FREQUENCY; } void bl31_plat_runtime_setup(void) { return; } trusted-firmware-a-2.2/plat/imx/imx8qx/imx8qx_psci.c000066400000000000000000000175351355360272700225370ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "../../common/sci/imx8_mu.h" const static int ap_core_index[PLATFORM_CORE_COUNT] = { SC_R_A35_0, SC_R_A35_1, SC_R_A35_2, SC_R_A35_3 }; /* save gic dist/redist context when GIC is power down */ static struct plat_gic_ctx imx_gicv3_ctx; static unsigned int gpt_lpcg, gpt_reg[2]; static void imx_enable_irqstr_wakeup(void) { uint32_t irq_mask; gicv3_dist_ctx_t *dist_ctx = &imx_gicv3_ctx.dist_ctx; /* put IRQSTR into ON mode */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON); /* enable the irqsteer to handle wakeup irq */ mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x1); for (int i = 0; i < 15; i++) { irq_mask = dist_ctx->gicd_isenabler[i]; mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x3c - 0x4 * i, irq_mask); } /* set IRQSTR low power mode */ if (imx_is_wakeup_src_irqsteer()) sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_STBY); else sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF); } static void imx_disable_irqstr_wakeup(void) { /* Put IRQSTEER back to ON mode */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_ON); /* disable the irqsteer */ mmio_write_32(IMX_WUP_IRQSTR_BASE, 0x0); for (int i = 0; i < 16; i++) mmio_write_32(IMX_WUP_IRQSTR_BASE + 0x4 + 0x4 * i, 0x0); /* Put IRQSTEER into OFF mode */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_IRQSTR_SCU2, SC_PM_PW_MODE_OFF); } int imx_pwr_domain_on(u_register_t mpidr) { int ret = PSCI_E_SUCCESS; unsigned int cpu_id; cpu_id = MPIDR_AFFLVL0_VAL(mpidr); printf("imx_pwr_domain_on cpu_id %d\n", cpu_id); if (sc_pm_set_resource_power_mode(ipc_handle, ap_core_index[cpu_id], SC_PM_PW_MODE_ON) != SC_ERR_NONE) { ERROR("core %d power on failed!\n", cpu_id); ret = PSCI_E_INTERN_FAIL; } if (sc_pm_cpu_start(ipc_handle, ap_core_index[cpu_id], true, BL31_BASE) != SC_ERR_NONE) { ERROR("boot core %d failed!\n", cpu_id); ret = PSCI_E_INTERN_FAIL; } return ret; } void imx_pwr_domain_on_finish(const psci_power_state_t *target_state) { plat_gic_pcpu_init(); plat_gic_cpuif_enable(); } int imx_validate_ns_entrypoint(uintptr_t ns_entrypoint) { return PSCI_E_SUCCESS; } void imx_pwr_domain_off(const psci_power_state_t *target_state) { u_register_t mpidr = read_mpidr_el1(); unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); plat_gic_cpuif_disable(); sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_NONE); printf("turn off core:%d\n", cpu_id); } void imx_domain_suspend(const psci_power_state_t *target_state) { u_register_t mpidr = read_mpidr_el1(); unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL0])) { plat_gic_cpuif_disable(); sc_pm_set_cpu_resume(ipc_handle, ap_core_index[cpu_id], true, BL31_BASE); sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_GIC); } else { dsb(); write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); isb(); } if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL1])) sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_OFF); if (is_local_state_retn(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL])) { plat_gic_cpuif_disable(); /* save gic context */ plat_gic_save(cpu_id, &imx_gicv3_ctx); /* enable the irqsteer for wakeup */ imx_enable_irqstr_wakeup(); /* Save GPT clock and registers, then turn off its power */ gpt_lpcg = mmio_read_32(IMX_GPT0_LPCG_BASE); gpt_reg[0] = mmio_read_32(IMX_GPT0_BASE); gpt_reg[1] = mmio_read_32(IMX_GPT0_BASE + 0x4); sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_OFF); sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_OFF); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_OFF); /* Put GIC in OFF mode. */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_OFF); sc_pm_set_cpu_resume(ipc_handle, ap_core_index[cpu_id], true, BL31_BASE); if (imx_is_wakeup_src_irqsteer()) sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_IRQSTEER); else sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], SC_PM_PW_MODE_OFF, SC_PM_WAKE_SRC_SCU); } } void imx_domain_suspend_finish(const psci_power_state_t *target_state) { u_register_t mpidr = read_mpidr_el1(); unsigned int cpu_id = MPIDR_AFFLVL0_VAL(mpidr); if (is_local_state_retn(target_state->pwr_domain_state[PLAT_MAX_PWR_LVL])) { MU_Resume(SC_IPC_BASE); sc_pm_req_low_power_mode(ipc_handle, ap_core_index[cpu_id], SC_PM_PW_MODE_ON); sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC); /* Put GIC back to high power mode. */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_GIC, SC_PM_PW_MODE_ON); /* restore gic context */ plat_gic_restore(cpu_id, &imx_gicv3_ctx); /* Turn on GPT power and restore its clock and registers */ sc_pm_set_resource_power_mode(ipc_handle, SC_R_GPT_0, SC_PM_PW_MODE_ON); sc_pm_clock_enable(ipc_handle, SC_R_GPT_0, SC_PM_CLK_PER, true, 0); mmio_write_32(IMX_GPT0_BASE, gpt_reg[0]); mmio_write_32(IMX_GPT0_BASE + 0x4, gpt_reg[1]); mmio_write_32(IMX_GPT0_LPCG_BASE, gpt_lpcg); sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); /* disable the irqsteer wakeup */ imx_disable_irqstr_wakeup(); plat_gic_cpuif_enable(); } if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL1])) sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON); if (is_local_state_off(target_state->pwr_domain_state[MPIDR_AFFLVL0])) { sc_pm_req_cpu_low_power_mode(ipc_handle, ap_core_index[cpu_id], SC_PM_PW_MODE_ON, SC_PM_WAKE_SRC_GIC); plat_gic_cpuif_enable(); } else { write_scr_el3(read_scr_el3() & (~SCR_FIQ_BIT)); isb(); } } static const plat_psci_ops_t imx_plat_psci_ops = { .pwr_domain_on = imx_pwr_domain_on, .pwr_domain_on_finish = imx_pwr_domain_on_finish, .validate_ns_entrypoint = imx_validate_ns_entrypoint, .system_off = imx_system_off, .system_reset = imx_system_reset, .pwr_domain_off = imx_pwr_domain_off, .pwr_domain_suspend = imx_domain_suspend, .pwr_domain_suspend_finish = imx_domain_suspend_finish, .get_sys_suspend_power_state = imx_get_sys_suspend_power_state, .validate_power_state = imx_validate_power_state, }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { imx_mailbox_init(sec_entrypoint); *psci_ops = &imx_plat_psci_ops; /* make sure system sources power ON in low power mode by default */ sc_pm_req_low_power_mode(ipc_handle, SC_R_A35, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_DDR, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_MU, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); sc_pm_req_sys_if_power_mode(ipc_handle, SC_R_A35, SC_PM_SYS_IF_INTERCONNECT, SC_PM_PW_MODE_ON, SC_PM_PW_MODE_ON); return 0; } trusted-firmware-a-2.2/plat/imx/imx8qx/include/000077500000000000000000000000001355360272700215275ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/imx/imx8qx/include/platform_def.h000066400000000000000000000032551355360272700243470ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 #define PLATFORM_STACK_SIZE 0x400 #define CACHE_WRITEBACK_GRANULE 64 #define PLAT_PRIMARY_CPU 0x0 #define PLATFORM_MAX_CPU_PER_CLUSTER 4 #define PLATFORM_CLUSTER_COUNT 1 #define PLATFORM_CORE_COUNT 4 #define PLATFORM_CLUSTER0_CORE_COUNT 4 #define PLATFORM_CLUSTER1_CORE_COUNT 0 #define PWR_DOMAIN_AT_MAX_LVL U(1) #define PLAT_MAX_PWR_LVL U(2) #define PLAT_MAX_OFF_STATE U(2) #define PLAT_MAX_RET_STATE U(1) #define BL31_BASE 0x80000000 #define BL31_LIMIT 0x80020000 #define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32) #define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32) #define MAX_XLAT_TABLES 8 #define MAX_MMAP_REGIONS 8 #define PLAT_GICD_BASE 0x51a00000 #define PLAT_GICR_BASE 0x51b00000 #define IMX_BOOT_UART_BASE 0x5a060000 #define IMX_BOOT_UART_BAUDRATE 115200 #define IMX_BOOT_UART_CLK_IN_HZ 24000000 #define PLAT_CRASH_UART_BASE IMX_BOOT_UART_BASE #define PLAT__CRASH_UART_CLK_IN_HZ 24000000 #define IMX_CONSOLE_BAUDRATE 115200 #define SC_IPC_BASE 0x5d1b0000 #define IMX_GPT0_LPCG_BASE 0x5d540000 #define IMX_GPT0_BASE 0x5d140000 #define IMX_WUP_IRQSTR_BASE 0x51090000 #define IMX_REG_BASE 0x50000000 #define IMX_REG_SIZE 0x10000000 #define COUNTER_FREQUENCY 8000000 /* non-secure u-boot base */ #define PLAT_NS_IMAGE_OFFSET 0x80020000 #define DEBUG_CONSOLE 0 #define DEBUG_CONSOLE_A35 0 #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/imx/imx8qx/include/sec_rsrc.h000066400000000000000000000007371355360272700235120ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* resources that are going to stay in secure partition */ sc_rsrc_t secure_rsrcs[] = { SC_R_MU_0A, SC_R_A35, SC_R_A35_0, SC_R_A35_1, SC_R_A35_2, SC_R_A35_3, SC_R_GIC, SC_R_SYSTEM, SC_R_IRQSTR_SCU2, SC_R_GPT_0 }; /* resources that have register access for non-secure domain */ sc_rsrc_t ns_access_allowed[] = { SC_R_GIC, SC_R_GPT_0 }; trusted-firmware-a-2.2/plat/imx/imx8qx/platform.mk000066400000000000000000000020741355360272700222640ustar00rootroot00000000000000# # Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # PLAT_INCLUDES := -Iplat/imx/imx8qx/include \ -Iplat/imx/common/include \ IMX_GIC_SOURCES := drivers/arm/gic/v3/gicv3_helpers.c \ drivers/arm/gic/v3/arm_gicv3_common.c \ drivers/arm/gic/v3/gic500.c \ drivers/arm/gic/v3/gicv3_main.c \ drivers/arm/gic/common/gic_common.c \ plat/common/plat_gicv3.c \ plat/imx/common/plat_imx8_gic.c BL31_SOURCES += plat/imx/common/lpuart_console.S \ plat/imx/common/imx8_helpers.S \ plat/imx/imx8qx/imx8qx_bl31_setup.c \ plat/imx/imx8qx/imx8qx_psci.c \ plat/imx/common/imx8_topology.c \ plat/imx/common/imx8_psci.c \ plat/imx/common/imx_sip_svc.c \ plat/imx/common/imx_sip_handler.c \ plat/common/plat_psci_common.c \ lib/xlat_tables/xlat_tables_common.c \ lib/xlat_tables/aarch64/xlat_tables.c \ lib/cpus/aarch64/cortex_a35.S \ ${IMX_GIC_SOURCES} \ include plat/imx/common/sci/sci_api.mk USE_COHERENT_MEM := 1 RESET_TO_BL31 := 1 trusted-firmware-a-2.2/plat/intel/000077500000000000000000000000001355360272700171645ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/intel/soc/000077500000000000000000000000001355360272700177505ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/intel/soc/agilex/000077500000000000000000000000001355360272700212215ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/intel/soc/agilex/bl2_plat_setup.c000066400000000000000000000107141355360272700243070ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include "agilex_clock_manager.h" #include "agilex_handoff.h" #include "agilex_mailbox.h" #include "agilex_memory_controller.h" #include "agilex_pinmux.h" #include "agilex_private.h" #include "agilex_reset_manager.h" #include "agilex_system_manager.h" #include "ccu/ncore_ccu.h" #include "qspi/cadence_qspi.h" #include "wdt/watchdog.h" const mmap_region_t agilex_plat_mmap[] = { MAP_REGION_FLAT(DRAM_BASE, DRAM_SIZE, MT_MEMORY | MT_RW | MT_NS), MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_NS), MAP_REGION_FLAT(DEVICE2_BASE, DEVICE2_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(OCRAM_BASE, OCRAM_SIZE, MT_NON_CACHEABLE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DEVICE3_BASE, DEVICE3_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(MEM64_BASE, MEM64_SIZE, MT_DEVICE | MT_RW | MT_NS), MAP_REGION_FLAT(DEVICE4_BASE, DEVICE4_SIZE, MT_DEVICE | MT_RW | MT_NS), {0}, }; boot_source_type boot_source; void bl2_el3_early_platform_setup(u_register_t x0, u_register_t x1, u_register_t x2, u_register_t x4) { static console_16550_t console; handoff reverse_handoff_ptr; generic_delay_timer_init(); if (agilex_get_handoff(&reverse_handoff_ptr)) return; config_pinmux(&reverse_handoff_ptr); boot_source = reverse_handoff_ptr.boot_source; config_clkmgr_handoff(&reverse_handoff_ptr); enable_nonsecure_access(); deassert_peripheral_reset(); config_hps_hs_before_warm_reset(); watchdog_init(get_wdt_clk()); console_16550_register(PLAT_UART0_BASE, get_uart_clk(), PLAT_BAUDRATE, &console); socfpga_delay_timer_init(); init_ncore_ccu(); init_hard_memory_controller(); enable_ns_bridge_access(); } void bl2_el3_plat_arch_setup(void) { struct mmc_device_info info; const mmap_region_t bl_regions[] = { MAP_REGION_FLAT(BL2_BASE, BL2_END - BL2_BASE, MT_MEMORY | MT_RW | MT_SECURE), MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, MT_CODE | MT_SECURE), MAP_REGION_FLAT(BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE, MT_RO_DATA | MT_SECURE), #if USE_COHERENT_MEM_BAR MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, MT_DEVICE | MT_RW | MT_SECURE), #endif {0}, }; setup_page_tables(bl_regions, agilex_plat_mmap); enable_mmu_el3(0); dw_mmc_params_t params = EMMC_INIT_PARAMS(0x100000, get_mmc_clk()); info.mmc_dev_type = MMC_IS_SD; info.ocr_voltage = OCR_3_3_3_4 | OCR_3_2_3_3; mailbox_init(); switch (boot_source) { case BOOT_SOURCE_SDMMC: dw_mmc_init(¶ms, &info); socfpga_io_setup(boot_source); break; case BOOT_SOURCE_QSPI: mailbox_set_qspi_open(); mailbox_set_qspi_direct(); cad_qspi_init(0, QSPI_CONFIG_CPHA, QSPI_CONFIG_CPOL, QSPI_CONFIG_CSDA, QSPI_CONFIG_CSDADS, QSPI_CONFIG_CSEOT, QSPI_CONFIG_CSSOT, 0); socfpga_io_setup(boot_source); break; default: ERROR("Unsupported boot source\n"); panic(); break; } } uint32_t get_spsr_for_bl33_entry(void) { unsigned long el_status; unsigned int mode; uint32_t spsr; /* Figure out what mode we enter the non-secure world in */ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; el_status &= ID_AA64PFR0_ELX_MASK; mode = (el_status) ? MODE_EL2 : MODE_EL1; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; } int bl2_plat_handle_post_image_load(unsigned int image_id) { bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id); switch (image_id) { case BL33_IMAGE_ID: bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr(); bl_mem_params->ep_info.spsr = get_spsr_for_bl33_entry(); break; default: break; } return 0; } /******************************************************************************* * Perform any BL3-1 platform setup code ******************************************************************************/ void bl2_platform_setup(void) { } trusted-firmware-a-2.2/plat/intel/soc/agilex/bl31_plat_setup.c000066400000000000000000000101771355360272700243740ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; next_image_info = (type == NON_SECURE) ? &bl33_image_ep_info : &bl32_image_ep_info; /* None of the images on this platform can have 0x0 as the entrypoint */ if (next_image_info->pc) return next_image_info; else return NULL; } void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { static console_16550_t console; console_16550_register(PLAT_UART0_BASE, PLAT_UART_CLOCK, PLAT_BAUDRATE, &console); /* * Check params passed from BL31 should not be NULL, */ void *from_bl2 = (void *) arg0; bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2; assert(params_from_bl2 != NULL); assert(params_from_bl2->h.type == PARAM_BL_PARAMS); assert(params_from_bl2->h.version >= VERSION_2); /* * Copy BL32 (if populated by BL31) and BL33 entry point information. * They are stored in Secure RAM, in BL31's address space. */ bl_params_node_t *bl_params = params_from_bl2->head; while (bl_params) { if (bl_params->image_id == BL33_IMAGE_ID) bl33_image_ep_info = *bl_params->ep_info; bl_params = bl_params->next_params_info; } SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); } static const interrupt_prop_t s10_interrupt_props[] = { PLAT_INTEL_AGX_G1S_IRQ_PROPS(GICV2_INTR_GROUP0), PLAT_INTEL_AGX_G0_IRQ_PROPS(GICV2_INTR_GROUP0) }; static unsigned int target_mask_array[PLATFORM_CORE_COUNT]; static const gicv2_driver_data_t plat_gicv2_gic_data = { .gicd_base = PLAT_INTEL_AGX_GICD_BASE, .gicc_base = PLAT_INTEL_AGX_GICC_BASE, .interrupt_props = s10_interrupt_props, .interrupt_props_num = ARRAY_SIZE(s10_interrupt_props), .target_masks = target_mask_array, .target_masks_num = ARRAY_SIZE(target_mask_array), }; /******************************************************************************* * Perform any BL3-1 platform setup code ******************************************************************************/ void bl31_platform_setup(void) { /* Initialize the gic cpu and distributor interfaces */ gicv2_driver_init(&plat_gicv2_gic_data); gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } const mmap_region_t plat_agilex_mmap[] = { MAP_REGION_FLAT(DRAM_BASE, DRAM_SIZE, MT_MEMORY | MT_RW | MT_NS), MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_NS), MAP_REGION_FLAT(DEVICE2_BASE, DEVICE2_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(OCRAM_BASE, OCRAM_SIZE, MT_NON_CACHEABLE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DEVICE3_BASE, DEVICE3_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(MEM64_BASE, MEM64_SIZE, MT_DEVICE | MT_RW | MT_NS), MAP_REGION_FLAT(DEVICE4_BASE, DEVICE4_SIZE, MT_DEVICE | MT_RW | MT_NS), {0}, }; /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this is only intializes the mmu in a quick and dirty way. ******************************************************************************/ void bl31_plat_arch_setup(void) { const mmap_region_t bl_regions[] = { MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE, MT_MEMORY | MT_RW | MT_SECURE), MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, MT_CODE | MT_SECURE), MAP_REGION_FLAT(BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE, MT_RO_DATA | MT_SECURE), #if USE_COHERENT_MEM MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, MT_DEVICE | MT_RW | MT_SECURE), #endif {0}, }; setup_page_tables(bl_regions, plat_agilex_mmap); enable_mmu_el3(0); } trusted-firmware-a-2.2/plat/intel/soc/agilex/include/000077500000000000000000000000001355360272700226445ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/intel/soc/agilex/include/agilex_clock_manager.h000066400000000000000000000076431355360272700271450ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CLOCKMANAGER_H #define CLOCKMANAGER_H #include "agilex_handoff.h" /* Clock Manager Registers */ #define CLKMGR_OFFSET 0xffd10000 #define CLKMGR_CTRL 0x0 #define CLKMGR_STAT 0x4 #define CLKMGR_INTRCLR 0x14 /* Main PLL Group */ #define CLKMGR_MAINPLL 0xffd10024 #define CLKMGR_MAINPLL_EN 0x0 #define CLKMGR_MAINPLL_BYPASS 0xc #define CLKMGR_MAINPLL_MPUCLK 0x18 #define CLKMGR_MAINPLL_NOCCLK 0x1c #define CLKMGR_MAINPLL_NOCDIV 0x20 #define CLKMGR_MAINPLL_PLLGLOB 0x24 #define CLKMGR_MAINPLL_FDBCK 0x28 #define CLKMGR_MAINPLL_MEM 0x2c #define CLKMGR_MAINPLL_MEMSTAT 0x30 #define CLKMGR_MAINPLL_PLLC0 0x34 #define CLKMGR_MAINPLL_PLLC1 0x38 #define CLKMGR_MAINPLL_VCOCALIB 0x3c #define CLKMGR_MAINPLL_PLLC2 0x40 #define CLKMGR_MAINPLL_PLLC3 0x44 #define CLKMGR_MAINPLL_PLLM 0x48 #define CLKMGR_MAINPLL_LOSTLOCK 0x54 /* Peripheral PLL Group */ #define CLKMGR_PERPLL 0xffd1007c #define CLKMGR_PERPLL_EN 0x0 #define CLKMGR_PERPLL_BYPASS 0xc #define CLKMGR_PERPLL_EMACCTL 0x18 #define CLKMGR_PERPLL_GPIODIV 0x1c #define CLKMGR_PERPLL_PLLGLOB 0x20 #define CLKMGR_PERPLL_FDBCK 0x24 #define CLKMGR_PERPLL_MEM 0x28 #define CLKMGR_PERPLL_MEMSTAT 0x2c #define CLKMGR_PERPLL_PLLC0 0x30 #define CLKMGR_PERPLL_PLLC1 0x34 #define CLKMGR_PERPLL_VCOCALIB 0x38 #define CLKMGR_PERPLL_PLLC2 0x3c #define CLKMGR_PERPLL_PLLC3 0x40 #define CLKMGR_PERPLL_PLLM 0x44 #define CLKMGR_PERPLL_LOSTLOCK 0x50 /* Altera Group */ #define CLKMGR_ALTERA 0xffd100d0 #define CLKMGR_ALTERA_JTAG 0x0 #define CLKMGR_ALTERA_EMACACTR 0x4 #define CLKMGR_ALTERA_EMACBCTR 0x8 #define CLKMGR_ALTERA_EMACPTPCTR 0xc #define CLKMGR_ALTERA_GPIODBCTR 0x10 #define CLKMGR_ALTERA_SDMMCCTR 0x14 #define CLKMGR_ALTERA_S2FUSER0CTR 0x18 #define CLKMGR_ALTERA_S2FUSER1CTR 0x1c #define CLKMGR_ALTERA_PSIREFCTR 0x20 #define CLKMGR_ALTERA_EXTCNTRST 0x24 /* Membus */ #define CLKMGR_MEM_REQ BIT(24) #define CLKMGR_MEM_WR BIT(25) #define CLKMGR_MEM_ERR BIT(26) #define CLKMGR_MEM_WDAT_OFFSET 16 #define CLKMGR_MEM_ADDR 0x4027 #define CLKMGR_MEM_WDAT 0x80 /* Clock Manager Macros */ #define CLKMGR_CTRL_BOOTMODE_SET_MSK 0x00000001 #define CLKMGR_STAT_BUSY_E_BUSY 0x1 #define CLKMGR_STAT_BUSY(x) (((x) & 0x00000001) >> 0) #define CLKMGR_STAT_MAINPLLLOCKED(x) (((x) & 0x00000100) >> 8) #define CLKMGR_STAT_PERPLLLOCKED(x) (((x) & 0x00010000) >> 16) #define CLKMGR_INTRCLR_MAINLOCKLOST_SET_MSK 0x00000004 #define CLKMGR_INTRCLR_PERLOCKLOST_SET_MSK 0x00000008 #define CLKMGR_INTOSC_HZ 460000000 /* Main PLL Macros */ #define CLKMGR_MAINPLL_EN_RESET 0x000000ff /* Peripheral PLL Macros */ #define CLKMGR_PERPLL_EN_RESET 0x00000fff #define CLKMGR_PERPLL_GPIODIV_GPIODBCLK_SET(x) (((x) << 0) & 0x0000ffff) /* Altera Macros */ #define CLKMGR_ALTERA_EXTCNTRST_RESET 0xff /* Shared Macros */ #define CLKMGR_PSRC(x) (((x) & 0x00030000) >> 16) #define CLKMGR_PSRC_MAIN 0 #define CLKMGR_PSRC_PER 1 #define CLKMGR_PLLGLOB_PSRC_EOSC1 0x0 #define CLKMGR_PLLGLOB_PSRC_INTOSC 0x1 #define CLKMGR_PLLGLOB_PSRC_F2S 0x2 #define CLKMGR_PLLM_MDIV(x) ((x) & 0x000003ff) #define CLKMGR_PLLGLOB_PD_SET_MSK 0x00000001 #define CLKMGR_PLLGLOB_RST_SET_MSK 0x00000002 #define CLKMGR_PLLGLOB_REFCLKDIV(x) (((x) & 0x00003f00) >> 8) #define CLKMGR_PLLGLOB_AREFCLKDIV(x) (((x) & 0x00000f00) >> 8) #define CLKMGR_PLLGLOB_DREFCLKDIV(x) (((x) & 0x00003000) >> 12) #define CLKMGR_VCOCALIB_HSCNT_SET(x) (((x) << 0) & 0x000003ff) #define CLKMGR_VCOCALIB_MSCNT_SET(x) (((x) << 16) & 0x00ff0000) #define CLKMGR_CLR_LOSTLOCK_BYPASS 0x20000000 typedef struct { uint32_t clk_freq_of_eosc1; uint32_t clk_freq_of_f2h_free; uint32_t clk_freq_of_cb_intosc_ls; } CLOCK_SOURCE_CONFIG; void config_clkmgr_handoff(handoff *hoff_ptr); uint32_t get_wdt_clk(void); uint32_t get_uart_clk(void); uint32_t get_mmc_clk(void); #endif trusted-firmware-a-2.2/plat/intel/soc/agilex/include/agilex_handoff.h000066400000000000000000000047571355360272700257700ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef HANDOFF_H #define HANDOFF_H #define HANDOFF_MAGIC_HEADER 0x424f4f54 /* BOOT */ #define HANDOFF_MAGIC_PINMUX_SEL 0x504d5558 /* PMUX */ #define HANDOFF_MAGIC_IOCTLR 0x494f4354 /* IOCT */ #define HANDOFF_MAGIC_FPGA 0x46504741 /* FPGA */ #define HANDOFF_MAGIC_IODELAY 0x444c4159 /* DLAY */ #define HANDOFF_MAGIC_CLOCK 0x434c4b53 /* CLKS */ #define HANDOFF_MAGIC_MISC 0x4d495343 /* MISC */ typedef struct handoff_t { /* header */ uint32_t header_magic; uint32_t header_device; uint32_t _pad_0x08_0x10[2]; /* pinmux configuration - select */ uint32_t pinmux_sel_magic; uint32_t pinmux_sel_length; uint32_t _pad_0x18_0x20[2]; uint32_t pinmux_sel_array[96]; /* offset, value */ /* pinmux configuration - io control */ uint32_t pinmux_io_magic; uint32_t pinmux_io_length; uint32_t _pad_0x1a8_0x1b0[2]; uint32_t pinmux_io_array[96]; /* offset, value */ /* pinmux configuration - use fpga switch */ uint32_t pinmux_fpga_magic; uint32_t pinmux_fpga_length; uint32_t _pad_0x338_0x340[2]; uint32_t pinmux_fpga_array[42]; /* offset, value */ uint32_t _pad_0x3e8_0x3f0[2]; /* pinmux configuration - io delay */ uint32_t pinmux_delay_magic; uint32_t pinmux_delay_length; uint32_t _pad_0x3f8_0x400[2]; uint32_t pinmux_iodelay_array[96]; /* offset, value */ /* clock configuration */ uint32_t clock_magic; uint32_t clock_length; uint32_t _pad_0x588_0x590[2]; uint32_t main_pll_mpuclk; uint32_t main_pll_nocclk; uint32_t main_pll_nocdiv; uint32_t main_pll_pllglob; uint32_t main_pll_fdbck; uint32_t main_pll_pllc0; uint32_t main_pll_pllc1; uint32_t main_pll_pllc2; uint32_t main_pll_pllc3; uint32_t main_pll_pllm; uint32_t per_pll_emacctl; uint32_t per_pll_gpiodiv; uint32_t per_pll_pllglob; uint32_t per_pll_fdbck; uint32_t per_pll_pllc0; uint32_t per_pll_pllc1; uint32_t per_pll_pllc2; uint32_t per_pll_pllc3; uint32_t per_pll_pllm; uint32_t alt_emacactr; uint32_t alt_emacbctr; uint32_t alt_emacptpctr; uint32_t alt_gpiodbctr; uint32_t alt_sdmmcctr; uint32_t alt_s2fuser0ctr; uint32_t alt_s2fuser1ctr; uint32_t alt_psirefctr; uint32_t hps_osc_clk_h; uint32_t fpga_clk_hz; uint32_t _pad_0x604_0x610[3]; /* misc configuration */ uint32_t misc_magic; uint32_t misc_length; uint32_t _pad_0x618_0x620[2]; uint32_t boot_source; } handoff; int verify_handoff_image(handoff *hoff_ptr, handoff *reverse_hoff_ptr); int agilex_get_handoff(handoff *hoff_ptr); #endif trusted-firmware-a-2.2/plat/intel/soc/agilex/include/agilex_mailbox.h000066400000000000000000000075421355360272700260110ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef AGX_MBOX_H #define AGX_MBOX_H #include #define MBOX_OFFSET 0xffa30000 #define MBOX_ATF_CLIENT_ID 0x1 #define MBOX_JOB_ID 0x1 /* Mailbox interrupt flags and masks */ #define MBOX_INT_FLAG_COE 0x1 #define MBOX_INT_FLAG_RIE 0x2 #define MBOX_INT_FLAG_UAE 0x100 #define MBOX_COE_BIT(INTERRUPT) ((INTERRUPT) & 0x3) #define MBOX_UAE_BIT(INTERRUPT) (((INTERRUPT) & (1<<8))) /* Mailbox response and status */ #define MBOX_RESP_BUFFER_SIZE 16 #define MBOX_RESP_ERR(BUFFER) ((BUFFER) & 0x00000fff) #define MBOX_RESP_LEN(BUFFER) (((BUFFER) & 0x007ff000) >> 12) #define MBOX_RESP_CLIENT_ID(BUFFER) (((BUFFER) & 0xf0000000) >> 28) #define MBOX_RESP_JOB_ID(BUFFER) (((BUFFER) & 0x0f000000) >> 24) #define MBOX_STATUS_UA_MASK (1<<8) /* Mailbox command and response */ #define MBOX_CMD_FREE_OFFSET 0x14 #define MBOX_CMD_BUFFER_SIZE 32 #define MBOX_CLIENT_ID_CMD(CLIENT_ID) ((CLIENT_ID) << 28) #define MBOX_JOB_ID_CMD(JOB_ID) (JOB_ID<<24) #define MBOX_CMD_LEN_CMD(CMD_LEN) ((CMD_LEN) << 12) #define MBOX_INDIRECT (1 << 11) #define MBOX_INSUFFICIENT_BUFFER -2 #define MBOX_CIN 0x00 #define MBOX_ROUT 0x04 #define MBOX_URG 0x08 #define MBOX_INT 0x0C #define MBOX_COUT 0x20 #define MBOX_RIN 0x24 #define MBOX_STATUS 0x2C #define MBOX_CMD_BUFFER 0x40 #define MBOX_RESP_BUFFER 0xC0 #define MBOX_RESP_BUFFER_SIZE 16 #define MBOX_RESP_OK 0 #define MBOX_RESP_INVALID_CMD 1 #define MBOX_RESP_UNKNOWN_BR 2 #define MBOX_RESP_UNKNOWN 3 #define MBOX_RESP_NOT_CONFIGURED 256 /* Mailbox SDM doorbell */ #define MBOX_DOORBELL_TO_SDM 0x400 #define MBOX_DOORBELL_FROM_SDM 0x480 /* Mailbox QSPI commands */ #define MBOX_CMD_RESTART 2 #define MBOX_CMD_QSPI_OPEN 50 #define MBOX_CMD_QSPI_CLOSE 51 #define MBOX_CMD_QSPI_DIRECT 59 #define MBOX_CMD_GET_IDCODE 16 #define MBOX_CMD_QSPI_SET_CS 52 /* Mailbox REBOOT commands */ #define MBOX_CMD_REBOOT_HPS 71 /* Generic error handling */ #define MBOX_TIMEOUT -2047 #define MBOX_NO_RESPONSE -2 #define MBOX_WRONG_ID -3 /* Mailbox status */ #define RECONFIG_STATUS_STATE 0 #define RECONFIG_STATUS_PIN_STATUS 2 #define RECONFIG_STATUS_SOFTFUNC_STATUS 3 #define PIN_STATUS_NSTATUS (U(1) << 31) #define SOFTFUNC_STATUS_SEU_ERROR (1 << 3) #define SOFTFUNC_STATUS_INIT_DONE (1 << 1) #define SOFTFUNC_STATUS_CONF_DONE (1 << 0) #define MBOX_CFGSTAT_STATE_CONFIG 0x10000000 /* SMC function IDs for SiP Service queries */ #define SIP_SVC_CALL_COUNT 0x8200ff00 #define SIP_SVC_UID 0x8200ff01 #define SIP_SVC_VERSION 0x8200ff03 /* SiP Service Calls version numbers */ #define SIP_SVC_VERSION_MAJOR 0 #define SIP_SVC_VERSION_MINOR 1 /* Mailbox reconfiguration commands */ #define MBOX_RECONFIG 6 #define MBOX_RECONFIG_DATA 8 #define MBOX_RECONFIG_STATUS 9 /* Sip get memory */ #define INTEL_SIP_SMC_FPGA_CONFIG_START 0xC2000001 #define INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM 0xC2000005 #define INTEL_SIP_SMC_FPGA_CONFIG_ISDONE 0xC2000004 #define INTEL_SIP_SMC_FPGA_CONFIG_WRITE 0x42000002 #define INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE 0xC2000003 #define INTEL_SIP_SMC_STATUS_OK 0 #define INTEL_SIP_SMC_STATUS_ERROR 0x4 #define INTEL_SIP_SMC_STATUS_BUSY 0x1 #define INTEL_SIP_SMC_STATUS_REJECTED 0x2 #define INTEL_SIP_SMC_FPGA_CONFIG_ADDR 0x1000 #define INTEL_SIP_SMC_FPGA_CONFIG_SIZE 16777216 void mailbox_set_int(int interrupt_input); int mailbox_init(void); void mailbox_set_qspi_close(void); void mailbox_set_qspi_open(void); void mailbox_set_qspi_direct(void); int mailbox_send_cmd(int job_id, unsigned int cmd, uint32_t *args, int len, int urgent, uint32_t *response); void mailbox_send_cmd_async(int job_id, unsigned int cmd, uint32_t *args, int len, int urgent); int mailbox_read_response(int job_id, uint32_t *response); int mailbox_get_qspi_clock(void); void mailbox_reset_cold(void); #endif trusted-firmware-a-2.2/plat/intel/soc/agilex/include/agilex_memory_controller.h000066400000000000000000000154761355360272700301360ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef AGX_MEMORYCONTROLLER_H #define AGX_MEMORYCONTROLLER_H #define AGX_MPFE_IOHMC_REG_DRAMADDRW 0xf80100a8 #define AGX_MPFE_IOHMC_CTRLCFG0 0xf8010028 #define AGX_MPFE_IOHMC_CTRLCFG1 0xf801002c #define AGX_MPFE_IOHMC_CTRLCFG2 0xf8010030 #define AGX_MPFE_IOHMC_CTRLCFG3 0xf8010034 #define AGX_MPFE_IOHMC_DRAMADDRW 0xf80100a8 #define AGX_MPFE_IOHMC_DRAMTIMING0 0xf8010050 #define AGX_MPFE_IOHMC_CALTIMING0 0xf801007c #define AGX_MPFE_IOHMC_CALTIMING1 0xf8010080 #define AGX_MPFE_IOHMC_CALTIMING2 0xf8010084 #define AGX_MPFE_IOHMC_CALTIMING3 0xf8010088 #define AGX_MPFE_IOHMC_CALTIMING4 0xf801008c #define AGX_MPFE_IOHMC_CALTIMING9 0xf80100a0 #define AGX_MPFE_IOHMC_CALTIMING9_ACT_TO_ACT(x) (((x) & 0x000000ff) >> 0) #define AGX_MPFE_IOHMC_CTRLCFG1_CFG_ADDR_ORDER(value) \ (((value) & 0x00000060) >> 5) #define AGX_RSTMGR_BRGMODRST 0xffd1102c #define AGX_RSTMGR_BRGMODRST_DDRSCH 0x00000040 #define AGX_MPFE_HMC_ADP_ECCCTRL1 0xf8011100 #define AGX_MPFE_HMC_ADP_ECCCTRL2 0xf8011104 #define AGX_MPFE_HMC_ADP_RSTHANDSHAKESTAT 0xf8011218 #define AGX_MPFE_HMC_ADP_RSTHANDSHAKESTAT_SEQ2CORE 0x000000ff #define AGX_MPFE_HMC_ADP_RSTHANDSHAKECTRL 0xf8011214 #define AGX_MPFE_IOHMC_REG_CTRLCFG1 0xf801002c #define AGX_MPFE_IOHMC_REG_NIOSRESERVE0_OFST 0xf8010110 #define IOHMC_DRAMADDRW_COL_ADDR_WIDTH(x) (((x) & 0x0000001f) >> 0) #define IOHMC_DRAMADDRW_ROW_ADDR_WIDTH(x) (((x) & 0x000003e0) >> 5) #define IOHMC_DRAMADDRW_CS_ADDR_WIDTH(x) (((x) & 0x00070000) >> 16) #define IOHMC_DRAMADDRW_BANK_GRP_ADDR_WIDTH(x) (((x) & 0x0000c000) >> 14) #define IOHMC_DRAMADDRW_BANK_ADDR_WIDTH(x) (((x) & 0x00003c00) >> 10) #define AGX_MPFE_DDR(x) (0xf8000000 + x) #define AGX_MPFE_HMC_ADP_DDRCALSTAT 0xf801100c #define AGX_MPFE_DDR_MAIN_SCHED 0xf8000400 #define AGX_MPFE_DDR_MAIN_SCHED_DDRCONF 0xf8000408 #define AGX_MPFE_DDR_MAIN_SCHED_DDRTIMING 0xf800040c #define AGX_MPFE_DDR_MAIN_SCHED_DDRCONF_SET_MSK 0x0000001f #define AGX_MPFE_DDR_MAIN_SCHED_DDRMODE 0xf8000410 #define AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV 0xf800043c #define AGX_MPFE_DDR_MAIN_SCHED_READLATENCY 0xf8000414 #define AGX_MPFE_DDR_MAIN_SCHED_ACTIVATE 0xf8000438 #define AGX_MPFE_DDR_MAIN_SCHED_ACTIVATE_FAWBANK_OFST 10 #define AGX_MPFE_DDR_MAIN_SCHED_ACTIVATE_FAW_OFST 4 #define AGX_MPFE_DDR_MAIN_SCHED_ACTIVATE_RRD_OFST 0 #define AGX_MPFE_DDR_MAIN_SCHED_DDRCONF_SET(x) (((x) << 0) & 0x0000001f) #define AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTORD_OFST 0 #define AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTORD_MSK (BIT(0) | BIT(1)) #define AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTOWR_OFST 2 #define AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTOWR_MSK (BIT(2) | BIT(3)) #define AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSWRTORD_OFST 4 #define AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSWRTORD_MSK (BIT(4) | BIT(5)) #define AGX_MPFE_HMC_ADP(x) (0xf8011000 + (x)) #define AGX_MPFE_HMC_ADP_HPSINTFCSEL 0xf8011210 #define AGX_MPFE_HMC_ADP_DDRIOCTRL 0xf8011008 #define HMC_ADP_DDRIOCTRL 0x8 #define HMC_ADP_DDRIOCTRL_IO_SIZE(x) (((x) & 0x00000003) >> 0) #define HMC_ADP_DDRIOCTRL_CTRL_BURST_LENGTH(x) (((x) & 0x00003e00) >> 9) #define ADP_DRAMADDRWIDTH 0xe0 #define ACT_TO_ACT_DIFF_BANK(value) (((value) & 0x00fc0000) >> 18) #define ACT_TO_ACT(value) (((value) & 0x0003f000) >> 12) #define ACT_TO_RDWR(value) (((value) & 0x0000003f) >> 0) #define ACT_TO_ACT(value) (((value) & 0x0003f000) >> 12) /* timing 2 */ #define RD_TO_RD_DIFF_CHIP(value) (((value) & 0x00000fc0) >> 6) #define RD_TO_WR_DIFF_CHIP(value) (((value) & 0x3f000000) >> 24) #define RD_TO_WR(value) (((value) & 0x00fc0000) >> 18) #define RD_TO_PCH(value) (((value) & 0x00000fc0) >> 6) /* timing 3 */ #define CALTIMING3_WR_TO_RD_DIFF_CHIP(value) (((value) & 0x0003f000) >> 12) #define CALTIMING3_WR_TO_RD(value) (((value) & 0x00000fc0) >> 6) /* timing 4 */ #define PCH_TO_VALID(value) (((value) & 0x00000fc0) >> 6) #define DDRTIMING_BWRATIO_OFST 31 #define DDRTIMING_WRTORD_OFST 26 #define DDRTIMING_RDTOWR_OFST 21 #define DDRTIMING_BURSTLEN_OFST 18 #define DDRTIMING_WRTOMISS_OFST 12 #define DDRTIMING_RDTOMISS_OFST 6 #define DDRTIMING_ACTTOACT_OFST 0 #define ADP_DDRIOCTRL_IO_SIZE(x) (((x) & 0x3) >> 0) #define DDRMODE_AUTOPRECHARGE_OFST 1 #define DDRMODE_BWRATIOEXTENDED_OFST 0 #define AGX_MPFE_IOHMC_REG_DRAMTIMING0_CFG_TCL(x) (((x) & 0x7f) >> 0) #define AGX_MPFE_IOHMC_REG_CTRLCFG0_CFG_MEM_TYPE(x) (((x) & 0x0f) >> 0) #define AGX_CCU_CPU0_MPRT_DDR 0xf7004400 #define AGX_CCU_CPU0_MPRT_MEM0 0xf70045c0 #define AGX_CCU_CPU0_MPRT_MEM1A 0xf70045e0 #define AGX_CCU_CPU0_MPRT_MEM1B 0xf7004600 #define AGX_CCU_CPU0_MPRT_MEM1C 0xf7004620 #define AGX_CCU_CPU0_MPRT_MEM1D 0xf7004640 #define AGX_CCU_CPU0_MPRT_MEM1E 0xf7004660 #define AGX_CCU_IOM_MPRT_MEM0 0xf7018560 #define AGX_CCU_IOM_MPRT_MEM1A 0xf7018580 #define AGX_CCU_IOM_MPRT_MEM1B 0xf70185a0 #define AGX_CCU_IOM_MPRT_MEM1C 0xf70185c0 #define AGX_CCU_IOM_MPRT_MEM1D 0xf70185e0 #define AGX_CCU_IOM_MPRT_MEM1E 0xf7018600 #define AGX_NOC_FW_DDR_SCR 0xf8020200 #define AGX_NOC_FW_DDR_SCR_MPUREGION0ADDR_LIMITEXT 0xf802021c #define AGX_NOC_FW_DDR_SCR_MPUREGION0ADDR_LIMIT 0xf8020218 #define AGX_NOC_FW_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT 0xf802029c #define AGX_NOC_FW_DDR_SCR_NONMPUREGION0ADDR_LIMIT 0xf8020298 #define AGX_SOC_NOC_FW_DDR_SCR_ENABLE 0xf8020200 #define AGX_SOC_NOC_FW_DDR_SCR_ENABLESET 0xf8020204 #define AGX_CCU_NOC_DI_SET_MSK 0x10 #define AGX_SYSMGR_CORE_HMC_CLK 0xffd120b4 #define AGX_SYSMGR_CORE_HMC_CLK_STATUS 0x00000001 #define AGX_MPFE_IOHMC_NIOSRESERVE0_NIOS_RESERVE0(x) (((x) & 0xffff) >> 0) #define AGX_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE_MSK 0x00000003 #define AGX_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE_OFST 0 #define AGX_MPFE_HMC_ADP_HPSINTFCSEL_ENABLE 0x001f1f1f #define AGX_IOHMC_CTRLCFG1_ENABLE_ECC_OFST 7 #define AGX_MPFE_HMC_ADP_ECCCTRL1_AUTOWB_CNT_RST_SET_MSK 0x00010000 #define AGX_MPFE_HMC_ADP_ECCCTRL1_CNT_RST_SET_MSK 0x00000100 #define AGX_MPFE_HMC_ADP_ECCCTRL1_ECC_EN_SET_MSK 0x00000001 #define AGX_MPFE_HMC_ADP_ECCCTRL2_AUTOWB_EN_SET_MSK 0x00000001 #define AGX_MPFE_HMC_ADP_ECCCTRL2_OVRW_RB_ECC_EN_SET_MSK 0x00010000 #define AGX_MPFE_HMC_ADP_ECCCTRL2_RMW_EN_SET_MSK 0x00000100 #define AGX_MPFE_HMC_ADP_DDRCALSTAT_CAL(value) (((value) & 0x1) >> 0) #define AGX_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE(x) (((x) & 0x00003) >> 0) #define IOHMC_DRAMADDRW_CFG_BANK_ADDR_WIDTH(x) (((x) & 0x03c00) >> 10) #define IOHMC_DRAMADDRW_CFG_BANK_GROUP_ADDR_WIDTH(x) (((x) & 0x0c000) >> 14) #define IOHMC_DRAMADDRW_CFG_COL_ADDR_WIDTH(x) (((x) & 0x0001f) >> 0) #define IOHMC_DRAMADDRW_CFG_CS_ADDR_WIDTH(x) (((x) & 0x70000) >> 16) #define IOHMC_DRAMADDRW_CFG_ROW_ADDR_WIDTH(x) (((x) & 0x003e0) >> 5) #define AGX_SDRAM_0_LB_ADDR 0x0 #define AGX_DDR_SIZE 0x40000000 int init_hard_memory_controller(void); #endif trusted-firmware-a-2.2/plat/intel/soc/agilex/include/agilex_noc.h000066400000000000000000000047611355360272700251350ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef AGX_NOC_H #define AGX_NOC_H #define AXI_AP (1<<0) #define FPGA2SOC (1<<16) #define MPU (1<<24) #define AGX_NOC_PER_SCR_NAND 0xffd21000 #define AGX_NOC_PER_SCR_NAND_DATA 0xffd21004 #define AGX_NOC_PER_SCR_USB0 0xffd2100c #define AGX_NOC_PER_SCR_USB1 0xffd21010 #define AGX_NOC_PER_SCR_SPI_M0 0xffd2101c #define AGX_NOC_PER_SCR_SPI_M1 0xffd21020 #define AGX_NOC_PER_SCR_SPI_S0 0xffd21024 #define AGX_NOC_PER_SCR_SPI_S1 0xffd21028 #define AGX_NOC_PER_SCR_EMAC0 0xffd2102c #define AGX_NOC_PER_SCR_EMAC1 0xffd21030 #define AGX_NOC_PER_SCR_EMAC2 0xffd21034 #define AGX_NOC_PER_SCR_SDMMC 0xffd21040 #define AGX_NOC_PER_SCR_GPIO0 0xffd21044 #define AGX_NOC_PER_SCR_GPIO1 0xffd21048 #define AGX_NOC_PER_SCR_I2C0 0xffd21050 #define AGX_NOC_PER_SCR_I2C1 0xffd21058 #define AGX_NOC_PER_SCR_I2C2 0xffd2105c #define AGX_NOC_PER_SCR_I2C3 0xffd21060 #define AGX_NOC_PER_SCR_SP_TIMER0 0xffd21064 #define AGX_NOC_PER_SCR_SP_TIMER1 0xffd21068 #define AGX_NOC_PER_SCR_UART0 0xffd2106c #define AGX_NOC_PER_SCR_UART1 0xffd21070 #define AGX_NOC_SYS_SCR_DMA_ECC 0xffd21108 #define AGX_NOC_SYS_SCR_EMAC0RX_ECC 0xffd2110c #define AGX_NOC_SYS_SCR_EMAC0TX_ECC 0xffd21110 #define AGX_NOC_SYS_SCR_EMAC1RX_ECC 0xffd21114 #define AGX_NOC_SYS_SCR_EMAC1TX_ECC 0xffd21118 #define AGX_NOC_SYS_SCR_EMAC2RX_ECC 0xffd2111c #define AGX_NOC_SYS_SCR_EMAC2TX_ECC 0xffd21120 #define AGX_NOC_SYS_SCR_NAND_ECC 0xffd2112c #define AGX_NOC_SYS_SCR_NAND_READ_ECC 0xffd21130 #define AGX_NOC_SYS_SCR_NAND_WRITE_ECC 0xffd21134 #define AGX_NOC_SYS_SCR_OCRAM_ECC 0xffd21138 #define AGX_NOC_SYS_SCR_SDMMC_ECC 0xffd21140 #define AGX_NOC_SYS_SCR_USB0_ECC 0xffd21144 #define AGX_NOC_SYS_SCR_USB1_ECC 0xffd21148 #define AGX_NOC_SYS_SCR_CLK_MGR 0xffd2114c #define AGX_NOC_SYS_SCR_IO_MGR 0xffd21154 #define AGX_NOC_SYS_SCR_RST_MGR 0xffd21158 #define AGX_NOC_SYS_SCR_SYS_MGR 0xffd2115c #define AGX_NOC_SYS_SCR_OSC0_TIMER 0xffd21160 #define AGX_NOC_SYS_SCR_OSC1_TIMER 0xffd21164 #define AGX_NOC_SYS_SCR_WATCHDOG0 0xffd21168 #define AGX_NOC_SYS_SCR_WATCHDOG1 0xffd2116c #define AGX_NOC_SYS_SCR_WATCHDOG2 0xffd21170 #define AGX_NOC_SYS_SCR_WATCHDOG3 0xffd21174 #define AGX_NOC_SYS_SCR_DAP 0xffd21178 #define AGX_NOC_SYS_SCR_L4_NOC_PROBES 0xffd21190 #define AGX_NOC_SYS_SCR_L4_NOC_QOS 0xffd21194 #define AGX_CCU_NOC_BRIDGE_CPU0_RAM 0xf7004688 #define AGX_CCU_NOC_BRIDGE_IOM_RAM 0xf7004688 #endif trusted-firmware-a-2.2/plat/intel/soc/agilex/include/agilex_pinmux.h000066400000000000000000000006251355360272700256710ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef AGX_PINMUX_H #define AGX_PINMUX_H #define AGX_PINMUX_PIN0SEL 0xffd13000 #define AGX_PINMUX_IO0CTRL 0xffd13130 #define AGX_PINMUX_PINMUX_EMAC0_USEFPGA 0xffd13300 #define AGX_PINMUX_IO0_DELAY 0xffd13400 #include "agilex_handoff.h" void config_pinmux(handoff *handoff); #endif trusted-firmware-a-2.2/plat/intel/soc/agilex/include/agilex_private.h000066400000000000000000000013361355360272700260230ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef AGX_PRIVATE_H #define AGX_PRIVATE_H #define AGX_MMC_REG_BASE 0xff808000 #define EMMC_DESC_SIZE (1<<20) #define EMMC_INIT_PARAMS(base, clk) \ { .bus_width = MMC_BUS_WIDTH_4, \ .clk_rate = (clk), \ .desc_base = (base), \ .desc_size = EMMC_DESC_SIZE, \ .flags = 0, \ .reg_base = AGX_MMC_REG_BASE \ } typedef enum { BOOT_SOURCE_FPGA = 0, BOOT_SOURCE_SDMMC, BOOT_SOURCE_NAND, BOOT_SOURCE_RSVD, BOOT_SOURCE_QSPI } boot_source_type; void enable_nonsecure_access(void); void socfpga_io_setup(int boot_source); #endif trusted-firmware-a-2.2/plat/intel/soc/agilex/include/agilex_reset_manager.h000066400000000000000000000061641355360272700271710ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef AGX_RESETMANAGER_H #define AGX_RESETMANAGER_H #define AGX_RSTMGR_HDSKEN 0xffd11010 #define AGX_RSTMGR_PER0MODRST 0xffd11024 #define AGX_RSTMGR_PER1MODRST 0xffd11028 #define AGX_RSTMGR_BRGMODRST 0xffd1102c #define AGX_RSTMGR_PER0MODRST_EMAC0 0x00000001 #define AGX_RSTMGR_PER0MODRST_EMAC1 0x00000002 #define AGX_RSTMGR_PER0MODRST_EMAC2 0x00000004 #define AGX_RSTMGR_PER0MODRST_USB0 0x00000008 #define AGX_RSTMGR_PER0MODRST_USB1 0x00000010 #define AGX_RSTMGR_PER0MODRST_NAND 0x00000020 #define AGX_RSTMGR_PER0MODRST_SDMMC 0x00000080 #define AGX_RSTMGR_PER0MODRST_EMAC0OCP 0x00000100 #define AGX_RSTMGR_PER0MODRST_EMAC1OCP 0x00000200 #define AGX_RSTMGR_PER0MODRST_EMAC2OCP 0x00000400 #define AGX_RSTMGR_PER0MODRST_USB0OCP 0x00000800 #define AGX_RSTMGR_PER0MODRST_USB1OCP 0x00001000 #define AGX_RSTMGR_PER0MODRST_NANDOCP 0x00002000 #define AGX_RSTMGR_PER0MODRST_SDMMCOCP 0x00008000 #define AGX_RSTMGR_PER0MODRST_DMA 0x00010000 #define AGX_RSTMGR_PER0MODRST_SPIM0 0x00020000 #define AGX_RSTMGR_PER0MODRST_SPIM1 0x00040000 #define AGX_RSTMGR_PER0MODRST_SPIS0 0x00080000 #define AGX_RSTMGR_PER0MODRST_SPIS1 0x00100000 #define AGX_RSTMGR_PER0MODRST_DMAOCP 0x00200000 #define AGX_RSTMGR_PER0MODRST_EMACPTP 0x00400000 #define AGX_RSTMGR_PER0MODRST_DMAIF0 0x01000000 #define AGX_RSTMGR_PER0MODRST_DMAIF1 0x02000000 #define AGX_RSTMGR_PER0MODRST_DMAIF2 0x04000000 #define AGX_RSTMGR_PER0MODRST_DMAIF3 0x08000000 #define AGX_RSTMGR_PER0MODRST_DMAIF4 0x10000000 #define AGX_RSTMGR_PER0MODRST_DMAIF5 0x20000000 #define AGX_RSTMGR_PER0MODRST_DMAIF6 0x40000000 #define AGX_RSTMGR_PER0MODRST_DMAIF7 0x80000000 #define AGX_RSTMGR_PER1MODRST_WATCHDOG0 0x1 #define AGX_RSTMGR_PER1MODRST_WATCHDOG1 0x2 #define AGX_RSTMGR_PER1MODRST_WATCHDOG2 0x4 #define AGX_RSTMGR_PER1MODRST_WATCHDOG3 0x8 #define AGX_RSTMGR_PER1MODRST_L4SYSTIMER0 0x00000010 #define AGX_RSTMGR_PER1MODRST_L4SYSTIMER1 0x00000020 #define AGX_RSTMGR_PER1MODRST_SPTIMER0 0x00000040 #define AGX_RSTMGR_PER1MODRST_SPTIMER1 0x00000080 #define AGX_RSTMGR_PER1MODRST_I2C0 0x00000100 #define AGX_RSTMGR_PER1MODRST_I2C1 0x00000200 #define AGX_RSTMGR_PER1MODRST_I2C2 0x00000400 #define AGX_RSTMGR_PER1MODRST_I2C3 0x00000800 #define AGX_RSTMGR_PER1MODRST_I2C4 0x00001000 #define AGX_RSTMGR_PER1MODRST_UART0 0x00010000 #define AGX_RSTMGR_PER1MODRST_UART1 0x00020000 #define AGX_RSTMGR_PER1MODRST_GPIO0 0x01000000 #define AGX_RSTMGR_PER1MODRST_GPIO1 0x02000000 #define AGX_RSTMGR_HDSKEN_FPGAHSEN 0x00000004 #define AGX_RSTMGR_HDSKEN_ETRSTALLEN 0x00000008 #define AGX_RSTMGR_HDSKEN_L2FLUSHEN 0x00000100 #define AGX_RSTMGR_HDSKEN_L3NOC_DBG 0x00010000 #define AGX_RSTMGR_HDSKEN_DEBUG_L3NOC 0x00020000 #define AGX_RSTMGR_HDSKEN_SDRSELFREFEN 0x00000001 #define AGX_RSTMGR_BRGMODRST_SOC2FPGA 0x1 #define AGX_RSTMGR_BRGMODRST_LWHPS2FPGA 0x2 #define AGX_RSTMGR_BRGMODRST_FPGA2SOC 0x4 #define AGX_RSTMGR_BRGMODRST_MPFE 0x40 void deassert_peripheral_reset(void); void config_hps_hs_before_warm_reset(void); #endif trusted-firmware-a-2.2/plat/intel/soc/agilex/include/agilex_system_manager.h000066400000000000000000000063301355360272700273660ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef AGX_SYSTEMMANAGER_H #define AGX_SYSTEMMANAGER_H #define AGX_FIREWALL_SOC2FPGA 0xffd21200 #define AGX_FIREWALL_LWSOC2FPGA 0xffd21300 #define AGX_NOC_FW_L4_PER_SCR_NAND_REGISTER 0xffd21000 #define AGX_NOC_FW_L4_PER_SCR_NAND_DATA 0xffd21004 #define AGX_NOC_FW_L4_PER_SCR_USB0_REGISTER 0xffd2100c #define AGX_NOC_FW_L4_PER_SCR_USB1_REGISTER 0xffd21010 #define AGX_NOC_FW_L4_PER_SCR_SPI_MASTER0 0xffd2101c #define AGX_NOC_FW_L4_PER_SCR_SPI_MASTER1 0xffd21020 #define AGX_NOC_FW_L4_PER_SCR_SPI_SLAVE0 0xffd21024 #define AGX_NOC_FW_L4_PER_SCR_SPI_SLAVE1 0xffd21028 #define AGX_NOC_FW_L4_PER_SCR_EMAC0 0xffd2102c #define AGX_NOC_FW_L4_PER_SCR_EMAC1 0xffd21030 #define AGX_NOC_FW_L4_PER_SCR_EMAC2 0xffd21034 #define AGX_NOC_FW_L4_PER_SCR_SDMMC 0xffd21040 #define AGX_NOC_FW_L4_PER_SCR_GPIO0 0xffd21044 #define AGX_NOC_FW_L4_PER_SCR_GPIO1 0xffd21048 #define AGX_NOC_FW_L4_PER_SCR_I2C0 0xffd21050 #define AGX_NOC_FW_L4_PER_SCR_I2C1 0xffd21054 #define AGX_NOC_FW_L4_PER_SCR_I2C2 0xffd21058 #define AGX_NOC_FW_L4_PER_SCR_I2C3 0xffd2105c #define AGX_NOC_FW_L4_PER_SCR_I2C4 0xffd21060 #define AGX_NOC_FW_L4_PER_SCR_SP_TIMER0 0xffd21064 #define AGX_NOC_FW_L4_PER_SCR_SP_TIMER1 0xffd21068 #define AGX_NOC_FW_L4_PER_SCR_UART0 0xffd2106c #define AGX_NOC_FW_L4_PER_SCR_UART1 0xffd21070 #define AGX_NOC_FW_L4_SYS_SCR_DMA_ECC 0xffd21108 #define AGX_NOC_FW_L4_SYS_SCR_EMAC0RX_ECC 0xffd2110c #define AGX_NOC_FW_L4_SYS_SCR_EMAC0TX_ECC 0xffd21110 #define AGX_NOC_FW_L4_SYS_SCR_EMAC1RX_ECC 0xffd21114 #define AGX_NOC_FW_L4_SYS_SCR_EMAC1TX_ECC 0xffd21118 #define AGX_NOC_FW_L4_SYS_SCR_EMAC2RX_ECC 0xffd2111c #define AGX_NOC_FW_L4_SYS_SCR_EMAC2TX_ECC 0xffd21120 #define AGX_NOC_FW_L4_SYS_SCR_NAND_ECC 0xffd2112c #define AGX_NOC_FW_L4_SYS_SCR_NAND_READ_ECC 0xffd21130 #define AGX_NOC_FW_L4_SYS_SCR_NAND_WRITE_ECC 0xffd21134 #define AGX_NOC_FW_L4_SYS_SCR_OCRAM_ECC 0xffd21138 #define AGX_NOC_FW_L4_SYS_SCR_SDMMC_ECC 0xffd21140 #define AGX_NOC_FW_L4_SYS_SCR_USB0_ECC 0xffd21144 #define AGX_NOC_FW_L4_SYS_SCR_USB1_ECC 0xffd21148 #define AGX_NOC_FW_L4_SYS_SCR_CLK_MGR 0xffd2114c #define AGX_NOC_FW_L4_SYS_SCR_IO_MGR 0xffd21154 #define AGX_NOC_FW_L4_SYS_SCR_RST_MGR 0xffd21158 #define AGX_NOC_FW_L4_SYS_SCR_SYS_MGR 0xffd2115c #define AGX_NOC_FW_L4_SYS_SCR_OSC0_TIMER 0xffd21160 #define AGX_NOC_FW_L4_SYS_SCR_OSC1_TIMER 0xffd21164 #define AGX_NOC_FW_L4_SYS_SCR_WATCHDOG0 0xffd21168 #define AGX_NOC_FW_L4_SYS_SCR_WATCHDOG1 0xffd2116c #define AGX_NOC_FW_L4_SYS_SCR_WATCHDOG2 0xffd21170 #define AGX_NOC_FW_L4_SYS_SCR_WATCHDOG3 0xffd21174 #define AGX_NOC_FW_L4_SYS_SCR_DAP 0xffd21178 #define AGX_NOC_FW_L4_SYS_SCR_L4_NOC_PROBES 0xffd21190 #define AGX_NOC_FW_L4_SYS_SCR_L4_NOC_QOS 0xffd21194 #define AGX_CCU_NOC_CPU0_RAMSPACE0_0 0xf7004688 #define AGX_CCU_NOC_IOM_RAMSPACE0_0 0xf7018628 #define AGX_SYSMGR_CORE(x) (0xffd12000 + (x)) #define SYSMGR_BOOT_SCRATCH_COLD_0 0x200 #define SYSMGR_BOOT_SCRATCH_COLD_1 0x204 #define SYSMGR_BOOT_SCRATCH_COLD_2 0x208 #define DISABLE_BRIDGE_FIREWALL 0x0ffe0101 #define DISABLE_L4_FIREWALL (BIT(0) | BIT(16) | BIT(24)) void enable_nonsecure_access(void); void enable_ns_bridge_access(void); #endif trusted-firmware-a-2.2/plat/intel/soc/agilex/include/platform_def.h000066400000000000000000000155311355360272700254640ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include #define PLAT_CPUID_RELEASE 0xffe1b000 #define PLAT_SEC_ENTRY 0xffe1b008 /* Define next boot image name and offset */ #define PLAT_NS_IMAGE_OFFSET 0x50000 #define PLAT_HANDOFF_OFFSET 0xFFE3F000 /******************************************************************************* * Platform binary types for linking ******************************************************************************/ #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 /* Agilex supports up to 124GB RAM */ #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 39) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 39) /******************************************************************************* * Generic platform constants ******************************************************************************/ #define PLAT_PRIMARY_CPU 0 #define PLAT_SECONDARY_ENTRY_BASE 0x01f78bf0 /* Size of cacheable stacks */ #define PLATFORM_STACK_SIZE 0x2000 /* PSCI related constant */ #define PLAT_NUM_POWER_DOMAINS 5 #define PLAT_MAX_PWR_LVL 1 #define PLAT_MAX_RET_STATE 1 #define PLAT_MAX_OFF_STATE 2 #define PLATFORM_SYSTEM_COUNT 1 #define PLATFORM_CLUSTER_COUNT 1 #define PLATFORM_CLUSTER0_CORE_COUNT 4 #define PLATFORM_CLUSTER1_CORE_COUNT 0 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \ PLATFORM_CLUSTER0_CORE_COUNT) #define PLATFORM_MAX_CPUS_PER_CLUSTER 4 /* Interrupt related constant */ #define INTEL_AGX_IRQ_SEC_PHY_TIMER 29 #define INTEL_AGX_IRQ_SEC_SGI_0 8 #define INTEL_AGX_IRQ_SEC_SGI_1 9 #define INTEL_AGX_IRQ_SEC_SGI_2 10 #define INTEL_AGX_IRQ_SEC_SGI_3 11 #define INTEL_AGX_IRQ_SEC_SGI_4 12 #define INTEL_AGX_IRQ_SEC_SGI_5 13 #define INTEL_AGX_IRQ_SEC_SGI_6 14 #define INTEL_AGX_IRQ_SEC_SGI_7 15 #define TSP_IRQ_SEC_PHY_TIMER INTEL_AGX_IRQ_SEC_PHY_TIMER #define TSP_SEC_MEM_BASE BL32_BASE #define TSP_SEC_MEM_SIZE (BL32_LIMIT - BL32_BASE + 1) /******************************************************************************* * Platform memory map related constants ******************************************************************************/ #define DRAM_BASE (0x0) #define DRAM_SIZE (0x80000000) #define OCRAM_BASE (0xFFE00000) #define OCRAM_SIZE (0x00040000) #define MEM64_BASE (0x0100000000) #define MEM64_SIZE (0x1F00000000) #define DEVICE1_BASE (0x80000000) #define DEVICE1_SIZE (0x60000000) #define DEVICE2_BASE (0xF7000000) #define DEVICE2_SIZE (0x08E00000) #define DEVICE3_BASE (0xFFFC0000) #define DEVICE3_SIZE (0x00008000) #define DEVICE4_BASE (0x2000000000) #define DEVICE4_SIZE (0x0100000000) /******************************************************************************* * BL31 specific defines. ******************************************************************************/ /* * Put BL3-1 at the top of the Trusted SRAM (just below the shared memory, if * present). BL31_BASE is calculated using the current BL3-1 debug size plus a * little space for growth. */ #define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n" #define BL1_RO_BASE (0xffe00000) #define BL1_RO_LIMIT (0xffe0f000) #define BL1_RW_BASE (0xffe10000) #define BL1_RW_LIMIT (0xffe1ffff) #define BL1_RW_SIZE (0x14000) #define BL2_BASE (0xffe00000) #define BL2_LIMIT (0xffe1b000) #define BL31_BASE (0xffe1c000) #define BL31_LIMIT (0xffe3bfff) /******************************************************************************* * Platform specific page table and MMU setup constants ******************************************************************************/ #define MAX_XLAT_TABLES 8 #define MAX_MMAP_REGIONS 16 /******************************************************************************* * Declarations and constants to access the mailboxes safely. Each mailbox is * aligned on the biggest cache line size in the platform. This is known only * to the platform as it might have a combination of integrated and external * caches. Such alignment ensures that two maiboxes do not sit on the same cache * line at any cache level. They could belong to different cpus/clusters & * get written while being protected by different locks causing corruption of * a valid mailbox address. ******************************************************************************/ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) #define PLAT_GIC_BASE (0xFFFC0000) #define PLAT_GICC_BASE (PLAT_GIC_BASE + 0x2000) #define PLAT_GICD_BASE (PLAT_GIC_BASE + 0x1000) #define PLAT_GICR_BASE 0 /******************************************************************************* * UART related constants ******************************************************************************/ #define PLAT_UART0_BASE (0xFFC02000) #define PLAT_UART1_BASE (0xFFC02100) #define CRASH_CONSOLE_BASE PLAT_UART0_BASE #define PLAT_BAUDRATE (115200) #define PLAT_UART_CLOCK (100000000) /******************************************************************************* * System counter frequency related constants ******************************************************************************/ #define PLAT_SYS_COUNTER_FREQ_IN_TICKS (400000000) #define PLAT_SYS_COUNTER_FREQ_IN_MHZ (400) #define PLAT_INTEL_AGX_GICD_BASE PLAT_GICD_BASE #define PLAT_INTEL_AGX_GICC_BASE PLAT_GICC_BASE /* * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 * terminology. On a GICv2 system or mode, the lists will be merged and treated * as Group 0 interrupts. */ #define PLAT_INTEL_AGX_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(INTEL_AGX_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE) #define PLAT_INTEL_AGX_G0_IRQ_PROPS(grp) #define MAX_IO_HANDLES 4 #define MAX_IO_DEVICES 4 #define MAX_IO_BLOCK_DEVICES 2 #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/intel/soc/agilex/platform.mk000066400000000000000000000053371355360272700234060ustar00rootroot00000000000000# # Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. # Copyright (c) 2019, Intel Corporation. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # PLAT_INCLUDES := \ -Iplat/intel/soc/agilex/include/ \ -Iplat/intel/soc/common/drivers/ \ -Iplat/intel/soc/common/include/ PLAT_BL_COMMON_SOURCES := \ drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/ti/uart/aarch64/16550_console.S \ lib/xlat_tables/aarch64/xlat_tables.c \ lib/xlat_tables/xlat_tables_common.c \ plat/common/plat_gicv2.c \ plat/intel/soc/common/aarch64/platform_common.c \ plat/intel/soc/common/aarch64/plat_helpers.S BL2_SOURCES += \ common/desc_image_load.c \ drivers/partition/partition.c \ drivers/partition/gpt.c \ drivers/arm/pl061/pl061_gpio.c \ drivers/mmc/mmc.c \ drivers/synopsys/emmc/dw_mmc.c \ drivers/io/io_storage.c \ drivers/io/io_block.c \ drivers/io/io_fip.c \ drivers/gpio/gpio.c \ drivers/intel/soc/stratix10/io/s10_memmap_qspi.c \ lib/cpus/aarch64/cortex_a53.S \ plat/intel/soc/agilex/bl2_plat_setup.c \ plat/intel/soc/agilex/socfpga_storage.c \ plat/intel/soc/common/bl2_plat_mem_params_desc.c \ plat/intel/soc/agilex/soc/agilex_reset_manager.c \ plat/intel/soc/agilex/soc/agilex_handoff.c \ plat/intel/soc/agilex/soc/agilex_clock_manager.c \ plat/intel/soc/agilex/soc/agilex_pinmux.c \ plat/intel/soc/agilex/soc/agilex_memory_controller.c \ plat/intel/soc/common/socfpga_delay_timer.c \ plat/intel/soc/common/socfpga_image_load.c \ plat/intel/soc/agilex/soc/agilex_system_manager.c \ plat/intel/soc/agilex/soc/agilex_mailbox.c \ plat/intel/soc/common/drivers/qspi/cadence_qspi.c \ plat/intel/soc/common/drivers/wdt/watchdog.c \ plat/intel/soc/common/drivers/ccu/ncore_ccu.c BL31_SOURCES += \ drivers/arm/cci/cci.c \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/aem_generic.S \ plat/common/plat_psci_common.c \ plat/intel/soc/agilex/socfpga_sip_svc.c \ plat/intel/soc/agilex/bl31_plat_setup.c \ plat/intel/soc/agilex/socfpga_psci.c \ plat/intel/soc/common/socfpga_topology.c \ plat/intel/soc/common/socfpga_delay_timer.c \ plat/intel/soc/agilex/soc/agilex_reset_manager.c \ plat/intel/soc/agilex/soc/agilex_pinmux.c \ plat/intel/soc/agilex/soc/agilex_clock_manager.c \ plat/intel/soc/agilex/soc/agilex_handoff.c \ plat/intel/soc/agilex/soc/agilex_mailbox.c PROGRAMMABLE_RESET_ADDRESS := 0 BL2_AT_EL3 := 1 BL2_INV_DCACHE := 0 MULTI_CONSOLE_API := 1 USE_COHERENT_MEM := 1 trusted-firmware-a-2.2/plat/intel/soc/agilex/soc/000077500000000000000000000000001355360272700220055ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/intel/soc/agilex/soc/agilex_clock_manager.c000066400000000000000000000243101355360272700262670ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "agilex_clock_manager.h" #include "agilex_handoff.h" #include "agilex_system_manager.h" uint32_t wait_pll_lock(void) { uint32_t data; uint32_t count = 0; do { data = mmio_read_32(CLKMGR_OFFSET + CLKMGR_STAT); count++; if (count >= 1000) return -ETIMEDOUT; } while ((CLKMGR_STAT_MAINPLLLOCKED(data) == 0) || (CLKMGR_STAT_PERPLLLOCKED(data) == 0)); return 0; } uint32_t wait_fsm(void) { uint32_t data; uint32_t count = 0; do { data = mmio_read_32(CLKMGR_OFFSET + CLKMGR_STAT); count++; if (count >= 1000) return -ETIMEDOUT; } while (CLKMGR_STAT_BUSY(data) == CLKMGR_STAT_BUSY_E_BUSY); return 0; } uint32_t pll_source_sync_config(uint32_t pll_mem_offset) { uint32_t val = 0; uint32_t count = 0; uint32_t req_status = 0; val = (CLKMGR_MEM_WR | CLKMGR_MEM_REQ | CLKMGR_MEM_WDAT << CLKMGR_MEM_WDAT_OFFSET | CLKMGR_MEM_ADDR); mmio_write_32(pll_mem_offset, val); do { req_status = mmio_read_32(pll_mem_offset); count++; } while ((req_status & CLKMGR_MEM_REQ) && (count < 10)); if (count >= 100) return -ETIMEDOUT; return 0; } uint32_t pll_source_sync_read(uint32_t pll_mem_offset) { uint32_t val = 0; uint32_t rdata = 0; uint32_t count = 0; uint32_t req_status = 0; val = (CLKMGR_MEM_REQ | CLKMGR_MEM_ADDR); mmio_write_32(pll_mem_offset, val); do { req_status = mmio_read_32(pll_mem_offset); count++; } while ((req_status & CLKMGR_MEM_REQ) && (count < 10)); if (count >= 100) return -ETIMEDOUT; rdata = mmio_read_32(pll_mem_offset + 0x4); INFO("rdata (%x) = %x\n", pll_mem_offset + 0x4, rdata); return 0; } void config_clkmgr_handoff(handoff *hoff_ptr) { uint32_t mdiv, mscnt, hscnt; uint32_t arefclk_div, drefclk_div; /* Bypass all mainpllgrp's clocks */ mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_BYPASS, 0x7); wait_fsm(); /* Bypass all perpllgrp's clocks */ mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_BYPASS, 0x7f); wait_fsm(); /* Put both PLL in reset and power down */ mmio_clrbits_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB, CLKMGR_PLLGLOB_PD_SET_MSK | CLKMGR_PLLGLOB_RST_SET_MSK); mmio_clrbits_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB, CLKMGR_PLLGLOB_PD_SET_MSK | CLKMGR_PLLGLOB_RST_SET_MSK); /* Setup main PLL dividers */ mdiv = CLKMGR_PLLM_MDIV(hoff_ptr->main_pll_pllm); arefclk_div = CLKMGR_PLLGLOB_AREFCLKDIV( hoff_ptr->main_pll_pllglob); drefclk_div = CLKMGR_PLLGLOB_DREFCLKDIV( hoff_ptr->main_pll_pllglob); mscnt = 100 / (mdiv / BIT(drefclk_div)); if (!mscnt) mscnt = 1; hscnt = (mdiv * mscnt * BIT(drefclk_div) / arefclk_div) - 4; mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_VCOCALIB, CLKMGR_VCOCALIB_HSCNT_SET(hscnt) | CLKMGR_VCOCALIB_MSCNT_SET(mscnt)); mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_NOCDIV, hoff_ptr->main_pll_nocdiv); mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB, hoff_ptr->main_pll_pllglob); mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_FDBCK, hoff_ptr->main_pll_fdbck); mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLC0, hoff_ptr->main_pll_pllc0); mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLC1, hoff_ptr->main_pll_pllc1); mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLC2, hoff_ptr->main_pll_pllc2); mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLC3, hoff_ptr->main_pll_pllc3); mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLM, hoff_ptr->main_pll_pllm); mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_MPUCLK, hoff_ptr->main_pll_mpuclk); mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_NOCCLK, hoff_ptr->main_pll_nocclk); /* Setup peripheral PLL dividers */ mdiv = CLKMGR_PLLM_MDIV(hoff_ptr->per_pll_pllm); arefclk_div = CLKMGR_PLLGLOB_AREFCLKDIV( hoff_ptr->per_pll_pllglob); drefclk_div = CLKMGR_PLLGLOB_DREFCLKDIV( hoff_ptr->per_pll_pllglob); mscnt = 100 / (mdiv / BIT(drefclk_div)); if (!mscnt) mscnt = 1; hscnt = (mdiv * mscnt * BIT(drefclk_div) / arefclk_div) - 4; mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_VCOCALIB, CLKMGR_VCOCALIB_HSCNT_SET(hscnt) | CLKMGR_VCOCALIB_MSCNT_SET(mscnt)); mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_EMACCTL, hoff_ptr->per_pll_emacctl); mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_GPIODIV, CLKMGR_PERPLL_GPIODIV_GPIODBCLK_SET( hoff_ptr->per_pll_gpiodiv)); mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB, hoff_ptr->per_pll_pllglob); mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_FDBCK, hoff_ptr->per_pll_fdbck); mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLC0, hoff_ptr->per_pll_pllc0); mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLC1, hoff_ptr->per_pll_pllc1); mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLC2, hoff_ptr->per_pll_pllc2); mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLC3, hoff_ptr->per_pll_pllc3); mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLM, hoff_ptr->per_pll_pllm); /* Take both PLL out of reset and power up */ mmio_setbits_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB, CLKMGR_PLLGLOB_PD_SET_MSK | CLKMGR_PLLGLOB_RST_SET_MSK); mmio_setbits_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB, CLKMGR_PLLGLOB_PD_SET_MSK | CLKMGR_PLLGLOB_RST_SET_MSK); wait_pll_lock(); pll_source_sync_config(CLKMGR_MAINPLL + CLKMGR_MAINPLL_MEM); pll_source_sync_read(CLKMGR_MAINPLL + CLKMGR_MAINPLL_MEM); pll_source_sync_config(CLKMGR_PERPLL + CLKMGR_PERPLL_MEM); pll_source_sync_read(CLKMGR_PERPLL + CLKMGR_PERPLL_MEM); /*Configure Ping Pong counters in altera group */ mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_EMACACTR, hoff_ptr->alt_emacactr); mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_EMACBCTR, hoff_ptr->alt_emacbctr); mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_EMACPTPCTR, hoff_ptr->alt_emacptpctr); mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_GPIODBCTR, hoff_ptr->alt_gpiodbctr); mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_SDMMCCTR, hoff_ptr->alt_sdmmcctr); mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_S2FUSER0CTR, hoff_ptr->alt_s2fuser0ctr); mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_S2FUSER1CTR, hoff_ptr->alt_s2fuser1ctr); mmio_write_32(CLKMGR_ALTERA + CLKMGR_ALTERA_PSIREFCTR, hoff_ptr->alt_psirefctr); /* Clear lost lock bypass mode */ mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_LOSTLOCK, 0x1); mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_LOSTLOCK, 0x1); mmio_setbits_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB, CLKMGR_CLR_LOSTLOCK_BYPASS); mmio_setbits_32(CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB, CLKMGR_CLR_LOSTLOCK_BYPASS); /* Take all PLLs out of bypass */ mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_BYPASS, 0); wait_fsm(); mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_BYPASS, 0); wait_fsm(); /* Clear loss lock interrupt status register that */ /* might be set during configuration */ mmio_setbits_32(CLKMGR_OFFSET + CLKMGR_INTRCLR, CLKMGR_INTRCLR_MAINLOCKLOST_SET_MSK | CLKMGR_INTRCLR_PERLOCKLOST_SET_MSK); /* Take all ping pong counters out of reset */ mmio_clrbits_32(CLKMGR_ALTERA + CLKMGR_ALTERA_EXTCNTRST, CLKMGR_ALTERA_EXTCNTRST_RESET); /* Set safe mode / out of boot mode */ mmio_clrbits_32(CLKMGR_OFFSET + CLKMGR_CTRL, CLKMGR_CTRL_BOOTMODE_SET_MSK); wait_fsm(); /* Enable mainpllgrp's software-managed clock */ mmio_write_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_EN, CLKMGR_MAINPLL_EN_RESET); mmio_write_32(CLKMGR_PERPLL + CLKMGR_PERPLL_EN, CLKMGR_PERPLL_EN_RESET); /* Pass clock source frequency into scratch register */ mmio_write_32(AGX_SYSMGR_CORE(SYSMGR_BOOT_SCRATCH_COLD_1), hoff_ptr->hps_osc_clk_h); mmio_write_32(AGX_SYSMGR_CORE(SYSMGR_BOOT_SCRATCH_COLD_2), hoff_ptr->fpga_clk_hz); } /* Extract reference clock from platform clock source */ uint32_t get_ref_clk(uint32_t pllglob) { uint32_t arefclkdiv, ref_clk; uint32_t scr_reg; switch (CLKMGR_PSRC(pllglob)) { case CLKMGR_PLLGLOB_PSRC_EOSC1: scr_reg = AGX_SYSMGR_CORE(SYSMGR_BOOT_SCRATCH_COLD_1); ref_clk = mmio_read_32(scr_reg); break; case CLKMGR_PLLGLOB_PSRC_INTOSC: ref_clk = CLKMGR_INTOSC_HZ; break; case CLKMGR_PLLGLOB_PSRC_F2S: scr_reg = AGX_SYSMGR_CORE(SYSMGR_BOOT_SCRATCH_COLD_2); ref_clk = mmio_read_32(scr_reg); break; default: ref_clk = 0; assert(0); break; } arefclkdiv = CLKMGR_PLLGLOB_AREFCLKDIV(pllglob); ref_clk /= arefclkdiv; return ref_clk; } /* Calculate clock frequency based on parameter */ uint32_t get_clk_freq(uint32_t psrc_reg, uint32_t main_pllc, uint32_t per_pllc) { uint32_t clk_psrc, mdiv, ref_clk; uint32_t pllm_reg, pllc_reg, pllc_div, pllglob_reg; clk_psrc = mmio_read_32(CLKMGR_MAINPLL + psrc_reg); switch (CLKMGR_PSRC(clk_psrc)) { case CLKMGR_PSRC_MAIN: pllm_reg = CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLM; pllc_reg = CLKMGR_MAINPLL + main_pllc; pllglob_reg = CLKMGR_MAINPLL + CLKMGR_MAINPLL_PLLGLOB; break; case CLKMGR_PSRC_PER: pllm_reg = CLKMGR_PERPLL + CLKMGR_PERPLL_PLLM; pllc_reg = CLKMGR_PERPLL + per_pllc; pllglob_reg = CLKMGR_PERPLL + CLKMGR_PERPLL_PLLGLOB; break; default: return 0; } ref_clk = get_ref_clk(mmio_read_32(pllglob_reg)); mdiv = CLKMGR_PLLM_MDIV(mmio_read_32(pllm_reg)); ref_clk *= mdiv; pllc_div = mmio_read_32(pllc_reg) & 0x7ff; return ref_clk / pllc_div; } /* Return L3 interconnect clock */ uint32_t get_l3_clk(void) { uint32_t l3_clk; l3_clk = get_clk_freq(CLKMGR_MAINPLL_NOCCLK, CLKMGR_MAINPLL_PLLC1, CLKMGR_PERPLL_PLLC1); return l3_clk; } /* Calculate clock frequency to be used for watchdog timer */ uint32_t get_wdt_clk(void) { uint32_t l3_clk, l4_sys_clk; l3_clk = get_l3_clk(); l4_sys_clk = l3_clk / 4; return l4_sys_clk; } /* Calculate clock frequency to be used for UART driver */ uint32_t get_uart_clk(void) { uint32_t data32, l3_clk, l4_sp_clk; l3_clk = get_l3_clk(); data32 = mmio_read_32(CLKMGR_MAINPLL + CLKMGR_MAINPLL_NOCDIV); data32 = (data32 >> 16) & 0x3; l4_sp_clk = l3_clk >> data32; return l4_sp_clk; } /* Calculate clock frequency to be used for SDMMC driver */ uint32_t get_mmc_clk(void) { uint32_t data32, mmc_clk; mmc_clk = get_clk_freq(CLKMGR_ALTERA_SDMMCCTR, CLKMGR_MAINPLL_PLLC3, CLKMGR_PERPLL_PLLC3); data32 = mmio_read_32(CLKMGR_ALTERA + CLKMGR_ALTERA_SDMMCCTR); data32 = (data32 & 0x7ff) + 1; mmc_clk = (mmc_clk / data32) / 4; return mmc_clk; } trusted-firmware-a-2.2/plat/intel/soc/agilex/soc/agilex_handoff.c000066400000000000000000000020561355360272700251120ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "agilex_handoff.h" #define SWAP_UINT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | \ (((x) & 0x0000FF00) << 8) | ((x) << 24)) int agilex_get_handoff(handoff *reverse_hoff_ptr) { int i; uint32_t *buffer; handoff *handoff_ptr = (handoff *) PLAT_HANDOFF_OFFSET; memcpy(reverse_hoff_ptr, handoff_ptr, sizeof(handoff)); buffer = (uint32_t *)reverse_hoff_ptr; /* convert big endian to little endian */ for (i = 0; i < sizeof(handoff) / 4; i++) buffer[i] = SWAP_UINT32(buffer[i]); if (reverse_hoff_ptr->header_magic != HANDOFF_MAGIC_HEADER) return -1; if (reverse_hoff_ptr->pinmux_sel_magic != HANDOFF_MAGIC_PINMUX_SEL) return -1; if (reverse_hoff_ptr->pinmux_io_magic != HANDOFF_MAGIC_IOCTLR) return -1; if (reverse_hoff_ptr->pinmux_fpga_magic != HANDOFF_MAGIC_FPGA) return -1; if (reverse_hoff_ptr->pinmux_delay_magic != HANDOFF_MAGIC_IODELAY) return -1; return 0; } trusted-firmware-a-2.2/plat/intel/soc/agilex/soc/agilex_mailbox.c000066400000000000000000000144351355360272700251440ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "agilex_mailbox.h" static int fill_mailbox_circular_buffer(uint32_t header_cmd, uint32_t *args, int len) { uint32_t cmd_free_offset; int i; cmd_free_offset = mmio_read_32(MBOX_OFFSET + MBOX_CIN); if (cmd_free_offset >= MBOX_CMD_BUFFER_SIZE) { INFO("Insufficient buffer in mailbox\n"); return MBOX_INSUFFICIENT_BUFFER; } mmio_write_32(MBOX_OFFSET + MBOX_CMD_BUFFER + (cmd_free_offset++ * 4), header_cmd); for (i = 0; i < len; i++) { cmd_free_offset %= MBOX_CMD_BUFFER_SIZE; mmio_write_32(MBOX_OFFSET + MBOX_CMD_BUFFER + (cmd_free_offset++ * 4), args[i]); } cmd_free_offset %= MBOX_CMD_BUFFER_SIZE; mmio_write_32(MBOX_OFFSET + MBOX_CIN, cmd_free_offset); return 0; } int mailbox_read_response(int job_id, uint32_t *response) { int rin = 0; int rout = 0; int response_length = 0; int resp = 0; int total_resp_len = 0; int timeout = 100000; mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1); while (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) != 1) { if (timeout-- < 0) return MBOX_NO_RESPONSE; } mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0); rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN); rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT); while (rout != rin) { resp = mmio_read_32(MBOX_OFFSET + MBOX_RESP_BUFFER + ((rout++)*4)); rout %= MBOX_RESP_BUFFER_SIZE; mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout); if (MBOX_RESP_CLIENT_ID(resp) != MBOX_ATF_CLIENT_ID || MBOX_RESP_JOB_ID(resp) != job_id) { return MBOX_WRONG_ID; } if (MBOX_RESP_ERR(resp) > 0) { INFO("Error in response: %x\n", resp); return -resp; } response_length = MBOX_RESP_LEN(resp); while (response_length) { response_length--; resp = mmio_read_32(MBOX_OFFSET + MBOX_RESP_BUFFER + (rout)*4); if (response) { *(response + total_resp_len) = resp; total_resp_len++; } rout++; rout %= MBOX_RESP_BUFFER_SIZE; mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout); } return total_resp_len; } return MBOX_NO_RESPONSE; } int mailbox_poll_response(int job_id, int urgent, uint32_t *response) { int timeout = 80000; int rin = 0; int rout = 0; int response_length = 0; int resp = 0; int total_resp_len = 0; mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1); while (1) { while (timeout > 0 && mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) != 1) { timeout--; } if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) != 1) { INFO("Timed out waiting for SDM"); return MBOX_TIMEOUT; } mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0); if (urgent & 1) { if ((mmio_read_32(MBOX_OFFSET + MBOX_STATUS) & MBOX_STATUS_UA_MASK) ^ (urgent & MBOX_STATUS_UA_MASK)) { mmio_write_32(MBOX_OFFSET + MBOX_URG, 0); return 0; } mmio_write_32(MBOX_OFFSET + MBOX_URG, 0); INFO("Error: Mailbox did not get UA"); return -1; } rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN); rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT); while (rout != rin) { resp = mmio_read_32(MBOX_OFFSET + MBOX_RESP_BUFFER + ((rout++)*4)); rout %= MBOX_RESP_BUFFER_SIZE; mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout); if (MBOX_RESP_CLIENT_ID(resp) != MBOX_ATF_CLIENT_ID || MBOX_RESP_JOB_ID(resp) != job_id) continue; if (MBOX_RESP_ERR(resp) > 0) { INFO("Error in response: %x\n", resp); return -MBOX_RESP_ERR(resp); } response_length = MBOX_RESP_LEN(resp); while (response_length) { response_length--; resp = mmio_read_32(MBOX_OFFSET + MBOX_RESP_BUFFER + (rout)*4); if (response) { *(response + total_resp_len) = resp; total_resp_len++; } rout++; rout %= MBOX_RESP_BUFFER_SIZE; mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout); } return total_resp_len; } } } void mailbox_send_cmd_async(int job_id, unsigned int cmd, uint32_t *args, int len, int urgent) { if (urgent) mmio_write_32(MBOX_OFFSET + MBOX_URG, 1); fill_mailbox_circular_buffer(MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) | MBOX_JOB_ID_CMD(job_id) | MBOX_CMD_LEN_CMD(len) | MBOX_INDIRECT | cmd, args, len); } int mailbox_send_cmd(int job_id, unsigned int cmd, uint32_t *args, int len, int urgent, uint32_t *response) { int status; if (urgent) { urgent |= mmio_read_32(MBOX_OFFSET + MBOX_STATUS) & MBOX_STATUS_UA_MASK; mmio_write_32(MBOX_OFFSET + MBOX_URG, cmd); status = 0; } else { status = fill_mailbox_circular_buffer( MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) | MBOX_JOB_ID_CMD(job_id) | cmd, args, len); } if (status) return status; return mailbox_poll_response(job_id, urgent, response); } void mailbox_set_int(int interrupt) { mmio_write_32(MBOX_OFFSET+MBOX_INT, MBOX_COE_BIT(interrupt) | MBOX_UAE_BIT(interrupt)); } void mailbox_set_qspi_open(void) { mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE); mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_OPEN, 0, 0, 0, 0); } void mailbox_set_qspi_direct(void) { mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_DIRECT, 0, 0, 0, 0); } void mailbox_set_qspi_close(void) { mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE); mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_CLOSE, 0, 0, 0, 0); } int mailbox_get_qspi_clock(void) { mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE); return mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_DIRECT, 0, 0, 0, 0); } void mailbox_qspi_set_cs(int device_select) { uint32_t cs_setting = device_select; /* QSPI device select settings at 31:28 */ cs_setting = (cs_setting << 28); mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE); mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_SET_CS, &cs_setting, 1, 0, 0); } void mailbox_reset_cold(void) { mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE); mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_REBOOT_HPS, 0, 0, 0, 0); } int mailbox_init(void) { int status = 0; mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE | MBOX_INT_FLAG_UAE); mmio_write_32(MBOX_OFFSET + MBOX_URG, 0); mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0); status = mailbox_send_cmd(0, MBOX_CMD_RESTART, 0, 0, 1, 0); if (status) return status; mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE); return 0; } trusted-firmware-a-2.2/plat/intel/soc/agilex/soc/agilex_memory_controller.c000066400000000000000000000256001355360272700272600ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "agilex_memory_controller.h" #define ALT_CCU_NOC_DI_SET_MSK 0x10 #define DDR_READ_LATENCY_DELAY 40 #define MAX_MEM_CAL_RETRY 3 #define PRE_CALIBRATION_DELAY 1 #define POST_CALIBRATION_DELAY 1 #define TIMEOUT_EMIF_CALIBRATION 1000 #define CLEAR_EMIF_DELAY 50000 #define CLEAR_EMIF_TIMEOUT 0x100000 #define TIMEOUT_INT_RESP 10000 #define DDR_CONFIG(A, B, C, R) (((A) << 24) | ((B) << 16) | ((C) << 8) | (R)) #define DDR_CONFIG_ELEMENTS (sizeof(ddr_config)/sizeof(uint32_t)) /* tWR = Min. 15ns constant, see JEDEC standard eg. DDR4 is JESD79-4.pdf */ #define tWR_IN_NS 15 void configure_hmc_adaptor_regs(void); void configure_ddr_sched_ctrl_regs(void); /* The followring are the supported configurations */ uint32_t ddr_config[] = { /* DDR_CONFIG(Address order,Bank,Column,Row) */ /* List for DDR3 or LPDDR3 (pinout order > chip, row, bank, column) */ DDR_CONFIG(0, 3, 10, 12), DDR_CONFIG(0, 3, 9, 13), DDR_CONFIG(0, 3, 10, 13), DDR_CONFIG(0, 3, 9, 14), DDR_CONFIG(0, 3, 10, 14), DDR_CONFIG(0, 3, 10, 15), DDR_CONFIG(0, 3, 11, 14), DDR_CONFIG(0, 3, 11, 15), DDR_CONFIG(0, 3, 10, 16), DDR_CONFIG(0, 3, 11, 16), DDR_CONFIG(0, 3, 12, 15), /* 0xa */ /* List for DDR4 only (pinout order > chip, bank, row, column) */ DDR_CONFIG(1, 3, 10, 14), DDR_CONFIG(1, 4, 10, 14), DDR_CONFIG(1, 3, 10, 15), DDR_CONFIG(1, 4, 10, 15), DDR_CONFIG(1, 3, 10, 16), DDR_CONFIG(1, 4, 10, 16), DDR_CONFIG(1, 3, 10, 17), DDR_CONFIG(1, 4, 10, 17), }; static int match_ddr_conf(uint32_t ddr_conf) { int i; for (i = 0; i < DDR_CONFIG_ELEMENTS; i++) { if (ddr_conf == ddr_config[i]) return i; } return 0; } static int check_hmc_clk(void) { unsigned long timeout = 0; uint32_t hmc_clk; do { hmc_clk = mmio_read_32(AGX_SYSMGR_CORE_HMC_CLK); if (hmc_clk & AGX_SYSMGR_CORE_HMC_CLK_STATUS) break; udelay(1); } while (++timeout < 1000); if (timeout >= 1000) return -ETIMEDOUT; return 0; } static int clear_emif(void) { uint32_t data; unsigned long timeout; mmio_write_32(AGX_MPFE_HMC_ADP_RSTHANDSHAKECTRL, 0); timeout = 0; do { data = mmio_read_32(AGX_MPFE_HMC_ADP_RSTHANDSHAKESTAT); if ((data & AGX_MPFE_HMC_ADP_RSTHANDSHAKESTAT_SEQ2CORE) == 0) break; udelay(CLEAR_EMIF_DELAY); } while (++timeout < CLEAR_EMIF_TIMEOUT); if (timeout >= CLEAR_EMIF_TIMEOUT) return -ETIMEDOUT; return 0; } static int mem_calibration(void) { int status; uint32_t data; unsigned long timeout; unsigned long retry = 0; udelay(PRE_CALIBRATION_DELAY); do { if (retry != 0) INFO("DDR: Retrying DRAM calibration\n"); timeout = 0; do { data = mmio_read_32(AGX_MPFE_HMC_ADP_DDRCALSTAT); if (AGX_MPFE_HMC_ADP_DDRCALSTAT_CAL(data) == 1) break; mdelay(1); } while (++timeout < TIMEOUT_EMIF_CALIBRATION); if (AGX_MPFE_HMC_ADP_DDRCALSTAT_CAL(data) == 0) { status = clear_emif(); if (status) ERROR("Failed to clear Emif\n"); } else { break; } } while (++retry < MAX_MEM_CAL_RETRY); if (AGX_MPFE_HMC_ADP_DDRCALSTAT_CAL(data) == 0) { ERROR("DDR: DRAM calibration failed.\n"); status = -EIO; } else { INFO("DDR: DRAM calibration success.\n"); status = 0; } udelay(POST_CALIBRATION_DELAY); return status; } int init_hard_memory_controller(void) { int status; status = check_hmc_clk(); if (status) { ERROR("DDR: Error, HMC clock not running\n"); return status; } status = mem_calibration(); if (status) { ERROR("DDR: Memory Calibration Failed\n"); return status; } configure_hmc_adaptor_regs(); return 0; } void configure_ddr_sched_ctrl_regs(void) { uint32_t data, dram_addr_order, ddr_conf, bank, row, col, rd_to_miss, wr_to_miss, burst_len, burst_len_ddr_clk, burst_len_sched_clk, act_to_act, rd_to_wr, wr_to_rd, bw_ratio, t_rtp, t_rp, t_rcd, rd_latency, tw_rin_clk_cycles, bw_ratio_extended, auto_precharge = 0, act_to_act_bank, faw, faw_bank, bus_rd_to_rd, bus_rd_to_wr, bus_wr_to_rd; INFO("Init HPS NOC's DDR Scheduler.\n"); data = mmio_read_32(AGX_MPFE_IOHMC_CTRLCFG1); dram_addr_order = AGX_MPFE_IOHMC_CTRLCFG1_CFG_ADDR_ORDER(data); data = mmio_read_32(AGX_MPFE_IOHMC_DRAMADDRW); col = IOHMC_DRAMADDRW_COL_ADDR_WIDTH(data); row = IOHMC_DRAMADDRW_ROW_ADDR_WIDTH(data); bank = IOHMC_DRAMADDRW_BANK_ADDR_WIDTH(data) + IOHMC_DRAMADDRW_BANK_GRP_ADDR_WIDTH(data); ddr_conf = match_ddr_conf(DDR_CONFIG(dram_addr_order, bank, col, row)); if (ddr_conf) { mmio_clrsetbits_32( AGX_MPFE_DDR_MAIN_SCHED_DDRCONF, AGX_MPFE_DDR_MAIN_SCHED_DDRCONF_SET_MSK, AGX_MPFE_DDR_MAIN_SCHED_DDRCONF_SET(ddr_conf)); } else { ERROR("DDR: Cannot find predefined ddrConf configuration.\n"); } mmio_write_32(AGX_MPFE_HMC_ADP(ADP_DRAMADDRWIDTH), data); data = mmio_read_32(AGX_MPFE_IOHMC_DRAMTIMING0); rd_latency = AGX_MPFE_IOHMC_REG_DRAMTIMING0_CFG_TCL(data); data = mmio_read_32(AGX_MPFE_IOHMC_CALTIMING0); act_to_act = ACT_TO_ACT(data); t_rcd = ACT_TO_RDWR(data); act_to_act_bank = ACT_TO_ACT_DIFF_BANK(data); data = mmio_read_32(AGX_MPFE_IOHMC_CALTIMING1); rd_to_wr = RD_TO_WR(data); bus_rd_to_rd = RD_TO_RD_DIFF_CHIP(data); bus_rd_to_wr = RD_TO_WR_DIFF_CHIP(data); data = mmio_read_32(AGX_MPFE_IOHMC_CALTIMING2); t_rtp = RD_TO_PCH(data); data = mmio_read_32(AGX_MPFE_IOHMC_CALTIMING3); wr_to_rd = CALTIMING3_WR_TO_RD(data); bus_wr_to_rd = CALTIMING3_WR_TO_RD_DIFF_CHIP(data); data = mmio_read_32(AGX_MPFE_IOHMC_CALTIMING4); t_rp = PCH_TO_VALID(data); data = mmio_read_32(AGX_MPFE_HMC_ADP(HMC_ADP_DDRIOCTRL)); bw_ratio = ((HMC_ADP_DDRIOCTRL_IO_SIZE(data) == 0) ? 0 : 1); data = mmio_read_32(AGX_MPFE_IOHMC_CTRLCFG0); burst_len = HMC_ADP_DDRIOCTRL_CTRL_BURST_LENGTH(data); burst_len_ddr_clk = burst_len / 2; burst_len_sched_clk = ((burst_len/2) / 2); data = mmio_read_32(AGX_MPFE_IOHMC_CTRLCFG0); switch (AGX_MPFE_IOHMC_REG_CTRLCFG0_CFG_MEM_TYPE(data)) { case 1: /* DDR4 - 1333MHz */ /* 20 (19.995) clock cycles = 15ns */ /* Calculate with rounding */ tw_rin_clk_cycles = (((tWR_IN_NS * 1333) % 1000) >= 500) ? ((tWR_IN_NS * 1333) / 1000) + 1 : ((tWR_IN_NS * 1333) / 1000); break; default: /* Others - 1066MHz or slower */ /* 16 (15.990) clock cycles = 15ns */ /* Calculate with rounding */ tw_rin_clk_cycles = (((tWR_IN_NS * 1066) % 1000) >= 500) ? ((tWR_IN_NS * 1066) / 1000) + 1 : ((tWR_IN_NS * 1066) / 1000); break; } rd_to_miss = t_rtp + t_rp + t_rcd - burst_len_sched_clk; wr_to_miss = ((rd_latency + burst_len_ddr_clk + 2 + tw_rin_clk_cycles) / 2) - rd_to_wr + t_rp + t_rcd; mmio_write_32(AGX_MPFE_DDR_MAIN_SCHED_DDRTIMING, bw_ratio << DDRTIMING_BWRATIO_OFST | wr_to_rd << DDRTIMING_WRTORD_OFST| rd_to_wr << DDRTIMING_RDTOWR_OFST | burst_len_sched_clk << DDRTIMING_BURSTLEN_OFST | wr_to_miss << DDRTIMING_WRTOMISS_OFST | rd_to_miss << DDRTIMING_RDTOMISS_OFST | act_to_act << DDRTIMING_ACTTOACT_OFST); data = mmio_read_32(AGX_MPFE_HMC_ADP(HMC_ADP_DDRIOCTRL)); bw_ratio_extended = ((ADP_DDRIOCTRL_IO_SIZE(data) == 0) ? 1 : 0); mmio_write_32(AGX_MPFE_DDR_MAIN_SCHED_DDRMODE, bw_ratio_extended << DDRMODE_BWRATIOEXTENDED_OFST | auto_precharge << DDRMODE_AUTOPRECHARGE_OFST); mmio_write_32(AGX_MPFE_DDR_MAIN_SCHED_READLATENCY, (rd_latency / 2) + DDR_READ_LATENCY_DELAY); data = mmio_read_32(AGX_MPFE_IOHMC_CALTIMING9); faw = AGX_MPFE_IOHMC_CALTIMING9_ACT_TO_ACT(data); faw_bank = 1; // always 1 because we always have 4 bank DDR. mmio_write_32(AGX_MPFE_DDR_MAIN_SCHED_ACTIVATE, faw_bank << AGX_MPFE_DDR_MAIN_SCHED_ACTIVATE_FAWBANK_OFST | faw << AGX_MPFE_DDR_MAIN_SCHED_ACTIVATE_FAW_OFST | act_to_act_bank << AGX_MPFE_DDR_MAIN_SCHED_ACTIVATE_RRD_OFST); mmio_write_32(AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV, ((bus_rd_to_rd << AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTORD_OFST) & AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTORD_MSK) | ((bus_rd_to_wr << AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTOWR_OFST) & AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTOWR_MSK) | ((bus_wr_to_rd << AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSWRTORD_OFST) & AGX_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSWRTORD_MSK)); } unsigned long get_physical_dram_size(void) { uint32_t data; unsigned long ram_addr_width, ram_ext_if_io_width; data = mmio_read_32(AGX_MPFE_HMC_ADP_DDRIOCTRL); switch (AGX_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE(data)) { case 0: ram_ext_if_io_width = 16; break; case 1: ram_ext_if_io_width = 32; break; case 2: ram_ext_if_io_width = 64; break; default: ram_ext_if_io_width = 0; break; } data = mmio_read_32(AGX_MPFE_IOHMC_REG_DRAMADDRW); ram_addr_width = IOHMC_DRAMADDRW_CFG_COL_ADDR_WIDTH(data) + IOHMC_DRAMADDRW_CFG_ROW_ADDR_WIDTH(data) + IOHMC_DRAMADDRW_CFG_BANK_ADDR_WIDTH(data) + IOHMC_DRAMADDRW_CFG_BANK_GROUP_ADDR_WIDTH(data) + IOHMC_DRAMADDRW_CFG_CS_ADDR_WIDTH(data); return (1 << ram_addr_width) * (ram_ext_if_io_width / 8); } void configure_hmc_adaptor_regs(void) { uint32_t data; uint32_t dram_io_width; /* Configure DDR data rate */ dram_io_width = AGX_MPFE_IOHMC_NIOSRESERVE0_NIOS_RESERVE0( mmio_read_32(AGX_MPFE_IOHMC_REG_NIOSRESERVE0_OFST)); dram_io_width = (dram_io_width & 0xFF) >> 5; data = mmio_read_32(AGX_MPFE_IOHMC_CTRLCFG3); dram_io_width |= (data & 0x4); mmio_write_32(AGX_MPFE_HMC_ADP_DDRIOCTRL, dram_io_width); /* Copy dram addr width from IOHMC to HMC ADP */ data = mmio_read_32(AGX_MPFE_IOHMC_DRAMADDRW); mmio_write_32(AGX_MPFE_HMC_ADP(ADP_DRAMADDRWIDTH), data); /* Enable nonsecure access to DDR */ data = get_physical_dram_size(); if (data < AGX_DDR_SIZE) data = AGX_DDR_SIZE; mmio_write_32(AGX_NOC_FW_DDR_SCR_MPUREGION0ADDR_LIMIT, data - 1); mmio_write_32(AGX_NOC_FW_DDR_SCR_MPUREGION0ADDR_LIMITEXT, 0x1f); mmio_write_32(AGX_NOC_FW_DDR_SCR_NONMPUREGION0ADDR_LIMIT, data - 1); mmio_write_32(AGX_SOC_NOC_FW_DDR_SCR_ENABLESET, BIT(0) | BIT(8)); /* ECC enablement */ data = mmio_read_32(AGX_MPFE_IOHMC_REG_CTRLCFG1); if (data & (1 << AGX_IOHMC_CTRLCFG1_ENABLE_ECC_OFST)) { mmio_clrsetbits_32(AGX_MPFE_HMC_ADP_ECCCTRL1, AGX_MPFE_HMC_ADP_ECCCTRL1_AUTOWB_CNT_RST_SET_MSK | AGX_MPFE_HMC_ADP_ECCCTRL1_CNT_RST_SET_MSK | AGX_MPFE_HMC_ADP_ECCCTRL1_ECC_EN_SET_MSK, AGX_MPFE_HMC_ADP_ECCCTRL1_AUTOWB_CNT_RST_SET_MSK | AGX_MPFE_HMC_ADP_ECCCTRL1_CNT_RST_SET_MSK); mmio_clrsetbits_32(AGX_MPFE_HMC_ADP_ECCCTRL2, AGX_MPFE_HMC_ADP_ECCCTRL2_OVRW_RB_ECC_EN_SET_MSK | AGX_MPFE_HMC_ADP_ECCCTRL2_RMW_EN_SET_MSK | AGX_MPFE_HMC_ADP_ECCCTRL2_AUTOWB_EN_SET_MSK, AGX_MPFE_HMC_ADP_ECCCTRL2_RMW_EN_SET_MSK | AGX_MPFE_HMC_ADP_ECCCTRL2_AUTOWB_EN_SET_MSK); mmio_clrsetbits_32(AGX_MPFE_HMC_ADP_ECCCTRL1, AGX_MPFE_HMC_ADP_ECCCTRL1_AUTOWB_CNT_RST_SET_MSK | AGX_MPFE_HMC_ADP_ECCCTRL1_CNT_RST_SET_MSK | AGX_MPFE_HMC_ADP_ECCCTRL1_ECC_EN_SET_MSK, AGX_MPFE_HMC_ADP_ECCCTRL1_ECC_EN_SET_MSK); INFO("Scrubbing ECC\n"); /* ECC Scrubbing */ zeromem(DRAM_BASE, DRAM_SIZE); } else { INFO("ECC is disabled.\n"); } } trusted-firmware-a-2.2/plat/intel/soc/agilex/soc/agilex_pinmux.c000066400000000000000000000124411355360272700250240ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "agilex_pinmux.h" const uint32_t sysmgr_pinmux_array_sel[] = { 0x00000000, 0x00000001, /* usb */ 0x00000004, 0x00000001, 0x00000008, 0x00000001, 0x0000000c, 0x00000001, 0x00000010, 0x00000001, 0x00000014, 0x00000001, 0x00000018, 0x00000001, 0x0000001c, 0x00000001, 0x00000020, 0x00000001, 0x00000024, 0x00000001, 0x00000028, 0x00000001, 0x0000002c, 0x00000001, 0x00000030, 0x00000000, /* emac0 */ 0x00000034, 0x00000000, 0x00000038, 0x00000000, 0x0000003c, 0x00000000, 0x00000040, 0x00000000, 0x00000044, 0x00000000, 0x00000048, 0x00000000, 0x0000004c, 0x00000000, 0x00000050, 0x00000000, 0x00000054, 0x00000000, 0x00000058, 0x00000000, 0x0000005c, 0x00000000, 0x00000060, 0x00000008, /* gpio1 */ 0x00000064, 0x00000008, 0x00000068, 0x00000005, /* uart0 tx */ 0x0000006c, 0x00000005, /* uart 0 rx */ 0x00000070, 0x00000008, /* gpio */ 0x00000074, 0x00000008, 0x00000078, 0x00000004, /* i2c1 */ 0x0000007c, 0x00000004, 0x00000080, 0x00000007, /* jtag */ 0x00000084, 0x00000007, 0x00000088, 0x00000007, 0x0000008c, 0x00000007, 0x00000090, 0x00000001, /* sdmmc data0 */ 0x00000094, 0x00000001, 0x00000098, 0x00000001, 0x0000009c, 0x00000001, 0x00000100, 0x00000001, 0x00000104, 0x00000001, /* sdmmc.data3 */ 0x00000108, 0x00000008, /* loan */ 0x0000010c, 0x00000008, /* gpio */ 0x00000110, 0x00000008, 0x00000114, 0x00000008, /* gpio1.io21 */ 0x00000118, 0x00000005, /* mdio0.mdio */ 0x0000011c, 0x00000005 /* mdio0.mdc */ }; const uint32_t sysmgr_pinmux_array_ctrl[] = { 0x00000000, 0x00502c38, /* Q1_1 */ 0x00000004, 0x00102c38, 0x00000008, 0x00502c38, 0x0000000c, 0x00502c38, 0x00000010, 0x00502c38, 0x00000014, 0x00502c38, 0x00000018, 0x00502c38, 0x0000001c, 0x00502c38, 0x00000020, 0x00502c38, 0x00000024, 0x00502c38, 0x00000028, 0x00502c38, 0x0000002c, 0x00502c38, 0x00000030, 0x00102c38, /* Q2_1 */ 0x00000034, 0x00102c38, 0x00000038, 0x00502c38, 0x0000003c, 0x00502c38, 0x00000040, 0x00102c38, 0x00000044, 0x00102c38, 0x00000048, 0x00502c38, 0x0000004c, 0x00502c38, 0x00000050, 0x00102c38, 0x00000054, 0x00102c38, 0x00000058, 0x00502c38, 0x0000005c, 0x00502c38, 0x00000060, 0x00502c38, /* Q3_1 */ 0x00000064, 0x00502c38, 0x00000068, 0x00102c38, 0x0000006c, 0x00502c38, 0x000000d0, 0x00502c38, 0x000000d4, 0x00502c38, 0x000000d8, 0x00542c38, 0x000000dc, 0x00542c38, 0x000000e0, 0x00502c38, 0x000000e4, 0x00502c38, 0x000000e8, 0x00102c38, 0x000000ec, 0x00502c38, 0x000000f0, 0x00502c38, /* Q4_1 */ 0x000000f4, 0x00502c38, 0x000000f8, 0x00102c38, 0x000000fc, 0x00502c38, 0x00000100, 0x00502c38, 0x00000104, 0x00502c38, 0x00000108, 0x00102c38, 0x0000010c, 0x00502c38, 0x00000110, 0x00502c38, 0x00000114, 0x00502c38, 0x00000118, 0x00542c38, 0x0000011c, 0x00102c38 }; const uint32_t sysmgr_pinmux_array_fpga[] = { 0x00000000, 0x00000000, 0x00000004, 0x00000000, 0x00000008, 0x00000000, 0x0000000c, 0x00000000, 0x00000010, 0x00000000, 0x00000014, 0x00000000, 0x00000018, 0x00000000, 0x0000001c, 0x00000000, 0x00000020, 0x00000000, 0x00000028, 0x00000000, 0x0000002c, 0x00000000, 0x00000030, 0x00000000, 0x00000034, 0x00000000, 0x00000038, 0x00000000, 0x0000003c, 0x00000000, 0x00000040, 0x00000000, 0x00000044, 0x00000000, 0x00000048, 0x00000000, 0x00000050, 0x00000000, 0x00000054, 0x00000000, 0x00000058, 0x0000002a }; const uint32_t sysmgr_pinmux_array_iodelay[] = { 0x00000000, 0x00000000, 0x00000004, 0x00000000, 0x00000008, 0x00000000, 0x0000000c, 0x00000000, 0x00000010, 0x00000000, 0x00000014, 0x00000000, 0x00000018, 0x00000000, 0x0000001c, 0x00000000, 0x00000020, 0x00000000, 0x00000024, 0x00000000, 0x00000028, 0x00000000, 0x0000002c, 0x00000000, 0x00000030, 0x00000000, 0x00000034, 0x00000000, 0x00000038, 0x00000000, 0x0000003c, 0x00000000, 0x00000040, 0x00000000, 0x00000044, 0x00000000, 0x00000048, 0x00000000, 0x0000004c, 0x00000000, 0x00000050, 0x00000000, 0x00000054, 0x00000000, 0x00000058, 0x00000000, 0x0000005c, 0x00000000, 0x00000060, 0x00000000, 0x00000064, 0x00000000, 0x00000068, 0x00000000, 0x0000006c, 0x00000000, 0x00000070, 0x00000000, 0x00000074, 0x00000000, 0x00000078, 0x00000000, 0x0000007c, 0x00000000, 0x00000080, 0x00000000, 0x00000084, 0x00000000, 0x00000088, 0x00000000, 0x0000008c, 0x00000000, 0x00000090, 0x00000000, 0x00000094, 0x00000000, 0x00000098, 0x00000000, 0x0000009c, 0x00000000, 0x00000100, 0x00000000, 0x00000104, 0x00000000, 0x00000108, 0x00000000, 0x0000010c, 0x00000000, 0x00000110, 0x00000000, 0x00000114, 0x00000000, 0x00000118, 0x00000000, 0x0000011c, 0x00000000 }; void config_pinmux(handoff *hoff_ptr) { unsigned int i; for (i = 0; i < 96; i += 2) { mmio_write_32(AGX_PINMUX_PIN0SEL + hoff_ptr->pinmux_sel_array[i], hoff_ptr->pinmux_sel_array[i+1]); } for (i = 0; i < 96; i += 2) { mmio_write_32(AGX_PINMUX_IO0CTRL + hoff_ptr->pinmux_io_array[i], hoff_ptr->pinmux_io_array[i+1]); } for (i = 0; i < 42; i += 2) { mmio_write_32(AGX_PINMUX_PINMUX_EMAC0_USEFPGA + hoff_ptr->pinmux_fpga_array[i], hoff_ptr->pinmux_fpga_array[i+1]); } for (i = 0; i < 96; i += 2) { mmio_write_32(AGX_PINMUX_IO0_DELAY + hoff_ptr->pinmux_iodelay_array[i], hoff_ptr->pinmux_iodelay_array[i+1]); } } trusted-firmware-a-2.2/plat/intel/soc/agilex/soc/agilex_reset_manager.c000066400000000000000000000044551355360272700263260ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "agilex_reset_manager.h" void deassert_peripheral_reset(void) { mmio_clrbits_32(AGX_RSTMGR_PER1MODRST, AGX_RSTMGR_PER1MODRST_WATCHDOG0 | AGX_RSTMGR_PER1MODRST_WATCHDOG1 | AGX_RSTMGR_PER1MODRST_WATCHDOG2 | AGX_RSTMGR_PER1MODRST_WATCHDOG3 | AGX_RSTMGR_PER1MODRST_L4SYSTIMER0 | AGX_RSTMGR_PER1MODRST_L4SYSTIMER1 | AGX_RSTMGR_PER1MODRST_SPTIMER0 | AGX_RSTMGR_PER1MODRST_SPTIMER1 | AGX_RSTMGR_PER1MODRST_I2C0 | AGX_RSTMGR_PER1MODRST_I2C1 | AGX_RSTMGR_PER1MODRST_I2C2 | AGX_RSTMGR_PER1MODRST_I2C3 | AGX_RSTMGR_PER1MODRST_I2C4 | AGX_RSTMGR_PER1MODRST_UART0 | AGX_RSTMGR_PER1MODRST_UART1 | AGX_RSTMGR_PER1MODRST_GPIO0 | AGX_RSTMGR_PER1MODRST_GPIO1); mmio_clrbits_32(AGX_RSTMGR_PER0MODRST, AGX_RSTMGR_PER0MODRST_EMAC0OCP | AGX_RSTMGR_PER0MODRST_EMAC1OCP | AGX_RSTMGR_PER0MODRST_EMAC2OCP | AGX_RSTMGR_PER0MODRST_USB0OCP | AGX_RSTMGR_PER0MODRST_USB1OCP | AGX_RSTMGR_PER0MODRST_NANDOCP | AGX_RSTMGR_PER0MODRST_SDMMCOCP | AGX_RSTMGR_PER0MODRST_DMAOCP); mmio_clrbits_32(AGX_RSTMGR_PER0MODRST, AGX_RSTMGR_PER0MODRST_EMAC0 | AGX_RSTMGR_PER0MODRST_EMAC1 | AGX_RSTMGR_PER0MODRST_EMAC2 | AGX_RSTMGR_PER0MODRST_USB0 | AGX_RSTMGR_PER0MODRST_USB1 | AGX_RSTMGR_PER0MODRST_NAND | AGX_RSTMGR_PER0MODRST_SDMMC | AGX_RSTMGR_PER0MODRST_DMA | AGX_RSTMGR_PER0MODRST_SPIM0 | AGX_RSTMGR_PER0MODRST_SPIM1 | AGX_RSTMGR_PER0MODRST_SPIS0 | AGX_RSTMGR_PER0MODRST_SPIS1 | AGX_RSTMGR_PER0MODRST_EMACPTP | AGX_RSTMGR_PER0MODRST_DMAIF0 | AGX_RSTMGR_PER0MODRST_DMAIF1 | AGX_RSTMGR_PER0MODRST_DMAIF2 | AGX_RSTMGR_PER0MODRST_DMAIF3 | AGX_RSTMGR_PER0MODRST_DMAIF4 | AGX_RSTMGR_PER0MODRST_DMAIF5 | AGX_RSTMGR_PER0MODRST_DMAIF6 | AGX_RSTMGR_PER0MODRST_DMAIF7); mmio_clrbits_32(AGX_RSTMGR_BRGMODRST, AGX_RSTMGR_BRGMODRST_MPFE); } void config_hps_hs_before_warm_reset(void) { uint32_t or_mask = 0; or_mask |= AGX_RSTMGR_HDSKEN_SDRSELFREFEN; or_mask |= AGX_RSTMGR_HDSKEN_FPGAHSEN; or_mask |= AGX_RSTMGR_HDSKEN_ETRSTALLEN; or_mask |= AGX_RSTMGR_HDSKEN_L2FLUSHEN; or_mask |= AGX_RSTMGR_HDSKEN_L3NOC_DBG; or_mask |= AGX_RSTMGR_HDSKEN_DEBUG_L3NOC; mmio_setbits_32(AGX_RSTMGR_HDSKEN, or_mask); } trusted-firmware-a-2.2/plat/intel/soc/agilex/soc/agilex_system_manager.c000066400000000000000000000073721355360272700265310ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "agilex_system_manager.h" void enable_nonsecure_access(void) { mmio_write_32(AGX_NOC_FW_L4_PER_SCR_NAND_REGISTER, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_NAND_DATA, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_NAND_ECC, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_NAND_READ_ECC, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_NAND_WRITE_ECC, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_USB0_REGISTER, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_USB1_REGISTER, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_USB0_ECC, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_USB1_ECC, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_SPI_MASTER0, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_SPI_MASTER1, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_SPI_SLAVE0, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_SPI_SLAVE1, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_EMAC0, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_EMAC1, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_EMAC2, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_EMAC0RX_ECC, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_EMAC0TX_ECC, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_EMAC1RX_ECC, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_EMAC1TX_ECC, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_EMAC2RX_ECC, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_EMAC2TX_ECC, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_SDMMC, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_SDMMC_ECC, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_GPIO0, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_GPIO1, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_I2C0, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_I2C1, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_I2C2, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_I2C3, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_I2C4, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_SP_TIMER1, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_UART0, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_PER_SCR_UART1, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_DMA_ECC, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_OCRAM_ECC, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_CLK_MGR, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_IO_MGR, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_RST_MGR, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_SYS_MGR, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_OSC0_TIMER, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_OSC1_TIMER, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_WATCHDOG0, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_WATCHDOG1, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_WATCHDOG2, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_WATCHDOG3, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_DAP, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_L4_NOC_PROBES, DISABLE_L4_FIREWALL); mmio_write_32(AGX_NOC_FW_L4_SYS_SCR_L4_NOC_QOS, DISABLE_L4_FIREWALL); } void enable_ns_bridge_access(void) { mmio_write_32(AGX_FIREWALL_SOC2FPGA, DISABLE_BRIDGE_FIREWALL); mmio_write_32(AGX_FIREWALL_LWSOC2FPGA, DISABLE_BRIDGE_FIREWALL); } trusted-firmware-a-2.2/plat/intel/soc/agilex/socfpga_psci.c000066400000000000000000000155421355360272700240340ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "agilex_reset_manager.h" #include "agilex_mailbox.h" #define AGX_RSTMGR_OFST 0xffd11000 #define AGX_RSTMGR_MPUMODRST_OFST 0x20 uintptr_t *agilex_sec_entry = (uintptr_t *) PLAT_SEC_ENTRY; uintptr_t *cpuid_release = (uintptr_t *) PLAT_CPUID_RELEASE; /******************************************************************************* * plat handler called when a CPU is about to enter standby. ******************************************************************************/ void socfpga_cpu_standby(plat_local_state_t cpu_state) { /* * Enter standby state * dsb is good practice before using wfi to enter low power states */ VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state); dsb(); wfi(); } /******************************************************************************* * plat handler called when a power domain is about to be turned on. The * mpidr determines the CPU to be turned on. ******************************************************************************/ int socfpga_pwr_domain_on(u_register_t mpidr) { unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); if (cpu_id == -1) return PSCI_E_INTERN_FAIL; *cpuid_release = cpu_id; /* release core reset */ mmio_setbits_32(AGX_RSTMGR_OFST + AGX_RSTMGR_MPUMODRST_OFST, 1 << cpu_id); return PSCI_E_SUCCESS; } /******************************************************************************* * plat handler called when a power domain is about to be turned off. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ void socfpga_pwr_domain_off(const psci_power_state_t *target_state) { for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); /* Prevent interrupts from spuriously waking up this cpu */ gicv2_cpuif_disable(); } /******************************************************************************* * plat handler called when a power domain is about to be suspended. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ void socfpga_pwr_domain_suspend(const psci_power_state_t *target_state) { unsigned int cpu_id = plat_my_core_pos(); for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); /* assert core reset */ mmio_setbits_32(AGX_RSTMGR_OFST + AGX_RSTMGR_MPUMODRST_OFST, 1 << cpu_id); } /******************************************************************************* * plat handler called when a power domain has just been powered on after * being turned off earlier. The target_state encodes the low power state that * each level has woken up from. ******************************************************************************/ void socfpga_pwr_domain_on_finish(const psci_power_state_t *target_state) { for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); /* Program the gic per-cpu distributor or re-distributor interface */ gicv2_pcpu_distif_init(); gicv2_set_pe_target_mask(plat_my_core_pos()); /* Enable the gic cpu interface */ gicv2_cpuif_enable(); } /******************************************************************************* * plat handler called when a power domain has just been powered on after * having been suspended earlier. The target_state encodes the low power state * that each level has woken up from. * TODO: At the moment we reuse the on finisher and reinitialize the secure * context. Need to implement a separate suspend finisher. ******************************************************************************/ void socfpga_pwr_domain_suspend_finish(const psci_power_state_t *target_state) { unsigned int cpu_id = plat_my_core_pos(); for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); /* release core reset */ mmio_clrbits_32(AGX_RSTMGR_OFST + AGX_RSTMGR_MPUMODRST_OFST, 1 << cpu_id); } /******************************************************************************* * plat handlers to shutdown/reboot the system ******************************************************************************/ static void __dead2 socfpga_system_off(void) { wfi(); ERROR("System Off: operation not handled.\n"); panic(); } static void __dead2 socfpga_system_reset(void) { INFO("assert Peripheral from Reset\r\n"); deassert_peripheral_reset(); mailbox_reset_cold(); while (1) wfi(); } int socfpga_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); return PSCI_E_SUCCESS; } int socfpga_validate_ns_entrypoint(unsigned long ns_entrypoint) { VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint); return PSCI_E_SUCCESS; } void socfpga_get_sys_suspend_power_state(psci_power_state_t *req_state) { req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE; req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE; } /******************************************************************************* * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard * platform layer will take care of registering the handlers with PSCI. ******************************************************************************/ const plat_psci_ops_t socfpga_psci_pm_ops = { .cpu_standby = socfpga_cpu_standby, .pwr_domain_on = socfpga_pwr_domain_on, .pwr_domain_off = socfpga_pwr_domain_off, .pwr_domain_suspend = socfpga_pwr_domain_suspend, .pwr_domain_on_finish = socfpga_pwr_domain_on_finish, .pwr_domain_suspend_finish = socfpga_pwr_domain_suspend_finish, .system_off = socfpga_system_off, .system_reset = socfpga_system_reset, .validate_power_state = socfpga_validate_power_state, .validate_ns_entrypoint = socfpga_validate_ns_entrypoint, .get_sys_suspend_power_state = socfpga_get_sys_suspend_power_state }; /******************************************************************************* * Export the platform specific power ops. ******************************************************************************/ int plat_setup_psci_ops(uintptr_t sec_entrypoint, const struct plat_psci_ops **psci_ops) { /* Save warm boot entrypoint.*/ *agilex_sec_entry = sec_entrypoint; *psci_ops = &socfpga_psci_pm_ops; return 0; } trusted-firmware-a-2.2/plat/intel/soc/agilex/socfpga_sip_svc.c000066400000000000000000000207721355360272700245450ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "agilex_mailbox.h" /* Number of SiP Calls implemented */ #define SIP_NUM_CALLS 0x3 /* Total buffer the driver can hold */ #define FPGA_CONFIG_BUFFER_SIZE 4 int current_block; int current_buffer; int current_id = 1; int max_blocks; uint32_t bytes_per_block; uint32_t blocks_submitted; uint32_t blocks_completed; struct fpga_config_info { uint32_t addr; int size; int size_written; uint32_t write_requested; int subblocks_sent; int block_number; }; /* SiP Service UUID */ DEFINE_SVC_UUID2(intl_svc_uid, 0xa85273b0, 0xe85a, 0x4862, 0xa6, 0x2a, 0xfa, 0x88, 0x88, 0x17, 0x68, 0x81); uint64_t socfpga_sip_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, void *cookie, void *handle, uint64_t flags) { ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); SMC_RET1(handle, SMC_UNK); } struct fpga_config_info fpga_config_buffers[FPGA_CONFIG_BUFFER_SIZE]; static void intel_fpga_sdm_write_buffer(struct fpga_config_info *buffer) { uint32_t args[3]; while (max_blocks > 0 && buffer->size > buffer->size_written) { if (buffer->size - buffer->size_written <= bytes_per_block) { args[0] = (1<<8); args[1] = buffer->addr + buffer->size_written; args[2] = buffer->size - buffer->size_written; buffer->size_written += buffer->size - buffer->size_written; buffer->subblocks_sent++; mailbox_send_cmd_async(0x4, MBOX_RECONFIG_DATA, args, 3, 0); current_buffer++; current_buffer %= FPGA_CONFIG_BUFFER_SIZE; } else { args[0] = (1<<8); args[1] = buffer->addr + buffer->size_written; args[2] = bytes_per_block; buffer->size_written += bytes_per_block; mailbox_send_cmd_async(0x4, MBOX_RECONFIG_DATA, args, 3, 0); buffer->subblocks_sent++; } max_blocks--; } } static int intel_fpga_sdm_write_all(void) { int i; for (i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) intel_fpga_sdm_write_buffer( &fpga_config_buffers[current_buffer]); return 0; } uint32_t intel_mailbox_fpga_config_isdone(void) { uint32_t args[2]; uint32_t response[6]; int status; status = mailbox_send_cmd(1, MBOX_RECONFIG_STATUS, args, 0, 0, response); if (status < 0) return INTEL_SIP_SMC_STATUS_ERROR; if (response[RECONFIG_STATUS_STATE] && response[RECONFIG_STATUS_STATE] != MBOX_CFGSTAT_STATE_CONFIG) return INTEL_SIP_SMC_STATUS_ERROR; if (!(response[RECONFIG_STATUS_PIN_STATUS] & PIN_STATUS_NSTATUS)) return INTEL_SIP_SMC_STATUS_ERROR; if (response[RECONFIG_STATUS_SOFTFUNC_STATUS] & SOFTFUNC_STATUS_SEU_ERROR) return INTEL_SIP_SMC_STATUS_ERROR; if ((response[RECONFIG_STATUS_SOFTFUNC_STATUS] & SOFTFUNC_STATUS_CONF_DONE) && (response[RECONFIG_STATUS_SOFTFUNC_STATUS] & SOFTFUNC_STATUS_INIT_DONE)) return INTEL_SIP_SMC_STATUS_OK; return INTEL_SIP_SMC_STATUS_ERROR; } static int mark_last_buffer_xfer_completed(uint32_t *buffer_addr_completed) { int i; for (i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) { if (fpga_config_buffers[i].block_number == current_block) { fpga_config_buffers[i].subblocks_sent--; if (fpga_config_buffers[i].subblocks_sent == 0 && fpga_config_buffers[i].size <= fpga_config_buffers[i].size_written) { fpga_config_buffers[i].write_requested = 0; current_block++; *buffer_addr_completed = fpga_config_buffers[i].addr; return 0; } } } return -1; } unsigned int address_in_ddr(uint32_t *addr) { if (((unsigned long long)addr > DRAM_BASE) && ((unsigned long long)addr < DRAM_BASE + DRAM_SIZE)) return 0; return -1; } int intel_fpga_config_completed_write(uint32_t *completed_addr, uint32_t *count) { uint32_t status = INTEL_SIP_SMC_STATUS_OK; *count = 0; int resp_len = 0; uint32_t resp[5]; int all_completed = 1; int count_check = 0; if (address_in_ddr(completed_addr) != 0 || address_in_ddr(count) != 0) return INTEL_SIP_SMC_STATUS_ERROR; for (count_check = 0; count_check < 3; count_check++) if (address_in_ddr(&completed_addr[*count + count_check]) != 0) return INTEL_SIP_SMC_STATUS_ERROR; resp_len = mailbox_read_response(0x4, resp); while (resp_len >= 0 && *count < 3) { max_blocks++; if (mark_last_buffer_xfer_completed( &completed_addr[*count]) == 0) *count = *count + 1; else break; resp_len = mailbox_read_response(0x4, resp); } if (*count <= 0) { if (resp_len != MBOX_NO_RESPONSE && resp_len != MBOX_TIMEOUT && resp_len != 0) { return INTEL_SIP_SMC_STATUS_ERROR; } *count = 0; } intel_fpga_sdm_write_all(); if (*count > 0) status = INTEL_SIP_SMC_STATUS_OK; else if (*count == 0) status = INTEL_SIP_SMC_STATUS_BUSY; for (int i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) { if (fpga_config_buffers[i].write_requested != 0) { all_completed = 0; break; } } if (all_completed == 1) return INTEL_SIP_SMC_STATUS_OK; return status; } int intel_fpga_config_start(uint32_t config_type) { uint32_t response[3]; int status = 0; status = mailbox_send_cmd(2, MBOX_RECONFIG, 0, 0, 0, response); if (status < 0) return status; max_blocks = response[0]; bytes_per_block = response[1]; for (int i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) { fpga_config_buffers[i].size = 0; fpga_config_buffers[i].size_written = 0; fpga_config_buffers[i].addr = 0; fpga_config_buffers[i].write_requested = 0; fpga_config_buffers[i].block_number = 0; fpga_config_buffers[i].subblocks_sent = 0; } blocks_submitted = 0; current_block = 0; current_buffer = 0; return 0; } uint32_t intel_fpga_config_write(uint64_t mem, uint64_t size) { int i = 0; uint32_t status = INTEL_SIP_SMC_STATUS_OK; if (mem < DRAM_BASE || mem > DRAM_BASE + DRAM_SIZE) status = INTEL_SIP_SMC_STATUS_REJECTED; if (mem + size > DRAM_BASE + DRAM_SIZE) status = INTEL_SIP_SMC_STATUS_REJECTED; for (i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) { if (!fpga_config_buffers[i].write_requested) { fpga_config_buffers[i].addr = mem; fpga_config_buffers[i].size = size; fpga_config_buffers[i].size_written = 0; fpga_config_buffers[i].write_requested = 1; fpga_config_buffers[i].block_number = blocks_submitted++; fpga_config_buffers[i].subblocks_sent = 0; break; } } if (i == FPGA_CONFIG_BUFFER_SIZE) { status = INTEL_SIP_SMC_STATUS_REJECTED; return status; } else if (i == FPGA_CONFIG_BUFFER_SIZE - 1) { status = INTEL_SIP_SMC_STATUS_BUSY; } intel_fpga_sdm_write_all(); return status; } /* * This function is responsible for handling all SiP calls from the NS world */ uintptr_t sip_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 status = INTEL_SIP_SMC_STATUS_OK; uint32_t completed_addr[3]; uint32_t count = 0; switch (smc_fid) { case SIP_SVC_UID: /* Return UID to the caller */ SMC_UUID_RET(handle, intl_svc_uid); break; case INTEL_SIP_SMC_FPGA_CONFIG_ISDONE: status = intel_mailbox_fpga_config_isdone(); SMC_RET4(handle, status, 0, 0, 0); break; case INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM: SMC_RET3(handle, INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_FPGA_CONFIG_ADDR, INTEL_SIP_SMC_FPGA_CONFIG_SIZE - INTEL_SIP_SMC_FPGA_CONFIG_ADDR); break; case INTEL_SIP_SMC_FPGA_CONFIG_START: status = intel_fpga_config_start(x1); SMC_RET4(handle, status, 0, 0, 0); break; case INTEL_SIP_SMC_FPGA_CONFIG_WRITE: status = intel_fpga_config_write(x1, x2); SMC_RET4(handle, status, 0, 0, 0); break; case INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE: status = intel_fpga_config_completed_write(completed_addr, &count); switch (count) { case 1: SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK, completed_addr[0], 0, 0); break; case 2: SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK, completed_addr[0], completed_addr[1], 0); break; case 3: SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK, completed_addr[0], completed_addr[1], completed_addr[2]); break; case 0: SMC_RET4(handle, status, 0, 0, 0); break; default: SMC_RET1(handle, INTEL_SIP_SMC_STATUS_ERROR); } break; default: return socfpga_sip_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); } } DECLARE_RT_SVC( agilex_sip_svc, OEN_SIP_START, OEN_SIP_END, SMC_TYPE_FAST, NULL, sip_smc_handler ); DECLARE_RT_SVC( agilex_sip_svc_std, OEN_SIP_START, OEN_SIP_END, SMC_TYPE_YIELD, NULL, sip_smc_handler ); trusted-firmware-a-2.2/plat/intel/soc/agilex/socfpga_storage.c000066400000000000000000000105051355360272700245340ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "agilex_private.h" #define PLAT_FIP_BASE (0) #define PLAT_FIP_MAX_SIZE (0x1000000) #define PLAT_MMC_DATA_BASE (0xffe3c000) #define PLAT_MMC_DATA_SIZE (0x2000) #define PLAT_QSPI_DATA_BASE (0x3C00000) #define PLAT_QSPI_DATA_SIZE (0x1000000) static const io_dev_connector_t *fip_dev_con; static const io_dev_connector_t *boot_dev_con; static uintptr_t fip_dev_handle; static uintptr_t boot_dev_handle; static const io_uuid_spec_t bl2_uuid_spec = { .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2, }; static const io_uuid_spec_t bl31_uuid_spec = { .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31, }; static const io_uuid_spec_t bl33_uuid_spec = { .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33, }; uintptr_t a2_lba_offset; const char a2[] = {0xa2, 0x0}; static const io_block_spec_t gpt_block_spec = { .offset = 0, .length = MMC_BLOCK_SIZE }; static int check_fip(const uintptr_t spec); static int check_dev(const uintptr_t spec); static io_block_dev_spec_t boot_dev_spec; static int (*register_io_dev)(const io_dev_connector_t **); static io_block_spec_t fip_spec = { .offset = PLAT_FIP_BASE, .length = PLAT_FIP_MAX_SIZE, }; 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[] = { [FIP_IMAGE_ID] = { &boot_dev_handle, (uintptr_t)&fip_spec, check_dev }, [BL2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl2_uuid_spec, check_fip }, [BL31_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl31_uuid_spec, check_fip }, [BL33_IMAGE_ID] = { &fip_dev_handle, (uintptr_t) &bl33_uuid_spec, check_fip }, [GPT_IMAGE_ID] = { &boot_dev_handle, (uintptr_t) &gpt_block_spec, check_dev }, }; static int check_dev(const uintptr_t spec) { int result; uintptr_t local_handle; result = io_dev_init(boot_dev_handle, (uintptr_t)NULL); if (result == 0) { result = io_open(boot_dev_handle, spec, &local_handle); if (result == 0) io_close(local_handle); } return result; } static int check_fip(const uintptr_t spec) { int result; uintptr_t local_image_handle; result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); if (result == 0) { result = io_open(fip_dev_handle, spec, &local_image_handle); if (result == 0) io_close(local_image_handle); } return result; } void socfpga_io_setup(int boot_source) { int result; switch (boot_source) { case BOOT_SOURCE_SDMMC: register_io_dev = ®ister_io_dev_block; boot_dev_spec.buffer.offset = PLAT_MMC_DATA_BASE; boot_dev_spec.buffer.length = MMC_BLOCK_SIZE; boot_dev_spec.ops.read = mmc_read_blocks; boot_dev_spec.ops.write = mmc_write_blocks; boot_dev_spec.block_size = MMC_BLOCK_SIZE; break; case BOOT_SOURCE_QSPI: register_io_dev = ®ister_io_dev_memmap; fip_spec.offset = fip_spec.offset + PLAT_QSPI_DATA_BASE; break; default: ERROR("Unsupported boot source\n"); panic(); break; } result = (*register_io_dev)(&boot_dev_con); assert(result == 0); result = register_io_dev_fip(&fip_dev_con); assert(result == 0); result = io_dev_open(boot_dev_con, (uintptr_t)&boot_dev_spec, &boot_dev_handle); assert(result == 0); result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle); assert(result == 0); if (boot_source == BOOT_SOURCE_SDMMC) { partition_init(GPT_IMAGE_ID); fip_spec.offset = get_partition_entry(a2)->start; } (void)result; } int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, uintptr_t *image_spec) { int result; const struct plat_io_policy *policy; assert(image_id < ARRAY_SIZE(policies)); policy = &policies[image_id]; result = policy->check(policy->image_spec); assert(result == 0); *image_spec = policy->image_spec; *dev_handle = *(policy->dev_handle); return result; } trusted-firmware-a-2.2/plat/intel/soc/common/000077500000000000000000000000001355360272700212405ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/intel/soc/common/aarch64/000077500000000000000000000000001355360272700224705ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/intel/soc/common/aarch64/plat_helpers.S000066400000000000000000000056721355360272700253100ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl plat_secondary_cold_boot_setup .globl platform_is_primary_cpu .globl plat_is_my_cpu_primary .globl plat_my_core_pos .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush .globl platform_mem_init .globl plat_get_my_entrypoint /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions * needed for a secondary cpu after a cold reset e.g * mark the cpu's presence, mechanism to place it in a * holding pen etc. * ----------------------------------------------------- */ func plat_secondary_cold_boot_setup /* Wait until the it gets reset signal from rstmgr gets populated */ poll_mailbox: wfi mov_imm x0, PLAT_SEC_ENTRY ldr x1, [x0] mov_imm x2, PLAT_CPUID_RELEASE ldr x3, [x2] mrs x4, mpidr_el1 and x4, x4, #0xff cmp x3, x4 b.ne poll_mailbox br x1 endfunc plat_secondary_cold_boot_setup func platform_is_primary_cpu and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) cmp x0, #PLAT_PRIMARY_CPU cset x0, eq ret endfunc platform_is_primary_cpu func plat_is_my_cpu_primary mrs x0, mpidr_el1 b platform_is_primary_cpu endfunc plat_is_my_cpu_primary func plat_my_core_pos mrs x0, mpidr_el1 and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 ret endfunc plat_my_core_pos func plat_get_my_entrypoint mov_imm x1, PLAT_SEC_ENTRY ldr x0, [x1] ret endfunc plat_get_my_entrypoint /* --------------------------------------------- * int plat_crash_console_init(void) * Function to initialize the crash console * without a C Runtime to print crash report. * Clobber list : x0, x1, x2 * --------------------------------------------- */ func plat_crash_console_init mov_imm x0, PLAT_UART0_BASE mov_imm x1, PLAT_UART_CLOCK mov_imm x2, PLAT_BAUDRATE b console_16550_core_init endfunc plat_crash_console_init /* --------------------------------------------- * int plat_crash_console_putc(void) * Function to print a character on the crash * console without a C Runtime. * Clobber list : x1, x2 * --------------------------------------------- */ func plat_crash_console_putc mov_imm x1, PLAT_UART0_BASE b console_16550_core_putc endfunc plat_crash_console_putc func plat_crash_console_flush mov_imm x0, CRASH_CONSOLE_BASE b console_16550_core_flush endfunc plat_crash_console_flush /* -------------------------------------------------------- * void platform_mem_init (void); * * Any memory init, relocation to be done before the * platform boots. Called very early in the boot process. * -------------------------------------------------------- */ func platform_mem_init mov x0, #0 ret endfunc platform_mem_init trusted-firmware-a-2.2/plat/intel/soc/common/aarch64/platform_common.c000066400000000000000000000027741355360272700260420ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include unsigned int plat_get_syscnt_freq2(void) { return PLAT_SYS_COUNTER_FREQ_IN_TICKS; } unsigned long socfpga_get_ns_image_entrypoint(void) { return PLAT_NS_IMAGE_OFFSET; } /****************************************************************************** * Gets SPSR for BL32 entry *****************************************************************************/ uint32_t socfpga_get_spsr_for_bl32_entry(void) { /* * The Secure Payload Dispatcher service is responsible for * setting the SPSR prior to entry into the BL32 image. */ return 0; } /****************************************************************************** * Gets SPSR for BL33 entry *****************************************************************************/ uint32_t socfpga_get_spsr_for_bl33_entry(void) { unsigned long el_status; unsigned int mode; uint32_t spsr; /* Figure out what mode we enter the non-secure world in */ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; el_status &= ID_AA64PFR0_ELX_MASK; mode = (el_status) ? MODE_EL2 : MODE_EL1; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; } trusted-firmware-a-2.2/plat/intel/soc/common/bl2_plat_mem_params_desc.c000066400000000000000000000057201355360272700263060ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /******************************************************************************* * Following descriptor provides BL image/ep information that gets used * by BL2 to load the images and also subset of this information is * passed to next BL image. The image loading sequence is managed by * populating the images in required loading order. The image execution * sequence is managed by populating the `next_handoff_image_id` with * the next executable image id. ******************************************************************************/ static bl_mem_params_node_t bl2_mem_params_descs[] = { #ifdef SCP_BL2_BASE /* Fill SCP_BL2 related information if it exists */ { .image_id = SCP_BL2_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE), SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, VERSION_2, image_info_t, 0), .image_info.image_base = SCP_BL2_BASE, .image_info.image_max_size = SCP_BL2_SIZE, .next_handoff_image_id = INVALID_IMAGE_ID, }, #endif /* SCP_BL2_BASE */ #ifdef EL3_PAYLOAD_BASE /* Fill EL3 payload related information (BL31 is EL3 payload)*/ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = EL3_PAYLOAD_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING), .next_handoff_image_id = INVALID_IMAGE_ID, }, #else /* EL3_PAYLOAD_BASE */ /* Fill BL31 related information */ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = BL31_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP), .image_info.image_base = BL31_BASE, .image_info.image_max_size = BL31_LIMIT - BL31_BASE, .next_handoff_image_id = BL33_IMAGE_ID, }, #endif /* EL3_PAYLOAD_BASE */ { .image_id = BL33_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), .ep_info.pc = PLAT_NS_IMAGE_OFFSET, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = PLAT_NS_IMAGE_OFFSET, .image_info.image_max_size = 0x0 + 0x40000000 - PLAT_NS_IMAGE_OFFSET, .next_handoff_image_id = INVALID_IMAGE_ID, }, }; REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) trusted-firmware-a-2.2/plat/intel/soc/common/drivers/000077500000000000000000000000001355360272700227165ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/intel/soc/common/drivers/ccu/000077500000000000000000000000001355360272700234705ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/intel/soc/common/drivers/ccu/ncore_ccu.c000066400000000000000000000055751355360272700256100ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "ncore_ccu.h" #include uint32_t poll_active_bit(uint32_t dir); static coh_ss_id_t subsystem_id; void get_subsystem_id(void) { uint32_t snoop_filter, directory, coh_agent; snoop_filter = CSIDR_NUM_SF(mmio_read_32(NCORE_CCU_CSR(NCORE_CSIDR))); directory = CSUIDR_NUM_DIR(mmio_read_32(NCORE_CCU_CSR(NCORE_CSUIDR))); coh_agent = CSUIDR_NUM_CAI(mmio_read_32(NCORE_CCU_CSR(NCORE_CSUIDR))); subsystem_id.num_snoop_filter = snoop_filter + 1; subsystem_id.num_directory = directory; subsystem_id.num_coh_agent = coh_agent; } uint32_t directory_init(void) { uint32_t dir_sf_mtn, dir_sf_en; uint32_t dir, sf, ret; for (dir = 0; dir < subsystem_id.num_directory; dir++) { dir_sf_mtn = DIRECTORY_UNIT(dir, NCORE_DIRUSFMCR); dir_sf_en = DIRECTORY_UNIT(dir, NCORE_DIRUSFER); for (sf = 0; sf < subsystem_id.num_snoop_filter; sf++) { /* Initialize All Entries */ mmio_write_32(dir_sf_mtn, SNOOP_FILTER_ID(sf)); /* Poll Active Bit */ ret = poll_active_bit(dir); if (ret != 0) { ERROR("Timeout during active bit polling"); return -ETIMEDOUT; } /* Snoope Filter Enable */ mmio_write_32(dir_sf_en, BIT(sf)); } } return 0; } uint32_t coherent_agent_intfc_init(void) { uint32_t dir, ca, ca_id, ca_type, ca_snoop_en; for (dir = 0; dir < subsystem_id.num_directory; dir++) { ca_snoop_en = DIRECTORY_UNIT(dir, NCORE_DIRUCASER0); for (ca = 0; ca < subsystem_id.num_coh_agent; ca++) { ca_id = mmio_read_32(COH_AGENT_UNIT(ca, NCORE_CAIUIDR)); /* Coh Agent Snoop Enable */ if (CACHING_AGENT_BIT(ca_id)) mmio_write_32(ca_snoop_en, BIT(ca)); /* Coh Agent Snoop DVM Enable */ ca_type = CACHING_AGENT_TYPE(ca_id); if (ca_type == ACE_W_DVM || ca_type == ACE_L_W_DVM) mmio_write_32(NCORE_CCU_CSR(NCORE_CSADSER0), BIT(ca)); } } return 0; } uint32_t poll_active_bit(uint32_t dir) { uint32_t timeout = 80000; uint32_t poll_dir = DIRECTORY_UNIT(dir, NCORE_DIRUSFMAR); while (timeout > 0) { if (mmio_read_32(poll_dir) == 0) return 0; timeout--; } return -1; } void bypass_ocram_firewall(void) { mmio_clrbits_32(COH_CPU0_BYPASS_REG(NCORE_FW_OCRAM_BLK_CGF1), OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK); mmio_clrbits_32(COH_CPU0_BYPASS_REG(NCORE_FW_OCRAM_BLK_CGF2), OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK); mmio_clrbits_32(COH_CPU0_BYPASS_REG(NCORE_FW_OCRAM_BLK_CGF3), OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK); mmio_clrbits_32(COH_CPU0_BYPASS_REG(NCORE_FW_OCRAM_BLK_CGF4), OCRAM_PRIVILEGED_MASK | OCRAM_SECURE_MASK); } uint32_t init_ncore_ccu(void) { uint32_t status; get_subsystem_id(); status = directory_init(); status = coherent_agent_intfc_init(); bypass_ocram_firewall(); return status; } trusted-firmware-a-2.2/plat/intel/soc/common/drivers/ccu/ncore_ccu.h000066400000000000000000000053701355360272700256060ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef NCORE_CCU_H #define NCORE_CCU_H #define NCORE_CCU_OFFSET 0xf7000000 /* Coherent Sub-System Address Map */ #define NCORE_CAIU_OFFSET 0x00000 #define NCORE_CAIU_SIZE 0x01000 #define NCORE_NCBU_OFFSET 0x60000 #define NCORE_NCBU_SIZE 0x01000 #define NCORE_DIRU_OFFSET 0x80000 #define NCORE_DIRU_SIZE 0x01000 #define NCORE_CMIU_OFFSET 0xc0000 #define NCORE_CMIU_SIZE 0x01000 #define NCORE_CSR_OFFSET 0xff000 #define NCORE_CSADSERO 0x00040 #define NCORE_CSUIDR 0x00ff8 #define NCORE_CSIDR 0x00ffc /* Directory Unit Register Map */ #define NCORE_DIRUSFER 0x00010 #define NCORE_DIRUMRHER 0x00070 #define NCORE_DIRUSFMCR 0x00080 #define NCORE_DIRUSFMAR 0x00084 /* Coherent Agent Interface Unit Register Map */ #define NCORE_CAIUIDR 0x00ffc /* Snoop Enable Register */ #define NCORE_DIRUCASER0 0x00040 #define NCORE_DIRUCASER1 0x00044 #define NCORE_DIRUCASER2 0x00048 #define NCORE_DIRUCASER3 0x0004c #define NCORE_CSADSER0 0x00040 #define NCORE_CSADSER1 0x00044 #define NCORE_CSADSER2 0x00048 #define NCORE_CSADSER3 0x0004c /* Protocols Definition */ #define ACE_W_DVM 0 #define ACE_L_W_DVM 1 #define ACE_WO_DVM 2 #define ACE_L_WO_DVM 3 /* Bypass OC Ram Firewall */ #define NCORE_FW_OCRAM_BLK_BASE 0x100200 #define NCORE_FW_OCRAM_BLK_CGF1 0x04 #define NCORE_FW_OCRAM_BLK_CGF2 0x08 #define NCORE_FW_OCRAM_BLK_CGF3 0x0c #define NCORE_FW_OCRAM_BLK_CGF4 0x10 #define OCRAM_PRIVILEGED_MASK BIT(29) #define OCRAM_SECURE_MASK BIT(30) /* Macros */ #define NCORE_CCU_REG(base) (NCORE_CCU_OFFSET + (base)) #define NCORE_CCU_CSR(reg) (NCORE_CCU_REG(NCORE_CSR_OFFSET)\ + (reg)) #define NCORE_CCU_DIR(reg) (NCORE_CCU_REG(NCORE_DIRU_OFFSET)\ + (reg)) #define NCORE_CCU_CAI(reg) (NCORE_CCU_REG(NCORE_CAIU_OFFSET)\ + (reg)) #define DIRECTORY_UNIT(x, reg) (NCORE_CCU_DIR(reg)\ + NCORE_DIRU_SIZE * (x)) #define COH_AGENT_UNIT(x, reg) (NCORE_CCU_CAI(reg)\ + NCORE_CAIU_SIZE * (x)) #define COH_CPU0_BYPASS_REG(reg) (NCORE_CCU_REG(NCORE_FW_OCRAM_BLK_BASE)\ + (reg)) #define CSUIDR_NUM_CMI(x) (((x) & 0x3f000000) >> 24) #define CSUIDR_NUM_DIR(x) (((x) & 0x003f0000) >> 16) #define CSUIDR_NUM_NCB(x) (((x) & 0x00003f00) >> 8) #define CSUIDR_NUM_CAI(x) (((x) & 0x0000007f) >> 0) #define CSIDR_NUM_SF(x) (((x) & 0x007c0000) >> 18) #define SNOOP_FILTER_ID(x) (((x) << 16)) #define CACHING_AGENT_BIT(x) (((x) & 0x08000) >> 15) #define CACHING_AGENT_TYPE(x) (((x) & 0xf0000) >> 16) typedef struct coh_ss_id { uint8_t num_coh_mem; uint8_t num_directory; uint8_t num_non_coh_bridge; uint8_t num_coh_agent; uint8_t num_snoop_filter; } coh_ss_id_t; uint32_t init_ncore_ccu(void); #endif trusted-firmware-a-2.2/plat/intel/soc/common/drivers/qspi/000077500000000000000000000000001355360272700236725ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/intel/soc/common/drivers/qspi/cadence_qspi.c000066400000000000000000000470621355360272700264650ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "cadence_qspi.h" #include #define LESS(a, b) (((a) < (b)) ? (a) : (b)) #define MORE(a, b) (((a) > (b)) ? (a) : (b)) uint32_t qspi_device_size; int cad_qspi_cs; int cad_qspi_idle(void) { return (mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG) & CAD_QSPI_CFG_IDLE) >> 31; } int cad_qspi_set_baudrate_div(uint32_t div) { if (div > 0xf) return CAD_INVALID; mmio_clrsetbits_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG, ~CAD_QSPI_CFG_BAUDDIV_MSK, CAD_QSPI_CFG_BAUDDIV(div)); return 0; } int cad_qspi_configure_dev_size(uint32_t addr_bytes, uint32_t bytes_per_dev, uint32_t bytes_per_block) { mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DEVSZ, CAD_QSPI_DEVSZ_ADDR_BYTES(addr_bytes) | CAD_QSPI_DEVSZ_BYTES_PER_PAGE(bytes_per_dev) | CAD_QSPI_DEVSZ_BYTES_PER_BLOCK(bytes_per_block)); return 0; } int cad_qspi_set_read_config(uint32_t opcode, uint32_t instr_type, uint32_t addr_type, uint32_t data_type, uint32_t mode_bit, uint32_t dummy_clk_cycle) { mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DEVRD, CAD_QSPI_DEV_OPCODE(opcode) | CAD_QSPI_DEV_INST_TYPE(instr_type) | CAD_QSPI_DEV_ADDR_TYPE(addr_type) | CAD_QSPI_DEV_DATA_TYPE(data_type) | CAD_QSPI_DEV_MODE_BIT(mode_bit) | CAD_QSPI_DEV_DUMMY_CLK_CYCLE(dummy_clk_cycle)); return 0; } int cad_qspi_set_write_config(uint32_t opcode, uint32_t addr_type, uint32_t data_type, uint32_t dummy_clk_cycle) { mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DEVWR, CAD_QSPI_DEV_OPCODE(opcode) | CAD_QSPI_DEV_ADDR_TYPE(addr_type) | CAD_QSPI_DEV_DATA_TYPE(data_type) | CAD_QSPI_DEV_DUMMY_CLK_CYCLE(dummy_clk_cycle)); return 0; } int cad_qspi_timing_config(uint32_t clkphase, uint32_t clkpol, uint32_t csda, uint32_t csdads, uint32_t cseot, uint32_t cssot, uint32_t rddatacap) { uint32_t cfg = mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG); cfg &= CAD_QSPI_CFG_SELCLKPHASE_CLR_MSK & CAD_QSPI_CFG_SELCLKPOL_CLR_MSK; cfg |= CAD_QSPI_SELCLKPHASE(clkphase) | CAD_QSPI_SELCLKPOL(clkpol); mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG, cfg); mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_DELAY, CAD_QSPI_DELAY_CSSOT(cssot) | CAD_QSPI_DELAY_CSEOT(cseot) | CAD_QSPI_DELAY_CSDADS(csdads) | CAD_QSPI_DELAY_CSDA(csda)); return 0; } int cad_qspi_stig_cmd_helper(int cs, uint32_t cmd) { uint32_t count = 0; /* chip select */ mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG, (mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG) & CAD_QSPI_CFG_CS_MSK) | CAD_QSPI_CFG_CS(cs)); mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD, cmd); mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD, cmd | CAD_QSPI_FLASHCMD_EXECUTE); do { uint32_t reg = mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD); if (!(reg & CAD_QSPI_FLASHCMD_EXECUTE_STAT)) break; count++; } while (count < CAD_QSPI_COMMAND_TIMEOUT); if (count >= CAD_QSPI_COMMAND_TIMEOUT) { ERROR("Error sending QSPI command %x, timed out\n", cmd); return CAD_QSPI_ERROR; } return 0; } int cad_qspi_stig_cmd(uint32_t opcode, uint32_t dummy) { if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) { ERROR("Faulty dummy bytes\n"); return -1; } return cad_qspi_stig_cmd_helper(cad_qspi_cs, CAD_QSPI_FLASHCMD_OPCODE(opcode) | CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES(dummy)); } int cad_qspi_stig_read_cmd(uint32_t opcode, uint32_t dummy, uint32_t num_bytes, uint32_t *output) { if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) { ERROR("Faulty dummy byes\n"); return -1; } if ((num_bytes > 8) || (num_bytes == 0)) return -1; uint32_t cmd = CAD_QSPI_FLASHCMD_OPCODE(opcode) | CAD_QSPI_FLASHCMD_ENRDDATA(1) | CAD_QSPI_FLASHCMD_NUMRDDATABYTES(num_bytes - 1) | CAD_QSPI_FLASHCMD_ENCMDADDR(0) | CAD_QSPI_FLASHCMD_ENMODEBIT(0) | CAD_QSPI_FLASHCMD_NUMADDRBYTES(0) | CAD_QSPI_FLASHCMD_ENWRDATA(0) | CAD_QSPI_FLASHCMD_NUMWRDATABYTES(0) | CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(dummy); if (cad_qspi_stig_cmd_helper(cad_qspi_cs, cmd)) { ERROR("failed to send stig cmd\n"); return -1; } output[0] = mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_RDDATA0); if (num_bytes > 4) { output[1] = mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_RDDATA1); } return 0; } int cad_qspi_stig_wr_cmd(uint32_t opcode, uint32_t dummy, uint32_t num_bytes, uint32_t *input) { if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) { ERROR("Faulty dummy byes\n"); return -1; } if ((num_bytes > 8) || (num_bytes == 0)) return -1; uint32_t cmd = CAD_QSPI_FLASHCMD_OPCODE(opcode) | CAD_QSPI_FLASHCMD_ENRDDATA(0) | CAD_QSPI_FLASHCMD_NUMRDDATABYTES(0) | CAD_QSPI_FLASHCMD_ENCMDADDR(0) | CAD_QSPI_FLASHCMD_ENMODEBIT(0) | CAD_QSPI_FLASHCMD_NUMADDRBYTES(0) | CAD_QSPI_FLASHCMD_ENWRDATA(1) | CAD_QSPI_FLASHCMD_NUMWRDATABYTES(num_bytes - 1) | CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(dummy); mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_WRDATA0, input[0]); if (num_bytes > 4) mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_WRDATA1, input[1]); return cad_qspi_stig_cmd_helper(cad_qspi_cs, cmd); } int cad_qspi_stig_addr_cmd(uint32_t opcode, uint32_t dummy, uint32_t addr) { uint32_t cmd; if (dummy > ((1 << CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX) - 1)) return -1; cmd = CAD_QSPI_FLASHCMD_OPCODE(opcode) | CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(dummy) | CAD_QSPI_FLASHCMD_ENCMDADDR(1) | CAD_QSPI_FLASHCMD_NUMADDRBYTES(2); mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_FLASHCMD_ADDR, addr); return cad_qspi_stig_cmd_helper(cad_qspi_cs, cmd); } int cad_qspi_device_bank_select(uint32_t bank) { int status = 0; status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0); if (status != 0) return status; status = cad_qspi_stig_wr_cmd(CAD_QSPI_STIG_OPCODE_WREN_EXT_REG, 0, 1, &bank); if (status != 0) return status; return cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WRDIS, 0); } int cad_qspi_device_status(uint32_t *status) { return cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDSR, 0, 1, status); } #if CAD_QSPI_MICRON_N25Q_SUPPORT int cad_qspi_n25q_enable(void) { cad_qspi_set_read_config(QSPI_FAST_READ, CAD_QSPI_INST_SINGLE, CAD_QSPI_ADDR_FASTREAD, CAT_QSPI_ADDR_SINGLE_IO, 1, 0); cad_qspi_set_write_config(QSPI_WRITE, 0, 0, 0); return 0; } int cad_qspi_n25q_wait_for_program_and_erase(int program_only) { uint32_t status, flag_sr; int count = 0; while (count < CAD_QSPI_COMMAND_TIMEOUT) { status = cad_qspi_device_status(&status); if (status != 0) { ERROR("Error getting device status\n"); return -1; } if (!CAD_QSPI_STIG_SR_BUSY(status)) break; count++; } if (count >= CAD_QSPI_COMMAND_TIMEOUT) { ERROR("Timed out waiting for idle\n"); return -1; } count = 0; while (count < CAD_QSPI_COMMAND_TIMEOUT) { status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDFLGSR, 0, 1, &flag_sr); if (status != 0) { ERROR("Error waiting program and erase.\n"); return status; } if ((program_only && CAD_QSPI_STIG_FLAGSR_PROGRAMREADY(flag_sr)) || (!program_only && CAD_QSPI_STIG_FLAGSR_ERASEREADY(flag_sr))) break; } if (count >= CAD_QSPI_COMMAND_TIMEOUT) ERROR("Timed out waiting for program and erase\n"); if ((program_only && CAD_QSPI_STIG_FLAGSR_PROGRAMERROR(flag_sr)) || (!program_only && CAD_QSPI_STIG_FLAGSR_ERASEERROR(flag_sr))) { ERROR("Error programming/erasing flash\n"); cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_CLFSR, 0); return -1; } return 0; } #endif int cad_qspi_indirect_read_start_bank(uint32_t flash_addr, uint32_t num_bytes) { mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRDSTADDR, flash_addr); mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRDCNT, num_bytes); mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRD, CAD_QSPI_INDRD_START | CAD_QSPI_INDRD_IND_OPS_DONE); return 0; } int cad_qspi_indirect_write_start_bank(uint32_t flash_addr, uint32_t num_bytes) { mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWRSTADDR, flash_addr); mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWRCNT, num_bytes); mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWR, CAD_QSPI_INDWR_START | CAD_QSPI_INDWR_INDDONE); return 0; } int cad_qspi_indirect_write_finish(void) { #if CAD_QSPI_MICRON_N25Q_SUPPORT return cad_qspi_n25q_wait_for_program_and_erase(1); #else return 0; #endif } int cad_qspi_enable(void) { int status; mmio_setbits_32(CAD_QSPI_OFFSET + CAD_QSPI_CFG, CAD_QSPI_CFG_ENABLE); #if CAD_QSPI_MICRON_N25Q_SUPPORT status = cad_qspi_n25q_enable(); if (status != 0) return status; #endif return 0; } int cad_qspi_enable_subsector_bank(uint32_t addr) { int status = 0; status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0); if (status != 0) return status; status = cad_qspi_stig_addr_cmd(CAD_QSPI_STIG_OPCODE_SUBSEC_ERASE, 0, addr); if (status != 0) return status; #if CAD_QSPI_MICRON_N25Q_SUPPORT status = cad_qspi_n25q_wait_for_program_and_erase(0); #endif return status; } int cad_qspi_erase_subsector(uint32_t addr) { int status = 0; status = cad_qspi_device_bank_select(addr >> 24); if (status != 0) return status; return cad_qspi_enable_subsector_bank(addr); } int cad_qspi_erase_sector(uint32_t addr) { int status = 0; status = cad_qspi_device_bank_select(addr >> 24); if (status != 0) return status; status = cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_WREN, 0); if (status != 0) return status; status = cad_qspi_stig_addr_cmd(CAD_QSPI_STIG_OPCODE_SEC_ERASE, 0, addr); if (status != 0) return status; #if CAD_QSPI_MICRON_N25Q_SUPPORT status = cad_qspi_n25q_wait_for_program_and_erase(0); #endif return status; } void cad_qspi_calibration(uint32_t dev_clk, uint32_t qspi_clk_mhz) { int status; uint32_t dev_sclk_mhz = 27; /*min value to get biggest 0xF div factor*/ uint32_t data_cap_delay; uint32_t sample_rdid; uint32_t rdid; uint32_t div_actual; uint32_t div_bits; int first_pass, last_pass; /*1. Set divider to bigger value (slowest SCLK) *2. RDID and save the value */ div_actual = (qspi_clk_mhz + (dev_sclk_mhz - 1)) / dev_sclk_mhz; div_bits = (((div_actual + 1) / 2) - 1); status = cad_qspi_set_baudrate_div(0xf); status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0, 3, &sample_rdid); if (status != 0) return; /*3. Set divider to the intended frequency *4. Set the read delay = 0 *5. RDID and check whether the value is same as item 2 *6. Increase read delay and compared the value against item 2 *7. Find the range of read delay that have same as * item 2 and divide it to 2 */ div_actual = (qspi_clk_mhz + (dev_clk - 1)) / dev_clk; div_bits = (((div_actual + 1) / 2) - 1); status = cad_qspi_set_baudrate_div(div_bits); if (status != 0) return; data_cap_delay = 0; first_pass = -1; last_pass = -1; do { if (status != 0) break; status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0, 3, &rdid); if (status != 0) break; if (rdid == sample_rdid) { if (first_pass == -1) first_pass = data_cap_delay; else last_pass = data_cap_delay; } data_cap_delay++; mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_RDDATACAP, CAD_QSPI_RDDATACAP_BYP(1) | CAD_QSPI_RDDATACAP_DELAY(data_cap_delay)); } while (data_cap_delay < 0x10); if (first_pass > 0) { int diff = first_pass - last_pass; data_cap_delay = first_pass + diff / 2; } mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_RDDATACAP, CAD_QSPI_RDDATACAP_BYP(1) | CAD_QSPI_RDDATACAP_DELAY(data_cap_delay)); status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0, 3, &rdid); if (status != 0) return; } int cad_qspi_int_disable(uint32_t mask) { if (cad_qspi_idle() == 0) return -1; if ((CAD_QSPI_INT_STATUS_ALL & mask) == 0) return -1; mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_IRQMSK, mask); return 0; } void cad_qspi_set_chip_select(int cs) { cad_qspi_cs = cs; } int cad_qspi_init(uint32_t desired_clk_freq, uint32_t clk_phase, uint32_t clk_pol, uint32_t csda, uint32_t csdads, uint32_t cseot, uint32_t cssot, uint32_t rddatacap) { int status = 0; uint32_t qspi_desired_clk_freq; uint32_t rdid = 0; uint32_t cap_code; INFO("Initializing Qspi\n"); if (cad_qspi_idle() == 0) { ERROR("device not idle\n"); return -1; } status = cad_qspi_timing_config(clk_phase, clk_pol, csda, csdads, cseot, cssot, rddatacap); if (status != 0) { ERROR("config set timing failure\n"); return status; } mmio_write_32(CAD_QSPI_OFFSET + CAD_QSPI_REMAPADDR, CAD_QSPI_REMAPADDR_VALUE_SET(0)); status = cad_qspi_int_disable(CAD_QSPI_INT_STATUS_ALL); if (status != 0) { ERROR("failed disable\n"); return status; } cad_qspi_set_baudrate_div(0xf); status = cad_qspi_enable(); if (status != 0) { ERROR("failed enable\n"); return status; } qspi_desired_clk_freq = 100; cad_qspi_calibration(qspi_desired_clk_freq, 50000000); status = cad_qspi_stig_read_cmd(CAD_QSPI_STIG_OPCODE_RDID, 0, 3, &rdid); if (status != 0) { ERROR("Error reading RDID\n"); return status; } /* * NOTE: The Size code seems to be a form of BCD (binary coded decimal). * The first nibble is the 10's digit and the second nibble is the 1's * digit in the number of bytes. * * Capacity ID samples: * 0x15 : 16 Mb => 2 MiB => 1 << 21 ; BCD=15 * 0x16 : 32 Mb => 4 MiB => 1 << 22 ; BCD=16 * 0x17 : 64 Mb => 8 MiB => 1 << 23 ; BCD=17 * 0x18 : 128 Mb => 16 MiB => 1 << 24 ; BCD=18 * 0x19 : 256 Mb => 32 MiB => 1 << 25 ; BCD=19 * 0x1a * 0x1b * 0x1c * 0x1d * 0x1e * 0x1f * 0x20 : 512 Mb => 64 MiB => 1 << 26 ; BCD=20 * 0x21 : 1024 Mb => 128 MiB => 1 << 27 ; BCD=21 */ cap_code = CAD_QSPI_STIG_RDID_CAPACITYID(rdid); if (!(((cap_code >> 4) > 0x9) || ((cap_code & 0xf) > 0x9))) { uint32_t decoded_cap = ((cap_code >> 4) * 10) + (cap_code & 0xf); qspi_device_size = 1 << (decoded_cap + 6); INFO("QSPI Capacity: %x\n\n", qspi_device_size); } else { ERROR("Invalid CapacityID encountered: 0x%02x\n", cap_code); return -1; } cad_qspi_configure_dev_size(INTEL_QSPI_ADDR_BYTES, INTEL_QSPI_BYTES_PER_DEV, INTEL_BYTES_PER_BLOCK); INFO("Flash size: %d Bytes\n", qspi_device_size); return status; } int cad_qspi_indirect_page_bound_write(uint32_t offset, uint8_t *buffer, uint32_t len) { int status = 0, i; uint32_t write_count, write_capacity, *write_data, space, write_fill_level, sram_partition; status = cad_qspi_indirect_write_start_bank(offset, len); if (status != 0) return status; write_count = 0; sram_partition = CAD_QSPI_SRAMPART_ADDR(mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_SRAMPART)); write_capacity = (uint32_t) CAD_QSPI_SRAM_FIFO_ENTRY_COUNT - sram_partition; while (write_count < len) { write_fill_level = CAD_QSPI_SRAMFILL_INDWRPART( mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_SRAMFILL)); space = LESS(write_capacity - write_fill_level, (len - write_count) / sizeof(uint32_t)); write_data = (uint32_t *)(buffer + write_count); for (i = 0; i < space; ++i) mmio_write_32(CAD_QSPIDATA_OFST, *write_data++); write_count += space * sizeof(uint32_t); } return cad_qspi_indirect_write_finish(); } int cad_qspi_read_bank(uint8_t *buffer, uint32_t offset, uint32_t size) { int status; uint32_t read_count = 0, *read_data; int level = 1, count = 0, i; status = cad_qspi_indirect_read_start_bank(offset, size); if (status != 0) return status; while (read_count < size) { do { level = CAD_QSPI_SRAMFILL_INDRDPART( mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_SRAMFILL)); read_data = (uint32_t *)(buffer + read_count); for (i = 0; i < level; ++i) *read_data++ = mmio_read_32(CAD_QSPIDATA_OFST); read_count += level * sizeof(uint32_t); count++; } while (level > 0); } return 0; } int cad_qspi_write_bank(uint32_t offset, uint8_t *buffer, uint32_t size) { int status = 0; uint32_t page_offset = offset & (CAD_QSPI_PAGE_SIZE - 1); uint32_t write_size = LESS(size, CAD_QSPI_PAGE_SIZE - page_offset); while (size) { status = cad_qspi_indirect_page_bound_write(offset, buffer, write_size); if (status != 0) break; offset += write_size; buffer += write_size; size -= write_size; write_size = LESS(size, CAD_QSPI_PAGE_SIZE); } return status; } int cad_qspi_read(void *buffer, uint32_t offset, uint32_t size) { uint32_t bank_count, bank_addr, bank_offset, copy_len; uint8_t *read_data; int i, status; status = 0; if ((offset >= qspi_device_size) || (offset + size - 1 >= qspi_device_size) || (size == 0) || ((long) ((int *)buffer) & 0x3) || (offset & 0x3) || (size & 0x3)) { ERROR("Invalid read parameter\n"); return -1; } if (CAD_QSPI_INDRD_RD_STAT(mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_INDRD))) { ERROR("Read in progress\n"); return -1; } /* * bank_count : Number of bank(s) affected, including partial banks. * bank_addr : Aligned address of the first bank, * including partial bank. * bank_ofst : The offset of the bank to read. * Only used when reading the first bank. */ bank_count = CAD_QSPI_BANK_ADDR(offset + size - 1) - CAD_QSPI_BANK_ADDR(offset) + 1; bank_addr = offset & CAD_QSPI_BANK_ADDR_MSK; bank_offset = offset & (CAD_QSPI_BANK_SIZE - 1); read_data = (uint8_t *)buffer; copy_len = LESS(size, CAD_QSPI_BANK_SIZE - bank_offset); for (i = 0; i < bank_count; ++i) { status = cad_qspi_device_bank_select(CAD_QSPI_BANK_ADDR( bank_addr)); if (status != 0) break; status = cad_qspi_read_bank(read_data, bank_offset, copy_len); if (status != 0) break; bank_addr += CAD_QSPI_BANK_SIZE; read_data += copy_len; size -= copy_len; bank_offset = 0; copy_len = LESS(size, CAD_QSPI_BANK_SIZE); } return status; } int cad_qspi_erase(uint32_t offset, uint32_t size) { int status = 0; uint32_t subsector_offset = offset & (CAD_QSPI_SUBSECTOR_SIZE - 1); uint32_t erase_size = LESS(size, CAD_QSPI_SUBSECTOR_SIZE - subsector_offset); while (size) { status = cad_qspi_erase_subsector(offset); if (status != 0) break; offset += erase_size; size -= erase_size; erase_size = LESS(size, CAD_QSPI_SUBSECTOR_SIZE); } return status; } int cad_qspi_write(void *buffer, uint32_t offset, uint32_t size) { int status, i; uint32_t bank_count, bank_addr, bank_offset, copy_len; uint8_t *write_data; status = 0; if ((offset >= qspi_device_size) || (offset + size - 1 >= qspi_device_size) || (size == 0) || ((long)buffer & 0x3) || (offset & 0x3) || (size & 0x3)) return -2; if (CAD_QSPI_INDWR_RDSTAT(mmio_read_32(CAD_QSPI_OFFSET + CAD_QSPI_INDWR))) { ERROR("QSPI Error: Write in progress\n"); return -1; } bank_count = CAD_QSPI_BANK_ADDR(offset + size - 1) - CAD_QSPI_BANK_ADDR(offset) + 1; bank_addr = offset & CAD_QSPI_BANK_ADDR_MSK; bank_offset = offset & (CAD_QSPI_BANK_SIZE - 1); write_data = buffer; copy_len = LESS(size, CAD_QSPI_BANK_SIZE - bank_offset); for (i = 0; i < bank_count; ++i) { status = cad_qspi_device_bank_select( CAD_QSPI_BANK_ADDR(bank_addr)); if (status != 0) break; status = cad_qspi_write_bank(bank_offset, write_data, copy_len); if (status != 0) break; bank_addr += CAD_QSPI_BANK_SIZE; write_data += copy_len; size -= copy_len; bank_offset = 0; copy_len = LESS(size, CAD_QSPI_BANK_SIZE); } return status; } int cad_qspi_update(void *Buffer, uint32_t offset, uint32_t size) { int status = 0; status = cad_qspi_erase(offset, size); if (status != 0) return status; return cad_qspi_write(Buffer, offset, size); } void cad_qspi_reset(void) { cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_RESET_EN, 0); cad_qspi_stig_cmd(CAD_QSPI_STIG_OPCODE_RESET_MEM, 0); } trusted-firmware-a-2.2/plat/intel/soc/common/drivers/qspi/cadence_qspi.h000066400000000000000000000141741355360272700264700ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CAD_QSPI_H #define CAD_QSPI_H #define CAD_QSPI_MICRON_N25Q_SUPPORT 1 #define CAD_QSPI_OFFSET 0xff8d2000 #define CAD_INVALID -1 #define CAD_QSPI_ERROR -2 #define CAD_QSPI_ADDR_FASTREAD 0 #define CAD_QSPI_ADDR_FASTREAD_DUAL_IO 1 #define CAD_QSPI_ADDR_FASTREAD_QUAD_IO 2 #define CAT_QSPI_ADDR_SINGLE_IO 0 #define CAT_QSPI_ADDR_DUAL_IO 1 #define CAT_QSPI_ADDR_QUAD_IO 2 #define CAD_QSPI_BANK_ADDR(x) ((x) >> 24) #define CAD_QSPI_BANK_ADDR_MSK 0xff000000 #define CAD_QSPI_COMMAND_TIMEOUT 0x10000000 #define CAD_QSPI_CFG 0x0 #define CAD_QSPI_CFG_BAUDDIV_MSK 0xff87ffff #define CAD_QSPI_CFG_BAUDDIV(x) (((x) << 19) & 0x780000) #define CAD_QSPI_CFG_CS_MSK ~0x3c00 #define CAD_QSPI_CFG_CS(x) (((x) << 11)) #define CAD_QSPI_CFG_ENABLE (1 << 0) #define CAD_QSPI_CFG_ENDMA_CLR_MSK 0xffff7fff #define CAD_QSPI_CFG_IDLE (1U << 31) #define CAD_QSPI_CFG_SELCLKPHASE_CLR_MSK 0xfffffffb #define CAD_QSPI_CFG_SELCLKPOL_CLR_MSK 0xfffffffd #define CAD_QSPIDATA_OFST 0xff900000 #define CAD_QSPI_DELAY 0xc #define CAD_QSPI_DELAY_CSSOT(x) (((x) & 0xff) << 0) #define CAD_QSPI_DELAY_CSEOT(x) (((x) & 0xff) << 8) #define CAD_QSPI_DELAY_CSDADS(x) (((x) & 0xff) << 16) #define CAD_QSPI_DELAY_CSDA(x) (((x) & 0xff) << 24) #define CAD_QSPI_DEVSZ 0x14 #define CAD_QSPI_DEVSZ_ADDR_BYTES(x) ((x) << 0) #define CAD_QSPI_DEVSZ_BYTES_PER_PAGE(x) ((x) << 4) #define CAD_QSPI_DEVSZ_BYTES_PER_BLOCK(x) ((x) << 16) #define CAD_QSPI_DEVWR 0x8 #define CAD_QSPI_DEVRD 0x4 #define CAD_QSPI_DEV_OPCODE(x) (((x) & 0xff) << 0) #define CAD_QSPI_DEV_INST_TYPE(x) (((x) & 0x03) << 8) #define CAD_QSPI_DEV_ADDR_TYPE(x) (((x) & 0x03) << 12) #define CAD_QSPI_DEV_DATA_TYPE(x) (((x) & 0x03) << 16) #define CAD_QSPI_DEV_MODE_BIT(x) (((x) & 0x01) << 20) #define CAD_QSPI_DEV_DUMMY_CLK_CYCLE(x) (((x) & 0x0f) << 24) #define CAD_QSPI_FLASHCMD 0x90 #define CAD_QSPI_FLASHCMD_ADDR 0x94 #define CAD_QSPI_FLASHCMD_EXECUTE 0x1 #define CAD_QSPI_FLASHCMD_EXECUTE_STAT 0x2 #define CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES_MAX 5 #define CAD_QSPI_FLASHCMD_NUM_DUMMYBYTES(x) (((x) << 7) & 0x000f80) #define CAD_QSPI_FLASHCMD_OPCODE(x) (((x) & 0xff) << 24) #define CAD_QSPI_FLASHCMD_ENRDDATA(x) (((x) & 1) << 23) #define CAD_QSPI_FLASHCMD_NUMRDDATABYTES(x) (((x) & 0xf) << 20) #define CAD_QSPI_FLASHCMD_ENCMDADDR(x) (((x) & 1) << 19) #define CAD_QSPI_FLASHCMD_ENMODEBIT(x) (((x) & 1) << 18) #define CAD_QSPI_FLASHCMD_NUMADDRBYTES(x) (((x) & 0x3) << 16) #define CAD_QSPI_FLASHCMD_ENWRDATA(x) (((x) & 1) << 15) #define CAD_QSPI_FLASHCMD_NUMWRDATABYTES(x) (((x) & 0x7) << 12) #define CAD_QSPI_FLASHCMD_NUMDUMMYBYTES(x) (((x) & 0x1f) << 7) #define CAD_QSPI_FLASHCMD_RDDATA0 0xa0 #define CAD_QSPI_FLASHCMD_RDDATA1 0xa4 #define CAD_QSPI_FLASHCMD_WRDATA0 0xa8 #define CAD_QSPI_FLASHCMD_WRDATA1 0xac #define CAD_QSPI_RDDATACAP 0x10 #define CAD_QSPI_RDDATACAP_BYP(x) (((x) & 1) << 0) #define CAD_QSPI_RDDATACAP_DELAY(x) (((x) & 0xf) << 1) #define CAD_QSPI_REMAPADDR 0x24 #define CAD_QSPI_REMAPADDR_VALUE_SET(x) (((x) & 0xffffffff) << 0) #define CAD_QSPI_SRAMPART 0x18 #define CAD_QSPI_SRAMFILL 0x2c #define CAD_QSPI_SRAMPART_ADDR(x) (((x) >> 0) & 0x3ff) #define CAD_QSPI_SRAM_FIFO_ENTRY_COUNT (512 / sizeof(uint32_t)) #define CAD_QSPI_SRAMFILL_INDWRPART(x) (((x) >> 16) & 0x00ffff) #define CAD_QSPI_SRAMFILL_INDRDPART(x) (((x) >> 0) & 0x00ffff) #define CAD_QSPI_SELCLKPHASE(x) (((x) & 1) << 2) #define CAD_QSPI_SELCLKPOL(x) (((x) & 1) << 1) #define CAD_QSPI_STIG_FLAGSR_PROGRAMREADY(x) (((x) >> 7) & 1) #define CAD_QSPI_STIG_FLAGSR_ERASEREADY(x) (((x) >> 7) & 1) #define CAD_QSPI_STIG_FLAGSR_ERASEERROR(x) (((x) >> 5) & 1) #define CAD_QSPI_STIG_FLAGSR_PROGRAMERROR(x) (((x) >> 4) & 1) #define CAD_QSPI_STIG_OPCODE_CLFSR 0x50 #define CAD_QSPI_STIG_OPCODE_RDID 0x9f #define CAD_QSPI_STIG_OPCODE_WRDIS 0x4 #define CAD_QSPI_STIG_OPCODE_WREN 0x6 #define CAD_QSPI_STIG_OPCODE_SUBSEC_ERASE 0x20 #define CAD_QSPI_STIG_OPCODE_SEC_ERASE 0xd8 #define CAD_QSPI_STIG_OPCODE_WREN_EXT_REG 0xc5 #define CAD_QSPI_STIG_OPCODE_DIE_ERASE 0xc4 #define CAD_QSPI_STIG_OPCODE_BULK_ERASE 0xc7 #define CAD_QSPI_STIG_OPCODE_RDSR 0x5 #define CAD_QSPI_STIG_OPCODE_RDFLGSR 0x70 #define CAD_QSPI_STIG_OPCODE_RESET_EN 0x66 #define CAD_QSPI_STIG_OPCODE_RESET_MEM 0x99 #define CAD_QSPI_STIG_RDID_CAPACITYID(x) (((x) >> 16) & 0xff) #define CAD_QSPI_STIG_SR_BUSY(x) (((x) >> 0) & 1) #define CAD_QSPI_INST_SINGLE 0 #define CAD_QSPI_INST_DUAL 1 #define CAD_QSPI_INST_QUAD 2 #define CAD_QSPI_INDRDSTADDR 0x68 #define CAD_QSPI_INDRDCNT 0x6c #define CAD_QSPI_INDRD 0x60 #define CAD_QSPI_INDRD_RD_STAT(x) (((x) >> 2) & 1) #define CAD_QSPI_INDRD_START 1 #define CAD_QSPI_INDRD_IND_OPS_DONE 0x20 #define CAD_QSPI_INDWR 0x70 #define CAD_QSPI_INDWR_RDSTAT(x) (((x) >> 2) & 1) #define CAD_QSPI_INDWRSTADDR 0x78 #define CAD_QSPI_INDWRCNT 0x7c #define CAD_QSPI_INDWR 0x70 #define CAD_QSPI_INDWR_START 0x1 #define CAD_QSPI_INDWR_INDDONE 0x20 #define CAD_QSPI_INT_STATUS_ALL 0x0000ffff #define CAD_QSPI_N25Q_DIE_SIZE 0x02000000 #define CAD_QSPI_BANK_SIZE 0x01000000 #define CAD_QSPI_PAGE_SIZE 0x00000100 #define CAD_QSPI_IRQMSK 0x44 #define CAD_QSPI_SUBSECTOR_SIZE 0x1000 #define INTEL_QSPI_ADDR_BYTES 2 #define INTEL_QSPI_BYTES_PER_DEV 256 #define INTEL_BYTES_PER_BLOCK 16 #define QSPI_FAST_READ 0xb #define QSPI_WRITE 0x2 // QSPI CONFIGURATIONS #define QSPI_CONFIG_CPOL 1 #define QSPI_CONFIG_CPHA 1 #define QSPI_CONFIG_CSSOT 0x14 #define QSPI_CONFIG_CSEOT 0x14 #define QSPI_CONFIG_CSDADS 0xff #define QSPI_CONFIG_CSDA 0xc8 int cad_qspi_init(uint32_t desired_clk_freq, uint32_t clk_phase, uint32_t clk_pol, uint32_t csda, uint32_t csdads, uint32_t cseot, uint32_t cssot, uint32_t rddatacap); void cad_qspi_set_chip_select(int cs); int cad_qspi_erase(uint32_t offset, uint32_t size); int cad_qspi_write(void *buffer, uint32_t offset, uint32_t size); int cad_qspi_read(void *buffer, uint32_t offset, uint32_t size); int cad_qspi_update(void *buffer, uint32_t offset, uint32_t size); #endif trusted-firmware-a-2.2/plat/intel/soc/common/drivers/wdt/000077500000000000000000000000001355360272700235145ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/intel/soc/common/drivers/wdt/watchdog.c000066400000000000000000000022511355360272700254600ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "watchdog.h" /* Reset watchdog timer */ void watchdog_sw_rst(void) { mmio_write_32(WDT_CRR, WDT_SW_RST); } /* Print component information */ void watchdog_info(void) { INFO("Component Type : %x\r\n", mmio_read_32(WDT_COMP_VERSION)); INFO("Component Version : %x\r\n", mmio_read_32(WDT_COMP_TYPE)); } /* Check watchdog current status */ void watchdog_status(void) { if (mmio_read_32(WDT_CR) & 1) { INFO("Watchdog Timer is currently enabled\n"); INFO("Current Counter : 0x%x\r\n", mmio_read_32(WDT_CCVR)); } else { INFO("Watchdog Timer is currently disabled\n"); } } /* Initialize & enable watchdog */ void watchdog_init(int watchdog_clk) { uint8_t cycles_i = 0; uint32_t wdt_cycles = WDT_MIN_CYCLES; uint32_t top_init_cycles = WDT_PERIOD * watchdog_clk; while ((cycles_i < 15) && (wdt_cycles < top_init_cycles)) { wdt_cycles = (wdt_cycles << 1); cycles_i++; } mmio_write_32(WDT_TORR, (cycles_i << 4) | cycles_i); mmio_write_32(WDT_CR, WDT_CR_RMOD|WDT_CR_EN); } trusted-firmware-a-2.2/plat/intel/soc/common/drivers/wdt/watchdog.h000066400000000000000000000015251355360272700254700ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CAD_WATCHDOG_H #define CAD_WATCHDOG_H #define WDT_BASE (0xFFD00200) #define WDT_REG_SIZE_OFFSET (0x4) #define WDT_MIN_CYCLES (65536) #define WDT_PERIOD (20) #define WDT_CR (WDT_BASE + 0x0) #define WDT_TORR (WDT_BASE + 0x4) #define WDT_CRR (WDT_BASE + 0xC) #define WDT_CCVR (WDT_BASE + 0x8) #define WDT_STAT (WDT_BASE + 0x10) #define WDT_EOI (WDT_BASE + 0x14) #define WDT_COMP_PARAM_1 (WDT_BASE + 0xF4) #define WDT_COMP_VERSION (WDT_BASE + 0xF8) #define WDT_COMP_TYPE (WDT_BASE + 0XFC) #define WDT_CR_RMOD (0x0) #define WDT_CR_EN (0x1) #define WDT_SW_RST (0x76) void watchdog_init(int watchdog_clk); void watchdog_info(void); void watchdog_status(void); void watchdog_sw_rst(void); #endif trusted-firmware-a-2.2/plat/intel/soc/common/include/000077500000000000000000000000001355360272700226635ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/intel/soc/common/include/plat_macros.S000066400000000000000000000007701355360272700253170ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S #include /* --------------------------------------------- * The below required platform porting macro * prints out relevant platform registers * whenever an unhandled exception is taken in * BL31. * --------------------------------------------- */ .macro plat_crash_print_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/intel/soc/common/include/socfpga_private.h000066400000000000000000000020011355360272700262010ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_PRIVATE_H #define PLATFORM_PRIVATE_H /******************************************************************************* * Function and variable prototypes ******************************************************************************/ void socfgpa_configure_mmu_el3(unsigned long total_base, unsigned long total_size, unsigned long ro_start, unsigned long ro_limit, unsigned long coh_start, unsigned long coh_limit); void socfpga_configure_mmu_el1(unsigned long total_base, unsigned long total_size, unsigned long ro_start, unsigned long ro_limit, unsigned long coh_start, unsigned long coh_limit); void socfpga_delay_timer_init(void); void socfpga_gic_driver_init(void); uint32_t socfpga_get_spsr_for_bl32_entry(void); uint32_t socfpga_get_spsr_for_bl33_entry(void); unsigned long socfpga_get_ns_image_entrypoint(void); #endif /* PLATFORM_PRIVATE_H */ trusted-firmware-a-2.2/plat/intel/soc/common/socfpga_delay_timer.c000066400000000000000000000021361355360272700254060ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #define SOCFPGA_GLOBAL_TIMER 0xffd01000 #define SOCFPGA_GLOBAL_TIMER_EN 0x3 /******************************************************************** * The timer delay function ********************************************************************/ static uint32_t socfpga_get_timer_value(void) { /* * Generic delay timer implementation expects the timer to be a down * counter. We apply bitwise NOT operator to the tick values returned * by read_cntpct_el0() to simulate the down counter. The value is * clipped from 64 to 32 bits. */ return (uint32_t)(~read_cntpct_el0()); } static const timer_ops_t plat_timer_ops = { .get_timer_value = socfpga_get_timer_value, .clk_mult = 1, .clk_div = PLAT_SYS_COUNTER_FREQ_IN_MHZ, }; void socfpga_delay_timer_init(void) { timer_init(&plat_timer_ops); mmio_write_32(SOCFPGA_GLOBAL_TIMER, SOCFPGA_GLOBAL_TIMER_EN); } trusted-firmware-a-2.2/plat/intel/soc/common/socfpga_image_load.c000066400000000000000000000021561355360272700251730ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /******************************************************************************* * This function flushes the data structures so that they are visible * in memory for the next BL image. ******************************************************************************/ void plat_flush_next_bl_params(void) { flush_bl_params_desc(); } /******************************************************************************* * This function returns the list of loadable images. ******************************************************************************/ bl_load_info_t *plat_get_bl_image_load_info(void) { return get_bl_load_info_from_mem_params_desc(); } /******************************************************************************* * This function returns the list of executable images. ******************************************************************************/ bl_params_t *plat_get_next_bl_params(void) { return get_next_bl_params_from_mem_params_desc(); } trusted-firmware-a-2.2/plat/intel/soc/common/socfpga_topology.c000066400000000000000000000031151355360272700247620ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include static const unsigned char plat_power_domain_tree_desc[] = {1, 4}; /******************************************************************************* * This function returns the default topology tree information. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { return plat_power_domain_tree_desc; } /******************************************************************************* * This function implements a part of the critical interface between the psci * generic layer and the platform that allows the former to query the platform * to convert an MPIDR to a unique linear index. An error code (-1) is returned * in case the MPIDR is invalid. ******************************************************************************/ int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; mpidr &= MPIDR_AFFINITY_MASK; if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) return -1; cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; if (cluster_id >= PLATFORM_CLUSTER_COUNT) return -1; /* * Validate cpu_id by checking whether it represents a CPU in * one of the two clusters present on the platform. */ if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER) return -1; return (cpu_id + (cluster_id * 4)); } trusted-firmware-a-2.2/plat/intel/soc/stratix10/000077500000000000000000000000001355360272700216075ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/intel/soc/stratix10/bl2_plat_setup.c000066400000000000000000000107351355360272700247000ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "s10_memory_controller.h" #include "s10_reset_manager.h" #include "s10_clock_manager.h" #include "s10_handoff.h" #include "s10_pinmux.h" #include "stratix10_private.h" #include "include/s10_mailbox.h" #include "qspi/cadence_qspi.h" #include "wdt/watchdog.h" const mmap_region_t plat_stratix10_mmap[] = { MAP_REGION_FLAT(DRAM_BASE, DRAM_SIZE, MT_MEMORY | MT_RW | MT_NS), MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_NS), MAP_REGION_FLAT(DEVICE2_BASE, DEVICE2_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(OCRAM_BASE, OCRAM_SIZE, MT_NON_CACHEABLE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DEVICE3_BASE, DEVICE3_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(MEM64_BASE, MEM64_SIZE, MT_DEVICE | MT_RW | MT_NS), MAP_REGION_FLAT(DEVICE4_BASE, DEVICE4_SIZE, MT_DEVICE | MT_RW | MT_NS), {0}, }; boot_source_type boot_source; void bl2_el3_early_platform_setup(u_register_t x0, u_register_t x1, u_register_t x2, u_register_t x4) { static console_16550_t console; handoff reverse_handoff_ptr; generic_delay_timer_init(); if (s10_get_handoff(&reverse_handoff_ptr)) return; config_pinmux(&reverse_handoff_ptr); boot_source = reverse_handoff_ptr.boot_source; config_clkmgr_handoff(&reverse_handoff_ptr); enable_nonsecure_access(); deassert_peripheral_reset(); config_hps_hs_before_warm_reset(); watchdog_init(get_wdt_clk()); console_16550_register(PLAT_UART0_BASE, get_uart_clk(), PLAT_BAUDRATE, &console); socfpga_delay_timer_init(); init_hard_memory_controller(); } void bl2_el3_plat_arch_setup(void) { struct mmc_device_info info; const mmap_region_t bl_regions[] = { MAP_REGION_FLAT(BL2_BASE, BL2_END - BL2_BASE, MT_MEMORY | MT_RW | MT_SECURE), MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, MT_CODE | MT_SECURE), MAP_REGION_FLAT(BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE, MT_RO_DATA | MT_SECURE), #if USE_COHERENT_MEM_BAR MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, MT_DEVICE | MT_RW | MT_SECURE), #endif {0}, }; setup_page_tables(bl_regions, plat_stratix10_mmap); enable_mmu_el3(0); dw_mmc_params_t params = EMMC_INIT_PARAMS(0x100000, get_mmc_clk()); info.mmc_dev_type = MMC_IS_SD; info.ocr_voltage = OCR_3_3_3_4 | OCR_3_2_3_3; switch (boot_source) { case BOOT_SOURCE_SDMMC: dw_mmc_init(¶ms, &info); stratix10_io_setup(boot_source); break; case BOOT_SOURCE_QSPI: mailbox_set_qspi_open(); mailbox_set_qspi_direct(); cad_qspi_init(0, QSPI_CONFIG_CPHA, QSPI_CONFIG_CPOL, QSPI_CONFIG_CSDA, QSPI_CONFIG_CSDADS, QSPI_CONFIG_CSEOT, QSPI_CONFIG_CSSOT, 0); stratix10_io_setup(boot_source); break; default: ERROR("Unsupported boot source\n"); panic(); break; } } uint32_t get_spsr_for_bl33_entry(void) { unsigned long el_status; unsigned int mode; uint32_t spsr; /* Figure out what mode we enter the non-secure world in */ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; el_status &= ID_AA64PFR0_ELX_MASK; mode = (el_status) ? MODE_EL2 : MODE_EL1; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; } int bl2_plat_handle_post_image_load(unsigned int image_id) { bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id); switch (image_id) { case BL33_IMAGE_ID: bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr(); bl_mem_params->ep_info.spsr = get_spsr_for_bl33_entry(); break; default: break; } return 0; } /******************************************************************************* * Perform any BL3-1 platform setup code ******************************************************************************/ void bl2_platform_setup(void) { } trusted-firmware-a-2.2/plat/intel/soc/stratix10/bl31_plat_setup.c000066400000000000000000000110641355360272700247560ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "stratix10_private.h" #include "s10_handoff.h" #include "s10_reset_manager.h" #include "s10_memory_controller.h" #include "s10_pinmux.h" #include "s10_clock_manager.h" #include "s10_system_manager.h" static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; next_image_info = (type == NON_SECURE) ? &bl33_image_ep_info : &bl32_image_ep_info; /* None of the images on this platform can have 0x0 as the entrypoint */ if (next_image_info->pc) return next_image_info; else return NULL; } void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { static console_16550_t console; console_16550_register(PLAT_UART0_BASE, PLAT_UART_CLOCK, PLAT_BAUDRATE, &console); /* * Check params passed from BL31 should not be NULL, */ void *from_bl2 = (void *) arg0; bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2; assert(params_from_bl2 != NULL); assert(params_from_bl2->h.type == PARAM_BL_PARAMS); assert(params_from_bl2->h.version >= VERSION_2); /* * Copy BL32 (if populated by BL31) and BL33 entry point information. * They are stored in Secure RAM, in BL31's address space. */ bl_params_node_t *bl_params = params_from_bl2->head; while (bl_params) { if (bl_params->image_id == BL33_IMAGE_ID) bl33_image_ep_info = *bl_params->ep_info; bl_params = bl_params->next_params_info; } SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); } static const interrupt_prop_t s10_interrupt_props[] = { PLAT_INTEL_S10_G1S_IRQ_PROPS(GICV2_INTR_GROUP0), PLAT_INTEL_S10_G0_IRQ_PROPS(GICV2_INTR_GROUP0) }; static unsigned int target_mask_array[PLATFORM_CORE_COUNT]; static const gicv2_driver_data_t plat_gicv2_gic_data = { .gicd_base = PLAT_INTEL_S10_GICD_BASE, .gicc_base = PLAT_INTEL_S10_GICC_BASE, .interrupt_props = s10_interrupt_props, .interrupt_props_num = ARRAY_SIZE(s10_interrupt_props), .target_masks = target_mask_array, .target_masks_num = ARRAY_SIZE(target_mask_array), }; /******************************************************************************* * Perform any BL3-1 platform setup code ******************************************************************************/ void bl31_platform_setup(void) { /* Initialize the gic cpu and distributor interfaces */ gicv2_driver_init(&plat_gicv2_gic_data); gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } const mmap_region_t plat_stratix10_mmap[] = { MAP_REGION_FLAT(DRAM_BASE, DRAM_SIZE, MT_MEMORY | MT_RW | MT_NS), MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_NS), MAP_REGION_FLAT(DEVICE2_BASE, DEVICE2_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(OCRAM_BASE, OCRAM_SIZE, MT_NON_CACHEABLE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DEVICE3_BASE, DEVICE3_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(MEM64_BASE, MEM64_SIZE, MT_DEVICE | MT_RW | MT_NS), MAP_REGION_FLAT(DEVICE4_BASE, DEVICE4_SIZE, MT_DEVICE | MT_RW | MT_NS), {0} }; /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this is only intializes the mmu in a quick and dirty way. ******************************************************************************/ void bl31_plat_arch_setup(void) { const mmap_region_t bl_regions[] = { MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE, MT_MEMORY | MT_RW | MT_SECURE), MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, MT_CODE | MT_SECURE), MAP_REGION_FLAT(BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE, MT_RO_DATA | MT_SECURE), #if USE_COHERENT_MEM MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, MT_DEVICE | MT_RW | MT_SECURE), #endif {0} }; setup_page_tables(bl_regions, plat_stratix10_mmap); enable_mmu_el3(0); } trusted-firmware-a-2.2/plat/intel/soc/stratix10/include/000077500000000000000000000000001355360272700232325ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/intel/soc/stratix10/include/platform_def.h000066400000000000000000000156141355360272700260540ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __PLATFORM_DEF_H__ #define __PLATFORM_DEF_H__ #include #include #include #include #include #include #define PLAT_CPUID_RELEASE 0xffe1b000 #define PLAT_SEC_ENTRY 0xffe1b008 /* Define next boot image name and offset */ #define PLAT_NS_IMAGE_OFFSET 0x50000 #define PLAT_HANDOFF_OFFSET 0xFFE3F000 /******************************************************************************* * Platform binary types for linking ******************************************************************************/ #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 /* Stratix 10 supports up to 124GB RAM */ #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 39) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 39) /******************************************************************************* * Generic platform constants ******************************************************************************/ #define PLAT_PRIMARY_CPU 0 #define PLAT_SECONDARY_ENTRY_BASE 0x01f78bf0 /* Size of cacheable stacks */ #define PLATFORM_STACK_SIZE 0x2000 /* PSCI related constant */ #define PLAT_NUM_POWER_DOMAINS 5 #define PLAT_MAX_PWR_LVL 1 #define PLAT_MAX_RET_STATE 1 #define PLAT_MAX_OFF_STATE 2 #define PLATFORM_SYSTEM_COUNT 1 #define PLATFORM_CLUSTER_COUNT 1 #define PLATFORM_CLUSTER0_CORE_COUNT 4 #define PLATFORM_CLUSTER1_CORE_COUNT 0 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \ PLATFORM_CLUSTER0_CORE_COUNT) #define PLATFORM_MAX_CPUS_PER_CLUSTER 4 /* Interrupt related constant */ #define INTEL_S10_IRQ_SEC_PHY_TIMER 29 #define INTEL_S10_IRQ_SEC_SGI_0 8 #define INTEL_S10_IRQ_SEC_SGI_1 9 #define INTEL_S10_IRQ_SEC_SGI_2 10 #define INTEL_S10_IRQ_SEC_SGI_3 11 #define INTEL_S10_IRQ_SEC_SGI_4 12 #define INTEL_S10_IRQ_SEC_SGI_5 13 #define INTEL_S10_IRQ_SEC_SGI_6 14 #define INTEL_S10_IRQ_SEC_SGI_7 15 #define TSP_IRQ_SEC_PHY_TIMER INTEL_S10_IRQ_SEC_PHY_TIMER #define TSP_SEC_MEM_BASE BL32_BASE #define TSP_SEC_MEM_SIZE (BL32_LIMIT - BL32_BASE + 1) /******************************************************************************* * Platform memory map related constants ******************************************************************************/ #define DRAM_BASE (0x0) #define DRAM_SIZE (0x80000000) #define OCRAM_BASE (0xFFE00000) #define OCRAM_SIZE (0x00040000) #define MEM64_BASE (0x0100000000) #define MEM64_SIZE (0x1F00000000) #define DEVICE1_BASE (0x80000000) #define DEVICE1_SIZE (0x60000000) #define DEVICE2_BASE (0xF7000000) #define DEVICE2_SIZE (0x08E00000) #define DEVICE3_BASE (0xFFFC0000) #define DEVICE3_SIZE (0x00008000) #define DEVICE4_BASE (0x2000000000) #define DEVICE4_SIZE (0x0100000000) /******************************************************************************* * BL31 specific defines. ******************************************************************************/ /* * Put BL3-1 at the top of the Trusted SRAM (just below the shared memory, if * present). BL31_BASE is calculated using the current BL3-1 debug size plus a * little space for growth. */ #define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n" #define BL1_RO_BASE (0xffe00000) #define BL1_RO_LIMIT (0xffe0f000) #define BL1_RW_BASE (0xffe10000) #define BL1_RW_LIMIT (0xffe1ffff) #define BL1_RW_SIZE (0x14000) #define BL2_BASE (0xffe00000) #define BL2_LIMIT (0xffe1b000) #define BL31_BASE (0xffe1c000) #define BL31_LIMIT (0xffe3bfff) /******************************************************************************* * Platform specific page table and MMU setup constants ******************************************************************************/ #define MAX_XLAT_TABLES 8 #define MAX_MMAP_REGIONS 16 /******************************************************************************* * Declarations and constants to access the mailboxes safely. Each mailbox is * aligned on the biggest cache line size in the platform. This is known only * to the platform as it might have a combination of integrated and external * caches. Such alignment ensures that two maiboxes do not sit on the same cache * line at any cache level. They could belong to different cpus/clusters & * get written while being protected by different locks causing corruption of * a valid mailbox address. ******************************************************************************/ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) #define PLAT_GIC_BASE (0xFFFC0000) #define PLAT_GICC_BASE (PLAT_GIC_BASE + 0x2000) #define PLAT_GICD_BASE (PLAT_GIC_BASE + 0x1000) #define PLAT_GICR_BASE 0 /******************************************************************************* * UART related constants ******************************************************************************/ #define PLAT_UART0_BASE (0xFFC02000) #define PLAT_UART1_BASE (0xFFC02100) #define CRASH_CONSOLE_BASE PLAT_UART0_BASE #define PLAT_BAUDRATE (115200) #define PLAT_UART_CLOCK (100000000) /******************************************************************************* * System counter frequency related constants ******************************************************************************/ #define PLAT_SYS_COUNTER_FREQ_IN_TICKS (400000000) #define PLAT_SYS_COUNTER_FREQ_IN_MHZ (400) #define PLAT_INTEL_S10_GICD_BASE PLAT_GICD_BASE #define PLAT_INTEL_S10_GICC_BASE PLAT_GICC_BASE /* * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 * terminology. On a GICv2 system or mode, the lists will be merged and treated * as Group 0 interrupts. */ #define PLAT_INTEL_S10_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(INTEL_S10_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(INTEL_S10_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(INTEL_S10_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(INTEL_S10_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(INTEL_S10_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(INTEL_S10_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(INTEL_S10_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(INTEL_S10_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(INTEL_S10_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE) #define PLAT_INTEL_S10_G0_IRQ_PROPS(grp) #define MAX_IO_HANDLES 4 #define MAX_IO_DEVICES 4 #define MAX_IO_BLOCK_DEVICES 2 #endif /* __PLATFORM_DEF_H__ */ trusted-firmware-a-2.2/plat/intel/soc/stratix10/include/s10_clock_manager.h000066400000000000000000000072001355360272700266520ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __CLOCKMANAGER_H__ #define __CLOCKMANAGER_H__ #include "s10_handoff.h" #define ALT_CLKMGR 0xffd10000 #define ALT_CLKMGR_CTRL 0x0 #define ALT_CLKMGR_STAT 0x4 #define ALT_CLKMGR_INTRCLR 0x14 #define ALT_CLKMGR_INTRCLR_MAINLOCKLOST_SET_MSK 0x00000004 #define ALT_CLKMGR_INTRCLR_PERLOCKLOST_SET_MSK 0x00000008 #define ALT_CLKMGR_CTRL_BOOTMODE_SET_MSK 0x00000001 #define ALT_CLKMGR_STAT_BUSY_E_BUSY 0x1 #define ALT_CLKMGR_STAT_BUSY(x) (((x) & 0x00000001) >> 0) #define ALT_CLKMGR_STAT_MAINPLLLOCKED(x) (((x) & 0x00000100) >> 8) #define ALT_CLKMGR_STAT_PERPLLLOCKED(x) (((x) & 0x00000200) >> 9) #define ALT_CLKMGR_MAINPLL 0xffd10030 #define ALT_CLKMGR_MAINPLL_EN 0x0 #define ALT_CLKMGR_MAINPLL_BYPASS 0xc #define ALT_CLKMGR_MAINPLL_MPUCLK 0x18 #define ALT_CLKMGR_MAINPLL_NOCCLK 0x1c #define ALT_CLKMGR_MAINPLL_CNTR2CLK 0x20 #define ALT_CLKMGR_MAINPLL_CNTR3CLK 0x24 #define ALT_CLKMGR_MAINPLL_CNTR4CLK 0x28 #define ALT_CLKMGR_MAINPLL_CNTR5CLK 0x2c #define ALT_CLKMGR_MAINPLL_CNTR6CLK 0x30 #define ALT_CLKMGR_MAINPLL_CNTR7CLK 0x34 #define ALT_CLKMGR_MAINPLL_CNTR8CLK 0x38 #define ALT_CLKMGR_MAINPLL_CNTR9CLK 0x3c #define ALT_CLKMGR_MAINPLL_NOCDIV 0x40 #define ALT_CLKMGR_MAINPLL_PLLGLOB 0x44 #define ALT_CLKMGR_MAINPLL_FDBCK 0x48 #define ALT_CLKMGR_MAINPLL_PLLC0 0x54 #define ALT_CLKMGR_MAINPLL_PLLC1 0x58 #define ALT_CLKMGR_MAINPLL_VCOCALIB 0x5c #define ALT_CLKMGR_MAINPLL_EN_RESET 0x000000ff #define ALT_CLKMGR_MAINPLL_FDBCK_MDIV(x) (((x) & 0xff000000) >> 24) #define ALT_CLKMGR_MAINPLL_PLLGLOB_PD_SET_MSK 0x00000001 #define ALT_CLKMGR_MAINPLL_PLLGLOB_REFCLKDIV(x) (((x) & 0x00003f00) >> 8) #define ALT_CLKMGR_MAINPLL_PLLGLOB_RST_SET_MSK 0x00000002 #define ALT_CLKMGR_MAINPLL_VCOCALIB_HSCNT_SET(x) (((x) << 0) & 0x000000ff) #define ALT_CLKMGR_MAINPLL_VCOCALIB_MSCNT_SET(x) (((x) << 9) & 0x0001fe00) #define ALT_CLKMGR_PSRC(x) (((x) & 0x00030000) >> 16) #define ALT_CLKMGR_SRC_MAIN 0 #define ALT_CLKMGR_SRC_PER 1 #define ALT_CLKMGR_PLLGLOB_PSRC_EOSC1 0x0 #define ALT_CLKMGR_PLLGLOB_PSRC_INTOSC 0x1 #define ALT_CLKMGR_PLLGLOB_PSRC_F2S 0x2 #define ALT_CLKMGR_PERPLL 0xffd100a4 #define ALT_CLKMGR_PERPLL_EN 0x0 #define ALT_CLKMGR_PERPLL_BYPASS 0xc #define ALT_CLKMGR_PERPLL_CNTR2CLK 0x18 #define ALT_CLKMGR_PERPLL_CNTR3CLK 0x1c #define ALT_CLKMGR_PERPLL_CNTR4CLK 0x20 #define ALT_CLKMGR_PERPLL_CNTR5CLK 0x24 #define ALT_CLKMGR_PERPLL_CNTR6CLK 0x28 #define ALT_CLKMGR_PERPLL_CNTR7CLK 0x2c #define ALT_CLKMGR_PERPLL_CNTR8CLK 0x30 #define ALT_CLKMGR_PERPLL_CNTR9CLK 0x34 #define ALT_CLKMGR_PERPLL_GPIODIV 0x3c #define ALT_CLKMGR_PERPLL_EMACCTL 0x38 #define ALT_CLKMGR_PERPLL_PLLGLOB 0x40 #define ALT_CLKMGR_PERPLL_FDBCK 0x44 #define ALT_CLKMGR_PERPLL_PLLC0 0x50 #define ALT_CLKMGR_PERPLL_PLLC1 0x54 #define ALT_CLKMGR_PERPLL_EN_RESET 0x00000fff #define ALT_CLKMGR_PERPLL_FDBCK_MDIV(x) (((x) & 0xff000000) >> 24) #define ALT_CLKMGR_PERPLL_GPIODIV_GPIODBCLK_SET(x) (((x) << 0) & 0x0000ffff) #define ALT_CLKMGR_PERPLL_PLLGLOB_PD_SET_MSK 0x00000001 #define ALT_CLKMGR_PERPLL_PLLGLOB_REFCLKDIV(x) (((x) & 0x00003f00) >> 8) #define ALT_CLKMGR_PERPLL_PLLGLOB_REFCLKDIV_SET(x) (((x) << 8) & 0x00003f00) #define ALT_CLKMGR_PERPLL_PLLGLOB_RST_SET_MSK 0x00000002 #define ALT_CLKMGR_PERPLL_VCOCALIB_HSCNT_SET(x) (((x) << 0) & 0x000000ff) #define ALT_CLKMGR_PERPLL_VCOCALIB_MSCNT_SET(x) (((x) << 9) & 0x0001fe00) #define ALT_CLKMGR_PERPLL_VCOCALIB 0x58 #define ALT_CLKMGR_INTOSC_HZ 460000000 void config_clkmgr_handoff(handoff *hoff_ptr); uint32_t get_wdt_clk(void); uint32_t get_uart_clk(void); uint32_t get_mmc_clk(void); #endif trusted-firmware-a-2.2/plat/intel/soc/stratix10/include/s10_handoff.h000066400000000000000000000051241355360272700254750ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef _HANDOFF_H_ #define _HANDOFF_H_ #define HANDOFF_MAGIC_HEADER 0x424f4f54 /* BOOT */ #define HANDOFF_MAGIC_PINMUX_SEL 0x504d5558 /* PMUX */ #define HANDOFF_MAGIC_IOCTLR 0x494f4354 /* IOCT */ #define HANDOFF_MAGIC_FPGA 0x46504741 /* FPGA */ #define HANDOFF_MAGIC_IODELAY 0x444c4159 /* DLAY */ #define HANDOFF_MAGIC_CLOCK 0x434c4b53 /* CLKS */ #define HANDOFF_MAGIC_MISC 0x4d495343 /* MISC */ typedef struct handoff_t { /* header */ uint32_t header_magic; uint32_t header_device; uint32_t _pad_0x08_0x10[2]; /* pinmux configuration - select */ uint32_t pinmux_sel_magic; uint32_t pinmux_sel_length; uint32_t _pad_0x18_0x20[2]; uint32_t pinmux_sel_array[96]; /* offset, value */ /* pinmux configuration - io control */ uint32_t pinmux_io_magic; uint32_t pinmux_io_length; uint32_t _pad_0x1a8_0x1b0[2]; uint32_t pinmux_io_array[96]; /* offset, value */ /* pinmux configuration - use fpga switch */ uint32_t pinmux_fpga_magic; uint32_t pinmux_fpga_length; uint32_t _pad_0x338_0x340[2]; uint32_t pinmux_fpga_array[42]; /* offset, value */ uint32_t _pad_0x3e8_0x3f0[2]; /* pinmux configuration - io delay */ uint32_t pinmux_delay_magic; uint32_t pinmux_delay_length; uint32_t _pad_0x3f8_0x400[2]; uint32_t pinmux_iodelay_array[96]; /* offset, value */ /* clock configuration */ uint32_t clock_magic; uint32_t clock_length; uint32_t _pad_0x588_0x590[2]; uint32_t main_pll_mpuclk; uint32_t main_pll_nocclk; uint32_t main_pll_cntr2clk; uint32_t main_pll_cntr3clk; uint32_t main_pll_cntr4clk; uint32_t main_pll_cntr5clk; uint32_t main_pll_cntr6clk; uint32_t main_pll_cntr7clk; uint32_t main_pll_cntr8clk; uint32_t main_pll_cntr9clk; uint32_t main_pll_nocdiv; uint32_t main_pll_pllglob; uint32_t main_pll_fdbck; uint32_t main_pll_pllc0; uint32_t main_pll_pllc1; uint32_t _pad_0x5cc_0x5d0[1]; uint32_t per_pll_cntr2clk; uint32_t per_pll_cntr3clk; uint32_t per_pll_cntr4clk; uint32_t per_pll_cntr5clk; uint32_t per_pll_cntr6clk; uint32_t per_pll_cntr7clk; uint32_t per_pll_cntr8clk; uint32_t per_pll_cntr9clk; uint32_t per_pll_emacctl; uint32_t per_pll_gpiodiv; uint32_t per_pll_pllglob; uint32_t per_pll_fdbck; uint32_t per_pll_pllc0; uint32_t per_pll_pllc1; uint32_t hps_osc_clk_h; uint32_t fpga_clk_hz; /* misc configuration */ uint32_t misc_magic; uint32_t misc_length; uint32_t _pad_0x618_0x620[2]; uint32_t boot_source; } handoff; int verify_handoff_image(handoff *hoff_ptr, handoff *reverse_hoff_ptr); int s10_get_handoff(handoff *hoff_ptr); #endif trusted-firmware-a-2.2/plat/intel/soc/stratix10/include/s10_mailbox.h000066400000000000000000000075041355360272700255270ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __S10_MBOX__ #define __S10_MBOX__ #define MBOX_OFFSET 0xffa30000 #define MBOX_ATF_CLIENT_ID 0x1 #define MBOX_JOB_ID 0x1 /* Mailbox interrupt flags and masks */ #define MBOX_INT_FLAG_COE 0x1 #define MBOX_INT_FLAG_RIE 0x2 #define MBOX_INT_FLAG_UAE 0x100 #define MBOX_COE_BIT(INTERRUPT) ((INTERRUPT) & 0x3) #define MBOX_UAE_BIT(INTERRUPT) (((INTERRUPT) & (1<<4))) /* Mailbox response and status */ #define MBOX_RESP_BUFFER_SIZE 16 #define MBOX_RESP_ERR(BUFFER) ((BUFFER) & 0x00000fff) #define MBOX_RESP_LEN(BUFFER) (((BUFFER) & 0x007ff000) >> 12) #define MBOX_RESP_CLIENT_ID(BUFFER) (((BUFFER) & 0xf0000000) >> 28) #define MBOX_RESP_JOB_ID(BUFFER) (((BUFFER) & 0x0f000000) >> 24) #define MBOX_STATUS_UA_MASK (1<<8) /* Mailbox command and response */ #define MBOX_CMD_FREE_OFFSET 0x14 #define MBOX_CMD_BUFFER_SIZE 32 #define MBOX_CLIENT_ID_CMD(CLIENT_ID) ((CLIENT_ID) << 28) #define MBOX_JOB_ID_CMD(JOB_ID) (JOB_ID<<24) #define MBOX_CMD_LEN_CMD(CMD_LEN) ((CMD_LEN) << 12) #define MBOX_INDIRECT (1 << 11) #define MBOX_INSUFFICIENT_BUFFER -2 #define MBOX_CIN 0x00 #define MBOX_ROUT 0x04 #define MBOX_URG 0x08 #define MBOX_INT 0x0C #define MBOX_COUT 0x20 #define MBOX_RIN 0x24 #define MBOX_STATUS 0x2C #define MBOX_CMD_BUFFER 0x40 #define MBOX_RESP_BUFFER 0xC0 #define MBOX_RESP_BUFFER_SIZE 16 #define MBOX_RESP_OK 0 #define MBOX_RESP_INVALID_CMD 1 #define MBOX_RESP_UNKNOWN_BR 2 #define MBOX_RESP_UNKNOWN 3 #define MBOX_RESP_NOT_CONFIGURED 256 /* Mailbox SDM doorbell */ #define MBOX_DOORBELL_TO_SDM 0x400 #define MBOX_DOORBELL_FROM_SDM 0x480 /* Mailbox QSPI commands */ #define MBOX_CMD_RESTART 2 #define MBOX_CMD_QSPI_OPEN 50 #define MBOX_CMD_QSPI_CLOSE 51 #define MBOX_CMD_QSPI_DIRECT 59 #define MBOX_CMD_GET_IDCODE 16 #define MBOX_CMD_QSPI_SET_CS 52 /* Mailbox REBOOT commands */ #define MBOX_CMD_REBOOT_HPS 71 /* Generic error handling */ #define MBOX_TIMEOUT -2047 #define MBOX_NO_RESPONSE -2 #define MBOX_WRONG_ID -3 /* Mailbox status */ #define RECONFIG_STATUS_STATE 0 #define RECONFIG_STATUS_PIN_STATUS 2 #define RECONFIG_STATUS_SOFTFUNC_STATUS 3 #define PIN_STATUS_NSTATUS (1U << 31) #define SOFTFUNC_STATUS_SEU_ERROR (1 << 3) #define SOFTFUNC_STATUS_INIT_DONE (1 << 1) #define SOFTFUNC_STATUS_CONF_DONE (1 << 0) #define MBOX_CFGSTAT_STATE_CONFIG 0x10000000 /* SMC function IDs for SiP Service queries */ #define SIP_SVC_CALL_COUNT 0x8200ff00 #define SIP_SVC_UID 0x8200ff01 #define SIP_SVC_VERSION 0x8200ff03 /* SiP Service Calls version numbers */ #define SIP_SVC_VERSION_MAJOR 0 #define SIP_SVC_VERSION_MINOR 1 /* Mailbox reconfiguration commands */ #define MBOX_RECONFIG 6 #define MBOX_RECONFIG_DATA 8 #define MBOX_RECONFIG_STATUS 9 /* Sip get memory */ #define INTEL_SIP_SMC_FPGA_CONFIG_START 0xC2000001 #define INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM 0xC2000005 #define INTEL_SIP_SMC_FPGA_CONFIG_ISDONE 0xC2000004 #define INTEL_SIP_SMC_FPGA_CONFIG_WRITE 0x42000002 #define INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE 0xC2000003 #define INTEL_SIP_SMC_STATUS_OK 0 #define INTEL_SIP_SMC_STATUS_ERROR 0x4 #define INTEL_SIP_SMC_STATUS_BUSY 0x1 #define INTEL_SIP_SMC_STATUS_REJECTED 0x2 #define INTEL_SIP_SMC_FPGA_CONFIG_ADDR 0x1000 #define INTEL_SIP_SMC_FPGA_CONFIG_SIZE 16777216 void mailbox_set_int(int interrupt_input); int mailbox_init(void); void mailbox_set_qspi_close(void); void mailbox_set_qspi_open(void); void mailbox_set_qspi_direct(void); int mailbox_send_cmd(int job_id, unsigned int cmd, uint32_t *args, int len, int urgent, uint32_t *response); void mailbox_send_cmd_async(int job_id, unsigned int cmd, uint32_t *args, int len, int urgent); int mailbox_read_response(int job_id, uint32_t *response); int mailbox_get_qspi_clock(void); void mailbox_reset_cold(void); #endif trusted-firmware-a-2.2/plat/intel/soc/stratix10/include/s10_memory_controller.h000066400000000000000000000152031355360272700276420ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __S10_MEMORYCONTROLLER_H__ #define __S10_MEMORYCONTROLLER_H__ #define S10_MPFE_IOHMC_REG_DRAMADDRW 0xf80100a8 #define S10_MPFE_IOHMC_CTRLCFG0 0xf8010028 #define S10_MPFE_IOHMC_CTRLCFG1 0xf801002c #define S10_MPFE_IOHMC_DRAMADDRW 0xf80100a8 #define S10_MPFE_IOHMC_DRAMTIMING0 0xf8010050 #define S10_MPFE_IOHMC_CALTIMING0 0xf801007c #define S10_MPFE_IOHMC_CALTIMING1 0xf8010080 #define S10_MPFE_IOHMC_CALTIMING2 0xf8010084 #define S10_MPFE_IOHMC_CALTIMING3 0xf8010088 #define S10_MPFE_IOHMC_CALTIMING4 0xf801008c #define S10_MPFE_IOHMC_CALTIMING9 0xf80100a0 #define S10_MPFE_IOHMC_CALTIMING9_ACT_TO_ACT(x) (((x) & 0x000000ff) >> 0) #define S10_MPFE_IOHMC_CTRLCFG1_CFG_ADDR_ORDER(value) \ (((value) & 0x00000060) >> 5) #define S10_RSTMGR_BRGMODRST 0xffd1102c #define S10_RSTMGR_BRGMODRST_DDRSCH 0x00000040 #define S10_MPFE_HMC_ADP_ECCCTRL1 0xf8011100 #define S10_MPFE_HMC_ADP_ECCCTRL2 0xf8011104 #define S10_MPFE_HMC_ADP_RSTHANDSHAKESTAT 0xf8011218 #define S10_MPFE_HMC_ADP_RSTHANDSHAKESTAT_SEQ2CORE 0x000000ff #define S10_MPFE_HMC_ADP_RSTHANDSHAKECTRL 0xf8011214 #define S10_MPFE_IOHMC_REG_CTRLCFG1 0xf801002c #define S10_MPFE_IOHMC_REG_NIOSRESERVE0_OFST 0xf8010110 #define IOHMC_DRAMADDRW_COL_ADDR_WIDTH(x) (((x) & 0x0000001f) >> 0) #define IOHMC_DRAMADDRW_ROW_ADDR_WIDTH(x) (((x) & 0x000003e0) >> 5) #define IOHMC_DRAMADDRW_CS_ADDR_WIDTH(x) (((x) & 0x00070000) >> 16) #define IOHMC_DRAMADDRW_BANK_GRP_ADDR_WIDTH(x) (((x) & 0x0000c000) >> 14) #define IOHMC_DRAMADDRW_BANK_ADDR_WIDTH(x) (((x) & 0x00003c00) >> 10) #define S10_MPFE_DDR(x) (0xf8000000 + x) #define S10_MPFE_HMC_ADP_DDRCALSTAT 0xf801100c #define S10_MPFE_DDR_MAIN_SCHED 0xf8000400 #define S10_MPFE_DDR_MAIN_SCHED_DDRCONF 0xf8000408 #define S10_MPFE_DDR_MAIN_SCHED_DDRTIMING 0xf800040c #define S10_MPFE_DDR_MAIN_SCHED_DDRCONF_SET_MSK 0x0000001f #define S10_MPFE_DDR_MAIN_SCHED_DDRMODE 0xf8000410 #define S10_MPFE_DDR_MAIN_SCHED_DEVTODEV 0xf800043c #define S10_MPFE_DDR_MAIN_SCHED_READLATENCY 0xf8000414 #define S10_MPFE_DDR_MAIN_SCHED_ACTIVATE 0xf8000438 #define S10_MPFE_DDR_MAIN_SCHED_ACTIVATE_FAWBANK_OFST 10 #define S10_MPFE_DDR_MAIN_SCHED_ACTIVATE_FAW_OFST 4 #define S10_MPFE_DDR_MAIN_SCHED_ACTIVATE_RRD_OFST 0 #define S10_MPFE_DDR_MAIN_SCHED_DDRCONF_SET(x) (((x) << 0) & 0x0000001f) #define S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTORD_OFST 0 #define S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTORD_MSK (BIT(0) | BIT(1)) #define S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTOWR_OFST 2 #define S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTOWR_MSK (BIT(2) | BIT(3)) #define S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSWRTORD_OFST 4 #define S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSWRTORD_MSK (BIT(4) | BIT(5)) #define S10_MPFE_HMC_ADP(x) (0xf8011000 + (x)) #define S10_MPFE_HMC_ADP_HPSINTFCSEL 0xf8011210 #define S10_MPFE_HMC_ADP_DDRIOCTRL 0xf8011008 #define HMC_ADP_DDRIOCTRL 0x8 #define HMC_ADP_DDRIOCTRL_IO_SIZE(x) (((x) & 0x00000003) >> 0) #define HMC_ADP_DDRIOCTRL_CTRL_BURST_LENGTH(x) (((x) & 0x00003e00) >> 9) #define ADP_DRAMADDRWIDTH 0xe0 #define ACT_TO_ACT_DIFF_BANK(value) (((value) & 0x00fc0000) >> 18) #define ACT_TO_ACT(value) (((value) & 0x0003f000) >> 12) #define ACT_TO_RDWR(value) (((value) & 0x0000003f) >> 0) #define ACT_TO_ACT(value) (((value) & 0x0003f000) >> 12) /* timing 2 */ #define RD_TO_RD_DIFF_CHIP(value) (((value) & 0x00000fc0) >> 6) #define RD_TO_WR_DIFF_CHIP(value) (((value) & 0x3f000000) >> 24) #define RD_TO_WR(value) (((value) & 0x00fc0000) >> 18) #define RD_TO_PCH(value) (((value) & 0x00000fc0) >> 6) /* timing 3 */ #define CALTIMING3_WR_TO_RD_DIFF_CHIP(value) (((value) & 0x0003f000) >> 12) #define CALTIMING3_WR_TO_RD(value) (((value) & 0x00000fc0) >> 6) /* timing 4 */ #define PCH_TO_VALID(value) (((value) & 0x00000fc0) >> 6) #define DDRTIMING_BWRATIO_OFST 31 #define DDRTIMING_WRTORD_OFST 26 #define DDRTIMING_RDTOWR_OFST 21 #define DDRTIMING_BURSTLEN_OFST 18 #define DDRTIMING_WRTOMISS_OFST 12 #define DDRTIMING_RDTOMISS_OFST 6 #define DDRTIMING_ACTTOACT_OFST 0 #define ADP_DDRIOCTRL_IO_SIZE(x) (((x) & 0x00000003) >> 0) #define DDRMODE_AUTOPRECHARGE_OFST 1 #define DDRMODE_BWRATIOEXTENDED_OFST 0 #define S10_MPFE_IOHMC_REG_DRAMTIMING0_CFG_TCL(x) (((x) & 0x0000007f) >> 0) #define S10_MPFE_IOHMC_REG_CTRLCFG0_CFG_MEM_TYPE(x) (((x) & 0x0000000f) >> 0) #define S10_CCU_CPU0_MPRT_DDR 0xf7004400 #define S10_CCU_CPU0_MPRT_MEM0 0xf70045c0 #define S10_CCU_CPU0_MPRT_MEM1A 0xf70045e0 #define S10_CCU_CPU0_MPRT_MEM1B 0xf7004600 #define S10_CCU_CPU0_MPRT_MEM1C 0xf7004620 #define S10_CCU_CPU0_MPRT_MEM1D 0xf7004640 #define S10_CCU_CPU0_MPRT_MEM1E 0xf7004660 #define S10_CCU_IOM_MPRT_MEM0 0xf7018560 #define S10_CCU_IOM_MPRT_MEM1A 0xf7018580 #define S10_CCU_IOM_MPRT_MEM1B 0xf70185a0 #define S10_CCU_IOM_MPRT_MEM1C 0xf70185c0 #define S10_CCU_IOM_MPRT_MEM1D 0xf70185e0 #define S10_CCU_IOM_MPRT_MEM1E 0xf7018600 #define S10_NOC_FW_DDR_SCR 0xf8020100 #define S10_NOC_FW_DDR_SCR_MPUREGION0ADDR_LIMITEXT 0xf802011c #define S10_NOC_FW_DDR_SCR_MPUREGION0ADDR_LIMIT 0xf8020118 #define S10_NOC_FW_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT 0xf802019c #define S10_NOC_FW_DDR_SCR_NONMPUREGION0ADDR_LIMIT 0xf8020198 #define S10_SOC_NOC_FW_DDR_SCR_ENABLE 0xf8020100 #define S10_CCU_NOC_DI_SET_MSK 0x10 #define S10_SYSMGR_CORE_HMC_CLK 0xffd120b4 #define S10_SYSMGR_CORE_HMC_CLK_STATUS 0x00000001 #define S10_MPFE_IOHMC_NIOSRESERVE0_NIOS_RESERVE0(x) (((x) & 0x0000ffff) >> 0) #define S10_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE_MSK 0x00000003 #define S10_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE_OFST 0 #define S10_MPFE_HMC_ADP_HPSINTFCSEL_ENABLE 0x001f1f1f #define S10_IOHMC_CTRLCFG1_ENABLE_ECC_OFST 7 #define S10_MPFE_HMC_ADP_ECCCTRL1_AUTOWB_CNT_RST_SET_MSK 0x00010000 #define S10_MPFE_HMC_ADP_ECCCTRL1_CNT_RST_SET_MSK 0x00000100 #define S10_MPFE_HMC_ADP_ECCCTRL1_ECC_EN_SET_MSK 0x00000001 #define S10_MPFE_HMC_ADP_ECCCTRL2_AUTOWB_EN_SET_MSK 0x00000001 #define S10_MPFE_HMC_ADP_ECCCTRL2_OVRW_RB_ECC_EN_SET_MSK 0x00010000 #define S10_MPFE_HMC_ADP_ECCCTRL2_RMW_EN_SET_MSK 0x00000100 #define S10_MPFE_HMC_ADP_DDRCALSTAT_CAL(value) (((value) & 0x00000001) >> 0) #define S10_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE(x) (((x) & 0x00000003) >> 0) #define IOHMC_DRAMADDRW_CFG_BANK_ADDR_WIDTH(x) (((x) & 0x00003c00) >> 10) #define IOHMC_DRAMADDRW_CFG_BANK_GROUP_ADDR_WIDTH(x) (((x) & 0x0000c000) >> 14) #define IOHMC_DRAMADDRW_CFG_COL_ADDR_WIDTH(x) (((x) & 0x0000001f) >> 0) #define IOHMC_DRAMADDRW_CFG_CS_ADDR_WIDTH(x) (((x) & 0x00070000) >> 16) #define IOHMC_DRAMADDRW_CFG_ROW_ADDR_WIDTH(x) (((x) & 0x000003e0) >> 5) #define S10_SDRAM_0_LB_ADDR 0x0 int init_hard_memory_controller(void); #endif trusted-firmware-a-2.2/plat/intel/soc/stratix10/include/s10_noc.h000066400000000000000000000046521355360272700246540ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #define AXI_AP (1<<0) #define FPGA2SOC (1<<16) #define MPU (1<<24) #define S10_NOC_PER_SCR_NAND 0xffd21000 #define S10_NOC_PER_SCR_NAND_DATA 0xffd21004 #define S10_NOC_PER_SCR_USB0 0xffd2100c #define S10_NOC_PER_SCR_USB1 0xffd21010 #define S10_NOC_PER_SCR_SPI_M0 0xffd2101c #define S10_NOC_PER_SCR_SPI_M1 0xffd21020 #define S10_NOC_PER_SCR_SPI_S0 0xffd21024 #define S10_NOC_PER_SCR_SPI_S1 0xffd21028 #define S10_NOC_PER_SCR_EMAC0 0xffd2102c #define S10_NOC_PER_SCR_EMAC1 0xffd21030 #define S10_NOC_PER_SCR_EMAC2 0xffd21034 #define S10_NOC_PER_SCR_SDMMC 0xffd21040 #define S10_NOC_PER_SCR_GPIO0 0xffd21044 #define S10_NOC_PER_SCR_GPIO1 0xffd21048 #define S10_NOC_PER_SCR_I2C0 0xffd21050 #define S10_NOC_PER_SCR_I2C1 0xffd21058 #define S10_NOC_PER_SCR_I2C2 0xffd2105c #define S10_NOC_PER_SCR_I2C3 0xffd21060 #define S10_NOC_PER_SCR_SP_TIMER0 0xffd21064 #define S10_NOC_PER_SCR_SP_TIMER1 0xffd21068 #define S10_NOC_PER_SCR_UART0 0xffd2106c #define S10_NOC_PER_SCR_UART1 0xffd21070 #define S10_NOC_SYS_SCR_DMA_ECC 0xffd21108 #define S10_NOC_SYS_SCR_EMAC0RX_ECC 0xffd2110c #define S10_NOC_SYS_SCR_EMAC0TX_ECC 0xffd21110 #define S10_NOC_SYS_SCR_EMAC1RX_ECC 0xffd21114 #define S10_NOC_SYS_SCR_EMAC1TX_ECC 0xffd21118 #define S10_NOC_SYS_SCR_EMAC2RX_ECC 0xffd2111c #define S10_NOC_SYS_SCR_EMAC2TX_ECC 0xffd21120 #define S10_NOC_SYS_SCR_NAND_ECC 0xffd2112c #define S10_NOC_SYS_SCR_NAND_READ_ECC 0xffd21130 #define S10_NOC_SYS_SCR_NAND_WRITE_ECC 0xffd21134 #define S10_NOC_SYS_SCR_OCRAM_ECC 0xffd21138 #define S10_NOC_SYS_SCR_SDMMC_ECC 0xffd21140 #define S10_NOC_SYS_SCR_USB0_ECC 0xffd21144 #define S10_NOC_SYS_SCR_USB1_ECC 0xffd21148 #define S10_NOC_SYS_SCR_CLK_MGR 0xffd2114c #define S10_NOC_SYS_SCR_IO_MGR 0xffd21154 #define S10_NOC_SYS_SCR_RST_MGR 0xffd21158 #define S10_NOC_SYS_SCR_SYS_MGR 0xffd2115c #define S10_NOC_SYS_SCR_OSC0_TIMER 0xffd21160 #define S10_NOC_SYS_SCR_OSC1_TIMER 0xffd21164 #define S10_NOC_SYS_SCR_WATCHDOG0 0xffd21168 #define S10_NOC_SYS_SCR_WATCHDOG1 0xffd2116c #define S10_NOC_SYS_SCR_WATCHDOG2 0xffd21170 #define S10_NOC_SYS_SCR_WATCHDOG3 0xffd21174 #define S10_NOC_SYS_SCR_DAP 0xffd21178 #define S10_NOC_SYS_SCR_L4_NOC_PROBES 0xffd21190 #define S10_NOC_SYS_SCR_L4_NOC_QOS 0xffd21194 #define S10_CCU_NOC_BRIDGE_CPU0_RAM 0xf7004688 #define S10_CCU_NOC_BRIDGE_IOM_RAM 0xf7004688 trusted-firmware-a-2.2/plat/intel/soc/stratix10/include/s10_pinmux.h000066400000000000000000000006321355360272700254070ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __S10_PINMUX_H__ #define __S10_PINMUX_H__ #define S10_PINMUX_PIN0SEL 0xffd13000 #define S10_PINMUX_IO0CTRL 0xffd13130 #define S10_PINMUX_PINMUX_EMAC0_USEFPGA 0xffd13300 #define S10_PINMUX_IO0_DELAY 0xffd13400 #include "s10_handoff.h" void config_pinmux(handoff *handoff); #endif trusted-firmware-a-2.2/plat/intel/soc/stratix10/include/s10_reset_manager.h000066400000000000000000000070631355360272700267100ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __S10_RESETMANAGER_H__ #define __S10_RESETMANAGER_H__ #define S10_RSTMGR_PER0MODRST 0xffd11024 #define S10_RSTMGR_PER1MODRST 0xffd11028 #define S10_RSTMGR_HDSKEN 0xffd11010 #define S10_RSTMGR_PER0MODRST_EMAC0 0x00000001 #define S10_RSTMGR_PER0MODRST_EMAC1 0x00000002 #define S10_RSTMGR_PER0MODRST_EMAC2 0x00000004 #define S10_RSTMGR_PER0MODRST_EMAC0OCP 0x00000100 #define S10_RSTMGR_PER0MODRST_EMAC1OCP 0x00000200 #define S10_RSTMGR_PER0MODRST_DMAOCP 0x00200000 #define S10_RSTMGR_PER0MODRST_DMA 0x00010000 #define S10_RSTMGR_PER0MODRST_EMAC0 0x00000001 #define S10_RSTMGR_PER0MODRST_EMAC1 0x00000002 #define S10_RSTMGR_PER0MODRST_EMAC2OCP 0x00000400 #define S10_RSTMGR_PER0MODRST_EMAC2 0x00000004 #define S10_RSTMGR_PER0MODRST_EMACPTP 0x00400000 #define S10_RSTMGR_PER0MODRST_NANDOCP 0x00002000 #define S10_RSTMGR_PER0MODRST_NAND 0x00000020 #define S10_RSTMGR_PER0MODRST_SDMMCOCP 0x00008000 #define S10_RSTMGR_PER0MODRST_SDMMC 0x00000080 #define S10_RSTMGR_PER0MODRST_SPIM0 0x00020000 #define S10_RSTMGR_PER0MODRST_SPIM1 0x00040000 #define S10_RSTMGR_PER0MODRST_SPIS0 0x00080000 #define S10_RSTMGR_PER0MODRST_SPIS1 0x00100000 #define S10_RSTMGR_PER0MODRST_USB0OCP 0x00000800 #define S10_RSTMGR_PER0MODRST_USB0 0x00000008 #define S10_RSTMGR_PER0MODRST_USB1OCP 0x00001000 #define S10_RSTMGR_PER0MODRST_USB1 0x00000010 #define S10_RSTMGR_PER1MODRST_WATCHDOG0 0x1 #define S10_RSTMGR_PER1MODRST_WATCHDOG1 0x2 #define S10_RSTMGR_PER1MODRST_WATCHDOG2 0x4 #define S10_RSTMGR_PER1MODRST_WATCHDOG3 0x8 #define S10_RSTMGR_PER1MODRST_GPIO0 0x01000000 #define S10_RSTMGR_PER1MODRST_GPIO0 0x01000000 #define S10_RSTMGR_PER1MODRST_GPIO1 0x02000000 #define S10_RSTMGR_PER1MODRST_GPIO1 0x02000000 #define S10_RSTMGR_PER1MODRST_I2C0 0x00000100 #define S10_RSTMGR_PER1MODRST_I2C0 0x00000100 #define S10_RSTMGR_PER1MODRST_I2C1 0x00000200 #define S10_RSTMGR_PER1MODRST_I2C1 0x00000200 #define S10_RSTMGR_PER1MODRST_I2C2 0x00000400 #define S10_RSTMGR_PER1MODRST_I2C2 0x00000400 #define S10_RSTMGR_PER1MODRST_I2C3 0x00000800 #define S10_RSTMGR_PER1MODRST_I2C3 0x00000800 #define S10_RSTMGR_PER1MODRST_I2C4 0x00001000 #define S10_RSTMGR_PER1MODRST_I2C4 0x00001000 #define S10_RSTMGR_PER1MODRST_L4SYSTIMER0 0x00000010 #define S10_RSTMGR_PER1MODRST_L4SYSTIMER1 0x00000020 #define S10_RSTMGR_PER1MODRST_SPTIMER0 0x00000040 #define S10_RSTMGR_PER1MODRST_SPTIMER0 0x00000040 #define S10_RSTMGR_PER1MODRST_SPTIMER1 0x00000080 #define S10_RSTMGR_PER1MODRST_SPTIMER1 0x00000080 #define S10_RSTMGR_PER1MODRST_UART0 0x00010000 #define S10_RSTMGR_PER1MODRST_UART0 0x00010000 #define S10_RSTMGR_PER1MODRST_UART1 0x00020000 #define S10_RSTMGR_PER1MODRST_UART1 0x00020000 #define S10_RSTMGR_HDSKEN_DEBUG_L3NOC 0x00020000 #define S10_RSTMGR_HDSKEN_ETRSTALLEN 0x00000008 #define S10_RSTMGR_HDSKEN_FPGAHSEN 0x00000004 #define S10_RSTMGR_HDSKEN_L2FLUSHEN 0x00000100 #define S10_RSTMGR_HDSKEN_L3NOC_DBG 0x00010000 #define S10_RSTMGR_HDSKEN_SDRSELFREFEN 0x00000001 #define S10_RSTMGR_PER0MODRST_DMAIF0 0x01000000 #define S10_RSTMGR_PER0MODRST_DMAIF1 0x02000000 #define S10_RSTMGR_PER0MODRST_DMAIF2 0x04000000 #define S10_RSTMGR_PER0MODRST_DMAIF3 0x08000000 #define S10_RSTMGR_PER0MODRST_DMAIF4 0x10000000 #define S10_RSTMGR_PER0MODRST_DMAIF5 0x20000000 #define S10_RSTMGR_PER0MODRST_DMAIF6 0x40000000 #define S10_RSTMGR_PER0MODRST_DMAIF7 0x80000000 void deassert_peripheral_reset(void); void config_hps_hs_before_warm_reset(void); #endif trusted-firmware-a-2.2/plat/intel/soc/stratix10/include/s10_system_manager.h000066400000000000000000000060511355360272700271060ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #define S10_NOC_FW_L4_PER_SCR_NAND_REGISTER 0xffd21000 #define S10_NOC_FW_L4_PER_SCR_NAND_DATA 0xffd21004 #define S10_NOC_FW_L4_PER_SCR_USB0_REGISTER 0xffd2100c #define S10_NOC_FW_L4_PER_SCR_USB1_REGISTER 0xffd21010 #define S10_NOC_FW_L4_PER_SCR_SPI_MASTER0 0xffd2101c #define S10_NOC_FW_L4_PER_SCR_SPI_MASTER1 0xffd21020 #define S10_NOC_FW_L4_PER_SCR_SPI_SLAVE0 0xffd21024 #define S10_NOC_FW_L4_PER_SCR_SPI_SLAVE1 0xffd21028 #define S10_NOC_FW_L4_PER_SCR_EMAC0 0xffd2102c #define S10_NOC_FW_L4_PER_SCR_EMAC1 0xffd21030 #define S10_NOC_FW_L4_PER_SCR_EMAC2 0xffd21034 #define S10_NOC_FW_L4_PER_SCR_SDMMC 0xffd21040 #define S10_NOC_FW_L4_PER_SCR_GPIO0 0xffd21044 #define S10_NOC_FW_L4_PER_SCR_GPIO1 0xffd21048 #define S10_NOC_FW_L4_PER_SCR_I2C0 0xffd21050 #define S10_NOC_FW_L4_PER_SCR_I2C1 0xffd21054 #define S10_NOC_FW_L4_PER_SCR_I2C2 0xffd21058 #define S10_NOC_FW_L4_PER_SCR_I2C3 0xffd2105c #define S10_NOC_FW_L4_PER_SCR_I2C4 0xffd21060 #define S10_NOC_FW_L4_PER_SCR_SP_TIMER0 0xffd21064 #define S10_NOC_FW_L4_PER_SCR_SP_TIMER1 0xffd21068 #define S10_NOC_FW_L4_PER_SCR_UART0 0xffd2106c #define S10_NOC_FW_L4_PER_SCR_UART1 0xffd21070 #define S10_NOC_FW_L4_SYS_SCR_DMA_ECC 0xffd21108 #define S10_NOC_FW_L4_SYS_SCR_EMAC0RX_ECC 0xffd2110c #define S10_NOC_FW_L4_SYS_SCR_EMAC0TX_ECC 0xffd21110 #define S10_NOC_FW_L4_SYS_SCR_EMAC1RX_ECC 0xffd21114 #define S10_NOC_FW_L4_SYS_SCR_EMAC1TX_ECC 0xffd21118 #define S10_NOC_FW_L4_SYS_SCR_EMAC2RX_ECC 0xffd2111c #define S10_NOC_FW_L4_SYS_SCR_EMAC2TX_ECC 0xffd21120 #define S10_NOC_FW_L4_SYS_SCR_NAND_ECC 0xffd2112c #define S10_NOC_FW_L4_SYS_SCR_NAND_READ_ECC 0xffd21130 #define S10_NOC_FW_L4_SYS_SCR_NAND_WRITE_ECC 0xffd21134 #define S10_NOC_FW_L4_SYS_SCR_OCRAM_ECC 0xffd21138 #define S10_NOC_FW_L4_SYS_SCR_SDMMC_ECC 0xffd21140 #define S10_NOC_FW_L4_SYS_SCR_USB0_ECC 0xffd21144 #define S10_NOC_FW_L4_SYS_SCR_USB1_ECC 0xffd21148 #define S10_NOC_FW_L4_SYS_SCR_CLK_MGR 0xffd2114c #define S10_NOC_FW_L4_SYS_SCR_IO_MGR 0xffd21154 #define S10_NOC_FW_L4_SYS_SCR_RST_MGR 0xffd21158 #define S10_NOC_FW_L4_SYS_SCR_SYS_MGR 0xffd2115c #define S10_NOC_FW_L4_SYS_SCR_OSC0_TIMER 0xffd21160 #define S10_NOC_FW_L4_SYS_SCR_OSC1_TIMER 0xffd21164 #define S10_NOC_FW_L4_SYS_SCR_WATCHDOG0 0xffd21168 #define S10_NOC_FW_L4_SYS_SCR_WATCHDOG1 0xffd2116c #define S10_NOC_FW_L4_SYS_SCR_WATCHDOG2 0xffd21170 #define S10_NOC_FW_L4_SYS_SCR_WATCHDOG3 0xffd21174 #define S10_NOC_FW_L4_SYS_SCR_DAP 0xffd21178 #define S10_NOC_FW_L4_SYS_SCR_L4_NOC_PROBES 0xffd21190 #define S10_NOC_FW_L4_SYS_SCR_L4_NOC_QOS 0xffd21194 #define S10_CCU_NOC_CPU0_RAMSPACE0_0 0xf7004688 #define S10_CCU_NOC_IOM_RAMSPACE0_0 0xf7018628 #define S10_SYSMGR_CORE(x) (0xffd12000 + (x)) #define SYSMGR_MMC 0x28 #define SYSMGR_MMC_DRVSEL(x) (((x) & 0x7) << 0) #define SYSMGR_BOOT_SCRATCH_COLD_0 0x200 #define SYSMGR_BOOT_SCRATCH_COLD_1 0x204 #define SYSMGR_BOOT_SCRATCH_COLD_2 0x208 #define DISABLE_L4_FIREWALL (BIT(0) | BIT(16) | BIT(24)) void enable_nonsecure_access(void); trusted-firmware-a-2.2/plat/intel/soc/stratix10/include/stratix10_private.h000066400000000000000000000012601355360272700267730ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __S10_PRIVATE_H__ #define __S10_PRIVATE_H__ #define S10_MMC_REG_BASE 0xff808000 #define EMMC_DESC_SIZE (1<<20) #define EMMC_INIT_PARAMS(base, clk) \ { .bus_width = MMC_BUS_WIDTH_4, \ .clk_rate = (clk), \ .desc_base = (base), \ .desc_size = EMMC_DESC_SIZE, \ .flags = 0, \ .reg_base = S10_MMC_REG_BASE, \ \ } typedef enum { BOOT_SOURCE_FPGA = 0, BOOT_SOURCE_SDMMC, BOOT_SOURCE_NAND, BOOT_SOURCE_RSVD, BOOT_SOURCE_QSPI, } boot_source_type; void enable_nonsecure_access(void); void stratix10_io_setup(int boot_source); #endif trusted-firmware-a-2.2/plat/intel/soc/stratix10/plat_psci.c000066400000000000000000000160371355360272700237400ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "platform_def.h" #include "s10_reset_manager.h" #include "s10_mailbox.h" #define S10_RSTMGR_OFST 0xffd11000 #define S10_RSTMGR_MPUMODRST_OFST 0x20 uintptr_t *stratix10_sec_entry = (uintptr_t *) PLAT_SEC_ENTRY; uintptr_t *cpuid_release = (uintptr_t *) PLAT_CPUID_RELEASE; /******************************************************************************* * plat handler called when a CPU is about to enter standby. ******************************************************************************/ void plat_cpu_standby(plat_local_state_t cpu_state) { /* * Enter standby state * dsb is good practice before using wfi to enter low power states */ VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state); dsb(); wfi(); } /******************************************************************************* * plat handler called when a power domain is about to be turned on. The * mpidr determines the CPU to be turned on. ******************************************************************************/ int plat_pwr_domain_on(u_register_t mpidr) { unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); if (cpu_id == -1) return PSCI_E_INTERN_FAIL; *cpuid_release = cpu_id; /* release core reset */ mmio_setbits_32(S10_RSTMGR_OFST + S10_RSTMGR_MPUMODRST_OFST, 1 << cpu_id); return PSCI_E_SUCCESS; } /******************************************************************************* * plat handler called when a power domain is about to be turned off. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ void plat_pwr_domain_off(const psci_power_state_t *target_state) { unsigned int cpu_id = plat_my_core_pos(); for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); /* TODO: Prevent interrupts from spuriously waking up this cpu */ /* gicv2_cpuif_disable(); */ /* assert core reset */ mmio_setbits_32(S10_RSTMGR_OFST + S10_RSTMGR_MPUMODRST_OFST, 1 << cpu_id); } /******************************************************************************* * plat handler called when a power domain is about to be suspended. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ void plat_pwr_domain_suspend(const psci_power_state_t *target_state) { unsigned int cpu_id = plat_my_core_pos(); for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); /* assert core reset */ mmio_setbits_32(S10_RSTMGR_OFST + S10_RSTMGR_MPUMODRST_OFST, 1 << cpu_id); } /******************************************************************************* * plat handler called when a power domain has just been powered on after * being turned off earlier. The target_state encodes the low power state that * each level has woken up from. ******************************************************************************/ void plat_pwr_domain_on_finish(const psci_power_state_t *target_state) { for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); /* Program the gic per-cpu distributor or re-distributor interface */ gicv2_pcpu_distif_init(); gicv2_set_pe_target_mask(plat_my_core_pos()); /* Enable the gic cpu interface */ gicv2_cpuif_enable(); } /******************************************************************************* * plat handler called when a power domain has just been powered on after * having been suspended earlier. The target_state encodes the low power state * that each level has woken up from. * TODO: At the moment we reuse the on finisher and reinitialize the secure * context. Need to implement a separate suspend finisher. ******************************************************************************/ void plat_pwr_domain_suspend_finish(const psci_power_state_t *target_state) { unsigned int cpu_id = plat_my_core_pos(); for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); /* release core reset */ mmio_clrbits_32(S10_RSTMGR_OFST + S10_RSTMGR_MPUMODRST_OFST, 1 << cpu_id); } /******************************************************************************* * plat handlers to shutdown/reboot the system ******************************************************************************/ static void __dead2 plat_system_off(void) { wfi(); ERROR("System Off: operation not handled.\n"); panic(); } static void __dead2 plat_system_reset(void) { INFO("assert Peripheral from Reset\r\n"); deassert_peripheral_reset(); mailbox_reset_cold(); while (1) wfi(); } int plat_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); return PSCI_E_SUCCESS; } int plat_validate_ns_entrypoint(unsigned long ns_entrypoint) { VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint); return PSCI_E_SUCCESS; } void plat_get_sys_suspend_power_state(psci_power_state_t *req_state) { req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE; req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE; } /******************************************************************************* * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard * platform layer will take care of registering the handlers with PSCI. ******************************************************************************/ const plat_psci_ops_t plat_psci_pm_ops = { .cpu_standby = plat_cpu_standby, .pwr_domain_on = plat_pwr_domain_on, .pwr_domain_off = plat_pwr_domain_off, .pwr_domain_suspend = plat_pwr_domain_suspend, .pwr_domain_on_finish = plat_pwr_domain_on_finish, .pwr_domain_suspend_finish = plat_pwr_domain_suspend_finish, .system_off = plat_system_off, .system_reset = plat_system_reset, .validate_power_state = plat_validate_power_state, .validate_ns_entrypoint = plat_validate_ns_entrypoint, .get_sys_suspend_power_state = plat_get_sys_suspend_power_state }; /******************************************************************************* * Export the platform specific power ops. ******************************************************************************/ int plat_setup_psci_ops(uintptr_t sec_entrypoint, const struct plat_psci_ops **psci_ops) { /* Save warm boot entrypoint.*/ *stratix10_sec_entry = sec_entrypoint; *psci_ops = &plat_psci_pm_ops; return 0; } trusted-firmware-a-2.2/plat/intel/soc/stratix10/plat_sip_svc.c000066400000000000000000000210001355360272700244320ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* Number of SiP Calls implemented */ #define SIP_NUM_CALLS 0x3 /* Total buffer the driver can hold */ #define FPGA_CONFIG_BUFFER_SIZE 4 int current_block; int current_buffer; int current_id = 1; int max_blocks; uint32_t bytes_per_block; uint32_t blocks_submitted; uint32_t blocks_completed; struct fpga_config_info { uint32_t addr; int size; int size_written; uint32_t write_requested; int subblocks_sent; int block_number; }; /* SiP Service UUID */ DEFINE_SVC_UUID2(intl_svc_uid, 0xa85273b0, 0xe85a, 0x4862, 0xa6, 0x2a, 0xfa, 0x88, 0x88, 0x17, 0x68, 0x81); uint64_t plat_sip_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, void *cookie, void *handle, uint64_t flags) { ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); SMC_RET1(handle, SMC_UNK); } struct fpga_config_info fpga_config_buffers[FPGA_CONFIG_BUFFER_SIZE]; static void intel_fpga_sdm_write_buffer(struct fpga_config_info *buffer) { uint32_t args[3]; while (max_blocks > 0 && buffer->size > buffer->size_written) { if (buffer->size - buffer->size_written <= bytes_per_block) { args[0] = (1<<8); args[1] = buffer->addr + buffer->size_written; args[2] = buffer->size - buffer->size_written; buffer->size_written += buffer->size - buffer->size_written; buffer->subblocks_sent++; mailbox_send_cmd_async(0x4, MBOX_RECONFIG_DATA, args, 3, 0); current_buffer++; current_buffer %= FPGA_CONFIG_BUFFER_SIZE; } else { args[0] = (1<<8); args[1] = buffer->addr + buffer->size_written; args[2] = bytes_per_block; buffer->size_written += bytes_per_block; mailbox_send_cmd_async(0x4, MBOX_RECONFIG_DATA, args, 3, 0); buffer->subblocks_sent++; } max_blocks--; } } static int intel_fpga_sdm_write_all(void) { int i; for (i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) intel_fpga_sdm_write_buffer( &fpga_config_buffers[current_buffer]); return 0; } uint32_t intel_mailbox_fpga_config_isdone(void) { uint32_t args[2]; uint32_t response[6]; int status; status = mailbox_send_cmd(1, MBOX_RECONFIG_STATUS, args, 0, 0, response); if (status < 0) return INTEL_SIP_SMC_STATUS_ERROR; if (response[RECONFIG_STATUS_STATE] && response[RECONFIG_STATUS_STATE] != MBOX_CFGSTAT_STATE_CONFIG) return INTEL_SIP_SMC_STATUS_ERROR; if (!(response[RECONFIG_STATUS_PIN_STATUS] & PIN_STATUS_NSTATUS)) return INTEL_SIP_SMC_STATUS_ERROR; if (response[RECONFIG_STATUS_SOFTFUNC_STATUS] & SOFTFUNC_STATUS_SEU_ERROR) return INTEL_SIP_SMC_STATUS_ERROR; if ((response[RECONFIG_STATUS_SOFTFUNC_STATUS] & SOFTFUNC_STATUS_CONF_DONE) && (response[RECONFIG_STATUS_SOFTFUNC_STATUS] & SOFTFUNC_STATUS_INIT_DONE)) return INTEL_SIP_SMC_STATUS_OK; return INTEL_SIP_SMC_STATUS_ERROR; } static int mark_last_buffer_xfer_completed(uint32_t *buffer_addr_completed) { int i; for (i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) { if (fpga_config_buffers[i].block_number == current_block) { fpga_config_buffers[i].subblocks_sent--; if (fpga_config_buffers[i].subblocks_sent == 0 && fpga_config_buffers[i].size <= fpga_config_buffers[i].size_written) { fpga_config_buffers[i].write_requested = 0; current_block++; *buffer_addr_completed = fpga_config_buffers[i].addr; return 0; } } } return -1; } unsigned int address_in_ddr(uint32_t *addr) { if (((unsigned long long)addr > DRAM_BASE) && ((unsigned long long)addr < DRAM_BASE + DRAM_SIZE)) return 0; return -1; } int intel_fpga_config_completed_write(uint32_t *completed_addr, uint32_t *count) { uint32_t status = INTEL_SIP_SMC_STATUS_OK; *count = 0; int resp_len = 0; uint32_t resp[5]; int all_completed = 1; int count_check = 0; if (address_in_ddr(completed_addr) != 0 || address_in_ddr(count) != 0) return INTEL_SIP_SMC_STATUS_ERROR; for (count_check = 0; count_check < 3; count_check++) if (address_in_ddr(&completed_addr[*count + count_check]) != 0) return INTEL_SIP_SMC_STATUS_ERROR; resp_len = mailbox_read_response(0x4, resp); while (resp_len >= 0 && *count < 3) { max_blocks++; if (mark_last_buffer_xfer_completed( &completed_addr[*count]) == 0) *count = *count + 1; else break; resp_len = mailbox_read_response(0x4, resp); } if (*count <= 0) { if (resp_len != MBOX_NO_RESPONSE && resp_len != MBOX_TIMEOUT && resp_len != 0) { return INTEL_SIP_SMC_STATUS_ERROR; } *count = 0; } intel_fpga_sdm_write_all(); if (*count > 0) status = INTEL_SIP_SMC_STATUS_OK; else if (*count == 0) status = INTEL_SIP_SMC_STATUS_BUSY; for (int i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) { if (fpga_config_buffers[i].write_requested != 0) { all_completed = 0; break; } } if (all_completed == 1) return INTEL_SIP_SMC_STATUS_OK; return status; } int intel_fpga_config_start(uint32_t config_type) { uint32_t response[3]; int status = 0; status = mailbox_send_cmd(2, MBOX_RECONFIG, 0, 0, 0, response); if (status < 0) return status; max_blocks = response[0]; bytes_per_block = response[1]; for (int i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) { fpga_config_buffers[i].size = 0; fpga_config_buffers[i].size_written = 0; fpga_config_buffers[i].addr = 0; fpga_config_buffers[i].write_requested = 0; fpga_config_buffers[i].block_number = 0; fpga_config_buffers[i].subblocks_sent = 0; } blocks_submitted = 0; current_block = 0; current_buffer = 0; return 0; } uint32_t intel_fpga_config_write(uint64_t mem, uint64_t size) { int i = 0; uint32_t status = INTEL_SIP_SMC_STATUS_OK; if (mem < DRAM_BASE || mem > DRAM_BASE + DRAM_SIZE) status = INTEL_SIP_SMC_STATUS_REJECTED; if (mem + size > DRAM_BASE + DRAM_SIZE) status = INTEL_SIP_SMC_STATUS_REJECTED; for (i = 0; i < FPGA_CONFIG_BUFFER_SIZE; i++) { if (!fpga_config_buffers[i].write_requested) { fpga_config_buffers[i].addr = mem; fpga_config_buffers[i].size = size; fpga_config_buffers[i].size_written = 0; fpga_config_buffers[i].write_requested = 1; fpga_config_buffers[i].block_number = blocks_submitted++; fpga_config_buffers[i].subblocks_sent = 0; break; } } if (i == FPGA_CONFIG_BUFFER_SIZE) { status = INTEL_SIP_SMC_STATUS_REJECTED; return status; } else if (i == FPGA_CONFIG_BUFFER_SIZE - 1) { status = INTEL_SIP_SMC_STATUS_BUSY; } intel_fpga_sdm_write_all(); return status; } /* * This function is responsible for handling all SiP calls from the NS world */ uintptr_t sip_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 status = INTEL_SIP_SMC_STATUS_OK; uint32_t completed_addr[3]; uint32_t count = 0; switch (smc_fid) { case SIP_SVC_UID: /* Return UID to the caller */ SMC_UUID_RET(handle, intl_svc_uid); break; case INTEL_SIP_SMC_FPGA_CONFIG_ISDONE: status = intel_mailbox_fpga_config_isdone(); SMC_RET4(handle, status, 0, 0, 0); break; case INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM: SMC_RET3(handle, INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_FPGA_CONFIG_ADDR, INTEL_SIP_SMC_FPGA_CONFIG_SIZE - INTEL_SIP_SMC_FPGA_CONFIG_ADDR); break; case INTEL_SIP_SMC_FPGA_CONFIG_START: status = intel_fpga_config_start(x1); SMC_RET4(handle, status, 0, 0, 0); break; case INTEL_SIP_SMC_FPGA_CONFIG_WRITE: status = intel_fpga_config_write(x1, x2); SMC_RET4(handle, status, 0, 0, 0); break; case INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE: status = intel_fpga_config_completed_write(completed_addr, &count); switch (count) { case 1: SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK, completed_addr[0], 0, 0); break; case 2: SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK, completed_addr[0], completed_addr[1], 0); break; case 3: SMC_RET4(handle, INTEL_SIP_SMC_STATUS_OK, completed_addr[0], completed_addr[1], completed_addr[2]); break; case 0: SMC_RET4(handle, status, 0, 0, 0); break; default: SMC_RET1(handle, INTEL_SIP_SMC_STATUS_ERROR); } break; default: return plat_sip_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); } } DECLARE_RT_SVC( s10_sip_svc, OEN_SIP_START, OEN_SIP_END, SMC_TYPE_FAST, NULL, sip_smc_handler ); DECLARE_RT_SVC( s10_sip_svc_std, OEN_SIP_START, OEN_SIP_END, SMC_TYPE_YIELD, NULL, sip_smc_handler ); trusted-firmware-a-2.2/plat/intel/soc/stratix10/plat_storage.c000066400000000000000000000106411355360272700244410ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "platform_def.h" #include "stratix10_private.h" #define STRATIX10_FIP_BASE (0) #define STRATIX10_FIP_MAX_SIZE (0x1000000) #define STRATIX10_MMC_DATA_BASE (0xffe3c000) #define STRATIX10_MMC_DATA_SIZE (0x2000) #define STRATIX10_QSPI_DATA_BASE (0x3C00000) #define STRATIX10_QSPI_DATA_SIZE (0x1000000) static const io_dev_connector_t *fip_dev_con; static const io_dev_connector_t *boot_dev_con; static uintptr_t fip_dev_handle; static uintptr_t boot_dev_handle; static const io_uuid_spec_t bl2_uuid_spec = { .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2, }; static const io_uuid_spec_t bl31_uuid_spec = { .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31, }; static const io_uuid_spec_t bl33_uuid_spec = { .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33, }; uintptr_t a2_lba_offset; const char a2[] = {0xa2, 0x0}; static const io_block_spec_t gpt_block_spec = { .offset = 0, .length = MMC_BLOCK_SIZE }; static int check_fip(const uintptr_t spec); static int check_dev(const uintptr_t spec); static io_block_dev_spec_t boot_dev_spec; static int (*register_io_dev)(const io_dev_connector_t **); static io_block_spec_t fip_spec = { .offset = STRATIX10_FIP_BASE, .length = STRATIX10_FIP_MAX_SIZE, }; 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[] = { [FIP_IMAGE_ID] = { &boot_dev_handle, (uintptr_t)&fip_spec, check_dev }, [BL2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl2_uuid_spec, check_fip }, [BL31_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl31_uuid_spec, check_fip }, [BL33_IMAGE_ID] = { &fip_dev_handle, (uintptr_t) &bl33_uuid_spec, check_fip }, [GPT_IMAGE_ID] = { &boot_dev_handle, (uintptr_t) &gpt_block_spec, check_dev }, }; static int check_dev(const uintptr_t spec) { int result; uintptr_t local_handle; result = io_dev_init(boot_dev_handle, (uintptr_t)NULL); if (result == 0) { result = io_open(boot_dev_handle, spec, &local_handle); if (result == 0) io_close(local_handle); } return result; } static int check_fip(const uintptr_t spec) { int result; uintptr_t local_image_handle; result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); if (result == 0) { result = io_open(fip_dev_handle, spec, &local_image_handle); if (result == 0) io_close(local_image_handle); } return result; } void stratix10_io_setup(int boot_source) { int result; switch (boot_source) { case BOOT_SOURCE_SDMMC: register_io_dev = ®ister_io_dev_block; boot_dev_spec.buffer.offset = STRATIX10_MMC_DATA_BASE; boot_dev_spec.buffer.length = MMC_BLOCK_SIZE; boot_dev_spec.ops.read = mmc_read_blocks; boot_dev_spec.ops.write = mmc_write_blocks; boot_dev_spec.block_size = MMC_BLOCK_SIZE; break; case BOOT_SOURCE_QSPI: register_io_dev = ®ister_io_dev_memmap; fip_spec.offset = fip_spec.offset + STRATIX10_QSPI_DATA_BASE; break; default: ERROR("Unsupported boot source\n"); panic(); break; } result = (*register_io_dev)(&boot_dev_con); assert(result == 0); result = register_io_dev_fip(&fip_dev_con); assert(result == 0); result = io_dev_open(boot_dev_con, (uintptr_t)&boot_dev_spec, &boot_dev_handle); assert(result == 0); result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle); assert(result == 0); if (boot_source == BOOT_SOURCE_SDMMC) { partition_init(GPT_IMAGE_ID); fip_spec.offset = get_partition_entry(a2)->start; } (void)result; } int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, uintptr_t *image_spec) { int result; const struct plat_io_policy *policy; assert(image_id < ARRAY_SIZE(policies)); policy = &policies[image_id]; result = policy->check(policy->image_spec); assert(result == 0); *image_spec = policy->image_spec; *dev_handle = *(policy->dev_handle); return result; } trusted-firmware-a-2.2/plat/intel/soc/stratix10/platform.mk000066400000000000000000000051501355360272700237650ustar00rootroot00000000000000# # Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # PLAT_INCLUDES := \ -Iplat/intel/soc/stratix10/include/ \ -Iplat/intel/soc/common/drivers/ \ -Iplat/intel/soc/common/include/ PLAT_BL_COMMON_SOURCES := \ lib/xlat_tables/xlat_tables_common.c \ lib/xlat_tables/aarch64/xlat_tables.c \ drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/ti/uart/aarch64/16550_console.S \ plat/intel/soc/common/aarch64/platform_common.c \ plat/intel/soc/common/aarch64/plat_helpers.S BL2_SOURCES += \ drivers/partition/partition.c \ drivers/partition/gpt.c \ drivers/arm/pl061/pl061_gpio.c \ drivers/mmc/mmc.c \ drivers/synopsys/emmc/dw_mmc.c \ drivers/io/io_storage.c \ drivers/io/io_block.c \ drivers/io/io_fip.c \ drivers/gpio/gpio.c \ drivers/intel/soc/stratix10/io/s10_memmap_qspi.c \ plat/intel/soc/stratix10/bl2_plat_setup.c \ plat/intel/soc/stratix10/plat_storage.c \ plat/intel/soc/common/bl2_plat_mem_params_desc.c \ plat/intel/soc/stratix10/soc/s10_reset_manager.c \ plat/intel/soc/stratix10/soc/s10_handoff.c \ plat/intel/soc/stratix10/soc/s10_clock_manager.c \ plat/intel/soc/stratix10/soc/s10_pinmux.c \ plat/intel/soc/stratix10/soc/s10_memory_controller.c \ plat/intel/soc/common/socfpga_delay_timer.c \ lib/cpus/aarch64/cortex_a53.S \ plat/intel/soc/common/socfpga_image_load.c \ plat/intel/soc/stratix10/soc/s10_system_manager.c \ common/desc_image_load.c \ plat/intel/soc/stratix10/soc/s10_mailbox.c \ plat/intel/soc/common/drivers/qspi/cadence_qspi.c \ plat/intel/soc/common/drivers/wdt/watchdog.c BL31_SOURCES += drivers/arm/cci/cci.c \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/aem_generic.S \ lib/cpus/aarch64/cortex_a53.S \ plat/common/plat_psci_common.c \ plat/intel/soc/stratix10/plat_sip_svc.c \ plat/intel/soc/stratix10/bl31_plat_setup.c \ plat/intel/soc/stratix10/plat_psci.c \ plat/intel/soc/common/socfpga_topology.c \ plat/intel/soc/common/socfpga_delay_timer.c \ plat/intel/soc/stratix10/soc/s10_reset_manager.c\ plat/intel/soc/stratix10/soc/s10_pinmux.c \ plat/intel/soc/stratix10/soc/s10_clock_manager.c\ plat/intel/soc/stratix10/soc/s10_handoff.c \ plat/intel/soc/stratix10/soc/s10_mailbox.c PROGRAMMABLE_RESET_ADDRESS := 0 BL2_AT_EL3 := 1 USE_COHERENT_MEM := 1 trusted-firmware-a-2.2/plat/intel/soc/stratix10/soc/000077500000000000000000000000001355360272700223735ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/intel/soc/stratix10/soc/s10_clock_manager.c000066400000000000000000000236541355360272700260210ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "s10_clock_manager.h" #include "s10_handoff.h" #include "s10_system_manager.h" void wait_pll_lock(void) { uint32_t data; do { data = mmio_read_32(ALT_CLKMGR + ALT_CLKMGR_STAT); } while ((ALT_CLKMGR_STAT_MAINPLLLOCKED(data) == 0) || (ALT_CLKMGR_STAT_PERPLLLOCKED(data) == 0)); } void wait_fsm(void) { uint32_t data; do { data = mmio_read_32(ALT_CLKMGR + ALT_CLKMGR_STAT); } while (ALT_CLKMGR_STAT_BUSY(data) == ALT_CLKMGR_STAT_BUSY_E_BUSY); } void config_clkmgr_handoff(handoff *hoff_ptr) { uint32_t m_div, refclk_div, mscnt, hscnt; /* Bypass all mainpllgrp's clocks */ mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_BYPASS, 0x7); wait_fsm(); /* Bypass all perpllgrp's clocks */ mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_BYPASS, 0x7f); wait_fsm(); /* Setup main PLL dividers */ m_div = ALT_CLKMGR_MAINPLL_FDBCK_MDIV(hoff_ptr->main_pll_fdbck); refclk_div = ALT_CLKMGR_MAINPLL_PLLGLOB_REFCLKDIV( hoff_ptr->main_pll_pllglob); mscnt = 200 / ((6 + m_div) / refclk_div); hscnt = (m_div + 6) * mscnt / refclk_div - 9; mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_PLLGLOB, hoff_ptr->main_pll_pllglob); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_FDBCK, hoff_ptr->main_pll_fdbck); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_VCOCALIB, ALT_CLKMGR_MAINPLL_VCOCALIB_HSCNT_SET(hscnt) | ALT_CLKMGR_MAINPLL_VCOCALIB_MSCNT_SET(mscnt)); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_PLLC0, hoff_ptr->main_pll_pllc0); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_PLLC1, hoff_ptr->main_pll_pllc1); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_NOCDIV, hoff_ptr->main_pll_nocdiv); /* Setup peripheral PLL dividers */ m_div = ALT_CLKMGR_PERPLL_FDBCK_MDIV(hoff_ptr->per_pll_fdbck); refclk_div = ALT_CLKMGR_PERPLL_PLLGLOB_REFCLKDIV( hoff_ptr->per_pll_pllglob); mscnt = 200 / ((6 + m_div) / refclk_div); hscnt = (m_div + 6) * mscnt / refclk_div - 9; mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_PLLGLOB, hoff_ptr->per_pll_pllglob); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_FDBCK, hoff_ptr->per_pll_fdbck); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_VCOCALIB, ALT_CLKMGR_PERPLL_VCOCALIB_HSCNT_SET(hscnt) | ALT_CLKMGR_PERPLL_VCOCALIB_MSCNT_SET(mscnt)); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_PLLC0, hoff_ptr->per_pll_pllc0); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_PLLC1, hoff_ptr->per_pll_pllc1); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_GPIODIV, ALT_CLKMGR_PERPLL_GPIODIV_GPIODBCLK_SET( hoff_ptr->per_pll_gpiodiv)); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_EMACCTL, hoff_ptr->per_pll_emacctl); /* Take both PLL out of reset and power up */ mmio_setbits_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_PLLGLOB, ALT_CLKMGR_MAINPLL_PLLGLOB_PD_SET_MSK | ALT_CLKMGR_MAINPLL_PLLGLOB_RST_SET_MSK); mmio_setbits_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_PLLGLOB, ALT_CLKMGR_PERPLL_PLLGLOB_PD_SET_MSK | ALT_CLKMGR_PERPLL_PLLGLOB_RST_SET_MSK); wait_pll_lock(); /* Dividers for C2 to C9 only init after PLLs are lock. */ mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_MPUCLK, 0xff); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_NOCCLK, 0xff); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR2CLK, 0xff); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR3CLK, 0xff); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR4CLK, 0xff); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR5CLK, 0xff); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR6CLK, 0xff); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR7CLK, 0xff); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR8CLK, 0xff); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR9CLK, 0xff); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR2CLK, 0xff); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR3CLK, 0xff); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR4CLK, 0xff); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR5CLK, 0xff); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR6CLK, 0xff); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR7CLK, 0xff); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR8CLK, 0xff); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_MPUCLK, hoff_ptr->main_pll_mpuclk); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_NOCCLK, hoff_ptr->main_pll_nocclk); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR2CLK, hoff_ptr->main_pll_cntr2clk); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR3CLK, hoff_ptr->main_pll_cntr3clk); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR4CLK, hoff_ptr->main_pll_cntr4clk); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR5CLK, hoff_ptr->main_pll_cntr5clk); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR6CLK, hoff_ptr->main_pll_cntr6clk); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR7CLK, hoff_ptr->main_pll_cntr7clk); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR8CLK, hoff_ptr->main_pll_cntr8clk); mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR9CLK, hoff_ptr->main_pll_cntr9clk); /* Peripheral PLL Clock Source and Counters/Divider */ mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR2CLK, hoff_ptr->per_pll_cntr2clk); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR3CLK, hoff_ptr->per_pll_cntr3clk); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR4CLK, hoff_ptr->per_pll_cntr4clk); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR5CLK, hoff_ptr->per_pll_cntr5clk); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR6CLK, hoff_ptr->per_pll_cntr6clk); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR7CLK, hoff_ptr->per_pll_cntr7clk); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR8CLK, hoff_ptr->per_pll_cntr8clk); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_CNTR9CLK, hoff_ptr->per_pll_cntr9clk); /* Take all PLLs out of bypass */ mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_BYPASS, 0); wait_fsm(); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_BYPASS, 0); wait_fsm(); /* Set safe mode/ out of boot mode */ mmio_clrbits_32(ALT_CLKMGR + ALT_CLKMGR_CTRL, ALT_CLKMGR_CTRL_BOOTMODE_SET_MSK); wait_fsm(); /* 10 Enable mainpllgrp's software-managed clock */ mmio_write_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_EN, ALT_CLKMGR_MAINPLL_EN_RESET); mmio_write_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_EN, ALT_CLKMGR_PERPLL_EN_RESET); /* Clear loss lock interrupt status register that */ /* might be set during configuration */ mmio_write_32(ALT_CLKMGR + ALT_CLKMGR_INTRCLR, ALT_CLKMGR_INTRCLR_MAINLOCKLOST_SET_MSK | ALT_CLKMGR_INTRCLR_PERLOCKLOST_SET_MSK); /* Pass clock source frequency into scratch register */ mmio_write_32(S10_SYSMGR_CORE(SYSMGR_BOOT_SCRATCH_COLD_1), hoff_ptr->hps_osc_clk_h); mmio_write_32(S10_SYSMGR_CORE(SYSMGR_BOOT_SCRATCH_COLD_2), hoff_ptr->fpga_clk_hz); } /* Extract reference clock from platform clock source */ uint32_t get_ref_clk(uint32_t pllglob) { uint32_t data32, mdiv, refclkdiv, ref_clk; uint32_t scr_reg; switch (ALT_CLKMGR_PSRC(pllglob)) { case ALT_CLKMGR_PLLGLOB_PSRC_EOSC1: scr_reg = S10_SYSMGR_CORE(SYSMGR_BOOT_SCRATCH_COLD_1); ref_clk = mmio_read_32(scr_reg); break; case ALT_CLKMGR_PLLGLOB_PSRC_INTOSC: ref_clk = ALT_CLKMGR_INTOSC_HZ; break; case ALT_CLKMGR_PLLGLOB_PSRC_F2S: scr_reg = S10_SYSMGR_CORE(SYSMGR_BOOT_SCRATCH_COLD_2); ref_clk = mmio_read_32(scr_reg); break; default: ref_clk = 0; assert(0); break; } refclkdiv = ALT_CLKMGR_MAINPLL_PLLGLOB_REFCLKDIV(pllglob); data32 = mmio_read_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_FDBCK); mdiv = ALT_CLKMGR_MAINPLL_FDBCK_MDIV(data32); ref_clk = (ref_clk / refclkdiv) * (6 + mdiv); return ref_clk; } /* Calculate L3 interconnect main clock */ uint32_t get_l3_clk(uint32_t ref_clk) { uint32_t noc_base_clk, l3_clk, noc_clk, data32; uint32_t pllc1_reg; noc_clk = mmio_read_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_NOCCLK); switch (ALT_CLKMGR_PSRC(noc_clk)) { case ALT_CLKMGR_SRC_MAIN: pllc1_reg = ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_PLLC1; break; case ALT_CLKMGR_SRC_PER: pllc1_reg = ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_PLLC1; break; default: pllc1_reg = 0; assert(0); break; } data32 = mmio_read_32(pllc1_reg); noc_base_clk = ref_clk / (data32 & 0xff); l3_clk = noc_base_clk / (noc_clk + 1); return l3_clk; } /* Calculate clock frequency to be used for watchdog timer */ uint32_t get_wdt_clk(void) { uint32_t data32, ref_clk, l3_clk, l4_sys_clk; data32 = mmio_read_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_PLLGLOB); ref_clk = get_ref_clk(data32); l3_clk = get_l3_clk(ref_clk); l4_sys_clk = l3_clk / 4; return l4_sys_clk; } /* Calculate clock frequency to be used for UART driver */ uint32_t get_uart_clk(void) { uint32_t data32, ref_clk, l3_clk, l4_sp_clk; data32 = mmio_read_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_PLLGLOB); ref_clk = get_ref_clk(data32); l3_clk = get_l3_clk(ref_clk); data32 = mmio_read_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_NOCDIV); data32 = (data32 >> 16) & 0x3; data32 = 1 << data32; l4_sp_clk = (l3_clk / data32); return l4_sp_clk; } /* Calculate clock frequency to be used for SDMMC driver */ uint32_t get_mmc_clk(void) { uint32_t data32, ref_clk, l3_clk, mmc_clk; data32 = mmio_read_32(ALT_CLKMGR_PERPLL + ALT_CLKMGR_PERPLL_PLLGLOB); ref_clk = get_ref_clk(data32); l3_clk = get_l3_clk(ref_clk); data32 = mmio_read_32(ALT_CLKMGR_MAINPLL + ALT_CLKMGR_MAINPLL_CNTR6CLK); mmc_clk = (l3_clk / (data32 + 1)) / 4; return mmc_clk; } trusted-firmware-a-2.2/plat/intel/soc/stratix10/soc/s10_handoff.c000066400000000000000000000023351355360272700246320ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "s10_handoff.h" #define SWAP_UINT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | \ (((x) & 0x0000FF00) << 8) | ((x) << 24)) int s10_get_handoff(handoff *reverse_hoff_ptr) { int i; uint32_t *buffer; handoff *handoff_ptr = (handoff *) PLAT_HANDOFF_OFFSET; memcpy(reverse_hoff_ptr, handoff_ptr, sizeof(handoff)); buffer = (uint32_t *)reverse_hoff_ptr; /* convert big indian to little indian */ for (i = 0; i < sizeof(handoff) / 4; i++) buffer[i] = SWAP_UINT32(buffer[i]); if (reverse_hoff_ptr->header_magic != HANDOFF_MAGIC_HEADER) return -1; if (reverse_hoff_ptr->pinmux_sel_magic != HANDOFF_MAGIC_PINMUX_SEL) return -1; if (reverse_hoff_ptr->pinmux_io_magic != HANDOFF_MAGIC_IOCTLR) return -1; if (reverse_hoff_ptr->pinmux_fpga_magic != HANDOFF_MAGIC_FPGA) return -1; if (reverse_hoff_ptr->pinmux_delay_magic != HANDOFF_MAGIC_IODELAY) return -1; return 0; } trusted-firmware-a-2.2/plat/intel/soc/stratix10/soc/s10_mailbox.c000066400000000000000000000142041355360272700246560ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "s10_mailbox.h" static int fill_mailbox_circular_buffer(uint32_t header_cmd, uint32_t *args, int len) { uint32_t cmd_free_offset; int i; cmd_free_offset = mmio_read_32(MBOX_OFFSET + MBOX_CIN); if (cmd_free_offset >= MBOX_CMD_BUFFER_SIZE) { INFO("Insufficient buffer in mailbox\n"); return MBOX_INSUFFICIENT_BUFFER; } mmio_write_32(MBOX_OFFSET + MBOX_CMD_BUFFER + (cmd_free_offset++ * 4), header_cmd); for (i = 0; i < len; i++) { cmd_free_offset %= MBOX_CMD_BUFFER_SIZE; mmio_write_32(MBOX_OFFSET + MBOX_CMD_BUFFER + (cmd_free_offset++ * 4), args[i]); } cmd_free_offset %= MBOX_CMD_BUFFER_SIZE; mmio_write_32(MBOX_OFFSET + MBOX_CIN, cmd_free_offset); return 0; } int mailbox_read_response(int job_id, uint32_t *response) { int rin = 0; int rout = 0; int response_length = 0; int resp = 0; int total_resp_len = 0; int timeout = 100000; mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1); while (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) != 1) { if (timeout-- < 0) return MBOX_NO_RESPONSE; } mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0); rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN); rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT); while (rout != rin) { resp = mmio_read_32(MBOX_OFFSET + MBOX_RESP_BUFFER + ((rout++)*4)); rout %= MBOX_RESP_BUFFER_SIZE; mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout); if (MBOX_RESP_CLIENT_ID(resp) != MBOX_ATF_CLIENT_ID || MBOX_RESP_JOB_ID(resp) != job_id) { return MBOX_WRONG_ID; } if (MBOX_RESP_ERR(resp) > 0) { INFO("Error in response: %x\n", resp); return -resp; } response_length = MBOX_RESP_LEN(resp); while (response_length) { response_length--; resp = mmio_read_32(MBOX_OFFSET + MBOX_RESP_BUFFER + (rout)*4); if (response) { *(response + total_resp_len) = resp; total_resp_len++; } rout++; rout %= MBOX_RESP_BUFFER_SIZE; mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout); } return total_resp_len; } return MBOX_NO_RESPONSE; } int mailbox_poll_response(int job_id, int urgent, uint32_t *response) { int timeout = 80000; int rin = 0; int rout = 0; int response_length = 0; int resp = 0; int total_resp_len = 0; mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_TO_SDM, 1); while (1) { while (timeout > 0 && mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) != 1) { timeout--; } if (mmio_read_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM) != 1) { INFO("Timed out waiting for SDM"); return MBOX_TIMEOUT; } mmio_write_32(MBOX_OFFSET + MBOX_DOORBELL_FROM_SDM, 0); if (urgent & 1) { if ((mmio_read_32(MBOX_OFFSET + MBOX_STATUS) & MBOX_STATUS_UA_MASK) ^ (urgent & MBOX_STATUS_UA_MASK)) { mmio_write_32(MBOX_OFFSET + MBOX_URG, 0); return 0; } mmio_write_32(MBOX_OFFSET + MBOX_URG, 0); INFO("Error: Mailbox did not get UA"); return -1; } rin = mmio_read_32(MBOX_OFFSET + MBOX_RIN); rout = mmio_read_32(MBOX_OFFSET + MBOX_ROUT); while (rout != rin) { resp = mmio_read_32(MBOX_OFFSET + MBOX_RESP_BUFFER + ((rout++)*4)); rout %= MBOX_RESP_BUFFER_SIZE; mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout); if (MBOX_RESP_CLIENT_ID(resp) != MBOX_ATF_CLIENT_ID || MBOX_RESP_JOB_ID(resp) != job_id) continue; if (MBOX_RESP_ERR(resp) > 0) { INFO("Error in response: %x\n", resp); return -MBOX_RESP_ERR(resp); } response_length = MBOX_RESP_LEN(resp); while (response_length) { response_length--; resp = mmio_read_32(MBOX_OFFSET + MBOX_RESP_BUFFER + (rout)*4); if (response) { *(response + total_resp_len) = resp; total_resp_len++; } rout++; rout %= MBOX_RESP_BUFFER_SIZE; mmio_write_32(MBOX_OFFSET + MBOX_ROUT, rout); } return total_resp_len; } } } void mailbox_send_cmd_async(int job_id, unsigned int cmd, uint32_t *args, int len, int urgent) { if (urgent) mmio_write_32(MBOX_OFFSET + MBOX_URG, 1); fill_mailbox_circular_buffer(MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) | MBOX_JOB_ID_CMD(job_id) | MBOX_CMD_LEN_CMD(len) | MBOX_INDIRECT | cmd, args, len); } int mailbox_send_cmd(int job_id, unsigned int cmd, uint32_t *args, int len, int urgent, uint32_t *response) { int status; if (urgent) { urgent |= mmio_read_32(MBOX_OFFSET + MBOX_STATUS) & MBOX_STATUS_UA_MASK; mmio_write_32(MBOX_OFFSET + MBOX_URG, 1); } status = fill_mailbox_circular_buffer( MBOX_CLIENT_ID_CMD(MBOX_ATF_CLIENT_ID) | MBOX_JOB_ID_CMD(job_id) | cmd, args, len); if (status) return status; return mailbox_poll_response(job_id, urgent, response); } void mailbox_set_int(int interrupt) { mmio_write_32(MBOX_OFFSET+MBOX_INT, MBOX_COE_BIT(interrupt) | MBOX_UAE_BIT(interrupt)); } void mailbox_set_qspi_open(void) { mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE); mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_OPEN, 0, 0, 0, 0); } void mailbox_set_qspi_direct(void) { mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_DIRECT, 0, 0, 0, 0); } void mailbox_set_qspi_close(void) { mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE); mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_CLOSE, 0, 0, 0, 0); } int mailbox_get_qspi_clock(void) { mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE); return mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_DIRECT, 0, 0, 0, 0); } void mailbox_qspi_set_cs(int device_select) { uint32_t cs_setting = device_select; /* QSPI device select settings at 31:28 */ cs_setting = (cs_setting << 28); mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE); mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_QSPI_SET_CS, &cs_setting, 1, 0, 0); } void mailbox_reset_cold(void) { mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE); mailbox_send_cmd(MBOX_JOB_ID, MBOX_CMD_REBOOT_HPS, 0, 0, 0, 0); } int mailbox_init(void) { int status = 0; mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE); status = mailbox_send_cmd(0, MBOX_CMD_RESTART, 0, 0, 1, 0); if (status) return status; mailbox_set_int(MBOX_INT_FLAG_COE | MBOX_INT_FLAG_RIE); return 0; } trusted-firmware-a-2.2/plat/intel/soc/stratix10/soc/s10_memory_controller.c000066400000000000000000000273351355360272700270070ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "s10_memory_controller.h" #define ALT_CCU_NOC_DI_SET_MSK 0x10 #define DDR_READ_LATENCY_DELAY 40 #define MAX_MEM_CAL_RETRY 3 #define PRE_CALIBRATION_DELAY 1 #define POST_CALIBRATION_DELAY 1 #define TIMEOUT_EMIF_CALIBRATION 100 #define CLEAR_EMIF_DELAY 50000 #define CLEAR_EMIF_TIMEOUT 0x100000 #define TIMEOUT_INT_RESP 10000 #define DDR_CONFIG(A, B, C, R) (((A) << 24) | ((B) << 16) | ((C) << 8) | (R)) #define DDR_CONFIG_ELEMENTS (sizeof(ddr_config)/sizeof(uint32_t)) /* tWR = Min. 15ns constant, see JEDEC standard eg. DDR4 is JESD79-4.pdf */ #define tWR_IN_NS 15 void configure_hmc_adaptor_regs(void); void configure_ddr_sched_ctrl_regs(void); /* The followring are the supported configurations */ uint32_t ddr_config[] = { /* DDR_CONFIG(Address order,Bank,Column,Row) */ /* List for DDR3 or LPDDR3 (pinout order > chip, row, bank, column) */ DDR_CONFIG(0, 3, 10, 12), DDR_CONFIG(0, 3, 9, 13), DDR_CONFIG(0, 3, 10, 13), DDR_CONFIG(0, 3, 9, 14), DDR_CONFIG(0, 3, 10, 14), DDR_CONFIG(0, 3, 10, 15), DDR_CONFIG(0, 3, 11, 14), DDR_CONFIG(0, 3, 11, 15), DDR_CONFIG(0, 3, 10, 16), DDR_CONFIG(0, 3, 11, 16), DDR_CONFIG(0, 3, 12, 15), /* 0xa */ /* List for DDR4 only (pinout order > chip, bank, row, column) */ DDR_CONFIG(1, 3, 10, 14), DDR_CONFIG(1, 4, 10, 14), DDR_CONFIG(1, 3, 10, 15), DDR_CONFIG(1, 4, 10, 15), DDR_CONFIG(1, 3, 10, 16), DDR_CONFIG(1, 4, 10, 16), DDR_CONFIG(1, 3, 10, 17), DDR_CONFIG(1, 4, 10, 17), }; static int match_ddr_conf(uint32_t ddr_conf) { int i; for (i = 0; i < DDR_CONFIG_ELEMENTS; i++) { if (ddr_conf == ddr_config[i]) return i; } return 0; } static int check_hmc_clk(void) { unsigned long timeout = 0; uint32_t hmc_clk; do { hmc_clk = mmio_read_32(S10_SYSMGR_CORE_HMC_CLK); if (hmc_clk & S10_SYSMGR_CORE_HMC_CLK_STATUS) break; udelay(1); } while (++timeout < 1000); if (timeout >= 1000) return -ETIMEDOUT; return 0; } static int clear_emif(void) { uint32_t data; unsigned long timeout; mmio_write_32(S10_MPFE_HMC_ADP_RSTHANDSHAKECTRL, 0); timeout = 0; do { data = mmio_read_32(S10_MPFE_HMC_ADP_RSTHANDSHAKESTAT); if ((data & S10_MPFE_HMC_ADP_RSTHANDSHAKESTAT_SEQ2CORE) == 0) break; udelay(CLEAR_EMIF_DELAY); } while (++timeout < CLEAR_EMIF_TIMEOUT); if (timeout >= CLEAR_EMIF_TIMEOUT) return -ETIMEDOUT; return 0; } static int mem_calibration(void) { int status = 0; uint32_t data; unsigned long timeout; unsigned long retry = 0; udelay(PRE_CALIBRATION_DELAY); do { if (retry != 0) INFO("DDR: Retrying DRAM calibration\n"); timeout = 0; do { data = mmio_read_32(S10_MPFE_HMC_ADP_DDRCALSTAT); if (S10_MPFE_HMC_ADP_DDRCALSTAT_CAL(data) == 1) break; udelay(1); } while (++timeout < TIMEOUT_EMIF_CALIBRATION); if (S10_MPFE_HMC_ADP_DDRCALSTAT_CAL(data) == 0) { status = clear_emif(); if (status) ERROR("Failed to clear Emif\n"); } else { break; } } while (++retry < MAX_MEM_CAL_RETRY); if (S10_MPFE_HMC_ADP_DDRCALSTAT_CAL(data) == 0) { ERROR("DDR: DRAM calibration failed.\n"); status = -EIO; } else { INFO("DDR: DRAM calibration success.\n"); status = 0; } udelay(POST_CALIBRATION_DELAY); return status; } int init_hard_memory_controller(void) { int status; mmio_clrbits_32(S10_CCU_CPU0_MPRT_DDR, S10_CCU_NOC_DI_SET_MSK); mmio_clrbits_32(S10_CCU_CPU0_MPRT_MEM0, S10_CCU_NOC_DI_SET_MSK); mmio_clrbits_32(S10_CCU_CPU0_MPRT_MEM1A, S10_CCU_NOC_DI_SET_MSK); mmio_clrbits_32(S10_CCU_CPU0_MPRT_MEM1B, S10_CCU_NOC_DI_SET_MSK); mmio_clrbits_32(S10_CCU_CPU0_MPRT_MEM1C, S10_CCU_NOC_DI_SET_MSK); mmio_clrbits_32(S10_CCU_CPU0_MPRT_MEM1D, S10_CCU_NOC_DI_SET_MSK); mmio_clrbits_32(S10_CCU_CPU0_MPRT_MEM1E, S10_CCU_NOC_DI_SET_MSK); mmio_clrbits_32(S10_CCU_IOM_MPRT_MEM0, S10_CCU_NOC_DI_SET_MSK); mmio_clrbits_32(S10_CCU_IOM_MPRT_MEM1A, S10_CCU_NOC_DI_SET_MSK); mmio_clrbits_32(S10_CCU_IOM_MPRT_MEM1B, S10_CCU_NOC_DI_SET_MSK); mmio_clrbits_32(S10_CCU_IOM_MPRT_MEM1C, S10_CCU_NOC_DI_SET_MSK); mmio_clrbits_32(S10_CCU_IOM_MPRT_MEM1D, S10_CCU_NOC_DI_SET_MSK); mmio_clrbits_32(S10_CCU_IOM_MPRT_MEM1E, S10_CCU_NOC_DI_SET_MSK); mmio_write_32(S10_NOC_FW_DDR_SCR_MPUREGION0ADDR_LIMIT, 0xFFFF0000); mmio_write_32(S10_NOC_FW_DDR_SCR_MPUREGION0ADDR_LIMITEXT, 0x1F); mmio_write_32(S10_NOC_FW_DDR_SCR_NONMPUREGION0ADDR_LIMIT, 0xFFFF0000); mmio_write_32(S10_NOC_FW_DDR_SCR_NONMPUREGION0ADDR_LIMITEXT, 0x1F); mmio_write_32(S10_SOC_NOC_FW_DDR_SCR_ENABLE, BIT(0) | BIT(8)); status = check_hmc_clk(); if (status) { ERROR("DDR: Error, HMC clock not running\n"); return status; } mmio_clrbits_32(S10_RSTMGR_BRGMODRST, S10_RSTMGR_BRGMODRST_DDRSCH); status = mem_calibration(); if (status) { ERROR("DDR: Memory Calibration Failed\n"); return status; } configure_hmc_adaptor_regs(); configure_ddr_sched_ctrl_regs(); return 0; } void configure_ddr_sched_ctrl_regs(void) { uint32_t data, dram_addr_order, ddr_conf, bank, row, col, rd_to_miss, wr_to_miss, burst_len, burst_len_ddr_clk, burst_len_sched_clk, act_to_act, rd_to_wr, wr_to_rd, bw_ratio, t_rtp, t_rp, t_rcd, rd_latency, tw_rin_clk_cycles, bw_ratio_extended, auto_precharge = 0, act_to_act_bank, faw, faw_bank, bus_rd_to_rd, bus_rd_to_wr, bus_wr_to_rd; INFO("Init HPS NOC's DDR Scheduler.\n"); data = mmio_read_32(S10_MPFE_IOHMC_CTRLCFG1); dram_addr_order = S10_MPFE_IOHMC_CTRLCFG1_CFG_ADDR_ORDER(data); data = mmio_read_32(S10_MPFE_IOHMC_DRAMADDRW); col = IOHMC_DRAMADDRW_COL_ADDR_WIDTH(data); row = IOHMC_DRAMADDRW_ROW_ADDR_WIDTH(data); bank = IOHMC_DRAMADDRW_BANK_ADDR_WIDTH(data) + IOHMC_DRAMADDRW_BANK_GRP_ADDR_WIDTH(data); ddr_conf = match_ddr_conf(DDR_CONFIG(dram_addr_order, bank, col, row)); if (ddr_conf) { mmio_clrsetbits_32( S10_MPFE_DDR_MAIN_SCHED_DDRCONF, S10_MPFE_DDR_MAIN_SCHED_DDRCONF_SET_MSK, S10_MPFE_DDR_MAIN_SCHED_DDRCONF_SET(ddr_conf)); } else { ERROR("DDR: Cannot find predefined ddrConf configuration.\n"); } mmio_write_32(S10_MPFE_HMC_ADP(ADP_DRAMADDRWIDTH), data); data = mmio_read_32(S10_MPFE_IOHMC_DRAMTIMING0); rd_latency = S10_MPFE_IOHMC_REG_DRAMTIMING0_CFG_TCL(data); data = mmio_read_32(S10_MPFE_IOHMC_CALTIMING0); act_to_act = ACT_TO_ACT(data); t_rcd = ACT_TO_RDWR(data); act_to_act_bank = ACT_TO_ACT_DIFF_BANK(data); data = mmio_read_32(S10_MPFE_IOHMC_CALTIMING1); rd_to_wr = RD_TO_WR(data); bus_rd_to_rd = RD_TO_RD_DIFF_CHIP(data); bus_rd_to_wr = RD_TO_WR_DIFF_CHIP(data); data = mmio_read_32(S10_MPFE_IOHMC_CALTIMING2); t_rtp = RD_TO_PCH(data); data = mmio_read_32(S10_MPFE_IOHMC_CALTIMING3); wr_to_rd = CALTIMING3_WR_TO_RD(data); bus_wr_to_rd = CALTIMING3_WR_TO_RD_DIFF_CHIP(data); data = mmio_read_32(S10_MPFE_IOHMC_CALTIMING4); t_rp = PCH_TO_VALID(data); data = mmio_read_32(S10_MPFE_HMC_ADP(HMC_ADP_DDRIOCTRL)); bw_ratio = ((HMC_ADP_DDRIOCTRL_IO_SIZE(data) == 0) ? 0 : 1); data = mmio_read_32(S10_MPFE_IOHMC_CTRLCFG0); burst_len = HMC_ADP_DDRIOCTRL_CTRL_BURST_LENGTH(data); burst_len_ddr_clk = burst_len / 2; burst_len_sched_clk = ((burst_len/2) / 2); data = mmio_read_32(S10_MPFE_IOHMC_CTRLCFG0); switch (S10_MPFE_IOHMC_REG_CTRLCFG0_CFG_MEM_TYPE(data)) { case 1: /* DDR4 - 1333MHz */ /* 20 (19.995) clock cycles = 15ns */ /* Calculate with rounding */ tw_rin_clk_cycles = (((tWR_IN_NS * 1333) % 1000) >= 500) ? ((tWR_IN_NS * 1333) / 1000) + 1 : ((tWR_IN_NS * 1333) / 1000); break; default: /* Others - 1066MHz or slower */ /* 16 (15.990) clock cycles = 15ns */ /* Calculate with rounding */ tw_rin_clk_cycles = (((tWR_IN_NS * 1066) % 1000) >= 500) ? ((tWR_IN_NS * 1066) / 1000) + 1 : ((tWR_IN_NS * 1066) / 1000); break; } rd_to_miss = t_rtp + t_rp + t_rcd - burst_len_sched_clk; wr_to_miss = ((rd_latency + burst_len_ddr_clk + 2 + tw_rin_clk_cycles) / 2) - rd_to_wr + t_rp + t_rcd; mmio_write_32(S10_MPFE_DDR_MAIN_SCHED_DDRTIMING, bw_ratio << DDRTIMING_BWRATIO_OFST | wr_to_rd << DDRTIMING_WRTORD_OFST| rd_to_wr << DDRTIMING_RDTOWR_OFST | burst_len_sched_clk << DDRTIMING_BURSTLEN_OFST | wr_to_miss << DDRTIMING_WRTOMISS_OFST | rd_to_miss << DDRTIMING_RDTOMISS_OFST | act_to_act << DDRTIMING_ACTTOACT_OFST); data = mmio_read_32(S10_MPFE_HMC_ADP(HMC_ADP_DDRIOCTRL)); bw_ratio_extended = ((ADP_DDRIOCTRL_IO_SIZE(data) == 0) ? 1 : 0); mmio_write_32(S10_MPFE_DDR_MAIN_SCHED_DDRMODE, bw_ratio_extended << DDRMODE_BWRATIOEXTENDED_OFST | auto_precharge << DDRMODE_AUTOPRECHARGE_OFST); mmio_write_32(S10_MPFE_DDR_MAIN_SCHED_READLATENCY, (rd_latency / 2) + DDR_READ_LATENCY_DELAY); data = mmio_read_32(S10_MPFE_IOHMC_CALTIMING9); faw = S10_MPFE_IOHMC_CALTIMING9_ACT_TO_ACT(data); faw_bank = 1; // always 1 because we always have 4 bank DDR. mmio_write_32(S10_MPFE_DDR_MAIN_SCHED_ACTIVATE, faw_bank << S10_MPFE_DDR_MAIN_SCHED_ACTIVATE_FAWBANK_OFST | faw << S10_MPFE_DDR_MAIN_SCHED_ACTIVATE_FAW_OFST | act_to_act_bank << S10_MPFE_DDR_MAIN_SCHED_ACTIVATE_RRD_OFST); mmio_write_32(S10_MPFE_DDR_MAIN_SCHED_DEVTODEV, ((bus_rd_to_rd << S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTORD_OFST) & S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTORD_MSK) | ((bus_rd_to_wr << S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTOWR_OFST) & S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSRDTOWR_MSK) | ((bus_wr_to_rd << S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSWRTORD_OFST) & S10_MPFE_DDR_MAIN_SCHED_DEVTODEV_BUSWRTORD_MSK)); } unsigned long get_physical_dram_size(void) { uint32_t data; unsigned long ram_addr_width, ram_ext_if_io_width; data = mmio_read_32(S10_MPFE_HMC_ADP_DDRIOCTRL); switch (S10_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE(data)) { case 0: ram_ext_if_io_width = 16; break; case 1: ram_ext_if_io_width = 32; break; case 2: ram_ext_if_io_width = 64; break; default: ram_ext_if_io_width = 0; break; } data = mmio_read_32(S10_MPFE_IOHMC_REG_DRAMADDRW); ram_addr_width = IOHMC_DRAMADDRW_CFG_COL_ADDR_WIDTH(data) + IOHMC_DRAMADDRW_CFG_ROW_ADDR_WIDTH(data) + IOHMC_DRAMADDRW_CFG_BANK_ADDR_WIDTH(data) + IOHMC_DRAMADDRW_CFG_BANK_GROUP_ADDR_WIDTH(data) + IOHMC_DRAMADDRW_CFG_CS_ADDR_WIDTH(data); return (1 << ram_addr_width) * (ram_ext_if_io_width / 8); } void configure_hmc_adaptor_regs(void) { uint32_t data; uint32_t dram_io_width; dram_io_width = S10_MPFE_IOHMC_NIOSRESERVE0_NIOS_RESERVE0( mmio_read_32(S10_MPFE_IOHMC_REG_NIOSRESERVE0_OFST)); dram_io_width = (dram_io_width & 0xFF) >> 5; mmio_clrsetbits_32(S10_MPFE_HMC_ADP_DDRIOCTRL, S10_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE_MSK, dram_io_width << S10_MPFE_HMC_ADP_DDRIOCTRL_IO_SIZE_OFST); mmio_write_32(S10_MPFE_HMC_ADP_HPSINTFCSEL, S10_MPFE_HMC_ADP_HPSINTFCSEL_ENABLE); data = mmio_read_32(S10_MPFE_IOHMC_REG_CTRLCFG1); if (data & (1 << S10_IOHMC_CTRLCFG1_ENABLE_ECC_OFST)) { mmio_clrsetbits_32(S10_MPFE_HMC_ADP_ECCCTRL1, S10_MPFE_HMC_ADP_ECCCTRL1_AUTOWB_CNT_RST_SET_MSK | S10_MPFE_HMC_ADP_ECCCTRL1_CNT_RST_SET_MSK | S10_MPFE_HMC_ADP_ECCCTRL1_ECC_EN_SET_MSK, S10_MPFE_HMC_ADP_ECCCTRL1_AUTOWB_CNT_RST_SET_MSK | S10_MPFE_HMC_ADP_ECCCTRL1_CNT_RST_SET_MSK); mmio_clrsetbits_32(S10_MPFE_HMC_ADP_ECCCTRL2, S10_MPFE_HMC_ADP_ECCCTRL2_OVRW_RB_ECC_EN_SET_MSK | S10_MPFE_HMC_ADP_ECCCTRL2_RMW_EN_SET_MSK | S10_MPFE_HMC_ADP_ECCCTRL2_AUTOWB_EN_SET_MSK, S10_MPFE_HMC_ADP_ECCCTRL2_RMW_EN_SET_MSK | S10_MPFE_HMC_ADP_ECCCTRL2_AUTOWB_EN_SET_MSK); mmio_clrsetbits_32(S10_MPFE_HMC_ADP_ECCCTRL1, S10_MPFE_HMC_ADP_ECCCTRL1_AUTOWB_CNT_RST_SET_MSK | S10_MPFE_HMC_ADP_ECCCTRL1_CNT_RST_SET_MSK | S10_MPFE_HMC_ADP_ECCCTRL1_ECC_EN_SET_MSK, S10_MPFE_HMC_ADP_ECCCTRL1_ECC_EN_SET_MSK); INFO("Scrubbing ECC\n"); /* ECC Scrubbing */ zeromem(DRAM_BASE, DRAM_SIZE); } else { INFO("ECC is disabled.\n"); } } trusted-firmware-a-2.2/plat/intel/soc/stratix10/soc/s10_pinmux.c000066400000000000000000000124361355360272700245500ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "s10_pinmux.h" const uint32_t sysmgr_pinmux_array_sel[] = { 0x00000000, 0x00000001, /* usb */ 0x00000004, 0x00000001, 0x00000008, 0x00000001, 0x0000000c, 0x00000001, 0x00000010, 0x00000001, 0x00000014, 0x00000001, 0x00000018, 0x00000001, 0x0000001c, 0x00000001, 0x00000020, 0x00000001, 0x00000024, 0x00000001, 0x00000028, 0x00000001, 0x0000002c, 0x00000001, 0x00000030, 0x00000000, /* emac0 */ 0x00000034, 0x00000000, 0x00000038, 0x00000000, 0x0000003c, 0x00000000, 0x00000040, 0x00000000, 0x00000044, 0x00000000, 0x00000048, 0x00000000, 0x0000004c, 0x00000000, 0x00000050, 0x00000000, 0x00000054, 0x00000000, 0x00000058, 0x00000000, 0x0000005c, 0x00000000, 0x00000060, 0x00000008, /* gpio1 */ 0x00000064, 0x00000008, 0x00000068, 0x00000005, /* uart0 tx */ 0x0000006c, 0x00000005, /* uart 0 rx */ 0x00000070, 0x00000008, /* gpio */ 0x00000074, 0x00000008, 0x00000078, 0x00000004, /* i2c1 */ 0x0000007c, 0x00000004, 0x00000080, 0x00000007, /* jtag */ 0x00000084, 0x00000007, 0x00000088, 0x00000007, 0x0000008c, 0x00000007, 0x00000090, 0x00000001, /* sdmmc data0 */ 0x00000094, 0x00000001, 0x00000098, 0x00000001, 0x0000009c, 0x00000001, 0x00000100, 0x00000001, 0x00000104, 0x00000001, /* sdmmc.data3 */ 0x00000108, 0x00000008, /* loan */ 0x0000010c, 0x00000008, /* gpio */ 0x00000110, 0x00000008, 0x00000114, 0x00000008, /* gpio1.io21 */ 0x00000118, 0x00000005, /* mdio0.mdio */ 0x0000011c, 0x00000005 /* mdio0.mdc */ }; const uint32_t sysmgr_pinmux_array_ctrl[] = { 0x00000000, 0x00502c38, /* Q1_1 */ 0x00000004, 0x00102c38, 0x00000008, 0x00502c38, 0x0000000c, 0x00502c38, 0x00000010, 0x00502c38, 0x00000014, 0x00502c38, 0x00000018, 0x00502c38, 0x0000001c, 0x00502c38, 0x00000020, 0x00502c38, 0x00000024, 0x00502c38, 0x00000028, 0x00502c38, 0x0000002c, 0x00502c38, 0x00000030, 0x00102c38, /* Q2_1 */ 0x00000034, 0x00102c38, 0x00000038, 0x00502c38, 0x0000003c, 0x00502c38, 0x00000040, 0x00102c38, 0x00000044, 0x00102c38, 0x00000048, 0x00502c38, 0x0000004c, 0x00502c38, 0x00000050, 0x00102c38, 0x00000054, 0x00102c38, 0x00000058, 0x00502c38, 0x0000005c, 0x00502c38, 0x00000060, 0x00502c38, /* Q3_1 */ 0x00000064, 0x00502c38, 0x00000068, 0x00102c38, 0x0000006c, 0x00502c38, 0x000000d0, 0x00502c38, 0x000000d4, 0x00502c38, 0x000000d8, 0x00542c38, 0x000000dc, 0x00542c38, 0x000000e0, 0x00502c38, 0x000000e4, 0x00502c38, 0x000000e8, 0x00102c38, 0x000000ec, 0x00502c38, 0x000000f0, 0x00502c38, /* Q4_1 */ 0x000000f4, 0x00502c38, 0x000000f8, 0x00102c38, 0x000000fc, 0x00502c38, 0x00000100, 0x00502c38, 0x00000104, 0x00502c38, 0x00000108, 0x00102c38, 0x0000010c, 0x00502c38, 0x00000110, 0x00502c38, 0x00000114, 0x00502c38, 0x00000118, 0x00542c38, 0x0000011c, 0x00102c38 }; const uint32_t sysmgr_pinmux_array_fpga[] = { 0x00000000, 0x00000000, 0x00000004, 0x00000000, 0x00000008, 0x00000000, 0x0000000c, 0x00000000, 0x00000010, 0x00000000, 0x00000014, 0x00000000, 0x00000018, 0x00000000, 0x0000001c, 0x00000000, 0x00000020, 0x00000000, 0x00000028, 0x00000000, 0x0000002c, 0x00000000, 0x00000030, 0x00000000, 0x00000034, 0x00000000, 0x00000038, 0x00000000, 0x0000003c, 0x00000000, 0x00000040, 0x00000000, 0x00000044, 0x00000000, 0x00000048, 0x00000000, 0x00000050, 0x00000000, 0x00000054, 0x00000000, 0x00000058, 0x0000002a }; const uint32_t sysmgr_pinmux_array_iodelay[] = { 0x00000000, 0x00000000, 0x00000004, 0x00000000, 0x00000008, 0x00000000, 0x0000000c, 0x00000000, 0x00000010, 0x00000000, 0x00000014, 0x00000000, 0x00000018, 0x00000000, 0x0000001c, 0x00000000, 0x00000020, 0x00000000, 0x00000024, 0x00000000, 0x00000028, 0x00000000, 0x0000002c, 0x00000000, 0x00000030, 0x00000000, 0x00000034, 0x00000000, 0x00000038, 0x00000000, 0x0000003c, 0x00000000, 0x00000040, 0x00000000, 0x00000044, 0x00000000, 0x00000048, 0x00000000, 0x0000004c, 0x00000000, 0x00000050, 0x00000000, 0x00000054, 0x00000000, 0x00000058, 0x00000000, 0x0000005c, 0x00000000, 0x00000060, 0x00000000, 0x00000064, 0x00000000, 0x00000068, 0x00000000, 0x0000006c, 0x00000000, 0x00000070, 0x00000000, 0x00000074, 0x00000000, 0x00000078, 0x00000000, 0x0000007c, 0x00000000, 0x00000080, 0x00000000, 0x00000084, 0x00000000, 0x00000088, 0x00000000, 0x0000008c, 0x00000000, 0x00000090, 0x00000000, 0x00000094, 0x00000000, 0x00000098, 0x00000000, 0x0000009c, 0x00000000, 0x00000100, 0x00000000, 0x00000104, 0x00000000, 0x00000108, 0x00000000, 0x0000010c, 0x00000000, 0x00000110, 0x00000000, 0x00000114, 0x00000000, 0x00000118, 0x00000000, 0x0000011c, 0x00000000 }; void config_pinmux(handoff *hoff_ptr) { unsigned int i; for (i = 0; i < 96; i += 2) { mmio_write_32(S10_PINMUX_PIN0SEL + hoff_ptr->pinmux_sel_array[i], hoff_ptr->pinmux_sel_array[i+1]); } for (i = 0; i < 96; i += 2) { mmio_write_32(S10_PINMUX_IO0CTRL + hoff_ptr->pinmux_io_array[i], hoff_ptr->pinmux_io_array[i+1]); } for (i = 0; i < 42; i += 2) { mmio_write_32(S10_PINMUX_PINMUX_EMAC0_USEFPGA + hoff_ptr->pinmux_fpga_array[i], hoff_ptr->pinmux_fpga_array[i+1]); } for (i = 0; i < 96; i += 2) { mmio_write_32(S10_PINMUX_IO0_DELAY + hoff_ptr->pinmux_iodelay_array[i], hoff_ptr->pinmux_iodelay_array[i+1]); } } trusted-firmware-a-2.2/plat/intel/soc/stratix10/soc/s10_reset_manager.c000066400000000000000000000047231355360272700260440ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "s10_reset_manager.h" void deassert_peripheral_reset(void) { mmio_clrbits_32(S10_RSTMGR_PER1MODRST, S10_RSTMGR_PER1MODRST_WATCHDOG0 | S10_RSTMGR_PER1MODRST_WATCHDOG1 | S10_RSTMGR_PER1MODRST_WATCHDOG2 | S10_RSTMGR_PER1MODRST_WATCHDOG3 | S10_RSTMGR_PER1MODRST_L4SYSTIMER0 | S10_RSTMGR_PER1MODRST_L4SYSTIMER1 | S10_RSTMGR_PER1MODRST_SPTIMER0 | S10_RSTMGR_PER1MODRST_SPTIMER1 | S10_RSTMGR_PER1MODRST_I2C0 | S10_RSTMGR_PER1MODRST_I2C1 | S10_RSTMGR_PER1MODRST_I2C2 | S10_RSTMGR_PER1MODRST_I2C3 | S10_RSTMGR_PER1MODRST_I2C4 | S10_RSTMGR_PER1MODRST_UART0 | S10_RSTMGR_PER1MODRST_UART1 | S10_RSTMGR_PER1MODRST_GPIO0 | S10_RSTMGR_PER1MODRST_GPIO1); mmio_clrbits_32(S10_RSTMGR_PER0MODRST, S10_RSTMGR_PER0MODRST_EMAC0OCP | S10_RSTMGR_PER0MODRST_EMAC1OCP | S10_RSTMGR_PER0MODRST_EMAC2OCP | S10_RSTMGR_PER0MODRST_USB0OCP | S10_RSTMGR_PER0MODRST_USB1OCP | S10_RSTMGR_PER0MODRST_NANDOCP | S10_RSTMGR_PER0MODRST_SDMMCOCP | S10_RSTMGR_PER0MODRST_DMAOCP); mmio_clrbits_32(S10_RSTMGR_PER0MODRST, S10_RSTMGR_PER0MODRST_EMAC0 | S10_RSTMGR_PER0MODRST_EMAC1 | S10_RSTMGR_PER0MODRST_EMAC2 | S10_RSTMGR_PER0MODRST_USB0 | S10_RSTMGR_PER0MODRST_USB1 | S10_RSTMGR_PER0MODRST_NAND | S10_RSTMGR_PER0MODRST_SDMMC | S10_RSTMGR_PER0MODRST_DMA | S10_RSTMGR_PER0MODRST_SPIM0 | S10_RSTMGR_PER0MODRST_SPIM1 | S10_RSTMGR_PER0MODRST_SPIS0 | S10_RSTMGR_PER0MODRST_SPIS1 | S10_RSTMGR_PER0MODRST_EMACPTP | S10_RSTMGR_PER0MODRST_DMAIF0 | S10_RSTMGR_PER0MODRST_DMAIF1 | S10_RSTMGR_PER0MODRST_DMAIF2 | S10_RSTMGR_PER0MODRST_DMAIF3 | S10_RSTMGR_PER0MODRST_DMAIF4 | S10_RSTMGR_PER0MODRST_DMAIF5 | S10_RSTMGR_PER0MODRST_DMAIF6 | S10_RSTMGR_PER0MODRST_DMAIF7); } void config_hps_hs_before_warm_reset(void) { uint32_t or_mask = 0; or_mask |= S10_RSTMGR_HDSKEN_SDRSELFREFEN; or_mask |= S10_RSTMGR_HDSKEN_FPGAHSEN; or_mask |= S10_RSTMGR_HDSKEN_ETRSTALLEN; or_mask |= S10_RSTMGR_HDSKEN_L2FLUSHEN; or_mask |= S10_RSTMGR_HDSKEN_L3NOC_DBG; or_mask |= S10_RSTMGR_HDSKEN_DEBUG_L3NOC; mmio_setbits_32(S10_RSTMGR_HDSKEN, or_mask); } trusted-firmware-a-2.2/plat/intel/soc/stratix10/soc/s10_system_manager.c000066400000000000000000000073761355360272700262550ustar00rootroot00000000000000/* * Copyright (c) 2019, Intel Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "s10_system_manager.h" void enable_nonsecure_access(void) { mmio_write_32(S10_NOC_FW_L4_PER_SCR_NAND_REGISTER, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_NAND_DATA, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_NAND_ECC, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_NAND_READ_ECC, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_NAND_WRITE_ECC, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_USB0_REGISTER, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_USB1_REGISTER, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_USB0_ECC, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_USB1_ECC, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_SPI_MASTER0, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_SPI_MASTER1, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_SPI_SLAVE0, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_SPI_SLAVE1, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_EMAC0, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_EMAC1, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_EMAC2, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_EMAC0RX_ECC, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_EMAC0TX_ECC, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_EMAC1RX_ECC, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_EMAC1TX_ECC, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_EMAC2RX_ECC, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_EMAC2TX_ECC, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_SDMMC, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_SDMMC_ECC, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_GPIO0, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_GPIO1, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_I2C0, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_I2C1, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_I2C2, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_I2C3, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_I2C4, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_SP_TIMER1, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_UART0, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_PER_SCR_UART1, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_DMA_ECC, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_OCRAM_ECC, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_CLK_MGR, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_IO_MGR, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_RST_MGR, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_SYS_MGR, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_OSC0_TIMER, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_OSC1_TIMER, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_WATCHDOG0, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_WATCHDOG1, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_WATCHDOG2, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_WATCHDOG3, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_DAP, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_L4_NOC_PROBES, DISABLE_L4_FIREWALL); mmio_write_32(S10_NOC_FW_L4_SYS_SCR_L4_NOC_QOS, DISABLE_L4_FIREWALL); mmio_clrbits_32(S10_CCU_NOC_CPU0_RAMSPACE0_0, 0x03); mmio_clrbits_32(S10_CCU_NOC_IOM_RAMSPACE0_0, 0x03); mmio_write_32(S10_SYSMGR_CORE(SYSMGR_MMC), SYSMGR_MMC_DRVSEL(3)); } trusted-firmware-a-2.2/plat/layerscape/000077500000000000000000000000001355360272700202015ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/layerscape/board/000077500000000000000000000000001355360272700212705ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/layerscape/board/ls1043/000077500000000000000000000000001355360272700222165ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/layerscape/board/ls1043/aarch64/000077500000000000000000000000001355360272700234465ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/layerscape/board/ls1043/aarch64/ls1043_helpers.S000066400000000000000000000050551355360272700262470ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl plat_reset_handler .globl plat_my_core_pos .globl platform_mem_init func plat_my_core_pos mrs x0, mpidr_el1 and x1, x0, #MPIDR_CPU_MASK //reserve the last 8 bits and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #4 //4 cores ret endfunc plat_my_core_pos func platform_mem_init mov x29, x30 bl inv_dcache_range //SDRAM_CFG ldr w0, =0x1080000 ldr w1, =0x0c000c45 str w1, [x0, #0x110] //CS0_BNDS ldr w1, =0x7f000000 str w1, [x0, #0x000] //CS0_CONFIG ldr w1, =0x22030480 str w1, [x0, #0x080] //TIMING_CFG_0 ldr w1, =0x18005591 str w1, [x0, #0x104] //TIMING_CFG_1 ldr w1, =0x428cb4bb str w1, [x0, #0x108] //TIMING_CFG_2 ldr w1, =0x11c14800 str w1, [x0, #0x10C] //TIMING_CFG_3 ldr w1, =0x00100c01 str w1, [x0, #0x100] //TIMING_CFG_4 ldr w1, =0x02000000 str w1, [x0, #0x160] //TIMING_CFG_5 ldr w1, =0x00144003 str w1, [x0, #0x164] //TIMING_CFG_7 ldr w1, =0x00003013 str w1, [x0, #0x16C] //TIMING_CFG_8 ldr w1, =0x00561102 str w1, [x0, #0x250] //SDRAM_CFG_2 ldr w1, =0x00114000 str w1, [x0, #0x114] //SDRAM_MODE ldr w1, =0x10020103 str w1, [x0, #0x118] //SDRAM_MODE_2 ldr w1, =0x0 str w1, [x0, #0x11C] //SDRAM_INTERVAL ldr w1, =0x18066018 str w1, [x0, #0x124] //DDR_WRLVL_CNTL ldr w1, =0x07f675c6 str w1, [x0, #0x174] //DDR_WRLVL_CNTL_2 ldr w1, =0x00080907 str w1, [x0, #0x190] //DDR_WRLVL_CNTL_3 ldr w1, =0x0 str w1, [x0, #0x194] //DDR_CDR1 ldr w1, =0x00000480 str w1, [x0, #0xB28] //DDR_CDR2 ldr w1, =0x81a10000 str w1, [x0, #0xB2C] //SDRAM_CLK_CNTL ldr w1, =0x00000003 str w1, [x0, #0x130] //DDR_ZQ_CNTL ldr w1, =0x0507098a str w1, [x0, #0x170] //SDRAM_MODE_9 ldr w1, =0x00050000 str w1, [x0, #0x220] //SDRAM_MODE_10 ldr w1, =0x00000004 str w1, [x0, #0x224] //CS0_CONFIG_2 ldr w1, =0x0 str w1, [x0, #0x0C0] //SDRAM_CFG ldr w1, =0x08000cc5 str w1, [x0, #0x110] mov w3,#0 ldr w4,=0xffffff01 z_loop: delay_loop1: sub w4, w4, #1 cmp w4, #0 b.gt delay_loop1 ldr w1, [x0, #0x114] add w3, w3, #1 cmp w1, #0 //'\n' b.eq 1f cmp w3, #20 b.gt 1f b z_loop 1: ldr w4,=0xffffff02 delay_loop2: sub w4, w4, #1 cmp w4, #0 b.gt delay_loop2 ldr w1, =0x00000000 str w1, [x0] ret x29 endfunc platform_mem_init func apply_platform_errata /*TODO if needed*/ ret endfunc apply_platform_errata func plat_reset_handler mov x29, x30 bl apply_platform_errata mov x30, x29 ret endfunc plat_reset_handler trusted-firmware-a-2.2/plat/layerscape/board/ls1043/include/000077500000000000000000000000001355360272700236415ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/layerscape/board/ls1043/include/ls_def.h000066400000000000000000000063441355360272700252550ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef LS_DEF_H #define LS_DEF_H #include #include #include #include #include #include /****************************************************************************** * Definitions common to all ARM standard platforms *****************************************************************************/ /* Special value used to verify platform parameters from BL2 to BL31 */ #define LS_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL #define LS_CACHE_WRITEBACK_SHIFT 6 /* * Macros mapping the MPIDR Affinity levels to Layerscape Platform Power levels. The * power levels have a 1:1 mapping with the MPIDR affinity levels. */ #define LS_PWR_LVL0 MPIDR_AFFLVL0 #define LS_PWR_LVL1 MPIDR_AFFLVL1 #define LS_PWR_LVL2 MPIDR_AFFLVL2 /* * Macros for local power states in Layerscape platforms encoded by State-ID field * within the power-state parameter. */ /* Local power state for power domains in Run state. */ #define LS_LOCAL_STATE_RUN U(0) /* Local power state for retention. Valid only for CPU power domains */ #define LS_LOCAL_STATE_RET U(1) /* * Local power state for OFF/power-down. Valid for CPU and cluster power * domains */ #define LS_LOCAL_STATE_OFF U(2) #define LS_MAP_NS_DRAM MAP_REGION_FLAT( \ (LS_NS_DRAM_BASE), \ LS_DRAM1_SIZE, \ MT_DEVICE | MT_RW | MT_NS) #define LS_MAP_TSP_SEC_MEM MAP_REGION_FLAT( \ TSP_SEC_MEM_BASE, \ TSP_SEC_MEM_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define LS_MAP_FLASH0_RW MAP_REGION_FLAT(PLAT_LS_FLASH_BASE,\ PLAT_LS_FLASH_SIZE, \ MT_DEVICE | MT_RW) #define LS_MAP_CCSR MAP_REGION_FLAT(PLAT_LS_CCSR_BASE, \ PLAT_LS_CCSR_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define LS_MAP_CONSOLE MAP_REGION_FLAT(PLAT_LS1043_DUART1_BASE, \ PLAT_LS1043_DUART_SIZE, \ MT_DEVICE | MT_RW | MT_NS) /* * The number of regions like RO(code), coherent and data required by * different BL stages which need to be mapped in the MMU. */ /****************************************************************************** * Required platform porting definitions common to all ARM standard platforms *****************************************************************************/ #define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32) /* * This macro defines the deepest retention state possible. A higher state * id will represent an invalid or a power down state. */ #define PLAT_MAX_RET_STATE LS_LOCAL_STATE_RET /* * This macro defines the deepest power down states possible. Any state ID * higher than this is invalid. */ #define PLAT_MAX_OFF_STATE LS_LOCAL_STATE_OFF /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. */ #define CACHE_WRITEBACK_GRANULE (1 << LS_CACHE_WRITEBACK_SHIFT) /* * One cache line needed for bakery locks on Layerscape platforms */ #define PLAT_PERCPU_BAKERY_LOCK_SIZE (1 * CACHE_WRITEBACK_GRANULE) #endif /* LS_DEF_H */ trusted-firmware-a-2.2/plat/layerscape/board/ls1043/include/ns_access.h000066400000000000000000000102441355360272700257540ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef NS_ACCESS_H #define NS_ACCESS_H #include "fsl_csu.h" enum csu_cslx_ind { CSU_CSLX_PCIE2_IO = 0, CSU_CSLX_PCIE1_IO, CSU_CSLX_MG2TPR_IP, CSU_CSLX_IFC_MEM, CSU_CSLX_OCRAM, CSU_CSLX_GIC, CSU_CSLX_PCIE1, CSU_CSLX_OCRAM2, CSU_CSLX_QSPI_MEM, CSU_CSLX_PCIE2, CSU_CSLX_SATA, CSU_CSLX_USB1, CSU_CSLX_QM_BM_SWPORTAL, CSU_CSLX_PCIE3 = 16, CSU_CSLX_PCIE3_IO, CSU_CSLX_USB3 = 20, CSU_CSLX_USB2, CSU_CSLX_PFE = 23, CSU_CSLX_SERDES = 32, CSU_CSLX_QDMA, CSU_CSLX_LPUART2, CSU_CSLX_LPUART1, CSU_CSLX_LPUART4, CSU_CSLX_LPUART3, CSU_CSLX_LPUART6, CSU_CSLX_LPUART5, CSU_CSLX_DSPI1 = 41, CSU_CSLX_QSPI, CSU_CSLX_ESDHC, CSU_CSLX_IFC = 45, CSU_CSLX_I2C1, CSU_CSLX_USB_2, CSU_CSLX_I2C3 = 48, CSU_CSLX_I2C2, CSU_CSLX_DUART2 = 50, CSU_CSLX_DUART1, CSU_CSLX_WDT2, CSU_CSLX_WDT1, CSU_CSLX_EDMA, CSU_CSLX_SYS_CNT, CSU_CSLX_DMA_MUX2, CSU_CSLX_DMA_MUX1, CSU_CSLX_DDR, CSU_CSLX_QUICC, CSU_CSLX_DCFG_CCU_RCPM = 60, CSU_CSLX_SECURE_BOOTROM, CSU_CSLX_SFP, CSU_CSLX_TMU, CSU_CSLX_SECURE_MONITOR, CSU_CSLX_SCFG, CSU_CSLX_FM = 66, CSU_CSLX_SEC5_5, CSU_CSLX_BM, CSU_CSLX_QM, CSU_CSLX_GPIO2 = 70, CSU_CSLX_GPIO1, CSU_CSLX_GPIO4, CSU_CSLX_GPIO3, CSU_CSLX_PLATFORM_CONT, CSU_CSLX_CSU, CSU_CSLX_IIC4 = 77, CSU_CSLX_WDT4, CSU_CSLX_WDT3, CSU_CSLX_ESDHC2 = 80, CSU_CSLX_WDT5 = 81, CSU_CSLX_SAI2, CSU_CSLX_SAI1, CSU_CSLX_SAI4, CSU_CSLX_SAI3, CSU_CSLX_FTM2 = 86, CSU_CSLX_FTM1, CSU_CSLX_FTM4, CSU_CSLX_FTM3, CSU_CSLX_FTM6 = 90, CSU_CSLX_FTM5, CSU_CSLX_FTM8, CSU_CSLX_FTM7, CSU_CSLX_DSCR = 121, }; static struct csu_ns_dev ns_dev[] = { {CSU_CSLX_PCIE2_IO, CSU_ALL_RW}, {CSU_CSLX_PCIE1_IO, CSU_ALL_RW}, {CSU_CSLX_MG2TPR_IP, CSU_ALL_RW}, {CSU_CSLX_IFC_MEM, CSU_ALL_RW}, {CSU_CSLX_OCRAM, CSU_ALL_RW}, {CSU_CSLX_GIC, CSU_ALL_RW}, {CSU_CSLX_PCIE1, CSU_ALL_RW}, {CSU_CSLX_OCRAM2, CSU_ALL_RW}, {CSU_CSLX_QSPI_MEM, CSU_ALL_RW}, {CSU_CSLX_PCIE2, CSU_ALL_RW}, {CSU_CSLX_SATA, CSU_ALL_RW}, {CSU_CSLX_USB1, CSU_ALL_RW}, {CSU_CSLX_QM_BM_SWPORTAL, CSU_ALL_RW}, {CSU_CSLX_PCIE3, CSU_ALL_RW}, {CSU_CSLX_PCIE3_IO, CSU_ALL_RW}, {CSU_CSLX_USB3, CSU_ALL_RW}, {CSU_CSLX_USB2, CSU_ALL_RW}, {CSU_CSLX_PFE, CSU_ALL_RW}, {CSU_CSLX_SERDES, CSU_ALL_RW}, {CSU_CSLX_QDMA, CSU_ALL_RW}, {CSU_CSLX_LPUART2, CSU_ALL_RW}, {CSU_CSLX_LPUART1, CSU_ALL_RW}, {CSU_CSLX_LPUART4, CSU_ALL_RW}, {CSU_CSLX_LPUART3, CSU_ALL_RW}, {CSU_CSLX_LPUART6, CSU_ALL_RW}, {CSU_CSLX_LPUART5, CSU_ALL_RW}, {CSU_CSLX_DSPI1, CSU_ALL_RW}, {CSU_CSLX_QSPI, CSU_ALL_RW}, {CSU_CSLX_ESDHC, CSU_ALL_RW}, {CSU_CSLX_IFC, CSU_ALL_RW}, {CSU_CSLX_I2C1, CSU_ALL_RW}, {CSU_CSLX_USB_2, CSU_ALL_RW}, {CSU_CSLX_I2C3, CSU_ALL_RW}, {CSU_CSLX_I2C2, CSU_ALL_RW}, {CSU_CSLX_DUART2, CSU_ALL_RW}, {CSU_CSLX_DUART1, CSU_ALL_RW}, {CSU_CSLX_WDT2, CSU_ALL_RW}, {CSU_CSLX_WDT1, CSU_ALL_RW}, {CSU_CSLX_EDMA, CSU_ALL_RW}, {CSU_CSLX_SYS_CNT, CSU_ALL_RW}, {CSU_CSLX_DMA_MUX2, CSU_ALL_RW}, {CSU_CSLX_DMA_MUX1, CSU_ALL_RW}, {CSU_CSLX_DDR, CSU_ALL_RW}, {CSU_CSLX_QUICC, CSU_ALL_RW}, {CSU_CSLX_DCFG_CCU_RCPM, CSU_ALL_RW}, {CSU_CSLX_SECURE_BOOTROM, CSU_ALL_RW}, {CSU_CSLX_SFP, CSU_ALL_RW}, {CSU_CSLX_TMU, CSU_ALL_RW}, {CSU_CSLX_SECURE_MONITOR, CSU_ALL_RW}, {CSU_CSLX_SCFG, CSU_ALL_RW}, {CSU_CSLX_FM, CSU_ALL_RW}, {CSU_CSLX_SEC5_5, CSU_ALL_RW}, {CSU_CSLX_BM, CSU_ALL_RW}, {CSU_CSLX_QM, CSU_ALL_RW}, {CSU_CSLX_GPIO2, CSU_ALL_RW}, {CSU_CSLX_GPIO1, CSU_ALL_RW}, {CSU_CSLX_GPIO4, CSU_ALL_RW}, {CSU_CSLX_GPIO3, CSU_ALL_RW}, {CSU_CSLX_PLATFORM_CONT, CSU_ALL_RW}, {CSU_CSLX_CSU, CSU_ALL_RW}, {CSU_CSLX_IIC4, CSU_ALL_RW}, {CSU_CSLX_WDT4, CSU_ALL_RW}, {CSU_CSLX_WDT3, CSU_ALL_RW}, {CSU_CSLX_ESDHC2, CSU_ALL_RW}, {CSU_CSLX_WDT5, CSU_ALL_RW}, {CSU_CSLX_SAI2, CSU_ALL_RW}, {CSU_CSLX_SAI1, CSU_ALL_RW}, {CSU_CSLX_SAI4, CSU_ALL_RW}, {CSU_CSLX_SAI3, CSU_ALL_RW}, {CSU_CSLX_FTM2, CSU_ALL_RW}, {CSU_CSLX_FTM1, CSU_ALL_RW}, {CSU_CSLX_FTM4, CSU_ALL_RW}, {CSU_CSLX_FTM3, CSU_ALL_RW}, {CSU_CSLX_FTM6, CSU_ALL_RW}, {CSU_CSLX_FTM5, CSU_ALL_RW}, {CSU_CSLX_FTM8, CSU_ALL_RW}, {CSU_CSLX_FTM7, CSU_ALL_RW}, {CSU_CSLX_DSCR, CSU_ALL_RW}, }; #endif /* NS_ACCESS_H */ trusted-firmware-a-2.2/plat/layerscape/board/ls1043/include/plat_macros.S000066400000000000000000000010201355360272700262620ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S /* --------------------------------------------- * The below required platform porting macro * prints out relevant GIC and CCI registers * whenever an unhandled exception is taken in * BL31. * Clobbers: x0 - x10, x16, x17, sp * --------------------------------------------- */ .macro plat_crash_print_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/layerscape/board/ls1043/include/platform_def.h000066400000000000000000000142161355360272700264600ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include "ls_def.h" #define FIRMWARE_WELCOME_STR_LS1043 "Welcome to LS1043 BL1 Phase\n" #define FIRMWARE_WELCOME_STR_LS1043_BL2 "Welcome to LS1043 BL2 Phase\n" #define FIRMWARE_WELCOME_STR_LS1043_BL31 "Welcome to LS1043 BL31 Phase\n" #define FIRMWARE_WELCOME_STR_LS1043_BL32 "Welcome to LS1043 BL32 Phase, TSP\n" /* Required platform porting definitions */ #define PLAT_PRIMARY_CPU 0x0 #define PLAT_MAX_PWR_LVL LS_PWR_LVL1 #define PLATFORM_CORE_COUNT 4 #define COUNTER_FREQUENCY 25000000 /* 25MHz */ /* * Required LS standard platform porting definitions */ #define PLAT_LS_CLUSTER_COUNT 1 #define PLAT_LS1043_CCI_CLUSTER0_SL_IFACE_IX 4 #define LS1043_CLUSTER_COUNT 1 #define LS1043_MAX_CPUS_PER_CLUSTER 4 #define LS_DRAM1_BASE 0x80000000 #define LS_DRAM2_BASE 0x880000000 #define LS_DRAM2_SIZE 0x780000000 /* 30G */ #define LS_DRAM1_SIZE 0x80000000 /* 2G */ #define LS_NS_DRAM_BASE LS_DRAM1_BASE /* 64M Secure Memory, in fact there a 2M non-secure hole on top of it */ #define LS_SECURE_DRAM_SIZE (64 * 1024 * 1024) #define LS_SECURE_DRAM_BASE (LS_NS_DRAM_BASE + LS_DRAM1_SIZE - \ LS_SECURE_DRAM_SIZE) #define LS_NS_DRAM_SIZE (LS_DRAM1_SIZE - LS_SECURE_DRAM_SIZE) /* * By default, BL2 is in DDR memory. * If LS_BL2_IN_OCRAM is defined, BL2 will in OCRAM */ /* #define LS_BL2_IN_OCRAM */ #ifndef LS_BL2_IN_OCRAM /* * on top of SECURE memory is 2M non-secure hole for OPTee, * 1M secure memory below this hole will be used for BL2. */ #define LS_BL2_DDR_BASE (LS_SECURE_DRAM_BASE + \ LS_SECURE_DRAM_SIZE \ - 3 * 1024 * 1024) #endif #define PLAT_LS_CCSR_BASE 0x1000000 #define PLAT_LS_CCSR_SIZE 0xF000000 /* Flash base address, currently ROM is not used for TF-A images on LS platforms */ #define PLAT_LS_TRUSTED_ROM_BASE 0x60100000 #define PLAT_LS_TRUSTED_ROM_SIZE 0x20000000 /* Flash size */ #define PLAT_LS_FLASH_SIZE 0x20000000 #define PLAT_LS_FLASH_BASE 0x60000000 #define LS_SRAM_BASE 0x10000000 #define LS_SRAM_LIMIT 0x10020000 /* 128K */ #define LS_SRAM_SHARED_SIZE 0x1000 /* 4K */ #define LS_SRAM_SIZE (LS_SRAM_LIMIT - LS_SRAM_BASE) #define LS_BL_RAM_BASE (LS_SRAM_BASE + LS_SRAM_SHARED_SIZE) #define PLAT_LS_FIP_MAX_SIZE 0x4000000 /* Memory Layout */ #define BL1_RO_BASE PLAT_LS_TRUSTED_ROM_BASE #define BL1_RO_LIMIT (PLAT_LS_TRUSTED_ROM_BASE \ + PLAT_LS_TRUSTED_ROM_SIZE) #define PLAT_LS_FIP_BASE 0x60120000 #ifdef LS_BL2_IN_OCRAM /* BL2 is in OCRAM */ #define PLAT_LS_MAX_BL1_RW_SIZE (52 * 1024) /* 52K */ #define PLAT_LS_MAX_BL31_SIZE (64 * 1024) /* 64K */ #define PLAT_LS_MAX_BL2_SIZE (44 * 1024) /* 44K */ /* Reserve memory in OCRAM for BL31 Text and ROData segment */ #define BL31_TEXT_RODATA_SIZE (32 * 1024) /* 32K */ #else /* LS_BL2_IN_OCRAM */ /* BL2 in DDR */ #define PLAT_LS_MAX_BL1_RW_SIZE (64 * 1024) /* 64K */ #define PLAT_LS_MAX_BL31_SIZE (64 * 1024) /* 64K */ #define PLAT_LS_MAX_BL2_SIZE (1 * 1024 * 1024) /* 1M */ #endif /* LS_BL2_IN_OCRAM */ /* * Put BL31 at the start of OCRAM. */ #define BL31_BASE LS_SRAM_BASE #define BL31_LIMIT (LS_SRAM_BASE + PLAT_LS_MAX_BL31_SIZE) #ifdef LS_BL2_IN_OCRAM /* * BL2 follow BL31 Text and ROData region. */ #define BL2_BASE (BL31_BASE + BL31_TEXT_RODATA_SIZE) #define BL2_LIMIT (BL2_BASE + PLAT_LS_MAX_BL2_SIZE) #else /* * BL2 in DDR memory. */ #define BL2_BASE LS_BL2_DDR_BASE #define BL2_LIMIT (BL2_BASE + PLAT_LS_MAX_BL2_SIZE) #endif /* * Put BL1 RW at the top of the Trusted SRAM. */ #ifdef LS_BL2_IN_OCRAM #define BL1_RW_BASE BL2_LIMIT #else #define BL1_RW_BASE BL31_LIMIT #endif #define BL1_RW_LIMIT LS_SRAM_LIMIT /* Put BL32 in secure memory */ #define BL32_BASE LS_SECURE_DRAM_BASE #define BL32_LIMIT (LS_SECURE_DRAM_BASE + LS_SECURE_DRAM_SIZE) /* BL33 memory region */ #define BL33_BASE 0x82000000 #define BL33_LIMIT (LS_NS_DRAM_BASE + LS_NS_DRAM_SIZE) /******************************************************************************* * BL32 specific defines. ******************************************************************************/ /* * On ARM standard platforms, the TSP can execute from Trusted SRAM, * Trusted DRAM (if available) or the DRAM region secured by the TrustZone * controller. */ #define TSP_SEC_MEM_BASE BL32_BASE #define TSP_SEC_MEM_SIZE (BL32_LIMIT - BL32_BASE) /* * ID of the secure physical generic timer interrupt used by the TSP. */ #define TSP_IRQ_SEC_PHY_TIMER 29 /* * GIC related constants */ #define PLAT_LS1043_CCI_BASE 0x01180000 #define GICD_BASE 0x01401000 #define GICC_BASE 0x01402000 #define GICD_BASE_64K 0x01410000 #define GICC_BASE_64K 0x01420000 #define DCFG_CCSR_SVR 0x1ee00a4 #define REV1_0 0x10 #define REV1_1 0x11 #define GIC_ADDR_BIT 31 #define SCFG_GIC400_ALIGN 0x1570188 /* UART related definition */ #define PLAT_LS1043_DUART1_BASE 0x021c0000 #define PLAT_LS1043_DUART2_BASE 0x021d0000 #define PLAT_LS1043_DUART_SIZE 0x10000 #define PLAT_LS1043_UART_BASE 0x21c0500 #define PLAT_LS1043_UART2_BASE 0x21c0600 #define PLAT_LS1043_UART_CLOCK 400000000 #define PLAT_LS1043_UART_BAUDRATE 115200 /* Define UART to be used by TF-A log */ #define LS_TF_UART_BASE PLAT_LS1043_UART_BASE #define LS_TF_UART_CLOCK PLAT_LS1043_UART_CLOCK #define LS_TF_UART_BAUDRATE PLAT_LS1043_UART_BAUDRATE #define LS1043_SYS_CNTCTL_BASE 0x2B00000 #define CONFIG_SYS_IMMR 0x01000000 #define CONFIG_SYS_FSL_CSU_ADDR (CONFIG_SYS_IMMR + 0x00510000) /* Size of cacheable stacks */ #if defined(IMAGE_BL1) #define PLATFORM_STACK_SIZE 0x440 #define MAX_MMAP_REGIONS 6 #define MAX_XLAT_TABLES 4 #elif defined(IMAGE_BL2) #define PLATFORM_STACK_SIZE 0x400 #define MAX_MMAP_REGIONS 8 #define MAX_XLAT_TABLES 6 #elif defined(IMAGE_BL31) #define PLATFORM_STACK_SIZE 0x400 #define MAX_MMAP_REGIONS 8 #define MAX_XLAT_TABLES 4 #elif defined(IMAGE_BL32) #define PLATFORM_STACK_SIZE 0x440 #define MAX_MMAP_REGIONS 8 #define MAX_XLAT_TABLES 9 #endif #define MAX_IO_DEVICES 3 #define MAX_IO_HANDLES 4 #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/layerscape/board/ls1043/include/soc_tzasc.h000066400000000000000000000053501355360272700260050ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SOC_TZASC_H #define SOC_TZASC_H #define MAX_NUM_TZC_REGION 3 /* TZASC related constants */ #define TZASC_CONFIGURATION_REG 0x000 #define TZASC_SECURITY_INV_REG 0x034 #define TZASC_SECURITY_INV_EN 0x1 #define TZASC_REGIONS_REG 0x100 /* As region address should address atleast 32KB memory. */ #define TZASC_REGION_LOWADDR_MASK 0xFFFF8000 #define TZASC_REGION_LOWADDR_OFFSET 0x0 #define TZASC_REGION_HIGHADDR_OFFSET 0x4 #define TZASC_REGION_ATTR_OFFSET 0x8 #define TZASC_REGION_ENABLED 1 #define TZASC_REGION_DISABLED 0 #define TZASC_REGION_SIZE_32KB 0xE #define TZASC_REGION_SIZE_64KB 0xF #define TZASC_REGION_SIZE_128KB 0x10 #define TZASC_REGION_SIZE_256KB 0x11 #define TZASC_REGION_SIZE_512KB 0x12 #define TZASC_REGION_SIZE_1MB 0x13 #define TZASC_REGION_SIZE_2MB 0x14 #define TZASC_REGION_SIZE_4MB 0x15 #define TZASC_REGION_SIZE_8MB 0x16 #define TZASC_REGION_SIZE_16MB 0x17 #define TZASC_REGION_SIZE_32MB 0x18 #define TZASC_REGION_SIZE_64MB 0x19 #define TZASC_REGION_SIZE_128MB 0x1A #define TZASC_REGION_SIZE_256MB 0x1B #define TZASC_REGION_SIZE_512MB 0x1C #define TZASC_REGION_SIZE_1GB 0x1D #define TZASC_REGION_SIZE_2GB 0x1E #define TZASC_REGION_SIZE_4GB 0x1F #define TZASC_REGION_SIZE_8GB 0x20 #define TZASC_REGION_SIZE_16GB 0x21 #define TZASC_REGION_SIZE_32GB 0x22 #define TZASC_REGION_SECURITY_SR (1 << 3) #define TZASC_REGION_SECURITY_SW (1 << 2) #define TZASC_REGION_SECURITY_SRW (TZASC_REGION_SECURITY_SR| \ TZASC_REGION_SECURITY_SW) #define TZASC_REGION_SECURITY_NSR (1 << 1) #define TZASC_REGION_SECURITY_NSW 1 #define TZASC_REGION_SECURITY_NSRW (TZASC_REGION_SECURITY_NSR| \ TZASC_REGION_SECURITY_NSW) #define CSU_SEC_ACCESS_REG_OFFSET 0x21C #define TZASC_BYPASS_MUX_DISABLE 0x4 #define CCI_TERMINATE_BARRIER_TX 0x8 #define CONFIG_SYS_FSL_TZASC_ADDR 0x1500000 struct tzc380_reg { unsigned int secure; unsigned int enabled; unsigned int low_addr; unsigned int high_addr; unsigned int size; unsigned int sub_mask; }; /* List of MAX_NUM_TZC_REGION TZC regions' boundaries and configurations. */ static const struct tzc380_reg tzc380_reg_list[] = { { TZASC_REGION_SECURITY_NSRW, /* .secure attr */ 0x0, /* .enabled */ 0x0, /* .lowaddr */ 0x0, /* .highaddr */ 0x0, /* .size */ 0x0, /* .submask */ }, { TZASC_REGION_SECURITY_SRW, TZASC_REGION_ENABLED, 0xFC000000, 0x0, TZASC_REGION_SIZE_64MB, 0x80, /* Disable region 7 */ }, /* reserve 2M non-scure memory for OPTEE public memory */ { TZASC_REGION_SECURITY_SRW, TZASC_REGION_ENABLED, 0xFF800000, 0x0, TZASC_REGION_SIZE_8MB, 0xC0, /* Disable region 6 & 7 */ }, {} }; #endif /* SOC_TZASC_H */ trusted-firmware-a-2.2/plat/layerscape/board/ls1043/ls1043_bl1_setup.c000066400000000000000000000025451355360272700252740ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "plat_ls.h" static const int cci_map[] = { PLAT_LS1043_CCI_CLUSTER0_SL_IFACE_IX }; void bl1_platform_setup(void) { NOTICE(FIRMWARE_WELCOME_STR_LS1043); ls_bl1_platform_setup(); /* * Initialize system level generic timer for Layerscape Socs. */ ls_delay_timer_init(); /* TODO: remove these DDR code */ VERBOSE("CS0_BNDS = %x\n", mmio_read_32(0x1080000 + 0x000)); mmio_write_32(0x1080000 + 0x000, 0x7f000000); VERBOSE("CS0_BNDS = %x\n", mmio_read_32(0x1080000 + 0x000)); } /******************************************************************************* * Perform any BL1 specific platform actions. ******************************************************************************/ void bl1_early_platform_setup(void) { ls_bl1_early_platform_setup(); /* * Initialize Interconnect for this cluster during cold boot. * No need for locks as no other CPU is active. */ cci_init(PLAT_LS1043_CCI_BASE, cci_map, ARRAY_SIZE(cci_map)); /* * Enable coherency in Interconnect for the primary CPU's cluster. */ cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr())); } unsigned int bl1_plat_get_next_image_id(void) { return BL2_IMAGE_ID; } trusted-firmware-a-2.2/plat/layerscape/board/ls1043/ls1043_bl2_setup.c000066400000000000000000000010251355360272700252650ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "plat_ls.h" void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { ls_bl2_early_platform_setup((meminfo_t *)arg1); /* * Initialize system level generic timer for Layerscape Socs. */ ls_delay_timer_init(); } void bl2_platform_setup(void) { NOTICE(FIRMWARE_WELCOME_STR_LS1043_BL2); } trusted-firmware-a-2.2/plat/layerscape/board/ls1043/ls1043_bl31_setup.c000066400000000000000000000027761355360272700253650ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "plat_ls.h" #include "fsl_csu.h" /* slave interfaces according to the RM */ static const int cci_map[] = { 4, }; void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { #ifdef LS_BL2_IN_OCRAM unsigned long romem_base = (unsigned long)(&__TEXT_START__); unsigned long romem_size = (unsigned long)(&__RODATA_END__) - romem_base; /* Check the Text and RO-Data region size */ if (romem_size > BL31_TEXT_RODATA_SIZE) { ERROR("BL31 Text and RO-Data region size exceed reserved memory size\n"); panic(); } #endif /* * Initialize system level generic timer for Layerscape Socs. */ ls_delay_timer_init(); ls_bl31_early_platform_setup((void *)arg0, (void *)arg3); /* * Initialize the correct interconnect for this cluster during cold * boot. No need for locks as no other CPU is active. */ cci_init(PLAT_LS1043_CCI_BASE, cci_map, ARRAY_SIZE(cci_map)); /* * Enable coherency in interconnect for the primary CPU's cluster. * Earlier bootloader stages might already do this (e.g. Trusted * Firmware's BL1 does it) but we can't assume so. There is no harm in * executing this code twice anyway. */ cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr())); /* Init CSU to enable non-secure access to peripherals */ enable_layerscape_ns_access(); } trusted-firmware-a-2.2/plat/layerscape/board/ls1043/ls1043_err.c000066400000000000000000000007171355360272700241650ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /* * Error handler */ void plat_error_handler(int err) { switch (err) { case -ENOENT: case -EAUTH: /* ToDo */ break; default: /* Unexpected error */ break; } /* Loop until the watchdog resets the system */ for (;;) wfi(); } trusted-firmware-a-2.2/plat/layerscape/board/ls1043/ls1043_psci.c000066400000000000000000000103451355360272700243310ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #define LS_SCFG_BASE 0x01570000 /* register to store warm boot entry, big endian, higher 32bit */ #define LS_SCFG_SCRATCHRW0_OFFSET 0x600 /* register to store warm boot entry, big endian, lower 32bit */ #define LS_SCFG_SCRATCHRW1_OFFSET 0x604 #define LS_SCFG_COREBCR_OFFSET 0x680 #define LS_DCFG_BASE 0x01EE0000 #define LS_DCFG_RSTCR_OFFSET 0x0B0 #define LS_DCFG_RSTRQMR1_OFFSET 0x0C0 #define LS_DCFG_BRR_OFFSET 0x0E4 #define LS_SCFG_CORE0_SFT_RST_OFFSET 0x130 #define LS_SCFG_CORE1_SFT_RST_OFFSET 0x134 #define LS_SCFG_CORE2_SFT_RST_OFFSET 0x138 #define LS_SCFG_CORE3_SFT_RST_OFFSET 0x13C #define LS_SCFG_CORESRENCR_OFFSET 0x204 #define LS_SCFG_RVBAR0_0_OFFSET 0x220 #define LS_SCFG_RVBAR0_1_OFFSET 0x224 #define LS_SCFG_RVBAR1_0_OFFSET 0x228 #define LS_SCFG_RVBAR1_1_OFFSET 0x22C #define LS_SCFG_RVBAR2_0_OFFSET 0x230 #define LS_SCFG_RVBAR2_1_OFFSET 0x234 #define LS_SCFG_RVBAR3_0_OFFSET 0x238 #define LS_SCFG_RVBAR3_1_OFFSET 0x23C /* the entry for core warm boot */ static uintptr_t warmboot_entry; /* warm reset single core */ static void ls1043_reset_core(int core_pos) { assert(core_pos >= 0 && core_pos < PLATFORM_CORE_COUNT); /* set 0 in RVBAR, boot from bootrom at 0x0 */ mmio_write_32(LS_SCFG_BASE + LS_SCFG_RVBAR0_0_OFFSET + core_pos * 8, 0); mmio_write_32(LS_SCFG_BASE + LS_SCFG_RVBAR0_1_OFFSET + core_pos * 8, 0); dsb(); /* enable core soft reset */ mmio_write_32(LS_SCFG_BASE + LS_SCFG_CORESRENCR_OFFSET, htobe32(1U << 31)); dsb(); isb(); /* reset core */ mmio_write_32(LS_SCFG_BASE + LS_SCFG_CORE0_SFT_RST_OFFSET + core_pos * 4, htobe32(1U << 31)); mdelay(10); } static void __dead2 ls1043_system_reset(void) { /* clear reset request mask bits */ mmio_write_32(LS_DCFG_BASE + LS_DCFG_RSTRQMR1_OFFSET, 0); /* set reset request bit */ mmio_write_32(LS_DCFG_BASE + LS_DCFG_RSTCR_OFFSET, htobe32((uint32_t)0x2)); /* system will reset; if fail, enter wfi */ dsb(); isb(); wfi(); panic(); } static int ls1043_pwr_domain_on(u_register_t mpidr) { int core_pos = plat_core_pos_by_mpidr(mpidr); uint32_t core_mask, brr; assert(core_pos >= 0 && core_pos < PLATFORM_CORE_COUNT); core_mask = 1 << core_pos; /* set warm boot entry */ mmio_write_32(LS_SCFG_BASE + LS_SCFG_SCRATCHRW0_OFFSET, htobe32((uint32_t)(warmboot_entry >> 32))); mmio_write_32(LS_SCFG_BASE + LS_SCFG_SCRATCHRW1_OFFSET, htobe32((uint32_t)warmboot_entry)); dsb(); brr = be32toh(mmio_read_32(LS_DCFG_BASE + LS_DCFG_BRR_OFFSET)); if (brr & core_mask) { /* core has been released, must reset it to restart */ ls1043_reset_core(core_pos); /* set bit in core boot control register to enable boot */ mmio_write_32(LS_SCFG_BASE + LS_SCFG_COREBCR_OFFSET, htobe32(core_mask)); } else { /* set bit in core boot control register to enable boot */ mmio_write_32(LS_SCFG_BASE + LS_SCFG_COREBCR_OFFSET, htobe32(core_mask)); /* release core */ mmio_write_32(LS_DCFG_BASE + LS_DCFG_BRR_OFFSET, htobe32(brr | core_mask)); } mdelay(20); /* wake core in case it is in wfe */ dsb(); isb(); sev(); return PSCI_E_SUCCESS; } static void ls1043_pwr_domain_on_finish(const psci_power_state_t *target_state) { /* Per cpu gic distributor setup */ gicv2_pcpu_distif_init(); /* Enable the gic CPU interface */ gicv2_cpuif_enable(); } static void ls1043_pwr_domain_off(const psci_power_state_t *target_state) { /* Disable the gic CPU interface */ gicv2_cpuif_disable(); } static plat_psci_ops_t ls1043_psci_pm_ops = { .system_reset = ls1043_system_reset, .pwr_domain_on = ls1043_pwr_domain_on, .pwr_domain_on_finish = ls1043_pwr_domain_on_finish, .pwr_domain_off = ls1043_pwr_domain_off, }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { warmboot_entry = sec_entrypoint; *psci_ops = &ls1043_psci_pm_ops; return 0; } trusted-firmware-a-2.2/plat/layerscape/board/ls1043/ls1043_security.c000066400000000000000000000004321355360272700252360ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "plat_ls.h" /* * We assume that all security programming is done by the primary core. */ void plat_ls_security_setup(void) { tzc380_setup(); } trusted-firmware-a-2.2/plat/layerscape/board/ls1043/ls1043_stack_protector.c000066400000000000000000000011401355360272700265720ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #define RANDOM_CANARY_VALUE ((u_register_t) 3288484550995823360ULL) u_register_t plat_get_stack_protector_canary(void) { /* * Ideally, a random number should be returned instead of the * combination of a timer's value and a compile-time constant. As the * FVP does not have any random number generator, this is better than * nothing but not necessarily really secure. */ return RANDOM_CANARY_VALUE ^ read_cntpct_el0(); } trusted-firmware-a-2.2/plat/layerscape/board/ls1043/ls1043_topology.c000066400000000000000000000035271355360272700252530ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "plat_ls.h" #include "platform_def.h" unsigned char ls1043_power_domain_tree_desc[LS1043_CLUSTER_COUNT + 1]; CASSERT(LS1043_CLUSTER_COUNT && LS1043_CLUSTER_COUNT <= 256, assert_invalid_ls1043_cluster_count); /******************************************************************************* * This function dynamically constructs the topology according to * LS1043_CLUSTER_COUNT and returns it. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { int i; ls1043_power_domain_tree_desc[0] = LS1043_CLUSTER_COUNT; for (i = 0; i < LS1043_CLUSTER_COUNT; i++) ls1043_power_domain_tree_desc[i + 1] = LS1043_MAX_CPUS_PER_CLUSTER; return ls1043_power_domain_tree_desc; } /******************************************************************************* * This function returns the core count within the cluster corresponding to * `mpidr`. ******************************************************************************/ unsigned int plat_ls_get_cluster_core_count(u_register_t mpidr) { return LS1043_MAX_CPUS_PER_CLUSTER; } /******************************************************************************* * This function implements a part of the critical interface between the psci * generic layer and the platform that allows the former to query the platform * to convert an MPIDR to a unique linear index. An error code (-1) is returned * in case the MPIDR is invalid. ******************************************************************************/ int plat_core_pos_by_mpidr(u_register_t mpidr) { if (ls_check_mpidr(mpidr) == -1) return -1; return plat_ls_calc_core_pos(mpidr); } trusted-firmware-a-2.2/plat/layerscape/board/ls1043/ls_gic.c000066400000000000000000000021711355360272700236230ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "soc.h" /* * Get GIC offset * For LS1043a rev1.0, GIC base address align with 4k. * For LS1043a rev1.1, if DCFG_GIC400_ALIGN[GIC_ADDR_BIT] * is set, GIC base address align with 4K, or else align * with 64k. */ void get_gic_offset(uint32_t *gicc_base, uint32_t *gicd_base) { uint32_t *ccsr_svr = (uint32_t *)DCFG_CCSR_SVR; uint32_t *gic_align = (uint32_t *)SCFG_GIC400_ALIGN; uint32_t val; uint32_t soc_dev_id; val = be32toh(mmio_read_32((uintptr_t)ccsr_svr)); soc_dev_id = val & (SVR_WO_E << 8); if ((soc_dev_id == (SVR_LS1043A << 8) || soc_dev_id == (SVR_LS1043AE << 8)) && ((val & 0xff) == REV1_1)) { val = be32toh(mmio_read_32((uintptr_t)gic_align)); if (val & (1U << GIC_ADDR_BIT)) { *gicc_base = GICC_BASE; *gicd_base = GICD_BASE; } else { *gicc_base = GICC_BASE_64K; *gicd_base = GICD_BASE_64K; } } else { *gicc_base = GICC_BASE; *gicd_base = GICD_BASE; } } trusted-firmware-a-2.2/plat/layerscape/board/ls1043/platform.mk000066400000000000000000000042321355360272700243740ustar00rootroot00000000000000# # Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # indicate the reset vector address can be programmed PROGRAMMABLE_RESET_ADDRESS := 1 USE_COHERENT_MEM := 0 RESET_TO_BL31 := 0 ENABLE_STACK_PROTECTOR := 0 LS1043_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c \ plat/layerscape/board/ls1043/ls_gic.c LS1043_INTERCONNECT_SOURCES := drivers/arm/cci/cci.c LS1043_SECURITY_SOURCES := plat/layerscape/common/ls_tzc380.c \ plat/layerscape/board/ls1043/ls1043_security.c PLAT_INCLUDES := -Iplat/layerscape/board/ls1043/include \ -Iplat/layerscape/common/include \ PLAT_BL_COMMON_SOURCES := plat/layerscape/common/aarch64/ls_console.S LS1043_CPU_LIBS := lib/cpus/${ARCH}/aem_generic.S LS1043_CPU_LIBS += lib/cpus/aarch64/cortex_a53.S BL1_SOURCES += plat/layerscape/board/ls1043/ls1043_bl1_setup.c \ plat/layerscape/board/ls1043/ls1043_err.c \ drivers/delay_timer/delay_timer.c \ BL1_SOURCES += plat/layerscape/board/ls1043/${ARCH}/ls1043_helpers.S \ ${LS1043_CPU_LIBS} \ ${LS1043_INTERCONNECT_SOURCES} \ $(LS1043_SECURITY_SOURCES) BL2_SOURCES += drivers/delay_timer/delay_timer.c \ plat/layerscape/board/ls1043/ls1043_bl2_setup.c \ plat/layerscape/board/ls1043/ls1043_err.c \ ${LS1043_SECURITY_SOURCES} BL31_SOURCES += plat/layerscape/board/ls1043/ls1043_bl31_setup.c \ plat/layerscape/board/ls1043/ls1043_topology.c \ plat/layerscape/board/ls1043/aarch64/ls1043_helpers.S \ plat/layerscape/board/ls1043/ls1043_psci.c \ drivers/delay_timer/delay_timer.c \ ${LS1043_CPU_LIBS} \ ${LS1043_GIC_SOURCES} \ ${LS1043_INTERCONNECT_SOURCES} \ ${LS1043_SECURITY_SOURCES} # Enable workarounds for selected Cortex-A53 erratas. ERRATA_A53_855873 := 1 ifneq (${ENABLE_STACK_PROTECTOR},0) PLAT_BL_COMMON_SOURCES += plat/layerscape/board/ls1043/ls1043_stack_protector.c endif ifeq (${ARCH},aarch32) NEED_BL32 := yes endif include plat/layerscape/common/ls_common.mk trusted-firmware-a-2.2/plat/layerscape/board/ls1043/tsp/000077500000000000000000000000001355360272700230245ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/layerscape/board/ls1043/tsp/ls1043_tsp_setup.c000066400000000000000000000004431355360272700262250ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "plat_ls.h" void tsp_early_platform_setup(void) { ls_tsp_early_platform_setup(); /*Todo: Initialize the platform config for future decision making */ } trusted-firmware-a-2.2/plat/layerscape/board/ls1043/tsp/tsp-ls1043.mk000066400000000000000000000005521355360272700251110ustar00rootroot00000000000000# # Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # TSP source files specific to FVP platform BL32_SOURCES += plat/layerscape/board/ls1043/ls1043_topology.c \ plat/layerscape/board/ls1043/tsp/ls1043_tsp_setup.c \ ${LS1043_GIC_SOURCES} include plat/layerscape/common/tsp/ls_tsp.mk trusted-firmware-a-2.2/plat/layerscape/common/000077500000000000000000000000001355360272700214715ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/layerscape/common/aarch64/000077500000000000000000000000001355360272700227215ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/layerscape/common/aarch64/ls_bl2_mem_params_desc.c000066400000000000000000000063671355360272700274550ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /******************************************************************************* * Following descriptor provides BL image/ep information that gets used * by BL2 to load the images and also subset of this information is * passed to next BL image. The image loading sequence is managed by * populating the images in required loading order. The image execution * sequence is managed by populating the `next_handoff_image_id` with * the next executable image id. ******************************************************************************/ static bl_mem_params_node_t bl2_mem_params_descs[] = { #ifdef EL3_PAYLOAD_BASE /* Fill EL3 payload related information (BL31 is EL3 payload)*/ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = EL3_PAYLOAD_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING), .next_handoff_image_id = INVALID_IMAGE_ID, }, #else /* EL3_PAYLOAD_BASE */ /* Fill BL31 related information */ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = BL31_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), #if DEBUG .ep_info.args.arg1 = LS_BL31_PLAT_PARAM_VAL, #endif SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP), .image_info.image_base = BL31_BASE, .image_info.image_max_size = (BL31_LIMIT - BL31_BASE), # ifdef BL32_BASE .next_handoff_image_id = BL32_IMAGE_ID, # else .next_handoff_image_id = BL33_IMAGE_ID, # endif }, # ifdef BL32_BASE /* Fill BL32 related information */ { .image_id = BL32_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE), .ep_info.pc = BL32_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = BL32_BASE, .image_info.image_max_size = (BL32_LIMIT - BL32_BASE), .next_handoff_image_id = BL33_IMAGE_ID, }, # endif /* BL32_BASE */ /* Fill BL33 related information */ { .image_id = BL33_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), # ifdef PRELOADED_BL33_BASE .ep_info.pc = PRELOADED_BL33_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), # else .ep_info.pc = BL33_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = BL33_BASE, .image_info.image_max_size = LS_NS_DRAM_SIZE, # endif /* PRELOADED_BL33_BASE */ .next_handoff_image_id = INVALID_IMAGE_ID, } #endif /* EL3_PAYLOAD_BASE */ }; REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) trusted-firmware-a-2.2/plat/layerscape/common/aarch64/ls_console.S000066400000000000000000000165041355360272700252130ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "ls_16550.h" /* * "core" functions are low-level implementations that don't require * writable memory and are thus safe to call in BL1 crash context. */ .globl console_ls_16550_core_init .globl console_ls_16550_core_putc .globl console_ls_16550_core_getc .globl console_ls_16550_putc .globl console_ls_16550_getc .globl console_ls_16550_flush /* ----------------------------------------------- * int console_ls_16550_core_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. This * function will be accessed by console_init and * crash reporting. * In: x0 - console base address * w1 - Uart clock in Hz * w2 - Baud rate * Out: return 1 on success, 0 on error * Clobber list : x1, x2, x3 * ----------------------------------------------- */ func console_ls_16550_core_init /* Check the input base address */ cbz x0, init_fail /* Check baud rate and uart clock for sanity */ cbz w1, init_fail cbz w2, init_fail /* Program the baudrate */ /* Divisor = Uart clock / (16 * baudrate) */ lsl w2, w2, #4 udiv w2, w1, w2 and w1, w2, #0xff /* w1 = DLL */ lsr w2, w2, #8 and w2, w2, #0xff /* w2 = DLLM */ ldrb w3, [x0, #UARTLCR] orr w3, w3, #UARTLCR_DLAB strb w3, [x0, #UARTLCR] /* enable DLL, DLLM programming */ strb w1, [x0, #UARTDLL] /* program DLL */ strb w2, [x0, #UARTDLLM] /* program DLLM */ mov w2, #~UARTLCR_DLAB and w3, w3, w2 strb w3, [x0, #UARTLCR] /* disable DLL, DLLM programming */ /* 8n1 */ mov w3, #3 strb w3, [x0, #UARTLCR] /* no interrupt */ mov w3, #0 strb w3, [x0, #UARTIER] /* enable fifo, DMA */ mov w3, #(UARTFCR_FIFOEN |UARTFCR_TXCLR | UARTFCR_RXCLR) strb w3, [x0, #UARTFCR] /* DTR + RTS */ mov w3, #3 str w3, [x0, #UARTMCR] mov w0, #1 ret init_fail: mov w0, #0 ret endfunc console_ls_16550_core_init .globl console_ls_16550_register /* ----------------------------------------------- * int console_ls_16550_register(console_ls_16550_t *console, * uintptr_t base, uint32_t clk, uint32_t baud) * Function to initialize and register a new 16550 * console. Storage passed in for the console struct * *must* be persistent (i.e. not from the stack). * In: x0 - UART register base address * w1 - UART clock in Hz * w2 - Baud rate * x3 - pointer to empty console_ls_16550_t struct * Out: return 1 on success, 0 on error * Clobber list : x0, x1, x2, x6, x7, x14 * ----------------------------------------------- */ func console_ls_16550_register mov x7, x30 mov x6, x3 cbz x6, register_fail str x0, [x6, #CONSOLE_T_16550_BASE] bl console_ls_16550_core_init cbz x0, register_fail mov x0, x6 mov x30, x7 finish_console_register ls_16550 putc=1, getc=1, flush=1 register_fail: ret x7 endfunc console_ls_16550_register /* -------------------------------------------------------- * int console_ls_16550_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. * In : w0 - character to be printed * x1 - console base address * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_ls_16550_core_putc #if ENABLE_ASSERTIONS cmp x1, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ /* Prepend '\r' to '\n' */ cmp w0, #0xA //'\n' b.ne 2f /* Check if the transmit FIFO is full */ 1: ldrb w2, [x1, #UARTLSR] and w2, w2, #UARTLSR_THRE /* #(UARTLSR_TEMT | UARTLSR_THRE)*/ cmp w2, #(UARTLSR_THRE) b.ne 1b mov w2, #0xD /* '\r' */ strb w2, [x1, #UARTTX] ldrb w2, [x1, #UARTFCR] orr w2, w2, #UARTFCR_TXCLR /* Check if the transmit FIFO is full */ 2: ldrb w2, [x1, #UARTLSR] and w2, w2, #(UARTLSR_THRE) cmp w2, #(UARTLSR_THRE) b.ne 2b strb w0, [x1, #UARTTX] ret endfunc console_ls_16550_core_putc /* -------------------------------------------------------- * int console_16550_putc(int c, console_ls_16550_t *console) * Function to output a character over the console. It * returns the character printed on success or -1 on error. * In : w0 - character to be printed * x1 - pointer to console_t structure * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_ls_16550_putc #if ENABLE_ASSERTIONS cmp x1, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr x1, [x1, #CONSOLE_T_16550_BASE] b console_ls_16550_core_putc endfunc console_ls_16550_putc /* --------------------------------------------- * int console_ls_16550_core_getc(uintptr_t base_addr) * Function to get a character from the console. * It returns the character grabbed on success * or -1 on if no character is available. * In : x0 - console base address * Out : w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ func console_ls_16550_core_getc #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ /* Check if the receive FIFO is empty */ 1: ldrb w1, [x0, #UARTLSR] tbz w1, #UARTLSR_RDR, 1b ldrb w0, [x0, #UARTRX] ret no_char: mov w0, #ERROR_NO_PENDING_CHAR ret endfunc console_ls_16550_core_getc /* --------------------------------------------- * int console_ls_16550_getc(console_ls_16550_t *console) * Function to get a character from the console. * It returns the character grabbed on success * or -1 on if no character is available. * In : x0 - pointer to console_t structure * Out : w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ func console_ls_16550_getc #if ENABLE_ASSERTIONS cmp x1, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr x0, [x0, #CONSOLE_T_16550_BASE] b console_ls_16550_core_getc endfunc console_ls_16550_getc /* --------------------------------------------- * int console_ls_16550_core_flush(uintptr_t base_addr) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - console base address * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func console_ls_16550_core_flush #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ /* Loop until the transmit FIFO is empty */ 1: ldrb w1, [x0, #UARTLSR] and w1, w1, #(UARTLSR_TEMT | UARTLSR_THRE) cmp w1, #(UARTLSR_TEMT | UARTLSR_THRE) b.ne 1b mov w0, #0 ret endfunc console_ls_16550_core_flush /* --------------------------------------------- * int console_ls_16550_flush(console_ls_16550_t *console) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - pointer to console_t structure * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func console_ls_16550_flush #if ENABLE_ASSERTIONS cmp x0, #0 ASM_ASSERT(ne) #endif /* ENABLE_ASSERTIONS */ ldr x0, [x0, #CONSOLE_T_16550_BASE] b console_ls_16550_core_flush endfunc console_ls_16550_flush trusted-firmware-a-2.2/plat/layerscape/common/aarch64/ls_helpers.S000066400000000000000000000067631355360272700252210ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .weak plat_my_core_pos .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush .weak platform_mem_init .globl plat_ls_calc_core_pos /* ----------------------------------------------------- * unsigned int plat_my_core_pos(void) * This function uses the plat_ls_calc_core_pos() * definition to get the index of the calling CPU. * ----------------------------------------------------- */ func plat_my_core_pos mrs x0, mpidr_el1 b plat_ls_calc_core_pos endfunc plat_my_core_pos /* ----------------------------------------------------- * unsigned int plat_ls_calc_core_pos(u_register_t mpidr) * Helper function to calculate the core position. * With this function: CorePos = (ClusterId * 4) + * CoreId * ----------------------------------------------------- */ func plat_ls_calc_core_pos and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 ret endfunc plat_ls_calc_core_pos /* --------------------------------------------- * int plat_crash_console_init(void) * Function to initialize the crash console * without a C Runtime to print crash report. * Clobber list : x0 - x4 * --------------------------------------------- */ /* ----------------------------------------------------- * 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 /* --------------------------------------------------------------------- * We don't need to carry out any memory initialization on LS * platforms. The Secure SRAM is accessible straight away. * --------------------------------------------------------------------- */ func platform_mem_init ret endfunc platform_mem_init trusted-firmware-a-2.2/plat/layerscape/common/include/000077500000000000000000000000001355360272700231145ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/layerscape/common/include/fsl_csu.h000066400000000000000000000011251355360272700247220ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef FSL_CSU_H #define FSL_CSU_H enum csu_cslx_access { CSU_NS_SUP_R = 0x08, CSU_NS_SUP_W = 0x80, CSU_NS_SUP_RW = 0x88, CSU_NS_USER_R = 0x04, CSU_NS_USER_W = 0x40, CSU_NS_USER_RW = 0x44, CSU_S_SUP_R = 0x02, CSU_S_SUP_W = 0x20, CSU_S_SUP_RW = 0x22, CSU_S_USER_R = 0x01, CSU_S_USER_W = 0x10, CSU_S_USER_RW = 0x11, CSU_ALL_RW = 0xff, }; struct csu_ns_dev { uintptr_t ind; uint32_t val; }; void enable_layerscape_ns_access(void); #endif /* FSL_CSU_H */ trusted-firmware-a-2.2/plat/layerscape/common/include/ls_16550.h000066400000000000000000000054701355360272700244510ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef LS_16550_H #define LS_16550_H #include /* UART16550 Registers */ #define UARTTX 0x0 #define UARTRX 0x0 #define UARTDLL 0x0 #define UARTIER 0x1 #define UARTDLLM 0x1 #define UARTFCR 0x2 #define UARTLCR 0x3 #define UARTLSR 0x5 #define UARTMCR 0x4 /* FIFO Control Register bits */ #define UARTFCR_FIFOMD_16450 (0 << 6) #define UARTFCR_FIFOMD_16550 (1 << 6) #define UARTFCR_RXTRIG_1 (0 << 6) #define UARTFCR_RXTRIG_4 (1 << 6) #define UARTFCR_RXTRIG_8 (2 << 6) #define UARTFCR_RXTRIG_16 (3 << 6) #define UARTFCR_TXTRIG_1 (0 << 4) #define UARTFCR_TXTRIG_4 (1 << 4) #define UARTFCR_TXTRIG_8 (2 << 4) #define UARTFCR_TXTRIG_16 (3 << 4) #define UARTFCR_DMAEN (1 << 3) /* Enable DMA mode */ #define UARTFCR_TXCLR (1 << 2) /* Clear contents of Tx FIFO */ #define UARTFCR_RXCLR (1 << 1) /* Clear contents of Rx FIFO */ #define UARTFCR_FIFOEN (1 << 0) /* Enable the Tx/Rx FIFO */ #define UARTFCR_64FIFO (1 << 5) /* Line Control Register bits */ #define UARTLCR_DLAB (1 << 7) /* Divisor Latch Access */ #define UARTLCR_SETB (1 << 6) /* Set BREAK Condition */ #define UARTLCR_SETP (1 << 5) /* Set Parity to LCR[4] */ #define UARTLCR_EVEN (1 << 4) /* Even Parity Format */ #define UARTLCR_PAR (1 << 3) /* Parity */ #define UARTLCR_STOP (1 << 2) /* Stop Bit */ #define UARTLCR_WORDSZ_5 0 /* Word Length of 5 */ #define UARTLCR_WORDSZ_6 1 /* Word Length of 6 */ #define UARTLCR_WORDSZ_7 2 /* Word Length of 7 */ #define UARTLCR_WORDSZ_8 3 /* Word Length of 8 */ /* Line Status Register bits */ #define UARTLSR_RXFIFOEMT (1 << 9) /* Rx Fifo Empty */ #define UARTLSR_TXFIFOFULL (1 << 8) /* Tx Fifo Full */ #define UARTLSR_RXFIFOERR (1 << 7) /* Rx Fifo Error */ #define UARTLSR_TEMT (1 << 6) /* Tx Shift Register Empty */ #define UARTLSR_THRE (1 << 5) /* Tx Holding Register Empty */ #define UARTLSR_BRK (1 << 4) /* Break Condition Detected */ #define UARTLSR_FERR (1 << 3) /* Framing Error */ #define UARTLSR_PERR (1 << 3) /* Parity Error */ #define UARTLSR_OVRF (1 << 2) /* Rx Overrun Error */ #define UARTLSR_RDR (1 << 2) /* Rx Data Ready */ #define CONSOLE_T_16550_BASE CONSOLE_T_DRVDATA #ifndef __ASSEMBLER__ #include typedef struct { console_t console; uintptr_t base; } console_ls_16550_t; /* * Initialize a new 16550 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_ls_16550_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud, console_ls_16550_t *console); #endif /*__ASSEMBLER__*/ #endif /* LS_16550_H */ trusted-firmware-a-2.2/plat/layerscape/common/include/plat_ls.h000066400000000000000000000026031355360272700247240ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_LS_H #define PLAT_LS_H #include #include /* BL1 utility functions */ void ls_bl1_platform_setup(void); void ls_bl1_early_platform_setup(void); /* BL2 utility functions */ void ls_bl2_early_platform_setup(meminfo_t *mem_layout); uint32_t ls_get_spsr_for_bl32_entry(void); uint32_t ls_get_spsr_for_bl33_entry(void); /* BL3 utility functions */ void ls_bl31_early_platform_setup(void *from_bl2, void *plat_params_from_bl2); /* IO storage utility functions */ void plat_ls_io_setup(void); void ls_setup_page_tables(uintptr_t total_base, size_t total_size, uintptr_t code_start, uintptr_t code_limit, uintptr_t rodata_start, uintptr_t rodata_limit #if USE_COHERENT_MEM , uintptr_t coh_start, uintptr_t coh_limit #endif ); /* PSCI utility functions */ int ls_check_mpidr(u_register_t mpidr); /* Security utility functions */ int tzc380_setup(void); /* Timer utility functions */ uint64_t ls_get_timer(uint64_t start); void ls_delay_timer_init(void); /* TSP utility functions */ void ls_tsp_early_platform_setup(void); /* Helper functions */ unsigned int plat_ls_calc_core_pos(u_register_t mpidr); /* others */ unsigned int plat_ls_get_cluster_core_count(u_register_t mpidr); #endif /* PLAT_LS_H */ trusted-firmware-a-2.2/plat/layerscape/common/include/soc.h000066400000000000000000000005371355360272700240560ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SOC_H #define SOC_H #include #define SVR_WO_E 0xFFFFFEu #define SVR_LS1043A 0x879204u #define SVR_LS1043AE 0x879200u void get_gic_offset(uint32_t *gicc_base, uint32_t *gicd_base); #endif /* SOC_H */ trusted-firmware-a-2.2/plat/layerscape/common/ls_bl1_setup.c000066400000000000000000000045651355360272700242430ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "ls_16550.h" #include "plat_ls.h" /* Data structure which holds the extents of the trusted SRAM for BL1*/ static meminfo_t bl1_tzram_layout; meminfo_t *bl1_plat_sec_mem_layout(void) { return &bl1_tzram_layout; } /******************************************************************************* * BL1 specific platform actions shared between ARM standard platforms. ******************************************************************************/ void ls_bl1_early_platform_setup(void) { static console_ls_16550_t console; #if !LS1043_DISABLE_TRUSTED_WDOG /* TODO: Enable watchdog */ #endif /* Initialize the console to provide early debug support */ console_ls_16550_register(LS_TF_UART_BASE, LS_TF_UART_CLOCK, LS_TF_UART_BAUDRATE, &console); /* Allow BL1 to see the whole Trusted RAM */ bl1_tzram_layout.total_base = LS_SRAM_BASE; bl1_tzram_layout.total_size = LS_SRAM_SIZE; } /****************************************************************************** * Perform the very early platform specific architecture setup shared between * ARM standard platforms. This only does basic initialization. Later * architectural setup (bl1_arch_setup()) does not do anything platform * specific. *****************************************************************************/ void ls_bl1_plat_arch_setup(void) { ls_setup_page_tables(bl1_tzram_layout.total_base, bl1_tzram_layout.total_size, BL_CODE_BASE, BL1_CODE_END, BL1_RO_DATA_BASE, BL1_RO_DATA_END #if USE_COHERENT_MEM , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END #endif ); VERBOSE("After setup the page tables\n"); #ifdef __aarch64__ enable_mmu_el3(0); #else enable_mmu_svc_mon(0); #endif /* __aarch64__ */ VERBOSE("After MMU enabled\n"); } void bl1_plat_arch_setup(void) { ls_bl1_plat_arch_setup(); } /* * Perform the platform specific architecture setup shared between * ARM standard platforms. */ void ls_bl1_platform_setup(void) { /* Initialise the IO layer and register platform IO devices */ plat_ls_io_setup(); } void bl1_plat_prepare_exit(entry_point_info_t *ep_info) { #if !LS1043_DISABLE_TRUSTED_WDOG /*TODO: Disable watchdog before leaving BL1 */ #endif } trusted-firmware-a-2.2/plat/layerscape/common/ls_bl2_setup.c000066400000000000000000000055731355360272700242440ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "ls_16550.h" #include "plat_ls.h" #include "ls_def.h" /* Data structure which holds the extents of the trusted SRAM for BL2 */ static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE); /******************************************************************************* * BL1 has passed the extents of the trusted SRAM that should be visible to BL2 * in x0. This memory layout is sitting at the base of the free trusted SRAM. * Copy it to a safe location before its reclaimed by later BL2 functionality. ******************************************************************************/ void ls_bl2_early_platform_setup(meminfo_t *mem_layout) { static console_ls_16550_t console; /* Initialize the console to provide early debug support */ console_ls_16550_register(LS_TF_UART_BASE, LS_TF_UART_CLOCK, LS_TF_UART_BAUDRATE, &console); /* Setup the BL2 memory layout */ bl2_tzram_layout = *mem_layout; /* Initialise the IO layer and register platform IO devices */ plat_ls_io_setup(); } /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this is only initializes the mmu in a quick and dirty way. ******************************************************************************/ void ls_bl2_plat_arch_setup(void) { ls_setup_page_tables(bl2_tzram_layout.total_base, bl2_tzram_layout.total_size, BL_CODE_BASE, BL_CODE_END, BL_RO_DATA_BASE, BL_RO_DATA_END #if USE_COHERENT_MEM , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END #endif ); #ifdef __aarch64__ enable_mmu_el1(0); #else enable_mmu_svc_mon(0); #endif } void bl2_plat_arch_setup(void) { ls_bl2_plat_arch_setup(); } int ls_bl2_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); assert(bl_mem_params); switch (image_id) { #ifdef __aarch64__ case BL32_IMAGE_ID: bl_mem_params->ep_info.spsr = ls_get_spsr_for_bl32_entry(); break; #endif case BL33_IMAGE_ID: /* BL33 expects to receive the primary CPU MPID (through r0) */ bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr(); bl_mem_params->ep_info.spsr = ls_get_spsr_for_bl33_entry(); break; } return err; } /******************************************************************************* * 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) { return ls_bl2_handle_post_image_load(image_id); } trusted-firmware-a-2.2/plat/layerscape/common/ls_bl31_setup.c000066400000000000000000000153021355360272700243150ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "ls_16550.h" #include "plat_ls.h" #include "soc.h" /* * Placeholder variables for copying the arguments that have been passed to * BL31 from BL2. */ static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; static const interrupt_prop_t g0_interrupt_props[] = { INTR_PROP_DESC(9, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), }; gicv2_driver_data_t ls_gic_data = { .gicd_base = GICD_BASE, .gicc_base = GICC_BASE, .interrupt_props = g0_interrupt_props, .interrupt_props_num = ARRAY_SIZE(g0_interrupt_props), }; /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for the * security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. ******************************************************************************/ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; assert(sec_state_is_valid(type)); next_image_info = (type == NON_SECURE) ? &bl33_image_ep_info : &bl32_image_ep_info; if (next_image_info->pc) return next_image_info; else return NULL; } /******************************************************************************* * Perform any BL31 early platform setup common to Layerscape platforms. * Here is an opportunity to copy parameters passed by the calling EL (S-EL1 * in BL2 & EL3 in BL1) before they are lost (potentially). This needs to be * done before the MMU is initialized so that the memory layout can be used * while creating page tables. BL2 has flushed this information to memory, so * we are guaranteed to pick up good data. ******************************************************************************/ void ls_bl31_early_platform_setup(void *from_bl2, void *plat_params_from_bl2) { static console_ls_16550_t console; /* Initialize the console to provide early debug support */ console_ls_16550_register(LS_TF_UART_BASE, LS_TF_UART_CLOCK, LS_TF_UART_BAUDRATE, &console); #if RESET_TO_BL31 /* There are no parameters from BL2 if BL31 is a reset vector */ assert(from_bl2 == NULL); assert(plat_params_from_bl2 == NULL); #ifdef BL32_BASE /* Populate entry point information for BL32 */ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0); SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); bl32_image_ep_info.pc = BL32_BASE; bl32_image_ep_info.spsr = ls_get_spsr_for_bl32_entry(); #endif /* BL32_BASE */ /* Populate entry point information for BL33 */ SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); /* * Tell BL31 where the non-trusted software image * is located and the entry state information */ bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); bl33_image_ep_info.spsr = ls_get_spsr_for_bl33_entry(); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); #else /* RESET_TO_BL31 */ /* * In debug builds, we pass a special value in 'plat_params_from_bl2' * to verify platform parameters from BL2 to BL31. * In release builds, it's not used. */ assert(((unsigned long long)plat_params_from_bl2) == LS_BL31_PLAT_PARAM_VAL); /* * Check params passed from BL2 should not be NULL, */ bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2; assert(params_from_bl2 != NULL); assert(params_from_bl2->h.type == PARAM_BL_PARAMS); assert(params_from_bl2->h.version >= VERSION_2); bl_params_node_t *bl_params = params_from_bl2->head; /* * Copy BL33 and BL32 (if present), entry point information. * They are stored in Secure RAM, in BL2's address space. */ while (bl_params) { if (bl_params->image_id == BL32_IMAGE_ID) bl32_image_ep_info = *bl_params->ep_info; if (bl_params->image_id == BL33_IMAGE_ID) bl33_image_ep_info = *bl_params->ep_info; bl_params = bl_params->next_params_info; } if (bl33_image_ep_info.pc == 0) panic(); #endif /* RESET_TO_BL31 */ } /******************************************************************************* * Perform any BL31 platform setup common to Layerscape platforms ******************************************************************************/ void ls_bl31_platform_setup(void) { uint32_t gicc_base, gicd_base; NOTICE(FIRMWARE_WELCOME_STR_LS1043_BL31); /* Initialize the GIC driver, cpu and distributor interfaces */ get_gic_offset(&gicc_base, &gicd_base); ls_gic_data.gicd_base = (uintptr_t)gicd_base; ls_gic_data.gicc_base = (uintptr_t)gicc_base; gicv2_driver_init(&ls_gic_data); gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); #if RESET_TO_BL31 /* * Do initial security configuration to allow DRAM/device access * (if earlier BL has not already done so). */ plat_ls_security_setup(); #endif /* RESET_TO_BL31 */ /* Enable and initialize the System level generic timer */ mmio_write_32(LS1043_SYS_CNTCTL_BASE + CNTCR_OFF, CNTCR_FCREQ(0U) | CNTCR_EN); VERBOSE("Leave arm_bl31_platform_setup\n"); } /******************************************************************************* * Perform any BL31 platform runtime setup prior to BL31 exit common to Layerscape * platforms ******************************************************************************/ void ls_bl31_plat_runtime_setup(void) { static console_ls_16550_t console; /* Initialize the runtime console */ console_ls_16550_register(PLAT_LS1043_UART_BASE, PLAT_LS1043_UART_CLOCK, PLAT_LS1043_UART_BAUDRATE, &console); } void bl31_platform_setup(void) { ls_bl31_platform_setup(); } void bl31_plat_runtime_setup(void) { ls_bl31_plat_runtime_setup(); } /******************************************************************************* * Perform the very early platform specific architectural setup shared between * Layerscape platforms. This only does basic initialization. Later * architectural setup (bl31_arch_setup()) does not do anything platform * specific. ******************************************************************************/ void ls_bl31_plat_arch_setup(void) { ls_setup_page_tables(BL31_BASE, BL31_END - BL31_BASE, BL_CODE_BASE, BL_CODE_END, BL_RO_DATA_BASE, BL_RO_DATA_END #if USE_COHERENT_MEM , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END #endif ); enable_mmu_el3(0); } void bl31_plat_arch_setup(void) { ls_bl31_plat_arch_setup(); } trusted-firmware-a-2.2/plat/layerscape/common/ls_common.c000066400000000000000000000123161355360272700236260ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include const mmap_region_t *plat_ls_get_mmap(void); /* * Table of memory regions for various BL stages to map using the MMU. * This doesn't include Trusted SRAM as ls_setup_page_tables() already * takes care of mapping it. * * The flash needs to be mapped as writable in order to erase the FIP's Table of * Contents in case of unrecoverable error (see plat_error_handler()). */ #ifdef IMAGE_BL1 const mmap_region_t plat_ls_mmap[] = { LS_MAP_FLASH0_RW, LS_MAP_NS_DRAM, LS_MAP_CCSR, {0} }; #endif #ifdef IMAGE_BL2 const mmap_region_t plat_ls_mmap[] = { LS_MAP_FLASH0_RW, LS_MAP_CCSR, LS_MAP_NS_DRAM, LS_MAP_TSP_SEC_MEM, {0} }; #endif #ifdef IMAGE_BL31 const mmap_region_t plat_ls_mmap[] = { LS_MAP_CCSR, LS_MAP_FLASH0_RW, LS_MAP_NS_DRAM, LS_MAP_TSP_SEC_MEM, {0} }; #endif #ifdef IMAGE_BL32 const mmap_region_t plat_ls_mmap[] = { LS_MAP_CCSR, LS_MAP_FLASH0_RW, LS_MAP_TSP_SEC_MEM, {0} }; #endif /* * Set up the page tables for the generic and platform-specific memory regions. * The extents of the generic memory regions are specified by the function * arguments and consist of: * - Trusted SRAM seen by the BL image; * - Code section; * - Read-only data section; * - Coherent memory region, if applicable. */ void ls_setup_page_tables(uintptr_t total_base, size_t total_size, uintptr_t code_start, uintptr_t code_limit, uintptr_t rodata_start, uintptr_t rodata_limit #if USE_COHERENT_MEM , uintptr_t coh_start, uintptr_t coh_limit #endif ) { /* Now (re-)map the platform-specific memory regions */ mmap_add(plat_ls_get_mmap()); /* * Map the Trusted SRAM with appropriate memory attributes. * Subsequent mappings will adjust the attributes for specific regions. */ VERBOSE("Trusted SRAM seen by this BL image: %p - %p\n", (void *) total_base, (void *) (total_base + total_size)); mmap_add_region(total_base, total_base, total_size, MT_MEMORY | MT_RW | MT_SECURE); /* Re-map the code section */ VERBOSE("Code region: %p - %p\n", (void *) code_start, (void *) code_limit); mmap_add_region(code_start, code_start, code_limit - code_start, MT_CODE | MT_SECURE); /* Re-map the read-only data section */ VERBOSE("Read-only data region: %p - %p\n", (void *) rodata_start, (void *) rodata_limit); mmap_add_region(rodata_start, rodata_start, rodata_limit - rodata_start, MT_RO_DATA | MT_SECURE); #if USE_COHERENT_MEM /* Re-map the coherent memory region */ VERBOSE("Coherent region: %p - %p\n", (void *) coh_start, (void *) coh_limit); mmap_add_region(coh_start, coh_start, coh_limit - coh_start, MT_DEVICE | MT_RW | MT_SECURE); #endif /* Create the page tables to reflect the above mappings */ init_xlat_tables(); } uintptr_t plat_get_ns_image_entrypoint(void) { #ifdef PRELOADED_BL33_BASE return PRELOADED_BL33_BASE; #else return LS_NS_DRAM_BASE; #endif } /******************************************************************************* * Gets SPSR for BL32 entry ******************************************************************************/ uint32_t ls_get_spsr_for_bl32_entry(void) { /* * The Secure Payload Dispatcher service is responsible for * setting the SPSR prior to entry into the BL32 image. */ return 0; } /******************************************************************************* * Gets SPSR for BL33 entry ******************************************************************************/ #ifdef __aarch64__ uint32_t ls_get_spsr_for_bl33_entry(void) { unsigned int mode; uint32_t spsr; /* Figure out what mode we enter the non-secure world in */ mode = (el_implemented(2) != EL_IMPL_NONE) ? MODE_EL2 : MODE_EL1; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; } #else /******************************************************************************* * Gets SPSR for BL33 entry ******************************************************************************/ uint32_t ls_get_spsr_for_bl33_entry(void) { unsigned int hyp_status, mode, spsr; hyp_status = GET_VIRT_EXT(read_id_pfr1()); mode = (hyp_status) ? MODE32_hyp : MODE32_svc; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_MODE32(mode, plat_get_ns_image_entrypoint() & 0x1, SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS); return spsr; } #endif /* __aarch64__ */ /******************************************************************************* * Returns Layerscape platform specific memory map regions. ******************************************************************************/ const mmap_region_t *plat_ls_get_mmap(void) { return plat_ls_mmap; } unsigned int plat_get_syscnt_freq2(void) { unsigned int counter_base_frequency; counter_base_frequency = COUNTER_FREQUENCY; return counter_base_frequency; } trusted-firmware-a-2.2/plat/layerscape/common/ls_common.mk000066400000000000000000000030211355360272700240040ustar00rootroot00000000000000# # Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Process LS1043_DISABLE_TRUSTED_WDOG flag # TODO:Temparally disabled it on development phase, not implemented yet LS1043_DISABLE_TRUSTED_WDOG := 1 # On Layerscape platforms, separate the code and read-only data sections to allow # mapping the former as executable and the latter as execute-never. SEPARATE_CODE_AND_RODATA := 1 COLD_BOOT_SINGLE_CPU := 1 PLAT_BL_COMMON_SOURCES += plat/layerscape/common/${ARCH}/ls_helpers.S \ plat/layerscape/common/ls_common.c include lib/xlat_tables_v2/xlat_tables.mk PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} BL1_SOURCES += \ drivers/io/io_fip.c \ drivers/io/io_memmap.c \ drivers/io/io_storage.c \ plat/layerscape/common/ls_timer.c \ plat/layerscape/common/ls_bl1_setup.c \ plat/layerscape/common/ls_io_storage.c BL2_SOURCES += drivers/io/io_fip.c \ drivers/io/io_memmap.c \ drivers/io/io_storage.c \ plat/layerscape/common/ls_timer.c \ plat/layerscape/common/ls_bl2_setup.c \ plat/layerscape/common/ls_io_storage.c BL2_SOURCES += plat/layerscape/common/${ARCH}/ls_bl2_mem_params_desc.c BL2_SOURCES += plat/layerscape/common/ls_image_load.c \ common/desc_image_load.c BL31_SOURCES += plat/layerscape/common/ls_bl31_setup.c \ plat/layerscape/common/ls_timer.c \ plat/layerscape/common/ls_topology.c \ plat/layerscape/common/ns_access.c \ plat/common/plat_psci_common.c trusted-firmware-a-2.2/plat/layerscape/common/ls_image_load.c000066400000000000000000000022031355360272700244110ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "ls_def.h" /******************************************************************************* * This function flushes the data structures so that they are visible * in memory for the next BL image. ******************************************************************************/ void plat_flush_next_bl_params(void) { flush_bl_params_desc(); } /******************************************************************************* * This function returns the list of loadable images. ******************************************************************************/ bl_load_info_t *plat_get_bl_image_load_info(void) { return get_bl_load_info_from_mem_params_desc(); } /******************************************************************************* * This function returns the list of executable images. ******************************************************************************/ bl_params_t *plat_get_next_bl_params(void) { return get_next_bl_params_from_mem_params_desc(); } trusted-firmware-a-2.2/plat/layerscape/common/ls_io_storage.c000066400000000000000000000075131355360272700244740ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include /* IO devices */ static const io_dev_connector_t *fip_dev_con; static uintptr_t fip_dev_handle; static const io_dev_connector_t *memmap_dev_con; static uintptr_t memmap_dev_handle; static const io_block_spec_t fip_block_spec = { .offset = PLAT_LS_FIP_BASE, .length = PLAT_LS_FIP_MAX_SIZE }; static const io_uuid_spec_t bl2_uuid_spec = { .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2, }; static const io_uuid_spec_t bl31_uuid_spec = { .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31, }; static const io_uuid_spec_t bl32_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32, }; static const io_uuid_spec_t bl33_uuid_spec = { .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33, }; static int open_fip(const uintptr_t spec); static int open_memmap(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[] = { [FIP_IMAGE_ID] = { &memmap_dev_handle, (uintptr_t)&fip_block_spec, open_memmap }, [BL2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl2_uuid_spec, open_fip }, [BL31_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl31_uuid_spec, open_fip }, [BL32_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_uuid_spec, open_fip }, [BL33_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl33_uuid_spec, open_fip }, }; static int open_fip(const uintptr_t spec) { int result; uintptr_t local_image_handle; /* See if a Firmware Image Package is available */ result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); if (result == 0) { result = io_open(fip_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using FIP\n"); io_close(local_image_handle); } } return result; } static int open_memmap(const uintptr_t spec) { int result; uintptr_t local_image_handle; result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL); if (result == 0) { result = io_open(memmap_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using Memmap\n"); io_close(local_image_handle); } } return result; } void ls_io_setup(void) { int io_result; io_result = register_io_dev_fip(&fip_dev_con); assert(io_result == 0); io_result = register_io_dev_memmap(&memmap_dev_con); assert(io_result == 0); /* Open connections to devices and cache the handles */ io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle); assert(io_result == 0); io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL, &memmap_dev_handle); assert(io_result == 0); /* Ignore improbable errors in release builds */ (void)io_result; } void plat_ls_io_setup(void) { ls_io_setup(); } int plat_ls_get_alt_image_source( unsigned int image_id __unused, uintptr_t *dev_handle __unused, uintptr_t *image_spec __unused) { /* By default do not try an alternative */ return -ENOENT; } /* * 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 result; const struct plat_io_policy *policy; assert(image_id < ARRAY_SIZE(policies)); policy = &policies[image_id]; result = policy->check(policy->image_spec); if (result == 0) { *image_spec = policy->image_spec; *dev_handle = *(policy->dev_handle); } else { VERBOSE("Trying alternative IO\n"); result = plat_ls_get_alt_image_source(image_id, dev_handle, image_spec); } return result; } trusted-firmware-a-2.2/plat/layerscape/common/ls_timer.c000066400000000000000000000020111355360272700234450ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #define TIMER_BASE_ADDR 0x02B00000 uint64_t ls_get_timer(uint64_t start) { return read_cntpct_el0() * 1000 / read_cntfrq_el0() - start; } static uint32_t ls_timeus_get_value(void) { /* * Generic delay timer implementation expects the timer to be a down * counter. We apply bitwise NOT operator to the tick values returned * by read_cntpct_el0() to simulate the down counter. The value is * clipped from 64 to 32 bits. */ return (uint32_t)(~read_cntpct_el0()); } static const timer_ops_t ls_timer_ops = { .get_timer_value = ls_timeus_get_value, .clk_mult = 1, .clk_div = 25, }; /* * Initialise the nxp layerscape on-chip free rolling us counter as the delay * timer. */ void ls_delay_timer_init(void) { uintptr_t cntcr = TIMER_BASE_ADDR; mmio_write_32(cntcr, 0x1); timer_init(&ls_timer_ops); } trusted-firmware-a-2.2/plat/layerscape/common/ls_topology.c000066400000000000000000000020731355360272700242110ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "plat_ls.h" /******************************************************************************* * This function validates an MPIDR by checking whether it falls within the * acceptable bounds. An error code (-1) is returned if an incorrect mpidr * is passed. ******************************************************************************/ int ls_check_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; uint64_t valid_mask; valid_mask = ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK); cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; mpidr &= MPIDR_AFFINITY_MASK; if (mpidr & valid_mask) return -1; if (cluster_id >= PLAT_LS_CLUSTER_COUNT) return -1; /* * Validate cpu_id by checking whether it represents a CPU in * one of the two clusters present on the platform. */ if (cpu_id >= plat_ls_get_cluster_core_count(mpidr)) return -1; return 0; } trusted-firmware-a-2.2/plat/layerscape/common/ls_tzc380.c000066400000000000000000000037111355360272700233700ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "soc_tzasc.h" int tzc380_set_region(unsigned int tzasc_base, unsigned int region_id, unsigned int enabled, unsigned int low_addr, unsigned int high_addr, unsigned int size, unsigned int security, unsigned int subreg_disable_mask) { unsigned int reg; unsigned int reg_base; unsigned int attr_value; reg_base = (tzasc_base + TZASC_REGIONS_REG + (region_id << 4)); if (region_id == 0) { reg = (reg_base + TZASC_REGION_ATTR_OFFSET); mmio_write_32((uintptr_t)reg, ((security & 0xF) << 28)); } else { reg = reg_base + TZASC_REGION_LOWADDR_OFFSET; mmio_write_32((uintptr_t)reg, (low_addr & TZASC_REGION_LOWADDR_MASK)); reg = reg_base + TZASC_REGION_HIGHADDR_OFFSET; mmio_write_32((uintptr_t)reg, high_addr); reg = reg_base + TZASC_REGION_ATTR_OFFSET; attr_value = ((security & 0xF) << 28) | ((subreg_disable_mask & 0xFF) << 8) | ((size & 0x3F) << 1) | (enabled & 0x1); mmio_write_32((uintptr_t)reg, attr_value); } return 0; } int tzc380_setup(void) { int reg_id = 0; INFO("Configuring TZASC-380\n"); /* * Configure CCI control override register to terminate all barrier * transactions */ mmio_write_32(PLAT_LS1043_CCI_BASE, CCI_TERMINATE_BARRIER_TX); /* Configure CSU secure access register to disable TZASC bypass mux */ mmio_write_32((uintptr_t)(CONFIG_SYS_FSL_CSU_ADDR + CSU_SEC_ACCESS_REG_OFFSET), bswap32(TZASC_BYPASS_MUX_DISABLE)); for (reg_id = 0; reg_id < MAX_NUM_TZC_REGION; reg_id++) { tzc380_set_region(CONFIG_SYS_FSL_TZASC_ADDR, reg_id, tzc380_reg_list[reg_id].enabled, tzc380_reg_list[reg_id].low_addr, tzc380_reg_list[reg_id].high_addr, tzc380_reg_list[reg_id].size, tzc380_reg_list[reg_id].secure, tzc380_reg_list[reg_id].sub_mask); } return 0; } trusted-firmware-a-2.2/plat/layerscape/common/ns_access.c000066400000000000000000000014761355360272700236060ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "ns_access.h" static void enable_devices_ns_access(struct csu_ns_dev *ns_dev, uint32_t num) { uint32_t *base = (uint32_t *)CONFIG_SYS_FSL_CSU_ADDR; uint32_t *reg; uint32_t val; int i; for (i = 0; i < num; i++) { reg = base + ns_dev[i].ind / 2; val = be32toh(mmio_read_32((uintptr_t)reg)); if (ns_dev[i].ind % 2 == 0) { val &= 0x0000ffff; val |= ns_dev[i].val << 16; } else { val &= 0xffff0000; val |= ns_dev[i].val; } mmio_write_32((uintptr_t)reg, htobe32(val)); } } void enable_layerscape_ns_access(void) { enable_devices_ns_access(ns_dev, ARRAY_SIZE(ns_dev)); } trusted-firmware-a-2.2/plat/layerscape/common/tsp/000077500000000000000000000000001355360272700222775ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/layerscape/common/tsp/ls_tsp.mk000066400000000000000000000005031355360272700241320ustar00rootroot00000000000000# # Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # TSP source files common to ARM standard platforms BL32_SOURCES += plat/layerscape/common/ls_topology.c \ plat/layerscape/common/tsp/ls_tsp_setup.c \ plat/common/aarch64/platform_mp_stack.S trusted-firmware-a-2.2/plat/layerscape/common/tsp/ls_tsp_setup.c000066400000000000000000000044611355360272700251740ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "ls_16550.h" #include "plat_ls.h" #include "soc.h" static const interrupt_prop_t g0_interrupt_props[] = { INTR_PROP_DESC(9, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), }; gicv2_driver_data_t ls_gic_data = { .gicd_base = GICD_BASE, .gicc_base = GICC_BASE, .interrupt_props = g0_interrupt_props, .interrupt_props_num = ARRAY_SIZE(g0_interrupt_props), }; /******************************************************************************* * Initialize the UART ******************************************************************************/ void ls_tsp_early_platform_setup(void) { static console_ls_16550_t console; /* * Initialize a different console than already in use to display * messages from TSP */ console_ls_16550_register(PLAT_LS1043_UART2_BASE, PLAT_LS1043_UART_CLOCK, PLAT_LS1043_UART_BAUDRATE, &console); NOTICE(FIRMWARE_WELCOME_STR_LS1043_BL32); } /******************************************************************************* * Perform platform specific setup placeholder ******************************************************************************/ void tsp_platform_setup(void) { uint32_t gicc_base, gicd_base; /* Initialize the GIC driver, cpu and distributor interfaces */ get_gic_offset(&gicc_base, &gicd_base); ls_gic_data.gicd_base = (uintptr_t)gicd_base; ls_gic_data.gicc_base = (uintptr_t)gicc_base; gicv2_driver_init(&ls_gic_data); gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this is only intializes the MMU ******************************************************************************/ void tsp_plat_arch_setup(void) { ls_setup_page_tables(BL32_BASE, (BL32_END - BL32_BASE), BL_CODE_BASE, BL_CODE_END, BL_RO_DATA_BASE, BL_RO_DATA_END #if USE_COHERENT_MEM , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END #endif ); enable_mmu_el1(0); } trusted-firmware-a-2.2/plat/layerscape/common/tsp/platform_tsp.h000066400000000000000000000010151355360272700251570ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_TSP_H #define PLATFORM_TSP_H /******************************************************************************* * Mandatory TSP functions (only if platform contains a TSP) ******************************************************************************/ void tsp_early_platform_setup(void); void tsp_plat_arch_setup(void); void tsp_platform_setup(void); #endif /* PLATFORM_TSP_H */ trusted-firmware-a-2.2/plat/marvell/000077500000000000000000000000001355360272700175135ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a3700/000077500000000000000000000000001355360272700202455ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a3700/a3700/000077500000000000000000000000001355360272700207775ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a3700/a3700/board/000077500000000000000000000000001355360272700220665ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a3700/a3700/board/pm_src.c000066400000000000000000000014471355360272700235230ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include /* This struct provides the PM wake up src configuration */ static struct pm_wake_up_src_config wake_up_src_cfg = { .wake_up_src_num = 3, .wake_up_src[0] = { .wake_up_src_type = WAKE_UP_SRC_GPIO, .wake_up_data = { .gpio_data.bank_num = 0, /* North Bridge */ .gpio_data.gpio_num = 14 } }, .wake_up_src[1] = { .wake_up_src_type = WAKE_UP_SRC_GPIO, .wake_up_data = { .gpio_data.bank_num = 1, /* South Bridge */ .gpio_data.gpio_num = 2 } }, .wake_up_src[2] = { .wake_up_src_type = WAKE_UP_SRC_UART1, } }; struct pm_wake_up_src_config *mv_wake_up_src_config_get(void) { return &wake_up_src_cfg; } trusted-firmware-a-2.2/plat/marvell/a3700/a3700/mvebu_def.h000066400000000000000000000003451355360272700231060ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MVEBU_DEF_H #define MVEBU_DEF_H #include #endif /* MVEBU_DEF_H */ trusted-firmware-a-2.2/plat/marvell/a3700/a3700/plat_bl31_setup.c000066400000000000000000000040051355360272700241430ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include /* This routine does MPP initialization */ static void marvell_bl31_mpp_init(void) { mmio_clrbits_32(MVEBU_NB_GPIO_SEL_REG, 1 << MVEBU_GPIO_TW1_GPIO_EN_OFF); /* Set hidden GPIO setting for SPI. * In north_bridge_pin_out_en_high register 13804, * bit 28 is the one which enables CS, CLK pins to be * output, need to set it to 1. * The initial value of this bit is 1, but in UART boot mode * initialization, this bit is disabled and the SPI CS and CLK pins * are used for downloading image purpose; so after downloading, * we should set this bit to 1 again to enable SPI CS and CLK pins. * And anyway, this bit value should be 1 in all modes, * so here we does not judge boot mode and set this bit to 1 always. */ mmio_setbits_32(MVEBU_NB_GPIO_OUTPUT_EN_HIGH_REG, 1 << MVEBU_GPIO_NB_SPI_PIN_MODE_OFF); } /* This function overruns the same function in marvell_bl31_setup.c */ void bl31_plat_arch_setup(void) { struct dec_win_config *io_dec_map; uint32_t dec_win_num; struct dram_win_map dram_wins_map; marvell_bl31_plat_arch_setup(); /* MPP init */ marvell_bl31_mpp_init(); /* initialize the timer for delay functionality */ plat_delay_timer_init(); /* CPU address decoder windows initialization. */ cpu_wins_init(); /* fetch CPU-DRAM window mapping information by reading * CPU-DRAM decode windows (only the enabled ones) */ dram_win_map_build(&dram_wins_map); /* Get IO address decoder windows */ if (marvell_get_io_dec_win_conf(&io_dec_map, &dec_win_num)) { printf("No IO address decoder windows configurations found!\n"); return; } /* IO address decoder init */ if (init_io_addr_dec(&dram_wins_map, io_dec_map, dec_win_num)) { printf("IO address decoder windows initialization failed!\n"); return; } } trusted-firmware-a-2.2/plat/marvell/a3700/a3700/platform.mk000066400000000000000000000003341355360272700231540ustar00rootroot00000000000000# # Copyright (C) 2018 Marvell International Ltd. # # SPDX-License-Identifier: BSD-3-Clause # https://spdx.org/licenses # include plat/marvell/a3700/common/a3700_common.mk include plat/marvell/common/marvell_common.mk trusted-firmware-a-2.2/plat/marvell/a3700/common/000077500000000000000000000000001355360272700215355ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a3700/common/a3700_common.mk000066400000000000000000000153471355360272700242020ustar00rootroot00000000000000# # Copyright (C) 2018 Marvell International Ltd. # # SPDX-License-Identifier: BSD-3-Clause # https://spdx.org/licenses # MARVELL_PLAT_BASE := plat/marvell MARVELL_PLAT_INCLUDE_BASE := include/plat/marvell PLAT_FAMILY := a3700 PLAT_FAMILY_BASE := $(MARVELL_PLAT_BASE)/$(PLAT_FAMILY) PLAT_INCLUDE_BASE := $(MARVELL_PLAT_INCLUDE_BASE)/$(PLAT_FAMILY) PLAT_COMMON_BASE := $(PLAT_FAMILY_BASE)/common MARVELL_DRV_BASE := drivers/marvell MARVELL_COMMON_BASE := $(MARVELL_PLAT_BASE)/common HANDLE_EA_EL3_FIRST := 1 include $(MARVELL_PLAT_BASE)/marvell.mk #*********** A3700 ************* DOIMAGEPATH := $(WTP) DOIMAGETOOL := $(DOIMAGEPATH)/wtptp/linux/tbb_linux ifeq ($(MARVELL_SECURE_BOOT),1) DOIMAGE_CFG := $(DOIMAGEPATH)/atf-tim.txt IMAGESPATH := $(DOIMAGEPATH)/tim/trusted TIMNCFG := $(DOIMAGEPATH)/atf-timN.txt TIMNSIG := $(IMAGESPATH)/timnsign.txt TIM2IMGARGS := -i $(DOIMAGE_CFG) -n $(TIMNCFG) TIMN_IMAGE := $$(grep "Image Filename:" -m 1 $(TIMNCFG) | cut -c 17-) else #MARVELL_SECURE_BOOT DOIMAGE_CFG := $(DOIMAGEPATH)/atf-ntim.txt IMAGESPATH := $(DOIMAGEPATH)/tim/untrusted TIM2IMGARGS := -i $(DOIMAGE_CFG) endif #MARVELL_SECURE_BOOT TIMBUILD := $(DOIMAGEPATH)/script/buildtim.sh TIM2IMG := $(DOIMAGEPATH)/script/tim2img.pl # WTMI_IMG is used to specify the customized RTOS image running over # Service CPU (CM3 processor). By the default, it points to a # baremetal binary of fuse programming in A3700_utils. WTMI_IMG := $(DOIMAGEPATH)/wtmi/fuse/build/fuse.bin # WTMI_SYSINIT_IMG is used for the system early initialization, # such as AVS settings, clock-tree setup and dynamic DDR PHY training. # After the initialization is done, this image will be wiped out # from the memory and CM3 will continue with RTOS image or other application. WTMI_SYSINIT_IMG := $(DOIMAGEPATH)/wtmi/sys_init/build/sys_init.bin # WTMI_MULTI_IMG is composed of CM3 RTOS image (WTMI_IMG) # and sys-init image (WTMI_SYSINIT_IMG). WTMI_MULTI_IMG := $(DOIMAGEPATH)/wtmi/build/wtmi.bin WTMI_ENC_IMG := $(DOIMAGEPATH)/wtmi/build/wtmi-enc.bin BUILD_UART := uart-images SRCPATH := $(dir $(BL33)) CLOCKSPRESET ?= CPU_800_DDR_800 DDR_TOPOLOGY ?= 0 BOOTDEV ?= SPINOR PARTNUM ?= 0 TIM_IMAGE := $$(grep "Image Filename:" -m 1 $(DOIMAGE_CFG) | cut -c 17-) TIMBLDARGS := $(MARVELL_SECURE_BOOT) $(BOOTDEV) $(IMAGESPATH) $(DOIMAGEPATH) $(CLOCKSPRESET) \ $(DDR_TOPOLOGY) $(PARTNUM) $(DEBUG) $(DOIMAGE_CFG) $(TIMNCFG) $(TIMNSIG) 1 TIMBLDUARTARGS := $(MARVELL_SECURE_BOOT) UART $(IMAGESPATH) $(DOIMAGEPATH) $(CLOCKSPRESET) \ $(DDR_TOPOLOGY) 0 0 $(DOIMAGE_CFG) $(TIMNCFG) $(TIMNSIG) 0 DOIMAGE_FLAGS := -r $(DOIMAGE_CFG) -v -D # GICV3 $(eval $(call add_define,CONFIG_GICV3)) # CCI-400 $(eval $(call add_define,USE_CCI)) MARVELL_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v3/gicv3_main.c \ drivers/arm/gic/v3/gicv3_helpers.c \ drivers/arm/gic/v3/arm_gicv3_common.c \ plat/common/plat_gicv3.c \ drivers/arm/gic/v3/gic500.c PLAT_INCLUDES := -I$(PLAT_FAMILY_BASE)/$(PLAT) \ -I$(PLAT_COMMON_BASE)/include \ -I$(PLAT_INCLUDE_BASE)/common \ -I$(MARVELL_DRV_BASE) \ -I$/drivers/arm/gic/common/ PLAT_BL_COMMON_SOURCES := $(PLAT_COMMON_BASE)/aarch64/a3700_common.c \ $(MARVELL_COMMON_BASE)/marvell_cci.c \ $(MARVELL_DRV_BASE)/uart/a3700_console.S BL1_SOURCES += $(PLAT_COMMON_BASE)/aarch64/plat_helpers.S \ lib/cpus/aarch64/cortex_a53.S BL31_PORTING_SOURCES := $(PLAT_FAMILY_BASE)/$(PLAT)/board/pm_src.c MARVELL_DRV := $(MARVELL_DRV_BASE)/comphy/phy-comphy-3700.c BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \ $(PLAT_COMMON_BASE)/aarch64/plat_helpers.S \ $(PLAT_COMMON_BASE)/plat_pm.c \ $(PLAT_COMMON_BASE)/dram_win.c \ $(PLAT_COMMON_BASE)/io_addr_dec.c \ $(PLAT_COMMON_BASE)/marvell_plat_config.c \ $(PLAT_COMMON_BASE)/a3700_ea.c \ $(PLAT_FAMILY_BASE)/$(PLAT)/plat_bl31_setup.c \ $(MARVELL_COMMON_BASE)/marvell_ddr_info.c \ $(MARVELL_COMMON_BASE)/marvell_gicv3.c \ $(MARVELL_GIC_SOURCES) \ drivers/arm/cci/cci.c \ $(BL31_PORTING_SOURCES) \ $(PLAT_COMMON_BASE)/a3700_sip_svc.c \ $(MARVELL_DRV) mrvl_flash: ${BUILD_PLAT}/${FIP_NAME} ${DOIMAGETOOL} $(shell truncate -s %128K ${BUILD_PLAT}/bl1.bin) $(shell cat ${BUILD_PLAT}/bl1.bin ${BUILD_PLAT}/${FIP_NAME} > ${BUILD_PLAT}/${BOOT_IMAGE}) $(shell truncate -s %4 ${BUILD_PLAT}/${BOOT_IMAGE}) $(shell truncate -s %4 $(WTMI_IMG)) @echo @echo "Building uart images" $(TIMBUILD) $(TIMBLDUARTARGS) @sed -i 's|WTMI_IMG|$(WTMI_MULTI_IMG)|1' $(DOIMAGE_CFG) @sed -i 's|BOOT_IMAGE|$(BUILD_PLAT)/$(BOOT_IMAGE)|1' $(DOIMAGE_CFG) ifeq ($(MARVELL_SECURE_BOOT),1) @sed -i 's|WTMI_IMG|$(WTMI_MULTI_IMG)|1' $(TIMNCFG) @sed -i 's|BOOT_IMAGE|$(BUILD_PLAT)/$(BOOT_IMAGE)|1' $(TIMNCFG) endif $(DOIMAGETOOL) $(DOIMAGE_FLAGS) @if [ -e "$(TIMNCFG)" ]; then $(DOIMAGETOOL) -r $(TIMNCFG); fi @rm -rf $(BUILD_PLAT)/$(BUILD_UART)* @mkdir $(BUILD_PLAT)/$(BUILD_UART) @mv -t $(BUILD_PLAT)/$(BUILD_UART) $(TIM_IMAGE) $(DOIMAGE_CFG) $(TIMN_IMAGE) $(TIMNCFG) @find . -name "*_h.*" |xargs cp -ut $(BUILD_PLAT)/$(BUILD_UART) @mv $(subst .bin,_h.bin,$(WTMI_MULTI_IMG)) $(BUILD_PLAT)/$(BUILD_UART)/wtmi_h.bin @tar czf $(BUILD_PLAT)/$(BUILD_UART).tgz -C $(BUILD_PLAT) ./$(BUILD_UART) @echo @echo "Building flash image" $(TIMBUILD) $(TIMBLDARGS) sed -i 's|WTMI_IMG|$(WTMI_MULTI_IMG)|1' $(DOIMAGE_CFG) sed -i 's|BOOT_IMAGE|$(BUILD_PLAT)/$(BOOT_IMAGE)|1' $(DOIMAGE_CFG) ifeq ($(MARVELL_SECURE_BOOT),1) @sed -i 's|WTMI_IMG|$(WTMI_MULTI_IMG)|1' $(TIMNCFG) @sed -i 's|BOOT_IMAGE|$(BUILD_PLAT)/$(BOOT_IMAGE)|1' $(TIMNCFG) @echo -e "\n\t=======================================================\n"; @echo -e "\t Secure boot. Encrypting wtmi and boot-image \n"; @echo -e "\t=======================================================\n"; @truncate -s %16 $(WTMI_MULTI_IMG) @openssl enc -aes-256-cbc -e -in $(WTMI_MULTI_IMG) \ -out $(WTMI_ENC_IMG) \ -K `cat $(IMAGESPATH)/aes-256.txt` -nosalt \ -iv `cat $(IMAGESPATH)/iv.txt` -p @truncate -s %16 $(BUILD_PLAT)/$(BOOT_IMAGE); @openssl enc -aes-256-cbc -e -in $(BUILD_PLAT)/$(BOOT_IMAGE) \ -out $(BUILD_PLAT)/$(BOOT_ENC_IMAGE) \ -K `cat $(IMAGESPATH)/aes-256.txt` -nosalt \ -iv `cat $(IMAGESPATH)/iv.txt` -p endif $(DOIMAGETOOL) $(DOIMAGE_FLAGS) @if [ -e "$(TIMNCFG)" ]; then $(DOIMAGETOOL) -r $(TIMNCFG); fi @if [ "$(MARVELL_SECURE_BOOT)" = "1" ]; then sed -i 's|$(WTMI_MULTI_IMG)|$(WTMI_ENC_IMG)|1;s|$(BOOT_IMAGE)|$(BOOT_ENC_IMAGE)|1;' $(TIMNCFG); fi $(TIM2IMG) $(TIM2IMGARGS) -o $(BUILD_PLAT)/$(FLASH_IMAGE) @mv -t $(BUILD_PLAT) $(TIM_IMAGE) $(DOIMAGE_CFG) $(TIMN_IMAGE) $(TIMNCFG) $(WTMI_IMG) $(WTMI_SYSINIT_IMG) $(WTMI_MULTI_IMG) @if [ "$(MARVELL_SECURE_BOOT)" = "1" ]; then mv -t $(BUILD_PLAT) $(WTMI_ENC_IMG) OtpHash.txt; fi @find . -name "*.txt" | grep -E "CSK[[:alnum:]]_KeyHash.txt|Tim_msg.txt|TIMHash.txt" | xargs rm -f trusted-firmware-a-2.2/plat/marvell/a3700/common/a3700_ea.c000066400000000000000000000011041355360272700230740ustar00rootroot00000000000000/* * Copyright (C) 2019 Repk repk@triplefau.lt * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #define ADVK_SERROR_SYNDROME 0xbf000002 void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie, void *handle, uint64_t flags) { if (syndrome != ADVK_SERROR_SYNDROME) { ERROR("Unhandled External Abort received on 0x%lx at EL3!\n", read_mpidr_el1()); ERROR(" exception reason=%u syndrome=0x%llx\n", ea_reason, syndrome); panic(); } } trusted-firmware-a-2.2/plat/marvell/a3700/common/a3700_sip_svc.c000066400000000000000000000041211355360272700241570ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include "comphy/phy-comphy-3700.h" /* Comphy related FID's */ #define MV_SIP_COMPHY_POWER_ON 0x82000001 #define MV_SIP_COMPHY_POWER_OFF 0x82000002 #define MV_SIP_COMPHY_PLL_LOCK 0x82000003 /* Miscellaneous FID's' */ #define MV_SIP_DRAM_SIZE 0x82000010 /* This macro is used to identify COMPHY related calls from SMC function ID */ #define is_comphy_fid(fid) \ ((fid) >= MV_SIP_COMPHY_POWER_ON && (fid) <= MV_SIP_COMPHY_PLL_LOCK) uintptr_t mrvl_sip_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) { u_register_t ret; VERBOSE("%s: got SMC (0x%x) x1 0x%lx, x2 0x%lx\n", __func__, smc_fid, x1, x2); if (is_comphy_fid(smc_fid)) { if (x1 >= MAX_LANE_NR) { ERROR("%s: Wrong smc (0x%x) lane nr: %lx\n", __func__, smc_fid, x2); SMC_RET1(handle, SMC_UNK); } } switch (smc_fid) { /* Comphy related FID's */ case MV_SIP_COMPHY_POWER_ON: /* x1: comphy_index, x2: comphy_mode */ ret = mvebu_3700_comphy_power_on(x1, x2); SMC_RET1(handle, ret); case MV_SIP_COMPHY_POWER_OFF: /* x1: comphy_index, x2: comphy_mode */ ret = mvebu_3700_comphy_power_off(x1, x2); SMC_RET1(handle, ret); case MV_SIP_COMPHY_PLL_LOCK: /* x1: comphy_index, x2: comphy_mode */ ret = mvebu_3700_comphy_is_pll_locked(x1, x2); SMC_RET1(handle, ret); /* Miscellaneous FID's' */ case MV_SIP_DRAM_SIZE: /* x1: ap_base_addr */ ret = mvebu_get_dram_size(MVEBU_REGS_BASE); SMC_RET1(handle, ret); default: ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); SMC_RET1(handle, SMC_UNK); } } /* Define a runtime service descriptor for fast SMC calls */ DECLARE_RT_SVC( marvell_sip_svc, OEN_SIP_START, OEN_SIP_END, SMC_TYPE_FAST, NULL, mrvl_sip_smc_handler ); trusted-firmware-a-2.2/plat/marvell/a3700/common/aarch64/000077500000000000000000000000001355360272700227655ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a3700/common/aarch64/a3700_common.c000066400000000000000000000017101355360272700252320ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include /* MMU entry for internal (register) space access */ #define MAP_DEVICE0 MAP_REGION_FLAT(DEVICE0_BASE, \ DEVICE0_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) /* * Table of regions for various BL stages to map using the MMU. */ #if IMAGE_BL1 const mmap_region_t plat_marvell_mmap[] = { MARVELL_MAP_SHARED_RAM, MAP_DEVICE0, {0} }; #endif #if IMAGE_BL2 const mmap_region_t plat_marvell_mmap[] = { MARVELL_MAP_SHARED_RAM, MAP_DEVICE0, MARVELL_MAP_DRAM, {0} }; #endif #if IMAGE_BL2U const mmap_region_t plat_marvell_mmap[] = { MAP_DEVICE0, {0} }; #endif #if IMAGE_BL31 const mmap_region_t plat_marvell_mmap[] = { MARVELL_MAP_SHARED_RAM, MAP_DEVICE0, MARVELL_MAP_DRAM, {0} }; #endif #if IMAGE_BL32 const mmap_region_t plat_marvell_mmap[] = { MAP_DEVICE0, {0} }; #endif MARVELL_CASSERT_MMAP; trusted-firmware-a-2.2/plat/marvell/a3700/common/aarch64/plat_helpers.S000066400000000000000000000037201355360272700255750ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include .globl plat_secondary_cold_boot_setup .globl plat_get_my_entrypoint .globl plat_is_my_cpu_primary /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions * needed for a secondary cpu after a cold reset. Right * now this is a stub function. * ----------------------------------------------------- */ func plat_secondary_cold_boot_setup mov x0, #0 ret endfunc plat_secondary_cold_boot_setup /* --------------------------------------------------------------------- * unsigned long plat_get_my_entrypoint (void); * * Main job of this routine is to distinguish between cold and warm boot * For a cold boot, return 0. * For a warm boot, read the mailbox and return the address it contains. * A magic number is placed before entrypoint to avoid mistake caused by * uninitialized mailbox data area. * --------------------------------------------------------------------- */ func plat_get_my_entrypoint /* Read first word and compare it with magic num */ mov_imm x0, PLAT_MARVELL_MAILBOX_BASE ldr x1, [x0] mov_imm x2, PLAT_MARVELL_MAILBOX_MAGIC_NUM cmp x1, x2 /* If compare failed, return 0, i.e. cold boot */ beq entrypoint mov x0, #0 ret entrypoint: /* Second word contains the jump address */ add x0, x0, #8 ldr x0, [x0] ret endfunc plat_get_my_entrypoint /* ----------------------------------------------------- * unsigned int plat_is_my_cpu_primary (void); * * Find out whether the current cpu is the primary * cpu. * ----------------------------------------------------- */ func plat_is_my_cpu_primary mrs x0, mpidr_el1 and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) cmp x0, #MVEBU_PRIMARY_CPU cset w0, eq ret endfunc plat_is_my_cpu_primary trusted-firmware-a-2.2/plat/marvell/a3700/common/dram_win.c000066400000000000000000000161601355360272700235050ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include /* Armada 3700 has 5 configurable windows */ #define MV_CPU_WIN_NUM 5 #define CPU_WIN_DISABLED 0 #define CPU_WIN_ENABLED 1 /* * There are 2 different cpu decode window configuration cases: * - DRAM size is not over 2GB; * - DRAM size is 4GB. */ enum cpu_win_config_num { CPU_WIN_CONFIG_DRAM_NOT_OVER_2GB = 0, CPU_WIN_CONFIG_DRAM_4GB, CPU_WIN_CONFIG_MAX }; enum cpu_win_target { CPU_WIN_TARGET_DRAM = 0, CPU_WIN_TARGET_INTERNAL_REG, CPU_WIN_TARGET_PCIE, CPU_WIN_TARGET_PCIE_OVER_MCI, CPU_WIN_TARGET_BOOT_ROM, CPU_WIN_TARGET_MCI_EXTERNAL, CPU_WIN_TARGET_RWTM_RAM = 7, CPU_WIN_TARGET_CCI400_REG }; struct cpu_win_configuration { uint32_t enabled; enum cpu_win_target target; uint64_t base_addr; uint64_t size; uint64_t remap_addr; }; struct cpu_win_configuration mv_cpu_wins[CPU_WIN_CONFIG_MAX][MV_CPU_WIN_NUM] = { /* * When total dram size is not over 2GB: * DDR window 0 is configured in tim header, its size may be not 512MB, * but the actual dram size, no need to configure it again; * other cpu windows are kept as default. */ { /* enabled * target * base * size * remap */ {CPU_WIN_ENABLED, CPU_WIN_TARGET_DRAM, 0x0, 0x08000000, 0x0}, {CPU_WIN_ENABLED, CPU_WIN_TARGET_MCI_EXTERNAL, 0xe0000000, 0x08000000, 0xe0000000}, {CPU_WIN_ENABLED, CPU_WIN_TARGET_PCIE, 0xe8000000, 0x08000000, 0xe8000000}, {CPU_WIN_ENABLED, CPU_WIN_TARGET_RWTM_RAM, 0xf0000000, 0x00020000, 0x1fff0000}, {CPU_WIN_ENABLED, CPU_WIN_TARGET_PCIE_OVER_MCI, 0x80000000, 0x10000000, 0x80000000}, }, /* * If total dram size is more than 2GB, now there is only one case - 4GB * dram; we will use below cpu windows configurations: * - Internal Regs, CCI-400, Boot Rom and PCIe windows are kept as * default; * - Use 4 CPU decode windows for DRAM, which cover 3.375GB DRAM; * DDR window 0 is configured in tim header with 2GB size, no need to * configure it again here; * * 0xFFFFFFFF ---> |-----------------------| * | Boot ROM | 64KB * 0xFFF00000 ---> +-----------------------+ * : : * 0xF0000000 ---> |-----------------------| * | PCIE | 128 MB * 0xE8000000 ---> |-----------------------| * | DDR window 3 | 128 MB * 0xE0000000 ---> +-----------------------+ * : : * 0xD8010000 ---> |-----------------------| * | CCI Regs | 64 KB * 0xD8000000 ---> +-----------------------+ * : : * : : * 0xD2000000 ---> +-----------------------+ * | Internal Regs | 32MB * 0xD0000000 ---> |-----------------------| * | DDR window 2 | 256 MB * 0xC0000000 ---> |-----------------------| * | | * | DDR window 1 | 1 GB * | | * 0x80000000 ---> |-----------------------| * | | * | | * | DDR window 0 | 2 GB * | | * | | * 0x00000000 ---> +-----------------------+ */ { /* win_id * target * base * size * remap */ {CPU_WIN_ENABLED, CPU_WIN_TARGET_DRAM, 0x0, 0x80000000, 0x0}, {CPU_WIN_ENABLED, CPU_WIN_TARGET_DRAM, 0x80000000, 0x40000000, 0x80000000}, {CPU_WIN_ENABLED, CPU_WIN_TARGET_DRAM, 0xc0000000, 0x10000000, 0xc0000000}, {CPU_WIN_ENABLED, CPU_WIN_TARGET_DRAM, 0xe0000000, 0x08000000, 0xe0000000}, {CPU_WIN_ENABLED, CPU_WIN_TARGET_PCIE, 0xe8000000, 0x08000000, 0xe8000000}, }, }; /* * dram_win_map_build * * This function builds cpu dram windows mapping * which includes base address and window size by * reading cpu dram decode windows registers. * * @input: N/A * * @output: * - win_map: cpu dram windows mapping * * @return: N/A */ void dram_win_map_build(struct dram_win_map *win_map) { int32_t win_id; struct dram_win *win; uint32_t base_reg, ctrl_reg, size_reg, enabled, target; memset(win_map, 0, sizeof(struct dram_win_map)); for (win_id = 0; win_id < DRAM_WIN_MAP_NUM_MAX; win_id++) { ctrl_reg = mmio_read_32(CPU_DEC_WIN_CTRL_REG(win_id)); target = (ctrl_reg & CPU_DEC_CR_WIN_TARGET_MASK) >> CPU_DEC_CR_WIN_TARGET_OFFS; enabled = ctrl_reg & CPU_DEC_CR_WIN_ENABLE; /* Ignore invalid and non-dram windows*/ if ((enabled == 0) || (target != DRAM_CPU_DEC_TARGET_NUM)) continue; win = win_map->dram_windows + win_map->dram_win_num; base_reg = mmio_read_32(CPU_DEC_WIN_BASE_REG(win_id)); size_reg = mmio_read_32(CPU_DEC_WIN_SIZE_REG(win_id)); /* Base reg [15:0] corresponds to transaction address [39:16] */ win->base_addr = (base_reg & CPU_DEC_BR_BASE_MASK) >> CPU_DEC_BR_BASE_OFFS; win->base_addr *= CPU_DEC_CR_WIN_SIZE_ALIGNMENT; /* * Size reg [15:0] is programmed from LSB to MSB as a sequence * of 1s followed by a sequence of 0s and the number of 1s * specifies the size of the window in 64 KB granularity, * for example, a value of 00FFh specifies 256 x 64 KB = 16 MB */ win->win_size = (size_reg & CPU_DEC_CR_WIN_SIZE_MASK) >> CPU_DEC_CR_WIN_SIZE_OFFS; win->win_size = (win->win_size + 1) * CPU_DEC_CR_WIN_SIZE_ALIGNMENT; win_map->dram_win_num++; } } static void cpu_win_set(uint32_t win_id, struct cpu_win_configuration *win_cfg) { uint32_t base_reg, ctrl_reg, size_reg, remap_reg; /* Disable window */ ctrl_reg = mmio_read_32(CPU_DEC_WIN_CTRL_REG(win_id)); ctrl_reg &= ~CPU_DEC_CR_WIN_ENABLE; mmio_write_32(CPU_DEC_WIN_CTRL_REG(win_id), ctrl_reg); /* For an disabled window, only disable it. */ if (!win_cfg->enabled) return; /* Set Base Register */ base_reg = (uint32_t)(win_cfg->base_addr / CPU_DEC_CR_WIN_SIZE_ALIGNMENT); base_reg <<= CPU_DEC_BR_BASE_OFFS; base_reg &= CPU_DEC_BR_BASE_MASK; mmio_write_32(CPU_DEC_WIN_BASE_REG(win_id), base_reg); /* Set Remap Register with the same value * as the field in Base Register */ remap_reg = (uint32_t)(win_cfg->remap_addr / CPU_DEC_CR_WIN_SIZE_ALIGNMENT); remap_reg <<= CPU_DEC_RLR_REMAP_LOW_OFFS; remap_reg &= CPU_DEC_RLR_REMAP_LOW_MASK; mmio_write_32(CPU_DEC_REMAP_LOW_REG(win_id), remap_reg); /* Set Size Register */ size_reg = (win_cfg->size / CPU_DEC_CR_WIN_SIZE_ALIGNMENT) - 1; size_reg <<= CPU_DEC_CR_WIN_SIZE_OFFS; size_reg &= CPU_DEC_CR_WIN_SIZE_MASK; mmio_write_32(CPU_DEC_WIN_SIZE_REG(win_id), size_reg); /* Set Control Register - set target id and enable window */ ctrl_reg &= ~CPU_DEC_CR_WIN_TARGET_MASK; ctrl_reg |= (win_cfg->target << CPU_DEC_CR_WIN_TARGET_OFFS); ctrl_reg |= CPU_DEC_CR_WIN_ENABLE; mmio_write_32(CPU_DEC_WIN_CTRL_REG(win_id), ctrl_reg); } void cpu_wins_init(void) { uint32_t cfg_idx, win_id; if (mvebu_get_dram_size(MVEBU_REGS_BASE) <= _2GB_) cfg_idx = CPU_WIN_CONFIG_DRAM_NOT_OVER_2GB; else cfg_idx = CPU_WIN_CONFIG_DRAM_4GB; /* Window 0 is configured always for DRAM in tim header * already, no need to configure it again here */ for (win_id = 1; win_id < MV_CPU_WIN_NUM; win_id++) cpu_win_set(win_id, &mv_cpu_wins[cfg_idx][win_id]); } trusted-firmware-a-2.2/plat/marvell/a3700/common/include/000077500000000000000000000000001355360272700231605ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a3700/common/include/a3700_plat_def.h000066400000000000000000000110071355360272700257200ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef A3700_PLAT_DEF_H #define A3700_PLAT_DEF_H #include #define MVEBU_MAX_CPUS_PER_CLUSTER 2 #define MVEBU_PRIMARY_CPU 0x0 /* * The counter on A3700 is always fed from reference 25M clock (XTAL). * However minimal CPU counter prescaler is 2, so the counter * frequency will be divided by 2, the number is 12.5M */ #define COUNTER_FREQUENCY 12500000 #define MVEBU_REGS_BASE 0xD0000000 /***************************************************************************** * MVEBU memory map related constants ***************************************************************************** */ /* Aggregate of all devices in the first GB */ #define DEVICE0_BASE MVEBU_REGS_BASE #define DEVICE0_SIZE 0x10000000 /***************************************************************************** * GIC-500 & interrupt handling related constants ***************************************************************************** */ /* Base MVEBU compatible GIC memory map */ #define MVEBU_GICD_BASE 0x1D00000 #define MVEBU_GICR_BASE 0x1D40000 #define MVEBU_GICC_BASE 0x1D80000 /* CCI-400 */ #define MVEBU_CCI_BASE 0x8000000 /***************************************************************************** * North and south bridge register base ***************************************************************************** */ #define MVEBU_NB_REGS_BASE (MVEBU_REGS_BASE + 0x13000) #define MVEBU_SB_REGS_BASE (MVEBU_REGS_BASE + 0x18000) /***************************************************************************** * GPIO registers related constants ***************************************************************************** */ /* North and south bridge GPIO register base address */ #define MVEBU_NB_GPIO_REG_BASE (MVEBU_NB_REGS_BASE + 0x800) #define MVEBU_NB_GPIO_IRQ_REG_BASE (MVEBU_NB_REGS_BASE + 0xC00) #define MVEBU_SB_GPIO_REG_BASE (MVEBU_SB_REGS_BASE + 0x800) #define MVEBU_SB_GPIO_IRQ_REG_BASE (MVEBU_SB_REGS_BASE + 0xC00) #define MVEBU_NB_SB_IRQ_REG_BASE (MVEBU_REGS_BASE + 0x8A00) /* North Bridge GPIO selection register */ #define MVEBU_NB_GPIO_SEL_REG (MVEBU_NB_GPIO_REG_BASE + 0x30) #define MVEBU_NB_GPIO_OUTPUT_EN_HIGH_REG (MVEBU_NB_GPIO_REG_BASE + 0x04) /* I2C1 GPIO Enable bit offset */ #define MVEBU_GPIO_TW1_GPIO_EN_OFF (10) /* SPI pins mode bit offset */ #define MVEBU_GPIO_NB_SPI_PIN_MODE_OFF (28) /***************************************************************************** * DRAM registers related constants ***************************************************************************** */ #define MVEBU_DRAM_REG_BASE (MVEBU_REGS_BASE) /***************************************************************************** * SB wake-up registers related constants ***************************************************************************** */ #define MVEBU_SB_WAKEUP_REG_BASE (MVEBU_REGS_BASE + 0x19000) /***************************************************************************** * PMSU registers related constants ***************************************************************************** */ #define MVEBU_PMSU_REG_BASE (MVEBU_REGS_BASE + 0x14000) /***************************************************************************** * North Bridge Step-Down Registers ***************************************************************************** */ #define MVEBU_NB_STEP_DOWN_REG_BASE (MVEBU_REGS_BASE + 0x12800) /***************************************************************************** * DRAM CS memory map register base ***************************************************************************** */ #define MVEBU_CS_MMAP_REG_BASE (MVEBU_REGS_BASE + 0x200) /***************************************************************************** * CPU decoder window registers related constants ***************************************************************************** */ #define MVEBU_CPU_DEC_WIN_REG_BASE (MVEBU_REGS_BASE + 0xCF00) /***************************************************************************** * AVS registers related constants ***************************************************************************** */ #define MVEBU_AVS_REG_BASE (MVEBU_REGS_BASE + 0x11500) /***************************************************************************** * AVS registers related constants ***************************************************************************** */ #define MVEBU_COMPHY_REG_BASE (MVEBU_REGS_BASE + 0x18300) #endif /* A3700_PLAT_DEF_H */ trusted-firmware-a-2.2/plat/marvell/a3700/common/include/a3700_pm.h000066400000000000000000000016701355360272700245630ustar00rootroot00000000000000/* * Copyright (C) 2016 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef A3700_PM_H #define A3700_PM_H #include /* supported wake up sources */ enum pm_wake_up_src_type { WAKE_UP_SRC_GPIO, /* FOLLOWING SRC NOT SUPPORTED YET */ WAKE_UP_SRC_TIMER, WAKE_UP_SRC_UART0, WAKE_UP_SRC_UART1, WAKE_UP_SRC_MAX, }; struct pm_gpio_data { /* * bank 0: North bridge GPIO * bank 1: South bridge GPIO */ uint32_t bank_num; uint32_t gpio_num; }; union pm_wake_up_src_data { struct pm_gpio_data gpio_data; /* delay in seconds */ uint32_t timer_delay; }; struct pm_wake_up_src { enum pm_wake_up_src_type wake_up_src_type; union pm_wake_up_src_data wake_up_data; }; struct pm_wake_up_src_config { uint32_t wake_up_src_num; struct pm_wake_up_src wake_up_src[WAKE_UP_SRC_MAX]; }; struct pm_wake_up_src_config *mv_wake_up_src_config_get(void); #endif /* A3700_PM_H */ trusted-firmware-a-2.2/plat/marvell/a3700/common/include/ddr_info.h000066400000000000000000000004101355360272700251100ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef DDR_INFO_H #define DDR_INFO_H #define DRAM_MAX_IFACE 1 #define DRAM_CH0_MMAP_LOW_OFFSET 0x200 #endif /* DDR_INFO_H */ trusted-firmware-a-2.2/plat/marvell/a3700/common/include/dram_win.h000066400000000000000000000005141355360272700251310ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef DRAM_WIN_H #define DRAM_WIN_H #include #include void dram_win_map_build(struct dram_win_map *win_map); void cpu_wins_init(void); #endif /* DRAM_WIN_H */ trusted-firmware-a-2.2/plat/marvell/a3700/common/include/io_addr_dec.h000066400000000000000000000035171355360272700255530ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef IO_ADDR_DEC_H #define IO_ADDR_DEC_H #include /* There are 5 configurable cpu decoder windows. */ #define DRAM_WIN_MAP_NUM_MAX 5 /* Target number for dram in cpu decoder windows. */ #define DRAM_CPU_DEC_TARGET_NUM 0 /* * Not all configurable decode windows could be used for dram, some units have * to reserve one decode window for other unit they have to communicate with; * for example, DMA engineer has 3 configurable windows, but only two could be * for dram while the last one has to be for pcie, so for DMA, its max_dram_win * is 2. */ struct dec_win_config { uint32_t dec_reg_base; /* IO address decoder register base address */ uint32_t win_attr; /* IO address decoder windows attributes */ /* How many configurable dram decoder windows that this unit has; */ uint32_t max_dram_win; /* The decoder windows number including remapping that this unit has */ uint32_t max_remap; /* The offset between continuous decode windows * within the same unit, typically 0x10 */ uint32_t win_offset; }; struct dram_win { uintptr_t base_addr; uintptr_t win_size; }; struct dram_win_map { int dram_win_num; struct dram_win dram_windows[DRAM_WIN_MAP_NUM_MAX]; }; /* * init_io_addr_dec * * This function initializes io address decoder windows by * cpu dram window mapping information * * @input: N/A * - dram_wins_map: cpu dram windows mapping * - io_dec_config: io address decoder windows configuration * - io_unit_num: io address decoder unit number * @output: N/A * * @return: 0 on success and others on failure */ int init_io_addr_dec(struct dram_win_map *dram_wins_map, struct dec_win_config *io_dec_config, uint32_t io_unit_num); #endif /* IO_ADDR_DEC_H */ trusted-firmware-a-2.2/plat/marvell/a3700/common/include/plat_macros.S000066400000000000000000000011241355360272700256060ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S #include /* --------------------------------------------- * The below macro prints out relevant GIC and * CCI registers registers whenever an unhandled * exception is taken in BL31. * --------------------------------------------- */ .macro plat_crash_print_regs mov_imm x17, MVEBU_GICC_BASE mov_imm x16, MVEBU_GICD_BASE marvell_print_gic_regs print_cci_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/marvell/a3700/common/include/platform_def.h000066400000000000000000000171611355360272700260010ustar00rootroot00000000000000/* * Copyright (C) 2016 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #ifndef __ASSEMBLER__ #include #endif /* __ASSEMBLER__ */ #include #include /* * Most platform porting definitions provided by included headers */ /* * DRAM Memory layout: * +-----------------------+ * : : * : Linux : * 0x04X00000-->+-----------------------+ * | BL3-3(u-boot) |>>}>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> * |-----------------------| } | * | BL3-[0,1, 2] | }---------------------------------> | * |-----------------------| } || | * | BL2 | }->FIP (loaded by || | * |-----------------------| } BootROM to DRAM) || | * | FIP_TOC | } || | * 0x04120000-->|-----------------------| || | * | BL1 (RO) | || | * 0x04100000-->+-----------------------+ || | * : : || | * : Trusted SRAM section : \/ | * 0x04040000-->+-----------------------+ Replaced by BL2 +----------------+ | * | BL1 (RW) | <<<<<<<<<<<<<<<< | BL3-1 NOBITS | | * 0x04037000-->|-----------------------| <<<<<<<<<<<<<<<< |----------------| | * | | <<<<<<<<<<<<<<<< | BL3-1 PROGBITS | | * 0x04023000-->|-----------------------| +----------------+ | * | BL2 | | * |-----------------------| | * | | | * 0x04001000-->|-----------------------| | * | Shared | | * 0x04000000-->+-----------------------+ | * : : | * : Linux : | * : : | * |-----------------------| | * | | U-Boot(BL3-3) Loaded by BL2 | * | U-Boot | <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< * 0x00000000-->+-----------------------+ * * Trusted SRAM section 0x4000000..0x4200000: * ---------------------------------------- * SRAM_BASE = 0x4001000 * BL2_BASE = 0x4006000 * BL2_LIMIT = BL31_BASE * BL31_BASE = 0x4023000 = (64MB + 256KB - 0x1D000) * BL31_PROGBITS_LIMIT = BL1_RW_BASE * BL1_RW_BASE = 0x4037000 = (64MB + 256KB - 0x9000) * BL1_RW_LIMIT = BL31_LIMIT = 0x4040000 * * * PLAT_MARVELL_FIP_BASE = 0x4120000 */ #define PLAT_MARVELL_ATF_BASE 0x4000000 #define PLAT_MARVELL_ATF_LOAD_ADDR \ (PLAT_MARVELL_ATF_BASE + 0x100000) #define PLAT_MARVELL_FIP_BASE \ (PLAT_MARVELL_ATF_LOAD_ADDR + 0x20000) #define PLAT_MARVELL_FIP_MAX_SIZE 0x4000000 #define PLAT_MARVELL_CLUSTER_CORE_COUNT 2 /* DRAM[2MB..66MB] is used as Trusted ROM */ #define PLAT_MARVELL_TRUSTED_ROM_BASE PLAT_MARVELL_ATF_LOAD_ADDR /* 64 MB TODO: reduce this to minimum needed according to fip image size*/ #define PLAT_MARVELL_TRUSTED_ROM_SIZE 0x04000000 /* Reserve 16M for SCP (Secure PayLoad) Trusted DRAM */ #define PLAT_MARVELL_TRUSTED_DRAM_BASE 0x04400000 #define PLAT_MARVELL_TRUSTED_DRAM_SIZE 0x01000000 /* 16 MB */ /* * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size * plus a little space for growth. */ #define PLAT_MARVELL_MAX_BL1_RW_SIZE 0xA000 /* * PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a * little space for growth. */ #define PLAT_MARVELL_MAX_BL2_SIZE 0xF000 /* * PLAT_ARM_MAX_BL31_SIZE is calculated using the current BL31 debug size plus a * little space for growth. */ #define PLAT_MARVEL_MAX_BL31_SIZE 0x5D000 #define PLAT_MARVELL_CPU_ENTRY_ADDR BL1_RO_BASE /* GIC related definitions */ #define PLAT_MARVELL_GICD_BASE (MVEBU_REGS_BASE + MVEBU_GICD_BASE) #define PLAT_MARVELL_GICR_BASE (MVEBU_REGS_BASE + MVEBU_GICR_BASE) #define PLAT_MARVELL_GICC_BASE (MVEBU_REGS_BASE + MVEBU_GICC_BASE) #define PLAT_MARVELL_G0_IRQ_PROPS(grp) \ INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL) #define PLAT_MARVELL_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(MARVELL_IRQ_SEC_PHY_TIMER, \ GIC_HIGHEST_SEC_PRIORITY, grp, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL) #define PLAT_MARVELL_SHARED_RAM_CACHED 1 /* CCI related constants */ #define PLAT_MARVELL_CCI_BASE (MVEBU_REGS_BASE + MVEBU_CCI_BASE) #define PLAT_MARVELL_CCI_CLUSTER0_SL_IFACE_IX 3 #define PLAT_MARVELL_CCI_CLUSTER1_SL_IFACE_IX 4 /* * Load address of BL3-3 for this platform port */ #define PLAT_MARVELL_NS_IMAGE_OFFSET 0x0 /* System Reference Clock*/ #define PLAT_REF_CLK_IN_HZ COUNTER_FREQUENCY /* * PL011 related constants */ #define PLAT_MARVELL_BOOT_UART_BASE (MVEBU_REGS_BASE + 0x12000) #define PLAT_MARVELL_BOOT_UART_CLK_IN_HZ 25804800 #define PLAT_MARVELL_CRASH_UART_BASE PLAT_MARVELL_BOOT_UART_BASE #define PLAT_MARVELL_CRASH_UART_CLK_IN_HZ PLAT_MARVELL_BOOT_UART_CLK_IN_HZ #define PLAT_MARVELL_BL31_RUN_UART_BASE PLAT_MARVELL_BOOT_UART_BASE #define PLAT_MARVELL_BL31_RUN_UART_CLK_IN_HZ PLAT_MARVELL_BOOT_UART_CLK_IN_HZ /* Required platform porting definitions */ #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1 /* System timer related constants */ #define PLAT_MARVELL_NSTIMER_FRAME_ID 1 /* Mailbox base address */ #define PLAT_MARVELL_MAILBOX_BASE \ (MARVELL_TRUSTED_SRAM_BASE + 0x400) #define PLAT_MARVELL_MAILBOX_SIZE 0x100 #define PLAT_MARVELL_MAILBOX_MAGIC_NUM 0x6D72766C /* mrvl */ /* DRAM CS memory map registers related constants */ #define MVEBU_CS_MMAP_LOW(cs_num) \ (MVEBU_CS_MMAP_REG_BASE + (cs_num) * 0x8) #define MVEBU_CS_MMAP_ENABLE 0x1 #define MVEBU_CS_MMAP_AREA_LEN_OFFS 16 #define MVEBU_CS_MMAP_AREA_LEN_MASK \ (0x1f << MVEBU_CS_MMAP_AREA_LEN_OFFS) #define MVEBU_CS_MMAP_START_ADDR_LOW_OFFS 23 #define MVEBU_CS_MMAP_START_ADDR_LOW_MASK \ (0x1ff << MVEBU_CS_MMAP_START_ADDR_LOW_OFFS) #define MVEBU_CS_MMAP_HIGH(cs_num) \ (MVEBU_CS_MMAP_REG_BASE + 0x4 + (cs_num) * 0x8) /* DRAM max CS number */ #define MVEBU_MAX_CS_MMAP_NUM (2) /* CPU decoder window related constants */ #define CPU_DEC_WIN_CTRL_REG(win_num) \ (MVEBU_CPU_DEC_WIN_REG_BASE + (win_num) * 0x10) #define CPU_DEC_CR_WIN_ENABLE 0x1 #define CPU_DEC_CR_WIN_TARGET_OFFS 4 #define CPU_DEC_CR_WIN_TARGET_MASK \ (0xf << CPU_DEC_CR_WIN_TARGET_OFFS) #define CPU_DEC_WIN_SIZE_REG(win_num) \ (MVEBU_CPU_DEC_WIN_REG_BASE + 0x4 + (win_num) * 0x10) #define CPU_DEC_CR_WIN_SIZE_OFFS 0 #define CPU_DEC_CR_WIN_SIZE_MASK \ (0xffff << CPU_DEC_CR_WIN_SIZE_OFFS) #define CPU_DEC_CR_WIN_SIZE_ALIGNMENT 0x10000 #define CPU_DEC_WIN_BASE_REG(win_num) \ (MVEBU_CPU_DEC_WIN_REG_BASE + 0x8 + (win_num) * 0x10) #define CPU_DEC_BR_BASE_OFFS 0 #define CPU_DEC_BR_BASE_MASK \ (0xffff << CPU_DEC_BR_BASE_OFFS) #define CPU_DEC_REMAP_LOW_REG(win_num) \ (MVEBU_CPU_DEC_WIN_REG_BASE + 0xC + (win_num) * 0x10) #define CPU_DEC_RLR_REMAP_LOW_OFFS 0 #define CPU_DEC_RLR_REMAP_LOW_MASK \ (0xffff << CPU_DEC_BR_BASE_OFFS) /* Securities */ #define IRQ_SEC_OS_TICK_INT MARVELL_IRQ_SEC_PHY_TIMER #define TRUSTED_DRAM_BASE PLAT_MARVELL_TRUSTED_DRAM_BASE #define TRUSTED_DRAM_SIZE PLAT_MARVELL_TRUSTED_DRAM_SIZE #ifdef BL32 #define BL32_BASE TRUSTED_DRAM_BASE #define BL32_LIMIT TRUSTED_DRAM_SIZE #endif #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/marvell/a3700/common/io_addr_dec.c000066400000000000000000000126151355360272700241220ustar00rootroot00000000000000/* * Copyright (C) 2016 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #define MVEBU_DEC_WIN_CTRL_REG(base, win, off) (MVEBU_REGS_BASE + (base) + \ (win) * (off)) #define MVEBU_DEC_WIN_BASE_REG(base, win, off) (MVEBU_REGS_BASE + (base) + \ (win) * (off) + 0x4) #define MVEBU_DEC_WIN_REMAP_REG(base, win, off) (MVEBU_REGS_BASE + (base) + \ (win) * (off) + 0x8) #define MVEBU_DEC_WIN_CTRL_SIZE_OFF (16) #define MVEBU_DEC_WIN_ENABLE (0x1) #define MVEBU_DEC_WIN_CTRL_ATTR_OFF (8) #define MVEBU_DEC_WIN_CTRL_TARGET_OFF (4) #define MVEBU_DEC_WIN_CTRL_EN_OFF (0) #define MVEBU_DEC_WIN_BASE_OFF (16) #define MVEBU_WIN_BASE_SIZE_ALIGNMENT (0x10000) /* There are up to 14 IO unit which need address decode in Armada-3700 */ #define IO_UNIT_NUM_MAX (14) #define MVEBU_MAX_ADDRSS_4GB (0x100000000ULL) static void set_io_addr_dec_win(int win_id, uintptr_t base_addr, uintptr_t win_size, struct dec_win_config *dec_win) { uint32_t ctrl = 0; uint32_t base = 0; /* set size */ ctrl = ((win_size / MVEBU_WIN_BASE_SIZE_ALIGNMENT) - 1) << MVEBU_DEC_WIN_CTRL_SIZE_OFF; /* set attr according to IO decode window */ ctrl |= dec_win->win_attr << MVEBU_DEC_WIN_CTRL_ATTR_OFF; /* set target */ ctrl |= DRAM_CPU_DEC_TARGET_NUM << MVEBU_DEC_WIN_CTRL_TARGET_OFF; /* set base */ base = (base_addr / MVEBU_WIN_BASE_SIZE_ALIGNMENT) << MVEBU_DEC_WIN_BASE_OFF; /* set base address*/ mmio_write_32(MVEBU_DEC_WIN_BASE_REG(dec_win->dec_reg_base, win_id, dec_win->win_offset), base); /* set remap window, some unit does not have remap window */ if (win_id < dec_win->max_remap) mmio_write_32(MVEBU_DEC_WIN_REMAP_REG(dec_win->dec_reg_base, win_id, dec_win->win_offset), base); /* set control register */ mmio_write_32(MVEBU_DEC_WIN_CTRL_REG(dec_win->dec_reg_base, win_id, dec_win->win_offset), ctrl); /* enable the address decode window at last to make it effective */ ctrl |= MVEBU_DEC_WIN_ENABLE << MVEBU_DEC_WIN_CTRL_EN_OFF; mmio_write_32(MVEBU_DEC_WIN_CTRL_REG(dec_win->dec_reg_base, win_id, dec_win->win_offset), ctrl); INFO("set_io_addr_dec %d result: ctrl(0x%x) base(0x%x)", win_id, mmio_read_32(MVEBU_DEC_WIN_CTRL_REG(dec_win->dec_reg_base, win_id, dec_win->win_offset)), mmio_read_32(MVEBU_DEC_WIN_BASE_REG(dec_win->dec_reg_base, win_id, dec_win->win_offset))); if (win_id < dec_win->max_remap) INFO(" remap(%x)\n", mmio_read_32(MVEBU_DEC_WIN_REMAP_REG(dec_win->dec_reg_base, win_id, dec_win->win_offset))); else INFO("\n"); } /* Set io decode window */ static int set_io_addr_dec(struct dram_win_map *win_map, struct dec_win_config *dec_win) { struct dram_win *win; int id; /* disable all windows first */ for (id = 0; id < dec_win->max_dram_win; id++) mmio_write_32(MVEBU_DEC_WIN_CTRL_REG(dec_win->dec_reg_base, id, dec_win->win_offset), 0); /* configure IO decode windows for DRAM, inheritate DRAM size, * base and target from CPU-DRAM decode window and others * from hard coded IO decode window settings array. */ if (win_map->dram_win_num > dec_win->max_dram_win) { /* * If cpu dram windows number exceeds the io decode windows * max number, then fill the first io decode window * with base(0) and size(4GB). */ set_io_addr_dec_win(0, 0, MVEBU_MAX_ADDRSS_4GB, dec_win); return 0; } for (id = 0; id < win_map->dram_win_num; id++, win++) { win = &win_map->dram_windows[id]; set_io_addr_dec_win(id, win->base_addr, win->win_size, dec_win); } return 0; } /* * init_io_addr_dec * * This function initializes io address decoder windows by * cpu dram window mapping information * * @input: N/A * - dram_wins_map: cpu dram windows mapping * - io_dec_config: io address decoder windows configuration * - io_unit_num: io address decoder unit number * @output: N/A * * @return: 0 on success and others on failure */ int init_io_addr_dec(struct dram_win_map *dram_wins_map, struct dec_win_config *io_dec_config, uint32_t io_unit_num) { int32_t index; struct dec_win_config *io_dec_win; int32_t ret; INFO("Initializing IO address decode windows\n"); if (io_dec_config == NULL || io_unit_num == 0) { ERROR("No IO address decoder windows configurations!\n"); return -1; } if (io_unit_num > IO_UNIT_NUM_MAX) { ERROR("IO address decoder windows number %d is over max %d\n", io_unit_num, IO_UNIT_NUM_MAX); return -1; } if (dram_wins_map == NULL) { ERROR("No cpu dram decoder windows map!\n"); return -1; } for (index = 0; index < dram_wins_map->dram_win_num; index++) INFO("DRAM mapping %d base(0x%lx) size(0x%lx)\n", index, dram_wins_map->dram_windows[index].base_addr, dram_wins_map->dram_windows[index].win_size); /* Set address decode window for each IO */ for (index = 0; index < io_unit_num; index++) { io_dec_win = io_dec_config + index; ret = set_io_addr_dec(dram_wins_map, io_dec_win); if (ret) { ERROR("Failed to set IO address decode\n"); return -1; } INFO("Set IO decode window successfully, base(0x%x)", io_dec_win->dec_reg_base); INFO(" win_attr(%x) max_dram_win(%d) max_remap(%d)", io_dec_win->win_attr, io_dec_win->max_dram_win, io_dec_win->max_remap); INFO(" win_offset(%d)\n", io_dec_win->win_offset); } return 0; } trusted-firmware-a-2.2/plat/marvell/a3700/common/marvell_plat_config.c000066400000000000000000000021731355360272700257130ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include struct dec_win_config io_dec_win_conf[] = { /* dec_reg_base win_attr max_dram_win max_remap win_offset */ {0xc000, 0x3d, 2, 0, 0x08}, /* USB */ {0xc100, 0x3d, 3, 0, 0x10}, /* USB3 */ {0xc200, 0x3d, 2, 0, 0x10}, /* DMA */ {0xc300, 0x3d, 2, 0, 0x10}, /* NETA0 */ {0xc400, 0x3d, 2, 0, 0x10}, /* NETA1 */ {0xc500, 0x3d, 2, 0, 0x10}, /* PCIe */ {0xc800, 0x3d, 3, 0, 0x10}, /* SATA */ {0xca00, 0x3d, 3, 0, 0x08}, /* SD */ {0xcb00, 0x3d, 3, 0, 0x10}, /* eMMC */ {0xce00, 0x3d, 2, 0, 0x08}, /* EIP97 */ }; int marvell_get_io_dec_win_conf(struct dec_win_config **win, uint32_t *size) { *win = io_dec_win_conf; *size = sizeof(io_dec_win_conf)/sizeof(struct dec_win_config); return 0; } trusted-firmware-a-2.2/plat/marvell/a3700/common/plat_pm.c000066400000000000000000000655311355360272700233470ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #ifdef USE_CCI #include #endif #include #include #include #include #include #include #include #include #include #include #include #include /* Warm reset register */ #define MVEBU_WARM_RESET_REG (MVEBU_NB_REGS_BASE + 0x840) #define MVEBU_WARM_RESET_MAGIC 0x1D1E /* North Bridge GPIO1 SEL register */ #define MVEBU_NB_GPIO1_SEL_REG (MVEBU_NB_REGS_BASE + 0x830) #define MVEBU_NB_GPIO1_UART1_SEL BIT(19) #define MVEBU_NB_GPIO1_GPIO_25_26_EN BIT(17) #define MVEBU_NB_GPIO1_GPIO_19_EN BIT(14) #define MVEBU_NB_GPIO1_GPIO_18_EN BIT(13) /* CPU 1 reset register */ #define MVEBU_CPU_1_RESET_VECTOR (MVEBU_REGS_BASE + 0x14044) #define MVEBU_CPU_1_RESET_REG (MVEBU_REGS_BASE + 0xD00C) #define MVEBU_CPU_1_RESET_BIT 31 /* IRQ register */ #define MVEBU_NB_IRQ_STATUS_1_REG (MVEBU_NB_SB_IRQ_REG_BASE) #define MVEBU_NB_IRQ_STATUS_2_REG (MVEBU_NB_SB_IRQ_REG_BASE + \ 0x10) #define MVEBU_NB_IRQ_MASK_2_REG (MVEBU_NB_SB_IRQ_REG_BASE + \ 0x18) #define MVEBU_SB_IRQ_STATUS_1_REG (MVEBU_NB_SB_IRQ_REG_BASE + \ 0x40) #define MVEBU_SB_IRQ_STATUS_2_REG (MVEBU_NB_SB_IRQ_REG_BASE + \ 0x50) #define MVEBU_NB_GPIO_IRQ_MASK_1_REG (MVEBU_NB_SB_IRQ_REG_BASE + \ 0xC8) #define MVEBU_NB_GPIO_IRQ_MASK_2_REG (MVEBU_NB_SB_IRQ_REG_BASE + \ 0xD8) #define MVEBU_SB_GPIO_IRQ_MASK_REG (MVEBU_NB_SB_IRQ_REG_BASE + \ 0xE8) #define MVEBU_NB_GPIO_IRQ_EN_LOW_REG (MVEBU_NB_GPIO_IRQ_REG_BASE) #define MVEBU_NB_GPIO_IRQ_EN_HIGH_REG (MVEBU_NB_GPIO_IRQ_REG_BASE + \ 0x04) #define MVEBU_NB_GPIO_IRQ_STATUS_LOW_REG (MVEBU_NB_GPIO_IRQ_REG_BASE + \ 0x10) #define MVEBU_NB_GPIO_IRQ_STATUS_HIGH_REG (MVEBU_NB_GPIO_IRQ_REG_BASE + \ 0x14) #define MVEBU_NB_GPIO_IRQ_WK_LOW_REG (MVEBU_NB_GPIO_IRQ_REG_BASE + \ 0x18) #define MVEBU_NB_GPIO_IRQ_WK_HIGH_REG (MVEBU_NB_GPIO_IRQ_REG_BASE + \ 0x1C) #define MVEBU_SB_GPIO_IRQ_EN_REG (MVEBU_SB_GPIO_IRQ_REG_BASE) #define MVEBU_SB_GPIO_IRQ_STATUS_REG (MVEBU_SB_GPIO_IRQ_REG_BASE + \ 0x10) #define MVEBU_SB_GPIO_IRQ_WK_REG (MVEBU_SB_GPIO_IRQ_REG_BASE + \ 0x18) /* PMU registers */ #define MVEBU_PM_NB_PWR_CTRL_REG (MVEBU_PMSU_REG_BASE) #define MVEBU_PM_PWR_DN_CNT_SEL BIT(28) #define MVEBU_PM_SB_PWR_DWN BIT(4) #define MVEBU_PM_INTERFACE_IDLE BIT(0) #define MVEBU_PM_NB_CPU_PWR_CTRL_REG (MVEBU_PMSU_REG_BASE + 0x4) #define MVEBU_PM_L2_FLUSH_EN BIT(22) #define MVEBU_PM_NB_PWR_OPTION_REG (MVEBU_PMSU_REG_BASE + 0x8) #define MVEBU_PM_DDR_SR_EN BIT(29) #define MVEBU_PM_DDR_CLK_DIS_EN BIT(28) #define MVEBU_PM_WARM_RESET_EN BIT(27) #define MVEBU_PM_DDRPHY_PWRDWN_EN BIT(23) #define MVEBU_PM_DDRPHY_PAD_PWRDWN_EN BIT(22) #define MVEBU_PM_OSC_OFF_EN BIT(21) #define MVEBU_PM_TBG_OFF_EN BIT(20) #define MVEBU_PM_CPU_VDDV_OFF_EN BIT(19) #define MVEBU_PM_AVS_DISABLE_MODE BIT(14) #define MVEBU_PM_AVS_VDD2_MODE BIT(13) #define MVEBU_PM_AVS_HOLD_MODE BIT(12) #define MVEBU_PM_L2_SRAM_LKG_PD_EN BIT(8) #define MVEBU_PM_EIP_SRAM_LKG_PD_EN BIT(7) #define MVEBU_PM_DDRMC_SRAM_LKG_PD_EN BIT(6) #define MVEBU_PM_MCI_SRAM_LKG_PD_EN BIT(5) #define MVEBU_PM_MMC_SRAM_LKG_PD_EN BIT(4) #define MVEBU_PM_SATA_SRAM_LKG_PD_EN BIT(3) #define MVEBU_PM_DMA_SRAM_LKG_PD_EN BIT(2) #define MVEBU_PM_SEC_SRAM_LKG_PD_EN BIT(1) #define MVEBU_PM_CPU_SRAM_LKG_PD_EN BIT(0) #define MVEBU_PM_NB_SRAM_LKG_PD_EN (MVEBU_PM_L2_SRAM_LKG_PD_EN |\ MVEBU_PM_EIP_SRAM_LKG_PD_EN | MVEBU_PM_DDRMC_SRAM_LKG_PD_EN |\ MVEBU_PM_MCI_SRAM_LKG_PD_EN | MVEBU_PM_MMC_SRAM_LKG_PD_EN |\ MVEBU_PM_SATA_SRAM_LKG_PD_EN | MVEBU_PM_DMA_SRAM_LKG_PD_EN |\ MVEBU_PM_SEC_SRAM_LKG_PD_EN | MVEBU_PM_CPU_SRAM_LKG_PD_EN) #define MVEBU_PM_NB_PWR_DEBUG_REG (MVEBU_PMSU_REG_BASE + 0xC) #define MVEBU_PM_NB_FORCE_CLK_ON BIT(30) #define MVEBU_PM_IGNORE_CM3_SLEEP BIT(21) #define MVEBU_PM_IGNORE_CM3_DEEP BIT(20) #define MVEBU_PM_NB_WAKE_UP_EN_REG (MVEBU_PMSU_REG_BASE + 0x2C) #define MVEBU_PM_SB_WKP_NB_EN BIT(31) #define MVEBU_PM_NB_GPIO_WKP_EN BIT(27) #define MVEBU_PM_SOC_TIMER_WKP_EN BIT(26) #define MVEBU_PM_UART_WKP_EN BIT(25) #define MVEBU_PM_UART2_WKP_EN BIT(19) #define MVEBU_PM_CPU_TIMER_WKP_EN BIT(17) #define MVEBU_PM_NB_WKP_EN BIT(16) #define MVEBU_PM_CORE1_FIQ_IRQ_WKP_EN BIT(13) #define MVEBU_PM_CORE0_FIQ_IRQ_WKP_EN BIT(12) #define MVEBU_PM_CPU_0_PWR_CTRL_REG (MVEBU_PMSU_REG_BASE + 0x34) #define MVEBU_PM_CPU_1_PWR_CTRL_REG (MVEBU_PMSU_REG_BASE + 0x38) #define MVEBU_PM_CORE_SOC_PD BIT(2) #define MVEBU_PM_CORE_PROC_PD BIT(1) #define MVEBU_PM_CORE_PD BIT(0) #define MVEBU_PM_CORE_1_RETURN_ADDR_REG (MVEBU_PMSU_REG_BASE + 0x44) #define MVEBU_PM_CPU_VDD_OFF_INFO_1_REG (MVEBU_PMSU_REG_BASE + 0x48) #define MVEBU_PM_CPU_VDD_OFF_INFO_2_REG (MVEBU_PMSU_REG_BASE + 0x4C) #define MVEBU_PM_LOW_POWER_STATE BIT(0) #define MVEBU_PM_CPU_WAKE_UP_CONF_REG (MVEBU_PMSU_REG_BASE + 0x54) #define MVEBU_PM_CORE1_WAKEUP BIT(13) #define MVEBU_PM_CORE0_WAKEUP BIT(12) #define MVEBU_PM_WAIT_DDR_RDY_VALUE (0x15) #define MVEBU_PM_SB_CPU_PWR_CTRL_REG (MVEBU_SB_WAKEUP_REG_BASE) #define MVEBU_PM_SB_PM_START BIT(0) #define MVEBU_PM_SB_PWR_OPTION_REG (MVEBU_SB_WAKEUP_REG_BASE + 0x4) #define MVEBU_PM_SDIO_PHY_PDWN_EN BIT(17) #define MVEBU_PM_SB_VDDV_OFF_EN BIT(16) #define MVEBU_PM_EBM_SRAM_LKG_PD_EN BIT(11) #define MVEBU_PM_PCIE_SRAM_LKG_PD_EN BIT(10) #define MVEBU_PM_GBE1_TX_SRAM_LKG_PD_EN BIT(9) #define MVEBU_PM_GBE1_RX_SRAM_LKG_PD_EN BIT(8) #define MVEBU_PM_GBE1_MIB_SRAM_LKG_PD_EN BIT(7) #define MVEBU_PM_GBE0_TX_SRAM_LKG_PD_EN BIT(6) #define MVEBU_PM_GBE0_RX_SRAM_LKG_PD_EN BIT(5) #define MVEBU_PM_GBE0_MIB_SRAM_LKG_PD_EN BIT(4) #define MVEBU_PM_SDIO_SRAM_LKG_PD_EN BIT(3) #define MVEBU_PM_USB2_SRAM_LKG_PD_EN BIT(2) #define MVEBU_PM_USB3_H_SRAM_LKG_PD_EN BIT(1) #define MVEBU_PM_SB_SRAM_LKG_PD_EN (MVEBU_PM_EBM_SRAM_LKG_PD_EN |\ MVEBU_PM_PCIE_SRAM_LKG_PD_EN | MVEBU_PM_GBE1_TX_SRAM_LKG_PD_EN |\ MVEBU_PM_GBE1_RX_SRAM_LKG_PD_EN | MVEBU_PM_GBE1_MIB_SRAM_LKG_PD_EN |\ MVEBU_PM_GBE0_TX_SRAM_LKG_PD_EN | MVEBU_PM_GBE0_RX_SRAM_LKG_PD_EN |\ MVEBU_PM_GBE0_MIB_SRAM_LKG_PD_EN | MVEBU_PM_SDIO_SRAM_LKG_PD_EN |\ MVEBU_PM_USB2_SRAM_LKG_PD_EN | MVEBU_PM_USB3_H_SRAM_LKG_PD_EN) #define MVEBU_PM_SB_WK_EN_REG (MVEBU_SB_WAKEUP_REG_BASE + 0x10) #define MVEBU_PM_SB_GPIO_WKP_EN BIT(24) #define MVEBU_PM_SB_WKP_EN BIT(20) /* DRAM registers */ #define MVEBU_DRAM_STATS_CH0_REG (MVEBU_DRAM_REG_BASE + 0x4) #define MVEBU_DRAM_WCP_EMPTY BIT(19) #define MVEBU_DRAM_CMD_0_REG (MVEBU_DRAM_REG_BASE + 0x20) #define MVEBU_DRAM_CH0_CMD0 BIT(28) #define MVEBU_DRAM_CS_CMD0 BIT(24) #define MVEBU_DRAM_WCB_DRAIN_REQ BIT(1) #define MVEBU_DRAM_PWR_CTRL_REG (MVEBU_DRAM_REG_BASE + 0x54) #define MVEBU_DRAM_PHY_CLK_GATING_EN BIT(1) #define MVEBU_DRAM_PHY_AUTO_AC_OFF_EN BIT(0) /* AVS registers */ #define MVEBU_AVS_CTRL_2_REG (MVEBU_AVS_REG_BASE + 0x8) #define MVEBU_LOW_VDD_MODE_EN BIT(6) /* Clock registers */ #define MVEBU_NB_CLOCK_SEL_REG (MVEBU_NB_REGS_BASE + 0x10) #define MVEBU_A53_CPU_CLK_SEL BIT(15) /* North Bridge Step-Down Registers */ #define MVEBU_NB_STEP_DOWN_INT_EN_REG MVEBU_NB_STEP_DOWN_REG_BASE #define MVEBU_NB_GPIO_INT_WAKE_WCPU_CLK BIT(8) #define MVEBU_NB_GPIO_18 18 #define MVEBU_NB_GPIO_19 19 #define MVEBU_NB_GPIO_25 25 #define MVEBU_NB_GPIO_26 26 typedef int (*wake_up_src_func)(union pm_wake_up_src_data *); struct wake_up_src_func_map { enum pm_wake_up_src_type type; wake_up_src_func func; }; void marvell_psci_arch_init(int die_index) { } static void a3700_pm_ack_irq(void) { uint32_t reg; reg = mmio_read_32(MVEBU_NB_IRQ_STATUS_1_REG); if (reg) mmio_write_32(MVEBU_NB_IRQ_STATUS_1_REG, reg); reg = mmio_read_32(MVEBU_NB_IRQ_STATUS_2_REG); if (reg) mmio_write_32(MVEBU_NB_IRQ_STATUS_2_REG, reg); reg = mmio_read_32(MVEBU_SB_IRQ_STATUS_1_REG); if (reg) mmio_write_32(MVEBU_SB_IRQ_STATUS_1_REG, reg); reg = mmio_read_32(MVEBU_SB_IRQ_STATUS_2_REG); if (reg) mmio_write_32(MVEBU_SB_IRQ_STATUS_2_REG, reg); reg = mmio_read_32(MVEBU_NB_GPIO_IRQ_STATUS_LOW_REG); if (reg) mmio_write_32(MVEBU_NB_GPIO_IRQ_STATUS_LOW_REG, reg); reg = mmio_read_32(MVEBU_NB_GPIO_IRQ_STATUS_HIGH_REG); if (reg) mmio_write_32(MVEBU_NB_GPIO_IRQ_STATUS_HIGH_REG, reg); reg = mmio_read_32(MVEBU_SB_GPIO_IRQ_STATUS_REG); if (reg) mmio_write_32(MVEBU_SB_GPIO_IRQ_STATUS_REG, reg); } /***************************************************************************** * A3700 handler called to check the validity of the power state * parameter. ***************************************************************************** */ int a3700_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { ERROR("%s needs to be implemented\n", __func__); panic(); } /***************************************************************************** * A3700 handler called when a CPU is about to enter standby. ***************************************************************************** */ void a3700_cpu_standby(plat_local_state_t cpu_state) { ERROR("%s needs to be implemented\n", __func__); panic(); } /***************************************************************************** * A3700 handler called when a power domain is about to be turned on. The * mpidr determines the CPU to be turned on. ***************************************************************************** */ int a3700_pwr_domain_on(u_register_t mpidr) { /* Set barrier */ dsbsy(); /* Set the cpu start address to BL1 entry point */ mmio_write_32(MVEBU_CPU_1_RESET_VECTOR, PLAT_MARVELL_CPU_ENTRY_ADDR >> 2); /* Get the cpu out of reset */ mmio_clrbits_32(MVEBU_CPU_1_RESET_REG, BIT(MVEBU_CPU_1_RESET_BIT)); mmio_setbits_32(MVEBU_CPU_1_RESET_REG, BIT(MVEBU_CPU_1_RESET_BIT)); return 0; } /***************************************************************************** * A3700 handler called to validate the entry point. ***************************************************************************** */ int a3700_validate_ns_entrypoint(uintptr_t entrypoint) { return PSCI_E_SUCCESS; } /***************************************************************************** * A3700 handler called when a power domain is about to be turned off. The * target_state encodes the power state that each level should transition to. ***************************************************************************** */ void a3700_pwr_domain_off(const psci_power_state_t *target_state) { /* Prevent interrupts from spuriously waking up this cpu */ plat_marvell_gic_cpuif_disable(); /* Core can not be powered down with pending IRQ, * acknowledge all the pending IRQ */ a3700_pm_ack_irq(); } static void a3700_set_gen_pwr_off_option(void) { /* Enable L2 flush -> processor state-machine option */ mmio_setbits_32(MVEBU_PM_NB_CPU_PWR_CTRL_REG, MVEBU_PM_L2_FLUSH_EN); /* * North bridge cannot be VDD off (always ON). * The NB state machine support low power mode by its state machine. * This bit MUST be set for north bridge power down, e.g., * OSC input cutoff(NOT TEST), SRAM power down, PMIC, etc. * It is not related to CPU VDD OFF!! */ mmio_clrbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_CPU_VDDV_OFF_EN); /* * MUST: Switch CPU/AXI clock to OSC * NB state machine clock is always connected to OSC (slow clock). * But Core0/1/processor state machine's clock are connected to AXI * clock. Now, AXI clock takes the TBG as clock source. * If using AXI clock, Core0/1/processor state machine may much faster * than NB state machine. It will cause problem in this case if cores * are released before north bridge gets ready. */ mmio_clrbits_32(MVEBU_NB_CLOCK_SEL_REG, MVEBU_A53_CPU_CLK_SEL); /* * These register bits will trigger north bridge * power-down state machine regardless CM3 status. */ mmio_setbits_32(MVEBU_PM_NB_PWR_DEBUG_REG, MVEBU_PM_IGNORE_CM3_SLEEP); mmio_setbits_32(MVEBU_PM_NB_PWR_DEBUG_REG, MVEBU_PM_IGNORE_CM3_DEEP); /* * SRAM => controlled by north bridge state machine. * Core VDD OFF is not related to CPU SRAM power down. */ mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_NB_SRAM_LKG_PD_EN); /* * Idle AXI interface in order to get L2_WFI * L2 WFI is only asserted after CORE-0 and CORE-1 WFI asserted. * (only both core-0/1in WFI, L2 WFI will be issued by CORE.) * Once L2 WFI asserted, this bit is used for signalling assertion * to AXI IO masters. */ mmio_setbits_32(MVEBU_PM_NB_PWR_CTRL_REG, MVEBU_PM_INTERFACE_IDLE); /* Enable core0 and core1 VDD_OFF */ mmio_setbits_32(MVEBU_PM_CPU_0_PWR_CTRL_REG, MVEBU_PM_CORE_PD); mmio_setbits_32(MVEBU_PM_CPU_1_PWR_CTRL_REG, MVEBU_PM_CORE_PD); /* Enable North bridge power down - * Both Cores MUST enable this bit to power down north bridge! */ mmio_setbits_32(MVEBU_PM_CPU_0_PWR_CTRL_REG, MVEBU_PM_CORE_SOC_PD); mmio_setbits_32(MVEBU_PM_CPU_1_PWR_CTRL_REG, MVEBU_PM_CORE_SOC_PD); /* CA53 (processor domain) power down */ mmio_setbits_32(MVEBU_PM_CPU_0_PWR_CTRL_REG, MVEBU_PM_CORE_PROC_PD); mmio_setbits_32(MVEBU_PM_CPU_1_PWR_CTRL_REG, MVEBU_PM_CORE_PROC_PD); } static void a3700_en_ddr_self_refresh(void) { /* * Both count is 16 bits and configurable. By default, osc stb cnt * is 0xFFF for lower 12 bits. * Thus, powerdown count is smaller than osc count. * This count is used for exiting DDR SR mode on wakeup event. * The powerdown count also has impact on the following * state changes: idle -> count-down -> ... (power-down, vdd off, etc) * Here, make stable counter shorter * Use power down count value instead of osc_stb_cnt to speed up * DDR self refresh exit */ mmio_setbits_32(MVEBU_PM_NB_PWR_CTRL_REG, MVEBU_PM_PWR_DN_CNT_SEL); /* * Enable DDR SR mode => controlled by north bridge state machine * Therefore, we must powerdown north bridge to trigger the DDR SR * mode switching. */ mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_DDR_SR_EN); /* Disable DDR clock, otherwise DDR will not enter into SR mode. */ mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_DDR_CLK_DIS_EN); /* Power down DDR PHY (PAD) */ mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_DDRPHY_PWRDWN_EN); mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_DDRPHY_PAD_PWRDWN_EN); /* Set wait time for DDR ready in ROM code */ mmio_write_32(MVEBU_PM_CPU_VDD_OFF_INFO_1_REG, MVEBU_PM_WAIT_DDR_RDY_VALUE); /* DDR flush write buffer - mandatory */ mmio_write_32(MVEBU_DRAM_CMD_0_REG, MVEBU_DRAM_CH0_CMD0 | MVEBU_DRAM_CS_CMD0 | MVEBU_DRAM_WCB_DRAIN_REQ); while ((mmio_read_32(MVEBU_DRAM_STATS_CH0_REG) & MVEBU_DRAM_WCP_EMPTY) != MVEBU_DRAM_WCP_EMPTY) ; /* Trigger PHY reset after ddr out of self refresh => * supply reset pulse for DDR phy after wake up */ mmio_setbits_32(MVEBU_DRAM_PWR_CTRL_REG, MVEBU_DRAM_PHY_CLK_GATING_EN | MVEBU_DRAM_PHY_AUTO_AC_OFF_EN); } static void a3700_pwr_dn_avs(void) { /* * AVS power down - controlled by north bridge statemachine * Enable AVS power down by clear the AVS disable bit. */ mmio_clrbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_AVS_DISABLE_MODE); /* * Should set BIT[12:13] to powerdown AVS. * 1. Enable AVS VDD2 mode * 2. After power down AVS, we must hold AVS output voltage. * 3. We can choose the lower VDD for AVS power down. */ mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_AVS_VDD2_MODE); mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_AVS_HOLD_MODE); /* Enable low VDD mode, AVS will set CPU to lowest core VDD 747mV */ mmio_setbits_32(MVEBU_AVS_CTRL_2_REG, MVEBU_LOW_VDD_MODE_EN); } static void a3700_pwr_dn_tbg(void) { /* Power down TBG */ mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_TBG_OFF_EN); } static void a3700_pwr_dn_sb(void) { /* Enable south bridge power down option */ mmio_setbits_32(MVEBU_PM_NB_PWR_CTRL_REG, MVEBU_PM_SB_PWR_DWN); /* Enable SDIO_PHY_PWRDWN */ mmio_setbits_32(MVEBU_PM_SB_PWR_OPTION_REG, MVEBU_PM_SDIO_PHY_PDWN_EN); /* Enable SRAM LRM on SB */ mmio_setbits_32(MVEBU_PM_SB_PWR_OPTION_REG, MVEBU_PM_SB_SRAM_LKG_PD_EN); /* Enable SB Power Off */ mmio_setbits_32(MVEBU_PM_SB_PWR_OPTION_REG, MVEBU_PM_SB_VDDV_OFF_EN); /* Kick off South Bridge Power Off */ mmio_setbits_32(MVEBU_PM_SB_CPU_PWR_CTRL_REG, MVEBU_PM_SB_PM_START); } static void a3700_set_pwr_off_option(void) { /* Set general power off option */ a3700_set_gen_pwr_off_option(); /* Enable DDR self refresh in low power mode */ a3700_en_ddr_self_refresh(); /* Power down AVS */ a3700_pwr_dn_avs(); /* Power down TBG */ a3700_pwr_dn_tbg(); /* Power down south bridge, pay attention south bridge setting * should be done before */ a3700_pwr_dn_sb(); } static void a3700_set_wake_up_option(void) { /* * Enable the wakeup event for NB SOC => north-bridge * state-machine enablement on wake-up event */ mmio_setbits_32(MVEBU_PM_NB_WAKE_UP_EN_REG, MVEBU_PM_NB_WKP_EN); /* Enable both core0 and core1 wakeup on demand */ mmio_setbits_32(MVEBU_PM_CPU_WAKE_UP_CONF_REG, MVEBU_PM_CORE1_WAKEUP | MVEBU_PM_CORE0_WAKEUP); /* Enable warm reset in low power mode */ mmio_setbits_32(MVEBU_PM_NB_PWR_OPTION_REG, MVEBU_PM_WARM_RESET_EN); } static void a3700_pm_en_nb_gpio(uint32_t gpio) { /* For GPIO1 interrupt -- North bridge only */ if (gpio >= 32) { /* GPIO int mask */ mmio_clrbits_32(MVEBU_NB_GPIO_IRQ_MASK_2_REG, BIT(gpio - 32)); /* NB_CPU_WAKE-up ENABLE GPIO int */ mmio_setbits_32(MVEBU_NB_GPIO_IRQ_EN_HIGH_REG, BIT(gpio - 32)); } else { /* GPIO int mask */ mmio_clrbits_32(MVEBU_NB_GPIO_IRQ_MASK_1_REG, BIT(gpio)); /* NB_CPU_WAKE-up ENABLE GPIO int */ mmio_setbits_32(MVEBU_NB_GPIO_IRQ_EN_LOW_REG, BIT(gpio)); } mmio_setbits_32(MVEBU_NB_STEP_DOWN_INT_EN_REG, MVEBU_NB_GPIO_INT_WAKE_WCPU_CLK); /* Enable using GPIO as wakeup event * (actually not only for north bridge) */ mmio_setbits_32(MVEBU_PM_NB_WAKE_UP_EN_REG, MVEBU_PM_NB_GPIO_WKP_EN | MVEBU_PM_NB_WKP_EN | MVEBU_PM_CORE1_FIQ_IRQ_WKP_EN | MVEBU_PM_CORE0_FIQ_IRQ_WKP_EN); } static void a3700_pm_en_sb_gpio(uint32_t gpio) { /* Enable using GPIO as wakeup event */ mmio_setbits_32(MVEBU_PM_NB_WAKE_UP_EN_REG, MVEBU_PM_SB_WKP_NB_EN | MVEBU_PM_NB_WKP_EN | MVEBU_PM_CORE1_FIQ_IRQ_WKP_EN | MVEBU_PM_CORE0_FIQ_IRQ_WKP_EN); /* SB GPIO Wake UP | South Bridge Wake Up Enable */ mmio_setbits_32(MVEBU_PM_SB_WK_EN_REG, MVEBU_PM_SB_GPIO_WKP_EN | MVEBU_PM_SB_GPIO_WKP_EN); /* GPIO int mask */ mmio_clrbits_32(MVEBU_SB_GPIO_IRQ_MASK_REG, BIT(gpio)); /* NB_CPU_WAKE-up ENABLE GPIO int */ mmio_setbits_32(MVEBU_SB_GPIO_IRQ_EN_REG, BIT(gpio)); } int a3700_pm_src_gpio(union pm_wake_up_src_data *src_data) { if (src_data->gpio_data.bank_num == 0) /* North Bridge GPIO */ a3700_pm_en_nb_gpio(src_data->gpio_data.gpio_num); else a3700_pm_en_sb_gpio(src_data->gpio_data.gpio_num); return 0; } int a3700_pm_src_uart1(union pm_wake_up_src_data *src_data) { /* Clear Uart1 select */ mmio_clrbits_32(MVEBU_NB_GPIO1_SEL_REG, MVEBU_NB_GPIO1_UART1_SEL); /* set pin 19 gpio usage*/ mmio_setbits_32(MVEBU_NB_GPIO1_SEL_REG, MVEBU_NB_GPIO1_GPIO_19_EN); /* Enable gpio wake-up*/ a3700_pm_en_nb_gpio(MVEBU_NB_GPIO_19); /* set pin 18 gpio usage*/ mmio_setbits_32(MVEBU_NB_GPIO1_SEL_REG, MVEBU_NB_GPIO1_GPIO_18_EN); /* Enable gpio wake-up*/ a3700_pm_en_nb_gpio(MVEBU_NB_GPIO_18); return 0; } int a3700_pm_src_uart0(union pm_wake_up_src_data *src_data) { /* set pin 25/26 gpio usage*/ mmio_setbits_32(MVEBU_NB_GPIO1_SEL_REG, MVEBU_NB_GPIO1_GPIO_25_26_EN); /* Enable gpio wake-up*/ a3700_pm_en_nb_gpio(MVEBU_NB_GPIO_25); /* Enable gpio wake-up*/ a3700_pm_en_nb_gpio(MVEBU_NB_GPIO_26); return 0; } struct wake_up_src_func_map src_func_table[WAKE_UP_SRC_MAX] = { {WAKE_UP_SRC_GPIO, a3700_pm_src_gpio}, {WAKE_UP_SRC_UART1, a3700_pm_src_uart1}, {WAKE_UP_SRC_UART0, a3700_pm_src_uart0}, /* FOLLOWING SRC NOT SUPPORTED YET */ {WAKE_UP_SRC_TIMER, NULL} }; static wake_up_src_func a3700_get_wake_up_src_func( enum pm_wake_up_src_type type) { uint32_t loop; for (loop = 0; loop < WAKE_UP_SRC_MAX; loop++) { if (src_func_table[loop].type == type) return src_func_table[loop].func; } return NULL; } static void a3700_set_wake_up_source(void) { struct pm_wake_up_src_config *wake_up_src; uint32_t loop; wake_up_src_func src_func = NULL; wake_up_src = mv_wake_up_src_config_get(); for (loop = 0; loop < wake_up_src->wake_up_src_num; loop++) { src_func = a3700_get_wake_up_src_func( wake_up_src->wake_up_src[loop].wake_up_src_type); if (src_func) src_func( &(wake_up_src->wake_up_src[loop].wake_up_data)); } } static void a3700_pm_save_lp_flag(void) { /* Save the flag for enter the low power mode */ mmio_setbits_32(MVEBU_PM_CPU_VDD_OFF_INFO_2_REG, MVEBU_PM_LOW_POWER_STATE); } static void a3700_pm_clear_lp_flag(void) { /* Clear the flag for enter the low power mode */ mmio_clrbits_32(MVEBU_PM_CPU_VDD_OFF_INFO_2_REG, MVEBU_PM_LOW_POWER_STATE); } static uint32_t a3700_pm_get_lp_flag(void) { /* Get the flag for enter the low power mode */ return mmio_read_32(MVEBU_PM_CPU_VDD_OFF_INFO_2_REG) & MVEBU_PM_LOW_POWER_STATE; } /***************************************************************************** * A3700 handler called when a power domain is about to be suspended. The * target_state encodes the power state that each level should transition to. ***************************************************************************** */ void a3700_pwr_domain_suspend(const psci_power_state_t *target_state) { /* Prevent interrupts from spuriously waking up this cpu */ plat_marvell_gic_cpuif_disable(); /* Save IRQ states */ plat_marvell_gic_irq_save(); /* Set wake up options */ a3700_set_wake_up_option(); /* Set wake up sources */ a3700_set_wake_up_source(); /* SoC can not be powered down with pending IRQ, * acknowledge all the pending IRQ */ a3700_pm_ack_irq(); /* Set power off options */ a3700_set_pwr_off_option(); /* Save the flag for enter the low power mode */ a3700_pm_save_lp_flag(); isb(); } /***************************************************************************** * A3700 handler called when a power domain has just been powered on after * being turned off earlier. The target_state encodes the low power state that * each level has woken up from. ***************************************************************************** */ void a3700_pwr_domain_on_finish(const psci_power_state_t *target_state) { /* arch specific configuration */ marvell_psci_arch_init(0); /* Per-CPU interrupt initialization */ plat_marvell_gic_pcpu_init(); plat_marvell_gic_cpuif_enable(); /* Restore the per-cpu IRQ state */ if (a3700_pm_get_lp_flag()) plat_marvell_gic_irq_pcpu_restore(); } /***************************************************************************** * A3700 handler called when a power domain has just been powered on after * having been suspended earlier. The target_state encodes the low power state * that each level has woken up from. * TODO: At the moment we reuse the on finisher and reinitialize the secure * context. Need to implement a separate suspend finisher. ***************************************************************************** */ void a3700_pwr_domain_suspend_finish(const psci_power_state_t *target_state) { struct dec_win_config *io_dec_map; uint32_t dec_win_num; struct dram_win_map dram_wins_map; /* arch specific configuration */ marvell_psci_arch_init(0); /* Interrupt initialization */ plat_marvell_gic_init(); /* Restore IRQ states */ plat_marvell_gic_irq_restore(); /* * Initialize CCI for this cluster after resume from suspend state. * No need for locks as no other CPU is active. */ plat_marvell_interconnect_init(); /* * Enable CCI coherency for the primary CPU's cluster. * Platform specific PSCI code will enable coherency for other * clusters. */ plat_marvell_interconnect_enter_coherency(); /* CPU address decoder windows initialization. */ cpu_wins_init(); /* fetch CPU-DRAM window mapping information by reading * CPU-DRAM decode windows (only the enabled ones) */ dram_win_map_build(&dram_wins_map); /* Get IO address decoder windows */ if (marvell_get_io_dec_win_conf(&io_dec_map, &dec_win_num)) { printf("No IO address decoder windows configurations found!\n"); return; } /* IO address decoder init */ if (init_io_addr_dec(&dram_wins_map, io_dec_map, dec_win_num)) { printf("IO address decoder windows initialization failed!\n"); return; } /* Clear low power mode flag */ a3700_pm_clear_lp_flag(); } /***************************************************************************** * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND * call to get the `power_state` parameter. This allows the platform to encode * the appropriate State-ID field within the `power_state` parameter which can * be utilized in `pwr_domain_suspend()` to suspend to system affinity level. ***************************************************************************** */ void a3700_get_sys_suspend_power_state(psci_power_state_t *req_state) { /* lower affinities use PLAT_MAX_OFF_STATE */ for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; } /***************************************************************************** * A3700 handlers to shutdown/reboot the system ***************************************************************************** */ static void __dead2 a3700_system_off(void) { ERROR("%s needs to be implemented\n", __func__); panic(); } /***************************************************************************** * A3700 handlers to reset the system ***************************************************************************** */ static void __dead2 a3700_system_reset(void) { /* Clean the mailbox magic number to let it as act like cold boot */ mmio_write_32(PLAT_MARVELL_MAILBOX_BASE, 0x0); dsbsy(); /* Flush data cache if the mail box shared RAM is cached */ #if PLAT_MARVELL_SHARED_RAM_CACHED flush_dcache_range((uintptr_t)PLAT_MARVELL_MAILBOX_BASE, 2 * sizeof(uint64_t)); #endif /* Trigger the warm reset */ mmio_write_32(MVEBU_WARM_RESET_REG, MVEBU_WARM_RESET_MAGIC); /* Shouldn't get to this point */ panic(); } /***************************************************************************** * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard * platform layer will take care of registering the handlers with PSCI. ***************************************************************************** */ const plat_psci_ops_t plat_arm_psci_pm_ops = { .cpu_standby = a3700_cpu_standby, .pwr_domain_on = a3700_pwr_domain_on, .pwr_domain_off = a3700_pwr_domain_off, .pwr_domain_suspend = a3700_pwr_domain_suspend, .pwr_domain_on_finish = a3700_pwr_domain_on_finish, .pwr_domain_suspend_finish = a3700_pwr_domain_suspend_finish, .get_sys_suspend_power_state = a3700_get_sys_suspend_power_state, .system_off = a3700_system_off, .system_reset = a3700_system_reset, .validate_power_state = a3700_validate_power_state, .validate_ns_entrypoint = a3700_validate_ns_entrypoint }; trusted-firmware-a-2.2/plat/marvell/a8k/000077500000000000000000000000001355360272700201765ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a8k/a70x0/000077500000000000000000000000001355360272700210355ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a8k/a70x0/board/000077500000000000000000000000001355360272700221245ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a8k/a70x0/board/dram_port.c000066400000000000000000000047241355360272700242660ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include /* * This function may modify the default DRAM parameters * based on information received from SPD or bootloader * configuration located on non volatile storage */ void plat_marvell_dram_update_topology(void) { } /* * This struct provides the DRAM training code with * the appropriate board DRAM configuration */ static struct mv_ddr_topology_map board_topology_map = { /* FIXME: MISL board 2CS 4Gb x8 devices of micron - 2133P */ DEBUG_LEVEL_ERROR, 0x1, /* active interfaces */ /* cs_mask, mirror, dqs_swap, ck_swap X subphys */ { { { {0x3, 0x2, 0, 0}, {0x3, 0x2, 0, 0}, {0x3, 0x2, 0, 0}, {0x3, 0x2, 0, 0}, {0x3, 0x2, 0, 0}, {0x3, 0x2, 0, 0}, {0x3, 0x2, 0, 0}, {0x3, 0x2, 0, 0}, {0x3, 0x2, 0, 0} }, SPEED_BIN_DDR_2133P, /* speed_bin */ MV_DDR_DEV_WIDTH_8BIT, /* sdram device width */ MV_DDR_DIE_CAP_4GBIT, /* die capacity */ MV_DDR_FREQ_SAR, /* frequency */ 0, 0, /* cas_l, cas_wl */ MV_DDR_TEMP_LOW} }, /* temperature */ MV_DDR_32BIT_ECC_PUP8_BUS_MASK, /* subphys mask */ MV_DDR_CFG_DEFAULT, /* ddr configuration data source */ { {0} }, /* raw spd data */ {0}, /* timing parameters */ { /* electrical configuration */ { /* memory electrical configuration */ MV_DDR_RTT_NOM_PARK_RZQ_DISABLE, /* rtt_nom */ { MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */ MV_DDR_RTT_NOM_PARK_RZQ_DIV1 /* rtt_park 2cs */ }, { MV_DDR_RTT_WR_DYN_ODT_OFF, /* rtt_wr 1cs */ MV_DDR_RTT_WR_RZQ_DIV2 /* rtt_wr 2cs */ }, MV_DDR_DIC_RZQ_DIV7 /* dic */ }, { /* phy electrical configuration */ MV_DDR_OHM_30, /* data_drv_p */ MV_DDR_OHM_30, /* data_drv_n */ MV_DDR_OHM_30, /* ctrl_drv_p */ MV_DDR_OHM_30, /* ctrl_drv_n */ { MV_DDR_OHM_60, /* odt_p 1cs */ MV_DDR_OHM_120 /* odt_p 2cs */ }, { MV_DDR_OHM_60, /* odt_n 1cs */ MV_DDR_OHM_120 /* odt_n 2cs */ }, }, { /* mac electrical configuration */ MV_DDR_ODT_CFG_NORMAL, /* odtcfg_pattern */ MV_DDR_ODT_CFG_ALWAYS_ON, /* odtcfg_write */ MV_DDR_ODT_CFG_NORMAL, /* odtcfg_read */ }, } }; struct mv_ddr_topology_map *mv_ddr_topology_map_get(void) { /* Return the board topology as defined in the board code */ return &board_topology_map; } trusted-firmware-a-2.2/plat/marvell/a8k/a70x0/board/marvell_plat_config.c000066400000000000000000000070631355360272700263050ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include /* * If bootrom is currently at BLE there's no need to include the memory * maps structure at this point */ #include #ifndef IMAGE_BLE /***************************************************************************** * AMB Configuration ***************************************************************************** */ struct addr_map_win amb_memory_map[] = { /* CP0 SPI1 CS0 Direct Mode access */ {0xf900, 0x1000000, AMB_SPI1_CS0_ID}, }; int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size, uintptr_t base) { *win = amb_memory_map; if (*win == NULL) *size = 0; else *size = ARRAY_SIZE(amb_memory_map); return 0; } #endif /***************************************************************************** * IO_WIN Configuration ***************************************************************************** */ struct addr_map_win io_win_memory_map[] = { #ifndef IMAGE_BLE /* MCI 0 indirect window */ {MVEBU_MCI_REG_BASE_REMAP(0), 0x100000, MCI_0_TID}, /* MCI 1 indirect window */ {MVEBU_MCI_REG_BASE_REMAP(1), 0x100000, MCI_1_TID}, #endif }; uint32_t marvell_get_io_win_gcr_target(int ap_index) { return PIDI_TID; } int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win, uint32_t *size) { *win = io_win_memory_map; if (*win == NULL) *size = 0; else *size = ARRAY_SIZE(io_win_memory_map); return 0; } #ifndef IMAGE_BLE /***************************************************************************** * IOB Configuration ***************************************************************************** */ struct addr_map_win iob_memory_map[] = { /* PEX1_X1 window */ {0x00000000f7000000, 0x1000000, PEX1_TID}, /* PEX2_X1 window */ {0x00000000f8000000, 0x1000000, PEX2_TID}, {0x00000000c0000000, 0x30000000, PEX2_TID}, {0x0000000800000000, 0x100000000, PEX2_TID}, /* PEX0_X4 window */ {0x00000000f6000000, 0x1000000, PEX0_TID}, /* SPI1_CS0 (RUNIT) window */ {0x00000000f9000000, 0x1000000, RUNIT_TID}, }; int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size, uintptr_t base) { *win = iob_memory_map; *size = ARRAY_SIZE(iob_memory_map); return 0; } #endif /***************************************************************************** * CCU Configuration ***************************************************************************** */ struct addr_map_win ccu_memory_map[] = { /* IO window */ #ifdef IMAGE_BLE {0x00000000f2000000, 0x4000000, IO_0_TID}, /* IO window */ #else {0x00000000f2000000, 0xe000000, IO_0_TID}, {0x00000000c0000000, 0x30000000, IO_0_TID}, /* IO window */ {0x0000000800000000, 0x100000000, IO_0_TID}, /* IO window */ #endif }; uint32_t marvell_get_ccu_gcr_target(int ap) { return DRAM_0_TID; } int marvell_get_ccu_memory_map(int ap_index, struct addr_map_win **win, uint32_t *size) { *win = ccu_memory_map; *size = ARRAY_SIZE(ccu_memory_map); return 0; } #ifdef IMAGE_BLE /***************************************************************************** * SKIP IMAGE Configuration ***************************************************************************** */ #if PLAT_RECOVERY_IMAGE_ENABLE struct skip_image skip_im = { .detection_method = GPIO, .info.gpio.num = 33, .info.gpio.button_state = HIGH, .info.test.cp_ap = CP, .info.test.cp_index = 0, }; void *plat_marvell_get_skip_image_data(void) { /* Return the skip_image configurations */ return &skip_im; } #endif #endif trusted-firmware-a-2.2/plat/marvell/a8k/a70x0/mvebu_def.h000066400000000000000000000004231355360272700231410ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MVEBU_DEF_H #define MVEBU_DEF_H #include #define CP_COUNT 1 /* A70x0 has single CP0 */ #endif /* MVEBU_DEF_H */ trusted-firmware-a-2.2/plat/marvell/a8k/a70x0/platform.mk000066400000000000000000000006271355360272700232170ustar00rootroot00000000000000# # Copyright (C) 2018 Marvell International Ltd. # # SPDX-License-Identifier: BSD-3-Clause # https://spdx.org/licenses # PCI_EP_SUPPORT := 0 CP_NUM := 1 $(eval $(call add_define,CP_NUM)) DOIMAGE_SEC := tools/doimage/secure/sec_img_7K.cfg MARVELL_MOCHI_DRV := drivers/marvell/mochi/apn806_setup.c include plat/marvell/a8k/common/a8k_common.mk include plat/marvell/common/marvell_common.mk trusted-firmware-a-2.2/plat/marvell/a8k/a70x0_amc/000077500000000000000000000000001355360272700216555ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a8k/a70x0_amc/board/000077500000000000000000000000001355360272700227445ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a8k/a70x0_amc/board/dram_port.c000066400000000000000000000047241355360272700251060ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include /* * This function may modify the default DRAM parameters * based on information received from SPD or bootloader * configuration located on non volatile storage */ void plat_marvell_dram_update_topology(void) { } /* * This struct provides the DRAM training code with * the appropriate board DRAM configuration */ static struct mv_ddr_topology_map board_topology_map = { /* FIXME: MISL board 2CS 8Gb x8 devices of micron - 2133P */ DEBUG_LEVEL_ERROR, 0x1, /* active interfaces */ /* cs_mask, mirror, dqs_swap, ck_swap X subphys */ { { { {0x3, 0x2, 0, 0}, {0x3, 0x2, 0, 0}, {0x3, 0x2, 0, 0}, {0x3, 0x2, 0, 0}, {0x3, 0x2, 0, 0}, {0x3, 0x2, 0, 0}, {0x3, 0x2, 0, 0}, {0x3, 0x2, 0, 0}, {0x3, 0x2, 0, 0} }, SPEED_BIN_DDR_2400T, /* speed_bin */ MV_DDR_DEV_WIDTH_8BIT, /* sdram device width */ MV_DDR_DIE_CAP_8GBIT, /* die capacity */ MV_DDR_FREQ_SAR, /* frequency */ 0, 0, /* cas_l, cas_wl */ MV_DDR_TEMP_LOW} }, /* temperature */ MV_DDR_32BIT_ECC_PUP8_BUS_MASK, /* subphys mask */ MV_DDR_CFG_DEFAULT, /* ddr configuration data source */ { {0} }, /* raw spd data */ {0}, /* timing parameters */ { /* electrical configuration */ { /* memory electrical configuration */ MV_DDR_RTT_NOM_PARK_RZQ_DISABLE, /* rtt_nom */ { MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */ MV_DDR_RTT_NOM_PARK_RZQ_DIV1 /* rtt_park 2cs */ }, { MV_DDR_RTT_WR_DYN_ODT_OFF, /* rtt_wr 1cs */ MV_DDR_RTT_WR_RZQ_DIV2 /* rtt_wr 2cs */ }, MV_DDR_DIC_RZQ_DIV7 /* dic */ }, { /* phy electrical configuration */ MV_DDR_OHM_30, /* data_drv_p */ MV_DDR_OHM_30, /* data_drv_n */ MV_DDR_OHM_30, /* ctrl_drv_p */ MV_DDR_OHM_30, /* ctrl_drv_n */ { MV_DDR_OHM_60, /* odt_p 1cs */ MV_DDR_OHM_120 /* odt_p 2cs */ }, { MV_DDR_OHM_60, /* odt_n 1cs */ MV_DDR_OHM_120 /* odt_n 2cs */ }, }, { /* mac electrical configuration */ MV_DDR_ODT_CFG_NORMAL, /* odtcfg_pattern */ MV_DDR_ODT_CFG_ALWAYS_ON, /* odtcfg_write */ MV_DDR_ODT_CFG_NORMAL, /* odtcfg_read */ }, } }; struct mv_ddr_topology_map *mv_ddr_topology_map_get(void) { /* Return the board topology as defined in the board code */ return &board_topology_map; } trusted-firmware-a-2.2/plat/marvell/a8k/a70x0_amc/board/marvell_plat_config.c000066400000000000000000000065241355360272700271260ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include /* * If bootrom is currently at BLE there's no need to include the memory * maps structure at this point */ #include #ifndef IMAGE_BLE /***************************************************************************** * AMB Configuration ***************************************************************************** */ struct addr_map_win *amb_memory_map; int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size, uintptr_t base) { *win = amb_memory_map; if (*win == NULL) *size = 0; else *size = ARRAY_SIZE(amb_memory_map); return 0; } #endif /***************************************************************************** * IO WIN Configuration ***************************************************************************** */ struct addr_map_win io_win_memory_map[] = { #ifndef IMAGE_BLE /* MCI 0 indirect window */ {MVEBU_MCI_REG_BASE_REMAP(0), 0x100000, MCI_0_TID}, /* MCI 1 indirect window */ {MVEBU_MCI_REG_BASE_REMAP(1), 0x100000, MCI_1_TID}, #endif }; uint32_t marvell_get_io_win_gcr_target(int ap_index) { return PIDI_TID; } int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win, uint32_t *size) { *win = io_win_memory_map; if (*win == NULL) *size = 0; else *size = ARRAY_SIZE(io_win_memory_map); return 0; } #ifndef IMAGE_BLE /***************************************************************************** * IOB Configuration ***************************************************************************** */ struct addr_map_win iob_memory_map[] = { /* PEX0_X4 window */ {0x00000000f6000000, 0x6000000, PEX0_TID}, {0x00000000c0000000, 0x30000000, PEX0_TID}, {0x0000000800000000, 0x200000000, PEX0_TID}, }; int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size, uintptr_t base) { *win = iob_memory_map; *size = ARRAY_SIZE(iob_memory_map); return 0; } #endif /***************************************************************************** * CCU Configuration ***************************************************************************** */ struct addr_map_win ccu_memory_map[] = { #ifdef IMAGE_BLE {0x00000000f2000000, 0x4000000, IO_0_TID}, /* IO window */ #else {0x00000000f2000000, 0xe000000, IO_0_TID}, {0x00000000c0000000, 0x30000000, IO_0_TID}, /* IO window */ {0x0000000800000000, 0x200000000, IO_0_TID}, /* IO window */ #endif }; uint32_t marvell_get_ccu_gcr_target(int ap) { return DRAM_0_TID; } int marvell_get_ccu_memory_map(int ap_index, struct addr_map_win **win, uint32_t *size) { *win = ccu_memory_map; *size = ARRAY_SIZE(ccu_memory_map); return 0; } #ifdef IMAGE_BLE struct pci_hw_cfg *plat_get_pcie_hw_data(void) { return NULL; } /***************************************************************************** * SKIP IMAGE Configuration ***************************************************************************** */ #if PLAT_RECOVERY_IMAGE_ENABLE struct skip_image skip_im = { .detection_method = GPIO, .info.gpio.num = 33, .info.gpio.button_state = HIGH, .info.test.cp_ap = CP, .info.test.cp_index = 0, }; void *plat_marvell_get_skip_image_data(void) { /* Return the skip_image configurations */ return &skip_im; } #endif #endif trusted-firmware-a-2.2/plat/marvell/a8k/a70x0_amc/mvebu_def.h000066400000000000000000000013621355360272700237640ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MVEBU_DEF_H #define MVEBU_DEF_H #include #define CP_COUNT 1 /* A70x0 has single CP0 */ /*********************************************************************** * Required platform porting definitions common to all * Management Compute SubSystems (MSS) *********************************************************************** */ /* * Load address of SCP_BL2 * SCP_BL2 is loaded to the same place as BL31. * Once SCP_BL2 is transferred to the SCP, * it is discarded and BL31 is loaded over the top. */ #ifdef SCP_IMAGE #define SCP_BL2_BASE BL31_BASE #endif #endif /* MVEBU_DEF_H */ trusted-firmware-a-2.2/plat/marvell/a8k/a70x0_amc/platform.mk000066400000000000000000000006271355360272700240370ustar00rootroot00000000000000# # Copyright (C) 2018 Marvell International Ltd. # # SPDX-License-Identifier: BSD-3-Clause # https://spdx.org/licenses # PCI_EP_SUPPORT := 0 CP_NUM := 1 $(eval $(call add_define,CP_NUM)) DOIMAGE_SEC := tools/doimage/secure/sec_img_7K.cfg MARVELL_MOCHI_DRV := drivers/marvell/mochi/apn806_setup.c include plat/marvell/a8k/common/a8k_common.mk include plat/marvell/common/marvell_common.mk trusted-firmware-a-2.2/plat/marvell/a8k/a80x0/000077500000000000000000000000001355360272700210365ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a8k/a80x0/board/000077500000000000000000000000001355360272700221255ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a8k/a80x0/board/dram_port.c000066400000000000000000000077521355360272700242730ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #define MVEBU_AP_MPP_CTRL0_7_REG MVEBU_AP_MPP_REGS(0) #define MVEBU_AP_MPP_CTRL4_OFFS 16 #define MVEBU_AP_MPP_CTRL5_OFFS 20 #define MVEBU_AP_MPP_CTRL4_I2C0_SDA_ENA 0x3 #define MVEBU_AP_MPP_CTRL5_I2C0_SCK_ENA 0x3 #define MVEBU_CP_MPP_CTRL37_OFFS 20 #define MVEBU_CP_MPP_CTRL38_OFFS 24 #define MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA 0x2 #define MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA 0x2 #define MVEBU_MPP_CTRL_MASK 0xf /* * This struct provides the DRAM training code with * the appropriate board DRAM configuration */ static struct mv_ddr_topology_map board_topology_map = { /* MISL board with 1CS 8Gb x4 devices of Micron 2400T */ DEBUG_LEVEL_ERROR, 0x1, /* active interfaces */ /* cs_mask, mirror, dqs_swap, ck_swap X subphys */ { { { {0x1, 0x0, 0, 0}, /* FIXME: change the cs mask for all 64 bit */ {0x1, 0x0, 0, 0}, {0x1, 0x0, 0, 0}, {0x1, 0x0, 0, 0}, {0x1, 0x0, 0, 0}, {0x1, 0x0, 0, 0}, {0x1, 0x0, 0, 0}, {0x1, 0x0, 0, 0}, {0x1, 0x0, 0, 0} }, /* TODO: double check if the speed bin is 2400T */ SPEED_BIN_DDR_2400T, /* speed_bin */ MV_DDR_DEV_WIDTH_8BIT, /* sdram device width */ MV_DDR_DIE_CAP_8GBIT, /* die capacity */ MV_DDR_FREQ_SAR, /* frequency */ 0, 0, /* cas_l, cas_wl */ MV_DDR_TEMP_LOW} }, /* temperature */ MV_DDR_64BIT_ECC_PUP8_BUS_MASK, /* subphys mask */ MV_DDR_CFG_SPD, /* ddr configuration data source */ { {0} }, /* raw spd data */ {0}, /* timing parameters */ { /* electrical configuration */ { /* memory electrical configuration */ MV_DDR_RTT_NOM_PARK_RZQ_DISABLE, /* rtt_nom */ { MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */ MV_DDR_RTT_NOM_PARK_RZQ_DIV1 /* rtt_park 2cs */ }, { MV_DDR_RTT_WR_DYN_ODT_OFF, /* rtt_wr 1cs */ MV_DDR_RTT_WR_RZQ_DIV2 /* rtt_wr 2cs */ }, MV_DDR_DIC_RZQ_DIV7 /* dic */ }, { /* phy electrical configuration */ MV_DDR_OHM_30, /* data_drv_p */ MV_DDR_OHM_30, /* data_drv_n */ MV_DDR_OHM_30, /* ctrl_drv_p */ MV_DDR_OHM_30, /* ctrl_drv_n */ { MV_DDR_OHM_60, /* odt_p 1cs */ MV_DDR_OHM_120 /* odt_p 2cs */ }, { MV_DDR_OHM_60, /* odt_n 1cs */ MV_DDR_OHM_120 /* odt_n 2cs */ }, }, { /* mac electrical configuration */ MV_DDR_ODT_CFG_NORMAL, /* odtcfg_pattern */ MV_DDR_ODT_CFG_ALWAYS_ON, /* odtcfg_write */ MV_DDR_ODT_CFG_NORMAL, /* odtcfg_read */ }, } }; struct mv_ddr_topology_map *mv_ddr_topology_map_get(void) { /* Return the board topology as defined in the board code */ return &board_topology_map; } static void mpp_config(void) { uintptr_t reg; uint32_t val; reg = MVEBU_CP_MPP_REGS(0, 4); /* configure CP0 MPP 37 and 38 to i2c */ val = mmio_read_32(reg); val &= ~((MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL37_OFFS) | (MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL38_OFFS)); val |= (MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA << MVEBU_CP_MPP_CTRL37_OFFS) | (MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA << MVEBU_CP_MPP_CTRL38_OFFS); mmio_write_32(reg, val); } /* * This function may modify the default DRAM parameters * based on information received from SPD or bootloader * configuration located on non volatile storage */ void plat_marvell_dram_update_topology(void) { struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); INFO("Gathering DRAM information\n"); if (tm->cfg_src == MV_DDR_CFG_SPD) { /* configure MPPs to enable i2c */ mpp_config(); /* initialize i2c */ i2c_init((void *)MVEBU_CP0_I2C_BASE); /* select SPD memory page 0 to access DRAM configuration */ i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 1); /* read data from spd */ i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes, sizeof(tm->spd_data.all_bytes)); } } trusted-firmware-a-2.2/plat/marvell/a8k/a80x0/board/marvell_plat_config.c000066400000000000000000000117161355360272700263060ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include /* * If bootrom is currently at BLE there's no need to include the memory * maps structure at this point */ #include #ifndef IMAGE_BLE /***************************************************************************** * AMB Configuration ***************************************************************************** */ struct addr_map_win amb_memory_map[] = { /* CP1 SPI1 CS0 Direct Mode access */ {0xf900, 0x1000000, AMB_SPI1_CS0_ID}, }; int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size, uintptr_t base) { *win = amb_memory_map; if (*win == NULL) *size = 0; else *size = ARRAY_SIZE(amb_memory_map); return 0; } #endif /***************************************************************************** * IO WIN Configuration ***************************************************************************** */ struct addr_map_win io_win_memory_map[] = { /* CP1 (MCI0) internal regs */ {0x00000000f4000000, 0x2000000, MCI_0_TID}, #ifndef IMAGE_BLE /* PCIe0 and SPI1_CS0 (RUNIT) on CP1*/ {0x00000000f9000000, 0x2000000, MCI_0_TID}, /* PCIe1 on CP1*/ {0x00000000fb000000, 0x1000000, MCI_0_TID}, /* PCIe2 on CP1*/ {0x00000000fc000000, 0x1000000, MCI_0_TID}, /* MCI 0 indirect window */ {MVEBU_MCI_REG_BASE_REMAP(0), 0x100000, MCI_0_TID}, /* MCI 1 indirect window */ {MVEBU_MCI_REG_BASE_REMAP(1), 0x100000, MCI_1_TID}, #endif }; uint32_t marvell_get_io_win_gcr_target(int ap_index) { return PIDI_TID; } int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win, uint32_t *size) { *win = io_win_memory_map; if (*win == NULL) *size = 0; else *size = ARRAY_SIZE(io_win_memory_map); return 0; } #ifndef IMAGE_BLE /***************************************************************************** * IOB Configuration ***************************************************************************** */ struct addr_map_win iob_memory_map_cp0[] = { /* CP0 */ /* PEX1_X1 window */ {0x00000000f7000000, 0x1000000, PEX1_TID}, /* PEX2_X1 window */ {0x00000000f8000000, 0x1000000, PEX2_TID}, /* PEX0_X4 window */ {0x00000000f6000000, 0x1000000, PEX0_TID}, {0x00000000c0000000, 0x30000000, PEX0_TID}, {0x0000000800000000, 0x100000000, PEX0_TID}, }; struct addr_map_win iob_memory_map_cp1[] = { /* CP1 */ /* SPI1_CS0 (RUNIT) window */ {0x00000000f9000000, 0x1000000, RUNIT_TID}, /* PEX1_X1 window */ {0x00000000fb000000, 0x1000000, PEX1_TID}, /* PEX2_X1 window */ {0x00000000fc000000, 0x1000000, PEX2_TID}, /* PEX0_X4 window */ {0x00000000fa000000, 0x1000000, PEX0_TID} }; int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size, uintptr_t base) { switch (base) { case MVEBU_CP_REGS_BASE(0): *win = iob_memory_map_cp0; *size = ARRAY_SIZE(iob_memory_map_cp0); return 0; case MVEBU_CP_REGS_BASE(1): *win = iob_memory_map_cp1; *size = ARRAY_SIZE(iob_memory_map_cp1); return 0; default: *size = 0; *win = 0; return 1; } } #endif /***************************************************************************** * CCU Configuration ***************************************************************************** */ struct addr_map_win ccu_memory_map[] = { #ifdef IMAGE_BLE {0x00000000f2000000, 0x4000000, IO_0_TID}, /* IO window */ #else {0x00000000f2000000, 0xe000000, IO_0_TID}, /* IO window */ {0x00000000c0000000, 0x30000000, IO_0_TID}, /* IO window */ {0x0000000800000000, 0x100000000, IO_0_TID}, /* IO window */ #endif }; uint32_t marvell_get_ccu_gcr_target(int ap) { return DRAM_0_TID; } int marvell_get_ccu_memory_map(int ap, struct addr_map_win **win, uint32_t *size) { *win = ccu_memory_map; *size = ARRAY_SIZE(ccu_memory_map); return 0; } #ifndef IMAGE_BLE /***************************************************************************** * SoC PM configuration ***************************************************************************** */ /* CP GPIO should be used and the GPIOs should be within same GPIO register */ struct power_off_method pm_cfg = { .type = PMIC_GPIO, .cfg.gpio.pin_count = 1, .cfg.gpio.info = {{0, 35} }, .cfg.gpio.step_count = 7, .cfg.gpio.seq = {1, 0, 1, 0, 1, 0, 1}, .cfg.gpio.delay_ms = 10, }; void *plat_marvell_get_pm_cfg(void) { /* Return the PM configurations */ return &pm_cfg; } /* In reference to #ifndef IMAGE_BLE, this part is used for BLE only. */ #else /***************************************************************************** * SKIP IMAGE Configuration ***************************************************************************** */ #if PLAT_RECOVERY_IMAGE_ENABLE struct skip_image skip_im = { .detection_method = GPIO, .info.gpio.num = 33, .info.gpio.button_state = HIGH, .info.test.cp_ap = CP, .info.test.cp_index = 0, }; void *plat_marvell_get_skip_image_data(void) { /* Return the skip_image configurations */ return &skip_im; } #endif #endif trusted-firmware-a-2.2/plat/marvell/a8k/a80x0/board/phy-porting-layer.h000066400000000000000000000130251355360272700256710ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef PHY_PORTING_LAYER_H #define PHY_PORTING_LAYER_H #define MAX_LANE_NR 6 static const struct xfi_params xfi_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = { /* AP0 */ { /* CP 0 */ { { 0 }, /* Comphy0 */ { 0 }, /* Comphy1 */ { .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf, .align90 = 0x5f, .g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe, .g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1, .g1_tx_emph_en = 0x1, .g1_tx_emph = 0x0, .g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0, .g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2, .valid = 0x1 }, /* Comphy2 */ { 0 }, /* Comphy3 */ { .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf, .align90 = 0x5f, .g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe, .g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1, .g1_tx_emph_en = 0x1, .g1_tx_emph = 0x0, .g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0, .g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2, .valid = 0x1 }, /* Comphy4 */ { 0 }, /* Comphy5 */ }, /* CP 1 */ { { 0 }, /* Comphy0 */ { 0 }, /* Comphy1 */ { .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf, .align90 = 0x5f, .g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe, .g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1, .g1_tx_emph_en = 0x1, .g1_tx_emph = 0x0, .g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0, .g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2, .valid = 0x1 }, /* Comphy2 */ { 0 }, /* Comphy3 */ { .g1_ffe_res_sel = 0x3, .g1_ffe_cap_sel = 0xf, .align90 = 0x5f, .g1_dfe_res = 0x2, .g1_amp = 0x1c, .g1_emph = 0xe, .g1_emph_en = 0x1, .g1_tx_amp_adj = 0x1, .g1_tx_emph_en = 0x1, .g1_tx_emph = 0x0, .g1_rx_selmuff = 0x1, .g1_rx_selmufi = 0x0, .g1_rx_selmupf = 0x2, .g1_rx_selmupi = 0x2, .valid = 0x1 }, /* Comphy4 */ { 0 }, /* Comphy5 */ }, }, }; static const struct sata_params sata_static_values_tab[AP_NUM][CP_NUM][MAX_LANE_NR] = { /* AP0 */ { /* CP 0 */ { { 0 }, /* Comphy0 */ { .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e, .g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe, .g1_emph_en = 0x1, .g2_emph_en = 0x1, .g3_emph_en = 0x1, .g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1, .g3_tx_amp_adj = 0x1, .g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0, .g3_tx_emph_en = 0x0, .g1_tx_emph = 0x1, .g2_tx_emph = 0x1, .g3_tx_emph = 0x1, .g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4, .g3_ffe_cap_sel = 0xf, .align90 = 0x61, .g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3, .g3_rx_selmuff = 0x3, .g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0, .g3_rx_selmufi = 0x3, .g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1, .g3_rx_selmupf = 0x2, .g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0, .g3_rx_selmupi = 0x2, .valid = 0x1 }, /* Comphy1 */ { 0 }, /* Comphy2 */ { .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e, .g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe, .g1_emph_en = 0x1, .g2_emph_en = 0x1, .g3_emph_en = 0x1, .g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1, .g3_tx_amp_adj = 0x1, .g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0, .g3_tx_emph_en = 0x0, .g1_tx_emph = 0x1, .g2_tx_emph = 0x1, .g3_tx_emph = 0x1, .g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4, .g3_ffe_cap_sel = 0xf, .align90 = 0x61, .g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3, .g3_rx_selmuff = 0x3, .g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0, .g3_rx_selmufi = 0x3, .g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1, .g3_rx_selmupf = 0x2, .g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0, .g3_rx_selmupi = 0x2, .valid = 0x1 }, /* Comphy3 */ { 0 }, /* Comphy4 */ { 0 }, /* Comphy5 */ }, /* CP 1 */ { { 0 }, /* Comphy0 */ { .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e, .g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe, .g1_emph_en = 0x1, .g2_emph_en = 0x1, .g3_emph_en = 0x1, .g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1, .g3_tx_amp_adj = 0x1, .g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0, .g3_tx_emph_en = 0x0, .g1_tx_emph = 0x1, .g2_tx_emph = 0x1, .g3_tx_emph = 0x1, .g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4, .g3_ffe_cap_sel = 0xf, .align90 = 0x61, .g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3, .g3_rx_selmuff = 0x3, .g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0, .g3_rx_selmufi = 0x3, .g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1, .g3_rx_selmupf = 0x2, .g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0, .g3_rx_selmupi = 0x2, .valid = 0x1 }, /* Comphy1 */ { 0 }, /* Comphy2 */ { .g1_amp = 0x8, .g2_amp = 0xa, .g3_amp = 0x1e, .g1_emph = 0x1, .g2_emph = 0x2, .g3_emph = 0xe, .g1_emph_en = 0x1, .g2_emph_en = 0x1, .g3_emph_en = 0x1, .g1_tx_amp_adj = 0x1, .g2_tx_amp_adj = 0x1, .g3_tx_amp_adj = 0x1, .g1_tx_emph_en = 0x0, .g2_tx_emph_en = 0x0, .g3_tx_emph_en = 0x0, .g1_tx_emph = 0x1, .g2_tx_emph = 0x1, .g3_tx_emph = 0x1, .g3_dfe_res = 0x1, .g3_ffe_res_sel = 0x4, .g3_ffe_cap_sel = 0xf, .align90 = 0x61, .g1_rx_selmuff = 0x3, .g2_rx_selmuff = 0x3, .g3_rx_selmuff = 0x3, .g1_rx_selmufi = 0x0, .g2_rx_selmufi = 0x0, .g3_rx_selmufi = 0x3, .g1_rx_selmupf = 0x1, .g2_rx_selmupf = 0x1, .g3_rx_selmupf = 0x2, .g1_rx_selmupi = 0x0, .g2_rx_selmupi = 0x0, .g3_rx_selmupi = 0x2, .valid = 0x1 }, /* Comphy3 */ { 0 }, /* Comphy4 */ { 0 }, /* Comphy5 */ }, }, }; #endif /* PHY_PORTING_LAYER_H */ trusted-firmware-a-2.2/plat/marvell/a8k/a80x0/mvebu_def.h000066400000000000000000000006031355360272700231420ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MVEBU_DEF_H #define MVEBU_DEF_H #include #define CP_COUNT 2 /* A80x0 has both CP0 & CP1 */ #define I2C_SPD_ADDR 0x53 /* Access SPD data */ #define I2C_SPD_P0_ADDR 0x36 /* Select SPD data page 0 */ #endif /* MVEBU_DEF_H */ trusted-firmware-a-2.2/plat/marvell/a8k/a80x0/platform.mk000066400000000000000000000007101355360272700232110ustar00rootroot00000000000000# # Copyright (C) 2018 Marvell International Ltd. # # SPDX-License-Identifier: BSD-3-Clause # https://spdx.org/licenses # PCI_EP_SUPPORT := 0 CP_NUM := 2 $(eval $(call add_define,CP_NUM)) DOIMAGE_SEC := tools/doimage/secure/sec_img_8K.cfg MARVELL_MOCHI_DRV := drivers/marvell/mochi/apn806_setup.c include plat/marvell/a8k/common/a8k_common.mk include plat/marvell/common/marvell_common.mk PLAT_INCLUDES += -Iplat/marvell/a8k/a80x0/board trusted-firmware-a-2.2/plat/marvell/a8k/a80x0_mcbin/000077500000000000000000000000001355360272700222065ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a8k/a80x0_mcbin/board/000077500000000000000000000000001355360272700232755ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a8k/a80x0_mcbin/board/dram_port.c000066400000000000000000000073721355360272700254410ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #define MVEBU_CP_MPP_CTRL37_OFFS 20 #define MVEBU_CP_MPP_CTRL38_OFFS 24 #define MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA 0x2 #define MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA 0x2 #define MVEBU_MPP_CTRL_MASK 0xf /* * This struct provides the DRAM training code with * the appropriate board DRAM configuration */ static struct mv_ddr_topology_map board_topology_map = { /* Board with 1CS 8Gb x4 devices of Micron 2400T */ DEBUG_LEVEL_ERROR, 0x1, /* active interfaces */ /* cs_mask, mirror, dqs_swap, ck_swap X subphys */ { { { {0x1, 0x0, 0, 0}, /* FIXME: change the cs mask for all 64 bit */ {0x1, 0x0, 0, 0}, {0x1, 0x0, 0, 0}, {0x1, 0x0, 0, 0}, {0x1, 0x0, 0, 0}, {0x1, 0x0, 0, 0}, {0x1, 0x0, 0, 0}, {0x1, 0x0, 0, 0}, {0x1, 0x0, 0, 0} }, /* TODO: double check if the speed bin is 2400T */ SPEED_BIN_DDR_2400T, /* speed_bin */ MV_DDR_DEV_WIDTH_8BIT, /* sdram device width */ MV_DDR_DIE_CAP_8GBIT, /* die capacity */ MV_DDR_FREQ_SAR, /* frequency */ 0, 0, /* cas_l, cas_wl */ MV_DDR_TEMP_LOW} }, /* temperature */ MV_DDR_64BIT_BUS_MASK, /* subphys mask */ MV_DDR_CFG_SPD, /* ddr configuration data source */ { {0} }, /* raw spd data */ {0}, /* timing parameters */ { /* electrical configuration */ { /* memory electrical configuration */ MV_DDR_RTT_NOM_PARK_RZQ_DISABLE, /* rtt_nom */ { MV_DDR_RTT_NOM_PARK_RZQ_DIV4, /* rtt_park 1cs */ MV_DDR_RTT_NOM_PARK_RZQ_DIV1 /* rtt_park 2cs */ }, { MV_DDR_RTT_WR_DYN_ODT_OFF, /* rtt_wr 1cs */ MV_DDR_RTT_WR_RZQ_DIV2 /* rtt_wr 2cs */ }, MV_DDR_DIC_RZQ_DIV7 /* dic */ }, { /* phy electrical configuration */ MV_DDR_OHM_30, /* data_drv_p */ MV_DDR_OHM_30, /* data_drv_n */ MV_DDR_OHM_30, /* ctrl_drv_p */ MV_DDR_OHM_30, /* ctrl_drv_n */ { MV_DDR_OHM_60, /* odt_p 1cs */ MV_DDR_OHM_120 /* odt_p 2cs */ }, { MV_DDR_OHM_60, /* odt_n 1cs */ MV_DDR_OHM_120 /* odt_n 2cs */ }, }, { /* mac electrical configuration */ MV_DDR_ODT_CFG_NORMAL, /* odtcfg_pattern */ MV_DDR_ODT_CFG_ALWAYS_ON, /* odtcfg_write */ MV_DDR_ODT_CFG_NORMAL, /* odtcfg_read */ }, } }; struct mv_ddr_topology_map *mv_ddr_topology_map_get(void) { /* Return the board topology as defined in the board code */ return &board_topology_map; } static void mpp_config(void) { uint32_t val; uintptr_t reg = MVEBU_CP_MPP_REGS(0, 4); /* configure CP0 MPP 37 and 38 to i2c */ val = mmio_read_32(reg); val &= ~((MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL37_OFFS) | (MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL38_OFFS)); val |= (MVEBU_CP_MPP_CTRL37_I2C0_SCK_ENA << MVEBU_CP_MPP_CTRL37_OFFS) | (MVEBU_CP_MPP_CTRL38_I2C0_SDA_ENA << MVEBU_CP_MPP_CTRL38_OFFS); mmio_write_32(reg, val); } /* * This function may modify the default DRAM parameters * based on information received from SPD or bootloader * configuration located on non volatile storage */ void plat_marvell_dram_update_topology(void) { struct mv_ddr_topology_map *tm = mv_ddr_topology_map_get(); INFO("Gathering DRAM information\n"); if (tm->cfg_src == MV_DDR_CFG_SPD) { /* configure MPPs to enable i2c */ mpp_config(); /* initialize the i2c */ i2c_init((void *)MVEBU_CP0_I2C_BASE); /* select SPD memory page 0 to access DRAM configuration */ i2c_write(I2C_SPD_P0_ADDR, 0x0, 1, tm->spd_data.all_bytes, 1); /* read data from spd */ i2c_read(I2C_SPD_ADDR, 0x0, 1, tm->spd_data.all_bytes, sizeof(tm->spd_data.all_bytes)); } } trusted-firmware-a-2.2/plat/marvell/a8k/a80x0_mcbin/board/marvell_plat_config.c000066400000000000000000000121271355360272700274530ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include /* * If bootrom is currently at BLE there's no need to include the memory * maps structure at this point */ #include #ifndef IMAGE_BLE /***************************************************************************** * GPIO Configuration ***************************************************************************** */ #define MPP_CONTROL_REGISTER 0xf2440018 #define MPP_CONTROL_MPP_SEL_52_MASK 0xf0000 #define GPIO_DATA_OUT1_REGISTER 0xf2440140 #define GPIO_DATA_OUT_EN_CTRL1_REGISTER 0xf2440144 #define GPIO52_MASK 0x100000 /* Reset PCIe via GPIO number 52 */ int marvell_gpio_config(void) { uint32_t reg; reg = mmio_read_32(MPP_CONTROL_REGISTER); reg |= MPP_CONTROL_MPP_SEL_52_MASK; mmio_write_32(MPP_CONTROL_REGISTER, reg); reg = mmio_read_32(GPIO_DATA_OUT1_REGISTER); reg |= GPIO52_MASK; mmio_write_32(GPIO_DATA_OUT1_REGISTER, reg); reg = mmio_read_32(GPIO_DATA_OUT_EN_CTRL1_REGISTER); reg &= ~GPIO52_MASK; mmio_write_32(GPIO_DATA_OUT_EN_CTRL1_REGISTER, reg); udelay(100); return 0; } /***************************************************************************** * AMB Configuration ***************************************************************************** */ struct addr_map_win amb_memory_map[] = { /* CP1 SPI1 CS0 Direct Mode access */ {0xf900, 0x1000000, AMB_SPI1_CS0_ID}, }; int marvell_get_amb_memory_map(struct addr_map_win **win, uint32_t *size, uintptr_t base) { *win = amb_memory_map; if (*win == NULL) *size = 0; else *size = ARRAY_SIZE(amb_memory_map); return 0; } #endif /***************************************************************************** * IO WIN Configuration ***************************************************************************** */ struct addr_map_win io_win_memory_map[] = { /* CP1 (MCI0) internal regs */ {0x00000000f4000000, 0x2000000, MCI_0_TID}, #ifndef IMAGE_BLE /* PCIe0 and SPI1_CS0 (RUNIT) on CP1*/ {0x00000000f9000000, 0x2000000, MCI_0_TID}, /* PCIe1 on CP1*/ {0x00000000fb000000, 0x1000000, MCI_0_TID}, /* PCIe2 on CP1*/ {0x00000000fc000000, 0x1000000, MCI_0_TID}, /* MCI 0 indirect window */ {MVEBU_MCI_REG_BASE_REMAP(0), 0x100000, MCI_0_TID}, /* MCI 1 indirect window */ {MVEBU_MCI_REG_BASE_REMAP(1), 0x100000, MCI_1_TID}, #endif }; uint32_t marvell_get_io_win_gcr_target(int ap_index) { return PIDI_TID; } int marvell_get_io_win_memory_map(int ap_index, struct addr_map_win **win, uint32_t *size) { *win = io_win_memory_map; if (*win == NULL) *size = 0; else *size = ARRAY_SIZE(io_win_memory_map); return 0; } #ifndef IMAGE_BLE /***************************************************************************** * IOB Configuration ***************************************************************************** */ struct addr_map_win iob_memory_map_cp0[] = { /* CP0 */ /* PEX1_X1 window */ {0x00000000f7000000, 0x1000000, PEX1_TID}, /* PEX2_X1 window */ {0x00000000f8000000, 0x1000000, PEX2_TID}, /* PEX0_X4 window */ {0x00000000f6000000, 0x1000000, PEX0_TID}, {0x00000000c0000000, 0x30000000, PEX0_TID}, {0x0000000800000000, 0x100000000, PEX0_TID}, }; struct addr_map_win iob_memory_map_cp1[] = { /* CP1 */ /* SPI1_CS0 (RUNIT) window */ {0x00000000f9000000, 0x1000000, RUNIT_TID}, /* PEX1_X1 window */ {0x00000000fb000000, 0x1000000, PEX1_TID}, /* PEX2_X1 window */ {0x00000000fc000000, 0x1000000, PEX2_TID}, /* PEX0_X4 window */ {0x00000000fa000000, 0x1000000, PEX0_TID} }; int marvell_get_iob_memory_map(struct addr_map_win **win, uint32_t *size, uintptr_t base) { switch (base) { case MVEBU_CP_REGS_BASE(0): *win = iob_memory_map_cp0; *size = ARRAY_SIZE(iob_memory_map_cp0); return 0; case MVEBU_CP_REGS_BASE(1): *win = iob_memory_map_cp1; *size = ARRAY_SIZE(iob_memory_map_cp1); return 0; default: *size = 0; *win = 0; return 1; } } #endif /***************************************************************************** * CCU Configuration ***************************************************************************** */ struct addr_map_win ccu_memory_map[] = { #ifdef IMAGE_BLE {0x00000000f2000000, 0x4000000, IO_0_TID}, /* IO window */ #else {0x00000000f2000000, 0xe000000, IO_0_TID}, /* IO window */ {0x00000000c0000000, 0x30000000, IO_0_TID}, /* IO window */ {0x0000000800000000, 0x100000000, IO_0_TID}, /* IO window */ #endif }; uint32_t marvell_get_ccu_gcr_target(int ap) { return DRAM_0_TID; } int marvell_get_ccu_memory_map(int ap_index, struct addr_map_win **win, uint32_t *size) { *win = ccu_memory_map; *size = ARRAY_SIZE(ccu_memory_map); return 0; } /* In reference to #ifndef IMAGE_BLE, this part is used for BLE only. */ /***************************************************************************** * SKIP IMAGE Configuration ***************************************************************************** */ void *plat_marvell_get_skip_image_data(void) { /* No recovery button on A8k-MCBIN board */ return NULL; } trusted-firmware-a-2.2/plat/marvell/a8k/a80x0_mcbin/mvebu_def.h000066400000000000000000000006031355360272700243120ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MVEBU_DEF_H #define MVEBU_DEF_H #include #define CP_COUNT 2 /* A80x0 has both CP0 & CP1 */ #define I2C_SPD_ADDR 0x53 /* Access SPD data */ #define I2C_SPD_P0_ADDR 0x36 /* Select SPD data page 0 */ #endif /* MVEBU_DEF_H */ trusted-firmware-a-2.2/plat/marvell/a8k/a80x0_mcbin/platform.mk000066400000000000000000000006271355360272700243700ustar00rootroot00000000000000# # Copyright (C) 2018 Marvell International Ltd. # # SPDX-License-Identifier: BSD-3-Clause # https://spdx.org/licenses # PCI_EP_SUPPORT := 0 CP_NUM := 2 $(eval $(call add_define,CP_NUM)) DOIMAGE_SEC := tools/doimage/secure/sec_img_8K.cfg MARVELL_MOCHI_DRV := drivers/marvell/mochi/apn806_setup.c include plat/marvell/a8k/common/a8k_common.mk include plat/marvell/common/marvell_common.mk trusted-firmware-a-2.2/plat/marvell/a8k/common/000077500000000000000000000000001355360272700214665ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a8k/common/a8k_common.mk000066400000000000000000000074301355360272700240560ustar00rootroot00000000000000# # Copyright (C) 2016 - 2018 Marvell International Ltd. # # SPDX-License-Identifier: BSD-3-Clause # https://spdx.org/licenses include tools/marvell/doimage/doimage.mk PLAT_FAMILY := a8k PLAT_FAMILY_BASE := plat/marvell/$(PLAT_FAMILY) PLAT_INCLUDE_BASE := include/plat/marvell/$(PLAT_FAMILY) PLAT_COMMON_BASE := $(PLAT_FAMILY_BASE)/common MARVELL_DRV_BASE := drivers/marvell MARVELL_COMMON_BASE := plat/marvell/common MARVELL_SVC_TEST := 0 $(eval $(call add_define,MARVELL_SVC_TEST)) ERRATA_A72_859971 := 1 # Enable MSS support for a8k family MSS_SUPPORT := 1 # Disable EL3 cache for power management BL31_CACHE_DISABLE := 1 $(eval $(call add_define,BL31_CACHE_DISABLE)) $(eval $(call add_define,PCI_EP_SUPPORT)) $(eval $(call assert_boolean,PCI_EP_SUPPORT)) AP_NUM := 1 $(eval $(call add_define,AP_NUM)) DOIMAGEPATH ?= tools/marvell/doimage DOIMAGETOOL ?= ${DOIMAGEPATH}/doimage ROM_BIN_EXT ?= $(BUILD_PLAT)/ble.bin DOIMAGE_FLAGS += -b $(ROM_BIN_EXT) $(NAND_DOIMAGE_FLAGS) $(DOIMAGE_SEC_FLAGS) # This define specifies DDR type for BLE $(eval $(call add_define,CONFIG_DDR4)) MARVELL_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c PLAT_INCLUDES := -I$(PLAT_FAMILY_BASE)/$(PLAT) \ -I$(PLAT_COMMON_BASE)/include \ -I$(PLAT_INCLUDE_BASE)/common PLAT_BL_COMMON_SOURCES := $(PLAT_COMMON_BASE)/aarch64/a8k_common.c \ drivers/ti/uart/aarch64/16550_console.S BLE_PORTING_SOURCES := $(PLAT_FAMILY_BASE)/$(PLAT)/board/dram_port.c \ $(PLAT_FAMILY_BASE)/$(PLAT)/board/marvell_plat_config.c MARVELL_MOCHI_DRV += $(MARVELL_DRV_BASE)/mochi/cp110_setup.c BLE_SOURCES := drivers/mentor/i2c/mi2cv.c \ $(PLAT_COMMON_BASE)/plat_ble_setup.c \ $(MARVELL_MOCHI_DRV) \ $(PLAT_COMMON_BASE)/plat_pm.c \ $(MARVELL_DRV_BASE)/ap807_clocks_init.c \ $(MARVELL_DRV_BASE)/thermal.c \ $(PLAT_COMMON_BASE)/plat_thermal.c \ $(BLE_PORTING_SOURCES) \ $(MARVELL_DRV_BASE)/ccu.c \ $(MARVELL_DRV_BASE)/io_win.c BL1_SOURCES += $(PLAT_COMMON_BASE)/aarch64/plat_helpers.S \ lib/cpus/aarch64/cortex_a72.S MARVELL_DRV := $(MARVELL_DRV_BASE)/io_win.c \ $(MARVELL_DRV_BASE)/iob.c \ $(MARVELL_DRV_BASE)/mci.c \ $(MARVELL_DRV_BASE)/amb_adec.c \ $(MARVELL_DRV_BASE)/ccu.c \ $(MARVELL_DRV_BASE)/cache_llc.c \ $(MARVELL_DRV_BASE)/comphy/phy-comphy-cp110.c \ $(MARVELL_DRV_BASE)/mc_trustzone/mc_trustzone.c BL31_PORTING_SOURCES := $(PLAT_FAMILY_BASE)/$(PLAT)/board/marvell_plat_config.c BL31_SOURCES += lib/cpus/aarch64/cortex_a72.S \ $(PLAT_COMMON_BASE)/aarch64/plat_helpers.S \ $(PLAT_COMMON_BASE)/aarch64/plat_arch_config.c \ $(PLAT_COMMON_BASE)/plat_pm.c \ $(PLAT_COMMON_BASE)/plat_bl31_setup.c \ $(MARVELL_COMMON_BASE)/marvell_gicv2.c \ $(MARVELL_COMMON_BASE)/mrvl_sip_svc.c \ $(MARVELL_COMMON_BASE)/marvell_ddr_info.c \ $(BL31_PORTING_SOURCES) \ $(MARVELL_DRV) \ $(MARVELL_MOCHI_DRV) \ $(MARVELL_GIC_SOURCES) # Add trace functionality for PM BL31_SOURCES += $(PLAT_COMMON_BASE)/plat_pm_trace.c # Force builds with BL2 image on a80x0 platforms ifndef SCP_BL2 $(error "Error: SCP_BL2 image is mandatory for a8k family") endif # MSS (SCP) build include $(PLAT_COMMON_BASE)/mss/mss_a8k.mk # BLE (ROM context execution code, AKA binary extension) BLE_PATH ?= $(PLAT_COMMON_BASE)/ble include ${BLE_PATH}/ble.mk $(eval $(call MAKE_BL,e)) mrvl_flash: ${BUILD_PLAT}/${FIP_NAME} ${DOIMAGETOOL} ${BUILD_PLAT}/ble.bin $(shell truncate -s %128K ${BUILD_PLAT}/bl1.bin) $(shell cat ${BUILD_PLAT}/bl1.bin ${BUILD_PLAT}/${FIP_NAME} > ${BUILD_PLAT}/${BOOT_IMAGE}) ${DOIMAGETOOL} ${DOIMAGE_FLAGS} ${BUILD_PLAT}/${BOOT_IMAGE} ${BUILD_PLAT}/${FLASH_IMAGE} trusted-firmware-a-2.2/plat/marvell/a8k/common/aarch64/000077500000000000000000000000001355360272700227165ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a8k/common/aarch64/a8k_common.c000066400000000000000000000020501355360272700251120ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include /* MMU entry for internal (register) space access */ #define MAP_DEVICE0 MAP_REGION_FLAT(DEVICE0_BASE, \ DEVICE0_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) /* * Table of regions for various BL stages to map using the MMU. */ #if IMAGE_BL1 const mmap_region_t plat_marvell_mmap[] = { MARVELL_MAP_SHARED_RAM, MAP_DEVICE0, {0} }; #endif #if IMAGE_BL2 const mmap_region_t plat_marvell_mmap[] = { MARVELL_MAP_SHARED_RAM, MAP_DEVICE0, MARVELL_MAP_DRAM, {0} }; #endif #if IMAGE_BL2U const mmap_region_t plat_marvell_mmap[] = { MAP_DEVICE0, {0} }; #endif #if IMAGE_BLE const mmap_region_t plat_marvell_mmap[] = { MAP_DEVICE0, {0} }; #endif #if IMAGE_BL31 const mmap_region_t plat_marvell_mmap[] = { MARVELL_MAP_SHARED_RAM, MAP_DEVICE0, MARVELL_MAP_DRAM, {0} }; #endif #if IMAGE_BL32 const mmap_region_t plat_marvell_mmap[] = { MAP_DEVICE0, {0} }; #endif MARVELL_CASSERT_MMAP; trusted-firmware-a-2.2/plat/marvell/a8k/common/aarch64/plat_arch_config.c000066400000000000000000000017371355360272700263540ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #define CCU_HTC_ASET (MVEBU_CCU_BASE(MVEBU_AP0) + 0x264) #define MVEBU_IO_AFFINITY (0xF00) static void plat_enable_affinity(void) { int cluster_id; int affinity; /* set CPU Affinity */ cluster_id = plat_my_core_pos() / PLAT_MARVELL_CLUSTER_CORE_COUNT; affinity = (MVEBU_IO_AFFINITY | (1 << cluster_id)); mmio_write_32(CCU_HTC_ASET, affinity); /* set barier */ isb(); } void marvell_psci_arch_init(int die_index) { #if LLC_ENABLE /* check if LLC is in exclusive mode * as L2 is configured to UniqueClean eviction * (in a8k reset handler) */ if (llc_is_exclusive(0) == 0) ERROR("LLC should be configured to exclusice mode\n"); #endif /* Enable Affinity */ plat_enable_affinity(); } trusted-firmware-a-2.2/plat/marvell/a8k/common/aarch64/plat_helpers.S000066400000000000000000000062521355360272700255310ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include .globl plat_secondary_cold_boot_setup .globl plat_get_my_entrypoint .globl plat_is_my_cpu_primary .globl plat_reset_handler /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions * needed for a secondary cpu after a cold reset. Right * now this is a stub function. * ----------------------------------------------------- */ func plat_secondary_cold_boot_setup mov x0, #0 ret endfunc plat_secondary_cold_boot_setup /* --------------------------------------------------------------------- * unsigned long plat_get_my_entrypoint (void); * * Main job of this routine is to distinguish * between a cold and warm boot * For a cold boot, return 0. * For a warm boot, read the mailbox and return the address it contains. * * --------------------------------------------------------------------- */ func plat_get_my_entrypoint /* Read first word and compare it with magic num */ mov_imm x0, PLAT_MARVELL_MAILBOX_BASE ldr x1, [x0] mov_imm x2, MVEBU_MAILBOX_MAGIC_NUM cmp x1, x2 beq warm_boot /* If compare failed, return 0, i.e. cold boot */ mov x0, #0 ret warm_boot: mov_imm x1, MBOX_IDX_SEC_ADDR /* Get the jump address */ subs x1, x1, #1 mov x2, #(MBOX_IDX_SEC_ADDR * 8) lsl x3, x2, x1 add x0, x0, x3 ldr x0, [x0] ret endfunc plat_get_my_entrypoint /* ----------------------------------------------------- * unsigned int plat_is_my_cpu_primary (void); * * Find out whether the current cpu is the primary * cpu. * ----------------------------------------------------- */ func plat_is_my_cpu_primary mrs x0, mpidr_el1 and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) cmp x0, #MVEBU_PRIMARY_CPU cset w0, eq ret endfunc plat_is_my_cpu_primary /* ----------------------------------------------------- * void plat_reset_handler (void); * * Platform specific configuration right after cpu is * is our of reset. * * The plat_reset_handler can clobber x0 - x18, x30. * ----------------------------------------------------- */ func plat_reset_handler /* * Note: the configurations below should be done before MMU, * I Cache and L2are enabled. * The reset handler is executed right after reset * and before Caches are enabled. */ /* Enable L1/L2 ECC and Parity */ mrs x5, s3_1_c11_c0_2 /* L2 Ctrl */ orr x5, x5, #(1 << 21) /* Enable L1/L2 cache ECC & Parity */ msr s3_1_c11_c0_2, x5 /* L2 Ctrl */ #if LLC_ENABLE /* * Enable L2 UniqueClean evictions * Note: this configuration assumes that LLC is configured * in exclusive mode. * Later on in the code this assumption will be validated */ mrs x5, s3_1_c15_c0_0 /* L2 Ctrl */ orr x5, x5, #(1 << 14) /* Enable UniqueClean evictions with data */ msr s3_1_c15_c0_0, x5 /* L2 Ctrl */ #endif /* Instruction Barrier to allow msr command completion */ isb ret endfunc plat_reset_handler trusted-firmware-a-2.2/plat/marvell/a8k/common/ble/000077500000000000000000000000001355360272700222305ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a8k/common/ble/ble.ld.S000066400000000000000000000031521355360272700235150ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT) OUTPUT_ARCH(PLATFORM_LINKER_ARCH) ENTRY(ble_main) MEMORY { RAM (rwx): ORIGIN = BLE_BASE, LENGTH = BLE_LIMIT - BLE_BASE } SECTIONS { . = BLE_BASE; ro . : { __RO_START__ = .; *ble_main.o(.entry*) *(.text*) *(.rodata*) __RO_END_UNALIGNED__ = .; __RO_END__ = .; } >RAM /* * Define a linker symbol to mark start of the RW memory area for this * image. */ __RW_START__ = . ; .data . : { __DATA_START__ = .; *(.data*) __DATA_END__ = .; } >RAM stacks . (NOLOAD) : { __STACKS_START__ = .; *(tzfw_normal_stacks) __STACKS_END__ = .; } >RAM .bss : { __BSS_START__ = .; *(.bss*) __BSS_END__ = .; } >RAM /* * Extend the BLE binary to the maximum size allocated for it in platform * definition files and prevent overlapping between BLE BSS section and * additional extensions that can follow the BLE in flash image preamble. * This situation happens for instance when secure extension is added to * the image preamble. */ .fill LOADADDR(.bss) + SIZEOF(.bss) : { FILL(0xDEADC0DE); . = ORIGIN(RAM) + LENGTH(RAM) - 1; BYTE(0x00) } >RAM /* * Define a linker symbol to mark end of the RW memory area for this * image. */ __RW_END__ = .; __BLE_END__ = .; __BSS_SIZE__ = SIZEOF(.bss); } trusted-firmware-a-2.2/plat/marvell/a8k/common/ble/ble.mk000066400000000000000000000020211355360272700233160ustar00rootroot00000000000000# Copyright (C) 2018 Marvell International Ltd. # # SPDX-License-Identifier: BSD-3-Clause # https://spdx.org/licenses MV_DDR_PATH ?= drivers/marvell/mv_ddr MV_DDR_LIB = $(CURDIR)/$(BUILD_PLAT)/ble/mv_ddr_lib.a LIBC_LIB = $(CURDIR)/$(BUILD_PLAT)/lib/libc.a BLE_LIBS = $(MV_DDR_LIB) $(LIBC_LIB) PLAT_MARVELL = plat/marvell BLE_SOURCES += $(BLE_PATH)/ble_main.c \ $(BLE_PATH)/ble_mem.S \ drivers/delay_timer/delay_timer.c \ $(PLAT_MARVELL)/common/aarch64/marvell_helpers.S \ $(PLAT_MARVELL)/common/plat_delay_timer.c \ $(PLAT_MARVELL)/common/marvell_console.c PLAT_INCLUDES += -I$(MV_DDR_PATH) \ -I$(CURDIR)/include \ -I$(CURDIR)/include/arch/aarch64 \ -I$(CURDIR)/include/lib/libc \ -I$(CURDIR)/include/lib/libc/aarch64 \ -I$(CURDIR)/drivers/marvell BLE_LINKERFILE := $(BLE_PATH)/ble.ld.S FORCE: $(MV_DDR_LIB): FORCE @+make -C $(MV_DDR_PATH) --no-print-directory PLAT_INCLUDES="$(PLAT_INCLUDES)" PLATFORM=$(PLAT) ARCH=AARCH64 OBJ_DIR=$(CURDIR)/$(BUILD_PLAT)/ble trusted-firmware-a-2.2/plat/marvell/a8k/common/ble/ble_main.c000066400000000000000000000052111355360272700241410ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #include #define BR_FLAG_SILENT 0x1 #define SKIP_IMAGE_CODE 0xDEADB002 void mailbox_clean(void) { uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE; memset(mailbox, 0, PLAT_MARVELL_MAILBOX_SIZE); } int exec_ble_main(int bootrom_flags) { int skip = 0; uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE; /* * In some situations, like boot from UART, bootrom will * request to avoid printing to console. in that case don't * initialize the console and prints will be ignored */ if ((bootrom_flags & BR_FLAG_SILENT) == 0) marvell_console_boot_init(); NOTICE("Starting binary extension\n"); /* initialize time (for delay functionality) */ plat_delay_timer_init(); ble_plat_setup(&skip); /* if there's skip image request, bootrom will load from the image * saved on the next address of the flash */ if (skip) return SKIP_IMAGE_CODE; /* * Check if the mailbox magic number is stored at index MBOX_IDX_MAGIC * and the suspend to RAM magic number at index MBOX_IDX_SUSPEND_MAGIC. * If the above is true, this is the recovery from suspend to RAM state. * In such case the mailbox should remain intact, since it stores the * warm boot jump address to be used by the TF-A in BL31. * Othervise the mailbox should be cleaned from a garbage data. */ if (mailbox[MBOX_IDX_MAGIC] != MVEBU_MAILBOX_MAGIC_NUM || mailbox[MBOX_IDX_SUSPEND_MAGIC] != MVEBU_MAILBOX_SUSPEND_STATE) { NOTICE("Cold boot\n"); mailbox_clean(); } else { void (*bootrom_exit)(void) = (void (*)(void))mailbox[MBOX_IDX_ROM_EXIT_ADDR]; INFO("Recovery...\n"); /* * If this is recovery from suspend, two things has to be done: * 1. Define the DRAM region as executable memory for preparing * jump to TF-A * 2. Instead of returning control to the BootROM, invalidate * and flush caches, and continue execution at address stored * in the mailbox. * This should be done until the BootROM have a native support * for the system restore flow. */ marvell_ble_prepare_exit(); bootrom_exit(); } return 0; } /* NOTE: don't notify this function, all code must be added to exec_ble_main * in order to keep the end of ble_main as a fixed address. */ int __attribute__ ((section(".entry"))) ble_main(int bootrom_flags) { volatile int ret; ret = exec_ble_main(bootrom_flags); return ret; } trusted-firmware-a-2.2/plat/marvell/a8k/common/ble/ble_mem.S000066400000000000000000000012271355360272700237560ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #define PTE_NON_EXEC_OFF 54 /* XN - eXecute Never bit offset - see VMSAv8-64 */ .globl marvell_ble_prepare_exit func marvell_ble_prepare_exit /* * Read the page table base and set the first page to be executable. * This is required for jumping to DRAM for further execution. */ mrs x0, ttbr0_el3 ldr x1, [x0] mov x2, #1 bic x1, x1, x2, lsl #PTE_NON_EXEC_OFF str x1, [x0] tlbi alle3 dsb sy isb ret endfunc marvell_ble_prepare_exit trusted-firmware-a-2.2/plat/marvell/a8k/common/include/000077500000000000000000000000001355360272700231115ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a8k/common/include/a8k_plat_def.h000066400000000000000000000145441355360272700256130ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef A8K_PLAT_DEF_H #define A8K_PLAT_DEF_H #include #define MVEBU_PRIMARY_CPU 0x0 #define MVEBU_AP0 0x0 /* APN806 revision ID */ #define MVEBU_CSS_GWD_CTRL_IIDR2_REG (MVEBU_REGS_BASE + 0x610FCC) #define GWD_IIDR2_REV_ID_OFFSET 12 #define GWD_IIDR2_REV_ID_MASK 0xF #define GWD_IIDR2_CHIP_ID_OFFSET 20 #define GWD_IIDR2_CHIP_ID_MASK (0xFFFu << GWD_IIDR2_CHIP_ID_OFFSET) #define CHIP_ID_AP806 0x806 #define CHIP_ID_AP807 0x807 #define COUNTER_FREQUENCY 25000000 #define MVEBU_REGS_BASE 0xF0000000 #define MVEBU_REGS_BASE_MASK 0xF0000000 #define MVEBU_REGS_BASE_AP(ap) MVEBU_REGS_BASE #define MVEBU_AP_IO_BASE(ap) 0xF2000000 #define MVEBU_CP_OFFSET 0x2000000 #define MVEBU_CP_REGS_BASE(cp_index) (MVEBU_AP_IO_BASE(0) + \ (cp_index) * MVEBU_CP_OFFSET) #define MVEBU_RFU_BASE (MVEBU_REGS_BASE + 0x6F0000) #define MVEBU_IO_WIN_BASE(ap_index) (MVEBU_RFU_BASE) #define MVEBU_IO_WIN_GCR_OFFSET (0x70) #define MVEBU_IO_WIN_MAX_WINS (7) /* Misc SoC configurations Base */ #define MVEBU_MISC_SOC_BASE (MVEBU_REGS_BASE + 0x6F4300) #define MVEBU_CCU_BASE(ap_index) (MVEBU_REGS_BASE + 0x4000) #define MVEBU_CCU_MAX_WINS (8) #define MVEBU_LLC_BASE(ap_index) (MVEBU_REGS_BASE + 0x8000) #define MVEBU_DRAM_MAC_BASE (MVEBU_REGS_BASE + 0x20000) #define MVEBU_DRAM_PHY_BASE (MVEBU_REGS_BASE + 0x20000) #define MVEBU_SMMU_BASE (MVEBU_REGS_BASE + 0x100000) #define MVEBU_CP_MPP_REGS(cp_index, n) (MVEBU_CP_REGS_BASE(cp_index) + \ 0x440000 + ((n) << 2)) #define MVEBU_PM_MPP_REGS(cp_index, n) (MVEBU_CP_REGS_BASE(cp_index) + \ 0x440000 + ((n / 8) << 2)) #define MVEBU_CP_GPIO_DATA_OUT(cp_index, n) \ (MVEBU_CP_REGS_BASE(cp_index) + \ 0x440100 + ((n > 31) ? 0x40 : 0x00)) #define MVEBU_CP_GPIO_DATA_OUT_EN(cp_index, n) \ (MVEBU_CP_REGS_BASE(cp_index) + \ 0x440104 + ((n > 31) ? 0x40 : 0x00)) #define MVEBU_CP_GPIO_DATA_IN(cp_index, n) (MVEBU_CP_REGS_BASE(cp_index) + \ 0x440110 + ((n > 31) ? 0x40 : 0x00)) #define MVEBU_AP_MPP_REGS(n) (MVEBU_RFU_BASE + 0x4000 + ((n) << 2)) #define MVEBU_AP_GPIO_REGS (MVEBU_RFU_BASE + 0x5040) #define MVEBU_AP_GPIO_DATA_IN (MVEBU_AP_GPIO_REGS + 0x10) #define MVEBU_AP_I2C_BASE (MVEBU_REGS_BASE + 0x511000) #define MVEBU_CP0_I2C_BASE (MVEBU_CP_REGS_BASE(0) + 0x701000) #define MVEBU_AP_EXT_TSEN_BASE (MVEBU_RFU_BASE + 0x8084) #define MVEBU_AP_MC_TRUSTZONE_REG_LOW(ap, win) (MVEBU_REGS_BASE_AP(ap) + \ 0x20080 + ((win) * 0x8)) #define MVEBU_AP_MC_TRUSTZONE_REG_HIGH(ap, win) (MVEBU_REGS_BASE_AP(ap) + \ 0x20084 + ((win) * 0x8)) /* MCI indirect access definitions */ #define MCI_MAX_UNIT_ID 2 /* SoC RFU / IHBx4 Control */ #define MCIX4_REG_START_ADDRESS_REG(unit_id) (MVEBU_RFU_BASE + \ 0x4218 + (unit_id * 0x20)) #define MCI_REMAP_OFF_SHIFT 8 #define MVEBU_MCI_REG_BASE_REMAP(index) (0xFD000000 + \ ((index) * 0x1000000)) #define MVEBU_PCIE_X4_MAC_BASE(x) (MVEBU_CP_REGS_BASE(x) + 0x600000) #define MVEBU_COMPHY_BASE(x) (MVEBU_CP_REGS_BASE(x) + 0x441000) #define MVEBU_HPIPE_BASE(x) (MVEBU_CP_REGS_BASE(x) + 0x120000) #define MVEBU_CP_DFX_OFFSET (0x400200) /***************************************************************************** * MVEBU memory map related constants ***************************************************************************** */ /* Aggregate of all devices in the first GB */ #define DEVICE0_BASE MVEBU_REGS_BASE #define DEVICE0_SIZE 0x10000000 /***************************************************************************** * GIC-400 & interrupt handling related constants ***************************************************************************** */ /* Base MVEBU compatible GIC memory map */ #define MVEBU_GICD_BASE 0x210000 #define MVEBU_GICC_BASE 0x220000 /***************************************************************************** * AXI Configuration ***************************************************************************** */ #define MVEBU_AXI_ATTR_ARCACHE_OFFSET 4 #define MVEBU_AXI_ATTR_ARCACHE_MASK (0xF << \ MVEBU_AXI_ATTR_ARCACHE_OFFSET) #define MVEBU_AXI_ATTR_ARDOMAIN_OFFSET 12 #define MVEBU_AXI_ATTR_ARDOMAIN_MASK (0x3 << \ MVEBU_AXI_ATTR_ARDOMAIN_OFFSET) #define MVEBU_AXI_ATTR_AWCACHE_OFFSET 20 #define MVEBU_AXI_ATTR_AWCACHE_MASK (0xF << \ MVEBU_AXI_ATTR_AWCACHE_OFFSET) #define MVEBU_AXI_ATTR_AWDOMAIN_OFFSET 28 #define MVEBU_AXI_ATTR_AWDOMAIN_MASK (0x3 << \ MVEBU_AXI_ATTR_AWDOMAIN_OFFSET) /* SATA MBUS to AXI configuration */ #define MVEBU_SATA_M2A_AXI_ARCACHE_OFFSET 1 #define MVEBU_SATA_M2A_AXI_ARCACHE_MASK (0xF << \ MVEBU_SATA_M2A_AXI_ARCACHE_OFFSET) #define MVEBU_SATA_M2A_AXI_AWCACHE_OFFSET 5 #define MVEBU_SATA_M2A_AXI_AWCACHE_MASK (0xF << \ MVEBU_SATA_M2A_AXI_AWCACHE_OFFSET) /* ARM cache attributes */ #define CACHE_ATTR_BUFFERABLE 0x1 #define CACHE_ATTR_CACHEABLE 0x2 #define CACHE_ATTR_READ_ALLOC 0x4 #define CACHE_ATTR_WRITE_ALLOC 0x8 /* Domain */ #define DOMAIN_NON_SHAREABLE 0x0 #define DOMAIN_INNER_SHAREABLE 0x1 #define DOMAIN_OUTER_SHAREABLE 0x2 #define DOMAIN_SYSTEM_SHAREABLE 0x3 /************************************************************************ * Required platform porting definitions common to all * Management Compute SubSystems (MSS) ************************************************************************ */ /* * Load address of SCP_BL2 * SCP_BL2 is loaded to the same place as BL31. * Once SCP_BL2 is transferred to the SCP, * it is discarded and BL31 is loaded over the top. */ #ifdef SCP_IMAGE #define SCP_BL2_BASE BL31_BASE #define SCP_BL2_SIZE BL31_LIMIT #endif #ifndef __ASSEMBLER__ enum ap806_sar_target_dev { SAR_PIDI_MCIX2 = 0x0, SAR_MCIX4 = 0x1, SAR_SPI = 0x2, SAR_SD = 0x3, SAR_PIDI_MCIX2_BD = 0x4, /* BootRom disabled */ SAR_MCIX4_DB = 0x5, /* BootRom disabled */ SAR_SPI_DB = 0x6, /* BootRom disabled */ SAR_EMMC = 0x7 }; enum io_win_target_ids { MCI_0_TID = 0x0, MCI_1_TID = 0x1, MCI_2_TID = 0x2, PIDI_TID = 0x3, SPI_TID = 0x4, STM_TID = 0x5, BOOTROM_TID = 0x6, IO_WIN_MAX_TID }; enum ccu_target_ids { IO_0_TID = 0x00, DRAM_0_TID = 0x03, IO_1_TID = 0x0F, CFG_REG_TID = 0x10, RAR_TID = 0x20, SRAM_TID = 0x40, DRAM_1_TID = 0xC0, CCU_MAX_TID, INVALID_TID = 0xFF }; #endif /* __ASSEMBLER__ */ #endif /* A8K_PLAT_DEF_H */ trusted-firmware-a-2.2/plat/marvell/a8k/common/include/ddr_info.h000066400000000000000000000003121355360272700250420ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #define DRAM_MAX_IFACE 1 #define DRAM_CH0_MMAP_LOW_OFFSET 0x20200 trusted-firmware-a-2.2/plat/marvell/a8k/common/include/mentor_i2c_plat.h000066400000000000000000000013341355360272700263440ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ /* This driver provides I2C support for Marvell A8K and compatible SoCs */ #ifndef MENTOR_I2C_PLAT_H #define MENTOR_I2C_PLAT_H #define CONFIG_SYS_TCLK 250000000 #define CONFIG_SYS_I2C_SPEED 100000 #define CONFIG_SYS_I2C_SLAVE 0x0 #define I2C_CAN_UNSTUCK struct mentor_i2c_regs { uint32_t slave_address; uint32_t data; uint32_t control; union { uint32_t status; /* when reading */ uint32_t baudrate; /* when writing */ }; uint32_t xtnd_slave_addr; uint32_t reserved[2]; uint32_t soft_reset; uint8_t reserved2[0xa0 - 0x20]; uint32_t unstuck; }; #endif /* MENTOR_I2C_PLAT_H */ trusted-firmware-a-2.2/plat/marvell/a8k/common/include/plat_macros.S000066400000000000000000000005341355360272700255430ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S #include /* * Required platform porting macros * (Provided by included headers) */ .macro plat_crash_print_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/marvell/a8k/common/include/platform_def.h000066400000000000000000000147251355360272700257350ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #ifndef __ASSEMBLER__ #include #endif /* __ASSEMBLER__ */ #include #include #include #include /* * Most platform porting definitions provided by included headers */ /* * DRAM Memory layout: * +-----------------------+ * : : * : Linux : * 0x04X00000-->+-----------------------+ * | BL3-3(u-boot) |>>}>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> * |-----------------------| } | * | BL3-[0,1, 2] | }---------------------------------> | * |-----------------------| } || | * | BL2 | }->FIP (loaded by || | * |-----------------------| } BootROM to DRAM) || | * | FIP_TOC | } || | * 0x04120000-->|-----------------------| || | * | BL1 (RO) | || | * 0x04100000-->+-----------------------+ || | * : : || | * : Trusted SRAM section : \/ | * 0x04040000-->+-----------------------+ Replaced by BL2 +----------------+ | * | BL1 (RW) | <<<<<<<<<<<<<<<< | BL3-1 NOBITS | | * 0x04037000-->|-----------------------| <<<<<<<<<<<<<<<< |----------------| | * | | <<<<<<<<<<<<<<<< | BL3-1 PROGBITS | | * 0x04023000-->|-----------------------| +----------------+ | * | BL2 | | * |-----------------------| | * | | | * 0x04001000-->|-----------------------| | * | Shared | | * 0x04000000-->+-----------------------+ | * : : | * : Linux : | * : : | * |-----------------------| | * | | U-Boot(BL3-3) Loaded by BL2 | * | U-Boot | <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< * 0x00000000-->+-----------------------+ * * Trusted SRAM section 0x4000000..0x4200000: * ---------------------------------------- * SRAM_BASE = 0x4001000 * BL2_BASE = 0x4006000 * BL2_LIMIT = BL31_BASE * BL31_BASE = 0x4023000 = (64MB + 256KB - 0x1D000) * BL31_PROGBITS_LIMIT = BL1_RW_BASE * BL1_RW_BASE = 0x4037000 = (64MB + 256KB - 0x9000) * BL1_RW_LIMIT = BL31_LIMIT = 0x4040000 * * * PLAT_MARVELL_FIP_BASE = 0x4120000 */ #define PLAT_MARVELL_SRAM_BASE 0xFFE1C048 #define PLAT_MARVELL_SRAM_END 0xFFE78000 #define PLAT_MARVELL_ATF_BASE 0x4000000 #define PLAT_MARVELL_ATF_LOAD_ADDR (PLAT_MARVELL_ATF_BASE + \ 0x100000) #define PLAT_MARVELL_FIP_BASE (PLAT_MARVELL_ATF_LOAD_ADDR + \ 0x20000) #define PLAT_MARVELL_FIP_MAX_SIZE 0x4000000 #define PLAT_MARVELL_NORTHB_COUNT 1 #define PLAT_MARVELL_CLUSTER_COUNT 2 #define PLAT_MARVELL_CLUSTER_CORE_COUNT 2 #define PLAT_MARVELL_CORE_COUNT (PLAT_MARVELL_CLUSTER_COUNT * \ PLAT_MARVELL_CLUSTER_CORE_COUNT) /* DRAM[2MB..66MB] is used as Trusted ROM */ #define PLAT_MARVELL_TRUSTED_ROM_BASE PLAT_MARVELL_ATF_LOAD_ADDR /* 64 MB TODO: reduce this to minimum needed according to fip image size */ #define PLAT_MARVELL_TRUSTED_ROM_SIZE 0x04000000 /* Reserve 16M for SCP (Secure PayLoad) Trusted DRAM */ #define PLAT_MARVELL_TRUSTED_DRAM_BASE 0x04400000 #define PLAT_MARVELL_TRUSTED_DRAM_SIZE 0x01000000 /* 16 MB */ /* * PLAT_ARM_MAX_BL1_RW_SIZE is calculated using the current BL1 RW debug size * plus a little space for growth. */ #define PLAT_MARVELL_MAX_BL1_RW_SIZE 0xA000 /* * PLAT_ARM_MAX_BL2_SIZE is calculated using the current BL2 debug size plus a * little space for growth. */ #define PLAT_MARVELL_MAX_BL2_SIZE 0xF000 /* * PLAT_ARM_MAX_BL31_SIZE is calculated using the current BL31 debug size plus a * little space for growth. */ #define PLAT_MARVEL_MAX_BL31_SIZE 0x5D000 #define PLAT_MARVELL_CPU_ENTRY_ADDR BL1_RO_BASE /* GIC related definitions */ #define PLAT_MARVELL_GICD_BASE (MVEBU_REGS_BASE + MVEBU_GICD_BASE) #define PLAT_MARVELL_GICC_BASE (MVEBU_REGS_BASE + MVEBU_GICC_BASE) #define PLAT_MARVELL_G0_IRQ_PROPS(grp) \ INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(MARVELL_IRQ_PIC0, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL) #define PLAT_MARVELL_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(MARVELL_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(MARVELL_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL) #define PLAT_MARVELL_SHARED_RAM_CACHED 1 /* * Load address of BL3-3 for this platform port */ #define PLAT_MARVELL_NS_IMAGE_OFFSET 0x0 /* System Reference Clock*/ #define PLAT_REF_CLK_IN_HZ COUNTER_FREQUENCY /* * PL011 related constants */ #define PLAT_MARVELL_BOOT_UART_BASE (MVEBU_REGS_BASE + 0x512000) #define PLAT_MARVELL_BOOT_UART_CLK_IN_HZ 200000000 #define PLAT_MARVELL_CRASH_UART_BASE PLAT_MARVELL_BOOT_UART_BASE #define PLAT_MARVELL_CRASH_UART_CLK_IN_HZ PLAT_MARVELL_BOOT_UART_CLK_IN_HZ #define PLAT_MARVELL_BL31_RUN_UART_BASE PLAT_MARVELL_BOOT_UART_BASE #define PLAT_MARVELL_BL31_RUN_UART_CLK_IN_HZ PLAT_MARVELL_BOOT_UART_CLK_IN_HZ /* Recovery image enable */ #define PLAT_RECOVERY_IMAGE_ENABLE 0 /* Required platform porting definitions */ #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1 /* System timer related constants */ #define PLAT_MARVELL_NSTIMER_FRAME_ID 1 /* Mailbox base address (note the lower memory space * is reserved for BLE data) */ #define PLAT_MARVELL_MAILBOX_BASE (MARVELL_TRUSTED_SRAM_BASE \ + 0x400) #define PLAT_MARVELL_MAILBOX_SIZE 0x100 #define PLAT_MARVELL_MAILBOX_MAGIC_NUM 0x6D72766C /* mrvl */ /* Securities */ #define IRQ_SEC_OS_TICK_INT MARVELL_IRQ_SEC_PHY_TIMER #define TRUSTED_DRAM_BASE PLAT_MARVELL_TRUSTED_DRAM_BASE #define TRUSTED_DRAM_SIZE PLAT_MARVELL_TRUSTED_DRAM_SIZE #ifdef BL32 #define BL32_BASE TRUSTED_DRAM_BASE #define BL32_LIMIT TRUSTED_DRAM_SIZE #endif #define MVEBU_PMU_IRQ_WA #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/marvell/a8k/common/mss/000077500000000000000000000000001355360272700222705ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/a8k/common/mss/mss_a8k.mk000066400000000000000000000007211355360272700241660ustar00rootroot00000000000000# # Copyright (C) 2018 Marvell International Ltd. # # SPDX-License-Identifier: BSD-3-Clause # https://spdx.org/licenses # PLAT_MARVELL := plat/marvell A8K_MSS_SOURCE := $(PLAT_MARVELL)/a8k/common/mss BL2_SOURCES += $(A8K_MSS_SOURCE)/mss_bl2_setup.c BL31_SOURCES += $(A8K_MSS_SOURCE)/mss_pm_ipc.c PLAT_INCLUDES += -I$(A8K_MSS_SOURCE) ifneq (${SCP_BL2},) # This define is used to inidcate the SCP image is present $(eval $(call add_define,SCP_IMAGE)) endif trusted-firmware-a-2.2/plat/marvell/a8k/common/mss/mss_bl2_setup.c000066400000000000000000000076431355360272700252270ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #include /* timer functionality */ #include "mss_scp_bootloader.h" /* IO windows configuration */ #define IOW_GCR_OFFSET (0x70) /* MSS windows configuration */ #define MSS_AEBR(base) (base + 0x160) #define MSS_AIBR(base) (base + 0x164) #define MSS_AEBR_MASK 0xFFF #define MSS_AIBR_MASK 0xFFF #define MSS_EXTERNAL_SPACE 0x50000000 #define MSS_EXTERNAL_ACCESS_BIT 28 #define MSS_EXTERNAL_ADDR_MASK 0xfffffff #define MSS_INTERNAL_ACCESS_BIT 28 struct addr_map_win ccu_mem_map[] = { {MVEBU_CP_REGS_BASE(0), 0x4000000, IO_0_TID} }; /* Since the scp_bl2 image can contain firmware for cp1 and cp0 coprocessors, * the access to cp0 and cp1 need to be provided. More precisely it is * required to: * - get the information about device id which is stored in CP0 registers * (to distinguish between cases where we have cp0 and cp1 or standalone cp0) * - get the access to cp which is needed for loading fw for cp0/cp1 * coprocessors * This function configures ccu windows accordingly. * * Note: there is no need to restore previous ccu configuration, since in next * phase (BL31) the init_ccu will be called (via apn806_init/ * bl31_plat_arch_setu) and therefore the ccu configuration will be overwritten. */ static int bl2_plat_mmap_init(void) { int cfg_num, win_id, cfg_idx; cfg_num = ARRAY_SIZE(ccu_mem_map); /* CCU window-0 should not be counted - it's already used */ if (cfg_num > (MVEBU_CCU_MAX_WINS - 1)) { ERROR("BL2: %s: trying to open too many windows\n", __func__); return -1; } /* Enable required CCU windows * Do not touch CCU window 0, * it's used for the internal registers access */ for (cfg_idx = 0, win_id = 1; cfg_idx < cfg_num; cfg_idx++, win_id++) { /* Enable required CCU windows */ ccu_win_check(&ccu_mem_map[cfg_idx]); ccu_enable_win(MVEBU_AP0, &ccu_mem_map[cfg_idx], win_id); } /* Set the default target id to PIDI */ mmio_write_32(MVEBU_IO_WIN_BASE(MVEBU_AP0) + IOW_GCR_OFFSET, PIDI_TID); return 0; } /***************************************************************************** * Transfer SCP_BL2 from Trusted RAM using the SCP Download protocol. * Return 0 on success, -1 otherwise. ***************************************************************************** */ int bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info) { int ret; INFO("BL2: Initiating SCP_BL2 transfer to SCP\n"); /* initialize time (for delay functionality) */ plat_delay_timer_init(); ret = bl2_plat_mmap_init(); if (ret != 0) return ret; ret = scp_bootloader_transfer((void *)scp_bl2_image_info->image_base, scp_bl2_image_info->image_size); if (ret == 0) INFO("BL2: SCP_BL2 transferred to SCP\n"); else ERROR("BL2: SCP_BL2 transfer failure\n"); return ret; } uintptr_t bl2_plat_get_cp_mss_regs(int ap_idx, int cp_idx) { return MVEBU_CP_REGS_BASE(cp_idx) + 0x280000; } uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx) { return MVEBU_REGS_BASE + 0x580000; } uint32_t bl2_plat_get_cp_count(int ap_idx) { uint32_t revision = cp110_device_id_get(MVEBU_CP_REGS_BASE(0)); /* A8040: two CPs. * A7040: one CP. */ if (revision == MVEBU_80X0_DEV_ID || revision == MVEBU_80X0_CP115_DEV_ID) return 2; else return 1; } uint32_t bl2_plat_get_ap_count(void) { /* A8040 and A7040 have only one AP */ return 1; } void bl2_plat_configure_mss_windows(uintptr_t mss_regs) { /* set AXI External and Internal Address Bus extension */ mmio_write_32(MSS_AEBR(mss_regs), ((0x0 >> MSS_EXTERNAL_ACCESS_BIT) & MSS_AEBR_MASK)); mmio_write_32(MSS_AIBR(mss_regs), ((mss_regs >> MSS_INTERNAL_ACCESS_BIT) & MSS_AIBR_MASK)); } trusted-firmware-a-2.2/plat/marvell/a8k/common/mss/mss_pm_ipc.c000066400000000000000000000041461355360272700245720ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include /* * SISR is 32 bit interrupt register representing 32 interrupts * * +======+=============+=============+ * + Bits + 31 + 30 - 00 + * +======+=============+=============+ * + Desc + MSS Msg Int + Reserved + * +======+=============+=============+ */ #define MSS_SISR (MVEBU_REGS_BASE + 0x5800D0) #define MSS_SISTR (MVEBU_REGS_BASE + 0x5800D8) #define MSS_MSG_INT_MASK (0x80000000) #define MSS_TIMER_BASE (MVEBU_REGS_BASE_MASK + 0x580110) #define MSS_TRIGGER_TIMEOUT (2000) /***************************************************************************** * mss_pm_ipc_msg_send * * DESCRIPTION: create and transmit IPC message ***************************************************************************** */ int mss_pm_ipc_msg_send(unsigned int channel_id, unsigned int msg_id, const psci_power_state_t *target_state) { /* Transmit IPC message */ #ifndef DISABLE_CLUSTER_LEVEL mv_pm_ipc_msg_tx(channel_id, msg_id, (unsigned int)target_state->pwr_domain_state[ MPIDR_AFFLVL1]); #else mv_pm_ipc_msg_tx(channel_id, msg_id, 0); #endif return 0; } /***************************************************************************** * mss_pm_ipc_msg_trigger * * DESCRIPTION: Trigger IPC message interrupt to MSS ***************************************************************************** */ int mss_pm_ipc_msg_trigger(void) { unsigned int timeout; unsigned int t_end; unsigned int t_start = mmio_read_32(MSS_TIMER_BASE); mmio_write_32(MSS_SISR, MSS_MSG_INT_MASK); do { /* wait while SCP process incoming interrupt */ if (mmio_read_32(MSS_SISTR) != MSS_MSG_INT_MASK) break; /* check timeout */ t_end = mmio_read_32(MSS_TIMER_BASE); timeout = ((t_start > t_end) ? (t_start - t_end) : (t_end - t_start)); if (timeout > MSS_TRIGGER_TIMEOUT) { ERROR("PM MSG Trigger Timeout\n"); break; } } while (1); return 0; } trusted-firmware-a-2.2/plat/marvell/a8k/common/mss/mss_pm_ipc.h000066400000000000000000000016721355360272700246000ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MSS_PM_IPC_H #define MSS_PM_IPC_H #include /* Currently MSS does not support Cluster level Power Down */ #define DISABLE_CLUSTER_LEVEL /***************************************************************************** * mss_pm_ipc_msg_send * * DESCRIPTION: create and transmit IPC message ***************************************************************************** */ int mss_pm_ipc_msg_send(unsigned int channel_id, unsigned int msg_id, const psci_power_state_t *target_state); /***************************************************************************** * mss_pm_ipc_msg_trigger * * DESCRIPTION: Trigger IPC message interrupt to MSS ***************************************************************************** */ int mss_pm_ipc_msg_trigger(void); #endif /* MSS_PM_IPC_H */ trusted-firmware-a-2.2/plat/marvell/a8k/common/plat_bl1_setup.c000066400000000000000000000006071355360272700245530ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include void marvell_bl1_setup_mpps(void) { /* Enable UART MPPs. ** In a normal system, this is done by Bootrom. */ mmio_write_32(MVEBU_AP_MPP_REGS(1), 0x3000); mmio_write_32(MVEBU_AP_MPP_REGS(2), 0x3000); } trusted-firmware-a-2.2/plat/marvell/a8k/common/plat_bl31_setup.c000066400000000000000000000065551355360272700246460ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #include #include #include #include #include /* In Armada-8k family AP806/AP807, CP0 connected to PIDI * and CP1 connected to IHB via MCI #0 */ #define MVEBU_MCI0 0 static _Bool pm_fw_running; /* Set a weak stub for platforms that don't need to configure GPIO */ #pragma weak marvell_gpio_config int marvell_gpio_config(void) { return 0; } static void marvell_bl31_mpp_init(int cp) { uint32_t reg; /* need to do for CP#0 only */ if (cp) return; /* * Enable CP0 I2C MPPs (MPP: 37-38) * U-Boot rely on proper MPP settings for I2C EEPROM usage * (only for CP0) */ reg = mmio_read_32(MVEBU_CP_MPP_REGS(0, 4)); mmio_write_32(MVEBU_CP_MPP_REGS(0, 4), reg | 0x2200000); } void marvell_bl31_mss_init(void) { struct mss_pm_ctrl_block *mss_pm_crtl = (struct mss_pm_ctrl_block *)MSS_SRAM_PM_CONTROL_BASE; /* Check that the image was loaded successfully */ if (mss_pm_crtl->handshake != HOST_ACKNOWLEDGMENT) { NOTICE("MSS PM is not supported in this build\n"); return; } /* If we got here it means that the PM firmware is running */ pm_fw_running = 1; INFO("MSS IPC init\n"); if (mss_pm_crtl->ipc_state == IPC_INITIALIZED) mv_pm_ipc_init(mss_pm_crtl->ipc_base_address | MVEBU_REGS_BASE); } _Bool is_pm_fw_running(void) { return pm_fw_running; } /* For TrusTzone we treat the "target" field of addr_map_win * struct as attribute */ static const struct addr_map_win tz_map[] = { {PLAT_MARVELL_ATF_BASE, 0x200000, TZ_PERM_ABORT} }; /* Configure MC TrustZone regions */ static void marvell_bl31_security_setup(void) { int tz_nr, win_id; tz_nr = ARRAY_SIZE(tz_map); for (win_id = 0; win_id < tz_nr; win_id++) tz_enable_win(MVEBU_AP0, tz_map, win_id); } /* This function overruns the same function in marvell_bl31_setup.c */ void bl31_plat_arch_setup(void) { int cp; uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE; /* initialize the timer for mdelay/udelay functionality */ plat_delay_timer_init(); /* configure apn806 */ ap_init(); /* In marvell_bl31_plat_arch_setup, el3 mmu is configured. * el3 mmu configuration MUST be called after apn806_init, if not, * this will cause an hang in init_io_win * (after setting the IO windows GCR values). */ if (mailbox[MBOX_IDX_MAGIC] != MVEBU_MAILBOX_MAGIC_NUM || mailbox[MBOX_IDX_SUSPEND_MAGIC] != MVEBU_MAILBOX_SUSPEND_STATE) marvell_bl31_plat_arch_setup(); for (cp = 0; cp < CP_COUNT; cp++) { /* configure cp110 for CP0*/ if (cp == 1) mci_initialize(MVEBU_MCI0); /* initialize MCI & CP1 */ cp110_init(MVEBU_CP_REGS_BASE(cp), STREAM_ID_BASE + (cp * MAX_STREAM_ID_PER_CP)); /* Should be called only after setting IOB windows */ marvell_bl31_mpp_init(cp); } /* initialize IPC between MSS and ATF */ if (mailbox[MBOX_IDX_MAGIC] != MVEBU_MAILBOX_MAGIC_NUM || mailbox[MBOX_IDX_SUSPEND_MAGIC] != MVEBU_MAILBOX_SUSPEND_STATE) marvell_bl31_mss_init(); /* Configure GPIO */ marvell_gpio_config(); marvell_bl31_security_setup(); } trusted-firmware-a-2.2/plat/marvell/a8k/common/plat_ble_setup.c000066400000000000000000000551251355360272700246440ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #include #include #include #include /* Register for skip image use */ #define SCRATCH_PAD_REG2 0xF06F00A8 #define SCRATCH_PAD_SKIP_VAL 0x01 #define NUM_OF_GPIO_PER_REG 32 #define MMAP_SAVE_AND_CONFIG 0 #define MMAP_RESTORE_SAVED 1 /* SAR clock settings */ #define MVEBU_AP_GEN_MGMT_BASE (MVEBU_RFU_BASE + 0x8000) #define MVEBU_AP_SAR_REG_BASE(r) (MVEBU_AP_GEN_MGMT_BASE + 0x200 +\ ((r) << 2)) #define SAR_CLOCK_FREQ_MODE_OFFSET (0) #define SAR_CLOCK_FREQ_MODE_MASK (0x1f << SAR_CLOCK_FREQ_MODE_OFFSET) #define SAR_PIDI_LOW_SPEED_OFFSET (20) #define SAR_PIDI_LOW_SPEED_MASK (1 << SAR_PIDI_LOW_SPEED_OFFSET) #define SAR_PIDI_LOW_SPEED_SHIFT (15) #define SAR_PIDI_LOW_SPEED_SET (1 << SAR_PIDI_LOW_SPEED_SHIFT) #define FREQ_MODE_AP_SAR_REG_NUM (0) #define SAR_CLOCK_FREQ_MODE(v) (((v) & SAR_CLOCK_FREQ_MODE_MASK) >> \ SAR_CLOCK_FREQ_MODE_OFFSET) #define AVS_I2C_EEPROM_ADDR 0x57 /* EEPROM */ #define AVS_EN_CTRL_REG (MVEBU_AP_GEN_MGMT_BASE + 0x130) #define AVS_ENABLE_OFFSET (0) #define AVS_SOFT_RESET_OFFSET (2) #define AVS_TARGET_DELTA_OFFSET (21) #ifndef MVEBU_SOC_AP807 /* AP806 SVC bits */ #define AVS_LOW_VDD_LIMIT_OFFSET (4) #define AVS_HIGH_VDD_LIMIT_OFFSET (12) #define AVS_VDD_LOW_LIMIT_MASK (0xFF << AVS_LOW_VDD_LIMIT_OFFSET) #define AVS_VDD_HIGH_LIMIT_MASK (0xFF << AVS_HIGH_VDD_LIMIT_OFFSET) #else /* AP807 SVC bits */ #define AVS_LOW_VDD_LIMIT_OFFSET (3) #define AVS_HIGH_VDD_LIMIT_OFFSET (13) #define AVS_VDD_LOW_LIMIT_MASK (0x3FF << AVS_LOW_VDD_LIMIT_OFFSET) #define AVS_VDD_HIGH_LIMIT_MASK (0x3FF << AVS_HIGH_VDD_LIMIT_OFFSET) #endif /* VDD limit is 0.9V for A70x0 @ CPU frequency < 1600MHz */ #define AVS_A7K_LOW_CLK_VALUE ((0x80 << AVS_TARGET_DELTA_OFFSET) | \ (0x1A << AVS_HIGH_VDD_LIMIT_OFFSET) | \ (0x1A << AVS_LOW_VDD_LIMIT_OFFSET) | \ (0x1 << AVS_SOFT_RESET_OFFSET) | \ (0x1 << AVS_ENABLE_OFFSET)) /* VDD limit is 1.0V for all A80x0 devices */ #define AVS_A8K_CLK_VALUE ((0x80 << AVS_TARGET_DELTA_OFFSET) | \ (0x24 << AVS_HIGH_VDD_LIMIT_OFFSET) | \ (0x24 << AVS_LOW_VDD_LIMIT_OFFSET) | \ (0x1 << AVS_SOFT_RESET_OFFSET) | \ (0x1 << AVS_ENABLE_OFFSET)) /* VDD limit is 0.82V for all A3900 devices * AVS offsets are not the same as in A70x0 */ #define AVS_A3900_CLK_VALUE ((0x80u << 24) | \ (0x2c2 << 13) | \ (0x2c2 << 3) | \ (0x1 << AVS_SOFT_RESET_OFFSET) | \ (0x1 << AVS_ENABLE_OFFSET)) /* VDD is 0.88V for 2GHz clock */ #define AVS_A3900_HIGH_CLK_VALUE ((0x80u << 24) | \ (0x2f5 << 13) | \ (0x2f5 << 3) | \ (0x1 << AVS_SOFT_RESET_OFFSET) | \ (0x1 << AVS_ENABLE_OFFSET)) #define MVEBU_AP_EFUSE_SRV_CTRL_REG (MVEBU_AP_GEN_MGMT_BASE + 0x8) #define EFUSE_SRV_CTRL_LD_SELECT_OFFS 6 #define EFUSE_SRV_CTRL_LD_SEL_USER_MASK (1 << EFUSE_SRV_CTRL_LD_SELECT_OFFS) /* * - Identification information in the LD-0 eFuse: * DRO: LD0[74:65] - Not used by the SW * Revision: LD0[78:75] - Not used by the SW * Bin: LD0[80:79] - Not used by the SW * SW Revision: LD0[115:113] * Cluster 1 PWR: LD0[193] - if set to 1, power down CPU Cluster-1 * resulting in 2 CPUs active only (7020) */ #define MVEBU_AP_LD_EFUSE_BASE (MVEBU_AP_GEN_MGMT_BASE + 0xF00) /* Bits [94:63] - 32 data bits total */ #define MVEBU_AP_LD0_94_63_EFUSE_OFFS (MVEBU_AP_LD_EFUSE_BASE + 0x8) /* Bits [125:95] - 31 data bits total, 32nd bit is parity for bits [125:63] */ #define MVEBU_AP_LD0_125_95_EFUSE_OFFS (MVEBU_AP_LD_EFUSE_BASE + 0xC) /* Bits [220:189] - 32 data bits total */ #define MVEBU_AP_LD0_220_189_EFUSE_OFFS (MVEBU_AP_LD_EFUSE_BASE + 0x18) /* Offsets for the above 2 fields combined into single 64-bit value [125:63] */ #define EFUSE_AP_LD0_DRO_OFFS 2 /* LD0[74:65] */ #define EFUSE_AP_LD0_DRO_MASK 0x3FF #define EFUSE_AP_LD0_REVID_OFFS 12 /* LD0[78:75] */ #define EFUSE_AP_LD0_REVID_MASK 0xF #define EFUSE_AP_LD0_BIN_OFFS 16 /* LD0[80:79] */ #define EFUSE_AP_LD0_BIN_MASK 0x3 #define EFUSE_AP_LD0_SWREV_OFFS 50 /* LD0[115:113] */ #define EFUSE_AP_LD0_SWREV_MASK 0x7 #ifndef MVEBU_SOC_AP807 /* AP806 AVS work points in the LD0 eFuse * SVC1 work point: LD0[88:81] * SVC2 work point: LD0[96:89] * SVC3 work point: LD0[104:97] * SVC4 work point: LD0[112:105] */ #define EFUSE_AP_LD0_SVC1_OFFS 18 /* LD0[88:81] */ #define EFUSE_AP_LD0_SVC2_OFFS 26 /* LD0[96:89] */ #define EFUSE_AP_LD0_SVC3_OFFS 34 /* LD0[104:97] */ #define EFUSE_AP_LD0_WP_MASK 0xFF #else /* AP807 AVS work points in the LD0 eFuse * SVC1 work point: LD0[91:81] * SVC2 work point: LD0[102:92] * SVC3 work point: LD0[113:103] */ #define EFUSE_AP_LD0_SVC1_OFFS 17 /* LD0[91:81] */ #define EFUSE_AP_LD0_SVC2_OFFS 28 /* LD0[102:92] */ #define EFUSE_AP_LD0_SVC3_OFFS 39 /* LD0[113:103] */ #define EFUSE_AP_LD0_WP_MASK 0x3FF #endif #define EFUSE_AP_LD0_SVC4_OFFS 42 /* LD0[112:105] */ #define EFUSE_AP_LD0_CLUSTER_DOWN_OFFS 4 #if MARVELL_SVC_TEST #define MVEBU_CP_MPP_CTRL37_OFFS 20 #define MVEBU_CP_MPP_CTRL38_OFFS 24 #define MVEBU_CP_MPP_I2C_FUNC 2 #define MVEBU_MPP_CTRL_MASK 0xf #endif /* Return the AP revision of the chip */ static unsigned int ble_get_ap_type(void) { unsigned int chip_rev_id; chip_rev_id = mmio_read_32(MVEBU_CSS_GWD_CTRL_IIDR2_REG); chip_rev_id = ((chip_rev_id & GWD_IIDR2_CHIP_ID_MASK) >> GWD_IIDR2_CHIP_ID_OFFSET); return chip_rev_id; } /****************************************************************************** * The routine allows to save the CCU and IO windows configuration during DRAM * setup and restore them afterwards before exiting the BLE stage. * Such window configuration is required since not all default settings coming * from the HW and the BootROM allow access to peripherals connected to * all available CPn components. * For instance, when the boot device is located on CP0, the IO window to CP1 * is not opened automatically by the HW and if the DRAM SPD is located on CP1 * i2c channel, it cannot be read at BLE stage. * Therefore the DRAM init procedure have to provide access to all available * CPn peripherals during the BLE stage by setting the CCU IO window to all * CPnph addresses and by enabling the IO windows accordingly. * Additionally this function configures the CCU GCR to DRAM, which allows * usage or more than 4GB DRAM as it configured by the default CCU DRAM window. * * IN: * MMAP_SAVE_AND_CONFIG - save the existing configuration and update it * MMAP_RESTORE_SAVED - restore saved configuration * OUT: * NONE **************************************************************************** */ static void ble_plat_mmap_config(int restore) { if (restore == MMAP_RESTORE_SAVED) { /* Restore all orig. settings that were modified by BLE stage */ ccu_restore_win_all(MVEBU_AP0); /* Restore CCU */ iow_restore_win_all(MVEBU_AP0); return; } /* Store original values */ ccu_save_win_all(MVEBU_AP0); /* Save CCU */ iow_save_win_all(MVEBU_AP0); init_ccu(MVEBU_AP0); /* The configuration saved, now all the changes can be done */ init_io_win(MVEBU_AP0); } /**************************************************************************** * Setup Adaptive Voltage Switching - this is required for some platforms **************************************************************************** */ #if !MARVELL_SVC_TEST static void ble_plat_avs_config(void) { uint32_t freq_mode, device_id; uint32_t avs_val = 0; freq_mode = SAR_CLOCK_FREQ_MODE(mmio_read_32(MVEBU_AP_SAR_REG_BASE( FREQ_MODE_AP_SAR_REG_NUM))); /* Check which SoC is running and act accordingly */ if (ble_get_ap_type() == CHIP_ID_AP807) { /* Increase CPU voltage for higher CPU clock */ if (freq_mode == CPU_2000_DDR_1200_RCLK_1200) avs_val = AVS_A3900_HIGH_CLK_VALUE; else avs_val = AVS_A3900_CLK_VALUE; } else { /* Check which SoC is running and act accordingly */ device_id = cp110_device_id_get(MVEBU_CP_REGS_BASE(0)); switch (device_id) { case MVEBU_80X0_DEV_ID: case MVEBU_80X0_CP115_DEV_ID: /* Always fix the default AVS value on A80x0 */ avs_val = AVS_A8K_CLK_VALUE; break; case MVEBU_70X0_DEV_ID: case MVEBU_70X0_CP115_DEV_ID: /* Fix AVS for CPU clocks lower than 1600MHz on A70x0 */ if ((freq_mode > CPU_1600_DDR_900_RCLK_900_2) && (freq_mode < CPU_DDR_RCLK_INVALID)) avs_val = AVS_A7K_LOW_CLK_VALUE; break; default: ERROR("Unsupported Device ID 0x%x\n", device_id); return; } } if (avs_val) { VERBOSE("AVS: Setting AVS CTRL to 0x%x\n", avs_val); mmio_write_32(AVS_EN_CTRL_REG, avs_val); } } #endif /****************************************************************************** * Update or override current AVS work point value using data stored in EEPROM * This is only required by QA/validation flows and activated by * MARVELL_SVC_TEST flag. * * The function is expected to be called twice. * * First time with AVS value of 0 for testing if the EEPROM requests completely * override the AVS value and bypass the eFuse test * * Second time - with non-zero AVS value obtained from eFuses as an input. * In this case the EEPROM may contain AVS correction value (either positive * or negative) that is added to the input AVS value and returned back for * further processing. ****************************************************************************** */ static uint32_t avs_update_from_eeprom(uint32_t avs_workpoint) { uint32_t new_wp = avs_workpoint; #if MARVELL_SVC_TEST /* --------------------------------------------------------------------- * EEPROM | Data description (avs_step) * address | * --------------------------------------------------------------------- * 0x120 | AVS workpoint correction value * | if not 0 and not 0xff, correct the AVS taken from eFuse * | by the number of steps indicated by bit[6:0] * | bit[7] defines correction direction. * | If bit[7]=1, add the value from bit[6:0] to AVS workpoint, * | othervise substruct this value from AVS workpoint. * --------------------------------------------------------------------- * 0x121 | AVS workpoint override value * | Override the AVS workpoint with the value stored in this * | byte. When running on AP806, the AVS workpoint is 7 bits * | wide and override value is valid when bit[6:0] holds * | value greater than zero and smaller than 0x33. * | When running on AP807, the AVS workpoint is 10 bits wide. * | Additional 2 MSB bits are supplied by EEPROM byte 0x122. * | AVS override value is valid when byte @ 0x121 and bit[1:0] * | of byte @ 0x122 combined have non-zero value. * --------------------------------------------------------------------- * 0x122 | Extended AVS workpoint override value * | Valid only for AP807 platforms and must be less than 0x4 * --------------------------------------------------------------------- */ static uint8_t avs_step[3] = {0}; uintptr_t reg; uint32_t val; unsigned int ap_type = ble_get_ap_type(); /* Always happens on second call to this function */ if (avs_workpoint != 0) { /* Get correction steps from the EEPROM */ if ((avs_step[0] != 0) && (avs_step[0] != 0xff)) { NOTICE("AVS request to step %s by 0x%x from old 0x%x\n", avs_step[0] & 0x80 ? "DOWN" : "UP", avs_step[0] & 0x7f, new_wp); if (avs_step[0] & 0x80) new_wp -= avs_step[0] & 0x7f; else new_wp += avs_step[0] & 0x7f; } return new_wp; } /* AVS values are located in EEPROM * at CP0 i2c bus #0, device 0x57 offset 0x120 * The SDA and SCK pins of CP0 i2c-0: MPP[38:37], i2c function 0x2. */ reg = MVEBU_CP_MPP_REGS(0, 4); val = mmio_read_32(reg); val &= ~((MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL37_OFFS) | (MVEBU_MPP_CTRL_MASK << MVEBU_CP_MPP_CTRL38_OFFS)); val |= (MVEBU_CP_MPP_I2C_FUNC << MVEBU_CP_MPP_CTRL37_OFFS) | (MVEBU_CP_MPP_I2C_FUNC << MVEBU_CP_MPP_CTRL38_OFFS); mmio_write_32(reg, val); /* Init CP0 i2c-0 */ i2c_init((void *)(MVEBU_CP0_I2C_BASE)); /* Read EEPROM only once at the fist call! */ i2c_read(AVS_I2C_EEPROM_ADDR, 0x120, 2, avs_step, 3); NOTICE("== SVC test build ==\n"); NOTICE("EEPROM holds values 0x%x, 0x%x and 0x%x\n", avs_step[0], avs_step[1], avs_step[2]); /* Override the AVS value? */ if ((ap_type != CHIP_ID_AP807) && (avs_step[1] < 0x33)) { /* AP806 - AVS is 7 bits */ new_wp = avs_step[1]; } else if (ap_type == CHIP_ID_AP807 && (avs_step[2] < 0x4)) { /* AP807 - AVS is 10 bits */ new_wp = avs_step[2]; new_wp <<= 8; new_wp |= avs_step[1]; } if (new_wp == 0) NOTICE("Ignore BAD AVS Override value in EEPROM!\n"); else NOTICE("Override AVS by EEPROM value 0x%x\n", new_wp); #endif /* MARVELL_SVC_TEST */ return new_wp; } /**************************************************************************** * SVC flow - v0.10 * The feature is intended to configure AVS value according to eFuse values * that are burned individually for each SoC during the test process. * Primary AVS value is stored in HD efuse and processed on power on * by the HW engine * Secondary AVS value is located in LD efuse and contains 4 work points for * various CPU frequencies. * The Secondary AVS value is only taken into account if the SW Revision stored * in the efuse is greater than 0 and the CPU is running in a certain speed. **************************************************************************** */ static void ble_plat_svc_config(void) { uint32_t reg_val, avs_workpoint, freq_pidi_mode; uint64_t efuse; uint32_t device_id, single_cluster; uint16_t svc[4], perr[4], i, sw_ver; unsigned int ap_type; /* Set access to LD0 */ avs_workpoint = avs_update_from_eeprom(0); if (avs_workpoint) goto set_aws_wp; /* Set access to LD0 */ reg_val = mmio_read_32(MVEBU_AP_EFUSE_SRV_CTRL_REG); reg_val &= ~EFUSE_SRV_CTRL_LD_SELECT_OFFS; mmio_write_32(MVEBU_AP_EFUSE_SRV_CTRL_REG, reg_val); /* Obtain the value of LD0[125:63] */ efuse = mmio_read_32(MVEBU_AP_LD0_125_95_EFUSE_OFFS); efuse <<= 32; efuse |= mmio_read_32(MVEBU_AP_LD0_94_63_EFUSE_OFFS); /* SW Revision: * Starting from SW revision 1 the SVC flow is supported. * SW version 0 (efuse not programmed) should follow the * regular AVS update flow. */ sw_ver = (efuse >> EFUSE_AP_LD0_SWREV_OFFS) & EFUSE_AP_LD0_SWREV_MASK; if (sw_ver < 1) { NOTICE("SVC: SW Revision 0x%x. SVC is not supported\n", sw_ver); #if MARVELL_SVC_TEST NOTICE("SVC_TEST: AVS bypassed\n"); #else ble_plat_avs_config(); #endif return; } /* Frequency mode from SAR */ freq_pidi_mode = SAR_CLOCK_FREQ_MODE( mmio_read_32( MVEBU_AP_SAR_REG_BASE( FREQ_MODE_AP_SAR_REG_NUM))); /* Decode all SVC work points */ svc[0] = (efuse >> EFUSE_AP_LD0_SVC1_OFFS) & EFUSE_AP_LD0_WP_MASK; svc[1] = (efuse >> EFUSE_AP_LD0_SVC2_OFFS) & EFUSE_AP_LD0_WP_MASK; svc[2] = (efuse >> EFUSE_AP_LD0_SVC3_OFFS) & EFUSE_AP_LD0_WP_MASK; /* Fetch AP type to distinguish between AP806 and AP807 */ ap_type = ble_get_ap_type(); if (ap_type != CHIP_ID_AP807) { svc[3] = (efuse >> EFUSE_AP_LD0_SVC4_OFFS) & EFUSE_AP_LD0_WP_MASK; INFO("SVC: Efuse WP: [0]=0x%x, [1]=0x%x, [2]=0x%x, [3]=0x%x\n", svc[0], svc[1], svc[2], svc[3]); } else { INFO("SVC: Efuse WP: [0]=0x%x, [1]=0x%x, [2]=0x%x\n", svc[0], svc[1], svc[2]); } /* Validate parity of SVC workpoint values */ for (i = 0; i < 4; i++) { uint8_t parity, bit; perr[i] = 0; for (bit = 1, parity = svc[i] & 1; bit < 7; bit++) parity ^= (svc[i] >> bit) & 1; /* Starting from SW version 2, the parity check is mandatory */ if ((sw_ver > 1) && (parity != ((svc[i] >> 7) & 1))) perr[i] = 1; /* register the error */ } single_cluster = mmio_read_32(MVEBU_AP_LD0_220_189_EFUSE_OFFS); single_cluster = (single_cluster >> EFUSE_AP_LD0_CLUSTER_DOWN_OFFS) & 1; device_id = cp110_device_id_get(MVEBU_CP_REGS_BASE(0)); if (device_id == MVEBU_80X0_DEV_ID || device_id == MVEBU_80X0_CP115_DEV_ID) { /* A8040/A8020 */ NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n", single_cluster == 0 ? "8040" : "8020", freq_pidi_mode); switch (freq_pidi_mode) { case CPU_1800_DDR_1200_RCLK_1200: case CPU_1800_DDR_1050_RCLK_1050: if (perr[1]) goto perror; avs_workpoint = svc[1]; break; case CPU_1600_DDR_1050_RCLK_1050: case CPU_1600_DDR_900_RCLK_900_2: if (perr[2]) goto perror; avs_workpoint = svc[2]; break; case CPU_1300_DDR_800_RCLK_800: case CPU_1300_DDR_650_RCLK_650: if (perr[3]) goto perror; avs_workpoint = svc[3]; break; case CPU_2000_DDR_1200_RCLK_1200: case CPU_2000_DDR_1050_RCLK_1050: default: if (perr[0]) goto perror; avs_workpoint = svc[0]; break; } } else if (device_id == MVEBU_70X0_DEV_ID || device_id == MVEBU_70X0_CP115_DEV_ID) { /* A7040/A7020/A6040 */ NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n", single_cluster == 0 ? "7040" : "7020", freq_pidi_mode); switch (freq_pidi_mode) { case CPU_1400_DDR_800_RCLK_800: if (single_cluster) {/* 7020 */ if (perr[1]) goto perror; avs_workpoint = svc[1]; } else { if (perr[0]) goto perror; avs_workpoint = svc[0]; } break; case CPU_1200_DDR_800_RCLK_800: if (single_cluster) {/* 7020 */ if (perr[2]) goto perror; avs_workpoint = svc[2]; } else { if (perr[1]) goto perror; avs_workpoint = svc[1]; } break; case CPU_800_DDR_800_RCLK_800: case CPU_1000_DDR_800_RCLK_800: if (single_cluster) {/* 7020 */ if (perr[3]) goto perror; avs_workpoint = svc[3]; } else { if (perr[2]) goto perror; avs_workpoint = svc[2]; } break; case CPU_600_DDR_800_RCLK_800: if (perr[3]) goto perror; avs_workpoint = svc[3]; /* Same for 6040 and 7020 */ break; case CPU_1600_DDR_800_RCLK_800: /* 7020 only */ default: if (single_cluster) {/* 7020 */ if (perr[0]) goto perror; avs_workpoint = svc[0]; } else avs_workpoint = 0; break; } } else if (device_id == MVEBU_3900_DEV_ID) { NOTICE("SVC: DEV ID: %s, FREQ Mode: 0x%x\n", "3900", freq_pidi_mode); switch (freq_pidi_mode) { case CPU_1600_DDR_1200_RCLK_1200: if (perr[0]) goto perror; avs_workpoint = svc[0]; break; case CPU_1300_DDR_800_RCLK_800: if (perr[1]) goto perror; avs_workpoint = svc[1]; break; default: if (perr[0]) goto perror; avs_workpoint = svc[0]; break; } } else { ERROR("SVC: Unsupported Device ID 0x%x\n", device_id); return; } /* Set AVS control if needed */ if (avs_workpoint == 0) { ERROR("SVC: AVS work point not changed\n"); return; } /* Remove parity bit */ if (ap_type != CHIP_ID_AP807) avs_workpoint &= 0x7F; /* Update WP from EEPROM if needed */ avs_workpoint = avs_update_from_eeprom(avs_workpoint); set_aws_wp: reg_val = mmio_read_32(AVS_EN_CTRL_REG); NOTICE("SVC: AVS work point changed from 0x%x to 0x%x\n", (reg_val & AVS_VDD_LOW_LIMIT_MASK) >> AVS_LOW_VDD_LIMIT_OFFSET, avs_workpoint); reg_val &= ~(AVS_VDD_LOW_LIMIT_MASK | AVS_VDD_HIGH_LIMIT_MASK); reg_val |= 0x1 << AVS_ENABLE_OFFSET; reg_val |= avs_workpoint << AVS_HIGH_VDD_LIMIT_OFFSET; reg_val |= avs_workpoint << AVS_LOW_VDD_LIMIT_OFFSET; mmio_write_32(AVS_EN_CTRL_REG, reg_val); return; perror: ERROR("Failed SVC WP[%d] parity check!\n", i); ERROR("Ignoring the WP values\n"); } #if PLAT_RECOVERY_IMAGE_ENABLE static int ble_skip_image_i2c(struct skip_image *skip_im) { ERROR("skipping image using i2c is not supported\n"); /* not supported */ return 0; } static int ble_skip_image_other(struct skip_image *skip_im) { ERROR("implementation missing for skip image request\n"); /* not supported, make your own implementation */ return 0; } static int ble_skip_image_gpio(struct skip_image *skip_im) { unsigned int val; unsigned int mpp_address = 0; unsigned int offset = 0; switch (skip_im->info.test.cp_ap) { case(CP): mpp_address = MVEBU_CP_GPIO_DATA_IN(skip_im->info.test.cp_index, skip_im->info.gpio.num); if (skip_im->info.gpio.num > NUM_OF_GPIO_PER_REG) offset = skip_im->info.gpio.num - NUM_OF_GPIO_PER_REG; else offset = skip_im->info.gpio.num; break; case(AP): mpp_address = MVEBU_AP_GPIO_DATA_IN; offset = skip_im->info.gpio.num; break; } val = mmio_read_32(mpp_address); val &= (1 << offset); if ((!val && skip_im->info.gpio.button_state == HIGH) || (val && skip_im->info.gpio.button_state == LOW)) { mmio_write_32(SCRATCH_PAD_REG2, SCRATCH_PAD_SKIP_VAL); return 1; } return 0; } /* * This function checks if there's a skip image request: * return values: * 1: (true) images request been made. * 0: (false) no image request been made. */ static int ble_skip_current_image(void) { struct skip_image *skip_im; /*fetching skip image info*/ skip_im = (struct skip_image *)plat_marvell_get_skip_image_data(); if (skip_im == NULL) return 0; /* check if skipping image request has already been made */ if (mmio_read_32(SCRATCH_PAD_REG2) == SCRATCH_PAD_SKIP_VAL) return 0; switch (skip_im->detection_method) { case GPIO: return ble_skip_image_gpio(skip_im); case I2C: return ble_skip_image_i2c(skip_im); case USER_DEFINED: return ble_skip_image_other(skip_im); } return 0; } #endif int ble_plat_setup(int *skip) { int ret; unsigned int freq_mode; /* Power down unused CPUs */ plat_marvell_early_cpu_powerdown(); /* * Save the current CCU configuration and make required changes: * - Allow access to DRAM larger than 4GB * - Open memory access to all CPn peripherals */ ble_plat_mmap_config(MMAP_SAVE_AND_CONFIG); #if PLAT_RECOVERY_IMAGE_ENABLE /* Check if there's a skip request to bootRom recovery Image */ if (ble_skip_current_image()) { /* close memory access to all CPn peripherals. */ ble_plat_mmap_config(MMAP_RESTORE_SAVED); *skip = 1; return 0; } #endif /* Do required CP-110 setups for BLE stage */ cp110_ble_init(MVEBU_CP_REGS_BASE(0)); /* Setup AVS */ ble_plat_svc_config(); /* read clk option from sampled-at-reset register */ freq_mode = SAR_CLOCK_FREQ_MODE(mmio_read_32(MVEBU_AP_SAR_REG_BASE( FREQ_MODE_AP_SAR_REG_NUM))); /* work with PLL clock driver in AP807 */ if (ble_get_ap_type() == CHIP_ID_AP807) ap807_clocks_init(freq_mode); /* Do required AP setups for BLE stage */ ap_ble_init(); /* Update DRAM topology (scan DIMM SPDs) */ plat_marvell_dram_update_topology(); /* Kick it in */ ret = dram_init(); /* Restore the original CCU configuration before exit from BLE */ ble_plat_mmap_config(MMAP_RESTORE_SAVED); return ret; } trusted-firmware-a-2.2/plat/marvell/a8k/common/plat_pm.c000066400000000000000000000604131355360272700232720ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MVEBU_PRIVATE_UID_REG 0x30 #define MVEBU_RFU_GLOBL_SW_RST 0x84 #define MVEBU_CCU_RVBAR(cpu) (MVEBU_REGS_BASE + 0x640 + (cpu * 4)) #define MVEBU_CCU_CPU_UN_RESET(cpu) (MVEBU_REGS_BASE + 0x650 + (cpu * 4)) #define MPIDR_CPU_GET(mpidr) ((mpidr) & MPIDR_CPU_MASK) #define MPIDR_CLUSTER_GET(mpidr) MPIDR_AFFLVL1_VAL((mpidr)) #define MVEBU_GPIO_MASK(index) (1 << (index % 32)) #define MVEBU_MPP_MASK(index) (0xF << (4 * (index % 8))) #define MVEBU_GPIO_VALUE(index, value) (value << (index % 32)) #define MVEBU_USER_CMD_0_REG (MVEBU_DRAM_MAC_BASE + 0x20) #define MVEBU_USER_CMD_CH0_OFFSET 28 #define MVEBU_USER_CMD_CH0_MASK (1 << MVEBU_USER_CMD_CH0_OFFSET) #define MVEBU_USER_CMD_CH0_EN (1 << MVEBU_USER_CMD_CH0_OFFSET) #define MVEBU_USER_CMD_CS_OFFSET 24 #define MVEBU_USER_CMD_CS_MASK (0xF << MVEBU_USER_CMD_CS_OFFSET) #define MVEBU_USER_CMD_CS_ALL (0xF << MVEBU_USER_CMD_CS_OFFSET) #define MVEBU_USER_CMD_SR_OFFSET 6 #define MVEBU_USER_CMD_SR_MASK (0x3 << MVEBU_USER_CMD_SR_OFFSET) #define MVEBU_USER_CMD_SR_ENTER (0x1 << MVEBU_USER_CMD_SR_OFFSET) #define MVEBU_MC_PWR_CTRL_REG (MVEBU_DRAM_MAC_BASE + 0x54) #define MVEBU_MC_AC_ON_DLY_OFFSET 8 #define MVEBU_MC_AC_ON_DLY_MASK (0xF << MVEBU_MC_AC_ON_DLY_OFFSET) #define MVEBU_MC_AC_ON_DLY_DEF_VAR (8 << MVEBU_MC_AC_ON_DLY_OFFSET) #define MVEBU_MC_AC_OFF_DLY_OFFSET 4 #define MVEBU_MC_AC_OFF_DLY_MASK (0xF << MVEBU_MC_AC_OFF_DLY_OFFSET) #define MVEBU_MC_AC_OFF_DLY_DEF_VAR (0xC << MVEBU_MC_AC_OFF_DLY_OFFSET) #define MVEBU_MC_PHY_AUTO_OFF_OFFSET 0 #define MVEBU_MC_PHY_AUTO_OFF_MASK (1 << MVEBU_MC_PHY_AUTO_OFF_OFFSET) #define MVEBU_MC_PHY_AUTO_OFF_EN (1 << MVEBU_MC_PHY_AUTO_OFF_OFFSET) /* this lock synchronize AP multiple cores execution with MSS */ DEFINE_BAKERY_LOCK(pm_sys_lock); /* Weak definitions may be overridden in specific board */ #pragma weak plat_marvell_get_pm_cfg /* AP806 CPU power down /power up definitions */ enum CPU_ID { CPU0, CPU1, CPU2, CPU3 }; #define REG_WR_VALIDATE_TIMEOUT (2000) #define FEATURE_DISABLE_STATUS_REG \ (MVEBU_REGS_BASE + 0x6F8230) #define FEATURE_DISABLE_STATUS_CPU_CLUSTER_OFFSET 4 #define FEATURE_DISABLE_STATUS_CPU_CLUSTER_MASK \ (0x1 << FEATURE_DISABLE_STATUS_CPU_CLUSTER_OFFSET) #ifdef MVEBU_SOC_AP807 #define PWRC_CPUN_CR_PWR_DN_RQ_OFFSET 1 #define PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET 0 #else #define PWRC_CPUN_CR_PWR_DN_RQ_OFFSET 0 #define PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET 31 #endif #define PWRC_CPUN_CR_REG(cpu_id) \ (MVEBU_REGS_BASE + 0x680000 + (cpu_id * 0x10)) #define PWRC_CPUN_CR_PWR_DN_RQ_MASK \ (0x1 << PWRC_CPUN_CR_PWR_DN_RQ_OFFSET) #define PWRC_CPUN_CR_ISO_ENABLE_OFFSET 16 #define PWRC_CPUN_CR_ISO_ENABLE_MASK \ (0x1 << PWRC_CPUN_CR_ISO_ENABLE_OFFSET) #define PWRC_CPUN_CR_LDO_BYPASS_RDY_MASK \ (0x1U << PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET) #define CCU_B_PRCRN_REG(cpu_id) \ (MVEBU_REGS_BASE + 0x1A50 + \ ((cpu_id / 2) * (0x400)) + ((cpu_id % 2) * 4)) #define CCU_B_PRCRN_CPUPORESET_STATIC_OFFSET 0 #define CCU_B_PRCRN_CPUPORESET_STATIC_MASK \ (0x1 << CCU_B_PRCRN_CPUPORESET_STATIC_OFFSET) /* power switch fingers */ #define AP807_PWRC_LDO_CR0_REG \ (MVEBU_REGS_BASE + 0x680000 + 0x100) #define AP807_PWRC_LDO_CR0_OFFSET 16 #define AP807_PWRC_LDO_CR0_MASK \ (0xff << AP807_PWRC_LDO_CR0_OFFSET) #define AP807_PWRC_LDO_CR0_VAL 0xfc /* * Power down CPU: * Used to reduce power consumption, and avoid SoC unnecessary temperature rise. */ static int plat_marvell_cpu_powerdown(int cpu_id) { uint32_t reg_val; int exit_loop = REG_WR_VALIDATE_TIMEOUT; INFO("Powering down CPU%d\n", cpu_id); /* 1. Isolation enable */ reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id)); reg_val |= 0x1 << PWRC_CPUN_CR_ISO_ENABLE_OFFSET; mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val); /* 2. Read and check Isolation enabled - verify bit set to 1 */ do { reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id)); exit_loop--; } while (!(reg_val & (0x1 << PWRC_CPUN_CR_ISO_ENABLE_OFFSET)) && exit_loop > 0); /* 3. Switch off CPU power */ reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id)); reg_val &= ~PWRC_CPUN_CR_PWR_DN_RQ_MASK; mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val); /* 4. Read and check Switch Off - verify bit set to 0 */ exit_loop = REG_WR_VALIDATE_TIMEOUT; do { reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id)); exit_loop--; } while (reg_val & PWRC_CPUN_CR_PWR_DN_RQ_MASK && exit_loop > 0); if (exit_loop <= 0) goto cpu_poweroff_error; /* 5. De-Assert power ready */ reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id)); reg_val &= ~PWRC_CPUN_CR_LDO_BYPASS_RDY_MASK; mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val); /* 6. Assert CPU POR reset */ reg_val = mmio_read_32(CCU_B_PRCRN_REG(cpu_id)); reg_val &= ~CCU_B_PRCRN_CPUPORESET_STATIC_MASK; mmio_write_32(CCU_B_PRCRN_REG(cpu_id), reg_val); /* 7. Read and poll on Validate the CPU is out of reset */ exit_loop = REG_WR_VALIDATE_TIMEOUT; do { reg_val = mmio_read_32(CCU_B_PRCRN_REG(cpu_id)); exit_loop--; } while (reg_val & CCU_B_PRCRN_CPUPORESET_STATIC_MASK && exit_loop > 0); if (exit_loop <= 0) goto cpu_poweroff_error; INFO("Successfully powered down CPU%d\n", cpu_id); return 0; cpu_poweroff_error: ERROR("ERROR: Can't power down CPU%d\n", cpu_id); return -1; } /* * Power down CPUs 1-3 at early boot stage, * to reduce power consumption and SoC temperature. * This is triggered by BLE prior to DDR initialization. * * Note: * All CPUs will be powered up by plat_marvell_cpu_powerup on Linux boot stage, * which is triggered by PSCI ops (pwr_domain_on). */ int plat_marvell_early_cpu_powerdown(void) { uint32_t cpu_cluster_status = mmio_read_32(FEATURE_DISABLE_STATUS_REG) & FEATURE_DISABLE_STATUS_CPU_CLUSTER_MASK; /* if cpu_cluster_status bit is set, * that means we have only single cluster */ int cluster_count = cpu_cluster_status ? 1 : 2; INFO("Powering off unused CPUs\n"); /* CPU1 is in AP806 cluster-0, which always exists, so power it down */ if (plat_marvell_cpu_powerdown(CPU1) == -1) return -1; /* * CPU2-3 are in AP806 2nd cluster (cluster-1), * which doesn't exists in dual-core systems. * so need to check if we have dual-core (single cluster) * or quad-code (2 clusters) */ if (cluster_count == 2) { /* CPU2-3 are part of 2nd cluster */ if (plat_marvell_cpu_powerdown(CPU2) == -1) return -1; if (plat_marvell_cpu_powerdown(CPU3) == -1) return -1; } return 0; } /* * Power up CPU - part of Linux boot stage */ static int plat_marvell_cpu_powerup(u_register_t mpidr) { uint32_t reg_val; int cpu_id = MPIDR_CPU_GET(mpidr), cluster = MPIDR_CLUSTER_GET(mpidr); int exit_loop = REG_WR_VALIDATE_TIMEOUT; /* calculate absolute CPU ID */ cpu_id = cluster * PLAT_MARVELL_CLUSTER_CORE_COUNT + cpu_id; INFO("Powering on CPU%d\n", cpu_id); #ifdef MVEBU_SOC_AP807 /* Activate 2 power switch fingers */ reg_val = mmio_read_32(AP807_PWRC_LDO_CR0_REG); reg_val &= ~(AP807_PWRC_LDO_CR0_MASK); reg_val |= (AP807_PWRC_LDO_CR0_VAL << AP807_PWRC_LDO_CR0_OFFSET); mmio_write_32(AP807_PWRC_LDO_CR0_REG, reg_val); udelay(100); #endif /* 1. Switch CPU power ON */ reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id)); reg_val |= 0x1 << PWRC_CPUN_CR_PWR_DN_RQ_OFFSET; mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val); /* 2. Wait for CPU on, up to 100 uSec: */ udelay(100); /* 3. Assert power ready */ reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id)); reg_val |= 0x1U << PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET; mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val); /* 4. Read & Validate power ready * used in order to generate 16 Host CPU cycles */ do { reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id)); exit_loop--; } while (!(reg_val & (0x1U << PWRC_CPUN_CR_LDO_BYPASS_RDY_OFFSET)) && exit_loop > 0); if (exit_loop <= 0) goto cpu_poweron_error; /* 5. Isolation disable */ reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id)); reg_val &= ~PWRC_CPUN_CR_ISO_ENABLE_MASK; mmio_write_32(PWRC_CPUN_CR_REG(cpu_id), reg_val); /* 6. Read and check Isolation enabled - verify bit set to 1 */ exit_loop = REG_WR_VALIDATE_TIMEOUT; do { reg_val = mmio_read_32(PWRC_CPUN_CR_REG(cpu_id)); exit_loop--; } while ((reg_val & (0x1 << PWRC_CPUN_CR_ISO_ENABLE_OFFSET)) && exit_loop > 0); /* 7. De Assert CPU POR reset & Core reset */ reg_val = mmio_read_32(CCU_B_PRCRN_REG(cpu_id)); reg_val |= 0x1 << CCU_B_PRCRN_CPUPORESET_STATIC_OFFSET; mmio_write_32(CCU_B_PRCRN_REG(cpu_id), reg_val); /* 8. Read & Validate CPU POR reset */ exit_loop = REG_WR_VALIDATE_TIMEOUT; do { reg_val = mmio_read_32(CCU_B_PRCRN_REG(cpu_id)); exit_loop--; } while (!(reg_val & (0x1 << CCU_B_PRCRN_CPUPORESET_STATIC_OFFSET)) && exit_loop > 0); if (exit_loop <= 0) goto cpu_poweron_error; INFO("Successfully powered on CPU%d\n", cpu_id); return 0; cpu_poweron_error: ERROR("ERROR: Can't power up CPU%d\n", cpu_id); return -1; } static int plat_marvell_cpu_on(u_register_t mpidr) { int cpu_id; int cluster; /* Set barierr */ dsbsy(); /* Get cpu number - use CPU ID */ cpu_id = MPIDR_CPU_GET(mpidr); /* Get cluster number - use affinity level 1 */ cluster = MPIDR_CLUSTER_GET(mpidr); /* Set CPU private UID */ mmio_write_32(MVEBU_REGS_BASE + MVEBU_PRIVATE_UID_REG, cluster + 0x4); /* Set the cpu start address to BL1 entry point (align to 0x10000) */ mmio_write_32(MVEBU_CCU_RVBAR(cpu_id), PLAT_MARVELL_CPU_ENTRY_ADDR >> 16); /* Get the cpu out of reset */ mmio_write_32(MVEBU_CCU_CPU_UN_RESET(cpu_id), 0x10001); return 0; } /***************************************************************************** * A8K handler called to check the validity of the power state * parameter. ***************************************************************************** */ static int a8k_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { int pstate = psci_get_pstate_type(power_state); int pwr_lvl = psci_get_pstate_pwrlvl(power_state); int i; if (pwr_lvl > PLAT_MAX_PWR_LVL) return PSCI_E_INVALID_PARAMS; /* Sanity check the requested state */ if (pstate == PSTATE_TYPE_STANDBY) { /* * It's possible to enter standby only on power level 0 * Ignore any other power level. */ if (pwr_lvl != MARVELL_PWR_LVL0) return PSCI_E_INVALID_PARAMS; req_state->pwr_domain_state[MARVELL_PWR_LVL0] = MARVELL_LOCAL_STATE_RET; } else { for (i = MARVELL_PWR_LVL0; i <= pwr_lvl; i++) req_state->pwr_domain_state[i] = MARVELL_LOCAL_STATE_OFF; } /* * We expect the 'state id' to be zero. */ if (psci_get_pstate_id(power_state)) return PSCI_E_INVALID_PARAMS; return PSCI_E_SUCCESS; } /***************************************************************************** * A8K handler called when a CPU is about to enter standby. ***************************************************************************** */ static void a8k_cpu_standby(plat_local_state_t cpu_state) { if (!is_pm_fw_running()) { ERROR("%s: needs to be implemented\n", __func__); panic(); } } /***************************************************************************** * A8K handler called when a power domain is about to be turned on. The * mpidr determines the CPU to be turned on. ***************************************************************************** */ static int a8k_pwr_domain_on(u_register_t mpidr) { /* Power up CPU (CPUs 1-3 are powered off at start of BLE) */ plat_marvell_cpu_powerup(mpidr); if (is_pm_fw_running()) { unsigned int target = ((mpidr & 0xFF) + (((mpidr >> 8) & 0xFF) * 2)); /* * pm system synchronization - used to synchronize * multiple core access to MSS */ bakery_lock_get(&pm_sys_lock); /* send CPU ON IPC Message to MSS */ mss_pm_ipc_msg_send(target, PM_IPC_MSG_CPU_ON, 0); /* trigger IPC message to MSS */ mss_pm_ipc_msg_trigger(); /* pm system synchronization */ bakery_lock_release(&pm_sys_lock); /* trace message */ PM_TRACE(TRACE_PWR_DOMAIN_ON | target); } else { /* proprietary CPU ON exection flow */ plat_marvell_cpu_on(mpidr); } return 0; } /***************************************************************************** * A8K handler called to validate the entry point. ***************************************************************************** */ static int a8k_validate_ns_entrypoint(uintptr_t entrypoint) { return PSCI_E_SUCCESS; } /***************************************************************************** * A8K handler called when a power domain is about to be turned off. The * target_state encodes the power state that each level should transition to. ***************************************************************************** */ static void a8k_pwr_domain_off(const psci_power_state_t *target_state) { if (is_pm_fw_running()) { unsigned int idx = plat_my_core_pos(); /* Prevent interrupts from spuriously waking up this cpu */ gicv2_cpuif_disable(); /* pm system synchronization - used to synchronize multiple * core access to MSS */ bakery_lock_get(&pm_sys_lock); /* send CPU OFF IPC Message to MSS */ mss_pm_ipc_msg_send(idx, PM_IPC_MSG_CPU_OFF, target_state); /* trigger IPC message to MSS */ mss_pm_ipc_msg_trigger(); /* pm system synchronization */ bakery_lock_release(&pm_sys_lock); /* trace message */ PM_TRACE(TRACE_PWR_DOMAIN_OFF); } else { INFO("%s: is not supported without SCP\n", __func__); } } /* Get PM config to power off the SoC */ void *plat_marvell_get_pm_cfg(void) { return NULL; } /* * This function should be called on restore from * "suspend to RAM" state when the execution flow * has to bypass BootROM image to RAM copy and speed up * the system recovery * */ static void plat_marvell_exit_bootrom(void) { marvell_exit_bootrom(PLAT_MARVELL_TRUSTED_ROM_BASE); } /* * Prepare for the power off of the system via GPIO */ static void plat_marvell_power_off_gpio(struct power_off_method *pm_cfg, register_t *gpio_addr, register_t *gpio_data) { unsigned int gpio; unsigned int idx; unsigned int shift; unsigned int reg; unsigned int addr; gpio_info_t *info; unsigned int tog_bits; assert((pm_cfg->cfg.gpio.pin_count < PMIC_GPIO_MAX_NUMBER) && (pm_cfg->cfg.gpio.step_count < PMIC_GPIO_MAX_TOGGLE_STEP)); /* Prepare GPIOs for PMIC */ for (gpio = 0; gpio < pm_cfg->cfg.gpio.pin_count; gpio++) { info = &pm_cfg->cfg.gpio.info[gpio]; /* Set PMIC GPIO to output mode */ reg = mmio_read_32(MVEBU_CP_GPIO_DATA_OUT_EN( info->cp_index, info->gpio_index)); mmio_write_32(MVEBU_CP_GPIO_DATA_OUT_EN( info->cp_index, info->gpio_index), reg & ~MVEBU_GPIO_MASK(info->gpio_index)); /* Set the appropriate MPP to GPIO mode */ reg = mmio_read_32(MVEBU_PM_MPP_REGS(info->cp_index, info->gpio_index)); mmio_write_32(MVEBU_PM_MPP_REGS(info->cp_index, info->gpio_index), reg & ~MVEBU_MPP_MASK(info->gpio_index)); } /* Wait for MPP & GPIO pre-configurations done */ mdelay(pm_cfg->cfg.gpio.delay_ms); /* Toggle the GPIO values, and leave final step to be triggered * after DDR self-refresh is enabled */ for (idx = 0; idx < pm_cfg->cfg.gpio.step_count; idx++) { tog_bits = pm_cfg->cfg.gpio.seq[idx]; /* The GPIOs must be within same GPIO register, * thus could get the original value by first GPIO */ info = &pm_cfg->cfg.gpio.info[0]; reg = mmio_read_32(MVEBU_CP_GPIO_DATA_OUT( info->cp_index, info->gpio_index)); addr = MVEBU_CP_GPIO_DATA_OUT(info->cp_index, info->gpio_index); for (gpio = 0; gpio < pm_cfg->cfg.gpio.pin_count; gpio++) { shift = pm_cfg->cfg.gpio.info[gpio].gpio_index % 32; if (GPIO_LOW == (tog_bits & (1 << gpio))) reg &= ~(1 << shift); else reg |= (1 << shift); } /* Set the GPIO register, for last step just store * register address and values to system registers */ if (idx < pm_cfg->cfg.gpio.step_count - 1) { mmio_write_32(MVEBU_CP_GPIO_DATA_OUT( info->cp_index, info->gpio_index), reg); mdelay(pm_cfg->cfg.gpio.delay_ms); } else { /* Save GPIO register and address values for * finishing the power down operation later */ *gpio_addr = addr; *gpio_data = reg; } } } /* * Prepare for the power off of the system */ static void plat_marvell_power_off_prepare(struct power_off_method *pm_cfg, register_t *addr, register_t *data) { switch (pm_cfg->type) { case PMIC_GPIO: plat_marvell_power_off_gpio(pm_cfg, addr, data); break; default: break; } } /***************************************************************************** * A8K handler called when a power domain is about to be suspended. The * target_state encodes the power state that each level should transition to. ***************************************************************************** */ static void a8k_pwr_domain_suspend(const psci_power_state_t *target_state) { if (is_pm_fw_running()) { unsigned int idx; /* Prevent interrupts from spuriously waking up this cpu */ gicv2_cpuif_disable(); idx = plat_my_core_pos(); /* pm system synchronization - used to synchronize multiple * core access to MSS */ bakery_lock_get(&pm_sys_lock); /* send CPU Suspend IPC Message to MSS */ mss_pm_ipc_msg_send(idx, PM_IPC_MSG_CPU_SUSPEND, target_state); /* trigger IPC message to MSS */ mss_pm_ipc_msg_trigger(); /* pm system synchronization */ bakery_lock_release(&pm_sys_lock); /* trace message */ PM_TRACE(TRACE_PWR_DOMAIN_SUSPEND); } else { uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE; INFO("Suspending to RAM\n"); marvell_console_runtime_end(); /* Prevent interrupts from spuriously waking up this cpu */ gicv2_cpuif_disable(); mailbox[MBOX_IDX_SUSPEND_MAGIC] = MVEBU_MAILBOX_SUSPEND_STATE; mailbox[MBOX_IDX_ROM_EXIT_ADDR] = (uintptr_t)&plat_marvell_exit_bootrom; #if PLAT_MARVELL_SHARED_RAM_CACHED flush_dcache_range(PLAT_MARVELL_MAILBOX_BASE + MBOX_IDX_SUSPEND_MAGIC * sizeof(uintptr_t), 2 * sizeof(uintptr_t)); #endif /* Flush and disable LLC before going off-power */ llc_disable(0); isb(); /* * Do not halt here! * The function must return for allowing the caller function * psci_power_up_finish() to do the proper context saving and * to release the CPU lock. */ } } /***************************************************************************** * A8K handler called when a power domain has just been powered on after * being turned off earlier. The target_state encodes the low power state that * each level has woken up from. ***************************************************************************** */ static void a8k_pwr_domain_on_finish(const psci_power_state_t *target_state) { /* arch specific configuration */ marvell_psci_arch_init(0); /* Interrupt initialization */ gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); if (is_pm_fw_running()) { /* trace message */ PM_TRACE(TRACE_PWR_DOMAIN_ON_FINISH); } } /***************************************************************************** * A8K handler called when a power domain has just been powered on after * having been suspended earlier. The target_state encodes the low power state * that each level has woken up from. * TODO: At the moment we reuse the on finisher and reinitialize the secure * context. Need to implement a separate suspend finisher. ***************************************************************************** */ static void a8k_pwr_domain_suspend_finish( const psci_power_state_t *target_state) { if (is_pm_fw_running()) { /* arch specific configuration */ marvell_psci_arch_init(0); /* Interrupt initialization */ gicv2_cpuif_enable(); /* trace message */ PM_TRACE(TRACE_PWR_DOMAIN_SUSPEND_FINISH); } else { uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE; /* Only primary CPU requres platform init */ if (!plat_my_core_pos()) { /* Initialize the console to provide * early debug support */ marvell_console_runtime_init(); bl31_plat_arch_setup(); marvell_bl31_platform_setup(); /* * Remove suspend to RAM marker from the mailbox * for treating a regular reset as a cold boot */ mailbox[MBOX_IDX_SUSPEND_MAGIC] = 0; mailbox[MBOX_IDX_ROM_EXIT_ADDR] = 0; #if PLAT_MARVELL_SHARED_RAM_CACHED flush_dcache_range(PLAT_MARVELL_MAILBOX_BASE + MBOX_IDX_SUSPEND_MAGIC * sizeof(uintptr_t), 2 * sizeof(uintptr_t)); #endif } } } /***************************************************************************** * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND` * call to get the `power_state` parameter. This allows the platform to encode * the appropriate State-ID field within the `power_state` parameter which can * be utilized in `pwr_domain_suspend()` to suspend to system affinity level. ***************************************************************************** */ static void a8k_get_sys_suspend_power_state(psci_power_state_t *req_state) { /* lower affinities use PLAT_MAX_OFF_STATE */ for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; } static void __dead2 a8k_pwr_domain_pwr_down_wfi(const psci_power_state_t *target_state) { struct power_off_method *pm_cfg; unsigned int srcmd; unsigned int sdram_reg; register_t gpio_data = 0, gpio_addr = 0; if (is_pm_fw_running()) { psci_power_down_wfi(); panic(); } pm_cfg = (struct power_off_method *)plat_marvell_get_pm_cfg(); /* Prepare for power off */ plat_marvell_power_off_prepare(pm_cfg, &gpio_addr, &gpio_data); /* First step to enable DDR self-refresh * to keep the data during suspend */ mmio_write_32(MVEBU_MC_PWR_CTRL_REG, 0x8C1); /* Save DDR self-refresh second step register * and value to be issued later */ sdram_reg = MVEBU_USER_CMD_0_REG; srcmd = mmio_read_32(sdram_reg); srcmd &= ~(MVEBU_USER_CMD_CH0_MASK | MVEBU_USER_CMD_CS_MASK | MVEBU_USER_CMD_SR_MASK); srcmd |= (MVEBU_USER_CMD_CH0_EN | MVEBU_USER_CMD_CS_ALL | MVEBU_USER_CMD_SR_ENTER); /* * Wait for DRAM is done using registers access only. * At this stage any access to DRAM (procedure call) will * release it from the self-refresh mode */ __asm__ volatile ( /* Align to a cache line */ " .balign 64\n\t" /* Enter self refresh */ " str %[srcmd], [%[sdram_reg]]\n\t" /* * Wait 100 cycles for DDR to enter self refresh, by * doing 50 times two instructions. */ " mov x1, #50\n\t" "1: subs x1, x1, #1\n\t" " bne 1b\n\t" /* Issue the command to trigger the SoC power off */ " str %[gpio_data], [%[gpio_addr]]\n\t" /* Trap the processor */ " b .\n\t" : : [srcmd] "r" (srcmd), [sdram_reg] "r" (sdram_reg), [gpio_addr] "r" (gpio_addr), [gpio_data] "r" (gpio_data) : "x1"); panic(); } /***************************************************************************** * A8K handlers to shutdown/reboot the system ***************************************************************************** */ static void __dead2 a8k_system_off(void) { ERROR("%s: needs to be implemented\n", __func__); panic(); } void plat_marvell_system_reset(void) { mmio_write_32(MVEBU_RFU_BASE + MVEBU_RFU_GLOBL_SW_RST, 0x0); } static void __dead2 a8k_system_reset(void) { plat_marvell_system_reset(); /* we shouldn't get to this point */ panic(); } /***************************************************************************** * Export the platform handlers via plat_arm_psci_pm_ops. The ARM Standard * platform layer will take care of registering the handlers with PSCI. ***************************************************************************** */ const plat_psci_ops_t plat_arm_psci_pm_ops = { .cpu_standby = a8k_cpu_standby, .pwr_domain_on = a8k_pwr_domain_on, .pwr_domain_off = a8k_pwr_domain_off, .pwr_domain_suspend = a8k_pwr_domain_suspend, .pwr_domain_on_finish = a8k_pwr_domain_on_finish, .get_sys_suspend_power_state = a8k_get_sys_suspend_power_state, .pwr_domain_suspend_finish = a8k_pwr_domain_suspend_finish, .pwr_domain_pwr_down_wfi = a8k_pwr_domain_pwr_down_wfi, .system_off = a8k_system_off, .system_reset = a8k_system_reset, .validate_power_state = a8k_validate_power_state, .validate_ns_entrypoint = a8k_validate_ns_entrypoint }; trusted-firmware-a-2.2/plat/marvell/a8k/common/plat_pm_trace.c000066400000000000000000000055051355360272700244510ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #ifdef PM_TRACE_ENABLE /* core trace APIs */ core_trace_func funcTbl[PLATFORM_CORE_COUNT] = { pm_core_0_trace, pm_core_1_trace, pm_core_2_trace, pm_core_3_trace}; /***************************************************************************** * pm_core0_trace * pm_core1_trace * pm_core2_trace * pm_core_3trace * * This functions set trace info into core cyclic trace queue in MSS SRAM * memory space ***************************************************************************** */ void pm_core_0_trace(unsigned int trace) { unsigned int current_position_core_0 = mmio_read_32(AP_MSS_ATF_CORE_0_CTRL_BASE); mmio_write_32((AP_MSS_ATF_CORE_0_INFO_BASE + (current_position_core_0 * AP_MSS_ATF_CORE_ENTRY_SIZE)), mmio_read_32(AP_MSS_TIMER_BASE)); mmio_write_32((AP_MSS_ATF_CORE_0_INFO_TRACE + (current_position_core_0 * AP_MSS_ATF_CORE_ENTRY_SIZE)), trace); mmio_write_32(AP_MSS_ATF_CORE_0_CTRL_BASE, ((current_position_core_0 + 1) & AP_MSS_ATF_TRACE_SIZE_MASK)); } void pm_core_1_trace(unsigned int trace) { unsigned int current_position_core_1 = mmio_read_32(AP_MSS_ATF_CORE_1_CTRL_BASE); mmio_write_32((AP_MSS_ATF_CORE_1_INFO_BASE + (current_position_core_1 * AP_MSS_ATF_CORE_ENTRY_SIZE)), mmio_read_32(AP_MSS_TIMER_BASE)); mmio_write_32((AP_MSS_ATF_CORE_1_INFO_TRACE + (current_position_core_1 * AP_MSS_ATF_CORE_ENTRY_SIZE)), trace); mmio_write_32(AP_MSS_ATF_CORE_1_CTRL_BASE, ((current_position_core_1 + 1) & AP_MSS_ATF_TRACE_SIZE_MASK)); } void pm_core_2_trace(unsigned int trace) { unsigned int current_position_core_2 = mmio_read_32(AP_MSS_ATF_CORE_2_CTRL_BASE); mmio_write_32((AP_MSS_ATF_CORE_2_INFO_BASE + (current_position_core_2 * AP_MSS_ATF_CORE_ENTRY_SIZE)), mmio_read_32(AP_MSS_TIMER_BASE)); mmio_write_32((AP_MSS_ATF_CORE_2_INFO_TRACE + (current_position_core_2 * AP_MSS_ATF_CORE_ENTRY_SIZE)), trace); mmio_write_32(AP_MSS_ATF_CORE_2_CTRL_BASE, ((current_position_core_2 + 1) & AP_MSS_ATF_TRACE_SIZE_MASK)); } void pm_core_3_trace(unsigned int trace) { unsigned int current_position_core_3 = mmio_read_32(AP_MSS_ATF_CORE_3_CTRL_BASE); mmio_write_32((AP_MSS_ATF_CORE_3_INFO_BASE + (current_position_core_3 * AP_MSS_ATF_CORE_ENTRY_SIZE)), mmio_read_32(AP_MSS_TIMER_BASE)); mmio_write_32((AP_MSS_ATF_CORE_3_INFO_TRACE + (current_position_core_3 * AP_MSS_ATF_CORE_ENTRY_SIZE)), trace); mmio_write_32(AP_MSS_ATF_CORE_3_CTRL_BASE, ((current_position_core_3 + 1) & AP_MSS_ATF_TRACE_SIZE_MASK)); } #endif /* PM_TRACE_ENABLE */ trusted-firmware-a-2.2/plat/marvell/a8k/common/plat_thermal.c000066400000000000000000000067061355360272700243170ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #define THERMAL_TIMEOUT 1200 #define THERMAL_SEN_CTRL_LSB_STRT_OFFSET 0 #define THERMAL_SEN_CTRL_LSB_STRT_MASK \ (0x1 << THERMAL_SEN_CTRL_LSB_STRT_OFFSET) #define THERMAL_SEN_CTRL_LSB_RST_OFFSET 1 #define THERMAL_SEN_CTRL_LSB_RST_MASK \ (0x1 << THERMAL_SEN_CTRL_LSB_RST_OFFSET) #define THERMAL_SEN_CTRL_LSB_EN_OFFSET 2 #define THERMAL_SEN_CTRL_LSB_EN_MASK \ (0x1 << THERMAL_SEN_CTRL_LSB_EN_OFFSET) #define THERMAL_SEN_CTRL_STATS_VALID_OFFSET 16 #define THERMAL_SEN_CTRL_STATS_VALID_MASK \ (0x1 << THERMAL_SEN_CTRL_STATS_VALID_OFFSET) #define THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET 0 #define THERMAL_SEN_CTRL_STATS_TEMP_OUT_MASK \ (0x3FF << THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET) #define THERMAL_SEN_OUTPUT_MSB 512 #define THERMAL_SEN_OUTPUT_COMP 1024 struct tsen_regs { uint32_t ext_tsen_ctrl_lsb; uint32_t ext_tsen_ctrl_msb; uint32_t ext_tsen_status; }; static int ext_tsen_probe(struct tsen_config *tsen_cfg) { uint32_t reg, timeout = 0; struct tsen_regs *base; if (tsen_cfg == NULL && tsen_cfg->regs_base == NULL) { ERROR("initial thermal sensor configuration is missing\n"); return -1; } base = (struct tsen_regs *)tsen_cfg->regs_base; INFO("initializing thermal sensor\n"); /* initialize thermal sensor hardware reset once */ reg = mmio_read_32((uintptr_t)&base->ext_tsen_ctrl_lsb); reg &= ~THERMAL_SEN_CTRL_LSB_RST_OFFSET; /* de-assert TSEN_RESET */ reg |= THERMAL_SEN_CTRL_LSB_EN_MASK; /* set TSEN_EN to 1 */ reg |= THERMAL_SEN_CTRL_LSB_STRT_MASK; /* set TSEN_START to 1 */ mmio_write_32((uintptr_t)&base->ext_tsen_ctrl_lsb, reg); reg = mmio_read_32((uintptr_t)&base->ext_tsen_status); while ((reg & THERMAL_SEN_CTRL_STATS_VALID_MASK) == 0 && timeout < THERMAL_TIMEOUT) { udelay(100); reg = mmio_read_32((uintptr_t)&base->ext_tsen_status); timeout++; } if ((reg & THERMAL_SEN_CTRL_STATS_VALID_MASK) == 0) { ERROR("thermal sensor is not ready\n"); return -1; } tsen_cfg->tsen_ready = 1; VERBOSE("thermal sensor was initialized\n"); return 0; } static int ext_tsen_read(struct tsen_config *tsen_cfg, int *temp) { uint32_t reg; struct tsen_regs *base; if (tsen_cfg == NULL && !tsen_cfg->tsen_ready) { ERROR("thermal sensor was not initialized\n"); return -1; } base = (struct tsen_regs *)tsen_cfg->regs_base; reg = mmio_read_32((uintptr_t)&base->ext_tsen_status); reg = ((reg & THERMAL_SEN_CTRL_STATS_TEMP_OUT_MASK) >> THERMAL_SEN_CTRL_STATS_TEMP_OUT_OFFSET); /* * TSEN output format is signed as a 2s complement number * ranging from-512 to +511. when MSB is set, need to * calculate the complement number */ if (reg >= THERMAL_SEN_OUTPUT_MSB) reg -= THERMAL_SEN_OUTPUT_COMP; if (tsen_cfg->tsen_divisor == 0) { ERROR("thermal sensor divisor cannot be zero\n"); return -1; } *temp = ((tsen_cfg->tsen_gain * ((int)reg)) + tsen_cfg->tsen_offset) / tsen_cfg->tsen_divisor; return 0; } static struct tsen_config tsen_cfg = { .tsen_offset = 153400, .tsen_gain = 425, .tsen_divisor = 1000, .tsen_ready = 0, .regs_base = (void *)MVEBU_AP_EXT_TSEN_BASE, .ptr_tsen_probe = ext_tsen_probe, .ptr_tsen_read = ext_tsen_read }; struct tsen_config *marvell_thermal_config_get(void) { return &tsen_cfg; } trusted-firmware-a-2.2/plat/marvell/common/000077500000000000000000000000001355360272700210035ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/common/aarch64/000077500000000000000000000000001355360272700222335ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/common/aarch64/marvell_bl2_mem_params_desc.c000066400000000000000000000076011355360272700300030ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /******************************************************************************* * Following descriptor provides BL image/ep information that gets used * by BL2 to load the images and also subset of this information is * passed to next BL image. The image loading sequence is managed by * populating the images in required loading order. The image execution * sequence is managed by populating the `next_handoff_image_id` with * the next executable image id. ******************************************************************************/ static bl_mem_params_node_t bl2_mem_params_descs[] = { #ifdef SCP_BL2_BASE /* Fill SCP_BL2 related information if it exists */ { .image_id = SCP_BL2_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE), SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, VERSION_2, image_info_t, 0), .image_info.image_base = SCP_BL2_BASE, .image_info.image_max_size = SCP_BL2_SIZE, .next_handoff_image_id = INVALID_IMAGE_ID, }, #endif /* SCP_BL2_BASE */ #ifdef EL3_PAYLOAD_BASE /* Fill EL3 payload related information (BL31 is EL3 payload)*/ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = EL3_PAYLOAD_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING), .next_handoff_image_id = INVALID_IMAGE_ID, }, #else /* EL3_PAYLOAD_BASE */ /* Fill BL31 related information */ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = BL31_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), #if DEBUG .ep_info.args.arg3 = MARVELL_BL31_PLAT_PARAM_VAL, #endif SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP), .image_info.image_base = BL31_BASE, .image_info.image_max_size = BL31_LIMIT - BL31_BASE, # ifdef BL32_BASE .next_handoff_image_id = BL32_IMAGE_ID, # else .next_handoff_image_id = BL33_IMAGE_ID, # endif }, # ifdef BL32_BASE /* Fill BL32 related information */ { .image_id = BL32_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE), .ep_info.pc = BL32_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = BL32_BASE, .image_info.image_max_size = BL32_LIMIT - BL32_BASE, .next_handoff_image_id = BL33_IMAGE_ID, }, # endif /* BL32_BASE */ /* Fill BL33 related information */ { .image_id = BL33_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), # ifdef PRELOADED_BL33_BASE .ep_info.pc = PRELOADED_BL33_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), # else .ep_info.pc = MARVELL_DRAM_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = MARVELL_DRAM_BASE, .image_info.image_max_size = MARVELL_DRAM_SIZE, # endif /* PRELOADED_BL33_BASE */ .next_handoff_image_id = INVALID_IMAGE_ID, } #endif /* EL3_PAYLOAD_BASE */ }; REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) trusted-firmware-a-2.2/plat/marvell/common/aarch64/marvell_common.c000066400000000000000000000074321355360272700254170ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #include /* Weak definitions may be overridden in specific ARM standard platform */ #pragma weak plat_get_ns_image_entrypoint #pragma weak plat_marvell_get_mmap /* * Set up the page tables for the generic and platform-specific memory regions. * The extents of the generic memory regions are specified by the function * arguments and consist of: * - Trusted SRAM seen by the BL image; * - Code section; * - Read-only data section; * - Coherent memory region, if applicable. */ void marvell_setup_page_tables(uintptr_t total_base, size_t total_size, uintptr_t code_start, uintptr_t code_limit, uintptr_t rodata_start, uintptr_t rodata_limit #if USE_COHERENT_MEM , uintptr_t coh_start, uintptr_t coh_limit #endif ) { /* * Map the Trusted SRAM with appropriate memory attributes. * Subsequent mappings will adjust the attributes for specific regions. */ VERBOSE("Trusted SRAM seen by this BL image: %p - %p\n", (void *) total_base, (void *) (total_base + total_size)); mmap_add_region(total_base, total_base, total_size, MT_MEMORY | MT_RW | MT_SECURE); /* Re-map the code section */ VERBOSE("Code region: %p - %p\n", (void *) code_start, (void *) code_limit); mmap_add_region(code_start, code_start, code_limit - code_start, MT_CODE | MT_SECURE); /* Re-map the read-only data section */ VERBOSE("Read-only data region: %p - %p\n", (void *) rodata_start, (void *) rodata_limit); mmap_add_region(rodata_start, rodata_start, rodata_limit - rodata_start, MT_RO_DATA | MT_SECURE); #if USE_COHERENT_MEM /* Re-map the coherent memory region */ VERBOSE("Coherent region: %p - %p\n", (void *) coh_start, (void *) coh_limit); mmap_add_region(coh_start, coh_start, coh_limit - coh_start, MT_DEVICE | MT_RW | MT_SECURE); #endif /* Now (re-)map the platform-specific memory regions */ mmap_add(plat_marvell_get_mmap()); /* Create the page tables to reflect the above mappings */ init_xlat_tables(); } unsigned long plat_get_ns_image_entrypoint(void) { return PLAT_MARVELL_NS_IMAGE_OFFSET; } /***************************************************************************** * Gets SPSR for BL32 entry ***************************************************************************** */ uint32_t marvell_get_spsr_for_bl32_entry(void) { /* * The Secure Payload Dispatcher service is responsible for * setting the SPSR prior to entry into the BL32 image. */ return 0; } /***************************************************************************** * Gets SPSR for BL33 entry ***************************************************************************** */ uint32_t marvell_get_spsr_for_bl33_entry(void) { unsigned long el_status; unsigned int mode; uint32_t spsr; /* Figure out what mode we enter the non-secure world in */ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; el_status &= ID_AA64PFR0_ELX_MASK; mode = (el_status) ? MODE_EL2 : MODE_EL1; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; } /***************************************************************************** * Returns ARM platform specific memory map regions. ***************************************************************************** */ const mmap_region_t *plat_marvell_get_mmap(void) { return plat_marvell_mmap; } trusted-firmware-a-2.2/plat/marvell/common/aarch64/marvell_helpers.S000066400000000000000000000144361355360272700255530ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #ifndef PLAT_a3700 #include #include #endif #include #include .weak plat_marvell_calc_core_pos .weak plat_my_core_pos .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush .globl platform_mem_init .globl disable_mmu_dcache .globl invalidate_tlb_all .globl platform_unmap_sram .globl disable_sram .globl disable_icache .globl invalidate_icache_all .globl marvell_exit_bootrom .globl ca72_l2_enable_unique_clean /* ----------------------------------------------------- * unsigned int plat_my_core_pos(void) * This function uses the plat_marvell_calc_core_pos() * definition to get the index of the calling CPU. * ----------------------------------------------------- */ func plat_my_core_pos mrs x0, mpidr_el1 b plat_marvell_calc_core_pos endfunc plat_my_core_pos /* ----------------------------------------------------- * unsigned int plat_marvell_calc_core_pos(uint64_t mpidr) * Helper function to calculate the core position. * With this function: CorePos = (ClusterId * 2) + * CoreId * ----------------------------------------------------- */ func plat_marvell_calc_core_pos and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #7 ret endfunc plat_marvell_calc_core_pos /* --------------------------------------------- * int plat_crash_console_init(void) * Function to initialize the crash console * without a C Runtime to print crash report. * Clobber list : x0, x1, x2 * --------------------------------------------- */ func plat_crash_console_init mov_imm x0, PLAT_MARVELL_CRASH_UART_BASE mov_imm x1, PLAT_MARVELL_CRASH_UART_CLK_IN_HZ mov_imm x2, MARVELL_CONSOLE_BAUDRATE #ifdef PLAT_a3700 b console_a3700_core_init #else b console_16550_core_init #endif endfunc plat_crash_console_init /* --------------------------------------------- * int plat_crash_console_putc(int c) * Function to print a character on the crash * console without a C Runtime. * Clobber list : x1, x2 * --------------------------------------------- */ func plat_crash_console_putc mov_imm x1, PLAT_MARVELL_CRASH_UART_BASE #ifdef PLAT_a3700 b console_a3700_core_putc #else b console_16550_core_putc #endif endfunc plat_crash_console_putc /* --------------------------------------------- * int plat_crash_console_flush() * Function to force a write of all buffered * data that hasn't been output. * Out : return -1 on error else return 0. * Clobber list : r0 * --------------------------------------------- */ func plat_crash_console_flush mov_imm x0, PLAT_MARVELL_CRASH_UART_BASE #ifdef PLAT_a3700 b console_a3700_core_flush #else b console_16550_core_flush #endif endfunc plat_crash_console_flush /* --------------------------------------------------------------------- * We don't need to carry out any memory initialization on ARM * platforms. The Secure RAM is accessible straight away. * --------------------------------------------------------------------- */ func platform_mem_init ret endfunc platform_mem_init /* ----------------------------------------------------- * Disable icache, dcache, and MMU * ----------------------------------------------------- */ func disable_mmu_dcache mrs x0, sctlr_el3 bic x0, x0, 0x1 /* M bit - MMU */ bic x0, x0, 0x4 /* C bit - Dcache L1 & L2 */ msr sctlr_el3, x0 isb b mmu_off mmu_off: ret endfunc disable_mmu_dcache /* ----------------------------------------------------- * Disable all TLB entries * ----------------------------------------------------- */ func invalidate_tlb_all tlbi alle3 dsb sy isb ret endfunc invalidate_tlb_all /* ----------------------------------------------------- * Disable the i cache * ----------------------------------------------------- */ func disable_icache mrs x0, sctlr_el3 bic x0, x0, 0x1000 /* I bit - Icache L1 & L2 */ msr sctlr_el3, x0 isb ret endfunc disable_icache /* ----------------------------------------------------- * Disable all of the i caches * ----------------------------------------------------- */ func invalidate_icache_all ic ialluis isb sy ret endfunc invalidate_icache_all /* ----------------------------------------------------- * Clear the SRAM enabling bit to unmap SRAM * ----------------------------------------------------- */ func platform_unmap_sram ldr x0, =CCU_SRAM_WIN_CR str wzr, [x0] ret endfunc platform_unmap_sram /* ----------------------------------------------------- * Disable the SRAM * ----------------------------------------------------- */ func disable_sram /* Disable the line lockings. They must be disabled expictly * or the OS will have problems using the cache */ ldr x1, =MASTER_LLC_TC0_LOCK str wzr, [x1] /* Invalidate all ways */ ldr w1, =LLC_WAY_MASK ldr x0, =MASTER_L2X0_INV_WAY str w1, [x0] /* Finally disable LLC */ ldr x0, =MASTER_LLC_CTRL str wzr, [x0] ret endfunc disable_sram /* ----------------------------------------------------- * Operation when exit bootROM: * Disable the MMU * Disable and invalidate the dcache * Unmap and disable the SRAM * Disable and invalidate the icache * ----------------------------------------------------- */ func marvell_exit_bootrom /* Save the system restore address */ mov x28, x0 /* Close the caches and MMU */ bl disable_mmu_dcache /* * There is nothing important in the caches now, * so invalidate them instead of cleaning. */ adr x0, __RW_START__ adr x1, __RW_END__ sub x1, x1, x0 bl inv_dcache_range bl invalidate_tlb_all /* * Clean the memory mapping of SRAM * the DDR mapping will remain to enable boot image to execute */ bl platform_unmap_sram /* Disable the SRAM */ bl disable_sram /* Disable and invalidate icache */ bl disable_icache bl invalidate_icache_all mov x0, x28 br x0 endfunc marvell_exit_bootrom /* * Enable L2 UniqueClean evictions with data */ func ca72_l2_enable_unique_clean mrs x0, CORTEX_A72_L2ACTLR_EL1 orr x0, x0, #CORTEX_A72_L2ACTLR_ENABLE_UNIQUE_CLEAN msr CORTEX_A72_L2ACTLR_EL1, x0 ret endfunc ca72_l2_enable_unique_clean trusted-firmware-a-2.2/plat/marvell/common/marvell_bl1_setup.c000066400000000000000000000046421355360272700245750ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #include /* Weak definitions may be overridden in specific Marvell standard platform */ #pragma weak bl1_early_platform_setup #pragma weak bl1_plat_arch_setup #pragma weak bl1_platform_setup #pragma weak bl1_plat_sec_mem_layout /* Data structure which holds the extents of the RAM for BL1*/ static meminfo_t bl1_ram_layout; meminfo_t *bl1_plat_sec_mem_layout(void) { return &bl1_ram_layout; } /* * BL1 specific platform actions shared between Marvell standard platforms. */ void marvell_bl1_early_platform_setup(void) { /* Initialize the console to provide early debug support */ marvell_console_boot_init(); /* Allow BL1 to see the whole Trusted RAM */ bl1_ram_layout.total_base = MARVELL_BL_RAM_BASE; bl1_ram_layout.total_size = MARVELL_BL_RAM_SIZE; } void bl1_early_platform_setup(void) { marvell_bl1_early_platform_setup(); } /* * Perform the very early platform specific architecture setup shared between * MARVELL standard platforms. This only does basic initialization. Later * architectural setup (bl1_arch_setup()) does not do anything platform * specific. */ void marvell_bl1_plat_arch_setup(void) { marvell_setup_page_tables(bl1_ram_layout.total_base, bl1_ram_layout.total_size, BL1_RO_BASE, BL1_RO_LIMIT, BL1_RO_DATA_BASE, BL1_RO_DATA_END #if USE_COHERENT_MEM , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END #endif ); enable_mmu_el3(0); } void bl1_plat_arch_setup(void) { marvell_bl1_plat_arch_setup(); } /* * Perform the platform specific architecture setup shared between * MARVELL standard platforms. */ void marvell_bl1_platform_setup(void) { /* Initialise the IO layer and register platform IO devices */ plat_marvell_io_setup(); } void bl1_platform_setup(void) { marvell_bl1_platform_setup(); } void bl1_plat_prepare_exit(entry_point_info_t *ep_info) { #ifdef EL3_PAYLOAD_BASE /* * Program the EL3 payload's entry point address into the CPUs mailbox * in order to release secondary CPUs from their holding pen and make * them jump there. */ marvell_program_trusted_mailbox(ep_info->pc); dsbsy(); sev(); #endif } trusted-firmware-a-2.2/plat/marvell/common/marvell_bl2_setup.c000066400000000000000000000072101355360272700245700ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #include #include #include #include /* Data structure which holds the extents of the trusted SRAM for BL2 */ static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE); /* Weak definitions may be overridden in specific MARVELL standard platform */ #pragma weak bl2_early_platform_setup2 #pragma weak bl2_platform_setup #pragma weak bl2_plat_arch_setup #pragma weak bl2_plat_sec_mem_layout meminfo_t *bl2_plat_sec_mem_layout(void) { return &bl2_tzram_layout; } /***************************************************************************** * BL1 has passed the extents of the trusted SRAM that should be visible to BL2 * in x0. This memory layout is sitting at the base of the free trusted SRAM. * Copy it to a safe location before its reclaimed by later BL2 functionality. ***************************************************************************** */ void marvell_bl2_early_platform_setup(meminfo_t *mem_layout) { /* Initialize the console to provide early debug support */ marvell_console_boot_init(); /* Setup the BL2 memory layout */ bl2_tzram_layout = *mem_layout; /* Initialise the IO layer and register platform IO devices */ plat_marvell_io_setup(); } void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { struct meminfo *mem_layout = (struct meminfo *)arg1; marvell_bl2_early_platform_setup(mem_layout); } void bl2_platform_setup(void) { /* Nothing to do */ } /***************************************************************************** * Perform the very early platform specific architectural setup here. At the * moment this is only initializes the mmu in a quick and dirty way. ***************************************************************************** */ void marvell_bl2_plat_arch_setup(void) { marvell_setup_page_tables(bl2_tzram_layout.total_base, bl2_tzram_layout.total_size, BL_CODE_BASE, BL_CODE_END, BL_RO_DATA_BASE, BL_RO_DATA_END #if USE_COHERENT_MEM , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END #endif ); enable_mmu_el1(0); } void bl2_plat_arch_setup(void) { marvell_bl2_plat_arch_setup(); } int marvell_bl2_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); assert(bl_mem_params); switch (image_id) { case BL33_IMAGE_ID: /* BL33 expects to receive the primary CPU MPID (through r0) */ bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr(); bl_mem_params->ep_info.spsr = marvell_get_spsr_for_bl33_entry(); break; #ifdef SCP_BL2_BASE case SCP_BL2_IMAGE_ID: /* The subsequent handling of SCP_BL2 is platform specific */ err = bl2_plat_handle_scp_bl2(&bl_mem_params->image_info); if (err) { WARN("Failure in platform-specific handling of SCP_BL2 image.\n"); } break; #endif default: /* Do nothing in default case */ break; } return err; } /******************************************************************************* * 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) { return marvell_bl2_handle_post_image_load(image_id); } trusted-firmware-a-2.2/plat/marvell/common/marvell_bl31_setup.c000066400000000000000000000155131355360272700246570ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #ifdef USE_CCI #include #endif #include #include #include #include #include /* * Placeholder variables for copying the arguments that have been passed to * BL31 from BL2. */ static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; /* Weak definitions may be overridden in specific ARM standard platform */ #pragma weak bl31_early_platform_setup2 #pragma weak bl31_platform_setup #pragma weak bl31_plat_arch_setup #pragma weak bl31_plat_get_next_image_ep_info #pragma weak plat_get_syscnt_freq2 /***************************************************************************** * Return a pointer to the 'entry_point_info' structure of the next image for * the security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. ***************************************************************************** */ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; assert(sec_state_is_valid(type)); next_image_info = (type == NON_SECURE) ? &bl33_image_ep_info : &bl32_image_ep_info; return next_image_info; } /***************************************************************************** * Perform any BL31 early platform setup common to ARM standard platforms. * Here is an opportunity to copy parameters passed by the calling EL (S-EL1 * in BL2 & EL3 in BL1) before they are lost (potentially). This needs to be * done before the MMU is initialized so that the memory layout can be used * while creating page tables. BL2 has flushed this information to memory, so * we are guaranteed to pick up good data. ***************************************************************************** */ void marvell_bl31_early_platform_setup(void *from_bl2, uintptr_t soc_fw_config, uintptr_t hw_config, void *plat_params_from_bl2) { /* Initialize the console to provide early debug support */ marvell_console_boot_init(); #if RESET_TO_BL31 /* There are no parameters from BL2 if BL31 is a reset vector */ assert(from_bl2 == NULL); assert(plat_params_from_bl2 == NULL); #ifdef BL32_BASE /* Populate entry point information for BL32 */ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0); SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); bl32_image_ep_info.pc = BL32_BASE; bl32_image_ep_info.spsr = marvell_get_spsr_for_bl32_entry(); #endif /* BL32_BASE */ /* Populate entry point information for BL33 */ SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); /* * Tell BL31 where the non-trusted software image * is located and the entry state information */ bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); bl33_image_ep_info.spsr = marvell_get_spsr_for_bl33_entry(); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); #else /* * In debug builds, we pass a special value in 'plat_params_from_bl2' * to verify platform parameters from BL2 to BL31. * In release builds, it's not used. */ assert(((unsigned long long)plat_params_from_bl2) == MARVELL_BL31_PLAT_PARAM_VAL); /* * Check params passed from BL2 should not be NULL, */ bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2; assert(params_from_bl2 != NULL); assert(params_from_bl2->h.type == PARAM_BL_PARAMS); assert(params_from_bl2->h.version >= VERSION_2); bl_params_node_t *bl_params = params_from_bl2->head; /* * Copy BL33 and BL32 (if present), entry point information. * They are stored in Secure RAM, in BL2's address space. */ while (bl_params != NULL) { if (bl_params->image_id == BL32_IMAGE_ID) bl32_image_ep_info = *bl_params->ep_info; if (bl_params->image_id == BL33_IMAGE_ID) bl33_image_ep_info = *bl_params->ep_info; bl_params = bl_params->next_params_info; } #endif } void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { marvell_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3); #ifdef USE_CCI /* * Initialize CCI for this cluster during cold boot. * No need for locks as no other CPU is active. */ plat_marvell_interconnect_init(); /* * Enable CCI coherency for the primary CPU's cluster. * Platform specific PSCI code will enable coherency for other * clusters. */ plat_marvell_interconnect_enter_coherency(); #endif } /***************************************************************************** * Perform any BL31 platform setup common to ARM standard platforms ***************************************************************************** */ void marvell_bl31_platform_setup(void) { /* Initialize the GIC driver, cpu and distributor interfaces */ plat_marvell_gic_driver_init(); plat_marvell_gic_init(); /* For Armada-8k-plus family, the SoC includes more than * a single AP die, but the default die that boots is AP #0. * For other families there is only one die (#0). * Initialize psci arch from die 0 */ marvell_psci_arch_init(0); } /***************************************************************************** * Perform any BL31 platform runtime setup prior to BL31 exit common to ARM * standard platforms ***************************************************************************** */ void marvell_bl31_plat_runtime_setup(void) { console_switch_state(CONSOLE_FLAG_RUNTIME); /* Initialize the runtime console */ marvell_console_runtime_init(); } void bl31_platform_setup(void) { marvell_bl31_platform_setup(); } void bl31_plat_runtime_setup(void) { marvell_bl31_plat_runtime_setup(); } /***************************************************************************** * Perform the very early platform specific architectural setup shared between * ARM standard platforms. This only does basic initialization. Later * architectural setup (bl31_arch_setup()) does not do anything platform * specific. ***************************************************************************** */ void marvell_bl31_plat_arch_setup(void) { marvell_setup_page_tables(BL31_BASE, BL31_END - BL31_BASE, BL_CODE_BASE, BL_CODE_END, BL_RO_DATA_BASE, BL_RO_DATA_END #if USE_COHERENT_MEM , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END #endif ); #if BL31_CACHE_DISABLE enable_mmu_el3(DISABLE_DCACHE); INFO("Cache is disabled in BL3\n"); #else enable_mmu_el3(0); #endif } void bl31_plat_arch_setup(void) { marvell_bl31_plat_arch_setup(); } unsigned int plat_get_syscnt_freq2(void) { return PLAT_REF_CLK_IN_HZ; } trusted-firmware-a-2.2/plat/marvell/common/marvell_cci.c000066400000000000000000000033301355360272700234260ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include static const int cci_map[] = { PLAT_MARVELL_CCI_CLUSTER0_SL_IFACE_IX, PLAT_MARVELL_CCI_CLUSTER1_SL_IFACE_IX }; /**************************************************************************** * The following functions are defined as weak to allow a platform to override * the way ARM CCI driver is initialised and used. **************************************************************************** */ #pragma weak plat_marvell_interconnect_init #pragma weak plat_marvell_interconnect_enter_coherency #pragma weak plat_marvell_interconnect_exit_coherency /**************************************************************************** * Helper function to initialize ARM CCI driver. **************************************************************************** */ void plat_marvell_interconnect_init(void) { cci_init(PLAT_MARVELL_CCI_BASE, cci_map, ARRAY_SIZE(cci_map)); } /**************************************************************************** * Helper function to place current master into coherency **************************************************************************** */ void plat_marvell_interconnect_enter_coherency(void) { cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); } /**************************************************************************** * Helper function to remove current master from coherency **************************************************************************** */ void plat_marvell_interconnect_exit_coherency(void) { cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); } trusted-firmware-a-2.2/plat/marvell/common/marvell_common.mk000066400000000000000000000042441355360272700243520ustar00rootroot00000000000000# Copyright (C) 2018 Marvell International Ltd. # # SPDX-License-Identifier: BSD-3-Clause # https://spdx.org/licenses MARVELL_PLAT_BASE := plat/marvell MARVELL_PLAT_INCLUDE_BASE := include/plat/marvell include $(MARVELL_PLAT_BASE)/version.mk include $(MARVELL_PLAT_BASE)/marvell.mk VERSION_STRING +=(Marvell-${SUBVERSION}) SEPARATE_CODE_AND_RODATA := 1 # flag to switch from PLL to ARO ARO_ENABLE := 0 $(eval $(call add_define,ARO_ENABLE)) # Enable/Disable LLC LLC_ENABLE := 1 $(eval $(call add_define,LLC_ENABLE)) include lib/xlat_tables_v2/xlat_tables.mk PLAT_INCLUDES += -I$(MARVELL_PLAT_INCLUDE_BASE)/common \ -I$(MARVELL_PLAT_INCLUDE_BASE)/common/aarch64 PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} \ $(MARVELL_PLAT_BASE)/common/aarch64/marvell_common.c \ $(MARVELL_PLAT_BASE)/common/aarch64/marvell_helpers.S \ $(MARVELL_COMMON_BASE)/marvell_console.c BL1_SOURCES += drivers/delay_timer/delay_timer.c \ drivers/io/io_fip.c \ drivers/io/io_memmap.c \ drivers/io/io_storage.c \ $(MARVELL_PLAT_BASE)/common/marvell_bl1_setup.c \ $(MARVELL_PLAT_BASE)/common/marvell_io_storage.c \ $(MARVELL_PLAT_BASE)/common/plat_delay_timer.c ifdef EL3_PAYLOAD_BASE # Need the arm_program_trusted_mailbox() function to release secondary CPUs from # their holding pen endif BL2_SOURCES += drivers/io/io_fip.c \ drivers/io/io_memmap.c \ drivers/io/io_storage.c \ common/desc_image_load.c \ $(MARVELL_PLAT_BASE)/common/marvell_bl2_setup.c \ $(MARVELL_PLAT_BASE)/common/marvell_io_storage.c \ $(MARVELL_PLAT_BASE)/common/aarch64/marvell_bl2_mem_params_desc.c \ $(MARVELL_PLAT_BASE)/common/marvell_image_load.c BL31_SOURCES += $(MARVELL_PLAT_BASE)/common/marvell_bl31_setup.c \ $(MARVELL_PLAT_BASE)/common/marvell_pm.c \ $(MARVELL_PLAT_BASE)/common/marvell_topology.c \ plat/common/plat_psci_common.c \ $(MARVELL_PLAT_BASE)/common/plat_delay_timer.c \ drivers/delay_timer/delay_timer.c # PSCI functionality $(eval $(call add_define,CONFIG_ARM64)) # MSS (SCP) build ifeq (${MSS_SUPPORT}, 1) include $(MARVELL_PLAT_BASE)/common/mss/mss_common.mk endif fip: mrvl_flash trusted-firmware-a-2.2/plat/marvell/common/marvell_console.c000066400000000000000000000037721355360272700243440ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #ifdef PLAT_a3700 #include static console_a3700_t marvell_boot_console; static console_a3700_t marvell_runtime_console; #else #include static console_16550_t marvell_boot_console; static console_16550_t marvell_runtime_console; #endif /******************************************************************************* * Functions that set up the console ******************************************************************************/ /* Initialize the console to provide early debug support */ void marvell_console_boot_init(void) { int rc = #ifdef PLAT_a3700 console_a3700_register( #else console_16550_register( #endif PLAT_MARVELL_BOOT_UART_BASE, PLAT_MARVELL_BOOT_UART_CLK_IN_HZ, MARVELL_CONSOLE_BAUDRATE, &marvell_boot_console); if (rc == 0) { /* * The crash console doesn't use the multi console API, it uses * the core console functions directly. It is safe to call panic * and let it print debug information. */ panic(); } console_set_scope(&marvell_boot_console.console, CONSOLE_FLAG_BOOT); } void marvell_console_boot_end(void) { (void)console_flush(); (void)console_unregister(&marvell_boot_console.console); } /* Initialize the runtime console */ void marvell_console_runtime_init(void) { int rc = #ifdef PLAT_a3700 console_a3700_register( #else console_16550_register( #endif PLAT_MARVELL_BOOT_UART_BASE, PLAT_MARVELL_BOOT_UART_CLK_IN_HZ, MARVELL_CONSOLE_BAUDRATE, &marvell_runtime_console); if (rc == 0) panic(); console_set_scope(&marvell_runtime_console.console, CONSOLE_FLAG_RUNTIME); } void marvell_console_runtime_end(void) { (void)console_flush(); (void)console_unregister(&marvell_runtime_console.console); } trusted-firmware-a-2.2/plat/marvell/common/marvell_ddr_info.c000066400000000000000000000055741355360272700244700ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #define DRAM_CH0_MMAP_LOW_REG(iface, cs, base) \ (base + DRAM_CH0_MMAP_LOW_OFFSET + (iface) * 0x10000 + (cs) * 0x8) #define DRAM_CH0_MMAP_HIGH_REG(iface, cs, base) \ (DRAM_CH0_MMAP_LOW_REG(iface, cs, base) + 4) #define DRAM_CS_VALID_ENABLED_MASK 0x1 #define DRAM_AREA_LENGTH_OFFS 16 #define DRAM_AREA_LENGTH_MASK (0x1f << DRAM_AREA_LENGTH_OFFS) #define DRAM_START_ADDRESS_L_OFFS 23 #define DRAM_START_ADDRESS_L_MASK \ (0x1ff << DRAM_START_ADDRESS_L_OFFS) #define DRAM_START_ADDR_HTOL_OFFS 32 #define DRAM_MAX_CS_NUM 2 #define DRAM_CS_ENABLED(iface, cs, base) \ (mmio_read_32(DRAM_CH0_MMAP_LOW_REG(iface, cs, base)) & \ DRAM_CS_VALID_ENABLED_MASK) #define GET_DRAM_REGION_SIZE_CODE(iface, cs, base) \ (mmio_read_32(DRAM_CH0_MMAP_LOW_REG(iface, cs, base)) & \ DRAM_AREA_LENGTH_MASK) >> DRAM_AREA_LENGTH_OFFS /* Mapping between DDR area length and real DDR size is specific and looks like * bellow: * 0 => 384 MB * 1 => 768 MB * 2 => 1536 MB * 3 => 3 GB * 4 => 6 GB * * 7 => 8 MB * 8 => 16 MB * 9 => 32 MB * 10 => 64 MB * 11 => 128 MB * 12 => 256 MB * 13 => 512 MB * 14 => 1 GB * 15 => 2 GB * 16 => 4 GB * 17 => 8 GB * 18 => 16 GB * 19 => 32 GB * 20 => 64 GB * 21 => 128 GB * 22 => 256 GB * 23 => 512 GB * 24 => 1 TB * 25 => 2 TB * 26 => 4 TB * * to calculate real size we need to use two different formulas: * -- GET_DRAM_REGION_SIZE_ODD for values 0-4 (DRAM_REGION_SIZE_ODD) * -- GET_DRAM_REGION_SIZE_EVEN for values 7-26 (DRAM_REGION_SIZE_EVEN) * using mentioned formulas we cover whole mapping between "Area length" value * and real size (see above mapping). */ #define DRAM_REGION_SIZE_EVEN(C) (((C) >= 7) && ((C) <= 26)) #define GET_DRAM_REGION_SIZE_EVEN(C) ((uint64_t)1 << ((C) + 16)) #define DRAM_REGION_SIZE_ODD(C) ((C) <= 4) #define GET_DRAM_REGION_SIZE_ODD(C) ((uint64_t)0x18000000 << (C)) uint64_t mvebu_get_dram_size(uint64_t ap_base_addr) { uint64_t mem_size = 0; uint8_t region_code; uint8_t cs, iface; for (iface = 0; iface < DRAM_MAX_IFACE; iface++) { for (cs = 0; cs < DRAM_MAX_CS_NUM; cs++) { /* Exit loop on first disabled DRAM CS */ if (!DRAM_CS_ENABLED(iface, cs, ap_base_addr)) break; /* Decode area length for current CS * from register value */ region_code = GET_DRAM_REGION_SIZE_CODE(iface, cs, ap_base_addr); if (DRAM_REGION_SIZE_EVEN(region_code)) { mem_size += GET_DRAM_REGION_SIZE_EVEN(region_code); } else if (DRAM_REGION_SIZE_ODD(region_code)) { mem_size += GET_DRAM_REGION_SIZE_ODD(region_code); } else { WARN("%s: Invalid mem region (0x%x) CS#%d\n", __func__, region_code, cs); return 0; } } } return mem_size; } trusted-firmware-a-2.2/plat/marvell/common/marvell_gicv2.c000066400000000000000000000073001355360272700237030ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #include /* * The following functions are defined as weak to allow a platform to override * the way the GICv2 driver is initialised and used. */ #pragma weak plat_marvell_gic_driver_init #pragma weak plat_marvell_gic_init #define A7K8K_PIC_CAUSE_REG 0xf03f0100 #define A7K8K_PIC0_MASK_REG 0xf03f0108 #define A7K8K_PIC_PMUOF_IRQ_MASK (1 << 17) #define A7K8K_PIC_MAX_IRQS 32 #define A7K8K_PIC_MAX_IRQ_MASK ((1UL << A7K8K_PIC_MAX_IRQS) - 1) #define A7K8K_ODMIN_SET_REG 0xf0300040 #define A7K8K_ODMI_PMU_IRQ(idx) ((2 + idx) << 12) #define A7K8K_ODMI_PMU_GIC_IRQ(idx) (130 + idx) static DEFINE_BAKERY_LOCK(a7k8k_irq_lock); /* * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0 * interrupts. */ static const interrupt_prop_t marvell_interrupt_props[] = { PLAT_MARVELL_G1S_IRQ_PROPS(GICV2_INTR_GROUP0), PLAT_MARVELL_G0_IRQ_PROPS(GICV2_INTR_GROUP0) }; static unsigned int target_mask_array[PLATFORM_CORE_COUNT]; /* * Ideally `marvell_gic_data` structure definition should be a `const` but it is * kept as modifiable for overwriting with different GICD and GICC base when * running on FVP with VE memory map. */ static gicv2_driver_data_t marvell_gic_data = { .gicd_base = PLAT_MARVELL_GICD_BASE, .gicc_base = PLAT_MARVELL_GICC_BASE, .interrupt_props = marvell_interrupt_props, .interrupt_props_num = ARRAY_SIZE(marvell_interrupt_props), .target_masks = target_mask_array, .target_masks_num = ARRAY_SIZE(target_mask_array), }; /* * ARM common helper to initialize the GICv2 only driver. */ void plat_marvell_gic_driver_init(void) { gicv2_driver_init(&marvell_gic_data); } static uint64_t a7k8k_pmu_interrupt_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { unsigned int idx = plat_my_core_pos(); uint32_t irq; bakery_lock_get(&a7k8k_irq_lock); /* Acknowledge IRQ */ irq = plat_ic_acknowledge_interrupt(); plat_ic_end_of_interrupt(irq); if (irq != MARVELL_IRQ_PIC0) { bakery_lock_release(&a7k8k_irq_lock); return 0; } /* Acknowledge PMU overflow IRQ in PIC0 */ mmio_setbits_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_PMUOF_IRQ_MASK); /* Trigger ODMI Frame IRQ */ mmio_write_32(A7K8K_ODMIN_SET_REG, A7K8K_ODMI_PMU_IRQ(idx)); bakery_lock_release(&a7k8k_irq_lock); return 0; } void mvebu_pmu_interrupt_enable(void) { unsigned int idx; uint32_t flags; int32_t rc; /* Reset PIC */ mmio_write_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_MAX_IRQ_MASK); /* Unmask PMU overflow IRQ in PIC0 */ mmio_clrbits_32(A7K8K_PIC0_MASK_REG, A7K8K_PIC_PMUOF_IRQ_MASK); /* Configure ODMI Frame IRQs as edge triggered */ for (idx = 0; idx < PLATFORM_CORE_COUNT; idx++) gicv2_interrupt_set_cfg(A7K8K_ODMI_PMU_GIC_IRQ(idx), GIC_INTR_CFG_EDGE); /* * Register IRQ handler as INTR_TYPE_S_EL1 as its the only valid type * for GICv2 in ARM-TF. */ flags = 0U; set_interrupt_rm_flag((flags), (NON_SECURE)); rc = register_interrupt_type_handler(INTR_TYPE_S_EL1, a7k8k_pmu_interrupt_handler, flags); if (rc != 0) panic(); } void mvebu_pmu_interrupt_disable(void) { /* Reset PIC */ mmio_write_32(A7K8K_PIC_CAUSE_REG, A7K8K_PIC_MAX_IRQ_MASK); /* Mask PMU overflow IRQ in PIC0 */ mmio_setbits_32(A7K8K_PIC0_MASK_REG, A7K8K_PIC_PMUOF_IRQ_MASK); } void plat_marvell_gic_init(void) { gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_set_pe_target_mask(plat_my_core_pos()); gicv2_cpuif_enable(); } trusted-firmware-a-2.2/plat/marvell/common/marvell_gicv3.c000066400000000000000000000156271355360272700237170ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include /****************************************************************************** * The following functions are defined as weak to allow a platform to override * the way the GICv3 driver is initialised and used. ****************************************************************************** */ #pragma weak plat_marvell_gic_driver_init #pragma weak plat_marvell_gic_init #pragma weak plat_marvell_gic_cpuif_enable #pragma weak plat_marvell_gic_cpuif_disable #pragma weak plat_marvell_gic_pcpu_init /* The GICv3 driver only needs to be initialized in EL3 */ static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT]; static const interrupt_prop_t marvell_interrupt_props[] = { PLAT_MARVELL_G1S_IRQ_PROPS(INTR_GROUP1S), PLAT_MARVELL_G0_IRQ_PROPS(INTR_GROUP0) }; /* * We save and restore the GICv3 context on system suspend. Allocate the * data in the designated EL3 Secure carve-out memory */ static gicv3_redist_ctx_t rdist_ctx __section("arm_el3_tzc_dram"); static gicv3_dist_ctx_t dist_ctx __section("arm_el3_tzc_dram"); /* * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register * to core position. * * Calculating core position is dependent on MPIDR_EL1.MT bit. However, affinity * values read from GICR_TYPER don't have an MT field. To reuse the same * translation used for CPUs, we insert MT bit read from the PE's MPIDR into * that read from GICR_TYPER. * * Assumptions: * * - All CPUs implemented in the system have MPIDR_EL1.MT bit set; * - No CPUs implemented in the system use affinity level 3. */ static unsigned int marvell_gicv3_mpidr_hash(u_register_t mpidr) { mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK); return plat_marvell_calc_core_pos(mpidr); } const gicv3_driver_data_t marvell_gic_data = { .gicd_base = PLAT_MARVELL_GICD_BASE, .gicr_base = PLAT_MARVELL_GICR_BASE, .interrupt_props = marvell_interrupt_props, .interrupt_props_num = ARRAY_SIZE(marvell_interrupt_props), .rdistif_num = PLATFORM_CORE_COUNT, .rdistif_base_addrs = rdistif_base_addrs, .mpidr_to_core_pos = marvell_gicv3_mpidr_hash }; void plat_marvell_gic_driver_init(void) { /* * The GICv3 driver is initialized in EL3 and does not need * to be initialized again in SEL1. This is because the S-EL1 * can use GIC system registers to manage interrupts and does * not need GIC interface base addresses to be configured. */ #if IMAGE_BL31 gicv3_driver_init(&marvell_gic_data); #endif } /****************************************************************************** * Marvell common helper to initialize the GIC. Only invoked by BL31 ****************************************************************************** */ void plat_marvell_gic_init(void) { /* Initialize GIC-600 Multi Chip feature, * only if the maximum number of north bridges * is more than 1 - otherwise no need for multi * chip feature initialization */ #if (PLAT_MARVELL_NORTHB_COUNT > 1) if (gic600_multi_chip_init()) ERROR("GIC-600 Multi Chip initialization failed\n"); #endif gicv3_distif_init(); gicv3_rdistif_init(plat_my_core_pos()); gicv3_cpuif_enable(plat_my_core_pos()); } /****************************************************************************** * Marvell common helper to enable the GIC CPU interface ****************************************************************************** */ void plat_marvell_gic_cpuif_enable(void) { gicv3_cpuif_enable(plat_my_core_pos()); } /****************************************************************************** * Marvell common helper to disable the GIC CPU interface ****************************************************************************** */ void plat_marvell_gic_cpuif_disable(void) { gicv3_cpuif_disable(plat_my_core_pos()); } /****************************************************************************** * Marvell common helper to init. the per-cpu redistributor interface in GICv3 ****************************************************************************** */ void plat_marvell_gic_pcpu_init(void) { gicv3_rdistif_init(plat_my_core_pos()); } /****************************************************************************** * Marvell common helper to save SPI irq states in GICv3 ****************************************************************************** */ void plat_marvell_gic_irq_save(void) { /* * If an ITS is available, save its context before * the Redistributor using: * gicv3_its_save_disable(gits_base, &its_ctx[i]) * Additionally, an implementation-defined sequence may * be required to save the whole ITS state. */ /* * Save the GIC Redistributors and ITS contexts before the * Distributor context. As we only handle SYSTEM SUSPEND API, * we only need to save the context of the CPU that is issuing * the SYSTEM SUSPEND call, i.e. the current CPU. */ gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx); /* Save the GIC Distributor context */ gicv3_distif_save(&dist_ctx); /* * From here, all the components of the GIC can be safely powered down * as long as there is an alternate way to handle wakeup interrupt * sources. */ } /****************************************************************************** * Marvell common helper to restore SPI irq states in GICv3 ****************************************************************************** */ void plat_marvell_gic_irq_restore(void) { /* Restore the GIC Distributor context */ gicv3_distif_init_restore(&dist_ctx); /* * Restore the GIC Redistributor and ITS contexts after the * Distributor context. As we only handle SYSTEM SUSPEND API, * we only need to restore the context of the CPU that issued * the SYSTEM SUSPEND call. */ gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx); /* * If an ITS is available, restore its context after * the Redistributor using: * gicv3_its_restore(gits_base, &its_ctx[i]) * An implementation-defined sequence may be required to * restore the whole ITS state. The ITS must also be * re-enabled after this sequence has been executed. */ } /****************************************************************************** * Marvell common helper to save per-cpu PPI irq states in GICv3 ****************************************************************************** */ void plat_marvell_gic_irq_pcpu_save(void) { gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx); } /****************************************************************************** * Marvell common helper to restore per-cpu PPI irq states in GICv3 ****************************************************************************** */ void plat_marvell_gic_irq_pcpu_restore(void) { gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx); } trusted-firmware-a-2.2/plat/marvell/common/marvell_image_load.c000066400000000000000000000023111355360272700247470ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /******************************************************************************* * This function flushes the data structures so that they are visible * in memory for the next BL image. ******************************************************************************/ void plat_flush_next_bl_params(void) { flush_bl_params_desc(); } /******************************************************************************* * This function returns the list of loadable images. ******************************************************************************/ bl_load_info_t *plat_get_bl_image_load_info(void) { return get_bl_load_info_from_mem_params_desc(); } /******************************************************************************* * This function returns the list of executable images. ******************************************************************************/ bl_params_t *plat_get_next_bl_params(void) { return get_next_bl_params_from_mem_params_desc(); } trusted-firmware-a-2.2/plat/marvell/common/marvell_io_storage.c000066400000000000000000000111161355360272700250240ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #include #include #include /* IO devices */ static const io_dev_connector_t *fip_dev_con; static uintptr_t fip_dev_handle; static const io_dev_connector_t *memmap_dev_con; static uintptr_t memmap_dev_handle; static const io_block_spec_t fip_block_spec = { .offset = PLAT_MARVELL_FIP_BASE, .length = PLAT_MARVELL_FIP_MAX_SIZE }; static const io_uuid_spec_t bl2_uuid_spec = { .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2, }; static const io_uuid_spec_t scp_bl2_uuid_spec = { .uuid = UUID_SCP_FIRMWARE_SCP_BL2, }; static const io_uuid_spec_t bl31_uuid_spec = { .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31, }; static const io_uuid_spec_t bl32_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32, }; static const io_uuid_spec_t bl33_uuid_spec = { .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33, }; static int open_fip(const uintptr_t spec); static int open_memmap(const uintptr_t spec); struct plat_io_policy { uintptr_t *dev_handle; uintptr_t image_spec; int (*check)(const uintptr_t spec); }; /* By default, Marvell platforms load images from the FIP */ static const struct plat_io_policy policies[] = { [FIP_IMAGE_ID] = { &memmap_dev_handle, (uintptr_t)&fip_block_spec, open_memmap }, [BL2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl2_uuid_spec, open_fip }, [SCP_BL2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&scp_bl2_uuid_spec, open_fip }, [BL31_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl31_uuid_spec, open_fip }, [BL32_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_uuid_spec, open_fip }, [BL33_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl33_uuid_spec, open_fip }, }; /* Weak definitions may be overridden in specific ARM standard platform */ #pragma weak plat_marvell_io_setup #pragma weak plat_marvell_get_alt_image_source static int open_fip(const uintptr_t spec) { int result; uintptr_t local_image_handle; /* See if a Firmware Image Package is available */ result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); if (result == 0) { result = io_open(fip_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using FIP\n"); io_close(local_image_handle); } } return result; } static int open_memmap(const uintptr_t spec) { int result; uintptr_t local_image_handle; result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL); if (result == 0) { result = io_open(memmap_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using Memmap\n"); io_close(local_image_handle); } } return result; } void marvell_io_setup(void) { int io_result; io_result = register_io_dev_fip(&fip_dev_con); assert(io_result == 0); io_result = register_io_dev_memmap(&memmap_dev_con); assert(io_result == 0); /* Open connections to devices and cache the handles */ io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle); assert(io_result == 0); io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL, &memmap_dev_handle); assert(io_result == 0); /* Ignore improbable errors in release builds */ (void)io_result; } void plat_marvell_io_setup(void) { marvell_io_setup(); } int plat_marvell_get_alt_image_source( unsigned int image_id __attribute__((unused)), uintptr_t *dev_handle __attribute__((unused)), uintptr_t *image_spec __attribute__((unused))) { /* By default do not try an alternative */ return -ENOENT; } /* * 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 result; const struct plat_io_policy *policy; assert(image_id < ARRAY_SIZE(policies)); policy = &policies[image_id]; result = policy->check(policy->image_spec); if (result == 0) { *image_spec = policy->image_spec; *dev_handle = *(policy->dev_handle); } else { VERBOSE("Trying alternative IO\n"); result = plat_marvell_get_alt_image_source(image_id, dev_handle, image_spec); } return result; } /* * See if a Firmware Image Package is available, * by checking if TOC is valid or not. */ int marvell_io_is_toc_valid(void) { int result; result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); return result == 0; } trusted-firmware-a-2.2/plat/marvell/common/marvell_pm.c000066400000000000000000000035241355360272700233110ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include /* Standard ARM platforms are expected to export plat_arm_psci_pm_ops */ extern const plat_psci_ops_t plat_arm_psci_pm_ops; /***************************************************************************** * Private function to program the mailbox for a cpu before it is released * from reset. This function assumes that the mail box base is within * the MARVELL_SHARED_RAM region ***************************************************************************** */ void marvell_program_mailbox(uintptr_t address) { uintptr_t *mailbox = (void *)PLAT_MARVELL_MAILBOX_BASE; /* * Ensure that the PLAT_MARVELL_MAILBOX_BASE is within * MARVELL_SHARED_RAM region. */ assert((PLAT_MARVELL_MAILBOX_BASE >= MARVELL_SHARED_RAM_BASE) && ((PLAT_MARVELL_MAILBOX_BASE + sizeof(*mailbox)) <= (MARVELL_SHARED_RAM_BASE + MARVELL_SHARED_RAM_SIZE))); mailbox[MBOX_IDX_MAGIC] = MVEBU_MAILBOX_MAGIC_NUM; mailbox[MBOX_IDX_SEC_ADDR] = address; /* Flush data cache if the mail box shared RAM is cached */ #if PLAT_MARVELL_SHARED_RAM_CACHED flush_dcache_range((uintptr_t)PLAT_MARVELL_MAILBOX_BASE + 8 * MBOX_IDX_MAGIC, 2 * sizeof(uint64_t)); #endif } /***************************************************************************** * The ARM Standard platform definition of platform porting API * `plat_setup_psci_ops`. ***************************************************************************** */ int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { *psci_ops = &plat_arm_psci_pm_ops; /* Setup mailbox with entry point. */ marvell_program_mailbox(sec_entrypoint); return 0; } trusted-firmware-a-2.2/plat/marvell/common/marvell_topology.c000066400000000000000000000051151355360272700245470ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include /* The power domain tree descriptor */ unsigned char marvell_power_domain_tree_desc[PLAT_MARVELL_CLUSTER_COUNT + 1]; /***************************************************************************** * This function dynamically constructs the topology according to * PLAT_MARVELL_CLUSTER_COUNT and returns it. ***************************************************************************** */ const unsigned char *plat_get_power_domain_tree_desc(void) { int i; /* * The power domain tree does not have a single system level power * domain i.e. a single root node. The first entry in the power domain * descriptor specifies the number of power domains at the highest power * level. * For Marvell Platform this is the number of cluster power domains. */ marvell_power_domain_tree_desc[0] = PLAT_MARVELL_CLUSTER_COUNT; for (i = 0; i < PLAT_MARVELL_CLUSTER_COUNT; i++) marvell_power_domain_tree_desc[i + 1] = PLAT_MARVELL_CLUSTER_CORE_COUNT; return marvell_power_domain_tree_desc; } /***************************************************************************** * This function validates an MPIDR by checking whether it falls within the * acceptable bounds. An error code (-1) is returned if an incorrect mpidr * is passed. ***************************************************************************** */ int marvell_check_mpidr(u_register_t mpidr) { unsigned int nb_id, cluster_id, cpu_id; mpidr &= MPIDR_AFFINITY_MASK; if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK | MPIDR_AFFLVL_MASK << MPIDR_AFF2_SHIFT)) return -1; /* Get north bridge ID */ nb_id = MPIDR_AFFLVL3_VAL(mpidr); cluster_id = MPIDR_AFFLVL1_VAL(mpidr); cpu_id = MPIDR_AFFLVL0_VAL(mpidr); if (nb_id >= PLAT_MARVELL_CLUSTER_COUNT) return -1; if (cluster_id >= PLAT_MARVELL_CLUSTER_COUNT) return -1; if (cpu_id >= PLAT_MARVELL_CLUSTER_CORE_COUNT) return -1; return 0; } /***************************************************************************** * This function implements a part of the critical interface between the PSCI * generic layer and the platform that allows the former to query the platform * to convert an MPIDR to a unique linear index. An error code (-1) is returned * in case the MPIDR is invalid. ***************************************************************************** */ int plat_core_pos_by_mpidr(u_register_t mpidr) { if (marvell_check_mpidr(mpidr) == -1) return -1; return plat_marvell_calc_core_pos(mpidr); } trusted-firmware-a-2.2/plat/marvell/common/mrvl_sip_svc.c000066400000000000000000000073061355360272700236630ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #include "comphy/phy-comphy-cp110.h" #include /* #define DEBUG_COMPHY */ #ifdef DEBUG_COMPHY #define debug(format...) NOTICE(format) #else #define debug(format, arg...) #endif /* Comphy related FID's */ #define MV_SIP_COMPHY_POWER_ON 0x82000001 #define MV_SIP_COMPHY_POWER_OFF 0x82000002 #define MV_SIP_COMPHY_PLL_LOCK 0x82000003 #define MV_SIP_COMPHY_XFI_TRAIN 0x82000004 #define MV_SIP_COMPHY_DIG_RESET 0x82000005 /* Miscellaneous FID's' */ #define MV_SIP_DRAM_SIZE 0x82000010 #define MV_SIP_LLC_ENABLE 0x82000011 #define MV_SIP_PMU_IRQ_ENABLE 0x82000012 #define MV_SIP_PMU_IRQ_DISABLE 0x82000013 #define MAX_LANE_NR 6 #define MVEBU_COMPHY_OFFSET 0x441000 #define MVEBU_CP_BASE_MASK (~0xffffff) /* This macro is used to identify COMPHY related calls from SMC function ID */ #define is_comphy_fid(fid) \ ((fid) >= MV_SIP_COMPHY_POWER_ON && (fid) <= MV_SIP_COMPHY_DIG_RESET) _Bool is_cp_range_valid(u_register_t *addr) { int cp_nr; *addr &= MVEBU_CP_BASE_MASK; for (cp_nr = 0; cp_nr < CP_NUM; cp_nr++) { if (*addr == MVEBU_CP_REGS_BASE(cp_nr)) return true; } return false; } uintptr_t mrvl_sip_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) { u_register_t ret; int i; debug("%s: got SMC (0x%x) x1 0x%lx, x2 0x%lx, x3 0x%lx\n", __func__, smc_fid, x1, x2, x3); if (is_comphy_fid(smc_fid)) { /* validate address passed via x1 */ if (!is_cp_range_valid(&x1)) { ERROR("%s: Wrong smc (0x%x) address: %lx\n", __func__, smc_fid, x1); SMC_RET1(handle, SMC_UNK); } x1 += MVEBU_COMPHY_OFFSET; if (x2 >= MAX_LANE_NR) { ERROR("%s: Wrong smc (0x%x) lane nr: %lx\n", __func__, smc_fid, x2); SMC_RET1(handle, SMC_UNK); } } switch (smc_fid) { /* Comphy related FID's */ case MV_SIP_COMPHY_POWER_ON: /* x1: comphy_base, x2: comphy_index, x3: comphy_mode */ ret = mvebu_cp110_comphy_power_on(x1, x2, x3); SMC_RET1(handle, ret); case MV_SIP_COMPHY_POWER_OFF: /* x1: comphy_base, x2: comphy_index */ ret = mvebu_cp110_comphy_power_off(x1, x2, x3); SMC_RET1(handle, ret); case MV_SIP_COMPHY_PLL_LOCK: /* x1: comphy_base, x2: comphy_index */ ret = mvebu_cp110_comphy_is_pll_locked(x1, x2); SMC_RET1(handle, ret); case MV_SIP_COMPHY_XFI_TRAIN: /* x1: comphy_base, x2: comphy_index */ ret = mvebu_cp110_comphy_xfi_rx_training(x1, x2); SMC_RET1(handle, ret); case MV_SIP_COMPHY_DIG_RESET: /* x1: comphy_base, x2: comphy_index, x3: mode, x4: command */ ret = mvebu_cp110_comphy_digital_reset(x1, x2, x3, x4); SMC_RET1(handle, ret); /* Miscellaneous FID's' */ case MV_SIP_DRAM_SIZE: ret = mvebu_get_dram_size(MVEBU_REGS_BASE); SMC_RET1(handle, ret); case MV_SIP_LLC_ENABLE: for (i = 0; i < ap_get_count(); i++) llc_runtime_enable(i); SMC_RET1(handle, 0); #ifdef MVEBU_PMU_IRQ_WA case MV_SIP_PMU_IRQ_ENABLE: mvebu_pmu_interrupt_enable(); SMC_RET1(handle, 0); case MV_SIP_PMU_IRQ_DISABLE: mvebu_pmu_interrupt_disable(); SMC_RET1(handle, 0); #endif default: ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); SMC_RET1(handle, SMC_UNK); } } /* Define a runtime service descriptor for fast SMC calls */ DECLARE_RT_SVC( marvell_sip_svc, OEN_SIP_START, OEN_SIP_END, SMC_TYPE_FAST, NULL, mrvl_sip_smc_handler ); trusted-firmware-a-2.2/plat/marvell/common/mss/000077500000000000000000000000001355360272700216055ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/marvell/common/mss/mss_common.mk000066400000000000000000000010161355360272700243060ustar00rootroot00000000000000# # Copyright (C) 2018 Marvell International Ltd. # # SPDX-License-Identifier: BSD-3-Clause # https://spdx.org/licenses # PLAT_MARVELL := plat/marvell MSS_SOURCE := $(PLAT_MARVELL)/common/mss BL2_SOURCES += $(MSS_SOURCE)/mss_scp_bootloader.c \ $(PLAT_MARVELL)/common/plat_delay_timer.c \ drivers/delay_timer/delay_timer.c \ $(MARVELL_DRV) \ $(PLAT_FAMILY_BASE)/$(PLAT)/board/marvell_plat_config.c BL31_SOURCES += $(MSS_SOURCE)/mss_ipc_drv.c PLAT_INCLUDES += -I$(MSS_SOURCE) trusted-firmware-a-2.2/plat/marvell/common/mss/mss_ipc_drv.c000066400000000000000000000061041355360272700242620ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #define IPC_MSG_BASE_MASK MVEBU_REGS_BASE_MASK #define IPC_CH_NUM_OF_MSG (16) #define IPC_CH_MSG_IDX (-1) unsigned long mv_pm_ipc_msg_base; unsigned int mv_pm_ipc_queue_size; unsigned int msg_sync; int msg_index = IPC_CH_MSG_IDX; /****************************************************************************** * mss_pm_ipc_init * * DESCRIPTION: Initialize PM IPC infrastructure ****************************************************************************** */ int mv_pm_ipc_init(unsigned long ipc_control_addr) { struct mss_pm_ipc_ctrl *ipc_control = (struct mss_pm_ipc_ctrl *)ipc_control_addr; /* Initialize PM IPC control block */ mv_pm_ipc_msg_base = ipc_control->msg_base_address | IPC_MSG_BASE_MASK; mv_pm_ipc_queue_size = ipc_control->queue_size; return 0; } /****************************************************************************** * mv_pm_ipc_queue_addr_get * * DESCRIPTION: Returns the IPC queue address ****************************************************************************** */ unsigned int mv_pm_ipc_queue_addr_get(void) { unsigned int addr; inv_dcache_range((uint64_t)&msg_index, sizeof(msg_index)); msg_index = msg_index + 1; if (msg_index >= IPC_CH_NUM_OF_MSG) msg_index = 0; addr = (unsigned int)(mv_pm_ipc_msg_base + (msg_index * mv_pm_ipc_queue_size)); flush_dcache_range((uint64_t)&msg_index, sizeof(msg_index)); return addr; } /****************************************************************************** * mv_pm_ipc_msg_rx * * DESCRIPTION: Retrieve message from IPC channel ****************************************************************************** */ int mv_pm_ipc_msg_rx(unsigned int channel_id, struct mss_pm_ipc_msg *msg) { unsigned int addr = mv_pm_ipc_queue_addr_get(); msg->msg_reply = mmio_read_32(addr + IPC_MSG_REPLY_LOC); return 0; } /****************************************************************************** * mv_pm_ipc_msg_tx * * DESCRIPTION: Send message via IPC channel ****************************************************************************** */ int mv_pm_ipc_msg_tx(unsigned int channel_id, unsigned int msg_id, unsigned int cluster_power_state) { unsigned int addr = mv_pm_ipc_queue_addr_get(); /* Validate the entry for message placed by the host is free */ if (mmio_read_32(addr + IPC_MSG_STATE_LOC) == IPC_MSG_FREE) { inv_dcache_range((uint64_t)&msg_sync, sizeof(msg_sync)); msg_sync = msg_sync + 1; flush_dcache_range((uint64_t)&msg_sync, sizeof(msg_sync)); mmio_write_32(addr + IPC_MSG_SYNC_ID_LOC, msg_sync); mmio_write_32(addr + IPC_MSG_ID_LOC, msg_id); mmio_write_32(addr + IPC_MSG_CPU_ID_LOC, channel_id); mmio_write_32(addr + IPC_MSG_POWER_STATE_LOC, cluster_power_state); mmio_write_32(addr + IPC_MSG_STATE_LOC, IPC_MSG_OCCUPY); } else { ERROR("%s: FAILED\n", __func__); } return 0; } trusted-firmware-a-2.2/plat/marvell/common/mss/mss_ipc_drv.h000066400000000000000000000061011355360272700242640ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MSS_IPC_DRV_H #define MSS_IPC_DRV_H #include #define MV_PM_FW_IPC_VERSION_MAGIC (0xCA530000) /* Do NOT change */ /* Increament for each version */ #define MV_PM_FW_IPC_VERSION_SEQ (0x00000001) #define MV_PM_FW_IPC_VERSION (MV_PM_FW_IPC_VERSION_MAGIC | \ MV_PM_FW_IPC_VERSION_SEQ) #define IPC_MSG_STATE_LOC (0x0) #define IPC_MSG_SYNC_ID_LOC (0x4) #define IPC_MSG_ID_LOC (0x8) #define IPC_MSG_RET_CH_ID_LOC (0xC) #define IPC_MSG_CPU_ID_LOC (0x10) #define IPC_MSG_CLUSTER_ID_LOC (0x14) #define IPC_MSG_SYSTEM_ID_LOC (0x18) #define IPC_MSG_POWER_STATE_LOC (0x1C) #define IPC_MSG_REPLY_LOC (0x20) #define IPC_MSG_RESERVED_LOC (0x24) /* IPC initialization state */ enum mss_pm_ipc_init_state { IPC_UN_INITIALIZED = 1, IPC_INITIALIZED = 2 }; /* IPC queue direction */ enum mss_pm_ipc_init_msg_dir { IPC_MSG_TX = 0, IPC_MSG_RX = 1 }; /* IPC message state */ enum mss_pm_ipc_msg_state { IPC_MSG_FREE = 1, IPC_MSG_OCCUPY = 2 }; /* IPC control block */ struct mss_pm_ipc_ctrl { unsigned int ctrl_base_address; unsigned int msg_base_address; unsigned int num_of_channels; unsigned int channel_size; unsigned int queue_size; }; /* IPC message types */ enum mss_pm_msg_id { PM_IPC_MSG_CPU_SUSPEND = 1, PM_IPC_MSG_CPU_OFF = 2, PM_IPC_MSG_CPU_ON = 3, PM_IPC_MSG_SYSTEM_RESET = 4, PM_IPC_MSG_SYSTEM_SUSPEND = 5, PM_IPC_MAX_MSG }; struct mss_pm_ipc_msg { unsigned int msg_sync_id; /* * Sync number, validate message * reply corresponding to message * received */ unsigned int msg_id; /* Message Id */ unsigned int ret_channel_id; /* IPC channel reply */ unsigned int cpu_id; /* CPU Id */ unsigned int cluster_id; /* Cluster Id */ unsigned int system_id; /* System Id */ unsigned int power_state; unsigned int msg_reply; /* Message reply */ }; /* IPC queue */ struct mss_pm_ipc_queue { unsigned int state; struct mss_pm_ipc_msg msg; }; /* IPC channel */ struct mss_pm_ipc_ch { struct mss_pm_ipc_queue *tx_queue; struct mss_pm_ipc_queue *rx_queue; }; /***************************************************************************** * mv_pm_ipc_init * * DESCRIPTION: Initialize PM IPC infrastructure ***************************************************************************** */ int mv_pm_ipc_init(unsigned long ipc_control_addr); /***************************************************************************** * mv_pm_ipc_msg_rx * * DESCRIPTION: Retrieve message from IPC channel ***************************************************************************** */ int mv_pm_ipc_msg_rx(unsigned int channel_id, struct mss_pm_ipc_msg *msg); /***************************************************************************** * mv_pm_ipc_msg_tx * * DESCRIPTION: Send message via IPC channel ***************************************************************************** */ int mv_pm_ipc_msg_tx(unsigned int channel_id, unsigned int msg_id, unsigned int cluster_power_state); #endif /* MSS_IPC_DRV_H */ trusted-firmware-a-2.2/plat/marvell/common/mss/mss_mem.h000066400000000000000000000026561355360272700234270ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MSS_MEM_H #define MSS_MEM_H /* MSS SRAM Memory base */ #define MSS_SRAM_PM_CONTROL_BASE (MVEBU_REGS_BASE + 0x520000) enum mss_pm_ctrl_handshake { MSS_UN_INITIALIZED = 0, MSS_COMPATIBILITY_ERROR = 1, MSS_ACKNOWLEDGMENT = 2, HOST_ACKNOWLEDGMENT = 3 }; enum mss_pm_ctrl_rtos_env { MSS_MULTI_PROCESS_ENV = 0, MSS_SINGLE_PROCESS_ENV = 1, MSS_MAX_PROCESS_ENV }; struct mss_pm_ctrl_block { /* This field is used to synchronize the Host * and MSS initialization sequence * Valid Values * 0 - Un-Initialized * 1 - Compatibility Error * 2 - MSS Acknowledgment * 3 - Host Acknowledgment */ unsigned int handshake; /* * This field include Host IPC version. Once received by the MSS * It will be compared to MSS IPC version and set MSS Acknowledge to * "compatibility error" in case there is no match */ unsigned int ipc_version; unsigned int ipc_base_address; unsigned int ipc_state; /* Following fields defines firmware core architecture */ unsigned int num_of_cores; unsigned int num_of_clusters; unsigned int num_of_cores_per_cluster; /* Following fields define pm trace debug base address */ unsigned int pm_trace_ctrl_base_address; unsigned int pm_trace_info_base_address; unsigned int pm_trace_info_core_size; unsigned int ctrl_blk_size; }; #endif /* MSS_MEM_H */ trusted-firmware-a-2.2/plat/marvell/common/mss/mss_scp_bl2_format.h000066400000000000000000000016521355360272700255400ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MSS_SCP_BL2_FORMAT_H #define MSS_SCP_BL2_FORMAT_H #define MAX_NR_OF_FILES 5 #define FILE_MAGIC 0xddd01ff #define HEADER_VERSION 0x1 #define MSS_IDRAM_SIZE 0x10000 /* 64KB */ #define MG_SRAM_SIZE 0x20000 /* 128KB */ /* Types definitions */ typedef struct file_header { /* Magic specific for concatenated file (used for validation) */ uint32_t magic; uint32_t nr_of_imgs; /* Number of images concatenated */ } file_header_t; /* Types definitions */ enum cm3_t { MSS_AP, MSS_CP0, MSS_CP1, MSS_CP2, MSS_CP3, MG_CP0, MG_CP1, }; typedef struct img_header { uint32_t type; /* CM3 type, can be one of cm3_t */ uint32_t length; /* Image length */ uint32_t version; /* For sanity checks and future * extended functionality */ } img_header_t; #endif /* MSS_SCP_BL2_FORMAT_H */ trusted-firmware-a-2.2/plat/marvell/common/mss/mss_scp_bootloader.c000066400000000000000000000207221355360272700256350ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #include #include #include #include #define MSS_DMA_SRCBR(base) (base + 0xC0) #define MSS_DMA_DSTBR(base) (base + 0xC4) #define MSS_DMA_CTRLR(base) (base + 0xC8) #define MSS_M3_RSTCR(base) (base + 0xFC) #define MSS_DMA_CTRLR_SIZE_OFFSET (0) #define MSS_DMA_CTRLR_REQ_OFFSET (15) #define MSS_DMA_CTRLR_REQ_SET (1) #define MSS_DMA_CTRLR_ACK_OFFSET (12) #define MSS_DMA_CTRLR_ACK_MASK (0x1) #define MSS_DMA_CTRLR_ACK_READY (1) #define MSS_M3_RSTCR_RST_OFFSET (0) #define MSS_M3_RSTCR_RST_OFF (1) #define MSS_DMA_TIMEOUT 1000 #define MSS_EXTERNAL_SPACE 0x50000000 #define MSS_EXTERNAL_ADDR_MASK 0xfffffff #define DMA_SIZE 128 #define MSS_HANDSHAKE_TIMEOUT 50 static int mss_check_image_ready(volatile struct mss_pm_ctrl_block *mss_pm_crtl) { int timeout = MSS_HANDSHAKE_TIMEOUT; /* Wait for SCP to signal it's ready */ while ((mss_pm_crtl->handshake != MSS_ACKNOWLEDGMENT) && (timeout-- > 0)) mdelay(1); if (mss_pm_crtl->handshake != MSS_ACKNOWLEDGMENT) return -1; mss_pm_crtl->handshake = HOST_ACKNOWLEDGMENT; return 0; } static int mss_image_load(uint32_t src_addr, uint32_t size, uintptr_t mss_regs) { uint32_t i, loop_num, timeout; /* Check if the img size is not bigger than ID-RAM size of MSS CM3 */ if (size > MSS_IDRAM_SIZE) { ERROR("image is too big to fit into MSS CM3 memory\n"); return 1; } NOTICE("Loading MSS image from addr. 0x%x Size 0x%x to MSS at 0x%lx\n", src_addr, size, mss_regs); /* load image to MSS RAM using DMA */ loop_num = (size / DMA_SIZE) + (((size & (DMA_SIZE - 1)) == 0) ? 0 : 1); for (i = 0; i < loop_num; i++) { /* write destination and source addresses */ mmio_write_32(MSS_DMA_SRCBR(mss_regs), MSS_EXTERNAL_SPACE | ((src_addr & MSS_EXTERNAL_ADDR_MASK) + (i * DMA_SIZE))); mmio_write_32(MSS_DMA_DSTBR(mss_regs), (i * DMA_SIZE)); dsb(); /* make sure DMA data is ready before triggering it */ /* set the DMA control register */ mmio_write_32(MSS_DMA_CTRLR(mss_regs), ((MSS_DMA_CTRLR_REQ_SET << MSS_DMA_CTRLR_REQ_OFFSET) | (DMA_SIZE << MSS_DMA_CTRLR_SIZE_OFFSET))); /* Poll DMA_ACK at MSS_DMACTLR until it is ready */ timeout = MSS_DMA_TIMEOUT; while (timeout) { if ((mmio_read_32(MSS_DMA_CTRLR(mss_regs)) >> MSS_DMA_CTRLR_ACK_OFFSET & MSS_DMA_CTRLR_ACK_MASK) == MSS_DMA_CTRLR_ACK_READY) { break; } udelay(50); timeout--; } if (timeout == 0) { ERROR("\nDMA failed to load MSS image\n"); return 1; } } bl2_plat_configure_mss_windows(mss_regs); /* Release M3 from reset */ mmio_write_32(MSS_M3_RSTCR(mss_regs), (MSS_M3_RSTCR_RST_OFF << MSS_M3_RSTCR_RST_OFFSET)); NOTICE("Done\n"); return 0; } /* Load image to MSS AP and do PM related initialization * Note that this routine is different than other CM3 loading routines, because * firmware for AP is dedicated for PM and therefore some additional PM * initialization is required */ static int mss_ap_load_image(uintptr_t single_img, uint32_t image_size, uint32_t ap_idx) { volatile struct mss_pm_ctrl_block *mss_pm_crtl; int ret; /* TODO: add PM Control Info from platform */ mss_pm_crtl = (struct mss_pm_ctrl_block *)MSS_SRAM_PM_CONTROL_BASE; mss_pm_crtl->ipc_version = MV_PM_FW_IPC_VERSION; mss_pm_crtl->num_of_clusters = PLAT_MARVELL_CLUSTER_COUNT; mss_pm_crtl->num_of_cores_per_cluster = PLAT_MARVELL_CLUSTER_CORE_COUNT; mss_pm_crtl->num_of_cores = PLAT_MARVELL_CLUSTER_COUNT * PLAT_MARVELL_CLUSTER_CORE_COUNT; mss_pm_crtl->pm_trace_ctrl_base_address = AP_MSS_ATF_CORE_CTRL_BASE; mss_pm_crtl->pm_trace_info_base_address = AP_MSS_ATF_CORE_INFO_BASE; mss_pm_crtl->pm_trace_info_core_size = AP_MSS_ATF_CORE_INFO_SIZE; VERBOSE("MSS Control Block = 0x%x\n", MSS_SRAM_PM_CONTROL_BASE); VERBOSE("mss_pm_crtl->ipc_version = 0x%x\n", mss_pm_crtl->ipc_version); VERBOSE("mss_pm_crtl->num_of_cores = 0x%x\n", mss_pm_crtl->num_of_cores); VERBOSE("mss_pm_crtl->num_of_clusters = 0x%x\n", mss_pm_crtl->num_of_clusters); VERBOSE("mss_pm_crtl->num_of_cores_per_cluster = 0x%x\n", mss_pm_crtl->num_of_cores_per_cluster); VERBOSE("mss_pm_crtl->pm_trace_ctrl_base_address = 0x%x\n", mss_pm_crtl->pm_trace_ctrl_base_address); VERBOSE("mss_pm_crtl->pm_trace_info_base_address = 0x%x\n", mss_pm_crtl->pm_trace_info_base_address); VERBOSE("mss_pm_crtl->pm_trace_info_core_size = 0x%x\n", mss_pm_crtl->pm_trace_info_core_size); /* TODO: add checksum to image */ VERBOSE("Send info about the SCP_BL2 image to be transferred to SCP\n"); ret = mss_image_load(single_img, image_size, bl2_plat_get_ap_mss_regs(ap_idx)); if (ret != 0) { ERROR("SCP Image load failed\n"); return -1; } /* check that the image was loaded successfully */ ret = mss_check_image_ready(mss_pm_crtl); if (ret != 0) NOTICE("SCP Image doesn't contain PM firmware\n"); return 0; } /* Load CM3 image (single_img) to CM3 pointed by cm3_type */ static int load_img_to_cm3(enum cm3_t cm3_type, uintptr_t single_img, uint32_t image_size) { int ret, ap_idx, cp_index; uint32_t ap_count = bl2_plat_get_ap_count(); switch (cm3_type) { case MSS_AP: for (ap_idx = 0; ap_idx < ap_count; ap_idx++) { NOTICE("Load image to AP%d MSS\n", ap_idx); ret = mss_ap_load_image(single_img, image_size, ap_idx); if (ret != 0) return ret; } break; case MSS_CP0: case MSS_CP1: case MSS_CP2: case MSS_CP3: /* MSS_AP = 0 * MSS_CP1 = 1 * . * . * MSS_CP3 = 4 * Actual CP index is MSS_CPX - 1 */ cp_index = cm3_type - 1; for (ap_idx = 0; ap_idx < ap_count; ap_idx++) { /* Check if we should load this image * according to number of CPs */ if (bl2_plat_get_cp_count(ap_idx) <= cp_index) { NOTICE("Skipping MSS CP%d related image\n", cp_index); break; } NOTICE("Load image to CP%d MSS AP%d\n", cp_index, ap_idx); ret = mss_image_load(single_img, image_size, bl2_plat_get_cp_mss_regs( ap_idx, cp_index)); if (ret != 0) { ERROR("SCP Image load failed\n"); return -1; } } break; case MG_CP0: /* TODO: */ NOTICE("Load image to CP0 MG not supported\n"); break; case MG_CP1: /* TODO: */ NOTICE("Load image to CP1 MG not supported\n"); break; default: ERROR("SCP_BL2 wrong img format (cm3_type=%d)\n", cm3_type); break; } return 0; } /* The Armada 8K has 5 service CPUs and Armada 7K has 3. Therefore it was * required to provide a method for loading firmware to all of the service CPUs. * To achieve that, the scp_bl2 image in fact is file containing up to 5 * concatenated firmwares and this routine splits concatenated image into single * images dedicated for appropriate service CPU and then load them. */ static int split_and_load_bl2_image(void *image) { file_header_t *file_hdr; img_header_t *img_hdr; uintptr_t single_img; int i; file_hdr = (file_header_t *)image; if (file_hdr->magic != FILE_MAGIC) { ERROR("SCP_BL2 wrong img format\n"); return -1; } if (file_hdr->nr_of_imgs > MAX_NR_OF_FILES) { ERROR("SCP_BL2 concatenated image contains to many images\n"); return -1; } img_hdr = (img_header_t *)((uintptr_t)image + sizeof(file_header_t)); single_img = (uintptr_t)image + sizeof(file_header_t) + sizeof(img_header_t) * file_hdr->nr_of_imgs; NOTICE("SCP_BL2 contains %d concatenated images\n", file_hdr->nr_of_imgs); for (i = 0; i < file_hdr->nr_of_imgs; i++) { /* Before loading make sanity check on header */ if (img_hdr->version != HEADER_VERSION) { ERROR("Wrong header, img corrupted exiting\n"); return -1; } load_img_to_cm3(img_hdr->type, single_img, img_hdr->length); /* Prepare offsets for next run */ single_img += img_hdr->length; img_hdr++; } return 0; } int scp_bootloader_transfer(void *image, unsigned int image_size) { #ifdef SCP_BL2_BASE assert((uintptr_t) image == SCP_BL2_BASE); #endif VERBOSE("Concatenated img size %d\n", image_size); if (image_size == 0) { ERROR("SCP_BL2 image size can't be 0 (current size = 0x%x)\n", image_size); return -1; } if (split_and_load_bl2_image(image)) return -1; return 0; } trusted-firmware-a-2.2/plat/marvell/common/mss/mss_scp_bootloader.h000066400000000000000000000011101355360272700256300ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #ifndef MSS_SCP_BOOTLOADER_H #define MSS_SCP_BOOTLOADER_H int scp_bootloader_transfer(void *image, unsigned int image_size); uintptr_t bl2_plat_get_cp_mss_regs(int ap_idx, int cp_idx); uintptr_t bl2_plat_get_ap_mss_regs(int ap_idx); uint32_t bl2_plat_get_cp_count(int ap_idx); uint32_t bl2_plat_get_ap_count(void); void bl2_plat_configure_mss_windows(uintptr_t mss_regs); int bl2_plat_mss_check_image_ready(void); #endif /* MSS_SCP_BOOTLOADER_H */ trusted-firmware-a-2.2/plat/marvell/common/plat_delay_timer.c000066400000000000000000000014171355360272700244700ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #define SYS_COUNTER_FREQ_IN_MHZ (COUNTER_FREQUENCY/1000000) static uint32_t plat_get_timer_value(void) { /* * Generic delay timer implementation expects the timer to be a down * counter. We apply bitwise NOT operator to the tick values returned * by read_cntpct_el0() to simulate the down counter. */ return (uint32_t)(~read_cntpct_el0()); } static const timer_ops_t plat_timer_ops = { .get_timer_value = plat_get_timer_value, .clk_mult = 1, .clk_div = SYS_COUNTER_FREQ_IN_MHZ }; void plat_delay_timer_init(void) { timer_init(&plat_timer_ops); } trusted-firmware-a-2.2/plat/marvell/marvell.mk000066400000000000000000000041001355360272700215010ustar00rootroot00000000000000# Copyright (C) 2018 Marvell International Ltd. # # SPDX-License-Identifier: BSD-3-Clause # https://spdx.org/licenses # Marvell images BOOT_IMAGE := boot-image.bin BOOT_ENC_IMAGE := boot-image-enc.bin FLASH_IMAGE := flash-image.bin # Make non-trusted image by default MARVELL_SECURE_BOOT := 0 $(eval $(call add_define,MARVELL_SECURE_BOOT)) # Enable compilation for Palladium emulation platform PALLADIUM := 0 $(eval $(call add_define,PALLADIUM)) ifeq (${MARVELL_SECURE_BOOT},1) DOIMAGE_SEC_FLAGS := -c $(DOIMAGE_SEC) DOIMAGE_LIBS_CHECK = \ if ! [ -d "/usr/include/mbedtls" ]; then \ echo "****************************************" >&2; \ echo "Missing mbedTLS installation! " >&2; \ echo "Please download it from \"tls.mbed.org\"" >&2; \ echo "Alternatively on Debian/Ubuntu system install" >&2; \ echo "\"libmbedtls-dev\" package" >&2; \ echo "Make sure to use version 2.1.0 or later" >&2; \ echo "****************************************" >&2; \ exit 1; \ else if ! [ -f "/usr/include/libconfig.h" ]; then \ echo "********************************************************" >&2; \ echo "Missing Libconfig installation!" >&2; \ echo "Please download it from \"www.hyperrealm.com/libconfig/\"" >&2; \ echo "Alternatively on Debian/Ubuntu system install packages" >&2; \ echo "\"libconfig8\" and \"libconfig8-dev\"" >&2; \ echo "********************************************************" >&2; \ exit 1; \ fi \ fi else #MARVELL_SECURE_BOOT DOIMAGE_LIBS_CHECK = DOIMAGE_SEC_FLAGS = endif #MARVELL_SECURE_BOOT mrvl_clean: @echo " Doimage CLEAN" ${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${DOIMAGEPATH} clean ${DOIMAGETOOL}: mrvl_clean @$(DOIMAGE_LIBS_CHECK) ${Q}${MAKE} --no-print-directory -C ${DOIMAGEPATH} VERSION=$(SUBVERSION) WTMI_IMG=$(WTMI_IMG) trusted-firmware-a-2.2/plat/marvell/version.mk000066400000000000000000000000331355360272700215250ustar00rootroot00000000000000SUBVERSION = devel-18.12.0 trusted-firmware-a-2.2/plat/mediatek/000077500000000000000000000000001355360272700176345ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/common/000077500000000000000000000000001355360272700211245ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/common/custom/000077500000000000000000000000001355360272700224365ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/common/custom/oem_svc.c000066400000000000000000000042641355360272700242430ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include /* OEM Service UUID */ DEFINE_SVC_UUID2(oem_svc_uid, 0xd0ad43b9, 0x9b06, 0xe411, 0x91, 0x91, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66); /* Setup OEM Services */ static int32_t oem_svc_setup(void) { /* * Invoke related module setup from here */ return 0; } /******************************************************************************* * OEM top level handler for servicing SMCs. ******************************************************************************/ uintptr_t oem_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) { WARN("Unimplemented OEM Call: 0x%x\n", smc_fid); SMC_RET1(handle, SMC_UNK); } /* * Top-level OEM Service SMC handler. This handler will in turn dispatch * calls to related SMC handler */ uintptr_t oem_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) { /* * Dispatch OEM calls to OEM Common handler and return its return value */ if (is_oem_fid(smc_fid)) { return oem_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); } switch (smc_fid) { case OEM_SVC_CALL_COUNT: /* * Return the number of OEM Service Calls. */ SMC_RET1(handle, OEM_SVC_NUM_CALLS); case OEM_SVC_UID: /* Return UID to the caller */ SMC_UUID_RET(handle, oem_svc_uid); case OEM_SVC_VERSION: /* Return the version of current implementation */ SMC_RET2(handle, OEM_VERSION_MAJOR, OEM_VERSION_MINOR); default: WARN("Unimplemented OEM Service Call: 0x%x\n", smc_fid); SMC_RET1(handle, SMC_UNK); } } /* Register OEM Service Calls as runtime service */ DECLARE_RT_SVC( oem_svc, OEN_OEM_START, OEN_OEM_END, SMC_TYPE_FAST, oem_svc_setup, oem_svc_smc_handler ); trusted-firmware-a-2.2/plat/mediatek/common/custom/oem_svc.h000066400000000000000000000026341355360272700242470ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef OEM_SVC_H #define OEM_SVC_H /******************************************************************************* * Defines for runtime services func ids ******************************************************************************/ /* * Number of OEM calls (above) implemented. */ #define OEM_SVC_NUM_CALLS 3 /******************************************************************************* * Defines for OEM Service queries ******************************************************************************/ /* 0x83000000 - 0x8300FEFF is OEM service calls */ #define OEM_SVC_CALL_COUNT 0x8300ff00 #define OEM_SVC_UID 0x8300ff01 /* 0x8300ff02 is reserved */ #define OEM_SVC_VERSION 0x8300ff03 /* 0x8300ff04 - 0x8300FFFF is reserved for future expansion */ /* OEM Service Calls version numbers */ #define OEM_VERSION_MAJOR 0x0 #define OEM_VERSION_MINOR 0x1 /* The macros below are used to identify OEM calls from the SMC function ID */ /* SMC32 ID range from 0x83000000 to 0x83000FFF */ /* SMC64 ID range from 0xC3000000 to 0xC3000FFF */ #define OEM_FID_MASK 0xf000u #define OEM_FID_VALUE 0u #define is_oem_fid(_fid) \ (((_fid) & OEM_FID_MASK) == OEM_FID_VALUE) #define OEM_SVC_E_SUCCESS 0 #define OEM_SVC_E_NOT_SUPPORTED -1 #define OEM_SVC_E_INVALID_PARAMS -2 #endif /* OEM_SVC_H */ trusted-firmware-a-2.2/plat/mediatek/common/drivers/000077500000000000000000000000001355360272700226025ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/common/drivers/pmic_wrap/000077500000000000000000000000001355360272700245635ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/common/drivers/pmic_wrap/pmic_wrap_init.c000066400000000000000000000075011355360272700277360ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* pmic wrap module wait_idle and read polling interval (in microseconds) */ enum { WAIT_IDLE_POLLING_DELAY_US = 1, READ_POLLING_DELAY_US = 2 }; static inline uint32_t wait_for_state_idle(uint32_t timeout_us, void *wacs_register, void *wacs_vldclr_register, uint32_t *read_reg) { uint32_t reg_rdata; uint32_t retry; retry = (timeout_us + WAIT_IDLE_POLLING_DELAY_US) / WAIT_IDLE_POLLING_DELAY_US; do { udelay(WAIT_IDLE_POLLING_DELAY_US); reg_rdata = mmio_read_32((uintptr_t)wacs_register); /* if last read command timeout,clear vldclr bit * read command state machine:FSM_REQ-->wfdle-->WFVLDCLR; * write:FSM_REQ-->idle */ switch (((reg_rdata >> RDATA_WACS_FSM_SHIFT) & RDATA_WACS_FSM_MASK)) { case WACS_FSM_WFVLDCLR: mmio_write_32((uintptr_t)wacs_vldclr_register, 1); ERROR("WACS_FSM = PMIC_WRAP_WACS_VLDCLR\n"); break; case WACS_FSM_WFDLE: ERROR("WACS_FSM = WACS_FSM_WFDLE\n"); break; case WACS_FSM_REQ: ERROR("WACS_FSM = WACS_FSM_REQ\n"); break; case WACS_FSM_IDLE: goto done; default: break; } retry--; } while (retry); done: if (!retry) /* timeout */ return E_PWR_WAIT_IDLE_TIMEOUT; if (read_reg) *read_reg = reg_rdata; return 0; } static inline uint32_t wait_for_state_ready(uint32_t timeout_us, void *wacs_register, uint32_t *read_reg) { uint32_t reg_rdata; uint32_t retry; retry = (timeout_us + READ_POLLING_DELAY_US) / READ_POLLING_DELAY_US; do { udelay(READ_POLLING_DELAY_US); reg_rdata = mmio_read_32((uintptr_t)wacs_register); if (((reg_rdata >> RDATA_WACS_FSM_SHIFT) & RDATA_WACS_FSM_MASK) == WACS_FSM_WFVLDCLR) break; retry--; } while (retry); if (!retry) { /* timeout */ ERROR("timeout when waiting for idle\n"); return E_PWR_WAIT_IDLE_TIMEOUT_READ; } if (read_reg) *read_reg = reg_rdata; return 0; } static int32_t pwrap_wacs2(uint32_t write, uint32_t adr, uint32_t wdata, uint32_t *rdata, uint32_t init_check) { uint32_t reg_rdata = 0; uint32_t wacs_write = 0; uint32_t wacs_adr = 0; uint32_t wacs_cmd = 0; uint32_t return_value = 0; if (init_check) { reg_rdata = mmio_read_32((uintptr_t)&mtk_pwrap->wacs2_rdata); /* Prevent someone to used pwrap before pwrap init */ if (((reg_rdata >> RDATA_INIT_DONE_SHIFT) & RDATA_INIT_DONE_MASK) != WACS_INIT_DONE) { ERROR("initialization isn't finished\n"); return E_PWR_NOT_INIT_DONE; } } reg_rdata = 0; /* Check IDLE in advance */ return_value = wait_for_state_idle(TIMEOUT_WAIT_IDLE, &mtk_pwrap->wacs2_rdata, &mtk_pwrap->wacs2_vldclr, 0); if (return_value != 0) { ERROR("wait_for_fsm_idle fail,return_value=%d\n", return_value); goto FAIL; } wacs_write = write << 31; wacs_adr = (adr >> 1) << 16; wacs_cmd = wacs_write | wacs_adr | wdata; mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_cmd, wacs_cmd); if (write == 0) { if (rdata == NULL) { ERROR("rdata is a NULL pointer\n"); return_value = E_PWR_INVALID_ARG; goto FAIL; } return_value = wait_for_state_ready(TIMEOUT_READ, &mtk_pwrap->wacs2_rdata, ®_rdata); if (return_value != 0) { ERROR("wait_for_fsm_vldclr fail,return_value=%d\n", return_value); goto FAIL; } *rdata = ((reg_rdata >> RDATA_WACS_RDATA_SHIFT) & RDATA_WACS_RDATA_MASK); mmio_write_32((uintptr_t)&mtk_pwrap->wacs2_vldclr, 1); } FAIL: return return_value; } /* external API for pmic_wrap user */ int32_t pwrap_read(uint32_t adr, uint32_t *rdata) { return pwrap_wacs2(0, adr, 0, rdata, 1); } int32_t pwrap_write(uint32_t adr, uint32_t wdata) { return pwrap_wacs2(1, adr, wdata, 0, 1); } trusted-firmware-a-2.2/plat/mediatek/common/drivers/rtc/000077500000000000000000000000001355360272700233725ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/common/drivers/rtc/rtc_common.c000066400000000000000000000021321355360272700256740ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /* RTC busy status polling interval and retry count */ enum { RTC_WRTGR_POLLING_DELAY_MS = 10, RTC_WRTGR_POLLING_CNT = 100 }; uint16_t RTC_Read(uint32_t addr) { uint32_t rdata = 0; pwrap_read((uint32_t)addr, &rdata); return (uint16_t)rdata; } void RTC_Write(uint32_t addr, uint16_t data) { pwrap_write((uint32_t)addr, (uint32_t)data); } int32_t rtc_busy_wait(void) { uint64_t retry = RTC_WRTGR_POLLING_CNT; do { mdelay(RTC_WRTGR_POLLING_DELAY_MS); if (!(RTC_Read(RTC_BBPU) & RTC_BBPU_CBUSY)) return 1; retry--; } while (retry); ERROR("[RTC] rtc cbusy time out!\n"); return 0; } int32_t RTC_Write_Trigger(void) { RTC_Write(RTC_WRTGR, 1); return rtc_busy_wait(); } int32_t Writeif_unlock(void) { RTC_Write(RTC_PROT, RTC_PROT_UNLOCK1); if (!RTC_Write_Trigger()) return 0; RTC_Write(RTC_PROT, RTC_PROT_UNLOCK2); if (!RTC_Write_Trigger()) return 0; return 1; } trusted-firmware-a-2.2/plat/mediatek/common/drivers/uart/000077500000000000000000000000001355360272700235555ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/common/drivers/uart/8250_console.S000066400000000000000000000100141355360272700260150ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .globl console_core_init .globl console_core_putc .globl console_core_getc .globl console_core_flush /* ----------------------------------------------- * int console_core_init(unsigned long base_addr, * unsigned int uart_clk, unsigned int baud_rate) * Function to initialize the console without a * C Runtime to print debug information. This * function will be accessed by console_init and * crash reporting. * In: x0 - console base address * w1 - Uart clock in Hz * w2 - Baud rate * Out: return 1 on success else 0 on error * Clobber list : x1, x2, x3 * ----------------------------------------------- */ func console_core_init /* Check the input base address */ cbz x0, core_init_fail /* Check baud rate and uart clock for sanity */ cbz w1, core_init_fail cbz w2, core_init_fail /* Disable interrupt */ str wzr, [x0, #UART_IER] /* Force DTR and RTS to high */ mov w3, #(UART_MCR_DTR | UART_MCR_RTS) str w3, [x0, #UART_MCR] /* Check high speed */ movz w3, #:abs_g1:115200 movk w3, #:abs_g0_nc:115200 cmp w2, w3 b.hi 1f /* Non high speed */ lsl w2, w2, #4 mov w3, wzr b 2f /* High speed */ 1: lsl w2, w2, #2 mov w3, #2 /* Set high speed UART register */ 2: str w3, [x0, #UART_HIGHSPEED] /* Calculate divisor */ udiv w3, w1, w2 /* divisor = uartclk / (quot * baudrate) */ msub w1, w3, w2, w1 /* remainder = uartclk % (quot * baudrate) */ lsr w2, w2, #1 cmp w1, w2 cinc w3, w3, hs /* Set line configuration, access divisor latches */ mov w1, #(UART_LCR_DLAB | UART_LCR_WLS_8) str w1, [x0, #UART_LCR] /* Set the divisor */ and w1, w3, #0xff str w1, [x0, #UART_DLL] lsr w1, w3, #8 and w1, w1, #0xff str w1, [x0, #UART_DLH] /* Hide the divisor latches */ mov w1, #UART_LCR_WLS_8 str w1, [x0, #UART_LCR] /* Enable FIFOs, and clear receive and transmit */ mov w1, #(UART_FCR_FIFO_EN | UART_FCR_CLEAR_RCVR | \ UART_FCR_CLEAR_XMIT) str w1, [x0, #UART_FCR] mov w0, #1 ret core_init_fail: mov w0, wzr ret endfunc console_core_init /* -------------------------------------------------------- * int console_core_putc(int c, unsigned long base_addr) * Function to output a character over the console. It * returns the character printed on success or -1 on error. * In : w0 - character to be printed * x1 - console base address * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_core_putc /* Check the input parameter */ cbz x1, putc_error /* Prepend '\r' to '\n' */ cmp w0, #0xA b.ne 2f /* Check if the transmit FIFO is full */ 1: ldr w2, [x1, #UART_LSR] and w2, w2, #UART_LSR_THRE cbz w2, 1b mov w2, #0xD str w2, [x1, #UART_THR] /* Check if the transmit FIFO is full */ 2: ldr w2, [x1, #UART_LSR] and w2, w2, #UART_LSR_THRE cbz w2, 2b str w0, [x1, #UART_THR] ret putc_error: mov w0, #-1 ret endfunc console_core_putc /* --------------------------------------------- * int console_core_getc(unsigned long base_addr) * Function to get a character from the console. * It returns the character grabbed on success * or -1 on error. * In : x0 - console base address * Clobber list : x0, x1 * --------------------------------------------- */ func console_core_getc cbz x0, getc_error /* Check if the receive FIFO is empty */ 1: ldr w1, [x0, #UART_LSR] tbz w1, #UART_LSR_DR, 1b ldr w0, [x0, #UART_RBR] ret getc_error: mov w0, #-1 ret endfunc console_core_getc /* --------------------------------------------- * int console_core_flush(uintptr_t base_addr) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - console base address * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func console_core_flush /* Placeholder */ mov w0, #0 ret endfunc console_core_flush trusted-firmware-a-2.2/plat/mediatek/common/drivers/uart/uart8250.h000066400000000000000000000022671355360272700252270ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef UART8250_H #define UART8250_H /* UART register */ #define UART_RBR 0x00 /* Receive buffer register */ #define UART_DLL 0x00 /* Divisor latch lsb */ #define UART_THR 0x00 /* Transmit holding register */ #define UART_DLH 0x04 /* Divisor latch msb */ #define UART_IER 0x04 /* Interrupt enable register */ #define UART_FCR 0x08 /* FIFO control register */ #define UART_LCR 0x0c /* Line control register */ #define UART_MCR 0x10 /* Modem control register */ #define UART_LSR 0x14 /* Line status register */ #define UART_HIGHSPEED 0x24 /* High speed UART */ /* FCR */ #define UART_FCR_FIFO_EN 0x01 /* enable FIFO */ #define UART_FCR_CLEAR_RCVR 0x02 /* clear the RCVR FIFO */ #define UART_FCR_CLEAR_XMIT 0x04 /* clear the XMIT FIFO */ /* LCR */ #define UART_LCR_WLS_8 0x03 /* 8 bit character length */ #define UART_LCR_DLAB 0x80 /* divisor latch access bit */ /* MCR */ #define UART_MCR_DTR 0x01 #define UART_MCR_RTS 0x02 /* LSR */ #define UART_LSR_DR 0x01 /* Data ready */ #define UART_LSR_THRE 0x20 /* Xmit holding register empty */ #endif /* UART8250_H */ trusted-firmware-a-2.2/plat/mediatek/common/mtk_plat_common.c000066400000000000000000000045071355360272700244610ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include struct atf_arg_t gteearg; void clean_top_32b_of_param(uint32_t smc_fid, u_register_t *px1, u_register_t *px2, u_register_t *px3, u_register_t *px4) { /* if parameters from SMC32. Clean top 32 bits */ if (0 == (smc_fid & SMC_AARCH64_BIT)) { *px1 = *px1 & SMC32_PARAM_MASK; *px2 = *px2 & SMC32_PARAM_MASK; *px3 = *px3 & SMC32_PARAM_MASK; *px4 = *px4 & SMC32_PARAM_MASK; } } #if MTK_SIP_KERNEL_BOOT_ENABLE static struct kernel_info k_info; static void save_kernel_info(uint64_t pc, uint64_t r0, uint64_t r1, uint64_t k32_64) { k_info.k32_64 = k32_64; k_info.pc = pc; if (LINUX_KERNEL_32 == k32_64) { /* for 32 bits kernel */ k_info.r0 = 0; /* machtype */ k_info.r1 = r0; /* tags */ k_info.r2 = r1; } else { /* for 64 bits kernel */ k_info.r0 = r0; k_info.r1 = r1; } } uint64_t get_kernel_info_pc(void) { return k_info.pc; } uint64_t get_kernel_info_r0(void) { return k_info.r0; } uint64_t get_kernel_info_r1(void) { return k_info.r1; } uint64_t get_kernel_info_r2(void) { return k_info.r2; } void boot_to_kernel(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4) { static uint8_t kernel_boot_once_flag; /* only support in booting flow */ if (0 == kernel_boot_once_flag) { kernel_boot_once_flag = 1; console_init(gteearg.atf_log_port, UART_CLOCK, UART_BAUDRATE); INFO("save kernel info\n"); save_kernel_info(x1, x2, x3, x4); bl31_prepare_kernel_entry(x4); INFO("el3_exit\n"); console_uninit(); } } #endif uint32_t plat_get_spsr_for_bl33_entry(void) { unsigned int mode; uint32_t spsr; unsigned int ee; unsigned long daif; INFO("Secondary bootloader is AArch32\n"); mode = MODE32_svc; ee = 0; /* * TODO: Choose async. exception bits if HYP mode is not * implemented according to the values of SCR.{AW, FW} bits */ daif = DAIF_ABT_BIT | DAIF_IRQ_BIT | DAIF_FIQ_BIT; spsr = SPSR_MODE32(mode, 0, ee, daif); return spsr; } trusted-firmware-a-2.2/plat/mediatek/common/mtk_plat_common.h000066400000000000000000000042121355360272700244570ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MTK_PLAT_COMMON_H #define MTK_PLAT_COMMON_H #include #include #include /******************************************************************************* * Function and variable prototypes ******************************************************************************/ #define DEVINFO_SIZE 4 #define LINUX_KERNEL_32 0 #define SMC32_PARAM_MASK (0xFFFFFFFF) struct atf_arg_t { unsigned int atf_magic; unsigned int tee_support; unsigned int tee_entry; unsigned int tee_boot_arg_addr; unsigned int hwuid[4]; /* HW Unique id for t-base used */ unsigned int HRID[2]; /* HW random id for t-base used */ unsigned int atf_log_port; unsigned int atf_log_baudrate; unsigned int atf_log_buf_start; unsigned int atf_log_buf_size; unsigned int atf_irq_num; unsigned int devinfo[DEVINFO_SIZE]; unsigned int atf_aee_debug_buf_start; unsigned int atf_aee_debug_buf_size; }; struct kernel_info { uint64_t pc; uint64_t r0; uint64_t r1; uint64_t r2; uint64_t k32_64; }; struct mtk_bl_param_t { uint64_t bootarg_loc; uint64_t bootarg_size; uint64_t bl33_start_addr; uint64_t tee_info_addr; }; struct mtk_bl31_params { param_header_t h; image_info_t *bl31_image_info; entry_point_info_t *bl32_ep_info; image_info_t *bl32_image_info; entry_point_info_t *bl33_ep_info; image_info_t *bl33_image_info; }; /* Declarations for mtk_plat_common.c */ uint32_t plat_get_spsr_for_bl32_entry(void); uint32_t plat_get_spsr_for_bl33_entry(void); void clean_top_32b_of_param(uint32_t smc_fid, u_register_t *x1, u_register_t *x2, u_register_t *x3, u_register_t *x4); void bl31_prepare_kernel_entry(uint64_t k32_64); void enable_ns_access_to_cpuectlr(void); void boot_to_kernel(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4); uint64_t get_kernel_info_pc(void); uint64_t get_kernel_info_r0(void); uint64_t get_kernel_info_r1(void); uint64_t get_kernel_info_r2(void); extern struct atf_arg_t gteearg; #endif /* MTK_PLAT_COMMON_H */ trusted-firmware-a-2.2/plat/mediatek/common/mtk_sip_svc.c000066400000000000000000000056011355360272700236130ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include /* Mediatek SiP Service UUID */ DEFINE_SVC_UUID2(mtk_sip_svc_uid, 0xa42b58f7, 0x6242, 0x7d4d, 0x80, 0xe5, 0x8f, 0x95, 0x05, 0x00, 0x0f, 0x3d); #pragma weak mediatek_plat_sip_handler uintptr_t mediatek_plat_sip_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) { ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); SMC_RET1(handle, SMC_UNK); } /* * This function handles Mediatek defined SiP Calls */ uintptr_t mediatek_sip_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 ns; /* if parameter is sent from SMC32. Clean top 32 bits */ clean_top_32b_of_param(smc_fid, &x1, &x2, &x3, &x4); /* Determine which security state this SMC originated from */ ns = is_caller_non_secure(flags); if (!ns) { /* SiP SMC service secure world's call */ ; } else { /* SiP SMC service normal world's call */ switch (smc_fid) { #if MTK_SIP_SET_AUTHORIZED_SECURE_REG_ENABLE case MTK_SIP_SET_AUTHORIZED_SECURE_REG: { /* only use ret here */ uint64_t ret; ret = mt_sip_set_authorized_sreg((uint32_t)x1, (uint32_t)x2); SMC_RET1(handle, ret); } #endif #if MTK_SIP_KERNEL_BOOT_ENABLE case MTK_SIP_KERNEL_BOOT_AARCH32: boot_to_kernel(x1, x2, x3, x4); SMC_RET0(handle); #endif default: /* Do nothing in default case */ break; } } return mediatek_plat_sip_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); } /* * This function is responsible for handling all SiP calls from the NS world */ uintptr_t sip_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) { switch (smc_fid) { case SIP_SVC_CALL_COUNT: /* Return the number of Mediatek SiP Service Calls. */ SMC_RET1(handle, MTK_COMMON_SIP_NUM_CALLS + MTK_PLAT_SIP_NUM_CALLS); case SIP_SVC_UID: /* Return UID to the caller */ SMC_UUID_RET(handle, mtk_sip_svc_uid); case SIP_SVC_VERSION: /* Return the version of current implementation */ SMC_RET2(handle, MTK_SIP_SVC_VERSION_MAJOR, MTK_SIP_SVC_VERSION_MINOR); default: return mediatek_sip_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); } } /* Define a runtime service descriptor for fast SMC calls */ DECLARE_RT_SVC( mediatek_sip_svc, OEN_SIP_START, OEN_SIP_END, SMC_TYPE_FAST, NULL, sip_smc_handler ); trusted-firmware-a-2.2/plat/mediatek/common/mtk_sip_svc.h000066400000000000000000000030161355360272700236160ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MTK_SIP_SVC_H #define MTK_SIP_SVC_H #include /* SMC function IDs for SiP Service queries */ #define SIP_SVC_CALL_COUNT 0x8200ff00 #define SIP_SVC_UID 0x8200ff01 /* 0x8200ff02 is reserved */ #define SIP_SVC_VERSION 0x8200ff03 /* Mediatek SiP Service Calls version numbers */ #define MTK_SIP_SVC_VERSION_MAJOR 0x0 #define MTK_SIP_SVC_VERSION_MINOR 0x1 #define SMC_AARCH64_BIT 0x40000000 /* Number of Mediatek SiP Calls implemented */ #define MTK_COMMON_SIP_NUM_CALLS 4 /* Mediatek SiP Service Calls function IDs */ #define MTK_SIP_SET_AUTHORIZED_SECURE_REG 0x82000001 /* For MTK SMC from Secure OS */ /* 0x82000000 - 0x820000FF & 0xC2000000 - 0xC20000FF */ #define MTK_SIP_KERNEL_BOOT_AARCH32 0x82000200 #define MTK_SIP_KERNEL_BOOT_AARCH64 0xC2000200 /* Mediatek SiP Calls error code */ enum { MTK_SIP_E_SUCCESS = 0, MTK_SIP_E_INVALID_PARAM = -1, MTK_SIP_E_NOT_SUPPORTED = -2, MTK_SIP_E_INVALID_RANGE = -3, MTK_SIP_E_PERMISSION_DENY = -4, MTK_SIP_E_LOCK_FAIL = -5 }; /* * This function should be implemented in Mediatek SOC directory. It fullfills * MTK_SIP_SET_AUTHORIZED_SECURE_REG SiP call by checking the sreg with the * predefined secure register list, if a match was found, set val to sreg. * * Return MTK_SIP_E_SUCCESS on success, and MTK_SIP_E_INVALID_PARAM on failure. */ uint64_t mt_sip_set_authorized_sreg(uint32_t sreg, uint32_t val); #endif /* MTK_SIP_SVC_H */ trusted-firmware-a-2.2/plat/mediatek/common/params_setup.c000066400000000000000000000013751355360272700240010ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include static struct bl_aux_gpio_info rst_gpio; struct bl_aux_gpio_info *plat_get_mtk_gpio_reset(void) { return &rst_gpio; } static bool mtk_aux_param_handler(struct bl_aux_param_header *param) { /* Store platform parameters for later processing if needed. */ switch (param->type) { case BL_AUX_PARAM_MTK_RESET_GPIO: rst_gpio = ((struct bl_aux_param_gpio *)param)->gpio; return true; } return false; } void params_early_setup(u_register_t plat_param_from_bl2) { bl_aux_params_parse(plat_param_from_bl2, mtk_aux_param_handler); } trusted-firmware-a-2.2/plat/mediatek/common/plat_params.h000066400000000000000000000005451355360272700236040ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_PARAMS_H #define PLAT_PARAMS_H #include #include struct bl_aux_gpio_info *plat_get_mtk_gpio_reset(void); void params_early_setup(u_register_t plat_param_from_bl2); #endif trusted-firmware-a-2.2/plat/mediatek/mt6795/000077500000000000000000000000001355360272700206075ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt6795/aarch64/000077500000000000000000000000001355360272700220375ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt6795/aarch64/plat_helpers.S000066400000000000000000000074331355360272700246540ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl plat_secondary_cold_boot_setup .globl plat_report_exception .globl platform_is_primary_cpu .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush .globl platform_mem_init .macro crash_ram_log /* * Check teearg->atf_log_buf_size. * Exit if atf_log_buf_size equals 0 */ adr x2, ptr_atf_crash_flag ldr x2, [x2] /* exit if ptr_atf_crash_flag equals NULL */ cbz x2, exit_putc /* * set atf crash magic number */ 1: adr x2, ptr_atf_crash_flag ldr x2, [x2] mov_imm x1, 0xdead1abf /* p_atf_log_ctrl->atf_crash_flag = 0xdead1abf */ str w1, [x2] /* can't use w3 return addr, w4, start of buffer addr */ ldr w2, [x2] cmp w2, w1 b.ne 1b /* * get cpu id */ mrs x1, mpidr_el1 /* refer to platform_get_core_pos */ and x2, x1, #MPIDR_CPU_MASK and x1, x1, #MPIDR_CLUSTER_MASK /* x1 = cpu id (cpu id = aff0 + aff1*4 ) */ add x1, x2, x1, LSR #6 adr x2, ptr_atf_except_write_pos_per_cpu ldr x2, [x2] /* * plus (cpu_id * 8)--> * &p_atf_log_ctrl->atf_except_write_pos_per_cpu[cpu_id] * x2 = &p_atf_log_ctrl->atf_except_write_pos_per_cpu[cpu_id]; */ add x2, x2, x1, LSL # 3 /* log write */ /* w1 = p_atf_log_ctrl->atf_except_write_pos_per_cpu[cpu_id] */ ldr x1, [x2] /* *x1 = w0--> * *(p_atf_log_ctrl->atf_except_write_pos_per_cpu[cpu_id]) = c) */ strb w0, [x1] /* w1++ */ add x1, x1, #1 /* p_atf_log_ctrl->atf_except_write_pos_per_cpu[cpu_id] = w1 */ str x1, [x2] exit_putc: .endm /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions * needed for a secondary cpu after a cold reset e.g * mark the cpu's presence, mechanism to place it in a * holding pen etc. * ----------------------------------------------------- */ func plat_secondary_cold_boot_setup /* Do not do cold boot for secondary CPU */ cb_panic: b cb_panic endfunc plat_secondary_cold_boot_setup func platform_is_primary_cpu and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) cmp x0, #PLAT_PRIMARY_CPU cset x0, eq ret endfunc platform_is_primary_cpu /* --------------------------------------------- * int plat_crash_console_init(void) * Function to initialize the crash console * without a C Runtime to print crash report. * Clobber list : x0, x1, x2 * --------------------------------------------- */ func plat_crash_console_init mov_imm x0, UART0_BASE mov_imm x1, UART_CLOCK mov_imm x2, UART_BAUDRATE b console_init ret endfunc plat_crash_console_init /* --------------------------------------------- * int plat_crash_console_putc(void) * Function to print a character on the crash * console without a C Runtime. * Clobber list : x1, x2 * --------------------------------------------- */ func plat_crash_console_putc mov_imm x1, UART0_BASE b console_core_putc ret endfunc plat_crash_console_putc /* --------------------------------------------- * int plat_crash_console_flush(int c) * Function to force a write of all buffered * data that hasn't been output. * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func plat_crash_console_flush mov_imm x0, UART0_BASE b console_core_flush endfunc plat_crash_console_flush /* -------------------------------------------------------- * void platform_mem_init (void); * * Any memory init, relocation to be done before the * platform boots. Called very early in the boot process. * -------------------------------------------------------- */ func platform_mem_init ret endfunc platform_mem_init trusted-firmware-a-2.2/plat/mediatek/mt6795/bl31.ld.S000066400000000000000000000126241355360272700220770ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT) OUTPUT_ARCH(PLATFORM_LINKER_ARCH) ENTRY(bl31_entrypoint) MEMORY { RAM (rwx): ORIGIN = BL31_BASE, LENGTH = BL31_TZRAM_SIZE RAM2 (rwx): ORIGIN = TZRAM2_BASE, LENGTH = TZRAM2_SIZE } SECTIONS { . = BL31_BASE; ASSERT(. == ALIGN(2048), "vector base is not aligned on a 2K boundary.") __RO_START__ = .; vector . : { *(.vectors) } >RAM ASSERT(. == ALIGN(PAGE_SIZE), "BL31_BASE address is not aligned on a page boundary.") ro . : { *bl31_entrypoint.o(.text*) *(.text*) *(.rodata*) /* Ensure 8-byte alignment for descriptors and ensure inclusion */ . = ALIGN(8); __RT_SVC_DESCS_START__ = .; KEEP(*(rt_svc_descs)) __RT_SVC_DESCS_END__ = .; /* * Ensure 8-byte alignment for cpu_ops so that its fields are also * aligned. Also ensure cpu_ops inclusion. */ . = ALIGN(8); __CPU_OPS_START__ = .; KEEP(*(cpu_ops)) __CPU_OPS_END__ = .; __RO_END_UNALIGNED__ = .; /* * Memory page(s) mapped to this section will be marked as read-only, * executable. No RW data from the next section must creep in. * Ensure the rest of the current memory page is unused. */ . = ALIGN(PAGE_SIZE); __RO_END__ = .; } >RAM ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__, "cpu_ops not defined for this platform.") /* * Define a linker symbol to mark start of the RW memory area for this * image. */ __RW_START__ = . ; /* * .data must be placed at a lower address than the stacks if the stack * protector is enabled. Alternatively, the .data.stack_protector_canary * section can be placed independently of the main .data section. */ .data . : { __DATA_START__ = .; *(.data*) __DATA_END__ = .; } >RAM #ifdef BL31_PROGBITS_LIMIT ASSERT(. <= BL31_PROGBITS_LIMIT, "BL3-1 progbits has exceeded its limit.") #endif stacks (NOLOAD) : { __STACKS_START__ = .; *(tzfw_normal_stacks) __STACKS_END__ = .; } >RAM /* * The .bss section gets initialised to 0 at runtime. * Its base address should be 16-byte aligned for better performance of the * zero-initialization code. */ .bss (NOLOAD) : ALIGN(16) { __BSS_START__ = .; *(.bss*) *(COMMON) #if !USE_COHERENT_MEM /* * Bakery locks are stored in normal .bss memory * * Each lock's data is spread across multiple cache lines, one per CPU, * but multiple locks can share the same cache line. * The compiler will allocate enough memory for one CPU's bakery locks, * the remaining cache lines are allocated by the linker script */ . = ALIGN(CACHE_WRITEBACK_GRANULE); __BAKERY_LOCK_START__ = .; __PERCPU_BAKERY_LOCK_START__ = .; *(bakery_lock) . = ALIGN(CACHE_WRITEBACK_GRANULE); __PERCPU_BAKERY_LOCK_END__ = .; __PERCPU_BAKERY_LOCK_SIZE__ = ABSOLUTE(__PERCPU_BAKERY_LOCK_END__ - __PERCPU_BAKERY_LOCK_START__); . = . + (__PERCPU_BAKERY_LOCK_SIZE__ * (PLATFORM_CORE_COUNT - 1)); __BAKERY_LOCK_END__ = .; #ifdef PLAT_PERCPU_BAKERY_LOCK_SIZE ASSERT(__PERCPU_BAKERY_LOCK_SIZE__ == PLAT_PERCPU_BAKERY_LOCK_SIZE, "PLAT_PERCPU_BAKERY_LOCK_SIZE does not match bakery lock requirements"); #endif #endif __BSS_END__ = .; __RW_END__ = .; } >RAM ASSERT(. <= BL31_LIMIT, "BL3-1 image has exceeded its limit.") /* * The xlat_table section is for full, aligned page tables (4K). * Removing them from .bss avoids forcing 4K alignment on * the .bss section. The tables are initialized to zero by the translation * tables library. */ xlat_table (NOLOAD) : { *(xlat_table) } >RAM2 #if USE_COHERENT_MEM /* * The base address of the coherent memory section must be page-aligned (4K) * to guarantee that the coherent data are stored on their own pages and * are not mixed with normal data. This is required to set up the correct * memory attributes for the coherent data page tables. */ coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) { __COHERENT_RAM_START__ = .; /* * Bakery locks are stored in coherent memory * * Each lock's data is contiguous and fully allocated by the compiler */ *(bakery_lock) *(tzfw_coherent_mem) __COHERENT_RAM_END_UNALIGNED__ = .; /* * Memory page(s) mapped to this section will be marked * as device memory. No other unexpected data must creep in. * Ensure the rest of the current memory page is unused. */ . = ALIGN(PAGE_SIZE); __COHERENT_RAM_END__ = .; } >RAM2 #endif /* * Define a linker symbol to mark end of the RW memory area for this * image. */ __BL31_END__ = .; __BSS_SIZE__ = SIZEOF(.bss); #if USE_COHERENT_MEM __COHERENT_RAM_UNALIGNED_SIZE__ = __COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__; #endif ASSERT(. <= TZRAM2_LIMIT, "TZRAM2 image has exceeded its limit.") } trusted-firmware-a-2.2/plat/mediatek/mt6795/bl31_plat_setup.c000066400000000000000000000336121355360272700237610ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * Declarations of linker defined symbols which will help us find the layout * of trusted SRAM ******************************************************************************/ /* * The next 2 constants identify the extents of the code & RO data region. * These addresses are used by the MMU setup code and therefore they must be * page-aligned. It is the responsibility of the linker script to ensure that * __RO_START__ and __RO_END__ linker symbols refer to page-aligned addresses. */ IMPORT_SYM(unsigned long, __RO_START__, BL31_RO_BASE); IMPORT_SYM(unsigned long, __RO_END__, BL31_RO_LIMIT); /* * Placeholder variables for copying the arguments that have been passed to * BL3-1 from BL2. */ static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; static const int cci_map[] = { PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX, PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX }; static uint32_t cci_map_length = ARRAY_SIZE(cci_map); /* Table of regions to map using the MMU. */ static const mmap_region_t plat_mmap[] = { /* for TF text, RO, RW */ MAP_REGION_FLAT(MTK_DEV_RNG0_BASE, MTK_DEV_RNG0_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(MTK_DEV_RNG1_BASE, MTK_DEV_RNG1_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(RAM_CONSOLE_BASE & ~(PAGE_SIZE_MASK), RAM_CONSOLE_SIZE, MT_DEVICE | MT_RW | MT_NS), { 0 } }; /******************************************************************************* * Macro generating the code for the function setting up the pagetables as per * the platform memory map & initialize the mmu, for the given exception level ******************************************************************************/ #define DEFINE_CONFIGURE_MMU_EL(_el) \ void plat_configure_mmu_el ## _el(unsigned long total_base, \ unsigned long total_size, \ unsigned long ro_start, \ unsigned long ro_limit, \ unsigned long coh_start, \ unsigned long coh_limit) \ { \ mmap_add_region(total_base, total_base, \ total_size, \ MT_MEMORY | MT_RW | MT_SECURE); \ mmap_add_region(ro_start, ro_start, \ ro_limit - ro_start, \ MT_MEMORY | MT_RO | MT_SECURE); \ mmap_add_region(coh_start, coh_start, \ coh_limit - coh_start, \ MT_DEVICE | MT_RW | MT_SECURE); \ mmap_add(plat_mmap); \ init_xlat_tables(); \ \ enable_mmu_el ## _el(0); \ } /* Define EL3 variants of the function initialising the MMU */ DEFINE_CONFIGURE_MMU_EL(3) unsigned int plat_get_syscnt_freq2(void) { return SYS_COUNTER_FREQ_IN_TICKS; } void plat_cci_init(void) { /* Initialize CCI driver */ cci_init(PLAT_MT_CCI_BASE, cci_map, cci_map_length); } void plat_cci_enable(void) { /* * Enable CCI coherency for this cluster. * No need for locks as no other cpu is active at the moment. */ cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr())); } void plat_cci_disable(void) { cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr())); } static void platform_setup_cpu(void) { /* setup big cores */ mmio_write_32((uintptr_t)&mt6795_mcucfg->mp1_config_res, MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK | MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK | MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK | MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK | MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK); mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp1_miscdbg, MP1_AINACTS); mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp1_clkenm_div, MP1_SW_CG_GEN); mmio_clrbits_32((uintptr_t)&mt6795_mcucfg->mp1_rst_ctl, MP1_L2RSTDISABLE); /* set big cores arm64 boot mode */ mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp1_cpucfg, MP1_CPUCFG_64BIT); /* set LITTLE cores arm64 boot mode */ mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp0_rv_addr[0].rv_addr_hw, MP0_CPUCFG_64BIT); } /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for * the security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. ******************************************************************************/ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; next_image_info = (type == NON_SECURE) ? &bl33_image_ep_info : &bl32_image_ep_info; /* None of the images on this platform can have 0x0 as the entrypoint */ if (next_image_info->pc) return next_image_info; else return NULL; } /******************************************************************************* * Perform any BL3-1 early platform setup. Here is an opportunity to copy * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before they * are lost (potentially). This needs to be done before the MMU is initialized * so that the memory layout can be used while creating page tables. * BL2 has flushed this information to memory, so we are guaranteed to pick up * good data. ******************************************************************************/ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { struct mtk_bl_param_t *pmtk_bl_param = (struct mtk_bl_param_t *)arg0; struct atf_arg_t *teearg; unsigned long long normal_base; unsigned long long atf_base; assert(pmtk_bl_param != NULL); /* * Mediatek preloader(i.e, BL2) is in 32 bit state, high 32bits * of 64 bit GP registers are UNKNOWN if CPU warm reset from 32 bit * to 64 bit state. So we need to clear high 32bit, * which may be random value. */ pmtk_bl_param = (struct mtk_bl_param_t *)((uint64_t)pmtk_bl_param & 0x00000000ffffffff); teearg = (struct atf_arg_t *)pmtk_bl_param->tee_info_addr; console_init(teearg->atf_log_port, UART_CLOCK, UART_BAUDRATE); memcpy((void *)>eearg, (void *)teearg, sizeof(struct atf_arg_t)); normal_base = 0; /* in ATF boot time, timer for cntpct_el0 is not initialized * so it will not count now. */ atf_base = read_cntpct_el0(); sched_clock_init(normal_base, atf_base); VERBOSE("bl31_setup\n"); /* Populate entry point information for BL3-2 and BL3-3 */ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0); SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); bl32_image_ep_info.pc = BL32_BASE; SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); /* * Tell BL3-1 where the non-trusted software image * is located and the entry state information */ /* BL33_START_ADDRESS */ bl33_image_ep_info.pc = pmtk_bl_param->bl33_start_addr; bl33_image_ep_info.spsr = plat_get_spsr_for_bl33_entry(); bl33_image_ep_info.args.arg4 = pmtk_bl_param->bootarg_loc; bl33_image_ep_info.args.arg5 = pmtk_bl_param->bootarg_size; SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); } /******************************************************************************* * Perform any BL3-1 platform setup code ******************************************************************************/ void bl31_platform_setup(void) { platform_setup_cpu(); generic_delay_timer_init(); plat_mt_gic_driver_init(); /* Initialize the gic cpu and distributor interfaces */ plat_mt_gic_init(); /* Topologies are best known to the platform. */ mt_setup_topology(); } /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this is only intializes the mmu in a quick and dirty way. * Init MTK propiartary log buffer control field. ******************************************************************************/ void bl31_plat_arch_setup(void) { /* Enable non-secure access to CCI-400 registers */ mmio_write_32(CCI400_BASE + CCI_SEC_ACCESS_OFFSET, 0x1); plat_cci_init(); plat_cci_enable(); if (gteearg.atf_log_buf_size != 0) { INFO("mmap atf buffer : 0x%x, 0x%x\n\r", gteearg.atf_log_buf_start, gteearg.atf_log_buf_size); mmap_add_region( gteearg.atf_log_buf_start & ~(PAGE_SIZE_2MB_MASK), gteearg.atf_log_buf_start & ~(PAGE_SIZE_2MB_MASK), PAGE_SIZE_2MB, MT_DEVICE | MT_RW | MT_NS); INFO("mmap atf buffer (force 2MB aligned):0x%x, 0x%x\n", (gteearg.atf_log_buf_start & ~(PAGE_SIZE_2MB_MASK)), PAGE_SIZE_2MB); } /* * add TZRAM_BASE to memory map * then set RO and COHERENT to different attribute */ plat_configure_mmu_el3( (TZRAM_BASE & ~(PAGE_SIZE_MASK)), (TZRAM_SIZE & ~(PAGE_SIZE_MASK)), (BL31_RO_BASE & ~(PAGE_SIZE_MASK)), BL31_RO_LIMIT, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); /* Initialize for ATF log buffer */ if (gteearg.atf_log_buf_size != 0) { gteearg.atf_aee_debug_buf_size = ATF_AEE_BUFFER_SIZE; gteearg.atf_aee_debug_buf_start = gteearg.atf_log_buf_start + gteearg.atf_log_buf_size - ATF_AEE_BUFFER_SIZE; INFO("ATF log service is registered (0x%x, aee:0x%x)\n", gteearg.atf_log_buf_start, gteearg.atf_aee_debug_buf_start); } else{ gteearg.atf_aee_debug_buf_size = 0; gteearg.atf_aee_debug_buf_start = 0; } /* Platform code before bl31_main */ /* compatible to the earlier chipset */ /* Show to ATF log buffer & UART */ INFO("BL3-1: %s\n", version_string); INFO("BL3-1: %s\n", build_message); } #if 0 /* MTK Define */ #define ACTLR_CPUECTLR_BIT (1 << 1) void enable_ns_access_to_cpuectlr(void) { unsigned int next_actlr; /* ACTLR_EL1 do not implement CUPECTLR */ next_actlr = read_actlr_el2(); next_actlr |= ACTLR_CPUECTLR_BIT; write_actlr_el2(next_actlr); next_actlr = read_actlr_el3(); next_actlr |= ACTLR_CPUECTLR_BIT; write_actlr_el3(next_actlr); } #endif /******************************************************************************* * This function prepare boot argument for 64 bit kernel entry ******************************************************************************/ static entry_point_info_t *bl31_plat_get_next_kernel64_ep_info(void) { entry_point_info_t *next_image_info; unsigned int mode; mode = 0; /* Kernel image is always non-secured */ next_image_info = &bl33_image_ep_info; /* Figure out what mode we enter the non-secure world in */ if (el_implemented(2) != EL_IMPL_NONE) { INFO("Kernel_EL2\n"); mode = MODE_EL2; } else{ INFO("Kernel_EL1\n"); mode = MODE_EL1; } INFO("Kernel is 64Bit\n"); next_image_info->spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); next_image_info->pc = get_kernel_info_pc(); next_image_info->args.arg0 = get_kernel_info_r0(); next_image_info->args.arg1 = get_kernel_info_r1(); INFO("pc=0x%lx, r0=0x%lx, r1=0x%lx\n", next_image_info->pc, next_image_info->args.arg0, next_image_info->args.arg1); SET_SECURITY_STATE(next_image_info->h.attr, NON_SECURE); /* None of the images on this platform can have 0x0 as the entrypoint */ if (next_image_info->pc) return next_image_info; else return NULL; } /******************************************************************************* * This function prepare boot argument for 32 bit kernel entry ******************************************************************************/ static entry_point_info_t *bl31_plat_get_next_kernel32_ep_info(void) { entry_point_info_t *next_image_info; unsigned int mode; mode = 0; /* Kernel image is always non-secured */ next_image_info = &bl33_image_ep_info; /* Figure out what mode we enter the non-secure world in */ mode = MODE32_hyp; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ INFO("Kernel is 32Bit\n"); next_image_info->spsr = SPSR_MODE32(mode, SPSR_T_ARM, SPSR_E_LITTLE, (DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT)); next_image_info->pc = get_kernel_info_pc(); next_image_info->args.arg0 = get_kernel_info_r0(); next_image_info->args.arg1 = get_kernel_info_r1(); next_image_info->args.arg2 = get_kernel_info_r2(); INFO("pc=0x%lx, r0=0x%lx, r1=0x%lx, r2=0x%lx\n", next_image_info->pc, next_image_info->args.arg0, next_image_info->args.arg1, next_image_info->args.arg2); SET_SECURITY_STATE(next_image_info->h.attr, NON_SECURE); /* None of the images on this platform can have 0x0 as the entrypoint */ if (next_image_info->pc) return next_image_info; else return NULL; } /******************************************************************************* * This function prepare boot argument for kernel entrypoint ******************************************************************************/ void bl31_prepare_kernel_entry(uint64_t k32_64) { entry_point_info_t *next_image_info; uint32_t image_type; /* Determine which image to execute next */ /* image_type = bl31_get_next_image_type(); */ image_type = NON_SECURE; /* Program EL3 registers to enable entry into the next EL */ if (k32_64 == 0) next_image_info = bl31_plat_get_next_kernel32_ep_info(); else next_image_info = bl31_plat_get_next_kernel64_ep_info(); assert(next_image_info); assert(image_type == GET_SECURITY_STATE(next_image_info->h.attr)); INFO("BL3-1: Preparing for EL3 exit to %s world, Kernel\n", (image_type == SECURE) ? "secure" : "normal"); INFO("BL3-1: Next image address = 0x%llx\n", (unsigned long long) next_image_info->pc); INFO("BL3-1: Next image spsr = 0x%x\n", next_image_info->spsr); cm_init_my_context(next_image_info); cm_prepare_el3_exit(image_type); } trusted-firmware-a-2.2/plat/mediatek/mt6795/drivers/000077500000000000000000000000001355360272700222655ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt6795/drivers/timer/000077500000000000000000000000001355360272700234055ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt6795/drivers/timer/mt_cpuxgpt.c000066400000000000000000000025511355360272700257460ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #define CPUXGPT_BASE 0x10200000 #define INDEX_BASE (CPUXGPT_BASE+0x0674) #define CTL_BASE (CPUXGPT_BASE+0x0670) uint64_t normal_time_base; uint64_t atf_time_base; void sched_clock_init(uint64_t normal_base, uint64_t atf_base) { normal_time_base = normal_base; atf_time_base = atf_base; } uint64_t sched_clock(void) { uint64_t cval; cval = (((read_cntpct_el0() - atf_time_base)*1000)/ SYS_COUNTER_FREQ_IN_MHZ) + normal_time_base; return cval; } /* * Return: 0 - Trying to disable the CPUXGPT control bit, * and not allowed to disable it. * Return: 1 - reg_addr is not realted to disable the control bit. */ unsigned char check_cpuxgpt_write_permission(unsigned int reg_addr, unsigned int reg_value) { unsigned int idx; unsigned int ctl_val; if (reg_addr == CTL_BASE) { idx = mmio_read_32(INDEX_BASE); /* idx 0: CPUXGPT system control */ if (idx == 0) { ctl_val = mmio_read_32(CTL_BASE); if (ctl_val & 1) { /* * if enable bit already set, * then bit 0 is not allow to set as 0 */ if (!(reg_value & 1)) return 0; } } } return 1; } trusted-firmware-a-2.2/plat/mediatek/mt6795/drivers/timer/mt_cpuxgpt.h000066400000000000000000000013061355360272700257500ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MT_CPUXGPT_H #define MT_CPUXGPT_H /* REG */ #define INDEX_CTL_REG 0x000 #define INDEX_STA_REG 0x004 #define INDEX_CNT_L_INIT 0x008 #define INDEX_CNT_H_INIT 0x00C /* CTL_REG SET */ #define EN_CPUXGPT 0x01 #define EN_AHLT_DEBUG 0x02 #define CLK_DIV1 (0x1 << 8) #define CLK_DIV2 (0x2 << 8) #define CLK_DIV4 (0x4 << 8) #define CLK_DIV_MASK (~(0x7<<8)) void generic_timer_backup(void); void sched_clock_init(uint64_t normal_base, uint64_t atf_base); uint64_t sched_clock(void); #endif /* MT_CPUXGPT_H */ trusted-firmware-a-2.2/plat/mediatek/mt6795/include/000077500000000000000000000000001355360272700222325ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt6795/include/mcucfg.h000066400000000000000000000075241355360272700236570ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MCUCFG_H #define MCUCFG_H #include #include struct mt6795_mcucfg_regs { uint32_t mp0_ca7l_cache_config; struct { uint32_t mem_delsel0; uint32_t mem_delsel1; } mp0_cpu[4]; uint32_t mp0_cache_mem_delsel0; uint32_t mp0_cache_mem_delsel1; uint32_t mp0_axi_config; uint32_t mp0_misc_config[2]; struct { uint32_t rv_addr_lw; uint32_t rv_addr_hw; } mp0_rv_addr[4]; uint32_t mp0_ca7l_cfg_dis; uint32_t mp0_ca7l_clken_ctrl; uint32_t mp0_ca7l_rst_ctrl; uint32_t mp0_ca7l_misc_config; uint32_t mp0_ca7l_dbg_pwr_ctrl; uint32_t mp0_rw_rsvd0; uint32_t mp0_rw_rsvd1; uint32_t mp0_ro_rsvd; uint32_t reserved0_0[100]; uint32_t mp1_cpucfg; uint32_t mp1_miscdbg; uint32_t reserved0_1[13]; uint32_t mp1_rst_ctl; uint32_t mp1_clkenm_div; uint32_t reserved0_2[7]; uint32_t mp1_config_res; uint32_t reserved0_3[13]; struct { uint32_t rv_addr_lw; uint32_t rv_addr_hw; } mp1_rv_addr[2]; uint32_t reserved0_4[84]; uint32_t mp0_rst_status; /* 0x400 */ uint32_t mp0_dbg_ctrl; uint32_t mp0_dbg_flag; uint32_t mp0_ca7l_ir_mon; struct { uint32_t pc_lw; uint32_t pc_hw; uint32_t fp_arch32; uint32_t sp_arch32; uint32_t fp_arch64_lw; uint32_t fp_arch64_hw; uint32_t sp_arch64_lw; uint32_t sp_arch64_hw; } mp0_dbg_core[4]; uint32_t dfd_ctrl; uint32_t dfd_cnt_l; uint32_t dfd_cnt_h; uint32_t misccfg_mp0_rw_rsvd; uint32_t misccfg_sec_vio_status0; uint32_t misccfg_sec_vio_status1; uint32_t reserved1[22]; uint32_t misccfg_rw_rsvd; /* 0x500 */ uint32_t mcusys_dbg_mon_sel_a; uint32_t mcusys_dbg_mon; uint32_t reserved2[61]; uint32_t mcusys_config_a; /* 0x600 */ uint32_t mcusys_config1_a; uint32_t mcusys_gic_peribase_a; uint32_t reserved3; uint32_t sec_range0_start; /* 0x610 */ uint32_t sec_range0_end; uint32_t sec_range_enable; uint32_t reserved4; uint32_t int_pol_ctl[8]; /* 0x620 */ uint32_t aclken_div; /* 0x640 */ uint32_t pclken_div; uint32_t l2c_sram_ctrl; uint32_t armpll_jit_ctrl; uint32_t cci_addrmap; /* 0x650 */ uint32_t cci_config; uint32_t cci_periphbase; uint32_t cci_nevntcntovfl; uint32_t cci_clk_ctrl; /* 0x660 */ uint32_t cci_acel_s1_ctrl; uint32_t bus_fabric_dcm_ctrl; uint32_t reserved5; uint32_t xgpt_ctl; /* 0x670 */ uint32_t xgpt_idx; uint32_t ptpod2_ctl0; uint32_t ptpod2_ctl1; uint32_t mcusys_revid; uint32_t mcusys_rw_rsvd0; uint32_t mcusys_rw_rsvd1; }; static struct mt6795_mcucfg_regs *const mt6795_mcucfg = (void *)MCUCFG_BASE; /* cpu boot mode */ #define MP0_CPUCFG_64BIT_SHIFT 12 #define MP1_CPUCFG_64BIT_SHIFT 28 #define MP0_CPUCFG_64BIT (U(0xf) << MP0_CPUCFG_64BIT_SHIFT) #define MP1_CPUCFG_64BIT (U(0xf) << MP1_CPUCFG_64BIT_SHIFT) /* scu related */ enum { MP0_ACINACTM_SHIFT = 4, MP1_ACINACTM_SHIFT = 0, MP0_ACINACTM = 1 << MP0_ACINACTM_SHIFT, MP1_ACINACTM = 1 << MP1_ACINACTM_SHIFT }; enum { MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT = 0, MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT = 4, MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT = 8, MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT = 12, MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT = 16, MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK = 0xf << MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT, MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK = 0xf << MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT, MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK = 0xf << MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT, MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK = 0xf << MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT, MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK = 0xf << MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT }; enum { MP1_AINACTS_SHIFT = 4, MP1_AINACTS = 1 << MP1_AINACTS_SHIFT }; enum { MP1_SW_CG_GEN_SHIFT = 12, MP1_SW_CG_GEN = 1 << MP1_SW_CG_GEN_SHIFT }; enum { MP1_L2RSTDISABLE_SHIFT = 14, MP1_L2RSTDISABLE = 1 << MP1_L2RSTDISABLE_SHIFT }; #endif /* MCUCFG_H */ trusted-firmware-a-2.2/plat/mediatek/mt6795/include/plat_macros.S000066400000000000000000000044031355360272700246630ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .section .rodata.gic_reg_name, "aS" gicc_regs: .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", "" gicd_pend_reg: .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n" \ " Offset:\t\t\tvalue\n" newline: .asciz "\n" spacer: .asciz ":\t\t0x" /* --------------------------------------------- * The below macro prints out relevant GIC * registers whenever an unhandled exception is * taken in BL3-1. * Clobbers: x0 - x10, x16, x17, sp * --------------------------------------------- */ .macro plat_crash_print_regs mov_imm x16, BASE_GICD_BASE mov_imm x17, BASE_GICC_BASE /* Load the gicc reg list to x6 */ adr x6, gicc_regs /* Load the gicc regs to gp regs used by str_in_crash_buf_print */ ldr w8, [x17, #GICC_HPPIR] ldr w9, [x17, #GICC_AHPPIR] ldr w10, [x17, #GICC_CTLR] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print /* Print the GICD_ISPENDR regs */ add x7, x16, #GICD_ISPENDR adr x4, gicd_pend_reg bl asm_print_str gicd_ispendr_loop: sub x4, x7, x16 cmp x4, #0x280 b.eq exit_print_gic_regs bl asm_print_hex adr x4, spacer bl asm_print_str ldr x4, [x7], #8 bl asm_print_hex adr x4, newline bl asm_print_str b gicd_ispendr_loop exit_print_gic_regs: .endm .section .rodata.cci_reg_name, "aS" cci_iface_regs: .asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , "" /* ------------------------------------------------ * The below macro prints out relevant interconnect * registers whenever an unhandled exception is * taken in BL3-1. * Clobbers: x0 - x9, sp * ------------------------------------------------ */ .macro plat_print_interconnect_regs adr x6, cci_iface_regs /* Store in x7 the base address of the first interface */ mov_imm x7, (PLAT_MT_CCI_BASE + SLAVE_IFACE_OFFSET( \ PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX)) ldr w8, [x7, #SNOOP_CTRL_REG] /* Store in x7 the base address of the second interface */ mov_imm x7, (PLAT_MT_CCI_BASE + SLAVE_IFACE_OFFSET( \ PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX)) ldr w9, [x7, #SNOOP_CTRL_REG] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print .endm trusted-firmware-a-2.2/plat/mediatek/mt6795/include/plat_private.h000066400000000000000000000015341355360272700251000ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_PRIVATE_H #define PLAT_PRIVATE_H #include #include void plat_configure_mmu_el3(unsigned long total_base, unsigned long total_size, unsigned long, unsigned long, unsigned long, unsigned long); void plat_cci_init(void); void plat_cci_enable(void); void plat_cci_disable(void); /* Declarations for plat_mt_gic.c */ void plat_mt_gic_init(void); /* Declarations for plat_topology.c */ int mt_setup_topology(void); void plat_delay_timer_init(void); void plat_mt_gic_driver_init(void); void plat_mt_gic_init(void); void plat_mt_gic_cpuif_enable(void); void plat_mt_gic_cpuif_disable(void); void plat_mt_gic_pcpu_init(void); #endif /* PLAT_PRIVATE_H */ trusted-firmware-a-2.2/plat/mediatek/mt6795/include/plat_sip_calls.h000066400000000000000000000006621355360272700254000ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_SIP_CALLS_H #define PLAT_SIP_CALLS_H /******************************************************************************* * Plat SiP function constants ******************************************************************************/ #define MTK_PLAT_SIP_NUM_CALLS 0 #endif /* PLAT_SIP_CALLS_H */ trusted-firmware-a-2.2/plat/mediatek/mt6795/include/platform_def.h000066400000000000000000000225431355360272700250530ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #define PLAT_PRIMARY_CPU 0x0 /* Special value used to verify platform parameters from BL2 to BL3-1 */ #define MT_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL #define IO_PHYS (0x10000000) #define INFRACFG_AO_BASE (IO_PHYS + 0x1000) #define MCUCFG_BASE (IO_PHYS + 0x200000) #define PERI_BASE (IO_PHYS + 0x1000000) #define GPIO_BASE (IO_PHYS + 0x370000) #define SPM_BASE (IO_PHYS + 0x6000) #define RGU_BASE (MCUCFG_BASE + 0x11000) #define PMIC_WRAP_BASE (IO_PHYS + 0x10000) #define TRNG_base (MCUCFG_BASE + 0x230000) #define MT_GIC_BASE (0x10220000) #define MCU_SYS_SIZE (0x700000) #define PLAT_MT_CCI_BASE (IO_PHYS + 0x390000) /* Aggregate of all devices in the first GB */ #define MTK_DEV_RNG0_BASE IO_PHYS #define MTK_DEV_RNG0_SIZE 0x400000 #define MTK_DEV_RNG1_BASE (PERI_BASE) #define MTK_DEV_RNG1_SIZE 0x4000000 /******************************************************************************* * UART related constants ******************************************************************************/ #define UART0_BASE (PERI_BASE + 0x2000) #define UART_BAUDRATE (921600) #define UART_CLOCK (26000000) /******************************************************************************* * System counter frequency related constants ******************************************************************************/ #define SYS_COUNTER_FREQ_IN_TICKS 13000000 #define SYS_COUNTER_FREQ_IN_MHZ (SYS_COUNTER_FREQ_IN_TICKS/1000000) /******************************************************************************* * GIC-400 & interrupt handling related constants ******************************************************************************/ /* Base MTK_platform compatible GIC memory map */ #define BASE_GICD_BASE (MT_GIC_BASE+0x1000) #define BASE_GICC_BASE (MT_GIC_BASE + 0x2000) #define BASE_GICR_BASE (MT_GIC_BASE + 0x200000) #define BASE_GICH_BASE (MT_GIC_BASE + 0x4000) #define BASE_GICV_BASE (MT_GIC_BASE + 0x6000) #define INT_POL_CTL0 0x10200620 #define GIC_PRIVATE_SIGNALS (32) /******************************************************************************* * CCI-400 related constants ******************************************************************************/ #define PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX 4 #define PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX 3 /******************************************************************************* * WDT Registers ******************************************************************************/ #define MTK_WDT_BASE (RGU_BASE) #define MTK_WDT_SIZE (0x1000) #define MTK_WDT_MODE (MTK_WDT_BASE+0x0000) #define MTK_WDT_LENGTH (MTK_WDT_BASE+0x0004) #define MTK_WDT_RESTART (MTK_WDT_BASE+0x0008) #define MTK_WDT_STATUS (MTK_WDT_BASE+0x000C) #define MTK_WDT_INTERVAL (MTK_WDT_BASE+0x0010) #define MTK_WDT_SWRST (MTK_WDT_BASE+0x0014) #define MTK_WDT_SWSYSRST (MTK_WDT_BASE+0x0018) #define MTK_WDT_NONRST_REG (MTK_WDT_BASE+0x0020) #define MTK_WDT_NONRST_REG2 (MTK_WDT_BASE+0x0024) #define MTK_WDT_REQ_MODE (MTK_WDT_BASE+0x0030) #define MTK_WDT_REQ_IRQ_EN (MTK_WDT_BASE+0x0034) #define MTK_WDT_DEBUG_CTL (MTK_WDT_BASE+0x0040) /*WDT_STATUS*/ #define MTK_WDT_STATUS_HWWDT_RST (0x80000000) #define MTK_WDT_STATUS_SWWDT_RST (0x40000000) #define MTK_WDT_STATUS_IRQWDT_RST (0x20000000) #define MTK_WDT_STATUS_DEBUGWDT_RST (0x00080000) #define MTK_WDT_STATUS_SPMWDT_RST (0x0002) #define MTK_WDT_STATUS_SPM_THERMAL_RST (0x0001) #define MTK_WDT_STATUS_THERMAL_DIRECT_RST (1<<18) #define MTK_WDT_STATUS_SECURITY_RST (1<<28) #define MTK_WDT_MODE_DUAL_MODE 0x0040 #define MTK_WDT_MODE_IRQ 0x0008 #define MTK_WDT_MODE_KEY 0x22000000 #define MTK_WDT_MODE_EXTEN 0x0004 #define MTK_WDT_SWRST_KEY 0x1209 #define MTK_WDT_RESTART_KEY (0x1971) /* FIQ platform related define */ #define MT_IRQ_SEC_SGI_0 8 #define MT_IRQ_SEC_SGI_1 9 #define MT_IRQ_SEC_SGI_2 10 #define MT_IRQ_SEC_SGI_3 11 #define MT_IRQ_SEC_SGI_4 12 #define MT_IRQ_SEC_SGI_5 13 #define MT_IRQ_SEC_SGI_6 14 #define MT_IRQ_SEC_SGI_7 15 #define FIQ_SMP_CALL_SGI MT_IRQ_SEC_SGI_5 /******************************************************************************* * Platform binary types for linking ******************************************************************************/ #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 /******************************************************************************* * Generic platform constants ******************************************************************************/ /* Size of cacheable stacks */ #if defined(IMAGE_BL1) #define PLATFORM_STACK_SIZE 0x440 #elif defined(IMAGE_BL2) #define PLATFORM_STACK_SIZE 0x400 #elif defined(IMAGE_BL31) #define PLATFORM_STACK_SIZE 0x800 #elif defined(IMAGE_BL32) #define PLATFORM_STACK_SIZE 0x440 #endif #define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n" #define PLAT_MAX_PWR_LVL U(2) /* MPIDR_AFFLVL2 */ #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE U(2) #define PLATFORM_CACHE_LINE_SIZE 64 #define PLATFORM_SYSTEM_COUNT 1 #define PLATFORM_CLUSTER_COUNT 2 #define PLATFORM_CLUSTER0_CORE_COUNT 4 #define PLATFORM_CLUSTER1_CORE_COUNT 4 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \ PLATFORM_CLUSTER0_CORE_COUNT) #define PLATFORM_MAX_CPUS_PER_CLUSTER 4 #define PLATFORM_NUM_AFFS (PLATFORM_SYSTEM_COUNT + \ PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) /******************************************************************************* * Platform memory map related constants ******************************************************************************/ /* ATF Argument */ #define ATF_ARG_SIZE (0x800) /* TF txet, ro, rw, internal SRAM, Size: release: 80KB, debug: 92KB */ #define TZRAM_BASE (0x110000) #if DEBUG #define TZRAM_SIZE (0x1C400) #else #define TZRAM_SIZE (0x1C400) #endif #define TZRAM2_BASE 0x00100000 #define TZRAM2_SIZE 0xDC00 #define TZRAM2_LIMIT (TZRAM2_BASE + TZRAM2_SIZE) #define RAM_CONSOLE_BASE 0x0012D000 #define RAM_CONSOLE_SIZE 0x00001000 /******************************************************************************* * BL31 specific defines. ******************************************************************************/ /* * Put BL3-1 at the top of the Trusted SRAM (just below the shared memory, if * present). BL31_BASE is calculated using the current BL3-1 debug size plus a * little space for growth. */ #define BL31_BASE (TZRAM_BASE + 0x1000) #define BL31_LIMIT (TZRAM_BASE + TZRAM_SIZE) #define BSS1_STACK_LIMIT (TZRAM_BASE + TZRAM_SIZE) #define BL31_TZRAM_SIZE (TZRAM_SIZE - ATF_ARG_SIZE) /******************************************************************************* * Platform specific page table and MMU setup constants ******************************************************************************/ #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define MAX_XLAT_TABLES 7 #define MAX_MMAP_REGIONS 16 /******************************************************************************* * CCI-400 related constants ******************************************************************************/ #define CCI400_BASE 0x10390000 #define CCI400_SL_IFACE_CLUSTER0 4 #define CCI400_SL_IFACE_CLUSTER1 3 #define CCI400_SL_IFACE_INDEX(mpidr) (mpidr & MPIDR_CLUSTER_MASK ? \ CCI400_SL_IFACE_CLUSTER1 : \ CCI400_SL_IFACE_CLUSTER0) #define CCI_SEC_ACCESS_OFFSET (0x8) /******************************************************************************* * Declarations and constants to access the mailboxes safely. Each mailbox is * aligned on the biggest cache line size in the platform. This is known only * to the platform as it might have a combination of integrated and external * caches. Such alignment ensures that two maiboxes do not sit on the same cache * line at any cache level. They could belong to different cpus/clusters & * get written while being protected by different locks causing corruption of * a valid mailbox address. ******************************************************************************/ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) #define BL32_BASE (0x0) /* * Load address of BL3-3 for this platform port */ #define LK_SIZE_LIMIT (0x100000) #define PLAT_MTK_NS_IMAGE_OFFSET (0x41E00000) /* 16KB */ #define ATF_AEE_BUFFER_SIZE (0x4000) #define PAGE_SIZE_2MB_MASK (PAGE_SIZE_2MB - 1) #define IS_PAGE_2MB_ALIGNED(addr) (((addr) & PAGE_SIZE_2MB_MASK) == 0) #define PAGE_SIZE_2MB (1 << PAGE_SIZE_2MB_SHIFT) #define PAGE_SIZE_2MB_SHIFT TWO_MB_SHIFT #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/mediatek/mt6795/include/power_tracer.h000066400000000000000000000006141355360272700251000ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef POWER_TRACER_H #define POWER_TRACER_H #define CPU_UP 0 #define CPU_DOWN 1 #define CPU_SUSPEND 2 #define CLUSTER_UP 3 #define CLUSTER_DOWN 4 #define CLUSTER_SUSPEND 5 void trace_power_flow(unsigned long mpidr, unsigned char mode); #endif /* POWER_TRACER_H */ trusted-firmware-a-2.2/plat/mediatek/mt6795/include/scu.h000066400000000000000000000003741355360272700232010ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SCU_H #define SCU_H void disable_scu(unsigned long mpidr); void enable_scu(unsigned long mpidr); #endif /* SCU_H */ trusted-firmware-a-2.2/plat/mediatek/mt6795/include/spm.h000066400000000000000000000170731355360272700232120ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPM_H #define SPM_H #define SPM_POWERON_CONFIG_SET (SPM_BASE + 0x000) #define SPM_POWER_ON_VAL0 (SPM_BASE + 0x010) #define SPM_POWER_ON_VAL1 (SPM_BASE + 0x014) #define SPM_CLK_SETTLE (SPM_BASE + 0x100) #define SPM_CA7_CPU1_PWR_CON (SPM_BASE + 0x218) #define SPM_CA7_CPU2_PWR_CON (SPM_BASE + 0x21c) #define SPM_CA7_CPU3_PWR_CON (SPM_BASE + 0x220) #define SPM_CA7_CPU1_L1_PDN (SPM_BASE + 0x264) #define SPM_CA7_CPU2_L1_PDN (SPM_BASE + 0x26c) #define SPM_CA7_CPU3_L1_PDN (SPM_BASE + 0x274) #define SPM_MD32_SRAM_CON (SPM_BASE + 0x2c8) #define SPM_PCM_CON0 (SPM_BASE + 0x310) #define SPM_PCM_CON1 (SPM_BASE + 0x314) #define SPM_PCM_IM_PTR (SPM_BASE + 0x318) #define SPM_PCM_IM_LEN (SPM_BASE + 0x31c) #define SPM_PCM_REG_DATA_INI (SPM_BASE + 0x320) #define SPM_PCM_EVENT_VECTOR0 (SPM_BASE + 0x340) #define SPM_PCM_EVENT_VECTOR1 (SPM_BASE + 0x344) #define SPM_PCM_EVENT_VECTOR2 (SPM_BASE + 0x348) #define SPM_PCM_EVENT_VECTOR3 (SPM_BASE + 0x34c) #define SPM_PCM_MAS_PAUSE_MASK (SPM_BASE + 0x354) #define SPM_PCM_PWR_IO_EN (SPM_BASE + 0x358) #define SPM_PCM_TIMER_VAL (SPM_BASE + 0x35c) #define SPM_PCM_TIMER_OUT (SPM_BASE + 0x360) #define SPM_PCM_REG0_DATA (SPM_BASE + 0x380) #define SPM_PCM_REG1_DATA (SPM_BASE + 0x384) #define SPM_PCM_REG2_DATA (SPM_BASE + 0x388) #define SPM_PCM_REG3_DATA (SPM_BASE + 0x38c) #define SPM_PCM_REG4_DATA (SPM_BASE + 0x390) #define SPM_PCM_REG5_DATA (SPM_BASE + 0x394) #define SPM_PCM_REG6_DATA (SPM_BASE + 0x398) #define SPM_PCM_REG7_DATA (SPM_BASE + 0x39c) #define SPM_PCM_REG8_DATA (SPM_BASE + 0x3a0) #define SPM_PCM_REG9_DATA (SPM_BASE + 0x3a4) #define SPM_PCM_REG10_DATA (SPM_BASE + 0x3a8) #define SPM_PCM_REG11_DATA (SPM_BASE + 0x3ac) #define SPM_PCM_REG12_DATA (SPM_BASE + 0x3b0) #define SPM_PCM_REG13_DATA (SPM_BASE + 0x3b4) #define SPM_PCM_REG14_DATA (SPM_BASE + 0x3b8) #define SPM_PCM_REG15_DATA (SPM_BASE + 0x3bc) #define SPM_PCM_EVENT_REG_STA (SPM_BASE + 0x3c0) #define SPM_PCM_FSM_STA (SPM_BASE + 0x3c4) #define SPM_PCM_IM_HOST_RW_PTR (SPM_BASE + 0x3c8) #define SPM_PCM_IM_HOST_RW_DAT (SPM_BASE + 0x3cc) #define SPM_PCM_EVENT_VECTOR4 (SPM_BASE + 0x3d0) #define SPM_PCM_EVENT_VECTOR5 (SPM_BASE + 0x3d4) #define SPM_PCM_EVENT_VECTOR6 (SPM_BASE + 0x3d8) #define SPM_PCM_EVENT_VECTOR7 (SPM_BASE + 0x3dc) #define SPM_PCM_SW_INT_SET (SPM_BASE + 0x3e0) #define SPM_PCM_SW_INT_CLEAR (SPM_BASE + 0x3e4) #define SPM_CLK_CON (SPM_BASE + 0x400) #define SPM_SLEEP_PTPOD2_CON (SPM_BASE + 0x408) #define SPM_APMCU_PWRCTL (SPM_BASE + 0x600) #define SPM_AP_DVFS_CON_SET (SPM_BASE + 0x604) #define SPM_AP_STANBY_CON (SPM_BASE + 0x608) #define SPM_PWR_STATUS (SPM_BASE + 0x60c) #define SPM_PWR_STATUS_2ND (SPM_BASE + 0x610) #define SPM_AP_BSI_REQ (SPM_BASE + 0x614) #define SPM_SLEEP_TIMER_STA (SPM_BASE + 0x720) #define SPM_SLEEP_WAKEUP_EVENT_MASK (SPM_BASE + 0x810) #define SPM_SLEEP_CPU_WAKEUP_EVENT (SPM_BASE + 0x814) #define SPM_SLEEP_MD32_WAKEUP_EVENT_MASK (SPM_BASE + 0x818) #define SPM_PCM_WDT_TIMER_VAL (SPM_BASE + 0x824) #define SPM_PCM_WDT_TIMER_OUT (SPM_BASE + 0x828) #define SPM_PCM_MD32_MAILBOX (SPM_BASE + 0x830) #define SPM_PCM_MD32_IRQ (SPM_BASE + 0x834) #define SPM_SLEEP_ISR_MASK (SPM_BASE + 0x900) #define SPM_SLEEP_ISR_STATUS (SPM_BASE + 0x904) #define SPM_SLEEP_ISR_RAW_STA (SPM_BASE + 0x910) #define SPM_SLEEP_MD32_ISR_RAW_STA (SPM_BASE + 0x914) #define SPM_SLEEP_WAKEUP_MISC (SPM_BASE + 0x918) #define SPM_SLEEP_BUS_PROTECT_RDY (SPM_BASE + 0x91c) #define SPM_SLEEP_SUBSYS_IDLE_STA (SPM_BASE + 0x920) #define SPM_PCM_RESERVE (SPM_BASE + 0xb00) #define SPM_PCM_RESERVE2 (SPM_BASE + 0xb04) #define SPM_PCM_FLAGS (SPM_BASE + 0xb08) #define SPM_PCM_SRC_REQ (SPM_BASE + 0xb0c) #define SPM_PCM_DEBUG_CON (SPM_BASE + 0xb20) #define SPM_CA7_CPU0_IRQ_MASK (SPM_BASE + 0xb30) #define SPM_CA7_CPU1_IRQ_MASK (SPM_BASE + 0xb34) #define SPM_CA7_CPU2_IRQ_MASK (SPM_BASE + 0xb38) #define SPM_CA7_CPU3_IRQ_MASK (SPM_BASE + 0xb3c) #define SPM_CA15_CPU0_IRQ_MASK (SPM_BASE + 0xb40) #define SPM_CA15_CPU1_IRQ_MASK (SPM_BASE + 0xb44) #define SPM_CA15_CPU2_IRQ_MASK (SPM_BASE + 0xb48) #define SPM_CA15_CPU3_IRQ_MASK (SPM_BASE + 0xb4c) #define SPM_PCM_PASR_DPD_0 (SPM_BASE + 0xb60) #define SPM_PCM_PASR_DPD_1 (SPM_BASE + 0xb64) #define SPM_PCM_PASR_DPD_2 (SPM_BASE + 0xb68) #define SPM_PCM_PASR_DPD_3 (SPM_BASE + 0xb6c) #define SPM_SLEEP_CA7_WFI0_EN (SPM_BASE + 0xf00) #define SPM_SLEEP_CA7_WFI1_EN (SPM_BASE + 0xf04) #define SPM_SLEEP_CA7_WFI2_EN (SPM_BASE + 0xf08) #define SPM_SLEEP_CA7_WFI3_EN (SPM_BASE + 0xf0c) #define SPM_SLEEP_CA15_WFI0_EN (SPM_BASE + 0xf10) #define SPM_SLEEP_CA15_WFI1_EN (SPM_BASE + 0xf14) #define SPM_SLEEP_CA15_WFI2_EN (SPM_BASE + 0xf18) #define SPM_SLEEP_CA15_WFI3_EN (SPM_BASE + 0xf1c) #define SPM_PROJECT_CODE 0xb16 #define SPM_REGWR_EN (1U << 0) #define SPM_REGWR_CFG_KEY (SPM_PROJECT_CODE << 16) #define SPM_CPU_PDN_DIS (1U << 0) #define SPM_INFRA_PDN_DIS (1U << 1) #define SPM_DDRPHY_PDN_DIS (1U << 2) #define SPM_DUALVCORE_PDN_DIS (1U << 3) #define SPM_PASR_DIS (1U << 4) #define SPM_DPD_DIS (1U << 5) #define SPM_SODI_DIS (1U << 6) #define SPM_MEMPLL_RESET (1U << 7) #define SPM_MAINPLL_PDN_DIS (1U << 8) #define SPM_CPU_DVS_DIS (1U << 9) #define SPM_CPU_DORMANT (1U << 10) #define SPM_EXT_VSEL_GPIO103 (1U << 11) #define SPM_DDR_HIGH_SPEED (1U << 12) #define SPM_OPT (1U << 13) #define POWER_ON_VAL1_DEF 0x01011820 #define PCM_FSM_STA_DEF 0x48490 #define PCM_END_FSM_STA_DEF 0x08490 #define PCM_END_FSM_STA_MASK 0x3fff0 #define PCM_HANDSHAKE_SEND1 0xbeefbeef #define PCM_WDT_TIMEOUT (30 * 32768) #define PCM_TIMER_MAX (0xffffffff - PCM_WDT_TIMEOUT) #define CON0_PCM_KICK (1U << 0) #define CON0_IM_KICK (1U << 1) #define CON0_IM_SLEEP_DVS (1U << 3) #define CON0_PCM_SW_RESET (1U << 15) #define CON0_CFG_KEY (SPM_PROJECT_CODE << 16) #define CON1_IM_SLAVE (1U << 0) #define CON1_MIF_APBEN (1U << 3) #define CON1_PCM_TIMER_EN (1U << 5) #define CON1_IM_NONRP_EN (1U << 6) #define CON1_PCM_WDT_EN (1U << 8) #define CON1_PCM_WDT_WAKE_MODE (1U << 9) #define CON1_SPM_SRAM_SLP_B (1U << 10) #define CON1_SPM_SRAM_ISO_B (1U << 11) #define CON1_EVENT_LOCK_EN (1U << 12) #define CON1_CFG_KEY (SPM_PROJECT_CODE << 16) #define PCM_PWRIO_EN_R0 (1U << 0) #define PCM_PWRIO_EN_R7 (1U << 7) #define PCM_RF_SYNC_R0 (1U << 16) #define PCM_RF_SYNC_R2 (1U << 18) #define PCM_RF_SYNC_R6 (1U << 22) #define PCM_RF_SYNC_R7 (1U << 23) #define CC_SYSCLK0_EN_0 (1U << 0) #define CC_SYSCLK0_EN_1 (1U << 1) #define CC_SYSCLK1_EN_0 (1U << 2) #define CC_SYSCLK1_EN_1 (1U << 3) #define CC_SYSSETTLE_SEL (1U << 4) #define CC_LOCK_INFRA_DCM (1U << 5) #define CC_SRCLKENA_MASK_0 (1U << 6) #define CC_CXO32K_RM_EN_MD1 (1U << 9) #define CC_CXO32K_RM_EN_MD2 (1U << 10) #define CC_CLKSQ1_SEL (1U << 12) #define CC_DISABLE_DORM_PWR (1U << 14) #define CC_MD32_DCM_EN (1U << 18) #define WFI_OP_AND 1 #define WFI_OP_OR 0 #define WAKE_MISC_PCM_TIMER (1U << 19) #define WAKE_MISC_CPU_WAKE (1U << 20) /* define WAKE_SRC_XXX */ #define WAKE_SRC_SPM_MERGE (1 << 0) #define WAKE_SRC_KP (1 << 2) #define WAKE_SRC_WDT (1 << 3) #define WAKE_SRC_GPT (1 << 4) #define WAKE_SRC_EINT (1 << 6) #define WAKE_SRC_LOW_BAT (1 << 9) #define WAKE_SRC_MD32 (1 << 10) #define WAKE_SRC_USB_CD (1 << 14) #define WAKE_SRC_USB_PDN (1 << 15) #define WAKE_SRC_AFE (1 << 20) #define WAKE_SRC_THERM (1 << 21) #define WAKE_SRC_SYSPWREQ (1 << 24) #define WAKE_SRC_SEJ (1 << 27) #define WAKE_SRC_ALL_MD32 (1 << 28) #define WAKE_SRC_CPU_IRQ (1 << 29) #endif /* SPM_H */ trusted-firmware-a-2.2/plat/mediatek/mt6795/plat_delay_timer.c000066400000000000000000000013161355360272700242720ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include static uint32_t plat_get_timer_value(void) { /* * Generic delay timer implementation expects the timer to be a down * counter. We apply bitwise NOT operator to the tick values returned * by read_cntpct_el0() to simulate the down counter. */ return (uint32_t)(~read_cntpct_el0()); } static const timer_ops_t plat_timer_ops = { .get_timer_value = plat_get_timer_value, .clk_mult = 1, .clk_div = SYS_COUNTER_FREQ_IN_MHZ, }; void plat_delay_timer_init(void) { timer_init(&plat_timer_ops); } trusted-firmware-a-2.2/plat/mediatek/mt6795/plat_mt_gic.c000066400000000000000000000017471355360272700232460ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include static const interrupt_prop_t g0_interrupt_props[] = { INTR_PROP_DESC(FIQ_SMP_CALL_SGI, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), }; gicv2_driver_data_t arm_gic_data = { .gicd_base = BASE_GICD_BASE, .gicc_base = BASE_GICC_BASE, .interrupt_props = g0_interrupt_props, .interrupt_props_num = ARRAY_SIZE(g0_interrupt_props), }; void plat_mt_gic_driver_init(void) { gicv2_driver_init(&arm_gic_data); } void plat_mt_gic_init(void) { gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } void plat_mt_gic_cpuif_enable(void) { gicv2_cpuif_enable(); } void plat_mt_gic_cpuif_disable(void) { gicv2_cpuif_disable(); } void plat_mt_gic_pcpu_init(void) { gicv2_pcpu_distif_init(); } trusted-firmware-a-2.2/plat/mediatek/mt6795/plat_pm.c000066400000000000000000000333301355360272700224110ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct core_context { unsigned long timer_data[8]; unsigned int count; unsigned int rst; unsigned int abt; unsigned int brk; }; struct cluster_context { struct core_context core[PLATFORM_MAX_CPUS_PER_CLUSTER]; }; /* * Top level structure to hold the complete context of a multi cluster system */ struct system_context { struct cluster_context cluster[PLATFORM_CLUSTER_COUNT]; }; /* * Top level structure which encapsulates the context of the entire system */ static struct system_context dormant_data[1]; static inline struct cluster_context *system_cluster( struct system_context *system, uint32_t clusterid) { return &system->cluster[clusterid]; } static inline struct core_context *cluster_core(struct cluster_context *cluster, uint32_t cpuid) { return &cluster->core[cpuid]; } static struct cluster_context *get_cluster_data(unsigned long mpidr) { uint32_t clusterid; clusterid = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS; return system_cluster(dormant_data, clusterid); } static struct core_context *get_core_data(unsigned long mpidr) { struct cluster_context *cluster; uint32_t cpuid; cluster = get_cluster_data(mpidr); cpuid = mpidr & MPIDR_CPU_MASK; return cluster_core(cluster, cpuid); } static void mt_save_generic_timer(unsigned long *container) { uint64_t ctl; uint64_t val; __asm__ volatile("mrs %x0, cntkctl_el1\n\t" "mrs %x1, cntp_cval_el0\n\t" "stp %x0, %x1, [%2, #0]" : "=&r" (ctl), "=&r" (val) : "r" (container) : "memory"); __asm__ volatile("mrs %x0, cntp_tval_el0\n\t" "mrs %x1, cntp_ctl_el0\n\t" "stp %x0, %x1, [%2, #16]" : "=&r" (val), "=&r" (ctl) : "r" (container) : "memory"); __asm__ volatile("mrs %x0, cntv_tval_el0\n\t" "mrs %x1, cntv_ctl_el0\n\t" "stp %x0, %x1, [%2, #32]" : "=&r" (val), "=&r" (ctl) : "r" (container) : "memory"); } static void mt_restore_generic_timer(unsigned long *container) { uint64_t ctl; uint64_t val; __asm__ volatile("ldp %x0, %x1, [%2, #0]\n\t" "msr cntkctl_el1, %x0\n\t" "msr cntp_cval_el0, %x1" : "=&r" (ctl), "=&r" (val) : "r" (container) : "memory"); __asm__ volatile("ldp %x0, %x1, [%2, #16]\n\t" "msr cntp_tval_el0, %x0\n\t" "msr cntp_ctl_el0, %x1" : "=&r" (val), "=&r" (ctl) : "r" (container) : "memory"); __asm__ volatile("ldp %x0, %x1, [%2, #32]\n\t" "msr cntv_tval_el0, %x0\n\t" "msr cntv_ctl_el0, %x1" : "=&r" (val), "=&r" (ctl) : "r" (container) : "memory"); } static void stop_generic_timer(void) { /* * Disable the timer and mask the irq to prevent * suprious interrupts on this cpu interface. It * will bite us when we come back if we don't. It * will be replayed on the inbound cluster. */ uint64_t cntpctl = read_cntp_ctl_el0(); write_cntp_ctl_el0(clr_cntp_ctl_enable(cntpctl)); } static void mt_cpu_save(unsigned long mpidr) { struct core_context *core; core = get_core_data(mpidr); mt_save_generic_timer(core->timer_data); /* disable timer irq, and upper layer should enable it again. */ stop_generic_timer(); } static void mt_cpu_restore(unsigned long mpidr) { struct core_context *core; core = get_core_data(mpidr); mt_restore_generic_timer(core->timer_data); } static void mt_platform_save_context(unsigned long mpidr) { /* mcusys_save_context: */ mt_cpu_save(mpidr); } static void mt_platform_restore_context(unsigned long mpidr) { /* mcusys_restore_context: */ mt_cpu_restore(mpidr); } /******************************************************************************* * Private function which is used to determine if any platform actions * should be performed for the specified affinity instance given its * state. Nothing needs to be done if the 'state' is not off or if this is not * the highest affinity level which will enter the 'state'. *******************************************************************************/ static int32_t plat_do_plat_actions(unsigned int afflvl, unsigned int state) { unsigned int max_phys_off_afflvl; assert(afflvl <= MPIDR_AFFLVL2); if (state != PSCI_STATE_OFF) return -EAGAIN; /* * Find the highest affinity level which will be suspended and postpone * all the platform specific actions until that level is hit. */ max_phys_off_afflvl = psci_get_max_phys_off_afflvl(); assert(max_phys_off_afflvl != PSCI_INVALID_DATA); if (afflvl != max_phys_off_afflvl) return -EAGAIN; return 0; } /******************************************************************************* * MTK_platform handler called when an affinity instance is about to enter * standby. ******************************************************************************/ static void plat_affinst_standby(unsigned int power_state) { unsigned int target_afflvl; /* Sanity check the requested state */ target_afflvl = psci_get_pstate_afflvl(power_state); /* * It's possible to enter standby only on affinity level 0 i.e. a cpu * on the MTK_platform. Ignore any other affinity level. */ if (target_afflvl == MPIDR_AFFLVL0) { /* * Enter standby state. dsb is good practice before using wfi * to enter low power states. */ dsb(); wfi(); } } /******************************************************************************* * MTK_platform handler called when an affinity instance is about to be turned * on. The level and mpidr determine the affinity instance. ******************************************************************************/ static int plat_affinst_on(unsigned long mpidr, unsigned long sec_entrypoint, unsigned int afflvl, unsigned int state) { int rc = PSCI_E_SUCCESS; unsigned long cpu_id; unsigned long cluster_id; uintptr_t rv; /* * It's possible to turn on only affinity level 0 i.e. a cpu * on the MTK_platform. Ignore any other affinity level. */ if (afflvl != MPIDR_AFFLVL0) return rc; cpu_id = mpidr & MPIDR_CPU_MASK; cluster_id = mpidr & MPIDR_CLUSTER_MASK; if (cluster_id) rv = (uintptr_t)&mt6795_mcucfg->mp1_rv_addr[cpu_id].rv_addr_lw; else rv = (uintptr_t)&mt6795_mcucfg->mp0_rv_addr[cpu_id].rv_addr_lw; mmio_write_32(rv, sec_entrypoint); INFO("mt_on[%ld:%ld], entry %x\n", cluster_id, cpu_id, mmio_read_32(rv)); return rc; } /******************************************************************************* * MTK_platform handler called when an affinity instance is about to be turned * off. The level and mpidr determine the affinity instance. The 'state' arg. * allows the platform to decide whether the cluster is being turned off and * take apt actions. * * CAUTION: This function is called with coherent stacks so that caches can be * turned off, flushed and coherency disabled. There is no guarantee that caches * will remain turned on across calls to this function as each affinity level is * dealt with. So do not write & read global variables across calls. It will be * wise to do flush a write to the global to prevent unpredictable results. ******************************************************************************/ static void plat_affinst_off(unsigned int afflvl, unsigned int state) { unsigned long mpidr = read_mpidr_el1(); /* Determine if any platform actions need to be executed. */ if (plat_do_plat_actions(afflvl, state) == -EAGAIN) return; /* Prevent interrupts from spuriously waking up this cpu */ plat_mt_gic_cpuif_disable(); trace_power_flow(mpidr, CPU_DOWN); if (afflvl != MPIDR_AFFLVL0) { /* Disable coherency if this cluster is to be turned off */ plat_cci_disable(); trace_power_flow(mpidr, CLUSTER_DOWN); } } /******************************************************************************* * MTK_platform handler called when an affinity instance is about to be * suspended. The level and mpidr determine the affinity instance. The 'state' * arg. allows the platform to decide whether the cluster is being turned off * and take apt actions. * * CAUTION: This function is called with coherent stacks so that caches can be * turned off, flushed and coherency disabled. There is no guarantee that caches * will remain turned on across calls to this function as each affinity level is * dealt with. So do not write & read global variables across calls. It will be * wise to do flush a write to the global to prevent unpredictable results. ******************************************************************************/ static void plat_affinst_suspend(unsigned long sec_entrypoint, unsigned int afflvl, unsigned int state) { unsigned long mpidr = read_mpidr_el1(); unsigned long cluster_id; unsigned long cpu_id; uintptr_t rv; /* Determine if any platform actions need to be executed. */ if (plat_do_plat_actions(afflvl, state) == -EAGAIN) return; cpu_id = mpidr & MPIDR_CPU_MASK; cluster_id = mpidr & MPIDR_CLUSTER_MASK; if (cluster_id) rv = (uintptr_t)&mt6795_mcucfg->mp1_rv_addr[cpu_id].rv_addr_lw; else rv = (uintptr_t)&mt6795_mcucfg->mp0_rv_addr[cpu_id].rv_addr_lw; mmio_write_32(rv, sec_entrypoint); if (afflvl >= MPIDR_AFFLVL0) mt_platform_save_context(mpidr); /* Perform the common cluster specific operations */ if (afflvl >= MPIDR_AFFLVL1) { /* Disable coherency if this cluster is to be turned off */ plat_cci_disable(); disable_scu(mpidr); trace_power_flow(mpidr, CLUSTER_SUSPEND); } if (afflvl >= MPIDR_AFFLVL2) { /* Prevent interrupts from spuriously waking up this cpu */ plat_mt_gic_cpuif_disable(); } } /******************************************************************************* * MTK_platform handler called when an affinity instance has just been powered * on after being turned off earlier. The level and mpidr determine the affinity * instance. The 'state' arg. allows the platform to decide whether the cluster * was turned off prior to wakeup and do what's necessary to setup it up * correctly. ******************************************************************************/ static void plat_affinst_on_finish(unsigned int afflvl, unsigned int state) { unsigned long mpidr = read_mpidr_el1(); /* Determine if any platform actions need to be executed. */ if (plat_do_plat_actions(afflvl, state) == -EAGAIN) return; /* Perform the common cluster specific operations */ if (afflvl >= MPIDR_AFFLVL1) { enable_scu(mpidr); /* Enable coherency if this cluster was off */ plat_cci_enable(); trace_power_flow(mpidr, CLUSTER_UP); } /* Enable the gic cpu interface */ plat_mt_gic_cpuif_enable(); plat_mt_gic_pcpu_init(); trace_power_flow(mpidr, CPU_UP); } /******************************************************************************* * MTK_platform handler called when an affinity instance has just been powered * on after having been suspended earlier. The level and mpidr determine the * affinity instance. ******************************************************************************/ static void plat_affinst_suspend_finish(unsigned int afflvl, unsigned int state) { unsigned long mpidr = read_mpidr_el1(); /* Determine if any platform actions need to be executed. */ if (plat_do_plat_actions(afflvl, state) == -EAGAIN) return; if (afflvl >= MPIDR_AFFLVL2) { /* Enable the gic cpu interface */ plat_mt_gic_init(); plat_mt_gic_cpuif_enable(); } /* Perform the common cluster specific operations */ if (afflvl >= MPIDR_AFFLVL1) { enable_scu(mpidr); /* Enable coherency if this cluster was off */ plat_cci_enable(); trace_power_flow(mpidr, CLUSTER_UP); } if (afflvl >= MPIDR_AFFLVL0) mt_platform_restore_context(mpidr); plat_mt_gic_pcpu_init(); } static unsigned int plat_get_sys_suspend_power_state(void) { /* StateID: 0, StateType: 1(power down), PowerLevel: 2(system) */ return psci_make_powerstate(0, 1, 2); } /******************************************************************************* * MTK handlers to shutdown/reboot the system ******************************************************************************/ static void __dead2 plat_system_off(void) { INFO("MTK System Off\n"); wfi(); ERROR("MTK System Off: operation not handled.\n"); panic(); } static void __dead2 plat_system_reset(void) { /* Write the System Configuration Control Register */ INFO("MTK System Reset\n"); mmio_clrbits_32(MTK_WDT_BASE, (MTK_WDT_MODE_DUAL_MODE | MTK_WDT_MODE_IRQ)); mmio_setbits_32(MTK_WDT_BASE, (MTK_WDT_MODE_KEY | MTK_WDT_MODE_EXTEN)); mmio_setbits_32(MTK_WDT_SWRST, MTK_WDT_SWRST_KEY); wfi(); ERROR("MTK System Reset: operation not handled.\n"); panic(); } /******************************************************************************* * Export the platform handlers to enable psci to invoke them ******************************************************************************/ static const plat_pm_ops_t plat_plat_pm_ops = { .affinst_standby = plat_affinst_standby, .affinst_on = plat_affinst_on, .affinst_off = plat_affinst_off, .affinst_suspend = plat_affinst_suspend, .affinst_on_finish = plat_affinst_on_finish, .affinst_suspend_finish = plat_affinst_suspend_finish, .system_off = plat_system_off, .system_reset = plat_system_reset, .get_sys_suspend_power_state = plat_get_sys_suspend_power_state, }; /******************************************************************************* * Export the platform specific power ops & initialize the mtk_platform power * controller ******************************************************************************/ int platform_setup_pm(const plat_pm_ops_t **plat_ops) { *plat_ops = &plat_plat_pm_ops; return 0; } trusted-firmware-a-2.2/plat/mediatek/mt6795/plat_topology.c000066400000000000000000000014631355360272700236530ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include unsigned int plat_get_aff_count(unsigned int aff_lvl, unsigned long mpidr) { /* Report 1 (absent) instance at levels higher that the cluster level */ if (aff_lvl > MPIDR_AFFLVL1) return PLATFORM_SYSTEM_COUNT; if (aff_lvl == MPIDR_AFFLVL1) return PLATFORM_CLUSTER_COUNT; return mpidr & 0x100 ? PLATFORM_CLUSTER1_CORE_COUNT : PLATFORM_CLUSTER0_CORE_COUNT; } unsigned int plat_get_aff_state(unsigned int aff_lvl, unsigned long mpidr) { return aff_lvl <= MPIDR_AFFLVL2 ? PSCI_AFF_PRESENT : PSCI_AFF_ABSENT; } int mt_setup_topology(void) { /* [TODO] Make topology configurable via SCC */ return 0; } trusted-firmware-a-2.2/plat/mediatek/mt6795/platform.mk000066400000000000000000000037141355360272700227710ustar00rootroot00000000000000# # Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # MTK_PLAT := plat/mediatek MTK_PLAT_SOC := ${MTK_PLAT}/${PLAT} # Add OEM customized codes OEMS := true MTK_SIP_KERNEL_BOOT_ENABLE := 1 ifneq (${OEMS},none) OEMS_INCLUDES := -I${MTK_PLAT}/common/custom/ OEMS_SOURCES := ${MTK_PLAT}/common/custom/oem_svc.c endif PLAT_INCLUDES := -I${MTK_PLAT}/common/ \ -I${MTK_PLAT}/common/drivers/uart \ -I${MTK_PLAT_SOC}/ \ -I${MTK_PLAT_SOC}/drivers/timer/ \ -I${MTK_PLAT_SOC}/include/ \ -Iinclude/plat/arm/common/ \ ${OEMS_INCLUDES} PLAT_BL_COMMON_SOURCES := lib/xlat_tables/aarch64/xlat_tables.c \ lib/xlat_tables/xlat_tables_common.c \ plat/common/plat_gic.c BL31_SOURCES += drivers/arm/cci/cci.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c \ drivers/console/aarch64/console.S \ drivers/delay_timer/delay_timer.c \ lib/cpus/aarch64/cortex_a53.S \ ${MTK_PLAT_SOC}/bl31_plat_setup.c \ ${MTK_PLAT_SOC}/plat_mt_gic.c \ ${MTK_PLAT}/common/mtk_sip_svc.c \ ${MTK_PLAT}/common/mtk_plat_common.c \ ${MTK_PLAT}/common/drivers/uart/8250_console.S \ ${MTK_PLAT_SOC}/aarch64/plat_helpers.S \ ${MTK_PLAT_SOC}/drivers/timer/mt_cpuxgpt.c \ ${MTK_PLAT_SOC}/plat_delay_timer.c \ ${MTK_PLAT_SOC}/plat_pm.c \ ${MTK_PLAT_SOC}/plat_topology.c \ ${MTK_PLAT_SOC}/power_tracer.c \ ${MTK_PLAT_SOC}/scu.c \ ${OEMS_SOURCES} # Enable workarounds for selected Cortex-A53 erratas. ERRATA_A53_826319 := 1 ERRATA_A53_836870 := 1 WORKAROUND_CVE_2017_5715 := 0 # indicate the reset vector address can be programmed PROGRAMMABLE_RESET_ADDRESS := 1 $(eval $(call add_define,MTK_SIP_KERNEL_BOOT_ENABLE)) # Do not enable SVE ENABLE_SVE_FOR_NS := 0 trusted-firmware-a-2.2/plat/mediatek/mt6795/power_tracer.c000066400000000000000000000023041355360272700234460ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #define trace_log(...) INFO("psci: " __VA_ARGS__) void trace_power_flow(unsigned long mpidr, unsigned char mode) { switch (mode) { case CPU_UP: trace_log("core %lld:%lld ON\n", (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS, (mpidr & MPIDR_CPU_MASK)); break; case CPU_DOWN: trace_log("core %lld:%lld OFF\n", (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS, (mpidr & MPIDR_CPU_MASK)); break; case CPU_SUSPEND: trace_log("core %lld:%lld SUSPEND\n", (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS, (mpidr & MPIDR_CPU_MASK)); break; case CLUSTER_UP: trace_log("cluster %lld ON\n", (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS); break; case CLUSTER_DOWN: trace_log("cluster %lld OFF\n", (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS); break; case CLUSTER_SUSPEND: trace_log("cluster %lld SUSPEND\n", (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS); break; default: trace_log("unknown power mode\n"); break; } } trusted-firmware-a-2.2/plat/mediatek/mt6795/scu.c000066400000000000000000000012241355360272700215440ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include void disable_scu(unsigned long mpidr) { if (mpidr & MPIDR_CLUSTER_MASK) mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp1_miscdbg, MP1_ACINACTM); else mmio_setbits_32((uintptr_t)&mt6795_mcucfg->mp0_axi_config, MP0_ACINACTM); } void enable_scu(unsigned long mpidr) { if (mpidr & MPIDR_CLUSTER_MASK) mmio_clrbits_32((uintptr_t)&mt6795_mcucfg->mp1_miscdbg, MP1_ACINACTM); else mmio_clrbits_32((uintptr_t)&mt6795_mcucfg->mp0_axi_config, MP0_ACINACTM); } trusted-firmware-a-2.2/plat/mediatek/mt8173/000077500000000000000000000000001355360272700205775ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8173/aarch64/000077500000000000000000000000001355360272700220275ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8173/aarch64/plat_helpers.S000066400000000000000000000025561355360272700246450ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl plat_secondary_cold_boot_setup .globl plat_report_exception .globl platform_is_primary_cpu .globl plat_my_core_pos /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions * needed for a secondary cpu after a cold reset e.g * mark the cpu's presence, mechanism to place it in a * holding pen etc. * ----------------------------------------------------- */ func plat_secondary_cold_boot_setup /* MT8173 Oak does not do cold boot for secondary CPU */ cb_panic: b cb_panic endfunc plat_secondary_cold_boot_setup func platform_is_primary_cpu and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) cmp x0, #MT8173_PRIMARY_CPU cset x0, eq ret endfunc platform_is_primary_cpu /* ----------------------------------------------------- * unsigned int plat_my_core_pos(void); * * result: CorePos = CoreId + (ClusterId << 2) * ----------------------------------------------------- */ func plat_my_core_pos mrs x0, mpidr_el1 and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 ret endfunc plat_my_core_pos trusted-firmware-a-2.2/plat/mediatek/mt8173/aarch64/platform_common.c000066400000000000000000000046511355360272700253750ustar00rootroot00000000000000/* * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include static const int cci_map[] = { PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX, PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX }; /* Table of regions to map using the MMU. */ const mmap_region_t plat_mmap[] = { /* for TF text, RO, RW */ MAP_REGION_FLAT(TZRAM_BASE, TZRAM_SIZE, MT_MEMORY | MT_RW | MT_SECURE), MAP_REGION_FLAT(MTK_DEV_RNG0_BASE, MTK_DEV_RNG0_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(MTK_DEV_RNG1_BASE, MTK_DEV_RNG1_SIZE, MT_DEVICE | MT_RW | MT_SECURE), { 0 } }; /******************************************************************************* * Macro generating the code for the function setting up the pagetables as per * the platform memory map & initialize the mmu, for the given exception level ******************************************************************************/ #define DEFINE_CONFIGURE_MMU_EL(_el) \ void plat_configure_mmu_el ## _el(unsigned long total_base, \ unsigned long total_size, \ unsigned long ro_start, \ unsigned long ro_limit, \ unsigned long coh_start, \ unsigned long coh_limit) \ { \ mmap_add_region(total_base, total_base, \ total_size, \ MT_MEMORY | MT_RW | MT_SECURE); \ mmap_add_region(ro_start, ro_start, \ ro_limit - ro_start, \ MT_MEMORY | MT_RO | MT_SECURE); \ mmap_add_region(coh_start, coh_start, \ coh_limit - coh_start, \ MT_DEVICE | MT_RW | MT_SECURE); \ mmap_add(plat_mmap); \ init_xlat_tables(); \ \ enable_mmu_el ## _el(0); \ } /* Define EL3 variants of the function initialising the MMU */ DEFINE_CONFIGURE_MMU_EL(3) unsigned int plat_get_syscnt_freq2(void) { return SYS_COUNTER_FREQ_IN_TICKS; } void plat_cci_init(void) { /* Initialize CCI driver */ cci_init(PLAT_MT_CCI_BASE, cci_map, ARRAY_SIZE(cci_map)); } void plat_cci_enable(void) { /* * Enable CCI coherency for this cluster. * No need for locks as no other cpu is active at the moment. */ cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr())); } void plat_cci_disable(void) { cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr())); } trusted-firmware-a-2.2/plat/mediatek/mt8173/bl31_plat_setup.c000066400000000000000000000114441355360272700237500ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static entry_point_info_t bl32_ep_info; static entry_point_info_t bl33_ep_info; static void platform_setup_cpu(void) { /* turn off all the little core's power except cpu 0 */ mtcmos_little_cpu_off(); /* setup big cores */ mmio_write_32((uintptr_t)&mt8173_mcucfg->mp1_config_res, MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK | MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK | MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK | MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK | MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK); mmio_setbits_32((uintptr_t)&mt8173_mcucfg->mp1_miscdbg, MP1_AINACTS); mmio_setbits_32((uintptr_t)&mt8173_mcucfg->mp1_clkenm_div, MP1_SW_CG_GEN); mmio_clrbits_32((uintptr_t)&mt8173_mcucfg->mp1_rst_ctl, MP1_L2RSTDISABLE); /* set big cores arm64 boot mode */ mmio_setbits_32((uintptr_t)&mt8173_mcucfg->mp1_cpucfg, MP1_CPUCFG_64BIT); /* set LITTLE cores arm64 boot mode */ mmio_setbits_32((uintptr_t)&mt8173_mcucfg->mp0_rv_addr[0].rv_addr_hw, MP0_CPUCFG_64BIT); /* enable dcm control */ mmio_setbits_32((uintptr_t)&mt8173_mcucfg->bus_fabric_dcm_ctrl, ADB400_GRP_DCM_EN | CCI400_GRP_DCM_EN | ADBCLK_GRP_DCM_EN | EMICLK_GRP_DCM_EN | ACLK_GRP_DCM_EN | L2C_IDLE_DCM_EN | INFRACLK_PSYS_DYNAMIC_CG_EN); mmio_setbits_32((uintptr_t)&mt8173_mcucfg->l2c_sram_ctrl, L2C_SRAM_DCM_EN); mmio_setbits_32((uintptr_t)&mt8173_mcucfg->cci_clk_ctrl, MCU_BUS_DCM_EN); } static void platform_setup_sram(void) { /* protect BL31 memory from non-secure read/write access */ mmio_write_32(SRAMROM_SEC_ADDR, (uint32_t)(BL31_END + 0x3ff) & 0x3fc00); mmio_write_32(SRAMROM_SEC_CTRL, 0x10000ff9); } /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for * the security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. ******************************************************************************/ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; next_image_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info; assert(next_image_info->h.type == PARAM_EP); /* None of the images on this platform can have 0x0 as the entrypoint */ if (next_image_info->pc) return next_image_info; else return NULL; } /******************************************************************************* * Perform any BL3-1 early platform setup. Here is an opportunity to copy * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before they * are lost (potentially). This needs to be done before the MMU is initialized * so that the memory layout can be used while creating page tables. * BL2 has flushed this information to memory, so we are guaranteed to pick up * good data. ******************************************************************************/ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { static console_16550_t console; console_16550_register(MT8173_UART0_BASE, MT8173_UART_CLOCK, MT8173_BAUDRATE, &console); VERBOSE("bl31_setup\n"); bl31_params_parse_helper(arg0, &bl32_ep_info, &bl33_ep_info); } /******************************************************************************* * Perform any BL3-1 platform setup code ******************************************************************************/ void bl31_platform_setup(void) { platform_setup_cpu(); platform_setup_sram(); generic_delay_timer_init(); /* Initialize the gic cpu and distributor interfaces */ plat_arm_gic_driver_init(); plat_arm_gic_init(); /* Initialize spm at boot time */ spm_boot_init(); } /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this is only intializes the mmu in a quick and dirty way. ******************************************************************************/ void bl31_plat_arch_setup(void) { plat_cci_init(); plat_cci_enable(); plat_configure_mmu_el3(BL_CODE_BASE, BL_COHERENT_RAM_END - BL_CODE_BASE, BL_CODE_BASE, BL_CODE_END, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); } trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/000077500000000000000000000000001355360272700222555ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/crypt/000077500000000000000000000000001355360272700234165ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/crypt/crypt.c000066400000000000000000000054411355360272700247270ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #define crypt_read32(offset) \ mmio_read_32((uintptr_t)(CRYPT_BASE+((offset) * 4))) #define crypt_write32(offset, value) \ mmio_write_32((uintptr_t)(CRYPT_BASE + ((offset) * 4)), (uint32_t)value) #define GET_L32(x) ((uint32_t)(x & 0xffffffff)) #define GET_H32(x) ((uint32_t)((x >> 32) & 0xffffffff)) #define REG_INIT 0 #define REG_MSC 4 #define REG_TRIG 256 #define REG_STAT 512 #define REG_CLR 513 #define REG_INT 514 #define REG_P68 768 #define REG_P69 769 #define REG_P70 770 #define REG_P71 771 #define REG_P72 772 #define REG_D20 820 #define KEY_SIZE 160 #define KEY_LEN 40 /* Wait until crypt is completed */ uint64_t crypt_wait(void) { crypt_write32(REG_TRIG, 0); while (crypt_read32(REG_STAT) == 0) ; udelay(100); crypt_write32(REG_CLR, crypt_read32(REG_STAT)); crypt_write32(REG_INT, 0); return MTK_SIP_E_SUCCESS; } static uint32_t record[4]; /* Copy encrypted key to crypt engine */ uint64_t crypt_set_hdcp_key_ex(uint64_t x1, uint64_t x2, uint64_t x3) { uint32_t i = (uint32_t)x1; uint32_t j = 0; if (i > KEY_LEN) return MTK_SIP_E_INVALID_PARAM; if (i < KEY_LEN) { crypt_write32(REG_MSC, 0x80ff3800); crypt_write32(REG_INIT, 0); crypt_write32(REG_INIT, 0xF); crypt_write32(REG_CLR, 1); crypt_write32(REG_INT, 0); crypt_write32(REG_P68, 0x70); crypt_write32(REG_P69, 0x1C0); crypt_write32(REG_P70, 0x30); crypt_write32(REG_P71, 0x4); crypt_wait(); crypt_write32(REG_D20 + 4 * i, GET_L32(x2)); crypt_write32(REG_D20 + 4 * i + 1, GET_H32(x2)); crypt_write32(REG_D20 + 4 * i + 2, GET_L32(x3)); crypt_write32(REG_D20 + 4 * i + 3, GET_H32(x3)); crypt_write32(REG_P69, 0); crypt_write32(REG_P68, 0x20); crypt_write32(REG_P71, 0x34 + 4 * i); crypt_write32(REG_P72, 0x34 + 4 * i); crypt_wait(); for (j = 0; j < 4; j++) { crypt_write32(REG_P68, 0x71); crypt_write32(REG_P69, 0x34 + 4 * i + j); crypt_write32(REG_P70, record[j]); crypt_wait(); } } /* Prepare data for next iteration */ record[0] = GET_L32(x2); record[1] = GET_H32(x2); record[2] = GET_L32(x3); record[3] = GET_H32(x3); return MTK_SIP_E_SUCCESS; } /* Set key to hdcp */ uint64_t crypt_set_hdcp_key_num(uint32_t num) { if (num > KEY_LEN) return MTK_SIP_E_INVALID_PARAM; crypt_write32(REG_P68, 0x6A); crypt_write32(REG_P69, 0x34 + 4 * num); crypt_wait(); return MTK_SIP_E_SUCCESS; } /* Clear key in crypt engine */ uint64_t crypt_clear_hdcp_key(void) { uint32_t i; for (i = 0; i < KEY_SIZE; i++) crypt_write32(REG_D20 + i, 0); return MTK_SIP_E_SUCCESS; } trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/crypt/crypt.h000066400000000000000000000006031355360272700247270ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CRYPT_H #define CRYPT_H #include /* crypt function prototype */ uint64_t crypt_set_hdcp_key_ex(uint64_t x1, uint64_t x2, uint64_t x3); uint64_t crypt_set_hdcp_key_num(uint32_t num); uint64_t crypt_clear_hdcp_key(void); #endif /* CRYPT_H */ trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/mtcmos/000077500000000000000000000000001355360272700235575ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/mtcmos/mtcmos.c000066400000000000000000000151731355360272700252340ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include enum { SRAM_ISOINT_B = 1U << 6, SRAM_CKISO = 1U << 5, PWR_CLK_DIS = 1U << 4, PWR_ON_2ND = 1U << 3, PWR_ON = 1U << 2, PWR_ISO = 1U << 1, PWR_RST_B = 1U << 0 }; enum { L1_PDN_ACK = 1U << 8, L1_PDN = 1U << 0 }; enum { LITTLE_CPU3 = 1U << 12, LITTLE_CPU2 = 1U << 11, LITTLE_CPU1 = 1U << 10, }; enum { SRAM_PDN = 0xf << 8, DIS_SRAM_ACK = 0x1 << 12, AUD_SRAM_ACK = 0xf << 12, }; enum { DIS_PWR_STA_MASK = 0x1 << 3, AUD_PWR_STA_MASK = 0x1 << 24, }; #define SPM_VDE_PWR_CON 0x0210 #define SPM_MFG_PWR_CON 0x0214 #define SPM_VEN_PWR_CON 0x0230 #define SPM_ISP_PWR_CON 0x0238 #define SPM_DIS_PWR_CON 0x023c #define SPM_VEN2_PWR_CON 0x0298 #define SPM_AUDIO_PWR_CON 0x029c #define SPM_MFG_2D_PWR_CON 0x02c0 #define SPM_MFG_ASYNC_PWR_CON 0x02c4 #define SPM_USB_PWR_CON 0x02cc #define MTCMOS_CTRL_SUCCESS 0 #define MTCMOS_CTRL_ERROR -1 #define MTCMOS_CTRL_EN (0x1 << 18) #define VDE_PWR_ON 0 #define VEN_PWR_ON 1 #define ISP_PWR_ON 2 #define DIS_PWR_ON 3 #define VEN2_PWR_ON 4 #define AUDIO_PWR_ON 5 #define MFG_ASYNC_PWR_ON 6 #define MFG_2D_PWR_ON 7 #define MFG_PWR_ON 8 #define USB_PWR_ON 9 #define VDE_PWR_OFF 10 #define VEN_PWR_OFF 11 #define ISP_PWR_OFF 12 #define DIS_PWR_OFF 13 #define VEN2_PWR_OFF 14 #define AUDIO_PWR_OFF 15 #define MFG_ASYNC_PWR_OFF 16 #define MFG_2D_PWR_OFF 17 #define MFG_PWR_OFF 18 #define USB_PWR_OFF 19 #define VDE_PWR_CON_PWR_STA 7 #define VEN_PWR_CON_PWR_STA 21 #define ISP_PWR_CON_PWR_STA 5 #define DIS_PWR_CON_PWR_STA 3 #define VEN2_PWR_CON_PWR_STA 20 #define AUDIO_PWR_CON_PWR_STA 24 #define MFG_ASYNC_PWR_CON_PWR_STA 23 #define MFG_2D_PWR_CON_PWR_STA 22 #define MFG_PWR_CON_PWR_STA 4 #define USB_PWR_CON_PWR_STA 25 /* * Timeout if the ack is not signled after 1 second. * According to designer, one mtcmos operation should be done * around 10us. */ #define MTCMOS_ACK_POLLING_MAX_COUNT 10000 #define MTCMOS_ACK_POLLING_INTERVAL 10 static void mtcmos_ctrl_little_off(unsigned int linear_id) { uint32_t reg_pwr_con; uint32_t reg_l1_pdn; uint32_t bit_cpu; switch (linear_id) { case 1: reg_pwr_con = SPM_CA7_CPU1_PWR_CON; reg_l1_pdn = SPM_CA7_CPU1_L1_PDN; bit_cpu = LITTLE_CPU1; break; case 2: reg_pwr_con = SPM_CA7_CPU2_PWR_CON; reg_l1_pdn = SPM_CA7_CPU2_L1_PDN; bit_cpu = LITTLE_CPU2; break; case 3: reg_pwr_con = SPM_CA7_CPU3_PWR_CON; reg_l1_pdn = SPM_CA7_CPU3_L1_PDN; bit_cpu = LITTLE_CPU3; break; default: /* should never come to here */ return; } /* enable register control */ mmio_write_32(SPM_POWERON_CONFIG_SET, (SPM_PROJECT_CODE << 16) | (1U << 0)); mmio_setbits_32(reg_pwr_con, PWR_ISO); mmio_setbits_32(reg_pwr_con, SRAM_CKISO); mmio_clrbits_32(reg_pwr_con, SRAM_ISOINT_B); mmio_setbits_32(reg_l1_pdn, L1_PDN); while (!(mmio_read_32(reg_l1_pdn) & L1_PDN_ACK)) continue; mmio_clrbits_32(reg_pwr_con, PWR_RST_B); mmio_setbits_32(reg_pwr_con, PWR_CLK_DIS); mmio_clrbits_32(reg_pwr_con, PWR_ON); mmio_clrbits_32(reg_pwr_con, PWR_ON_2ND); while ((mmio_read_32(SPM_PWR_STATUS) & bit_cpu) || (mmio_read_32(SPM_PWR_STATUS_2ND) & bit_cpu)) continue; } void mtcmos_little_cpu_off(void) { /* turn off little cpu 1 - 3 */ mtcmos_ctrl_little_off(1); mtcmos_ctrl_little_off(2); mtcmos_ctrl_little_off(3); } uint32_t wait_mtcmos_ack(uint32_t on, uint32_t pwr_ctrl, uint32_t spm_pwr_sta) { int i = 0; uint32_t cmp, pwr_sta, pwr_sta_2nd; while (1) { cmp = mmio_read_32(SPM_PCM_PASR_DPD_3) & pwr_ctrl; pwr_sta = (mmio_read_32(SPM_PWR_STATUS) >> spm_pwr_sta) & 1; pwr_sta_2nd = (mmio_read_32(SPM_PWR_STATUS_2ND) >> spm_pwr_sta) & 1; if (cmp && (pwr_sta == on) && (pwr_sta_2nd == on)) { mmio_write_32(SPM_PCM_RESERVE2, 0); return MTCMOS_CTRL_SUCCESS; } udelay(MTCMOS_ACK_POLLING_INTERVAL); i++; if (i > MTCMOS_ACK_POLLING_MAX_COUNT) { INFO("MTCMOS control failed(%d), SPM_PWR_STA(%d),\n" "SPM_PCM_RESERVE=0x%x,SPM_PCM_RESERVE2=0x%x,\n" "SPM_PWR_STATUS=0x%x,SPM_PWR_STATUS_2ND=0x%x\n" "SPM_PCM_PASR_DPD_3 = 0x%x\n", on, spm_pwr_sta, mmio_read_32(SPM_PCM_RESERVE), mmio_read_32(SPM_PCM_RESERVE2), mmio_read_32(SPM_PWR_STATUS), mmio_read_32(SPM_PWR_STATUS_2ND), mmio_read_32(SPM_PCM_PASR_DPD_3)); mmio_write_32(SPM_PCM_RESERVE2, 0); return MTCMOS_CTRL_ERROR; } } } uint32_t mtcmos_non_cpu_ctrl(uint32_t on, uint32_t mtcmos_num) { uint32_t ret = MTCMOS_CTRL_SUCCESS; uint32_t power_on; uint32_t power_off; uint32_t power_ctrl; uint32_t power_status; spm_lock_get(); spm_mcdi_prepare_for_mtcmos(); mmio_setbits_32(SPM_PCM_RESERVE, MTCMOS_CTRL_EN); switch (mtcmos_num) { case SPM_VDE_PWR_CON: power_on = VDE_PWR_ON; power_off = VDE_PWR_OFF; power_status = VDE_PWR_CON_PWR_STA; break; case SPM_MFG_PWR_CON: power_on = MFG_PWR_ON; power_off = MFG_PWR_OFF; power_status = MFG_PWR_CON_PWR_STA; break; case SPM_VEN_PWR_CON: power_on = VEN_PWR_ON; power_off = VEN_PWR_OFF; power_status = VEN_PWR_CON_PWR_STA; break; case SPM_ISP_PWR_CON: power_on = ISP_PWR_ON; power_off = ISP_PWR_OFF; power_status = ISP_PWR_CON_PWR_STA; break; case SPM_DIS_PWR_CON: power_on = DIS_PWR_ON; power_off = DIS_PWR_OFF; power_status = DIS_PWR_CON_PWR_STA; break; case SPM_VEN2_PWR_CON: power_on = VEN2_PWR_ON; power_off = VEN2_PWR_OFF; power_status = VEN2_PWR_CON_PWR_STA; break; case SPM_AUDIO_PWR_CON: power_on = AUDIO_PWR_ON; power_off = AUDIO_PWR_OFF; power_status = AUDIO_PWR_CON_PWR_STA; break; case SPM_MFG_2D_PWR_CON: power_on = MFG_2D_PWR_ON; power_off = MFG_2D_PWR_OFF; power_status = MFG_2D_PWR_CON_PWR_STA; break; case SPM_MFG_ASYNC_PWR_CON: power_on = MFG_ASYNC_PWR_ON; power_off = MFG_ASYNC_PWR_OFF; power_status = MFG_ASYNC_PWR_CON_PWR_STA; break; case SPM_USB_PWR_CON: power_on = USB_PWR_ON; power_off = USB_PWR_OFF; power_status = USB_PWR_CON_PWR_STA; break; default: ret = MTCMOS_CTRL_ERROR; INFO("No mapping MTCMOS(%d), ret = %d\n", mtcmos_num, ret); break; } if (ret == MTCMOS_CTRL_SUCCESS) { power_ctrl = on ? (1 << power_on) : (1 << power_off); mmio_setbits_32(SPM_PCM_RESERVE2, power_ctrl); ret = wait_mtcmos_ack(on, power_ctrl, power_status); VERBOSE("0x%x(%d), PWR_STATUS(0x%x), ret(%d)\n", power_ctrl, on, mmio_read_32(SPM_PWR_STATUS), ret); } mmio_clrbits_32(SPM_PCM_RESERVE, MTCMOS_CTRL_EN); spm_lock_release(); return ret; } trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/mtcmos/mtcmos.h000066400000000000000000000010371355360272700252330ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MTCMOS_H #define MTCMOS_H /* * This function will turn off all the little core's power except cpu 0. The * cores in cluster 0 are all powered when the system power on. The System * Power Manager (SPM) will do nothing if it found the core's power was on * during CPU_ON psci call. */ void mtcmos_little_cpu_off(void); uint32_t mtcmos_non_cpu_ctrl(uint32_t on, uint32_t mtcmos_num); #endif /* MTCMOS_H */ trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/pmic/000077500000000000000000000000001355360272700232055ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/pmic/pmic_wrap_init.h000066400000000000000000000076021355360272700263670ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PMIC_WRAP_INIT_H #define PMIC_WRAP_INIT_H #include /* external API */ int32_t pwrap_read(uint32_t adr, uint32_t *rdata); int32_t pwrap_write(uint32_t adr, uint32_t wdata); static struct mt8173_pmic_wrap_regs *const mtk_pwrap = (void *)PMIC_WRAP_BASE; /* timeout setting */ enum { TIMEOUT_RESET = 50, /* us */ TIMEOUT_READ = 50, /* us */ TIMEOUT_WAIT_IDLE = 50 /* us */ }; /* PMIC_WRAP registers */ struct mt8173_pmic_wrap_regs { uint32_t mux_sel; uint32_t wrap_en; uint32_t dio_en; uint32_t sidly; uint32_t rddmy; uint32_t si_ck_con; uint32_t cshext_write; uint32_t cshext_read; uint32_t cslext_start; uint32_t cslext_end; uint32_t staupd_prd; uint32_t staupd_grpen; uint32_t reserved[4]; uint32_t staupd_man_trig; uint32_t staupd_sta; uint32_t wrap_sta; uint32_t harb_init; uint32_t harb_hprio; uint32_t hiprio_arb_en; uint32_t harb_sta0; uint32_t harb_sta1; uint32_t man_en; uint32_t man_cmd; uint32_t man_rdata; uint32_t man_vldclr; uint32_t wacs0_en; uint32_t init_done0; uint32_t wacs0_cmd; uint32_t wacs0_rdata; uint32_t wacs0_vldclr; uint32_t wacs1_en; uint32_t init_done1; uint32_t wacs1_cmd; uint32_t wacs1_rdata; uint32_t wacs1_vldclr; uint32_t wacs2_en; uint32_t init_done2; uint32_t wacs2_cmd; uint32_t wacs2_rdata; uint32_t wacs2_vldclr; uint32_t int_en; uint32_t int_flg_raw; uint32_t int_flg; uint32_t int_clr; uint32_t sig_adr; uint32_t sig_mode; uint32_t sig_value; uint32_t sig_errval; uint32_t crc_en; uint32_t timer_en; uint32_t timer_sta; uint32_t wdt_unit; uint32_t wdt_src_en; uint32_t wdt_flg; uint32_t debug_int_sel; uint32_t dvfs_adr0; uint32_t dvfs_wdata0; uint32_t dvfs_adr1; uint32_t dvfs_wdata1; uint32_t dvfs_adr2; uint32_t dvfs_wdata2; uint32_t dvfs_adr3; uint32_t dvfs_wdata3; uint32_t dvfs_adr4; uint32_t dvfs_wdata4; uint32_t dvfs_adr5; uint32_t dvfs_wdata5; uint32_t dvfs_adr6; uint32_t dvfs_wdata6; uint32_t dvfs_adr7; uint32_t dvfs_wdata7; uint32_t spminf_sta; uint32_t cipher_key_sel; uint32_t cipher_iv_sel; uint32_t cipher_en; uint32_t cipher_rdy; uint32_t cipher_mode; uint32_t cipher_swrst; uint32_t dcm_en; uint32_t dcm_dbc_prd; }; enum { RDATA_WACS_RDATA_SHIFT = 0, RDATA_WACS_FSM_SHIFT = 16, RDATA_WACS_REQ_SHIFT = 19, RDATA_SYNC_IDLE_SHIFT, RDATA_INIT_DONE_SHIFT, RDATA_SYS_IDLE_SHIFT, }; enum { RDATA_WACS_RDATA_MASK = 0xffff, RDATA_WACS_FSM_MASK = 0x7, RDATA_WACS_REQ_MASK = 0x1, RDATA_SYNC_IDLE_MASK = 0x1, RDATA_INIT_DONE_MASK = 0x1, RDATA_SYS_IDLE_MASK = 0x1, }; /* WACS_FSM */ enum { WACS_FSM_IDLE = 0x00, WACS_FSM_REQ = 0x02, WACS_FSM_WFDLE = 0x04, WACS_FSM_WFVLDCLR = 0x06, WACS_INIT_DONE = 0x01, WACS_SYNC_IDLE = 0x01, WACS_SYNC_BUSY = 0x00 }; /* error information flag */ enum { E_PWR_INVALID_ARG = 1, E_PWR_INVALID_RW = 2, E_PWR_INVALID_ADDR = 3, E_PWR_INVALID_WDAT = 4, E_PWR_INVALID_OP_MANUAL = 5, E_PWR_NOT_IDLE_STATE = 6, E_PWR_NOT_INIT_DONE = 7, E_PWR_NOT_INIT_DONE_READ = 8, E_PWR_WAIT_IDLE_TIMEOUT = 9, E_PWR_WAIT_IDLE_TIMEOUT_READ = 10, E_PWR_INIT_SIDLY_FAIL = 11, E_PWR_RESET_TIMEOUT = 12, E_PWR_TIMEOUT = 13, E_PWR_INIT_RESET_SPI = 20, E_PWR_INIT_SIDLY = 21, E_PWR_INIT_REG_CLOCK = 22, E_PWR_INIT_ENABLE_PMIC = 23, E_PWR_INIT_DIO = 24, E_PWR_INIT_CIPHER = 25, E_PWR_INIT_WRITE_TEST = 26, E_PWR_INIT_ENABLE_CRC = 27, E_PWR_INIT_ENABLE_DEWRAP = 28, E_PWR_INIT_ENABLE_EVENT = 29, E_PWR_READ_TEST_FAIL = 30, E_PWR_WRITE_TEST_FAIL = 31, E_PWR_SWITCH_DIO = 32 }; #endif /* PMIC_WRAP_INIT_H */ trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/rtc/000077500000000000000000000000001355360272700230455ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/rtc/rtc.c000066400000000000000000000007221355360272700240020ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include void rtc_bbpu_power_down(void) { uint16_t bbpu; /* pull PWRBB low */ bbpu = RTC_BBPU_KEY | RTC_BBPU_AUTO | RTC_BBPU_PWREN; if (Writeif_unlock()) { RTC_Write(RTC_BBPU, bbpu); if (!RTC_Write_Trigger()) assert(0); } else { assert(0); } } trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/rtc/rtc.h000066400000000000000000000017701355360272700240130ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RTC_H #define RTC_H /* RTC registers */ enum { RTC_BBPU = 0xE000, RTC_IRQ_STA = 0xE002, RTC_IRQ_EN = 0xE004, RTC_CII_EN = 0xE006 }; enum { RTC_OSC32CON = 0xE026, RTC_CON = 0xE03E, RTC_WRTGR = 0xE03C }; enum { RTC_PDN1 = 0xE02C, RTC_PDN2 = 0xE02E, RTC_SPAR0 = 0xE030, RTC_SPAR1 = 0xE032, RTC_PROT = 0xE036, RTC_DIFF = 0xE038, RTC_CALI = 0xE03A }; enum { RTC_PROT_UNLOCK1 = 0x586A, RTC_PROT_UNLOCK2 = 0x9136 }; enum { RTC_BBPU_PWREN = 1U << 0, RTC_BBPU_BBPU = 1U << 2, RTC_BBPU_AUTO = 1U << 3, RTC_BBPU_CLRPKY = 1U << 4, RTC_BBPU_RELOAD = 1U << 5, RTC_BBPU_CBUSY = 1U << 6 }; enum { RTC_BBPU_KEY = 0x43 << 8 }; /* external API */ uint16_t RTC_Read(uint32_t addr); void RTC_Write(uint32_t addr, uint16_t data); int32_t rtc_busy_wait(void); int32_t RTC_Write_Trigger(void); int32_t Writeif_unlock(void); void rtc_bbpu_power_down(void); #endif /* RTC_H */ trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/spm/000077500000000000000000000000001355360272700230545ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/spm/spm.c000066400000000000000000000246761355360272700240360ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* * System Power Manager (SPM) is a hardware module, which controls cpu or * system power for different power scenarios using different firmware, i.e., * - spm_hotplug.c for cpu power control in cpu hotplug flow. * - spm_mcdi.c for cpu power control in cpu idle power saving state. * - spm_suspend.c for system power control in system suspend scenario. * * This file provide utility functions common to hotplug, mcdi(idle), suspend * power scenarios. A bakery lock (software lock) is incoporated to protect * certain critical sections to avoid kicking different SPM firmware * concurrently. */ #define SPM_SYSCLK_SETTLE 128 /* 3.9ms */ DEFINE_BAKERY_LOCK(spm_lock); static int spm_hotplug_ready __section("tzfw_coherent_mem"); static int spm_mcdi_ready __section("tzfw_coherent_mem"); static int spm_suspend_ready __section("tzfw_coherent_mem"); void spm_lock_init(void) { bakery_lock_init(&spm_lock); } void spm_lock_get(void) { bakery_lock_get(&spm_lock); } void spm_lock_release(void) { bakery_lock_release(&spm_lock); } int is_mcdi_ready(void) { return spm_mcdi_ready; } int is_hotplug_ready(void) { return spm_hotplug_ready; } int is_suspend_ready(void) { return spm_suspend_ready; } void set_mcdi_ready(void) { spm_mcdi_ready = 1; spm_hotplug_ready = 0; spm_suspend_ready = 0; } void set_hotplug_ready(void) { spm_mcdi_ready = 0; spm_hotplug_ready = 1; spm_suspend_ready = 0; } void set_suspend_ready(void) { spm_mcdi_ready = 0; spm_hotplug_ready = 0; spm_suspend_ready = 1; } void clear_all_ready(void) { spm_mcdi_ready = 0; spm_hotplug_ready = 0; spm_suspend_ready = 0; } void spm_register_init(void) { mmio_write_32(SPM_POWERON_CONFIG_SET, SPM_REGWR_CFG_KEY | SPM_REGWR_EN); mmio_write_32(SPM_POWER_ON_VAL0, 0); mmio_write_32(SPM_POWER_ON_VAL1, POWER_ON_VAL1_DEF); mmio_write_32(SPM_PCM_PWR_IO_EN, 0); mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY | CON0_PCM_SW_RESET); mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY); if (mmio_read_32(SPM_PCM_FSM_STA) != PCM_FSM_STA_DEF) WARN("PCM reset failed\n"); mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY | CON0_IM_SLEEP_DVS); mmio_write_32(SPM_PCM_CON1, CON1_CFG_KEY | CON1_EVENT_LOCK_EN | CON1_SPM_SRAM_ISO_B | CON1_SPM_SRAM_SLP_B | CON1_MIF_APBEN); mmio_write_32(SPM_PCM_IM_PTR, 0); mmio_write_32(SPM_PCM_IM_LEN, 0); mmio_write_32(SPM_CLK_CON, CC_SYSCLK0_EN_1 | CC_SYSCLK0_EN_0 | CC_SYSCLK1_EN_0 | CC_SRCLKENA_MASK_0 | CC_CLKSQ1_SEL | CC_CXO32K_RM_EN_MD2 | CC_CXO32K_RM_EN_MD1 | CC_MD32_DCM_EN); mmio_write_32(SPM_SLEEP_ISR_MASK, 0xff0c); mmio_write_32(SPM_SLEEP_ISR_STATUS, 0xc); mmio_write_32(SPM_PCM_SW_INT_CLEAR, 0xff); mmio_write_32(SPM_MD32_SRAM_CON, 0xff0); } void spm_reset_and_init_pcm(void) { unsigned int con1; int i = 0; mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY | CON0_PCM_SW_RESET); mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY); while (mmio_read_32(SPM_PCM_FSM_STA) != PCM_FSM_STA_DEF) { i++; if (i > 1000) { i = 0; WARN("PCM reset failed\n"); break; } } mmio_write_32(SPM_PCM_CON0, CON0_CFG_KEY | CON0_IM_SLEEP_DVS); con1 = mmio_read_32(SPM_PCM_CON1) & (CON1_PCM_WDT_WAKE_MODE | CON1_PCM_WDT_EN); mmio_write_32(SPM_PCM_CON1, con1 | CON1_CFG_KEY | CON1_EVENT_LOCK_EN | CON1_SPM_SRAM_ISO_B | CON1_SPM_SRAM_SLP_B | CON1_IM_NONRP_EN | CON1_MIF_APBEN); } void spm_init_pcm_register(void) { mmio_write_32(SPM_PCM_REG_DATA_INI, mmio_read_32(SPM_POWER_ON_VAL0)); mmio_write_32(SPM_PCM_PWR_IO_EN, PCM_RF_SYNC_R0); mmio_write_32(SPM_PCM_PWR_IO_EN, 0); mmio_write_32(SPM_PCM_REG_DATA_INI, mmio_read_32(SPM_POWER_ON_VAL1)); mmio_write_32(SPM_PCM_PWR_IO_EN, PCM_RF_SYNC_R7); mmio_write_32(SPM_PCM_PWR_IO_EN, 0); } void spm_set_power_control(const struct pwr_ctrl *pwrctrl) { mmio_write_32(SPM_AP_STANBY_CON, (!pwrctrl->md32_req_mask << 21) | (!pwrctrl->mfg_req_mask << 17) | (!pwrctrl->disp_req_mask << 16) | (!!pwrctrl->mcusys_idle_mask << 7) | (!!pwrctrl->ca15top_idle_mask << 6) | (!!pwrctrl->ca7top_idle_mask << 5) | (!!pwrctrl->wfi_op << 4)); mmio_write_32(SPM_PCM_SRC_REQ, (!!pwrctrl->pcm_apsrc_req << 0)); mmio_write_32(SPM_PCM_PASR_DPD_2, 0); mmio_clrsetbits_32(SPM_CLK_CON, CC_SRCLKENA_MASK_0, (pwrctrl->srclkenai_mask ? CC_SRCLKENA_MASK_0 : 0)); mmio_write_32(SPM_SLEEP_CA15_WFI0_EN, !!pwrctrl->ca15_wfi0_en); mmio_write_32(SPM_SLEEP_CA15_WFI1_EN, !!pwrctrl->ca15_wfi1_en); mmio_write_32(SPM_SLEEP_CA15_WFI2_EN, !!pwrctrl->ca15_wfi2_en); mmio_write_32(SPM_SLEEP_CA15_WFI3_EN, !!pwrctrl->ca15_wfi3_en); mmio_write_32(SPM_SLEEP_CA7_WFI0_EN, !!pwrctrl->ca7_wfi0_en); mmio_write_32(SPM_SLEEP_CA7_WFI1_EN, !!pwrctrl->ca7_wfi1_en); mmio_write_32(SPM_SLEEP_CA7_WFI2_EN, !!pwrctrl->ca7_wfi2_en); mmio_write_32(SPM_SLEEP_CA7_WFI3_EN, !!pwrctrl->ca7_wfi3_en); } void spm_set_wakeup_event(const struct pwr_ctrl *pwrctrl) { unsigned int val, mask; if (pwrctrl->timer_val_cust == 0) val = pwrctrl->timer_val ? pwrctrl->timer_val : PCM_TIMER_MAX; else val = pwrctrl->timer_val_cust; mmio_write_32(SPM_PCM_TIMER_VAL, val); mmio_setbits_32(SPM_PCM_CON1, CON1_CFG_KEY); if (pwrctrl->wake_src_cust == 0) mask = pwrctrl->wake_src; else mask = pwrctrl->wake_src_cust; if (pwrctrl->syspwreq_mask) mask &= ~WAKE_SRC_SYSPWREQ; mmio_write_32(SPM_SLEEP_WAKEUP_EVENT_MASK, ~mask); mmio_write_32(SPM_SLEEP_ISR_MASK, 0xfe04); } void spm_get_wakeup_status(struct wake_status *wakesta) { wakesta->assert_pc = mmio_read_32(SPM_PCM_REG_DATA_INI); wakesta->r12 = mmio_read_32(SPM_PCM_REG12_DATA); wakesta->raw_sta = mmio_read_32(SPM_SLEEP_ISR_RAW_STA); wakesta->wake_misc = mmio_read_32(SPM_SLEEP_WAKEUP_MISC); wakesta->timer_out = mmio_read_32(SPM_PCM_TIMER_OUT); wakesta->r13 = mmio_read_32(SPM_PCM_REG13_DATA); wakesta->idle_sta = mmio_read_32(SPM_SLEEP_SUBSYS_IDLE_STA); wakesta->debug_flag = mmio_read_32(SPM_PCM_PASR_DPD_3); wakesta->event_reg = mmio_read_32(SPM_PCM_EVENT_REG_STA); wakesta->isr = mmio_read_32(SPM_SLEEP_ISR_STATUS); } void spm_init_event_vector(const struct pcm_desc *pcmdesc) { /* init event vector register */ mmio_write_32(SPM_PCM_EVENT_VECTOR0, pcmdesc->vec0); mmio_write_32(SPM_PCM_EVENT_VECTOR1, pcmdesc->vec1); mmio_write_32(SPM_PCM_EVENT_VECTOR2, pcmdesc->vec2); mmio_write_32(SPM_PCM_EVENT_VECTOR3, pcmdesc->vec3); mmio_write_32(SPM_PCM_EVENT_VECTOR4, pcmdesc->vec4); mmio_write_32(SPM_PCM_EVENT_VECTOR5, pcmdesc->vec5); mmio_write_32(SPM_PCM_EVENT_VECTOR6, pcmdesc->vec6); mmio_write_32(SPM_PCM_EVENT_VECTOR7, pcmdesc->vec7); /* event vector will be enabled by PCM itself */ } void spm_kick_im_to_fetch(const struct pcm_desc *pcmdesc) { unsigned int ptr = 0, len, con0; ptr = (unsigned int)(unsigned long)(pcmdesc->base); len = pcmdesc->size - 1; if (mmio_read_32(SPM_PCM_IM_PTR) != ptr || mmio_read_32(SPM_PCM_IM_LEN) != len || pcmdesc->sess > 2) { mmio_write_32(SPM_PCM_IM_PTR, ptr); mmio_write_32(SPM_PCM_IM_LEN, len); } else { mmio_setbits_32(SPM_PCM_CON1, CON1_CFG_KEY | CON1_IM_SLAVE); } /* kick IM to fetch (only toggle IM_KICK) */ con0 = mmio_read_32(SPM_PCM_CON0) & ~(CON0_IM_KICK | CON0_PCM_KICK); mmio_write_32(SPM_PCM_CON0, con0 | CON0_CFG_KEY | CON0_IM_KICK); mmio_write_32(SPM_PCM_CON0, con0 | CON0_CFG_KEY); /* kick IM to fetch (only toggle PCM_KICK) */ con0 = mmio_read_32(SPM_PCM_CON0) & ~(CON0_IM_KICK | CON0_PCM_KICK); mmio_write_32(SPM_PCM_CON0, con0 | CON0_CFG_KEY | CON0_PCM_KICK); mmio_write_32(SPM_PCM_CON0, con0 | CON0_CFG_KEY); } void spm_set_sysclk_settle(void) { mmio_write_32(SPM_CLK_SETTLE, SPM_SYSCLK_SETTLE); INFO("settle = %u\n", mmio_read_32(SPM_CLK_SETTLE)); } void spm_kick_pcm_to_run(struct pwr_ctrl *pwrctrl) { unsigned int con1; con1 = mmio_read_32(SPM_PCM_CON1) & ~(CON1_PCM_WDT_WAKE_MODE | CON1_PCM_WDT_EN); mmio_write_32(SPM_PCM_CON1, CON1_CFG_KEY | con1); if (mmio_read_32(SPM_PCM_TIMER_VAL) > PCM_TIMER_MAX) mmio_write_32(SPM_PCM_TIMER_VAL, PCM_TIMER_MAX); mmio_write_32(SPM_PCM_WDT_TIMER_VAL, mmio_read_32(SPM_PCM_TIMER_VAL) + PCM_WDT_TIMEOUT); mmio_write_32(SPM_PCM_CON1, con1 | CON1_CFG_KEY | CON1_PCM_WDT_EN); mmio_write_32(SPM_PCM_PASR_DPD_0, 0); mmio_write_32(SPM_PCM_MAS_PAUSE_MASK, 0xffffffff); mmio_write_32(SPM_PCM_REG_DATA_INI, 0); mmio_clrbits_32(SPM_CLK_CON, CC_DISABLE_DORM_PWR); mmio_write_32(SPM_PCM_FLAGS, pwrctrl->pcm_flags); mmio_clrsetbits_32(SPM_CLK_CON, CC_LOCK_INFRA_DCM, (pwrctrl->infra_dcm_lock ? CC_LOCK_INFRA_DCM : 0)); mmio_write_32(SPM_PCM_PWR_IO_EN, (pwrctrl->r0_ctrl_en ? PCM_PWRIO_EN_R0 : 0) | (pwrctrl->r7_ctrl_en ? PCM_PWRIO_EN_R7 : 0)); } void spm_clean_after_wakeup(void) { mmio_clrsetbits_32(SPM_PCM_CON1, CON1_PCM_WDT_EN, CON1_CFG_KEY); mmio_write_32(SPM_PCM_PWR_IO_EN, 0); mmio_write_32(SPM_SLEEP_CPU_WAKEUP_EVENT, 0); mmio_clrsetbits_32(SPM_PCM_CON1, CON1_PCM_TIMER_EN, CON1_CFG_KEY); mmio_write_32(SPM_SLEEP_WAKEUP_EVENT_MASK, ~0); mmio_write_32(SPM_SLEEP_ISR_MASK, 0xFF0C); mmio_write_32(SPM_SLEEP_ISR_STATUS, 0xC); mmio_write_32(SPM_PCM_SW_INT_CLEAR, 0xFF); } enum wake_reason_t spm_output_wake_reason(struct wake_status *wakesta) { enum wake_reason_t wr; int i; wr = WR_UNKNOWN; if (wakesta->assert_pc != 0) { ERROR("PCM ASSERT AT %u, r12=0x%x, r13=0x%x, debug_flag=0x%x\n", wakesta->assert_pc, wakesta->r12, wakesta->r13, wakesta->debug_flag); return WR_PCM_ASSERT; } if (wakesta->r12 & WAKE_SRC_SPM_MERGE) { if (wakesta->wake_misc & WAKE_MISC_PCM_TIMER) wr = WR_PCM_TIMER; if (wakesta->wake_misc & WAKE_MISC_CPU_WAKE) wr = WR_WAKE_SRC; } for (i = 1; i < 32; i++) { if (wakesta->r12 & (1U << i)) wr = WR_WAKE_SRC; } if ((wakesta->event_reg & 0x100000) == 0) { INFO("pcm sleep abort!\n"); wr = WR_PCM_ABORT; } INFO("timer_out = %u, r12 = 0x%x, r13 = 0x%x, debug_flag = 0x%x\n", wakesta->timer_out, wakesta->r12, wakesta->r13, wakesta->debug_flag); INFO("raw_sta = 0x%x, idle_sta = 0x%x, event_reg = 0x%x, isr = 0x%x\n", wakesta->raw_sta, wakesta->idle_sta, wakesta->event_reg, wakesta->isr); return wr; } void spm_boot_init(void) { /* set spm transaction to secure mode */ mmio_write_32(DEVAPC0_APC_CON, 0x0); mmio_write_32(DEVAPC0_MAS_SEC_0, 0x200); /* Only CPU0 is online during boot, initialize cpu online reserve bit */ mmio_write_32(SPM_PCM_RESERVE, 0xFE); mmio_clrbits_32(AP_PLL_CON3, 0xFFFFF); mmio_clrbits_32(AP_PLL_CON4, 0xF); spm_lock_init(); spm_register_init(); } trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/spm/spm.h000066400000000000000000000265631355360272700240400ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPM_H #define SPM_H #define SPM_POWERON_CONFIG_SET (SPM_BASE + 0x000) #define SPM_POWER_ON_VAL0 (SPM_BASE + 0x010) #define SPM_POWER_ON_VAL1 (SPM_BASE + 0x014) #define SPM_CLK_SETTLE (SPM_BASE + 0x100) #define SPM_CA7_CPU1_PWR_CON (SPM_BASE + 0x218) #define SPM_CA7_CPU2_PWR_CON (SPM_BASE + 0x21c) #define SPM_CA7_CPU3_PWR_CON (SPM_BASE + 0x220) #define SPM_CA7_CPU1_L1_PDN (SPM_BASE + 0x264) #define SPM_CA7_CPU2_L1_PDN (SPM_BASE + 0x26c) #define SPM_CA7_CPU3_L1_PDN (SPM_BASE + 0x274) #define SPM_MD32_SRAM_CON (SPM_BASE + 0x2c8) #define SPM_PCM_CON0 (SPM_BASE + 0x310) #define SPM_PCM_CON1 (SPM_BASE + 0x314) #define SPM_PCM_IM_PTR (SPM_BASE + 0x318) #define SPM_PCM_IM_LEN (SPM_BASE + 0x31c) #define SPM_PCM_REG_DATA_INI (SPM_BASE + 0x320) #define SPM_PCM_EVENT_VECTOR0 (SPM_BASE + 0x340) #define SPM_PCM_EVENT_VECTOR1 (SPM_BASE + 0x344) #define SPM_PCM_EVENT_VECTOR2 (SPM_BASE + 0x348) #define SPM_PCM_EVENT_VECTOR3 (SPM_BASE + 0x34c) #define SPM_PCM_MAS_PAUSE_MASK (SPM_BASE + 0x354) #define SPM_PCM_PWR_IO_EN (SPM_BASE + 0x358) #define SPM_PCM_TIMER_VAL (SPM_BASE + 0x35c) #define SPM_PCM_TIMER_OUT (SPM_BASE + 0x360) #define SPM_PCM_REG0_DATA (SPM_BASE + 0x380) #define SPM_PCM_REG1_DATA (SPM_BASE + 0x384) #define SPM_PCM_REG2_DATA (SPM_BASE + 0x388) #define SPM_PCM_REG3_DATA (SPM_BASE + 0x38c) #define SPM_PCM_REG4_DATA (SPM_BASE + 0x390) #define SPM_PCM_REG5_DATA (SPM_BASE + 0x394) #define SPM_PCM_REG6_DATA (SPM_BASE + 0x398) #define SPM_PCM_REG7_DATA (SPM_BASE + 0x39c) #define SPM_PCM_REG8_DATA (SPM_BASE + 0x3a0) #define SPM_PCM_REG9_DATA (SPM_BASE + 0x3a4) #define SPM_PCM_REG10_DATA (SPM_BASE + 0x3a8) #define SPM_PCM_REG11_DATA (SPM_BASE + 0x3ac) #define SPM_PCM_REG12_DATA (SPM_BASE + 0x3b0) #define SPM_PCM_REG13_DATA (SPM_BASE + 0x3b4) #define SPM_PCM_REG14_DATA (SPM_BASE + 0x3b8) #define SPM_PCM_REG15_DATA (SPM_BASE + 0x3bc) #define SPM_PCM_EVENT_REG_STA (SPM_BASE + 0x3c0) #define SPM_PCM_FSM_STA (SPM_BASE + 0x3c4) #define SPM_PCM_IM_HOST_RW_PTR (SPM_BASE + 0x3c8) #define SPM_PCM_IM_HOST_RW_DAT (SPM_BASE + 0x3cc) #define SPM_PCM_EVENT_VECTOR4 (SPM_BASE + 0x3d0) #define SPM_PCM_EVENT_VECTOR5 (SPM_BASE + 0x3d4) #define SPM_PCM_EVENT_VECTOR6 (SPM_BASE + 0x3d8) #define SPM_PCM_EVENT_VECTOR7 (SPM_BASE + 0x3dc) #define SPM_PCM_SW_INT_SET (SPM_BASE + 0x3e0) #define SPM_PCM_SW_INT_CLEAR (SPM_BASE + 0x3e4) #define SPM_CLK_CON (SPM_BASE + 0x400) #define SPM_SLEEP_PTPOD2_CON (SPM_BASE + 0x408) #define SPM_APMCU_PWRCTL (SPM_BASE + 0x600) #define SPM_AP_DVFS_CON_SET (SPM_BASE + 0x604) #define SPM_AP_STANBY_CON (SPM_BASE + 0x608) #define SPM_PWR_STATUS (SPM_BASE + 0x60c) #define SPM_PWR_STATUS_2ND (SPM_BASE + 0x610) #define SPM_AP_BSI_REQ (SPM_BASE + 0x614) #define SPM_SLEEP_TIMER_STA (SPM_BASE + 0x720) #define SPM_SLEEP_WAKEUP_EVENT_MASK (SPM_BASE + 0x810) #define SPM_SLEEP_CPU_WAKEUP_EVENT (SPM_BASE + 0x814) #define SPM_SLEEP_MD32_WAKEUP_EVENT_MASK (SPM_BASE + 0x818) #define SPM_PCM_WDT_TIMER_VAL (SPM_BASE + 0x824) #define SPM_PCM_WDT_TIMER_OUT (SPM_BASE + 0x828) #define SPM_PCM_MD32_MAILBOX (SPM_BASE + 0x830) #define SPM_PCM_MD32_IRQ (SPM_BASE + 0x834) #define SPM_SLEEP_ISR_MASK (SPM_BASE + 0x900) #define SPM_SLEEP_ISR_STATUS (SPM_BASE + 0x904) #define SPM_SLEEP_ISR_RAW_STA (SPM_BASE + 0x910) #define SPM_SLEEP_MD32_ISR_RAW_STA (SPM_BASE + 0x914) #define SPM_SLEEP_WAKEUP_MISC (SPM_BASE + 0x918) #define SPM_SLEEP_BUS_PROTECT_RDY (SPM_BASE + 0x91c) #define SPM_SLEEP_SUBSYS_IDLE_STA (SPM_BASE + 0x920) #define SPM_PCM_RESERVE (SPM_BASE + 0xb00) #define SPM_PCM_RESERVE2 (SPM_BASE + 0xb04) #define SPM_PCM_FLAGS (SPM_BASE + 0xb08) #define SPM_PCM_SRC_REQ (SPM_BASE + 0xb0c) #define SPM_PCM_DEBUG_CON (SPM_BASE + 0xb20) #define SPM_CA7_CPU0_IRQ_MASK (SPM_BASE + 0xb30) #define SPM_CA7_CPU1_IRQ_MASK (SPM_BASE + 0xb34) #define SPM_CA7_CPU2_IRQ_MASK (SPM_BASE + 0xb38) #define SPM_CA7_CPU3_IRQ_MASK (SPM_BASE + 0xb3c) #define SPM_CA15_CPU0_IRQ_MASK (SPM_BASE + 0xb40) #define SPM_CA15_CPU1_IRQ_MASK (SPM_BASE + 0xb44) #define SPM_CA15_CPU2_IRQ_MASK (SPM_BASE + 0xb48) #define SPM_CA15_CPU3_IRQ_MASK (SPM_BASE + 0xb4c) #define SPM_PCM_PASR_DPD_0 (SPM_BASE + 0xb60) #define SPM_PCM_PASR_DPD_1 (SPM_BASE + 0xb64) #define SPM_PCM_PASR_DPD_2 (SPM_BASE + 0xb68) #define SPM_PCM_PASR_DPD_3 (SPM_BASE + 0xb6c) #define SPM_SLEEP_CA7_WFI0_EN (SPM_BASE + 0xf00) #define SPM_SLEEP_CA7_WFI1_EN (SPM_BASE + 0xf04) #define SPM_SLEEP_CA7_WFI2_EN (SPM_BASE + 0xf08) #define SPM_SLEEP_CA7_WFI3_EN (SPM_BASE + 0xf0c) #define SPM_SLEEP_CA15_WFI0_EN (SPM_BASE + 0xf10) #define SPM_SLEEP_CA15_WFI1_EN (SPM_BASE + 0xf14) #define SPM_SLEEP_CA15_WFI2_EN (SPM_BASE + 0xf18) #define SPM_SLEEP_CA15_WFI3_EN (SPM_BASE + 0xf1c) #define AP_PLL_CON3 0x1020900c #define AP_PLL_CON4 0x10209010 #define SPM_PROJECT_CODE 0xb16 #define SPM_REGWR_EN (1U << 0) #define SPM_REGWR_CFG_KEY (SPM_PROJECT_CODE << 16) #define SPM_CPU_PDN_DIS (1U << 0) #define SPM_INFRA_PDN_DIS (1U << 1) #define SPM_DDRPHY_PDN_DIS (1U << 2) #define SPM_DUALVCORE_PDN_DIS (1U << 3) #define SPM_PASR_DIS (1U << 4) #define SPM_DPD_DIS (1U << 5) #define SPM_SODI_DIS (1U << 6) #define SPM_MEMPLL_RESET (1U << 7) #define SPM_MAINPLL_PDN_DIS (1U << 8) #define SPM_CPU_DVS_DIS (1U << 9) #define SPM_CPU_DORMANT (1U << 10) #define SPM_EXT_VSEL_GPIO103 (1U << 11) #define SPM_DDR_HIGH_SPEED (1U << 12) #define SPM_OPT (1U << 13) #define POWER_ON_VAL1_DEF 0x01011820 #define PCM_FSM_STA_DEF 0x48490 #define PCM_END_FSM_STA_DEF 0x08490 #define PCM_END_FSM_STA_MASK 0x3fff0 #define PCM_HANDSHAKE_SEND1 0xbeefbeef #define PCM_WDT_TIMEOUT (30 * 32768) #define PCM_TIMER_MAX (0xffffffff - PCM_WDT_TIMEOUT) #define CON0_PCM_KICK (1U << 0) #define CON0_IM_KICK (1U << 1) #define CON0_IM_SLEEP_DVS (1U << 3) #define CON0_PCM_SW_RESET (1U << 15) #define CON0_CFG_KEY (SPM_PROJECT_CODE << 16) #define CON1_IM_SLAVE (1U << 0) #define CON1_MIF_APBEN (1U << 3) #define CON1_PCM_TIMER_EN (1U << 5) #define CON1_IM_NONRP_EN (1U << 6) #define CON1_PCM_WDT_EN (1U << 8) #define CON1_PCM_WDT_WAKE_MODE (1U << 9) #define CON1_SPM_SRAM_SLP_B (1U << 10) #define CON1_SPM_SRAM_ISO_B (1U << 11) #define CON1_EVENT_LOCK_EN (1U << 12) #define CON1_CFG_KEY (SPM_PROJECT_CODE << 16) #define PCM_PWRIO_EN_R0 (1U << 0) #define PCM_PWRIO_EN_R7 (1U << 7) #define PCM_RF_SYNC_R0 (1U << 16) #define PCM_RF_SYNC_R2 (1U << 18) #define PCM_RF_SYNC_R6 (1U << 22) #define PCM_RF_SYNC_R7 (1U << 23) #define CC_SYSCLK0_EN_0 (1U << 0) #define CC_SYSCLK0_EN_1 (1U << 1) #define CC_SYSCLK1_EN_0 (1U << 2) #define CC_SYSCLK1_EN_1 (1U << 3) #define CC_SYSSETTLE_SEL (1U << 4) #define CC_LOCK_INFRA_DCM (1U << 5) #define CC_SRCLKENA_MASK_0 (1U << 6) #define CC_CXO32K_RM_EN_MD1 (1U << 9) #define CC_CXO32K_RM_EN_MD2 (1U << 10) #define CC_CLKSQ1_SEL (1U << 12) #define CC_DISABLE_DORM_PWR (1U << 14) #define CC_MD32_DCM_EN (1U << 18) #define WFI_OP_AND 1 #define WFI_OP_OR 0 #define WAKE_MISC_PCM_TIMER (1U << 19) #define WAKE_MISC_CPU_WAKE (1U << 20) /* define WAKE_SRC_XXX */ #define WAKE_SRC_SPM_MERGE (1 << 0) #define WAKE_SRC_KP (1 << 2) #define WAKE_SRC_WDT (1 << 3) #define WAKE_SRC_GPT (1 << 4) #define WAKE_SRC_EINT (1 << 6) #define WAKE_SRC_LOW_BAT (1 << 9) #define WAKE_SRC_MD32 (1 << 10) #define WAKE_SRC_USB_CD (1 << 14) #define WAKE_SRC_USB_PDN (1 << 15) #define WAKE_SRC_AFE (1 << 20) #define WAKE_SRC_THERM (1 << 21) #define WAKE_SRC_CIRQ (1 << 22) #define WAKE_SRC_SYSPWREQ (1 << 24) #define WAKE_SRC_SEJ (1 << 27) #define WAKE_SRC_ALL_MD32 (1 << 28) #define WAKE_SRC_CPU_IRQ (1 << 29) enum wake_reason_t { WR_NONE = 0, WR_UART_BUSY = 1, WR_PCM_ASSERT = 2, WR_PCM_TIMER = 3, WR_PCM_ABORT = 4, WR_WAKE_SRC = 5, WR_UNKNOWN = 6, }; struct pwr_ctrl { unsigned int pcm_flags; unsigned int pcm_flags_cust; unsigned int pcm_reserve; unsigned int timer_val; unsigned int timer_val_cust; unsigned int wake_src; unsigned int wake_src_cust; unsigned int wake_src_md32; unsigned short r0_ctrl_en; unsigned short r7_ctrl_en; unsigned short infra_dcm_lock; unsigned short pcm_apsrc_req; unsigned short mcusys_idle_mask; unsigned short ca15top_idle_mask; unsigned short ca7top_idle_mask; unsigned short wfi_op; unsigned short ca15_wfi0_en; unsigned short ca15_wfi1_en; unsigned short ca15_wfi2_en; unsigned short ca15_wfi3_en; unsigned short ca7_wfi0_en; unsigned short ca7_wfi1_en; unsigned short ca7_wfi2_en; unsigned short ca7_wfi3_en; unsigned short disp_req_mask; unsigned short mfg_req_mask; unsigned short md32_req_mask; unsigned short syspwreq_mask; unsigned short srclkenai_mask; }; struct wake_status { unsigned int assert_pc; unsigned int r12; unsigned int raw_sta; unsigned int wake_misc; unsigned int timer_out; unsigned int r13; unsigned int idle_sta; unsigned int debug_flag; unsigned int event_reg; unsigned int isr; }; struct pcm_desc { const char *version; /* PCM code version */ const unsigned int *base; /* binary array base */ const unsigned int size; /* binary array size */ const unsigned char sess; /* session number */ const unsigned char replace; /* replace mode */ unsigned int vec0; /* event vector 0 config */ unsigned int vec1; /* event vector 1 config */ unsigned int vec2; /* event vector 2 config */ unsigned int vec3; /* event vector 3 config */ unsigned int vec4; /* event vector 4 config */ unsigned int vec5; /* event vector 5 config */ unsigned int vec6; /* event vector 6 config */ unsigned int vec7; /* event vector 7 config */ }; struct spm_lp_scen { const struct pcm_desc *pcmdesc; struct pwr_ctrl *pwrctrl; }; #define EVENT_VEC(event, resume, imme, pc) \ (((pc) << 16) | \ (!!(imme) << 6) | \ (!!(resume) << 5) | \ ((event) & 0x1f)) #define spm_read(addr) mmio_read_32(addr) #define spm_write(addr, val) mmio_write_32(addr, val) #define is_cpu_pdn(flags) (!((flags) & SPM_CPU_PDN_DIS)) #define is_infra_pdn(flags) (!((flags) & SPM_INFRA_PDN_DIS)) #define is_ddrphy_pdn(flags) (!((flags) & SPM_DDRPHY_PDN_DIS)) static inline void set_pwrctrl_pcm_flags(struct pwr_ctrl *pwrctrl, unsigned int flags) { flags &= ~SPM_EXT_VSEL_GPIO103; if (pwrctrl->pcm_flags_cust == 0) pwrctrl->pcm_flags = flags; else pwrctrl->pcm_flags = pwrctrl->pcm_flags_cust; } static inline void set_pwrctrl_pcm_data(struct pwr_ctrl *pwrctrl, unsigned int data) { pwrctrl->pcm_reserve = data; } void spm_reset_and_init_pcm(void); void spm_init_pcm_register(void); /* init r0 and r7 */ void spm_set_power_control(const struct pwr_ctrl *pwrctrl); void spm_set_wakeup_event(const struct pwr_ctrl *pwrctrl); void spm_get_wakeup_status(struct wake_status *wakesta); void spm_set_sysclk_settle(void); void spm_kick_pcm_to_run(struct pwr_ctrl *pwrctrl); void spm_clean_after_wakeup(void); enum wake_reason_t spm_output_wake_reason(struct wake_status *wakesta); void spm_register_init(void); void spm_go_to_hotplug(void); void spm_init_event_vector(const struct pcm_desc *pcmdesc); void spm_kick_im_to_fetch(const struct pcm_desc *pcmdesc); void spm_set_sysclk_settle(void); int is_mcdi_ready(void); int is_hotplug_ready(void); int is_suspend_ready(void); void set_mcdi_ready(void); void set_hotplug_ready(void); void set_suspend_ready(void); void clear_all_ready(void); void spm_lock_init(void); void spm_lock_get(void); void spm_lock_release(void); void spm_boot_init(void); #endif /* SPM_H */ trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/spm/spm_hotplug.c000066400000000000000000000331501355360272700255630ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* * System Power Manager (SPM) is a hardware module, which controls cpu or * system power for different power scenarios using different firmware. * This driver controls the cpu power in cpu hotplug flow. */ #define PCM_HOTPLUG_VALID_MASK 0x0000ff00 #define PCM_HOTPLUG_VALID_SHIFT 0x8 /********************************************************** * PCM sequence for CPU hotplug **********************************************************/ static const unsigned int hotplug_binary[] = { 0x1900001f, 0x1020020c, 0x1950001f, 0x1020020c, 0xa9400005, 0x00000001, 0xe1000005, 0x1910001f, 0x10006720, 0x814c9001, 0xd82000e5, 0x17c07c1f, 0x1900001f, 0x10001220, 0x1950001f, 0x10001220, 0xa15f0405, 0xe1000005, 0x1900001f, 0x10001228, 0x1950001f, 0x10001228, 0x810f1401, 0xd8200244, 0x17c07c1f, 0xe2e0006d, 0xe2e0002d, 0x1a00001f, 0x100062b8, 0x1910001f, 0x100062b8, 0xa9000004, 0x00000001, 0xe2000004, 0x1910001f, 0x100062b8, 0x81142804, 0xd8200444, 0x17c07c1f, 0xe2e0002c, 0xe2e0003c, 0xe2e0003e, 0xe2e0003a, 0xe2e00032, 0x1910001f, 0x1000660c, 0x81079001, 0x1950001f, 0x10006610, 0x81479401, 0xa1001404, 0xd8000584, 0x17c07c1f, 0x1900001f, 0x10006404, 0x1950001f, 0x10006404, 0xa1568405, 0xe1000005, 0xf0000000, 0x17c07c1f, 0x1900001f, 0x10006404, 0x1950001f, 0x10006404, 0x89400005, 0x0000dfff, 0xe1000005, 0xe2e00036, 0xe2e0003e, 0x1910001f, 0x1000660c, 0x81079001, 0x1950001f, 0x10006610, 0x81479401, 0x81001404, 0xd82008c4, 0x17c07c1f, 0xe2e0002e, 0x1a00001f, 0x100062b8, 0x1910001f, 0x100062b8, 0x89000004, 0x0000fffe, 0xe2000004, 0x1910001f, 0x100062b8, 0x81142804, 0xd8000ae4, 0x17c07c1f, 0xe2e0006e, 0xe2e0004e, 0xe2e0004c, 0xe2e0004d, 0x1900001f, 0x10001220, 0x1950001f, 0x10001220, 0x89400005, 0xbfffffff, 0xe1000005, 0x1900001f, 0x10001228, 0x1950001f, 0x10001228, 0x810f1401, 0xd8000ce4, 0x17c07c1f, 0x1900001f, 0x1020020c, 0x1950001f, 0x1020020c, 0x89400005, 0xfffffffe, 0xe1000005, 0xf0000000, 0x17c07c1f, 0x1212841f, 0xe2e00036, 0xe2e0003e, 0x1380201f, 0xe2e0003c, 0xe2a00000, 0x1b80001f, 0x20000080, 0xe2e0007c, 0x1b80001f, 0x20000003, 0xe2e0005c, 0xe2e0004c, 0xe2e0004d, 0xf0000000, 0x17c07c1f, 0xe2e0004f, 0xe2e0006f, 0xe2e0002f, 0xe2a00001, 0x1b80001f, 0x20000080, 0xe2e0002e, 0xe2e0003e, 0xe2e00032, 0xf0000000, 0x17c07c1f, 0x1212841f, 0xe2e00026, 0xe2e0002e, 0x1380201f, 0x1a00001f, 0x100062b4, 0x1910001f, 0x100062b4, 0x81322804, 0xe2000004, 0x81202804, 0xe2000004, 0x1b80001f, 0x20000034, 0x1910001f, 0x100062b4, 0x81142804, 0xd8001404, 0x17c07c1f, 0xe2e0000e, 0xe2e0000c, 0xe2e0000d, 0xf0000000, 0x17c07c1f, 0xe2e0002d, 0x1a00001f, 0x100062b4, 0x1910001f, 0x100062b4, 0xa1002804, 0xe2000004, 0xa1122804, 0xe2000004, 0x1b80001f, 0x20000080, 0x1910001f, 0x100062b4, 0x81142804, 0xd82016a4, 0x17c07c1f, 0xe2e0002f, 0xe2e0002b, 0xe2e00023, 0x1380201f, 0xe2e00022, 0xf0000000, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x1840001f, 0x00000001, 0x1840001f, 0x00000001, 0x1840001f, 0x00000001, 0xa1d48407, 0x1b00001f, 0x2f7be75f, 0xe8208000, 0x10006354, 0xfffe7b47, 0xa1d10407, 0x1b80001f, 0x20000020, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x81461001, 0xb14690a1, 0xd82044e5, 0x17c07c1f, 0x1910001f, 0x10006610, 0x81079001, 0xd80044e4, 0x17c07c1f, 0x1990001f, 0x10006b00, 0x81421801, 0x82429801, 0x81402405, 0xd80044e5, 0x17c07c1f, 0x1a40001f, 0x100062b0, 0x1280041f, 0xc24007a0, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x81449001, 0xd8204be5, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x81009001, 0xd8204984, 0x17c07c1f, 0x1910001f, 0x10006610, 0x81051001, 0xd8204be4, 0x17c07c1f, 0x1910001f, 0x10006720, 0x81489001, 0xd82046c5, 0x17c07c1f, 0x1a40001f, 0x10006218, 0x1a80001f, 0x10006264, 0xc24010e0, 0x17c07c1f, 0x1910001f, 0x1000660c, 0x81051001, 0x1950001f, 0x10006610, 0x81451401, 0xa1001404, 0xd8004824, 0x17c07c1f, 0xd0004b00, 0x17c07c1f, 0x17c07c1f, 0x1910001f, 0x10006610, 0x81051001, 0xd8004be4, 0x17c07c1f, 0x1a40001f, 0x10006218, 0x1a80001f, 0x10006264, 0xc2400ee0, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x89000004, 0xfffffdff, 0x1940001f, 0x10006b00, 0xe1400004, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x81451001, 0xd8205305, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x81011001, 0xd82050a4, 0x17c07c1f, 0x1910001f, 0x10006610, 0x81059001, 0xd8205304, 0x17c07c1f, 0x1910001f, 0x10006720, 0x81491001, 0xd8204de5, 0x17c07c1f, 0x1a40001f, 0x1000621c, 0x1a80001f, 0x1000626c, 0xc24010e0, 0x17c07c1f, 0x1910001f, 0x1000660c, 0x81059001, 0x1950001f, 0x10006610, 0x81459401, 0xa1001404, 0xd8004f44, 0x17c07c1f, 0xd0005220, 0x17c07c1f, 0x17c07c1f, 0x1910001f, 0x10006610, 0x81059001, 0xd8005304, 0x17c07c1f, 0x1a40001f, 0x1000621c, 0x1a80001f, 0x1000626c, 0xc2400ee0, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x89000004, 0xfffffbff, 0x1940001f, 0x10006b00, 0xe1400004, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x81459001, 0xd8205a25, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x81019001, 0xd82057c4, 0x17c07c1f, 0x1910001f, 0x10006610, 0x81061001, 0xd8205a24, 0x17c07c1f, 0x1910001f, 0x10006720, 0x81499001, 0xd8205505, 0x17c07c1f, 0x1a40001f, 0x10006220, 0x1a80001f, 0x10006274, 0xc24010e0, 0x17c07c1f, 0x1910001f, 0x1000660c, 0x81061001, 0x1950001f, 0x10006610, 0x81461401, 0xa1001404, 0xd8005664, 0x17c07c1f, 0xd0005940, 0x17c07c1f, 0x17c07c1f, 0x1910001f, 0x10006610, 0x81061001, 0xd8005a24, 0x17c07c1f, 0x1a40001f, 0x10006220, 0x1a80001f, 0x10006274, 0xc2400ee0, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x89000004, 0xfffff7ff, 0x1940001f, 0x10006b00, 0xe1400004, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x81461001, 0xd8206185, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x81021001, 0xd8205ec4, 0x17c07c1f, 0x1910001f, 0x10006610, 0x81081001, 0xd8206184, 0x17c07c1f, 0x1910001f, 0x10006720, 0x814a1001, 0xd8205c25, 0x17c07c1f, 0x1a40001f, 0x100062a0, 0x1280041f, 0xc2401540, 0x17c07c1f, 0x1910001f, 0x1000660c, 0x81081001, 0x1950001f, 0x10006610, 0x81481401, 0xa1001404, 0xd8005d64, 0x17c07c1f, 0xd00060a0, 0x17c07c1f, 0x17c07c1f, 0x1910001f, 0x10006610, 0x81479001, 0x81881001, 0x69a00006, 0x00000000, 0x81401805, 0xd8206185, 0x17c07c1f, 0x1a40001f, 0x100062a0, 0x1280041f, 0xc2401240, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x89000004, 0xffffefff, 0x1940001f, 0x10006b00, 0xe1400004, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x81469001, 0xd82068e5, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x81029001, 0xd8206624, 0x17c07c1f, 0x1910001f, 0x10006610, 0x81089001, 0xd82068e4, 0x17c07c1f, 0x1910001f, 0x10006720, 0x814a9001, 0xd8206385, 0x17c07c1f, 0x1a40001f, 0x100062a4, 0x1290841f, 0xc2401540, 0x17c07c1f, 0x1910001f, 0x1000660c, 0x81089001, 0x1950001f, 0x10006610, 0x81489401, 0xa1001404, 0xd80064c4, 0x17c07c1f, 0xd0006800, 0x17c07c1f, 0x17c07c1f, 0x1910001f, 0x10006610, 0x81479001, 0x81889001, 0x69a00006, 0x00000000, 0x81401805, 0xd82068e5, 0x17c07c1f, 0x1a40001f, 0x100062a4, 0x1290841f, 0xc2401240, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x89000004, 0xffffdfff, 0x1940001f, 0x10006b00, 0xe1400004, 0x1910001f, 0x10006610, 0x81479001, 0x81881001, 0x69600005, 0x00000000, 0xa1401805, 0x81889001, 0xa1401805, 0xd8006bc5, 0x17c07c1f, 0x1910001f, 0x10006b00, 0x81421001, 0x82429001, 0x82802405, 0xd8206bca, 0x17c07c1f, 0x1a40001f, 0x100062b0, 0x1280041f, 0xc2400000, 0x17c07c1f, 0x1990001f, 0x10006b00, 0x89800006, 0x00003f00, 0x69200006, 0x00000000, 0xd82041e4, 0x17c07c1f, 0x1990001f, 0x10006320, 0x69200006, 0xbeefbeef, 0xd8006dc4, 0x17c07c1f, 0xd00041e0, 0x17c07c1f, 0x1910001f, 0x10006358, 0x810b1001, 0xd8006dc4, 0x17c07c1f, 0x1980001f, 0xdeaddead, 0x19c0001f, 0x01411820, 0xf0000000 }; static const struct pcm_desc hotplug_pcm = { .version = "pcm_power_down_mt8173_V37", .base = hotplug_binary, .size = 888, .sess = 2, .replace = 0, }; static struct pwr_ctrl hotplug_ctrl = { .wake_src = 0, .wake_src_md32 = 0, .wfi_op = WFI_OP_OR, .mcusys_idle_mask = 1, .ca7top_idle_mask = 1, .ca15top_idle_mask = 1, .disp_req_mask = 1, .mfg_req_mask = 1, .md32_req_mask = 1, .syspwreq_mask = 1, .pcm_flags = 0, }; static const struct spm_lp_scen spm_hotplug = { .pcmdesc = &hotplug_pcm, .pwrctrl = &hotplug_ctrl, }; void spm_go_to_hotplug(void) { const struct pcm_desc *pcmdesc = spm_hotplug.pcmdesc; struct pwr_ctrl *pwrctrl = spm_hotplug.pwrctrl; set_pwrctrl_pcm_flags(pwrctrl, 0); spm_reset_and_init_pcm(); spm_kick_im_to_fetch(pcmdesc); spm_set_power_control(pwrctrl); spm_set_wakeup_event(pwrctrl); spm_kick_pcm_to_run(pwrctrl); } void spm_clear_hotplug(void) { /* Inform SPM that CPU wants to program CPU_WAKEUP_EVENT and * DISABLE_CPU_DROM */ mmio_write_32(SPM_PCM_REG_DATA_INI, PCM_HANDSHAKE_SEND1); mmio_write_32(SPM_PCM_PWR_IO_EN, PCM_RF_SYNC_R6); mmio_write_32(SPM_PCM_PWR_IO_EN, 0); /* Wait SPM's response, can't use sleep api */ while ((mmio_read_32(SPM_PCM_FSM_STA) & PCM_END_FSM_STA_MASK) != PCM_END_FSM_STA_DEF) ; /* no hotplug pcm running */ clear_all_ready(); } void spm_hotplug_on(unsigned long mpidr) { unsigned long linear_id; linear_id = ((mpidr & MPIDR_CLUSTER_MASK) >> 6) | (mpidr & MPIDR_CPU_MASK); spm_lock_get(); if (is_hotplug_ready() == 0) { spm_mcdi_wakeup_all_cores(); mmio_clrbits_32(SPM_PCM_RESERVE, PCM_HOTPLUG_VALID_MASK); spm_go_to_hotplug(); set_hotplug_ready(); } /* turn on CPUx */ mmio_clrsetbits_32(SPM_PCM_RESERVE, PCM_HOTPLUG_VALID_MASK | (1 << linear_id), 1 << (linear_id + PCM_HOTPLUG_VALID_SHIFT)); spm_lock_release(); } void spm_hotplug_off(unsigned long mpidr) { unsigned long linear_id; linear_id = ((mpidr & MPIDR_CLUSTER_MASK) >> 6) | (mpidr & MPIDR_CPU_MASK); spm_lock_get(); if (is_hotplug_ready() == 0) { spm_mcdi_wakeup_all_cores(); mmio_clrbits_32(SPM_PCM_RESERVE, PCM_HOTPLUG_VALID_MASK); spm_go_to_hotplug(); set_hotplug_ready(); } mmio_clrsetbits_32(SPM_PCM_RESERVE, PCM_HOTPLUG_VALID_MASK, (1 << linear_id) | (1 << (linear_id + PCM_HOTPLUG_VALID_SHIFT))); spm_lock_release(); } trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/spm/spm_hotplug.h000066400000000000000000000004711355360272700255700ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPM_HOTPLUG_H #define SPM_HOTPLUG_H void spm_clear_hotplug(void); void spm_hotplug_off(unsigned long mpidr); void spm_hotplug_on(unsigned long mpidr); #endif /* SPM_HOTPLUG_H */ trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/spm/spm_mcdi.c000066400000000000000000000510071355360272700250160ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include /* * System Power Manager (SPM) is a hardware module, which controls cpu or * system power for different power scenarios using different firmware. * This driver controls the cpu power in cpu idle power saving state. */ #define WAKE_SRC_FOR_MCDI \ (WAKE_SRC_KP | WAKE_SRC_GPT | WAKE_SRC_EINT | \ WAKE_SRC_MD32 | WAKE_SRC_USB_CD | WAKE_SRC_USB_PDN | \ WAKE_SRC_AFE | WAKE_SRC_THERM | WAKE_SRC_CIRQ | \ WAKE_SRC_SYSPWREQ | WAKE_SRC_CPU_IRQ) #define PCM_MCDI_HANDSHAKE_SYNC 0xbeefbeef #define PCM_MCDI_HANDSHAKE_ACK 0xdeaddead #define PCM_MCDI_UPDATE_INFORM 0xabcdabcd #define PCM_MCDI_CKECK_DONE 0x12345678 #define PCM_MCDI_ALL_CORE_AWAKE 0x0 #define PCM_MCDI_OFFLOADED 0xaa55aa55 #define PCM_MCDI_CA72_CPUTOP_PWRCTL (0x1 << 16) #define PCM_MCDI_CA53_CPUTOP_PWRCTL (0x1 << 17) #define PCM_MCDI_CA72_PWRSTA_SHIFT 16 #define PCM_MCDI_CA53_PWRSTA_SHIFT 9 static const unsigned int mcdi_binary[] = { 0x1a10001f, 0x10006b04, 0x1890001f, 0x10006b6c, 0x1a40001f, 0x10006210, 0x18d0001f, 0x10006210, 0x81002001, 0xd82001c4, 0x17c07c1f, 0xa0900402, 0xc2401540, 0x17c07c1f, 0x81052001, 0xd8200284, 0x17c07c1f, 0xa0950402, 0xc2401b80, 0x17c07c1f, 0x1a40001f, 0x10006230, 0x18d0001f, 0x10006230, 0x8100a001, 0xd82003c4, 0x17c07c1f, 0xa0908402, 0xc2401540, 0x17c07c1f, 0x8105a001, 0xd8200484, 0x17c07c1f, 0xa0958402, 0xc2401b80, 0x17c07c1f, 0x1a40001f, 0x10006238, 0x18d0001f, 0x10006238, 0x81012001, 0xd82005c4, 0x17c07c1f, 0xa0910402, 0xc2401540, 0x17c07c1f, 0x81062001, 0xd8200684, 0x17c07c1f, 0xa0960402, 0xc2401b80, 0x17c07c1f, 0x1a40001f, 0x1000623c, 0x18d0001f, 0x1000623c, 0x8101a001, 0xd82007c4, 0x17c07c1f, 0xa0918402, 0xc2401540, 0x17c07c1f, 0x8106a001, 0xd8200884, 0x17c07c1f, 0xa0968402, 0xc2401b80, 0x17c07c1f, 0x1a40001f, 0x10006298, 0x18d0001f, 0x10006298, 0x81022001, 0xd82009c4, 0x17c07c1f, 0xa0920402, 0xc2401540, 0x17c07c1f, 0x81072001, 0xd8200a84, 0x17c07c1f, 0xa0970402, 0xc2401b80, 0x17c07c1f, 0x1a40001f, 0x1000629c, 0x18d0001f, 0x1000629c, 0x8102a001, 0xd8200bc4, 0x17c07c1f, 0xa0928402, 0xc2401540, 0x17c07c1f, 0x8107a001, 0xd8200c84, 0x17c07c1f, 0xa0978402, 0xc2401b80, 0x17c07c1f, 0x1a40001f, 0x100062c4, 0x18d0001f, 0x100062c4, 0x81032001, 0xd8200dc4, 0x17c07c1f, 0xa0930402, 0xc2401540, 0x17c07c1f, 0x81082001, 0xd8200e84, 0x17c07c1f, 0xa0980402, 0xc2401b80, 0x17c07c1f, 0x1a40001f, 0x100062c0, 0x18d0001f, 0x100062c0, 0x8103a001, 0xd8200fc4, 0x17c07c1f, 0xa0938402, 0xc2401540, 0x17c07c1f, 0x8108a001, 0xd8201084, 0x17c07c1f, 0xa0988402, 0xc2401b80, 0x17c07c1f, 0x1a40001f, 0x10006214, 0x18d0001f, 0x10006214, 0x81042001, 0xd82011c4, 0x17c07c1f, 0xa0940402, 0xc2401540, 0x17c07c1f, 0x81092001, 0xd8201284, 0x17c07c1f, 0xa0990402, 0xc2401b80, 0x17c07c1f, 0x1a40001f, 0x100062cc, 0x18d0001f, 0x100062cc, 0x8104a001, 0xd82013c4, 0x17c07c1f, 0xa0948402, 0xc2401540, 0x17c07c1f, 0x8109a001, 0xd8201484, 0x17c07c1f, 0xa0998402, 0xc2401b80, 0x17c07c1f, 0x1900001f, 0x10006b6c, 0x80802002, 0xe1000002, 0xf0000000, 0x17c07c1f, 0xa8c00003, 0x00000004, 0xe2400003, 0xa8c00003, 0x00000008, 0xe2400003, 0x1b80001f, 0x00000020, 0x88c00003, 0xffffffef, 0xe2400003, 0x88c00003, 0xfffffffd, 0xe2400003, 0xa8c00003, 0x00000001, 0xe2400003, 0x88c00003, 0xfffff0ff, 0xe2400003, 0x1b80001f, 0x20000080, 0x1a90001f, 0x10001220, 0x69200009, 0x1000623c, 0xd8001984, 0x17c07c1f, 0x69200009, 0x10006214, 0xd8001a64, 0x17c07c1f, 0xd0001b00, 0x17c07c1f, 0x1900001f, 0x10001220, 0x8a80000a, 0xfffffff9, 0xe100000a, 0xd0001b00, 0x17c07c1f, 0x1900001f, 0x10001220, 0x8a80000a, 0xff1fbfff, 0xe100000a, 0x1b80001f, 0x20000080, 0xf0000000, 0x17c07c1f, 0x1a90001f, 0x10001220, 0x69200009, 0x1000623c, 0xd8001d04, 0x17c07c1f, 0x69200009, 0x10006214, 0xd8001de4, 0x17c07c1f, 0xd0001e80, 0x17c07c1f, 0x1900001f, 0x10001220, 0xaa80000a, 0x00000006, 0xe100000a, 0xd0001e80, 0x17c07c1f, 0x1900001f, 0x10001220, 0xaa80000a, 0x00e04000, 0xe100000a, 0x1b80001f, 0x20000080, 0x69200009, 0x10006214, 0xd8001fe4, 0x17c07c1f, 0xa8c00003, 0x00000f00, 0xe2400003, 0xd0002040, 0x17c07c1f, 0xa8c00003, 0x00003f00, 0xe2400003, 0x1b80001f, 0x20000080, 0xa8c00003, 0x00000002, 0xe2400003, 0x88c00003, 0xfffffffe, 0xe2400003, 0xa8c00003, 0x00000010, 0xe2400003, 0x88c00003, 0xfffffffb, 0xe2400003, 0x88c00003, 0xfffffff7, 0xe2400003, 0xf0000000, 0x17c07c1f, 0xe2e00036, 0xe2e0003e, 0x1b80001f, 0x00000020, 0xe2e0003c, 0xe8208000, 0x10006244, 0x00000000, 0x1b80001f, 0x20000080, 0xe2e0007c, 0x1b80001f, 0x20000003, 0xe2e0005c, 0xe2e0004c, 0xe2e0004d, 0xf0000000, 0x17c07c1f, 0xe2e0004f, 0xe2e0006f, 0xe2e0002f, 0xe8208000, 0x10006244, 0x00000001, 0x1b80001f, 0x20000080, 0xe2e0002e, 0xe2e0003e, 0xe2e0003a, 0xe2e00032, 0x1b80001f, 0x00000020, 0xf0000000, 0x17c07c1f, 0xe2e00036, 0xe2e0003e, 0x1b80001f, 0x00000020, 0xe2e0003c, 0xe2a00000, 0x1b80001f, 0x20000080, 0xe2e0007c, 0x1b80001f, 0x20000003, 0xe2e0005c, 0xe2e0004c, 0xe2e0004d, 0xf0000000, 0x17c07c1f, 0xe2e0004f, 0xe2e0006f, 0xe2e0002f, 0xe2a00001, 0x1b80001f, 0x20000080, 0xe2e0002e, 0xe2e0003e, 0xe2e0003a, 0xe2e00032, 0xf0000000, 0x17c07c1f, 0xe2e00026, 0xe2e0002e, 0x1b80001f, 0x00000020, 0x1a00001f, 0x100062b4, 0x1910001f, 0x100062b4, 0x81322804, 0xe2000004, 0x81202804, 0xe2000004, 0x1b80001f, 0x20000080, 0xe2e0000e, 0xe2e0000c, 0xe2e0000d, 0xf0000000, 0x17c07c1f, 0xe2e0002d, 0x1a00001f, 0x100062b4, 0x1910001f, 0x100062b4, 0xa1002804, 0xe2000004, 0xa1122804, 0xe2000004, 0x1b80001f, 0x20000080, 0xe2e0002f, 0xe2e0002b, 0xe2e00023, 0x1b80001f, 0x00000020, 0xe2e00022, 0xf0000000, 0x17c07c1f, 0x1910001f, 0x1000660c, 0x1a10001f, 0x10006610, 0xa2002004, 0x89000008, 0x00030000, 0xd80036c4, 0x17c07c1f, 0x8207a001, 0xd82036c8, 0x17c07c1f, 0x1900001f, 0x1020020c, 0x1a10001f, 0x1020020c, 0xaa000008, 0x00000001, 0xe1000008, 0x1910001f, 0x1020020c, 0x81001001, 0xd8203184, 0x17c07c1f, 0x1910001f, 0x10006720, 0x820c9001, 0xd8203228, 0x17c07c1f, 0x1900001f, 0x10001220, 0x1a10001f, 0x10001220, 0xa21f0408, 0xe1000008, 0x1b80001f, 0x20000080, 0xe2e0006d, 0xe2e0002d, 0x1a00001f, 0x100062b8, 0x1910001f, 0x100062b8, 0xa9000004, 0x00000001, 0xe2000004, 0x1b80001f, 0x20000080, 0xe2e0002c, 0xe2e0003c, 0xe2e0003e, 0xe2e0003a, 0xe2e00032, 0x1b80001f, 0x00000020, 0x1900001f, 0x10006404, 0x1a10001f, 0x10006404, 0xa2168408, 0xe1000008, 0xf0000000, 0x17c07c1f, 0x1a10001f, 0x10006610, 0x8207a001, 0xd8003e68, 0x17c07c1f, 0x1a10001f, 0x10006918, 0x8a000008, 0x00003030, 0xb900010c, 0x01000001, 0xd8203e64, 0x17c07c1f, 0x1900001f, 0x10006404, 0x1a10001f, 0x10006404, 0x8a000008, 0x0000dfff, 0xe1000008, 0xe2e00036, 0xe2e0003e, 0x1b80001f, 0x00000020, 0xe2e0002e, 0x1a00001f, 0x100062b8, 0x1910001f, 0x100062b8, 0x89000004, 0x0000fffe, 0xe2000004, 0x1b80001f, 0x20000080, 0xe2e0006e, 0xe2e0004e, 0xe2e0004c, 0xe2e0004d, 0x1900001f, 0x10001220, 0x1a10001f, 0x10001220, 0x8a000008, 0xbfffffff, 0xe1000008, 0x1b80001f, 0x20000080, 0x1900001f, 0x1020020c, 0x1a10001f, 0x1020020c, 0x8a000008, 0xfffffffe, 0xe1000008, 0x1910001f, 0x1020020c, 0x81001001, 0xd8003dc4, 0x17c07c1f, 0xf0000000, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x1840001f, 0x00000001, 0x11407c1f, 0xe8208000, 0x10006310, 0x0b160008, 0x1900001f, 0x000f7bde, 0x1a00001f, 0x10200268, 0xe2000004, 0xe8208000, 0x10006600, 0x00000000, 0x69200006, 0xbeefbeef, 0xd8204584, 0x17c07c1f, 0x1910001f, 0x10006358, 0x810b1001, 0xd8004244, 0x17c07c1f, 0x1980001f, 0xdeaddead, 0x69200006, 0xabcdabcd, 0xd8204324, 0x17c07c1f, 0x88900001, 0x10006814, 0x1910001f, 0x10006400, 0x81271002, 0x1880001f, 0x10006600, 0xe0800004, 0x1910001f, 0x10006358, 0x810b1001, 0xd80044a4, 0x17c07c1f, 0x1980001f, 0x12345678, 0x60a07c05, 0x89100002, 0x10006600, 0x80801001, 0xd8007bc2, 0x17c07c1f, 0x1890001f, 0x10006b00, 0x82090801, 0xc8800008, 0x17c07c1f, 0x1b00001f, 0x3fffe7ff, 0x8a00000c, 0x3fffe7ff, 0xd82041c8, 0x17c07c1f, 0x1b80001f, 0xd0010000, 0x1a10001f, 0x10006720, 0x82002001, 0x82201408, 0xd8204988, 0x17c07c1f, 0x1a40001f, 0x10006200, 0x1a80001f, 0x1000625c, 0xc24028e0, 0x17c07c1f, 0xa1400405, 0x1a10001f, 0x10006720, 0x8200a001, 0x82209408, 0xd8204b28, 0x17c07c1f, 0x1a40001f, 0x10006218, 0x1a80001f, 0x10006264, 0xc24028e0, 0x17c07c1f, 0xa1508405, 0x1a10001f, 0x10006720, 0x82012001, 0x82211408, 0xd8204cc8, 0x17c07c1f, 0x1a40001f, 0x1000621c, 0x1a80001f, 0x1000626c, 0xc24028e0, 0x17c07c1f, 0xa1510405, 0x1a10001f, 0x10006720, 0x8201a001, 0x82219408, 0xd8204e68, 0x17c07c1f, 0x1a40001f, 0x10006220, 0x1a80001f, 0x10006274, 0xc24028e0, 0x17c07c1f, 0xa1518405, 0x1a10001f, 0x10006720, 0x82022001, 0x82221408, 0xd8204fe8, 0x17c07c1f, 0x1a40001f, 0x100062a0, 0x1280041f, 0xc2402cc0, 0x17c07c1f, 0xa1520405, 0x1a10001f, 0x10006720, 0x8202a001, 0x82229408, 0xd8205168, 0x17c07c1f, 0x1a40001f, 0x100062a4, 0x1290841f, 0xc2402cc0, 0x17c07c1f, 0xa1528405, 0x1a10001f, 0x10006720, 0x82032001, 0x82231408, 0xd8205248, 0x17c07c1f, 0xa1530405, 0x1a10001f, 0x10006720, 0x8203a001, 0x82239408, 0xd8205328, 0x17c07c1f, 0xa1538405, 0x1a10001f, 0x10006b00, 0x8108a001, 0xd8205e84, 0x17c07c1f, 0x1910001f, 0x1000660c, 0x1a10001f, 0x10006610, 0xa2002004, 0x89000008, 0x00001e00, 0xd8005944, 0x17c07c1f, 0x82042001, 0xd8205948, 0x17c07c1f, 0x1900001f, 0x1020002c, 0x1a10001f, 0x1020002c, 0xaa000008, 0x00000010, 0xe1000008, 0x1910001f, 0x10006720, 0x820c1001, 0xd8205628, 0x17c07c1f, 0x1900001f, 0x10001250, 0x1a10001f, 0x10001250, 0xa2110408, 0xe1000008, 0x1b80001f, 0x20000080, 0x1900001f, 0x10001220, 0x1a10001f, 0x10001220, 0xa21e8408, 0xe1000008, 0x1b80001f, 0x20000080, 0x1a40001f, 0x10006208, 0xc24024e0, 0x17c07c1f, 0x1a10001f, 0x10006610, 0x82042001, 0xd8005e88, 0x17c07c1f, 0x1a10001f, 0x10006918, 0x8a000008, 0x00000f0f, 0xba00010c, 0x1fffe7ff, 0xd8205e88, 0x17c07c1f, 0x1a40001f, 0x10006208, 0xc24022a0, 0x17c07c1f, 0x1900001f, 0x10001250, 0x1a10001f, 0x10001250, 0x8a000008, 0xfffffffb, 0xe1000008, 0x1b80001f, 0x20000080, 0x1900001f, 0x10001220, 0x1a10001f, 0x10001220, 0x8a000008, 0xdfffffff, 0xe1000008, 0x1b80001f, 0x20000080, 0x1900001f, 0x1020002c, 0x1a10001f, 0x1020002c, 0x8a000008, 0xffffffef, 0xe1000008, 0x1a10001f, 0x10006b00, 0x81082001, 0xd8205fa4, 0x17c07c1f, 0x1a40001f, 0x100062b0, 0xc2402f20, 0x17c07c1f, 0x1b80001f, 0x20000208, 0xd8207b8c, 0x17c07c1f, 0x1a40001f, 0x100062b0, 0xc2403700, 0x17c07c1f, 0x81001401, 0xd8206424, 0x17c07c1f, 0x1a10001f, 0x10006918, 0x81002001, 0xb1042081, 0xb900008c, 0x1fffe7ff, 0xd8206424, 0x17c07c1f, 0x1a40001f, 0x10006200, 0x1a80001f, 0x1000625c, 0xc24026e0, 0x17c07c1f, 0x89400005, 0xfffffffe, 0xe8208000, 0x10006f00, 0x00000000, 0xe8208000, 0x10006b30, 0x00000000, 0xe8208000, 0x100063e0, 0x00000001, 0x81009401, 0xd82067a4, 0x17c07c1f, 0x1a10001f, 0x10006918, 0x8100a001, 0xb104a081, 0xb900008c, 0x01000001, 0xd82067a4, 0x17c07c1f, 0x1a40001f, 0x10006218, 0x1a80001f, 0x10006264, 0xc24026e0, 0x17c07c1f, 0x89400005, 0xfffffffd, 0xe8208000, 0x10006f04, 0x00000000, 0xe8208000, 0x10006b34, 0x00000000, 0xe8208000, 0x100063e0, 0x00000002, 0x81011401, 0xd8206b24, 0x17c07c1f, 0x1a10001f, 0x10006918, 0x81012001, 0xb1052081, 0xb900008c, 0x01000001, 0xd8206b24, 0x17c07c1f, 0x1a40001f, 0x1000621c, 0x1a80001f, 0x1000626c, 0xc24026e0, 0x17c07c1f, 0x89400005, 0xfffffffb, 0xe8208000, 0x10006f08, 0x00000000, 0xe8208000, 0x10006b38, 0x00000000, 0xe8208000, 0x100063e0, 0x00000004, 0x81019401, 0xd8206ea4, 0x17c07c1f, 0x1a10001f, 0x10006918, 0x8101a001, 0xb105a081, 0xb900008c, 0x01000001, 0xd8206ea4, 0x17c07c1f, 0x1a40001f, 0x10006220, 0x1a80001f, 0x10006274, 0xc24026e0, 0x17c07c1f, 0x89400005, 0xfffffff7, 0xe8208000, 0x10006f0c, 0x00000000, 0xe8208000, 0x10006b3c, 0x00000000, 0xe8208000, 0x100063e0, 0x00000008, 0x1a10001f, 0x10006610, 0x8207a001, 0xd8207608, 0x17c07c1f, 0x81021401, 0xd82072a4, 0x17c07c1f, 0x1a10001f, 0x10006918, 0x81022001, 0xb1062081, 0xb900008c, 0x01000001, 0xd82072a4, 0x17c07c1f, 0x1a40001f, 0x100062a0, 0x1280041f, 0xc2402a60, 0x17c07c1f, 0x89400005, 0xffffffef, 0xe8208000, 0x10006f10, 0x00000000, 0xe8208000, 0x10006b40, 0x00000000, 0xe8208000, 0x100063e0, 0x00000010, 0x81029401, 0xd8207604, 0x17c07c1f, 0x1a10001f, 0x10006918, 0x8102a001, 0xb106a081, 0xb900008c, 0x01000001, 0xd8207604, 0x17c07c1f, 0x1a40001f, 0x100062a4, 0x1290841f, 0xc2402a60, 0x17c07c1f, 0x89400005, 0xffffffdf, 0xe8208000, 0x10006f14, 0x00000000, 0xe8208000, 0x10006b44, 0x00000000, 0xe8208000, 0x100063e0, 0x00000020, 0x81031401, 0xd82078c4, 0x17c07c1f, 0x1a10001f, 0x10006918, 0x81032001, 0xb1072081, 0xb900008c, 0x01000001, 0xd82078c4, 0x17c07c1f, 0x89400005, 0xffffffbf, 0xe8208000, 0x10006f18, 0x00000000, 0xe8208000, 0x10006b48, 0x00000000, 0xe8208000, 0x100063e0, 0x00000040, 0x81039401, 0xd8207b84, 0x17c07c1f, 0x1a10001f, 0x10006918, 0x8103a001, 0xb107a081, 0xb900008c, 0x01000001, 0xd8207b84, 0x17c07c1f, 0x89400005, 0xffffff7f, 0xe8208000, 0x10006f1c, 0x00000000, 0xe8208000, 0x10006b4c, 0x00000000, 0xe8208000, 0x100063e0, 0x00000080, 0xd00041c0, 0x17c07c1f, 0xe8208000, 0x10006600, 0x00000000, 0x1ac0001f, 0x55aa55aa, 0x1940001f, 0xaa55aa55, 0x1b80001f, 0x00001000, 0xf0000000, 0x17c07c1f }; static const struct pcm_desc mcdi_pcm = { .version = "pcm_mcdi_mt8173_20160401_v1", .base = mcdi_binary, .size = 1001, .sess = 2, .replace = 0, }; static struct pwr_ctrl mcdi_ctrl = { .wake_src = WAKE_SRC_FOR_MCDI, .wake_src_md32 = 0, .wfi_op = WFI_OP_OR, .mcusys_idle_mask = 1, .ca7top_idle_mask = 1, .ca15top_idle_mask = 1, .disp_req_mask = 1, .mfg_req_mask = 1, .md32_req_mask = 1, }; static const struct spm_lp_scen spm_mcdi = { .pcmdesc = &mcdi_pcm, .pwrctrl = &mcdi_ctrl, }; void spm_mcdi_cpu_wake_up_event(int wake_up_event, int disable_dormant_power) { if (((mmio_read_32(SPM_SLEEP_CPU_WAKEUP_EVENT) & 0x1) == 1) && ((mmio_read_32(SPM_CLK_CON) & CC_DISABLE_DORM_PWR) == 0)) { /* MCDI is offload? */ INFO("%s: SPM_SLEEP_CPU_WAKEUP_EVENT:%x, SPM_CLK_CON %x", __func__, mmio_read_32(SPM_SLEEP_CPU_WAKEUP_EVENT), mmio_read_32(SPM_CLK_CON)); return; } /* Inform SPM that CPU wants to program CPU_WAKEUP_EVENT and * DISABLE_CPU_DROM */ mmio_write_32(SPM_PCM_REG_DATA_INI, PCM_MCDI_HANDSHAKE_SYNC); mmio_write_32(SPM_PCM_PWR_IO_EN, PCM_RF_SYNC_R6); mmio_write_32(SPM_PCM_PWR_IO_EN, 0); /* Wait SPM's response, can't use sleep api */ while (mmio_read_32(SPM_PCM_REG6_DATA) != PCM_MCDI_HANDSHAKE_ACK) ; if (disable_dormant_power) { mmio_setbits_32(SPM_CLK_CON, CC_DISABLE_DORM_PWR); while (mmio_read_32(SPM_CLK_CON) != (mmio_read_32(SPM_CLK_CON) | CC_DISABLE_DORM_PWR)) ; } else { mmio_clrbits_32(SPM_CLK_CON, CC_DISABLE_DORM_PWR); while (mmio_read_32(SPM_CLK_CON) != (mmio_read_32(SPM_CLK_CON) & ~CC_DISABLE_DORM_PWR)) ; } mmio_write_32(SPM_SLEEP_CPU_WAKEUP_EVENT, wake_up_event); while (mmio_read_32(SPM_SLEEP_CPU_WAKEUP_EVENT) != wake_up_event) ; /* Inform SPM to see updated setting */ mmio_write_32(SPM_PCM_REG_DATA_INI, PCM_MCDI_UPDATE_INFORM); mmio_write_32(SPM_PCM_PWR_IO_EN, PCM_RF_SYNC_R6); mmio_write_32(SPM_PCM_PWR_IO_EN, 0); while (mmio_read_32(SPM_PCM_REG6_DATA) != PCM_MCDI_CKECK_DONE) ; /* END OF sequence */ mmio_write_32(SPM_PCM_REG_DATA_INI, 0x0); mmio_write_32(SPM_PCM_PWR_IO_EN, PCM_RF_SYNC_R6); mmio_write_32(SPM_PCM_PWR_IO_EN, 0); } void spm_mcdi_wakeup_all_cores(void) { if (is_mcdi_ready() == 0) return; spm_mcdi_cpu_wake_up_event(1, 1); while (mmio_read_32(SPM_PCM_REG5_DATA) != PCM_MCDI_ALL_CORE_AWAKE) ; spm_mcdi_cpu_wake_up_event(1, 0); while (mmio_read_32(SPM_PCM_REG5_DATA) != PCM_MCDI_OFFLOADED) ; spm_clean_after_wakeup(); clear_all_ready(); } static void spm_mcdi_wfi_sel_enter(unsigned long mpidr) { int core_id_val = mpidr & MPIDR_CPU_MASK; int cluster_id = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS; /* SPM WFI Select by core number */ if (cluster_id) { switch (core_id_val) { case 0: mmio_write_32(SPM_CA15_CPU0_IRQ_MASK, 1); mmio_write_32(SPM_SLEEP_CA15_WFI0_EN, 1); break; case 1: mmio_write_32(SPM_CA15_CPU1_IRQ_MASK, 1); mmio_write_32(SPM_SLEEP_CA15_WFI1_EN, 1); break; case 2: mmio_write_32(SPM_CA15_CPU2_IRQ_MASK, 1); mmio_write_32(SPM_SLEEP_CA15_WFI2_EN, 1); break; case 3: mmio_write_32(SPM_CA15_CPU3_IRQ_MASK, 1); mmio_write_32(SPM_SLEEP_CA15_WFI3_EN, 1); break; default: break; } } else { switch (core_id_val) { case 0: mmio_write_32(SPM_CA7_CPU0_IRQ_MASK, 1); mmio_write_32(SPM_SLEEP_CA7_WFI0_EN, 1); break; case 1: mmio_write_32(SPM_CA7_CPU1_IRQ_MASK, 1); mmio_write_32(SPM_SLEEP_CA7_WFI1_EN, 1); break; case 2: mmio_write_32(SPM_CA7_CPU2_IRQ_MASK, 1); mmio_write_32(SPM_SLEEP_CA7_WFI2_EN, 1); break; case 3: mmio_write_32(SPM_CA7_CPU3_IRQ_MASK, 1); mmio_write_32(SPM_SLEEP_CA7_WFI3_EN, 1); break; default: break; } } } static void spm_mcdi_wfi_sel_leave(unsigned long mpidr) { int core_id_val = mpidr & MPIDR_CPU_MASK; int cluster_id = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS; /* SPM WFI Select by core number */ if (cluster_id) { switch (core_id_val) { case 0: mmio_write_32(SPM_SLEEP_CA15_WFI0_EN, 0); mmio_write_32(SPM_CA15_CPU0_IRQ_MASK, 0); break; case 1: mmio_write_32(SPM_SLEEP_CA15_WFI1_EN, 0); mmio_write_32(SPM_CA15_CPU1_IRQ_MASK, 0); break; case 2: mmio_write_32(SPM_SLEEP_CA15_WFI2_EN, 0); mmio_write_32(SPM_CA15_CPU2_IRQ_MASK, 0); break; case 3: mmio_write_32(SPM_SLEEP_CA15_WFI3_EN, 0); mmio_write_32(SPM_CA15_CPU3_IRQ_MASK, 0); break; default: break; } } else { switch (core_id_val) { case 0: mmio_write_32(SPM_SLEEP_CA7_WFI0_EN, 0); mmio_write_32(SPM_CA7_CPU0_IRQ_MASK, 0); break; case 1: mmio_write_32(SPM_SLEEP_CA7_WFI1_EN, 0); mmio_write_32(SPM_CA7_CPU1_IRQ_MASK, 0); break; case 2: mmio_write_32(SPM_SLEEP_CA7_WFI2_EN, 0); mmio_write_32(SPM_CA7_CPU2_IRQ_MASK, 0); break; case 3: mmio_write_32(SPM_SLEEP_CA7_WFI3_EN, 0); mmio_write_32(SPM_CA7_CPU3_IRQ_MASK, 0); break; default: break; } } } static void spm_mcdi_set_cputop_pwrctrl_for_cluster_off(unsigned long mpidr) { unsigned long cluster_id = mpidr & MPIDR_CLUSTER_MASK; unsigned long cpu_id = mpidr & MPIDR_CPU_MASK; unsigned int pwr_status, shift, i, flag = 0; pwr_status = mmio_read_32(SPM_PWR_STATUS) | mmio_read_32(SPM_PWR_STATUS_2ND); if (cluster_id) { for (i = 0; i < PLATFORM_CLUSTER1_CORE_COUNT; i++) { if (i == cpu_id) continue; shift = i + PCM_MCDI_CA72_PWRSTA_SHIFT; flag |= (pwr_status & (1 << shift)) >> shift; } if (!flag) mmio_setbits_32(SPM_PCM_RESERVE, PCM_MCDI_CA72_CPUTOP_PWRCTL); } else { for (i = 0; i < PLATFORM_CLUSTER0_CORE_COUNT; i++) { if (i == cpu_id) continue; shift = i + PCM_MCDI_CA53_PWRSTA_SHIFT; flag |= (pwr_status & (1 << shift)) >> shift; } if (!flag) mmio_setbits_32(SPM_PCM_RESERVE, PCM_MCDI_CA53_CPUTOP_PWRCTL); } } static void spm_mcdi_clear_cputop_pwrctrl_for_cluster_on(unsigned long mpidr) { unsigned long cluster_id = mpidr & MPIDR_CLUSTER_MASK; if (cluster_id) mmio_clrbits_32(SPM_PCM_RESERVE, PCM_MCDI_CA72_CPUTOP_PWRCTL); else mmio_clrbits_32(SPM_PCM_RESERVE, PCM_MCDI_CA53_CPUTOP_PWRCTL); } void spm_mcdi_prepare_for_mtcmos(void) { const struct pcm_desc *pcmdesc = spm_mcdi.pcmdesc; struct pwr_ctrl *pwrctrl = spm_mcdi.pwrctrl; if (is_mcdi_ready() == 0) { if (is_hotplug_ready() == 1) spm_clear_hotplug(); set_pwrctrl_pcm_flags(pwrctrl, 0); spm_reset_and_init_pcm(); spm_kick_im_to_fetch(pcmdesc); spm_set_power_control(pwrctrl); spm_set_wakeup_event(pwrctrl); spm_kick_pcm_to_run(pwrctrl); set_mcdi_ready(); } } void spm_mcdi_prepare_for_off_state(unsigned long mpidr, unsigned int afflvl) { const struct pcm_desc *pcmdesc = spm_mcdi.pcmdesc; struct pwr_ctrl *pwrctrl = spm_mcdi.pwrctrl; spm_lock_get(); if (is_mcdi_ready() == 0) { if (is_hotplug_ready() == 1) spm_clear_hotplug(); set_pwrctrl_pcm_flags(pwrctrl, 0); spm_reset_and_init_pcm(); spm_kick_im_to_fetch(pcmdesc); spm_set_power_control(pwrctrl); spm_set_wakeup_event(pwrctrl); spm_kick_pcm_to_run(pwrctrl); set_mcdi_ready(); } spm_mcdi_wfi_sel_enter(mpidr); if (afflvl == MPIDR_AFFLVL1) spm_mcdi_set_cputop_pwrctrl_for_cluster_off(mpidr); spm_lock_release(); } void spm_mcdi_finish_for_on_state(unsigned long mpidr, unsigned int afflvl) { unsigned long linear_id; linear_id = ((mpidr & MPIDR_CLUSTER_MASK) >> 6) | (mpidr & MPIDR_CPU_MASK); spm_lock_get(); spm_mcdi_clear_cputop_pwrctrl_for_cluster_on(mpidr); spm_mcdi_wfi_sel_leave(mpidr); mmio_write_32(SPM_PCM_SW_INT_CLEAR, (0x1 << linear_id)); spm_lock_release(); } trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/spm/spm_mcdi.h000066400000000000000000000006471355360272700250270ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPM_MCDI_H #define SPM_MCDI_H void spm_mcdi_wakeup_all_cores(void); void spm_mcdi_prepare_for_mtcmos(void); void spm_mcdi_prepare_for_off_state(unsigned long mpidr, unsigned int afflvl); void spm_mcdi_finish_for_on_state(unsigned long mpidr, unsigned int afflvl); #endif /* SPM_MCDI_H */ trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/spm/spm_suspend.c000066400000000000000000000347401355360272700255700ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* * System Power Manager (SPM) is a hardware module, which controls cpu or * system power for different power scenarios using different firmware. * This driver controls the system power in system suspend flow. */ #define WAKE_SRC_FOR_SUSPEND \ (WAKE_SRC_KP | WAKE_SRC_EINT | WAKE_SRC_MD32 | \ WAKE_SRC_USB_CD | WAKE_SRC_USB_PDN | WAKE_SRC_THERM | \ WAKE_SRC_SYSPWREQ | WAKE_SRC_ALL_MD32) #define WAKE_SRC_FOR_MD32 0 #define spm_is_wakesrc_invalid(wakesrc) \ (!!((unsigned int)(wakesrc) & 0xc0003803)) #define ARMCA15PLL_CON0 (APMIXED_BASE + 0x200) #define ARMCA15PLL_CON1 (APMIXED_BASE + 0x204) #define ARMCA15PLL_PWR_CON0 (APMIXED_BASE + 0x20c) #define ARMCA15PLL_PWR_ON (1U << 0) #define ARMCA15PLL_ISO_EN (1U << 1) #define ARMCA15PLL_EN (1U << 0) const unsigned int spm_flags = SPM_DUALVCORE_PDN_DIS | SPM_PASR_DIS | SPM_DPD_DIS | SPM_CPU_DVS_DIS | SPM_OPT | SPM_INFRA_PDN_DIS; enum wake_reason_t spm_wake_reason = WR_NONE; /********************************************************** * PCM sequence for cpu suspend **********************************************************/ static const unsigned int suspend_binary_ca7[] = { 0x81f58407, 0x81f68407, 0x803a0400, 0x803a8400, 0x1b80001f, 0x20000000, 0x80300400, 0x80318400, 0x80328400, 0xa1d28407, 0x81f20407, 0x81009801, 0xd8000244, 0x17c07c1f, 0x18c0001f, 0x10006234, 0xc0c032e0, 0x1200041f, 0x80310400, 0x1b80001f, 0x2000000a, 0xa0110400, 0x18c0001f, 0x100062c8, 0xe0e00010, 0xe0e00030, 0xe0e00070, 0xe0e000f0, 0x1b80001f, 0x2000001a, 0xe0e00ff0, 0xe8208000, 0x10006354, 0xfffe7fff, 0xe8208000, 0x10006834, 0x00000010, 0x81f00407, 0xa1dd0407, 0x81fd0407, 0xc2803800, 0x1290041f, 0x8880000c, 0x2f7be75f, 0xd8200722, 0x17c07c1f, 0xd82006a9, 0x17c07c1f, 0xe8208000, 0x10006814, 0x00000001, 0xc2803800, 0x1293841f, 0x1b00001f, 0x7fffe7ff, 0xd0000760, 0x17c07c1f, 0x1b00001f, 0x7ffff7ff, 0xf0000000, 0x17c07c1f, 0x80880001, 0xd8000842, 0x17c07c1f, 0xd00028e0, 0x1200041f, 0xe8208000, 0x10006834, 0x00000000, 0x1b00001f, 0x3fffe7ff, 0x1b80001f, 0x20000004, 0xd8200a0c, 0x17c07c1f, 0xe8208000, 0x10006834, 0x00000010, 0xd0001280, 0x17c07c1f, 0x18c0001f, 0x10006608, 0x1910001f, 0x10006608, 0x813b0404, 0xe0c00004, 0x1880001f, 0x10006320, 0xc0c03760, 0xe080000f, 0xd8200c03, 0x17c07c1f, 0x1b00001f, 0x7ffff7ff, 0xd0001280, 0x17c07c1f, 0xe080001f, 0xe8208000, 0x10006354, 0xffffffff, 0x18c0001f, 0x100062c8, 0xe0e000f0, 0xe0e00030, 0xe0e00000, 0x81009801, 0xd80010c4, 0x17c07c1f, 0x18c0001f, 0x10004094, 0x1910001f, 0x1020e374, 0xe0c00004, 0x18c0001f, 0x10004098, 0x1910001f, 0x1020e378, 0xe0c00004, 0x18c0001f, 0x10011094, 0x1910001f, 0x10213374, 0xe0c00004, 0x18c0001f, 0x10011098, 0x1910001f, 0x10213378, 0xe0c00004, 0x1910001f, 0x10213378, 0x18c0001f, 0x10006234, 0xc0c034a0, 0x17c07c1f, 0xc2803800, 0x1290841f, 0xa1d20407, 0x81f28407, 0xa1d68407, 0xa0128400, 0xa0118400, 0xa0100400, 0xa01a8400, 0xa01a0400, 0x19c0001f, 0x001c239f, 0x1b00001f, 0x3fffefff, 0xf0000000, 0x17c07c1f, 0x808d8001, 0xd8201502, 0x17c07c1f, 0x803d8400, 0x1b80001f, 0x2000001a, 0x80340400, 0x17c07c1f, 0x17c07c1f, 0x80310400, 0x81fa0407, 0x81f18407, 0x81f08407, 0xa1dc0407, 0x1b80001f, 0x200000b6, 0xd0002220, 0x17c07c1f, 0x1880001f, 0x20000208, 0x81011801, 0xd80016e4, 0x17c07c1f, 0xe8208000, 0x1000f600, 0xd2000000, 0x1380081f, 0x18c0001f, 0x10006240, 0xe0e00016, 0xe0e0001e, 0xe0e0000e, 0xe0e0000f, 0x80368400, 0x1380081f, 0x80370400, 0x1380081f, 0x80360400, 0x803e0400, 0x1380081f, 0x80380400, 0x803b0400, 0xa01d8400, 0x1b80001f, 0x20000034, 0x803d8400, 0x1b80001f, 0x20000152, 0x803d0400, 0x1380081f, 0x18c0001f, 0x1000f5c8, 0x1910001f, 0x1000f5c8, 0xa1000404, 0xe0c00004, 0x18c0001f, 0x100125c8, 0x1910001f, 0x100125c8, 0xa1000404, 0xe0c00004, 0x1910001f, 0x100125c8, 0x80340400, 0x17c07c1f, 0x17c07c1f, 0x80310400, 0xe8208000, 0x10000044, 0x00000100, 0x1b80001f, 0x20000068, 0x1b80001f, 0x2000000a, 0x18c0001f, 0x10006240, 0xe0e0000d, 0x81011801, 0xd8001f64, 0x17c07c1f, 0x18c0001f, 0x100040f4, 0x1910001f, 0x100040f4, 0xa11c8404, 0xe0c00004, 0x1b80001f, 0x2000000a, 0x813c8404, 0xe0c00004, 0x18c0001f, 0x100110f4, 0x1910001f, 0x100110f4, 0xa11c8404, 0xe0c00004, 0x1b80001f, 0x2000000a, 0x813c8404, 0xe0c00004, 0x1b80001f, 0x20000100, 0x81fa0407, 0x81f18407, 0x81f08407, 0xe8208000, 0x10006354, 0xfffe7b47, 0x18c0001f, 0x65930003, 0xc0c031c0, 0x17c07c1f, 0xc2803800, 0x1293041f, 0xa1d80407, 0xa1dc0407, 0x18c0001f, 0x10006608, 0x1910001f, 0x10006608, 0xa11b0404, 0xe0c00004, 0xc2803800, 0x1291041f, 0x8880000c, 0x2f7be75f, 0xd8202362, 0x17c07c1f, 0x1b00001f, 0x3fffe7ff, 0xd00023a0, 0x17c07c1f, 0x1b00001f, 0xbfffe7ff, 0xf0000000, 0x17c07c1f, 0x1890001f, 0x10006608, 0x808b0801, 0xd8202642, 0x17c07c1f, 0x1880001f, 0x10006320, 0xc0c03540, 0xe080000f, 0xd80027a3, 0x17c07c1f, 0xe080001f, 0xa1da0407, 0x81fc0407, 0xa0110400, 0xa0140400, 0xa01d8400, 0xd0003100, 0x17c07c1f, 0x1b80001f, 0x20000fdf, 0x1890001f, 0x10006608, 0x80c98801, 0x810a8801, 0x10918c1f, 0xa0939002, 0x8080080d, 0xd82028e2, 0x12007c1f, 0x1b00001f, 0x3fffe7ff, 0x1b80001f, 0x20000004, 0xd800318c, 0x17c07c1f, 0x1b00001f, 0xbfffe7ff, 0xd0003180, 0x17c07c1f, 0x81f80407, 0x81fc0407, 0x18c0001f, 0x65930006, 0xc0c031c0, 0x17c07c1f, 0x18c0001f, 0x65930007, 0xc0c031c0, 0x17c07c1f, 0x1880001f, 0x10006320, 0xc0c03540, 0xe080000f, 0xd80027a3, 0x17c07c1f, 0xe080001f, 0x18c0001f, 0x65930005, 0xc0c031c0, 0x17c07c1f, 0xa1da0407, 0xe8208000, 0x10000048, 0x00000100, 0x1b80001f, 0x20000068, 0xa0110400, 0xa0140400, 0x18c0001f, 0x1000f5c8, 0x1910001f, 0x1000f5c8, 0x81200404, 0xe0c00004, 0x18c0001f, 0x100125c8, 0x1910001f, 0x100125c8, 0x81200404, 0xe0c00004, 0x1910001f, 0x100125c8, 0xa01d0400, 0xa01b0400, 0xa0180400, 0x803d8400, 0xa01e0400, 0xa0160400, 0xa0170400, 0xa0168400, 0x1b80001f, 0x20000104, 0x81011801, 0xd80030c4, 0x17c07c1f, 0x18c0001f, 0x10006240, 0xc0c034a0, 0x17c07c1f, 0xe8208000, 0x1000f600, 0xd2000001, 0xd8000848, 0x17c07c1f, 0xc2803800, 0x1291841f, 0x1b00001f, 0x7ffff7ff, 0xf0000000, 0x17c07c1f, 0x1900001f, 0x10006830, 0xe1000003, 0x18c0001f, 0x10006834, 0xe0e00000, 0xe0e00001, 0xf0000000, 0x17c07c1f, 0xe0f07f16, 0x1380201f, 0xe0f07f1e, 0x1380201f, 0xe0f07f0e, 0x1b80001f, 0x20000104, 0xe0f07f0c, 0xe0f07f0d, 0xe0f07e0d, 0xe0f07c0d, 0xe0f0780d, 0xf0000000, 0xe0f0700d, 0xe0f07f0d, 0xe0f07f0f, 0xe0f07f1e, 0xf0000000, 0xe0f07f12, 0x11407c1f, 0x81f08407, 0x81f18407, 0x1b80001f, 0x20000001, 0xa1d08407, 0xa1d18407, 0x1392841f, 0x812ab401, 0x80ebb401, 0xa0c00c04, 0xd8203743, 0x17c07c1f, 0x80c01403, 0xd8203563, 0x01400405, 0xf0000000, 0xa1d00407, 0x1b80001f, 0x20000208, 0x80ea3401, 0xf0000000, 0x18c0001f, 0x10006b6c, 0x1910001f, 0x10006b6c, 0xa1002804, 0xf0000000, 0xe0c00004, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x17c07c1f, 0x1840001f, 0x00000001, 0xa1d48407, 0x1990001f, 0x10006b08, 0x1a50001f, 0x10006610, 0x8246a401, 0xe8208000, 0x10006b6c, 0x00000000, 0x1b00001f, 0x2f7be75f, 0x81469801, 0xd8004305, 0x17c07c1f, 0x1b80001f, 0xd00f0000, 0x8880000c, 0x2f7be75f, 0xd8005fa2, 0x17c07c1f, 0xd0004340, 0x17c07c1f, 0x1b80001f, 0x500f0000, 0xe8208000, 0x10006354, 0xfffe7b47, 0xc0c06c00, 0x81401801, 0xd80048e5, 0x17c07c1f, 0x81f60407, 0x18c0001f, 0x10006200, 0xc0c06060, 0x12807c1f, 0xe8208000, 0x1000625c, 0x00000001, 0x1b80001f, 0x20000080, 0xc0c06060, 0x1280041f, 0x18c0001f, 0x10006204, 0xc0c06400, 0x1280041f, 0x18c0001f, 0x10006208, 0xc0c06060, 0x12807c1f, 0xe8208000, 0x10006244, 0x00000001, 0x1b80001f, 0x20000080, 0xc0c06060, 0x1280041f, 0x18d0001f, 0x10200200, 0x18c0001f, 0x10006290, 0xc0c06060, 0x1280041f, 0xe8208000, 0x10006404, 0x00003101, 0xc2803800, 0x1292041f, 0x81469801, 0xd8204a45, 0x17c07c1f, 0x1b00001f, 0x2f7be75f, 0x1b80001f, 0x30000004, 0x8880000c, 0x2f7be75f, 0xd8005a02, 0x17c07c1f, 0xc0c06780, 0x17c07c1f, 0x18c0001f, 0x10006294, 0xe0f07fff, 0xe0e00fff, 0xe0e000ff, 0x81449801, 0xd8004c85, 0x17c07c1f, 0x1a00001f, 0x10006604, 0xe2200003, 0xc0c06840, 0x17c07c1f, 0xe2200005, 0xc0c06840, 0x17c07c1f, 0xa1d38407, 0xa1d98407, 0x1800001f, 0x00000012, 0x1800001f, 0x00000e12, 0x1800001f, 0x03800e12, 0x1800001f, 0x038e0e12, 0xe8208000, 0x10006310, 0x0b1600f8, 0x1940001f, 0x00000000, 0x12407c1f, 0x1b00001f, 0xbfffe7ff, 0x1b80001f, 0x90100000, 0x17c07c1f, 0xd8004fc5, 0x17c07c1f, 0x8247b001, 0x1940001f, 0xffffffff, 0x80c00400, 0xd82050c3, 0xa1d58407, 0xa1dd8407, 0x1b00001f, 0x3fffefff, 0xd0004ec0, 0x17c07c1f, 0x1890001f, 0x100063e8, 0x88c0000c, 0x2f7be75f, 0xd80052e3, 0x17c07c1f, 0x80c40001, 0xd8005263, 0x17c07c1f, 0x1b00001f, 0xbfffe7ff, 0xd00052a0, 0x17c07c1f, 0x1b00001f, 0x7ffff7ff, 0xd0004ec0, 0x17c07c1f, 0x80c40001, 0xd82053e3, 0x17c07c1f, 0xa1de0407, 0x1b00001f, 0x7fffe7ff, 0xd0004ec0, 0x17c07c1f, 0xe8208000, 0x10006814, 0x00000000, 0x18c0001f, 0x10006b00, 0xe0e00000, 0xe0c00009, 0x18c0001f, 0x10006294, 0xe0e001fe, 0xe0e003fc, 0xe0e007f8, 0xe0e00ff0, 0x1b80001f, 0x20000020, 0xe0f07ff0, 0xe0f07f00, 0x81449801, 0xd80057a5, 0x17c07c1f, 0x1a00001f, 0x10006604, 0xe2200002, 0xc0c06840, 0x17c07c1f, 0xe2200004, 0xc0c06840, 0x17c07c1f, 0x1b80001f, 0x200016a8, 0x1800001f, 0x03800e12, 0x1b80001f, 0x20000300, 0x1800001f, 0x00000e12, 0x1b80001f, 0x20000300, 0x1800001f, 0x00000012, 0x1b80001f, 0x20000104, 0x10007c1f, 0x81f38407, 0x81f98407, 0x81f90407, 0x81f40407, 0x1b80001f, 0x200016a8, 0x81401801, 0xd8005fa5, 0x17c07c1f, 0xe8208000, 0x10006404, 0x00002101, 0x18c0001f, 0x10006290, 0x1212841f, 0xc0c061e0, 0x12807c1f, 0xc0c061e0, 0x1280041f, 0x18c0001f, 0x10006208, 0x1212841f, 0xc0c061e0, 0x12807c1f, 0xe8208000, 0x10006244, 0x00000000, 0x1b80001f, 0x20000080, 0xc0c061e0, 0x1280041f, 0xe8208000, 0x10200268, 0x000ffffe, 0x18c0001f, 0x10006204, 0x1212841f, 0xc0c065a0, 0x1280041f, 0x18c0001f, 0x10006200, 0x1212841f, 0xc0c061e0, 0x12807c1f, 0xe8208000, 0x1000625c, 0x00000000, 0x1b80001f, 0x20000080, 0xc0c061e0, 0x1280041f, 0x19c0001f, 0x01411820, 0x1ac0001f, 0x55aa55aa, 0x10007c1f, 0xf0000000, 0xd800610a, 0x17c07c1f, 0xe2e0004f, 0xe2e0006f, 0xe2e0002f, 0xd82061aa, 0x17c07c1f, 0xe2e0002e, 0xe2e0003e, 0xe2e00032, 0xf0000000, 0x17c07c1f, 0xd80062aa, 0x17c07c1f, 0xe2e00036, 0xe2e0003e, 0x1380201f, 0xe2e0003c, 0xd82063ca, 0x17c07c1f, 0x1380201f, 0xe2e0007c, 0x1b80001f, 0x20000003, 0xe2e0005c, 0xe2e0004c, 0xe2e0004d, 0xf0000000, 0x17c07c1f, 0x1a50001f, 0x10006610, 0x8246a401, 0xd8206569, 0x17c07c1f, 0xe2e0000d, 0xe2e0000c, 0xe2e0001c, 0xe2e0001e, 0xe2e00016, 0xe2e00012, 0xf0000000, 0x17c07c1f, 0x1a50001f, 0x10006610, 0x8246a401, 0xd8206749, 0x17c07c1f, 0xe2e00016, 0x1380201f, 0xe2e0001e, 0x1380201f, 0xe2e0001c, 0x1380201f, 0xe2e0000c, 0xe2e0000d, 0xf0000000, 0x17c07c1f, 0xa1d40407, 0x1391841f, 0xa1d90407, 0x1393041f, 0xf0000000, 0x17c07c1f, 0x18d0001f, 0x10006604, 0x10cf8c1f, 0xd8206843, 0x17c07c1f, 0xf0000000, 0x17c07c1f, 0xe8208000, 0x11008014, 0x00000002, 0xe8208000, 0x11008020, 0x00000101, 0xe8208000, 0x11008004, 0x000000d0, 0x1a00001f, 0x11008000, 0xd8006b0a, 0xe220005d, 0xd8206b2a, 0xe2200000, 0xe2200001, 0xe8208000, 0x11008024, 0x00000001, 0x1b80001f, 0x20000424, 0xf0000000, 0x17c07c1f, 0xa1d10407, 0x1b80001f, 0x20000020, 0xf0000000, 0x17c07c1f }; /* * PCM binary for suspend scenario */ static const struct pcm_desc suspend_pcm_ca7 = { .version = "pcm_suspend_20150917_V4", .base = suspend_binary_ca7, .size = 869, .sess = 2, .replace = 0, .vec0 = EVENT_VEC(11, 1, 0, 0), .vec1 = EVENT_VEC(12, 1, 0, 61), .vec2 = EVENT_VEC(30, 1, 0, 150), .vec3 = EVENT_VEC(31, 1, 0, 287), }; /* * SPM settings for suspend scenario */ static struct pwr_ctrl spm_ctrl = { .wake_src = WAKE_SRC_FOR_SUSPEND, .wake_src_md32 = WAKE_SRC_FOR_MD32, .r0_ctrl_en = 1, .r7_ctrl_en = 1, .infra_dcm_lock = 1, .wfi_op = WFI_OP_AND, .pcm_apsrc_req = 0, .ca7top_idle_mask = 0, .ca15top_idle_mask = 0, .mcusys_idle_mask = 0, .disp_req_mask = 0, .mfg_req_mask = 0, .md32_req_mask = 1, .srclkenai_mask = 1, .ca7_wfi0_en = 1, .ca7_wfi1_en = 1, .ca7_wfi2_en = 1, .ca7_wfi3_en = 1, .ca15_wfi0_en = 1, .ca15_wfi1_en = 1, .ca15_wfi2_en = 1, .ca15_wfi3_en = 1, }; /* * go_to_sleep_before_wfi() - trigger SPM to enter suspend scenario */ static void go_to_sleep_before_wfi(const unsigned int spm_flags) { struct pwr_ctrl *pwrctrl; pwrctrl = &spm_ctrl; set_pwrctrl_pcm_flags(pwrctrl, spm_flags); spm_set_sysclk_settle(); INFO("sec = %u, wakesrc = 0x%x (%u)(%u)\n", pwrctrl->timer_val, pwrctrl->wake_src, is_cpu_pdn(pwrctrl->pcm_flags), is_infra_pdn(pwrctrl->pcm_flags)); spm_reset_and_init_pcm(); spm_init_pcm_register(); spm_set_power_control(pwrctrl); spm_set_wakeup_event(pwrctrl); spm_kick_pcm_to_run(pwrctrl); spm_init_event_vector(&suspend_pcm_ca7); spm_kick_im_to_fetch(&suspend_pcm_ca7); } /* * go_to_sleep_after_wfi() - get wakeup reason after * leaving suspend scenario and clean up SPM settings */ static enum wake_reason_t go_to_sleep_after_wfi(void) { struct wake_status wakesta; static enum wake_reason_t last_wr = WR_NONE; spm_get_wakeup_status(&wakesta); spm_clean_after_wakeup(); last_wr = spm_output_wake_reason(&wakesta); return last_wr; } static void bigcore_pll_on(void) { mmio_setbits_32(ARMCA15PLL_PWR_CON0, ARMCA15PLL_PWR_ON); mmio_clrbits_32(ARMCA15PLL_PWR_CON0, ARMCA15PLL_ISO_EN); mmio_setbits_32(ARMCA15PLL_CON0, ARMCA15PLL_EN); } static void bigcore_pll_off(void) { mmio_clrbits_32(ARMCA15PLL_CON0, ARMCA15PLL_EN); mmio_setbits_32(ARMCA15PLL_PWR_CON0, ARMCA15PLL_ISO_EN); mmio_clrbits_32(ARMCA15PLL_PWR_CON0, ARMCA15PLL_PWR_ON); } void spm_system_suspend(void) { bigcore_pll_off(); spm_lock_get(); go_to_sleep_before_wfi(spm_flags); set_suspend_ready(); spm_lock_release(); } void spm_system_suspend_finish(void) { spm_lock_get(); spm_wake_reason = go_to_sleep_after_wfi(); INFO("spm_wake_reason=%d\n", spm_wake_reason); clear_all_ready(); spm_lock_release(); bigcore_pll_on(); /* Add 20us delay for turning on PLL*/ udelay(20); } trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/spm/spm_suspend.h000066400000000000000000000005571355360272700255740ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPM_SUSPEND_H #define SPM_SUSPEND_H /* cpu dormant return code */ #define CPU_DORMANT_RESET 0 #define CPU_DORMANT_ABORT 1 void spm_system_suspend(void); void spm_system_suspend_finish(void); #endif /* SPM_SUSPEND_H*/ trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/timer/000077500000000000000000000000001355360272700233755ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/timer/mt_cpuxgpt.c000066400000000000000000000014621355360272700257360ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include static void write_cpuxgpt(unsigned int reg_index, unsigned int value) { mmio_write_32((uintptr_t)&mt8173_mcucfg->xgpt_idx, reg_index); mmio_write_32((uintptr_t)&mt8173_mcucfg->xgpt_ctl, value); } static void cpuxgpt_set_init_cnt(unsigned int countH, unsigned int countL) { write_cpuxgpt(INDEX_CNT_H_INIT, countH); /* update count when countL programmed */ write_cpuxgpt(INDEX_CNT_L_INIT, countL); } void generic_timer_backup(void) { uint64_t cval; cval = read_cntpct_el0(); cpuxgpt_set_init_cnt((uint32_t)(cval >> 32), (uint32_t)(cval & 0xffffffff)); } trusted-firmware-a-2.2/plat/mediatek/mt8173/drivers/timer/mt_cpuxgpt.h000066400000000000000000000004641355360272700257440ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MT_CPUXGPT_H #define MT_CPUXGPT_H /* REG */ #define INDEX_CNT_L_INIT 0x008 #define INDEX_CNT_H_INIT 0x00C void generic_timer_backup(void); #endif /* MT_CPUXGPT_H */ trusted-firmware-a-2.2/plat/mediatek/mt8173/include/000077500000000000000000000000001355360272700222225ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8173/include/mcucfg.h000066400000000000000000000127501355360272700236440ustar00rootroot00000000000000/* * Copyright (c) 2014-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MCUCFG_H #define MCUCFG_H #include #include struct mt8173_mcucfg_regs { uint32_t mp0_ca7l_cache_config; struct { uint32_t mem_delsel0; uint32_t mem_delsel1; } mp0_cpu[4]; uint32_t mp0_cache_mem_delsel0; uint32_t mp0_cache_mem_delsel1; uint32_t mp0_axi_config; uint32_t mp0_misc_config[2]; struct { uint32_t rv_addr_lw; uint32_t rv_addr_hw; } mp0_rv_addr[4]; uint32_t mp0_ca7l_cfg_dis; uint32_t mp0_ca7l_clken_ctrl; uint32_t mp0_ca7l_rst_ctrl; uint32_t mp0_ca7l_misc_config; uint32_t mp0_ca7l_dbg_pwr_ctrl; uint32_t mp0_rw_rsvd0; uint32_t mp0_rw_rsvd1; uint32_t mp0_ro_rsvd; uint32_t reserved0_0[100]; uint32_t mp1_cpucfg; uint32_t mp1_miscdbg; uint32_t reserved0_1[13]; uint32_t mp1_rst_ctl; uint32_t mp1_clkenm_div; uint32_t reserved0_2[7]; uint32_t mp1_config_res; uint32_t reserved0_3[13]; struct { uint32_t rv_addr_lw; uint32_t rv_addr_hw; } mp1_rv_addr[2]; uint32_t reserved0_4[84]; uint32_t mp0_rst_status; /* 0x400 */ uint32_t mp0_dbg_ctrl; uint32_t mp0_dbg_flag; uint32_t mp0_ca7l_ir_mon; struct { uint32_t pc_lw; uint32_t pc_hw; uint32_t fp_arch32; uint32_t sp_arch32; uint32_t fp_arch64_lw; uint32_t fp_arch64_hw; uint32_t sp_arch64_lw; uint32_t sp_arch64_hw; } mp0_dbg_core[4]; uint32_t dfd_ctrl; uint32_t dfd_cnt_l; uint32_t dfd_cnt_h; uint32_t misccfg_mp0_rw_rsvd; uint32_t misccfg_sec_vio_status0; uint32_t misccfg_sec_vio_status1; uint32_t reserved1[22]; uint32_t misccfg_rw_rsvd; /* 0x500 */ uint32_t mcusys_dbg_mon_sel_a; uint32_t mcusys_dbg_mon; uint32_t reserved2[61]; uint32_t mcusys_config_a; /* 0x600 */ uint32_t mcusys_config1_a; uint32_t mcusys_gic_peribase_a; uint32_t reserved3; uint32_t sec_range0_start; /* 0x610 */ uint32_t sec_range0_end; uint32_t sec_range_enable; uint32_t reserved4; uint32_t int_pol_ctl[8]; /* 0x620 */ uint32_t aclken_div; /* 0x640 */ uint32_t pclken_div; uint32_t l2c_sram_ctrl; uint32_t armpll_jit_ctrl; uint32_t cci_addrmap; /* 0x650 */ uint32_t cci_config; uint32_t cci_periphbase; uint32_t cci_nevntcntovfl; uint32_t cci_clk_ctrl; /* 0x660 */ uint32_t cci_acel_s1_ctrl; uint32_t bus_fabric_dcm_ctrl; uint32_t reserved5; uint32_t xgpt_ctl; /* 0x670 */ uint32_t xgpt_idx; uint32_t ptpod2_ctl0; uint32_t ptpod2_ctl1; uint32_t mcusys_revid; uint32_t mcusys_rw_rsvd0; uint32_t mcusys_rw_rsvd1; }; static struct mt8173_mcucfg_regs *const mt8173_mcucfg = (void *)MCUCFG_BASE; /* cpu boot mode */ #define MP0_CPUCFG_64BIT_SHIFT 12 #define MP1_CPUCFG_64BIT_SHIFT 28 #define MP0_CPUCFG_64BIT (U(0xf) << MP0_CPUCFG_64BIT_SHIFT) #define MP1_CPUCFG_64BIT (U(0xf) << MP1_CPUCFG_64BIT_SHIFT) /* scu related */ enum { MP0_ACINACTM_SHIFT = 4, MP1_ACINACTM_SHIFT = 0, MP0_ACINACTM = 1 << MP0_ACINACTM_SHIFT, MP1_ACINACTM = 1 << MP1_ACINACTM_SHIFT }; enum { MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT = 0, MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT = 4, MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT = 8, MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT = 12, MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT = 16, MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK = 0xf << MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT, MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK = 0xf << MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT, MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK = 0xf << MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT, MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK = 0xf << MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT, MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK = 0xf << MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT }; enum { MP1_AINACTS_SHIFT = 4, MP1_AINACTS = 1 << MP1_AINACTS_SHIFT }; enum { MP1_SW_CG_GEN_SHIFT = 12, MP1_SW_CG_GEN = 1 << MP1_SW_CG_GEN_SHIFT }; enum { MP1_L2RSTDISABLE_SHIFT = 14, MP1_L2RSTDISABLE = 1 << MP1_L2RSTDISABLE_SHIFT }; /* cci clock control related */ enum { MCU_BUS_DCM_EN = 1 << 8 }; /* l2c sram control related */ enum { L2C_SRAM_DCM_EN = 1 << 0 }; /* bus fabric dcm control related */ enum { PSYS_ADB400_DCM_EN = 1 << 29, GPU_ADB400_DCM_EN = 1 << 28, EMI1_ADB400_DCM_EN = 1 << 27, EMI_ADB400_DCM_EN = 1 << 26, INFRA_ADB400_DCM_EN = 1 << 25, L2C_ADB400_DCM_EN = 1 << 24, MP0_ADB400_DCM_EN = 1 << 23, CCI400_CK_ONLY_DCM_EN = 1 << 22, L2C_IDLE_DCM_EN = 1 << 21, CA15U_ADB_DYNAMIC_CG_EN = 1 << 19, CA7L_ADB_DYNAMIC_CG_EN = 1 << 18, L2C_ADB_DYNAMIC_CG_EN = 1 << 17, EMICLK_EMI1_DYNAMIC_CG_EN = 1 << 12, INFRACLK_PSYS_DYNAMIC_CG_EN = 1 << 11, EMICLK_GPU_DYNAMIC_CG_EN = 1 << 10, EMICLK_EMI_DYNAMIC_CG_EN = 1 << 8, CCI400_SLV_RW_DCM_EN = 1 << 7, CCI400_SLV_DCM_EN = 1 << 5, ACLK_PSYS_DYNAMIC_CG_EN = 1 << 3, ACLK_GPU_DYNAMIC_CG_EN = 1 << 2, ACLK_EMI_DYNAMIC_CG_EN = 1 << 1, ACLK_INFRA_DYNAMIC_CG_EN = 1 << 0, /* adb400 related */ ADB400_GRP_DCM_EN = PSYS_ADB400_DCM_EN | GPU_ADB400_DCM_EN | EMI1_ADB400_DCM_EN | EMI_ADB400_DCM_EN | INFRA_ADB400_DCM_EN | L2C_ADB400_DCM_EN | MP0_ADB400_DCM_EN, /* cci400 related */ CCI400_GRP_DCM_EN = CCI400_CK_ONLY_DCM_EN | CCI400_SLV_RW_DCM_EN | CCI400_SLV_DCM_EN, /* adb clock related */ ADBCLK_GRP_DCM_EN = CA15U_ADB_DYNAMIC_CG_EN | CA7L_ADB_DYNAMIC_CG_EN | L2C_ADB_DYNAMIC_CG_EN, /* emi clock related */ EMICLK_GRP_DCM_EN = EMICLK_EMI1_DYNAMIC_CG_EN | EMICLK_GPU_DYNAMIC_CG_EN | EMICLK_EMI_DYNAMIC_CG_EN, /* bus clock related */ ACLK_GRP_DCM_EN = ACLK_PSYS_DYNAMIC_CG_EN | ACLK_GPU_DYNAMIC_CG_EN | ACLK_EMI_DYNAMIC_CG_EN | ACLK_INFRA_DYNAMIC_CG_EN, }; #endif /* MCUCFG_H */ trusted-firmware-a-2.2/plat/mediatek/mt8173/include/mt8173_def.h000066400000000000000000000123351355360272700241600ustar00rootroot00000000000000/* * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MT8173_DEF_H #define MT8173_DEF_H #if RESET_TO_BL31 #error "MT8173 is incompatible with RESET_TO_BL31!" #endif #define MT8173_PRIMARY_CPU 0x0 /* Register base address */ #define IO_PHYS (0x10000000) #define INFRACFG_AO_BASE (IO_PHYS + 0x1000) #define SRAMROM_SEC_BASE (IO_PHYS + 0x1800) #define PERI_CON_BASE (IO_PHYS + 0x3000) #define GPIO_BASE (IO_PHYS + 0x5000) #define SPM_BASE (IO_PHYS + 0x6000) #define RGU_BASE (IO_PHYS + 0x7000) #define PMIC_WRAP_BASE (IO_PHYS + 0xD000) #define DEVAPC0_BASE (IO_PHYS + 0xE000) #define MCUCFG_BASE (IO_PHYS + 0x200000) #define APMIXED_BASE (IO_PHYS + 0x209000) #define TRNG_BASE (IO_PHYS + 0x20F000) #define CRYPT_BASE (IO_PHYS + 0x210000) #define MT_GIC_BASE (IO_PHYS + 0x220000) #define PLAT_MT_CCI_BASE (IO_PHYS + 0x390000) /* Aggregate of all devices in the first GB */ #define MTK_DEV_RNG0_BASE IO_PHYS #define MTK_DEV_RNG0_SIZE 0x400000 #define MTK_DEV_RNG1_BASE (IO_PHYS + 0x1000000) #define MTK_DEV_RNG1_SIZE 0x4000000 /* SRAMROM related registers */ #define SRAMROM_SEC_CTRL (SRAMROM_SEC_BASE + 0x4) #define SRAMROM_SEC_ADDR (SRAMROM_SEC_BASE + 0x8) /* DEVAPC0 related registers */ #define DEVAPC0_MAS_SEC_0 (DEVAPC0_BASE + 0x500) #define DEVAPC0_APC_CON (DEVAPC0_BASE + 0xF00) /******************************************************************************* * UART related constants ******************************************************************************/ #define MT8173_UART0_BASE (IO_PHYS + 0x01002000) #define MT8173_UART1_BASE (IO_PHYS + 0x01003000) #define MT8173_UART2_BASE (IO_PHYS + 0x01004000) #define MT8173_UART3_BASE (IO_PHYS + 0x01005000) #define MT8173_BAUDRATE (115200) #define MT8173_UART_CLOCK (26000000) /******************************************************************************* * System counter frequency related constants ******************************************************************************/ #define SYS_COUNTER_FREQ_IN_TICKS 13000000 /******************************************************************************* * GIC-400 & interrupt handling related constants ******************************************************************************/ /* Base MTK_platform compatible GIC memory map */ #define BASE_GICD_BASE (MT_GIC_BASE + 0x1000) #define BASE_GICC_BASE (MT_GIC_BASE + 0x2000) #define BASE_GICR_BASE 0 /* no GICR in GIC-400 */ #define BASE_GICH_BASE (MT_GIC_BASE + 0x4000) #define BASE_GICV_BASE (MT_GIC_BASE + 0x6000) #define INT_POL_CTL0 0x10200620 #define GIC_PRIVATE_SIGNALS (32) /******************************************************************************* * CCI-400 related constants ******************************************************************************/ #define PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX 4 #define PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX 3 /******************************************************************************* * WDT related constants ******************************************************************************/ #define MTK_WDT_BASE (RGU_BASE + 0) #define MTK_WDT_SWRST (MTK_WDT_BASE + 0x0014) #define MTK_WDT_MODE_DUAL_MODE 0x0040 #define MTK_WDT_MODE_IRQ 0x0008 #define MTK_WDT_MODE_KEY 0x22000000 #define MTK_WDT_MODE_EXTEN 0x0004 #define MTK_WDT_SWRST_KEY 0x1209 /* FIQ platform related define */ #define MT_IRQ_SEC_SGI_0 8 #define MT_IRQ_SEC_SGI_1 9 #define MT_IRQ_SEC_SGI_2 10 #define MT_IRQ_SEC_SGI_3 11 #define MT_IRQ_SEC_SGI_4 12 #define MT_IRQ_SEC_SGI_5 13 #define MT_IRQ_SEC_SGI_6 14 #define MT_IRQ_SEC_SGI_7 15 /* * Macros for local power states in MTK platforms encoded by State-ID field * within the power-state parameter. */ /* Local power state for power domains in Run state. */ #define MTK_LOCAL_STATE_RUN 0 /* Local power state for retention. Valid only for CPU power domains */ #define MTK_LOCAL_STATE_RET 1 /* Local power state for OFF/power-down. Valid for CPU and cluster power * domains */ #define MTK_LOCAL_STATE_OFF 2 #if PSCI_EXTENDED_STATE_ID /* * Macros used to parse state information from State-ID if it is using the * recommended encoding for State-ID. */ #define MTK_LOCAL_PSTATE_WIDTH 4 #define MTK_LOCAL_PSTATE_MASK ((1 << MTK_LOCAL_PSTATE_WIDTH) - 1) /* Macros to construct the composite power state */ /* Make composite power state parameter till power level 0 */ #define mtk_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ (((lvl0_state) << PSTATE_ID_SHIFT) | ((type) << PSTATE_TYPE_SHIFT)) #else #define mtk_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ (((lvl0_state) << PSTATE_ID_SHIFT) | \ ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \ ((type) << PSTATE_TYPE_SHIFT)) #endif /* __PSCI_EXTENDED_STATE_ID__ */ /* Make composite power state parameter till power level 1 */ #define mtk_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \ (((lvl1_state) << MTK_LOCAL_PSTATE_WIDTH) | \ mtk_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type)) /* Make composite power state parameter till power level 2 */ #define mtk_make_pwrstate_lvl2( \ lvl2_state, lvl1_state, lvl0_state, pwr_lvl, type) \ (((lvl2_state) << (MTK_LOCAL_PSTATE_WIDTH * 2)) | \ mtk_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type)) #endif /* MT8173_DEF_H */ trusted-firmware-a-2.2/plat/mediatek/mt8173/include/plat_macros.S000066400000000000000000000040421355360272700246520ustar00rootroot00000000000000/* * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .section .rodata.gic_reg_name, "aS" gicc_regs: .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", "" gicd_pend_reg: .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n" \ " Offset:\t\t\tvalue\n" newline: .asciz "\n" spacer: .asciz ":\t\t0x" .section .rodata.cci_reg_name, "aS" cci_iface_regs: .asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , "" /* --------------------------------------------- * The below macro prints out relevant GIC and * CCI registers whenever an unhandled exception * is taken in BL3-1. * Clobbers: x0 - x10, x16, x17, sp * --------------------------------------------- */ .macro plat_crash_print_regs mov_imm x16, BASE_GICD_BASE mov_imm x17, BASE_GICC_BASE /* Load the gicc reg list to x6 */ adr x6, gicc_regs /* Load the gicc regs to gp regs used by str_in_crash_buf_print */ ldr w8, [x17, #GICC_HPPIR] ldr w9, [x17, #GICC_AHPPIR] ldr w10, [x17, #GICC_CTLR] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print /* Print the GICD_ISPENDR regs */ add x7, x16, #GICD_ISPENDR adr x4, gicd_pend_reg bl asm_print_str gicd_ispendr_loop: sub x4, x7, x16 cmp x4, #0x280 b.eq exit_print_gic_regs bl asm_print_hex adr x4, spacer bl asm_print_str ldr x4, [x7], #8 bl asm_print_hex adr x4, newline bl asm_print_str b gicd_ispendr_loop exit_print_gic_regs: adr x6, cci_iface_regs /* Store in x7 the base address of the first interface */ mov_imm x7, (PLAT_MT_CCI_BASE + SLAVE_IFACE_OFFSET( \ PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX)) ldr w8, [x7, #SNOOP_CTRL_REG] /* Store in x7 the base address of the second interface */ mov_imm x7, (PLAT_MT_CCI_BASE + SLAVE_IFACE_OFFSET( \ PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX)) ldr w9, [x7, #SNOOP_CTRL_REG] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print .endm trusted-firmware-a-2.2/plat/mediatek/mt8173/include/plat_private.h000066400000000000000000000013361355360272700250700ustar00rootroot00000000000000/* * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_PRIVATE_H #define PLAT_PRIVATE_H /******************************************************************************* * Function and variable prototypes ******************************************************************************/ void plat_configure_mmu_el3(unsigned long total_base, unsigned long total_size, unsigned long, unsigned long, unsigned long, unsigned long); void plat_cci_init(void); void plat_cci_enable(void); void plat_cci_disable(void); /* Declarations for plat_topology.c */ int mt_setup_topology(void); #endif /* PLAT_PRIVATE_H */ trusted-firmware-a-2.2/plat/mediatek/mt8173/include/plat_sip_calls.h000066400000000000000000000012751355360272700253710ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_SIP_CALLS_H #define PLAT_SIP_CALLS_H /******************************************************************************* * Plat SiP function constants ******************************************************************************/ #define MTK_PLAT_SIP_NUM_CALLS 6 #define MTK_SIP_PWR_ON_MTCMOS 0x82000402 #define MTK_SIP_PWR_OFF_MTCMOS 0x82000403 #define MTK_SIP_PWR_MTCMOS_SUPPORT 0x82000404 #define MTK_SIP_SET_HDCP_KEY_NUM 0x82000405 #define MTK_SIP_CLR_HDCP_KEY 0x82000406 #define MTK_SIP_SET_HDCP_KEY_EX 0x82000407 #endif /* PLAT_SIP_CALLS_H */ trusted-firmware-a-2.2/plat/mediatek/mt8173/include/platform_def.h000066400000000000000000000117411355360272700250410ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include "mt8173_def.h" /******************************************************************************* * Platform binary types for linking ******************************************************************************/ #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 /******************************************************************************* * Generic platform constants ******************************************************************************/ /* Size of cacheable stacks */ #if defined(IMAGE_BL1) #define PLATFORM_STACK_SIZE 0x440 #elif defined(IMAGE_BL2) #define PLATFORM_STACK_SIZE 0x400 #elif defined(IMAGE_BL31) #define PLATFORM_STACK_SIZE 0x800 #elif defined(IMAGE_BL32) #define PLATFORM_STACK_SIZE 0x440 #endif #define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n" #define PLATFORM_MAX_AFFLVL MPIDR_AFFLVL2 #define PLAT_MAX_PWR_LVL U(2) #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE U(2) #define PLATFORM_SYSTEM_COUNT 1 #define PLATFORM_CLUSTER_COUNT 2 #define PLATFORM_CLUSTER0_CORE_COUNT 4 #define PLATFORM_CLUSTER1_CORE_COUNT 2 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \ PLATFORM_CLUSTER0_CORE_COUNT) #define PLATFORM_MAX_CPUS_PER_CLUSTER 4 #define PLATFORM_NUM_AFFS (PLATFORM_SYSTEM_COUNT + \ PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) /******************************************************************************* * Platform memory map related constants ******************************************************************************/ /* * MT8173 SRAM memory layout * 0x100000 +-------------------+ * | shared mem (4KB) | * 0x101000 +-------------------+ * | | * | BL3-1 (124KB) | * | | * 0x120000 +-------------------+ * | reserved (64KB) | * 0x130000 +-------------------+ */ /* TF txet, ro, rw, xlat table, coherent memory ... etc. * Size: release: 128KB, debug: 128KB */ #define TZRAM_BASE (0x100000) #if DEBUG #define TZRAM_SIZE (0x20000) #else #define TZRAM_SIZE (0x20000) #endif /* Reserved: 64KB */ #define TZRAM2_BASE (TZRAM_BASE + TZRAM_SIZE) #define TZRAM2_SIZE (0x10000) /******************************************************************************* * BL31 specific defines. ******************************************************************************/ /* * Put BL3-1 at the top of the Trusted SRAM (just below the shared memory, if * present). BL31_BASE is calculated using the current BL3-1 debug size plus a * little space for growth. */ #define BL31_BASE (TZRAM_BASE + 0x1000) #define BL31_LIMIT (TZRAM_BASE + TZRAM_SIZE) #define TZRAM2_LIMIT (TZRAM2_BASE + TZRAM2_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 MAX_XLAT_TABLES 4 #define MAX_MMAP_REGIONS 16 /******************************************************************************* * Declarations and constants to access the mailboxes safely. Each mailbox is * aligned on the biggest cache line size in the platform. This is known only * to the platform as it might have a combination of integrated and external * caches. Such alignment ensures that two maiboxes do not sit on the same cache * line at any cache level. They could belong to different cpus/clusters & * get written while being protected by different locks causing corruption of * a valid mailbox address. ******************************************************************************/ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) #define PLAT_ARM_GICD_BASE BASE_GICD_BASE #define PLAT_ARM_GICC_BASE BASE_GICC_BASE #define PLAT_ARM_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(MT_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(MT_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(MT_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(MT_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(MT_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(MT_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(MT_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(MT_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE) #define PLAT_ARM_G0_IRQ_PROPS(grp) #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/mediatek/mt8173/include/power_tracer.h000066400000000000000000000006141355360272700250700ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef POWER_TRACER_H #define POWER_TRACER_H #define CPU_UP 0 #define CPU_DOWN 1 #define CPU_SUSPEND 2 #define CLUSTER_UP 3 #define CLUSTER_DOWN 4 #define CLUSTER_SUSPEND 5 void trace_power_flow(unsigned long mpidr, unsigned char mode); #endif /* POWER_TRACER_H */ trusted-firmware-a-2.2/plat/mediatek/mt8173/include/scu.h000066400000000000000000000003741355360272700231710ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SCU_H #define SCU_H void disable_scu(unsigned long mpidr); void enable_scu(unsigned long mpidr); #endif /* SCU_H */ trusted-firmware-a-2.2/plat/mediatek/mt8173/plat_mt_gic.c000066400000000000000000000010561355360272700232270ustar00rootroot00000000000000/* * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include const unsigned int mt_irq_sec_array[] = { MT_IRQ_SEC_SGI_0, MT_IRQ_SEC_SGI_1, MT_IRQ_SEC_SGI_2, MT_IRQ_SEC_SGI_3, MT_IRQ_SEC_SGI_4, MT_IRQ_SEC_SGI_5, MT_IRQ_SEC_SGI_6, MT_IRQ_SEC_SGI_7 }; void plat_mt_gic_init(void) { arm_gic_init(BASE_GICC_BASE, BASE_GICD_BASE, BASE_GICR_BASE, mt_irq_sec_array, ARRAY_SIZE(mt_irq_sec_array)); } trusted-firmware-a-2.2/plat/mediatek/mt8173/plat_pm.c000066400000000000000000000420141355360272700224000ustar00rootroot00000000000000/* * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* generic_timer_backup() */ #include #include #include #include #include #include #include #define MTK_PWR_LVL0 0 #define MTK_PWR_LVL1 1 #define MTK_PWR_LVL2 2 /* Macros to read the MTK power domain state */ #define MTK_CORE_PWR_STATE(state) (state)->pwr_domain_state[MTK_PWR_LVL0] #define MTK_CLUSTER_PWR_STATE(state) (state)->pwr_domain_state[MTK_PWR_LVL1] #define MTK_SYSTEM_PWR_STATE(state) ((PLAT_MAX_PWR_LVL > MTK_PWR_LVL1) ?\ (state)->pwr_domain_state[MTK_PWR_LVL2] : 0) #if PSCI_EXTENDED_STATE_ID /* * The table storing the valid idle power states. Ensure that the * array entries are populated in ascending order of state-id to * enable us to use binary search during power state validation. * The table must be terminated by a NULL entry. */ const unsigned int mtk_pm_idle_states[] = { /* State-id - 0x001 */ mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_RET, MTK_PWR_LVL0, PSTATE_TYPE_STANDBY), /* State-id - 0x002 */ mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_OFF, MTK_PWR_LVL0, PSTATE_TYPE_POWERDOWN), /* State-id - 0x022 */ mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_OFF, MTK_LOCAL_STATE_OFF, MTK_PWR_LVL1, PSTATE_TYPE_POWERDOWN), #if PLAT_MAX_PWR_LVL > MTK_PWR_LVL1 /* State-id - 0x222 */ mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_OFF, MTK_LOCAL_STATE_OFF, MTK_LOCAL_STATE_OFF, MTK_PWR_LVL2, PSTATE_TYPE_POWERDOWN), #endif 0, }; #endif struct core_context { unsigned long timer_data[8]; unsigned int count; unsigned int rst; unsigned int abt; unsigned int brk; }; struct cluster_context { struct core_context core[PLATFORM_MAX_CPUS_PER_CLUSTER]; }; /* * Top level structure to hold the complete context of a multi cluster system */ struct system_context { struct cluster_context cluster[PLATFORM_CLUSTER_COUNT]; }; /* * Top level structure which encapsulates the context of the entire system */ static struct system_context dormant_data[1]; static inline struct cluster_context *system_cluster( struct system_context *system, uint32_t clusterid) { return &system->cluster[clusterid]; } static inline struct core_context *cluster_core(struct cluster_context *cluster, uint32_t cpuid) { return &cluster->core[cpuid]; } static struct cluster_context *get_cluster_data(unsigned long mpidr) { uint32_t clusterid; clusterid = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS; return system_cluster(dormant_data, clusterid); } static struct core_context *get_core_data(unsigned long mpidr) { struct cluster_context *cluster; uint32_t cpuid; cluster = get_cluster_data(mpidr); cpuid = mpidr & MPIDR_CPU_MASK; return cluster_core(cluster, cpuid); } static void mt_save_generic_timer(unsigned long *container) { uint64_t ctl; uint64_t val; __asm__ volatile("mrs %x0, cntkctl_el1\n\t" "mrs %x1, cntp_cval_el0\n\t" "stp %x0, %x1, [%2, #0]" : "=&r" (ctl), "=&r" (val) : "r" (container) : "memory"); __asm__ volatile("mrs %x0, cntp_tval_el0\n\t" "mrs %x1, cntp_ctl_el0\n\t" "stp %x0, %x1, [%2, #16]" : "=&r" (val), "=&r" (ctl) : "r" (container) : "memory"); __asm__ volatile("mrs %x0, cntv_tval_el0\n\t" "mrs %x1, cntv_ctl_el0\n\t" "stp %x0, %x1, [%2, #32]" : "=&r" (val), "=&r" (ctl) : "r" (container) : "memory"); } static void mt_restore_generic_timer(unsigned long *container) { uint64_t ctl; uint64_t val; __asm__ volatile("ldp %x0, %x1, [%2, #0]\n\t" "msr cntkctl_el1, %x0\n\t" "msr cntp_cval_el0, %x1" : "=&r" (ctl), "=&r" (val) : "r" (container) : "memory"); __asm__ volatile("ldp %x0, %x1, [%2, #16]\n\t" "msr cntp_tval_el0, %x0\n\t" "msr cntp_ctl_el0, %x1" : "=&r" (val), "=&r" (ctl) : "r" (container) : "memory"); __asm__ volatile("ldp %x0, %x1, [%2, #32]\n\t" "msr cntv_tval_el0, %x0\n\t" "msr cntv_ctl_el0, %x1" : "=&r" (val), "=&r" (ctl) : "r" (container) : "memory"); } static inline uint64_t read_cntpctl(void) { uint64_t cntpctl; __asm__ volatile("mrs %x0, cntp_ctl_el0" : "=r" (cntpctl) : : "memory"); return cntpctl; } static inline void write_cntpctl(uint64_t cntpctl) { __asm__ volatile("msr cntp_ctl_el0, %x0" : : "r"(cntpctl)); } static void stop_generic_timer(void) { /* * Disable the timer and mask the irq to prevent * suprious interrupts on this cpu interface. It * will bite us when we come back if we don't. It * will be replayed on the inbound cluster. */ uint64_t cntpctl = read_cntpctl(); write_cntpctl(clr_cntp_ctl_enable(cntpctl)); } static void mt_cpu_save(unsigned long mpidr) { struct core_context *core; core = get_core_data(mpidr); mt_save_generic_timer(core->timer_data); /* disable timer irq, and upper layer should enable it again. */ stop_generic_timer(); } static void mt_cpu_restore(unsigned long mpidr) { struct core_context *core; core = get_core_data(mpidr); mt_restore_generic_timer(core->timer_data); } static void mt_platform_save_context(unsigned long mpidr) { /* mcusys_save_context: */ mt_cpu_save(mpidr); } static void mt_platform_restore_context(unsigned long mpidr) { /* mcusys_restore_context: */ mt_cpu_restore(mpidr); } static void plat_cpu_standby(plat_local_state_t cpu_state) { unsigned int scr; scr = read_scr_el3(); write_scr_el3(scr | SCR_IRQ_BIT); isb(); dsb(); wfi(); write_scr_el3(scr); } /******************************************************************************* * MTK_platform handler called when an affinity instance is about to be turned * on. The level and mpidr determine the affinity instance. ******************************************************************************/ static uintptr_t secure_entrypoint; static int plat_power_domain_on(unsigned long mpidr) { int rc = PSCI_E_SUCCESS; unsigned long cpu_id; unsigned long cluster_id; uintptr_t rv; cpu_id = mpidr & MPIDR_CPU_MASK; cluster_id = mpidr & MPIDR_CLUSTER_MASK; if (cluster_id) rv = (uintptr_t)&mt8173_mcucfg->mp1_rv_addr[cpu_id].rv_addr_lw; else rv = (uintptr_t)&mt8173_mcucfg->mp0_rv_addr[cpu_id].rv_addr_lw; mmio_write_32(rv, secure_entrypoint); INFO("mt_on[%ld:%ld], entry %x\n", cluster_id, cpu_id, mmio_read_32(rv)); spm_hotplug_on(mpidr); return rc; } /******************************************************************************* * MTK_platform handler called when an affinity instance is about to be turned * off. The level and mpidr determine the affinity instance. The 'state' arg. * allows the platform to decide whether the cluster is being turned off and * take apt actions. * * CAUTION: This function is called with coherent stacks so that caches can be * turned off, flushed and coherency disabled. There is no guarantee that caches * will remain turned on across calls to this function as each affinity level is * dealt with. So do not write & read global variables across calls. It will be * wise to do flush a write to the global to prevent unpredictable results. ******************************************************************************/ static void plat_power_domain_off(const psci_power_state_t *state) { unsigned long mpidr = read_mpidr_el1(); /* Prevent interrupts from spuriously waking up this cpu */ gicv2_cpuif_disable(); spm_hotplug_off(mpidr); trace_power_flow(mpidr, CPU_DOWN); if (MTK_CLUSTER_PWR_STATE(state) == MTK_LOCAL_STATE_OFF) { /* Disable coherency if this cluster is to be turned off */ plat_cci_disable(); trace_power_flow(mpidr, CLUSTER_DOWN); } } /******************************************************************************* * MTK_platform handler called when an affinity instance is about to be * suspended. The level and mpidr determine the affinity instance. The 'state' * arg. allows the platform to decide whether the cluster is being turned off * and take apt actions. * * CAUTION: This function is called with coherent stacks so that caches can be * turned off, flushed and coherency disabled. There is no guarantee that caches * will remain turned on across calls to this function as each affinity level is * dealt with. So do not write & read global variables across calls. It will be * wise to do flush a write to the global to prevent unpredictable results. ******************************************************************************/ static void plat_power_domain_suspend(const psci_power_state_t *state) { unsigned long mpidr = read_mpidr_el1(); unsigned long cluster_id; unsigned long cpu_id; uintptr_t rv; cpu_id = mpidr & MPIDR_CPU_MASK; cluster_id = mpidr & MPIDR_CLUSTER_MASK; if (cluster_id) rv = (uintptr_t)&mt8173_mcucfg->mp1_rv_addr[cpu_id].rv_addr_lw; else rv = (uintptr_t)&mt8173_mcucfg->mp0_rv_addr[cpu_id].rv_addr_lw; mmio_write_32(rv, secure_entrypoint); if (MTK_SYSTEM_PWR_STATE(state) != MTK_LOCAL_STATE_OFF) { spm_mcdi_prepare_for_off_state(mpidr, MTK_PWR_LVL0); if (MTK_CLUSTER_PWR_STATE(state) == MTK_LOCAL_STATE_OFF) spm_mcdi_prepare_for_off_state(mpidr, MTK_PWR_LVL1); } mt_platform_save_context(mpidr); /* Perform the common cluster specific operations */ if (MTK_CLUSTER_PWR_STATE(state) == MTK_LOCAL_STATE_OFF) { /* Disable coherency if this cluster is to be turned off */ plat_cci_disable(); } if (MTK_SYSTEM_PWR_STATE(state) == MTK_LOCAL_STATE_OFF) { disable_scu(mpidr); generic_timer_backup(); spm_system_suspend(); /* Prevent interrupts from spuriously waking up this cpu */ gicv2_cpuif_disable(); } } /******************************************************************************* * MTK_platform handler called when an affinity instance has just been powered * on after being turned off earlier. The level and mpidr determine the affinity * instance. The 'state' arg. allows the platform to decide whether the cluster * was turned off prior to wakeup and do what's necessary to setup it up * correctly. ******************************************************************************/ void mtk_system_pwr_domain_resume(void); static void plat_power_domain_on_finish(const psci_power_state_t *state) { unsigned long mpidr = read_mpidr_el1(); assert(state->pwr_domain_state[MPIDR_AFFLVL0] == MTK_LOCAL_STATE_OFF); if ((PLAT_MAX_PWR_LVL > MTK_PWR_LVL1) && (state->pwr_domain_state[MTK_PWR_LVL2] == MTK_LOCAL_STATE_OFF)) mtk_system_pwr_domain_resume(); if (state->pwr_domain_state[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF) { plat_cci_enable(); trace_power_flow(mpidr, CLUSTER_UP); } if ((PLAT_MAX_PWR_LVL > MTK_PWR_LVL1) && (state->pwr_domain_state[MTK_PWR_LVL2] == MTK_LOCAL_STATE_OFF)) return; /* Enable the gic cpu interface */ gicv2_cpuif_enable(); gicv2_pcpu_distif_init(); trace_power_flow(mpidr, CPU_UP); } /******************************************************************************* * MTK_platform handler called when an affinity instance has just been powered * on after having been suspended earlier. The level and mpidr determine the * affinity instance. ******************************************************************************/ static void plat_power_domain_suspend_finish(const psci_power_state_t *state) { unsigned long mpidr = read_mpidr_el1(); if (state->pwr_domain_state[MTK_PWR_LVL0] == MTK_LOCAL_STATE_RET) return; if (MTK_SYSTEM_PWR_STATE(state) == MTK_LOCAL_STATE_OFF) { /* Enable the gic cpu interface */ plat_arm_gic_init(); spm_system_suspend_finish(); enable_scu(mpidr); } /* Perform the common cluster specific operations */ if (MTK_CLUSTER_PWR_STATE(state) == MTK_LOCAL_STATE_OFF) { /* Enable coherency if this cluster was off */ plat_cci_enable(); } mt_platform_restore_context(mpidr); if (MTK_SYSTEM_PWR_STATE(state) != MTK_LOCAL_STATE_OFF) { spm_mcdi_finish_for_on_state(mpidr, MTK_PWR_LVL0); if (MTK_CLUSTER_PWR_STATE(state) == MTK_LOCAL_STATE_OFF) spm_mcdi_finish_for_on_state(mpidr, MTK_PWR_LVL1); } gicv2_pcpu_distif_init(); } static void plat_get_sys_suspend_power_state(psci_power_state_t *req_state) { assert(PLAT_MAX_PWR_LVL >= 2); for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = MTK_LOCAL_STATE_OFF; } /******************************************************************************* * MTK handlers to shutdown/reboot the system ******************************************************************************/ static void __dead2 plat_system_off(void) { INFO("MTK System Off\n"); rtc_bbpu_power_down(); wfi(); ERROR("MTK System Off: operation not handled.\n"); panic(); } static void __dead2 plat_system_reset(void) { /* Write the System Configuration Control Register */ INFO("MTK System Reset\n"); mmio_clrsetbits_32(MTK_WDT_BASE, (MTK_WDT_MODE_DUAL_MODE | MTK_WDT_MODE_IRQ), MTK_WDT_MODE_KEY); mmio_setbits_32(MTK_WDT_BASE, (MTK_WDT_MODE_KEY | MTK_WDT_MODE_EXTEN)); mmio_setbits_32(MTK_WDT_SWRST, MTK_WDT_SWRST_KEY); wfi(); ERROR("MTK System Reset: operation not handled.\n"); panic(); } #if !PSCI_EXTENDED_STATE_ID static int plat_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { int pstate = psci_get_pstate_type(power_state); int pwr_lvl = psci_get_pstate_pwrlvl(power_state); int i; assert(req_state); if (pwr_lvl > PLAT_MAX_PWR_LVL) return PSCI_E_INVALID_PARAMS; /* Sanity check the requested state */ if (pstate == PSTATE_TYPE_STANDBY) { /* * It's possible to enter standby only on power level 0 * Ignore any other power level. */ if (pwr_lvl != 0) return PSCI_E_INVALID_PARAMS; req_state->pwr_domain_state[MTK_PWR_LVL0] = MTK_LOCAL_STATE_RET; } else { for (i = 0; i <= pwr_lvl; i++) req_state->pwr_domain_state[i] = MTK_LOCAL_STATE_OFF; } /* * We expect the 'state id' to be zero. */ if (psci_get_pstate_id(power_state)) return PSCI_E_INVALID_PARAMS; return PSCI_E_SUCCESS; } #else int plat_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { unsigned int state_id; int i; assert(req_state); /* * Currently we are using a linear search for finding the matching * entry in the idle power state array. This can be made a binary * search if the number of entries justify the additional complexity. */ for (i = 0; !!mtk_pm_idle_states[i]; i++) { if (power_state == mtk_pm_idle_states[i]) break; } /* Return error if entry not found in the idle state array */ if (!mtk_pm_idle_states[i]) return PSCI_E_INVALID_PARAMS; i = 0; state_id = psci_get_pstate_id(power_state); /* Parse the State ID and populate the state info parameter */ while (state_id) { req_state->pwr_domain_state[i++] = state_id & MTK_LOCAL_PSTATE_MASK; state_id >>= MTK_LOCAL_PSTATE_WIDTH; } return PSCI_E_SUCCESS; } #endif void mtk_system_pwr_domain_resume(void) { console_switch_state(CONSOLE_FLAG_BOOT); /* Assert system power domain is available on the platform */ assert(PLAT_MAX_PWR_LVL >= MTK_PWR_LVL2); plat_arm_gic_init(); console_switch_state(CONSOLE_FLAG_RUNTIME); } static const plat_psci_ops_t plat_plat_pm_ops = { .cpu_standby = plat_cpu_standby, .pwr_domain_on = plat_power_domain_on, .pwr_domain_on_finish = plat_power_domain_on_finish, .pwr_domain_off = plat_power_domain_off, .pwr_domain_suspend = plat_power_domain_suspend, .pwr_domain_suspend_finish = plat_power_domain_suspend_finish, .system_off = plat_system_off, .system_reset = plat_system_reset, .validate_power_state = plat_validate_power_state, .get_sys_suspend_power_state = plat_get_sys_suspend_power_state, }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { *psci_ops = &plat_plat_pm_ops; secure_entrypoint = sec_entrypoint; return 0; } /* * The PSCI generic code uses this API to let the platform participate in state * coordination during a power management operation. It compares the platform * specific local power states requested by each cpu for a given power domain * and returns the coordinated target power state that the domain should * enter. A platform assigns a number to a local power state. This default * implementation assumes that the platform assigns these numbers in order of * increasing depth of the power state i.e. for two power states X & Y, if X < Y * then X represents a shallower power state than Y. As a result, the * coordinated target local power state for a power domain will be the minimum * of the requested local power states. */ plat_local_state_t plat_get_target_pwr_state(unsigned int lvl, const plat_local_state_t *states, unsigned int ncpu) { plat_local_state_t target = PLAT_MAX_OFF_STATE, temp; assert(ncpu); do { temp = *states++; if (temp < target) target = temp; } while (--ncpu); return target; } trusted-firmware-a-2.2/plat/mediatek/mt8173/plat_sip_calls.c000066400000000000000000000042141355360272700237350ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* Authorized secure register list */ enum { SREG_HDMI_COLOR_EN = 0x14000904 }; static const uint32_t authorized_sreg[] = { SREG_HDMI_COLOR_EN }; #define authorized_sreg_cnt \ (sizeof(authorized_sreg) / sizeof(authorized_sreg[0])) uint64_t mt_sip_set_authorized_sreg(uint32_t sreg, uint32_t val) { uint64_t i; for (i = 0; i < authorized_sreg_cnt; i++) { if (authorized_sreg[i] == sreg) { mmio_write_32(sreg, val); return MTK_SIP_E_SUCCESS; } } return MTK_SIP_E_INVALID_PARAM; } static uint64_t mt_sip_pwr_on_mtcmos(uint32_t val) { uint32_t ret; ret = mtcmos_non_cpu_ctrl(1, val); if (ret) return MTK_SIP_E_INVALID_PARAM; else return MTK_SIP_E_SUCCESS; } static uint64_t mt_sip_pwr_off_mtcmos(uint32_t val) { uint32_t ret; ret = mtcmos_non_cpu_ctrl(0, val); if (ret) return MTK_SIP_E_INVALID_PARAM; else return MTK_SIP_E_SUCCESS; } static uint64_t mt_sip_pwr_mtcmos_support(void) { return MTK_SIP_E_SUCCESS; } uint64_t mediatek_plat_sip_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, void *cookie, void *handle, uint64_t flags) { uint64_t ret; switch (smc_fid) { case MTK_SIP_PWR_ON_MTCMOS: ret = mt_sip_pwr_on_mtcmos((uint32_t)x1); SMC_RET1(handle, ret); case MTK_SIP_PWR_OFF_MTCMOS: ret = mt_sip_pwr_off_mtcmos((uint32_t)x1); SMC_RET1(handle, ret); case MTK_SIP_PWR_MTCMOS_SUPPORT: ret = mt_sip_pwr_mtcmos_support(); SMC_RET1(handle, ret); case MTK_SIP_SET_HDCP_KEY_EX: ret = crypt_set_hdcp_key_ex(x1, x2, x3); SMC_RET1(handle, ret); case MTK_SIP_SET_HDCP_KEY_NUM: ret = crypt_set_hdcp_key_num((uint32_t)x1); SMC_RET1(handle, ret); case MTK_SIP_CLR_HDCP_KEY: ret = crypt_clear_hdcp_key(); SMC_RET1(handle, ret); default: ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); break; } SMC_RET1(handle, SMC_UNK); } trusted-firmware-a-2.2/plat/mediatek/mt8173/plat_topology.c000066400000000000000000000035361355360272700236460ustar00rootroot00000000000000/* * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include const unsigned char mtk_power_domain_tree_desc[] = { /* No of root nodes */ PLATFORM_SYSTEM_COUNT, /* No of children for the root node */ PLATFORM_CLUSTER_COUNT, /* No of children for the first cluster node */ PLATFORM_CLUSTER0_CORE_COUNT, /* No of children for the second cluster node */ PLATFORM_CLUSTER1_CORE_COUNT }; /******************************************************************************* * This function returns the MT8173 default topology tree information. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { return mtk_power_domain_tree_desc; } /******************************************************************************* * This function implements a part of the critical interface between the psci * generic layer and the platform that allows the former to query the platform * to convert an MPIDR to a unique linear index. An error code (-1) is returned * in case the MPIDR is invalid. ******************************************************************************/ int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; mpidr &= MPIDR_AFFINITY_MASK; if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) return -1; cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; if (cluster_id >= PLATFORM_CLUSTER_COUNT) return -1; /* * Validate cpu_id by checking whether it represents a CPU in * one of the two clusters present on the platform. */ if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER) return -1; return (cpu_id + (cluster_id * 4)); } trusted-firmware-a-2.2/plat/mediatek/mt8173/platform.mk000066400000000000000000000046721355360272700227650ustar00rootroot00000000000000# # Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # MTK_PLAT := plat/mediatek MTK_PLAT_SOC := ${MTK_PLAT}/${PLAT} PLAT_INCLUDES := -I${MTK_PLAT}/common/ \ -Iinclude/plat/arm/common/aarch64 \ -I${MTK_PLAT_SOC}/drivers/crypt/ \ -I${MTK_PLAT_SOC}/drivers/mtcmos/ \ -I${MTK_PLAT_SOC}/drivers/pmic/ \ -I${MTK_PLAT_SOC}/drivers/rtc/ \ -I${MTK_PLAT_SOC}/drivers/spm/ \ -I${MTK_PLAT_SOC}/drivers/timer/ \ -I${MTK_PLAT_SOC}/include/ PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \ lib/xlat_tables/aarch64/xlat_tables.c \ plat/arm/common/arm_gicv2.c \ plat/common/plat_gicv2.c \ plat/common/aarch64/crash_console_helpers.S BL31_SOURCES += common/desc_image_load.c \ drivers/arm/cci/cci.c \ drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/ti/uart/aarch64/16550_console.S \ lib/cpus/aarch64/aem_generic.S \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S \ lib/cpus/aarch64/cortex_a72.S \ ${MTK_PLAT}/common/drivers/pmic_wrap/pmic_wrap_init.c \ ${MTK_PLAT}/common/drivers/rtc/rtc_common.c \ ${MTK_PLAT}/common/mtk_plat_common.c \ ${MTK_PLAT}/common/mtk_sip_svc.c \ ${MTK_PLAT_SOC}/aarch64/plat_helpers.S \ ${MTK_PLAT_SOC}/aarch64/platform_common.c \ ${MTK_PLAT_SOC}/bl31_plat_setup.c \ ${MTK_PLAT_SOC}/drivers/crypt/crypt.c \ ${MTK_PLAT_SOC}/drivers/mtcmos/mtcmos.c \ ${MTK_PLAT_SOC}/drivers/rtc/rtc.c \ ${MTK_PLAT_SOC}/drivers/spm/spm.c \ ${MTK_PLAT_SOC}/drivers/spm/spm_hotplug.c \ ${MTK_PLAT_SOC}/drivers/spm/spm_mcdi.c \ ${MTK_PLAT_SOC}/drivers/spm/spm_suspend.c \ ${MTK_PLAT_SOC}/drivers/timer/mt_cpuxgpt.c \ ${MTK_PLAT_SOC}/plat_pm.c \ ${MTK_PLAT_SOC}/plat_sip_calls.c \ ${MTK_PLAT_SOC}/plat_topology.c \ ${MTK_PLAT_SOC}/power_tracer.c \ ${MTK_PLAT_SOC}/scu.c # Enable workarounds for selected Cortex-A53 erratas. ERRATA_A53_826319 := 1 ERRATA_A53_836870 := 1 ERRATA_A53_855873 := 1 # indicate the reset vector address can be programmed PROGRAMMABLE_RESET_ADDRESS := 1 $(eval $(call add_define,MTK_SIP_SET_AUTHORIZED_SECURE_REG_ENABLE)) # Do not enable SVE ENABLE_SVE_FOR_NS := 0 MULTI_CONSOLE_API := 1 trusted-firmware-a-2.2/plat/mediatek/mt8173/power_tracer.c000066400000000000000000000023041355360272700234360ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #define trace_log(...) INFO("psci: " __VA_ARGS__) void trace_power_flow(unsigned long mpidr, unsigned char mode) { switch (mode) { case CPU_UP: trace_log("core %lld:%lld ON\n", (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS, (mpidr & MPIDR_CPU_MASK)); break; case CPU_DOWN: trace_log("core %lld:%lld OFF\n", (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS, (mpidr & MPIDR_CPU_MASK)); break; case CPU_SUSPEND: trace_log("core %lld:%lld SUSPEND\n", (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS, (mpidr & MPIDR_CPU_MASK)); break; case CLUSTER_UP: trace_log("cluster %lld ON\n", (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS); break; case CLUSTER_DOWN: trace_log("cluster %lld OFF\n", (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS); break; case CLUSTER_SUSPEND: trace_log("cluster %lld SUSPEND\n", (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS); break; default: trace_log("unknown power mode\n"); break; } } trusted-firmware-a-2.2/plat/mediatek/mt8173/scu.c000066400000000000000000000012241355360272700215340ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include void disable_scu(unsigned long mpidr) { if (mpidr & MPIDR_CLUSTER_MASK) mmio_setbits_32((uintptr_t)&mt8173_mcucfg->mp1_miscdbg, MP1_ACINACTM); else mmio_setbits_32((uintptr_t)&mt8173_mcucfg->mp0_axi_config, MP0_ACINACTM); } void enable_scu(unsigned long mpidr) { if (mpidr & MPIDR_CLUSTER_MASK) mmio_clrbits_32((uintptr_t)&mt8173_mcucfg->mp1_miscdbg, MP1_ACINACTM); else mmio_clrbits_32((uintptr_t)&mt8173_mcucfg->mp0_axi_config, MP0_ACINACTM); } trusted-firmware-a-2.2/plat/mediatek/mt8183/000077500000000000000000000000001355360272700206005ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8183/aarch64/000077500000000000000000000000001355360272700220305ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8183/aarch64/plat_helpers.S000066400000000000000000000014571355360272700246450ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl plat_is_my_cpu_primary .globl plat_my_core_pos func plat_is_my_cpu_primary mrs x0, mpidr_el1 and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) cmp x0, #PLAT_PRIMARY_CPU cset x0, eq ret endfunc plat_is_my_cpu_primary /* ----------------------------------------------------- * unsigned int plat_my_core_pos(void); * * result: CorePos = CoreId + (ClusterId << 2) * ----------------------------------------------------- */ func plat_my_core_pos mrs x0, mpidr_el1 and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 ret endfunc plat_my_core_pos trusted-firmware-a-2.2/plat/mediatek/mt8183/aarch64/platform_common.c000066400000000000000000000043741355360272700254000ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include static const int cci_map[] = { PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX, PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX }; /* Table of regions to map using the MMU. */ const mmap_region_t plat_mmap[] = { /* for TF text, RO, RW */ MAP_REGION_FLAT(TZRAM_BASE, TZRAM_SIZE, MT_MEMORY | MT_RW | MT_SECURE), MAP_REGION_FLAT(MTK_DEV_RNG0_BASE, MTK_DEV_RNG0_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(MTK_DEV_RNG1_BASE, MTK_DEV_RNG1_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(MTK_DEV_RNG2_BASE, MTK_DEV_RNG2_SIZE, MT_DEVICE | MT_RW | MT_SECURE), { 0 } }; /******************************************************************************* * Macro generating the code for the function setting up the pagetables as per * the platform memory map & initialize the mmu, for the given exception level ******************************************************************************/ void plat_configure_mmu_el3(uintptr_t total_base, uintptr_t total_size, uintptr_t ro_start, uintptr_t ro_limit, uintptr_t coh_start, uintptr_t coh_limit) { mmap_add_region(total_base, total_base, total_size, MT_MEMORY | MT_RW | MT_SECURE); mmap_add_region(ro_start, ro_start, ro_limit - ro_start, MT_MEMORY | MT_RO | MT_SECURE); mmap_add_region(coh_start, coh_start, coh_limit - coh_start, MT_DEVICE | MT_RW | MT_SECURE); mmap_add(plat_mmap); init_xlat_tables(); enable_mmu_el3(0); } unsigned int plat_get_syscnt_freq2(void) { return SYS_COUNTER_FREQ_IN_TICKS; } void plat_mtk_cci_init(void) { /* Initialize CCI driver */ mcsi_init(PLAT_MT_CCI_BASE, ARRAY_SIZE(cci_map)); } void plat_mtk_cci_enable(void) { /* Enable CCI coherency for this cluster. * No need for locks as no other cpu is active at the moment. */ cci_enable_cluster_coherency(read_mpidr()); } void plat_mtk_cci_disable(void) { cci_disable_cluster_coherency(read_mpidr()); } void plat_mtk_cci_init_sf(void) { /* Init mcsi snoop filter. */ cci_init_sf(); } trusted-firmware-a-2.2/plat/mediatek/mt8183/bl31_plat_setup.c000066400000000000000000000130211355360272700237420ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static entry_point_info_t bl32_ep_info; static entry_point_info_t bl33_ep_info; static void platform_setup_cpu(void) { mmio_write_32((uintptr_t)&mt8183_mcucfg->mp0_rw_rsvd0, 0x00000001); /* Mcusys dcm control */ /* Enable pll plldiv dcm */ mmio_setbits_32((uintptr_t)&mt8183_mcucfg->bus_pll_divider_cfg, BUS_PLLDIV_DCM); mmio_setbits_32((uintptr_t)&mt8183_mcucfg->mp0_pll_divider_cfg, MP0_PLLDIV_DCM); mmio_setbits_32((uintptr_t)&mt8183_mcucfg->mp2_pll_divider_cfg, MP2_PLLDIV_DCM); /* Enable mscib dcm */ mmio_clrsetbits_32((uintptr_t)&mt8183_mcucfg->mscib_dcm_en, MCSIB_CACTIVE_SEL_MASK, MCSIB_CACTIVE_SEL); mmio_clrsetbits_32((uintptr_t)&mt8183_mcucfg->mscib_dcm_en, MCSIB_DCM_MASK, MCSIB_DCM); /* Enable adb400 dcm */ mmio_clrsetbits_32((uintptr_t)&mt8183_mcucfg->cci_adb400_dcm_config, CCI_ADB400_DCM_MASK, CCI_ADB400_DCM); /* Enable bus clock dcm */ mmio_setbits_32((uintptr_t)&mt8183_mcucfg->cci_clk_ctrl, MCU_BUS_DCM); /* Enable bus fabric dcm */ mmio_clrsetbits_32( (uintptr_t)&mt8183_mcucfg->mcusys_bus_fabric_dcm_ctrl, MCUSYS_BUS_FABRIC_DCM_MASK, MCUSYS_BUS_FABRIC_DCM); /* Enable l2c sram dcm */ mmio_setbits_32((uintptr_t)&mt8183_mcucfg->l2c_sram_ctrl, L2C_SRAM_DCM); /* Enable busmp0 sync dcm */ mmio_clrsetbits_32((uintptr_t)&mt8183_mcucfg->sync_dcm_config, SYNC_DCM_MASK, SYNC_DCM); /* Enable cntvalue dcm */ mmio_setbits_32((uintptr_t)&mt8183_mcucfg->mcu_misc_dcm_ctrl, CNTVALUEB_DCM); /* Enable dcm cluster stall */ mmio_clrsetbits_32( (uintptr_t)&mt8183_mcucfg->sync_dcm_cluster_config, MCUSYS_MAX_ACCESS_LATENCY_MASK, MCUSYS_MAX_ACCESS_LATENCY); mmio_setbits_32((uintptr_t)&mt8183_mcucfg->sync_dcm_cluster_config, MCU0_SYNC_DCM_STALL_WR_EN); /* Enable rgu dcm */ mmio_setbits_32((uintptr_t)&mt8183_mcucfg->mp0_rgu_dcm_config, CPUSYS_RGU_DCM_CINFIG); } /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for * the security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. ******************************************************************************/ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; next_image_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info; assert(next_image_info->h.type == PARAM_EP); /* None of the images on this platform can have 0x0 as the entrypoint */ if (next_image_info->pc) return next_image_info; else return NULL; } /******************************************************************************* * Perform any BL31 early platform setup. Here is an opportunity to copy * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they * are lost (potentially). This needs to be done before the MMU is initialized * so that the memory layout can be used while creating page tables. * BL2 has flushed this information to memory, so we are guaranteed to pick up * good data. ******************************************************************************/ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { static console_16550_t console; params_early_setup(arg1); #if COREBOOT if (coreboot_serial.type) console_16550_register(coreboot_serial.baseaddr, coreboot_serial.input_hertz, coreboot_serial.baud, &console); #else console_16550_register(UART0_BASE, UART_CLOCK, UART_BAUDRATE, &console); #endif NOTICE("MT8183 bl31_setup\n"); bl31_params_parse_helper(arg0, &bl32_ep_info, &bl33_ep_info); } /******************************************************************************* * Perform any BL31 platform setup code ******************************************************************************/ void bl31_platform_setup(void) { devapc_init(); emi_mpu_init(); platform_setup_cpu(); generic_delay_timer_init(); /* Initialize the GIC driver, CPU and distributor interfaces */ mt_gic_driver_init(); mt_gic_init(); /* Init mcsi SF */ plat_mtk_cci_init_sf(); #if SPMC_MODE == 1 spmc_init(); #endif spm_boot_init(); mcdi_init(); } /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this is only intializes the mmu in a quick and dirty way. ******************************************************************************/ void bl31_plat_arch_setup(void) { plat_mtk_cci_init(); plat_mtk_cci_enable(); enable_scu(read_mpidr()); plat_configure_mmu_el3(BL_CODE_BASE, BL_COHERENT_RAM_END - BL_CODE_BASE, BL_CODE_BASE, BL_CODE_END, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); } trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/000077500000000000000000000000001355360272700222565ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/devapc/000077500000000000000000000000001355360272700235205ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/devapc/devapc.c000066400000000000000000000153161355360272700251340ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include static void set_master_transaction(uint32_t master_index, enum TRANSACTION transaction_type) { uintptr_t base; uint32_t master_register_index; uint32_t master_set_index; uint32_t set_bit; master_register_index = master_index / (MOD_NO_IN_1_DEVAPC * 2); master_set_index = master_index % (MOD_NO_IN_1_DEVAPC * 2); base = DEVAPC_INFRA_MAS_SEC_0 + master_register_index * 4; set_bit = 0x1 << master_set_index; if (transaction_type == SECURE_TRANSACTION) mmio_setbits_32(base, set_bit); else mmio_clrbits_32(base, set_bit); } static void set_master_domain(uint32_t master_index, enum MASK_DOM domain) { uintptr_t base; uint32_t domain_reg; uint32_t domain_index; uint32_t clr_bit; uint32_t set_bit; domain_reg = master_index / MASTER_MOD_NO_IN_1_DEVAPC; domain_index = master_index % MASTER_MOD_NO_IN_1_DEVAPC; clr_bit = 0xF << (4 * domain_index); set_bit = domain << (4 * domain_index); base = DEVAPC_INFRA_MAS_DOM_0 + domain_reg * 4; mmio_clrsetbits_32(base, clr_bit, set_bit); } static void set_master_domain_remap_infra(enum MASK_DOM domain_emi_view, enum MASK_DOM domain_infra_view) { uintptr_t base; uint32_t clr_bit; uint32_t set_bit; if (domain_emi_view < DOMAIN_10) { base = DEVAPC_INFRA_DOM_RMP_0; clr_bit = 0x7 << (domain_emi_view * 3); set_bit = domain_infra_view << (domain_emi_view * 3); mmio_clrsetbits_32(base, clr_bit, set_bit); } else if (domain_emi_view > DOMAIN_10) { base = DEVAPC_INFRA_DOM_RMP_1; domain_emi_view = domain_emi_view - DOMAIN_11; clr_bit = 0x7 << (domain_emi_view * 3 + 1); set_bit = domain_infra_view << (domain_emi_view * 3 + 1); mmio_clrsetbits_32(base, clr_bit, set_bit); } else { base = DEVAPC_INFRA_DOM_RMP_0; clr_bit = 0x3 << (domain_emi_view * 3); set_bit = domain_infra_view << (domain_emi_view * 3); mmio_clrsetbits_32(base, clr_bit, set_bit); base = DEVAPC_INFRA_DOM_RMP_1; set_bit = (domain_infra_view & 0x4) >> 2; mmio_clrsetbits_32(base, 0x1, set_bit); } } static void set_master_domain_remap_mm(enum MASK_DOM domain_emi_view, enum MASK_DOM domain_mm_view) { uintptr_t base; uint32_t clr_bit; uint32_t set_bit; base = DEVAPC_MM_DOM_RMP_0; clr_bit = 0x3 << (domain_emi_view * 2); set_bit = domain_mm_view << (domain_emi_view * 2); mmio_clrsetbits_32(base, clr_bit, set_bit); } static void set_module_apc(enum DAPC_SLAVE_TYPE slave_type, uint32_t module, enum MASK_DOM domain_num, enum APC_ATTR permission_control) { uintptr_t base; uint32_t apc_index; uint32_t apc_set_index; uint32_t clr_bit; uint32_t set_bit; apc_index = module / MOD_NO_IN_1_DEVAPC; apc_set_index = module % MOD_NO_IN_1_DEVAPC; clr_bit = 0x3 << (apc_set_index * 2); set_bit = permission_control << (apc_set_index * 2); if (slave_type == DAPC_INFRA_SLAVE && module <= SLAVE_INFRA_MAX_INDEX) base = DEVAPC_INFRA_D0_APC_0 + domain_num * 0x100 + apc_index * 4; else if (slave_type == DAPC_MM_SLAVE && module <= SLAVE_MM_MAX_INDEX) base = DEVAPC_MM_D0_APC_0 + domain_num * 0x100 + apc_index * 4; else return; mmio_clrsetbits_32(base, clr_bit, set_bit); } static void set_default_master_transaction(void) { set_master_transaction(MASTER_SSPM, SECURE_TRANSACTION); } static void set_default_master_domain(void) { set_master_domain(MASTER_SCP, DOMAIN_1); set_master_domain_remap_infra(DOMAIN_1, DOMAIN_1); set_master_domain_remap_mm(DOMAIN_1, DOMAIN_1); set_master_domain(MASTER_SPM, DOMAIN_2); set_master_domain_remap_infra(DOMAIN_2, DOMAIN_2); set_master_domain_remap_mm(DOMAIN_2, DOMAIN_2); set_master_domain(MASTER_SSPM, DOMAIN_2); set_master_domain_remap_infra(DOMAIN_2, DOMAIN_2); set_master_domain_remap_mm(DOMAIN_2, DOMAIN_2); } static void set_default_slave_permission(void) { uint32_t module_index; uint32_t infra_size; uint32_t mm_size; infra_size = sizeof(D_APC_INFRA_Devices) / sizeof(struct DEVICE_INFO); mm_size = sizeof(D_APC_MM_Devices) / sizeof(struct DEVICE_INFO); for (module_index = 0; module_index < infra_size; module_index++) { if (D_APC_INFRA_Devices[module_index].d0_permission > 0) { set_module_apc(DAPC_INFRA_SLAVE, module_index, DOMAIN_0, D_APC_INFRA_Devices[module_index].d0_permission); } if (D_APC_INFRA_Devices[module_index].d1_permission > 0) { set_module_apc(DAPC_INFRA_SLAVE, module_index, DOMAIN_1, D_APC_INFRA_Devices[module_index].d1_permission); } if (D_APC_INFRA_Devices[module_index].d2_permission > 0) { set_module_apc(DAPC_INFRA_SLAVE, module_index, DOMAIN_2, D_APC_INFRA_Devices[module_index].d2_permission); } } for (module_index = 0; module_index < mm_size; module_index++) { if (D_APC_MM_Devices[module_index].d0_permission > 0) { set_module_apc(DAPC_MM_SLAVE, module_index, DOMAIN_0, D_APC_MM_Devices[module_index].d0_permission); } if (D_APC_MM_Devices[module_index].d1_permission > 0) { set_module_apc(DAPC_MM_SLAVE, module_index, DOMAIN_1, D_APC_MM_Devices[module_index].d1_permission); } if (D_APC_MM_Devices[module_index].d2_permission > 0) { set_module_apc(DAPC_MM_SLAVE, module_index, DOMAIN_2, D_APC_MM_Devices[module_index].d2_permission); } } } static void dump_devapc(void) { int i; INFO("[DEVAPC] dump DEVAPC registers:\n"); for (i = 0; i < 13; i++) { INFO("[DEVAPC] (INFRA)D0_APC_%d = 0x%x, " "(INFRA)D1_APC_%d = 0x%x, " "(INFRA)D2_APC_%d = 0x%x\n", i, mmio_read_32(DEVAPC_INFRA_D0_APC_0 + i * 4), i, mmio_read_32(DEVAPC_INFRA_D0_APC_0 + 0x100 + i * 4), i, mmio_read_32(DEVAPC_INFRA_D0_APC_0 + 0x200 + i * 4)); } for (i = 0; i < 9; i++) { INFO("[DEVAPC] (MM)D0_APC_%d = 0x%x, " "(MM)D1_APC_%d = 0x%x, " "(MM)D2_APC_%d = 0x%x\n", i, mmio_read_32(DEVAPC_MM_D0_APC_0 + i * 4), i, mmio_read_32(DEVAPC_MM_D0_APC_0 + 0x100 + i * 4), i, mmio_read_32(DEVAPC_MM_D0_APC_0 + 0x200 + i * 4)); } for (i = 0; i < 4; i++) { INFO("[DEVAPC] MAS_DOM_%d = 0x%x\n", i, mmio_read_32(DEVAPC_INFRA_MAS_DOM_0 + i * 4)); } INFO("[DEVAPC] MAS_SEC_0 = 0x%x\n", mmio_read_32(DEVAPC_INFRA_MAS_SEC_0)); INFO("[DEVAPC] (INFRA)MAS_DOMAIN_REMAP_0 = 0x%x, " "(INFRA)MAS_DOMAIN_REMAP_1 = 0x%x\n", mmio_read_32(DEVAPC_INFRA_DOM_RMP_0), mmio_read_32(DEVAPC_INFRA_DOM_RMP_1)); INFO("[DEVAPC] (MM)MAS_DOMAIN_REMAP_0 = 0x%x\n", mmio_read_32(DEVAPC_MM_DOM_RMP_0)); } void devapc_init(void) { mmio_write_32(DEVAPC_INFRA_APC_CON, 0x80000001); mmio_write_32(DEVAPC_MM_APC_CON, 0x80000001); mmio_write_32(DEVAPC_MD_APC_CON, 0x80000001); set_default_master_transaction(); set_default_master_domain(); set_default_slave_permission(); dump_devapc(); } trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/devapc/devapc.h000066400000000000000000000642401355360272700251410ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef DEVAPC_H #define DEVAPC_H #include #define DEVAPC_AO_INFRA_BASE 0x1000E000 #define DEVAPC_AO_MM_BASE 0x1001C000 #define DEVAPC_AO_MD_BASE 0x10019000 #define DEVAPC_INFRA_D0_APC_0 (DEVAPC_AO_INFRA_BASE + 0x0000) #define DEVAPC_INFRA_MAS_DOM_0 (DEVAPC_AO_INFRA_BASE + 0x0A00) #define DEVAPC_INFRA_MAS_SEC_0 (DEVAPC_AO_INFRA_BASE + 0x0B00) #define DEVAPC_INFRA_DOM_RMP_0 (DEVAPC_AO_INFRA_BASE + 0x0D00) #define DEVAPC_INFRA_DOM_RMP_1 (DEVAPC_AO_INFRA_BASE + 0x0D04) #define DEVAPC_INFRA_APC_CON (DEVAPC_AO_INFRA_BASE + 0x0F00) #define DEVAPC_MD_APC_CON (DEVAPC_AO_MD_BASE + 0x0F00) #define DEVAPC_MM_D0_APC_0 (DEVAPC_AO_MM_BASE + 0x0000) #define DEVAPC_MM_DOM_RMP_0 (DEVAPC_AO_MM_BASE + 0x0D00) #define DEVAPC_MM_APC_CON (DEVAPC_AO_MM_BASE + 0x0F00) #define MOD_NO_IN_1_DEVAPC 16 #define MASTER_MOD_NO_IN_1_DEVAPC 8 #define SLAVE_INFRA_MAX_INDEX 195 #define SLAVE_MM_MAX_INDEX 140 enum { MASTER_SCP = 0, MASTER_SPM = 10, MASTER_SSPM = 27 }; enum MASK_DOM { DOMAIN_0 = 0, DOMAIN_1, DOMAIN_2, DOMAIN_3, DOMAIN_4, DOMAIN_5, DOMAIN_6, DOMAIN_7, DOMAIN_8, DOMAIN_9, DOMAIN_10, DOMAIN_11 }; enum TRANSACTION { NON_SECURE_TRANSACTION = 0, SECURE_TRANSACTION }; enum DAPC_SLAVE_TYPE { DAPC_INFRA_SLAVE = 0, DAPC_MM_SLAVE }; enum APC_ATTR { NO_SEC = 0, S_RW_ONLY, S_RW_NS_R, FORBID, }; struct DEVICE_INFO { uint8_t d0_permission; uint8_t d1_permission; uint8_t d2_permission; }; #define PERMISSION(DEV_NAME, ATTR1, ATTR2, ATTR3) \ {(uint8_t)ATTR1, (uint8_t)ATTR2, (uint8_t)ATTR3} static const struct DEVICE_INFO D_APC_INFRA_Devices[] = { /* module, domain0, domain1, domain2 */ /* 0 */ PERMISSION("INFRA_AO_TOPCKGEN", NO_SEC, NO_SEC, NO_SEC), PERMISSION("INFRA_AO_INFRASYS_CONFIG_REGS", NO_SEC, FORBID, NO_SEC), PERMISSION("IO_CFG", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_PERICFG", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_EFUSE_AO_DEBUG", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_GPIO", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_SLEEP_CONTROLLER", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_TOPRGU", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_APXGPT", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_RESERVE", NO_SEC, FORBID, NO_SEC), /* 10 */ PERMISSION("INFRA_AO_SEJ", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_AP_CIRQ_EINT", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_APMIXEDSYS", NO_SEC, NO_SEC, NO_SEC), PERMISSION("INFRA_AO_PMIC_WRAP", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_DEVICE_APC_AO_INFRA_PERI", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_SLEEP_CONTROLLER_MD", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_KEYPAD", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_TOP_MISC", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_DVFS_CTRL_PROC", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_MBIST_AO_REG", NO_SEC, FORBID, NO_SEC), /* 20 */ PERMISSION("INFRA_AO_CLDMA_AO_AP", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_DEVICE_MPU", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_AES_TOP_0", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_SYS_TIMER", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_MDEM_TEMP_SHARE", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_DEVICE_APC_AO_MD", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_SECURITY_AO", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_TOPCKGEN_REG", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_DEVICE_APC_AO_MM", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_RESERVE", NO_SEC, FORBID, NO_SEC), /* 30 */ PERMISSION("INFRASYS_RESERVE", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_RESERVE", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_RESERVE", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_SYS_CIRQ", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_MM_IOMMU", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_EFUSE_PDN_DEBUG", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_DEVICE_APC", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_DBG_TRACKER", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_CCIF0_AP", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_CCIF0_MD", NO_SEC, FORBID, NO_SEC), /* 40 */ PERMISSION("INFRASYS_CCIF1_AP", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_CCIF1_MD", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_MBIST", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_INFRA_PDN_REGISTER", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_TRNG", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_DX_CC", NO_SEC, FORBID, NO_SEC), PERMISSION("MD_CCIF_MD1", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_CQ_DMA", NO_SEC, FORBID, NO_SEC), PERMISSION("MD_CCIF_MD2", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_SRAMROM", NO_SEC, FORBID, NO_SEC), /* 50 */ PERMISSION("ANA_MIPI_DSI0", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_RESERVE", NO_SEC, FORBID, NO_SEC), PERMISSION("ANA_MIPI_CSI0", NO_SEC, FORBID, NO_SEC), PERMISSION("ANA_MIPI_CSI1", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_EMI", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_RESERVE", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_CLDMA_PDN", NO_SEC, FORBID, NO_SEC), PERMISSION("CLDMA_PDN_MD_MISC", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_MD", NO_SEC, FORBID, NO_SEC), PERMISSION("BPI_BSI_SLV0", NO_SEC, FORBID, NO_SEC), /* 60 */ PERMISSION("BPI_BSI_SLV1", NO_SEC, FORBID, NO_SEC), PERMISSION("BPI_BSI_SLV2", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_EMI_MPU", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_DVFS_PROC", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_DRAMC_CH0_TOP0", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_DRAMC_CH0_TOP1", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_DRAMC_CH0_TOP2", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_DRAMC_CH0_TOP3", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_DRAMC_CH0_TOP4", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_DRAMC_CH1_TOP0", NO_SEC, FORBID, NO_SEC), /* 70 */ PERMISSION("INFRASYS_DRAMC_CH1_TOP1", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_DRAMC_CH1_TOP2", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_DRAMC_CH1_TOP3", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_DRAMC_CH1_TOP4", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_GCE", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_CCIF2_AP", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_CCIF2_MD", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_CCIF3_AP", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_CCIF3_MD", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRA_AO_PWRMCU Partition 1", S_RW_NS_R, FORBID, NO_SEC), /* 80 */ PERMISSION("INFRA_AO_PWRMCU Partition 2", S_RW_NS_R, FORBID, NO_SEC), PERMISSION("INFRA_AO_PWRMCU Partition 3", S_RW_NS_R, FORBID, NO_SEC), PERMISSION("INFRA_AO_PWRMCU Partition 4", S_RW_NS_R, FORBID, NO_SEC), PERMISSION("INFRA_AO_PWRMCU Partition 5", S_RW_NS_R, FORBID, NO_SEC), PERMISSION("INFRA_AO_PWRMCU Partition 6", S_RW_NS_R, FORBID, NO_SEC), PERMISSION("INFRA_AO_PWRMCU Partition 7", S_RW_NS_R, FORBID, NO_SEC), PERMISSION("INFRA_AO_PWRMCU Partition 8", S_RW_NS_R, FORBID, NO_SEC), PERMISSION("INFRA_AO_SCP", NO_SEC, NO_SEC, NO_SEC), PERMISSION("INFRA_AO_MCUCFG", NO_SEC, FORBID, NO_SEC), PERMISSION("INFRASYS_DBUGSYS", NO_SEC, FORBID, NO_SEC), /* 90 */ PERMISSION("PERISYS_APDMA", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_AUXADC", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_UART0", NO_SEC, NO_SEC, NO_SEC), PERMISSION("PERISYS_UART1", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_UART2", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_I2C6", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_PWM", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_I2C0", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_I2C1", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_I2C2", NO_SEC, FORBID, NO_SEC), /* 100 */ PERMISSION("PERISYS_SPI0", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_PTP", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_BTIF", NO_SEC, FORBID, NO_SEC), PERMISSION("RESERVE", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_DISP_PWM", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_I2C3", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_SPI1", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_I2C4", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_SPI2", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_SPI3", NO_SEC, FORBID, NO_SEC), /* 110 */ PERMISSION("PERISYS_I2C1_IMM", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_I2C2_IMM", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_I2C5", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_I2C5_IMM", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_SPI4", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_SPI5", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_I2C7", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_I2C8", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_USB", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_USB_2_0_SUB", NO_SEC, FORBID, NO_SEC), /* 120 */ PERMISSION("PERISYS_AUDIO", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_MSDC0", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_MSDC1", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_MSDC2", NO_SEC, FORBID, NO_SEC), PERMISSION("RESERVE", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_UFS", NO_SEC, FORBID, NO_SEC), PERMISSION("RESERVE", NO_SEC, FORBID, NO_SEC), PERMISSION("RESERVE", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_RESERVE", NO_SEC, FORBID, NO_SEC), PERMISSION("EAST_RESERVE_0", NO_SEC, FORBID, NO_SEC), /* 130 */ PERMISSION("EAST_RESERVE_1", NO_SEC, FORBID, NO_SEC), PERMISSION("EAST_RESERVE_2", NO_SEC, FORBID, NO_SEC), PERMISSION("EAST_RESERVE_3", NO_SEC, FORBID, NO_SEC), PERMISSION("EAST_RESERVE_4", NO_SEC, FORBID, NO_SEC), PERMISSION("EAST_IO_CFG_RT", NO_SEC, FORBID, NO_SEC), PERMISSION("EAST_RESERVE_6", NO_SEC, FORBID, NO_SEC), PERMISSION("EAST_RESERVE_7", NO_SEC, FORBID, NO_SEC), PERMISSION("EAST_CSI0_TOP_AO", NO_SEC, FORBID, NO_SEC), PERMISSION("RESERVE", NO_SEC, FORBID, NO_SEC), PERMISSION("EAST_RESERVE_A", NO_SEC, FORBID, NO_SEC), /* 140 */ PERMISSION("EAST_RESERVE_B", NO_SEC, FORBID, NO_SEC), PERMISSION("EAST_RESERVE_C", NO_SEC, FORBID, NO_SEC), PERMISSION("EAST_RESERVE_D", NO_SEC, FORBID, NO_SEC), PERMISSION("EAST_RESERVE_E", NO_SEC, FORBID, NO_SEC), PERMISSION("EAST_RESERVE_F", NO_SEC, FORBID, NO_SEC), PERMISSION("SOUTH_RESERVE_0", NO_SEC, FORBID, NO_SEC), PERMISSION("SOUTH_RESERVE_1", NO_SEC, FORBID, NO_SEC), PERMISSION("SOUTH_IO_CFG_RM", NO_SEC, FORBID, NO_SEC), PERMISSION("SOUTH_IO_CFG_RB", NO_SEC, FORBID, NO_SEC), PERMISSION("SOUTH_EFUSE", NO_SEC, FORBID, NO_SEC), /* 150 */ PERMISSION("SOUTH_RESERVE_5", NO_SEC, FORBID, NO_SEC), PERMISSION("SOUTH_RESERVE_6", NO_SEC, FORBID, NO_SEC), PERMISSION("SOUTH_RESERVE_7", NO_SEC, FORBID, NO_SEC), PERMISSION("SOUTH_RESERVE_8", NO_SEC, FORBID, NO_SEC), PERMISSION("SOUTH_RESERVE_9", NO_SEC, FORBID, NO_SEC), PERMISSION("SOUTH_RESERVE_A", NO_SEC, FORBID, NO_SEC), PERMISSION("SOUTH_RESERVE_B", NO_SEC, FORBID, NO_SEC), PERMISSION("SOUTH_RESERVE_C", NO_SEC, FORBID, NO_SEC), PERMISSION("SOUTH_RESERVE_D", NO_SEC, FORBID, NO_SEC), PERMISSION("SOUTH_RESERVE_E", NO_SEC, FORBID, NO_SEC), /* 160 */ PERMISSION("SOUTH_RESERVE_F", NO_SEC, FORBID, NO_SEC), PERMISSION("WEST_RESERVE_0", NO_SEC, FORBID, NO_SEC), PERMISSION("WEST_MSDC1_PAD_MACRO", NO_SEC, FORBID, NO_SEC), PERMISSION("WEST_RESERVE_2", NO_SEC, FORBID, NO_SEC), PERMISSION("WEST_RESERVE_3", NO_SEC, FORBID, NO_SEC), PERMISSION("WEST_RESERVE_4", NO_SEC, FORBID, NO_SEC), PERMISSION("WEST_MIPI_TX_CONFIG", NO_SEC, FORBID, NO_SEC), PERMISSION("WEST_RESERVE_6", NO_SEC, FORBID, NO_SEC), PERMISSION("WEST_IO_CFG_LB", NO_SEC, FORBID, NO_SEC), PERMISSION("WEST_IO_CFG_LM", NO_SEC, FORBID, NO_SEC), /* 170 */ PERMISSION("WEST_IO_CFG_BL", NO_SEC, FORBID, NO_SEC), PERMISSION("WEST_RESERVE_A", NO_SEC, FORBID, NO_SEC), PERMISSION("WEST_RESERVE_B", NO_SEC, FORBID, NO_SEC), PERMISSION("WEST_RESERVE_C", NO_SEC, FORBID, NO_SEC), PERMISSION("WEST_RESERVE_D", NO_SEC, FORBID, NO_SEC), PERMISSION("WEST_RESERVE_E", NO_SEC, FORBID, NO_SEC), PERMISSION("WEST_RESERVE_F", NO_SEC, FORBID, NO_SEC), PERMISSION("NORTH_RESERVE_0", NO_SEC, FORBID, NO_SEC), PERMISSION("EFUSE_TOP", NO_SEC, FORBID, NO_SEC), PERMISSION("NORTH_IO_CFG_LT", NO_SEC, FORBID, NO_SEC), /* 180 */ PERMISSION("NORTH_IO_CFG_TL", NO_SEC, FORBID, NO_SEC), PERMISSION("NORTH_USB20 PHY", NO_SEC, FORBID, NO_SEC), PERMISSION("NORTH_MSDC0 PAD MACRO", NO_SEC, FORBID, NO_SEC), PERMISSION("NORTH_RESERVE_6", NO_SEC, FORBID, NO_SEC), PERMISSION("NORTH_RESERVE_7", NO_SEC, FORBID, NO_SEC), PERMISSION("NORTH_RESERVE_8", NO_SEC, FORBID, NO_SEC), PERMISSION("NORTH_RESERVE_9", NO_SEC, FORBID, NO_SEC), PERMISSION("NORTH_UFS_MPHY", NO_SEC, FORBID, NO_SEC), PERMISSION("NORTH_RESERVE_B", NO_SEC, FORBID, NO_SEC), PERMISSION("NORTH_RESERVE_C", NO_SEC, FORBID, NO_SEC), /* 190 */ PERMISSION("NORTH_RESERVE_D", NO_SEC, FORBID, NO_SEC), PERMISSION("NORTH_RESERVE_E", NO_SEC, FORBID, NO_SEC), PERMISSION("NORTH_RESERVE_F", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_CONN", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_MD_VIOLATION", NO_SEC, FORBID, NO_SEC), PERMISSION("PERISYS_RESERVE", NO_SEC, FORBID, NO_SEC) }; static const struct DEVICE_INFO D_APC_MM_Devices[] = { /* module, domain0, domain1, domain2 */ /* 0 */ PERMISSION("G3D_CONFIG", NO_SEC, FORBID, NO_SEC), PERMISSION("MFG VAD", NO_SEC, FORBID, NO_SEC), PERMISSION("SC0 VAD", NO_SEC, FORBID, NO_SEC), PERMISSION("MFG_OTHERS", NO_SEC, FORBID, NO_SEC), PERMISSION("MMSYS_CONFIG", NO_SEC, NO_SEC, NO_SEC), PERMISSION("MDP_RDMA0", NO_SEC, NO_SEC, NO_SEC), PERMISSION("MDP_RDMA1", NO_SEC, NO_SEC, NO_SEC), PERMISSION("MDP_RSZ0", NO_SEC, NO_SEC, NO_SEC), PERMISSION("MDP_RSZ1", NO_SEC, NO_SEC, NO_SEC), PERMISSION("MDP_WROT0", NO_SEC, NO_SEC, NO_SEC), /* 10 */ PERMISSION("MDP_WDMA", NO_SEC, NO_SEC, NO_SEC), PERMISSION("MDP_TDSHP", NO_SEC, FORBID, NO_SEC), PERMISSION("DISP_OVL0", NO_SEC, FORBID, NO_SEC), PERMISSION("DISP_OVL0_2L", NO_SEC, FORBID, NO_SEC), PERMISSION("DISP_OVL1_2L", NO_SEC, FORBID, NO_SEC), PERMISSION("DISP_RDMA0", NO_SEC, FORBID, NO_SEC), PERMISSION("DISP_RDMA1", NO_SEC, FORBID, NO_SEC), PERMISSION("DISP_WDMA0", NO_SEC, FORBID, NO_SEC), PERMISSION("DISP_COLOR0", NO_SEC, FORBID, NO_SEC), PERMISSION("DISP_CCORR0", NO_SEC, FORBID, NO_SEC), /* 20 */ PERMISSION("DISP_AAL0", NO_SEC, FORBID, NO_SEC), PERMISSION("DISP_GAMMA0", NO_SEC, FORBID, NO_SEC), PERMISSION("DISP_DITHER0", NO_SEC, FORBID, NO_SEC), PERMISSION("DSI_SPLIT", NO_SEC, FORBID, NO_SEC), PERMISSION("DSI0", NO_SEC, FORBID, NO_SEC), PERMISSION("DPI", NO_SEC, FORBID, NO_SEC), PERMISSION("MM_MUTEX", NO_SEC, FORBID, NO_SEC), PERMISSION("SMI_LARB0", NO_SEC, FORBID, NO_SEC), PERMISSION("SMI_LARB1", NO_SEC, FORBID, NO_SEC), PERMISSION("SMI_COMMON", NO_SEC, FORBID, NO_SEC), /* 30 */ PERMISSION("DISP_RSZ", NO_SEC, FORBID, NO_SEC), PERMISSION("MDP_AAL", NO_SEC, NO_SEC, NO_SEC), PERMISSION("MDP_CCORR", NO_SEC, NO_SEC, NO_SEC), PERMISSION("DBI", NO_SEC, FORBID, NO_SEC), PERMISSION("MMSYS_OTHERS", NO_SEC, FORBID, NO_SEC), PERMISSION("IMGSYS_CONFIG", NO_SEC, NO_SEC, NO_SEC), PERMISSION("IMGSYS_SMI_LARB1", NO_SEC, FORBID, NO_SEC), PERMISSION("IMGSYS_DISP_A0", NO_SEC, NO_SEC, NO_SEC), PERMISSION("IMGSYS_DISP_A1", NO_SEC, FORBID, NO_SEC), PERMISSION("IMGSYS_DISP_A2", NO_SEC, FORBID, NO_SEC), /* 40 */ PERMISSION("IMGSYS_DISP_A3", NO_SEC, FORBID, NO_SEC), PERMISSION("IMGSYS_DISP_A4", NO_SEC, FORBID, NO_SEC), PERMISSION("IMGSYS_DISP_A5", NO_SEC, FORBID, NO_SEC), PERMISSION("IMGSYS_DPE", NO_SEC, FORBID, NO_SEC), PERMISSION("IMGSYS_RSC", NO_SEC, FORBID, NO_SEC), PERMISSION("IMGSYS_WPEA", NO_SEC, FORBID, NO_SEC), PERMISSION("IMGSYS_FDVT", NO_SEC, NO_SEC, NO_SEC), PERMISSION("IMGSYS_OWE", NO_SEC, FORBID, NO_SEC), PERMISSION("IMGSYS_WPEB", NO_SEC, FORBID, NO_SEC), PERMISSION("IMGSYS_MFB", NO_SEC, FORBID, NO_SEC), /* 50 */ PERMISSION("IMGSYS_SMI_LARB2", NO_SEC, FORBID, NO_SEC), PERMISSION("IMGSYS_OTHERS", NO_SEC, FORBID, NO_SEC), PERMISSION("VENCSYS_GLOBAL_CON", NO_SEC, NO_SEC, NO_SEC), PERMISSION("VENCSYSSYS_SMI_LARB4", NO_SEC, NO_SEC, NO_SEC), PERMISSION("VENCSYS_VENC", NO_SEC, NO_SEC, NO_SEC), PERMISSION("VENCSYS_JPGENC", NO_SEC, FORBID, NO_SEC), PERMISSION("VENCSYS_MBIST_CTRL", NO_SEC, FORBID, NO_SEC), PERMISSION("VENCSYS_OTHERS", NO_SEC, FORBID, NO_SEC), PERMISSION("VDECSYS_GLOBAL_CON", NO_SEC, NO_SEC, NO_SEC), PERMISSION("VDECSYS_SMI_LARB1", NO_SEC, FORBID, NO_SEC), /* 60 */ PERMISSION("VDECSYS_FULL_TOP", NO_SEC, NO_SEC, NO_SEC), PERMISSION("VDECSYS_OTHERS", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAMSYS_TOP", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_LARB6", NO_SEC, NO_SEC, NO_SEC), PERMISSION("CAMSYS_LARB3", NO_SEC, NO_SEC, NO_SEC), PERMISSION("CAMSYS_CAM_TOP", NO_SEC, NO_SEC, NO_SEC), PERMISSION("CAMSYS_CAM_A", NO_SEC, NO_SEC, NO_SEC), PERMISSION("CAMSYS_CAM_A", NO_SEC, NO_SEC, NO_SEC), PERMISSION("CAMSYS_CAM_B", NO_SEC, NO_SEC, NO_SEC), PERMISSION("CAMSYS_CAM_B", NO_SEC, NO_SEC, NO_SEC), /* 70 */ PERMISSION("CAMSYS_CAM_C", NO_SEC, NO_SEC, NO_SEC), PERMISSION("CAMSYS_CAM_C", NO_SEC, NO_SEC, NO_SEC), PERMISSION("CAMSYS_CAM_TOP_SET", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_A_SET", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_A_SET", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_B_SET", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_B_SET", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_C_SET", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_C_SET", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_TOP_INNER", NO_SEC, FORBID, NO_SEC), /* 80 */ PERMISSION("CAMSYS_CAM_A_INNER", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_A_INNER", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_B_INNER", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_B_INNER", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_C_INNER", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_C_INNER", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_A_EXT", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_B_EXT", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_C_EXT", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_TOP_CLR", NO_SEC, FORBID, NO_SEC), /* 90 */ PERMISSION("CAMSYS_CAM_A_CLR", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_A_CLR", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_B_CLR", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_B_CLR", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_C_CLR", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_C_CLR", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_A_EXT", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_B_EXT", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_C_EXT", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAM_RESERVE", NO_SEC, FORBID, NO_SEC), /* 100 */ PERMISSION("CAMSYS_SENINF_A", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_SENINF_B", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_SENINF_C", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_SENINF_D", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_SENINF_E", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_SENINF_F", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_SENINF_G", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_SENINF_H", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAMSV_A", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAMSV_B", NO_SEC, FORBID, NO_SEC), /* 110 */ PERMISSION("CAMSYS_CAMSV_C", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CAMSV_D", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_MD32 DMEM_12", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_RESEVE", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CCU_CTL", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CCU_H2T_A", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CCU_T2H_A", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_RESERVE", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_RESERVE", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_CCU_DMA", NO_SEC, FORBID, NO_SEC), /* 120 */ PERMISSION("CAMSYS_TSF", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_MD32_PMEM_24", NO_SEC, FORBID, NO_SEC), PERMISSION("CAMSYS_OTHERS", NO_SEC, FORBID, NO_SEC), PERMISSION("VPUSYS_CFG", NO_SEC, FORBID, NO_SEC), PERMISSION("VPUSYS_ADL_CTRL", NO_SEC, FORBID, NO_SEC), PERMISSION("VPUSYS_COREA_DMEM_0_128KB", NO_SEC, FORBID, NO_SEC), PERMISSION("VPUSYS_COREA_DMEM_128_256KB", NO_SEC, FORBID, NO_SEC), PERMISSION("VPUSYS_COREA_IMEM_256KB", NO_SEC, FORBID, NO_SEC), PERMISSION("VPUSYS_COREA_CONTROL", NO_SEC, FORBID, NO_SEC), PERMISSION("VPUSYS_COREA_DEBUG", NO_SEC, FORBID, NO_SEC), /* 130 */ PERMISSION("VPUSYS_COREB_DMEM_0_128KB", NO_SEC, FORBID, NO_SEC), PERMISSION("VPUSYS_COREB_DMEM_128_256KB", NO_SEC, FORBID, NO_SEC), PERMISSION("VPUSYS_COREB_IMEM_256KB", NO_SEC, FORBID, NO_SEC), PERMISSION("VPUSYS_COREB_CONTROL", NO_SEC, FORBID, NO_SEC), PERMISSION("VPUSYS_COREB_DEBUG", NO_SEC, FORBID, NO_SEC), PERMISSION("VPUSYS_COREC_DMEM_0_128KB", NO_SEC, FORBID, NO_SEC), PERMISSION("VPUSYS_COREC_DMEM_128_256KB", NO_SEC, FORBID, NO_SEC), PERMISSION("VPUSYS_COREC_IMEM_256KB", NO_SEC, FORBID, NO_SEC), PERMISSION("VPUSYS_COREC_CONTROL", NO_SEC, FORBID, NO_SEC), PERMISSION("VPUSYS_COREC_DEBUG", NO_SEC, FORBID, NO_SEC), /* 140 */ PERMISSION("VPUSYS_OTHERS", NO_SEC, FORBID, NO_SEC) }; void devapc_init(void); #endif /* DEVAPC_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/emi_mpu/000077500000000000000000000000001355360272700237115ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/emi_mpu/emi_mpu.c000066400000000000000000000074041355360272700255150ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include int is_4GB(void) { return 0; /* 8183 doesn't use 4GB */ } /* * emi_mpu_set_region_protection: protect a region. * @start: start address of the region * @end: end address of the region * @region: EMI MPU region id * @access_permission: EMI MPU access permission * Return 0 for success, otherwise negative status code. */ int emi_mpu_set_region_protection( unsigned long start, unsigned long end, int region, unsigned int access_permission) { int ret = 0; if (end <= start) { ERROR("[EMI][MTEE][MPU] Invalid address!.\n"); return -1; } if (is_4GB()) { /* 4GB mode: emi_addr = phy_addr & 0xffff */ start = EMI_PHY_OFFSET & 0xffff; end = EMI_PHY_OFFSET & 0xffff; } else { /* non-4GB mode: emi_addr = phy_addr - MEM_OFFSET */ start = start - EMI_PHY_OFFSET; end = end - EMI_PHY_OFFSET; } /*Address 64KB alignment*/ start = start >> 16; end = end >> 16; switch (region) { case 0: mmio_write_32(EMI_MPU_APC0, 0); mmio_write_32(EMI_MPU_SA0, start); mmio_write_32(EMI_MPU_EA0, end); mmio_write_32(EMI_MPU_APC0, access_permission); break; case 1: mmio_write_32(EMI_MPU_APC1, 0); mmio_write_32(EMI_MPU_SA1, start); mmio_write_32(EMI_MPU_EA1, end); mmio_write_32(EMI_MPU_APC1, access_permission); break; case 2: mmio_write_32(EMI_MPU_APC2, 0); mmio_write_32(EMI_MPU_SA2, start); mmio_write_32(EMI_MPU_EA2, end); mmio_write_32(EMI_MPU_APC2, access_permission); break; case 3: mmio_write_32(EMI_MPU_APC3, 0); mmio_write_32(EMI_MPU_SA3, start); mmio_write_32(EMI_MPU_EA3, end); mmio_write_32(EMI_MPU_APC3, access_permission); break; case 4: mmio_write_32(EMI_MPU_APC4, 0); mmio_write_32(EMI_MPU_SA4, start); mmio_write_32(EMI_MPU_EA4, end); mmio_write_32(EMI_MPU_APC4, access_permission); break; case 5: mmio_write_32(EMI_MPU_APC5, 0); mmio_write_32(EMI_MPU_SA5, start); mmio_write_32(EMI_MPU_EA5, end); mmio_write_32(EMI_MPU_APC5, access_permission); break; case 6: mmio_write_32(EMI_MPU_APC6, 0); mmio_write_32(EMI_MPU_SA6, start); mmio_write_32(EMI_MPU_EA6, end); mmio_write_32(EMI_MPU_APC6, access_permission); break; case 7: mmio_write_32(EMI_MPU_APC7, 0); mmio_write_32(EMI_MPU_SA7, start); mmio_write_32(EMI_MPU_EA7, end); mmio_write_32(EMI_MPU_APC7, access_permission); break; default: ret = -1; break; } return ret; } void dump_emi_mpu_regions(void) { unsigned int apc, sa, ea; unsigned int apc_addr = EMI_MPU_APC0; unsigned int sa_addr = EMI_MPU_SA0; unsigned int ea_addr = EMI_MPU_EA0; int i; for (i = 0; i < 8; ++i) { apc = mmio_read_32(apc_addr + i * 4); sa = mmio_read_32(sa_addr + i * 4); ea = mmio_read_32(ea_addr + i * 4); WARN("region %d:\n", i); WARN("\tapc:0x%x, sa:0x%x, ea:0x%x\n", apc, sa, ea); } } void emi_mpu_init(void) { /* Set permission */ emi_mpu_set_region_protection(0x40000000UL, 0x4FFFFFFFUL, 0, (FORBIDDEN << 3 | FORBIDDEN << 6)); emi_mpu_set_region_protection(0x50000000UL, 0x528FFFFFUL, 1, (FORBIDDEN << 6)); emi_mpu_set_region_protection(0x52900000UL, 0x5FFFFFFFUL, 2, (FORBIDDEN << 3 | FORBIDDEN << 6)); emi_mpu_set_region_protection(0x60000000UL, 0x7FFFFFFFUL, 3, (FORBIDDEN << 3 | FORBIDDEN << 6)); emi_mpu_set_region_protection(0x80000000UL, 0x9FFFFFFFUL, 4, (FORBIDDEN << 3 | FORBIDDEN << 6)); emi_mpu_set_region_protection(0xA0000000UL, 0xBFFFFFFFUL, 5, (FORBIDDEN << 3 | FORBIDDEN << 6)); emi_mpu_set_region_protection(0xC0000000UL, 0xDFFFFFFFUL, 6, (FORBIDDEN << 3 | FORBIDDEN << 6)); emi_mpu_set_region_protection(0xE0000000UL, 0xFFFFFFFFUL, 7, (FORBIDDEN << 3 | FORBIDDEN << 6)); dump_emi_mpu_regions(); } trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/emi_mpu/emi_mpu.h000066400000000000000000000077041355360272700255250ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __EMI_MPU_H #define __EMI_MPU_H #include #define EMI_MPUP (EMI_BASE + 0x01D8) #define EMI_MPUQ (EMI_BASE + 0x01E0) #define EMI_MPUR (EMI_BASE + 0x01E8) #define EMI_MPUS (EMI_BASE + 0x01F0) #define EMI_MPUT (EMI_BASE + 0x01F8) #define EMI_MPUY (EMI_BASE + 0x0220) #define EMI_MPU_CTRL (EMI_MPU_BASE + 0x0000) #define EMI_MPUD0_ST (EMI_BASE + 0x0160) #define EMI_MPUD1_ST (EMI_BASE + 0x0164) #define EMI_MPUD2_ST (EMI_BASE + 0x0168) #define EMI_MPUD3_ST (EMI_BASE + 0x016C) #define EMI_MPUD0_ST2 (EMI_BASE + 0x0200) #define EMI_MPUD1_ST2 (EMI_BASE + 0x0204) #define EMI_MPUD2_ST2 (EMI_BASE + 0x0208) #define EMI_MPUD3_ST2 (EMI_BASE + 0x020C) #define EMI_PHY_OFFSET (0x40000000UL) #define EIGHT_DOMAIN #define NO_PROTECTION (0) #define SEC_RW (1) #define SEC_RW_NSEC_R (2) #define SEC_RW_NSEC_W (3) #define SEC_R_NSEC_R (4) #define FORBIDDEN (5) #define SEC_R_NSEC_RW (6) #define SECURE_OS_MPU_REGION_ID (0) #define ATF_MPU_REGION_ID (1) #ifdef EIGHT_DOMAIN #define SET_ACCESS_PERMISSON(d7, d6, d5, d4, d3, d2, d1, d0) \ (((d7) << 21) | ((d6) << 18) | ((d5) << 15) | ((d4) << 12) \ | ((d3) << 9) | ((d2) << 6) | ((d1) << 3) | (d0)) #else #define SET_ACCESS_PERMISSON(d3, d2, d1, d0) \ (((d3) << 9) | ((d2) << 6) | ((d1) << 3) | (d0)) #endif //#define EMI_MPU_BASE (0x1020E000U) #define EMI_MPU_SA0 (EMI_MPU_BASE + 0x100) #define EMI_MPU_SA1 (EMI_MPU_BASE + 0x104) #define EMI_MPU_SA2 (EMI_MPU_BASE + 0x108) #define EMI_MPU_SA3 (EMI_MPU_BASE + 0x10C) #define EMI_MPU_SA4 (EMI_MPU_BASE + 0x110) #define EMI_MPU_SA5 (EMI_MPU_BASE + 0x114) #define EMI_MPU_SA6 (EMI_MPU_BASE + 0x118) #define EMI_MPU_SA7 (EMI_MPU_BASE + 0x11C) #define EMI_MPU_EA0 (EMI_MPU_BASE + 0x200) #define EMI_MPU_EA1 (EMI_MPU_BASE + 0x204) #define EMI_MPU_EA2 (EMI_MPU_BASE + 0x208) #define EMI_MPU_EA3 (EMI_MPU_BASE + 0x20C) #define EMI_MPU_EA4 (EMI_MPU_BASE + 0x210) #define EMI_MPU_EA5 (EMI_MPU_BASE + 0x214) #define EMI_MPU_EA6 (EMI_MPU_BASE + 0x218) #define EMI_MPU_EA7 (EMI_MPU_BASE + 0x21C) #define EMI_MPU_APC0 (EMI_MPU_BASE + 0x300) #define EMI_MPU_APC1 (EMI_MPU_BASE + 0x304) #define EMI_MPU_APC2 (EMI_MPU_BASE + 0x308) #define EMI_MPU_APC3 (EMI_MPU_BASE + 0x30C) #define EMI_MPU_APC4 (EMI_MPU_BASE + 0x310) #define EMI_MPU_APC5 (EMI_MPU_BASE + 0x314) #define EMI_MPU_APC6 (EMI_MPU_BASE + 0x318) #define EMI_MPU_APC7 (EMI_MPU_BASE + 0x31C) #define EMI_MPU_CTRL_D0 (EMI_MPU_BASE + 0x800) #define EMI_MPU_CTRL_D1 (EMI_MPU_BASE + 0x804) #define EMI_MPU_CTRL_D2 (EMI_MPU_BASE + 0x808) #define EMI_MPU_CTRL_D3 (EMI_MPU_BASE + 0x80C) #define EMI_MPU_CTRL_D4 (EMI_MPU_BASE + 0x810) #define EMI_MPU_CTRL_D5 (EMI_MPU_BASE + 0x814) #define EMI_MPU_CTRL_D6 (EMI_MPU_BASE + 0x818) #define EMI_MPU_CTRL_D7 (EMI_MPU_BASE + 0x81C) #define EMI_MPU_MASK_D0 (EMI_MPU_BASE + 0x900) #define EMI_MPU_MASK_D1 (EMI_MPU_BASE + 0x904) #define EMI_MPU_MASK_D2 (EMI_MPU_BASE + 0x908) #define EMI_MPU_MASK_D3 (EMI_MPU_BASE + 0x90C) #define EMI_MPU_MASK_D4 (EMI_MPU_BASE + 0x910) #define EMI_MPU_MASK_D5 (EMI_MPU_BASE + 0x914) #define EMI_MPU_MASK_D6 (EMI_MPU_BASE + 0x918) #define EMI_MPU_MASK_D7 (EMI_MPU_BASE + 0x91C) int emi_mpu_set_region_protection( unsigned long start, unsigned long end, int region, unsigned int access_permission); void dump_emi_mpu_regions(void); void emi_mpu_init(void); #endif /* __EMI_MPU_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/gpio/000077500000000000000000000000001355360272700232145ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/gpio/mtgpio.c000066400000000000000000000240071355360272700246620ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include /****************************************************************************** *Macro Definition ******************************************************************************/ #define GPIO_MODE_BITS 4 #define MAX_GPIO_MODE_PER_REG 8 #define MAX_GPIO_REG_BITS 32 #define DIR_BASE (GPIO_BASE + 0x000) #define DOUT_BASE (GPIO_BASE + 0x100) #define DIN_BASE (GPIO_BASE + 0x200) #define MODE_BASE (GPIO_BASE + 0x300) #define SET 0x4 #define CLR 0x8 #define PULLEN_ADDR_OFFSET 0x060 #define PULLSEL_ADDR_OFFSET 0x080 void mt_set_gpio_dir_chip(uint32_t pin, int dir) { uint32_t pos, bit; assert(pin < MAX_GPIO_PIN); assert(dir < GPIO_DIR_MAX); pos = pin / MAX_GPIO_REG_BITS; bit = pin % MAX_GPIO_REG_BITS; if (dir == GPIO_DIR_IN) mmio_write_32(DIR_BASE + 0x10 * pos + CLR, 1U << bit); else mmio_write_32(DIR_BASE + 0x10 * pos + SET, 1U << bit); } int mt_get_gpio_dir_chip(uint32_t pin) { uint32_t pos, bit; uint32_t reg; assert(pin < MAX_GPIO_PIN); pos = pin / MAX_GPIO_REG_BITS; bit = pin % MAX_GPIO_REG_BITS; reg = mmio_read_32(DIR_BASE + 0x10 * pos); return (((reg & (1U << bit)) != 0) ? GPIO_DIR_OUT : GPIO_DIR_IN); } void mt_set_gpio_out_chip(uint32_t pin, int output) { uint32_t pos, bit; assert(pin < MAX_GPIO_PIN); assert(output < GPIO_OUT_MAX); pos = pin / MAX_GPIO_REG_BITS; bit = pin % MAX_GPIO_REG_BITS; if (output == GPIO_OUT_ZERO) mmio_write_32(DOUT_BASE + 0x10 * pos + CLR, 1U << bit); else mmio_write_32(DOUT_BASE + 0x10 * pos + SET, 1U << bit); } int mt_get_gpio_out_chip(uint32_t pin) { uint32_t pos, bit; uint32_t reg; assert(pin < MAX_GPIO_PIN); pos = pin / MAX_GPIO_REG_BITS; bit = pin % MAX_GPIO_REG_BITS; reg = mmio_read_32(DOUT_BASE + 0x10 * pos); return (((reg & (1U << bit)) != 0) ? 1 : 0); } int mt_get_gpio_in_chip(uint32_t pin) { uint32_t pos, bit; uint32_t reg; assert(pin < MAX_GPIO_PIN); pos = pin / MAX_GPIO_REG_BITS; bit = pin % MAX_GPIO_REG_BITS; reg = mmio_read_32(DIN_BASE + 0x10 * pos); return (((reg & (1U << bit)) != 0) ? 1 : 0); } void mt_set_gpio_mode_chip(uint32_t pin, int mode) { uint32_t pos, bit; uint32_t data; uint32_t mask; assert(pin < MAX_GPIO_PIN); assert(mode < GPIO_MODE_MAX); mask = (1U << GPIO_MODE_BITS) - 1; mode = mode & mask; pos = pin / MAX_GPIO_MODE_PER_REG; bit = (pin % MAX_GPIO_MODE_PER_REG) * GPIO_MODE_BITS; data = mmio_read_32(MODE_BASE + 0x10 * pos); data &= (~(mask << bit)); data |= (mode << bit); mmio_write_32(MODE_BASE + 0x10 * pos, data); } int mt_get_gpio_mode_chip(uint32_t pin) { uint32_t pos, bit; uint32_t data; uint32_t mask; assert(pin < MAX_GPIO_PIN); mask = (1U << GPIO_MODE_BITS) - 1; pos = pin / MAX_GPIO_MODE_PER_REG; bit = (pin % MAX_GPIO_MODE_PER_REG) * GPIO_MODE_BITS; data = mmio_read_32(MODE_BASE + 0x10 * pos); return (data >> bit) & mask; } int32_t gpio_get_pull_iocfg(uint32_t pin) { switch (pin) { case 0 ... 10: return IOCFG_5_BASE; case 11 ... 12: return IOCFG_0_BASE; case 13 ... 28: return IOCFG_1_BASE; case 43 ... 49: return IOCFG_2_BASE; case 50 ... 60: return IOCFG_3_BASE; case 61 ... 88: return IOCFG_4_BASE; case 89 ... 90: return IOCFG_5_BASE; case 95 ... 106: return IOCFG_5_BASE; case 107 ... 121: return IOCFG_6_BASE; case 134 ... 160: return IOCFG_0_BASE; case 161 ... 166: return IOCFG_1_BASE; case 167 ... 176: return IOCFG_3_BASE; case 177 ... 179: return IOCFG_5_BASE; default: return -1; } } int32_t gpio_get_pupd_iocfg(uint32_t pin) { const int32_t offset = 0x0c0; switch (pin) { case 29 ... 34: return IOCFG_1_BASE + offset; case 35 ... 42: return IOCFG_2_BASE + offset; case 91 ... 94: return IOCFG_5_BASE + offset; case 122 ... 133: return IOCFG_7_BASE + offset; default: return -1; } } int gpio_get_pupd_offset(uint32_t pin) { switch (pin) { case 29 ... 34: return (pin - 29) * 4 % 32; case 35 ... 42: return (pin - 35) * 4 % 32; case 91 ... 94: return (pin - 91) * 4 % 32; case 122 ... 129: return (pin - 122) * 4 % 32; case 130 ... 133: return (pin - 130) * 4 % 32; default: return -1; } } void mt_set_gpio_pull_enable_chip(uint32_t pin, int en) { int pullen_addr = gpio_get_pull_iocfg(pin) + PULLEN_ADDR_OFFSET; int pupd_addr = gpio_get_pupd_iocfg(pin); int pupd_offset = gpio_get_pupd_offset(pin); assert(pin < MAX_GPIO_PIN); assert(!((PULL_offset[pin].offset == (int8_t)-1) && (pupd_offset == (int8_t)-1))); if (en == GPIO_PULL_DISABLE) { if (PULL_offset[pin].offset == (int8_t)-1) mmio_clrbits_32(pupd_addr, 3U << pupd_offset); else mmio_clrbits_32(pullen_addr, 1U << PULL_offset[pin].offset); } else if (en == GPIO_PULL_ENABLE) { if (PULL_offset[pin].offset == (int8_t)-1) { /* For PUPD+R0+R1 Type, mt_set_gpio_pull_enable * does not know * which one between PU and PD shall be enabled. * Use R0 to guarantee at one resistor is set when lk * apply default setting */ mmio_setbits_32(pupd_addr, 1U << pupd_offset); mmio_clrbits_32(pupd_addr, 1U << (pupd_offset + 1)); } else { /* For PULLEN + PULLSEL Type */ mmio_setbits_32(pullen_addr, 1U << PULL_offset[pin].offset); } } else if (en == GPIO_PULL_ENABLE_R0) { assert(!(pupd_offset == (int8_t)-1)); mmio_setbits_32(pupd_addr, 1U << pupd_offset); mmio_clrbits_32(pupd_addr, 1U << (pupd_offset + 1)); } else if (en == GPIO_PULL_ENABLE_R1) { assert(!(pupd_offset == (int8_t)-1)); mmio_clrbits_32(pupd_addr, 1U << pupd_offset); mmio_setbits_32(pupd_addr, 1U << (pupd_offset + 1)); } else if (en == GPIO_PULL_ENABLE_R0R1) { assert(!(pupd_offset == (int8_t)-1)); mmio_setbits_32(pupd_addr, 3U << pupd_offset); } } int mt_get_gpio_pull_enable_chip(uint32_t pin) { uint32_t reg; int pullen_addr = gpio_get_pull_iocfg(pin) + PULLEN_ADDR_OFFSET; int pupd_addr = gpio_get_pupd_iocfg(pin); int pupd_offset = gpio_get_pupd_offset(pin); assert(pin < MAX_GPIO_PIN); assert(!((PULL_offset[pin].offset == (int8_t)-1) && (pupd_offset == (int8_t)-1))); if (PULL_offset[pin].offset == (int8_t)-1) { reg = mmio_read_32(pupd_addr); return ((reg & (3U << pupd_offset)) ? 1 : 0); } else if (pupd_offset == (int8_t)-1) { reg = mmio_read_32(pullen_addr); return ((reg & (1U << PULL_offset[pin].offset)) ? 1 : 0); } return -ERINVAL; } void mt_set_gpio_pull_select_chip(uint32_t pin, int sel) { int pullsel_addr = gpio_get_pull_iocfg(pin) + PULLSEL_ADDR_OFFSET; int pupd_addr = gpio_get_pupd_iocfg(pin); int pupd_offset = gpio_get_pupd_offset(pin); assert(pin < MAX_GPIO_PIN); assert(!((PULL_offset[pin].offset == (int8_t) -1) && (pupd_offset == (int8_t)-1))); if (sel == GPIO_PULL_NONE) { /* Regard No PULL as PULL disable + pull down */ mt_set_gpio_pull_enable_chip(pin, GPIO_PULL_DISABLE); if (PULL_offset[pin].offset == (int8_t)-1) mmio_setbits_32(pupd_addr, 1U << (pupd_offset + 2)); else mmio_clrbits_32(pullsel_addr, 1U << PULL_offset[pin].offset); } else if (sel == GPIO_PULL_UP) { mt_set_gpio_pull_enable_chip(pin, GPIO_PULL_ENABLE); if (PULL_offset[pin].offset == (int8_t)-1) mmio_clrbits_32(pupd_addr, 1U << (pupd_offset + 2)); else mmio_setbits_32(pullsel_addr, 1U << PULL_offset[pin].offset); } else if (sel == GPIO_PULL_DOWN) { mt_set_gpio_pull_enable_chip(pin, GPIO_PULL_ENABLE); if (PULL_offset[pin].offset == -1) mmio_setbits_32(pupd_addr, 1U << (pupd_offset + 2)); else mmio_clrbits_32(pullsel_addr, 1U << PULL_offset[pin].offset); } } /* get pull-up or pull-down, regardless of resistor value */ int mt_get_gpio_pull_select_chip(uint32_t pin) { uint32_t reg; int pullen_addr = gpio_get_pull_iocfg(pin) + PULLEN_ADDR_OFFSET; int pullsel_addr = gpio_get_pull_iocfg(pin) + PULLSEL_ADDR_OFFSET; int pupd_addr = gpio_get_pupd_iocfg(pin); int pupd_offset = gpio_get_pupd_offset(pin); assert(pin < MAX_GPIO_PIN); assert(!((PULL_offset[pin].offset == (int8_t)-1) && (pupd_offset == (int8_t)-1))); if (PULL_offset[pin].offset == (int8_t)-1) { reg = mmio_read_32(pupd_addr); if (reg & (3U << pupd_offset)) { reg = mmio_read_32(pupd_addr); /* Reg value: 0 for PU, 1 for PD --> * reverse return value */ return ((reg & (1U << (pupd_offset + 2))) ? GPIO_PULL_DOWN : GPIO_PULL_UP); } else { return GPIO_PULL_NONE; } } else if (pupd_offset == (int8_t)-1) { reg = mmio_read_32(pullen_addr); if ((reg & (1U << PULL_offset[pin].offset))) { reg = mmio_read_32(pullsel_addr); return ((reg & (1U << PULL_offset[pin].offset)) ? GPIO_PULL_UP : GPIO_PULL_DOWN); } else { return GPIO_PULL_NONE; } } return -ERINVAL; } void mt_set_gpio_dir(int gpio, int direction) { mt_set_gpio_dir_chip((uint32_t)gpio, direction); } int mt_get_gpio_dir(int gpio) { uint32_t pin; pin = (uint32_t)gpio; return mt_get_gpio_dir_chip(pin); } void mt_set_gpio_pull(int gpio, int pull) { uint32_t pin; pin = (uint32_t)gpio; mt_set_gpio_pull_select_chip(pin, pull); } int mt_get_gpio_pull(int gpio) { uint32_t pin; pin = (uint32_t)gpio; return mt_get_gpio_pull_select_chip(pin); } void mt_set_gpio_out(int gpio, int value) { uint32_t pin; pin = (uint32_t)gpio; mt_set_gpio_out_chip(pin, value); } int mt_get_gpio_out(int gpio) { uint32_t pin; pin = (uint32_t)gpio; return mt_get_gpio_out_chip(pin); } int mt_get_gpio_in(int gpio) { uint32_t pin; pin = (uint32_t)gpio; return mt_get_gpio_in_chip(pin); } void mt_set_gpio_mode(int gpio, int mode) { uint32_t pin; pin = (uint32_t)gpio; mt_set_gpio_mode_chip(pin, mode); } int mt_get_gpio_mode(int gpio) { uint32_t pin; pin = (uint32_t)gpio; return mt_get_gpio_mode_chip(pin); } const gpio_ops_t mtgpio_ops = { .get_direction = mt_get_gpio_dir, .set_direction = mt_set_gpio_dir, .get_value = mt_get_gpio_in, .set_value = mt_set_gpio_out, .set_pull = mt_set_gpio_pull, .get_pull = mt_get_gpio_pull, }; trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/gpio/mtgpio.h000066400000000000000000000103201355360272700246600ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MT_GPIO_H #define MT_GPIO_H #include #include /* Error Code No. */ #define RSUCCESS 0 #define ERACCESS 1 #define ERINVAL 2 #define ERWRAPPER 3 #define MAX_GPIO_PIN MT_GPIO_BASE_MAX /* Enumeration for GPIO pin */ typedef enum GPIO_PIN { GPIO_UNSUPPORTED = -1, GPIO0, GPIO1, GPIO2, GPIO3, GPIO4, GPIO5, GPIO6, GPIO7, GPIO8, GPIO9, GPIO10, GPIO11, GPIO12, GPIO13, GPIO14, GPIO15, GPIO16, GPIO17, GPIO18, GPIO19, GPIO20, GPIO21, GPIO22, GPIO23, GPIO24, GPIO25, GPIO26, GPIO27, GPIO28, GPIO29, GPIO30, GPIO31, GPIO32, GPIO33, GPIO34, GPIO35, GPIO36, GPIO37, GPIO38, GPIO39, GPIO40, GPIO41, GPIO42, GPIO43, GPIO44, GPIO45, GPIO46, GPIO47, GPIO48, GPIO49, GPIO50, GPIO51, GPIO52, GPIO53, GPIO54, GPIO55, GPIO56, GPIO57, GPIO58, GPIO59, GPIO60, GPIO61, GPIO62, GPIO63, GPIO64, GPIO65, GPIO66, GPIO67, GPIO68, GPIO69, GPIO70, GPIO71, GPIO72, GPIO73, GPIO74, GPIO75, GPIO76, GPIO77, GPIO78, GPIO79, GPIO80, GPIO81, GPIO82, GPIO83, GPIO84, GPIO85, GPIO86, GPIO87, GPIO88, GPIO89, GPIO90, GPIO91, GPIO92, GPIO93, GPIO94, GPIO95, GPIO96, GPIO97, GPIO98, GPIO99, GPIO100, GPIO101, GPIO102, GPIO103, GPIO104, GPIO105, GPIO106, GPIO107, GPIO108, GPIO109, GPIO110, GPIO111, GPIO112, GPIO113, GPIO114, GPIO115, GPIO116, GPIO117, GPIO118, GPIO119, GPIO120, GPIO121, GPIO122, GPIO123, GPIO124, GPIO125, GPIO126, GPIO127, GPIO128, GPIO129, GPIO130, GPIO131, GPIO132, GPIO133, GPIO134, GPIO135, GPIO136, GPIO137, GPIO138, GPIO139, GPIO140, GPIO141, GPIO142, GPIO143, GPIO144, GPIO145, GPIO146, GPIO147, GPIO148, GPIO149, GPIO150, GPIO151, GPIO152, GPIO153, GPIO154, GPIO155, GPIO156, GPIO157, GPIO158, GPIO159, GPIO160, GPIO161, GPIO162, GPIO163, GPIO164, GPIO165, GPIO166, GPIO167, GPIO168, GPIO169, GPIO170, GPIO171, GPIO172, GPIO173, GPIO174, GPIO175, GPIO176, GPIO177, GPIO178, GPIO179, MT_GPIO_BASE_MAX } GPIO_PIN; /* GPIO MODE CONTROL VALUE*/ typedef enum { GPIO_MODE_UNSUPPORTED = -1, GPIO_MODE_GPIO = 0, GPIO_MODE_00 = 0, GPIO_MODE_01, GPIO_MODE_02, GPIO_MODE_03, GPIO_MODE_04, GPIO_MODE_05, GPIO_MODE_06, GPIO_MODE_07, GPIO_MODE_MAX, GPIO_MODE_DEFAULT = GPIO_MODE_00, } GPIO_MODE; /* GPIO DIRECTION */ typedef enum { GPIO_DIR_UNSUPPORTED = -1, GPIO_DIR_OUT = 0, GPIO_DIR_IN = 1, GPIO_DIR_MAX, GPIO_DIR_DEFAULT = GPIO_DIR_IN, } GPIO_DIR; /* GPIO PULL ENABLE*/ typedef enum { GPIO_PULL_EN_UNSUPPORTED = -1, GPIO_PULL_DISABLE = 0, GPIO_PULL_ENABLE = 1, GPIO_PULL_ENABLE_R0 = 2, GPIO_PULL_ENABLE_R1 = 3, GPIO_PULL_ENABLE_R0R1 = 4, GPIO_PULL_EN_MAX, GPIO_PULL_EN_DEFAULT = GPIO_PULL_ENABLE, } GPIO_PULL_EN; /* GPIO PULL-UP/PULL-DOWN*/ typedef enum { GPIO_PULL_UNSUPPORTED = -1, GPIO_PULL_NONE = 0, GPIO_PULL_UP = 1, GPIO_PULL_DOWN = 2, GPIO_PULL_MAX, GPIO_PULL_DEFAULT = GPIO_PULL_DOWN } GPIO_PULL; /* GPIO OUTPUT */ typedef enum { GPIO_OUT_UNSUPPORTED = -1, GPIO_OUT_ZERO = 0, GPIO_OUT_ONE = 1, GPIO_OUT_MAX, GPIO_OUT_DEFAULT = GPIO_OUT_ZERO, GPIO_DATA_OUT_DEFAULT = GPIO_OUT_ZERO, /*compatible with DCT*/ } GPIO_OUT; /* GPIO INPUT */ typedef enum { GPIO_IN_UNSUPPORTED = -1, GPIO_IN_ZERO = 0, GPIO_IN_ONE = 1, GPIO_IN_MAX, } GPIO_IN; typedef struct { uint32_t val; uint32_t set; uint32_t rst; uint32_t _align1; } VAL_REGS; typedef struct { VAL_REGS dir[6]; /*0x0000 ~ 0x005F: 96 bytes */ uint8_t rsv00[160]; /*0x0060 ~ 0x00FF: 160 bytes */ VAL_REGS dout[6]; /*0x0100 ~ 0x015F: 96 bytes */ uint8_t rsv01[160]; /*0x0160 ~ 0x01FF: 160 bytes */ VAL_REGS din[6]; /*0x0200 ~ 0x025F: 96 bytes */ uint8_t rsv02[160]; /*0x0260 ~ 0x02FF: 160 bytes */ VAL_REGS mode[23]; /*0x0300 ~ 0x046F: 368 bytes */ } GPIO_REGS; /* GPIO Driver interface */ /*direction*/ void mt_set_gpio_dir(int gpio, int direction); int mt_get_gpio_dir(int gpio); /*pull select*/ void mt_set_gpio_pull(int gpio, int pull); int mt_get_gpio_pull(int gpio); /*input/output*/ void mt_set_gpio_out(int gpio, int value); int mt_get_gpio_out(int gpio); int mt_get_gpio_in(int gpio); /*mode control*/ void mt_set_gpio_mode(int gpio, int mode); int mt_get_gpio_mode(int gpio); #endif /* MT_GPIO_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/gpio/mtgpio_cfg.h000066400000000000000000000066131355360272700255110ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MT_GPIO_CFG_H #define MT_GPIO_CFG_H #include #include #define IOCFG_0_BASE 0x11F20000 #define IOCFG_1_BASE 0x11E80000 #define IOCFG_2_BASE 0x11E70000 #define IOCFG_3_BASE 0x11E90000 #define IOCFG_4_BASE 0x11D30000 #define IOCFG_5_BASE 0x11D20000 #define IOCFG_6_BASE 0x11C50000 #define IOCFG_7_BASE 0x11F30000 typedef struct { int8_t offset; } PIN_offset; PIN_offset PULL_offset[] = { /* 0 */ {6}, /* 1 */ {7}, /* 2 */ {8}, /* 3 */ {9}, /* 4 */ {11}, /* 5 */ {12}, /* 6 */ {13}, /* 7 */ {14}, /* 8 */ {0}, /* 9 */ {26}, /* 10 */ {27}, /* 11 */ {10}, /* 12 */ {17}, /* 13 */ {6}, /* 14 */ {7}, /* 15 */ {8}, /* 16 */ {9}, /* 17 */ {10}, /* 18 */ {11}, /* 19 */ {12}, /* 20 */ {13}, /* 21 */ {14}, /* 22 */ {15}, /* 23 */ {16}, /* 24 */ {17}, /* 25 */ {18}, /* 26 */ {19}, /* 27 */ {20}, /* 28 */ {21}, /* 29 */ {-1}, /* 30 */ {-1}, /* 31 */ {-1}, /* 32 */ {-1}, /* 33 */ {-1}, /* 34 */ {-1}, /* 35 */ {-1}, /* 36 */ {-1}, /* 37 */ {-1}, /* 38 */ {-1}, /* 39 */ {-1}, /* 40 */ {-1}, /* 41 */ {-1}, /* 42 */ {-1}, /* 43 */ {8}, /* 44 */ {9}, /* 45 */ {10}, /* 46 */ {11}, /* 47 */ {12}, /* 48 */ {13}, /* 49 */ {14}, /* 50 */ {0}, /* 51 */ {1}, /* 52 */ {2}, /* 53 */ {3}, /* 54 */ {4}, /* 55 */ {5}, /* 56 */ {6}, /* 57 */ {7}, /* 58 */ {8}, /* 59 */ {9}, /* 60 */ {10}, /* 61 */ {0}, /* 62 */ {1}, /* 63 */ {2}, /* 64 */ {3}, /* 65 */ {4}, /* 66 */ {5}, /* 67 */ {6}, /* 68 */ {7}, /* 69 */ {8}, /* 70 */ {9}, /* 71 */ {10}, /* 72 */ {11}, /* 73 */ {12}, /* 74 */ {13}, /* 75 */ {14}, /* 76 */ {15}, /* 77 */ {16}, /* 78 */ {17}, /* 79 */ {18}, /* 80 */ {19}, /* 81 */ {20}, /* 82 */ {21}, /* 83 */ {22}, /* 84 */ {23}, /* 85 */ {24}, /* 86 */ {25}, /* 87 */ {26}, /* 88 */ {27}, /* 89 */ {24}, /* 90 */ {1}, /* 91 */ {-1}, /* 92 */ {-1}, /* 93 */ {-1}, /* 94 */ {-1}, /* 95 */ {15}, /* 96 */ {17}, /* 97 */ {18}, /* 98 */ {19}, /* 99 */ {20}, /* 100 */ {21}, /* 101 */ {22}, /* 102 */ {23}, /* 103 */ {28}, /* 104 */ {29}, /* 105 */ {30}, /* 106 */ {31}, /* 107 */ {0}, /* 108 */ {1}, /* 109 */ {2}, /* 110 */ {3}, /* 111 */ {4}, /* 112 */ {5}, /* 113 */ {6}, /* 114 */ {7}, /* 115 */ {8}, /* 116 */ {9}, /* 117 */ {10}, /* 118 */ {11}, /* 119 */ {12}, /* 120 */ {13}, /* 121 */ {14}, /* 122 */ {-1}, /* 123 */ {-1}, /* 124 */ {-1}, /* 125 */ {-1}, /* 126 */ {-1}, /* 127 */ {-1}, /* 128 */ {-1}, /* 129 */ {-1}, /* 130 */ {-1}, /* 131 */ {-1}, /* 132 */ {-1}, /* 133 */ {-1}, /* 134 */ {0}, /* 135 */ {1}, /* 136 */ {2}, /* 137 */ {3}, /* 138 */ {4}, /* 139 */ {5}, /* 140 */ {6}, /* 141 */ {7}, /* 142 */ {8}, /* 143 */ {9}, /* 144 */ {11}, /* 145 */ {12}, /* 146 */ {13}, /* 147 */ {14}, /* 148 */ {15}, /* 149 */ {16}, /* 150 */ {18}, /* 151 */ {19}, /* 152 */ {20}, /* 153 */ {21}, /* 154 */ {22}, /* 155 */ {23}, /* 156 */ {24}, /* 157 */ {25}, /* 158 */ {26}, /* 159 */ {27}, /* 160 */ {28}, /* 161 */ {0}, /* 162 */ {1}, /* 163 */ {2}, /* 164 */ {3}, /* 165 */ {4}, /* 166 */ {5}, /* 167 */ {11}, /* 168 */ {12}, /* 169 */ {13}, /* 170 */ {14}, /* 171 */ {15}, /* 172 */ {16}, /* 173 */ {17}, /* 174 */ {18}, /* 175 */ {19}, /* 176 */ {20}, /* 177 */ {10}, /* 178 */ {16}, /* 179 */ {25} }; #endif /* MT_GPIO_CFG_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/mcdi/000077500000000000000000000000001355360272700231725ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/mcdi/mtk_mcdi.c000066400000000000000000000130041355360272700251230ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include static inline uint32_t mcdi_mbox_read(uint32_t id) { return mmio_read_32(SSPM_MBOX_3_BASE + (id << 2)); } static inline void mcdi_mbox_write(uint32_t id, uint32_t val) { mmio_write_32(SSPM_MBOX_3_BASE + (id << 2), val); } void sspm_set_bootaddr(uint32_t bootaddr) { mcdi_mbox_write(MCDI_MBOX_BOOTADDR, bootaddr); } void sspm_cluster_pwr_off_notify(uint32_t cluster) { mcdi_mbox_write(MCDI_MBOX_CLUSTER_0_ATF_ACTION_DONE + cluster, 1); } void sspm_cluster_pwr_on_notify(uint32_t cluster) { mcdi_mbox_write(MCDI_MBOX_CLUSTER_0_ATF_ACTION_DONE + cluster, 0); } void sspm_standbywfi_irq_enable(uint32_t cpu_idx) { mmio_write_32(SSPM_CFGREG_ACAO_INT_SET, STANDBYWFI_EN(cpu_idx)); } uint32_t mcdi_avail_cpu_mask_read(void) { return mcdi_mbox_read(MCDI_MBOX_AVAIL_CPU_MASK); } uint32_t mcdi_avail_cpu_mask_write(uint32_t mask) { mcdi_mbox_write(MCDI_MBOX_AVAIL_CPU_MASK, mask); return mask; } uint32_t mcdi_avail_cpu_mask_set(uint32_t mask) { uint32_t m; m = mcdi_mbox_read(MCDI_MBOX_AVAIL_CPU_MASK); m |= mask; mcdi_mbox_write(MCDI_MBOX_AVAIL_CPU_MASK, m); return m; } uint32_t mcdi_avail_cpu_mask_clr(uint32_t mask) { uint32_t m; m = mcdi_mbox_read(MCDI_MBOX_AVAIL_CPU_MASK); m &= ~mask; mcdi_mbox_write(MCDI_MBOX_AVAIL_CPU_MASK, m); return m; } uint32_t mcdi_cpu_cluster_pwr_stat_read(void) { return mcdi_mbox_read(MCDI_MBOX_CPU_CLUSTER_PWR_STAT); } #define PAUSE_BIT 1 #define CLUSTER_OFF_OFS 20 #define CPU_OFF_OFS 24 #define CLUSTER_ON_OFS 4 #define CPU_ON_OFS 8 static uint32_t target_mask(int cluster, int cpu_idx, bool on) { uint32_t t = 0; if (on) { if (cluster >= 0) t |= BIT(cluster + CLUSTER_ON_OFS); if (cpu_idx >= 0) t |= BIT(cpu_idx + CPU_ON_OFS); } else { if (cluster >= 0) t |= BIT(cluster + CLUSTER_OFF_OFS); if (cpu_idx >= 0) t |= BIT(cpu_idx + CPU_OFF_OFS); } return t; } void mcdi_pause_clr(int cluster, int cpu_idx, bool on) { uint32_t tgt = target_mask(cluster, cpu_idx, on); uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION); m &= ~tgt; mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); } void mcdi_pause_set(int cluster, int cpu_idx, bool on) { uint32_t tgt = target_mask(cluster, cpu_idx, on); uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION); uint32_t tgtn = target_mask(-1, cpu_idx, !on); /* request on and off at the same time to ensure it can be paused */ m |= tgt | tgtn; mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); /* wait pause_ack */ while (!mcdi_mbox_read(MCDI_MBOX_PAUSE_ACK)) ; /* clear non-requested operation */ m &= ~tgtn; mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); } void mcdi_pause(void) { uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) | BIT(PAUSE_BIT); mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); /* wait pause_ack */ while (!mcdi_mbox_read(MCDI_MBOX_PAUSE_ACK)) ; } void mcdi_unpause(void) { uint32_t m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) & ~BIT(PAUSE_BIT); mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); } void mcdi_hotplug_wait_ack(int cluster, int cpu_idx, bool on) { uint32_t tgt = target_mask(cluster, cpu_idx, on); uint32_t ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); /* wait until ack */ while (!(ack & tgt)) ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); } void mcdi_hotplug_clr(int cluster, int cpu_idx, bool on) { uint32_t tgt = target_mask(cluster, cpu_idx, on); uint32_t tgt_cpu = target_mask(-1, cpu_idx, on); uint32_t cmd = mcdi_mbox_read(MCDI_MBOX_HP_CMD); uint32_t ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); if (!(cmd & tgt)) return; /* wait until ack */ while (!(ack & tgt_cpu)) ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); cmd &= ~tgt; mcdi_mbox_write(MCDI_MBOX_HP_CMD, cmd); } void mcdi_hotplug_set(int cluster, int cpu_idx, bool on) { uint32_t tgt = target_mask(cluster, cpu_idx, on); uint32_t tgt_cpu = target_mask(-1, cpu_idx, on); uint32_t cmd = mcdi_mbox_read(MCDI_MBOX_HP_CMD); uint32_t ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); if ((cmd & tgt) == tgt) return; /* wait until ack clear */ while (ack & tgt_cpu) ack = mcdi_mbox_read(MCDI_MBOX_HP_ACK); cmd |= tgt; mcdi_mbox_write(MCDI_MBOX_HP_CMD, cmd); } bool check_mcdi_ctl_stat(void) { uint32_t clk_regs[] = {0x100010ac, 0x100010c8}; uint32_t clk_mask[] = {0x00028000, 0x00000018}; uint32_t tgt = target_mask(0, 0, true); uint32_t m; int i; /* check clk status */ for (i = 0; i < ARRAY_SIZE(clk_regs); i++) { if (mmio_read_32(clk_regs[i]) & clk_mask[i]) { WARN("mcdi: clk check fail.\n"); return false; } } /* check mcdi cmd handling */ m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) | BIT(PAUSE_BIT); mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); i = 500; while (!mcdi_mbox_read(MCDI_MBOX_PAUSE_ACK) && --i > 0) udelay(10); m = mcdi_mbox_read(MCDI_MBOX_PAUSE_ACTION) & ~BIT(PAUSE_BIT); mcdi_mbox_write(MCDI_MBOX_PAUSE_ACTION, m); if (i == 0) { WARN("mcdi: pause_action fail.\n"); return false; } /* check mcdi cmd handling */ if (mcdi_mbox_read(MCDI_MBOX_HP_CMD) || mcdi_mbox_read(MCDI_MBOX_HP_ACK)) { WARN("mcdi: hp_cmd fail.\n"); return false; } mcdi_mbox_write(MCDI_MBOX_HP_CMD, tgt); i = 500; while ((mcdi_mbox_read(MCDI_MBOX_HP_ACK) & tgt) != tgt && --i > 0) udelay(10); mcdi_mbox_write(MCDI_MBOX_HP_CMD, 0); if (i == 0) { WARN("mcdi: hp_ack fail.\n"); return false; } return true; } void mcdi_init(void) { mcdi_avail_cpu_mask_write(0x01); /* cpu0 default on */ } trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/mcdi/mtk_mcdi.h000066400000000000000000000020361355360272700251330ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __MTK_MCDI_H__ #define __MTK_MCDI_H__ #include void sspm_set_bootaddr(uint32_t bootaddr); void sspm_standbywfi_irq_enable(uint32_t cpu_idx); void sspm_cluster_pwr_off_notify(uint32_t cluster); void sspm_cluster_pwr_on_notify(uint32_t cluster); uint32_t mcdi_avail_cpu_mask_read(void); uint32_t mcdi_avail_cpu_mask_write(uint32_t mask); uint32_t mcdi_avail_cpu_mask_set(uint32_t mask); uint32_t mcdi_avail_cpu_mask_clr(uint32_t mask); uint32_t mcdi_cpu_cluster_pwr_stat_read(void); void mcdi_pause(void); void mcdi_unpause(void); void mcdi_pause_set(int cluster, int cpu_idx, bool on); void mcdi_pause_clr(int cluster, int cpu_idx, bool on); void mcdi_hotplug_set(int cluster, int cpu_idx, bool on); void mcdi_hotplug_clr(int cluster, int cpu_idx, bool on); void mcdi_hotplug_wait_ack(int cluster, int cpu_idx, bool on); bool check_mcdi_ctl_stat(void); void mcdi_init(void); #endif /* __MTK_MCDI_H__ */ trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/mcsi/000077500000000000000000000000001355360272700232115ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/mcsi/mcsi.c000066400000000000000000000115201355360272700243070ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #define MAX_CLUSTERS 5 static unsigned long cci_base_addr; static unsigned int cci_cluster_ix_to_iface[MAX_CLUSTERS]; void mcsi_init(unsigned long cci_base, unsigned int num_cci_masters) { int i; assert(cci_base); assert(num_cci_masters < MAX_CLUSTERS); cci_base_addr = cci_base; for (i = 0; i < num_cci_masters; i++) cci_cluster_ix_to_iface[i] = SLAVE_IFACE_OFFSET(i); } void mcsi_cache_flush(void) { /* timeout is 10ms */ int timeout = 10000; /* to make flush by SF safe, need to disable BIU DCM */ mmio_clrbits_32(CCI_CLK_CTRL, 1 << 8); mmio_write_32(cci_base_addr + FLUSH_SF, 0x1); for (; timeout; timeout--, udelay(1)) { if ((mmio_read_32(cci_base_addr + FLUSH_SF) & 0x1) == 0x0) break; } if (!timeout) { INFO("SF lush timeout\n"); return; } /* enable BIU DCM as it was */ mmio_setbits_32(CCI_CLK_CTRL, 1 << 8); } static inline unsigned long get_slave_iface_base(unsigned long mpidr) { /* * We assume the TF topology code allocates affinity instances * consecutively from zero. * It is a programming error if this is called without initializing * the slave interface to use for this cluster. */ unsigned int cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; assert(cluster_id < MAX_CLUSTERS); assert(cci_cluster_ix_to_iface[cluster_id] != 0); return cci_base_addr + cci_cluster_ix_to_iface[cluster_id]; } void cci_enable_cluster_coherency(unsigned long mpidr) { unsigned long slave_base; unsigned int support_ability; unsigned int config = 0; unsigned int pending = 0; assert(cci_base_addr); slave_base = get_slave_iface_base(mpidr); support_ability = mmio_read_32(slave_base); pending = (mmio_read_32( cci_base_addr + SNP_PENDING_REG)) >> SNP_PENDING; while (pending) { pending = (mmio_read_32( cci_base_addr + SNP_PENDING_REG)) >> SNP_PENDING; } if (support_ability & SNP_SUPPORT) config |= SNOOP_EN_BIT; if (support_ability & DVM_SUPPORT) config |= DVM_EN_BIT; mmio_write_32(slave_base, support_ability | config); /* Wait for the dust to settle down */ while (mmio_read_32(cci_base_addr + SNP_PENDING_REG) >> SNP_PENDING) ; } #if ERRATA_MCSIB_SW #pragma weak mcsib_sw_workaround_main #endif void cci_disable_cluster_coherency(unsigned long mpidr) { unsigned long slave_base; unsigned int config = 0; assert(cci_base_addr); slave_base = get_slave_iface_base(mpidr); while (mmio_read_32(cci_base_addr + SNP_PENDING_REG) >> SNP_PENDING) ; config = mmio_read_32(slave_base); config &= ~(DVM_EN_BIT | SNOOP_EN_BIT); /* Disable Snoops and DVM messages */ mmio_write_32(slave_base, config); #if ERRATA_MCSIB_SW mcsib_sw_workaround_main(); #endif /* Wait for the dust to settle down */ while (mmio_read_32(cci_base_addr + SNP_PENDING_REG) >> SNP_PENDING) ; } void cci_secure_switch(unsigned int status) { unsigned int config; config = mmio_read_32(cci_base_addr + CENTRAL_CTRL_REG); if (status == NS_ACC) config |= SECURE_ACC_EN; else config &= ~SECURE_ACC_EN; mmio_write_32(cci_base_addr + CENTRAL_CTRL_REG, config); } void cci_pmu_secure_switch(unsigned int status) { unsigned int config; config = mmio_read_32(cci_base_addr + CENTRAL_CTRL_REG); if (status == NS_ACC) config |= PMU_SECURE_ACC_EN; else config &= ~PMU_SECURE_ACC_EN; mmio_write_32(cci_base_addr + CENTRAL_CTRL_REG, config); } void cci_init_sf(void) { while (mmio_read_32(cci_base_addr + SNP_PENDING_REG) >> SNP_PENDING) ; /* init sf1 */ mmio_write_32(cci_base_addr + SF_INIT_REG, TRIG_SF1_INIT); while (mmio_read_32(cci_base_addr + SF_INIT_REG) & TRIG_SF1_INIT) ; while (!(mmio_read_32(cci_base_addr + SF_INIT_REG) & SF1_INIT_DONE)) ; /* init sf2 */ mmio_write_32(cci_base_addr + SF_INIT_REG, TRIG_SF2_INIT); while (mmio_read_32(cci_base_addr + SF_INIT_REG) & TRIG_SF2_INIT) ; while (!(mmio_read_32(cci_base_addr + SF_INIT_REG) & SF2_INIT_DONE)) ; } void cci_interrupt_en(void) { mmio_setbits_32(cci_base_addr + CENTRAL_CTRL_REG, INT_EN); } unsigned long cci_reg_access(unsigned int op, unsigned long offset, unsigned long val) { unsigned long ret = 0; if ((cci_base_addr == 0) || (offset > MSCI_MEMORY_SZ)) panic(); switch (op) { case MCSI_REG_ACCESS_READ: ret = mmio_read_32(cci_base_addr + offset); break; case MCSI_REG_ACCESS_WRITE: mmio_write_32(cci_base_addr + offset, val); dsb(); break; case MCSI_REG_ACCESS_SET_BITMASK: mmio_setbits_32(cci_base_addr + offset, val); dsb(); break; case MCSI_REG_ACCESS_CLEAR_BITMASK: mmio_clrbits_32(cci_base_addr + offset, val); dsb(); break; default: break; } return ret; } trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/mcsi/mcsi.h000066400000000000000000000063641355360272700243260ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MCSI_H #define MCSI_H #define SLAVE_IFACE7_OFFSET 0x1700 #define SLAVE_IFACE6_OFFSET 0x1600 #define SLAVE_IFACE5_OFFSET 0x1500 #define SLAVE_IFACE4_OFFSET 0x1400 #define SLAVE_IFACE3_OFFSET 0x1300 #define SLAVE_IFACE2_OFFSET 0x1200 #define SLAVE_IFACE1_OFFSET 0x1100 #define SLAVE_IFACE0_OFFSET 0x1000 #define SLAVE_IFACE_OFFSET(index) (SLAVE_IFACE0_OFFSET + \ (0x100 * (index))) /* Control and ID register offsets */ #define CENTRAL_CTRL_REG 0x0 #define ERR_FLAG_REG 0x4 #define SF_INIT_REG 0x10 #define SF_CTRL_REG 0x14 #define DCM_CTRL_REG 0x18 #define ERR_FLAG2_REG 0x20 #define SNP_PENDING_REG 0x28 #define ACP_PENDING_REG 0x2c #define FLUSH_SF 0x500 #define SYS_CCE_CTRL 0x2000 #define MST1_CTRL 0x2100 #define MTS2_CTRL 0x2200 #define XBAR_ARAW_ARB 0x3000 #define XBAR_R_ARB 0x3004 /* Slave interface register offsets */ #define SNOOP_CTRL_REG 0x0 #define QOS_CTRL_REG 0x4 #define QOS_OVERRIDE_REG 0x8 #define QOS_TARGET_REG 0xc #define BD_CTRL_REG 0x40 /* Snoop Control register bit definitions */ #define DVM_SUPPORT (1U << 31) #define SNP_SUPPORT (1 << 30) #define SHAREABLE_OVWRT (1 << 2) #define DVM_EN_BIT (1 << 1) #define SNOOP_EN_BIT (1 << 0) #define SF2_INIT_DONE (1 << 17) #define SF1_INIT_DONE (1 << 16) #define TRIG_SF2_INIT (1 << 1) #define TRIG_SF1_INIT (1 << 0) /* Status register bit definitions */ #define SNP_PENDING 31 /* Status bit */ #define NS_ACC 1 #define S_ACC 0 /* Central control register bit definitions */ #define PMU_SECURE_ACC_EN (1 << 4) #define INT_EN (1 << 3) #define SECURE_ACC_EN (1 << 2) #define DVM_DIS (1 << 1) #define SNOOP_DIS (1 << 0) #define MSCI_MEMORY_SZ (0x10000) #define MCSI_REG_ACCESS_READ (0x0) #define MCSI_REG_ACCESS_WRITE (0x1) #define MCSI_REG_ACCESS_SET_BITMASK (0x2) #define MCSI_REG_ACCESS_CLEAR_BITMASK (0x3) #define NR_MAX_SLV (7) /* ICCS */ #define CACHE_INSTR_EN (1 << 2) #define IDLE_CACHE (1 << 3) #define USE_SHARED_CACHE (1 << 4) #define CACHE_SHARED_PRE_EN (1 << 5) #define CACHE_SHARED_POST_EN (1 << 6) #define ACP_PENDING_MASK (0x1007f) #define CCI_CLK_CTRL (MCUCFG_BASE + 0x660) #ifndef __ASSEMBLER__ #include #include /* Function declarations */ /* * The MCSI driver must be initialized with the base address of the * MCSI device in the platform memory map, and the cluster indices for * the MCSI slave interfaces 3 and 4 respectively. These are the fully * coherent ACE slave interfaces of MCSI. * The cluster indices must either be 0 or 1, corresponding to the level 1 * affinity instance of the mpidr representing the cluster. A negative cluster * index indicates that no cluster is present on that slave interface. */ void mcsi_init(unsigned long cci_base, unsigned int num_cci_masters); void mcsi_cache_flush(void); void cci_enable_cluster_coherency(unsigned long mpidr); void cci_disable_cluster_coherency(unsigned long mpidr); void cci_secure_switch(unsigned int ns); void cci_init_sf(void); unsigned long cci_reg_access(unsigned int op, unsigned long offset, unsigned long val); #endif /* __ASSEMBLER__ */ #endif /* MCSI_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/pmic/000077500000000000000000000000001355360272700232065ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/pmic/pmic.c000066400000000000000000000014301355360272700243000ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include void bcpu_enable(uint32_t en) { pwrap_write(PMIC_VPROC11_OP_EN, 0x1); if (en) pwrap_write(PMIC_VPROC11_CON0, 1); else pwrap_write(PMIC_VPROC11_CON0, 0); } void bcpu_sram_enable(uint32_t en) { pwrap_write(PMIC_VSRAM_PROC11_OP_EN, 0x1); if (en) pwrap_write(PMIC_VSRAM_PROC11_CON0, 1); else pwrap_write(PMIC_VSRAM_PROC11_CON0, 0); } void wk_pmic_enable_sdn_delay(void) { uint32_t con; pwrap_write(PMIC_TMA_KEY, 0x9CA7); pwrap_read(PMIC_PSEQ_ELR11, &con); con &= ~PMIC_RG_SDN_DLY_ENB; pwrap_write(PMIC_PSEQ_ELR11, con); pwrap_write(PMIC_TMA_KEY, 0); } void pmic_power_off(void) { pwrap_write(PMIC_PWRHOLD, 0x0); } trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/pmic/pmic.h000066400000000000000000000010701355360272700243050ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PMIC_H #define PMIC_H enum { PMIC_TMA_KEY = 0x03a8, PMIC_PWRHOLD = 0x0a08, PMIC_PSEQ_ELR11 = 0x0a62, PMIC_VPROC11_CON0 = 0x1388, PMIC_VPROC11_OP_EN = 0x1390, PMIC_VSRAM_PROC11_CON0 = 0x1b46, PMIC_VSRAM_PROC11_OP_EN = 0x1b4e }; enum { PMIC_RG_SDN_DLY_ENB = 1U << 10 }; /* external API */ void bcpu_enable(uint32_t en); void bcpu_sram_enable(uint32_t en); void wk_pmic_enable_sdn_delay(void); void pmic_power_off(void); #endif /* PMIC_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/pmic/pmic_wrap_init.h000066400000000000000000000044351355360272700263710ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PMIC_WRAP_INIT_H #define PMIC_WRAP_INIT_H #include #include /* external API */ int32_t pwrap_read(uint32_t adr, uint32_t *rdata); int32_t pwrap_write(uint32_t adr, uint32_t wdata); static struct mt8183_pmic_wrap_regs *const mtk_pwrap = (void *)PMIC_WRAP_BASE; /* timeout setting */ enum { TIMEOUT_READ = 255, /* us */ TIMEOUT_WAIT_IDLE = 255 /* us */ }; /* PMIC_WRAP registers */ struct mt8183_pmic_wrap_regs { uint32_t reserved[776]; uint32_t wacs2_cmd; uint32_t wacs2_rdata; uint32_t wacs2_vldclr; uint32_t reserved1[4]; }; enum { RDATA_WACS_RDATA_SHIFT = 0, RDATA_WACS_FSM_SHIFT = 16, RDATA_WACS_REQ_SHIFT = 19, RDATA_SYNC_IDLE_SHIFT, RDATA_INIT_DONE_SHIFT, RDATA_SYS_IDLE_SHIFT, }; enum { RDATA_WACS_RDATA_MASK = 0xffff, RDATA_WACS_FSM_MASK = 0x7, RDATA_WACS_REQ_MASK = 0x1, RDATA_SYNC_IDLE_MASK = 0x1, RDATA_INIT_DONE_MASK = 0x1, RDATA_SYS_IDLE_MASK = 0x1, }; /* WACS_FSM */ enum { WACS_FSM_IDLE = 0x00, WACS_FSM_REQ = 0x02, WACS_FSM_WFDLE = 0x04, WACS_FSM_WFVLDCLR = 0x06, WACS_INIT_DONE = 0x01, WACS_SYNC_IDLE = 0x01, WACS_SYNC_BUSY = 0x00 }; /* error information flag */ enum { E_PWR_INVALID_ARG = 1, E_PWR_INVALID_RW = 2, E_PWR_INVALID_ADDR = 3, E_PWR_INVALID_WDAT = 4, E_PWR_INVALID_OP_MANUAL = 5, E_PWR_NOT_IDLE_STATE = 6, E_PWR_NOT_INIT_DONE = 7, E_PWR_NOT_INIT_DONE_READ = 8, E_PWR_WAIT_IDLE_TIMEOUT = 9, E_PWR_WAIT_IDLE_TIMEOUT_READ = 10, E_PWR_INIT_SIDLY_FAIL = 11, E_PWR_RESET_TIMEOUT = 12, E_PWR_TIMEOUT = 13, E_PWR_INIT_RESET_SPI = 20, E_PWR_INIT_SIDLY = 21, E_PWR_INIT_REG_CLOCK = 22, E_PWR_INIT_ENABLE_PMIC = 23, E_PWR_INIT_DIO = 24, E_PWR_INIT_CIPHER = 25, E_PWR_INIT_WRITE_TEST = 26, E_PWR_INIT_ENABLE_CRC = 27, E_PWR_INIT_ENABLE_DEWRAP = 28, E_PWR_INIT_ENABLE_EVENT = 29, E_PWR_READ_TEST_FAIL = 30, E_PWR_WRITE_TEST_FAIL = 31, E_PWR_SWITCH_DIO = 32 }; #endif /* PMIC_WRAP_INIT_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/rtc/000077500000000000000000000000001355360272700230465ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/rtc/rtc.c000066400000000000000000000066551355360272700240160ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include static void RTC_Config_Interface(uint32_t addr, uint16_t data, uint16_t MASK, uint16_t SHIFT) { uint16_t pmic_reg = 0; pmic_reg = RTC_Read(addr); pmic_reg &= ~(MASK << SHIFT); pmic_reg |= (data << SHIFT); RTC_Write(addr, pmic_reg); } static void rtc_disable_2sec_reboot(void) { uint16_t reboot; reboot = (RTC_Read(RTC_AL_SEC) & ~RTC_BBPU_2SEC_EN) & ~RTC_BBPU_AUTO_PDN_SEL; RTC_Write(RTC_AL_SEC, reboot); RTC_Write_Trigger(); } static void rtc_xosc_write(uint16_t val, bool reload) { uint16_t bbpu; RTC_Write(RTC_OSC32CON, RTC_OSC32CON_UNLOCK1); rtc_busy_wait(); RTC_Write(RTC_OSC32CON, RTC_OSC32CON_UNLOCK2); rtc_busy_wait(); RTC_Write(RTC_OSC32CON, val); rtc_busy_wait(); if (reload) { bbpu = RTC_Read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD; RTC_Write(RTC_BBPU, bbpu); RTC_Write_Trigger(); } } static void rtc_enable_k_eosc(void) { uint16_t osc32; uint16_t rtc_eosc_cali_td = 8; /* eosc cali period time */ /* Truning on eosc cali mode clock */ RTC_Config_Interface(PMIC_RG_TOP_CON, 1, PMIC_RG_SRCLKEN_IN0_HW_MODE_MASK, PMIC_RG_SRCLKEN_IN0_HW_MODE_SHIFT); RTC_Config_Interface(PMIC_RG_TOP_CON, 1, PMIC_RG_SRCLKEN_IN1_HW_MODE_MASK, PMIC_RG_SRCLKEN_IN1_HW_MODE_SHIFT); RTC_Config_Interface(PMIC_RG_SCK_TOP_CKPDN_CON0, 0, PMIC_RG_RTC_EOSC32_CK_PDN_MASK, PMIC_RG_RTC_EOSC32_CK_PDN_SHIFT); switch (rtc_eosc_cali_td) { case 1: RTC_Config_Interface(PMIC_RG_EOSC_CALI_CON0, 0x3, PMIC_RG_EOSC_CALI_TD_MASK, PMIC_RG_EOSC_CALI_TD_SHIFT); break; case 2: RTC_Config_Interface(PMIC_RG_EOSC_CALI_CON0, 0x4, PMIC_RG_EOSC_CALI_TD_MASK, PMIC_RG_EOSC_CALI_TD_SHIFT); break; case 4: RTC_Config_Interface(PMIC_RG_EOSC_CALI_CON0, 0x5, PMIC_RG_EOSC_CALI_TD_MASK, PMIC_RG_EOSC_CALI_TD_SHIFT); break; case 16: RTC_Config_Interface(PMIC_RG_EOSC_CALI_CON0, 0x7, PMIC_RG_EOSC_CALI_TD_MASK, PMIC_RG_EOSC_CALI_TD_SHIFT); break; default: RTC_Config_Interface(PMIC_RG_EOSC_CALI_CON0, 0x6, PMIC_RG_EOSC_CALI_TD_MASK, PMIC_RG_EOSC_CALI_TD_SHIFT); break; } /* Switch the DCXO from 32k-less mode to RTC mode, * otherwise, EOSC cali will fail */ /* RTC mode will have only OFF mode and FPM */ RTC_Config_Interface(PMIC_RG_DCXO_CW02, 0, PMIC_RG_XO_EN32K_MAN_MASK, PMIC_RG_XO_EN32K_MAN_SHIFT); RTC_Write(RTC_BBPU, RTC_Read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD); RTC_Write_Trigger(); /* Enable K EOSC mode for normal power off and then plug out battery */ RTC_Write(RTC_AL_YEA, ((RTC_Read(RTC_AL_YEA) | RTC_K_EOSC_RSV_0) & (~RTC_K_EOSC_RSV_1)) | RTC_K_EOSC_RSV_2); RTC_Write_Trigger(); osc32 = RTC_Read(RTC_OSC32CON); rtc_xosc_write(osc32 | RTC_EMBCK_SRC_SEL, true); INFO("[RTC] RTC_enable_k_eosc\n"); } void rtc_power_off_sequence(void) { uint16_t bbpu; rtc_disable_2sec_reboot(); rtc_enable_k_eosc(); /* clear alarm */ bbpu = RTC_BBPU_KEY | RTC_BBPU_CLR | RTC_BBPU_PWREN; if (Writeif_unlock()) { RTC_Write(RTC_BBPU, bbpu); RTC_Write(RTC_AL_MASK, RTC_AL_MASK_DOW); RTC_Write_Trigger(); mdelay(1); bbpu = RTC_Read(RTC_BBPU) | RTC_BBPU_KEY | RTC_BBPU_RELOAD; RTC_Write(RTC_BBPU, bbpu); RTC_Write_Trigger(); INFO("[RTC] BBPU=0x%x, IRQ_EN=0x%x, AL_MSK=0x%x, AL_SEC=0x%x\n", RTC_Read(RTC_BBPU), RTC_Read(RTC_IRQ_EN), RTC_Read(RTC_AL_MASK), RTC_Read(RTC_AL_SEC)); } } trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/rtc/rtc.h000066400000000000000000000055341355360272700240160ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RTC_H #define RTC_H /* RTC registers */ enum { RTC_BBPU = 0x0588, RTC_IRQ_STA = 0x058A, RTC_IRQ_EN = 0x058C, RTC_CII_EN = 0x058E }; enum { RTC_AL_SEC = 0x05A0, RTC_AL_MIN = 0x05A2, RTC_AL_HOU = 0x05A4, RTC_AL_DOM = 0x05A6, RTC_AL_DOW = 0x05A8, RTC_AL_MTH = 0x05AA, RTC_AL_YEA = 0x05AC, RTC_AL_MASK = 0x0590 }; enum { RTC_OSC32CON = 0x05AE, RTC_CON = 0x05C4, RTC_WRTGR = 0x05C2 }; enum { RTC_PDN1 = 0x05B4, RTC_PDN2 = 0x05B6, RTC_SPAR0 = 0x05B8, RTC_SPAR1 = 0x05BA, RTC_PROT = 0x05BC, RTC_DIFF = 0x05BE, RTC_CALI = 0x05C0 }; enum { RTC_OSC32CON_UNLOCK1 = 0x1A57, RTC_OSC32CON_UNLOCK2 = 0x2B68 }; enum { RTC_PROT_UNLOCK1 = 0x586A, RTC_PROT_UNLOCK2 = 0x9136 }; enum { RTC_BBPU_PWREN = 1U << 0, RTC_BBPU_CLR = 1U << 1, RTC_BBPU_INIT = 1U << 2, RTC_BBPU_AUTO = 1U << 3, RTC_BBPU_CLRPKY = 1U << 4, RTC_BBPU_RELOAD = 1U << 5, RTC_BBPU_CBUSY = 1U << 6 }; enum { RTC_AL_MASK_SEC = 1U << 0, RTC_AL_MASK_MIN = 1U << 1, RTC_AL_MASK_HOU = 1U << 2, RTC_AL_MASK_DOM = 1U << 3, RTC_AL_MASK_DOW = 1U << 4, RTC_AL_MASK_MTH = 1U << 5, RTC_AL_MASK_YEA = 1U << 6 }; enum { RTC_BBPU_AUTO_PDN_SEL = 1U << 6, RTC_BBPU_2SEC_CK_SEL = 1U << 7, RTC_BBPU_2SEC_EN = 1U << 8, RTC_BBPU_2SEC_MODE = 0x3 << 9, RTC_BBPU_2SEC_STAT_CLEAR = 1U << 11, RTC_BBPU_2SEC_STAT_STA = 1U << 12 }; enum { RTC_BBPU_KEY = 0x43 << 8 }; enum { RTC_EMBCK_SRC_SEL = 1 << 8, RTC_EMBCK_SEL_MODE = 3 << 6, RTC_XOSC32_ENB = 1 << 5, RTC_REG_XOSC32_ENB = 1 << 15 }; enum { RTC_K_EOSC_RSV_0 = 1 << 8, RTC_K_EOSC_RSV_1 = 1 << 9, RTC_K_EOSC_RSV_2 = 1 << 10 }; /* PMIC TOP Register Definition */ enum { PMIC_RG_TOP_CON = 0x001E, PMIC_RG_TOP_CKPDN_CON1 = 0x0112, PMIC_RG_TOP_CKPDN_CON1_SET = 0x0114, PMIC_RG_TOP_CKPDN_CON1_CLR = 0x0116, PMIC_RG_TOP_CKSEL_CON0 = 0x0118, PMIC_RG_TOP_CKSEL_CON0_SET = 0x011A, PMIC_RG_TOP_CKSEL_CON0_CLR = 0x011C }; /* PMIC SCK Register Definition */ enum { PMIC_RG_SCK_TOP_CKPDN_CON0 = 0x051A, PMIC_RG_SCK_TOP_CKPDN_CON0_SET = 0x051C, PMIC_RG_SCK_TOP_CKPDN_CON0_CLR = 0x051E, PMIC_RG_EOSC_CALI_CON0 = 0x540 }; /* PMIC DCXO Register Definition */ enum { PMIC_RG_DCXO_CW00 = 0x0788, PMIC_RG_DCXO_CW02 = 0x0790 }; enum { PMIC_RG_SRCLKEN_IN0_HW_MODE_MASK = 0x1, PMIC_RG_SRCLKEN_IN0_HW_MODE_SHIFT = 1, PMIC_RG_SRCLKEN_IN1_HW_MODE_MASK = 0x1, PMIC_RG_SRCLKEN_IN1_HW_MODE_SHIFT = 3, PMIC_RG_RTC_EOSC32_CK_PDN_MASK = 0x1, PMIC_RG_RTC_EOSC32_CK_PDN_SHIFT = 2, PMIC_RG_EOSC_CALI_TD_MASK = 0x7, PMIC_RG_EOSC_CALI_TD_SHIFT = 5, PMIC_RG_XO_EN32K_MAN_MASK = 0x1, PMIC_RG_XO_EN32K_MAN_SHIFT = 0 }; /* external API */ uint16_t RTC_Read(uint32_t addr); void RTC_Write(uint32_t addr, uint16_t data); int32_t rtc_busy_wait(void); int32_t RTC_Write_Trigger(void); int32_t Writeif_unlock(void); void rtc_power_off_sequence(void); #endif /* RTC_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/spm/000077500000000000000000000000001355360272700230555ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/spm/spm.c000066400000000000000000000254211355360272700240240ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include DEFINE_BAKERY_LOCK(spm_lock); const char *wakeup_src_str[32] = { [0] = "R12_PCM_TIMER", [1] = "R12_SSPM_WDT_EVENT_B", [2] = "R12_KP_IRQ_B", [3] = "R12_APWDT_EVENT_B", [4] = "R12_APXGPT1_EVENT_B", [5] = "R12_CONN2AP_SPM_WAKEUP_B", [6] = "R12_EINT_EVENT_B", [7] = "R12_CONN_WDT_IRQ_B", [8] = "R12_CCIF0_EVENT_B", [9] = "R12_LOWBATTERY_IRQ_B", [10] = "R12_SSPM_SPM_IRQ_B", [11] = "R12_SCP_SPM_IRQ_B", [12] = "R12_SCP_WDT_EVENT_B", [13] = "R12_PCM_WDT_WAKEUP_B", [14] = "R12_USB_CDSC_B ", [15] = "R12_USB_POWERDWN_B", [16] = "R12_SYS_TIMER_EVENT_B", [17] = "R12_EINT_EVENT_SECURE_B", [18] = "R12_CCIF1_EVENT_B", [19] = "R12_UART0_IRQ_B", [20] = "R12_AFE_IRQ_MCU_B", [21] = "R12_THERM_CTRL_EVENT_B", [22] = "R12_SYS_CIRQ_IRQ_B", [23] = "R12_MD2AP_PEER_EVENT_B", [24] = "R12_CSYSPWREQ_B", [25] = "R12_MD1_WDT_B ", [26] = "R12_CLDMA_EVENT_B", [27] = "R12_SEJ_WDT_GPT_B", [28] = "R12_ALL_SSPM_WAKEUP_B", [29] = "R12_CPU_IRQ_B", [30] = "R12_CPU_WFI_AND_B" }; const char *spm_get_firmware_version(void) { return "DYNAMIC_SPM_FW_VERSION"; } void spm_lock_init(void) { bakery_lock_init(&spm_lock); } void spm_lock_get(void) { bakery_lock_get(&spm_lock); } void spm_lock_release(void) { bakery_lock_release(&spm_lock); } void spm_set_bootaddr(unsigned long bootaddr) { /* initialize core4~7 boot entry address */ mmio_write_32(SW2SPM_MAILBOX_3, bootaddr); } void spm_set_cpu_status(int cpu) { if (cpu >= 0 && cpu < 4) { mmio_write_32(ROOT_CPUTOP_ADDR, 0x10006204); mmio_write_32(ROOT_CORE_ADDR, 0x10006208 + (cpu * 0x4)); } else if (cpu >= 4 && cpu < 8) { mmio_write_32(ROOT_CPUTOP_ADDR, 0x10006218); mmio_write_32(ROOT_CORE_ADDR, 0x1000621c + ((cpu - 4) * 0x4)); } else { ERROR("%s: error cpu number %d\n", __func__, cpu); } } void spm_set_power_control(const struct pwr_ctrl *pwrctrl) { mmio_write_32(SPM_AP_STANDBY_CON, ((pwrctrl->wfi_op & 0x1) << 0) | ((pwrctrl->mp0_cputop_idle_mask & 0x1) << 1) | ((pwrctrl->mp1_cputop_idle_mask & 0x1) << 2) | ((pwrctrl->mcusys_idle_mask & 0x1) << 4) | ((pwrctrl->mm_mask_b & 0x3) << 16) | ((pwrctrl->md_ddr_en_0_dbc_en & 0x1) << 18) | ((pwrctrl->md_ddr_en_1_dbc_en & 0x1) << 19) | ((pwrctrl->md_mask_b & 0x3) << 20) | ((pwrctrl->sspm_mask_b & 0x1) << 22) | ((pwrctrl->scp_mask_b & 0x1) << 23) | ((pwrctrl->srcclkeni_mask_b & 0x1) << 24) | ((pwrctrl->md_apsrc_1_sel & 0x1) << 25) | ((pwrctrl->md_apsrc_0_sel & 0x1) << 26) | ((pwrctrl->conn_ddr_en_dbc_en & 0x1) << 27) | ((pwrctrl->conn_mask_b & 0x1) << 28) | ((pwrctrl->conn_apsrc_sel & 0x1) << 29)); mmio_write_32(SPM_SRC_REQ, ((pwrctrl->spm_apsrc_req & 0x1) << 0) | ((pwrctrl->spm_f26m_req & 0x1) << 1) | ((pwrctrl->spm_infra_req & 0x1) << 3) | ((pwrctrl->spm_vrf18_req & 0x1) << 4) | ((pwrctrl->spm_ddren_req & 0x1) << 7) | ((pwrctrl->spm_rsv_src_req & 0x7) << 8) | ((pwrctrl->spm_ddren_2_req & 0x1) << 11) | ((pwrctrl->cpu_md_dvfs_sop_force_on & 0x1) << 16)); mmio_write_32(SPM_SRC_MASK, ((pwrctrl->csyspwreq_mask & 0x1) << 0) | ((pwrctrl->ccif0_md_event_mask_b & 0x1) << 1) | ((pwrctrl->ccif0_ap_event_mask_b & 0x1) << 2) | ((pwrctrl->ccif1_md_event_mask_b & 0x1) << 3) | ((pwrctrl->ccif1_ap_event_mask_b & 0x1) << 4) | ((pwrctrl->ccif2_md_event_mask_b & 0x1) << 5) | ((pwrctrl->ccif2_ap_event_mask_b & 0x1) << 6) | ((pwrctrl->ccif3_md_event_mask_b & 0x1) << 7) | ((pwrctrl->ccif3_ap_event_mask_b & 0x1) << 8) | ((pwrctrl->md_srcclkena_0_infra_mask_b & 0x1) << 9) | ((pwrctrl->md_srcclkena_1_infra_mask_b & 0x1) << 10) | ((pwrctrl->conn_srcclkena_infra_mask_b & 0x1) << 11) | ((pwrctrl->ufs_infra_req_mask_b & 0x1) << 12) | ((pwrctrl->srcclkeni_infra_mask_b & 0x1) << 13) | ((pwrctrl->md_apsrc_req_0_infra_mask_b & 0x1) << 14) | ((pwrctrl->md_apsrc_req_1_infra_mask_b & 0x1) << 15) | ((pwrctrl->conn_apsrcreq_infra_mask_b & 0x1) << 16) | ((pwrctrl->ufs_srcclkena_mask_b & 0x1) << 17) | ((pwrctrl->md_vrf18_req_0_mask_b & 0x1) << 18) | ((pwrctrl->md_vrf18_req_1_mask_b & 0x1) << 19) | ((pwrctrl->ufs_vrf18_req_mask_b & 0x1) << 20) | ((pwrctrl->gce_vrf18_req_mask_b & 0x1) << 21) | ((pwrctrl->conn_infra_req_mask_b & 0x1) << 22) | ((pwrctrl->gce_apsrc_req_mask_b & 0x1) << 23) | ((pwrctrl->disp0_apsrc_req_mask_b & 0x1) << 24) | ((pwrctrl->disp1_apsrc_req_mask_b & 0x1) << 25) | ((pwrctrl->mfg_req_mask_b & 0x1) << 26) | ((pwrctrl->vdec_req_mask_b & 0x1) << 27)); mmio_write_32(SPM_SRC2_MASK, ((pwrctrl->md_ddr_en_0_mask_b & 0x1) << 0) | ((pwrctrl->md_ddr_en_1_mask_b & 0x1) << 1) | ((pwrctrl->conn_ddr_en_mask_b & 0x1) << 2) | ((pwrctrl->ddren_sspm_apsrc_req_mask_b & 0x1) << 3) | ((pwrctrl->ddren_scp_apsrc_req_mask_b & 0x1) << 4) | ((pwrctrl->disp0_ddren_mask_b & 0x1) << 5) | ((pwrctrl->disp1_ddren_mask_b & 0x1) << 6) | ((pwrctrl->gce_ddren_mask_b & 0x1) << 7) | ((pwrctrl->ddren_emi_self_refresh_ch0_mask_b & 0x1) << 8) | ((pwrctrl->ddren_emi_self_refresh_ch1_mask_b & 0x1) << 9)); mmio_write_32(SPM_WAKEUP_EVENT_MASK, ((pwrctrl->spm_wakeup_event_mask & 0xffffffff) << 0)); mmio_write_32(SPM_WAKEUP_EVENT_EXT_MASK, ((pwrctrl->spm_wakeup_event_ext_mask & 0xffffffff) << 0)); mmio_write_32(SPM_SRC3_MASK, ((pwrctrl->md_ddr_en_2_0_mask_b & 0x1) << 0) | ((pwrctrl->md_ddr_en_2_1_mask_b & 0x1) << 1) | ((pwrctrl->conn_ddr_en_2_mask_b & 0x1) << 2) | ((pwrctrl->ddren2_sspm_apsrc_req_mask_b & 0x1) << 3) | ((pwrctrl->ddren2_scp_apsrc_req_mask_b & 0x1) << 4) | ((pwrctrl->disp0_ddren2_mask_b & 0x1) << 5) | ((pwrctrl->disp1_ddren2_mask_b & 0x1) << 6) | ((pwrctrl->gce_ddren2_mask_b & 0x1) << 7) | ((pwrctrl->ddren2_emi_self_refresh_ch0_mask_b & 0x1) << 8) | ((pwrctrl->ddren2_emi_self_refresh_ch1_mask_b & 0x1) << 9)); mmio_write_32(MP0_CPU0_WFI_EN, ((pwrctrl->mp0_cpu0_wfi_en & 0x1) << 0)); mmio_write_32(MP0_CPU1_WFI_EN, ((pwrctrl->mp0_cpu1_wfi_en & 0x1) << 0)); mmio_write_32(MP0_CPU2_WFI_EN, ((pwrctrl->mp0_cpu2_wfi_en & 0x1) << 0)); mmio_write_32(MP0_CPU3_WFI_EN, ((pwrctrl->mp0_cpu3_wfi_en & 0x1) << 0)); mmio_write_32(MP1_CPU0_WFI_EN, ((pwrctrl->mp1_cpu0_wfi_en & 0x1) << 0)); mmio_write_32(MP1_CPU1_WFI_EN, ((pwrctrl->mp1_cpu1_wfi_en & 0x1) << 0)); mmio_write_32(MP1_CPU2_WFI_EN, ((pwrctrl->mp1_cpu2_wfi_en & 0x1) << 0)); mmio_write_32(MP1_CPU3_WFI_EN, ((pwrctrl->mp1_cpu3_wfi_en & 0x1) << 0)); } void spm_disable_pcm_timer(void) { mmio_clrsetbits_32(PCM_CON1, PCM_TIMER_EN_LSB, SPM_REGWR_CFG_KEY); } void spm_set_wakeup_event(const struct pwr_ctrl *pwrctrl) { uint32_t val, mask, isr; val = pwrctrl->timer_val ? pwrctrl->timer_val : PCM_TIMER_MAX; mmio_write_32(PCM_TIMER_VAL, val); mmio_setbits_32(PCM_CON1, SPM_REGWR_CFG_KEY | PCM_TIMER_EN_LSB); mask = pwrctrl->wake_src; if (pwrctrl->csyspwreq_mask) mask &= ~WAKE_SRC_R12_CSYSPWREQ_B; mmio_write_32(SPM_WAKEUP_EVENT_MASK, ~mask); isr = mmio_read_32(SPM_IRQ_MASK) & SPM_TWAM_IRQ_MASK_LSB; mmio_write_32(SPM_IRQ_MASK, isr | ISRM_RET_IRQ_AUX); } void spm_set_pcm_flags(const struct pwr_ctrl *pwrctrl) { mmio_write_32(SPM_SW_FLAG, pwrctrl->pcm_flags); mmio_write_32(SPM_SW_RSV_2, pwrctrl->pcm_flags1); } void spm_set_pcm_wdt(int en) { if (en) { mmio_clrsetbits_32(PCM_CON1, PCM_WDT_WAKE_MODE_LSB, SPM_REGWR_CFG_KEY); if (mmio_read_32(PCM_TIMER_VAL) > PCM_TIMER_MAX) mmio_write_32(PCM_TIMER_VAL, PCM_TIMER_MAX); mmio_write_32(PCM_WDT_VAL, mmio_read_32(PCM_TIMER_VAL) + PCM_WDT_TIMEOUT); mmio_setbits_32(PCM_CON1, SPM_REGWR_CFG_KEY | PCM_WDT_EN_LSB); } else { mmio_clrsetbits_32(PCM_CON1, PCM_WDT_EN_LSB, SPM_REGWR_CFG_KEY); } } void spm_send_cpu_wakeup_event(void) { mmio_write_32(PCM_REG_DATA_INI, 0); mmio_write_32(SPM_CPU_WAKEUP_EVENT, 1); } void spm_get_wakeup_status(struct wake_status *wakesta) { wakesta->assert_pc = mmio_read_32(PCM_REG_DATA_INI); wakesta->r12 = mmio_read_32(SPM_SW_RSV_0); wakesta->r12_ext = mmio_read_32(PCM_REG12_EXT_DATA); wakesta->raw_sta = mmio_read_32(SPM_WAKEUP_STA); wakesta->raw_ext_sta = mmio_read_32(SPM_WAKEUP_EXT_STA); wakesta->wake_misc = mmio_read_32(SPM_BSI_D0_SR); wakesta->timer_out = mmio_read_32(SPM_BSI_D1_SR); wakesta->r13 = mmio_read_32(PCM_REG13_DATA); wakesta->idle_sta = mmio_read_32(SUBSYS_IDLE_STA); wakesta->req_sta = mmio_read_32(SRC_REQ_STA); wakesta->sw_flag = mmio_read_32(SPM_SW_FLAG); wakesta->sw_flag1 = mmio_read_32(SPM_SW_RSV_2); wakesta->r15 = mmio_read_32(PCM_REG15_DATA); wakesta->debug_flag = mmio_read_32(SPM_SW_DEBUG); wakesta->debug_flag1 = mmio_read_32(WDT_LATCH_SPARE0_FIX); wakesta->event_reg = mmio_read_32(SPM_BSI_D2_SR); wakesta->isr = mmio_read_32(SPM_IRQ_STA); } void spm_clean_after_wakeup(void) { mmio_write_32(SPM_SW_RSV_0, mmio_read_32(SPM_WAKEUP_STA) | mmio_read_32(SPM_SW_RSV_0)); mmio_write_32(SPM_CPU_WAKEUP_EVENT, 0); mmio_write_32(SPM_WAKEUP_EVENT_MASK, ~0); mmio_setbits_32(SPM_IRQ_MASK, ISRM_ALL_EXC_TWAM); mmio_write_32(SPM_IRQ_STA, ISRC_ALL_EXC_TWAM); mmio_write_32(SPM_SWINT_CLR, PCM_SW_INT_ALL); } void spm_output_wake_reason(struct wake_status *wakesta, const char *scenario) { uint32_t i; if (wakesta->assert_pc != 0) { INFO("%s: PCM ASSERT AT %u, ULPOSC_CON = 0x%x\n", scenario, wakesta->assert_pc, mmio_read_32(ULPOSC_CON)); goto spm_debug_flags; } for (i = 0; i <= 31; i++) { if (wakesta->r12 & (1U << i)) { INFO("%s: wake up by %s, timer_out = %u\n", scenario, wakeup_src_str[i], wakesta->timer_out); break; } } spm_debug_flags: INFO("r15 = 0x%x, r13 = 0x%x, debug_flag = 0x%x 0x%x\n", wakesta->r15, wakesta->r13, wakesta->debug_flag, wakesta->debug_flag1); INFO("sw_flag = 0x%x 0x%x, r12 = 0x%x, r12_ext = 0x%x\n", wakesta->sw_flag, wakesta->sw_flag1, wakesta->r12, wakesta->r12_ext); INFO("idle_sta = 0x%x, req_sta = 0x%x, event_reg = 0x%x\n", wakesta->idle_sta, wakesta->req_sta, wakesta->event_reg); INFO("isr = 0x%x, raw_sta = 0x%x, raw_ext_sta = 0x%x\n", wakesta->isr, wakesta->raw_sta, wakesta->raw_ext_sta); INFO("wake_misc = 0x%x\n", wakesta->wake_misc); } void spm_boot_init(void) { NOTICE("%s() start\n", __func__); spm_lock_init(); mt_spm_pmic_wrap_set_phase(PMIC_WRAP_PHASE_ALLINONE); NOTICE("%s() end\n", __func__); } trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/spm/spm.h000066400000000000000000004262271355360272700240420ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPM_H #define SPM_H /************************************** * Define and Declare **************************************/ #define POWERON_CONFIG_EN (SPM_BASE + 0x000) #define SPM_POWER_ON_VAL0 (SPM_BASE + 0x004) #define SPM_POWER_ON_VAL1 (SPM_BASE + 0x008) #define SPM_CLK_CON (SPM_BASE + 0x00C) #define SPM_CLK_SETTLE (SPM_BASE + 0x010) #define SPM_AP_STANDBY_CON (SPM_BASE + 0x014) #define PCM_CON0 (SPM_BASE + 0x018) #define PCM_CON1 (SPM_BASE + 0x01C) #define PCM_IM_PTR (SPM_BASE + 0x020) #define PCM_IM_LEN (SPM_BASE + 0x024) #define PCM_REG_DATA_INI (SPM_BASE + 0x028) #define PCM_PWR_IO_EN (SPM_BASE + 0x02C) #define PCM_TIMER_VAL (SPM_BASE + 0x030) #define PCM_WDT_VAL (SPM_BASE + 0x034) #define PCM_IM_HOST_RW_PTR (SPM_BASE + 0x038) #define PCM_IM_HOST_RW_DAT (SPM_BASE + 0x03C) #define PCM_EVENT_VECTOR0 (SPM_BASE + 0x040) #define PCM_EVENT_VECTOR1 (SPM_BASE + 0x044) #define PCM_EVENT_VECTOR2 (SPM_BASE + 0x048) #define PCM_EVENT_VECTOR3 (SPM_BASE + 0x04C) #define PCM_EVENT_VECTOR4 (SPM_BASE + 0x050) #define PCM_EVENT_VECTOR5 (SPM_BASE + 0x054) #define PCM_EVENT_VECTOR6 (SPM_BASE + 0x058) #define PCM_EVENT_VECTOR7 (SPM_BASE + 0x05C) #define PCM_EVENT_VECTOR8 (SPM_BASE + 0x060) #define PCM_EVENT_VECTOR9 (SPM_BASE + 0x064) #define PCM_EVENT_VECTOR10 (SPM_BASE + 0x068) #define PCM_EVENT_VECTOR11 (SPM_BASE + 0x06C) #define PCM_EVENT_VECTOR12 (SPM_BASE + 0x070) #define PCM_EVENT_VECTOR13 (SPM_BASE + 0x074) #define PCM_EVENT_VECTOR14 (SPM_BASE + 0x078) #define PCM_EVENT_VECTOR15 (SPM_BASE + 0x07C) #define PCM_EVENT_VECTOR_EN (SPM_BASE + 0x080) #define SPM_SRAM_RSV_CON (SPM_BASE + 0x088) #define SPM_SWINT (SPM_BASE + 0x08C) #define SPM_SWINT_SET (SPM_BASE + 0x090) #define SPM_SWINT_CLR (SPM_BASE + 0x094) #define SPM_SCP_MAILBOX (SPM_BASE + 0x098) #define SCP_SPM_MAILBOX (SPM_BASE + 0x09C) #define SPM_TWAM_CON (SPM_BASE + 0x0A0) #define SPM_TWAM_WINDOW_LEN (SPM_BASE + 0x0A4) #define SPM_TWAM_IDLE_SEL (SPM_BASE + 0x0A8) #define SPM_SCP_IRQ (SPM_BASE + 0x0AC) #define SPM_CPU_WAKEUP_EVENT (SPM_BASE + 0x0B0) #define SPM_IRQ_MASK (SPM_BASE + 0x0B4) #define SPM_SRC_REQ (SPM_BASE + 0x0B8) #define SPM_SRC_MASK (SPM_BASE + 0x0BC) #define SPM_SRC2_MASK (SPM_BASE + 0x0C0) #define SPM_WAKEUP_EVENT_MASK (SPM_BASE + 0x0C4) #define SPM_WAKEUP_EVENT_EXT_MASK (SPM_BASE + 0x0C8) #define SPM_TWAM_EVENT_CLEAR (SPM_BASE + 0x0CC) #define SCP_CLK_CON (SPM_BASE + 0x0D0) #define PCM_DEBUG_CON (SPM_BASE + 0x0D4) #define DDR_EN_DBC_LEN (SPM_BASE + 0x0D8) #define AHB_BUS_CON (SPM_BASE + 0x0DC) #define SPM_SRC3_MASK (SPM_BASE + 0x0E0) #define DDR_EN_EMI_DBC_CON (SPM_BASE + 0x0E4) #define SSPM_CLK_CON (SPM_BASE + 0x0E8) #define PCM_REG0_DATA (SPM_BASE + 0x100) #define PCM_REG1_DATA (SPM_BASE + 0x104) #define PCM_REG2_DATA (SPM_BASE + 0x108) #define PCM_REG3_DATA (SPM_BASE + 0x10C) #define PCM_REG4_DATA (SPM_BASE + 0x110) #define PCM_REG5_DATA (SPM_BASE + 0x114) #define PCM_REG6_DATA (SPM_BASE + 0x118) #define PCM_REG7_DATA (SPM_BASE + 0x11C) #define PCM_REG8_DATA (SPM_BASE + 0x120) #define PCM_REG9_DATA (SPM_BASE + 0x124) #define PCM_REG10_DATA (SPM_BASE + 0x128) #define PCM_REG11_DATA (SPM_BASE + 0x12C) #define PCM_REG12_DATA (SPM_BASE + 0x130) #define PCM_REG13_DATA (SPM_BASE + 0x134) #define PCM_REG14_DATA (SPM_BASE + 0x138) #define PCM_REG15_DATA (SPM_BASE + 0x13C) #define PCM_REG12_MASK_B_STA (SPM_BASE + 0x140) #define PCM_REG12_EXT_DATA (SPM_BASE + 0x144) #define PCM_REG12_EXT_MASK_B_STA (SPM_BASE + 0x148) #define PCM_EVENT_REG_STA (SPM_BASE + 0x14C) #define PCM_TIMER_OUT (SPM_BASE + 0x150) #define PCM_WDT_OUT (SPM_BASE + 0x154) #define SPM_IRQ_STA (SPM_BASE + 0x158) #define SPM_WAKEUP_STA (SPM_BASE + 0x15C) #define SPM_WAKEUP_EXT_STA (SPM_BASE + 0x160) #define SPM_WAKEUP_MISC (SPM_BASE + 0x164) #define BUS_PROTECT_RDY (SPM_BASE + 0x168) #define BUS_PROTECT2_RDY (SPM_BASE + 0x16C) #define SUBSYS_IDLE_STA (SPM_BASE + 0x170) #define CPU_IDLE_STA (SPM_BASE + 0x174) #define PCM_FSM_STA (SPM_BASE + 0x178) #define SRC_REQ_STA (SPM_BASE + 0x17C) #define PWR_STATUS (SPM_BASE + 0x180) #define PWR_STATUS_2ND (SPM_BASE + 0x184) #define CPU_PWR_STATUS (SPM_BASE + 0x188) #define CPU_PWR_STATUS_2ND (SPM_BASE + 0x18C) #define MISC_STA (SPM_BASE + 0x190) #define SPM_SRC_RDY_STA (SPM_BASE + 0x194) #define DRAMC_DBG_LATCH (SPM_BASE + 0x19C) #define SPM_TWAM_LAST_STA0 (SPM_BASE + 0x1A0) #define SPM_TWAM_LAST_STA1 (SPM_BASE + 0x1A4) #define SPM_TWAM_LAST_STA2 (SPM_BASE + 0x1A8) #define SPM_TWAM_LAST_STA3 (SPM_BASE + 0x1AC) #define SPM_TWAM_CURR_STA0 (SPM_BASE + 0x1B0) #define SPM_TWAM_CURR_STA1 (SPM_BASE + 0x1B4) #define SPM_TWAM_CURR_STA2 (SPM_BASE + 0x1B8) #define SPM_TWAM_CURR_STA3 (SPM_BASE + 0x1BC) #define SPM_TWAM_TIMER_OUT (SPM_BASE + 0x1C0) #define SPM_DVFS_STA (SPM_BASE + 0x1C8) #define BUS_PROTECT3_RDY (SPM_BASE + 0x1CC) #define SRC_DDREN_STA (SPM_BASE + 0x1E0) #define MCU_PWR_CON (SPM_BASE + 0x200) #define MP0_CPUTOP_PWR_CON (SPM_BASE + 0x204) #define MP0_CPU0_PWR_CON (SPM_BASE + 0x208) #define MP0_CPU1_PWR_CON (SPM_BASE + 0x20C) #define MP0_CPU2_PWR_CON (SPM_BASE + 0x210) #define MP0_CPU3_PWR_CON (SPM_BASE + 0x214) #define MP1_CPUTOP_PWR_CON (SPM_BASE + 0x218) #define MP1_CPU0_PWR_CON (SPM_BASE + 0x21C) #define MP1_CPU1_PWR_CON (SPM_BASE + 0x220) #define MP1_CPU2_PWR_CON (SPM_BASE + 0x224) #define MP1_CPU3_PWR_CON (SPM_BASE + 0x228) #define MP0_CPUTOP_L2_PDN (SPM_BASE + 0x240) #define MP0_CPUTOP_L2_SLEEP_B (SPM_BASE + 0x244) #define MP0_CPU0_L1_PDN (SPM_BASE + 0x248) #define MP0_CPU1_L1_PDN (SPM_BASE + 0x24C) #define MP0_CPU2_L1_PDN (SPM_BASE + 0x250) #define MP0_CPU3_L1_PDN (SPM_BASE + 0x254) #define MP1_CPUTOP_L2_PDN (SPM_BASE + 0x258) #define MP1_CPUTOP_L2_SLEEP_B (SPM_BASE + 0x25C) #define MP1_CPU0_L1_PDN (SPM_BASE + 0x260) #define MP1_CPU1_L1_PDN (SPM_BASE + 0x264) #define MP1_CPU2_L1_PDN (SPM_BASE + 0x268) #define MP1_CPU3_L1_PDN (SPM_BASE + 0x26C) #define CPU_EXT_BUCK_ISO (SPM_BASE + 0x290) #define DUMMY1_PWR_CON (SPM_BASE + 0x2B0) #define BYPASS_SPMC (SPM_BASE + 0x2B4) #define SPMC_DORMANT_ENABLE (SPM_BASE + 0x2B8) #define ARMPLL_CLK_CON (SPM_BASE + 0x2BC) #define SPMC_IN_RET (SPM_BASE + 0x2C0) #define VDE_PWR_CON (SPM_BASE + 0x300) #define VEN_PWR_CON (SPM_BASE + 0x304) #define ISP_PWR_CON (SPM_BASE + 0x308) #define DIS_PWR_CON (SPM_BASE + 0x30C) #define MFG_CORE1_PWR_CON (SPM_BASE + 0x310) #define AUDIO_PWR_CON (SPM_BASE + 0x314) #define IFR_PWR_CON (SPM_BASE + 0x318) #define DPY_PWR_CON (SPM_BASE + 0x31C) #define MD1_PWR_CON (SPM_BASE + 0x320) #define VPU_TOP_PWR_CON (SPM_BASE + 0x324) #define CONN_PWR_CON (SPM_BASE + 0x32C) #define VPU_CORE2_PWR_CON (SPM_BASE + 0x330) #define MFG_ASYNC_PWR_CON (SPM_BASE + 0x334) #define MFG_PWR_CON (SPM_BASE + 0x338) #define VPU_CORE0_PWR_CON (SPM_BASE + 0x33C) #define VPU_CORE1_PWR_CON (SPM_BASE + 0x340) #define CAM_PWR_CON (SPM_BASE + 0x344) #define MFG_2D_PWR_CON (SPM_BASE + 0x348) #define MFG_CORE0_PWR_CON (SPM_BASE + 0x34C) #define SYSRAM_CON (SPM_BASE + 0x350) #define SYSROM_CON (SPM_BASE + 0x354) #define SSPM_SRAM_CON (SPM_BASE + 0x358) #define SCP_SRAM_CON (SPM_BASE + 0x35C) #define UFS_SRAM_CON (SPM_BASE + 0x36C) #define DUMMY_SRAM_CON (SPM_BASE + 0x380) #define MD_EXT_BUCK_ISO_CON (SPM_BASE + 0x390) #define MD_SRAM_ISO_CON (SPM_BASE + 0x394) #define MD_EXTRA_PWR_CON (SPM_BASE + 0x398) #define EXT_BUCK_CON (SPM_BASE + 0x3A0) #define MBIST_EFUSE_REPAIR_ACK_STA (SPM_BASE + 0x3D0) #define SPM_DVFS_CON (SPM_BASE + 0x400) #define SPM_MDBSI_CON (SPM_BASE + 0x404) #define SPM_MAS_PAUSE_MASK_B (SPM_BASE + 0x408) #define SPM_MAS_PAUSE2_MASK_B (SPM_BASE + 0x40C) #define SPM_BSI_GEN (SPM_BASE + 0x410) #define SPM_BSI_EN_SR (SPM_BASE + 0x414) #define SPM_BSI_CLK_SR (SPM_BASE + 0x418) #define SPM_BSI_D0_SR (SPM_BASE + 0x41C) #define SPM_BSI_D1_SR (SPM_BASE + 0x420) #define SPM_BSI_D2_SR (SPM_BASE + 0x424) #define SPM_AP_SEMA (SPM_BASE + 0x428) #define SPM_SPM_SEMA (SPM_BASE + 0x42C) #define AP_MDSRC_REQ (SPM_BASE + 0x430) #define SPM2MD_DVFS_CON (SPM_BASE + 0x438) #define MD2SPM_DVFS_CON (SPM_BASE + 0x43C) #define DRAMC_DPY_CLK_SW_CON_RSV (SPM_BASE + 0x440) #define DPY_LP_CON (SPM_BASE + 0x444) #define CPU_DVFS_REQ (SPM_BASE + 0x448) #define SPM_PLL_CON (SPM_BASE + 0x44C) #define SPM_EMI_BW_MODE (SPM_BASE + 0x450) #define AP2MD_PEER_WAKEUP (SPM_BASE + 0x454) #define ULPOSC_CON (SPM_BASE + 0x458) #define SPM2MM_CON (SPM_BASE + 0x45C) #define DRAMC_DPY_CLK_SW_CON_SEL (SPM_BASE + 0x460) #define DRAMC_DPY_CLK_SW_CON (SPM_BASE + 0x464) #define SPM_S1_MODE_CH (SPM_BASE + 0x468) #define EMI_SELF_REFRESH_CH_STA (SPM_BASE + 0x46C) #define DRAMC_DPY_CLK_SW_CON_SEL2 (SPM_BASE + 0x470) #define DRAMC_DPY_CLK_SW_CON2 (SPM_BASE + 0x474) #define DRAMC_DMYRD_CON (SPM_BASE + 0x478) #define SPM_DRS_CON (SPM_BASE + 0x47C) #define SPM_SEMA_M0 (SPM_BASE + 0x480) #define SPM_SEMA_M1 (SPM_BASE + 0x484) #define SPM_SEMA_M2 (SPM_BASE + 0x488) #define SPM_SEMA_M3 (SPM_BASE + 0x48C) #define SPM_SEMA_M4 (SPM_BASE + 0x490) #define SPM_SEMA_M5 (SPM_BASE + 0x494) #define SPM_SEMA_M6 (SPM_BASE + 0x498) #define SPM_SEMA_M7 (SPM_BASE + 0x49C) #define SPM_MAS_PAUSE_MM_MASK_B (SPM_BASE + 0x4A0) #define SPM_MAS_PAUSE_MCU_MASK_B (SPM_BASE + 0x4A4) #define SRAM_DREQ_ACK (SPM_BASE + 0x4AC) #define SRAM_DREQ_CON (SPM_BASE + 0x4B0) #define SRAM_DREQ_CON_SET (SPM_BASE + 0x4B4) #define SRAM_DREQ_CON_CLR (SPM_BASE + 0x4B8) #define SPM2EMI_ENTER_ULPM (SPM_BASE + 0x4BC) #define SPM_SSPM_IRQ (SPM_BASE + 0x4C0) #define SPM2PMCU_INT (SPM_BASE + 0x4C4) #define SPM2PMCU_INT_SET (SPM_BASE + 0x4C8) #define SPM2PMCU_INT_CLR (SPM_BASE + 0x4CC) #define SPM2PMCU_MAILBOX_0 (SPM_BASE + 0x4D0) #define SPM2PMCU_MAILBOX_1 (SPM_BASE + 0x4D4) #define SPM2PMCU_MAILBOX_2 (SPM_BASE + 0x4D8) #define SPM2PMCU_MAILBOX_3 (SPM_BASE + 0x4DC) #define PMCU2SPM_INT (SPM_BASE + 0x4E0) #define PMCU2SPM_INT_SET (SPM_BASE + 0x4E4) #define PMCU2SPM_INT_CLR (SPM_BASE + 0x4E8) #define PMCU2SPM_MAILBOX_0 (SPM_BASE + 0x4EC) #define PMCU2SPM_MAILBOX_1 (SPM_BASE + 0x4F0) #define PMCU2SPM_MAILBOX_2 (SPM_BASE + 0x4F4) #define PMCU2SPM_MAILBOX_3 (SPM_BASE + 0x4F8) #define PMCU2SPM_CFG (SPM_BASE + 0x4FC) #define MP0_CPU0_IRQ_MASK (SPM_BASE + 0x500) #define MP0_CPU1_IRQ_MASK (SPM_BASE + 0x504) #define MP0_CPU2_IRQ_MASK (SPM_BASE + 0x508) #define MP0_CPU3_IRQ_MASK (SPM_BASE + 0x50C) #define MP1_CPU0_IRQ_MASK (SPM_BASE + 0x510) #define MP1_CPU1_IRQ_MASK (SPM_BASE + 0x514) #define MP1_CPU2_IRQ_MASK (SPM_BASE + 0x518) #define MP1_CPU3_IRQ_MASK (SPM_BASE + 0x51C) #define MP0_CPU0_WFI_EN (SPM_BASE + 0x530) #define MP0_CPU1_WFI_EN (SPM_BASE + 0x534) #define MP0_CPU2_WFI_EN (SPM_BASE + 0x538) #define MP0_CPU3_WFI_EN (SPM_BASE + 0x53C) #define MP1_CPU0_WFI_EN (SPM_BASE + 0x540) #define MP1_CPU1_WFI_EN (SPM_BASE + 0x544) #define MP1_CPU2_WFI_EN (SPM_BASE + 0x548) #define MP1_CPU3_WFI_EN (SPM_BASE + 0x54C) #define MP0_L2CFLUSH (SPM_BASE + 0x554) #define MP1_L2CFLUSH (SPM_BASE + 0x558) #define CPU_PTPOD2_CON (SPM_BASE + 0x560) #define ROOT_CPUTOP_ADDR (SPM_BASE + 0x570) #define ROOT_CORE_ADDR (SPM_BASE + 0x574) #define CPU_SPARE_CON (SPM_BASE + 0x580) #define CPU_SPARE_CON_SET (SPM_BASE + 0x584) #define CPU_SPARE_CON_CLR (SPM_BASE + 0x588) #define SPM2SW_MAILBOX_0 (SPM_BASE + 0x5D0) #define SPM2SW_MAILBOX_1 (SPM_BASE + 0x5D4) #define SPM2SW_MAILBOX_2 (SPM_BASE + 0x5D8) #define SPM2SW_MAILBOX_3 (SPM_BASE + 0x5DC) #define SW2SPM_INT (SPM_BASE + 0x5E0) #define SW2SPM_INT_SET (SPM_BASE + 0x5E4) #define SW2SPM_INT_CLR (SPM_BASE + 0x5E8) #define SW2SPM_MAILBOX_0 (SPM_BASE + 0x5EC) #define SW2SPM_MAILBOX_1 (SPM_BASE + 0x5F0) #define SW2SPM_MAILBOX_2 (SPM_BASE + 0x5F4) #define SW2SPM_MAILBOX_3 (SPM_BASE + 0x5F8) #define SW2SPM_CFG (SPM_BASE + 0x5FC) #define SPM_SW_FLAG (SPM_BASE + 0x600) #define SPM_SW_DEBUG (SPM_BASE + 0x604) #define SPM_SW_RSV_0 (SPM_BASE + 0x608) #define SPM_SW_RSV_1 (SPM_BASE + 0x60C) #define SPM_SW_RSV_2 (SPM_BASE + 0x610) #define SPM_SW_RSV_3 (SPM_BASE + 0x614) #define SPM_SW_RSV_4 (SPM_BASE + 0x618) #define SPM_SW_RSV_5 (SPM_BASE + 0x61C) #define SPM_RSV_CON (SPM_BASE + 0x620) #define SPM_RSV_STA (SPM_BASE + 0x624) #define SPM_RSV_CON1 (SPM_BASE + 0x628) #define SPM_RSV_STA1 (SPM_BASE + 0x62C) #define SPM_PASR_DPD_0 (SPM_BASE + 0x630) #define SPM_PASR_DPD_1 (SPM_BASE + 0x634) #define SPM_PASR_DPD_2 (SPM_BASE + 0x638) #define SPM_PASR_DPD_3 (SPM_BASE + 0x63C) #define SPM_SPARE_CON (SPM_BASE + 0x640) #define SPM_SPARE_CON_SET (SPM_BASE + 0x644) #define SPM_SPARE_CON_CLR (SPM_BASE + 0x648) #define SPM_SW_RSV_6 (SPM_BASE + 0x64C) #define SPM_SW_RSV_7 (SPM_BASE + 0x650) #define SPM_SW_RSV_8 (SPM_BASE + 0x654) #define SPM_SW_RSV_9 (SPM_BASE + 0x658) #define SPM_SW_RSV_10 (SPM_BASE + 0x65C) #define SPM_SW_RSV_18 (SPM_BASE + 0x67C) #define SPM_SW_RSV_19 (SPM_BASE + 0x680) #define DVFSRC_EVENT_MASK_CON (SPM_BASE + 0x690) #define DVFSRC_EVENT_FORCE_ON (SPM_BASE + 0x694) #define DVFSRC_EVENT_SEL (SPM_BASE + 0x698) #define SPM_DVFS_EVENT_STA (SPM_BASE + 0x69C) #define SPM_DVFS_EVENT_STA1 (SPM_BASE + 0x6A0) #define SPM_DVFS_LEVEL (SPM_BASE + 0x6A4) #define DVFS_ABORT_STA (SPM_BASE + 0x6A8) #define DVFS_ABORT_OTHERS_MASK (SPM_BASE + 0x6AC) #define SPM_DFS_LEVEL (SPM_BASE + 0x6B0) #define SPM_DVS_LEVEL (SPM_BASE + 0x6B4) #define SPM_DVFS_MISC (SPM_BASE + 0x6B8) #define SPARE_SRC_REQ_MASK (SPM_BASE + 0x6C0) #define SCP_VCORE_LEVEL (SPM_BASE + 0x6C4) #define SC_MM_CK_SEL_CON (SPM_BASE + 0x6C8) #define SPARE_ACK_STA (SPM_BASE + 0x6F0) #define SPARE_ACK_MASK (SPM_BASE + 0x6F4) #define SPM_DVFS_CON1 (SPM_BASE + 0x700) #define SPM_DVFS_CON1_STA (SPM_BASE + 0x704) #define SPM_DVFS_CMD0 (SPM_BASE + 0x710) #define SPM_DVFS_CMD1 (SPM_BASE + 0x714) #define SPM_DVFS_CMD2 (SPM_BASE + 0x718) #define SPM_DVFS_CMD3 (SPM_BASE + 0x71C) #define SPM_DVFS_CMD4 (SPM_BASE + 0x720) #define SPM_DVFS_CMD5 (SPM_BASE + 0x724) #define SPM_DVFS_CMD6 (SPM_BASE + 0x728) #define SPM_DVFS_CMD7 (SPM_BASE + 0x72C) #define SPM_DVFS_CMD8 (SPM_BASE + 0x730) #define SPM_DVFS_CMD9 (SPM_BASE + 0x734) #define SPM_DVFS_CMD10 (SPM_BASE + 0x738) #define SPM_DVFS_CMD11 (SPM_BASE + 0x73C) #define SPM_DVFS_CMD12 (SPM_BASE + 0x740) #define SPM_DVFS_CMD13 (SPM_BASE + 0x744) #define SPM_DVFS_CMD14 (SPM_BASE + 0x748) #define SPM_DVFS_CMD15 (SPM_BASE + 0x74C) #define WDT_LATCH_SPARE0_FIX (SPM_BASE + 0x780) #define WDT_LATCH_SPARE1_FIX (SPM_BASE + 0x784) #define WDT_LATCH_SPARE2_FIX (SPM_BASE + 0x788) #define WDT_LATCH_SPARE3_FIX (SPM_BASE + 0x78C) #define SPARE_ACK_IN_FIX (SPM_BASE + 0x790) #define DCHA_LATCH_RSV0_FIX (SPM_BASE + 0x794) #define DCHB_LATCH_RSV0_FIX (SPM_BASE + 0x798) #define PCM_WDT_LATCH_0 (SPM_BASE + 0x800) #define PCM_WDT_LATCH_1 (SPM_BASE + 0x804) #define PCM_WDT_LATCH_2 (SPM_BASE + 0x808) #define PCM_WDT_LATCH_3 (SPM_BASE + 0x80C) #define PCM_WDT_LATCH_4 (SPM_BASE + 0x810) #define PCM_WDT_LATCH_5 (SPM_BASE + 0x814) #define PCM_WDT_LATCH_6 (SPM_BASE + 0x818) #define PCM_WDT_LATCH_7 (SPM_BASE + 0x81C) #define PCM_WDT_LATCH_8 (SPM_BASE + 0x820) #define PCM_WDT_LATCH_9 (SPM_BASE + 0x824) #define WDT_LATCH_SPARE0 (SPM_BASE + 0x828) #define WDT_LATCH_SPARE1 (SPM_BASE + 0x82C) #define WDT_LATCH_SPARE2 (SPM_BASE + 0x830) #define WDT_LATCH_SPARE3 (SPM_BASE + 0x834) #define PCM_WDT_LATCH_10 (SPM_BASE + 0x838) #define PCM_WDT_LATCH_11 (SPM_BASE + 0x83C) #define DCHA_GATING_LATCH_0 (SPM_BASE + 0x840) #define DCHA_GATING_LATCH_1 (SPM_BASE + 0x844) #define DCHA_GATING_LATCH_2 (SPM_BASE + 0x848) #define DCHA_GATING_LATCH_3 (SPM_BASE + 0x84C) #define DCHA_GATING_LATCH_4 (SPM_BASE + 0x850) #define DCHA_GATING_LATCH_5 (SPM_BASE + 0x854) #define DCHA_GATING_LATCH_6 (SPM_BASE + 0x858) #define DCHA_GATING_LATCH_7 (SPM_BASE + 0x85C) #define DCHB_GATING_LATCH_0 (SPM_BASE + 0x860) #define DCHB_GATING_LATCH_1 (SPM_BASE + 0x864) #define DCHB_GATING_LATCH_2 (SPM_BASE + 0x868) #define DCHB_GATING_LATCH_3 (SPM_BASE + 0x86C) #define DCHB_GATING_LATCH_4 (SPM_BASE + 0x870) #define DCHB_GATING_LATCH_5 (SPM_BASE + 0x874) #define DCHB_GATING_LATCH_6 (SPM_BASE + 0x878) #define DCHB_GATING_LATCH_7 (SPM_BASE + 0x87C) #define DCHA_LATCH_RSV0 (SPM_BASE + 0x880) #define DCHB_LATCH_RSV0 (SPM_BASE + 0x884) #define PCM_WDT_LATCH_12 (SPM_BASE + 0x888) #define PCM_WDT_LATCH_13 (SPM_BASE + 0x88C) #define SPM_PC_TRACE_CON (SPM_BASE + 0x8C0) #define SPM_PC_TRACE_G0 (SPM_BASE + 0x8C4) #define SPM_PC_TRACE_G1 (SPM_BASE + 0x8C8) #define SPM_PC_TRACE_G2 (SPM_BASE + 0x8CC) #define SPM_PC_TRACE_G3 (SPM_BASE + 0x8D0) #define SPM_PC_TRACE_G4 (SPM_BASE + 0x8D4) #define SPM_PC_TRACE_G5 (SPM_BASE + 0x8D8) #define SPM_PC_TRACE_G6 (SPM_BASE + 0x8DC) #define SPM_PC_TRACE_G7 (SPM_BASE + 0x8E0) #define SPM_ACK_CHK_CON (SPM_BASE + 0x900) #define SPM_ACK_CHK_PC (SPM_BASE + 0x904) #define SPM_ACK_CHK_SEL (SPM_BASE + 0x908) #define SPM_ACK_CHK_TIMER (SPM_BASE + 0x90C) #define SPM_ACK_CHK_STA (SPM_BASE + 0x910) #define SPM_ACK_CHK_LATCH (SPM_BASE + 0x914) #define SPM_ACK_CHK_CON2 (SPM_BASE + 0x920) #define SPM_ACK_CHK_PC2 (SPM_BASE + 0x924) #define SPM_ACK_CHK_SEL2 (SPM_BASE + 0x928) #define SPM_ACK_CHK_TIMER2 (SPM_BASE + 0x92C) #define SPM_ACK_CHK_STA2 (SPM_BASE + 0x930) #define SPM_ACK_CHK_LATCH2 (SPM_BASE + 0x934) #define SPM_ACK_CHK_CON3 (SPM_BASE + 0x940) #define SPM_ACK_CHK_PC3 (SPM_BASE + 0x944) #define SPM_ACK_CHK_SEL3 (SPM_BASE + 0x948) #define SPM_ACK_CHK_TIMER3 (SPM_BASE + 0x94C) #define SPM_ACK_CHK_STA3 (SPM_BASE + 0x950) #define SPM_ACK_CHK_LATCH3 (SPM_BASE + 0x954) #define SPM_ACK_CHK_CON4 (SPM_BASE + 0x960) #define SPM_ACK_CHK_PC4 (SPM_BASE + 0x964) #define SPM_ACK_CHK_SEL4 (SPM_BASE + 0x968) #define SPM_ACK_CHK_TIMER4 (SPM_BASE + 0x96C) #define SPM_ACK_CHK_STA4 (SPM_BASE + 0x970) #define SPM_ACK_CHK_LATCH4 (SPM_BASE + 0x974) /* POWERON_CONFIG_EN (0x10006000+0x000) */ #define BCLK_CG_EN_LSB (1U << 0) /* 1b */ #define MD_BCLK_CG_EN_LSB (1U << 1) /* 1b */ #define PROJECT_CODE_LSB (1U << 16) /* 16b */ /* SPM_POWER_ON_VAL0 (0x10006000+0x004) */ #define POWER_ON_VAL0_LSB (1U << 0) /* 32b */ /* SPM_POWER_ON_VAL1 (0x10006000+0x008) */ #define POWER_ON_VAL1_LSB (1U << 0) /* 32b */ /* SPM_CLK_CON (0x10006000+0x00C) */ #define SYSCLK0_EN_CTRL_LSB (1U << 0) /* 2b */ #define SYSCLK1_EN_CTRL_LSB (1U << 2) /* 2b */ #define SYS_SETTLE_SEL_LSB (1U << 4) /* 1b */ #define SPM_LOCK_INFRA_DCM_LSB (1U << 5) /* 1b */ #define EXT_SRCCLKEN_MASK_LSB (1U << 6) /* 3b */ #define CXO32K_REMOVE_EN_MD1_LSB (1U << 9) /* 1b */ #define CXO32K_REMOVE_EN_MD2_LSB (1U << 10) /* 1b */ #define CLKSQ0_SEL_CTRL_LSB (1U << 11) /* 1b */ #define CLKSQ1_SEL_CTRL_LSB (1U << 12) /* 1b */ #define SRCLKEN0_EN_LSB (1U << 13) /* 1b */ #define SRCLKEN1_EN_LSB (1U << 14) /* 1b */ #define SCP_DCM_EN_LSB (1U << 15) /* 1b */ #define SYSCLK0_SRC_MASK_B_LSB (1U << 16) /* 7b */ #define SYSCLK1_SRC_MASK_B_LSB (1U << 23) /* 7b */ /* SPM_CLK_SETTLE (0x10006000+0x010) */ #define SYSCLK_SETTLE_LSB (1U << 0) /* 28b */ /* SPM_AP_STANDBY_CON (0x10006000+0x014) */ #define WFI_OP_LSB (1U << 0) /* 1b */ #define MP0_CPUTOP_IDLE_MASK_LSB (1U << 1) /* 1b */ #define MP1_CPUTOP_IDLE_MASK_LSB (1U << 2) /* 1b */ #define MCUSYS_IDLE_MASK_LSB (1U << 4) /* 1b */ #define MM_MASK_B_LSB (1U << 16) /* 2b */ #define MD_DDR_EN_0_DBC_EN_LSB (1U << 18) /* 1b */ #define MD_DDR_EN_1_DBC_EN_LSB (1U << 19) /* 1b */ #define MD_MASK_B_LSB (1U << 20) /* 2b */ #define SSPM_MASK_B_LSB (1U << 22) /* 1b */ #define SCP_MASK_B_LSB (1U << 23) /* 1b */ #define SRCCLKENI_MASK_B_LSB (1U << 24) /* 1b */ #define MD_APSRC_1_SEL_LSB (1U << 25) /* 1b */ #define MD_APSRC_0_SEL_LSB (1U << 26) /* 1b */ #define CONN_DDR_EN_DBC_EN_LSB (1U << 27) /* 1b */ #define CONN_MASK_B_LSB (1U << 28) /* 1b */ #define CONN_APSRC_SEL_LSB (1U << 29) /* 1b */ /* PCM_CON0 (0x10006000+0x018) */ #define PCM_KICK_L_LSB (1U << 0) /* 1b */ #define IM_KICK_L_LSB (1U << 1) /* 1b */ #define PCM_CK_EN_LSB (1U << 2) /* 1b */ #define EN_IM_SLEEP_DVS_LSB (1U << 3) /* 1b */ #define IM_AUTO_PDN_EN_LSB (1U << 4) /* 1b */ #define PCM_SW_RESET_LSB (1U << 15) /* 1b */ #define PROJECT_CODE_LSB (1U << 16) /* 16b */ /* PCM_CON1 (0x10006000+0x01C) */ #define IM_SLAVE_LSB (1U << 0) /* 1b */ #define IM_SLEEP_LSB (1U << 1) /* 1b */ #define MIF_APBEN_LSB (1U << 3) /* 1b */ #define IM_PDN_LSB (1U << 4) /* 1b */ #define PCM_TIMER_EN_LSB (1U << 5) /* 1b */ #define IM_NONRP_EN_LSB (1U << 6) /* 1b */ #define DIS_MIF_PROT_LSB (1U << 7) /* 1b */ #define PCM_WDT_EN_LSB (1U << 8) /* 1b */ #define PCM_WDT_WAKE_MODE_LSB (1U << 9) /* 1b */ #define SPM_SRAM_SLEEP_B_LSB (1U << 10) /* 1b */ #define SPM_SRAM_ISOINT_B_LSB (1U << 11) /* 1b */ #define EVENT_LOCK_EN_LSB (1U << 12) /* 1b */ #define SRCCLKEN_FAST_RESP_LSB (1U << 13) /* 1b */ #define SCP_APB_INTERNAL_EN_LSB (1U << 14) /* 1b */ #define PROJECT_CODE_LSB (1U << 16) /* 16b */ /* PCM_IM_PTR (0x10006000+0x020) */ #define PCM_IM_PTR_LSB (1U << 0) /* 32b */ /* PCM_IM_LEN (0x10006000+0x024) */ #define PCM_IM_LEN_LSB (1U << 0) /* 13b */ /* PCM_REG_DATA_INI (0x10006000+0x028) */ #define PCM_REG_DATA_INI_LSB (1U << 0) /* 32b */ /* PCM_PWR_IO_EN (0x10006000+0x02C) */ #define PCM_PWR_IO_EN_LSB (1U << 0) /* 8b */ #define PCM_RF_SYNC_EN_LSB (1U << 16) /* 8b */ /* PCM_TIMER_VAL (0x10006000+0x030) */ #define PCM_TIMER_VAL_LSB (1U << 0) /* 32b */ /* PCM_WDT_VAL (0x10006000+0x034) */ #define PCM_WDT_VAL_LSB (1U << 0) /* 32b */ /* PCM_IM_HOST_RW_PTR (0x10006000+0x038) */ #define PCM_IM_HOST_RW_PTR_LSB (1U << 0) /* 12b */ #define PCM_IM_HOST_W_EN_LSB (1U << 30) /* 1b */ #define PCM_IM_HOST_EN_LSB (1U << 31) /* 1b */ /* PCM_IM_HOST_RW_DAT (0x10006000+0x03C) */ #define PCM_IM_HOST_RW_DAT_LSB (1U << 0) /* 32b */ /* PCM_EVENT_VECTOR0 (0x10006000+0x040) */ #define PCM_EVENT_VECTOR_0_LSB (1U << 0) /* 6b */ #define PCM_EVENT_RESUME_0_LSB (1U << 6) /* 1b */ #define PCM_EVENT_IMMEDIA_0_LSB (1U << 7) /* 1b */ #define PCM_EVENT_VECTPC_0_LSB (1U << 16) /* 11b */ /* PCM_EVENT_VECTOR1 (0x10006000+0x044) */ #define PCM_EVENT_VECTOR_1_LSB (1U << 0) /* 6b */ #define PCM_EVENT_RESUME_1_LSB (1U << 6) /* 1b */ #define PCM_EVENT_IMMEDIA_1_LSB (1U << 7) /* 1b */ #define PCM_EVENT_VECTPC_1_LSB (1U << 16) /* 11b */ /* PCM_EVENT_VECTOR2 (0x10006000+0x048) */ #define PCM_EVENT_VECTOR_2_LSB (1U << 0) /* 6b */ #define PCM_EVENT_RESUME_2_LSB (1U << 6) /* 1b */ #define PCM_EVENT_IMMEDIA_2_LSB (1U << 7) /* 1b */ #define PCM_EVENT_VECTPC_2_LSB (1U << 16) /* 11b */ /* PCM_EVENT_VECTOR3 (0x10006000+0x04C) */ #define PCM_EVENT_VECTOR_3_LSB (1U << 0) /* 6b */ #define PCM_EVENT_RESUME_3_LSB (1U << 6) /* 1b */ #define PCM_EVENT_IMMEDIA_3_LSB (1U << 7) /* 1b */ #define PCM_EVENT_VECTPC_3_LSB (1U << 16) /* 11b */ /* PCM_EVENT_VECTOR4 (0x10006000+0x050) */ #define PCM_EVENT_VECTOR_4_LSB (1U << 0) /* 6b */ #define PCM_EVENT_RESUME_4_LSB (1U << 6) /* 1b */ #define PCM_EVENT_IMMEDIA_4_LSB (1U << 7) /* 1b */ #define PCM_EVENT_VECTPC_4_LSB (1U << 16) /* 11b */ /* PCM_EVENT_VECTOR5 (0x10006000+0x054) */ #define PCM_EVENT_VECTOR_5_LSB (1U << 0) /* 6b */ #define PCM_EVENT_RESUME_5_LSB (1U << 6) /* 1b */ #define PCM_EVENT_IMMEDIA_5_LSB (1U << 7) /* 1b */ #define PCM_EVENT_VECTPC_5_LSB (1U << 16) /* 11b */ /* PCM_EVENT_VECTOR6 (0x10006000+0x058) */ #define PCM_EVENT_VECTOR_6_LSB (1U << 0) /* 6b */ #define PCM_EVENT_RESUME_6_LSB (1U << 6) /* 1b */ #define PCM_EVENT_IMMEDIA_6_LSB (1U << 7) /* 1b */ #define PCM_EVENT_VECTPC_6_LSB (1U << 16) /* 11b */ /* PCM_EVENT_VECTOR7 (0x10006000+0x05C) */ #define PCM_EVENT_VECTOR_7_LSB (1U << 0) /* 6b */ #define PCM_EVENT_RESUME_7_LSB (1U << 6) /* 1b */ #define PCM_EVENT_IMMEDIA_7_LSB (1U << 7) /* 1b */ #define PCM_EVENT_VECTPC_7_LSB (1U << 16) /* 11b */ /* PCM_EVENT_VECTOR8 (0x10006000+0x060) */ #define PCM_EVENT_VECTOR_8_LSB (1U << 0) /* 6b */ #define PCM_EVENT_RESUME_8_LSB (1U << 6) /* 1b */ #define PCM_EVENT_IMMEDIA_8_LSB (1U << 7) /* 1b */ #define PCM_EVENT_VECTPC_8_LSB (1U << 16) /* 11b */ /* PCM_EVENT_VECTOR9 (0x10006000+0x064) */ #define PCM_EVENT_VECTOR_9_LSB (1U << 0) /* 6b */ #define PCM_EVENT_RESUME_9_LSB (1U << 6) /* 1b */ #define PCM_EVENT_IMMEDIA_9_LSB (1U << 7) /* 1b */ #define PCM_EVENT_VECTPC_9_LSB (1U << 16) /* 11b */ /* PCM_EVENT_VECTOR10 (0x10006000+0x068) */ #define PCM_EVENT_VECTOR_10_LSB (1U << 0) /* 6b */ #define PCM_EVENT_RESUME_10_LSB (1U << 6) /* 1b */ #define PCM_EVENT_IMMEDIA_10_LSB (1U << 7) /* 1b */ #define PCM_EVENT_VECTPC_10_LSB (1U << 16) /* 11b */ /* PCM_EVENT_VECTOR11 (0x10006000+0x06C) */ #define PCM_EVENT_VECTOR_11_LSB (1U << 0) /* 6b */ #define PCM_EVENT_RESUME_11_LSB (1U << 6) /* 1b */ #define PCM_EVENT_IMMEDIA_11_LSB (1U << 7) /* 1b */ #define PCM_EVENT_VECTPC_11_LSB (1U << 16) /* 11b */ /* PCM_EVENT_VECTOR12 (0x10006000+0x070) */ #define PCM_EVENT_VECTOR_12_LSB (1U << 0) /* 6b */ #define PCM_EVENT_RESUME_12_LSB (1U << 6) /* 1b */ #define PCM_EVENT_IMMEDIA_12_LSB (1U << 7) /* 1b */ #define PCM_EVENT_VECTPC_12_LSB (1U << 16) /* 11b */ /* PCM_EVENT_VECTOR13 (0x10006000+0x074) */ #define PCM_EVENT_VECTOR_13_LSB (1U << 0) /* 6b */ #define PCM_EVENT_RESUME_13_LSB (1U << 6) /* 1b */ #define PCM_EVENT_IMMEDIA_13_LSB (1U << 7) /* 1b */ #define PCM_EVENT_VECTPC_13_LSB (1U << 16) /* 11b */ /* PCM_EVENT_VECTOR14 (0x10006000+0x078) */ #define PCM_EVENT_VECTOR_14_LSB (1U << 0) /* 6b */ #define PCM_EVENT_RESUME_14_LSB (1U << 6) /* 1b */ #define PCM_EVENT_IMMEDIA_14_LSB (1U << 7) /* 1b */ #define PCM_EVENT_VECTPC_14_LSB (1U << 16) /* 11b */ /* PCM_EVENT_VECTOR15 (0x10006000+0x07C) */ #define PCM_EVENT_VECTOR_15_LSB (1U << 0) /* 6b */ #define PCM_EVENT_RESUME_15_LSB (1U << 6) /* 1b */ #define PCM_EVENT_IMMEDIA_15_LSB (1U << 7) /* 1b */ #define PCM_EVENT_VECTPC_15_LSB (1U << 16) /* 11b */ /* PCM_EVENT_VECTOR_EN (0x10006000+0x080) */ #define PCM_EVENT_VECTOR_EN_LSB (1U << 0) /* 16b */ /* SPM_SRAM_RSV_CON (0x10006000+0x088) */ #define SPM_SRAM_SLEEP_B_ECO_EN_LSB (1U << 0) /* 1b */ /* SPM_SWINT (0x10006000+0x08C) */ #define SPM_SWINT_LSB (1U << 0) /* 10b */ /* SPM_SWINT_SET (0x10006000+0x090) */ #define SPM_SWINT_SET_LSB (1U << 0) /* 10b */ /* SPM_SWINT_CLR (0x10006000+0x094) */ #define SPM_SWINT_CLR_LSB (1U << 0) /* 10b */ /* SPM_SCP_MAILBOX (0x10006000+0x098) */ #define SPM_SCP_MAILBOX_LSB (1U << 0) /* 32b */ /* SCP_SPM_MAILBOX (0x10006000+0x09C) */ #define SCP_SPM_MAILBOX_LSB (1U << 0) /* 32b */ /* SPM_TWAM_CON (0x10006000+0x0A0) */ #define TWAM_ENABLE_LSB (1U << 0) /* 1b */ #define TWAM_SPEED_MODE_ENABLE_LSB (1U << 1) /* 1b */ #define TWAM_SW_RST_LSB (1U << 2) /* 1b */ #define TWAM_MON_TYPE0_LSB (1U << 4) /* 2b */ #define TWAM_MON_TYPE1_LSB (1U << 6) /* 2b */ #define TWAM_MON_TYPE2_LSB (1U << 8) /* 2b */ #define TWAM_MON_TYPE3_LSB (1U << 10) /* 2b */ #define TWAM_SIGNAL_SEL0_LSB (1U << 12) /* 5b */ #define TWAM_SIGNAL_SEL1_LSB (1U << 17) /* 5b */ #define TWAM_SIGNAL_SEL2_LSB (1U << 22) /* 5b */ #define TWAM_SIGNAL_SEL3_LSB (1U << 27) /* 5b */ /* SPM_TWAM_WINDOW_LEN (0x10006000+0x0A4) */ #define TWAM_WINDOW_LEN_LSB (1U << 0) /* 32b */ /* SPM_TWAM_IDLE_SEL (0x10006000+0x0A8) */ #define TWAM_IDLE_SEL_LSB (1U << 0) /* 5b */ /* SPM_SCP_IRQ (0x10006000+0x0AC) */ #define SPM_SCP_IRQ_LSB (1U << 0) /* 1b */ #define SPM_SCP_IRQ_SEL_LSB (1U << 4) /* 1b */ /* SPM_CPU_WAKEUP_EVENT (0x10006000+0x0B0) */ #define SPM_CPU_WAKEUP_EVENT_LSB (1U << 0) /* 1b */ /* SPM_IRQ_MASK (0x10006000+0x0B4) */ #define SPM_TWAM_IRQ_MASK_LSB (1U << 2) /* 1b */ #define PCM_IRQ_ROOT_MASK_LSB (1U << 3) /* 1b */ #define SPM_IRQ_MASK_LSB (1U << 8) /* 10b */ /* SPM_SRC_REQ (0x10006000+0x0B8) */ #define SPM_APSRC_REQ_LSB (1U << 0) /* 1b */ #define SPM_F26M_REQ_LSB (1U << 1) /* 1b */ #define SPM_INFRA_REQ_LSB (1U << 3) /* 1b */ #define SPM_VRF18_REQ_LSB (1U << 4) /* 1b */ #define SPM_DDREN_REQ_LSB (1U << 7) /* 1b */ #define SPM_RSV_SRC_REQ_LSB (1U << 8) /* 3b */ #define SPM_DDREN_2_REQ_LSB (1U << 11) /* 1b */ #define CPU_MD_DVFS_SOP_FORCE_ON_LSB (1U << 16) /* 1b */ /* SPM_SRC_MASK (0x10006000+0x0BC) */ #define CSYSPWREQ_MASK_LSB (1U << 0) /* 1b */ #define CCIF0_MD_EVENT_MASK_B_LSB (1U << 1) /* 1b */ #define CCIF0_AP_EVENT_MASK_B_LSB (1U << 2) /* 1b */ #define CCIF1_MD_EVENT_MASK_B_LSB (1U << 3) /* 1b */ #define CCIF1_AP_EVENT_MASK_B_LSB (1U << 4) /* 1b */ #define CCIF2_MD_EVENT_MASK_B_LSB (1U << 5) /* 1b */ #define CCIF2_AP_EVENT_MASK_B_LSB (1U << 6) /* 1b */ #define CCIF3_MD_EVENT_MASK_B_LSB (1U << 7) /* 1b */ #define CCIF3_AP_EVENT_MASK_B_LSB (1U << 8) /* 1b */ #define MD_SRCCLKENA_0_INFRA_MASK_B_LSB (1U << 9) /* 1b */ #define MD_SRCCLKENA_1_INFRA_MASK_B_LSB (1U << 10) /* 1b */ #define CONN_SRCCLKENA_INFRA_MASK_B_LSB (1U << 11) /* 1b */ #define UFS_INFRA_REQ_MASK_B_LSB (1U << 12) /* 1b */ #define SRCCLKENI_INFRA_MASK_B_LSB (1U << 13) /* 1b */ #define MD_APSRC_REQ_0_INFRA_MASK_B_LSB (1U << 14) /* 1b */ #define MD_APSRC_REQ_1_INFRA_MASK_B_LSB (1U << 15) /* 1b */ #define CONN_APSRCREQ_INFRA_MASK_B_LSB (1U << 16) /* 1b */ #define UFS_SRCCLKENA_MASK_B_LSB (1U << 17) /* 1b */ #define MD_VRF18_REQ_0_MASK_B_LSB (1U << 18) /* 1b */ #define MD_VRF18_REQ_1_MASK_B_LSB (1U << 19) /* 1b */ #define UFS_VRF18_REQ_MASK_B_LSB (1U << 20) /* 1b */ #define GCE_VRF18_REQ_MASK_B_LSB (1U << 21) /* 1b */ #define CONN_INFRA_REQ_MASK_B_LSB (1U << 22) /* 1b */ #define GCE_APSRC_REQ_MASK_B_LSB (1U << 23) /* 1b */ #define DISP0_APSRC_REQ_MASK_B_LSB (1U << 24) /* 1b */ #define DISP1_APSRC_REQ_MASK_B_LSB (1U << 25) /* 1b */ #define MFG_REQ_MASK_B_LSB (1U << 26) /* 1b */ #define VDEC_REQ_MASK_B_LSB (1U << 27) /* 1b */ /* SPM_SRC2_MASK (0x10006000+0x0C0) */ #define MD_DDR_EN_0_MASK_B_LSB (1U << 0) /* 1b */ #define MD_DDR_EN_1_MASK_B_LSB (1U << 1) /* 1b */ #define CONN_DDR_EN_MASK_B_LSB (1U << 2) /* 1b */ #define DDREN_SSPM_APSRC_REQ_MASK_B_LSB (1U << 3) /* 1b */ #define DDREN_SCP_APSRC_REQ_MASK_B_LSB (1U << 4) /* 1b */ #define DISP0_DDREN_MASK_B_LSB (1U << 5) /* 1b */ #define DISP1_DDREN_MASK_B_LSB (1U << 6) /* 1b */ #define GCE_DDREN_MASK_B_LSB (1U << 7) /* 1b */ #define DDREN_EMI_SELF_REFRESH_CH0_MASK_B_LSB (1U << 8) /* 1b */ #define DDREN_EMI_SELF_REFRESH_CH1_MASK_B_LSB (1U << 9) /* 1b */ /* SPM_WAKEUP_EVENT_MASK (0x10006000+0x0C4) */ #define SPM_WAKEUP_EVENT_MASK_LSB (1U << 0) /* 32b */ /* SPM_WAKEUP_EVENT_EXT_MASK (0x10006000+0x0C8) */ #define SPM_WAKEUP_EVENT_EXT_MASK_LSB (1U << 0) /* 32b */ /* SPM_TWAM_EVENT_CLEAR (0x10006000+0x0CC) */ #define SPM_TWAM_EVENT_CLEAR_LSB (1U << 0) /* 1b */ /* SCP_CLK_CON (0x10006000+0x0D0) */ #define SCP_26M_CK_SEL_LSB (1U << 0) /* 1b */ #define SCP_SECURE_V_REQ_MASK_LSB (1U << 1) /* 1b */ #define SCP_SLP_REQ_LSB (1U << 2) /* 1b */ #define SCP_SLP_ACK_LSB (1U << 3) /* 1b */ /* PCM_DEBUG_CON (0x10006000+0x0D4) */ #define PCM_DEBUG_OUT_ENABLE_LSB (1U << 0) /* 1b */ /* DDR_EN_DBC_LEN (0x10006000+0x0D8) */ #define MD_DDR_EN_0_DBC_LEN_LSB (1U << 0) /* 10b */ #define MD_DDR_EN_1_DBC_LEN_LSB (1U << 10) /* 10b */ #define CONN_DDR_EN_DBC_LEN_LSB (1U << 20) /* 10b */ /* AHB_BUS_CON (0x10006000+0x0DC) */ #define AHB_HADDR_EXT_LSB (1U << 0) /* 2b */ #define REG_AHB_LOCK_LSB (1U << 8) /* 1b */ /* SPM_SRC3_MASK (0x10006000+0x0E0) */ #define MD_DDR_EN_2_0_MASK_B_LSB (1U << 0) /* 1b */ #define MD_DDR_EN_2_1_MASK_B_LSB (1U << 1) /* 1b */ #define CONN_DDR_EN_2_MASK_B_LSB (1U << 2) /* 1b */ #define DDREN2_SSPM_APSRC_REQ_MASK_B_LSB (1U << 3) /* 1b */ #define DDREN2_SCP_APSRC_REQ_MASK_B_LSB (1U << 4) /* 1b */ #define DISP0_DDREN2_MASK_B_LSB (1U << 5) /* 1b */ #define DISP1_DDREN2_MASK_B_LSB (1U << 6) /* 1b */ #define GCE_DDREN2_MASK_B_LSB (1U << 7) /* 1b */ #define DDREN2_EMI_SELF_REFRESH_CH0_MASK_B_LSB (1U << 8) /* 1b */ #define DDREN2_EMI_SELF_REFRESH_CH1_MASK_B_LSB (1U << 9) /* 1b */ /* DDR_EN_EMI_DBC_CON (0x10006000+0x0E4) */ #define EMI_SELF_REFRESH_CH0_DBC_LEN_LSB (1U << 0) /* 10b */ #define EMI_SELF_REFRESH_CH0_DBC_EN_LSB (1U << 10) /* 1b */ #define EMI_SELF_REFRESH_CH1_DBC_LEN_LSB (1U << 16) /* 10b */ #define EMI_SELF_REFRESH_CH1_DBC_EN_LSB (1U << 26) /* 1b */ /* SSPM_CLK_CON (0x10006000+0x0E8) */ #define SSPM_26M_CK_SEL_LSB (1U << 0) /* 1b */ /* PCM_REG0_DATA (0x10006000+0x100) */ #define PCM_REG0_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG1_DATA (0x10006000+0x104) */ #define PCM_REG1_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG2_DATA (0x10006000+0x108) */ #define PCM_REG2_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG3_DATA (0x10006000+0x10C) */ #define PCM_REG3_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG4_DATA (0x10006000+0x110) */ #define PCM_REG4_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG5_DATA (0x10006000+0x114) */ #define PCM_REG5_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG6_DATA (0x10006000+0x118) */ #define PCM_REG6_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG7_DATA (0x10006000+0x11C) */ #define PCM_REG7_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG8_DATA (0x10006000+0x120) */ #define PCM_REG8_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG9_DATA (0x10006000+0x124) */ #define PCM_REG9_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG10_DATA (0x10006000+0x128) */ #define PCM_REG10_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG11_DATA (0x10006000+0x12C) */ #define PCM_REG11_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG12_DATA (0x10006000+0x130) */ #define PCM_REG12_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG13_DATA (0x10006000+0x134) */ #define PCM_REG13_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG14_DATA (0x10006000+0x138) */ #define PCM_REG14_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG15_DATA (0x10006000+0x13C) */ #define PCM_REG15_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG12_MASK_B_STA (0x10006000+0x140) */ #define PCM_REG12_MASK_B_STA_LSB (1U << 0) /* 32b */ /* PCM_REG12_EXT_DATA (0x10006000+0x144) */ #define PCM_REG12_EXT_DATA_LSB (1U << 0) /* 32b */ /* PCM_REG12_EXT_MASK_B_STA (0x10006000+0x148) */ #define PCM_REG12_EXT_MASK_B_STA_LSB (1U << 0) /* 32b */ /* PCM_EVENT_REG_STA (0x10006000+0x14C) */ #define PCM_EVENT_REG_STA_LSB (1U << 0) /* 32b */ /* PCM_TIMER_OUT (0x10006000+0x150) */ #define PCM_TIMER_OUT_LSB (1U << 0) /* 32b */ /* PCM_WDT_OUT (0x10006000+0x154) */ #define PCM_WDT_OUT_LSB (1U << 0) /* 32b */ /* SPM_IRQ_STA (0x10006000+0x158) */ #define SPM_ACK_CHK_WAKEUP_LSB (1U << 1) /* 1b */ #define TWAM_IRQ_LSB (1U << 2) /* 1b */ #define PCM_IRQ_LSB (1U << 3) /* 1b */ /* #define SPM_SWINT_LSB (1U << 4) */ /* 10b */ /* SPM_WAKEUP_STA (0x10006000+0x15C) */ #define SPM_WAKEUP_EVENT_STA_LSB (1U << 0) /* 32b */ /* SPM_WAKEUP_EXT_STA (0x10006000+0x160) */ #define SPM_WAKEUP_EVENT_EXT_STA_LSB (1U << 0) /* 32b */ /* SPM_WAKEUP_MISC (0x10006000+0x164) */ #define SPM_WAKEUP_EVENT_MISC_LSB (1U << 0) /* 30b */ #define SPM_PWRAP_IRQ_ACK_LSB (1U << 30) /* 1b */ #define SPM_PWRAP_IRQ_LSB (1U << 31) /* 1b */ /* BUS_PROTECT_RDY (0x10006000+0x168) */ #define BUS_PROTECT_RDY_LSB (1U << 0) /* 32b */ /* BUS_PROTECT2_RDY (0x10006000+0x16C) */ #define BUS_PROTECT2_RDY_LSB (1U << 0) /* 32b */ /* SUBSYS_IDLE_STA (0x10006000+0x170) */ #define SUBSYS_IDLE_STA_LSB (1U << 0) /* 32b */ /* CPU_IDLE_STA (0x10006000+0x174) */ #define MP0_CPU0_STANDBYWFI_AFTER_SEL_LSB (1U << 0) /* 1b */ #define MP0_CPU1_STANDBYWFI_AFTER_SEL_LSB (1U << 1) /* 1b */ #define MP0_CPU2_STANDBYWFI_AFTER_SEL_LSB (1U << 2) /* 1b */ #define MP0_CPU3_STANDBYWFI_AFTER_SEL_LSB (1U << 3) /* 1b */ #define MP1_CPU0_STANDBYWFI_AFTER_SEL_LSB (1U << 4) /* 1b */ #define MP1_CPU1_STANDBYWFI_AFTER_SEL_LSB (1U << 5) /* 1b */ #define MP1_CPU2_STANDBYWFI_AFTER_SEL_LSB (1U << 6) /* 1b */ #define MP1_CPU3_STANDBYWFI_AFTER_SEL_LSB (1U << 7) /* 1b */ #define MP0_CPU0_STANDBYWFI_LSB (1U << 10) /* 1b */ #define MP0_CPU1_STANDBYWFI_LSB (1U << 11) /* 1b */ #define MP0_CPU2_STANDBYWFI_LSB (1U << 12) /* 1b */ #define MP0_CPU3_STANDBYWFI_LSB (1U << 13) /* 1b */ #define MP1_CPU0_STANDBYWFI_LSB (1U << 14) /* 1b */ #define MP1_CPU1_STANDBYWFI_LSB (1U << 15) /* 1b */ #define MP1_CPU2_STANDBYWFI_LSB (1U << 16) /* 1b */ #define MP1_CPU3_STANDBYWFI_LSB (1U << 17) /* 1b */ #define MP0_CPUTOP_IDLE_LSB (1U << 20) /* 1b */ #define MP1_CPUTOP_IDLE_LSB (1U << 21) /* 1b */ #define MCU_BIU_IDLE_LSB (1U << 22) /* 1b */ #define MCUSYS_IDLE_LSB (1U << 23) /* 1b */ /* PCM_FSM_STA (0x10006000+0x178) */ #define EXEC_INST_OP_LSB (1U << 0) /* 4b */ #define PC_STATE_LSB (1U << 4) /* 3b */ #define IM_STATE_LSB (1U << 7) /* 3b */ #define MASTER_STATE_LSB (1U << 10) /* 5b */ #define EVENT_FSM_LSB (1U << 15) /* 3b */ #define PCM_CLK_SEL_STA_LSB (1U << 18) /* 3b */ #define PCM_KICK_LSB (1U << 21) /* 1b */ #define IM_KICK_LSB (1U << 22) /* 1b */ #define EXT_SRCCLKEN_STA_LSB (1U << 23) /* 2b */ #define EXT_SRCVOLTEN_STA_LSB (1U << 25) /* 1b */ /* SRC_REQ_STA (0x10006000+0x17C) */ #define SRC_REQ_STA_LSB (1U << 0) /* 32b */ /* PWR_STATUS (0x10006000+0x180) */ #define PWR_STATUS_LSB (1U << 0) /* 32b */ /* PWR_STATUS_2ND (0x10006000+0x184) */ #define PWR_STATUS_2ND_LSB (1U << 0) /* 32b */ /* CPU_PWR_STATUS (0x10006000+0x188) */ #define CPU_PWR_STATUS_LSB (1U << 0) /* 32b */ /* CPU_PWR_STATUS_2ND (0x10006000+0x18C) */ #define CPU_PWR_STATUS_2ND_LSB (1U << 0) /* 32b */ /* MISC_STA (0x10006000+0x190) */ #define MM_DVFS_HALT_AF_MASK_LSB (1U << 0) /* 5b */ /* SPM_SRC_RDY_STA (0x10006000+0x194) */ #define SPM_INFRA_SRC_ACK_LSB (1U << 0) /* 1b */ #define SPM_VRF18_SRC_ACK_LSB (1U << 1) /* 1b */ /* DRAMC_DBG_LATCH (0x10006000+0x19C) */ #define DRAMC_DEBUG_LATCH_STATUS_LSB (1U << 0) /* 32b */ /* SPM_TWAM_LAST_STA0 (0x10006000+0x1A0) */ #define SPM_TWAM_LAST_STA0_LSB (1U << 0) /* 32b */ /* SPM_TWAM_LAST_STA1 (0x10006000+0x1A4) */ #define SPM_TWAM_LAST_STA1_LSB (1U << 0) /* 32b */ /* SPM_TWAM_LAST_STA2 (0x10006000+0x1A8) */ #define SPM_TWAM_LAST_STA2_LSB (1U << 0) /* 32b */ /* SPM_TWAM_LAST_STA3 (0x10006000+0x1AC) */ #define SPM_TWAM_LAST_STA3_LSB (1U << 0) /* 32b */ /* SPM_TWAM_CURR_STA0 (0x10006000+0x1B0) */ #define SPM_TWAM_CURR_STA0_LSB (1U << 0) /* 32b */ /* SPM_TWAM_CURR_STA1 (0x10006000+0x1B4) */ #define SPM_TWAM_CURR_STA1_LSB (1U << 0) /* 32b */ /* SPM_TWAM_CURR_STA2 (0x10006000+0x1B8) */ #define SPM_TWAM_CURR_STA2_LSB (1U << 0) /* 32b */ /* SPM_TWAM_CURR_STA3 (0x10006000+0x1BC) */ #define SPM_TWAM_CURR_STA3_LSB (1U << 0) /* 32b */ /* SPM_TWAM_TIMER_OUT (0x10006000+0x1C0) */ #define SPM_TWAM_TIMER_OUT_LSB (1U << 0) /* 32b */ /* SPM_DVFS_STA (0x10006000+0x1C8) */ #define MD_DVFS_ERROR_STATUS_LSB (1U << 0) /* 1b */ /* BUS_PROTECT3_RDY (0x10006000+0x1CC) */ #define BUS_PROTECT_MM_RDY_LSB (1U << 0) /* 16b */ #define BUS_PROTECT_MCU_RDY_LSB (1U << 16) /* 16b */ /* SRC_DDREN_STA (0x10006000+0x1E0) */ #define SRC_DDREN_STA_LSB (1U << 0) /* 32b */ /* MCU_PWR_CON (0x10006000+0x200) */ #define MCU_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MCU_PWR_ISO_LSB (1U << 1) /* 1b */ #define MCU_PWR_ON_LSB (1U << 2) /* 1b */ #define MCU_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MCU_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MCU_SRAM_CKISO_LSB (1U << 5) /* 1b */ #define MCU_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */ #define MCU_SRAM_PD_SLPB_CLAMP_LSB (1U << 7) /* 1b */ #define MCU_SRAM_PDN_LSB (1U << 8) /* 1b */ #define MCU_SRAM_SLEEP_B_LSB (1U << 12) /* 1b */ #define SC_MCU_SRAM_PDN_ACK_LSB (1U << 24) /* 1b */ #define SC_MCU_SRAM_SLEEP_B_ACK_LSB (1U << 28) /* 1b */ /* MP0_CPUTOP_PWR_CON (0x10006000+0x204) */ #define MP0_CPUTOP_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MP0_CPUTOP_PWR_ISO_LSB (1U << 1) /* 1b */ #define MP0_CPUTOP_PWR_ON_LSB (1U << 2) /* 1b */ #define MP0_CPUTOP_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MP0_CPUTOP_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MP0_CPUTOP_SRAM_CKISO_LSB (1U << 5) /* 1b */ #define MP0_CPUTOP_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */ #define MP0_CPUTOP_SRAM_PD_SLPB_CLAMP_LSB (1U << 7) /* 1b */ #define MP0_CPUTOP_SRAM_PDN_LSB (1U << 8) /* 1b */ #define MP0_CPUTOP_SRAM_SLEEP_B_LSB (1U << 12) /* 1b */ #define SC_MP0_CPUTOP_SRAM_PDN_ACK_LSB (1U << 24) /* 1b */ #define SC_MP0_CPUTOP_SRAM_SLEEP_B_ACK_LSB (1U << 28) /* 1b */ /* MP0_CPU0_PWR_CON (0x10006000+0x208) */ #define MP0_CPU0_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MP0_CPU0_PWR_ISO_LSB (1U << 1) /* 1b */ #define MP0_CPU0_PWR_ON_LSB (1U << 2) /* 1b */ #define MP0_CPU0_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MP0_CPU0_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MP0_CPU0_SRAM_CKISO_LSB (1U << 5) /* 1b */ #define MP0_CPU0_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */ #define MP0_CPU0_SRAM_PD_SLPB_CLAMP_LSB (1U << 7) /* 1b */ #define MP0_CPU0_SRAM_PDN_LSB (1U << 8) /* 1b */ #define MP0_CPU0_SRAM_SLEEP_B_LSB (1U << 12) /* 1b */ #define SC_MP0_CPU0_SRAM_PDN_ACK_LSB (1U << 24) /* 1b */ #define SC_MP0_CPU0_SRAM_SLEEP_B_ACK_LSB (1U << 28) /* 1b */ /* MP0_CPU1_PWR_CON (0x10006000+0x20C) */ #define MP0_CPU1_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MP0_CPU1_PWR_ISO_LSB (1U << 1) /* 1b */ #define MP0_CPU1_PWR_ON_LSB (1U << 2) /* 1b */ #define MP0_CPU1_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MP0_CPU1_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MP0_CPU1_SRAM_CKISO_LSB (1U << 5) /* 1b */ #define MP0_CPU1_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */ #define MP0_CPU1_SRAM_PD_SLPB_CLAMP_LSB (1U << 7) /* 1b */ #define MP0_CPU1_SRAM_PDN_LSB (1U << 8) /* 1b */ #define MP0_CPU1_SRAM_SLEEP_B_LSB (1U << 12) /* 1b */ #define SC_MP0_CPU1_SRAM_PDN_ACK_LSB (1U << 24) /* 1b */ #define SC_MP0_CPU1_SRAM_SLEEP_B_ACK_LSB (1U << 28) /* 1b */ /* MP0_CPU2_PWR_CON (0x10006000+0x210) */ #define MP0_CPU2_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MP0_CPU2_PWR_ISO_LSB (1U << 1) /* 1b */ #define MP0_CPU2_PWR_ON_LSB (1U << 2) /* 1b */ #define MP0_CPU2_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MP0_CPU2_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MP0_CPU2_SRAM_CKISO_LSB (1U << 5) /* 1b */ #define MP0_CPU2_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */ #define MP0_CPU2_SRAM_PD_SLPB_CLAMP_LSB (1U << 7) /* 1b */ #define MP0_CPU2_SRAM_PDN_LSB (1U << 8) /* 1b */ #define MP0_CPU2_SRAM_SLEEP_B_LSB (1U << 12) /* 1b */ #define SC_MP0_CPU2_SRAM_PDN_ACK_LSB (1U << 24) /* 1b */ #define SC_MP0_CPU2_SRAM_SLEEP_B_ACK_LSB (1U << 28) /* 1b */ /* MP0_CPU3_PWR_CON (0x10006000+0x214) */ #define MP0_CPU3_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MP0_CPU3_PWR_ISO_LSB (1U << 1) /* 1b */ #define MP0_CPU3_PWR_ON_LSB (1U << 2) /* 1b */ #define MP0_CPU3_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MP0_CPU3_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MP0_CPU3_SRAM_CKISO_LSB (1U << 5) /* 1b */ #define MP0_CPU3_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */ #define MP0_CPU3_SRAM_PD_SLPB_CLAMP_LSB (1U << 7) /* 1b */ #define MP0_CPU3_SRAM_PDN_LSB (1U << 8) /* 1b */ #define MP0_CPU3_SRAM_SLEEP_B_LSB (1U << 12) /* 1b */ #define SC_MP0_CPU3_SRAM_PDN_ACK_LSB (1U << 24) /* 1b */ #define SC_MP0_CPU3_SRAM_SLEEP_B_ACK_LSB (1U << 28) /* 1b */ /* MP1_CPUTOP_PWR_CON (0x10006000+0x218) */ #define MP1_CPUTOP_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MP1_CPUTOP_PWR_ISO_LSB (1U << 1) /* 1b */ #define MP1_CPUTOP_PWR_ON_LSB (1U << 2) /* 1b */ #define MP1_CPUTOP_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MP1_CPUTOP_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MP1_CPUTOP_SRAM_CKISO_LSB (1U << 5) /* 1b */ #define MP1_CPUTOP_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */ #define MP1_CPUTOP_SRAM_PD_SLPB_CLAMP_LSB (1U << 7) /* 1b */ #define MP1_CPUTOP_SRAM_PDN_LSB (1U << 8) /* 1b */ #define MP1_CPUTOP_SRAM_SLEEP_B_LSB (1U << 12) /* 1b */ #define SC_MP1_CPUTOP_SRAM_PDN_ACK_LSB (1U << 24) /* 1b */ #define SC_MP1_CPUTOP_SRAM_SLEEP_B_ACK_LSB (1U << 28) /* 1b */ /* MP1_CPU0_PWR_CON (0x10006000+0x21C) */ #define MP1_CPU0_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MP1_CPU0_PWR_ISO_LSB (1U << 1) /* 1b */ #define MP1_CPU0_PWR_ON_LSB (1U << 2) /* 1b */ #define MP1_CPU0_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MP1_CPU0_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MP1_CPU0_SRAM_CKISO_LSB (1U << 5) /* 1b */ #define MP1_CPU0_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */ #define MP1_CPU0_SRAM_PD_SLPB_CLAMP_LSB (1U << 7) /* 1b */ #define MP1_CPU0_SRAM_PDN_LSB (1U << 8) /* 1b */ #define MP1_CPU0_SRAM_SLEEP_B_LSB (1U << 12) /* 1b */ #define SC_MP1_CPU0_SRAM_PDN_ACK_LSB (1U << 24) /* 1b */ #define SC_MP1_CPU0_SRAM_SLEEP_B_ACK_LSB (1U << 28) /* 1b */ /* MP1_CPU1_PWR_CON (0x10006000+0x220) */ #define MP1_CPU1_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MP1_CPU1_PWR_ISO_LSB (1U << 1) /* 1b */ #define MP1_CPU1_PWR_ON_LSB (1U << 2) /* 1b */ #define MP1_CPU1_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MP1_CPU1_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MP1_CPU1_SRAM_CKISO_LSB (1U << 5) /* 1b */ #define MP1_CPU1_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */ #define MP1_CPU1_SRAM_PD_SLPB_CLAMP_LSB (1U << 7) /* 1b */ #define MP1_CPU1_SRAM_PDN_LSB (1U << 8) /* 1b */ #define MP1_CPU1_SRAM_SLEEP_B_LSB (1U << 12) /* 1b */ #define SC_MP1_CPU1_SRAM_PDN_ACK_LSB (1U << 24) /* 1b */ #define SC_MP1_CPU1_SRAM_SLEEP_B_ACK_LSB (1U << 28) /* 1b */ /* MP1_CPU2_PWR_CON (0x10006000+0x224) */ #define MP1_CPU2_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MP1_CPU2_PWR_ISO_LSB (1U << 1) /* 1b */ #define MP1_CPU2_PWR_ON_LSB (1U << 2) /* 1b */ #define MP1_CPU2_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MP1_CPU2_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MP1_CPU2_SRAM_CKISO_LSB (1U << 5) /* 1b */ #define MP1_CPU2_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */ #define MP1_CPU2_SRAM_PD_SLPB_CLAMP_LSB (1U << 7) /* 1b */ #define MP1_CPU2_SRAM_PDN_LSB (1U << 8) /* 1b */ #define MP1_CPU2_SRAM_SLEEP_B_LSB (1U << 12) /* 1b */ #define SC_MP1_CPU2_SRAM_PDN_ACK_LSB (1U << 24) /* 1b */ #define SC_MP1_CPU2_SRAM_SLEEP_B_ACK_LSB (1U << 28) /* 1b */ /* MP1_CPU3_PWR_CON (0x10006000+0x228) */ #define MP1_CPU3_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MP1_CPU3_PWR_ISO_LSB (1U << 1) /* 1b */ #define MP1_CPU3_PWR_ON_LSB (1U << 2) /* 1b */ #define MP1_CPU3_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MP1_CPU3_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MP1_CPU3_SRAM_CKISO_LSB (1U << 5) /* 1b */ #define MP1_CPU3_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */ #define MP1_CPU3_SRAM_PD_SLPB_CLAMP_LSB (1U << 7) /* 1b */ #define MP1_CPU3_SRAM_PDN_LSB (1U << 8) /* 1b */ #define MP1_CPU3_SRAM_SLEEP_B_LSB (1U << 12) /* 1b */ #define SC_MP1_CPU3_SRAM_PDN_ACK_LSB (1U << 24) /* 1b */ #define SC_MP1_CPU3_SRAM_SLEEP_B_ACK_LSB (1U << 28) /* 1b */ /* MP0_CPUTOP_L2_PDN (0x10006000+0x240) */ #define MP0_CPUTOP_L2_SRAM_PDN_LSB (1U << 0) /* 1b */ #define MP0_CPUTOP_L2_SRAM_PDN_ACK_LSB (1U << 8) /* 1b */ /* MP0_CPUTOP_L2_SLEEP_B (0x10006000+0x244) */ #define MP0_CPUTOP_L2_SRAM_SLEEP_B_LSB (1U << 0) /* 1b */ #define MP0_CPUTOP_L2_SRAM_SLEEP_B_ACK_LSB (1U << 8) /* 1b */ /* MP0_CPU0_L1_PDN (0x10006000+0x248) */ #define MP0_CPU0_L1_PDN_LSB (1U << 0) /* 1b */ #define MP0_CPU0_L1_PDN_ACK_LSB (1U << 8) /* 1b */ /* MP0_CPU1_L1_PDN (0x10006000+0x24C) */ #define MP0_CPU1_L1_PDN_LSB (1U << 0) /* 1b */ #define MP0_CPU1_L1_PDN_ACK_LSB (1U << 8) /* 1b */ /* MP0_CPU2_L1_PDN (0x10006000+0x250) */ #define MP0_CPU2_L1_PDN_LSB (1U << 0) /* 1b */ #define MP0_CPU2_L1_PDN_ACK_LSB (1U << 8) /* 1b */ /* MP0_CPU3_L1_PDN (0x10006000+0x254) */ #define MP0_CPU3_L1_PDN_LSB (1U << 0) /* 1b */ #define MP0_CPU3_L1_PDN_ACK_LSB (1U << 8) /* 1b */ /* MP1_CPUTOP_L2_PDN (0x10006000+0x258) */ #define MP1_CPUTOP_L2_SRAM_PDN_LSB (1U << 0) /* 1b */ #define MP1_CPUTOP_L2_SRAM_PDN_ACK_LSB (1U << 8) /* 1b */ /* MP1_CPUTOP_L2_SLEEP_B (0x10006000+0x25C) */ #define MP1_CPUTOP_L2_SRAM_SLEEP_B_LSB (1U << 0) /* 1b */ #define MP1_CPUTOP_L2_SRAM_SLEEP_B_ACK_LSB (1U << 8) /* 1b */ /* MP1_CPU0_L1_PDN (0x10006000+0x260) */ #define MP1_CPU0_L1_PDN_LSB (1U << 0) /* 1b */ #define MP1_CPU0_L1_PDN_ACK_LSB (1U << 8) /* 1b */ /* MP1_CPU1_L1_PDN (0x10006000+0x264) */ #define MP1_CPU1_L1_PDN_LSB (1U << 0) /* 1b */ #define MP1_CPU1_L1_PDN_ACK_LSB (1U << 8) /* 1b */ /* MP1_CPU2_L1_PDN (0x10006000+0x268) */ #define MP1_CPU2_L1_PDN_LSB (1U << 0) /* 1b */ #define MP1_CPU2_L1_PDN_ACK_LSB (1U << 8) /* 1b */ /* MP1_CPU3_L1_PDN (0x10006000+0x26C) */ #define MP1_CPU3_L1_PDN_LSB (1U << 0) /* 1b */ #define MP1_CPU3_L1_PDN_ACK_LSB (1U << 8) /* 1b */ /* CPU_EXT_BUCK_ISO (0x10006000+0x290) */ #define MP0_EXT_BUCK_ISO_LSB (1U << 0) /* 1b */ #define MP1_EXT_BUCK_ISO_LSB (1U << 1) /* 1b */ #define MP_EXT_BUCK_ISO_LSB (1U << 2) /* 1b */ /* DUMMY1_PWR_CON (0x10006000+0x2B0) */ #define DUMMY1_PWR_RST_B_LSB (1U << 0) /* 1b */ #define DUMMY1_PWR_ISO_LSB (1U << 1) /* 1b */ #define DUMMY1_PWR_ON_LSB (1U << 2) /* 1b */ #define DUMMY1_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define DUMMY1_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ /* BYPASS_SPMC (0x10006000+0x2B4) */ #define BYPASS_CPU_SPMC_MODE_LSB (1U << 0) /* 1b */ /* SPMC_DORMANT_ENABLE (0x10006000+0x2B8) */ #define MP0_SPMC_SRAM_DORMANT_EN_LSB (1U << 0) /* 1b */ #define MP1_SPMC_SRAM_DORMANT_EN_LSB (1U << 1) /* 1b */ /* ARMPLL_CLK_CON (0x10006000+0x2BC) */ #define REG_SC_ARM_FHC_PAUSE_LSB (1U << 0) /* 3b */ #define REG_SC_ARM_CLK_OFF_LSB (1U << 3) /* 3b */ #define REG_SC_ARMPLLOUT_OFF_LSB (1U << 6) /* 3b */ #define REG_SC_ARMPLL_OFF_LSB (1U << 9) /* 3b */ #define REG_SC_ARMPLL_S_OFF_LSB (1U << 12) /* 3b */ /* SPMC_IN_RET (0x10006000+0x2C0) */ #define SPMC_STATUS_LSB (1U << 0) /* 8b */ /* VDE_PWR_CON (0x10006000+0x300) */ #define VDE_PWR_RST_B_LSB (1U << 0) /* 1b */ #define VDE_PWR_ISO_LSB (1U << 1) /* 1b */ #define VDE_PWR_ON_LSB (1U << 2) /* 1b */ #define VDE_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define VDE_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define VDE_SRAM_PDN_LSB (1U << 8) /* 4b */ #define VDE_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ /* VEN_PWR_CON (0x10006000+0x304) */ #define VEN_PWR_RST_B_LSB (1U << 0) /* 1b */ #define VEN_PWR_ISO_LSB (1U << 1) /* 1b */ #define VEN_PWR_ON_LSB (1U << 2) /* 1b */ #define VEN_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define VEN_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define VEN_SRAM_PDN_LSB (1U << 8) /* 4b */ #define VEN_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ /* ISP_PWR_CON (0x10006000+0x308) */ #define ISP_PWR_RST_B_LSB (1U << 0) /* 1b */ #define ISP_PWR_ISO_LSB (1U << 1) /* 1b */ #define ISP_PWR_ON_LSB (1U << 2) /* 1b */ #define ISP_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define ISP_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define ISP_SRAM_PDN_LSB (1U << 8) /* 4b */ #define ISP_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ /* DIS_PWR_CON (0x10006000+0x30C) */ #define DIS_PWR_RST_B_LSB (1U << 0) /* 1b */ #define DIS_PWR_ISO_LSB (1U << 1) /* 1b */ #define DIS_PWR_ON_LSB (1U << 2) /* 1b */ #define DIS_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define DIS_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define DIS_SRAM_PDN_LSB (1U << 8) /* 4b */ #define DIS_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ /* MFG_CORE1_PWR_CON (0x10006000+0x310) */ #define MFG_CORE1_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MFG_CORE1_PWR_ISO_LSB (1U << 1) /* 1b */ #define MFG_CORE1_PWR_ON_LSB (1U << 2) /* 1b */ #define MFG_CORE1_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MFG_CORE1_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MFG_CORE1_SRAM_PDN_LSB (1U << 8) /* 4b */ #define MFG_CORE1_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ /* AUDIO_PWR_CON (0x10006000+0x314) */ #define AUD_PWR_RST_B_LSB (1U << 0) /* 1b */ #define AUD_PWR_ISO_LSB (1U << 1) /* 1b */ #define AUD_PWR_ON_LSB (1U << 2) /* 1b */ #define AUD_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define AUD_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define AUD_SRAM_PDN_LSB (1U << 8) /* 4b */ #define AUD_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ /* IFR_PWR_CON (0x10006000+0x318) */ #define IFR_PWR_RST_B_LSB (1U << 0) /* 1b */ #define IFR_PWR_ISO_LSB (1U << 1) /* 1b */ #define IFR_PWR_ON_LSB (1U << 2) /* 1b */ #define IFR_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define IFR_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define IFR_SRAM_PDN_LSB (1U << 8) /* 4b */ #define IFR_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ /* DPY_PWR_CON (0x10006000+0x31C) */ #define DPY_PWR_RST_B_LSB (1U << 0) /* 1b */ #define DPY_PWR_ISO_LSB (1U << 1) /* 1b */ #define DPY_PWR_ON_LSB (1U << 2) /* 1b */ #define DPY_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define DPY_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define DPY_SRAM_PDN_LSB (1U << 8) /* 4b */ #define DPY_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ /* MD1_PWR_CON (0x10006000+0x320) */ #define MD1_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MD1_PWR_ISO_LSB (1U << 1) /* 1b */ #define MD1_PWR_ON_LSB (1U << 2) /* 1b */ #define MD1_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MD1_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MD1_SRAM_PDN_LSB (1U << 8) /* 1b */ /* VPU_TOP_PWR_CON (0x10006000+0x324) */ #define VPU_TOP_PWR_RST_B_LSB (1U << 0) /* 1b */ #define VPU_TOP_PWR_ISO_LSB (1U << 1) /* 1b */ #define VPU_TOP_PWR_ON_LSB (1U << 2) /* 1b */ #define VPU_TOP_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define VPU_TOP_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define VPU_TOP_SRAM_CKISO_LSB (1U << 5) /* 1b */ #define VPU_TOP_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */ #define VPU_TOP_SRAM_PDN_LSB (1U << 8) /* 4b */ #define VPU_TOP_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ #define VPU_TOP_SRAM_SLPB_LSB (1U << 16) /* 4b */ #define VPU_TOP_SRAM_SLPB_ACK_LSB (1U << 28) /* 4b */ /* CONN_PWR_CON (0x10006000+0x32C) */ #define CONN_PWR_RST_B_LSB (1U << 0) /* 1b */ #define CONN_PWR_ISO_LSB (1U << 1) /* 1b */ #define CONN_PWR_ON_LSB (1U << 2) /* 1b */ #define CONN_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define CONN_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define CONN_SRAM_PDN_LSB (1U << 8) /* 1b */ #define CONN_SRAM_PDN_ACK_LSB (1U << 12) /* 1b */ /* VPU_CORE2_PWR_CON (0x10006000+0x330) */ #define VPU_CORE2_PWR_RST_B_LSB (1U << 0) /* 1b */ #define VPU_CORE2_PWR_ISO_LSB (1U << 1) /* 1b */ #define VPU_CORE2_PWR_ON_LSB (1U << 2) /* 1b */ #define VPU_CORE2_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define VPU_CORE2_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define VPU_CORE2_SRAM_CKISO_LSB (1U << 5) /* 1b */ #define VPU_CORE2_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */ #define VPU_CORE2_SRAM_PDN_LSB (1U << 8) /* 4b */ #define VPU_CORE2_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ #define VPU_CORE2_SRAM_SLPB_LSB (1U << 16) /* 4b */ #define VPU_CORE2_SRAM_SLPB_ACK_LSB (1U << 28) /* 4b */ /* MFG_ASYNC_PWR_CON (0x10006000+0x334) */ #define MFG_ASYNC_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MFG_ASYNC_PWR_ISO_LSB (1U << 1) /* 1b */ #define MFG_ASYNC_PWR_ON_LSB (1U << 2) /* 1b */ #define MFG_ASYNC_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MFG_ASYNC_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MFG_ASYNC_SRAM_PDN_LSB (1U << 8) /* 4b */ #define MFG_ASYNC_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ /* MFG_PWR_CON (0x10006000+0x338) */ #define MFG_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MFG_PWR_ISO_LSB (1U << 1) /* 1b */ #define MFG_PWR_ON_LSB (1U << 2) /* 1b */ #define MFG_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MFG_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MFG_SRAM_PDN_LSB (1U << 8) /* 4b */ #define MFG_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ /* VPU_CORE0_PWR_CON (0x10006000+0x33C) */ #define VPU_CORE0_PWR_RST_B_LSB (1U << 0) /* 1b */ #define VPU_CORE0_PWR_ISO_LSB (1U << 1) /* 1b */ #define VPU_CORE0_PWR_ON_LSB (1U << 2) /* 1b */ #define VPU_CORE0_ON_2ND_LSB (1U << 3) /* 1b */ #define VPU_CORE0_CLK_DIS_LSB (1U << 4) /* 1b */ #define VPU_CORE0_SRAM_CKISO_LSB (1U << 5) /* 1b */ #define VPU_CORE0_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */ #define VPU_CORE0_SRAM_PDN_LSB (1U << 8) /* 4b */ #define VPU_CORE0_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ #define VPU_CORE0_SRAM_SLPB_LSB (1U << 16) /* 4b */ #define VPU_CORE0_SRAM_SLPB_ACK_LSB (1U << 28) /* 4b */ /* VPU_CORE1_PWR_CON (0x10006000+0x340) */ #define VPU_CORE1_PWR_RST_B_LSB (1U << 0) /* 1b */ #define VPU_CORE1_PWR_ISO_LSB (1U << 1) /* 1b */ #define VPU_CORE1_PWR_ON_LSB (1U << 2) /* 1b */ #define VPU_CORE1_ON_2ND_LSB (1U << 3) /* 1b */ #define VPU_CORE1_CLK_DIS_LSB (1U << 4) /* 1b */ #define VPU_CORE1_SRAM_CKISO_LSB (1U << 5) /* 1b */ #define VPU_CORE1_SRAM_ISOINT_B_LSB (1U << 6) /* 1b */ #define VPU_CORE1_SRAM_PDN_LSB (1U << 8) /* 4b */ #define VPU_CORE1_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ #define VPU_CORE1_SRAM_SLPB_LSB (1U << 16) /* 4b */ #define VPU_CORE1_SRAM_SLPB_ACK_LSB (1U << 28) /* 4b */ /* CAM_PWR_CON (0x10006000+0x344) */ #define CAM_PWR_RST_B_LSB (1U << 0) /* 1b */ #define CAM_PWR_ISO_LSB (1U << 1) /* 1b */ #define CAM_PWR_ON_LSB (1U << 2) /* 1b */ #define CAM_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define CAM_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define CAM_SRAM_PDN_LSB (1U << 8) /* 4b */ #define CAM_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ /* MFG_2D_PWR_CON (0x10006000+0x348) */ #define MFG_2D_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MFG_2D_PWR_ISO_LSB (1U << 1) /* 1b */ #define MFG_2D_PWR_ON_LSB (1U << 2) /* 1b */ #define MFG_2D_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MFG_2D_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MFG_2D_SRAM_PDN_LSB (1U << 8) /* 4b */ #define MFG_2D_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ /* MFG_CORE0_PWR_CON (0x10006000+0x34C) */ #define MFG_CORE0_PWR_RST_B_LSB (1U << 0) /* 1b */ #define MFG_CORE0_PWR_ISO_LSB (1U << 1) /* 1b */ #define MFG_CORE0_PWR_ON_LSB (1U << 2) /* 1b */ #define MFG_CORE0_PWR_ON_2ND_LSB (1U << 3) /* 1b */ #define MFG_CORE0_PWR_CLK_DIS_LSB (1U << 4) /* 1b */ #define MFG_CORE0_SRAM_PDN_LSB (1U << 8) /* 4b */ #define MFG_CORE0_SRAM_PDN_ACK_LSB (1U << 12) /* 4b */ /* SYSRAM_CON (0x10006000+0x350) */ #define IFR_SRAMROM_SRAM_CKISO_LSB (1U << 0) /* 1b */ #define IFR_SRAMROM_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */ #define IFR_SRAMROM_SRAM_SLEEP_B_LSB (1U << 4) /* 8b */ #define IFR_SRAMROM_SRAM_PDN_LSB (1U << 16) /* 8b */ /* SYSROM_CON (0x10006000+0x354) */ #define IFR_SRAMROM_ROM_PDN_LSB (1U << 0) /* 6b */ /* SSPM_SRAM_CON (0x10006000+0x358) */ #define SSPM_SRAM_CKISO_LSB (1U << 0) /* 1b */ #define SSPM_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */ #define SSPM_SRAM_SLEEP_B_LSB (1U << 4) /* 1b */ #define SSPM_SRAM_PDN_LSB (1U << 16) /* 1b */ /* SCP_SRAM_CON (0x10006000+0x35C) */ #define SCP_SRAM_CKISO_LSB (1U << 0) /* 1b */ #define SCP_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */ #define SCP_SRAM_SLEEP_B_LSB (1U << 4) /* 1b */ #define SCP_SRAM_PDN_LSB (1U << 16) /* 1b */ /* UFS_SRAM_CON (0x10006000+0x36C) */ #define UFS_SRAM_CKISO_LSB (1U << 0) /* 1b */ #define UFS_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */ #define UFS_SRAM_SLEEP_B_LSB (1U << 4) /* 5b */ #define UFS_SRAM_PDN_LSB (1U << 16) /* 5b */ /* DUMMY_SRAM_CON (0x10006000+0x380) */ #define DUMMY_SRAM_CKISO_LSB (1U << 0) /* 1b */ #define DUMMY_SRAM_ISOINT_B_LSB (1U << 1) /* 1b */ #define DUMMY_SRAM_SLEEP_B_LSB (1U << 4) /* 8b */ #define DUMMY_SRAM_PDN_LSB (1U << 16) /* 8b */ /* MD_EXT_BUCK_ISO_CON (0x10006000+0x390) */ #define VMODEM_BUCK_ELS_EN_LSB (1U << 0) /* 1b */ #define VMD_BUCK_ELS_EN_LSB (1U << 1) /* 1b */ /* MD_SRAM_ISO_CON (0x10006000+0x394) */ #define MD1_SRAM_ISOINT_B_LSB (1U << 0) /* 1b */ /* MD_EXTRA_PWR_CON (0x10006000+0x398) */ #define MD1_PWR_PROT_REQ_STA_LSB (1U << 0) /* 1b */ #define MD2_PWR_PROT_REQ_STA_LSB (1U << 1) /* 1b */ /* EXT_BUCK_CON (0x10006000+0x3A0) */ #define RG_VA09_ON_LSB (1U << 0) /* 1b */ /* MBIST_EFUSE_REPAIR_ACK_STA (0x10006000+0x3D0) */ #define MBIST_EFUSE_REPAIR_ACK_STA_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CON (0x10006000+0x400) */ #define SPM_DVFS_CON_LSB (1U << 0) /* 4b */ #define SPM_DVFS_ACK_LSB (1U << 30) /* 2b */ /* SPM_MDBSI_CON (0x10006000+0x404) */ #define SPM_MDBSI_CON_LSB (1U << 0) /* 3b */ /* SPM_MAS_PAUSE_MASK_B (0x10006000+0x408) */ #define SPM_MAS_PAUSE_MASK_B_LSB (1U << 0) /* 32b */ /* SPM_MAS_PAUSE2_MASK_B (0x10006000+0x40C) */ #define SPM_MAS_PAUSE2_MASK_B_LSB (1U << 0) /* 32b */ /* SPM_BSI_GEN (0x10006000+0x410) */ #define SPM_BSI_START_LSB (1U << 0) /* 1b */ /* SPM_BSI_EN_SR (0x10006000+0x414) */ #define SPM_BSI_EN_SR_LSB (1U << 0) /* 32b */ /* SPM_BSI_CLK_SR (0x10006000+0x418) */ #define SPM_BSI_CLK_SR_LSB (1U << 0) /* 32b */ /* SPM_BSI_D0_SR (0x10006000+0x41C) */ #define SPM_BSI_D0_SR_LSB (1U << 0) /* 32b */ /* SPM_BSI_D1_SR (0x10006000+0x420) */ #define SPM_BSI_D1_SR_LSB (1U << 0) /* 32b */ /* SPM_BSI_D2_SR (0x10006000+0x424) */ #define SPM_BSI_D2_SR_LSB (1U << 0) /* 32b */ /* SPM_AP_SEMA (0x10006000+0x428) */ #define SPM_AP_SEMA_LSB (1U << 0) /* 1b */ /* SPM_SPM_SEMA (0x10006000+0x42C) */ #define SPM_SPM_SEMA_LSB (1U << 0) /* 1b */ /* AP_MDSRC_REQ (0x10006000+0x430) */ #define AP_MDSMSRC_REQ_LSB (1U << 0) /* 1b */ #define AP_L1SMSRC_REQ_LSB (1U << 1) /* 1b */ #define AP_MD2SRC_REQ_LSB (1U << 2) /* 1b */ #define AP_MDSMSRC_ACK_LSB (1U << 4) /* 1b */ #define AP_L1SMSRC_ACK_LSB (1U << 5) /* 1b */ #define AP_MD2SRC_ACK_LSB (1U << 6) /* 1b */ /* SPM2MD_DVFS_CON (0x10006000+0x438) */ #define SPM2MD_DVFS_CON_LSB (1U << 0) /* 32b */ /* MD2SPM_DVFS_CON (0x10006000+0x43C) */ #define MD2SPM_DVFS_CON_LSB (1U << 0) /* 32b */ /* DRAMC_DPY_CLK_SW_CON_RSV (0x10006000+0x440) */ #define SPM2DRAMC_SHUFFLE_START_LSB (1U << 0) /* 1b */ #define SPM2DRAMC_SHUFFLE_SWITCH_LSB (1U << 1) /* 1b */ #define SPM2DPY_DIV2_SYNC_LSB (1U << 2) /* 1b */ #define SPM2DPY_1PLL_SWITCH_LSB (1U << 3) /* 1b */ #define SPM2DPY_TEST_CK_MUX_LSB (1U << 4) /* 1b */ #define SPM2DPY_ASYNC_MODE_LSB (1U << 5) /* 1b */ #define SPM2TOP_ASYNC_MODE_LSB (1U << 6) /* 1b */ /* DPY_LP_CON (0x10006000+0x444) */ #define SC_DDRPHY_LP_SIGNALS_LSB (1U << 0) /* 3b */ /* CPU_DVFS_REQ (0x10006000+0x448) */ #define CPU_DVFS_REQ_LSB (1U << 0) /* 32b */ /* SPM_PLL_CON (0x10006000+0x44C) */ #define SC_MAINPLLOUT_OFF_LSB (1U << 0) /* 1b */ #define SC_UNIPLLOUT_OFF_LSB (1U << 1) /* 1b */ #define SC_MAINPLL_OFF_LSB (1U << 4) /* 1b */ #define SC_UNIPLL_OFF_LSB (1U << 5) /* 1b */ #define SC_MAINPLL_S_OFF_LSB (1U << 8) /* 1b */ #define SC_UNIPLL_S_OFF_LSB (1U << 9) /* 1b */ #define SC_SMI_CK_OFF_LSB (1U << 16) /* 1b */ #define SC_SSPMK_CK_OFF_LSB (1U << 17) /* 1b */ /* SPM_EMI_BW_MODE (0x10006000+0x450) */ #define EMI_BW_MODE_LSB (1U << 0) /* 1b */ #define EMI_BOOST_MODE_LSB (1U << 1) /* 1b */ #define EMI_BW_MODE_2_LSB (1U << 2) /* 1b */ #define EMI_BOOST_MODE_2_LSB (1U << 3) /* 1b */ /* AP2MD_PEER_WAKEUP (0x10006000+0x454) */ #define AP2MD_PEER_WAKEUP_LSB (1U << 0) /* 1b */ /* ULPOSC_CON (0x10006000+0x458) */ #define ULPOSC_EN_LSB (1U << 0) /* 1b */ #define ULPOSC_RST_LSB (1U << 1) /* 1b */ #define ULPOSC_CG_EN_LSB (1U << 2) /* 1b */ #define ULPOSC_CLK_SEL_LSB (1U << 3) /* 1b */ /* SPM2MM_CON (0x10006000+0x45C) */ #define SPM2MM_FORCE_ULTRA_LSB (1U << 0) /* 1b */ #define SPM2MM_DBL_OSTD_ACT_LSB (1U << 1) /* 1b */ #define SPM2MM_ULTRAREQ_LSB (1U << 2) /* 1b */ #define SPM2MD_ULTRAREQ_LSB (1U << 3) /* 1b */ #define SPM2ISP_ULTRAREQ_LSB (1U << 4) /* 1b */ #define MM2SPM_FORCE_ULTRA_ACK_LSB (1U << 16) /* 1b */ #define MM2SPM_DBL_OSTD_ACT_ACK_LSB (1U << 17) /* 1b */ #define SPM2ISP_ULTRAACK_D2T_LSB (1U << 18) /* 1b */ #define SPM2MM_ULTRAACK_D2T_LSB (1U << 19) /* 1b */ #define SPM2MD_ULTRAACK_D2T_LSB (1U << 20) /* 1b */ /* DRAMC_DPY_CLK_SW_CON_SEL (0x10006000+0x460) */ #define SW_DR_GATE_RETRY_EN_SEL_LSB (1U << 0) /* 2b */ #define SW_EMI_CLK_OFF_SEL_LSB (1U << 2) /* 2b */ #define SW_DPY_MODE_SW_SEL_LSB (1U << 4) /* 2b */ #define SW_DMSUS_OFF_SEL_LSB (1U << 6) /* 2b */ #define SW_MEM_CK_OFF_SEL_LSB (1U << 8) /* 2b */ #define SW_DPY_2ND_DLL_EN_SEL_LSB (1U << 10) /* 2b */ #define SW_DPY_DLL_EN_SEL_LSB (1U << 12) /* 2b */ #define SW_DPY_DLL_CK_EN_SEL_LSB (1U << 14) /* 2b */ #define SW_DPY_VREF_EN_SEL_LSB (1U << 16) /* 2b */ #define SW_PHYPLL_EN_SEL_LSB (1U << 18) /* 2b */ #define SW_DDRPHY_FB_CK_EN_SEL_LSB (1U << 20) /* 2b */ #define SEPERATE_PHY_PWR_SEL_LSB (1U << 23) /* 1b */ #define SW_DMDRAMCSHU_ACK_SEL_LSB (1U << 24) /* 2b */ #define SW_EMI_CLK_OFF_ACK_SEL_LSB (1U << 26) /* 2b */ #define SW_DR_SHORT_QUEUE_ACK_SEL_LSB (1U << 28) /* 2b */ #define SW_DRAMC_DFS_STA_SEL_LSB (1U << 30) /* 2b */ /* DRAMC_DPY_CLK_SW_CON (0x10006000+0x464) */ #define SW_DR_GATE_RETRY_EN_LSB (1U << 0) /* 2b */ #define SW_EMI_CLK_OFF_LSB (1U << 2) /* 2b */ #define SW_DPY_MODE_SW_LSB (1U << 4) /* 2b */ #define SW_DMSUS_OFF_LSB (1U << 6) /* 2b */ #define SW_MEM_CK_OFF_LSB (1U << 8) /* 2b */ #define SW_DPY_2ND_DLL_EN_LSB (1U << 10) /* 2b */ #define SW_DPY_DLL_EN_LSB (1U << 12) /* 2b */ #define SW_DPY_DLL_CK_EN_LSB (1U << 14) /* 2b */ #define SW_DPY_VREF_EN_LSB (1U << 16) /* 2b */ #define SW_PHYPLL_EN_LSB (1U << 18) /* 2b */ #define SW_DDRPHY_FB_CK_EN_LSB (1U << 20) /* 2b */ #define SC_DR_SHU_EN_ACK_LSB (1U << 24) /* 2b */ #define EMI_CLK_OFF_ACK_LSB (1U << 26) /* 2b */ #define SC_DR_SHORT_QUEUE_ACK_LSB (1U << 28) /* 2b */ #define SC_DRAMC_DFS_STA_LSB (1U << 30) /* 2b */ /* SPM_S1_MODE_CH (0x10006000+0x468) */ #define SPM_S1_MODE_CH_LSB (1U << 0) /* 2b */ #define S1_EMI_CK_SWITCH_LSB (1U << 8) /* 2b */ /* EMI_SELF_REFRESH_CH_STA (0x10006000+0x46C) */ #define EMI_SELF_REFRESH_CH_LSB (1U << 0) /* 2b */ /* DRAMC_DPY_CLK_SW_CON_SEL2 (0x10006000+0x470) */ #define SW_PHYPLL_SHU_EN_SEL_LSB (1U << 0) /* 1b */ #define SW_PHYPLL2_SHU_EN_SEL_LSB (1U << 1) /* 1b */ #define SW_PHYPLL_MODE_SW_SEL_LSB (1U << 2) /* 1b */ #define SW_PHYPLL2_MODE_SW_SEL_LSB (1U << 3) /* 1b */ #define SW_DR_SHORT_QUEUE_SEL_LSB (1U << 4) /* 1b */ #define SW_DR_SHU_EN_SEL_LSB (1U << 5) /* 1b */ #define SW_DR_SHU_LEVEL_SEL_LSB (1U << 6) /* 1b */ #define SW_DPY_BCLK_ENABLE_SEL_LSB (1U << 8) /* 2b */ #define SW_SHU_RESTORE_SEL_LSB (1U << 10) /* 2b */ #define SW_DPHY_PRECAL_UP_SEL_LSB (1U << 12) /* 2b */ #define SW_DPHY_RXDLY_TRACK_EN_SEL_LSB (1U << 14) /* 2b */ #define SW_TX_TRACKING_DIS_SEL_LSB (1U << 16) /* 2b */ /* DRAMC_DPY_CLK_SW_CON2 (0x10006000+0x474) */ #define SW_PHYPLL_SHU_EN_LSB (1U << 0) /* 1b */ #define SW_PHYPLL2_SHU_EN_LSB (1U << 1) /* 1b */ #define SW_PHYPLL_MODE_SW_LSB (1U << 2) /* 1b */ #define SW_PHYPLL2_MODE_SW_LSB (1U << 3) /* 1b */ #define SW_DR_SHORT_QUEUE_LSB (1U << 4) /* 1b */ #define SW_DR_SHU_EN_LSB (1U << 5) /* 1b */ #define SW_DR_SHU_LEVEL_LSB (1U << 6) /* 2b */ #define SW_DPY_BCLK_ENABLE_LSB (1U << 8) /* 2b */ #define SW_SHU_RESTORE_LSB (1U << 10) /* 2b */ #define SW_DPHY_PRECAL_UP_LSB (1U << 12) /* 2b */ #define SW_DPHY_RXDLY_TRACK_EN_LSB (1U << 14) /* 2b */ #define SW_TX_TRACKING_DIS_LSB (1U << 16) /* 2b */ /* DRAMC_DMYRD_CON (0x10006000+0x478) */ #define DRAMC_DMYRD_EN_CH0_LSB (1U << 0) /* 1b */ #define DRAMC_DMYRD_INTV_SEL_CH0_LSB (1U << 1) /* 1b */ #define DRAMC_DMYRD_EN_MOD_SEL_CH0_LSB (1U << 2) /* 1b */ #define DRAMC_DMYRD_EN_CH1_LSB (1U << 8) /* 1b */ #define DRAMC_DMYRD_INTV_SEL_CH1_LSB (1U << 9) /* 1b */ #define DRAMC_DMYRD_EN_MOD_SEL_CH1_LSB (1U << 10) /* 1b */ /* SPM_DRS_CON (0x10006000+0x47C) */ #define SPM_DRS_DIS_REQ_CH0_LSB (1U << 0) /* 1b */ #define SPM_DRS_DIS_REQ_CH1_LSB (1U << 1) /* 1b */ #define SPM_DRS_DIS_ACK_CH0_LSB (1U << 8) /* 1b */ #define SPM_DRS_DIS_ACK_CH1_LSB (1U << 9) /* 1b */ /* SPM_SEMA_M0 (0x10006000+0x480) */ #define SPM_SEMA_M0_LSB (1U << 0) /* 8b */ /* SPM_SEMA_M1 (0x10006000+0x484) */ #define SPM_SEMA_M1_LSB (1U << 0) /* 8b */ /* SPM_SEMA_M2 (0x10006000+0x488) */ #define SPM_SEMA_M2_LSB (1U << 0) /* 8b */ /* SPM_SEMA_M3 (0x10006000+0x48C) */ #define SPM_SEMA_M3_LSB (1U << 0) /* 8b */ /* SPM_SEMA_M4 (0x10006000+0x490) */ #define SPM_SEMA_M4_LSB (1U << 0) /* 8b */ /* SPM_SEMA_M5 (0x10006000+0x494) */ #define SPM_SEMA_M5_LSB (1U << 0) /* 8b */ /* SPM_SEMA_M6 (0x10006000+0x498) */ #define SPM_SEMA_M6_LSB (1U << 0) /* 8b */ /* SPM_SEMA_M7 (0x10006000+0x49C) */ #define SPM_SEMA_M7_LSB (1U << 0) /* 8b */ /* SPM_MAS_PAUSE_MM_MASK_B (0x10006000+0x4A0) */ #define SPM_MAS_PAUSE_MM_MASK_B_LSB (1U << 0) /* 16b */ /* SPM_MAS_PAUSE_MCU_MASK_B (0x10006000+0x4A4) */ #define SPM_MAS_PAUSE_MCU_MASK_B_LSB (1U << 0) /* 16b */ /* SRAM_DREQ_ACK (0x10006000+0x4AC) */ #define SRAM_DREQ_ACK_LSB (1U << 0) /* 16b */ /* SRAM_DREQ_CON (0x10006000+0x4B0) */ #define SRAM_DREQ_CON_LSB (1U << 0) /* 16b */ /* SRAM_DREQ_CON_SET (0x10006000+0x4B4) */ #define SRAM_DREQ_CON_SET_LSB (1U << 0) /* 16b */ /* SRAM_DREQ_CON_CLR (0x10006000+0x4B8) */ #define SRAM_DREQ_CON_CLR_LSB (1U << 0) /* 16b */ /* SPM2EMI_ENTER_ULPM (0x10006000+0x4BC) */ #define SPM2EMI_ENTER_ULPM_LSB (1U << 0) /* 1b */ /* SPM_SSPM_IRQ (0x10006000+0x4C0) */ #define SPM_SSPM_IRQ_LSB (1U << 0) /* 1b */ #define SPM_SSPM_IRQ_SEL_LSB (1U << 4) /* 1b */ /* SPM2PMCU_INT (0x10006000+0x4C4) */ #define SPM2PMCU_INT_LSB (1U << 0) /* 4b */ /* SPM2PMCU_INT_SET (0x10006000+0x4C8) */ #define SPM2PMCU_INT_SET_LSB (1U << 0) /* 4b */ /* SPM2PMCU_INT_CLR (0x10006000+0x4CC) */ #define SPM2PMCU_INT_CLR_LSB (1U << 0) /* 4b */ /* SPM2PMCU_MAILBOX_0 (0x10006000+0x4D0) */ #define SPM2PMCU_MAILBOX_0_LSB (1U << 0) /* 32b */ /* SPM2PMCU_MAILBOX_1 (0x10006000+0x4D4) */ #define SPM2PMCU_MAILBOX_1_LSB (1U << 0) /* 32b */ /* SPM2PMCU_MAILBOX_2 (0x10006000+0x4D8) */ #define SPM2PMCU_MAILBOX_2_LSB (1U << 0) /* 32b */ /* SPM2PMCU_MAILBOX_3 (0x10006000+0x4DC) */ #define SPM2PMCU_MAILBOX_3_LSB (1U << 0) /* 32b */ /* PMCU2SPM_INT (0x10006000+0x4E0) */ #define PMCU2SPM_INT_LSB (1U << 0) /* 4b */ /* PMCU2SPM_INT_SET (0x10006000+0x4E4) */ #define PMCU2SPM_INT_SET_LSB (1U << 0) /* 4b */ /* PMCU2SPM_INT_CLR (0x10006000+0x4E8) */ #define PMCU2SPM_INT_CLR_LSB (1U << 0) /* 4b */ /* PMCU2SPM_MAILBOX_0 (0x10006000+0x4EC) */ #define PMCU2SPM_MAILBOX_0_LSB (1U << 0) /* 32b */ /* PMCU2SPM_MAILBOX_1 (0x10006000+0x4F0) */ #define PMCU2SPM_MAILBOX_1_LSB (1U << 0) /* 32b */ /* PMCU2SPM_MAILBOX_2 (0x10006000+0x4F4) */ #define PMCU2SPM_MAILBOX_2_LSB (1U << 0) /* 32b */ /* PMCU2SPM_MAILBOX_3 (0x10006000+0x4F8) */ #define PMCU2SPM_MAILBOX_3_LSB (1U << 0) /* 32b */ /* PMCU2SPM_CFG (0x10006000+0x4FC) */ #define PMCU2SPM_INT_MASK_B_LSB (1U << 0) /* 4b */ #define SPM_PMCU_MAILBOX_REQ_LSB (1U << 8) /* 1b */ /* MP0_CPU0_IRQ_MASK (0x10006000+0x500) */ #define MP0_CPU0_IRQ_MASK_LSB (1U << 0) /* 1b */ #define MP0_CPU0_AUX_LSB (1U << 8) /* 11b */ /* MP0_CPU1_IRQ_MASK (0x10006000+0x504) */ #define MP0_CPU1_IRQ_MASK_LSB (1U << 0) /* 1b */ #define MP0_CPU1_AUX_LSB (1U << 8) /* 11b */ /* MP0_CPU2_IRQ_MASK (0x10006000+0x508) */ #define MP0_CPU2_IRQ_MASK_LSB (1U << 0) /* 1b */ #define MP0_CPU2_AUX_LSB (1U << 8) /* 11b */ /* MP0_CPU3_IRQ_MASK (0x10006000+0x50C) */ #define MP0_CPU3_IRQ_MASK_LSB (1U << 0) /* 1b */ #define MP0_CPU3_AUX_LSB (1U << 8) /* 11b */ /* MP1_CPU0_IRQ_MASK (0x10006000+0x510) */ #define MP1_CPU0_IRQ_MASK_LSB (1U << 0) /* 1b */ #define MP1_CPU0_AUX_LSB (1U << 8) /* 11b */ /* MP1_CPU1_IRQ_MASK (0x10006000+0x514) */ #define MP1_CPU1_IRQ_MASK_LSB (1U << 0) /* 1b */ #define MP1_CPU1_AUX_LSB (1U << 8) /* 11b */ /* MP1_CPU2_IRQ_MASK (0x10006000+0x518) */ #define MP1_CPU2_IRQ_MASK_LSB (1U << 0) /* 1b */ #define MP1_CPU2_AUX_LSB (1U << 8) /* 11b */ /* MP1_CPU3_IRQ_MASK (0x10006000+0x51C) */ #define MP1_CPU3_IRQ_MASK_LSB (1U << 0) /* 1b */ #define MP1_CPU3_AUX_LSB (1U << 8) /* 11b */ /* MP0_CPU0_WFI_EN (0x10006000+0x530) */ #define MP0_CPU0_WFI_EN_LSB (1U << 0) /* 1b */ /* MP0_CPU1_WFI_EN (0x10006000+0x534) */ #define MP0_CPU1_WFI_EN_LSB (1U << 0) /* 1b */ /* MP0_CPU2_WFI_EN (0x10006000+0x538) */ #define MP0_CPU2_WFI_EN_LSB (1U << 0) /* 1b */ /* MP0_CPU3_WFI_EN (0x10006000+0x53C) */ #define MP0_CPU3_WFI_EN_LSB (1U << 0) /* 1b */ /* MP1_CPU0_WFI_EN (0x10006000+0x540) */ #define MP1_CPU0_WFI_EN_LSB (1U << 0) /* 1b */ /* MP1_CPU1_WFI_EN (0x10006000+0x544) */ #define MP1_CPU1_WFI_EN_LSB (1U << 0) /* 1b */ /* MP1_CPU2_WFI_EN (0x10006000+0x548) */ #define MP1_CPU2_WFI_EN_LSB (1U << 0) /* 1b */ /* MP1_CPU3_WFI_EN (0x10006000+0x54C) */ #define MP1_CPU3_WFI_EN_LSB (1U << 0) /* 1b */ /* MP0_L2CFLUSH (0x10006000+0x554) */ #define MP0_L2CFLUSH_REQ_LSB (1U << 0) /* 1b */ #define MP0_L2CFLUSH_DONE_LSB (1U << 4) /* 1b */ /* MP1_L2CFLUSH (0x10006000+0x558) */ #define MP1_L2CFLUSH_REQ_LSB (1U << 0) /* 1b */ #define MP1_L2CFLUSH_DONE_LSB (1U << 4) /* 1b */ /* CPU_PTPOD2_CON (0x10006000+0x560) */ #define MP0_PTPOD2_FBB_EN_LSB (1U << 0) /* 1b */ #define MP1_PTPOD2_FBB_EN_LSB (1U << 1) /* 1b */ #define MP0_PTPOD2_SPARK_EN_LSB (1U << 2) /* 1b */ #define MP1_PTPOD2_SPARK_EN_LSB (1U << 3) /* 1b */ #define MP0_PTPOD2_FBB_ACK_LSB (1U << 4) /* 1b */ #define MP1_PTPOD2_FBB_ACK_LSB (1U << 5) /* 1b */ /* ROOT_CPUTOP_ADDR (0x10006000+0x570) */ #define ROOT_CPUTOP_ADDR_LSB (1U << 0) /* 32b */ /* ROOT_CORE_ADDR (0x10006000+0x574) */ #define ROOT_CORE_ADDR_LSB (1U << 0) /* 32b */ /* CPU_SPARE_CON (0x10006000+0x580) */ #define CPU_SPARE_CON_LSB (1U << 0) /* 32b */ /* CPU_SPARE_CON_SET (0x10006000+0x584) */ #define CPU_SPARE_CON_SET_LSB (1U << 0) /* 32b */ /* CPU_SPARE_CON_CLR (0x10006000+0x588) */ #define CPU_SPARE_CON_CLR_LSB (1U << 0) /* 32b */ /* SPM2SW_MAILBOX_0 (0x10006000+0x5D0) */ #define SPM2SW_MAILBOX_0_LSB (1U << 0) /* 32b */ /* SPM2SW_MAILBOX_1 (0x10006000+0x5D4) */ #define SPM2SW_MAILBOX_1_LSB (1U << 0) /* 32b */ /* SPM2SW_MAILBOX_2 (0x10006000+0x5D8) */ #define SPM2SW_MAILBOX_2_LSB (1U << 0) /* 32b */ /* SPM2SW_MAILBOX_3 (0x10006000+0x5DC) */ #define SPM2SW_MAILBOX_3_LSB (1U << 0) /* 32b */ /* SW2SPM_INT (0x10006000+0x5E0) */ #define SW2SPM_INT_LSB (1U << 0) /* 4b */ /* SW2SPM_INT_SET (0x10006000+0x5E4) */ #define SW2SPM_INT_SET_LSB (1U << 0) /* 4b */ /* SW2SPM_INT_CLR (0x10006000+0x5E8) */ #define SW2SPM_INT_CLR_LSB (1U << 0) /* 4b */ /* SW2SPM_MAILBOX_0 (0x10006000+0x5EC) */ #define SW2SPM_MAILBOX_0_LSB (1U << 0) /* 32b */ /* SW2SPM_MAILBOX_1 (0x10006000+0x5F0) */ #define SW2SPM_MAILBOX_1_LSB (1U << 0) /* 32b */ /* SW2SPM_MAILBOX_2 (0x10006000+0x5F4) */ #define SW2SPM_MAILBOX_2_LSB (1U << 0) /* 32b */ /* SW2SPM_MAILBOX_3 (0x10006000+0x5F8) */ #define SW2SPM_MAILBOX_3_LSB (1U << 0) /* 32b */ /* SW2SPM_CFG (0x10006000+0x5FC) */ #define SWU2SPM_INT_MASK_B_LSB (1U << 0) /* 4b */ #define SPM_SW_MAILBOX_REQ_LSB (1U << 8) /* 1b */ /* SPM_SW_FLAG (0x10006000+0x600) */ #define SPM_SW_FLAG_LSB (1U << 0) /* 32b */ /* SPM_SW_DEBUG (0x10006000+0x604) */ #define SPM_SW_DEBUG_LSB (1U << 0) /* 32b */ /* SPM_SW_RSV_0 (0x10006000+0x608) */ #define SPM_SW_RSV_0_LSB (1U << 0) /* 32b */ /* SPM_SW_RSV_1 (0x10006000+0x60C) */ #define SPM_SW_RSV_1_LSB (1U << 0) /* 32b */ /* SPM_SW_RSV_2 (0x10006000+0x610) */ #define SPM_SW_RSV_2_LSB (1U << 0) /* 32b */ /* SPM_SW_RSV_3 (0x10006000+0x614) */ #define SPM_SW_RSV_3_LSB (1U << 0) /* 32b */ /* SPM_SW_RSV_4 (0x10006000+0x618) */ #define SPM_SW_RSV_4_LSB (1U << 0) /* 32b */ /* SPM_SW_RSV_5 (0x10006000+0x61C) */ #define SPM_SW_RSV_5_LSB (1U << 0) /* 32b */ /* SPM_RSV_CON (0x10006000+0x620) */ #define SPM_RSV_CON_LSB (1U << 0) /* 16b */ /* SPM_RSV_STA (0x10006000+0x624) */ #define SPM_RSV_STA_LSB (1U << 0) /* 16b */ /* SPM_RSV_CON1 (0x10006000+0x628) */ #define SPM_RSV_CON1_LSB (1U << 0) /* 16b */ /* SPM_RSV_STA1 (0x10006000+0x62C) */ #define SPM_RSV_STA1_LSB (1U << 0) /* 16b */ /* SPM_PASR_DPD_0 (0x10006000+0x630) */ #define SPM_PASR_DPD_0_LSB (1U << 0) /* 32b */ /* SPM_PASR_DPD_1 (0x10006000+0x634) */ #define SPM_PASR_DPD_1_LSB (1U << 0) /* 32b */ /* SPM_PASR_DPD_2 (0x10006000+0x638) */ #define SPM_PASR_DPD_2_LSB (1U << 0) /* 32b */ /* SPM_PASR_DPD_3 (0x10006000+0x63C) */ #define SPM_PASR_DPD_3_LSB (1U << 0) /* 32b */ /* SPM_SPARE_CON (0x10006000+0x640) */ #define SPM_SPARE_CON_LSB (1U << 0) /* 32b */ /* SPM_SPARE_CON_SET (0x10006000+0x644) */ #define SPM_SPARE_CON_SET_LSB (1U << 0) /* 32b */ /* SPM_SPARE_CON_CLR (0x10006000+0x648) */ #define SPM_SPARE_CON_CLR_LSB (1U << 0) /* 32b */ /* SPM_SW_RSV_6 (0x10006000+0x64C) */ #define SPM_SW_RSV_6_LSB (1U << 0) /* 32b */ /* SPM_SW_RSV_7 (0x10006000+0x650) */ #define SPM_SW_RSV_7_LSB (1U << 0) /* 32b */ /* SPM_SW_RSV_8 (0x10006000+0x654) */ #define SPM_SW_RSV_8_LSB (1U << 0) /* 32b */ /* SPM_SW_RSV_9 (0x10006000+0x658) */ #define SPM_SW_RSV_9_LSB (1U << 0) /* 32b */ /* SPM_SW_RSV_10 (0x10006000+0x65C) */ #define SPM_SW_RSV_10_LSB (1U << 0) /* 32b */ /* SPM_SW_RSV_18 (0x10006000+0x67C) */ #define SPM_SW_RSV_18_LSB (1U << 0) /* 32b */ /* SPM_SW_RSV_19 (0x10006000+0x680) */ #define SPM_SW_RSV_19_LSB (1U << 0) /* 32b */ /* DVFSRC_EVENT_MASK_CON (0x10006000+0x690) */ #define DVFSRC_EVENT_MASK_B_LSB (1U << 0) /* 16b */ #define DVFSRC_EVENT_TRIGGER_MASK_B_LSB (1U << 16) /* 1b */ /* DVFSRC_EVENT_FORCE_ON (0x10006000+0x694) */ #define DVFSRC_EVENT_FORCE_ON_LSB (1U << 0) /* 16b */ #define DVFSRC_EVENT_TRIGGER_FORCE_ON_LSB (1U << 16) /* 1b */ /* DVFSRC_EVENT_SEL (0x10006000+0x698) */ #define DVFSRC_EVENT_SEL_LSB (1U << 0) /* 16b */ /* SPM_DVFS_EVENT_STA (0x10006000+0x69C) */ #define SPM_DVFS_EVENT_STA_LSB (1U << 0) /* 32b */ /* SPM_DVFS_EVENT_STA1 (0x10006000+0x6A0) */ #define SPM_DVFS_EVENT_STA1_LSB (1U << 0) /* 32b */ /* SPM_DVFS_LEVEL (0x10006000+0x6A4) */ #define SPM_DVFS_LEVEL_LSB (1U << 0) /* 16b */ /* DVFS_ABORT_STA (0x10006000+0x6A8) */ #define RC2SPM_EVENT_ABORT_D2T_LSB (1U << 0) /* 16b */ #define RC2SPM_EVENT_ABORT_MASK_OR_LSB (1U << 16) /* 1b */ /* DVFS_ABORT_OTHERS_MASK (0x10006000+0x6AC) */ #define DVFS_ABORT_OTHERS_MASK_B_LSB (1U << 0) /* 16b */ /* SPM_DFS_LEVEL (0x10006000+0x6B0) */ #define SPM_DFS_LEVEL_LSB (1U << 0) /* 4b */ /* SPM_DVS_LEVEL (0x10006000+0x6B4) */ #define SPM_VCORE_LEVEL_LSB (1U << 0) /* 8b */ #define SPM_VSRAM_LEVEL_LSB (1U << 8) /* 8b */ #define SPM_VMODEM_LEVEL_LSB (1U << 16) /* 8b */ /* SPM_DVFS_MISC (0x10006000+0x6B8) */ #define MSDC_DVFS_REQUEST_LSB (1U << 0) /* 1b */ #define MSDC_DVFS_LEVEL_LSB (1U << 1) /* 4b */ #define SDIO_READY_TO_SPM_LSB (1U << 7) /* 1b */ #define MD2AP_CENTRAL_BUCK_GEAR_REQ_D2T_LSB (1U << 8) /* 1b */ #define MD2AP_CENTRAL_BUCK_GEAR_RDY_D2T_LSB (1U << 9) /* 1b */ /* SPARE_SRC_REQ_MASK (0x10006000+0x6C0) */ #define SPARE1_DDREN_MASK_B_LSB (1U << 0) /* 1b */ #define SPARE1_APSRC_REQ_MASK_B_LSB (1U << 1) /* 1b */ #define SPARE1_VRF18_REQ_MASK_B_LSB (1U << 2) /* 1b */ #define SPARE1_INFRA_REQ_MASK_B_LSB (1U << 3) /* 1b */ #define SPARE1_SRCCLKENA_MASK_B_LSB (1U << 4) /* 1b */ #define SPARE1_DDREN_2_MASK_B_LSB (1U << 5) /* 1b */ #define SPARE2_DDREN_MASK_B_LSB (1U << 8) /* 1b */ #define SPARE2_APSRC_REQ_MASK_B_LSB (1U << 9) /* 1b */ #define SPARE2_VRF18_REQ_MASK_B_LSB (1U << 10) /* 1b */ #define SPARE2_INFRA_REQ_MASK_B_LSB (1U << 11) /* 1b */ #define SPARE2_SRCCLKENA_MASK_B_LSB (1U << 12) /* 1b */ #define SPARE2_DDREN_2_MASK_B_LSB (1U << 13) /* 1b */ /* SCP_VCORE_LEVEL (0x10006000+0x6C4) */ #define SCP_VCORE_LEVEL_LSB (1U << 0) /* 8b */ /* SC_MM_CK_SEL_CON (0x10006000+0x6C8) */ #define SC_MM_CK_SEL_LSB (1U << 0) /* 4b */ #define SC_MM_CK_SEL_EN_LSB (1U << 4) /* 1b */ /* SPARE_ACK_STA (0x10006000+0x6F0) */ #define SPARE_ACK_SYNC_LSB (1U << 0) /* 32b */ /* SPARE_ACK_MASK (0x10006000+0x6F4) */ #define SPARE_ACK_MASK_B_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CON1 (0x10006000+0x700) */ #define SPM_DVFS_CON1_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CON1_STA (0x10006000+0x704) */ #define SPM_DVFS_CON1_STA_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CMD0 (0x10006000+0x710) */ #define SPM_DVFS_CMD0_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CMD1 (0x10006000+0x714) */ #define SPM_DVFS_CMD1_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CMD2 (0x10006000+0x718) */ #define SPM_DVFS_CMD2_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CMD3 (0x10006000+0x71C) */ #define SPM_DVFS_CMD3_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CMD4 (0x10006000+0x720) */ #define SPM_DVFS_CMD4_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CMD5 (0x10006000+0x724) */ #define SPM_DVFS_CMD5_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CMD6 (0x10006000+0x728) */ #define SPM_DVFS_CMD6_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CMD7 (0x10006000+0x72C) */ #define SPM_DVFS_CMD7_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CMD8 (0x10006000+0x730) */ #define SPM_DVFS_CMD8_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CMD9 (0x10006000+0x734) */ #define SPM_DVFS_CMD9_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CMD10 (0x10006000+0x738) */ #define SPM_DVFS_CMD10_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CMD11 (0x10006000+0x73C) */ #define SPM_DVFS_CMD11_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CMD12 (0x10006000+0x740) */ #define SPM_DVFS_CMD12_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CMD13 (0x10006000+0x744) */ #define SPM_DVFS_CMD13_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CMD14 (0x10006000+0x748) */ #define SPM_DVFS_CMD14_LSB (1U << 0) /* 32b */ /* SPM_DVFS_CMD15 (0x10006000+0x74C) */ #define SPM_DVFS_CMD15_LSB (1U << 0) /* 32b */ /* WDT_LATCH_SPARE0_FIX (0x10006000+0x780) */ #define WDT_LATCH_SPARE0_FIX_LSB (1U << 0) /* 32b */ /* WDT_LATCH_SPARE1_FIX (0x10006000+0x784) */ #define WDT_LATCH_SPARE1_FIX_LSB (1U << 0) /* 32b */ /* WDT_LATCH_SPARE2_FIX (0x10006000+0x788) */ #define WDT_LATCH_SPARE2_FIX_LSB (1U << 0) /* 32b */ /* WDT_LATCH_SPARE3_FIX (0x10006000+0x78C) */ #define WDT_LATCH_SPARE3_FIX_LSB (1U << 0) /* 32b */ /* SPARE_ACK_IN_FIX (0x10006000+0x790) */ #define SPARE_ACK_IN_FIX_LSB (1U << 0) /* 32b */ /* DCHA_LATCH_RSV0_FIX (0x10006000+0x794) */ #define DCHA_LATCH_RSV0_FIX_LSB (1U << 0) /* 32b */ /* DCHB_LATCH_RSV0_FIX (0x10006000+0x798) */ #define DCHB_LATCH_RSV0_FIX_LSB (1U << 0) /* 32b */ /* PCM_WDT_LATCH_0 (0x10006000+0x800) */ #define PCM_WDT_LATCH_0_LSB (1U << 0) /* 32b */ /* PCM_WDT_LATCH_1 (0x10006000+0x804) */ #define PCM_WDT_LATCH_1_LSB (1U << 0) /* 32b */ /* PCM_WDT_LATCH_2 (0x10006000+0x808) */ #define PCM_WDT_LATCH_2_LSB (1U << 0) /* 32b */ /* PCM_WDT_LATCH_3 (0x10006000+0x80C) */ #define PCM_WDT_LATCH_3_LSB (1U << 0) /* 32b */ /* PCM_WDT_LATCH_4 (0x10006000+0x810) */ #define PCM_WDT_LATCH_4_LSB (1U << 0) /* 32b */ /* PCM_WDT_LATCH_5 (0x10006000+0x814) */ #define PCM_WDT_LATCH_5_LSB (1U << 0) /* 32b */ /* PCM_WDT_LATCH_6 (0x10006000+0x818) */ #define PCM_WDT_LATCH_6_LSB (1U << 0) /* 32b */ /* PCM_WDT_LATCH_7 (0x10006000+0x81C) */ #define PCM_WDT_LATCH_7_LSB (1U << 0) /* 32b */ /* PCM_WDT_LATCH_8 (0x10006000+0x820) */ #define PCM_WDT_LATCH_8_LSB (1U << 0) /* 32b */ /* PCM_WDT_LATCH_9 (0x10006000+0x824) */ #define PCM_WDT_LATCH_9_LSB (1U << 0) /* 32b */ /* WDT_LATCH_SPARE0 (0x10006000+0x828) */ #define WDT_LATCH_SPARE0_LSB (1U << 0) /* 32b */ /* WDT_LATCH_SPARE1 (0x10006000+0x82C) */ #define WDT_LATCH_SPARE1_LSB (1U << 0) /* 32b */ /* WDT_LATCH_SPARE2 (0x10006000+0x830) */ #define WDT_LATCH_SPARE2_LSB (1U << 0) /* 32b */ /* WDT_LATCH_SPARE3 (0x10006000+0x834) */ #define WDT_LATCH_SPARE3_LSB (1U << 0) /* 32b */ /* PCM_WDT_LATCH_10 (0x10006000+0x838) */ #define PCM_WDT_LATCH_10_LSB (1U << 0) /* 32b */ /* PCM_WDT_LATCH_11 (0x10006000+0x83C) */ #define PCM_WDT_LATCH_11_LSB (1U << 0) /* 32b */ /* DCHA_GATING_LATCH_0 (0x10006000+0x840) */ #define DCHA_GATING_LATCH_0_LSB (1U << 0) /* 32b */ /* DCHA_GATING_LATCH_1 (0x10006000+0x844) */ #define DCHA_GATING_LATCH_1_LSB (1U << 0) /* 32b */ /* DCHA_GATING_LATCH_2 (0x10006000+0x848) */ #define DCHA_GATING_LATCH_2_LSB (1U << 0) /* 32b */ /* DCHA_GATING_LATCH_3 (0x10006000+0x84C) */ #define DCHA_GATING_LATCH_3_LSB (1U << 0) /* 32b */ /* DCHA_GATING_LATCH_4 (0x10006000+0x850) */ #define DCHA_GATING_LATCH_4_LSB (1U << 0) /* 32b */ /* DCHA_GATING_LATCH_5 (0x10006000+0x854) */ #define DCHA_GATING_LATCH_5_LSB (1U << 0) /* 32b */ /* DCHA_GATING_LATCH_6 (0x10006000+0x858) */ #define DCHA_GATING_LATCH_6_LSB (1U << 0) /* 32b */ /* DCHA_GATING_LATCH_7 (0x10006000+0x85C) */ #define DCHA_GATING_LATCH_7_LSB (1U << 0) /* 32b */ /* DCHB_GATING_LATCH_0 (0x10006000+0x860) */ #define DCHB_GATING_LATCH_0_LSB (1U << 0) /* 32b */ /* DCHB_GATING_LATCH_1 (0x10006000+0x864) */ #define DCHB_GATING_LATCH_1_LSB (1U << 0) /* 32b */ /* DCHB_GATING_LATCH_2 (0x10006000+0x868) */ #define DCHB_GATING_LATCH_2_LSB (1U << 0) /* 32b */ /* DCHB_GATING_LATCH_3 (0x10006000+0x86C) */ #define DCHB_GATING_LATCH_3_LSB (1U << 0) /* 32b */ /* DCHB_GATING_LATCH_4 (0x10006000+0x870) */ #define DCHB_GATING_LATCH_4_LSB (1U << 0) /* 32b */ /* DCHB_GATING_LATCH_5 (0x10006000+0x874) */ #define DCHB_GATING_LATCH_5_LSB (1U << 0) /* 32b */ /* DCHB_GATING_LATCH_6 (0x10006000+0x878) */ #define DCHB_GATING_LATCH_6_LSB (1U << 0) /* 32b */ /* DCHB_GATING_LATCH_7 (0x10006000+0x87C) */ #define DCHB_GATING_LATCH_7_LSB (1U << 0) /* 32b */ /* DCHA_LATCH_RSV0 (0x10006000+0x880) */ #define DCHA_LATCH_RSV0_LSB (1U << 0) /* 32b */ /* DCHB_LATCH_RSV0 (0x10006000+0x884) */ #define DCHB_LATCH_RSV0_LSB (1U << 0) /* 32b */ /* PCM_WDT_LATCH_12 (0x10006000+0x888) */ #define PCM_WDT_LATCH_12_LSB (1U << 0) /* 32b */ /* PCM_WDT_LATCH_13 (0x10006000+0x88C) */ #define PCM_WDT_LATCH_13_LSB (1U << 0) /* 32b */ /* SPM_PC_TRACE_CON (0x10006000+0x8C0) */ #define SPM_PC_TRACE_OFFSET_LSB (1U << 0) /* 12b */ #define SPM_PC_TRACE_HW_EN_LSB (1U << 16) /* 1b */ #define SPM_PC_TRACE_SW_LSB (1U << 17) /* 1b */ /* SPM_PC_TRACE_G0 (0x10006000+0x8C4) */ #define SPM_PC_TRACE0_LSB (1U << 0) /* 12b */ #define SPM_PC_TRACE1_LSB (1U << 16) /* 12b */ /* SPM_PC_TRACE_G1 (0x10006000+0x8C8) */ #define SPM_PC_TRACE2_LSB (1U << 0) /* 12b */ #define SPM_PC_TRACE3_LSB (1U << 16) /* 12b */ /* SPM_PC_TRACE_G2 (0x10006000+0x8CC) */ #define SPM_PC_TRACE4_LSB (1U << 0) /* 12b */ #define SPM_PC_TRACE5_LSB (1U << 16) /* 12b */ /* SPM_PC_TRACE_G3 (0x10006000+0x8D0) */ #define SPM_PC_TRACE6_LSB (1U << 0) /* 12b */ #define SPM_PC_TRACE7_LSB (1U << 16) /* 12b */ /* SPM_PC_TRACE_G4 (0x10006000+0x8D4) */ #define SPM_PC_TRACE8_LSB (1U << 0) /* 12b */ #define SPM_PC_TRACE9_LSB (1U << 16) /* 12b */ /* SPM_PC_TRACE_G5 (0x10006000+0x8D8) */ #define SPM_PC_TRACE10_LSB (1U << 0) /* 12b */ #define SPM_PC_TRACE11_LSB (1U << 16) /* 12b */ /* SPM_PC_TRACE_G6 (0x10006000+0x8DC) */ #define SPM_PC_TRACE12_LSB (1U << 0) /* 12b */ #define SPM_PC_TRACE13_LSB (1U << 16) /* 12b */ /* SPM_PC_TRACE_G7 (0x10006000+0x8E0) */ #define SPM_PC_TRACE14_LSB (1U << 0) /* 12b */ #define SPM_PC_TRACE15_LSB (1U << 16) /* 12b */ /* SPM_ACK_CHK_CON (0x10006000+0x900) */ #define SPM_ACK_CHK_SW_EN_LSB (1U << 0) /* 1b */ #define SPM_ACK_CHK_CLR_ALL_LSB (1U << 1) /* 1b */ #define SPM_ACK_CHK_CLR_TIMER_LSB (1U << 2) /* 1b */ #define SPM_ACK_CHK_CLR_IRQ_LSB (1U << 3) /* 1b */ #define SPM_ACK_CHK_STA_EN_LSB (1U << 4) /* 1b */ #define SPM_ACK_CHK_WAKEUP_EN_LSB (1U << 5) /* 1b */ #define SPM_ACK_CHK_WDT_EN_LSB (1U << 6) /* 1b */ #define SPM_ACK_CHK_LOCK_PC_TRACE_EN_LSB (1U << 7) /* 1b */ #define SPM_ACK_CHK_HW_EN_LSB (1U << 8) /* 1b */ #define SPM_ACK_CHK_HW_MODE_LSB (1U << 9) /* 3b */ #define SPM_ACK_CHK_FAIL_LSB (1U << 15) /* 1b */ #define SPM_ACK_CHK_SWINT_EN_LSB (1U << 16) /* 16b */ /* SPM_ACK_CHK_PC (0x10006000+0x904) */ #define SPM_ACK_CHK_HW_TRIG_PC_VAL_LSB (1U << 0) /* 16b */ #define SPM_ACK_CHK_HW_TARG_PC_VAL_LSB (1U << 16) /* 16b */ /* SPM_ACK_CHK_SEL (0x10006000+0x908) */ #define SPM_ACK_CHK_HW_TRIG_SIGNAL_SEL_LSB (1U << 0) /* 5b */ #define SPM_ACK_CHK_HW_TRIG_GROUP_SEL_LSB (1U << 5) /* 3b */ #define SPM_ACK_CHK_HW_TARG_SIGNAL_SEL_LSB (1U << 16) /* 5b */ #define SPM_ACK_CHK_HW_TARG_GROUP_SEL_LSB (1U << 21) /* 3b */ /* SPM_ACK_CHK_TIMER (0x10006000+0x90C) */ #define SPM_ACK_CHK_TIMER_VAL_LSB (1U << 0) /* 16b */ #define SPM_ACK_CHK_TIMER_LSB (1U << 16) /* 16b */ /* SPM_ACK_CHK_STA (0x10006000+0x910) */ #define SPM_ACK_CHK_STA_LSB (1U << 0) /* 32b */ /* SPM_ACK_CHK_LATCH (0x10006000+0x914) */ #define SPM_ACK_CHK_LATCH_LSB (1U << 0) /* 32b */ /* SPM_ACK_CHK_CON2 (0x10006000+0x920) */ #define SPM_ACK_CHK_SW_EN2_LSB (1U << 0) /* 1b */ #define SPM_ACK_CHK_CLR_ALL2_LSB (1U << 1) /* 1b */ #define SPM_ACK_CHK_CLR_TIMER2_LSB (1U << 2) /* 1b */ #define SPM_ACK_CHK_CLR_IRQ2_LSB (1U << 3) /* 1b */ #define SPM_ACK_CHK_STA_EN2_LSB (1U << 4) /* 1b */ #define SPM_ACK_CHK_WAKEUP_EN2_LSB (1U << 5) /* 1b */ #define SPM_ACK_CHK_WDT_EN2_LSB (1U << 6) /* 1b */ #define SPM_ACK_CHK_LOCK_PC_TRACE_EN2_LSB (1U << 7) /* 1b */ #define SPM_ACK_CHK_HW_EN2_LSB (1U << 8) /* 1b */ #define SPM_ACK_CHK_HW_MODE2_LSB (1U << 9) /* 3b */ #define SPM_ACK_CHK_FAIL2_LSB (1U << 15) /* 1b */ #define SPM_ACK_CHK_SWINT_EN2_LSB (1U << 16) /* 16b */ /* SPM_ACK_CHK_PC2 (0x10006000+0x924) */ #define SPM_ACK_CHK_HW_TRIG_PC_VAL2_LSB (1U << 0) /* 16b */ #define SPM_ACK_CHK_HW_TARG_PC_VAL2_LSB (1U << 16) /* 16b */ /* SPM_ACK_CHK_SEL2 (0x10006000+0x928) */ #define SPM_ACK_CHK_HW_TRIG_SIGNAL_SEL2_LSB (1U << 0) /* 5b */ #define SPM_ACK_CHK_HW_TRIG_GROUP_SEL2_LSB (1U << 5) /* 3b */ #define SPM_ACK_CHK_HW_TARG_SIGNAL_SEL2_LSB (1U << 16) /* 5b */ #define SPM_ACK_CHK_HW_TARG_GROUP_SEL2_LSB (1U << 21) /* 3b */ /* SPM_ACK_CHK_TIMER2 (0x10006000+0x92C) */ #define SPM_ACK_CHK_TIMER_VAL2_LSB (1U << 0) /* 16b */ #define SPM_ACK_CHK_TIMER2_LSB (1U << 16) /* 16b */ /* SPM_ACK_CHK_STA2 (0x10006000+0x930) */ #define SPM_ACK_CHK_STA2_LSB (1U << 0) /* 32b */ /* SPM_ACK_CHK_LATCH2 (0x10006000+0x934) */ #define SPM_ACK_CHK_LATCH2_LSB (1U << 0) /* 32b */ /* SPM_ACK_CHK_CON3 (0x10006000+0x940) */ #define SPM_ACK_CHK_SW_EN3_LSB (1U << 0) /* 1b */ #define SPM_ACK_CHK_CLR_ALL3_LSB (1U << 1) /* 1b */ #define SPM_ACK_CHK_CLR_TIMER3_LSB (1U << 2) /* 1b */ #define SPM_ACK_CHK_CLR_IRQ3_LSB (1U << 3) /* 1b */ #define SPM_ACK_CHK_STA_EN3_LSB (1U << 4) /* 1b */ #define SPM_ACK_CHK_WAKEUP_EN3_LSB (1U << 5) /* 1b */ #define SPM_ACK_CHK_WDT_EN3_LSB (1U << 6) /* 1b */ #define SPM_ACK_CHK_LOCK_PC_TRACE_EN3_LSB (1U << 7) /* 1b */ #define SPM_ACK_CHK_HW_EN3_LSB (1U << 8) /* 1b */ #define SPM_ACK_CHK_HW_MODE3_LSB (1U << 9) /* 3b */ #define SPM_ACK_CHK_FAIL3_LSB (1U << 15) /* 1b */ #define SPM_ACK_CHK_SWINT_EN3_LSB (1U << 16) /* 16b */ /* SPM_ACK_CHK_PC3 (0x10006000+0x944) */ #define SPM_ACK_CHK_HW_TRIG_PC_VAL3_LSB (1U << 0) /* 16b */ #define SPM_ACK_CHK_HW_TARG_PC_VAL3_LSB (1U << 16) /* 16b */ /* SPM_ACK_CHK_SEL3 (0x10006000+0x948) */ #define SPM_ACK_CHK_HW_TRIG_SIGNAL_SEL3_LSB (1U << 0) /* 5b */ #define SPM_ACK_CHK_HW_TRIG_GROUP_SEL3_LSB (1U << 5) /* 3b */ #define SPM_ACK_CHK_HW_TARG_SIGNAL_SEL3_LSB (1U << 16) /* 5b */ #define SPM_ACK_CHK_HW_TARG_GROUP_SEL3_LSB (1U << 21) /* 3b */ /* SPM_ACK_CHK_TIMER3 (0x10006000+0x94C) */ #define SPM_ACK_CHK_TIMER_VAL3_LSB (1U << 0) /* 16b */ #define SPM_ACK_CHK_TIMER3_LSB (1U << 16) /* 16b */ /* SPM_ACK_CHK_STA3 (0x10006000+0x950) */ #define SPM_ACK_CHK_STA3_LSB (1U << 0) /* 32b */ /* SPM_ACK_CHK_LATCH3 (0x10006000+0x954) */ #define SPM_ACK_CHK_LATCH3_LSB (1U << 0) /* 32b */ /* SPM_ACK_CHK_CON4 (0x10006000+0x960) */ #define SPM_ACK_CHK_SW_EN4_LSB (1U << 0) /* 1b */ #define SPM_ACK_CHK_CLR_ALL4_LSB (1U << 1) /* 1b */ #define SPM_ACK_CHK_CLR_TIMER4_LSB (1U << 2) /* 1b */ #define SPM_ACK_CHK_CLR_IRQ4_LSB (1U << 3) /* 1b */ #define SPM_ACK_CHK_STA_EN4_LSB (1U << 4) /* 1b */ #define SPM_ACK_CHK_WAKEUP_EN4_LSB (1U << 5) /* 1b */ #define SPM_ACK_CHK_WDT_EN4_LSB (1U << 6) /* 1b */ #define SPM_ACK_CHK_LOCK_PC_TRACE_EN4_LSB (1U << 7) /* 1b */ #define SPM_ACK_CHK_HW_EN4_LSB (1U << 8) /* 1b */ #define SPM_ACK_CHK_HW_MODE4_LSB (1U << 9) /* 3b */ #define SPM_ACK_CHK_FAIL4_LSB (1U << 15) /* 1b */ #define SPM_ACK_CHK_SWINT_EN4_LSB (1U << 16) /* 16b */ /* SPM_ACK_CHK_PC4 (0x10006000+0x964) */ #define SPM_ACK_CHK_HW_TRIG_PC_VAL4_LSB (1U << 0) /* 16b */ #define SPM_ACK_CHK_HW_TARG_PC_VAL4_LSB (1U << 16) /* 16b */ /* SPM_ACK_CHK_SEL4 (0x10006000+0x968) */ #define SPM_ACK_CHK_HW_TRIG_SIGNAL_SEL4_LSB (1U << 0) /* 5b */ #define SPM_ACK_CHK_HW_TRIG_GROUP_SEL4_LSB (1U << 5) /* 3b */ #define SPM_ACK_CHK_HW_TARG_SIGNAL_SEL4_LSB (1U << 16) /* 5b */ #define SPM_ACK_CHK_HW_TARG_GROUP_SEL4_LSB (1U << 21) /* 3b */ /* SPM_ACK_CHK_TIMER4 (0x10006000+0x96C) */ #define SPM_ACK_CHK_TIMER_VAL4_LSB (1U << 0) /* 16b */ #define SPM_ACK_CHK_TIMER4_LSB (1U << 16) /* 16b */ /* SPM_ACK_CHK_STA4 (0x10006000+0x970) */ #define SPM_ACK_CHK_STA4_LSB (1U << 0) /* 32b */ /* SPM_ACK_CHK_LATCH4 (0x10006000+0x974) */ #define SPM_ACK_CHK_LATCH4_LSB (1U << 0) /* 32b */ /* --- SPM Flag Define --- */ #define SPM_FLAG_DIS_CPU_PDN (1U << 0) #define SPM_FLAG_DIS_INFRA_PDN (1U << 1) #define SPM_FLAG_DIS_DDRPHY_PDN (1U << 2) #define SPM_FLAG_DIS_VCORE_DVS (1U << 3) #define SPM_FLAG_DIS_VCORE_DFS (1U << 4) #define SPM_FLAG_DIS_COMMON_SCENARIO (1U << 5) #define SPM_FLAG_DIS_BUS_CLOCK_OFF (1U << 6) #define SPM_FLAG_DIS_ATF_ABORT (1U << 7) #define SPM_FLAG_KEEP_CSYSPWRUPACK_HIGH (1U << 8) #define SPM_FLAG_DIS_VPROC_VSRAM_DVS (1U << 9) #define SPM_FLAG_RUN_COMMON_SCENARIO (1U << 10) #define SPM_FLAG_EN_MET_DEBUG_USAGE (1U << 11) #define SPM_FLAG_SODI_CG_MODE (1U << 12) #define SPM_FLAG_SODI_NO_EVENT (1U << 13) #define SPM_FLAG_ENABLE_SODI3 (1U << 14) #define SPM_FLAG_DISABLE_MMSYS_DVFS (1U << 15) #define SPM_FLAG_DIS_SYSRAM_SLEEP (1U << 16) #define SPM_FLAG_DIS_SSPM_SRAM_SLEEP (1U << 17) #define SPM_FLAG_DIS_VMODEM_DVS (1U << 18) #define SPM_FLAG_SUSPEND_OPTION (1U << 19) #define SPM_FLAG_DEEPIDLE_OPTION (1U << 20) #define SPM_FLAG_SODI_OPTION (1U << 21) #define SPM_FLAG_SPM_FLAG_DONT_TOUCH_BIT22 (1U << 22) #define SPM_FLAG_SPM_FLAG_DONT_TOUCH_BIT23 (1U << 23) #define SPM_FLAG_SPM_FLAG_DONT_TOUCH_BIT24 (1U << 24) #define SPM_FLAG_SPM_FLAG_DONT_TOUCH_BIT25 (1U << 25) #define SPM_FLAG_SPM_FLAG_DONT_TOUCH_BIT26 (1U << 26) #define SPM_FLAG_SPM_FLAG_DONT_TOUCH_BIT27 (1U << 27) #define SPM_FLAG_SPM_FLAG_DONT_TOUCH_BIT28 (1U << 28) #define SPM_FLAG_SPM_FLAG_DONT_TOUCH_BIT29 (1U << 29) #define SPM_FLAG_SPM_FLAG_DONT_TOUCH_BIT30 (1U << 30) #define SPM_FLAG_SPM_FLAG_DONT_TOUCH_BIT31 (1U << 31) /* --- SPM Flag1 Define --- */ #define SPM_FLAG1_RESERVED_BIT0 (1U << 0) #define SPM_FLAG1_ENABLE_CPU_DORMANT (1U << 1) #define SPM_FLAG1_ENABLE_CPU_SLEEP_VOLT (1U << 2) #define SPM_FLAG1_DISABLE_PWRAP_CLK_SWITCH (1U << 3) #define SPM_FLAG1_DISABLE_ULPOSC_OFF (1U << 4) #define SPM_FLAG1_VCORE_LP_0P7V (1U << 5) #define SPM_FLAG1_DISABLE_MCDSR (1U << 6) #define SPM_FLAG1_DISABLE_NO_RESUME (1U << 7) #define SPM_FLAG1_BIG_BUCK_OFF_ENABLE (1U << 8) #define SPM_FLAG1_BIG_BUCK_ON_ENABLE (1U << 9) #define SPM_FLAG1_RESERVED_BIT10 (1U << 10) #define SPM_FLAG1_RESERVED_BIT11 (1U << 11) #define SPM_FLAG1_RESERVED_BIT12 (1U << 12) #define SPM_FLAG1_RESERVED_BIT13 (1U << 13) #define SPM_FLAG1_RESERVED_BIT14 (1U << 14) #define SPM_FLAG1_DIS_ARMPLL_OFF (1U << 15) #define SPM_FLAG1_DIS_AXI_BUS_TO_26M (1U << 16) #define SPM_FLAG1_DIS_IMP_DIS (1U << 17) #define SPM_FLAG1_DIS_IMP_COPY (1U << 18) #define SPM_FLAG1_DIS_EMI_TOGGLE_WORKAROUND (1U << 19) #define SPM_FLAG1_DIS_DRAM_ENTER_SREF (1U << 20) #define SPM_FLAG1_DIS_DRAM_DLL_OFF (1U << 21) #define SPM_FLAG1_DIS_PHYPLL_OFF (1U << 22) #define SPM_FLAG1_DIS_MPLL_OFF (1U << 23) #define SPM_FLAG1_DIS_SYSPLL_OFF (1U << 24) #define SPM_FLAG1_DIS_TOP_AXI_CLK_OFF (1U << 25) #define SPM_FLAG1_DIS_PCM_26M_SWITCH (1U << 26) #define SPM_FLAG1_DIS_CKSQ_OFF (1U << 27) #define SPM_FLAG1_DIS_SRCVOLTEN_OFF (1U << 28) #define SPM_FLAG1_DIS_CHB_CG_FREE_EN (1U << 29) #define SPM_FLAG1_DIS_CHA_DCM_RES (1U << 30) #define SPM_FLAG1_DIS_SW_MR4 (1U << 31) /* --- SPM DEBUG Define --- */ #define SPM_DBG_DEBUG_IDX_26M_WAKE (1U << 0) #define SPM_DBG_DEBUG_IDX_26M_SLEEP (1U << 1) #define SPM_DBG_DEBUG_IDX_INFRA_WAKE (1U << 2) #define SPM_DBG_DEBUG_IDX_INFRA_SLEEP (1U << 3) #define SPM_DBG_DEBUG_IDX_APSRC_WAKE (1U << 4) #define SPM_DBG_DEBUG_IDX_APSRC_SLEEP (1U << 5) #define SPM_DBG_DEBUG_IDX_VRF18_WAKE (1U << 6) #define SPM_DBG_DEBUG_IDX_VRF18_SLEEP (1U << 7) #define SPM_DBG_DEBUG_IDX_DDREN_WAKE (1U << 8) #define SPM_DBG_DEBUG_IDX_DDREN_SLEEP (1U << 9) #define SPM_DBG_DEBUG_IDX_NFC_CKBUF_ON (1U << 10) #define SPM_DBG_DEBUG_IDX_NFC_CKBUF_OFF (1U << 11) #define SPM_DBG_DEBUG_IDX_CPU_PDN (1U << 12) #define SPM_DBG_DEBUG_IDX_DPD (1U << 13) #define SPM_DBG_DEBUG_IDX_CONN_CKBUF_ON (1U << 14) #define SPM_DBG_DEBUG_IDX_CONN_CKBUF_OFF (1U << 15) #define SPM_DBG_DEBUG_IDX_VCORE_DVFS_START (1U << 16) #define SPM_DBG_DEBUG_IDX_DDREN2_WAKE (1U << 17) #define SPM_DBG_DEBUG_IDX_DDREN2_SLEEP (1U << 18) #define SPM_DBG_DEBUG_IDX_SSPM_WFI (1U << 19) #define SPM_DBG_DEBUG_IDX_SSPM_SRAM_SLP (1U << 20) #define SPM_DBG_RESERVED_BIT21 (1U << 21) #define SPM_DBG_RESERVED_BIT22 (1U << 22) #define SPM_DBG_RESERVED_BIT23 (1U << 23) #define SPM_DBG_RESERVED_BIT24 (1U << 24) #define SPM_DBG_RESERVED_BIT25 (1U << 25) #define SPM_DBG_RESERVED_BIT26 (1U << 26) #define SPM_DBG_SODI1_FLAG (1U << 27) #define SPM_DBG_SODI3_FLAG (1U << 28) #define SPM_DBG_VCORE_DVFS_FLAG (1U << 29) #define SPM_DBG_DEEPIDLE_FLAG (1U << 30) #define SPM_DBG_SUSPEND_FLAG (1U << 31) /* --- SPM DEBUG1 Define --- */ #define SPM_DBG1_DRAM_SREF_ACK_TO (1U << 0) #define SPM_DBG1_PWRAP_SLEEP_ACK_TO (1U << 1) #define SPM_DBG1_PWRAP_SPI_ACK_TO (1U << 2) #define SPM_DBG1_DRAM_GATE_ERR_DDREN_WAKEUP (1U << 3) #define SPM_DBG1_DRAM_GATE_ERR_LEAVE_LP_SCN (1U << 4) #define SPM_DBG1_RESERVED_BIT5 (1U << 5) #define SPM_DBG1_RESERVED_BIT6 (1U << 6) #define SPM_DBG1_RESERVED_BIT7 (1U << 7) #define SPM_DBG1_RESERVED_BIT8 (1U << 8) #define SPM_DBG1_RESERVED_BIT9 (1U << 9) #define SPM_DBG1_RESERVED_BIT10 (1U << 10) #define SPM_DBG1_RESERVED_BIT11 (1U << 11) #define SPM_DBG1_RESERVED_BIT12 (1U << 12) #define SPM_DBG1_RESERVED_BIT13 (1U << 13) #define SPM_DBG1_RESERVED_BIT14 (1U << 14) #define SPM_DBG1_RESERVED_BIT15 (1U << 15) #define SPM_DBG1_RESERVED_BIT16 (1U << 16) #define SPM_DBG1_RESERVED_BIT17 (1U << 17) #define SPM_DBG1_RESERVED_BIT18 (1U << 18) #define SPM_DBG1_RESERVED_BIT19 (1U << 19) #define SPM_DBG1_RESERVED_BIT20 (1U << 20) #define SPM_DBG1_RESERVED_BIT21 (1U << 21) #define SPM_DBG1_RESERVED_BIT22 (1U << 22) #define SPM_DBG1_RESERVED_BIT23 (1U << 23) #define SPM_DBG1_RESERVED_BIT24 (1U << 24) #define SPM_DBG1_RESERVED_BIT25 (1U << 25) #define SPM_DBG1_RESERVED_BIT26 (1U << 26) #define SPM_DBG1_RESERVED_BIT27 (1U << 27) #define SPM_DBG1_RESERVED_BIT28 (1U << 28) #define SPM_DBG1_RESERVED_BIT29 (1U << 29) #define SPM_DBG1_RESERVED_BIT30 (1U << 30) #define SPM_DBG1_RESERVED_BIT31 (1U << 31) /* --- R0 Define --- */ #define R0_SC_26M_CK_OFF (1U << 0) #define R0_BIT1 (1U << 1) #define R0_SC_MEM_CK_OFF (1U << 2) #define R0_SC_AXI_CK_OFF (1U << 3) #define R0_SC_DR_GATE_RETRY_EN_PCM (1U << 4) #define R0_SC_MD26M_CK_OFF (1U << 5) #define R0_SC_DPY_MODE_SW_PCM (1U << 6) #define R0_SC_DMSUS_OFF_PCM (1U << 7) #define R0_SC_DPY_2ND_DLL_EN_PCM (1U << 8) #define R0_BIT9 (1U << 9) #define R0_SC_MPLLOUT_OFF (1U << 10) #define R0_SC_TX_TRACKING_DIS (1U << 11) #define R0_SC_DPY_DLL_EN_PCM (1U << 12) #define R0_SC_DPY_DLL_CK_EN_PCM (1U << 13) #define R0_SC_DPY_VREF_EN_PCM (1U << 14) #define R0_SC_PHYPLL_EN_PCM (1U << 15) #define R0_SC_DDRPHY_FB_CK_EN_PCM (1U << 16) #define R0_SC_DPY_BCLK_ENABLE (1U << 17) #define R0_SC_MPLL_OFF (1U << 18) #define R0_SC_SHU_RESTORE (1U << 19) #define R0_SC_CKSQ0_OFF (1U << 20) #define R0_SC_CKSQ1_OFF (1U << 21) #define R0_SC_DR_SHU_EN_PCM (1U << 22) #define R0_SC_DPHY_PRECAL_UP (1U << 23) #define R0_SC_MPLL_S_OFF (1U << 24) #define R0_SC_DPHY_RXDLY_TRACK_EN (1U << 25) #define R0_SC_PHYPLL_SHU_EN_PCM (1U << 26) #define R0_SC_PHYPLL2_SHU_EN_PCM (1U << 27) #define R0_SC_PHYPLL_MODE_SW_PCM (1U << 28) #define R0_SC_PHYPLL2_MODE_SW_PCM (1U << 29) #define R0_SC_DR_SHU_LEVEL_PCM0 (1U << 30) #define R0_SC_DR_SHU_LEVEL_PCM1 (1U << 31) /* --- R7 Define --- */ #define R7_PWRAP_SLEEP_REQ (1U << 0) #define R7_EMI_CLK_OFF_REQ (1U << 1) #define R7_TOP_MAS_PAU_REQ (1U << 2) #define R7_SPM2CKSYS_MEM_CK_MUX_UPDATE (1U << 3) #define R7_PCM_CK_SEL0 (1U << 4) #define R7_PCM_CK_SEL1 (1U << 5) #define R7_SPM2RC_DVS_DONE (1U << 6) #define R7_FREQH_PAUSE_MPLL (1U << 7) #define R7_SC_26M_CK_SEL (1U << 8) #define R7_PCM_TIMER_SET (1U << 9) #define R7_PCM_TIMER_CLR (1U << 10) #define R7_SRCVOLTEN (1U << 11) #define R7_CSYSPWRUPACK (1U << 12) #define R7_IM_SLEEP_ENABLE (1U << 13) #define R7_SRCCLKENO_0 (1U << 14) #define R7_SYSRST (1U << 15) #define R7_MD_APSRC_ACK (1U << 16) #define R7_CPU_SYS_TIMER_CLK_SEL (1U << 17) #define R7_SC_AXI_DCM_DIS (1U << 18) #define R7_FREQH_PAUSE_MAIN (1U << 19) #define R7_FREQH_PAUSE_MEM (1U << 20) #define R7_SRCCLKENO_1 (1U << 21) #define R7_WDT_KICK_P (1U << 22) #define R7_SPM2RC_EVENT_ABORT_ACK (1U << 23) #define R7_WAKEUP_EXT_W_SEL (1U << 24) #define R7_WAKEUP_EXT_R_SEL (1U << 25) #define R7_PMIC_IRQ_REQ_EN (1U << 26) #define R7_FORCE_26M_WAKE (1U << 27) #define R7_FORCE_APSRC_WAKE (1U << 28) #define R7_FORCE_INFRA_WAKE (1U << 29) #define R7_FORCE_VRF18_WAKE (1U << 30) #define R7_SC_DR_SHORT_QUEUE_PCM (1U << 31) /* --- R12 Define --- */ #define R12_PCM_TIMER (1U << 0) #define R12_SSPM_WDT_EVENT_B (1U << 1) #define R12_KP_IRQ_B (1U << 2) #define R12_APWDT_EVENT_B (1U << 3) #define R12_APXGPT1_EVENT_B (1U << 4) #define R12_CONN2AP_SPM_WAKEUP_B (1U << 5) #define R12_EINT_EVENT_B (1U << 6) #define R12_CONN_WDT_IRQ_B (1U << 7) #define R12_CCIF0_EVENT_B (1U << 8) #define R12_LOWBATTERY_IRQ_B (1U << 9) #define R12_SSPM_SPM_IRQ_B (1U << 10) #define R12_SCP_SPM_IRQ_B (1U << 11) #define R12_SCP_WDT_EVENT_B (1U << 12) #define R12_PCM_WDT_WAKEUP_B (1U << 13) #define R12_USB_CDSC_B (1U << 14) #define R12_USB_POWERDWN_B (1U << 15) #define R12_SYS_TIMER_EVENT_B (1U << 16) #define R12_EINT_EVENT_SECURE_B (1U << 17) #define R12_CCIF1_EVENT_B (1U << 18) #define R12_UART0_IRQ_B (1U << 19) #define R12_AFE_IRQ_MCU_B (1U << 20) #define R12_THERM_CTRL_EVENT_B (1U << 21) #define R12_SYS_CIRQ_IRQ_B (1U << 22) #define R12_MD2AP_PEER_EVENT_B (1U << 23) #define R12_CSYSPWREQ_B (1U << 24) #define R12_MD1_WDT_B (1U << 25) #define R12_CLDMA_EVENT_B (1U << 26) #define R12_SEJ_WDT_GPT_B (1U << 27) #define R12_ALL_SSPM_WAKEUP_B (1U << 28) #define R12_CPU_IRQ_B (1U << 29) #define R12_CPU_WFI_AND_B (1U << 30) #define R12_MCUSYS_IDLE_TO_EMI_ALL_B (1U << 31) /* --- R12ext Define --- */ #define R12EXT_26M_WAKE (1U << 0) #define R12EXT_26M_SLEEP (1U << 1) #define R12EXT_INFRA_WAKE (1U << 2) #define R12EXT_INFRA_SLEEP (1U << 3) #define R12EXT_APSRC_WAKE (1U << 4) #define R12EXT_APSRC_SLEEP (1U << 5) #define R12EXT_VRF18_WAKE (1U << 6) #define R12EXT_VRF18_SLEEP (1U << 7) #define R12EXT_DVFS_ALL_STATE (1U << 8) #define R12EXT_DVFS_LEVEL_STATE0 (1U << 9) #define R12EXT_DVFS_LEVEL_STATE1 (1U << 10) #define R12EXT_DVFS_LEVEL_STATE2 (1U << 11) #define R12EXT_DDREN_WAKE (1U << 12) #define R12EXT_DDREN_SLEEP (1U << 13) #define R12EXT_NFC_CLK_BUF_WAKE (1U << 14) #define R12EXT_NFC_CLK_BUF_SLEEP (1U << 15) #define R12EXT_CONN_CLK_BUF_WAKE (1U << 16) #define R12EXT_CONN_CLK_BUF_SLEEP (1U << 17) #define R12EXT_MD_DVFS_ERROR_STATUS (1U << 18) #define R12EXT_DVFS_LEVEL_STATE3 (1U << 19) #define R12EXT_DVFS_LEVEL_STATE4 (1U << 20) #define R12EXT_DVFS_LEVEL_STATE5 (1U << 21) #define R12EXT_DVFS_LEVEL_STATE6 (1U << 22) #define R12EXT_DVFS_LEVEL_STATE7 (1U << 23) #define R12EXT_DVFS_LEVEL_STATE8 (1U << 24) #define R12EXT_DVFS_LEVEL_STATE9 (1U << 25) #define R12EXT_DVFS_LEVEL_STATE_G0 (1U << 26) #define R12EXT_DVFS_LEVEL_STATE_G1 (1U << 27) #define R12EXT_DVFS_LEVEL_STATE_G2 (1U << 28) #define R12EXT_DVFS_LEVEL_STATE_G3 (1U << 29) #define R12EXT_HYBRID_DDREN_SLEEP (1U << 30) #define R12EXT_HYBRID_DDREN_WAKE (1U << 31) /* --- R13 Define --- */ #define R13_EXT_SRCCLKENI_0 (1U << 0) #define R13_EXT_SRCCLKENI_1 (1U << 1) #define R13_MD1_SRCCLKENA (1U << 2) #define R13_MD1_APSRC_REQ (1U << 3) #define R13_CONN_DDR_EN (1U << 4) #define R13_MD2_SRCCLKENA (1U << 5) #define R13_SSPM_SRCCLKENA (1U << 6) #define R13_SSPM_APSRC_REQ (1U << 7) #define R13_MD_STATE (1U << 8) #define R13_EMI_CLK_OFF_2_ACK (1U << 9) #define R13_MM_STATE (1U << 10) #define R13_SSPM_STATE (1U << 11) #define R13_MD_DDR_EN (1U << 12) #define R13_CONN_STATE (1U << 13) #define R13_CONN_SRCCLKENA (1U << 14) #define R13_CONN_APSRC_REQ (1U << 15) #define R13_SLEEP_EVENT_STA (1U << 16) #define R13_WAKE_EVENT_STA (1U << 17) #define R13_EMI_IDLE (1U << 18) #define R13_CSYSPWRUPREQ (1U << 19) #define R13_PWRAP_SLEEP_ACK (1U << 20) #define R13_EMI_CLK_OFF_ACK_ALL (1U << 21) #define R13_TOP_MAS_PAU_ACK (1U << 22) #define R13_SW_DMDRAMCSHU_ACK_ALL (1U << 23) #define R13_RC2SPM_EVENT_ABORT_MASK_OR (1U << 24) #define R13_DR_SHORT_QUEUE_ACK_ALL (1U << 25) #define R13_INFRA_AUX_IDLE (1U << 26) #define R13_DVFS_ALL_STATE (1U << 27) #define R13_RC2SPM_EVENT_ABORT_OR (1U << 28) #define R13_DRAMC_SPCMD_APSRC_REQ (1U << 29) #define R13_MD1_VRF18_REQ (1U << 30) #define R13_C2K_VRF18_REQ (1U << 31) #define is_cpu_pdn(flags) (!((flags) & SPM_FLAG_DIS_CPU_PDN)) #define is_infra_pdn(flags) (!((flags) & SPM_FLAG_DIS_INFRA_PDN)) #define is_ddrphy_pdn(flags) (!((flags) & SPM_FLAG_DIS_DDRPHY_PDN)) #define MP0_SPMC_SRAM_DORMANT_EN (1<<0) #define MP1_SPMC_SRAM_DORMANT_EN (1<<1) #define MP2_SPMC_SRAM_DORMANT_EN (1<<2) #define EVENT_VEC(event, resume, imme, pc) \ (((pc) << 16) | \ (!!(imme) << 7) | \ (!!(resume) << 6) | \ ((event) & 0x3f)) #define SPM_PROJECT_CODE 0xb16 #define SPM_REGWR_CFG_KEY (SPM_PROJECT_CODE << 16) /************************************** * Config and Parameter **************************************/ #define POWER_ON_VAL1_DEF 0x00015800 #define PCM_FSM_STA_DEF 0x00108490 #define SPM_WAKEUP_EVENT_MASK_DEF 0xF0F92218 #define PCM_WDT_TIMEOUT (30 * 32768) /* 30s */ #define PCM_TIMER_MAX (0xffffffff - PCM_WDT_TIMEOUT) /************************************** * Define and Declare **************************************/ /* PCM_PWR_IO_EN */ #define PCM_PWRIO_EN_R0 (1U << 0) #define PCM_PWRIO_EN_R7 (1U << 7) #define PCM_RF_SYNC_R0 (1U << 16) #define PCM_RF_SYNC_R6 (1U << 22) #define PCM_RF_SYNC_R7 (1U << 23) /* SPM_SWINT */ #define PCM_SW_INT0 (1U << 0) #define PCM_SW_INT1 (1U << 1) #define PCM_SW_INT2 (1U << 2) #define PCM_SW_INT3 (1U << 3) #define PCM_SW_INT4 (1U << 4) #define PCM_SW_INT5 (1U << 5) #define PCM_SW_INT6 (1U << 6) #define PCM_SW_INT7 (1U << 7) #define PCM_SW_INT8 (1U << 8) #define PCM_SW_INT9 (1U << 9) #define PCM_SW_INT_ALL (PCM_SW_INT9 | PCM_SW_INT8 | PCM_SW_INT7 | \ PCM_SW_INT6 | PCM_SW_INT5 | PCM_SW_INT4 | \ PCM_SW_INT3 | PCM_SW_INT2 | PCM_SW_INT1 | \ PCM_SW_INT0) /* SPM_IRQ_MASK */ #define ISRM_TWAM (1U << 2) #define ISRM_PCM_RETURN (1U << 3) #define ISRM_RET_IRQ0 (1U << 8) #define ISRM_RET_IRQ1 (1U << 9) #define ISRM_RET_IRQ2 (1U << 10) #define ISRM_RET_IRQ3 (1U << 11) #define ISRM_RET_IRQ4 (1U << 12) #define ISRM_RET_IRQ5 (1U << 13) #define ISRM_RET_IRQ6 (1U << 14) #define ISRM_RET_IRQ7 (1U << 15) #define ISRM_RET_IRQ8 (1U << 16) #define ISRM_RET_IRQ9 (1U << 17) #define ISRM_RET_IRQ_AUX (ISRM_RET_IRQ9 | ISRM_RET_IRQ8 | \ ISRM_RET_IRQ7 | ISRM_RET_IRQ6 | \ ISRM_RET_IRQ5 | ISRM_RET_IRQ4 | \ ISRM_RET_IRQ3 | ISRM_RET_IRQ2 | \ ISRM_RET_IRQ1) #define ISRM_ALL_EXC_TWAM (ISRM_RET_IRQ_AUX) #define ISRM_ALL (ISRM_ALL_EXC_TWAM | ISRM_TWAM) /* SPM_IRQ_STA */ #define ISRS_TWAM (1U << 2) #define ISRS_PCM_RETURN (1U << 3) #define ISRS_SW_INT0 (1U << 4) #define ISRC_TWAM ISRS_TWAM #define ISRC_ALL_EXC_TWAM ISRS_PCM_RETURN #define ISRC_ALL (ISRC_ALL_EXC_TWAM | ISRC_TWAM) /* SPM_WAKEUP_MISC */ #define WAKE_MISC_TWAM (1U << 18) #define WAKE_MISC_PCM_TIMER (1U << 19) #define WAKE_MISC_CPU_WAKE (1U << 20) enum SPM_WAKE_SRC_LIST { WAKE_SRC_R12_PCM_TIMER = (1U << 0), WAKE_SRC_R12_SSPM_WDT_EVENT_B = (1U << 1), WAKE_SRC_R12_KP_IRQ_B = (1U << 2), WAKE_SRC_R12_APWDT_EVENT_B = (1U << 3), WAKE_SRC_R12_APXGPT1_EVENT_B = (1U << 4), WAKE_SRC_R12_CONN2AP_SPM_WAKEUP_B = (1U << 5), WAKE_SRC_R12_EINT_EVENT_B = (1U << 6), WAKE_SRC_R12_CONN_WDT_IRQ_B = (1U << 7), WAKE_SRC_R12_CCIF0_EVENT_B = (1U << 8), WAKE_SRC_R12_LOWBATTERY_IRQ_B = (1U << 9), WAKE_SRC_R12_SSPM_SPM_IRQ_B = (1U << 10), WAKE_SRC_R12_SCP_SPM_IRQ_B = (1U << 11), WAKE_SRC_R12_SCP_WDT_EVENT_B = (1U << 12), WAKE_SRC_R12_PCM_WDT_WAKEUP_B = (1U << 13), WAKE_SRC_R12_USB_CDSC_B = (1U << 14), WAKE_SRC_R12_USB_POWERDWN_B = (1U << 15), WAKE_SRC_R12_SYS_TIMER_EVENT_B = (1U << 16), WAKE_SRC_R12_EINT_EVENT_SECURE_B = (1U << 17), WAKE_SRC_R12_CCIF1_EVENT_B = (1U << 18), WAKE_SRC_R12_UART0_IRQ_B = (1U << 19), WAKE_SRC_R12_AFE_IRQ_MCU_B = (1U << 20), WAKE_SRC_R12_THERM_CTRL_EVENT_B = (1U << 21), WAKE_SRC_R12_SYS_CIRQ_IRQ_B = (1U << 22), WAKE_SRC_R12_MD2AP_PEER_EVENT_B = (1U << 23), WAKE_SRC_R12_CSYSPWREQ_B = (1U << 24), WAKE_SRC_R12_MD1_WDT_B = (1U << 25), WAKE_SRC_R12_CLDMA_EVENT_B = (1U << 26), WAKE_SRC_R12_SEJ_WDT_GPT_B = (1U << 27), WAKE_SRC_R12_ALL_SSPM_WAKEUP_B = (1U << 28), WAKE_SRC_R12_CPU_IRQ_B = (1U << 29), WAKE_SRC_R12_CPU_WFI_AND_B = (1U << 30), }; struct pcm_desc { const char *version; const uint32_t *base; const uint32_t base_dma; const uint32_t size; const uint32_t sess; const uint32_t replace; const uint32_t addr_2nd; const uint32_t reserved; uint32_t vec0; uint32_t vec1; uint32_t vec2; uint32_t vec3; uint32_t vec4; uint32_t vec5; uint32_t vec6; uint32_t vec7; uint32_t vec8; uint32_t vec9; uint32_t vec10; uint32_t vec11; uint32_t vec12; uint32_t vec13; uint32_t vec14; uint32_t vec15; }; struct pwr_ctrl { uint32_t pcm_flags; uint32_t pcm_flags1; uint32_t timer_val; uint32_t wake_src; /* SPM_AP_STANDBY_CON */ uint8_t wfi_op; uint8_t mp0_cputop_idle_mask; uint8_t mp1_cputop_idle_mask; uint8_t mcusys_idle_mask; uint8_t mm_mask_b; uint8_t md_ddr_en_0_dbc_en; uint8_t md_ddr_en_1_dbc_en; uint8_t md_mask_b; uint8_t sspm_mask_b; uint8_t scp_mask_b; uint8_t srcclkeni_mask_b; uint8_t md_apsrc_1_sel; uint8_t md_apsrc_0_sel; uint8_t conn_ddr_en_dbc_en; uint8_t conn_mask_b; uint8_t conn_apsrc_sel; /* SPM_SRC_REQ */ uint8_t spm_apsrc_req; uint8_t spm_f26m_req; uint8_t spm_infra_req; uint8_t spm_vrf18_req; uint8_t spm_ddren_req; uint8_t spm_rsv_src_req; uint8_t spm_ddren_2_req; uint8_t cpu_md_dvfs_sop_force_on; /* SPM_SRC_MASK */ uint8_t csyspwreq_mask; uint8_t ccif0_md_event_mask_b; uint8_t ccif0_ap_event_mask_b; uint8_t ccif1_md_event_mask_b; uint8_t ccif1_ap_event_mask_b; uint8_t ccif2_md_event_mask_b; uint8_t ccif2_ap_event_mask_b; uint8_t ccif3_md_event_mask_b; uint8_t ccif3_ap_event_mask_b; uint8_t md_srcclkena_0_infra_mask_b; uint8_t md_srcclkena_1_infra_mask_b; uint8_t conn_srcclkena_infra_mask_b; uint8_t ufs_infra_req_mask_b; uint8_t srcclkeni_infra_mask_b; uint8_t md_apsrc_req_0_infra_mask_b; uint8_t md_apsrc_req_1_infra_mask_b; uint8_t conn_apsrcreq_infra_mask_b; uint8_t ufs_srcclkena_mask_b; uint8_t md_vrf18_req_0_mask_b; uint8_t md_vrf18_req_1_mask_b; uint8_t ufs_vrf18_req_mask_b; uint8_t gce_vrf18_req_mask_b; uint8_t conn_infra_req_mask_b; uint8_t gce_apsrc_req_mask_b; uint8_t disp0_apsrc_req_mask_b; uint8_t disp1_apsrc_req_mask_b; uint8_t mfg_req_mask_b; uint8_t vdec_req_mask_b; /* SPM_SRC2_MASK */ uint8_t md_ddr_en_0_mask_b; uint8_t md_ddr_en_1_mask_b; uint8_t conn_ddr_en_mask_b; uint8_t ddren_sspm_apsrc_req_mask_b; uint8_t ddren_scp_apsrc_req_mask_b; uint8_t disp0_ddren_mask_b; uint8_t disp1_ddren_mask_b; uint8_t gce_ddren_mask_b; uint8_t ddren_emi_self_refresh_ch0_mask_b; uint8_t ddren_emi_self_refresh_ch1_mask_b; /* SPM_WAKEUP_EVENT_MASK */ uint32_t spm_wakeup_event_mask; /* SPM_WAKEUP_EVENT_EXT_MASK */ uint32_t spm_wakeup_event_ext_mask; /* SPM_SRC3_MASK */ uint8_t md_ddr_en_2_0_mask_b; uint8_t md_ddr_en_2_1_mask_b; uint8_t conn_ddr_en_2_mask_b; uint8_t ddren2_sspm_apsrc_req_mask_b; uint8_t ddren2_scp_apsrc_req_mask_b; uint8_t disp0_ddren2_mask_b; uint8_t disp1_ddren2_mask_b; uint8_t gce_ddren2_mask_b; uint8_t ddren2_emi_self_refresh_ch0_mask_b; uint8_t ddren2_emi_self_refresh_ch1_mask_b; uint8_t mp0_cpu0_wfi_en; uint8_t mp0_cpu1_wfi_en; uint8_t mp0_cpu2_wfi_en; uint8_t mp0_cpu3_wfi_en; uint8_t mp1_cpu0_wfi_en; uint8_t mp1_cpu1_wfi_en; uint8_t mp1_cpu2_wfi_en; uint8_t mp1_cpu3_wfi_en; }; struct wake_status { uint32_t assert_pc; uint32_t r12; uint32_t r12_ext; uint32_t raw_sta; uint32_t raw_ext_sta; uint32_t wake_misc; uint32_t timer_out; uint32_t r13; uint32_t r15; uint32_t idle_sta; uint32_t req_sta; uint32_t debug_flag; uint32_t debug_flag1; uint32_t event_reg; uint32_t isr; uint32_t sw_flag; uint32_t sw_flag1; uint32_t log_index; }; typedef struct spm_data { unsigned int cmd; union { struct { unsigned int sys_timestamp_l; unsigned int sys_timestamp_h; unsigned int sys_src_clk_l; unsigned int sys_src_clk_h; unsigned int spm_opt; } suspend; struct { unsigned int args1; unsigned int args2; unsigned int args3; unsigned int args4; unsigned int args5; unsigned int args6; unsigned int args7; } args; } u; } spm_data_t; enum { SPM_SUSPEND, SPM_RESUME }; extern void spm_disable_pcm_timer(void); extern void spm_set_bootaddr(unsigned long bootaddr); extern void spm_set_cpu_status(int cpu); extern void spm_set_power_control(const struct pwr_ctrl *pwrctrl); extern void spm_set_wakeup_event(const struct pwr_ctrl *pwrctrl); extern void spm_set_pcm_flags(const struct pwr_ctrl *pwrctrl); extern void spm_send_cpu_wakeup_event(void); extern void spm_get_wakeup_status(struct wake_status *wakesta); extern void spm_clean_after_wakeup(void); extern void spm_output_wake_reason(struct wake_status *wakesta, const char *scenario); extern void spm_set_pcm_wdt(int en); extern void spm_lock_get(void); extern void spm_lock_release(void); extern void spm_boot_init(void); extern const char *spm_get_firmware_version(void); #endif /* SPM_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/spm/spm_pmic_wrap.c000066400000000000000000000122611355360272700260630ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #define SLEEP_REG_MD_SPM_DVFS_CMD20 (SLEEP_REG_MD_BASE + 0x010) #define SLEEP_REG_MD_SPM_DVFS_CMD21 (SLEEP_REG_MD_BASE + 0x014) #define SLEEP_REG_MD_SPM_DVFS_CMD22 (SLEEP_REG_MD_BASE + 0x018) #define SLEEP_REG_MD_SPM_DVFS_CMD23 (SLEEP_REG_MD_BASE + 0x01C) /* PMIC_WRAP -> PMIC MT6358 */ #define VCORE_BASE_UV 50000 #define VOLT_TO_PMIC_VAL(volt) (((volt) - VCORE_BASE_UV + 625 - 1) / 625) #define PMIC_VAL_TO_VOLT(pmic) (((pmic) * 625) + VCORE_BASE_UV) #define DEFAULT_VOLT_VSRAM (100000) #define DEFAULT_VOLT_VCORE (100000) #define NR_PMIC_WRAP_CMD (NR_IDX_ALL) #define MAX_RETRY_COUNT (100) #define SPM_DATA_SHIFT (16) #define BUCK_VCORE_ELR0 0x14AA #define BUCK_VPROC12_CON0 0x1408 #define BUCK_VPROC11_CON0 0x1388 #define TOP_SPI_CON0 0x044C #define LDO_VSRAM_PROC12_CON0 0x1B88 #define LDO_VSRAM_PROC11_CON0 0x1B46 #define BUCK_VMODEM_ELR0 0x15A6 struct pmic_wrap_cmd { unsigned long cmd_addr; unsigned long cmd_wdata; }; struct pmic_wrap_setting { enum pmic_wrap_phase_id phase; struct pmic_wrap_cmd addr[NR_PMIC_WRAP_CMD]; struct { struct { unsigned long cmd_addr; unsigned long cmd_wdata; } _[NR_PMIC_WRAP_CMD]; const int nr_idx; } set[NR_PMIC_WRAP_PHASE]; }; static struct pmic_wrap_setting pw = { .phase = NR_PMIC_WRAP_PHASE, .addr = {{0, 0} }, .set[PMIC_WRAP_PHASE_ALLINONE] = { ._[CMD_0] = {BUCK_VCORE_ELR0, VOLT_TO_PMIC_VAL(70000),}, ._[CMD_1] = {BUCK_VCORE_ELR0, VOLT_TO_PMIC_VAL(80000),}, ._[CMD_2] = {BUCK_VPROC12_CON0, 0x3,}, ._[CMD_3] = {BUCK_VPROC12_CON0, 0x1,}, ._[CMD_4] = {BUCK_VPROC11_CON0, 0x3,}, ._[CMD_5] = {BUCK_VPROC11_CON0, 0x1,}, ._[CMD_6] = {TOP_SPI_CON0, 0x1,}, ._[CMD_7] = {TOP_SPI_CON0, 0x0,}, ._[CMD_8] = {BUCK_VPROC12_CON0, 0x0,}, ._[CMD_9] = {BUCK_VPROC12_CON0, 0x1,}, ._[CMD_10] = {BUCK_VPROC11_CON0, 0x0,}, ._[CMD_11] = {BUCK_VPROC11_CON0, 0x1,}, ._[CMD_12] = {LDO_VSRAM_PROC12_CON0, 0x0,}, ._[CMD_13] = {LDO_VSRAM_PROC12_CON0, 0x1,}, ._[CMD_14] = {LDO_VSRAM_PROC11_CON0, 0x0,}, ._[CMD_15] = {LDO_VSRAM_PROC11_CON0, 0x1,}, ._[CMD_20] = {BUCK_VMODEM_ELR0, VOLT_TO_PMIC_VAL(55000),}, ._[CMD_21] = {BUCK_VCORE_ELR0, VOLT_TO_PMIC_VAL(60000),}, ._[CMD_22] = {LDO_VSRAM_PROC11_CON0, 0x3,}, ._[CMD_23] = {LDO_VSRAM_PROC11_CON0, 0x1,}, .nr_idx = NR_IDX_ALL } }; void _mt_spm_pmic_table_init(void) { struct pmic_wrap_cmd pwrap_cmd_default[NR_PMIC_WRAP_CMD] = { {(uint32_t)SPM_DVFS_CMD0, (uint32_t)SPM_DVFS_CMD0,}, {(uint32_t)SPM_DVFS_CMD1, (uint32_t)SPM_DVFS_CMD1,}, {(uint32_t)SPM_DVFS_CMD2, (uint32_t)SPM_DVFS_CMD2,}, {(uint32_t)SPM_DVFS_CMD3, (uint32_t)SPM_DVFS_CMD3,}, {(uint32_t)SPM_DVFS_CMD4, (uint32_t)SPM_DVFS_CMD4,}, {(uint32_t)SPM_DVFS_CMD5, (uint32_t)SPM_DVFS_CMD5,}, {(uint32_t)SPM_DVFS_CMD6, (uint32_t)SPM_DVFS_CMD6,}, {(uint32_t)SPM_DVFS_CMD7, (uint32_t)SPM_DVFS_CMD7,}, {(uint32_t)SPM_DVFS_CMD8, (uint32_t)SPM_DVFS_CMD8,}, {(uint32_t)SPM_DVFS_CMD9, (uint32_t)SPM_DVFS_CMD9,}, {(uint32_t)SPM_DVFS_CMD10, (uint32_t)SPM_DVFS_CMD10,}, {(uint32_t)SPM_DVFS_CMD11, (uint32_t)SPM_DVFS_CMD11,}, {(uint32_t)SPM_DVFS_CMD12, (uint32_t)SPM_DVFS_CMD12,}, {(uint32_t)SPM_DVFS_CMD13, (uint32_t)SPM_DVFS_CMD13,}, {(uint32_t)SPM_DVFS_CMD14, (uint32_t)SPM_DVFS_CMD14,}, {(uint32_t)SPM_DVFS_CMD15, (uint32_t)SPM_DVFS_CMD15,}, {(uint32_t)SLEEP_REG_MD_SPM_DVFS_CMD20, (uint32_t)SLEEP_REG_MD_SPM_DVFS_CMD20,}, {(uint32_t)SLEEP_REG_MD_SPM_DVFS_CMD21, (uint32_t)SLEEP_REG_MD_SPM_DVFS_CMD21,}, {(uint32_t)SLEEP_REG_MD_SPM_DVFS_CMD22, (uint32_t)SLEEP_REG_MD_SPM_DVFS_CMD22,}, {(uint32_t)SLEEP_REG_MD_SPM_DVFS_CMD23, (uint32_t)SLEEP_REG_MD_SPM_DVFS_CMD23,} }; memcpy(pw.addr, pwrap_cmd_default, sizeof(pwrap_cmd_default)); } void mt_spm_pmic_wrap_set_phase(enum pmic_wrap_phase_id phase) { uint32_t idx, addr, data; if (phase >= NR_PMIC_WRAP_PHASE) return; if (pw.phase == phase) return; if (pw.addr[0].cmd_addr == 0) _mt_spm_pmic_table_init(); pw.phase = phase; mmio_write_32(POWERON_CONFIG_EN, SPM_REGWR_CFG_KEY | BCLK_CG_EN_LSB | MD_BCLK_CG_EN_LSB); for (idx = 0; idx < pw.set[phase].nr_idx; idx++) { addr = pw.set[phase]._[idx].cmd_addr << SPM_DATA_SHIFT; data = pw.set[phase]._[idx].cmd_wdata; mmio_write_32(pw.addr[idx].cmd_addr, addr | data); } } void mt_spm_pmic_wrap_set_cmd(enum pmic_wrap_phase_id phase, uint32_t idx, uint32_t cmd_wdata) { uint32_t addr; if (phase >= NR_PMIC_WRAP_PHASE) return; if (idx >= pw.set[phase].nr_idx) return; pw.set[phase]._[idx].cmd_wdata = cmd_wdata; mmio_write_32(POWERON_CONFIG_EN, SPM_REGWR_CFG_KEY | BCLK_CG_EN_LSB | MD_BCLK_CG_EN_LSB); if (pw.phase == phase) { addr = pw.set[phase]._[idx].cmd_addr << SPM_DATA_SHIFT; mmio_write_32(pw.addr[idx].cmd_addr, addr | cmd_wdata); } } uint64_t mt_spm_pmic_wrap_get_cmd(enum pmic_wrap_phase_id phase, uint32_t idx) { if (phase >= NR_PMIC_WRAP_PHASE) return 0; if (idx >= pw.set[phase].nr_idx) return 0; return pw.set[phase]._[idx].cmd_wdata; } trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/spm/spm_pmic_wrap.h000066400000000000000000000024511355360272700260700ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /**************************************************************** * Auto generated by DE, please DO NOT modify this file directly. *****************************************************************/ #ifndef SPM_PMIC_WRAP__H #define SPM_PMIC_WRAP__H enum pmic_wrap_phase_id { PMIC_WRAP_PHASE_ALLINONE, NR_PMIC_WRAP_PHASE }; /* IDX mapping */ enum { CMD_0, /* 0x0 *//* PMIC_WRAP_PHASE_ALLINONE */ CMD_1, /* 0x1 */ CMD_2, /* 0x2 */ CMD_3, /* 0x3 */ CMD_4, /* 0x4 */ CMD_5, /* 0x5 */ CMD_6, /* 0x6 */ CMD_7, /* 0x7 */ CMD_8, /* 0x8 */ CMD_9, /* 0x9 */ CMD_10, /* 0xA */ CMD_11, /* 0xB */ CMD_12, /* 0xC */ CMD_13, /* 0xD */ CMD_14, /* 0xE */ CMD_15, /* 0xF */ CMD_20, /* 0x14 */ CMD_21, /* 0x15 */ CMD_22, /* 0x16 */ CMD_23, /* 0x17 */ NR_IDX_ALL }; /* APIs */ void mt_spm_pmic_wrap_set_phase(enum pmic_wrap_phase_id phase); void mt_spm_pmic_wrap_set_cmd(enum pmic_wrap_phase_id phase, uint32_t idx, uint32_t cmd_wdata); uint64_t mt_spm_pmic_wrap_get_cmd(enum pmic_wrap_phase_id phase, uint32_t idx); #endif /* SPM_PMIC_WRAP__H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/spm/spm_suspend.c000066400000000000000000000142131355360272700255620ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #define SPM_SYSCLK_SETTLE 99 #define WAKE_SRC_FOR_SUSPEND \ (WAKE_SRC_R12_PCM_TIMER | \ WAKE_SRC_R12_SSPM_WDT_EVENT_B | \ WAKE_SRC_R12_KP_IRQ_B | \ WAKE_SRC_R12_CONN2AP_SPM_WAKEUP_B | \ WAKE_SRC_R12_EINT_EVENT_B | \ WAKE_SRC_R12_CONN_WDT_IRQ_B | \ WAKE_SRC_R12_CCIF0_EVENT_B | \ WAKE_SRC_R12_SSPM_SPM_IRQ_B | \ WAKE_SRC_R12_SCP_SPM_IRQ_B | \ WAKE_SRC_R12_SCP_WDT_EVENT_B | \ WAKE_SRC_R12_USB_CDSC_B | \ WAKE_SRC_R12_USB_POWERDWN_B | \ WAKE_SRC_R12_SYS_TIMER_EVENT_B | \ WAKE_SRC_R12_EINT_EVENT_SECURE_B | \ WAKE_SRC_R12_CCIF1_EVENT_B | \ WAKE_SRC_R12_MD2AP_PEER_EVENT_B | \ WAKE_SRC_R12_MD1_WDT_B | \ WAKE_SRC_R12_CLDMA_EVENT_B | \ WAKE_SRC_R12_SEJ_WDT_GPT_B) #define SLP_PCM_FLAGS \ (SPM_FLAG_DIS_VCORE_DVS | SPM_FLAG_DIS_VCORE_DFS | \ SPM_FLAG_DIS_ATF_ABORT | SPM_FLAG_DISABLE_MMSYS_DVFS | \ SPM_FLAG_DIS_INFRA_PDN | SPM_FLAG_SUSPEND_OPTION) #define SLP_PCM_FLAGS1 \ (SPM_FLAG1_DISABLE_MCDSR) static const struct pwr_ctrl suspend_ctrl = { .wake_src = WAKE_SRC_FOR_SUSPEND, .pcm_flags = SLP_PCM_FLAGS, .pcm_flags1 = SLP_PCM_FLAGS1, /* SPM_AP_STANDBY_CON */ .wfi_op = 0x1, .mp0_cputop_idle_mask = 0, .mp1_cputop_idle_mask = 0, .mcusys_idle_mask = 0, .mm_mask_b = 0, .md_ddr_en_0_dbc_en = 0x1, .md_ddr_en_1_dbc_en = 0, .md_mask_b = 0x1, .sspm_mask_b = 0x1, .scp_mask_b = 0x1, .srcclkeni_mask_b = 0x1, .md_apsrc_1_sel = 0, .md_apsrc_0_sel = 0, .conn_ddr_en_dbc_en = 0x1, .conn_mask_b = 0x1, .conn_apsrc_sel = 0, /* SPM_SRC_REQ */ .spm_apsrc_req = 0, .spm_f26m_req = 0, .spm_infra_req = 0, .spm_vrf18_req = 0, .spm_ddren_req = 0, .spm_rsv_src_req = 0, .spm_ddren_2_req = 0, .cpu_md_dvfs_sop_force_on = 0, /* SPM_SRC_MASK */ .csyspwreq_mask = 0x1, .ccif0_md_event_mask_b = 0x1, .ccif0_ap_event_mask_b = 0x1, .ccif1_md_event_mask_b = 0x1, .ccif1_ap_event_mask_b = 0x1, .ccif2_md_event_mask_b = 0x1, .ccif2_ap_event_mask_b = 0x1, .ccif3_md_event_mask_b = 0x1, .ccif3_ap_event_mask_b = 0x1, .md_srcclkena_0_infra_mask_b = 0x1, .md_srcclkena_1_infra_mask_b = 0, .conn_srcclkena_infra_mask_b = 0, .ufs_infra_req_mask_b = 0, .srcclkeni_infra_mask_b = 0, .md_apsrc_req_0_infra_mask_b = 0x1, .md_apsrc_req_1_infra_mask_b = 0x1, .conn_apsrcreq_infra_mask_b = 0x1, .ufs_srcclkena_mask_b = 0, .md_vrf18_req_0_mask_b = 0, .md_vrf18_req_1_mask_b = 0, .ufs_vrf18_req_mask_b = 0, .gce_vrf18_req_mask_b = 0, .conn_infra_req_mask_b = 0x1, .gce_apsrc_req_mask_b = 0, .disp0_apsrc_req_mask_b = 0, .disp1_apsrc_req_mask_b = 0, .mfg_req_mask_b = 0, .vdec_req_mask_b = 0, /* SPM_SRC2_MASK */ .md_ddr_en_0_mask_b = 0x1, .md_ddr_en_1_mask_b = 0, .conn_ddr_en_mask_b = 0x1, .ddren_sspm_apsrc_req_mask_b = 0x1, .ddren_scp_apsrc_req_mask_b = 0x1, .disp0_ddren_mask_b = 0x1, .disp1_ddren_mask_b = 0x1, .gce_ddren_mask_b = 0x1, .ddren_emi_self_refresh_ch0_mask_b = 0, .ddren_emi_self_refresh_ch1_mask_b = 0, /* SPM_WAKEUP_EVENT_MASK */ .spm_wakeup_event_mask = 0xF1782218, /* SPM_WAKEUP_EVENT_EXT_MASK */ .spm_wakeup_event_ext_mask = 0xFFFFFFFF, /* SPM_SRC3_MASK */ .md_ddr_en_2_0_mask_b = 0x1, .md_ddr_en_2_1_mask_b = 0, .conn_ddr_en_2_mask_b = 0x1, .ddren2_sspm_apsrc_req_mask_b = 0x1, .ddren2_scp_apsrc_req_mask_b = 0x1, .disp0_ddren2_mask_b = 0, .disp1_ddren2_mask_b = 0, .gce_ddren2_mask_b = 0, .ddren2_emi_self_refresh_ch0_mask_b = 0, .ddren2_emi_self_refresh_ch1_mask_b = 0, .mp0_cpu0_wfi_en = 0x1, .mp0_cpu1_wfi_en = 0x1, .mp0_cpu2_wfi_en = 0x1, .mp0_cpu3_wfi_en = 0x1, .mp1_cpu0_wfi_en = 0x1, .mp1_cpu1_wfi_en = 0x1, .mp1_cpu2_wfi_en = 0x1, .mp1_cpu3_wfi_en = 0x1 }; static uint32_t spm_set_sysclk_settle(void) { mmio_write_32(SPM_CLK_SETTLE, SPM_SYSCLK_SETTLE); return mmio_read_32(SPM_CLK_SETTLE); } void go_to_sleep_before_wfi(void) { int cpu = MPIDR_AFFLVL0_VAL(read_mpidr()); uint32_t settle; settle = spm_set_sysclk_settle(); spm_set_cpu_status(cpu); spm_set_power_control(&suspend_ctrl); spm_set_wakeup_event(&suspend_ctrl); spm_set_pcm_flags(&suspend_ctrl); spm_send_cpu_wakeup_event(); spm_set_pcm_wdt(0); spm_disable_pcm_timer(); if (is_infra_pdn(suspend_ctrl.pcm_flags)) mt_uart_save(); if (!mt_console_uart_cg_status()) console_switch_state(CONSOLE_FLAG_BOOT); INFO("cpu%d: \"%s\", wakesrc = 0x%x, pcm_con1 = 0x%x\n", cpu, spm_get_firmware_version(), suspend_ctrl.wake_src, mmio_read_32(PCM_CON1)); INFO("settle = %u, sec = %u, sw_flag = 0x%x 0x%x, src_req = 0x%x\n", settle, mmio_read_32(PCM_TIMER_VAL) / 32768, suspend_ctrl.pcm_flags, suspend_ctrl.pcm_flags1, mmio_read_32(SPM_SRC_REQ)); if (!mt_console_uart_cg_status()) console_switch_state(CONSOLE_FLAG_RUNTIME); } static void go_to_sleep_after_wfi(void) { struct wake_status spm_wakesta; if (is_infra_pdn(suspend_ctrl.pcm_flags)) mt_uart_restore(); spm_set_pcm_wdt(0); spm_get_wakeup_status(&spm_wakesta); spm_clean_after_wakeup(); if (!mt_console_uart_cg_status()) console_switch_state(CONSOLE_FLAG_BOOT); spm_output_wake_reason(&spm_wakesta, "suspend"); if (!mt_console_uart_cg_status()) console_switch_state(CONSOLE_FLAG_RUNTIME); } static void spm_enable_armpll_l(void) { /* power on */ mmio_setbits_32(ARMPLL_L_PWR_CON0, 0x1); /* clear isolation */ mmio_clrbits_32(ARMPLL_L_PWR_CON0, 0x2); /* enable pll */ mmio_setbits_32(ARMPLL_L_CON0, 0x1); /* Add 20us delay for turning on PLL */ udelay(20); } static void spm_disable_armpll_l(void) { /* disable pll */ mmio_clrbits_32(ARMPLL_L_CON0, 0x1); /* isolation */ mmio_setbits_32(ARMPLL_L_PWR_CON0, 0x2); /* power off */ mmio_clrbits_32(ARMPLL_L_PWR_CON0, 0x1); } void spm_system_suspend(void) { spm_disable_armpll_l(); bcpu_enable(0); bcpu_sram_enable(0); spm_lock_get(); go_to_sleep_before_wfi(); spm_lock_release(); } void spm_system_suspend_finish(void) { spm_lock_get(); go_to_sleep_after_wfi(); spm_lock_release(); spm_enable_armpll_l(); bcpu_sram_enable(1); bcpu_enable(1); } trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/spm/spm_suspend.h000066400000000000000000000004271355360272700255710ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __SPM_SUSPEND_H__ #define __SPM_SUSPEND_H__ void spm_system_suspend(void); void spm_system_suspend_finish(void); #endif /* __SPM_SUSPEND_H__*/ trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/spmc/000077500000000000000000000000001355360272700232205ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/spmc/mtspmc.c000066400000000000000000000224411355360272700246720ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include "mtspmc_private.h" static void set_retention(int cluster, int tick) { uint64_t cpuectlr; if (cluster) cpuectlr = read_a73_cpuectlr_el1(); else cpuectlr = read_a53_cpuectlr_el1(); cpuectlr &= ~0x7ULL; cpuectlr |= tick & 0x7; if (cluster) write_a73_cpuectlr_el1(cpuectlr); else write_a53_cpuectlr_el1(cpuectlr); } void spm_enable_cpu_auto_off(int cluster, int cpu) { uintptr_t reg = per_cpu(cluster, cpu, MCUCFG_SPARK); set_retention(cluster, 1); mmio_clrbits_32(reg, SW_NO_WAIT_Q); } void spm_disable_cpu_auto_off(int cluster, int cpu) { uintptr_t reg = per_cpu(cluster, cpu, MCUCFG_SPARK); mmio_setbits_32(reg, SW_NO_WAIT_Q); set_retention(cluster, 0); } void spm_set_cpu_power_off(int cluster, int cpu) { mmio_clrbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWRCTRL_PWR_ON); } void spm_enable_cluster_auto_off(int cluster) { assert(cluster); mmio_clrbits_32(MCUCFG_MP2_SPMC, SW_NO_WAIT_Q); mmio_clrbits_32(MCUCFG_MP2_COQ, BIT(0)); mmio_clrbits_32(SPM_SPMC_DORMANT_ENABLE, MP1_SPMC_SRAM_DORMANT_EN); mmio_clrbits_32(per_cluster(cluster, SPM_CLUSTER_PWR), PWRCTRL_PWR_ON); } void mcucfg_set_bootaddr(int cluster, int cpu, uintptr_t bootaddr) { uintptr_t reg; const uintptr_t mp2_bootreg[] = { MCUCFG_MP2_RVADDR0, MCUCFG_MP2_RVADDR1, MCUCFG_MP2_RVADDR2, MCUCFG_MP2_RVADDR3 }; if (cluster) { assert(cpu >= 0 && cpu < 4); reg = mp2_bootreg[cpu]; } else { reg = per_cpu(cluster, cpu, MCUCFG_BOOTADDR); } mmio_write_32(reg, bootaddr); } uintptr_t mcucfg_get_bootaddr(int cluster, int cpu) { uintptr_t reg; const uintptr_t mp2_bootreg[] = { MCUCFG_MP2_RVADDR0, MCUCFG_MP2_RVADDR1, MCUCFG_MP2_RVADDR2, MCUCFG_MP2_RVADDR3 }; if (cluster) { assert(cpu >= 0 && cpu < 4); reg = mp2_bootreg[cpu]; } else { reg = per_cpu(cluster, cpu, MCUCFG_BOOTADDR); } return mmio_read_32(reg); } void mcucfg_init_archstate(int cluster, int cpu, int arm64) { uintptr_t reg; int i; reg = per_cluster(cluster, MCUCFG_INITARCH); i = cluster ? 16 : 12; mmio_setbits_32(reg, (arm64 & 1) << (i + cpu)); } /** * Return power state of specified subsystem * * @mask: mask to SPM_PWR_STATUS to query the power state * of one subsystem. * RETURNS: * 0 (the subsys was powered off) * 1 (the subsys was powered on) */ int spm_get_powerstate(uint32_t mask) { return mmio_read_32(SPM_PWR_STATUS) & mask; } int spm_get_cluster_powerstate(int cluster) { uint32_t mask; mask = cluster ? PWR_STATUS_MP1_CPUTOP : PWR_STATUS_MP0_CPUTOP; return spm_get_powerstate(mask); } int spm_get_cpu_powerstate(int cluster, int cpu) { uint32_t i; /* * a quick way to specify the mask of cpu[0-3]/cpu[4-7] in PWR_STATUS * register which are the BITS[9:12](MP0_CPU0~3) and * BITS[16:19](MP1_CPU0~3) */ i = (cluster) ? 16 : 9; i = 1 << (i + cpu); return spm_get_powerstate(i); } int spmc_init(void) { /* enable SPM register control */ mmio_write_32(SPM_POWERON_CONFIG_EN, PROJECT_CODE | MD_BCLK_CG_EN | BCLK_CG_EN); #if SPMC_MODE == 1 INFO("SPM: enable SPMC mode\n"); /* 0: SPMC mode 1: Legacy mode */ mmio_write_32(SPM_BYPASS_SPMC, 0); mmio_clrbits_32(per_cluster(0, SPM_CLUSTER_PWR), PWRCTRL_PWR_ON_2ND); mmio_clrbits_32(per_cpu(0, 0, SPM_CPU_PWR), PWRCTRL_PWR_ON_2ND); mmio_clrbits_32(per_cpu(0, 1, SPM_CPU_PWR), PWRCTRL_PWR_ON_2ND); mmio_clrbits_32(per_cpu(0, 2, SPM_CPU_PWR), PWRCTRL_PWR_ON_2ND); mmio_clrbits_32(per_cpu(0, 3, SPM_CPU_PWR), PWRCTRL_PWR_ON_2ND); mmio_setbits_32(per_cpu(0, 1, SPM_CPU_PWR), PWRCTRL_PWR_RST_B); mmio_setbits_32(per_cpu(0, 2, SPM_CPU_PWR), PWRCTRL_PWR_RST_B); mmio_setbits_32(per_cpu(0, 3, SPM_CPU_PWR), PWRCTRL_PWR_RST_B); #endif mmio_clrbits_32(per_cluster(1, SPM_CLUSTER_PWR), PWRCTRL_PWR_ON_2ND); mmio_setbits_32(per_cluster(1, SPM_CLUSTER_PWR), PWRCTRL_PWR_RST_B); mmio_clrbits_32(per_cluster(1, SPM_CLUSTER_PWR), PWRCTRL_PWR_CLK_DIS); mmio_clrbits_32(per_cpu(1, 0, SPM_CPU_PWR), PWRCTRL_PWR_ON_2ND); mmio_clrbits_32(per_cpu(1, 1, SPM_CPU_PWR), PWRCTRL_PWR_ON_2ND); mmio_clrbits_32(per_cpu(1, 2, SPM_CPU_PWR), PWRCTRL_PWR_ON_2ND); mmio_clrbits_32(per_cpu(1, 3, SPM_CPU_PWR), PWRCTRL_PWR_ON_2ND); mmio_setbits_32(per_cpu(1, 0, SPM_CPU_PWR), PWRCTRL_PWR_RST_B); mmio_setbits_32(per_cpu(1, 1, SPM_CPU_PWR), PWRCTRL_PWR_RST_B); mmio_setbits_32(per_cpu(1, 2, SPM_CPU_PWR), PWRCTRL_PWR_RST_B); mmio_setbits_32(per_cpu(1, 3, SPM_CPU_PWR), PWRCTRL_PWR_RST_B); return 0; } /** * Power on a core with specified cluster and core index * * @cluster: the cluster ID of the CPU which to be powered on * @cpu: the CPU ID of the CPU which to be powered on */ void spm_poweron_cpu(int cluster, int cpu) { INFO("spmc: power on core %d.%d\n", cluster, cpu); /* STA_POWER_ON */ /* Start to turn on MP0_CPU0 */ /* Set PWR_RST_B = 1 */ mmio_setbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWRCTRL_PWR_RST_B); /* Set PWR_ON = 1 */ mmio_setbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWRCTRL_PWR_ON); /* Wait until MP0_CPU0_PWR_STA_MASK = 1 */ while (!spm_get_cpu_powerstate(cluster, cpu)) ; /* Finish to turn on MP0_CPU0 */ INFO("spmc: power on core %d.%d successfully\n", cluster, cpu); } /** * Power off a core with specified cluster and core index * * @cluster: the cluster ID of the CPU which to be powered off * @cpu: the CPU ID of the CPU which to be powered off */ void spm_poweroff_cpu(int cluster, int cpu) { INFO("spmc: power off core %d.%d\n", cluster, cpu); /* Start to turn off MP0_CPU0 */ /* Set PWR_ON_2ND = 0 */ mmio_clrbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWRCTRL_PWR_ON_2ND); /* Set PWR_ON = 0 */ mmio_clrbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWRCTRL_PWR_ON); /* Wait until MP0_CPU0_PWR_STA_MASK = 0 */ while (spm_get_cpu_powerstate(cluster, cpu)) ; /* Set PWR_RST_B = 0 */ mmio_clrbits_32(per_cpu(cluster, cpu, SPM_CPU_PWR), PWRCTRL_PWR_RST_B); /* Finish to turn off MP0_CPU0 */ INFO("spmc: power off core %d.%d successfully\n", cluster, cpu); } /** * Power off a cluster with specified index * * @cluster: the cluster index which to be powered off */ void spm_poweroff_cluster(int cluster) { uint32_t mask; uint32_t pwr_rst_ctl; INFO("spmc: power off cluster %d\n", cluster); /* Start to turn off MP0_CPUTOP */ /* Set bus protect - step1 : 0 */ mask = (cluster) ? MP1_CPUTOP_PROT_STEP1_0_MASK : MP0_CPUTOP_PROT_STEP1_0_MASK; mmio_write_32(INFRA_TOPAXI_PROTECTEN_1_SET, mask); while ((mmio_read_32(INFRA_TOPAXI_PROTECTEN_STA1_1) & mask) != mask) ; /* Set PWR_ON_2ND = 0 */ mmio_clrbits_32(per_cluster(cluster, SPM_CLUSTER_PWR), PWRCTRL_PWR_ON_2ND); /* SPMC_DORMANT_ENABLE[0]=0 */ mask = (cluster) ? MP1_SPMC_SRAM_DORMANT_EN : MP0_SPMC_SRAM_DORMANT_EN; mmio_clrbits_32(SPM_SPMC_DORMANT_ENABLE, mask); /* Set PWR_ON = 0" */ mmio_clrbits_32(per_cluster(cluster, SPM_CLUSTER_PWR), PWRCTRL_PWR_ON); /* Wait until MP0_CPUTOP_PWR_STA_MASK = 0 */ while (spm_get_cluster_powerstate(cluster)) ; /* NOTE * Following flow only for BIG core cluster. It was from * application note but not covered in mtcmos_ctrl.c */ if (cluster) { pwr_rst_ctl = mmio_read_32(MCUCFG_MP2_PWR_RST_CTL); mmio_write_32(MCUCFG_MP2_PWR_RST_CTL, (pwr_rst_ctl & ~SW_RST_B) | TOPAON_APB_MASK); } /* CPU_EXT_BUCK_ISO[0]=1 */ if (cluster) mmio_setbits_32(SPM_CPU_EXT_BUCK_ISO, MP1_EXT_BUCK_ISO); /* Finish to turn off MP0_CPUTOP */ INFO("spmc: power off cluster %d successfully\n", cluster); } /** * Power on a cluster with specified index * * @cluster: the cluster index which to be powered on */ void spm_poweron_cluster(int cluster) { uint32_t mask; uint32_t pwr_rst_ctl; INFO("spmc: power on cluster %d\n", cluster); /* Start to turn on MP1_CPUTOP */ /* NOTE * Following flow only for BIG core cluster. It was from * application note but not covered in mtcmos_ctrl.c */ if (cluster) { mmio_clrbits_32(MCUCFG_MP2_PWR_RST_CTL, SW_RST_B); /* CPU_EXT_BUCK_ISO[1]=0 */ /* Set mp_vproc_ext_off to 0 to release vproc isolation control */ mmio_clrbits_32(SPM_CPU_EXT_BUCK_ISO, MP1_EXT_BUCK_ISO); /* NOTE * Following flow only for BIG core cluster. It was from * application note but not covered in mtcmos_ctrl.c */ pwr_rst_ctl = mmio_read_32(MCUCFG_MP2_PWR_RST_CTL); mmio_write_32(MCUCFG_MP2_PWR_RST_CTL, (pwr_rst_ctl | SW_RST_B) & ~TOPAON_APB_MASK); } /* Set PWR_ON_2ND = 0 */ mmio_clrbits_32(per_cluster(cluster, SPM_CLUSTER_PWR), PWRCTRL_PWR_ON_2ND); /* Set PWR_RST_B = 1 */ mmio_setbits_32(per_cluster(cluster, SPM_CLUSTER_PWR), PWRCTRL_PWR_RST_B); /* Set PWR_CLK_DIS = 0 */ mmio_clrbits_32(per_cluster(cluster, SPM_CLUSTER_PWR), PWRCTRL_PWR_CLK_DIS); /* Set PWR_ON = 1 */ mmio_setbits_32(per_cluster(cluster, SPM_CLUSTER_PWR), PWRCTRL_PWR_ON); /* Wait until MP1_CPUTOP_PWR_STA_MASK = 1 */ while (!spm_get_cluster_powerstate(cluster)) ; /* Release bus protect - step1 : 0 */ mask = (cluster) ? MP1_CPUTOP_PROT_STEP1_0_MASK : MP0_CPUTOP_PROT_STEP1_0_MASK; mmio_write_32(INFRA_TOPAXI_PROTECTEN_1_CLR, mask); /* Finish to turn on MP1_CPUTOP */ INFO("spmc: power on cluster %d successfully\n", cluster); } trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/spmc/mtspmc.h000066400000000000000000000021711355360272700246750ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MTSPMC_H #define MTSPMC_H /* * CONFIG_SPMC_MODE: Select CPU power control mode. * * 0: Legacy * Control power flow from SW through SPM register (MP*_PWR_CON). * 1: HW * Control power flow from SPMC. Most control flow and timing are handled * by SPMC. */ #define SPMC_MODE 1 int spmc_init(void); void spm_poweron_cpu(int cluster, int cpu); void spm_poweroff_cpu(int cluster, int cpu); void spm_poweroff_cluster(int cluster); void spm_poweron_cluster(int cluster); int spm_get_cpu_powerstate(int cluster, int cpu); int spm_get_cluster_powerstate(int cluster); int spm_get_powerstate(uint32_t mask); void spm_enable_cpu_auto_off(int cluster, int cpu); void spm_disable_cpu_auto_off(int cluster, int cpu); void spm_set_cpu_power_off(int cluster, int cpu); void spm_enable_cluster_auto_off(int cluster); void mcucfg_init_archstate(int cluster, int cpu, int arm64); void mcucfg_set_bootaddr(int cluster, int cpu, uintptr_t bootaddr); uintptr_t mcucfg_get_bootaddr(int cluster, int cpu); #endif /* MTSPMC_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/spmc/mtspmc_private.h000066400000000000000000000207061355360272700264330ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MTSPMC_PRIVATE_H #define MTSPMC_PRIVATE_H /* * per_cpu/cluster helper */ struct per_cpu_reg { int cluster_addr; int cpu_stride; }; #define per_cpu(cluster, cpu, reg) (reg[cluster].cluster_addr + \ (cpu << reg[cluster].cpu_stride)) #define per_cluster(cluster, reg) (reg[cluster].cluster_addr) /* SPMC related registers */ #define SPM_POWERON_CONFIG_EN (SPM_BASE + 0x000) /* bit-fields of SPM_POWERON_CONFIG_EN */ #define BCLK_CG_EN (1 << 0) #define MD_BCLK_CG_EN (1 << 1) #define PROJECT_CODE (0xb16 << 16) #define SPM_PWR_STATUS (SPM_BASE + 0x180) #define SPM_PWR_STATUS_2ND (SPM_BASE + 0x184) #define SPM_BYPASS_SPMC (SPM_BASE + 0x2b4) #define SPM_SPMC_DORMANT_ENABLE (SPM_BASE + 0x2b8) #define SPM_MP0_CPUTOP_PWR_CON (SPM_BASE + 0x204) #define SPM_MP0_CPU0_PWR_CON (SPM_BASE + 0x208) #define SPM_MP0_CPU1_PWR_CON (SPM_BASE + 0x20C) #define SPM_MP0_CPU2_PWR_CON (SPM_BASE + 0x210) #define SPM_MP0_CPU3_PWR_CON (SPM_BASE + 0x214) #define SPM_MP1_CPUTOP_PWR_CON (SPM_BASE + 0x218) #define SPM_MP1_CPU0_PWR_CON (SPM_BASE + 0x21C) #define SPM_MP1_CPU1_PWR_CON (SPM_BASE + 0x220) #define SPM_MP1_CPU2_PWR_CON (SPM_BASE + 0x224) #define SPM_MP1_CPU3_PWR_CON (SPM_BASE + 0x228) #define SPM_MP0_CPUTOP_L2_PDN (SPM_BASE + 0x240) #define SPM_MP0_CPUTOP_L2_SLEEP_B (SPM_BASE + 0x244) #define SPM_MP0_CPU0_L1_PDN (SPM_BASE + 0x248) #define SPM_MP0_CPU1_L1_PDN (SPM_BASE + 0x24C) #define SPM_MP0_CPU2_L1_PDN (SPM_BASE + 0x250) #define SPM_MP0_CPU3_L1_PDN (SPM_BASE + 0x254) #define SPM_MP1_CPUTOP_L2_PDN (SPM_BASE + 0x258) #define SPM_MP1_CPUTOP_L2_SLEEP_B (SPM_BASE + 0x25C) #define SPM_MP1_CPU0_L1_PDN (SPM_BASE + 0x260) #define SPM_MP1_CPU1_L1_PDN (SPM_BASE + 0x264) #define SPM_MP1_CPU2_L1_PDN (SPM_BASE + 0x268) #define SPM_MP1_CPU3_L1_PDN (SPM_BASE + 0x26C) #define SPM_CPU_EXT_BUCK_ISO (SPM_BASE + 0x290) /* bit-fields of SPM_CPU_EXT_BUCK_ISO */ #define MP0_EXT_BUCK_ISO (1 << 0) #define MP1_EXT_BUCK_ISO (1 << 1) #define MP_EXT_BUCK_ISO (1 << 2) /* bit-fields of SPM_PWR_STATUS */ #define PWR_STATUS_MD (1 << 0) #define PWR_STATUS_CONN (1 << 1) #define PWR_STATUS_DDRPHY (1 << 2) #define PWR_STATUS_DISP (1 << 3) #define PWR_STATUS_MFG (1 << 4) #define PWR_STATUS_ISP (1 << 5) #define PWR_STATUS_INFRA (1 << 6) #define PWR_STATUS_VDEC (1 << 7) #define PWR_STATUS_MP0_CPUTOP (1 << 8) #define PWR_STATUS_MP0_CPU0 (1 << 9) #define PWR_STATUS_MP0_CPU1 (1 << 10) #define PWR_STATUS_MP0_CPU2 (1 << 11) #define PWR_STATUS_MP0_CPU3 (1 << 12) #define PWR_STATUS_MCUSYS (1 << 14) #define PWR_STATUS_MP1_CPUTOP (1 << 15) #define PWR_STATUS_MP1_CPU0 (1 << 16) #define PWR_STATUS_MP1_CPU1 (1 << 17) #define PWR_STATUS_MP1_CPU2 (1 << 18) #define PWR_STATUS_MP1_CPU3 (1 << 19) #define PWR_STATUS_VEN (1 << 21) #define PWR_STATUS_MFG_ASYNC (1 << 23) #define PWR_STATUS_AUDIO (1 << 24) #define PWR_STATUS_C2K (1 << 28) #define PWR_STATUS_MD_INFRA (1 << 29) /* bit-fields of SPM_*_PWR_CON */ #define PWRCTRL_PWR_RST_B (1 << 0) #define PWRCTRL_PWR_ISO (1 << 1) #define PWRCTRL_PWR_ON (1 << 2) #define PWRCTRL_PWR_ON_2ND (1 << 3) #define PWRCTRL_PWR_CLK_DIS (1 << 4) #define PWRCTRL_PWR_SRAM_CKISO (1 << 5) #define PWRCTRL_PWR_SRAM_ISOINT_B (1 << 6) #define PWRCTRL_PWR_SRAM_PD_SLPB_CLAMP (1 << 7) #define PWRCTRL_PWR_SRAM_PDN (1 << 8) #define PWRCTRL_PWR_SRAM_SLEEP_B (1 << 12) #define PWRCTRL_PWR_SRAM_PDN_ACK (1 << 24) #define PWRCTRL_PWR_SRAM_SLEEP_B_ACK (1 << 28) /* per_cpu registers for SPM_MP?_CPU?_PWR_CON */ static const struct per_cpu_reg SPM_CPU_PWR[] = { [0] = { .cluster_addr = SPM_MP0_CPU0_PWR_CON, .cpu_stride = 2 }, [1] = { .cluster_addr = SPM_MP1_CPU0_PWR_CON, .cpu_stride = 2 }, }; /* per_cluster registers for SPM_MP?_CPUTOP_PWR_CON */ static const struct per_cpu_reg SPM_CLUSTER_PWR[] = { [0] = { .cluster_addr = SPM_MP0_CPUTOP_PWR_CON }, [1] = { .cluster_addr = SPM_MP1_CPUTOP_PWR_CON }, }; /* APB Module infracfg_ao */ #define INFRA_TOPAXI_PROTECTEN_1 (INFRACFG_AO_BASE + 0x250) #define INFRA_TOPAXI_PROTECTEN_STA1_1 (INFRACFG_AO_BASE + 0x258) #define INFRA_TOPAXI_PROTECTEN_1_SET (INFRACFG_AO_BASE + 0x2A8) #define INFRA_TOPAXI_PROTECTEN_1_CLR (INFRACFG_AO_BASE + 0x2AC) /* bit-fields of INFRA_TOPAXI_PROTECTEN_1_SET */ #define MP0_CPUTOP_PROT_STEP1_0_MASK ((1 << 10)|(1 << 12)| \ (1 << 13)|(1 << 26)) #define MP1_CPUTOP_PROT_STEP1_0_MASK ((1 << 11)|(1 << 14)| \ (1 << 15)|(1 << 27)) /* bit-fields of INFRA_TOPAXI_PROTECTEN_STA1_1 */ #define MP0_CPUTOP_PROT_STEP1_0_ACK_MASK ((1 << 10)|(1 << 12)| \ (1 << 13)|(1 << 26)) #define MP1_CPUTOP_PROT_STEP1_0_ACK_MASK ((1 << 11)|(1 << 14)| \ (1 << 15)|(1 << 27)) /* * MCU configuration registers */ /* bit-fields of MCUCFG_MP?_AXI_CONFIG */ #define MCUCFG_AXI_CONFIG_BROADCASTINNER (1 << 0) #define MCUCFG_AXI_CONFIG_BROADCASTOUTER (1 << 1) #define MCUCFG_AXI_CONFIG_BROADCASTCACHEMAINT (1 << 2) #define MCUCFG_AXI_CONFIG_SYSBARDISABLE (1 << 3) #define MCUCFG_AXI_CONFIG_ACINACTM (1 << 4) #define MCUCFG_AXI_CONFIG_AINACTS (1 << 5) #define MCUCFG_MP0_MISC_CONFIG2 ((uintptr_t)&mt8183_mcucfg->mp0_misc_config[2]) #define MCUCFG_MP0_MISC_CONFIG3 ((uintptr_t)&mt8183_mcucfg->mp0_misc_config[3]) #define MCUCFG_MP1_MISC_CONFIG2 ((uintptr_t)&mt8183_mcucfg->mp1_misc_config[2]) #define MCUCFG_MP1_MISC_CONFIG3 ((uintptr_t)&mt8183_mcucfg->mp1_misc_config[3]) #define MCUCFG_CPUSYS0_SPARKVRETCNTRL (MCUCFG_BASE + 0x1c00) /* bit-fields of MCUCFG_CPUSYS0_SPARKVRETCNTRL */ #define CPU0_SPARK_VRET_CTRL (0x3f << 0) #define CPU1_SPARK_VRET_CTRL (0x3f << 8) #define CPU2_SPARK_VRET_CTRL (0x3f << 16) #define CPU3_SPARK_VRET_CTRL (0x3f << 24) /* SPARK control in little cores */ #define MCUCFG_CPUSYS0_CPU0_SPMC_CTL (MCUCFG_BASE + 0x1c30) #define MCUCFG_CPUSYS0_CPU1_SPMC_CTL (MCUCFG_BASE + 0x1c34) #define MCUCFG_CPUSYS0_CPU2_SPMC_CTL (MCUCFG_BASE + 0x1c38) #define MCUCFG_CPUSYS0_CPU3_SPMC_CTL (MCUCFG_BASE + 0x1c3c) /* bit-fields of MCUCFG_CPUSYS0_CPU?_SPMC_CTL */ #define SW_SPARK_EN (1 << 0) #define SW_NO_WAIT_Q (1 << 1) /* the MCUCFG which BIG cores used is at (MCUCFG_BASE + 0x2000) */ #define MCUCFG_MP2_BASE (MCUCFG_BASE + 0x2000) #define MCUCFG_MP2_PWR_RST_CTL (MCUCFG_MP2_BASE + 0x8) /* bit-fields of MCUCFG_MP2_PWR_RST_CTL */ #define SW_RST_B (1 << 0) #define TOPAON_APB_MASK (1 << 1) #define MCUCFG_MP2_CPUCFG (MCUCFG_MP2_BASE + 0x208) #define MCUCFG_MP2_RVADDR0 (MCUCFG_MP2_BASE + 0x290) #define MCUCFG_MP2_RVADDR1 (MCUCFG_MP2_BASE + 0x298) #define MCUCFG_MP2_RVADDR2 (MCUCFG_MP2_BASE + 0x2c0) #define MCUCFG_MP2_RVADDR3 (MCUCFG_MP2_BASE + 0x2c8) /* SPMC control */ #define MCUCFG_MP0_SPMC (MCUCFG_BASE + 0x788) #define MCUCFG_MP2_SPMC (MCUCFG_MP2_BASE + 0x2a0) #define MCUCFG_MP2_COQ (MCUCFG_MP2_BASE + 0x2bC) /* per_cpu registers for MCUCFG_MP?_MISC_CONFIG2 */ static const struct per_cpu_reg MCUCFG_BOOTADDR[] = { [0] = { .cluster_addr = MCUCFG_MP0_MISC_CONFIG2, .cpu_stride = 3 }, }; /* per_cpu registers for MCUCFG_MP?_MISC_CONFIG3 */ static const struct per_cpu_reg MCUCFG_INITARCH[] = { [0] = { .cluster_addr = MCUCFG_MP0_MISC_CONFIG3 }, [1] = { .cluster_addr = MCUCFG_MP2_CPUCFG }, }; /* SPARK control in BIG cores */ #define MCUCFG_MP2_PTP3_CPU0_SPMC0 (MCUCFG_MP2_BASE + 0x430) #define MCUCFG_MP2_PTP3_CPU0_SPMC1 (MCUCFG_MP2_BASE + 0x434) #define MCUCFG_MP2_PTP3_CPU1_SPMC0 (MCUCFG_MP2_BASE + 0x438) #define MCUCFG_MP2_PTP3_CPU1_SPMC1 (MCUCFG_MP2_BASE + 0x43c) #define MCUCFG_MP2_PTP3_CPU2_SPMC0 (MCUCFG_MP2_BASE + 0x440) #define MCUCFG_MP2_PTP3_CPU2_SPMC1 (MCUCFG_MP2_BASE + 0x444) #define MCUCFG_MP2_PTP3_CPU3_SPMC0 (MCUCFG_MP2_BASE + 0x448) #define MCUCFG_MP2_PTP3_CPU3_SPMC1 (MCUCFG_MP2_BASE + 0x44c) /* bit-fields of MCUCFG_MP2_PTP3_CPU?_SPMC? */ #define SW_SPARK_EN (1 << 0) #define SW_NO_WAIT_Q (1 << 1) #define MCUCFG_MP2_SPARK2LDO (MCUCFG_MP2_BASE + 0x700) /* bit-fields of MCUCFG_MP2_SPARK2LDO */ #define SPARK_VRET_CTRL (0x3f << 0) #define CPU0_SPARK_LDO_AMUXSEL (0xf << 6) #define CPU1_SPARK_LDO_AMUXSEL (0xf << 10) #define CPU2_SPARK_LDO_AMUXSEL (0xf << 14) #define CPU3_SPARK_LDO_AMUXSEL (0xf << 18) /* per_cpu registers for SPARK */ static const struct per_cpu_reg MCUCFG_SPARK[] = { [0] = { .cluster_addr = MCUCFG_CPUSYS0_CPU0_SPMC_CTL, .cpu_stride = 2 }, [1] = { .cluster_addr = MCUCFG_MP2_PTP3_CPU0_SPMC0, .cpu_stride = 3 }, }; /* per_cpu registers for SPARK2LDO */ static const struct per_cpu_reg MCUCFG_SPARK2LDO[] = { [0] = { .cluster_addr = MCUCFG_CPUSYS0_SPARKVRETCNTRL }, [1] = { .cluster_addr = MCUCFG_MP2_SPARK2LDO }, }; #endif /* MTSPMC_PRIVATE_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/sspm/000077500000000000000000000000001355360272700232405ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/sspm/sspm.c000066400000000000000000000060461355360272700243740ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include static void memcpy_to_sspm(uint32_t dst, uint32_t *src, uint32_t len) { while (len--) { mmio_write_32(dst, *src); dst += sizeof(uint32_t); src++; } } static void memcpy_from_sspm(uint32_t *dst, uint32_t src, uint32_t len) { while (len--) { *dst = mmio_read_32(src); dst++; src += sizeof(uint32_t); } } int sspm_mbox_read(uint32_t slot, uint32_t *data, uint32_t len) { if (slot >= 32) { ERROR("%s:slot = %d\n", __func__, slot); return -EINVAL; } if (data) memcpy_from_sspm(data, MBOX3_BASE + slot * 4, len); return 0; } int sspm_mbox_write(uint32_t slot, uint32_t *data, uint32_t len) { if (slot >= 32) { ERROR("%s:slot = %d\n", __func__, slot); return -EINVAL; } if (data) memcpy_to_sspm(MBOX3_BASE + slot * 4, data, len); return 0; } static int sspm_ipi_check_ack(uint32_t id) { int ret = 0; if (id == IPI_ID_PLATFORM) { if ((mmio_read_32(MBOX0_BASE + MBOX_IN_IRQ_OFS) & 0x1) == 0x1) ret = -EINPROGRESS; } else if (id == IPI_ID_SUSPEND) { if ((mmio_read_32(MBOX1_BASE + MBOX_IN_IRQ_OFS) & 0x2) == 0x2) ret = -EINPROGRESS; } else { ERROR("%s: id = %d\n", __func__, id); ret = -EINVAL; } return ret; } int sspm_ipi_send_non_blocking(uint32_t id, uint32_t *data) { int ret = 0; ret = sspm_ipi_check_ack(id); if (ret) return ret; if (id == IPI_ID_PLATFORM) { memcpy_to_sspm(MBOX0_BASE + PINR_OFFSET_PLATFORM * 4, data, PINR_SIZE_PLATFORM); dsb(); mmio_write_32(MBOX0_BASE + MBOX_OUT_IRQ_OFS, 0x1); } else if (id == IPI_ID_SUSPEND) { memcpy_to_sspm(MBOX1_BASE + PINR_OFFSET_SUSPEND * 4, data, PINR_SIZE_SUSPEND); dsb(); mmio_write_32(MBOX1_BASE + MBOX_OUT_IRQ_OFS, 0x2); } return 0; } int sspm_ipi_recv_non_blocking(uint32_t id, uint32_t *data, uint32_t len) { int ret = 0; ret = sspm_ipi_check_ack(id); if (ret == -EINPROGRESS) { if (id == IPI_ID_PLATFORM) { memcpy_from_sspm(data, MBOX0_BASE + PINR_OFFSET_PLATFORM * 4, len); dsb(); /* clear interrupt bit*/ mmio_write_32(MBOX0_BASE + MBOX_IN_IRQ_OFS, 0x1); ret = 0; } else if (id == IPI_ID_SUSPEND) { memcpy_from_sspm(data, MBOX1_BASE + PINR_OFFSET_SUSPEND * 4, len); dsb(); /* clear interrupt bit*/ mmio_write_32(MBOX1_BASE + MBOX_IN_IRQ_OFS, 0x2); ret = 0; } } else if (ret == 0) { ret = -EBUSY; } return ret; } int sspm_alive_show(void) { uint32_t ipi_data, count; int ret = 0; count = 5; ipi_data = 0xdead; if (sspm_ipi_send_non_blocking(IPI_ID_PLATFORM, &ipi_data) != 0) { ERROR("sspm init send fail! ret=%d\n", ret); return -1; } while (sspm_ipi_recv_non_blocking(IPI_ID_PLATFORM, &ipi_data, sizeof(ipi_data)) && count) { mdelay(100); count--; } return (ipi_data == 1) ? 0 : -1; } trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/sspm/sspm.h000066400000000000000000000017461355360272700244030ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __SSPM_H__ #define __SSPM_H__ /* These should sync with sspm.bin */ #define IPI_ID_PLATFORM 0 #define IPI_ID_SUSPEND 6 #define PINR_OFFSET_PLATFORM 0 #define PINR_SIZE_PLATFORM 3 #define PINR_OFFSET_SUSPEND 2 #define PINR_SIZE_SUSPEND 8 #define MBOX0_BASE 0x10450000 #define MBOX1_BASE 0x10460000 #define MBOX3_BASE 0x10480000 #define MBOX_OUT_IRQ_OFS 0x1000 #define MBOX_IN_IRQ_OFS 0x1004 #define SHAREMBOX_OFFSET_MCDI 0 #define SHAREMBOX_SIZE_MCDI 20 #define SHAREMBOX_OFFSET_SUSPEND 26 #define SHAREMBOX_SIZE_SUSPEND 6 int sspm_mbox_read(uint32_t slot, uint32_t *data, uint32_t len); int sspm_mbox_write(uint32_t slot, uint32_t *data, uint32_t len); int sspm_ipi_send_non_blocking(uint32_t id, uint32_t *data); int sspm_ipi_recv_non_blocking(uint32_t slot, uint32_t *data, uint32_t len); int sspm_alive_show(void); #endif /* __SSPM_H__ */ trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/uart/000077500000000000000000000000001355360272700232315ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/uart/uart.c000066400000000000000000000067541355360272700243640ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include static struct mt_uart uart_save_addr[DRV_SUPPORT_UART_PORTS]; static const unsigned int uart_base_addr[DRV_SUPPORT_UART_PORTS] = { UART0_BASE, UART1_BASE }; void mt_uart_restore(void) { int uart_idx = UART_PORT0; struct mt_uart *uart; unsigned long base; /* Must NOT print any debug log before UART restore */ for (uart_idx = UART_PORT0; uart_idx < HW_SUPPORT_UART_PORTS; uart_idx++) { uart = &uart_save_addr[uart_idx]; base = uart->base; mmio_write_32(UART_LCR(base), UART_LCR_MODE_B); mmio_write_32(UART_EFR(base), uart->registers.efr); mmio_write_32(UART_LCR(base), uart->registers.lcr); mmio_write_32(UART_FCR(base), uart->registers.fcr); /* baudrate */ mmio_write_32(UART_HIGHSPEED(base), uart->registers.highspeed); mmio_write_32(UART_FRACDIV_L(base), uart->registers.fracdiv_l); mmio_write_32(UART_FRACDIV_M(base), uart->registers.fracdiv_m); mmio_write_32(UART_LCR(base), uart->registers.lcr | UART_LCR_DLAB); mmio_write_32(UART_DLL(base), uart->registers.dll); mmio_write_32(UART_DLH(base), uart->registers.dlh); mmio_write_32(UART_LCR(base), uart->registers.lcr); mmio_write_32(UART_SAMPLE_COUNT(base), uart->registers.sample_count); mmio_write_32(UART_SAMPLE_POINT(base), uart->registers.sample_point); mmio_write_32(UART_GUARD(base), uart->registers.guard); /* flow control */ mmio_write_32(UART_ESCAPE_EN(base), uart->registers.escape_en); mmio_write_32(UART_MCR(base), uart->registers.mcr); mmio_write_32(UART_IER(base), uart->registers.ier); mmio_write_32(UART_SCR(base), uart->registers.scr); } } void mt_uart_save(void) { int uart_idx = UART_PORT0; struct mt_uart *uart; unsigned long base; for (uart_idx = UART_PORT0; uart_idx < HW_SUPPORT_UART_PORTS; uart_idx++) { uart_save_addr[uart_idx].base = uart_base_addr[uart_idx]; base = uart_base_addr[uart_idx]; uart = &uart_save_addr[uart_idx]; uart->registers.lcr = mmio_read_32(UART_LCR(base)); mmio_write_32(UART_LCR(base), UART_LCR_MODE_B); uart->registers.efr = mmio_read_32(UART_EFR(base)); mmio_write_32(UART_LCR(base), uart->registers.lcr); uart->registers.fcr = mmio_read_32(UART_FCR_RD(base)); /* baudrate */ uart->registers.highspeed = mmio_read_32(UART_HIGHSPEED(base)); uart->registers.fracdiv_l = mmio_read_32(UART_FRACDIV_L(base)); uart->registers.fracdiv_m = mmio_read_32(UART_FRACDIV_M(base)); mmio_write_32(UART_LCR(base), uart->registers.lcr | UART_LCR_DLAB); uart->registers.dll = mmio_read_32(UART_DLL(base)); uart->registers.dlh = mmio_read_32(UART_DLH(base)); mmio_write_32(UART_LCR(base), uart->registers.lcr); uart->registers.sample_count = mmio_read_32( UART_SAMPLE_COUNT(base)); uart->registers.sample_point = mmio_read_32( UART_SAMPLE_POINT(base)); uart->registers.guard = mmio_read_32(UART_GUARD(base)); /* flow control */ uart->registers.escape_en = mmio_read_32(UART_ESCAPE_EN(base)); uart->registers.mcr = mmio_read_32(UART_MCR(base)); uart->registers.ier = mmio_read_32(UART_IER(base)); uart->registers.scr = mmio_read_32(UART_SCR(base)); } } void mt_console_uart_cg(int on) { if (on) mmio_write_32(UART_CLOCK_GATE_CLR, UART0_CLOCK_GATE_BIT); else mmio_write_32(UART_CLOCK_GATE_SET, UART0_CLOCK_GATE_BIT); } int mt_console_uart_cg_status(void) { return mmio_read_32(UART_CLOCK_GATE_STA) & UART0_CLOCK_GATE_BIT; } trusted-firmware-a-2.2/plat/mediatek/mt8183/drivers/uart/uart.h000066400000000000000000000062751355360272700243670ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __UART_H__ #define __UART_H__ #include /* UART HW information */ #define HW_SUPPORT_UART_PORTS 2 #define DRV_SUPPORT_UART_PORTS 2 /* console UART clock cg */ #define UART_CLOCK_GATE_SET (INFRACFG_AO_BASE + 0x80) #define UART_CLOCK_GATE_CLR (INFRACFG_AO_BASE + 0x84) #define UART_CLOCK_GATE_STA (INFRACFG_AO_BASE + 0x90) #define UART0_CLOCK_GATE_BIT (1U<<22) #define UART1_CLOCK_GATE_BIT (1U<<23) /* UART registers */ #define UART_RBR(_baseaddr) (_baseaddr + 0x0) #define UART_THR(_baseaddr) (_baseaddr + 0x0) #define UART_IER(_baseaddr) (_baseaddr + 0x4) #define UART_IIR(_baseaddr) (_baseaddr + 0x8) #define UART_FCR(_baseaddr) (_baseaddr + 0x8) #define UART_LCR(_baseaddr) (_baseaddr + 0xc) #define UART_MCR(_baseaddr) (_baseaddr + 0x10) #define UART_LSR(_baseaddr) (_baseaddr + 0x14) #define UART_MSR(_baseaddr) (_baseaddr + 0x18) #define UART_SCR(_baseaddr) (_baseaddr + 0x1c) #define UART_DLL(_baseaddr) (_baseaddr + 0x0) #define UART_DLH(_baseaddr) (_baseaddr + 0x4) #define UART_EFR(_baseaddr) (_baseaddr + 0x8) #define UART_XON1(_baseaddr) (_baseaddr + 0x10) #define UART_XON2(_baseaddr) (_baseaddr + 0x14) #define UART_XOFF1(_baseaddr) (_baseaddr + 0x18) #define UART_XOFF2(_baseaddr) (_baseaddr + 0x1c) #define UART_AUTOBAUD(_baseaddr) (_baseaddr + 0x20) #define UART_HIGHSPEED(_baseaddr) (_baseaddr + 0x24) #define UART_SAMPLE_COUNT(_baseaddr) (_baseaddr + 0x28) #define UART_SAMPLE_POINT(_baseaddr) (_baseaddr + 0x2c) #define UART_AUTOBAUD_REG(_baseaddr) (_baseaddr + 0x30) #define UART_RATE_FIX_REG(_baseaddr) (_baseaddr + 0x34) #define UART_AUTO_BAUDSAMPLE(_baseaddr) (_baseaddr + 0x38) #define UART_GUARD(_baseaddr) (_baseaddr + 0x3c) #define UART_ESCAPE_DAT(_baseaddr) (_baseaddr + 0x40) #define UART_ESCAPE_EN(_baseaddr) (_baseaddr + 0x44) #define UART_SLEEP_EN(_baseaddr) (_baseaddr + 0x48) #define UART_DMA_EN(_baseaddr) (_baseaddr + 0x4c) #define UART_RXTRI_AD(_baseaddr) (_baseaddr + 0x50) #define UART_FRACDIV_L(_baseaddr) (_baseaddr + 0x54) #define UART_FRACDIV_M(_baseaddr) (_baseaddr + 0x58) #define UART_FCR_RD(_baseaddr) (_baseaddr + 0x5C) #define UART_USB_RX_SEL(_baseaddr) (_baseaddr + 0xB0) #define UART_SLEEP_REQ(_baseaddr) (_baseaddr + 0xB4) #define UART_SLEEP_ACK(_baseaddr) (_baseaddr + 0xB8) #define UART_SPM_SEL(_baseaddr) (_baseaddr + 0xBC) #define UART_LCR_DLAB 0x0080 #define UART_LCR_MODE_B 0x00bf enum uart_port_ID { UART_PORT0 = 0, UART_PORT1 }; struct mt_uart_register { unsigned int dll; unsigned int dlh; unsigned int ier; unsigned int lcr; unsigned int mcr; unsigned int fcr; unsigned int lsr; unsigned int scr; unsigned int efr; unsigned int highspeed; unsigned int sample_count; unsigned int sample_point; unsigned int fracdiv_l; unsigned int fracdiv_m; unsigned int escape_en; unsigned int guard; unsigned int rx_sel; }; struct mt_uart { unsigned long base; struct mt_uart_register registers; }; /* external API */ void mt_uart_save(void); void mt_uart_restore(void); void mt_console_uart_cg(int on); int mt_console_uart_cg_status(void); #endif /* __UART_H__ */ trusted-firmware-a-2.2/plat/mediatek/mt8183/include/000077500000000000000000000000001355360272700222235ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/mediatek/mt8183/include/mcucfg.h000066400000000000000000000437421355360272700236520ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MT8183_MCUCFG_H #define MT8183_MCUCFG_H #include #include struct mt8183_mcucfg_regs { uint32_t mp0_ca7l_cache_config; /* 0x0 */ struct { uint32_t mem_delsel0; uint32_t mem_delsel1; } mp0_cpu[4]; /* 0x4 */ uint32_t mp0_cache_mem_delsel0; /* 0x24 */ uint32_t mp0_cache_mem_delsel1; /* 0x28 */ uint32_t mp0_axi_config; /* 0x2C */ uint32_t mp0_misc_config[10]; /* 0x30 */ uint32_t mp0_ca7l_cfg_dis; /* 0x58 */ uint32_t mp0_ca7l_clken_ctrl; /* 0x5C */ uint32_t mp0_ca7l_rst_ctrl; /* 0x60 */ uint32_t mp0_ca7l_misc_config; /* 0x64 */ uint32_t mp0_ca7l_dbg_pwr_ctrl; /* 0x68 */ uint32_t mp0_rw_rsvd0; /* 0x6C */ uint32_t mp0_rw_rsvd1; /* 0x70 */ uint32_t mp0_ro_rsvd; /* 0x74 */ uint32_t reserved0_0; /* 0x78 */ uint32_t mp0_l2_cache_parity1_rdata; /* 0x7C */ uint32_t mp0_l2_cache_parity2_rdata; /* 0x80 */ uint32_t reserved0_1; /* 0x84 */ uint32_t mp0_rgu_dcm_config; /* 0x88 */ uint32_t mp0_ca53_specific_ctrl; /* 0x8C */ uint32_t mp0_esr_case; /* 0x90 */ uint32_t mp0_esr_mask; /* 0x94 */ uint32_t mp0_esr_trig_en; /* 0x98 */ uint32_t reserved_0_2; /* 0x9C */ uint32_t mp0_ses_cg_en; /* 0xA0 */ uint32_t reserved0_3[216]; /* 0xA4 */ uint32_t mp_dbg_ctrl; /* 0x404 */ uint32_t reserved0_4[34]; /* 0x408 */ uint32_t mp_dfd_ctrl; /* 0x490 */ uint32_t dfd_cnt_l; /* 0x494 */ uint32_t dfd_cnt_h; /* 0x498 */ uint32_t misccfg_ro_rsvd; /* 0x49C */ uint32_t reserved0_5[24]; /* 0x4A0 */ uint32_t mp1_rst_status; /* 0x500 */ uint32_t mp1_dbg_ctrl; /* 0x504 */ uint32_t mp1_dbg_flag; /* 0x508 */ uint32_t mp1_ca7l_ir_mon; /* 0x50C */ uint32_t reserved0_6[32]; /* 0x510 */ uint32_t mcusys_dbg_mon_sel_a; /* 0x590 */ uint32_t mcucys_dbg_mon; /* 0x594 */ uint32_t misccfg_sec_voi_status0; /* 0x598 */ uint32_t misccfg_sec_vio_status1; /* 0x59C */ uint32_t reserved0_7[18]; /* 0x5A0 */ uint32_t gic500_int_mask; /* 0x5E8 */ uint32_t core_rst_en_latch; /* 0x5EC */ uint32_t reserved0_8[3]; /* 0x5F0 */ uint32_t dbg_core_ret; /* 0x5FC */ uint32_t mcusys_config_a; /* 0x600 */ uint32_t mcusys_config1_a; /* 0x604 */ uint32_t mcusys_gic_prebase_a; /* 0x608 */ uint32_t mcusys_pinmux; /* 0x60C */ uint32_t sec_range0_start; /* 0x610 */ uint32_t sec_range0_end; /* 0x614 */ uint32_t sec_range_enable; /* 0x618 */ uint32_t l2c_mm_base; /* 0x61C */ uint32_t reserved0_9[8]; /* 0x620 */ uint32_t aclken_div; /* 0x640 */ uint32_t pclken_div; /* 0x644 */ uint32_t l2c_sram_ctrl; /* 0x648 */ uint32_t armpll_jit_ctrl; /* 0x64C */ uint32_t cci_addrmap; /* 0x650 */ uint32_t cci_config; /* 0x654 */ uint32_t cci_periphbase; /* 0x658 */ uint32_t cci_nevntcntovfl; /* 0x65C */ uint32_t cci_clk_ctrl; /* 0x660 */ uint32_t cci_acel_s1_ctrl; /* 0x664 */ uint32_t mcusys_bus_fabric_dcm_ctrl; /* 0x668 */ uint32_t mcu_misc_dcm_ctrl; /* 0x66C */ uint32_t xgpt_ctl; /* 0x670 */ uint32_t xgpt_idx; /* 0x674 */ uint32_t reserved0_10[3]; /* 0x678 */ uint32_t mcusys_rw_rsvd0; /* 0x684 */ uint32_t mcusys_rw_rsvd1; /* 0x688 */ uint32_t reserved0_11[13]; /* 0x68C */ uint32_t gic_500_delsel_ctl; /* 0x6C0 */ uint32_t etb_delsel_ctl; /* 0x6C4 */ uint32_t etb_rst_ctl; /* 0x6C8 */ uint32_t reserved0_12[29]; /* 0x6CC */ uint32_t cci_adb400_dcm_config; /* 0x740 */ uint32_t sync_dcm_config; /* 0x744 */ uint32_t reserved0_13; /* 0x748 */ uint32_t sync_dcm_cluster_config; /* 0x74C */ uint32_t sw_udi; /* 0x750 */ uint32_t reserved0_14; /* 0x754 */ uint32_t gic_sync_dcm; /* 0x758 */ uint32_t big_dbg_pwr_ctrl; /* 0x75C */ uint32_t gic_cpu_periphbase; /* 0x760 */ uint32_t axi_cpu_config; /* 0x764 */ uint32_t reserved0_15[2]; /* 0x768 */ uint32_t mcsib_sys_ctrl1; /* 0x770 */ uint32_t mcsib_sys_ctrl2; /* 0x774 */ uint32_t mcsib_sys_ctrl3; /* 0x778 */ uint32_t mcsib_sys_ctrl4; /* 0x77C */ uint32_t mcsib_dbg_ctrl1; /* 0x780 */ uint32_t pwrmcu_apb2to1; /* 0x784 */ uint32_t mp0_spmc; /* 0x788 */ uint32_t reserved0_16; /* 0x78C */ uint32_t mp0_spmc_sram_ctl; /* 0x790 */ uint32_t reserved0_17; /* 0x794 */ uint32_t mp0_sw_rst_wait_cycle; /* 0x798 */ uint32_t reserved0_18; /* 0x79C */ uint32_t mp0_pll_divider_cfg; /* 0x7A0 */ uint32_t reserved0_19; /* 0x7A4 */ uint32_t mp2_pll_divider_cfg; /* 0x7A8 */ uint32_t reserved0_20[5]; /* 0x7AC */ uint32_t bus_pll_divider_cfg; /* 0x7C0 */ uint32_t reserved0_21[7]; /* 0x7C4 */ uint32_t clusterid_aff1; /* 0x7E0 */ uint32_t clusterid_aff2; /* 0x7E4 */ uint32_t reserved0_22[2]; /* 0x7E8 */ uint32_t l2_cfg_mp0; /* 0x7F0 */ uint32_t l2_cfg_mp1; /* 0x7F4 */ uint32_t reserved0_23[218]; /* 0x7F8 */ uint32_t mscib_dcm_en; /* 0xB60 */ uint32_t reserved0_24[1063]; /* 0xB64 */ uint32_t cpusys0_sparkvretcntrl; /* 0x1C00 */ uint32_t cpusys0_sparken; /* 0x1C04 */ uint32_t cpusys0_amuxsel; /* 0x1C08 */ uint32_t reserved0_25[9]; /* 0x1C0C */ uint32_t cpusys0_cpu0_spmc_ctl; /* 0x1C30 */ uint32_t cpusys0_cpu1_spmc_ctl; /* 0x1C34 */ uint32_t cpusys0_cpu2_spmc_ctl; /* 0x1C38 */ uint32_t cpusys0_cpu3_spmc_ctl; /* 0x1C3C */ uint32_t reserved0_26[8]; /* 0x1C40 */ uint32_t mp0_sync_dcm_cgavg_ctrl; /* 0x1C60 */ uint32_t mp0_sync_dcm_cgavg_fact; /* 0x1C64 */ uint32_t mp0_sync_dcm_cgavg_rfact; /* 0x1C68 */ uint32_t mp0_sync_dcm_cgavg; /* 0x1C6C */ uint32_t mp0_l2_parity_clr; /* 0x1C70 */ uint32_t reserved0_27[357]; /* 0x1C74 */ uint32_t mp2_cpucfg; /* 0x2208 */ uint32_t mp2_axi_config; /* 0x220C */ uint32_t reserved0_28[25]; /* 0x2210 */ uint32_t mp2_sync_dcm; /* 0x2274 */ uint32_t reserved0_29[10]; /* 0x2278 */ uint32_t ptp3_cputop_spmc0; /* 0x22A0 */ uint32_t ptp3_cputop_spmc1; /* 0x22A4 */ uint32_t reserved0_30[98]; /* 0x22A8 */ uint32_t ptp3_cpu0_spmc0; /* 0x2430 */ uint32_t ptp3_cpu0_spmc1; /* 0x2434 */ uint32_t ptp3_cpu1_spmc0; /* 0x2438 */ uint32_t ptp3_cpu1_spmc1; /* 0x243C */ uint32_t ptp3_cpu2_spmc0; /* 0x2440 */ uint32_t ptp3_cpu2_spmc1; /* 0x2444 */ uint32_t ptp3_cpu3_spmc0; /* 0x2448 */ uint32_t ptp3_cpu3_spmc1; /* 0x244C */ uint32_t ptp3_cpux_spmc; /* 0x2450 */ uint32_t reserved0_31[171]; /* 0x2454 */ uint32_t spark2ld0; /* 0x2700 */ }; static struct mt8183_mcucfg_regs *const mt8183_mcucfg = (void *)MCUCFG_BASE; enum { SW_SPARK_EN = 1 << 0, SW_NO_WAIT_FOR_Q_CHANNEL = 1 << 1, SW_FSM_OVERRIDE = 1 << 2, SW_LOGIC_PRE1_PDB = 1 << 3, SW_LOGIC_PRE2_PDB = 1 << 4, SW_LOGIC_PDB = 1 << 5, SW_ISO = 1 << 6, SW_SRAM_SLEEPB = 0x3f << 7, SW_SRAM_ISOINTB = 1 << 13, SW_CLK_DIS = 1 << 14, SW_CKISO = 1 << 15, SW_PD = 0x3f << 16, SW_HOT_PLUG_RESET = 1 << 22, SW_PWR_ON_OVERRIDE_EN = 1 << 23, SW_PWR_ON = 1 << 24, SW_COQ_DIS = 1 << 25, LOGIC_PDBO_ALL_OFF_ACK = 1 << 26, LOGIC_PDBO_ALL_ON_ACK = 1 << 27, LOGIC_PRE2_PDBO_ALL_ON_ACK = 1 << 28, LOGIC_PRE1_PDBO_ALL_ON_ACK = 1 << 29 }; enum { CPU_SW_SPARK_EN = 1 << 0, CPU_SW_NO_WAIT_FOR_Q_CHANNEL = 1 << 1, CPU_SW_FSM_OVERRIDE = 1 << 2, CPU_SW_LOGIC_PRE1_PDB = 1 << 3, CPU_SW_LOGIC_PRE2_PDB = 1 << 4, CPU_SW_LOGIC_PDB = 1 << 5, CPU_SW_ISO = 1 << 6, CPU_SW_SRAM_SLEEPB = 1 << 7, CPU_SW_SRAM_ISOINTB = 1 << 8, CPU_SW_CLK_DIS = 1 << 9, CPU_SW_CKISO = 1 << 10, CPU_SW_PD = 0x1f << 11, CPU_SW_HOT_PLUG_RESET = 1 << 16, CPU_SW_POWR_ON_OVERRIDE_EN = 1 << 17, CPU_SW_PWR_ON = 1 << 18, CPU_SPARK2LDO_ALLSWOFF = 1 << 19, CPU_PDBO_ALL_ON_ACK = 1 << 20, CPU_PRE2_PDBO_ALLON_ACK = 1 << 21, CPU_PRE1_PDBO_ALLON_ACK = 1 << 22 }; enum { MP2_AXI_CONFIG_ACINACTM = 1 << 0, MPx_AXI_CONFIG_ACINACTM = 1 << 4, MPX_CA7_MISC_CONFIG_STANDBYWFIL2 = 1 << 28 }; enum { MP0_CPU0_STANDBYWFE = 1 << 20, MP0_CPU1_STANDBYWFE = 1 << 21, MP0_CPU2_STANDBYWFE = 1 << 22, MP0_CPU3_STANDBYWFE = 1 << 23 }; enum { MP1_CPU0_STANDBYWFE = 1 << 20, MP1_CPU1_STANDBYWFE = 1 << 21, MP1_CPU2_STANDBYWFE = 1 << 22, MP1_CPU3_STANDBYWFE = 1 << 23 }; enum { B_SW_HOT_PLUG_RESET = 1 << 30, B_SW_PD_OFFSET = 18, B_SW_PD = 0x3f << B_SW_PD_OFFSET, B_SW_SRAM_SLEEPB_OFFSET = 12, B_SW_SRAM_SLEEPB = 0x3f << B_SW_SRAM_SLEEPB_OFFSET }; enum { B_SW_SRAM_ISOINTB = 1 << 9, B_SW_ISO = 1 << 8, B_SW_LOGIC_PDB = 1 << 7, B_SW_LOGIC_PRE2_PDB = 1 << 6, B_SW_LOGIC_PRE1_PDB = 1 << 5, B_SW_FSM_OVERRIDE = 1 << 4, B_SW_PWR_ON = 1 << 3, B_SW_PWR_ON_OVERRIDE_EN = 1 << 2 }; enum { B_FSM_STATE_OUT_OFFSET = 6, B_FSM_STATE_OUT_MASK = 0x1f << B_FSM_STATE_OUT_OFFSET, B_SW_LOGIC_PDBO_ALL_OFF_ACK = 1 << 5, B_SW_LOGIC_PDBO_ALL_ON_ACK = 1 << 4, B_SW_LOGIC_PRE2_PDBO_ALL_ON_ACK = 1 << 3, B_SW_LOGIC_PRE1_PDBO_ALL_ON_ACK = 1 << 2, B_FSM_OFF = 0 << B_FSM_STATE_OUT_OFFSET, B_FSM_ON = 1 << B_FSM_STATE_OUT_OFFSET, B_FSM_RET = 2 << B_FSM_STATE_OUT_OFFSET }; /* APB Module infracfg_ao */ enum { INFRA_TOPAXI_PROTECTEN_1 = INFRACFG_AO_BASE + 0x250, INFRA_TOPAXI_PROTECTSTA1_1 = INFRACFG_AO_BASE + 0x258, INFRA_TOPAXI_PROTECTEN_1_SET = INFRACFG_AO_BASE + 0x2A8, INFRA_TOPAXI_PROTECTEN_1_CLR = INFRACFG_AO_BASE + 0x2AC }; enum { IDX_PROTECT_MP0_CACTIVE = 10, IDX_PROTECT_MP1_CACTIVE = 11, IDX_PROTECT_ICC0_CACTIVE = 12, IDX_PROTECT_ICD0_CACTIVE = 13, IDX_PROTECT_ICC1_CACTIVE = 14, IDX_PROTECT_ICD1_CACTIVE = 15, IDX_PROTECT_L2C0_CACTIVE = 26, IDX_PROTECT_L2C1_CACTIVE = 27 }; /* cpu boot mode */ enum { MP0_CPUCFG_64BIT_SHIFT = 12, MP1_CPUCFG_64BIT_SHIFT = 28, MP0_CPUCFG_64BIT = 0xf << MP0_CPUCFG_64BIT_SHIFT, MP1_CPUCFG_64BIT = 0xfu << MP1_CPUCFG_64BIT_SHIFT }; /* scu related */ enum { MP0_ACINACTM_SHIFT = 4, MP1_ACINACTM_SHIFT = 4, MP2_ACINACTM_SHIFT = 0, MP0_ACINACTM = 1 << MP0_ACINACTM_SHIFT, MP1_ACINACTM = 1 << MP1_ACINACTM_SHIFT, MP2_ACINACTM = 1 << MP2_ACINACTM_SHIFT }; enum { MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT = 0, MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT = 4, MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT = 8, MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT = 12, MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT = 16, MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK = 0xf << MP1_DIS_RGU0_WAIT_PD_CPUS_L1_ACK_SHIFT, MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK = 0xf << MP1_DIS_RGU1_WAIT_PD_CPUS_L1_ACK_SHIFT, MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK = 0xf << MP1_DIS_RGU2_WAIT_PD_CPUS_L1_ACK_SHIFT, MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK = 0xf << MP1_DIS_RGU3_WAIT_PD_CPUS_L1_ACK_SHIFT, MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK = 0xf << MP1_DIS_RGU_NOCPU_WAIT_PD_CPUS_L1_ACK_SHIFT }; enum { MP1_AINACTS_SHIFT = 4, MP1_AINACTS = 1 << MP1_AINACTS_SHIFT }; enum { MP1_SW_CG_GEN_SHIFT = 12, MP1_SW_CG_GEN = 1 << MP1_SW_CG_GEN_SHIFT }; enum { MP1_L2RSTDISABLE_SHIFT = 14, MP1_L2RSTDISABLE = 1 << MP1_L2RSTDISABLE_SHIFT }; /* bus pll divider dcm related */ enum { BUS_PLLDIVIDER_DCM_DBC_CNT_0_SHIFT = 11, BUS_PLLDIV_ARMWFI_DCM_EN_SHIFT = 24, BUS_PLLDIV_ARMWFE_DCM_EN_SHIFT = 25, BUS_PLLDIV_DCM = (1 << BUS_PLLDIVIDER_DCM_DBC_CNT_0_SHIFT) | (1 << BUS_PLLDIV_ARMWFI_DCM_EN_SHIFT) | (1 << BUS_PLLDIV_ARMWFE_DCM_EN_SHIFT) }; /* mp0 pll divider dcm related */ enum { MP0_PLLDIV_DCM_DBC_CNT_0_SHIFT = 11, MP0_PLLDIV_ARMWFI_DCM_EN_SHIFT = 24, MP0_PLLDIV_ARMWFE_DCM_EN_SHIFT = 25, MP0_PLLDIV_LASTCORE_IDLE_EN_SHIFT = 31, MP0_PLLDIV_DCM = (1 << MP0_PLLDIV_DCM_DBC_CNT_0_SHIFT) | (1 << MP0_PLLDIV_ARMWFI_DCM_EN_SHIFT) | (1 << MP0_PLLDIV_ARMWFE_DCM_EN_SHIFT) | (1u << MP0_PLLDIV_LASTCORE_IDLE_EN_SHIFT) }; /* mp2 pll divider dcm related */ enum { MP2_PLLDIV_DCM_DBC_CNT_0_SHIFT = 11, MP2_PLLDIV_ARMWFI_DCM_EN_SHIFT = 24, MP2_PLLDIV_ARMWFE_DCM_EN_SHIFT = 25, MP2_PLLDIV_LASTCORE_IDLE_EN_SHIFT = 31, MP2_PLLDIV_DCM = (1 << MP2_PLLDIV_DCM_DBC_CNT_0_SHIFT) | (1 << MP2_PLLDIV_ARMWFI_DCM_EN_SHIFT) | (1 << MP2_PLLDIV_ARMWFE_DCM_EN_SHIFT) | (1u << MP2_PLLDIV_LASTCORE_IDLE_EN_SHIFT) }; /* mcsib dcm related */ enum { MCSIB_CACTIVE_SEL_SHIFT = 0, MCSIB_DCM_EN_SHIFT = 16, MCSIB_CACTIVE_SEL_MASK = 0xffff << MCSIB_CACTIVE_SEL_SHIFT, MCSIB_CACTIVE_SEL = 0xffff << MCSIB_CACTIVE_SEL_SHIFT, MCSIB_DCM_MASK = 0xffffu << MCSIB_DCM_EN_SHIFT, MCSIB_DCM = 0xffffu << MCSIB_DCM_EN_SHIFT, }; /* cci adb400 dcm related */ enum { CCI_M0_ADB400_DCM_EN_SHIFT = 0, CCI_M1_ADB400_DCM_EN_SHIFT = 1, CCI_M2_ADB400_DCM_EN_SHIFT = 2, CCI_S2_ADB400_DCM_EN_SHIFT = 3, CCI_S3_ADB400_DCM_EN_SHIFT = 4, CCI_S4_ADB400_DCM_EN_SHIFT = 5, CCI_S5_ADB400_DCM_EN_SHIFT = 6, ACP_S3_ADB400_DCM_EN_SHIFT = 11, CCI_ADB400_DCM_MASK = (1 << CCI_M0_ADB400_DCM_EN_SHIFT) | (1 << CCI_M1_ADB400_DCM_EN_SHIFT) | (1 << CCI_M2_ADB400_DCM_EN_SHIFT) | (1 << CCI_S2_ADB400_DCM_EN_SHIFT) | (1 << CCI_S4_ADB400_DCM_EN_SHIFT) | (1 << CCI_S4_ADB400_DCM_EN_SHIFT) | (1 << CCI_S5_ADB400_DCM_EN_SHIFT) | (1 << ACP_S3_ADB400_DCM_EN_SHIFT), CCI_ADB400_DCM = (1 << CCI_M0_ADB400_DCM_EN_SHIFT) | (1 << CCI_M1_ADB400_DCM_EN_SHIFT) | (1 << CCI_M2_ADB400_DCM_EN_SHIFT) | (0 << CCI_S2_ADB400_DCM_EN_SHIFT) | (0 << CCI_S4_ADB400_DCM_EN_SHIFT) | (0 << CCI_S4_ADB400_DCM_EN_SHIFT) | (0 << CCI_S5_ADB400_DCM_EN_SHIFT) | (1 << ACP_S3_ADB400_DCM_EN_SHIFT) }; /* sync dcm related */ enum { CCI_SYNC_DCM_DIV_EN_SHIFT = 0, CCI_SYNC_DCM_UPDATE_TOG_SHIFT = 1, CCI_SYNC_DCM_DIV_SEL_SHIFT = 2, MP0_SYNC_DCM_DIV_EN_SHIFT = 10, MP0_SYNC_DCM_UPDATE_TOG_SHIFT = 11, MP0_SYNC_DCM_DIV_SEL_SHIFT = 12, SYNC_DCM_MASK = (1 << CCI_SYNC_DCM_DIV_EN_SHIFT) | (1 << CCI_SYNC_DCM_UPDATE_TOG_SHIFT) | (0x7f << CCI_SYNC_DCM_DIV_SEL_SHIFT) | (1 << MP0_SYNC_DCM_DIV_EN_SHIFT) | (1 << MP0_SYNC_DCM_UPDATE_TOG_SHIFT) | (0x7f << MP0_SYNC_DCM_DIV_SEL_SHIFT), SYNC_DCM = (1 << CCI_SYNC_DCM_DIV_EN_SHIFT) | (1 << CCI_SYNC_DCM_UPDATE_TOG_SHIFT) | (0 << CCI_SYNC_DCM_DIV_SEL_SHIFT) | (1 << MP0_SYNC_DCM_DIV_EN_SHIFT) | (1 << MP0_SYNC_DCM_UPDATE_TOG_SHIFT) | (0 << MP0_SYNC_DCM_DIV_SEL_SHIFT) }; /* mcu bus dcm related */ enum { MCU_BUS_DCM_EN_SHIFT = 8, MCU_BUS_DCM = 1 << MCU_BUS_DCM_EN_SHIFT }; /* mcusys bus fabric dcm related */ enum { ACLK_INFRA_DYNAMIC_CG_EN_SHIFT = 0, EMI2_ADB400_S_DCM_CTRL_SHIFT = 1, ACLK_GPU_DYNAMIC_CG_EN_SHIFT = 2, ACLK_PSYS_DYNAMIC_CG_EN_SHIFT = 3, MP0_ADB400_S_DCM_CTRL_SHIFT = 4, MP0_ADB400_M_DCM_CTRL_SHIFT = 5, MP1_ADB400_S_DCM_CTRL_SHIFT = 6, MP1_ADB400_M_DCM_CTRL_SHIFT = 7, EMICLK_EMI_DYNAMIC_CG_EN_SHIFT = 8, INFRACLK_INFRA_DYNAMIC_CG_EN_SHIFT = 9, EMICLK_GPU_DYNAMIC_CG_EN_SHIFT = 10, INFRACLK_PSYS_DYNAMIC_CG_EN_SHIFT = 11, EMICLK_EMI1_DYNAMIC_CG_EN_SHIFT = 12, EMI1_ADB400_S_DCM_CTRL_SHIFT = 16, MP2_ADB400_M_DCM_CTRL_SHIFT = 17, MP0_ICC_AXI_STREAM_ARCH_CG_SHIFT = 18, MP1_ICC_AXI_STREAM_ARCH_CG_SHIFT = 19, MP2_ICC_AXI_STREAM_ARCH_CG_SHIFT = 20, L2_SHARE_ADB400_DCM_CTRL_SHIFT = 21, MP1_AGGRESS_DCM_CTRL_SHIFT = 22, MP0_AGGRESS_DCM_CTRL_SHIFT = 23, MP0_ADB400_ACP_S_DCM_CTRL_SHIFT = 24, MP0_ADB400_ACP_M_DCM_CTRL_SHIFT = 25, MP1_ADB400_ACP_S_DCM_CTRL_SHIFT = 26, MP1_ADB400_ACP_M_DCM_CTRL_SHIFT = 27, MP3_ADB400_M_DCM_CTRL_SHIFT = 28, MP3_ICC_AXI_STREAM_ARCH_CG_SHIFT = 29, MCUSYS_BUS_FABRIC_DCM_MASK = (1 << ACLK_INFRA_DYNAMIC_CG_EN_SHIFT) | (1 << EMI2_ADB400_S_DCM_CTRL_SHIFT) | (1 << ACLK_GPU_DYNAMIC_CG_EN_SHIFT) | (1 << ACLK_PSYS_DYNAMIC_CG_EN_SHIFT) | (1 << MP0_ADB400_S_DCM_CTRL_SHIFT) | (1 << MP0_ADB400_M_DCM_CTRL_SHIFT) | (1 << MP1_ADB400_S_DCM_CTRL_SHIFT) | (1 << MP1_ADB400_M_DCM_CTRL_SHIFT) | (1 << EMICLK_EMI_DYNAMIC_CG_EN_SHIFT) | (1 << INFRACLK_INFRA_DYNAMIC_CG_EN_SHIFT) | (1 << EMICLK_GPU_DYNAMIC_CG_EN_SHIFT) | (1 << INFRACLK_PSYS_DYNAMIC_CG_EN_SHIFT) | (1 << EMICLK_EMI1_DYNAMIC_CG_EN_SHIFT) | (1 << EMI1_ADB400_S_DCM_CTRL_SHIFT) | (1 << MP2_ADB400_M_DCM_CTRL_SHIFT) | (1 << MP0_ICC_AXI_STREAM_ARCH_CG_SHIFT) | (1 << MP1_ICC_AXI_STREAM_ARCH_CG_SHIFT) | (1 << MP2_ICC_AXI_STREAM_ARCH_CG_SHIFT) | (1 << L2_SHARE_ADB400_DCM_CTRL_SHIFT) | (1 << MP1_AGGRESS_DCM_CTRL_SHIFT) | (1 << MP0_AGGRESS_DCM_CTRL_SHIFT) | (1 << MP0_ADB400_ACP_S_DCM_CTRL_SHIFT) | (1 << MP0_ADB400_ACP_M_DCM_CTRL_SHIFT) | (1 << MP1_ADB400_ACP_S_DCM_CTRL_SHIFT) | (1 << MP1_ADB400_ACP_M_DCM_CTRL_SHIFT) | (1 << MP3_ADB400_M_DCM_CTRL_SHIFT) | (1 << MP3_ICC_AXI_STREAM_ARCH_CG_SHIFT), MCUSYS_BUS_FABRIC_DCM = (1 << ACLK_INFRA_DYNAMIC_CG_EN_SHIFT) | (1 << EMI2_ADB400_S_DCM_CTRL_SHIFT) | (1 << ACLK_GPU_DYNAMIC_CG_EN_SHIFT) | (1 << ACLK_PSYS_DYNAMIC_CG_EN_SHIFT) | (0 << MP0_ADB400_S_DCM_CTRL_SHIFT) | (0 << MP0_ADB400_M_DCM_CTRL_SHIFT) | (1 << MP1_ADB400_S_DCM_CTRL_SHIFT) | (1 << MP1_ADB400_M_DCM_CTRL_SHIFT) | (1 << EMICLK_EMI_DYNAMIC_CG_EN_SHIFT) | (1 << INFRACLK_INFRA_DYNAMIC_CG_EN_SHIFT) | (1 << EMICLK_GPU_DYNAMIC_CG_EN_SHIFT) | (1 << INFRACLK_PSYS_DYNAMIC_CG_EN_SHIFT) | (1 << EMICLK_EMI1_DYNAMIC_CG_EN_SHIFT) | (1 << EMI1_ADB400_S_DCM_CTRL_SHIFT) | (0 << MP2_ADB400_M_DCM_CTRL_SHIFT) | (1 << MP0_ICC_AXI_STREAM_ARCH_CG_SHIFT) | (1 << MP1_ICC_AXI_STREAM_ARCH_CG_SHIFT) | (1 << MP2_ICC_AXI_STREAM_ARCH_CG_SHIFT) | (1 << L2_SHARE_ADB400_DCM_CTRL_SHIFT) | (1 << MP1_AGGRESS_DCM_CTRL_SHIFT) | (1 << MP0_AGGRESS_DCM_CTRL_SHIFT) | (1 << MP0_ADB400_ACP_S_DCM_CTRL_SHIFT) | (1 << MP0_ADB400_ACP_M_DCM_CTRL_SHIFT) | (1 << MP1_ADB400_ACP_S_DCM_CTRL_SHIFT) | (1 << MP1_ADB400_ACP_M_DCM_CTRL_SHIFT) | (1 << MP3_ADB400_M_DCM_CTRL_SHIFT) | (1 << MP3_ICC_AXI_STREAM_ARCH_CG_SHIFT) }; /* l2c_sram dcm related */ enum { L2C_SRAM_DCM_EN_SHIFT = 0, L2C_SRAM_DCM = 1 << L2C_SRAM_DCM_EN_SHIFT }; /* mcu misc dcm related */ enum { MP0_CNTVALUEB_DCM_EN_SHIFT = 0, MP_CNTVALUEB_DCM_EN = 8, CNTVALUEB_DCM = (1 << MP0_CNTVALUEB_DCM_EN_SHIFT) | (1 << MP_CNTVALUEB_DCM_EN) }; /* sync dcm cluster config related */ enum { MP0_SYNC_DCM_STALL_WR_EN_SHIFT = 7, MCUSYS_MAX_ACCESS_LATENCY_SHIFT = 24, MCU0_SYNC_DCM_STALL_WR_EN = 1 << MP0_SYNC_DCM_STALL_WR_EN_SHIFT, MCUSYS_MAX_ACCESS_LATENCY_MASK = 0xf << MCUSYS_MAX_ACCESS_LATENCY_SHIFT, MCUSYS_MAX_ACCESS_LATENCY = 0x5 << MCUSYS_MAX_ACCESS_LATENCY_SHIFT }; /* cpusys rgu dcm related */ enum { CPUSYS_RGU_DCM_CONFIG_SHIFT = 0, CPUSYS_RGU_DCM_CINFIG = 1 << CPUSYS_RGU_DCM_CONFIG_SHIFT }; /* mp2 sync dcm related */ enum { MP2_DCM_EN_SHIFT = 0, MP2_DCM_EN = 1 << MP2_DCM_EN_SHIFT }; #endif /* MT8183_MCUCFG_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/include/mt_gic_v3.h000066400000000000000000000014631355360272700242520ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MT_GIC_V3_H #define MT_GIC_V3_H #include #define GIC_INT_MASK (MCUCFG_BASE + 0x5e8) #define GIC500_ACTIVE_SEL_SHIFT 3 #define GIC500_ACTIVE_SEL_MASK (0x7 << GIC500_ACTIVE_SEL_SHIFT) #define GIC500_ACTIVE_CPU_SHIFT 16 #define GIC500_ACTIVE_CPU_MASK (0xff << GIC500_ACTIVE_CPU_SHIFT) void mt_gic_driver_init(void); void mt_gic_init(void); void mt_gic_set_pending(uint32_t irq); uint32_t mt_gic_get_pending(uint32_t irq); void mt_gic_cpuif_enable(void); void mt_gic_cpuif_disable(void); void mt_gic_pcpu_init(void); void mt_gic_irq_save(void); void mt_gic_irq_restore(void); void mt_gic_sync_dcm_enable(void); void mt_gic_sync_dcm_disable(void); #endif /* MT_GIC_V3_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/include/plat_dcm.h000066400000000000000000000027251355360272700241650ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_DCM_H #define PLAT_DCM_H #define MP2_SYNC_DCM (MCUCFG_BASE + 0x2274) #define MP2_SYNC_DCM_MASK (0x1 << 0) #define MP2_SYNC_DCM_ON (0x1 << 0) #define MP2_SYNC_DCM_OFF (0x0 << 0) extern uint64_t plat_dcm_mcsi_a_addr; extern uint32_t plat_dcm_mcsi_a_val; extern int plat_dcm_initiated; extern void plat_dcm_mcsi_a_backup(void); extern void plat_dcm_mcsi_a_restore(void); extern void plat_dcm_rgu_enable(void); extern void plat_dcm_restore_cluster_on(unsigned long mpidr); extern void plat_dcm_msg_handler(uint64_t x1); extern unsigned long plat_dcm_get_enabled_cnt(uint64_t type); extern void plat_dcm_init(void); #define ALL_DCM_TYPE (ARMCORE_DCM_TYPE | MCUSYS_DCM_TYPE \ | STALL_DCM_TYPE | BIG_CORE_DCM_TYPE \ | GIC_SYNC_DCM_TYPE | RGU_DCM_TYPE \ | INFRA_DCM_TYPE \ | DDRPHY_DCM_TYPE | EMI_DCM_TYPE | DRAMC_DCM_TYPE \ | MCSI_DCM_TYPE) enum { ARMCORE_DCM_TYPE = (1U << 0), MCUSYS_DCM_TYPE = (1U << 1), INFRA_DCM_TYPE = (1U << 2), PERI_DCM_TYPE = (1U << 3), EMI_DCM_TYPE = (1U << 4), DRAMC_DCM_TYPE = (1U << 5), DDRPHY_DCM_TYPE = (1U << 6), STALL_DCM_TYPE = (1U << 7), BIG_CORE_DCM_TYPE = (1U << 8), GIC_SYNC_DCM_TYPE = (1U << 9), LAST_CORE_DCM_TYPE = (1U << 10), RGU_DCM_TYPE = (1U << 11), TOPCKG_DCM_TYPE = (1U << 12), LPDMA_DCM_TYPE = (1U << 13), MCSI_DCM_TYPE = (1U << 14), NR_DCM_TYPE = 15, }; #endif /* PLAT_DCM_H */trusted-firmware-a-2.2/plat/mediatek/mt8183/include/plat_debug.h000066400000000000000000000020131355360272700244760ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEBUG_H #define PLATFORM_DEBUG_H #define sync_writel(addr, val) \ do { mmio_write_32((addr), (val)); dsbsy(); } while (0) #define MCU_BIU_BASE 0x0c530000 #define MISC1_CFG_BASE 0xb00 #define CA15M_CFG_BASE 0x2000 #define DFD_INTERNAL_CTL (MCU_BIU_BASE + MISC1_CFG_BASE + 0x00) #define CA15M_DBG_CONTROL (MCU_BIU_BASE + CA15M_CFG_BASE + 0x728) #define CA15M_PWR_RST_CTL (MCU_BIU_BASE + CA15M_CFG_BASE + 0x08) #define VPROC_EXT_CTL 0x10006290 #define CFG_SF_CTRL 0x0c510014 #define CFG_SF_INI 0x0c510010 #define BIT_CA15M_L2PARITY_EN (1 << 1) #define BIT_CA15M_LASTPC_DIS (1 << 8) #define MCU_ALL_PWR_ON_CTRL 0x0c530b58 #define PLAT_MTK_CIRCULAR_BUFFER_UNLOCK 0xefab4133 #define PLAT_MTK_CIRCULAR_BUFFER_LOCK 0xefab4134 extern void circular_buffer_setup(void); extern void l2c_parity_check_setup(void); extern void clear_all_on_mux(void); #endif /* PLATFORM_DEBUG_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/include/plat_macros.S000066400000000000000000000040361355360272700246560ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .section .rodata.gic_reg_name, "aS" gicc_regs: .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", "" gicd_pend_reg: .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n" \ " Offset:\t\t\tvalue\n" newline: .asciz "\n" spacer: .asciz ":\t\t0x" .section .rodata.cci_reg_name, "aS" cci_iface_regs: .asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , "" /* --------------------------------------------- * The below macro prints out relevant GIC and * CCI registers whenever an unhandled exception * is taken in BL31. * Clobbers: x0 - x10, x26, x27, sp * --------------------------------------------- */ .macro plat_crash_print_regs mov_imm x26, BASE_GICD_BASE mov_imm x27, BASE_GICC_BASE /* Load the gicc reg list to x6 */ adr x6, gicc_regs /* Load the gicc regs to gp regs used by str_in_crash_buf_print */ ldr w8, [x27, #GICC_HPPIR] ldr w9, [x27, #GICC_AHPPIR] ldr w10, [x27, #GICC_CTLR] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print /* Print the GICD_ISPENDR regs */ add x7, x26, #GICD_ISPENDR adr x4, gicd_pend_reg bl asm_print_str gicd_ispendr_loop: sub x4, x7, x26 cmp x4, #0x280 b.eq exit_print_gic_regs bl asm_print_hex adr x4, spacer bl asm_print_str ldr x4, [x7], #8 bl asm_print_hex adr x4, newline bl asm_print_str b gicd_ispendr_loop exit_print_gic_regs: adr x6, cci_iface_regs /* Store in x7 the base address of the first interface */ mov_imm x7, (PLAT_MT_CCI_BASE + SLAVE_IFACE_OFFSET( \ PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX)) ldr w8, [x7, #SNOOP_CTRL_REG] /* Store in x7 the base address of the second interface */ mov_imm x7, (PLAT_MT_CCI_BASE + SLAVE_IFACE_OFFSET( \ PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX)) ldr w9, [x7, #SNOOP_CTRL_REG] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print .endm trusted-firmware-a-2.2/plat/mediatek/mt8183/include/plat_private.h000066400000000000000000000014241355360272700250670ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_PRIVATE_H #define PLAT_PRIVATE_H /******************************************************************************* * Function and variable prototypes ******************************************************************************/ void plat_configure_mmu_el3(uintptr_t total_base, uintptr_t total_size, uintptr_t ro_start, uintptr_t ro_limit, uintptr_t coh_start, uintptr_t coh_limit); void plat_mtk_cci_init(void); void plat_mtk_cci_enable(void); void plat_mtk_cci_disable(void); void plat_mtk_cci_init_sf(void); /* Declarations for plat_topology.c */ int mt_setup_topology(void); #endif /* PLAT_PRIVATE_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/include/platform_def.h000066400000000000000000000307251355360272700250450ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #define PLAT_PRIMARY_CPU 0x0 #define IO_PHYS 0x10000000 #define INFRACFG_AO_BASE (IO_PHYS + 0x1000) #define PERI_BASE (IO_PHYS + 0x3000) #define GPIO_BASE (IO_PHYS + 0x5000) #define SPM_BASE (IO_PHYS + 0x6000) #define SLEEP_REG_MD_BASE (IO_PHYS + 0xf000) #define RGU_BASE (IO_PHYS + 0x7000) #define I2C4_BASE_SE (IO_PHYS + 0x1008000) #define I2C2_BASE_SE (IO_PHYS + 0x1009000) #define PMIC_WRAP_BASE (IO_PHYS + 0xd000) #define MCUCFG_BASE 0x0c530000 #define CFG_SF_CTRL 0x0c510014 #define CFG_SF_INI 0x0c510010 #define EMI_BASE (IO_PHYS + 0x219000) #define EMI_MPU_BASE (IO_PHYS + 0x226000) #define TRNG_base (IO_PHYS + 0x20f000) #define MT_GIC_BASE 0x0c000000 #define PLAT_MT_CCI_BASE 0x0c500000 #define CCI_SIZE 0x00010000 #define EINT_BASE 0x1000b000 #define DVFSRC_BASE (IO_PHYS + 0x12000) #define SSPM_CFGREG_BASE (IO_PHYS + 0x440000) #define SSPM_MBOX_3_BASE (IO_PHYS + 0x480000) #define INFRACFG_AO_BASE (IO_PHYS + 0x1000) #define APMIXEDSYS (IO_PHYS + 0xC000) #define ARMPLL_LL_CON0 (APMIXEDSYS + 0x200) #define ARMPLL_L_CON0 (APMIXEDSYS + 0x210) #define ARMPLL_L_PWR_CON0 (APMIXEDSYS + 0x21c) #define MAINPLL_CON0 (APMIXEDSYS + 0x220) #define CCIPLL_CON0 (APMIXEDSYS + 0x290) #define TOP_CKMUXSEL (INFRACFG_AO_BASE + 0x0) #define armpll_mux1_sel_big_mask (0xf << 4) #define armpll_mux1_sel_big_ARMSPLL (0x1 << 4) #define armpll_mux1_sel_sml_mask (0xf << 8) #define armpll_mux1_sel_sml_ARMSPLL (0x1 << 8) /* Aggregate of all devices in the first GB */ #define MTK_DEV_RNG0_BASE IO_PHYS #define MTK_DEV_RNG0_SIZE 0x490000 #define MTK_DEV_RNG1_BASE (IO_PHYS + 0x1000000) #define MTK_DEV_RNG1_SIZE 0x4000000 #define MTK_DEV_RNG2_BASE 0x0c000000 #define MTK_DEV_RNG2_SIZE 0x600000 #define MT_MCUSYS_SIZE 0x90000 #define RAM_CONSOLE_BASE 0x11d000 #define RAM_CONSOLE_SIZE 0x1000 /******************************************************************************* * MSDC ******************************************************************************/ #define MSDC0_BASE (IO_PHYS + 0x01230000) /******************************************************************************* * MCUSYS related constants ******************************************************************************/ #define MT_L2_WRITE_ACCESS_RATE (MCUCFG_BASE + 0x604) #define MP0_CA7L_CACHE_CONFIG (MCUCFG_BASE + 0x7f0) #define MP1_CA7L_CACHE_CONFIG (MCUCFG_BASE + 0x7f4) #define EMI_WFIFO (MCUCFG_BASE + 0x0b5c) /******************************************************************************* * GIC related constants ******************************************************************************/ #define MT_POLARITY_LOW 0 #define MT_POLARITY_HIGH 1 #define MT_EDGE_SENSITIVE 1 #define MT_LEVEL_SENSITIVE 0 /******************************************************************************* * UART related constants ******************************************************************************/ #define UART0_BASE (IO_PHYS + 0x01002000) #define UART1_BASE (IO_PHYS + 0x01003000) #define UART_BAUDRATE 115200 #define UART_CLOCK 26000000 /******************************************************************************* * System counter frequency related constants ******************************************************************************/ #define SYS_COUNTER_FREQ_IN_TICKS 13000000 #define SYS_COUNTER_FREQ_IN_MHZ 13 /******************************************************************************* * GIC-400 & interrupt handling related constants ******************************************************************************/ /* Base MTK_platform compatible GIC memory map */ #define BASE_GICD_BASE MT_GIC_BASE #define BASE_GICC_BASE (MT_GIC_BASE + 0x400000) #define MT_GIC_RDIST_BASE (MT_GIC_BASE + 0x100000) #define BASE_GICR_BASE (MT_GIC_BASE + 0x100000) #define BASE_GICH_BASE (MT_GIC_BASE + 0x4000) #define BASE_GICV_BASE (MT_GIC_BASE + 0x6000) #define INT_POL_CTL0 (MCUCFG_BASE + 0xa80) #define SEC_POL_CTL_EN0 (MCUCFG_BASE + 0xa00) #define GIC_SYNC_DCM (MCUCFG_BASE + 0x758) #define GIC_SYNC_DCM_MASK 0x3 #define GIC_SYNC_DCM_ON 0x3 #define GIC_SYNC_DCM_OFF 0x0 #define GIC_PRIVATE_SIGNALS 32 #define PLAT_ARM_GICD_BASE BASE_GICD_BASE #define PLAT_ARM_GICC_BASE BASE_GICC_BASE #define PLAT_ARM_G1S_IRQ_PROPS(grp) ( \ INTR_PROP_DESC(MT_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(MT_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(MT_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(MT_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(MT_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(MT_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(MT_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(MT_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE)) \ #define PLAT_ARM_G0_IRQ_PROPS(grp) /******************************************************************************* * CCI-400 related constants ******************************************************************************/ #define PLAT_MT_CCI_CLUSTER0_SL_IFACE_IX 4 #define PLAT_MT_CCI_CLUSTER1_SL_IFACE_IX 3 /******************************************************************************* * WDT Registers ******************************************************************************/ #define MTK_WDT_BASE (IO_PHYS + 0x00007000) #define MTK_WDT_SIZE 0x1000 #define MTK_WDT_MODE (MTK_WDT_BASE + 0x0000) #define MTK_WDT_LENGTH (MTK_WDT_BASE + 0x0004) #define MTK_WDT_RESTART (MTK_WDT_BASE + 0x0008) #define MTK_WDT_STATUS (MTK_WDT_BASE + 0x000C) #define MTK_WDT_INTERVAL (MTK_WDT_BASE + 0x0010) #define MTK_WDT_SWRST (MTK_WDT_BASE + 0x0014) #define MTK_WDT_SWSYSRST (MTK_WDT_BASE + 0x0018) #define MTK_WDT_NONRST_REG (MTK_WDT_BASE + 0x0020) #define MTK_WDT_NONRST_REG2 (MTK_WDT_BASE + 0x0024) #define MTK_WDT_REQ_MODE (MTK_WDT_BASE + 0x0030) #define MTK_WDT_REQ_IRQ_EN (MTK_WDT_BASE + 0x0034) #define MTK_WDT_EXT_REQ_CON (MTK_WDT_BASE + 0x0038) #define MTK_WDT_DEBUG_CTL (MTK_WDT_BASE + 0x0040) #define MTK_WDT_LATCH_CTL (MTK_WDT_BASE + 0x0044) #define MTK_WDT_DEBUG_CTL2 (MTK_WDT_BASE + 0x00A0) #define MTK_WDT_COUNTER (MTK_WDT_BASE + 0x0514) /* WDT_STATUS */ #define MTK_WDT_STATUS_SPM_THERMAL_RST (1 << 0) #define MTK_WDT_STATUS_SPM_RST (1 << 1) #define MTK_WDT_STATUS_EINT_RST (1 << 2) #define MTK_WDT_STATUS_SYSRST_RST (1 << 3) /* from PMIC */ #define MTK_WDT_STATUS_DVFSP_RST (1 << 4) #define MTK_WDT_STATUS_PMCU_RST (1 << 16) #define MTK_WDT_STATUS_MDDBG_RST (1 << 17) #define MTK_WDT_STATUS_THERMAL_DIRECT_RST (1 << 18) #define MTK_WDT_STATUS_DEBUG_RST (1 << 19) #define MTK_WDT_STATUS_SECURITY_RST (1 << 28) #define MTK_WDT_STATUS_IRQ_ASSERT (1 << 29) #define MTK_WDT_STATUS_SW_WDT_RST (1 << 30) #define MTK_WDT_STATUS_HW_WDT_RST (1U << 31) /* RGU other related */ #define MTK_WDT_MODE_DUAL_MODE 0x0040 #define MTK_WDT_MODE_IRQ 0x0008 #define MTK_WDT_MODE_KEY 0x22000000 #define MTK_WDT_MODE_EXTEN 0x0004 #define MTK_WDT_SWRST_KEY 0x1209 #define MTK_WDT_RESTART_KEY 0x1971 /******************************************************************************* * TRNG Registers ******************************************************************************/ #define TRNG_BASE_ADDR TRNG_base #define TRNG_BASE_SIZE 0x1000 #define TRNG_CTRL (TRNG_base + 0x0000) #define TRNG_TIME (TRNG_base + 0x0004) #define TRNG_DATA (TRNG_base + 0x0008) #define TRNG_PDN_base 0x10001000 #define TRNG_PDN_BASE_ADDR TRNG_PDN_BASE_ADDR #define TRNG_PDN_BASE_SIZE 0x1000 #define TRNG_PDN_SET (TRNG_PDN_base + 0x0088) #define TRNG_PDN_CLR (TRNG_PDN_base + 0x008c) #define TRNG_PDN_STATUS (TRNG_PDN_base + 0x0094) #define TRNG_CTRL_RDY 0x80000000 #define TRNG_CTRL_START 0x00000001 #define TRNG_PDN_VALUE 0x200 /* FIQ platform related define */ #define MT_IRQ_SEC_SGI_0 8 #define MT_IRQ_SEC_SGI_1 9 #define MT_IRQ_SEC_SGI_2 10 #define MT_IRQ_SEC_SGI_3 11 #define MT_IRQ_SEC_SGI_4 12 #define MT_IRQ_SEC_SGI_5 13 #define MT_IRQ_SEC_SGI_6 14 #define MT_IRQ_SEC_SGI_7 15 #define FIQ_SMP_CALL_SGI 13 #define WDT_IRQ_BIT_ID 174 #define ATF_LOG_IRQ_ID 277 #define ATF_AMMS_IRQ_ID 338 #define PCCIF1_IRQ0_BIT_ID 185 #define PCCIF1_IRQ1_BIT_ID 186 #define DEBUG_XLAT_TABLE 0 /******************************************************************************* * Platform binary types for linking ******************************************************************************/ #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 /******************************************************************************* * Generic platform constants ******************************************************************************/ /* Size of cacheable stacks */ #if DEBUG_XLAT_TABLE #define PLATFORM_STACK_SIZE 0x800 #elif IMAGE_BL1 #define PLATFORM_STACK_SIZE 0x440 #elif IMAGE_BL2 #define PLATFORM_STACK_SIZE 0x400 #elif IMAGE_BL31 #define PLATFORM_STACK_SIZE 0x800 #elif IMAGE_BL32 #define PLATFORM_STACK_SIZE 0x440 #endif #define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n" #define PLAT_MAX_PWR_LVL U(2) #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE U(2) #define PLATFORM_CACHE_LINE_SIZE 64 #define PLATFORM_SYSTEM_COUNT 1 #define PLATFORM_CLUSTER_COUNT 2 #define PLATFORM_CLUSTER0_CORE_COUNT 4 #define PLATFORM_CLUSTER1_CORE_COUNT 4 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \ PLATFORM_CLUSTER0_CORE_COUNT) #define PLATFORM_MAX_CPUS_PER_CLUSTER 4 #define PLATFORM_NUM_AFFS (PLATFORM_SYSTEM_COUNT + \ PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) /******************************************************************************* * Platform memory map related constants ******************************************************************************/ #define TZRAM_BASE 0x54600000 #define TZRAM_SIZE 0x00030000 /******************************************************************************* * BL31 specific defines. ******************************************************************************/ /* * Put BL31 at the top of the Trusted SRAM (just below the shared memory, if * present). BL31_BASE is calculated using the current BL31 debug size plus a * little space for growth. */ #define BL31_BASE (TZRAM_BASE + 0x1000) #define BL31_LIMIT (TZRAM_BASE + TZRAM_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 MAX_XLAT_TABLES 16 #define MAX_MMAP_REGIONS 16 /******************************************************************************* * Declarations and constants to access the mailboxes safely. Each mailbox is * aligned on the biggest cache line size in the platform. This is known only * to the platform as it might have a combination of integrated and external * caches. Such alignment ensures that two maiboxes do not sit on the same cache * line at any cache level. They could belong to different cpus/clusters & * get written while being protected by different locks causing corruption of * a valid mailbox address. ******************************************************************************/ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/include/power_tracer.h000066400000000000000000000006141355360272700250710ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef POWER_TRACER_H #define POWER_TRACER_H #define CPU_UP 0 #define CPU_DOWN 1 #define CPU_SUSPEND 2 #define CLUSTER_UP 3 #define CLUSTER_DOWN 4 #define CLUSTER_SUSPEND 5 void trace_power_flow(u_register_t mpidr, unsigned char mode); #endif /* POWER_TRACER_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/include/scu.h000066400000000000000000000003721355360272700231700ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SCU_H #define SCU_H void disable_scu(u_register_t mpidr); void enable_scu(u_register_t mpidr); #endif /* SCU_H */ trusted-firmware-a-2.2/plat/mediatek/mt8183/include/sspm_reg.h000066400000000000000000000031231355360272700242120ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __SSPM_REG_H__ #define __SSPM_REG_H__ #include "platform_def.h" #define SSPM_CFGREG_RSV_RW_REG0 (SSPM_CFGREG_BASE + 0x0100) #define SSPM_CFGREG_ACAO_INT_SET (SSPM_CFGREG_BASE + 0x00D8) #define SSPM_CFGREG_ACAO_INT_CLR (SSPM_CFGREG_BASE + 0x00DC) #define SSPM_CFGREG_ACAO_WAKEUP_EN (SSPM_CFGREG_BASE + 0x0204) #define STANDBYWFI_EN(n) (1 << (n + 8)) #define GIC_IRQOUT_EN(n) (1 << (n + 0)) #define NF_MCDI_MBOX 19 #define MCDI_MBOX_CLUSTER_0_CAN_POWER_OFF 0 #define MCDI_MBOX_CLUSTER_1_CAN_POWER_OFF 1 #define MCDI_MBOX_BUCK_POWER_OFF_MASK 2 #define MCDI_MBOX_CLUSTER_0_ATF_ACTION_DONE 3 #define MCDI_MBOX_CLUSTER_1_ATF_ACTION_DONE 4 #define MCDI_MBOX_BOOTADDR 5 #define MCDI_MBOX_PAUSE_ACTION 6 #define MCDI_MBOX_AVAIL_CPU_MASK 7 #define MCDI_MBOX_CPU_CLUSTER_PWR_STAT 8 #define MCDI_MBOX_ACTION_STAT 9 #define MCDI_MBOX_CLUSTER_0_CNT 10 #define MCDI_MBOX_CLUSTER_1_CNT 11 #define MCDI_MBOX_CPU_ISOLATION_MASK 12 #define MCDI_MBOX_PAUSE_ACK 13 #define MCDI_MBOX_PENDING_ON_EVENT 14 #define MCDI_MBOX_PROF_CMD 15 #define MCDI_MBOX_DRCC_CALI_DONE 16 #define MCDI_MBOX_HP_CMD 17 #define MCDI_MBOX_HP_ACK 18 #endif /* __SSPM_REG_H__ */ trusted-firmware-a-2.2/plat/mediatek/mt8183/plat_dcm.c000066400000000000000000000040121355360272700225240ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #define PWR_STATUS (SPM_BASE + 0x180) uint64_t plat_dcm_mcsi_a_addr; uint32_t plat_dcm_mcsi_a_val; static int plat_dcm_init_type; static unsigned int dcm_big_core_cnt; int plat_dcm_initiated; #define PWR_STA_BIG_MP_MASK (0x1 << 15) DEFINE_BAKERY_LOCK(dcm_lock); void dcm_lock_init(void) { bakery_lock_init(&dcm_lock); } void dcm_lock_get(void) { bakery_lock_get(&dcm_lock); } void dcm_lock_release(void) { bakery_lock_release(&dcm_lock); } void plat_dcm_mcsi_a_backup(void) { } void plat_dcm_mcsi_a_restore(void) { } void plat_dcm_rgu_enable(void) { } void plat_dcm_big_core_sync(short on) { /* Check if Big cluster power is existed */ if (!(mmio_read_32(PWR_STATUS) & PWR_STA_BIG_MP_MASK)) return; if (on) { mmio_write_32(MP2_SYNC_DCM, (mmio_read_32(MP2_SYNC_DCM) & ~MP2_SYNC_DCM_MASK) | MP2_SYNC_DCM_ON); dcm_big_core_cnt++; } else mmio_write_32(MP2_SYNC_DCM, (mmio_read_32(MP2_SYNC_DCM) & ~MP2_SYNC_DCM_MASK) | MP2_SYNC_DCM_OFF); } void plat_dcm_restore_cluster_on(unsigned long mpidr) { unsigned long cluster_id = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS; switch (cluster_id) { case 0x1: dcm_lock_get(); if (plat_dcm_init_type & BIG_CORE_DCM_TYPE) plat_dcm_big_core_sync(1); else plat_dcm_big_core_sync(0); dcm_lock_release(); break; default: break; } } void plat_dcm_msg_handler(uint64_t x1) { plat_dcm_init_type = x1 & ALL_DCM_TYPE; } unsigned long plat_dcm_get_enabled_cnt(uint64_t type) { switch (type) { case BIG_CORE_DCM_TYPE: return dcm_big_core_cnt; default: return 0; } } void plat_dcm_init(void) { dcm_lock_init(); } trusted-firmware-a-2.2/plat/mediatek/mt8183/plat_debug.c000066400000000000000000000027011355360272700230520ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include void circular_buffer_setup(void) { /* Clear DBG_CONTROL.lastpc_disable to enable circular buffer */ sync_writel(CA15M_DBG_CONTROL, mmio_read_32(CA15M_DBG_CONTROL) & ~(BIT_CA15M_LASTPC_DIS)); } void circular_buffer_unlock(void) { unsigned int i; /* Disable big vproc external off (set CPU_EXT_BUCK_ISO to 0x0) */ sync_writel(VPROC_EXT_CTL, mmio_read_32(VPROC_EXT_CTL) & ~(0x1 << 1)); /* Release vproc apb mask (set 0x0C53_2008[1] to 0x0) */ sync_writel(CA15M_PWR_RST_CTL, mmio_read_32(CA15M_PWR_RST_CTL) & ~(0x1 << 1)); for (i = 1; i <= 4; ++i) sync_writel(MP1_CPUTOP_PWR_CON + i * 4, (mmio_read_32(MP1_CPUTOP_PWR_CON + i * 4) & ~(0x4))|(0x4)); /* Set DFD.en */ sync_writel(DFD_INTERNAL_CTL, 0x1); } void circular_buffer_lock(void) { /* Clear DFD.en */ sync_writel(DFD_INTERNAL_CTL, 0x0); } void clear_all_on_mux(void) { sync_writel(MCU_ALL_PWR_ON_CTRL, mmio_read_32(MCU_ALL_PWR_ON_CTRL) & ~(1 << 2)); sync_writel(MCU_ALL_PWR_ON_CTRL, mmio_read_32(MCU_ALL_PWR_ON_CTRL) & ~(1 << 1)); } void l2c_parity_check_setup(void) { /* Enable DBG_CONTROL.l2parity_en */ sync_writel(CA15M_DBG_CONTROL, mmio_read_32(CA15M_DBG_CONTROL) | BIT_CA15M_L2PARITY_EN); } trusted-firmware-a-2.2/plat/mediatek/mt8183/plat_mt_gic.c000066400000000000000000000044111355360272700232260ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "plat_private.h" #include #include #include #include #define NR_INT_POL_CTL 20 uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT]; /* we save and restore the GICv3 context on system suspend */ gicv3_redist_ctx_t rdist_ctx; gicv3_dist_ctx_t dist_ctx; static unsigned int mt_mpidr_to_core_pos(u_register_t mpidr) { return plat_core_pos_by_mpidr(mpidr); } gicv3_driver_data_t mt_gicv3_data = { .gicd_base = MT_GIC_BASE, .gicr_base = MT_GIC_RDIST_BASE, .rdistif_num = PLATFORM_CORE_COUNT, .rdistif_base_addrs = rdistif_base_addrs, .mpidr_to_core_pos = mt_mpidr_to_core_pos, }; void clear_sec_pol_ctl_en(void) { unsigned int i; /* total 19 polarity ctrl registers */ for (i = 0; i <= NR_INT_POL_CTL - 1; i++) { mmio_write_32((SEC_POL_CTL_EN0 + (i * 4)), 0); } dsb(); } void mt_gic_driver_init(void) { gicv3_driver_init(&mt_gicv3_data); } void mt_gic_init(void) { gicv3_distif_init(); gicv3_rdistif_init(plat_my_core_pos()); gicv3_cpuif_enable(plat_my_core_pos()); clear_sec_pol_ctl_en(); } void mt_gic_set_pending(uint32_t irq) { gicv3_set_interrupt_pending(irq, plat_my_core_pos()); } void mt_gic_cpuif_enable(void) { gicv3_cpuif_enable(plat_my_core_pos()); } void mt_gic_cpuif_disable(void) { gicv3_cpuif_disable(plat_my_core_pos()); } void mt_gic_pcpu_init(void) { gicv3_rdistif_init(plat_my_core_pos()); } void mt_gic_irq_save(void) { gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx); gicv3_distif_save(&dist_ctx); } void mt_gic_irq_restore(void) { gicv3_distif_init_restore(&dist_ctx); gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx); } void mt_gic_sync_dcm_enable(void) { unsigned int val = mmio_read_32(GIC_SYNC_DCM); val &= ~GIC_SYNC_DCM_MASK; mmio_write_32(GIC_SYNC_DCM, val | GIC_SYNC_DCM_ON); } void mt_gic_sync_dcm_disable(void) { unsigned int val = mmio_read_32(GIC_SYNC_DCM); val &= ~GIC_SYNC_DCM_MASK; mmio_write_32(GIC_SYNC_DCM, val | GIC_SYNC_DCM_OFF); } trusted-firmware-a-2.2/plat/mediatek/mt8183/plat_pm.c000066400000000000000000000351741355360272700224120ustar00rootroot00000000000000/* * Copyright (c) 2019, MediaTek Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* common headers */ #include #include #include #include #include #include /* mediatek platform specific headers */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Local power state for power domains in Run state. */ #define MTK_LOCAL_STATE_RUN 0 /* Local power state for retention. */ #define MTK_LOCAL_STATE_RET 1 /* Local power state for OFF/power-down. */ #define MTK_LOCAL_STATE_OFF 2 #if PSCI_EXTENDED_STATE_ID /* * Macros used to parse state information from State-ID if it is using the * recommended encoding for State-ID. */ #define MTK_LOCAL_PSTATE_WIDTH 4 #define MTK_LOCAL_PSTATE_MASK ((1 << MTK_LOCAL_PSTATE_WIDTH) - 1) /* Macros to construct the composite power state */ /* Make composite power state parameter till power level 0 */ #define mtk_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ (((lvl0_state) << PSTATE_ID_SHIFT) | ((type) << PSTATE_TYPE_SHIFT)) #else /* !PSCI_EXTENDED_STATE_ID */ #define mtk_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ (((lvl0_state) << PSTATE_ID_SHIFT) | \ ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \ ((type) << PSTATE_TYPE_SHIFT)) #endif /* PSCI_EXTENDED_STATE_ID */ /* Make composite power state parameter till power level 1 */ #define mtk_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \ (((lvl1_state) << MTK_LOCAL_PSTATE_WIDTH) | \ mtk_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type)) /* Make composite power state parameter till power level 2 */ #define mtk_make_pwrstate_lvl2( \ lvl2_state, lvl1_state, lvl0_state, pwr_lvl, type) \ (((lvl2_state) << (MTK_LOCAL_PSTATE_WIDTH * 2)) | \ mtk_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type)) #define MTK_PWR_LVL0 0 #define MTK_PWR_LVL1 1 #define MTK_PWR_LVL2 2 /* Macros to read the MTK power domain state */ #define MTK_CORE_PWR_STATE(state) (state)->pwr_domain_state[MTK_PWR_LVL0] #define MTK_CLUSTER_PWR_STATE(state) (state)->pwr_domain_state[MTK_PWR_LVL1] #define MTK_SYSTEM_PWR_STATE(state) ((PLAT_MAX_PWR_LVL > MTK_PWR_LVL1) ? \ (state)->pwr_domain_state[MTK_PWR_LVL2] : 0) #if PSCI_EXTENDED_STATE_ID /* * The table storing the valid idle power states. Ensure that the * array entries are populated in ascending order of state-id to * enable us to use binary search during power state validation. * The table must be terminated by a NULL entry. */ const unsigned int mtk_pm_idle_states[] = { /* State-id - 0x001 */ mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_RET, MTK_PWR_LVL0, PSTATE_TYPE_STANDBY), /* State-id - 0x002 */ mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_OFF, MTK_PWR_LVL0, PSTATE_TYPE_POWERDOWN), /* State-id - 0x022 */ mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_RUN, MTK_LOCAL_STATE_OFF, MTK_LOCAL_STATE_OFF, MTK_PWR_LVL1, PSTATE_TYPE_POWERDOWN), #if PLAT_MAX_PWR_LVL > MTK_PWR_LVL1 /* State-id - 0x222 */ mtk_make_pwrstate_lvl2(MTK_LOCAL_STATE_OFF, MTK_LOCAL_STATE_OFF, MTK_LOCAL_STATE_OFF, MTK_PWR_LVL2, PSTATE_TYPE_POWERDOWN), #endif 0, }; #endif #define CPU_IDX(cluster, cpu) ((cluster << 2) + cpu) #define ON true #define OFF false /* Pause MCDI when CPU hotplug */ static bool HP_SSPM_PAUSE; /* CPU Hotplug by SSPM */ static bool HP_SSPM_CTRL = true; /* Turn off cluster when CPU hotplug off */ static bool HP_CLUSTER_OFF = true; /* Turn off cluster when CPU MCDI off */ static bool MCDI_C2 = true; /* Enable MCDI */ static bool MCDI_SSPM = true; static uintptr_t secure_entrypoint; static void mp1_L2_desel_config(void) { mmio_write_64(MCUCFG_BASE + 0x2200, 0x2092c820); dsb(); } static bool clst_single_pwr(int cluster, int cpu) { uint32_t cpu_mask[2] = {0x00001e00, 0x000f0000}; uint32_t cpu_pwr_bit[] = {9, 10, 11, 12, 16, 17, 18, 19}; int my_idx = (cluster << 2) + cpu; uint32_t pwr_stat = mmio_read_32(0x10006180); return !(pwr_stat & (cpu_mask[cluster] & ~BIT(cpu_pwr_bit[my_idx]))); } static bool clst_single_on(int cluster, int cpu) { uint32_t cpu_mask[2] = {0x0f, 0xf0}; int my_idx = (cluster << 2) + cpu; uint32_t on_stat = mcdi_avail_cpu_mask_read(); return !(on_stat & (cpu_mask[cluster] & ~BIT(my_idx))); } static void plat_cluster_pwrdwn_common(uint64_t mpidr, int cluster) { if (cluster > 0) mt_gic_sync_dcm_enable(); /* Disable coherency */ plat_mtk_cci_disable(); disable_scu(mpidr); } static void plat_cluster_pwron_common(uint64_t mpidr, int cluster) { if (cluster > 0) { l2c_parity_check_setup(); circular_buffer_setup(); mp1_L2_desel_config(); mt_gic_sync_dcm_disable(); } /* Enable coherency */ enable_scu(mpidr); plat_mtk_cci_enable(); /* Enable big core dcm */ plat_dcm_restore_cluster_on(mpidr); /* Enable rgu dcm */ plat_dcm_rgu_enable(); } static void plat_cpu_standby(plat_local_state_t cpu_state) { unsigned int scr; scr = read_scr_el3(); write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT); isb(); dsb(); wfi(); write_scr_el3(scr); } static void mcdi_ctrl_before_hotplug_on(int cluster, int cpu) { if (!HP_SSPM_CTRL && HP_SSPM_PAUSE && MCDI_SSPM) { mcdi_pause_clr(cluster, CPU_IDX(cluster, cpu), OFF); mcdi_pause_set(cluster, CPU_IDX(cluster, cpu), ON); } } static void mcdi_ctrl_before_hotplug_off(int cluster, int cpu, bool cluster_off) { if (!HP_SSPM_CTRL && HP_SSPM_PAUSE && MCDI_SSPM) mcdi_pause_set(cluster_off ? cluster : -1, CPU_IDX(cluster, cpu), OFF); } static void mcdi_ctrl_cluster_cpu_off(int cluster, int cpu, bool cluster_off) { if (MCDI_SSPM) { sspm_set_bootaddr(secure_entrypoint); sspm_standbywfi_irq_enable(CPU_IDX(cluster, cpu)); if (cluster_off) sspm_cluster_pwr_off_notify(cluster); else sspm_cluster_pwr_on_notify(cluster); } } static void mcdi_ctrl_suspend(void) { if (MCDI_SSPM) mcdi_pause(); } static void mcdi_ctrl_resume(void) { if (MCDI_SSPM) mcdi_unpause(); } static void hotplug_ctrl_cluster_on(int cluster, int cpu) { if (HP_SSPM_CTRL && MCDI_SSPM) { mcdi_hotplug_clr(cluster, CPU_IDX(cluster, cpu), OFF); mcdi_hotplug_set(cluster, -1, ON); mcdi_hotplug_wait_ack(cluster, -1, ON); } else { /* power on cluster */ if (!spm_get_cluster_powerstate(cluster)) spm_poweron_cluster(cluster); } } static void hotplug_ctrl_cpu_on(int cluster, int cpu) { if (HP_SSPM_CTRL && MCDI_SSPM) mcdi_hotplug_set(cluster, CPU_IDX(cluster, cpu), ON); else spm_poweron_cpu(cluster, cpu); } static void hotplug_ctrl_cpu_on_finish(int cluster, int cpu) { spm_disable_cpu_auto_off(cluster, cpu); if (HP_SSPM_CTRL && MCDI_SSPM) mcdi_hotplug_clr(cluster, CPU_IDX(cluster, cpu), ON); else if (HP_SSPM_PAUSE && MCDI_SSPM) mcdi_pause_clr(cluster, CPU_IDX(cluster, cpu), ON); mcdi_avail_cpu_mask_set(BIT(CPU_IDX(cluster, cpu))); } static void hotplug_ctrl_cluster_cpu_off(int cluster, int cpu, bool cluster_off) { mcdi_avail_cpu_mask_clr(BIT(CPU_IDX(cluster, cpu))); if (HP_SSPM_CTRL && MCDI_SSPM) { mcdi_hotplug_set(cluster_off ? cluster : -1, CPU_IDX(cluster, cpu), OFF); } else { spm_enable_cpu_auto_off(cluster, cpu); if (cluster_off) spm_enable_cluster_auto_off(cluster); spm_set_cpu_power_off(cluster, cpu); } } static int plat_mtk_power_domain_on(unsigned long mpidr) { int cpu = MPIDR_AFFLVL0_VAL(mpidr); int cluster = MPIDR_AFFLVL1_VAL(mpidr); mcdi_ctrl_before_hotplug_on(cluster, cpu); hotplug_ctrl_cluster_on(cluster, cpu); /* init cpu reset arch as AARCH64 */ mcucfg_init_archstate(cluster, cpu, 1); mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint); hotplug_ctrl_cpu_on(cluster, cpu); return PSCI_E_SUCCESS; } static void plat_mtk_power_domain_off(const psci_power_state_t *state) { uint64_t mpidr = read_mpidr(); int cpu = MPIDR_AFFLVL0_VAL(mpidr); int cluster = MPIDR_AFFLVL1_VAL(mpidr); const plat_local_state_t *pds = state->pwr_domain_state; bool afflvl1 = (pds[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF); bool cluster_off = (HP_CLUSTER_OFF && afflvl1 && clst_single_on(cluster, cpu)); mt_gic_cpuif_disable(); if (cluster_off) plat_cluster_pwrdwn_common(mpidr, cluster); mcdi_ctrl_before_hotplug_off(cluster, cpu, cluster_off); hotplug_ctrl_cluster_cpu_off(cluster, cpu, cluster_off); } static void plat_mtk_power_domain_on_finish(const psci_power_state_t *state) { uint64_t mpidr = read_mpidr(); int cpu = MPIDR_AFFLVL0_VAL(mpidr); int cluster = MPIDR_AFFLVL1_VAL(mpidr); const plat_local_state_t *pds = state->pwr_domain_state; bool afflvl1 = (pds[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF); if (afflvl1) plat_cluster_pwron_common(mpidr, cluster); mt_gic_pcpu_init(); mt_gic_cpuif_enable(); hotplug_ctrl_cpu_on_finish(cluster, cpu); } static void plat_mtk_power_domain_suspend(const psci_power_state_t *state) { uint64_t mpidr = read_mpidr(); int cpu = MPIDR_AFFLVL0_VAL(mpidr); int cluster = MPIDR_AFFLVL1_VAL(mpidr); const plat_local_state_t *pds = state->pwr_domain_state; bool afflvl1 = (pds[MPIDR_AFFLVL1] == MTK_LOCAL_STATE_OFF); bool afflvl2 = (pds[MPIDR_AFFLVL2] == MTK_LOCAL_STATE_OFF); bool cluster_off = MCDI_C2 && afflvl1 && clst_single_pwr(cluster, cpu); /* init cpu reset arch as AARCH64 */ mcucfg_init_archstate(cluster, cpu, 1); mcucfg_set_bootaddr(cluster, cpu, secure_entrypoint); mt_gic_cpuif_disable(); mt_gic_irq_save(); plat_dcm_mcsi_a_backup(); if (cluster_off || afflvl2) plat_cluster_pwrdwn_common(mpidr, cluster); if (afflvl2) { spm_data_t spm_d = { .cmd = SPM_SUSPEND }; uint32_t *d = (uint32_t *)&spm_d; uint32_t l = sizeof(spm_d) / sizeof(uint32_t); mcdi_ctrl_suspend(); spm_set_bootaddr(secure_entrypoint); if (MCDI_SSPM) sspm_ipi_send_non_blocking(IPI_ID_SUSPEND, d); spm_system_suspend(); if (MCDI_SSPM) while (sspm_ipi_recv_non_blocking(IPI_ID_SUSPEND, d, l)) ; } else { mcdi_ctrl_cluster_cpu_off(cluster, cpu, cluster_off); } } static void plat_mtk_power_domain_suspend_finish(const psci_power_state_t *state) { uint64_t mpidr = read_mpidr(); int cluster = MPIDR_AFFLVL1_VAL(mpidr); const plat_local_state_t *pds = state->pwr_domain_state; bool afflvl2 = (pds[MPIDR_AFFLVL2] == MTK_LOCAL_STATE_OFF); if (afflvl2) { spm_data_t spm_d = { .cmd = SPM_RESUME }; uint32_t *d = (uint32_t *)&spm_d; uint32_t l = sizeof(spm_d) / sizeof(uint32_t); mt_gic_init(); mt_gic_irq_restore(); mmio_write_32(EMI_WFIFO, 0xf); if (MCDI_SSPM) sspm_ipi_send_non_blocking(IPI_ID_SUSPEND, d); spm_system_suspend_finish(); if (MCDI_SSPM) while (sspm_ipi_recv_non_blocking(IPI_ID_SUSPEND, d, l)) ; mcdi_ctrl_resume(); } plat_cluster_pwron_common(mpidr, cluster); plat_dcm_mcsi_a_restore(); } #if PSCI_EXTENDED_STATE_ID static int plat_mtk_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { unsigned int state_id; int i; assert(req_state); if (!MCDI_SSPM) return PSCI_E_INVALID_PARAMS; /* * Currently we are using a linear search for finding the matching * entry in the idle power state array. This can be made a binary * search if the number of entries justify the additional complexity. */ for (i = 0; !!mtk_pm_idle_states[i]; i++) { if (power_state == mtk_pm_idle_states[i]) break; } /* Return error if entry not found in the idle state array */ if (!mtk_pm_idle_states[i]) return PSCI_E_INVALID_PARAMS; i = 0; state_id = psci_get_pstate_id(power_state); /* Parse the State ID and populate the state info parameter */ while (state_id) { req_state->pwr_domain_state[i++] = state_id & MTK_LOCAL_PSTATE_MASK; state_id >>= MTK_LOCAL_PSTATE_WIDTH; } return PSCI_E_SUCCESS; } #else /* if !PSCI_EXTENDED_STATE_ID */ static int plat_mtk_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { int pstate = psci_get_pstate_type(power_state); int pwr_lvl = psci_get_pstate_pwrlvl(power_state); int i; assert(req_state); if (pwr_lvl > PLAT_MAX_PWR_LVL) return PSCI_E_INVALID_PARAMS; /* Sanity check the requested state */ if (pstate == PSTATE_TYPE_STANDBY) { /* * It's possible to enter standby only on power level 0 * Ignore any other power level. */ if (pwr_lvl != 0) return PSCI_E_INVALID_PARAMS; req_state->pwr_domain_state[MTK_PWR_LVL0] = MTK_LOCAL_STATE_RET; } else if (!MCDI_SSPM) { return PSCI_E_INVALID_PARAMS; } else { for (i = 0; i <= pwr_lvl; i++) req_state->pwr_domain_state[i] = MTK_LOCAL_STATE_OFF; } return PSCI_E_SUCCESS; } #endif /* PSCI_EXTENDED_STATE_ID */ /******************************************************************************* * MTK handlers to shutdown/reboot the system ******************************************************************************/ static void __dead2 plat_mtk_system_off(void) { INFO("MTK System Off\n"); rtc_power_off_sequence(); wk_pmic_enable_sdn_delay(); pmic_power_off(); wfi(); ERROR("MTK System Off: operation not handled.\n"); panic(); } static void __dead2 plat_mtk_system_reset(void) { struct bl_aux_gpio_info *gpio_reset = plat_get_mtk_gpio_reset(); INFO("MTK System Reset\n"); mt_set_gpio_out(gpio_reset->index, gpio_reset->polarity); wfi(); ERROR("MTK System Reset: operation not handled.\n"); panic(); } static void plat_mtk_get_sys_suspend_power_state(psci_power_state_t *req_state) { assert(PLAT_MAX_PWR_LVL >= 2); for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = MTK_LOCAL_STATE_OFF; } /******************************************************************************* * MTK_platform handler called when an affinity instance is about to be turned * on. The level and mpidr determine the affinity instance. ******************************************************************************/ static const plat_psci_ops_t plat_plat_pm_ops = { .cpu_standby = plat_cpu_standby, .pwr_domain_on = plat_mtk_power_domain_on, .pwr_domain_on_finish = plat_mtk_power_domain_on_finish, .pwr_domain_off = plat_mtk_power_domain_off, .pwr_domain_suspend = plat_mtk_power_domain_suspend, .pwr_domain_suspend_finish = plat_mtk_power_domain_suspend_finish, .system_off = plat_mtk_system_off, .system_reset = plat_mtk_system_reset, .validate_power_state = plat_mtk_validate_power_state, .get_sys_suspend_power_state = plat_mtk_get_sys_suspend_power_state, }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { *psci_ops = &plat_plat_pm_ops; secure_entrypoint = sec_entrypoint; if (!check_mcdi_ctl_stat()) { HP_SSPM_CTRL = false; MCDI_SSPM = false; } return 0; } trusted-firmware-a-2.2/plat/mediatek/mt8183/plat_topology.c000066400000000000000000000035501355360272700236430ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include const unsigned char mtk_power_domain_tree_desc[] = { /* Number of root nodes */ PLATFORM_SYSTEM_COUNT, /* Number of children for the root node */ PLATFORM_CLUSTER_COUNT, /* Number of children for the first cluster node */ PLATFORM_CLUSTER0_CORE_COUNT, /* Number of children for the second cluster node */ PLATFORM_CLUSTER1_CORE_COUNT }; /******************************************************************************* * This function returns the MT8173 default topology tree information. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { return mtk_power_domain_tree_desc; } /******************************************************************************* * This function implements a part of the critical interface between the psci * generic layer and the platform that allows the former to query the platform * to convert an MPIDR to a unique linear index. An error code (-1) is returned * in case the MPIDR is invalid. ******************************************************************************/ int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; mpidr &= MPIDR_AFFINITY_MASK; if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) return -1; cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; if (cluster_id >= PLATFORM_CLUSTER_COUNT) return -1; /* * Validate cpu_id by checking whether it represents a CPU in * one of the two clusters present on the platform. */ if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER) return -1; return (cpu_id + (cluster_id * 4)); } trusted-firmware-a-2.2/plat/mediatek/mt8183/platform.mk000066400000000000000000000113051355360272700227550ustar00rootroot00000000000000# # Copyright (c) 2019, MediaTek Inc. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # MTK_PLAT := plat/mediatek MTK_PLAT_SOC := ${MTK_PLAT}/${PLAT} PLAT_INCLUDES := -I${MTK_PLAT}/common/ \ -I${MTK_PLAT_SOC}/drivers/ \ -I${MTK_PLAT_SOC}/drivers/emi_mpu/ \ -I${MTK_PLAT_SOC}/drivers/devapc/ \ -I${MTK_PLAT_SOC}/drivers/mcdi/ \ -I${MTK_PLAT_SOC}/drivers/spmc/ \ -I${MTK_PLAT_SOC}/drivers/gpio/ \ -I${MTK_PLAT_SOC}/drivers/pmic/ \ -I${MTK_PLAT_SOC}/drivers/spm/ \ -I${MTK_PLAT_SOC}/drivers/sspm/ \ -I${MTK_PLAT_SOC}/drivers/rtc/ \ -I${MTK_PLAT_SOC}/drivers/uart/ \ -I${MTK_PLAT_SOC}/include/ PLAT_BL_COMMON_SOURCES := lib/xlat_tables/aarch64/xlat_tables.c \ lib/xlat_tables/xlat_tables_common.c \ plat/common/plat_psci_common.c \ plat/common/aarch64/crash_console_helpers.S BL31_SOURCES += common/desc_image_load.c \ drivers/arm/cci/cci.c \ drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v3/arm_gicv3_common.c \ drivers/arm/gic/v3/gicv3_helpers.c \ drivers/arm/gic/v3/gic500.c \ drivers/arm/gic/v3/gicv3_main.c \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/gpio/gpio.c \ drivers/ti/uart/aarch64/16550_console.S \ lib/bl_aux_params/bl_aux_params.c \ lib/cpus/aarch64/aem_generic.S \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a73.S \ plat/common/plat_gicv3.c \ ${MTK_PLAT}/common/mtk_plat_common.c \ ${MTK_PLAT}/common/drivers/pmic_wrap/pmic_wrap_init.c \ ${MTK_PLAT}/common/drivers/rtc/rtc_common.c \ ${MTK_PLAT}/common/params_setup.c \ ${MTK_PLAT_SOC}/aarch64/plat_helpers.S \ ${MTK_PLAT_SOC}/aarch64/platform_common.c \ ${MTK_PLAT_SOC}/drivers/devapc/devapc.c \ ${MTK_PLAT_SOC}/drivers/mcsi/mcsi.c \ ${MTK_PLAT_SOC}/drivers/pmic/pmic.c \ ${MTK_PLAT_SOC}/drivers/rtc/rtc.c \ ${MTK_PLAT_SOC}/drivers/mcdi/mtk_mcdi.c \ ${MTK_PLAT_SOC}/drivers/spmc/mtspmc.c \ ${MTK_PLAT_SOC}/drivers/spm/spm.c \ ${MTK_PLAT_SOC}/drivers/spm/spm_pmic_wrap.c \ ${MTK_PLAT_SOC}/drivers/spm/spm_suspend.c \ ${MTK_PLAT_SOC}/drivers/gpio/mtgpio.c \ ${MTK_PLAT_SOC}/drivers/uart/uart.c \ ${MTK_PLAT_SOC}/drivers/emi_mpu/emi_mpu.c \ ${MTK_PLAT_SOC}/plat_pm.c \ ${MTK_PLAT_SOC}/plat_topology.c \ ${MTK_PLAT_SOC}/plat_mt_gic.c \ ${MTK_PLAT_SOC}/plat_dcm.c \ ${MTK_PLAT_SOC}/bl31_plat_setup.c \ ${MTK_PLAT_SOC}/plat_debug.c \ ${MTK_PLAT_SOC}/scu.c \ ${MTK_PLAT_SOC}/drivers/sspm/sspm.c # Enable workarounds for selected Cortex-A53 erratas. ERRATA_A53_826319 := 0 ERRATA_A53_836870 := 1 ERRATA_A53_855873 := 1 # indicate the reset vector address can be programmed PROGRAMMABLE_RESET_ADDRESS := 1 COLD_BOOT_SINGLE_CPU := 1 MULTI_CONSOLE_API := 1 MACH_MT8183 := 1 $(eval $(call add_define,MACH_MT8183)) include lib/coreboot/coreboot.mk trusted-firmware-a-2.2/plat/mediatek/mt8183/scu.c000066400000000000000000000022721355360272700215410ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include void disable_scu(u_register_t mpidr) { uintptr_t axi_config = 0; uint32_t axi_value; switch (mpidr & MPIDR_CLUSTER_MASK) { case 0x000: axi_config = (uintptr_t)&mt8183_mcucfg->mp0_axi_config; axi_value = MP0_ACINACTM; break; case 0x100: axi_config = (uintptr_t)&mt8183_mcucfg->mp2_axi_config; axi_value = MP2_ACINACTM; break; default: ERROR("%s: mpidr does not exist\n", __func__); panic(); } mmio_setbits_32(axi_config, axi_value); } void enable_scu(u_register_t mpidr) { uintptr_t axi_config = 0; uint32_t axi_value; switch (mpidr & MPIDR_CLUSTER_MASK) { case 0x000: axi_config = (uintptr_t)&mt8183_mcucfg->mp0_axi_config; axi_value = MP0_ACINACTM; break; case 0x100: axi_config = (uintptr_t)&mt8183_mcucfg->mp2_axi_config; axi_value = MP2_ACINACTM; break; default: ERROR("%s: mpidr does not exist\n", __func__); panic(); } mmio_clrbits_32(axi_config, axi_value); } trusted-firmware-a-2.2/plat/nvidia/000077500000000000000000000000001355360272700173235ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/000077500000000000000000000000001355360272700204255ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/common/000077500000000000000000000000001355360272700217155ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/common/aarch64/000077500000000000000000000000001355360272700231455ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/common/aarch64/tegra_helpers.S000066400000000000000000000261301355360272700261170ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #define MIDR_PN_CORTEX_A57 0xD07 /******************************************************************************* * Implementation defined ACTLR_EL3 bit definitions ******************************************************************************/ #define ACTLR_EL3_L2ACTLR_BIT (U(1) << 6) #define ACTLR_EL3_L2ECTLR_BIT (U(1) << 5) #define ACTLR_EL3_L2CTLR_BIT (U(1) << 4) #define ACTLR_EL3_CPUECTLR_BIT (U(1) << 1) #define ACTLR_EL3_CPUACTLR_BIT (U(1) << 0) #define ACTLR_EL3_ENABLE_ALL_MASK (ACTLR_EL3_L2ACTLR_BIT | \ ACTLR_EL3_L2ECTLR_BIT | \ ACTLR_EL3_L2CTLR_BIT | \ ACTLR_EL3_CPUECTLR_BIT | \ ACTLR_EL3_CPUACTLR_BIT) #define ACTLR_EL3_ENABLE_ALL_ACCESS (ACTLR_EL3_L2ACTLR_BIT | \ ACTLR_EL3_L2ECTLR_BIT | \ ACTLR_EL3_L2CTLR_BIT | \ ACTLR_EL3_CPUECTLR_BIT | \ ACTLR_EL3_CPUACTLR_BIT) /* Global functions */ .globl plat_is_my_cpu_primary .globl plat_my_core_pos .globl plat_get_my_entrypoint .globl plat_secondary_cold_boot_setup .globl platform_mem_init .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush .globl tegra_secure_entrypoint .globl plat_reset_handler /* Global variables */ .globl tegra_sec_entry_point .globl ns_image_entrypoint .globl tegra_bl31_phys_base .globl tegra_console_base /* --------------------- * Common CPU init code * --------------------- */ .macro cpu_init_common /* ------------------------------------------------ * We enable procesor retention, L2/CPUECTLR NS * access and ECC/Parity protection for A57 CPUs * ------------------------------------------------ */ mrs x0, midr_el1 mov x1, #(MIDR_PN_MASK << MIDR_PN_SHIFT) and x0, x0, x1 lsr x0, x0, #MIDR_PN_SHIFT cmp x0, #MIDR_PN_CORTEX_A57 b.ne 1f /* --------------------------- * Enable processor retention * --------------------------- */ mrs x0, CORTEX_A57_L2ECTLR_EL1 mov x1, #RETENTION_ENTRY_TICKS_512 bic x0, x0, #CORTEX_A57_L2ECTLR_RET_CTRL_MASK orr x0, x0, x1 msr CORTEX_A57_L2ECTLR_EL1, x0 isb mrs x0, CORTEX_A57_ECTLR_EL1 mov x1, #RETENTION_ENTRY_TICKS_512 bic x0, x0, #CORTEX_A57_ECTLR_CPU_RET_CTRL_MASK orr x0, x0, x1 msr CORTEX_A57_ECTLR_EL1, x0 isb /* ------------------------------------------------------- * Enable L2 and CPU ECTLR RW access from non-secure world * ------------------------------------------------------- */ mrs x0, actlr_el3 mov x1, #ACTLR_EL3_ENABLE_ALL_MASK bic x0, x0, x1 mov x1, #ACTLR_EL3_ENABLE_ALL_ACCESS orr x0, x0, x1 msr actlr_el3, x0 mrs x0, actlr_el2 mov x1, #ACTLR_EL3_ENABLE_ALL_MASK bic x0, x0, x1 mov x1, #ACTLR_EL3_ENABLE_ALL_ACCESS orr x0, x0, x1 msr actlr_el2, x0 isb /* -------------------------------- * Enable the cycle count register * -------------------------------- */ 1: mrs x0, pmcr_el0 ubfx x0, x0, #11, #5 // read PMCR.N field mov x1, #1 lsl x0, x1, x0 sub x0, x0, #1 // mask of event counters orr x0, x0, #0x80000000 // disable overflow intrs msr pmintenclr_el1, x0 msr pmuserenr_el0, x1 // enable user mode access /* ---------------------------------------------------------------- * Allow non-privileged access to CNTVCT: Set CNTKCTL (Kernel Count * register), bit 1 (EL0VCTEN) to enable access to CNTVCT/CNTFRQ * registers from EL0. * ---------------------------------------------------------------- */ mrs x0, cntkctl_el1 orr x0, x0, #EL0VCTEN_BIT msr cntkctl_el1, x0 .endm /* ----------------------------------------------------- * unsigned int plat_is_my_cpu_primary(void); * * This function checks if this is the Primary CPU * ----------------------------------------------------- */ func plat_is_my_cpu_primary mrs x0, mpidr_el1 and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) cmp x0, #TEGRA_PRIMARY_CPU cset x0, eq ret endfunc plat_is_my_cpu_primary /* ---------------------------------------------------------- * unsigned int plat_my_core_pos(void); * * result: CorePos = CoreId + (ClusterId * cpus per cluster) * ---------------------------------------------------------- */ func plat_my_core_pos mrs x0, mpidr_el1 and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK lsr x0, x0, #MPIDR_AFFINITY_BITS mov x2, #PLATFORM_MAX_CPUS_PER_CLUSTER mul x0, x0, x2 add x0, x1, x0 ret endfunc plat_my_core_pos /* ----------------------------------------------------- * unsigned long plat_get_my_entrypoint (void); * * Main job of this routine is to distinguish between * a cold and warm boot. If the tegra_sec_entry_point for * this CPU is present, then it's a warm boot. * * ----------------------------------------------------- */ func plat_get_my_entrypoint adr x1, tegra_sec_entry_point ldr x0, [x1] ret endfunc plat_get_my_entrypoint /* ----------------------------------------------------- * int platform_get_core_pos(int mpidr); * * result: CorePos = (ClusterId * cpus per cluster) + * CoreId * ----------------------------------------------------- */ func platform_get_core_pos and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK lsr x0, x0, #MPIDR_AFFINITY_BITS mov x2, #PLATFORM_MAX_CPUS_PER_CLUSTER mul x0, x0, x2 add x0, x1, x0 ret endfunc platform_get_core_pos /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions * needed for a secondary cpu after a cold reset. Right * now this is a stub function. * ----------------------------------------------------- */ func plat_secondary_cold_boot_setup mov x0, #0 ret endfunc plat_secondary_cold_boot_setup /* -------------------------------------------------------- * void platform_mem_init (void); * * Any memory init, relocation to be done before the * platform boots. Called very early in the boot process. * -------------------------------------------------------- */ func platform_mem_init mov x0, #0 ret endfunc platform_mem_init /* --------------------------------------------------- * Function to handle a platform reset and store * input parameters passed by BL2. * --------------------------------------------------- */ func plat_reset_handler /* ---------------------------------------------------- * Verify if we are running from BL31_BASE address * ---------------------------------------------------- */ adr x18, bl31_entrypoint mov x17, #BL31_BASE cmp x18, x17 b.eq 1f /* ---------------------------------------------------- * Copy the entire BL31 code to BL31_BASE if we are not * running from it already * ---------------------------------------------------- */ mov x0, x17 mov x1, x18 mov x2, #BL31_SIZE _loop16: cmp x2, #16 b.lo _loop1 ldp x3, x4, [x1], #16 stp x3, x4, [x0], #16 sub x2, x2, #16 b _loop16 /* copy byte per byte */ _loop1: cbz x2, _end ldrb w3, [x1], #1 strb w3, [x0], #1 subs x2, x2, #1 b.ne _loop1 /* ---------------------------------------------------- * Jump to BL31_BASE and start execution again * ---------------------------------------------------- */ _end: mov x0, x20 mov x1, x21 br x17 1: /* ----------------------------------- * derive and save the phys_base addr * ----------------------------------- */ adr x17, tegra_bl31_phys_base ldr x18, [x17] cbnz x18, 1f adr x18, bl31_entrypoint str x18, [x17] 1: cpu_init_common ret endfunc plat_reset_handler /* ---------------------------------------- * Secure entrypoint function for CPU boot * ---------------------------------------- */ func tegra_secure_entrypoint _align=6 #if ERRATA_TEGRA_INVALIDATE_BTB_AT_BOOT /* -------------------------------------------------------- * Skip the invalidate BTB workaround for Tegra210B01 SKUs. * -------------------------------------------------------- */ mov x0, #TEGRA_MISC_BASE add x0, x0, #HARDWARE_REVISION_OFFSET ldr w1, [x0] lsr w1, w1, #CHIP_ID_SHIFT and w1, w1, #CHIP_ID_MASK cmp w1, #TEGRA_CHIPID_TEGRA21 /* T210? */ b.ne 2f ldr w1, [x0] lsr w1, w1, #MAJOR_VERSION_SHIFT and w1, w1, #MAJOR_VERSION_MASK cmp w1, #0x02 /* T210 B01? */ b.eq 2f /* ------------------------------------------------------- * Invalidate BTB along with I$ to remove any stale * entries from the branch predictor array. * ------------------------------------------------------- */ mrs x0, CORTEX_A57_CPUACTLR_EL1 orr x0, x0, #1 msr CORTEX_A57_CPUACTLR_EL1, x0 /* invalidate BTB and I$ together */ dsb sy isb ic iallu /* actual invalidate */ dsb sy isb mrs x0, CORTEX_A57_CPUACTLR_EL1 bic x0, x0, #1 msr CORTEX_A57_CPUACTLR_EL1, X0 /* restore original CPUACTLR_EL1 */ dsb sy isb .rept 7 nop /* wait */ .endr /* ----------------------------------------------- * Extract OSLK bit and check if it is '1'. This * bit remains '0' for A53 on warm-resets. If '1', * turn off regional clock gating and request warm * reset. * ----------------------------------------------- */ mrs x0, oslsr_el1 and x0, x0, #2 mrs x1, mpidr_el1 bics xzr, x0, x1, lsr #7 /* 0 = slow cluster or warm reset */ b.eq restore_oslock mov x0, xzr msr oslar_el1, x0 /* os lock stays 0 across warm reset */ mov x3, #3 movz x4, #0x8000, lsl #48 msr CORTEX_A57_CPUACTLR_EL1, x4 /* turn off RCG */ isb msr rmr_el3, x3 /* request warm reset */ isb dsb sy 1: wfi b 1b /* -------------------------------------------------- * These nops are here so that speculative execution * won't harm us before we are done with warm reset. * -------------------------------------------------- */ .rept 65 nop .endr 2: /* -------------------------------------------------- * Do not insert instructions here * -------------------------------------------------- */ #endif /* -------------------------------------------------- * Restore OS Lock bit * -------------------------------------------------- */ restore_oslock: mov x0, #1 msr oslar_el1, x0 /* -------------------------------------------------- * Get secure world's entry point and jump to it * -------------------------------------------------- */ bl plat_get_my_entrypoint br x0 endfunc tegra_secure_entrypoint .data .align 3 /* -------------------------------------------------- * CPU Secure entry point - resume from suspend * -------------------------------------------------- */ tegra_sec_entry_point: .quad 0 /* -------------------------------------------------- * NS world's cold boot entry point * -------------------------------------------------- */ ns_image_entrypoint: .quad 0 /* -------------------------------------------------- * BL31's physical base address * -------------------------------------------------- */ tegra_bl31_phys_base: .quad 0 /* -------------------------------------------------- * UART controller base for console init * -------------------------------------------------- */ tegra_console_base: .quad 0 trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/000077500000000000000000000000001355360272700233735ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/bpmp/000077500000000000000000000000001355360272700243315ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/bpmp/bpmp.c000066400000000000000000000124001355360272700254300ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #define BPMP_TIMEOUT 500 /* 500ms */ static uint32_t channel_base[NR_CHANNELS]; static uint32_t bpmp_init_state = BPMP_INIT_PENDING; static uint32_t channel_field(unsigned int ch) { return mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET) & CH_MASK(ch); } static bool master_free(unsigned int ch) { return channel_field(ch) == MA_FREE(ch); } static bool master_acked(unsigned int ch) { return channel_field(ch) == MA_ACKD(ch); } static void signal_slave(unsigned int ch) { mmio_write_32(TEGRA_RES_SEMA_BASE + CLR_OFFSET, CH_MASK(ch)); } static void free_master(unsigned int ch) { mmio_write_32(TEGRA_RES_SEMA_BASE + CLR_OFFSET, MA_ACKD(ch) ^ MA_FREE(ch)); } /* should be called with local irqs disabled */ int32_t tegra_bpmp_send_receive_atomic(int mrq, const void *ob_data, int ob_sz, void *ib_data, int ib_sz) { unsigned int ch = (unsigned int)plat_my_core_pos(); mb_data_t *p = (mb_data_t *)(uintptr_t)channel_base[ch]; int32_t ret = -ETIMEDOUT, timeout = 0; if (bpmp_init_state == BPMP_INIT_COMPLETE) { /* loop until BPMP is free */ for (timeout = 0; timeout < BPMP_TIMEOUT; timeout++) { if (master_free(ch) == true) { break; } mdelay(1); } if (timeout != BPMP_TIMEOUT) { /* generate the command struct */ p->code = mrq; p->flags = DO_ACK; (void)memcpy((void *)p->data, ob_data, (size_t)ob_sz); /* signal command ready to the BPMP */ signal_slave(ch); mmio_write_32(TEGRA_PRI_ICTLR_BASE + CPU_IEP_FIR_SET, (1U << INT_SHR_SEM_OUTBOX_FULL)); /* loop until the command is executed */ for (timeout = 0; timeout < BPMP_TIMEOUT; timeout++) { if (master_acked(ch) == true) { break; } mdelay(1); } if (timeout != BPMP_TIMEOUT) { /* get the command response */ (void)memcpy(ib_data, (const void *)p->data, (size_t)ib_sz); /* return error code */ ret = p->code; /* free this channel */ free_master(ch); } } } else { /* return error code */ ret = -EINVAL; } if (timeout == BPMP_TIMEOUT) { ERROR("Timed out waiting for bpmp's response\n"); } return ret; } int tegra_bpmp_init(void) { uint32_t val, base, timeout = BPMP_TIMEOUT; unsigned int ch; int ret = 0; if (bpmp_init_state == BPMP_INIT_PENDING) { /* check if the bpmp processor is alive. */ do { val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET); if (val != SIGN_OF_LIFE) { mdelay(1); timeout--; } } while ((val != SIGN_OF_LIFE) && (timeout > 0U)); if (val == SIGN_OF_LIFE) { /* check if clock for the atomics block is enabled */ val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_ENB_V); if ((val & CAR_ENABLE_ATOMICS) == 0) { ERROR("Clock to the atomics block is disabled\n"); } /* check if the atomics block is out of reset */ val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_CLR_V); if ((val & CAR_ENABLE_ATOMICS) == CAR_ENABLE_ATOMICS) { ERROR("Reset to the atomics block is asserted\n"); } /* base address to get the result from Atomics */ base = TEGRA_ATOMICS_BASE + RESULT0_REG_OFFSET; /* channel area is setup by BPMP before signaling handshake */ for (ch = 0; ch < NR_CHANNELS; ch++) { /* issue command to get the channel base address */ mmio_write_32(base, (ch << TRIGGER_ID_SHIFT) | ATOMIC_CMD_GET); /* get the base address for the channel */ channel_base[ch] = mmio_read_32(base); /* increment result register offset */ base += 4U; } /* mark state as "initialized" */ bpmp_init_state = BPMP_INIT_COMPLETE; /* the channel values have to be visible across all cpus */ flush_dcache_range((uint64_t)channel_base, sizeof(channel_base)); flush_dcache_range((uint64_t)&bpmp_init_state, sizeof(bpmp_init_state)); INFO("%s: done\n", __func__); } else { ERROR("BPMP not powered on\n"); /* bpmp is not present in the system */ bpmp_init_state = BPMP_NOT_PRESENT; /* communication timed out */ ret = -ETIMEDOUT; } } return ret; } void tegra_bpmp_suspend(void) { /* freeze the interface */ if (bpmp_init_state == BPMP_INIT_COMPLETE) { bpmp_init_state = BPMP_SUSPEND_ENTRY; flush_dcache_range((uint64_t)&bpmp_init_state, sizeof(bpmp_init_state)); } } void tegra_bpmp_resume(void) { uint32_t val, timeout = 0; if (bpmp_init_state == BPMP_SUSPEND_ENTRY) { /* check if the bpmp processor is alive. */ do { val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET); if (val != SIGN_OF_LIFE) { mdelay(1); timeout++; } } while ((val != SIGN_OF_LIFE) && (timeout < BPMP_TIMEOUT)); if (val == SIGN_OF_LIFE) { INFO("%s: BPMP took %d ms to resume\n", __func__, timeout); /* mark state as "initialized" */ bpmp_init_state = BPMP_INIT_COMPLETE; /* state has to be visible across all cpus */ flush_dcache_range((uint64_t)&bpmp_init_state, sizeof(bpmp_init_state)); } else { ERROR("BPMP not powered on\n"); } } } trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/bpmp_ipc/000077500000000000000000000000001355360272700251645ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/bpmp_ipc/intf.c000066400000000000000000000173301355360272700262740ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "intf.h" #include "ivc.h" /** * Holds IVC channel data */ struct ccplex_bpmp_channel_data { /* Buffer for incoming data */ struct frame_data *ib; /* Buffer for outgoing data */ struct frame_data *ob; }; static struct ccplex_bpmp_channel_data s_channel; static struct ivc ivc_ccplex_bpmp_channel; /* * Helper functions to access the HSP doorbell registers */ static inline uint32_t hsp_db_read(uint32_t reg) { return mmio_read_32((uint32_t)(TEGRA_HSP_DBELL_BASE + reg)); } static inline void hsp_db_write(uint32_t reg, uint32_t val) { mmio_write_32((uint32_t)(TEGRA_HSP_DBELL_BASE + reg), val); } /******************************************************************************* * IVC wrappers for CCPLEX <-> BPMP communication. ******************************************************************************/ static void tegra_bpmp_ring_bpmp_doorbell(void); /* * Get the next frame where data can be written. */ static struct frame_data *tegra_bpmp_get_next_out_frame(void) { struct frame_data *frame; const struct ivc *ch = &ivc_ccplex_bpmp_channel; frame = (struct frame_data *)tegra_ivc_write_get_next_frame(ch); if (frame == NULL) { ERROR("%s: Error in getting next frame, exiting\n", __func__); } else { s_channel.ob = frame; } return frame; } static void tegra_bpmp_signal_slave(void) { (void)tegra_ivc_write_advance(&ivc_ccplex_bpmp_channel); tegra_bpmp_ring_bpmp_doorbell(); } static int32_t tegra_bpmp_free_master(void) { return tegra_ivc_read_advance(&ivc_ccplex_bpmp_channel); } static bool tegra_bpmp_slave_acked(void) { struct frame_data *frame; bool ret = true; frame = (struct frame_data *)tegra_ivc_read_get_next_frame(&ivc_ccplex_bpmp_channel); if (frame == NULL) { ret = false; } else { s_channel.ib = frame; } return ret; } static struct frame_data *tegra_bpmp_get_cur_in_frame(void) { return s_channel.ib; } /* * Enables BPMP to ring CCPlex doorbell */ static void tegra_bpmp_enable_ccplex_doorbell(void) { uint32_t reg; reg = hsp_db_read(HSP_DBELL_1_ENABLE); reg |= HSP_MASTER_BPMP_BIT; hsp_db_write(HSP_DBELL_1_ENABLE, reg); } /* * CCPlex rings the BPMP doorbell */ static void tegra_bpmp_ring_bpmp_doorbell(void) { /* * Any writes to this register has the same effect, * uses master ID of the write transaction and set * corresponding flag. */ hsp_db_write(HSP_DBELL_3_TRIGGER, HSP_MASTER_CCPLEX_BIT); } /* * Returns true if CCPLex can ring BPMP doorbell, otherwise false. * This also signals that BPMP is up and ready. */ static bool tegra_bpmp_can_ccplex_ring_doorbell(void) { uint32_t reg; /* check if ccplex can communicate with bpmp */ reg = hsp_db_read(HSP_DBELL_3_ENABLE); return ((reg & HSP_MASTER_CCPLEX_BIT) != 0U); } static int32_t tegra_bpmp_wait_for_slave_ack(void) { uint32_t timeout = TIMEOUT_RESPONSE_FROM_BPMP_US; while (!tegra_bpmp_slave_acked() && (timeout != 0U)) { udelay(1); timeout--; }; return ((timeout == 0U) ? -ETIMEDOUT : 0); } /* * Notification from the ivc layer */ static void tegra_bpmp_ivc_notify(const struct ivc *ivc) { (void)(ivc); tegra_bpmp_ring_bpmp_doorbell(); } /* * Atomic send/receive API, which means it waits until slave acks */ static int32_t tegra_bpmp_ipc_send_req_atomic(uint32_t mrq, void *p_out, uint32_t size_out, void *p_in, uint32_t size_in) { struct frame_data *frame = tegra_bpmp_get_next_out_frame(); const struct frame_data *f_in = NULL; int32_t ret = 0; void *p_fdata; if ((p_out == NULL) || (size_out > IVC_DATA_SZ_BYTES) || (frame == NULL)) { ERROR("%s: invalid parameters, exiting\n", __func__); ret = -EINVAL; } if (ret == 0) { /* prepare the command frame */ frame->mrq = mrq; frame->flags = FLAG_DO_ACK; p_fdata = frame->data; (void)memcpy(p_fdata, p_out, (size_t)size_out); /* signal the slave */ tegra_bpmp_signal_slave(); /* wait for slave to ack */ ret = tegra_bpmp_wait_for_slave_ack(); if (ret != 0) { ERROR("failed waiting for the slave to ack\n"); } /* retrieve the response frame */ if ((size_in <= IVC_DATA_SZ_BYTES) && (p_in != NULL) && (ret == 0)) { f_in = tegra_bpmp_get_cur_in_frame(); if (f_in != NULL) { ERROR("Failed to get next input frame!\n"); } else { (void)memcpy(p_in, p_fdata, (size_t)size_in); } } if (ret == 0) { ret = tegra_bpmp_free_master(); if (ret != 0) { ERROR("Failed to free master\n"); } } } return ret; } /* * Initializes the BPMP<--->CCPlex communication path. */ int32_t tegra_bpmp_ipc_init(void) { size_t msg_size; uint32_t frame_size, timeout; int32_t error = 0; /* allow bpmp to ring CCPLEX's doorbell */ tegra_bpmp_enable_ccplex_doorbell(); /* wait for BPMP to actually ring the doorbell */ timeout = TIMEOUT_RESPONSE_FROM_BPMP_US; while ((timeout != 0U) && !tegra_bpmp_can_ccplex_ring_doorbell()) { udelay(1); /* bpmp turn-around time */ timeout--; } if (timeout == 0U) { ERROR("%s: BPMP firmware is not ready\n", __func__); return -ENOTSUP; } INFO("%s: BPMP handshake completed\n", __func__); msg_size = tegra_ivc_align(IVC_CMD_SZ_BYTES); frame_size = (uint32_t)tegra_ivc_total_queue_size(msg_size); if (frame_size > TEGRA_BPMP_IPC_CH_MAP_SIZE) { ERROR("%s: carveout size is not sufficient\n", __func__); return -EINVAL; } error = tegra_ivc_init(&ivc_ccplex_bpmp_channel, (uint32_t)TEGRA_BPMP_IPC_RX_PHYS_BASE, (uint32_t)TEGRA_BPMP_IPC_TX_PHYS_BASE, 1U, frame_size, tegra_bpmp_ivc_notify); if (error != 0) { ERROR("%s: IVC init failed (%d)\n", __func__, error); } else { /* reset channel */ tegra_ivc_channel_reset(&ivc_ccplex_bpmp_channel); /* wait for notification from BPMP */ while (tegra_ivc_channel_notified(&ivc_ccplex_bpmp_channel) != 0) { /* * Interrupt BPMP with doorbell each time after * tegra_ivc_channel_notified() returns non zero * value. */ tegra_bpmp_ring_bpmp_doorbell(); } INFO("%s: All communication channels initialized\n", __func__); } return error; } /* Handler to reset a hardware module */ int32_t tegra_bpmp_ipc_reset_module(uint32_t rst_id) { int32_t ret; struct mrq_reset_request req = { .cmd = (uint32_t)CMD_RESET_MODULE, .reset_id = rst_id }; /* only GPCDMA/XUSB_PADCTL resets are supported */ assert((rst_id == TEGRA_RESET_ID_XUSB_PADCTL) || (rst_id == TEGRA_RESET_ID_GPCDMA)); ret = tegra_bpmp_ipc_send_req_atomic(MRQ_RESET, &req, (uint32_t)sizeof(req), NULL, 0); if (ret != 0) { ERROR("%s: failed for module %d with error %d\n", __func__, rst_id, ret); } return ret; } int tegra_bpmp_ipc_enable_clock(uint32_t clk_id) { int ret; struct mrq_clk_request req; /* only SE clocks are supported */ if (clk_id != TEGRA_CLK_SE) { return -ENOTSUP; } /* prepare the MRQ_CLK command */ req.cmd_and_id = make_mrq_clk_cmd(CMD_CLK_ENABLE, clk_id); ret = tegra_bpmp_ipc_send_req_atomic(MRQ_CLK, &req, sizeof(req), NULL, 0); if (ret != 0) { ERROR("%s: failed for module %d with error %d\n", __func__, clk_id, ret); } return ret; } int tegra_bpmp_ipc_disable_clock(uint32_t clk_id) { int ret; struct mrq_clk_request req; /* only SE clocks are supported */ if (clk_id != TEGRA_CLK_SE) { return -ENOTSUP; } /* prepare the MRQ_CLK command */ req.cmd_and_id = make_mrq_clk_cmd(CMD_CLK_DISABLE, clk_id); ret = tegra_bpmp_ipc_send_req_atomic(MRQ_CLK, &req, sizeof(req), NULL, 0); if (ret != 0) { ERROR("%s: failed for module %d with error %d\n", __func__, clk_id, ret); } return ret; } trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/bpmp_ipc/intf.h000066400000000000000000000060711355360272700263010ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef INTF_H #define INTF_H /** * Flags used in IPC req */ #define FLAG_DO_ACK (U(1) << 0) #define FLAG_RING_DOORBELL (U(1) << 1) /* Bit 1 is designated for CCPlex in secure world */ #define HSP_MASTER_CCPLEX_BIT (U(1) << 1) /* Bit 19 is designated for BPMP in non-secure world */ #define HSP_MASTER_BPMP_BIT (U(1) << 19) /* Timeout to receive response from BPMP is 1 sec */ #define TIMEOUT_RESPONSE_FROM_BPMP_US U(1000000) /* in microseconds */ /** * IVC protocol defines and command/response frame */ /** * IVC specific defines */ #define IVC_CMD_SZ_BYTES U(128) #define IVC_DATA_SZ_BYTES U(120) /** * Holds frame data for an IPC request */ struct frame_data { /* Identification as to what kind of data is being transmitted */ uint32_t mrq; /* Flags for slave as to how to respond back */ uint32_t flags; /* Actual data being sent */ uint8_t data[IVC_DATA_SZ_BYTES]; }; /** * Commands send to the BPMP firmware */ /** * MRQ command codes */ #define MRQ_RESET U(20) #define MRQ_CLK U(22) /** * Reset sub-commands */ #define CMD_RESET_ASSERT U(1) #define CMD_RESET_DEASSERT U(2) #define CMD_RESET_MODULE U(3) /** * Used by the sender of an #MRQ_RESET message to request BPMP to * assert or deassert a given reset line. */ struct __attribute__((packed)) mrq_reset_request { /* reset action to perform (mrq_reset_commands) */ uint32_t cmd; /* id of the reset to affected */ uint32_t reset_id; }; /** * MRQ_CLK sub-commands * */ enum { CMD_CLK_GET_RATE = 1, CMD_CLK_SET_RATE = 2, CMD_CLK_ROUND_RATE = 3, CMD_CLK_GET_PARENT = 4, CMD_CLK_SET_PARENT = 5, CMD_CLK_IS_ENABLED = 6, CMD_CLK_ENABLE = 7, CMD_CLK_DISABLE = 8, CMD_CLK_GET_ALL_INFO = 14, CMD_CLK_GET_MAX_CLK_ID = 15, CMD_CLK_MAX, }; /** * Used by the sender of an #MRQ_CLK message to control clocks. The * clk_request is split into several sub-commands. Some sub-commands * require no additional data. Others have a sub-command specific * payload * * |sub-command |payload | * |----------------------------|-----------------------| * |CMD_CLK_GET_RATE |- | * |CMD_CLK_SET_RATE |clk_set_rate | * |CMD_CLK_ROUND_RATE |clk_round_rate | * |CMD_CLK_GET_PARENT |- | * |CMD_CLK_SET_PARENT |clk_set_parent | * |CMD_CLK_IS_ENABLED |- | * |CMD_CLK_ENABLE |- | * |CMD_CLK_DISABLE |- | * |CMD_CLK_GET_ALL_INFO |- | * |CMD_CLK_GET_MAX_CLK_ID |- | * */ struct mrq_clk_request { /** * sub-command and clock id concatenated to 32-bit word. * - bits[31..24] is the sub-cmd. * - bits[23..0] is the clock id */ uint32_t cmd_and_id; }; /** * Macro to prepare the MRQ_CLK sub-command */ #define make_mrq_clk_cmd(cmd, id) (((cmd) << 24) | (id & 0xFFFFFF)) #endif /* INTF_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/bpmp_ipc/ivc.c000066400000000000000000000377241355360272700261260ustar00rootroot00000000000000/* * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "ivc.h" /* * IVC channel reset protocol. * * Each end uses its tx_channel.state to indicate its synchronization state. */ enum { /* * This value is zero for backwards compatibility with services that * assume channels to be initially zeroed. Such channels are in an * initially valid state, but cannot be asynchronously reset, and must * maintain a valid state at all times. * * The transmitting end can enter the established state from the sync or * ack state when it observes the receiving endpoint in the ack or * established state, indicating that has cleared the counters in our * rx_channel. */ ivc_state_established = U(0), /* * If an endpoint is observed in the sync state, the remote endpoint is * allowed to clear the counters it owns asynchronously with respect to * the current endpoint. Therefore, the current endpoint is no longer * allowed to communicate. */ ivc_state_sync = U(1), /* * When the transmitting end observes the receiving end in the sync * state, it can clear the w_count and r_count and transition to the ack * state. If the remote endpoint observes us in the ack state, it can * return to the established state once it has cleared its counters. */ ivc_state_ack = U(2) }; /* * This structure is divided into two-cache aligned parts, the first is only * written through the tx_channel pointer, while the second is only written * through the rx_channel pointer. This delineates ownership of the cache lines, * which is critical to performance and necessary in non-cache coherent * implementations. */ struct ivc_channel_header { struct { /* fields owned by the transmitting end */ uint32_t w_count; uint32_t state; uint32_t w_rsvd[IVC_CHHDR_TX_FIELDS - 2]; }; struct { /* fields owned by the receiving end */ uint32_t r_count; uint32_t r_rsvd[IVC_CHHDR_RX_FIELDS - 1]; }; }; static inline bool ivc_channel_empty(const struct ivc *ivc, volatile const struct ivc_channel_header *ch) { /* * This function performs multiple checks on the same values with * security implications, so sample the counters' current values in * shared memory to ensure that these checks use the same values. */ uint32_t wr_count = ch->w_count; uint32_t rd_count = ch->r_count; bool ret = false; (void)ivc; /* * Perform an over-full check to prevent denial of service attacks where * a server could be easily fooled into believing that there's an * extremely large number of frames ready, since receivers are not * expected to check for full or over-full conditions. * * Although the channel isn't empty, this is an invalid case caused by * a potentially malicious peer, so returning empty is safer, because it * gives the impression that the channel has gone silent. */ if (((wr_count - rd_count) > ivc->nframes) || (wr_count == rd_count)) { ret = true; } return ret; } static inline bool ivc_channel_full(const struct ivc *ivc, volatile const struct ivc_channel_header *ch) { uint32_t wr_count = ch->w_count; uint32_t rd_count = ch->r_count; (void)ivc; /* * Invalid cases where the counters indicate that the queue is over * capacity also appear full. */ return ((wr_count - rd_count) >= ivc->nframes); } static inline uint32_t ivc_channel_avail_count(const struct ivc *ivc, volatile const struct ivc_channel_header *ch) { uint32_t wr_count = ch->w_count; uint32_t rd_count = ch->r_count; (void)ivc; /* * This function isn't expected to be used in scenarios where an * over-full situation can lead to denial of service attacks. See the * comment in ivc_channel_empty() for an explanation about special * over-full considerations. */ return (wr_count - rd_count); } static inline void ivc_advance_tx(struct ivc *ivc) { ivc->tx_channel->w_count++; if (ivc->w_pos == (ivc->nframes - (uint32_t)1U)) { ivc->w_pos = 0U; } else { ivc->w_pos++; } } static inline void ivc_advance_rx(struct ivc *ivc) { ivc->rx_channel->r_count++; if (ivc->r_pos == (ivc->nframes - (uint32_t)1U)) { ivc->r_pos = 0U; } else { ivc->r_pos++; } } static inline int32_t ivc_check_read(const struct ivc *ivc) { /* * tx_channel->state is set locally, so it is not synchronized with * state from the remote peer. The remote peer cannot reset its * transmit counters until we've acknowledged its synchronization * request, so no additional synchronization is required because an * asynchronous transition of rx_channel->state to ivc_state_ack is not * allowed. */ if (ivc->tx_channel->state != ivc_state_established) { return -ECONNRESET; } /* * Avoid unnecessary invalidations when performing repeated accesses to * an IVC channel by checking the old queue pointers first. * Synchronization is only necessary when these pointers indicate empty * or full. */ if (!ivc_channel_empty(ivc, ivc->rx_channel)) { return 0; } return ivc_channel_empty(ivc, ivc->rx_channel) ? -ENOMEM : 0; } static inline int32_t ivc_check_write(const struct ivc *ivc) { if (ivc->tx_channel->state != ivc_state_established) { return -ECONNRESET; } if (!ivc_channel_full(ivc, ivc->tx_channel)) { return 0; } return ivc_channel_full(ivc, ivc->tx_channel) ? -ENOMEM : 0; } bool tegra_ivc_can_read(const struct ivc *ivc) { return ivc_check_read(ivc) == 0; } bool tegra_ivc_can_write(const struct ivc *ivc) { return ivc_check_write(ivc) == 0; } bool tegra_ivc_tx_empty(const struct ivc *ivc) { return ivc_channel_empty(ivc, ivc->tx_channel); } static inline uintptr_t calc_frame_offset(uint32_t frame_index, uint32_t frame_size, uint32_t frame_offset) { return ((uintptr_t)frame_index * (uintptr_t)frame_size) + (uintptr_t)frame_offset; } static void *ivc_frame_pointer(const struct ivc *ivc, volatile const struct ivc_channel_header *ch, uint32_t frame) { assert(frame < ivc->nframes); return (void *)((uintptr_t)(&ch[1]) + calc_frame_offset(frame, ivc->frame_size, 0)); } int32_t tegra_ivc_read(struct ivc *ivc, void *buf, size_t max_read) { const void *src; int32_t result; if (buf == NULL) { return -EINVAL; } if (max_read > ivc->frame_size) { return -E2BIG; } result = ivc_check_read(ivc); if (result != 0) { return result; } /* * Order observation of w_pos potentially indicating new data before * data read. */ dmbish(); src = ivc_frame_pointer(ivc, ivc->rx_channel, ivc->r_pos); (void)memcpy(buf, src, max_read); ivc_advance_rx(ivc); /* * Ensure our write to r_pos occurs before our read from w_pos. */ dmbish(); /* * Notify only upon transition from full to non-full. * The available count can only asynchronously increase, so the * worst possible side-effect will be a spurious notification. */ if (ivc_channel_avail_count(ivc, ivc->rx_channel) == (ivc->nframes - (uint32_t)1U)) { ivc->notify(ivc); } return (int32_t)max_read; } /* directly peek at the next frame rx'ed */ void *tegra_ivc_read_get_next_frame(const struct ivc *ivc) { if (ivc_check_read(ivc) != 0) { return NULL; } /* * Order observation of w_pos potentially indicating new data before * data read. */ dmbld(); return ivc_frame_pointer(ivc, ivc->rx_channel, ivc->r_pos); } int32_t tegra_ivc_read_advance(struct ivc *ivc) { /* * No read barriers or synchronization here: the caller is expected to * have already observed the channel non-empty. This check is just to * catch programming errors. */ int32_t result = ivc_check_read(ivc); if (result != 0) { return result; } ivc_advance_rx(ivc); /* * Ensure our write to r_pos occurs before our read from w_pos. */ dmbish(); /* * Notify only upon transition from full to non-full. * The available count can only asynchronously increase, so the * worst possible side-effect will be a spurious notification. */ if (ivc_channel_avail_count(ivc, ivc->rx_channel) == (ivc->nframes - (uint32_t)1U)) { ivc->notify(ivc); } return 0; } int32_t tegra_ivc_write(struct ivc *ivc, const void *buf, size_t size) { void *p; int32_t result; if ((buf == NULL) || (ivc == NULL)) { return -EINVAL; } if (size > ivc->frame_size) { return -E2BIG; } result = ivc_check_write(ivc); if (result != 0) { return result; } p = ivc_frame_pointer(ivc, ivc->tx_channel, ivc->w_pos); (void)memset(p, 0, ivc->frame_size); (void)memcpy(p, buf, size); /* * Ensure that updated data is visible before the w_pos counter * indicates that it is ready. */ dmbst(); ivc_advance_tx(ivc); /* * Ensure our write to w_pos occurs before our read from r_pos. */ dmbish(); /* * Notify only upon transition from empty to non-empty. * The available count can only asynchronously decrease, so the * worst possible side-effect will be a spurious notification. */ if (ivc_channel_avail_count(ivc, ivc->tx_channel) == 1U) { ivc->notify(ivc); } return (int32_t)size; } /* directly poke at the next frame to be tx'ed */ void *tegra_ivc_write_get_next_frame(const struct ivc *ivc) { if (ivc_check_write(ivc) != 0) { return NULL; } return ivc_frame_pointer(ivc, ivc->tx_channel, ivc->w_pos); } /* advance the tx buffer */ int32_t tegra_ivc_write_advance(struct ivc *ivc) { int32_t result = ivc_check_write(ivc); if (result != 0) { return result; } /* * Order any possible stores to the frame before update of w_pos. */ dmbst(); ivc_advance_tx(ivc); /* * Ensure our write to w_pos occurs before our read from r_pos. */ dmbish(); /* * Notify only upon transition from empty to non-empty. * The available count can only asynchronously decrease, so the * worst possible side-effect will be a spurious notification. */ if (ivc_channel_avail_count(ivc, ivc->tx_channel) == (uint32_t)1U) { ivc->notify(ivc); } return 0; } void tegra_ivc_channel_reset(const struct ivc *ivc) { ivc->tx_channel->state = ivc_state_sync; ivc->notify(ivc); } /* * =============================================================== * IVC State Transition Table - see tegra_ivc_channel_notified() * =============================================================== * * local remote action * ----- ------ ----------------------------------- * SYNC EST * SYNC ACK reset counters; move to EST; notify * SYNC SYNC reset counters; move to ACK; notify * ACK EST move to EST; notify * ACK ACK move to EST; notify * ACK SYNC reset counters; move to ACK; notify * EST EST * EST ACK * EST SYNC reset counters; move to ACK; notify * * =============================================================== */ int32_t tegra_ivc_channel_notified(struct ivc *ivc) { uint32_t peer_state; /* Copy the receiver's state out of shared memory. */ peer_state = ivc->rx_channel->state; if (peer_state == (uint32_t)ivc_state_sync) { /* * Order observation of ivc_state_sync before stores clearing * tx_channel. */ dmbld(); /* * Reset tx_channel counters. The remote end is in the SYNC * state and won't make progress until we change our state, * so the counters are not in use at this time. */ ivc->tx_channel->w_count = 0U; ivc->rx_channel->r_count = 0U; ivc->w_pos = 0U; ivc->r_pos = 0U; /* * Ensure that counters appear cleared before new state can be * observed. */ dmbst(); /* * Move to ACK state. We have just cleared our counters, so it * is now safe for the remote end to start using these values. */ ivc->tx_channel->state = ivc_state_ack; /* * Notify remote end to observe state transition. */ ivc->notify(ivc); } else if ((ivc->tx_channel->state == (uint32_t)ivc_state_sync) && (peer_state == (uint32_t)ivc_state_ack)) { /* * Order observation of ivc_state_sync before stores clearing * tx_channel. */ dmbld(); /* * Reset tx_channel counters. The remote end is in the ACK * state and won't make progress until we change our state, * so the counters are not in use at this time. */ ivc->tx_channel->w_count = 0U; ivc->rx_channel->r_count = 0U; ivc->w_pos = 0U; ivc->r_pos = 0U; /* * Ensure that counters appear cleared before new state can be * observed. */ dmbst(); /* * Move to ESTABLISHED state. We know that the remote end has * already cleared its counters, so it is safe to start * writing/reading on this channel. */ ivc->tx_channel->state = ivc_state_established; /* * Notify remote end to observe state transition. */ ivc->notify(ivc); } else if (ivc->tx_channel->state == (uint32_t)ivc_state_ack) { /* * At this point, we have observed the peer to be in either * the ACK or ESTABLISHED state. Next, order observation of * peer state before storing to tx_channel. */ dmbld(); /* * Move to ESTABLISHED state. We know that we have previously * cleared our counters, and we know that the remote end has * cleared its counters, so it is safe to start writing/reading * on this channel. */ ivc->tx_channel->state = ivc_state_established; /* * Notify remote end to observe state transition. */ ivc->notify(ivc); } else { /* * There is no need to handle any further action. Either the * channel is already fully established, or we are waiting for * the remote end to catch up with our current state. Refer * to the diagram in "IVC State Transition Table" above. */ } return ((ivc->tx_channel->state == (uint32_t)ivc_state_established) ? 0 : -EAGAIN); } size_t tegra_ivc_align(size_t size) { return (size + (IVC_ALIGN - 1U)) & ~(IVC_ALIGN - 1U); } size_t tegra_ivc_total_queue_size(size_t queue_size) { if ((queue_size & (IVC_ALIGN - 1U)) != 0U) { ERROR("queue_size (%d) must be %d-byte aligned\n", (int32_t)queue_size, IVC_ALIGN); return 0; } return queue_size + sizeof(struct ivc_channel_header); } static int32_t check_ivc_params(uintptr_t queue_base1, uintptr_t queue_base2, uint32_t nframes, uint32_t frame_size) { assert((offsetof(struct ivc_channel_header, w_count) & (IVC_ALIGN - 1U)) == 0U); assert((offsetof(struct ivc_channel_header, r_count) & (IVC_ALIGN - 1U)) == 0U); assert((sizeof(struct ivc_channel_header) & (IVC_ALIGN - 1U)) == 0U); if (((uint64_t)nframes * (uint64_t)frame_size) >= 0x100000000ULL) { ERROR("nframes * frame_size overflows\n"); return -EINVAL; } /* * The headers must at least be aligned enough for counters * to be accessed atomically. */ if ((queue_base1 & (IVC_ALIGN - 1U)) != 0U) { ERROR("ivc channel start not aligned: %lx\n", queue_base1); return -EINVAL; } if ((queue_base2 & (IVC_ALIGN - 1U)) != 0U) { ERROR("ivc channel start not aligned: %lx\n", queue_base2); return -EINVAL; } if ((frame_size & (IVC_ALIGN - 1U)) != 0U) { ERROR("frame size not adequately aligned: %u\n", frame_size); return -EINVAL; } if (queue_base1 < queue_base2) { if ((queue_base1 + ((uint64_t)frame_size * nframes)) > queue_base2) { ERROR("queue regions overlap: %lx + %x, %x\n", queue_base1, frame_size, frame_size * nframes); return -EINVAL; } } else { if ((queue_base2 + ((uint64_t)frame_size * nframes)) > queue_base1) { ERROR("queue regions overlap: %lx + %x, %x\n", queue_base2, frame_size, frame_size * nframes); return -EINVAL; } } return 0; } int32_t tegra_ivc_init(struct ivc *ivc, uintptr_t rx_base, uintptr_t tx_base, uint32_t nframes, uint32_t frame_size, ivc_notify_function notify) { int32_t result; /* sanity check input params */ if ((ivc == NULL) || (notify == NULL)) { return -EINVAL; } result = check_ivc_params(rx_base, tx_base, nframes, frame_size); if (result != 0) { return result; } /* * All sizes that can be returned by communication functions should * fit in a 32-bit integer. */ if (frame_size > (1u << 31)) { return -E2BIG; } ivc->rx_channel = (struct ivc_channel_header *)rx_base; ivc->tx_channel = (struct ivc_channel_header *)tx_base; ivc->notify = notify; ivc->frame_size = frame_size; ivc->nframes = nframes; ivc->w_pos = 0U; ivc->r_pos = 0U; INFO("%s: done\n", __func__); return 0; } trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/bpmp_ipc/ivc.h000066400000000000000000000030021355360272700261110ustar00rootroot00000000000000/* * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef IVC_H #define IVC_H #include #include #include #define IVC_ALIGN U(64) #define IVC_CHHDR_TX_FIELDS U(16) #define IVC_CHHDR_RX_FIELDS U(16) struct ivc; struct ivc_channel_header; /* callback handler for notify on receiving a response */ typedef void (* ivc_notify_function)(const struct ivc *); struct ivc { struct ivc_channel_header *rx_channel; struct ivc_channel_header *tx_channel; uint32_t w_pos; uint32_t r_pos; ivc_notify_function notify; uint32_t nframes; uint32_t frame_size; }; int32_t tegra_ivc_init(struct ivc *ivc, uintptr_t rx_base, uintptr_t tx_base, uint32_t nframes, uint32_t frame_size, ivc_notify_function notify); size_t tegra_ivc_total_queue_size(size_t queue_size); size_t tegra_ivc_align(size_t size); int32_t tegra_ivc_channel_notified(struct ivc *ivc); void tegra_ivc_channel_reset(const struct ivc *ivc); int32_t tegra_ivc_write_advance(struct ivc *ivc); void *tegra_ivc_write_get_next_frame(const struct ivc *ivc); int32_t tegra_ivc_write(struct ivc *ivc, const void *buf, size_t size); int32_t tegra_ivc_read_advance(struct ivc *ivc); void *tegra_ivc_read_get_next_frame(const struct ivc *ivc); int32_t tegra_ivc_read(struct ivc *ivc, void *buf, size_t max_read); bool tegra_ivc_tx_empty(const struct ivc *ivc); bool tegra_ivc_can_write(const struct ivc *ivc); bool tegra_ivc_can_read(const struct ivc *ivc); #endif /* IVC_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/flowctrl/000077500000000000000000000000001355360272700252275ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c000066400000000000000000000241461355360272700272360ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #define CLK_RST_DEV_L_SET 0x300 #define CLK_RST_DEV_L_CLR 0x304 #define CLK_BPMP_RST (1 << 1) #define EVP_BPMP_RESET_VECTOR 0x200 static const uint64_t flowctrl_offset_cpu_csr[4] = { (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU0_CSR), (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR), (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR + 8), (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR + 16) }; static const uint64_t flowctrl_offset_halt_cpu[4] = { (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU0_EVENTS), (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS), (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS + 8), (TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS + 16) }; static const uint64_t flowctrl_offset_cc4_ctrl[4] = { (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL), (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 4), (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 8), (TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 12) }; static inline void tegra_fc_cc4_ctrl(int cpu_id, uint32_t val) { mmio_write_32(flowctrl_offset_cc4_ctrl[cpu_id], val); val = mmio_read_32(flowctrl_offset_cc4_ctrl[cpu_id]); } static inline void tegra_fc_cpu_csr(int cpu_id, uint32_t val) { mmio_write_32(flowctrl_offset_cpu_csr[cpu_id], val); val = mmio_read_32(flowctrl_offset_cpu_csr[cpu_id]); } static inline void tegra_fc_halt_cpu(int cpu_id, uint32_t val) { mmio_write_32(flowctrl_offset_halt_cpu[cpu_id], val); val = mmio_read_32(flowctrl_offset_halt_cpu[cpu_id]); } static void tegra_fc_prepare_suspend(int cpu_id, uint32_t csr) { uint32_t val; val = FLOWCTRL_HALT_GIC_IRQ | FLOWCTRL_HALT_GIC_FIQ | FLOWCTRL_HALT_LIC_IRQ | FLOWCTRL_HALT_LIC_FIQ | FLOWCTRL_WAITEVENT; tegra_fc_halt_cpu(cpu_id, val); val = FLOWCTRL_CSR_INTR_FLAG | FLOWCTRL_CSR_EVENT_FLAG | FLOWCTRL_CSR_ENABLE | (FLOWCTRL_WAIT_WFI_BITMAP << cpu_id); tegra_fc_cpu_csr(cpu_id, val | csr); } /******************************************************************************* * After this, no core can wake from C7 until the action is reverted. * If a wake up event is asserted, the FC state machine will stall until * the action is reverted. ******************************************************************************/ void tegra_fc_ccplex_pgexit_lock(void) { unsigned int i, cpu = read_mpidr() & MPIDR_CPU_MASK; uint32_t flags = tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT) & ~INTERCEPT_IRQ_PENDING;; uint32_t icept_cpu_flags[] = { INTERCEPT_EXIT_PG_CORE0, INTERCEPT_EXIT_PG_CORE1, INTERCEPT_EXIT_PG_CORE2, INTERCEPT_EXIT_PG_CORE3 }; /* set the intercept flags */ for (i = 0; i < ARRAY_SIZE(icept_cpu_flags); i++) { /* skip current CPU */ if (i == cpu) continue; /* enable power gate exit intercept locks */ flags |= icept_cpu_flags[i]; } tegra_fc_write_32(FLOWCTRL_FC_SEQ_INTERCEPT, flags); (void)tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT); } /******************************************************************************* * Revert the ccplex powergate exit locks ******************************************************************************/ void tegra_fc_ccplex_pgexit_unlock(void) { /* clear lock bits, clear pending interrupts */ tegra_fc_write_32(FLOWCTRL_FC_SEQ_INTERCEPT, INTERCEPT_IRQ_PENDING); (void)tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT); } /******************************************************************************* * Powerdn the current CPU ******************************************************************************/ void tegra_fc_cpu_powerdn(uint32_t mpidr) { int cpu = mpidr & MPIDR_CPU_MASK; VERBOSE("CPU%d powering down...\n", cpu); tegra_fc_prepare_suspend(cpu, 0); } /******************************************************************************* * Suspend the current CPU cluster ******************************************************************************/ void tegra_fc_cluster_idle(uint32_t mpidr) { int cpu = mpidr & MPIDR_CPU_MASK; uint32_t val; VERBOSE("Entering cluster idle state...\n"); tegra_fc_cc4_ctrl(cpu, 0); /* hardware L2 flush is faster for A53 only */ tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL, !!MPIDR_AFFLVL1_VAL(mpidr)); /* suspend the CPU cluster */ val = FLOWCTRL_PG_CPU_NONCPU << FLOWCTRL_ENABLE_EXT; tegra_fc_prepare_suspend(cpu, val); } /******************************************************************************* * Power down the current CPU cluster ******************************************************************************/ void tegra_fc_cluster_powerdn(uint32_t mpidr) { int cpu = mpidr & MPIDR_CPU_MASK; uint32_t val; VERBOSE("Entering cluster powerdn state...\n"); tegra_fc_cc4_ctrl(cpu, 0); /* hardware L2 flush is faster for A53 only */ tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL, read_midr() == CORTEX_A53_MIDR); /* power down the CPU cluster */ val = FLOWCTRL_TURNOFF_CPURAIL << FLOWCTRL_ENABLE_EXT; tegra_fc_prepare_suspend(cpu, val); } /******************************************************************************* * Check if cluster idle or power down state is allowed from this CPU ******************************************************************************/ bool tegra_fc_is_ccx_allowed(void) { unsigned int i, cpu = read_mpidr() & MPIDR_CPU_MASK; uint32_t val; bool ccx_allowed = true; for (i = 0; i < ARRAY_SIZE(flowctrl_offset_cpu_csr); i++) { /* skip current CPU */ if (i == cpu) continue; /* check if all other CPUs are already halted */ val = mmio_read_32(flowctrl_offset_cpu_csr[i]); if ((val & FLOWCTRL_CSR_HALT_MASK) == 0U) { ccx_allowed = false; } } return ccx_allowed; } /******************************************************************************* * Suspend the entire SoC ******************************************************************************/ void tegra_fc_soc_powerdn(uint32_t mpidr) { int cpu = mpidr & MPIDR_CPU_MASK; uint32_t val; VERBOSE("Entering SoC powerdn state...\n"); tegra_fc_cc4_ctrl(cpu, 0); tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL, 1); val = FLOWCTRL_TURNOFF_CPURAIL << FLOWCTRL_ENABLE_EXT; tegra_fc_prepare_suspend(cpu, val); /* overwrite HALT register */ tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT); } /******************************************************************************* * Power up the CPU ******************************************************************************/ void tegra_fc_cpu_on(int cpu) { tegra_fc_cpu_csr(cpu, FLOWCTRL_CSR_ENABLE); tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT | FLOWCTRL_HALT_SCLK); } /******************************************************************************* * Power down the CPU ******************************************************************************/ void tegra_fc_cpu_off(int cpu) { uint32_t val; /* * Flow controller powers down the CPU during wfi. The CPU would be * powered on when it receives any interrupt. */ val = FLOWCTRL_CSR_INTR_FLAG | FLOWCTRL_CSR_EVENT_FLAG | FLOWCTRL_CSR_ENABLE | (FLOWCTRL_WAIT_WFI_BITMAP << cpu); tegra_fc_cpu_csr(cpu, val); tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT); tegra_fc_cc4_ctrl(cpu, 0); } /******************************************************************************* * Inform the BPMP that we have completed the cluster power up ******************************************************************************/ void tegra_fc_lock_active_cluster(void) { uint32_t val; val = tegra_fc_read_32(FLOWCTRL_BPMP_CLUSTER_CONTROL); val |= FLOWCTRL_BPMP_CLUSTER_PWRON_LOCK; tegra_fc_write_32(FLOWCTRL_BPMP_CLUSTER_CONTROL, val); val = tegra_fc_read_32(FLOWCTRL_BPMP_CLUSTER_CONTROL); } /******************************************************************************* * Power ON BPMP processor ******************************************************************************/ void tegra_fc_bpmp_on(uint32_t entrypoint) { /* halt BPMP */ tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT); /* Assert BPMP reset */ mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST); /* Set reset address (stored in PMC_SCRATCH39) */ mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, entrypoint); while (entrypoint != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR)) ; /* wait till value reaches EVP_BPMP_RESET_VECTOR */ /* Wait for 2us before de-asserting the reset signal. */ udelay(2); /* De-assert BPMP reset */ mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_CLR, CLK_BPMP_RST); /* Un-halt BPMP */ tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, 0); } /******************************************************************************* * Power OFF BPMP processor ******************************************************************************/ void tegra_fc_bpmp_off(void) { /* halt BPMP */ tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT); /* Assert BPMP reset */ mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST); /* Clear reset address */ mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, 0); while (0 != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR)) ; /* wait till value reaches EVP_BPMP_RESET_VECTOR */ } /******************************************************************************* * Route legacy FIQ to the GICD ******************************************************************************/ void tegra_fc_enable_fiq_to_ccplex_routing(void) { uint32_t val = tegra_fc_read_32(FLOW_CTLR_FLOW_DBG_QUAL); /* set the bit to pass FIQs to the GICD */ tegra_fc_write_32(FLOW_CTLR_FLOW_DBG_QUAL, val | FLOWCTRL_FIQ2CCPLEX_ENABLE); } /******************************************************************************* * Disable routing legacy FIQ to the GICD ******************************************************************************/ void tegra_fc_disable_fiq_to_ccplex_routing(void) { uint32_t val = tegra_fc_read_32(FLOW_CTLR_FLOW_DBG_QUAL); /* clear the bit to pass FIQs to the GICD */ tegra_fc_write_32(FLOW_CTLR_FLOW_DBG_QUAL, val & ~FLOWCTRL_FIQ2CCPLEX_ENABLE); } trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/gpcdma/000077500000000000000000000000001355360272700246265ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/gpcdma/gpcdma.c000066400000000000000000000122521355360272700262270ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include /* DMA channel registers */ #define DMA_CH_CSR U(0x0) #define DMA_CH_CSR_WEIGHT_SHIFT U(10) #define DMA_CH_CSR_XFER_MODE_SHIFT U(21) #define DMA_CH_CSR_DMA_MODE_MEM2MEM U(4) #define DMA_CH_CSR_DMA_MODE_FIXEDPATTERN U(6) #define DMA_CH_CSR_IRQ_MASK_ENABLE (U(1) << 15) #define DMA_CH_CSR_RUN_ONCE (U(1) << 27) #define DMA_CH_CSR_ENABLE (U(1) << 31) #define DMA_CH_STAT U(0x4) #define DMA_CH_STAT_BUSY (U(1) << 31) #define DMA_CH_SRC_PTR U(0xC) #define DMA_CH_DST_PTR U(0x10) #define DMA_CH_HI_ADR_PTR U(0x14) #define DMA_CH_HI_ADR_PTR_SRC_MASK U(0xFF) #define DMA_CH_HI_ADR_PTR_DST_SHIFT U(16) #define DMA_CH_HI_ADR_PTR_DST_MASK U(0xFF) #define DMA_CH_MC_SEQ U(0x18) #define DMA_CH_MC_SEQ_REQ_CNT_SHIFT U(25) #define DMA_CH_MC_SEQ_REQ_CNT_VAL U(0x10) #define DMA_CH_MC_SEQ_BURST_SHIFT U(23) #define DMA_CH_MC_SEQ_BURST_16_WORDS U(0x3) #define DMA_CH_WORD_COUNT U(0x20) #define DMA_CH_FIXED_PATTERN U(0x34) #define DMA_CH_TZ U(0x38) #define DMA_CH_TZ_ACCESS_ENABLE U(0) #define DMA_CH_TZ_ACCESS_DISABLE U(3) #define MAX_TRANSFER_SIZE (1U*1024U*1024U*1024U) /* 1GB */ #define GPCDMA_TIMEOUT_MS U(100) #define GPCDMA_RESET_BIT (U(1) << 1) static bool init_done; static void tegra_gpcdma_write32(uint32_t offset, uint32_t val) { mmio_write_32(TEGRA_GPCDMA_BASE + offset, val); } static uint32_t tegra_gpcdma_read32(uint32_t offset) { return mmio_read_32(TEGRA_GPCDMA_BASE + offset); } static void tegra_gpcdma_init(void) { /* assert reset for DMA engine */ mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPCDMA_RST_SET_REG_OFFSET, GPCDMA_RESET_BIT); udelay(2); /* de-assert reset for DMA engine */ mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPCDMA_RST_CLR_REG_OFFSET, GPCDMA_RESET_BIT); } static void tegra_gpcdma_memcpy_priv(uint64_t dst_addr, uint64_t src_addr, uint32_t num_bytes, uint32_t mode) { uint32_t val, timeout = 0; int32_t ret = 0; /* sanity check byte count */ if ((num_bytes > MAX_TRANSFER_SIZE) || ((num_bytes & 0x3U) != U(0))) { ret = -EINVAL; } /* initialise GPCDMA block */ if (!init_done) { tegra_gpcdma_init(); init_done = true; } /* make sure channel isn't busy */ val = tegra_gpcdma_read32(DMA_CH_STAT); if ((val & DMA_CH_STAT_BUSY) == DMA_CH_STAT_BUSY) { ERROR("DMA channel is busy\n"); ret = -EBUSY; } if (ret == 0) { /* disable any DMA transfers */ tegra_gpcdma_write32(DMA_CH_CSR, 0); /* enable DMA access to TZDRAM */ tegra_gpcdma_write32(DMA_CH_TZ, DMA_CH_TZ_ACCESS_ENABLE); /* configure MC sequencer */ val = (DMA_CH_MC_SEQ_REQ_CNT_VAL << DMA_CH_MC_SEQ_REQ_CNT_SHIFT) | (DMA_CH_MC_SEQ_BURST_16_WORDS << DMA_CH_MC_SEQ_BURST_SHIFT); tegra_gpcdma_write32(DMA_CH_MC_SEQ, val); /* reset fixed pattern */ tegra_gpcdma_write32(DMA_CH_FIXED_PATTERN, 0); /* populate src and dst address registers */ tegra_gpcdma_write32(DMA_CH_SRC_PTR, (uint32_t)src_addr); tegra_gpcdma_write32(DMA_CH_DST_PTR, (uint32_t)dst_addr); val = (uint32_t)((src_addr >> 32) & DMA_CH_HI_ADR_PTR_SRC_MASK); val |= (uint32_t)(((dst_addr >> 32) & DMA_CH_HI_ADR_PTR_DST_MASK) << DMA_CH_HI_ADR_PTR_DST_SHIFT); tegra_gpcdma_write32(DMA_CH_HI_ADR_PTR, val); /* transfer size (in words) */ tegra_gpcdma_write32(DMA_CH_WORD_COUNT, ((num_bytes >> 2) - 1U)); /* populate value for CSR */ val = (mode << DMA_CH_CSR_XFER_MODE_SHIFT) | DMA_CH_CSR_RUN_ONCE | (U(1) << DMA_CH_CSR_WEIGHT_SHIFT) | DMA_CH_CSR_IRQ_MASK_ENABLE; tegra_gpcdma_write32(DMA_CH_CSR, val); /* enable transfer */ val = tegra_gpcdma_read32(DMA_CH_CSR); val |= DMA_CH_CSR_ENABLE; tegra_gpcdma_write32(DMA_CH_CSR, val); /* wait till transfer completes */ do { /* read the status */ val = tegra_gpcdma_read32(DMA_CH_STAT); if ((val & DMA_CH_STAT_BUSY) != DMA_CH_STAT_BUSY) { break; } mdelay(1); timeout++; } while (timeout < GPCDMA_TIMEOUT_MS); /* flag timeout error */ if (timeout == GPCDMA_TIMEOUT_MS) { ERROR("DMA transfer timed out\n"); } dsbsy(); /* disable DMA access to TZDRAM */ tegra_gpcdma_write32(DMA_CH_TZ, DMA_CH_TZ_ACCESS_DISABLE); isb(); } } /******************************************************************************* * Memcpy using GPCDMA block (Mem2Mem copy) ******************************************************************************/ void tegra_gpcdma_memcpy(uint64_t dst_addr, uint64_t src_addr, uint32_t num_bytes) { tegra_gpcdma_memcpy_priv(dst_addr, src_addr, num_bytes, DMA_CH_CSR_DMA_MODE_MEM2MEM); } /******************************************************************************* * Memset using GPCDMA block (Fixed pattern write) ******************************************************************************/ void tegra_gpcdma_zeromem(uint64_t dst_addr, uint32_t num_bytes) { tegra_gpcdma_memcpy_priv(dst_addr, 0, num_bytes, DMA_CH_CSR_DMA_MODE_FIXEDPATTERN); } trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/memctrl/000077500000000000000000000000001355360272700250365ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v1.c000066400000000000000000000153561355360272700272650ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include /* Video Memory base and size (live values) */ static uint64_t video_mem_base; static uint64_t video_mem_size; /* * Init SMMU. */ void tegra_memctrl_setup(void) { /* * Setup the Memory controller to allow only secure accesses to * the TZDRAM carveout */ INFO("Tegra Memory Controller (v1)\n"); /* allow translations for all MC engines */ tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_0_0, (unsigned int)MC_SMMU_TRANSLATION_ENABLE); tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_1_0, (unsigned int)MC_SMMU_TRANSLATION_ENABLE); tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_2_0, (unsigned int)MC_SMMU_TRANSLATION_ENABLE); tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_3_0, (unsigned int)MC_SMMU_TRANSLATION_ENABLE); tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_4_0, (unsigned int)MC_SMMU_TRANSLATION_ENABLE); tegra_mc_write_32(MC_SMMU_ASID_SECURITY_0, MC_SMMU_ASID_SECURITY); tegra_mc_write_32(MC_SMMU_TLB_CONFIG_0, MC_SMMU_TLB_CONFIG_0_RESET_VAL); tegra_mc_write_32(MC_SMMU_PTC_CONFIG_0, MC_SMMU_PTC_CONFIG_0_RESET_VAL); /* flush PTC and TLB */ tegra_mc_write_32(MC_SMMU_PTC_FLUSH_0, MC_SMMU_PTC_FLUSH_ALL); (void)tegra_mc_read_32(MC_SMMU_CONFIG_0); /* read to flush writes */ tegra_mc_write_32(MC_SMMU_TLB_FLUSH_0, MC_SMMU_TLB_FLUSH_ALL); /* enable SMMU */ tegra_mc_write_32(MC_SMMU_CONFIG_0, MC_SMMU_CONFIG_0_SMMU_ENABLE_ENABLE); (void)tegra_mc_read_32(MC_SMMU_CONFIG_0); /* read to flush writes */ /* video memory carveout */ tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI, (uint32_t)(video_mem_base >> 32)); tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO, (uint32_t)video_mem_base); tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, video_mem_size); } /* * Restore Memory Controller settings after "System Suspend" */ void tegra_memctrl_restore_settings(void) { tegra_memctrl_setup(); } /* * Secure the BL31 DRAM aperture. * * phys_base = physical base of TZDRAM aperture * size_in_bytes = size of aperture in bytes */ void tegra_memctrl_tzdram_setup(uint64_t phys_base, uint32_t size_in_bytes) { /* * Setup the Memory controller to allow only secure accesses to * the TZDRAM carveout */ INFO("Configuring TrustZone DRAM Memory Carveout\n"); tegra_mc_write_32(MC_SECURITY_CFG0_0, phys_base); tegra_mc_write_32(MC_SECURITY_CFG1_0, size_in_bytes >> 20); } /* * Secure the BL31 TZRAM aperture. * * phys_base = physical base of TZRAM aperture * size_in_bytes = size of aperture in bytes */ void tegra_memctrl_tzram_setup(uint64_t phys_base, uint32_t size_in_bytes) { /* * The v1 hardware controller does not have any registers * for setting up the on-chip TZRAM. */ } static void tegra_clear_videomem(uintptr_t non_overlap_area_start, unsigned long long non_overlap_area_size) { int ret; /* * Map the NS memory first, clean it and then unmap it. */ ret = mmap_add_dynamic_region(non_overlap_area_start, /* PA */ non_overlap_area_start, /* VA */ non_overlap_area_size, /* size */ MT_NS | MT_RW | MT_EXECUTE_NEVER); /* attrs */ assert(ret == 0); zeromem((void *)non_overlap_area_start, non_overlap_area_size); flush_dcache_range(non_overlap_area_start, non_overlap_area_size); mmap_remove_dynamic_region(non_overlap_area_start, non_overlap_area_size); } /* * Program the Video Memory carveout region * * phys_base = physical base of aperture * size_in_bytes = size of aperture in bytes */ void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes) { uintptr_t vmem_end_old = video_mem_base + (video_mem_size << 20); uintptr_t vmem_end_new = phys_base + size_in_bytes; unsigned long long non_overlap_area_size; /* * Setup the Memory controller to restrict CPU accesses to the Video * Memory region */ INFO("Configuring Video Memory Carveout\n"); /* * Configure Memory Controller directly for the first time. */ if (video_mem_base == 0) goto done; /* * Clear the old regions now being exposed. The following cases * can occur - * * 1. clear whole old region (no overlap with new region) * 2. clear old sub-region below new base * 3. clear old sub-region above new end */ INFO("Cleaning previous Video Memory Carveout\n"); if (phys_base > vmem_end_old || video_mem_base > vmem_end_new) { tegra_clear_videomem(video_mem_base, video_mem_size << 20); } else { if (video_mem_base < phys_base) { non_overlap_area_size = phys_base - video_mem_base; tegra_clear_videomem(video_mem_base, non_overlap_area_size); } if (vmem_end_old > vmem_end_new) { non_overlap_area_size = vmem_end_old - vmem_end_new; tegra_clear_videomem(vmem_end_new, non_overlap_area_size); } } done: tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI, (uint32_t)(phys_base >> 32)); tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO, (uint32_t)phys_base); tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, size_in_bytes >> 20); /* store new values */ video_mem_base = phys_base; video_mem_size = size_in_bytes >> 20; } /* * During boot, USB3 and flash media (SDMMC/SATA) devices need access to * IRAM. Because these clients connect to the MC and do not have a direct * path to the IRAM, the MC implements AHB redirection during boot to allow * path to IRAM. In this mode, accesses to a programmed memory address aperture * are directed to the AHB bus, allowing access to the IRAM. The AHB aperture * is defined by the IRAM_BASE_LO and IRAM_BASE_HI registers, which are * initialized to disable this aperture. * * Once bootup is complete, we must program IRAM base to 0xffffffff and * IRAM top to 0x00000000, thus disabling access to IRAM. DRAM is then * potentially accessible in this address range. These aperture registers * also have an access_control/lock bit. After disabling the aperture, the * access_control register should be programmed to lock the registers. */ void tegra_memctrl_disable_ahb_redirection(void) { /* program the aperture registers */ tegra_mc_write_32(MC_IRAM_BASE_LO, 0xFFFFFFFF); tegra_mc_write_32(MC_IRAM_TOP_LO, 0); tegra_mc_write_32(MC_IRAM_BASE_TOP_HI, 0); /* lock the aperture registers */ tegra_mc_write_32(MC_IRAM_REG_CTRL, MC_DISABLE_IRAM_CFG_WRITES); } void tegra_memctrl_clear_pending_interrupts(void) { uint32_t mcerr; /* check if there are any pending interrupts */ mcerr = mmio_read_32(TEGRA_MC_BASE + MC_INTSTATUS); if (mcerr != (uint32_t)0U) { /* should not see error here */ WARN("MC_INTSTATUS = 0x%x (should be zero)\n", mcerr); mmio_write_32((TEGRA_MC_BASE + MC_INTSTATUS), mcerr); } } trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/memctrl/memctrl_v2.c000066400000000000000000000272571355360272700272710ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2019, NVIDIA Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* Video Memory base and size (live values) */ static uint64_t video_mem_base; static uint64_t video_mem_size_mb; /* * The following platform setup functions are weakly defined. They * provide typical implementations that will be overridden by a SoC. */ #pragma weak plat_memctrl_tzdram_setup void plat_memctrl_tzdram_setup(uint64_t phys_base, uint64_t size_in_bytes) { ; /* do nothing */ } /* * Init Memory controller during boot. */ void tegra_memctrl_setup(void) { uint32_t val; const uint32_t *mc_streamid_override_regs; uint32_t num_streamid_override_regs; const mc_streamid_security_cfg_t *mc_streamid_sec_cfgs; uint32_t num_streamid_sec_cfgs; const tegra_mc_settings_t *plat_mc_settings = tegra_get_mc_settings(); uint32_t i; INFO("Tegra Memory Controller (v2)\n"); /* Program the SMMU pagesize */ tegra_smmu_init(); /* Get the settings from the platform */ assert(plat_mc_settings != NULL); mc_streamid_override_regs = plat_mc_settings->streamid_override_cfg; num_streamid_override_regs = plat_mc_settings->num_streamid_override_cfgs; mc_streamid_sec_cfgs = plat_mc_settings->streamid_security_cfg; num_streamid_sec_cfgs = plat_mc_settings->num_streamid_security_cfgs; /* Program all the Stream ID overrides */ for (i = 0; i < num_streamid_override_regs; i++) tegra_mc_streamid_write_32(mc_streamid_override_regs[i], MC_STREAM_ID_MAX); /* Program the security config settings for all Stream IDs */ for (i = 0; i < num_streamid_sec_cfgs; i++) { val = mc_streamid_sec_cfgs[i].override_enable << 16 | mc_streamid_sec_cfgs[i].override_client_inputs << 8 | mc_streamid_sec_cfgs[i].override_client_ns_flag << 0; tegra_mc_streamid_write_32(mc_streamid_sec_cfgs[i].offset, val); } /* * All requests at boot time, and certain requests during * normal run time, are physically addressed and must bypass * the SMMU. The client hub logic implements a hardware bypass * path around the Translation Buffer Units (TBU). During * boot-time, the SMMU_BYPASS_CTRL register (which defaults to * TBU_BYPASS mode) will be used to steer all requests around * the uninitialized TBUs. During normal operation, this register * is locked into TBU_BYPASS_SID config, which routes requests * with special StreamID 0x7f on the bypass path and all others * through the selected TBU. This is done to disable SMMU Bypass * mode, as it could be used to circumvent SMMU security checks. */ tegra_mc_write_32(MC_SMMU_BYPASS_CONFIG, MC_SMMU_BYPASS_CONFIG_SETTINGS); /* * Re-configure MSS to allow ROC to deal with ordering of the * Memory Controller traffic. This is needed as the Memory Controller * boots with MSS having all control, but ROC provides a performance * boost as compared to MSS. */ if (plat_mc_settings->reconfig_mss_clients != NULL) { plat_mc_settings->reconfig_mss_clients(); } /* Program overrides for MC transactions */ if (plat_mc_settings->set_txn_overrides != NULL) { plat_mc_settings->set_txn_overrides(); } } /* * Restore Memory Controller settings after "System Suspend" */ void tegra_memctrl_restore_settings(void) { const tegra_mc_settings_t *plat_mc_settings = tegra_get_mc_settings(); assert(plat_mc_settings != NULL); /* * Re-configure MSS to allow ROC to deal with ordering of the * Memory Controller traffic. This is needed as the Memory Controller * resets during System Suspend with MSS having all control, but ROC * provides a performance boost as compared to MSS. */ if (plat_mc_settings->reconfig_mss_clients != NULL) { plat_mc_settings->reconfig_mss_clients(); } /* Program overrides for MC transactions */ if (plat_mc_settings->set_txn_overrides != NULL) { plat_mc_settings->set_txn_overrides(); } /* video memory carveout region */ if (video_mem_base != 0ULL) { tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO, (uint32_t)video_mem_base); tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI, (uint32_t)(video_mem_base >> 32)); tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, video_mem_size_mb); /* * MCE propagates the VideoMem configuration values across the * CCPLEX. */ mce_update_gsc_videomem(); } } /* * Secure the BL31 DRAM aperture. * * phys_base = physical base of TZDRAM aperture * size_in_bytes = size of aperture in bytes */ void tegra_memctrl_tzdram_setup(uint64_t phys_base, uint32_t size_in_bytes) { /* * Perform platform specific steps. */ plat_memctrl_tzdram_setup(phys_base, size_in_bytes); } /* * Secure the BL31 TZRAM aperture. * * phys_base = physical base of TZRAM aperture * size_in_bytes = size of aperture in bytes */ void tegra_memctrl_tzram_setup(uint64_t phys_base, uint32_t size_in_bytes) { uint32_t index; uint32_t total_128kb_blocks = size_in_bytes >> 17; uint32_t residual_4kb_blocks = (size_in_bytes & (uint32_t)0x1FFFF) >> 12; uint32_t val; INFO("Configuring TrustZone SRAM Memory Carveout\n"); /* * Reset the access configuration registers to restrict access * to the TZRAM aperture */ for (index = MC_TZRAM_CLIENT_ACCESS0_CFG0; index < ((uint32_t)MC_TZRAM_CARVEOUT_CFG + (uint32_t)MC_GSC_CONFIG_REGS_SIZE); index += 4U) { tegra_mc_write_32(index, 0); } /* * Enable CPU access configuration registers to access the TZRAM aperture */ if (!tegra_chipid_is_t186()) { val = tegra_mc_read_32(MC_TZRAM_CLIENT_ACCESS1_CFG0); val |= TZRAM_ALLOW_MPCORER | TZRAM_ALLOW_MPCOREW; tegra_mc_write_32(MC_TZRAM_CLIENT_ACCESS1_CFG0, val); } /* * Set the TZRAM base. TZRAM base must be 4k aligned, at least. */ assert((phys_base & (uint64_t)0xFFF) == 0U); tegra_mc_write_32(MC_TZRAM_BASE_LO, (uint32_t)phys_base); tegra_mc_write_32(MC_TZRAM_BASE_HI, (uint32_t)(phys_base >> 32) & MC_GSC_BASE_HI_MASK); /* * Set the TZRAM size * * total size = (number of 128KB blocks) + (number of remaining 4KB * blocks) * */ val = (residual_4kb_blocks << MC_GSC_SIZE_RANGE_4KB_SHIFT) | total_128kb_blocks; tegra_mc_write_32(MC_TZRAM_SIZE, val); /* * Lock the configuration settings by disabling TZ-only lock * and locking the configuration against any future changes * at all. */ val = tegra_mc_read_32(MC_TZRAM_CARVEOUT_CFG); val &= (uint32_t)~MC_GSC_ENABLE_TZ_LOCK_BIT; val |= MC_GSC_LOCK_CFG_SETTINGS_BIT; if (!tegra_chipid_is_t186()) { val |= MC_GSC_ENABLE_CPU_SECURE_BIT; } tegra_mc_write_32(MC_TZRAM_CARVEOUT_CFG, val); /* * MCE propagates the security configuration values across the * CCPLEX. */ mce_update_gsc_tzram(); } static void tegra_lock_videomem_nonoverlap(uint64_t phys_base, uint64_t size_in_bytes) { uint32_t index; uint64_t total_128kb_blocks = size_in_bytes >> 17; uint64_t residual_4kb_blocks = (size_in_bytes & (uint32_t)0x1FFFF) >> 12; uint64_t val; /* * Reset the access configuration registers to restrict access to * old Videomem aperture */ for (index = MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0; index < ((uint32_t)MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0 + (uint32_t)MC_GSC_CONFIG_REGS_SIZE); index += 4U) { tegra_mc_write_32(index, 0); } /* * Set the base. It must be 4k aligned, at least. */ assert((phys_base & (uint64_t)0xFFF) == 0U); tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_LO, (uint32_t)phys_base); tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_HI, (uint32_t)(phys_base >> 32) & (uint32_t)MC_GSC_BASE_HI_MASK); /* * Set the aperture size * * total size = (number of 128KB blocks) + (number of remaining 4KB * blocks) * */ val = (uint32_t)((residual_4kb_blocks << MC_GSC_SIZE_RANGE_4KB_SHIFT) | total_128kb_blocks); tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_SIZE, (uint32_t)val); /* * Lock the configuration settings by enabling TZ-only lock and * locking the configuration against any future changes from NS * world. */ tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_CFG, (uint32_t)MC_GSC_ENABLE_TZ_LOCK_BIT); /* * MCE propagates the GSC configuration values across the * CCPLEX. */ } static void tegra_unlock_videomem_nonoverlap(void) { /* Clear the base */ tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_LO, 0); tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_HI, 0); /* Clear the size */ tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_SIZE, 0); } static void tegra_clear_videomem(uintptr_t non_overlap_area_start, unsigned long long non_overlap_area_size) { int ret; /* * Map the NS memory first, clean it and then unmap it. */ ret = mmap_add_dynamic_region(non_overlap_area_start, /* PA */ non_overlap_area_start, /* VA */ non_overlap_area_size, /* size */ MT_NS | MT_RW | MT_EXECUTE_NEVER); /* attrs */ assert(ret == 0); zero_normalmem((void *)non_overlap_area_start, non_overlap_area_size); flush_dcache_range(non_overlap_area_start, non_overlap_area_size); (void)mmap_remove_dynamic_region(non_overlap_area_start, non_overlap_area_size); } /* * Program the Video Memory carveout region * * phys_base = physical base of aperture * size_in_bytes = size of aperture in bytes */ void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes) { uintptr_t vmem_end_old = video_mem_base + (video_mem_size_mb << 20); uintptr_t vmem_end_new = phys_base + size_in_bytes; unsigned long long non_overlap_area_size; /* * Setup the Memory controller to restrict CPU accesses to the Video * Memory region */ INFO("Configuring Video Memory Carveout\n"); /* * Configure Memory Controller directly for the first time. */ if (video_mem_base == 0U) goto done; /* * Lock the non overlapping memory being cleared so that other masters * do not accidently write to it. The memory would be unlocked once * the non overlapping region is cleared and the new memory * settings take effect. */ tegra_lock_videomem_nonoverlap(video_mem_base, video_mem_size_mb << 20); /* * Clear the old regions now being exposed. The following cases * can occur - * * 1. clear whole old region (no overlap with new region) * 2. clear old sub-region below new base * 3. clear old sub-region above new end */ INFO("Cleaning previous Video Memory Carveout\n"); if ((phys_base > vmem_end_old) || (video_mem_base > vmem_end_new)) { tegra_clear_videomem(video_mem_base, video_mem_size_mb << 20U); } else { if (video_mem_base < phys_base) { non_overlap_area_size = phys_base - video_mem_base; tegra_clear_videomem(video_mem_base, non_overlap_area_size); } if (vmem_end_old > vmem_end_new) { non_overlap_area_size = vmem_end_old - vmem_end_new; tegra_clear_videomem(vmem_end_new, non_overlap_area_size); } } done: /* program the Videomem aperture */ tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO, (uint32_t)phys_base); tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI, (uint32_t)(phys_base >> 32)); tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, size_in_bytes >> 20); /* unlock the previous locked nonoverlapping aperture */ tegra_unlock_videomem_nonoverlap(); /* store new values */ video_mem_base = phys_base; video_mem_size_mb = size_in_bytes >> 20; /* * MCE propagates the VideoMem configuration values across the * CCPLEX. */ mce_update_gsc_videomem(); } /* * This feature exists only for v1 of the Tegra Memory Controller. */ void tegra_memctrl_disable_ahb_redirection(void) { ; /* do nothing */ } void tegra_memctrl_clear_pending_interrupts(void) { ; /* do nothing */ } trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/pmc/000077500000000000000000000000001355360272700241525ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/pmc/pmc.c000066400000000000000000000104731355360272700251020ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #define RESET_ENABLE 0x10U /* Module IDs used during power ungate procedure */ static const uint32_t pmc_cpu_powergate_id[4] = { 14, /* CPU 0 */ 9, /* CPU 1 */ 10, /* CPU 2 */ 11 /* CPU 3 */ }; /******************************************************************************* * Power ungate CPU to start the boot process. CPU reset vectors must be * populated before calling this function. ******************************************************************************/ void tegra_pmc_cpu_on(int32_t cpu) { uint32_t val; /* * Check if CPU is already power ungated */ val = tegra_pmc_read_32(PMC_PWRGATE_STATUS); if ((val & (1U << pmc_cpu_powergate_id[cpu])) == 0U) { /* * The PMC deasserts the START bit when it starts the power * ungate process. Loop till no power toggle is in progress. */ do { val = tegra_pmc_read_32(PMC_PWRGATE_TOGGLE); } while ((val & PMC_TOGGLE_START) != 0U); /* * Start the power ungate procedure */ val = pmc_cpu_powergate_id[cpu] | PMC_TOGGLE_START; tegra_pmc_write_32(PMC_PWRGATE_TOGGLE, val); /* * The PMC deasserts the START bit when it starts the power * ungate process. Loop till powergate START bit is asserted. */ do { val = tegra_pmc_read_32(PMC_PWRGATE_TOGGLE); } while ((val & (1U << 8)) != 0U); /* loop till the CPU is power ungated */ do { val = tegra_pmc_read_32(PMC_PWRGATE_STATUS); } while ((val & (1U << pmc_cpu_powergate_id[cpu])) == 0U); } } /******************************************************************************* * Setup CPU vectors for resume from deep sleep ******************************************************************************/ void tegra_pmc_cpu_setup(uint64_t reset_addr) { uint32_t val; tegra_pmc_write_32(PMC_SECURE_SCRATCH34, ((uint32_t)reset_addr & 0xFFFFFFFFU) | 1U); val = (uint32_t)(reset_addr >> 32U); tegra_pmc_write_32(PMC_SECURE_SCRATCH35, val & 0x7FFU); } /******************************************************************************* * Lock CPU vectors to restrict further writes ******************************************************************************/ void tegra_pmc_lock_cpu_vectors(void) { uint32_t val; /* lock PMC_SECURE_SCRATCH22 */ val = tegra_pmc_read_32(PMC_SECURE_DISABLE2); val |= PMC_SECURE_DISABLE2_WRITE22_ON; tegra_pmc_write_32(PMC_SECURE_DISABLE2, val); /* lock PMC_SECURE_SCRATCH34/35 */ val = tegra_pmc_read_32(PMC_SECURE_DISABLE3); val |= (PMC_SECURE_DISABLE3_WRITE34_ON | PMC_SECURE_DISABLE3_WRITE35_ON); tegra_pmc_write_32(PMC_SECURE_DISABLE3, val); } /******************************************************************************* * Find out if this is the last standing CPU ******************************************************************************/ bool tegra_pmc_is_last_on_cpu(void) { int i, cpu = read_mpidr() & MPIDR_CPU_MASK; uint32_t val = tegra_pmc_read_32(PMC_PWRGATE_STATUS);; bool status = true; /* check if this is the last standing CPU */ for (i = 0; i < PLATFORM_MAX_CPUS_PER_CLUSTER; i++) { /* skip the current CPU */ if (i == cpu) continue; /* are other CPUs already power gated? */ if ((val & ((uint32_t)1 << pmc_cpu_powergate_id[i])) != 0U) { status = false; } } return status; } /******************************************************************************* * Handler to be called on exiting System suspend. Right now only DPD registers * are cleared. ******************************************************************************/ void tegra_pmc_resume(void) { /* Clear DPD sample */ mmio_write_32((TEGRA_PMC_BASE + PMC_IO_DPD_SAMPLE), 0x0); /* Clear DPD Enable */ mmio_write_32((TEGRA_PMC_BASE + PMC_DPD_ENABLE_0), 0x0); } /******************************************************************************* * Restart the system ******************************************************************************/ __dead2 void tegra_pmc_system_reset(void) { uint32_t reg; reg = tegra_pmc_read_32(PMC_CONFIG); reg |= RESET_ENABLE; /* restart */ tegra_pmc_write_32(PMC_CONFIG, reg); wfi(); ERROR("Tegra System Reset: operation not handled.\n"); panic(); } trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/smmu/000077500000000000000000000000001355360272700243545ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/smmu/smmu.c000066400000000000000000000115651355360272700255110ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include extern void memcpy16(void *dest, const void *src, unsigned int length); /* SMMU IDs currently supported by the driver */ enum { TEGRA_SMMU0 = 0U, TEGRA_SMMU1, TEGRA_SMMU2 }; static uint32_t tegra_smmu_read_32(uint32_t smmu_id, uint32_t off) { uint32_t ret = 0U; #if defined(TEGRA_SMMU0_BASE) if (smmu_id == TEGRA_SMMU0) { ret = mmio_read_32(TEGRA_SMMU0_BASE + (uint64_t)off); } #endif #if defined(TEGRA_SMMU1_BASE) if (smmu_id == TEGRA_SMMU1) { ret = mmio_read_32(TEGRA_SMMU1_BASE + (uint64_t)off); } #endif #if defined(TEGRA_SMMU2_BASE) if (smmu_id == TEGRA_SMMU2) { ret = mmio_read_32(TEGRA_SMMU2_BASE + (uint64_t)off); } #endif return ret; } static void tegra_smmu_write_32(uint32_t smmu_id, uint32_t off, uint32_t val) { #if defined(TEGRA_SMMU0_BASE) if (smmu_id == TEGRA_SMMU0) { mmio_write_32(TEGRA_SMMU0_BASE + (uint64_t)off, val); } #endif #if defined(TEGRA_SMMU1_BASE) if (smmu_id == TEGRA_SMMU1) { mmio_write_32(TEGRA_SMMU1_BASE + (uint64_t)off, val); } #endif #if defined(TEGRA_SMMU2_BASE) if (smmu_id == TEGRA_SMMU2) { mmio_write_32(TEGRA_SMMU2_BASE + (uint64_t)off, val); } #endif } /* * Save SMMU settings before "System Suspend" to TZDRAM */ void tegra_smmu_save_context(uint64_t smmu_ctx_addr) { uint32_t i, num_entries = 0; smmu_regs_t *smmu_ctx_regs; const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); uint64_t tzdram_base = params_from_bl2->tzdram_base; uint64_t tzdram_end = tzdram_base + params_from_bl2->tzdram_size; uint32_t reg_id1, pgshift, cb_size; /* sanity check SMMU settings c*/ reg_id1 = mmio_read_32((TEGRA_SMMU0_BASE + SMMU_GNSR0_IDR1)); pgshift = ((reg_id1 & ID1_PAGESIZE) != 0U) ? 16U : 12U; cb_size = ((uint32_t)2 << pgshift) * \ ((uint32_t)1 << (((reg_id1 >> ID1_NUMPAGENDXB_SHIFT) & ID1_NUMPAGENDXB_MASK) + 1U)); assert(!((pgshift != PGSHIFT) || (cb_size != CB_SIZE))); assert((smmu_ctx_addr >= tzdram_base) && (smmu_ctx_addr <= tzdram_end)); /* get SMMU context table */ smmu_ctx_regs = plat_get_smmu_ctx(); assert(smmu_ctx_regs != NULL); /* * smmu_ctx_regs[0].val contains the size of the context table minus * the last entry. Sanity check the table size before we start with * the context save operation. */ while ((smmu_ctx_regs[num_entries].reg != 0xFFFFFFFFU)) { num_entries++; } /* panic if the sizes do not match */ if (num_entries != smmu_ctx_regs[0].val) { ERROR("SMMU context size mismatch!"); panic(); } /* save SMMU register values */ for (i = 1U; i < num_entries; i++) { smmu_ctx_regs[i].val = mmio_read_32(smmu_ctx_regs[i].reg); } /* increment by 1 to take care of the last entry */ num_entries++; /* Save SMMU config settings */ (void)memcpy16((uint8_t *)smmu_ctx_addr, (uint8_t *)smmu_ctx_regs, (sizeof(smmu_regs_t) * num_entries)); /* save the SMMU table address */ mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SMMU_TABLE_ADDR_LO, (uint32_t)smmu_ctx_addr); mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SMMU_TABLE_ADDR_HI, (uint32_t)(smmu_ctx_addr >> 32)); } #define SMMU_NUM_CONTEXTS 64 #define SMMU_CONTEXT_BANK_MAX_IDX 64 /* * Init SMMU during boot or "System Suspend" exit */ void tegra_smmu_init(void) { uint32_t val, cb_idx, smmu_id, ctx_base; uint32_t smmu_counter = plat_get_num_smmu_devices(); for (smmu_id = 0U; smmu_id < smmu_counter; smmu_id++) { /* Program the SMMU pagesize and reset CACHE_LOCK bit */ val = tegra_smmu_read_32(smmu_id, SMMU_GSR0_SECURE_ACR); val |= SMMU_GSR0_PGSIZE_64K; val &= (uint32_t)~SMMU_ACR_CACHE_LOCK_ENABLE_BIT; tegra_smmu_write_32(smmu_id, SMMU_GSR0_SECURE_ACR, val); /* reset CACHE LOCK bit for NS Aux. Config. Register */ val = tegra_smmu_read_32(smmu_id, SMMU_GNSR_ACR); val &= (uint32_t)~SMMU_ACR_CACHE_LOCK_ENABLE_BIT; tegra_smmu_write_32(smmu_id, SMMU_GNSR_ACR, val); /* disable TCU prefetch for all contexts */ ctx_base = (SMMU_GSR0_PGSIZE_64K * SMMU_NUM_CONTEXTS) + SMMU_CBn_ACTLR; for (cb_idx = 0; cb_idx < SMMU_CONTEXT_BANK_MAX_IDX; cb_idx++) { val = tegra_smmu_read_32(smmu_id, ctx_base + (SMMU_GSR0_PGSIZE_64K * cb_idx)); val &= (uint32_t)~SMMU_CBn_ACTLR_CPRE_BIT; tegra_smmu_write_32(smmu_id, ctx_base + (SMMU_GSR0_PGSIZE_64K * cb_idx), val); } /* set CACHE LOCK bit for NS Aux. Config. Register */ val = tegra_smmu_read_32(smmu_id, SMMU_GNSR_ACR); val |= (uint32_t)SMMU_ACR_CACHE_LOCK_ENABLE_BIT; tegra_smmu_write_32(smmu_id, SMMU_GNSR_ACR, val); /* set CACHE LOCK bit for S Aux. Config. Register */ val = tegra_smmu_read_32(smmu_id, SMMU_GSR0_SECURE_ACR); val |= (uint32_t)SMMU_ACR_CACHE_LOCK_ENABLE_BIT; tegra_smmu_write_32(smmu_id, SMMU_GSR0_SECURE_ACR, val); } } trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/spe/000077500000000000000000000000001355360272700241625ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/common/drivers/spe/shared_console.S000066400000000000000000000115061355360272700273010ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #define CONSOLE_NUM_BYTES_SHIFT 24 #define CONSOLE_FLUSH_DATA_TO_PORT (1 << 26) #define CONSOLE_RING_DOORBELL (1 << 31) #define CONSOLE_IS_BUSY (1 << 31) #define CONSOLE_WRITE (CONSOLE_RING_DOORBELL | CONSOLE_FLUSH_DATA_TO_PORT) /* * This file contains a driver implementation to make use of the * real console implementation provided by the SPE firmware running * SoCs after Tegra186. * * This console is shared by multiple components and the SPE firmware * finally displays everything on the UART port. */ .globl console_spe_core_init .globl console_spe_core_putc .globl console_spe_core_getc .globl console_spe_core_flush .globl console_spe_putc .globl console_spe_getc .globl console_spe_flush .globl console_spe_register /* ------------------------------------------------- * int console_spe_register(uintptr_t baseaddr, * uint32_t clock, uint32_t baud, * console_spe_t *console); * Function to initialize and register a new spe * console. Storage passed in for the console struct * *must* be persistent (i.e. not from the stack). * In: x0 - UART register base address * w1 - UART clock in Hz * w2 - Baud rate * x3 - pointer to empty console_spe_t struct * Out: return 1 on success, 0 on error * Clobber list : x0, x1, x2, x6, x7, x14 * ------------------------------------------------- */ func console_spe_register cbz x3, register_fail str x0, [x3, #CONSOLE_T_DRVDATA] mov x0, x3 finish_console_register spe putc=1, getc=1, flush=1 register_fail: mov w0, wzr ret endfunc console_spe_register /* -------------------------------------------------------- * int console_spe_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. * In : w0 - character to be printed * x1 - console base address * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_spe_core_putc /* Check the input parameter */ cbz x1, putc_error /* Prepend '\r' to '\n' */ cmp w0, #0xA b.ne 2f /* wait until spe is ready */ 1: ldr w2, [x1] and w2, w2, #CONSOLE_IS_BUSY cbnz w2, 1b /* spe is ready */ mov w2, #0xD /* '\r' */ and w2, w2, #0xFF mov w3, #(CONSOLE_WRITE | (1 << CONSOLE_NUM_BYTES_SHIFT)) orr w2, w2, w3 str w2, [x1] /* wait until spe is ready */ 2: ldr w2, [x1] and w2, w2, #CONSOLE_IS_BUSY cbnz w2, 2b /* spe is ready */ mov w2, w0 and w2, w2, #0xFF mov w3, #(CONSOLE_WRITE | (1 << CONSOLE_NUM_BYTES_SHIFT)) orr w2, w2, w3 str w2, [x1] ret putc_error: mov w0, #-1 ret endfunc console_spe_core_putc /* -------------------------------------------------------- * int console_spe_putc(int c, console_spe_t *console) * Function to output a character over the console. It * returns the character printed on success or -1 on error. * In : w0 - character to be printed * x1 - pointer to console_t structure * Out : return -1 on error else return character. * Clobber list : x2 * -------------------------------------------------------- */ func console_spe_putc ldr x1, [x1, #CONSOLE_T_DRVDATA] b console_spe_core_putc endfunc console_spe_putc /* --------------------------------------------- * int console_spe_getc(console_spe_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 : x0 - pointer to console_t structure * Out: w0 - character if available, else -1 * Clobber list : x0, x1 * --------------------------------------------- */ func console_spe_getc mov w0, #-1 ret endfunc console_spe_getc /* ------------------------------------------------- * int console_spe_core_flush(uintptr_t base_addr) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - console base address * Out : return -1 on error else return 0. * Clobber list : x0, x1 * ------------------------------------------------- */ func console_spe_core_flush cbz x0, flush_error /* flush console */ mov w1, #CONSOLE_WRITE str w1, [x0] mov w0, #0 ret flush_error: mov w0, #-1 ret endfunc console_spe_core_flush /* --------------------------------------------- * int console_spe_flush(console_spe_t *console) * Function to force a write of all buffered * data that hasn't been output. * In : x0 - pointer to console_t structure * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func console_spe_flush ldr x0, [x0, #CONSOLE_T_DRVDATA] b console_spe_core_flush endfunc console_spe_flush trusted-firmware-a-2.2/plat/nvidia/tegra/common/lib/000077500000000000000000000000001355360272700224635ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/common/lib/debug/000077500000000000000000000000001355360272700235515ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/common/lib/debug/profiler.c000066400000000000000000000077631355360272700255540ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /******************************************************************************* * The profiler stores the timestamps captured during cold boot to the shared * memory for the non-secure world. The non-secure world driver parses the * shared memory block and writes the contents to a file on the device, which * can be later extracted for analysis. * * Profiler memory map * * TOP --------------------------- --- * Trusted OS timestamps 3KB * --------------------------- --- * Trusted Firmware timestamps 1KB * BASE --------------------------- --- * ******************************************************************************/ #include #include #include #include #include #include #include #include #include static uint64_t shmem_base_addr; #define MAX_PROFILER_RECORDS U(16) #define TAG_LEN_BYTES U(56) /******************************************************************************* * Profiler entry format ******************************************************************************/ typedef struct { /* text explaining the timestamp location in code */ uint8_t tag[TAG_LEN_BYTES]; /* timestamp value */ uint64_t timestamp; } profiler_rec_t; static profiler_rec_t *head, *cur, *tail; static uint32_t tmr; static bool is_shmem_buf_mapped; /******************************************************************************* * Initialise the profiling library ******************************************************************************/ void boot_profiler_init(uint64_t shmem_base, uint32_t tmr_base) { uint64_t shmem_end_base; assert(shmem_base != ULL(0)); assert(tmr_base != U(0)); /* store the buffer address */ shmem_base_addr = shmem_base; /* calculate the base address of the last record */ shmem_end_base = shmem_base + (sizeof(profiler_rec_t) * (MAX_PROFILER_RECORDS - U(1))); /* calculate the head, tail and cur values */ head = (profiler_rec_t *)shmem_base; tail = (profiler_rec_t *)shmem_end_base; cur = head; /* timer used to get the current timestamp */ tmr = tmr_base; } /******************************************************************************* * Add tag and timestamp to profiler ******************************************************************************/ void boot_profiler_add_record(const char *str) { unsigned int len; /* calculate the length of the tag */ if (((unsigned int)strlen(str) + U(1)) > TAG_LEN_BYTES) { len = TAG_LEN_BYTES; } else { len = (unsigned int)strlen(str) + U(1); } if (head != NULL) { /* * The profiler runs with/without MMU enabled. Check * if MMU is enabled and memmap the shmem buffer, in * case it is. */ if ((!is_shmem_buf_mapped) && ((read_sctlr_el3() & SCTLR_M_BIT) != U(0))) { (void)mmap_add_dynamic_region(shmem_base_addr, shmem_base_addr, PROFILER_SIZE_BYTES, (MT_NS | MT_RW | MT_EXECUTE_NEVER)); is_shmem_buf_mapped = true; } /* write the tag and timestamp to buffer */ (void)snprintf((char *)cur->tag, len, "%s", str); cur->timestamp = mmio_read_32(tmr); /* start from head if we reached the end */ if (cur == tail) { cur = head; } else { cur++; } } } /******************************************************************************* * Deinint the profiler ******************************************************************************/ void boot_profiler_deinit(void) { if (shmem_base_addr != ULL(0)) { /* clean up resources */ cur = NULL; head = NULL; tail = NULL; /* flush the shmem for it to be visible to the NS world */ flush_dcache_range(shmem_base_addr, PROFILER_SIZE_BYTES); /* unmap the shmem buffer */ if (is_shmem_buf_mapped) { (void)mmap_remove_dynamic_region(shmem_base_addr, PROFILER_SIZE_BYTES); } } } trusted-firmware-a-2.2/plat/nvidia/tegra/common/tegra_bl31_setup.c000066400000000000000000000347571355360272700252440ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* length of Trusty's input parameters (in bytes) */ #define TRUSTY_PARAMS_LEN_BYTES (4096*2) extern void memcpy16(void *dest, const void *src, unsigned int length); /******************************************************************************* * Declarations of linker defined symbols which will help us find the layout * of trusted SRAM ******************************************************************************/ IMPORT_SYM(uint64_t, __RW_START__, BL31_RW_START); IMPORT_SYM(uint64_t, __RW_END__, BL31_RW_END); IMPORT_SYM(uint64_t, __RODATA_START__, BL31_RODATA_BASE); IMPORT_SYM(uint64_t, __RODATA_END__, BL31_RODATA_END); IMPORT_SYM(uint64_t, __TEXT_START__, TEXT_START); IMPORT_SYM(uint64_t, __TEXT_END__, TEXT_END); extern uint64_t tegra_bl31_phys_base; static entry_point_info_t bl33_image_ep_info, bl32_image_ep_info; static plat_params_from_bl2_t plat_bl31_params_from_bl2 = { .tzdram_size = TZDRAM_SIZE }; static unsigned long bl32_mem_size; static unsigned long bl32_boot_params; /******************************************************************************* * This variable holds the non-secure image entry address ******************************************************************************/ extern uint64_t ns_image_entrypoint; /******************************************************************************* * The following platform setup functions are weakly defined. They * provide typical implementations that will be overridden by a SoC. ******************************************************************************/ #pragma weak plat_early_platform_setup #pragma weak plat_get_bl31_params #pragma weak plat_get_bl31_plat_params #pragma weak plat_late_platform_setup void plat_early_platform_setup(void) { ; /* do nothing */ } struct tegra_bl31_params *plat_get_bl31_params(void) { return NULL; } plat_params_from_bl2_t *plat_get_bl31_plat_params(void) { return NULL; } void plat_late_platform_setup(void) { ; /* do nothing */ } /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for * security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. ******************************************************************************/ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *ep = NULL; /* return BL32 entry point info if it is valid */ if (type == NON_SECURE) { ep = &bl33_image_ep_info; } else if ((type == SECURE) && (bl32_image_ep_info.pc != 0U)) { ep = &bl32_image_ep_info; } return ep; } /******************************************************************************* * Return a pointer to the 'plat_params_from_bl2_t' structure. The BL2 image * passes this platform specific information. ******************************************************************************/ plat_params_from_bl2_t *bl31_get_plat_params(void) { return &plat_bl31_params_from_bl2; } /******************************************************************************* * Perform any BL31 specific platform actions. Populate the BL33 and BL32 image * info. ******************************************************************************/ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { struct tegra_bl31_params *arg_from_bl2 = (struct tegra_bl31_params *) arg0; plat_params_from_bl2_t *plat_params = (plat_params_from_bl2_t *)arg1; image_info_t bl32_img_info = { {0} }; uint64_t tzdram_start, tzdram_end, bl32_start, bl32_end, console_base; uint32_t console_clock; int32_t ret; static console_16550_t console; /* * For RESET_TO_BL31 systems, BL31 is the first bootloader to run so * there's no argument to relay from a previous bootloader. Platforms * might use custom ways to get arguments, so provide handlers which * they can override. */ if (arg_from_bl2 == NULL) { arg_from_bl2 = plat_get_bl31_params(); } if (plat_params == NULL) { plat_params = plat_get_bl31_plat_params(); } /* * Copy BL3-3, BL3-2 entry point information. * They are stored in Secure RAM, in BL2's address space. */ assert(arg_from_bl2 != NULL); assert(arg_from_bl2->bl33_ep_info != NULL); bl33_image_ep_info = *arg_from_bl2->bl33_ep_info; if (arg_from_bl2->bl32_ep_info != NULL) { bl32_image_ep_info = *arg_from_bl2->bl32_ep_info; bl32_mem_size = arg_from_bl2->bl32_ep_info->args.arg0; bl32_boot_params = arg_from_bl2->bl32_ep_info->args.arg2; } /* * Parse platform specific parameters */ assert(plat_params != NULL); plat_bl31_params_from_bl2.tzdram_base = plat_params->tzdram_base; plat_bl31_params_from_bl2.tzdram_size = plat_params->tzdram_size; plat_bl31_params_from_bl2.uart_id = plat_params->uart_id; plat_bl31_params_from_bl2.l2_ecc_parity_prot_dis = plat_params->l2_ecc_parity_prot_dis; plat_bl31_params_from_bl2.sc7entry_fw_size = plat_params->sc7entry_fw_size; plat_bl31_params_from_bl2.sc7entry_fw_base = plat_params->sc7entry_fw_base; /* * It is very important that we run either from TZDRAM or TZSRAM base. * Add an explicit check here. */ if ((plat_bl31_params_from_bl2.tzdram_base != (uint64_t)BL31_BASE) && (TEGRA_TZRAM_BASE != BL31_BASE)) { panic(); } /* * Reference clock used by the FPGAs is a lot slower. */ if (tegra_platform_is_fpga()) { console_clock = TEGRA_BOOT_UART_CLK_13_MHZ; } else { console_clock = TEGRA_BOOT_UART_CLK_408_MHZ; } /* * Get the base address of the UART controller to be used for the * console */ console_base = plat_get_console_from_id(plat_params->uart_id); if (console_base != 0U) { /* * Configure the UART port to be used as the console */ (void)console_16550_register(console_base, console_clock, TEGRA_CONSOLE_BAUDRATE, &console); console_set_scope(&console.console, CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH); } /* * The previous bootloader passes the base address of the shared memory * location to store the boot profiler logs. Sanity check the * address and initialise the profiler library, if it looks ok. */ if (plat_params->boot_profiler_shmem_base != 0ULL) { ret = bl31_check_ns_address(plat_params->boot_profiler_shmem_base, PROFILER_SIZE_BYTES); if (ret == (int32_t)0) { /* store the membase for the profiler lib */ plat_bl31_params_from_bl2.boot_profiler_shmem_base = plat_params->boot_profiler_shmem_base; /* initialise the profiler library */ boot_profiler_init(plat_params->boot_profiler_shmem_base, TEGRA_TMRUS_BASE); } } /* * Add timestamp for platform early setup entry. */ boot_profiler_add_record("[TF] early setup entry"); /* * Initialize delay timer */ tegra_delay_timer_init(); /* Early platform setup for Tegra SoCs */ plat_early_platform_setup(); /* * Do initial security configuration to allow DRAM/device access. */ tegra_memctrl_tzdram_setup(plat_bl31_params_from_bl2.tzdram_base, (uint32_t)plat_bl31_params_from_bl2.tzdram_size); /* * The previous bootloader might not have placed the BL32 image * inside the TZDRAM. We check the BL32 image info to find out * the base/PC values and relocate the image if necessary. */ if (arg_from_bl2->bl32_image_info != NULL) { bl32_img_info = *arg_from_bl2->bl32_image_info; /* Relocate BL32 if it resides outside of the TZDRAM */ tzdram_start = plat_bl31_params_from_bl2.tzdram_base; tzdram_end = plat_bl31_params_from_bl2.tzdram_base + plat_bl31_params_from_bl2.tzdram_size; bl32_start = bl32_img_info.image_base; bl32_end = bl32_img_info.image_base + bl32_img_info.image_size; assert(tzdram_end > tzdram_start); assert(bl32_end > bl32_start); assert(bl32_image_ep_info.pc > tzdram_start); assert(bl32_image_ep_info.pc < tzdram_end); /* relocate BL32 */ if ((bl32_start >= tzdram_end) || (bl32_end <= tzdram_start)) { INFO("Relocate BL32 to TZDRAM\n"); (void)memcpy16((void *)(uintptr_t)bl32_image_ep_info.pc, (void *)(uintptr_t)bl32_start, bl32_img_info.image_size); /* clean up non-secure intermediate buffer */ zeromem((void *)(uintptr_t)bl32_start, bl32_img_info.image_size); } } /* * Add timestamp for platform early setup exit. */ boot_profiler_add_record("[TF] early setup exit"); INFO("BL3-1: Boot CPU: %s Processor [%lx]\n", (((read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK) == DENVER_IMPL) ? "Denver" : "ARM", read_mpidr()); } #ifdef SPD_trusty void plat_trusty_set_boot_args(aapcs64_params_t *args) { args->arg0 = bl32_mem_size; args->arg1 = bl32_boot_params; args->arg2 = TRUSTY_PARAMS_LEN_BYTES; /* update EKS size */ if (args->arg4 != 0U) { args->arg2 = args->arg4; } /* Profiler Carveout Base */ args->arg3 = args->arg5; } #endif /******************************************************************************* * Initialize the gic, configure the SCR. ******************************************************************************/ void bl31_platform_setup(void) { /* * Add timestamp for platform setup entry. */ boot_profiler_add_record("[TF] plat setup entry"); /* Initialize the gic cpu and distributor interfaces */ plat_gic_setup(); /* * Setup secondary CPU POR infrastructure. */ plat_secondary_setup(); /* * Initial Memory Controller configuration. */ tegra_memctrl_setup(); /* * Set up the TZRAM memory aperture to allow only secure world * access */ tegra_memctrl_tzram_setup(TEGRA_TZRAM_BASE, TEGRA_TZRAM_SIZE); /* * Late setup handler to allow platforms to performs additional * functionality. * This handler gets called with MMU enabled. */ plat_late_platform_setup(); /* * Add timestamp for platform setup exit. */ boot_profiler_add_record("[TF] plat setup exit"); INFO("BL3-1: Tegra platform setup complete\n"); } /******************************************************************************* * Perform any BL3-1 platform runtime setup prior to BL3-1 cold boot exit ******************************************************************************/ void bl31_plat_runtime_setup(void) { /* * During cold boot, it is observed that the arbitration * bit is set in the Memory controller leading to false * error interrupts in the non-secure world. To avoid * this, clean the interrupt status register before * booting into the non-secure world */ tegra_memctrl_clear_pending_interrupts(); /* * During boot, USB3 and flash media (SDMMC/SATA) devices need * access to IRAM. Because these clients connect to the MC and * do not have a direct path to the IRAM, the MC implements AHB * redirection during boot to allow path to IRAM. In this mode * accesses to a programmed memory address aperture are directed * to the AHB bus, allowing access to the IRAM. This mode must be * disabled before we jump to the non-secure world. */ tegra_memctrl_disable_ahb_redirection(); /* * Add final timestamp before exiting BL31. */ boot_profiler_add_record("[TF] bl31 exit"); boot_profiler_deinit(); } /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this only intializes the mmu in a quick and dirty way. ******************************************************************************/ void bl31_plat_arch_setup(void) { uint64_t rw_start = BL31_RW_START; uint64_t rw_size = BL31_RW_END - BL31_RW_START; uint64_t rodata_start = BL31_RODATA_BASE; uint64_t rodata_size = BL31_RODATA_END - BL31_RODATA_BASE; uint64_t code_base = TEXT_START; uint64_t code_size = TEXT_END - TEXT_START; const mmap_region_t *plat_mmio_map = NULL; #if USE_COHERENT_MEM uint32_t coh_start, coh_size; #endif const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); /* * Add timestamp for arch setup entry. */ boot_profiler_add_record("[TF] arch setup entry"); /* add MMIO space */ plat_mmio_map = plat_get_mmio_map(); if (plat_mmio_map != NULL) { mmap_add(plat_mmio_map); } else { WARN("MMIO map not available\n"); } /* add memory regions */ mmap_add_region(rw_start, rw_start, rw_size, MT_MEMORY | MT_RW | MT_SECURE); mmap_add_region(rodata_start, rodata_start, rodata_size, MT_RO_DATA | MT_SECURE); mmap_add_region(code_base, code_base, code_size, MT_CODE | MT_SECURE); #if USE_COHERENT_MEM coh_start = total_base + (BL_COHERENT_RAM_BASE - BL31_RO_BASE); coh_size = BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE; mmap_add_region(coh_start, coh_start, coh_size, (uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE); #endif /* map TZDRAM used by BL31 as coherent memory */ if (TEGRA_TZRAM_BASE == tegra_bl31_phys_base) { mmap_add_region(params_from_bl2->tzdram_base, params_from_bl2->tzdram_base, BL31_SIZE, MT_DEVICE | MT_RW | MT_SECURE); } /* set up translation tables */ init_xlat_tables(); /* enable the MMU */ enable_mmu_el3(0); /* * Add timestamp for arch setup exit. */ boot_profiler_add_record("[TF] arch setup exit"); INFO("BL3-1: Tegra: MMU enabled\n"); } /******************************************************************************* * Check if the given NS DRAM range is valid ******************************************************************************/ int32_t bl31_check_ns_address(uint64_t base, uint64_t size_in_bytes) { uint64_t end = base + size_in_bytes - U(1); int32_t ret = 0; /* * Check if the NS DRAM address is valid */ if ((base < TEGRA_DRAM_BASE) || (base >= TEGRA_DRAM_END) || (end > TEGRA_DRAM_END)) { ERROR("NS address 0x%llx is out-of-bounds!\n", base); ret = -EFAULT; } /* * TZDRAM aperture contains the BL31 and BL32 images, so we need * to check if the NS DRAM range overlaps the TZDRAM aperture. */ if ((base < (uint64_t)TZDRAM_END) && (end > tegra_bl31_phys_base)) { ERROR("NS address 0x%llx overlaps TZDRAM!\n", base); ret = -ENOTSUP; } /* valid NS address */ return ret; } trusted-firmware-a-2.2/plat/nvidia/tegra/common/tegra_common.mk000066400000000000000000000023371355360272700247250ustar00rootroot00000000000000# # Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # PLAT_INCLUDES := -Iplat/nvidia/tegra/include/drivers \ -Iplat/nvidia/tegra/include/lib \ -Iplat/nvidia/tegra/include \ -Iplat/nvidia/tegra/include/${TARGET_SOC} include lib/xlat_tables_v2/xlat_tables.mk PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} COMMON_DIR := plat/nvidia/tegra/common TEGRA_GICv2_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c \ ${COMMON_DIR}/tegra_gicv2.c BL31_SOURCES += drivers/delay_timer/delay_timer.c \ drivers/io/io_storage.c \ plat/common/aarch64/crash_console_helpers.S \ ${TEGRA_GICv2_SOURCES} \ ${COMMON_DIR}/aarch64/tegra_helpers.S \ ${COMMON_DIR}/drivers/pmc/pmc.c \ ${COMMON_DIR}/lib/debug/profiler.c \ ${COMMON_DIR}/tegra_bl31_setup.c \ ${COMMON_DIR}/tegra_delay_timer.c \ ${COMMON_DIR}/tegra_fiq_glue.c \ ${COMMON_DIR}/tegra_io_storage.c \ ${COMMON_DIR}/tegra_platform.c \ ${COMMON_DIR}/tegra_pm.c \ ${COMMON_DIR}/tegra_sip_calls.c \ ${COMMON_DIR}/tegra_topology.c trusted-firmware-a-2.2/plat/nvidia/tegra/common/tegra_delay_timer.c000066400000000000000000000011421355360272700255370ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include static uint32_t tegra_timerus_get_value(void) { return mmio_read_32(TEGRA_TMRUS_BASE); } /* * Initialise the on-chip free rolling us counter as the delay * timer. */ void tegra_delay_timer_init(void) { static const timer_ops_t tegra_timer_ops = { .get_timer_value = tegra_timerus_get_value, .clk_mult = 1, .clk_div = 1, }; timer_init(&tegra_timer_ops); } trusted-firmware-a-2.2/plat/nvidia/tegra/common/tegra_fiq_glue.c000066400000000000000000000120321355360272700250340ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #if ENABLE_WDT_LEGACY_FIQ_HANDLING #include #endif #include #include /* Legacy FIQ used by earlier Tegra platforms */ #define LEGACY_FIQ_PPI_WDT 28U static DEFINE_BAKERY_LOCK(tegra_fiq_lock); /******************************************************************************* * Static variables ******************************************************************************/ static uint64_t ns_fiq_handler_addr; static uint32_t fiq_handler_active; static pcpu_fiq_state_t fiq_state[PLATFORM_CORE_COUNT]; /******************************************************************************* * Handler for FIQ interrupts ******************************************************************************/ static uint64_t tegra_fiq_interrupt_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { cpu_context_t *ctx = cm_get_context(NON_SECURE); el3_state_t *el3state_ctx = get_el3state_ctx(ctx); uint32_t cpu = plat_my_core_pos(); uint32_t irq; (void)id; (void)flags; (void)handle; (void)cookie; /* * Read the pending interrupt ID */ irq = plat_ic_get_pending_interrupt_id(); bakery_lock_get(&tegra_fiq_lock); /* * Jump to NS world only if the NS world's FIQ handler has * been registered */ if (ns_fiq_handler_addr != 0U) { /* * The FIQ was generated when the execution was in the non-secure * world. Save the context registers to start with. */ cm_el1_sysregs_context_save(NON_SECURE); /* * Save elr_el3 and spsr_el3 from the saved context, and overwrite * the context with the NS fiq_handler_addr and SPSR value. */ fiq_state[cpu].elr_el3 = read_ctx_reg((el3state_ctx), (uint32_t)(CTX_ELR_EL3)); fiq_state[cpu].spsr_el3 = read_ctx_reg((el3state_ctx), (uint32_t)(CTX_SPSR_EL3)); /* * Set the new ELR to continue execution in the NS world using the * FIQ handler registered earlier. */ cm_set_elr_el3(NON_SECURE, ns_fiq_handler_addr); } #if ENABLE_WDT_LEGACY_FIQ_HANDLING /* * Tegra platforms that use LEGACY_FIQ as the watchdog timer FIQ * need to issue an IPI to other CPUs, to allow them to handle * the "system hung" scenario. This interrupt is passed to the GICD * via the Flow Controller. So, once we receive this interrupt, * disable the routing so that we can mark it as "complete" in the * GIC later. */ if (irq == LEGACY_FIQ_PPI_WDT) { tegra_fc_disable_fiq_to_ccplex_routing(); } #endif /* * Mark this interrupt as complete to avoid a FIQ storm. */ if (irq < 1022U) { (void)plat_ic_acknowledge_interrupt(); plat_ic_end_of_interrupt(irq); } bakery_lock_release(&tegra_fiq_lock); return 0; } /******************************************************************************* * Setup handler for FIQ interrupts ******************************************************************************/ void tegra_fiq_handler_setup(void) { uint32_t flags; int32_t rc; /* return if already registered */ if (fiq_handler_active == 0U) { /* * Register an interrupt handler for FIQ interrupts generated for * NS interrupt sources */ flags = 0U; set_interrupt_rm_flag((flags), (NON_SECURE)); rc = register_interrupt_type_handler(INTR_TYPE_EL3, tegra_fiq_interrupt_handler, flags); if (rc != 0) { panic(); } /* handler is now active */ fiq_handler_active = 1; } } /******************************************************************************* * Validate and store NS world's entrypoint for FIQ interrupts ******************************************************************************/ void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint) { ns_fiq_handler_addr = entrypoint; } /******************************************************************************* * Handler to return the NS EL1/EL0 CPU context ******************************************************************************/ int32_t tegra_fiq_get_intr_context(void) { cpu_context_t *ctx = cm_get_context(NON_SECURE); gp_regs_t *gpregs_ctx = get_gpregs_ctx(ctx); const el1_sys_regs_t *el1state_ctx = get_sysregs_ctx(ctx); uint32_t cpu = plat_my_core_pos(); uint64_t val; /* * We store the ELR_EL3, SPSR_EL3, SP_EL0 and SP_EL1 registers so * that el3_exit() sends these values back to the NS world. */ write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X0), (fiq_state[cpu].elr_el3)); write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X1), (fiq_state[cpu].spsr_el3)); val = read_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_SP_EL0)); write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X2), (val)); val = read_ctx_reg((el1state_ctx), (uint32_t)(CTX_SP_EL1)); write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X3), (val)); return 0; } trusted-firmware-a-2.2/plat/nvidia/tegra/common/tegra_gicv2.c000066400000000000000000000036221355360272700242600ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /****************************************************************************** * Tegra common helper to setup the GICv2 driver data. *****************************************************************************/ void tegra_gic_setup(const interrupt_prop_t *interrupt_props, unsigned int interrupt_props_num) { /* * Tegra GIC configuration settings */ static gicv2_driver_data_t tegra_gic_data; /* * Register Tegra GICv2 driver */ tegra_gic_data.gicd_base = TEGRA_GICD_BASE; tegra_gic_data.gicc_base = TEGRA_GICC_BASE; tegra_gic_data.interrupt_props = interrupt_props; tegra_gic_data.interrupt_props_num = interrupt_props_num; gicv2_driver_init(&tegra_gic_data); } /****************************************************************************** * Tegra common helper to initialize the GICv2 only driver. *****************************************************************************/ void tegra_gic_init(void) { gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } /****************************************************************************** * Tegra common helper to disable the GICv2 CPU interface *****************************************************************************/ void tegra_gic_cpuif_deactivate(void) { gicv2_cpuif_disable(); } /****************************************************************************** * Tegra common helper to initialize the per cpu distributor interface * in GICv2 *****************************************************************************/ void tegra_gic_pcpu_init(void) { gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } trusted-firmware-a-2.2/plat/nvidia/tegra/common/tegra_io_storage.c000066400000000000000000000007401355360272700253770ustar00rootroot00000000000000/* * Copyright (c) 2019, NVIDIA Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /* * Return an IO device handle and specification which can be used to access * an image. Use this to enforce platform load policy. * * This function is not supported at this time */ int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, uintptr_t *image_spec) { return -ENOTSUP; } trusted-firmware-a-2.2/plat/nvidia/tegra/common/tegra_platform.c000066400000000000000000000144271355360272700250770ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /******************************************************************************* * Tegra platforms ******************************************************************************/ typedef enum tegra_platform { TEGRA_PLATFORM_SILICON = 0U, TEGRA_PLATFORM_QT, TEGRA_PLATFORM_FPGA, TEGRA_PLATFORM_EMULATION, TEGRA_PLATFORM_LINSIM, TEGRA_PLATFORM_UNIT_FPGA, TEGRA_PLATFORM_VIRT_DEV_KIT, TEGRA_PLATFORM_MAX, } tegra_platform_t; /******************************************************************************* * Tegra macros defining all the SoC minor versions ******************************************************************************/ #define TEGRA_MINOR_QT U(0) #define TEGRA_MINOR_FPGA U(1) #define TEGRA_MINOR_ASIM_QT U(2) #define TEGRA_MINOR_ASIM_LINSIM U(3) #define TEGRA_MINOR_DSIM_ASIM_LINSIM U(4) #define TEGRA_MINOR_UNIT_FPGA U(5) #define TEGRA_MINOR_VIRT_DEV_KIT U(6) /******************************************************************************* * Tegra macros defining all the SoC pre_si_platform ******************************************************************************/ #define TEGRA_PRE_SI_QT U(1) #define TEGRA_PRE_SI_FPGA U(2) #define TEGRA_PRE_SI_UNIT_FPGA U(3) #define TEGRA_PRE_SI_ASIM_QT U(4) #define TEGRA_PRE_SI_ASIM_LINSIM U(5) #define TEGRA_PRE_SI_DSIM_ASIM_LINSIM U(6) #define TEGRA_PRE_SI_VDK U(8) /* * Read the chip ID value */ static uint32_t tegra_get_chipid(void) { return mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET); } /* * Read the chip's major version from chip ID value */ uint32_t tegra_get_chipid_major(void) { return (tegra_get_chipid() >> MAJOR_VERSION_SHIFT) & MAJOR_VERSION_MASK; } /* * Read the chip's minor version from the chip ID value */ uint32_t tegra_get_chipid_minor(void) { return (tegra_get_chipid() >> MINOR_VERSION_SHIFT) & MINOR_VERSION_MASK; } /* * Read the chip's pre_si_platform valus from the chip ID value */ static uint32_t tegra_get_chipid_pre_si_platform(void) { return (tegra_get_chipid() >> PRE_SI_PLATFORM_SHIFT) & PRE_SI_PLATFORM_MASK; } bool tegra_chipid_is_t132(void) { uint32_t chip_id = ((tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK); return (chip_id == TEGRA_CHIPID_TEGRA13); } bool tegra_chipid_is_t186(void) { uint32_t chip_id = (tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK; return (chip_id == TEGRA_CHIPID_TEGRA18); } bool tegra_chipid_is_t210(void) { uint32_t chip_id = (tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK; return (chip_id == TEGRA_CHIPID_TEGRA21); } bool tegra_chipid_is_t210_b01(void) { return (tegra_chipid_is_t210() && (tegra_get_chipid_major() == 0x2U)); } /* * Read the chip ID value and derive the platform */ static tegra_platform_t tegra_get_platform(void) { uint32_t major, minor, pre_si_platform; tegra_platform_t ret; /* get the major/minor chip ID values */ major = tegra_get_chipid_major(); minor = tegra_get_chipid_minor(); pre_si_platform = tegra_get_chipid_pre_si_platform(); if (major == 0U) { /* * The minor version number is used by simulation platforms */ switch (minor) { /* * Cadence's QuickTurn emulation system is a Solaris-based * chip emulation system */ case TEGRA_MINOR_QT: case TEGRA_MINOR_ASIM_QT: ret = TEGRA_PLATFORM_QT; break; /* * FPGAs are used during early software/hardware development */ case TEGRA_MINOR_FPGA: ret = TEGRA_PLATFORM_FPGA; break; /* * Linsim is a reconfigurable, clock-driven, mixed RTL/cmodel * simulation framework. */ case TEGRA_MINOR_ASIM_LINSIM: case TEGRA_MINOR_DSIM_ASIM_LINSIM: ret = TEGRA_PLATFORM_LINSIM; break; /* * Unit FPGAs run the actual hardware block IP on the FPGA with * the other parts of the system using Linsim. */ case TEGRA_MINOR_UNIT_FPGA: ret = TEGRA_PLATFORM_UNIT_FPGA; break; /* * The Virtualizer Development Kit (VDK) is the standard chip * development from Synopsis. */ case TEGRA_MINOR_VIRT_DEV_KIT: ret = TEGRA_PLATFORM_VIRT_DEV_KIT; break; default: ret = TEGRA_PLATFORM_MAX; break; } } else if (pre_si_platform > 0U) { switch (pre_si_platform) { /* * Cadence's QuickTurn emulation system is a Solaris-based * chip emulation system */ case TEGRA_PRE_SI_QT: case TEGRA_PRE_SI_ASIM_QT: ret = TEGRA_PLATFORM_QT; break; /* * FPGAs are used during early software/hardware development */ case TEGRA_PRE_SI_FPGA: ret = TEGRA_PLATFORM_FPGA; break; /* * Linsim is a reconfigurable, clock-driven, mixed RTL/cmodel * simulation framework. */ case TEGRA_PRE_SI_ASIM_LINSIM: case TEGRA_PRE_SI_DSIM_ASIM_LINSIM: ret = TEGRA_PLATFORM_LINSIM; break; /* * Unit FPGAs run the actual hardware block IP on the FPGA with * the other parts of the system using Linsim. */ case TEGRA_PRE_SI_UNIT_FPGA: ret = TEGRA_PLATFORM_UNIT_FPGA; break; /* * The Virtualizer Development Kit (VDK) is the standard chip * development from Synopsis. */ case TEGRA_PRE_SI_VDK: ret = TEGRA_PLATFORM_VIRT_DEV_KIT; break; default: ret = TEGRA_PLATFORM_MAX; break; } } else { /* Actual silicon platforms have a non-zero major version */ ret = TEGRA_PLATFORM_SILICON; } return ret; } bool tegra_platform_is_silicon(void) { return ((tegra_get_platform() == TEGRA_PLATFORM_SILICON) ? true : false); } bool tegra_platform_is_qt(void) { return ((tegra_get_platform() == TEGRA_PLATFORM_QT) ? true : false); } bool tegra_platform_is_linsim(void) { tegra_platform_t plat = tegra_get_platform(); return (((plat == TEGRA_PLATFORM_LINSIM) || (plat == TEGRA_PLATFORM_UNIT_FPGA)) ? true : false); } bool tegra_platform_is_fpga(void) { return ((tegra_get_platform() == TEGRA_PLATFORM_FPGA) ? true : false); } bool tegra_platform_is_emulation(void) { return (tegra_get_platform() == TEGRA_PLATFORM_EMULATION); } bool tegra_platform_is_unit_fpga(void) { return ((tegra_get_platform() == TEGRA_PLATFORM_UNIT_FPGA) ? true : false); } bool tegra_platform_is_virt_dev_kit(void) { return ((tegra_get_platform() == TEGRA_PLATFORM_VIRT_DEV_KIT) ? true : false); } trusted-firmware-a-2.2/plat/nvidia/tegra/common/tegra_pm.c000066400000000000000000000327311355360272700236650ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern uint64_t tegra_bl31_phys_base; extern uint64_t tegra_sec_entry_point; /* * tegra_fake_system_suspend acts as a boolean var controlling whether * we are going to take fake system suspend code or normal system suspend code * path. This variable is set inside the sip call handlers,when the kernel * requests a SIP call to set the suspend debug flags. */ uint8_t tegra_fake_system_suspend; /* * The following platform setup functions are weakly defined. They * provide typical implementations that will be overridden by a SoC. */ #pragma weak tegra_soc_pwr_domain_suspend_pwrdown_early #pragma weak tegra_soc_cpu_standby #pragma weak tegra_soc_pwr_domain_suspend #pragma weak tegra_soc_pwr_domain_on #pragma weak tegra_soc_pwr_domain_off #pragma weak tegra_soc_pwr_domain_on_finish #pragma weak tegra_soc_pwr_domain_power_down_wfi #pragma weak tegra_soc_prepare_system_reset #pragma weak tegra_soc_prepare_system_off #pragma weak tegra_soc_get_target_pwr_state int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state) { return PSCI_E_NOT_SUPPORTED; } int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state) { (void)cpu_state; return PSCI_E_SUCCESS; } int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) { (void)target_state; return PSCI_E_NOT_SUPPORTED; } int32_t tegra_soc_pwr_domain_on(u_register_t mpidr) { (void)mpidr; return PSCI_E_SUCCESS; } int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) { (void)target_state; return PSCI_E_SUCCESS; } int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) { (void)target_state; return PSCI_E_SUCCESS; } int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state) { (void)target_state; return PSCI_E_SUCCESS; } int32_t tegra_soc_prepare_system_reset(void) { return PSCI_E_SUCCESS; } __dead2 void tegra_soc_prepare_system_off(void) { ERROR("Tegra System Off: operation not handled.\n"); panic(); } plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl, const plat_local_state_t *states, uint32_t ncpu) { plat_local_state_t target = PLAT_MAX_OFF_STATE, temp; uint32_t num_cpu = ncpu; const plat_local_state_t *local_state = states; (void)lvl; assert(ncpu != 0U); do { temp = *local_state; if ((temp < target)) { target = temp; } --num_cpu; local_state++; } while (num_cpu != 0U); return target; } /******************************************************************************* * This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND` * call to get the `power_state` parameter. This allows the platform to encode * the appropriate State-ID field within the `power_state` parameter which can * be utilized in `pwr_domain_suspend()` to suspend to system affinity level. ******************************************************************************/ void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state) { /* all affinities use system suspend state id */ for (uint32_t i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) { req_state->pwr_domain_state[i] = PSTATE_ID_SOC_POWERDN; } } /******************************************************************************* * Handler called when an affinity instance is about to enter standby. ******************************************************************************/ void tegra_cpu_standby(plat_local_state_t cpu_state) { u_register_t saved_scr_el3; (void)cpu_state; /* Tegra SoC specific handler */ if (tegra_soc_cpu_standby(cpu_state) != PSCI_E_SUCCESS) ERROR("%s failed\n", __func__); saved_scr_el3 = read_scr_el3(); /* * As per ARM ARM D1.17.2, any physical IRQ interrupt received by the * PE will be treated as a wake-up event, if SCR_EL3.IRQ is set to '1', * irrespective of the value of the PSTATE.I bit value. */ write_scr_el3(saved_scr_el3 | SCR_IRQ_BIT); /* * Enter standby state * * dsb & isb is good practice before using wfi to enter low power states */ dsb(); isb(); wfi(); /* * Restore saved scr_el3 that has IRQ bit cleared as we don't want EL3 * handling any further interrupts */ write_scr_el3(saved_scr_el3); } /******************************************************************************* * Handler called when an affinity instance is about to be turned on. The * level and mpidr determine the affinity instance. ******************************************************************************/ int32_t tegra_pwr_domain_on(u_register_t mpidr) { return tegra_soc_pwr_domain_on(mpidr); } /******************************************************************************* * Handler called when a power domain is about to be turned off. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ void tegra_pwr_domain_off(const psci_power_state_t *target_state) { (void)tegra_soc_pwr_domain_off(target_state); } /******************************************************************************* * Handler called when a power domain is about to be suspended. The * target_state encodes the power state that each level should transition to. * This handler is called with SMP and data cache enabled, when * HW_ASSISTED_COHERENCY = 0 ******************************************************************************/ void tegra_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state) { tegra_soc_pwr_domain_suspend_pwrdown_early(target_state); } /******************************************************************************* * Handler called when a power domain is about to be suspended. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ void tegra_pwr_domain_suspend(const psci_power_state_t *target_state) { (void)tegra_soc_pwr_domain_suspend(target_state); /* Disable console if we are entering deep sleep. */ if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == PSTATE_ID_SOC_POWERDN) { (void)console_flush(); console_switch_state(0); } /* disable GICC */ tegra_gic_cpuif_deactivate(); } /******************************************************************************* * Handler called at the end of the power domain suspend sequence. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ __dead2 void tegra_pwr_domain_power_down_wfi(const psci_power_state_t *target_state) { uint8_t pwr_state = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL]; uint64_t rmr_el3 = 0; /* call the chip's power down handler */ (void)tegra_soc_pwr_domain_power_down_wfi(target_state); /* * If we are in fake system suspend mode, ensure we start doing * procedures that help in looping back towards system suspend exit * instead of calling WFI by requesting a warm reset. * Else, just call WFI to enter low power state. */ if ((tegra_fake_system_suspend != 0U) && (pwr_state == (uint8_t)PSTATE_ID_SOC_POWERDN)) { /* warm reboot */ rmr_el3 = read_rmr_el3(); write_rmr_el3(rmr_el3 | RMR_WARM_RESET_CPU); } else { /* enter power down state */ wfi(); } /* we can never reach here */ panic(); } /******************************************************************************* * Handler called when a power domain has just been powered on after * being turned off earlier. The target_state encodes the low power state that * each level has woken up from. ******************************************************************************/ void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state) { const plat_params_from_bl2_t *plat_params; /* * Initialize the GIC cpu and distributor interfaces */ tegra_gic_init(); /* * Check if we are exiting from deep sleep. */ if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == PSTATE_ID_SOC_POWERDN) { /* Restart console output. */ console_switch_state(CONSOLE_FLAG_RUNTIME); /* * Restore Memory Controller settings as it loses state * during system suspend. */ tegra_memctrl_restore_settings(); /* * Security configuration to allow DRAM/device access. */ plat_params = bl31_get_plat_params(); tegra_memctrl_tzdram_setup(plat_params->tzdram_base, (uint32_t)plat_params->tzdram_size); /* * Set up the TZRAM memory aperture to allow only secure world * access */ tegra_memctrl_tzram_setup(TEGRA_TZRAM_BASE, TEGRA_TZRAM_SIZE); } /* * Reset hardware settings. */ (void)tegra_soc_pwr_domain_on_finish(target_state); } /******************************************************************************* * Handler called when a power domain has just been powered on after * having been suspended earlier. The target_state encodes the low power state * that each level has woken up from. ******************************************************************************/ void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state) { tegra_pwr_domain_on_finish(target_state); } /******************************************************************************* * Handler called when the system wants to be powered off ******************************************************************************/ __dead2 void tegra_system_off(void) { INFO("Powering down system...\n"); tegra_soc_prepare_system_off(); } /******************************************************************************* * Handler called when the system wants to be restarted. ******************************************************************************/ __dead2 void tegra_system_reset(void) { INFO("Restarting system...\n"); /* per-SoC system reset handler */ (void)tegra_soc_prepare_system_reset(); /* * Program the PMC in order to restart the system. */ tegra_pmc_system_reset(); } /******************************************************************************* * Handler called to check the validity of the power state parameter. ******************************************************************************/ int32_t tegra_validate_power_state(uint32_t power_state, psci_power_state_t *req_state) { assert(req_state != NULL); return tegra_soc_validate_power_state(power_state, req_state); } /******************************************************************************* * Platform handler called to check the validity of the non secure entrypoint. ******************************************************************************/ int32_t tegra_validate_ns_entrypoint(uintptr_t entrypoint) { int32_t ret = PSCI_E_INVALID_ADDRESS; /* * Check if the non secure entrypoint lies within the non * secure DRAM. */ if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END)) { ret = PSCI_E_SUCCESS; } return ret; } /******************************************************************************* * Export the platform handlers to enable psci to invoke them ******************************************************************************/ static const plat_psci_ops_t tegra_plat_psci_ops = { .cpu_standby = tegra_cpu_standby, .pwr_domain_on = tegra_pwr_domain_on, .pwr_domain_off = tegra_pwr_domain_off, .pwr_domain_suspend_pwrdown_early = tegra_pwr_domain_suspend_pwrdown_early, .pwr_domain_suspend = tegra_pwr_domain_suspend, .pwr_domain_on_finish = tegra_pwr_domain_on_finish, .pwr_domain_suspend_finish = tegra_pwr_domain_suspend_finish, .pwr_domain_pwr_down_wfi = tegra_pwr_domain_power_down_wfi, .system_off = tegra_system_off, .system_reset = tegra_system_reset, .validate_power_state = tegra_validate_power_state, .validate_ns_entrypoint = tegra_validate_ns_entrypoint, .get_sys_suspend_power_state = tegra_get_sys_suspend_power_state, }; /******************************************************************************* * Export the platform specific power ops and initialize Power Controller ******************************************************************************/ int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } }; /* * Flush entrypoint variable to PoC since it will be * accessed after a reset with the caches turned off. */ tegra_sec_entry_point = sec_entrypoint; flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t)); /* * Reset hardware settings. */ (void)tegra_soc_pwr_domain_on_finish(&target_state); /* * Initialize PSCI ops struct */ *psci_ops = &tegra_plat_psci_ops; return 0; } /******************************************************************************* * Platform handler to calculate the proper target power level at the * specified affinity level ******************************************************************************/ plat_local_state_t plat_get_target_pwr_state(unsigned int lvl, const plat_local_state_t *states, unsigned int ncpu) { return tegra_soc_get_target_pwr_state(lvl, states, ncpu); } trusted-firmware-a-2.2/plat/nvidia/tegra/common/tegra_sip_calls.c000066400000000000000000000125561355360272700252250ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * Common Tegra SiP SMCs ******************************************************************************/ #define TEGRA_SIP_NEW_VIDEOMEM_REGION 0x82000003 #define TEGRA_SIP_FIQ_NS_ENTRYPOINT 0x82000005 #define TEGRA_SIP_FIQ_NS_GET_CONTEXT 0x82000006 #define TEGRA_SIP_ENABLE_FAKE_SYSTEM_SUSPEND 0xC2000007 /******************************************************************************* * Fake system suspend mode control var ******************************************************************************/ extern uint8_t tegra_fake_system_suspend; /******************************************************************************* * SoC specific SiP handler ******************************************************************************/ #pragma weak plat_sip_handler int32_t plat_sip_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, const void *cookie, void *handle, uint64_t flags) { /* unused parameters */ (void)smc_fid; (void)x1; (void)x2; (void)x3; (void)x4; (void)cookie; (void)handle; (void)flags; return -ENOTSUP; } /******************************************************************************* * This function is responsible for handling all SiP calls ******************************************************************************/ uintptr_t tegra_sip_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 regval, local_x2_32 = (uint32_t)x2; int32_t err; /* Check if this is a SoC specific SiP */ err = plat_sip_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); if (err == 0) { SMC_RET1(handle, (uint64_t)err); } else { switch (smc_fid) { case TEGRA_SIP_NEW_VIDEOMEM_REGION: /* * Check if Video Memory overlaps TZDRAM (contains bl31/bl32) * or falls outside of the valid DRAM range */ err = bl31_check_ns_address(x1, local_x2_32); if (err != 0) { SMC_RET1(handle, (uint64_t)err); } /* * Check if Video Memory is aligned to 1MB. */ if (((x1 & 0xFFFFFU) != 0U) || ((local_x2_32 & 0xFFFFFU) != 0U)) { ERROR("Unaligned Video Memory base address!\n"); SMC_RET1(handle, (uint64_t)-ENOTSUP); } /* * The GPU is the user of the Video Memory region. In order to * transition to the new memory region smoothly, we program the * new base/size ONLY if the GPU is in reset mode. */ regval = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET); if ((regval & GPU_RESET_BIT) == 0U) { ERROR("GPU not in reset! Video Memory setup failed\n"); SMC_RET1(handle, (uint64_t)-ENOTSUP); } /* new video memory carveout settings */ tegra_memctrl_videomem_setup(x1, local_x2_32); /* * Ensure again that GPU is still in reset after VPR resize */ regval = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET); if ((regval & GPU_RESET_BIT) == 0U) { mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_GPU_SET_OFFSET, GPU_SET_BIT); } SMC_RET1(handle, 0); /* * The NS world registers the address of its handler to be * used for processing the FIQ. This is normally used by the * NS FIQ debugger driver to detect system hangs by programming * a watchdog timer to fire a FIQ interrupt. */ case TEGRA_SIP_FIQ_NS_ENTRYPOINT: if (x1 == 0U) { SMC_RET1(handle, SMC_UNK); } /* * TODO: Check if x1 contains a valid DRAM address */ /* store the NS world's entrypoint */ tegra_fiq_set_ns_entrypoint(x1); SMC_RET1(handle, 0); /* * The NS world's FIQ handler issues this SMC to get the NS EL1/EL0 * CPU context when the FIQ interrupt was triggered. This allows the * NS world to understand the CPU state when the watchdog interrupt * triggered. */ case TEGRA_SIP_FIQ_NS_GET_CONTEXT: /* retrieve context registers when FIQ triggered */ (void)tegra_fiq_get_intr_context(); SMC_RET0(handle); case TEGRA_SIP_ENABLE_FAKE_SYSTEM_SUSPEND: /* * System suspend fake mode is set if we are on VDK and we make * a debug SIP call. This mode ensures that we excercise debug * path instead of the regular code path to suit the pre-silicon * platform needs. These include replacing the call to WFI by * a warm reset request. */ if (tegra_platform_is_virt_dev_kit() != false) { tegra_fake_system_suspend = 1; SMC_RET1(handle, 0); } /* * We return to the external world as if this SIP is not * implemented in case, we are not running on VDK. */ break; default: ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); break; } } SMC_RET1(handle, SMC_UNK); } /* Define a runtime service descriptor for fast SMC calls */ DECLARE_RT_SVC( tegra_sip_fast, (OEN_SIP_START), (OEN_SIP_END), (SMC_TYPE_FAST), (NULL), (tegra_sip_handler) ); trusted-firmware-a-2.2/plat/nvidia/tegra/common/tegra_topology.c000066400000000000000000000027071355360272700251250ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #pragma weak plat_core_pos_by_mpidr /******************************************************************************* * This function implements a part of the critical interface between the psci * generic layer and the platform that allows the former to query the platform * to convert an MPIDR to a unique linear index. An error code (-1) is returned * in case the MPIDR is invalid. ******************************************************************************/ int32_t plat_core_pos_by_mpidr(u_register_t mpidr) { u_register_t cluster_id, cpu_id; int32_t result; cluster_id = (mpidr >> (u_register_t)MPIDR_AFF1_SHIFT) & (u_register_t)MPIDR_AFFLVL_MASK; cpu_id = (mpidr >> (u_register_t)MPIDR_AFF0_SHIFT) & (u_register_t)MPIDR_AFFLVL_MASK; /* CorePos = CoreId + (ClusterId * cpus per cluster) */ result = (int32_t)cpu_id + ((int32_t)cluster_id * PLATFORM_MAX_CPUS_PER_CLUSTER); if (cluster_id >= (u_register_t)PLATFORM_CLUSTER_COUNT) { result = PSCI_E_NOT_PRESENT; } /* * Validate cpu_id by checking whether it represents a CPU in * one of the two clusters present on the platform. */ if (cpu_id >= (u_register_t)PLATFORM_MAX_CPUS_PER_CLUSTER) { result = PSCI_E_NOT_PRESENT; } return result; } trusted-firmware-a-2.2/plat/nvidia/tegra/include/000077500000000000000000000000001355360272700220505ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/include/drivers/000077500000000000000000000000001355360272700235265ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/include/drivers/bpmp.h000066400000000000000000000057471355360272700246520ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BPMP_H #define BPMP_H #include /* macro to enable clock to the Atomics block */ #define CAR_ENABLE_ATOMICS (1U << 16) /* command to get the channel base addresses from bpmp */ #define ATOMIC_CMD_GET 4U /* Hardware IRQ # used to signal bpmp of an incoming command */ #define INT_SHR_SEM_OUTBOX_FULL 6U /* macros to decode the bpmp's state */ #define CH_MASK(ch) ((uint32_t)0x3 << ((ch) * 2U)) #define MA_FREE(ch) ((uint32_t)0x2 << ((ch) * 2U)) #define MA_ACKD(ch) ((uint32_t)0x3 << ((ch) * 2U)) /* response from bpmp to indicate it has powered up */ #define SIGN_OF_LIFE 0xAAAAAAAAU /* flags to indicate bpmp driver's state */ #define BPMP_NOT_PRESENT 0xF00DBEEFU #define BPMP_INIT_COMPLETE 0xBEEFF00DU #define BPMP_INIT_PENDING 0xDEADBEEFU #define BPMP_SUSPEND_ENTRY 0xF00DCAFEU /* requests serviced by the bpmp */ #define MRQ_PING 0 #define MRQ_QUERY_TAG 1 #define MRQ_DO_IDLE 2 #define MRQ_TOLERATE_IDLE 3 #define MRQ_MODULE_LOAD 4 #define MRQ_MODULE_UNLOAD 5 #define MRQ_SWITCH_CLUSTER 6 #define MRQ_TRACE_MODIFY 7 #define MRQ_WRITE_TRACE 8 #define MRQ_THREADED_PING 9 #define MRQ_CPUIDLE_USAGE 10 #define MRQ_MODULE_MAIL 11 #define MRQ_SCX_ENABLE 12 #define MRQ_BPMPIDLE_USAGE 14 #define MRQ_HEAP_USAGE 15 #define MRQ_SCLK_SKIP_SET_RATE 16 #define MRQ_ENABLE_SUSPEND 17 #define MRQ_PASR_MASK 18 #define MRQ_DEBUGFS 19 #define MRQ_THERMAL 27 /* Tegra PM states as known to BPMP */ #define TEGRA_PM_CC1 9 #define TEGRA_PM_CC4 12 #define TEGRA_PM_CC6 14 #define TEGRA_PM_CC7 15 #define TEGRA_PM_SC1 17 #define TEGRA_PM_SC2 18 #define TEGRA_PM_SC3 19 #define TEGRA_PM_SC4 20 #define TEGRA_PM_SC7 23 /* flag to indicate if entry into a CCx power state is allowed */ #define BPMP_CCx_ALLOWED 0U /* number of communication channels to interact with the bpmp */ #define NR_CHANNELS 4U /* flag to ask bpmp to acknowledge command packet */ #define NO_ACK (0U << 0U) #define DO_ACK (1U << 0U) /* size of the command/response data */ #define MSG_DATA_MAX_SZ 120U /** * command/response packet to/from the bpmp * * command * ------- * code: MRQ_* command * flags: DO_ACK or NO_ACK * data: * [0] = cpu # * [1] = cluster power state (TEGRA_PM_CCx) * [2] = system power state (TEGRA_PM_SCx) * * response * --------- * code: error code * flags: not used * data: * [0-3] = response value */ typedef struct mb_data { int32_t code; uint32_t flags; uint8_t data[MSG_DATA_MAX_SZ]; } mb_data_t; /** * Function to initialise the interface with the bpmp */ int tegra_bpmp_init(void); /** * Function to suspend the interface with the bpmp */ void tegra_bpmp_suspend(void); /** * Function to resume the interface with the bpmp */ void tegra_bpmp_resume(void); /** * Handler to send a MRQ_* command to the bpmp */ int32_t tegra_bpmp_send_receive_atomic(int mrq, const void *ob_data, int ob_sz, void *ib_data, int ib_sz); #endif /* BPMP_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/drivers/bpmp_ipc.h000066400000000000000000000016661355360272700255010ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __BPMP_IPC_H__ #define __BPMP_IPC_H__ #include #include #include /** * Currently supported reset identifiers */ #define TEGRA_RESET_ID_XUSB_PADCTL U(114) #define TEGRA_RESET_ID_GPCDMA U(70) /** * Clock identifier for the SE device */ #define TEGRA_CLK_SE U(124) /** * Function to initialise the IPC with the bpmp */ int32_t tegra_bpmp_ipc_init(void); /** * Handler to reset a module */ int32_t tegra_bpmp_ipc_reset_module(uint32_t rst_id); /** * Handler to enable clock to a module. Only SE device is * supported for now. */ int tegra_bpmp_ipc_enable_clock(uint32_t clk_id); /** * Handler to disable clock to a module. Only SE device is * supported for now. */ int tegra_bpmp_ipc_disable_clock(uint32_t clk_id); #endif /* __BPMP_IPC_H__ */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/drivers/flowctrl.h000066400000000000000000000064531355360272700255430ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef FLOWCTRL_H #define FLOWCTRL_H #include #include #define FLOWCTRL_HALT_CPU0_EVENTS (0x0U) #define FLOWCTRL_WAITEVENT (2U << 29) #define FLOWCTRL_WAIT_FOR_INTERRUPT (4U << 29) #define FLOWCTRL_JTAG_RESUME (1U << 28) #define FLOWCTRL_HALT_SCLK (1U << 27) #define FLOWCTRL_HALT_LIC_IRQ (1U << 11) #define FLOWCTRL_HALT_LIC_FIQ (1U << 10) #define FLOWCTRL_HALT_GIC_IRQ (1U << 9) #define FLOWCTRL_HALT_GIC_FIQ (1U << 8) #define FLOWCTRL_HALT_BPMP_EVENTS (0x4U) #define FLOWCTRL_CPU0_CSR (0x8U) #define FLOWCTRL_CSR_HALT_MASK (1U << 22) #define FLOWCTRL_CSR_PWR_OFF_STS (1U << 16) #define FLOWCTRL_CSR_INTR_FLAG (1U << 15) #define FLOWCTRL_CSR_EVENT_FLAG (1U << 14) #define FLOWCTRL_CSR_IMMEDIATE_WAKE (1U << 3) #define FLOWCTRL_CSR_ENABLE (1U << 0) #define FLOWCTRL_HALT_CPU1_EVENTS (0x14U) #define FLOWCTRL_CPU1_CSR (0x18U) #define FLOW_CTLR_FLOW_DBG_QUAL (0x50U) #define FLOWCTRL_FIQ2CCPLEX_ENABLE (1U << 28) #define FLOWCTRL_FC_SEQ_INTERCEPT (0x5cU) #define INTERCEPT_IRQ_PENDING (0xffU) #define INTERCEPT_HVC (U(1) << 21) #define INTERCEPT_ENTRY_CC4 (U(1) << 20) #define INTERCEPT_ENTRY_PG_NONCPU (U(1) << 19) #define INTERCEPT_EXIT_PG_NONCPU (U(1) << 18) #define INTERCEPT_ENTRY_RG_CPU (U(1) << 17) #define INTERCEPT_EXIT_RG_CPU (U(1) << 16) #define INTERCEPT_ENTRY_PG_CORE0 (U(1) << 15) #define INTERCEPT_EXIT_PG_CORE0 (U(1) << 14) #define INTERCEPT_ENTRY_PG_CORE1 (U(1) << 13) #define INTERCEPT_EXIT_PG_CORE1 (U(1) << 12) #define INTERCEPT_ENTRY_PG_CORE2 (U(1) << 11) #define INTERCEPT_EXIT_PG_CORE2 (U(1) << 10) #define INTERCEPT_ENTRY_PG_CORE3 (U(1) << 9) #define INTERCEPT_EXIT_PG_CORE3 (U(1) << 8) #define INTERRUPT_PENDING_NONCPU (U(1) << 7) #define INTERRUPT_PENDING_CRAIL (U(1) << 6) #define INTERRUPT_PENDING_CORE0 (U(1) << 5) #define INTERRUPT_PENDING_CORE1 (U(1) << 4) #define INTERRUPT_PENDING_CORE2 (U(1) << 3) #define INTERRUPT_PENDING_CORE3 (U(1) << 2) #define CC4_INTERRUPT_PENDING (U(1) << 1) #define HVC_INTERRUPT_PENDING (U(1) << 0) #define FLOWCTRL_CC4_CORE0_CTRL (0x6cU) #define FLOWCTRL_WAIT_WFI_BITMAP (0x100U) #define FLOWCTRL_L2_FLUSH_CONTROL (0x94U) #define FLOWCTRL_BPMP_CLUSTER_CONTROL (0x98U) #define FLOWCTRL_BPMP_CLUSTER_PWRON_LOCK (1U << 2) #define FLOWCTRL_ENABLE_EXT 12U #define FLOWCTRL_ENABLE_EXT_MASK 3U #define FLOWCTRL_PG_CPU_NONCPU 0x1U #define FLOWCTRL_TURNOFF_CPURAIL 0x2U static inline uint32_t tegra_fc_read_32(uint32_t off) { return mmio_read_32(TEGRA_FLOWCTRL_BASE + off); } static inline void tegra_fc_write_32(uint32_t off, uint32_t val) { mmio_write_32(TEGRA_FLOWCTRL_BASE + off, val); } void tegra_fc_bpmp_on(uint32_t entrypoint); void tegra_fc_bpmp_off(void); void tegra_fc_ccplex_pgexit_lock(void); void tegra_fc_ccplex_pgexit_unlock(void); void tegra_fc_cluster_idle(uint32_t midr); void tegra_fc_cpu_powerdn(uint32_t mpidr); void tegra_fc_cluster_powerdn(uint32_t midr); void tegra_fc_cpu_on(int cpu); void tegra_fc_cpu_off(int cpu); void tegra_fc_disable_fiq_to_ccplex_routing(void); void tegra_fc_enable_fiq_to_ccplex_routing(void); bool tegra_fc_is_ccx_allowed(void); void tegra_fc_lock_active_cluster(void); void tegra_fc_soc_powerdn(uint32_t midr); #endif /* FLOWCTRL_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/drivers/gpcdma.h000066400000000000000000000005661355360272700251410ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __GPCDMA_H__ #define __GPCDMA_H__ #include void tegra_gpcdma_memcpy(uint64_t dst_addr, uint64_t src_addr, uint32_t num_bytes); void tegra_gpcdma_zeromem(uint64_t dst_addr, uint32_t num_bytes); #endif /* __GPCDMA_H__ */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/drivers/mce.h000066400000000000000000000044341355360272700244500ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MCE_H #define MCE_H #include #include /******************************************************************************* * MCE commands ******************************************************************************/ typedef enum mce_cmd { MCE_CMD_ENTER_CSTATE = 0U, MCE_CMD_UPDATE_CSTATE_INFO = 1U, MCE_CMD_UPDATE_CROSSOVER_TIME = 2U, MCE_CMD_READ_CSTATE_STATS = 3U, MCE_CMD_WRITE_CSTATE_STATS = 4U, MCE_CMD_IS_SC7_ALLOWED = 5U, MCE_CMD_ONLINE_CORE = 6U, MCE_CMD_CC3_CTRL = 7U, MCE_CMD_ECHO_DATA = 8U, MCE_CMD_READ_VERSIONS = 9U, MCE_CMD_ENUM_FEATURES = 10U, MCE_CMD_ROC_FLUSH_CACHE_TRBITS = 11U, MCE_CMD_ENUM_READ_MCA = 12U, MCE_CMD_ENUM_WRITE_MCA = 13U, MCE_CMD_ROC_FLUSH_CACHE = 14U, MCE_CMD_ROC_CLEAN_CACHE = 15U, MCE_CMD_ENABLE_LATIC = 16U, MCE_CMD_UNCORE_PERFMON_REQ = 17U, MCE_CMD_MISC_CCPLEX = 18U, MCE_CMD_IS_CCX_ALLOWED = 0xFEU, MCE_CMD_MAX = 0xFFU, } mce_cmd_t; #define MCE_CMD_MASK 0xFFU /******************************************************************************* * Timeout value used to powerdown a core ******************************************************************************/ #define MCE_CORE_SLEEP_TIME_INFINITE 0xFFFFFFFFU /******************************************************************************* * Struct to prepare UPDATE_CSTATE_INFO request ******************************************************************************/ typedef struct mce_cstate_info { /* cluster cstate value */ uint32_t cluster; /* ccplex cstate value */ uint32_t ccplex; /* system cstate value */ uint32_t system; /* force system state? */ uint8_t system_state_force; /* wake mask value */ uint32_t wake_mask; /* update the wake mask? */ uint8_t update_wake_mask; } mce_cstate_info_t; /* public interfaces */ int mce_command_handler(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2); int mce_update_reset_vector(void); int mce_update_gsc_videomem(void); int mce_update_gsc_tzdram(void); int mce_update_gsc_tzram(void); __dead2 void mce_enter_ccplex_state(uint32_t state_idx); void mce_update_cstate_info(const mce_cstate_info_t *cstate); void mce_verify_firmware_version(void); #endif /* MCE_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/drivers/memctrl.h000066400000000000000000000011301355360272700253350ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MEMCTRL_H #define MEMCTRL_H void tegra_memctrl_setup(void); void tegra_memctrl_restore_settings(void); void tegra_memctrl_tzdram_setup(uint64_t phys_base, uint32_t size_in_bytes); void tegra_memctrl_tzram_setup(uint64_t phys_base, uint32_t size_in_bytes); void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes); void tegra_memctrl_disable_ahb_redirection(void); void tegra_memctrl_clear_pending_interrupts(void); #endif /* MEMCTRL_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/drivers/memctrl_v1.h000066400000000000000000000032631355360272700257540ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MEMCTRL_V1_H #define MEMCTRL_V1_H #include #include /* SMMU registers */ #define MC_SMMU_CONFIG_0 0x10U #define MC_SMMU_CONFIG_0_SMMU_ENABLE_DISABLE 0U #define MC_SMMU_CONFIG_0_SMMU_ENABLE_ENABLE 1U #define MC_SMMU_TLB_CONFIG_0 0x14U #define MC_SMMU_TLB_CONFIG_0_RESET_VAL 0x20000010U #define MC_SMMU_PTC_CONFIG_0 0x18U #define MC_SMMU_PTC_CONFIG_0_RESET_VAL 0x2000003fU #define MC_SMMU_TLB_FLUSH_0 0x30U #define TLB_FLUSH_VA_MATCH_ALL 0U #define TLB_FLUSH_ASID_MATCH_DISABLE 0U #define TLB_FLUSH_ASID_MATCH_SHIFT 31U #define MC_SMMU_TLB_FLUSH_ALL \ (TLB_FLUSH_VA_MATCH_ALL | \ (TLB_FLUSH_ASID_MATCH_DISABLE << TLB_FLUSH_ASID_MATCH_SHIFT)) #define MC_SMMU_PTC_FLUSH_0 0x34U #define MC_SMMU_PTC_FLUSH_ALL 0U #define MC_SMMU_ASID_SECURITY_0 0x38U #define MC_SMMU_ASID_SECURITY 0U #define MC_SMMU_TRANSLATION_ENABLE_0_0 0x228U #define MC_SMMU_TRANSLATION_ENABLE_1_0 0x22cU #define MC_SMMU_TRANSLATION_ENABLE_2_0 0x230U #define MC_SMMU_TRANSLATION_ENABLE_3_0 0x234U #define MC_SMMU_TRANSLATION_ENABLE_4_0 0xb98U #define MC_SMMU_TRANSLATION_ENABLE (~0) /* MC IRAM aperture registers */ #define MC_IRAM_BASE_LO 0x65CU #define MC_IRAM_TOP_LO 0x660U #define MC_IRAM_BASE_TOP_HI 0x980U #define MC_IRAM_REG_CTRL 0x964U #define MC_DISABLE_IRAM_CFG_WRITES 1U static inline uint32_t tegra_mc_read_32(uint32_t off) { return mmio_read_32(TEGRA_MC_BASE + off); } static inline void tegra_mc_write_32(uint32_t off, uint32_t val) { mmio_write_32(TEGRA_MC_BASE + off, val); } #endif /* MEMCTRL_V1_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/drivers/memctrl_v2.h000066400000000000000000000145251355360272700257600ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MEMCTRL_V2_H #define MEMCTRL_V2_H #include #ifndef __ASSEMBLER__ #include #include /******************************************************************************* * Structure to hold the transaction override settings to use to override * client inputs ******************************************************************************/ typedef struct mc_txn_override_cfg { uint32_t offset; uint8_t cgid_tag; } mc_txn_override_cfg_t; #define mc_make_txn_override_cfg(off, val) \ { \ .offset = MC_TXN_OVERRIDE_CONFIG_ ## off, \ .cgid_tag = MC_TXN_OVERRIDE_ ## val \ } /******************************************************************************* * Structure to hold the Stream ID to use to override client inputs ******************************************************************************/ typedef struct mc_streamid_override_cfg { uint32_t offset; uint8_t stream_id; } mc_streamid_override_cfg_t; /******************************************************************************* * Structure to hold the Stream ID Security Configuration settings ******************************************************************************/ typedef struct mc_streamid_security_cfg { char *name; uint32_t offset; int override_enable; int override_client_inputs; int override_client_ns_flag; } mc_streamid_security_cfg_t; #define OVERRIDE_DISABLE 1U #define OVERRIDE_ENABLE 0U #define CLIENT_FLAG_SECURE 0U #define CLIENT_FLAG_NON_SECURE 1U #define CLIENT_INPUTS_OVERRIDE 1U #define CLIENT_INPUTS_NO_OVERRIDE 0U /******************************************************************************* * StreamID to indicate no SMMU translations (requests to be steered on the * SMMU bypass path) ******************************************************************************/ #define MC_STREAM_ID_MAX 0x7FU /******************************************************************************* * Memory Controller SMMU Bypass config register ******************************************************************************/ #define MC_SMMU_BYPASS_CONFIG 0x1820U #define MC_SMMU_BYPASS_CTRL_MASK 0x3U #define MC_SMMU_BYPASS_CTRL_SHIFT 0U #define MC_SMMU_CTRL_TBU_BYPASS_ALL (0U << MC_SMMU_BYPASS_CTRL_SHIFT) #define MC_SMMU_CTRL_TBU_RSVD (1U << MC_SMMU_BYPASS_CTRL_SHIFT) #define MC_SMMU_CTRL_TBU_BYPASS_SPL_STREAMID (2U << MC_SMMU_BYPASS_CTRL_SHIFT) #define MC_SMMU_CTRL_TBU_BYPASS_NONE (3U << MC_SMMU_BYPASS_CTRL_SHIFT) #define MC_SMMU_BYPASS_CONFIG_WRITE_ACCESS_BIT (1U << 31) #define MC_SMMU_BYPASS_CONFIG_SETTINGS (MC_SMMU_BYPASS_CONFIG_WRITE_ACCESS_BIT | \ MC_SMMU_CTRL_TBU_BYPASS_SPL_STREAMID) #define mc_make_sec_cfg(off, ns, ovrrd, access) \ { \ .name = # off, \ .offset = MC_STREAMID_OVERRIDE_TO_SECURITY_CFG( \ MC_STREAMID_OVERRIDE_CFG_ ## off), \ .override_client_ns_flag = CLIENT_FLAG_ ## ns, \ .override_client_inputs = CLIENT_INPUTS_ ## ovrrd, \ .override_enable = OVERRIDE_ ## access \ } /******************************************************************************* * Structure to hold Memory Controller's Configuration settings ******************************************************************************/ typedef struct tegra_mc_settings { const uint32_t *streamid_override_cfg; uint32_t num_streamid_override_cfgs; const mc_streamid_security_cfg_t *streamid_security_cfg; uint32_t num_streamid_security_cfgs; const mc_txn_override_cfg_t *txn_override_cfg; uint32_t num_txn_override_cfgs; void (*reconfig_mss_clients)(void); void (*set_txn_overrides)(void); } tegra_mc_settings_t; static inline uint32_t tegra_mc_read_32(uint32_t off) { return mmio_read_32(TEGRA_MC_BASE + off); } static inline void tegra_mc_write_32(uint32_t off, uint32_t val) { mmio_write_32(TEGRA_MC_BASE + off, val); } static inline uint32_t tegra_mc_streamid_read_32(uint32_t off) { return mmio_read_32(TEGRA_MC_STREAMID_BASE + off); } static inline void tegra_mc_streamid_write_32(uint32_t off, uint32_t val) { mmio_write_32(TEGRA_MC_STREAMID_BASE + off, val); } #define mc_set_pcfifo_unordered_boot_so_mss(id, client) \ ((uint32_t)~MC_PCFIFO_CLIENT_CONFIG##id##_PCFIFO_##client##_MASK | \ MC_PCFIFO_CLIENT_CONFIG##id##_PCFIFO_##client##_UNORDERED) #define mc_set_pcfifo_ordered_boot_so_mss(id, client) \ MC_PCFIFO_CLIENT_CONFIG##id##_PCFIFO_##client##_ORDERED #define mc_set_tsa_passthrough(client) \ { \ mmio_write_32(TEGRA_TSA_BASE + TSA_CONFIG_STATIC0_CSW_##client, \ (TSA_CONFIG_STATIC0_CSW_##client##_RESET & \ (uint32_t)~TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_MASK) | \ (uint32_t)TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_PASTHRU); \ } #define mc_set_tsa_w_passthrough(client) \ { \ mmio_write_32(TEGRA_TSA_BASE + TSA_CONFIG_STATIC0_CSW_##client, \ (TSA_CONFIG_STATIC0_CSW_RESET_W & \ (uint32_t)~TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_MASK) | \ (uint32_t)TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_PASTHRU); \ } #define mc_set_tsa_r_passthrough(client) \ { \ mmio_write_32(TEGRA_TSA_BASE + TSA_CONFIG_STATIC0_CSR_##client, \ (TSA_CONFIG_STATIC0_CSR_RESET_R & \ (uint32_t)~TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_MASK) | \ (uint32_t)TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_PASTHRU); \ } #define mc_set_txn_override(client, normal_axi_id, so_dev_axi_id, normal_override, so_dev_override) \ { \ tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_##client, \ MC_TXN_OVERRIDE_##normal_axi_id | \ MC_TXN_OVERRIDE_CONFIG_COH_PATH_##so_dev_override##_SO_DEV | \ MC_TXN_OVERRIDE_CONFIG_COH_PATH_##normal_override##_NORMAL | \ MC_TXN_OVERRIDE_CONFIG_CGID_##so_dev_axi_id); \ } /******************************************************************************* * Handler to read memory configuration settings * * Implemented by SoCs under tegra/soc/txxx ******************************************************************************/ tegra_mc_settings_t *tegra_get_mc_settings(void); /******************************************************************************* * Handler to program the scratch registers with TZDRAM settings for the * resume firmware. * * Implemented by SoCs under tegra/soc/txxx ******************************************************************************/ void plat_memctrl_tzdram_setup(uint64_t phys_base, uint64_t size_in_bytes); #endif /* __ASSEMBLER__ */ #endif /* MEMCTRL_V2_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/drivers/pmc.h000066400000000000000000000033731355360272700244640ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PMC_H #define PMC_H #include #include #include #include #define PMC_CONFIG U(0x0) #define PMC_IO_DPD_SAMPLE U(0x20) #define PMC_DPD_ENABLE_0 U(0x24) #define PMC_PWRGATE_STATUS U(0x38) #define PMC_PWRGATE_TOGGLE U(0x30) #define PMC_SECURE_SCRATCH0 U(0xb0) #define PMC_SECURE_SCRATCH5 U(0xc4) #define PMC_CRYPTO_OP_0 U(0xf4) #define PMC_TOGGLE_START U(0x100) #define PMC_SCRATCH39 U(0x138) #define PMC_SCRATCH41 U(0x140) #define PMC_SECURE_SCRATCH6 U(0x224) #define PMC_SECURE_SCRATCH7 U(0x228) #define PMC_SECURE_DISABLE2 U(0x2c4) #define PMC_SECURE_DISABLE2_WRITE22_ON (U(1) << 28) #define PMC_SECURE_SCRATCH8 U(0x300) #define PMC_SECURE_SCRATCH79 U(0x41c) #define PMC_FUSE_CONTROL_0 U(0x450) #define PMC_SECURE_SCRATCH22 U(0x338) #define PMC_SECURE_DISABLE3 U(0x2d8) #define PMC_SECURE_DISABLE3_WRITE34_ON (U(1) << 20) #define PMC_SECURE_DISABLE3_WRITE35_ON (U(1) << 22) #define PMC_SECURE_SCRATCH34 U(0x368) #define PMC_SECURE_SCRATCH35 U(0x36c) #define PMC_SECURE_SCRATCH80 U(0xa98) #define PMC_SECURE_SCRATCH119 U(0xb34) #define PMC_SCRATCH201 U(0x844) static inline uint32_t tegra_pmc_read_32(uint32_t off) { return mmio_read_32(TEGRA_PMC_BASE + off); } static inline void tegra_pmc_write_32(uint32_t off, uint32_t val) { mmio_write_32(TEGRA_PMC_BASE + off, val); } void tegra_pmc_cpu_on(int32_t cpu); void tegra_pmc_cpu_setup(uint64_t reset_addr); bool tegra_pmc_is_last_on_cpu(void); void tegra_pmc_lock_cpu_vectors(void); void tegra_pmc_resume(void); __dead2 void tegra_pmc_system_reset(void); #endif /* PMC_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/drivers/security_engine.h000066400000000000000000000032431355360272700270750ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SECURITY_ENGINE_H #define SECURITY_ENGINE_H /******************************************************************************* * Structure definition ******************************************************************************/ /* Security Engine Linked List */ struct tegra_se_ll { /* DMA buffer address */ uint32_t addr; /* Data length in DMA buffer */ uint32_t data_len; }; #define SE_LL_MAX_BUFFER_NUM 4 typedef struct tegra_se_io_lst { volatile uint32_t last_buff_num; volatile struct tegra_se_ll buffer[SE_LL_MAX_BUFFER_NUM]; } tegra_se_io_lst_t __attribute__((aligned(4))); /* SE device structure */ typedef struct tegra_se_dev { /* Security Engine ID */ const int se_num; /* SE base address */ const uint64_t se_base; /* SE context size in AES blocks */ const uint32_t ctx_size_blks; /* pointer to source linked list buffer */ tegra_se_io_lst_t *src_ll_buf; /* pointer to destination linked list buffer */ tegra_se_io_lst_t *dst_ll_buf; /* LP context buffer pointer */ uint32_t *ctx_save_buf; } tegra_se_dev_t; /* PKA1 device structure */ typedef struct tegra_pka_dev { /* PKA1 base address */ uint64_t pka_base; } tegra_pka_dev_t; /******************************************************************************* * Public interface ******************************************************************************/ void tegra_se_init(void); int tegra_se_suspend(void); void tegra_se_resume(void); int tegra_se_save_tzram(void); #endif /* SECURITY_ENGINE_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/drivers/smmu.h000066400000000000000000000742141355360272700246700ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SMMU_H #define SMMU_H #include #include #include /******************************************************************************* * SMMU Register constants ******************************************************************************/ #define SMMU_CBn_SCTLR (0x0U) #define SMMU_CBn_SCTLR_STAGE2 (0x0U) #define SMMU_CBn_ACTLR (0x4U) #define SMMU_CBn_RESUME (0x8U) #define SMMU_CBn_TCR2 (0x10U) #define SMMU_CBn_TTBR0_LO (0x20U) #define SMMU_CBn_TTBR0_HI (0x24U) #define SMMU_CBn_TTBR1_LO (0x28U) #define SMMU_CBn_TTBR1_HI (0x2cU) #define SMMU_CBn_TCR_LPAE (0x30U) #define SMMU_CBn_TCR (0x30U) #define SMMU_CBn_TCR_EAE_1 (0x30U) #define SMMU_CBn_TCR (0x30U) #define SMMU_CBn_CONTEXTIDR (0x34U) #define SMMU_CBn_CONTEXTIDR_EAE_1 (0x34U) #define SMMU_CBn_PRRR_MAIR0 (0x38U) #define SMMU_CBn_NMRR_MAIR1 (0x3cU) #define SMMU_CBn_SMMU_CBn_PAR (0x50U) #define SMMU_CBn_SMMU_CBn_PAR0 (0x50U) #define SMMU_CBn_SMMU_CBn_PAR1 (0x54U) /* SMMU_CBn_SMMU_CBn_PAR0_Fault (0x50U) */ /* SMMU_CBn_SMMU_CBn_PAR0_Fault (0x54U) */ #define SMMU_CBn_FSR (0x58U) #define SMMU_CBn_FSRRESTORE (0x5cU) #define SMMU_CBn_FAR_LO (0x60U) #define SMMU_CBn_FAR_HI (0x64U) #define SMMU_CBn_FSYNR0 (0x68U) #define SMMU_CBn_IPAFAR_LO (0x70U) #define SMMU_CBn_IPAFAR_HI (0x74U) #define SMMU_CBn_TLBIVA_LO (0x600U) #define SMMU_CBn_TLBIVA_HI (0x604U) #define SMMU_CBn_TLBIVA_AARCH_32 (0x600U) #define SMMU_CBn_TLBIVAA_LO (0x608U) #define SMMU_CBn_TLBIVAA_HI (0x60cU) #define SMMU_CBn_TLBIVAA_AARCH_32 (0x608U) #define SMMU_CBn_TLBIASID (0x610U) #define SMMU_CBn_TLBIALL (0x618U) #define SMMU_CBn_TLBIVAL_LO (0x620U) #define SMMU_CBn_TLBIVAL_HI (0x624U) #define SMMU_CBn_TLBIVAL_AARCH_32 (0x618U) #define SMMU_CBn_TLBIVAAL_LO (0x628U) #define SMMU_CBn_TLBIVAAL_HI (0x62cU) #define SMMU_CBn_TLBIVAAL_AARCH_32 (0x628U) #define SMMU_CBn_TLBIIPAS2_LO (0x630U) #define SMMU_CBn_TLBIIPAS2_HI (0x634U) #define SMMU_CBn_TLBIIPAS2L_LO (0x638U) #define SMMU_CBn_TLBIIPAS2L_HI (0x63cU) #define SMMU_CBn_TLBSYNC (0x7f0U) #define SMMU_CBn_TLBSTATUS (0x7f4U) #define SMMU_CBn_ATSR (0x800U) #define SMMU_CBn_PMEVCNTR0 (0xe00U) #define SMMU_CBn_PMEVCNTR1 (0xe04U) #define SMMU_CBn_PMEVCNTR2 (0xe08U) #define SMMU_CBn_PMEVCNTR3 (0xe0cU) #define SMMU_CBn_PMEVTYPER0 (0xe80U) #define SMMU_CBn_PMEVTYPER1 (0xe84U) #define SMMU_CBn_PMEVTYPER2 (0xe88U) #define SMMU_CBn_PMEVTYPER3 (0xe8cU) #define SMMU_CBn_PMCFGR (0xf00U) #define SMMU_CBn_PMCR (0xf04U) #define SMMU_CBn_PMCEID (0xf20U) #define SMMU_CBn_PMCNTENSE (0xf40U) #define SMMU_CBn_PMCNTENCLR (0xf44U) #define SMMU_CBn_PMCNTENSET (0xf48U) #define SMMU_CBn_PMINTENCLR (0xf4cU) #define SMMU_CBn_PMOVSCLR (0xf50U) #define SMMU_CBn_PMOVSSET (0xf58U) #define SMMU_CBn_PMAUTHSTATUS (0xfb8U) #define SMMU_GNSR0_CR0 (0x0U) #define SMMU_GNSR0_CR2 (0x8U) #define SMMU_GNSR0_ACR (0x10U) #define SMMU_GNSR0_IDR0 (0x20U) #define SMMU_GNSR0_IDR1 (0x24U) #define SMMU_GNSR0_IDR2 (0x28U) #define SMMU_GNSR0_IDR7 (0x3cU) #define SMMU_GNSR0_GFAR_LO (0x40U) #define SMMU_GNSR0_GFAR_HI (0x44U) #define SMMU_GNSR0_GFSR (0x48U) #define SMMU_GNSR0_GFSRRESTORE (0x4cU) #define SMMU_GNSR0_GFSYNR0 (0x50U) #define SMMU_GNSR0_GFSYNR1 (0x54U) #define SMMU_GNSR0_GFSYNR1_v2 (0x54U) #define SMMU_GNSR0_TLBIVMID (0x64U) #define SMMU_GNSR0_TLBIALLNSNH (0x68U) #define SMMU_GNSR0_TLBIALLH (0x6cU) #define SMMU_GNSR0_TLBGSYNC (0x70U) #define SMMU_GNSR0_TLBGSTATUS (0x74U) #define SMMU_GNSR0_TLBIVAH_LO (0x78U) #define SMMU_GNSR0_TLBIVALH64_LO (0xb0U) #define SMMU_GNSR0_TLBIVALH64_HI (0xb4U) #define SMMU_GNSR0_TLBIVMIDS1 (0xb8U) #define SMMU_GNSR0_TLBIVAH64_LO (0xc0U) #define SMMU_GNSR0_TLBIVAH64_HI (0xc4U) #define SMMU_GNSR0_SMR0 (0x800U) #define SMMU_GNSR0_SMRn (0x800U) #define SMMU_GNSR0_SMR1 (0x804U) #define SMMU_GNSR0_SMR2 (0x808U) #define SMMU_GNSR0_SMR3 (0x80cU) #define SMMU_GNSR0_SMR4 (0x810U) #define SMMU_GNSR0_SMR5 (0x814U) #define SMMU_GNSR0_SMR6 (0x818U) #define SMMU_GNSR0_SMR7 (0x81cU) #define SMMU_GNSR0_SMR8 (0x820U) #define SMMU_GNSR0_SMR9 (0x824U) #define SMMU_GNSR0_SMR10 (0x828U) #define SMMU_GNSR0_SMR11 (0x82cU) #define SMMU_GNSR0_SMR12 (0x830U) #define SMMU_GNSR0_SMR13 (0x834U) #define SMMU_GNSR0_SMR14 (0x838U) #define SMMU_GNSR0_SMR15 (0x83cU) #define SMMU_GNSR0_SMR16 (0x840U) #define SMMU_GNSR0_SMR17 (0x844U) #define SMMU_GNSR0_SMR18 (0x848U) #define SMMU_GNSR0_SMR19 (0x84cU) #define SMMU_GNSR0_SMR20 (0x850U) #define SMMU_GNSR0_SMR21 (0x854U) #define SMMU_GNSR0_SMR22 (0x858U) #define SMMU_GNSR0_SMR23 (0x85cU) #define SMMU_GNSR0_SMR24 (0x860U) #define SMMU_GNSR0_SMR25 (0x864U) #define SMMU_GNSR0_SMR26 (0x868U) #define SMMU_GNSR0_SMR27 (0x86cU) #define SMMU_GNSR0_SMR28 (0x870U) #define SMMU_GNSR0_SMR29 (0x874U) #define SMMU_GNSR0_SMR30 (0x878U) #define SMMU_GNSR0_SMR31 (0x87cU) #define SMMU_GNSR0_SMR32 (0x880U) #define SMMU_GNSR0_SMR33 (0x884U) #define SMMU_GNSR0_SMR34 (0x888U) #define SMMU_GNSR0_SMR35 (0x88cU) #define SMMU_GNSR0_SMR36 (0x890U) #define SMMU_GNSR0_SMR37 (0x894U) #define SMMU_GNSR0_SMR38 (0x898U) #define SMMU_GNSR0_SMR39 (0x89cU) #define SMMU_GNSR0_SMR40 (0x8a0U) #define SMMU_GNSR0_SMR41 (0x8a4U) #define SMMU_GNSR0_SMR42 (0x8a8U) #define SMMU_GNSR0_SMR43 (0x8acU) #define SMMU_GNSR0_SMR44 (0x8b0U) #define SMMU_GNSR0_SMR45 (0x8b4U) #define SMMU_GNSR0_SMR46 (0x8b8U) #define SMMU_GNSR0_SMR47 (0x8bcU) #define SMMU_GNSR0_SMR48 (0x8c0U) #define SMMU_GNSR0_SMR49 (0x8c4U) #define SMMU_GNSR0_SMR50 (0x8c8U) #define SMMU_GNSR0_SMR51 (0x8ccU) #define SMMU_GNSR0_SMR52 (0x8d0U) #define SMMU_GNSR0_SMR53 (0x8d4U) #define SMMU_GNSR0_SMR54 (0x8d8U) #define SMMU_GNSR0_SMR55 (0x8dcU) #define SMMU_GNSR0_SMR56 (0x8e0U) #define SMMU_GNSR0_SMR57 (0x8e4U) #define SMMU_GNSR0_SMR58 (0x8e8U) #define SMMU_GNSR0_SMR59 (0x8ecU) #define SMMU_GNSR0_SMR60 (0x8f0U) #define SMMU_GNSR0_SMR61 (0x8f4U) #define SMMU_GNSR0_SMR62 (0x8f8U) #define SMMU_GNSR0_SMR63 (0x8fcU) #define SMMU_GNSR0_SMR64 (0x900U) #define SMMU_GNSR0_SMR65 (0x904U) #define SMMU_GNSR0_SMR66 (0x908U) #define SMMU_GNSR0_SMR67 (0x90cU) #define SMMU_GNSR0_SMR68 (0x910U) #define SMMU_GNSR0_SMR69 (0x914U) #define SMMU_GNSR0_SMR70 (0x918U) #define SMMU_GNSR0_SMR71 (0x91cU) #define SMMU_GNSR0_SMR72 (0x920U) #define SMMU_GNSR0_SMR73 (0x924U) #define SMMU_GNSR0_SMR74 (0x928U) #define SMMU_GNSR0_SMR75 (0x92cU) #define SMMU_GNSR0_SMR76 (0x930U) #define SMMU_GNSR0_SMR77 (0x934U) #define SMMU_GNSR0_SMR78 (0x938U) #define SMMU_GNSR0_SMR79 (0x93cU) #define SMMU_GNSR0_SMR80 (0x940U) #define SMMU_GNSR0_SMR81 (0x944U) #define SMMU_GNSR0_SMR82 (0x948U) #define SMMU_GNSR0_SMR83 (0x94cU) #define SMMU_GNSR0_SMR84 (0x950U) #define SMMU_GNSR0_SMR85 (0x954U) #define SMMU_GNSR0_SMR86 (0x958U) #define SMMU_GNSR0_SMR87 (0x95cU) #define SMMU_GNSR0_SMR88 (0x960U) #define SMMU_GNSR0_SMR89 (0x964U) #define SMMU_GNSR0_SMR90 (0x968U) #define SMMU_GNSR0_SMR91 (0x96cU) #define SMMU_GNSR0_SMR92 (0x970U) #define SMMU_GNSR0_SMR93 (0x974U) #define SMMU_GNSR0_SMR94 (0x978U) #define SMMU_GNSR0_SMR95 (0x97cU) #define SMMU_GNSR0_SMR96 (0x980U) #define SMMU_GNSR0_SMR97 (0x984U) #define SMMU_GNSR0_SMR98 (0x988U) #define SMMU_GNSR0_SMR99 (0x98cU) #define SMMU_GNSR0_SMR100 (0x990U) #define SMMU_GNSR0_SMR101 (0x994U) #define SMMU_GNSR0_SMR102 (0x998U) #define SMMU_GNSR0_SMR103 (0x99cU) #define SMMU_GNSR0_SMR104 (0x9a0U) #define SMMU_GNSR0_SMR105 (0x9a4U) #define SMMU_GNSR0_SMR106 (0x9a8U) #define SMMU_GNSR0_SMR107 (0x9acU) #define SMMU_GNSR0_SMR108 (0x9b0U) #define SMMU_GNSR0_SMR109 (0x9b4U) #define SMMU_GNSR0_SMR110 (0x9b8U) #define SMMU_GNSR0_SMR111 (0x9bcU) #define SMMU_GNSR0_SMR112 (0x9c0U) #define SMMU_GNSR0_SMR113 (0x9c4U) #define SMMU_GNSR0_SMR114 (0x9c8U) #define SMMU_GNSR0_SMR115 (0x9ccU) #define SMMU_GNSR0_SMR116 (0x9d0U) #define SMMU_GNSR0_SMR117 (0x9d4U) #define SMMU_GNSR0_SMR118 (0x9d8U) #define SMMU_GNSR0_SMR119 (0x9dcU) #define SMMU_GNSR0_SMR120 (0x9e0U) #define SMMU_GNSR0_SMR121 (0x9e4U) #define SMMU_GNSR0_SMR122 (0x9e8U) #define SMMU_GNSR0_SMR123 (0x9ecU) #define SMMU_GNSR0_SMR124 (0x9f0U) #define SMMU_GNSR0_SMR125 (0x9f4U) #define SMMU_GNSR0_SMR126 (0x9f8U) #define SMMU_GNSR0_SMR127 (0x9fcU) #define SMMU_GNSR0_S2CR0 (0xc00U) #define SMMU_GNSR0_S2CRn (0xc00U) #define SMMU_GNSR0_S2CRn (0xc00U) #define SMMU_GNSR0_S2CR1 (0xc04U) #define SMMU_GNSR0_S2CR2 (0xc08U) #define SMMU_GNSR0_S2CR3 (0xc0cU) #define SMMU_GNSR0_S2CR4 (0xc10U) #define SMMU_GNSR0_S2CR5 (0xc14U) #define SMMU_GNSR0_S2CR6 (0xc18U) #define SMMU_GNSR0_S2CR7 (0xc1cU) #define SMMU_GNSR0_S2CR8 (0xc20U) #define SMMU_GNSR0_S2CR9 (0xc24U) #define SMMU_GNSR0_S2CR10 (0xc28U) #define SMMU_GNSR0_S2CR11 (0xc2cU) #define SMMU_GNSR0_S2CR12 (0xc30U) #define SMMU_GNSR0_S2CR13 (0xc34U) #define SMMU_GNSR0_S2CR14 (0xc38U) #define SMMU_GNSR0_S2CR15 (0xc3cU) #define SMMU_GNSR0_S2CR16 (0xc40U) #define SMMU_GNSR0_S2CR17 (0xc44U) #define SMMU_GNSR0_S2CR18 (0xc48U) #define SMMU_GNSR0_S2CR19 (0xc4cU) #define SMMU_GNSR0_S2CR20 (0xc50U) #define SMMU_GNSR0_S2CR21 (0xc54U) #define SMMU_GNSR0_S2CR22 (0xc58U) #define SMMU_GNSR0_S2CR23 (0xc5cU) #define SMMU_GNSR0_S2CR24 (0xc60U) #define SMMU_GNSR0_S2CR25 (0xc64U) #define SMMU_GNSR0_S2CR26 (0xc68U) #define SMMU_GNSR0_S2CR27 (0xc6cU) #define SMMU_GNSR0_S2CR28 (0xc70U) #define SMMU_GNSR0_S2CR29 (0xc74U) #define SMMU_GNSR0_S2CR30 (0xc78U) #define SMMU_GNSR0_S2CR31 (0xc7cU) #define SMMU_GNSR0_S2CR32 (0xc80U) #define SMMU_GNSR0_S2CR33 (0xc84U) #define SMMU_GNSR0_S2CR34 (0xc88U) #define SMMU_GNSR0_S2CR35 (0xc8cU) #define SMMU_GNSR0_S2CR36 (0xc90U) #define SMMU_GNSR0_S2CR37 (0xc94U) #define SMMU_GNSR0_S2CR38 (0xc98U) #define SMMU_GNSR0_S2CR39 (0xc9cU) #define SMMU_GNSR0_S2CR40 (0xca0U) #define SMMU_GNSR0_S2CR41 (0xca4U) #define SMMU_GNSR0_S2CR42 (0xca8U) #define SMMU_GNSR0_S2CR43 (0xcacU) #define SMMU_GNSR0_S2CR44 (0xcb0U) #define SMMU_GNSR0_S2CR45 (0xcb4U) #define SMMU_GNSR0_S2CR46 (0xcb8U) #define SMMU_GNSR0_S2CR47 (0xcbcU) #define SMMU_GNSR0_S2CR48 (0xcc0U) #define SMMU_GNSR0_S2CR49 (0xcc4U) #define SMMU_GNSR0_S2CR50 (0xcc8U) #define SMMU_GNSR0_S2CR51 (0xcccU) #define SMMU_GNSR0_S2CR52 (0xcd0U) #define SMMU_GNSR0_S2CR53 (0xcd4U) #define SMMU_GNSR0_S2CR54 (0xcd8U) #define SMMU_GNSR0_S2CR55 (0xcdcU) #define SMMU_GNSR0_S2CR56 (0xce0U) #define SMMU_GNSR0_S2CR57 (0xce4U) #define SMMU_GNSR0_S2CR58 (0xce8U) #define SMMU_GNSR0_S2CR59 (0xcecU) #define SMMU_GNSR0_S2CR60 (0xcf0U) #define SMMU_GNSR0_S2CR61 (0xcf4U) #define SMMU_GNSR0_S2CR62 (0xcf8U) #define SMMU_GNSR0_S2CR63 (0xcfcU) #define SMMU_GNSR0_S2CR64 (0xd00U) #define SMMU_GNSR0_S2CR65 (0xd04U) #define SMMU_GNSR0_S2CR66 (0xd08U) #define SMMU_GNSR0_S2CR67 (0xd0cU) #define SMMU_GNSR0_S2CR68 (0xd10U) #define SMMU_GNSR0_S2CR69 (0xd14U) #define SMMU_GNSR0_S2CR70 (0xd18U) #define SMMU_GNSR0_S2CR71 (0xd1cU) #define SMMU_GNSR0_S2CR72 (0xd20U) #define SMMU_GNSR0_S2CR73 (0xd24U) #define SMMU_GNSR0_S2CR74 (0xd28U) #define SMMU_GNSR0_S2CR75 (0xd2cU) #define SMMU_GNSR0_S2CR76 (0xd30U) #define SMMU_GNSR0_S2CR77 (0xd34U) #define SMMU_GNSR0_S2CR78 (0xd38U) #define SMMU_GNSR0_S2CR79 (0xd3cU) #define SMMU_GNSR0_S2CR80 (0xd40U) #define SMMU_GNSR0_S2CR81 (0xd44U) #define SMMU_GNSR0_S2CR82 (0xd48U) #define SMMU_GNSR0_S2CR83 (0xd4cU) #define SMMU_GNSR0_S2CR84 (0xd50U) #define SMMU_GNSR0_S2CR85 (0xd54U) #define SMMU_GNSR0_S2CR86 (0xd58U) #define SMMU_GNSR0_S2CR87 (0xd5cU) #define SMMU_GNSR0_S2CR88 (0xd60U) #define SMMU_GNSR0_S2CR89 (0xd64U) #define SMMU_GNSR0_S2CR90 (0xd68U) #define SMMU_GNSR0_S2CR91 (0xd6cU) #define SMMU_GNSR0_S2CR92 (0xd70U) #define SMMU_GNSR0_S2CR93 (0xd74U) #define SMMU_GNSR0_S2CR94 (0xd78U) #define SMMU_GNSR0_S2CR95 (0xd7cU) #define SMMU_GNSR0_S2CR96 (0xd80U) #define SMMU_GNSR0_S2CR97 (0xd84U) #define SMMU_GNSR0_S2CR98 (0xd88U) #define SMMU_GNSR0_S2CR99 (0xd8cU) #define SMMU_GNSR0_S2CR100 (0xd90U) #define SMMU_GNSR0_S2CR101 (0xd94U) #define SMMU_GNSR0_S2CR102 (0xd98U) #define SMMU_GNSR0_S2CR103 (0xd9cU) #define SMMU_GNSR0_S2CR104 (0xda0U) #define SMMU_GNSR0_S2CR105 (0xda4U) #define SMMU_GNSR0_S2CR106 (0xda8U) #define SMMU_GNSR0_S2CR107 (0xdacU) #define SMMU_GNSR0_S2CR108 (0xdb0U) #define SMMU_GNSR0_S2CR109 (0xdb4U) #define SMMU_GNSR0_S2CR110 (0xdb8U) #define SMMU_GNSR0_S2CR111 (0xdbcU) #define SMMU_GNSR0_S2CR112 (0xdc0U) #define SMMU_GNSR0_S2CR113 (0xdc4U) #define SMMU_GNSR0_S2CR114 (0xdc8U) #define SMMU_GNSR0_S2CR115 (0xdccU) #define SMMU_GNSR0_S2CR116 (0xdd0U) #define SMMU_GNSR0_S2CR117 (0xdd4U) #define SMMU_GNSR0_S2CR118 (0xdd8U) #define SMMU_GNSR0_S2CR119 (0xddcU) #define SMMU_GNSR0_S2CR120 (0xde0U) #define SMMU_GNSR0_S2CR121 (0xde4U) #define SMMU_GNSR0_S2CR122 (0xde8U) #define SMMU_GNSR0_S2CR123 (0xdecU) #define SMMU_GNSR0_S2CR124 (0xdf0U) #define SMMU_GNSR0_S2CR125 (0xdf4U) #define SMMU_GNSR0_S2CR126 (0xdf8U) #define SMMU_GNSR0_S2CR127 (0xdfcU) #define SMMU_GNSR0_PIDR0 (0xfe0U) #define SMMU_GNSR0_PIDR1 (0xfe4U) #define SMMU_GNSR0_PIDR2 (0xfe8U) #define SMMU_GNSR0_PIDR3 (0xfecU) #define SMMU_GNSR0_PIDR4 (0xfd0U) #define SMMU_GNSR0_PIDR5 (0xfd4U) #define SMMU_GNSR0_PIDR6 (0xfd8U) #define SMMU_GNSR0_PIDR7 (0xfdcU) #define SMMU_GNSR0_CIDR0 (0xff0U) #define SMMU_GNSR0_CIDR1 (0xff4U) #define SMMU_GNSR0_CIDR2 (0xff8U) #define SMMU_GNSR0_CIDR3 (0xffcU) #define SMMU_GNSR1_CBAR0 (0x0U) #define SMMU_GNSR1_CBARn (0x0U) #define SMMU_GNSR1_CBFRSYNRA0 (0x400U) #define SMMU_GNSR1_CBA2R0 (0x800U) #define SMMU_GNSR1_CBAR1 (0x4U) #define SMMU_GNSR1_CBFRSYNRA1 (0x404U) #define SMMU_GNSR1_CBA2R1 (0x804U) #define SMMU_GNSR1_CBAR2 (0x8U) #define SMMU_GNSR1_CBFRSYNRA2 (0x408U) #define SMMU_GNSR1_CBA2R2 (0x808U) #define SMMU_GNSR1_CBAR3 (0xcU) #define SMMU_GNSR1_CBFRSYNRA3 (0x40cU) #define SMMU_GNSR1_CBA2R3 (0x80cU) #define SMMU_GNSR1_CBAR4 (0x10U) #define SMMU_GNSR1_CBFRSYNRA4 (0x410U) #define SMMU_GNSR1_CBA2R4 (0x810U) #define SMMU_GNSR1_CBAR5 (0x14U) #define SMMU_GNSR1_CBFRSYNRA5 (0x414U) #define SMMU_GNSR1_CBA2R5 (0x814U) #define SMMU_GNSR1_CBAR6 (0x18U) #define SMMU_GNSR1_CBFRSYNRA6 (0x418U) #define SMMU_GNSR1_CBA2R6 (0x818U) #define SMMU_GNSR1_CBAR7 (0x1cU) #define SMMU_GNSR1_CBFRSYNRA7 (0x41cU) #define SMMU_GNSR1_CBA2R7 (0x81cU) #define SMMU_GNSR1_CBAR8 (0x20U) #define SMMU_GNSR1_CBFRSYNRA8 (0x420U) #define SMMU_GNSR1_CBA2R8 (0x820U) #define SMMU_GNSR1_CBAR9 (0x24U) #define SMMU_GNSR1_CBFRSYNRA9 (0x424U) #define SMMU_GNSR1_CBA2R9 (0x824U) #define SMMU_GNSR1_CBAR10 (0x28U) #define SMMU_GNSR1_CBFRSYNRA10 (0x428U) #define SMMU_GNSR1_CBA2R10 (0x828U) #define SMMU_GNSR1_CBAR11 (0x2cU) #define SMMU_GNSR1_CBFRSYNRA11 (0x42cU) #define SMMU_GNSR1_CBA2R11 (0x82cU) #define SMMU_GNSR1_CBAR12 (0x30U) #define SMMU_GNSR1_CBFRSYNRA12 (0x430U) #define SMMU_GNSR1_CBA2R12 (0x830U) #define SMMU_GNSR1_CBAR13 (0x34U) #define SMMU_GNSR1_CBFRSYNRA13 (0x434U) #define SMMU_GNSR1_CBA2R13 (0x834U) #define SMMU_GNSR1_CBAR14 (0x38U) #define SMMU_GNSR1_CBFRSYNRA14 (0x438U) #define SMMU_GNSR1_CBA2R14 (0x838U) #define SMMU_GNSR1_CBAR15 (0x3cU) #define SMMU_GNSR1_CBFRSYNRA15 (0x43cU) #define SMMU_GNSR1_CBA2R15 (0x83cU) #define SMMU_GNSR1_CBAR16 (0x40U) #define SMMU_GNSR1_CBFRSYNRA16 (0x440U) #define SMMU_GNSR1_CBA2R16 (0x840U) #define SMMU_GNSR1_CBAR17 (0x44U) #define SMMU_GNSR1_CBFRSYNRA17 (0x444U) #define SMMU_GNSR1_CBA2R17 (0x844U) #define SMMU_GNSR1_CBAR18 (0x48U) #define SMMU_GNSR1_CBFRSYNRA18 (0x448U) #define SMMU_GNSR1_CBA2R18 (0x848U) #define SMMU_GNSR1_CBAR19 (0x4cU) #define SMMU_GNSR1_CBFRSYNRA19 (0x44cU) #define SMMU_GNSR1_CBA2R19 (0x84cU) #define SMMU_GNSR1_CBAR20 (0x50U) #define SMMU_GNSR1_CBFRSYNRA20 (0x450U) #define SMMU_GNSR1_CBA2R20 (0x850U) #define SMMU_GNSR1_CBAR21 (0x54U) #define SMMU_GNSR1_CBFRSYNRA21 (0x454U) #define SMMU_GNSR1_CBA2R21 (0x854U) #define SMMU_GNSR1_CBAR22 (0x58U) #define SMMU_GNSR1_CBFRSYNRA22 (0x458U) #define SMMU_GNSR1_CBA2R22 (0x858U) #define SMMU_GNSR1_CBAR23 (0x5cU) #define SMMU_GNSR1_CBFRSYNRA23 (0x45cU) #define SMMU_GNSR1_CBA2R23 (0x85cU) #define SMMU_GNSR1_CBAR24 (0x60U) #define SMMU_GNSR1_CBFRSYNRA24 (0x460U) #define SMMU_GNSR1_CBA2R24 (0x860U) #define SMMU_GNSR1_CBAR25 (0x64U) #define SMMU_GNSR1_CBFRSYNRA25 (0x464U) #define SMMU_GNSR1_CBA2R25 (0x864U) #define SMMU_GNSR1_CBAR26 (0x68U) #define SMMU_GNSR1_CBFRSYNRA26 (0x468U) #define SMMU_GNSR1_CBA2R26 (0x868U) #define SMMU_GNSR1_CBAR27 (0x6cU) #define SMMU_GNSR1_CBFRSYNRA27 (0x46cU) #define SMMU_GNSR1_CBA2R27 (0x86cU) #define SMMU_GNSR1_CBAR28 (0x70U) #define SMMU_GNSR1_CBFRSYNRA28 (0x470U) #define SMMU_GNSR1_CBA2R28 (0x870U) #define SMMU_GNSR1_CBAR29 (0x74U) #define SMMU_GNSR1_CBFRSYNRA29 (0x474U) #define SMMU_GNSR1_CBA2R29 (0x874U) #define SMMU_GNSR1_CBAR30 (0x78U) #define SMMU_GNSR1_CBFRSYNRA30 (0x478U) #define SMMU_GNSR1_CBA2R30 (0x878U) #define SMMU_GNSR1_CBAR31 (0x7cU) #define SMMU_GNSR1_CBFRSYNRA31 (0x47cU) #define SMMU_GNSR1_CBA2R31 (0x87cU) #define SMMU_GNSR1_CBAR32 (0x80U) #define SMMU_GNSR1_CBFRSYNRA32 (0x480U) #define SMMU_GNSR1_CBA2R32 (0x880U) #define SMMU_GNSR1_CBAR33 (0x84U) #define SMMU_GNSR1_CBFRSYNRA33 (0x484U) #define SMMU_GNSR1_CBA2R33 (0x884U) #define SMMU_GNSR1_CBAR34 (0x88U) #define SMMU_GNSR1_CBFRSYNRA34 (0x488U) #define SMMU_GNSR1_CBA2R34 (0x888U) #define SMMU_GNSR1_CBAR35 (0x8cU) #define SMMU_GNSR1_CBFRSYNRA35 (0x48cU) #define SMMU_GNSR1_CBA2R35 (0x88cU) #define SMMU_GNSR1_CBAR36 (0x90U) #define SMMU_GNSR1_CBFRSYNRA36 (0x490U) #define SMMU_GNSR1_CBA2R36 (0x890U) #define SMMU_GNSR1_CBAR37 (0x94U) #define SMMU_GNSR1_CBFRSYNRA37 (0x494U) #define SMMU_GNSR1_CBA2R37 (0x894U) #define SMMU_GNSR1_CBAR38 (0x98U) #define SMMU_GNSR1_CBFRSYNRA38 (0x498U) #define SMMU_GNSR1_CBA2R38 (0x898U) #define SMMU_GNSR1_CBAR39 (0x9cU) #define SMMU_GNSR1_CBFRSYNRA39 (0x49cU) #define SMMU_GNSR1_CBA2R39 (0x89cU) #define SMMU_GNSR1_CBAR40 (0xa0U) #define SMMU_GNSR1_CBFRSYNRA40 (0x4a0U) #define SMMU_GNSR1_CBA2R40 (0x8a0U) #define SMMU_GNSR1_CBAR41 (0xa4U) #define SMMU_GNSR1_CBFRSYNRA41 (0x4a4U) #define SMMU_GNSR1_CBA2R41 (0x8a4U) #define SMMU_GNSR1_CBAR42 (0xa8U) #define SMMU_GNSR1_CBFRSYNRA42 (0x4a8U) #define SMMU_GNSR1_CBA2R42 (0x8a8U) #define SMMU_GNSR1_CBAR43 (0xacU) #define SMMU_GNSR1_CBFRSYNRA43 (0x4acU) #define SMMU_GNSR1_CBA2R43 (0x8acU) #define SMMU_GNSR1_CBAR44 (0xb0U) #define SMMU_GNSR1_CBFRSYNRA44 (0x4b0U) #define SMMU_GNSR1_CBA2R44 (0x8b0U) #define SMMU_GNSR1_CBAR45 (0xb4U) #define SMMU_GNSR1_CBFRSYNRA45 (0x4b4U) #define SMMU_GNSR1_CBA2R45 (0x8b4U) #define SMMU_GNSR1_CBAR46 (0xb8U) #define SMMU_GNSR1_CBFRSYNRA46 (0x4b8U) #define SMMU_GNSR1_CBA2R46 (0x8b8U) #define SMMU_GNSR1_CBAR47 (0xbcU) #define SMMU_GNSR1_CBFRSYNRA47 (0x4bcU) #define SMMU_GNSR1_CBA2R47 (0x8bcU) #define SMMU_GNSR1_CBAR48 (0xc0U) #define SMMU_GNSR1_CBFRSYNRA48 (0x4c0U) #define SMMU_GNSR1_CBA2R48 (0x8c0U) #define SMMU_GNSR1_CBAR49 (0xc4U) #define SMMU_GNSR1_CBFRSYNRA49 (0x4c4U) #define SMMU_GNSR1_CBA2R49 (0x8c4U) #define SMMU_GNSR1_CBAR50 (0xc8U) #define SMMU_GNSR1_CBFRSYNRA50 (0x4c8U) #define SMMU_GNSR1_CBA2R50 (0x8c8U) #define SMMU_GNSR1_CBAR51 (0xccU) #define SMMU_GNSR1_CBFRSYNRA51 (0x4ccU) #define SMMU_GNSR1_CBA2R51 (0x8ccU) #define SMMU_GNSR1_CBAR52 (0xd0U) #define SMMU_GNSR1_CBFRSYNRA52 (0x4d0U) #define SMMU_GNSR1_CBA2R52 (0x8d0U) #define SMMU_GNSR1_CBAR53 (0xd4U) #define SMMU_GNSR1_CBFRSYNRA53 (0x4d4U) #define SMMU_GNSR1_CBA2R53 (0x8d4U) #define SMMU_GNSR1_CBAR54 (0xd8U) #define SMMU_GNSR1_CBFRSYNRA54 (0x4d8U) #define SMMU_GNSR1_CBA2R54 (0x8d8U) #define SMMU_GNSR1_CBAR55 (0xdcU) #define SMMU_GNSR1_CBFRSYNRA55 (0x4dcU) #define SMMU_GNSR1_CBA2R55 (0x8dcU) #define SMMU_GNSR1_CBAR56 (0xe0U) #define SMMU_GNSR1_CBFRSYNRA56 (0x4e0U) #define SMMU_GNSR1_CBA2R56 (0x8e0U) #define SMMU_GNSR1_CBAR57 (0xe4U) #define SMMU_GNSR1_CBFRSYNRA57 (0x4e4U) #define SMMU_GNSR1_CBA2R57 (0x8e4U) #define SMMU_GNSR1_CBAR58 (0xe8U) #define SMMU_GNSR1_CBFRSYNRA58 (0x4e8U) #define SMMU_GNSR1_CBA2R58 (0x8e8U) #define SMMU_GNSR1_CBAR59 (0xecU) #define SMMU_GNSR1_CBFRSYNRA59 (0x4ecU) #define SMMU_GNSR1_CBA2R59 (0x8ecU) #define SMMU_GNSR1_CBAR60 (0xf0U) #define SMMU_GNSR1_CBFRSYNRA60 (0x4f0U) #define SMMU_GNSR1_CBA2R60 (0x8f0U) #define SMMU_GNSR1_CBAR61 (0xf4U) #define SMMU_GNSR1_CBFRSYNRA61 (0x4f4U) #define SMMU_GNSR1_CBA2R61 (0x8f4U) #define SMMU_GNSR1_CBAR62 (0xf8U) #define SMMU_GNSR1_CBFRSYNRA62 (0x4f8U) #define SMMU_GNSR1_CBA2R62 (0x8f8U) #define SMMU_GNSR1_CBAR63 (0xfcU) #define SMMU_GNSR1_CBFRSYNRA63 (0x4fcU) #define SMMU_GNSR1_CBA2R63 (0x8fcU) /******************************************************************************* * SMMU Global Secure Aux. Configuration Register ******************************************************************************/ #define SMMU_GSR0_SECURE_ACR 0x10U #define SMMU_GNSR_ACR (SMMU_GSR0_SECURE_ACR + 0x400U) #define SMMU_GSR0_PGSIZE_SHIFT 16U #define SMMU_GSR0_PGSIZE_4K (0U << SMMU_GSR0_PGSIZE_SHIFT) #define SMMU_GSR0_PGSIZE_64K (1U << SMMU_GSR0_PGSIZE_SHIFT) #define SMMU_ACR_CACHE_LOCK_ENABLE_BIT (1U << 26) /******************************************************************************* * SMMU Global Aux. Control Register ******************************************************************************/ #define SMMU_CBn_ACTLR_CPRE_BIT (1ULL << 1U) /******************************************************************************* * SMMU configuration constants ******************************************************************************/ #define ID1_PAGESIZE (1U << 31U) #define ID1_NUMPAGENDXB_SHIFT 28U #define ID1_NUMPAGENDXB_MASK 7U #define ID1_NUMS2CB_SHIFT 16U #define ID1_NUMS2CB_MASK 0xffU #define ID1_NUMCB_SHIFT 0U #define ID1_NUMCB_MASK 0xffU #define PGSHIFT 16U #define CB_SIZE 0x800000U typedef struct smmu_regs { uint32_t reg; uint32_t val; } smmu_regs_t; #define mc_make_sid_override_cfg(name) \ { \ .reg = TEGRA_MC_STREAMID_BASE + MC_STREAMID_OVERRIDE_CFG_ ## name, \ .val = 0x00000000U, \ } #define mc_make_sid_security_cfg(name) \ { \ .reg = TEGRA_MC_STREAMID_BASE + MC_STREAMID_OVERRIDE_TO_SECURITY_CFG(MC_STREAMID_OVERRIDE_CFG_ ## name), \ .val = 0x00000000U, \ } #define smmu_make_gnsr0_sec_cfg(base_addr, name) \ { \ .reg = base_addr + SMMU_GNSR0_ ## name, \ .val = 0x00000000U, \ } /* * On ARM-SMMU, conditional offset to access secure aliases of non-secure registers * is 0x400. So, add it to register address */ #define smmu_make_gnsr0_nsec_cfg(base_addr, name) \ { \ .reg = base_addr + 0x400U + SMMU_GNSR0_ ## name, \ .val = 0x00000000U, \ } #define smmu_make_gnsr0_smr_cfg(base_addr, n) \ { \ .reg = base_addr + SMMU_GNSR0_SMR ## n, \ .val = 0x00000000U, \ } #define smmu_make_gnsr0_s2cr_cfg(base_addr, n) \ { \ .reg = base_addr + SMMU_GNSR0_S2CR ## n, \ .val = 0x00000000U, \ } #define smmu_make_gnsr1_cbar_cfg(base_addr, n) \ { \ .reg = base_addr + (1U << PGSHIFT) + SMMU_GNSR1_CBAR ## n, \ .val = 0x00000000U, \ } #define smmu_make_gnsr1_cba2r_cfg(base_addr, n) \ { \ .reg = base_addr + (1U << PGSHIFT) + SMMU_GNSR1_CBA2R ## n, \ .val = 0x00000000U, \ } #define smmu_make_cb_cfg(base_addr, name, n) \ { \ .reg = base_addr + (CB_SIZE >> 1) + (n * (1 << PGSHIFT)) \ + SMMU_CBn_ ## name, \ .val = 0x00000000U, \ } #define smmu_make_smrg_group(base_addr, n) \ smmu_make_gnsr0_smr_cfg(base_addr, n), \ smmu_make_gnsr0_s2cr_cfg(base_addr, n), \ smmu_make_gnsr1_cbar_cfg(base_addr, n), \ smmu_make_gnsr1_cba2r_cfg(base_addr, n) /* don't put "," here. */ #define smmu_make_cb_group(base_addr, n) \ smmu_make_cb_cfg(base_addr, SCTLR, n), \ smmu_make_cb_cfg(base_addr, TCR2, n), \ smmu_make_cb_cfg(base_addr, TTBR0_LO, n), \ smmu_make_cb_cfg(base_addr, TTBR0_HI, n), \ smmu_make_cb_cfg(base_addr, TCR, n), \ smmu_make_cb_cfg(base_addr, PRRR_MAIR0, n),\ smmu_make_cb_cfg(base_addr, FSR, n), \ smmu_make_cb_cfg(base_addr, FAR_LO, n), \ smmu_make_cb_cfg(base_addr, FAR_HI, n), \ smmu_make_cb_cfg(base_addr, FSYNR0, n) /* don't put "," here. */ #define smmu_make_cfg(base_addr) \ smmu_make_gnsr0_nsec_cfg(base_addr, CR0), \ smmu_make_gnsr0_sec_cfg(base_addr, IDR0), \ smmu_make_gnsr0_sec_cfg(base_addr, IDR1), \ smmu_make_gnsr0_sec_cfg(base_addr, IDR2), \ smmu_make_gnsr0_nsec_cfg(base_addr, GFSR), \ smmu_make_gnsr0_nsec_cfg(base_addr, GFSYNR0), \ smmu_make_gnsr0_nsec_cfg(base_addr, GFSYNR1), \ smmu_make_gnsr0_nsec_cfg(base_addr, TLBGSTATUS),\ smmu_make_gnsr0_nsec_cfg(base_addr, PIDR2), \ smmu_make_smrg_group(base_addr, 0), \ smmu_make_smrg_group(base_addr, 1), \ smmu_make_smrg_group(base_addr, 2), \ smmu_make_smrg_group(base_addr, 3), \ smmu_make_smrg_group(base_addr, 4), \ smmu_make_smrg_group(base_addr, 5), \ smmu_make_smrg_group(base_addr, 6), \ smmu_make_smrg_group(base_addr, 7), \ smmu_make_smrg_group(base_addr, 8), \ smmu_make_smrg_group(base_addr, 9), \ smmu_make_smrg_group(base_addr, 10), \ smmu_make_smrg_group(base_addr, 11), \ smmu_make_smrg_group(base_addr, 12), \ smmu_make_smrg_group(base_addr, 13), \ smmu_make_smrg_group(base_addr, 14), \ smmu_make_smrg_group(base_addr, 15), \ smmu_make_smrg_group(base_addr, 16), \ smmu_make_smrg_group(base_addr, 17), \ smmu_make_smrg_group(base_addr, 18), \ smmu_make_smrg_group(base_addr, 19), \ smmu_make_smrg_group(base_addr, 20), \ smmu_make_smrg_group(base_addr, 21), \ smmu_make_smrg_group(base_addr, 22), \ smmu_make_smrg_group(base_addr, 23), \ smmu_make_smrg_group(base_addr, 24), \ smmu_make_smrg_group(base_addr, 25), \ smmu_make_smrg_group(base_addr, 26), \ smmu_make_smrg_group(base_addr, 27), \ smmu_make_smrg_group(base_addr, 28), \ smmu_make_smrg_group(base_addr, 29), \ smmu_make_smrg_group(base_addr, 30), \ smmu_make_smrg_group(base_addr, 31), \ smmu_make_smrg_group(base_addr, 32), \ smmu_make_smrg_group(base_addr, 33), \ smmu_make_smrg_group(base_addr, 34), \ smmu_make_smrg_group(base_addr, 35), \ smmu_make_smrg_group(base_addr, 36), \ smmu_make_smrg_group(base_addr, 37), \ smmu_make_smrg_group(base_addr, 38), \ smmu_make_smrg_group(base_addr, 39), \ smmu_make_smrg_group(base_addr, 40), \ smmu_make_smrg_group(base_addr, 41), \ smmu_make_smrg_group(base_addr, 42), \ smmu_make_smrg_group(base_addr, 43), \ smmu_make_smrg_group(base_addr, 44), \ smmu_make_smrg_group(base_addr, 45), \ smmu_make_smrg_group(base_addr, 46), \ smmu_make_smrg_group(base_addr, 47), \ smmu_make_smrg_group(base_addr, 48), \ smmu_make_smrg_group(base_addr, 49), \ smmu_make_smrg_group(base_addr, 50), \ smmu_make_smrg_group(base_addr, 51), \ smmu_make_smrg_group(base_addr, 52), \ smmu_make_smrg_group(base_addr, 53), \ smmu_make_smrg_group(base_addr, 54), \ smmu_make_smrg_group(base_addr, 55), \ smmu_make_smrg_group(base_addr, 56), \ smmu_make_smrg_group(base_addr, 57), \ smmu_make_smrg_group(base_addr, 58), \ smmu_make_smrg_group(base_addr, 59), \ smmu_make_smrg_group(base_addr, 60), \ smmu_make_smrg_group(base_addr, 61), \ smmu_make_smrg_group(base_addr, 62), \ smmu_make_smrg_group(base_addr, 63), \ smmu_make_cb_group(base_addr, 0), \ smmu_make_cb_group(base_addr, 1), \ smmu_make_cb_group(base_addr, 2), \ smmu_make_cb_group(base_addr, 3), \ smmu_make_cb_group(base_addr, 4), \ smmu_make_cb_group(base_addr, 5), \ smmu_make_cb_group(base_addr, 6), \ smmu_make_cb_group(base_addr, 7), \ smmu_make_cb_group(base_addr, 8), \ smmu_make_cb_group(base_addr, 9), \ smmu_make_cb_group(base_addr, 10), \ smmu_make_cb_group(base_addr, 11), \ smmu_make_cb_group(base_addr, 12), \ smmu_make_cb_group(base_addr, 13), \ smmu_make_cb_group(base_addr, 14), \ smmu_make_cb_group(base_addr, 15), \ smmu_make_cb_group(base_addr, 16), \ smmu_make_cb_group(base_addr, 17), \ smmu_make_cb_group(base_addr, 18), \ smmu_make_cb_group(base_addr, 19), \ smmu_make_cb_group(base_addr, 20), \ smmu_make_cb_group(base_addr, 21), \ smmu_make_cb_group(base_addr, 22), \ smmu_make_cb_group(base_addr, 23), \ smmu_make_cb_group(base_addr, 24), \ smmu_make_cb_group(base_addr, 25), \ smmu_make_cb_group(base_addr, 26), \ smmu_make_cb_group(base_addr, 27), \ smmu_make_cb_group(base_addr, 28), \ smmu_make_cb_group(base_addr, 29), \ smmu_make_cb_group(base_addr, 30), \ smmu_make_cb_group(base_addr, 31), \ smmu_make_cb_group(base_addr, 32), \ smmu_make_cb_group(base_addr, 33), \ smmu_make_cb_group(base_addr, 34), \ smmu_make_cb_group(base_addr, 35), \ smmu_make_cb_group(base_addr, 36), \ smmu_make_cb_group(base_addr, 37), \ smmu_make_cb_group(base_addr, 38), \ smmu_make_cb_group(base_addr, 39), \ smmu_make_cb_group(base_addr, 40), \ smmu_make_cb_group(base_addr, 41), \ smmu_make_cb_group(base_addr, 42), \ smmu_make_cb_group(base_addr, 43), \ smmu_make_cb_group(base_addr, 44), \ smmu_make_cb_group(base_addr, 45), \ smmu_make_cb_group(base_addr, 46), \ smmu_make_cb_group(base_addr, 47), \ smmu_make_cb_group(base_addr, 48), \ smmu_make_cb_group(base_addr, 49), \ smmu_make_cb_group(base_addr, 50), \ smmu_make_cb_group(base_addr, 51), \ smmu_make_cb_group(base_addr, 52), \ smmu_make_cb_group(base_addr, 53), \ smmu_make_cb_group(base_addr, 54), \ smmu_make_cb_group(base_addr, 55), \ smmu_make_cb_group(base_addr, 56), \ smmu_make_cb_group(base_addr, 57), \ smmu_make_cb_group(base_addr, 58), \ smmu_make_cb_group(base_addr, 59), \ smmu_make_cb_group(base_addr, 60), \ smmu_make_cb_group(base_addr, 61), \ smmu_make_cb_group(base_addr, 62), \ smmu_make_cb_group(base_addr, 63) /* don't put "," here. */ #define smmu_bypass_cfg \ { \ .reg = TEGRA_MC_BASE + MC_SMMU_BYPASS_CONFIG, \ .val = 0x00000000U, \ } #define _START_OF_TABLE_ \ { \ .reg = 0xCAFE05C7U, \ .val = 0x00000000U, \ } #define _END_OF_TABLE_ \ { \ .reg = 0xFFFFFFFFU, \ .val = 0xFFFFFFFFU, \ } void tegra_smmu_init(void); void tegra_smmu_save_context(uint64_t smmu_ctx_addr); smmu_regs_t *plat_get_smmu_ctx(void); uint32_t plat_get_num_smmu_devices(void); #endif /* SMMU_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/drivers/tegra_gic.h000066400000000000000000000016511355360272700256260ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __TEGRA_GIC_H__ #define __TEGRA_GIC_H__ #include /******************************************************************************* * Per-CPU struct describing FIQ state to be stored ******************************************************************************/ typedef struct pcpu_fiq_state { uint64_t elr_el3; uint64_t spsr_el3; } pcpu_fiq_state_t; /******************************************************************************* * Fucntion declarations ******************************************************************************/ void tegra_gic_cpuif_deactivate(void); void tegra_gic_init(void); void tegra_gic_pcpu_init(void); void tegra_gic_setup(const interrupt_prop_t *interrupt_props, unsigned int interrupt_props_num); #endif /* __TEGRA_GIC_H__ */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/lib/000077500000000000000000000000001355360272700226165ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/include/lib/profiler.h000066400000000000000000000011401355360272700246050ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __PROFILER_H__ #define __PROFILER_H__ /******************************************************************************* * Number of bytes of memory used by the profiler on Tegra ******************************************************************************/ #define PROFILER_SIZE_BYTES U(0x1000) void boot_profiler_init(uint64_t shmem_base, uint32_t tmr_base); void boot_profiler_add_record(const char *str); void boot_profiler_deinit(void); #endif /* __PROFILER_H__ */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/plat_macros.S000066400000000000000000000026021355360272700245000ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S #include #include .section .rodata.gic_reg_name, "aS" gicc_regs: .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", "" gicd_pend_reg: .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n" newline: .asciz "\n" spacer: .asciz ":\t\t0x" /* --------------------------------------------- * The below macro prints out relevant GIC * registers whenever an unhandled exception is * taken in BL31. * --------------------------------------------- */ .macro plat_crash_print_regs mov_imm x16, TEGRA_GICC_BASE /* gicc base address is now in x16 */ adr x6, gicc_regs /* Load the gicc reg list to x6 */ /* Load the gicc regs to gp regs used by str_in_crash_buf_print */ ldr w8, [x16, #GICC_HPPIR] ldr w9, [x16, #GICC_AHPPIR] ldr w10, [x16, #GICC_CTLR] /* Store to the crash buf and print to cosole */ bl str_in_crash_buf_print /* Print the GICD_ISPENDR regs */ mov_imm x16, TEGRA_GICD_BASE add x7, x16, #GICD_ISPENDR adr x4, gicd_pend_reg bl asm_print_str 2: sub x4, x7, x16 cmp x4, #0x280 b.eq 1f bl asm_print_hex adr x4, spacer bl asm_print_str ldr w4, [x7], #4 bl asm_print_hex adr x4, newline bl asm_print_str b 2b 1: .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/platform_def.h000066400000000000000000000052441355360272700246700ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include /* * Platform binary types for linking */ #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 /******************************************************************************* * Generic platform constants ******************************************************************************/ /* Size of cacheable stacks */ #ifdef IMAGE_BL31 #define PLATFORM_STACK_SIZE U(0x400) #endif #define TEGRA_PRIMARY_CPU U(0x0) #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \ PLATFORM_MAX_CPUS_PER_CLUSTER) #define PLAT_NUM_PWR_DOMAINS (PLATFORM_CORE_COUNT + \ PLATFORM_CLUSTER_COUNT + 1) /******************************************************************************* * Platform console related constants ******************************************************************************/ #define TEGRA_CONSOLE_BAUDRATE U(115200) #define TEGRA_BOOT_UART_CLK_13_MHZ U(13000000) #define TEGRA_BOOT_UART_CLK_408_MHZ U(408000000) /******************************************************************************* * Platform memory map related constants ******************************************************************************/ /* Size of trusted dram */ #define TZDRAM_SIZE U(0x00400000) #define TZDRAM_END (TZDRAM_BASE + TZDRAM_SIZE) /******************************************************************************* * BL31 specific defines. ******************************************************************************/ #define BL31_SIZE U(0x40000) #define BL31_BASE TZDRAM_BASE #define BL31_LIMIT (TZDRAM_BASE + BL31_SIZE - 1) #define BL32_BASE (TZDRAM_BASE + BL31_SIZE) #define BL32_LIMIT TZDRAM_END /******************************************************************************* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. ******************************************************************************/ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (0x40) /* (U(1) << CACHE_WRITEBACK_SHIFT) */ /******************************************************************************* * Dummy macros to compile io_storage support ******************************************************************************/ #define MAX_IO_DEVICES U(0) #define MAX_IO_HANDLES U(0) #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/t132/000077500000000000000000000000001355360272700225415ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/include/t132/tegra_def.h000066400000000000000000000113501355360272700246320ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TEGRA_DEF_H #define TEGRA_DEF_H #include /******************************************************************************* * This value is used by the PSCI implementation during the `SYSTEM_SUSPEND` * call as the `state-id` field in the 'power state' parameter. ******************************************************************************/ #define PSTATE_ID_SOC_POWERDN U(0xD) /******************************************************************************* * Platform power states (used by PSCI framework) * * - PLAT_MAX_RET_STATE should be less than lowest PSTATE_ID * - PLAT_MAX_OFF_STATE should be greater than the highest PSTATE_ID ******************************************************************************/ #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE (PSTATE_ID_SOC_POWERDN + U(1)) /******************************************************************************* * Chip specific page table and MMU setup constants ******************************************************************************/ #define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 35) #define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 35) /******************************************************************************* * GIC memory map ******************************************************************************/ #define TEGRA_GICD_BASE U(0x50041000) #define TEGRA_GICC_BASE U(0x50042000) /******************************************************************************* * Tegra micro-seconds timer constants ******************************************************************************/ #define TEGRA_TMRUS_BASE U(0x60005010) #define TEGRA_TMRUS_SIZE U(0x1000) /******************************************************************************* * Tegra Clock and Reset Controller constants ******************************************************************************/ #define TEGRA_CAR_RESET_BASE U(0x60006000) #define TEGRA_GPU_RESET_REG_OFFSET U(0x28C) #define TEGRA_GPU_RESET_GPU_SET_OFFSET U(0x290) #define GPU_RESET_BIT (U(1) << 24) #define GPU_SET_BIT (U(1) << 24) /******************************************************************************* * Tegra Flow Controller constants ******************************************************************************/ #define TEGRA_FLOWCTRL_BASE U(0x60007000) /******************************************************************************* * Tegra Secure Boot Controller constants ******************************************************************************/ #define TEGRA_SB_BASE U(0x6000C200) /******************************************************************************* * Tegra Exception Vectors constants ******************************************************************************/ #define TEGRA_EVP_BASE U(0x6000F000) /******************************************************************************* * Tegra Miscellaneous register constants ******************************************************************************/ #define TEGRA_MISC_BASE U(0x70000000) #define HARDWARE_REVISION_OFFSET U(0x804) /******************************************************************************* * Tegra UART controller base addresses ******************************************************************************/ #define TEGRA_UARTA_BASE U(0x70006000) #define TEGRA_UARTB_BASE U(0x70006040) #define TEGRA_UARTC_BASE U(0x70006200) #define TEGRA_UARTD_BASE U(0x70006300) #define TEGRA_UARTE_BASE U(0x70006400) /******************************************************************************* * Tegra Power Mgmt Controller constants ******************************************************************************/ #define TEGRA_PMC_BASE U(0x7000E400) /******************************************************************************* * Tegra Memory Controller constants ******************************************************************************/ #define TEGRA_MC_BASE U(0x70019000) /* Memory Controller Interrupt Status */ #define MC_INTSTATUS 0x00U /* TZDRAM carveout configuration registers */ #define MC_SECURITY_CFG0_0 U(0x70) #define MC_SECURITY_CFG1_0 U(0x74) #define MC_SECURITY_CFG3_0 U(0x9BC) /* Video Memory carveout configuration registers */ #define MC_VIDEO_PROTECT_BASE_HI U(0x978) #define MC_VIDEO_PROTECT_BASE_LO U(0x648) #define MC_VIDEO_PROTECT_SIZE_MB U(0x64c) /******************************************************************************* * Tegra TZRAM constants ******************************************************************************/ #define TEGRA_TZRAM_BASE U(0x7C010000) #define TEGRA_TZRAM_SIZE U(0x10000) #endif /* TEGRA_DEF_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/t186/000077500000000000000000000000001355360272700225525ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/include/t186/tegra186_private.h000066400000000000000000000006661355360272700260260ustar00rootroot00000000000000/* * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TEGRA186_PRIVATE_H #define TEGRA186_PRIVATE_H void tegra186_cpu_reset_handler(void); uint64_t tegra186_get_cpu_reset_handler_base(void); uint64_t tegra186_get_cpu_reset_handler_size(void); uint64_t tegra186_get_smmu_ctx_offset(void); void tegra186_set_system_suspend_entry(void); #endif /* TEGRA186_PRIVATE_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/t186/tegra_def.h000066400000000000000000000301171355360272700246450ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TEGRA_DEF_H #define TEGRA_DEF_H #include /******************************************************************************* * MCE apertures used by the ARI interface * * Aperture 0 - Cpu0 (ARM Cortex A-57) * Aperture 1 - Cpu1 (ARM Cortex A-57) * Aperture 2 - Cpu2 (ARM Cortex A-57) * Aperture 3 - Cpu3 (ARM Cortex A-57) * Aperture 4 - Cpu4 (Denver15) * Aperture 5 - Cpu5 (Denver15) ******************************************************************************/ #define MCE_ARI_APERTURE_0_OFFSET U(0x0) #define MCE_ARI_APERTURE_1_OFFSET U(0x10000) #define MCE_ARI_APERTURE_2_OFFSET U(0x20000) #define MCE_ARI_APERTURE_3_OFFSET U(0x30000) #define MCE_ARI_APERTURE_4_OFFSET U(0x40000) #define MCE_ARI_APERTURE_5_OFFSET U(0x50000) #define MCE_ARI_APERTURE_OFFSET_MAX MCE_APERTURE_5_OFFSET /* number of apertures */ #define MCE_ARI_APERTURES_MAX U(6) /* each ARI aperture is 64KB */ #define MCE_ARI_APERTURE_SIZE U(0x10000) /******************************************************************************* * CPU core id macros for the MCE_ONLINE_CORE ARI ******************************************************************************/ #define MCE_CORE_ID_MAX U(8) #define MCE_CORE_ID_MASK U(0x7) /******************************************************************************* * These values are used by the PSCI implementation during the `CPU_SUSPEND` * and `SYSTEM_SUSPEND` calls as the `state-id` field in the 'power state' * parameter. ******************************************************************************/ #define PSTATE_ID_CORE_IDLE U(6) #define PSTATE_ID_CORE_POWERDN U(7) #define PSTATE_ID_SOC_POWERDN U(2) /******************************************************************************* * Platform power states (used by PSCI framework) * * - PLAT_MAX_RET_STATE should be less than lowest PSTATE_ID * - PLAT_MAX_OFF_STATE should be greater than the highest PSTATE_ID ******************************************************************************/ #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE U(8) /******************************************************************************* * Chip specific page table and MMU setup constants ******************************************************************************/ #define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 35) #define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 35) /******************************************************************************* * Secure IRQ definitions ******************************************************************************/ #define TEGRA186_TOP_WDT_IRQ U(49) #define TEGRA186_AON_WDT_IRQ U(50) #define TEGRA186_SEC_IRQ_TARGET_MASK U(0xF3) /* 4 A57 - 2 Denver */ /******************************************************************************* * Tegra Miscellanous register constants ******************************************************************************/ #define TEGRA_MISC_BASE U(0x00100000) #define HARDWARE_REVISION_OFFSET U(0x4) #define MISCREG_PFCFG U(0x200C) /******************************************************************************* * Tegra TSA Controller constants ******************************************************************************/ #define TEGRA_TSA_BASE U(0x02400000) /******************************************************************************* * TSA configuration registers ******************************************************************************/ #define TSA_CONFIG_STATIC0_CSW_SESWR U(0x4010) #define TSA_CONFIG_STATIC0_CSW_SESWR_RESET U(0x1100) #define TSA_CONFIG_STATIC0_CSW_ETRW U(0x4038) #define TSA_CONFIG_STATIC0_CSW_ETRW_RESET U(0x1100) #define TSA_CONFIG_STATIC0_CSW_SDMMCWAB U(0x5010) #define TSA_CONFIG_STATIC0_CSW_SDMMCWAB_RESET U(0x1100) #define TSA_CONFIG_STATIC0_CSW_AXISW U(0x7008) #define TSA_CONFIG_STATIC0_CSW_AXISW_RESET U(0x1100) #define TSA_CONFIG_STATIC0_CSW_HDAW U(0xA008) #define TSA_CONFIG_STATIC0_CSW_HDAW_RESET U(0x100) #define TSA_CONFIG_STATIC0_CSW_AONDMAW U(0xB018) #define TSA_CONFIG_STATIC0_CSW_AONDMAW_RESET U(0x1100) #define TSA_CONFIG_STATIC0_CSW_SCEDMAW U(0xD018) #define TSA_CONFIG_STATIC0_CSW_SCEDMAW_RESET U(0x1100) #define TSA_CONFIG_STATIC0_CSW_BPMPDMAW U(0xD028) #define TSA_CONFIG_STATIC0_CSW_BPMPDMAW_RESET U(0x1100) #define TSA_CONFIG_STATIC0_CSW_APEDMAW U(0x12018) #define TSA_CONFIG_STATIC0_CSW_APEDMAW_RESET U(0x1100) #define TSA_CONFIG_STATIC0_CSW_UFSHCW U(0x13008) #define TSA_CONFIG_STATIC0_CSW_UFSHCW_RESET U(0x1100) #define TSA_CONFIG_STATIC0_CSW_AFIW U(0x13018) #define TSA_CONFIG_STATIC0_CSW_AFIW_RESET U(0x1100) #define TSA_CONFIG_STATIC0_CSW_SATAW U(0x13028) #define TSA_CONFIG_STATIC0_CSW_SATAW_RESET U(0x1100) #define TSA_CONFIG_STATIC0_CSW_EQOSW U(0x13038) #define TSA_CONFIG_STATIC0_CSW_EQOSW_RESET U(0x1100) #define TSA_CONFIG_STATIC0_CSW_XUSB_DEVW U(0x15008) #define TSA_CONFIG_STATIC0_CSW_XUSB_DEVW_RESET U(0x1100) #define TSA_CONFIG_STATIC0_CSW_XUSB_HOSTW U(0x15018) #define TSA_CONFIG_STATIC0_CSW_XUSB_HOSTW_RESET U(0x1100) #define TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_MASK (ULL(0x3) << 11) #define TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_PASTHRU (ULL(0) << 11) /******************************************************************************* * Tegra General Purpose Centralised DMA constants ******************************************************************************/ #define TEGRA_GPCDMA_BASE ULL(0x2610000) /******************************************************************************* * Tegra Memory Controller constants ******************************************************************************/ #define TEGRA_MC_STREAMID_BASE U(0x02C00000) #define TEGRA_MC_BASE U(0x02C10000) /* General Security Carveout register macros */ #define MC_GSC_CONFIG_REGS_SIZE U(0x40) #define MC_GSC_LOCK_CFG_SETTINGS_BIT (U(1) << 1) #define MC_GSC_ENABLE_TZ_LOCK_BIT (ULL(1) << 0) #define MC_GSC_SIZE_RANGE_4KB_SHIFT U(27) #define MC_GSC_BASE_LO_SHIFT U(12) #define MC_GSC_BASE_LO_MASK U(0xFFFFF) #define MC_GSC_BASE_HI_SHIFT U(0) #define MC_GSC_BASE_HI_MASK U(3) #define MC_GSC_ENABLE_CPU_SECURE_BIT (U(1) << 31) /* TZDRAM carveout configuration registers */ #define MC_SECURITY_CFG0_0 U(0x70) #define MC_SECURITY_CFG1_0 U(0x74) #define MC_SECURITY_CFG3_0 U(0x9BC) #define MC_SECURITY_BOM_MASK (U(0xFFF) << 20) #define MC_SECURITY_SIZE_MB_MASK (U(0x1FFF) << 0) #define MC_SECURITY_BOM_HI_MASK (U(0x3) << 0) /* Video Memory carveout configuration registers */ #define MC_VIDEO_PROTECT_BASE_HI U(0x978) #define MC_VIDEO_PROTECT_BASE_LO U(0x648) #define MC_VIDEO_PROTECT_SIZE_MB U(0x64C) /* * Carveout (MC_SECURITY_CARVEOUT24) registers used to clear the * non-overlapping Video memory region */ #define MC_VIDEO_PROTECT_CLEAR_CFG U(0x25A0) #define MC_VIDEO_PROTECT_CLEAR_BASE_LO U(0x25A4) #define MC_VIDEO_PROTECT_CLEAR_BASE_HI U(0x25A8) #define MC_VIDEO_PROTECT_CLEAR_SIZE U(0x25AC) #define MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0 U(0x25B0) /* TZRAM carveout (MC_SECURITY_CARVEOUT11) configuration registers */ #define MC_TZRAM_CARVEOUT_CFG U(0x2190) #define MC_TZRAM_BASE_LO U(0x2194) #define MC_TZRAM_BASE_HI U(0x2198) #define MC_TZRAM_SIZE U(0x219C) #define MC_TZRAM_CLIENT_ACCESS0_CFG0 U(0x21A0) #define MC_TZRAM_CLIENT_ACCESS1_CFG0 U(0x21A4) #define TZRAM_ALLOW_MPCORER (U(1) << 7) #define TZRAM_ALLOW_MPCOREW (U(1) << 25) /******************************************************************************* * Tegra UART Controller constants ******************************************************************************/ #define TEGRA_UARTA_BASE U(0x03100000) #define TEGRA_UARTB_BASE U(0x03110000) #define TEGRA_UARTC_BASE U(0x0C280000) #define TEGRA_UARTD_BASE U(0x03130000) #define TEGRA_UARTE_BASE U(0x03140000) #define TEGRA_UARTF_BASE U(0x03150000) #define TEGRA_UARTG_BASE U(0x0C290000) /******************************************************************************* * Tegra Fuse Controller related constants ******************************************************************************/ #define TEGRA_FUSE_BASE U(0x03820000) #define OPT_SUBREVISION U(0x248) #define SUBREVISION_MASK U(0xFF) /******************************************************************************* * GICv2 & interrupt handling related constants ******************************************************************************/ #define TEGRA_GICD_BASE U(0x03881000) #define TEGRA_GICC_BASE U(0x03882000) /******************************************************************************* * Security Engine related constants ******************************************************************************/ #define TEGRA_SE0_BASE U(0x03AC0000) #define SE_MUTEX_WATCHDOG_NS_LIMIT U(0x6C) #define TEGRA_PKA1_BASE U(0x03AD0000) #define PKA_MUTEX_WATCHDOG_NS_LIMIT U(0x8144) #define TEGRA_RNG1_BASE U(0x03AE0000) #define RNG_MUTEX_WATCHDOG_NS_LIMIT U(0xFE0) /******************************************************************************* * Tegra Clock and Reset Controller constants ******************************************************************************/ #define TEGRA_CAR_RESET_BASE U(0x05000000) #define TEGRA_GPU_RESET_REG_OFFSET U(0x30) #define TEGRA_GPU_RESET_GPU_SET_OFFSET U(0x34) #define GPU_RESET_BIT (U(1) << 0) #define GPU_SET_BIT (U(1) << 0) #define TEGRA_GPCDMA_RST_SET_REG_OFFSET U(0x6A0004) #define TEGRA_GPCDMA_RST_CLR_REG_OFFSET U(0x6A0008) /******************************************************************************* * Tegra micro-seconds timer constants ******************************************************************************/ #define TEGRA_TMRUS_BASE U(0x0C2E0000) #define TEGRA_TMRUS_SIZE U(0x1000) /******************************************************************************* * Tegra Power Mgmt Controller constants ******************************************************************************/ #define TEGRA_PMC_BASE U(0x0C360000) /******************************************************************************* * Tegra scratch registers constants ******************************************************************************/ #define TEGRA_SCRATCH_BASE U(0x0C390000) #define SECURE_SCRATCH_RSV1_LO U(0x658) #define SECURE_SCRATCH_RSV1_HI U(0x65C) #define SECURE_SCRATCH_RSV6 U(0x680) #define SECURE_SCRATCH_RSV11_LO U(0x6A8) #define SECURE_SCRATCH_RSV11_HI U(0x6AC) #define SECURE_SCRATCH_RSV53_LO U(0x7F8) #define SECURE_SCRATCH_RSV53_HI U(0x7FC) #define SECURE_SCRATCH_RSV55_LO U(0x808) #define SECURE_SCRATCH_RSV55_HI U(0x80C) #define SCRATCH_RESET_VECTOR_LO SECURE_SCRATCH_RSV1_LO #define SCRATCH_RESET_VECTOR_HI SECURE_SCRATCH_RSV1_HI #define SCRATCH_SECURE_BOOTP_FCFG SECURE_SCRATCH_RSV6 #define SCRATCH_SMMU_TABLE_ADDR_LO SECURE_SCRATCH_RSV11_LO #define SCRATCH_SMMU_TABLE_ADDR_HI SECURE_SCRATCH_RSV11_HI #define SCRATCH_BL31_PARAMS_ADDR SECURE_SCRATCH_RSV53_LO #define SCRATCH_BL31_PLAT_PARAMS_ADDR SECURE_SCRATCH_RSV53_HI #define SCRATCH_TZDRAM_ADDR_LO SECURE_SCRATCH_RSV55_LO #define SCRATCH_TZDRAM_ADDR_HI SECURE_SCRATCH_RSV55_HI /******************************************************************************* * Tegra Memory Mapped Control Register Access constants ******************************************************************************/ #define TEGRA_MMCRAB_BASE U(0x0E000000) /******************************************************************************* * Tegra Memory Mapped Activity Monitor Register Access constants ******************************************************************************/ #define TEGRA_ARM_ACTMON_CTR_BASE U(0x0E060000) #define TEGRA_DENVER_ACTMON_CTR_BASE U(0x0E070000) /******************************************************************************* * Tegra SMMU Controller constants ******************************************************************************/ #define TEGRA_SMMU0_BASE U(0x12000000) /******************************************************************************* * Tegra TZRAM constants ******************************************************************************/ #define TEGRA_TZRAM_BASE U(0x30000000) #define TEGRA_TZRAM_SIZE U(0x40000) #endif /* TEGRA_DEF_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/t186/tegra_mc_def.h000066400000000000000000000345611355360272700253330ustar00rootroot00000000000000/* * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TEGRA_MC_DEF_H #define TEGRA_MC_DEF_H /******************************************************************************* * Memory Controller's PCFIFO client configuration registers ******************************************************************************/ #define MC_PCFIFO_CLIENT_CONFIG0 0xdd0U #define MC_PCFIFO_CLIENT_CONFIG1 0xdd4U #define MC_PCFIFO_CLIENT_CONFIG1_RESET_VAL 0x20000U #define MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_AFIW_UNORDERED (0U << 17) #define MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_AFIW_MASK (1U << 17) #define MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_HDAW_UNORDERED (0U << 21) #define MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_HDAW_MASK (1U << 21) #define MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_SATAW_UNORDERED (0U << 29) #define MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_SATAW_MASK (1U << 29) #define MC_PCFIFO_CLIENT_CONFIG2 0xdd8U #define MC_PCFIFO_CLIENT_CONFIG2_RESET_VAL 0x20000U #define MC_PCFIFO_CLIENT_CONFIG2_PCFIFO_XUSB_HOSTW_UNORDERED (0U << 11) #define MC_PCFIFO_CLIENT_CONFIG2_PCFIFO_XUSB_HOSTW_MASK (1U << 11) #define MC_PCFIFO_CLIENT_CONFIG2_PCFIFO_XUSB_DEVW_UNORDERED (0U << 13) #define MC_PCFIFO_CLIENT_CONFIG2_PCFIFO_XUSB_DEVW_MASK (1U << 13) #define MC_PCFIFO_CLIENT_CONFIG3 0xddcU #define MC_PCFIFO_CLIENT_CONFIG3_RESET_VAL 0U #define MC_PCFIFO_CLIENT_CONFIG3_PCFIFO_SDMMCWAB_UNORDERED (0U << 7) #define MC_PCFIFO_CLIENT_CONFIG3_PCFIFO_SDMMCWAB_MASK (1U << 7) #define MC_PCFIFO_CLIENT_CONFIG4 0xde0U #define MC_PCFIFO_CLIENT_CONFIG4_RESET_VAL 0U #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_SESWR_UNORDERED (0U << 1) #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_SESWR_MASK (1U << 1) #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_ETRW_UNORDERED (0U << 5) #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_ETRW_MASK (1U << 5) #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_AXISW_UNORDERED (0U << 13) #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_AXISW_MASK (1U << 13) #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_EQOSW_UNORDERED (0U << 15) #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_EQOSW_ORDERED (1U << 15) #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_EQOSW_MASK (1U << 15) #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_UFSHCW_UNORDERED (0U << 17) #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_UFSHCW_MASK (1U << 17) #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_BPMPDMAW_UNORDERED (0U << 22) #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_BPMPDMAW_MASK (1U << 22) #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_AONDMAW_UNORDERED (0U << 26) #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_AONDMAW_MASK (1U << 26) #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_SCEDMAW_UNORDERED (0U << 30) #define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_SCEDMAW_MASK (1U << 30) #define MC_PCFIFO_CLIENT_CONFIG5 0xbf4U #define MC_PCFIFO_CLIENT_CONFIG5_RESET_VAL 0U #define MC_PCFIFO_CLIENT_CONFIG5_PCFIFO_APEDMAW_UNORDERED (0U << 0) #define MC_PCFIFO_CLIENT_CONFIG5_PCFIFO_APEDMAW_MASK (1U << 0) /******************************************************************************* * Stream ID Override Config registers ******************************************************************************/ #define MC_STREAMID_OVERRIDE_CFG_PTCR 0x000U #define MC_STREAMID_OVERRIDE_CFG_AFIR 0x070U #define MC_STREAMID_OVERRIDE_CFG_HDAR 0x0A8U #define MC_STREAMID_OVERRIDE_CFG_HOST1XDMAR 0x0B0U #define MC_STREAMID_OVERRIDE_CFG_NVENCSRD 0x0E0U #define MC_STREAMID_OVERRIDE_CFG_SATAR 0x0F8U #define MC_STREAMID_OVERRIDE_CFG_MPCORER 0x138U #define MC_STREAMID_OVERRIDE_CFG_NVENCSWR 0x158U #define MC_STREAMID_OVERRIDE_CFG_AFIW 0x188U #define MC_STREAMID_OVERRIDE_CFG_HDAW 0x1A8U #define MC_STREAMID_OVERRIDE_CFG_MPCOREW 0x1C8U #define MC_STREAMID_OVERRIDE_CFG_SATAW 0x1E8U #define MC_STREAMID_OVERRIDE_CFG_ISPRA 0x220U #define MC_STREAMID_OVERRIDE_CFG_ISPWA 0x230U #define MC_STREAMID_OVERRIDE_CFG_ISPWB 0x238U #define MC_STREAMID_OVERRIDE_CFG_XUSB_HOSTR 0x250U #define MC_STREAMID_OVERRIDE_CFG_XUSB_HOSTW 0x258U #define MC_STREAMID_OVERRIDE_CFG_XUSB_DEVR 0x260U #define MC_STREAMID_OVERRIDE_CFG_XUSB_DEVW 0x268U #define MC_STREAMID_OVERRIDE_CFG_TSECSRD 0x2A0U #define MC_STREAMID_OVERRIDE_CFG_TSECSWR 0x2A8U #define MC_STREAMID_OVERRIDE_CFG_GPUSRD 0x2C0U #define MC_STREAMID_OVERRIDE_CFG_GPUSWR 0x2C8U #define MC_STREAMID_OVERRIDE_CFG_SDMMCRA 0x300U #define MC_STREAMID_OVERRIDE_CFG_SDMMCRAA 0x308U #define MC_STREAMID_OVERRIDE_CFG_SDMMCR 0x310U #define MC_STREAMID_OVERRIDE_CFG_SDMMCRAB 0x318U #define MC_STREAMID_OVERRIDE_CFG_SDMMCWA 0x320U #define MC_STREAMID_OVERRIDE_CFG_SDMMCWAA 0x328U #define MC_STREAMID_OVERRIDE_CFG_SDMMCW 0x330U #define MC_STREAMID_OVERRIDE_CFG_SDMMCWAB 0x338U #define MC_STREAMID_OVERRIDE_CFG_VICSRD 0x360U #define MC_STREAMID_OVERRIDE_CFG_VICSWR 0x368U #define MC_STREAMID_OVERRIDE_CFG_VIW 0x390U #define MC_STREAMID_OVERRIDE_CFG_NVDECSRD 0x3C0U #define MC_STREAMID_OVERRIDE_CFG_NVDECSWR 0x3C8U #define MC_STREAMID_OVERRIDE_CFG_APER 0x3D0U #define MC_STREAMID_OVERRIDE_CFG_APEW 0x3D8U #define MC_STREAMID_OVERRIDE_CFG_NVJPGSRD 0x3F0U #define MC_STREAMID_OVERRIDE_CFG_NVJPGSWR 0x3F8U #define MC_STREAMID_OVERRIDE_CFG_SESRD 0x400U #define MC_STREAMID_OVERRIDE_CFG_SESWR 0x408U #define MC_STREAMID_OVERRIDE_CFG_ETRR 0x420U #define MC_STREAMID_OVERRIDE_CFG_ETRW 0x428U #define MC_STREAMID_OVERRIDE_CFG_TSECSRDB 0x430U #define MC_STREAMID_OVERRIDE_CFG_TSECSWRB 0x438U #define MC_STREAMID_OVERRIDE_CFG_GPUSRD2 0x440U #define MC_STREAMID_OVERRIDE_CFG_GPUSWR2 0x448U #define MC_STREAMID_OVERRIDE_CFG_AXISR 0x460U #define MC_STREAMID_OVERRIDE_CFG_AXISW 0x468U #define MC_STREAMID_OVERRIDE_CFG_EQOSR 0x470U #define MC_STREAMID_OVERRIDE_CFG_EQOSW 0x478U #define MC_STREAMID_OVERRIDE_CFG_UFSHCR 0x480U #define MC_STREAMID_OVERRIDE_CFG_UFSHCW 0x488U #define MC_STREAMID_OVERRIDE_CFG_NVDISPLAYR 0x490U #define MC_STREAMID_OVERRIDE_CFG_BPMPR 0x498U #define MC_STREAMID_OVERRIDE_CFG_BPMPW 0x4A0U #define MC_STREAMID_OVERRIDE_CFG_BPMPDMAR 0x4A8U #define MC_STREAMID_OVERRIDE_CFG_BPMPDMAW 0x4B0U #define MC_STREAMID_OVERRIDE_CFG_AONR 0x4B8U #define MC_STREAMID_OVERRIDE_CFG_AONW 0x4C0U #define MC_STREAMID_OVERRIDE_CFG_AONDMAR 0x4C8U #define MC_STREAMID_OVERRIDE_CFG_AONDMAW 0x4D0U #define MC_STREAMID_OVERRIDE_CFG_SCER 0x4D8U #define MC_STREAMID_OVERRIDE_CFG_SCEW 0x4E0U #define MC_STREAMID_OVERRIDE_CFG_SCEDMAR 0x4E8U #define MC_STREAMID_OVERRIDE_CFG_SCEDMAW 0x4F0U #define MC_STREAMID_OVERRIDE_CFG_APEDMAR 0x4F8U #define MC_STREAMID_OVERRIDE_CFG_APEDMAW 0x500U #define MC_STREAMID_OVERRIDE_CFG_NVDISPLAYR1 0x508U #define MC_STREAMID_OVERRIDE_CFG_VICSRD1 0x510U #define MC_STREAMID_OVERRIDE_CFG_NVDECSRD1 0x518U /******************************************************************************* * Macro to calculate Security cfg register addr from StreamID Override register ******************************************************************************/ #define MC_STREAMID_OVERRIDE_TO_SECURITY_CFG(addr) ((addr) + (uint32_t)sizeof(uint32_t)) #define MC_TXN_OVERRIDE_CONFIG_COH_PATH_NO_OVERRIDE_SO_DEV (0U << 4) #define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_NON_COHERENT_SO_DEV (1U << 4) #define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_COHERENT_SO_DEV (2U << 4) #define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_COHERENT_SNOOP_SO_DEV (3U << 4) #define MC_TXN_OVERRIDE_CONFIG_COH_PATH_NO_OVERRIDE_NORMAL (0U << 8) #define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_NON_COHERENT_NORMAL (1U << 8) #define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_COHERENT_NORMAL (2U << 8) #define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_COHERENT_SNOOP_NORMAL (3U << 8) #define MC_TXN_OVERRIDE_CONFIG_CGID_SO_DEV_ZERO (0U << 12) #define MC_TXN_OVERRIDE_CONFIG_CGID_SO_DEV_CLIENT_AXI_ID (1U << 12) /******************************************************************************* * Memory Controller transaction override config registers ******************************************************************************/ #define MC_TXN_OVERRIDE_CONFIG_HDAR 0x10a8U #define MC_TXN_OVERRIDE_CONFIG_BPMPW 0x14a0U #define MC_TXN_OVERRIDE_CONFIG_PTCR 0x1000U #define MC_TXN_OVERRIDE_CONFIG_NVDISPLAYR 0x1490U #define MC_TXN_OVERRIDE_CONFIG_EQOSW 0x1478U #define MC_TXN_OVERRIDE_CONFIG_NVJPGSWR 0x13f8U #define MC_TXN_OVERRIDE_CONFIG_ISPRA 0x1220U #define MC_TXN_OVERRIDE_CONFIG_SDMMCWAA 0x1328U #define MC_TXN_OVERRIDE_CONFIG_VICSRD 0x1360U #define MC_TXN_OVERRIDE_CONFIG_MPCOREW 0x11c8U #define MC_TXN_OVERRIDE_CONFIG_GPUSRD 0x12c0U #define MC_TXN_OVERRIDE_CONFIG_AXISR 0x1460U #define MC_TXN_OVERRIDE_CONFIG_SCEDMAW 0x14f0U #define MC_TXN_OVERRIDE_CONFIG_SDMMCW 0x1330U #define MC_TXN_OVERRIDE_CONFIG_EQOSR 0x1470U #define MC_TXN_OVERRIDE_CONFIG_APEDMAR 0x14f8U #define MC_TXN_OVERRIDE_CONFIG_NVENCSRD 0x10e0U #define MC_TXN_OVERRIDE_CONFIG_SDMMCRAB 0x1318U #define MC_TXN_OVERRIDE_CONFIG_VICSRD1 0x1510U #define MC_TXN_OVERRIDE_CONFIG_BPMPDMAR 0x14a8U #define MC_TXN_OVERRIDE_CONFIG_VIW 0x1390U #define MC_TXN_OVERRIDE_CONFIG_SDMMCRAA 0x1308U #define MC_TXN_OVERRIDE_CONFIG_AXISW 0x1468U #define MC_TXN_OVERRIDE_CONFIG_XUSB_DEVR 0x1260U #define MC_TXN_OVERRIDE_CONFIG_UFSHCR 0x1480U #define MC_TXN_OVERRIDE_CONFIG_TSECSWR 0x12a8U #define MC_TXN_OVERRIDE_CONFIG_GPUSWR 0x12c8U #define MC_TXN_OVERRIDE_CONFIG_SATAR 0x10f8U #define MC_TXN_OVERRIDE_CONFIG_XUSB_HOSTW 0x1258U #define MC_TXN_OVERRIDE_CONFIG_TSECSWRB 0x1438U #define MC_TXN_OVERRIDE_CONFIG_GPUSRD2 0x1440U #define MC_TXN_OVERRIDE_CONFIG_SCEDMAR 0x14e8U #define MC_TXN_OVERRIDE_CONFIG_GPUSWR2 0x1448U #define MC_TXN_OVERRIDE_CONFIG_AONDMAW 0x14d0U #define MC_TXN_OVERRIDE_CONFIG_APEDMAW 0x1500U #define MC_TXN_OVERRIDE_CONFIG_AONW 0x14c0U #define MC_TXN_OVERRIDE_CONFIG_HOST1XDMAR 0x10b0U #define MC_TXN_OVERRIDE_CONFIG_ETRR 0x1420U #define MC_TXN_OVERRIDE_CONFIG_SESWR 0x1408U #define MC_TXN_OVERRIDE_CONFIG_NVJPGSRD 0x13f0U #define MC_TXN_OVERRIDE_CONFIG_NVDECSRD 0x13c0U #define MC_TXN_OVERRIDE_CONFIG_TSECSRDB 0x1430U #define MC_TXN_OVERRIDE_CONFIG_BPMPDMAW 0x14b0U #define MC_TXN_OVERRIDE_CONFIG_APER 0x13d0U #define MC_TXN_OVERRIDE_CONFIG_NVDECSRD1 0x1518U #define MC_TXN_OVERRIDE_CONFIG_XUSB_HOSTR 0x1250U #define MC_TXN_OVERRIDE_CONFIG_ISPWA 0x1230U #define MC_TXN_OVERRIDE_CONFIG_SESRD 0x1400U #define MC_TXN_OVERRIDE_CONFIG_SCER 0x14d8U #define MC_TXN_OVERRIDE_CONFIG_AONR 0x14b8U #define MC_TXN_OVERRIDE_CONFIG_MPCORER 0x1138U #define MC_TXN_OVERRIDE_CONFIG_SDMMCWA 0x1320U #define MC_TXN_OVERRIDE_CONFIG_HDAW 0x11a8U #define MC_TXN_OVERRIDE_CONFIG_NVDECSWR 0x13c8U #define MC_TXN_OVERRIDE_CONFIG_UFSHCW 0x1488U #define MC_TXN_OVERRIDE_CONFIG_AONDMAR 0x14c8U #define MC_TXN_OVERRIDE_CONFIG_SATAW 0x11e8U #define MC_TXN_OVERRIDE_CONFIG_ETRW 0x1428U #define MC_TXN_OVERRIDE_CONFIG_VICSWR 0x1368U #define MC_TXN_OVERRIDE_CONFIG_NVENCSWR 0x1158U #define MC_TXN_OVERRIDE_CONFIG_AFIR 0x1070U #define MC_TXN_OVERRIDE_CONFIG_SDMMCWAB 0x1338U #define MC_TXN_OVERRIDE_CONFIG_SDMMCRA 0x1300U #define MC_TXN_OVERRIDE_CONFIG_NVDISPLAYR1 0x1508U #define MC_TXN_OVERRIDE_CONFIG_ISPWB 0x1238U #define MC_TXN_OVERRIDE_CONFIG_BPMPR 0x1498U #define MC_TXN_OVERRIDE_CONFIG_APEW 0x13d8U #define MC_TXN_OVERRIDE_CONFIG_SDMMCR 0x1310U #define MC_TXN_OVERRIDE_CONFIG_XUSB_DEVW 0x1268U #define MC_TXN_OVERRIDE_CONFIG_TSECSRD 0x12a0U #define MC_TXN_OVERRIDE_CONFIG_AFIW 0x1188U #define MC_TXN_OVERRIDE_CONFIG_SCEW 0x14e0U #define MC_TXN_OVERRIDE_CONFIG_AXID_OVERRIDE_CGID (1U << 0) #define MC_TXN_OVERRIDE_CONFIG_COH_PATH_OVERRIDE_SO_DEV (2U << 4) #define MC_TXN_OVERRIDE_CONFIG_AXID_OVERRIDE_SO_DEV_CGID_SO_DEV_CLIENT (1U << 12) /******************************************************************************* * Non-SO_DEV transactions override values for CGID_TAG bitfield for the * MC_TXN_OVERRIDE_CONFIG_{module} registers ******************************************************************************/ #define MC_TXN_OVERRIDE_CGID_TAG_DEFAULT 0U #define MC_TXN_OVERRIDE_CGID_TAG_CLIENT_AXI_ID 1U #define MC_TXN_OVERRIDE_CGID_TAG_ZERO 2U #define MC_TXN_OVERRIDE_CGID_TAG_ADR 3U #define MC_TXN_OVERRIDE_CGID_TAG_MASK 3ULL /******************************************************************************* * Memory Controller Reset Control registers ******************************************************************************/ #define MC_CLIENT_HOTRESET_CTRL0 0x200U #define MC_CLIENT_HOTRESET_CTRL0_RESET_VAL 0U #define MC_CLIENT_HOTRESET_CTRL0_AFI_FLUSH_ENB (1U << 0) #define MC_CLIENT_HOTRESET_CTRL0_HC_FLUSH_ENB (1U << 6) #define MC_CLIENT_HOTRESET_CTRL0_HDA_FLUSH_ENB (1U << 7) #define MC_CLIENT_HOTRESET_CTRL0_ISP2_FLUSH_ENB (1U << 8) #define MC_CLIENT_HOTRESET_CTRL0_MPCORE_FLUSH_ENB (1U << 9) #define MC_CLIENT_HOTRESET_CTRL0_NVENC_FLUSH_ENB (1U << 11) #define MC_CLIENT_HOTRESET_CTRL0_SATA_FLUSH_ENB (1U << 15) #define MC_CLIENT_HOTRESET_CTRL0_VI_FLUSH_ENB (1U << 17) #define MC_CLIENT_HOTRESET_CTRL0_VIC_FLUSH_ENB (1U << 18) #define MC_CLIENT_HOTRESET_CTRL0_XUSB_HOST_FLUSH_ENB (1U << 19) #define MC_CLIENT_HOTRESET_CTRL0_XUSB_DEV_FLUSH_ENB (1U << 20) #define MC_CLIENT_HOTRESET_CTRL0_TSEC_FLUSH_ENB (1U << 22) #define MC_CLIENT_HOTRESET_CTRL0_SDMMC1A_FLUSH_ENB (1U << 29) #define MC_CLIENT_HOTRESET_CTRL0_SDMMC2A_FLUSH_ENB (1U << 30) #define MC_CLIENT_HOTRESET_CTRL0_SDMMC3A_FLUSH_ENB (1U << 31) #define MC_CLIENT_HOTRESET_STATUS0 0x204U #define MC_CLIENT_HOTRESET_CTRL1 0x970U #define MC_CLIENT_HOTRESET_CTRL1_RESET_VAL 0U #define MC_CLIENT_HOTRESET_CTRL1_SDMMC4A_FLUSH_ENB (1U << 0) #define MC_CLIENT_HOTRESET_CTRL1_GPU_FLUSH_ENB (1U << 2) #define MC_CLIENT_HOTRESET_CTRL1_NVDEC_FLUSH_ENB (1U << 5) #define MC_CLIENT_HOTRESET_CTRL1_APE_FLUSH_ENB (1U << 6) #define MC_CLIENT_HOTRESET_CTRL1_SE_FLUSH_ENB (1U << 7) #define MC_CLIENT_HOTRESET_CTRL1_NVJPG_FLUSH_ENB (1U << 8) #define MC_CLIENT_HOTRESET_CTRL1_ETR_FLUSH_ENB (1U << 12) #define MC_CLIENT_HOTRESET_CTRL1_TSECB_FLUSH_ENB (1U << 13) #define MC_CLIENT_HOTRESET_CTRL1_AXIS_FLUSH_ENB (1U << 18) #define MC_CLIENT_HOTRESET_CTRL1_EQOS_FLUSH_ENB (1U << 19) #define MC_CLIENT_HOTRESET_CTRL1_UFSHC_FLUSH_ENB (1U << 20) #define MC_CLIENT_HOTRESET_CTRL1_NVDISPLAY_FLUSH_ENB (1U << 21) #define MC_CLIENT_HOTRESET_CTRL1_BPMP_FLUSH_ENB (1U << 22) #define MC_CLIENT_HOTRESET_CTRL1_AON_FLUSH_ENB (1U << 23) #define MC_CLIENT_HOTRESET_CTRL1_SCE_FLUSH_ENB (1U << 24) #define MC_CLIENT_HOTRESET_STATUS1 0x974U #endif /* TEGRA_MC_DEF_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/t210/000077500000000000000000000000001355360272700225365ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/include/t210/tegra_def.h000066400000000000000000000264301355360272700246340ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TEGRA_DEF_H #define TEGRA_DEF_H #include /******************************************************************************* * Power down state IDs ******************************************************************************/ #define PSTATE_ID_CORE_POWERDN U(7) #define PSTATE_ID_CLUSTER_IDLE U(16) #define PSTATE_ID_SOC_POWERDN U(27) /******************************************************************************* * This value is used by the PSCI implementation during the `SYSTEM_SUSPEND` * call as the `state-id` field in the 'power state' parameter. ******************************************************************************/ #define PLAT_SYS_SUSPEND_STATE_ID PSTATE_ID_SOC_POWERDN /******************************************************************************* * Platform power states (used by PSCI framework) * * - PLAT_MAX_RET_STATE should be less than lowest PSTATE_ID * - PLAT_MAX_OFF_STATE should be greater than the highest PSTATE_ID ******************************************************************************/ #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE (PSTATE_ID_SOC_POWERDN + U(1)) /******************************************************************************* * Chip specific page table and MMU setup constants ******************************************************************************/ #define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 35) #define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 35) /******************************************************************************* * SC7 entry firmware's header size ******************************************************************************/ #define SC7ENTRY_FW_HEADER_SIZE_BYTES U(0x400) /******************************************************************************* * iRAM memory constants ******************************************************************************/ #define TEGRA_IRAM_BASE U(0x40000000) #define TEGRA_IRAM_A_SIZE U(0x10000) /* 64KB */ #define TEGRA_IRAM_SIZE U(40000) /* 256KB */ /******************************************************************************* * GIC memory map ******************************************************************************/ #define TEGRA_GICD_BASE U(0x50041000) #define TEGRA_GICC_BASE U(0x50042000) /******************************************************************************* * Secure IRQ definitions ******************************************************************************/ #define TEGRA210_WDT_CPU_LEGACY_FIQ U(28) /******************************************************************************* * Tegra Memory Select Switch Controller constants ******************************************************************************/ #define TEGRA_MSELECT_BASE U(0x50060000) #define MSELECT_CONFIG U(0x0) #define ENABLE_WRAP_INCR_MASTER2_BIT (U(1) << U(29)) #define ENABLE_WRAP_INCR_MASTER1_BIT (U(1) << U(28)) #define ENABLE_WRAP_INCR_MASTER0_BIT (U(1) << U(27)) #define UNSUPPORTED_TX_ERR_MASTER2_BIT (U(1) << U(25)) #define UNSUPPORTED_TX_ERR_MASTER1_BIT (U(1) << U(24)) #define ENABLE_UNSUP_TX_ERRORS (UNSUPPORTED_TX_ERR_MASTER2_BIT | \ UNSUPPORTED_TX_ERR_MASTER1_BIT) #define ENABLE_WRAP_TO_INCR_BURSTS (ENABLE_WRAP_INCR_MASTER2_BIT | \ ENABLE_WRAP_INCR_MASTER1_BIT | \ ENABLE_WRAP_INCR_MASTER0_BIT) /******************************************************************************* * Tegra Resource Semaphore constants ******************************************************************************/ #define TEGRA_RES_SEMA_BASE 0x60001000UL #define STA_OFFSET 0UL #define SET_OFFSET 4UL #define CLR_OFFSET 8UL /******************************************************************************* * Tegra Primary Interrupt Controller constants ******************************************************************************/ #define TEGRA_PRI_ICTLR_BASE 0x60004000UL #define CPU_IEP_FIR_SET 0x18UL /******************************************************************************* * Tegra micro-seconds timer constants ******************************************************************************/ #define TEGRA_TMRUS_BASE U(0x60005010) #define TEGRA_TMRUS_SIZE U(0x1000) /******************************************************************************* * Tegra Clock and Reset Controller constants ******************************************************************************/ #define TEGRA_CAR_RESET_BASE U(0x60006000) #define TEGRA_BOND_OUT_H U(0x74) #define APB_DMA_LOCK_BIT (U(1) << 2) #define AHB_DMA_LOCK_BIT (U(1) << 1) #define TEGRA_BOND_OUT_U U(0x78) #define IRAM_D_LOCK_BIT (U(1) << 23) #define IRAM_C_LOCK_BIT (U(1) << 22) #define IRAM_B_LOCK_BIT (U(1) << 21) #define TEGRA_GPU_RESET_REG_OFFSET U(0x28C) #define TEGRA_GPU_RESET_GPU_SET_OFFSET U(0x290) #define GPU_RESET_BIT (U(1) << 24) #define GPU_SET_BIT (U(1) << 24) #define TEGRA_RST_DEV_SET_Y U(0x2a8) #define NVENC_RESET_BIT (U(1) << 27) #define TSECB_RESET_BIT (U(1) << 14) #define APE_RESET_BIT (U(1) << 6) #define NVJPG_RESET_BIT (U(1) << 3) #define NVDEC_RESET_BIT (U(1) << 2) #define TEGRA_RST_DEV_SET_L U(0x300) #define HOST1X_RESET_BIT (U(1) << 28) #define ISP_RESET_BIT (U(1) << 23) #define USBD_RESET_BIT (U(1) << 22) #define VI_RESET_BIT (U(1) << 20) #define SDMMC4_RESET_BIT (U(1) << 15) #define SDMMC1_RESET_BIT (U(1) << 14) #define SDMMC2_RESET_BIT (U(1) << 9) #define TEGRA_RST_DEV_SET_H U(0x308) #define USB2_RESET_BIT (U(1) << 26) #define APBDMA_RESET_BIT (U(1) << 2) #define AHBDMA_RESET_BIT (U(1) << 1) #define TEGRA_RST_DEV_SET_U U(0x310) #define XUSB_DEV_RESET_BIT (U(1) << 31) #define XUSB_HOST_RESET_BIT (U(1) << 25) #define TSEC_RESET_BIT (U(1) << 19) #define PCIE_RESET_BIT (U(1) << 6) #define SDMMC3_RESET_BIT (U(1) << 5) #define TEGRA_RST_DEVICES_V U(0x358) #define TEGRA_RST_DEVICES_W U(0x35C) #define ENTROPY_CLK_ENB_BIT (U(1) << 21) #define TEGRA_CLK_OUT_ENB_V U(0x360) #define SE_CLK_ENB_BIT (U(1) << 31) #define TEGRA_CLK_OUT_ENB_W U(0x364) #define ENTROPY_RESET_BIT (U(1) << 21) #define TEGRA_RST_DEV_SET_V U(0x430) #define SE_RESET_BIT (U(1) << 31) #define HDA_RESET_BIT (U(1) << 29) #define SATA_RESET_BIT (U(1) << 28) #define TEGRA_RST_DEV_CLR_V U(0x434) #define TEGRA_CLK_ENB_V U(0x440) /******************************************************************************* * Tegra Flow Controller constants ******************************************************************************/ #define TEGRA_FLOWCTRL_BASE U(0x60007000) /******************************************************************************* * Tegra AHB arbitration controller ******************************************************************************/ #define TEGRA_AHB_ARB_BASE 0x6000C000UL /******************************************************************************* * Tegra Secure Boot Controller constants ******************************************************************************/ #define TEGRA_SB_BASE U(0x6000C200) /******************************************************************************* * Tegra Exception Vectors constants ******************************************************************************/ #define TEGRA_EVP_BASE U(0x6000F000) /******************************************************************************* * Tegra Miscellaneous register constants ******************************************************************************/ #define TEGRA_MISC_BASE U(0x70000000) #define HARDWARE_REVISION_OFFSET U(0x804) #define APB_SLAVE_SECURITY_ENABLE U(0xC00) #define PMC_SECURITY_EN_BIT (U(1) << 13) #define PINMUX_AUX_DVFS_PWM U(0x3184) #define PINMUX_PWM_TRISTATE (U(1) << 4) /******************************************************************************* * Tegra UART controller base addresses ******************************************************************************/ #define TEGRA_UARTA_BASE U(0x70006000) #define TEGRA_UARTB_BASE U(0x70006040) #define TEGRA_UARTC_BASE U(0x70006200) #define TEGRA_UARTD_BASE U(0x70006300) #define TEGRA_UARTE_BASE U(0x70006400) /******************************************************************************* * Tegra Fuse Controller related constants ******************************************************************************/ #define TEGRA_FUSE_BASE 0x7000F800UL #define FUSE_BOOT_SECURITY_INFO 0x268UL #define FUSE_ATOMIC_SAVE_CARVEOUT_EN (0x1U << 7) #define FUSE_JTAG_SECUREID_VALID (0x104UL) #define ECID_VALID (0x1UL) /******************************************************************************* * Tegra Power Mgmt Controller constants ******************************************************************************/ #define TEGRA_PMC_BASE U(0x7000E400) #define TEGRA_PMC_SIZE U(0xC00) /* 3k */ /******************************************************************************* * Tegra Atomics constants ******************************************************************************/ #define TEGRA_ATOMICS_BASE 0x70016000UL #define TRIGGER0_REG_OFFSET 0UL #define TRIGGER_WIDTH_SHIFT 4UL #define TRIGGER_ID_SHIFT 16UL #define RESULT0_REG_OFFSET 0xC00UL /******************************************************************************* * Tegra Memory Controller constants ******************************************************************************/ #define TEGRA_MC_BASE U(0x70019000) /* Memory Controller Interrupt Status */ #define MC_INTSTATUS 0x00U /* TZDRAM carveout configuration registers */ #define MC_SECURITY_CFG0_0 U(0x70) #define MC_SECURITY_CFG1_0 U(0x74) #define MC_SECURITY_CFG3_0 U(0x9BC) /* Video Memory carveout configuration registers */ #define MC_VIDEO_PROTECT_BASE_HI U(0x978) #define MC_VIDEO_PROTECT_BASE_LO U(0x648) #define MC_VIDEO_PROTECT_SIZE_MB U(0x64c) /* SMMU configuration registers*/ #define MC_SMMU_PPCS_ASID_0 0x270U #define PPCS_SMMU_ENABLE (0x1U << 31) /******************************************************************************* * Tegra CLDVFS constants ******************************************************************************/ #define TEGRA_CL_DVFS_BASE U(0x70110000) #define DVFS_DFLL_CTRL U(0x00) #define ENABLE_OPEN_LOOP U(1) #define ENABLE_CLOSED_LOOP U(2) #define DVFS_DFLL_OUTPUT_CFG U(0x20) #define DFLL_OUTPUT_CFG_I2C_EN_BIT (U(1) << 30) #define DFLL_OUTPUT_CFG_CLK_EN_BIT (U(1) << 6) /******************************************************************************* * Tegra SE constants ******************************************************************************/ #define TEGRA_SE1_BASE U(0x70012000) #define TEGRA_SE2_BASE U(0x70412000) #define TEGRA_PKA1_BASE U(0x70420000) #define TEGRA_SE2_RANGE_SIZE U(0x2000) #define SE_TZRAM_SECURITY U(0x4) /******************************************************************************* * Tegra TZRAM constants ******************************************************************************/ #define TEGRA_TZRAM_BASE U(0x7C010000) #define TEGRA_TZRAM_SIZE U(0x10000) /******************************************************************************* * Tegra TZRAM carveout constants ******************************************************************************/ #define TEGRA_TZRAM_CARVEOUT_BASE U(0x7C04C000) #define TEGRA_TZRAM_CARVEOUT_SIZE U(0x4000) #endif /* TEGRA_DEF_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/tegra_platform.h000066400000000000000000000032721355360272700252330ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TEGRA_PLATFORM_H #define TEGRA_PLATFORM_H #include #include #include /******************************************************************************* * Tegra major, minor version helper macros ******************************************************************************/ #define MAJOR_VERSION_SHIFT U(0x4) #define MAJOR_VERSION_MASK U(0xF) #define MINOR_VERSION_SHIFT U(0x10) #define MINOR_VERSION_MASK U(0xF) #define CHIP_ID_SHIFT U(8) #define CHIP_ID_MASK U(0xFF) #define PRE_SI_PLATFORM_SHIFT U(0x14) #define PRE_SI_PLATFORM_MASK U(0xF) /******************************************************************************* * Tegra chip ID values ******************************************************************************/ #define TEGRA_CHIPID_TEGRA13 U(0x13) #define TEGRA_CHIPID_TEGRA21 U(0x21) #define TEGRA_CHIPID_TEGRA18 U(0x18) #ifndef __ASSEMBLER__ /* * Tegra chip ID major/minor identifiers */ uint32_t tegra_get_chipid_major(void); uint32_t tegra_get_chipid_minor(void); /* * Tegra chip ID identifiers */ bool tegra_chipid_is_t132(void); bool tegra_chipid_is_t186(void); bool tegra_chipid_is_t210(void); bool tegra_chipid_is_t210_b01(void); /* * Tegra platform identifiers */ bool tegra_platform_is_silicon(void); bool tegra_platform_is_qt(void); bool tegra_platform_is_emulation(void); bool tegra_platform_is_linsim(void); bool tegra_platform_is_fpga(void); bool tegra_platform_is_unit_fpga(void); bool tegra_platform_is_virt_dev_kit(void); #endif /* __ASSEMBLER__ */ #endif /* TEGRA_PLATFORM_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/include/tegra_private.h000066400000000000000000000140211355360272700250530ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TEGRA_PRIVATE_H #define TEGRA_PRIVATE_H #include #include #include #include #include #include #include /******************************************************************************* * Tegra DRAM memory base address ******************************************************************************/ #define TEGRA_DRAM_BASE ULL(0x80000000) #define TEGRA_DRAM_END ULL(0x27FFFFFFF) /******************************************************************************* * Implementation defined ACTLR_EL1 bit definitions ******************************************************************************/ #define ACTLR_EL1_PMSTATE_MASK (ULL(0xF) << 0) /******************************************************************************* * Implementation defined ACTLR_EL2 bit definitions ******************************************************************************/ #define ACTLR_EL2_PMSTATE_MASK (ULL(0xF) << 0) /******************************************************************************* * Struct for parameters received from BL2 ******************************************************************************/ typedef struct plat_params_from_bl2 { /* TZ memory size */ uint64_t tzdram_size; /* TZ memory base */ uint64_t tzdram_base; /* UART port ID */ int32_t uart_id; /* L2 ECC parity protection disable flag */ int32_t l2_ecc_parity_prot_dis; /* SHMEM base address for storing the boot logs */ uint64_t boot_profiler_shmem_base; /* System Suspend Entry Firmware size */ uint64_t sc7entry_fw_size; /* System Suspend Entry Firmware base address */ uint64_t sc7entry_fw_base; } plat_params_from_bl2_t; /******************************************************************************* * Helper function to access l2ctlr_el1 register on Cortex-A57 CPUs ******************************************************************************/ DEFINE_RENAME_SYSREG_RW_FUNCS(l2ctlr_el1, CORTEX_A57_L2CTLR_EL1) /******************************************************************************* * Struct describing parameters passed to bl31 ******************************************************************************/ struct tegra_bl31_params { param_header_t h; image_info_t *bl31_image_info; entry_point_info_t *bl32_ep_info; image_info_t *bl32_image_info; entry_point_info_t *bl33_ep_info; image_info_t *bl33_image_info; }; /* Declarations for plat_psci_handlers.c */ int32_t tegra_soc_validate_power_state(uint32_t power_state, psci_power_state_t *req_state); /* Declarations for plat_setup.c */ const mmap_region_t *plat_get_mmio_map(void); uint32_t plat_get_console_from_id(int32_t id); void plat_gic_setup(void); struct tegra_bl31_params *plat_get_bl31_params(void); plat_params_from_bl2_t *plat_get_bl31_plat_params(void); void plat_early_platform_setup(void); void plat_late_platform_setup(void); /* Declarations for plat_secondary.c */ void plat_secondary_setup(void); int32_t plat_lock_cpu_vectors(void); /* Declarations for tegra_fiq_glue.c */ void tegra_fiq_handler_setup(void); int tegra_fiq_get_intr_context(void); void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint); /* Declarations for tegra_security.c */ void tegra_security_setup(void); void tegra_security_setup_videomem(uintptr_t base, uint64_t size); /* Declarations for tegra_pm.c */ extern uint8_t tegra_fake_system_suspend; void tegra_pm_system_suspend_entry(void); void tegra_pm_system_suspend_exit(void); int32_t tegra_system_suspended(void); int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state); int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state); int32_t tegra_soc_pwr_domain_on(u_register_t mpidr); int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state); int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state); int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state); int32_t tegra_soc_prepare_system_reset(void); __dead2 void tegra_soc_prepare_system_off(void); plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl, const plat_local_state_t *states, uint32_t ncpu); void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state); void tegra_cpu_standby(plat_local_state_t cpu_state); int32_t tegra_pwr_domain_on(u_register_t mpidr); void tegra_pwr_domain_off(const psci_power_state_t *target_state); void tegra_pwr_domain_suspend(const psci_power_state_t *target_state); void __dead2 tegra_pwr_domain_power_down_wfi(const psci_power_state_t *target_state); void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state); void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state); __dead2 void tegra_system_off(void); __dead2 void tegra_system_reset(void); int32_t tegra_validate_power_state(uint32_t power_state, psci_power_state_t *req_state); int32_t tegra_validate_ns_entrypoint(uintptr_t entrypoint); /* Declarations for tegraXXX_pm.c */ int tegra_prepare_cpu_suspend(unsigned int id, unsigned int afflvl); int tegra_prepare_cpu_on_finish(unsigned long mpidr); /* Declarations for tegra_bl31_setup.c */ plat_params_from_bl2_t *bl31_get_plat_params(void); int32_t bl31_check_ns_address(uint64_t base, uint64_t size_in_bytes); /* Declarations for tegra_delay_timer.c */ void tegra_delay_timer_init(void); void tegra_secure_entrypoint(void); void tegra186_cpu_reset_handler(void); /* Declarations for tegra_sip_calls.c */ uintptr_t tegra_sip_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); int plat_sip_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, const void *cookie, void *handle, uint64_t flags); #endif /* TEGRA_PRIVATE_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/platform.mk000066400000000000000000000040741355360272700226070ustar00rootroot00000000000000# # Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # SOC_DIR := plat/nvidia/tegra/soc/${TARGET_SOC} # dump the state on crash console CRASH_REPORTING := 1 $(eval $(call add_define,CRASH_REPORTING)) # enable assert() for release/debug builds ENABLE_ASSERTIONS := 1 PLAT_LOG_LEVEL_ASSERT := 40 $(eval $(call add_define,PLAT_LOG_LEVEL_ASSERT)) # enable dynamic memory mapping PLAT_XLAT_TABLES_DYNAMIC := 1 $(eval $(call add_define,PLAT_XLAT_TABLES_DYNAMIC)) # Enable PSCI v1.0 extended state ID format PSCI_EXTENDED_STATE_ID := 1 # code and read-only data should be put on separate memory pages SEPARATE_CODE_AND_RODATA := 1 # do not use coherent memory USE_COHERENT_MEM := 0 # do not enable SVE ENABLE_SVE_FOR_NS := 0 # enable D-cache early during CPU warmboot WARMBOOT_ENABLE_DCACHE_EARLY := 1 # remove the standard libc OVERRIDE_LIBC := 1 include plat/nvidia/tegra/common/tegra_common.mk include ${SOC_DIR}/platform_${TARGET_SOC}.mk # modify BUILD_PLAT to point to SoC specific build directory BUILD_PLAT := ${BUILD_BASE}/${PLAT}/${TARGET_SOC}/${BUILD_TYPE} # platform cflags (enable signed comparisons, disable stdlib) TF_CFLAGS += -Wsign-compare -nostdlib # override with necessary libc files for the Tegra platform override LIBC_SRCS := $(addprefix lib/libc/, \ assert.c \ memcpy.c \ memmove.c \ memset.c \ printf.c \ putchar.c \ strlen.c \ snprintf.c) INCLUDES += -Iinclude/lib/libc \ -Iinclude/lib/libc/$(ARCH) \ ifneq ($(findstring armlink,$(notdir $(LD))),) # o suppress warnings for section mismatches, undefined symbols # o use only those libraries that are specified in the input file # list to resolve references # o create a static callgraph of functions # o resolve undefined symbols to el3_panic # o include only required sections TF_LDFLAGS += --diag_suppress=L6314,L6332 --no_scanlib --callgraph TF_LDFLAGS += --keep="*(__pubsub*)" --keep="*(rt_svc_descs*)" --keep="*(*cpu_ops)" ifeq (${ENABLE_PMF},1) TF_LDFLAGS += --keep="*(*pmf_svc_descs*)" endif endif trusted-firmware-a-2.2/plat/nvidia/tegra/scat/000077500000000000000000000000001355360272700213575ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/scat/bl31.scat000066400000000000000000000145231355360272700230010ustar00rootroot00000000000000#! armclang -E -x c /* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #define PAGE_SIZE (1024 * 4) LR_START BL31_BASE { __BL31_START__ +0 FIXED EMPTY 0 { /* placeholder */ } /* BL31_BASE address must be aligned on a page boundary. */ ScatterAssert((ImageBase(__BL31_START__) AND 0xFFF) == 0) } LR_TEXT BL31_BASE { __TEXT__ +0 FIXED { *(:gdef:bl31_entrypoint, +FIRST) *(.text*) *(.vectors) .ANY1(+RO-CODE) } __TEXT_EPILOGUE__ AlignExpr(+0, PAGE_SIZE) FIXED EMPTY 0 { /* section delimiter */ } } LR_RO_DATA +0 { __RODATA__ AlignExpr(ImageLimit(LR_TEXT), 0) FIXED { *(.rodata*) .ANY2(+RO-DATA) } /* Ensure 8-byte alignment for descriptors and ensure inclusion */ __RT_SVC_DESCS__ AlignExpr(ImageLimit(__RODATA__), 8) FIXED { *(rt_svc_descs) } #if ENABLE_PMF /* Ensure 8-byte alignment for descriptors and ensure inclusion */ __PMF_SVC_DESCS__ AlignExpr(ImageLimit(__RT_SVC_DESCS__), 8) FIXED { *(pmf_svc_descs) } #endif /* ENABLE_PMF */ /* * Ensure 8-byte alignment for cpu_ops so that its fields are also * aligned. */ __CPU_OPS__ AlignExpr(+0, 8) FIXED { *(cpu_ops) } /* * Keep the .got section in the RO section as it is patched * prior to enabling the MMU and having the .got in RO is better for * security. GOT is a table of addresses so ensure 8-byte alignment. */ __GOT__ AlignExpr(ImageLimit(__CPU_OPS__), 8) FIXED { *(.got) } /* Place pubsub sections for events */ __PUBSUB_EVENTS__ AlignExpr(+0, 8) EMPTY 0 { /* placeholder */ } #include __RODATA_EPILOGUE__ AlignExpr(+0, PAGE_SIZE) FIXED EMPTY 0 { /* section delimiter */ } } /* cpu_ops must always be defined */ ScatterAssert(ImageLength(__CPU_OPS__) > 0) #if ENABLE_SPM LR_SPM +0 { /* * Exception vectors of the SPM shim layer. They must be aligned to a 2K * address, but we need to place them in a separate page so that we can set * individual permissions to them, so the actual alignment needed is 4K. * * There's no need to include this into the RO section of BL31 because it * doesn't need to be accessed by BL31. */ __SPM_SHIM_EXCEPTIONS__ AlignExpr(ImageLimit(LR_RO_DATA), PAGE_SIZE) FIXED { *(.spm_shim_exceptions) } __SPM_SHIM_EXCEPTIONS_EPILOGUE__ AlignExpr(ImageLimit(__SPM_SHIM_EXCEPTIONS__), PAGE_SIZE) FIXED { /* placeholder */ } } #endif LR_RW_DATA +0 { __DATA__ AlignExpr(+0, 16) FIXED { *(.data*) *(.constdata) *(locale$$data) } } LR_RELA +0 { /* * .rela.dyn needs to come after .data for the read-elf utility to parse * this section correctly. Ensure 8-byte alignment so that the fields of * RELA data structure are aligned. */ __RELA__ AlignExpr(ImageLimit(LR_RW_DATA), 8) FIXED { *(.rela.dyn) } } #ifdef BL31_PROGBITS_LIMIT /* BL31 progbits has exceeded its limit. */ ScatterAssert(ImageLimit(LR_RELA) <= BL31_PROGBITS_LIMIT) #endif LR_STACKS +0 { __STACKS__ AlignExpr(+0, 64) FIXED { *(tzfw_normal_stacks) } } #define __BAKERY_LOCK_SIZE__ (ImageLimit(__BAKERY_LOCKS_EPILOGUE__) - \ ImageBase(__BAKERY_LOCKS__)) #define BAKERY_LOCK_SIZE (__BAKERY_LOCK_SIZE__ * (PLATFORM_CORE_COUNT - 1)) #define __PMF_TIMESTAMP_SIZE__ (ImageLimit(__PMF_TIMESTAMP__) - \ ImageBase(__PMF_TIMESTAMP__)) #define PER_CPU_TIMESTAMP_SIZE (__PMF_TIMESTAMP_SIZE__ * (PLATFORM_CORE_COUNT - 1)) LR_BSS +0 { __BSS__ AlignExpr(ImageLimit(LR_STACKS), 256) FIXED { *(.bss*) *(COMDAT) } #if !USE_COHERENT_MEM /* * Bakery locks are stored in normal .bss memory * * Each lock's data is spread across multiple cache lines, one per CPU, * but multiple locks can share the same cache line. * The compiler will allocate enough memory for one CPU's bakery locks, * the remaining cache lines are allocated by the linker script */ __BAKERY_LOCKS__ AlignExpr(ImageLimit(__BSS__), CACHE_WRITEBACK_GRANULE) FIXED { *(bakery_lock) } __BAKERY_LOCKS_EPILOGUE__ AlignExpr(ImageLimit(__BAKERY_LOCKS__), CACHE_WRITEBACK_GRANULE) FIXED EMPTY 0 { /* section delimiter */ } __PER_CPU_BAKERY_LOCKS__ ImageLimit(__BAKERY_LOCKS_EPILOGUE__) FIXED FILL 0 BAKERY_LOCK_SIZE { /* padded memory section to store per cpu bakery locks */ } #ifdef PLAT_PERCPU_BAKERY_LOCK_SIZE /* PLAT_PERCPU_BAKERY_LOCK_SIZE does not match bakery lock requirements */ ScatterAssert(__PER_CPU_BAKERY_LOCK_SIZE__ == PLAT_PERCPU_BAKERY_LOCK_SIZE) #endif #endif #if ENABLE_PMF /* * Time-stamps are stored in normal .bss memory * * The compiler will allocate enough memory for one CPU's time-stamps, * the remaining memory for other CPU's is allocated by the * linker script */ __PMF_TIMESTAMP__ AlignExpr(+0, CACHE_WRITEBACK_GRANULE) FIXED EMPTY CACHE_WRITEBACK_GRANULE { /* store timestamps in this carved out memory */ } __PMF_TIMESTAMP_EPILOGUE__ AlignExpr(ImageLimit(__PMF_TIMESTAMP__), CACHE_WRITEBACK_GRANULE) FIXED EMPTY 0 { /* * placeholder to make __PMF_TIMESTAMP_START__ end on a * CACHE_WRITEBACK_GRANULE boundary */ } __PER_CPU_TIMESTAMPS__ +0 FIXED FILL 0 PER_CPU_TIMESTAMP_SIZE { /* padded memory section to store per cpu timestamps */ } #endif /* ENABLE_PMF */ } LR_XLAT_TABLE +0 { xlat_table +0 FIXED { *(xlat_table) } } #if USE_COHERENT_MEM LR_COHERENT_RAM +0 { /* * The base address of the coherent memory section must be page-aligned (4K) * to guarantee that the coherent data are stored on their own pages and * are not mixed with normal data. This is required to set up the correct * memory attributes for the coherent data page tables. */ __COHERENT_RAM__ AlignExpr(+0, PAGE_SIZE) FIXED { /* * Bakery locks are stored in coherent memory * * Each lock's data is contiguous and fully allocated by the compiler */ *(bakery_lock) *(tzfw_coherent_mem) } __COHERENT_RAM_EPILOGUE_UNALIGNED__ +0 FIXED EMPTY 0 { /* section delimiter */ } /* * Memory page(s) mapped to this section will be marked * as device memory. No other unexpected data must creep in. * Ensure the rest of the current memory page is unused. */ __COHERENT_RAM_EPILOGUE__ AlignExpr(ImageLimit(__COHERENT_RAM_START__), PAGE_SIZE) FIXED EMPTY 0 { /* section delimiter */ } } #endif LR_END +0 { __BL31_END__ +0 FIXED EMPTY 0 { /* placeholder */ } /* BL31 image has exceeded its limit. */ ScatterAssert(ImageLimit(__BL31_END__) <= BL31_LIMIT) } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/000077500000000000000000000000001355360272700212115ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t132/000077500000000000000000000000001355360272700217025ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t132/plat_psci_handlers.c000066400000000000000000000073771355360272700257220ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Register used to clear CPU reset signals. Each CPU has two reset * signals: CPU reset (3:0) and Core reset (19:16) */ #define CPU_CMPLX_RESET_CLR 0x344 #define CPU_CORE_RESET_MASK 0x10001 /* Clock and Reset controller registers for system clock's settings */ #define SCLK_RATE 0x30 #define SCLK_BURST_POLICY 0x28 #define SCLK_BURST_POLICY_DEFAULT 0x10000000 static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER]; int32_t tegra_soc_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { int state_id = psci_get_pstate_id(power_state); int cpu = read_mpidr() & MPIDR_CPU_MASK; /* * Sanity check the requested state id, power level and CPU number. * Currently T132 only supports SYSTEM_SUSPEND on last standing CPU * i.e. CPU 0 */ if ((state_id != PSTATE_ID_SOC_POWERDN) || (cpu != 0)) { ERROR("unsupported state id @ power level\n"); return PSCI_E_INVALID_PARAMS; } /* Set lower power states to PLAT_MAX_OFF_STATE */ for (uint32_t i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; /* Set the SYSTEM_SUSPEND state-id */ req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSTATE_ID_SOC_POWERDN; return PSCI_E_SUCCESS; } int tegra_soc_pwr_domain_on(u_register_t mpidr) { int cpu = mpidr & MPIDR_CPU_MASK; uint32_t mask = CPU_CORE_RESET_MASK << cpu; if (cpu_powergate_mask[cpu] == 0) { /* Deassert CPU reset signals */ mmio_write_32(TEGRA_CAR_RESET_BASE + CPU_CMPLX_RESET_CLR, mask); /* Power on CPU using PMC */ tegra_pmc_cpu_on(cpu); /* Fill in the CPU powergate mask */ cpu_powergate_mask[cpu] = 1; } else { /* Power on CPU using Flow Controller */ tegra_fc_cpu_on(cpu); } return PSCI_E_SUCCESS; } int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) { /* * Lock scratch registers which hold the CPU vectors */ tegra_pmc_lock_cpu_vectors(); return PSCI_E_SUCCESS; } int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) { uint64_t val; tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK); /* Disable DCO operations */ denver_disable_dco(); /* Power down the CPU */ val = read_actlr_el1() & ~ACTLR_EL1_PMSTATE_MASK; write_actlr_el1(val | DENVER_CPU_STATE_POWER_DOWN); return PSCI_E_SUCCESS; } int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) { uint64_t val; #if ENABLE_ASSERTIONS int cpu = read_mpidr() & MPIDR_CPU_MASK; /* SYSTEM_SUSPEND only on CPU0 */ assert(cpu == 0); #endif /* Allow restarting CPU #1 using PMC on suspend exit */ cpu_powergate_mask[1] = 0; /* Program FC to enter suspend state */ tegra_fc_cpu_powerdn(read_mpidr()); /* Disable DCO operations */ denver_disable_dco(); /* Program the suspend state ID */ val = read_actlr_el1() & ~ACTLR_EL1_PMSTATE_MASK; write_actlr_el1(val | target_state->pwr_domain_state[PLAT_MAX_PWR_LVL]); return PSCI_E_SUCCESS; } int tegra_soc_prepare_system_reset(void) { /* * Set System Clock (SCLK) to POR default so that the clock source * for the PMC APB clock would not be changed due to system reset. */ mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_BURST_POLICY, SCLK_BURST_POLICY_DEFAULT); mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_RATE, 0); /* Wait 1 ms to make sure clock source/device logic is stabilized. */ mdelay(1); return PSCI_E_SUCCESS; } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t132/plat_secondary.c000066400000000000000000000041711355360272700250600ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #define SB_CSR 0x0 #define SB_CSR_NS_RST_VEC_WR_DIS (1 << 1) /* AARCH64 CPU reset vector */ #define SB_AA64_RESET_LOW 0x30 /* width = 31:0 */ #define SB_AA64_RESET_HI 0x34 /* width = 11:0 */ /* AARCH32 CPU reset vector */ #define EVP_CPU_RESET_VECTOR 0x100 extern void tegra_secure_entrypoint(void); /* * For T132, CPUs reset to AARCH32, so the reset vector is first * armv8_trampoline which does a warm reset to AARCH64 and starts * execution at the address in SB_AA64_RESET_LOW/SB_AA64_RESET_HI. */ __aligned(8) const uint32_t armv8_trampoline[] = { 0xE3A00003, /* mov r0, #3 */ 0xEE0C0F50, /* mcr p15, 0, r0, c12, c0, 2 */ 0xEAFFFFFE, /* b . */ }; /******************************************************************************* * Setup secondary CPU vectors ******************************************************************************/ void plat_secondary_setup(void) { uint32_t val; uint64_t reset_addr = (uint64_t)tegra_secure_entrypoint; /* * For T132, CPUs reset to AARCH32, so the reset vector is first * armv8_trampoline, which does a warm reset to AARCH64 and starts * execution at the address in SCRATCH34/SCRATCH35. */ INFO("Setting up T132 CPU boot\n"); /* initial AARCH32 reset address */ tegra_pmc_write_32(PMC_SECURE_SCRATCH22, (unsigned long)&armv8_trampoline); /* set AARCH32 exception vector (read to flush) */ mmio_write_32(TEGRA_EVP_BASE + EVP_CPU_RESET_VECTOR, (unsigned long)&armv8_trampoline); val = mmio_read_32(TEGRA_EVP_BASE + EVP_CPU_RESET_VECTOR); /* setup secondary CPU vector */ mmio_write_32(TEGRA_SB_BASE + SB_AA64_RESET_LOW, (reset_addr & 0xFFFFFFFF) | 1); val = reset_addr >> 32; mmio_write_32(TEGRA_SB_BASE + SB_AA64_RESET_HI, val & 0x7FF); /* configure PMC */ tegra_pmc_cpu_setup(reset_addr); tegra_pmc_lock_cpu_vectors(); } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t132/plat_setup.c000066400000000000000000000065571355360272700242430ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /* sets of MMIO ranges setup */ #define MMIO_RANGE_0_ADDR 0x50000000 #define MMIO_RANGE_1_ADDR 0x60000000 #define MMIO_RANGE_2_ADDR 0x70000000 #define MMIO_RANGE_SIZE 0x200000 /* * Table of regions to map using the MMU. */ static const mmap_region_t tegra_mmap[] = { MAP_REGION_FLAT(MMIO_RANGE_0_ADDR, MMIO_RANGE_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(MMIO_RANGE_1_ADDR, MMIO_RANGE_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(MMIO_RANGE_2_ADDR, MMIO_RANGE_SIZE, MT_DEVICE | MT_RW | MT_SECURE), {0} }; /******************************************************************************* * Set up the pagetables as per the platform memory map & initialize the MMU ******************************************************************************/ const mmap_region_t *plat_get_mmio_map(void) { /* MMIO space */ return tegra_mmap; } /******************************************************************************* * The Tegra power domain tree has a single system level power domain i.e. a * single root node. The first entry in the power domain descriptor specifies * the number of power domains at the highest power level. ******************************************************************************* */ const unsigned char tegra_power_domain_tree_desc[] = { /* No of root nodes */ 1, /* No of clusters */ PLATFORM_CLUSTER_COUNT, /* No of CPU cores */ PLATFORM_CORE_COUNT, }; /******************************************************************************* * This function returns the Tegra default topology tree information. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { return tegra_power_domain_tree_desc; } unsigned int plat_get_syscnt_freq2(void) { return 12000000; } /******************************************************************************* * Maximum supported UART controllers ******************************************************************************/ #define TEGRA132_MAX_UART_PORTS 5 /******************************************************************************* * This variable holds the UART port base addresses ******************************************************************************/ static uint32_t tegra132_uart_addresses[TEGRA132_MAX_UART_PORTS + 1] = { 0, /* undefined - treated as an error case */ TEGRA_UARTA_BASE, TEGRA_UARTB_BASE, TEGRA_UARTC_BASE, TEGRA_UARTD_BASE, TEGRA_UARTE_BASE, }; /******************************************************************************* * Retrieve the UART controller base to be used as the console ******************************************************************************/ uint32_t plat_get_console_from_id(int id) { if (id > TEGRA132_MAX_UART_PORTS) return 0; return tegra132_uart_addresses[id]; } /******************************************************************************* * Initialize the GIC and SGIs ******************************************************************************/ void plat_gic_setup(void) { tegra_gic_setup(NULL, 0); tegra_gic_init(); } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t132/plat_sip_calls.c000066400000000000000000000040551355360272700250430ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #define NS_SWITCH_AARCH32 1 #define SCR_RW_BITPOS __builtin_ctz(SCR_RW_BIT) /******************************************************************************* * Tegra132 SiP SMCs ******************************************************************************/ #define TEGRA_SIP_AARCH_SWITCH 0x82000004 /******************************************************************************* * SPSR settings for AARCH32/AARCH64 modes ******************************************************************************/ #define SPSR32 SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE, \ DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT) #define SPSR64 SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS) /******************************************************************************* * This function is responsible for handling all T132 SiP calls ******************************************************************************/ int plat_sip_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, const void *cookie, void *handle, uint64_t flags) { switch (smc_fid) { case TEGRA_SIP_AARCH_SWITCH: /* clean up the high bits */ x1 = (uint32_t)x1; x2 = (uint32_t)x2; if (!x1 || x2 > NS_SWITCH_AARCH32) { ERROR("%s: invalid parameters\n", __func__); return -EINVAL; } /* x1 = ns entry point */ cm_set_elr_spsr_el3(NON_SECURE, x1, (x2 == NS_SWITCH_AARCH32) ? SPSR32 : SPSR64); /* switch NS world mode */ cm_write_scr_el3_bit(NON_SECURE, SCR_RW_BITPOS, !x2); INFO("CPU switched to AARCH%s mode\n", (x2 == NS_SWITCH_AARCH32) ? "32" : "64"); return 0; default: ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); break; } return -ENOTSUP; } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t132/platform_t132.mk000066400000000000000000000014751355360272700246370ustar00rootroot00000000000000# # Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # TZDRAM_BASE := 0xF5C00000 $(eval $(call add_define,TZDRAM_BASE)) PLATFORM_CLUSTER_COUNT := 1 $(eval $(call add_define,PLATFORM_CLUSTER_COUNT)) PLATFORM_MAX_CPUS_PER_CLUSTER := 2 $(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER)) MAX_XLAT_TABLES := 3 $(eval $(call add_define,MAX_XLAT_TABLES)) MAX_MMAP_REGIONS := 8 $(eval $(call add_define,MAX_MMAP_REGIONS)) BL31_SOURCES += drivers/ti/uart/aarch64/16550_console.S \ lib/cpus/aarch64/denver.S \ ${COMMON_DIR}/drivers/flowctrl/flowctrl.c \ ${COMMON_DIR}/drivers/memctrl/memctrl_v1.c \ ${SOC_DIR}/plat_psci_handlers.c \ ${SOC_DIR}/plat_sip_calls.c \ ${SOC_DIR}/plat_setup.c \ ${SOC_DIR}/plat_secondary.c trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/000077500000000000000000000000001355360272700217135ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/drivers/000077500000000000000000000000001355360272700233715ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/drivers/include/000077500000000000000000000000001355360272700250145ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/drivers/include/mce_private.h000066400000000000000000000252001355360272700274620ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MCE_PRIVATE_H #define MCE_PRIVATE_H #include #include /******************************************************************************* * Macros to prepare CSTATE info request ******************************************************************************/ /* Description of the parameters for UPDATE_CSTATE_INFO request */ #define CLUSTER_CSTATE_MASK ULL(0x7) #define CLUSTER_CSTATE_SHIFT U(0) #define CLUSTER_CSTATE_UPDATE_BIT (ULL(1) << 7) #define CCPLEX_CSTATE_MASK ULL(0x3) #define CCPLEX_CSTATE_SHIFT ULL(8) #define CCPLEX_CSTATE_UPDATE_BIT (ULL(1) << 15) #define SYSTEM_CSTATE_MASK ULL(0xF) #define SYSTEM_CSTATE_SHIFT ULL(16) #define SYSTEM_CSTATE_FORCE_UPDATE_SHIFT ULL(22) #define SYSTEM_CSTATE_FORCE_UPDATE_BIT (ULL(1) << 22) #define SYSTEM_CSTATE_UPDATE_BIT (ULL(1) << 23) #define CSTATE_WAKE_MASK_UPDATE_BIT (ULL(1) << 31) #define CSTATE_WAKE_MASK_SHIFT ULL(32) #define CSTATE_WAKE_MASK_CLEAR U(0xFFFFFFFF) /******************************************************************************* * Auto-CC3 control macros ******************************************************************************/ #define MCE_AUTO_CC3_FREQ_MASK U(0x1FF) #define MCE_AUTO_CC3_FREQ_SHIFT U(0) #define MCE_AUTO_CC3_VTG_MASK U(0x7F) #define MCE_AUTO_CC3_VTG_SHIFT U(16) #define MCE_AUTO_CC3_ENABLE_BIT (U(1) << 31) /******************************************************************************* * Macros for the 'IS_SC7_ALLOWED' command ******************************************************************************/ #define MCE_SC7_ALLOWED_MASK U(0x7) #define MCE_SC7_WAKE_TIME_SHIFT U(32) /******************************************************************************* * Macros for 'read/write ctats' commands ******************************************************************************/ #define MCE_CSTATE_STATS_TYPE_SHIFT ULL(32) #define MCE_CSTATE_WRITE_DATA_LO_MASK U(0xF) /******************************************************************************* * Macros for 'update crossover threshold' command ******************************************************************************/ #define MCE_CROSSOVER_THRESHOLD_TIME_SHIFT U(32) /******************************************************************************* * MCA argument macros ******************************************************************************/ #define MCA_ARG_ERROR_MASK U(0xFF) #define MCA_ARG_FINISH_SHIFT U(24) #define MCA_ARG_FINISH_MASK U(0xFF) /******************************************************************************* * Uncore PERFMON ARI macros ******************************************************************************/ #define UNCORE_PERFMON_CMD_READ U(0) #define UNCORE_PERFMON_CMD_WRITE U(1) #define UNCORE_PERFMON_CMD_MASK U(0xFF) #define UNCORE_PERFMON_UNIT_GRP_MASK U(0xF) #define UNCORE_PERFMON_SELECTOR_MASK U(0xF) #define UNCORE_PERFMON_REG_MASK U(0xFF) #define UNCORE_PERFMON_CTR_MASK U(0xFF) #define UNCORE_PERFMON_RESP_STATUS_MASK U(0xFF) /******************************************************************************* * Structure populated by arch specific code to export routines which perform * common low level MCE functions ******************************************************************************/ typedef struct arch_mce_ops { /* * This ARI request sets up the MCE to start execution on assertion * of STANDBYWFI, update the core power state and expected wake time, * then determine the proper power state to enter. */ int32_t (*enter_cstate)(uint32_t ari_base, uint32_t state, uint32_t wake_time); /* * This ARI request allows updating of the CLUSTER_CSTATE, * CCPLEX_CSTATE, and SYSTEM_CSTATE register values. */ int32_t (*update_cstate_info)(uint32_t ari_base, uint32_t cluster, uint32_t ccplex, uint32_t system, uint8_t sys_state_force, uint32_t wake_mask, uint8_t update_wake_mask); /* * This ARI request allows updating of power state crossover * threshold times. An index value specifies which crossover * state is being updated. */ int32_t (*update_crossover_time)(uint32_t ari_base, uint32_t type, uint32_t time); /* * This ARI request allows read access to statistical information * related to power states. */ uint64_t (*read_cstate_stats)(uint32_t ari_base, uint32_t state); /* * This ARI request allows write access to statistical information * related to power states. */ int32_t (*write_cstate_stats)(uint32_t ari_base, uint32_t state, uint32_t stats); /* * This ARI request allows the CPU to understand the features * supported by the MCE firmware. */ uint64_t (*call_enum_misc)(uint32_t ari_base, uint32_t cmd, uint32_t data); /* * This ARI request allows querying the CCPLEX to determine if * the CCx state is allowed given a target core C-state and wake * time. If the CCx state is allowed, the response indicates CCx * must be entered. If the CCx state is not allowed, the response * indicates CC6/CC7 can't be entered */ int32_t (*is_ccx_allowed)(uint32_t ari_base, uint32_t state, uint32_t wake_time); /* * This ARI request allows querying the CCPLEX to determine if * the SC7 state is allowed given a target core C-state and wake * time. If the SC7 state is allowed, all cores but the associated * core are offlined (WAKE_EVENTS are set to 0) and the response * indicates SC7 must be entered. If the SC7 state is not allowed, * the response indicates SC7 can't be entered */ int32_t (*is_sc7_allowed)(uint32_t ari_base, uint32_t state, uint32_t wake_time); /* * This ARI request allows a core to bring another offlined core * back online to the C0 state. Note that a core is offlined by * entering a C-state where the WAKE_MASK is all 0. */ int32_t (*online_core)(uint32_t ari_base, uint32_t cpuid); /* * This ARI request allows the CPU to enable/disable Auto-CC3 idle * state. */ int32_t (*cc3_ctrl)(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable); /* * This ARI request allows updating the reset vector register for * D15 and A57 CPUs. */ int32_t (*update_reset_vector)(uint32_t ari_base); /* * This ARI request instructs the ROC to flush A57 data caches in * order to maintain coherency with the Denver cluster. */ int32_t (*roc_flush_cache)(uint32_t ari_base); /* * This ARI request instructs the ROC to flush A57 data caches along * with the caches covering ARM code in order to maintain coherency * with the Denver cluster. */ int32_t (*roc_flush_cache_trbits)(uint32_t ari_base); /* * This ARI request instructs the ROC to clean A57 data caches along * with the caches covering ARM code in order to maintain coherency * with the Denver cluster. */ int32_t (*roc_clean_cache)(uint32_t ari_base); /* * This ARI request reads/writes the Machine Check Arch. (MCA) * registers. */ uint64_t (*read_write_mca)(uint32_t ari_base, uint64_t cmd, uint64_t *data); /* * Some MC GSC (General Security Carveout) register values are * expected to be changed by TrustZone secure ARM code after boot. * Since there is no hardware mechanism for the CCPLEX to know * that an MC GSC register has changed to allow it to update its * own internal GSC register, there needs to be a mechanism that * can be used by ARM code to cause the CCPLEX to update its GSC * register value. This ARI request allows updating the GSC register * value for a certain carveout in the CCPLEX. */ int32_t (*update_ccplex_gsc)(uint32_t ari_base, uint32_t gsc_idx); /* * This ARI request instructs the CCPLEX to either shutdown or * reset the entire system */ void (*enter_ccplex_state)(uint32_t ari_base, uint32_t state_idx); /* * This ARI request reads/writes data from/to Uncore PERFMON * registers */ int32_t (*read_write_uncore_perfmon)(uint32_t ari_base, uint64_t req, uint64_t *data); /* * This ARI implements ARI_MISC_CCPLEX commands. This can be * used to enable/disable coresight clock gating. */ void (*misc_ccplex)(uint32_t ari_base, uint32_t index, uint32_t value); } arch_mce_ops_t; /* declarations for ARI/NVG handler functions */ int32_t ari_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time); int32_t ari_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex, uint32_t system, uint8_t sys_state_force, uint32_t wake_mask, uint8_t update_wake_mask); int32_t ari_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time); uint64_t ari_read_cstate_stats(uint32_t ari_base, uint32_t state); int32_t ari_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats); uint64_t ari_enumeration_misc(uint32_t ari_base, uint32_t cmd, uint32_t data); int32_t ari_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time); int32_t ari_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time); int32_t ari_online_core(uint32_t ari_base, uint32_t core); int32_t ari_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable); int32_t ari_reset_vector_update(uint32_t ari_base); int32_t ari_roc_flush_cache_trbits(uint32_t ari_base); int32_t ari_roc_flush_cache(uint32_t ari_base); int32_t ari_roc_clean_cache(uint32_t ari_base); uint64_t ari_read_write_mca(uint32_t ari_base, uint64_t cmd, uint64_t *data); int32_t ari_update_ccplex_gsc(uint32_t ari_base, uint32_t gsc_idx); void ari_enter_ccplex_state(uint32_t ari_base, uint32_t state_idx); int32_t ari_read_write_uncore_perfmon(uint32_t ari_base, uint64_t req, uint64_t *data); void ari_misc_ccplex(uint32_t ari_base, uint32_t index, uint32_t value); int32_t nvg_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time); int32_t nvg_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex, uint32_t system, uint8_t sys_state_force, uint32_t wake_mask, uint8_t update_wake_mask); int32_t nvg_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time); uint64_t nvg_read_cstate_stats(uint32_t ari_base, uint32_t state); int32_t nvg_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats); int32_t nvg_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time); int32_t nvg_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time); int32_t nvg_online_core(uint32_t ari_base, uint32_t core); int32_t nvg_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable); extern void nvg_set_request_data(uint64_t req, uint64_t data); extern void nvg_set_request(uint64_t req); extern uint64_t nvg_get_result(void); #endif /* MCE_PRIVATE_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/drivers/include/t18x_ari.h000066400000000000000000000467401355360272700266370ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef T18X_ARI_H #define T18X_ARI_H /* * ---------------------------------------------------------------------------- * t18x_ari.h * * Global ARI definitions. * ---------------------------------------------------------------------------- */ enum { TEGRA_ARI_VERSION_MAJOR = 3U, TEGRA_ARI_VERSION_MINOR = 1U, }; typedef enum { /* indexes below get the core lock */ TEGRA_ARI_MISC = 0U, /* index 1 is deprecated */ /* index 2 is deprecated */ /* index 3 is deprecated */ TEGRA_ARI_ONLINE_CORE = 4U, /* indexes below need cluster lock */ TEGRA_ARI_MISC_CLUSTER = 41U, TEGRA_ARI_IS_CCX_ALLOWED = 42U, TEGRA_ARI_CC3_CTRL = 43U, /* indexes below need ccplex lock */ TEGRA_ARI_ENTER_CSTATE = 80U, TEGRA_ARI_UPDATE_CSTATE_INFO = 81U, TEGRA_ARI_IS_SC7_ALLOWED = 82U, /* index 83 is deprecated */ TEGRA_ARI_PERFMON = 84U, TEGRA_ARI_UPDATE_CCPLEX_GSC = 85U, /* index 86 is depracated */ /* index 87 is deprecated */ TEGRA_ARI_ROC_FLUSH_CACHE_ONLY = 88U, TEGRA_ARI_ROC_FLUSH_CACHE_TRBITS = 89U, TEGRA_ARI_MISC_CCPLEX = 90U, TEGRA_ARI_MCA = 91U, TEGRA_ARI_UPDATE_CROSSOVER = 92U, TEGRA_ARI_CSTATE_STATS = 93U, TEGRA_ARI_WRITE_CSTATE_STATS = 94U, TEGRA_ARI_COPY_MISCREG_AA64_RST = 95U, TEGRA_ARI_ROC_CLEAN_CACHE_ONLY = 96U, } tegra_ari_req_id_t; typedef enum { TEGRA_ARI_MISC_ECHO = 0U, TEGRA_ARI_MISC_VERSION = 1U, TEGRA_ARI_MISC_FEATURE_LEAF_0 = 2U, } tegra_ari_misc_index_t; typedef enum { TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF = 0U, TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT = 1U, TEGRA_ARI_MISC_CCPLEX_CORESIGHT_CG_CTRL = 2U, TEGRA_ARI_MISC_CCPLEX_EDBGREQ = 3U, } tegra_ari_misc_ccplex_index_t; typedef enum { TEGRA_ARI_CORE_C0 = 0U, TEGRA_ARI_CORE_C1 = 1U, TEGRA_ARI_CORE_C6 = 6U, TEGRA_ARI_CORE_C7 = 7U, TEGRA_ARI_CORE_WARMRSTREQ = 8U, } tegra_ari_core_sleep_state_t; typedef enum { TEGRA_ARI_CLUSTER_CC0 = 0U, TEGRA_ARI_CLUSTER_CC1 = 1U, TEGRA_ARI_CLUSTER_CC6 = 6U, TEGRA_ARI_CLUSTER_CC7 = 7U, } tegra_ari_cluster_sleep_state_t; typedef enum { TEGRA_ARI_CCPLEX_CCP0 = 0U, TEGRA_ARI_CCPLEX_CCP1 = 1U, TEGRA_ARI_CCPLEX_CCP3 = 3U, /* obsoleted */ } tegra_ari_ccplex_sleep_state_t; typedef enum { TEGRA_ARI_SYSTEM_SC0 = 0U, TEGRA_ARI_SYSTEM_SC1 = 1U, /* obsoleted */ TEGRA_ARI_SYSTEM_SC2 = 2U, /* obsoleted */ TEGRA_ARI_SYSTEM_SC3 = 3U, /* obsoleted */ TEGRA_ARI_SYSTEM_SC4 = 4U, /* obsoleted */ TEGRA_ARI_SYSTEM_SC7 = 7U, TEGRA_ARI_SYSTEM_SC8 = 8U, } tegra_ari_system_sleep_state_t; typedef enum { TEGRA_ARI_CROSSOVER_C1_C6 = 0U, TEGRA_ARI_CROSSOVER_CC1_CC6 = 1U, TEGRA_ARI_CROSSOVER_CC1_CC7 = 2U, TEGRA_ARI_CROSSOVER_CCP1_CCP3 = 3U, /* obsoleted */ TEGRA_ARI_CROSSOVER_CCP3_SC2 = 4U, /* obsoleted */ TEGRA_ARI_CROSSOVER_CCP3_SC3 = 5U, /* obsoleted */ TEGRA_ARI_CROSSOVER_CCP3_SC4 = 6U, /* obsoleted */ TEGRA_ARI_CROSSOVER_CCP3_SC7 = 7U, /* obsoleted */ TEGRA_ARI_CROSSOVER_SC0_SC7 = 7U, TEGRA_ARI_CROSSOVER_CCP3_SC1 = 8U, /* obsoleted */ } tegra_ari_crossover_index_t; typedef enum { TEGRA_ARI_CSTATE_STATS_CLEAR = 0U, TEGRA_ARI_CSTATE_STATS_SC7_ENTRIES = 1U, TEGRA_ARI_CSTATE_STATS_SC4_ENTRIES, /* obsoleted */ TEGRA_ARI_CSTATE_STATS_SC3_ENTRIES, /* obsoleted */ TEGRA_ARI_CSTATE_STATS_SC2_ENTRIES, /* obsoleted */ TEGRA_ARI_CSTATE_STATS_CCP3_ENTRIES, /* obsoleted */ TEGRA_ARI_CSTATE_STATS_A57_CC6_ENTRIES, TEGRA_ARI_CSTATE_STATS_A57_CC7_ENTRIES, TEGRA_ARI_CSTATE_STATS_D15_CC6_ENTRIES, TEGRA_ARI_CSTATE_STATS_D15_CC7_ENTRIES, TEGRA_ARI_CSTATE_STATS_D15_0_C6_ENTRIES, TEGRA_ARI_CSTATE_STATS_D15_1_C6_ENTRIES, TEGRA_ARI_CSTATE_STATS_D15_0_C7_ENTRIES = 14U, TEGRA_ARI_CSTATE_STATS_D15_1_C7_ENTRIES, TEGRA_ARI_CSTATE_STATS_A57_0_C7_ENTRIES = 18U, TEGRA_ARI_CSTATE_STATS_A57_1_C7_ENTRIES, TEGRA_ARI_CSTATE_STATS_A57_2_C7_ENTRIES, TEGRA_ARI_CSTATE_STATS_A57_3_C7_ENTRIES, TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_0, TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_1, TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_0 = 26U, TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_1, TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_2, TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_3, } tegra_ari_cstate_stats_index_t; typedef enum { TEGRA_ARI_GSC_ALL = 0U, TEGRA_ARI_GSC_BPMP = 6U, TEGRA_ARI_GSC_APE = 7U, TEGRA_ARI_GSC_SPE = 8U, TEGRA_ARI_GSC_SCE = 9U, TEGRA_ARI_GSC_APR = 10U, TEGRA_ARI_GSC_TZRAM = 11U, TEGRA_ARI_GSC_SE = 12U, TEGRA_ARI_GSC_BPMP_TO_SPE = 16U, TEGRA_ARI_GSC_SPE_TO_BPMP = 17U, TEGRA_ARI_GSC_CPU_TZ_TO_BPMP = 18U, TEGRA_ARI_GSC_BPMP_TO_CPU_TZ = 19U, TEGRA_ARI_GSC_CPU_NS_TO_BPMP = 20U, TEGRA_ARI_GSC_BPMP_TO_CPU_NS = 21U, TEGRA_ARI_GSC_IPC_SE_SPE_SCE_BPMP = 22U, TEGRA_ARI_GSC_SC7_RESUME_FW = 23U, TEGRA_ARI_GSC_TZ_DRAM_IDX = 34U, TEGRA_ARI_GSC_VPR_IDX = 35U, } tegra_ari_gsc_index_t; /* This macro will produce enums for __name##_LSB, __name##_MSB and __name##_MSK */ #define TEGRA_ARI_ENUM_MASK_LSB_MSB(__name, __lsb, __msb) __name##_LSB = __lsb, __name##_MSB = __msb typedef enum { TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CLUSTER_CSTATE, 0U, 2U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CLUSTER_CSTATE_PRESENT, 7U, 7U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CCPLEX_CSTATE, 8U, 9U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CCPLEX_CSTATE_PRESENT, 15U, 15U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__SYSTEM_CSTATE, 16U, 19U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__IGNORE_CROSSOVERS, 22U, 22U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__SYSTEM_CSTATE_PRESENT, 23U, 23U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__WAKE_MASK_PRESENT, 31U, 31U), } tegra_ari_update_cstate_info_bitmasks_t; typedef enum { TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MISC_CCPLEX_CORESIGHT_CG_CTRL__EN, 0U, 0U), } tegra_ari_misc_ccplex_bitmasks_t; typedef enum { TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_CC3_CTRL__IDLE_FREQ, 0U, 8U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_CC3_CTRL__IDLE_VOLT, 16U, 23U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_CC3_CTRL__ENABLE, 31U, 31U), } tegra_ari_cc3_ctrl_bitmasks_t; typedef enum { TEGRA_ARI_MCA_NOP = 0U, TEGRA_ARI_MCA_READ_SERR = 1U, TEGRA_ARI_MCA_WRITE_SERR = 2U, TEGRA_ARI_MCA_CLEAR_SERR = 4U, TEGRA_ARI_MCA_REPORT_SERR = 5U, TEGRA_ARI_MCA_READ_INTSTS = 6U, TEGRA_ARI_MCA_WRITE_INTSTS = 7U, TEGRA_ARI_MCA_READ_PREBOOT_SERR = 8U, } tegra_ari_mca_commands_t; typedef enum { TEGRA_ARI_MCA_RD_WR_DPMU = 0U, TEGRA_ARI_MCA_RD_WR_IOB = 1U, TEGRA_ARI_MCA_RD_WR_MCB = 2U, TEGRA_ARI_MCA_RD_WR_CCE = 3U, TEGRA_ARI_MCA_RD_WR_CQX = 4U, TEGRA_ARI_MCA_RD_WR_CTU = 5U, TEGRA_ARI_MCA_RD_WR_JSR_MTS = 7U, TEGRA_ARI_MCA_RD_BANK_INFO = 0x0fU, TEGRA_ARI_MCA_RD_BANK_TEMPLATE = 0x10U, TEGRA_ARI_MCA_RD_WR_SECURE_ACCESS_REGISTER = 0x11U, TEGRA_ARI_MCA_RD_WR_GLOBAL_CONFIG_REGISTER = 0x12U, } tegra_ari_mca_rd_wr_indexes_t; typedef enum { TEGRA_ARI_MCA_RD_WR_ASERRX_CTRL = 0U, TEGRA_ARI_MCA_RD_WR_ASERRX_STATUS = 1U, TEGRA_ARI_MCA_RD_WR_ASERRX_ADDR = 2U, TEGRA_ARI_MCA_RD_WR_ASERRX_MISC1 = 3U, TEGRA_ARI_MCA_RD_WR_ASERRX_MISC2 = 4U, } tegra_ari_mca_read_asserx_subindexes_t; typedef enum { TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_SETTING_ENABLES_NS_PERMITTED, 0U, 0U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_READING_STATUS_NS_PERMITTED, 1U, 1U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_PENDING_MCA_ERRORS_NS_PERMITTED, 2U, 2U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_CLEARING_MCA_INTERRUPTS_NS_PERMITTED, 3U, 3U), } tegra_ari_mca_secure_register_bitmasks_t; typedef enum { TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_SERR_ERR_CODE, 0U, 15U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_PWM_ERR, 16U, 16U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_CRAB_ERR, 17U, 17U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_RD_WR_N, 18U, 18U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_UCODE_ERR, 19U, 19U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_PWM, 20U, 23U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_AV, 58U, 58U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_MV, 59U, 59U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_EN, 60U, 60U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_UC, 61U, 61U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_OVF, 62U, 62U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_VAL, 63U, 63U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_ADDR_ADDR, 0U, 41U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_ADDR_UCODE_ERRCD, 42U, 52U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_CTRL_EN_PWM_ERR, 0U, 0U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_CTRL_EN_CRAB_ERR, 1U, 1U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_CTRL_EN_UCODE_ERR, 3U, 3U), } tegra_ari_mca_aserr0_bitmasks_t; typedef enum { TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_SERR_ERR_CODE, 0U, 15U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_MSI_ERR, 16U, 16U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_IHI_ERR, 17U, 17U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CRI_ERR, 18U, 18U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_MMCRAB_ERR, 19U, 19U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CSI_ERR, 20U, 20U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_RD_WR_N, 21U, 21U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_REQ_ERRT, 22U, 23U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_RESP_ERRT, 24U, 25U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_AV, 58U, 58U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_MV, 59U, 59U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_EN, 60U, 60U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_UC, 61U, 61U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_OVF, 62U, 62U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_VAL, 63U, 63U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_AXI_ID, 0U, 7U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CQX_ID, 8U, 27U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CQX_CID, 28U, 31U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CQX_CMD, 32U, 35U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_MSI_ERR, 0U, 0U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_IHI_ERR, 1U, 1U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_CRI_ERR, 2U, 2U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_MMCRAB_ERR, 3U, 3U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_CSI_ERR, 4U, 4U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_MISC_ADDR, 0U, 41U), } tegra_ari_mca_aserr1_bitmasks_t; typedef enum { TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_SERR_ERR_CODE, 0U, 15U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_MC_ERR, 16U, 16U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_SYSRAM_ERR, 17U, 17U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_CLIENT_ID, 18U, 19U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_AV, 58U, 58U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_MV, 59U, 59U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_EN, 60U, 60U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_UC, 61U, 61U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_OVF, 62U, 62U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_VAL, 63U, 63U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_ADDR_ID, 0U, 17U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_ADDR_CMD, 18U, 21U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_ADDR_ADDR, 22U, 53U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_CTRL_EN_MC_ERR, 0U, 0U), } tegra_ari_mca_aserr2_bitmasks_t; typedef enum { TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_SERR_ERR_CODE, 0U, 15U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_TO_ERR, 16U, 16U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_STAT_ERR, 17U, 17U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_DST_ERR, 18U, 18U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_UNC_ERR, 19U, 19U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_MH_ERR, 20U, 20U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_PERR, 21U, 21U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_PSN_ERR, 22U, 22U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_AV, 58U, 58U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_MV, 59U, 59U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_EN, 60U, 60U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_UC, 61U, 61U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_OVF, 62U, 62U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_VAL, 63U, 63U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_ADDR_CMD, 0U, 5U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_ADDR_ADDR, 6U, 47U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_TO, 0U, 0U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_DIV4, 1U, 1U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_TLIMIT, 2U, 11U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_PSN_ERR_CORR_MSK, 12U, 25U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_MORE_INFO, 0U, 17U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_TO_INFO, 18U, 43U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_SRC, 44U, 45U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_TID, 46U, 52U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_TO_ERR, 0U, 0U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_STAT_ERR, 1U, 1U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_DST_ERR, 2U, 2U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_UNC_ERR, 3U, 3U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_MH_ERR, 4U, 4U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_PERR, 5U, 5U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_PSN_ERR, 6U, 19U), } tegra_ari_mca_aserr3_bitmasks_t; typedef enum { TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_SERR_ERR_CODE, 0U, 15U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_SRC_ERR, 16U, 16U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_DST_ERR, 17U, 17U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_REQ_ERR, 18U, 18U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_RSP_ERR, 19U, 19U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_AV, 58U, 58U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_MV, 59U, 59U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_EN, 60U, 60U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_UC, 61U, 61U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_OVF, 62U, 62U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_VAL, 63U, 63U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_CTRL_EN_CPE_ERR, 0U, 0U), } tegra_ari_mca_aserr4_bitmasks_t; typedef enum { TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_SERR_ERR_CODE, 0U, 15U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_CTUPAR, 16U, 16U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_MULTI, 17U, 17U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_AV, 58U, 58U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_MV, 59U, 59U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_EN, 60U, 60U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_UC, 61U, 61U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_OVF, 62U, 62U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_VAL, 63U, 63U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_SRC, 0U, 7U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_ID, 8U, 15U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_DATA, 16U, 26U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_CMD, 32U, 35U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_ADDR, 36U, 45U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_CTRL_EN_CTUPAR, 0U, 0U), } tegra_ari_mca_aserr5_bitmasks_t; typedef enum { TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_SERR_ERR_CODE, 0U, 15U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_AV, 58U, 58U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_MV, 59U, 59U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_EN, 60U, 60U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_UC, 61U, 61U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_OVF, 62U, 62U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_VAL, 63U, 63U), TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_ADDR_TBD_INFO, 0U, 63U), } tegra_ari_mca_serr1_bitmasks_t; #undef TEGRA_ARI_ENUM_MASK_LSB_MSB typedef enum { TEGRA_NVG_CHANNEL_PMIC = 0U, TEGRA_NVG_CHANNEL_POWER_PERF = 1U, TEGRA_NVG_CHANNEL_POWER_MODES = 2U, TEGRA_NVG_CHANNEL_WAKE_TIME = 3U, TEGRA_NVG_CHANNEL_CSTATE_INFO = 4U, TEGRA_NVG_CHANNEL_CROSSOVER_C1_C6 = 5U, TEGRA_NVG_CHANNEL_CROSSOVER_CC1_CC6 = 6U, TEGRA_NVG_CHANNEL_CROSSOVER_CC1_CC7 = 7U, TEGRA_NVG_CHANNEL_CROSSOVER_CCP1_CCP3 = 8U, /* obsoleted */ TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC2 = 9U, /* obsoleted */ TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC3 = 10U, /* obsoleted */ TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC4 = 11U, /* obsoleted */ TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC7 = 12U, /* obsoleted */ TEGRA_NVG_CHANNEL_CROSSOVER_SC0_SC7 = 12U, TEGRA_NVG_CHANNEL_CSTATE_STATS_CLEAR = 13U, TEGRA_NVG_CHANNEL_CSTATE_STATS_SC7_ENTRIES = 14U, TEGRA_NVG_CHANNEL_CSTATE_STATS_SC4_ENTRIES = 15U, /* obsoleted */ TEGRA_NVG_CHANNEL_CSTATE_STATS_SC3_ENTRIES = 16U, /* obsoleted */ TEGRA_NVG_CHANNEL_CSTATE_STATS_SC2_ENTRIES = 17U, /* obsoleted */ TEGRA_NVG_CHANNEL_CSTATE_STATS_CCP3_ENTRIES = 18U, /* obsoleted */ TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_CC6_ENTRIES = 19U, TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_CC7_ENTRIES = 20U, TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_CC6_ENTRIES = 21U, TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_CC7_ENTRIES = 22U, TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_0_C6_ENTRIES = 23U, TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_1_C6_ENTRIES = 24U, TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_2_C6_ENTRIES = 25U, /* Reserved (for Denver15 core 2) */ TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_3_C6_ENTRIES = 26U, /* Reserved (for Denver15 core 3) */ TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_0_C7_ENTRIES = 27U, TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_1_C7_ENTRIES = 28U, TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_2_C7_ENTRIES = 29U, /* Reserved (for Denver15 core 2) */ TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_3_C7_ENTRIES = 30U, /* Reserved (for Denver15 core 3) */ TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_0_C7_ENTRIES = 31U, TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_1_C7_ENTRIES = 32U, TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_2_C7_ENTRIES = 33U, TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_3_C7_ENTRIES = 34U, TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_0 = 35U, TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_1 = 36U, TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_2 = 37U, /* Reserved (for Denver15 core 2) */ TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_3 = 38U, /* Reserved (for Denver15 core 3) */ TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_0 = 39U, TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_1 = 40U, TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_2 = 41U, TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_3 = 42U, TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED = 43U, TEGRA_NVG_CHANNEL_ONLINE_CORE = 44U, TEGRA_NVG_CHANNEL_CC3_CTRL = 45U, TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC1 = 46U, /* obsoleted */ TEGRA_NVG_CHANNEL_LAST_INDEX, } tegra_nvg_channel_id_t; #endif /* T18X_ARI_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/drivers/mce/000077500000000000000000000000001355360272700241355ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/000077500000000000000000000000001355360272700253655ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/drivers/mce/aarch64/nvg_helpers.S000066400000000000000000000012011355360272700300170ustar00rootroot00000000000000/* * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .globl nvg_set_request_data .globl nvg_set_request .globl nvg_get_result /* void nvg_set_request_data(uint64_t req, uint64_t data) */ func nvg_set_request_data msr s3_0_c15_c1_2, x0 msr s3_0_c15_c1_3, x1 ret endfunc nvg_set_request_data /* void nvg_set_request(uint64_t req) */ func nvg_set_request msr s3_0_c15_c1_2, x0 ret endfunc nvg_set_request /* uint64_t nvg_get_result(void) */ func nvg_get_result mrs x0, s3_0_c15_c1_3 ret endfunc nvg_get_result trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/drivers/mce/ari.c000066400000000000000000000355151355360272700250650ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * Register offsets for ARI request/results ******************************************************************************/ #define ARI_REQUEST 0x0U #define ARI_REQUEST_EVENT_MASK 0x4U #define ARI_STATUS 0x8U #define ARI_REQUEST_DATA_LO 0xCU #define ARI_REQUEST_DATA_HI 0x10U #define ARI_RESPONSE_DATA_LO 0x14U #define ARI_RESPONSE_DATA_HI 0x18U /* Status values for the current request */ #define ARI_REQ_PENDING 1U #define ARI_REQ_ONGOING 3U #define ARI_REQUEST_VALID_BIT (1U << 8) #define ARI_EVT_MASK_STANDBYWFI_BIT (1U << 7) /* default timeout (us) to wait for ARI completion */ #define ARI_MAX_RETRY_COUNT U(2000000) /******************************************************************************* * ARI helper functions ******************************************************************************/ static inline uint32_t ari_read_32(uint32_t ari_base, uint32_t reg) { return mmio_read_32((uint64_t)ari_base + (uint64_t)reg); } static inline void ari_write_32(uint32_t ari_base, uint32_t val, uint32_t reg) { mmio_write_32((uint64_t)ari_base + (uint64_t)reg, val); } static inline uint32_t ari_get_request_low(uint32_t ari_base) { return ari_read_32(ari_base, ARI_REQUEST_DATA_LO); } static inline uint32_t ari_get_request_high(uint32_t ari_base) { return ari_read_32(ari_base, ARI_REQUEST_DATA_HI); } static inline uint32_t ari_get_response_low(uint32_t ari_base) { return ari_read_32(ari_base, ARI_RESPONSE_DATA_LO); } static inline uint32_t ari_get_response_high(uint32_t ari_base) { return ari_read_32(ari_base, ARI_RESPONSE_DATA_HI); } static inline void ari_clobber_response(uint32_t ari_base) { ari_write_32(ari_base, 0, ARI_RESPONSE_DATA_LO); ari_write_32(ari_base, 0, ARI_RESPONSE_DATA_HI); } static int32_t ari_request_wait(uint32_t ari_base, uint32_t evt_mask, uint32_t req, uint32_t lo, uint32_t hi) { uint32_t retries = (uint32_t)ARI_MAX_RETRY_COUNT; uint32_t status; int32_t ret = 0; /* program the request, event_mask, hi and lo registers */ ari_write_32(ari_base, lo, ARI_REQUEST_DATA_LO); ari_write_32(ari_base, hi, ARI_REQUEST_DATA_HI); ari_write_32(ari_base, evt_mask, ARI_REQUEST_EVENT_MASK); ari_write_32(ari_base, req | ARI_REQUEST_VALID_BIT, ARI_REQUEST); /* * For commands that have an event trigger, we should bypass * ARI_STATUS polling, since MCE is waiting for SW to trigger * the event. */ if (evt_mask != 0U) { ret = 0; } else { /* For shutdown/reboot commands, we dont have to check for timeouts */ if ((req == TEGRA_ARI_MISC_CCPLEX) && ((lo == TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF) || (lo == TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT))) { ret = 0; } else { /* * Wait for the command response for not more than the timeout */ while (retries != 0U) { /* read the command status */ status = ari_read_32(ari_base, ARI_STATUS); if ((status & (ARI_REQ_ONGOING | ARI_REQ_PENDING)) == 0U) { break; } /* delay 1 us */ udelay(1); /* decrement the retry count */ retries--; } /* assert if the command timed out */ if (retries == 0U) { ERROR("ARI request timed out: req %d on CPU %d\n", req, plat_my_core_pos()); assert(retries != 0U); } } } return ret; } int32_t ari_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time) { int32_t ret = 0; /* check for allowed power state */ if ((state != TEGRA_ARI_CORE_C0) && (state != TEGRA_ARI_CORE_C1) && (state != TEGRA_ARI_CORE_C6) && (state != TEGRA_ARI_CORE_C7)) { ERROR("%s: unknown cstate (%d)\n", __func__, state); ret = EINVAL; } else { /* clean the previous response state */ ari_clobber_response(ari_base); /* Enter the cstate, to be woken up after wake_time (TSC ticks) */ ret = ari_request_wait(ari_base, ARI_EVT_MASK_STANDBYWFI_BIT, (uint32_t)TEGRA_ARI_ENTER_CSTATE, state, wake_time); } return ret; } int32_t ari_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex, uint32_t system, uint8_t sys_state_force, uint32_t wake_mask, uint8_t update_wake_mask) { uint64_t val = 0U; /* clean the previous response state */ ari_clobber_response(ari_base); /* update CLUSTER_CSTATE? */ if (cluster != 0U) { val |= (cluster & CLUSTER_CSTATE_MASK) | CLUSTER_CSTATE_UPDATE_BIT; } /* update CCPLEX_CSTATE? */ if (ccplex != 0U) { val |= ((ccplex & CCPLEX_CSTATE_MASK) << CCPLEX_CSTATE_SHIFT) | CCPLEX_CSTATE_UPDATE_BIT; } /* update SYSTEM_CSTATE? */ if (system != 0U) { val |= ((system & SYSTEM_CSTATE_MASK) << SYSTEM_CSTATE_SHIFT) | (((uint64_t)sys_state_force << SYSTEM_CSTATE_FORCE_UPDATE_SHIFT) | SYSTEM_CSTATE_UPDATE_BIT); } /* update wake mask value? */ if (update_wake_mask != 0U) { val |= CSTATE_WAKE_MASK_UPDATE_BIT; } /* set the updated cstate info */ return ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_UPDATE_CSTATE_INFO, (uint32_t)val, wake_mask); } int32_t ari_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time) { int32_t ret = 0; /* sanity check crossover type */ if ((type == TEGRA_ARI_CROSSOVER_C1_C6) || (type > TEGRA_ARI_CROSSOVER_CCP3_SC1)) { ret = EINVAL; } else { /* clean the previous response state */ ari_clobber_response(ari_base); /* update crossover threshold time */ ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_UPDATE_CROSSOVER, type, time); } return ret; } uint64_t ari_read_cstate_stats(uint32_t ari_base, uint32_t state) { int32_t ret; uint64_t result; /* sanity check crossover type */ if (state == 0U) { result = EINVAL; } else { /* clean the previous response state */ ari_clobber_response(ari_base); ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_CSTATE_STATS, state, 0U); if (ret != 0) { result = EINVAL; } else { result = (uint64_t)ari_get_response_low(ari_base); } } return result; } int32_t ari_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats) { /* clean the previous response state */ ari_clobber_response(ari_base); /* write the cstate stats */ return ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_WRITE_CSTATE_STATS, state, stats); } uint64_t ari_enumeration_misc(uint32_t ari_base, uint32_t cmd, uint32_t data) { uint64_t resp; int32_t ret; uint32_t local_data = data; /* clean the previous response state */ ari_clobber_response(ari_base); /* ARI_REQUEST_DATA_HI is reserved for commands other than 'ECHO' */ if (cmd != TEGRA_ARI_MISC_ECHO) { local_data = 0U; } ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_MISC, cmd, local_data); if (ret != 0) { resp = (uint64_t)ret; } else { /* get the command response */ resp = ari_get_response_low(ari_base); resp |= ((uint64_t)ari_get_response_high(ari_base) << 32); } return resp; } int32_t ari_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time) { int32_t ret; uint32_t result; /* clean the previous response state */ ari_clobber_response(ari_base); ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_IS_CCX_ALLOWED, state & 0x7U, wake_time); if (ret != 0) { ERROR("%s: failed (%d)\n", __func__, ret); result = 0U; } else { result = ari_get_response_low(ari_base) & 0x1U; } /* 1 = CCx allowed, 0 = CCx not allowed */ return (int32_t)result; } int32_t ari_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time) { int32_t ret, result; /* check for allowed power state */ if ((state != TEGRA_ARI_CORE_C0) && (state != TEGRA_ARI_CORE_C1) && (state != TEGRA_ARI_CORE_C6) && (state != TEGRA_ARI_CORE_C7)) { ERROR("%s: unknown cstate (%d)\n", __func__, state); result = EINVAL; } else { /* clean the previous response state */ ari_clobber_response(ari_base); ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_IS_SC7_ALLOWED, state, wake_time); if (ret != 0) { ERROR("%s: failed (%d)\n", __func__, ret); result = 0; } else { /* 1 = SC7 allowed, 0 = SC7 not allowed */ result = (ari_get_response_low(ari_base) != 0U) ? 1 : 0; } } return result; } int32_t ari_online_core(uint32_t ari_base, uint32_t core) { uint64_t cpu = read_mpidr() & (MPIDR_CPU_MASK); uint64_t cluster = (read_mpidr() & (MPIDR_CLUSTER_MASK)) >> (MPIDR_AFFINITY_BITS); uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; int32_t ret; /* construct the current CPU # */ cpu |= (cluster << 2); /* sanity check target core id */ if ((core >= MCE_CORE_ID_MAX) || (cpu == (uint64_t)core)) { ERROR("%s: unsupported core id (%d)\n", __func__, core); ret = EINVAL; } else { /* * The Denver cluster has 2 CPUs only - 0, 1. */ if ((impl == DENVER_IMPL) && ((core == 2U) || (core == 3U))) { ERROR("%s: unknown core id (%d)\n", __func__, core); ret = EINVAL; } else { /* clean the previous response state */ ari_clobber_response(ari_base); ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_ONLINE_CORE, core, 0U); } } return ret; } int32_t ari_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable) { uint32_t val; /* clean the previous response state */ ari_clobber_response(ari_base); /* * If the enable bit is cleared, Auto-CC3 will be disabled by setting * the SW visible voltage/frequency request registers for all non * floorswept cores valid independent of StandbyWFI and disabling * the IDLE voltage/frequency request register. If set, Auto-CC3 * will be enabled by setting the ARM SW visible voltage/frequency * request registers for all non floorswept cores to be enabled by * StandbyWFI or the equivalent signal, and always keeping the IDLE * voltage/frequency request register enabled. */ val = (((freq & MCE_AUTO_CC3_FREQ_MASK) << MCE_AUTO_CC3_FREQ_SHIFT) |\ ((volt & MCE_AUTO_CC3_VTG_MASK) << MCE_AUTO_CC3_VTG_SHIFT) |\ ((enable != 0U) ? MCE_AUTO_CC3_ENABLE_BIT : 0U)); return ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_CC3_CTRL, val, 0U); } int32_t ari_reset_vector_update(uint32_t ari_base) { /* clean the previous response state */ ari_clobber_response(ari_base); /* * Need to program the CPU reset vector one time during cold boot * and SC7 exit */ (void)ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_COPY_MISCREG_AA64_RST, 0U, 0U); return 0; } int32_t ari_roc_flush_cache_trbits(uint32_t ari_base) { /* clean the previous response state */ ari_clobber_response(ari_base); return ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_ROC_FLUSH_CACHE_TRBITS, 0U, 0U); } int32_t ari_roc_flush_cache(uint32_t ari_base) { /* clean the previous response state */ ari_clobber_response(ari_base); return ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_ROC_FLUSH_CACHE_ONLY, 0U, 0U); } int32_t ari_roc_clean_cache(uint32_t ari_base) { /* clean the previous response state */ ari_clobber_response(ari_base); return ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_ROC_CLEAN_CACHE_ONLY, 0U, 0U); } uint64_t ari_read_write_mca(uint32_t ari_base, uint64_t cmd, uint64_t *data) { uint64_t mca_arg_data, result = 0; uint32_t resp_lo, resp_hi; uint32_t mca_arg_err, mca_arg_finish; int32_t ret; /* Set data (write) */ mca_arg_data = (data != NULL) ? *data : 0ULL; /* Set command */ ari_write_32(ari_base, (uint32_t)cmd, ARI_RESPONSE_DATA_LO); ari_write_32(ari_base, (uint32_t)(cmd >> 32U), ARI_RESPONSE_DATA_HI); ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_MCA, (uint32_t)mca_arg_data, (uint32_t)(mca_arg_data >> 32U)); if (ret == 0) { resp_lo = ari_get_response_low(ari_base); resp_hi = ari_get_response_high(ari_base); mca_arg_err = resp_lo & MCA_ARG_ERROR_MASK; mca_arg_finish = (resp_hi >> MCA_ARG_FINISH_SHIFT) & MCA_ARG_FINISH_MASK; if (mca_arg_finish == 0U) { result = (uint64_t)mca_arg_err; } else { if (data != NULL) { resp_lo = ari_get_request_low(ari_base); resp_hi = ari_get_request_high(ari_base); *data = ((uint64_t)resp_hi << 32U) | (uint64_t)resp_lo; } } } return result; } int32_t ari_update_ccplex_gsc(uint32_t ari_base, uint32_t gsc_idx) { int32_t ret = 0; /* sanity check GSC ID */ if (gsc_idx > TEGRA_ARI_GSC_VPR_IDX) { ret = EINVAL; } else { /* clean the previous response state */ ari_clobber_response(ari_base); /* * The MCE code will read the GSC carveout value, corrseponding to * the ID, from the MC registers and update the internal GSC registers * of the CCPLEX. */ (void)ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_UPDATE_CCPLEX_GSC, gsc_idx, 0U); } return ret; } void ari_enter_ccplex_state(uint32_t ari_base, uint32_t state_idx) { /* clean the previous response state */ ari_clobber_response(ari_base); /* * The MCE will shutdown or restart the entire system */ (void)ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_MISC_CCPLEX, state_idx, 0U); } int32_t ari_read_write_uncore_perfmon(uint32_t ari_base, uint64_t req, uint64_t *data) { int32_t ret, result; uint32_t val, req_status; uint8_t req_cmd; req_cmd = (uint8_t)(req & UNCORE_PERFMON_CMD_MASK); /* clean the previous response state */ ari_clobber_response(ari_base); /* sanity check input parameters */ if ((req_cmd == UNCORE_PERFMON_CMD_READ) && (data == NULL)) { ERROR("invalid parameters\n"); result = EINVAL; } else { /* * For "write" commands get the value that has to be written * to the uncore perfmon registers */ val = (req_cmd == UNCORE_PERFMON_CMD_WRITE) ? (uint32_t)*data : 0U; ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_PERFMON, val, (uint32_t)req); if (ret != 0) { result = ret; } else { /* read the command status value */ req_status = ari_get_response_high(ari_base) & UNCORE_PERFMON_RESP_STATUS_MASK; /* * For "read" commands get the data from the uncore * perfmon registers */ req_status &= UNCORE_PERFMON_RESP_STATUS_MASK; if ((req_status == 0U) && (req_cmd == UNCORE_PERFMON_CMD_READ)) { *data = ari_get_response_low(ari_base); } result = (int32_t)req_status; } } return result; } void ari_misc_ccplex(uint32_t ari_base, uint32_t index, uint32_t value) { /* * This invokes the ARI_MISC_CCPLEX commands. This can be * used to enable/disable coresight clock gating. */ if ((index > TEGRA_ARI_MISC_CCPLEX_EDBGREQ) || ((index == TEGRA_ARI_MISC_CCPLEX_CORESIGHT_CG_CTRL) && (value > 1U))) { ERROR("%s: invalid parameters \n", __func__); } else { /* clean the previous response state */ ari_clobber_response(ari_base); (void)ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_MISC_CCPLEX, index, value); } } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/drivers/mce/mce.c000066400000000000000000000330771355360272700250570ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* NVG functions handlers */ static arch_mce_ops_t nvg_mce_ops = { .enter_cstate = nvg_enter_cstate, .update_cstate_info = nvg_update_cstate_info, .update_crossover_time = nvg_update_crossover_time, .read_cstate_stats = nvg_read_cstate_stats, .write_cstate_stats = nvg_write_cstate_stats, .call_enum_misc = ari_enumeration_misc, .is_ccx_allowed = nvg_is_ccx_allowed, .is_sc7_allowed = nvg_is_sc7_allowed, .online_core = nvg_online_core, .cc3_ctrl = nvg_cc3_ctrl, .update_reset_vector = ari_reset_vector_update, .roc_flush_cache = ari_roc_flush_cache, .roc_flush_cache_trbits = ari_roc_flush_cache_trbits, .roc_clean_cache = ari_roc_clean_cache, .read_write_mca = ari_read_write_mca, .update_ccplex_gsc = ari_update_ccplex_gsc, .enter_ccplex_state = ari_enter_ccplex_state, .read_write_uncore_perfmon = ari_read_write_uncore_perfmon, .misc_ccplex = ari_misc_ccplex }; /* ARI functions handlers */ static arch_mce_ops_t ari_mce_ops = { .enter_cstate = ari_enter_cstate, .update_cstate_info = ari_update_cstate_info, .update_crossover_time = ari_update_crossover_time, .read_cstate_stats = ari_read_cstate_stats, .write_cstate_stats = ari_write_cstate_stats, .call_enum_misc = ari_enumeration_misc, .is_ccx_allowed = ari_is_ccx_allowed, .is_sc7_allowed = ari_is_sc7_allowed, .online_core = ari_online_core, .cc3_ctrl = ari_cc3_ctrl, .update_reset_vector = ari_reset_vector_update, .roc_flush_cache = ari_roc_flush_cache, .roc_flush_cache_trbits = ari_roc_flush_cache_trbits, .roc_clean_cache = ari_roc_clean_cache, .read_write_mca = ari_read_write_mca, .update_ccplex_gsc = ari_update_ccplex_gsc, .enter_ccplex_state = ari_enter_ccplex_state, .read_write_uncore_perfmon = ari_read_write_uncore_perfmon, .misc_ccplex = ari_misc_ccplex }; typedef struct { uint32_t ari_base; arch_mce_ops_t *ops; } mce_config_t; /* Table to hold the per-CPU ARI base address and function handlers */ static mce_config_t mce_cfg_table[MCE_ARI_APERTURES_MAX] = { { /* A57 Core 0 */ .ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_0_OFFSET, .ops = &ari_mce_ops, }, { /* A57 Core 1 */ .ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_1_OFFSET, .ops = &ari_mce_ops, }, { /* A57 Core 2 */ .ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_2_OFFSET, .ops = &ari_mce_ops, }, { /* A57 Core 3 */ .ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_3_OFFSET, .ops = &ari_mce_ops, }, { /* D15 Core 0 */ .ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_4_OFFSET, .ops = &nvg_mce_ops, }, { /* D15 Core 1 */ .ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_5_OFFSET, .ops = &nvg_mce_ops, } }; static uint32_t mce_get_curr_cpu_ari_base(void) { uint64_t mpidr = read_mpidr(); uint64_t cpuid = mpidr & MPIDR_CPU_MASK; uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; /* * T186 has 2 CPU clusters, one with Denver CPUs and the other with * ARM CortexA-57 CPUs. Each cluster consists of 4 CPUs and the CPU * numbers start from 0. In order to get the proper arch_mce_ops_t * struct, we have to convert the Denver CPU ids to the corresponding * indices in the mce_ops_table array. */ if (impl == DENVER_IMPL) { cpuid |= 0x4U; } return mce_cfg_table[cpuid].ari_base; } static arch_mce_ops_t *mce_get_curr_cpu_ops(void) { uint64_t mpidr = read_mpidr(); uint64_t cpuid = mpidr & MPIDR_CPU_MASK; uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; /* * T186 has 2 CPU clusters, one with Denver CPUs and the other with * ARM CortexA-57 CPUs. Each cluster consists of 4 CPUs and the CPU * numbers start from 0. In order to get the proper arch_mce_ops_t * struct, we have to convert the Denver CPU ids to the corresponding * indices in the mce_ops_table array. */ if (impl == DENVER_IMPL) { cpuid |= 0x4U; } return mce_cfg_table[cpuid].ops; } /******************************************************************************* * Common handler for all MCE commands ******************************************************************************/ int32_t mce_command_handler(uint64_t cmd, uint64_t arg0, uint64_t arg1, uint64_t arg2) { const arch_mce_ops_t *ops; gp_regs_t *gp_regs = get_gpregs_ctx(cm_get_context(NON_SECURE)); uint32_t cpu_ari_base; uint64_t ret64 = 0, arg3, arg4, arg5; int32_t ret = 0; assert(gp_regs != NULL); /* get a pointer to the CPU's arch_mce_ops_t struct */ ops = mce_get_curr_cpu_ops(); /* get the CPU's ARI base address */ cpu_ari_base = mce_get_curr_cpu_ari_base(); switch (cmd) { case (uint64_t)MCE_CMD_ENTER_CSTATE: ret = ops->enter_cstate(cpu_ari_base, arg0, arg1); break; case (uint64_t)MCE_CMD_UPDATE_CSTATE_INFO: /* * get the parameters required for the update cstate info * command */ arg3 = read_ctx_reg(gp_regs, CTX_GPREG_X4); arg4 = read_ctx_reg(gp_regs, CTX_GPREG_X5); arg5 = read_ctx_reg(gp_regs, CTX_GPREG_X6); ret = ops->update_cstate_info(cpu_ari_base, (uint32_t)arg0, (uint32_t)arg1, (uint32_t)arg2, (uint8_t)arg3, (uint32_t)arg4, (uint8_t)arg5); write_ctx_reg(gp_regs, CTX_GPREG_X4, (0ULL)); write_ctx_reg(gp_regs, CTX_GPREG_X5, (0ULL)); write_ctx_reg(gp_regs, CTX_GPREG_X6, (0ULL)); break; case (uint64_t)MCE_CMD_UPDATE_CROSSOVER_TIME: ret = ops->update_crossover_time(cpu_ari_base, arg0, arg1); break; case (uint64_t)MCE_CMD_READ_CSTATE_STATS: ret64 = ops->read_cstate_stats(cpu_ari_base, arg0); /* update context to return cstate stats value */ write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64)); write_ctx_reg(gp_regs, CTX_GPREG_X2, (ret64)); break; case (uint64_t)MCE_CMD_WRITE_CSTATE_STATS: ret = ops->write_cstate_stats(cpu_ari_base, arg0, arg1); break; case (uint64_t)MCE_CMD_IS_CCX_ALLOWED: ret = ops->is_ccx_allowed(cpu_ari_base, arg0, arg1); /* update context to return CCx status value */ write_ctx_reg(gp_regs, CTX_GPREG_X1, (uint64_t)(ret)); break; case (uint64_t)MCE_CMD_IS_SC7_ALLOWED: ret = ops->is_sc7_allowed(cpu_ari_base, arg0, arg1); /* update context to return SC7 status value */ write_ctx_reg(gp_regs, CTX_GPREG_X1, (uint64_t)(ret)); write_ctx_reg(gp_regs, CTX_GPREG_X3, (uint64_t)(ret)); break; case (uint64_t)MCE_CMD_ONLINE_CORE: ret = ops->online_core(cpu_ari_base, arg0); break; case (uint64_t)MCE_CMD_CC3_CTRL: ret = ops->cc3_ctrl(cpu_ari_base, arg0, arg1, arg2); break; case (uint64_t)MCE_CMD_ECHO_DATA: ret64 = ops->call_enum_misc(cpu_ari_base, TEGRA_ARI_MISC_ECHO, arg0); /* update context to return if echo'd data matched source */ write_ctx_reg(gp_regs, CTX_GPREG_X1, ((ret64 == arg0) ? 1ULL : 0ULL)); write_ctx_reg(gp_regs, CTX_GPREG_X2, ((ret64 == arg0) ? 1ULL : 0ULL)); break; case (uint64_t)MCE_CMD_READ_VERSIONS: ret64 = ops->call_enum_misc(cpu_ari_base, TEGRA_ARI_MISC_VERSION, arg0); /* * version = minor(63:32) | major(31:0). Update context * to return major and minor version number. */ write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64)); write_ctx_reg(gp_regs, CTX_GPREG_X2, (ret64 >> 32ULL)); break; case (uint64_t)MCE_CMD_ENUM_FEATURES: ret64 = ops->call_enum_misc(cpu_ari_base, TEGRA_ARI_MISC_FEATURE_LEAF_0, arg0); /* update context to return features value */ write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64)); break; case (uint64_t)MCE_CMD_ROC_FLUSH_CACHE_TRBITS: ret = ops->roc_flush_cache_trbits(cpu_ari_base); break; case (uint64_t)MCE_CMD_ROC_FLUSH_CACHE: ret = ops->roc_flush_cache(cpu_ari_base); break; case (uint64_t)MCE_CMD_ROC_CLEAN_CACHE: ret = ops->roc_clean_cache(cpu_ari_base); break; case (uint64_t)MCE_CMD_ENUM_READ_MCA: ret64 = ops->read_write_mca(cpu_ari_base, arg0, &arg1); /* update context to return MCA data/error */ write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64)); write_ctx_reg(gp_regs, CTX_GPREG_X2, (arg1)); write_ctx_reg(gp_regs, CTX_GPREG_X3, (ret64)); break; case (uint64_t)MCE_CMD_ENUM_WRITE_MCA: ret64 = ops->read_write_mca(cpu_ari_base, arg0, &arg1); /* update context to return MCA error */ write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64)); write_ctx_reg(gp_regs, CTX_GPREG_X3, (ret64)); break; #if ENABLE_CHIP_VERIFICATION_HARNESS case (uint64_t)MCE_CMD_ENABLE_LATIC: /* * This call is not for production use. The constant value, * 0xFFFF0000, is specific to allowing for enabling LATIC on * pre-production parts for the chip verification harness. * * Enabling LATIC allows S/W to read the MINI ISPs in the * CCPLEX. The ISMs are used for various measurements relevant * to particular locations in the Silicon. They are small * counters which can be polled to determine how fast a * particular location in the Silicon is. */ ops->enter_ccplex_state(mce_get_curr_cpu_ari_base(), 0xFFFF0000); break; #endif case (uint64_t)MCE_CMD_UNCORE_PERFMON_REQ: ret = ops->read_write_uncore_perfmon(cpu_ari_base, arg0, &arg1); /* update context to return data */ write_ctx_reg(gp_regs, CTX_GPREG_X1, (arg1)); break; case (uint64_t)MCE_CMD_MISC_CCPLEX: ops->misc_ccplex(cpu_ari_base, arg0, arg1); break; default: ERROR("unknown MCE command (%llu)\n", cmd); ret = EINVAL; break; } return ret; } /******************************************************************************* * Handler to update the reset vector for CPUs ******************************************************************************/ int32_t mce_update_reset_vector(void) { const arch_mce_ops_t *ops = mce_get_curr_cpu_ops(); ops->update_reset_vector(mce_get_curr_cpu_ari_base()); return 0; } static int32_t mce_update_ccplex_gsc(tegra_ari_gsc_index_t gsc_idx) { const arch_mce_ops_t *ops = mce_get_curr_cpu_ops(); ops->update_ccplex_gsc(mce_get_curr_cpu_ari_base(), gsc_idx); return 0; } /******************************************************************************* * Handler to update carveout values for Video Memory Carveout region ******************************************************************************/ int32_t mce_update_gsc_videomem(void) { return mce_update_ccplex_gsc(TEGRA_ARI_GSC_VPR_IDX); } /******************************************************************************* * Handler to update carveout values for TZDRAM aperture ******************************************************************************/ int32_t mce_update_gsc_tzdram(void) { return mce_update_ccplex_gsc(TEGRA_ARI_GSC_TZ_DRAM_IDX); } /******************************************************************************* * Handler to update carveout values for TZ SysRAM aperture ******************************************************************************/ int32_t mce_update_gsc_tzram(void) { return mce_update_ccplex_gsc(TEGRA_ARI_GSC_TZRAM); } /******************************************************************************* * Handler to shutdown/reset the entire system ******************************************************************************/ __dead2 void mce_enter_ccplex_state(uint32_t state_idx) { const arch_mce_ops_t *ops = mce_get_curr_cpu_ops(); /* sanity check state value */ if ((state_idx != TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF) && (state_idx != TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT)) { panic(); } ops->enter_ccplex_state(mce_get_curr_cpu_ari_base(), state_idx); /* wait till the CCPLEX powers down */ for (;;) { ; } } /******************************************************************************* * Handler to issue the UPDATE_CSTATE_INFO request ******************************************************************************/ void mce_update_cstate_info(const mce_cstate_info_t *cstate) { const arch_mce_ops_t *ops = mce_get_curr_cpu_ops(); /* issue the UPDATE_CSTATE_INFO request */ ops->update_cstate_info(mce_get_curr_cpu_ari_base(), cstate->cluster, cstate->ccplex, cstate->system, cstate->system_state_force, cstate->wake_mask, cstate->update_wake_mask); } /******************************************************************************* * Handler to read the MCE firmware version and check if it is compatible * with interface header the BL3-1 was compiled against ******************************************************************************/ void mce_verify_firmware_version(void) { const arch_mce_ops_t *ops; uint32_t cpu_ari_base; uint64_t version; uint32_t major, minor; /* * MCE firmware is not supported on simulation platforms. */ if (tegra_platform_is_emulation()) { INFO("MCE firmware is not supported\n"); } else { /* get a pointer to the CPU's arch_mce_ops_t struct */ ops = mce_get_curr_cpu_ops(); /* get the CPU's ARI base address */ cpu_ari_base = mce_get_curr_cpu_ari_base(); /* * Read the MCE firmware version and extract the major and minor * version fields */ version = ops->call_enum_misc(cpu_ari_base, TEGRA_ARI_MISC_VERSION, 0); major = (uint32_t)version; minor = (uint32_t)(version >> 32); INFO("MCE Version - HW=%d:%d, SW=%d:%d\n", major, minor, TEGRA_ARI_VERSION_MAJOR, TEGRA_ARI_VERSION_MINOR); /* * Verify that the MCE firmware version and the interface header * match */ if (major != TEGRA_ARI_VERSION_MAJOR) { ERROR("ARI major version mismatch\n"); panic(); } if (minor < TEGRA_ARI_VERSION_MINOR) { ERROR("ARI minor version mismatch\n"); panic(); } } } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/drivers/mce/nvg.c000066400000000000000000000153161355360272700251010ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include int32_t nvg_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time) { int32_t ret = 0; uint64_t val = 0ULL; (void)ari_base; /* check for allowed power state */ if ((state != TEGRA_ARI_CORE_C0) && (state != TEGRA_ARI_CORE_C1) && (state != TEGRA_ARI_CORE_C6) && (state != TEGRA_ARI_CORE_C7)) { ERROR("%s: unknown cstate (%d)\n", __func__, state); ret = EINVAL; } else { /* time (TSC ticks) until the core is expected to get a wake event */ nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_WAKE_TIME, wake_time); /* set the core cstate */ val = read_actlr_el1() & ~ACTLR_EL1_PMSTATE_MASK; write_actlr_el1(val | (uint64_t)state); } return ret; } /* * This request allows updating of CLUSTER_CSTATE, CCPLEX_CSTATE and * SYSTEM_CSTATE values. */ int32_t nvg_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex, uint32_t system, uint8_t sys_state_force, uint32_t wake_mask, uint8_t update_wake_mask) { uint64_t val = 0ULL; (void)ari_base; /* update CLUSTER_CSTATE? */ if (cluster != 0U) { val |= ((uint64_t)cluster & CLUSTER_CSTATE_MASK) | CLUSTER_CSTATE_UPDATE_BIT; } /* update CCPLEX_CSTATE? */ if (ccplex != 0U) { val |= (((uint64_t)ccplex & CCPLEX_CSTATE_MASK) << CCPLEX_CSTATE_SHIFT) | CCPLEX_CSTATE_UPDATE_BIT; } /* update SYSTEM_CSTATE? */ if (system != 0U) { val |= (((uint64_t)system & SYSTEM_CSTATE_MASK) << SYSTEM_CSTATE_SHIFT) | (((uint64_t)sys_state_force << SYSTEM_CSTATE_FORCE_UPDATE_SHIFT) | SYSTEM_CSTATE_UPDATE_BIT); } /* update wake mask value? */ if (update_wake_mask != 0U) { val |= CSTATE_WAKE_MASK_UPDATE_BIT; } /* set the wake mask */ val &= CSTATE_WAKE_MASK_CLEAR; val |= ((uint64_t)wake_mask << CSTATE_WAKE_MASK_SHIFT); /* set the updated cstate info */ nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_CSTATE_INFO, val); return 0; } int32_t nvg_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time) { int32_t ret = 0; (void)ari_base; /* sanity check crossover type */ if (type > TEGRA_ARI_CROSSOVER_CCP3_SC1) { ret = EINVAL; } else { /* * The crossover threshold limit types start from * TEGRA_CROSSOVER_TYPE_C1_C6 to TEGRA_CROSSOVER_TYPE_CCP3_SC7. * The command indices for updating the threshold be generated * by adding the type to the NVG_SET_THRESHOLD_CROSSOVER_C1_C6 * command index. */ nvg_set_request_data((TEGRA_NVG_CHANNEL_CROSSOVER_C1_C6 + (uint64_t)type), (uint64_t)time); } return ret; } uint64_t nvg_read_cstate_stats(uint32_t ari_base, uint32_t state) { uint64_t ret; (void)ari_base; /* sanity check state */ if (state == 0U) { ret = EINVAL; } else { /* * The cstate types start from NVG_READ_CSTATE_STATS_SC7_ENTRIES * to NVG_GET_LAST_CSTATE_ENTRY_A57_3. The command indices for * reading the threshold can be generated by adding the type to * the NVG_CLEAR_CSTATE_STATS command index. */ nvg_set_request((TEGRA_NVG_CHANNEL_CSTATE_STATS_CLEAR + (uint64_t)state)); ret = nvg_get_result(); } return ret; } int32_t nvg_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats) { uint64_t val; (void)ari_base; /* * The only difference between a CSTATE_STATS_WRITE and * CSTATE_STATS_READ is the usage of the 63:32 in the request. * 63:32 are set to '0' for a read, while a write contains the * actual stats value to be written. */ val = ((uint64_t)stats << MCE_CSTATE_STATS_TYPE_SHIFT) | state; /* * The cstate types start from NVG_READ_CSTATE_STATS_SC7_ENTRIES * to NVG_GET_LAST_CSTATE_ENTRY_A57_3. The command indices for * reading the threshold can be generated by adding the type to * the NVG_CLEAR_CSTATE_STATS command index. */ nvg_set_request_data((TEGRA_NVG_CHANNEL_CSTATE_STATS_CLEAR + (uint64_t)state), val); return 0; } int32_t nvg_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time) { (void)ari_base; (void)state; (void)wake_time; /* This does not apply to the Denver cluster */ return 0; } int32_t nvg_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time) { uint64_t val; int32_t ret; (void)ari_base; /* check for allowed power state */ if ((state != TEGRA_ARI_CORE_C0) && (state != TEGRA_ARI_CORE_C1) && (state != TEGRA_ARI_CORE_C6) && (state != TEGRA_ARI_CORE_C7)) { ERROR("%s: unknown cstate (%d)\n", __func__, state); ret = EINVAL; } else { /* * Request format - * 63:32 = wake time * 31:0 = C-state for this core */ val = ((uint64_t)wake_time << MCE_SC7_WAKE_TIME_SHIFT) | ((uint64_t)state & MCE_SC7_ALLOWED_MASK); /* issue command to check if SC7 is allowed */ nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED, val); /* 1 = SC7 allowed, 0 = SC7 not allowed */ ret = (nvg_get_result() != 0ULL) ? 1 : 0; } return ret; } int32_t nvg_online_core(uint32_t ari_base, uint32_t core) { uint64_t cpu = read_mpidr() & MPIDR_CPU_MASK; uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; int32_t ret = 0; (void)ari_base; /* sanity check code id */ if ((core >= MCE_CORE_ID_MAX) || (cpu == core)) { ERROR("%s: unsupported core id (%d)\n", __func__, core); ret = EINVAL; } else { /* * The Denver cluster has 2 CPUs only - 0, 1. */ if ((impl == DENVER_IMPL) && ((core == 2U) || (core == 3U))) { ERROR("%s: unknown core id (%d)\n", __func__, core); ret = EINVAL; } else { /* get a core online */ nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_ONLINE_CORE, ((uint64_t)core & MCE_CORE_ID_MASK)); } } return ret; } int32_t nvg_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable) { uint32_t val; (void)ari_base; /* * If the enable bit is cleared, Auto-CC3 will be disabled by setting * the SW visible voltage/frequency request registers for all non * floorswept cores valid independent of StandbyWFI and disabling * the IDLE voltage/frequency request register. If set, Auto-CC3 * will be enabled by setting the ARM SW visible voltage/frequency * request registers for all non floorswept cores to be enabled by * StandbyWFI or the equivalent signal, and always keeping the IDLE * voltage/frequency request register enabled. */ val = (((freq & MCE_AUTO_CC3_FREQ_MASK) << MCE_AUTO_CC3_FREQ_SHIFT) |\ ((volt & MCE_AUTO_CC3_VTG_MASK) << MCE_AUTO_CC3_VTG_SHIFT) |\ ((enable != 0U) ? MCE_AUTO_CC3_ENABLE_BIT : 0U)); nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_CC3_CTRL, (uint64_t)val); return 0; } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/plat_memctrl.c000066400000000000000000000663561355360272700245620ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /******************************************************************************* * Array to hold stream_id override config register offsets ******************************************************************************/ const static uint32_t tegra186_streamid_override_regs[] = { MC_STREAMID_OVERRIDE_CFG_PTCR, MC_STREAMID_OVERRIDE_CFG_AFIR, MC_STREAMID_OVERRIDE_CFG_HDAR, MC_STREAMID_OVERRIDE_CFG_HOST1XDMAR, MC_STREAMID_OVERRIDE_CFG_NVENCSRD, MC_STREAMID_OVERRIDE_CFG_SATAR, MC_STREAMID_OVERRIDE_CFG_MPCORER, MC_STREAMID_OVERRIDE_CFG_NVENCSWR, MC_STREAMID_OVERRIDE_CFG_AFIW, MC_STREAMID_OVERRIDE_CFG_HDAW, MC_STREAMID_OVERRIDE_CFG_MPCOREW, MC_STREAMID_OVERRIDE_CFG_SATAW, MC_STREAMID_OVERRIDE_CFG_ISPRA, MC_STREAMID_OVERRIDE_CFG_ISPWA, MC_STREAMID_OVERRIDE_CFG_ISPWB, MC_STREAMID_OVERRIDE_CFG_XUSB_HOSTR, MC_STREAMID_OVERRIDE_CFG_XUSB_HOSTW, MC_STREAMID_OVERRIDE_CFG_XUSB_DEVR, MC_STREAMID_OVERRIDE_CFG_XUSB_DEVW, MC_STREAMID_OVERRIDE_CFG_TSECSRD, MC_STREAMID_OVERRIDE_CFG_TSECSWR, MC_STREAMID_OVERRIDE_CFG_GPUSRD, MC_STREAMID_OVERRIDE_CFG_GPUSWR, MC_STREAMID_OVERRIDE_CFG_SDMMCRA, MC_STREAMID_OVERRIDE_CFG_SDMMCRAA, MC_STREAMID_OVERRIDE_CFG_SDMMCR, MC_STREAMID_OVERRIDE_CFG_SDMMCRAB, MC_STREAMID_OVERRIDE_CFG_SDMMCWA, MC_STREAMID_OVERRIDE_CFG_SDMMCWAA, MC_STREAMID_OVERRIDE_CFG_SDMMCW, MC_STREAMID_OVERRIDE_CFG_SDMMCWAB, MC_STREAMID_OVERRIDE_CFG_VICSRD, MC_STREAMID_OVERRIDE_CFG_VICSWR, MC_STREAMID_OVERRIDE_CFG_VIW, MC_STREAMID_OVERRIDE_CFG_NVDECSRD, MC_STREAMID_OVERRIDE_CFG_NVDECSWR, MC_STREAMID_OVERRIDE_CFG_APER, MC_STREAMID_OVERRIDE_CFG_APEW, MC_STREAMID_OVERRIDE_CFG_NVJPGSRD, MC_STREAMID_OVERRIDE_CFG_NVJPGSWR, MC_STREAMID_OVERRIDE_CFG_SESRD, MC_STREAMID_OVERRIDE_CFG_SESWR, MC_STREAMID_OVERRIDE_CFG_ETRR, MC_STREAMID_OVERRIDE_CFG_ETRW, MC_STREAMID_OVERRIDE_CFG_TSECSRDB, MC_STREAMID_OVERRIDE_CFG_TSECSWRB, MC_STREAMID_OVERRIDE_CFG_GPUSRD2, MC_STREAMID_OVERRIDE_CFG_GPUSWR2, MC_STREAMID_OVERRIDE_CFG_AXISR, MC_STREAMID_OVERRIDE_CFG_AXISW, MC_STREAMID_OVERRIDE_CFG_EQOSR, MC_STREAMID_OVERRIDE_CFG_EQOSW, MC_STREAMID_OVERRIDE_CFG_UFSHCR, MC_STREAMID_OVERRIDE_CFG_UFSHCW, MC_STREAMID_OVERRIDE_CFG_NVDISPLAYR, MC_STREAMID_OVERRIDE_CFG_BPMPR, MC_STREAMID_OVERRIDE_CFG_BPMPW, MC_STREAMID_OVERRIDE_CFG_BPMPDMAR, MC_STREAMID_OVERRIDE_CFG_BPMPDMAW, MC_STREAMID_OVERRIDE_CFG_AONR, MC_STREAMID_OVERRIDE_CFG_AONW, MC_STREAMID_OVERRIDE_CFG_AONDMAR, MC_STREAMID_OVERRIDE_CFG_AONDMAW, MC_STREAMID_OVERRIDE_CFG_SCER, MC_STREAMID_OVERRIDE_CFG_SCEW, MC_STREAMID_OVERRIDE_CFG_SCEDMAR, MC_STREAMID_OVERRIDE_CFG_SCEDMAW, MC_STREAMID_OVERRIDE_CFG_APEDMAR, MC_STREAMID_OVERRIDE_CFG_APEDMAW, MC_STREAMID_OVERRIDE_CFG_NVDISPLAYR1, MC_STREAMID_OVERRIDE_CFG_VICSRD1, MC_STREAMID_OVERRIDE_CFG_NVDECSRD1 }; /******************************************************************************* * Array to hold the security configs for stream IDs ******************************************************************************/ const static mc_streamid_security_cfg_t tegra186_streamid_sec_cfgs[] = { mc_make_sec_cfg(SCEW, NON_SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(AFIR, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(AFIW, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(NVDISPLAYR1, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(XUSB_DEVR, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(VICSRD1, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(NVENCSWR, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(TSECSRDB, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(AXISW, SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(SDMMCWAB, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(AONDMAW, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(GPUSWR2, SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(SATAW, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(UFSHCW, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(SDMMCR, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(SCEDMAW, NON_SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(UFSHCR, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(SDMMCWAA, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(SESWR, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(MPCORER, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(PTCR, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(BPMPW, NON_SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(ETRW, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(GPUSRD, SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(VICSWR, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(SCEDMAR, NON_SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(HDAW, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(ISPWA, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(EQOSW, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(XUSB_HOSTW, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(TSECSWR, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(SDMMCRAA, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(VIW, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(AXISR, SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(SDMMCW, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(BPMPDMAW, NON_SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(ISPRA, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(NVDECSWR, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(XUSB_DEVW, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(NVDECSRD, NON_SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(MPCOREW, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(NVDISPLAYR, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(BPMPDMAR, NON_SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(NVJPGSWR, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(NVDECSRD1, NON_SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(TSECSRD, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(NVJPGSRD, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(SDMMCWA, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(SCER, NON_SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(XUSB_HOSTR, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(VICSRD, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(AONDMAR, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(AONW, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(SDMMCRA, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(HOST1XDMAR, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(EQOSR, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(SATAR, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(BPMPR, NON_SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(HDAR, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(SDMMCRAB, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(ETRR, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(AONR, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(SESRD, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(NVENCSRD, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(GPUSWR, SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(TSECSWRB, NON_SECURE, NO_OVERRIDE, ENABLE), mc_make_sec_cfg(ISPWB, NON_SECURE, OVERRIDE, ENABLE), mc_make_sec_cfg(GPUSRD2, SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(APEDMAW, NON_SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(APER, NON_SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(APEW, NON_SECURE, NO_OVERRIDE, DISABLE), mc_make_sec_cfg(APEDMAR, NON_SECURE, NO_OVERRIDE, DISABLE), }; /******************************************************************************* * Array to hold the transaction override configs ******************************************************************************/ const static mc_txn_override_cfg_t tegra186_txn_override_cfgs[] = { mc_make_txn_override_cfg(BPMPW, CGID_TAG_ADR), mc_make_txn_override_cfg(EQOSW, CGID_TAG_ADR), mc_make_txn_override_cfg(NVJPGSWR, CGID_TAG_ADR), mc_make_txn_override_cfg(SDMMCWAA, CGID_TAG_ADR), mc_make_txn_override_cfg(MPCOREW, CGID_TAG_ADR), mc_make_txn_override_cfg(SCEDMAW, CGID_TAG_ADR), mc_make_txn_override_cfg(SDMMCW, CGID_TAG_ADR), mc_make_txn_override_cfg(AXISW, CGID_TAG_ADR), mc_make_txn_override_cfg(TSECSWR, CGID_TAG_ADR), mc_make_txn_override_cfg(GPUSWR, CGID_TAG_ADR), mc_make_txn_override_cfg(XUSB_HOSTW, CGID_TAG_ADR), mc_make_txn_override_cfg(TSECSWRB, CGID_TAG_ADR), mc_make_txn_override_cfg(GPUSWR2, CGID_TAG_ADR), mc_make_txn_override_cfg(AONDMAW, CGID_TAG_ADR), mc_make_txn_override_cfg(AONW, CGID_TAG_ADR), mc_make_txn_override_cfg(SESWR, CGID_TAG_ADR), mc_make_txn_override_cfg(BPMPDMAW, CGID_TAG_ADR), mc_make_txn_override_cfg(SDMMCWA, CGID_TAG_ADR), mc_make_txn_override_cfg(HDAW, CGID_TAG_ADR), mc_make_txn_override_cfg(NVDECSWR, CGID_TAG_ADR), mc_make_txn_override_cfg(UFSHCW, CGID_TAG_ADR), mc_make_txn_override_cfg(SATAW, CGID_TAG_ADR), mc_make_txn_override_cfg(ETRW, CGID_TAG_ADR), mc_make_txn_override_cfg(VICSWR, CGID_TAG_ADR), mc_make_txn_override_cfg(NVENCSWR, CGID_TAG_ADR), mc_make_txn_override_cfg(SDMMCWAB, CGID_TAG_ADR), mc_make_txn_override_cfg(ISPWB, CGID_TAG_ADR), mc_make_txn_override_cfg(APEW, CGID_TAG_ADR), mc_make_txn_override_cfg(XUSB_DEVW, CGID_TAG_ADR), mc_make_txn_override_cfg(AFIW, CGID_TAG_ADR), mc_make_txn_override_cfg(SCEW, CGID_TAG_ADR), }; static void tegra186_memctrl_reconfig_mss_clients(void) { #if ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS uint32_t val, wdata_0, wdata_1; /* * Assert Memory Controller's HOTRESET_FLUSH_ENABLE signal for * boot and strongly ordered MSS clients to flush existing memory * traffic and stall future requests. */ val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL0); assert(val == MC_CLIENT_HOTRESET_CTRL0_RESET_VAL); wdata_0 = MC_CLIENT_HOTRESET_CTRL0_HDA_FLUSH_ENB | MC_CLIENT_HOTRESET_CTRL0_AFI_FLUSH_ENB | MC_CLIENT_HOTRESET_CTRL0_SATA_FLUSH_ENB | MC_CLIENT_HOTRESET_CTRL0_XUSB_HOST_FLUSH_ENB | MC_CLIENT_HOTRESET_CTRL0_XUSB_DEV_FLUSH_ENB; tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL0, wdata_0); /* Wait for HOTRESET STATUS to indicate FLUSH_DONE */ do { val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS0); } while ((val & wdata_0) != wdata_0); /* Wait one more time due to SW WAR for known legacy issue */ do { val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS0); } while ((val & wdata_0) != wdata_0); val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL1); assert(val == MC_CLIENT_HOTRESET_CTRL1_RESET_VAL); wdata_1 = MC_CLIENT_HOTRESET_CTRL1_SDMMC4A_FLUSH_ENB | MC_CLIENT_HOTRESET_CTRL1_APE_FLUSH_ENB | MC_CLIENT_HOTRESET_CTRL1_SE_FLUSH_ENB | MC_CLIENT_HOTRESET_CTRL1_ETR_FLUSH_ENB | MC_CLIENT_HOTRESET_CTRL1_AXIS_FLUSH_ENB | MC_CLIENT_HOTRESET_CTRL1_EQOS_FLUSH_ENB | MC_CLIENT_HOTRESET_CTRL1_UFSHC_FLUSH_ENB | MC_CLIENT_HOTRESET_CTRL1_BPMP_FLUSH_ENB | MC_CLIENT_HOTRESET_CTRL1_AON_FLUSH_ENB | MC_CLIENT_HOTRESET_CTRL1_SCE_FLUSH_ENB; tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL1, wdata_1); /* Wait for HOTRESET STATUS to indicate FLUSH_DONE */ do { val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS1); } while ((val & wdata_1) != wdata_1); /* Wait one more time due to SW WAR for known legacy issue */ do { val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS1); } while ((val & wdata_1) != wdata_1); /* * Change MEMTYPE_OVERRIDE from SO_DEV -> PASSTHRU for boot and * strongly ordered MSS clients. ROC needs to be single point * of control on overriding the memory type. So, remove TSA's * memtype override. * * MC clients with default SO_DEV override still enabled at TSA: * AONW, BPMPW, SCEW, APEW */ mc_set_tsa_passthrough(AFIW); mc_set_tsa_passthrough(HDAW); mc_set_tsa_passthrough(SATAW); mc_set_tsa_passthrough(XUSB_HOSTW); mc_set_tsa_passthrough(XUSB_DEVW); mc_set_tsa_passthrough(SDMMCWAB); mc_set_tsa_passthrough(APEDMAW); mc_set_tsa_passthrough(SESWR); mc_set_tsa_passthrough(ETRW); mc_set_tsa_passthrough(AXISW); mc_set_tsa_passthrough(EQOSW); mc_set_tsa_passthrough(UFSHCW); mc_set_tsa_passthrough(BPMPDMAW); mc_set_tsa_passthrough(AONDMAW); mc_set_tsa_passthrough(SCEDMAW); /* Parker has no IO Coherency support and need the following: * Ordered MC Clients on Parker are AFI, EQOS, SATA, XUSB. * ISO clients(DISP, VI, EQOS) should never snoop caches and * don't need ROC/PCFIFO ordering. * ISO clients(EQOS) that need ordering should use PCFIFO ordering * and bypass ROC ordering by using FORCE_NON_COHERENT path. * FORCE_NON_COHERENT/FORCE_COHERENT config take precedence * over SMMU attributes. * Force all Normal memory transactions from ISO and non-ISO to be * non-coherent(bypass ROC, avoid cache snoop to avoid perf hit). * Force the SO_DEV transactions from ordered ISO clients(EQOS) to * non-coherent path and enable MC PCFIFO interlock for ordering. * Force the SO_DEV transactions from ordered non-ISO clients (PCIe, * XUSB, SATA) to coherent so that the transactions are * ordered by ROC. * PCFIFO ensure write ordering. * Read after Write ordering is maintained/enforced by MC clients. * Clients that need PCIe type write ordering must * go through ROC ordering. * Ordering enable for Read clients is not necessary. * R5's and A9 would get necessary ordering from AXI and * don't need ROC ordering enable: * - MMIO ordering is through dev mapping and MMIO * accesses bypass SMMU. * - Normal memory is accessed through SMMU and ordering is * ensured by client and AXI. * - Ack point for Normal memory is WCAM in MC. * - MMIO's can be early acked and AXI ensures dev memory ordering, * Client ensures read/write direction change ordering. * - See Bug 200312466 for more details. * * CGID_TAG_ADR is only present from T186 A02. As this code is common * between A01 and A02, tegra_memctrl_set_overrides() programs * CGID_TAG_ADR for the necessary clients on A02. */ mc_set_txn_override(HDAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(BPMPW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(PTCR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(NVDISPLAYR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(EQOSW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(NVJPGSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(ISPRA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(SDMMCWAA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(VICSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(MPCOREW, CGID_TAG_DEFAULT, SO_DEV_ZERO, NO_OVERRIDE, NO_OVERRIDE); mc_set_txn_override(GPUSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(AXISR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(SCEDMAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(SDMMCW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(EQOSR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); /* See bug 200131110 comment #35*/ mc_set_txn_override(APEDMAR, CGID_TAG_CLIENT_AXI_ID, SO_DEV_CLIENT_AXI_ID, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(NVENCSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(SDMMCRAB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(VICSRD1, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(BPMPDMAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(VIW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(SDMMCRAA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(AXISW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(XUSB_DEVR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(UFSHCR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(TSECSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(GPUSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(SATAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(XUSB_HOSTW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_COHERENT); mc_set_txn_override(TSECSWRB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(GPUSRD2, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(SCEDMAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(GPUSWR2, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(AONDMAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); /* See bug 200131110 comment #35*/ mc_set_txn_override(APEDMAW, CGID_TAG_CLIENT_AXI_ID, SO_DEV_CLIENT_AXI_ID, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(AONW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(HOST1XDMAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(ETRR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(SESWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(NVJPGSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(NVDECSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(TSECSRDB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(BPMPDMAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(APER, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(NVDECSRD1, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(XUSB_HOSTR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(ISPWA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(SESRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(SCER, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(AONR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(MPCORER, CGID_TAG_DEFAULT, SO_DEV_ZERO, NO_OVERRIDE, NO_OVERRIDE); mc_set_txn_override(SDMMCWA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(HDAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(NVDECSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(UFSHCW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(AONDMAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(SATAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_COHERENT); mc_set_txn_override(ETRW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(VICSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(NVENCSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); /* See bug 200131110 comment #35 */ mc_set_txn_override(AFIR, CGID_TAG_DEFAULT, SO_DEV_CLIENT_AXI_ID, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(SDMMCWAB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(SDMMCRA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(NVDISPLAYR1, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(ISPWB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(BPMPR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(APEW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(SDMMCR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); mc_set_txn_override(XUSB_DEVW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_COHERENT); mc_set_txn_override(TSECSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); /* * See bug 200131110 comment #35 - there are no normal requests * and AWID for SO/DEV requests is hardcoded in RTL for a * particular PCIE controller */ mc_set_txn_override(AFIW, CGID_TAG_DEFAULT, SO_DEV_CLIENT_AXI_ID, FORCE_NON_COHERENT, FORCE_COHERENT); mc_set_txn_override(SCEW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT); /* * At this point, ordering can occur at ROC. So, remove PCFIFO's * control over ordering requests. * * Change PCFIFO_*_ORDERED_CLIENT from ORDERED -> UNORDERED for * boot and strongly ordered MSS clients */ val = MC_PCFIFO_CLIENT_CONFIG1_RESET_VAL & mc_set_pcfifo_unordered_boot_so_mss(1, AFIW) & mc_set_pcfifo_unordered_boot_so_mss(1, HDAW) & mc_set_pcfifo_unordered_boot_so_mss(1, SATAW); tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG1, val); val = MC_PCFIFO_CLIENT_CONFIG2_RESET_VAL & mc_set_pcfifo_unordered_boot_so_mss(2, XUSB_HOSTW) & mc_set_pcfifo_unordered_boot_so_mss(2, XUSB_DEVW); tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG2, val); val = MC_PCFIFO_CLIENT_CONFIG3_RESET_VAL & mc_set_pcfifo_unordered_boot_so_mss(3, SDMMCWAB); tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG3, val); val = MC_PCFIFO_CLIENT_CONFIG4_RESET_VAL & mc_set_pcfifo_unordered_boot_so_mss(4, SESWR) & mc_set_pcfifo_unordered_boot_so_mss(4, ETRW) & mc_set_pcfifo_unordered_boot_so_mss(4, AXISW) & mc_set_pcfifo_unordered_boot_so_mss(4, UFSHCW) & mc_set_pcfifo_unordered_boot_so_mss(4, BPMPDMAW) & mc_set_pcfifo_unordered_boot_so_mss(4, AONDMAW) & mc_set_pcfifo_unordered_boot_so_mss(4, SCEDMAW); /* EQOSW is the only client that has PCFIFO order enabled. */ val |= mc_set_pcfifo_ordered_boot_so_mss(4, EQOSW); tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG4, val); val = MC_PCFIFO_CLIENT_CONFIG5_RESET_VAL & mc_set_pcfifo_unordered_boot_so_mss(5, APEDMAW); tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG5, val); /* * Deassert HOTRESET FLUSH_ENABLE for boot and strongly ordered MSS * clients to allow memory traffic from all clients to start passing * through ROC */ val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL0); assert(val == wdata_0); wdata_0 = MC_CLIENT_HOTRESET_CTRL0_RESET_VAL; tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL0, wdata_0); val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL1); assert(val == wdata_1); wdata_1 = MC_CLIENT_HOTRESET_CTRL1_RESET_VAL; tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL1, wdata_1); #endif } static void tegra186_memctrl_set_overrides(void) { const tegra_mc_settings_t *plat_mc_settings = tegra_get_mc_settings(); const mc_txn_override_cfg_t *mc_txn_override_cfgs; uint32_t num_txn_override_cfgs; uint32_t i, val; /* Get the settings from the platform */ assert(plat_mc_settings != NULL); mc_txn_override_cfgs = plat_mc_settings->txn_override_cfg; num_txn_override_cfgs = plat_mc_settings->num_txn_override_cfgs; /* * Set the MC_TXN_OVERRIDE registers for write clients. */ if ((tegra_chipid_is_t186()) && (!tegra_platform_is_silicon() || (tegra_platform_is_silicon() && (tegra_get_chipid_minor() == 1U)))) { /* * GPU and NVENC settings for Tegra186 simulation and * Silicon rev. A01 */ val = tegra_mc_read_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR); val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK; tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR, val | MC_TXN_OVERRIDE_CGID_TAG_ZERO); val = tegra_mc_read_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR2); val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK; tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR2, val | MC_TXN_OVERRIDE_CGID_TAG_ZERO); val = tegra_mc_read_32(MC_TXN_OVERRIDE_CONFIG_NVENCSWR); val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK; tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_NVENCSWR, val | MC_TXN_OVERRIDE_CGID_TAG_CLIENT_AXI_ID); } else { /* * Settings for Tegra186 silicon rev. A02 and onwards. */ for (i = 0; i < num_txn_override_cfgs; i++) { val = tegra_mc_read_32(mc_txn_override_cfgs[i].offset); val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK; tegra_mc_write_32(mc_txn_override_cfgs[i].offset, val | mc_txn_override_cfgs[i].cgid_tag); } } } /******************************************************************************* * Struct to hold the memory controller settings ******************************************************************************/ static tegra_mc_settings_t tegra186_mc_settings = { .streamid_override_cfg = tegra186_streamid_override_regs, .num_streamid_override_cfgs = (uint32_t)ARRAY_SIZE(tegra186_streamid_override_regs), .streamid_security_cfg = tegra186_streamid_sec_cfgs, .num_streamid_security_cfgs = (uint32_t)ARRAY_SIZE(tegra186_streamid_sec_cfgs), .txn_override_cfg = tegra186_txn_override_cfgs, .num_txn_override_cfgs = (uint32_t)ARRAY_SIZE(tegra186_txn_override_cfgs), .reconfig_mss_clients = tegra186_memctrl_reconfig_mss_clients, .set_txn_overrides = tegra186_memctrl_set_overrides, }; /******************************************************************************* * Handler to return the pointer to the memory controller's settings struct ******************************************************************************/ tegra_mc_settings_t *tegra_get_mc_settings(void) { return &tegra186_mc_settings; } /******************************************************************************* * Handler to program the scratch registers with TZDRAM settings for the * resume firmware ******************************************************************************/ void plat_memctrl_tzdram_setup(uint64_t phys_base, uint64_t size_in_bytes) { uint32_t val; /* * Setup the Memory controller to allow only secure accesses to * the TZDRAM carveout */ INFO("Configuring TrustZone DRAM Memory Carveout\n"); tegra_mc_write_32(MC_SECURITY_CFG0_0, (uint32_t)phys_base); tegra_mc_write_32(MC_SECURITY_CFG3_0, (uint32_t)(phys_base >> 32)); tegra_mc_write_32(MC_SECURITY_CFG1_0, size_in_bytes >> 20); /* * When TZ encryption is enabled, we need to setup TZDRAM * before CPU accesses TZ Carveout, else CPU will fetch * non-decrypted data. So save TZDRAM setting for SC7 resume * FW to restore. * * Scratch registers map: * RSV55_0 = CFG1[12:0] | CFG0[31:20] * RSV55_1 = CFG3[1:0] */ val = tegra_mc_read_32(MC_SECURITY_CFG1_0) & MC_SECURITY_SIZE_MB_MASK; val |= tegra_mc_read_32(MC_SECURITY_CFG0_0) & MC_SECURITY_BOM_MASK; mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_TZDRAM_ADDR_LO, val); val = tegra_mc_read_32(MC_SECURITY_CFG3_0) & MC_SECURITY_BOM_HI_MASK; mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_TZDRAM_ADDR_HI, val); /* * MCE propagates the security configuration values across the * CCPLEX. */ (void)mce_update_gsc_tzdram(); } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/plat_psci_handlers.c000066400000000000000000000277761355360272700257400ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern void memcpy16(void *dest, const void *src, unsigned int length); /* state id mask */ #define TEGRA186_STATE_ID_MASK 0xFU /* constants to get power state's wake time */ #define TEGRA186_WAKE_TIME_MASK 0x0FFFFFF0U #define TEGRA186_WAKE_TIME_SHIFT 4U /* default core wake mask for CPU_SUSPEND */ #define TEGRA186_CORE_WAKE_MASK 0x180cU /* context size to save during system suspend */ #define TEGRA186_SE_CONTEXT_SIZE 3U static uint32_t se_regs[TEGRA186_SE_CONTEXT_SIZE]; static struct tegra_psci_percpu_data { uint32_t wake_time; } __aligned(CACHE_WRITEBACK_GRANULE) tegra_percpu_data[PLATFORM_CORE_COUNT]; int32_t tegra_soc_validate_power_state(uint32_t power_state, psci_power_state_t *req_state) { uint8_t state_id = (uint8_t)psci_get_pstate_id(power_state) & TEGRA186_STATE_ID_MASK; uint32_t cpu = plat_my_core_pos(); int32_t ret = PSCI_E_SUCCESS; /* save the core wake time (in TSC ticks)*/ tegra_percpu_data[cpu].wake_time = (power_state & TEGRA186_WAKE_TIME_MASK) << TEGRA186_WAKE_TIME_SHIFT; /* * Clean percpu_data[cpu] to DRAM. This needs to be done to ensure that * the correct value is read in tegra_soc_pwr_domain_suspend(), which * is called with caches disabled. It is possible to read a stale value * from DRAM in that function, because the L2 cache is not flushed * unless the cluster is entering CC6/CC7. */ clean_dcache_range((uint64_t)&tegra_percpu_data[cpu], sizeof(tegra_percpu_data[cpu])); /* Sanity check the requested state id */ switch (state_id) { case PSTATE_ID_CORE_IDLE: case PSTATE_ID_CORE_POWERDN: /* Core powerdown request */ req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id; req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id; break; default: ERROR("%s: unsupported state id (%d)\n", __func__, state_id); ret = PSCI_E_INVALID_PARAMS; break; } return ret; } int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) { const plat_local_state_t *pwr_domain_state; uint8_t stateid_afflvl0, stateid_afflvl2; uint32_t cpu = plat_my_core_pos(); const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); mce_cstate_info_t cstate_info = { 0 }; uint64_t smmu_ctx_base; uint32_t val; /* get the state ID */ pwr_domain_state = target_state->pwr_domain_state; stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] & TEGRA186_STATE_ID_MASK; stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] & TEGRA186_STATE_ID_MASK; if ((stateid_afflvl0 == PSTATE_ID_CORE_IDLE) || (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN)) { /* Enter CPU idle/powerdown */ val = (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ? (uint32_t)TEGRA_ARI_CORE_C6 : (uint32_t)TEGRA_ARI_CORE_C7; (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE, (uint64_t)val, tegra_percpu_data[cpu].wake_time, 0U); } else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { /* save SE registers */ se_regs[0] = mmio_read_32(TEGRA_SE0_BASE + SE_MUTEX_WATCHDOG_NS_LIMIT); se_regs[1] = mmio_read_32(TEGRA_RNG1_BASE + RNG_MUTEX_WATCHDOG_NS_LIMIT); se_regs[2] = mmio_read_32(TEGRA_PKA1_BASE + PKA_MUTEX_WATCHDOG_NS_LIMIT); /* save 'Secure Boot' Processor Feature Config Register */ val = mmio_read_32(TEGRA_MISC_BASE + MISCREG_PFCFG); mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SECURE_BOOTP_FCFG, val); /* save SMMU context to TZDRAM */ smmu_ctx_base = params_from_bl2->tzdram_base + tegra186_get_smmu_ctx_offset(); tegra_smmu_save_context((uintptr_t)smmu_ctx_base); /* Prepare for system suspend */ cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7; cstate_info.system = (uint32_t)TEGRA_ARI_SYSTEM_SC7; cstate_info.system_state_force = 1; cstate_info.update_wake_mask = 1; mce_update_cstate_info(&cstate_info); /* Loop until system suspend is allowed */ do { val = (uint32_t)mce_command_handler( (uint64_t)MCE_CMD_IS_SC7_ALLOWED, (uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U); } while (val == 0U); /* Instruct the MCE to enter system suspend state */ (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE, (uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U); /* set system suspend state for house-keeping */ tegra186_set_system_suspend_entry(); } else { ; /* do nothing */ } return PSCI_E_SUCCESS; } /******************************************************************************* * Helper function to check if this is the last ON CPU in the cluster ******************************************************************************/ static bool tegra_last_cpu_in_cluster(const plat_local_state_t *states, uint32_t ncpu) { plat_local_state_t target; bool last_on_cpu = true; uint32_t num_cpus = ncpu, pos = 0; do { target = states[pos]; if (target != PLAT_MAX_OFF_STATE) { last_on_cpu = false; } --num_cpus; pos++; } while (num_cpus != 0U); return last_on_cpu; } /******************************************************************************* * Helper function to get target power state for the cluster ******************************************************************************/ static plat_local_state_t tegra_get_afflvl1_pwr_state(const plat_local_state_t *states, uint32_t ncpu) { uint32_t core_pos = (uint32_t)read_mpidr() & (uint32_t)MPIDR_CPU_MASK; uint32_t cpu = plat_my_core_pos(); int32_t ret; plat_local_state_t target = states[core_pos]; mce_cstate_info_t cstate_info = { 0 }; /* CPU suspend */ if (target == PSTATE_ID_CORE_POWERDN) { /* Program default wake mask */ cstate_info.wake_mask = TEGRA186_CORE_WAKE_MASK; cstate_info.update_wake_mask = 1; mce_update_cstate_info(&cstate_info); /* Check if CCx state is allowed. */ ret = mce_command_handler((uint64_t)MCE_CMD_IS_CCX_ALLOWED, (uint64_t)TEGRA_ARI_CORE_C7, tegra_percpu_data[cpu].wake_time, 0U); if (ret == 0) { target = PSCI_LOCAL_STATE_RUN; } } /* CPU off */ if (target == PLAT_MAX_OFF_STATE) { /* Enable cluster powerdn from last CPU in the cluster */ if (tegra_last_cpu_in_cluster(states, ncpu)) { /* Enable CC7 state and turn off wake mask */ cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7; cstate_info.update_wake_mask = 1; mce_update_cstate_info(&cstate_info); /* Check if CCx state is allowed. */ ret = mce_command_handler((uint64_t)MCE_CMD_IS_CCX_ALLOWED, (uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U); if (ret == 0) { target = PSCI_LOCAL_STATE_RUN; } } else { /* Turn off wake_mask */ cstate_info.update_wake_mask = 1; mce_update_cstate_info(&cstate_info); target = PSCI_LOCAL_STATE_RUN; } } return target; } /******************************************************************************* * Platform handler to calculate the proper target power level at the * specified affinity level ******************************************************************************/ plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl, const plat_local_state_t *states, uint32_t ncpu) { plat_local_state_t target = PSCI_LOCAL_STATE_RUN; uint32_t cpu = plat_my_core_pos(); /* System Suspend */ if ((lvl == (uint32_t)MPIDR_AFFLVL2) && (states[cpu] == PSTATE_ID_SOC_POWERDN)) { target = PSTATE_ID_SOC_POWERDN; } /* CPU off, CPU suspend */ if (lvl == (uint32_t)MPIDR_AFFLVL1) { target = tegra_get_afflvl1_pwr_state(states, ncpu); } /* target cluster/system state */ return target; } int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state) { const plat_local_state_t *pwr_domain_state = target_state->pwr_domain_state; const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); uint8_t stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] & TEGRA186_STATE_ID_MASK; uint64_t val; if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { /* * The TZRAM loses power when we enter system suspend. To * allow graceful exit from system suspend, we need to copy * BL3-1 over to TZDRAM. */ val = params_from_bl2->tzdram_base + tegra186_get_cpu_reset_handler_size(); memcpy16((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE, (uintptr_t)BL31_END - (uintptr_t)BL31_BASE); } return PSCI_E_SUCCESS; } int32_t tegra_soc_pwr_domain_on(u_register_t mpidr) { int32_t ret = PSCI_E_SUCCESS; uint64_t target_cpu = mpidr & MPIDR_CPU_MASK; uint64_t target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >> MPIDR_AFFINITY_BITS; if (target_cluster > ((uint32_t)PLATFORM_CLUSTER_COUNT - 1U)) { ERROR("%s: unsupported CPU (0x%lx)\n", __func__, mpidr); ret = PSCI_E_NOT_PRESENT; } else { /* construct the target CPU # */ target_cpu |= (target_cluster << 2); (void)mce_command_handler((uint64_t)MCE_CMD_ONLINE_CORE, target_cpu, 0U, 0U); } return ret; } int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) { uint8_t stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL]; uint8_t stateid_afflvl0 = target_state->pwr_domain_state[MPIDR_AFFLVL0]; mce_cstate_info_t cstate_info = { 0 }; uint64_t impl, val; const plat_params_from_bl2_t *plat_params = bl31_get_plat_params(); impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; /* * Enable ECC and Parity Protection for Cortex-A57 CPUs (Tegra186 * A02p and beyond). */ if ((plat_params->l2_ecc_parity_prot_dis != 1) && (impl != DENVER_IMPL)) { val = read_l2ctlr_el1(); val |= CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT; write_l2ctlr_el1(val); } /* * Reset power state info for CPUs when onlining, we set * deepest power when offlining a core but that may not be * requested by non-secure sw which controls idle states. It * will re-init this info from non-secure software when the * core come online. */ if (stateid_afflvl0 == PLAT_MAX_OFF_STATE) { cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC1; cstate_info.update_wake_mask = 1; mce_update_cstate_info(&cstate_info); } /* * Check if we are exiting from deep sleep and restore SE * context if we are. */ if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { mmio_write_32(TEGRA_SE0_BASE + SE_MUTEX_WATCHDOG_NS_LIMIT, se_regs[0]); mmio_write_32(TEGRA_RNG1_BASE + RNG_MUTEX_WATCHDOG_NS_LIMIT, se_regs[1]); mmio_write_32(TEGRA_PKA1_BASE + PKA_MUTEX_WATCHDOG_NS_LIMIT, se_regs[2]); /* Init SMMU */ tegra_smmu_init(); /* * Reset power state info for the last core doing SC7 * entry and exit, we set deepest power state as CC7 * and SC7 for SC7 entry which may not be requested by * non-secure SW which controls idle states. */ cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7; cstate_info.system = (uint32_t)TEGRA_ARI_SYSTEM_SC1; cstate_info.update_wake_mask = 1; mce_update_cstate_info(&cstate_info); } return PSCI_E_SUCCESS; } int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) { uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & (uint64_t)MIDR_IMPL_MASK; (void)target_state; /* Disable Denver's DCO operations */ if (impl == DENVER_IMPL) { denver_disable_dco(); } /* Turn off CPU */ (void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE, (uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U); return PSCI_E_SUCCESS; } __dead2 void tegra_soc_prepare_system_off(void) { /* power off the entire system */ mce_enter_ccplex_state((uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF); wfi(); /* wait for the system to power down */ for (;;) { ; } } int32_t tegra_soc_prepare_system_reset(void) { mce_enter_ccplex_state((uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT); return PSCI_E_SUCCESS; } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/plat_secondary.c000066400000000000000000000042151355360272700250700ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #define MISCREG_AA64_RST_LOW 0x2004U #define MISCREG_AA64_RST_HIGH 0x2008U #define SCRATCH_SECURE_RSV1_SCRATCH_0 0x658U #define SCRATCH_SECURE_RSV1_SCRATCH_1 0x65CU #define CPU_RESET_MODE_AA64 1U extern void memcpy16(void *dest, const void *src, unsigned int length); /******************************************************************************* * Setup secondary CPU vectors ******************************************************************************/ void plat_secondary_setup(void) { uint32_t addr_low, addr_high; const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params(); uint64_t cpu_reset_handler_base, cpu_reset_handler_size; INFO("Setting up secondary CPU boot\n"); /* * The BL31 code resides in the TZSRAM which loses state * when we enter System Suspend. Copy the wakeup trampoline * code to TZDRAM to help us exit from System Suspend. */ cpu_reset_handler_base = tegra186_get_cpu_reset_handler_base(); cpu_reset_handler_size = tegra186_get_cpu_reset_handler_size(); (void)memcpy16((void *)(uintptr_t)params_from_bl2->tzdram_base, (const void *)(uintptr_t)cpu_reset_handler_base, cpu_reset_handler_size); /* TZDRAM base will be used as the "resume" address */ addr_low = (uint32_t)params_from_bl2->tzdram_base | CPU_RESET_MODE_AA64; addr_high = (uint32_t)((params_from_bl2->tzdram_base >> 32U) & 0x7ffU); /* write lower 32 bits first, then the upper 11 bits */ mmio_write_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_LOW, addr_low); mmio_write_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_HIGH, addr_high); /* save reset vector to be used during SYSTEM_SUSPEND exit */ mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_LO, addr_low); mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_HI, addr_high); /* update reset vector address to the CCPLEX */ (void)mce_update_reset_vector(); } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/plat_setup.c000066400000000000000000000221761355360272700242470ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * Tegra186 CPU numbers in cluster #0 ******************************************************************************* */ #define TEGRA186_CLUSTER0_CORE2 2U #define TEGRA186_CLUSTER0_CORE3 3U /******************************************************************************* * The Tegra power domain tree has a single system level power domain i.e. a * single root node. The first entry in the power domain descriptor specifies * the number of power domains at the highest power level. ******************************************************************************* */ static const uint8_t tegra_power_domain_tree_desc[] = { /* No of root nodes */ 1, /* No of clusters */ PLATFORM_CLUSTER_COUNT, /* No of CPU cores - cluster0 */ PLATFORM_MAX_CPUS_PER_CLUSTER, /* No of CPU cores - cluster1 */ PLATFORM_MAX_CPUS_PER_CLUSTER }; /******************************************************************************* * This function returns the Tegra default topology tree information. ******************************************************************************/ const uint8_t *plat_get_power_domain_tree_desc(void) { return tegra_power_domain_tree_desc; } /* * Table of regions to map using the MMU. */ static const mmap_region_t tegra_mmap[] = { MAP_REGION_FLAT(TEGRA_MISC_BASE, 0x10000U, /* 64KB */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_TSA_BASE, 0x20000U, /* 128KB */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_MC_STREAMID_BASE, 0x10000U, /* 64KB */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_MC_BASE, 0x10000U, /* 64KB */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_UARTA_BASE, 0x20000U, /* 128KB - UART A, B*/ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_UARTC_BASE, 0x20000U, /* 128KB - UART C, G */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_UARTD_BASE, 0x30000U, /* 192KB - UART D, E, F */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_FUSE_BASE, 0x10000U, /* 64KB */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_GICD_BASE, 0x20000U, /* 128KB */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_SE0_BASE, 0x10000U, /* 64KB */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_PKA1_BASE, 0x10000U, /* 64KB */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_RNG1_BASE, 0x10000U, /* 64KB */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_CAR_RESET_BASE, 0x10000U, /* 64KB */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_PMC_BASE, 0x40000U, /* 256KB */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_TMRUS_BASE, 0x1000U, /* 4KB */ MT_DEVICE | MT_RO | MT_SECURE), MAP_REGION_FLAT(TEGRA_SCRATCH_BASE, 0x10000U, /* 64KB */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_MMCRAB_BASE, 0x60000U, /* 384KB */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_ARM_ACTMON_CTR_BASE, 0x20000U, /* 128KB - ARM/Denver */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TEGRA_SMMU0_BASE, 0x1000000U, /* 64KB */ MT_DEVICE | MT_RW | MT_SECURE), {0} }; /******************************************************************************* * Set up the pagetables as per the platform memory map & initialize the MMU ******************************************************************************/ const mmap_region_t *plat_get_mmio_map(void) { /* MMIO space */ return tegra_mmap; } /******************************************************************************* * Handler to get the System Counter Frequency ******************************************************************************/ uint32_t plat_get_syscnt_freq2(void) { return 31250000; } /******************************************************************************* * Maximum supported UART controllers ******************************************************************************/ #define TEGRA186_MAX_UART_PORTS 7 /******************************************************************************* * This variable holds the UART port base addresses ******************************************************************************/ static uint32_t tegra186_uart_addresses[TEGRA186_MAX_UART_PORTS + 1] = { 0, /* undefined - treated as an error case */ TEGRA_UARTA_BASE, TEGRA_UARTB_BASE, TEGRA_UARTC_BASE, TEGRA_UARTD_BASE, TEGRA_UARTE_BASE, TEGRA_UARTF_BASE, TEGRA_UARTG_BASE, }; /******************************************************************************* * Retrieve the UART controller base to be used as the console ******************************************************************************/ uint32_t plat_get_console_from_id(int32_t id) { uint32_t ret; if (id > TEGRA186_MAX_UART_PORTS) { ret = 0; } else { ret = tegra186_uart_addresses[id]; } return ret; } /******************************************************************************* * Handler for early platform setup ******************************************************************************/ void plat_early_platform_setup(void) { uint64_t impl, val; const plat_params_from_bl2_t *plat_params = bl31_get_plat_params(); /* sanity check MCE firmware compatibility */ mce_verify_firmware_version(); impl = (read_midr() >> MIDR_IMPL_SHIFT) & (uint64_t)MIDR_IMPL_MASK; /* * Enable ECC and Parity Protection for Cortex-A57 CPUs (Tegra186 * A02p and beyond). */ if ((plat_params->l2_ecc_parity_prot_dis != 1) && (impl != (uint64_t)DENVER_IMPL)) { val = read_l2ctlr_el1(); val |= CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT; write_l2ctlr_el1(val); } } /* Secure IRQs for Tegra186 */ static const interrupt_prop_t tegra186_interrupt_props[] = { INTR_PROP_DESC(TEGRA186_TOP_WDT_IRQ, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE), INTR_PROP_DESC(TEGRA186_AON_WDT_IRQ, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE) }; /******************************************************************************* * Initialize the GIC and SGIs ******************************************************************************/ void plat_gic_setup(void) { tegra_gic_setup(tegra186_interrupt_props, ARRAY_SIZE(tegra186_interrupt_props)); tegra_gic_init(); /* * Initialize the FIQ handler only if the platform supports any * FIQ interrupt sources. */ tegra_fiq_handler_setup(); } /******************************************************************************* * Return pointer to the BL31 params from previous bootloader ******************************************************************************/ struct tegra_bl31_params *plat_get_bl31_params(void) { uint32_t val; val = mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PARAMS_ADDR); return (struct tegra_bl31_params *)(uintptr_t)val; } /******************************************************************************* * Return pointer to the BL31 platform params from previous bootloader ******************************************************************************/ plat_params_from_bl2_t *plat_get_bl31_plat_params(void) { uint32_t val; val = mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PLAT_PARAMS_ADDR); return (plat_params_from_bl2_t *)(uintptr_t)val; } /******************************************************************************* * This function implements a part of the critical interface between the psci * generic layer and the platform that allows the former to query the platform * to convert an MPIDR to a unique linear index. An error code (-1) is returned * in case the MPIDR is invalid. ******************************************************************************/ int32_t plat_core_pos_by_mpidr(u_register_t mpidr) { u_register_t cluster_id, cpu_id, pos; int32_t ret; cluster_id = (mpidr >> (u_register_t)MPIDR_AFF1_SHIFT) & (u_register_t)MPIDR_AFFLVL_MASK; cpu_id = (mpidr >> (u_register_t)MPIDR_AFF0_SHIFT) & (u_register_t)MPIDR_AFFLVL_MASK; /* * Validate cluster_id by checking whether it represents * one of the two clusters present on the platform. * Validate cpu_id by checking whether it represents a CPU in * one of the two clusters present on the platform. */ if ((cluster_id >= (u_register_t)PLATFORM_CLUSTER_COUNT) || (cpu_id >= (u_register_t)PLATFORM_MAX_CPUS_PER_CLUSTER)) { ret = PSCI_E_NOT_PRESENT; } else { /* calculate the core position */ pos = cpu_id + (cluster_id << 2U); /* check for non-existent CPUs */ if ((pos == TEGRA186_CLUSTER0_CORE2) || (pos == TEGRA186_CLUSTER0_CORE3)) { ret = PSCI_E_NOT_PRESENT; } else { ret = (int32_t)pos; } } return ret; } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/plat_sip_calls.c000066400000000000000000000117251355360272700250560ustar00rootroot00000000000000/* * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * Offset to read the ref_clk counter value ******************************************************************************/ #define REF_CLK_OFFSET 4ULL /******************************************************************************* * Tegra186 SiP SMCs ******************************************************************************/ #define TEGRA_SIP_GET_ACTMON_CLK_COUNTERS 0xC2FFFE02 #define TEGRA_SIP_MCE_CMD_ENTER_CSTATE 0xC2FFFF00 #define TEGRA_SIP_MCE_CMD_UPDATE_CSTATE_INFO 0xC2FFFF01 #define TEGRA_SIP_MCE_CMD_UPDATE_CROSSOVER_TIME 0xC2FFFF02 #define TEGRA_SIP_MCE_CMD_READ_CSTATE_STATS 0xC2FFFF03 #define TEGRA_SIP_MCE_CMD_WRITE_CSTATE_STATS 0xC2FFFF04 #define TEGRA_SIP_MCE_CMD_IS_SC7_ALLOWED 0xC2FFFF05 #define TEGRA_SIP_MCE_CMD_CC3_CTRL 0xC2FFFF07 #define TEGRA_SIP_MCE_CMD_ECHO_DATA 0xC2FFFF08 #define TEGRA_SIP_MCE_CMD_READ_VERSIONS 0xC2FFFF09 #define TEGRA_SIP_MCE_CMD_ENUM_FEATURES 0xC2FFFF0A #define TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE_TRBITS 0xC2FFFF0B #define TEGRA_SIP_MCE_CMD_ENUM_READ_MCA 0xC2FFFF0C #define TEGRA_SIP_MCE_CMD_ENUM_WRITE_MCA 0xC2FFFF0D #define TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE 0xC2FFFF0E #define TEGRA_SIP_MCE_CMD_ROC_CLEAN_CACHE 0xC2FFFF0F #define TEGRA_SIP_MCE_CMD_ENABLE_LATIC 0xC2FFFF10 #define TEGRA_SIP_MCE_CMD_UNCORE_PERFMON_REQ 0xC2FFFF11 #define TEGRA_SIP_MCE_CMD_MISC_CCPLEX 0xC2FFFF12 /******************************************************************************* * This function is responsible for handling all T186 SiP calls ******************************************************************************/ int32_t plat_sip_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, const void *cookie, void *handle, uint64_t flags) { int32_t mce_ret, ret = 0; uint32_t impl, cpu; uint32_t base, core_clk_ctr, ref_clk_ctr; uint32_t local_smc_fid = smc_fid; uint64_t local_x1 = x1, local_x2 = x2, local_x3 = x3; (void)x4; (void)cookie; (void)flags; if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) { /* 32-bit function, clear top parameter bits */ local_x1 = (uint32_t)x1; local_x2 = (uint32_t)x2; local_x3 = (uint32_t)x3; } /* * Convert SMC FID to SMC64, to support SMC32/SMC64 configurations */ local_smc_fid |= (SMC_64 << FUNCID_CC_SHIFT); switch (local_smc_fid) { /* * Micro Coded Engine (MCE) commands reside in the 0x82FFFF00 - * 0x82FFFFFF SiP SMC space */ case TEGRA_SIP_MCE_CMD_ENTER_CSTATE: case TEGRA_SIP_MCE_CMD_UPDATE_CSTATE_INFO: case TEGRA_SIP_MCE_CMD_UPDATE_CROSSOVER_TIME: case TEGRA_SIP_MCE_CMD_READ_CSTATE_STATS: case TEGRA_SIP_MCE_CMD_WRITE_CSTATE_STATS: case TEGRA_SIP_MCE_CMD_IS_SC7_ALLOWED: case TEGRA_SIP_MCE_CMD_CC3_CTRL: case TEGRA_SIP_MCE_CMD_ECHO_DATA: case TEGRA_SIP_MCE_CMD_READ_VERSIONS: case TEGRA_SIP_MCE_CMD_ENUM_FEATURES: case TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE_TRBITS: case TEGRA_SIP_MCE_CMD_ENUM_READ_MCA: case TEGRA_SIP_MCE_CMD_ENUM_WRITE_MCA: case TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE: case TEGRA_SIP_MCE_CMD_ROC_CLEAN_CACHE: case TEGRA_SIP_MCE_CMD_ENABLE_LATIC: case TEGRA_SIP_MCE_CMD_UNCORE_PERFMON_REQ: case TEGRA_SIP_MCE_CMD_MISC_CCPLEX: /* clean up the high bits */ local_smc_fid &= MCE_CMD_MASK; /* execute the command and store the result */ mce_ret = mce_command_handler(local_smc_fid, local_x1, local_x2, local_x3); write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X0, (uint64_t)(mce_ret)); break; /* * This function ID reads the Activity monitor's core/ref clock * counter values for a core/cluster. * * x1 = MPIDR of the target core * x2 = MIDR of the target core */ case TEGRA_SIP_GET_ACTMON_CLK_COUNTERS: cpu = (uint32_t)x1 & MPIDR_CPU_MASK; impl = ((uint32_t)x2 >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; /* sanity check target CPU number */ if (cpu > (uint32_t)PLATFORM_MAX_CPUS_PER_CLUSTER) { ret = -EINVAL; } else { /* get the base address for the current CPU */ base = (impl == DENVER_IMPL) ? TEGRA_DENVER_ACTMON_CTR_BASE : TEGRA_ARM_ACTMON_CTR_BASE; /* read the clock counter values */ core_clk_ctr = mmio_read_32(base + (8ULL * cpu)); ref_clk_ctr = mmio_read_32(base + (8ULL * cpu) + REF_CLK_OFFSET); /* return the counter values as two different parameters */ write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X1, (core_clk_ctr)); write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X2, (ref_clk_ctr)); } break; default: ret = -ENOTSUP; break; } return ret; } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/plat_smmu.c000066400000000000000000000144711355360272700240670ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #define MAX_NUM_SMMU_DEVICES U(1) /******************************************************************************* * Array to hold SMMU context for Tegra186 ******************************************************************************/ static __attribute__((aligned(16))) smmu_regs_t tegra186_smmu_context[] = { _START_OF_TABLE_, mc_make_sid_security_cfg(SCEW), mc_make_sid_security_cfg(AFIR), mc_make_sid_security_cfg(NVDISPLAYR1), mc_make_sid_security_cfg(XUSB_DEVR), mc_make_sid_security_cfg(VICSRD1), mc_make_sid_security_cfg(NVENCSWR), mc_make_sid_security_cfg(TSECSRDB), mc_make_sid_security_cfg(AXISW), mc_make_sid_security_cfg(SDMMCWAB), mc_make_sid_security_cfg(AONDMAW), mc_make_sid_security_cfg(GPUSWR2), mc_make_sid_security_cfg(SATAW), mc_make_sid_security_cfg(UFSHCW), mc_make_sid_security_cfg(AFIW), mc_make_sid_security_cfg(SDMMCR), mc_make_sid_security_cfg(SCEDMAW), mc_make_sid_security_cfg(UFSHCR), mc_make_sid_security_cfg(SDMMCWAA), mc_make_sid_security_cfg(APEDMAW), mc_make_sid_security_cfg(SESWR), mc_make_sid_security_cfg(MPCORER), mc_make_sid_security_cfg(PTCR), mc_make_sid_security_cfg(BPMPW), mc_make_sid_security_cfg(ETRW), mc_make_sid_security_cfg(GPUSRD), mc_make_sid_security_cfg(VICSWR), mc_make_sid_security_cfg(SCEDMAR), mc_make_sid_security_cfg(HDAW), mc_make_sid_security_cfg(ISPWA), mc_make_sid_security_cfg(EQOSW), mc_make_sid_security_cfg(XUSB_HOSTW), mc_make_sid_security_cfg(TSECSWR), mc_make_sid_security_cfg(SDMMCRAA), mc_make_sid_security_cfg(APER), mc_make_sid_security_cfg(VIW), mc_make_sid_security_cfg(APEW), mc_make_sid_security_cfg(AXISR), mc_make_sid_security_cfg(SDMMCW), mc_make_sid_security_cfg(BPMPDMAW), mc_make_sid_security_cfg(ISPRA), mc_make_sid_security_cfg(NVDECSWR), mc_make_sid_security_cfg(XUSB_DEVW), mc_make_sid_security_cfg(NVDECSRD), mc_make_sid_security_cfg(MPCOREW), mc_make_sid_security_cfg(NVDISPLAYR), mc_make_sid_security_cfg(BPMPDMAR), mc_make_sid_security_cfg(NVJPGSWR), mc_make_sid_security_cfg(NVDECSRD1), mc_make_sid_security_cfg(TSECSRD), mc_make_sid_security_cfg(NVJPGSRD), mc_make_sid_security_cfg(SDMMCWA), mc_make_sid_security_cfg(SCER), mc_make_sid_security_cfg(XUSB_HOSTR), mc_make_sid_security_cfg(VICSRD), mc_make_sid_security_cfg(AONDMAR), mc_make_sid_security_cfg(AONW), mc_make_sid_security_cfg(SDMMCRA), mc_make_sid_security_cfg(HOST1XDMAR), mc_make_sid_security_cfg(EQOSR), mc_make_sid_security_cfg(SATAR), mc_make_sid_security_cfg(BPMPR), mc_make_sid_security_cfg(HDAR), mc_make_sid_security_cfg(SDMMCRAB), mc_make_sid_security_cfg(ETRR), mc_make_sid_security_cfg(AONR), mc_make_sid_security_cfg(APEDMAR), mc_make_sid_security_cfg(SESRD), mc_make_sid_security_cfg(NVENCSRD), mc_make_sid_security_cfg(GPUSWR), mc_make_sid_security_cfg(TSECSWRB), mc_make_sid_security_cfg(ISPWB), mc_make_sid_security_cfg(GPUSRD2), mc_make_sid_override_cfg(APER), mc_make_sid_override_cfg(VICSRD), mc_make_sid_override_cfg(NVENCSRD), mc_make_sid_override_cfg(NVJPGSWR), mc_make_sid_override_cfg(AONW), mc_make_sid_override_cfg(BPMPR), mc_make_sid_override_cfg(BPMPW), mc_make_sid_override_cfg(HDAW), mc_make_sid_override_cfg(NVDISPLAYR1), mc_make_sid_override_cfg(APEDMAR), mc_make_sid_override_cfg(AFIR), mc_make_sid_override_cfg(AXISR), mc_make_sid_override_cfg(VICSRD1), mc_make_sid_override_cfg(TSECSRD), mc_make_sid_override_cfg(BPMPDMAW), mc_make_sid_override_cfg(MPCOREW), mc_make_sid_override_cfg(XUSB_HOSTR), mc_make_sid_override_cfg(GPUSWR), mc_make_sid_override_cfg(XUSB_DEVR), mc_make_sid_override_cfg(UFSHCW), mc_make_sid_override_cfg(XUSB_HOSTW), mc_make_sid_override_cfg(SDMMCWAB), mc_make_sid_override_cfg(SATAW), mc_make_sid_override_cfg(SCEDMAR), mc_make_sid_override_cfg(HOST1XDMAR), mc_make_sid_override_cfg(SDMMCWA), mc_make_sid_override_cfg(APEDMAW), mc_make_sid_override_cfg(SESWR), mc_make_sid_override_cfg(AXISW), mc_make_sid_override_cfg(AONDMAW), mc_make_sid_override_cfg(TSECSWRB), mc_make_sid_override_cfg(MPCORER), mc_make_sid_override_cfg(ISPWB), mc_make_sid_override_cfg(AONR), mc_make_sid_override_cfg(BPMPDMAR), mc_make_sid_override_cfg(HDAR), mc_make_sid_override_cfg(SDMMCRA), mc_make_sid_override_cfg(ETRW), mc_make_sid_override_cfg(GPUSWR2), mc_make_sid_override_cfg(EQOSR), mc_make_sid_override_cfg(TSECSWR), mc_make_sid_override_cfg(ETRR), mc_make_sid_override_cfg(NVDECSRD), mc_make_sid_override_cfg(TSECSRDB), mc_make_sid_override_cfg(SDMMCRAA), mc_make_sid_override_cfg(NVDECSRD1), mc_make_sid_override_cfg(SDMMCR), mc_make_sid_override_cfg(NVJPGSRD), mc_make_sid_override_cfg(SCEDMAW), mc_make_sid_override_cfg(SDMMCWAA), mc_make_sid_override_cfg(APEW), mc_make_sid_override_cfg(AONDMAR), mc_make_sid_override_cfg(PTCR), mc_make_sid_override_cfg(SCER), mc_make_sid_override_cfg(ISPRA), mc_make_sid_override_cfg(ISPWA), mc_make_sid_override_cfg(VICSWR), mc_make_sid_override_cfg(SESRD), mc_make_sid_override_cfg(SDMMCW), mc_make_sid_override_cfg(SDMMCRAB), mc_make_sid_override_cfg(EQOSW), mc_make_sid_override_cfg(GPUSRD2), mc_make_sid_override_cfg(SCEW), mc_make_sid_override_cfg(GPUSRD), mc_make_sid_override_cfg(NVDECSWR), mc_make_sid_override_cfg(XUSB_DEVW), mc_make_sid_override_cfg(SATAR), mc_make_sid_override_cfg(NVDISPLAYR), mc_make_sid_override_cfg(VIW), mc_make_sid_override_cfg(UFSHCR), mc_make_sid_override_cfg(NVENCSWR), mc_make_sid_override_cfg(AFIW), smmu_make_cfg(TEGRA_SMMU0_BASE), smmu_bypass_cfg, /* TBU settings */ _END_OF_TABLE_, }; /******************************************************************************* * Handler to return the pointer to the SMMU's context struct ******************************************************************************/ smmu_regs_t *plat_get_smmu_ctx(void) { /* index of _END_OF_TABLE_ */ tegra186_smmu_context[0].val = (uint32_t)(ARRAY_SIZE(tegra186_smmu_context)) - 1U; return tegra186_smmu_context; } /******************************************************************************* * Handler to return the support SMMU devices number ******************************************************************************/ uint32_t plat_get_num_smmu_devices(void) { return MAX_NUM_SMMU_DEVICES; } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/plat_trampoline.S000066400000000000000000000067471355360272700252470ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #define TEGRA186_STATE_SYSTEM_SUSPEND 0x5C7 #define TEGRA186_STATE_SYSTEM_RESUME 0x600D #define TEGRA186_SMMU_CTX_SIZE 0x420 .globl tegra186_cpu_reset_handler /* CPU reset handler routine */ func tegra186_cpu_reset_handler _align=4 /* check if we are exiting system suspend state */ adr x0, __tegra186_system_suspend_state ldr x1, [x0] mov x2, #TEGRA186_STATE_SYSTEM_SUSPEND lsl x2, x2, #16 add x2, x2, #TEGRA186_STATE_SYSTEM_SUSPEND cmp x1, x2 bne boot_cpu /* set system resume state */ mov x1, #TEGRA186_STATE_SYSTEM_RESUME lsl x1, x1, #16 mov x2, #TEGRA186_STATE_SYSTEM_RESUME add x1, x1, x2 str x1, [x0] dsb sy /* prepare to relocate to TZSRAM */ mov x0, #BL31_BASE adr x1, __tegra186_cpu_reset_handler_end adr x2, __tegra186_cpu_reset_handler_data ldr x2, [x2, #8] /* memcpy16 */ m_loop16: cmp x2, #16 b.lt m_loop1 ldp x3, x4, [x1], #16 stp x3, x4, [x0], #16 sub x2, x2, #16 b m_loop16 /* copy byte per byte */ m_loop1: cbz x2, boot_cpu ldrb w3, [x1], #1 strb w3, [x0], #1 subs x2, x2, #1 b.ne m_loop1 boot_cpu: adr x0, __tegra186_cpu_reset_handler_data ldr x0, [x0] br x0 endfunc tegra186_cpu_reset_handler /* * Tegra186 reset data (offset 0x0 - 0x430) * * 0x000: secure world's entrypoint * 0x008: BL31 size (RO + RW) * 0x00C: SMMU context start * 0x42C: SMMU context end */ .align 4 .type __tegra186_cpu_reset_handler_data, %object .globl __tegra186_cpu_reset_handler_data __tegra186_cpu_reset_handler_data: .quad tegra_secure_entrypoint .quad __BL31_END__ - BL31_BASE .globl __tegra186_system_suspend_state __tegra186_system_suspend_state: .quad 0 .align 4 .globl __tegra186_smmu_context __tegra186_smmu_context: .rept TEGRA186_SMMU_CTX_SIZE .quad 0 .endr .size __tegra186_cpu_reset_handler_data, \ . - __tegra186_cpu_reset_handler_data .align 4 .globl __tegra186_cpu_reset_handler_end __tegra186_cpu_reset_handler_end: .globl tegra186_get_cpu_reset_handler_size .globl tegra186_get_cpu_reset_handler_base .globl tegra186_get_smmu_ctx_offset .globl tegra186_set_system_suspend_entry /* return size of the CPU reset handler */ func tegra186_get_cpu_reset_handler_size adr x0, __tegra186_cpu_reset_handler_end adr x1, tegra186_cpu_reset_handler sub x0, x0, x1 ret endfunc tegra186_get_cpu_reset_handler_size /* return the start address of the CPU reset handler */ func tegra186_get_cpu_reset_handler_base adr x0, tegra186_cpu_reset_handler ret endfunc tegra186_get_cpu_reset_handler_base /* return the size of the SMMU context */ func tegra186_get_smmu_ctx_offset adr x0, __tegra186_smmu_context adr x1, tegra186_cpu_reset_handler sub x0, x0, x1 ret endfunc tegra186_get_smmu_ctx_offset /* set system suspend state before SC7 entry */ func tegra186_set_system_suspend_entry mov x0, #TEGRA_MC_BASE mov x3, #MC_SECURITY_CFG3_0 ldr w1, [x0, x3] lsl x1, x1, #32 mov x3, #MC_SECURITY_CFG0_0 ldr w2, [x0, x3] orr x3, x1, x2 /* TZDRAM base */ adr x0, __tegra186_system_suspend_state adr x1, tegra186_cpu_reset_handler sub x2, x0, x1 /* offset in TZDRAM */ mov x0, #TEGRA186_STATE_SYSTEM_SUSPEND lsl x0, x0, #16 add x0, x0, #TEGRA186_STATE_SYSTEM_SUSPEND str x0, [x3, x2] /* set value in TZDRAM */ dsb sy ret endfunc tegra186_set_system_suspend_entry trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t186/platform_t186.mk000066400000000000000000000034731355360272700246610ustar00rootroot00000000000000# # Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # platform configs ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS := 1 $(eval $(call add_define,ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS)) ENABLE_CHIP_VERIFICATION_HARNESS := 0 $(eval $(call add_define,ENABLE_CHIP_VERIFICATION_HARNESS)) RESET_TO_BL31 := 1 PROGRAMMABLE_RESET_ADDRESS := 1 COLD_BOOT_SINGLE_CPU := 1 # platform settings TZDRAM_BASE := 0x30000000 $(eval $(call add_define,TZDRAM_BASE)) PLATFORM_CLUSTER_COUNT := 2 $(eval $(call add_define,PLATFORM_CLUSTER_COUNT)) PLATFORM_MAX_CPUS_PER_CLUSTER := 4 $(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER)) MAX_XLAT_TABLES := 24 $(eval $(call add_define,MAX_XLAT_TABLES)) MAX_MMAP_REGIONS := 25 $(eval $(call add_define,MAX_MMAP_REGIONS)) # platform files PLAT_INCLUDES += -I${SOC_DIR}/drivers/include BL31_SOURCES += drivers/ti/uart/aarch64/16550_console.S \ lib/cpus/aarch64/denver.S \ lib/cpus/aarch64/cortex_a57.S \ ${COMMON_DIR}/drivers/gpcdma/gpcdma.c \ ${COMMON_DIR}/drivers/memctrl/memctrl_v2.c \ ${COMMON_DIR}/drivers/smmu/smmu.c \ ${SOC_DIR}/drivers/mce/mce.c \ ${SOC_DIR}/drivers/mce/ari.c \ ${SOC_DIR}/drivers/mce/nvg.c \ ${SOC_DIR}/drivers/mce/aarch64/nvg_helpers.S \ ${SOC_DIR}/plat_memctrl.c \ ${SOC_DIR}/plat_psci_handlers.c \ ${SOC_DIR}/plat_setup.c \ ${SOC_DIR}/plat_secondary.c \ ${SOC_DIR}/plat_sip_calls.c \ ${SOC_DIR}/plat_smmu.c \ ${SOC_DIR}/plat_trampoline.S # Enable workarounds for selected Cortex-A57 erratas. A57_DISABLE_NON_TEMPORAL_HINT := 1 ERRATA_A57_806969 := 1 ERRATA_A57_813419 := 1 ERRATA_A57_813420 := 1 ERRATA_A57_826974 := 1 ERRATA_A57_826977 := 1 ERRATA_A57_828024 := 1 ERRATA_A57_829520 := 1 ERRATA_A57_833471 := 1 trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t210/000077500000000000000000000000001355360272700216775ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t210/drivers/000077500000000000000000000000001355360272700233555ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t210/drivers/se/000077500000000000000000000000001355360272700237645ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t210/drivers/se/se_private.h000066400000000000000000000473231355360272700263070ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SE_PRIVATE_H #define SE_PRIVATE_H #include #include /* * PMC registers */ /* Secure scratch registers */ #define PMC_SECURE_SCRATCH4_OFFSET 0xC0U #define PMC_SECURE_SCRATCH5_OFFSET 0xC4U #define PMC_SECURE_SCRATCH6_OFFSET 0x224U #define PMC_SECURE_SCRATCH7_OFFSET 0x228U #define PMC_SECURE_SCRATCH116_OFFSET 0xB28U #define PMC_SECURE_SCRATCH117_OFFSET 0xB2CU #define PMC_SECURE_SCRATCH120_OFFSET 0xB38U #define PMC_SECURE_SCRATCH121_OFFSET 0xB3CU #define PMC_SECURE_SCRATCH122_OFFSET 0xB40U #define PMC_SECURE_SCRATCH123_OFFSET 0xB44U /* * AHB arbitration memory write queue */ #define ARAHB_MEM_WRQUE_MST_ID_OFFSET 0xFCU #define ARAHB_MST_ID_SE2_MASK (0x1U << 13) #define ARAHB_MST_ID_SE_MASK (0x1U << 14) /** * SE registers */ #define TEGRA_SE_AES_KEYSLOT_COUNT 16 #define SE_MAX_LAST_BLOCK_SIZE 0xFFFFF /* SE Status register */ #define SE_STATUS_OFFSET 0x800U #define SE_STATUS_SHIFT 0 #define SE_STATUS_IDLE \ ((0U) << SE_STATUS_SHIFT) #define SE_STATUS_BUSY \ ((1U) << SE_STATUS_SHIFT) #define SE_STATUS(x) \ ((x) & ((0x3U) << SE_STATUS_SHIFT)) #define SE_MEM_INTERFACE_SHIFT 2 #define SE_MEM_INTERFACE_IDLE 0 #define SE_MEM_INTERFACE_BUSY 1 #define SE_MEM_INTERFACE(x) ((x) << SE_STATUS_SHIFT) /* SE register definitions */ #define SE_SECURITY_REG_OFFSET 0x0 #define SE_SECURITY_TZ_LOCK_SOFT_SHIFT 5 #define SE_SECURE 0x0 #define SE_SECURITY_TZ_LOCK_SOFT(x) ((x) << SE_SECURITY_TZ_LOCK_SOFT_SHIFT) #define SE_SEC_ENG_DIS_SHIFT 1 #define SE_DISABLE_FALSE 0 #define SE_DISABLE_TRUE 1 #define SE_SEC_ENG_DISABLE(x)((x) << SE_SEC_ENG_DIS_SHIFT) /* SE config register */ #define SE_CONFIG_REG_OFFSET 0x14U #define SE_CONFIG_ENC_ALG_SHIFT 12 #define SE_CONFIG_ENC_ALG_AES_ENC \ ((1U) << SE_CONFIG_ENC_ALG_SHIFT) #define SE_CONFIG_ENC_ALG_RNG \ ((2U) << SE_CONFIG_ENC_ALG_SHIFT) #define SE_CONFIG_ENC_ALG_SHA \ ((3U) << SE_CONFIG_ENC_ALG_SHIFT) #define SE_CONFIG_ENC_ALG_RSA \ ((4U) << SE_CONFIG_ENC_ALG_SHIFT) #define SE_CONFIG_ENC_ALG_NOP \ ((0U) << SE_CONFIG_ENC_ALG_SHIFT) #define SE_CONFIG_ENC_ALG(x) \ ((x) & ((0xFU) << SE_CONFIG_ENC_ALG_SHIFT)) #define SE_CONFIG_DEC_ALG_SHIFT 8 #define SE_CONFIG_DEC_ALG_AES \ ((1U) << SE_CONFIG_DEC_ALG_SHIFT) #define SE_CONFIG_DEC_ALG_NOP \ ((0U) << SE_CONFIG_DEC_ALG_SHIFT) #define SE_CONFIG_DEC_ALG(x) \ ((x) & ((0xFU) << SE_CONFIG_DEC_ALG_SHIFT)) #define SE_CONFIG_DST_SHIFT 2 #define SE_CONFIG_DST_MEMORY \ ((0U) << SE_CONFIG_DST_SHIFT) #define SE_CONFIG_DST_HASHREG \ ((1U) << SE_CONFIG_DST_SHIFT) #define SE_CONFIG_DST_KEYTAB \ ((2U) << SE_CONFIG_DST_SHIFT) #define SE_CONFIG_DST_SRK \ ((3U) << SE_CONFIG_DST_SHIFT) #define SE_CONFIG_DST_RSAREG \ ((4U) << SE_CONFIG_DST_SHIFT) #define SE_CONFIG_DST(x) \ ((x) & ((0x7U) << SE_CONFIG_DST_SHIFT)) #define SE_CONFIG_ENC_MODE_SHIFT 24 #define SE_CONFIG_ENC_MODE_KEY128 \ ((0UL) << SE_CONFIG_ENC_MODE_SHIFT) #define SE_CONFIG_ENC_MODE_KEY192 \ ((1UL) << SE_CONFIG_ENC_MODE_SHIFT) #define SE_CONFIG_ENC_MODE_KEY256 \ ((2UL) << SE_CONFIG_ENC_MODE_SHIFT) #define SE_CONFIG_ENC_MODE_SHA1 \ ((0UL) << SE_CONFIG_ENC_MODE_SHIFT) #define SE_CONFIG_ENC_MODE_SHA224 \ ((4UL) << SE_CONFIG_ENC_MODE_SHIFT) #define SE_CONFIG_ENC_MODE_SHA256 \ ((5UL) << SE_CONFIG_ENC_MODE_SHIFT) #define SE_CONFIG_ENC_MODE_SHA384 \ ((6UL) << SE_CONFIG_ENC_MODE_SHIFT) #define SE_CONFIG_ENC_MODE_SHA512 \ ((7UL) << SE_CONFIG_ENC_MODE_SHIFT) #define SE_CONFIG_ENC_MODE(x)\ ((x) & ((0xFFUL) << SE_CONFIG_ENC_MODE_SHIFT)) #define SE_CONFIG_DEC_MODE_SHIFT 16 #define SE_CONFIG_DEC_MODE_KEY128 \ ((0UL) << SE_CONFIG_DEC_MODE_SHIFT) #define SE_CONFIG_DEC_MODE_KEY192 \ ((1UL) << SE_CONFIG_DEC_MODE_SHIFT) #define SE_CONFIG_DEC_MODE_KEY256 \ ((2UL) << SE_CONFIG_DEC_MODE_SHIFT) #define SE_CONFIG_DEC_MODE_SHA1 \ ((0UL) << SE_CONFIG_DEC_MODE_SHIFT) #define SE_CONFIG_DEC_MODE_SHA224 \ ((4UL) << SE_CONFIG_DEC_MODE_SHIFT) #define SE_CONFIG_DEC_MODE_SHA256 \ ((5UL) << SE_CONFIG_DEC_MODE_SHIFT) #define SE_CONFIG_DEC_MODE_SHA384 \ ((6UL) << SE_CONFIG_DEC_MODE_SHIFT) #define SE_CONFIG_DEC_MODE_SHA512 \ ((7UL) << SE_CONFIG_DEC_MODE_SHIFT) #define SE_CONFIG_DEC_MODE(x)\ ((x) & ((0xFFUL) << SE_CONFIG_DEC_MODE_SHIFT)) /* DRBG random number generator config */ #define SE_RNG_CONFIG_REG_OFFSET 0x340 #define DRBG_MODE_SHIFT 0 #define DRBG_MODE_NORMAL \ ((0U) << DRBG_MODE_SHIFT) #define DRBG_MODE_FORCE_INSTANTION \ ((1U) << DRBG_MODE_SHIFT) #define DRBG_MODE_FORCE_RESEED \ ((2U) << DRBG_MODE_SHIFT) #define SE_RNG_CONFIG_MODE(x) \ ((x) & ((0x3U) << DRBG_MODE_SHIFT)) #define DRBG_SRC_SHIFT 2 #define DRBG_SRC_NONE \ ((0U) << DRBG_SRC_SHIFT) #define DRBG_SRC_ENTROPY \ ((1U) << DRBG_SRC_SHIFT) #define DRBG_SRC_LFSR \ ((2U) << DRBG_SRC_SHIFT) #define SE_RNG_SRC_CONFIG_MODE(x) \ ((x) & ((0x3U) << DRBG_SRC_SHIFT)) /* DRBG random number generator entropy config */ #define SE_RNG_SRC_CONFIG_REG_OFFSET 0x344U #define DRBG_RO_ENT_SRC_SHIFT 1 #define DRBG_RO_ENT_SRC_ENABLE \ ((1U) << DRBG_RO_ENT_SRC_SHIFT) #define DRBG_RO_ENT_SRC_DISABLE \ ((0U) << DRBG_RO_ENT_SRC_SHIFT) #define SE_RNG_SRC_CONFIG_RO_ENT_SRC(x) \ ((x) & ((0x1U) << DRBG_RO_ENT_SRC_SHIFT)) #define DRBG_RO_ENT_SRC_LOCK_SHIFT 0 #define DRBG_RO_ENT_SRC_LOCK_ENABLE \ ((1U) << DRBG_RO_ENT_SRC_LOCK_SHIFT) #define DRBG_RO_ENT_SRC_LOCK_DISABLE \ ((0U) << DRBG_RO_ENT_SRC_LOCK_SHIFT) #define SE_RNG_SRC_CONFIG_RO_ENT_SRC_LOCK(x) \ ((x) & ((0x1U) << DRBG_RO_ENT_SRC_LOCK_SHIFT)) #define DRBG_RO_ENT_IGNORE_MEM_SHIFT 12 #define DRBG_RO_ENT_IGNORE_MEM_ENABLE \ ((1U) << DRBG_RO_ENT_IGNORE_MEM_SHIFT) #define DRBG_RO_ENT_IGNORE_MEM_DISABLE \ ((0U) << DRBG_RO_ENT_IGNORE_MEM_SHIFT) #define SE_RNG_SRC_CONFIG_RO_ENT_IGNORE_MEM(x) \ ((x) & ((0x1U) << DRBG_RO_ENT_IGNORE_MEM_SHIFT)) #define SE_RNG_RESEED_INTERVAL_REG_OFFSET 0x348 /* SE CRYPTO */ #define SE_CRYPTO_REG_OFFSET 0x304 #define SE_CRYPTO_HASH_SHIFT 0 #define SE_CRYPTO_HASH_DISABLE \ ((0U) << SE_CRYPTO_HASH_SHIFT) #define SE_CRYPTO_HASH_ENABLE \ ((1U) << SE_CRYPTO_HASH_SHIFT) #define SE_CRYPTO_XOR_POS_SHIFT 1 #define SE_CRYPTO_XOR_BYPASS \ ((0U) << SE_CRYPTO_XOR_POS_SHIFT) #define SE_CRYPTO_XOR_TOP \ ((2U) << SE_CRYPTO_XOR_POS_SHIFT) #define SE_CRYPTO_XOR_BOTTOM \ ((3U) << SE_CRYPTO_XOR_POS_SHIFT) #define SE_CRYPTO_INPUT_SEL_SHIFT 3 #define SE_CRYPTO_INPUT_AHB \ ((0U) << SE_CRYPTO_INPUT_SEL_SHIFT) #define SE_CRYPTO_INPUT_RANDOM \ ((1U) << SE_CRYPTO_INPUT_SEL_SHIFT) #define SE_CRYPTO_INPUT_AESOUT \ ((2U) << SE_CRYPTO_INPUT_SEL_SHIFT) #define SE_CRYPTO_INPUT_LNR_CTR \ ((3U) << SE_CRYPTO_INPUT_SEL_SHIFT) #define SE_CRYPTO_VCTRAM_SEL_SHIFT 5 #define SE_CRYPTO_VCTRAM_AHB \ ((0U) << SE_CRYPTO_VCTRAM_SEL_SHIFT) #define SE_CRYPTO_VCTRAM_AESOUT \ ((2U) << SE_CRYPTO_VCTRAM_SEL_SHIFT) #define SE_CRYPTO_VCTRAM_PREVAHB \ ((3U) << SE_CRYPTO_VCTRAM_SEL_SHIFT) #define SE_CRYPTO_IV_SEL_SHIFT 7 #define SE_CRYPTO_IV_ORIGINAL \ ((0U) << SE_CRYPTO_IV_SEL_SHIFT) #define SE_CRYPTO_IV_UPDATED \ ((1U) << SE_CRYPTO_IV_SEL_SHIFT) #define SE_CRYPTO_CORE_SEL_SHIFT 8 #define SE_CRYPTO_CORE_DECRYPT \ ((0U) << SE_CRYPTO_CORE_SEL_SHIFT) #define SE_CRYPTO_CORE_ENCRYPT \ ((1U) << SE_CRYPTO_CORE_SEL_SHIFT) #define SE_CRYPTO_KEY_INDEX_SHIFT 24 #define SE_CRYPTO_KEY_INDEX(x) (x << SE_CRYPTO_KEY_INDEX_SHIFT) #define SE_CRYPTO_MEMIF_AHB \ ((0U) << SE_CRYPTO_MEMIF_SHIFT) #define SE_CRYPTO_MEMIF_MCCIF \ ((1U) << SE_CRYPTO_MEMIF_SHIFT) #define SE_CRYPTO_MEMIF_SHIFT 31 /* KEY TABLE */ #define SE_KEYTABLE_REG_OFFSET 0x31C /* KEYIV PKT - key slot */ #define SE_KEYTABLE_SLOT_SHIFT 4 #define SE_KEYTABLE_SLOT(x) (x << SE_KEYTABLE_SLOT_SHIFT) /* KEYIV PKT - KEYIV select */ #define SE_KEYIV_PKT_KEYIV_SEL_SHIFT 3 #define SE_CRYPTO_KEYIV_KEY \ ((0U) << SE_KEYIV_PKT_KEYIV_SEL_SHIFT) #define SE_CRYPTO_KEYIV_IVS \ ((1U) << SE_KEYIV_PKT_KEYIV_SEL_SHIFT) /* KEYIV PKT - IV select */ #define SE_KEYIV_PKT_IV_SEL_SHIFT 2 #define SE_CRYPTO_KEYIV_IVS_OIV \ ((0U) << SE_KEYIV_PKT_IV_SEL_SHIFT) #define SE_CRYPTO_KEYIV_IVS_UIV \ ((1U) << SE_KEYIV_PKT_IV_SEL_SHIFT) /* KEYIV PKT - key word */ #define SE_KEYIV_PKT_KEY_WORD_SHIFT 0 #define SE_KEYIV_PKT_KEY_WORD(x) \ ((x) << SE_KEYIV_PKT_KEY_WORD_SHIFT) /* KEYIV PKT - iv word */ #define SE_KEYIV_PKT_IV_WORD_SHIFT 0 #define SE_KEYIV_PKT_IV_WORD(x) \ ((x) << SE_KEYIV_PKT_IV_WORD_SHIFT) /* SE OPERATION */ #define SE_OPERATION_REG_OFFSET 0x8U #define SE_OPERATION_SHIFT 0 #define SE_OP_ABORT \ ((0x0U) << SE_OPERATION_SHIFT) #define SE_OP_START \ ((0x1U) << SE_OPERATION_SHIFT) #define SE_OP_RESTART \ ((0x2U) << SE_OPERATION_SHIFT) #define SE_OP_CTX_SAVE \ ((0x3U) << SE_OPERATION_SHIFT) #define SE_OP_RESTART_IN \ ((0x4U) << SE_OPERATION_SHIFT) #define SE_OPERATION(x) \ ((x) & ((0x7U) << SE_OPERATION_SHIFT)) /* SE CONTEXT */ #define SE_CTX_SAVE_CONFIG_REG_OFFSET 0x70 #define SE_CTX_SAVE_WORD_QUAD_SHIFT 0 #define SE_CTX_SAVE_WORD_QUAD(x) \ (x << SE_CTX_SAVE_WORD_QUAD_SHIFT) #define SE_CTX_SAVE_WORD_QUAD_KEYS_0_3 \ ((0U) << SE_CTX_SAVE_WORD_QUAD_SHIFT) #define SE_CTX_SAVE_WORD_QUAD_KEYS_4_7 \ ((1U) << SE_CTX_SAVE_WORD_QUAD_SHIFT) #define SE_CTX_SAVE_WORD_QUAD_ORIG_IV \ ((2U) << SE_CTX_SAVE_WORD_QUAD_SHIFT) #define SE_CTX_SAVE_WORD_QUAD_UPD_IV \ ((3U) << SE_CTX_SAVE_WORD_QUAD_SHIFT) #define SE_CTX_SAVE_KEY_INDEX_SHIFT 8 #define SE_CTX_SAVE_KEY_INDEX(x) (x << SE_CTX_SAVE_KEY_INDEX_SHIFT) #define SE_CTX_SAVE_STICKY_WORD_QUAD_SHIFT 24 #define SE_CTX_SAVE_STICKY_WORD_QUAD_STICKY_0_3 \ ((0U) << SE_CTX_SAVE_STICKY_WORD_QUAD_SHIFT) #define SE_CTX_SAVE_STICKY_WORD_QUAD_STICKY_4_7 \ ((1U) << SE_CTX_SAVE_STICKY_WORD_QUAD_SHIFT) #define SE_CTX_SAVE_STICKY_WORD_QUAD(x) \ (x << SE_CTX_SAVE_STICKY_WORD_QUAD_SHIFT) #define SE_CTX_SAVE_SRC_SHIFT 29 #define SE_CTX_SAVE_SRC_STICKY_BITS \ ((0U) << SE_CTX_SAVE_SRC_SHIFT) #define SE_CTX_SAVE_SRC_RSA_KEYTABLE \ ((1U) << SE_CTX_SAVE_SRC_SHIFT) #define SE_CTX_SAVE_SRC_AES_KEYTABLE \ ((2U) << SE_CTX_SAVE_SRC_SHIFT) #define SE_CTX_SAVE_SRC_PKA1_STICKY_BITS \ ((3U) << SE_CTX_SAVE_SRC_SHIFT) #define SE_CTX_SAVE_SRC_MEM \ ((4U) << SE_CTX_SAVE_SRC_SHIFT) #define SE_CTX_SAVE_SRC_SRK \ ((6U) << SE_CTX_SAVE_SRC_SHIFT) #define SE_CTX_SAVE_SRC_PKA1_KEYTABLE \ ((7U) << SE_CTX_SAVE_SRC_SHIFT) #define SE_CTX_STICKY_WORD_QUAD_SHIFT 24 #define SE_CTX_STICKY_WORD_QUAD_WORDS_0_3 \ ((0U) << SE_CTX_STICKY_WORD_QUAD_SHIFT) #define SE_CTX_STICKY_WORD_QUAD_WORDS_4_7 \ ((1U) << SE_CTX_STICKY_WORD_QUAD_SHIFT) #define SE_CTX_STICKY_WORD_QUAD(x) (x << SE_CTX_STICKY_WORD_QUAD_SHIFT) #define SE_CTX_SAVE_RSA_KEY_INDEX_SHIFT 16 #define SE_CTX_SAVE_RSA_KEY_INDEX(x) \ (x << SE_CTX_SAVE_RSA_KEY_INDEX_SHIFT) #define SE_CTX_RSA_WORD_QUAD_SHIFT 12 #define SE_CTX_RSA_WORD_QUAD(x) \ (x << SE_CTX_RSA_WORD_QUAD_SHIFT) #define SE_CTX_PKA1_WORD_QUAD_L_SHIFT 0 #define SE_CTX_PKA1_WORD_QUAD_L_SIZE \ ((true ? 4:0) - \ (false ? 4:0) + 1) #define SE_CTX_PKA1_WORD_QUAD_L(x)\ (((x) << SE_CTX_PKA1_WORD_QUAD_L_SHIFT) & 0x1f) #define SE_CTX_PKA1_WORD_QUAD_H_SHIFT 12 #define SE_CTX_PKA1_WORD_QUAD_H(x)\ ((((x) >> SE_CTX_PKA1_WORD_QUAD_L_SIZE) & 0xf) \ << SE_CTX_PKA1_WORD_QUAD_H_SHIFT) #define SE_RSA_KEY_INDEX_SLOT0_EXP 0 #define SE_RSA_KEY_INDEX_SLOT0_MOD 1 #define SE_RSA_KEY_INDEX_SLOT1_EXP 2 #define SE_RSA_KEY_INDEX_SLOT1_MOD 3 /* SE_CTX_SAVE_AUTO */ #define SE_CTX_SAVE_AUTO_REG_OFFSET 0x74U /* Enable */ #define SE_CTX_SAVE_AUTO_ENABLE_SHIFT 0 #define SE_CTX_SAVE_AUTO_DIS \ ((0U) << SE_CTX_SAVE_AUTO_ENABLE_SHIFT) #define SE_CTX_SAVE_AUTO_EN \ ((1U) << SE_CTX_SAVE_AUTO_ENABLE_SHIFT) #define SE_CTX_SAVE_AUTO_ENABLE(x) \ ((x) & ((0x1U) << SE_CTX_SAVE_AUTO_ENABLE_SHIFT)) /* Lock */ #define SE_CTX_SAVE_AUTO_LOCK_SHIFT 8 #define SE_CTX_SAVE_AUTO_LOCK_EN \ ((1U) << SE_CTX_SAVE_AUTO_LOCK_SHIFT) #define SE_CTX_SAVE_AUTO_LOCK_DIS \ ((0U) << SE_CTX_SAVE_AUTO_LOCK_SHIFT) #define SE_CTX_SAVE_AUTO_LOCK(x) \ ((x) & ((0x1U) << SE_CTX_SAVE_AUTO_LOCK_SHIFT)) /* Current context save number of blocks*/ #define SE_CTX_SAVE_AUTO_CURR_CNT_SHIFT 16 #define SE_CTX_SAVE_AUTO_CURR_CNT_MASK 0x3FFU #define SE_CTX_SAVE_GET_BLK_COUNT(x) \ (((x) >> SE_CTX_SAVE_AUTO_CURR_CNT_SHIFT) & \ SE_CTX_SAVE_AUTO_CURR_CNT_MASK) #define SE_CTX_SAVE_SIZE_BLOCKS_SE1 133 #define SE_CTX_SAVE_SIZE_BLOCKS_SE2 646 /* SE TZRAM OPERATION - only for SE1 */ #define SE_TZRAM_OPERATION 0x540U #define SE_TZRAM_OP_MODE_SHIFT 1 #define SE_TZRAM_OP_COMMAND_INIT 1 #define SE_TZRAM_OP_COMMAND_SHIFT 0 #define SE_TZRAM_OP_MODE_SAVE \ ((0U) << SE_TZRAM_OP_MODE_SHIFT) #define SE_TZRAM_OP_MODE_RESTORE \ ((1U) << SE_TZRAM_OP_MODE_SHIFT) #define SE_TZRAM_OP_MODE(x) \ ((x) & ((0x1U) << SE_TZRAM_OP_MODE_SHIFT)) #define SE_TZRAM_OP_BUSY_SHIFT 2 #define SE_TZRAM_OP_BUSY_OFF \ ((0U) << SE_TZRAM_OP_BUSY_SHIFT) #define SE_TZRAM_OP_BUSY_ON \ ((1U) << SE_TZRAM_OP_BUSY_SHIFT) #define SE_TZRAM_OP_BUSY(x) \ ((x) & ((0x1U) << SE_TZRAM_OP_BUSY_SHIFT)) #define SE_TZRAM_OP_REQ_SHIFT 0 #define SE_TZRAM_OP_REQ_IDLE \ ((0U) << SE_TZRAM_OP_REQ_SHIFT) #define SE_TZRAM_OP_REQ_INIT \ ((1U) << SE_TZRAM_OP_REQ_SHIFT) #define SE_TZRAM_OP_REQ(x) \ ((x) & ((0x1U) << SE_TZRAM_OP_REQ_SHIFT)) /* SE Interrupt */ #define SE_INT_STATUS_REG_OFFSET 0x10U #define SE_INT_OP_DONE_SHIFT 4 #define SE_INT_OP_DONE_CLEAR \ ((0U) << SE_INT_OP_DONE_SHIFT) #define SE_INT_OP_DONE_ACTIVE \ ((1U) << SE_INT_OP_DONE_SHIFT) #define SE_INT_OP_DONE(x) \ ((x) & ((0x1U) << SE_INT_OP_DONE_SHIFT)) /* SE TZRAM SECURITY */ #define SE_TZRAM_SEC_REG_OFFSET 0x4 #define SE_TZRAM_SEC_SETTING_SHIFT 0 #define SE_TZRAM_SECURE \ ((0UL) << SE_TZRAM_SEC_SETTING_SHIFT) #define SE_TZRAM_NONSECURE \ ((1UL) << SE_TZRAM_SEC_SETTING_SHIFT) #define SE_TZRAM_SEC_SETTING(x) \ ((x) & ((0x1UL) << SE_TZRAM_SEC_SETTING_SHIFT)) /* PKA1 KEY SLOTS */ #define TEGRA_SE_PKA1_KEYSLOT_COUNT 4 /* SE error status */ #define SE_ERR_STATUS_REG_OFFSET 0x804U #define SE_CRYPTO_KEYTABLE_DST_REG_OFFSET 0x330 #define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT 0 #define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD(x) \ (x << SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT) #define SE_KEY_INDEX_SHIFT 8 #define SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(x) (x << SE_KEY_INDEX_SHIFT) /* SE linked list (LL) register */ #define SE_IN_LL_ADDR_REG_OFFSET 0x18U #define SE_OUT_LL_ADDR_REG_OFFSET 0x24U #define SE_BLOCK_COUNT_REG_OFFSET 0x318U /* AES data sizes */ #define TEGRA_SE_KEY_256_SIZE 32 #define TEGRA_SE_KEY_192_SIZE 24 #define TEGRA_SE_KEY_128_SIZE 16 #define TEGRA_SE_AES_BLOCK_SIZE 16 #define TEGRA_SE_AES_MIN_KEY_SIZE 16 #define TEGRA_SE_AES_MAX_KEY_SIZE 32 #define TEGRA_SE_AES_IV_SIZE 16 #define TEGRA_SE_RNG_IV_SIZE 16 #define TEGRA_SE_RNG_DT_SIZE 16 #define TEGRA_SE_RNG_KEY_SIZE 16 #define TEGRA_SE_RNG_SEED_SIZE (TEGRA_SE_RNG_IV_SIZE + \ TEGRA_SE_RNG_KEY_SIZE + \ TEGRA_SE_RNG_DT_SIZE) #define TEGRA_SE_RSA512_DIGEST_SIZE 64 #define TEGRA_SE_RSA1024_DIGEST_SIZE 128 #define TEGRA_SE_RSA1536_DIGEST_SIZE 192 #define TEGRA_SE_RSA2048_DIGEST_SIZE 256 #define SE_KEY_TABLE_ACCESS_REG_OFFSET 0x284 #define SE_KEY_READ_DISABLE_SHIFT 0 #define SE_CTX_BUFER_SIZE 1072 #define SE_CTX_DRBG_BUFER_SIZE 2112 /* SE blobs size in bytes */ #define SE_CTX_SAVE_RSA_KEY_LENGTH 1024 #define SE_CTX_SAVE_RANDOM_DATA_SIZE 16 #define SE_CTX_SAVE_STICKY_BITS_SIZE 16 #define SE2_CONTEXT_SAVE_PKA1_STICKY_BITS_LENGTH 16 #define SE2_CONTEXT_SAVE_PKA1_KEYS_LENGTH 8192 #define SE_CTX_KNOWN_PATTERN_SIZE 16 #define SE_CTX_KNOWN_PATTERN_SIZE_WORDS (SE_CTX_KNOWN_PATTERN_SIZE/4) /* SE RSA */ #define TEGRA_SE_RSA_KEYSLOT_COUNT 2 #define SE_RSA_KEY_SIZE_REG_OFFSET 0x404 #define SE_RSA_EXP_SIZE_REG_OFFSET 0x408 #define SE_RSA_MAX_EXP_BIT_SIZE 2048 #define SE_RSA_MAX_EXP_SIZE32 \ (SE_RSA_MAX_EXP_BIT_SIZE >> 5) #define SE_RSA_MAX_MOD_BIT_SIZE 2048 #define SE_RSA_MAX_MOD_SIZE32 \ (SE_RSA_MAX_MOD_BIT_SIZE >> 5) /* SE_RSA_KEYTABLE_ADDR */ #define SE_RSA_KEYTABLE_ADDR 0x420 #define RSA_KEY_PKT_WORD_ADDR_SHIFT 0 #define RSA_KEY_PKT_EXPMOD_SEL_SHIFT \ ((6U) << RSA_KEY_PKT_WORD_ADDR_SHIFT) #define RSA_KEY_MOD \ ((1U) << RSA_KEY_PKT_EXPMOD_SEL_SHIFT) #define RSA_KEY_EXP \ ((0U) << RSA_KEY_PKT_EXPMOD_SEL_SHIFT) #define RSA_KEY_PKT_SLOT_SHIFT 7 #define RSA_KEY_SLOT_1 \ ((0U) << RSA_KEY_PKT_SLOT_SHIFT) #define RSA_KEY_SLOT_2 \ ((1U) << RSA_KEY_PKT_SLOT_SHIFT) #define RSA_KEY_PKT_INPUT_MODE_SHIFT 8 #define RSA_KEY_REG_INPUT \ ((0U) << RSA_KEY_PKT_INPUT_MODE_SHIFT) #define RSA_KEY_DMA_INPUT \ ((1U) << RSA_KEY_PKT_INPUT_MODE_SHIFT) /* SE_RSA_KEYTABLE_DATA */ #define SE_RSA_KEYTABLE_DATA 0x424 /* SE_RSA_CONFIG register */ #define SE_RSA_CONFIG 0x400 #define RSA_KEY_SLOT_SHIFT 24 #define RSA_KEY_SLOT(x) \ ((x) << RSA_KEY_SLOT_SHIFT) /******************************************************************************* * Structure definition ******************************************************************************/ /* SE context blob */ #pragma pack(push, 1) typedef struct tegra_aes_key_slot { /* 0 - 7 AES key */ uint32_t key[8]; /* 8 - 11 Original IV */ uint32_t oiv[4]; /* 12 - 15 Updated IV */ uint32_t uiv[4]; } tegra_se_aes_key_slot_t; #pragma pack(pop) #pragma pack(push, 1) typedef struct tegra_se_context { /* random number */ unsigned char rand_data[SE_CTX_SAVE_RANDOM_DATA_SIZE]; /* Sticky bits */ unsigned char sticky_bits[SE_CTX_SAVE_STICKY_BITS_SIZE * 2]; /* AES key slots */ tegra_se_aes_key_slot_t key_slots[TEGRA_SE_AES_KEYSLOT_COUNT]; /* RSA key slots */ unsigned char rsa_keys[SE_CTX_SAVE_RSA_KEY_LENGTH]; } tegra_se_context_t; #pragma pack(pop) /* PKA context blob */ #pragma pack(push, 1) typedef struct tegra_pka_context { unsigned char sticky_bits[SE2_CONTEXT_SAVE_PKA1_STICKY_BITS_LENGTH]; unsigned char pka_keys[SE2_CONTEXT_SAVE_PKA1_KEYS_LENGTH]; } tegra_pka_context_t; #pragma pack(pop) /* SE context blob */ #pragma pack(push, 1) typedef struct tegra_se_context_blob { /* SE context */ tegra_se_context_t se_ctx; /* Known Pattern */ unsigned char known_pattern[SE_CTX_KNOWN_PATTERN_SIZE]; } tegra_se_context_blob_t; #pragma pack(pop) /* SE2 and PKA1 context blob */ #pragma pack(push, 1) typedef struct tegra_se2_context_blob { /* SE2 context */ tegra_se_context_t se_ctx; /* PKA1 context */ tegra_pka_context_t pka_ctx; /* Known Pattern */ unsigned char known_pattern[SE_CTX_KNOWN_PATTERN_SIZE]; } tegra_se2_context_blob_t; #pragma pack(pop) /* SE AES key type 128bit, 192bit, 256bit */ typedef enum { SE_AES_KEY128, SE_AES_KEY192, SE_AES_KEY256, } tegra_se_aes_key_type_t; /* SE RSA key slot */ typedef struct tegra_se_rsa_key_slot { /* 0 - 63 exponent key */ uint32_t exponent[SE_RSA_MAX_EXP_SIZE32]; /* 64 - 127 modulus key */ uint32_t modulus[SE_RSA_MAX_MOD_SIZE32]; } tegra_se_rsa_key_slot_t; /******************************************************************************* * Inline functions definition ******************************************************************************/ static inline uint32_t tegra_se_read_32(const tegra_se_dev_t *dev, uint32_t offset) { return mmio_read_32(dev->se_base + offset); } static inline void tegra_se_write_32(const tegra_se_dev_t *dev, uint32_t offset, uint32_t val) { mmio_write_32(dev->se_base + offset, val); } static inline uint32_t tegra_pka_read_32(tegra_pka_dev_t *dev, uint32_t offset) { return mmio_read_32(dev->pka_base + offset); } static inline void tegra_pka_write_32(tegra_pka_dev_t *dev, uint32_t offset, uint32_t val) { mmio_write_32(dev->pka_base + offset, val); } /******************************************************************************* * Prototypes ******************************************************************************/ int tegra_se_start_normal_operation(const tegra_se_dev_t *, uint32_t); int tegra_se_start_ctx_save_operation(const tegra_se_dev_t *, uint32_t); #endif /* SE_PRIVATE_H */ trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t210/drivers/se/security_engine.c000066400000000000000000000750751355360272700273420ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * Constants and Macros ******************************************************************************/ #define TIMEOUT_100MS 100U // Timeout in 100ms #define RNG_AES_KEY_INDEX 1 /******************************************************************************* * Data structure and global variables ******************************************************************************/ /* The security engine contexts are formatted as follows: * * SE1 CONTEXT: * #--------------------------------# * | Random Data 1 Block | * #--------------------------------# * | Sticky Bits 2 Blocks | * #--------------------------------# * | Key Table 64 Blocks | * | For each Key (x16): | * | Key: 2 Blocks | * | Original-IV: 1 Block | * | Updated-IV: 1 Block | * #--------------------------------# * | RSA Keys 64 Blocks | * #--------------------------------# * | Known Pattern 1 Block | * #--------------------------------# * * SE2/PKA1 CONTEXT: * #--------------------------------# * | Random Data 1 Block | * #--------------------------------# * | Sticky Bits 2 Blocks | * #--------------------------------# * | Key Table 64 Blocks | * | For each Key (x16): | * | Key: 2 Blocks | * | Original-IV: 1 Block | * | Updated-IV: 1 Block | * #--------------------------------# * | RSA Keys 64 Blocks | * #--------------------------------# * | PKA sticky bits 1 Block | * #--------------------------------# * | PKA keys 512 Blocks | * #--------------------------------# * | Known Pattern 1 Block | * #--------------------------------# */ /* Known pattern data */ static const uint32_t se_ctx_known_pattern_data[SE_CTX_KNOWN_PATTERN_SIZE_WORDS] = { /* 128 bit AES block */ 0x0C0D0E0F, 0x08090A0B, 0x04050607, 0x00010203, }; /* SE input and output linked list buffers */ static tegra_se_io_lst_t se1_src_ll_buf; static tegra_se_io_lst_t se1_dst_ll_buf; /* SE2 input and output linked list buffers */ static tegra_se_io_lst_t se2_src_ll_buf; static tegra_se_io_lst_t se2_dst_ll_buf; /* SE1 security engine device handle */ static tegra_se_dev_t se_dev_1 = { .se_num = 1, /* Setup base address for se */ .se_base = TEGRA_SE1_BASE, /* Setup context size in AES blocks */ .ctx_size_blks = SE_CTX_SAVE_SIZE_BLOCKS_SE1, /* Setup SRC buffers for SE operations */ .src_ll_buf = &se1_src_ll_buf, /* Setup DST buffers for SE operations */ .dst_ll_buf = &se1_dst_ll_buf, /* Setup context save destination */ .ctx_save_buf = (uint32_t *)(TEGRA_TZRAM_CARVEOUT_BASE), }; /* SE2 security engine device handle */ static tegra_se_dev_t se_dev_2 = { .se_num = 2, /* Setup base address for se */ .se_base = TEGRA_SE2_BASE, /* Setup context size in AES blocks */ .ctx_size_blks = SE_CTX_SAVE_SIZE_BLOCKS_SE2, /* Setup SRC buffers for SE operations */ .src_ll_buf = &se2_src_ll_buf, /* Setup DST buffers for SE operations */ .dst_ll_buf = &se2_dst_ll_buf, /* Setup context save destination */ .ctx_save_buf = (uint32_t *)(TEGRA_TZRAM_CARVEOUT_BASE + 0x1000), }; static bool ecid_valid; /******************************************************************************* * Functions Definition ******************************************************************************/ static void tegra_se_make_data_coherent(const tegra_se_dev_t *se_dev) { flush_dcache_range(((uint64_t)(se_dev->src_ll_buf)), sizeof(tegra_se_io_lst_t)); flush_dcache_range(((uint64_t)(se_dev->dst_ll_buf)), sizeof(tegra_se_io_lst_t)); } /* * Check that SE operation has completed after kickoff * This function is invoked after an SE operation has been started, * and it checks the following conditions: * 1. SE_INT_STATUS = SE_OP_DONE * 2. SE_STATUS = IDLE * 3. AHB bus data transfer complete. * 4. SE_ERR_STATUS is clean. */ static int32_t tegra_se_operation_complete(const tegra_se_dev_t *se_dev) { uint32_t val = 0; int32_t ret = 0; uint32_t timeout; /* Poll the SE interrupt register to ensure H/W operation complete */ val = tegra_se_read_32(se_dev, SE_INT_STATUS_REG_OFFSET); for (timeout = 0; (SE_INT_OP_DONE(val) == SE_INT_OP_DONE_CLEAR) && (timeout < TIMEOUT_100MS); timeout++) { mdelay(1); val = tegra_se_read_32(se_dev, SE_INT_STATUS_REG_OFFSET); } if (timeout == TIMEOUT_100MS) { ERROR("%s: ERR: Atomic context save operation timeout!\n", __func__); ret = -ETIMEDOUT; } /* Poll the SE status idle to ensure H/W operation complete */ if (ret == 0) { val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET); for (timeout = 0; (val != 0U) && (timeout < TIMEOUT_100MS); timeout++) { mdelay(1); val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET); } if (timeout == TIMEOUT_100MS) { ERROR("%s: ERR: MEM_INTERFACE and SE state " "idle state timeout.\n", __func__); ret = -ETIMEDOUT; } } /* Check AHB bus transfer complete */ if (ret == 0) { val = mmio_read_32(TEGRA_AHB_ARB_BASE + ARAHB_MEM_WRQUE_MST_ID_OFFSET); for (timeout = 0; ((val & (ARAHB_MST_ID_SE_MASK | ARAHB_MST_ID_SE2_MASK)) != 0U) && (timeout < TIMEOUT_100MS); timeout++) { mdelay(1); val = mmio_read_32(TEGRA_AHB_ARB_BASE + ARAHB_MEM_WRQUE_MST_ID_OFFSET); } if (timeout == TIMEOUT_100MS) { ERROR("%s: SE write over AHB timeout.\n", __func__); ret = -ETIMEDOUT; } } /* Ensure that no errors are thrown during operation */ if (ret == 0) { val = tegra_se_read_32(se_dev, SE_ERR_STATUS_REG_OFFSET); if (val != 0U) { ERROR("%s: error during SE operation! 0x%x", __func__, val); ret = -ENOTSUP; } } return ret; } /* * Returns true if the SE engine is configured to perform SE context save in * hardware. */ static inline bool tegra_se_atomic_save_enabled(const tegra_se_dev_t *se_dev) { uint32_t val; val = tegra_se_read_32(se_dev, SE_CTX_SAVE_AUTO_REG_OFFSET); return (SE_CTX_SAVE_AUTO_ENABLE(val) == SE_CTX_SAVE_AUTO_EN); } /* * Wait for SE engine to be idle and clear pending interrupts before * starting the next SE operation. */ static int32_t tegra_se_operation_prepare(const tegra_se_dev_t *se_dev) { int32_t ret = 0; uint32_t val = 0; uint32_t timeout; /* Wait for previous operation to finish */ val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET); for (timeout = 0; (val != 0U) && (timeout < TIMEOUT_100MS); timeout++) { mdelay(1); val = tegra_se_read_32(se_dev, SE_STATUS_OFFSET); } if (timeout == TIMEOUT_100MS) { ERROR("%s: ERR: SE status is not idle!\n", __func__); ret = -ETIMEDOUT; } /* Clear any pending interrupts from previous operation */ val = tegra_se_read_32(se_dev, SE_INT_STATUS_REG_OFFSET); tegra_se_write_32(se_dev, SE_INT_STATUS_REG_OFFSET, val); return ret; } /* * SE atomic context save. At SC7 entry, SE driver triggers the * hardware automatically performs the context save operation. */ static int32_t tegra_se_context_save_atomic(const tegra_se_dev_t *se_dev) { int32_t ret = 0; uint32_t val = 0; uint32_t blk_count_limit = 0; uint32_t block_count; /* Check that previous operation is finalized */ ret = tegra_se_operation_prepare(se_dev); /* Read the context save progress counter: block_count * Ensure no previous context save has been triggered * SE_CTX_SAVE_AUTO.CURR_CNT == 0 */ if (ret == 0) { val = tegra_se_read_32(se_dev, SE_CTX_SAVE_AUTO_REG_OFFSET); block_count = SE_CTX_SAVE_GET_BLK_COUNT(val); if (block_count != 0U) { ERROR("%s: ctx_save triggered multiple times\n", __func__); ret = -EALREADY; } } /* Set the destination block count when the context save complete */ if (ret == 0) { blk_count_limit = block_count + se_dev->ctx_size_blks; } /* Program SE_CONFIG register as for RNG operation * SE_CONFIG.ENC_ALG = RNG * SE_CONFIG.DEC_ALG = NOP * SE_CONFIG.ENC_MODE is ignored * SE_CONFIG.DEC_MODE is ignored * SE_CONFIG.DST = MEMORY */ if (ret == 0) { val = (SE_CONFIG_ENC_ALG_RNG | SE_CONFIG_DEC_ALG_NOP | SE_CONFIG_DST_MEMORY); tegra_se_write_32(se_dev, SE_CONFIG_REG_OFFSET, val); tegra_se_make_data_coherent(se_dev); /* SE_CTX_SAVE operation */ tegra_se_write_32(se_dev, SE_OPERATION_REG_OFFSET, SE_OP_CTX_SAVE); ret = tegra_se_operation_complete(se_dev); } /* Check that context has written the correct number of blocks */ if (ret == 0) { val = tegra_se_read_32(se_dev, SE_CTX_SAVE_AUTO_REG_OFFSET); if (SE_CTX_SAVE_GET_BLK_COUNT(val) != blk_count_limit) { ERROR("%s: expected %d blocks but %d were written\n", __func__, blk_count_limit, val); ret = -ECANCELED; } } return ret; } /* * Security engine primitive operations, including normal operation * and the context save operation. */ static int tegra_se_perform_operation(const tegra_se_dev_t *se_dev, uint32_t nbytes, bool context_save) { uint32_t nblocks = nbytes / TEGRA_SE_AES_BLOCK_SIZE; int ret = 0; assert(se_dev); /* Use device buffers for in and out */ tegra_se_write_32(se_dev, SE_OUT_LL_ADDR_REG_OFFSET, ((uint64_t)(se_dev->dst_ll_buf))); tegra_se_write_32(se_dev, SE_IN_LL_ADDR_REG_OFFSET, ((uint64_t)(se_dev->src_ll_buf))); /* Check that previous operation is finalized */ ret = tegra_se_operation_prepare(se_dev); if (ret != 0) { goto op_error; } /* Program SE operation size */ if (nblocks) { tegra_se_write_32(se_dev, SE_BLOCK_COUNT_REG_OFFSET, nblocks - 1); } /* Make SE LL data coherent before the SE operation */ tegra_se_make_data_coherent(se_dev); /* Start hardware operation */ if (context_save) tegra_se_write_32(se_dev, SE_OPERATION_REG_OFFSET, SE_OP_CTX_SAVE); else tegra_se_write_32(se_dev, SE_OPERATION_REG_OFFSET, SE_OP_START); /* Wait for operation to finish */ ret = tegra_se_operation_complete(se_dev); op_error: return ret; } /* * Normal security engine operations other than the context save */ int tegra_se_start_normal_operation(const tegra_se_dev_t *se_dev, uint32_t nbytes) { return tegra_se_perform_operation(se_dev, nbytes, false); } /* * Security engine context save operation */ int tegra_se_start_ctx_save_operation(const tegra_se_dev_t *se_dev, uint32_t nbytes) { return tegra_se_perform_operation(se_dev, nbytes, true); } /* * Security Engine sequence to generat SRK * SE and SE2 will generate different SRK by different * entropy seeds. */ static int tegra_se_generate_srk(const tegra_se_dev_t *se_dev) { int ret = PSCI_E_INTERN_FAIL; uint32_t val; /* Confgure the following hardware register settings: * SE_CONFIG.DEC_ALG = NOP * SE_CONFIG.ENC_ALG = RNG * SE_CONFIG.DST = SRK * SE_OPERATION.OP = START * SE_CRYPTO_LAST_BLOCK = 0 */ se_dev->src_ll_buf->last_buff_num = 0; se_dev->dst_ll_buf->last_buff_num = 0; /* Configure random number generator */ if (ecid_valid) val = (DRBG_MODE_FORCE_INSTANTION | DRBG_SRC_ENTROPY); else val = (DRBG_MODE_FORCE_RESEED | DRBG_SRC_ENTROPY); tegra_se_write_32(se_dev, SE_RNG_CONFIG_REG_OFFSET, val); /* Configure output destination = SRK */ val = (SE_CONFIG_ENC_ALG_RNG | SE_CONFIG_DEC_ALG_NOP | SE_CONFIG_DST_SRK); tegra_se_write_32(se_dev, SE_CONFIG_REG_OFFSET, val); /* Perform hardware operation */ ret = tegra_se_start_normal_operation(se_dev, 0); return ret; } /* * Generate plain text random data to some memory location using * SE/SE2's SP800-90 random number generator. The random data size * must be some multiple of the AES block size (16 bytes). */ static int tegra_se_lp_generate_random_data(tegra_se_dev_t *se_dev) { int ret = 0; uint32_t val; /* Set some arbitrary memory location to store the random data */ se_dev->dst_ll_buf->last_buff_num = 0; if (!se_dev->ctx_save_buf) { ERROR("%s: ERR: context save buffer NULL pointer!\n", __func__); return PSCI_E_NOT_PRESENT; } se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(((tegra_se_context_t *) se_dev->ctx_save_buf)->rand_data))); se_dev->dst_ll_buf->buffer[0].data_len = SE_CTX_SAVE_RANDOM_DATA_SIZE; /* Confgure the following hardware register settings: * SE_CONFIG.DEC_ALG = NOP * SE_CONFIG.ENC_ALG = RNG * SE_CONFIG.ENC_MODE = KEY192 * SE_CONFIG.DST = MEMORY */ val = (SE_CONFIG_ENC_ALG_RNG | SE_CONFIG_DEC_ALG_NOP | SE_CONFIG_ENC_MODE_KEY192 | SE_CONFIG_DST_MEMORY); tegra_se_write_32(se_dev, SE_CONFIG_REG_OFFSET, val); /* Program the RNG options in SE_CRYPTO_CONFIG as follows: * XOR_POS = BYPASS * INPUT_SEL = RANDOM (Entropy or LFSR) * HASH_ENB = DISABLE */ val = (SE_CRYPTO_INPUT_RANDOM | SE_CRYPTO_XOR_BYPASS | SE_CRYPTO_CORE_ENCRYPT | SE_CRYPTO_HASH_DISABLE | SE_CRYPTO_KEY_INDEX(RNG_AES_KEY_INDEX) | SE_CRYPTO_IV_ORIGINAL); tegra_se_write_32(se_dev, SE_CRYPTO_REG_OFFSET, val); /* Configure RNG */ if (ecid_valid) val = (DRBG_MODE_FORCE_INSTANTION | DRBG_SRC_LFSR); else val = (DRBG_MODE_FORCE_RESEED | DRBG_SRC_LFSR); tegra_se_write_32(se_dev, SE_RNG_CONFIG_REG_OFFSET, val); /* SE normal operation */ ret = tegra_se_start_normal_operation(se_dev, SE_CTX_SAVE_RANDOM_DATA_SIZE); return ret; } /* * Encrypt memory blocks with SRK as part of the security engine context. * The data blocks include: random data and the known pattern data, where * the random data is the first block and known pattern is the last block. */ static int tegra_se_lp_data_context_save(tegra_se_dev_t *se_dev, uint64_t src_addr, uint64_t dst_addr, uint32_t data_size) { int ret = 0; se_dev->src_ll_buf->last_buff_num = 0; se_dev->dst_ll_buf->last_buff_num = 0; se_dev->src_ll_buf->buffer[0].addr = src_addr; se_dev->src_ll_buf->buffer[0].data_len = data_size; se_dev->dst_ll_buf->buffer[0].addr = dst_addr; se_dev->dst_ll_buf->buffer[0].data_len = data_size; /* By setting the context source from memory and calling the context save * operation, the SE encrypts the memory data with SRK. */ tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, SE_CTX_SAVE_SRC_MEM); ret = tegra_se_start_ctx_save_operation(se_dev, data_size); return ret; } /* * Context save the key table access control sticky bits and * security status of each key-slot. The encrypted sticky-bits are * 32 bytes (2 AES blocks) and formatted as the following structure: * { bit in registers bit in context save * SECURITY_0[4] 158 * SE_RSA_KEYTABLE_ACCE4SS_1[2:0] 157:155 * SE_RSA_KEYTABLE_ACCE4SS_0[2:0] 154:152 * SE_RSA_SECURITY_PERKEY_0[1:0] 151:150 * SE_CRYPTO_KEYTABLE_ACCESS_15[7:0] 149:142 * ..., * SE_CRYPTO_KEYTABLE_ACCESS_0[7:0] 29:22 * SE_CRYPTO_SECURITY_PERKEY_0[15:0] 21:6 * SE_TZRAM_SECURITY_0[1:0] 5:4 * SE_SECURITY_0[16] 3:3 * SE_SECURITY_0[2:0] } 2:0 */ static int tegra_se_lp_sticky_bits_context_save(tegra_se_dev_t *se_dev) { int ret = PSCI_E_INTERN_FAIL; uint32_t val = 0; se_dev->dst_ll_buf->last_buff_num = 0; if (!se_dev->ctx_save_buf) { ERROR("%s: ERR: context save buffer NULL pointer!\n", __func__); return PSCI_E_NOT_PRESENT; } se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&(((tegra_se_context_t *) se_dev->ctx_save_buf)->sticky_bits))); se_dev->dst_ll_buf->buffer[0].data_len = SE_CTX_SAVE_STICKY_BITS_SIZE; /* * The 1st AES block save the sticky-bits context 1 - 16 bytes (0 - 3 words). * The 2nd AES block save the sticky-bits context 17 - 32 bytes (4 - 7 words). */ for (int i = 0; i < 2; i++) { val = SE_CTX_SAVE_SRC_STICKY_BITS | SE_CTX_SAVE_STICKY_WORD_QUAD(i); tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, val); /* SE context save operation */ ret = tegra_se_start_ctx_save_operation(se_dev, SE_CTX_SAVE_STICKY_BITS_SIZE); if (ret) break; se_dev->dst_ll_buf->buffer[0].addr += SE_CTX_SAVE_STICKY_BITS_SIZE; } return ret; } static int tegra_se_aeskeytable_context_save(tegra_se_dev_t *se_dev) { uint32_t val = 0; int ret = 0; se_dev->dst_ll_buf->last_buff_num = 0; if (!se_dev->ctx_save_buf) { ERROR("%s: ERR: context save buffer NULL pointer!\n", __func__); ret = -EINVAL; goto aes_keytable_save_err; } /* AES key context save */ for (int slot = 0; slot < TEGRA_SE_AES_KEYSLOT_COUNT; slot++) { se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&( ((tegra_se_context_t *)se_dev-> ctx_save_buf)->key_slots[slot].key))); se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_KEY_128_SIZE; for (int i = 0; i < 2; i++) { val = SE_CTX_SAVE_SRC_AES_KEYTABLE | SE_CTX_SAVE_KEY_INDEX(slot) | SE_CTX_SAVE_WORD_QUAD(i); tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, val); /* SE context save operation */ ret = tegra_se_start_ctx_save_operation(se_dev, TEGRA_SE_KEY_128_SIZE); if (ret) { ERROR("%s: ERR: AES key CTX_SAVE OP failed, " "slot=%d, word_quad=%d.\n", __func__, slot, i); goto aes_keytable_save_err; } se_dev->dst_ll_buf->buffer[0].addr += TEGRA_SE_KEY_128_SIZE; } /* OIV context save */ se_dev->dst_ll_buf->last_buff_num = 0; se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&( ((tegra_se_context_t *)se_dev-> ctx_save_buf)->key_slots[slot].oiv))); se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_AES_IV_SIZE; val = SE_CTX_SAVE_SRC_AES_KEYTABLE | SE_CTX_SAVE_KEY_INDEX(slot) | SE_CTX_SAVE_WORD_QUAD_ORIG_IV; tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, val); /* SE context save operation */ ret = tegra_se_start_ctx_save_operation(se_dev, TEGRA_SE_AES_IV_SIZE); if (ret) { ERROR("%s: ERR: OIV CTX_SAVE OP failed, slot=%d.\n", __func__, slot); goto aes_keytable_save_err; } /* UIV context save */ se_dev->dst_ll_buf->last_buff_num = 0; se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&( ((tegra_se_context_t *)se_dev-> ctx_save_buf)->key_slots[slot].uiv))); se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_AES_IV_SIZE; val = SE_CTX_SAVE_SRC_AES_KEYTABLE | SE_CTX_SAVE_KEY_INDEX(slot) | SE_CTX_SAVE_WORD_QUAD_UPD_IV; tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, val); /* SE context save operation */ ret = tegra_se_start_ctx_save_operation(se_dev, TEGRA_SE_AES_IV_SIZE); if (ret) { ERROR("%s: ERR: UIV CTX_SAVE OP failed, slot=%d\n", __func__, slot); goto aes_keytable_save_err; } } aes_keytable_save_err: return ret; } static int tegra_se_lp_rsakeytable_context_save(tegra_se_dev_t *se_dev) { uint32_t val = 0; int ret = 0; /* First the modulus and then the exponent must be * encrypted and saved. This is repeated for SLOT 0 * and SLOT 1. Hence the order: * SLOT 0 exponent : RSA_KEY_INDEX : 0 * SLOT 0 modulus : RSA_KEY_INDEX : 1 * SLOT 1 exponent : RSA_KEY_INDEX : 2 * SLOT 1 modulus : RSA_KEY_INDEX : 3 */ const unsigned int key_index_mod[TEGRA_SE_RSA_KEYSLOT_COUNT][2] = { /* RSA key slot 0 */ {SE_RSA_KEY_INDEX_SLOT0_EXP, SE_RSA_KEY_INDEX_SLOT0_MOD}, /* RSA key slot 1 */ {SE_RSA_KEY_INDEX_SLOT1_EXP, SE_RSA_KEY_INDEX_SLOT1_MOD}, }; se_dev->dst_ll_buf->last_buff_num = 0; se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&( ((tegra_se_context_t *)se_dev-> ctx_save_buf)->rsa_keys))); se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_KEY_128_SIZE; for (int slot = 0; slot < TEGRA_SE_RSA_KEYSLOT_COUNT; slot++) { /* loop for modulus and exponent */ for (int index = 0; index < 2; index++) { for (int word_quad = 0; word_quad < 16; word_quad++) { val = SE_CTX_SAVE_SRC_RSA_KEYTABLE | SE_CTX_SAVE_RSA_KEY_INDEX( key_index_mod[slot][index]) | SE_CTX_RSA_WORD_QUAD(word_quad); tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, val); /* SE context save operation */ ret = tegra_se_start_ctx_save_operation(se_dev, TEGRA_SE_KEY_128_SIZE); if (ret) { ERROR("%s: ERR: slot=%d.\n", __func__, slot); goto rsa_keytable_save_err; } /* Update the pointer to the next word quad */ se_dev->dst_ll_buf->buffer[0].addr += TEGRA_SE_KEY_128_SIZE; } } } rsa_keytable_save_err: return ret; } static int tegra_se_pkakeytable_sticky_bits_save(tegra_se_dev_t *se_dev) { int ret = 0; se_dev->dst_ll_buf->last_buff_num = 0; se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&( ((tegra_se2_context_blob_t *)se_dev-> ctx_save_buf)->pka_ctx.sticky_bits))); se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_AES_BLOCK_SIZE; /* PKA1 sticky bits are 1 AES block (16 bytes) */ tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, SE_CTX_SAVE_SRC_PKA1_STICKY_BITS | SE_CTX_STICKY_WORD_QUAD_WORDS_0_3); /* SE context save operation */ ret = tegra_se_start_ctx_save_operation(se_dev, 0); if (ret) { ERROR("%s: ERR: PKA1 sticky bits CTX_SAVE OP failed\n", __func__); goto pka_sticky_bits_save_err; } pka_sticky_bits_save_err: return ret; } static int tegra_se_pkakeytable_context_save(tegra_se_dev_t *se_dev) { uint32_t val = 0; int ret = 0; se_dev->dst_ll_buf->last_buff_num = 0; se_dev->dst_ll_buf->buffer[0].addr = ((uint64_t)(&( ((tegra_se2_context_blob_t *)se_dev-> ctx_save_buf)->pka_ctx.pka_keys))); se_dev->dst_ll_buf->buffer[0].data_len = TEGRA_SE_KEY_128_SIZE; /* for each slot, save word quad 0-127 */ for (int slot = 0; slot < TEGRA_SE_PKA1_KEYSLOT_COUNT; slot++) { for (int word_quad = 0; word_quad < 512/4; word_quad++) { val = SE_CTX_SAVE_SRC_PKA1_KEYTABLE | SE_CTX_PKA1_WORD_QUAD_L((slot * 128) + word_quad) | SE_CTX_PKA1_WORD_QUAD_H((slot * 128) + word_quad); tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, val); /* SE context save operation */ ret = tegra_se_start_ctx_save_operation(se_dev, TEGRA_SE_KEY_128_SIZE); if (ret) { ERROR("%s: ERR: pka1 keytable ctx save error\n", __func__); goto pka_keytable_save_err; } /* Update the pointer to the next word quad */ se_dev->dst_ll_buf->buffer[0].addr += TEGRA_SE_KEY_128_SIZE; } } pka_keytable_save_err: return ret; } static int tegra_se_save_SRK(tegra_se_dev_t *se_dev) { tegra_se_write_32(se_dev, SE_CTX_SAVE_CONFIG_REG_OFFSET, SE_CTX_SAVE_SRC_SRK); /* SE context save operation */ return tegra_se_start_ctx_save_operation(se_dev, 0); } /* * Lock both SE from non-TZ clients. */ static inline void tegra_se_lock(tegra_se_dev_t *se_dev) { uint32_t val; assert(se_dev); val = tegra_se_read_32(se_dev, SE_SECURITY_REG_OFFSET); val |= SE_SECURITY_TZ_LOCK_SOFT(SE_SECURE); tegra_se_write_32(se_dev, SE_SECURITY_REG_OFFSET, val); } /* * Use SRK to encrypt SE state and save to TZRAM carveout */ static int tegra_se_context_save_sw(tegra_se_dev_t *se_dev) { int err = 0; assert(se_dev); /* Lock entire SE/SE2 as TZ protected */ tegra_se_lock(se_dev); INFO("%s: generate SRK\n", __func__); /* Generate SRK */ err = tegra_se_generate_srk(se_dev); if (err) { ERROR("%s: ERR: SRK generation failed\n", __func__); return err; } INFO("%s: generate random data\n", __func__); /* Generate random data */ err = tegra_se_lp_generate_random_data(se_dev); if (err) { ERROR("%s: ERR: LP random pattern generation failed\n", __func__); return err; } INFO("%s: encrypt random data\n", __func__); /* Encrypt the random data block */ err = tegra_se_lp_data_context_save(se_dev, ((uint64_t)(&(((tegra_se_context_t *)se_dev-> ctx_save_buf)->rand_data))), ((uint64_t)(&(((tegra_se_context_t *)se_dev-> ctx_save_buf)->rand_data))), SE_CTX_SAVE_RANDOM_DATA_SIZE); if (err) { ERROR("%s: ERR: random pattern encryption failed\n", __func__); return err; } INFO("%s: save SE sticky bits\n", __func__); /* Save AES sticky bits context */ err = tegra_se_lp_sticky_bits_context_save(se_dev); if (err) { ERROR("%s: ERR: sticky bits context save failed\n", __func__); return err; } INFO("%s: save AES keytables\n", __func__); /* Save AES key table context */ err = tegra_se_aeskeytable_context_save(se_dev); if (err) { ERROR("%s: ERR: LP keytable save failed\n", __func__); return err; } /* RSA key slot table context save */ INFO("%s: save RSA keytables\n", __func__); err = tegra_se_lp_rsakeytable_context_save(se_dev); if (err) { ERROR("%s: ERR: rsa key table context save failed\n", __func__); return err; } /* Only SE2 has an interface with PKA1; thus, PKA1's context is saved * via SE2. */ if (se_dev->se_num == 2) { /* Encrypt PKA1 sticky bits on SE2 only */ INFO("%s: save PKA sticky bits\n", __func__); err = tegra_se_pkakeytable_sticky_bits_save(se_dev); if (err) { ERROR("%s: ERR: PKA sticky bits context save failed\n", __func__); return err; } /* Encrypt PKA1 keyslots on SE2 only */ INFO("%s: save PKA keytables\n", __func__); err = tegra_se_pkakeytable_context_save(se_dev); if (err) { ERROR("%s: ERR: PKA key table context save failed\n", __func__); return err; } } /* Encrypt known pattern */ if (se_dev->se_num == 1) { err = tegra_se_lp_data_context_save(se_dev, ((uint64_t)(&se_ctx_known_pattern_data)), ((uint64_t)(&(((tegra_se_context_blob_t *)se_dev->ctx_save_buf)->known_pattern))), SE_CTX_KNOWN_PATTERN_SIZE); } else if (se_dev->se_num == 2) { err = tegra_se_lp_data_context_save(se_dev, ((uint64_t)(&se_ctx_known_pattern_data)), ((uint64_t)(&(((tegra_se2_context_blob_t *)se_dev->ctx_save_buf)->known_pattern))), SE_CTX_KNOWN_PATTERN_SIZE); } if (err) { ERROR("%s: ERR: save LP known pattern failure\n", __func__); return err; } /* Write lp context buffer address into PMC scratch register */ if (se_dev->se_num == 1) { /* SE context address */ mmio_write_32((uint64_t)TEGRA_PMC_BASE + PMC_SECURE_SCRATCH117_OFFSET, ((uint64_t)(se_dev->ctx_save_buf))); } else if (se_dev->se_num == 2) { /* SE2 & PKA1 context address */ mmio_write_32((uint64_t)TEGRA_PMC_BASE + PMC_SECURE_SCRATCH116_OFFSET, ((uint64_t)(se_dev->ctx_save_buf))); } /* Saves SRK to PMC secure scratch registers for BootROM, which * verifies and restores the security engine context on warm boot. */ err = tegra_se_save_SRK(se_dev); if (err < 0) { ERROR("%s: ERR: LP SRK save failure\n", __func__); return err; } INFO("%s: SE context save done \n", __func__); return err; } /* * Initialize the SE engine handle */ void tegra_se_init(void) { uint32_t val = 0; INFO("%s: start SE init\n", __func__); /* Generate random SRK to initialize DRBG */ tegra_se_generate_srk(&se_dev_1); tegra_se_generate_srk(&se_dev_2); /* determine if ECID is valid */ val = mmio_read_32(TEGRA_FUSE_BASE + FUSE_JTAG_SECUREID_VALID); ecid_valid = (val == ECID_VALID); INFO("%s: SE init done\n", __func__); } static void tegra_se_enable_clocks(void) { uint32_t val = 0; /* Enable entropy clock */ val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_W); val |= ENTROPY_CLK_ENB_BIT; mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_W, val); /* De-Assert Entropy Reset */ val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEVICES_W); val &= ~ENTROPY_RESET_BIT; mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEVICES_W, val); /* Enable SE clock */ val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_V); val |= SE_CLK_ENB_BIT; mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_V, val); /* De-Assert SE Reset */ val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEVICES_V); val &= ~SE_RESET_BIT; mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEVICES_V, val); } static void tegra_se_disable_clocks(void) { uint32_t val = 0; /* Disable entropy clock */ val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_W); val &= ~ENTROPY_CLK_ENB_BIT; mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_W, val); /* Disable SE clock */ val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_V); val &= ~SE_CLK_ENB_BIT; mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_OUT_ENB_V, val); } /* * Security engine power suspend entry point. * This function is invoked from PSCI power domain suspend handler. */ int32_t tegra_se_suspend(void) { int32_t ret = 0; uint32_t val = 0; /* SE does not use SMMU in EL3, disable SMMU. * This will be re-enabled by kernel on resume */ val = mmio_read_32(TEGRA_MC_BASE + MC_SMMU_PPCS_ASID_0); val &= ~PPCS_SMMU_ENABLE; mmio_write_32(TEGRA_MC_BASE + MC_SMMU_PPCS_ASID_0, val); tegra_se_enable_clocks(); if (tegra_se_atomic_save_enabled(&se_dev_2) && tegra_se_atomic_save_enabled(&se_dev_1)) { /* Atomic context save se2 and pka1 */ INFO("%s: SE2/PKA1 atomic context save\n", __func__); if (ret == 0) { ret = tegra_se_context_save_atomic(&se_dev_2); } /* Atomic context save se */ if (ret == 0) { INFO("%s: SE1 atomic context save\n", __func__); ret = tegra_se_context_save_atomic(&se_dev_1); } if (ret == 0) { INFO("%s: SE atomic context save done\n", __func__); } } else if (!tegra_se_atomic_save_enabled(&se_dev_2) && !tegra_se_atomic_save_enabled(&se_dev_1)) { /* SW context save se2 and pka1 */ INFO("%s: SE2/PKA1 legacy(SW) context save\n", __func__); if (ret == 0) { ret = tegra_se_context_save_sw(&se_dev_2); } /* SW context save se */ if (ret == 0) { INFO("%s: SE1 legacy(SW) context save\n", __func__); ret = tegra_se_context_save_sw(&se_dev_1); } if (ret == 0) { INFO("%s: SE SW context save done\n", __func__); } } else { ERROR("%s: One SE set for atomic CTX save, the other is not\n", __func__); } tegra_se_disable_clocks(); return ret; } /* * Save TZRAM to shadow TZRAM in AON */ int32_t tegra_se_save_tzram(void) { uint32_t val = 0; int32_t ret = 0; uint32_t timeout; INFO("%s: SE TZRAM save start\n", __func__); tegra_se_enable_clocks(); val = (SE_TZRAM_OP_REQ_INIT | SE_TZRAM_OP_MODE_SAVE); tegra_se_write_32(&se_dev_1, SE_TZRAM_OPERATION, val); val = tegra_se_read_32(&se_dev_1, SE_TZRAM_OPERATION); for (timeout = 0; (SE_TZRAM_OP_BUSY(val) == SE_TZRAM_OP_BUSY_ON) && (timeout < TIMEOUT_100MS); timeout++) { mdelay(1); val = tegra_se_read_32(&se_dev_1, SE_TZRAM_OPERATION); } if (timeout == TIMEOUT_100MS) { ERROR("%s: ERR: TZRAM save timeout!\n", __func__); ret = -ETIMEDOUT; } if (ret == 0) { INFO("%s: SE TZRAM save done!\n", __func__); } tegra_se_disable_clocks(); return ret; } /* * The function is invoked by SE resume */ static void tegra_se_warm_boot_resume(const tegra_se_dev_t *se_dev) { uint32_t val; assert(se_dev); /* Lock RNG source to ENTROPY on resume */ val = DRBG_RO_ENT_IGNORE_MEM_ENABLE | DRBG_RO_ENT_SRC_LOCK_ENABLE | DRBG_RO_ENT_SRC_ENABLE; tegra_se_write_32(se_dev, SE_RNG_SRC_CONFIG_REG_OFFSET, val); /* Set a random value to SRK to initialize DRBG */ tegra_se_generate_srk(se_dev); } /* * The function is invoked on SC7 resume */ void tegra_se_resume(void) { tegra_se_warm_boot_resume(&se_dev_1); tegra_se_warm_boot_resume(&se_dev_2); } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c000066400000000000000000000373011355360272700257050ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Register used to clear CPU reset signals. Each CPU has two reset * signals: CPU reset (3:0) and Core reset (19:16). */ #define CPU_CMPLX_RESET_CLR 0x454 #define CPU_CORE_RESET_MASK 0x10001 /* Clock and Reset controller registers for system clock's settings */ #define SCLK_RATE 0x30 #define SCLK_BURST_POLICY 0x28 #define SCLK_BURST_POLICY_DEFAULT 0x10000000 static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER]; static bool tegra_bpmp_available = true; int32_t tegra_soc_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { int state_id = psci_get_pstate_id(power_state); const plat_params_from_bl2_t *plat_params = bl31_get_plat_params(); /* Sanity check the requested state id */ switch (state_id) { case PSTATE_ID_CORE_POWERDN: /* * Core powerdown request only for afflvl 0 */ req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id & 0xff; break; case PSTATE_ID_CLUSTER_IDLE: /* * Cluster idle request for afflvl 0 */ req_state->pwr_domain_state[MPIDR_AFFLVL0] = PSTATE_ID_CORE_POWERDN; req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id; break; case PSTATE_ID_SOC_POWERDN: /* * sc7entry-fw must be present in the system when the bpmp * firmware is not present, for a successful System Suspend * entry. */ if (!tegra_bpmp_init() && !plat_params->sc7entry_fw_base) return PSCI_E_NOT_SUPPORTED; /* * System powerdown request only for afflvl 2 */ for (uint32_t i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PLAT_SYS_SUSPEND_STATE_ID; break; default: ERROR("%s: unsupported state id (%d)\n", __func__, state_id); return PSCI_E_INVALID_PARAMS; } return PSCI_E_SUCCESS; } /******************************************************************************* * Platform handler to calculate the proper target power level at the * specified affinity level. ******************************************************************************/ plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl, const plat_local_state_t *states, unsigned int ncpu) { plat_local_state_t target = PSCI_LOCAL_STATE_RUN; int cpu = plat_my_core_pos(); int core_pos = read_mpidr() & MPIDR_CPU_MASK; uint32_t bpmp_reply, data[3], val; int ret; /* get the power state at this level */ if (lvl == MPIDR_AFFLVL1) target = *(states + core_pos); if (lvl == MPIDR_AFFLVL2) target = *(states + cpu); if ((lvl == MPIDR_AFFLVL1) && (target == PSTATE_ID_CLUSTER_IDLE)) { /* initialize the bpmp interface */ ret = tegra_bpmp_init(); if (ret != 0U) { /* * flag to indicate that BPMP firmware is not * available and the CPU has to handle entry/exit * for all power states */ tegra_bpmp_available = false; /* Cluster idle not allowed */ target = PSCI_LOCAL_STATE_RUN; /******************************************* * BPMP is not present, so handle CC6 entry * from the CPU ******************************************/ /* check if cluster idle state has been enabled */ val = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_CTRL); if (val == ENABLE_CLOSED_LOOP) { /* * Acquire the cluster idle lock to stop * other CPUs from powering up. */ tegra_fc_ccplex_pgexit_lock(); /* Cluster idle only from the last standing CPU */ if (tegra_pmc_is_last_on_cpu() && tegra_fc_is_ccx_allowed()) { /* Cluster idle allowed */ target = PSTATE_ID_CLUSTER_IDLE; } else { /* release cluster idle lock */ tegra_fc_ccplex_pgexit_unlock(); } } } else { /* Cluster power-down */ data[0] = (uint32_t)cpu; data[1] = TEGRA_PM_CC6; data[2] = TEGRA_PM_SC1; ret = tegra_bpmp_send_receive_atomic(MRQ_DO_IDLE, (void *)&data, (int)sizeof(data), (void *)&bpmp_reply, (int)sizeof(bpmp_reply)); /* check if cluster power down is allowed */ if ((ret != 0L) || (bpmp_reply != BPMP_CCx_ALLOWED)) { /* Cluster power down not allowed */ target = PSCI_LOCAL_STATE_RUN; } } } else if (((lvl == MPIDR_AFFLVL2) || (lvl == MPIDR_AFFLVL1)) && (target == PSTATE_ID_SOC_POWERDN)) { /* System Suspend */ target = PSTATE_ID_SOC_POWERDN; } else { ; /* do nothing */ } return target; } int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) { u_register_t mpidr = read_mpidr(); const plat_local_state_t *pwr_domain_state = target_state->pwr_domain_state; unsigned int stateid_afflvl2 = pwr_domain_state[MPIDR_AFFLVL2]; unsigned int stateid_afflvl1 = pwr_domain_state[MPIDR_AFFLVL1]; unsigned int stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0]; uint32_t cfg; int ret = PSCI_E_SUCCESS; uint32_t val; if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { assert((stateid_afflvl0 == PLAT_MAX_OFF_STATE) || (stateid_afflvl0 == PSTATE_ID_SOC_POWERDN)); assert((stateid_afflvl1 == PLAT_MAX_OFF_STATE) || (stateid_afflvl1 == PSTATE_ID_SOC_POWERDN)); if (tegra_chipid_is_t210_b01()) { /* Suspend se/se2 and pka1 */ if (tegra_se_suspend() != 0) { ret = PSCI_E_INTERN_FAIL; } } } else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_IDLE) { assert(stateid_afflvl0 == PSTATE_ID_CORE_POWERDN); if (!tegra_bpmp_available) { /* * When disabled, DFLL loses its state. Enable * open loop state for the DFLL as we dont want * garbage values being written to the pmic * when we enter cluster idle state. */ mmio_write_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_CTRL, ENABLE_OPEN_LOOP); /* Find if the platform uses OVR2/MAX77621 PMIC */ cfg = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_OUTPUT_CFG); if (cfg & DFLL_OUTPUT_CFG_CLK_EN_BIT) { /* OVR2 */ /* PWM tristate */ val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM); val |= PINMUX_PWM_TRISTATE; mmio_write_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM, val); /* * SCRATCH201[1] is being used to identify CPU * PMIC in warmboot code. * 0 : OVR2 * 1 : MAX77621 */ tegra_pmc_write_32(PMC_SCRATCH201, 0x0); } else { /* MAX77621 */ tegra_pmc_write_32(PMC_SCRATCH201, 0x2); } } /* Prepare for cluster idle */ tegra_fc_cluster_idle(mpidr); } else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) { /* Prepare for cpu powerdn */ tegra_fc_cpu_powerdn(mpidr); } else { ERROR("%s: Unknown state id (%d, %d, %d)\n", __func__, stateid_afflvl2, stateid_afflvl1, stateid_afflvl0); ret = PSCI_E_NOT_SUPPORTED; } return ret; } static void tegra_reset_all_dma_masters(void) { uint32_t val, mask; /* * Reset all possible DMA masters in the system. */ val = GPU_RESET_BIT; mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET, val); val = NVENC_RESET_BIT | TSECB_RESET_BIT | APE_RESET_BIT | NVJPG_RESET_BIT | NVDEC_RESET_BIT; mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_Y, val); val = HOST1X_RESET_BIT | ISP_RESET_BIT | USBD_RESET_BIT | VI_RESET_BIT | SDMMC4_RESET_BIT | SDMMC1_RESET_BIT | SDMMC2_RESET_BIT; mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_L, val); val = USB2_RESET_BIT | APBDMA_RESET_BIT | AHBDMA_RESET_BIT; mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_H, val); val = XUSB_DEV_RESET_BIT | XUSB_HOST_RESET_BIT | TSEC_RESET_BIT | PCIE_RESET_BIT | SDMMC3_RESET_BIT; mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_U, val); val = SE_RESET_BIT | HDA_RESET_BIT | SATA_RESET_BIT; mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_V, val); /* * If any of the DMA masters are still alive, assume * that the system has been compromised and reboot. */ val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET); mask = GPU_RESET_BIT; if ((val & mask) != mask) tegra_pmc_system_reset(); mask = NVENC_RESET_BIT | TSECB_RESET_BIT | APE_RESET_BIT | NVJPG_RESET_BIT | NVDEC_RESET_BIT; val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_Y); if ((val & mask) != mask) tegra_pmc_system_reset(); mask = HOST1X_RESET_BIT | ISP_RESET_BIT | USBD_RESET_BIT | VI_RESET_BIT | SDMMC4_RESET_BIT | SDMMC1_RESET_BIT | SDMMC2_RESET_BIT; val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_L); if ((val & mask) != mask) tegra_pmc_system_reset(); mask = USB2_RESET_BIT | APBDMA_RESET_BIT | AHBDMA_RESET_BIT; val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_H); if ((val & mask) != mask) tegra_pmc_system_reset(); mask = XUSB_DEV_RESET_BIT | XUSB_HOST_RESET_BIT | TSEC_RESET_BIT | PCIE_RESET_BIT | SDMMC3_RESET_BIT; val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_U); if ((val & mask) != mask) tegra_pmc_system_reset(); val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_V); mask = SE_RESET_BIT | HDA_RESET_BIT | SATA_RESET_BIT; if ((val & mask) != mask) tegra_pmc_system_reset(); } int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state) { u_register_t mpidr = read_mpidr(); const plat_local_state_t *pwr_domain_state = target_state->pwr_domain_state; unsigned int stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL]; const plat_params_from_bl2_t *plat_params = bl31_get_plat_params(); uint32_t val; if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { if (tegra_chipid_is_t210_b01()) { /* Save tzram contents */ tegra_se_save_tzram(); } /* de-init the interface */ tegra_bpmp_suspend(); /* * The CPU needs to load the System suspend entry firmware * if nothing is running on the BPMP. */ if (!tegra_bpmp_available) { /* * BPMP firmware is not running on the co-processor, so * we need to explicitly load the firmware to enable * entry/exit to/from System Suspend and set the BPMP * on its way. */ /* Power off BPMP before we proceed */ tegra_fc_bpmp_off(); /* bond out IRAM banks B, C and D */ mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_BOND_OUT_U, IRAM_B_LOCK_BIT | IRAM_C_LOCK_BIT | IRAM_D_LOCK_BIT); /* bond out APB/AHB DMAs */ mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_BOND_OUT_H, APB_DMA_LOCK_BIT | AHB_DMA_LOCK_BIT); /* Power off BPMP before we proceed */ tegra_fc_bpmp_off(); /* * Reset all the hardware blocks that can act as DMA * masters on the bus. */ tegra_reset_all_dma_masters(); /* clean up IRAM of any cruft */ zeromem((void *)(uintptr_t)TEGRA_IRAM_BASE, TEGRA_IRAM_A_SIZE); /* Copy the firmware to BPMP's internal RAM */ (void)memcpy((void *)(uintptr_t)TEGRA_IRAM_BASE, (const void *)(plat_params->sc7entry_fw_base + SC7ENTRY_FW_HEADER_SIZE_BYTES), plat_params->sc7entry_fw_size - SC7ENTRY_FW_HEADER_SIZE_BYTES); /* Power on the BPMP and execute from IRAM base */ tegra_fc_bpmp_on(TEGRA_IRAM_BASE); /* Wait until BPMP powers up */ do { val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET); } while (val != SIGN_OF_LIFE); } /* enter system suspend */ tegra_fc_soc_powerdn(mpidr); } return PSCI_E_SUCCESS; } int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state) { const plat_params_from_bl2_t *plat_params = bl31_get_plat_params(); uint32_t cfg; uint32_t val, entrypoint = 0; uint64_t offset; /* platform parameter passed by the previous bootloader */ if (plat_params->l2_ecc_parity_prot_dis != 1) { /* Enable ECC Parity Protection for Cortex-A57 CPUs */ val = read_l2ctlr_el1(); val |= (uint64_t)CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT; write_l2ctlr_el1(val); } /* * Check if we are exiting from SOC_POWERDN. */ if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] == PLAT_SYS_SUSPEND_STATE_ID) { /* * Security engine resume */ if (tegra_chipid_is_t210_b01()) { tegra_se_resume(); } /* * Lock scratch registers which hold the CPU vectors */ tegra_pmc_lock_cpu_vectors(); /* * Enable WRAP to INCR burst type conversions for * incoming requests on the AXI slave ports. */ val = mmio_read_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG); val &= ~ENABLE_UNSUP_TX_ERRORS; val |= ENABLE_WRAP_TO_INCR_BURSTS; mmio_write_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG, val); /* * Restore Boot and Power Management Processor (BPMP) reset * address and reset it, if it is supported by the platform. */ if (!tegra_bpmp_available) { tegra_fc_bpmp_off(); } else { entrypoint = tegra_pmc_read_32(PMC_SCRATCH39); tegra_fc_bpmp_on(entrypoint); /* initialise the interface */ tegra_bpmp_resume(); } /* sc7entry-fw is part of TZDRAM area */ if (plat_params->sc7entry_fw_base != 0U) { offset = plat_params->tzdram_base - plat_params->sc7entry_fw_base; tegra_memctrl_tzdram_setup(plat_params->sc7entry_fw_base, plat_params->tzdram_size + offset); /* restrict PMC access to secure world */ val = mmio_read_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE); val |= PMC_SECURITY_EN_BIT; mmio_write_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE, val); } } /* * Check if we are exiting cluster idle state */ if (target_state->pwr_domain_state[MPIDR_AFFLVL1] == PSTATE_ID_CLUSTER_IDLE) { if (!tegra_bpmp_available) { /* PWM un-tristate */ cfg = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_OUTPUT_CFG); if (cfg & DFLL_OUTPUT_CFG_CLK_EN_BIT) { val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM); val &= ~PINMUX_PWM_TRISTATE; mmio_write_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM, val); /* make sure the setting took effect */ val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM); assert((val & PINMUX_PWM_TRISTATE) == 0U); } /* * Restore operation mode for the DFLL ring * oscillator */ mmio_write_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_CTRL, ENABLE_CLOSED_LOOP); /* release cluster idle lock */ tegra_fc_ccplex_pgexit_unlock(); } } /* * T210 has a dedicated ARMv7 boot and power mgmt processor, BPMP. It's * used for power management and boot purposes. Inform the BPMP that * we have completed the cluster power up. */ tegra_fc_lock_active_cluster(); /* * Resume PMC hardware block for Tegra210 platforms supporting sc7entry-fw */ if (!tegra_chipid_is_t210_b01() && (plat_params->sc7entry_fw_base != 0U)) tegra_pmc_resume(); return PSCI_E_SUCCESS; } int tegra_soc_pwr_domain_on(u_register_t mpidr) { int cpu = mpidr & MPIDR_CPU_MASK; uint32_t mask = CPU_CORE_RESET_MASK << cpu; /* Deassert CPU reset signals */ mmio_write_32(TEGRA_CAR_RESET_BASE + CPU_CMPLX_RESET_CLR, mask); /* Turn on CPU using flow controller or PMC */ if (cpu_powergate_mask[cpu] == 0) { tegra_pmc_cpu_on(cpu); cpu_powergate_mask[cpu] = 1; } else { tegra_fc_cpu_on(cpu); } return PSCI_E_SUCCESS; } int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) { tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK); return PSCI_E_SUCCESS; } int tegra_soc_prepare_system_reset(void) { /* * Set System Clock (SCLK) to POR default so that the clock source * for the PMC APB clock would not be changed due to system reset. */ mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_BURST_POLICY, SCLK_BURST_POLICY_DEFAULT); mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_RATE, 0); /* Wait 1 ms to make sure clock source/device logic is stabilized. */ mdelay(1); return PSCI_E_SUCCESS; } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t210/plat_secondary.c000066400000000000000000000021031355360272700250460ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #define SB_CSR 0x0 #define SB_CSR_NS_RST_VEC_WR_DIS (1 << 1) /* CPU reset vector */ #define SB_AA64_RESET_LOW 0x30 /* width = 31:0 */ #define SB_AA64_RESET_HI 0x34 /* width = 11:0 */ extern void tegra_secure_entrypoint(void); /******************************************************************************* * Setup secondary CPU vectors ******************************************************************************/ void plat_secondary_setup(void) { uint32_t val; uint64_t reset_addr = (uint64_t)tegra_secure_entrypoint; INFO("Setting up secondary CPU boot\n"); /* setup secondary CPU vector */ mmio_write_32(TEGRA_SB_BASE + SB_AA64_RESET_LOW, (reset_addr & 0xFFFFFFFF) | 1); val = reset_addr >> 32; mmio_write_32(TEGRA_SB_BASE + SB_AA64_RESET_HI, val & 0x7FF); /* configure PMC */ tegra_pmc_cpu_setup(reset_addr); tegra_pmc_lock_cpu_vectors(); } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t210/plat_setup.c000066400000000000000000000157711355360272700242360ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* sets of MMIO ranges setup */ #define MMIO_RANGE_0_ADDR 0x50000000 #define MMIO_RANGE_1_ADDR 0x60000000 #define MMIO_RANGE_2_ADDR 0x70000000 #define MMIO_RANGE_SIZE 0x200000 /* * Table of regions to map using the MMU. */ static const mmap_region_t tegra_mmap[] = { MAP_REGION_FLAT(TEGRA_IRAM_BASE, 0x40000, /* 256KB */ MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(MMIO_RANGE_0_ADDR, MMIO_RANGE_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(MMIO_RANGE_1_ADDR, MMIO_RANGE_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(MMIO_RANGE_2_ADDR, MMIO_RANGE_SIZE, MT_DEVICE | MT_RW | MT_SECURE), {0} }; /******************************************************************************* * Set up the pagetables as per the platform memory map & initialize the MMU ******************************************************************************/ const mmap_region_t *plat_get_mmio_map(void) { /* Add the map region for security engine SE2 */ if (tegra_chipid_is_t210_b01()) { mmap_add_region((uint64_t)TEGRA_SE2_BASE, (uint64_t)TEGRA_SE2_BASE, (uint64_t)TEGRA_SE2_RANGE_SIZE, MT_DEVICE | MT_RW | MT_SECURE); } /* MMIO space */ return tegra_mmap; } /******************************************************************************* * The Tegra power domain tree has a single system level power domain i.e. a * single root node. The first entry in the power domain descriptor specifies * the number of power domains at the highest power level. ******************************************************************************* */ const unsigned char tegra_power_domain_tree_desc[] = { /* No of root nodes */ 1, /* No of clusters */ PLATFORM_CLUSTER_COUNT, /* No of CPU cores - cluster0 */ PLATFORM_MAX_CPUS_PER_CLUSTER, /* No of CPU cores - cluster1 */ PLATFORM_MAX_CPUS_PER_CLUSTER }; /******************************************************************************* * This function returns the Tegra default topology tree information. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { return tegra_power_domain_tree_desc; } /******************************************************************************* * Handler to get the System Counter Frequency ******************************************************************************/ unsigned int plat_get_syscnt_freq2(void) { return 19200000; } /******************************************************************************* * Maximum supported UART controllers ******************************************************************************/ #define TEGRA210_MAX_UART_PORTS 5 /******************************************************************************* * This variable holds the UART port base addresses ******************************************************************************/ static uint32_t tegra210_uart_addresses[TEGRA210_MAX_UART_PORTS + 1] = { 0, /* undefined - treated as an error case */ TEGRA_UARTA_BASE, TEGRA_UARTB_BASE, TEGRA_UARTC_BASE, TEGRA_UARTD_BASE, TEGRA_UARTE_BASE, }; /******************************************************************************* * Retrieve the UART controller base to be used as the console ******************************************************************************/ uint32_t plat_get_console_from_id(int id) { if (id > TEGRA210_MAX_UART_PORTS) return 0; return tegra210_uart_addresses[id]; } /******************************************************************************* * Handler for early platform setup ******************************************************************************/ void plat_early_platform_setup(void) { const plat_params_from_bl2_t *plat_params = bl31_get_plat_params(); uint64_t val; /* platform parameter passed by the previous bootloader */ if (plat_params->l2_ecc_parity_prot_dis != 1) { /* Enable ECC Parity Protection for Cortex-A57 CPUs */ val = read_l2ctlr_el1(); val |= (uint64_t)CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT; write_l2ctlr_el1(val); } /* Initialize security engine driver */ if (tegra_chipid_is_t210_b01()) { tegra_se_init(); } } /* Secure IRQs for Tegra186 */ static const interrupt_prop_t tegra210_interrupt_props[] = { INTR_PROP_DESC(TEGRA210_WDT_CPU_LEGACY_FIQ, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE), }; void plat_late_platform_setup(void) { const plat_params_from_bl2_t *plat_params = bl31_get_plat_params(); uint64_t sc7entry_end, offset; int ret; uint32_t val; /* memmap TZDRAM area containing the SC7 Entry Firmware */ if (plat_params->sc7entry_fw_base && plat_params->sc7entry_fw_size) { assert(plat_params->sc7entry_fw_size <= TEGRA_IRAM_A_SIZE); /* * Verify that the SC7 entry firmware resides inside the TZDRAM * aperture, _before_ the BL31 code and the start address is * exactly 1MB from BL31 base. */ /* sc7entry-fw must be _before_ BL31 base */ assert(plat_params->tzdram_base > plat_params->sc7entry_fw_base); sc7entry_end = plat_params->sc7entry_fw_base + plat_params->sc7entry_fw_size; assert(sc7entry_end < plat_params->tzdram_base); /* sc7entry-fw start must be exactly 1MB behind BL31 base */ offset = plat_params->tzdram_base - plat_params->sc7entry_fw_base; assert(offset == 0x100000); /* secure TZDRAM area */ tegra_memctrl_tzdram_setup(plat_params->sc7entry_fw_base, plat_params->tzdram_size + offset); /* power off BPMP processor until SC7 entry */ tegra_fc_bpmp_off(); /* memmap SC7 entry firmware code */ ret = mmap_add_dynamic_region(plat_params->sc7entry_fw_base, plat_params->sc7entry_fw_base, plat_params->sc7entry_fw_size, MT_SECURE | MT_RO_DATA); assert(ret == 0); /* restrict PMC access to secure world */ val = mmio_read_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE); val |= PMC_SECURITY_EN_BIT; mmio_write_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE, val); } } /******************************************************************************* * Initialize the GIC and SGIs ******************************************************************************/ void plat_gic_setup(void) { tegra_gic_setup(tegra210_interrupt_props, ARRAY_SIZE(tegra210_interrupt_props)); tegra_gic_init(); /* Enable handling for FIQs */ tegra_fiq_handler_setup(); /* * Enable routing watchdog FIQs from the flow controller to * the GICD. */ tegra_fc_enable_fiq_to_ccplex_routing(); } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t210/plat_sip_calls.c000066400000000000000000000051051355360272700250350ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /******************************************************************************* * PMC parameters ******************************************************************************/ #define PMC_READ U(0xaa) #define PMC_WRITE U(0xbb) /******************************************************************************* * Tegra210 SiP SMCs ******************************************************************************/ #define TEGRA_SIP_PMC_COMMANDS U(0xC2FFFE00) /******************************************************************************* * This function is responsible for handling all T210 SiP calls ******************************************************************************/ int plat_sip_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, const void *cookie, void *handle, uint64_t flags) { uint32_t val, ns; /* Determine which security state this SMC originated from */ ns = is_caller_non_secure(flags); if (!ns) SMC_RET1(handle, SMC_UNK); switch (smc_fid) { case TEGRA_SIP_PMC_COMMANDS: /* check the address is within PMC range and is 4byte aligned */ if ((x2 >= TEGRA_PMC_SIZE) || (x2 & 0x3)) return -EINVAL; /* pmc_secure_scratch registers are not accessible */ if (((x2 >= PMC_SECURE_SCRATCH0) && (x2 <= PMC_SECURE_SCRATCH5)) || ((x2 >= PMC_SECURE_SCRATCH6) && (x2 <= PMC_SECURE_SCRATCH7)) || ((x2 >= PMC_SECURE_SCRATCH8) && (x2 <= PMC_SECURE_SCRATCH79)) || ((x2 >= PMC_SECURE_SCRATCH80) && (x2 <= PMC_SECURE_SCRATCH119))) return -EFAULT; /* PMC secure-only registers are not accessible */ if ((x2 == PMC_DPD_ENABLE_0) || (x2 == PMC_FUSE_CONTROL_0) || (x2 == PMC_CRYPTO_OP_0)) return -EFAULT; /* Perform PMC read/write */ if (x1 == PMC_READ) { val = mmio_read_32((uint32_t)(TEGRA_PMC_BASE + x2)); write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X1, val); } else if (x1 == PMC_WRITE) { mmio_write_32((uint32_t)(TEGRA_PMC_BASE + x2), (uint32_t)x3); } else { return -EINVAL; } break; default: ERROR("%s: unsupported function ID\n", __func__); return -ENOTSUP; } return 0; } trusted-firmware-a-2.2/plat/nvidia/tegra/soc/t210/platform_t210.mk000066400000000000000000000032061355360272700246230ustar00rootroot00000000000000# # Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # TZDRAM_BASE := 0xFF800000 $(eval $(call add_define,TZDRAM_BASE)) ERRATA_TEGRA_INVALIDATE_BTB_AT_BOOT := 1 $(eval $(call add_define,ERRATA_TEGRA_INVALIDATE_BTB_AT_BOOT)) PLATFORM_CLUSTER_COUNT := 2 $(eval $(call add_define,PLATFORM_CLUSTER_COUNT)) PLATFORM_MAX_CPUS_PER_CLUSTER := 4 $(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER)) MAX_XLAT_TABLES := 10 $(eval $(call add_define,MAX_XLAT_TABLES)) MAX_MMAP_REGIONS := 16 $(eval $(call add_define,MAX_MMAP_REGIONS)) ENABLE_WDT_LEGACY_FIQ_HANDLING := 1 $(eval $(call add_define,ENABLE_WDT_LEGACY_FIQ_HANDLING)) PLAT_INCLUDES += -I${SOC_DIR}/drivers/se BL31_SOURCES += drivers/ti/uart/aarch64/16550_console.S \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S \ ${COMMON_DIR}/drivers/bpmp/bpmp.c \ ${COMMON_DIR}/drivers/flowctrl/flowctrl.c \ ${COMMON_DIR}/drivers/memctrl/memctrl_v1.c \ ${SOC_DIR}/plat_psci_handlers.c \ ${SOC_DIR}/plat_setup.c \ ${SOC_DIR}/drivers/se/security_engine.c \ ${SOC_DIR}/plat_secondary.c \ ${SOC_DIR}/plat_sip_calls.c # Enable workarounds for selected Cortex-A57 erratas. A57_DISABLE_NON_TEMPORAL_HINT := 1 ERRATA_A57_826974 := 1 ERRATA_A57_826977 := 1 ERRATA_A57_828024 := 1 ERRATA_A57_829520 := 1 ERRATA_A57_833471 := 1 # Enable workarounds for selected Cortex-A53 erratas. A53_DISABLE_NON_TEMPORAL_HINT := 1 ERRATA_A53_826319 := 1 ERRATA_A53_836870 := 1 ERRATA_A53_855873 := 1 # Skip L1 $ flush when powering down Cortex-A57 CPUs SKIP_A57_L1_FLUSH_PWR_DWN := 1 trusted-firmware-a-2.2/plat/qemu/000077500000000000000000000000001355360272700170205ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/qemu/common/000077500000000000000000000000001355360272700203105ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/qemu/common/aarch32/000077500000000000000000000000001355360272700215335ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/qemu/common/aarch32/plat_helpers.S000066400000000000000000000067631355360272700243550ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl plat_my_core_pos .globl plat_get_my_entrypoint .globl platform_mem_init .globl plat_qemu_calc_core_pos .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush .globl plat_secondary_cold_boot_setup .globl plat_get_my_entrypoint .globl plat_is_my_cpu_primary func plat_my_core_pos ldcopr r0, MPIDR b plat_qemu_calc_core_pos endfunc plat_my_core_pos /* * unsigned int plat_qemu_calc_core_pos(u_register_t mpidr); * With this function: CorePos = (ClusterId * 4) + CoreId */ func plat_qemu_calc_core_pos and r1, r0, #MPIDR_CPU_MASK and r0, r0, #MPIDR_CLUSTER_MASK add r0, r1, r0, LSR #6 bx lr endfunc plat_qemu_calc_core_pos /* ----------------------------------------------------- * unsigned int plat_is_my_cpu_primary (void); * * Find out whether the current cpu is the primary * cpu. * ----------------------------------------------------- */ func plat_is_my_cpu_primary ldcopr r0, MPIDR ldr r1, =(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) and r0, r1 cmp r0, #QEMU_PRIMARY_CPU moveq r0, #1 movne r0, #0 bx lr endfunc plat_is_my_cpu_primary /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions * needed for a secondary cpu after a cold reset e.g * mark the cpu's presence, mechanism to place it in a * holding pen etc. * ----------------------------------------------------- */ func plat_secondary_cold_boot_setup /* Calculate address of our hold entry */ bl plat_my_core_pos lsl r0, r0, #PLAT_QEMU_HOLD_ENTRY_SHIFT mov_imm r2, PLAT_QEMU_HOLD_BASE /* Wait until we have a go */ poll_mailbox: ldr r1, [r2, r0] cmp r1, #0 beq 1f mov_imm r0, PLAT_QEMU_TRUSTED_MAILBOX_BASE ldr r1, [r0] bx r1 1: wfe b poll_mailbox endfunc plat_secondary_cold_boot_setup func plat_get_my_entrypoint /* TODO support warm boot */ mov r0, #0 bx lr endfunc plat_get_my_entrypoint func platform_mem_init bx lr endfunc platform_mem_init /* --------------------------------------------- * int plat_crash_console_init(void) * Function to initialize the crash console * without a C Runtime to print crash report. * Clobber list : x0, x1, x2 * --------------------------------------------- */ func plat_crash_console_init mov_imm r0, PLAT_QEMU_CRASH_UART_BASE mov_imm r1, PLAT_QEMU_CRASH_UART_CLK_IN_HZ mov_imm r2, PLAT_QEMU_CONSOLE_BAUDRATE b console_pl011_core_init endfunc plat_crash_console_init /* --------------------------------------------- * int plat_crash_console_putc(int c) * Function to print a character on the crash * console without a C Runtime. * Clobber list : x1, x2 * --------------------------------------------- */ func plat_crash_console_putc mov_imm r1, PLAT_QEMU_CRASH_UART_BASE b console_pl011_core_putc endfunc plat_crash_console_putc /* --------------------------------------------- * int plat_crash_console_flush(int c) * Function to force a write of all buffered * data that hasn't been output. * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func plat_crash_console_flush mov_imm r0, PLAT_QEMU_CRASH_UART_BASE b console_pl011_core_flush endfunc plat_crash_console_flush trusted-firmware-a-2.2/plat/qemu/common/aarch64/000077500000000000000000000000001355360272700215405ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/qemu/common/aarch64/plat_helpers.S000066400000000000000000000066671355360272700243650ustar00rootroot00000000000000/* * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl plat_my_core_pos .globl plat_get_my_entrypoint .globl platform_mem_init .globl plat_qemu_calc_core_pos .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush .globl plat_secondary_cold_boot_setup .globl plat_get_my_entrypoint .globl plat_is_my_cpu_primary func plat_my_core_pos mrs x0, mpidr_el1 b plat_qemu_calc_core_pos endfunc plat_my_core_pos /* * unsigned int plat_qemu_calc_core_pos(u_register_t mpidr); * With this function: CorePos = (ClusterId * 4) + CoreId */ func plat_qemu_calc_core_pos and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 ret endfunc plat_qemu_calc_core_pos /* ----------------------------------------------------- * unsigned int plat_is_my_cpu_primary (void); * * Find out whether the current cpu is the primary * cpu. * ----------------------------------------------------- */ func plat_is_my_cpu_primary mrs x0, mpidr_el1 and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) cmp x0, #QEMU_PRIMARY_CPU cset w0, eq ret endfunc plat_is_my_cpu_primary /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions * needed for a secondary cpu after a cold reset e.g * mark the cpu's presence, mechanism to place it in a * holding pen etc. * ----------------------------------------------------- */ func plat_secondary_cold_boot_setup /* Calculate address of our hold entry */ bl plat_my_core_pos lsl x0, x0, #PLAT_QEMU_HOLD_ENTRY_SHIFT mov_imm x2, PLAT_QEMU_HOLD_BASE /* Wait until we have a go */ poll_mailbox: ldr x1, [x2, x0] cbz x1, 1f mov_imm x0, PLAT_QEMU_TRUSTED_MAILBOX_BASE ldr x1, [x0] br x1 1: wfe b poll_mailbox endfunc plat_secondary_cold_boot_setup func plat_get_my_entrypoint /* TODO support warm boot */ mov x0, #0 ret endfunc plat_get_my_entrypoint func platform_mem_init ret endfunc platform_mem_init /* --------------------------------------------- * int plat_crash_console_init(void) * Function to initialize the crash console * without a C Runtime to print crash report. * Clobber list : x0, x1, x2 * --------------------------------------------- */ func plat_crash_console_init mov_imm x0, PLAT_QEMU_CRASH_UART_BASE mov_imm x1, PLAT_QEMU_CRASH_UART_CLK_IN_HZ mov_imm x2, PLAT_QEMU_CONSOLE_BAUDRATE b console_pl011_core_init endfunc plat_crash_console_init /* --------------------------------------------- * int plat_crash_console_putc(int c) * Function to print a character on the crash * console without a C Runtime. * Clobber list : x1, x2 * --------------------------------------------- */ func plat_crash_console_putc mov_imm x1, PLAT_QEMU_CRASH_UART_BASE b console_pl011_core_putc endfunc plat_crash_console_putc /* --------------------------------------------- * int plat_crash_console_flush(int c) * Function to force a write of all buffered * data that hasn't been output. * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func plat_crash_console_flush mov_imm x0, PLAT_QEMU_CRASH_UART_BASE b console_pl011_core_flush endfunc plat_crash_console_flush trusted-firmware-a-2.2/plat/qemu/common/include/000077500000000000000000000000001355360272700217335ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/qemu/common/include/plat_macros.S000066400000000000000000000012061355360272700243620ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S #include #include /* --------------------------------------------- * The below required platform porting macro * prints out relevant GIC and CCI registers * whenever an unhandled exception is taken in * BL31. * Clobbers: x0 - x10, x16, x17, sp * --------------------------------------------- */ .macro plat_crash_print_regs mov_imm x17, GICC_BASE mov_imm x16, GICD_BASE arm_print_gic_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/qemu/common/qemu_bl1_setup.c000066400000000000000000000033421355360272700234030ustar00rootroot00000000000000/* * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "qemu_private.h" /* Data structure which holds the extents of the trusted SRAM for BL1*/ static meminfo_t bl1_tzram_layout; meminfo_t *bl1_plat_sec_mem_layout(void) { return &bl1_tzram_layout; } /******************************************************************************* * Perform any BL1 specific platform actions. ******************************************************************************/ void bl1_early_platform_setup(void) { /* Initialize the console to provide early debug support */ qemu_console_init(); /* Allow BL1 to see the whole Trusted RAM */ bl1_tzram_layout.total_base = BL_RAM_BASE; bl1_tzram_layout.total_size = BL_RAM_SIZE; } /****************************************************************************** * Perform the very early platform specific architecture setup. This only * does basic initialization. Later architectural setup (bl1_arch_setup()) * does not do anything platform specific. *****************************************************************************/ #ifdef __aarch64__ #define QEMU_CONFIGURE_BL1_MMU(...) qemu_configure_mmu_el3(__VA_ARGS__) #else #define QEMU_CONFIGURE_BL1_MMU(...) qemu_configure_mmu_svc_mon(__VA_ARGS__) #endif void bl1_plat_arch_setup(void) { QEMU_CONFIGURE_BL1_MMU(bl1_tzram_layout.total_base, bl1_tzram_layout.total_size, BL_CODE_BASE, BL1_CODE_END, BL1_RO_DATA_BASE, BL1_RO_DATA_END, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); } void bl1_platform_setup(void) { plat_qemu_io_setup(); } trusted-firmware-a-2.2/plat/qemu/common/qemu_bl2_mem_params_desc.c000066400000000000000000000112261355360272700253630ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /******************************************************************************* * Following descriptor provides BL image/ep information that gets used * by BL2 to load the images and also subset of this information is * passed to next BL image. The image loading sequence is managed by * populating the images in required loading order. The image execution * sequence is managed by populating the `next_handoff_image_id` with * the next executable image id. ******************************************************************************/ static bl_mem_params_node_t bl2_mem_params_descs[] = { #ifdef EL3_PAYLOAD_BASE /* Fill EL3 payload related information (BL31 is EL3 payload) */ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = EL3_PAYLOAD_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP | IMAGE_ATTRIB_SKIP_LOADING), .next_handoff_image_id = INVALID_IMAGE_ID, }, #else /* EL3_PAYLOAD_BASE */ #ifdef __aarch64__ /* Fill BL31 related information */ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = BL31_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), # if DEBUG .ep_info.args.arg1 = QEMU_BL31_PLAT_PARAM_VAL, # endif SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP), .image_info.image_base = BL31_BASE, .image_info.image_max_size = BL31_LIMIT - BL31_BASE, # ifdef QEMU_LOAD_BL32 .next_handoff_image_id = BL32_IMAGE_ID, # else .next_handoff_image_id = BL33_IMAGE_ID, # endif }, #endif /* __aarch64__ */ # ifdef QEMU_LOAD_BL32 #ifdef __aarch64__ #define BL32_EP_ATTRIBS (SECURE | EXECUTABLE) #define BL32_IMG_ATTRIBS 0 #else #define BL32_EP_ATTRIBS (SECURE | EXECUTABLE | EP_FIRST_EXE) #define BL32_IMG_ATTRIBS IMAGE_ATTRIB_PLAT_SETUP #endif /* Fill BL32 related information */ { .image_id = BL32_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, BL32_EP_ATTRIBS), .ep_info.pc = BL32_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, BL32_IMG_ATTRIBS), .image_info.image_base = BL32_BASE, .image_info.image_max_size = BL32_LIMIT - BL32_BASE, .next_handoff_image_id = BL33_IMAGE_ID, }, /* * Fill BL32 external 1 related information. * A typical use for extra1 image is with OP-TEE where it is the * pager image. */ { .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), .image_info.image_base = BL32_BASE, .image_info.image_max_size = BL32_LIMIT - BL32_BASE, .next_handoff_image_id = INVALID_IMAGE_ID, }, /* * Fill BL32 external 2 related information. * A typical use for extra2 image is with OP-TEE where it is the * paged image. */ { .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), #if defined(SPD_opteed) || defined(AARCH32_SP_OPTEE) .image_info.image_base = QEMU_OPTEE_PAGEABLE_LOAD_BASE, .image_info.image_max_size = QEMU_OPTEE_PAGEABLE_LOAD_SIZE, #endif .next_handoff_image_id = INVALID_IMAGE_ID, }, # endif /* QEMU_LOAD_BL32 */ /* Fill BL33 related information */ { .image_id = BL33_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), # ifdef PRELOADED_BL33_BASE .ep_info.pc = PRELOADED_BL33_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), # else /* PRELOADED_BL33_BASE */ .ep_info.pc = NS_IMAGE_OFFSET, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = NS_IMAGE_OFFSET, .image_info.image_max_size = NS_IMAGE_MAX_SIZE, # endif /* !PRELOADED_BL33_BASE */ .next_handoff_image_id = INVALID_IMAGE_ID, } #endif /* !EL3_PAYLOAD_BASE */ }; REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) trusted-firmware-a-2.2/plat/qemu/common/qemu_bl2_setup.c000066400000000000000000000133321355360272700234040ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include "qemu_private.h" /* Data structure which holds the extents of the trusted SRAM for BL2 */ static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE); void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { meminfo_t *mem_layout = (void *)arg1; /* Initialize the console to provide early debug support */ qemu_console_init(); /* Setup the BL2 memory layout */ bl2_tzram_layout = *mem_layout; plat_qemu_io_setup(); } static void security_setup(void) { /* * This is where a TrustZone address space controller and other * security related peripherals, would be configured. */ } static void update_dt(void) { int ret; void *fdt = (void *)(uintptr_t)PLAT_QEMU_DT_BASE; ret = fdt_open_into(fdt, fdt, PLAT_QEMU_DT_MAX_SIZE); if (ret < 0) { ERROR("Invalid Device Tree at %p: error %d\n", fdt, ret); return; } if (dt_add_psci_node(fdt)) { ERROR("Failed to add PSCI Device Tree node\n"); return; } if (dt_add_psci_cpu_enable_methods(fdt)) { ERROR("Failed to add PSCI cpu enable methods in Device Tree\n"); return; } ret = fdt_pack(fdt); if (ret < 0) ERROR("Failed to pack Device Tree at %p: error %d\n", fdt, ret); } void bl2_platform_setup(void) { security_setup(); update_dt(); /* TODO Initialize timer */ } #ifdef __aarch64__ #define QEMU_CONFIGURE_BL2_MMU(...) qemu_configure_mmu_el1(__VA_ARGS__) #else #define QEMU_CONFIGURE_BL2_MMU(...) qemu_configure_mmu_svc_mon(__VA_ARGS__) #endif void bl2_plat_arch_setup(void) { QEMU_CONFIGURE_BL2_MMU(bl2_tzram_layout.total_base, bl2_tzram_layout.total_size, BL_CODE_BASE, BL_CODE_END, BL_RO_DATA_BASE, BL_RO_DATA_END, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); } /******************************************************************************* * Gets SPSR for BL32 entry ******************************************************************************/ static uint32_t qemu_get_spsr_for_bl32_entry(void) { #ifdef __aarch64__ /* * The Secure Payload Dispatcher service is responsible for * setting the SPSR prior to entry into the BL3-2 image. */ return 0; #else return SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS); #endif } /******************************************************************************* * Gets SPSR for BL33 entry ******************************************************************************/ static uint32_t qemu_get_spsr_for_bl33_entry(void) { uint32_t spsr; #ifdef __aarch64__ unsigned int mode; /* Figure out what mode we enter the non-secure world in */ mode = (el_implemented(2) != EL_IMPL_NONE) ? MODE_EL2 : MODE_EL1; /* * TODO: Consider the possibility of specifying the SPSR in * the FIP ToC and allowing the platform to have a say as * well. */ spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); #else spsr = SPSR_MODE32(MODE32_svc, plat_get_ns_image_entrypoint() & 0x1, SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS); #endif return spsr; } static int qemu_bl2_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(SPD_opteed) || defined(AARCH32_SP_OPTEE) bl_mem_params_node_t *pager_mem_params = NULL; bl_mem_params_node_t *paged_mem_params = NULL; #endif assert(bl_mem_params); switch (image_id) { case BL32_IMAGE_ID: #if defined(SPD_opteed) || 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); err = parse_optee_header(&bl_mem_params->ep_info, &pager_mem_params->image_info, &paged_mem_params->image_info); if (err != 0) { WARN("OPTEE header parse error.\n"); } #if defined(SPD_opteed) /* * OP-TEE expect to receive DTB address in x2. * This will be copied into x2 by dispatcher. */ bl_mem_params->ep_info.args.arg3 = PLAT_QEMU_DT_BASE; #else /* case AARCH32_SP_OPTEE */ bl_mem_params->ep_info.args.arg0 = bl_mem_params->ep_info.args.arg1; bl_mem_params->ep_info.args.arg1 = 0; bl_mem_params->ep_info.args.arg2 = PLAT_QEMU_DT_BASE; bl_mem_params->ep_info.args.arg3 = 0; #endif #endif bl_mem_params->ep_info.spsr = qemu_get_spsr_for_bl32_entry(); break; case BL33_IMAGE_ID: #ifdef AARCH32_SP_OPTEE /* AArch32 only core: OP-TEE expects NSec EP in register LR */ pager_mem_params = get_bl_mem_params_node(BL32_IMAGE_ID); assert(pager_mem_params); pager_mem_params->ep_info.lr_svc = bl_mem_params->ep_info.pc; #endif /* BL33 expects to receive the primary CPU MPID (through r0) */ bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr(); bl_mem_params->ep_info.spsr = qemu_get_spsr_for_bl33_entry(); break; default: /* Do nothing in default case */ break; } return err; } /******************************************************************************* * 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) { return qemu_bl2_handle_post_image_load(image_id); } uintptr_t plat_get_ns_image_entrypoint(void) { return NS_IMAGE_OFFSET; } trusted-firmware-a-2.2/plat/qemu/common/qemu_bl31_setup.c000066400000000000000000000060361355360272700234710ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "qemu_private.h" /* * Placeholder variables for copying the arguments that have been passed to * BL3-1 from BL2. */ static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; /******************************************************************************* * Perform any BL3-1 early platform setup. Here is an opportunity to copy * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before * they are lost (potentially). This needs to be done before the MMU is * initialized so that the memory layout can be used while creating page * tables. BL2 has flushed this information to memory, so we are guaranteed * to pick up good data. ******************************************************************************/ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { /* Initialize the console to provide early debug support */ qemu_console_init(); /* * Check params passed from BL2 */ bl_params_t *params_from_bl2 = (bl_params_t *)arg0; assert(params_from_bl2); assert(params_from_bl2->h.type == PARAM_BL_PARAMS); assert(params_from_bl2->h.version >= VERSION_2); bl_params_node_t *bl_params = params_from_bl2->head; /* * Copy BL33 and BL32 (if present), entry point information. * They are stored in Secure RAM, in BL2's address space. */ while (bl_params) { if (bl_params->image_id == BL32_IMAGE_ID) bl32_image_ep_info = *bl_params->ep_info; if (bl_params->image_id == BL33_IMAGE_ID) bl33_image_ep_info = *bl_params->ep_info; bl_params = bl_params->next_params_info; } if (!bl33_image_ep_info.pc) panic(); } void bl31_plat_arch_setup(void) { qemu_configure_mmu_el3(BL31_BASE, (BL31_END - BL31_BASE), BL_CODE_BASE, BL_CODE_END, BL_RO_DATA_BASE, BL_RO_DATA_END, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); } void bl31_platform_setup(void) { plat_qemu_gic_init(); } unsigned int plat_get_syscnt_freq2(void) { return SYS_COUNTER_FREQ_IN_TICKS; } /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image * for the security state specified. BL3-3 corresponds to the non-secure * image type while BL3-2 corresponds to the secure image type. A NULL * pointer is returned if the image does not exist. ******************************************************************************/ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; assert(sec_state_is_valid(type)); next_image_info = (type == NON_SECURE) ? &bl33_image_ep_info : &bl32_image_ep_info; /* * None of the images on the ARM development platforms can have 0x0 * as the entrypoint */ if (next_image_info->pc) return next_image_info; else return NULL; } trusted-firmware-a-2.2/plat/qemu/common/qemu_common.c000066400000000000000000000070641355360272700230020ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "qemu_private.h" #define MAP_DEVICE0 MAP_REGION_FLAT(DEVICE0_BASE, \ DEVICE0_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #ifdef DEVICE1_BASE #define MAP_DEVICE1 MAP_REGION_FLAT(DEVICE1_BASE, \ DEVICE1_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #endif #ifdef DEVICE2_BASE #define MAP_DEVICE2 MAP_REGION_FLAT(DEVICE2_BASE, \ DEVICE2_SIZE, \ MT_DEVICE | MT_RO | MT_SECURE) #endif #define MAP_SHARED_RAM MAP_REGION_FLAT(SHARED_RAM_BASE, \ SHARED_RAM_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_BL32_MEM MAP_REGION_FLAT(BL32_MEM_BASE, BL32_MEM_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #define MAP_NS_DRAM0 MAP_REGION_FLAT(NS_DRAM0_BASE, NS_DRAM0_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define MAP_FLASH0 MAP_REGION_FLAT(QEMU_FLASH0_BASE, QEMU_FLASH0_SIZE, \ MT_MEMORY | MT_RO | MT_SECURE) #define MAP_FLASH1 MAP_REGION_FLAT(QEMU_FLASH1_BASE, QEMU_FLASH1_SIZE, \ MT_MEMORY | MT_RO | MT_SECURE) /* * Table of regions for various BL stages to map using the MMU. * This doesn't include TZRAM as the 'mem_layout' argument passed to * arm_configure_mmu_elx() will give the available subset of that, */ #ifdef IMAGE_BL1 static const mmap_region_t plat_qemu_mmap[] = { MAP_FLASH0, MAP_FLASH1, MAP_SHARED_RAM, MAP_DEVICE0, #ifdef MAP_DEVICE1 MAP_DEVICE1, #endif #ifdef MAP_DEVICE2 MAP_DEVICE2, #endif {0} }; #endif #ifdef IMAGE_BL2 static const mmap_region_t plat_qemu_mmap[] = { MAP_FLASH0, MAP_FLASH1, MAP_SHARED_RAM, MAP_DEVICE0, #ifdef MAP_DEVICE1 MAP_DEVICE1, #endif #ifdef MAP_DEVICE2 MAP_DEVICE2, #endif MAP_NS_DRAM0, MAP_BL32_MEM, {0} }; #endif #ifdef IMAGE_BL31 static const mmap_region_t plat_qemu_mmap[] = { MAP_SHARED_RAM, MAP_DEVICE0, #ifdef MAP_DEVICE1 MAP_DEVICE1, #endif MAP_BL32_MEM, {0} }; #endif #ifdef IMAGE_BL32 static const mmap_region_t plat_qemu_mmap[] = { MAP_SHARED_RAM, MAP_DEVICE0, #ifdef MAP_DEVICE1 MAP_DEVICE1, #endif {0} }; #endif /******************************************************************************* * Macro generating the code for the function setting up the pagetables as per * the platform memory map & initialize the mmu, for the given exception level ******************************************************************************/ #define DEFINE_CONFIGURE_MMU_EL(_el) \ void qemu_configure_mmu_##_el(unsigned long total_base, \ unsigned long total_size, \ unsigned long code_start, \ unsigned long code_limit, \ unsigned long ro_start, \ unsigned long ro_limit, \ unsigned long coh_start, \ unsigned long coh_limit) \ { \ mmap_add_region(total_base, total_base, \ total_size, \ MT_MEMORY | MT_RW | MT_SECURE); \ mmap_add_region(code_start, code_start, \ code_limit - code_start, \ MT_CODE | MT_SECURE); \ mmap_add_region(ro_start, ro_start, \ ro_limit - ro_start, \ MT_RO_DATA | MT_SECURE); \ mmap_add_region(coh_start, coh_start, \ coh_limit - coh_start, \ MT_DEVICE | MT_RW | MT_SECURE); \ mmap_add(plat_qemu_mmap); \ init_xlat_tables(); \ \ enable_mmu_##_el(0); \ } /* Define EL1 and EL3 variants of the function initialising the MMU */ #ifdef __aarch64__ DEFINE_CONFIGURE_MMU_EL(el1) DEFINE_CONFIGURE_MMU_EL(el3) #else DEFINE_CONFIGURE_MMU_EL(svc_mon) #endif trusted-firmware-a-2.2/plat/qemu/common/qemu_console.c000066400000000000000000000010061355360272700231420ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include static console_pl011_t console; void qemu_console_init(void) { (void)console_pl011_register(PLAT_QEMU_BOOT_UART_BASE, PLAT_QEMU_BOOT_UART_CLK_IN_HZ, PLAT_QEMU_CONSOLE_BAUDRATE, &console); console_set_scope(&console.console, CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME); } trusted-firmware-a-2.2/plat/qemu/common/qemu_gicv2.c000066400000000000000000000017161355360272700225220ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include static const interrupt_prop_t qemu_interrupt_props[] = { PLATFORM_G1S_PROPS(GICV2_INTR_GROUP0), PLATFORM_G0_PROPS(GICV2_INTR_GROUP0) }; static const struct gicv2_driver_data plat_gicv2_driver_data = { .gicd_base = GICD_BASE, .gicc_base = GICC_BASE, .interrupt_props = qemu_interrupt_props, .interrupt_props_num = ARRAY_SIZE(qemu_interrupt_props), }; void plat_qemu_gic_init(void) { /* Initialize the gic cpu and distributor interfaces */ gicv2_driver_init(&plat_gicv2_driver_data); gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } void qemu_pwr_gic_on_finish(void) { /* TODO: This setup is needed only after a cold boot */ gicv2_pcpu_distif_init(); /* Enable the gic cpu interface */ gicv2_cpuif_enable(); } trusted-firmware-a-2.2/plat/qemu/common/qemu_gicv3.c000066400000000000000000000023031355360272700225140ustar00rootroot00000000000000/* * Copyright (c) 2019, Linaro Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include static const interrupt_prop_t qemu_interrupt_props[] = { PLATFORM_G1S_PROPS(INTR_GROUP1S), PLATFORM_G0_PROPS(INTR_GROUP0) }; static uintptr_t qemu_rdistif_base_addrs[PLATFORM_CORE_COUNT]; static unsigned int qemu_mpidr_to_core_pos(unsigned long mpidr) { return (unsigned int)plat_core_pos_by_mpidr(mpidr); } static const gicv3_driver_data_t qemu_gicv3_driver_data = { .gicd_base = GICD_BASE, .gicr_base = GICR_BASE, .interrupt_props = qemu_interrupt_props, .interrupt_props_num = ARRAY_SIZE(qemu_interrupt_props), .rdistif_num = PLATFORM_CORE_COUNT, .rdistif_base_addrs = qemu_rdistif_base_addrs, .mpidr_to_core_pos = qemu_mpidr_to_core_pos }; void plat_qemu_gic_init(void) { gicv3_driver_init(&qemu_gicv3_driver_data); gicv3_distif_init(); gicv3_rdistif_init(plat_my_core_pos()); gicv3_cpuif_enable(plat_my_core_pos()); } void qemu_pwr_gic_on_finish(void) { gicv3_rdistif_init(plat_my_core_pos()); gicv3_cpuif_enable(plat_my_core_pos()); } trusted-firmware-a-2.2/plat/qemu/common/qemu_image_load.c000066400000000000000000000023671355360272700235740ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include /******************************************************************************* * This function is a wrapper of a common function which flushes the data * structures so that they are visible in memory for the next BL image. ******************************************************************************/ void plat_flush_next_bl_params(void) { flush_bl_params_desc(); } /******************************************************************************* * This function is a wrapper of a common function which returns the list of * loadable images. ******************************************************************************/ bl_load_info_t *plat_get_bl_image_load_info(void) { return get_bl_load_info_from_mem_params_desc(); } /******************************************************************************* * This function is a wrapper of a common function which returns the data * structures of the next BL image. ******************************************************************************/ bl_params_t *plat_get_next_bl_params(void) { return get_next_bl_params_from_mem_params_desc(); } trusted-firmware-a-2.2/plat/qemu/common/qemu_io_storage.c000066400000000000000000000216071355360272700236440ustar00rootroot00000000000000/* * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include /* Semihosting filenames */ #define BL2_IMAGE_NAME "bl2.bin" #define BL31_IMAGE_NAME "bl31.bin" #define BL32_IMAGE_NAME "bl32.bin" #define BL32_EXTRA1_IMAGE_NAME "bl32_extra1.bin" #define BL32_EXTRA2_IMAGE_NAME "bl32_extra2.bin" #define BL33_IMAGE_NAME "bl33.bin" #if TRUSTED_BOARD_BOOT #define TRUSTED_BOOT_FW_CERT_NAME "tb_fw.crt" #define TRUSTED_KEY_CERT_NAME "trusted_key.crt" #define SOC_FW_KEY_CERT_NAME "soc_fw_key.crt" #define TOS_FW_KEY_CERT_NAME "tos_fw_key.crt" #define NT_FW_KEY_CERT_NAME "nt_fw_key.crt" #define SOC_FW_CONTENT_CERT_NAME "soc_fw_content.crt" #define TOS_FW_CONTENT_CERT_NAME "tos_fw_content.crt" #define NT_FW_CONTENT_CERT_NAME "nt_fw_content.crt" #endif /* TRUSTED_BOARD_BOOT */ /* IO devices */ static const io_dev_connector_t *fip_dev_con; static uintptr_t fip_dev_handle; static const io_dev_connector_t *memmap_dev_con; static uintptr_t memmap_dev_handle; static const io_dev_connector_t *sh_dev_con; static uintptr_t sh_dev_handle; static const io_block_spec_t fip_block_spec = { .offset = PLAT_QEMU_FIP_BASE, .length = PLAT_QEMU_FIP_MAX_SIZE }; static const io_uuid_spec_t bl2_uuid_spec = { .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2, }; static const io_uuid_spec_t bl31_uuid_spec = { .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31, }; static const io_uuid_spec_t bl32_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32, }; static const io_uuid_spec_t bl32_extra1_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1, }; static const io_uuid_spec_t bl32_extra2_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2, }; static const io_uuid_spec_t bl33_uuid_spec = { .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33, }; #if TRUSTED_BOARD_BOOT static const io_uuid_spec_t tb_fw_cert_uuid_spec = { .uuid = UUID_TRUSTED_BOOT_FW_CERT, }; static const io_uuid_spec_t trusted_key_cert_uuid_spec = { .uuid = UUID_TRUSTED_KEY_CERT, }; static const io_uuid_spec_t soc_fw_key_cert_uuid_spec = { .uuid = UUID_SOC_FW_KEY_CERT, }; static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = { .uuid = UUID_TRUSTED_OS_FW_KEY_CERT, }; static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = { .uuid = UUID_NON_TRUSTED_FW_KEY_CERT, }; static const io_uuid_spec_t soc_fw_cert_uuid_spec = { .uuid = UUID_SOC_FW_CONTENT_CERT, }; static const io_uuid_spec_t tos_fw_cert_uuid_spec = { .uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT, }; static const io_uuid_spec_t nt_fw_cert_uuid_spec = { .uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT, }; #endif /* TRUSTED_BOARD_BOOT */ static const io_file_spec_t sh_file_spec[] = { [BL2_IMAGE_ID] = { .path = BL2_IMAGE_NAME, .mode = FOPEN_MODE_RB }, [BL31_IMAGE_ID] = { .path = BL31_IMAGE_NAME, .mode = FOPEN_MODE_RB }, [BL32_IMAGE_ID] = { .path = BL32_IMAGE_NAME, .mode = FOPEN_MODE_RB }, [BL32_EXTRA1_IMAGE_ID] = { .path = BL32_EXTRA1_IMAGE_NAME, .mode = FOPEN_MODE_RB }, [BL32_EXTRA2_IMAGE_ID] = { .path = BL32_EXTRA2_IMAGE_NAME, .mode = FOPEN_MODE_RB }, [BL33_IMAGE_ID] = { .path = BL33_IMAGE_NAME, .mode = FOPEN_MODE_RB }, #if TRUSTED_BOARD_BOOT [TRUSTED_BOOT_FW_CERT_ID] = { .path = TRUSTED_BOOT_FW_CERT_NAME, .mode = FOPEN_MODE_RB }, [TRUSTED_KEY_CERT_ID] = { .path = TRUSTED_KEY_CERT_NAME, .mode = FOPEN_MODE_RB }, [SOC_FW_KEY_CERT_ID] = { .path = SOC_FW_KEY_CERT_NAME, .mode = FOPEN_MODE_RB }, [TRUSTED_OS_FW_KEY_CERT_ID] = { .path = TOS_FW_KEY_CERT_NAME, .mode = FOPEN_MODE_RB }, [NON_TRUSTED_FW_KEY_CERT_ID] = { .path = NT_FW_KEY_CERT_NAME, .mode = FOPEN_MODE_RB }, [SOC_FW_CONTENT_CERT_ID] = { .path = SOC_FW_CONTENT_CERT_NAME, .mode = FOPEN_MODE_RB }, [TRUSTED_OS_FW_CONTENT_CERT_ID] = { .path = TOS_FW_CONTENT_CERT_NAME, .mode = FOPEN_MODE_RB }, [NON_TRUSTED_FW_CONTENT_CERT_ID] = { .path = NT_FW_CONTENT_CERT_NAME, .mode = FOPEN_MODE_RB }, #endif /* TRUSTED_BOARD_BOOT */ }; static int open_fip(const uintptr_t spec); static int open_memmap(const uintptr_t spec); struct plat_io_policy { uintptr_t *dev_handle; uintptr_t image_spec; int (*check)(const uintptr_t spec); }; /* By default, ARM platforms load images from the FIP */ static const struct plat_io_policy policies[] = { [FIP_IMAGE_ID] = { &memmap_dev_handle, (uintptr_t)&fip_block_spec, open_memmap }, [BL2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl2_uuid_spec, open_fip }, [BL31_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl31_uuid_spec, open_fip }, [BL32_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_uuid_spec, open_fip }, [BL32_EXTRA1_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_extra1_uuid_spec, open_fip }, [BL32_EXTRA2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_extra2_uuid_spec, open_fip }, [BL33_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl33_uuid_spec, open_fip }, #if TRUSTED_BOARD_BOOT [TRUSTED_BOOT_FW_CERT_ID] = { &fip_dev_handle, (uintptr_t)&tb_fw_cert_uuid_spec, open_fip }, [TRUSTED_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&trusted_key_cert_uuid_spec, open_fip }, [SOC_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&soc_fw_key_cert_uuid_spec, open_fip }, [TRUSTED_OS_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&tos_fw_key_cert_uuid_spec, open_fip }, [NON_TRUSTED_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&nt_fw_key_cert_uuid_spec, open_fip }, [SOC_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&soc_fw_cert_uuid_spec, open_fip }, [TRUSTED_OS_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&tos_fw_cert_uuid_spec, open_fip }, [NON_TRUSTED_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&nt_fw_cert_uuid_spec, open_fip }, #endif /* TRUSTED_BOARD_BOOT */ }; static int open_fip(const uintptr_t spec) { int result; uintptr_t local_image_handle; /* See if a Firmware Image Package is available */ result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); if (result == 0) { result = io_open(fip_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using FIP\n"); io_close(local_image_handle); } } return result; } static int open_memmap(const uintptr_t spec) { int result; uintptr_t local_image_handle; result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL); if (result == 0) { result = io_open(memmap_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using Memmap\n"); io_close(local_image_handle); } } return result; } static int open_semihosting(const uintptr_t spec) { int result; uintptr_t local_image_handle; /* See if the file exists on semi-hosting.*/ result = io_dev_init(sh_dev_handle, (uintptr_t)NULL); if (result == 0) { result = io_open(sh_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using Semi-hosting IO\n"); io_close(local_image_handle); } } return result; } void plat_qemu_io_setup(void) { int io_result; io_result = register_io_dev_fip(&fip_dev_con); assert(io_result == 0); io_result = register_io_dev_memmap(&memmap_dev_con); assert(io_result == 0); /* Open connections to devices and cache the handles */ io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle); assert(io_result == 0); io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL, &memmap_dev_handle); assert(io_result == 0); /* Register the additional IO devices on this platform */ io_result = register_io_dev_sh(&sh_dev_con); assert(io_result == 0); /* Open connections to devices and cache the handles */ io_result = io_dev_open(sh_dev_con, (uintptr_t)NULL, &sh_dev_handle); assert(io_result == 0); /* Ignore improbable errors in release builds */ (void)io_result; } static int get_alt_image_source(unsigned int image_id, uintptr_t *dev_handle, uintptr_t *image_spec) { int result = open_semihosting((const uintptr_t)&sh_file_spec[image_id]); if (result == 0) { *dev_handle = sh_dev_handle; *image_spec = (uintptr_t)&sh_file_spec[image_id]; } return result; } /* * 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 result; const struct plat_io_policy *policy; assert(image_id < ARRAY_SIZE(policies)); policy = &policies[image_id]; result = policy->check(policy->image_spec); if (result == 0) { *image_spec = policy->image_spec; *dev_handle = *(policy->dev_handle); } else { VERBOSE("Trying alternative IO\n"); result = get_alt_image_source(image_id, dev_handle, image_spec); } return result; } trusted-firmware-a-2.2/plat/qemu/common/qemu_pm.c000066400000000000000000000165341355360272700221300ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "qemu_private.h" /* * The secure entry point to be used on warm reset. */ static unsigned long secure_entrypoint; /* Make composite power state parameter till power level 0 */ #if PSCI_EXTENDED_STATE_ID #define qemu_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ (((lvl0_state) << PSTATE_ID_SHIFT) | \ ((type) << PSTATE_TYPE_SHIFT)) #else #define qemu_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ (((lvl0_state) << PSTATE_ID_SHIFT) | \ ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \ ((type) << PSTATE_TYPE_SHIFT)) #endif /* PSCI_EXTENDED_STATE_ID */ #define qemu_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \ (((lvl1_state) << PLAT_LOCAL_PSTATE_WIDTH) | \ qemu_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type)) /* * The table storing the valid idle power states. Ensure that the * array entries are populated in ascending order of state-id to * enable us to use binary search during power state validation. * The table must be terminated by a NULL entry. */ static const unsigned int qemu_pm_idle_states[] = { /* State-id - 0x01 */ qemu_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_RET, MPIDR_AFFLVL0, PSTATE_TYPE_STANDBY), /* State-id - 0x02 */ qemu_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_OFF, MPIDR_AFFLVL0, PSTATE_TYPE_POWERDOWN), /* State-id - 0x22 */ qemu_make_pwrstate_lvl1(PLAT_LOCAL_STATE_OFF, PLAT_LOCAL_STATE_OFF, MPIDR_AFFLVL1, PSTATE_TYPE_POWERDOWN), 0, }; /******************************************************************************* * Platform handler called to check the validity of the power state * parameter. The power state parameter has to be a composite power state. ******************************************************************************/ static int qemu_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { unsigned int state_id; int i; assert(req_state); /* * Currently we are using a linear search for finding the matching * entry in the idle power state array. This can be made a binary * search if the number of entries justify the additional complexity. */ for (i = 0; !!qemu_pm_idle_states[i]; i++) { if (power_state == qemu_pm_idle_states[i]) break; } /* Return error if entry not found in the idle state array */ if (!qemu_pm_idle_states[i]) return PSCI_E_INVALID_PARAMS; i = 0; state_id = psci_get_pstate_id(power_state); /* Parse the State ID and populate the state info parameter */ while (state_id) { req_state->pwr_domain_state[i++] = state_id & PLAT_LOCAL_PSTATE_MASK; state_id >>= PLAT_LOCAL_PSTATE_WIDTH; } return PSCI_E_SUCCESS; } /******************************************************************************* * Platform handler called to check the validity of the non secure * entrypoint. ******************************************************************************/ static int qemu_validate_ns_entrypoint(uintptr_t entrypoint) { /* * Check if the non secure entrypoint lies within the non * secure DRAM. */ if ((entrypoint >= NS_DRAM0_BASE) && (entrypoint < (NS_DRAM0_BASE + NS_DRAM0_SIZE))) return PSCI_E_SUCCESS; return PSCI_E_INVALID_ADDRESS; } /******************************************************************************* * Platform handler called when a CPU is about to enter standby. ******************************************************************************/ static void qemu_cpu_standby(plat_local_state_t cpu_state) { assert(cpu_state == PLAT_LOCAL_STATE_RET); /* * Enter standby state * dsb is good practice before using wfi to enter low power states */ dsb(); wfi(); } /******************************************************************************* * Platform handler called when a power domain is about to be turned on. The * mpidr determines the CPU to be turned on. ******************************************************************************/ static int qemu_pwr_domain_on(u_register_t mpidr) { int rc = PSCI_E_SUCCESS; unsigned pos = plat_core_pos_by_mpidr(mpidr); uint64_t *hold_base = (uint64_t *)PLAT_QEMU_HOLD_BASE; hold_base[pos] = PLAT_QEMU_HOLD_STATE_GO; sev(); return rc; } /******************************************************************************* * Platform handler called when a power domain is about to be turned off. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ void qemu_pwr_domain_off(const psci_power_state_t *target_state) { assert(0); } /******************************************************************************* * Platform handler called when a power domain is about to be suspended. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ void qemu_pwr_domain_suspend(const psci_power_state_t *target_state) { assert(0); } /******************************************************************************* * Platform handler called when a power domain has just been powered on after * being turned off earlier. The target_state encodes the low power state that * each level has woken up from. ******************************************************************************/ void qemu_pwr_domain_on_finish(const psci_power_state_t *target_state) { assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == PLAT_LOCAL_STATE_OFF); qemu_pwr_gic_on_finish(); } /******************************************************************************* * Platform handler called when a power domain has just been powered on after * having been suspended earlier. The target_state encodes the low power state * that each level has woken up from. ******************************************************************************/ void qemu_pwr_domain_suspend_finish(const psci_power_state_t *target_state) { assert(0); } /******************************************************************************* * Platform handlers to shutdown/reboot the system ******************************************************************************/ static void __dead2 qemu_system_off(void) { ERROR("QEMU System Off: operation not handled.\n"); panic(); } static void __dead2 qemu_system_reset(void) { ERROR("QEMU System Reset: operation not handled.\n"); panic(); } static const plat_psci_ops_t plat_qemu_psci_pm_ops = { .cpu_standby = qemu_cpu_standby, .pwr_domain_on = qemu_pwr_domain_on, .pwr_domain_off = qemu_pwr_domain_off, .pwr_domain_suspend = qemu_pwr_domain_suspend, .pwr_domain_on_finish = qemu_pwr_domain_on_finish, .pwr_domain_suspend_finish = qemu_pwr_domain_suspend_finish, .system_off = qemu_system_off, .system_reset = qemu_system_reset, .validate_power_state = qemu_validate_power_state, .validate_ns_entrypoint = qemu_validate_ns_entrypoint }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { uintptr_t *mailbox = (void *) PLAT_QEMU_TRUSTED_MAILBOX_BASE; *mailbox = sec_entrypoint; secure_entrypoint = (unsigned long) sec_entrypoint; *psci_ops = &plat_qemu_psci_pm_ops; return 0; } trusted-firmware-a-2.2/plat/qemu/common/qemu_private.h000066400000000000000000000021711355360272700231630ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef QEMU_PRIVATE_H #define QEMU_PRIVATE_H #include void qemu_configure_mmu_svc_mon(unsigned long total_base, unsigned long total_size, unsigned long code_start, unsigned long code_limit, unsigned long ro_start, unsigned long ro_limit, unsigned long coh_start, unsigned long coh_limit); void qemu_configure_mmu_el1(unsigned long total_base, unsigned long total_size, unsigned long code_start, unsigned long code_limit, unsigned long ro_start, unsigned long ro_limit, unsigned long coh_start, unsigned long coh_limit); void qemu_configure_mmu_el3(unsigned long total_base, unsigned long total_size, unsigned long code_start, unsigned long code_limit, unsigned long ro_start, unsigned long ro_limit, unsigned long coh_start, unsigned long coh_limit); void plat_qemu_io_setup(void); unsigned int plat_qemu_calc_core_pos(u_register_t mpidr); void qemu_console_init(void); void plat_qemu_gic_init(void); void qemu_pwr_gic_on_finish(void); #endif /* QEMU_PRIVATE_H */ trusted-firmware-a-2.2/plat/qemu/common/qemu_rotpk.S000066400000000000000000000006141355360272700226230ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ .global qemu_rotpk_hash .global qemu_rotpk_hash_end qemu_rotpk_hash: /* DER header */ .byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48 .byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 /* SHA256 */ .incbin ROTPK_HASH qemu_rotpk_hash_end: trusted-firmware-a-2.2/plat/qemu/common/qemu_stack_protector.c000066400000000000000000000012151355360272700247100ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #define RANDOM_CANARY_VALUE ((u_register_t) 3288484550995823360ULL) u_register_t plat_get_stack_protector_canary(void) { /* * Ideally, a random number should be returned instead of the * combination of a timer's value and a compile-time constant. * As the virt platform does not have any random number generator, * this is better than nothing but not necessarily really secure. */ return RANDOM_CANARY_VALUE ^ read_cntpct_el0(); } trusted-firmware-a-2.2/plat/qemu/common/qemu_trusted_boot.c000066400000000000000000000013241355360272700242200ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include extern char qemu_rotpk_hash[], qemu_rotpk_hash_end[]; int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, unsigned int *flags) { *key_ptr = qemu_rotpk_hash; *key_len = qemu_rotpk_hash_end - qemu_rotpk_hash; *flags = ROTPK_IS_HASH; return 0; } int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr) { *nv_ctr = 0; return 0; } int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr) { return 1; } int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size) { return get_mbedtls_heap_helper(heap_addr, heap_size); } trusted-firmware-a-2.2/plat/qemu/common/sp_min/000077500000000000000000000000001355360272700215755ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/qemu/common/sp_min/sp_min-qemu.mk000066400000000000000000000011431355360272700243570ustar00rootroot00000000000000# # Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # BL32_SOURCES += plat/qemu/sp_min/sp_min_setup.c \ plat/qemu/aarch32/plat_helpers.S \ plat/qemu/qemu_pm.c \ plat/qemu/topology.c BL32_SOURCES += lib/cpus/aarch32/aem_generic.S \ lib/cpus/aarch32/cortex_a15.S BL32_SOURCES += plat/common/aarch32/platform_mp_stack.S \ plat/common/plat_psci_common.c \ plat/common/plat_gicv2.c BL32_SOURCES += drivers/arm/gic/v2/gicv2_helpers.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/common/gic_common.c trusted-firmware-a-2.2/plat/qemu/common/sp_min/sp_min_setup.c000066400000000000000000000103731355360272700244520ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include "../qemu_private.h" #if RESET_TO_SP_MIN #error qemu does not support RESET_TO_SP_MIN #endif static entry_point_info_t bl33_image_ep_info; /****************************************************************************** * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0 * interrupts. *****************************************************************************/ #define PLATFORM_G1S_PROPS(grp) \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_LEVEL) #define PLATFORM_G0_PROPS(grp) static const interrupt_prop_t stih410_interrupt_props[] = { PLATFORM_G1S_PROPS(GICV2_INTR_GROUP0), PLATFORM_G0_PROPS(GICV2_INTR_GROUP0) }; static unsigned int target_mask_array[PLATFORM_CORE_COUNT]; static const struct gicv2_driver_data plat_gicv2_driver_data = { .gicd_base = GICD_BASE, .gicc_base = GICC_BASE, .interrupt_props = stih410_interrupt_props, .interrupt_props_num = ARRAY_SIZE(stih410_interrupt_props), .target_masks = target_mask_array, .target_masks_num = ARRAY_SIZE(target_mask_array), }; /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for * the security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. ******************************************************************************/ entry_point_info_t *sp_min_plat_get_bl33_ep_info(void) { entry_point_info_t *next_image_info = &bl33_image_ep_info; /* * None of the images on the ARM development platforms can have 0x0 * as the entrypoint */ if (next_image_info->pc) return next_image_info; else return NULL; } void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { bl_params_t *params_from_bl2 = (bl_params_t *)arg0; /* Initialize the console to provide early debug support */ qemu_console_init(); ERROR("qemu sp_min, console init\n"); /* * Check params passed from BL2 */ assert(params_from_bl2); assert(params_from_bl2->h.type == PARAM_BL_PARAMS); assert(params_from_bl2->h.version >= VERSION_2); bl_params_node_t *bl_params = params_from_bl2->head; /* * Copy BL33 entry point information from BL2's address space. */ while (bl_params) { if (bl_params->image_id == BL33_IMAGE_ID) bl33_image_ep_info = *bl_params->ep_info; bl_params = bl_params->next_params_info; } if (!bl33_image_ep_info.pc) panic(); } void sp_min_plat_arch_setup(void) { qemu_configure_mmu_svc_mon(BL32_RO_BASE, BL32_END - BL32_RO_BASE, BL_CODE_BASE, BL_CODE_END, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); } void sp_min_platform_setup(void) { /* Initialize the gic cpu and distributor interfaces */ gicv2_driver_init(&plat_gicv2_driver_data); gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } unsigned int plat_get_syscnt_freq2(void) { return SYS_COUNTER_FREQ_IN_TICKS; } void sp_min_plat_fiq_handler(uint32_t id) { VERBOSE("[sp_min] interrupt #%d\n", id); } trusted-firmware-a-2.2/plat/qemu/common/topology.c000066400000000000000000000033221355360272700223300ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "qemu_private.h" /* The power domain tree descriptor */ static unsigned char power_domain_tree_desc[] = { /* Number of root nodes */ PLATFORM_CLUSTER_COUNT, /* Number of children for the first node */ PLATFORM_CLUSTER0_CORE_COUNT, /* Number of children for the second node */ PLATFORM_CLUSTER1_CORE_COUNT, }; /******************************************************************************* * This function returns the ARM default topology tree information. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { return power_domain_tree_desc; } /******************************************************************************* * This function implements a part of the critical interface between the psci * generic layer and the platform that allows the former to query the platform * to convert an MPIDR to a unique linear index. An error code (-1) is returned * in case the MPIDR is invalid. ******************************************************************************/ int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; mpidr &= MPIDR_AFFINITY_MASK; if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) return -1; cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; if (cluster_id >= PLATFORM_CLUSTER_COUNT) return -1; if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER) return -1; return plat_qemu_calc_core_pos(mpidr); } trusted-firmware-a-2.2/plat/qemu/qemu/000077500000000000000000000000001355360272700177675ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/qemu/qemu/include/000077500000000000000000000000001355360272700214125ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/qemu/qemu/include/platform_def.h000066400000000000000000000172541355360272700242360ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include /* Special value used to verify platform parameters from BL2 to BL3-1 */ #define QEMU_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL #define PLATFORM_STACK_SIZE 0x1000 #if ARM_ARCH_MAJOR == 7 #define PLATFORM_MAX_CPUS_PER_CLUSTER 4 #define PLATFORM_CLUSTER_COUNT 1 #define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER #define PLATFORM_CLUSTER1_CORE_COUNT 0 #else #define PLATFORM_MAX_CPUS_PER_CLUSTER 4 #define PLATFORM_CLUSTER_COUNT 2 #define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER #define PLATFORM_CLUSTER1_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER #endif #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT + \ PLATFORM_CLUSTER1_CORE_COUNT) #define QEMU_PRIMARY_CPU 0 #define PLAT_NUM_PWR_DOMAINS (PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1 #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE U(2) /* Local power state for power domains in Run state. */ #define PLAT_LOCAL_STATE_RUN U(0) /* Local power state for retention. Valid only for CPU power domains */ #define PLAT_LOCAL_STATE_RET U(1) /* * Local power state for OFF/power-down. Valid for CPU and cluster power * domains. */ #define PLAT_LOCAL_STATE_OFF 2 /* * Macros used to parse state information from State-ID if it is using the * recommended encoding for State-ID. */ #define PLAT_LOCAL_PSTATE_WIDTH 4 #define PLAT_LOCAL_PSTATE_MASK ((1 << PLAT_LOCAL_PSTATE_WIDTH) - 1) /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. */ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) /* * Partition memory into secure ROM, non-secure DRAM, secure "SRAM", * and secure DRAM. */ #define SEC_ROM_BASE 0x00000000 #define SEC_ROM_SIZE 0x00020000 #define NS_DRAM0_BASE 0x40000000 #define NS_DRAM0_SIZE 0x3de00000 #define SEC_SRAM_BASE 0x0e000000 #define SEC_SRAM_SIZE 0x00060000 #define SEC_DRAM_BASE 0x0e100000 #define SEC_DRAM_SIZE 0x00f00000 /* Load pageable part of OP-TEE 2MB above secure DRAM base */ #define QEMU_OPTEE_PAGEABLE_LOAD_BASE (SEC_DRAM_BASE + 0x00200000) #define QEMU_OPTEE_PAGEABLE_LOAD_SIZE 0x00400000 /* * ARM-TF lives in SRAM, partition it here */ #define SHARED_RAM_BASE SEC_SRAM_BASE #define SHARED_RAM_SIZE 0x00001000 #define PLAT_QEMU_TRUSTED_MAILBOX_BASE SHARED_RAM_BASE #define PLAT_QEMU_TRUSTED_MAILBOX_SIZE (8 + PLAT_QEMU_HOLD_SIZE) #define PLAT_QEMU_HOLD_BASE (PLAT_QEMU_TRUSTED_MAILBOX_BASE + 8) #define PLAT_QEMU_HOLD_SIZE (PLATFORM_CORE_COUNT * \ PLAT_QEMU_HOLD_ENTRY_SIZE) #define PLAT_QEMU_HOLD_ENTRY_SHIFT 3 #define PLAT_QEMU_HOLD_ENTRY_SIZE (1 << PLAT_QEMU_HOLD_ENTRY_SHIFT) #define PLAT_QEMU_HOLD_STATE_WAIT 0 #define PLAT_QEMU_HOLD_STATE_GO 1 #define BL_RAM_BASE (SHARED_RAM_BASE + SHARED_RAM_SIZE) #define BL_RAM_SIZE (SEC_SRAM_SIZE - SHARED_RAM_SIZE) /* * BL1 specific defines. * * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of * addresses. * Put BL1 RW at the top of the Secure SRAM. BL1_RW_BASE is calculated using * the current BL1 RW debug size plus a little space for growth. */ #define BL1_RO_BASE SEC_ROM_BASE #define BL1_RO_LIMIT (SEC_ROM_BASE + SEC_ROM_SIZE) #define BL1_RW_BASE (BL1_RW_LIMIT - 0x12000) #define BL1_RW_LIMIT (BL_RAM_BASE + BL_RAM_SIZE) /* * BL2 specific defines. * * 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 (BL31_BASE - 0x25000) #define BL2_LIMIT BL31_BASE /* * BL3-1 specific defines. * * Put BL3-1 at the top of the Trusted SRAM. BL31_BASE is calculated using the * current BL3-1 debug size plus a little space for growth. */ #define BL31_BASE (BL31_LIMIT - 0x20000) #define BL31_LIMIT (BL_RAM_BASE + BL_RAM_SIZE) #define BL31_PROGBITS_LIMIT BL1_RW_BASE /* * BL3-2 specific defines. * * BL3-2 can execute from Secure SRAM, or Secure DRAM. */ #define BL32_SRAM_BASE BL_RAM_BASE #define BL32_SRAM_LIMIT BL31_BASE #define BL32_DRAM_BASE SEC_DRAM_BASE #define BL32_DRAM_LIMIT (SEC_DRAM_BASE + SEC_DRAM_SIZE) #define SEC_SRAM_ID 0 #define SEC_DRAM_ID 1 #if BL32_RAM_LOCATION_ID == SEC_SRAM_ID # define BL32_MEM_BASE BL_RAM_BASE # define BL32_MEM_SIZE BL_RAM_SIZE # define BL32_BASE BL32_SRAM_BASE # define BL32_LIMIT BL32_SRAM_LIMIT #elif BL32_RAM_LOCATION_ID == SEC_DRAM_ID # define BL32_MEM_BASE SEC_DRAM_BASE # define BL32_MEM_SIZE SEC_DRAM_SIZE # define BL32_BASE BL32_DRAM_BASE # define BL32_LIMIT BL32_DRAM_LIMIT #else # error "Unsupported BL32_RAM_LOCATION_ID value" #endif #define NS_IMAGE_OFFSET (NS_DRAM0_BASE + 0x20000000) #define NS_IMAGE_MAX_SIZE (NS_DRAM0_SIZE - 0x20000000) #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #define MAX_MMAP_REGIONS 11 #define MAX_XLAT_TABLES 6 #define MAX_IO_DEVICES 3 #define MAX_IO_HANDLES 4 /* * PL011 related constants */ #define UART0_BASE 0x09000000 #define UART1_BASE 0x09040000 #define UART0_CLK_IN_HZ 1 #define UART1_CLK_IN_HZ 1 #define PLAT_QEMU_BOOT_UART_BASE UART0_BASE #define PLAT_QEMU_BOOT_UART_CLK_IN_HZ UART0_CLK_IN_HZ #define PLAT_QEMU_CRASH_UART_BASE UART1_BASE #define PLAT_QEMU_CRASH_UART_CLK_IN_HZ UART1_CLK_IN_HZ #define PLAT_QEMU_CONSOLE_BAUDRATE 115200 #define QEMU_FLASH0_BASE 0x00000000 #define QEMU_FLASH0_SIZE 0x04000000 #define QEMU_FLASH1_BASE 0x04000000 #define QEMU_FLASH1_SIZE 0x04000000 #define PLAT_QEMU_FIP_BASE QEMU_FLASH1_BASE #define PLAT_QEMU_FIP_MAX_SIZE QEMU_FLASH1_SIZE #define DEVICE0_BASE 0x08000000 #define DEVICE0_SIZE 0x01000000 #define DEVICE1_BASE 0x09000000 #define DEVICE1_SIZE 0x00041000 /* * GIC related constants */ #define GICD_BASE 0x8000000 #define GICC_BASE 0x8010000 #define GICR_BASE 0x80A0000 #define QEMU_IRQ_SEC_SGI_0 8 #define QEMU_IRQ_SEC_SGI_1 9 #define QEMU_IRQ_SEC_SGI_2 10 #define QEMU_IRQ_SEC_SGI_3 11 #define QEMU_IRQ_SEC_SGI_4 12 #define QEMU_IRQ_SEC_SGI_5 13 #define QEMU_IRQ_SEC_SGI_6 14 #define QEMU_IRQ_SEC_SGI_7 15 /****************************************************************************** * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0 * interrupts. *****************************************************************************/ #define PLATFORM_G1S_PROPS(grp) \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE) #define PLATFORM_G0_PROPS(grp) /* * DT related constants */ #define PLAT_QEMU_DT_BASE NS_DRAM0_BASE #define PLAT_QEMU_DT_MAX_SIZE 0x100000 /* * System counter */ #define SYS_COUNTER_FREQ_IN_TICKS ((1000 * 1000 * 1000) / 16) #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/qemu/qemu/platform.mk000066400000000000000000000133251355360272700221500ustar00rootroot00000000000000# # Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Use the GICv2 driver on QEMU by default QEMU_USE_GIC_DRIVER := QEMU_GICV2 ifeq (${ARM_ARCH_MAJOR},7) # ARMv7 Qemu support in trusted firmware expects the Cortex-A15 model. # Qemu Cortex-A15 model does not implement the virtualization extension. # For this reason, we cannot set ARM_CORTEX_A15=yes and must define all # the ARMv7 build directives. MARCH32_DIRECTIVE := -mcpu=cortex-a15 $(eval $(call add_define,ARMV7_SUPPORTS_LARGE_PAGE_ADDRESSING)) $(eval $(call add_define,ARMV7_SUPPORTS_GENERIC_TIMER)) # Qemu expects a BL32 boot stage. NEED_BL32 := yes endif # ARMv7 ifeq (${SPD},opteed) add-lib-optee := yes endif ifeq ($(AARCH32_SP),optee) add-lib-optee := yes endif include lib/libfdt/libfdt.mk ifeq ($(NEED_BL32),yes) $(eval $(call add_define,QEMU_LOAD_BL32)) endif PLAT_QEMU_PATH := plat/qemu/qemu PLAT_QEMU_COMMON_PATH := plat/qemu/common PLAT_INCLUDES := -Iinclude/plat/arm/common/ \ -I${PLAT_QEMU_COMMON_PATH}/include \ -I${PLAT_QEMU_PATH}/include \ -Iinclude/common/tbbr ifeq (${ARM_ARCH_MAJOR},8) PLAT_INCLUDES += -Iinclude/plat/arm/common/${ARCH} endif PLAT_BL_COMMON_SOURCES := ${PLAT_QEMU_COMMON_PATH}/qemu_common.c \ ${PLAT_QEMU_COMMON_PATH}/qemu_console.c \ drivers/arm/pl011/${ARCH}/pl011_console.S include lib/xlat_tables_v2/xlat_tables.mk PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} ifneq (${TRUSTED_BOARD_BOOT},0) include drivers/auth/mbedtls/mbedtls_crypto.mk include drivers/auth/mbedtls/mbedtls_x509.mk AUTH_SOURCES := drivers/auth/auth_mod.c \ drivers/auth/crypto_mod.c \ drivers/auth/img_parser_mod.c \ drivers/auth/tbbr/tbbr_cot.c BL1_SOURCES += ${AUTH_SOURCES} \ bl1/tbbr/tbbr_img_desc.c \ plat/common/tbbr/plat_tbbr.c \ ${PLAT_QEMU_COMMON_PATH}/qemu_trusted_boot.c \ $(PLAT_QEMU_COMMON_PATH)/qemu_rotpk.S BL2_SOURCES += ${AUTH_SOURCES} \ plat/common/tbbr/plat_tbbr.c \ ${PLAT_QEMU_COMMON_PATH}/qemu_trusted_boot.c \ $(PLAT_QEMU_COMMON_PATH)/qemu_rotpk.S ROT_KEY = $(BUILD_PLAT)/rot_key.pem ROTPK_HASH = $(BUILD_PLAT)/rotpk_sha256.bin $(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"')) $(BUILD_PLAT)/bl1/qemu_rotpk.o: $(ROTPK_HASH) $(BUILD_PLAT)/bl2/qemu_rotpk.o: $(ROTPK_HASH) certificates: $(ROT_KEY) $(ROT_KEY): @echo " OPENSSL $@" $(Q)openssl genrsa 2048 > $@ 2>/dev/null $(ROTPK_HASH): $(ROT_KEY) @echo " OPENSSL $@" $(Q)openssl rsa -in $< -pubout -outform DER 2>/dev/null |\ openssl dgst -sha256 -binary > $@ 2>/dev/null endif BL1_SOURCES += drivers/io/io_semihosting.c \ drivers/io/io_storage.c \ drivers/io/io_fip.c \ drivers/io/io_memmap.c \ lib/semihosting/semihosting.c \ lib/semihosting/${ARCH}/semihosting_call.S \ ${PLAT_QEMU_COMMON_PATH}/qemu_io_storage.c \ ${PLAT_QEMU_COMMON_PATH}/${ARCH}/plat_helpers.S \ ${PLAT_QEMU_COMMON_PATH}/qemu_bl1_setup.c ifeq (${ARM_ARCH_MAJOR},8) BL1_SOURCES += lib/cpus/aarch64/aem_generic.S \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S else BL1_SOURCES += lib/cpus/${ARCH}/cortex_a15.S endif BL2_SOURCES += drivers/io/io_semihosting.c \ drivers/io/io_storage.c \ drivers/io/io_fip.c \ drivers/io/io_memmap.c \ lib/semihosting/semihosting.c \ lib/semihosting/${ARCH}/semihosting_call.S \ ${PLAT_QEMU_COMMON_PATH}/qemu_io_storage.c \ ${PLAT_QEMU_COMMON_PATH}/${ARCH}/plat_helpers.S \ ${PLAT_QEMU_COMMON_PATH}/qemu_bl2_setup.c \ ${PLAT_QEMU_COMMON_PATH}/qemu_bl2_mem_params_desc.c \ ${PLAT_QEMU_COMMON_PATH}/qemu_image_load.c \ common/fdt_fixup.c \ common/desc_image_load.c ifeq ($(add-lib-optee),yes) BL2_SOURCES += lib/optee/optee_utils.c endif QEMU_GICV2_SOURCES := drivers/arm/gic/v2/gicv2_helpers.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/common/gic_common.c \ plat/common/plat_gicv2.c \ ${PLAT_QEMU_COMMON_PATH}/qemu_gicv2.c QEMU_GICV3_SOURCES := drivers/arm/gic/v3/gicv3_helpers.c \ drivers/arm/gic/v3/gicv3_main.c \ drivers/arm/gic/common/gic_common.c \ plat/common/plat_gicv3.c \ ${PLAT_QEMU_COMMON_PATH}/qemu_gicv3.c ifeq (${QEMU_USE_GIC_DRIVER}, QEMU_GICV2) QEMU_GIC_SOURCES := ${QEMU_GICV2_SOURCES} else ifeq (${QEMU_USE_GIC_DRIVER}, QEMU_GICV3) QEMU_GIC_SOURCES := ${QEMU_GICV3_SOURCES} else $(error "Incorrect GIC driver chosen for QEMU platform") endif ifeq (${ARM_ARCH_MAJOR},8) BL31_SOURCES += lib/cpus/aarch64/aem_generic.S \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S \ plat/common/plat_psci_common.c \ ${PLAT_QEMU_COMMON_PATH}/qemu_pm.c \ ${PLAT_QEMU_COMMON_PATH}/topology.c \ ${PLAT_QEMU_COMMON_PATH}/aarch64/plat_helpers.S \ ${PLAT_QEMU_COMMON_PATH}/qemu_bl31_setup.c \ ${QEMU_GIC_SOURCES} endif # Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images # in the FIP if the platform requires. ifneq ($(BL32_EXTRA1),) $(eval $(call TOOL_ADD_IMG,bl32_extra1,--tos-fw-extra1)) endif ifneq ($(BL32_EXTRA2),) $(eval $(call TOOL_ADD_IMG,bl32_extra2,--tos-fw-extra2)) endif SEPARATE_CODE_AND_RODATA := 1 ENABLE_STACK_PROTECTOR := 0 ifneq ($(ENABLE_STACK_PROTECTOR), 0) PLAT_BL_COMMON_SOURCES += ${PLAT_QEMU_COMMON_PATH}/qemu_stack_protector.c endif BL32_RAM_LOCATION := tdram ifeq (${BL32_RAM_LOCATION}, tsram) BL32_RAM_LOCATION_ID = SEC_SRAM_ID else ifeq (${BL32_RAM_LOCATION}, tdram) BL32_RAM_LOCATION_ID = SEC_DRAM_ID else $(error "Unsupported BL32_RAM_LOCATION value") endif # Process flags $(eval $(call add_define,BL32_RAM_LOCATION_ID)) # Do not enable SVE ENABLE_SVE_FOR_NS := 0 trusted-firmware-a-2.2/plat/qemu/qemu_sbsa/000077500000000000000000000000001355360272700207775ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/qemu/qemu_sbsa/include/000077500000000000000000000000001355360272700224225ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/qemu/qemu_sbsa/include/platform_def.h000066400000000000000000000165031355360272700252420ustar00rootroot00000000000000/* SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 2019, Linaro Limited and Contributors. All rights reserved. */ #ifndef __PLATFORM_DEF_H__ #define __PLATFORM_DEF_H__ #include #include #include /* Special value used to verify platform parameters from BL2 to BL3-1 */ #define QEMU_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL #define PLATFORM_STACK_SIZE 0x1000 #define PLATFORM_MAX_CPUS_PER_CLUSTER 4 #define PLATFORM_CLUSTER_COUNT 2 #define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER #define PLATFORM_CLUSTER1_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT + \ PLATFORM_CLUSTER1_CORE_COUNT) #define QEMU_PRIMARY_CPU 0 #define PLAT_NUM_PWR_DOMAINS (PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1 #define PLAT_MAX_RET_STATE 1 #define PLAT_MAX_OFF_STATE 2 /* Local power state for power domains in Run state. */ #define PLAT_LOCAL_STATE_RUN 0 /* Local power state for retention. Valid only for CPU power domains */ #define PLAT_LOCAL_STATE_RET 1 /* * Local power state for OFF/power-down. Valid for CPU and cluster power * domains. */ #define PLAT_LOCAL_STATE_OFF 2 /* * Macros used to parse state information from State-ID if it is using the * recommended encoding for State-ID. */ #define PLAT_LOCAL_PSTATE_WIDTH 4 #define PLAT_LOCAL_PSTATE_MASK ((1 << PLAT_LOCAL_PSTATE_WIDTH) - 1) /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. */ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) /* * Partition memory into secure ROM, non-secure DRAM, secure "SRAM", * and secure DRAM. */ #define SEC_ROM_BASE 0x00000000 #define SEC_ROM_SIZE 0x00020000 #define NS_DRAM0_BASE 0x10000000000ULL #define NS_DRAM0_SIZE 0x00020000000 #define SEC_SRAM_BASE 0x20000000 #define SEC_SRAM_SIZE 0x20000000 /* * RAD just placeholders, need to be chosen after finalizing mem map */ #define SEC_DRAM_BASE 0x1000 #define SEC_DRAM_SIZE 0x1000 /* Load pageable part of OP-TEE 2MB above secure DRAM base */ #define QEMU_OPTEE_PAGEABLE_LOAD_BASE (SEC_DRAM_BASE + 0x00200000) #define QEMU_OPTEE_PAGEABLE_LOAD_SIZE 0x00400000 /* * ARM-TF lives in SRAM, partition it here */ #define SHARED_RAM_BASE SEC_SRAM_BASE #define SHARED_RAM_SIZE 0x00001000 #define PLAT_QEMU_TRUSTED_MAILBOX_BASE SHARED_RAM_BASE #define PLAT_QEMU_TRUSTED_MAILBOX_SIZE (8 + PLAT_QEMU_HOLD_SIZE) #define PLAT_QEMU_HOLD_BASE (PLAT_QEMU_TRUSTED_MAILBOX_BASE + 8) #define PLAT_QEMU_HOLD_SIZE (PLATFORM_CORE_COUNT * \ PLAT_QEMU_HOLD_ENTRY_SIZE) #define PLAT_QEMU_HOLD_ENTRY_SHIFT 3 #define PLAT_QEMU_HOLD_ENTRY_SIZE (1 << PLAT_QEMU_HOLD_ENTRY_SHIFT) #define PLAT_QEMU_HOLD_STATE_WAIT 0 #define PLAT_QEMU_HOLD_STATE_GO 1 #define BL_RAM_BASE (SHARED_RAM_BASE + SHARED_RAM_SIZE) #define BL_RAM_SIZE (SEC_SRAM_SIZE - SHARED_RAM_SIZE) /* * BL1 specific defines. * * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of * addresses. * Put BL1 RW at the top of the Secure SRAM. BL1_RW_BASE is calculated using * the current BL1 RW debug size plus a little space for growth. */ #define BL1_RO_BASE SEC_ROM_BASE #define BL1_RO_LIMIT (SEC_ROM_BASE + SEC_ROM_SIZE) #define BL1_RW_BASE (BL1_RW_LIMIT - 0x12000) #define BL1_RW_LIMIT (BL_RAM_BASE + BL_RAM_SIZE) /* * BL2 specific defines. * * 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 (BL31_BASE - 0x1D000) #define BL2_LIMIT BL31_BASE /* * BL3-1 specific defines. * * Put BL3-1 at the top of the Trusted SRAM. BL31_BASE is calculated using the * current BL3-1 debug size plus a little space for growth. */ #define BL31_BASE (BL31_LIMIT - 0x20000) #define BL31_LIMIT (BL_RAM_BASE + BL_RAM_SIZE) #define BL31_PROGBITS_LIMIT BL1_RW_BASE /* * BL3-2 specific defines. * * BL3-2 can execute from Secure SRAM, or Secure DRAM. */ #define BL32_SRAM_BASE BL_RAM_BASE #define BL32_SRAM_LIMIT BL31_BASE #define BL32_DRAM_BASE SEC_DRAM_BASE #define BL32_DRAM_LIMIT (SEC_DRAM_BASE + SEC_DRAM_SIZE) #define BL32_MEM_BASE BL_RAM_BASE #define BL32_MEM_SIZE BL_RAM_SIZE #define BL32_BASE BL32_SRAM_BASE #define BL32_LIMIT BL32_SRAM_LIMIT #define NS_IMAGE_OFFSET (NS_DRAM0_BASE + 0x20000000) #define NS_IMAGE_MAX_SIZE (NS_DRAM0_SIZE - 0x20000000) #define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 42) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 42) #define MAX_MMAP_REGIONS 11 #define MAX_XLAT_TABLES 10 #define MAX_IO_DEVICES 3 #define MAX_IO_HANDLES 4 /* * PL011 related constants */ #define UART0_BASE 0x60000000 #define UART1_BASE 0x60030000 #define UART0_CLK_IN_HZ 1 #define UART1_CLK_IN_HZ 1 #define PLAT_QEMU_BOOT_UART_BASE UART0_BASE #define PLAT_QEMU_BOOT_UART_CLK_IN_HZ UART0_CLK_IN_HZ #define PLAT_QEMU_CRASH_UART_BASE UART1_BASE #define PLAT_QEMU_CRASH_UART_CLK_IN_HZ UART1_CLK_IN_HZ #define PLAT_QEMU_CONSOLE_BAUDRATE 115200 #define QEMU_FLASH0_BASE 0x00000000 #define QEMU_FLASH0_SIZE 0x10000000 #define QEMU_FLASH1_BASE 0x10000000 #define QEMU_FLASH1_SIZE 0x10000000 #define PLAT_QEMU_FIP_BASE 0x00008000 #define PLAT_QEMU_FIP_MAX_SIZE 0x00020000 /* This is map from GIC_DIST up to last CPU (255) GIC_REDISTR */ #define DEVICE0_BASE 0x40000000 #define DEVICE0_SIZE 0x04080000 /* This is map from NORMAL_UART up to SECURE_UART_MM */ #define DEVICE1_BASE 0x60000000 #define DEVICE1_SIZE 0x00041000 /* * GIC related constants * We use GICv3 where CPU Interface registers are not memory mapped */ #define GICD_BASE 0x40060000 #define GICR_BASE 0x40080000 #define GICC_BASE 0x0 #define QEMU_IRQ_SEC_SGI_0 8 #define QEMU_IRQ_SEC_SGI_1 9 #define QEMU_IRQ_SEC_SGI_2 10 #define QEMU_IRQ_SEC_SGI_3 11 #define QEMU_IRQ_SEC_SGI_4 12 #define QEMU_IRQ_SEC_SGI_5 13 #define QEMU_IRQ_SEC_SGI_6 14 #define QEMU_IRQ_SEC_SGI_7 15 /****************************************************************************** * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0 * interrupts. *****************************************************************************/ #define PLATFORM_G1S_PROPS(grp) \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(QEMU_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE) #define PLATFORM_G0_PROPS(grp) /* * DT related constants */ #define PLAT_QEMU_DT_BASE NS_DRAM0_BASE #define PLAT_QEMU_DT_MAX_SIZE 0x10000 /* * System counter */ #define SYS_COUNTER_FREQ_IN_TICKS ((1000 * 1000 * 1000) / 16) #endif /* __PLATFORM_DEF_H__ */ trusted-firmware-a-2.2/plat/qemu/qemu_sbsa/platform.mk000066400000000000000000000061151355360272700231570ustar00rootroot00000000000000# # Copyright (c) 2019, Linaro Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # CRASH_REPORTING := 1 include lib/libfdt/libfdt.mk # Enable new version of image loading on QEMU platforms LOAD_IMAGE_V2 := 1 ifeq ($(NEED_BL32),yes) $(eval $(call add_define,QEMU_LOAD_BL32)) endif PLAT_QEMU_PATH := plat/qemu/qemu_sbsa PLAT_QEMU_COMMON_PATH := plat/qemu/common PLAT_INCLUDES := -Iinclude/plat/arm/common/ \ -I${PLAT_QEMU_COMMON_PATH}/include \ -I${PLAT_QEMU_PATH}/include \ -Iinclude/common/tbbr PLAT_INCLUDES += -Iinclude/plat/arm/common/${ARCH} PLAT_BL_COMMON_SOURCES := ${PLAT_QEMU_COMMON_PATH}/qemu_common.c \ ${PLAT_QEMU_COMMON_PATH}/qemu_console.c \ drivers/arm/pl011/${ARCH}/pl011_console.S include lib/xlat_tables_v2/xlat_tables.mk PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} BL1_SOURCES += drivers/io/io_semihosting.c \ drivers/io/io_storage.c \ drivers/io/io_fip.c \ drivers/io/io_memmap.c \ lib/semihosting/semihosting.c \ lib/semihosting/${ARCH}/semihosting_call.S \ ${PLAT_QEMU_COMMON_PATH}/qemu_io_storage.c \ ${PLAT_QEMU_COMMON_PATH}/${ARCH}/plat_helpers.S \ ${PLAT_QEMU_COMMON_PATH}/qemu_bl1_setup.c BL1_SOURCES += lib/cpus/aarch64/aem_generic.S \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S BL2_SOURCES += drivers/io/io_semihosting.c \ drivers/io/io_storage.c \ drivers/io/io_fip.c \ drivers/io/io_memmap.c \ lib/semihosting/semihosting.c \ lib/semihosting/${ARCH}/semihosting_call.S \ ${PLAT_QEMU_COMMON_PATH}/qemu_io_storage.c \ ${PLAT_QEMU_COMMON_PATH}/${ARCH}/plat_helpers.S \ ${PLAT_QEMU_COMMON_PATH}/qemu_bl2_setup.c \ common/fdt_fixup.c \ $(LIBFDT_SRCS) ifeq (${LOAD_IMAGE_V2},1) BL2_SOURCES += ${PLAT_QEMU_COMMON_PATH}/qemu_bl2_mem_params_desc.c \ ${PLAT_QEMU_COMMON_PATH}/qemu_image_load.c \ common/desc_image_load.c endif QEMU_GIC_SOURCES := drivers/arm/gic/v3/gicv3_helpers.c \ drivers/arm/gic/v3/gicv3_main.c \ drivers/arm/gic/common/gic_common.c \ plat/common/plat_gicv3.c \ ${PLAT_QEMU_COMMON_PATH}/qemu_gicv3.c BL31_SOURCES += lib/cpus/aarch64/aem_generic.S \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S \ plat/common/plat_psci_common.c \ ${PLAT_QEMU_COMMON_PATH}/qemu_pm.c \ ${PLAT_QEMU_COMMON_PATH}/topology.c \ ${PLAT_QEMU_COMMON_PATH}/aarch64/plat_helpers.S \ ${PLAT_QEMU_COMMON_PATH}/qemu_bl31_setup.c \ ${QEMU_GIC_SOURCES} SEPARATE_CODE_AND_RODATA := 1 ENABLE_STACK_PROTECTOR := 0 ifneq ($(ENABLE_STACK_PROTECTOR), 0) PLAT_BL_COMMON_SOURCES += ${PLAT_QEMU_COMMON_PATH}/qemu_stack_protector.c endif MULTI_CONSOLE_API := 1 # Disable the PSCI platform compatibility layer ENABLE_PLAT_COMPAT := 0 # Use known base for UEFI if not given from command line # By default BL33 is at FLASH1 base PRELOADED_BL33_BASE ?= 0x10000000 # Qemu SBSA plafrom only support SEC_SRAM BL32_RAM_LOCATION_ID = SEC_SRAM_ID $(eval $(call add_define,BL32_RAM_LOCATION_ID)) # Do not enable SVE ENABLE_SVE_FOR_NS := 0 trusted-firmware-a-2.2/plat/renesas/000077500000000000000000000000001355360272700175115ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/renesas/rcar/000077500000000000000000000000001355360272700204405ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/renesas/rcar/aarch64/000077500000000000000000000000001355360272700216705ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/renesas/rcar/aarch64/plat_helpers.S000066400000000000000000000230621355360272700245010ustar00rootroot00000000000000/* * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "rcar_def.h" .globl plat_get_my_entrypoint .extern plat_set_my_stack .globl platform_mem_init .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush .globl plat_invalidate_icache .globl plat_report_exception .globl plat_secondary_reset .globl plat_reset_handler .globl plat_my_core_pos .extern rcar_log_init .extern console_rcar_init .extern console_rcar_putc .extern console_rcar_flush #if IMAGE_BL2 #define INT_ID_MASK (0x3ff) .extern bl2_interrupt_error_type .extern bl2_interrupt_error_id .globl bl2_enter_bl31 .extern gicv2_acknowledge_interrupt .extern rcar_swdt_exec #endif /* ----------------------------------------------------- * void platform_get_core_pos (mpidr) * ----------------------------------------------------- */ func platform_get_core_pos and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 ret endfunc platform_get_core_pos /* ----------------------------------------------------- * void platform_my_core_pos * ----------------------------------------------------- */ func plat_my_core_pos mrs x0, mpidr_el1 b platform_get_core_pos endfunc plat_my_core_pos /* ----------------------------------------------------- * void platform_get_my_entrypoint (unsigned int mpid); * * Main job of this routine is to distinguish between * a cold and warm boot. * On a cold boot the secondaries first wait for the * platform to be initialized after which they are * hotplugged in. The primary proceeds to perform the * platform initialization. * On a warm boot, each cpu jumps to the address in its * mailbox. * * TODO: Not a good idea to save lr in a temp reg * ----------------------------------------------------- */ func plat_get_my_entrypoint mrs x0, mpidr_el1 mov x9, x30 /* lr */ #if defined(IMAGE_BL2) /* always cold boot on bl2 */ mov x0, #0 ret x9 #else ldr x1, =BOOT_KIND_BASE ldr x21, [x1] /* Check the reset info */ and x1, x21, #0x000c cmp x1, #0x0008 beq el3_panic cmp x1, #0x000c beq el3_panic /* Check the boot kind */ and x1, x21, #0x0003 cmp x1, #0x0002 beq el3_panic cmp x1, #0x0003 beq el3_panic /* warm boot or cold boot */ and x1, x21, #1 cmp x1, #0 bne warm_reset /* Cold boot */ mov x0, #0 b exit warm_reset: /* -------------------------------------------------------------------- * A per-cpu mailbox is maintained in the trusted SDRAM. Its flushed out * of the caches after every update using normal memory so its safe to * read it here with SO attributes * --------------------------------------------------------------------- */ ldr x10, =MBOX_BASE bl platform_get_core_pos lsl x0, x0, #CACHE_WRITEBACK_SHIFT ldr x0, [x10, x0] cbz x0, _panic exit: ret x9 _panic: b do_panic #endif endfunc plat_get_my_entrypoint /* --------------------------------------------- * plat_secondary_reset * * --------------------------------------------- */ func plat_secondary_reset mrs x0, sctlr_el3 bic x0, x0, #SCTLR_EE_BIT msr sctlr_el3, x0 isb mrs x0, cptr_el3 bic w0, w0, #TCPAC_BIT bic w0, w0, #TTA_BIT bic w0, w0, #TFP_BIT msr cptr_el3, x0 mov_imm x0, PARAMS_BASE mov_imm x2, BL31_BASE ldr x3, =BOOT_KIND_BASE mov x1, #0x1 str x1, [x3] br x2 /* jump to BL31 */ nop nop nop endfunc plat_secondary_reset /* --------------------------------------------- * plat_enter_bl31 * * --------------------------------------------- */ func bl2_enter_bl31 mov x20, x0 /* * MMU needs to be disabled because both BL2 and BL31 execute * in EL3, and therefore share the same address space. * BL31 will initialize the address space according to its * own requirement. */ #if RCAR_BL2_DCACHE == 1 /* Disable mmu and data cache */ bl disable_mmu_el3 /* Data cache clean and invalidate */ mov x0, #DCCISW bl dcsw_op_all /* TLB invalidate all, EL3 */ tlbi alle3 #endif /* RCAR_BL2_DCACHE == 1 */ bl disable_mmu_icache_el3 /* Invalidate instruction cache */ ic iallu dsb sy isb ldp x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET] msr elr_el3, x0 msr spsr_el3, x1 eret endfunc bl2_enter_bl31 /* ----------------------------------------------------- * void platform_mem_init (void); * * Zero out the mailbox registers in the shared memory * and set the rcar_boot_kind_flag. * The mmu is turned off right now and only the primary can * ever execute this code. Secondaries will read the * mailboxes using SO accesses. * ----------------------------------------------------- */ func platform_mem_init #if !IMAGE_BL2 ldr x0, =MBOX_BASE mov w1, #PLATFORM_CORE_COUNT loop: str xzr, [x0], #CACHE_WRITEBACK_GRANULE subs w1, w1, #1 b.gt loop #endif ret endfunc platform_mem_init /* --------------------------------------------- * void plat_report_exception(unsigned int type) * Function to report an unhandled exception * with platform-specific means. * --------------------------------------------- */ func plat_report_exception /* Switch to SP_EL0 */ msr spsel, #0 #if IMAGE_BL2 mov w1, #FIQ_SP_EL0 cmp w0, w1 beq rep_exec_fiq_elx b rep_exec_panic_type rep_exec_fiq_elx: bl gicv2_acknowledge_interrupt mov x2, #INT_ID_MASK and x0, x0, x2 mov x1, #ARM_IRQ_SEC_WDT cmp x0, x1 bne rep_exec_panic_id mrs x0, ELR_EL3 b rcar_swdt_exec rep_exec_panic_type: /* x0 is interrupt TYPE */ b bl2_interrupt_error_type rep_exec_panic_id: /* x0 is interrupt ID */ b bl2_interrupt_error_id rep_exec_end: #endif ret endfunc plat_report_exception /* --------------------------------------------- * int plat_crash_console_init(void) * Function to initialize log area * --------------------------------------------- */ func plat_crash_console_init #if IMAGE_BL2 mov x0, #0 #else mov x1, sp mov_imm x2, RCAR_CRASH_STACK mov sp, x2 str x1, [sp, #-16]! str x30, [sp, #-16]! bl console_rcar_init ldr x30, [sp], #16 ldr x1, [sp], #16 mov sp, x1 #endif ret endfunc plat_crash_console_init /* --------------------------------------------- * int plat_crash_console_putc(int c) * Function to store a character to log area * --------------------------------------------- */ func plat_crash_console_putc mov x1, sp mov_imm x2, RCAR_CRASH_STACK mov sp, x2 str x1, [sp, #-16]! str x30, [sp, #-16]! str x3, [sp, #-16]! str x4, [sp, #-16]! str x5, [sp, #-16]! bl console_rcar_putc ldr x5, [sp], #16 ldr x4, [sp], #16 ldr x3, [sp], #16 ldr x30, [sp], #16 ldr x1, [sp], #16 mov sp, x1 ret endfunc plat_crash_console_putc /* --------------------------------------------- * int plat_crash_console_flush() * --------------------------------------------- */ func plat_crash_console_flush b console_rcar_flush endfunc plat_crash_console_flush /* -------------------------------------------------------------------- * void plat_reset_handler(void); * * Before adding code in this function, refer to the guidelines in * docs/firmware-design.md to determine whether the code should reside * within the FIRST_RESET_HANDLER_CALL block or not. * * For R-Car H3: * - Set the L2 Tag RAM latency to 2 (i.e. 3 cycles) for Cortex-A57 * - Set the L2 Data setup latency to 1 (i.e. 1 cycles) for Cortex-A57 * - Set the L2 Data RAM latency to 3 (i.e. 4 cycles) for Cortex-A57 * For R-Car M3/M3N: * - Set the L2 Tag RAM latency to 2 (i.e. 3 cycles) for Cortex-A57 * - Set the L2 Data setup latency to 0 (i.e. 0 cycles) for Cortex-A57 * - Set the L2 Data RAM latency to 3 (i.e. 4 cycles) for Cortex-A57 * * -------------------------------------------------------------------- */ func plat_reset_handler /* * On R-Car H3 : x2 := 0 * On R-Car M3/M3N: x2 := 1 */ /* read PRR */ ldr x0, =0xFFF00044 ldr w0, [x0] ubfx w0, w0, 8, 8 /* H3? */ cmp w0, #0x4F b.eq RCARH3 /* set R-Car M3/M3N */ mov x2, #1 b CHK_A5x RCARH3: /* set R-Car H3 */ mov x2, #0 /* -------------------------------------------------------------------- * Determine whether this code is executed on a Cortex-A53 or on a * Cortex-A57 core. * -------------------------------------------------------------------- */ CHK_A5x: mrs x0, midr_el1 ubfx x1, x0, MIDR_PN_SHIFT, #12 cmp w1, #((CORTEX_A57_MIDR >> MIDR_PN_SHIFT) & MIDR_PN_MASK) b.eq A57 ret A57: /* Get data from CORTEX_A57_L2CTLR_EL1 */ mrs x0, CORTEX_A57_L2CTLR_EL1 /* * On R-Car H3/M3/M3N * * L2 Tag RAM latency is bit8-6 of CORTEX_A57_L2CTLR_EL1 * L2 Data RAM setup is bit5 of CORTEX_A57_L2CTLR_EL1 * L2 Data RAM latency is bit2-0 of CORTEX_A57_L2CTLR_EL1 */ /* clear bit of L2 RAM */ /* ~(0x1e7) -> x1 */ mov x1, #0x1e7 neg x1, x1 /* clear bit of L2 RAM -> x0 */ and x0, x0, x1 /* L2 Tag RAM latency (3 cycles) */ orr x0, x0, #0x2 << 6 /* If M3/M3N then L2 RAM setup is 0 */ cbnz x2, M3_L2 /* L2 Data RAM setup (1 cycle) */ orr x0, x0, #0x1 << 5 M3_L2: /* L2 Data RAM latency (4 cycles) */ orr x0, x0, #0x3 /* Store data to L2CTLR_EL1 */ msr CORTEX_A57_L2CTLR_EL1, x0 apply_l2_ram_latencies: ret endfunc plat_reset_handler /* --------------------------------------------- * void plat_invalidate_icache(void) * Instruction Cache Invalidate All to PoU * --------------------------------------------- */ func plat_invalidate_icache ic iallu ret endfunc plat_invalidate_icache trusted-firmware-a-2.2/plat/renesas/rcar/aarch64/platform_common.c000066400000000000000000000175501355360272700252400ustar00rootroot00000000000000/* * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include "rcar_def.h" #include "rcar_private.h" #include "rcar_version.h" #if (IMAGE_BL2) extern void rcar_read_certificate(uint64_t cert, uint32_t *len, uintptr_t *p); extern int32_t rcar_get_certificate(const int32_t name, uint32_t *cert); #endif const uint8_t version_of_renesas[VERSION_OF_RENESAS_MAXLEN] __attribute__ ((__section__("ro"))) = VERSION_OF_RENESAS; #define MAP_SHARED_RAM MAP_REGION_FLAT(RCAR_SHARED_MEM_BASE, \ RCAR_SHARED_MEM_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #define MAP_FLASH0 MAP_REGION_FLAT(FLASH0_BASE, \ FLASH0_SIZE, \ MT_MEMORY | MT_RO | MT_SECURE) #define MAP_DRAM1_NS MAP_REGION_FLAT(DRAM1_NS_BASE, \ DRAM1_NS_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define MAP_DEVICE_RCAR MAP_REGION_FLAT(DEVICE_RCAR_BASE, \ DEVICE_RCAR_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_DEVICE_RCAR2 MAP_REGION_FLAT(DEVICE_RCAR_BASE2, \ DEVICE_RCAR_SIZE2, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_SRAM MAP_REGION_FLAT(DEVICE_SRAM_BASE, \ DEVICE_SRAM_SIZE, \ MT_MEMORY | MT_RO | MT_SECURE) #define MAP_SRAM_STACK MAP_REGION_FLAT(DEVICE_SRAM_STACK_BASE, \ DEVICE_SRAM_STACK_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #define MAP_ATFW_CRASH MAP_REGION_FLAT(RCAR_BL31_CRASH_BASE, \ RCAR_BL31_CRASH_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #define MAP_ATFW_LOG MAP_REGION_FLAT(RCAR_BL31_LOG_BASE, \ RCAR_BL31_LOG_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #if IMAGE_BL2 #define MAP_DRAM0 MAP_REGION_FLAT(DRAM1_BASE, \ DRAM1_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #define MAP_REG0 MAP_REGION_FLAT(DEVICE_RCAR_BASE, \ DEVICE_RCAR_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_RAM0 MAP_REGION_FLAT(RCAR_SYSRAM_BASE, \ RCAR_SYSRAM_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #define MAP_REG1 MAP_REGION_FLAT(REG1_BASE, \ REG1_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_ROM MAP_REGION_FLAT(ROM0_BASE, \ ROM0_SIZE, \ MT_MEMORY | MT_RO | MT_SECURE) #define MAP_REG2 MAP_REGION_FLAT(REG2_BASE, \ REG2_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #define MAP_DRAM1 MAP_REGION_FLAT(DRAM_40BIT_BASE, \ DRAM_40BIT_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #endif #ifdef BL32_BASE #define MAP_BL32_MEM MAP_REGION_FLAT(BL32_BASE, \ BL32_LIMIT - BL32_BASE, \ MT_MEMORY | MT_RW | MT_SECURE) #endif #if IMAGE_BL2 static const mmap_region_t rcar_mmap[] = { MAP_FLASH0, /* 0x08000000 - 0x0BFFFFFF RPC area */ MAP_DRAM0, /* 0x40000000 - 0xBFFFFFFF DRAM area(Legacy) */ MAP_REG0, /* 0xE6000000 - 0xE62FFFFF SoC register area */ MAP_RAM0, /* 0xE6300000 - 0xE6303FFF System RAM area */ MAP_REG1, /* 0xE6400000 - 0xEAFFFFFF SoC register area */ MAP_ROM, /* 0xEB100000 - 0xEB127FFF boot ROM area */ MAP_REG2, /* 0xEC000000 - 0xFFFFFFFF SoC register area */ MAP_DRAM1, /* 0x0400000000 - 0x07FFFFFFFF DRAM area(4GB over) */ {0} }; #endif #if IMAGE_BL31 static const mmap_region_t rcar_mmap[] = { MAP_SHARED_RAM, MAP_ATFW_CRASH, MAP_ATFW_LOG, MAP_DEVICE_RCAR, MAP_DEVICE_RCAR2, MAP_SRAM, MAP_SRAM_STACK, {0} }; #endif #if IMAGE_BL32 static const mmap_region_t rcar_mmap[] = { MAP_DEVICE0, MAP_DEVICE1, {0} }; #endif CASSERT(ARRAY_SIZE(rcar_mmap) + RCAR_BL_REGIONS <= MAX_MMAP_REGIONS, assert_max_mmap_regions); /* * Macro generating the code for the function setting up the pagetables as per * the platform memory map & initialize the mmu, for the given exception level */ #if USE_COHERENT_MEM void rcar_configure_mmu_el3(unsigned long total_base, unsigned long total_size, unsigned long ro_start, unsigned long ro_limit, unsigned long coh_start, unsigned long coh_limit) { mmap_add_region(total_base, total_base, total_size, MT_MEMORY | MT_RW | MT_SECURE); mmap_add_region(ro_start, ro_start, ro_limit - ro_start, MT_MEMORY | MT_RO | MT_SECURE); mmap_add_region(coh_start, coh_start, coh_limit - coh_start, MT_DEVICE | MT_RW | MT_SECURE); mmap_add(rcar_mmap); init_xlat_tables(); enable_mmu_el3(0); } #else void rcar_configure_mmu_el3(unsigned long total_base, unsigned long total_size, unsigned long ro_start, unsigned long ro_limit) { mmap_add_region(total_base, total_base, total_size, MT_MEMORY | MT_RW | MT_SECURE); mmap_add_region(ro_start, ro_start, ro_limit - ro_start, MT_MEMORY | MT_RO | MT_SECURE); mmap_add(rcar_mmap); init_xlat_tables(); enable_mmu_el3(0); } #endif uintptr_t plat_get_ns_image_entrypoint(void) { #if (IMAGE_BL2) uint32_t cert, len; uintptr_t dst; int32_t ret; ret = rcar_get_certificate(NON_TRUSTED_FW_CONTENT_CERT_ID, &cert); if (ret) { ERROR("%s : cert file load error", __func__); return NS_IMAGE_OFFSET; } rcar_read_certificate((uint64_t) cert, &len, &dst); return dst; #else return NS_IMAGE_OFFSET; #endif } unsigned int plat_get_syscnt_freq2(void) { unsigned int freq; freq = mmio_read_32(ARM_SYS_CNTCTL_BASE + CNTFID_OFF); if (freq == 0) panic(); return freq; } void plat_rcar_gic_init(void) { gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } static const interrupt_prop_t interrupt_props[] = { #if IMAGE_BL2 INTR_PROP_DESC(ARM_IRQ_SEC_WDT, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), #else INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE), INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE), INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE), INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE), INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE), INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE), INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE), INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE), INTR_PROP_DESC(ARM_IRQ_SEC_RPC, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(ARM_IRQ_SEC_TIMER, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(ARM_IRQ_SEC_TIMER_UP, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(ARM_IRQ_SEC_WDT, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(ARM_IRQ_SEC_CRYPT, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(ARM_IRQ_SEC_CRYPT_SecPKA, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), INTR_PROP_DESC(ARM_IRQ_SEC_CRYPT_PubPKA, GIC_HIGHEST_SEC_PRIORITY, GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), #endif }; static const gicv2_driver_data_t plat_gicv2_driver_data = { .interrupt_props = interrupt_props, .interrupt_props_num = (uint32_t) ARRAY_SIZE(interrupt_props), .gicd_base = RCAR_GICD_BASE, .gicc_base = RCAR_GICC_BASE, }; void plat_rcar_gic_driver_init(void) { gicv2_driver_init(&plat_gicv2_driver_data); } trusted-firmware-a-2.2/plat/renesas/rcar/bl2_cpg_init.c000066400000000000000000000265621355360272700231520ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "rcar_def.h" #include "cpg_registers.h" #include "rcar_private.h" static void bl2_secure_cpg_init(void); #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_H3) || (RCAR_LSI == RCAR_H3N) static void bl2_realtime_cpg_init_h3(void); static void bl2_system_cpg_init_h3(void); #endif #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3) static void bl2_realtime_cpg_init_m3(void); static void bl2_system_cpg_init_m3(void); #endif #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3N) static void bl2_realtime_cpg_init_m3n(void); static void bl2_system_cpg_init_m3n(void); #endif #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_V3M) static void bl2_realtime_cpg_init_v3m(void); static void bl2_system_cpg_init_v3m(void); #endif #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_E3) static void bl2_realtime_cpg_init_e3(void); static void bl2_system_cpg_init_e3(void); #endif #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_D3) static void bl2_realtime_cpg_init_d3(void); static void bl2_system_cpg_init_d3(void); #endif typedef struct { uintptr_t adr; uint32_t val; } reg_setting_t; static void bl2_secure_cpg_init(void) { uint32_t stop_cr2, reset_cr2; uint32_t stop_cr4, reset_cr4; uint32_t stop_cr5, reset_cr5; #if (RCAR_LSI == RCAR_D3) reset_cr2 = 0x00000000U; stop_cr2 = 0xFFFFFFFFU; #elif (RCAR_LSI == RCAR_E3) reset_cr2 = 0x10000000U; stop_cr2 = 0xEFFFFFFFU; #else reset_cr2 = 0x14000000U; stop_cr2 = 0xEBFFFFFFU; #endif #if (RCAR_LSI == RCAR_D3) reset_cr4 = 0x00000000U; stop_cr4 = 0xFFFFFFFFU; reset_cr5 = 0x00000000U; stop_cr5 = 0xFFFFFFFFU; #else reset_cr4 = 0x80000003U; stop_cr4 = 0x7FFFFFFFU; reset_cr5 = 0x40000000U; stop_cr5 = 0xBFFFFFFFU; #endif /** Secure Module Stop Control Registers */ cpg_write(SCMSTPCR0, 0xFFFFFFFFU); cpg_write(SCMSTPCR1, 0xFFFFFFFFU); cpg_write(SCMSTPCR2, stop_cr2); cpg_write(SCMSTPCR3, 0xFFFFFFFFU); cpg_write(SCMSTPCR4, stop_cr4); cpg_write(SCMSTPCR5, stop_cr5); cpg_write(SCMSTPCR6, 0xFFFFFFFFU); cpg_write(SCMSTPCR7, 0xFFFFFFFFU); cpg_write(SCMSTPCR8, 0xFFFFFFFFU); cpg_write(SCMSTPCR9, 0xFFFDFFFFU); cpg_write(SCMSTPCR10, 0xFFFFFFFFU); cpg_write(SCMSTPCR11, 0xFFFFFFFFU); /** Secure Software Reset Access Enable Control Registers */ cpg_write(SCSRSTECR0, 0x00000000U); cpg_write(SCSRSTECR1, 0x00000000U); cpg_write(SCSRSTECR2, reset_cr2); cpg_write(SCSRSTECR3, 0x00000000U); cpg_write(SCSRSTECR4, reset_cr4); cpg_write(SCSRSTECR5, reset_cr5); cpg_write(SCSRSTECR6, 0x00000000U); cpg_write(SCSRSTECR7, 0x00000000U); cpg_write(SCSRSTECR8, 0x00000000U); cpg_write(SCSRSTECR9, 0x00020000U); cpg_write(SCSRSTECR10, 0x00000000U); cpg_write(SCSRSTECR11, 0x00000000U); } #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_H3) || (RCAR_LSI == RCAR_H3N) static void bl2_realtime_cpg_init_h3(void) { uint32_t cut = mmio_read_32(RCAR_PRR) & PRR_CUT_MASK; uint32_t cr0, cr8; cr0 = (cut == PRR_PRODUCT_10 || cut == PRR_PRODUCT_11) ? 0x00200000U : 0x00210000U; cr8 = (cut == PRR_PRODUCT_10 || cut == PRR_PRODUCT_11) ? 0x01F1FFF4U : 0x01F1FFF7U; cpg_write(RMSTPCR0, cr0); cpg_write(RMSTPCR1, 0xFFFFFFFFU); cpg_write(RMSTPCR2, 0x040E0FDCU); cpg_write(RMSTPCR3, 0xFFFFFFDFU); cpg_write(RMSTPCR4, 0x80000004U); cpg_write(RMSTPCR5, 0xC3FFFFFFU); cpg_write(RMSTPCR6, 0xFFFFFFFFU); cpg_write(RMSTPCR7, 0xFFFFFFFFU); cpg_write(RMSTPCR8, cr8); cpg_write(RMSTPCR9, 0xFFFFFFFEU); cpg_write(RMSTPCR10, 0xFFFEFFE0U); cpg_write(RMSTPCR11, 0x000000B7U); } static void bl2_system_cpg_init_h3(void) { /** System Module Stop Control Registers */ cpg_write(SMSTPCR0, 0x00210000U); cpg_write(SMSTPCR1, 0xFFFFFFFFU); cpg_write(SMSTPCR2, 0x040E2FDCU); cpg_write(SMSTPCR3, 0xFFFFFBDFU); cpg_write(SMSTPCR4, 0x80000004U); cpg_write(SMSTPCR5, 0xC3FFFFFFU); cpg_write(SMSTPCR6, 0xFFFFFFFFU); cpg_write(SMSTPCR7, 0xFFFFFFFFU); cpg_write(SMSTPCR8, 0x01F1FFF5U); cpg_write(SMSTPCR9, 0xFFFFFFFFU); cpg_write(SMSTPCR10, 0xFFFEFFE0U); cpg_write(SMSTPCR11, 0x000000B7U); } #endif #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3) static void bl2_realtime_cpg_init_m3(void) { /** Realtime Module Stop Control Registers */ cpg_write(RMSTPCR0, 0x00200000U); cpg_write(RMSTPCR1, 0xFFFFFFFFU); cpg_write(RMSTPCR2, 0x040E0FDCU); cpg_write(RMSTPCR3, 0xFFFFFFDFU); cpg_write(RMSTPCR4, 0x80000004U); cpg_write(RMSTPCR5, 0xC3FFFFFFU); cpg_write(RMSTPCR6, 0xFFFFFFFFU); cpg_write(RMSTPCR7, 0xFFFFFFFFU); cpg_write(RMSTPCR8, 0x01F1FFF7U); cpg_write(RMSTPCR9, 0xFFFFFFFEU); cpg_write(RMSTPCR10, 0xFFFEFFE0U); cpg_write(RMSTPCR11, 0x000000B7U); } static void bl2_system_cpg_init_m3(void) { /** System Module Stop Control Registers */ cpg_write(SMSTPCR0, 0x00200000U); cpg_write(SMSTPCR1, 0xFFFFFFFFU); cpg_write(SMSTPCR2, 0x040E2FDCU); cpg_write(SMSTPCR3, 0xFFFFFBDFU); cpg_write(SMSTPCR4, 0x80000004U); cpg_write(SMSTPCR5, 0xC3FFFFFFU); cpg_write(SMSTPCR6, 0xFFFFFFFFU); cpg_write(SMSTPCR7, 0xFFFFFFFFU); cpg_write(SMSTPCR8, 0x01F1FFF7U); cpg_write(SMSTPCR9, 0xFFFFFFFFU); cpg_write(SMSTPCR10, 0xFFFEFFE0U); cpg_write(SMSTPCR11, 0x000000B7U); } #endif #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_M3N) static void bl2_realtime_cpg_init_m3n(void) { /** Realtime Module Stop Control Registers */ cpg_write(RMSTPCR0, 0x00210000U); cpg_write(RMSTPCR1, 0xFFFFFFFFU); cpg_write(RMSTPCR2, 0x040E0FDCU); cpg_write(RMSTPCR3, 0xFFFFFFDFU); cpg_write(RMSTPCR4, 0x80000004U); cpg_write(RMSTPCR5, 0xC3FFFFFFU); cpg_write(RMSTPCR6, 0xFFFFFFFFU); cpg_write(RMSTPCR7, 0xFFFFFFFFU); cpg_write(RMSTPCR8, 0x00F1FFF7U); cpg_write(RMSTPCR9, 0xFFFFFFFFU); cpg_write(RMSTPCR10, 0xFFFFFFE0U); cpg_write(RMSTPCR11, 0x000000B7U); } static void bl2_system_cpg_init_m3n(void) { /* System Module Stop Control Registers */ cpg_write(SMSTPCR0, 0x00210000U); cpg_write(SMSTPCR1, 0xFFFFFFFFU); cpg_write(SMSTPCR2, 0x040E2FDCU); cpg_write(SMSTPCR3, 0xFFFFFBDFU); cpg_write(SMSTPCR4, 0x80000004U); cpg_write(SMSTPCR5, 0xC3FFFFFFU); cpg_write(SMSTPCR6, 0xFFFFFFFFU); cpg_write(SMSTPCR7, 0xFFFFFFFFU); cpg_write(SMSTPCR8, 0x00F1FFF7U); cpg_write(SMSTPCR9, 0xFFFFFFFFU); cpg_write(SMSTPCR10, 0xFFFFFFE0U); cpg_write(SMSTPCR11, 0x000000B7U); } #endif #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_V3M) static void bl2_realtime_cpg_init_v3m(void) { /* Realtime Module Stop Control Registers */ cpg_write(RMSTPCR0, 0x00230000U); cpg_write(RMSTPCR1, 0xFFFFFFFFU); cpg_write(RMSTPCR2, 0x14062FD8U); cpg_write(RMSTPCR3, 0xFFFFFFDFU); cpg_write(RMSTPCR4, 0x80000184U); cpg_write(RMSTPCR5, 0x83FFFFFFU); cpg_write(RMSTPCR6, 0xFFFFFFFFU); cpg_write(RMSTPCR7, 0xFFFFFFFFU); cpg_write(RMSTPCR8, 0x7FF3FFF4U); cpg_write(RMSTPCR9, 0xFFFFFFFEU); } static void bl2_system_cpg_init_v3m(void) { /* System Module Stop Control Registers */ cpg_write(SMSTPCR0, 0x00210000U); cpg_write(SMSTPCR1, 0xFFFFFFFFU); cpg_write(SMSTPCR2, 0x340E2FDCU); cpg_write(SMSTPCR3, 0xFFFFFBDFU); cpg_write(SMSTPCR4, 0x80000004U); cpg_write(SMSTPCR5, 0xC3FFFFFFU); cpg_write(SMSTPCR6, 0xFFFFFFFFU); cpg_write(SMSTPCR7, 0xFFFFFFFFU); cpg_write(SMSTPCR8, 0x01F1FFF5U); cpg_write(SMSTPCR9, 0xFFFFFFFEU); } #endif #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_E3) static void bl2_realtime_cpg_init_e3(void) { /* Realtime Module Stop Control Registers */ cpg_write(RMSTPCR0, 0x00210000U); cpg_write(RMSTPCR1, 0xFFFFFFFFU); cpg_write(RMSTPCR2, 0x000E0FDCU); cpg_write(RMSTPCR3, 0xFFFFFFDFU); cpg_write(RMSTPCR4, 0x80000004U); cpg_write(RMSTPCR5, 0xC3FFFFFFU); cpg_write(RMSTPCR6, 0xFFFFFFFFU); cpg_write(RMSTPCR7, 0xFFFFFFFFU); cpg_write(RMSTPCR8, 0x00F1FFF7U); cpg_write(RMSTPCR9, 0xFFFFFFDFU); cpg_write(RMSTPCR10, 0xFFFFFFE8U); cpg_write(RMSTPCR11, 0x000000B7U); } static void bl2_system_cpg_init_e3(void) { /* System Module Stop Control Registers */ cpg_write(SMSTPCR0, 0x00210000U); cpg_write(SMSTPCR1, 0xFFFFFFFFU); cpg_write(SMSTPCR2, 0x000E2FDCU); cpg_write(SMSTPCR3, 0xFFFFFBDFU); cpg_write(SMSTPCR4, 0x80000004U); cpg_write(SMSTPCR5, 0xC3FFFFFFU); cpg_write(SMSTPCR6, 0xFFFFFFFFU); cpg_write(SMSTPCR7, 0xFFFFFFFFU); cpg_write(SMSTPCR8, 0x00F1FFF7U); cpg_write(SMSTPCR9, 0xFFFFFFDFU); cpg_write(SMSTPCR10, 0xFFFFFFE8U); cpg_write(SMSTPCR11, 0x000000B7U); } #endif #if (RCAR_LSI == RCAR_AUTO) || (RCAR_LSI == RCAR_D3) static void bl2_realtime_cpg_init_d3(void) { /* Realtime Module Stop Control Registers */ cpg_write(RMSTPCR0, 0x00010000U); cpg_write(RMSTPCR1, 0xFFFFFFFFU); cpg_write(RMSTPCR2, 0x00060FDCU); cpg_write(RMSTPCR3, 0xFFFFFFDFU); cpg_write(RMSTPCR4, 0x80000184U); cpg_write(RMSTPCR5, 0x83FFFFFFU); cpg_write(RMSTPCR6, 0xFFFFFFFFU); cpg_write(RMSTPCR7, 0xFFFFFFFFU); cpg_write(RMSTPCR8, 0x00F1FFF7U); cpg_write(RMSTPCR9, 0xF3F5E016U); cpg_write(RMSTPCR10, 0xFFFEFFE0U); cpg_write(RMSTPCR11, 0x000000B7U); } static void bl2_system_cpg_init_d3(void) { /* System Module Stop Control Registers */ cpg_write(SMSTPCR0, 0x00010000U); cpg_write(SMSTPCR1, 0xFFFFFFFFU); cpg_write(SMSTPCR2, 0x00060FDCU); cpg_write(SMSTPCR3, 0xFFFFFBDFU); cpg_write(SMSTPCR4, 0x00000084U); cpg_write(SMSTPCR5, 0x83FFFFFFU); cpg_write(SMSTPCR6, 0xFFFFFFFFU); cpg_write(SMSTPCR7, 0xFFFFFFFFU); cpg_write(SMSTPCR8, 0x00F1FFF7U); cpg_write(SMSTPCR9, 0xF3F5E016U); cpg_write(SMSTPCR10, 0xFFFEFFE0U); cpg_write(SMSTPCR11, 0x000000B7U); } #endif void bl2_cpg_init(void) { uint32_t boot_cpu = mmio_read_32(RCAR_MODEMR) & MODEMR_BOOT_CPU_MASK; #if RCAR_LSI == RCAR_AUTO uint32_t product = mmio_read_32(RCAR_PRR) & PRR_PRODUCT_MASK; #endif bl2_secure_cpg_init(); if (boot_cpu == MODEMR_BOOT_CPU_CA57 || boot_cpu == MODEMR_BOOT_CPU_CA53) { #if RCAR_LSI == RCAR_AUTO switch (product) { case PRR_PRODUCT_H3: bl2_realtime_cpg_init_h3(); break; case PRR_PRODUCT_M3: bl2_realtime_cpg_init_m3(); break; case PRR_PRODUCT_M3N: bl2_realtime_cpg_init_m3n(); break; case PRR_PRODUCT_V3M: bl2_realtime_cpg_init_v3m(); break; case PRR_PRODUCT_E3: bl2_realtime_cpg_init_e3(); break; case PRR_PRODUCT_D3: bl2_realtime_cpg_init_d3(); break; default: panic(); break; } #elif (RCAR_LSI == RCAR_H3) || (RCAR_LSI == RCAR_H3N) bl2_realtime_cpg_init_h3(); #elif RCAR_LSI == RCAR_M3 bl2_realtime_cpg_init_m3(); #elif RCAR_LSI == RCAR_M3N bl2_realtime_cpg_init_m3n(); #elif RCAR_LSI == RCAR_V3M bl2_realtime_cpg_init_v3m(); #elif RCAR_LSI == RCAR_E3 bl2_realtime_cpg_init_e3(); #elif RCAR_LSI == RCAR_D3 bl2_realtime_cpg_init_d3(); #else #error "Don't have CPG initialize routine(unknown)." #endif } } void bl2_system_cpg_init(void) { #if RCAR_LSI == RCAR_AUTO uint32_t product = mmio_read_32(RCAR_PRR) & PRR_PRODUCT_MASK; switch (product) { case PRR_PRODUCT_H3: bl2_system_cpg_init_h3(); break; case PRR_PRODUCT_M3: bl2_system_cpg_init_m3(); break; case PRR_PRODUCT_M3N: bl2_system_cpg_init_m3n(); break; case PRR_PRODUCT_V3M: bl2_system_cpg_init_v3m(); break; case PRR_PRODUCT_E3: bl2_system_cpg_init_e3(); break; case PRR_PRODUCT_D3: bl2_system_cpg_init_d3(); break; default: panic(); break; } #elif (RCAR_LSI == RCAR_H3) || (RCAR_LSI == RCAR_H3N) bl2_system_cpg_init_h3(); #elif RCAR_LSI == RCAR_M3 bl2_system_cpg_init_m3(); #elif RCAR_LSI == RCAR_M3N bl2_system_cpg_init_m3n(); #elif RCAR_LSI == RCAR_V3M bl2_system_cpg_init_v3m(); #elif RCAR_LSI == RCAR_E3 bl2_system_cpg_init_e3(); #elif RCAR_LSI == RCAR_D3 bl2_system_cpg_init_d3(); #else #error "Don't have CPG initialize routine(unknown)." #endif } trusted-firmware-a-2.2/plat/renesas/rcar/bl2_interrupt_error.c000066400000000000000000000056531355360272700246210ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "rcar_def.h" #define SWDT_ERROR_ID (1024U) #define SWDT_ERROR_TYPE (16U) #define SWDT_CHAR_MAX (13U) extern void rcar_swdt_release(void); void bl2_interrupt_error_id(uint32_t int_id) { ERROR("\n"); if (int_id >= SWDT_ERROR_ID) { ERROR("Unhandled exception occurred.\n"); ERROR(" Exception type = FIQ_SP_EL0\n"); panic(); } /* Clear the interrupt request */ gicv2_end_of_interrupt((uint32_t) int_id); rcar_swdt_release(); ERROR("Unhandled exception occurred.\n"); ERROR(" Exception type = FIQ_SP_EL0\n"); ERROR(" SPSR_EL3 = 0x%x\n", (uint32_t) read_spsr_el3()); ERROR(" ELR_EL3 = 0x%x\n", (uint32_t) read_elr_el3()); ERROR(" ESR_EL3 = 0x%x\n", (uint32_t) read_esr_el3()); ERROR(" FAR_EL3 = 0x%x\n", (uint32_t) read_far_el3()); ERROR("\n"); panic(); } void bl2_interrupt_error_type(uint32_t ex_type) { const uint8_t interrupt_ex[SWDT_ERROR_TYPE][SWDT_CHAR_MAX] = { "SYNC SP EL0", "IRQ SP EL0", "FIQ SP EL0", "SERR SP EL0", "SYNC SP ELx", "IRQ SP ELx", "FIQ SP ELx", "SERR SP ELx", "SYNC AARCH64", "IRQ AARCH64", "FIQ AARCH64", "SERR AARCH64", "SYNC AARCH32", "IRQ AARCH32", "FIQ AARCH32", "SERR AARCH32" }; char msg[128]; /* Clear the interrupt request */ if (ex_type >= SWDT_ERROR_TYPE) { ERROR("\n"); ERROR("Unhandled exception occurred.\n"); ERROR(" Exception type = Unknown (%d)\n", ex_type); goto loop; } rcar_swdt_release(); ERROR("\n"); ERROR("Unhandled exception occurred.\n"); snprintf(msg, sizeof(msg), " Exception type = %s\n", &interrupt_ex[ex_type][0]); ERROR("%s", msg); switch (ex_type) { case SYNC_EXCEPTION_SP_EL0: ERROR(" SPSR_EL3 = 0x%x\n", (uint32_t) read_spsr_el3()); ERROR(" ELR_EL3 = 0x%x\n", (uint32_t) read_elr_el3()); ERROR(" ESR_EL3 = 0x%x\n", (uint32_t) read_esr_el3()); ERROR(" FAR_EL3 = 0x%x\n", (uint32_t) read_far_el3()); break; case IRQ_SP_EL0: ERROR(" SPSR_EL3 = 0x%x\n", (uint32_t) read_spsr_el3()); ERROR(" ELR_EL3 = 0x%x\n", (uint32_t) read_elr_el3()); ERROR(" IAR_EL3 = 0x%x\n", gicv2_acknowledge_interrupt()); break; case FIQ_SP_EL0: ERROR(" SPSR_EL3 = 0x%x\n", (uint32_t) read_spsr_el3()); ERROR(" ELR_EL3 = 0x%x\n", (uint32_t) read_elr_el3()); ERROR(" IAR_EL3 = 0x%x\n", gicv2_acknowledge_interrupt()); break; case SERROR_SP_EL0: ERROR(" SPSR_EL3 = 0x%x\n", (uint32_t) read_spsr_el3()); ERROR(" ELR_EL3 = 0x%x\n", (uint32_t) read_elr_el3()); ERROR(" ESR_EL3 = 0x%x\n", (uint32_t) read_esr_el3()); ERROR(" FAR_EL3 = 0x%x\n", (uint32_t) read_far_el3()); break; default: break; } loop: ERROR("\n"); panic(); } trusted-firmware-a-2.2/plat/renesas/rcar/bl2_plat_mem_params_desc.c000066400000000000000000000042751355360272700255120ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #if (RCAR_BL33_EXECUTION_EL != 0) && (RCAR_BL33_EXECUTION_EL != 1) #error #endif #if (RCAR_BL33_EXECUTION_EL == 0) #define BL33_MODE MODE_EL1 #else #define BL33_MODE MODE_EL2 #endif extern uint64_t fdt_blob[PAGE_SIZE_4KB / sizeof(uint64_t)]; static bl_mem_params_node_t bl2_mem_params_descs[] = { { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), .ep_info.pc = BL31_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP), .image_info.image_max_size = BL31_LIMIT - BL31_BASE, .image_info.image_base = BL31_BASE, # ifdef BL32_BASE .next_handoff_image_id = BL32_IMAGE_ID, # else .next_handoff_image_id = BL33_IMAGE_ID, # endif }, # ifdef BL32_BASE { .image_id = BL32_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE), .ep_info.pc = BL32_BASE, .ep_info.spsr = 0, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_max_size = BL32_LIMIT - BL32_BASE, .image_info.image_base = BL32_BASE, .next_handoff_image_id = BL33_IMAGE_ID, }, #endif { .image_id = BL33_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), .ep_info.spsr = SPSR_64(BL33_MODE, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), .ep_info.pc = BL33_BASE, #ifdef RCAR_BL33_ARG0 .ep_info.args.arg0 = RCAR_BL33_ARG0, #endif .ep_info.args.arg1 = (uintptr_t)fdt_blob, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_max_size = (uint32_t) (DRAM_LIMIT - BL33_BASE), .image_info.image_base = BL33_BASE, .next_handoff_image_id = INVALID_IMAGE_ID, } }; REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) trusted-firmware-a-2.2/plat/renesas/rcar/bl2_plat_setup.c000066400000000000000000000630721355360272700235330ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include "avs_driver.h" #include "boot_init_dram.h" #include "cpg_registers.h" #include "board.h" #include "emmc_def.h" #include "emmc_hal.h" #include "emmc_std.h" #if PMIC_ROHM_BD9571 && RCAR_SYSTEM_RESET_KEEPON_DDR #include "iic_dvfs.h" #endif #include "io_common.h" #include "qos_init.h" #include "rcar_def.h" #include "rcar_private.h" #include "rcar_version.h" #include "rom_api.h" IMPORT_SYM(unsigned long, __RO_START__, BL2_RO_BASE) IMPORT_SYM(unsigned long, __RO_END__, BL2_RO_LIMIT) #if USE_COHERENT_MEM IMPORT_SYM(unsigned long, __COHERENT_RAM_START__, BL2_COHERENT_RAM_BASE) IMPORT_SYM(unsigned long, __COHERENT_RAM_END__, BL2_COHERENT_RAM_LIMIT) #endif extern void plat_rcar_gic_driver_init(void); extern void plat_rcar_gic_init(void); extern void bl2_enter_bl31(const struct entry_point_info *bl_ep_info); extern void bl2_system_cpg_init(void); extern void bl2_secure_setting(void); extern void bl2_cpg_init(void); extern void rcar_io_emmc_setup(void); extern void rcar_io_setup(void); extern void rcar_swdt_release(void); extern void rcar_swdt_init(void); extern void rcar_rpc_init(void); extern void rcar_pfc_init(void); extern void rcar_dma_init(void); static void bl2_init_generic_timer(void); /* R-Car Gen3 product check */ #if (RCAR_LSI == RCAR_H3) || (RCAR_LSI == RCAR_H3N) #define TARGET_PRODUCT PRR_PRODUCT_H3 #define TARGET_NAME "R-Car H3" #elif RCAR_LSI == RCAR_M3 #define TARGET_PRODUCT PRR_PRODUCT_M3 #define TARGET_NAME "R-Car M3" #elif RCAR_LSI == RCAR_M3N #define TARGET_PRODUCT PRR_PRODUCT_M3N #define TARGET_NAME "R-Car M3N" #elif RCAR_LSI == RCAR_V3M #define TARGET_PRODUCT PRR_PRODUCT_V3M #define TARGET_NAME "R-Car V3M" #elif RCAR_LSI == RCAR_E3 #define TARGET_PRODUCT PRR_PRODUCT_E3 #define TARGET_NAME "R-Car E3" #elif RCAR_LSI == RCAR_D3 #define TARGET_PRODUCT PRR_PRODUCT_D3 #define TARGET_NAME "R-Car D3" #elif RCAR_LSI == RCAR_AUTO #define TARGET_NAME "R-Car H3/M3/M3N/V3M" #endif #if (RCAR_LSI == RCAR_E3) #define GPIO_INDT (GPIO_INDT6) #define GPIO_BKUP_TRG_SHIFT ((uint32_t)1U<<13U) #else #define GPIO_INDT (GPIO_INDT1) #define GPIO_BKUP_TRG_SHIFT ((uint32_t)1U<<8U) #endif CASSERT((PARAMS_BASE + sizeof(bl2_to_bl31_params_mem_t) + 0x100) < (RCAR_SHARED_MEM_BASE + RCAR_SHARED_MEM_SIZE), assert_bl31_params_do_not_fit_in_shared_memory); static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE); /* FDT with DRAM configuration */ uint64_t fdt_blob[PAGE_SIZE_4KB / sizeof(uint64_t)]; static void *fdt = (void *)fdt_blob; static void unsigned_num_print(unsigned long long int unum, unsigned int radix, char *string) { /* Just need enough space to store 64 bit decimal integer */ char num_buf[20]; int i = 0; unsigned int rem; do { rem = unum % radix; if (rem < 0xa) num_buf[i] = '0' + rem; else num_buf[i] = 'a' + (rem - 0xa); i++; unum /= radix; } while (unum > 0U); while (--i >= 0) *string++ = num_buf[i]; } #if (RCAR_LOSSY_ENABLE == 1) typedef struct bl2_lossy_info { uint32_t magic; uint32_t a0; uint32_t b0; } bl2_lossy_info_t; static void bl2_lossy_gen_fdt(uint32_t no, uint64_t start_addr, uint64_t end_addr, uint32_t format, uint32_t enable, int fcnlnode) { const uint64_t fcnlsize = cpu_to_fdt64(end_addr - start_addr); char nodename[40] = { 0 }; int ret, node; /* Ignore undefined addresses */ if (start_addr == 0 && end_addr == 0) return; snprintf(nodename, sizeof(nodename), "lossy-decompression@"); unsigned_num_print(start_addr, 16, nodename + strlen(nodename)); node = ret = fdt_add_subnode(fdt, fcnlnode, nodename); if (ret < 0) { NOTICE("BL2: Cannot create FCNL node (ret=%i)\n", ret); panic(); } ret = fdt_setprop_string(fdt, node, "compatible", "renesas,lossy-decompression"); if (ret < 0) { NOTICE("BL2: Cannot add FCNL compat string (ret=%i)\n", ret); panic(); } ret = fdt_appendprop_string(fdt, node, "compatible", "shared-dma-pool"); if (ret < 0) { NOTICE("BL2: Cannot append FCNL compat string (ret=%i)\n", ret); panic(); } ret = fdt_setprop_u64(fdt, node, "reg", start_addr); if (ret < 0) { NOTICE("BL2: Cannot add FCNL reg prop (ret=%i)\n", ret); panic(); } ret = fdt_appendprop(fdt, node, "reg", &fcnlsize, sizeof(fcnlsize)); if (ret < 0) { NOTICE("BL2: Cannot append FCNL reg size prop (ret=%i)\n", ret); panic(); } ret = fdt_setprop(fdt, node, "no-map", NULL, 0); if (ret < 0) { NOTICE("BL2: Cannot add FCNL no-map prop (ret=%i)\n", ret); panic(); } ret = fdt_setprop_u32(fdt, node, "renesas,formats", format); if (ret < 0) { NOTICE("BL2: Cannot add FCNL formats prop (ret=%i)\n", ret); panic(); } } static void bl2_lossy_setting(uint32_t no, uint64_t start_addr, uint64_t end_addr, uint32_t format, uint32_t enable, int fcnlnode) { bl2_lossy_info_t info; uint32_t reg; bl2_lossy_gen_fdt(no, start_addr, end_addr, format, enable, fcnlnode); reg = format | (start_addr >> 20); mmio_write_32(AXI_DCMPAREACRA0 + 0x8 * no, reg); mmio_write_32(AXI_DCMPAREACRB0 + 0x8 * no, end_addr >> 20); mmio_write_32(AXI_DCMPAREACRA0 + 0x8 * no, reg | enable); info.magic = 0x12345678U; info.a0 = mmio_read_32(AXI_DCMPAREACRA0 + 0x8 * no); info.b0 = mmio_read_32(AXI_DCMPAREACRB0 + 0x8 * no); mmio_write_32(LOSSY_PARAMS_BASE + sizeof(info) * no, info.magic); mmio_write_32(LOSSY_PARAMS_BASE + sizeof(info) * no + 0x4, info.a0); mmio_write_32(LOSSY_PARAMS_BASE + sizeof(info) * no + 0x8, info.b0); NOTICE(" Entry %d: DCMPAREACRAx:0x%x DCMPAREACRBx:0x%x\n", no, mmio_read_32(AXI_DCMPAREACRA0 + 0x8 * no), mmio_read_32(AXI_DCMPAREACRB0 + 0x8 * no)); } #endif void bl2_plat_flush_bl31_params(void) { uint32_t product_cut, product, cut; uint32_t boot_dev, boot_cpu; uint32_t lcs, reg, val; reg = mmio_read_32(RCAR_MODEMR); boot_dev = reg & MODEMR_BOOT_DEV_MASK; if (boot_dev == MODEMR_BOOT_DEV_EMMC_25X1 || boot_dev == MODEMR_BOOT_DEV_EMMC_50X8) emmc_terminate(); if ((reg & MODEMR_BOOT_CPU_MASK) != MODEMR_BOOT_CPU_CR7) bl2_secure_setting(); reg = mmio_read_32(RCAR_PRR); product_cut = reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK); product = reg & PRR_PRODUCT_MASK; cut = reg & PRR_CUT_MASK; if (product == PRR_PRODUCT_M3 && PRR_PRODUCT_30 > cut) goto tlb; if (product == PRR_PRODUCT_H3 && PRR_PRODUCT_20 > cut) goto tlb; if (product == PRR_PRODUCT_D3) goto tlb; /* Disable MFIS write protection */ mmio_write_32(MFISWPCNTR, MFISWPCNTR_PASSWORD | 1); tlb: reg = mmio_read_32(RCAR_MODEMR); boot_cpu = reg & MODEMR_BOOT_CPU_MASK; if (boot_cpu != MODEMR_BOOT_CPU_CA57 && boot_cpu != MODEMR_BOOT_CPU_CA53) goto mmu; if (product_cut == PRR_PRODUCT_H3_CUT20) { mmio_write_32(IPMMUVI0_IMSCTLR, IMSCTLR_DISCACHE); mmio_write_32(IPMMUVI1_IMSCTLR, IMSCTLR_DISCACHE); mmio_write_32(IPMMUPV0_IMSCTLR, IMSCTLR_DISCACHE); mmio_write_32(IPMMUPV1_IMSCTLR, IMSCTLR_DISCACHE); mmio_write_32(IPMMUPV2_IMSCTLR, IMSCTLR_DISCACHE); mmio_write_32(IPMMUPV3_IMSCTLR, IMSCTLR_DISCACHE); } else if (product_cut == (PRR_PRODUCT_M3N | PRR_PRODUCT_10) || product_cut == (PRR_PRODUCT_M3N | PRR_PRODUCT_11)) { mmio_write_32(IPMMUVI0_IMSCTLR, IMSCTLR_DISCACHE); mmio_write_32(IPMMUPV0_IMSCTLR, IMSCTLR_DISCACHE); } else if ((product_cut == (PRR_PRODUCT_E3 | PRR_PRODUCT_10)) || (product_cut == (PRR_PRODUCT_E3 | PRR_PRODUCT_11))) { mmio_write_32(IPMMUVI0_IMSCTLR, IMSCTLR_DISCACHE); mmio_write_32(IPMMUVP0_IMSCTLR, IMSCTLR_DISCACHE); mmio_write_32(IPMMUPV0_IMSCTLR, IMSCTLR_DISCACHE); } if (product_cut == (PRR_PRODUCT_H3_CUT20) || product_cut == (PRR_PRODUCT_M3N | PRR_PRODUCT_10) || product_cut == (PRR_PRODUCT_M3N | PRR_PRODUCT_11) || product_cut == (PRR_PRODUCT_E3 | PRR_PRODUCT_10)) { mmio_write_32(IPMMUHC_IMSCTLR, IMSCTLR_DISCACHE); mmio_write_32(IPMMURT_IMSCTLR, IMSCTLR_DISCACHE); mmio_write_32(IPMMUMP_IMSCTLR, IMSCTLR_DISCACHE); mmio_write_32(IPMMUDS0_IMSCTLR, IMSCTLR_DISCACHE); mmio_write_32(IPMMUDS1_IMSCTLR, IMSCTLR_DISCACHE); } mmu: mmio_write_32(IPMMUMM_IMSCTLR, IPMMUMM_IMSCTLR_ENABLE); mmio_write_32(IPMMUMM_IMAUXCTLR, IPMMUMM_IMAUXCTLR_NMERGE40_BIT); val = rcar_rom_get_lcs(&lcs); if (val) { ERROR("BL2: Failed to get the LCS. (%d)\n", val); panic(); } if (lcs == LCS_SE) mmio_clrbits_32(P_ARMREG_SEC_CTRL, P_ARMREG_SEC_CTRL_PROT); rcar_swdt_release(); bl2_system_cpg_init(); #if RCAR_BL2_DCACHE == 1 /* Disable data cache (clean and invalidate) */ disable_mmu_el3(); #endif } static uint32_t is_ddr_backup_mode(void) { #if RCAR_SYSTEM_SUSPEND static uint32_t reason = RCAR_COLD_BOOT; static uint32_t once; #if PMIC_ROHM_BD9571 && RCAR_SYSTEM_RESET_KEEPON_DDR uint8_t data; #endif if (once) return reason; once = 1; if ((mmio_read_32(GPIO_INDT) & GPIO_BKUP_TRG_SHIFT) == 0) return reason; #if PMIC_ROHM_BD9571 && RCAR_SYSTEM_RESET_KEEPON_DDR if (rcar_iic_dvfs_receive(PMIC, REG_KEEP10, &data)) { ERROR("BL2: REG Keep10 READ ERROR.\n"); panic(); } if (KEEP10_MAGIC != data) reason = RCAR_WARM_BOOT; #else reason = RCAR_WARM_BOOT; #endif return reason; #else return RCAR_COLD_BOOT; #endif } int bl2_plat_handle_pre_image_load(unsigned int image_id) { u_register_t *boot_kind = (void *) BOOT_KIND_BASE; bl_mem_params_node_t *bl_mem_params; if (image_id != BL31_IMAGE_ID) return 0; bl_mem_params = get_bl_mem_params_node(image_id); if (is_ddr_backup_mode() == RCAR_COLD_BOOT) goto cold_boot; *boot_kind = RCAR_WARM_BOOT; flush_dcache_range(BOOT_KIND_BASE, sizeof(*boot_kind)); console_flush(); bl2_plat_flush_bl31_params(); /* will not return */ bl2_enter_bl31(&bl_mem_params->ep_info); cold_boot: *boot_kind = RCAR_COLD_BOOT; flush_dcache_range(BOOT_KIND_BASE, sizeof(*boot_kind)); return 0; } int bl2_plat_handle_post_image_load(unsigned int image_id) { static bl2_to_bl31_params_mem_t *params; bl_mem_params_node_t *bl_mem_params; if (!params) { params = (bl2_to_bl31_params_mem_t *) PARAMS_BASE; memset((void *)PARAMS_BASE, 0, sizeof(*params)); } bl_mem_params = get_bl_mem_params_node(image_id); switch (image_id) { case BL31_IMAGE_ID: break; case BL32_IMAGE_ID: memcpy(¶ms->bl32_ep_info, &bl_mem_params->ep_info, sizeof(entry_point_info_t)); break; case BL33_IMAGE_ID: memcpy(¶ms->bl33_ep_info, &bl_mem_params->ep_info, sizeof(entry_point_info_t)); break; } return 0; } struct meminfo *bl2_plat_sec_mem_layout(void) { return &bl2_tzram_layout; } static void bl2_populate_compatible_string(void *fdt) { uint32_t board_type; uint32_t board_rev; uint32_t reg; int ret; /* Populate compatible string */ rcar_get_board_type(&board_type, &board_rev); switch (board_type) { case BOARD_SALVATOR_X: ret = fdt_setprop_string(fdt, 0, "compatible", "renesas,salvator-x"); break; case BOARD_SALVATOR_XS: ret = fdt_setprop_string(fdt, 0, "compatible", "renesas,salvator-xs"); break; case BOARD_STARTER_KIT: ret = fdt_setprop_string(fdt, 0, "compatible", "renesas,m3ulcb"); break; case BOARD_STARTER_KIT_PRE: ret = fdt_setprop_string(fdt, 0, "compatible", "renesas,h3ulcb"); break; case BOARD_EAGLE: ret = fdt_setprop_string(fdt, 0, "compatible", "renesas,eagle"); break; case BOARD_EBISU: case BOARD_EBISU_4D: ret = fdt_setprop_string(fdt, 0, "compatible", "renesas,ebisu"); break; case BOARD_DRAAK: ret = fdt_setprop_string(fdt, 0, "compatible", "renesas,draak"); break; default: NOTICE("BL2: Cannot set compatible string, board unsupported\n"); panic(); } if (ret < 0) { NOTICE("BL2: Cannot set compatible string (ret=%i)\n", ret); panic(); } reg = mmio_read_32(RCAR_PRR); switch (reg & PRR_PRODUCT_MASK) { case PRR_PRODUCT_H3: ret = fdt_appendprop_string(fdt, 0, "compatible", "renesas,r8a7795"); break; case PRR_PRODUCT_M3: ret = fdt_appendprop_string(fdt, 0, "compatible", "renesas,r8a7796"); break; case PRR_PRODUCT_M3N: ret = fdt_appendprop_string(fdt, 0, "compatible", "renesas,r8a77965"); break; case PRR_PRODUCT_V3M: ret = fdt_appendprop_string(fdt, 0, "compatible", "renesas,r8a77970"); break; case PRR_PRODUCT_E3: ret = fdt_appendprop_string(fdt, 0, "compatible", "renesas,r8a77990"); break; case PRR_PRODUCT_D3: ret = fdt_appendprop_string(fdt, 0, "compatible", "renesas,r8a77995"); break; default: NOTICE("BL2: Cannot set compatible string, SoC unsupported\n"); panic(); } if (ret < 0) { NOTICE("BL2: Cannot set compatible string (ret=%i)\n", ret); panic(); } } static void bl2_advertise_dram_entries(uint64_t dram_config[8]) { char nodename[32] = { 0 }; uint64_t start, size; uint64_t fdtsize; int ret, node, chan; for (chan = 0; chan < 4; chan++) { start = dram_config[2 * chan]; size = dram_config[2 * chan + 1]; if (!size) continue; NOTICE("BL2: CH%d: %llx - %llx, %lld %siB\n", chan, start, start + size - 1, (size >> 30) ? : size >> 20, (size >> 30) ? "G" : "M"); } /* * We add the DT nodes in reverse order here. The fdt_add_subnode() * adds the DT node before the first existing DT node, so we have * to add them in reverse order to get nodes sorted by address in * the resulting DT. */ for (chan = 3; chan >= 0; chan--) { start = dram_config[2 * chan]; size = dram_config[2 * chan + 1]; if (!size) continue; /* * Channel 0 is mapped in 32bit space and the first * 128 MiB are reserved */ if (chan == 0) { start = 0x48000000; size -= 0x8000000; } fdtsize = cpu_to_fdt64(size); snprintf(nodename, sizeof(nodename), "memory@"); unsigned_num_print(start, 16, nodename + strlen(nodename)); node = ret = fdt_add_subnode(fdt, 0, nodename); if (ret < 0) goto err; ret = fdt_setprop_string(fdt, node, "device_type", "memory"); if (ret < 0) goto err; ret = fdt_setprop_u64(fdt, node, "reg", start); if (ret < 0) goto err; ret = fdt_appendprop(fdt, node, "reg", &fdtsize, sizeof(fdtsize)); if (ret < 0) goto err; } return; err: NOTICE("BL2: Cannot add memory node to FDT (ret=%i)\n", ret); panic(); } static void bl2_advertise_dram_size(uint32_t product) { uint64_t dram_config[8] = { [0] = 0x400000000ULL, [2] = 0x500000000ULL, [4] = 0x600000000ULL, [6] = 0x700000000ULL, }; switch (product) { case PRR_PRODUCT_H3: #if (RCAR_DRAM_LPDDR4_MEMCONF == 0) /* 4GB(1GBx4) */ dram_config[1] = 0x40000000ULL; dram_config[3] = 0x40000000ULL; dram_config[5] = 0x40000000ULL; dram_config[7] = 0x40000000ULL; #elif (RCAR_DRAM_LPDDR4_MEMCONF == 1) && \ (RCAR_DRAM_CHANNEL == 5) && \ (RCAR_DRAM_SPLIT == 2) /* 4GB(2GBx2 2ch split) */ dram_config[1] = 0x80000000ULL; dram_config[3] = 0x80000000ULL; #elif (RCAR_DRAM_LPDDR4_MEMCONF == 1) && (RCAR_DRAM_CHANNEL == 15) /* 8GB(2GBx4: default) */ dram_config[1] = 0x80000000ULL; dram_config[3] = 0x80000000ULL; dram_config[5] = 0x80000000ULL; dram_config[7] = 0x80000000ULL; #endif /* RCAR_DRAM_LPDDR4_MEMCONF == 0 */ break; case PRR_PRODUCT_M3: #if (RCAR_GEN3_ULCB == 1) /* 2GB(1GBx2 2ch split) */ dram_config[1] = 0x40000000ULL; dram_config[5] = 0x40000000ULL; #else /* 4GB(2GBx2 2ch split) */ dram_config[1] = 0x80000000ULL; dram_config[5] = 0x80000000ULL; #endif break; case PRR_PRODUCT_M3N: /* 2GB(1GBx2) */ dram_config[1] = 0x80000000ULL; break; case PRR_PRODUCT_V3M: /* 1GB(512MBx2) */ dram_config[1] = 0x40000000ULL; break; case PRR_PRODUCT_E3: #if (RCAR_DRAM_DDR3L_MEMCONF == 0) /* 1GB(512MBx2) */ dram_config[1] = 0x40000000ULL; #elif (RCAR_DRAM_DDR3L_MEMCONF == 1) /* 2GB(512MBx4) */ dram_config[1] = 0x80000000ULL; #elif (RCAR_DRAM_DDR3L_MEMCONF == 2) /* 4GB(1GBx4) */ dram_config[1] = 0x100000000ULL; #endif /* RCAR_DRAM_DDR3L_MEMCONF == 0 */ break; case PRR_PRODUCT_D3: /* 512MB */ dram_config[1] = 0x20000000ULL; break; } bl2_advertise_dram_entries(dram_config); } void bl2_el3_early_platform_setup(u_register_t arg1, u_register_t arg2, u_register_t arg3, u_register_t arg4) { uint32_t reg, midr, lcs, boot_dev, boot_cpu, sscg, type, rev; uint32_t product, product_cut, major, minor; int32_t ret; const char *str; const char *unknown = "unknown"; const char *cpu_ca57 = "CA57"; const char *cpu_ca53 = "CA53"; const char *product_m3n = "M3N"; const char *product_h3 = "H3"; const char *product_m3 = "M3"; const char *product_e3 = "E3"; const char *product_d3 = "D3"; const char *product_v3m = "V3M"; const char *lcs_secure = "SE"; const char *lcs_cm = "CM"; const char *lcs_dm = "DM"; const char *lcs_sd = "SD"; const char *lcs_fa = "FA"; const char *sscg_off = "PLL1 nonSSCG Clock select"; const char *sscg_on = "PLL1 SSCG Clock select"; const char *boot_hyper80 = "HyperFlash(80MHz)"; const char *boot_qspi40 = "QSPI Flash(40MHz)"; const char *boot_qspi80 = "QSPI Flash(80MHz)"; const char *boot_emmc25x1 = "eMMC(25MHz x1)"; const char *boot_emmc50x8 = "eMMC(50MHz x8)"; #if (RCAR_LSI == RCAR_E3) || (RCAR_LSI == RCAR_D3) const char *boot_hyper160 = "HyperFlash(150MHz)"; #else const char *boot_hyper160 = "HyperFlash(160MHz)"; #endif #if (RCAR_LOSSY_ENABLE == 1) int fcnlnode; #endif bl2_init_generic_timer(); reg = mmio_read_32(RCAR_MODEMR); boot_dev = reg & MODEMR_BOOT_DEV_MASK; boot_cpu = reg & MODEMR_BOOT_CPU_MASK; bl2_cpg_init(); if (boot_cpu == MODEMR_BOOT_CPU_CA57 || boot_cpu == MODEMR_BOOT_CPU_CA53) { rcar_pfc_init(); rcar_console_boot_init(); } plat_rcar_gic_driver_init(); plat_rcar_gic_init(); rcar_swdt_init(); /* FIQ interrupts are taken to EL3 */ write_scr_el3(read_scr_el3() | SCR_FIQ_BIT); write_daifclr(DAIF_FIQ_BIT); reg = read_midr(); midr = reg & (MIDR_PN_MASK << MIDR_PN_SHIFT); switch (midr) { case MIDR_CA57: str = cpu_ca57; break; case MIDR_CA53: str = cpu_ca53; break; default: str = unknown; break; } NOTICE("BL2: R-Car Gen3 Initial Program Loader(%s) Rev.%s\n", str, version_of_renesas); reg = mmio_read_32(RCAR_PRR); product_cut = reg & (PRR_PRODUCT_MASK | PRR_CUT_MASK); product = reg & PRR_PRODUCT_MASK; switch (product) { case PRR_PRODUCT_H3: str = product_h3; break; case PRR_PRODUCT_M3: str = product_m3; break; case PRR_PRODUCT_M3N: str = product_m3n; break; case PRR_PRODUCT_V3M: str = product_v3m; break; case PRR_PRODUCT_E3: str = product_e3; break; case PRR_PRODUCT_D3: str = product_d3; break; default: str = unknown; break; } if ((PRR_PRODUCT_M3 == product) && (PRR_PRODUCT_20 == (reg & RCAR_MAJOR_MASK))) { if (RCAR_M3_CUT_VER11 == (reg & PRR_CUT_MASK)) { /* M3 Ver.1.1 or Ver.1.2 */ NOTICE("BL2: PRR is R-Car %s Ver.1.1 / Ver.1.2\n", str); } else { NOTICE("BL2: PRR is R-Car %s Ver.1.%d\n", str, (reg & RCAR_MINOR_MASK) + RCAR_M3_MINOR_OFFSET); } } else { major = (reg & RCAR_MAJOR_MASK) >> RCAR_MAJOR_SHIFT; major = major + RCAR_MAJOR_OFFSET; minor = reg & RCAR_MINOR_MASK; NOTICE("BL2: PRR is R-Car %s Ver.%d.%d\n", str, major, minor); } if (product == PRR_PRODUCT_E3) { reg = mmio_read_32(RCAR_MODEMR); sscg = reg & RCAR_SSCG_MASK; str = sscg == RCAR_SSCG_ENABLE ? sscg_on : sscg_off; NOTICE("BL2: %s\n", str); } rcar_get_board_type(&type, &rev); switch (type) { case BOARD_SALVATOR_X: case BOARD_KRIEK: case BOARD_STARTER_KIT: case BOARD_SALVATOR_XS: case BOARD_EBISU: case BOARD_STARTER_KIT_PRE: case BOARD_EBISU_4D: case BOARD_DRAAK: case BOARD_EAGLE: break; default: type = BOARD_UNKNOWN; break; } if (type == BOARD_UNKNOWN || rev == BOARD_REV_UNKNOWN) NOTICE("BL2: Board is %s Rev.---\n", GET_BOARD_NAME(type)); else { NOTICE("BL2: Board is %s Rev.%d.%d\n", GET_BOARD_NAME(type), GET_BOARD_MAJOR(rev), GET_BOARD_MINOR(rev)); } #if RCAR_LSI != RCAR_AUTO if (product != TARGET_PRODUCT) { ERROR("BL2: IPL was been built for the %s.\n", TARGET_NAME); ERROR("BL2: Please write the correct IPL to flash memory.\n"); panic(); } #endif rcar_avs_init(); rcar_avs_setting(); switch (boot_dev) { case MODEMR_BOOT_DEV_HYPERFLASH160: str = boot_hyper160; break; case MODEMR_BOOT_DEV_HYPERFLASH80: str = boot_hyper80; break; case MODEMR_BOOT_DEV_QSPI_FLASH40: str = boot_qspi40; break; case MODEMR_BOOT_DEV_QSPI_FLASH80: str = boot_qspi80; break; case MODEMR_BOOT_DEV_EMMC_25X1: #if RCAR_LSI == RCAR_D3 ERROR("BL2: Failed to Initialize. eMMC is not supported.\n"); panic(); #endif str = boot_emmc25x1; break; case MODEMR_BOOT_DEV_EMMC_50X8: #if RCAR_LSI == RCAR_D3 ERROR("BL2: Failed to Initialize. eMMC is not supported.\n"); panic(); #endif str = boot_emmc50x8; break; default: str = unknown; break; } NOTICE("BL2: Boot device is %s\n", str); rcar_avs_setting(); reg = rcar_rom_get_lcs(&lcs); if (reg) { str = unknown; goto lcm_state; } switch (lcs) { case LCS_CM: str = lcs_cm; break; case LCS_DM: str = lcs_dm; break; case LCS_SD: str = lcs_sd; break; case LCS_SE: str = lcs_secure; break; case LCS_FA: str = lcs_fa; break; default: str = unknown; break; } lcm_state: NOTICE("BL2: LCM state is %s\n", str); rcar_avs_end(); is_ddr_backup_mode(); bl2_tzram_layout.total_base = BL31_BASE; bl2_tzram_layout.total_size = BL31_LIMIT - BL31_BASE; if (boot_cpu == MODEMR_BOOT_CPU_CA57 || boot_cpu == MODEMR_BOOT_CPU_CA53) { ret = rcar_dram_init(); if (ret) { NOTICE("BL2: Failed to DRAM initialize (%d).\n", ret); panic(); } rcar_qos_init(); } /* Set up FDT */ ret = fdt_create_empty_tree(fdt, sizeof(fdt_blob)); if (ret) { NOTICE("BL2: Cannot allocate FDT for U-Boot (ret=%i)\n", ret); panic(); } /* Add platform compatible string */ bl2_populate_compatible_string(fdt); /* Print DRAM layout */ bl2_advertise_dram_size(product); if (boot_dev == MODEMR_BOOT_DEV_EMMC_25X1 || boot_dev == MODEMR_BOOT_DEV_EMMC_50X8) { if (rcar_emmc_init() != EMMC_SUCCESS) { NOTICE("BL2: Failed to eMMC driver initialize.\n"); panic(); } rcar_emmc_memcard_power(EMMC_POWER_ON); if (rcar_emmc_mount() != EMMC_SUCCESS) { NOTICE("BL2: Failed to eMMC mount operation.\n"); panic(); } } else { rcar_rpc_init(); rcar_dma_init(); } reg = mmio_read_32(RST_WDTRSTCR); reg &= ~WDTRSTCR_RWDT_RSTMSK; reg |= WDTRSTCR_PASSWORD; mmio_write_32(RST_WDTRSTCR, reg); mmio_write_32(CPG_CPGWPR, CPGWPR_PASSWORD); mmio_write_32(CPG_CPGWPCR, CPGWPCR_PASSWORD); reg = mmio_read_32(RCAR_PRR); if ((reg & RCAR_CPU_MASK_CA57) == RCAR_CPU_HAVE_CA57) mmio_write_32(CPG_CA57DBGRCR, DBGCPUPREN | mmio_read_32(CPG_CA57DBGRCR)); if ((reg & RCAR_CPU_MASK_CA53) == RCAR_CPU_HAVE_CA53) mmio_write_32(CPG_CA53DBGRCR, DBGCPUPREN | mmio_read_32(CPG_CA53DBGRCR)); if (product_cut == PRR_PRODUCT_H3_CUT10) { reg = mmio_read_32(CPG_PLL2CR); reg &= ~((uint32_t) 1 << 5); mmio_write_32(CPG_PLL2CR, reg); reg = mmio_read_32(CPG_PLL4CR); reg &= ~((uint32_t) 1 << 5); mmio_write_32(CPG_PLL4CR, reg); reg = mmio_read_32(CPG_PLL0CR); reg &= ~((uint32_t) 1 << 12); mmio_write_32(CPG_PLL0CR, reg); } #if (RCAR_LOSSY_ENABLE == 1) NOTICE("BL2: Lossy Decomp areas\n"); fcnlnode = fdt_add_subnode(fdt, 0, "reserved-memory"); if (fcnlnode < 0) { NOTICE("BL2: Cannot create reserved mem node (ret=%i)\n", fcnlnode); panic(); } bl2_lossy_setting(0, LOSSY_ST_ADDR0, LOSSY_END_ADDR0, LOSSY_FMT0, LOSSY_ENA_DIS0, fcnlnode); bl2_lossy_setting(1, LOSSY_ST_ADDR1, LOSSY_END_ADDR1, LOSSY_FMT1, LOSSY_ENA_DIS1, fcnlnode); bl2_lossy_setting(2, LOSSY_ST_ADDR2, LOSSY_END_ADDR2, LOSSY_FMT2, LOSSY_ENA_DIS2, fcnlnode); #endif fdt_pack(fdt); NOTICE("BL2: FDT at %p\n", fdt); if (boot_dev == MODEMR_BOOT_DEV_EMMC_25X1 || boot_dev == MODEMR_BOOT_DEV_EMMC_50X8) rcar_io_emmc_setup(); else rcar_io_setup(); } void bl2_el3_plat_arch_setup(void) { #if RCAR_BL2_DCACHE == 1 NOTICE("BL2: D-Cache enable\n"); rcar_configure_mmu_el3(BL2_BASE, BL2_END - BL2_BASE, BL2_RO_BASE, BL2_RO_LIMIT #if USE_COHERENT_MEM , BL2_COHERENT_RAM_BASE, BL2_COHERENT_RAM_LIMIT #endif ); #endif } void bl2_platform_setup(void) { } static void bl2_init_generic_timer(void) { /* FIXME: V3M 16.666 MHz ? */ #if RCAR_LSI == RCAR_D3 uint32_t reg_cntfid = EXTAL_DRAAK; #elif RCAR_LSI == RCAR_E3 uint32_t reg_cntfid = EXTAL_EBISU; #else /* RCAR_LSI == RCAR_E3 */ uint32_t reg; uint32_t reg_cntfid; uint32_t modemr; uint32_t modemr_pll; uint32_t board_type; uint32_t board_rev; uint32_t pll_table[] = { EXTAL_MD14_MD13_TYPE_0, /* MD14/MD13 : 0b00 */ EXTAL_MD14_MD13_TYPE_1, /* MD14/MD13 : 0b01 */ EXTAL_MD14_MD13_TYPE_2, /* MD14/MD13 : 0b10 */ EXTAL_MD14_MD13_TYPE_3 /* MD14/MD13 : 0b11 */ }; modemr = mmio_read_32(RCAR_MODEMR); modemr_pll = (modemr & MODEMR_BOOT_PLL_MASK); /* Set frequency data in CNTFID0 */ reg_cntfid = pll_table[modemr_pll >> MODEMR_BOOT_PLL_SHIFT]; reg = mmio_read_32(RCAR_PRR) & (PRR_PRODUCT_MASK | PRR_CUT_MASK); switch (modemr_pll) { case MD14_MD13_TYPE_0: rcar_get_board_type(&board_type, &board_rev); if (BOARD_SALVATOR_XS == board_type) { reg_cntfid = EXTAL_SALVATOR_XS; } break; case MD14_MD13_TYPE_3: if (PRR_PRODUCT_H3_CUT10 == reg) { reg_cntfid = reg_cntfid >> 1U; } break; default: /* none */ break; } #endif /* RCAR_LSI == RCAR_E3 */ /* Update memory mapped and register based freqency */ write_cntfrq_el0((u_register_t )reg_cntfid); mmio_write_32(ARM_SYS_CNTCTL_BASE + (uintptr_t)CNTFID_OFF, reg_cntfid); /* Enable counter */ mmio_setbits_32(RCAR_CNTC_BASE + (uintptr_t)CNTCR_OFF, (uint32_t)CNTCR_EN); } trusted-firmware-a-2.2/plat/renesas/rcar/bl2_secure_setting.c000066400000000000000000000364441355360272700244010ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "axi_registers.h" #include "lifec_registers.h" #include "micro_delay.h" static void lifec_security_setting(void); static void axi_security_setting(void); static const struct { uint32_t reg; uint32_t val; } lifec[] = { /** LIFEC0 (SECURITY) settings */ /* Security attribute setting for master ports */ /* Bit 0: ARM realtime core (Cortex-R7) master port */ /* 0: Non-Secure */ { SEC_SRC, 0x0000001EU}, /** Security attribute setting for slave ports 0 to 15 */ /* {SEC_SEL0, 0xFFFFFFFFU}, */ /* {SEC_SEL1, 0xFFFFFFFFU}, */ /* {SEC_SEL2, 0xFFFFFFFFU}, */ /* Bit19: AXI-Bus (Main Memory domain AXI) slave ports */ /* 0: registers accessed from secure resource only */ /* Bit 9: DBSC4 register access slave ports. */ /* 0: registers accessed from secure resource only. */ #if (LIFEC_DBSC_PROTECT_ENABLE == 1) { SEC_SEL3, 0xFFF7FDFFU}, #else { SEC_SEL3, 0xFFFFFFFFU}, #endif /* {SEC_SEL4, 0xFFFFFFFFU}, */ /* Bit 6: Boot ROM slave ports. */ /* 0: registers accessed from secure resource only */ { SEC_SEL5, 0xFFFFFFBFU}, /* Bit13: SCEG PKA (secure APB) slave ports */ /* 0: registers accessed from secure resource only */ /* 1: Reserved[R-Car E3] */ /* Bit12: SCEG PKA (public APB) slave ports */ /* 0: registers accessed from secure resource only */ /* 1: Reserved[R-Car E3] */ /* Bit10: SCEG Secure Core slave ports */ /* 0: registers accessed from secure resource only */ #if (RCAR_LSI == RCAR_E3) || (RCAR_LSI == RCAR_D3) { SEC_SEL6, 0xFFFFFBFFU}, #else { SEC_SEL6, 0xFFFFCBFFU}, #endif /* {SEC_SEL7, 0xFFFFFFFFU}, */ /* {SEC_SEL8, 0xFFFFFFFFU}, */ /* {SEC_SEL9, 0xFFFFFFFFU}, */ /* {SEC_SEL10, 0xFFFFFFFFU}, */ /* {SEC_SEL11, 0xFFFFFFFFU}, */ /* {SEC_SEL12, 0xFFFFFFFFU}, */ /* Bit22: RPC slave ports. */ /* 0: registers accessed from secure resource only. */ #if (RCAR_RPC_HYPERFLASH_LOCKED == 1) {SEC_SEL13, 0xFFBFFFFFU}, #endif /* Bit27: System Timer (SCMT) slave ports */ /* 0: registers accessed from secure resource only */ /* Bit26: System Watchdog Timer (SWDT) slave ports */ /* 0: registers accessed from secure resource only */ { SEC_SEL14, 0xF3FFFFFFU}, /* Bit13: RST slave ports. */ /* 0: registers accessed from secure resource only */ /* Bit 7: Life Cycle 0 slave ports */ /* 0: registers accessed from secure resource only */ { SEC_SEL15, 0xFFFFFF3FU}, /** Security group 0 attribute setting for master ports 0 */ /** Security group 1 attribute setting for master ports 0 */ /* {SEC_GRP0CR0, 0x00000000U}, */ /* {SEC_GRP1CR0, 0x00000000U}, */ /** Security group 0 attribute setting for master ports 1 */ /** Security group 1 attribute setting for master ports 1 */ /* {SEC_GRP0CR1, 0x00000000U}, */ /* {SEC_GRP1CR1, 0x00000000U}, */ /** Security group 0 attribute setting for master ports 2 */ /** Security group 1 attribute setting for master ports 2 */ /* Bit17: SCEG Secure Core master ports. */ /* SecurityGroup3 */ { SEC_GRP0CR2, 0x00020000U}, { SEC_GRP1CR2, 0x00020000U}, /** Security group 0 attribute setting for master ports 3 */ /** Security group 1 attribute setting for master ports 3 */ /* {SEC_GRP0CR3, 0x00000000U}, */ /* {SEC_GRP1CR3, 0x00000000U}, */ /** Security group 0 attribute setting for slave ports 0 */ /** Security group 1 attribute setting for slave ports 0 */ /* {SEC_GRP0COND0, 0x00000000U}, */ /* {SEC_GRP1COND0, 0x00000000U}, */ /** Security group 0 attribute setting for slave ports 1 */ /** Security group 1 attribute setting for slave ports 1 */ /* {SEC_GRP0COND1, 0x00000000U}, */ /* {SEC_GRP1COND1, 0x00000000U}, */ /** Security group 0 attribute setting for slave ports 2 */ /** Security group 1 attribute setting for slave ports 2 */ /* {SEC_GRP0COND2, 0x00000000U}, */ /* {SEC_GRP1COND2, 0x00000000U}, */ /** Security group 0 attribute setting for slave ports 3 */ /** Security group 1 attribute setting for slave ports 3 */ /* Bit19: AXI-Bus (Main Memory domain AXI) slave ports. */ /* SecurityGroup3 */ /* Bit 9: DBSC4 register access slave ports. */ /* SecurityGroup3 */ #if (LIFEC_DBSC_PROTECT_ENABLE == 1) { SEC_GRP0COND3, 0x00080200U}, { SEC_GRP1COND3, 0x00080200U}, #else { SEC_GRP0COND3, 0x00000000U}, { SEC_GRP1COND3, 0x00000000U}, #endif /** Security group 0 attribute setting for slave ports 4 */ /** Security group 1 attribute setting for slave ports 4 */ /* {SEC_GRP0COND4, 0x00000000U}, */ /* {SEC_GRP1COND4, 0x00000000U}, */ /** Security group 0 attribute setting for slave ports 5 */ /** Security group 1 attribute setting for slave ports 5 */ /* Bit 6: Boot ROM slave ports */ /* SecurityGroup3 */ { SEC_GRP0COND5, 0x00000040U}, { SEC_GRP1COND5, 0x00000040U}, /** Security group 0 attribute setting for slave ports 6 */ /** Security group 1 attribute setting for slave ports 6 */ /* Bit13: SCEG PKA (secure APB) slave ports */ /* SecurityGroup3 */ /* Reserved[R-Car E3] */ /* Bit12: SCEG PKA (public APB) slave ports */ /* SecurityGroup3 */ /* Reserved[R-Car E3] */ /* Bit10: SCEG Secure Core slave ports */ /* SecurityGroup3 */ #if RCAR_LSI == RCAR_E3 { SEC_GRP0COND6, 0x00000400U}, { SEC_GRP1COND6, 0x00000400U}, #else { SEC_GRP0COND6, 0x00003400U}, { SEC_GRP1COND6, 0x00003400U}, #endif /** Security group 0 attribute setting for slave ports 7 */ /** Security group 1 attribute setting for slave ports 7 */ /* {SEC_GRP0COND7, 0x00000000U}, */ /* {SEC_GRP1COND7, 0x00000000U}, */ /** Security group 0 attribute setting for slave ports 8 */ /** Security group 1 attribute setting for slave ports 8 */ /* {SEC_GRP0COND8, 0x00000000U}, */ /* {SEC_GRP1COND8, 0x00000000U}, */ /** Security group 0 attribute setting for slave ports 9 */ /** Security group 1 attribute setting for slave ports 9 */ /* {SEC_GRP0COND9, 0x00000000U}, */ /* {SEC_GRP1COND9, 0x00000000U}, */ /** Security group 0 attribute setting for slave ports 10 */ /** Security group 1 attribute setting for slave ports 10 */ /* {SEC_GRP0COND10, 0x00000000U}, */ /* {SEC_GRP1COND10, 0x00000000U}, */ /** Security group 0 attribute setting for slave ports 11 */ /** Security group 1 attribute setting for slave ports 11 */ /* {SEC_GRP0COND11, 0x00000000U}, */ /* {SEC_GRP1COND11, 0x00000000U}, */ /** Security group 0 attribute setting for slave ports 12 */ /** Security group 1 attribute setting for slave ports 12 */ /* {SEC_GRP0COND12, 0x00000000U}, */ /* {SEC_GRP1COND12, 0x00000000U}, */ /** Security group 0 attribute setting for slave ports 13 */ /** Security group 1 attribute setting for slave ports 13 */ /* Bit22: RPC slave ports. */ /* SecurityGroup3 */ #if (RCAR_RPC_HYPERFLASH_LOCKED == 1) {SEC_GRP0COND13, 0x00400000U}, {SEC_GRP1COND13, 0x00400000U}, #endif /** Security group 0 attribute setting for slave ports 14 */ /** Security group 1 attribute setting for slave ports 14 */ /* Bit26: System Timer (SCMT) slave ports */ /* SecurityGroup3 */ /* Bit27: System Watchdog Timer (SWDT) slave ports */ /* SecurityGroup3 */ { SEC_GRP0COND14, 0x0C000000U}, { SEC_GRP1COND14, 0x0C000000U}, /** Security group 0 attribute setting for slave ports 15 */ /** Security group 1 attribute setting for slave ports 15 */ /* Bit13: RST slave ports */ /* SecurityGroup3 */ /* Bit 7: Life Cycle 0 slave ports */ /* SecurityGroup3 */ /* Bit 6: TDBG slave ports */ /* SecurityGroup3 */ { SEC_GRP0COND15, 0x000000C0U}, { SEC_GRP1COND15, 0x000000C0U}, /** Security write protection attribute setting slave ports 0 */ /* {SEC_READONLY0, 0x00000000U}, */ /** Security write protection attribute setting slave ports 1 */ /* {SEC_READONLY1, 0x00000000U}, */ /** Security write protection attribute setting slave ports 2 */ /* {SEC_READONLY2, 0x00000000U}, */ /** Security write protection attribute setting slave ports 3 */ /* {SEC_READONLY3, 0x00000000U}, */ /** Security write protection attribute setting slave ports 4 */ /* {SEC_READONLY4, 0x00000000U}, */ /** Security write protection attribute setting slave ports 5 */ /* {SEC_READONLY5, 0x00000000U}, */ /** Security write protection attribute setting slave ports 6 */ /* {SEC_READONLY6, 0x00000000U}, */ /** Security write protection attribute setting slave ports 7 */ /* {SEC_READONLY7, 0x00000000U}, */ /** Security write protection attribute setting slave ports 8 */ /* {SEC_READONLY8, 0x00000000U}, */ /** Security write protection attribute setting slave ports 9 */ /* {SEC_READONLY9, 0x00000000U}, */ /** Security write protection attribute setting slave ports 10 */ /* {SEC_READONLY10, 0x00000000U}, */ /** Security write protection attribute setting slave ports 11 */ /* {SEC_READONLY11, 0x00000000U}, */ /** Security write protection attribute setting slave ports 12 */ /* {SEC_READONLY12, 0x00000000U}, */ /** Security write protection attribute setting slave ports 13 */ /* {SEC_READONLY13, 0x00000000U}, */ /** Security write protection attribute setting slave ports 14 */ /* {SEC_READONLY14, 0x00000000U}, */ /** Security write protection attribute setting slave ports 15 */ /* {SEC_READONLY15, 0x00000000U} */ }; /* AXI settings */ static const struct { uint32_t reg; uint32_t val; } axi[] = { /* DRAM protection */ /* AXI dram protected area division */ { AXI_DPTDIVCR0, 0x0E0403F0U}, { AXI_DPTDIVCR1, 0x0E0407E0U}, { AXI_DPTDIVCR2, 0x0E080000U}, { AXI_DPTDIVCR3, 0x0E080000U}, { AXI_DPTDIVCR4, 0x0E080000U}, { AXI_DPTDIVCR5, 0x0E080000U}, { AXI_DPTDIVCR6, 0x0E080000U}, { AXI_DPTDIVCR7, 0x0E080000U}, { AXI_DPTDIVCR8, 0x0E080000U}, { AXI_DPTDIVCR9, 0x0E080000U}, { AXI_DPTDIVCR10, 0x0E080000U}, { AXI_DPTDIVCR11, 0x0E080000U}, { AXI_DPTDIVCR12, 0x0E080000U}, { AXI_DPTDIVCR13, 0x0E080000U}, { AXI_DPTDIVCR14, 0x0E080000U}, /* AXI dram protected area setting */ { AXI_DPTCR0, 0x0E000000U}, { AXI_DPTCR1, 0x0E000E0EU}, { AXI_DPTCR2, 0x0E000000U}, { AXI_DPTCR3, 0x0E000000U}, { AXI_DPTCR4, 0x0E000000U}, { AXI_DPTCR5, 0x0E000000U}, { AXI_DPTCR6, 0x0E000000U}, { AXI_DPTCR7, 0x0E000000U}, { AXI_DPTCR8, 0x0E000000U}, { AXI_DPTCR9, 0x0E000000U}, { AXI_DPTCR10, 0x0E000000U}, { AXI_DPTCR11, 0x0E000000U}, { AXI_DPTCR12, 0x0E000000U}, { AXI_DPTCR13, 0x0E000000U}, { AXI_DPTCR14, 0x0E000000U}, { AXI_DPTCR15, 0x0E000000U}, /* SRAM ptotection */ /* AXI sram protected area division */ { AXI_SPTDIVCR0, 0x0E0E6304U}, { AXI_SPTDIVCR1, 0x0E0E6360U}, { AXI_SPTDIVCR2, 0x0E0E6360U}, { AXI_SPTDIVCR3, 0x0E0E6360U}, { AXI_SPTDIVCR4, 0x0E0E6360U}, { AXI_SPTDIVCR5, 0x0E0E6360U}, { AXI_SPTDIVCR6, 0x0E0E6360U}, { AXI_SPTDIVCR7, 0x0E0E6360U}, { AXI_SPTDIVCR8, 0x0E0E6360U}, { AXI_SPTDIVCR9, 0x0E0E6360U}, { AXI_SPTDIVCR10, 0x0E0E6360U}, { AXI_SPTDIVCR11, 0x0E0E6360U}, { AXI_SPTDIVCR12, 0x0E0E6360U}, { AXI_SPTDIVCR13, 0x0E0E6360U}, { AXI_SPTDIVCR14, 0x0E0E6360U}, /* AXI sram protected area setting */ { AXI_SPTCR0, 0x0E000E0EU}, { AXI_SPTCR1, 0x0E000000U}, { AXI_SPTCR2, 0x0E000000U}, { AXI_SPTCR3, 0x0E000000U}, { AXI_SPTCR4, 0x0E000000U}, { AXI_SPTCR5, 0x0E000000U}, { AXI_SPTCR6, 0x0E000000U}, { AXI_SPTCR7, 0x0E000000U}, { AXI_SPTCR8, 0x0E000000U}, { AXI_SPTCR9, 0x0E000000U}, { AXI_SPTCR10, 0x0E000000U}, { AXI_SPTCR11, 0x0E000000U}, { AXI_SPTCR12, 0x0E000000U}, { AXI_SPTCR13, 0x0E000000U}, { AXI_SPTCR14, 0x0E000000U}, { AXI_SPTCR15, 0x0E000000U} }; static void lifec_security_setting(void) { uint32_t i; for (i = 0; i < ARRAY_SIZE(lifec); i++) mmio_write_32(lifec[i].reg, lifec[i].val); } /* SRAM/DRAM protection setting */ static void axi_security_setting(void) { uint32_t i; for (i = 0; i < ARRAY_SIZE(axi); i++) mmio_write_32(axi[i].reg, axi[i].val); } void bl2_secure_setting(void) { const uint32_t delay = 10; lifec_security_setting(); axi_security_setting(); rcar_micro_delay(delay); return; } trusted-firmware-a-2.2/plat/renesas/rcar/bl31_plat_setup.c000066400000000000000000000062551355360272700236150ustar00rootroot00000000000000/* * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "pwrc.h" #include "rcar_def.h" #include "rcar_private.h" #include "rcar_version.h" IMPORT_SYM(uint64_t, __RO_START__, BL31_RO_BASE) IMPORT_SYM(uint64_t, __RO_END__, BL31_RO_LIMIT) #if USE_COHERENT_MEM IMPORT_SYM(uint64_t, __COHERENT_RAM_START__, BL31_COHERENT_RAM_BASE) IMPORT_SYM(uint64_t, __COHERENT_RAM_END__, BL31_COHERENT_RAM_LIMIT) #endif extern void plat_rcar_gic_driver_init(void); extern void plat_rcar_gic_init(void); u_register_t rcar_boot_mpidr; static int cci_map[] = { CCI500_CLUSTER0_SL_IFACE_IX_FOR_M3, CCI500_CLUSTER1_SL_IFACE_IX_FOR_M3 }; void plat_cci_init(void) { uint32_t prd; prd = mmio_read_32(RCAR_PRR) & (PRR_PRODUCT_MASK | PRR_CUT_MASK); if (PRR_PRODUCT_H3_CUT10 == prd || PRR_PRODUCT_H3_CUT11 == prd) { cci_map[0U] = CCI500_CLUSTER0_SL_IFACE_IX; cci_map[1U] = CCI500_CLUSTER1_SL_IFACE_IX; } cci_init(RCAR_CCI_BASE, cci_map, ARRAY_SIZE(cci_map)); } void plat_cci_enable(void) { cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr())); } void plat_cci_disable(void) { cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr())); } struct entry_point_info *bl31_plat_get_next_image_ep_info(uint32_t type) { bl2_to_bl31_params_mem_t *from_bl2 = (bl2_to_bl31_params_mem_t *) PARAMS_BASE; entry_point_info_t *next_image_info; next_image_info = (type == NON_SECURE) ? &from_bl2->bl33_ep_info : &from_bl2->bl32_ep_info; return next_image_info->pc ? next_image_info : NULL; } void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { rcar_console_runtime_init(); NOTICE("BL3-1 : Rev.%s\n", version_of_renesas); #if RCAR_LSI != RCAR_D3 if (RCAR_CLUSTER_A53A57 == rcar_pwrc_get_cluster()) { plat_cci_init(); plat_cci_enable(); } #endif } void bl31_plat_arch_setup(void) { rcar_configure_mmu_el3(BL31_BASE, BL31_LIMIT - BL31_BASE, BL31_RO_BASE, BL31_RO_LIMIT #if USE_COHERENT_MEM , BL31_COHERENT_RAM_BASE, BL31_COHERENT_RAM_LIMIT #endif ); rcar_pwrc_code_copy_to_system_ram(); } void bl31_platform_setup(void) { plat_rcar_gic_driver_init(); plat_rcar_gic_init(); /* enable the system level generic timer */ mmio_write_32(RCAR_CNTC_BASE + CNTCR_OFF, CNTCR_FCREQ(U(0)) | CNTCR_EN); rcar_pwrc_setup(); #if 0 /* TODO: there is a broad number of rcar-gen3 SoC configurations; to support all of them, Renesas use the pwrc driver to discover what cores are on/off before announcing the topology. This code hasnt been ported yet */ rcar_setup_topology(); #endif /* mask should match the kernel's MPIDR_HWID_BITMASK so the core can be identified during cpuhotplug (check the kernel's psci migrate set of functions */ rcar_boot_mpidr = read_mpidr_el1() & 0x0000ffffU; } trusted-firmware-a-2.2/plat/renesas/rcar/include/000077500000000000000000000000001355360272700220635ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/renesas/rcar/include/plat.ld.S000066400000000000000000000014671355360272700235550ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RCAR_PLAT_LD_S #define RCAR_PLAT_LD_S #include #include MEMORY { SRAM (rwx): ORIGIN = BL31_SRAM_BASE, LENGTH = DEVICE_SRAM_SIZE PRAM (r): ORIGIN = BL31_LIMIT - DEVICE_SRAM_SIZE, LENGTH = DEVICE_SRAM_SIZE } SECTIONS { /* SRAM_COPY is in PRAM */ . = BL31_LIMIT - DEVICE_SRAM_SIZE; __SRAM_COPY_START__ = .; .system_ram : { /* system ram start is in SRAM */ __system_ram_start__ = .; *(.system_ram*) *iic_dvfs.o(.rodata) __system_ram_end__ = .; } >SRAM AT>PRAM ASSERT(__BL31_END__ <= BL31_LIMIT - DEVICE_SRAM_SIZE, "BL31 image too large - writing on top of SRAM!") } #endif /* RCAR_PLAT_LD_S */ trusted-firmware-a-2.2/plat/renesas/rcar/include/plat_macros.S000066400000000000000000000045671355360272700245270ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "rcar_def.h" .section .rodata.gic_reg_name, "aS" gicc_regs: .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", "" gicd_pend_reg: .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n" newline: .asciz "\n" spacer: .asciz ":\t\t0x" /* --------------------------------------------- * The below macro prints out relevant GIC * registers whenever an unhandled exception is * taken in BL3-1. * Clobbers: x0 - x10, x16, x17, sp * --------------------------------------------- */ .macro plat_print_gic_regs mov_imm x17, RCAR_GICC_BASE mov_imm x16, RCAR_GICD_BASE print_gicc_regs: /* gicc base address is now in x17 */ adr x6, gicc_regs /* Load the gicc reg list to x6 */ /* Load the gicc regs to gp regs used by str_in_crash_buf_print */ ldr w8, [x17, #GICC_HPPIR] ldr w9, [x17, #GICC_AHPPIR] ldr w10, [x17, #GICC_CTLR] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print /* Print the GICD_ISPENDR regs */ add x7, x16, #GICD_ISPENDR adr x4, gicd_pend_reg bl asm_print_str gicd_ispendr_loop: sub x4, x7, x16 cmp x4, #0x280 b.eq exit_print_gic_regs bl asm_print_hex adr x4, spacer bl asm_print_str ldr x4, [x7], #8 bl asm_print_hex adr x4, newline bl asm_print_str b gicd_ispendr_loop exit_print_gic_regs: .endm .section .rodata.cci_reg_name, "aS" cci_iface_regs: .asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , "" /* ------------------------------------------------ * The below macro prints out relevant interconnect * registers whenever an unhandled exception is * taken in BL3-1. * Clobbers: x0 - x9, sp * ------------------------------------------------ */ .macro plat_print_interconnect_regs adr x6, cci_iface_regs /* Store in x7 the base address of the first interface */ mov_imm x7, (CCI500_BASE + SLAVE_IFACE3_OFFSET) ldr w8, [x7, #SNOOP_CTRL_REG] /* Store in x7 the base address of the second interface */ mov_imm x7, (CCI500_BASE + SLAVE_IFACE4_OFFSET) ldr w9, [x7, #SNOOP_CTRL_REG] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print .endm .macro plat_crash_print_regs plat_print_gic_regs plat_print_interconnect_regs .endm trusted-firmware-a-2.2/plat/renesas/rcar/include/platform_def.h000066400000000000000000000154701355360272700247050ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #ifndef __ASSEMBLER__ #include #endif #include #include "rcar_def.h" /******************************************************************************* * Platform binary types for linking ******************************************************************************/ #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 /******************************************************************************* * Generic platform constants ******************************************************************************/ #define FIRMWARE_WELCOME_STR "Booting Rcar-gen3 Trusted Firmware\n" /* Size of cacheable stacks */ #if IMAGE_BL1 #if TRUSTED_BOARD_BOOT #define PLATFORM_STACK_SIZE U(0x1000) #else #define PLATFORM_STACK_SIZE U(0x440) #endif #elif IMAGE_BL2 #if TRUSTED_BOARD_BOOT #define PLATFORM_STACK_SIZE U(0x1000) #else #define PLATFORM_STACK_SIZE U(0x400) #endif #elif IMAGE_BL31 #define PLATFORM_STACK_SIZE U(0x400) #elif IMAGE_BL32 #define PLATFORM_STACK_SIZE U(0x440) #endif #define BL332_IMAGE_ID (NS_BL2U_IMAGE_ID + 1) #define BL333_IMAGE_ID (NS_BL2U_IMAGE_ID + 2) #define BL334_IMAGE_ID (NS_BL2U_IMAGE_ID + 3) #define BL335_IMAGE_ID (NS_BL2U_IMAGE_ID + 4) #define BL336_IMAGE_ID (NS_BL2U_IMAGE_ID + 5) #define BL337_IMAGE_ID (NS_BL2U_IMAGE_ID + 6) #define BL338_IMAGE_ID (NS_BL2U_IMAGE_ID + 7) #define BL332_KEY_CERT_ID (NS_BL2U_IMAGE_ID + 8) #define BL333_KEY_CERT_ID (NS_BL2U_IMAGE_ID + 9) #define BL334_KEY_CERT_ID (NS_BL2U_IMAGE_ID + 10) #define BL335_KEY_CERT_ID (NS_BL2U_IMAGE_ID + 11) #define BL336_KEY_CERT_ID (NS_BL2U_IMAGE_ID + 12) #define BL337_KEY_CERT_ID (NS_BL2U_IMAGE_ID + 13) #define BL338_KEY_CERT_ID (NS_BL2U_IMAGE_ID + 14) #define BL332_CERT_ID (NS_BL2U_IMAGE_ID + 15) #define BL333_CERT_ID (NS_BL2U_IMAGE_ID + 16) #define BL334_CERT_ID (NS_BL2U_IMAGE_ID + 17) #define BL335_CERT_ID (NS_BL2U_IMAGE_ID + 18) #define BL336_CERT_ID (NS_BL2U_IMAGE_ID + 19) #define BL337_CERT_ID (NS_BL2U_IMAGE_ID + 20) #define BL338_CERT_ID (NS_BL2U_IMAGE_ID + 21) /* io drivers id */ #define FLASH_DEV_ID U(0) #define EMMC_DEV_ID U(1) /* * R-Car H3 Cortex-A57 * L1:I/48KB(16KBx3way) D/32KB(16KBx2way) L2:2MB(128KBx16way) * Cortex-A53 * L1:I/32KB(16KBx2way) D/32KB(8KBx4way) L2:512KB(32KBx16way) */ #define PLATFORM_CACHE_LINE_SIZE 64 #define PLATFORM_CLUSTER_COUNT U(2) #define PLATFORM_CLUSTER0_CORE_COUNT U(4) #define PLATFORM_CLUSTER1_CORE_COUNT U(4) #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \ PLATFORM_CLUSTER0_CORE_COUNT) #define PLATFORM_MAX_CPUS_PER_CLUSTER U(4) #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2 #define PLAT_NUM_PWR_DOMAINS (PLATFORM_CORE_COUNT + \ PLATFORM_CLUSTER_COUNT + 1) #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE U(2) #define MAX_IO_DEVICES U(3) #define MAX_IO_HANDLES U(4) /******************************************************************************* * BL2 specific defines. ******************************************************************************/ /* Put BL2 just below BL3-1. BL2_BASE is calculated using the current BL2 debug * size plus a little space for growth. */ #define RCAR_SYSRAM_BASE U(0xE6300000) #if (RCAR_LSI == RCAR_E3) || (RCAR_LSI == RCAR_D3) #define BL2_LIMIT U(0xE6320000) #else #define BL2_LIMIT U(0xE6360000) #endif #if (RCAR_LSI == RCAR_E3) || (RCAR_LSI == RCAR_D3) #define BL2_BASE U(0xE6304000) #define BL2_IMAGE_LIMIT U(0xE6318000) #elif (RCAR_LSI == RCAR_V3M) #define BL2_BASE U(0xE6344000) #define BL2_IMAGE_LIMIT U(0xE636E800) #else #define BL2_BASE U(0xE6304000) #define BL2_IMAGE_LIMIT U(0xE632E800) #endif #define RCAR_SYSRAM_SIZE (BL2_BASE - RCAR_SYSRAM_BASE) /******************************************************************************* * BL31 specific defines. ******************************************************************************/ /* Put BL3-1 at the top of the Trusted SRAM. BL31_BASE is calculated using the * current BL3-1 debug size plus a little space for growth. */ #define BL31_BASE (RCAR_TRUSTED_SRAM_BASE) #define BL31_LIMIT (RCAR_TRUSTED_SRAM_BASE + \ RCAR_TRUSTED_SRAM_SIZE) #define RCAR_BL31_LOG_BASE (0x44040000) #define RCAR_BL31_SDRAM_BTM (RCAR_BL31_LOG_BASE + 0x14000) #define RCAR_BL31_LOG_SIZE (RCAR_BL31_SDRAM_BTM - RCAR_BL31_LOG_BASE) #define BL31_SRAM_BASE (DEVICE_SRAM_BASE) #define BL31_SRAM_LIMIT (DEVICE_SRAM_BASE + DEVICE_SRAM_SIZE) /******************************************************************************* * BL32 specific defines. ******************************************************************************/ #ifndef SPD_NONE #define BL32_BASE U(0x44100000) #define BL32_LIMIT (BL32_BASE + U(0x100000)) #endif /******************************************************************************* * BL33 ******************************************************************************/ #define BL33_BASE DRAM1_NS_BASE /******************************************************************************* * Platform specific page table and MMU setup constants ******************************************************************************/ #if IMAGE_BL1 #define MAX_XLAT_TABLES U(2) #elif IMAGE_BL2 #define MAX_XLAT_TABLES U(5) #elif IMAGE_BL31 #define MAX_XLAT_TABLES U(4) #elif IMAGE_BL32 #define MAX_XLAT_TABLES U(3) #endif #if IMAGE_BL2 #define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 40) #define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 40) #else #define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32) #endif #define MAX_MMAP_REGIONS (RCAR_MMAP_ENTRIES + RCAR_BL_REGIONS) /******************************************************************************* * Declarations and constants to access the mailboxes safely. Each mailbox is * aligned on the biggest cache line size in the platform. This is known only * to the platform as it might have a combination of integrated and external * caches. Such alignment ensures that two maiboxes do not sit on the same cache * line at any cache level. They could belong to different cpus/clusters & * get written while being protected by different locks causing corruption of * a valid mailbox address. ******************************************************************************/ #define CACHE_WRITEBACK_SHIFT (6) #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) /******************************************************************************* * Size of the per-cpu data in bytes that should be reserved in the generic * per-cpu data structure for the RCAR port. ******************************************************************************/ #if !USE_COHERENT_MEM #define PLAT_PCPU_DATA_SIZE (2) #endif #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/renesas/rcar/include/rcar_def.h000066400000000000000000000307061355360272700240070ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RCAR_DEF_H #define RCAR_DEF_H #include #include #define RCAR_PRIMARY_CPU 0x0 #define RCAR_TRUSTED_SRAM_BASE 0x44000000 #define RCAR_TRUSTED_SRAM_SIZE 0x0003E000 #define RCAR_SHARED_MEM_BASE (RCAR_TRUSTED_SRAM_BASE + \ RCAR_TRUSTED_SRAM_SIZE) #define RCAR_SHARED_MEM_SIZE U(0x00001000) #define FLASH0_BASE U(0x08000000) #define FLASH0_SIZE U(0x04000000) #define FLASH_MEMORY_SIZE U(0x04000000) /* hyper flash */ #define FLASH_TRANS_SIZE_UNIT U(0x00000100) #define DEVICE_RCAR_BASE U(0xE6000000) #define DEVICE_RCAR_SIZE U(0x00300000) #define DEVICE_RCAR_BASE2 U(0xE6360000) #define DEVICE_RCAR_SIZE2 U(0x19CA0000) #define DEVICE_SRAM_BASE U(0xE6300000) #define DEVICE_SRAM_SIZE U(0x00002000) #define DEVICE_SRAM_STACK_BASE (DEVICE_SRAM_BASE + DEVICE_SRAM_SIZE) #define DEVICE_SRAM_STACK_SIZE U(0x00001000) #define DRAM_LIMIT ULL(0x0000010000000000) #define DRAM1_BASE U(0x40000000) #define DRAM1_SIZE U(0x80000000) #define DRAM1_NS_BASE (DRAM1_BASE + U(0x10000000)) #define DRAM1_NS_SIZE (DRAM1_SIZE - DRAM1_NS_BASE) #define DRAM_40BIT_BASE ULL(0x0400000000) #define DRAM_40BIT_SIZE ULL(0x0400000000) #define DRAM_PROTECTED_BASE ULL(0x43F00000) #define DRAM_40BIT_PROTECTED_BASE ULL(0x0403F00000) #define DRAM_PROTECTED_SIZE ULL(0x03F00000) #define RCAR_BL31_CRASH_BASE U(0x4403F000) #define RCAR_BL31_CRASH_SIZE U(0x00001000) /* Entrypoint mailboxes */ #define MBOX_BASE RCAR_SHARED_MEM_BASE #define MBOX_SIZE 0x200 /* Base address where parameters to BL31 are stored */ #define PARAMS_BASE (MBOX_BASE + MBOX_SIZE) #define BOOT_KIND_BASE (RCAR_SHARED_MEM_BASE + \ RCAR_SHARED_MEM_SIZE - 0x100) /* The number of regions like RO(code), coherent and data required by * different BL stages which need to be mapped in the MMU */ #if USE_COHERENT_MEM #define RCAR_BL_REGIONS (3) #else #define RCAR_BL_REGIONS (2) #endif /* The RCAR_MAX_MMAP_REGIONS depend on the number of entries in rcar_mmap[] * defined for each BL stage in rcar_common.c. */ #if IMAGE_BL2 #define RCAR_MMAP_ENTRIES (9) #endif #if IMAGE_BL31 #define RCAR_MMAP_ENTRIES (9) #endif #if IMAGE_BL2 #define REG1_BASE U(0xE6400000) #define REG1_SIZE U(0x04C00000) #define ROM0_BASE U(0xEB100000) #define ROM0_SIZE U(0x00028000) #define REG2_BASE U(0xEC000000) #define REG2_SIZE U(0x14000000) #endif /* BL33 */ #define NS_IMAGE_OFFSET (DRAM1_BASE + U(0x09000000)) /* BL31 */ #define RCAR_DEVICE_BASE DEVICE_RCAR_BASE #define RCAR_DEVICE_SIZE (0x1A000000) #define RCAR_LOG_RES_SIZE (512/8) #define RCAR_LOG_HEADER_SIZE (16) #define RCAR_LOG_OTHER_SIZE (RCAR_LOG_HEADER_SIZE + \ RCAR_LOG_RES_SIZE) #define RCAR_BL31_LOG_MAX (RCAR_BL31_LOG_SIZE - \ RCAR_LOG_OTHER_SIZE) #define RCAR_CRASH_STACK RCAR_BL31_CRASH_BASE #define AARCH64_SPACE_BASE ULL(0x00000000000) #define AARCH64_SPACE_SIZE ULL(0x10000000000) /* CCI related constants */ #define CCI500_BASE U(0xF1200000) #define CCI500_CLUSTER0_SL_IFACE_IX (2) #define CCI500_CLUSTER1_SL_IFACE_IX (3) #define CCI500_CLUSTER0_SL_IFACE_IX_FOR_M3 (1) #define CCI500_CLUSTER1_SL_IFACE_IX_FOR_M3 (2) #define RCAR_CCI_BASE CCI500_BASE /* GIC */ #define RCAR_GICD_BASE U(0xF1010000) #define RCAR_GICR_BASE U(0xF1010000) #define RCAR_GICC_BASE U(0xF1020000) #define RCAR_GICH_BASE U(0xF1040000) #define RCAR_GICV_BASE U(0xF1060000) #define ARM_IRQ_SEC_PHY_TIMER U(29) #define ARM_IRQ_SEC_SGI_0 U(8) #define ARM_IRQ_SEC_SGI_1 U(9) #define ARM_IRQ_SEC_SGI_2 U(10) #define ARM_IRQ_SEC_SGI_3 U(11) #define ARM_IRQ_SEC_SGI_4 U(12) #define ARM_IRQ_SEC_SGI_5 U(13) #define ARM_IRQ_SEC_SGI_6 U(14) #define ARM_IRQ_SEC_SGI_7 U(15) #define ARM_IRQ_SEC_RPC U(70) #define ARM_IRQ_SEC_TIMER U(166) #define ARM_IRQ_SEC_TIMER_UP U(171) #define ARM_IRQ_SEC_WDT U(173) #define ARM_IRQ_SEC_CRYPT U(102) #define ARM_IRQ_SEC_CRYPT_SecPKA U(97) #define ARM_IRQ_SEC_CRYPT_PubPKA U(98) /* Timer control */ #define RCAR_CNTC_BASE U(0xE6080000) /* Reset */ #define RCAR_CPGWPR U(0xE6150900) /* CPG write protect */ #define RCAR_MODEMR U(0xE6160060) /* Mode pin */ #define RCAR_CA57RESCNT U(0xE6160040) /* Reset control A57 */ #define RCAR_CA53RESCNT U(0xE6160044) /* Reset control A53 */ #define RCAR_SRESCR U(0xE6160110) /* Soft Power On Reset */ #define RCAR_CA53WUPCR U(0xE6151010) /* Wake-up control A53 */ #define RCAR_CA57WUPCR U(0xE6152010) /* Wake-up control A57 */ #define RCAR_CA53PSTR U(0xE6151040) /* Power status A53 */ #define RCAR_CA57PSTR U(0xE6152040) /* Power status A57 */ #define RCAR_CA53CPU0CR U(0xE6151100) /* CPU control A53 */ #define RCAR_CA57CPU0CR U(0xE6152100) /* CPU control A57 */ #define RCAR_CA53CPUCMCR U(0xE6151184) /* Common power A53 */ #define RCAR_CA57CPUCMCR U(0xE6152184) /* Common power A57 */ #define RCAR_WUPMSKCA57 U(0xE6180014) /* Wake-up mask A57 */ #define RCAR_WUPMSKCA53 U(0xE6180018) /* Wake-up mask A53 */ /* SYSC */ #define RCAR_PWRSR3 U(0xE6180140) /* Power stat A53-SCU */ #define RCAR_PWRSR5 U(0xE61801C0) /* Power stat A57-SCU */ #define RCAR_SYSCIER U(0xE618000C) /* Interrupt enable */ #define RCAR_SYSCIMR U(0xE6180010) /* Interrupt mask */ #define RCAR_SYSCSR U(0xE6180000) /* SYSC status */ #define RCAR_PWRONCR3 U(0xE618014C) /* Power resume A53-SCU */ #define RCAR_PWRONCR5 U(0xE61801CC) /* Power resume A57-SCU */ #define RCAR_PWROFFCR3 U(0xE6180144) /* Power shutof A53-SCU */ #define RCAR_PWROFFCR5 U(0xE61801C4) /* Power shutof A57-SCU */ #define RCAR_PWRER3 U(0xE6180154) /* shutoff/resume error */ #define RCAR_PWRER5 U(0xE61801D4) /* shutoff/resume error */ #define RCAR_SYSCISR U(0xE6180004) /* Interrupt status */ #define RCAR_SYSCISCR U(0xE6180008) /* Interrupt stat clear */ /* Product register */ #define RCAR_PRR U(0xFFF00044) #define RCAR_M3_CUT_VER11 U(0x00000010) /* M3 Ver.1.1/Ver.1.2 */ #define RCAR_MAJOR_MASK U(0x000000F0) #define RCAR_MINOR_MASK U(0x0000000F) #define PRR_PRODUCT_SHIFT U(8) #define RCAR_MAJOR_SHIFT U(4) #define RCAR_MINOR_SHIFT U(0) #define RCAR_MAJOR_OFFSET U(1) #define RCAR_M3_MINOR_OFFSET U(2) #define PRR_PRODUCT_H3_CUT10 (PRR_PRODUCT_H3 | U(0x00)) /* 1.0 */ #define PRR_PRODUCT_H3_CUT11 (PRR_PRODUCT_H3 | U(0x01)) /* 1.1 */ #define PRR_PRODUCT_H3_CUT20 (PRR_PRODUCT_H3 | U(0x10)) /* 2.0 */ #define PRR_PRODUCT_M3_CUT10 (PRR_PRODUCT_M3 | U(0x00)) /* 1.0 */ #define PRR_PRODUCT_M3_CUT11 (PRR_PRODUCT_M3 | U(0x10)) #define PRR 0xFFF00044U #define PRR_PRODUCT_MASK 0x00007F00U #define PRR_CUT_MASK 0x000000FFU #define PRR_PRODUCT_H3 0x00004F00U /* R-Car H3 */ #define PRR_PRODUCT_M3 0x00005200U /* R-Car M3-W */ #define PRR_PRODUCT_V3M 0x00005400U /* R-Car V3M */ #define PRR_PRODUCT_M3N 0x00005500U /* R-Car M3-N */ #define PRR_PRODUCT_V3H 0x00005600U /* R-Car V3H */ #define PRR_PRODUCT_E3 0x00005700U /* R-Car E3 */ #define PRR_PRODUCT_D3 0x00005800U /* R-Car D3 */ #define PRR_PRODUCT_10 0x00U /* Ver.1.0 */ #define PRR_PRODUCT_11 0x01U /* Ver.1.1 */ #define PRR_PRODUCT_20 0x10U /* Ver.2.0 */ #define PRR_PRODUCT_21 0x11U /* Ver.2.1 */ #define PRR_PRODUCT_30 0x20U /* Ver.3.0 */ #define RCAR_CPU_MASK_CA57 U(0x80000000) #define RCAR_CPU_MASK_CA53 U(0x04000000) #define RCAR_CPU_HAVE_CA57 U(0x00000000) #define RCAR_CPU_HAVE_CA53 U(0x00000000) #define RCAR_SSCG_MASK U(0x1000) /* MD12 */ #define RCAR_SSCG_ENABLE U(0x1000) /* MD pin information */ #define MODEMR_BOOT_CPU_MASK U(0x000000C0) #define MODEMR_BOOT_CPU_CR7 U(0x000000C0) #define MODEMR_BOOT_CPU_CA57 U(0x00000000) #define MODEMR_BOOT_CPU_CA53 U(0x00000040) #define MODEMR_BOOT_DEV_MASK U(0x0000001E) #define MODEMR_BOOT_DEV_HYPERFLASH160 U(0x00000004) #define MODEMR_BOOT_DEV_HYPERFLASH80 U(0x00000006) #define MODEMR_BOOT_DEV_QSPI_FLASH40 U(0x00000008) #define MODEMR_BOOT_DEV_QSPI_FLASH80 U(0x0000000C) #define MODEMR_BOOT_DEV_EMMC_25X1 U(0x0000000A) #define MODEMR_BOOT_DEV_EMMC_50X8 U(0x0000001A) #define MODEMR_BOOT_PLL_MASK U(0x00006000) #define MODEMR_BOOT_PLL_SHIFT U(13) /* Memory mapped Generic timer interfaces */ #define ARM_SYS_CNTCTL_BASE RCAR_CNTC_BASE /* MODEMR PLL masks and bitfield values */ #define CHECK_MD13_MD14 U(0x6000) #define MD14_MD13_TYPE_0 U(0x0000) /* MD14=0 MD13=0 */ #define MD14_MD13_TYPE_1 U(0x2000) /* MD14=0 MD13=1 */ #define MD14_MD13_TYPE_2 U(0x4000) /* MD14=1 MD13=0 */ #define MD14_MD13_TYPE_3 U(0x6000) /* MD14=1 MD13=1 */ /* Frequency of EXTAL(Hz) */ #define EXTAL_MD14_MD13_TYPE_0 U(8333300) /* MD14=0 MD13=0 */ #define EXTAL_MD14_MD13_TYPE_1 U(10000000) /* MD14=0 MD13=1 */ #define EXTAL_MD14_MD13_TYPE_2 U(12500000) /* MD14=1 MD13=0 */ #define EXTAL_MD14_MD13_TYPE_3 U(16666600) /* MD14=1 MD13=1 */ #define EXTAL_SALVATOR_XS U(8320000) /* Salvator-XS */ #define EXTAL_EBISU U(24000000) /* Ebisu */ #define EXTAL_DRAAK U(24000000) /* Draak */ /* CPG write protect registers */ #define CPGWPR_PASSWORD (0x5A5AFFFFU) #define CPGWPCR_PASSWORD (0xA5A50000U) /* CA5x Debug Resource control registers */ #define CPG_CA57DBGRCR (CPG_BASE + 0x2180U) #define CPG_CA53DBGRCR (CPG_BASE + 0x1180U) #define DBGCPUPREN ((uint32_t)1U << 19U) #define CPG_PLL0CR (CPG_BASE + 0x00D8U) #define CPG_PLL2CR (CPG_BASE + 0x002CU) #define CPG_PLL4CR (CPG_BASE + 0x01F4U) #define CPG_CPGWPCR (CPG_BASE + 0x0904U) /* RST Registers */ #define RST_BASE (0xE6160000U) #define RST_WDTRSTCR (RST_BASE + 0x0054U) #define RST_MODEMR (RST_BASE + 0x0060U) #define WDTRSTCR_PASSWORD (0xA55A0000U) #define WDTRSTCR_RWDT_RSTMSK ((uint32_t)1U << 0U) /* MFIS Registers */ #define MFISWPCNTR_PASSWORD (0xACCE0000U) #define MFISWPCNTR (0xE6260900U) /* IPMMU registers */ #define IPMMU_MM_BASE (0xE67B0000U) #define IPMMUMM_IMSCTLR (IPMMU_MM_BASE + 0x0500U) #define IPMMUMM_IMAUXCTLR (IPMMU_MM_BASE + 0x0504U) #define IPMMUMM_IMSCTLR_ENABLE (0xC0000000U) #define IPMMUMM_IMAUXCTLR_NMERGE40_BIT (0x01000000U) #define IMSCTLR_DISCACHE (0xE0000000U) #define IPMMU_VP0_BASE (0xFE990000U) #define IPMMUVP0_IMSCTLR (IPMMU_VP0_BASE + 0x0500U) #define IPMMU_VI0_BASE (0xFEBD0000U) #define IPMMUVI0_IMSCTLR (IPMMU_VI0_BASE + 0x0500U) #define IPMMU_VI1_BASE (0xFEBE0000U) #define IPMMUVI1_IMSCTLR (IPMMU_VI1_BASE + 0x0500U) #define IPMMU_PV0_BASE (0xFD800000U) #define IPMMUPV0_IMSCTLR (IPMMU_PV0_BASE + 0x0500U) #define IPMMU_PV1_BASE (0xFD950000U) #define IPMMUPV1_IMSCTLR (IPMMU_PV1_BASE + 0x0500U) #define IPMMU_PV2_BASE (0xFD960000U) #define IPMMUPV2_IMSCTLR (IPMMU_PV2_BASE + 0x0500U) #define IPMMU_PV3_BASE (0xFD970000U) #define IPMMUPV3_IMSCTLR (IPMMU_PV3_BASE + 0x0500U) #define IPMMU_HC_BASE (0xE6570000U) #define IPMMUHC_IMSCTLR (IPMMU_HC_BASE + 0x0500U) #define IPMMU_RT_BASE (0xFFC80000U) #define IPMMURT_IMSCTLR (IPMMU_RT_BASE + 0x0500U) #define IPMMU_MP_BASE (0xEC670000U) #define IPMMUMP_IMSCTLR (IPMMU_MP_BASE + 0x0500U) #define IPMMU_DS0_BASE (0xE6740000U) #define IPMMUDS0_IMSCTLR (IPMMU_DS0_BASE + 0x0500U) #define IPMMU_DS1_BASE (0xE7740000U) #define IPMMUDS1_IMSCTLR (IPMMU_DS1_BASE + 0x0500U) /* ARMREG registers */ #define P_ARMREG_SEC_CTRL (0xE62711F0U) #define P_ARMREG_SEC_CTRL_PROT (0x00000001U) /* MIDR */ #define MIDR_CA57 (0x0D07U << MIDR_PN_SHIFT) #define MIDR_CA53 (0x0D03U << MIDR_PN_SHIFT) /* for SuspendToRAM */ #define GPIO_BASE (0xE6050000U) #define GPIO_INDT1 (GPIO_BASE + 0x100CU) #define GPIO_INDT3 (GPIO_BASE + 0x300CU) #define GPIO_INDT6 (GPIO_BASE + 0x540CU) #define GPIO_OUTDT1 (GPIO_BASE + 0x1008U) #define GPIO_OUTDT3 (GPIO_BASE + 0x3008U) #define GPIO_OUTDT6 (GPIO_BASE + 0x5408U) #define RCAR_COLD_BOOT (0x00U) #define RCAR_WARM_BOOT (0x01U) #if PMIC_ROHM_BD9571 && RCAR_SYSTEM_RESET_KEEPON_DDR #define KEEP10_MAGIC (0x55U) #endif /* lossy registers */ #define LOSSY_PARAMS_BASE (0x47FD7000U) #define AXI_DCMPAREACRA0 (0xE6784100U) #define AXI_DCMPAREACRB0 (0xE6784104U) #define LOSSY_ENABLE (0x80000000U) #define LOSSY_DISABLE (0x00000000U) #define LOSSY_FMT_YUVPLANAR (0x00000000U) #define LOSSY_FMT_YUV422INTLV (0x20000000U) #define LOSSY_FMT_ARGB8888 (0x40000000U) #define LOSSY_ST_ADDR0 (0x54000000U) #define LOSSY_END_ADDR0 (0x57000000U) #define LOSSY_FMT0 LOSSY_FMT_YUVPLANAR #define LOSSY_ENA_DIS0 LOSSY_ENABLE #define LOSSY_ST_ADDR1 0x0U #define LOSSY_END_ADDR1 0x0U #define LOSSY_FMT1 LOSSY_FMT_ARGB8888 #define LOSSY_ENA_DIS1 LOSSY_DISABLE #define LOSSY_ST_ADDR2 0x0U #define LOSSY_END_ADDR2 0x0U #define LOSSY_FMT2 LOSSY_FMT_YUV422INTLV #define LOSSY_ENA_DIS2 LOSSY_DISABLE #endif /* RCAR_DEF_H */ trusted-firmware-a-2.2/plat/renesas/rcar/include/rcar_private.h000066400000000000000000000064261355360272700247250ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RCAR_PRIVATE_H #define RCAR_PRIVATE_H #include #include #include #include typedef volatile struct mailbox { unsigned long value __aligned(CACHE_WRITEBACK_GRANULE); } mailbox_t; /* * This structure represents the superset of information that is passed to * BL31 e.g. while passing control to it from BL2 which is bl31_params * and bl31_plat_params and its elements */ typedef struct bl2_to_bl31_params_mem { image_info_t bl32_image_info; image_info_t bl33_image_info; entry_point_info_t bl33_ep_info; entry_point_info_t bl32_ep_info; } bl2_to_bl31_params_mem_t; #if USE_COHERENT_MEM #define RCAR_INSTANTIATE_LOCK DEFINE_BAKERY_LOCK(rcar_lock); #define rcar_lock_init() bakery_lock_init(&rcar_lock) #define rcar_lock_get() bakery_lock_get(&rcar_lock) #define rcar_lock_release() bakery_lock_release(&rcar_lock) #else /* * Constants to specify how many bakery locks this platform implements. These * are used if the platform chooses not to use coherent memory for bakery lock * data structures. */ #define RCAR_MAX_BAKERIES 2 #define RCAR_PWRC_BAKERY_ID 0 /* * Definition of structure which holds platform specific per-cpu data. Currently * it holds only the bakery lock information for each cpu. Constants to * specify how many bakeries this platform implements and bakery ids are * specified in rcar_def.h */ typedef struct rcar_cpu_data { bakery_info_t pcpu_bakery_info[RCAR_MAX_BAKERIES]; } rcar_cpu_data_t; #define RCAR_CPU_DATA_LOCK_OFFSET \ __builtin_offsetof(rcar_cpu_data_t, pcpu_bakery_info) /* * Helper macros for bakery lock api when using the above rcar_cpu_data_t for * bakery lock data structures. It assumes that the bakery_info is at the * beginning of the platform specific per-cpu data. */ #define rcar_lock_init(_lock_arg) #define rcar_lock_get(_lock_arg) \ bakery_lock_get(_lock_arg, \ CPU_DATA_PLAT_PCPU_OFFSET + RCAR_CPU_DATA_LOCK_OFFSET) #define rcar_lock_release(_lock_arg) \ bakery_lock_release(_lock_arg, \ CPU_DATA_PLAT_PCPU_OFFSET + RCAR_CPU_DATA_LOCK_OFFSET) /* Ensure that the size of the RCAR specific per-cpu data structure and the size * of the memory allocated in generic per-cpu data for the platform are the same */ CASSERT(PLAT_PCPU_DATA_SIZE == sizeof(rcar_cpu_data_t), rcar_pcpu_data_size_mismatch); #endif /* * Function and variable prototypes */ void rcar_configure_mmu_el3(unsigned long total_base, unsigned long total_size, unsigned long ro_start, unsigned long ro_limit #if USE_COHERENT_MEM , unsigned long coh_start, unsigned long coh_limit #endif ); void rcar_setup_topology(void); void rcar_cci_disable(void); void rcar_cci_enable(void); void rcar_cci_init(void); void plat_invalidate_icache(void); void plat_cci_disable(void); void plat_cci_enable(void); void plat_cci_init(void); void mstpcr_write(uint32_t mstpcr, uint32_t mstpsr, uint32_t target_bit); void cpg_write(uintptr_t regadr, uint32_t regval); void rcar_console_boot_init(void); void rcar_console_boot_end(void); void rcar_console_runtime_init(void); void rcar_console_runtime_end(void); #endif /* RCAR_PRIVATE_H */ trusted-firmware-a-2.2/plat/renesas/rcar/include/rcar_version.h000066400000000000000000000005761355360272700247400ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RCAR_VERSION_H #define RCAR_VERSION_H #include #define VERSION_OF_RENESAS "2.0.4" #define VERSION_OF_RENESAS_MAXLEN (128) extern const uint8_t version_of_renesas[VERSION_OF_RENESAS_MAXLEN]; #endif /* RCAR_VERSION_H */ trusted-firmware-a-2.2/plat/renesas/rcar/include/registers/000077500000000000000000000000001355360272700240725ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/renesas/rcar/include/registers/axi_registers.h000066400000000000000000000222311355360272700271130ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef AXI_REGISTERS_H #define AXI_REGISTERS_H /* AXI registers */ /* AXI base address */ #define AXI_BASE (0xE6780000U) /* address split */ /* AXI address split control 0 */ #define AXI_ADSPLCR0 (AXI_BASE + 0x4008U) /* AXI address split control 1 */ #define AXI_ADSPLCR1 (AXI_BASE + 0x400CU) /* AXI address split control 2 */ #define AXI_ADSPLCR2 (AXI_BASE + 0x4010U) /* AXI address split control 3 */ #define AXI_ADSPLCR3 (AXI_BASE + 0x4014U) /* functional safety */ /* AXI functional safety control */ #define AXI_FUSACR (AXI_BASE + 0x4020U) /* decompression */ /* AXI decompression area configuration A0 */ #define AXI_DCMPAREACRA0 (AXI_BASE + 0x4100U) /* AXI decompression area configuration B0 */ #define AXI_DCMPAREACRB0 (AXI_BASE + 0x4104U) /* AXI decompression area configuration A1 */ #define AXI_DCMPAREACRA1 (AXI_BASE + 0x4108U) /* AXI decompression area configuration B1 */ #define AXI_DCMPAREACRB1 (AXI_BASE + 0x410CU) /* AXI decompression area configuration A2 */ #define AXI_DCMPAREACRA2 (AXI_BASE + 0x4110U) /* AXI decompression area configuration B2 */ #define AXI_DCMPAREACRB2 (AXI_BASE + 0x4114U) /* AXI decompression area configuration A3 */ #define AXI_DCMPAREACRA3 (AXI_BASE + 0x4118U) /* AXI decompression area configuration B3 */ #define AXI_DCMPAREACRB3 (AXI_BASE + 0x411CU) /* AXI decompression area configuration A4 */ #define AXI_DCMPAREACRA4 (AXI_BASE + 0x4120U) /* AXI decompression area configuration B4 */ #define AXI_DCMPAREACRB4 (AXI_BASE + 0x4124U) /* AXI decompression area configuration A5 */ #define AXI_DCMPAREACRA5 (AXI_BASE + 0x4128U) /* AXI decompression area configuration B5 */ #define AXI_DCMPAREACRB5 (AXI_BASE + 0x412CU) /* AXI decompression area configuration A6 */ #define AXI_DCMPAREACRA6 (AXI_BASE + 0x4130U) /* AXI decompression area configuration B6 */ #define AXI_DCMPAREACRB6 (AXI_BASE + 0x4134U) /* AXI decompression area configuration A7 */ #define AXI_DCMPAREACRA7 (AXI_BASE + 0x4138U) /* AXI decompression area configuration B7 */ #define AXI_DCMPAREACRB7 (AXI_BASE + 0x413CU) /* AXI decompression area configuration A8 */ #define AXI_DCMPAREACRA8 (AXI_BASE + 0x4140U) /* AXI decompression area configuration B8 */ #define AXI_DCMPAREACRB8 (AXI_BASE + 0x4144U) /* AXI decompression area configuration A9 */ #define AXI_DCMPAREACRA9 (AXI_BASE + 0x4148U) /* AXI decompression area configuration B9 */ #define AXI_DCMPAREACRB9 (AXI_BASE + 0x414CU) /* AXI decompression area configuration A10 */ #define AXI_DCMPAREACRA10 (AXI_BASE + 0x4150U) /* AXI decompression area configuration B10 */ #define AXI_DCMPAREACRB10 (AXI_BASE + 0x4154U) /* AXI decompression area configuration A11 */ #define AXI_DCMPAREACRA11 (AXI_BASE + 0x4158U) /* AXI decompression area configuration B11 */ #define AXI_DCMPAREACRB11 (AXI_BASE + 0x415CU) /* AXI decompression area configuration A12 */ #define AXI_DCMPAREACRA12 (AXI_BASE + 0x4160U) /* AXI decompression area configuration B12 */ #define AXI_DCMPAREACRB12 (AXI_BASE + 0x4164U) /* AXI decompression area configuration A13 */ #define AXI_DCMPAREACRA13 (AXI_BASE + 0x4168U) /* AXI decompression area configuration B13 */ #define AXI_DCMPAREACRB13 (AXI_BASE + 0x416CU) /* AXI decompression area configuration A14 */ #define AXI_DCMPAREACRA14 (AXI_BASE + 0x4170U) /* AXI decompression area configuration B14 */ #define AXI_DCMPAREACRB14 (AXI_BASE + 0x4174U) /* AXI decompression area configuration A15 */ #define AXI_DCMPAREACRA15 (AXI_BASE + 0x4178U) /* AXI decompression area configuration B15 */ #define AXI_DCMPAREACRB15 (AXI_BASE + 0x417CU) /* AXI decompression shadow area configuration */ #define AXI_DCMPSHDWCR (AXI_BASE + 0x4280U) /* SDRAM protection */ /* AXI dram protected area division 0 */ #define AXI_DPTDIVCR0 (AXI_BASE + 0x4400U) /* AXI dram protected area division 1 */ #define AXI_DPTDIVCR1 (AXI_BASE + 0x4404U) /* AXI dram protected area division 2 */ #define AXI_DPTDIVCR2 (AXI_BASE + 0x4408U) /* AXI dram protected area division 3 */ #define AXI_DPTDIVCR3 (AXI_BASE + 0x440CU) /* AXI dram protected area division 4 */ #define AXI_DPTDIVCR4 (AXI_BASE + 0x4410U) /* AXI dram protected area division 5 */ #define AXI_DPTDIVCR5 (AXI_BASE + 0x4414U) /* AXI dram protected area division 6 */ #define AXI_DPTDIVCR6 (AXI_BASE + 0x4418U) /* AXI dram protected area division 7 */ #define AXI_DPTDIVCR7 (AXI_BASE + 0x441CU) /* AXI dram protected area division 8 */ #define AXI_DPTDIVCR8 (AXI_BASE + 0x4420U) /* AXI dram protected area division 9 */ #define AXI_DPTDIVCR9 (AXI_BASE + 0x4424U) /* AXI dram protected area division 10 */ #define AXI_DPTDIVCR10 (AXI_BASE + 0x4428U) /* AXI dram protected area division 11 */ #define AXI_DPTDIVCR11 (AXI_BASE + 0x442CU) /* AXI dram protected area division 12 */ #define AXI_DPTDIVCR12 (AXI_BASE + 0x4430U) /* AXI dram protected area division 13 */ #define AXI_DPTDIVCR13 (AXI_BASE + 0x4434U) /* AXI dram protected area division 14 */ #define AXI_DPTDIVCR14 (AXI_BASE + 0x4438U) /* AXI dram protected area setting 0 */ #define AXI_DPTCR0 (AXI_BASE + 0x4440U) /* AXI dram protected area setting 1 */ #define AXI_DPTCR1 (AXI_BASE + 0x4444U) /* AXI dram protected area setting 2 */ #define AXI_DPTCR2 (AXI_BASE + 0x4448U) /* AXI dram protected area setting 3 */ #define AXI_DPTCR3 (AXI_BASE + 0x444CU) /* AXI dram protected area setting 4 */ #define AXI_DPTCR4 (AXI_BASE + 0x4450U) /* AXI dram protected area setting 5 */ #define AXI_DPTCR5 (AXI_BASE + 0x4454U) /* AXI dram protected area setting 6 */ #define AXI_DPTCR6 (AXI_BASE + 0x4458U) /* AXI dram protected area setting 7 */ #define AXI_DPTCR7 (AXI_BASE + 0x445CU) /* AXI dram protected area setting 8 */ #define AXI_DPTCR8 (AXI_BASE + 0x4460U) /* AXI dram protected area setting 9 */ #define AXI_DPTCR9 (AXI_BASE + 0x4464U) /* AXI dram protected area setting 10 */ #define AXI_DPTCR10 (AXI_BASE + 0x4468U) /* AXI dram protected area setting 11 */ #define AXI_DPTCR11 (AXI_BASE + 0x446CU) /* AXI dram protected area setting 12 */ #define AXI_DPTCR12 (AXI_BASE + 0x4470U) /* AXI dram protected area setting 13 */ #define AXI_DPTCR13 (AXI_BASE + 0x4474U) /* AXI dram protected area setting 14 */ #define AXI_DPTCR14 (AXI_BASE + 0x4478U) /* AXI dram protected area setting 15 */ #define AXI_DPTCR15 (AXI_BASE + 0x447CU) /* SRAM protection */ /* AXI sram protected area division 0 */ #define AXI_SPTDIVCR0 (AXI_BASE + 0x4500U) /* AXI sram protected area division 1 */ #define AXI_SPTDIVCR1 (AXI_BASE + 0x4504U) /* AXI sram protected area division 2 */ #define AXI_SPTDIVCR2 (AXI_BASE + 0x4508U) /* AXI sram protected area division 3 */ #define AXI_SPTDIVCR3 (AXI_BASE + 0x450CU) /* AXI sram protected area division 4 */ #define AXI_SPTDIVCR4 (AXI_BASE + 0x4510U) /* AXI sram protected area division 5 */ #define AXI_SPTDIVCR5 (AXI_BASE + 0x4514U) /* AXI sram protected area division 6 */ #define AXI_SPTDIVCR6 (AXI_BASE + 0x4518U) /* AXI sram protected area division 7 */ #define AXI_SPTDIVCR7 (AXI_BASE + 0x451CU) /* AXI sram protected area division 8 */ #define AXI_SPTDIVCR8 (AXI_BASE + 0x4520U) /* AXI sram protected area division 9 */ #define AXI_SPTDIVCR9 (AXI_BASE + 0x4524U) /* AXI sram protected area division 10 */ #define AXI_SPTDIVCR10 (AXI_BASE + 0x4528U) /* AXI sram protected area division 11 */ #define AXI_SPTDIVCR11 (AXI_BASE + 0x452CU) /* AXI sram protected area division 12 */ #define AXI_SPTDIVCR12 (AXI_BASE + 0x4530U) /* AXI sram protected area division 13 */ #define AXI_SPTDIVCR13 (AXI_BASE + 0x4534U) /* AXI sram protected area division 14 */ #define AXI_SPTDIVCR14 (AXI_BASE + 0x4538U) /* AXI sram protected area setting 0 */ #define AXI_SPTCR0 (AXI_BASE + 0x4540U) /* AXI sram protected area setting 1 */ #define AXI_SPTCR1 (AXI_BASE + 0x4544U) /* AXI sram protected area setting 2 */ #define AXI_SPTCR2 (AXI_BASE + 0x4548U) /* AXI sram protected area setting 3 */ #define AXI_SPTCR3 (AXI_BASE + 0x454CU) /* AXI sram protected area setting 4 */ #define AXI_SPTCR4 (AXI_BASE + 0x4550U) /* AXI sram protected area setting 5 */ #define AXI_SPTCR5 (AXI_BASE + 0x4554U) /* AXI sram protected area setting 6 */ #define AXI_SPTCR6 (AXI_BASE + 0x4558U) /* AXI sram protected area setting 7 */ #define AXI_SPTCR7 (AXI_BASE + 0x455CU) /* AXI sram protected area setting 8 */ #define AXI_SPTCR8 (AXI_BASE + 0x4560U) /* AXI sram protected area setting 9 */ #define AXI_SPTCR9 (AXI_BASE + 0x4564U) /* AXI sram protected area setting 10 */ #define AXI_SPTCR10 (AXI_BASE + 0x4568U) /* AXI sram protected area setting 11 */ #define AXI_SPTCR11 (AXI_BASE + 0x456CU) /* AXI sram protected area setting 12 */ #define AXI_SPTCR12 (AXI_BASE + 0x4570U) /* AXI sram protected area setting 13 */ #define AXI_SPTCR13 (AXI_BASE + 0x4574U) /* AXI sram protected area setting 14 */ #define AXI_SPTCR14 (AXI_BASE + 0x4578U) /* AXI sram protected area setting 15 */ #define AXI_SPTCR15 (AXI_BASE + 0x457CU) /* EDC base address */ #define EDC_BASE (0xFF840000U) /* EDC edc enable */ #define EDC_EDCEN (EDC_BASE + 0x0010U) /* EDC edc status 0 */ #define EDC_EDCST0 (EDC_BASE + 0x0020U) /* EDC edc status 1 */ #define EDC_EDCST1 (EDC_BASE + 0x0024U) /* EDC edc interrupt enable 0 */ #define EDC_EDCINTEN0 (EDC_BASE + 0x0040U) /* EDC edc interrupt enable 1 */ #define EDC_EDCINTEN1 (EDC_BASE + 0x0044U) #endif /* AXI_REGISTERS_H */ trusted-firmware-a-2.2/plat/renesas/rcar/include/registers/cpg_registers.h000066400000000000000000000120121355360272700270770ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CPG_REGISTERS_H #define CPG_REGISTERS_H /* CPG base address */ #define CPG_BASE (0xE6150000U) /* CPG system module stop control 2 */ #define CPG_SMSTPCR2 (CPG_BASE + 0x0138U) /* CPG software reset 2 */ #define CPG_SRCR2 (CPG_BASE + 0x00B0U) /* CPG module stop status 2 */ #define CPG_MSTPSR2 (CPG_BASE + 0x0040U) /* CPG write protect */ #define CPG_CPGWPR (CPG_BASE + 0x0900U) /* CPG write protect control */ #define CPG_CPGWPCR (CPG_BASE + 0x0904U) /* CPG system module stop control 9 */ #define CPG_SMSTPCR9 (CPG_BASE + 0x0994U) /* CPG module stop status 9 */ #define CPG_MSTPSR9 (CPG_BASE + 0x09A4U) /* CPG (SECURITY) registers */ /* Secure Module Stop Control Register 0 */ #define SCMSTPCR0 (CPG_BASE + 0x0B20U) /* Secure Module Stop Control Register 1 */ #define SCMSTPCR1 (CPG_BASE + 0x0B24U) /* Secure Module Stop Control Register 2 */ #define SCMSTPCR2 (CPG_BASE + 0x0B28U) /* Secure Module Stop Control Register 3 */ #define SCMSTPCR3 (CPG_BASE + 0x0B2CU) /* Secure Module Stop Control Register 4 */ #define SCMSTPCR4 (CPG_BASE + 0x0B30U) /* Secure Module Stop Control Register 5 */ #define SCMSTPCR5 (CPG_BASE + 0x0B34U) /* Secure Module Stop Control Register 6 */ #define SCMSTPCR6 (CPG_BASE + 0x0B38U) /* Secure Module Stop Control Register 7 */ #define SCMSTPCR7 (CPG_BASE + 0x0B3CU) /* Secure Module Stop Control Register 8 */ #define SCMSTPCR8 (CPG_BASE + 0x0B40U) /* Secure Module Stop Control Register 9 */ #define SCMSTPCR9 (CPG_BASE + 0x0B44U) /* Secure Module Stop Control Register 10 */ #define SCMSTPCR10 (CPG_BASE + 0x0B48U) /* Secure Module Stop Control Register 11 */ #define SCMSTPCR11 (CPG_BASE + 0x0B4CU) /* CPG (SECURITY) registers */ /* Secure Software Reset Access Enable Control Register 0 */ #define SCSRSTECR0 (CPG_BASE + 0x0B80U) /* Secure Software Reset Access Enable Control Register 1 */ #define SCSRSTECR1 (CPG_BASE + 0x0B84U) /* Secure Software Reset Access Enable Control Register 2 */ #define SCSRSTECR2 (CPG_BASE + 0x0B88U) /* Secure Software Reset Access Enable Control Register 3 */ #define SCSRSTECR3 (CPG_BASE + 0x0B8CU) /* Secure Software Reset Access Enable Control Register 4 */ #define SCSRSTECR4 (CPG_BASE + 0x0B90U) /* Secure Software Reset Access Enable Control Register 5 */ #define SCSRSTECR5 (CPG_BASE + 0x0B94U) /* Secure Software Reset Access Enable Control Register 6 */ #define SCSRSTECR6 (CPG_BASE + 0x0B98U) /* Secure Software Reset Access Enable Control Register 7 */ #define SCSRSTECR7 (CPG_BASE + 0x0B9CU) /* Secure Software Reset Access Enable Control Register 8 */ #define SCSRSTECR8 (CPG_BASE + 0x0BA0U) /* Secure Software Reset Access Enable Control Register 9 */ #define SCSRSTECR9 (CPG_BASE + 0x0BA4U) /* Secure Software Reset Access Enable Control Register 10 */ #define SCSRSTECR10 (CPG_BASE + 0x0BA8U) /* Secure Software Reset Access Enable Control Register 11 */ #define SCSRSTECR11 (CPG_BASE + 0x0BACU) /* CPG (REALTIME) registers */ /* Realtime Module Stop Control Register 0 */ #define RMSTPCR0 (CPG_BASE + 0x0110U) /* Realtime Module Stop Control Register 1 */ #define RMSTPCR1 (CPG_BASE + 0x0114U) /* Realtime Module Stop Control Register 2 */ #define RMSTPCR2 (CPG_BASE + 0x0118U) /* Realtime Module Stop Control Register 3 */ #define RMSTPCR3 (CPG_BASE + 0x011CU) /* Realtime Module Stop Control Register 4 */ #define RMSTPCR4 (CPG_BASE + 0x0120U) /* Realtime Module Stop Control Register 5 */ #define RMSTPCR5 (CPG_BASE + 0x0124U) /* Realtime Module Stop Control Register 6 */ #define RMSTPCR6 (CPG_BASE + 0x0128U) /* Realtime Module Stop Control Register 7 */ #define RMSTPCR7 (CPG_BASE + 0x012CU) /* Realtime Module Stop Control Register 8 */ #define RMSTPCR8 (CPG_BASE + 0x0980U) /* Realtime Module Stop Control Register 9 */ #define RMSTPCR9 (CPG_BASE + 0x0984U) /* Realtime Module Stop Control Register 10 */ #define RMSTPCR10 (CPG_BASE + 0x0988U) /* Realtime Module Stop Control Register 11 */ #define RMSTPCR11 (CPG_BASE + 0x098CU) /* CPG (SYSTEM) registers */ /* System Module Stop Control Register 0 */ #define SMSTPCR0 (CPG_BASE + 0x0130U) /* System Module Stop Control Register 1 */ #define SMSTPCR1 (CPG_BASE + 0x0134U) /* System Module Stop Control Register 2 */ #define SMSTPCR2 (CPG_BASE + 0x0138U) /* System Module Stop Control Register 3 */ #define SMSTPCR3 (CPG_BASE + 0x013CU) /* System Module Stop Control Register 4 */ #define SMSTPCR4 (CPG_BASE + 0x0140U) /* System Module Stop Control Register 5 */ #define SMSTPCR5 (CPG_BASE + 0x0144U) /* System Module Stop Control Register 6 */ #define SMSTPCR6 (CPG_BASE + 0x0148U) /* System Module Stop Control Register 7 */ #define SMSTPCR7 (CPG_BASE + 0x014CU) /* System Module Stop Control Register 8 */ #define SMSTPCR8 (CPG_BASE + 0x0990U) /* System Module Stop Control Register 9 */ #define SMSTPCR9 (CPG_BASE + 0x0994U) /* System Module Stop Control Register 10 */ #define SMSTPCR10 (CPG_BASE + 0x0998U) /* System Module Stop Control Register 11 */ #define SMSTPCR11 (CPG_BASE + 0x099CU) #endif /* CPG_REGISTERS_H */ trusted-firmware-a-2.2/plat/renesas/rcar/include/registers/lifec_registers.h000066400000000000000000000147761355360272700274330ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef LIFEC_REGISTERS_H #define LIFEC_REGISTERS_H #define LIFEC_SEC_BASE (0xE6110000U) #define SEC_SRC (LIFEC_SEC_BASE + 0x0008U) #define SEC_SEL0 (LIFEC_SEC_BASE + 0x0030U) #define SEC_SEL1 (LIFEC_SEC_BASE + 0x0034U) #define SEC_SEL2 (LIFEC_SEC_BASE + 0x0038U) #define SEC_SEL3 (LIFEC_SEC_BASE + 0x003CU) #define SEC_SEL4 (LIFEC_SEC_BASE + 0x0058U) #define SEC_SEL5 (LIFEC_SEC_BASE + 0x005CU) #define SEC_SEL6 (LIFEC_SEC_BASE + 0x0060U) #define SEC_SEL7 (LIFEC_SEC_BASE + 0x0064U) #define SEC_SEL8 (LIFEC_SEC_BASE + 0x0068U) #define SEC_SEL9 (LIFEC_SEC_BASE + 0x006CU) #define SEC_SEL10 (LIFEC_SEC_BASE + 0x0070U) #define SEC_SEL11 (LIFEC_SEC_BASE + 0x0074U) #define SEC_SEL12 (LIFEC_SEC_BASE + 0x0078U) #define SEC_SEL13 (LIFEC_SEC_BASE + 0x007CU) #define SEC_SEL14 (LIFEC_SEC_BASE + 0x0080U) #define SEC_SEL15 (LIFEC_SEC_BASE + 0x0084U) #define SEC_GRP0CR0 (LIFEC_SEC_BASE + 0x0138U) #define SEC_GRP1CR0 (LIFEC_SEC_BASE + 0x013CU) #define SEC_GRP0CR1 (LIFEC_SEC_BASE + 0x0140U) #define SEC_GRP1CR1 (LIFEC_SEC_BASE + 0x0144U) #define SEC_GRP0CR2 (LIFEC_SEC_BASE + 0x0148U) #define SEC_GRP1CR2 (LIFEC_SEC_BASE + 0x014CU) #define SEC_GRP0CR3 (LIFEC_SEC_BASE + 0x0150U) #define SEC_GRP1CR3 (LIFEC_SEC_BASE + 0x0154U) #define SEC_GRP0COND0 (LIFEC_SEC_BASE + 0x0158U) #define SEC_GRP1COND0 (LIFEC_SEC_BASE + 0x015CU) #define SEC_GRP0COND1 (LIFEC_SEC_BASE + 0x0160U) #define SEC_GRP1COND1 (LIFEC_SEC_BASE + 0x0164U) #define SEC_GRP0COND2 (LIFEC_SEC_BASE + 0x0168U) #define SEC_GRP1COND2 (LIFEC_SEC_BASE + 0x016CU) #define SEC_GRP0COND3 (LIFEC_SEC_BASE + 0x0170U) #define SEC_GRP1COND3 (LIFEC_SEC_BASE + 0x0174U) #define SEC_GRP0COND4 (LIFEC_SEC_BASE + 0x0178U) #define SEC_GRP1COND4 (LIFEC_SEC_BASE + 0x017CU) #define SEC_GRP0COND5 (LIFEC_SEC_BASE + 0x0180U) #define SEC_GRP1COND5 (LIFEC_SEC_BASE + 0x0184U) #define SEC_GRP0COND6 (LIFEC_SEC_BASE + 0x0188U) #define SEC_GRP1COND6 (LIFEC_SEC_BASE + 0x018CU) #define SEC_GRP0COND7 (LIFEC_SEC_BASE + 0x0190U) #define SEC_GRP1COND7 (LIFEC_SEC_BASE + 0x0194U) #define SEC_GRP0COND8 (LIFEC_SEC_BASE + 0x0198U) #define SEC_GRP1COND8 (LIFEC_SEC_BASE + 0x019CU) #define SEC_GRP0COND9 (LIFEC_SEC_BASE + 0x01A0U) #define SEC_GRP1COND9 (LIFEC_SEC_BASE + 0x01A4U) #define SEC_GRP0COND10 (LIFEC_SEC_BASE + 0x01A8U) #define SEC_GRP1COND10 (LIFEC_SEC_BASE + 0x01ACU) #define SEC_GRP0COND11 (LIFEC_SEC_BASE + 0x01B0U) #define SEC_GRP1COND11 (LIFEC_SEC_BASE + 0x01B4U) #define SEC_GRP0COND12 (LIFEC_SEC_BASE + 0x01B8U) #define SEC_GRP1COND12 (LIFEC_SEC_BASE + 0x01BCU) #define SEC_GRP0COND13 (LIFEC_SEC_BASE + 0x01C0U) #define SEC_GRP1COND13 (LIFEC_SEC_BASE + 0x01C4U) #define SEC_GRP0COND14 (LIFEC_SEC_BASE + 0x01C8U) #define SEC_GRP1COND14 (LIFEC_SEC_BASE + 0x01CCU) #define SEC_GRP0COND15 (LIFEC_SEC_BASE + 0x01D0U) #define SEC_GRP1COND15 (LIFEC_SEC_BASE + 0x01D4U) #define SEC_READONLY0 (LIFEC_SEC_BASE + 0x01D8U) #define SEC_READONLY1 (LIFEC_SEC_BASE + 0x01DCU) #define SEC_READONLY2 (LIFEC_SEC_BASE + 0x01E0U) #define SEC_READONLY3 (LIFEC_SEC_BASE + 0x01E4U) #define SEC_READONLY4 (LIFEC_SEC_BASE + 0x01E8U) #define SEC_READONLY5 (LIFEC_SEC_BASE + 0x01ECU) #define SEC_READONLY6 (LIFEC_SEC_BASE + 0x01F0U) #define SEC_READONLY7 (LIFEC_SEC_BASE + 0x01F4U) #define SEC_READONLY8 (LIFEC_SEC_BASE + 0x01F8U) #define SEC_READONLY9 (LIFEC_SEC_BASE + 0x01FCU) #define SEC_READONLY10 (LIFEC_SEC_BASE + 0x0200U) #define SEC_READONLY11 (LIFEC_SEC_BASE + 0x0204U) #define SEC_READONLY12 (LIFEC_SEC_BASE + 0x0208U) #define SEC_READONLY13 (LIFEC_SEC_BASE + 0x020CU) #define SEC_READONLY14 (LIFEC_SEC_BASE + 0x0210U) #define SEC_READONLY15 (LIFEC_SEC_BASE + 0x0214U) #define LIFEC_SAFE_BASE (0xE6120000U) #define SAFE_GRP0CR0 (LIFEC_SAFE_BASE + 0x0138U) #define SAFE_GRP1CR0 (LIFEC_SAFE_BASE + 0x013CU) #define SAFE_GRP0CR1 (LIFEC_SAFE_BASE + 0x0140U) #define SAFE_GRP1CR1 (LIFEC_SAFE_BASE + 0x0144U) #define SAFE_GRP0CR2 (LIFEC_SAFE_BASE + 0x0148U) #define SAFE_GRP1CR2 (LIFEC_SAFE_BASE + 0x014CU) #define SAFE_GRP0CR3 (LIFEC_SAFE_BASE + 0x0150U) #define SAFE_GRP1CR3 (LIFEC_SAFE_BASE + 0x0154U) #define SAFE_GRP0COND0 (LIFEC_SAFE_BASE + 0x0158U) #define SAFE_GRP1COND0 (LIFEC_SAFE_BASE + 0x015CU) #define SAFE_GRP0COND1 (LIFEC_SAFE_BASE + 0x0160U) #define SAFE_GRP1COND1 (LIFEC_SAFE_BASE + 0x0164U) #define SAFE_GRP0COND2 (LIFEC_SAFE_BASE + 0x0168U) #define SAFE_GRP1COND2 (LIFEC_SAFE_BASE + 0x016CU) #define SAFE_GRP0COND3 (LIFEC_SAFE_BASE + 0x0170U) #define SAFE_GRP1COND3 (LIFEC_SAFE_BASE + 0x0174U) #define SAFE_GRP0COND4 (LIFEC_SAFE_BASE + 0x0178U) #define SAFE_GRP1COND4 (LIFEC_SAFE_BASE + 0x017CU) #define SAFE_GRP0COND5 (LIFEC_SAFE_BASE + 0x0180U) #define SAFE_GRP1COND5 (LIFEC_SAFE_BASE + 0x0184U) #define SAFE_GRP0COND6 (LIFEC_SAFE_BASE + 0x0188U) #define SAFE_GRP1COND6 (LIFEC_SAFE_BASE + 0x018CU) #define SAFE_GRP0COND7 (LIFEC_SAFE_BASE + 0x0190U) #define SAFE_GRP1COND7 (LIFEC_SAFE_BASE + 0x0194U) #define SAFE_GRP0COND8 (LIFEC_SAFE_BASE + 0x0198U) #define SAFE_GRP1COND8 (LIFEC_SAFE_BASE + 0x019CU) #define SAFE_GRP0COND9 (LIFEC_SAFE_BASE + 0x01A0U) #define SAFE_GRP1COND9 (LIFEC_SAFE_BASE + 0x01A4U) #define SAFE_GRP0COND10 (LIFEC_SAFE_BASE + 0x01A8U) #define SAFE_GRP1COND10 (LIFEC_SAFE_BASE + 0x01ACU) #define SAFE_GRP0COND11 (LIFEC_SAFE_BASE + 0x01B0U) #define SAFE_GRP1COND11 (LIFEC_SAFE_BASE + 0x01B4U) #define SAFE_GRP0COND12 (LIFEC_SAFE_BASE + 0x01B8U) #define SAFE_GRP1COND12 (LIFEC_SAFE_BASE + 0x01BCU) #define SAFE_GRP0COND13 (LIFEC_SAFE_BASE + 0x01C0U) #define SAFE_GRP1COND13 (LIFEC_SAFE_BASE + 0x01C4U) #define SAFE_GRP0COND14 (LIFEC_SAFE_BASE + 0x01C8U) #define SAFE_GRP1COND14 (LIFEC_SAFE_BASE + 0x01CCU) #define SAFE_GRP0COND15 (LIFEC_SAFE_BASE + 0x01D0U) #define SAFE_GRP1COND15 (LIFEC_SAFE_BASE + 0x01D4U) #define SAFE_READONLY0 (LIFEC_SAFE_BASE + 0x01D8U) #define SAFE_READONLY1 (LIFEC_SAFE_BASE + 0x01DCU) #define SAFE_READONLY2 (LIFEC_SAFE_BASE + 0x01E0U) #define SAFE_READONLY3 (LIFEC_SAFE_BASE + 0x01E4U) #define SAFE_READONLY4 (LIFEC_SAFE_BASE + 0x01E8U) #define SAFE_READONLY5 (LIFEC_SAFE_BASE + 0x01ECU) #define SAFE_READONLY6 (LIFEC_SAFE_BASE + 0x01F0U) #define SAFE_READONLY7 (LIFEC_SAFE_BASE + 0x01F4U) #define SAFE_READONLY8 (LIFEC_SAFE_BASE + 0x01F8U) #define SAFE_READONLY9 (LIFEC_SAFE_BASE + 0x01FCU) #define SAFE_READONLY10 (LIFEC_SAFE_BASE + 0x0200U) #define SAFE_READONLY11 (LIFEC_SAFE_BASE + 0x0204U) #define SAFE_READONLY12 (LIFEC_SAFE_BASE + 0x0208U) #define SAFE_READONLY13 (LIFEC_SAFE_BASE + 0x020CU) #define SAFE_READONLY14 (LIFEC_SAFE_BASE + 0x0210U) #define SAFE_READONLY15 (LIFEC_SAFE_BASE + 0x0214U) #endif /* LIFEC_REGISTERS_H */ trusted-firmware-a-2.2/plat/renesas/rcar/plat_image_load.c000066400000000000000000000023701355360272700237070ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include extern void bl2_plat_flush_bl31_params(void); /******************************************************************************* * This function flushes the data structures so that they are visible * in memory for the next BL image. ******************************************************************************/ void plat_flush_next_bl_params(void) { #if IMAGE_BL2 bl2_plat_flush_bl31_params(); #endif } /******************************************************************************* * This function returns the list of loadable images. ******************************************************************************/ bl_load_info_t *plat_get_bl_image_load_info(void) { return get_bl_load_info_from_mem_params_desc(); } /******************************************************************************* * This function returns the list of executable images. ******************************************************************************/ bl_params_t *plat_get_next_bl_params(void) { return get_next_bl_params_from_mem_params_desc(); } trusted-firmware-a-2.2/plat/renesas/rcar/plat_pm.c000066400000000000000000000165351355360272700222520ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include "iic_dvfs.h" #include "pwrc.h" #include "rcar_def.h" #include "rcar_private.h" #include "ulcb_cpld.h" #define DVFS_SET_VID_0V (0x00) #define P_ALL_OFF (0x80) #define KEEPON_DDR1C (0x08) #define KEEPON_DDR0C (0x04) #define KEEPON_DDR1 (0x02) #define KEEPON_DDR0 (0x01) #define SYSTEM_PWR_STATE(s) ((s)->pwr_domain_state[PLAT_MAX_PWR_LVL]) #define CLUSTER_PWR_STATE(s) ((s)->pwr_domain_state[MPIDR_AFFLVL1]) #define CORE_PWR_STATE(s) ((s)->pwr_domain_state[MPIDR_AFFLVL0]) extern void rcar_pwrc_restore_generic_timer(uint64_t *stack); extern void plat_rcar_gic_driver_init(void); extern void plat_rcar_gic_init(void); extern u_register_t rcar_boot_mpidr; static uintptr_t rcar_sec_entrypoint; static void rcar_program_mailbox(uint64_t mpidr, uint64_t address) { mailbox_t *rcar_mboxes = (mailbox_t *) MBOX_BASE; uint64_t linear_id = plat_core_pos_by_mpidr(mpidr); unsigned long range; rcar_mboxes[linear_id].value = address; range = (unsigned long)&rcar_mboxes[linear_id]; flush_dcache_range(range, sizeof(range)); } static void rcar_cpu_standby(plat_local_state_t cpu_state) { uint32_t scr_el3 = read_scr_el3(); write_scr_el3(scr_el3 | SCR_IRQ_BIT); dsb(); wfi(); write_scr_el3(scr_el3); } static int rcar_pwr_domain_on(u_register_t mpidr) { rcar_program_mailbox(mpidr, rcar_sec_entrypoint); rcar_pwrc_cpuon(mpidr); return PSCI_E_SUCCESS; } static void rcar_pwr_domain_on_finish(const psci_power_state_t *target_state) { uint32_t cluster_type = rcar_pwrc_get_cluster(); unsigned long mpidr = read_mpidr_el1(); if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) if (cluster_type == RCAR_CLUSTER_A53A57) plat_cci_enable(); rcar_pwrc_disable_interrupt_wakeup(mpidr); rcar_program_mailbox(mpidr, 0); gicv2_cpuif_enable(); gicv2_pcpu_distif_init(); } static void rcar_pwr_domain_off(const psci_power_state_t *target_state) { #if RCAR_LSI != RCAR_D3 uint32_t cluster_type = rcar_pwrc_get_cluster(); #endif unsigned long mpidr = read_mpidr_el1(); gicv2_cpuif_disable(); rcar_pwrc_cpuoff(mpidr); #if RCAR_LSI != RCAR_D3 if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { if (cluster_type == RCAR_CLUSTER_A53A57) plat_cci_disable(); rcar_pwrc_clusteroff(mpidr); } #endif } static void rcar_pwr_domain_suspend(const psci_power_state_t *target_state) { uint32_t cluster_type = rcar_pwrc_get_cluster(); unsigned long mpidr = read_mpidr_el1(); if (CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) return; rcar_program_mailbox(mpidr, rcar_sec_entrypoint); rcar_pwrc_enable_interrupt_wakeup(mpidr); gicv2_cpuif_disable(); rcar_pwrc_cpuoff(mpidr); if (CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { if (cluster_type == RCAR_CLUSTER_A53A57) plat_cci_disable(); rcar_pwrc_clusteroff(mpidr); } #if RCAR_SYSTEM_SUSPEND if (SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) rcar_pwrc_suspend_to_ram(); #endif } static void rcar_pwr_domain_suspend_finish(const psci_power_state_t *target_state) { uint32_t cluster_type = rcar_pwrc_get_cluster(); if (SYSTEM_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) goto finish; plat_rcar_gic_driver_init(); plat_rcar_gic_init(); if (cluster_type == RCAR_CLUSTER_A53A57) plat_cci_init(); rcar_pwrc_restore_timer_state(); rcar_pwrc_setup(); rcar_pwrc_code_copy_to_system_ram(); #if RCAR_SYSTEM_SUSPEND rcar_pwrc_init_suspend_to_ram(); #endif finish: rcar_pwr_domain_on_finish(target_state); } static void __dead2 rcar_system_off(void) { #if PMIC_ROHM_BD9571 #if PMIC_LEVEL_MODE if (rcar_iic_dvfs_send(PMIC, DVFS_SET_VID, DVFS_SET_VID_0V)) ERROR("BL3-1:Failed the SYSTEM-OFF.\n"); #else if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF)) ERROR("BL3-1:Failed the SYSTEM-RESET.\n"); #endif #else uint64_t cpu = read_mpidr_el1() & 0x0000ffff; int32_t rtn_on; rtn_on = rcar_pwrc_cpu_on_check(cpu); if (cpu == rcar_boot_mpidr) panic(); if (rtn_on) panic(); rcar_pwrc_cpuoff(cpu); rcar_pwrc_clusteroff(cpu); #endif /* PMIC_ROHM_BD9571 */ wfi(); ERROR("RCAR System Off: operation not handled.\n"); panic(); } static void __dead2 rcar_system_reset(void) { #if PMIC_ROHM_BD9571 #if PMIC_LEVEL_MODE #if RCAR_SYSTEM_RESET_KEEPON_DDR uint8_t mode; int32_t error; error = rcar_iic_dvfs_send(PMIC, REG_KEEP10, KEEP10_MAGIC); if (error) { ERROR("Failed send KEEP10 magic ret=%d \n", error); goto done; } error = rcar_iic_dvfs_receive(PMIC, BKUP_MODE_CNT, &mode); if (error) { ERROR("Failed recieve BKUP_Mode_Cnt ret=%d \n", error); goto done; } mode |= KEEPON_DDR1C | KEEPON_DDR0C | KEEPON_DDR1 | KEEPON_DDR0; error = rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, mode); if (error) { ERROR("Failed send KEEPON_DDRx ret=%d \n", error); goto done; } rcar_pwrc_set_suspend_to_ram(); done: #else if (rcar_iic_dvfs_send(PMIC, BKUP_MODE_CNT, P_ALL_OFF)) ERROR("BL3-1:Failed the SYSTEM-RESET.\n"); #endif #else #if (RCAR_GEN3_ULCB == 1) rcar_cpld_reset_cpu(); #endif #endif #else rcar_pwrc_system_reset(); #endif wfi(); ERROR("RCAR System Reset: operation not handled.\n"); panic(); } static int rcar_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { unsigned int pwr_lvl = psci_get_pstate_pwrlvl(power_state); unsigned int pstate = psci_get_pstate_type(power_state); uint32_t i; if (pstate == PSTATE_TYPE_STANDBY) { if (pwr_lvl != MPIDR_AFFLVL0) return PSCI_E_INVALID_PARAMS; req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE; } else { for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++) req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; } if (psci_get_pstate_id(power_state)) return PSCI_E_INVALID_PARAMS; return PSCI_E_SUCCESS; } #if RCAR_SYSTEM_SUSPEND static void rcar_get_sys_suspend_power_state(psci_power_state_t *req_state) { unsigned long mpidr = read_mpidr_el1() & 0x0000ffffU; int i; if (mpidr != rcar_boot_mpidr) goto deny; for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; return; deny: /* deny system suspend entry */ req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSCI_LOCAL_STATE_RUN; for (i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE; } #endif static const plat_psci_ops_t rcar_plat_psci_ops = { .cpu_standby = rcar_cpu_standby, .pwr_domain_on = rcar_pwr_domain_on, .pwr_domain_off = rcar_pwr_domain_off, .pwr_domain_suspend = rcar_pwr_domain_suspend, .pwr_domain_on_finish = rcar_pwr_domain_on_finish, .pwr_domain_suspend_finish = rcar_pwr_domain_suspend_finish, .system_off = rcar_system_off, .system_reset = rcar_system_reset, .validate_power_state = rcar_validate_power_state, #if RCAR_SYSTEM_SUSPEND .get_sys_suspend_power_state = rcar_get_sys_suspend_power_state, #endif }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { *psci_ops = &rcar_plat_psci_ops; rcar_sec_entrypoint = sec_entrypoint; #if RCAR_SYSTEM_SUSPEND rcar_pwrc_init_suspend_to_ram(); #endif return 0; } trusted-firmware-a-2.2/plat/renesas/rcar/plat_storage.c000066400000000000000000000231251355360272700232730ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "io_common.h" #include "io_rcar.h" #include "io_memdrv.h" #include "io_emmcdrv.h" #include "io_private.h" static uintptr_t emmcdrv_dev_handle; static uintptr_t memdrv_dev_handle; static uintptr_t rcar_dev_handle; static uintptr_t boot_io_drv_id; static const io_block_spec_t rcar_block_spec = { .offset = FLASH0_BASE, .length = FLASH0_SIZE }; static const io_block_spec_t bl2_file_spec = { .offset = BL2_IMAGE_ID, }; static const io_block_spec_t bl31_file_spec = { .offset = BL31_IMAGE_ID, }; static const io_block_spec_t bl32_file_spec = { .offset = BL32_IMAGE_ID, }; static const io_block_spec_t bl33_file_spec = { .offset = BL33_IMAGE_ID, }; static const io_block_spec_t bl332_file_spec = { .offset = BL332_IMAGE_ID, }; static const io_block_spec_t bl333_file_spec = { .offset = BL333_IMAGE_ID, }; static const io_block_spec_t bl334_file_spec = { .offset = BL334_IMAGE_ID, }; static const io_block_spec_t bl335_file_spec = { .offset = BL335_IMAGE_ID, }; static const io_block_spec_t bl336_file_spec = { .offset = BL336_IMAGE_ID, }; static const io_block_spec_t bl337_file_spec = { .offset = BL337_IMAGE_ID, }; static const io_block_spec_t bl338_file_spec = { .offset = BL338_IMAGE_ID, }; #if TRUSTED_BOARD_BOOT static const io_block_spec_t trusted_key_cert_file_spec = { .offset = TRUSTED_KEY_CERT_ID, }; static const io_block_spec_t bl31_key_cert_file_spec = { .offset = SOC_FW_KEY_CERT_ID, }; static const io_block_spec_t bl32_key_cert_file_spec = { .offset = TRUSTED_OS_FW_KEY_CERT_ID, }; static const io_block_spec_t bl33_key_cert_file_spec = { .offset = NON_TRUSTED_FW_KEY_CERT_ID, }; static const io_block_spec_t bl332_key_cert_file_spec = { .offset = BL332_KEY_CERT_ID, }; static const io_block_spec_t bl333_key_cert_file_spec = { .offset = BL333_KEY_CERT_ID, }; static const io_block_spec_t bl334_key_cert_file_spec = { .offset = BL334_KEY_CERT_ID, }; static const io_block_spec_t bl335_key_cert_file_spec = { .offset = BL335_KEY_CERT_ID, }; static const io_block_spec_t bl336_key_cert_file_spec = { .offset = BL336_KEY_CERT_ID, }; static const io_block_spec_t bl337_key_cert_file_spec = { .offset = BL337_KEY_CERT_ID, }; static const io_block_spec_t bl338_key_cert_file_spec = { .offset = BL338_KEY_CERT_ID, }; static const io_block_spec_t bl31_cert_file_spec = { .offset = SOC_FW_CONTENT_CERT_ID, }; static const io_block_spec_t bl32_cert_file_spec = { .offset = TRUSTED_OS_FW_CONTENT_CERT_ID, }; static const io_block_spec_t bl33_cert_file_spec = { .offset = NON_TRUSTED_FW_CONTENT_CERT_ID, }; static const io_block_spec_t bl332_cert_file_spec = { .offset = BL332_CERT_ID, }; static const io_block_spec_t bl333_cert_file_spec = { .offset = BL333_CERT_ID, }; static const io_block_spec_t bl334_cert_file_spec = { .offset = BL334_CERT_ID, }; static const io_block_spec_t bl335_cert_file_spec = { .offset = BL335_CERT_ID, }; static const io_block_spec_t bl336_cert_file_spec = { .offset = BL336_CERT_ID, }; static const io_block_spec_t bl337_cert_file_spec = { .offset = BL337_CERT_ID, }; static const io_block_spec_t bl338_cert_file_spec = { .offset = BL338_CERT_ID, }; #endif static int32_t open_emmcdrv(const uintptr_t spec); static int32_t open_memmap(const uintptr_t spec); static int32_t open_rcar(const uintptr_t spec); struct plat_io_policy { uintptr_t *dev_handle; uintptr_t image_spec; int32_t(*check) (const uintptr_t spec); }; static const struct plat_io_policy policies[] = { [FIP_IMAGE_ID] = { &memdrv_dev_handle, (uintptr_t) &rcar_block_spec, &open_memmap}, [BL2_IMAGE_ID] = { &rcar_dev_handle, (uintptr_t) &bl2_file_spec, &open_rcar}, [BL31_IMAGE_ID] = { &rcar_dev_handle, (uintptr_t) &bl31_file_spec, &open_rcar}, [BL32_IMAGE_ID] = { &rcar_dev_handle, (uintptr_t) &bl32_file_spec, &open_rcar}, [BL33_IMAGE_ID] = { &rcar_dev_handle, (uintptr_t) &bl33_file_spec, &open_rcar}, [BL332_IMAGE_ID] = { &rcar_dev_handle, (uintptr_t) &bl332_file_spec, &open_rcar}, [BL333_IMAGE_ID] = { &rcar_dev_handle, (uintptr_t) &bl333_file_spec, &open_rcar}, [BL334_IMAGE_ID] = { &rcar_dev_handle, (uintptr_t) &bl334_file_spec, &open_rcar}, [BL335_IMAGE_ID] = { &rcar_dev_handle, (uintptr_t) &bl335_file_spec, &open_rcar}, [BL336_IMAGE_ID] = { &rcar_dev_handle, (uintptr_t) &bl336_file_spec, &open_rcar}, [BL337_IMAGE_ID] = { &rcar_dev_handle, (uintptr_t) &bl337_file_spec, &open_rcar}, [BL338_IMAGE_ID] = { &rcar_dev_handle, (uintptr_t) &bl338_file_spec, &open_rcar}, #if TRUSTED_BOARD_BOOT [TRUSTED_KEY_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &trusted_key_cert_file_spec, &open_rcar}, [SOC_FW_KEY_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl31_key_cert_file_spec, &open_rcar}, [TRUSTED_OS_FW_KEY_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl32_key_cert_file_spec, &open_rcar}, [NON_TRUSTED_FW_KEY_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl33_key_cert_file_spec, &open_rcar}, [BL332_KEY_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl332_key_cert_file_spec, &open_rcar}, [BL333_KEY_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl333_key_cert_file_spec, &open_rcar}, [BL334_KEY_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl334_key_cert_file_spec, &open_rcar}, [BL335_KEY_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl335_key_cert_file_spec, &open_rcar}, [BL336_KEY_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl336_key_cert_file_spec, &open_rcar}, [BL337_KEY_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl337_key_cert_file_spec, &open_rcar}, [BL338_KEY_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl338_key_cert_file_spec, &open_rcar}, [SOC_FW_CONTENT_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl31_cert_file_spec, &open_rcar}, [TRUSTED_OS_FW_CONTENT_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl32_cert_file_spec, &open_rcar}, [NON_TRUSTED_FW_CONTENT_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl33_cert_file_spec, &open_rcar}, [BL332_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl332_cert_file_spec, &open_rcar}, [BL333_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl333_cert_file_spec, &open_rcar}, [BL334_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl334_cert_file_spec, &open_rcar}, [BL335_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl335_cert_file_spec, &open_rcar}, [BL336_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl336_cert_file_spec, &open_rcar}, [BL337_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl337_cert_file_spec, &open_rcar}, [BL338_CERT_ID] = { &rcar_dev_handle, (uintptr_t) &bl338_cert_file_spec, &open_rcar}, { #else { #endif 0, 0, 0} }; static io_drv_spec_t io_drv_spec_memdrv = { FLASH0_BASE, FLASH0_SIZE, 0, }; static io_drv_spec_t io_drv_spec_emmcdrv = { 0, 0, 0, }; static struct plat_io_policy drv_policies[] __attribute__ ((section(".data"))) = { /* FLASH_DEV_ID */ { &memdrv_dev_handle, (uintptr_t) &io_drv_spec_memdrv, &open_memmap,}, /* EMMC_DEV_ID */ { &emmcdrv_dev_handle, (uintptr_t) &io_drv_spec_emmcdrv, &open_emmcdrv,} }; static int32_t open_rcar(const uintptr_t spec) { return io_dev_init(rcar_dev_handle, boot_io_drv_id); } static int32_t open_memmap(const uintptr_t spec) { uintptr_t handle; int32_t result; result = io_dev_init(memdrv_dev_handle, 0); if (result != IO_SUCCESS) return result; result = io_open(memdrv_dev_handle, spec, &handle); if (result == IO_SUCCESS) io_close(handle); return result; } static int32_t open_emmcdrv(const uintptr_t spec) { return io_dev_init(emmcdrv_dev_handle, 0); } void rcar_io_setup(void) { const io_dev_connector_t *memmap; const io_dev_connector_t *rcar; boot_io_drv_id = FLASH_DEV_ID; rcar_register_io_dev(&rcar); rcar_register_io_dev_memdrv(&memmap); io_dev_open(rcar, 0, &rcar_dev_handle); io_dev_open(memmap, 0, &memdrv_dev_handle); } void rcar_io_emmc_setup(void) { const io_dev_connector_t *rcar; const io_dev_connector_t *emmc; boot_io_drv_id = EMMC_DEV_ID; rcar_register_io_dev(&rcar); rcar_register_io_dev_emmcdrv(&emmc); io_dev_open(rcar, 0, &rcar_dev_handle); io_dev_open(emmc, 0, &emmcdrv_dev_handle); } int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, uintptr_t *image_spec) { const struct plat_io_policy *policy; int result; policy = &policies[image_id]; result = policy->check(policy->image_spec); if (result != IO_SUCCESS) return result; *image_spec = policy->image_spec; *dev_handle = *(policy->dev_handle); return IO_SUCCESS; } int32_t plat_get_drv_source(uint32_t io_drv_id, uintptr_t *dev_handle, uintptr_t *image_spec) { const struct plat_io_policy *policy; int32_t result; policy = &drv_policies[io_drv_id]; result = policy->check(policy->image_spec); if (result != IO_SUCCESS) return result; *image_spec = policy->image_spec; *dev_handle = *(policy->dev_handle); return IO_SUCCESS; } trusted-firmware-a-2.2/plat/renesas/rcar/plat_topology.c000066400000000000000000000020321355360272700234750ustar00rootroot00000000000000/* * Copyright (c) 2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include static const unsigned char rcar_power_domain_tree_desc[] = { 1, PLATFORM_CLUSTER_COUNT, PLATFORM_CLUSTER0_CORE_COUNT, PLATFORM_CLUSTER1_CORE_COUNT }; const unsigned char *plat_get_power_domain_tree_desc(void) { return rcar_power_domain_tree_desc; } int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; mpidr &= MPIDR_AFFINITY_MASK; if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) return -1; cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; if (cluster_id >= PLATFORM_CLUSTER_COUNT) return -1; if (cluster_id == 0 && cpu_id >= PLATFORM_CLUSTER0_CORE_COUNT) return -1; if (cluster_id == 1 && cpu_id >= PLATFORM_CLUSTER1_CORE_COUNT) return -1; return (cpu_id + cluster_id * PLATFORM_CLUSTER0_CORE_COUNT); } trusted-firmware-a-2.2/plat/renesas/rcar/platform.mk000066400000000000000000000323321355360272700226200ustar00rootroot00000000000000# # Copyright (c) 2018-2019, Renesas Electronics Corporation. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # PROGRAMMABLE_RESET_ADDRESS := 0 COLD_BOOT_SINGLE_CPU := 1 ARM_CCI_PRODUCT_ID := 500 TRUSTED_BOARD_BOOT := 1 RESET_TO_BL31 := 1 GENERATE_COT := 1 BL2_AT_EL3 := 1 ENABLE_SVE_FOR_NS := 0 MULTI_CONSOLE_API := 1 CRASH_REPORTING := 1 HANDLE_EA_EL3_FIRST := 1 $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) ifeq (${SPD},none) SPD_NONE:=1 $(eval $(call add_define,SPD_NONE)) endif # LSI setting common define RCAR_H3:=0 RCAR_M3:=1 RCAR_M3N:=2 RCAR_E3:=3 RCAR_H3N:=4 RCAR_D3:=5 RCAR_V3M:=6 RCAR_AUTO:=99 $(eval $(call add_define,RCAR_H3)) $(eval $(call add_define,RCAR_M3)) $(eval $(call add_define,RCAR_M3N)) $(eval $(call add_define,RCAR_E3)) $(eval $(call add_define,RCAR_H3N)) $(eval $(call add_define,RCAR_D3)) $(eval $(call add_define,RCAR_V3M)) $(eval $(call add_define,RCAR_AUTO)) RCAR_CUT_10:=0 RCAR_CUT_11:=1 RCAR_CUT_13:=3 RCAR_CUT_20:=10 RCAR_CUT_30:=20 $(eval $(call add_define,RCAR_CUT_10)) $(eval $(call add_define,RCAR_CUT_11)) $(eval $(call add_define,RCAR_CUT_13)) $(eval $(call add_define,RCAR_CUT_20)) $(eval $(call add_define,RCAR_CUT_30)) ifndef LSI $(error "Error: Unknown LSI. Please use LSI= to specify the LSI") else ifeq (${LSI},AUTO) RCAR_LSI:=${RCAR_AUTO} else ifeq (${LSI},H3) RCAR_LSI:=${RCAR_H3} ifndef LSI_CUT # enable compatible function. RCAR_LSI_CUT_COMPAT := 1 $(eval $(call add_define,RCAR_LSI_CUT_COMPAT)) else # disable compatible function. ifeq (${LSI_CUT},10) RCAR_LSI_CUT:=0 else ifeq (${LSI_CUT},11) RCAR_LSI_CUT:=1 else ifeq (${LSI_CUT},20) RCAR_LSI_CUT:=10 else ifeq (${LSI_CUT},30) RCAR_LSI_CUT:=20 else $(error "Error: ${LSI_CUT} is not supported.") endif $(eval $(call add_define,RCAR_LSI_CUT)) endif else ifeq (${LSI},H3N) RCAR_LSI:=${RCAR_H3N} ifndef LSI_CUT # enable compatible function. RCAR_LSI_CUT_COMPAT := 1 $(eval $(call add_define,RCAR_LSI_CUT_COMPAT)) else # disable compatible function. ifeq (${LSI_CUT},30) RCAR_LSI_CUT:=20 else $(error "Error: ${LSI_CUT} is not supported.") endif $(eval $(call add_define,RCAR_LSI_CUT)) endif else ifeq (${LSI},M3) RCAR_LSI:=${RCAR_M3} ifndef LSI_CUT # enable compatible function. RCAR_LSI_CUT_COMPAT := 1 $(eval $(call add_define,RCAR_LSI_CUT_COMPAT)) else # disable compatible function. ifeq (${LSI_CUT},10) RCAR_LSI_CUT:=0 else ifeq (${LSI_CUT},11) RCAR_LSI_CUT:=1 else ifeq (${LSI_CUT},13) RCAR_LSI_CUT:=3 else ifeq (${LSI_CUT},30) RCAR_LSI_CUT:=20 else $(error "Error: ${LSI_CUT} is not supported.") endif $(eval $(call add_define,RCAR_LSI_CUT)) endif else ifeq (${LSI},M3N) RCAR_LSI:=${RCAR_M3N} ifndef LSI_CUT # enable compatible function. RCAR_LSI_CUT_COMPAT := 1 $(eval $(call add_define,RCAR_LSI_CUT_COMPAT)) else # disable compatible function. ifeq (${LSI_CUT},10) RCAR_LSI_CUT:=0 else ifeq (${LSI_CUT},11) RCAR_LSI_CUT:=1 else $(error "Error: ${LSI_CUT} is not supported.") endif $(eval $(call add_define,RCAR_LSI_CUT)) endif else ifeq (${LSI},E3) RCAR_LSI:=${RCAR_E3} ifndef LSI_CUT # enable compatible function. RCAR_LSI_CUT_COMPAT := 1 $(eval $(call add_define,RCAR_LSI_CUT_COMPAT)) else # disable compatible function. ifeq (${LSI_CUT},10) RCAR_LSI_CUT:=0 else ifeq (${LSI_CUT},11) RCAR_LSI_CUT:=1 else $(error "Error: ${LSI_CUT} is not supported.") endif $(eval $(call add_define,RCAR_LSI_CUT)) endif else ifeq (${LSI},D3) RCAR_LSI:=${RCAR_D3} ifndef LSI_CUT # enable compatible function. RCAR_LSI_CUT_COMPAT := 1 $(eval $(call add_define,RCAR_LSI_CUT_COMPAT)) else # disable compatible function. ifeq (${LSI_CUT},10) RCAR_LSI_CUT:=0 else $(error "Error: ${LSI_CUT} is not supported.") endif $(eval $(call add_define,RCAR_LSI_CUT)) endif else ifeq (${LSI},V3M) RCAR_LSI:=${RCAR_V3M} ifndef LSI_CUT # enable compatible function. RCAR_LSI_CUT_COMPAT := 1 $(eval $(call add_define,RCAR_LSI_CUT_COMPAT)) else # disable compatible function. ifeq (${LSI_CUT},10) RCAR_LSI_CUT:=0 endif ifeq (${LSI_CUT},20) RCAR_LSI_CUT:=10 endif $(eval $(call add_define,RCAR_LSI_CUT)) endif else $(error "Error: ${LSI} is not supported.") endif $(eval $(call add_define,RCAR_LSI)) endif # lock RPC HYPERFLASH access by default # unlock to repogram the ATF firmware from u-boot ifndef RCAR_RPC_HYPERFLASH_LOCKED RCAR_RPC_HYPERFLASH_LOCKED := 1 endif $(eval $(call add_define,RCAR_RPC_HYPERFLASH_LOCKED)) # Process RCAR_SECURE_BOOT flag ifndef RCAR_SECURE_BOOT RCAR_SECURE_BOOT := 1 endif $(eval $(call add_define,RCAR_SECURE_BOOT)) # Process RCAR_QOS_TYPE flag ifndef RCAR_QOS_TYPE RCAR_QOS_TYPE := 0 endif $(eval $(call add_define,RCAR_QOS_TYPE)) # Process RCAR_DRAM_SPLIT flag ifndef RCAR_DRAM_SPLIT RCAR_DRAM_SPLIT := 0 endif $(eval $(call add_define,RCAR_DRAM_SPLIT)) # Process RCAR_BL33_EXECUTION_EL flag ifndef RCAR_BL33_EXECUTION_EL RCAR_BL33_EXECUTION_EL := 0 endif $(eval $(call add_define,RCAR_BL33_EXECUTION_EL)) # Process RCAR_AVS_SETTING_ENABLE flag ifeq (${RCAR_AVS_SETTING_ENABLE},0) AVS_SETTING_ENABLE := 0 else AVS_SETTING_ENABLE := 1 endif $(eval $(call add_define,AVS_SETTING_ENABLE)) # Process RCAR_LOSSY_ENABLE flag ifndef RCAR_LOSSY_ENABLE RCAR_LOSSY_ENABLE := 0 endif $(eval $(call add_define,RCAR_LOSSY_ENABLE)) # Process LIFEC_DBSC_PROTECT_ENABLE flag ifndef LIFEC_DBSC_PROTECT_ENABLE LIFEC_DBSC_PROTECT_ENABLE := 1 endif $(eval $(call add_define,LIFEC_DBSC_PROTECT_ENABLE)) # Process PMIC_ROHM_BD9571 flag ifndef PMIC_ROHM_BD9571 PMIC_ROHM_BD9571 := 1 endif $(eval $(call add_define,PMIC_ROHM_BD9571)) # Process PMIC_LEVEL_MODE flag ifndef PMIC_LEVEL_MODE PMIC_LEVEL_MODE := 1 endif $(eval $(call add_define,PMIC_LEVEL_MODE)) # Process RCAR_GEN3_ULCB flag ifndef RCAR_GEN3_ULCB RCAR_GEN3_ULCB := 0 endif ifeq (${RCAR_GEN3_ULCB},1) BOARD_DEFAULT := 0x10 $(eval $(call add_define,BOARD_DEFAULT)) endif $(eval $(call add_define,RCAR_GEN3_ULCB)) # Process RCAR_REF_INT flag ifndef RCAR_REF_INT RCAR_REF_INT :=0 endif $(eval $(call add_define,RCAR_REF_INT)) # Process RCAR_REWT_TRAINING flag ifndef RCAR_REWT_TRAINING RCAR_REWT_TRAINING := 1 endif $(eval $(call add_define,RCAR_REWT_TRAINING)) # Process RCAR_SYSTEM_SUSPEND flag ifndef RCAR_SYSTEM_SUSPEND RCAR_SYSTEM_SUSPEND := 1 endif $(eval $(call add_define,RCAR_SYSTEM_SUSPEND)) # SYSTEM_SUSPEND requires power control of PMIC etc. # When executing SYSTEM_SUSPEND other than Salvator-X, Salvator-XS and Ebisu, # processing equivalent to that implemented in PMIC_ROHM_BD9571 is necessary. ifeq (${RCAR_SYSTEM_SUSPEND},1) ifeq (${PMIC_ROHM_BD9571},0) $(error "Error: When you want RCAR_SYSTEM_SUSPEND to be enable, please also set PMIC_ROHM_BD9571 to enable.") endif endif # Process RCAR_DRAM_LPDDR4_MEMCONF flag ifndef RCAR_DRAM_LPDDR4_MEMCONF RCAR_DRAM_LPDDR4_MEMCONF :=1 endif $(eval $(call add_define,RCAR_DRAM_LPDDR4_MEMCONF)) # Process RCAR_DRAM_DDR3L_MEMCONF flag ifndef RCAR_DRAM_DDR3L_MEMCONF RCAR_DRAM_DDR3L_MEMCONF :=1 endif $(eval $(call add_define,RCAR_DRAM_DDR3L_MEMCONF)) # Process RCAR_DRAM_DDR3L_MEMDUAL flag ifndef RCAR_DRAM_DDR3L_MEMDUAL RCAR_DRAM_DDR3L_MEMDUAL :=1 endif $(eval $(call add_define,RCAR_DRAM_DDR3L_MEMDUAL)) # Process RCAR_BL33_ARG0 flag ifdef RCAR_BL33_ARG0 $(eval $(call add_define,RCAR_BL33_ARG0)) endif #Process RCAR_BL2_DCACHE flag ifndef RCAR_BL2_DCACHE RCAR_BL2_DCACHE := 0 endif $(eval $(call add_define,RCAR_BL2_DCACHE)) # Process RCAR_DRAM_CHANNEL flag ifndef RCAR_DRAM_CHANNEL RCAR_DRAM_CHANNEL :=15 endif $(eval $(call add_define,RCAR_DRAM_CHANNEL)) #Process RCAR_SYSTEM_RESET_KEEPON_DDR flag ifndef RCAR_SYSTEM_RESET_KEEPON_DDR RCAR_SYSTEM_RESET_KEEPON_DDR := 0 endif $(eval $(call add_define,RCAR_SYSTEM_RESET_KEEPON_DDR)) # RCAR_SYSTEM_RESET_KEEPON_DDR requires power control of PMIC etc. # When executing SYSTEM_SUSPEND other than Salvator-X, Salvator-XS and Ebisu, # processing equivalent to that implemented in PMIC_ROHM_BD9571 is necessary. # Also, it is necessary to enable RCAR_SYSTEM_SUSPEND. ifeq (${RCAR_SYSTEM_RESET_KEEPON_DDR},1) ifeq (${PMIC_ROHM_BD9571},0) $(error "Error: When you want RCAR_SYSTEM_RESET_KEEPON_DDR to be enable, please also set PMIC_ROHM_BD9571 to enable.") endif ifeq (${RCAR_SYSTEM_SUSPEND},0) $(error "Error: When you want RCAR_SYSTEM_RESET_KEEPON_DDR to be enable, please also set RCAR_SYSTEM_SUSPEND to enable.") endif endif # Enable workarounds for selected Cortex-A53 erratas. ERRATA_A53_835769 := 1 ERRATA_A53_843419 := 1 ERRATA_A53_855873 := 1 # Enable workarounds for selected Cortex-A57 erratas. ERRATA_A57_859972 := 1 ERRATA_A57_813419 := 1 include drivers/staging/renesas/rcar/ddr/ddr.mk include drivers/renesas/rcar/qos/qos.mk include drivers/renesas/rcar/pfc/pfc.mk include lib/libfdt/libfdt.mk PLAT_INCLUDES := -Idrivers/staging/renesas/rcar/ddr \ -Idrivers/renesas/rcar/qos \ -Idrivers/renesas/rcar/iic_dvfs \ -Idrivers/renesas/rcar/board \ -Idrivers/renesas/rcar/cpld/ \ -Idrivers/renesas/rcar/avs \ -Idrivers/renesas/rcar/delay \ -Idrivers/renesas/rcar/rom \ -Idrivers/renesas/rcar/scif \ -Idrivers/renesas/rcar/emmc \ -Idrivers/renesas/rcar/pwrc \ -Idrivers/renesas/rcar/io \ -Iplat/renesas/rcar/include/registers \ -Iplat/renesas/rcar/include \ -Iplat/renesas/rcar PLAT_BL_COMMON_SOURCES := drivers/renesas/rcar/iic_dvfs/iic_dvfs.c \ plat/renesas/rcar/rcar_common.c RCAR_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c BL2_SOURCES += ${RCAR_GIC_SOURCES} \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S \ ${LIBFDT_SRCS} \ common/desc_image_load.c \ plat/renesas/rcar/aarch64/platform_common.c \ plat/renesas/rcar/aarch64/plat_helpers.S \ plat/renesas/rcar/bl2_interrupt_error.c \ plat/renesas/rcar/bl2_secure_setting.c \ plat/renesas/rcar/bl2_plat_setup.c \ plat/renesas/rcar/plat_storage.c \ plat/renesas/rcar/bl2_plat_mem_params_desc.c \ plat/renesas/rcar/plat_image_load.c \ plat/renesas/rcar/bl2_cpg_init.c \ drivers/renesas/rcar/console/rcar_printf.c \ drivers/renesas/rcar/scif/scif.S \ drivers/renesas/rcar/common.c \ drivers/renesas/rcar/io/io_emmcdrv.c \ drivers/renesas/rcar/io/io_memdrv.c \ drivers/renesas/rcar/io/io_rcar.c \ drivers/renesas/rcar/auth/auth_mod.c \ drivers/renesas/rcar/rpc/rpc_driver.c \ drivers/renesas/rcar/dma/dma_driver.c \ drivers/renesas/rcar/avs/avs_driver.c \ drivers/renesas/rcar/delay/micro_delay.c \ drivers/renesas/rcar/emmc/emmc_interrupt.c \ drivers/renesas/rcar/emmc/emmc_utility.c \ drivers/renesas/rcar/emmc/emmc_mount.c \ drivers/renesas/rcar/emmc/emmc_init.c \ drivers/renesas/rcar/emmc/emmc_read.c \ drivers/renesas/rcar/emmc/emmc_cmd.c \ drivers/renesas/rcar/watchdog/swdt.c \ drivers/renesas/rcar/rom/rom_api.c \ drivers/renesas/rcar/board/board.c \ drivers/io/io_storage.c BL31_SOURCES += ${RCAR_GIC_SOURCES} \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a57.S \ plat/common/plat_psci_common.c \ plat/renesas/rcar/plat_topology.c \ plat/renesas/rcar/aarch64/plat_helpers.S \ plat/renesas/rcar/aarch64/platform_common.c \ plat/renesas/rcar/bl31_plat_setup.c \ plat/renesas/rcar/plat_pm.c \ drivers/renesas/rcar/console/rcar_console.S \ drivers/renesas/rcar/console/rcar_printf.c \ drivers/renesas/rcar/delay/micro_delay.c \ drivers/renesas/rcar/pwrc/call_sram.S \ drivers/renesas/rcar/pwrc/pwrc.c \ drivers/renesas/rcar/common.c \ drivers/arm/cci/cci.c ifeq (${RCAR_GEN3_ULCB},1) BL31_SOURCES += drivers/renesas/rcar/cpld/ulcb_cpld.c endif include lib/xlat_tables_v2/xlat_tables.mk include drivers/auth/mbedtls/mbedtls_crypto.mk PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} # build the layout images for the bootrom and the necessary srecords rcar: rcar_layout_tool rcar_srecord distclean realclean clean: clean_layout_tool clean_srecord # layout images LAYOUT_TOOLPATH ?= tools/renesas/rcar_layout_create clean_layout_tool: @echo "clean layout tool" ${Q}${MAKE} -C ${LAYOUT_TOOLPATH} clean .PHONY: rcar_layout_tool rcar_layout_tool: @echo "generating layout srecs" ${Q}${MAKE} CPPFLAGS="-D=AARCH64" --no-print-directory -C ${LAYOUT_TOOLPATH} # srecords SREC_PATH = ${BUILD_PLAT} BL2_ELF_SRC = ${SREC_PATH}/bl2/bl2.elf BL31_ELF_SRC = ${SREC_PATH}/bl31/bl31.elf clean_srecord: @echo "clean bl2 and bl31 srecs" rm -f ${SREC_PATH}/bl2.srec ${SREC_PATH}/bl31.srec .PHONY: rcar_srecord rcar_srecord: $(BL2_ELF_SRC) $(BL31_ELF_SRC) @echo "generating srec: ${SREC_PATH}/bl2.srec" $(Q)$(OC) -O srec --srec-forceS3 ${BL2_ELF_SRC} ${SREC_PATH}/bl2.srec @echo "generating srec: ${SREC_PATH}/bl31.srec" $(Q)$(OC) -O srec --srec-forceS3 ${BL31_ELF_SRC} ${SREC_PATH}/bl31.srec trusted-firmware-a-2.2/plat/renesas/rcar/rcar_common.c000066400000000000000000000043271355360272700231110ustar00rootroot00000000000000/* * Copyright (c) 2019, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #define CPG_BASE 0xE6150000 #define CPG_MSTPSR3 0x0048 #define MSTP318 (1 << 18) #define MSTP319 (1 << 19) #define PMSR 0x5c #define PMSR_L1FAEG (1U << 31) #define PMSR_PMEL1RX (1 << 23) #define PMCTLR 0x60 #define PMSR_L1IATN (1U << 31) static int rcar_pcie_fixup(unsigned int controller) { uint32_t rcar_pcie_base[] = { 0xfe011000, 0xee811000 }; uint32_t addr = rcar_pcie_base[controller]; uint32_t cpg, pmsr; int ret = 0; /* Test if PCIECx is enabled */ cpg = mmio_read_32(CPG_BASE + CPG_MSTPSR3); if (cpg & (MSTP318 << !controller)) return ret; pmsr = mmio_read_32(addr + PMSR); if ((pmsr & PMSR_PMEL1RX) && ((pmsr & 0x70000) != 0x30000)) { /* Fix applicable */ mmio_write_32(addr + PMCTLR, PMSR_L1IATN); while (!(mmio_read_32(addr + PMSR) & PMSR_L1FAEG)) ; mmio_write_32(addr + PMSR, PMSR_L1FAEG | PMSR_PMEL1RX); ret = 1; } return ret; } /* RAS functions common to AArch64 ARM platforms */ void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie, void *handle, uint64_t flags) { unsigned int fixed = 0; fixed |= rcar_pcie_fixup(0); fixed |= rcar_pcie_fixup(1); if (fixed) return; ERROR("Unhandled External Abort received on 0x%lx at EL3!\n", read_mpidr_el1()); ERROR(" exception reason=%u syndrome=0x%llx\n", ea_reason, syndrome); panic(); } #include static console_rcar_t rcar_boot_console; static console_rcar_t rcar_runtime_console; void rcar_console_boot_init(void) { int ret; ret = console_rcar_register(0, 0, 0, &rcar_boot_console); if (!ret) panic(); console_set_scope(&rcar_boot_console.console, CONSOLE_FLAG_BOOT); } void rcar_console_boot_end(void) { } void rcar_console_runtime_init(void) { int ret; ret = console_rcar_register(1, 0, 0, &rcar_runtime_console); if (!ret) panic(); console_set_scope(&rcar_boot_console.console, CONSOLE_FLAG_RUNTIME); } void rcar_console_runtime_end(void) { } trusted-firmware-a-2.2/plat/rockchip/000077500000000000000000000000001355360272700176535ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/common/000077500000000000000000000000001355360272700211435ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/common/aarch32/000077500000000000000000000000001355360272700223665ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/common/aarch32/plat_helpers.S000066400000000000000000000110231355360272700251710ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include .globl cpuson_entry_point .globl cpuson_flags .globl platform_cpu_warmboot .globl plat_secondary_cold_boot_setup .globl plat_report_exception .globl plat_is_my_cpu_primary .globl plat_my_core_pos .globl plat_reset_handler .globl plat_panic_handler /* * void plat_reset_handler(void); * * Determine the SOC type and call the appropriate reset * handler. * */ func plat_reset_handler bx lr endfunc plat_reset_handler func plat_my_core_pos ldcopr r0, MPIDR and r1, r0, #MPIDR_CPU_MASK #ifdef PLAT_RK_MPIDR_CLUSTER_MASK and r0, r0, #PLAT_RK_MPIDR_CLUSTER_MASK #else and r0, r0, #MPIDR_CLUSTER_MASK #endif add r0, r1, r0, LSR #PLAT_RK_CLST_TO_CPUID_SHIFT bx lr endfunc plat_my_core_pos /* -------------------------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions * needed for a secondary cpu after a cold reset e.g * mark the cpu's presence, mechanism to place it in a * holding pen etc. * -------------------------------------------------------------------- */ func plat_secondary_cold_boot_setup /* rk3288 does not do cold boot for secondary CPU */ cb_panic: b cb_panic endfunc plat_secondary_cold_boot_setup func plat_is_my_cpu_primary ldcopr r0, MPIDR #ifdef PLAT_RK_MPIDR_CLUSTER_MASK ldr r1, =(PLAT_RK_MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) #else ldr r1, =(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) #endif and r0, r1 cmp r0, #PLAT_RK_PRIMARY_CPU moveq r0, #1 movne r0, #0 bx lr endfunc plat_is_my_cpu_primary /* -------------------------------------------------------------------- * void plat_panic_handler(void) * Call system reset function on panic. Set up an emergency stack so we * can run C functions (it only needs to last for a few calls until we * reboot anyway). * -------------------------------------------------------------------- */ func plat_panic_handler bl plat_set_my_stack b rockchip_soc_soft_reset endfunc plat_panic_handler /* -------------------------------------------------------------------- * void platform_cpu_warmboot (void); * cpus online or resume entrypoint * -------------------------------------------------------------------- */ func platform_cpu_warmboot _align=16 push { r4 - r7, lr } ldcopr r0, MPIDR and r5, r0, #MPIDR_CPU_MASK #ifdef PLAT_RK_MPIDR_CLUSTER_MASK and r6, r0, #PLAT_RK_MPIDR_CLUSTER_MASK #else and r6, r0, #MPIDR_CLUSTER_MASK #endif mov r0, r6 func_rockchip_clst_warmboot /* -------------------------------------------------------------------- * big cluster id is 1 * big cores id is from 0-3, little cores id 4-7 * -------------------------------------------------------------------- */ add r7, r5, r6, LSR #PLAT_RK_CLST_TO_CPUID_SHIFT /* -------------------------------------------------------------------- * get per cpuup flag * -------------------------------------------------------------------- */ ldr r4, =cpuson_flags add r4, r4, r7, lsl #2 ldr r1, [r4] /* -------------------------------------------------------------------- * check cpuon reason * -------------------------------------------------------------------- */ cmp r1, #PMU_CPU_AUTO_PWRDN beq boot_entry cmp r1, #PMU_CPU_HOTPLUG beq boot_entry /* -------------------------------------------------------------------- * If the boot core cpuson_flags or cpuson_entry_point is not * expection. force the core into wfe. * -------------------------------------------------------------------- */ wfe_loop: wfe b wfe_loop boot_entry: mov r1, #0 str r1, [r4] /* -------------------------------------------------------------------- * get per cpuup boot addr * -------------------------------------------------------------------- */ ldr r5, =cpuson_entry_point ldr r2, [r5, r7, lsl #2] /* ehem. #3 */ pop { r4 - r7, lr } bx r2 endfunc platform_cpu_warmboot /* -------------------------------------------------------------------- * Per-CPU Secure entry point - resume or power up * -------------------------------------------------------------------- */ .section tzfw_coherent_mem, "a" .align 3 cpuson_entry_point: .rept PLATFORM_CORE_COUNT .quad 0 .endr cpuson_flags: .rept PLATFORM_CORE_COUNT .word 0 .endr rockchip_clst_warmboot_data trusted-firmware-a-2.2/plat/rockchip/common/aarch32/platform_common.c000066400000000000000000000023221355360272700257250ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include void plat_configure_mmu_svc_mon(unsigned long total_base, unsigned long total_size, unsigned long ro_start, unsigned long ro_limit, unsigned long coh_start, unsigned long coh_limit) { mmap_add_region(total_base, total_base, total_size, MT_MEMORY | MT_RW | MT_SECURE); mmap_add_region(ro_start, ro_start, ro_limit - ro_start, MT_MEMORY | MT_RO | MT_SECURE); mmap_add_region(coh_start, coh_start, coh_limit - coh_start, MT_DEVICE | MT_RW | MT_SECURE); mmap_add(plat_rk_mmap); rockchip_plat_mmu_svc_mon(); init_xlat_tables(); enable_mmu_svc_mon(0); } unsigned int plat_get_syscnt_freq2(void) { return SYS_COUNTER_FREQ_IN_TICKS; } /* * generic pm code does cci handling, but rockchip arm32 platforms * have ever only 1 cluster, so nothing to do. */ void plat_cci_init(void) { } void plat_cci_enable(void) { } void plat_cci_disable(void) { } trusted-firmware-a-2.2/plat/rockchip/common/aarch32/pmu_sram_cpus_on.S000066400000000000000000000017531355360272700260710ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl pmu_cpuson_entrypoint .macro pmusram_entry_func _name .section .pmusram.entry, "ax" .type \_name, %function .cfi_startproc \_name: .endm pmusram_entry_func pmu_cpuson_entrypoint #if PSRAM_CHECK_WAKEUP_CPU check_wake_cpus: ldcopr r0, MPIDR and r1, r0, #MPIDR_CPU_MASK #ifdef PLAT_RK_MPIDR_CLUSTER_MASK and r0, r0, #PLAT_RK_MPIDR_CLUSTER_MASK #else and r0, r0, #MPIDR_CLUSTER_MASK #endif orr r0, r0, r1 /* primary_cpu */ ldr r1, boot_mpidr cmp r0, r1 beq sys_wakeup /* * If the core is not the primary cpu, * force the core into wfe. */ wfe_loop: wfe b wfe_loop sys_wakeup: #endif #if PSRAM_DO_DDR_RESUME ddr_resume: ldr r2, =__bl32_sram_stack_end mov sp, r2 bl dmc_resume #endif bl sram_restore sys_resume: bl sp_min_warm_entrypoint endfunc pmu_cpuson_entrypoint trusted-firmware-a-2.2/plat/rockchip/common/aarch64/000077500000000000000000000000001355360272700223735ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/common/aarch64/plat_helpers.S000066400000000000000000000111761355360272700252070ustar00rootroot00000000000000/* * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include .globl cpuson_entry_point .globl cpuson_flags .globl platform_cpu_warmboot .globl plat_secondary_cold_boot_setup .globl plat_report_exception .globl plat_is_my_cpu_primary .globl plat_my_core_pos .globl plat_reset_handler .globl plat_panic_handler /* * void plat_reset_handler(void); * * Determine the SOC type and call the appropriate reset * handler. * */ func plat_reset_handler mrs x0, midr_el1 ubfx x0, x0, MIDR_PN_SHIFT, #12 cmp w0, #((CORTEX_A72_MIDR >> MIDR_PN_SHIFT) & MIDR_PN_MASK) b.eq handler_a72 b handler_end handler_a72: /* * This handler does the following: * Set the L2 Data RAM latency for Cortex-A72. * Set the L2 Tag RAM latency to for Cortex-A72. */ mov x0, #((5 << CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT) | \ (0x1 << 5)) msr CORTEX_A72_L2CTLR_EL1, x0 isb handler_end: ret endfunc plat_reset_handler func plat_my_core_pos mrs x0, mpidr_el1 and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #PLAT_RK_CLST_TO_CPUID_SHIFT ret endfunc plat_my_core_pos /* -------------------------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions * needed for a secondary cpu after a cold reset e.g * mark the cpu's presence, mechanism to place it in a * holding pen etc. * -------------------------------------------------------------------- */ func plat_secondary_cold_boot_setup /* rk3368 does not do cold boot for secondary CPU */ cb_panic: b cb_panic endfunc plat_secondary_cold_boot_setup func plat_is_my_cpu_primary mrs x0, mpidr_el1 and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) cmp x0, #PLAT_RK_PRIMARY_CPU cset x0, eq ret endfunc plat_is_my_cpu_primary /* -------------------------------------------------------------------- * void plat_panic_handler(void) * Call system reset function on panic. Set up an emergency stack so we * can run C functions (it only needs to last for a few calls until we * reboot anyway). * -------------------------------------------------------------------- */ func plat_panic_handler msr spsel, #0 bl plat_set_my_stack b rockchip_soc_soft_reset endfunc plat_panic_handler /* -------------------------------------------------------------------- * void platform_cpu_warmboot (void); * cpus online or resume enterpoint * -------------------------------------------------------------------- */ func platform_cpu_warmboot _align=16 mrs x0, MPIDR_EL1 and x19, x0, #MPIDR_CPU_MASK and x20, x0, #MPIDR_CLUSTER_MASK mov x0, x20 func_rockchip_clst_warmboot /* -------------------------------------------------------------------- * big cluster id is 1 * big cores id is from 0-3, little cores id 4-7 * -------------------------------------------------------------------- */ add x21, x19, x20, lsr #PLAT_RK_CLST_TO_CPUID_SHIFT /* -------------------------------------------------------------------- * get per cpuup flag * -------------------------------------------------------------------- */ adr x4, cpuson_flags add x4, x4, x21, lsl #2 ldr w1, [x4] /* -------------------------------------------------------------------- * check cpuon reason * -------------------------------------------------------------------- */ cmp w1, PMU_CPU_AUTO_PWRDN b.eq boot_entry cmp w1, PMU_CPU_HOTPLUG b.eq boot_entry /* -------------------------------------------------------------------- * If the boot core cpuson_flags or cpuson_entry_point is not * expection. force the core into wfe. * -------------------------------------------------------------------- */ wfe_loop: wfe b wfe_loop boot_entry: str wzr, [x4] /* -------------------------------------------------------------------- * get per cpuup boot addr * -------------------------------------------------------------------- */ adr x5, cpuson_entry_point ldr x2, [x5, x21, lsl #3] br x2 endfunc platform_cpu_warmboot /* -------------------------------------------------------------------- * Per-CPU Secure entry point - resume or power up * -------------------------------------------------------------------- */ .section tzfw_coherent_mem, "a" .align 3 cpuson_entry_point: .rept PLATFORM_CORE_COUNT .quad 0 .endr cpuson_flags: .rept PLATFORM_CORE_COUNT .word 0 .endr rockchip_clst_warmboot_data trusted-firmware-a-2.2/plat/rockchip/common/aarch64/platform_common.c000066400000000000000000000043511355360272700257360ustar00rootroot00000000000000/* * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #ifdef PLAT_RK_CCI_BASE static const int cci_map[] = { PLAT_RK_CCI_CLUSTER0_SL_IFACE_IX, PLAT_RK_CCI_CLUSTER1_SL_IFACE_IX }; #endif /****************************************************************************** * Macro generating the code for the function setting up the pagetables as per * the platform memory map & initialize the mmu, for the given exception level ******************************************************************************/ #define DEFINE_CONFIGURE_MMU_EL(_el) \ void plat_configure_mmu_el ## _el(unsigned long total_base, \ unsigned long total_size, \ unsigned long ro_start, \ unsigned long ro_limit, \ unsigned long coh_start, \ unsigned long coh_limit) \ { \ mmap_add_region(total_base, total_base, \ total_size, \ MT_MEMORY | MT_RW | MT_SECURE); \ mmap_add_region(ro_start, ro_start, \ ro_limit - ro_start, \ MT_MEMORY | MT_RO | MT_SECURE); \ mmap_add_region(coh_start, coh_start, \ coh_limit - coh_start, \ MT_DEVICE | MT_RW | MT_SECURE); \ mmap_add(plat_rk_mmap); \ rockchip_plat_mmu_el##_el(); \ init_xlat_tables(); \ \ enable_mmu_el ## _el(0); \ } /* Define EL3 variants of the function initialising the MMU */ DEFINE_CONFIGURE_MMU_EL(3) unsigned int plat_get_syscnt_freq2(void) { return SYS_COUNTER_FREQ_IN_TICKS; } void plat_cci_init(void) { #ifdef PLAT_RK_CCI_BASE /* Initialize CCI driver */ cci_init(PLAT_RK_CCI_BASE, cci_map, ARRAY_SIZE(cci_map)); #endif } void plat_cci_enable(void) { /* * Enable CCI coherency for this cluster. * No need for locks as no other cpu is active at the moment. */ #ifdef PLAT_RK_CCI_BASE cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr())); #endif } void plat_cci_disable(void) { #ifdef PLAT_RK_CCI_BASE cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr())); #endif } trusted-firmware-a-2.2/plat/rockchip/common/aarch64/pmu_sram_cpus_on.S000066400000000000000000000016231355360272700260720ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl pmu_cpuson_entrypoint .macro pmusram_entry_func _name .section .pmusram.entry, "ax" .type \_name, %function .cfi_startproc \_name: .endm pmusram_entry_func pmu_cpuson_entrypoint #if PSRAM_CHECK_WAKEUP_CPU check_wake_cpus: mrs x0, MPIDR_EL1 and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK orr x0, x0, x1 /* primary_cpu */ ldr w1, boot_mpidr cmp w0, w1 b.eq sys_wakeup /* * If the core is not the primary cpu, * force the core into wfe. */ wfe_loop: wfe b wfe_loop sys_wakeup: #endif #if PSRAM_DO_DDR_RESUME ddr_resume: ldr x2, =__bl31_sram_stack_end mov sp, x2 bl dmc_resume #endif bl sram_restore sys_resume: bl bl31_warm_entrypoint endfunc pmu_cpuson_entrypoint trusted-firmware-a-2.2/plat/rockchip/common/bl31_plat_setup.c000066400000000000000000000066151355360272700243200ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include static entry_point_info_t bl32_ep_info; static entry_point_info_t bl33_ep_info; /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for * the security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. ******************************************************************************/ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; next_image_info = (type == NON_SECURE) ? &bl33_ep_info : &bl32_ep_info; assert(next_image_info->h.type == PARAM_EP); /* None of the images on this platform can have 0x0 as the entrypoint */ if (next_image_info->pc) return next_image_info; else return NULL; } #pragma weak params_early_setup void params_early_setup(u_register_t plat_param_from_bl2) { } /******************************************************************************* * Perform any BL3-1 early platform setup. Here is an opportunity to copy * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before they * are lost (potentially). This needs to be done before the MMU is initialized * so that the memory layout can be used while creating page tables. * BL2 has flushed this information to memory, so we are guaranteed to pick up * good data. ******************************************************************************/ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { static console_16550_t console; params_early_setup(arg1); if (rockchip_get_uart_base() != 0) console_16550_register(rockchip_get_uart_base(), rockchip_get_uart_clock(), rockchip_get_uart_baudrate(), &console); VERBOSE("bl31_setup\n"); bl31_params_parse_helper(arg0, &bl32_ep_info, &bl33_ep_info); } /******************************************************************************* * Perform any BL3-1 platform setup code ******************************************************************************/ void bl31_platform_setup(void) { generic_delay_timer_init(); plat_rockchip_soc_init(); /* Initialize the gic cpu and distributor interfaces */ plat_rockchip_gic_driver_init(); plat_rockchip_gic_init(); plat_rockchip_pmu_init(); } /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this is only intializes the mmu in a quick and dirty way. ******************************************************************************/ void bl31_plat_arch_setup(void) { plat_cci_init(); plat_cci_enable(); plat_configure_mmu_el3(BL_CODE_BASE, BL_COHERENT_RAM_END - BL_CODE_BASE, BL_CODE_BASE, BL_CODE_END, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); } trusted-firmware-a-2.2/plat/rockchip/common/drivers/000077500000000000000000000000001355360272700226215ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/common/drivers/parameter/000077500000000000000000000000001355360272700246015ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/common/drivers/parameter/ddr_parameter.c000066400000000000000000000105421355360272700275600ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "ddr_parameter.h" /* * The miniloader delivers the parameters about ddr usage info from address * 0x02000000 and the data format is defined as below figure. It tells ATF the * areas of ddr that are used by platform, we treat them as non-secure regions * by default. Then we should parse the other part regions and configurate them * as secure regions to avoid illegal access. * * [ddr usage info data format] * 0x02000000 * ----------------------------------------------------------------------------- * | | | | * ----------------------------------------------------------------------------- * | count | 4byte | the array numbers of the | * | | | 'addr_array' and 'size_array' | * ----------------------------------------------------------------------------- * | reserved | 4byte | just for 'addr_array' 8byte aligned | * ----------------------------------------------------------------------------- * | addr_array[count] | per 8byte | memory region base address | * ----------------------------------------------------------------------------- * | size_array[count] | per 8byte | memory region size (byte) | * ----------------------------------------------------------------------------- */ /* * function: read parameters info(ns-regions) and try to parse s-regions info * * @addr: head address to the ddr usage struct from miniloader * @max_mb: the max ddr capacity(MB) that the platform support */ struct param_ddr_usage ddr_region_usage_parse(uint64_t addr, uint64_t max_mb) { uint64_t base, top; uint32_t i, addr_offset, size_offset; struct param_ddr_usage p; memset(&p, 0, sizeof(p)); /* read how many blocks of ns-regions, read from offset: 0x0 */ p.ns_nr = mmio_read_32(addr + REGION_NR_OFFSET); if ((p.ns_nr > DDR_REGION_NR_MAX) || (p.ns_nr == 0)) { ERROR("over or zero region, nr=%d, max=%d\n", p.ns_nr, DDR_REGION_NR_MAX); return p; } /* whole ddr regions boundary, it will be used when parse s-regions */ p.boundary = max_mb; /* calculate ns-region base addr and size offset */ addr_offset = REGION_ADDR_OFFSET; size_offset = REGION_ADDR_OFFSET + p.ns_nr * REGION_DATA_PER_BYTES; /* read all ns-regions base and top address */ for (i = 0; i < p.ns_nr; i++) { base = mmio_read_64(addr + addr_offset); top = base + mmio_read_64(addr + size_offset); /* * translate byte to MB and store info, * Miniloader will promise every ns-region is MB aligned. */ p.ns_base[i] = RG_SIZE_MB(base); p.ns_top[i] = RG_SIZE_MB(top); addr_offset += REGION_DATA_PER_BYTES; size_offset += REGION_DATA_PER_BYTES; } /* * a s-region's base starts from previous ns-region's top, and a * s-region's top ends with next ns-region's base. maybe like this: * * case1: ns-regison start from 0MB * ----------------------------------------------- * | ns0 | S0 | ns1 | S1 | ns2 | * 0----------------------------------------------- max_mb * * * case2: ns-regison not start from 0MB * ----------------------------------------------- * | S0 | ns0 | ns1 | ns2 | S1 | * 0----------------------------------------------- max_mb */ /* like above case2 figure, ns-region is not start from 0MB */ if (p.ns_base[0] != 0) { p.s_base[p.s_nr] = 0; p.s_top[p.s_nr] = p.ns_base[0]; p.s_nr++; } /* * notice: if ns-regions not start from 0MB, p.s_nr = 1 now, otherwise 0 */ for (i = 0; i < p.ns_nr; i++) { /* * if current ns-regions top covers boundary, * that means s-regions are all parsed yet, so finsh. */ if (p.ns_top[i] == p.boundary) goto out; /* s-region's base starts from previous ns-region's top */ p.s_base[p.s_nr] = p.ns_top[i]; /* s-region's top ends with next ns-region's base */ if (i + 1 < p.ns_nr) p.s_top[p.s_nr] = p.ns_base[i + 1]; else p.s_top[p.s_nr] = p.boundary; p.s_nr++; } out: return p; } trusted-firmware-a-2.2/plat/rockchip/common/drivers/parameter/ddr_parameter.h000066400000000000000000000016331355360272700275660ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef DDR_PARAMETER_H #define DDR_PARAMETER_H #include #include #include #include #include #include #include #include #include #define DDR_REGION_NR_MAX 10 #define REGION_NR_OFFSET 0 #define REGION_ADDR_OFFSET 8 #define REGION_DATA_PER_BYTES 8 #define RG_SIZE_MB(byte) ((byte) >> 20) /* unit: MB */ struct param_ddr_usage { uint64_t boundary; uint32_t ns_nr; uint64_t ns_base[DDR_REGION_NR_MAX]; uint64_t ns_top[DDR_REGION_NR_MAX]; uint32_t s_nr; uint64_t s_base[DDR_REGION_NR_MAX]; uint64_t s_top[DDR_REGION_NR_MAX]; }; struct param_ddr_usage ddr_region_usage_parse(uint64_t addr, uint64_t max_mb); #endif /* DDR_PARAMETER_H */ trusted-firmware-a-2.2/plat/rockchip/common/drivers/pmu/000077500000000000000000000000001355360272700234225ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/common/drivers/pmu/pmu_com.h000066400000000000000000000052711355360272700252370ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PMU_COM_H #define PMU_COM_H #ifndef CHECK_CPU_WFIE_BASE #define CHECK_CPU_WFIE_BASE (PMU_BASE + PMU_CORE_PWR_ST) #endif /* * Use this macro to instantiate lock before it is used in below * rockchip_pd_lock_xxx() macros */ DECLARE_BAKERY_LOCK(rockchip_pd_lock); /* * These are wrapper macros to the powe domain Bakery Lock API. */ #define rockchip_pd_lock_init() bakery_lock_init(&rockchip_pd_lock) #define rockchip_pd_lock_get() bakery_lock_get(&rockchip_pd_lock) #define rockchip_pd_lock_rls() bakery_lock_release(&rockchip_pd_lock) /***************************************************************************** * power domain on or off *****************************************************************************/ enum pmu_pd_state { pmu_pd_on = 0, pmu_pd_off = 1 }; #pragma weak plat_ic_get_pending_interrupt_id #pragma weak pmu_power_domain_ctr #pragma weak check_cpu_wfie static inline uint32_t pmu_power_domain_st(uint32_t pd) { uint32_t pwrdn_st = mmio_read_32(PMU_BASE + PMU_PWRDN_ST) & BIT(pd); if (pwrdn_st) return pmu_pd_off; else return pmu_pd_on; } static int pmu_power_domain_ctr(uint32_t pd, uint32_t pd_state) { uint32_t val; uint32_t loop = 0; int ret = 0; rockchip_pd_lock_get(); val = mmio_read_32(PMU_BASE + PMU_PWRDN_CON); if (pd_state == pmu_pd_off) val |= BIT(pd); else val &= ~BIT(pd); mmio_write_32(PMU_BASE + PMU_PWRDN_CON, val); dsb(); while ((pmu_power_domain_st(pd) != pd_state) && (loop < PD_CTR_LOOP)) { udelay(1); loop++; } if (pmu_power_domain_st(pd) != pd_state) { WARN("%s: %d, %d, error!\n", __func__, pd, pd_state); ret = -EINVAL; } rockchip_pd_lock_rls(); return ret; } static int check_cpu_wfie(uint32_t cpu_id, uint32_t wfie_msk) { uint32_t cluster_id, loop = 0; if (cpu_id >= PLATFORM_CLUSTER0_CORE_COUNT) { cluster_id = 1; cpu_id -= PLATFORM_CLUSTER0_CORE_COUNT; } else { cluster_id = 0; } /* * wfe/wfi tracking not possible, hopefully the host * was sucessful in enabling wfe/wfi. * We'll give a bit of additional time, like the kernel does. */ if ((cluster_id && clstb_cpu_wfe < 0) || (!cluster_id && clstl_cpu_wfe < 0)) { mdelay(1); return 0; } if (cluster_id) wfie_msk <<= (clstb_cpu_wfe + cpu_id); else wfie_msk <<= (clstl_cpu_wfe + cpu_id); while (!(mmio_read_32(CHECK_CPU_WFIE_BASE) & wfie_msk) && (loop < CHK_CPU_LOOP)) { udelay(1); loop++; } if ((mmio_read_32(CHECK_CPU_WFIE_BASE) & wfie_msk) == 0) { WARN("%s: %d, %d, %d, error!\n", __func__, cluster_id, cpu_id, wfie_msk); return -EINVAL; } return 0; } #endif /* PMU_COM_H */ trusted-firmware-a-2.2/plat/rockchip/common/include/000077500000000000000000000000001355360272700225665ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/common/include/plat_macros.S000066400000000000000000000060661355360272700252260ustar00rootroot00000000000000/* * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ROCKCHIP_PLAT_MACROS_S #define ROCKCHIP_PLAT_MACROS_S #include #include #include #include #include .section .rodata.gic_reg_name, "aS" /* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */ gicc_regs: .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", "" /* Applicable only to GICv3 with SRE enabled */ icc_regs: .asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", "" /* Registers common to both GICv2 and GICv3 */ gicd_pend_reg: .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n" \ " Offset:\t\t\tvalue\n" newline: .asciz "\n" spacer: .asciz ":\t\t0x" .section .rodata.cci_reg_name, "aS" cci_iface_regs: .asciz "cci_snoop_ctrl_cluster0", "cci_snoop_ctrl_cluster1" , "" /* --------------------------------------------- * The below utility macro prints out relevant GIC * and CCI registers whenever an unhandled * exception is taken in BL31. * Expects: GICD base in x26, GICC base in x27 * Clobbers: x0 - x10, sp * --------------------------------------------- */ .macro plat_crash_print_regs mov_imm x26, PLAT_RK_GICD_BASE mov_imm x27, PLAT_RK_GICC_BASE /* Check for GICv3 system register access */ mrs x7, id_aa64pfr0_el1 ubfx x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH cmp x7, #1 b.ne print_gicv2 /* Check for SRE enable */ mrs x8, ICC_SRE_EL3 tst x8, #ICC_SRE_SRE_BIT b.eq print_gicv2 /* Load the icc reg list to x6 */ adr x6, icc_regs /* Load the icc regs to gp regs used by str_in_crash_buf_print */ mrs x8, ICC_HPPIR0_EL1 mrs x9, ICC_HPPIR1_EL1 mrs x10, ICC_CTLR_EL3 /* Store to the crash buf and print to console */ bl str_in_crash_buf_print b print_gic_common print_gicv2: /* Load the gicc reg list to x6 */ adr x6, gicc_regs /* Load the gicc regs to gp regs used by str_in_crash_buf_print */ ldr w8, [x27, #GICC_HPPIR] ldr w9, [x27, #GICC_AHPPIR] ldr w10, [x27, #GICC_CTLR] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print print_gic_common: /* Print the GICD_ISPENDR regs */ add x7, x26, #GICD_ISPENDR adr x4, gicd_pend_reg bl asm_print_str gicd_ispendr_loop: sub x4, x7, x26 cmp x4, #0x280 b.eq exit_print_gic_regs bl asm_print_hex adr x4, spacer bl asm_print_str ldr x4, [x7], #8 bl asm_print_hex adr x4, newline bl asm_print_str b gicd_ispendr_loop exit_print_gic_regs: #if PLATFORM_CLUSTER_COUNT > 1 adr x6, cci_iface_regs /* Store in x7 the base address of the first interface */ mov_imm x7, (PLAT_RK_CCI_BASE + SLAVE_IFACE_OFFSET( \ PLAT_RK_CCI_CLUSTER0_SL_IFACE_IX)) ldr w8, [x7, #SNOOP_CTRL_REG] /* Store in x7 the base address of the second interface */ mov_imm x7, (PLAT_RK_CCI_BASE + SLAVE_IFACE_OFFSET( \ PLAT_RK_CCI_CLUSTER1_SL_IFACE_IX)) ldr w9, [x7, #SNOOP_CTRL_REG] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print #endif .endm #endif /* ROCKCHIP_PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/rockchip/common/include/plat_params.h000066400000000000000000000004321355360272700252410ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_PARAMS_H #define PLAT_PARAMS_H #include #include #endif /* PLAT_PARAMS_H */ trusted-firmware-a-2.2/plat/rockchip/common/include/plat_private.h000066400000000000000000000120701355360272700254310ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_PRIVATE_H #define PLAT_PRIVATE_H #ifndef __ASSEMBLER__ #include #include #include #include #include #define __sramdata __attribute__((section(".sram.data"))) #define __sramconst __attribute__((section(".sram.rodata"))) #define __sramfunc __attribute__((section(".sram.text"))) #define __pmusramdata __attribute__((section(".pmusram.data"))) #define __pmusramconst __attribute__((section(".pmusram.rodata"))) #define __pmusramfunc __attribute__((section(".pmusram.text"))) extern uint32_t __bl31_sram_text_start, __bl31_sram_text_end; extern uint32_t __bl31_sram_data_start, __bl31_sram_data_end; extern uint32_t __bl31_sram_stack_start, __bl31_sram_stack_end; extern uint32_t __bl31_sram_text_real_end, __bl31_sram_data_real_end; extern uint32_t __sram_incbin_start, __sram_incbin_end; extern uint32_t __sram_incbin_real_end; /****************************************************************************** * The register have write-mask bits, it is mean, if you want to set the bits, * you needs set the write-mask bits at the same time, * The write-mask bits is in high 16-bits. * The fllowing macro definition helps access write-mask bits reg efficient! ******************************************************************************/ #define REG_MSK_SHIFT 16 #ifndef WMSK_BIT #define WMSK_BIT(nr) BIT((nr) + REG_MSK_SHIFT) #endif /* set one bit with write mask */ #ifndef BIT_WITH_WMSK #define BIT_WITH_WMSK(nr) (BIT(nr) | WMSK_BIT(nr)) #endif #ifndef BITS_SHIFT #define BITS_SHIFT(bits, shift) (bits << (shift)) #endif #ifndef BITS_WITH_WMASK #define BITS_WITH_WMASK(bits, msk, shift)\ (BITS_SHIFT(bits, shift) | BITS_SHIFT(msk, (shift + REG_MSK_SHIFT))) #endif /****************************************************************************** * Function and variable prototypes *****************************************************************************/ #ifdef __aarch64__ void plat_configure_mmu_el3(unsigned long total_base, unsigned long total_size, unsigned long, unsigned long, unsigned long, unsigned long); void rockchip_plat_mmu_el3(void); #else void plat_configure_mmu_svc_mon(unsigned long total_base, unsigned long total_size, unsigned long, unsigned long, unsigned long, unsigned long); void rockchip_plat_mmu_svc_mon(void); #endif void plat_cci_init(void); void plat_cci_enable(void); void plat_cci_disable(void); void plat_delay_timer_init(void); void params_early_setup(u_register_t plat_params_from_bl2); void plat_rockchip_gic_driver_init(void); void plat_rockchip_gic_init(void); void plat_rockchip_gic_cpuif_enable(void); void plat_rockchip_gic_cpuif_disable(void); void plat_rockchip_gic_pcpu_init(void); void plat_rockchip_pmu_init(void); void plat_rockchip_soc_init(void); uintptr_t plat_get_sec_entrypoint(void); void platform_cpu_warmboot(void); struct bl_aux_gpio_info *plat_get_rockchip_gpio_reset(void); struct bl_aux_gpio_info *plat_get_rockchip_gpio_poweroff(void); struct bl_aux_gpio_info *plat_get_rockchip_suspend_gpio(uint32_t *count); struct bl_aux_rk_apio_info *plat_get_rockchip_suspend_apio(void); void plat_rockchip_gpio_init(void); void plat_rockchip_save_gpio(void); void plat_rockchip_restore_gpio(void); int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint); int rockchip_soc_hlvl_pwr_dm_off(uint32_t lvl, plat_local_state_t lvl_state); int rockchip_soc_cores_pwr_dm_off(void); int rockchip_soc_sys_pwr_dm_suspend(void); int rockchip_soc_cores_pwr_dm_suspend(void); int rockchip_soc_hlvl_pwr_dm_suspend(uint32_t lvl, plat_local_state_t lvl_state); int rockchip_soc_hlvl_pwr_dm_on_finish(uint32_t lvl, plat_local_state_t lvl_state); int rockchip_soc_cores_pwr_dm_on_finish(void); int rockchip_soc_sys_pwr_dm_resume(void); int rockchip_soc_hlvl_pwr_dm_resume(uint32_t lvl, plat_local_state_t lvl_state); int rockchip_soc_cores_pwr_dm_resume(void); void __dead2 rockchip_soc_soft_reset(void); void __dead2 rockchip_soc_system_off(void); void __dead2 rockchip_soc_cores_pd_pwr_dn_wfi( const psci_power_state_t *target_state); void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void); extern const unsigned char rockchip_power_domain_tree_desc[]; extern void *pmu_cpuson_entrypoint; extern u_register_t cpuson_entry_point[PLATFORM_CORE_COUNT]; extern uint32_t cpuson_flags[PLATFORM_CORE_COUNT]; extern const mmap_region_t plat_rk_mmap[]; uint32_t rockchip_get_uart_base(void); uint32_t rockchip_get_uart_baudrate(void); uint32_t rockchip_get_uart_clock(void); #endif /* __ASSEMBLER__ */ /****************************************************************************** * cpu up status * The bits of macro value is not more than 12 bits for cmp instruction! ******************************************************************************/ #define PMU_CPU_HOTPLUG 0xf00 #define PMU_CPU_AUTO_PWRDN 0xf0 #define PMU_CLST_RET 0xa5 #endif /* PLAT_PRIVATE_H */ trusted-firmware-a-2.2/plat/rockchip/common/include/rockchip_sip_svc.h000066400000000000000000000012021355360272700262620ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ROCKCHIP_SIP_SVC_H #define ROCKCHIP_SIP_SVC_H /* SMC function IDs for SiP Service queries */ #define SIP_SVC_CALL_COUNT 0x8200ff00 #define SIP_SVC_UID 0x8200ff01 #define SIP_SVC_VERSION 0x8200ff03 /* rockchip SiP Service Calls version numbers */ #define RK_SIP_SVC_VERSION_MAJOR 0x0 #define RK_SIP_SVC_VERSION_MINOR 0x1 /* Number of ROCKCHIP SiP Calls implemented */ #define RK_COMMON_SIP_NUM_CALLS 0x3 enum { RK_SIP_E_SUCCESS = 0, RK_SIP_E_INVALID_PARAM = -1 }; #endif /* ROCKCHIP_SIP_SVC_H */ trusted-firmware-a-2.2/plat/rockchip/common/params_setup.c000066400000000000000000000111711355360272700240130ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static struct bl_aux_gpio_info rst_gpio; static struct bl_aux_gpio_info poweroff_gpio; static struct bl_aux_gpio_info suspend_gpio[10]; uint32_t suspend_gpio_cnt; static struct bl_aux_rk_apio_info suspend_apio; #if COREBOOT static int dt_process_fdt(u_register_t param_from_bl2) { return -ENODEV; } #else static uint32_t rk_uart_base = PLAT_RK_UART_BASE; static uint32_t rk_uart_baudrate = PLAT_RK_UART_BAUDRATE; static uint32_t rk_uart_clock = PLAT_RK_UART_CLOCK; static uint8_t fdt_buffer[0x10000]; void *plat_get_fdt(void) { return &fdt_buffer[0]; } static void plat_rockchip_dt_process_fdt_uart(void *fdt) { const char *path_name = "/chosen"; const char *prop_name = "stdout-path"; int node_offset; int stdout_path_len; const char *stdout_path; const char *separator; const char *baud_start; char serial_char; int serial_no; uint32_t uart_base; uint32_t baud; node_offset = fdt_path_offset(fdt, path_name); if (node_offset < 0) return; stdout_path = fdt_getprop(fdt, node_offset, prop_name, &stdout_path_len); if (stdout_path == NULL) return; /* * We expect something like: * "serial0:baudrate" */ if (strncmp("serial", stdout_path, 6) != 0) return; serial_char = stdout_path[6]; serial_no = serial_char - '0'; switch (serial_no) { case 0: uart_base = UART0_BASE; break; case 1: uart_base = UART1_BASE; break; case 2: uart_base = UART2_BASE; break; #ifdef UART3_BASE case 3: uart_base = UART3_BASE; break; #endif #ifdef UART4_BASE case 4: uart_base = UART4_BASE; break; #endif #ifdef UART5_BASE case 5: uart_base = UART5_BASE; break; #endif default: return; } rk_uart_base = uart_base; separator = strchr(stdout_path, ':'); if (!separator) return; baud = 0; baud_start = separator + 1; while (*baud_start != '\0') { /* * uart binding is {{{...}}} * So the baudrate either is the whole string, or * we end in the parity characters. */ if (*baud_start == 'n' || *baud_start == 'o' || *baud_start == 'e') break; baud = baud * 10 + (*baud_start - '0'); baud_start++; } rk_uart_baudrate = baud; } static int dt_process_fdt(u_register_t param_from_bl2) { void *fdt = plat_get_fdt(); int ret; ret = fdt_open_into((void *)param_from_bl2, fdt, 0x10000); if (ret < 0) return ret; plat_rockchip_dt_process_fdt_uart(fdt); return 0; } #endif uint32_t rockchip_get_uart_base(void) { #if COREBOOT return coreboot_serial.baseaddr; #else return rk_uart_base; #endif } uint32_t rockchip_get_uart_baudrate(void) { #if COREBOOT return coreboot_serial.baud; #else return rk_uart_baudrate; #endif } uint32_t rockchip_get_uart_clock(void) { #if COREBOOT return coreboot_serial.input_hertz; #else return rk_uart_clock; #endif } struct bl_aux_gpio_info *plat_get_rockchip_gpio_reset(void) { return &rst_gpio; } struct bl_aux_gpio_info *plat_get_rockchip_gpio_poweroff(void) { return &poweroff_gpio; } struct bl_aux_gpio_info *plat_get_rockchip_suspend_gpio(uint32_t *count) { *count = suspend_gpio_cnt; return &suspend_gpio[0]; } struct bl_aux_rk_apio_info *plat_get_rockchip_suspend_apio(void) { return &suspend_apio; } static bool rk_aux_param_handler(struct bl_aux_param_header *param) { /* Store platform parameters for later processing if needed. */ switch (param->type) { case BL_AUX_PARAM_RK_RESET_GPIO: rst_gpio = ((struct bl_aux_param_gpio *)param)->gpio; return true; case BL_AUX_PARAM_RK_POWEROFF_GPIO: poweroff_gpio = ((struct bl_aux_param_gpio *)param)->gpio; return true; case BL_AUX_PARAM_RK_SUSPEND_GPIO: if (suspend_gpio_cnt >= ARRAY_SIZE(suspend_gpio)) { ERROR("Exceeded the supported suspend GPIO number.\n"); return true; } suspend_gpio[suspend_gpio_cnt++] = ((struct bl_aux_param_gpio *)param)->gpio; return true; case BL_AUX_PARAM_RK_SUSPEND_APIO: suspend_apio = ((struct bl_aux_param_rk_apio *)param)->apio; return true; } return false; } void params_early_setup(u_register_t plat_param_from_bl2) { /* * Test if this is a FDT passed as a platform-specific parameter * block. */ if (!dt_process_fdt(plat_param_from_bl2)) return; bl_aux_params_parse(plat_param_from_bl2, rk_aux_param_handler); } trusted-firmware-a-2.2/plat/rockchip/common/plat_pm.c000066400000000000000000000277061355360272700227570ustar00rootroot00000000000000/* * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include /* Macros to read the rk power domain state */ #define RK_CORE_PWR_STATE(state) \ ((state)->pwr_domain_state[MPIDR_AFFLVL0]) #define RK_CLUSTER_PWR_STATE(state) \ ((state)->pwr_domain_state[MPIDR_AFFLVL1]) #define RK_SYSTEM_PWR_STATE(state) \ ((state)->pwr_domain_state[PLAT_MAX_PWR_LVL]) static uintptr_t rockchip_sec_entrypoint; #pragma weak rockchip_soc_cores_pwr_dm_on #pragma weak rockchip_soc_hlvl_pwr_dm_off #pragma weak rockchip_soc_cores_pwr_dm_off #pragma weak rockchip_soc_sys_pwr_dm_suspend #pragma weak rockchip_soc_cores_pwr_dm_suspend #pragma weak rockchip_soc_hlvl_pwr_dm_suspend #pragma weak rockchip_soc_hlvl_pwr_dm_on_finish #pragma weak rockchip_soc_cores_pwr_dm_on_finish #pragma weak rockchip_soc_sys_pwr_dm_resume #pragma weak rockchip_soc_hlvl_pwr_dm_resume #pragma weak rockchip_soc_cores_pwr_dm_resume #pragma weak rockchip_soc_soft_reset #pragma weak rockchip_soc_system_off #pragma weak rockchip_soc_sys_pd_pwr_dn_wfi #pragma weak rockchip_soc_cores_pd_pwr_dn_wfi int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint) { return PSCI_E_NOT_SUPPORTED; } int rockchip_soc_hlvl_pwr_dm_off(uint32_t lvl, plat_local_state_t lvl_state) { return PSCI_E_NOT_SUPPORTED; } int rockchip_soc_cores_pwr_dm_off(void) { return PSCI_E_NOT_SUPPORTED; } int rockchip_soc_sys_pwr_dm_suspend(void) { return PSCI_E_NOT_SUPPORTED; } int rockchip_soc_cores_pwr_dm_suspend(void) { return PSCI_E_NOT_SUPPORTED; } int rockchip_soc_hlvl_pwr_dm_suspend(uint32_t lvl, plat_local_state_t lvl_state) { return PSCI_E_NOT_SUPPORTED; } int rockchip_soc_hlvl_pwr_dm_on_finish(uint32_t lvl, plat_local_state_t lvl_state) { return PSCI_E_NOT_SUPPORTED; } int rockchip_soc_cores_pwr_dm_on_finish(void) { return PSCI_E_NOT_SUPPORTED; } int rockchip_soc_sys_pwr_dm_resume(void) { return PSCI_E_NOT_SUPPORTED; } int rockchip_soc_hlvl_pwr_dm_resume(uint32_t lvl, plat_local_state_t lvl_state) { return PSCI_E_NOT_SUPPORTED; } int rockchip_soc_cores_pwr_dm_resume(void) { return PSCI_E_NOT_SUPPORTED; } void __dead2 rockchip_soc_soft_reset(void) { while (1) ; } void __dead2 rockchip_soc_system_off(void) { while (1) ; } void __dead2 rockchip_soc_cores_pd_pwr_dn_wfi( const psci_power_state_t *target_state) { psci_power_down_wfi(); } void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void) { psci_power_down_wfi(); } /******************************************************************************* * Rockchip standard platform handler called to check the validity of the power * state parameter. ******************************************************************************/ int rockchip_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { int pstate = psci_get_pstate_type(power_state); int pwr_lvl = psci_get_pstate_pwrlvl(power_state); int i; assert(req_state); if (pwr_lvl > PLAT_MAX_PWR_LVL) return PSCI_E_INVALID_PARAMS; /* Sanity check the requested state */ if (pstate == PSTATE_TYPE_STANDBY) { /* * It's probably to enter standby only on power level 0 * ignore any other power level. */ if (pwr_lvl != MPIDR_AFFLVL0) return PSCI_E_INVALID_PARAMS; req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE; } else { for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++) req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; for (i = (pwr_lvl + 1); i <= PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = PLAT_MAX_RET_STATE; } /* We expect the 'state id' to be zero */ if (psci_get_pstate_id(power_state)) return PSCI_E_INVALID_PARAMS; return PSCI_E_SUCCESS; } void rockchip_get_sys_suspend_power_state(psci_power_state_t *req_state) { int i; for (i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; } /******************************************************************************* * RockChip handler called when a CPU is about to enter standby. ******************************************************************************/ void rockchip_cpu_standby(plat_local_state_t cpu_state) { unsigned int scr; assert(cpu_state == PLAT_MAX_RET_STATE); scr = read_scr_el3(); /* Enable PhysicalIRQ bit for NS world to wake the CPU */ write_scr_el3(scr | SCR_IRQ_BIT); isb(); dsb(); wfi(); /* * Restore SCR to the original value, synchronisation of scr_el3 is * done by eret while el3_exit to save some execution cycles. */ write_scr_el3(scr); } /******************************************************************************* * RockChip handler called when a power domain is about to be turned on. The * mpidr determines the CPU to be turned on. ******************************************************************************/ int rockchip_pwr_domain_on(u_register_t mpidr) { return rockchip_soc_cores_pwr_dm_on(mpidr, rockchip_sec_entrypoint); } /******************************************************************************* * RockChip handler called when a power domain is about to be turned off. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ void rockchip_pwr_domain_off(const psci_power_state_t *target_state) { uint32_t lvl; plat_local_state_t lvl_state; int ret; assert(RK_CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE); plat_rockchip_gic_cpuif_disable(); if (RK_CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) plat_cci_disable(); rockchip_soc_cores_pwr_dm_off(); for (lvl = MPIDR_AFFLVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) { lvl_state = target_state->pwr_domain_state[lvl]; ret = rockchip_soc_hlvl_pwr_dm_off(lvl, lvl_state); if (ret == PSCI_E_NOT_SUPPORTED) break; } } /******************************************************************************* * RockChip handler called when a power domain is about to be suspended. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ void rockchip_pwr_domain_suspend(const psci_power_state_t *target_state) { uint32_t lvl; plat_local_state_t lvl_state; int ret; if (RK_CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) return; /* Prevent interrupts from spuriously waking up this cpu */ plat_rockchip_gic_cpuif_disable(); if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) rockchip_soc_sys_pwr_dm_suspend(); else rockchip_soc_cores_pwr_dm_suspend(); /* Perform the common cluster specific operations */ if (RK_CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) plat_cci_disable(); if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) return; for (lvl = MPIDR_AFFLVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) { lvl_state = target_state->pwr_domain_state[lvl]; ret = rockchip_soc_hlvl_pwr_dm_suspend(lvl, lvl_state); if (ret == PSCI_E_NOT_SUPPORTED) break; } } /******************************************************************************* * RockChip handler called when a power domain has just been powered on after * being turned off earlier. The target_state encodes the low power state that * each level has woken up from. ******************************************************************************/ void rockchip_pwr_domain_on_finish(const psci_power_state_t *target_state) { uint32_t lvl; plat_local_state_t lvl_state; int ret; assert(RK_CORE_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE); for (lvl = MPIDR_AFFLVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) { lvl_state = target_state->pwr_domain_state[lvl]; ret = rockchip_soc_hlvl_pwr_dm_on_finish(lvl, lvl_state); if (ret == PSCI_E_NOT_SUPPORTED) break; } rockchip_soc_cores_pwr_dm_on_finish(); /* Perform the common cluster specific operations */ if (RK_CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { /* Enable coherency if this cluster was off */ plat_cci_enable(); } /* Enable the gic cpu interface */ plat_rockchip_gic_pcpu_init(); /* Program the gic per-cpu distributor or re-distributor interface */ plat_rockchip_gic_cpuif_enable(); } /******************************************************************************* * RockChip handler called when a power domain has just been powered on after * having been suspended earlier. The target_state encodes the low power state * that each level has woken up from. * TODO: At the moment we reuse the on finisher and reinitialize the secure * context. Need to implement a separate suspend finisher. ******************************************************************************/ void rockchip_pwr_domain_suspend_finish(const psci_power_state_t *target_state) { uint32_t lvl; plat_local_state_t lvl_state; int ret; /* Nothing to be done on waking up from retention from CPU level */ if (RK_CORE_PWR_STATE(target_state) != PLAT_MAX_OFF_STATE) return; if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { rockchip_soc_sys_pwr_dm_resume(); goto comm_finish; } for (lvl = MPIDR_AFFLVL1; lvl <= PLAT_MAX_PWR_LVL; lvl++) { lvl_state = target_state->pwr_domain_state[lvl]; ret = rockchip_soc_hlvl_pwr_dm_resume(lvl, lvl_state); if (ret == PSCI_E_NOT_SUPPORTED) break; } rockchip_soc_cores_pwr_dm_resume(); /* * Program the gic per-cpu distributor or re-distributor interface. * For sys power domain operation, resuming of the gic needs to operate * in rockchip_soc_sys_pwr_dm_resume(), according to the sys power mode * implements. */ plat_rockchip_gic_cpuif_enable(); comm_finish: /* Perform the common cluster specific operations */ if (RK_CLUSTER_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) { /* Enable coherency if this cluster was off */ plat_cci_enable(); } } /******************************************************************************* * RockChip handlers to reboot the system ******************************************************************************/ static void __dead2 rockchip_system_reset(void) { rockchip_soc_soft_reset(); } /******************************************************************************* * RockChip handlers to power off the system ******************************************************************************/ static void __dead2 rockchip_system_poweroff(void) { rockchip_soc_system_off(); } static void __dead2 rockchip_pd_pwr_down_wfi( const psci_power_state_t *target_state) { if (RK_SYSTEM_PWR_STATE(target_state) == PLAT_MAX_OFF_STATE) rockchip_soc_sys_pd_pwr_dn_wfi(); else rockchip_soc_cores_pd_pwr_dn_wfi(target_state); } /******************************************************************************* * Export the platform handlers via plat_rockchip_psci_pm_ops. The rockchip * standard * platform layer will take care of registering the handlers with PSCI. ******************************************************************************/ const plat_psci_ops_t plat_rockchip_psci_pm_ops = { .cpu_standby = rockchip_cpu_standby, .pwr_domain_on = rockchip_pwr_domain_on, .pwr_domain_off = rockchip_pwr_domain_off, .pwr_domain_suspend = rockchip_pwr_domain_suspend, .pwr_domain_on_finish = rockchip_pwr_domain_on_finish, .pwr_domain_suspend_finish = rockchip_pwr_domain_suspend_finish, .pwr_domain_pwr_down_wfi = rockchip_pd_pwr_down_wfi, .system_reset = rockchip_system_reset, .system_off = rockchip_system_poweroff, .validate_power_state = rockchip_validate_power_state, .get_sys_suspend_power_state = rockchip_get_sys_suspend_power_state }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { *psci_ops = &plat_rockchip_psci_pm_ops; rockchip_sec_entrypoint = sec_entrypoint; return 0; } uintptr_t plat_get_sec_entrypoint(void) { assert(rockchip_sec_entrypoint); return rockchip_sec_entrypoint; } trusted-firmware-a-2.2/plat/rockchip/common/plat_topology.c000066400000000000000000000016751355360272700242140ustar00rootroot00000000000000/* * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /******************************************************************************* * This function returns the RockChip default topology tree information. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { return rockchip_power_domain_tree_desc; } int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; cpu_id = mpidr & MPIDR_AFFLVL_MASK; #ifdef PLAT_RK_MPIDR_CLUSTER_MASK cluster_id = mpidr & PLAT_RK_MPIDR_CLUSTER_MASK; #else cluster_id = mpidr & MPIDR_CLUSTER_MASK; #endif cpu_id += (cluster_id >> PLAT_RK_CLST_TO_CPUID_SHIFT); if (cpu_id >= PLATFORM_CORE_COUNT) return -1; return cpu_id; } trusted-firmware-a-2.2/plat/rockchip/common/pmusram/000077500000000000000000000000001355360272700226275ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/common/pmusram/cpus_on_fixed_addr.S000066400000000000000000000016611355360272700265760ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl sys_sleep_flag_sram .globl pmu_cpuson_entrypoint .macro pmusram_entry_func _name .section .pmusram.entry, "ax" .type \_name, %function .cfi_startproc \_name: .endm pmusram_entry_func pmu_cpuson_entrypoint adr x5, sys_sleep_flag_sram ldr w2, [x5, #PSRAM_DT_PM_FLAG] tbz w2, #PM_WARM_BOOT_SHT, sys_resume_sp ldr x1, =platform_cpu_warmboot br x1 sys_resume_sp: adr x5, sys_sleep_flag_sram ldr x1, [x5, #PSRAM_DT_SP] mov sp, x1 ddr_resume: ldr x1, [x5, #PSRAM_DT_DDR_FUNC] cmp x1, #0 b.eq sys_resume blr x1 sys_resume: ldr x1, =bl31_warm_entrypoint br x1 endfunc pmu_cpuson_entrypoint .section .pmusram.data, "a" .align 3 sys_sleep_flag_sram: .rept PSRAM_DT_SIZE_WORDS .word 0 .endr trusted-firmware-a-2.2/plat/rockchip/common/pmusram/cpus_on_fixed_addr.h000066400000000000000000000031371355360272700266230ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __CPU_ON_FIXED_ADDR_H__ #define __CPU_ON_FIXED_ADDR_H__ /***************************************************************************** * define data offset in struct psram_data *****************************************************************************/ #define PSRAM_DT_SP 0x0 #define PSRAM_DT_DDR_FUNC 0x8 #define PSRAM_DT_DDR_DATA 0x10 #define PSRAM_DT_DDRFLAG 0x18 #define PSRAM_DT_MPIDR 0x1c #define PSRAM_DT_PM_FLAG 0x20 #define PSRAM_DT_END 0x24 /* reserve 4 byte */ #define PSRAM_DT_END_RES4 (PSRAM_DT_END + 4) #define PSRAM_DT_SIZE_WORDS (PSRAM_DT_END_RES4 / 4) #define PM_WARM_BOOT_SHT 0 #define PM_WARM_BOOT_BIT (1 << PM_WARM_BOOT_SHT) #ifndef __ASSEMBLER__ struct psram_data_t { uint64_t sp; uint64_t ddr_func; uint64_t ddr_data; uint32_t ddr_flag; uint32_t boot_mpidr; uint32_t pm_flag; }; CASSERT(__builtin_offsetof(struct psram_data_t, sp) == PSRAM_DT_SP, assert_psram_dt_sp_offset_mistmatch); CASSERT(__builtin_offsetof(struct psram_data_t, ddr_func) == PSRAM_DT_DDR_FUNC, assert_psram_dt_ddr_func_offset_mistmatch); CASSERT(__builtin_offsetof(struct psram_data_t, ddr_data) == PSRAM_DT_DDR_DATA, assert_psram_dt_ddr_data_offset_mistmatch); CASSERT(__builtin_offsetof(struct psram_data_t, ddr_flag) == PSRAM_DT_DDRFLAG, assert_psram_dt_ddr_flag_offset_mistmatch); CASSERT(__builtin_offsetof(struct psram_data_t, boot_mpidr) == PSRAM_DT_MPIDR, assert_psram_dt_mpidr_offset_mistmatch); extern void *sys_sleep_flag_sram; #endif /* __ASSEMBLER__ */ #endif trusted-firmware-a-2.2/plat/rockchip/common/rockchip_gicv2.c000066400000000000000000000053311355360272700242050ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /****************************************************************************** * The following functions are defined as weak to allow a platform to override * the way the GICv2 driver is initialised and used. *****************************************************************************/ #pragma weak plat_rockchip_gic_driver_init #pragma weak plat_rockchip_gic_init #pragma weak plat_rockchip_gic_cpuif_enable #pragma weak plat_rockchip_gic_cpuif_disable #pragma weak plat_rockchip_gic_pcpu_init /****************************************************************************** * List of interrupts. *****************************************************************************/ static const interrupt_prop_t g0_interrupt_props[] = { PLAT_RK_GICV2_G0_IRQS }; /* * Ideally `rockchip_gic_data` structure definition should be a `const` but it * is kept as modifiable for overwriting with different GICD and GICC base when * running on FVP with VE memory map. */ gicv2_driver_data_t rockchip_gic_data = { .gicd_base = PLAT_RK_GICD_BASE, .gicc_base = PLAT_RK_GICC_BASE, .interrupt_props = g0_interrupt_props, .interrupt_props_num = ARRAY_SIZE(g0_interrupt_props), }; /****************************************************************************** * RockChip common helper to initialize the GICv2 only driver. *****************************************************************************/ void plat_rockchip_gic_driver_init(void) { gicv2_driver_init(&rockchip_gic_data); } void plat_rockchip_gic_init(void) { gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } /****************************************************************************** * RockChip common helper to enable the GICv2 CPU interface *****************************************************************************/ void plat_rockchip_gic_cpuif_enable(void) { gicv2_cpuif_enable(); } /****************************************************************************** * RockChip common helper to disable the GICv2 CPU interface *****************************************************************************/ void plat_rockchip_gic_cpuif_disable(void) { gicv2_cpuif_disable(); } /****************************************************************************** * RockChip common helper to initialize the per cpu distributor interface * in GICv2 *****************************************************************************/ void plat_rockchip_gic_pcpu_init(void) { gicv2_pcpu_distif_init(); } trusted-firmware-a-2.2/plat/rockchip/common/rockchip_gicv3.c000066400000000000000000000062041355360272700242060ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /****************************************************************************** * The following functions are defined as weak to allow a platform to override * the way the GICv3 driver is initialised and used. *****************************************************************************/ #pragma weak plat_rockchip_gic_driver_init #pragma weak plat_rockchip_gic_init #pragma weak plat_rockchip_gic_cpuif_enable #pragma weak plat_rockchip_gic_cpuif_disable #pragma weak plat_rockchip_gic_pcpu_init /* The GICv3 driver only needs to be initialized in EL3 */ uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT]; static const interrupt_prop_t g01s_interrupt_props[] = { PLAT_RK_GICV3_G0_IRQS, PLAT_RK_GICV3_G1S_IRQS }; static unsigned int plat_rockchip_mpidr_to_core_pos(unsigned long mpidr) { return (unsigned int)plat_core_pos_by_mpidr(mpidr); } const gicv3_driver_data_t rockchip_gic_data = { .gicd_base = PLAT_RK_GICD_BASE, .gicr_base = PLAT_RK_GICR_BASE, .interrupt_props = g01s_interrupt_props, .interrupt_props_num = ARRAY_SIZE(g01s_interrupt_props), .rdistif_num = PLATFORM_CORE_COUNT, .rdistif_base_addrs = rdistif_base_addrs, .mpidr_to_core_pos = plat_rockchip_mpidr_to_core_pos, }; void plat_rockchip_gic_driver_init(void) { /* * The GICv3 driver is initialized in EL3 and does not need * to be initialized again in SEL1. This is because the S-EL1 * can use GIC system registers to manage interrupts and does * not need GIC interface base addresses to be configured. */ #ifdef IMAGE_BL31 gicv3_driver_init(&rockchip_gic_data); #endif } /****************************************************************************** * RockChip common helper to initialize the GIC. Only invoked * by BL31 *****************************************************************************/ void plat_rockchip_gic_init(void) { gicv3_distif_init(); gicv3_rdistif_init(plat_my_core_pos()); gicv3_cpuif_enable(plat_my_core_pos()); } /****************************************************************************** * RockChip common helper to enable the GIC CPU interface *****************************************************************************/ void plat_rockchip_gic_cpuif_enable(void) { gicv3_cpuif_enable(plat_my_core_pos()); } /****************************************************************************** * RockChip common helper to disable the GIC CPU interface *****************************************************************************/ void plat_rockchip_gic_cpuif_disable(void) { gicv3_cpuif_disable(plat_my_core_pos()); } /****************************************************************************** * RockChip common helper to initialize the per-cpu redistributor interface * in GICv3 *****************************************************************************/ void plat_rockchip_gic_pcpu_init(void) { gicv3_rdistif_init(plat_my_core_pos()); } trusted-firmware-a-2.2/plat/rockchip/common/rockchip_sip_svc.c000066400000000000000000000036311355360272700246420ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* Rockchip SiP Service UUID */ DEFINE_SVC_UUID2(rk_sip_svc_uid, 0xe2c76fe8, 0x3e31, 0xe611, 0xb7, 0x0d, 0x8f, 0x88, 0xee, 0x74, 0x7b, 0x72); #pragma weak rockchip_plat_sip_handler uintptr_t rockchip_plat_sip_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) { ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); SMC_RET1(handle, SMC_UNK); } /* * This function is responsible for handling all SiP calls from the NS world */ uintptr_t sip_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 ns; /* Determine which security state this SMC originated from */ ns = is_caller_non_secure(flags); if (!ns) SMC_RET1(handle, SMC_UNK); switch (smc_fid) { case SIP_SVC_CALL_COUNT: /* Return the number of Rockchip SiP Service Calls. */ SMC_RET1(handle, RK_COMMON_SIP_NUM_CALLS + RK_PLAT_SIP_NUM_CALLS); case SIP_SVC_UID: /* Return UID to the caller */ SMC_UUID_RET(handle, rk_sip_svc_uid); case SIP_SVC_VERSION: /* Return the version of current implementation */ SMC_RET2(handle, RK_SIP_SVC_VERSION_MAJOR, RK_SIP_SVC_VERSION_MINOR); default: return rockchip_plat_sip_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); } } /* Define a runtime service descriptor for fast SMC calls */ DECLARE_RT_SVC( rockchip_sip_svc, OEN_SIP_START, OEN_SIP_END, SMC_TYPE_FAST, NULL, sip_smc_handler ); trusted-firmware-a-2.2/plat/rockchip/common/sp_min_plat_setup.c000066400000000000000000000057071355360272700250450ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include static entry_point_info_t bl33_ep_info; /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for * the security state specified. BL33 corresponds to the non-secure image type. * A NULL pointer is returned if the image does not exist. ******************************************************************************/ entry_point_info_t *sp_min_plat_get_bl33_ep_info(void) { entry_point_info_t *next_image_info; next_image_info = &bl33_ep_info; if (next_image_info->pc == 0U) { return NULL; } return next_image_info; } #pragma weak params_early_setup void params_early_setup(u_register_t plat_param_from_bl2) { } unsigned int plat_is_my_cpu_primary(void); /******************************************************************************* * Perform any BL32 specific platform actions. ******************************************************************************/ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { static console_16550_t console; params_early_setup(arg1); if (rockchip_get_uart_base() != 0) console_16550_register(rockchip_get_uart_base(), rockchip_get_uart_clock(), rockchip_get_uart_baudrate(), &console); VERBOSE("sp_min_setup\n"); bl31_params_parse_helper(arg0, NULL, &bl33_ep_info); } /******************************************************************************* * Perform any sp_min platform setup code ******************************************************************************/ void sp_min_platform_setup(void) { generic_delay_timer_init(); plat_rockchip_soc_init(); /* Initialize the gic cpu and distributor interfaces */ plat_rockchip_gic_driver_init(); plat_rockchip_gic_init(); plat_rockchip_pmu_init(); } /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this is only intializes the mmu in a quick and dirty way. ******************************************************************************/ void sp_min_plat_arch_setup(void) { plat_cci_init(); plat_cci_enable(); plat_configure_mmu_svc_mon(BL_CODE_BASE, BL_COHERENT_RAM_END - BL_CODE_BASE, BL_CODE_BASE, BL_CODE_END, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END); } void sp_min_plat_fiq_handler(uint32_t id) { VERBOSE("[sp_min] interrupt #%d\n", id); } trusted-firmware-a-2.2/plat/rockchip/px30/000077500000000000000000000000001355360272700204455ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/px30/drivers/000077500000000000000000000000001355360272700221235ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/px30/drivers/pmu/000077500000000000000000000000001355360272700227245ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/px30/drivers/pmu/plat_pmu_macros.S000066400000000000000000000005631355360272700262410ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl clst_warmboot_data .macro func_rockchip_clst_warmboot .endm .macro rockchip_clst_warmboot_data clst_warmboot_data: .rept PLATFORM_CLUSTER_COUNT .word 0 .endr .endm trusted-firmware-a-2.2/plat/rockchip/px30/drivers/pmu/pmu.c000066400000000000000000000704461355360272700237040ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include DEFINE_BAKERY_LOCK(rockchip_pd_lock); #define rockchip_pd_lock_init() bakery_lock_init(&rockchip_pd_lock) #define rockchip_pd_lock_get() bakery_lock_get(&rockchip_pd_lock) #define rockchip_pd_lock_rls() bakery_lock_release(&rockchip_pd_lock) static struct psram_data_t *psram_boot_cfg = (struct psram_data_t *)&sys_sleep_flag_sram; /* * There are two ways to powering on or off on core. * 1) Control it power domain into on or off in PMU_PWRDN_CON reg, * it is core_pwr_pd mode * 2) Enable the core power manage in PMU_CORE_PM_CON reg, * then, if the core enter into wfi, it power domain will be * powered off automatically. it is core_pwr_wfi or core_pwr_wfi_int mode * so we need core_pm_cfg_info to distinguish which method be used now. */ static uint32_t cores_pd_cfg_info[PLATFORM_CORE_COUNT] #if USE_COHERENT_MEM __attribute__ ((section("tzfw_coherent_mem"))) #endif ; struct px30_sleep_ddr_data { uint32_t clk_sel0; uint32_t cru_mode_save; uint32_t cru_pmu_mode_save; uint32_t ddrc_hwlpctl; uint32_t ddrc_pwrctrl; uint32_t ddrgrf_con0; uint32_t ddrgrf_con1; uint32_t ddrstdby_con0; uint32_t gpio0b_iomux; uint32_t gpio0c_iomux; uint32_t pmu_pwrmd_core_l; uint32_t pmu_pwrmd_core_h; uint32_t pmu_pwrmd_cmm_l; uint32_t pmu_pwrmd_cmm_h; uint32_t pmu_wkup_cfg2_l; uint32_t pmu_cru_clksel_con0; uint32_t pmugrf_soc_con0; uint32_t pmusgrf_soc_con0; uint32_t pmic_slp_iomux; uint32_t pgrf_pvtm_con[2]; uint32_t cru_clk_gate[CRU_CLKGATES_CON_CNT]; uint32_t cru_pmu_clk_gate[CRU_PMU_CLKGATE_CON_CNT]; uint32_t cru_plls_con_save[END_PLL_ID][PLL_CON_CNT]; uint32_t cpu_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t gpu_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t isp_128m_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t isp_rd_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t isp_wr_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t isp_m1_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t vip_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t rga_rd_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t rga_wr_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t vop_m0_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t vop_m1_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t vpu_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t vpu_r128_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t dcf_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t dmac_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t crypto_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t gmac_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t emmc_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t nand_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t sdio_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t sfc_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t sdmmc_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t usb_host_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t usb_otg_qos[CPU_AXI_QOS_NUM_REGS]; }; static struct px30_sleep_ddr_data ddr_data #if USE_COHERENT_MEM __attribute__ ((section("tzfw_coherent_mem"))) #endif ; static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id) { assert(cpu_id < PLATFORM_CORE_COUNT); return cores_pd_cfg_info[cpu_id]; } static inline void set_cpus_pwr_domain_cfg_info(uint32_t cpu_id, uint32_t value) { assert(cpu_id < PLATFORM_CORE_COUNT); cores_pd_cfg_info[cpu_id] = value; #if !USE_COHERENT_MEM flush_dcache_range((uintptr_t)&cores_pd_cfg_info[cpu_id], sizeof(uint32_t)); #endif } static inline uint32_t pmu_power_domain_st(uint32_t pd) { return mmio_read_32(PMU_BASE + PMU_PWRDN_ST) & BIT(pd) ? pmu_pd_off : pmu_pd_on; } static int pmu_power_domain_ctr(uint32_t pd, uint32_t pd_state) { uint32_t loop = 0; int ret = 0; rockchip_pd_lock_get(); mmio_write_32(PMU_BASE + PMU_PWRDN_CON, BITS_WITH_WMASK(pd_state, 0x1, pd)); dsb(); while ((pmu_power_domain_st(pd) != pd_state) && (loop < PD_CTR_LOOP)) { udelay(1); loop++; } if (pmu_power_domain_st(pd) != pd_state) { WARN("%s: %d, %d, error!\n", __func__, pd, pd_state); ret = -EINVAL; } rockchip_pd_lock_rls(); return ret; } static inline uint32_t pmu_bus_idle_st(uint32_t bus) { return !!((mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & BIT(bus)) && (mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & BIT(bus + 16))); } static void pmu_bus_idle_req(uint32_t bus, uint32_t state) { uint32_t wait_cnt = 0; mmio_write_32(PMU_BASE + PMU_BUS_IDLE_REQ, BITS_WITH_WMASK(state, 0x1, bus)); while (pmu_bus_idle_st(bus) != state && wait_cnt < BUS_IDLE_LOOP) { udelay(1); wait_cnt++; } if (pmu_bus_idle_st(bus) != state) WARN("%s:idle_st=0x%x, bus_id=%d\n", __func__, mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST), bus); } static void qos_save(void) { /* scu powerdomain will power off, so cpu qos should be saved */ SAVE_QOS(ddr_data.cpu_qos, CPU); if (pmu_power_domain_st(PD_GPU) == pmu_pd_on) SAVE_QOS(ddr_data.gpu_qos, GPU); if (pmu_power_domain_st(PD_VI) == pmu_pd_on) { SAVE_QOS(ddr_data.isp_128m_qos, ISP_128M); SAVE_QOS(ddr_data.isp_rd_qos, ISP_RD); SAVE_QOS(ddr_data.isp_wr_qos, ISP_WR); SAVE_QOS(ddr_data.isp_m1_qos, ISP_M1); SAVE_QOS(ddr_data.vip_qos, VIP); } if (pmu_power_domain_st(PD_VO) == pmu_pd_on) { SAVE_QOS(ddr_data.rga_rd_qos, RGA_RD); SAVE_QOS(ddr_data.rga_wr_qos, RGA_WR); SAVE_QOS(ddr_data.vop_m0_qos, VOP_M0); SAVE_QOS(ddr_data.vop_m1_qos, VOP_M1); } if (pmu_power_domain_st(PD_VPU) == pmu_pd_on) { SAVE_QOS(ddr_data.vpu_qos, VPU); SAVE_QOS(ddr_data.vpu_r128_qos, VPU_R128); } if (pmu_power_domain_st(PD_MMC_NAND) == pmu_pd_on) { SAVE_QOS(ddr_data.emmc_qos, EMMC); SAVE_QOS(ddr_data.nand_qos, NAND); SAVE_QOS(ddr_data.sdio_qos, SDIO); SAVE_QOS(ddr_data.sfc_qos, SFC); } if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on) SAVE_QOS(ddr_data.gmac_qos, GMAC); if (pmu_power_domain_st(PD_CRYPTO) == pmu_pd_on) SAVE_QOS(ddr_data.crypto_qos, CRYPTO); if (pmu_power_domain_st(PD_SDCARD) == pmu_pd_on) SAVE_QOS(ddr_data.sdmmc_qos, SDMMC); if (pmu_power_domain_st(PD_USB) == pmu_pd_on) { SAVE_QOS(ddr_data.usb_host_qos, USB_HOST); SAVE_QOS(ddr_data.usb_otg_qos, USB_OTG); } } static void qos_restore(void) { RESTORE_QOS(ddr_data.cpu_qos, CPU); if (pmu_power_domain_st(PD_GPU) == pmu_pd_on) RESTORE_QOS(ddr_data.gpu_qos, GPU); if (pmu_power_domain_st(PD_VI) == pmu_pd_on) { RESTORE_QOS(ddr_data.isp_128m_qos, ISP_128M); RESTORE_QOS(ddr_data.isp_rd_qos, ISP_RD); RESTORE_QOS(ddr_data.isp_wr_qos, ISP_WR); RESTORE_QOS(ddr_data.isp_m1_qos, ISP_M1); RESTORE_QOS(ddr_data.vip_qos, VIP); } if (pmu_power_domain_st(PD_VO) == pmu_pd_on) { RESTORE_QOS(ddr_data.rga_rd_qos, RGA_RD); RESTORE_QOS(ddr_data.rga_wr_qos, RGA_WR); RESTORE_QOS(ddr_data.vop_m0_qos, VOP_M0); RESTORE_QOS(ddr_data.vop_m1_qos, VOP_M1); } if (pmu_power_domain_st(PD_VPU) == pmu_pd_on) { RESTORE_QOS(ddr_data.vpu_qos, VPU); RESTORE_QOS(ddr_data.vpu_r128_qos, VPU_R128); } if (pmu_power_domain_st(PD_MMC_NAND) == pmu_pd_on) { RESTORE_QOS(ddr_data.emmc_qos, EMMC); RESTORE_QOS(ddr_data.nand_qos, NAND); RESTORE_QOS(ddr_data.sdio_qos, SDIO); RESTORE_QOS(ddr_data.sfc_qos, SFC); } if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on) RESTORE_QOS(ddr_data.gmac_qos, GMAC); if (pmu_power_domain_st(PD_CRYPTO) == pmu_pd_on) RESTORE_QOS(ddr_data.crypto_qos, CRYPTO); if (pmu_power_domain_st(PD_SDCARD) == pmu_pd_on) RESTORE_QOS(ddr_data.sdmmc_qos, SDMMC); if (pmu_power_domain_st(PD_USB) == pmu_pd_on) { RESTORE_QOS(ddr_data.usb_host_qos, USB_HOST); RESTORE_QOS(ddr_data.usb_otg_qos, USB_OTG); } } static int pmu_set_power_domain(uint32_t pd_id, uint32_t pd_state) { uint32_t state; if (pmu_power_domain_st(pd_id) == pd_state) goto out; if (pd_state == pmu_pd_on) pmu_power_domain_ctr(pd_id, pd_state); state = (pd_state == pmu_pd_off) ? bus_idle : bus_active; switch (pd_id) { case PD_GPU: pmu_bus_idle_req(BUS_ID_GPU, state); break; case PD_VI: pmu_bus_idle_req(BUS_ID_VI, state); break; case PD_VO: pmu_bus_idle_req(BUS_ID_VO, state); break; case PD_VPU: pmu_bus_idle_req(BUS_ID_VPU, state); break; case PD_MMC_NAND: pmu_bus_idle_req(BUS_ID_MMC, state); break; case PD_GMAC: pmu_bus_idle_req(BUS_ID_GMAC, state); break; case PD_CRYPTO: pmu_bus_idle_req(BUS_ID_CRYPTO, state); break; case PD_SDCARD: pmu_bus_idle_req(BUS_ID_SDCARD, state); break; case PD_USB: pmu_bus_idle_req(BUS_ID_USB, state); break; default: break; } if (pd_state == pmu_pd_off) pmu_power_domain_ctr(pd_id, pd_state); out: return 0; } static uint32_t pmu_powerdomain_state; static void pmu_power_domains_suspend(void) { uint32_t clkgt_save[CRU_CLKGATES_CON_CNT + CRU_PMU_CLKGATE_CON_CNT]; clk_gate_con_save(clkgt_save); clk_gate_con_disable(); qos_save(); pmu_powerdomain_state = mmio_read_32(PMU_BASE + PMU_PWRDN_ST); pmu_set_power_domain(PD_GPU, pmu_pd_off); pmu_set_power_domain(PD_VI, pmu_pd_off); pmu_set_power_domain(PD_VO, pmu_pd_off); pmu_set_power_domain(PD_VPU, pmu_pd_off); pmu_set_power_domain(PD_MMC_NAND, pmu_pd_off); pmu_set_power_domain(PD_GMAC, pmu_pd_off); pmu_set_power_domain(PD_CRYPTO, pmu_pd_off); pmu_set_power_domain(PD_SDCARD, pmu_pd_off); pmu_set_power_domain(PD_USB, pmu_pd_off); clk_gate_con_restore(clkgt_save); } static void pmu_power_domains_resume(void) { uint32_t clkgt_save[CRU_CLKGATES_CON_CNT + CRU_PMU_CLKGATE_CON_CNT]; clk_gate_con_save(clkgt_save); clk_gate_con_disable(); if (!(pmu_powerdomain_state & BIT(PD_USB))) pmu_set_power_domain(PD_USB, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_SDCARD))) pmu_set_power_domain(PD_SDCARD, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_CRYPTO))) pmu_set_power_domain(PD_CRYPTO, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_GMAC))) pmu_set_power_domain(PD_GMAC, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_MMC_NAND))) pmu_set_power_domain(PD_MMC_NAND, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_VPU))) pmu_set_power_domain(PD_VPU, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_VO))) pmu_set_power_domain(PD_VO, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_VI))) pmu_set_power_domain(PD_VI, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_GPU))) pmu_set_power_domain(PD_GPU, pmu_pd_on); qos_restore(); clk_gate_con_restore(clkgt_save); } static int check_cpu_wfie(uint32_t cpu) { uint32_t loop = 0, wfie_msk = CKECK_WFEI_MSK << cpu; while (!(mmio_read_32(GRF_BASE + GRF_CPU_STATUS1) & wfie_msk) && (loop < WFEI_CHECK_LOOP)) { udelay(1); loop++; } if ((mmio_read_32(GRF_BASE + GRF_CPU_STATUS1) & wfie_msk) == 0) { WARN("%s: %d, %d, error!\n", __func__, cpu, wfie_msk); return -EINVAL; } return 0; } static int cpus_power_domain_on(uint32_t cpu_id) { uint32_t cpu_pd, apm_value, cfg_info, loop = 0; cpu_pd = PD_CPU0 + cpu_id; cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id); if (cfg_info == core_pwr_pd) { /* disable apm cfg */ mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), WITH_16BITS_WMSK(CORES_PM_DISABLE)); if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) { mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), WITH_16BITS_WMSK(CORES_PM_DISABLE)); pmu_power_domain_ctr(cpu_pd, pmu_pd_off); } pmu_power_domain_ctr(cpu_pd, pmu_pd_on); } else { /* wait cpu down */ while (pmu_power_domain_st(cpu_pd) == pmu_pd_on && loop < 100) { udelay(2); loop++; } /* return error if can't wait cpu down */ if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) { WARN("%s:can't wait cpu down\n", __func__); return -EINVAL; } /* power up cpu in power down state */ apm_value = BIT(core_pm_sft_wakeup_en); mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), WITH_16BITS_WMSK(apm_value)); } return 0; } static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg) { uint32_t cpu_pd, apm_value; cpu_pd = PD_CPU0 + cpu_id; if (pmu_power_domain_st(cpu_pd) == pmu_pd_off) return 0; if (pd_cfg == core_pwr_pd) { if (check_cpu_wfie(cpu_id)) return -EINVAL; /* disable apm cfg */ mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), WITH_16BITS_WMSK(CORES_PM_DISABLE)); set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg); pmu_power_domain_ctr(cpu_pd, pmu_pd_off); } else { set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg); apm_value = BIT(core_pm_en) | BIT(core_pm_dis_int); if (pd_cfg == core_pwr_wfi_int) apm_value |= BIT(core_pm_int_wakeup_en); mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), WITH_16BITS_WMSK(apm_value)); } return 0; } static void nonboot_cpus_off(void) { uint32_t boot_cpu, cpu; boot_cpu = plat_my_core_pos(); for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) { if (cpu == boot_cpu) continue; cpus_power_domain_off(cpu, core_pwr_pd); } } int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint) { uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr); assert(cpu_id < PLATFORM_CORE_COUNT); assert(cpuson_flags[cpu_id] == 0); cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG; cpuson_entry_point[cpu_id] = entrypoint; dsb(); cpus_power_domain_on(cpu_id); return PSCI_E_SUCCESS; } int rockchip_soc_cores_pwr_dm_on_finish(void) { uint32_t cpu_id = plat_my_core_pos(); mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), WITH_16BITS_WMSK(CORES_PM_DISABLE)); return PSCI_E_SUCCESS; } int rockchip_soc_cores_pwr_dm_off(void) { uint32_t cpu_id = plat_my_core_pos(); cpus_power_domain_off(cpu_id, core_pwr_wfi); return PSCI_E_SUCCESS; } int rockchip_soc_cores_pwr_dm_suspend(void) { uint32_t cpu_id = plat_my_core_pos(); assert(cpu_id < PLATFORM_CORE_COUNT); assert(cpuson_flags[cpu_id] == 0); cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN; cpuson_entry_point[cpu_id] = plat_get_sec_entrypoint(); dsb(); cpus_power_domain_off(cpu_id, core_pwr_wfi_int); return PSCI_E_SUCCESS; } int rockchip_soc_cores_pwr_dm_resume(void) { uint32_t cpu_id = plat_my_core_pos(); /* Disable core_pm */ mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), WITH_16BITS_WMSK(CORES_PM_DISABLE)); return PSCI_E_SUCCESS; } #define CLK_MSK_GATING(msk, con) \ mmio_write_32(CRU_BASE + (con), ((msk) << 16) | 0xffff) #define CLK_MSK_UNGATING(msk, con) \ mmio_write_32(CRU_BASE + (con), ((~(msk)) << 16) | 0xffff) static uint32_t clk_ungt_msk[CRU_CLKGATES_CON_CNT] = { 0xe0ff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0380, 0x0000, 0x0000, 0x07c0, 0x0000, 0x0000, 0x000f, 0x0061, 0x1f02, 0x0440, 0x1801, 0x004b, 0x0000 }; static uint32_t clk_pmu_ungt_msk[CRU_PMU_CLKGATE_CON_CNT] = { 0xf1ff, 0x0310 }; void clk_gate_suspend(void) { int i; for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) { ddr_data.cru_clk_gate[i] = mmio_read_32(CRU_BASE + CRU_CLKGATES_CON(i)); mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), WITH_16BITS_WMSK(~clk_ungt_msk[i])); } for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++) { ddr_data.cru_pmu_clk_gate[i] = mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i)); mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i), WITH_16BITS_WMSK(~clk_pmu_ungt_msk[i])); } } void clk_gate_resume(void) { int i; for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++) mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i), WITH_16BITS_WMSK(ddr_data.cru_pmu_clk_gate[i])); for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), WITH_16BITS_WMSK(ddr_data.cru_clk_gate[i])); } static void pvtm_32k_config(void) { uint32_t pvtm_freq_khz, pvtm_div; ddr_data.pmu_cru_clksel_con0 = mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0)); ddr_data.pgrf_pvtm_con[0] = mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_CON0); ddr_data.pgrf_pvtm_con[1] = mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_CON1); mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0, BITS_WITH_WMASK(0, 0x3, pgrf_pvtm_st)); dsb(); mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0, BITS_WITH_WMASK(1, 0x1, pgrf_pvtm_en)); dsb(); mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON1, PVTM_CALC_CNT); dsb(); mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0, BITS_WITH_WMASK(1, 0x1, pgrf_pvtm_st)); /* pmugrf_pvtm_st0 will be clear after PVTM start, * which will cost about 6 cycles of pvtm at least. * So we wait 30 cycles of pvtm for security. */ while (mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST1) < 30) ; dsb(); while (!(mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST0) & 0x1)) ; pvtm_freq_khz = (mmio_read_32(PMUGRF_BASE + PMUGRF_PVTM_ST1) * 24000 + PVTM_CALC_CNT / 2) / PVTM_CALC_CNT; pvtm_div = (pvtm_freq_khz + 16) / 32; /* pvtm_div = div_factor << 2 + 1, * so div_factor = (pvtm_div - 1) >> 2. * But the operation ">> 2" will clear the low bit of pvtm_div, * so we don't have to do "- 1" for compasation */ pvtm_div = pvtm_div >> 2; if (pvtm_div > 0x3f) pvtm_div = 0x3f; mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0, BITS_WITH_WMASK(pvtm_div, 0x3f, pgrf_pvtm_div)); /* select pvtm as 32k source */ mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0), BITS_WITH_WMASK(1, 0x3U, 14)); } static void pvtm_32k_config_restore(void) { mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKSELS_CON(0), ddr_data.pmu_cru_clksel_con0 | BITS_WMSK(0x3U, 14)); mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON0, WITH_16BITS_WMSK(ddr_data.pgrf_pvtm_con[0])); mmio_write_32(PMUGRF_BASE + PMUGRF_PVTM_CON1, ddr_data.pgrf_pvtm_con[1]); } static void ddr_sleep_config(void) { /* disable ddr pd, sr */ ddr_data.ddrc_pwrctrl = mmio_read_32(DDR_UPCTL_BASE + 0x30); mmio_write_32(DDR_UPCTL_BASE + 0x30, BITS_WITH_WMASK(0x0, 0x3, 0)); /* disable ddr auto gt */ ddr_data.ddrgrf_con1 = mmio_read_32(DDRGRF_BASE + 0x4); mmio_write_32(DDRGRF_BASE + 0x4, BITS_WITH_WMASK(0x0, 0x1f, 0)); /* disable ddr standby */ ddr_data.ddrstdby_con0 = mmio_read_32(DDR_STDBY_BASE + 0x0); mmio_write_32(DDR_STDBY_BASE + 0x0, BITS_WITH_WMASK(0x0, 0x1, 0)); while ((mmio_read_32(DDR_UPCTL_BASE + 0x4) & 0x7) != 1) ; /* ddr pmu ctrl */ ddr_data.ddrgrf_con0 = mmio_read_32(DDRGRF_BASE + 0x0); mmio_write_32(DDRGRF_BASE + 0x0, BITS_WITH_WMASK(0x0, 0x1, 5)); dsb(); mmio_write_32(DDRGRF_BASE + 0x0, BITS_WITH_WMASK(0x1, 0x1, 4)); /* ddr ret sel */ ddr_data.pmugrf_soc_con0 = mmio_read_32(PMUGRF_BASE + PMUGRF_SOC_CON(0)); mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(0), BITS_WITH_WMASK(0x0, 0x1, 12)); } static void ddr_sleep_config_restore(void) { /* restore ddr ret sel */ mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(0), ddr_data.pmugrf_soc_con0 | BITS_WMSK(0x1, 12)); /* restore ddr pmu ctrl */ mmio_write_32(DDRGRF_BASE + 0x0, ddr_data.ddrgrf_con0 | BITS_WMSK(0x1, 4)); dsb(); mmio_write_32(DDRGRF_BASE + 0x0, ddr_data.ddrgrf_con0 | BITS_WMSK(0x1, 5)); /* restore ddr standby */ mmio_write_32(DDR_STDBY_BASE + 0x0, ddr_data.ddrstdby_con0 | BITS_WMSK(0x1, 0)); /* restore ddr auto gt */ mmio_write_32(DDRGRF_BASE + 0x4, ddr_data.ddrgrf_con1 | BITS_WMSK(0x1f, 0)); /* restore ddr pd, sr */ mmio_write_32(DDR_UPCTL_BASE + 0x30, ddr_data.ddrc_pwrctrl | BITS_WMSK(0x3, 0)); } static void pmu_sleep_config(void) { uint32_t pwrmd_core_lo, pwrmd_core_hi, pwrmd_com_lo, pwrmd_com_hi; uint32_t pmu_wkup_cfg2_lo; uint32_t clk_freq_khz; /* save pmic_sleep iomux gpio0_a4 */ ddr_data.pmic_slp_iomux = mmio_read_32(PMUGRF_BASE + GPIO0A_IOMUX); ddr_data.pmu_pwrmd_core_l = mmio_read_32(PMU_BASE + PMU_PWRMODE_CORE_LO); ddr_data.pmu_pwrmd_core_h = mmio_read_32(PMU_BASE + PMU_PWRMODE_CORE_HI); ddr_data.pmu_pwrmd_cmm_l = mmio_read_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO); ddr_data.pmu_pwrmd_cmm_h = mmio_read_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI); ddr_data.pmu_wkup_cfg2_l = mmio_read_32(PMU_BASE + PMU_WKUP_CFG2_LO); pwrmd_core_lo = BIT(pmu_global_int_dis) | BIT(pmu_core_src_gt) | BIT(pmu_cpu0_pd) | BIT(pmu_clr_core) | BIT(pmu_scu_pd) | BIT(pmu_l2_idle) | BIT(pmu_l2_flush) | BIT(pmu_clr_bus2main) | BIT(pmu_clr_peri2msch); pwrmd_core_hi = BIT(pmu_dpll_pd_en) | BIT(pmu_apll_pd_en) | BIT(pmu_cpll_pd_en) | BIT(pmu_gpll_pd_en) | BIT(pmu_npll_pd_en); pwrmd_com_lo = BIT(pmu_mode_en) | BIT(pmu_pll_pd) | BIT(pmu_pmu_use_if) | BIT(pmu_alive_use_if) | BIT(pmu_osc_dis) | BIT(pmu_sref_enter) | BIT(pmu_ddrc_gt) | BIT(pmu_clr_pmu) | BIT(pmu_clr_peri_pmu); pwrmd_com_hi = BIT(pmu_clr_bus) | BIT(pmu_clr_msch) | BIT(pmu_wakeup_begin_cfg); pmu_wkup_cfg2_lo = BIT(pmu_cluster_wkup_en) | BIT(pmu_gpio_wkup_en) | BIT(pmu_timer_wkup_en); /* set pmic_sleep iomux gpio0_a4 */ mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX, BITS_WITH_WMASK(1, 0x3, 8)); clk_freq_khz = 32; mmio_write_32(PMU_BASE + PMU_OSC_CNT_LO, WITH_16BITS_WMSK(clk_freq_khz * 32 & 0xffff)); mmio_write_32(PMU_BASE + PMU_OSC_CNT_HI, WITH_16BITS_WMSK(clk_freq_khz * 32 >> 16)); mmio_write_32(PMU_BASE + PMU_STABLE_CNT_LO, WITH_16BITS_WMSK(clk_freq_khz * 32 & 0xffff)); mmio_write_32(PMU_BASE + PMU_STABLE_CNT_HI, WITH_16BITS_WMSK(clk_freq_khz * 32 >> 16)); mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_LO, WITH_16BITS_WMSK(clk_freq_khz * 2 & 0xffff)); mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_HI, WITH_16BITS_WMSK(clk_freq_khz * 2 >> 16)); /* Pmu's clk has switched to 24M back When pmu FSM counts * the follow counters, so we should use 24M to calculate * these counters. */ mmio_write_32(PMU_BASE + PMU_SCU_PWRDN_CNT_LO, WITH_16BITS_WMSK(24000 * 2 & 0xffff)); mmio_write_32(PMU_BASE + PMU_SCU_PWRDN_CNT_HI, WITH_16BITS_WMSK(24000 * 2 >> 16)); mmio_write_32(PMU_BASE + PMU_SCU_PWRUP_CNT_LO, WITH_16BITS_WMSK(24000 * 2 & 0xffff)); mmio_write_32(PMU_BASE + PMU_SCU_PWRUP_CNT_HI, WITH_16BITS_WMSK(24000 * 2 >> 16)); mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT_LO, WITH_16BITS_WMSK(24000 * 5 & 0xffff)); mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT_HI, WITH_16BITS_WMSK(24000 * 5 >> 16)); mmio_write_32(PMU_BASE + PMU_PLLRST_CNT_LO, WITH_16BITS_WMSK(24000 * 2 & 0xffff)); mmio_write_32(PMU_BASE + PMU_PLLRST_CNT_HI, WITH_16BITS_WMSK(24000 * 2 >> 16)); /* Config pmu power mode and pmu wakeup source */ mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_LO, WITH_16BITS_WMSK(pwrmd_core_lo)); mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_HI, WITH_16BITS_WMSK(pwrmd_core_hi)); mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO, WITH_16BITS_WMSK(pwrmd_com_lo)); mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI, WITH_16BITS_WMSK(pwrmd_com_hi)); mmio_write_32(PMU_BASE + PMU_WKUP_CFG2_LO, WITH_16BITS_WMSK(pmu_wkup_cfg2_lo)); } static void pmu_sleep_restore(void) { mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_LO, WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_core_l)); mmio_write_32(PMU_BASE + PMU_PWRMODE_CORE_HI, WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_core_h)); mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_LO, WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_cmm_l)); mmio_write_32(PMU_BASE + PMU_PWRMODE_COMMON_CON_HI, WITH_16BITS_WMSK(ddr_data.pmu_pwrmd_cmm_h)); mmio_write_32(PMU_BASE + PMU_WKUP_CFG2_LO, WITH_16BITS_WMSK(ddr_data.pmu_wkup_cfg2_l)); /* restore pmic_sleep iomux */ mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX, WITH_16BITS_WMSK(ddr_data.pmic_slp_iomux)); } static void soc_sleep_config(void) { ddr_data.gpio0c_iomux = mmio_read_32(PMUGRF_BASE + GPIO0C_IOMUX); pmu_sleep_config(); ddr_sleep_config(); pvtm_32k_config(); } static void soc_sleep_restore(void) { secure_timer_init(); pvtm_32k_config_restore(); ddr_sleep_config_restore(); pmu_sleep_restore(); mmio_write_32(PMUGRF_BASE + GPIO0C_IOMUX, WITH_16BITS_WMSK(ddr_data.gpio0c_iomux)); } static inline void pm_pll_wait_lock(uint32_t pll_base, uint32_t pll_id) { uint32_t delay = PLL_LOCKED_TIMEOUT; while (delay > 0) { if (mmio_read_32(pll_base + PLL_CON(1)) & PLL_LOCK_MSK) break; delay--; } if (delay == 0) ERROR("Can't wait pll:%d lock\n", pll_id); } static inline void pll_pwr_ctr(uint32_t pll_base, uint32_t pll_id, uint32_t pd) { mmio_write_32(pll_base + PLL_CON(1), BITS_WITH_WMASK(1, 1U, 15)); if (pd) mmio_write_32(pll_base + PLL_CON(1), BITS_WITH_WMASK(1, 1, 14)); else mmio_write_32(pll_base + PLL_CON(1), BITS_WITH_WMASK(0, 1, 14)); } static inline void pll_set_mode(uint32_t pll_id, uint32_t mode) { uint32_t val = BITS_WITH_WMASK(mode, 0x3, PLL_MODE_SHIFT(pll_id)); if (pll_id != GPLL_ID) mmio_write_32(CRU_BASE + CRU_MODE, val); else mmio_write_32(PMUCRU_BASE + CRU_PMU_MODE, BITS_WITH_WMASK(mode, 0x3, 0)); } static inline void pll_suspend(uint32_t pll_id) { int i; uint32_t pll_base; if (pll_id != GPLL_ID) pll_base = CRU_BASE + CRU_PLL_CONS(pll_id, 0); else pll_base = PMUCRU_BASE + CRU_PLL_CONS(0, 0); /* save pll con */ for (i = 0; i < PLL_CON_CNT; i++) ddr_data.cru_plls_con_save[pll_id][i] = mmio_read_32(pll_base + PLL_CON(i)); /* slow mode */ pll_set_mode(pll_id, SLOW_MODE); } static inline void pll_resume(uint32_t pll_id) { uint32_t mode, pll_base; if (pll_id != GPLL_ID) { pll_base = CRU_BASE + CRU_PLL_CONS(pll_id, 0); mode = (ddr_data.cru_mode_save >> PLL_MODE_SHIFT(pll_id)) & 0x3; } else { pll_base = PMUCRU_BASE + CRU_PLL_CONS(0, 0); mode = ddr_data.cru_pmu_mode_save & 0x3; } /* if pll locked before suspend, we should wait atfer resume */ if (ddr_data.cru_plls_con_save[pll_id][1] & PLL_LOCK_MSK) pm_pll_wait_lock(pll_base, pll_id); pll_set_mode(pll_id, mode); } static void pm_plls_suspend(void) { ddr_data.cru_mode_save = mmio_read_32(CRU_BASE + CRU_MODE); ddr_data.cru_pmu_mode_save = mmio_read_32(PMUCRU_BASE + CRU_PMU_MODE); ddr_data.clk_sel0 = mmio_read_32(CRU_BASE + CRU_CLKSELS_CON(0)); pll_suspend(GPLL_ID); pll_suspend(NPLL_ID); pll_suspend(CPLL_ID); pll_suspend(APLL_ID); /* core */ mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0), BITS_WITH_WMASK(0, 0xf, 0)); /* pclk_dbg */ mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0), BITS_WITH_WMASK(0, 0xf, 8)); } static void pm_plls_resume(void) { /* pclk_dbg */ mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0), ddr_data.clk_sel0 | BITS_WMSK(0xf, 8)); /* core */ mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(0), ddr_data.clk_sel0 | BITS_WMSK(0xf, 0)); pll_resume(APLL_ID); pll_resume(CPLL_ID); pll_resume(NPLL_ID); pll_resume(GPLL_ID); } int rockchip_soc_sys_pwr_dm_suspend(void) { pmu_power_domains_suspend(); clk_gate_suspend(); soc_sleep_config(); pm_plls_suspend(); psram_boot_cfg->pm_flag &= ~PM_WARM_BOOT_BIT; return 0; } int rockchip_soc_sys_pwr_dm_resume(void) { psram_boot_cfg->pm_flag |= PM_WARM_BOOT_BIT; pm_plls_resume(); soc_sleep_restore(); clk_gate_resume(); pmu_power_domains_resume(); plat_rockchip_gic_cpuif_enable(); return 0; } void __dead2 rockchip_soc_soft_reset(void) { pll_set_mode(GPLL_ID, SLOW_MODE); pll_set_mode(CPLL_ID, SLOW_MODE); pll_set_mode(NPLL_ID, SLOW_MODE); pll_set_mode(APLL_ID, SLOW_MODE); dsb(); mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, CRU_GLB_SRST_FST_VALUE); dsb(); /* * Maybe the HW needs some times to reset the system, * so we do not hope the core to execute valid codes. */ psci_power_down_wfi(); } void __dead2 rockchip_soc_system_off(void) { uint32_t val; /* set pmic_sleep pin(gpio0_a4) to gpio mode */ mmio_write_32(PMUGRF_BASE + GPIO0A_IOMUX, BITS_WITH_WMASK(0, 0x3, 8)); /* config output */ val = mmio_read_32(GPIO0_BASE + SWPORTA_DDR); val |= BIT(4); mmio_write_32(GPIO0_BASE + SWPORTA_DDR, val); /* config output high level */ val = mmio_read_32(GPIO0_BASE); val |= BIT(4); mmio_write_32(GPIO0_BASE, val); dsb(); /* * Maybe the HW needs some times to reset the system, * so we do not hope the core to execute valid codes. */ psci_power_down_wfi(); } void rockchip_plat_mmu_el3(void) { /* TODO: support the el3 for px30 SoCs */ } void plat_rockchip_pmu_init(void) { uint32_t cpu; rockchip_pd_lock_init(); for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) cpuson_flags[cpu] = 0; psram_boot_cfg->ddr_func = (uint64_t)0; psram_boot_cfg->ddr_data = (uint64_t)0; psram_boot_cfg->sp = PSRAM_SP_TOP; psram_boot_cfg->ddr_flag = 0x0; psram_boot_cfg->boot_mpidr = read_mpidr_el1() & 0xffff; psram_boot_cfg->pm_flag = PM_WARM_BOOT_BIT; nonboot_cpus_off(); /* Remap pmu_sram's base address to boot address */ mmio_write_32(PMUSGRF_BASE + PMUSGRF_SOC_CON(0), BITS_WITH_WMASK(1, 0x1, 13)); INFO("%s: pd status %x\n", __func__, mmio_read_32(PMU_BASE + PMU_PWRDN_ST)); } trusted-firmware-a-2.2/plat/rockchip/px30/drivers/pmu/pmu.h000066400000000000000000000212111355360272700236730ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __PMU_H__ #define __PMU_H__ /* Needed aligned 16 bytes for sp stack top */ #define PSRAM_SP_TOP ((PMUSRAM_BASE + PMUSRAM_RSIZE) & ~0xf) /***************************************************************************** * pmu con,reg *****************************************************************************/ #define PMU_WKUP_CFG0_LO 0x00 #define PMU_WKUP_CFG0_HI 0x04 #define PMU_WKUP_CFG1_LO 0x08 #define PMU_WKUP_CFG1_HI 0x0c #define PMU_WKUP_CFG2_LO 0x10 #define PMU_PWRDN_CON 0x18 #define PMU_PWRDN_ST 0x20 #define PMU_PWRMODE_CORE_LO 0x24 #define PMU_PWRMODE_CORE_HI 0x28 #define PMU_PWRMODE_COMMON_CON_LO 0x2c #define PMU_PWRMODE_COMMON_CON_HI 0x30 #define PMU_SFT_CON 0x34 #define PMU_INT_ST 0x44 #define PMU_BUS_IDLE_REQ 0x64 #define PMU_BUS_IDLE_ST 0x6c #define PMU_OSC_CNT_LO 0x74 #define PMU_OSC_CNT_HI 0x78 #define PMU_PLLLOCK_CNT_LO 0x7c #define PMU_PLLLOCK_CNT_HI 0x80 #define PMU_PLLRST_CNT_LO 0x84 #define PMU_PLLRST_CNT_HI 0x88 #define PMU_STABLE_CNT_LO 0x8c #define PMU_STABLE_CNT_HI 0x90 #define PMU_WAKEUP_RST_CLR_LO 0x9c #define PMU_WAKEUP_RST_CLR_HI 0xa0 #define PMU_DDR_SREF_ST 0xa4 #define PMU_SYS_REG0_LO 0xa8 #define PMU_SYS_REG0_HI 0xac #define PMU_SYS_REG1_LO 0xb0 #define PMU_SYS_REG1_HI 0xb4 #define PMU_SYS_REG2_LO 0xb8 #define PMU_SYS_REG2_HI 0xbc #define PMU_SYS_REG3_LO 0xc0 #define PMU_SYS_REG3_HI 0xc4 #define PMU_SCU_PWRDN_CNT_LO 0xc8 #define PMU_SCU_PWRDN_CNT_HI 0xcc #define PMU_SCU_PWRUP_CNT_LO 0xd0 #define PMU_SCU_PWRUP_CNT_HI 0xd4 #define PMU_TIMEOUT_CNT_LO 0xd8 #define PMU_TIMEOUT_CNT_HI 0xdc #define PMU_CPUAPM_CON(cpu) (0xe0 + (cpu) * 0x4) #define CORES_PM_DISABLE 0x0 #define CLST_CPUS_MSK 0xf #define PD_CTR_LOOP 500 #define PD_CHECK_LOOP 500 #define WFEI_CHECK_LOOP 500 #define BUS_IDLE_LOOP 1000 enum pmu_wkup_cfg2 { pmu_cluster_wkup_en = 0, pmu_gpio_wkup_en = 2, pmu_sdio_wkup_en = 3, pmu_sdmmc_wkup_en = 4, pmu_uart0_wkup_en = 5, pmu_timer_wkup_en = 6, pmu_usbdev_wkup_en = 7, pmu_sft_wkup_en = 8, pmu_timeout_wkup_en = 10, }; enum pmu_powermode_core_lo { pmu_global_int_dis = 0, pmu_core_src_gt = 1, pmu_cpu0_pd = 3, pmu_clr_core = 5, pmu_scu_pd = 6, pmu_l2_idle = 8, pmu_l2_flush = 9, pmu_clr_bus2main = 10, pmu_clr_peri2msch = 11, }; enum pmu_powermode_core_hi { pmu_apll_pd_en = 3, pmu_dpll_pd_en = 4, pmu_cpll_pd_en = 5, pmu_gpll_pd_en = 6, pmu_npll_pd_en = 7, }; enum pmu_powermode_common_lo { pmu_mode_en = 0, pmu_ddr_pd_en = 1, pmu_wkup_rst = 3, pmu_pll_pd = 4, pmu_pmu_use_if = 6, pmu_alive_use_if = 7, pmu_osc_dis = 8, pmu_input_clamp = 9, pmu_sref_enter = 10, pmu_ddrc_gt = 11, pmu_ddrio_ret = 12, pmu_ddrio_ret_deq = 13, pmu_clr_pmu = 14, pmu_clr_peri_pmu = 15, }; enum pmu_powermode_common_hi { pmu_clr_bus = 0, pmu_clr_mmc = 1, pmu_clr_msch = 2, pmu_clr_nandc = 3, pmu_clr_gmac = 4, pmu_clr_vo = 5, pmu_clr_vi = 6, pmu_clr_gpu = 7, pmu_clr_usb = 8, pmu_clr_vpu = 9, pmu_clr_crypto = 10, pmu_wakeup_begin_cfg = 11, pmu_peri_clk_src_gt = 12, pmu_bus_clk_src_gt = 13, }; enum pmu_pd_id { PD_CPU0 = 0, PD_CPU1 = 1, PD_CPU2 = 2, PD_CPU3 = 3, PD_SCU = 4, PD_USB = 5, PD_DDR = 6, PD_SDCARD = 8, PD_CRYPTO = 9, PD_GMAC = 10, PD_MMC_NAND = 11, PD_VPU = 12, PD_VO = 13, PD_VI = 14, PD_GPU = 15, PD_END = 16, }; enum pmu_bus_id { BUS_ID_BUS = 0, BUS_ID_BUS2MAIN = 1, BUS_ID_GPU = 2, BUS_ID_CORE = 3, BUS_ID_CRYPTO = 4, BUS_ID_MMC = 5, BUS_ID_GMAC = 6, BUS_ID_VO = 7, BUS_ID_VI = 8, BUS_ID_SDCARD = 9, BUS_ID_USB = 10, BUS_ID_MSCH = 11, BUS_ID_PERI = 12, BUS_ID_PMU = 13, BUS_ID_VPU = 14, BUS_ID_PERI2MSCH = 15, }; enum pmu_pd_state { pmu_pd_on = 0, pmu_pd_off = 1 }; enum pmu_bus_state { bus_active = 0, bus_idle = 1, }; enum cores_pm_ctr_mode { core_pwr_pd = 0, core_pwr_wfi = 1, core_pwr_wfi_int = 2 }; enum pmu_cores_pm_by_wfi { core_pm_en = 0, core_pm_int_wakeup_en, core_pm_dis_int, core_pm_sft_wakeup_en }; /***************************************************************************** * pmu_sgrf *****************************************************************************/ #define PMUSGRF_SOC_CON(i) ((i) * 0x4) /***************************************************************************** * pmu_grf *****************************************************************************/ #define GPIO0A_IOMUX 0x0 #define GPIO0B_IOMUX 0x4 #define GPIO0C_IOMUX 0x8 #define GPIO0A_PULL 0x10 #define GPIO0L_SMT 0x38 #define GPIO0H_SMT 0x3c #define PMUGRF_SOC_CON(i) (0x100 + (i) * 4) #define PMUGRF_PVTM_CON0 0x180 #define PMUGRF_PVTM_CON1 0x184 #define PMUGRF_PVTM_ST0 0x190 #define PMUGRF_PVTM_ST1 0x194 #define PVTM_CALC_CNT 0x200 #define PMUGRF_OS_REG(n) (0x200 + (n) * 4) #define GPIO0A6_IOMUX_MSK (0x3 << 12) #define GPIO0A6_IOMUX_GPIO (0x0 << 12) #define GPIO0A6_IOMUX_RSTOUT (0x1 << 12) #define GPIO0A6_IOMUX_SHTDN (0x2 << 12) enum px30_pmugrf_pvtm_con0 { pgrf_pvtm_st = 0, pgrf_pvtm_en = 1, pgrf_pvtm_div = 2, }; /***************************************************************************** * pmu_cru *****************************************************************************/ #define CRU_PMU_MODE 0x20 #define CRU_PMU_CLKSEL_CON 0x40 #define CRU_PMU_CLKSELS_CON(i) (CRU_PMU_CLKSEL_CON + (i) * 4) #define CRU_PMU_CLKSEL_CON_CNT 5 #define CRU_PMU_CLKGATE_CON 0x80 #define CRU_PMU_CLKGATES_CON(i) (CRU_PMU_CLKGATE_CON + (i) * 4) #define CRU_PMU_CLKGATE_CON_CNT 2 #define CRU_PMU_ATCS_CON 0xc0 #define CRU_PMU_ATCSS_CON(i) (CRU_PMU_ATCS_CON + (i) * 4) #define CRU_PMU_ATCS_CON_CNT 2 /***************************************************************************** * pmusgrf *****************************************************************************/ #define PMUSGRF_RSTOUT_EN (0x7 << 10) #define PMUSGRF_RSTOUT_FST 10 #define PMUSGRF_RSTOUT_TSADC 11 #define PMUSGRF_RSTOUT_WDT 12 #define PMUGRF_SOC_CON2_US_WMSK (0x1fff << 16) #define PMUGRF_SOC_CON2_MAX_341US 0x1fff #define PMUGRF_SOC_CON2_200US 0x12c0 #define PMUGRF_FAILSAFE_SHTDN_TSADC BIT(0) #define PMUGRF_FAILSAFE_SHTDN_WDT BIT(1) /***************************************************************************** * QOS *****************************************************************************/ #define CPU_AXI_QOS_ID_COREID 0x00 #define CPU_AXI_QOS_REVISIONID 0x04 #define CPU_AXI_QOS_PRIORITY 0x08 #define CPU_AXI_QOS_MODE 0x0c #define CPU_AXI_QOS_BANDWIDTH 0x10 #define CPU_AXI_QOS_SATURATION 0x14 #define CPU_AXI_QOS_EXTCONTROL 0x18 #define CPU_AXI_QOS_NUM_REGS 0x07 #define CPU_AXI_CPU_QOS_BASE 0xff508000 #define CPU_AXI_GPU_QOS_BASE 0xff520000 #define CPU_AXI_ISP_128M_QOS_BASE 0xff548000 #define CPU_AXI_ISP_RD_QOS_BASE 0xff548080 #define CPU_AXI_ISP_WR_QOS_BASE 0xff548100 #define CPU_AXI_ISP_M1_QOS_BASE 0xff548180 #define CPU_AXI_VIP_QOS_BASE 0xff548200 #define CPU_AXI_RGA_RD_QOS_BASE 0xff550000 #define CPU_AXI_RGA_WR_QOS_BASE 0xff550080 #define CPU_AXI_VOP_M0_QOS_BASE 0xff550100 #define CPU_AXI_VOP_M1_QOS_BASE 0xff550180 #define CPU_AXI_VPU_QOS_BASE 0xff558000 #define CPU_AXI_VPU_R128_QOS_BASE 0xff558080 #define CPU_AXI_DCF_QOS_BASE 0xff500000 #define CPU_AXI_DMAC_QOS_BASE 0xff500080 #define CPU_AXI_CRYPTO_QOS_BASE 0xff510000 #define CPU_AXI_GMAC_QOS_BASE 0xff518000 #define CPU_AXI_EMMC_QOS_BASE 0xff538000 #define CPU_AXI_NAND_QOS_BASE 0xff538080 #define CPU_AXI_SDIO_QOS_BASE 0xff538100 #define CPU_AXI_SFC_QOS_BASE 0xff538180 #define CPU_AXI_SDMMC_QOS_BASE 0xff52c000 #define CPU_AXI_USB_HOST_QOS_BASE 0xff540000 #define CPU_AXI_USB_OTG_QOS_BASE 0xff540080 #define PX30_CPU_AXI_SAVE_QOS(array, base) do { \ array[0] = mmio_read_32(base + CPU_AXI_QOS_ID_COREID); \ array[1] = mmio_read_32(base + CPU_AXI_QOS_REVISIONID); \ array[2] = mmio_read_32(base + CPU_AXI_QOS_PRIORITY); \ array[3] = mmio_read_32(base + CPU_AXI_QOS_MODE); \ array[4] = mmio_read_32(base + CPU_AXI_QOS_BANDWIDTH); \ array[5] = mmio_read_32(base + CPU_AXI_QOS_SATURATION); \ array[6] = mmio_read_32(base + CPU_AXI_QOS_EXTCONTROL); \ } while (0) #define PX30_CPU_AXI_RESTORE_QOS(array, base) do { \ mmio_write_32(base + CPU_AXI_QOS_ID_COREID, array[0]); \ mmio_write_32(base + CPU_AXI_QOS_REVISIONID, array[1]); \ mmio_write_32(base + CPU_AXI_QOS_PRIORITY, array[2]); \ mmio_write_32(base + CPU_AXI_QOS_MODE, array[3]); \ mmio_write_32(base + CPU_AXI_QOS_BANDWIDTH, array[4]); \ mmio_write_32(base + CPU_AXI_QOS_SATURATION, array[5]); \ mmio_write_32(base + CPU_AXI_QOS_EXTCONTROL, array[6]); \ } while (0) #define SAVE_QOS(array, NAME) \ PX30_CPU_AXI_SAVE_QOS(array, CPU_AXI_##NAME##_QOS_BASE) #define RESTORE_QOS(array, NAME) \ PX30_CPU_AXI_RESTORE_QOS(array, CPU_AXI_##NAME##_QOS_BASE) #endif /* __PMU_H__ */ trusted-firmware-a-2.2/plat/rockchip/px30/drivers/soc/000077500000000000000000000000001355360272700227075ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/px30/drivers/soc/soc.c000066400000000000000000000127171355360272700236470ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include /* Aggregate of all devices in the first GB */ #define PX30_DEV_RNG0_BASE 0xff000000 #define PX30_DEV_RNG0_SIZE 0x00ff0000 const mmap_region_t plat_rk_mmap[] = { MAP_REGION_FLAT(PX30_DEV_RNG0_BASE, PX30_DEV_RNG0_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(SHARE_MEM_BASE, SHARE_MEM_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DDR_PARAM_BASE, DDR_PARAM_SIZE, MT_DEVICE | MT_RW | MT_SECURE), { 0 } }; /* The RockChip power domain tree descriptor */ const unsigned char rockchip_power_domain_tree_desc[] = { /* No of root nodes */ PLATFORM_SYSTEM_COUNT, /* No of children for the root node */ PLATFORM_CLUSTER_COUNT, /* No of children for the first cluster node */ PLATFORM_CLUSTER0_CORE_COUNT, }; void clk_gate_con_save(uint32_t *clkgt_save) { uint32_t i, j; for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) clkgt_save[i] = mmio_read_32(CRU_BASE + CRU_CLKGATES_CON(i)); j = i; for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++, j++) clkgt_save[j] = mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i)); } void clk_gate_con_restore(uint32_t *clkgt_save) { uint32_t i, j; for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), WITH_16BITS_WMSK(clkgt_save[i])); j = i; for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++, j++) mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i), WITH_16BITS_WMSK(clkgt_save[j])); } void clk_gate_con_disable(void) { uint32_t i; for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), 0xffff0000); for (i = 0; i < CRU_PMU_CLKGATE_CON_CNT; i++) mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATES_CON(i), 0xffff0000); } void secure_timer_init(void) { mmio_write_32(STIMER_CHN_BASE(1) + TIMER_CONTROL_REG, TIMER_DIS); mmio_write_32(STIMER_CHN_BASE(1) + TIMER_LOAD_COUNT0, 0xffffffff); mmio_write_32(STIMER_CHN_BASE(1) + TIMER_LOAD_COUNT1, 0xffffffff); /* auto reload & enable the timer */ mmio_write_32(STIMER_CHN_BASE(1) + TIMER_CONTROL_REG, TIMER_EN | TIMER_FMODE); } static void sgrf_init(void) { uint32_t i, val; struct param_ddr_usage usg; /* general secure regions */ usg = ddr_region_usage_parse(DDR_PARAM_BASE, PLAT_MAX_DDR_CAPACITY_MB); for (i = 0; i < usg.s_nr; i++) { /* enable secure */ val = mmio_read_32(FIREWALL_DDR_BASE + FIREWALL_DDR_FW_DDR_CON_REG); val |= BIT(7 - i); mmio_write_32(FIREWALL_DDR_BASE + FIREWALL_DDR_FW_DDR_CON_REG, val); /* map top and base */ mmio_write_32(FIREWALL_DDR_BASE + FIREWALL_DDR_FW_DDR_RGN(7 - i), RG_MAP_SECURE(usg.s_top[i], usg.s_base[i])); } /* set ddr rgn0_top and rga0_top as 0 */ mmio_write_32(FIREWALL_DDR_BASE + FIREWALL_DDR_FW_DDR_RGN(0), 0x0); /* set all slave ip into no-secure, except stimer */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(4), SGRF_SLV_S_ALL_NS); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(5), SGRF_SLV_S_ALL_NS); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6), SGRF_SLV_S_ALL_NS); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(7), SGRF_SLV_S_ALL_NS); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(8), 0x00030000); /* set master crypto to no-secure, dcf to secure */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(3), 0x000f0003); /* set DMAC into no-secure */ mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(0), DMA_IRQ_BOOT_NS); mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(1), DMA_PERI_CH_NS_15_0); mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(2), DMA_PERI_CH_NS_19_16); mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(3), DMA_MANAGER_BOOT_NS); /* soft reset dma before use */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1), DMA_SOFTRST_REQ); udelay(5); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1), DMA_SOFTRST_RLS); } static void soc_reset_config_all(void) { uint32_t tmp; /* tsadc and wdt can trigger a first rst */ tmp = mmio_read_32(CRU_BASE + CRU_GLB_RST_CON); tmp |= CRU_GLB_RST_TSADC_FST | CRU_GLB_RST_WDT_FST; mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, tmp); return; tmp = mmio_read_32(PMUGRF_BASE + PMUGRF_SOC_CON(3)); tmp &= ~(PMUGRF_FAILSAFE_SHTDN_TSADC | PMUGRF_FAILSAFE_SHTDN_WDT); mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(3), tmp); /* wdt pin rst eable */ mmio_write_32(GRF_BASE + GRF_SOC_CON(2), BIT_WITH_WMSK(GRF_SOC_CON2_NSWDT_RST_EN)); } void px30_soc_reset_config(void) { uint32_t tmp; /* enable soc ip rst hold time cfg */ tmp = mmio_read_32(CRU_BASE + CRU_GLB_RST_CON); tmp |= BIT(CRU_GLB_RST_TSADC_EXT) | BIT(CRU_GLB_RST_WDT_EXT); mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, tmp); /* soc ip rst hold time, 24m */ tmp = mmio_read_32(CRU_BASE + CRU_GLB_CNT_TH); tmp &= ~CRU_GLB_CNT_RST_MSK; tmp |= (CRU_GLB_CNT_RST_1MS / 2); mmio_write_32(CRU_BASE + CRU_GLB_CNT_TH, tmp); mmio_write_32(PMUSGRF_BASE + PMUSGRF_SOC_CON(0), BIT_WITH_WMSK(PMUSGRF_RSTOUT_FST) | BIT_WITH_WMSK(PMUSGRF_RSTOUT_TSADC) | BIT_WITH_WMSK(PMUSGRF_RSTOUT_WDT)); /* rst_out pulse time */ mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON(2), PMUGRF_SOC_CON2_MAX_341US | PMUGRF_SOC_CON2_US_WMSK); soc_reset_config_all(); } void plat_rockchip_soc_init(void) { secure_timer_init(); sgrf_init(); } trusted-firmware-a-2.2/plat/rockchip/px30/drivers/soc/soc.h000066400000000000000000000113101355360272700236400ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __SOC_H__ #define __SOC_H__ #include #ifndef BITS_WMSK #define BITS_WMSK(msk, shift) ((msk) << (shift + REG_MSK_SHIFT)) #endif enum plls_id { APLL_ID = 0, DPLL_ID, CPLL_ID, NPLL_ID, GPLL_ID, END_PLL_ID, }; enum pll_mode { SLOW_MODE, NORM_MODE, DEEP_SLOW_MODE, }; /*************************************************************************** * SGRF ***************************************************************************/ #define SGRF_SOC_CON(i) ((i) * 0x4) #define SGRF_DMAC_CON(i) (0x30 + (i) * 0x4) #define SGRF_MST_S_ALL_NS 0xffffffff #define SGRF_SLV_S_ALL_NS 0xffff0000 #define DMA_IRQ_BOOT_NS 0xffffffff #define DMA_PERI_CH_NS_15_0 0xffffffff #define DMA_PERI_CH_NS_19_16 0x000f000f #define DMA_MANAGER_BOOT_NS 0x00010001 #define DMA_SOFTRST_REQ BITS_WITH_WMASK(1, 0x1, 12) #define DMA_SOFTRST_RLS BITS_WITH_WMASK(0, 0x1, 12) /*************************************************************************** * GRF ***************************************************************************/ #define GRF_SOC_CON(i) (0x0400 + (i) * 4) #define GRF_PD_VO_CON0 0x0434 #define GRF_SOC_STATUS0 0x0480 #define GRF_CPU_STATUS0 0x0520 #define GRF_CPU_STATUS1 0x0524 #define GRF_SOC_NOC_CON0 0x0530 #define GRF_SOC_NOC_CON1 0x0534 #define CKECK_WFE_MSK 0x1 #define CKECK_WFI_MSK 0x10 #define CKECK_WFEI_MSK 0x11 #define GRF_SOC_CON2_NSWDT_RST_EN 12 /*************************************************************************** * DDR FIREWALL ***************************************************************************/ #define FIREWALL_DDR_FW_DDR_RGN(i) ((i) * 0x4) #define FIREWALL_DDR_FW_DDR_MST(i) (0x20 + (i) * 0x4) #define FIREWALL_DDR_FW_DDR_CON_REG 0x40 #define FIREWALL_DDR_FW_DDR_RGN_NUM 8 #define FIREWALL_DDR_FW_DDR_MST_NUM 6 #define PLAT_MAX_DDR_CAPACITY_MB 4096 #define RG_MAP_SECURE(top, base) ((((top) - 1) << 16) | (base)) /*************************************************************************** * cru ***************************************************************************/ #define CRU_MODE 0xa0 #define CRU_MISC 0xa4 #define CRU_GLB_CNT_TH 0xb0 #define CRU_GLB_RST_ST 0xb4 #define CRU_GLB_SRST_FST 0xb8 #define CRU_GLB_SRST_SND 0xbc #define CRU_GLB_RST_CON 0xc0 #define CRU_CLKSEL_CON 0x100 #define CRU_CLKSELS_CON(i) (CRU_CLKSEL_CON + (i) * 4) #define CRU_CLKSEL_CON_CNT 60 #define CRU_CLKGATE_CON 0x200 #define CRU_CLKGATES_CON(i) (CRU_CLKGATE_CON + (i) * 4) #define CRU_CLKGATES_CON_CNT 18 #define CRU_SOFTRST_CON 0x300 #define CRU_SOFTRSTS_CON(n) (CRU_SOFTRST_CON + ((n) * 4)) #define CRU_SOFTRSTS_CON_CNT 12 #define CRU_AUTOCS_CON0(id) (0x400 + (id) * 8) #define CRU_AUTOCS_CON1(id) (0x404 + (id) * 8) #define CRU_CONS_GATEID(i) (16 * (i)) #define GATE_ID(reg, bit) ((reg) * 16 + (bit)) #define CRU_GLB_SRST_FST_VALUE 0xfdb9 #define CRU_GLB_SRST_SND_VALUE 0xeca8 #define CRU_GLB_RST_TSADC_EXT 6 #define CRU_GLB_RST_WDT_EXT 7 #define CRU_GLB_CNT_RST_MSK 0xffff #define CRU_GLB_CNT_RST_1MS 0x5DC0 #define CRU_GLB_RST_TSADC_FST BIT(0) #define CRU_GLB_RST_WDT_FST BIT(1) /*************************************************************************** * pll ***************************************************************************/ #define CRU_PLL_CONS(id, i) ((id) * 0x20 + (i) * 4) #define PLL_CON(i) ((i) * 4) #define PLL_CON_CNT 5 #define PLL_LOCK_MSK BIT(10) #define PLL_MODE_SHIFT(id) ((id) == CPLL_ID ? \ 2 : \ ((id) == DPLL_ID ? 4 : 2 * (id))) #define PLL_MODE_MSK(id) (0x3 << PLL_MODE_SHIFT(id)) #define PLL_LOCKED_TIMEOUT 600000U /*************************************************************************** * GPIO ***************************************************************************/ #define SWPORTA_DR 0x00 #define SWPORTA_DDR 0x04 #define GPIO_INTEN 0x30 #define GPIO_INT_STATUS 0x40 #define GPIO_NUMS 4 /************************************************** * secure timer **************************************************/ /* chanal0~5 */ #define STIMER_CHN_BASE(n) (STIME_BASE + 0x20 * (n)) #define TIMER_LOAD_COUNT0 0x0 #define TIMER_LOAD_COUNT1 0x4 #define TIMER_CUR_VALUE0 0x8 #define TIMER_CUR_VALUE1 0xc #define TIMER_CONTROL_REG 0x10 #define TIMER_INTSTATUS 0x18 #define TIMER_DIS 0x0 #define TIMER_EN 0x1 #define TIMER_FMODE (0x0 << 1) #define TIMER_RMODE (0x1 << 1) #define TIMER_LOAD_COUNT0_MSK (0xffffffff) #define TIMER_LOAD_COUNT1_MSK (0xffffffff00000000) void clk_gate_con_save(uint32_t *clkgt_save); void clk_gate_con_restore(uint32_t *clkgt_save); void clk_gate_con_disable(void); void secure_timer_init(void); void secure_timer_disable(void); void px30_soc_reset_config(void); #endif /* __SOC_H__ */ trusted-firmware-a-2.2/plat/rockchip/px30/include/000077500000000000000000000000001355360272700220705ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/px30/include/plat.ld.S000066400000000000000000000013771355360272700235620ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __ROCKCHIP_PLAT_LD_S__ #define __ROCKCHIP_PLAT_LD_S__ MEMORY { PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE } SECTIONS { . = PMUSRAM_BASE; /* * pmu_cpuson_entrypoint request address * align 64K when resume, so put it in the * start of pmusram */ .pmusram : { ASSERT(. == ALIGN(64 * 1024), ".pmusram.entry request 64K aligned."); KEEP(*(.pmusram.entry)) __bl31_pmusram_text_start = .; *(.pmusram.text) *(.pmusram.rodata) __bl31_pmusram_text_end = .; __bl31_pmusram_data_start = .; *(.pmusram.data) __bl31_pmusram_data_end = .; } >PMUSRAM } #endif /* __ROCKCHIP_PLAT_LD_S__ */ trusted-firmware-a-2.2/plat/rockchip/px30/include/plat_sip_calls.h000066400000000000000000000003741355360272700252360ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __PLAT_SIP_CALLS_H__ #define __PLAT_SIP_CALLS_H__ #define RK_PLAT_SIP_NUM_CALLS 0 #endif /* __PLAT_SIP_CALLS_H__ */ trusted-firmware-a-2.2/plat/rockchip/px30/include/platform_def.h000066400000000000000000000076601355360272700247140ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __PLATFORM_DEF_H__ #define __PLATFORM_DEF_H__ #include #include #include #define DEBUG_XLAT_TABLE 0 /******************************************************************************* * Platform binary types for linking ******************************************************************************/ #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 /******************************************************************************* * Generic platform constants ******************************************************************************/ /* Size of cacheable stacks */ #if DEBUG_XLAT_TABLE #define PLATFORM_STACK_SIZE 0x800 #elif IMAGE_BL1 #define PLATFORM_STACK_SIZE 0x440 #elif IMAGE_BL2 #define PLATFORM_STACK_SIZE 0x400 #elif IMAGE_BL31 #define PLATFORM_STACK_SIZE 0x800 #elif IMAGE_BL32 #define PLATFORM_STACK_SIZE 0x440 #endif #define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n" #define PLATFORM_MAX_AFFLVL MPIDR_AFFLVL2 #define PLATFORM_SYSTEM_COUNT 1 #define PLATFORM_CLUSTER_COUNT 1 #define PLATFORM_CLUSTER0_CORE_COUNT 4 #define PLATFORM_CLUSTER1_CORE_COUNT 0 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \ PLATFORM_CLUSTER0_CORE_COUNT) #define PLATFORM_NUM_AFFS (PLATFORM_SYSTEM_COUNT + \ PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2 #define PLAT_RK_CLST_TO_CPUID_SHIFT 8 /* * This macro defines the deepest retention state possible. A higher state * id will represent an invalid or a power down state. */ #define PLAT_MAX_RET_STATE 1 /* * This macro defines the deepest power down states possible. Any state ID * higher than this is invalid. */ #define PLAT_MAX_OFF_STATE 2 /******************************************************************************* * Platform memory map related constants ******************************************************************************/ /* TF text, ro, rw, Size: 512KB */ #define TZRAM_BASE (0x0) #define TZRAM_SIZE (0x80000) /******************************************************************************* * BL31 specific defines. ******************************************************************************/ /* * Put BL3-1 at the top of the Trusted RAM */ #define BL31_BASE (TZRAM_BASE + 0x40000) #define BL31_LIMIT (TZRAM_BASE + TZRAM_SIZE) /******************************************************************************* * Platform specific page table and MMU setup constants ******************************************************************************/ #define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32) #define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32) #define ADDR_SPACE_SIZE (1ull << 32) #define MAX_XLAT_TABLES 8 #define MAX_MMAP_REGIONS 27 /******************************************************************************* * Declarations and constants to access the mailboxes safely. Each mailbox is * aligned on the biggest cache line size in the platform. This is known only * to the platform as it might have a combination of integrated and external * caches. Such alignment ensures that two maiboxes do not sit on the same cache * line at any cache level. They could belong to different cpus/clusters & * get written while being protected by different locks causing corruption of * a valid mailbox address. ******************************************************************************/ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) /* * Define GICD and GICC and GICR base */ #define PLAT_RK_GICD_BASE PX30_GICD_BASE #define PLAT_RK_GICC_BASE PX30_GICC_BASE #define PLAT_RK_UART_BASE PX30_UART_BASE #define PLAT_RK_UART_CLOCK PX30_UART_CLOCK #define PLAT_RK_UART_BAUDRATE PX30_BAUDRATE #define PLAT_RK_PRIMARY_CPU 0x0 #endif /* __PLATFORM_DEF_H__ */ trusted-firmware-a-2.2/plat/rockchip/px30/plat_sip_calls.c000066400000000000000000000011051355360272700235770ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include uintptr_t rockchip_plat_sip_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) { ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); SMC_RET1(handle, SMC_UNK); } trusted-firmware-a-2.2/plat/rockchip/px30/platform.mk000066400000000000000000000041471355360272700226300ustar00rootroot00000000000000# #Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. # #SPDX-License-Identifier: BSD-3-Clause # RK_PLAT := plat/rockchip RK_PLAT_SOC := ${RK_PLAT}/${PLAT} RK_PLAT_COMMON := ${RK_PLAT}/common DISABLE_BIN_GENERATION := 1 PLAT_INCLUDES := -Idrivers/arm/gic/common/ \ -Idrivers/arm/gic/v2/ \ -Iinclude/plat/common/ \ -I${RK_PLAT_COMMON}/ \ -I${RK_PLAT_COMMON}/include/ \ -I${RK_PLAT_COMMON}/drivers/parameter/ \ -I${RK_PLAT_COMMON}/pmusram \ -I${RK_PLAT_SOC}/ \ -I${RK_PLAT_SOC}/drivers/pmu/ \ -I${RK_PLAT_SOC}/drivers/soc/ \ -I${RK_PLAT_SOC}/include/ RK_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c \ plat/common/aarch64/crash_console_helpers.S \ ${RK_PLAT}/common/rockchip_gicv2.c PLAT_BL_COMMON_SOURCES := lib/bl_aux_params/bl_aux_params.c \ lib/xlat_tables/xlat_tables_common.c \ lib/xlat_tables/aarch64/xlat_tables.c \ plat/common/plat_psci_common.c BL31_SOURCES += ${RK_GIC_SOURCES} \ common/desc_image_load.c \ drivers/arm/cci/cci.c \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/ti/uart/aarch64/16550_console.S \ lib/cpus/aarch64/cortex_a35.S \ ${RK_PLAT_COMMON}/aarch64/plat_helpers.S \ ${RK_PLAT_COMMON}/aarch64/platform_common.c \ ${RK_PLAT_COMMON}/bl31_plat_setup.c \ ${RK_PLAT_COMMON}/drivers/parameter/ddr_parameter.c \ ${RK_PLAT_COMMON}/params_setup.c \ ${RK_PLAT_COMMON}/pmusram/cpus_on_fixed_addr.S \ ${RK_PLAT_COMMON}/plat_pm.c \ ${RK_PLAT_COMMON}/plat_topology.c \ ${RK_PLAT_COMMON}/rockchip_sip_svc.c \ ${RK_PLAT_SOC}/drivers/pmu/pmu.c \ ${RK_PLAT_SOC}/drivers/soc/soc.c \ ${RK_PLAT_SOC}/plat_sip_calls.c ENABLE_PLAT_COMPAT := 0 MULTI_CONSOLE_API := 1 include lib/libfdt/libfdt.mk $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) $(eval $(call add_define,PLAT_SKIP_OPTEE_S_EL1_INT_REGISTER)) $(eval $(call add_define,PLAT_WARMBOOT_ADDR_NOT_ALIGN)) trusted-firmware-a-2.2/plat/rockchip/px30/px30_def.h000066400000000000000000000107121355360272700222270ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef __PX30_DEF_H__ #define __PX30_DEF_H__ #define MAJOR_VERSION (1) #define MINOR_VERSION (0) #define SIZE_K(n) ((n) * 1024) #define WITH_16BITS_WMSK(bits) (0xffff0000 | (bits)) /* Special value used to verify platform parameters from BL2 to BL3-1 */ #define RK_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL #define PMU_BASE 0xff000000 #define PMU_SIZE SIZE_K(64) #define PMUGRF_BASE 0xff010000 #define PMUGRF_SIZE SIZE_K(64) #define PMUSRAM_BASE 0xff020000 #define PMUSRAM_SIZE SIZE_K(64) #define PMUSRAM_RSIZE SIZE_K(8) #define UART0_BASE 0xff030000 #define UART0_SIZE SIZE_K(64) #define GPIO0_BASE 0xff040000 #define GPIO0_SIZE SIZE_K(64) #define PMUSGRF_BASE 0xff050000 #define PMUSGRF_SIZE SIZE_K(64) #define INTSRAM_BASE 0xff0e0000 #define INTSRAM_SIZE SIZE_K(64) #define SGRF_BASE 0xff11c000 #define SGRF_SIZE SIZE_K(16) #define GIC400_BASE 0xff130000 #define GIC400_SIZE SIZE_K(64) #define GRF_BASE 0xff140000 #define GRF_SIZE SIZE_K(64) #define UART1_BASE 0xff158000 #define UART1_SIZE SIZE_K(64) #define UART2_BASE 0xff160000 #define UART2_SIZE SIZE_K(64) #define UART5_BASE 0xff178000 #define UART5_SIZE SIZE_K(64) #define I2C0_BASE 0xff180000 #define I2C0_SIZE SIZE_K(64) #define PWM0_BASE 0xff200000 #define PWM0_SIZE SIZE_K(32) #define PWM1_BASE 0xff208000 #define PWM1_SIZE SIZE_K(32) #define NTIME_BASE 0xff210000 #define NTIME_SIZE SIZE_K(64) #define STIME_BASE 0xff220000 #define STIME_SIZE SIZE_K(64) #define DCF_BASE 0xff230000 #define DCF_SIZE SIZE_K(64) #define GPIO1_BASE 0xff250000 #define GPIO1_SIZE SIZE_K(64) #define GPIO2_BASE 0xff260000 #define GPIO2_SIZE SIZE_K(64) #define GPIO3_BASE 0xff270000 #define GPIO3_SIZE SIZE_K(64) #define DDR_PHY_BASE 0xff2a0000 #define DDR_PHY_SIZE SIZE_K(64) #define CRU_BASE 0xff2b0000 #define CRU_SIZE SIZE_K(32) #define CRU_BOOST_BASE 0xff2b8000 #define CRU_BOOST_SIZE SIZE_K(16) #define PMUCRU_BASE 0xff2bc000 #define PMUCRU_SIZE SIZE_K(16) #define VOP_BASE 0xff460000 #define VOP_SIZE SIZE_K(16) #define SERVER_MSCH_BASE 0xff530000 #define SERVER_MSCH_SIZE SIZE_K(64) #define FIREWALL_DDR_BASE 0xff534000 #define FIREWALL_DDR_SIZE SIZE_K(16) #define DDR_UPCTL_BASE 0xff600000 #define DDR_UPCTL_SIZE SIZE_K(64) #define DDR_MNTR_BASE 0xff610000 #define DDR_MNTR_SIZE SIZE_K(64) #define DDR_STDBY_BASE 0xff620000 #define DDR_STDBY_SIZE SIZE_K(64) #define DDRGRF_BASE 0xff630000 #define DDRGRF_SIZE SIZE_K(32) /************************************************************************** * UART related constants **************************************************************************/ #define PX30_UART_BASE UART2_BASE #define PX30_BAUDRATE 1500000 #define PX30_UART_CLOCK 24000000 /****************************************************************************** * System counter frequency related constants ******************************************************************************/ #define SYS_COUNTER_FREQ_IN_TICKS 24000000 #define SYS_COUNTER_FREQ_IN_MHZ 24 /****************************************************************************** * GIC-400 & interrupt handling related constants ******************************************************************************/ /* Base rk_platform compatible GIC memory map */ #define PX30_GICD_BASE (GIC400_BASE + 0x1000) #define PX30_GICC_BASE (GIC400_BASE + 0x2000) #define PX30_GICR_BASE 0 /* no GICR in GIC-400 */ /****************************************************************************** * sgi, ppi ******************************************************************************/ #define RK_IRQ_SEC_PHY_TIMER 29 #define RK_IRQ_SEC_SGI_0 8 #define RK_IRQ_SEC_SGI_1 9 #define RK_IRQ_SEC_SGI_2 10 #define RK_IRQ_SEC_SGI_3 11 #define RK_IRQ_SEC_SGI_4 12 #define RK_IRQ_SEC_SGI_5 13 #define RK_IRQ_SEC_SGI_6 14 #define RK_IRQ_SEC_SGI_7 15 /* * Define a list of Group 0 interrupts. */ #define PLAT_RK_GICV2_G0_IRQS \ INTR_PROP_DESC(RK_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, \ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(RK_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, \ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL) #define SHARE_MEM_BASE 0x100000/* [1MB, 1MB+60K]*/ #define SHARE_MEM_PAGE_NUM 15 #define SHARE_MEM_SIZE SIZE_K(SHARE_MEM_PAGE_NUM * 4) #define DDR_PARAM_BASE 0x02000000 #define DDR_PARAM_SIZE SIZE_K(4) #endif /* __PLAT_DEF_H__ */ trusted-firmware-a-2.2/plat/rockchip/rk3288/000077500000000000000000000000001355360272700206145ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3288/drivers/000077500000000000000000000000001355360272700222725ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3288/drivers/pmu/000077500000000000000000000000001355360272700230735ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3288/drivers/pmu/plat_pmu_macros.S000066400000000000000000000005261355360272700264070ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .macro func_rockchip_clst_warmboot /* Nothing to do for rk3288 */ .endm .macro rockchip_clst_warmboot_data /* Nothing to do for rk3288 */ .endm trusted-firmware-a-2.2/plat/rockchip/rk3288/drivers/pmu/pmu.c000066400000000000000000000237241355360272700240500ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include DEFINE_BAKERY_LOCK(rockchip_pd_lock); static uint32_t cpu_warm_boot_addr; static uint32_t store_pmu_pwrmode_con; static uint32_t store_sgrf_soc_con0; static uint32_t store_sgrf_cpu_con0; /* These enum are variants of low power mode */ enum { ROCKCHIP_ARM_OFF_LOGIC_NORMAL = 0, ROCKCHIP_ARM_OFF_LOGIC_DEEP = 1, }; static inline int rk3288_pmu_bus_idle(uint32_t req, uint32_t idle) { uint32_t mask = BIT(req); uint32_t idle_mask = 0; uint32_t idle_target = 0; uint32_t val; uint32_t wait_cnt = 0; switch (req) { case bus_ide_req_gpu: idle_mask = BIT(pmu_idle_ack_gpu) | BIT(pmu_idle_gpu); idle_target = (idle << pmu_idle_ack_gpu) | (idle << pmu_idle_gpu); break; case bus_ide_req_core: idle_mask = BIT(pmu_idle_ack_core) | BIT(pmu_idle_core); idle_target = (idle << pmu_idle_ack_core) | (idle << pmu_idle_core); break; case bus_ide_req_cpup: idle_mask = BIT(pmu_idle_ack_cpup) | BIT(pmu_idle_cpup); idle_target = (idle << pmu_idle_ack_cpup) | (idle << pmu_idle_cpup); break; case bus_ide_req_bus: idle_mask = BIT(pmu_idle_ack_bus) | BIT(pmu_idle_bus); idle_target = (idle << pmu_idle_ack_bus) | (idle << pmu_idle_bus); break; case bus_ide_req_dma: idle_mask = BIT(pmu_idle_ack_dma) | BIT(pmu_idle_dma); idle_target = (idle << pmu_idle_ack_dma) | (idle << pmu_idle_dma); break; case bus_ide_req_peri: idle_mask = BIT(pmu_idle_ack_peri) | BIT(pmu_idle_peri); idle_target = (idle << pmu_idle_ack_peri) | (idle << pmu_idle_peri); break; case bus_ide_req_video: idle_mask = BIT(pmu_idle_ack_video) | BIT(pmu_idle_video); idle_target = (idle << pmu_idle_ack_video) | (idle << pmu_idle_video); break; case bus_ide_req_hevc: idle_mask = BIT(pmu_idle_ack_hevc) | BIT(pmu_idle_hevc); idle_target = (idle << pmu_idle_ack_hevc) | (idle << pmu_idle_hevc); break; case bus_ide_req_vio: idle_mask = BIT(pmu_idle_ack_vio) | BIT(pmu_idle_vio); idle_target = (pmu_idle_ack_vio) | (idle << pmu_idle_vio); break; case bus_ide_req_alive: idle_mask = BIT(pmu_idle_ack_alive) | BIT(pmu_idle_alive); idle_target = (idle << pmu_idle_ack_alive) | (idle << pmu_idle_alive); break; default: ERROR("%s: Unsupported the idle request\n", __func__); break; } val = mmio_read_32(PMU_BASE + PMU_BUS_IDE_REQ); if (idle) val |= mask; else val &= ~mask; mmio_write_32(PMU_BASE + PMU_BUS_IDE_REQ, val); while ((mmio_read_32(PMU_BASE + PMU_BUS_IDE_ST) & idle_mask) != idle_target) { wait_cnt++; if (!(wait_cnt % MAX_WAIT_CONUT)) WARN("%s:st=%x(%x)\n", __func__, mmio_read_32(PMU_BASE + PMU_BUS_IDE_ST), idle_mask); } return 0; } static bool rk3288_sleep_disable_osc(void) { static const uint32_t reg_offset[] = { GRF_UOC0_CON0, GRF_UOC1_CON0, GRF_UOC2_CON0 }; uint32_t reg, i; /* * if any usb phy is still on(GRF_SIDDQ==0), that means we need the * function of usb wakeup, so do not switch to 32khz, since the usb phy * clk does not connect to 32khz osc */ for (i = 0; i < ARRAY_SIZE(reg_offset); i++) { reg = mmio_read_32(GRF_BASE + reg_offset[i]); if (!(reg & GRF_SIDDQ)) return false; } return true; } static void pmu_set_sleep_mode(int level) { uint32_t mode_set, mode_set1; bool osc_disable = rk3288_sleep_disable_osc(); mode_set = BIT(pmu_mode_glb_int_dis) | BIT(pmu_mode_l2_flush_en) | BIT(pmu_mode_sref0_enter) | BIT(pmu_mode_sref1_enter) | BIT(pmu_mode_ddrc0_gt) | BIT(pmu_mode_ddrc1_gt) | BIT(pmu_mode_en) | BIT(pmu_mode_chip_pd) | BIT(pmu_mode_scu_pd); mode_set1 = BIT(pmu_mode_clr_core) | BIT(pmu_mode_clr_cpup); if (level == ROCKCHIP_ARM_OFF_LOGIC_DEEP) { /* arm off, logic deep sleep */ mode_set |= BIT(pmu_mode_bus_pd) | BIT(pmu_mode_pmu_use_lf) | BIT(pmu_mode_ddrio1_ret) | BIT(pmu_mode_ddrio0_ret) | BIT(pmu_mode_pmu_alive_use_lf) | BIT(pmu_mode_pll_pd); if (osc_disable) mode_set |= BIT(pmu_mode_osc_dis); mode_set1 |= BIT(pmu_mode_clr_alive) | BIT(pmu_mode_clr_bus) | BIT(pmu_mode_clr_peri) | BIT(pmu_mode_clr_dma); mmio_write_32(PMU_BASE + PMU_WAKEUP_CFG1, pmu_armint_wakeup_en); /* * In deep suspend we use PMU_PMU_USE_LF to let the rk3288 * switch its main clock supply to the alternative 32kHz * source. Therefore set 30ms on a 32kHz clock for pmic * stabilization. Similar 30ms on 24MHz for the other * mode below. */ mmio_write_32(PMU_BASE + PMU_STABL_CNT, 32 * 30); /* only wait for stabilization, if we turned the osc off */ mmio_write_32(PMU_BASE + PMU_OSC_CNT, osc_disable ? 32 * 30 : 0); } else { /* * arm off, logic normal * if pmu_clk_core_src_gate_en is not set, * wakeup will be error */ mode_set |= BIT(pmu_mode_core_src_gt); mmio_write_32(PMU_BASE + PMU_WAKEUP_CFG1, BIT(pmu_armint_wakeup_en) | BIT(pmu_gpioint_wakeup_en)); /* 30ms on a 24MHz clock for pmic stabilization */ mmio_write_32(PMU_BASE + PMU_STABL_CNT, 24000 * 30); /* oscillator is still running, so no need to wait */ mmio_write_32(PMU_BASE + PMU_OSC_CNT, 0); } mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, mode_set); mmio_write_32(PMU_BASE + PMU_PWRMODE_CON1, mode_set1); } static int cpus_power_domain_on(uint32_t cpu_id) { uint32_t cpu_pd; cpu_pd = PD_CPU0 + cpu_id; /* if the core has been on, power it off first */ if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) { /* put core in reset - some sort of A12/A17 bug */ mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(0), BIT(cpu_id) | (BIT(cpu_id) << 16)); pmu_power_domain_ctr(cpu_pd, pmu_pd_off); } pmu_power_domain_ctr(cpu_pd, pmu_pd_on); /* pull core out of reset */ mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(0), BIT(cpu_id) << 16); return 0; } static int cpus_power_domain_off(uint32_t cpu_id) { uint32_t cpu_pd = PD_CPU0 + cpu_id; if (pmu_power_domain_st(cpu_pd) == pmu_pd_off) return 0; if (check_cpu_wfie(cpu_id, CKECK_WFEI_MSK)) return -EINVAL; /* put core in reset - some sort of A12/A17 bug */ mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(0), BIT(cpu_id) | (BIT(cpu_id) << 16)); pmu_power_domain_ctr(cpu_pd, pmu_pd_off); return 0; } static void nonboot_cpus_off(void) { uint32_t boot_cpu, cpu; boot_cpu = plat_my_core_pos(); boot_cpu = MPIDR_AFFLVL0_VAL(read_mpidr()); /* turn off noboot cpus */ for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) { if (cpu == boot_cpu) continue; cpus_power_domain_off(cpu); } } void sram_save(void) { /* TODO: support the sdram save for rk3288 SoCs*/ } void sram_restore(void) { /* TODO: support the sdram restore for rk3288 SoCs */ } int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint) { uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr); assert(cpu_id < PLATFORM_CORE_COUNT); assert(cpuson_flags[cpu_id] == 0); cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG; cpuson_entry_point[cpu_id] = entrypoint; dsb(); cpus_power_domain_on(cpu_id); /* * We communicate with the bootrom to active the cpus other * than cpu0, after a blob of initialize code, they will * stay at wfe state, once they are actived, they will check * the mailbox: * sram_base_addr + 4: 0xdeadbeaf * sram_base_addr + 8: start address for pc * The cpu0 need to wait the other cpus other than cpu0 entering * the wfe state.The wait time is affected by many aspects. * (e.g: cpu frequency, bootrom frequency, sram frequency, ...) */ mdelay(1); /* ensure the cpus other than cpu0 to startup */ /* tell the bootrom mailbox where to start from */ mmio_write_32(SRAM_BASE + 8, cpu_warm_boot_addr); mmio_write_32(SRAM_BASE + 4, 0xDEADBEAF); dsb(); sev(); return 0; } int rockchip_soc_cores_pwr_dm_on_finish(void) { return 0; } int rockchip_soc_sys_pwr_dm_resume(void) { mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, store_pmu_pwrmode_con); mmio_write_32(SGRF_BASE + SGRF_CPU_CON(0), store_sgrf_cpu_con0 | SGRF_DAPDEVICE_MSK); /* disable fastboot mode */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(0), store_sgrf_soc_con0 | SGRF_FAST_BOOT_DIS); secure_watchdog_ungate(); clk_gate_con_restore(); clk_sel_con_restore(); clk_plls_resume(); secure_gic_init(); plat_rockchip_gic_init(); return 0; } int rockchip_soc_sys_pwr_dm_suspend(void) { nonboot_cpus_off(); store_sgrf_cpu_con0 = mmio_read_32(SGRF_BASE + SGRF_CPU_CON(0)); store_sgrf_soc_con0 = mmio_read_32(SGRF_BASE + SGRF_SOC_CON(0)); store_pmu_pwrmode_con = mmio_read_32(PMU_BASE + PMU_PWRMODE_CON); /* save clk-gates and ungate all for suspend */ clk_gate_con_save(); clk_gate_con_disable(); clk_sel_con_save(); pmu_set_sleep_mode(ROCKCHIP_ARM_OFF_LOGIC_NORMAL); clk_plls_suspend(); secure_watchdog_gate(); /* * The dapswjdp can not auto reset before resume, that cause it may * access some illegal address during resume. Let's disable it before * suspend, and the MASKROM will enable it back. */ mmio_write_32(SGRF_BASE + SGRF_CPU_CON(0), SGRF_DAPDEVICE_MSK); /* * SGRF_FAST_BOOT_EN - system to boot from FAST_BOOT_ADDR */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(0), SGRF_FAST_BOOT_ENA); /* boot-address of resuming system is from this register value */ mmio_write_32(SGRF_BASE + SGRF_FAST_BOOT_ADDR, (uint32_t)&pmu_cpuson_entrypoint); /* flush all caches - otherwise we might loose the resume address */ dcsw_op_all(DC_OP_CISW); return 0; } void rockchip_plat_mmu_svc_mon(void) { } void plat_rockchip_pmu_init(void) { uint32_t cpu; cpu_warm_boot_addr = (uint32_t)platform_cpu_warmboot; /* on boot all power-domains are on */ for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) cpuson_flags[cpu] = pmu_pd_on; nonboot_cpus_off(); } trusted-firmware-a-2.2/plat/rockchip/rk3288/drivers/pmu/pmu.h000066400000000000000000000054531355360272700240540ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PMU_H #define PMU_H /* Allocate sp reginon in pmusram */ #define PSRAM_SP_SIZE 0x80 #define PSRAM_SP_BOTTOM (PSRAM_SP_TOP - PSRAM_SP_SIZE) /***************************************************************************** * pmu con,reg *****************************************************************************/ #define PMU_WAKEUP_CFG0 0x0 #define PMU_WAKEUP_CFG1 0x4 #define PMU_PWRDN_CON 0x8 #define PMU_PWRDN_ST 0xc #define PMU_PWRMODE_CON 0x18 #define PMU_BUS_IDE_REQ 0x10 #define PMU_BUS_IDE_ST 0x14 #define PMU_OSC_CNT 0x20 #define PMU_PLL_CNT 0x24 #define PMU_STABL_CNT 0x28 #define PMU_DDRIO0_PWR_CNT 0x2c #define PMU_DDRIO1_PWR_CNT 0x30 #define PMU_WKUPRST_CNT 0x44 #define PMU_SFT_CON 0x48 #define PMU_PWRMODE_CON1 0x90 enum pmu_pdid { PD_CPU0 = 0, PD_CPU1, PD_CPU2, PD_CPU3, PD_BUS = 5, PD_PERI, PD_VIO, PD_VIDEO, PD_GPU, PD_SCU = 11, PD_HEVC = 14, PD_END }; enum pmu_bus_ide { bus_ide_req_bus = 0, bus_ide_req_peri, bus_ide_req_gpu, bus_ide_req_video, bus_ide_req_vio, bus_ide_req_core, bus_ide_req_alive, bus_ide_req_dma, bus_ide_req_cpup, bus_ide_req_hevc, bus_ide_req_end }; enum pmu_pwrmode { pmu_mode_en = 0, pmu_mode_core_src_gt, pmu_mode_glb_int_dis, pmu_mode_l2_flush_en, pmu_mode_bus_pd, pmu_mode_cpu0_pd, pmu_mode_scu_pd, pmu_mode_pll_pd = 7, pmu_mode_chip_pd, pmu_mode_pwr_off_comb, pmu_mode_pmu_alive_use_lf, pmu_mode_pmu_use_lf, pmu_mode_osc_dis = 12, pmu_mode_input_clamp, pmu_mode_wkup_rst, pmu_mode_sref0_enter, pmu_mode_sref1_enter, pmu_mode_ddrio0_ret, pmu_mode_ddrio1_ret, pmu_mode_ddrc0_gt, pmu_mode_ddrc1_gt, pmu_mode_ddrio0_ret_deq, pmu_mode_ddrio1_ret_deq, }; enum pmu_pwrmode1 { pmu_mode_clr_bus = 0, pmu_mode_clr_core, pmu_mode_clr_cpup, pmu_mode_clr_alive, pmu_mode_clr_dma, pmu_mode_clr_peri, pmu_mode_clr_gpu, pmu_mode_clr_video, pmu_mode_clr_hevc, pmu_mode_clr_vio }; enum pmu_sft_con { pmu_sft_ddrio0_ret_cfg = 6, pmu_sft_ddrio1_ret_cfg = 9, pmu_sft_l2flsh = 15, }; enum pmu_wakeup_cfg1 { pmu_armint_wakeup_en = 0, pmu_gpio_wakeup_negedge, pmu_sdmmc0_wakeup_en, pmu_gpioint_wakeup_en, }; enum pmu_bus_idle_st { pmu_idle_bus = 0, pmu_idle_peri, pmu_idle_gpu, pmu_idle_video, pmu_idle_vio, pmu_idle_core, pmu_idle_alive, pmu_idle_dma, pmu_idle_cpup, pmu_idle_hevc, pmu_idle_ack_bus = 16, pmu_idle_ack_peri, pmu_idle_ack_gpu, pmu_idle_ack_video, pmu_idle_ack_vio, pmu_idle_ack_core, pmu_idle_ack_alive, pmu_idle_ack_dma, pmu_idle_ack_cpup, pmu_idle_ack_hevc, }; #define CHECK_CPU_WFIE_BASE (0) #define clstl_cpu_wfe -1 #define clstb_cpu_wfe -1 #define CKECK_WFEI_MSK 0 #define PD_CTR_LOOP 500 #define CHK_CPU_LOOP 500 #define MAX_WAIT_CONUT 1000 #endif /* PMU_H */ trusted-firmware-a-2.2/plat/rockchip/rk3288/drivers/secure/000077500000000000000000000000001355360272700235605ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3288/drivers/secure/secure.c000066400000000000000000000110021355360272700252040ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include static void sgrf_ddr_rgn_global_bypass(uint32_t bypass) { if (bypass) /* set bypass (non-secure regions) for whole ddr regions */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(21), SGRF_DDR_RGN_BYPS); else /* cancel bypass for whole ddr regions */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(21), SGRF_DDR_RGN_NO_BYPS); } /** * There are 8 + 1 regions for DDR secure control: * DDR_RGN_0 ~ DDR_RGN_7: Per DDR_RGNs grain size is 1MB * DDR_RGN_X - the memories of exclude DDR_RGN_0 ~ DDR_RGN_7 * * SGRF_SOC_CON6 - start address of RGN_0 + control * SGRF_SOC_CON7 - end address of RGN_0 * ... * SGRF_SOC_CON20 - start address of the RGN_7 + control * SGRF_SOC_CON21 - end address of the RGN_7 + RGN_X control * * @rgn - the DDR regions 0 ~ 7 which are can be configured. * The @st and @ed indicate the start and end addresses for which to set * the security, and the unit is byte. When the st_mb == 0, ed_mb == 0, the * address range 0x0 ~ 0xfffff is secure. * * For example, if we would like to set the range [0, 32MB) is security via * DDR_RGN0, then rgn == 0, st_mb == 0, ed_mb == 31. */ static void sgrf_ddr_rgn_config(uint32_t rgn, uintptr_t st, uintptr_t ed) { uintptr_t st_mb, ed_mb; assert(rgn <= 7); assert(st < ed); /* check aligned 1MB */ assert(st % SIZE_M(1) == 0); assert(ed % SIZE_M(1) == 0); st_mb = st / SIZE_M(1); ed_mb = ed / SIZE_M(1); /* set ddr region addr start */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6 + (rgn * 2)), BITS_WITH_WMASK(st_mb, SGRF_DDR_RGN_ADDR_WMSK, 0)); /* set ddr region addr end */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6 + (rgn * 2) + 1), BITS_WITH_WMASK((ed_mb - 1), SGRF_DDR_RGN_ADDR_WMSK, 0)); /* select region security */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6 + (rgn * 2)), SGRF_DDR_RGN_SECURE_SEL); /* enable region security */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6 + (rgn * 2)), SGRF_DDR_RGN_SECURE_EN); } void secure_watchdog_gate(void) { mmio_write_32(SGRF_BASE + SGRF_SOC_CON(0), SGRF_PCLK_WDT_GATE); } void secure_watchdog_ungate(void) { mmio_write_32(SGRF_BASE + SGRF_SOC_CON(0), SGRF_PCLK_WDT_UNGATE); } __pmusramfunc void sram_secure_timer_init(void) { mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, 0); mmio_write_32(STIMER1_BASE + TIMER_LOAD_COUNT0, 0xffffffff); mmio_write_32(STIMER1_BASE + TIMER_LOAD_COUNT1, 0xffffffff); /* auto reload & enable the timer */ mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, TIMER_EN); } void secure_gic_init(void) { /* (re-)enable non-secure access to the gic*/ mmio_write_32(CORE_AXI_BUS_BASE + CORE_AXI_SECURITY0, AXI_SECURITY0_GIC); } void secure_timer_init(void) { mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, 0); mmio_write_32(STIMER1_BASE + TIMER_LOAD_COUNT0, 0xffffffff); mmio_write_32(STIMER1_BASE + TIMER_LOAD_COUNT1, 0xffffffff); /* auto reload & enable the timer */ mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, TIMER_EN); } void secure_sgrf_init(void) { /* * We use the first sram part to talk to the bootrom, * so make it secure. */ mmio_write_32(TZPC_BASE + TZPC_R0SIZE, TZPC_SRAM_SECURE_4K(1)); secure_gic_init(); /* set all master ip to non-secure */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(2), SGRF_SOC_CON2_MST_NS); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(3), SGRF_SOC_CON3_MST_NS); /* setting all configurable ip into non-secure */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(4), SGRF_SOC_CON4_SECURE_WMSK /*TODO:|SGRF_STIMER_SECURE*/); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(5), SGRF_SOC_CON5_SECURE_WMSK); /* secure dma to non-secure */ mmio_write_32(TZPC_BASE + TZPC_DECPROT1SET, 0xff); mmio_write_32(TZPC_BASE + TZPC_DECPROT2SET, 0xff); mmio_write_32(SGRF_BASE + SGRF_BUSDMAC_CON(1), 0x3800); dsb(); /* rst dma1 */ mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(1), RST_DMA1_MSK | (RST_DMA1_MSK << 16)); /* rst dma2 */ mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(4), RST_DMA2_MSK | (RST_DMA2_MSK << 16)); dsb(); /* release dma1 rst*/ mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(1), (RST_DMA1_MSK << 16)); /* release dma2 rst*/ mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(4), (RST_DMA2_MSK << 16)); } void secure_sgrf_ddr_rgn_init(void) { sgrf_ddr_rgn_config(0, TZRAM_BASE, TZRAM_SIZE); sgrf_ddr_rgn_global_bypass(0); } trusted-firmware-a-2.2/plat/rockchip/rk3288/drivers/secure/secure.h000066400000000000000000000063361355360272700252270ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SECURE_H #define SECURE_H /****************************************************************************** * TZPC TrustZone controller ******************************************************************************/ #define TZPC_R0SIZE 0x0 #define TZPC_SRAM_SECURE_4K(n) ((n) > 0x200 ? 0x200 : (n)) #define TZPC_DECPROT1STAT 0x80c #define TZPC_DECPROT1SET 0x810 #define TZPC_DECPROT1CLR 0x814 #define TZPC_DECPROT2STAT 0x818 #define TZPC_DECPROT2SET 0x818 #define TZPC_DECPROT2CLR 0x820 /************************************************** * sgrf reg, offset **************************************************/ /* * soc_con0-5 start at 0x0, soc_con6-... start art 0x50 * adjusted for the 5 lower registers */ #define SGRF_SOC_CON(n) ((((n) < 6) ? 0x0 : 0x38) + (n) * 4) #define SGRF_BUSDMAC_CON(n) (0x20 + (n) * 4) #define SGRF_CPU_CON(n) (0x40 + (n) * 4) #define SGRF_SOC_STATUS(n) (0x100 + (n) * 4) #define SGRF_FAST_BOOT_ADDR 0x120 /* SGRF_SOC_CON0 */ #define SGRF_FAST_BOOT_ENA BIT_WITH_WMSK(8) #define SGRF_FAST_BOOT_DIS WMSK_BIT(8) #define SGRF_PCLK_WDT_GATE BIT_WITH_WMSK(6) #define SGRF_PCLK_WDT_UNGATE WMSK_BIT(6) #define SGRF_PCLK_STIMER_GATE BIT_WITH_WMSK(4) #define SGRF_SOC_CON2_MST_NS 0xffe0ffe0 #define SGRF_SOC_CON3_MST_NS 0x003f003f /* SGRF_SOC_CON4 */ #define SGRF_SOC_CON4_SECURE_WMSK 0xffff0000 #define SGRF_DDRC1_SECURE BIT_WITH_WMSK(12) #define SGRF_DDRC0_SECURE BIT_WITH_WMSK(11) #define SGRF_PMUSRAM_SECURE BIT_WITH_WMSK(8) #define SGRF_WDT_SECURE BIT_WITH_WMSK(7) #define SGRF_STIMER_SECURE BIT_WITH_WMSK(6) /* SGRF_SOC_CON5 */ #define SGRF_SLV_SEC_BYPS BIT_WITH_WMSK(15) #define SGRF_SLV_SEC_NO_BYPS WMSK_BIT(15) #define SGRF_SOC_CON5_SECURE_WMSK 0x00ff0000 /* ddr regions in SGRF_SOC_CON6 and following */ #define SGRF_DDR_RGN_SECURE_SEL BIT_WITH_WMSK(15) #define SGRF_DDR_RGN_SECURE_EN BIT_WITH_WMSK(14) #define SGRF_DDR_RGN_ADDR_WMSK 0x0fff /* SGRF_SOC_CON21 */ /* All security of the DDR RGNs are bypassed */ #define SGRF_DDR_RGN_BYPS BIT_WITH_WMSK(15) #define SGRF_DDR_RGN_NO_BYPS WMSK_BIT(15) /* SGRF_CPU_CON0 */ #define SGRF_DAPDEVICE_ENA BIT_WITH_WMSK(0) #define SGRF_DAPDEVICE_MSK WMSK_BIT(0) /***************************************************************************** * core-axi *****************************************************************************/ #define CORE_AXI_SECURITY0 0x08 #define AXI_SECURITY0_GIC BIT(0) /***************************************************************************** * secure timer *****************************************************************************/ #define TIMER_LOAD_COUNT0 0x00 #define TIMER_LOAD_COUNT1 0x04 #define TIMER_CURRENT_VALUE0 0x08 #define TIMER_CURRENT_VALUE1 0x0C #define TIMER_CONTROL_REG 0x10 #define TIMER_INTSTATUS 0x18 #define TIMER_EN 0x1 #define STIMER1_BASE (STIME_BASE + 0x20) /* export secure operating APIs */ void secure_watchdog_gate(void); void secure_watchdog_ungate(void); void secure_gic_init(void); void secure_timer_init(void); void secure_sgrf_init(void); void secure_sgrf_ddr_rgn_init(void); __pmusramfunc void sram_secure_timer_init(void); #endif /* SECURE_H */ trusted-firmware-a-2.2/plat/rockchip/rk3288/drivers/soc/000077500000000000000000000000001355360272700230565ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3288/drivers/soc/soc.c000066400000000000000000000136541355360272700240170ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include /* sleep data for pll suspend */ static struct deepsleep_data_s slp_data; /* Table of regions to map using the MMU. */ const mmap_region_t plat_rk_mmap[] = { MAP_REGION_FLAT(GIC400_BASE, GIC400_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(STIME_BASE, STIME_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(SGRF_BASE, SGRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(TZPC_BASE, TZPC_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(PMUSRAM_BASE, PMUSRAM_SIZE, MT_MEMORY | MT_RW | MT_SECURE), MAP_REGION_FLAT(SRAM_BASE, SRAM_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(PMU_BASE, PMU_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(UART0_BASE, UART0_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(UART1_BASE, UART1_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(UART2_BASE, UART2_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(UART3_BASE, UART3_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(UART4_BASE, UART4_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(CRU_BASE, CRU_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(GRF_BASE, GRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DDR_PCTL0_BASE, DDR_PCTL0_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DDR_PHY0_BASE, DDR_PHY0_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DDR_PCTL1_BASE, DDR_PCTL1_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DDR_PHY1_BASE, DDR_PHY1_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(SERVICE_BUS_BASE, SERVICE_BUS_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(CORE_AXI_BUS_BASE, CORE_AXI_BUS_SIZE, MT_DEVICE | MT_RW | MT_SECURE), { 0 } }; /* The RockChip power domain tree descriptor */ const unsigned char rockchip_power_domain_tree_desc[] = { /* No of root nodes */ PLATFORM_SYSTEM_COUNT, /* No of children for the root node */ PLATFORM_CLUSTER_COUNT, /* No of children for the first cluster node */ PLATFORM_CLUSTER0_CORE_COUNT, }; void plat_rockchip_soc_init(void) { secure_timer_init(); secure_sgrf_init(); /* * We cannot enable ddr security at this point, as the kernel * seems to have an issue with it even living in the same 128MB * memory block. Only when moving the kernel to the second * 128MB block does it not conflict, but then we'd loose this * memory area for use. Late maybe enable * secure_sgrf_ddr_rgn_init(); */ } void regs_update_bits(uintptr_t addr, uint32_t val, uint32_t mask, uint32_t shift) { uint32_t tmp, orig; orig = mmio_read_32(addr); tmp = orig & ~(mask << shift); tmp |= (val & mask) << shift; if (tmp != orig) mmio_write_32(addr, tmp); dsb(); } static void pll_save(uint32_t pll_id) { uint32_t *pll = slp_data.pll_con[pll_id]; pll[0] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 0)); pll[1] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 1)); pll[2] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 2)); pll[3] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 3)); } void clk_plls_suspend(void) { pll_save(NPLL_ID); pll_save(CPLL_ID); pll_save(GPLL_ID); pll_save(APLL_ID); slp_data.pll_mode = mmio_read_32(CRU_BASE + PLL_MODE_CON); /* * Switch PLLs other than DPLL (for SDRAM) to slow mode to * avoid crashes on resume. The Mask ROM on the system will * put APLL, CPLL, and GPLL into slow mode at resume time * anyway (which is why we restore them), but we might not * even make it to the Mask ROM if this isn't done at suspend * time. * * NOTE: only APLL truly matters here, but we'll do them all. */ mmio_write_32(CRU_BASE + PLL_MODE_CON, 0xf3030000); } void clk_plls_resume(void) { /* restore pll-modes */ mmio_write_32(CRU_BASE + PLL_MODE_CON, slp_data.pll_mode | REG_SOC_WMSK); } void clk_gate_con_save(void) { uint32_t i = 0; for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) slp_data.cru_gate_con[i] = mmio_read_32(CRU_BASE + CRU_CLKGATES_CON(i)); } void clk_gate_con_disable(void) { uint32_t i; for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), REG_SOC_WMSK); } void clk_gate_con_restore(void) { uint32_t i; for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), REG_SOC_WMSK | slp_data.cru_gate_con[i]); } void clk_sel_con_save(void) { uint32_t i = 0; for (i = 0; i < CRU_CLKSELS_CON_CNT; i++) slp_data.cru_sel_con[i] = mmio_read_32(CRU_BASE + CRU_CLKSELS_CON(i)); } void clk_sel_con_restore(void) { uint32_t i, val; for (i = 0; i < CRU_CLKSELS_CON_CNT; i++) { /* fractional dividers don't have write-masks */ if ((i >= 7 && i <= 9) || (i >= 17 && i <= 20) || (i == 23) || (i == 41)) val = slp_data.cru_sel_con[i]; else val = slp_data.cru_sel_con[i] | REG_SOC_WMSK; mmio_write_32(CRU_BASE + CRU_CLKSELS_CON(i), val); } } void __dead2 rockchip_soc_soft_reset(void) { uint32_t temp_val; /* * Switch PLLs other than DPLL (for SDRAM) to slow mode to * avoid crashes on resume. The Mask ROM on the system will * put APLL, CPLL, and GPLL into slow mode at resume time * anyway (which is why we restore them), but we might not * even make it to the Mask ROM if this isn't done at suspend * time. * * NOTE: only APLL truly matters here, but we'll do them all. */ mmio_write_32(CRU_BASE + PLL_MODE_CON, 0xf3030000); temp_val = mmio_read_32(CRU_BASE + CRU_GLB_RST_CON); temp_val &= ~PMU_RST_MASK; temp_val |= PMU_RST_BY_SECOND_SFT; mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, temp_val); mmio_write_32(CRU_BASE + CRU_GLB_SRST_SND, 0xeca8); /* * Maybe the HW needs some times to reset the system, * so we do not hope the core to excute valid codes. */ while (1) ; } trusted-firmware-a-2.2/plat/rockchip/rk3288/drivers/soc/soc.h000066400000000000000000000063161355360272700240210ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SOC_H #define SOC_H enum plls_id { APLL_ID = 0, DPLL_ID, CPLL_ID, GPLL_ID, NPLL_ID, END_PLL_ID, }; #define CYCL_24M_CNT_US(us) (24 * (us)) #define CYCL_24M_CNT_MS(ms) ((ms) * CYCL_24M_CNT_US(1000)) /***************************************************************************** * grf regs *****************************************************************************/ #define GRF_UOC0_CON0 0x320 #define GRF_UOC1_CON0 0x334 #define GRF_UOC2_CON0 0x348 #define GRF_SIDDQ BIT(13) /***************************************************************************** * cru reg, offset *****************************************************************************/ #define CRU_SOFTRST_CON 0x1b8 #define CRU_SOFTRSTS_CON(n) (CRU_SOFTRST_CON + ((n) * 4)) #define CRU_SOFTRSTS_CON_CNT 11 #define RST_DMA1_MSK 0x4 #define RST_DMA2_MSK 0x1 #define CRU_CLKSEL_CON 0x60 #define CRU_CLKSELS_CON(i) (CRU_CLKSEL_CON + ((i) * 4)) #define CRU_CLKSELS_CON_CNT 42 #define CRU_CLKGATE_CON 0x160 #define CRU_CLKGATES_CON(i) (CRU_CLKGATE_CON + ((i) * 4)) #define CRU_CLKGATES_CON_CNT 18 #define CRU_GLB_SRST_FST 0x1b0 #define CRU_GLB_SRST_SND 0x1b4 #define CRU_GLB_RST_CON 0x1f0 #define CRU_CONS_GATEID(i) (16 * (i)) #define GATE_ID(reg, bit) (((reg) * 16) + (bit)) #define PMU_RST_MASK 0x3 #define PMU_RST_BY_FIRST_SFT (0 << 2) #define PMU_RST_BY_SECOND_SFT (1 << 2) #define PMU_RST_NOT_BY_SFT (2 << 2) /*************************************************************************** * pll ***************************************************************************/ #define PLL_CON_COUNT 4 #define PLL_CONS(id, i) ((id) * 0x10 + ((i) * 4)) #define PLL_PWR_DN_MSK BIT(1) #define PLL_PWR_DN REG_WMSK_BITS(1, 1, 0x1) #define PLL_PWR_ON REG_WMSK_BITS(0, 1, 0x1) #define PLL_RESET REG_WMSK_BITS(1, 5, 0x1) #define PLL_RESET_RESUME REG_WMSK_BITS(0, 5, 0x1) #define PLL_BYPASS_MSK BIT(0) #define PLL_BYPASS_W_MSK (PLL_BYPASS_MSK << 16) #define PLL_BYPASS REG_WMSK_BITS(1, 0, 0x1) #define PLL_NO_BYPASS REG_WMSK_BITS(0, 0, 0x1) #define PLL_MODE_CON 0x50 struct deepsleep_data_s { uint32_t pll_con[END_PLL_ID][PLL_CON_COUNT]; uint32_t pll_mode; uint32_t cru_sel_con[CRU_CLKSELS_CON_CNT]; uint32_t cru_gate_con[CRU_CLKGATES_CON_CNT]; }; #define REG_W_MSK(bits_shift, msk) \ ((msk) << ((bits_shift) + 16)) #define REG_VAL_CLRBITS(val, bits_shift, msk) \ ((val) & (~((msk) << bits_shift))) #define REG_SET_BITS(bits, bits_shift, msk) \ (((bits) & (msk)) << (bits_shift)) #define REG_WMSK_BITS(bits, bits_shift, msk) \ (REG_W_MSK(bits_shift, msk) | \ REG_SET_BITS(bits, bits_shift, msk)) #define REG_SOC_WMSK 0xffff0000 #define regs_update_bit_set(addr, shift) \ regs_update_bits((addr), 0x1, 0x1, (shift)) #define regs_update_bit_clr(addr, shift) \ regs_update_bits((addr), 0x0, 0x1, (shift)) void regs_update_bits(uintptr_t addr, uint32_t val, uint32_t mask, uint32_t shift); void clk_plls_suspend(void); void clk_plls_resume(void); void clk_gate_con_save(void); void clk_gate_con_disable(void); void clk_gate_con_restore(void); void clk_sel_con_save(void); void clk_sel_con_restore(void); #endif /* SOC_H */ trusted-firmware-a-2.2/plat/rockchip/rk3288/include/000077500000000000000000000000001355360272700222375ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3288/include/plat_sip_calls.h000066400000000000000000000003601355360272700254000ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_SIP_CALLS_H #define PLAT_SIP_CALLS_H #define RK_PLAT_SIP_NUM_CALLS 0 #endif /* PLAT_SIP_CALLS_H */ trusted-firmware-a-2.2/plat/rockchip/rk3288/include/plat_sp_min.ld.S000066400000000000000000000032251355360272700252700ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ROCKCHIP_PLAT_LD_S #define ROCKCHIP_PLAT_LD_S #include MEMORY { SRAM (rwx): ORIGIN = SRAM_BASE, LENGTH = SRAM_SIZE PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE } SECTIONS { . = SRAM_BASE; ASSERT(. == ALIGN(PAGE_SIZE), "SRAM_BASE address is not aligned on a page boundary.") .text_sram : ALIGN(PAGE_SIZE) { __bl32_sram_text_start = .; *(.sram.text) *(.sram.rodata) __bl32_sram_text_real_end = .; . = ALIGN(PAGE_SIZE); __bl32_sram_text_end = .; } >SRAM ASSERT((__bl32_sram_text_real_end - __bl32_sram_text_start) <= SRAM_TEXT_LIMIT, ".text_sram has exceeded its limit") .data_sram : ALIGN(PAGE_SIZE) { __bl32_sram_data_start = .; *(.sram.data) __bl32_sram_data_real_end = .; . = ALIGN(PAGE_SIZE); __bl32_sram_data_end = .; } >SRAM ASSERT((__bl32_sram_data_real_end - __bl32_sram_data_start) <= SRAM_DATA_LIMIT, ".data_sram has exceeded its limit") .stack_sram : ALIGN(PAGE_SIZE) { __bl32_sram_stack_start = .; . += PAGE_SIZE; __bl32_sram_stack_end = .; } >SRAM . = PMUSRAM_BASE; /* * pmu_cpuson_entrypoint request address * align 64K when resume, so put it in the * start of pmusram */ .pmusram : { ASSERT(. == ALIGN(64 * 1024), ".pmusram.entry request 64K aligned."); *(.pmusram.entry) __bl32_pmusram_text_start = .; *(.pmusram.text) *(.pmusram.rodata) __bl32_pmusram_text_end = .; __bl32_pmusram_data_start = .; *(.pmusram.data) __bl32_pmusram_data_end = .; } >PMUSRAM } #endif /* ROCKCHIP_PLAT_LD_S */ trusted-firmware-a-2.2/plat/rockchip/rk3288/include/platform_def.h000066400000000000000000000065441355360272700250630ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include #include /******************************************************************************* * Platform binary types for linking ******************************************************************************/ #define PLATFORM_LINKER_FORMAT "elf32-littlearm" #define PLATFORM_LINKER_ARCH arm /******************************************************************************* * Generic platform constants ******************************************************************************/ /* Size of cacheable stacks */ #if defined(IMAGE_BL1) #define PLATFORM_STACK_SIZE 0x440 #elif defined(IMAGE_BL2) #define PLATFORM_STACK_SIZE 0x400 #elif defined(IMAGE_BL32) #define PLATFORM_STACK_SIZE 0x800 #endif #define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n" #define PLATFORM_MAX_AFFLVL MPIDR_AFFLVL2 #define PLATFORM_SYSTEM_COUNT 1 #define PLATFORM_CLUSTER_COUNT 1 #define PLATFORM_CLUSTER0_CORE_COUNT 4 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT) #define PLATFORM_MAX_CPUS_PER_CLUSTER 4 #define PLATFORM_NUM_AFFS (PLATFORM_SYSTEM_COUNT + \ PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLAT_RK_CLST_TO_CPUID_SHIFT 6 #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2 /* * This macro defines the deepest retention state possible. A higher state * id will represent an invalid or a power down state. */ #define PLAT_MAX_RET_STATE U(1) /* * This macro defines the deepest power down states possible. Any state ID * higher than this is invalid. */ #define PLAT_MAX_OFF_STATE U(2) /******************************************************************************* * Platform specific page table and MMU setup constants ******************************************************************************/ #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define MAX_XLAT_TABLES 8 #define MAX_MMAP_REGIONS 18 /******************************************************************************* * Declarations and constants to access the mailboxes safely. Each mailbox is * aligned on the biggest cache line size in the platform. This is known only * to the platform as it might have a combination of integrated and external * caches. Such alignment ensures that two maiboxes do not sit on the same cache * line at any cache level. They could belong to different cpus/clusters & * get written while being protected by different locks causing corruption of * a valid mailbox address. ******************************************************************************/ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) /* * Define GICD and GICC and GICR base */ #define PLAT_RK_GICD_BASE RK3288_GICD_BASE #define PLAT_RK_GICC_BASE RK3288_GICC_BASE #define PLAT_RK_UART_BASE UART2_BASE #define PLAT_RK_UART_CLOCK RK3288_UART_CLOCK #define PLAT_RK_UART_BAUDRATE RK3288_BAUDRATE /* ClusterId is always 0x5 on rk3288, filter it */ #define PLAT_RK_MPIDR_CLUSTER_MASK 0 #define PLAT_RK_PRIMARY_CPU 0x0 #define PSRAM_DO_DDR_RESUME 0 #define PSRAM_CHECK_WAKEUP_CPU 0 #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/rockchip/rk3288/include/shared/000077500000000000000000000000001355360272700235055ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3288/include/shared/bl32_param.h000066400000000000000000000014611355360272700256020ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BL32_PARAM_H #define BL32_PARAM_H /******************************************************************************* * Platform memory map related constants ******************************************************************************/ /* TF text, ro, rw, Size: 1MB */ #define TZRAM_BASE (0x0) #define TZRAM_SIZE (0x100000) /******************************************************************************* * BL32 specific defines. ******************************************************************************/ /* * Put BL32 at the top of the Trusted RAM */ #define BL32_BASE (TZRAM_BASE + 0x40000) #define BL32_LIMIT (TZRAM_BASE + TZRAM_SIZE) #endif /* BL32_PARAM_H */ trusted-firmware-a-2.2/plat/rockchip/rk3288/plat_sip_calls.c000066400000000000000000000010761355360272700237550ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include uintptr_t rockchip_plat_sip_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) { ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); SMC_RET1(handle, SMC_UNK); } trusted-firmware-a-2.2/plat/rockchip/rk3288/platform.mk000066400000000000000000000041141355360272700227710ustar00rootroot00000000000000# # Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ARM_CORTEX_A12 := yes ARM_ARCH_MAJOR := 7 RK_PLAT := plat/rockchip RK_PLAT_SOC := ${RK_PLAT}/${PLAT} RK_PLAT_COMMON := ${RK_PLAT}/common DISABLE_BIN_GENERATION := 1 PLAT_INCLUDES := -I${RK_PLAT_COMMON}/ \ -I${RK_PLAT_COMMON}/include/ \ -I${RK_PLAT_COMMON}/aarch32/ \ -I${RK_PLAT_COMMON}/drivers/pmu/ \ -I${RK_PLAT_SOC}/ \ -I${RK_PLAT_SOC}/drivers/pmu/ \ -I${RK_PLAT_SOC}/drivers/secure/ \ -I${RK_PLAT_SOC}/drivers/soc/ \ -I${RK_PLAT_SOC}/include/ \ -I${RK_PLAT_SOC}/include/shared/ \ RK_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c \ ${RK_PLAT}/common/rockchip_gicv2.c PLAT_BL_COMMON_SOURCES := common/desc_image_load.c \ lib/bl_aux_params/bl_aux_params.c \ plat/common/aarch32/crash_console_helpers.S \ plat/common/plat_psci_common.c PLAT_BL_COMMON_SOURCES += lib/xlat_tables/xlat_tables_common.c \ lib/xlat_tables/aarch32/xlat_tables.c BL32_SOURCES += ${RK_GIC_SOURCES} \ drivers/arm/cci/cci.c \ drivers/ti/uart/aarch32/16550_console.S \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ lib/cpus/aarch32/cortex_a12.S \ ${RK_PLAT_COMMON}/aarch32/plat_helpers.S \ ${RK_PLAT_COMMON}/params_setup.c \ ${RK_PLAT_COMMON}/aarch32/pmu_sram_cpus_on.S \ ${RK_PLAT_COMMON}/plat_pm.c \ ${RK_PLAT_COMMON}/plat_topology.c \ ${RK_PLAT_COMMON}/aarch32/platform_common.c \ ${RK_PLAT_COMMON}/rockchip_sip_svc.c \ ${RK_PLAT_SOC}/plat_sip_calls.c \ ${RK_PLAT_SOC}/drivers/pmu/pmu.c \ ${RK_PLAT_SOC}/drivers/secure/secure.c \ ${RK_PLAT_SOC}/drivers/soc/soc.c \ MULTI_CONSOLE_API := 1 include lib/coreboot/coreboot.mk include lib/libfdt/libfdt.mk $(eval $(call add_define,PLAT_SP_MIN_EXTRA_LD_SCRIPT)) # Do not enable SVE ENABLE_SVE_FOR_NS := 0 WORKAROUND_CVE_2017_5715 := 0 trusted-firmware-a-2.2/plat/rockchip/rk3288/rk3288_def.h000066400000000000000000000070351355360272700225510ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RK3288_DEF_H #define RK3288_DEF_H /* Special value used to verify platform parameters from BL2 to BL31 */ #define RK_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL #define SIZE_K(n) ((n) * 1024) #define SIZE_M(n) ((n) * 1024 * 1024) #define SRAM_TEXT_LIMIT (4 * 1024) #define SRAM_DATA_LIMIT (4 * 1024) #define DDR_PCTL0_BASE 0xff610000 #define DDR_PCTL0_SIZE SIZE_K(64) #define DDR_PHY0_BASE 0xff620000 #define DDR_PHY0_SIZE SIZE_K(64) #define DDR_PCTL1_BASE 0xff630000 #define DDR_PCTL1_SIZE SIZE_K(64) #define DDR_PHY1_BASE 0xff640000 #define DDR_PHY1_SIZE SIZE_K(64) #define UART0_BASE 0xff180000 #define UART0_SIZE SIZE_K(64) #define UART1_BASE 0xff190000 #define UART1_SIZE SIZE_K(64) #define UART2_BASE 0xff690000 #define UART2_SIZE SIZE_K(64) #define UART3_BASE 0xff1b0000 #define UART3_SIZE SIZE_K(64) #define UART4_BASE 0xff1c0000 #define UART4_SIZE SIZE_K(64) /* 96k instead of 64k? */ #define SRAM_BASE 0xff700000 #define SRAM_SIZE SIZE_K(64) #define PMUSRAM_BASE 0xff720000 #define PMUSRAM_SIZE SIZE_K(4) #define PMUSRAM_RSIZE SIZE_K(4) #define PMU_BASE 0xff730000 #define PMU_SIZE SIZE_K(64) #define SGRF_BASE 0xff740000 #define SGRF_SIZE SIZE_K(64) #define CRU_BASE 0xff760000 #define CRU_SIZE SIZE_K(64) #define GRF_BASE 0xff770000 #define GRF_SIZE SIZE_K(64) /* timer 6+7 can be set as secure in SGRF */ #define STIME_BASE 0xff810000 #define STIME_SIZE SIZE_K(64) #define SERVICE_BUS_BASE 0xffac0000 #define SERVICE_BUS_SIZE SIZE_K(64) #define TZPC_BASE 0xffb00000 #define TZPC_SIZE SIZE_K(64) #define GIC400_BASE 0xffc00000 #define GIC400_SIZE SIZE_K(64) #define CORE_AXI_BUS_BASE 0xffd00000 #define CORE_AXI_BUS_SIZE SIZE_M(1) #define COLD_BOOT_BASE 0xffff0000 /************************************************************************** * UART related constants **************************************************************************/ #define RK3288_BAUDRATE 115200 #define RK3288_UART_CLOCK 24000000 /****************************************************************************** * System counter frequency related constants ******************************************************************************/ #define SYS_COUNTER_FREQ_IN_TICKS 24000000 /****************************************************************************** * GIC-400 & interrupt handling related constants ******************************************************************************/ /* Base rk_platform compatible GIC memory map */ #define RK3288_GICD_BASE (GIC400_BASE + 0x1000) #define RK3288_GICC_BASE (GIC400_BASE + 0x2000) #define RK3288_GICR_BASE 0 /* no GICR in GIC-400 */ /****************************************************************************** * sgi, ppi ******************************************************************************/ #define RK_IRQ_SEC_PHY_TIMER 29 /* what are these, and are they present on rk3288? */ #define RK_IRQ_SEC_SGI_0 8 #define RK_IRQ_SEC_SGI_1 9 #define RK_IRQ_SEC_SGI_2 10 #define RK_IRQ_SEC_SGI_3 11 #define RK_IRQ_SEC_SGI_4 12 #define RK_IRQ_SEC_SGI_5 13 #define RK_IRQ_SEC_SGI_6 14 #define RK_IRQ_SEC_SGI_7 15 /* * Define a list of Group 0 interrupts. */ #define PLAT_RK_GICV2_G0_IRQS \ INTR_PROP_DESC(RK_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, \ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(RK_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, \ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL) #endif /* RK3288_DEF_H */ trusted-firmware-a-2.2/plat/rockchip/rk3288/sp_min/000077500000000000000000000000001355360272700221015ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3288/sp_min/sp_min-rk3288.mk000066400000000000000000000003461355360272700246610ustar00rootroot00000000000000# # Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # BL32_SOURCES += plat/common/aarch32/platform_mp_stack.S \ plat/rockchip/common/sp_min_plat_setup.c trusted-firmware-a-2.2/plat/rockchip/rk3328/000077500000000000000000000000001355360272700206075ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3328/drivers/000077500000000000000000000000001355360272700222655ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3328/drivers/pmu/000077500000000000000000000000001355360272700230665ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3328/drivers/pmu/plat_pmu_macros.S000066400000000000000000000005631355360272700264030ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl clst_warmboot_data .macro func_rockchip_clst_warmboot .endm .macro rockchip_clst_warmboot_data clst_warmboot_data: .rept PLATFORM_CLUSTER_COUNT .word 0 .endr .endm trusted-firmware-a-2.2/plat/rockchip/rk3328/drivers/pmu/pmu.c000066400000000000000000000400601355360272700240330ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include DEFINE_BAKERY_LOCK(rockchip_pd_lock); static struct rk3328_sleep_ddr_data ddr_data; static __sramdata struct rk3328_sleep_sram_data sram_data; static uint32_t cpu_warm_boot_addr; #pragma weak rk3328_pmic_suspend #pragma weak rk3328_pmic_resume static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id) { uint32_t pd_reg, apm_reg; pd_reg = mmio_read_32(PMU_BASE + PMU_PWRDN_CON) & BIT(cpu_id); apm_reg = mmio_read_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id)) & BIT(core_pm_en); if (pd_reg && !apm_reg) return core_pwr_pd; else if (!pd_reg && apm_reg) return core_pwr_wfi; ERROR("%s: 0x%x, 0x%x\n", __func__, pd_reg, apm_reg); while (1) ; } static int cpus_power_domain_on(uint32_t cpu_id) { uint32_t cpu_pd, cfg_info; cpu_pd = PD_CPU0 + cpu_id; cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id); if (cfg_info == core_pwr_pd) { /* disable apm cfg */ mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), CORES_PM_DISABLE); /* if the cores have be on, power off it firstly */ if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) { mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), CORES_PM_DISABLE); pmu_power_domain_ctr(cpu_pd, pmu_pd_off); } pmu_power_domain_ctr(cpu_pd, pmu_pd_on); } else { if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) { WARN("%s: cpu%d is not in off,!\n", __func__, cpu_id); return -EINVAL; } mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), BIT(core_pm_sft_wakeup_en)); } return 0; } static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg) { uint32_t cpu_pd, core_pm_value; cpu_pd = PD_CPU0 + cpu_id; if (pmu_power_domain_st(cpu_pd) == pmu_pd_off) return 0; if (pd_cfg == core_pwr_pd) { if (check_cpu_wfie(cpu_id, CKECK_WFEI_MSK)) return -EINVAL; /* disable apm cfg */ mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), CORES_PM_DISABLE); pmu_power_domain_ctr(cpu_pd, pmu_pd_off); } else { core_pm_value = BIT(core_pm_en) | BIT(core_pm_dis_int); if (pd_cfg == core_pwr_wfi_int) core_pm_value |= BIT(core_pm_int_wakeup_en); mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), core_pm_value); } return 0; } static void nonboot_cpus_off(void) { uint32_t boot_cpu, cpu; /* turn off noboot cpus */ boot_cpu = plat_my_core_pos(); for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) { if (cpu == boot_cpu) continue; cpus_power_domain_off(cpu, core_pwr_pd); } } void sram_save(void) { /* TODO: support the sdram save for rk3328 SoCs*/ } void sram_restore(void) { /* TODO: support the sdram restore for rk3328 SoCs */ } int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint) { uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr); assert(cpu_id < PLATFORM_CORE_COUNT); assert(cpuson_flags[cpu_id] == 0); cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG; cpuson_entry_point[cpu_id] = entrypoint; dsb(); cpus_power_domain_on(cpu_id); return 0; } int rockchip_soc_cores_pwr_dm_off(void) { uint32_t cpu_id = plat_my_core_pos(); cpus_power_domain_off(cpu_id, core_pwr_wfi); return 0; } int rockchip_soc_cores_pwr_dm_suspend(void) { uint32_t cpu_id = plat_my_core_pos(); assert(cpu_id < PLATFORM_CORE_COUNT); assert(cpuson_flags[cpu_id] == 0); cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN; cpuson_entry_point[cpu_id] = (uintptr_t)plat_get_sec_entrypoint(); dsb(); cpus_power_domain_off(cpu_id, core_pwr_wfi_int); return 0; } int rockchip_soc_cores_pwr_dm_on_finish(void) { uint32_t cpu_id = plat_my_core_pos(); mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), CORES_PM_DISABLE); return 0; } int rockchip_soc_cores_pwr_dm_resume(void) { uint32_t cpu_id = plat_my_core_pos(); mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(cpu_id), CORES_PM_DISABLE); return 0; } void __dead2 rockchip_soc_soft_reset(void) { mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(CPLL_ID)); mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(GPLL_ID)); mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(NPLL_ID)); mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(APLL_ID)); dsb(); mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, CRU_GLB_SRST_FST_VALUE); dsb(); /* * Maybe the HW needs some times to reset the system, * so we do not hope the core to excute valid codes. */ while (1) ; } /* * For PMIC RK805, its sleep pin is connect with gpio2_d2 from rk3328. * If the PMIC is configed for responding the sleep pin to power off it, * once the pin is output high, it will get the pmic power off. */ void __dead2 rockchip_soc_system_off(void) { uint32_t val; /* gpio config */ val = mmio_read_32(GRF_BASE + GRF_GPIO2D_IOMUX); val &= ~GPIO2_D2_GPIO_MODE; mmio_write_32(GRF_BASE + GRF_GPIO2D_IOMUX, val); /* config output */ val = mmio_read_32(GPIO2_BASE + SWPORTA_DDR); val |= GPIO2_D2; mmio_write_32(GPIO2_BASE + SWPORTA_DDR, val); /* config output high level */ val = mmio_read_32(GPIO2_BASE); val |= GPIO2_D2; mmio_write_32(GPIO2_BASE, val); dsb(); while (1) ; } static uint32_t clk_ungt_msk[CRU_CLKGATE_NUMS] = { 0x187f, 0x0000, 0x010c, 0x0000, 0x0200, 0x0010, 0x0000, 0x0017, 0x001f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0003, 0x0000, 0xf001, 0x27c0, 0x04D9, 0x03ff, 0x0000, 0x0000, 0x0000, 0x0010, 0x0000, 0x0000, 0x0000, 0x0000, 0x0003, 0x0008 }; static void clks_gating_suspend(uint32_t *ungt_msk) { int i; for (i = 0; i < CRU_CLKGATE_NUMS; i++) { ddr_data.clk_ungt_save[i] = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(i)); mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i), ((~ungt_msk[i]) << 16) | 0xffff); } } static void clks_gating_resume(void) { int i; for (i = 0; i < CRU_CLKGATE_NUMS; i++) mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(i), ddr_data.clk_ungt_save[i] | 0xffff0000); } static inline void pm_pll_wait_lock(uint32_t pll_id) { uint32_t delay = PLL_LOCKED_TIMEOUT; while (delay > 0) { if (mmio_read_32(CRU_BASE + PLL_CONS(pll_id, 1)) & PLL_IS_LOCKED) break; delay--; } if (delay == 0) ERROR("lock-pll: %d\n", pll_id); } static inline void pll_pwr_dwn(uint32_t pll_id, uint32_t pd) { mmio_write_32(CRU_BASE + PLL_CONS(pll_id, 1), BITS_WITH_WMASK(1U, 1U, 15)); if (pd) mmio_write_32(CRU_BASE + PLL_CONS(pll_id, 1), BITS_WITH_WMASK(1, 1, 14)); else mmio_write_32(CRU_BASE + PLL_CONS(pll_id, 1), BITS_WITH_WMASK(0, 1, 14)); } static __sramfunc void dpll_suspend(void) { int i; /* slow mode */ mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(DPLL_ID)); /* save pll con */ for (i = 0; i < CRU_PLL_CON_NUMS; i++) sram_data.dpll_con_save[i] = mmio_read_32(CRU_BASE + PLL_CONS(DPLL_ID, i)); mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1), BITS_WITH_WMASK(1U, 1U, 15)); mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1), BITS_WITH_WMASK(1, 1, 14)); } static __sramfunc void dpll_resume(void) { uint32_t delay = PLL_LOCKED_TIMEOUT; mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1), BITS_WITH_WMASK(1U, 1U, 15)); mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1), BITS_WITH_WMASK(0, 1, 14)); mmio_write_32(CRU_BASE + PLL_CONS(DPLL_ID, 1), sram_data.dpll_con_save[1] | 0xc0000000); dsb(); while (delay > 0) { if (mmio_read_32(CRU_BASE + PLL_CONS(DPLL_ID, 1)) & PLL_IS_LOCKED) break; delay--; } if (delay == 0) while (1) ; mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_NORM_MODE(DPLL_ID)); } static inline void pll_suspend(uint32_t pll_id) { int i; /* slow mode */ mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_SLOW_MODE(pll_id)); /* save pll con */ for (i = 0; i < CRU_PLL_CON_NUMS; i++) ddr_data.cru_plls_con_save[pll_id][i] = mmio_read_32(CRU_BASE + PLL_CONS(pll_id, i)); /* powerdown pll */ pll_pwr_dwn(pll_id, pmu_pd_off); } static inline void pll_resume(uint32_t pll_id) { mmio_write_32(CRU_BASE + PLL_CONS(pll_id, 1), ddr_data.cru_plls_con_save[pll_id][1] | 0xc0000000); pm_pll_wait_lock(pll_id); if (PLL_IS_NORM_MODE(ddr_data.cru_mode_save, pll_id)) mmio_write_32(CRU_BASE + CRU_CRU_MODE, PLL_NORM_MODE(pll_id)); } static void pm_plls_suspend(void) { ddr_data.cru_mode_save = mmio_read_32(CRU_BASE + CRU_CRU_MODE); ddr_data.clk_sel0 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(0)); ddr_data.clk_sel1 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(1)); ddr_data.clk_sel18 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(18)); ddr_data.clk_sel20 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(20)); ddr_data.clk_sel24 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(24)); ddr_data.clk_sel38 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON(38)); pll_suspend(NPLL_ID); pll_suspend(CPLL_ID); pll_suspend(GPLL_ID); pll_suspend(APLL_ID); /* core */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(0), BITS_WITH_WMASK(0, 0x1f, 0)); /* pclk_dbg */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(1), BITS_WITH_WMASK(0, 0xf, 0)); /* crypto */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(20), BITS_WITH_WMASK(0, 0x1f, 0)); /* pwm0 */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(24), BITS_WITH_WMASK(0, 0x7f, 8)); /* uart2 from 24M */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(18), BITS_WITH_WMASK(2, 0x3, 8)); /* clk_rtc32k */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(38), BITS_WITH_WMASK(767, 0x3fff, 0) | BITS_WITH_WMASK(2U, 0x3u, 14)); } static void pm_plls_resume(void) { /* clk_rtc32k */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(38), ddr_data.clk_sel38 | BITS_WMSK(0x3fff, 0) | BITS_WMSK(0x3u, 14)); /* uart2 */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(18), ddr_data.clk_sel18 | BITS_WMSK(0x3, 8)); /* pwm0 */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(24), ddr_data.clk_sel24 | BITS_WMSK(0x7f, 8)); /* crypto */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(20), ddr_data.clk_sel20 | BITS_WMSK(0x1f, 0)); /* pclk_dbg */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(1), ddr_data.clk_sel1 | BITS_WMSK(0xf, 0)); /* core */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON(0), ddr_data.clk_sel0 | BITS_WMSK(0x1f, 0)); pll_pwr_dwn(APLL_ID, pmu_pd_on); pll_pwr_dwn(GPLL_ID, pmu_pd_on); pll_pwr_dwn(CPLL_ID, pmu_pd_on); pll_pwr_dwn(NPLL_ID, pmu_pd_on); pll_resume(APLL_ID); pll_resume(GPLL_ID); pll_resume(CPLL_ID); pll_resume(NPLL_ID); } #define ARCH_TIMER_TICKS_PER_US (SYS_COUNTER_FREQ_IN_TICKS / 1000000) static __sramfunc void sram_udelay(uint32_t us) { uint64_t pct_orig, pct_now; uint64_t to_wait = ARCH_TIMER_TICKS_PER_US * us; isb(); pct_orig = read_cntpct_el0(); do { isb(); pct_now = read_cntpct_el0(); } while ((pct_now - pct_orig) <= to_wait); } /* * For PMIC RK805, its sleep pin is connect with gpio2_d2 from rk3328. * If the PMIC is configed for responding the sleep pin * to get it into sleep mode, * once the pin is output high, it will get the pmic into sleep mode. */ __sramfunc void rk3328_pmic_suspend(void) { sram_data.pmic_sleep_save = mmio_read_32(GRF_BASE + PMIC_SLEEP_REG); sram_data.pmic_sleep_gpio_save[1] = mmio_read_32(GPIO2_BASE + 4); sram_data.pmic_sleep_gpio_save[0] = mmio_read_32(GPIO2_BASE); mmio_write_32(GRF_BASE + PMIC_SLEEP_REG, BITS_WITH_WMASK(0, 0x3, 4)); mmio_write_32(GPIO2_BASE + 4, sram_data.pmic_sleep_gpio_save[1] | BIT(26)); mmio_write_32(GPIO2_BASE, sram_data.pmic_sleep_gpio_save[0] | BIT(26)); } __sramfunc void rk3328_pmic_resume(void) { mmio_write_32(GPIO2_BASE, sram_data.pmic_sleep_gpio_save[0]); mmio_write_32(GPIO2_BASE + 4, sram_data.pmic_sleep_gpio_save[1]); mmio_write_32(GRF_BASE + PMIC_SLEEP_REG, sram_data.pmic_sleep_save | BITS_WMSK(0xffffu, 0)); /* Resuming volt need a lot of time */ sram_udelay(100); } static __sramfunc void ddr_suspend(void) { sram_data.pd_sr_idle_save = mmio_read_32(DDR_UPCTL_BASE + DDR_PCTL2_PWRCTL); sram_data.pd_sr_idle_save &= SELFREF_EN; mmio_clrbits_32(DDR_UPCTL_BASE + DDR_PCTL2_PWRCTL, SELFREF_EN); sram_data.ddr_grf_con0 = mmio_read_32(DDR_GRF_BASE + DDRGRF_SOC_CON(0)); mmio_write_32(DDR_GRF_BASE, BIT_WITH_WMSK(14) | WMSK_BIT(15)); /* * Override csysreq from ddrc and * send valid csysreq signal to PMU, * csysreq is controlled by ddrc only */ /* in self-refresh */ mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(0)); while ((mmio_read_32(DDR_GRF_BASE + DDRGRF_SOC_STATUS(1)) & (0x03 << 12)) != (0x02 << 12)) ; /* ddr retention */ mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(2)); /* ddr gating */ mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(0), BITS_WITH_WMASK(0x7, 0x7, 4)); mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(7), BITS_WITH_WMASK(1, 1, 4)); mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(18), BITS_WITH_WMASK(0x1ff, 0x1ff, 1)); mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(27), BITS_WITH_WMASK(0x3, 0x3, 0)); dpll_suspend(); } __sramfunc void dmc_restore(void) { dpll_resume(); /* ddr gating */ mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(0), BITS_WITH_WMASK(0, 0x7, 4)); mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(7), BITS_WITH_WMASK(0, 1, 4)); mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(18), BITS_WITH_WMASK(0, 0x1ff, 1)); mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(27), BITS_WITH_WMASK(0, 0x3, 0)); /* ddr de_retention */ mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(2)); /* exit self-refresh */ mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(0)); while ((mmio_read_32(DDR_GRF_BASE + DDRGRF_SOC_STATUS(1)) & (0x03 << 12)) != (0x00 << 12)) ; mmio_write_32(DDR_GRF_BASE, sram_data.ddr_grf_con0 | 0xc0000000); if (sram_data.pd_sr_idle_save) mmio_setbits_32(DDR_UPCTL_BASE + DDR_PCTL2_PWRCTL, SELFREF_EN); } static __sramfunc void sram_dbg_uart_suspend(void) { sram_data.uart2_ier = mmio_read_32(UART2_BASE + UART_IER); mmio_write_32(UART2_BASE + UART_IER, UART_INT_DISABLE); mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(16), 0x20002000); mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(2), 0x00040004); } __sramfunc void sram_dbg_uart_resume(void) { /* restore uart clk and reset fifo */ mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(16), 0x20000000); mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(2), 0x00040000); mmio_write_32(UART2_BASE + UART_FCR, UART_FIFO_RESET); mmio_write_32(UART2_BASE + UART_IER, sram_data.uart2_ier); } static __sramfunc void sram_soc_enter_lp(void) { uint32_t apm_value; apm_value = BIT(core_pm_en) | BIT(core_pm_dis_int) | BIT(core_pm_int_wakeup_en); mmio_write_32(PMU_BASE + PMU_CPUAPM_CON(PD_CPU0), apm_value); dsb(); isb(); err_loop: wfi(); /* *Soc will enter low power mode and *do not return to here. */ goto err_loop; } __sramfunc void sram_suspend(void) { /* disable mmu and icache */ disable_mmu_icache_el3(); tlbialle3(); dsbsy(); isb(); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1), ((uintptr_t)&pmu_cpuson_entrypoint >> CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK); /* ddr self-refresh and gating phy */ ddr_suspend(); rk3328_pmic_suspend(); sram_dbg_uart_suspend(); sram_soc_enter_lp(); } void __dead2 rockchip_soc_sys_pd_pwr_dn_wfi(void) { sram_suspend(); /* should never reach here */ psci_power_down_wfi(); } int rockchip_soc_sys_pwr_dm_suspend(void) { clks_gating_suspend(clk_ungt_msk); pm_plls_suspend(); return 0; } int rockchip_soc_sys_pwr_dm_resume(void) { pm_plls_resume(); clks_gating_resume(); plat_rockchip_gic_cpuif_enable(); return 0; } void rockchip_plat_mmu_el3(void) { /* TODO: support the el3 for rk3328 SoCs */ } void plat_rockchip_pmu_init(void) { uint32_t cpu; for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) cpuson_flags[cpu] = 0; cpu_warm_boot_addr = (uint64_t)platform_cpu_warmboot; /* the warm booting address of cpus */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1), (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK); nonboot_cpus_off(); INFO("%s: pd status 0x%x\n", __func__, mmio_read_32(PMU_BASE + PMU_PWRDN_ST)); } trusted-firmware-a-2.2/plat/rockchip/rk3328/drivers/pmu/pmu.h000066400000000000000000000054561355360272700240520ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PMU_H #define PMU_H #include struct rk3328_sleep_ddr_data { uint32_t pmu_debug_enable; uint32_t debug_iomux_save; uint32_t pmic_sleep_save; uint32_t pmu_wakeup_conf0; uint32_t pmu_pwrmd_com; uint32_t cru_mode_save; uint32_t clk_sel0, clk_sel1, clk_sel18, clk_sel20, clk_sel24, clk_sel38; uint32_t clk_ungt_save[CRU_CLKGATE_NUMS]; uint32_t cru_plls_con_save[MAX_PLL][CRU_PLL_CON_NUMS]; }; struct rk3328_sleep_sram_data { uint32_t pmic_sleep_save; uint32_t pmic_sleep_gpio_save[2]; uint32_t ddr_grf_con0; uint32_t dpll_con_save[CRU_PLL_CON_NUMS]; uint32_t pd_sr_idle_save; uint32_t uart2_ier; }; /***************************************************************************** * The ways of cores power domain contorlling *****************************************************************************/ enum cores_pm_ctr_mode { core_pwr_pd = 0, core_pwr_wfi = 1, core_pwr_wfi_int = 2 }; enum pmu_cores_pm_by_wfi { core_pm_en = 0, core_pm_int_wakeup_en, core_pm_dis_int, core_pm_sft_wakeup_en }; extern void *pmu_cpuson_entrypoint_start; extern void *pmu_cpuson_entrypoint_end; #define CORES_PM_DISABLE 0x0 /***************************************************************************** * pmu con,reg *****************************************************************************/ #define PMU_WAKEUP_CFG0 0x00 #define PMU_PWRDN_CON 0x0c #define PMU_PWRDN_ST 0x10 #define PMU_PWRMD_COM 0x18 #define PMU_SFT_CON 0x1c #define PMU_INT_CON 0x20 #define PMU_INT_ST 0x24 #define PMU_POWER_ST 0x44 #define PMU_CPUAPM_CON(n) (0x80 + (n) * 4) #define PMU_SYS_REG(n) (0xa0 + (n) * 4) #define CHECK_CPU_WFIE_BASE (GRF_BASE + GRF_CPU_STATUS(1)) enum pmu_core_pwrst_shift { clst_cpu_wfe = 0, clst_cpu_wfi = 4, }; #define clstl_cpu_wfe (clst_cpu_wfe) #define clstb_cpu_wfe (clst_cpu_wfe) enum pmu_pd_id { PD_CPU0 = 0, PD_CPU1, PD_CPU2, PD_CPU3, }; enum pmu_power_mode_common { pmu_mode_en = 0, sref_enter_en, global_int_disable_cfg, cpu0_pd_en, wait_wakeup_begin_cfg = 4, l2_flush_en, l2_idle_en, ddrio_ret_de_req, ddrio_ret_en = 8, }; enum pmu_sft_con { upctl_c_sysreq_cfg = 0, l2flushreq_req, ddr_io_ret_cfg, pmu_sft_ret_cfg, }; #define CKECK_WFE_MSK 0x1 #define CKECK_WFI_MSK 0x10 #define CKECK_WFEI_MSK 0x11 #define PD_CTR_LOOP 500 #define CHK_CPU_LOOP 500 #define MAX_WAIT_CONUT 1000 #define WAKEUP_INT_CLUSTER_EN 0x1 #define PMIC_SLEEP_REG 0x34 #define PLL_IS_NORM_MODE(mode, pll_id) \ ((mode & (PLL_NORM_MODE(pll_id)) & 0xffff) != 0) #define CTLR_ENABLE_G1_BIT BIT(1) #define UART_FIFO_EMPTY BIT(6) #define UART_IER 0x04 #define UART_FCR 0x08 #define UART_LSR 0x14 #define UART_INT_DISABLE 0x00 #define UART_FIFO_RESET 0x07 #endif /* PMU_H */ trusted-firmware-a-2.2/plat/rockchip/rk3328/drivers/soc/000077500000000000000000000000001355360272700230515ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3328/drivers/soc/soc.c000066400000000000000000000120661355360272700240060ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include /* Table of regions to map using the MMU. */ const mmap_region_t plat_rk_mmap[] = { MAP_REGION_FLAT(UART0_BASE, UART0_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(UART1_BASE, UART1_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(UART2_BASE, UART2_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(PMU_BASE, PMU_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(SGRF_BASE, SGRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(GPIO0_BASE, GPIO0_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(GPIO1_BASE, GPIO1_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(GPIO2_BASE, GPIO2_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(GPIO3_BASE, GPIO3_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(CRU_BASE, CRU_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(GRF_BASE, GRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(FIREWALL_DDR_BASE, FIREWALL_DDR_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(FIREWALL_CFG_BASE, FIREWALL_CFG_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(STIME_BASE, STIME_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(GIC400_BASE, GIC400_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(PMUSRAM_BASE, PMUSRAM_SIZE, MT_MEMORY | MT_RW | MT_SECURE), MAP_REGION_FLAT(SHARE_MEM_BASE, SHARE_MEM_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DDR_GRF_BASE, DDR_GRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DDR_UPCTL_BASE, DDR_UPCTL_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(PWM_BASE, PWM_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DDR_PARAM_BASE, DDR_PARAM_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(EFUSE8_BASE, EFUSE8_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(EFUSE32_BASE, EFUSE32_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DDR_PHY_BASE, DDR_PHY_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(SERVER_MSCH_BASE, SERVER_MSCH_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DDR_MONITOR_BASE, DDR_MONITOR_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(VOP_BASE, VOP_SIZE, MT_DEVICE | MT_RW | MT_SECURE), { 0 } }; /* The RockChip power domain tree descriptor */ const unsigned char rockchip_power_domain_tree_desc[] = { /* No of root nodes */ PLATFORM_SYSTEM_COUNT, /* No of children for the root node */ PLATFORM_CLUSTER_COUNT, /* No of children for the first cluster node */ PLATFORM_CLUSTER0_CORE_COUNT, }; void secure_timer_init(void) { mmio_write_32(STIMER_CHN_BASE(1) + TIMER_LOADE_COUNT0, 0xffffffff); mmio_write_32(STIMER_CHN_BASE(1) + TIMER_LOADE_COUNT1, 0xffffffff); /* auto reload & enable the timer */ mmio_write_32(STIMER_CHN_BASE(1) + TIMER_CONTROL_REG, TIMER_EN); } void sgrf_init(void) { uint32_t i, val; struct param_ddr_usage usg; /* general secure regions */ usg = ddr_region_usage_parse(DDR_PARAM_BASE, PLAT_MAX_DDR_CAPACITY_MB); for (i = 0; i < usg.s_nr; i++) { /* enable secure */ val = mmio_read_32(FIREWALL_DDR_BASE + FIREWALL_DDR_FW_DDR_CON_REG); val |= BIT(7 - i); mmio_write_32(FIREWALL_DDR_BASE + FIREWALL_DDR_FW_DDR_CON_REG, val); /* map top and base */ mmio_write_32(FIREWALL_DDR_BASE + FIREWALL_DDR_FW_DDR_RGN(7 - i), RG_MAP_SECURE(usg.s_top[i], usg.s_base[i])); } /* set ddr rgn0_top and rga0_top as 0 */ mmio_write_32(FIREWALL_DDR_BASE + FIREWALL_DDR_FW_DDR_RGN(0), 0x0); /* set all slave ip into no-secure, except stimer */ mmio_write_32(FIREWALL_CFG_BASE + FIREWALL_CFG_FW_SYS_CON(0), SGRF_SLV_S_ALL_NS); mmio_write_32(FIREWALL_CFG_BASE + FIREWALL_CFG_FW_SYS_CON(1), SGRF_SLV_S_ALL_NS); mmio_write_32(FIREWALL_CFG_BASE + FIREWALL_CFG_FW_SYS_CON(2), SGRF_SLV_S_ALL_NS | STIMER_S); mmio_write_32(FIREWALL_CFG_BASE + FIREWALL_CFG_FW_SYS_CON(3), SGRF_SLV_S_ALL_NS); /* set all master ip into no-secure */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(2), 0xf0000000); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(3), SGRF_MST_S_ALL_NS); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(4), SGRF_MST_S_ALL_NS); /* set DMAC into no-secure */ mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(3), DMA_IRQ_BOOT_NS); mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(4), DMA_PERI_CH_NS_15_0); mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(5), DMA_PERI_CH_NS_19_16); mmio_write_32(SGRF_BASE + SGRF_DMAC_CON(5), DMA_MANAGER_BOOT_NS); /* soft reset dma before use */ mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(3), DMA_SOFTRST_REQ); udelay(5); mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(3), DMA_SOFTRST_RLS); } void plat_rockchip_soc_init(void) { secure_timer_init(); sgrf_init(); NOTICE("BL31:Rockchip release version: v%d.%d\n", MAJOR_VERSION, MINOR_VERSION); } trusted-firmware-a-2.2/plat/rockchip/rk3328/drivers/soc/soc.h000066400000000000000000000071421355360272700240120ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SOC_H #define SOC_H /******************************* stimer ***************************************/ #define TIMER_LOADE_COUNT0 0x00 #define TIMER_LOADE_COUNT1 0x04 #define TIMER_CURRENT_VALUE0 0x08 #define TIMER_CURRENT_VALUE1 0x0C #define TIMER_CONTROL_REG 0x10 #define TIMER_INTSTATUS 0x18 #define TIMER_EN 0x1 extern const unsigned char rockchip_power_domain_tree_desc[]; /**************************** read/write **************************************/ #ifndef BITS_WMSK #define BITS_WMSK(msk, shift) ((msk) << (shift + REG_MSK_SHIFT)) #endif /**************************** cru *********************************************/ enum plls_id { APLL_ID = 0, DPLL_ID, CPLL_ID, GPLL_ID, REVERVE, NPLL_ID, MAX_PLL, }; #define CRU_CRU_MODE 0x0080 #define CRU_CRU_MISC 0x0084 #define CRU_GLB_SRST_FST 0x009c #define CRU_GLB_SRST_FST_VALUE 0xfdb9 #define PLL_CONS(id, i) (0x020 * (id) + ((i) * 4)) #define CRU_CLKSEL_CON(i) (0x100 + ((i) * 4)) #define CRU_CLKSEL_NUMS 53 #define CRU_CLKGATE_CON(i) (0x200 + ((i) * 4)) #define CRU_CLKGATE_NUMS 29 #define CRU_SOFTRSTS_CON(n) (0x300 + ((n) * 4)) #define CRU_SOFTRSTS_NUMS 12 #define CRU_PLL_CON_NUMS 5 /* PLLn_CON1 */ #define PLL_IS_LOCKED BIT(10) /* PLLn_CON0 */ #define PLL_BYPASS BITS_WITH_WMASK(1, 0x1, 15) #define PLL_NO_BYPASS BITS_WITH_WMASK(0, 0x1, 15) /* CRU_MODE */ #define PLL_SLOW_MODE(id) ((id) == NPLL_ID) ? \ BITS_WITH_WMASK(0, 0x1, 1) : \ BITS_WITH_WMASK(0, 0x1, ((id) * 4)) #define PLL_NORM_MODE(id) ((id) == NPLL_ID) ? \ BITS_WITH_WMASK(1, 0x1, 1) : \ BITS_WITH_WMASK(1, 0x1, ((id) * 4)) #define CRU_GATEID_CONS(ID) (0x200 + (ID / 16) * 4) #define CRU_CONS_GATEID(i) (16 * (i)) #define GATE_ID(reg, bit) ((reg * 16) + bit) #define PLL_LOCKED_TIMEOUT 600000U #define STIMER_CHN_BASE(n) (STIME_BASE + 0x20 * (n)) /************************** config regs ***************************************/ #define FIREWALL_CFG_FW_SYS_CON(n) (0x000 + (n) * 4) #define FIREWALL_DDR_FW_DDR_RGN(n) (0x000 + (n) * 4) #define FIREWALL_DDR_FW_DDR_MST(n) (0x020 + (n) * 4) #define FIREWALL_DDR_FW_DDR_CON_REG (0x040) #define GRF_SOC_CON(n) (0x400 + (n) * 4) #define GRF_SOC_STATUS(n) (0x480 + (n) * 4) #define GRF_CPU_STATUS(n) (0x520 + (n) * 4) #define GRF_OS_REG(n) (0x5c8 + (n) * 4) #define DDRGRF_SOC_CON(n) (0x000 + (n) * 4) #define DDRGRF_SOC_STATUS(n) (0x100 + (n) * 4) #define SGRF_SOC_CON(n) (0x000 + (n) * 4) #define SGRF_DMAC_CON(n) (0x100 + (n) * 4) #define SGRF_HDCP_KEY_CON(n) (0x280 + (n) * 4) #define DDR_PCTL2_PWRCTL 0x30 /************************** regs func *****************************************/ #define STIMER_S BIT(23) #define SGRF_SLV_S_ALL_NS 0x0 #define SGRF_MST_S_ALL_NS 0xffffffff #define DMA_IRQ_BOOT_NS 0xffffffff #define DMA_MANAGER_BOOT_NS 0x80008000 #define DMA_PERI_CH_NS_15_0 0xffffffff #define DMA_PERI_CH_NS_19_16 0x000f000f #define DMA_SOFTRST_REQ 0x01000100 #define DMA_SOFTRST_RLS 0x01000000 #define SELFREF_EN BIT(0) /************************** cpu ***********************************************/ #define CPU_BOOT_ADDR_WMASK 0xffff0000 #define CPU_BOOT_ADDR_ALIGN 16 /************************** ddr secure region *********************************/ #define PLAT_MAX_DDR_CAPACITY_MB 4096 #define RG_MAP_SECURE(top, base) ((((top) - 1) << 16) | (base)) /************************** gpio2_d2 ******************************************/ #define SWPORTA_DR 0x00 #define SWPORTA_DDR 0x04 #define GPIO2_D2 BIT(26) #define GPIO2_D2_GPIO_MODE 0x30 #define GRF_GPIO2D_IOMUX 0x34 #endif /* SOC_H */ trusted-firmware-a-2.2/plat/rockchip/rk3328/include/000077500000000000000000000000001355360272700222325ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3328/include/plat.ld.S000066400000000000000000000013611355360272700237150ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ROCKCHIP_PLAT_LD_S #define ROCKCHIP_PLAT_LD_S MEMORY { PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE } SECTIONS { . = PMUSRAM_BASE; /* * pmu_cpuson_entrypoint request address * align 64K when resume, so put it in the * start of pmusram */ .text_pmusram : { ASSERT(. == ALIGN(64 * 1024), ".pmusram.entry request 64K aligned."); *(.pmusram.entry) __bl31_pmusram_text_start = .; *(.pmusram.text) *(.pmusram.rodata) __bl31_pmusram_text_end = .; __bl31_pmusram_data_start = .; *(.pmusram.data) __bl31_pmusram_data_end = .; } >PMUSRAM } #endif /* ROCKCHIP_PLAT_LD_S */ trusted-firmware-a-2.2/plat/rockchip/rk3328/include/platform_def.h000066400000000000000000000076531355360272700250600ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include /******************************************************************************* * Platform binary types for linking ******************************************************************************/ #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 /******************************************************************************* * Generic platform constants ******************************************************************************/ /* Size of cacheable stacks */ #if defined(IMAGE_BL1) #define PLATFORM_STACK_SIZE 0x440 #elif defined(IMAGE_BL2) #define PLATFORM_STACK_SIZE 0x400 #elif defined(IMAGE_BL31) #define PLATFORM_STACK_SIZE 0x800 #elif defined(IMAGE_BL32) #define PLATFORM_STACK_SIZE 0x440 #endif #define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n" #define PLATFORM_MAX_AFFLVL MPIDR_AFFLVL2 #define PLATFORM_SYSTEM_COUNT 1 #define PLATFORM_CLUSTER_COUNT 1 #define PLATFORM_CLUSTER0_CORE_COUNT 4 #define PLATFORM_CLUSTER1_CORE_COUNT 0 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \ PLATFORM_CLUSTER0_CORE_COUNT) #define PLATFORM_NUM_AFFS (PLATFORM_SYSTEM_COUNT + \ PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2 #define PLAT_RK_CLST_TO_CPUID_SHIFT 6 /* * This macro defines the deepest retention state possible. A higher state * id will represent an invalid or a power down state. */ #define PLAT_MAX_RET_STATE U(1) /* * This macro defines the deepest power down states possible. Any state ID * higher than this is invalid. */ #define PLAT_MAX_OFF_STATE U(2) /******************************************************************************* * Platform memory map related constants ******************************************************************************/ /* TF text, ro, rw, Size: 512KB */ #define TZRAM_BASE (0x0) #define TZRAM_SIZE (0x80000) /******************************************************************************* * BL31 specific defines. ******************************************************************************/ /* * Put BL3-1 at the top of the Trusted RAM */ #define BL31_BASE (TZRAM_BASE + 0x40000) #define BL31_LIMIT (TZRAM_BASE + TZRAM_SIZE) /******************************************************************************* * Platform specific page table and MMU setup constants ******************************************************************************/ #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define MAX_XLAT_TABLES 9 #define MAX_MMAP_REGIONS 33 /******************************************************************************* * Declarations and constants to access the mailboxes safely. Each mailbox is * aligned on the biggest cache line size in the platform. This is known only * to the platform as it might have a combination of integrated and external * caches. Such alignment ensures that two maiboxes do not sit on the same cache * line at any cache level. They could belong to different cpus/clusters & * get written while being protected by different locks causing corruption of * a valid mailbox address. ******************************************************************************/ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) /* * Define GICD and GICC and GICR base */ #define PLAT_RK_GICD_BASE RK3328_GICD_BASE #define PLAT_RK_GICC_BASE RK3328_GICC_BASE #define PLAT_RK_UART_BASE UART2_BASE #define PLAT_RK_UART_CLOCK RK3328_UART_CLOCK #define PLAT_RK_UART_BAUDRATE RK3328_BAUDRATE #define PLAT_RK_PRIMARY_CPU 0x0 #define PSRAM_DO_DDR_RESUME 0 #define PSRAM_CHECK_WAKEUP_CPU 0 #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/rockchip/rk3328/platform.mk000066400000000000000000000041731355360272700227710ustar00rootroot00000000000000# # Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # RK_PLAT := plat/rockchip RK_PLAT_SOC := ${RK_PLAT}/${PLAT} RK_PLAT_COMMON := ${RK_PLAT}/common DISABLE_BIN_GENERATION := 1 PLAT_INCLUDES := -Idrivers/arm/gic/common/ \ -Idrivers/arm/gic/v2/ \ -I${RK_PLAT_COMMON}/ \ -I${RK_PLAT_COMMON}/include/ \ -I${RK_PLAT_COMMON}/aarch64/ \ -I${RK_PLAT_COMMON}/drivers/pmu/ \ -I${RK_PLAT_COMMON}/drivers/parameter/ \ -I${RK_PLAT_SOC}/ \ -I${RK_PLAT_SOC}/drivers/pmu/ \ -I${RK_PLAT_SOC}/drivers/soc/ \ -I${RK_PLAT_SOC}/include/ RK_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c \ ${RK_PLAT}/common/rockchip_gicv2.c PLAT_BL_COMMON_SOURCES := common/desc_image_load.c \ lib/bl_aux_params/bl_aux_params.c \ lib/xlat_tables/aarch64/xlat_tables.c \ lib/xlat_tables/xlat_tables_common.c \ plat/common/aarch64/crash_console_helpers.S \ plat/common/plat_psci_common.c BL31_SOURCES += ${RK_GIC_SOURCES} \ drivers/arm/cci/cci.c \ drivers/ti/uart/aarch64/16550_console.S \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ lib/cpus/aarch64/aem_generic.S \ lib/cpus/aarch64/cortex_a53.S \ ${RK_PLAT_COMMON}/drivers/parameter/ddr_parameter.c \ ${RK_PLAT_COMMON}/aarch64/plat_helpers.S \ ${RK_PLAT_COMMON}/params_setup.c \ ${RK_PLAT_COMMON}/bl31_plat_setup.c \ ${RK_PLAT_COMMON}/aarch64/pmu_sram_cpus_on.S \ ${RK_PLAT_COMMON}/plat_pm.c \ ${RK_PLAT_COMMON}/plat_topology.c \ ${RK_PLAT_COMMON}/aarch64/platform_common.c \ ${RK_PLAT_SOC}/drivers/pmu/pmu.c \ ${RK_PLAT_SOC}/drivers/soc/soc.c include lib/coreboot/coreboot.mk include lib/libfdt/libfdt.mk $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) $(eval $(call add_define,PLAT_SKIP_OPTEE_S_EL1_INT_REGISTER)) # Do not enable SVE ENABLE_SVE_FOR_NS := 0 WORKAROUND_CVE_2017_5715 := 0 trusted-firmware-a-2.2/plat/rockchip/rk3328/rk3328_def.h000066400000000000000000000100671355360272700225360ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RK3328_DEF_H #define RK3328_DEF_H #define MAJOR_VERSION (1) #define MINOR_VERSION (2) #define SIZE_K(n) ((n) * 1024) /* Special value used to verify platform parameters from BL2 to BL3-1 */ #define RK_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL #define UART0_BASE 0xff110000 #define UART0_SIZE SIZE_K(64) #define UART1_BASE 0xff120000 #define UART1_SIZE SIZE_K(64) #define UART2_BASE 0xff130000 #define UART2_SIZE SIZE_K(64) #define PMU_BASE 0xff140000 #define PMU_SIZE SIZE_K(64) #define SGRF_BASE 0xff0d0000 #define SGRF_SIZE SIZE_K(64) #define CRU_BASE 0xff440000 #define CRU_SIZE SIZE_K(64) #define GRF_BASE 0xff100000 #define GRF_SIZE SIZE_K(64) #define GPIO0_BASE 0xff210000 #define GPIO0_SIZE SIZE_K(32) #define GPIO1_BASE 0xff220000 #define GPIO1_SIZE SIZE_K(32) #define GPIO2_BASE 0xff230000 #define GPIO2_SIZE SIZE_K(64) #define GPIO3_BASE 0xff240000 #define GPIO3_SIZE SIZE_K(64) #define STIME_BASE 0xff1d0000 #define STIME_SIZE SIZE_K(64) #define INTMEM_BASE 0xff090000 #define INTMEM_SIZE SIZE_K(32) #define SRAM_LDS_BASE (INTMEM_BASE + SIZE_K(4)) #define SRAM_LDS_SIZE (INTMEM_SIZE - SIZE_K(4)) #define PMUSRAM_BASE INTMEM_BASE #define PMUSRAM_SIZE SIZE_K(4) #define PMUSRAM_RSIZE SIZE_K(4) #define VOP_BASE 0xff370000 #define VOP_SIZE SIZE_K(16) #define DDR_PHY_BASE 0xff400000 #define DDR_PHY_SIZE SIZE_K(4) #define SERVER_MSCH_BASE 0xff720000 #define SERVER_MSCH_SIZE SIZE_K(4) #define DDR_UPCTL_BASE 0xff780000 #define DDR_UPCTL_SIZE SIZE_K(12) #define DDR_MONITOR_BASE 0xff790000 #define DDR_MONITOR_SIZE SIZE_K(4) #define FIREWALL_DDR_BASE 0xff7c0000 #define FIREWALL_DDR_SIZE SIZE_K(64) #define FIREWALL_CFG_BASE 0xff7d0000 #define FIREWALL_CFG_SIZE SIZE_K(64) #define GIC400_BASE 0xff810000 #define GIC400_SIZE SIZE_K(64) #define DDR_GRF_BASE 0xff798000 #define DDR_GRF_SIZE SIZE_K(16) #define PWM_BASE 0xff1b0000 #define PWM_SIZE SIZE_K(64) #define DDR_PARAM_BASE 0x02000000 #define DDR_PARAM_SIZE SIZE_K(4) #define EFUSE8_BASE 0xff260000 #define EFUSE8_SIZE SIZE_K(4) #define EFUSE32_BASE 0xff0b0000 #define EFUSE32_SIZE SIZE_K(4) /************************************************************************** * UART related constants **************************************************************************/ #define RK3328_BAUDRATE 1500000 #define RK3328_UART_CLOCK 24000000 /****************************************************************************** * System counter frequency related constants ******************************************************************************/ #define SYS_COUNTER_FREQ_IN_TICKS 24000000U #define SYS_COUNTER_FREQ_IN_MHZ 24 /****************************************************************************** * GIC-400 & interrupt handling related constants ******************************************************************************/ /* Base rk_platform compatible GIC memory map */ #define RK3328_GICD_BASE (GIC400_BASE + 0x1000) #define RK3328_GICC_BASE (GIC400_BASE + 0x2000) #define RK3328_GICR_BASE 0 /* no GICR in GIC-400 */ /****************************************************************************** * sgi, ppi ******************************************************************************/ #define RK_IRQ_SEC_PHY_TIMER 29 #define RK_IRQ_SEC_SGI_0 8 #define RK_IRQ_SEC_SGI_1 9 #define RK_IRQ_SEC_SGI_2 10 #define RK_IRQ_SEC_SGI_3 11 #define RK_IRQ_SEC_SGI_4 12 #define RK_IRQ_SEC_SGI_5 13 #define RK_IRQ_SEC_SGI_6 14 #define RK_IRQ_SEC_SGI_7 15 /* * Define a list of Group 0 interrupts. */ #define PLAT_RK_GICV2_G0_IRQS \ INTR_PROP_DESC(RK_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, \ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(RK_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, \ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL) #define SHARE_MEM_BASE 0x100000/* [1MB, 1MB+60K]*/ #define SHARE_MEM_PAGE_NUM 15 #define SHARE_MEM_SIZE SIZE_K(SHARE_MEM_PAGE_NUM * 4) #endif /* RK3328_DEF_H */ trusted-firmware-a-2.2/plat/rockchip/rk3368/000077500000000000000000000000001355360272700206135ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3368/drivers/000077500000000000000000000000001355360272700222715ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3368/drivers/ddr/000077500000000000000000000000001355360272700230425ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3368/drivers/ddr/ddr_rk3368.c000066400000000000000000000356101355360272700250040ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include /* GRF_SOC_STATUS0 */ #define DPLL_LOCK (0x1 << 2) /* GRF_DDRC0_CON0 */ #define GRF_DDR_16BIT_EN (((0x1 << 3) << 16) | (0x1 << 3)) #define GRF_DDR_32BIT_EN (((0x1 << 3) << 16) | (0x0 << 3)) #define GRF_MOBILE_DDR_EN (((0x1 << 4) << 16) | (0x1 << 4)) #define GRF_MOBILE_DDR_DISB (((0x1 << 4) << 16) | (0x0 << 4)) #define GRF_DDR3_EN (((0x1 << 2) << 16) | (0x1 << 2)) #define GRF_LPDDR2_3_EN (((0x1 << 2) << 16) | (0x0 << 2)) /* PMUGRF_SOC_CON0 */ #define ddrphy_bufferen_io_en(n) ((0x1 << (9 + 16)) | (n << 9)) #define ddrphy_bufferen_core_en(n) ((0x1 << (8 + 16)) | (n << 8)) struct PCTRL_TIMING_TAG { uint32_t ddrfreq; uint32_t TOGCNT1U; uint32_t TINIT; uint32_t TRSTH; uint32_t TOGCNT100N; uint32_t TREFI; uint32_t TMRD; uint32_t TRFC; uint32_t TRP; uint32_t TRTW; uint32_t TAL; uint32_t TCL; uint32_t TCWL; uint32_t TRAS; uint32_t TRC; uint32_t TRCD; uint32_t TRRD; uint32_t TRTP; uint32_t TWR; uint32_t TWTR; uint32_t TEXSR; uint32_t TXP; uint32_t TXPDLL; uint32_t TZQCS; uint32_t TZQCSI; uint32_t TDQS; uint32_t TCKSRE; uint32_t TCKSRX; uint32_t TCKE; uint32_t TMOD; uint32_t TRSTL; uint32_t TZQCL; uint32_t TMRR; uint32_t TCKESR; uint32_t TDPD; uint32_t TREFI_MEM_DDR3; }; struct MSCH_SAVE_REG_TAG { uint32_t ddrconf; uint32_t ddrtiming; uint32_t ddrmode; uint32_t readlatency; uint32_t activate; uint32_t devtodev; }; /* ddr suspend need save reg */ struct PCTL_SAVE_REG_TAG { uint32_t SCFG; uint32_t CMDTSTATEN; uint32_t MCFG1; uint32_t MCFG; uint32_t PPCFG; struct PCTRL_TIMING_TAG pctl_timing; /* DFI Control Registers */ uint32_t DFITCTRLDELAY; uint32_t DFIODTCFG; uint32_t DFIODTCFG1; uint32_t DFIODTRANKMAP; /* DFI Write Data Registers */ uint32_t DFITPHYWRDATA; uint32_t DFITPHYWRLAT; uint32_t DFITPHYWRDATALAT; /* DFI Read Data Registers */ uint32_t DFITRDDATAEN; uint32_t DFITPHYRDLAT; /* DFI Update Registers */ uint32_t DFITPHYUPDTYPE0; uint32_t DFITPHYUPDTYPE1; uint32_t DFITPHYUPDTYPE2; uint32_t DFITPHYUPDTYPE3; uint32_t DFITCTRLUPDMIN; uint32_t DFITCTRLUPDMAX; uint32_t DFITCTRLUPDDLY; uint32_t DFIUPDCFG; uint32_t DFITREFMSKI; uint32_t DFITCTRLUPDI; /* DFI Status Registers */ uint32_t DFISTCFG0; uint32_t DFISTCFG1; uint32_t DFITDRAMCLKEN; uint32_t DFITDRAMCLKDIS; uint32_t DFISTCFG2; /* DFI Low Power Register */ uint32_t DFILPCFG0; }; struct DDRPHY_SAVE_REG_TAG { uint32_t PHY_REG0; uint32_t PHY_REG1; uint32_t PHY_REGB; uint32_t PHY_REGC; uint32_t PHY_REG11; uint32_t PHY_REG13; uint32_t PHY_REG14; uint32_t PHY_REG16; uint32_t PHY_REG20; uint32_t PHY_REG21; uint32_t PHY_REG26; uint32_t PHY_REG27; uint32_t PHY_REG28; uint32_t PHY_REG30; uint32_t PHY_REG31; uint32_t PHY_REG36; uint32_t PHY_REG37; uint32_t PHY_REG38; uint32_t PHY_REG40; uint32_t PHY_REG41; uint32_t PHY_REG46; uint32_t PHY_REG47; uint32_t PHY_REG48; uint32_t PHY_REG50; uint32_t PHY_REG51; uint32_t PHY_REG56; uint32_t PHY_REG57; uint32_t PHY_REG58; uint32_t PHY_REGDLL; uint32_t PHY_REGEC; uint32_t PHY_REGED; uint32_t PHY_REGEE; uint32_t PHY_REGEF; uint32_t PHY_REGFB; uint32_t PHY_REGFC; uint32_t PHY_REGFD; uint32_t PHY_REGFE; }; struct BACKUP_REG_TAG { uint32_t tag; uint32_t pctladdr; struct PCTL_SAVE_REG_TAG pctl; uint32_t phyaddr; struct DDRPHY_SAVE_REG_TAG phy; uint32_t nocaddr; struct MSCH_SAVE_REG_TAG noc; uint32_t pllselect; uint32_t phypllockaddr; uint32_t phyplllockmask; uint32_t phyplllockval; uint32_t pllpdstat; uint32_t dpllmodeaddr; uint32_t dpllslowmode; uint32_t dpllnormalmode; uint32_t dpllresetaddr; uint32_t dpllreset; uint32_t dplldereset; uint32_t dpllconaddr; uint32_t dpllcon[4]; uint32_t dplllockaddr; uint32_t dplllockmask; uint32_t dplllockval; uint32_t ddrpllsrcdivaddr; uint32_t ddrpllsrcdiv; uint32_t retendisaddr; uint32_t retendisval; uint32_t grfregaddr; uint32_t grfddrcreg; uint32_t crupctlphysoftrstaddr; uint32_t cruresetpctlphy; uint32_t cruderesetphy; uint32_t cruderesetpctlphy; uint32_t physoftrstaddr; uint32_t endtag; }; static uint32_t ddr_get_phy_pll_freq(void) { uint32_t ret = 0; uint32_t fb_div, pre_div; fb_div = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGEC); fb_div |= (mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGED) & 0x1) << 8; pre_div = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGEE) & 0xff; ret = 2 * 24 * fb_div / (4 * pre_div); return ret; } static void ddr_copy(uint32_t *pdest, uint32_t *psrc, uint32_t words) { uint32_t i; for (i = 0; i < words; i++) pdest[i] = psrc[i]; } static void ddr_get_dpll_cfg(uint32_t *p) { uint32_t nmhz, NO, NF, NR; nmhz = ddr_get_phy_pll_freq(); if (nmhz <= 150) NO = 6; else if (nmhz <= 250) NO = 4; else if (nmhz <= 500) NO = 2; else NO = 1; NR = 1; NF = 2 * nmhz * NR * NO / 24; p[0] = SET_NR(NR) | SET_NO(NO); p[1] = SET_NF(NF); p[2] = SET_NB(NF / 2); } void ddr_reg_save(uint32_t pllpdstat, uint64_t base_addr) { struct BACKUP_REG_TAG *p_ddr_reg = (struct BACKUP_REG_TAG *)base_addr; struct PCTL_SAVE_REG_TAG *pctl_tim = &p_ddr_reg->pctl; p_ddr_reg->tag = 0x56313031; p_ddr_reg->pctladdr = DDR_PCTL_BASE; p_ddr_reg->phyaddr = DDR_PHY_BASE; p_ddr_reg->nocaddr = SERVICE_BUS_BASE; /* PCTLR */ ddr_copy((uint32_t *)&pctl_tim->pctl_timing.TOGCNT1U, (uint32_t *)(DDR_PCTL_BASE + DDR_PCTL_TOGCNT1U), 35); pctl_tim->pctl_timing.TREFI |= DDR_UPD_REF_ENABLE; pctl_tim->SCFG = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_SCFG); pctl_tim->CMDTSTATEN = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_CMDTSTATEN); pctl_tim->MCFG1 = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_MCFG1); pctl_tim->MCFG = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_MCFG); pctl_tim->PPCFG = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_PPCFG); pctl_tim->pctl_timing.ddrfreq = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_TOGCNT1U * 2); pctl_tim->DFITCTRLDELAY = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITCTRLDELAY); pctl_tim->DFIODTCFG = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFIODTCFG); pctl_tim->DFIODTCFG1 = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFIODTCFG1); pctl_tim->DFIODTRANKMAP = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFIODTRANKMAP); pctl_tim->DFITPHYWRDATA = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITPHYWRDATA); pctl_tim->DFITPHYWRLAT = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITPHYWRLAT); pctl_tim->DFITPHYWRDATALAT = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITPHYWRDATALAT); pctl_tim->DFITRDDATAEN = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITRDDATAEN); pctl_tim->DFITPHYRDLAT = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITPHYRDLAT); pctl_tim->DFITPHYUPDTYPE0 = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITPHYUPDTYPE0); pctl_tim->DFITPHYUPDTYPE1 = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITPHYUPDTYPE1); pctl_tim->DFITPHYUPDTYPE2 = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITPHYUPDTYPE2); pctl_tim->DFITPHYUPDTYPE3 = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITPHYUPDTYPE3); pctl_tim->DFITCTRLUPDMIN = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITCTRLUPDMIN); pctl_tim->DFITCTRLUPDMAX = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITCTRLUPDMAX); pctl_tim->DFITCTRLUPDDLY = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITCTRLUPDDLY); pctl_tim->DFIUPDCFG = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFIUPDCFG); pctl_tim->DFITREFMSKI = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITREFMSKI); pctl_tim->DFITCTRLUPDI = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITCTRLUPDI); pctl_tim->DFISTCFG0 = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFISTCFG0); pctl_tim->DFISTCFG1 = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFISTCFG1); pctl_tim->DFITDRAMCLKEN = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITDRAMCLKEN); pctl_tim->DFITDRAMCLKDIS = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFITDRAMCLKDIS); pctl_tim->DFISTCFG2 = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFISTCFG2); pctl_tim->DFILPCFG0 = mmio_read_32(DDR_PCTL_BASE + DDR_PCTL_DFILPCFG0); /* PHY */ p_ddr_reg->phy.PHY_REG0 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG0); p_ddr_reg->phy.PHY_REG1 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG1); p_ddr_reg->phy.PHY_REGB = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGB); p_ddr_reg->phy.PHY_REGC = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGC); p_ddr_reg->phy.PHY_REG11 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG11); p_ddr_reg->phy.PHY_REG13 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG13); p_ddr_reg->phy.PHY_REG14 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG14); p_ddr_reg->phy.PHY_REG16 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG16); p_ddr_reg->phy.PHY_REG20 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG20); p_ddr_reg->phy.PHY_REG21 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG21); p_ddr_reg->phy.PHY_REG26 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG26); p_ddr_reg->phy.PHY_REG27 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG27); p_ddr_reg->phy.PHY_REG28 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG28); p_ddr_reg->phy.PHY_REG30 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG30); p_ddr_reg->phy.PHY_REG31 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG31); p_ddr_reg->phy.PHY_REG36 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG36); p_ddr_reg->phy.PHY_REG37 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG37); p_ddr_reg->phy.PHY_REG38 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG38); p_ddr_reg->phy.PHY_REG40 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG40); p_ddr_reg->phy.PHY_REG41 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG41); p_ddr_reg->phy.PHY_REG46 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG46); p_ddr_reg->phy.PHY_REG47 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG47); p_ddr_reg->phy.PHY_REG48 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG48); p_ddr_reg->phy.PHY_REG50 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG50); p_ddr_reg->phy.PHY_REG51 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG51); p_ddr_reg->phy.PHY_REG56 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG56); p_ddr_reg->phy.PHY_REG57 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG57); p_ddr_reg->phy.PHY_REG58 = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG58); p_ddr_reg->phy.PHY_REGDLL = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGDLL); p_ddr_reg->phy.PHY_REGEC = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGEC); p_ddr_reg->phy.PHY_REGED = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGED); p_ddr_reg->phy.PHY_REGEE = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGEE); p_ddr_reg->phy.PHY_REGEF = 0; if (mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG2) & 0x2) { p_ddr_reg->phy.PHY_REGFB = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG2C); p_ddr_reg->phy.PHY_REGFC = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG3C); p_ddr_reg->phy.PHY_REGFD = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG4C); p_ddr_reg->phy.PHY_REGFE = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REG5C); } else { p_ddr_reg->phy.PHY_REGFB = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGFB); p_ddr_reg->phy.PHY_REGFC = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGFC); p_ddr_reg->phy.PHY_REGFD = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGFD); p_ddr_reg->phy.PHY_REGFE = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGFE); } /* NOC */ p_ddr_reg->noc.ddrconf = mmio_read_32(SERVICE_BUS_BASE + MSCH_DDRCONF); p_ddr_reg->noc.ddrtiming = mmio_read_32(SERVICE_BUS_BASE + MSCH_DDRTIMING); p_ddr_reg->noc.ddrmode = mmio_read_32(SERVICE_BUS_BASE + MSCH_DDRMODE); p_ddr_reg->noc.readlatency = mmio_read_32(SERVICE_BUS_BASE + MSCH_READLATENCY); p_ddr_reg->noc.activate = mmio_read_32(SERVICE_BUS_BASE + MSCH_ACTIVATE); p_ddr_reg->noc.devtodev = mmio_read_32(SERVICE_BUS_BASE + MSCH_DEVTODEV); p_ddr_reg->pllselect = mmio_read_32(DDR_PHY_BASE + DDR_PHY_REGEE) * 0x1; p_ddr_reg->phypllockaddr = GRF_BASE + GRF_SOC_STATUS0; p_ddr_reg->phyplllockmask = GRF_DDRPHY_LOCK; p_ddr_reg->phyplllockval = 0; /* PLLPD */ p_ddr_reg->pllpdstat = pllpdstat; /* DPLL */ p_ddr_reg->dpllmodeaddr = CRU_BASE + PLL_CONS(DPLL_ID, 3); /* slow mode and power on */ p_ddr_reg->dpllslowmode = DPLL_WORK_SLOW_MODE | DPLL_POWER_DOWN; p_ddr_reg->dpllnormalmode = DPLL_WORK_NORMAL_MODE; p_ddr_reg->dpllresetaddr = CRU_BASE + PLL_CONS(DPLL_ID, 3); p_ddr_reg->dpllreset = DPLL_RESET_CONTROL_NORMAL; p_ddr_reg->dplldereset = DPLL_RESET_CONTROL_RESET; p_ddr_reg->dpllconaddr = CRU_BASE + PLL_CONS(DPLL_ID, 0); if (p_ddr_reg->pllselect == 0) { p_ddr_reg->dpllcon[0] = (mmio_read_32(CRU_BASE + PLL_CONS(DPLL_ID, 0)) & 0xffff) | (0xFFFFu << 16); p_ddr_reg->dpllcon[1] = (mmio_read_32(CRU_BASE + PLL_CONS(DPLL_ID, 1)) & 0xffff); p_ddr_reg->dpllcon[2] = (mmio_read_32(CRU_BASE + PLL_CONS(DPLL_ID, 2)) & 0xffff); p_ddr_reg->dpllcon[3] = (mmio_read_32(CRU_BASE + PLL_CONS(DPLL_ID, 3)) & 0xffff) | (0xFFFFu << 16); } else { ddr_get_dpll_cfg(&p_ddr_reg->dpllcon[0]); } p_ddr_reg->pllselect = 0; p_ddr_reg->dplllockaddr = CRU_BASE + PLL_CONS(DPLL_ID, 1); p_ddr_reg->dplllockmask = DPLL_STATUS_LOCK; p_ddr_reg->dplllockval = DPLL_STATUS_LOCK; /* SET_DDR_PLL_SRC */ p_ddr_reg->ddrpllsrcdivaddr = CRU_BASE + CRU_CLKSELS_CON(13); p_ddr_reg->ddrpllsrcdiv = (mmio_read_32(CRU_BASE + CRU_CLKSELS_CON(13)) & DDR_PLL_SRC_MASK) | (DDR_PLL_SRC_MASK << 16); p_ddr_reg->retendisaddr = PMU_BASE + PMU_PWRMD_COM; p_ddr_reg->retendisval = PD_PERI_PWRDN_ENABLE; p_ddr_reg->grfregaddr = GRF_BASE + GRF_DDRC0_CON0; p_ddr_reg->grfddrcreg = (mmio_read_32(GRF_BASE + GRF_DDRC0_CON0) & DDR_PLL_SRC_MASK) | (DDR_PLL_SRC_MASK << 16); /* pctl phy soft reset */ p_ddr_reg->crupctlphysoftrstaddr = CRU_BASE + CRU_SOFTRSTS_CON(10); p_ddr_reg->cruresetpctlphy = DDRCTRL0_PSRSTN_REQ(1) | DDRCTRL0_SRSTN_REQ(1) | DDRPHY0_PSRSTN_REQ(1) | DDRPHY0_SRSTN_REQ(1); p_ddr_reg->cruderesetphy = DDRCTRL0_PSRSTN_REQ(1) | DDRCTRL0_SRSTN_REQ(1) | DDRPHY0_PSRSTN_REQ(0) | DDRPHY0_SRSTN_REQ(0); p_ddr_reg->cruderesetpctlphy = DDRCTRL0_PSRSTN_REQ(0) | DDRCTRL0_SRSTN_REQ(0) | DDRPHY0_PSRSTN_REQ(0) | DDRPHY0_SRSTN_REQ(0); p_ddr_reg->physoftrstaddr = DDR_PHY_BASE + DDR_PHY_REG0; p_ddr_reg->endtag = 0xFFFFFFFF; } /* * "rk3368_ddr_reg_resume_V1.05.bin" is an executable bin which is generated * by ARM DS5 for resuming ddr controller. If the soc wakes up from system * suspend, ddr needs to be resumed and the resuming code needs to be run in * sram. But there is not a way to pointing the resuming code to the PMUSRAM * when linking .o files of bl31, so we use the * "rk3368_ddr_reg_resume_V1.05.bin" whose code is position-independent and * it can be loaded anywhere and run. */ static __aligned(4) unsigned int ddr_reg_resume[] = { #include "rk3368_ddr_reg_resume_V1.05.bin" }; uint32_t ddr_get_resume_code_size(void) { return sizeof(ddr_reg_resume); } uint32_t ddr_get_resume_data_size(void) { return sizeof(struct BACKUP_REG_TAG); } uint32_t *ddr_get_resume_code_base(void) { return (unsigned int *)ddr_reg_resume; } trusted-firmware-a-2.2/plat/rockchip/rk3368/drivers/ddr/ddr_rk3368.h000066400000000000000000000171031355360272700250060ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef DDR_RK3368_H #define DDR_RK3368_H #define DDR_PCTL_SCFG 0x0 #define DDR_PCTL_SCTL 0x4 #define DDR_PCTL_STAT 0x8 #define DDR_PCTL_INTRSTAT 0xc #define DDR_PCTL_MCMD 0x40 #define DDR_PCTL_POWCTL 0x44 #define DDR_PCTL_POWSTAT 0x48 #define DDR_PCTL_CMDTSTAT 0x4c #define DDR_PCTL_CMDTSTATEN 0x50 #define DDR_PCTL_MRRCFG0 0x60 #define DDR_PCTL_MRRSTAT0 0x64 #define DDR_PCTL_MRRSTAT1 0x68 #define DDR_PCTL_MCFG1 0x7c #define DDR_PCTL_MCFG 0x80 #define DDR_PCTL_PPCFG 0x84 #define DDR_PCTL_MSTAT 0x88 #define DDR_PCTL_LPDDR2ZQCFG 0x8c #define DDR_PCTL_DTUPDES 0x94 #define DDR_PCTL_DTUNA 0x98 #define DDR_PCTL_DTUNE 0x9c #define DDR_PCTL_DTUPRD0 0xa0 #define DDR_PCTL_DTUPRD1 0xa4 #define DDR_PCTL_DTUPRD2 0xa8 #define DDR_PCTL_DTUPRD3 0xac #define DDR_PCTL_DTUAWDT 0xb0 #define DDR_PCTL_TOGCNT1U 0xc0 #define DDR_PCTL_TINIT 0xc4 #define DDR_PCTL_TRSTH 0xc8 #define DDR_PCTL_TOGCNT100N 0xcc #define DDR_PCTL_TREFI 0xd0 #define DDR_PCTL_TMRD 0xd4 #define DDR_PCTL_TRFC 0xd8 #define DDR_PCTL_TRP 0xdc #define DDR_PCTL_TRTW 0xe0 #define DDR_PCTL_TAL 0xe4 #define DDR_PCTL_TCL 0xe8 #define DDR_PCTL_TCWL 0xec #define DDR_PCTL_TRAS 0xf0 #define DDR_PCTL_TRC 0xf4 #define DDR_PCTL_TRCD 0xf8 #define DDR_PCTL_TRRD 0xfc #define DDR_PCTL_TRTP 0x100 #define DDR_PCTL_TWR 0x104 #define DDR_PCTL_TWTR 0x108 #define DDR_PCTL_TEXSR 0x10c #define DDR_PCTL_TXP 0x110 #define DDR_PCTL_TXPDLL 0x114 #define DDR_PCTL_TZQCS 0x118 #define DDR_PCTL_TZQCSI 0x11c #define DDR_PCTL_TDQS 0x120 #define DDR_PCTL_TCKSRE 0x124 #define DDR_PCTL_TCKSRX 0x128 #define DDR_PCTL_TCKE 0x12c #define DDR_PCTL_TMOD 0x130 #define DDR_PCTL_TRSTL 0x134 #define DDR_PCTL_TZQCL 0x138 #define DDR_PCTL_TMRR 0x13c #define DDR_PCTL_TCKESR 0x140 #define DDR_PCTL_TDPD 0x144 #define DDR_PCTL_TREFI_MEM_DDR3 0x148 #define DDR_PCTL_ECCCFG 0x180 #define DDR_PCTL_ECCTST 0x184 #define DDR_PCTL_ECCCLR 0x188 #define DDR_PCTL_ECCLOG 0x18c #define DDR_PCTL_DTUWACTL 0x200 #define DDR_PCTL_DTURACTL 0x204 #define DDR_PCTL_DTUCFG 0x208 #define DDR_PCTL_DTUECTL 0x20c #define DDR_PCTL_DTUWD0 0x210 #define DDR_PCTL_DTUWD1 0x214 #define DDR_PCTL_DTUWD2 0x218 #define DDR_PCTL_DTUWD3 0x21c #define DDR_PCTL_DTUWDM 0x220 #define DDR_PCTL_DTURD0 0x224 #define DDR_PCTL_DTURD1 0x228 #define DDR_PCTL_DTURD2 0x22c #define DDR_PCTL_DTURD3 0x230 #define DDR_PCTL_DTULFSRWD 0x234 #define DDR_PCTL_DTULFSRRD 0x238 #define DDR_PCTL_DTUEAF 0x23c #define DDR_PCTL_DFITCTRLDELAY 0x240 #define DDR_PCTL_DFIODTCFG 0x244 #define DDR_PCTL_DFIODTCFG1 0x248 #define DDR_PCTL_DFIODTRANKMAP 0x24c #define DDR_PCTL_DFITPHYWRDATA 0x250 #define DDR_PCTL_DFITPHYWRLAT 0x254 #define DDR_PCTL_DFITPHYWRDATALAT 0x258 #define DDR_PCTL_DFITRDDATAEN 0x260 #define DDR_PCTL_DFITPHYRDLAT 0x264 #define DDR_PCTL_DFITPHYUPDTYPE0 0x270 #define DDR_PCTL_DFITPHYUPDTYPE1 0x274 #define DDR_PCTL_DFITPHYUPDTYPE2 0x278 #define DDR_PCTL_DFITPHYUPDTYPE3 0x27c #define DDR_PCTL_DFITCTRLUPDMIN 0x280 #define DDR_PCTL_DFITCTRLUPDMAX 0x284 #define DDR_PCTL_DFITCTRLUPDDLY 0x288 #define DDR_PCTL_DFIUPDCFG 0x290 #define DDR_PCTL_DFITREFMSKI 0x294 #define DDR_PCTL_DFITCTRLUPDI 0x298 #define DDR_PCTL_DFITRCFG0 0x2ac #define DDR_PCTL_DFITRSTAT0 0x2b0 #define DDR_PCTL_DFITRWRLVLEN 0x2b4 #define DDR_PCTL_DFITRRDLVLEN 0x2b8 #define DDR_PCTL_DFITRRDLVLGATEEN 0x2bc #define DDR_PCTL_DFISTSTAT0 0x2c0 #define DDR_PCTL_DFISTCFG0 0x2c4 #define DDR_PCTL_DFISTCFG1 0x2c8 #define DDR_PCTL_DFITDRAMCLKEN 0x2d0 #define DDR_PCTL_DFITDRAMCLKDIS 0x2d4 #define DDR_PCTL_DFISTCFG2 0x2d8 #define DDR_PCTL_DFISTPARCLR 0x2dc #define DDR_PCTL_DFISTPARLOG 0x2e0 #define DDR_PCTL_DFILPCFG0 0x2f0 #define DDR_PCTL_DFITRWRLVLRESP0 0x300 #define DDR_PCTL_DFITRWRLVLRESP1 0x304 #define DDR_PCTL_DFITRWRLVLRESP2 0x308 #define DDR_PCTL_DFITRRDLVLRESP0 0x30c #define DDR_PCTL_DFITRRDLVLRESP1 0x310 #define DDR_PCTL_DFITRRDLVLRESP2 0x314 #define DDR_PCTL_DFITRWRLVLDELAY0 0x318 #define DDR_PCTL_DFITRWRLVLDELAY1 0x31c #define DDR_PCTL_DFITRWRLVLDELAY2 0x320 #define DDR_PCTL_DFITRRDLVLDELAY0 0x324 #define DDR_PCTL_DFITRRDLVLDELAY1 0x328 #define DDR_PCTL_DFITRRDLVLDELAY2 0x32c #define DDR_PCTL_DFITRRDLVLGATEDELAY0 0x330 #define DDR_PCTL_DFITRRDLVLGATEDELAY1 0x334 #define DDR_PCTL_DFITRRDLVLGATEDELAY2 0x338 #define DDR_PCTL_DFITRCMD 0x33c #define DDR_PCTL_IPVR 0x3f8 #define DDR_PCTL_IPTR 0x3fc /* DDR PHY REG */ #define DDR_PHY_REG0 0x0 #define DDR_PHY_REG1 0x4 #define DDR_PHY_REG2 0x8 #define DDR_PHY_REG3 0xc #define DDR_PHY_REG4 0x10 #define DDR_PHY_REG5 0x14 #define DDR_PHY_REG6 0x18 #define DDR_PHY_REGB 0x2c #define DDR_PHY_REGC 0x30 #define DDR_PHY_REG11 0x44 #define DDR_PHY_REG12 0x48 #define DDR_PHY_REG13 0x4c #define DDR_PHY_REG14 0x50 #define DDR_PHY_REG16 0x58 #define DDR_PHY_REG20 0x80 #define DDR_PHY_REG21 0x84 #define DDR_PHY_REG26 0x98 #define DDR_PHY_REG27 0x9c #define DDR_PHY_REG28 0xa0 #define DDR_PHY_REG2C 0xb0 #define DDR_PHY_REG30 0xc0 #define DDR_PHY_REG31 0xc4 #define DDR_PHY_REG36 0xd8 #define DDR_PHY_REG37 0xdc #define DDR_PHY_REG38 0xe0 #define DDR_PHY_REG3C 0xf0 #define DDR_PHY_REG40 0x100 #define DDR_PHY_REG41 0x104 #define DDR_PHY_REG46 0x118 #define DDR_PHY_REG47 0x11c #define DDR_PHY_REG48 0x120 #define DDR_PHY_REG4C 0x130 #define DDR_PHY_REG50 0x140 #define DDR_PHY_REG51 0x144 #define DDR_PHY_REG56 0x158 #define DDR_PHY_REG57 0x15c #define DDR_PHY_REG58 0x160 #define DDR_PHY_REG5C 0x170 #define DDR_PHY_REGDLL 0x290 #define DDR_PHY_REGEC 0x3b0 #define DDR_PHY_REGED 0x3b4 #define DDR_PHY_REGEE 0x3b8 #define DDR_PHY_REGEF 0x3bc #define DDR_PHY_REGF0 0x3c0 #define DDR_PHY_REGF1 0x3c4 #define DDR_PHY_REGF2 0x3c8 #define DDR_PHY_REGFA 0x3e8 #define DDR_PHY_REGFB 0x3ec #define DDR_PHY_REGFC 0x3f0 #define DDR_PHY_REGFD 0x3f4 #define DDR_PHY_REGFE 0x3f8 #define DDR_PHY_REGFF 0x3fc /* MSCH REG define */ #define MSCH_COREID 0x0 #define MSCH_DDRCONF 0x8 #define MSCH_DDRTIMING 0xc #define MSCH_DDRMODE 0x10 #define MSCH_READLATENCY 0x14 #define MSCH_ACTIVATE 0x38 #define MSCH_DEVTODEV 0x3c #define SET_NR(n) ((0x3f << (8 + 16)) | ((n - 1) << 8)) #define SET_NO(n) ((0xf << (0 + 16)) | ((n - 1) << 0)) #define SET_NF(n) ((n - 1) & 0x1fff) #define SET_NB(n) ((n - 1) & 0xfff) #define PLLMODE(n) ((0x3 << (8 + 16)) | (n << 8)) /* GRF REG define */ #define GRF_SOC_STATUS0 0x480 #define GRF_DDRPHY_LOCK (0x1 << 15) #define GRF_DDRC0_CON0 0x600 /* CRU softreset ddr pctl, phy */ #define DDRMSCH0_SRSTN_REQ(n) (((0x1 << 10) << 16) | (n << 10)) #define DDRCTRL0_PSRSTN_REQ(n) (((0x1 << 3) << 16) | (n << 3)) #define DDRCTRL0_SRSTN_REQ(n) (((0x1 << 2) << 16) | (n << 2)) #define DDRPHY0_PSRSTN_REQ(n) (((0x1 << 1) << 16) | (n << 1)) #define DDRPHY0_SRSTN_REQ(n) (((0x1 << 0) << 16) | (n << 0)) /* CRU_DPLL_CON2 */ #define DPLL_STATUS_LOCK (1U << 31) /* CRU_DPLL_CON3 */ #define DPLL_POWER_DOWN ((0x1 << (1 + 16)) | (0 << 1)) #define DPLL_WORK_NORMAL_MODE ((0x3 << (8 + 16)) | (0 << 8)) #define DPLL_WORK_SLOW_MODE ((0x3 << (8 + 16)) | (1 << 8)) #define DPLL_RESET_CONTROL_NORMAL ((0x1 << (5 + 16)) | (0x0 << 5)) #define DPLL_RESET_CONTROL_RESET ((0x1 << (5 + 16)) | (0x1 << 5)) /* PMU_PWRDN_CON */ #define PD_PERI_PWRDN_ENABLE (1 << 13) #define DDR_PLL_SRC_MASK 0x13 /* DDR_PCTL_TREFI */ #define DDR_UPD_REF_ENABLE (0X1u << 31) uint32_t ddr_get_resume_code_size(void); uint32_t ddr_get_resume_data_size(void); uint32_t *ddr_get_resume_code_base(void); void ddr_reg_save(uint32_t pllpdstat, uint64_t base_addr); #endif /* DDR_RK3368_H */ trusted-firmware-a-2.2/plat/rockchip/rk3368/drivers/ddr/rk3368_ddr_reg_resume_V1.05.bin000066400000000000000000000135471355360272700303450ustar00rootroot00000000000000 0x14000088, 0xd10043ff, 0x5283ffe1, 0x52824902, 0x1b020400, 0x530d7c00, 0xb9000fe0, 0xb9400fe0, 0x340000a0, 0xb9400fe0, 0x51000401, 0xb9000fe1, 0x35ffffa0, 0x910043ff, 0xd65f03c0, 0x340000e2, 0xb9400023, 0xb9000003, 0x91001021, 0x91001000, 0x51000442, 0x35ffff62, 0xd65f03c0, 0xd10043ff, 0xb9400801, 0x12000821, 0xb9000fe1, 0xb9400fe1, 0x7100043f, 0x54000320, 0x52800021, 0x52800082, 0xb9400fe3, 0x34000143, 0x71000c7f, 0x54000100, 0x7100147f, 0x54000161, 0xb9000402, 0xb9400803, 0x12000863, 0x71000c7f, 0x54ffffa1, 0xb9000401, 0xb9400803, 0x12000863, 0x7100047f, 0x54ffffa1, 0xb9400803, 0x12000863, 0xb9000fe3, 0xb9400fe3, 0x7100047f, 0x54fffd61, 0x910043ff, 0xd65f03c0, 0xd10043ff, 0xb9400801, 0x12000821, 0xb9000fe1, 0xb9400fe1, 0x7100143f, 0x54000400, 0x52800021, 0x52800042, 0x52800063, 0xb9400fe4, 0x340000c4, 0x7100049f, 0x54000120, 0x71000c9f, 0x54000180, 0x14000010, 0xb9000401, 0xb9400804, 0x12000884, 0x7100049f, 0x54ffffa1, 0xb9000402, 0xb9400804, 0x12000884, 0x71000c9f, 0x54ffffa1, 0xb9000403, 0xb9400804, 0x12000884, 0x7100149f, 0x54ffffa1, 0xb9400804, 0x12000884, 0xb9000fe4, 0xb9400fe4, 0x7100149f, 0x54fffca1, 0x910043ff, 0xd65f03c0, 0xd10043ff, 0xb9400801, 0x12000821, 0xb9000fe1, 0xb9400fe1, 0x71000c3f, 0x54000400, 0x52800021, 0x52800042, 0x52800083, 0xb9400fe4, 0x34000164, 0x7100049f, 0x540001c0, 0x7100149f, 0x54000221, 0xb9000403, 0xb9400804, 0x12000884, 0x71000c9f, 0x54ffffa1, 0x1400000b, 0xb9000401, 0xb9400804, 0x12000884, 0x7100049f, 0x54ffffa1, 0xb9000402, 0xb9400804, 0x12000884, 0x71000c9f, 0x54ffffa1, 0xb9400804, 0x12000884, 0xb9000fe4, 0xb9400fe4, 0x71000c9f, 0x54fffca1, 0x910043ff, 0xd65f03c0, 0xd10103ff, 0xa9037bfd, 0x9100c3fd, 0xa9025ff6, 0xa90157f4, 0xf90007f3, 0xaa0003f3, 0xb9400674, 0xb9411276, 0xb941c660, 0xb941aa75, 0x7100041f, 0x54000261, 0xb9418e60, 0x321f0000, 0xb903b6c0, 0xb9418a60, 0xb903b2c0, 0xb9419260, 0xb903bac0, 0xb9418e60, 0x121e7800, 0xb903b6c0, 0xb941ca60, 0xb941ce61, 0xb941d262, 0xb9400003, 0xa030023, 0x6b22407f, 0x54ffffa0, 0x1400003b, 0xb941d660, 0x7100041f, 0x54000701, 0xb941da60, 0x3100041f, 0x54000080, 0xb941de61, 0x53007c00, 0xb9000001, 0xb941e660, 0x3100041f, 0x54000080, 0xb941ea61, 0x53007c00, 0xb9000001, 0xb941f260, 0x3100041f, 0x54000120, 0xaa1f03e1, 0x53007c00, 0x9107d262, 0xb8616843, 0xb8216803, 0x91001021, 0xf100203f, 0x54ffff81, 0x52800020, 0x97ffff3f, 0xb941e660, 0x3100041f, 0x54000080, 0xb941ee61, 0x53007c00, 0xb9000001, 0x52800020, 0x97ffff37, 0xb9420660, 0x3100041f, 0x54000100, 0xb9420a61, 0xb9420e62, 0x53007c00, 0xb9400003, 0xa030023, 0x6b22407f, 0x54ffffa1, 0xb9421260, 0x3100041f, 0x54000080, 0xb9421661, 0x53007c00, 0xb9000001, 0xb941da60, 0x3100041f, 0x54000080, 0xb941e261, 0x53007c00, 0xb9000001, 0xb9419660, 0xb903bec0, 0xb9422a60, 0x34000400, 0xb9422e61, 0x53007c17, 0xb90002e1, 0x52800140, 0x97ffff18, 0xb9423260, 0xb90002e0, 0x52800140, 0x97ffff14, 0xb9423660, 0xb90002e0, 0x52800140, 0x97ffff10, 0xb9423a60, 0x34000220, 0x53007c17, 0xb94002e0, 0x121c7400, 0xb90002e0, 0x52800020, 0x97ffff08, 0xb94002e0, 0x321e0000, 0xb90002e0, 0x528000a0, 0x97ffff03, 0xb94002e0, 0x321d0000, 0xb90002e0, 0x52800020, 0x97fffefe, 0xb9412a60, 0xb9004ec0, 0xb9412e60, 0xb90052c0, 0xb9413e60, 0xb9009ac0, 0xb9414260, 0xb9009ec0, 0xb9415260, 0xb900dac0, 0xb9415660, 0xb900dec0, 0xb9416660, 0xb9011ac0, 0xb9416a60, 0xb9011ec0, 0xb9417a60, 0xb9015ac0, 0xb9417e60, 0xb9015ec0, 0xb9418660, 0xb90292c0, 0xb9414660, 0xb900a2c0, 0xb9415a60, 0xb900e2c0, 0xb9416e60, 0xb90122c0, 0xb9418260, 0xb90162c0, 0xb9411660, 0xb90002c0, 0xb9411a60, 0xb90006c0, 0xb9411e60, 0xb9002ec0, 0xb9412260, 0xb90032c0, 0xb9412660, 0xb90046c0, 0xb9413260, 0xb9005ac0, 0xb9413660, 0xb90082c0, 0xb9413a60, 0xb90086c0, 0xb9414a60, 0xb900c2c0, 0xb9414e60, 0xb900c6c0, 0xb9415e60, 0xb90102c0, 0xb9416260, 0xb90106c0, 0xb9417260, 0xb90142c0, 0xb9417660, 0xb90146c0, 0x52800040, 0xb9000ac0, 0xb9411261, 0xb9419a60, 0xb900b020, 0xb9419a60, 0xb900b420, 0xb9419e60, 0xb900f020, 0xb9419e60, 0xb900f420, 0xb941a260, 0xb9013020, 0xb941a260, 0xb9013420, 0xb941a660, 0xb9017020, 0xb941a662, 0xaa1f03e0, 0xb9017422, 0x91008261, 0xb8606822, 0x8b000283, 0xb900c062, 0x91001000, 0xf102301f, 0x54ffff61, 0xb9400a60, 0xb9000280, 0xb9400e60, 0xb9005280, 0xb9401260, 0xb9007e80, 0xb9401660, 0xb9008280, 0xb9401a60, 0xb9008680, 0xb940ae60, 0xb9024280, 0xb940b260, 0xb9024680, 0xb940b660, 0xb9024a80, 0xb940ba60, 0xb9024e80, 0xb940be60, 0xb9025280, 0xb940c260, 0xb9025680, 0xb940c660, 0xb9025a80, 0xb940ca60, 0xb9026280, 0xb940ce60, 0xb9026680, 0xb940d260, 0xb9027280, 0xb940d660, 0xb9027680, 0xb940da60, 0xb9027a80, 0xb940de60, 0xb9027e80, 0xb940e260, 0xb9028280, 0xb940e660, 0xb9028680, 0xb940ea60, 0xb9028a80, 0xb940ee60, 0xb9029280, 0xb940f260, 0xb9029680, 0xb940f660, 0xb9029a80, 0xb940fa60, 0xb902c680, 0xb940fe60, 0xb902ca80, 0xb9410260, 0xb902d280, 0xb9410660, 0xb902d680, 0xb9410a60, 0xb902da80, 0xb9410e60, 0xb902f280, 0xb9422260, 0x3100041f, 0x540000c0, 0xb9422661, 0x53007c00, 0xb9000001, 0x52800020, 0x97fffe65, 0x52800020, 0xb9004680, 0xb9404a80, 0x3607ffe0, 0xb941ae60, 0xb9000aa0, 0xb941b260, 0xb9000ea0, 0xb941b660, 0xb90012a0, 0xb941ba60, 0xb90016a0, 0xb941be60, 0xb9003aa0, 0xb941c260, 0xb9003ea0, 0xb9422260, 0x3100041f, 0x54000080, 0x53007c00, 0x320083e1, 0xb9000001, 0xaa1403e0, 0x97fffe84, 0xb9421a60, 0x3100041f, 0x54000100, 0x53007c00, 0xb9421e61, 0xb9400002, 0x2a010041, 0xb9000001, 0x52800020, 0x97fffe43, 0xaa1403e0, 0x97fffea0, 0xb9422260, 0x3100041f, 0x54000080, 0x53007c00, 0x52a00021, 0xb9000001, 0xf94007f3, 0xa94157f4, 0xa9425ff6, 0xa9437bfd, 0x910103ff, 0xd65f03c0, trusted-firmware-a-2.2/plat/rockchip/rk3368/drivers/pmu/000077500000000000000000000000001355360272700230725ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3368/drivers/pmu/plat_pmu_macros.S000066400000000000000000000005261355360272700264060ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .macro func_rockchip_clst_warmboot /* Nothing to do for rk3368 */ .endm .macro rockchip_clst_warmboot_data /* Nothing to do for rk3368 */ .endm trusted-firmware-a-2.2/plat/rockchip/rk3368/drivers/pmu/pmu.c000066400000000000000000000222131355360272700240370ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include DEFINE_BAKERY_LOCK(rockchip_pd_lock); static uint32_t cpu_warm_boot_addr; void rk3368_flash_l2_b(void) { uint32_t wait_cnt = 0; regs_updata_bit_set(PMU_BASE + PMU_SFT_CON, pmu_sft_l2flsh_clst_b); dsb(); while (!(mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST) & BIT(clst_b_l2_flsh_done))) { wait_cnt++; if (!(wait_cnt % MAX_WAIT_CONUT)) WARN("%s:reg %x,wait\n", __func__, mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST)); } regs_updata_bit_clr(PMU_BASE + PMU_SFT_CON, pmu_sft_l2flsh_clst_b); } static inline int rk3368_pmu_bus_idle(uint32_t req, uint32_t idle) { uint32_t mask = BIT(req); uint32_t idle_mask = 0; uint32_t idle_target = 0; uint32_t val; uint32_t wait_cnt = 0; switch (req) { case bus_ide_req_clst_l: idle_mask = BIT(pmu_idle_ack_cluster_l); idle_target = (idle << pmu_idle_ack_cluster_l); break; case bus_ide_req_clst_b: idle_mask = BIT(pmu_idle_ack_cluster_b); idle_target = (idle << pmu_idle_ack_cluster_b); break; case bus_ide_req_cxcs: idle_mask = BIT(pmu_idle_ack_cxcs); idle_target = ((!idle) << pmu_idle_ack_cxcs); break; case bus_ide_req_cci400: idle_mask = BIT(pmu_idle_ack_cci400); idle_target = ((!idle) << pmu_idle_ack_cci400); break; case bus_ide_req_gpu: idle_mask = BIT(pmu_idle_ack_gpu) | BIT(pmu_idle_gpu); idle_target = (idle << pmu_idle_ack_gpu) | (idle << pmu_idle_gpu); break; case bus_ide_req_core: idle_mask = BIT(pmu_idle_ack_core) | BIT(pmu_idle_core); idle_target = (idle << pmu_idle_ack_core) | (idle << pmu_idle_core); break; case bus_ide_req_bus: idle_mask = BIT(pmu_idle_ack_bus) | BIT(pmu_idle_bus); idle_target = (idle << pmu_idle_ack_bus) | (idle << pmu_idle_bus); break; case bus_ide_req_dma: idle_mask = BIT(pmu_idle_ack_dma) | BIT(pmu_idle_dma); idle_target = (idle << pmu_idle_ack_dma) | (idle << pmu_idle_dma); break; case bus_ide_req_peri: idle_mask = BIT(pmu_idle_ack_peri) | BIT(pmu_idle_peri); idle_target = (idle << pmu_idle_ack_peri) | (idle << pmu_idle_peri); break; case bus_ide_req_video: idle_mask = BIT(pmu_idle_ack_video) | BIT(pmu_idle_video); idle_target = (idle << pmu_idle_ack_video) | (idle << pmu_idle_video); break; case bus_ide_req_vio: idle_mask = BIT(pmu_idle_ack_vio) | BIT(pmu_idle_vio); idle_target = (pmu_idle_ack_vio) | (idle << pmu_idle_vio); break; case bus_ide_req_alive: idle_mask = BIT(pmu_idle_ack_alive) | BIT(pmu_idle_alive); idle_target = (idle << pmu_idle_ack_alive) | (idle << pmu_idle_alive); break; case bus_ide_req_pmu: idle_mask = BIT(pmu_idle_ack_pmu) | BIT(pmu_idle_pmu); idle_target = (idle << pmu_idle_ack_pmu) | (idle << pmu_idle_pmu); break; case bus_ide_req_msch: idle_mask = BIT(pmu_idle_ack_msch) | BIT(pmu_idle_msch); idle_target = (idle << pmu_idle_ack_msch) | (idle << pmu_idle_msch); break; case bus_ide_req_cci: idle_mask = BIT(pmu_idle_ack_cci) | BIT(pmu_idle_cci); idle_target = (idle << pmu_idle_ack_cci) | (idle << pmu_idle_cci); break; default: ERROR("%s: Unsupported the idle request\n", __func__); break; } val = mmio_read_32(PMU_BASE + PMU_BUS_IDE_REQ); if (idle) val |= mask; else val &= ~mask; mmio_write_32(PMU_BASE + PMU_BUS_IDE_REQ, val); while ((mmio_read_32(PMU_BASE + PMU_BUS_IDE_ST) & idle_mask) != idle_target) { wait_cnt++; if (!(wait_cnt % MAX_WAIT_CONUT)) WARN("%s:st=%x(%x)\n", __func__, mmio_read_32(PMU_BASE + PMU_BUS_IDE_ST), idle_mask); } return 0; } void pmu_scu_b_pwrup(void) { regs_updata_bit_clr(PMU_BASE + PMU_SFT_CON, pmu_sft_acinactm_clst_b); rk3368_pmu_bus_idle(bus_ide_req_clst_b, 0); } static void pmu_scu_b_pwrdn(void) { uint32_t wait_cnt = 0; if ((mmio_read_32(PMU_BASE + PMU_PWRDN_ST) & PM_PWRDM_CPUSB_MSK) != PM_PWRDM_CPUSB_MSK) { ERROR("%s: not all cpus is off\n", __func__); return; } rk3368_flash_l2_b(); regs_updata_bit_set(PMU_BASE + PMU_SFT_CON, pmu_sft_acinactm_clst_b); while (!(mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST) & BIT(clst_b_l2_wfi))) { wait_cnt++; if (!(wait_cnt % MAX_WAIT_CONUT)) ERROR("%s:wait cluster-b l2(%x)\n", __func__, mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST)); } rk3368_pmu_bus_idle(bus_ide_req_clst_b, 1); } static void pmu_sleep_mode_config(void) { uint32_t pwrmd_core, pwrmd_com; pwrmd_core = BIT(pmu_mdcr_cpu0_pd) | BIT(pmu_mdcr_scu_l_pd) | BIT(pmu_mdcr_l2_flush) | BIT(pmu_mdcr_l2_idle) | BIT(pmu_mdcr_clr_clst_l) | BIT(pmu_mdcr_clr_core) | BIT(pmu_mdcr_clr_cci) | BIT(pmu_mdcr_core_pd); pwrmd_com = BIT(pmu_mode_en) | BIT(pmu_mode_sref_enter) | BIT(pmu_mode_pwr_off); regs_updata_bit_set(PMU_BASE + PMU_WKUP_CFG2, pmu_cluster_l_wkup_en); regs_updata_bit_set(PMU_BASE + PMU_WKUP_CFG2, pmu_cluster_b_wkup_en); regs_updata_bit_clr(PMU_BASE + PMU_WKUP_CFG2, pmu_gpio_wkup_en); mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT, CYCL_24M_CNT_MS(2)); mmio_write_32(PMU_BASE + PMU_PLLRST_CNT, CYCL_24M_CNT_US(100)); mmio_write_32(PMU_BASE + PMU_STABLE_CNT, CYCL_24M_CNT_MS(2)); mmio_write_32(PMU_BASE + PMU_PWRMD_CORE, pwrmd_core); mmio_write_32(PMU_BASE + PMU_PWRMD_COM, pwrmd_com); dsb(); } static void pmu_set_sleep_mode(void) { pmu_sleep_mode_config(); soc_sleep_config(); regs_updata_bit_set(PMU_BASE + PMU_PWRMD_CORE, pmu_mdcr_global_int_dis); regs_updata_bit_set(PMU_BASE + PMU_SFT_CON, pmu_sft_glbl_int_dis_b); pmu_scu_b_pwrdn(); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1), ((uintptr_t)&pmu_cpuson_entrypoint >> CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(2), ((uintptr_t)&pmu_cpuson_entrypoint >> CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK); } static int cpus_id_power_domain(uint32_t cluster, uint32_t cpu, uint32_t pd_state, uint32_t wfie_msk) { uint32_t pd; uint64_t mpidr; if (cluster) pd = PD_CPUB0 + cpu; else pd = PD_CPUL0 + cpu; if (pmu_power_domain_st(pd) == pd_state) return 0; if (pd_state == pmu_pd_off) { mpidr = (cluster << MPIDR_AFF1_SHIFT) | cpu; if (check_cpu_wfie(mpidr, wfie_msk)) return -EINVAL; } return pmu_power_domain_ctr(pd, pd_state); } static void nonboot_cpus_off(void) { uint32_t boot_cpu, boot_cluster, cpu; boot_cpu = MPIDR_AFFLVL0_VAL(read_mpidr_el1()); boot_cluster = MPIDR_AFFLVL1_VAL(read_mpidr_el1()); /* turn off noboot cpus */ for (cpu = 0; cpu < PLATFORM_CLUSTER0_CORE_COUNT; cpu++) { if (!boot_cluster && (cpu == boot_cpu)) continue; cpus_id_power_domain(0, cpu, pmu_pd_off, CKECK_WFEI_MSK); } for (cpu = 0; cpu < PLATFORM_CLUSTER1_CORE_COUNT; cpu++) { if (boot_cluster && (cpu == boot_cpu)) continue; cpus_id_power_domain(1, cpu, pmu_pd_off, CKECK_WFEI_MSK); } } void sram_save(void) { /* TODO: support the sdram save for rk3368 SoCs*/ } void sram_restore(void) { /* TODO: support the sdram restore for rk3368 SoCs */ } int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint) { uint32_t cpu, cluster; uint32_t cpuon_id; cpu = MPIDR_AFFLVL0_VAL(mpidr); cluster = MPIDR_AFFLVL1_VAL(mpidr); /* Make sure the cpu is off,Before power up the cpu! */ cpus_id_power_domain(cluster, cpu, pmu_pd_off, CKECK_WFEI_MSK); cpuon_id = (cluster * PLATFORM_CLUSTER0_CORE_COUNT) + cpu; assert(cpuon_id < PLATFORM_CORE_COUNT); assert(cpuson_flags[cpuon_id] == 0); cpuson_flags[cpuon_id] = PMU_CPU_HOTPLUG; cpuson_entry_point[cpuon_id] = entrypoint; /* Switch boot addr to pmusram */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1 + cluster), (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK); dsb(); cpus_id_power_domain(cluster, cpu, pmu_pd_on, CKECK_WFEI_MSK); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1 + cluster), (COLD_BOOT_BASE >> CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK); return 0; } int rockchip_soc_cores_pwr_dm_on_finish(void) { return 0; } int rockchip_soc_sys_pwr_dm_resume(void) { mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1), (COLD_BOOT_BASE >> CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(2), (COLD_BOOT_BASE >> CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK); pm_plls_resume(); pmu_scu_b_pwrup(); return 0; } int rockchip_soc_sys_pwr_dm_suspend(void) { nonboot_cpus_off(); pmu_set_sleep_mode(); return 0; } void rockchip_plat_mmu_el3(void) { /* TODO: support the el3 for rk3368 SoCs */ } void plat_rockchip_pmu_init(void) { uint32_t cpu; /* register requires 32bits mode, switch it to 32 bits */ cpu_warm_boot_addr = (uint64_t)platform_cpu_warmboot; for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) cpuson_flags[cpu] = 0; nonboot_cpus_off(); INFO("%s(%d): pd status %x\n", __func__, __LINE__, mmio_read_32(PMU_BASE + PMU_PWRDN_ST)); } trusted-firmware-a-2.2/plat/rockchip/rk3368/drivers/pmu/pmu.h000066400000000000000000000076431355360272700240560ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PMU_H #define PMU_H /* Allocate sp reginon in pmusram */ #define PSRAM_SP_SIZE 0x80 #define PSRAM_SP_BOTTOM (PSRAM_SP_TOP - PSRAM_SP_SIZE) /***************************************************************************** * pmu con,reg *****************************************************************************/ #define PMU_WKUP_CFG0 0x0 #define PMU_WKUP_CFG1 0x4 #define PMU_WKUP_CFG2 0x8 #define PMU_TIMEOUT_CNT 0x7c #define PMU_PWRDN_CON 0xc #define PMU_PWRDN_ST 0x10 #define PMU_CORE_PWR_ST 0x38 #define PMU_PWRMD_CORE 0x14 #define PMU_PWRMD_COM 0x18 #define PMU_SFT_CON 0x1c #define PMU_BUS_IDE_REQ 0x3c #define PMU_BUS_IDE_ST 0x40 #define PMU_OSC_CNT 0x48 #define PMU_PLLLOCK_CNT 0x4c #define PMU_PLLRST_CNT 0x50 #define PMU_STABLE_CNT 0x54 #define PMU_DDRIO_PWR_CNT 0x58 #define PMU_WKUPRST_CNT 0x5c enum pmu_powermode_core { pmu_mdcr_global_int_dis = 0, pmu_mdcr_core_src_gt, pmu_mdcr_clr_cci, pmu_mdcr_cpu0_pd, pmu_mdcr_clr_clst_l = 4, pmu_mdcr_clr_core, pmu_mdcr_scu_l_pd, pmu_mdcr_core_pd, pmu_mdcr_l2_idle = 8, pmu_mdcr_l2_flush }; /* * the shift of bits for cores status */ enum pmu_core_pwrst_shift { clstl_cpu_wfe = 2, clstl_cpu_wfi = 6, clstb_cpu_wfe = 12, clstb_cpu_wfi = 16 }; enum pmu_pdid { PD_CPUL0 = 0, PD_CPUL1, PD_CPUL2, PD_CPUL3, PD_SCUL, PD_CPUB0 = 5, PD_CPUB1, PD_CPUB2, PD_CPUB3, PD_SCUB = 9, PD_PERI = 13, PD_VIDEO, PD_VIO, PD_GPU0, PD_GPU1, PD_END }; enum pmu_bus_ide { bus_ide_req_clst_l = 0, bus_ide_req_clst_b, bus_ide_req_gpu, bus_ide_req_core, bus_ide_req_bus = 4, bus_ide_req_dma, bus_ide_req_peri, bus_ide_req_video, bus_ide_req_vio = 8, bus_ide_req_res0, bus_ide_req_cxcs, bus_ide_req_alive, bus_ide_req_pmu = 12, bus_ide_req_msch, bus_ide_req_cci, bus_ide_req_cci400 = 15, bus_ide_req_end }; enum pmu_powermode_common { pmu_mode_en = 0, pmu_mode_res0, pmu_mode_bus_pd, pmu_mode_wkup_rst, pmu_mode_pll_pd = 4, pmu_mode_pwr_off, pmu_mode_pmu_use_if, pmu_mode_pmu_alive_use_if, pmu_mode_osc_dis = 8, pmu_mode_input_clamp, pmu_mode_sref_enter, pmu_mode_ddrc_gt, pmu_mode_ddrio_ret = 12, pmu_mode_ddrio_ret_deq, pmu_mode_clr_pmu, pmu_mode_clr_alive, pmu_mode_clr_bus = 16, pmu_mode_clr_dma, pmu_mode_clr_msch, pmu_mode_clr_peri, pmu_mode_clr_video = 20, pmu_mode_clr_vio, pmu_mode_clr_gpu, pmu_mode_clr_mcu, pmu_mode_clr_cxcs = 24, pmu_mode_clr_cci400, pmu_mode_res1, pmu_mode_res2, pmu_mode_res3 = 28, pmu_mode_mclst }; enum pmu_core_power_st { clst_l_cpu_wfe = 2, clst_l_cpu_wfi = 6, clst_b_l2_flsh_done = 10, clst_b_l2_wfi = 11, clst_b_cpu_wfe = 12, clst_b_cpu_wfi = 16, mcu_sleeping = 20, }; enum pmu_sft_con { pmu_sft_acinactm_clst_b = 5, pmu_sft_l2flsh_clst_b, pmu_sft_glbl_int_dis_b = 9, pmu_sft_ddrio_ret_cfg = 11, }; enum pmu_wkup_cfg2 { pmu_cluster_l_wkup_en = 0, pmu_cluster_b_wkup_en, pmu_gpio_wkup_en, pmu_sdio_wkup_en, pmu_sdmmc_wkup_en, pmu_sim_wkup_en, pmu_timer_wkup_en, pmu_usbdev_wkup_en, pmu_sft_wkup_en, pmu_wdt_mcu_wkup_en, pmu_timeout_wkup_en, }; enum pmu_bus_idle_st { pmu_idle_ack_cluster_l = 0, pmu_idle_ack_cluster_b, pmu_idle_ack_gpu, pmu_idle_ack_core, pmu_idle_ack_bus, pmu_idle_ack_dma, pmu_idle_ack_peri, pmu_idle_ack_video, pmu_idle_ack_vio, pmu_idle_ack_cci = 10, pmu_idle_ack_msch, pmu_idle_ack_alive, pmu_idle_ack_pmu, pmu_idle_ack_cxcs, pmu_idle_ack_cci400, pmu_inactive_cluster_l, pmu_inactive_cluster_b, pmu_idle_gpu, pmu_idle_core, pmu_idle_bus, pmu_idle_dma, pmu_idle_peri, pmu_idle_video, pmu_idle_vio, pmu_idle_cci = 26, pmu_idle_msch, pmu_idle_alive, pmu_idle_pmu, pmu_active_cxcs, pmu_active_cci, }; #define PM_PWRDM_CPUSB_MSK (0xf << 5) #define CKECK_WFE_MSK 0x1 #define CKECK_WFI_MSK 0x10 #define CKECK_WFEI_MSK 0x11 #define PD_CTR_LOOP 500 #define CHK_CPU_LOOP 500 #define MAX_WAIT_CONUT 1000 #endif /* PMU_H */ trusted-firmware-a-2.2/plat/rockchip/rk3368/drivers/soc/000077500000000000000000000000001355360272700230555ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3368/drivers/soc/soc.c000066400000000000000000000140741355360272700240130ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include static uint32_t plls_con[END_PLL_ID][4]; /* Table of regions to map using the MMU. */ const mmap_region_t plat_rk_mmap[] = { MAP_REGION_FLAT(CCI400_BASE, CCI400_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(GIC400_BASE, GIC400_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(STIME_BASE, STIME_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(SGRF_BASE, SGRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(PMUSRAM_BASE, PMUSRAM_SIZE, MT_MEMORY | MT_RW | MT_SECURE), MAP_REGION_FLAT(PMU_BASE, PMU_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(UART0_BASE, UART0_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(UART1_BASE, UART1_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(UART2_BASE, UART2_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(UART3_BASE, UART3_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(UART4_BASE, UART4_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(CRU_BASE, CRU_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DDR_PCTL_BASE, DDR_PCTL_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DDR_PHY_BASE, DDR_PHY_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(GRF_BASE, GRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(SERVICE_BUS_BASE, SERVICE_BUS_SISE, MT_DEVICE | MT_RW | MT_SECURE), { 0 } }; /* The RockChip power domain tree descriptor */ const unsigned char rockchip_power_domain_tree_desc[] = { /* No of root nodes */ PLATFORM_SYSTEM_COUNT, /* No of children for the root node */ PLATFORM_CLUSTER_COUNT, /* No of children for the first cluster node */ PLATFORM_CLUSTER0_CORE_COUNT, /* No of children for the second cluster node */ PLATFORM_CLUSTER1_CORE_COUNT }; void secure_timer_init(void) { mmio_write_32(STIMER1_BASE + TIMER_LOADE_COUNT0, 0xffffffff); mmio_write_32(STIMER1_BASE + TIMER_LOADE_COUNT1, 0xffffffff); /* auto reload & enable the timer */ mmio_write_32(STIMER1_BASE + TIMER_CONTROL_REG, TIMER_EN); } void sgrf_init(void) { /* setting all configurable ip into no-secure */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(5), SGRF_SOC_CON_NS); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6), SGRF_SOC_CON7_BITS); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(7), SGRF_SOC_CON_NS); /* secure dma to no sesure */ mmio_write_32(SGRF_BASE + SGRF_BUSDMAC_CON(0), SGRF_BUSDMAC_CON0_NS); mmio_write_32(SGRF_BASE + SGRF_BUSDMAC_CON(1), SGRF_BUSDMAC_CON1_NS); dsb(); /* rst dma1 */ mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(1), RST_DMA1_MSK | (RST_DMA1_MSK << 16)); /* rst dma2 */ mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(4), RST_DMA2_MSK | (RST_DMA2_MSK << 16)); dsb(); /* release dma1 rst*/ mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(1), (RST_DMA1_MSK << 16)); /* release dma2 rst*/ mmio_write_32(CRU_BASE + CRU_SOFTRSTS_CON(4), (RST_DMA2_MSK << 16)); } void plat_rockchip_soc_init(void) { secure_timer_init(); sgrf_init(); } void regs_updata_bits(uintptr_t addr, uint32_t val, uint32_t mask, uint32_t shift) { uint32_t tmp, orig; orig = mmio_read_32(addr); tmp = orig & ~(mask << shift); tmp |= (val & mask) << shift; if (tmp != orig) mmio_write_32(addr, tmp); dsb(); } static void plls_suspend(uint32_t pll_id) { plls_con[pll_id][0] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 0)); plls_con[pll_id][1] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 1)); plls_con[pll_id][2] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 2)); plls_con[pll_id][3] = mmio_read_32(CRU_BASE + PLL_CONS((pll_id), 3)); mmio_write_32(CRU_BASE + PLL_CONS((pll_id), 3), PLL_SLOW_BITS); mmio_write_32(CRU_BASE + PLL_CONS((pll_id), 3), PLL_BYPASS); } static void pm_plls_suspend(void) { plls_suspend(NPLL_ID); plls_suspend(CPLL_ID); plls_suspend(GPLL_ID); plls_suspend(ABPLL_ID); plls_suspend(ALPLL_ID); } static inline void plls_resume(void) { mmio_write_32(CRU_BASE + PLL_CONS(ABPLL_ID, 3), plls_con[ABPLL_ID][3] | PLL_BYPASS_W_MSK); mmio_write_32(CRU_BASE + PLL_CONS(ALPLL_ID, 3), plls_con[ALPLL_ID][3] | PLL_BYPASS_W_MSK); mmio_write_32(CRU_BASE + PLL_CONS(GPLL_ID, 3), plls_con[GPLL_ID][3] | PLL_BYPASS_W_MSK); mmio_write_32(CRU_BASE + PLL_CONS(CPLL_ID, 3), plls_con[CPLL_ID][3] | PLL_BYPASS_W_MSK); mmio_write_32(CRU_BASE + PLL_CONS(NPLL_ID, 3), plls_con[NPLL_ID][3] | PLL_BYPASS_W_MSK); } void soc_sleep_config(void) { int i = 0; for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), 0xffff0000); pm_plls_suspend(); for (i = 0; i < CRU_CLKGATES_CON_CNT; i++) mmio_write_32(CRU_BASE + CRU_CLKGATES_CON(i), 0xffff0000); } void pm_plls_resume(void) { plls_resume(); mmio_write_32(CRU_BASE + PLL_CONS(ABPLL_ID, 3), plls_con[ABPLL_ID][3] | PLLS_MODE_WMASK); mmio_write_32(CRU_BASE + PLL_CONS(ALPLL_ID, 3), plls_con[ALPLL_ID][3] | PLLS_MODE_WMASK); mmio_write_32(CRU_BASE + PLL_CONS(GPLL_ID, 3), plls_con[GPLL_ID][3] | PLLS_MODE_WMASK); mmio_write_32(CRU_BASE + PLL_CONS(CPLL_ID, 3), plls_con[CPLL_ID][3] | PLLS_MODE_WMASK); mmio_write_32(CRU_BASE + PLL_CONS(NPLL_ID, 3), plls_con[NPLL_ID][3] | PLLS_MODE_WMASK); } void __dead2 rockchip_soc_soft_reset(void) { uint32_t temp_val; mmio_write_32(CRU_BASE + PLL_CONS((GPLL_ID), 3), PLL_SLOW_BITS); mmio_write_32(CRU_BASE + PLL_CONS((CPLL_ID), 3), PLL_SLOW_BITS); mmio_write_32(CRU_BASE + PLL_CONS((NPLL_ID), 3), PLL_SLOW_BITS); mmio_write_32(CRU_BASE + PLL_CONS((ABPLL_ID), 3), PLL_SLOW_BITS); mmio_write_32(CRU_BASE + PLL_CONS((ALPLL_ID), 3), PLL_SLOW_BITS); temp_val = mmio_read_32(CRU_BASE + CRU_GLB_RST_CON) | PMU_RST_BY_SECOND_SFT; mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, temp_val); mmio_write_32(CRU_BASE + CRU_GLB_SRST_SND, 0xeca8); /* * Maybe the HW needs some times to reset the system, * so we do not hope the core to excute valid codes. */ while (1) ; } trusted-firmware-a-2.2/plat/rockchip/rk3368/drivers/soc/soc.h000066400000000000000000000103121355360272700240070ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SOC_H #define SOC_H enum plls_id { ABPLL_ID = 0, ALPLL_ID, DPLL_ID, CPLL_ID, GPLL_ID, NPLL_ID, END_PLL_ID, }; /***************************************************************************** * secure timer *****************************************************************************/ #define TIMER_LOADE_COUNT0 0x00 #define TIMER_LOADE_COUNT1 0x04 #define TIMER_CURRENT_VALUE0 0x08 #define TIMER_CURRENT_VALUE1 0x0C #define TIMER_CONTROL_REG 0x10 #define TIMER_INTSTATUS 0x18 #define TIMER_EN 0x1 #define STIMER1_BASE (STIME_BASE + 0x20) #define CYCL_24M_CNT_US(us) (24 * us) #define CYCL_24M_CNT_MS(ms) (ms * CYCL_24M_CNT_US(1000)) /***************************************************************************** * sgrf reg, offset *****************************************************************************/ #define SGRF_SOC_CON(n) (0x0 + (n) * 4) #define SGRF_BUSDMAC_CON(n) (0x100 + (n) * 4) #define SGRF_SOC_CON_NS 0xffff0000 /***************************************************************************** * con6[2]pmusram is security. * con6[6]stimer is security. *****************************************************************************/ #define PMUSRAM_S_SHIFT 2 #define PMUSRAM_S 1 #define STIMER_S_SHIFT 6 #define STIMER_S 1 #define SGRF_SOC_CON7_BITS ((0xffffu << 16) | \ (PMUSRAM_S << PMUSRAM_S_SHIFT) | \ (STIMER_S << STIMER_S_SHIFT)) #define SGRF_BUSDMAC_CON0_NS 0xfffcfff8 #define SGRF_BUSDMAC_CON1_NS 0xffff0fff /* * sgrf_soc_con1~2, mask and offset */ #define CPU_BOOT_ADDR_WMASK 0xffff0000 #define CPU_BOOT_ADDR_ALIGN 16 /***************************************************************************** * cru reg, offset *****************************************************************************/ #define CRU_SOFTRST_CON 0x300 #define CRU_SOFTRSTS_CON(n) (CRU_SOFTRST_CON + ((n) * 4)) #define CRU_SOFTRSTS_CON_CNT 15 #define SOFTRST_DMA1 0x40004 #define SOFTRST_DMA2 0x10001 #define RST_DMA1_MSK 0x4 #define RST_DMA2_MSK 0x0 #define CRU_CLKSEL_CON 0x100 #define CRU_CLKSELS_CON(i) (CRU_CLKSEL_CON + ((i) * 4)) #define CRU_CLKSEL_CON_CNT 56 #define CRU_CLKGATE_CON 0x200 #define CRU_CLKGATES_CON(i) (CRU_CLKGATE_CON + ((i) * 4)) #define CRU_CLKGATES_CON_CNT 25 #define CRU_GLB_SRST_FST 0x280 #define CRU_GLB_SRST_SND 0x284 #define CRU_GLB_RST_CON 0x388 #define CRU_CONS_GATEID(i) (16 * (i)) #define GATE_ID(reg, bit) ((reg * 16) + bit) #define PMU_RST_BY_SECOND_SFT (BIT(1) << 2) #define PMU_RST_NOT_BY_SFT (BIT(1) << 2) /*************************************************************************** * pll ***************************************************************************/ #define PLL_PWR_DN_MSK (0x1 << 1) #define PLL_PWR_DN REG_WMSK_BITS(1, 1, 0x1) #define PLL_PWR_ON REG_WMSK_BITS(0, 1, 0x1) #define PLL_RESET REG_WMSK_BITS(1, 5, 0x1) #define PLL_RESET_RESUME REG_WMSK_BITS(0, 5, 0x1) #define PLL_BYPASS_MSK (0x1 << 0) #define PLL_BYPASS_W_MSK (PLL_BYPASS_MSK << 16) #define PLL_BYPASS REG_WMSK_BITS(1, 0, 0x1) #define PLL_NO_BYPASS REG_WMSK_BITS(0, 0, 0x1) #define PLL_MODE_SHIFT 8 #define PLL_MODE_MSK 0x3 #define PLLS_MODE_WMASK (PLL_MODE_MSK << (16 + PLL_MODE_SHIFT)) #define PLL_SLOW 0x0 #define PLL_NORM 0x1 #define PLL_DEEP 0x2 #define PLL_SLOW_BITS REG_WMSK_BITS(PLL_SLOW, 8, 0x3) #define PLL_NORM_BITS REG_WMSK_BITS(PLL_NORM, 8, 0x3) #define PLL_DEEP_BITS REG_WMSK_BITS(PLL_DEEP, 8, 0x3) #define PLL_CONS(id, i) ((id) * 0x10 + ((i) * 4)) #define REG_W_MSK(bits_shift, msk) \ ((msk) << ((bits_shift) + 16)) #define REG_VAL_CLRBITS(val, bits_shift, msk) \ (val & (~(msk << bits_shift))) #define REG_SET_BITS(bits, bits_shift, msk) \ (((bits) & (msk)) << (bits_shift)) #define REG_WMSK_BITS(bits, bits_shift, msk) \ (REG_W_MSK(bits_shift, msk) | \ REG_SET_BITS(bits, bits_shift, msk)) #define regs_updata_bit_set(addr, shift) \ regs_updata_bits((addr), 0x1, 0x1, (shift)) #define regs_updata_bit_clr(addr, shift) \ regs_updata_bits((addr), 0x0, 0x1, (shift)) void regs_updata_bits(uintptr_t addr, uint32_t val, uint32_t mask, uint32_t shift); void soc_sleep_config(void); void pm_plls_resume(void); #endif /* SOC_H */ trusted-firmware-a-2.2/plat/rockchip/rk3368/include/000077500000000000000000000000001355360272700222365ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3368/include/plat.ld.S000066400000000000000000000013611355360272700237210ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ROCKCHIP_PLAT_LD_S #define ROCKCHIP_PLAT_LD_S MEMORY { PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE } SECTIONS { . = PMUSRAM_BASE; /* * pmu_cpuson_entrypoint request address * align 64K when resume, so put it in the * start of pmusram */ .text_pmusram : { ASSERT(. == ALIGN(64 * 1024), ".pmusram.entry request 64K aligned."); *(.pmusram.entry) __bl31_pmusram_text_start = .; *(.pmusram.text) *(.pmusram.rodata) __bl31_pmusram_text_end = .; __bl31_pmusram_data_start = .; *(.pmusram.data) __bl31_pmusram_data_end = .; } >PMUSRAM } #endif /* ROCKCHIP_PLAT_LD_S */ trusted-firmware-a-2.2/plat/rockchip/rk3368/include/plat_sip_calls.h000066400000000000000000000003601355360272700253770ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_SIP_CALLS_H #define PLAT_SIP_CALLS_H #define RK_PLAT_SIP_NUM_CALLS 0 #endif /* PLAT_SIP_CALLS_H */ trusted-firmware-a-2.2/plat/rockchip/rk3368/include/platform_def.h000066400000000000000000000100221355360272700250440ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include /******************************************************************************* * Platform binary types for linking ******************************************************************************/ #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 /******************************************************************************* * Generic platform constants ******************************************************************************/ /* Size of cacheable stacks */ #if defined(IMAGE_BL1) #define PLATFORM_STACK_SIZE 0x440 #elif defined(IMAGE_BL2) #define PLATFORM_STACK_SIZE 0x400 #elif defined(IMAGE_BL31) #define PLATFORM_STACK_SIZE 0x800 #elif defined(IMAGE_BL32) #define PLATFORM_STACK_SIZE 0x440 #endif #define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n" #define PLATFORM_MAX_AFFLVL MPIDR_AFFLVL2 #define PLATFORM_SYSTEM_COUNT 1 #define PLATFORM_CLUSTER_COUNT 2 #define PLATFORM_CLUSTER0_CORE_COUNT 4 #define PLATFORM_CLUSTER1_CORE_COUNT 4 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \ PLATFORM_CLUSTER0_CORE_COUNT) #define PLATFORM_MAX_CPUS_PER_CLUSTER 4 #define PLATFORM_NUM_AFFS (PLATFORM_SYSTEM_COUNT + \ PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLAT_RK_CLST_TO_CPUID_SHIFT 8 #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2 /* * This macro defines the deepest retention state possible. A higher state * id will represent an invalid or a power down state. */ #define PLAT_MAX_RET_STATE U(1) /* * This macro defines the deepest power down states possible. Any state ID * higher than this is invalid. */ #define PLAT_MAX_OFF_STATE U(2) /******************************************************************************* * Platform memory map related constants ******************************************************************************/ /* TF text, ro, rw, Size: 512KB */ #define TZRAM_BASE (0x0) #define TZRAM_SIZE (0x80000) /******************************************************************************* * BL31 specific defines. ******************************************************************************/ /* * Put BL3-1 at the top of the Trusted RAM */ #define BL31_BASE (TZRAM_BASE + 0x40000) #define BL31_LIMIT (TZRAM_BASE + TZRAM_SIZE) /******************************************************************************* * Platform specific page table and MMU setup constants ******************************************************************************/ #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define MAX_XLAT_TABLES 8 #define MAX_MMAP_REGIONS 16 /******************************************************************************* * Declarations and constants to access the mailboxes safely. Each mailbox is * aligned on the biggest cache line size in the platform. This is known only * to the platform as it might have a combination of integrated and external * caches. Such alignment ensures that two maiboxes do not sit on the same cache * line at any cache level. They could belong to different cpus/clusters & * get written while being protected by different locks causing corruption of * a valid mailbox address. ******************************************************************************/ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) /* * Define GICD and GICC and GICR base */ #define PLAT_RK_GICD_BASE RK3368_GICD_BASE #define PLAT_RK_GICC_BASE RK3368_GICC_BASE #define PLAT_RK_UART_BASE UART2_BASE #define PLAT_RK_UART_CLOCK RK3368_UART_CLOCK #define PLAT_RK_UART_BAUDRATE RK3368_BAUDRATE #define PLAT_RK_CCI_BASE CCI400_BASE #define PLAT_RK_PRIMARY_CPU 0x0 #define PSRAM_DO_DDR_RESUME 0 #define PSRAM_CHECK_WAKEUP_CPU 0 #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/rockchip/rk3368/plat_sip_calls.c000066400000000000000000000010761355360272700237540ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include uintptr_t rockchip_plat_sip_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) { ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); SMC_RET1(handle, SMC_UNK); } trusted-firmware-a-2.2/plat/rockchip/rk3368/platform.mk000066400000000000000000000037711355360272700230000ustar00rootroot00000000000000# # Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # RK_PLAT := plat/rockchip RK_PLAT_SOC := ${RK_PLAT}/${PLAT} RK_PLAT_COMMON := ${RK_PLAT}/common DISABLE_BIN_GENERATION := 1 PLAT_INCLUDES := -I${RK_PLAT_COMMON}/ \ -I${RK_PLAT_COMMON}/include/ \ -I${RK_PLAT_COMMON}/aarch64/ \ -I${RK_PLAT_COMMON}/drivers/pmu/ \ -I${RK_PLAT_SOC}/ \ -I${RK_PLAT_SOC}/drivers/pmu/ \ -I${RK_PLAT_SOC}/drivers/soc/ \ -I${RK_PLAT_SOC}/drivers/ddr/ \ -I${RK_PLAT_SOC}/include/ RK_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ plat/common/plat_gicv2.c \ ${RK_PLAT}/common/rockchip_gicv2.c PLAT_BL_COMMON_SOURCES := common/desc_image_load.c \ lib/bl_aux_params/bl_aux_params.c \ lib/xlat_tables/xlat_tables_common.c \ lib/xlat_tables/aarch64/xlat_tables.c \ plat/common/aarch64/crash_console_helpers.S \ plat/common/plat_psci_common.c BL31_SOURCES += ${RK_GIC_SOURCES} \ drivers/arm/cci/cci.c \ drivers/ti/uart/aarch64/16550_console.S \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ lib/cpus/aarch64/cortex_a53.S \ ${RK_PLAT_COMMON}/aarch64/plat_helpers.S \ ${RK_PLAT_COMMON}/bl31_plat_setup.c \ ${RK_PLAT_COMMON}/params_setup.c \ ${RK_PLAT_COMMON}/aarch64/pmu_sram_cpus_on.S \ ${RK_PLAT_COMMON}/plat_pm.c \ ${RK_PLAT_COMMON}/plat_topology.c \ ${RK_PLAT_COMMON}/aarch64/platform_common.c \ ${RK_PLAT_COMMON}/rockchip_sip_svc.c \ ${RK_PLAT_SOC}/plat_sip_calls.c \ ${RK_PLAT_SOC}/drivers/pmu/pmu.c \ ${RK_PLAT_SOC}/drivers/soc/soc.c \ ${RK_PLAT_SOC}/drivers/ddr/ddr_rk3368.c \ include lib/coreboot/coreboot.mk include lib/libfdt/libfdt.mk $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) # Do not enable SVE ENABLE_SVE_FOR_NS := 0 WORKAROUND_CVE_2017_5715 := 0 trusted-firmware-a-2.2/plat/rockchip/rk3368/rk3368_def.h000066400000000000000000000064151355360272700225500ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RK3368_DEF_H #define RK3368_DEF_H /* Special value used to verify platform parameters from BL2 to BL3-1 */ #define RK_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL #define CCI400_BASE 0xffb90000 #define CCI400_SIZE 0x10000 #define GIC400_BASE 0xffb70000 #define GIC400_SIZE 0x10000 #define STIME_BASE 0xff830000 #define STIME_SIZE 0x10000 #define CRU_BASE 0xff760000 #define CRU_SIZE 0x10000 #define GRF_BASE 0xff770000 #define GRF_SIZE 0x10000 #define SGRF_BASE 0xff740000 #define SGRF_SIZE 0x10000 #define PMU_BASE 0xff730000 #define PMU_GRF_BASE 0xff738000 #define PMU_SIZE 0x10000 #define RK_INTMEM_BASE 0xff8c0000 #define RK_INTMEM_SIZE 0x10000 #define UART0_BASE 0xff180000 #define UART0_SIZE 0x10000 #define UART1_BASE 0xff190000 #define UART1_SIZE 0x10000 #define UART2_BASE 0xff690000 #define UART2_SIZE 0x10000 #define UART3_BASE 0xff1b0000 #define UART3_SIZE 0x10000 #define UART4_BASE 0xff1c0000 #define UART4_SIZE 0x10000 #define CRU_BASE 0xff760000 #define PMUSRAM_BASE 0xff720000 #define PMUSRAM_SIZE 0x10000 #define PMUSRAM_RSIZE 0x1000 #define DDR_PCTL_BASE 0xff610000 #define DDR_PCTL_SIZE 0x10000 #define DDR_PHY_BASE 0xff620000 #define DDR_PHY_SIZE 0x10000 #define SERVICE_BUS_BASE 0xffac0000 #define SERVICE_BUS_SISE 0x50000 #define COLD_BOOT_BASE 0xffff0000 /************************************************************************** * UART related constants **************************************************************************/ #define RK3368_BAUDRATE 115200 #define RK3368_UART_CLOCK 24000000 /****************************************************************************** * System counter frequency related constants ******************************************************************************/ #define SYS_COUNTER_FREQ_IN_TICKS 24000000 /****************************************************************************** * GIC-400 & interrupt handling related constants ******************************************************************************/ /* Base rk_platform compatible GIC memory map */ #define RK3368_GICD_BASE (GIC400_BASE + 0x1000) #define RK3368_GICC_BASE (GIC400_BASE + 0x2000) #define RK3368_GICR_BASE 0 /* no GICR in GIC-400 */ /***************************************************************************** * CCI-400 related constants ******************************************************************************/ #define PLAT_RK_CCI_CLUSTER0_SL_IFACE_IX 3 #define PLAT_RK_CCI_CLUSTER1_SL_IFACE_IX 4 /****************************************************************************** * sgi, ppi ******************************************************************************/ #define RK_IRQ_SEC_PHY_TIMER 29 #define RK_IRQ_SEC_SGI_0 8 #define RK_IRQ_SEC_SGI_1 9 #define RK_IRQ_SEC_SGI_2 10 #define RK_IRQ_SEC_SGI_3 11 #define RK_IRQ_SEC_SGI_4 12 #define RK_IRQ_SEC_SGI_5 13 #define RK_IRQ_SEC_SGI_6 14 #define RK_IRQ_SEC_SGI_7 15 /* * Define a list of Group 0 interrupts. */ #define PLAT_RK_GICV2_G0_IRQS \ INTR_PROP_DESC(RK_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, \ GICV2_INTR_GROUP0, GIC_INTR_CFG_LEVEL) #endif /* RK3368_DEF_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/000077500000000000000000000000001355360272700206175ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/000077500000000000000000000000001355360272700222755ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/dp/000077500000000000000000000000001355360272700227005ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/dp/cdn_dp.c000066400000000000000000000027071355360272700243010ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include __asm__( ".pushsection .text.hdcp_handler, \"ax\", %progbits\n" ".global hdcp_handler\n" ".balign 4\n" "hdcp_handler:\n" ".incbin \"" __XSTRING(HDCPFW) "\"\n" ".type hdcp_handler, %function\n" ".size hdcp_handler, .- hdcp_handler\n" ".popsection\n" ); static uint64_t *hdcp_key_pdata; static struct cdn_dp_hdcp_key_1x key; int hdcp_handler(struct cdn_dp_hdcp_key_1x *key); uint64_t dp_hdcp_ctrl(uint64_t type) { switch (type) { case HDCP_KEY_DATA_START_TRANSFER: memset(&key, 0x00, sizeof(key)); hdcp_key_pdata = (uint64_t *)&key; return 0; case HDCP_KEY_DATA_START_DECRYPT: if (hdcp_key_pdata == (uint64_t *)(&key + 1)) return hdcp_handler(&key); else return PSCI_E_INVALID_PARAMS; assert(0); /* Unreachable */ default: return SMC_UNK; } } uint64_t dp_hdcp_store_key(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6) { if (hdcp_key_pdata < (uint64_t *)&key || hdcp_key_pdata + 6 > (uint64_t *)(&key + 1)) return PSCI_E_INVALID_PARAMS; hdcp_key_pdata[0] = x1; hdcp_key_pdata[1] = x2; hdcp_key_pdata[2] = x3; hdcp_key_pdata[3] = x4; hdcp_key_pdata[4] = x5; hdcp_key_pdata[5] = x6; hdcp_key_pdata += 6; return 0; } trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/dp/cdn_dp.h000066400000000000000000000022771355360272700243100ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CDN_DP_H #define CDN_DP_H #include enum { CDN_DP_HDCP_1X_KSV_LEN = 5, CDN_DP_HDCP_KSV_LEN = 8, CDN_DP_HDCP_RESERVED_LEN = 10, CDN_DP_HDCP_UID_LEN = 16, CDN_DP_HDCP_SHA_LEN = 20, CDN_DP_HDCP_DPK_LEN = 280, CDN_DP_HDCP_1X_KEYS_LEN = 285, CDN_DP_HDCP_KEY_LEN = 326, }; struct cdn_dp_hdcp_key_1x { uint8_t ksv[CDN_DP_HDCP_KSV_LEN]; uint8_t device_key[CDN_DP_HDCP_DPK_LEN]; uint8_t sha1[CDN_DP_HDCP_SHA_LEN]; uint8_t uid[CDN_DP_HDCP_UID_LEN]; uint16_t seed; uint8_t reserved[CDN_DP_HDCP_RESERVED_LEN]; }; #define HDCP_KEY_DATA_START_TRANSFER 0 #define HDCP_KEY_DATA_START_DECRYPT 1 #define HDCP_KEY_1X_STORE_DATA_ALIGN_SIZE (6 * 64) / 8 /* Checks the cdn_dp_hdcp_key_1x must be aligned on 6 x 64-bit word boundary */ CASSERT(sizeof(struct cdn_dp_hdcp_key_1x) % HDCP_KEY_1X_STORE_DATA_ALIGN_SIZE, \ assert_hdcp_key_1x_store_data_align_size_mismatch); uint64_t dp_hdcp_ctrl(uint64_t type); uint64_t dp_hdcp_store_key(uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, uint64_t x5, uint64_t x6); #endif /* CDN_DP_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/dp/hdcp.bin000066400000000000000000000015401355360272700243100ustar00rootroot00000000000000ÿÑ€ÒÿCÑá ‘þùhb8Ch!8B‘_@ñÿÿTàC‘#€R"ˆBy€Ò9c €R9ÀR9c€R 9C€9# €R9€R9C€9ã €R 9£€R$9#€R(9ã€,9£ €R09# €R49C|S<989パ€Ò&‹e‹ÇÐD9hb8æJ¦h"8B‘_@ñÿÿT„@‘ŸñþÿT€Òàƒ‘Bh 8B‘_ñ¡ÿÿT€Ò€Rhb8ehb8„ „ „…|@“he8h"8B‘h%8_ñ¡þÿT$ ‘)€‘窀R€RÆÆÈ|@“hh8¥ ¥ª|@“ hj8 h(8h*8hh8 è@9BShb8Jâ8ÿ ëÁýÿT ‘"‘G@9ð_8ð8Fô8ë‘CÿÿT⪀‘_ëÂT@9E@9F8ô8úÿÿ„‘Ÿ ë¡þÿT Ì‘"€‘@9D@9E8ô8_ëcÿÿT€Ò"h`8bh 8‘ñÿÿT€Ò$‹b‹‘`ñ„ @9D9AÿÿT€R¢#€Rà€R%”þ@ùÿC‘ÿ‘À_Öh‰RSƒ  r€R€ÒØ¿ò!@¹4cqáT€ÒØ¿ò!@¹Á4 €"à;Õâ"*$à;Õå$*D AK¿k!„!|!ÿÿ4êÿÿ€ÒØ¿ò ¹€RÀ_ÖÿÃÑóS©T<Sà§9õ{©€~Sõªá£9€Òà«9ô¯9࣑`j`8Óÿÿ— 5s‘ñAÿÿT€ÒŸkÍT js8s‘Éÿÿ—`ÿÿ4€RóS@©õ{A©ÿÑÀ_Ötrusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/dram/000077500000000000000000000000001355360272700232205ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/dram/dfs.c000066400000000000000000002062271355360272700241510ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "dfs.h" #include "dram.h" #include "dram_spec_timing.h" #include "pmu.h" #include "soc.h" #include "string.h" #define ENPER_CS_TRAINING_FREQ (666) #define TDFI_LAT_THRESHOLD_FREQ (928) #define PHY_DLL_BYPASS_FREQ (260) static const struct pll_div dpll_rates_table[] = { /* _mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2 */ {.mhz = 928, .refdiv = 1, .fbdiv = 116, .postdiv1 = 3, .postdiv2 = 1}, {.mhz = 800, .refdiv = 1, .fbdiv = 100, .postdiv1 = 3, .postdiv2 = 1}, {.mhz = 732, .refdiv = 1, .fbdiv = 61, .postdiv1 = 2, .postdiv2 = 1}, {.mhz = 666, .refdiv = 1, .fbdiv = 111, .postdiv1 = 4, .postdiv2 = 1}, {.mhz = 600, .refdiv = 1, .fbdiv = 50, .postdiv1 = 2, .postdiv2 = 1}, {.mhz = 528, .refdiv = 1, .fbdiv = 66, .postdiv1 = 3, .postdiv2 = 1}, {.mhz = 400, .refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 1}, {.mhz = 300, .refdiv = 1, .fbdiv = 50, .postdiv1 = 4, .postdiv2 = 1}, {.mhz = 200, .refdiv = 1, .fbdiv = 50, .postdiv1 = 3, .postdiv2 = 2}, }; struct rk3399_dram_status { uint32_t current_index; uint32_t index_freq[2]; uint32_t boot_freq; uint32_t low_power_stat; struct timing_related_config timing_config; struct drv_odt_lp_config drv_odt_lp_cfg; }; struct rk3399_saved_status { uint32_t freq; uint32_t low_power_stat; uint32_t odt; }; static struct rk3399_dram_status rk3399_dram_status; static struct rk3399_saved_status rk3399_suspend_status; static uint32_t wrdqs_delay_val[2][2][4]; static uint32_t rddqs_delay_ps; static struct rk3399_sdram_default_config ddr3_default_config = { .bl = 8, .ap = 0, .burst_ref_cnt = 1, .zqcsi = 0 }; static struct rk3399_sdram_default_config lpddr3_default_config = { .bl = 8, .ap = 0, .burst_ref_cnt = 1, .zqcsi = 0 }; static struct rk3399_sdram_default_config lpddr4_default_config = { .bl = 16, .ap = 0, .caodt = 240, .burst_ref_cnt = 1, .zqcsi = 0 }; static uint32_t get_cs_die_capability(struct rk3399_sdram_params *sdram_config, uint8_t channel, uint8_t cs) { struct rk3399_sdram_channel *ch = &sdram_config->ch[channel]; uint32_t bandwidth; uint32_t die_bandwidth; uint32_t die; uint32_t cs_cap; uint32_t row; row = cs == 0 ? ch->cs0_row : ch->cs1_row; bandwidth = 8 * (1 << ch->bw); die_bandwidth = 8 * (1 << ch->dbw); die = bandwidth / die_bandwidth; cs_cap = (1 << (row + ((1 << ch->bk) / 4 + 1) + ch->col + (bandwidth / 16))); if (ch->row_3_4) cs_cap = cs_cap * 3 / 4; return (cs_cap / die); } static void get_dram_drv_odt_val(uint32_t dram_type, struct drv_odt_lp_config *drv_config) { uint32_t tmp; uint32_t mr1_val, mr3_val, mr11_val; switch (dram_type) { case DDR3: mr1_val = (mmio_read_32(CTL_REG(0, 133)) >> 16) & 0xffff; tmp = ((mr1_val >> 1) & 1) | ((mr1_val >> 4) & 1); if (tmp) drv_config->dram_side_drv = 34; else drv_config->dram_side_drv = 40; tmp = ((mr1_val >> 2) & 1) | ((mr1_val >> 5) & 1) | ((mr1_val >> 7) & 1); if (tmp == 0) drv_config->dram_side_dq_odt = 0; else if (tmp == 1) drv_config->dram_side_dq_odt = 60; else if (tmp == 3) drv_config->dram_side_dq_odt = 40; else drv_config->dram_side_dq_odt = 120; break; case LPDDR3: mr3_val = mmio_read_32(CTL_REG(0, 138)) & 0xf; mr11_val = (mmio_read_32(CTL_REG(0, 139)) >> 24) & 0x3; if (mr3_val == 0xb) drv_config->dram_side_drv = 3448; else if (mr3_val == 0xa) drv_config->dram_side_drv = 4048; else if (mr3_val == 0x9) drv_config->dram_side_drv = 3440; else if (mr3_val == 0x4) drv_config->dram_side_drv = 60; else if (mr3_val == 0x3) drv_config->dram_side_drv = 48; else if (mr3_val == 0x2) drv_config->dram_side_drv = 40; else drv_config->dram_side_drv = 34; if (mr11_val == 1) drv_config->dram_side_dq_odt = 60; else if (mr11_val == 2) drv_config->dram_side_dq_odt = 120; else if (mr11_val == 0) drv_config->dram_side_dq_odt = 0; else drv_config->dram_side_dq_odt = 240; break; case LPDDR4: default: mr3_val = (mmio_read_32(CTL_REG(0, 138)) >> 3) & 0x7; mr11_val = (mmio_read_32(CTL_REG(0, 139)) >> 24) & 0xff; if ((mr3_val == 0) || (mr3_val == 7)) drv_config->dram_side_drv = 40; else drv_config->dram_side_drv = 240 / mr3_val; tmp = mr11_val & 0x7; if ((tmp == 7) || (tmp == 0)) drv_config->dram_side_dq_odt = 0; else drv_config->dram_side_dq_odt = 240 / tmp; tmp = (mr11_val >> 4) & 0x7; if ((tmp == 7) || (tmp == 0)) drv_config->dram_side_ca_odt = 0; else drv_config->dram_side_ca_odt = 240 / tmp; break; } } static void sdram_timing_cfg_init(struct timing_related_config *ptiming_config, struct rk3399_sdram_params *sdram_params, struct drv_odt_lp_config *drv_config) { uint32_t i, j; for (i = 0; i < sdram_params->num_channels; i++) { ptiming_config->dram_info[i].speed_rate = DDR3_DEFAULT; ptiming_config->dram_info[i].cs_cnt = sdram_params->ch[i].rank; for (j = 0; j < sdram_params->ch[i].rank; j++) { ptiming_config->dram_info[i].per_die_capability[j] = get_cs_die_capability(sdram_params, i, j); } } ptiming_config->dram_type = sdram_params->dramtype; ptiming_config->ch_cnt = sdram_params->num_channels; switch (sdram_params->dramtype) { case DDR3: ptiming_config->bl = ddr3_default_config.bl; ptiming_config->ap = ddr3_default_config.ap; break; case LPDDR3: ptiming_config->bl = lpddr3_default_config.bl; ptiming_config->ap = lpddr3_default_config.ap; break; case LPDDR4: ptiming_config->bl = lpddr4_default_config.bl; ptiming_config->ap = lpddr4_default_config.ap; ptiming_config->rdbi = 0; ptiming_config->wdbi = 0; break; default: /* Do nothing in default case */ break; } ptiming_config->dramds = drv_config->dram_side_drv; ptiming_config->dramodt = drv_config->dram_side_dq_odt; ptiming_config->caodt = drv_config->dram_side_ca_odt; ptiming_config->odt = (mmio_read_32(PHY_REG(0, 5)) >> 16) & 0x1; } struct lat_adj_pair { uint32_t cl; uint32_t rdlat_adj; uint32_t cwl; uint32_t wrlat_adj; }; const struct lat_adj_pair ddr3_lat_adj[] = { {6, 5, 5, 4}, {8, 7, 6, 5}, {10, 9, 7, 6}, {11, 9, 8, 7}, {13, 0xb, 9, 8}, {14, 0xb, 0xa, 9} }; const struct lat_adj_pair lpddr3_lat_adj[] = { {3, 2, 1, 0}, {6, 5, 3, 2}, {8, 7, 4, 3}, {9, 8, 5, 4}, {10, 9, 6, 5}, {11, 9, 6, 5}, {12, 0xa, 6, 5}, {14, 0xc, 8, 7}, {16, 0xd, 8, 7} }; const struct lat_adj_pair lpddr4_lat_adj[] = { {6, 5, 4, 2}, {10, 9, 6, 4}, {14, 0xc, 8, 6}, {20, 0x11, 0xa, 8}, {24, 0x15, 0xc, 0xa}, {28, 0x18, 0xe, 0xc}, {32, 0x1b, 0x10, 0xe}, {36, 0x1e, 0x12, 0x10} }; static uint32_t get_rdlat_adj(uint32_t dram_type, uint32_t cl) { const struct lat_adj_pair *p; uint32_t cnt; uint32_t i; if (dram_type == DDR3) { p = ddr3_lat_adj; cnt = ARRAY_SIZE(ddr3_lat_adj); } else if (dram_type == LPDDR3) { p = lpddr3_lat_adj; cnt = ARRAY_SIZE(lpddr3_lat_adj); } else { p = lpddr4_lat_adj; cnt = ARRAY_SIZE(lpddr4_lat_adj); } for (i = 0; i < cnt; i++) { if (cl == p[i].cl) return p[i].rdlat_adj; } /* fail */ return 0xff; } static uint32_t get_wrlat_adj(uint32_t dram_type, uint32_t cwl) { const struct lat_adj_pair *p; uint32_t cnt; uint32_t i; if (dram_type == DDR3) { p = ddr3_lat_adj; cnt = ARRAY_SIZE(ddr3_lat_adj); } else if (dram_type == LPDDR3) { p = lpddr3_lat_adj; cnt = ARRAY_SIZE(lpddr3_lat_adj); } else { p = lpddr4_lat_adj; cnt = ARRAY_SIZE(lpddr4_lat_adj); } for (i = 0; i < cnt; i++) { if (cwl == p[i].cwl) return p[i].wrlat_adj; } /* fail */ return 0xff; } #define PI_REGS_DIMM_SUPPORT (0) #define PI_ADD_LATENCY (0) #define PI_DOUBLEFREEK (1) #define PI_PAD_DELAY_PS_VALUE (1000) #define PI_IE_ENABLE_VALUE (3000) #define PI_TSEL_ENABLE_VALUE (700) static uint32_t get_pi_rdlat_adj(struct dram_timing_t *pdram_timing) { /*[DLLSUBTYPE2] == "STD_DENALI_HS" */ uint32_t rdlat, delay_adder, ie_enable, hs_offset, tsel_adder, extra_adder, tsel_enable; ie_enable = PI_IE_ENABLE_VALUE; tsel_enable = PI_TSEL_ENABLE_VALUE; rdlat = pdram_timing->cl + PI_ADD_LATENCY; delay_adder = ie_enable / (1000000 / pdram_timing->mhz); if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0) delay_adder++; hs_offset = 0; tsel_adder = 0; extra_adder = 0; /* rdlat = rdlat - (PREAMBLE_SUPPORT & 0x1); */ tsel_adder = tsel_enable / (1000000 / pdram_timing->mhz); if ((tsel_enable % (1000000 / pdram_timing->mhz)) != 0) tsel_adder++; delay_adder = delay_adder - 1; if (tsel_adder > delay_adder) extra_adder = tsel_adder - delay_adder; else extra_adder = 0; if (PI_REGS_DIMM_SUPPORT && PI_DOUBLEFREEK) hs_offset = 2; else hs_offset = 1; if (delay_adder > (rdlat - 1 - hs_offset)) { rdlat = rdlat - tsel_adder; } else { if ((rdlat - delay_adder) < 2) rdlat = 2; else rdlat = rdlat - delay_adder - extra_adder; } return rdlat; } static uint32_t get_pi_wrlat(struct dram_timing_t *pdram_timing, struct timing_related_config *timing_config) { uint32_t tmp; if (timing_config->dram_type == LPDDR3) { tmp = pdram_timing->cl; if (tmp >= 14) tmp = 8; else if (tmp >= 10) tmp = 6; else if (tmp == 9) tmp = 5; else if (tmp == 8) tmp = 4; else if (tmp == 6) tmp = 3; else tmp = 1; } else { tmp = 1; } return tmp; } static uint32_t get_pi_wrlat_adj(struct dram_timing_t *pdram_timing, struct timing_related_config *timing_config) { return get_pi_wrlat(pdram_timing, timing_config) + PI_ADD_LATENCY - 1; } static uint32_t get_pi_tdfi_phy_rdlat(struct dram_timing_t *pdram_timing, struct timing_related_config *timing_config) { /* [DLLSUBTYPE2] == "STD_DENALI_HS" */ uint32_t cas_lat, delay_adder, ie_enable, hs_offset, ie_delay_adder; uint32_t mem_delay_ps, round_trip_ps; uint32_t phy_internal_delay, lpddr_adder, dfi_adder, rdlat_delay; ie_enable = PI_IE_ENABLE_VALUE; delay_adder = ie_enable / (1000000 / pdram_timing->mhz); if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0) delay_adder++; delay_adder = delay_adder - 1; if (PI_REGS_DIMM_SUPPORT && PI_DOUBLEFREEK) hs_offset = 2; else hs_offset = 1; cas_lat = pdram_timing->cl + PI_ADD_LATENCY; if (delay_adder > (cas_lat - 1 - hs_offset)) { ie_delay_adder = 0; } else { ie_delay_adder = ie_enable / (1000000 / pdram_timing->mhz); if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0) ie_delay_adder++; } if (timing_config->dram_type == DDR3) { mem_delay_ps = 0; } else if (timing_config->dram_type == LPDDR4) { mem_delay_ps = 3600; } else if (timing_config->dram_type == LPDDR3) { mem_delay_ps = 5500; } else { NOTICE("get_pi_tdfi_phy_rdlat:dramtype unsupport\n"); return 0; } round_trip_ps = 1100 + 500 + mem_delay_ps + 500 + 600; delay_adder = round_trip_ps / (1000000 / pdram_timing->mhz); if ((round_trip_ps % (1000000 / pdram_timing->mhz)) != 0) delay_adder++; phy_internal_delay = 5 + 2 + 4; lpddr_adder = mem_delay_ps / (1000000 / pdram_timing->mhz); if ((mem_delay_ps % (1000000 / pdram_timing->mhz)) != 0) lpddr_adder++; dfi_adder = 0; phy_internal_delay = phy_internal_delay + 2; rdlat_delay = delay_adder + phy_internal_delay + ie_delay_adder + lpddr_adder + dfi_adder; rdlat_delay = rdlat_delay + 2; return rdlat_delay; } static uint32_t get_pi_todtoff_min(struct dram_timing_t *pdram_timing, struct timing_related_config *timing_config) { uint32_t tmp, todtoff_min_ps; if (timing_config->dram_type == LPDDR3) todtoff_min_ps = 2500; else if (timing_config->dram_type == LPDDR4) todtoff_min_ps = 1500; else todtoff_min_ps = 0; /* todtoff_min */ tmp = todtoff_min_ps / (1000000 / pdram_timing->mhz); if ((todtoff_min_ps % (1000000 / pdram_timing->mhz)) != 0) tmp++; return tmp; } static uint32_t get_pi_todtoff_max(struct dram_timing_t *pdram_timing, struct timing_related_config *timing_config) { uint32_t tmp, todtoff_max_ps; if ((timing_config->dram_type == LPDDR4) || (timing_config->dram_type == LPDDR3)) todtoff_max_ps = 3500; else todtoff_max_ps = 0; /* todtoff_max */ tmp = todtoff_max_ps / (1000000 / pdram_timing->mhz); if ((todtoff_max_ps % (1000000 / pdram_timing->mhz)) != 0) tmp++; return tmp; } static void gen_rk3399_ctl_params_f0(struct timing_related_config *timing_config, struct dram_timing_t *pdram_timing) { uint32_t i; uint32_t tmp, tmp1; for (i = 0; i < timing_config->ch_cnt; i++) { if (timing_config->dram_type == DDR3) { tmp = ((700000 + 10) * timing_config->freq + 999) / 1000; tmp += pdram_timing->txsnr + (pdram_timing->tmrd * 3) + pdram_timing->tmod + pdram_timing->tzqinit; mmio_write_32(CTL_REG(i, 5), tmp); mmio_clrsetbits_32(CTL_REG(i, 22), 0xffff, pdram_timing->tdllk); mmio_write_32(CTL_REG(i, 32), (pdram_timing->tmod << 8) | pdram_timing->tmrd); mmio_clrsetbits_32(CTL_REG(i, 59), 0xffffu << 16, (pdram_timing->txsr - pdram_timing->trcd) << 16); } else if (timing_config->dram_type == LPDDR4) { mmio_write_32(CTL_REG(i, 5), pdram_timing->tinit1 + pdram_timing->tinit3); mmio_write_32(CTL_REG(i, 32), (pdram_timing->tmrd << 8) | pdram_timing->tmrd); mmio_clrsetbits_32(CTL_REG(i, 59), 0xffffu << 16, pdram_timing->txsr << 16); } else { mmio_write_32(CTL_REG(i, 5), pdram_timing->tinit1); mmio_write_32(CTL_REG(i, 7), pdram_timing->tinit4); mmio_write_32(CTL_REG(i, 32), (pdram_timing->tmrd << 8) | pdram_timing->tmrd); mmio_clrsetbits_32(CTL_REG(i, 59), 0xffffu << 16, pdram_timing->txsr << 16); } mmio_write_32(CTL_REG(i, 6), pdram_timing->tinit3); mmio_write_32(CTL_REG(i, 8), pdram_timing->tinit5); mmio_clrsetbits_32(CTL_REG(i, 23), (0x7f << 16), ((pdram_timing->cl * 2) << 16)); mmio_clrsetbits_32(CTL_REG(i, 23), (0x1f << 24), (pdram_timing->cwl << 24)); mmio_clrsetbits_32(CTL_REG(i, 24), 0x3f, pdram_timing->al); mmio_clrsetbits_32(CTL_REG(i, 26), 0xffffu << 16, (pdram_timing->trc << 24) | (pdram_timing->trrd << 16)); mmio_write_32(CTL_REG(i, 27), (pdram_timing->tfaw << 24) | (pdram_timing->trppb << 16) | (pdram_timing->twtr << 8) | pdram_timing->tras_min); mmio_clrsetbits_32(CTL_REG(i, 31), 0xffu << 24, max(4, pdram_timing->trtp) << 24); mmio_write_32(CTL_REG(i, 33), (pdram_timing->tcke << 24) | pdram_timing->tras_max); mmio_clrsetbits_32(CTL_REG(i, 34), 0xff, max(1, pdram_timing->tckesr)); mmio_clrsetbits_32(CTL_REG(i, 39), (0x3f << 16) | (0xff << 8), (pdram_timing->twr << 16) | (pdram_timing->trcd << 8)); mmio_clrsetbits_32(CTL_REG(i, 42), 0x1f << 16, pdram_timing->tmrz << 16); tmp = pdram_timing->tdal ? pdram_timing->tdal : (pdram_timing->twr + pdram_timing->trp); mmio_clrsetbits_32(CTL_REG(i, 44), 0xff, tmp); mmio_clrsetbits_32(CTL_REG(i, 45), 0xff, pdram_timing->trp); mmio_write_32(CTL_REG(i, 48), ((pdram_timing->trefi - 8) << 16) | pdram_timing->trfc); mmio_clrsetbits_32(CTL_REG(i, 52), 0xffff, pdram_timing->txp); mmio_clrsetbits_32(CTL_REG(i, 53), 0xffffu << 16, pdram_timing->txpdll << 16); mmio_clrsetbits_32(CTL_REG(i, 55), 0xf << 24, pdram_timing->tcscke << 24); mmio_clrsetbits_32(CTL_REG(i, 55), 0xff, pdram_timing->tmrri); mmio_write_32(CTL_REG(i, 56), (pdram_timing->tzqcke << 24) | (pdram_timing->tmrwckel << 16) | (pdram_timing->tckehcs << 8) | pdram_timing->tckelcs); mmio_clrsetbits_32(CTL_REG(i, 60), 0xffff, pdram_timing->txsnr); mmio_clrsetbits_32(CTL_REG(i, 62), 0xffffu << 16, (pdram_timing->tckehcmd << 24) | (pdram_timing->tckelcmd << 16)); mmio_write_32(CTL_REG(i, 63), (pdram_timing->tckelpd << 24) | (pdram_timing->tescke << 16) | (pdram_timing->tsr << 8) | pdram_timing->tckckel); mmio_clrsetbits_32(CTL_REG(i, 64), 0xfff, (pdram_timing->tcmdcke << 8) | pdram_timing->tcsckeh); mmio_clrsetbits_32(CTL_REG(i, 92), 0xffff << 8, (pdram_timing->tcksrx << 16) | (pdram_timing->tcksre << 8)); mmio_clrsetbits_32(CTL_REG(i, 108), 0x1 << 24, (timing_config->dllbp << 24)); mmio_clrsetbits_32(CTL_REG(i, 122), 0x3ff << 16, (pdram_timing->tvrcg_enable << 16)); mmio_write_32(CTL_REG(i, 123), (pdram_timing->tfc_long << 16) | pdram_timing->tvrcg_disable); mmio_write_32(CTL_REG(i, 124), (pdram_timing->tvref_long << 16) | (pdram_timing->tckfspx << 8) | pdram_timing->tckfspe); mmio_write_32(CTL_REG(i, 133), (pdram_timing->mr[1] << 16) | pdram_timing->mr[0]); mmio_clrsetbits_32(CTL_REG(i, 134), 0xffff, pdram_timing->mr[2]); mmio_clrsetbits_32(CTL_REG(i, 138), 0xffff, pdram_timing->mr[3]); mmio_clrsetbits_32(CTL_REG(i, 139), 0xffu << 24, pdram_timing->mr11 << 24); mmio_write_32(CTL_REG(i, 147), (pdram_timing->mr[1] << 16) | pdram_timing->mr[0]); mmio_clrsetbits_32(CTL_REG(i, 148), 0xffff, pdram_timing->mr[2]); mmio_clrsetbits_32(CTL_REG(i, 152), 0xffff, pdram_timing->mr[3]); mmio_clrsetbits_32(CTL_REG(i, 153), 0xffu << 24, pdram_timing->mr11 << 24); if (timing_config->dram_type == LPDDR4) { mmio_clrsetbits_32(CTL_REG(i, 140), 0xffffu << 16, pdram_timing->mr12 << 16); mmio_clrsetbits_32(CTL_REG(i, 142), 0xffffu << 16, pdram_timing->mr14 << 16); mmio_clrsetbits_32(CTL_REG(i, 145), 0xffffu << 16, pdram_timing->mr22 << 16); mmio_clrsetbits_32(CTL_REG(i, 154), 0xffffu << 16, pdram_timing->mr12 << 16); mmio_clrsetbits_32(CTL_REG(i, 156), 0xffffu << 16, pdram_timing->mr14 << 16); mmio_clrsetbits_32(CTL_REG(i, 159), 0xffffu << 16, pdram_timing->mr22 << 16); } mmio_clrsetbits_32(CTL_REG(i, 179), 0xfff << 8, pdram_timing->tzqinit << 8); mmio_write_32(CTL_REG(i, 180), (pdram_timing->tzqcs << 16) | (pdram_timing->tzqinit / 2)); mmio_write_32(CTL_REG(i, 181), (pdram_timing->tzqlat << 16) | pdram_timing->tzqcal); mmio_clrsetbits_32(CTL_REG(i, 212), 0xff << 8, pdram_timing->todton << 8); if (timing_config->odt) { mmio_setbits_32(CTL_REG(i, 213), 1 << 16); if (timing_config->freq < 400) tmp = 4 << 24; else tmp = 8 << 24; } else { mmio_clrbits_32(CTL_REG(i, 213), 1 << 16); tmp = 2 << 24; } mmio_clrsetbits_32(CTL_REG(i, 216), 0x1f << 24, tmp); mmio_clrsetbits_32(CTL_REG(i, 221), (0x3 << 16) | (0xf << 8), (pdram_timing->tdqsck << 16) | (pdram_timing->tdqsck_max << 8)); tmp = (get_wrlat_adj(timing_config->dram_type, pdram_timing->cwl) << 8) | get_rdlat_adj(timing_config->dram_type, pdram_timing->cl); mmio_clrsetbits_32(CTL_REG(i, 284), 0xffff, tmp); mmio_clrsetbits_32(CTL_REG(i, 82), 0xffffu << 16, (4 * pdram_timing->trefi) << 16); mmio_clrsetbits_32(CTL_REG(i, 83), 0xffff, (2 * pdram_timing->trefi) & 0xffff); if ((timing_config->dram_type == LPDDR3) || (timing_config->dram_type == LPDDR4)) { tmp = get_pi_wrlat(pdram_timing, timing_config); tmp1 = get_pi_todtoff_max(pdram_timing, timing_config); tmp = (tmp > tmp1) ? (tmp - tmp1) : 0; } else { tmp = 0; } mmio_clrsetbits_32(CTL_REG(i, 214), 0x3f << 16, (tmp & 0x3f) << 16); if ((timing_config->dram_type == LPDDR3) || (timing_config->dram_type == LPDDR4)) { /* min_rl_preamble = cl+TDQSCK_MIN -1 */ tmp = pdram_timing->cl + get_pi_todtoff_min(pdram_timing, timing_config) - 1; /* todtoff_max */ tmp1 = get_pi_todtoff_max(pdram_timing, timing_config); tmp = (tmp > tmp1) ? (tmp - tmp1) : 0; } else { tmp = pdram_timing->cl - pdram_timing->cwl; } mmio_clrsetbits_32(CTL_REG(i, 215), 0x3f << 8, (tmp & 0x3f) << 8); mmio_clrsetbits_32(CTL_REG(i, 275), 0xff << 16, (get_pi_tdfi_phy_rdlat(pdram_timing, timing_config) & 0xff) << 16); mmio_clrsetbits_32(CTL_REG(i, 277), 0xffff, (2 * pdram_timing->trefi) & 0xffff); mmio_clrsetbits_32(CTL_REG(i, 282), 0xffff, (2 * pdram_timing->trefi) & 0xffff); mmio_write_32(CTL_REG(i, 283), 20 * pdram_timing->trefi); /* CTL_308 TDFI_CALVL_CAPTURE_F0:RW:16:10 */ tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1; if ((20000 % (1000000 / pdram_timing->mhz)) != 0) tmp1++; tmp = (tmp1 >> 1) + (tmp1 % 2) + 5; mmio_clrsetbits_32(CTL_REG(i, 308), 0x3ff << 16, tmp << 16); /* CTL_308 TDFI_CALVL_CC_F0:RW:0:10 */ tmp = tmp + 18; mmio_clrsetbits_32(CTL_REG(i, 308), 0x3ff, tmp); /* CTL_314 TDFI_WRCSLAT_F0:RW:8:8 */ tmp1 = get_pi_wrlat_adj(pdram_timing, timing_config); if (timing_config->freq <= TDFI_LAT_THRESHOLD_FREQ) { if (tmp1 == 0) tmp = 0; else if (tmp1 < 5) tmp = tmp1 - 1; else tmp = tmp1 - 5; } else { tmp = tmp1 - 2; } mmio_clrsetbits_32(CTL_REG(i, 314), 0xff << 8, tmp << 8); /* CTL_314 TDFI_RDCSLAT_F0:RW:0:8 */ if ((timing_config->freq <= TDFI_LAT_THRESHOLD_FREQ) && (pdram_timing->cl >= 5)) tmp = pdram_timing->cl - 5; else tmp = pdram_timing->cl - 2; mmio_clrsetbits_32(CTL_REG(i, 314), 0xff, tmp); } } static void gen_rk3399_ctl_params_f1(struct timing_related_config *timing_config, struct dram_timing_t *pdram_timing) { uint32_t i; uint32_t tmp, tmp1; for (i = 0; i < timing_config->ch_cnt; i++) { if (timing_config->dram_type == DDR3) { tmp = ((700000 + 10) * timing_config->freq + 999) / 1000; tmp += pdram_timing->txsnr + (pdram_timing->tmrd * 3) + pdram_timing->tmod + pdram_timing->tzqinit; mmio_write_32(CTL_REG(i, 9), tmp); mmio_clrsetbits_32(CTL_REG(i, 22), 0xffffu << 16, pdram_timing->tdllk << 16); mmio_clrsetbits_32(CTL_REG(i, 34), 0xffffff00, (pdram_timing->tmod << 24) | (pdram_timing->tmrd << 16) | (pdram_timing->trtp << 8)); mmio_clrsetbits_32(CTL_REG(i, 60), 0xffffu << 16, (pdram_timing->txsr - pdram_timing->trcd) << 16); } else if (timing_config->dram_type == LPDDR4) { mmio_write_32(CTL_REG(i, 9), pdram_timing->tinit1 + pdram_timing->tinit3); mmio_clrsetbits_32(CTL_REG(i, 34), 0xffffff00, (pdram_timing->tmrd << 24) | (pdram_timing->tmrd << 16) | (pdram_timing->trtp << 8)); mmio_clrsetbits_32(CTL_REG(i, 60), 0xffffu << 16, pdram_timing->txsr << 16); } else { mmio_write_32(CTL_REG(i, 9), pdram_timing->tinit1); mmio_write_32(CTL_REG(i, 11), pdram_timing->tinit4); mmio_clrsetbits_32(CTL_REG(i, 34), 0xffffff00, (pdram_timing->tmrd << 24) | (pdram_timing->tmrd << 16) | (pdram_timing->trtp << 8)); mmio_clrsetbits_32(CTL_REG(i, 60), 0xffffu << 16, pdram_timing->txsr << 16); } mmio_write_32(CTL_REG(i, 10), pdram_timing->tinit3); mmio_write_32(CTL_REG(i, 12), pdram_timing->tinit5); mmio_clrsetbits_32(CTL_REG(i, 24), (0x7f << 8), ((pdram_timing->cl * 2) << 8)); mmio_clrsetbits_32(CTL_REG(i, 24), (0x1f << 16), (pdram_timing->cwl << 16)); mmio_clrsetbits_32(CTL_REG(i, 24), 0x3f << 24, pdram_timing->al << 24); mmio_clrsetbits_32(CTL_REG(i, 28), 0xffffff00, (pdram_timing->tras_min << 24) | (pdram_timing->trc << 16) | (pdram_timing->trrd << 8)); mmio_clrsetbits_32(CTL_REG(i, 29), 0xffffff, (pdram_timing->tfaw << 16) | (pdram_timing->trppb << 8) | pdram_timing->twtr); mmio_write_32(CTL_REG(i, 35), (pdram_timing->tcke << 24) | pdram_timing->tras_max); mmio_clrsetbits_32(CTL_REG(i, 36), 0xff, max(1, pdram_timing->tckesr)); mmio_clrsetbits_32(CTL_REG(i, 39), (0xffu << 24), (pdram_timing->trcd << 24)); mmio_clrsetbits_32(CTL_REG(i, 40), 0x3f, pdram_timing->twr); mmio_clrsetbits_32(CTL_REG(i, 42), 0x1f << 24, pdram_timing->tmrz << 24); tmp = pdram_timing->tdal ? pdram_timing->tdal : (pdram_timing->twr + pdram_timing->trp); mmio_clrsetbits_32(CTL_REG(i, 44), 0xff << 8, tmp << 8); mmio_clrsetbits_32(CTL_REG(i, 45), 0xff << 8, pdram_timing->trp << 8); mmio_write_32(CTL_REG(i, 49), ((pdram_timing->trefi - 8) << 16) | pdram_timing->trfc); mmio_clrsetbits_32(CTL_REG(i, 52), 0xffffu << 16, pdram_timing->txp << 16); mmio_clrsetbits_32(CTL_REG(i, 54), 0xffff, pdram_timing->txpdll); mmio_clrsetbits_32(CTL_REG(i, 55), 0xff << 8, pdram_timing->tmrri << 8); mmio_write_32(CTL_REG(i, 57), (pdram_timing->tmrwckel << 24) | (pdram_timing->tckehcs << 16) | (pdram_timing->tckelcs << 8) | pdram_timing->tcscke); mmio_clrsetbits_32(CTL_REG(i, 58), 0xf, pdram_timing->tzqcke); mmio_clrsetbits_32(CTL_REG(i, 61), 0xffff, pdram_timing->txsnr); mmio_clrsetbits_32(CTL_REG(i, 64), 0xffffu << 16, (pdram_timing->tckehcmd << 24) | (pdram_timing->tckelcmd << 16)); mmio_write_32(CTL_REG(i, 65), (pdram_timing->tckelpd << 24) | (pdram_timing->tescke << 16) | (pdram_timing->tsr << 8) | pdram_timing->tckckel); mmio_clrsetbits_32(CTL_REG(i, 66), 0xfff, (pdram_timing->tcmdcke << 8) | pdram_timing->tcsckeh); mmio_clrsetbits_32(CTL_REG(i, 92), (0xffu << 24), (pdram_timing->tcksre << 24)); mmio_clrsetbits_32(CTL_REG(i, 93), 0xff, pdram_timing->tcksrx); mmio_clrsetbits_32(CTL_REG(i, 108), (0x1 << 25), (timing_config->dllbp << 25)); mmio_write_32(CTL_REG(i, 125), (pdram_timing->tvrcg_disable << 16) | pdram_timing->tvrcg_enable); mmio_write_32(CTL_REG(i, 126), (pdram_timing->tckfspx << 24) | (pdram_timing->tckfspe << 16) | pdram_timing->tfc_long); mmio_clrsetbits_32(CTL_REG(i, 127), 0xffff, pdram_timing->tvref_long); mmio_clrsetbits_32(CTL_REG(i, 134), 0xffffu << 16, pdram_timing->mr[0] << 16); mmio_write_32(CTL_REG(i, 135), (pdram_timing->mr[2] << 16) | pdram_timing->mr[1]); mmio_clrsetbits_32(CTL_REG(i, 138), 0xffffu << 16, pdram_timing->mr[3] << 16); mmio_clrsetbits_32(CTL_REG(i, 140), 0xff, pdram_timing->mr11); mmio_clrsetbits_32(CTL_REG(i, 148), 0xffffu << 16, pdram_timing->mr[0] << 16); mmio_write_32(CTL_REG(i, 149), (pdram_timing->mr[2] << 16) | pdram_timing->mr[1]); mmio_clrsetbits_32(CTL_REG(i, 152), 0xffffu << 16, pdram_timing->mr[3] << 16); mmio_clrsetbits_32(CTL_REG(i, 154), 0xff, pdram_timing->mr11); if (timing_config->dram_type == LPDDR4) { mmio_clrsetbits_32(CTL_REG(i, 141), 0xffff, pdram_timing->mr12); mmio_clrsetbits_32(CTL_REG(i, 143), 0xffff, pdram_timing->mr14); mmio_clrsetbits_32(CTL_REG(i, 146), 0xffff, pdram_timing->mr22); mmio_clrsetbits_32(CTL_REG(i, 155), 0xffff, pdram_timing->mr12); mmio_clrsetbits_32(CTL_REG(i, 157), 0xffff, pdram_timing->mr14); mmio_clrsetbits_32(CTL_REG(i, 160), 0xffff, pdram_timing->mr22); } mmio_write_32(CTL_REG(i, 182), ((pdram_timing->tzqinit / 2) << 16) | pdram_timing->tzqinit); mmio_write_32(CTL_REG(i, 183), (pdram_timing->tzqcal << 16) | pdram_timing->tzqcs); mmio_clrsetbits_32(CTL_REG(i, 184), 0x3f, pdram_timing->tzqlat); mmio_clrsetbits_32(CTL_REG(i, 188), 0xfff, pdram_timing->tzqreset); mmio_clrsetbits_32(CTL_REG(i, 212), 0xff << 16, pdram_timing->todton << 16); if (timing_config->odt) { mmio_setbits_32(CTL_REG(i, 213), (1 << 24)); if (timing_config->freq < 400) tmp = 4 << 24; else tmp = 8 << 24; } else { mmio_clrbits_32(CTL_REG(i, 213), (1 << 24)); tmp = 2 << 24; } mmio_clrsetbits_32(CTL_REG(i, 217), 0x1f << 24, tmp); mmio_clrsetbits_32(CTL_REG(i, 221), 0xf << 24, (pdram_timing->tdqsck_max << 24)); mmio_clrsetbits_32(CTL_REG(i, 222), 0x3, pdram_timing->tdqsck); mmio_clrsetbits_32(CTL_REG(i, 291), 0xffff, (get_wrlat_adj(timing_config->dram_type, pdram_timing->cwl) << 8) | get_rdlat_adj(timing_config->dram_type, pdram_timing->cl)); mmio_clrsetbits_32(CTL_REG(i, 84), 0xffff, (4 * pdram_timing->trefi) & 0xffff); mmio_clrsetbits_32(CTL_REG(i, 84), 0xffffu << 16, ((2 * pdram_timing->trefi) & 0xffff) << 16); if ((timing_config->dram_type == LPDDR3) || (timing_config->dram_type == LPDDR4)) { tmp = get_pi_wrlat(pdram_timing, timing_config); tmp1 = get_pi_todtoff_max(pdram_timing, timing_config); tmp = (tmp > tmp1) ? (tmp - tmp1) : 0; } else { tmp = 0; } mmio_clrsetbits_32(CTL_REG(i, 214), 0x3f << 24, (tmp & 0x3f) << 24); if ((timing_config->dram_type == LPDDR3) || (timing_config->dram_type == LPDDR4)) { /* min_rl_preamble = cl + TDQSCK_MIN - 1 */ tmp = pdram_timing->cl + get_pi_todtoff_min(pdram_timing, timing_config); tmp--; /* todtoff_max */ tmp1 = get_pi_todtoff_max(pdram_timing, timing_config); tmp = (tmp > tmp1) ? (tmp - tmp1) : 0; } else { tmp = pdram_timing->cl - pdram_timing->cwl; } mmio_clrsetbits_32(CTL_REG(i, 215), 0x3f << 16, (tmp & 0x3f) << 16); mmio_clrsetbits_32(CTL_REG(i, 275), 0xffu << 24, (get_pi_tdfi_phy_rdlat(pdram_timing, timing_config) & 0xff) << 24); mmio_clrsetbits_32(CTL_REG(i, 284), 0xffffu << 16, ((2 * pdram_timing->trefi) & 0xffff) << 16); mmio_clrsetbits_32(CTL_REG(i, 289), 0xffff, (2 * pdram_timing->trefi) & 0xffff); mmio_write_32(CTL_REG(i, 290), 20 * pdram_timing->trefi); /* CTL_309 TDFI_CALVL_CAPTURE_F1:RW:16:10 */ tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1; if ((20000 % (1000000 / pdram_timing->mhz)) != 0) tmp1++; tmp = (tmp1 >> 1) + (tmp1 % 2) + 5; mmio_clrsetbits_32(CTL_REG(i, 309), 0x3ff << 16, tmp << 16); /* CTL_309 TDFI_CALVL_CC_F1:RW:0:10 */ tmp = tmp + 18; mmio_clrsetbits_32(CTL_REG(i, 309), 0x3ff, tmp); /* CTL_314 TDFI_WRCSLAT_F1:RW:24:8 */ tmp1 = get_pi_wrlat_adj(pdram_timing, timing_config); if (timing_config->freq <= TDFI_LAT_THRESHOLD_FREQ) { if (tmp1 == 0) tmp = 0; else if (tmp1 < 5) tmp = tmp1 - 1; else tmp = tmp1 - 5; } else { tmp = tmp1 - 2; } mmio_clrsetbits_32(CTL_REG(i, 314), 0xffu << 24, tmp << 24); /* CTL_314 TDFI_RDCSLAT_F1:RW:16:8 */ if ((timing_config->freq <= TDFI_LAT_THRESHOLD_FREQ) && (pdram_timing->cl >= 5)) tmp = pdram_timing->cl - 5; else tmp = pdram_timing->cl - 2; mmio_clrsetbits_32(CTL_REG(i, 314), 0xff << 16, tmp << 16); } } static void gen_rk3399_enable_training(uint32_t ch_cnt, uint32_t nmhz) { uint32_t i, tmp; if (nmhz <= PHY_DLL_BYPASS_FREQ) tmp = 0; else tmp = 1; for (i = 0; i < ch_cnt; i++) { mmio_clrsetbits_32(CTL_REG(i, 305), 1 << 16, tmp << 16); mmio_clrsetbits_32(CTL_REG(i, 71), 1, tmp); mmio_clrsetbits_32(CTL_REG(i, 70), 1 << 8, 1 << 8); } } static void gen_rk3399_disable_training(uint32_t ch_cnt) { uint32_t i; for (i = 0; i < ch_cnt; i++) { mmio_clrbits_32(CTL_REG(i, 305), 1 << 16); mmio_clrbits_32(CTL_REG(i, 71), 1); mmio_clrbits_32(CTL_REG(i, 70), 1 << 8); } } static void gen_rk3399_ctl_params(struct timing_related_config *timing_config, struct dram_timing_t *pdram_timing, uint32_t fn) { if (fn == 0) gen_rk3399_ctl_params_f0(timing_config, pdram_timing); else gen_rk3399_ctl_params_f1(timing_config, pdram_timing); } static void gen_rk3399_pi_params_f0(struct timing_related_config *timing_config, struct dram_timing_t *pdram_timing) { uint32_t tmp, tmp1, tmp2; uint32_t i; for (i = 0; i < timing_config->ch_cnt; i++) { /* PI_02 PI_TDFI_PHYMSTR_MAX_F0:RW:0:32 */ tmp = 4 * pdram_timing->trefi; mmio_write_32(PI_REG(i, 2), tmp); /* PI_03 PI_TDFI_PHYMSTR_RESP_F0:RW:0:16 */ tmp = 2 * pdram_timing->trefi; mmio_clrsetbits_32(PI_REG(i, 3), 0xffff, tmp); /* PI_07 PI_TDFI_PHYUPD_RESP_F0:RW:16:16 */ mmio_clrsetbits_32(PI_REG(i, 7), 0xffffu << 16, tmp << 16); /* PI_42 PI_TDELAY_RDWR_2_BUS_IDLE_F0:RW:0:8 */ if (timing_config->dram_type == LPDDR4) tmp = 2; else tmp = 0; tmp = (pdram_timing->bl / 2) + 4 + (get_pi_rdlat_adj(pdram_timing) - 2) + tmp + get_pi_tdfi_phy_rdlat(pdram_timing, timing_config); mmio_clrsetbits_32(PI_REG(i, 42), 0xff, tmp); /* PI_43 PI_WRLAT_F0:RW:0:5 */ if (timing_config->dram_type == LPDDR3) { tmp = get_pi_wrlat(pdram_timing, timing_config); mmio_clrsetbits_32(PI_REG(i, 43), 0x1f, tmp); } /* PI_43 PI_ADDITIVE_LAT_F0:RW:8:6 */ mmio_clrsetbits_32(PI_REG(i, 43), 0x3f << 8, PI_ADD_LATENCY << 8); /* PI_43 PI_CASLAT_LIN_F0:RW:16:7 */ mmio_clrsetbits_32(PI_REG(i, 43), 0x7f << 16, (pdram_timing->cl * 2) << 16); /* PI_46 PI_TREF_F0:RW:16:16 */ mmio_clrsetbits_32(PI_REG(i, 46), 0xffffu << 16, pdram_timing->trefi << 16); /* PI_46 PI_TRFC_F0:RW:0:10 */ mmio_clrsetbits_32(PI_REG(i, 46), 0x3ff, pdram_timing->trfc); /* PI_66 PI_TODTL_2CMD_F0:RW:24:8 */ if (timing_config->dram_type == LPDDR3) { tmp = get_pi_todtoff_max(pdram_timing, timing_config); mmio_clrsetbits_32(PI_REG(i, 66), 0xffu << 24, tmp << 24); } /* PI_72 PI_WR_TO_ODTH_F0:RW:16:6 */ if ((timing_config->dram_type == LPDDR3) || (timing_config->dram_type == LPDDR4)) { tmp1 = get_pi_wrlat(pdram_timing, timing_config); tmp2 = get_pi_todtoff_max(pdram_timing, timing_config); if (tmp1 > tmp2) tmp = tmp1 - tmp2; else tmp = 0; } else if (timing_config->dram_type == DDR3) { tmp = 0; } mmio_clrsetbits_32(PI_REG(i, 72), 0x3f << 16, tmp << 16); /* PI_73 PI_RD_TO_ODTH_F0:RW:8:6 */ if ((timing_config->dram_type == LPDDR3) || (timing_config->dram_type == LPDDR4)) { /* min_rl_preamble = cl + TDQSCK_MIN - 1 */ tmp1 = pdram_timing->cl; tmp1 += get_pi_todtoff_min(pdram_timing, timing_config); tmp1--; /* todtoff_max */ tmp2 = get_pi_todtoff_max(pdram_timing, timing_config); if (tmp1 > tmp2) tmp = tmp1 - tmp2; else tmp = 0; } else if (timing_config->dram_type == DDR3) { tmp = pdram_timing->cl - pdram_timing->cwl; } mmio_clrsetbits_32(PI_REG(i, 73), 0x3f << 8, tmp << 8); /* PI_89 PI_RDLAT_ADJ_F0:RW:16:8 */ tmp = get_pi_rdlat_adj(pdram_timing); mmio_clrsetbits_32(PI_REG(i, 89), 0xff << 16, tmp << 16); /* PI_90 PI_WRLAT_ADJ_F0:RW:16:8 */ tmp = get_pi_wrlat_adj(pdram_timing, timing_config); mmio_clrsetbits_32(PI_REG(i, 90), 0xff << 16, tmp << 16); /* PI_91 PI_TDFI_WRCSLAT_F0:RW:16:8 */ tmp1 = tmp; if (tmp1 == 0) tmp = 0; else if (tmp1 < 5) tmp = tmp1 - 1; else tmp = tmp1 - 5; mmio_clrsetbits_32(PI_REG(i, 91), 0xff << 16, tmp << 16); /* PI_95 PI_TDFI_CALVL_CAPTURE_F0:RW:16:10 */ tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1; if ((20000 % (1000000 / pdram_timing->mhz)) != 0) tmp1++; tmp = (tmp1 >> 1) + (tmp1 % 2) + 5; mmio_clrsetbits_32(PI_REG(i, 95), 0x3ff << 16, tmp << 16); /* PI_95 PI_TDFI_CALVL_CC_F0:RW:0:10 */ mmio_clrsetbits_32(PI_REG(i, 95), 0x3ff, tmp + 18); /* PI_102 PI_TMRZ_F0:RW:8:5 */ mmio_clrsetbits_32(PI_REG(i, 102), 0x1f << 8, pdram_timing->tmrz << 8); /* PI_111 PI_TDFI_CALVL_STROBE_F0:RW:8:4 */ tmp1 = 2 * 1000 / (1000000 / pdram_timing->mhz); if ((2 * 1000 % (1000000 / pdram_timing->mhz)) != 0) tmp1++; /* pi_tdfi_calvl_strobe=tds_train+5 */ tmp = tmp1 + 5; mmio_clrsetbits_32(PI_REG(i, 111), 0xf << 8, tmp << 8); /* PI_116 PI_TCKEHDQS_F0:RW:16:6 */ tmp = 10000 / (1000000 / pdram_timing->mhz); if ((10000 % (1000000 / pdram_timing->mhz)) != 0) tmp++; if (pdram_timing->mhz <= 100) tmp = tmp + 1; else tmp = tmp + 8; mmio_clrsetbits_32(PI_REG(i, 116), 0x3f << 16, tmp << 16); /* PI_125 PI_MR1_DATA_F0_0:RW+:8:16 */ mmio_clrsetbits_32(PI_REG(i, 125), 0xffff << 8, pdram_timing->mr[1] << 8); /* PI_133 PI_MR1_DATA_F0_1:RW+:0:16 */ mmio_clrsetbits_32(PI_REG(i, 133), 0xffff, pdram_timing->mr[1]); /* PI_140 PI_MR1_DATA_F0_2:RW+:16:16 */ mmio_clrsetbits_32(PI_REG(i, 140), 0xffffu << 16, pdram_timing->mr[1] << 16); /* PI_148 PI_MR1_DATA_F0_3:RW+:0:16 */ mmio_clrsetbits_32(PI_REG(i, 148), 0xffff, pdram_timing->mr[1]); /* PI_126 PI_MR2_DATA_F0_0:RW+:0:16 */ mmio_clrsetbits_32(PI_REG(i, 126), 0xffff, pdram_timing->mr[2]); /* PI_133 PI_MR2_DATA_F0_1:RW+:16:16 */ mmio_clrsetbits_32(PI_REG(i, 133), 0xffffu << 16, pdram_timing->mr[2] << 16); /* PI_141 PI_MR2_DATA_F0_2:RW+:0:16 */ mmio_clrsetbits_32(PI_REG(i, 141), 0xffff, pdram_timing->mr[2]); /* PI_148 PI_MR2_DATA_F0_3:RW+:16:16 */ mmio_clrsetbits_32(PI_REG(i, 148), 0xffffu << 16, pdram_timing->mr[2] << 16); /* PI_156 PI_TFC_F0:RW:0:10 */ mmio_clrsetbits_32(PI_REG(i, 156), 0x3ff, pdram_timing->tfc_long); /* PI_158 PI_TWR_F0:RW:24:6 */ mmio_clrsetbits_32(PI_REG(i, 158), 0x3f << 24, pdram_timing->twr << 24); /* PI_158 PI_TWTR_F0:RW:16:6 */ mmio_clrsetbits_32(PI_REG(i, 158), 0x3f << 16, pdram_timing->twtr << 16); /* PI_158 PI_TRCD_F0:RW:8:8 */ mmio_clrsetbits_32(PI_REG(i, 158), 0xff << 8, pdram_timing->trcd << 8); /* PI_158 PI_TRP_F0:RW:0:8 */ mmio_clrsetbits_32(PI_REG(i, 158), 0xff, pdram_timing->trp); /* PI_157 PI_TRTP_F0:RW:24:8 */ mmio_clrsetbits_32(PI_REG(i, 157), 0xffu << 24, pdram_timing->trtp << 24); /* PI_159 PI_TRAS_MIN_F0:RW:24:8 */ mmio_clrsetbits_32(PI_REG(i, 159), 0xffu << 24, pdram_timing->tras_min << 24); /* PI_159 PI_TRAS_MAX_F0:RW:0:17 */ tmp = pdram_timing->tras_max * 99 / 100; mmio_clrsetbits_32(PI_REG(i, 159), 0x1ffff, tmp); /* PI_160 PI_TMRD_F0:RW:16:6 */ mmio_clrsetbits_32(PI_REG(i, 160), 0x3f << 16, pdram_timing->tmrd << 16); /*PI_160 PI_TDQSCK_MAX_F0:RW:0:4 */ mmio_clrsetbits_32(PI_REG(i, 160), 0xf, pdram_timing->tdqsck_max); /* PI_187 PI_TDFI_CTRLUPD_MAX_F0:RW:8:16 */ mmio_clrsetbits_32(PI_REG(i, 187), 0xffff << 8, (2 * pdram_timing->trefi) << 8); /* PI_188 PI_TDFI_CTRLUPD_INTERVAL_F0:RW:0:32 */ mmio_clrsetbits_32(PI_REG(i, 188), 0xffffffff, 20 * pdram_timing->trefi); } } static void gen_rk3399_pi_params_f1(struct timing_related_config *timing_config, struct dram_timing_t *pdram_timing) { uint32_t tmp, tmp1, tmp2; uint32_t i; for (i = 0; i < timing_config->ch_cnt; i++) { /* PI_04 PI_TDFI_PHYMSTR_MAX_F1:RW:0:32 */ tmp = 4 * pdram_timing->trefi; mmio_write_32(PI_REG(i, 4), tmp); /* PI_05 PI_TDFI_PHYMSTR_RESP_F1:RW:0:16 */ tmp = 2 * pdram_timing->trefi; mmio_clrsetbits_32(PI_REG(i, 5), 0xffff, tmp); /* PI_12 PI_TDFI_PHYUPD_RESP_F1:RW:0:16 */ mmio_clrsetbits_32(PI_REG(i, 12), 0xffff, tmp); /* PI_42 PI_TDELAY_RDWR_2_BUS_IDLE_F1:RW:8:8 */ if (timing_config->dram_type == LPDDR4) tmp = 2; else tmp = 0; tmp = (pdram_timing->bl / 2) + 4 + (get_pi_rdlat_adj(pdram_timing) - 2) + tmp + get_pi_tdfi_phy_rdlat(pdram_timing, timing_config); mmio_clrsetbits_32(PI_REG(i, 42), 0xff << 8, tmp << 8); /* PI_43 PI_WRLAT_F1:RW:24:5 */ if (timing_config->dram_type == LPDDR3) { tmp = get_pi_wrlat(pdram_timing, timing_config); mmio_clrsetbits_32(PI_REG(i, 43), 0x1f << 24, tmp << 24); } /* PI_44 PI_ADDITIVE_LAT_F1:RW:0:6 */ mmio_clrsetbits_32(PI_REG(i, 44), 0x3f, PI_ADD_LATENCY); /* PI_44 PI_CASLAT_LIN_F1:RW:8:7:=0x18 */ mmio_clrsetbits_32(PI_REG(i, 44), 0x7f << 8, (pdram_timing->cl * 2) << 8); /* PI_47 PI_TREF_F1:RW:16:16 */ mmio_clrsetbits_32(PI_REG(i, 47), 0xffffu << 16, pdram_timing->trefi << 16); /* PI_47 PI_TRFC_F1:RW:0:10 */ mmio_clrsetbits_32(PI_REG(i, 47), 0x3ff, pdram_timing->trfc); /* PI_67 PI_TODTL_2CMD_F1:RW:8:8 */ if (timing_config->dram_type == LPDDR3) { tmp = get_pi_todtoff_max(pdram_timing, timing_config); mmio_clrsetbits_32(PI_REG(i, 67), 0xff << 8, tmp << 8); } /* PI_72 PI_WR_TO_ODTH_F1:RW:24:6 */ if ((timing_config->dram_type == LPDDR3) || (timing_config->dram_type == LPDDR4)) { tmp1 = get_pi_wrlat(pdram_timing, timing_config); tmp2 = get_pi_todtoff_max(pdram_timing, timing_config); if (tmp1 > tmp2) tmp = tmp1 - tmp2; else tmp = 0; } else if (timing_config->dram_type == DDR3) { tmp = 0; } mmio_clrsetbits_32(PI_REG(i, 72), 0x3f << 24, tmp << 24); /* PI_73 PI_RD_TO_ODTH_F1:RW:16:6 */ if ((timing_config->dram_type == LPDDR3) || (timing_config->dram_type == LPDDR4)) { /* min_rl_preamble = cl + TDQSCK_MIN - 1 */ tmp1 = pdram_timing->cl + get_pi_todtoff_min(pdram_timing, timing_config); tmp1--; /* todtoff_max */ tmp2 = get_pi_todtoff_max(pdram_timing, timing_config); if (tmp1 > tmp2) tmp = tmp1 - tmp2; else tmp = 0; } else if (timing_config->dram_type == DDR3) tmp = pdram_timing->cl - pdram_timing->cwl; mmio_clrsetbits_32(PI_REG(i, 73), 0x3f << 16, tmp << 16); /*P I_89 PI_RDLAT_ADJ_F1:RW:24:8 */ tmp = get_pi_rdlat_adj(pdram_timing); mmio_clrsetbits_32(PI_REG(i, 89), 0xffu << 24, tmp << 24); /* PI_90 PI_WRLAT_ADJ_F1:RW:24:8 */ tmp = get_pi_wrlat_adj(pdram_timing, timing_config); mmio_clrsetbits_32(PI_REG(i, 90), 0xffu << 24, tmp << 24); /* PI_91 PI_TDFI_WRCSLAT_F1:RW:24:8 */ tmp1 = tmp; if (tmp1 == 0) tmp = 0; else if (tmp1 < 5) tmp = tmp1 - 1; else tmp = tmp1 - 5; mmio_clrsetbits_32(PI_REG(i, 91), 0xffu << 24, tmp << 24); /*PI_96 PI_TDFI_CALVL_CAPTURE_F1:RW:16:10 */ /* tadr=20ns */ tmp1 = 20000 / (1000000 / pdram_timing->mhz) + 1; if ((20000 % (1000000 / pdram_timing->mhz)) != 0) tmp1++; tmp = (tmp1 >> 1) + (tmp1 % 2) + 5; mmio_clrsetbits_32(PI_REG(i, 96), 0x3ff << 16, tmp << 16); /* PI_96 PI_TDFI_CALVL_CC_F1:RW:0:10 */ tmp = tmp + 18; mmio_clrsetbits_32(PI_REG(i, 96), 0x3ff, tmp); /*PI_103 PI_TMRZ_F1:RW:0:5 */ mmio_clrsetbits_32(PI_REG(i, 103), 0x1f, pdram_timing->tmrz); /*PI_111 PI_TDFI_CALVL_STROBE_F1:RW:16:4 */ /* tds_train=ceil(2/ns) */ tmp1 = 2 * 1000 / (1000000 / pdram_timing->mhz); if ((2 * 1000 % (1000000 / pdram_timing->mhz)) != 0) tmp1++; /* pi_tdfi_calvl_strobe=tds_train+5 */ tmp = tmp1 + 5; mmio_clrsetbits_32(PI_REG(i, 111), 0xf << 16, tmp << 16); /* PI_116 PI_TCKEHDQS_F1:RW:24:6 */ tmp = 10000 / (1000000 / pdram_timing->mhz); if ((10000 % (1000000 / pdram_timing->mhz)) != 0) tmp++; if (pdram_timing->mhz <= 100) tmp = tmp + 1; else tmp = tmp + 8; mmio_clrsetbits_32(PI_REG(i, 116), 0x3f << 24, tmp << 24); /* PI_128 PI_MR1_DATA_F1_0:RW+:0:16 */ mmio_clrsetbits_32(PI_REG(i, 128), 0xffff, pdram_timing->mr[1]); /* PI_135 PI_MR1_DATA_F1_1:RW+:8:16 */ mmio_clrsetbits_32(PI_REG(i, 135), 0xffff << 8, pdram_timing->mr[1] << 8); /* PI_143 PI_MR1_DATA_F1_2:RW+:0:16 */ mmio_clrsetbits_32(PI_REG(i, 143), 0xffff, pdram_timing->mr[1]); /* PI_150 PI_MR1_DATA_F1_3:RW+:8:16 */ mmio_clrsetbits_32(PI_REG(i, 150), 0xffff << 8, pdram_timing->mr[1] << 8); /* PI_128 PI_MR2_DATA_F1_0:RW+:16:16 */ mmio_clrsetbits_32(PI_REG(i, 128), 0xffffu << 16, pdram_timing->mr[2] << 16); /* PI_136 PI_MR2_DATA_F1_1:RW+:0:16 */ mmio_clrsetbits_32(PI_REG(i, 136), 0xffff, pdram_timing->mr[2]); /* PI_143 PI_MR2_DATA_F1_2:RW+:16:16 */ mmio_clrsetbits_32(PI_REG(i, 143), 0xffffu << 16, pdram_timing->mr[2] << 16); /* PI_151 PI_MR2_DATA_F1_3:RW+:0:16 */ mmio_clrsetbits_32(PI_REG(i, 151), 0xffff, pdram_timing->mr[2]); /* PI_156 PI_TFC_F1:RW:16:10 */ mmio_clrsetbits_32(PI_REG(i, 156), 0x3ff << 16, pdram_timing->tfc_long << 16); /* PI_162 PI_TWR_F1:RW:8:6 */ mmio_clrsetbits_32(PI_REG(i, 162), 0x3f << 8, pdram_timing->twr << 8); /* PI_162 PI_TWTR_F1:RW:0:6 */ mmio_clrsetbits_32(PI_REG(i, 162), 0x3f, pdram_timing->twtr); /* PI_161 PI_TRCD_F1:RW:24:8 */ mmio_clrsetbits_32(PI_REG(i, 161), 0xffu << 24, pdram_timing->trcd << 24); /* PI_161 PI_TRP_F1:RW:16:8 */ mmio_clrsetbits_32(PI_REG(i, 161), 0xff << 16, pdram_timing->trp << 16); /* PI_161 PI_TRTP_F1:RW:8:8 */ mmio_clrsetbits_32(PI_REG(i, 161), 0xff << 8, pdram_timing->trtp << 8); /* PI_163 PI_TRAS_MIN_F1:RW:24:8 */ mmio_clrsetbits_32(PI_REG(i, 163), 0xffu << 24, pdram_timing->tras_min << 24); /* PI_163 PI_TRAS_MAX_F1:RW:0:17 */ mmio_clrsetbits_32(PI_REG(i, 163), 0x1ffff, pdram_timing->tras_max * 99 / 100); /* PI_164 PI_TMRD_F1:RW:16:6 */ mmio_clrsetbits_32(PI_REG(i, 164), 0x3f << 16, pdram_timing->tmrd << 16); /* PI_164 PI_TDQSCK_MAX_F1:RW:0:4 */ mmio_clrsetbits_32(PI_REG(i, 164), 0xf, pdram_timing->tdqsck_max); /* PI_189 PI_TDFI_CTRLUPD_MAX_F1:RW:0:16 */ mmio_clrsetbits_32(PI_REG(i, 189), 0xffff, 2 * pdram_timing->trefi); /* PI_190 PI_TDFI_CTRLUPD_INTERVAL_F1:RW:0:32 */ mmio_clrsetbits_32(PI_REG(i, 190), 0xffffffff, 20 * pdram_timing->trefi); } } static void gen_rk3399_pi_params(struct timing_related_config *timing_config, struct dram_timing_t *pdram_timing, uint32_t fn) { if (fn == 0) gen_rk3399_pi_params_f0(timing_config, pdram_timing); else gen_rk3399_pi_params_f1(timing_config, pdram_timing); } static void gen_rk3399_set_odt(uint32_t odt_en) { uint32_t drv_odt_val; uint32_t i; for (i = 0; i < rk3399_dram_status.timing_config.ch_cnt; i++) { drv_odt_val = (odt_en | (0 << 1) | (0 << 2)) << 16; mmio_clrsetbits_32(PHY_REG(i, 5), 0x7 << 16, drv_odt_val); mmio_clrsetbits_32(PHY_REG(i, 133), 0x7 << 16, drv_odt_val); mmio_clrsetbits_32(PHY_REG(i, 261), 0x7 << 16, drv_odt_val); mmio_clrsetbits_32(PHY_REG(i, 389), 0x7 << 16, drv_odt_val); drv_odt_val = (odt_en | (0 << 1) | (0 << 2)) << 24; mmio_clrsetbits_32(PHY_REG(i, 6), 0x7 << 24, drv_odt_val); mmio_clrsetbits_32(PHY_REG(i, 134), 0x7 << 24, drv_odt_val); mmio_clrsetbits_32(PHY_REG(i, 262), 0x7 << 24, drv_odt_val); mmio_clrsetbits_32(PHY_REG(i, 390), 0x7 << 24, drv_odt_val); } } static void gen_rk3399_phy_dll_bypass(uint32_t mhz, uint32_t ch, uint32_t index, uint32_t dram_type) { uint32_t sw_master_mode = 0; uint32_t rddqs_gate_delay, rddqs_latency, total_delay; uint32_t i; if (dram_type == DDR3) total_delay = PI_PAD_DELAY_PS_VALUE; else if (dram_type == LPDDR3) total_delay = PI_PAD_DELAY_PS_VALUE + 2500; else total_delay = PI_PAD_DELAY_PS_VALUE + 1500; /* total_delay + 0.55tck */ total_delay += (55 * 10000)/mhz; rddqs_latency = total_delay * mhz / 1000000; total_delay -= rddqs_latency * 1000000 / mhz; rddqs_gate_delay = total_delay * 0x200 * mhz / 1000000; if (mhz <= PHY_DLL_BYPASS_FREQ) { sw_master_mode = 0xc; mmio_setbits_32(PHY_REG(ch, 514), 1); mmio_setbits_32(PHY_REG(ch, 642), 1); mmio_setbits_32(PHY_REG(ch, 770), 1); /* setting bypass mode slave delay */ for (i = 0; i < 4; i++) { /* wr dq delay = -180deg + (0x60 / 4) * 20ps */ mmio_clrsetbits_32(PHY_REG(ch, 1 + 128 * i), 0x7ff << 8, 0x4a0 << 8); /* rd dqs/dq delay = (0x60 / 4) * 20ps */ mmio_clrsetbits_32(PHY_REG(ch, 11 + 128 * i), 0x3ff, 0xa0); /* rd rddqs_gate delay */ mmio_clrsetbits_32(PHY_REG(ch, 2 + 128 * i), 0x3ff, rddqs_gate_delay); mmio_clrsetbits_32(PHY_REG(ch, 78 + 128 * i), 0xf, rddqs_latency); } for (i = 0; i < 3; i++) /* adr delay */ mmio_clrsetbits_32(PHY_REG(ch, 513 + 128 * i), 0x7ff << 16, 0x80 << 16); if ((mmio_read_32(PHY_REG(ch, 86)) & 0xc00) == 0) { /* * old status is normal mode, * and saving the wrdqs slave delay */ for (i = 0; i < 4; i++) { /* save and clear wr dqs slave delay */ wrdqs_delay_val[ch][index][i] = 0x3ff & (mmio_read_32(PHY_REG(ch, 63 + i * 128)) >> 16); mmio_clrsetbits_32(PHY_REG(ch, 63 + i * 128), 0x03ff << 16, 0 << 16); /* * in normal mode the cmd may delay 1cycle by * wrlvl and in bypass mode making dqs also * delay 1cycle. */ mmio_clrsetbits_32(PHY_REG(ch, 78 + i * 128), 0x07 << 8, 0x1 << 8); } } } else if (mmio_read_32(PHY_REG(ch, 86)) & 0xc00) { /* old status is bypass mode and restore wrlvl resume */ for (i = 0; i < 4; i++) { mmio_clrsetbits_32(PHY_REG(ch, 63 + i * 128), 0x03ff << 16, (wrdqs_delay_val[ch][index][i] & 0x3ff) << 16); /* resume phy_write_path_lat_add */ mmio_clrbits_32(PHY_REG(ch, 78 + i * 128), 0x07 << 8); } } /* phy_sw_master_mode_X PHY_86/214/342/470 4bits offset_8 */ mmio_clrsetbits_32(PHY_REG(ch, 86), 0xf << 8, sw_master_mode << 8); mmio_clrsetbits_32(PHY_REG(ch, 214), 0xf << 8, sw_master_mode << 8); mmio_clrsetbits_32(PHY_REG(ch, 342), 0xf << 8, sw_master_mode << 8); mmio_clrsetbits_32(PHY_REG(ch, 470), 0xf << 8, sw_master_mode << 8); /* phy_adrctl_sw_master_mode PHY_547/675/803 4bits offset_16 */ mmio_clrsetbits_32(PHY_REG(ch, 547), 0xf << 16, sw_master_mode << 16); mmio_clrsetbits_32(PHY_REG(ch, 675), 0xf << 16, sw_master_mode << 16); mmio_clrsetbits_32(PHY_REG(ch, 803), 0xf << 16, sw_master_mode << 16); } static void gen_rk3399_phy_params(struct timing_related_config *timing_config, struct drv_odt_lp_config *drv_config, struct dram_timing_t *pdram_timing, uint32_t fn) { uint32_t tmp, i, div, j; uint32_t mem_delay_ps, pad_delay_ps, total_delay_ps, delay_frac_ps; uint32_t trpre_min_ps, gate_delay_ps, gate_delay_frac_ps; uint32_t ie_enable, tsel_enable, cas_lat, rddata_en_ie_dly, tsel_adder; uint32_t extra_adder, delta, hs_offset; for (i = 0; i < timing_config->ch_cnt; i++) { pad_delay_ps = PI_PAD_DELAY_PS_VALUE; ie_enable = PI_IE_ENABLE_VALUE; tsel_enable = PI_TSEL_ENABLE_VALUE; mmio_clrsetbits_32(PHY_REG(i, 896), (0x3 << 8) | 1, fn << 8); /* PHY_LOW_FREQ_SEL */ /* DENALI_PHY_913 1bit offset_0 */ if (timing_config->freq > 400) mmio_clrbits_32(PHY_REG(i, 913), 1); else mmio_setbits_32(PHY_REG(i, 913), 1); /* PHY_RPTR_UPDATE_x */ /* DENALI_PHY_87/215/343/471 4bit offset_16 */ tmp = 2500 / (1000000 / pdram_timing->mhz) + 3; if ((2500 % (1000000 / pdram_timing->mhz)) != 0) tmp++; mmio_clrsetbits_32(PHY_REG(i, 87), 0xf << 16, tmp << 16); mmio_clrsetbits_32(PHY_REG(i, 215), 0xf << 16, tmp << 16); mmio_clrsetbits_32(PHY_REG(i, 343), 0xf << 16, tmp << 16); mmio_clrsetbits_32(PHY_REG(i, 471), 0xf << 16, tmp << 16); /* PHY_PLL_CTRL */ /* DENALI_PHY_911 13bits offset_0 */ /* PHY_LP4_BOOT_PLL_CTRL */ /* DENALI_PHY_919 13bits offset_0 */ tmp = (1 << 12) | (2 << 7) | (1 << 1); mmio_clrsetbits_32(PHY_REG(i, 911), 0x1fff, tmp); mmio_clrsetbits_32(PHY_REG(i, 919), 0x1fff, tmp); /* PHY_PLL_CTRL_CA */ /* DENALI_PHY_911 13bits offset_16 */ /* PHY_LP4_BOOT_PLL_CTRL_CA */ /* DENALI_PHY_919 13bits offset_16 */ tmp = (2 << 7) | (1 << 5) | (1 << 1); mmio_clrsetbits_32(PHY_REG(i, 911), 0x1fff << 16, tmp << 16); mmio_clrsetbits_32(PHY_REG(i, 919), 0x1fff << 16, tmp << 16); /* PHY_TCKSRE_WAIT */ /* DENALI_PHY_922 4bits offset_24 */ if (pdram_timing->mhz <= 400) tmp = 1; else if (pdram_timing->mhz <= 800) tmp = 3; else if (pdram_timing->mhz <= 1000) tmp = 4; else tmp = 5; mmio_clrsetbits_32(PHY_REG(i, 922), 0xf << 24, tmp << 24); /* PHY_CAL_CLK_SELECT_0:RW8:3 */ div = pdram_timing->mhz / (2 * 20); for (j = 2, tmp = 1; j <= 128; j <<= 1, tmp++) { if (div < j) break; } mmio_clrsetbits_32(PHY_REG(i, 947), 0x7 << 8, tmp << 8); if (timing_config->dram_type == DDR3) { mem_delay_ps = 0; trpre_min_ps = 1000; } else if (timing_config->dram_type == LPDDR4) { mem_delay_ps = 1500; trpre_min_ps = 900; } else if (timing_config->dram_type == LPDDR3) { mem_delay_ps = 2500; trpre_min_ps = 900; } else { ERROR("gen_rk3399_phy_params:dramtype unsupport\n"); return; } total_delay_ps = mem_delay_ps + pad_delay_ps; delay_frac_ps = 1000 * total_delay_ps / (1000000 / pdram_timing->mhz); gate_delay_ps = delay_frac_ps + 1000 - (trpre_min_ps / 2); gate_delay_frac_ps = gate_delay_ps % 1000; tmp = gate_delay_frac_ps * 0x200 / 1000; /* PHY_RDDQS_GATE_SLAVE_DELAY */ /* DENALI_PHY_77/205/333/461 10bits offset_16 */ mmio_clrsetbits_32(PHY_REG(i, 77), 0x2ff << 16, tmp << 16); mmio_clrsetbits_32(PHY_REG(i, 205), 0x2ff << 16, tmp << 16); mmio_clrsetbits_32(PHY_REG(i, 333), 0x2ff << 16, tmp << 16); mmio_clrsetbits_32(PHY_REG(i, 461), 0x2ff << 16, tmp << 16); tmp = gate_delay_ps / 1000; /* PHY_LP4_BOOT_RDDQS_LATENCY_ADJUST */ /* DENALI_PHY_10/138/266/394 4bit offset_0 */ mmio_clrsetbits_32(PHY_REG(i, 10), 0xf, tmp); mmio_clrsetbits_32(PHY_REG(i, 138), 0xf, tmp); mmio_clrsetbits_32(PHY_REG(i, 266), 0xf, tmp); mmio_clrsetbits_32(PHY_REG(i, 394), 0xf, tmp); /* PHY_GTLVL_LAT_ADJ_START */ /* DENALI_PHY_80/208/336/464 4bits offset_16 */ tmp = rddqs_delay_ps / (1000000 / pdram_timing->mhz) + 2; mmio_clrsetbits_32(PHY_REG(i, 80), 0xf << 16, tmp << 16); mmio_clrsetbits_32(PHY_REG(i, 208), 0xf << 16, tmp << 16); mmio_clrsetbits_32(PHY_REG(i, 336), 0xf << 16, tmp << 16); mmio_clrsetbits_32(PHY_REG(i, 464), 0xf << 16, tmp << 16); cas_lat = pdram_timing->cl + PI_ADD_LATENCY; rddata_en_ie_dly = ie_enable / (1000000 / pdram_timing->mhz); if ((ie_enable % (1000000 / pdram_timing->mhz)) != 0) rddata_en_ie_dly++; rddata_en_ie_dly = rddata_en_ie_dly - 1; tsel_adder = tsel_enable / (1000000 / pdram_timing->mhz); if ((tsel_enable % (1000000 / pdram_timing->mhz)) != 0) tsel_adder++; if (rddata_en_ie_dly > tsel_adder) extra_adder = rddata_en_ie_dly - tsel_adder; else extra_adder = 0; delta = cas_lat - rddata_en_ie_dly; if (PI_REGS_DIMM_SUPPORT && PI_DOUBLEFREEK) hs_offset = 2; else hs_offset = 1; if (rddata_en_ie_dly > (cas_lat - 1 - hs_offset)) tmp = 0; else if ((delta == 2) || (delta == 1)) tmp = rddata_en_ie_dly - 0 - extra_adder; else tmp = extra_adder; /* PHY_LP4_BOOT_RDDATA_EN_TSEL_DLY */ /* DENALI_PHY_9/137/265/393 4bit offset_16 */ mmio_clrsetbits_32(PHY_REG(i, 9), 0xf << 16, tmp << 16); mmio_clrsetbits_32(PHY_REG(i, 137), 0xf << 16, tmp << 16); mmio_clrsetbits_32(PHY_REG(i, 265), 0xf << 16, tmp << 16); mmio_clrsetbits_32(PHY_REG(i, 393), 0xf << 16, tmp << 16); /* PHY_RDDATA_EN_TSEL_DLY */ /* DENALI_PHY_86/214/342/470 4bit offset_0 */ mmio_clrsetbits_32(PHY_REG(i, 86), 0xf, tmp); mmio_clrsetbits_32(PHY_REG(i, 214), 0xf, tmp); mmio_clrsetbits_32(PHY_REG(i, 342), 0xf, tmp); mmio_clrsetbits_32(PHY_REG(i, 470), 0xf, tmp); if (tsel_adder > rddata_en_ie_dly) extra_adder = tsel_adder - rddata_en_ie_dly; else extra_adder = 0; if (rddata_en_ie_dly > (cas_lat - 1 - hs_offset)) tmp = tsel_adder; else tmp = rddata_en_ie_dly - 0 + extra_adder; /* PHY_LP4_BOOT_RDDATA_EN_DLY */ /* DENALI_PHY_9/137/265/393 4bit offset_8 */ mmio_clrsetbits_32(PHY_REG(i, 9), 0xf << 8, tmp << 8); mmio_clrsetbits_32(PHY_REG(i, 137), 0xf << 8, tmp << 8); mmio_clrsetbits_32(PHY_REG(i, 265), 0xf << 8, tmp << 8); mmio_clrsetbits_32(PHY_REG(i, 393), 0xf << 8, tmp << 8); /* PHY_RDDATA_EN_DLY */ /* DENALI_PHY_85/213/341/469 4bit offset_24 */ mmio_clrsetbits_32(PHY_REG(i, 85), 0xf << 24, tmp << 24); mmio_clrsetbits_32(PHY_REG(i, 213), 0xf << 24, tmp << 24); mmio_clrsetbits_32(PHY_REG(i, 341), 0xf << 24, tmp << 24); mmio_clrsetbits_32(PHY_REG(i, 469), 0xf << 24, tmp << 24); if (pdram_timing->mhz <= ENPER_CS_TRAINING_FREQ) { /* * Note:Per-CS Training is not compatible at speeds * under 533 MHz. If the PHY is running at a speed * less than 533MHz, all phy_per_cs_training_en_X * parameters must be cleared to 0. */ /*DENALI_PHY_84/212/340/468 1bit offset_16 */ mmio_clrbits_32(PHY_REG(i, 84), 0x1 << 16); mmio_clrbits_32(PHY_REG(i, 212), 0x1 << 16); mmio_clrbits_32(PHY_REG(i, 340), 0x1 << 16); mmio_clrbits_32(PHY_REG(i, 468), 0x1 << 16); } else { mmio_setbits_32(PHY_REG(i, 84), 0x1 << 16); mmio_setbits_32(PHY_REG(i, 212), 0x1 << 16); mmio_setbits_32(PHY_REG(i, 340), 0x1 << 16); mmio_setbits_32(PHY_REG(i, 468), 0x1 << 16); } gen_rk3399_phy_dll_bypass(pdram_timing->mhz, i, fn, timing_config->dram_type); } } static int to_get_clk_index(unsigned int mhz) { int pll_cnt, i; pll_cnt = ARRAY_SIZE(dpll_rates_table); /* Assumming rate_table is in descending order */ for (i = 0; i < pll_cnt; i++) { if (mhz >= dpll_rates_table[i].mhz) break; } /* if mhz lower than lowest frequency in table, use lowest frequency */ if (i == pll_cnt) i = pll_cnt - 1; return i; } uint32_t ddr_get_rate(void) { uint32_t refdiv, postdiv1, fbdiv, postdiv2; refdiv = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) & 0x3f; fbdiv = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 0)) & 0xfff; postdiv1 = (mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) >> 8) & 0x7; postdiv2 = (mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, 1)) >> 12) & 0x7; return (24 / refdiv * fbdiv / postdiv1 / postdiv2) * 1000 * 1000; } /* * return: bit12: channel 1, external self-refresh * bit11: channel 1, stdby_mode * bit10: channel 1, self-refresh with controller and memory clock gate * bit9: channel 1, self-refresh * bit8: channel 1, power-down * * bit4: channel 1, external self-refresh * bit3: channel 0, stdby_mode * bit2: channel 0, self-refresh with controller and memory clock gate * bit1: channel 0, self-refresh * bit0: channel 0, power-down */ uint32_t exit_low_power(void) { uint32_t low_power = 0; uint32_t channel_mask; uint32_t tmp, i; channel_mask = (mmio_read_32(PMUGRF_BASE + PMUGRF_OSREG(2)) >> 28) & 0x3; for (i = 0; i < 2; i++) { if (!(channel_mask & (1 << i))) continue; /* exit stdby mode */ mmio_write_32(CIC_BASE + CIC_CTRL1, (1 << (i + 16)) | (0 << i)); /* exit external self-refresh */ tmp = i ? 12 : 8; low_power |= ((mmio_read_32(PMU_BASE + PMU_SFT_CON) >> tmp) & 0x1) << (4 + 8 * i); mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, 1 << tmp); while (!(mmio_read_32(PMU_BASE + PMU_DDR_SREF_ST) & (1 << i))) ; /* exit auto low-power */ mmio_clrbits_32(CTL_REG(i, 101), 0x7); /* lp_cmd to exit */ if (((mmio_read_32(CTL_REG(i, 100)) >> 24) & 0x7f) != 0x40) { while (mmio_read_32(CTL_REG(i, 200)) & 0x1) ; mmio_clrsetbits_32(CTL_REG(i, 93), 0xffu << 24, 0x69 << 24); while (((mmio_read_32(CTL_REG(i, 100)) >> 24) & 0x7f) != 0x40) ; } } return low_power; } void resume_low_power(uint32_t low_power) { uint32_t channel_mask; uint32_t tmp, i, val; channel_mask = (mmio_read_32(PMUGRF_BASE + PMUGRF_OSREG(2)) >> 28) & 0x3; for (i = 0; i < 2; i++) { if (!(channel_mask & (1 << i))) continue; /* resume external self-refresh */ tmp = i ? 12 : 8; val = (low_power >> (4 + 8 * i)) & 0x1; mmio_setbits_32(PMU_BASE + PMU_SFT_CON, val << tmp); /* resume auto low-power */ val = (low_power >> (8 * i)) & 0x7; mmio_setbits_32(CTL_REG(i, 101), val); /* resume stdby mode */ val = (low_power >> (3 + 8 * i)) & 0x1; mmio_write_32(CIC_BASE + CIC_CTRL1, (1 << (i + 16)) | (val << i)); } } static void dram_low_power_config(void) { uint32_t tmp, i; uint32_t ch_cnt = rk3399_dram_status.timing_config.ch_cnt; uint32_t dram_type = rk3399_dram_status.timing_config.dram_type; if (dram_type == DDR3) tmp = (2 << 16) | (0x7 << 8); else tmp = (3 << 16) | (0x7 << 8); for (i = 0; i < ch_cnt; i++) mmio_clrsetbits_32(CTL_REG(i, 101), 0x70f0f, tmp); /* standby idle */ mmio_write_32(CIC_BASE + CIC_CG_WAIT_TH, 0x640008); if (ch_cnt == 2) { mmio_write_32(GRF_BASE + GRF_DDRC1_CON1, (((0x1<<4) | (0x1<<5) | (0x1<<6) | (0x1<<7)) << 16) | ((0x1<<4) | (0x0<<5) | (0x1<<6) | (0x1<<7))); mmio_write_32(CIC_BASE + CIC_CTRL1, 0x002a0028); } mmio_write_32(GRF_BASE + GRF_DDRC0_CON1, (((0x1<<4) | (0x1<<5) | (0x1<<6) | (0x1<<7)) << 16) | ((0x1<<4) | (0x0<<5) | (0x1<<6) | (0x1<<7))); mmio_write_32(CIC_BASE + CIC_CTRL1, 0x00150014); } void dram_dfs_init(void) { uint32_t trefi0, trefi1, boot_freq; uint32_t rddqs_adjust, rddqs_slave; /* get sdram config for os reg */ get_dram_drv_odt_val(sdram_config.dramtype, &rk3399_dram_status.drv_odt_lp_cfg); sdram_timing_cfg_init(&rk3399_dram_status.timing_config, &sdram_config, &rk3399_dram_status.drv_odt_lp_cfg); trefi0 = ((mmio_read_32(CTL_REG(0, 48)) >> 16) & 0xffff) + 8; trefi1 = ((mmio_read_32(CTL_REG(0, 49)) >> 16) & 0xffff) + 8; rk3399_dram_status.index_freq[0] = trefi0 * 10 / 39; rk3399_dram_status.index_freq[1] = trefi1 * 10 / 39; rk3399_dram_status.current_index = (mmio_read_32(CTL_REG(0, 111)) >> 16) & 0x3; if (rk3399_dram_status.timing_config.dram_type == DDR3) { rk3399_dram_status.index_freq[0] /= 2; rk3399_dram_status.index_freq[1] /= 2; } boot_freq = rk3399_dram_status.index_freq[rk3399_dram_status.current_index]; boot_freq = dpll_rates_table[to_get_clk_index(boot_freq)].mhz; rk3399_dram_status.boot_freq = boot_freq; rk3399_dram_status.index_freq[rk3399_dram_status.current_index] = boot_freq; rk3399_dram_status.index_freq[(rk3399_dram_status.current_index + 1) & 0x1] = 0; rk3399_dram_status.low_power_stat = 0; /* * following register decide if NOC stall the access request * or return error when NOC being idled. when doing ddr frequency * scaling in M0 or DCF, we need to make sure noc stall the access * request, if return error cpu may data abort when ddr frequency * changing. it don't need to set this register every times, * so we init this register in function dram_dfs_init(). */ mmio_write_32(GRF_BASE + GRF_SOC_CON(0), 0xffffffff); mmio_write_32(GRF_BASE + GRF_SOC_CON(1), 0xffffffff); mmio_write_32(GRF_BASE + GRF_SOC_CON(2), 0xffffffff); mmio_write_32(GRF_BASE + GRF_SOC_CON(3), 0xffffffff); mmio_write_32(GRF_BASE + GRF_SOC_CON(4), 0x70007000); /* Disable multicast */ mmio_clrbits_32(PHY_REG(0, 896), 1); mmio_clrbits_32(PHY_REG(1, 896), 1); dram_low_power_config(); /* * If boot_freq isn't in the bypass mode, it can get the * rddqs_delay_ps from the result of gate training */ if (((mmio_read_32(PHY_REG(0, 86)) >> 8) & 0xf) != 0xc) { /* * Select PHY's frequency set to current_index * index for get the result of gate Training * from registers */ mmio_clrsetbits_32(PHY_REG(0, 896), 0x3 << 8, rk3399_dram_status.current_index << 8); rddqs_slave = (mmio_read_32(PHY_REG(0, 77)) >> 16) & 0x3ff; rddqs_slave = rddqs_slave * 1000000 / boot_freq / 512; rddqs_adjust = mmio_read_32(PHY_REG(0, 78)) & 0xf; rddqs_adjust = rddqs_adjust * 1000000 / boot_freq; rddqs_delay_ps = rddqs_slave + rddqs_adjust - (1000000 / boot_freq / 2); } else { rddqs_delay_ps = 3500; } } /* * arg0: bit0-7: sr_idle; bit8-15:sr_mc_gate_idle; bit16-31: standby idle * arg1: bit0-11: pd_idle; bit 16-27: srpd_lite_idle * arg2: bit0: if odt en */ uint32_t dram_set_odt_pd(uint32_t arg0, uint32_t arg1, uint32_t arg2) { struct drv_odt_lp_config *lp_cfg = &rk3399_dram_status.drv_odt_lp_cfg; uint32_t *low_power = &rk3399_dram_status.low_power_stat; uint32_t dram_type, ch_count, pd_tmp, sr_tmp, i; dram_type = rk3399_dram_status.timing_config.dram_type; ch_count = rk3399_dram_status.timing_config.ch_cnt; lp_cfg->sr_idle = arg0 & 0xff; lp_cfg->sr_mc_gate_idle = (arg0 >> 8) & 0xff; lp_cfg->standby_idle = (arg0 >> 16) & 0xffff; lp_cfg->pd_idle = arg1 & 0xfff; lp_cfg->srpd_lite_idle = (arg1 >> 16) & 0xfff; rk3399_dram_status.timing_config.odt = arg2 & 0x1; exit_low_power(); *low_power = 0; /* pd_idle en */ if (lp_cfg->pd_idle) *low_power |= ((1 << 0) | (1 << 8)); /* sr_idle en srpd_lite_idle */ if (lp_cfg->sr_idle | lp_cfg->srpd_lite_idle) *low_power |= ((1 << 1) | (1 << 9)); /* sr_mc_gate_idle */ if (lp_cfg->sr_mc_gate_idle) *low_power |= ((1 << 2) | (1 << 10)); /* standbyidle */ if (lp_cfg->standby_idle) { if (rk3399_dram_status.timing_config.ch_cnt == 2) *low_power |= ((1 << 3) | (1 << 11)); else *low_power |= (1 << 3); } pd_tmp = arg1; if (dram_type != LPDDR4) pd_tmp = arg1 & 0xfff; sr_tmp = arg0 & 0xffff; for (i = 0; i < ch_count; i++) { mmio_write_32(CTL_REG(i, 102), pd_tmp); mmio_clrsetbits_32(CTL_REG(i, 103), 0xffff, sr_tmp); } mmio_write_32(CIC_BASE + CIC_IDLE_TH, (arg0 >> 16) & 0xffff); return 0; } static void m0_configure_ddr(struct pll_div pll_div, uint32_t ddr_index) { mmio_write_32(M0_PARAM_ADDR + PARAM_DPLL_CON0, FBDIV(pll_div.fbdiv)); mmio_write_32(M0_PARAM_ADDR + PARAM_DPLL_CON1, POSTDIV2(pll_div.postdiv2) | POSTDIV1(pll_div.postdiv1) | REFDIV(pll_div.refdiv)); mmio_write_32(M0_PARAM_ADDR + PARAM_DRAM_FREQ, pll_div.mhz); mmio_write_32(M0_PARAM_ADDR + PARAM_FREQ_SELECT, ddr_index << 4); dmbst(); m0_configure_execute_addr(M0_BINCODE_BASE); } static uint32_t prepare_ddr_timing(uint32_t mhz) { uint32_t index; struct dram_timing_t dram_timing; rk3399_dram_status.timing_config.freq = mhz; if (mhz < 300) rk3399_dram_status.timing_config.dllbp = 1; else rk3399_dram_status.timing_config.dllbp = 0; if (rk3399_dram_status.timing_config.odt == 1) gen_rk3399_set_odt(1); index = (rk3399_dram_status.current_index + 1) & 0x1; /* * checking if having available gate traiing timing for * target freq. */ dram_get_parameter(&rk3399_dram_status.timing_config, &dram_timing); gen_rk3399_ctl_params(&rk3399_dram_status.timing_config, &dram_timing, index); gen_rk3399_pi_params(&rk3399_dram_status.timing_config, &dram_timing, index); gen_rk3399_phy_params(&rk3399_dram_status.timing_config, &rk3399_dram_status.drv_odt_lp_cfg, &dram_timing, index); rk3399_dram_status.index_freq[index] = mhz; return index; } uint32_t ddr_set_rate(uint32_t hz) { uint32_t low_power, index, ddr_index; uint32_t mhz = hz / (1000 * 1000); if (mhz == rk3399_dram_status.index_freq[rk3399_dram_status.current_index]) return mhz; index = to_get_clk_index(mhz); mhz = dpll_rates_table[index].mhz; ddr_index = prepare_ddr_timing(mhz); gen_rk3399_enable_training(rk3399_dram_status.timing_config.ch_cnt, mhz); if (ddr_index > 1) goto out; /* * Make sure the clock is enabled. The M0 clocks should be on all of the * time during S0. */ m0_configure_ddr(dpll_rates_table[index], ddr_index); m0_start(); m0_wait_done(); m0_stop(); if (rk3399_dram_status.timing_config.odt == 0) gen_rk3399_set_odt(0); rk3399_dram_status.current_index = ddr_index; low_power = rk3399_dram_status.low_power_stat; resume_low_power(low_power); out: gen_rk3399_disable_training(rk3399_dram_status.timing_config.ch_cnt); return mhz; } uint32_t ddr_round_rate(uint32_t hz) { int index; uint32_t mhz = hz / (1000 * 1000); index = to_get_clk_index(mhz); return dpll_rates_table[index].mhz * 1000 * 1000; } void ddr_prepare_for_sys_suspend(void) { uint32_t mhz = rk3399_dram_status.index_freq[rk3399_dram_status.current_index]; /* * If we're not currently at the boot (assumed highest) frequency, we * need to change frequencies to configure out current index. */ rk3399_suspend_status.freq = mhz; exit_low_power(); rk3399_suspend_status.low_power_stat = rk3399_dram_status.low_power_stat; rk3399_suspend_status.odt = rk3399_dram_status.timing_config.odt; rk3399_dram_status.low_power_stat = 0; rk3399_dram_status.timing_config.odt = 1; if (mhz != rk3399_dram_status.boot_freq) ddr_set_rate(rk3399_dram_status.boot_freq * 1000 * 1000); /* * This will configure the other index to be the same frequency as the * current one. We retrain both indices on resume, so both have to be * setup for the same frequency. */ prepare_ddr_timing(rk3399_dram_status.boot_freq); } void ddr_prepare_for_sys_resume(void) { /* Disable multicast */ mmio_clrbits_32(PHY_REG(0, 896), 1); mmio_clrbits_32(PHY_REG(1, 896), 1); /* The suspend code changes the current index, so reset it now. */ rk3399_dram_status.current_index = (mmio_read_32(CTL_REG(0, 111)) >> 16) & 0x3; rk3399_dram_status.low_power_stat = rk3399_suspend_status.low_power_stat; rk3399_dram_status.timing_config.odt = rk3399_suspend_status.odt; /* * Set the saved frequency from suspend if it's different than the * current frequency. */ if (rk3399_suspend_status.freq != rk3399_dram_status.index_freq[rk3399_dram_status.current_index]) { ddr_set_rate(rk3399_suspend_status.freq * 1000 * 1000); return; } gen_rk3399_set_odt(rk3399_dram_status.timing_config.odt); resume_low_power(rk3399_dram_status.low_power_stat); } trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/dram/dfs.h000066400000000000000000000021751355360272700241520ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef DFS_H #define DFS_H #include struct rk3399_sdram_default_config { unsigned char bl; /* 1:auto precharge, 0:never auto precharge */ unsigned char ap; /* dram driver strength */ unsigned char dramds; /* dram ODT, if odt=0, this parameter invalid */ unsigned char dramodt; /* ca ODT, if odt=0, this parameter invalid * only used by LPDDR4 */ unsigned char caodt; unsigned char burst_ref_cnt; /* zqcs period, unit(s) */ unsigned char zqcsi; }; struct drv_odt_lp_config { uint32_t pd_idle; uint32_t sr_idle; uint32_t sr_mc_gate_idle; uint32_t srpd_lite_idle; uint32_t standby_idle; uint32_t odt_en; uint32_t dram_side_drv; uint32_t dram_side_dq_odt; uint32_t dram_side_ca_odt; }; uint32_t ddr_set_rate(uint32_t hz); uint32_t ddr_round_rate(uint32_t hz); uint32_t ddr_get_rate(void); uint32_t dram_set_odt_pd(uint32_t arg0, uint32_t arg1, uint32_t arg2); void dram_dfs_init(void); void ddr_prepare_for_sys_suspend(void); void ddr_prepare_for_sys_resume(void); #endif /* DFS_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/dram/dram.c000066400000000000000000000032221355360272700243060ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include __pmusramdata struct rk3399_sdram_params sdram_config; void dram_init(void) { uint32_t os_reg2_val, i; os_reg2_val = mmio_read_32(PMUGRF_BASE + PMUGRF_OSREG(2)); sdram_config.dramtype = SYS_REG_DEC_DDRTYPE(os_reg2_val); sdram_config.num_channels = SYS_REG_DEC_NUM_CH(os_reg2_val); sdram_config.stride = (mmio_read_32(SGRF_BASE + SGRF_SOC_CON3_7(4)) >> 10) & 0x1f; for (i = 0; i < 2; i++) { struct rk3399_sdram_channel *ch = &sdram_config.ch[i]; struct rk3399_msch_timings *noc = &ch->noc_timings; if (!(SYS_REG_DEC_CHINFO(os_reg2_val, i))) continue; ch->rank = SYS_REG_DEC_RANK(os_reg2_val, i); ch->col = SYS_REG_DEC_COL(os_reg2_val, i); ch->bk = SYS_REG_DEC_BK(os_reg2_val, i); ch->bw = SYS_REG_DEC_BW(os_reg2_val, i); ch->dbw = SYS_REG_DEC_DBW(os_reg2_val, i); ch->row_3_4 = SYS_REG_DEC_ROW_3_4(os_reg2_val, i); ch->cs0_row = SYS_REG_DEC_CS0_ROW(os_reg2_val, i); ch->cs1_row = SYS_REG_DEC_CS1_ROW(os_reg2_val, i); ch->ddrconfig = mmio_read_32(MSCH_BASE(i) + MSCH_DEVICECONF); noc->ddrtiminga0.d32 = mmio_read_32(MSCH_BASE(i) + MSCH_DDRTIMINGA0); noc->ddrtimingb0.d32 = mmio_read_32(MSCH_BASE(i) + MSCH_DDRTIMINGB0); noc->ddrtimingc0.d32 = mmio_read_32(MSCH_BASE(i) + MSCH_DDRTIMINGC0); noc->devtodev0.d32 = mmio_read_32(MSCH_BASE(i) + MSCH_DEVTODEV0); noc->ddrmode.d32 = mmio_read_32(MSCH_BASE(i) + MSCH_DDRMODE); noc->agingx0 = mmio_read_32(MSCH_BASE(i) + MSCH_AGINGX0); } } trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/dram/dram.h000066400000000000000000000060721355360272700243210ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef DRAM_H #define DRAM_H #include #include #include enum { DDR3 = 3, LPDDR2 = 5, LPDDR3 = 6, LPDDR4 = 7, UNUSED = 0xff }; struct rk3399_ddr_pctl_regs { uint32_t denali_ctl[CTL_REG_NUM]; }; struct rk3399_ddr_publ_regs { /* * PHY registers from 0 to 90 for slice1. * These are used to restore slice1-4 on resume. */ uint32_t phy0[91]; /* * PHY registers from 512 to 895. * Only registers 0-37 of each 128 register range are used. */ uint32_t phy512[3][38]; uint32_t phy896[63]; }; struct rk3399_ddr_pi_regs { uint32_t denali_pi[PI_REG_NUM]; }; union noc_ddrtiminga0 { uint32_t d32; struct { unsigned acttoact : 6; unsigned reserved0 : 2; unsigned rdtomiss : 6; unsigned reserved1 : 2; unsigned wrtomiss : 6; unsigned reserved2 : 2; unsigned readlatency : 8; } b; }; union noc_ddrtimingb0 { uint32_t d32; struct { unsigned rdtowr : 5; unsigned reserved0 : 3; unsigned wrtord : 5; unsigned reserved1 : 3; unsigned rrd : 4; unsigned reserved2 : 4; unsigned faw : 6; unsigned reserved3 : 2; } b; }; union noc_ddrtimingc0 { uint32_t d32; struct { unsigned burstpenalty : 4; unsigned reserved0 : 4; unsigned wrtomwr : 6; unsigned reserved1 : 18; } b; }; union noc_devtodev0 { uint32_t d32; struct { unsigned busrdtord : 3; unsigned reserved0 : 1; unsigned busrdtowr : 3; unsigned reserved1 : 1; unsigned buswrtord : 3; unsigned reserved2 : 1; unsigned buswrtowr : 3; unsigned reserved3 : 17; } b; }; union noc_ddrmode { uint32_t d32; struct { unsigned autoprecharge : 1; unsigned bypassfiltering : 1; unsigned fawbank : 1; unsigned burstsize : 2; unsigned mwrsize : 2; unsigned reserved2 : 1; unsigned forceorder : 8; unsigned forceorderstate : 8; unsigned reserved3 : 8; } b; }; struct rk3399_msch_timings { union noc_ddrtiminga0 ddrtiminga0; union noc_ddrtimingb0 ddrtimingb0; union noc_ddrtimingc0 ddrtimingc0; union noc_devtodev0 devtodev0; union noc_ddrmode ddrmode; uint32_t agingx0; }; struct rk3399_sdram_channel { unsigned char rank; /* col = 0, means this channel is invalid */ unsigned char col; /* 3:8bank, 2:4bank */ unsigned char bk; /* channel buswidth, 2:32bit, 1:16bit, 0:8bit */ unsigned char bw; /* die buswidth, 2:32bit, 1:16bit, 0:8bit */ unsigned char dbw; /* row_3_4 = 1: 6Gb or 12Gb die * row_3_4 = 0: normal die, power of 2 */ unsigned char row_3_4; unsigned char cs0_row; unsigned char cs1_row; uint32_t ddrconfig; struct rk3399_msch_timings noc_timings; }; struct rk3399_sdram_params { struct rk3399_sdram_channel ch[2]; uint32_t ddr_freq; unsigned char dramtype; unsigned char num_channels; unsigned char stride; unsigned char odt; struct rk3399_ddr_pctl_regs pctl_regs; struct rk3399_ddr_pi_regs pi_regs; struct rk3399_ddr_publ_regs phy_regs; uint32_t rx_cal_dqs[2][4]; }; extern __sramdata struct rk3399_sdram_params sdram_config; void dram_init(void); #endif /* DRAM_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.c000066400000000000000000001223031355360272700266710ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "dram_spec_timing.h" static const uint8_t ddr3_cl_cwl[][7] = { /* * speed 0~330 331 ~ 400 401 ~ 533 534~666 667~800 801~933 934~1066 * tCK>3 2.5~3 1.875~2.5 1.5~1.875 1.25~1.5 1.07~1.25 0.938~1.07 * cl<<4, cwl cl<<4, cwl cl<<4, cwl */ /* DDR3_800D (5-5-5) */ {((5 << 4) | 5), ((5 << 4) | 5), 0, 0, 0, 0, 0}, /* DDR3_800E (6-6-6) */ {((5 << 4) | 5), ((6 << 4) | 5), 0, 0, 0, 0, 0}, /* DDR3_1066E (6-6-6) */ {((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), 0, 0, 0, 0}, /* DDR3_1066F (7-7-7) */ {((5 << 4) | 5), ((6 << 4) | 5), ((7 << 4) | 6), 0, 0, 0, 0}, /* DDR3_1066G (8-8-8) */ {((5 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), 0, 0, 0, 0}, /* DDR3_1333F (7-7-7) */ {((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((7 << 4) | 7), 0, 0, 0}, /* DDR3_1333G (8-8-8) */ {((5 << 4) | 5), ((5 << 4) | 5), ((7 << 4) | 6), ((8 << 4) | 7), 0, 0, 0}, /* DDR3_1333H (9-9-9) */ {((5 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), ((9 << 4) | 7), 0, 0, 0}, /* DDR3_1333J (10-10-10) */ {((5 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), ((10 << 4) | 7), 0, 0, 0}, /* DDR3_1600G (8-8-8) */ {((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((7 << 4) | 7), ((8 << 4) | 8), 0, 0}, /* DDR3_1600H (9-9-9) */ {((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((8 << 4) | 7), ((9 << 4) | 8), 0, 0}, /* DDR3_1600J (10-10-10) */ {((5 << 4) | 5), ((5 << 4) | 5), ((7 << 4) | 6), ((9 << 4) | 7), ((10 << 4) | 8), 0, 0}, /* DDR3_1600K (11-11-11) */ {((5 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), ((10 << 4) | 7), ((11 << 4) | 8), 0, 0}, /* DDR3_1866J (10-10-10) */ {((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((8 << 4) | 7), ((9 << 4) | 8), ((11 << 4) | 9), 0}, /* DDR3_1866K (11-11-11) */ {((5 << 4) | 5), ((5 << 4) | 5), ((7 << 4) | 6), ((8 << 4) | 7), ((10 << 4) | 8), ((11 << 4) | 9), 0}, /* DDR3_1866L (12-12-12) */ {((6 << 4) | 5), ((6 << 4) | 5), ((7 << 4) | 6), ((9 << 4) | 7), ((11 << 4) | 8), ((12 << 4) | 9), 0}, /* DDR3_1866M (13-13-13) */ {((6 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), ((10 << 4) | 7), ((11 << 4) | 8), ((13 << 4) | 9), 0}, /* DDR3_2133K (11-11-11) */ {((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((7 << 4) | 7), ((9 << 4) | 8), ((10 << 4) | 9), ((11 << 4) | 10)}, /* DDR3_2133L (12-12-12) */ {((5 << 4) | 5), ((5 << 4) | 5), ((6 << 4) | 6), ((8 << 4) | 7), ((9 << 4) | 8), ((11 << 4) | 9), ((12 << 4) | 10)}, /* DDR3_2133M (13-13-13) */ {((5 << 4) | 5), ((5 << 4) | 5), ((7 << 4) | 6), ((9 << 4) | 7), ((10 << 4) | 8), ((12 << 4) | 9), ((13 << 4) | 10)}, /* DDR3_2133N (14-14-14) */ {((6 << 4) | 5), ((6 << 4) | 5), ((7 << 4) | 6), ((9 << 4) | 7), ((11 << 4) | 8), ((13 << 4) | 9), ((14 << 4) | 10)}, /* DDR3_DEFAULT */ {((6 << 4) | 5), ((6 << 4) | 5), ((8 << 4) | 6), ((10 << 4) | 7), ((11 << 4) | 8), ((13 << 4) | 9), ((14 << 4) | 10)} }; static const uint16_t ddr3_trc_tfaw[] = { /* tRC tFAW */ ((50 << 8) | 50), /* DDR3_800D (5-5-5) */ ((53 << 8) | 50), /* DDR3_800E (6-6-6) */ ((49 << 8) | 50), /* DDR3_1066E (6-6-6) */ ((51 << 8) | 50), /* DDR3_1066F (7-7-7) */ ((53 << 8) | 50), /* DDR3_1066G (8-8-8) */ ((47 << 8) | 45), /* DDR3_1333F (7-7-7) */ ((48 << 8) | 45), /* DDR3_1333G (8-8-8) */ ((50 << 8) | 45), /* DDR3_1333H (9-9-9) */ ((51 << 8) | 45), /* DDR3_1333J (10-10-10) */ ((45 << 8) | 40), /* DDR3_1600G (8-8-8) */ ((47 << 8) | 40), /* DDR3_1600H (9-9-9)*/ ((48 << 8) | 40), /* DDR3_1600J (10-10-10) */ ((49 << 8) | 40), /* DDR3_1600K (11-11-11) */ ((45 << 8) | 35), /* DDR3_1866J (10-10-10) */ ((46 << 8) | 35), /* DDR3_1866K (11-11-11) */ ((47 << 8) | 35), /* DDR3_1866L (12-12-12) */ ((48 << 8) | 35), /* DDR3_1866M (13-13-13) */ ((44 << 8) | 35), /* DDR3_2133K (11-11-11) */ ((45 << 8) | 35), /* DDR3_2133L (12-12-12) */ ((46 << 8) | 35), /* DDR3_2133M (13-13-13) */ ((47 << 8) | 35), /* DDR3_2133N (14-14-14) */ ((53 << 8) | 50) /* DDR3_DEFAULT */ }; static uint32_t get_max_speed_rate(struct timing_related_config *timing_config) { if (timing_config->ch_cnt > 1) return max(timing_config->dram_info[0].speed_rate, timing_config->dram_info[1].speed_rate); else return timing_config->dram_info[0].speed_rate; } static uint32_t get_max_die_capability(struct timing_related_config *timing_config) { uint32_t die_cap = 0; uint32_t cs, ch; for (ch = 0; ch < timing_config->ch_cnt; ch++) { for (cs = 0; cs < timing_config->dram_info[ch].cs_cnt; cs++) { die_cap = max(die_cap, timing_config-> dram_info[ch].per_die_capability[cs]); } } return die_cap; } /* tRSTL, 100ns */ #define DDR3_TRSTL (100) /* trsth, 500us */ #define DDR3_TRSTH (500000) /* trefi, 7.8us */ #define DDR3_TREFI_7_8_US (7800) /* tWR, 15ns */ #define DDR3_TWR (15) /* tRTP, max(4 tCK,7.5ns) */ #define DDR3_TRTP (7) /* tRRD = max(4nCK, 10ns) */ #define DDR3_TRRD (10) /* tCK */ #define DDR3_TCCD (4) /*tWTR, max(4 tCK,7.5ns)*/ #define DDR3_TWTR (7) /* tCK */ #define DDR3_TRTW (0) /* tRAS, 37.5ns(400MHz) 37.5ns(533MHz) */ #define DDR3_TRAS (37) /* ns */ #define DDR3_TRFC_512MBIT (90) /* ns */ #define DDR3_TRFC_1GBIT (110) /* ns */ #define DDR3_TRFC_2GBIT (160) /* ns */ #define DDR3_TRFC_4GBIT (300) /* ns */ #define DDR3_TRFC_8GBIT (350) /*pd and sr*/ #define DDR3_TXP (7) /* tXP, max(3 tCK, 7.5ns)( < 933MHz) */ #define DDR3_TXPDLL (24) /* tXPDLL, max(10 tCK, 24ns) */ #define DDR3_TDLLK (512) /* tXSR, tDLLK=512 tCK */ #define DDR3_TCKE_400MHZ (7) /* tCKE, max(3 tCK,7.5ns)(400MHz) */ #define DDR3_TCKE_533MHZ (6) /* tCKE, max(3 tCK,5.625ns)(533MHz) */ #define DDR3_TCKSRE (10) /* tCKSRX, max(5 tCK, 10ns) */ /*mode register timing*/ #define DDR3_TMOD (15) /* tMOD, max(12 tCK,15ns) */ #define DDR3_TMRD (4) /* tMRD, 4 tCK */ /* ZQ */ #define DDR3_TZQINIT (640) /* tZQinit, max(512 tCK, 640ns) */ #define DDR3_TZQCS (80) /* tZQCS, max(64 tCK, 80ns) */ #define DDR3_TZQOPER (320) /* tZQoper, max(256 tCK, 320ns) */ /* Write leveling */ #define DDR3_TWLMRD (40) /* tCK */ #define DDR3_TWLO (9) /* max 7.5ns */ #define DDR3_TWLDQSEN (25) /* tCK */ /* * Description: depend on input parameter "timing_config", * and calculate all ddr3 * spec timing to "pdram_timing" * parameters: * input: timing_config * output: pdram_timing */ static void ddr3_get_parameter(struct timing_related_config *timing_config, struct dram_timing_t *pdram_timing) { uint32_t nmhz = timing_config->freq; uint32_t ddr_speed_bin = get_max_speed_rate(timing_config); uint32_t ddr_capability_per_die = get_max_die_capability(timing_config); uint32_t tmp; zeromem((void *)pdram_timing, sizeof(struct dram_timing_t)); pdram_timing->mhz = nmhz; pdram_timing->al = 0; pdram_timing->bl = timing_config->bl; if (nmhz <= 330) tmp = 0; else if (nmhz <= 400) tmp = 1; else if (nmhz <= 533) tmp = 2; else if (nmhz <= 666) tmp = 3; else if (nmhz <= 800) tmp = 4; else if (nmhz <= 933) tmp = 5; else tmp = 6; /* when dll bypss cl = cwl = 6 */ if (nmhz < 300) { pdram_timing->cl = 6; pdram_timing->cwl = 6; } else { pdram_timing->cl = (ddr3_cl_cwl[ddr_speed_bin][tmp] >> 4) & 0xf; pdram_timing->cwl = ddr3_cl_cwl[ddr_speed_bin][tmp] & 0xf; } switch (timing_config->dramds) { case 40: tmp = DDR3_DS_40; break; case 34: default: tmp = DDR3_DS_34; break; } if (timing_config->odt) switch (timing_config->dramodt) { case 60: pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_60; break; case 40: pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_40; break; case 120: pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_120; break; case 0: default: pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_DIS; break; } else pdram_timing->mr[1] = tmp | DDR3_RTT_NOM_DIS; pdram_timing->mr[2] = DDR3_MR2_CWL(pdram_timing->cwl); pdram_timing->mr[3] = 0; pdram_timing->trstl = ((DDR3_TRSTL * nmhz + 999) / 1000); pdram_timing->trsth = ((DDR3_TRSTH * nmhz + 999) / 1000); /* tREFI, average periodic refresh interval, 7.8us */ pdram_timing->trefi = ((DDR3_TREFI_7_8_US * nmhz + 999) / 1000); /* base timing */ pdram_timing->trcd = pdram_timing->cl; pdram_timing->trp = pdram_timing->cl; pdram_timing->trppb = pdram_timing->cl; tmp = ((DDR3_TWR * nmhz + 999) / 1000); pdram_timing->twr = tmp; pdram_timing->tdal = tmp + pdram_timing->trp; if (tmp < 9) { tmp = tmp - 4; } else { tmp += (tmp & 0x1) ? 1 : 0; tmp = tmp >> 1; } if (pdram_timing->bl == 4) pdram_timing->mr[0] = DDR3_BC4 | DDR3_CL(pdram_timing->cl) | DDR3_WR(tmp); else pdram_timing->mr[0] = DDR3_BL8 | DDR3_CL(pdram_timing->cl) | DDR3_WR(tmp); tmp = ((DDR3_TRTP * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->trtp = max(4, tmp); pdram_timing->trc = (((ddr3_trc_tfaw[ddr_speed_bin] >> 8) * nmhz + 999) / 1000); tmp = ((DDR3_TRRD * nmhz + 999) / 1000); pdram_timing->trrd = max(4, tmp); pdram_timing->tccd = DDR3_TCCD; tmp = ((DDR3_TWTR * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->twtr = max(4, tmp); pdram_timing->trtw = DDR3_TRTW; pdram_timing->tras_max = 9 * pdram_timing->trefi; pdram_timing->tras_min = ((DDR3_TRAS * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->tfaw = (((ddr3_trc_tfaw[ddr_speed_bin] & 0x0ff) * nmhz + 999) / 1000); /* tRFC, 90ns(512Mb),110ns(1Gb),160ns(2Gb),300ns(4Gb),350ns(8Gb) */ if (ddr_capability_per_die <= 0x4000000) tmp = DDR3_TRFC_512MBIT; else if (ddr_capability_per_die <= 0x8000000) tmp = DDR3_TRFC_1GBIT; else if (ddr_capability_per_die <= 0x10000000) tmp = DDR3_TRFC_2GBIT; else if (ddr_capability_per_die <= 0x20000000) tmp = DDR3_TRFC_4GBIT; else tmp = DDR3_TRFC_8GBIT; pdram_timing->trfc = (tmp * nmhz + 999) / 1000; pdram_timing->txsnr = max(5, (((tmp + 10) * nmhz + 999) / 1000)); pdram_timing->tdqsck_max = 0; /*pd and sr*/ pdram_timing->txsr = DDR3_TDLLK; tmp = ((DDR3_TXP * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->txp = max(3, tmp); tmp = ((DDR3_TXPDLL * nmhz + 999) / 1000); pdram_timing->txpdll = max(10, tmp); pdram_timing->tdllk = DDR3_TDLLK; if (nmhz >= 533) tmp = ((DDR3_TCKE_533MHZ * nmhz + 999) / 1000); else tmp = ((DDR3_TCKE_400MHZ * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->tcke = max(3, tmp); pdram_timing->tckesr = (pdram_timing->tcke + 1); tmp = ((DDR3_TCKSRE * nmhz + 999) / 1000); pdram_timing->tcksre = max(5, tmp); pdram_timing->tcksrx = max(5, tmp); /*mode register timing*/ tmp = ((DDR3_TMOD * nmhz + 999) / 1000); pdram_timing->tmod = max(12, tmp); pdram_timing->tmrd = DDR3_TMRD; pdram_timing->tmrr = 0; /*ODT*/ pdram_timing->todton = pdram_timing->cwl - 2; /*ZQ*/ tmp = ((DDR3_TZQINIT * nmhz + 999) / 1000); pdram_timing->tzqinit = max(512, tmp); tmp = ((DDR3_TZQCS * nmhz + 999) / 1000); pdram_timing->tzqcs = max(64, tmp); tmp = ((DDR3_TZQOPER * nmhz + 999) / 1000); pdram_timing->tzqoper = max(256, tmp); /* write leveling */ pdram_timing->twlmrd = DDR3_TWLMRD; pdram_timing->twldqsen = DDR3_TWLDQSEN; pdram_timing->twlo = ((DDR3_TWLO * nmhz + (nmhz >> 1) + 999) / 1000); } #define LPDDR2_TINIT1 (100) /* ns */ #define LPDDR2_TINIT2 (5) /* tCK */ #define LPDDR2_TINIT3 (200000) /* 200us */ #define LPDDR2_TINIT4 (1000) /* 1us */ #define LPDDR2_TINIT5 (10000) /* 10us */ #define LPDDR2_TRSTL (0) /* tCK */ #define LPDDR2_TRSTH (500000) /* 500us */ #define LPDDR2_TREFI_3_9_US (3900) /* 3.9us */ #define LPDDR2_TREFI_7_8_US (7800) /* 7.8us */ /* base timing */ #define LPDDR2_TRCD (24) /* tRCD,15ns(Fast)18ns(Typ)24ns(Slow) */ #define LPDDR2_TRP_PB (18) /* tRPpb,15ns(Fast)18ns(Typ)24ns(Slow) */ #define LPDDR2_TRP_AB_8_BANK (21) /* tRPab,18ns(Fast)21ns(Typ)27ns(Slow) */ #define LPDDR2_TWR (15) /* tWR, max(3tCK,15ns) */ #define LPDDR2_TRTP (7) /* tRTP, max(2tCK, 7.5ns) */ #define LPDDR2_TRRD (10) /* tRRD, max(2tCK,10ns) */ #define LPDDR2_TCCD (2) /* tCK */ #define LPDDR2_TWTR_GREAT_200MHZ (7) /* ns */ #define LPDDR2_TWTR_LITTLE_200MHZ (10) /* ns */ #define LPDDR2_TRTW (0) /* tCK */ #define LPDDR2_TRAS_MAX (70000) /* 70us */ #define LPDDR2_TRAS (42) /* tRAS, max(3tCK,42ns) */ #define LPDDR2_TFAW_GREAT_200MHZ (50) /* max(8tCK,50ns) */ #define LPDDR2_TFAW_LITTLE_200MHZ (60) /* max(8tCK,60ns) */ #define LPDDR2_TRFC_8GBIT (210) /* ns */ #define LPDDR2_TRFC_4GBIT (130) /* ns */ #define LPDDR2_TDQSCK_MIN (2) /* tDQSCKmin, 2.5ns */ #define LPDDR2_TDQSCK_MAX (5) /* tDQSCKmax, 5.5ns */ /*pd and sr*/ #define LPDDR2_TXP (7) /* tXP, max(2tCK,7.5ns) */ #define LPDDR2_TXPDLL (0) #define LPDDR2_TDLLK (0) /* tCK */ #define LPDDR2_TCKE (3) /* tCK */ #define LPDDR2_TCKESR (15) /* tCKESR, max(3tCK,15ns) */ #define LPDDR2_TCKSRE (1) /* tCK */ #define LPDDR2_TCKSRX (2) /* tCK */ /*mode register timing*/ #define LPDDR2_TMOD (0) #define LPDDR2_TMRD (5) /* tMRD, (=tMRW), 5 tCK */ #define LPDDR2_TMRR (2) /* tCK */ /*ZQ*/ #define LPDDR2_TZQINIT (1000) /* ns */ #define LPDDR2_TZQCS (90) /* tZQCS, max(6tCK,90ns) */ #define LPDDR2_TZQCL (360) /* tZQCL, max(6tCK,360ns) */ #define LPDDR2_TZQRESET (50) /* ZQreset, max(3tCK,50ns) */ /* * Description: depend on input parameter "timing_config", * and calculate all lpddr2 * spec timing to "pdram_timing" * parameters: * input: timing_config * output: pdram_timing */ static void lpddr2_get_parameter(struct timing_related_config *timing_config, struct dram_timing_t *pdram_timing) { uint32_t nmhz = timing_config->freq; uint32_t ddr_capability_per_die = get_max_die_capability(timing_config); uint32_t tmp, trp_tmp, trppb_tmp, tras_tmp, twr_tmp, bl_tmp; zeromem((void *)pdram_timing, sizeof(struct dram_timing_t)); pdram_timing->mhz = nmhz; pdram_timing->al = 0; pdram_timing->bl = timing_config->bl; /* 1066 933 800 667 533 400 333 * RL, 8 7 6 5 4 3 3 * WL, 4 4 3 2 2 1 1 */ if (nmhz <= 266) { pdram_timing->cl = 4; pdram_timing->cwl = 2; pdram_timing->mr[2] = LPDDR2_RL4_WL2; } else if (nmhz <= 333) { pdram_timing->cl = 5; pdram_timing->cwl = 2; pdram_timing->mr[2] = LPDDR2_RL5_WL2; } else if (nmhz <= 400) { pdram_timing->cl = 6; pdram_timing->cwl = 3; pdram_timing->mr[2] = LPDDR2_RL6_WL3; } else if (nmhz <= 466) { pdram_timing->cl = 7; pdram_timing->cwl = 4; pdram_timing->mr[2] = LPDDR2_RL7_WL4; } else { pdram_timing->cl = 8; pdram_timing->cwl = 4; pdram_timing->mr[2] = LPDDR2_RL8_WL4; } switch (timing_config->dramds) { case 120: pdram_timing->mr[3] = LPDDR2_DS_120; break; case 80: pdram_timing->mr[3] = LPDDR2_DS_80; break; case 60: pdram_timing->mr[3] = LPDDR2_DS_60; break; case 48: pdram_timing->mr[3] = LPDDR2_DS_48; break; case 40: pdram_timing->mr[3] = LPDDR2_DS_40; break; case 34: default: pdram_timing->mr[3] = LPDDR2_DS_34; break; } pdram_timing->mr[0] = 0; pdram_timing->tinit1 = (LPDDR2_TINIT1 * nmhz + 999) / 1000; pdram_timing->tinit2 = LPDDR2_TINIT2; pdram_timing->tinit3 = (LPDDR2_TINIT3 * nmhz + 999) / 1000; pdram_timing->tinit4 = (LPDDR2_TINIT4 * nmhz + 999) / 1000; pdram_timing->tinit5 = (LPDDR2_TINIT5 * nmhz + 999) / 1000; pdram_timing->trstl = LPDDR2_TRSTL; pdram_timing->trsth = (LPDDR2_TRSTH * nmhz + 999) / 1000; /* * tREFI, average periodic refresh interval, * 15.6us(<256Mb) 7.8us(256Mb-1Gb) 3.9us(2Gb-8Gb) */ if (ddr_capability_per_die >= 0x10000000) pdram_timing->trefi = (LPDDR2_TREFI_3_9_US * nmhz + 999) / 1000; else pdram_timing->trefi = (LPDDR2_TREFI_7_8_US * nmhz + 999) / 1000; /* base timing */ tmp = ((LPDDR2_TRCD * nmhz + 999) / 1000); pdram_timing->trcd = max(3, tmp); /* * tRPpb, max(3tCK, 15ns(Fast) 18ns(Typ) 24ns(Slow), */ trppb_tmp = ((LPDDR2_TRP_PB * nmhz + 999) / 1000); trppb_tmp = max(3, trppb_tmp); pdram_timing->trppb = trppb_tmp; /* * tRPab, max(3tCK, 4-bank:15ns(Fast) 18ns(Typ) 24ns(Slow), * 8-bank:18ns(Fast) 21ns(Typ) 27ns(Slow)) */ trp_tmp = ((LPDDR2_TRP_AB_8_BANK * nmhz + 999) / 1000); trp_tmp = max(3, trp_tmp); pdram_timing->trp = trp_tmp; twr_tmp = ((LPDDR2_TWR * nmhz + 999) / 1000); twr_tmp = max(3, twr_tmp); pdram_timing->twr = twr_tmp; bl_tmp = (pdram_timing->bl == 16) ? LPDDR2_BL16 : ((pdram_timing->bl == 8) ? LPDDR2_BL8 : LPDDR2_BL4); pdram_timing->mr[1] = bl_tmp | LPDDR2_N_WR(twr_tmp); tmp = ((LPDDR2_TRTP * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->trtp = max(2, tmp); tras_tmp = ((LPDDR2_TRAS * nmhz + 999) / 1000); tras_tmp = max(3, tras_tmp); pdram_timing->tras_min = tras_tmp; pdram_timing->tras_max = ((LPDDR2_TRAS_MAX * nmhz + 999) / 1000); pdram_timing->trc = (tras_tmp + trp_tmp); tmp = ((LPDDR2_TRRD * nmhz + 999) / 1000); pdram_timing->trrd = max(2, tmp); pdram_timing->tccd = LPDDR2_TCCD; /* tWTR, max(2tCK, 7.5ns(533-266MHz) 10ns(200-166MHz)) */ if (nmhz > 200) tmp = ((LPDDR2_TWTR_GREAT_200MHZ * nmhz + (nmhz >> 1) + 999) / 1000); else tmp = ((LPDDR2_TWTR_LITTLE_200MHZ * nmhz + 999) / 1000); pdram_timing->twtr = max(2, tmp); pdram_timing->trtw = LPDDR2_TRTW; if (nmhz <= 200) pdram_timing->tfaw = (LPDDR2_TFAW_LITTLE_200MHZ * nmhz + 999) / 1000; else pdram_timing->tfaw = (LPDDR2_TFAW_GREAT_200MHZ * nmhz + 999) / 1000; /* tRFC, 90ns(<=512Mb) 130ns(1Gb-4Gb) 210ns(8Gb) */ if (ddr_capability_per_die >= 0x40000000) { pdram_timing->trfc = (LPDDR2_TRFC_8GBIT * nmhz + 999) / 1000; tmp = (((LPDDR2_TRFC_8GBIT + 10) * nmhz + 999) / 1000); } else { pdram_timing->trfc = (LPDDR2_TRFC_4GBIT * nmhz + 999) / 1000; tmp = (((LPDDR2_TRFC_4GBIT + 10) * nmhz + 999) / 1000); } if (tmp < 2) tmp = 2; pdram_timing->txsr = tmp; pdram_timing->txsnr = tmp; /* tdqsck use rounded down */ pdram_timing->tdqsck = ((LPDDR2_TDQSCK_MIN * nmhz + (nmhz >> 1)) / 1000); pdram_timing->tdqsck_max = ((LPDDR2_TDQSCK_MAX * nmhz + (nmhz >> 1) + 999) / 1000); /* pd and sr */ tmp = ((LPDDR2_TXP * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->txp = max(2, tmp); pdram_timing->txpdll = LPDDR2_TXPDLL; pdram_timing->tdllk = LPDDR2_TDLLK; pdram_timing->tcke = LPDDR2_TCKE; tmp = ((LPDDR2_TCKESR * nmhz + 999) / 1000); pdram_timing->tckesr = max(3, tmp); pdram_timing->tcksre = LPDDR2_TCKSRE; pdram_timing->tcksrx = LPDDR2_TCKSRX; /* mode register timing */ pdram_timing->tmod = LPDDR2_TMOD; pdram_timing->tmrd = LPDDR2_TMRD; pdram_timing->tmrr = LPDDR2_TMRR; /* ZQ */ pdram_timing->tzqinit = (LPDDR2_TZQINIT * nmhz + 999) / 1000; tmp = ((LPDDR2_TZQCS * nmhz + 999) / 1000); pdram_timing->tzqcs = max(6, tmp); tmp = ((LPDDR2_TZQCL * nmhz + 999) / 1000); pdram_timing->tzqoper = max(6, tmp); tmp = ((LPDDR2_TZQRESET * nmhz + 999) / 1000); pdram_timing->tzqreset = max(3, tmp); } #define LPDDR3_TINIT1 (100) /* ns */ #define LPDDR3_TINIT2 (5) /* tCK */ #define LPDDR3_TINIT3 (200000) /* 200us */ #define LPDDR3_TINIT4 (1000) /* 1us */ #define LPDDR3_TINIT5 (10000) /* 10us */ #define LPDDR3_TRSTL (0) #define LPDDR3_TRSTH (0) /* 500us */ #define LPDDR3_TREFI_3_9_US (3900) /* 3.9us */ /* base timging */ #define LPDDR3_TRCD (18) /* tRCD,15ns(Fast)18ns(Typ)24ns(Slow) */ #define LPDDR3_TRP_PB (18) /* tRPpb, 15ns(Fast) 18ns(Typ) 24ns(Slow) */ #define LPDDR3_TRP_AB (21) /* tRPab, 18ns(Fast) 21ns(Typ) 27ns(Slow) */ #define LPDDR3_TWR (15) /* tWR, max(4tCK,15ns) */ #define LPDDR3_TRTP (7) /* tRTP, max(4tCK, 7.5ns) */ #define LPDDR3_TRRD (10) /* tRRD, max(2tCK,10ns) */ #define LPDDR3_TCCD (4) /* tCK */ #define LPDDR3_TWTR (7) /* tWTR, max(4tCK, 7.5ns) */ #define LPDDR3_TRTW (0) /* tCK register min valid value */ #define LPDDR3_TRAS_MAX (70000) /* 70us */ #define LPDDR3_TRAS (42) /* tRAS, max(3tCK,42ns) */ #define LPDDR3_TFAW (50) /* tFAW,max(8tCK, 50ns) */ #define LPDDR3_TRFC_8GBIT (210) /* tRFC, 130ns(4Gb) 210ns(>4Gb) */ #define LPDDR3_TRFC_4GBIT (130) /* ns */ #define LPDDR3_TDQSCK_MIN (2) /* tDQSCKmin,2.5ns */ #define LPDDR3_TDQSCK_MAX (5) /* tDQSCKmax,5.5ns */ /* pd and sr */ #define LPDDR3_TXP (7) /* tXP, max(3tCK,7.5ns) */ #define LPDDR3_TXPDLL (0) #define LPDDR3_TCKE (7) /* tCKE, (max 7.5ns,3 tCK) */ #define LPDDR3_TCKESR (15) /* tCKESR, max(3tCK,15ns) */ #define LPDDR3_TCKSRE (2) /* tCKSRE=tCPDED, 2 tCK */ #define LPDDR3_TCKSRX (2) /* tCKSRX, 2 tCK */ /* mode register timing */ #define LPDDR3_TMOD (0) #define LPDDR3_TMRD (14) /* tMRD, (=tMRW), max(14ns, 10 tCK) */ #define LPDDR3_TMRR (4) /* tMRR, 4 tCK */ #define LPDDR3_TMRRI LPDDR3_TRCD /* ODT */ #define LPDDR3_TODTON (3) /* 3.5ns */ /* ZQ */ #define LPDDR3_TZQINIT (1000) /* 1us */ #define LPDDR3_TZQCS (90) /* tZQCS, 90ns */ #define LPDDR3_TZQCL (360) /* 360ns */ #define LPDDR3_TZQRESET (50) /* ZQreset, max(3tCK,50ns) */ /* write leveling */ #define LPDDR3_TWLMRD (40) /* ns */ #define LPDDR3_TWLO (20) /* ns */ #define LPDDR3_TWLDQSEN (25) /* ns */ /* CA training */ #define LPDDR3_TCACKEL (10) /* tCK */ #define LPDDR3_TCAENT (10) /* tCK */ #define LPDDR3_TCAMRD (20) /* tCK */ #define LPDDR3_TCACKEH (10) /* tCK */ #define LPDDR3_TCAEXT (10) /* tCK */ #define LPDDR3_TADR (20) /* ns */ #define LPDDR3_TMRZ (3) /* ns */ /* FSP */ #define LPDDR3_TFC_LONG (250) /* ns */ /* * Description: depend on input parameter "timing_config", * and calculate all lpddr3 * spec timing to "pdram_timing" * parameters: * input: timing_config * output: pdram_timing */ static void lpddr3_get_parameter(struct timing_related_config *timing_config, struct dram_timing_t *pdram_timing) { uint32_t nmhz = timing_config->freq; uint32_t ddr_capability_per_die = get_max_die_capability(timing_config); uint32_t tmp, trp_tmp, trppb_tmp, tras_tmp, twr_tmp, bl_tmp; zeromem((void *)pdram_timing, sizeof(struct dram_timing_t)); pdram_timing->mhz = nmhz; pdram_timing->al = 0; pdram_timing->bl = timing_config->bl; /* * Only support Write Latency Set A here * 1066 933 800 733 667 600 533 400 166 * RL, 16 14 12 11 10 9 8 6 3 * WL, 8 8 6 6 6 5 4 3 1 */ if (nmhz <= 400) { pdram_timing->cl = 6; pdram_timing->cwl = 3; pdram_timing->mr[2] = LPDDR3_RL6_WL3; } else if (nmhz <= 533) { pdram_timing->cl = 8; pdram_timing->cwl = 4; pdram_timing->mr[2] = LPDDR3_RL8_WL4; } else if (nmhz <= 600) { pdram_timing->cl = 9; pdram_timing->cwl = 5; pdram_timing->mr[2] = LPDDR3_RL9_WL5; } else if (nmhz <= 667) { pdram_timing->cl = 10; pdram_timing->cwl = 6; pdram_timing->mr[2] = LPDDR3_RL10_WL6; } else if (nmhz <= 733) { pdram_timing->cl = 11; pdram_timing->cwl = 6; pdram_timing->mr[2] = LPDDR3_RL11_WL6; } else if (nmhz <= 800) { pdram_timing->cl = 12; pdram_timing->cwl = 6; pdram_timing->mr[2] = LPDDR3_RL12_WL6; } else if (nmhz <= 933) { pdram_timing->cl = 14; pdram_timing->cwl = 8; pdram_timing->mr[2] = LPDDR3_RL14_WL8; } else { pdram_timing->cl = 16; pdram_timing->cwl = 8; pdram_timing->mr[2] = LPDDR3_RL16_WL8; } switch (timing_config->dramds) { case 80: pdram_timing->mr[3] = LPDDR3_DS_80; break; case 60: pdram_timing->mr[3] = LPDDR3_DS_60; break; case 48: pdram_timing->mr[3] = LPDDR3_DS_48; break; case 40: pdram_timing->mr[3] = LPDDR3_DS_40; break; case 3440: pdram_timing->mr[3] = LPDDR3_DS_34D_40U; break; case 4048: pdram_timing->mr[3] = LPDDR3_DS_40D_48U; break; case 3448: pdram_timing->mr[3] = LPDDR3_DS_34D_48U; break; case 34: default: pdram_timing->mr[3] = LPDDR3_DS_34; break; } pdram_timing->mr[0] = 0; if (timing_config->odt) switch (timing_config->dramodt) { case 60: pdram_timing->mr11 = LPDDR3_ODT_60; break; case 120: pdram_timing->mr11 = LPDDR3_ODT_120; break; case 240: default: pdram_timing->mr11 = LPDDR3_ODT_240; break; } else pdram_timing->mr11 = LPDDR3_ODT_DIS; pdram_timing->tinit1 = (LPDDR3_TINIT1 * nmhz + 999) / 1000; pdram_timing->tinit2 = LPDDR3_TINIT2; pdram_timing->tinit3 = (LPDDR3_TINIT3 * nmhz + 999) / 1000; pdram_timing->tinit4 = (LPDDR3_TINIT4 * nmhz + 999) / 1000; pdram_timing->tinit5 = (LPDDR3_TINIT5 * nmhz + 999) / 1000; pdram_timing->trstl = LPDDR3_TRSTL; pdram_timing->trsth = (LPDDR3_TRSTH * nmhz + 999) / 1000; /* tREFI, average periodic refresh interval, 3.9us(4Gb-16Gb) */ pdram_timing->trefi = (LPDDR3_TREFI_3_9_US * nmhz + 999) / 1000; /* base timing */ tmp = ((LPDDR3_TRCD * nmhz + 999) / 1000); pdram_timing->trcd = max(3, tmp); trppb_tmp = ((LPDDR3_TRP_PB * nmhz + 999) / 1000); trppb_tmp = max(3, trppb_tmp); pdram_timing->trppb = trppb_tmp; trp_tmp = ((LPDDR3_TRP_AB * nmhz + 999) / 1000); trp_tmp = max(3, trp_tmp); pdram_timing->trp = trp_tmp; twr_tmp = ((LPDDR3_TWR * nmhz + 999) / 1000); twr_tmp = max(4, twr_tmp); pdram_timing->twr = twr_tmp; if (twr_tmp <= 6) twr_tmp = 6; else if (twr_tmp <= 8) twr_tmp = 8; else if (twr_tmp <= 12) twr_tmp = twr_tmp; else if (twr_tmp <= 14) twr_tmp = 14; else twr_tmp = 16; if (twr_tmp > 9) pdram_timing->mr[2] |= (1 << 4); /*enable nWR > 9*/ twr_tmp = (twr_tmp > 9) ? (twr_tmp - 10) : (twr_tmp - 2); bl_tmp = LPDDR3_BL8; pdram_timing->mr[1] = bl_tmp | LPDDR3_N_WR(twr_tmp); tmp = ((LPDDR3_TRTP * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->trtp = max(4, tmp); tras_tmp = ((LPDDR3_TRAS * nmhz + 999) / 1000); tras_tmp = max(3, tras_tmp); pdram_timing->tras_min = tras_tmp; pdram_timing->trc = (tras_tmp + trp_tmp); tmp = ((LPDDR3_TRRD * nmhz + 999) / 1000); pdram_timing->trrd = max(2, tmp); pdram_timing->tccd = LPDDR3_TCCD; tmp = ((LPDDR3_TWTR * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->twtr = max(4, tmp); pdram_timing->trtw = ((LPDDR3_TRTW * nmhz + 999) / 1000); pdram_timing->tras_max = ((LPDDR3_TRAS_MAX * nmhz + 999) / 1000); tmp = (LPDDR3_TFAW * nmhz + 999) / 1000; pdram_timing->tfaw = max(8, tmp); if (ddr_capability_per_die > 0x20000000) { pdram_timing->trfc = (LPDDR3_TRFC_8GBIT * nmhz + 999) / 1000; tmp = (((LPDDR3_TRFC_8GBIT + 10) * nmhz + 999) / 1000); } else { pdram_timing->trfc = (LPDDR3_TRFC_4GBIT * nmhz + 999) / 1000; tmp = (((LPDDR3_TRFC_4GBIT + 10) * nmhz + 999) / 1000); } pdram_timing->txsr = max(2, tmp); pdram_timing->txsnr = max(2, tmp); /* tdqsck use rounded down */ pdram_timing->tdqsck = ((LPDDR3_TDQSCK_MIN * nmhz + (nmhz >> 1)) / 1000); pdram_timing->tdqsck_max = ((LPDDR3_TDQSCK_MAX * nmhz + (nmhz >> 1) + 999) / 1000); /*pd and sr*/ tmp = ((LPDDR3_TXP * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->txp = max(3, tmp); pdram_timing->txpdll = LPDDR3_TXPDLL; tmp = ((LPDDR3_TCKE * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->tcke = max(3, tmp); tmp = ((LPDDR3_TCKESR * nmhz + 999) / 1000); pdram_timing->tckesr = max(3, tmp); pdram_timing->tcksre = LPDDR3_TCKSRE; pdram_timing->tcksrx = LPDDR3_TCKSRX; /*mode register timing*/ pdram_timing->tmod = LPDDR3_TMOD; tmp = ((LPDDR3_TMRD * nmhz + 999) / 1000); pdram_timing->tmrd = max(10, tmp); pdram_timing->tmrr = LPDDR3_TMRR; tmp = ((LPDDR3_TRCD * nmhz + 999) / 1000); pdram_timing->tmrri = max(3, tmp); /* ODT */ pdram_timing->todton = (LPDDR3_TODTON * nmhz + (nmhz >> 1) + 999) / 1000; /* ZQ */ pdram_timing->tzqinit = (LPDDR3_TZQINIT * nmhz + 999) / 1000; pdram_timing->tzqcs = ((LPDDR3_TZQCS * nmhz + 999) / 1000); pdram_timing->tzqoper = ((LPDDR3_TZQCL * nmhz + 999) / 1000); tmp = ((LPDDR3_TZQRESET * nmhz + 999) / 1000); pdram_timing->tzqreset = max(3, tmp); /* write leveling */ pdram_timing->twlmrd = (LPDDR3_TWLMRD * nmhz + 999) / 1000; pdram_timing->twlo = (LPDDR3_TWLO * nmhz + 999) / 1000; pdram_timing->twldqsen = (LPDDR3_TWLDQSEN * nmhz + 999) / 1000; /* CA training */ pdram_timing->tcackel = LPDDR3_TCACKEL; pdram_timing->tcaent = LPDDR3_TCAENT; pdram_timing->tcamrd = LPDDR3_TCAMRD; pdram_timing->tcackeh = LPDDR3_TCACKEH; pdram_timing->tcaext = LPDDR3_TCAEXT; pdram_timing->tadr = (LPDDR3_TADR * nmhz + 999) / 1000; pdram_timing->tmrz = (LPDDR3_TMRZ * nmhz + 999) / 1000; pdram_timing->tcacd = pdram_timing->tadr + 2; /* FSP */ pdram_timing->tfc_long = (LPDDR3_TFC_LONG * nmhz + 999) / 1000; } #define LPDDR4_TINIT1 (200000) /* 200us */ #define LPDDR4_TINIT2 (10) /* 10ns */ #define LPDDR4_TINIT3 (2000000) /* 2ms */ #define LPDDR4_TINIT4 (5) /* tCK */ #define LPDDR4_TINIT5 (2000) /* 2us */ #define LPDDR4_TRSTL LPDDR4_TINIT1 #define LPDDR4_TRSTH LPDDR4_TINIT3 #define LPDDR4_TREFI_3_9_US (3900) /* 3.9us */ /* base timging */ #define LPDDR4_TRCD (18) /* tRCD, max(18ns,4tCK) */ #define LPDDR4_TRP_PB (18) /* tRPpb, max(18ns, 4tCK) */ #define LPDDR4_TRP_AB (21) /* tRPab, max(21ns, 4tCK) */ #define LPDDR4_TRRD (10) /* tRRD, max(4tCK,10ns) */ #define LPDDR4_TCCD_BL16 (8) /* tCK */ #define LPDDR4_TCCD_BL32 (16) /* tCK */ #define LPDDR4_TWTR (10) /* tWTR, max(8tCK, 10ns) */ #define LPDDR4_TRTW (0) /* tCK register min valid value */ #define LPDDR4_TRAS_MAX (70000) /* 70us */ #define LPDDR4_TRAS (42) /* tRAS, max(3tCK,42ns) */ #define LPDDR4_TFAW (40) /* tFAW,min 40ns) */ #define LPDDR4_TRFC_12GBIT (280) /* tRFC, 280ns(>=12Gb) */ #define LPDDR4_TRFC_6GBIT (180) /* 6Gb/8Gb 180ns */ #define LPDDR4_TRFC_4GBIT (130) /* 4Gb 130ns */ #define LPDDR4_TDQSCK_MIN (1) /* tDQSCKmin,1.5ns */ #define LPDDR4_TDQSCK_MAX (3) /* tDQSCKmax,3.5ns */ #define LPDDR4_TPPD (4) /* tCK */ /* pd and sr */ #define LPDDR4_TXP (7) /* tXP, max(5tCK,7.5ns) */ #define LPDDR4_TCKE (7) /* tCKE, max(7.5ns,4 tCK) */ #define LPDDR4_TESCKE (1) /* tESCKE, max(1.75ns, 3tCK) */ #define LPDDR4_TSR (15) /* tSR, max(15ns, 3tCK) */ #define LPDDR4_TCMDCKE (1) /* max(1.75ns, 3tCK) */ #define LPDDR4_TCSCKE (1) /* 1.75ns */ #define LPDDR4_TCKELCS (5) /* max(5ns, 5tCK) */ #define LPDDR4_TCSCKEH (1) /* 1.75ns */ #define LPDDR4_TCKEHCS (7) /* max(7.5ns, 5tCK) */ #define LPDDR4_TMRWCKEL (14) /* max(14ns, 10tCK) */ #define LPDDR4_TCKELCMD (7) /* max(7.5ns, 3tCK) */ #define LPDDR4_TCKEHCMD (7) /* max(7.5ns, 3tCK) */ #define LPDDR4_TCKELPD (7) /* max(7.5ns, 3tCK) */ #define LPDDR4_TCKCKEL (7) /* max(7.5ns, 3tCK) */ /* mode register timing */ #define LPDDR4_TMRD (14) /* tMRD, (=tMRW), max(14ns, 10 tCK) */ #define LPDDR4_TMRR (8) /* tMRR, 8 tCK */ /* ODT */ #define LPDDR4_TODTON (3) /* 3.5ns */ /* ZQ */ #define LPDDR4_TZQCAL (1000) /* 1us */ #define LPDDR4_TZQLAT (30) /* tZQLAT, max(30ns,8tCK) */ #define LPDDR4_TZQRESET (50) /* ZQreset, max(3tCK,50ns) */ #define LPDDR4_TZQCKE (1) /* tZQCKE, max(1.75ns, 3tCK) */ /* write leveling */ #define LPDDR4_TWLMRD (40) /* tCK */ #define LPDDR4_TWLO (20) /* ns */ #define LPDDR4_TWLDQSEN (20) /* tCK */ /* CA training */ #define LPDDR4_TCAENT (250) /* ns */ #define LPDDR4_TADR (20) /* ns */ #define LPDDR4_TMRZ (1) /* 1.5ns */ #define LPDDR4_TVREF_LONG (250) /* ns */ #define LPDDR4_TVREF_SHORT (100) /* ns */ /* VRCG */ #define LPDDR4_TVRCG_ENABLE (200) /* ns */ #define LPDDR4_TVRCG_DISABLE (100) /* ns */ /* FSP */ #define LPDDR4_TFC_LONG (250) /* ns */ #define LPDDR4_TCKFSPE (7) /* max(7.5ns, 4tCK) */ #define LPDDR4_TCKFSPX (7) /* max(7.5ns, 4tCK) */ /* * Description: depend on input parameter "timing_config", * and calculate all lpddr4 * spec timing to "pdram_timing" * parameters: * input: timing_config * output: pdram_timing */ static void lpddr4_get_parameter(struct timing_related_config *timing_config, struct dram_timing_t *pdram_timing) { uint32_t nmhz = timing_config->freq; uint32_t ddr_capability_per_die = get_max_die_capability(timing_config); uint32_t tmp, trp_tmp, trppb_tmp, tras_tmp; zeromem((void *)pdram_timing, sizeof(struct dram_timing_t)); pdram_timing->mhz = nmhz; pdram_timing->al = 0; pdram_timing->bl = timing_config->bl; /* * Only support Write Latency Set A here * 2133 1866 1600 1333 1066 800 533 266 * RL, 36 32 28 24 20 14 10 6 * WL, 18 16 14 12 10 8 6 4 * nWR, 40 34 30 24 20 16 10 6 * nRTP,16 14 12 10 8 8 8 8 */ tmp = (timing_config->bl == 32) ? 1 : 0; /* * we always use WR preamble = 2tCK * RD preamble = Static */ tmp |= (1 << 2); if (nmhz <= 266) { pdram_timing->cl = 6; pdram_timing->cwl = 4; pdram_timing->twr = 6; pdram_timing->trtp = 8; pdram_timing->mr[2] = LPDDR4_RL6_NRTP8 | LPDDR4_A_WL4; } else if (nmhz <= 533) { if (timing_config->rdbi) { pdram_timing->cl = 12; pdram_timing->mr[2] = LPDDR4_RL12_NRTP8 | LPDDR4_A_WL6; } else { pdram_timing->cl = 10; pdram_timing->mr[2] = LPDDR4_RL10_NRTP8 | LPDDR4_A_WL6; } pdram_timing->cwl = 6; pdram_timing->twr = 10; pdram_timing->trtp = 8; tmp |= (1 << 4); } else if (nmhz <= 800) { if (timing_config->rdbi) { pdram_timing->cl = 16; pdram_timing->mr[2] = LPDDR4_RL16_NRTP8 | LPDDR4_A_WL8; } else { pdram_timing->cl = 14; pdram_timing->mr[2] = LPDDR4_RL14_NRTP8 | LPDDR4_A_WL8; } pdram_timing->cwl = 8; pdram_timing->twr = 16; pdram_timing->trtp = 8; tmp |= (2 << 4); } else if (nmhz <= 1066) { if (timing_config->rdbi) { pdram_timing->cl = 22; pdram_timing->mr[2] = LPDDR4_RL22_NRTP8 | LPDDR4_A_WL10; } else { pdram_timing->cl = 20; pdram_timing->mr[2] = LPDDR4_RL20_NRTP8 | LPDDR4_A_WL10; } pdram_timing->cwl = 10; pdram_timing->twr = 20; pdram_timing->trtp = 8; tmp |= (3 << 4); } else if (nmhz <= 1333) { if (timing_config->rdbi) { pdram_timing->cl = 28; pdram_timing->mr[2] = LPDDR4_RL28_NRTP10 | LPDDR4_A_WL12; } else { pdram_timing->cl = 24; pdram_timing->mr[2] = LPDDR4_RL24_NRTP10 | LPDDR4_A_WL12; } pdram_timing->cwl = 12; pdram_timing->twr = 24; pdram_timing->trtp = 10; tmp |= (4 << 4); } else if (nmhz <= 1600) { if (timing_config->rdbi) { pdram_timing->cl = 32; pdram_timing->mr[2] = LPDDR4_RL32_NRTP12 | LPDDR4_A_WL14; } else { pdram_timing->cl = 28; pdram_timing->mr[2] = LPDDR4_RL28_NRTP12 | LPDDR4_A_WL14; } pdram_timing->cwl = 14; pdram_timing->twr = 30; pdram_timing->trtp = 12; tmp |= (5 << 4); } else if (nmhz <= 1866) { if (timing_config->rdbi) { pdram_timing->cl = 36; pdram_timing->mr[2] = LPDDR4_RL36_NRTP14 | LPDDR4_A_WL16; } else { pdram_timing->cl = 32; pdram_timing->mr[2] = LPDDR4_RL32_NRTP14 | LPDDR4_A_WL16; } pdram_timing->cwl = 16; pdram_timing->twr = 34; pdram_timing->trtp = 14; tmp |= (6 << 4); } else { if (timing_config->rdbi) { pdram_timing->cl = 40; pdram_timing->mr[2] = LPDDR4_RL40_NRTP16 | LPDDR4_A_WL18; } else { pdram_timing->cl = 36; pdram_timing->mr[2] = LPDDR4_RL36_NRTP16 | LPDDR4_A_WL18; } pdram_timing->cwl = 18; pdram_timing->twr = 40; pdram_timing->trtp = 16; tmp |= (7 << 4); } pdram_timing->mr[1] = tmp; tmp = (timing_config->rdbi ? LPDDR4_DBI_RD_EN : 0) | (timing_config->wdbi ? LPDDR4_DBI_WR_EN : 0); switch (timing_config->dramds) { case 240: pdram_timing->mr[3] = LPDDR4_PDDS_240 | tmp; break; case 120: pdram_timing->mr[3] = LPDDR4_PDDS_120 | tmp; break; case 80: pdram_timing->mr[3] = LPDDR4_PDDS_80 | tmp; break; case 60: pdram_timing->mr[3] = LPDDR4_PDDS_60 | tmp; break; case 48: pdram_timing->mr[3] = LPDDR4_PDDS_48 | tmp; break; case 40: default: pdram_timing->mr[3] = LPDDR4_PDDS_40 | tmp; break; } pdram_timing->mr[0] = 0; if (timing_config->odt) { switch (timing_config->dramodt) { case 240: tmp = LPDDR4_DQODT_240; break; case 120: tmp = LPDDR4_DQODT_120; break; case 80: tmp = LPDDR4_DQODT_80; break; case 60: tmp = LPDDR4_DQODT_60; break; case 48: tmp = LPDDR4_DQODT_48; break; case 40: default: tmp = LPDDR4_DQODT_40; break; } switch (timing_config->caodt) { case 240: pdram_timing->mr11 = LPDDR4_CAODT_240 | tmp; break; case 120: pdram_timing->mr11 = LPDDR4_CAODT_120 | tmp; break; case 80: pdram_timing->mr11 = LPDDR4_CAODT_80 | tmp; break; case 60: pdram_timing->mr11 = LPDDR4_CAODT_60 | tmp; break; case 48: pdram_timing->mr11 = LPDDR4_CAODT_48 | tmp; break; case 40: default: pdram_timing->mr11 = LPDDR4_CAODT_40 | tmp; break; } } else { pdram_timing->mr11 = LPDDR4_CAODT_DIS | tmp; } pdram_timing->tinit1 = (LPDDR4_TINIT1 * nmhz + 999) / 1000; pdram_timing->tinit2 = (LPDDR4_TINIT2 * nmhz + 999) / 1000; pdram_timing->tinit3 = (LPDDR4_TINIT3 * nmhz + 999) / 1000; pdram_timing->tinit4 = (LPDDR4_TINIT4 * nmhz + 999) / 1000; pdram_timing->tinit5 = (LPDDR4_TINIT5 * nmhz + 999) / 1000; pdram_timing->trstl = (LPDDR4_TRSTL * nmhz + 999) / 1000; pdram_timing->trsth = (LPDDR4_TRSTH * nmhz + 999) / 1000; /* tREFI, average periodic refresh interval, 3.9us(4Gb-16Gb) */ pdram_timing->trefi = (LPDDR4_TREFI_3_9_US * nmhz + 999) / 1000; /* base timing */ tmp = ((LPDDR4_TRCD * nmhz + 999) / 1000); pdram_timing->trcd = max(4, tmp); trppb_tmp = ((LPDDR4_TRP_PB * nmhz + 999) / 1000); trppb_tmp = max(4, trppb_tmp); pdram_timing->trppb = trppb_tmp; trp_tmp = ((LPDDR4_TRP_AB * nmhz + 999) / 1000); trp_tmp = max(4, trp_tmp); pdram_timing->trp = trp_tmp; tras_tmp = ((LPDDR4_TRAS * nmhz + 999) / 1000); tras_tmp = max(3, tras_tmp); pdram_timing->tras_min = tras_tmp; pdram_timing->trc = (tras_tmp + trp_tmp); tmp = ((LPDDR4_TRRD * nmhz + 999) / 1000); pdram_timing->trrd = max(4, tmp); if (timing_config->bl == 32) pdram_timing->tccd = LPDDR4_TCCD_BL16; else pdram_timing->tccd = LPDDR4_TCCD_BL32; pdram_timing->tccdmw = 4 * pdram_timing->tccd; tmp = ((LPDDR4_TWTR * nmhz + 999) / 1000); pdram_timing->twtr = max(8, tmp); pdram_timing->trtw = ((LPDDR4_TRTW * nmhz + 999) / 1000); pdram_timing->tras_max = ((LPDDR4_TRAS_MAX * nmhz + 999) / 1000); pdram_timing->tfaw = (LPDDR4_TFAW * nmhz + 999) / 1000; if (ddr_capability_per_die > 0x60000000) { /* >= 12Gb */ pdram_timing->trfc = (LPDDR4_TRFC_12GBIT * nmhz + 999) / 1000; tmp = (((LPDDR4_TRFC_12GBIT + 7) * nmhz + (nmhz >> 1) + 999) / 1000); } else if (ddr_capability_per_die > 0x30000000) { pdram_timing->trfc = (LPDDR4_TRFC_6GBIT * nmhz + 999) / 1000; tmp = (((LPDDR4_TRFC_6GBIT + 7) * nmhz + (nmhz >> 1) + 999) / 1000); } else { pdram_timing->trfc = (LPDDR4_TRFC_4GBIT * nmhz + 999) / 1000; tmp = (((LPDDR4_TRFC_4GBIT + 7) * nmhz + (nmhz >> 1) + 999) / 1000); } pdram_timing->txsr = max(2, tmp); pdram_timing->txsnr = max(2, tmp); /* tdqsck use rounded down */ pdram_timing->tdqsck = ((LPDDR4_TDQSCK_MIN * nmhz + (nmhz >> 1)) / 1000); pdram_timing->tdqsck_max = ((LPDDR4_TDQSCK_MAX * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->tppd = LPDDR4_TPPD; /* pd and sr */ tmp = ((LPDDR4_TXP * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->txp = max(5, tmp); tmp = ((LPDDR4_TCKE * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->tcke = max(4, tmp); tmp = ((LPDDR4_TESCKE * nmhz + ((nmhz * 3) / 4) + 999) / 1000); pdram_timing->tescke = max(3, tmp); tmp = ((LPDDR4_TSR * nmhz + 999) / 1000); pdram_timing->tsr = max(3, tmp); tmp = ((LPDDR4_TCMDCKE * nmhz + ((nmhz * 3) / 4) + 999) / 1000); pdram_timing->tcmdcke = max(3, tmp); pdram_timing->tcscke = ((LPDDR4_TCSCKE * nmhz + ((nmhz * 3) / 4) + 999) / 1000); tmp = ((LPDDR4_TCKELCS * nmhz + 999) / 1000); pdram_timing->tckelcs = max(5, tmp); pdram_timing->tcsckeh = ((LPDDR4_TCSCKEH * nmhz + ((nmhz * 3) / 4) + 999) / 1000); tmp = ((LPDDR4_TCKEHCS * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->tckehcs = max(5, tmp); tmp = ((LPDDR4_TMRWCKEL * nmhz + 999) / 1000); pdram_timing->tmrwckel = max(10, tmp); tmp = ((LPDDR4_TCKELCMD * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->tckelcmd = max(3, tmp); tmp = ((LPDDR4_TCKEHCMD * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->tckehcmd = max(3, tmp); tmp = ((LPDDR4_TCKELPD * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->tckelpd = max(3, tmp); tmp = ((LPDDR4_TCKCKEL * nmhz + (nmhz >> 1) + 999) / 1000); pdram_timing->tckckel = max(3, tmp); /* mode register timing */ tmp = ((LPDDR4_TMRD * nmhz + 999) / 1000); pdram_timing->tmrd = max(10, tmp); pdram_timing->tmrr = LPDDR4_TMRR; pdram_timing->tmrri = pdram_timing->trcd + 3; /* ODT */ pdram_timing->todton = (LPDDR4_TODTON * nmhz + (nmhz >> 1) + 999) / 1000; /* ZQ */ pdram_timing->tzqcal = (LPDDR4_TZQCAL * nmhz + 999) / 1000; tmp = ((LPDDR4_TZQLAT * nmhz + 999) / 1000); pdram_timing->tzqlat = max(8, tmp); tmp = ((LPDDR4_TZQRESET * nmhz + 999) / 1000); pdram_timing->tzqreset = max(3, tmp); tmp = ((LPDDR4_TZQCKE * nmhz + ((nmhz * 3) / 4) + 999) / 1000); pdram_timing->tzqcke = max(3, tmp); /* write leveling */ pdram_timing->twlmrd = LPDDR4_TWLMRD; pdram_timing->twlo = (LPDDR4_TWLO * nmhz + 999) / 1000; pdram_timing->twldqsen = LPDDR4_TWLDQSEN; /* CA training */ pdram_timing->tcaent = (LPDDR4_TCAENT * nmhz + 999) / 1000; pdram_timing->tadr = (LPDDR4_TADR * nmhz + 999) / 1000; pdram_timing->tmrz = (LPDDR4_TMRZ * nmhz + (nmhz >> 1) + 999) / 1000; pdram_timing->tvref_long = (LPDDR4_TVREF_LONG * nmhz + 999) / 1000; pdram_timing->tvref_short = (LPDDR4_TVREF_SHORT * nmhz + 999) / 1000; /* VRCG */ pdram_timing->tvrcg_enable = (LPDDR4_TVRCG_ENABLE * nmhz + 999) / 1000; pdram_timing->tvrcg_disable = (LPDDR4_TVRCG_DISABLE * nmhz + 999) / 1000; /* FSP */ pdram_timing->tfc_long = (LPDDR4_TFC_LONG * nmhz + 999) / 1000; tmp = (LPDDR4_TCKFSPE * nmhz + (nmhz >> 1) + 999) / 1000; pdram_timing->tckfspe = max(4, tmp); tmp = (LPDDR4_TCKFSPX * nmhz + (nmhz >> 1) + 999) / 1000; pdram_timing->tckfspx = max(4, tmp); } /* * Description: depend on input parameter "timing_config", * and calculate correspond "dram_type" * spec timing to "pdram_timing" * parameters: * input: timing_config * output: pdram_timing * NOTE: MR ODT is set, need to disable by controller */ void dram_get_parameter(struct timing_related_config *timing_config, struct dram_timing_t *pdram_timing) { switch (timing_config->dram_type) { case DDR3: ddr3_get_parameter(timing_config, pdram_timing); break; case LPDDR2: lpddr2_get_parameter(timing_config, pdram_timing); break; case LPDDR3: lpddr3_get_parameter(timing_config, pdram_timing); break; case LPDDR4: lpddr4_get_parameter(timing_config, pdram_timing); break; default: /* Do nothing in default case */ break; } } trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/dram/dram_spec_timing.h000066400000000000000000000271331355360272700267030ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef DRAM_SPEC_TIMING_H #define DRAM_SPEC_TIMING_H #include enum ddr3_speed_rate { /* 5-5-5 */ DDR3_800D = 0, /* 6-6-6 */ DDR3_800E = 1, /* 6-6-6 */ DDR3_1066E = 2, /* 7-7-7 */ DDR3_1066F = 3, /* 8-8-8 */ DDR3_1066G = 4, /* 7-7-7 */ DDR3_1333F = 5, /* 8-8-8 */ DDR3_1333G = 6, /* 9-9-9 */ DDR3_1333H = 7, /* 10-10-10 */ DDR3_1333J = 8, /* 8-8-8 */ DDR3_1600G = 9, /* 9-9-9 */ DDR3_1600H = 10, /* 10-10-10 */ DDR3_1600J = 11, /* 11-11-11 */ DDR3_1600K = 12, /* 10-10-10 */ DDR3_1866J = 13, /* 11-11-11 */ DDR3_1866K = 14, /* 12-12-12 */ DDR3_1866L = 15, /* 13-13-13 */ DDR3_1866M = 16, /* 11-11-11 */ DDR3_2133K = 17, /* 12-12-12 */ DDR3_2133L = 18, /* 13-13-13 */ DDR3_2133M = 19, /* 14-14-14 */ DDR3_2133N = 20, DDR3_DEFAULT = 21, }; #define max(a, b) (((a) > (b)) ? (a) : (b)) #define range(mi, val, ma) (((ma) > (val)) ? (max(mi, val)) : (ma)) struct dram_timing_t { /* unit MHz */ uint32_t mhz; /* some timing unit is us */ uint32_t tinit1; uint32_t tinit2; uint32_t tinit3; uint32_t tinit4; uint32_t tinit5; /* reset low, DDR3:200us */ uint32_t trstl; /* reset high to CKE high, DDR3:500us */ uint32_t trsth; uint32_t trefi; /* base */ uint32_t trcd; /* trp per bank */ uint32_t trppb; /* trp all bank */ uint32_t trp; uint32_t twr; uint32_t tdal; uint32_t trtp; uint32_t trc; uint32_t trrd; uint32_t tccd; uint32_t twtr; uint32_t trtw; uint32_t tras_max; uint32_t tras_min; uint32_t tfaw; uint32_t trfc; uint32_t tdqsck; uint32_t tdqsck_max; /* pd or sr */ uint32_t txsr; uint32_t txsnr; uint32_t txp; uint32_t txpdll; uint32_t tdllk; uint32_t tcke; uint32_t tckesr; uint32_t tcksre; uint32_t tcksrx; uint32_t tdpd; /* mode regiter timing */ uint32_t tmod; uint32_t tmrd; uint32_t tmrr; uint32_t tmrri; /* ODT */ uint32_t todton; /* ZQ */ uint32_t tzqinit; uint32_t tzqcs; uint32_t tzqoper; uint32_t tzqreset; /* Write Leveling */ uint32_t twlmrd; uint32_t twlo; uint32_t twldqsen; /* CA Training */ uint32_t tcackel; uint32_t tcaent; uint32_t tcamrd; uint32_t tcackeh; uint32_t tcaext; uint32_t tadr; uint32_t tmrz; uint32_t tcacd; /* mode register */ uint32_t mr[4]; uint32_t mr11; /* lpddr4 spec */ uint32_t mr12; uint32_t mr13; uint32_t mr14; uint32_t mr16; uint32_t mr17; uint32_t mr20; uint32_t mr22; uint32_t tccdmw; uint32_t tppd; uint32_t tescke; uint32_t tsr; uint32_t tcmdcke; uint32_t tcscke; uint32_t tckelcs; uint32_t tcsckeh; uint32_t tckehcs; uint32_t tmrwckel; uint32_t tzqcal; uint32_t tzqlat; uint32_t tzqcke; uint32_t tvref_long; uint32_t tvref_short; uint32_t tvrcg_enable; uint32_t tvrcg_disable; uint32_t tfc_long; uint32_t tckfspe; uint32_t tckfspx; uint32_t tckehcmd; uint32_t tckelcmd; uint32_t tckelpd; uint32_t tckckel; /* other */ uint32_t al; uint32_t cl; uint32_t cwl; uint32_t bl; }; struct dram_info_t { /* speed_rate only used when DDR3 */ enum ddr3_speed_rate speed_rate; /* 1: use CS0, 2: use CS0 and CS1 */ uint32_t cs_cnt; /* give the max per-die capability on each rank/cs */ uint32_t per_die_capability[2]; }; struct timing_related_config { struct dram_info_t dram_info[2]; uint32_t dram_type; /* MHz */ uint32_t freq; uint32_t ch_cnt; uint32_t bl; /* 1:auto precharge, 0:never auto precharge */ uint32_t ap; /* * 1:dll bypass, 0:dll normal * dram and controller dll bypass at the same time */ uint32_t dllbp; /* 1:odt enable, 0:odt disable */ uint32_t odt; /* 1:enable, 0:disabe */ uint32_t rdbi; uint32_t wdbi; /* dram driver strength */ uint32_t dramds; /* dram ODT, if odt=0, this parameter invalid */ uint32_t dramodt; /* * ca ODT, if odt=0, this parameter invalid * it only used by LPDDR4 */ uint32_t caodt; }; /* mr0 for ddr3 */ #define DDR3_BL8 (0) #define DDR3_BC4_8 (1) #define DDR3_BC4 (2) #define DDR3_CL(n) (((((n) - 4) & 0x7) << 4)\ | ((((n) - 4) & 0x8) >> 1)) #define DDR3_WR(n) (((n) & 0x7) << 9) #define DDR3_DLL_RESET (1 << 8) #define DDR3_DLL_DERESET (0 << 8) /* mr1 for ddr3 */ #define DDR3_DLL_ENABLE (0) #define DDR3_DLL_DISABLE (1) #define DDR3_MR1_AL(n) (((n) & 0x3) << 3) #define DDR3_DS_40 (0) #define DDR3_DS_34 (1 << 1) #define DDR3_RTT_NOM_DIS (0) #define DDR3_RTT_NOM_60 (1 << 2) #define DDR3_RTT_NOM_120 (1 << 6) #define DDR3_RTT_NOM_40 ((1 << 2) | (1 << 6)) #define DDR3_TDQS (1 << 11) /* mr2 for ddr3 */ #define DDR3_MR2_CWL(n) ((((n) - 5) & 0x7) << 3) #define DDR3_RTT_WR_DIS (0) #define DDR3_RTT_WR_60 (1 << 9) #define DDR3_RTT_WR_120 (2 << 9) /* * MR0 (Device Information) * 0:DAI complete, 1:DAI still in progress */ #define LPDDR2_DAI (0x1) /* 0:S2 or S4 SDRAM, 1:NVM */ #define LPDDR2_DI (0x1 << 1) /* 0:DNV not supported, 1:DNV supported */ #define LPDDR2_DNVI (0x1 << 2) #define LPDDR2_RZQI (0x3 << 3) /* * 00:RZQ self test not supported, * 01:ZQ-pin may connect to VDDCA or float * 10:ZQ-pin may short to GND. * 11:ZQ-pin self test completed, no error condition detected. */ /* MR1 (Device Feature) */ #define LPDDR2_BL4 (0x2) #define LPDDR2_BL8 (0x3) #define LPDDR2_BL16 (0x4) #define LPDDR2_N_WR(n) (((n) - 2) << 5) /* MR2 (Device Feature 2) */ #define LPDDR2_RL3_WL1 (0x1) #define LPDDR2_RL4_WL2 (0x2) #define LPDDR2_RL5_WL2 (0x3) #define LPDDR2_RL6_WL3 (0x4) #define LPDDR2_RL7_WL4 (0x5) #define LPDDR2_RL8_WL4 (0x6) /* MR3 (IO Configuration 1) */ #define LPDDR2_DS_34 (0x1) #define LPDDR2_DS_40 (0x2) #define LPDDR2_DS_48 (0x3) #define LPDDR2_DS_60 (0x4) #define LPDDR2_DS_80 (0x6) /* optional */ #define LPDDR2_DS_120 (0x7) /* MR4 (Device Temperature) */ #define LPDDR2_TREF_MASK (0x7) #define LPDDR2_4_TREF (0x1) #define LPDDR2_2_TREF (0x2) #define LPDDR2_1_TREF (0x3) #define LPDDR2_025_TREF (0x5) #define LPDDR2_025_TREF_DERATE (0x6) #define LPDDR2_TUF (0x1 << 7) /* MR8 (Basic configuration 4) */ #define LPDDR2_S4 (0x0) #define LPDDR2_S2 (0x1) #define LPDDR2_N (0x2) /* Unit:MB */ #define LPDDR2_DENSITY(mr8) (8 << (((mr8) >> 2) & 0xf)) #define LPDDR2_IO_WIDTH(mr8) (32 >> (((mr8) >> 6) & 0x3)) /* MR10 (Calibration) */ #define LPDDR2_ZQINIT (0xff) #define LPDDR2_ZQCL (0xab) #define LPDDR2_ZQCS (0x56) #define LPDDR2_ZQRESET (0xc3) /* MR16 (PASR Bank Mask), S2 SDRAM Only */ #define LPDDR2_PASR_FULL (0x0) #define LPDDR2_PASR_1_2 (0x1) #define LPDDR2_PASR_1_4 (0x2) #define LPDDR2_PASR_1_8 (0x3) /* * MR0 (Device Information) * 0:DAI complete, * 1:DAI still in progress */ #define LPDDR3_DAI (0x1) /* * 00:RZQ self test not supported, * 01:ZQ-pin may connect to VDDCA or float * 10:ZQ-pin may short to GND. * 11:ZQ-pin self test completed, no error condition detected. */ #define LPDDR3_RZQI (0x3 << 3) /* * 0:DRAM does not support WL(Set B), * 1:DRAM support WL(Set B) */ #define LPDDR3_WL_SUPOT (1 << 6) /* * 0:DRAM does not support RL=3,nWR=3,WL=1; * 1:DRAM supports RL=3,nWR=3,WL=1 for frequencies <=166 */ #define LPDDR3_RL3_SUPOT (1 << 7) /* MR1 (Device Feature) */ #define LPDDR3_BL8 (0x3) #define LPDDR3_N_WR(n) ((n) << 5) /* MR2 (Device Feature 2), WL Set A,default */ /* <=166MHz,optional*/ #define LPDDR3_RL3_WL1 (0x1) /* <=400MHz*/ #define LPDDR3_RL6_WL3 (0x4) /* <=533MHz*/ #define LPDDR3_RL8_WL4 (0x6) /* <=600MHz*/ #define LPDDR3_RL9_WL5 (0x7) /* <=667MHz,default*/ #define LPDDR3_RL10_WL6 (0x8) /* <=733MHz*/ #define LPDDR3_RL11_WL6 (0x9) /* <=800MHz*/ #define LPDDR3_RL12_WL6 (0xa) /* <=933MHz*/ #define LPDDR3_RL14_WL8 (0xc) /* <=1066MHz*/ #define LPDDR3_RL16_WL8 (0xe) /* WL Set B, optional */ /* <=667MHz,default*/ #define LPDDR3_RL10_WL8 (0x8) /* <=733MHz*/ #define LPDDR3_RL11_WL9 (0x9) /* <=800MHz*/ #define LPDDR3_RL12_WL9 (0xa) /* <=933MHz*/ #define LPDDR3_RL14_WL11 (0xc) /* <=1066MHz*/ #define LPDDR3_RL16_WL13 (0xe) /* 1:enable nWR programming > 9(default)*/ #define LPDDR3_N_WRE (1 << 4) /* 1:Select WL Set B*/ #define LPDDR3_WL_S (1 << 6) /* 1:enable*/ #define LPDDR3_WR_LEVEL (1 << 7) /* MR3 (IO Configuration 1) */ #define LPDDR3_DS_34 (0x1) #define LPDDR3_DS_40 (0x2) #define LPDDR3_DS_48 (0x3) #define LPDDR3_DS_60 (0x4) #define LPDDR3_DS_80 (0x6) #define LPDDR3_DS_34D_40U (0x9) #define LPDDR3_DS_40D_48U (0xa) #define LPDDR3_DS_34D_48U (0xb) /* MR4 (Device Temperature) */ #define LPDDR3_TREF_MASK (0x7) /* SDRAM Low temperature operating limit exceeded */ #define LPDDR3_LT_EXED (0x0) #define LPDDR3_4_TREF (0x1) #define LPDDR3_2_TREF (0x2) #define LPDDR3_1_TREF (0x3) #define LPDDR3_05_TREF (0x4) #define LPDDR3_025_TREF (0x5) #define LPDDR3_025_TREF_DERATE (0x6) /* SDRAM High temperature operating limit exceeded */ #define LPDDR3_HT_EXED (0x7) /* 1:value has changed since last read of MR4 */ #define LPDDR3_TUF (0x1 << 7) /* MR8 (Basic configuration 4) */ #define LPDDR3_S8 (0x3) #define LPDDR3_DENSITY(mr8) (8 << (((mr8) >> 2) & 0xf)) #define LPDDR3_IO_WIDTH(mr8) (32 >> (((mr8) >> 6) & 0x3)) /* MR10 (Calibration) */ #define LPDDR3_ZQINIT (0xff) #define LPDDR3_ZQCL (0xab) #define LPDDR3_ZQCS (0x56) #define LPDDR3_ZQRESET (0xc3) /* MR11 (ODT Control) */ #define LPDDR3_ODT_60 (1) #define LPDDR3_ODT_120 (2) #define LPDDR3_ODT_240 (3) #define LPDDR3_ODT_DIS (0) /* MR2 (Device Feature 2) */ /* RL & nRTP for DBI-RD Disabled */ #define LPDDR4_RL6_NRTP8 (0x0) #define LPDDR4_RL10_NRTP8 (0x1) #define LPDDR4_RL14_NRTP8 (0x2) #define LPDDR4_RL20_NRTP8 (0x3) #define LPDDR4_RL24_NRTP10 (0x4) #define LPDDR4_RL28_NRTP12 (0x5) #define LPDDR4_RL32_NRTP14 (0x6) #define LPDDR4_RL36_NRTP16 (0x7) /* RL & nRTP for DBI-RD Disabled */ #define LPDDR4_RL12_NRTP8 (0x1) #define LPDDR4_RL16_NRTP8 (0x2) #define LPDDR4_RL22_NRTP8 (0x3) #define LPDDR4_RL28_NRTP10 (0x4) #define LPDDR4_RL32_NRTP12 (0x5) #define LPDDR4_RL36_NRTP14 (0x6) #define LPDDR4_RL40_NRTP16 (0x7) /* WL Set A,default */ #define LPDDR4_A_WL4 (0x0) #define LPDDR4_A_WL6 (0x1) #define LPDDR4_A_WL8 (0x2) #define LPDDR4_A_WL10 (0x3) #define LPDDR4_A_WL12 (0x4) #define LPDDR4_A_WL14 (0x5) #define LPDDR4_A_WL16 (0x6) #define LPDDR4_A_WL18 (0x7) /* WL Set B, optional */ #define LPDDR4_B_WL4 (0x0 << 3) #define LPDDR4_B_WL8 (0x1 << 3) #define LPDDR4_B_WL12 (0x2 << 3) #define LPDDR4_B_WL18 (0x3 << 3) #define LPDDR4_B_WL22 (0x4 << 3) #define LPDDR4_B_WL26 (0x5 << 3) #define LPDDR4_B_WL30 (0x6 << 3) #define LPDDR4_B_WL34 (0x7 << 3) /* 1:Select WL Set B*/ #define LPDDR4_WL_B (1 << 6) /* 1:enable*/ #define LPDDR4_WR_LEVEL (1 << 7) /* MR3 */ #define LPDDR4_VDDQ_2_5 (0) #define LPDDR4_VDDQ_3 (1) #define LPDDR4_WRPST_0_5_TCK (0 << 1) #define LPDDR4_WRPST_1_5_TCK (1 << 1) #define LPDDR4_PPR_EN (1 << 2) /* PDDS */ #define LPDDR4_PDDS_240 (0x1 << 3) #define LPDDR4_PDDS_120 (0x2 << 3) #define LPDDR4_PDDS_80 (0x3 << 3) #define LPDDR4_PDDS_60 (0x4 << 3) #define LPDDR4_PDDS_48 (0x5 << 3) #define LPDDR4_PDDS_40 (0x6 << 3) #define LPDDR4_DBI_RD_EN (1 << 6) #define LPDDR4_DBI_WR_EN (1 << 7) /* MR11 (ODT Control) */ #define LPDDR4_DQODT_240 (1) #define LPDDR4_DQODT_120 (2) #define LPDDR4_DQODT_80 (3) #define LPDDR4_DQODT_60 (4) #define LPDDR4_DQODT_48 (5) #define LPDDR4_DQODT_40 (6) #define LPDDR4_DQODT_DIS (0) #define LPDDR4_CAODT_240 (1 << 4) #define LPDDR4_CAODT_120 (2 << 4) #define LPDDR4_CAODT_80 (3 << 4) #define LPDDR4_CAODT_60 (4 << 4) #define LPDDR4_CAODT_48 (5 << 4) #define LPDDR4_CAODT_40 (6 << 4) #define LPDDR4_CAODT_DIS (0 << 4) /* * Description: depend on input parameter "timing_config", * and calculate correspond "dram_type" * spec timing to "pdram_timing" * parameters: * input: timing_config * output: pdram_timing * NOTE: MR ODT is set, need to disable by controller */ void dram_get_parameter(struct timing_related_config *timing_config, struct dram_timing_t *pdram_timing); #endif /* DRAM_SPEC_TIMING_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/dram/suspend.c000066400000000000000000000545011355360272700250520ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #define PMUGRF_OS_REG0 0x300 #define PMUGRF_OS_REG1 0x304 #define PMUGRF_OS_REG2 0x308 #define PMUGRF_OS_REG3 0x30c #define CRU_SFTRST_DDR_CTRL(ch, n) ((0x1 << (8 + 16 + (ch) * 4)) | \ ((n) << (8 + (ch) * 4))) #define CRU_SFTRST_DDR_PHY(ch, n) ((0x1 << (9 + 16 + (ch) * 4)) | \ ((n) << (9 + (ch) * 4))) #define FBDIV_ENC(n) ((n) << 16) #define FBDIV_DEC(n) (((n) >> 16) & 0xfff) #define POSTDIV2_ENC(n) ((n) << 12) #define POSTDIV2_DEC(n) (((n) >> 12) & 0x7) #define POSTDIV1_ENC(n) ((n) << 8) #define POSTDIV1_DEC(n) (((n) >> 8) & 0x7) #define REFDIV_ENC(n) (n) #define REFDIV_DEC(n) ((n) & 0x3f) /* PMU CRU */ #define PMUCRU_RSTNHOLD_CON0 0x120 #define PMUCRU_RSTNHOLD_CON1 0x124 #define PRESET_GPIO0_HOLD(n) (((n) << 7) | WMSK_BIT(7)) #define PRESET_GPIO1_HOLD(n) (((n) << 8) | WMSK_BIT(8)) #define SYS_COUNTER_FREQ_IN_MHZ (SYS_COUNTER_FREQ_IN_TICKS / 1000000) __pmusramdata uint32_t dpll_data[PLL_CON_COUNT]; __pmusramdata uint32_t cru_clksel_con6; /* * Copy @num registers from @src to @dst */ static __pmusramfunc void sram_regcpy(uintptr_t dst, uintptr_t src, uint32_t num) { while (num--) { mmio_write_32(dst, mmio_read_32(src)); dst += sizeof(uint32_t); src += sizeof(uint32_t); } } /* * Copy @num registers from @src to @dst * This is intentionally a copy of the sram_regcpy function. PMUSRAM functions * cannot be called from code running in DRAM. */ static void dram_regcpy(uintptr_t dst, uintptr_t src, uint32_t num) { while (num--) { mmio_write_32(dst, mmio_read_32(src)); dst += sizeof(uint32_t); src += sizeof(uint32_t); } } static __pmusramfunc uint32_t sram_get_timer_value(void) { /* * Generic delay timer implementation expects the timer to be a down * counter. We apply bitwise NOT operator to the tick values returned * by read_cntpct_el0() to simulate the down counter. */ return (uint32_t)(~read_cntpct_el0()); } static __pmusramfunc void sram_udelay(uint32_t usec) { uint32_t start, cnt, delta, total_ticks; /* counter is decreasing */ start = sram_get_timer_value(); total_ticks = usec * SYS_COUNTER_FREQ_IN_MHZ; do { cnt = sram_get_timer_value(); if (cnt > start) { delta = UINT32_MAX - cnt; delta += start; } else delta = start - cnt; } while (delta <= total_ticks); } static __pmusramfunc void configure_sgrf(void) { /* * SGRF_DDR_RGN_DPLL_CLK and SGRF_DDR_RGN_RTC_CLK: * IC ECO bug, need to set this register. * * SGRF_DDR_RGN_BYPS: * After the PD_CENTER suspend/resume, the DDR region * related registers in the SGRF will be reset, we * need to re-initialize them. */ mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(16), SGRF_DDR_RGN_DPLL_CLK | SGRF_DDR_RGN_RTC_CLK | SGRF_DDR_RGN_BYPS); } static __pmusramfunc void rkclk_ddr_reset(uint32_t channel, uint32_t ctl, uint32_t phy) { channel &= 0x1; ctl &= 0x1; phy &= 0x1; mmio_write_32(CRU_BASE + CRU_SOFTRST_CON(4), CRU_SFTRST_DDR_CTRL(channel, ctl) | CRU_SFTRST_DDR_PHY(channel, phy)); } static __pmusramfunc void phy_pctrl_reset(uint32_t ch) { rkclk_ddr_reset(ch, 1, 1); sram_udelay(10); rkclk_ddr_reset(ch, 1, 0); sram_udelay(10); rkclk_ddr_reset(ch, 0, 0); sram_udelay(10); } static __pmusramfunc void set_cs_training_index(uint32_t ch, uint32_t rank) { uint32_t byte; /* PHY_8/136/264/392 phy_per_cs_training_index_X 1bit offset_24 */ for (byte = 0; byte < 4; byte++) mmio_clrsetbits_32(PHY_REG(ch, 8 + (128 * byte)), 0x1 << 24, rank << 24); } static __pmusramfunc void select_per_cs_training_index(uint32_t ch, uint32_t rank) { /* PHY_84 PHY_PER_CS_TRAINING_EN_0 1bit offset_16 */ if ((mmio_read_32(PHY_REG(ch, 84)) >> 16) & 1) set_cs_training_index(ch, rank); } static __pmusramfunc void override_write_leveling_value(uint32_t ch) { uint32_t byte; for (byte = 0; byte < 4; byte++) { /* * PHY_8/136/264/392 * phy_per_cs_training_multicast_en_X 1bit offset_16 */ mmio_clrsetbits_32(PHY_REG(ch, 8 + (128 * byte)), 0x1 << 16, 1 << 16); mmio_clrsetbits_32(PHY_REG(ch, 63 + (128 * byte)), 0xffffu << 16, 0x200 << 16); } /* CTL_200 ctrlupd_req 1bit offset_8 */ mmio_clrsetbits_32(CTL_REG(ch, 200), 0x1 << 8, 0x1 << 8); } static __pmusramfunc int data_training(uint32_t ch, struct rk3399_sdram_params *sdram_params, uint32_t training_flag) { uint32_t obs_0, obs_1, obs_2, obs_3, obs_err = 0; uint32_t rank = sdram_params->ch[ch].rank; uint32_t rank_mask; uint32_t i, tmp; if (sdram_params->dramtype == LPDDR4) rank_mask = (rank == 1) ? 0x5 : 0xf; else rank_mask = (rank == 1) ? 0x1 : 0x3; /* PHY_927 PHY_PAD_DQS_DRIVE RPULL offset_22 */ mmio_setbits_32(PHY_REG(ch, 927), (1 << 22)); if (training_flag == PI_FULL_TRAINING) { if (sdram_params->dramtype == LPDDR4) { training_flag = PI_WRITE_LEVELING | PI_READ_GATE_TRAINING | PI_READ_LEVELING | PI_WDQ_LEVELING; } else if (sdram_params->dramtype == LPDDR3) { training_flag = PI_CA_TRAINING | PI_WRITE_LEVELING | PI_READ_GATE_TRAINING; } else if (sdram_params->dramtype == DDR3) { training_flag = PI_WRITE_LEVELING | PI_READ_GATE_TRAINING | PI_READ_LEVELING; } } /* ca training(LPDDR4,LPDDR3 support) */ if ((training_flag & PI_CA_TRAINING) == PI_CA_TRAINING) { for (i = 0; i < 4; i++) { if (!(rank_mask & (1 << i))) continue; select_per_cs_training_index(ch, i); /* PI_100 PI_CALVL_EN:RW:8:2 */ mmio_clrsetbits_32(PI_REG(ch, 100), 0x3 << 8, 0x2 << 8); /* PI_92 PI_CALVL_REQ:WR:16:1,PI_CALVL_CS:RW:24:2 */ mmio_clrsetbits_32(PI_REG(ch, 92), (0x1 << 16) | (0x3 << 24), (0x1 << 16) | (i << 24)); while (1) { /* PI_174 PI_INT_STATUS:RD:8:18 */ tmp = mmio_read_32(PI_REG(ch, 174)) >> 8; /* * check status obs * PHY_532/660/788 phy_adr_calvl_obs1_:0:32 */ obs_0 = mmio_read_32(PHY_REG(ch, 532)); obs_1 = mmio_read_32(PHY_REG(ch, 660)); obs_2 = mmio_read_32(PHY_REG(ch, 788)); if (((obs_0 >> 30) & 0x3) || ((obs_1 >> 30) & 0x3) || ((obs_2 >> 30) & 0x3)) obs_err = 1; if ((((tmp >> 11) & 0x1) == 0x1) && (((tmp >> 13) & 0x1) == 0x1) && (((tmp >> 5) & 0x1) == 0x0) && (obs_err == 0)) break; else if ((((tmp >> 5) & 0x1) == 0x1) || (obs_err == 1)) return -1; } /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ mmio_write_32(PI_REG(ch, 175), 0x00003f7c); } mmio_clrbits_32(PI_REG(ch, 100), 0x3 << 8); } /* write leveling(LPDDR4,LPDDR3,DDR3 support) */ if ((training_flag & PI_WRITE_LEVELING) == PI_WRITE_LEVELING) { for (i = 0; i < rank; i++) { select_per_cs_training_index(ch, i); /* PI_60 PI_WRLVL_EN:RW:8:2 */ mmio_clrsetbits_32(PI_REG(ch, 60), 0x3 << 8, 0x2 << 8); /* PI_59 PI_WRLVL_REQ:WR:8:1,PI_WRLVL_CS:RW:16:2 */ mmio_clrsetbits_32(PI_REG(ch, 59), (0x1 << 8) | (0x3 << 16), (0x1 << 8) | (i << 16)); while (1) { /* PI_174 PI_INT_STATUS:RD:8:18 */ tmp = mmio_read_32(PI_REG(ch, 174)) >> 8; /* * check status obs, if error maybe can not * get leveling done PHY_40/168/296/424 * phy_wrlvl_status_obs_X:0:13 */ obs_0 = mmio_read_32(PHY_REG(ch, 40)); obs_1 = mmio_read_32(PHY_REG(ch, 168)); obs_2 = mmio_read_32(PHY_REG(ch, 296)); obs_3 = mmio_read_32(PHY_REG(ch, 424)); if (((obs_0 >> 12) & 0x1) || ((obs_1 >> 12) & 0x1) || ((obs_2 >> 12) & 0x1) || ((obs_3 >> 12) & 0x1)) obs_err = 1; if ((((tmp >> 10) & 0x1) == 0x1) && (((tmp >> 13) & 0x1) == 0x1) && (((tmp >> 4) & 0x1) == 0x0) && (obs_err == 0)) break; else if ((((tmp >> 4) & 0x1) == 0x1) || (obs_err == 1)) return -1; } /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ mmio_write_32(PI_REG(ch, 175), 0x00003f7c); } override_write_leveling_value(ch); mmio_clrbits_32(PI_REG(ch, 60), 0x3 << 8); } /* read gate training(LPDDR4,LPDDR3,DDR3 support) */ if ((training_flag & PI_READ_GATE_TRAINING) == PI_READ_GATE_TRAINING) { for (i = 0; i < rank; i++) { select_per_cs_training_index(ch, i); /* PI_80 PI_RDLVL_GATE_EN:RW:24:2 */ mmio_clrsetbits_32(PI_REG(ch, 80), 0x3 << 24, 0x2 << 24); /* * PI_74 PI_RDLVL_GATE_REQ:WR:16:1 * PI_RDLVL_CS:RW:24:2 */ mmio_clrsetbits_32(PI_REG(ch, 74), (0x1 << 16) | (0x3 << 24), (0x1 << 16) | (i << 24)); while (1) { /* PI_174 PI_INT_STATUS:RD:8:18 */ tmp = mmio_read_32(PI_REG(ch, 174)) >> 8; /* * check status obs * PHY_43/171/299/427 * PHY_GTLVL_STATUS_OBS_x:16:8 */ obs_0 = mmio_read_32(PHY_REG(ch, 43)); obs_1 = mmio_read_32(PHY_REG(ch, 171)); obs_2 = mmio_read_32(PHY_REG(ch, 299)); obs_3 = mmio_read_32(PHY_REG(ch, 427)); if (((obs_0 >> (16 + 6)) & 0x3) || ((obs_1 >> (16 + 6)) & 0x3) || ((obs_2 >> (16 + 6)) & 0x3) || ((obs_3 >> (16 + 6)) & 0x3)) obs_err = 1; if ((((tmp >> 9) & 0x1) == 0x1) && (((tmp >> 13) & 0x1) == 0x1) && (((tmp >> 3) & 0x1) == 0x0) && (obs_err == 0)) break; else if ((((tmp >> 3) & 0x1) == 0x1) || (obs_err == 1)) return -1; } /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ mmio_write_32(PI_REG(ch, 175), 0x00003f7c); } mmio_clrbits_32(PI_REG(ch, 80), 0x3 << 24); } /* read leveling(LPDDR4,LPDDR3,DDR3 support) */ if ((training_flag & PI_READ_LEVELING) == PI_READ_LEVELING) { for (i = 0; i < rank; i++) { select_per_cs_training_index(ch, i); /* PI_80 PI_RDLVL_EN:RW:16:2 */ mmio_clrsetbits_32(PI_REG(ch, 80), 0x3 << 16, 0x2 << 16); /* PI_74 PI_RDLVL_REQ:WR:8:1,PI_RDLVL_CS:RW:24:2 */ mmio_clrsetbits_32(PI_REG(ch, 74), (0x1 << 8) | (0x3 << 24), (0x1 << 8) | (i << 24)); while (1) { /* PI_174 PI_INT_STATUS:RD:8:18 */ tmp = mmio_read_32(PI_REG(ch, 174)) >> 8; /* * make sure status obs not report error bit * PHY_46/174/302/430 * phy_rdlvl_status_obs_X:16:8 */ if ((((tmp >> 8) & 0x1) == 0x1) && (((tmp >> 13) & 0x1) == 0x1) && (((tmp >> 2) & 0x1) == 0x0)) break; else if (((tmp >> 2) & 0x1) == 0x1) return -1; } /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ mmio_write_32(PI_REG(ch, 175), 0x00003f7c); } mmio_clrbits_32(PI_REG(ch, 80), 0x3 << 16); } /* wdq leveling(LPDDR4 support) */ if ((training_flag & PI_WDQ_LEVELING) == PI_WDQ_LEVELING) { for (i = 0; i < 4; i++) { if (!(rank_mask & (1 << i))) continue; select_per_cs_training_index(ch, i); /* * disable PI_WDQLVL_VREF_EN before wdq leveling? * PI_181 PI_WDQLVL_VREF_EN:RW:8:1 */ mmio_clrbits_32(PI_REG(ch, 181), 0x1 << 8); /* PI_124 PI_WDQLVL_EN:RW:16:2 */ mmio_clrsetbits_32(PI_REG(ch, 124), 0x3 << 16, 0x2 << 16); /* PI_121 PI_WDQLVL_REQ:WR:8:1,PI_WDQLVL_CS:RW:16:2 */ mmio_clrsetbits_32(PI_REG(ch, 121), (0x1 << 8) | (0x3 << 16), (0x1 << 8) | (i << 16)); while (1) { /* PI_174 PI_INT_STATUS:RD:8:18 */ tmp = mmio_read_32(PI_REG(ch, 174)) >> 8; if ((((tmp >> 12) & 0x1) == 0x1) && (((tmp >> 13) & 0x1) == 0x1) && (((tmp >> 6) & 0x1) == 0x0)) break; else if (((tmp >> 6) & 0x1) == 0x1) return -1; } /* clear interrupt,PI_175 PI_INT_ACK:WR:0:17 */ mmio_write_32(PI_REG(ch, 175), 0x00003f7c); } mmio_clrbits_32(PI_REG(ch, 124), 0x3 << 16); } /* PHY_927 PHY_PAD_DQS_DRIVE RPULL offset_22 */ mmio_clrbits_32(PHY_REG(ch, 927), (1 << 22)); return 0; } static __pmusramfunc void set_ddrconfig( struct rk3399_sdram_params *sdram_params, unsigned char channel, uint32_t ddrconfig) { /* only need to set ddrconfig */ struct rk3399_sdram_channel *ch = &sdram_params->ch[channel]; unsigned int cs0_cap = 0; unsigned int cs1_cap = 0; cs0_cap = (1 << (ch->cs0_row + ch->col + ch->bk + ch->bw - 20)); if (ch->rank > 1) cs1_cap = cs0_cap >> (ch->cs0_row - ch->cs1_row); if (ch->row_3_4) { cs0_cap = cs0_cap * 3 / 4; cs1_cap = cs1_cap * 3 / 4; } mmio_write_32(MSCH_BASE(channel) + MSCH_DEVICECONF, ddrconfig | (ddrconfig << 6)); mmio_write_32(MSCH_BASE(channel) + MSCH_DEVICESIZE, ((cs0_cap / 32) & 0xff) | (((cs1_cap / 32) & 0xff) << 8)); } static __pmusramfunc void dram_all_config( struct rk3399_sdram_params *sdram_params) { unsigned int i; for (i = 0; i < 2; i++) { struct rk3399_sdram_channel *info = &sdram_params->ch[i]; struct rk3399_msch_timings *noc = &info->noc_timings; if (sdram_params->ch[i].col == 0) continue; mmio_write_32(MSCH_BASE(i) + MSCH_DDRTIMINGA0, noc->ddrtiminga0.d32); mmio_write_32(MSCH_BASE(i) + MSCH_DDRTIMINGB0, noc->ddrtimingb0.d32); mmio_write_32(MSCH_BASE(i) + MSCH_DDRTIMINGC0, noc->ddrtimingc0.d32); mmio_write_32(MSCH_BASE(i) + MSCH_DEVTODEV0, noc->devtodev0.d32); mmio_write_32(MSCH_BASE(i) + MSCH_DDRMODE, noc->ddrmode.d32); /* rank 1 memory clock disable (dfi_dram_clk_disable = 1) */ if (sdram_params->ch[i].rank == 1) mmio_setbits_32(CTL_REG(i, 276), 1 << 17); } DDR_STRIDE(sdram_params->stride); /* reboot hold register set */ mmio_write_32(PMUCRU_BASE + CRU_PMU_RSTHOLD_CON(1), CRU_PMU_SGRF_RST_RLS | PRESET_GPIO0_HOLD(1) | PRESET_GPIO1_HOLD(1)); mmio_clrsetbits_32(CRU_BASE + CRU_GLB_RST_CON, 0x3, 0x3); } static __pmusramfunc void pctl_cfg(uint32_t ch, struct rk3399_sdram_params *sdram_params) { const uint32_t *params_ctl = sdram_params->pctl_regs.denali_ctl; const uint32_t *params_pi = sdram_params->pi_regs.denali_pi; const struct rk3399_ddr_publ_regs *phy_regs = &sdram_params->phy_regs; uint32_t tmp, tmp1, tmp2, i; /* * Workaround controller bug: * Do not program DRAM_CLASS until NO_PHY_IND_TRAIN_INT is programmed */ sram_regcpy(CTL_REG(ch, 1), (uintptr_t)¶ms_ctl[1], CTL_REG_NUM - 1); mmio_write_32(CTL_REG(ch, 0), params_ctl[0]); sram_regcpy(PI_REG(ch, 0), (uintptr_t)¶ms_pi[0], PI_REG_NUM); sram_regcpy(PHY_REG(ch, 910), (uintptr_t)&phy_regs->phy896[910 - 896], 3); mmio_clrsetbits_32(CTL_REG(ch, 68), PWRUP_SREFRESH_EXIT, PWRUP_SREFRESH_EXIT); /* PHY_DLL_RST_EN */ mmio_clrsetbits_32(PHY_REG(ch, 957), 0x3 << 24, 1 << 24); dmbst(); mmio_setbits_32(PI_REG(ch, 0), START); mmio_setbits_32(CTL_REG(ch, 0), START); /* wait lock */ while (1) { tmp = mmio_read_32(PHY_REG(ch, 920)); tmp1 = mmio_read_32(PHY_REG(ch, 921)); tmp2 = mmio_read_32(PHY_REG(ch, 922)); if ((((tmp >> 16) & 0x1) == 0x1) && (((tmp1 >> 16) & 0x1) == 0x1) && (((tmp1 >> 0) & 0x1) == 0x1) && (((tmp2 >> 0) & 0x1) == 0x1)) break; /* if PLL bypass,don't need wait lock */ if (mmio_read_32(PHY_REG(ch, 911)) & 0x1) break; } sram_regcpy(PHY_REG(ch, 896), (uintptr_t)&phy_regs->phy896[0], 63); for (i = 0; i < 4; i++) sram_regcpy(PHY_REG(ch, 128 * i), (uintptr_t)&phy_regs->phy0[0], 91); for (i = 0; i < 3; i++) sram_regcpy(PHY_REG(ch, 512 + 128 * i), (uintptr_t)&phy_regs->phy512[i][0], 38); } static __pmusramfunc int dram_switch_to_next_index( struct rk3399_sdram_params *sdram_params) { uint32_t ch, ch_count; uint32_t fn = ((mmio_read_32(CTL_REG(0, 111)) >> 16) + 1) & 0x1; mmio_write_32(CIC_BASE + CIC_CTRL0, (((0x3 << 4) | (1 << 2) | 1) << 16) | (fn << 4) | (1 << 2) | 1); while (!(mmio_read_32(CIC_BASE + CIC_STATUS0) & (1 << 2))) ; mmio_write_32(CIC_BASE + CIC_CTRL0, 0x20002); while (!(mmio_read_32(CIC_BASE + CIC_STATUS0) & (1 << 0))) ; ch_count = sdram_params->num_channels; /* LPDDR4 f2 cann't do training, all training will fail */ for (ch = 0; ch < ch_count; ch++) { mmio_clrsetbits_32(PHY_REG(ch, 896), (0x3 << 8) | 1, fn << 8); /* data_training failed */ if (data_training(ch, sdram_params, PI_FULL_TRAINING)) return -1; } return 0; } /* * Needs to be done for both channels at once in case of a shared reset signal * between channels. */ static __pmusramfunc int pctl_start(uint32_t channel_mask, struct rk3399_sdram_params *sdram_params) { uint32_t count; uint32_t byte; mmio_setbits_32(CTL_REG(0, 68), PWRUP_SREFRESH_EXIT); mmio_setbits_32(CTL_REG(1, 68), PWRUP_SREFRESH_EXIT); /* need de-access IO retention before controller START */ if (channel_mask & (1 << 0)) mmio_setbits_32(PMU_BASE + PMU_PWRMODE_CON, (1 << 19)); if (channel_mask & (1 << 1)) mmio_setbits_32(PMU_BASE + PMU_PWRMODE_CON, (1 << 23)); /* PHY_DLL_RST_EN */ if (channel_mask & (1 << 0)) mmio_clrsetbits_32(PHY_REG(0, 957), 0x3 << 24, 0x2 << 24); if (channel_mask & (1 << 1)) mmio_clrsetbits_32(PHY_REG(1, 957), 0x3 << 24, 0x2 << 24); /* check ERROR bit */ if (channel_mask & (1 << 0)) { count = 0; while (!(mmio_read_32(CTL_REG(0, 203)) & (1 << 3))) { /* CKE is low, loop 10ms */ if (count > 100) return -1; sram_udelay(100); count++; } mmio_clrbits_32(CTL_REG(0, 68), PWRUP_SREFRESH_EXIT); /* Restore the PHY_RX_CAL_DQS value */ for (byte = 0; byte < 4; byte++) mmio_clrsetbits_32(PHY_REG(0, 57 + 128 * byte), 0xfff << 16, sdram_params->rx_cal_dqs[0][byte]); } if (channel_mask & (1 << 1)) { count = 0; while (!(mmio_read_32(CTL_REG(1, 203)) & (1 << 3))) { /* CKE is low, loop 10ms */ if (count > 100) return -1; sram_udelay(100); count++; } mmio_clrbits_32(CTL_REG(1, 68), PWRUP_SREFRESH_EXIT); /* Restore the PHY_RX_CAL_DQS value */ for (byte = 0; byte < 4; byte++) mmio_clrsetbits_32(PHY_REG(1, 57 + 128 * byte), 0xfff << 16, sdram_params->rx_cal_dqs[1][byte]); } return 0; } __pmusramfunc static void pmusram_restore_pll(int pll_id, uint32_t *src) { mmio_write_32((CRU_BASE + CRU_PLL_CON(pll_id, 3)), PLL_SLOW_MODE); mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 0), src[0] | REG_SOC_WMSK); mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 1), src[1] | REG_SOC_WMSK); mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 2), src[2]); mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 4), src[4] | REG_SOC_WMSK); mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 5), src[5] | REG_SOC_WMSK); mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3), src[3] | REG_SOC_WMSK); while ((mmio_read_32(CRU_BASE + CRU_PLL_CON(pll_id, 2)) & (1U << 31)) == 0x0) ; } __pmusramfunc static void pmusram_enable_watchdog(void) { /* Make the watchdog use the first global reset. */ mmio_write_32(CRU_BASE + CRU_GLB_RST_CON, 1 << 1); /* * This gives the system ~8 seconds before reset. The pclk for the * watchdog is 4MHz on reset. The value of 0x9 in WDT_TORR means that * the watchdog will wait for 0x1ffffff cycles before resetting. */ mmio_write_32(WDT0_BASE + 4, 0x9); /* Enable the watchdog */ mmio_setbits_32(WDT0_BASE, 0x1); /* Magic reset the watchdog timer value for WDT_CRR. */ mmio_write_32(WDT0_BASE + 0xc, 0x76); secure_watchdog_ungate(); /* The watchdog is in PD_ALIVE, so deidle it. */ mmio_clrbits_32(PMU_BASE + PMU_BUS_CLR, PMU_CLR_ALIVE); } void dmc_suspend(void) { struct rk3399_sdram_params *sdram_params = &sdram_config; struct rk3399_ddr_publ_regs *phy_regs; uint32_t *params_ctl; uint32_t *params_pi; uint32_t refdiv, postdiv2, postdiv1, fbdiv; uint32_t ch, byte, i; phy_regs = &sdram_params->phy_regs; params_ctl = sdram_params->pctl_regs.denali_ctl; params_pi = sdram_params->pi_regs.denali_pi; /* save dpll register and ddr clock register value to pmusram */ cru_clksel_con6 = mmio_read_32(CRU_BASE + CRU_CLKSEL_CON6); for (i = 0; i < PLL_CON_COUNT; i++) dpll_data[i] = mmio_read_32(CRU_BASE + CRU_PLL_CON(DPLL_ID, i)); fbdiv = dpll_data[0] & 0xfff; postdiv2 = POSTDIV2_DEC(dpll_data[1]); postdiv1 = POSTDIV1_DEC(dpll_data[1]); refdiv = REFDIV_DEC(dpll_data[1]); sdram_params->ddr_freq = ((fbdiv * 24) / (refdiv * postdiv1 * postdiv2)) * MHz; INFO("sdram_params->ddr_freq = %d\n", sdram_params->ddr_freq); sdram_params->odt = (((mmio_read_32(PHY_REG(0, 5)) >> 16) & 0x7) != 0) ? 1 : 0; /* copy the registers CTL PI and PHY */ dram_regcpy((uintptr_t)¶ms_ctl[0], CTL_REG(0, 0), CTL_REG_NUM); /* mask DENALI_CTL_00_DATA.START, only copy here, will trigger later */ params_ctl[0] &= ~(0x1 << 0); dram_regcpy((uintptr_t)¶ms_pi[0], PI_REG(0, 0), PI_REG_NUM); /* mask DENALI_PI_00_DATA.START, only copy here, will trigger later*/ params_pi[0] &= ~(0x1 << 0); dram_regcpy((uintptr_t)&phy_regs->phy0[0], PHY_REG(0, 0), 91); for (i = 0; i < 3; i++) dram_regcpy((uintptr_t)&phy_regs->phy512[i][0], PHY_REG(0, 512 + 128 * i), 38); dram_regcpy((uintptr_t)&phy_regs->phy896[0], PHY_REG(0, 896), 63); for (ch = 0; ch < sdram_params->num_channels; ch++) { for (byte = 0; byte < 4; byte++) sdram_params->rx_cal_dqs[ch][byte] = (0xfff << 16) & mmio_read_32(PHY_REG(ch, 57 + byte * 128)); } /* set DENALI_PHY_957_DATA.PHY_DLL_RST_EN = 0x1 */ phy_regs->phy896[957 - 896] &= ~(0x3 << 24); phy_regs->phy896[957 - 896] |= 1 << 24; phy_regs->phy896[0] |= 1; phy_regs->phy896[0] &= ~(0x3 << 8); } __pmusramfunc void dmc_resume(void) { struct rk3399_sdram_params *sdram_params = &sdram_config; uint32_t channel_mask = 0; uint32_t channel; pmusram_enable_watchdog(); pmu_sgrf_rst_hld_release(); restore_pmu_rsthold(); sram_secure_timer_init(); /* * we switch ddr clock to abpll when suspend, * we set back to dpll here */ mmio_write_32(CRU_BASE + CRU_CLKSEL_CON6, cru_clksel_con6 | REG_SOC_WMSK); pmusram_restore_pll(DPLL_ID, dpll_data); configure_sgrf(); retry: for (channel = 0; channel < sdram_params->num_channels; channel++) { phy_pctrl_reset(channel); pctl_cfg(channel, sdram_params); } for (channel = 0; channel < 2; channel++) { if (sdram_params->ch[channel].col) channel_mask |= 1 << channel; } if (pctl_start(channel_mask, sdram_params) < 0) goto retry; for (channel = 0; channel < sdram_params->num_channels; channel++) { /* LPDDR2/LPDDR3 need to wait DAI complete, max 10us */ if (sdram_params->dramtype == LPDDR3) sram_udelay(10); /* If traning fail, retry to do it again. */ if (data_training(channel, sdram_params, PI_FULL_TRAINING)) goto retry; set_ddrconfig(sdram_params, channel, sdram_params->ch[channel].ddrconfig); } dram_all_config(sdram_params); /* Switch to index 1 and prepare for DDR frequency switch. */ dram_switch_to_next_index(sdram_params); } trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/dram/suspend.h000066400000000000000000000010411355360272700250460ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SUSPEND_H #define SUSPEND_H #include #define KHz (1000) #define MHz (1000 * KHz) #define GHz (1000 * MHz) #define PI_CA_TRAINING (1 << 0) #define PI_WRITE_LEVELING (1 << 1) #define PI_READ_GATE_TRAINING (1 << 2) #define PI_READ_LEVELING (1 << 3) #define PI_WDQ_LEVELING (1 << 4) #define PI_FULL_TRAINING (0xff) void dmc_suspend(void); __pmusramfunc void dmc_resume(void); #endif /* SUSPEND_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/gpio/000077500000000000000000000000001355360272700232335ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/gpio/rk3399_gpio.c000066400000000000000000000251361355360272700253700ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include uint32_t gpio_port[] = { GPIO0_BASE, GPIO1_BASE, GPIO2_BASE, GPIO3_BASE, GPIO4_BASE, }; struct { uint32_t swporta_dr; uint32_t swporta_ddr; uint32_t inten; uint32_t intmask; uint32_t inttype_level; uint32_t int_polarity; uint32_t debounce; uint32_t ls_sync; } store_gpio[3]; static uint32_t store_grf_gpio[(GRF_GPIO2D_HE - GRF_GPIO2A_IOMUX) / 4 + 1]; #define SWPORTA_DR 0x00 #define SWPORTA_DDR 0x04 #define INTEN 0x30 #define INTMASK 0x34 #define INTTYPE_LEVEL 0x38 #define INT_POLARITY 0x3c #define DEBOUNCE 0x48 #define LS_SYNC 0x60 #define EXT_PORTA 0x50 #define PMU_GPIO_PORT0 0 #define PMU_GPIO_PORT1 1 #define GPIO_PORT2 2 #define GPIO_PORT3 3 #define GPIO_PORT4 4 #define PMU_GRF_GPIO0A_P 0x40 #define GRF_GPIO2A_P 0xe040 #define GPIO_P_MASK 0x03 #define GET_GPIO_PORT(pin) (pin / 32) #define GET_GPIO_NUM(pin) (pin % 32) #define GET_GPIO_BANK(pin) ((pin % 32) / 8) #define GET_GPIO_ID(pin) ((pin % 32) % 8) /* returns old clock state, enables clock, in order to do GPIO access */ static int gpio_get_clock(uint32_t gpio_number) { uint32_t port = GET_GPIO_PORT(gpio_number); uint32_t clock_state = 0; assert(port < 5); switch (port) { case PMU_GPIO_PORT0: clock_state = (mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1)) >> PCLK_GPIO0_GATE_SHIFT) & 0x01; mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), BITS_WITH_WMASK(0, CLK_GATE_MASK, PCLK_GPIO0_GATE_SHIFT)); break; case PMU_GPIO_PORT1: clock_state = (mmio_read_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1)) >> PCLK_GPIO1_GATE_SHIFT) & 0x01; mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), BITS_WITH_WMASK(0, CLK_GATE_MASK, PCLK_GPIO1_GATE_SHIFT)); break; case GPIO_PORT2: clock_state = (mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31)) >> PCLK_GPIO2_GATE_SHIFT) & 0x01; mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), BITS_WITH_WMASK(0, CLK_GATE_MASK, PCLK_GPIO2_GATE_SHIFT)); break; case GPIO_PORT3: clock_state = (mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31)) >> PCLK_GPIO3_GATE_SHIFT) & 0x01; mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), BITS_WITH_WMASK(0, CLK_GATE_MASK, PCLK_GPIO3_GATE_SHIFT)); break; case GPIO_PORT4: clock_state = (mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31)) >> PCLK_GPIO4_GATE_SHIFT) & 0x01; mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), BITS_WITH_WMASK(0, CLK_GATE_MASK, PCLK_GPIO4_GATE_SHIFT)); break; default: break; } return clock_state; } /* restores old state of gpio clock */ void gpio_put_clock(uint32_t gpio_number, uint32_t clock_state) { uint32_t port = GET_GPIO_PORT(gpio_number); switch (port) { case PMU_GPIO_PORT0: mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, PCLK_GPIO0_GATE_SHIFT)); break; case PMU_GPIO_PORT1: mmio_write_32(PMUCRU_BASE + CRU_PMU_CLKGATE_CON(1), BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, PCLK_GPIO1_GATE_SHIFT)); break; case GPIO_PORT2: mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, PCLK_GPIO2_GATE_SHIFT)); break; case GPIO_PORT3: mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, PCLK_GPIO3_GATE_SHIFT)); break; case GPIO_PORT4: mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), BITS_WITH_WMASK(clock_state, CLK_GATE_MASK, PCLK_GPIO4_GATE_SHIFT)); break; default: break; } } static int get_pull(int gpio) { uint32_t port = GET_GPIO_PORT(gpio); uint32_t bank = GET_GPIO_BANK(gpio); uint32_t id = GET_GPIO_ID(gpio); uint32_t val, clock_state; assert((port < 5) && (bank < 4)); clock_state = gpio_get_clock(gpio); if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) { val = mmio_read_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P + port * 16 + bank * 4); val = (val >> (id * 2)) & GPIO_P_MASK; } else { val = mmio_read_32(GRF_BASE + GRF_GPIO2A_P + (port - 2) * 16 + bank * 4); val = (val >> (id * 2)) & GPIO_P_MASK; } gpio_put_clock(gpio, clock_state); /* * in gpio0a, gpio0b, gpio2c, gpio2d, * 00: Z * 01: pull down * 10: Z * 11: pull up * different with other gpio, so need to correct it */ if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) { if (val == 3) val = GPIO_PULL_UP; else if (val == 1) val = GPIO_PULL_DOWN; else val = 0; } return val; } static void set_pull(int gpio, int pull) { uint32_t port = GET_GPIO_PORT(gpio); uint32_t bank = GET_GPIO_BANK(gpio); uint32_t id = GET_GPIO_ID(gpio); uint32_t clock_state; assert((port < 5) && (bank < 4)); clock_state = gpio_get_clock(gpio); /* * in gpio0a, gpio0b, gpio2c, gpio2d, * 00: Z * 01: pull down * 10: Z * 11: pull up * different with other gpio, so need to correct it */ if (((port == 0) && (bank < 2)) || ((port == 2) && (bank > 1))) { if (pull == GPIO_PULL_UP) pull = 3; else if (pull == GPIO_PULL_DOWN) pull = 1; else pull = 0; } if (port == PMU_GPIO_PORT0 || port == PMU_GPIO_PORT1) { mmio_write_32(PMUGRF_BASE + PMU_GRF_GPIO0A_P + port * 16 + bank * 4, BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2)); } else { mmio_write_32(GRF_BASE + GRF_GPIO2A_P + (port - 2) * 16 + bank * 4, BITS_WITH_WMASK(pull, GPIO_P_MASK, id * 2)); } gpio_put_clock(gpio, clock_state); } static void set_direction(int gpio, int direction) { uint32_t port = GET_GPIO_PORT(gpio); uint32_t num = GET_GPIO_NUM(gpio); uint32_t clock_state; assert((port < 5) && (num < 32)); clock_state = gpio_get_clock(gpio); /* * in gpio.h * #define GPIO_DIR_OUT 0 * #define GPIO_DIR_IN 1 * but rk3399 gpio direction 1: output, 0: input * so need to revert direction value */ mmio_setbits_32(gpio_port[port] + SWPORTA_DDR, !direction << num); gpio_put_clock(gpio, clock_state); } static int get_direction(int gpio) { uint32_t port = GET_GPIO_PORT(gpio); uint32_t num = GET_GPIO_NUM(gpio); int direction, clock_state; assert((port < 5) && (num < 32)); clock_state = gpio_get_clock(gpio); /* * in gpio.h * #define GPIO_DIR_OUT 0 * #define GPIO_DIR_IN 1 * but rk3399 gpio direction 1: output, 0: input * so need to revert direction value */ direction = !((mmio_read_32(gpio_port[port] + SWPORTA_DDR) >> num) & 0x1); gpio_put_clock(gpio, clock_state); return direction; } static int get_value(int gpio) { uint32_t port = GET_GPIO_PORT(gpio); uint32_t num = GET_GPIO_NUM(gpio); int value, clock_state; assert((port < 5) && (num < 32)); clock_state = gpio_get_clock(gpio); value = (mmio_read_32(gpio_port[port] + EXT_PORTA) >> num) & 0x1; gpio_put_clock(gpio, clock_state); return value; } static void set_value(int gpio, int value) { uint32_t port = GET_GPIO_PORT(gpio); uint32_t num = GET_GPIO_NUM(gpio); uint32_t clock_state; assert((port < 5) && (num < 32)); clock_state = gpio_get_clock(gpio); mmio_clrsetbits_32(gpio_port[port] + SWPORTA_DR, 1 << num, !!value << num); gpio_put_clock(gpio, clock_state); } void plat_rockchip_save_gpio(void) { int i; uint32_t cru_gate_save; cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31)); /* * when shutdown logic, we need to save gpio2 ~ gpio4 register, * we need to enable gpio2 ~ gpio4 clock here, since it may be gating, * and we do not care gpio0 and gpio1 clock gate, since we never * gating them */ mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT)); /* * since gpio0, gpio1 are pmugpio, they will keep ther value * when shutdown logic power rail, so only need to save gpio2 ~ gpio4 * register value */ for (i = 2; i < 5; i++) { store_gpio[i - 2].swporta_dr = mmio_read_32(gpio_port[i] + SWPORTA_DR); store_gpio[i - 2].swporta_ddr = mmio_read_32(gpio_port[i] + SWPORTA_DDR); store_gpio[i - 2].inten = mmio_read_32(gpio_port[i] + INTEN); store_gpio[i - 2].intmask = mmio_read_32(gpio_port[i] + INTMASK); store_gpio[i - 2].inttype_level = mmio_read_32(gpio_port[i] + INTTYPE_LEVEL); store_gpio[i - 2].int_polarity = mmio_read_32(gpio_port[i] + INT_POLARITY); store_gpio[i - 2].debounce = mmio_read_32(gpio_port[i] + DEBOUNCE); store_gpio[i - 2].ls_sync = mmio_read_32(gpio_port[i] + LS_SYNC); } mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), cru_gate_save | REG_SOC_WMSK); /* * gpio0, gpio1 in pmuiomux, they will keep ther value * when shutdown logic power rail, so only need to save gpio2 ~ gpio4 * iomux register value */ for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++) store_grf_gpio[i] = mmio_read_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4); } void plat_rockchip_restore_gpio(void) { int i; uint32_t cru_gate_save; for (i = 0; i < ARRAY_SIZE(store_grf_gpio); i++) mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4, REG_SOC_WMSK | store_grf_gpio[i]); cru_gate_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31)); /* * when shutdown logic, we need to save gpio2 ~ gpio4 register, * we need to enable gpio2 ~ gpio4 clock here, since it may be gating, * and we do not care gpio0 and gpio1 clock gate, since we never * gating them */ mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT)); for (i = 2; i < 5; i++) { mmio_write_32(gpio_port[i] + SWPORTA_DR, store_gpio[i - 2].swporta_dr); mmio_write_32(gpio_port[i] + SWPORTA_DDR, store_gpio[i - 2].swporta_ddr); mmio_write_32(gpio_port[i] + INTEN, store_gpio[i - 2].inten); mmio_write_32(gpio_port[i] + INTMASK, store_gpio[i - 2].intmask); mmio_write_32(gpio_port[i] + INTTYPE_LEVEL, store_gpio[i - 2].inttype_level); mmio_write_32(gpio_port[i] + INT_POLARITY, store_gpio[i - 2].int_polarity); mmio_write_32(gpio_port[i] + DEBOUNCE, store_gpio[i - 2].debounce); mmio_write_32(gpio_port[i] + LS_SYNC, store_gpio[i - 2].ls_sync); } mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), cru_gate_save | REG_SOC_WMSK); } const gpio_ops_t rk3399_gpio_ops = { .get_direction = get_direction, .set_direction = set_direction, .get_value = get_value, .set_value = set_value, .set_pull = set_pull, .get_pull = get_pull, }; void plat_rockchip_gpio_init(void) { gpio_init(&rk3399_gpio_ops); } trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/m0/000077500000000000000000000000001355360272700226115ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/m0/Makefile000066400000000000000000000071101355360272700242500ustar00rootroot00000000000000# # Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # Cross Compile M0_CROSS_COMPILE ?= arm-none-eabi- # Build architecture ARCH := cortex-m0 # Build platform PLAT_M0 ?= rk3399m0 PLAT_M0_PMU ?= rk3399m0pmu ifeq (${V},0) Q=@ else Q= endif export Q .SUFFIXES: INCLUDES += -Iinclude/ \ -I../../include/shared/ # NOTE: Add C source files here C_SOURCES_COMMON := src/startup.c C_SOURCES := src/dram.c \ src/stopwatch.c C_SOURCES_PMU := src/suspend.c # Flags definition COMMON_FLAGS := -g -mcpu=$(ARCH) -mthumb -Wall -O3 -nostdlib -mfloat-abi=soft CFLAGS := -ffunction-sections -fdata-sections -fomit-frame-pointer -fno-common ASFLAGS := -Wa,--gdwarf-2 LDFLAGS := -Wl,--gc-sections -Wl,--build-id=none # Cross tool CC := ${M0_CROSS_COMPILE}gcc CPP := ${M0_CROSS_COMPILE}cpp AR := ${M0_CROSS_COMPILE}ar OC := ${M0_CROSS_COMPILE}objcopy OD := ${M0_CROSS_COMPILE}objdump NM := ${M0_CROSS_COMPILE}nm # NOTE: The line continuation '\' is required in the next define otherwise we # end up with a line-feed characer at the end of the last c filename. # Also bare this issue in mind if extending the list of supported filetypes. define SOURCES_TO_OBJS $(notdir $(patsubst %.c,%.o,$(filter %.c,$(1)))) \ $(notdir $(patsubst %.S,%.o,$(filter %.S,$(1)))) endef SOURCES_COMMON := $(C_SOURCES_COMMON) SOURCES := $(C_SOURCES) SOURCES_PMU := $(C_SOURCES_PMU) OBJS_COMMON := $(addprefix $(BUILD)/,$(call SOURCES_TO_OBJS,$(SOURCES_COMMON))) OBJS := $(addprefix $(BUILD)/,$(call SOURCES_TO_OBJS,$(SOURCES))) OBJS_PMU := $(addprefix $(BUILD)/,$(call SOURCES_TO_OBJS,$(SOURCES_PMU))) LINKERFILE := $(BUILD)/$(PLAT_M0).ld MAPFILE := $(BUILD)/$(PLAT_M0).map MAPFILE_PMU := $(BUILD)/$(PLAT_M0_PMU).map ELF := $(BUILD)/$(PLAT_M0).elf ELF_PMU := $(BUILD)/$(PLAT_M0_PMU).elf BIN := $(BUILD)/$(PLAT_M0).bin BIN_PMU := $(BUILD)/$(PLAT_M0_PMU).bin LINKERFILE_SRC := src/$(PLAT_M0).ld.S # Function definition related compilation define MAKE_C $(eval OBJ := $(1)/$(patsubst %.c,%.o,$(notdir $(2)))) -include $(patsubst %.o,%.d,$(OBJ)) $(OBJ) : $(2) @echo " CC $$<" $$(Q)$$(CC) $$(COMMON_FLAGS) $$(CFLAGS) $$(INCLUDES) -MMD -MT $$@ -c $$< -o $$@ endef define MAKE_S $(eval OBJ := $(1)/$(patsubst %.S,%.o,$(notdir $(2)))) $(OBJ) : $(2) @echo " AS $$<" $$(Q)$$(CC) -x assembler-with-cpp $$(COMMON_FLAGS) $$(ASFLAGS) -c $$< -o $$@ endef define MAKE_OBJS $(eval C_OBJS := $(filter %.c,$(2))) $(eval REMAIN := $(filter-out %.c,$(2))) $(eval $(foreach obj,$(C_OBJS),$(call MAKE_C,$(1),$(obj),$(3)))) $(eval S_OBJS := $(filter %.S,$(REMAIN))) $(eval REMAIN := $(filter-out %.S,$(REMAIN))) $(eval $(foreach obj,$(S_OBJS),$(call MAKE_S,$(1),$(obj),$(3)))) $(and $(REMAIN),$(error Unexpected source files present: $(REMAIN))) endef .PHONY: all all: $(BIN) $(BIN_PMU) .DEFAULT_GOAL := all $(LINKERFILE): $(LINKERFILE_SRC) $(CC) $(COMMON_FLAGS) $(INCLUDES) -P -E -D__LINKER__ -MMD -MF $@.d -MT $@ -o $@ $< -include $(LINKERFILE).d $(ELF) : $(OBJS) $(OBJS_COMMON) $(LINKERFILE) @echo " LD $@" $(Q)$(CC) -o $@ $(COMMON_FLAGS) $(LDFLAGS) -Wl,-Map=$(MAPFILE) -Wl,-T$(LINKERFILE) $(OBJS) $(OBJS_COMMON) %.bin : %.elf @echo " BIN $@" $(Q)$(OC) -O binary $< $@ $(ELF_PMU) : $(OBJS_COMMON) $(OBJS_PMU) $(LINKERFILE) @echo " LD $@" $(Q)$(CC) -o $@ $(COMMON_FLAGS) $(LDFLAGS) -Wl,-Map=$(MAPFILE_PMU) -Wl,-T$(LINKERFILE) $(OBJS_PMU) $(OBJS_COMMON) $(eval $(call MAKE_OBJS,$(BUILD),$(SOURCES_COMMON),$(1))) $(eval $(call MAKE_OBJS,$(BUILD),$(SOURCES),$(1))) $(eval $(call MAKE_OBJS,$(BUILD),$(SOURCES_PMU),$(1))) trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/m0/include/000077500000000000000000000000001355360272700242345ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/m0/include/addressmap.h000066400000000000000000000004471355360272700265350ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ADDRESSMAP_H #define ADDRESSMAP_H #include /* Registers base address for M0 */ #define MMIO_BASE 0x40000000 #endif /* ADDRESSMAP_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/m0/include/rk3399_mcu.h000066400000000000000000000016101355360272700262130ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RK3399_MCU_H #define RK3399_MCU_H #include typedef unsigned int uint32_t; #define mmio_read_32(c) ({unsigned int __v = \ (*(volatile unsigned int *)(c)); __v; }) #define mmio_write_32(c, v) ((*(volatile unsigned int *)(c)) = (v)) #define mmio_clrbits_32(addr, clear) \ mmio_write_32(addr, (mmio_read_32(addr) & ~(clear))) #define mmio_setbits_32(addr, set) \ mmio_write_32(addr, (mmio_read_32(addr)) | (set)) #define mmio_clrsetbits_32(addr, clear, set) \ mmio_write_32(addr, (mmio_read_32(addr) & ~(clear)) | (set)) #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) void stopwatch_init_usecs_expire(unsigned int usecs); int stopwatch_expired(void); void stopwatch_reset(void); #endif /* RK3399_MCU_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/m0/src/000077500000000000000000000000001355360272700234005ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/m0/src/dram.c000066400000000000000000000046251355360272700244760ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "misc_regs.h" #include "rk3399_mcu.h" static uint32_t gatedis_con0; static void idle_port(void) { gatedis_con0 = mmio_read_32(PMUCRU_BASE + PMU_CRU_GATEDIS_CON0); mmio_write_32(PMUCRU_BASE + PMU_CRU_GATEDIS_CON0, 0x3fffffff); mmio_setbits_32(PMU_BASE + PMU_BUS_IDLE_REQ, (1 << PMU_IDLE_REQ_MSCH0) | (1 << PMU_IDLE_REQ_MSCH1)); while ((mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & ((1 << PMU_IDLE_ST_MSCH1) | (1 << PMU_IDLE_ST_MSCH0))) != ((1 << PMU_IDLE_ST_MSCH1) | (1 << PMU_IDLE_ST_MSCH0))) continue; } static void deidle_port(void) { mmio_clrbits_32(PMU_BASE + PMU_BUS_IDLE_REQ, (1 << PMU_IDLE_REQ_MSCH0) | (1 << PMU_IDLE_REQ_MSCH1)); while (mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & ((1 << PMU_IDLE_ST_MSCH1) | (1 << PMU_IDLE_ST_MSCH0))) continue; /* document is wrong, PMU_CRU_GATEDIS_CON0 do not need set MASK BIT */ mmio_write_32(PMUCRU_BASE + PMU_CRU_GATEDIS_CON0, gatedis_con0); } static void ddr_set_pll(void) { mmio_write_32(CRU_BASE + CRU_DPLL_CON3, PLL_MODE(PLL_SLOW_MODE)); mmio_write_32(CRU_BASE + CRU_DPLL_CON3, PLL_POWER_DOWN(1)); mmio_write_32(CRU_BASE + CRU_DPLL_CON0, mmio_read_32(PARAM_ADDR + PARAM_DPLL_CON0)); mmio_write_32(CRU_BASE + CRU_DPLL_CON1, mmio_read_32(PARAM_ADDR + PARAM_DPLL_CON1)); mmio_write_32(CRU_BASE + CRU_DPLL_CON3, PLL_POWER_DOWN(0)); while ((mmio_read_32(CRU_BASE + CRU_DPLL_CON2) & (1u << 31)) == 0) continue; mmio_write_32(CRU_BASE + CRU_DPLL_CON3, PLL_MODE(PLL_NORMAL_MODE)); } __attribute__((noreturn)) void m0_main(void) { mmio_setbits_32(PHY_REG(0, 927), (1 << 22)); mmio_setbits_32(PHY_REG(1, 927), (1 << 22)); idle_port(); mmio_write_32(CIC_BASE + CIC_CTRL0, (((0x3 << 4) | (1 << 2) | 1) << 16) | (1 << 2) | 1 | mmio_read_32(PARAM_ADDR + PARAM_FREQ_SELECT)); while ((mmio_read_32(CIC_BASE + CIC_STATUS0) & (1 << 2)) == 0) continue; ddr_set_pll(); mmio_write_32(CIC_BASE + CIC_CTRL0, 0x20002); while ((mmio_read_32(CIC_BASE + CIC_STATUS0) & (1 << 0)) == 0) continue; deidle_port(); mmio_clrbits_32(PHY_REG(0, 927), (1 << 22)); mmio_clrbits_32(PHY_REG(1, 927), (1 << 22)); mmio_write_32(PARAM_ADDR + PARAM_M0_DONE, M0_DONE_FLAG); for (;;) __asm__ volatile ("wfi"); } trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/m0/src/rk3399m0.ld.S000066400000000000000000000007751355360272700253340ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include OUTPUT_FORMAT("elf32-littlearm") SECTIONS { .m0_bin 0 : { KEEP(*(.isr_vector)) ASSERT(. == 0xc0, "ISR vector has the wrong size."); ASSERT(. == PARAM_ADDR, "M0 params should go right behind ISR table."); . += PARAM_M0_SIZE; *(.text*) *(.rodata*) *(.data*) *(.bss*) . = ALIGN(8); *(.co_stack*) } /DISCARD/ : { *(.comment) *(.note*) } } trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/m0/src/startup.c000066400000000000000000000045721355360272700252560ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "rk3399_mcu.h" /* Stack configuration */ #define STACK_SIZE 0x00000040 __attribute__ ((section(".co_stack"))) unsigned long pstack[STACK_SIZE]; /* Macro definition */ #define WEAK __attribute__ ((weak)) /* System exception vector handler */ __attribute__ ((used)) void WEAK reset_handler(void); void WEAK nmi_handler(void); void WEAK hardware_fault_handler(void); void WEAK svc_handler(void); void WEAK pend_sv_handler(void); void WEAK systick_handler(void); extern int m0_main(void); /* Function prototypes */ static void default_reset_handler(void); static void default_handler(void); /* * The minimal vector table for a Cortex M3. Note that the proper constructs * must be placed on this to ensure that it ends up at physical address * 0x00000000. */ __attribute__ ((used, section(".isr_vector"))) void (* const g_pfnVectors[])(void) = { /* core Exceptions */ (void *)&pstack[STACK_SIZE], /* the initial stack pointer */ reset_handler, nmi_handler, hardware_fault_handler, 0, 0, 0, 0, 0, 0, 0, svc_handler, 0, 0, pend_sv_handler, systick_handler, /* external exceptions */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /** * This is the code that gets called when the processor first * starts execution following a reset event. Only the absolutely * necessary set is performed, after which the application * supplied m0_main() routine is called. */ static void default_reset_handler(void) { /* call the application's entry point */ m0_main(); } /** * Provide weak aliases for each Exception handler to the Default_Handler. * As they are weak aliases, any function with the same name will override * this definition. */ #pragma weak reset_handler = default_reset_handler #pragma weak nmi_handler = default_handler #pragma weak hardware_fault_handler = default_handler #pragma weak svc_handler = default_handler #pragma weak pend_sv_handler = default_handler #pragma weak systick_handler = default_handler /** * This is the code that gets called when the processor receives * an unexpected interrupt. This simply enters an infinite loop, * preserving the system state for examination by a debugger. */ static void default_handler(void) { /* go into an infinite loop. */ while (1) ; } trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/m0/src/stopwatch.c000066400000000000000000000030141355360272700255560ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "rk3399_mcu.h" /* use 24MHz SysTick */ #define US_TO_CYCLE(US) (US * 24) #define SYST_CST 0xe000e010 /* enable counter */ #define ENABLE (1 << 0) /* count down to 0 does not cause SysTick exception to pend */ #define TICKINT (1 << 1) /* core clock used for SysTick */ #define CLKSOURCE (1 << 2) #define COUNTFLAG (1 << 16) #define SYST_RVR 0xe000e014 #define MAX_VALUE 0xffffff #define MAX_USECS (MAX_VALUE / US_TO_CYCLE(1)) #define SYST_CVR 0xe000e018 #define SYST_CALIB 0xe000e01c unsigned int remaining_usecs; static inline void stopwatch_set_usecs(void) { unsigned int cycle; unsigned int usecs = MIN(MAX_USECS, remaining_usecs); remaining_usecs -= usecs; cycle = US_TO_CYCLE(usecs); mmio_write_32(SYST_RVR, cycle); mmio_write_32(SYST_CVR, 0); mmio_write_32(SYST_CST, ENABLE | TICKINT | CLKSOURCE); } void stopwatch_init_usecs_expire(unsigned int usecs) { /* * Enter an inifite loop if the stopwatch is in use. This will allow the * state to be analyzed with a debugger. */ if (mmio_read_32(SYST_CST) & ENABLE) while (1) ; remaining_usecs = usecs; stopwatch_set_usecs(); } int stopwatch_expired(void) { int val = mmio_read_32(SYST_CST); if ((val & COUNTFLAG) || !(val & ENABLE)) { if (!remaining_usecs) return 1; stopwatch_set_usecs(); } return 0; } void stopwatch_reset(void) { mmio_clrbits_32(SYST_CST, ENABLE); remaining_usecs = 0; } trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/m0/src/suspend.c000066400000000000000000000032461355360272700252320ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "rk3399_mcu.h" #define M0_SCR 0xe000ed10 /* System Control Register (SCR) */ #define SCR_SLEEPDEEP_SHIFT (1 << 2) __attribute__((noreturn)) void m0_main(void) { unsigned int status_value; /* * PMU sometimes doesn't clear power mode bit as it's supposed to due * to a hardware bug. Make the M0 clear it manually to be sure, * otherwise interrupts some cases with concurrent wake interrupts * we stay asleep forever. */ while (1) { status_value = mmio_read_32(PMU_BASE + PMU_POWER_ST); if (status_value) { mmio_clrbits_32(PMU_BASE + PMU_PWRMODE_CON, 0x01); break; } } /* * FSM power secquence is .. -> ST_INPUT_CLAMP(step.17) -> .. -> * ST_WAKEUP_RESET -> ST_EXT_PWRUP-> ST_RELEASE_CLAMP -> * ST_24M_OSC_EN -> .. -> ST_WAKEUP_RESET_CLR(step.26) -> .., * INPUT_CLAMP and WAKEUP_RESET will hold the SOC not affect by * power or other single glitch, but WAKEUP_RESET need work with 24MHz, * so between RELEASE_CLAMP and 24M_OSC_EN, there have a chance * that glitch will affect SOC, and mess up SOC status, so we * addressmap_shared software clamp between ST_INPUT_CLAMP and * ST_WAKEUP_RESET_CLR to avoid this happen. */ while (1) { status_value = mmio_read_32(PMU_BASE + PMU_POWER_ST); if (status_value >= 17) { mmio_setbits_32(PMU_BASE + PMU_SFT_CON, 0x02); break; } } while (1) { status_value = mmio_read_32(PMU_BASE + PMU_POWER_ST); if (status_value >= 26) { mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, 0x02); break; } } for (;;) __asm__ volatile ("wfi"); } trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/pmu/000077500000000000000000000000001355360272700230765ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/pmu/m0_ctl.c000066400000000000000000000050651355360272700244260ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include void m0_init(void) { /* secure config for M0 */ mmio_write_32(SGRF_BASE + SGRF_PMU_CON(0), WMSK_BIT(7)); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6), WMSK_BIT(12)); /* document is wrong, PMU_CRU_GATEDIS_CON0 do not need set MASK BIT */ mmio_setbits_32(PMUCRU_BASE + PMUCRU_GATEDIS_CON0, 0x02); /* * To switch the parent to xin24M and div == 1, * * We need to close most of the PLLs and clocks except the OSC 24MHz * durning suspend, and this should be enough to supplies the ddrfreq, * For the simple handle, we just keep the fixed 24MHz to supply the * suspend and ddrfreq directly. */ mmio_write_32(PMUCRU_BASE + PMUCRU_CLKSEL_CON0, BIT_WITH_WMSK(15) | BITS_WITH_WMASK(0x0, 0x1f, 8)); mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2, WMSK_BIT(5)); } void m0_configure_execute_addr(uintptr_t addr) { /* set the execute address for M0 */ mmio_write_32(SGRF_BASE + SGRF_PMU_CON(3), BITS_WITH_WMASK((addr >> 12) & 0xffff, 0xffffu, 0)); mmio_write_32(SGRF_BASE + SGRF_PMU_CON(7), BITS_WITH_WMASK((addr >> 28) & 0xf, 0xfu, 0)); } void m0_start(void) { /* enable clocks for M0 */ mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2, BITS_WITH_WMASK(0x0, 0xf, 0)); /* clean the PARAM_M0_DONE flag, mean that M0 will start working */ mmio_write_32(M0_PARAM_ADDR + PARAM_M0_DONE, 0); dmbst(); mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0, BITS_WITH_WMASK(0x0, 0x4, 0)); udelay(5); /* start M0 */ mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0, BITS_WITH_WMASK(0x0, 0x20, 0)); dmbst(); } void m0_stop(void) { /* stop M0 */ mmio_write_32(PMUCRU_BASE + PMUCRU_SOFTRST_CON0, BITS_WITH_WMASK(0x24, 0x24, 0)); /* disable clocks for M0 */ mmio_write_32(PMUCRU_BASE + PMUCRU_CLKGATE_CON2, BITS_WITH_WMASK(0xf, 0xf, 0)); } void m0_wait_done(void) { do { /* * Don't starve the M0 for access to SRAM, so delay before * reading the PARAM_M0_DONE value again. */ udelay(5); dsb(); } while (mmio_read_32(M0_PARAM_ADDR + PARAM_M0_DONE) != M0_DONE_FLAG); /* * Let the M0 settle into WFI before we leave. This is so we don't reset * the M0 in a bad spot which can cause problems with the M0. */ udelay(10); dsb(); } trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/pmu/m0_ctl.h000066400000000000000000000012511355360272700244240ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef M0_CTL_H #define M0_CTL_H #include #define M0_BINCODE_BASE ((uintptr_t)rk3399m0_bin) #define M0_PARAM_ADDR (M0_BINCODE_BASE + PARAM_ADDR) #define M0PMU_BINCODE_BASE ((uintptr_t)rk3399m0pmu_bin) /* pmu_fw.c */ extern char rk3399m0_bin[]; extern char rk3399m0_bin_end[]; extern char rk3399m0pmu_bin[]; extern char rk3399m0pmu_bin_end[]; extern void m0_init(void); extern void m0_start(void); extern void m0_stop(void); extern void m0_wait_done(void); extern void m0_configure_execute_addr(uintptr_t addr); #endif /* M0_CTL_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/pmu/plat_pmu_macros.S000066400000000000000000000057421355360272700264170ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl clst_warmboot_data .macro sram_func _name .cfi_sections .debug_frame .section .sram.text, "ax" .type \_name, %function .cfi_startproc \_name: .endm #define CRU_CLKSEL_CON6 0x118 #define DDRCTL0_C_SYSREQ_CFG 0x0100 #define DDRCTL1_C_SYSREQ_CFG 0x1000 #define DDRC0_SREF_DONE_EXT 0x01 #define DDRC1_SREF_DONE_EXT 0x04 #define PLL_MODE_SHIFT (0x8) #define PLL_NORMAL_MODE ((0x3 << (PLL_MODE_SHIFT + 16)) | \ (0x1 << PLL_MODE_SHIFT)) #define MPIDR_CLST_L_BITS 0x0 /* * For different socs, if we want to speed up warmboot, * we need to config some regs here. * If scu was suspend, we must resume related clk * from slow (24M) mode to normal mode first. * X0: MPIDR_EL1 & MPIDR_CLUSTER_MASK */ .macro func_rockchip_clst_warmboot adr x4, clst_warmboot_data lsr x5, x0, #6 ldr w3, [x4, x5] str wzr, [x4, x5] cmp w3, #PMU_CLST_RET b.ne clst_warmboot_end ldr w6, =(PLL_NORMAL_MODE) /* * core_l offset is CRU_BASE + 0xc, * core_b offset is CRU_BASE + 0x2c */ ldr x7, =(CRU_BASE + 0xc) lsr x2, x0, #3 str w6, [x7, x2] clst_warmboot_end: .endm .macro rockchip_clst_warmboot_data clst_warmboot_data: .rept PLATFORM_CLUSTER_COUNT .word 0 .endr .endm /* ----------------------------------------------- * void sram_func_set_ddrctl_pll(uint32_t pll_src) * Function to switch the PLL source for ddrctrl * In: x0 - The PLL of the clk_ddrc clock source * out: None * Clobber list : x0 - x3, x5, x8 - x10 * ----------------------------------------------- */ .globl sram_func_set_ddrctl_pll sram_func sram_func_set_ddrctl_pll /* backup parameter */ mov x8, x0 /* disable the MMU at EL3 */ mrs x9, sctlr_el3 bic x10, x9, #(SCTLR_M_BIT) msr sctlr_el3, x10 isb dsb sy /* enable ddrctl0_1 idle request */ mov x5, PMU_BASE ldr w0, [x5, #PMU_SFT_CON] orr w0, w0, #DDRCTL0_C_SYSREQ_CFG orr w0, w0, #DDRCTL1_C_SYSREQ_CFG str w0, [x5, #PMU_SFT_CON] check_ddrc0_1_sref_enter: ldr w1, [x5, #PMU_DDR_SREF_ST] and w2, w1, #DDRC0_SREF_DONE_EXT and w3, w1, #DDRC1_SREF_DONE_EXT orr w2, w2, w3 cmp w2, #(DDRC0_SREF_DONE_EXT | DDRC1_SREF_DONE_EXT) b.eq check_ddrc0_1_sref_enter /* * select a PLL for ddrctrl: * x0 = 0: ALPLL * x0 = 1: ABPLL * x0 = 2: DPLL * x0 = 3: GPLLL */ mov x5, CRU_BASE lsl w0, w8, #4 orr w0, w0, #0x00300000 str w0, [x5, #CRU_CLKSEL_CON6] /* disable ddrctl0_1 idle request */ mov x5, PMU_BASE ldr w0, [x5, #PMU_SFT_CON] bic w0, w0, #DDRCTL0_C_SYSREQ_CFG bic w0, w0, #DDRCTL1_C_SYSREQ_CFG str w0, [x5, #PMU_SFT_CON] check_ddrc0_1_sref_exit: ldr w1, [x5, #PMU_DDR_SREF_ST] and w2, w1, #DDRC0_SREF_DONE_EXT and w3, w1, #DDRC1_SREF_DONE_EXT orr w2, w2, w3 cmp w2, #0x0 b.eq check_ddrc0_1_sref_exit /* reenable the MMU at EL3 */ msr sctlr_el3, x9 isb dsb sy ret endfunc sram_func_set_ddrctl_pll trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/pmu/pmu.c000066400000000000000000001343621355360272700240540ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include DEFINE_BAKERY_LOCK(rockchip_pd_lock); static uint32_t cpu_warm_boot_addr; static char store_sram[SRAM_BIN_LIMIT + SRAM_TEXT_LIMIT + SRAM_DATA_LIMIT]; static uint32_t store_cru[CRU_SDIO0_CON1 / 4 + 1]; static uint32_t store_usbphy0[7]; static uint32_t store_usbphy1[7]; static uint32_t store_grf_io_vsel; static uint32_t store_grf_soc_con0; static uint32_t store_grf_soc_con1; static uint32_t store_grf_soc_con2; static uint32_t store_grf_soc_con3; static uint32_t store_grf_soc_con4; static uint32_t store_grf_soc_con7; static uint32_t store_grf_ddrc_con[4]; static uint32_t store_wdt0[2]; static uint32_t store_wdt1[2]; static gicv3_dist_ctx_t dist_ctx; static gicv3_redist_ctx_t rdist_ctx; /* * There are two ways to powering on or off on core. * 1) Control it power domain into on or off in PMU_PWRDN_CON reg, * it is core_pwr_pd mode * 2) Enable the core power manage in PMU_CORE_PM_CON reg, * then, if the core enter into wfi, it power domain will be * powered off automatically. it is core_pwr_wfi or core_pwr_wfi_int mode * so we need core_pm_cfg_info to distinguish which method be used now. */ static uint32_t core_pm_cfg_info[PLATFORM_CORE_COUNT] #if USE_COHERENT_MEM __attribute__ ((section("tzfw_coherent_mem"))) #endif ;/* coheront */ static void pmu_bus_idle_req(uint32_t bus, uint32_t state) { uint32_t bus_id = BIT(bus); uint32_t bus_req; uint32_t wait_cnt = 0; uint32_t bus_state, bus_ack; if (state) bus_req = BIT(bus); else bus_req = 0; mmio_clrsetbits_32(PMU_BASE + PMU_BUS_IDLE_REQ, bus_id, bus_req); do { bus_state = mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST) & bus_id; bus_ack = mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ACK) & bus_id; if (bus_state == bus_req && bus_ack == bus_req) break; wait_cnt++; udelay(1); } while (wait_cnt < MAX_WAIT_COUNT); if (bus_state != bus_req || bus_ack != bus_req) { INFO("%s:st=%x(%x)\n", __func__, mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ST), bus_state); INFO("%s:st=%x(%x)\n", __func__, mmio_read_32(PMU_BASE + PMU_BUS_IDLE_ACK), bus_ack); } } struct pmu_slpdata_s pmu_slpdata; static void qos_restore(void) { if (pmu_power_domain_st(PD_GPU) == pmu_pd_on) RESTORE_QOS(pmu_slpdata.gpu_qos, GPU); if (pmu_power_domain_st(PD_ISP0) == pmu_pd_on) { RESTORE_QOS(pmu_slpdata.isp0_m0_qos, ISP0_M0); RESTORE_QOS(pmu_slpdata.isp0_m1_qos, ISP0_M1); } if (pmu_power_domain_st(PD_ISP1) == pmu_pd_on) { RESTORE_QOS(pmu_slpdata.isp1_m0_qos, ISP1_M0); RESTORE_QOS(pmu_slpdata.isp1_m1_qos, ISP1_M1); } if (pmu_power_domain_st(PD_VO) == pmu_pd_on) { RESTORE_QOS(pmu_slpdata.vop_big_r, VOP_BIG_R); RESTORE_QOS(pmu_slpdata.vop_big_w, VOP_BIG_W); RESTORE_QOS(pmu_slpdata.vop_little, VOP_LITTLE); } if (pmu_power_domain_st(PD_HDCP) == pmu_pd_on) RESTORE_QOS(pmu_slpdata.hdcp_qos, HDCP); if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on) RESTORE_QOS(pmu_slpdata.gmac_qos, GMAC); if (pmu_power_domain_st(PD_CCI) == pmu_pd_on) { RESTORE_QOS(pmu_slpdata.cci_m0_qos, CCI_M0); RESTORE_QOS(pmu_slpdata.cci_m1_qos, CCI_M1); } if (pmu_power_domain_st(PD_SD) == pmu_pd_on) RESTORE_QOS(pmu_slpdata.sdmmc_qos, SDMMC); if (pmu_power_domain_st(PD_EMMC) == pmu_pd_on) RESTORE_QOS(pmu_slpdata.emmc_qos, EMMC); if (pmu_power_domain_st(PD_SDIOAUDIO) == pmu_pd_on) RESTORE_QOS(pmu_slpdata.sdio_qos, SDIO); if (pmu_power_domain_st(PD_GIC) == pmu_pd_on) RESTORE_QOS(pmu_slpdata.gic_qos, GIC); if (pmu_power_domain_st(PD_RGA) == pmu_pd_on) { RESTORE_QOS(pmu_slpdata.rga_r_qos, RGA_R); RESTORE_QOS(pmu_slpdata.rga_w_qos, RGA_W); } if (pmu_power_domain_st(PD_IEP) == pmu_pd_on) RESTORE_QOS(pmu_slpdata.iep_qos, IEP); if (pmu_power_domain_st(PD_USB3) == pmu_pd_on) { RESTORE_QOS(pmu_slpdata.usb_otg0_qos, USB_OTG0); RESTORE_QOS(pmu_slpdata.usb_otg1_qos, USB_OTG1); } if (pmu_power_domain_st(PD_PERIHP) == pmu_pd_on) { RESTORE_QOS(pmu_slpdata.usb_host0_qos, USB_HOST0); RESTORE_QOS(pmu_slpdata.usb_host1_qos, USB_HOST1); RESTORE_QOS(pmu_slpdata.perihp_nsp_qos, PERIHP_NSP); } if (pmu_power_domain_st(PD_PERILP) == pmu_pd_on) { RESTORE_QOS(pmu_slpdata.dmac0_qos, DMAC0); RESTORE_QOS(pmu_slpdata.dmac1_qos, DMAC1); RESTORE_QOS(pmu_slpdata.dcf_qos, DCF); RESTORE_QOS(pmu_slpdata.crypto0_qos, CRYPTO0); RESTORE_QOS(pmu_slpdata.crypto1_qos, CRYPTO1); RESTORE_QOS(pmu_slpdata.perilp_nsp_qos, PERILP_NSP); RESTORE_QOS(pmu_slpdata.perilpslv_nsp_qos, PERILPSLV_NSP); RESTORE_QOS(pmu_slpdata.peri_cm1_qos, PERI_CM1); } if (pmu_power_domain_st(PD_VDU) == pmu_pd_on) RESTORE_QOS(pmu_slpdata.video_m0_qos, VIDEO_M0); if (pmu_power_domain_st(PD_VCODEC) == pmu_pd_on) { RESTORE_QOS(pmu_slpdata.video_m1_r_qos, VIDEO_M1_R); RESTORE_QOS(pmu_slpdata.video_m1_w_qos, VIDEO_M1_W); } } static void qos_save(void) { if (pmu_power_domain_st(PD_GPU) == pmu_pd_on) SAVE_QOS(pmu_slpdata.gpu_qos, GPU); if (pmu_power_domain_st(PD_ISP0) == pmu_pd_on) { SAVE_QOS(pmu_slpdata.isp0_m0_qos, ISP0_M0); SAVE_QOS(pmu_slpdata.isp0_m1_qos, ISP0_M1); } if (pmu_power_domain_st(PD_ISP1) == pmu_pd_on) { SAVE_QOS(pmu_slpdata.isp1_m0_qos, ISP1_M0); SAVE_QOS(pmu_slpdata.isp1_m1_qos, ISP1_M1); } if (pmu_power_domain_st(PD_VO) == pmu_pd_on) { SAVE_QOS(pmu_slpdata.vop_big_r, VOP_BIG_R); SAVE_QOS(pmu_slpdata.vop_big_w, VOP_BIG_W); SAVE_QOS(pmu_slpdata.vop_little, VOP_LITTLE); } if (pmu_power_domain_st(PD_HDCP) == pmu_pd_on) SAVE_QOS(pmu_slpdata.hdcp_qos, HDCP); if (pmu_power_domain_st(PD_GMAC) == pmu_pd_on) SAVE_QOS(pmu_slpdata.gmac_qos, GMAC); if (pmu_power_domain_st(PD_CCI) == pmu_pd_on) { SAVE_QOS(pmu_slpdata.cci_m0_qos, CCI_M0); SAVE_QOS(pmu_slpdata.cci_m1_qos, CCI_M1); } if (pmu_power_domain_st(PD_SD) == pmu_pd_on) SAVE_QOS(pmu_slpdata.sdmmc_qos, SDMMC); if (pmu_power_domain_st(PD_EMMC) == pmu_pd_on) SAVE_QOS(pmu_slpdata.emmc_qos, EMMC); if (pmu_power_domain_st(PD_SDIOAUDIO) == pmu_pd_on) SAVE_QOS(pmu_slpdata.sdio_qos, SDIO); if (pmu_power_domain_st(PD_GIC) == pmu_pd_on) SAVE_QOS(pmu_slpdata.gic_qos, GIC); if (pmu_power_domain_st(PD_RGA) == pmu_pd_on) { SAVE_QOS(pmu_slpdata.rga_r_qos, RGA_R); SAVE_QOS(pmu_slpdata.rga_w_qos, RGA_W); } if (pmu_power_domain_st(PD_IEP) == pmu_pd_on) SAVE_QOS(pmu_slpdata.iep_qos, IEP); if (pmu_power_domain_st(PD_USB3) == pmu_pd_on) { SAVE_QOS(pmu_slpdata.usb_otg0_qos, USB_OTG0); SAVE_QOS(pmu_slpdata.usb_otg1_qos, USB_OTG1); } if (pmu_power_domain_st(PD_PERIHP) == pmu_pd_on) { SAVE_QOS(pmu_slpdata.usb_host0_qos, USB_HOST0); SAVE_QOS(pmu_slpdata.usb_host1_qos, USB_HOST1); SAVE_QOS(pmu_slpdata.perihp_nsp_qos, PERIHP_NSP); } if (pmu_power_domain_st(PD_PERILP) == pmu_pd_on) { SAVE_QOS(pmu_slpdata.dmac0_qos, DMAC0); SAVE_QOS(pmu_slpdata.dmac1_qos, DMAC1); SAVE_QOS(pmu_slpdata.dcf_qos, DCF); SAVE_QOS(pmu_slpdata.crypto0_qos, CRYPTO0); SAVE_QOS(pmu_slpdata.crypto1_qos, CRYPTO1); SAVE_QOS(pmu_slpdata.perilp_nsp_qos, PERILP_NSP); SAVE_QOS(pmu_slpdata.perilpslv_nsp_qos, PERILPSLV_NSP); SAVE_QOS(pmu_slpdata.peri_cm1_qos, PERI_CM1); } if (pmu_power_domain_st(PD_VDU) == pmu_pd_on) SAVE_QOS(pmu_slpdata.video_m0_qos, VIDEO_M0); if (pmu_power_domain_st(PD_VCODEC) == pmu_pd_on) { SAVE_QOS(pmu_slpdata.video_m1_r_qos, VIDEO_M1_R); SAVE_QOS(pmu_slpdata.video_m1_w_qos, VIDEO_M1_W); } } static int pmu_set_power_domain(uint32_t pd_id, uint32_t pd_state) { uint32_t state; if (pmu_power_domain_st(pd_id) == pd_state) goto out; if (pd_state == pmu_pd_on) pmu_power_domain_ctr(pd_id, pd_state); state = (pd_state == pmu_pd_off) ? BUS_IDLE : BUS_ACTIVE; switch (pd_id) { case PD_GPU: pmu_bus_idle_req(BUS_ID_GPU, state); break; case PD_VIO: pmu_bus_idle_req(BUS_ID_VIO, state); break; case PD_ISP0: pmu_bus_idle_req(BUS_ID_ISP0, state); break; case PD_ISP1: pmu_bus_idle_req(BUS_ID_ISP1, state); break; case PD_VO: pmu_bus_idle_req(BUS_ID_VOPB, state); pmu_bus_idle_req(BUS_ID_VOPL, state); break; case PD_HDCP: pmu_bus_idle_req(BUS_ID_HDCP, state); break; case PD_TCPD0: break; case PD_TCPD1: break; case PD_GMAC: pmu_bus_idle_req(BUS_ID_GMAC, state); break; case PD_CCI: pmu_bus_idle_req(BUS_ID_CCIM0, state); pmu_bus_idle_req(BUS_ID_CCIM1, state); break; case PD_SD: pmu_bus_idle_req(BUS_ID_SD, state); break; case PD_EMMC: pmu_bus_idle_req(BUS_ID_EMMC, state); break; case PD_EDP: pmu_bus_idle_req(BUS_ID_EDP, state); break; case PD_SDIOAUDIO: pmu_bus_idle_req(BUS_ID_SDIOAUDIO, state); break; case PD_GIC: pmu_bus_idle_req(BUS_ID_GIC, state); break; case PD_RGA: pmu_bus_idle_req(BUS_ID_RGA, state); break; case PD_VCODEC: pmu_bus_idle_req(BUS_ID_VCODEC, state); break; case PD_VDU: pmu_bus_idle_req(BUS_ID_VDU, state); break; case PD_IEP: pmu_bus_idle_req(BUS_ID_IEP, state); break; case PD_USB3: pmu_bus_idle_req(BUS_ID_USB3, state); break; case PD_PERIHP: pmu_bus_idle_req(BUS_ID_PERIHP, state); break; default: /* Do nothing in default case */ break; } if (pd_state == pmu_pd_off) pmu_power_domain_ctr(pd_id, pd_state); out: return 0; } static uint32_t pmu_powerdomain_state; static void pmu_power_domains_suspend(void) { clk_gate_con_save(); clk_gate_con_disable(); qos_save(); pmu_powerdomain_state = mmio_read_32(PMU_BASE + PMU_PWRDN_ST); pmu_set_power_domain(PD_GPU, pmu_pd_off); pmu_set_power_domain(PD_TCPD0, pmu_pd_off); pmu_set_power_domain(PD_TCPD1, pmu_pd_off); pmu_set_power_domain(PD_VO, pmu_pd_off); pmu_set_power_domain(PD_ISP0, pmu_pd_off); pmu_set_power_domain(PD_ISP1, pmu_pd_off); pmu_set_power_domain(PD_HDCP, pmu_pd_off); pmu_set_power_domain(PD_SDIOAUDIO, pmu_pd_off); pmu_set_power_domain(PD_GMAC, pmu_pd_off); pmu_set_power_domain(PD_EDP, pmu_pd_off); pmu_set_power_domain(PD_IEP, pmu_pd_off); pmu_set_power_domain(PD_RGA, pmu_pd_off); pmu_set_power_domain(PD_VCODEC, pmu_pd_off); pmu_set_power_domain(PD_VDU, pmu_pd_off); pmu_set_power_domain(PD_USB3, pmu_pd_off); pmu_set_power_domain(PD_EMMC, pmu_pd_off); pmu_set_power_domain(PD_VIO, pmu_pd_off); pmu_set_power_domain(PD_SD, pmu_pd_off); pmu_set_power_domain(PD_PERIHP, pmu_pd_off); clk_gate_con_restore(); } static void pmu_power_domains_resume(void) { clk_gate_con_save(); clk_gate_con_disable(); if (!(pmu_powerdomain_state & BIT(PD_VDU))) pmu_set_power_domain(PD_VDU, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_VCODEC))) pmu_set_power_domain(PD_VCODEC, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_RGA))) pmu_set_power_domain(PD_RGA, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_IEP))) pmu_set_power_domain(PD_IEP, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_EDP))) pmu_set_power_domain(PD_EDP, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_GMAC))) pmu_set_power_domain(PD_GMAC, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_SDIOAUDIO))) pmu_set_power_domain(PD_SDIOAUDIO, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_HDCP))) pmu_set_power_domain(PD_HDCP, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_ISP1))) pmu_set_power_domain(PD_ISP1, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_ISP0))) pmu_set_power_domain(PD_ISP0, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_VO))) pmu_set_power_domain(PD_VO, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_TCPD1))) pmu_set_power_domain(PD_TCPD1, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_TCPD0))) pmu_set_power_domain(PD_TCPD0, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_GPU))) pmu_set_power_domain(PD_GPU, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_USB3))) pmu_set_power_domain(PD_USB3, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_EMMC))) pmu_set_power_domain(PD_EMMC, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_VIO))) pmu_set_power_domain(PD_VIO, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_SD))) pmu_set_power_domain(PD_SD, pmu_pd_on); if (!(pmu_powerdomain_state & BIT(PD_PERIHP))) pmu_set_power_domain(PD_PERIHP, pmu_pd_on); qos_restore(); clk_gate_con_restore(); } void rk3399_flush_l2_b(void) { uint32_t wait_cnt = 0; mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(L2_FLUSH_REQ_CLUSTER_B)); dsb(); /* * The Big cluster flush L2 cache took ~4ms by default, give 10ms for * the enough margin. */ while (!(mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST) & BIT(L2_FLUSHDONE_CLUSTER_B))) { wait_cnt++; udelay(10); if (wait_cnt == 10000 / 10) WARN("L2 cache flush on suspend took longer than 10ms\n"); } mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(L2_FLUSH_REQ_CLUSTER_B)); } static void pmu_scu_b_pwrdn(void) { uint32_t wait_cnt = 0; if ((mmio_read_32(PMU_BASE + PMU_PWRDN_ST) & (BIT(PMU_A72_B0_PWRDWN_ST) | BIT(PMU_A72_B1_PWRDWN_ST))) != (BIT(PMU_A72_B0_PWRDWN_ST) | BIT(PMU_A72_B1_PWRDWN_ST))) { ERROR("%s: not all cpus is off\n", __func__); return; } rk3399_flush_l2_b(); mmio_setbits_32(PMU_BASE + PMU_SFT_CON, BIT(ACINACTM_CLUSTER_B_CFG)); while (!(mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST) & BIT(STANDBY_BY_WFIL2_CLUSTER_B))) { wait_cnt++; udelay(1); if (wait_cnt >= MAX_WAIT_COUNT) ERROR("%s:wait cluster-b l2(%x)\n", __func__, mmio_read_32(PMU_BASE + PMU_CORE_PWR_ST)); } } static void pmu_scu_b_pwrup(void) { mmio_clrbits_32(PMU_BASE + PMU_SFT_CON, BIT(ACINACTM_CLUSTER_B_CFG)); } static inline uint32_t get_cpus_pwr_domain_cfg_info(uint32_t cpu_id) { assert(cpu_id < PLATFORM_CORE_COUNT); return core_pm_cfg_info[cpu_id]; } static inline void set_cpus_pwr_domain_cfg_info(uint32_t cpu_id, uint32_t value) { assert(cpu_id < PLATFORM_CORE_COUNT); core_pm_cfg_info[cpu_id] = value; #if !USE_COHERENT_MEM flush_dcache_range((uintptr_t)&core_pm_cfg_info[cpu_id], sizeof(uint32_t)); #endif } static int cpus_power_domain_on(uint32_t cpu_id) { uint32_t cfg_info; uint32_t cpu_pd = PD_CPUL0 + cpu_id; /* * There are two ways to powering on or off on core. * 1) Control it power domain into on or off in PMU_PWRDN_CON reg * 2) Enable the core power manage in PMU_CORE_PM_CON reg, * then, if the core enter into wfi, it power domain will be * powered off automatically. */ cfg_info = get_cpus_pwr_domain_cfg_info(cpu_id); if (cfg_info == core_pwr_pd) { /* disable core_pm cfg */ mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), CORES_PM_DISABLE); /* if the cores have be on, power off it firstly */ if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) { mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), 0); pmu_power_domain_ctr(cpu_pd, pmu_pd_off); } pmu_power_domain_ctr(cpu_pd, pmu_pd_on); } else { if (pmu_power_domain_st(cpu_pd) == pmu_pd_on) { WARN("%s: cpu%d is not in off,!\n", __func__, cpu_id); return -EINVAL; } mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), BIT(core_pm_sft_wakeup_en)); dsb(); } return 0; } static int cpus_power_domain_off(uint32_t cpu_id, uint32_t pd_cfg) { uint32_t cpu_pd; uint32_t core_pm_value; cpu_pd = PD_CPUL0 + cpu_id; if (pmu_power_domain_st(cpu_pd) == pmu_pd_off) return 0; if (pd_cfg == core_pwr_pd) { if (check_cpu_wfie(cpu_id, CKECK_WFEI_MSK)) return -EINVAL; /* disable core_pm cfg */ mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), CORES_PM_DISABLE); set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg); pmu_power_domain_ctr(cpu_pd, pmu_pd_off); } else { set_cpus_pwr_domain_cfg_info(cpu_id, pd_cfg); core_pm_value = BIT(core_pm_en); if (pd_cfg == core_pwr_wfi_int) core_pm_value |= BIT(core_pm_int_wakeup_en); mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), core_pm_value); dsb(); } return 0; } static inline void clst_pwr_domain_suspend(plat_local_state_t lvl_state) { uint32_t cpu_id = plat_my_core_pos(); uint32_t pll_id, clst_st_msk, clst_st_chk_msk, pmu_st; assert(cpu_id < PLATFORM_CORE_COUNT); if (lvl_state == PLAT_MAX_OFF_STATE) { if (cpu_id < PLATFORM_CLUSTER0_CORE_COUNT) { pll_id = ALPLL_ID; clst_st_msk = CLST_L_CPUS_MSK; } else { pll_id = ABPLL_ID; clst_st_msk = CLST_B_CPUS_MSK << PLATFORM_CLUSTER0_CORE_COUNT; } clst_st_chk_msk = clst_st_msk & ~(BIT(cpu_id)); pmu_st = mmio_read_32(PMU_BASE + PMU_PWRDN_ST); pmu_st &= clst_st_msk; if (pmu_st == clst_st_chk_msk) { mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3), PLL_SLOW_MODE); clst_warmboot_data[pll_id] = PMU_CLST_RET; pmu_st = mmio_read_32(PMU_BASE + PMU_PWRDN_ST); pmu_st &= clst_st_msk; if (pmu_st == clst_st_chk_msk) return; /* * it is mean that others cpu is up again, * we must resume the cfg at once. */ mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3), PLL_NOMAL_MODE); clst_warmboot_data[pll_id] = 0; } } } static int clst_pwr_domain_resume(plat_local_state_t lvl_state) { uint32_t cpu_id = plat_my_core_pos(); uint32_t pll_id, pll_st; assert(cpu_id < PLATFORM_CORE_COUNT); if (lvl_state == PLAT_MAX_OFF_STATE) { if (cpu_id < PLATFORM_CLUSTER0_CORE_COUNT) pll_id = ALPLL_ID; else pll_id = ABPLL_ID; pll_st = mmio_read_32(CRU_BASE + CRU_PLL_CON(pll_id, 3)) >> PLL_MODE_SHIFT; if (pll_st != NORMAL_MODE) { WARN("%s: clst (%d) is in error mode (%d)\n", __func__, pll_id, pll_st); return -1; } } return 0; } static void nonboot_cpus_off(void) { uint32_t boot_cpu, cpu; boot_cpu = plat_my_core_pos(); /* turn off noboot cpus */ for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) { if (cpu == boot_cpu) continue; cpus_power_domain_off(cpu, core_pwr_pd); } } int rockchip_soc_cores_pwr_dm_on(unsigned long mpidr, uint64_t entrypoint) { uint32_t cpu_id = plat_core_pos_by_mpidr(mpidr); assert(cpu_id < PLATFORM_CORE_COUNT); assert(cpuson_flags[cpu_id] == 0); cpuson_flags[cpu_id] = PMU_CPU_HOTPLUG; cpuson_entry_point[cpu_id] = entrypoint; dsb(); cpus_power_domain_on(cpu_id); return PSCI_E_SUCCESS; } int rockchip_soc_cores_pwr_dm_off(void) { uint32_t cpu_id = plat_my_core_pos(); cpus_power_domain_off(cpu_id, core_pwr_wfi); return PSCI_E_SUCCESS; } int rockchip_soc_hlvl_pwr_dm_off(uint32_t lvl, plat_local_state_t lvl_state) { if (lvl == MPIDR_AFFLVL1) { clst_pwr_domain_suspend(lvl_state); } return PSCI_E_SUCCESS; } int rockchip_soc_cores_pwr_dm_suspend(void) { uint32_t cpu_id = plat_my_core_pos(); assert(cpu_id < PLATFORM_CORE_COUNT); assert(cpuson_flags[cpu_id] == 0); cpuson_flags[cpu_id] = PMU_CPU_AUTO_PWRDN; cpuson_entry_point[cpu_id] = plat_get_sec_entrypoint(); dsb(); cpus_power_domain_off(cpu_id, core_pwr_wfi_int); return PSCI_E_SUCCESS; } int rockchip_soc_hlvl_pwr_dm_suspend(uint32_t lvl, plat_local_state_t lvl_state) { if (lvl == MPIDR_AFFLVL1) { clst_pwr_domain_suspend(lvl_state); } return PSCI_E_SUCCESS; } int rockchip_soc_cores_pwr_dm_on_finish(void) { uint32_t cpu_id = plat_my_core_pos(); mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), CORES_PM_DISABLE); return PSCI_E_SUCCESS; } int rockchip_soc_hlvl_pwr_dm_on_finish(uint32_t lvl, plat_local_state_t lvl_state) { if (lvl == MPIDR_AFFLVL1) { clst_pwr_domain_resume(lvl_state); } return PSCI_E_SUCCESS; } int rockchip_soc_cores_pwr_dm_resume(void) { uint32_t cpu_id = plat_my_core_pos(); /* Disable core_pm */ mmio_write_32(PMU_BASE + PMU_CORE_PM_CON(cpu_id), CORES_PM_DISABLE); return PSCI_E_SUCCESS; } int rockchip_soc_hlvl_pwr_dm_resume(uint32_t lvl, plat_local_state_t lvl_state) { if (lvl == MPIDR_AFFLVL1) { clst_pwr_domain_resume(lvl_state); } return PSCI_E_SUCCESS; } /** * init_pmu_counts - Init timing counts in the PMU register area * * At various points when we power up or down parts of the system we need * a delay to wait for power / clocks to become stable. The PMU has counters * to help software do the delay properly. Basically, it works like this: * - Software sets up counter values * - When software turns on something in the PMU, the counter kicks off * - The hardware sets a bit automatically when the counter has finished and * software knows that the initialization is done. * * It's software's job to setup these counters. The hardware power on default * for these settings is conservative, setting everything to 0x5dc0 * (750 ms in 32 kHz counts or 1 ms in 24 MHz counts). * * Note that some of these counters are only really used at suspend/resume * time (for instance, that's the only time we turn off/on the oscillator) and * others are used during normal runtime (like turning on/off a CPU or GPU) but * it doesn't hurt to init everything at boot. * * Also note that these counters can run off the 32 kHz clock or the 24 MHz * clock. While the 24 MHz clock can give us more precision, it's not always * available (like when we turn the oscillator off at sleep time). The * pmu_use_lf (lf: low freq) is available in power mode. Current understanding * is that counts work like this: * IF (pmu_use_lf == 0) || (power_mode_en == 0) * use the 24M OSC for counts * ELSE * use the 32K OSC for counts * * Notes: * - There is a separate bit for the PMU called PMU_24M_EN_CFG. At the moment * we always keep that 0. This apparently choose between using the PLL as * the source for the PMU vs. the 24M clock. If we ever set it to 1 we * should consider how it affects these counts (if at all). * - The power_mode_en is documented to auto-clear automatically when we leave * "power mode". That's why most clocks are on 24M. Only timings used when * in "power mode" are 32k. * - In some cases the kernel may override these counts. * * The PMU_STABLE_CNT / PMU_OSC_CNT / PMU_PLLLOCK_CNT are important CNTs * in power mode, we need to ensure that they are available. */ static void init_pmu_counts(void) { /* COUNTS FOR INSIDE POWER MODE */ /* * From limited testing, need PMU stable >= 2ms, but go overkill * and choose 30 ms to match testing on past SoCs. Also let * OSC have 30 ms for stabilization. */ mmio_write_32(PMU_BASE + PMU_STABLE_CNT, CYCL_32K_CNT_MS(30)); mmio_write_32(PMU_BASE + PMU_OSC_CNT, CYCL_32K_CNT_MS(30)); /* Unclear what these should be; try 3 ms */ mmio_write_32(PMU_BASE + PMU_WAKEUP_RST_CLR_CNT, CYCL_32K_CNT_MS(3)); /* Unclear what this should be, but set the default explicitly */ mmio_write_32(PMU_BASE + PMU_TIMEOUT_CNT, 0x5dc0); /* COUNTS FOR OUTSIDE POWER MODE */ /* Put something sorta conservative here until we know better */ mmio_write_32(PMU_BASE + PMU_PLLLOCK_CNT, CYCL_24M_CNT_MS(3)); mmio_write_32(PMU_BASE + PMU_DDRIO_PWRON_CNT, CYCL_24M_CNT_MS(1)); mmio_write_32(PMU_BASE + PMU_CENTER_PWRDN_CNT, CYCL_24M_CNT_MS(1)); mmio_write_32(PMU_BASE + PMU_CENTER_PWRUP_CNT, CYCL_24M_CNT_MS(1)); /* * when we enable PMU_CLR_PERILP, it will shut down the SRAM, but * M0 code run in SRAM, and we need it to check whether cpu enter * FSM status, so we must wait M0 finish their code and enter WFI, * then we can shutdown SRAM, according FSM order: * ST_NORMAL->..->ST_SCU_L_PWRDN->..->ST_CENTER_PWRDN->ST_PERILP_PWRDN * we can add delay when shutdown ST_SCU_L_PWRDN to guarantee M0 get * the FSM status and enter WFI, then enable PMU_CLR_PERILP. */ mmio_write_32(PMU_BASE + PMU_SCU_L_PWRDN_CNT, CYCL_24M_CNT_MS(5)); mmio_write_32(PMU_BASE + PMU_SCU_L_PWRUP_CNT, CYCL_24M_CNT_US(1)); /* * Set CPU/GPU to 1 us. * * NOTE: Even though ATF doesn't configure the GPU we'll still setup * counts here. After all ATF controls all these other bits and also * chooses which clock these counters use. */ mmio_write_32(PMU_BASE + PMU_SCU_B_PWRDN_CNT, CYCL_24M_CNT_US(1)); mmio_write_32(PMU_BASE + PMU_SCU_B_PWRUP_CNT, CYCL_24M_CNT_US(1)); mmio_write_32(PMU_BASE + PMU_GPU_PWRDN_CNT, CYCL_24M_CNT_US(1)); mmio_write_32(PMU_BASE + PMU_GPU_PWRUP_CNT, CYCL_24M_CNT_US(1)); } static uint32_t clk_ddrc_save; static void sys_slp_config(void) { uint32_t slp_mode_cfg = 0; /* keep enabling clk_ddrc_bpll_src_en gate for DDRC */ clk_ddrc_save = mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(3)); mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(3), WMSK_BIT(1)); prepare_abpll_for_ddrctrl(); sram_func_set_ddrctl_pll(ABPLL_ID); mmio_write_32(GRF_BASE + GRF_SOC_CON4, CCI_FORCE_WAKEUP); mmio_write_32(PMU_BASE + PMU_CCI500_CON, BIT_WITH_WMSK(PMU_CLR_PREQ_CCI500_HW) | BIT_WITH_WMSK(PMU_CLR_QREQ_CCI500_HW) | BIT_WITH_WMSK(PMU_QGATING_CCI500_CFG)); mmio_write_32(PMU_BASE + PMU_ADB400_CON, BIT_WITH_WMSK(PMU_CLR_CORE_L_HW) | BIT_WITH_WMSK(PMU_CLR_CORE_L_2GIC_HW) | BIT_WITH_WMSK(PMU_CLR_GIC2_CORE_L_HW)); slp_mode_cfg = BIT(PMU_PWR_MODE_EN) | BIT(PMU_WKUP_RST_EN) | BIT(PMU_INPUT_CLAMP_EN) | BIT(PMU_POWER_OFF_REQ_CFG) | BIT(PMU_CPU0_PD_EN) | BIT(PMU_L2_FLUSH_EN) | BIT(PMU_L2_IDLE_EN) | BIT(PMU_SCU_PD_EN) | BIT(PMU_CCI_PD_EN) | BIT(PMU_CLK_CORE_SRC_GATE_EN) | BIT(PMU_ALIVE_USE_LF) | BIT(PMU_SREF0_ENTER_EN) | BIT(PMU_SREF1_ENTER_EN) | BIT(PMU_DDRC0_GATING_EN) | BIT(PMU_DDRC1_GATING_EN) | BIT(PMU_DDRIO0_RET_EN) | BIT(PMU_DDRIO0_RET_DE_REQ) | BIT(PMU_DDRIO1_RET_EN) | BIT(PMU_DDRIO1_RET_DE_REQ) | BIT(PMU_CENTER_PD_EN) | BIT(PMU_PERILP_PD_EN) | BIT(PMU_CLK_PERILP_SRC_GATE_EN) | BIT(PMU_PLL_PD_EN) | BIT(PMU_CLK_CENTER_SRC_GATE_EN) | BIT(PMU_OSC_DIS) | BIT(PMU_PMU_USE_LF); mmio_setbits_32(PMU_BASE + PMU_WKUP_CFG4, BIT(PMU_GPIO_WKUP_EN)); mmio_write_32(PMU_BASE + PMU_PWRMODE_CON, slp_mode_cfg); mmio_write_32(PMU_BASE + PMU_PLL_CON, PLL_PD_HW); mmio_write_32(PMUGRF_BASE + PMUGRF_SOC_CON0, EXTERNAL_32K); mmio_write_32(PMUGRF_BASE, IOMUX_CLK_32K); /* 32k iomux */ } static void set_hw_idle(uint32_t hw_idle) { mmio_setbits_32(PMU_BASE + PMU_BUS_CLR, hw_idle); } static void clr_hw_idle(uint32_t hw_idle) { mmio_clrbits_32(PMU_BASE + PMU_BUS_CLR, hw_idle); } static uint32_t iomux_status[12]; static uint32_t pull_mode_status[12]; static uint32_t gpio_direction[3]; static uint32_t gpio_2_4_clk_gate; static void suspend_apio(void) { struct bl_aux_rk_apio_info *suspend_apio; int i; suspend_apio = plat_get_rockchip_suspend_apio(); if (!suspend_apio) return; /* save gpio2 ~ gpio4 iomux and pull mode */ for (i = 0; i < 12; i++) { iomux_status[i] = mmio_read_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4); pull_mode_status[i] = mmio_read_32(GRF_BASE + GRF_GPIO2A_P + i * 4); } /* store gpio2 ~ gpio4 clock gate state */ gpio_2_4_clk_gate = (mmio_read_32(CRU_BASE + CRU_CLKGATE_CON(31)) >> PCLK_GPIO2_GATE_SHIFT) & 0x07; /* enable gpio2 ~ gpio4 clock gate */ mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), BITS_WITH_WMASK(0, 0x07, PCLK_GPIO2_GATE_SHIFT)); /* save gpio2 ~ gpio4 direction */ gpio_direction[0] = mmio_read_32(GPIO2_BASE + 0x04); gpio_direction[1] = mmio_read_32(GPIO3_BASE + 0x04); gpio_direction[2] = mmio_read_32(GPIO4_BASE + 0x04); /* apio1 charge gpio3a0 ~ gpio3c7 */ if (suspend_apio->apio1) { /* set gpio3a0 ~ gpio3c7 iomux to gpio */ mmio_write_32(GRF_BASE + GRF_GPIO3A_IOMUX, REG_SOC_WMSK | GRF_IOMUX_GPIO); mmio_write_32(GRF_BASE + GRF_GPIO3B_IOMUX, REG_SOC_WMSK | GRF_IOMUX_GPIO); mmio_write_32(GRF_BASE + GRF_GPIO3C_IOMUX, REG_SOC_WMSK | GRF_IOMUX_GPIO); /* set gpio3a0 ~ gpio3c7 pull mode to pull none */ mmio_write_32(GRF_BASE + GRF_GPIO3A_P, REG_SOC_WMSK | 0); mmio_write_32(GRF_BASE + GRF_GPIO3B_P, REG_SOC_WMSK | 0); mmio_write_32(GRF_BASE + GRF_GPIO3C_P, REG_SOC_WMSK | 0); /* set gpio3a0 ~ gpio3c7 to input */ mmio_clrbits_32(GPIO3_BASE + 0x04, 0x00ffffff); } /* apio2 charge gpio2a0 ~ gpio2b4 */ if (suspend_apio->apio2) { /* set gpio2a0 ~ gpio2b4 iomux to gpio */ mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX, REG_SOC_WMSK | GRF_IOMUX_GPIO); mmio_write_32(GRF_BASE + GRF_GPIO2B_IOMUX, REG_SOC_WMSK | GRF_IOMUX_GPIO); /* set gpio2a0 ~ gpio2b4 pull mode to pull none */ mmio_write_32(GRF_BASE + GRF_GPIO2A_P, REG_SOC_WMSK | 0); mmio_write_32(GRF_BASE + GRF_GPIO2B_P, REG_SOC_WMSK | 0); /* set gpio2a0 ~ gpio2b4 to input */ mmio_clrbits_32(GPIO2_BASE + 0x04, 0x00001fff); } /* apio3 charge gpio2c0 ~ gpio2d4*/ if (suspend_apio->apio3) { /* set gpio2a0 ~ gpio2b4 iomux to gpio */ mmio_write_32(GRF_BASE + GRF_GPIO2C_IOMUX, REG_SOC_WMSK | GRF_IOMUX_GPIO); mmio_write_32(GRF_BASE + GRF_GPIO2D_IOMUX, REG_SOC_WMSK | GRF_IOMUX_GPIO); /* set gpio2c0 ~ gpio2d4 pull mode to pull none */ mmio_write_32(GRF_BASE + GRF_GPIO2C_P, REG_SOC_WMSK | 0); mmio_write_32(GRF_BASE + GRF_GPIO2D_P, REG_SOC_WMSK | 0); /* set gpio2c0 ~ gpio2d4 to input */ mmio_clrbits_32(GPIO2_BASE + 0x04, 0x1fff0000); } /* apio4 charge gpio4c0 ~ gpio4c7, gpio4d0 ~ gpio4d6 */ if (suspend_apio->apio4) { /* set gpio4c0 ~ gpio4d6 iomux to gpio */ mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, REG_SOC_WMSK | GRF_IOMUX_GPIO); mmio_write_32(GRF_BASE + GRF_GPIO4D_IOMUX, REG_SOC_WMSK | GRF_IOMUX_GPIO); /* set gpio4c0 ~ gpio4d6 pull mode to pull none */ mmio_write_32(GRF_BASE + GRF_GPIO4C_P, REG_SOC_WMSK | 0); mmio_write_32(GRF_BASE + GRF_GPIO4D_P, REG_SOC_WMSK | 0); /* set gpio4c0 ~ gpio4d6 to input */ mmio_clrbits_32(GPIO4_BASE + 0x04, 0x7fff0000); } /* apio5 charge gpio3d0 ~ gpio3d7, gpio4a0 ~ gpio4a7*/ if (suspend_apio->apio5) { /* set gpio3d0 ~ gpio4a7 iomux to gpio */ mmio_write_32(GRF_BASE + GRF_GPIO3D_IOMUX, REG_SOC_WMSK | GRF_IOMUX_GPIO); mmio_write_32(GRF_BASE + GRF_GPIO4A_IOMUX, REG_SOC_WMSK | GRF_IOMUX_GPIO); /* set gpio3d0 ~ gpio4a7 pull mode to pull none */ mmio_write_32(GRF_BASE + GRF_GPIO3D_P, REG_SOC_WMSK | 0); mmio_write_32(GRF_BASE + GRF_GPIO4A_P, REG_SOC_WMSK | 0); /* set gpio4c0 ~ gpio4d6 to input */ mmio_clrbits_32(GPIO3_BASE + 0x04, 0xff000000); mmio_clrbits_32(GPIO4_BASE + 0x04, 0x000000ff); } } static void resume_apio(void) { struct bl_aux_rk_apio_info *suspend_apio; int i; suspend_apio = plat_get_rockchip_suspend_apio(); if (!suspend_apio) return; for (i = 0; i < 12; i++) { mmio_write_32(GRF_BASE + GRF_GPIO2A_P + i * 4, REG_SOC_WMSK | pull_mode_status[i]); mmio_write_32(GRF_BASE + GRF_GPIO2A_IOMUX + i * 4, REG_SOC_WMSK | iomux_status[i]); } /* set gpio2 ~ gpio4 direction back to store value */ mmio_write_32(GPIO2_BASE + 0x04, gpio_direction[0]); mmio_write_32(GPIO3_BASE + 0x04, gpio_direction[1]); mmio_write_32(GPIO4_BASE + 0x04, gpio_direction[2]); /* set gpio2 ~ gpio4 clock gate back to store value */ mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(31), BITS_WITH_WMASK(gpio_2_4_clk_gate, 0x07, PCLK_GPIO2_GATE_SHIFT)); } static void suspend_gpio(void) { struct bl_aux_gpio_info *suspend_gpio; uint32_t count; int i; suspend_gpio = plat_get_rockchip_suspend_gpio(&count); for (i = 0; i < count; i++) { gpio_set_value(suspend_gpio[i].index, suspend_gpio[i].polarity); gpio_set_direction(suspend_gpio[i].index, GPIO_DIR_OUT); udelay(1); } } static void resume_gpio(void) { struct bl_aux_gpio_info *suspend_gpio; uint32_t count; int i; suspend_gpio = plat_get_rockchip_suspend_gpio(&count); for (i = count - 1; i >= 0; i--) { gpio_set_value(suspend_gpio[i].index, !suspend_gpio[i].polarity); gpio_set_direction(suspend_gpio[i].index, GPIO_DIR_OUT); udelay(1); } } void sram_save(void) { size_t text_size = (char *)&__bl31_sram_text_real_end - (char *)&__bl31_sram_text_start; size_t data_size = (char *)&__bl31_sram_data_real_end - (char *)&__bl31_sram_data_start; size_t incbin_size = (char *)&__sram_incbin_real_end - (char *)&__sram_incbin_start; memcpy(&store_sram[0], &__bl31_sram_text_start, text_size); memcpy(&store_sram[text_size], &__bl31_sram_data_start, data_size); memcpy(&store_sram[text_size + data_size], &__sram_incbin_start, incbin_size); } void sram_restore(void) { size_t text_size = (char *)&__bl31_sram_text_real_end - (char *)&__bl31_sram_text_start; size_t data_size = (char *)&__bl31_sram_data_real_end - (char *)&__bl31_sram_data_start; size_t incbin_size = (char *)&__sram_incbin_real_end - (char *)&__sram_incbin_start; memcpy(&__bl31_sram_text_start, &store_sram[0], text_size); memcpy(&__bl31_sram_data_start, &store_sram[text_size], data_size); memcpy(&__sram_incbin_start, &store_sram[text_size + data_size], incbin_size); } struct uart_debug { uint32_t uart_dll; uint32_t uart_dlh; uint32_t uart_ier; uint32_t uart_fcr; uint32_t uart_mcr; uint32_t uart_lcr; }; #define UART_DLL 0x00 #define UART_DLH 0x04 #define UART_IER 0x04 #define UART_FCR 0x08 #define UART_LCR 0x0c #define UART_MCR 0x10 #define UARTSRR 0x88 #define UART_RESET BIT(0) #define UARTFCR_FIFOEN BIT(0) #define RCVR_FIFO_RESET BIT(1) #define XMIT_FIFO_RESET BIT(2) #define DIAGNOSTIC_MODE BIT(4) #define UARTLCR_DLAB BIT(7) static struct uart_debug uart_save; void suspend_uart(void) { uint32_t uart_base = rockchip_get_uart_base(); if (uart_base == 0) return; uart_save.uart_lcr = mmio_read_32(uart_base + UART_LCR); uart_save.uart_ier = mmio_read_32(uart_base + UART_IER); uart_save.uart_mcr = mmio_read_32(uart_base + UART_MCR); mmio_write_32(uart_base + UART_LCR, uart_save.uart_lcr | UARTLCR_DLAB); uart_save.uart_dll = mmio_read_32(uart_base + UART_DLL); uart_save.uart_dlh = mmio_read_32(uart_base + UART_DLH); mmio_write_32(uart_base + UART_LCR, uart_save.uart_lcr); } void resume_uart(void) { uint32_t uart_base = rockchip_get_uart_base(); uint32_t uart_lcr; if (uart_base == 0) return; mmio_write_32(uart_base + UARTSRR, XMIT_FIFO_RESET | RCVR_FIFO_RESET | UART_RESET); uart_lcr = mmio_read_32(uart_base + UART_LCR); mmio_write_32(uart_base + UART_MCR, DIAGNOSTIC_MODE); mmio_write_32(uart_base + UART_LCR, uart_lcr | UARTLCR_DLAB); mmio_write_32(uart_base + UART_DLL, uart_save.uart_dll); mmio_write_32(uart_base + UART_DLH, uart_save.uart_dlh); mmio_write_32(uart_base + UART_LCR, uart_save.uart_lcr); mmio_write_32(uart_base + UART_IER, uart_save.uart_ier); mmio_write_32(uart_base + UART_FCR, UARTFCR_FIFOEN); mmio_write_32(uart_base + UART_MCR, uart_save.uart_mcr); } void save_usbphy(void) { store_usbphy0[0] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL0); store_usbphy0[1] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL2); store_usbphy0[2] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL3); store_usbphy0[3] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL12); store_usbphy0[4] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL13); store_usbphy0[5] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL15); store_usbphy0[6] = mmio_read_32(GRF_BASE + GRF_USBPHY0_CTRL16); store_usbphy1[0] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL0); store_usbphy1[1] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL2); store_usbphy1[2] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL3); store_usbphy1[3] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL12); store_usbphy1[4] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL13); store_usbphy1[5] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL15); store_usbphy1[6] = mmio_read_32(GRF_BASE + GRF_USBPHY1_CTRL16); } void restore_usbphy(void) { mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL0, REG_SOC_WMSK | store_usbphy0[0]); mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL2, REG_SOC_WMSK | store_usbphy0[1]); mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL3, REG_SOC_WMSK | store_usbphy0[2]); mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL12, REG_SOC_WMSK | store_usbphy0[3]); mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL13, REG_SOC_WMSK | store_usbphy0[4]); mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL15, REG_SOC_WMSK | store_usbphy0[5]); mmio_write_32(GRF_BASE + GRF_USBPHY0_CTRL16, REG_SOC_WMSK | store_usbphy0[6]); mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL0, REG_SOC_WMSK | store_usbphy1[0]); mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL2, REG_SOC_WMSK | store_usbphy1[1]); mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL3, REG_SOC_WMSK | store_usbphy1[2]); mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL12, REG_SOC_WMSK | store_usbphy1[3]); mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL13, REG_SOC_WMSK | store_usbphy1[4]); mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL15, REG_SOC_WMSK | store_usbphy1[5]); mmio_write_32(GRF_BASE + GRF_USBPHY1_CTRL16, REG_SOC_WMSK | store_usbphy1[6]); } void grf_register_save(void) { int i; store_grf_soc_con0 = mmio_read_32(GRF_BASE + GRF_SOC_CON(0)); store_grf_soc_con1 = mmio_read_32(GRF_BASE + GRF_SOC_CON(1)); store_grf_soc_con2 = mmio_read_32(GRF_BASE + GRF_SOC_CON(2)); store_grf_soc_con3 = mmio_read_32(GRF_BASE + GRF_SOC_CON(3)); store_grf_soc_con4 = mmio_read_32(GRF_BASE + GRF_SOC_CON(4)); store_grf_soc_con7 = mmio_read_32(GRF_BASE + GRF_SOC_CON(7)); for (i = 0; i < 4; i++) store_grf_ddrc_con[i] = mmio_read_32(GRF_BASE + GRF_DDRC0_CON0 + i * 4); store_grf_io_vsel = mmio_read_32(GRF_BASE + GRF_IO_VSEL); } void grf_register_restore(void) { int i; mmio_write_32(GRF_BASE + GRF_SOC_CON(0), REG_SOC_WMSK | store_grf_soc_con0); mmio_write_32(GRF_BASE + GRF_SOC_CON(1), REG_SOC_WMSK | store_grf_soc_con1); mmio_write_32(GRF_BASE + GRF_SOC_CON(2), REG_SOC_WMSK | store_grf_soc_con2); mmio_write_32(GRF_BASE + GRF_SOC_CON(3), REG_SOC_WMSK | store_grf_soc_con3); mmio_write_32(GRF_BASE + GRF_SOC_CON(4), REG_SOC_WMSK | store_grf_soc_con4); mmio_write_32(GRF_BASE + GRF_SOC_CON(7), REG_SOC_WMSK | store_grf_soc_con7); for (i = 0; i < 4; i++) mmio_write_32(GRF_BASE + GRF_DDRC0_CON0 + i * 4, REG_SOC_WMSK | store_grf_ddrc_con[i]); mmio_write_32(GRF_BASE + GRF_IO_VSEL, REG_SOC_WMSK | store_grf_io_vsel); } void cru_register_save(void) { int i; for (i = 0; i <= CRU_SDIO0_CON1; i = i + 4) store_cru[i / 4] = mmio_read_32(CRU_BASE + i); } void cru_register_restore(void) { int i; for (i = 0; i <= CRU_SDIO0_CON1; i = i + 4) { /* * since DPLL, CRU_CLKSEL_CON6 have been restore in * dmc_resume, ABPLL will resote later, so skip them */ if ((i == CRU_CLKSEL_CON6) || (i >= CRU_PLL_CON(ABPLL_ID, 0) && i <= CRU_PLL_CON(DPLL_ID, 5))) continue; if ((i == CRU_PLL_CON(ALPLL_ID, 2)) || (i == CRU_PLL_CON(CPLL_ID, 2)) || (i == CRU_PLL_CON(GPLL_ID, 2)) || (i == CRU_PLL_CON(NPLL_ID, 2)) || (i == CRU_PLL_CON(VPLL_ID, 2))) mmio_write_32(CRU_BASE + i, store_cru[i / 4]); /* * CRU_GLB_CNT_TH and CRU_CLKSEL_CON97~CRU_CLKSEL_CON107 * not need do high 16bit mask */ else if ((i > 0x27c && i < 0x2b0) || (i == 0x508)) mmio_write_32(CRU_BASE + i, store_cru[i / 4]); else mmio_write_32(CRU_BASE + i, REG_SOC_WMSK | store_cru[i / 4]); } } void wdt_register_save(void) { int i; for (i = 0; i < 2; i++) { store_wdt0[i] = mmio_read_32(WDT0_BASE + i * 4); store_wdt1[i] = mmio_read_32(WDT1_BASE + i * 4); } } void wdt_register_restore(void) { int i; for (i = 1; i >= 0; i--) { mmio_write_32(WDT0_BASE + i * 4, store_wdt0[i]); mmio_write_32(WDT1_BASE + i * 4, store_wdt1[i]); } /* write 0x76 to cnt_restart to keep watchdog alive */ mmio_write_32(WDT0_BASE + 0x0c, 0x76); mmio_write_32(WDT1_BASE + 0x0c, 0x76); } int rockchip_soc_sys_pwr_dm_suspend(void) { uint32_t wait_cnt = 0; uint32_t status = 0; ddr_prepare_for_sys_suspend(); dmc_suspend(); pmu_scu_b_pwrdn(); gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx); gicv3_distif_save(&dist_ctx); /* need to save usbphy before shutdown PERIHP PD */ save_usbphy(); pmu_power_domains_suspend(); set_hw_idle(BIT(PMU_CLR_CENTER1) | BIT(PMU_CLR_ALIVE) | BIT(PMU_CLR_MSCH0) | BIT(PMU_CLR_MSCH1) | BIT(PMU_CLR_CCIM0) | BIT(PMU_CLR_CCIM1) | BIT(PMU_CLR_CENTER) | BIT(PMU_CLR_PERILP) | BIT(PMU_CLR_PERILPM0) | BIT(PMU_CLR_GIC)); set_pmu_rsthold(); sys_slp_config(); m0_configure_execute_addr(M0PMU_BINCODE_BASE); m0_start(); pmu_sgrf_rst_hld(); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1), ((uintptr_t)&pmu_cpuson_entrypoint >> CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK); mmio_write_32(PMU_BASE + PMU_ADB400_CON, BIT_WITH_WMSK(PMU_PWRDWN_REQ_CORE_B_2GIC_SW) | BIT_WITH_WMSK(PMU_PWRDWN_REQ_CORE_B_SW) | BIT_WITH_WMSK(PMU_PWRDWN_REQ_GIC2_CORE_B_SW)); dsb(); status = BIT(PMU_PWRDWN_REQ_CORE_B_2GIC_SW_ST) | BIT(PMU_PWRDWN_REQ_CORE_B_SW_ST) | BIT(PMU_PWRDWN_REQ_GIC2_CORE_B_SW_ST); while ((mmio_read_32(PMU_BASE + PMU_ADB400_ST) & status) != status) { wait_cnt++; if (wait_cnt >= MAX_WAIT_COUNT) { ERROR("%s:wait cluster-b l2(%x)\n", __func__, mmio_read_32(PMU_BASE + PMU_ADB400_ST)); panic(); } udelay(1); } mmio_setbits_32(PMU_BASE + PMU_PWRDN_CON, BIT(PMU_SCU_B_PWRDWN_EN)); wdt_register_save(); secure_watchdog_gate(); /* * Disabling PLLs/PWM/DVFS is approaching WFI which is * the last steps in suspend. */ disable_dvfs_plls(); disable_pwms(); disable_nodvfs_plls(); suspend_apio(); suspend_gpio(); suspend_uart(); grf_register_save(); cru_register_save(); sram_save(); plat_rockchip_save_gpio(); return 0; } int rockchip_soc_sys_pwr_dm_resume(void) { uint32_t wait_cnt = 0; uint32_t status = 0; plat_rockchip_restore_gpio(); cru_register_restore(); grf_register_restore(); wdt_register_restore(); resume_uart(); resume_apio(); resume_gpio(); enable_nodvfs_plls(); enable_pwms(); /* PWM regulators take time to come up; give 300us to be safe. */ udelay(300); enable_dvfs_plls(); secure_sgrf_init(); secure_sgrf_ddr_rgn_init(); /* restore clk_ddrc_bpll_src_en gate */ mmio_write_32(CRU_BASE + CRU_CLKGATE_CON(3), BITS_WITH_WMASK(clk_ddrc_save, 0xff, 0)); /* * The wakeup status is not cleared by itself, we need to clear it * manually. Otherwise we will alway query some interrupt next time. * * NOTE: If the kernel needs to query this, we might want to stash it * somewhere. */ mmio_write_32(PMU_BASE + PMU_WAKEUP_STATUS, 0xffffffff); mmio_write_32(PMU_BASE + PMU_WKUP_CFG4, 0x00); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1), (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK); mmio_write_32(PMU_BASE + PMU_CCI500_CON, WMSK_BIT(PMU_CLR_PREQ_CCI500_HW) | WMSK_BIT(PMU_CLR_QREQ_CCI500_HW) | WMSK_BIT(PMU_QGATING_CCI500_CFG)); dsb(); mmio_clrbits_32(PMU_BASE + PMU_PWRDN_CON, BIT(PMU_SCU_B_PWRDWN_EN)); mmio_write_32(PMU_BASE + PMU_ADB400_CON, WMSK_BIT(PMU_PWRDWN_REQ_CORE_B_2GIC_SW) | WMSK_BIT(PMU_PWRDWN_REQ_CORE_B_SW) | WMSK_BIT(PMU_PWRDWN_REQ_GIC2_CORE_B_SW) | WMSK_BIT(PMU_CLR_CORE_L_HW) | WMSK_BIT(PMU_CLR_CORE_L_2GIC_HW) | WMSK_BIT(PMU_CLR_GIC2_CORE_L_HW)); status = BIT(PMU_PWRDWN_REQ_CORE_B_2GIC_SW_ST) | BIT(PMU_PWRDWN_REQ_CORE_B_SW_ST) | BIT(PMU_PWRDWN_REQ_GIC2_CORE_B_SW_ST); while ((mmio_read_32(PMU_BASE + PMU_ADB400_ST) & status)) { wait_cnt++; if (wait_cnt >= MAX_WAIT_COUNT) { ERROR("%s:wait cluster-b l2(%x)\n", __func__, mmio_read_32(PMU_BASE + PMU_ADB400_ST)); panic(); } udelay(1); } pmu_scu_b_pwrup(); pmu_power_domains_resume(); restore_abpll(); clr_hw_idle(BIT(PMU_CLR_CENTER1) | BIT(PMU_CLR_ALIVE) | BIT(PMU_CLR_MSCH0) | BIT(PMU_CLR_MSCH1) | BIT(PMU_CLR_CCIM0) | BIT(PMU_CLR_CCIM1) | BIT(PMU_CLR_CENTER) | BIT(PMU_CLR_PERILP) | BIT(PMU_CLR_PERILPM0) | BIT(PMU_CLR_GIC)); gicv3_distif_init_restore(&dist_ctx); gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx); plat_rockchip_gic_cpuif_enable(); m0_stop(); restore_usbphy(); ddr_prepare_for_sys_resume(); return 0; } void __dead2 rockchip_soc_soft_reset(void) { struct bl_aux_gpio_info *rst_gpio; rst_gpio = plat_get_rockchip_gpio_reset(); if (rst_gpio) { gpio_set_direction(rst_gpio->index, GPIO_DIR_OUT); gpio_set_value(rst_gpio->index, rst_gpio->polarity); } else { soc_global_soft_reset(); } while (1) ; } void __dead2 rockchip_soc_system_off(void) { struct bl_aux_gpio_info *poweroff_gpio; poweroff_gpio = plat_get_rockchip_gpio_poweroff(); if (poweroff_gpio) { /* * if use tsadc over temp pin(GPIO1A6) as shutdown gpio, * need to set this pin iomux back to gpio function */ if (poweroff_gpio->index == TSADC_INT_PIN) { mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO1A_IOMUX, GPIO1A6_IOMUX); } gpio_set_direction(poweroff_gpio->index, GPIO_DIR_OUT); gpio_set_value(poweroff_gpio->index, poweroff_gpio->polarity); } else { WARN("Do nothing when system off\n"); } while (1) ; } void rockchip_plat_mmu_el3(void) { size_t sram_size; /* sram.text size */ sram_size = (char *)&__bl31_sram_text_end - (char *)&__bl31_sram_text_start; mmap_add_region((unsigned long)&__bl31_sram_text_start, (unsigned long)&__bl31_sram_text_start, sram_size, MT_MEMORY | MT_RO | MT_SECURE); /* sram.data size */ sram_size = (char *)&__bl31_sram_data_end - (char *)&__bl31_sram_data_start; mmap_add_region((unsigned long)&__bl31_sram_data_start, (unsigned long)&__bl31_sram_data_start, sram_size, MT_MEMORY | MT_RW | MT_SECURE); sram_size = (char *)&__bl31_sram_stack_end - (char *)&__bl31_sram_stack_start; mmap_add_region((unsigned long)&__bl31_sram_stack_start, (unsigned long)&__bl31_sram_stack_start, sram_size, MT_MEMORY | MT_RW | MT_SECURE); sram_size = (char *)&__sram_incbin_end - (char *)&__sram_incbin_start; mmap_add_region((unsigned long)&__sram_incbin_start, (unsigned long)&__sram_incbin_start, sram_size, MT_NON_CACHEABLE | MT_RW | MT_SECURE); } void plat_rockchip_pmu_init(void) { uint32_t cpu; rockchip_pd_lock_init(); /* register requires 32bits mode, switch it to 32 bits */ cpu_warm_boot_addr = (uint64_t)platform_cpu_warmboot; for (cpu = 0; cpu < PLATFORM_CORE_COUNT; cpu++) cpuson_flags[cpu] = 0; for (cpu = 0; cpu < PLATFORM_CLUSTER_COUNT; cpu++) clst_warmboot_data[cpu] = 0; /* config cpu's warm boot address */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(1), (cpu_warm_boot_addr >> CPU_BOOT_ADDR_ALIGN) | CPU_BOOT_ADDR_WMASK); mmio_write_32(PMU_BASE + PMU_NOC_AUTO_ENA, NOC_AUTO_ENABLE); /* * Enable Schmitt trigger for better 32 kHz input signal, which is * important for suspend/resume reliability among other things. */ mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO0A_SMT, GPIO0A0_SMT_ENABLE); init_pmu_counts(); nonboot_cpus_off(); INFO("%s(%d): pd status %x\n", __func__, __LINE__, mmio_read_32(PMU_BASE + PMU_PWRDN_ST)); } trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/pmu/pmu.h000066400000000000000000000110261355360272700240500ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PMU_H #define PMU_H #include #include #include /* Allocate sp reginon in pmusram */ #define PSRAM_SP_SIZE 0x80 #define PSRAM_SP_BOTTOM (PSRAM_SP_TOP - PSRAM_SP_SIZE) /***************************************************************************** * Common define for per soc pmu.h *****************************************************************************/ /* The ways of cores power domain contorlling */ enum cores_pm_ctr_mode { core_pwr_pd = 0, core_pwr_wfi = 1, core_pwr_wfi_int = 2 }; /***************************************************************************** * pmu con,reg *****************************************************************************/ #define PMU_WKUP_CFG(n) ((n) * 4) #define PMU_CORE_PM_CON(cpu) (0xc0 + (cpu * 4)) /* the shift of bits for cores status */ enum pmu_core_pwrst_shift { clstl_cpu_wfe = 2, clstl_cpu_wfi = 6, clstb_cpu_wfe = 12, clstb_cpu_wfi = 16 }; #define CKECK_WFE_MSK 0x1 #define CKECK_WFI_MSK 0x10 #define CKECK_WFEI_MSK 0x11 /* Specific features required */ #define AP_PWROFF 0x0a #define GPIO0A0_SMT_ENABLE BITS_WITH_WMASK(1, 3, 0) #define GPIO1A6_IOMUX BITS_WITH_WMASK(0, 3, 12) #define TSADC_INT_PIN 38 #define CORES_PM_DISABLE 0x0 #define PD_CTR_LOOP 10000 #define CHK_CPU_LOOP 500 #define MAX_WAIT_COUNT 1000 #define GRF_SOC_CON4 0x0e210 #define PMUGRF_GPIO0A_SMT 0x0120 #define PMUGRF_SOC_CON0 0x0180 #define CCI_FORCE_WAKEUP WMSK_BIT(8) #define EXTERNAL_32K WMSK_BIT(0) #define PLL_PD_HW 0xff #define IOMUX_CLK_32K 0x00030002 #define NOC_AUTO_ENABLE 0x3fffffff #define SAVE_QOS(array, NAME) \ RK3399_CPU_AXI_SAVE_QOS(array, CPU_AXI_##NAME##_QOS_BASE) #define RESTORE_QOS(array, NAME) \ RK3399_CPU_AXI_RESTORE_QOS(array, CPU_AXI_##NAME##_QOS_BASE) #define RK3399_CPU_AXI_SAVE_QOS(array, base) do { \ array[0] = mmio_read_32(base + CPU_AXI_QOS_ID_COREID); \ array[1] = mmio_read_32(base + CPU_AXI_QOS_REVISIONID); \ array[2] = mmio_read_32(base + CPU_AXI_QOS_PRIORITY); \ array[3] = mmio_read_32(base + CPU_AXI_QOS_MODE); \ array[4] = mmio_read_32(base + CPU_AXI_QOS_BANDWIDTH); \ array[5] = mmio_read_32(base + CPU_AXI_QOS_SATURATION); \ array[6] = mmio_read_32(base + CPU_AXI_QOS_EXTCONTROL); \ } while (0) #define RK3399_CPU_AXI_RESTORE_QOS(array, base) do { \ mmio_write_32(base + CPU_AXI_QOS_ID_COREID, array[0]); \ mmio_write_32(base + CPU_AXI_QOS_REVISIONID, array[1]); \ mmio_write_32(base + CPU_AXI_QOS_PRIORITY, array[2]); \ mmio_write_32(base + CPU_AXI_QOS_MODE, array[3]); \ mmio_write_32(base + CPU_AXI_QOS_BANDWIDTH, array[4]); \ mmio_write_32(base + CPU_AXI_QOS_SATURATION, array[5]); \ mmio_write_32(base + CPU_AXI_QOS_EXTCONTROL, array[6]); \ } while (0) struct pmu_slpdata_s { uint32_t cci_m0_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t cci_m1_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t dmac0_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t dmac1_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t dcf_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t crypto0_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t crypto1_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t pmu_cm0_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t peri_cm1_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t gic_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t sdmmc_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t gmac_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t emmc_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t usb_otg0_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t usb_otg1_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t usb_host0_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t usb_host1_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t gpu_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t video_m0_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t video_m1_r_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t video_m1_w_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t rga_r_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t rga_w_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t vop_big_r[CPU_AXI_QOS_NUM_REGS]; uint32_t vop_big_w[CPU_AXI_QOS_NUM_REGS]; uint32_t vop_little[CPU_AXI_QOS_NUM_REGS]; uint32_t iep_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t isp1_m0_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t isp1_m1_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t isp0_m0_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t isp0_m1_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t hdcp_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t perihp_nsp_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t perilp_nsp_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t perilpslv_nsp_qos[CPU_AXI_QOS_NUM_REGS]; uint32_t sdio_qos[CPU_AXI_QOS_NUM_REGS]; }; extern uint32_t clst_warmboot_data[PLATFORM_CLUSTER_COUNT]; extern void sram_func_set_ddrctl_pll(uint32_t pll_src); #endif /* PMU_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/pmu/pmu_fw.c000066400000000000000000000012101355360272700245310ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* convoluted way to make sure that the define is pasted just the right way */ #define _INCBIN(file, sym, sec) \ __asm__( \ ".section " #sec "\n" \ ".global " #sym "\n" \ ".type " #sym ", %object\n" \ ".align 4\n" \ #sym ":\n" \ ".incbin \"" #file "\"\n" \ ".size " #sym ", .-" #sym "\n" \ ".global " #sym "_end\n" \ #sym "_end:\n" \ ) #define INCBIN(file, sym, sec) _INCBIN(file, sym, sec) INCBIN(RK3399M0FW, rk3399m0_bin, ".sram.incbin"); INCBIN(RK3399M0PMUFW, rk3399m0pmu_bin, ".pmusram.incbin"); trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/pwm/000077500000000000000000000000001355360272700231005ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/pwm/pwm.c000066400000000000000000000066421355360272700240570ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #define PWM0_IOMUX_PWM_EN (1 << 0) #define PWM1_IOMUX_PWM_EN (1 << 1) #define PWM2_IOMUX_PWM_EN (1 << 2) #define PWM3_IOMUX_PWM_EN (1 << 3) struct pwm_data_s { uint32_t iomux_bitmask; uint32_t enable_bitmask; }; static struct pwm_data_s pwm_data; /* * Disable the PWMs. */ void disable_pwms(void) { uint32_t i, val; pwm_data.iomux_bitmask = 0; /* Save PWMs pinmux and change PWMs pinmux to GPIOs */ val = mmio_read_32(GRF_BASE + GRF_GPIO4C_IOMUX); if (((val >> GRF_GPIO4C2_IOMUX_SHIFT) & GRF_IOMUX_2BIT_MASK) == GRF_GPIO4C2_IOMUX_PWM) { pwm_data.iomux_bitmask |= PWM0_IOMUX_PWM_EN; val = BITS_WITH_WMASK(GRF_IOMUX_GPIO, GRF_IOMUX_2BIT_MASK, GRF_GPIO4C2_IOMUX_SHIFT); mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, val); } val = mmio_read_32(GRF_BASE + GRF_GPIO4C_IOMUX); if (((val >> GRF_GPIO4C6_IOMUX_SHIFT) & GRF_IOMUX_2BIT_MASK) == GRF_GPIO4C6_IOMUX_PWM) { pwm_data.iomux_bitmask |= PWM1_IOMUX_PWM_EN; val = BITS_WITH_WMASK(GRF_IOMUX_GPIO, GRF_IOMUX_2BIT_MASK, GRF_GPIO4C6_IOMUX_SHIFT); mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, val); } val = mmio_read_32(PMUGRF_BASE + PMUGRF_GPIO1C_IOMUX); if (((val >> PMUGRF_GPIO1C3_IOMUX_SHIFT) & GRF_IOMUX_2BIT_MASK) == PMUGRF_GPIO1C3_IOMUX_PWM) { pwm_data.iomux_bitmask |= PWM2_IOMUX_PWM_EN; val = BITS_WITH_WMASK(GRF_IOMUX_GPIO, GRF_IOMUX_2BIT_MASK, PMUGRF_GPIO1C3_IOMUX_SHIFT); mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO1C_IOMUX, val); } val = mmio_read_32(PMUGRF_BASE + PMUGRF_GPIO0A_IOMUX); if (((val >> PMUGRF_GPIO0A6_IOMUX_SHIFT) & GRF_IOMUX_2BIT_MASK) == PMUGRF_GPIO0A6_IOMUX_PWM) { pwm_data.iomux_bitmask |= PWM3_IOMUX_PWM_EN; val = BITS_WITH_WMASK(GRF_IOMUX_GPIO, GRF_IOMUX_2BIT_MASK, PMUGRF_GPIO0A6_IOMUX_SHIFT); mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO0A_IOMUX, val); } /* Disable the pwm channel */ pwm_data.enable_bitmask = 0; for (i = 0; i < 4; i++) { val = mmio_read_32(PWM_BASE + PWM_CTRL(i)); if ((val & PWM_ENABLE) != PWM_ENABLE) continue; pwm_data.enable_bitmask |= (1 << i); mmio_write_32(PWM_BASE + PWM_CTRL(i), val & ~PWM_ENABLE); } } /* * Enable the PWMs. */ void enable_pwms(void) { uint32_t i, val; for (i = 0; i < 4; i++) { val = mmio_read_32(PWM_BASE + PWM_CTRL(i)); if (!(pwm_data.enable_bitmask & (1 << i))) continue; mmio_write_32(PWM_BASE + PWM_CTRL(i), val | PWM_ENABLE); } /* Restore all IOMUXes */ if (pwm_data.iomux_bitmask & PWM3_IOMUX_PWM_EN) { val = BITS_WITH_WMASK(PMUGRF_GPIO0A6_IOMUX_PWM, GRF_IOMUX_2BIT_MASK, PMUGRF_GPIO0A6_IOMUX_SHIFT); mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO0A_IOMUX, val); } if (pwm_data.iomux_bitmask & PWM2_IOMUX_PWM_EN) { val = BITS_WITH_WMASK(PMUGRF_GPIO1C3_IOMUX_PWM, GRF_IOMUX_2BIT_MASK, PMUGRF_GPIO1C3_IOMUX_SHIFT); mmio_write_32(PMUGRF_BASE + PMUGRF_GPIO1C_IOMUX, val); } if (pwm_data.iomux_bitmask & PWM1_IOMUX_PWM_EN) { val = BITS_WITH_WMASK(GRF_GPIO4C6_IOMUX_PWM, GRF_IOMUX_2BIT_MASK, GRF_GPIO4C6_IOMUX_SHIFT); mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, val); } if (pwm_data.iomux_bitmask & PWM0_IOMUX_PWM_EN) { val = BITS_WITH_WMASK(GRF_GPIO4C2_IOMUX_PWM, GRF_IOMUX_2BIT_MASK, GRF_GPIO4C2_IOMUX_SHIFT); mmio_write_32(GRF_BASE + GRF_GPIO4C_IOMUX, val); } } trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/pwm/pwm.h000066400000000000000000000003401355360272700240510ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PWM_H #define PWM_H void disable_pwms(void); void enable_pwms(void); #endif /* PWM_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/secure/000077500000000000000000000000001355360272700235635ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/secure/secure.c000066400000000000000000000120761355360272700252230ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include static void sgrf_ddr_rgn_global_bypass(uint32_t bypass) { if (bypass) /* set bypass (non-secure regions) for whole ddr regions */ mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(16), SGRF_DDR_RGN_BYPS); else /* cancel bypass for whole ddr regions */ mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(16), SGRF_DDR_RGN_NO_BYPS); } /** * There are 8 + 1 regions for DDR secure control: * DDR_RGN_0 ~ DDR_RGN_7: Per DDR_RGNs grain size is 1MB * DDR_RGN_X - the memories of exclude DDR_RGN_0 ~ DDR_RGN_7 * * DDR_RGN_0 - start address of the RGN0 * DDR_RGN_8 - end address of the RGN0 * DDR_RGN_1 - start address of the RGN1 * DDR_RGN_9 - end address of the RGN1 * ... * DDR_RGN_7 - start address of the RGN7 * DDR_RGN_15 - end address of the RGN7 * DDR_RGN_16 - bit 0 ~ 7 is bitmap for RGN0~7 secure,0: disable, 1: enable * bit 8 is setting for RGNx, the rest of the memory and region * which excludes RGN0~7, 0: disable, 1: enable * bit 9, the global secure configuration via bypass, 0: disable * bypass, 1: enable bypass * * @rgn - the DDR regions 0 ~ 7 which are can be configured. * The @st_mb and @ed_mb indicate the start and end addresses for which to set * the security, and the unit is megabyte. When the st_mb == 0, ed_mb == 0, the * address range 0x0 ~ 0xfffff is secure. * * For example, if we would like to set the range [0, 32MB) is security via * DDR_RGN0, then rgn == 0, st_mb == 0, ed_mb == 31. */ static void sgrf_ddr_rgn_config(uint32_t rgn, uintptr_t st, uintptr_t ed) { uintptr_t st_mb, ed_mb; assert(rgn <= 7); assert(st < ed); /* check aligned 1MB */ assert(st % SIZE_M(1) == 0); assert(ed % SIZE_M(1) == 0); st_mb = st / SIZE_M(1); ed_mb = ed / SIZE_M(1); /* set ddr region addr start */ mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(rgn), BITS_WITH_WMASK(st_mb, SGRF_DDR_RGN_0_16_WMSK, 0)); /* set ddr region addr end */ mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(rgn + 8), BITS_WITH_WMASK((ed_mb - 1), SGRF_DDR_RGN_0_16_WMSK, 0)); mmio_write_32(SGRF_BASE + SGRF_DDRRGN_CON0_16(16), BIT_WITH_WMSK(rgn)); } void secure_watchdog_gate(void) { /** * Disable CA53 and CM0 wdt pclk * BIT[8]: ca53 wdt pclk, 0: enable 1: disable * BIT[10]: cm0 wdt pclk, 0: enable 1: disable */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(3), BIT_WITH_WMSK(PCLK_WDT_CA53_GATE_SHIFT) | BIT_WITH_WMSK(PCLK_WDT_CM0_GATE_SHIFT)); } __pmusramfunc void secure_watchdog_ungate(void) { /** * Enable CA53 and CM0 wdt pclk * BIT[8]: ca53 wdt pclk, 0: enable 1: disable * BIT[10]: cm0 wdt pclk, 0: enable 1: disable */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(3), WMSK_BIT(PCLK_WDT_CA53_GATE_SHIFT) | WMSK_BIT(PCLK_WDT_CM0_GATE_SHIFT)); } __pmusramfunc void sram_secure_timer_init(void) { mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_END_COUNT0, 0xffffffff); mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_END_COUNT1, 0xffffffff); mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_INIT_COUNT0, 0x0); mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_INIT_COUNT0, 0x0); /* auto reload & enable the timer */ mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_CONTROL_REG, TIMER_EN | TIMER_FMODE); } void secure_timer_init(void) { mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_END_COUNT0, 0xffffffff); mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_END_COUNT1, 0xffffffff); mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_INIT_COUNT0, 0x0); mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_INIT_COUNT0, 0x0); /* auto reload & enable the timer */ mmio_write_32(STIMER1_CHN_BASE(5) + TIMER_CONTROL_REG, TIMER_EN | TIMER_FMODE); } void secure_sgrf_init(void) { /* security config for master */ mmio_write_32(SGRF_BASE + SGRF_SOC_CON(5), REG_SOC_WMSK | SGRF_SOC_ALLMST_NS); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(6), REG_SOC_WMSK | SGRF_SOC_ALLMST_NS); mmio_write_32(SGRF_BASE + SGRF_SOC_CON(7), REG_SOC_WMSK | SGRF_SOC_ALLMST_NS); /* security config for slave */ mmio_write_32(SGRF_BASE + SGRF_PMU_SLV_CON0_1(0), SGRF_PMU_SLV_S_CFGED | SGRF_PMU_SLV_CRYPTO1_NS); mmio_write_32(SGRF_BASE + SGRF_PMU_SLV_CON0_1(1), SGRF_SLV_S_WMSK | SGRF_PMUSRAM_S); mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(0), SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS); mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(1), SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS); mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(2), SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS); mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(3), SGRF_SLV_S_WMSK | SGRF_SLV_S_ALL_NS); mmio_write_32(SGRF_BASE + SGRF_SLV_SECURE_CON0_4(4), SGRF_SLV_S_WMSK | SGRF_INTSRAM_S); } void secure_sgrf_ddr_rgn_init(void) { sgrf_ddr_rgn_config(0, TZRAM_BASE, TZRAM_SIZE); sgrf_ddr_rgn_global_bypass(0); } trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/secure/secure.h000066400000000000000000000060561355360272700252310ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SECURE_H #define SECURE_H /************************************************** * sgrf reg, offset **************************************************/ #define SGRF_SOC_CON0_1(n) (0xc000 + (n) * 4) #define SGRF_SOC_CON3_7(n) (0xe00c + ((n) - 3) * 4) #define SGRF_SOC_CON8_15(n) (0x8020 + ((n) - 8) * 4) #define SGRF_SOC_CON(n) (n < 3 ? SGRF_SOC_CON0_1(n) :\ (n < 8 ? SGRF_SOC_CON3_7(n) :\ SGRF_SOC_CON8_15(n))) #define SGRF_PMU_SLV_CON0_1(n) (0xc240 + ((n) - 0) * 4) #define SGRF_SLV_SECURE_CON0_4(n) (0xe3c0 + ((n) - 0) * 4) #define SGRF_DDRRGN_CON0_16(n) ((n) * 4) #define SGRF_DDRRGN_CON20_34(n) (0x50 + ((n) - 20) * 4) /* All of master in ns */ #define SGRF_SOC_ALLMST_NS 0xffff /* security config for slave */ #define SGRF_SLV_S_WMSK 0xffff0000 #define SGRF_SLV_S_ALL_NS 0x0 /* security config pmu slave ip */ /* All of slaves is ns */ #define SGRF_PMU_SLV_S_NS BIT_WITH_WMSK(0) /* slaves secure attr is configed */ #define SGRF_PMU_SLV_S_CFGED WMSK_BIT(0) #define SGRF_PMU_SLV_CRYPTO1_NS WMSK_BIT(1) #define SGRF_PMUSRAM_S BIT(8) #define SGRF_INTSRAM_S BIT(13) /* ddr region */ #define SGRF_DDR_RGN_0_16_WMSK 0x0fff /* DDR RGN 0~16 size mask */ #define SGRF_DDR_RGN_DPLL_CLK BIT_WITH_WMSK(15) /* DDR PLL output clock */ #define SGRF_DDR_RGN_RTC_CLK BIT_WITH_WMSK(14) /* 32K clock for DDR PLL */ /* All security of the DDR RGNs are bypass */ #define SGRF_DDR_RGN_BYPS BIT_WITH_WMSK(9) /* All security of the DDR RGNs are not bypass */ #define SGRF_DDR_RGN_NO_BYPS WMSK_BIT(9) /* The MST access the ddr rgn n with secure attribution */ #define SGRF_L_MST_S_DDR_RGN(n) BIT_WITH_WMSK((n)) /* bits[16:8]*/ #define SGRF_H_MST_S_DDR_RGN(n) BIT_WITH_WMSK((n) + 8) #define SGRF_PMU_CON0 0x0c100 #define SGRF_PMU_CON(n) (SGRF_PMU_CON0 + (n) * 4) /************************************************** * secure timer **************************************************/ /* chanal0~5 */ #define STIMER0_CHN_BASE(n) (STIME_BASE + 0x20 * (n)) /* chanal6~11 */ #define STIMER1_CHN_BASE(n) (STIME_BASE + 0x8000 + 0x20 * (n)) /* low 32 bits */ #define TIMER_END_COUNT0 0x00 /* high 32 bits */ #define TIMER_END_COUNT1 0x04 #define TIMER_CURRENT_VALUE0 0x08 #define TIMER_CURRENT_VALUE1 0x0C /* low 32 bits */ #define TIMER_INIT_COUNT0 0x10 /* high 32 bits */ #define TIMER_INIT_COUNT1 0x14 #define TIMER_INTSTATUS 0x18 #define TIMER_CONTROL_REG 0x1c #define TIMER_EN 0x1 #define TIMER_FMODE (0x0 << 1) #define TIMER_RMODE (0x1 << 1) /************************************************** * secure WDT **************************************************/ #define PCLK_WDT_CA53_GATE_SHIFT 8 #define PCLK_WDT_CM0_GATE_SHIFT 10 /* export secure operating APIs */ void secure_watchdog_gate(void); __pmusramfunc void secure_watchdog_ungate(void); void secure_timer_init(void); void secure_sgrf_init(void); void secure_sgrf_ddr_rgn_init(void); __pmusramfunc void sram_secure_timer_init(void); #endif /* SECURE_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/soc/000077500000000000000000000000001355360272700230615ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/soc/soc.c000066400000000000000000000221161355360272700240130ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* Table of regions to map using the MMU. */ const mmap_region_t plat_rk_mmap[] = { MAP_REGION_FLAT(DEV_RNG0_BASE, DEV_RNG0_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(PMUSRAM_BASE, PMUSRAM_SIZE, MT_MEMORY | MT_RW | MT_SECURE), { 0 } }; /* The RockChip power domain tree descriptor */ const unsigned char rockchip_power_domain_tree_desc[] = { /* No of root nodes */ PLATFORM_SYSTEM_COUNT, /* No of children for the root node */ PLATFORM_CLUSTER_COUNT, /* No of children for the first cluster node */ PLATFORM_CLUSTER0_CORE_COUNT, /* No of children for the second cluster node */ PLATFORM_CLUSTER1_CORE_COUNT }; /* sleep data for pll suspend */ static struct deepsleep_data_s slp_data; /* sleep data that needs to be accessed from pmusram */ __pmusramdata struct pmu_sleep_data pmu_slp_data; static void set_pll_slow_mode(uint32_t pll_id) { if (pll_id == PPLL_ID) mmio_write_32(PMUCRU_BASE + PMUCRU_PPLL_CON(3), PLL_SLOW_MODE); else mmio_write_32((CRU_BASE + CRU_PLL_CON(pll_id, 3)), PLL_SLOW_MODE); } static void set_pll_normal_mode(uint32_t pll_id) { if (pll_id == PPLL_ID) mmio_write_32(PMUCRU_BASE + PMUCRU_PPLL_CON(3), PLL_NOMAL_MODE); else mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3), PLL_NOMAL_MODE); } static void set_pll_bypass(uint32_t pll_id) { if (pll_id == PPLL_ID) mmio_write_32(PMUCRU_BASE + PMUCRU_PPLL_CON(3), PLL_BYPASS_MODE); else mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3), PLL_BYPASS_MODE); } static void _pll_suspend(uint32_t pll_id) { set_pll_slow_mode(pll_id); set_pll_bypass(pll_id); } /** * disable_dvfs_plls - To suspend the specific PLLs * * When we close the center logic, the DPLL will be closed, * so we need to keep the ABPLL and switch to it to supply * clock for DDR during suspend, then we should not close * the ABPLL and exclude ABPLL_ID. */ void disable_dvfs_plls(void) { _pll_suspend(CPLL_ID); _pll_suspend(NPLL_ID); _pll_suspend(VPLL_ID); _pll_suspend(GPLL_ID); _pll_suspend(ALPLL_ID); } /** * disable_nodvfs_plls - To suspend the PPLL */ void disable_nodvfs_plls(void) { _pll_suspend(PPLL_ID); } /** * restore_pll - Copy PLL settings from memory to a PLL. * * This will copy PLL settings from an array in memory to the memory mapped * registers for a PLL. * * Note that: above the PLL exclude PPLL. * * pll_id: One of the values from enum plls_id * src: Pointer to the array of values to restore from */ static void restore_pll(int pll_id, uint32_t *src) { /* Nice to have PLL off while configuring */ mmio_write_32((CRU_BASE + CRU_PLL_CON(pll_id, 3)), PLL_SLOW_MODE); mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 0), src[0] | REG_SOC_WMSK); mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 1), src[1] | REG_SOC_WMSK); mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 2), src[2]); mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 4), src[4] | REG_SOC_WMSK); mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 5), src[5] | REG_SOC_WMSK); /* Do PLL_CON3 since that will enable things */ mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3), src[3] | REG_SOC_WMSK); /* Wait for PLL lock done */ while ((mmio_read_32(CRU_BASE + CRU_PLL_CON(pll_id, 2)) & 0x80000000) == 0x0) ; } /** * save_pll - Copy PLL settings a PLL to memory * * This will copy PLL settings from the memory mapped registers for a PLL to * an array in memory. * * Note that: above the PLL exclude PPLL. * * pll_id: One of the values from enum plls_id * src: Pointer to the array of values to save to. */ static void save_pll(uint32_t *dst, int pll_id) { int i; for (i = 0; i < PLL_CON_COUNT; i++) dst[i] = mmio_read_32(CRU_BASE + CRU_PLL_CON(pll_id, i)); } /** * prepare_abpll_for_ddrctrl - Copy DPLL settings to ABPLL * * This will copy DPLL settings from the memory mapped registers for a PLL to * an array in memory. */ void prepare_abpll_for_ddrctrl(void) { save_pll(slp_data.plls_con[ABPLL_ID], ABPLL_ID); save_pll(slp_data.plls_con[DPLL_ID], DPLL_ID); restore_pll(ABPLL_ID, slp_data.plls_con[DPLL_ID]); } void restore_abpll(void) { restore_pll(ABPLL_ID, slp_data.plls_con[ABPLL_ID]); } void clk_gate_con_save(void) { uint32_t i = 0; for (i = 0; i < PMUCRU_GATE_COUNT; i++) slp_data.pmucru_gate_con[i] = mmio_read_32(PMUCRU_BASE + PMUCRU_GATE_CON(i)); for (i = 0; i < CRU_GATE_COUNT; i++) slp_data.cru_gate_con[i] = mmio_read_32(CRU_BASE + CRU_GATE_CON(i)); } void clk_gate_con_disable(void) { uint32_t i; for (i = 0; i < PMUCRU_GATE_COUNT; i++) mmio_write_32(PMUCRU_BASE + PMUCRU_GATE_CON(i), REG_SOC_WMSK); for (i = 0; i < CRU_GATE_COUNT; i++) mmio_write_32(CRU_BASE + CRU_GATE_CON(i), REG_SOC_WMSK); } void clk_gate_con_restore(void) { uint32_t i; for (i = 0; i < PMUCRU_GATE_COUNT; i++) mmio_write_32(PMUCRU_BASE + PMUCRU_GATE_CON(i), REG_SOC_WMSK | slp_data.pmucru_gate_con[i]); for (i = 0; i < CRU_GATE_COUNT; i++) mmio_write_32(CRU_BASE + CRU_GATE_CON(i), REG_SOC_WMSK | slp_data.cru_gate_con[i]); } static void set_plls_nobypass(uint32_t pll_id) { if (pll_id == PPLL_ID) mmio_write_32(PMUCRU_BASE + PMUCRU_PPLL_CON(3), PLL_NO_BYPASS_MODE); else mmio_write_32(CRU_BASE + CRU_PLL_CON(pll_id, 3), PLL_NO_BYPASS_MODE); } static void _pll_resume(uint32_t pll_id) { set_plls_nobypass(pll_id); set_pll_normal_mode(pll_id); } void set_pmu_rsthold(void) { uint32_t rstnhold_cofig0; uint32_t rstnhold_cofig1; pmu_slp_data.pmucru_rstnhold_con0 = mmio_read_32(PMUCRU_BASE + PMUCRU_RSTNHOLD_CON0); pmu_slp_data.pmucru_rstnhold_con1 = mmio_read_32(PMUCRU_BASE + PMUCRU_RSTNHOLD_CON1); rstnhold_cofig0 = BIT_WITH_WMSK(PRESETN_NOC_PMU_HOLD) | BIT_WITH_WMSK(PRESETN_INTMEM_PMU_HOLD) | BIT_WITH_WMSK(HRESETN_CM0S_PMU_HOLD) | BIT_WITH_WMSK(HRESETN_CM0S_NOC_PMU_HOLD) | BIT_WITH_WMSK(DRESETN_CM0S_PMU_HOLD) | BIT_WITH_WMSK(POESETN_CM0S_PMU_HOLD) | BIT_WITH_WMSK(PRESETN_TIMER_PMU_0_1_HOLD) | BIT_WITH_WMSK(RESETN_TIMER_PMU_0_HOLD) | BIT_WITH_WMSK(RESETN_TIMER_PMU_1_HOLD) | BIT_WITH_WMSK(PRESETN_UART_M0_PMU_HOLD) | BIT_WITH_WMSK(RESETN_UART_M0_PMU_HOLD) | BIT_WITH_WMSK(PRESETN_WDT_PMU_HOLD); rstnhold_cofig1 = BIT_WITH_WMSK(PRESETN_RKPWM_PMU_HOLD) | BIT_WITH_WMSK(PRESETN_PMUGRF_HOLD) | BIT_WITH_WMSK(PRESETN_SGRF_HOLD) | BIT_WITH_WMSK(PRESETN_GPIO0_HOLD) | BIT_WITH_WMSK(PRESETN_GPIO1_HOLD) | BIT_WITH_WMSK(PRESETN_CRU_PMU_HOLD) | BIT_WITH_WMSK(PRESETN_PVTM_PMU_HOLD); mmio_write_32(PMUCRU_BASE + PMUCRU_RSTNHOLD_CON0, rstnhold_cofig0); mmio_write_32(PMUCRU_BASE + PMUCRU_RSTNHOLD_CON1, rstnhold_cofig1); } void pmu_sgrf_rst_hld(void) { mmio_write_32(PMUCRU_BASE + CRU_PMU_RSTHOLD_CON(1), CRU_PMU_SGRF_RST_HOLD); } /* * When system reset in running state, we want the cpus to be reboot * from maskrom (system reboot), * the pmusgrf reset-hold bits needs to be released. * When system wake up from system deep suspend, some soc will be reset * when waked up, * we want the bootcpu to be reboot from pmusram, * the pmusgrf reset-hold bits needs to be held. */ __pmusramfunc void pmu_sgrf_rst_hld_release(void) { mmio_write_32(PMUCRU_BASE + CRU_PMU_RSTHOLD_CON(1), CRU_PMU_SGRF_RST_RLS); } __pmusramfunc void restore_pmu_rsthold(void) { mmio_write_32(PMUCRU_BASE + PMUCRU_RSTNHOLD_CON0, pmu_slp_data.pmucru_rstnhold_con0 | REG_SOC_WMSK); mmio_write_32(PMUCRU_BASE + PMUCRU_RSTNHOLD_CON1, pmu_slp_data.pmucru_rstnhold_con1 | REG_SOC_WMSK); } /** * enable_dvfs_plls - To resume the specific PLLs * * Please see the comment at the disable_dvfs_plls() * we don't suspend the ABPLL, so don't need resume * it too. */ void enable_dvfs_plls(void) { _pll_resume(ALPLL_ID); _pll_resume(GPLL_ID); _pll_resume(VPLL_ID); _pll_resume(NPLL_ID); _pll_resume(CPLL_ID); } /** * enable_nodvfs_plls - To resume the PPLL */ void enable_nodvfs_plls(void) { _pll_resume(PPLL_ID); } void soc_global_soft_reset_init(void) { mmio_write_32(PMUCRU_BASE + CRU_PMU_RSTHOLD_CON(1), CRU_PMU_SGRF_RST_RLS); mmio_clrbits_32(CRU_BASE + CRU_GLB_RST_CON, CRU_PMU_WDTRST_MSK | CRU_PMU_FIRST_SFTRST_MSK); } void __dead2 soc_global_soft_reset(void) { set_pll_slow_mode(VPLL_ID); set_pll_slow_mode(NPLL_ID); set_pll_slow_mode(GPLL_ID); set_pll_slow_mode(CPLL_ID); set_pll_slow_mode(PPLL_ID); set_pll_slow_mode(ABPLL_ID); set_pll_slow_mode(ALPLL_ID); dsb(); mmio_write_32(CRU_BASE + CRU_GLB_SRST_FST, GLB_SRST_FST_CFG_VAL); /* * Maybe the HW needs some times to reset the system, * so we do not hope the core to excute valid codes. */ while (1) ; } void plat_rockchip_soc_init(void) { secure_timer_init(); secure_sgrf_init(); secure_sgrf_ddr_rgn_init(); soc_global_soft_reset_init(); plat_rockchip_gpio_init(); m0_init(); dram_init(); dram_dfs_init(); } trusted-firmware-a-2.2/plat/rockchip/rk3399/drivers/soc/soc.h000066400000000000000000000161771355360272700240320ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SOC_H #define SOC_H #include #define GLB_SRST_FST_CFG_VAL 0xfdb9 #define GLB_SRST_SND_CFG_VAL 0xeca8 #define PMUCRU_PPLL_CON(n) ((n) * 4) #define CRU_PLL_CON(pll_id, n) ((pll_id) * 0x20 + (n) * 4) #define PLL_MODE_MSK 0x03 #define PLL_MODE_SHIFT 0x08 #define PLL_BYPASS_MSK 0x01 #define PLL_BYPASS_SHIFT 0x01 #define PLL_PWRDN_MSK 0x01 #define PLL_PWRDN_SHIFT 0x0 #define PLL_BYPASS BIT(1) #define PLL_PWRDN BIT(0) #define NO_PLL_BYPASS (0x00) #define NO_PLL_PWRDN (0x00) #define FBDIV(n) ((0xfff << 16) | n) #define POSTDIV2(n) ((0x7 << (12 + 16)) | (n << 12)) #define POSTDIV1(n) ((0x7 << (8 + 16)) | (n << 8)) #define REFDIV(n) ((0x3F << 16) | n) #define PLL_LOCK(n) ((n >> 31) & 0x1) #define PLL_SLOW_MODE BITS_WITH_WMASK(SLOW_MODE,\ PLL_MODE_MSK, PLL_MODE_SHIFT) #define PLL_NOMAL_MODE BITS_WITH_WMASK(NORMAL_MODE,\ PLL_MODE_MSK, PLL_MODE_SHIFT) #define PLL_BYPASS_MODE BIT_WITH_WMSK(PLL_BYPASS_SHIFT) #define PLL_NO_BYPASS_MODE WMSK_BIT(PLL_BYPASS_SHIFT) #define PLL_CON_COUNT 0x06 #define CRU_CLKSEL_COUNT 108 #define CRU_CLKSEL_CON(n) (0x100 + (n) * 4) #define PMUCRU_CLKSEL_CONUT 0x06 #define PMUCRU_CLKSEL_OFFSET 0x080 #define REG_SIZE 0x04 #define REG_SOC_WMSK 0xffff0000 #define CLK_GATE_MASK 0x01 #define PMUCRU_GATE_COUNT 0x03 #define CRU_GATE_COUNT 0x23 #define PMUCRU_GATE_CON(n) (0x100 + (n) * 4) #define CRU_GATE_CON(n) (0x300 + (n) * 4) #define PMUCRU_RSTNHOLD_CON0 0x120 enum { PRESETN_NOC_PMU_HOLD = 1, PRESETN_INTMEM_PMU_HOLD, HRESETN_CM0S_PMU_HOLD, HRESETN_CM0S_NOC_PMU_HOLD, DRESETN_CM0S_PMU_HOLD, POESETN_CM0S_PMU_HOLD, PRESETN_SPI3_HOLD, RESETN_SPI3_HOLD, PRESETN_TIMER_PMU_0_1_HOLD, RESETN_TIMER_PMU_0_HOLD, RESETN_TIMER_PMU_1_HOLD, PRESETN_UART_M0_PMU_HOLD, RESETN_UART_M0_PMU_HOLD, PRESETN_WDT_PMU_HOLD }; #define PMUCRU_RSTNHOLD_CON1 0x124 enum { PRESETN_I2C0_HOLD, PRESETN_I2C4_HOLD, PRESETN_I2C8_HOLD, PRESETN_MAILBOX_PMU_HOLD, PRESETN_RKPWM_PMU_HOLD, PRESETN_PMUGRF_HOLD, PRESETN_SGRF_HOLD, PRESETN_GPIO0_HOLD, PRESETN_GPIO1_HOLD, PRESETN_CRU_PMU_HOLD, PRESETN_INTR_ARB_HOLD, PRESETN_PVTM_PMU_HOLD, RESETN_I2C0_HOLD, RESETN_I2C4_HOLD, RESETN_I2C8_HOLD }; enum plls_id { ALPLL_ID = 0, ABPLL_ID, DPLL_ID, CPLL_ID, GPLL_ID, NPLL_ID, VPLL_ID, PPLL_ID, END_PLL_ID, }; #define CLST_L_CPUS_MSK (0xf) #define CLST_B_CPUS_MSK (0x3) enum pll_work_mode { SLOW_MODE = 0x00, NORMAL_MODE = 0x01, DEEP_SLOW_MODE = 0x02, }; enum glb_sft_reset { PMU_RST_BY_FIRST_SFT, PMU_RST_BY_SECOND_SFT = BIT(2), PMU_RST_NOT_BY_SFT = BIT(3), }; struct pll_div { uint32_t mhz; uint32_t refdiv; uint32_t fbdiv; uint32_t postdiv1; uint32_t postdiv2; uint32_t frac; uint32_t freq; }; struct deepsleep_data_s { uint32_t plls_con[END_PLL_ID][PLL_CON_COUNT]; uint32_t cru_gate_con[CRU_GATE_COUNT]; uint32_t pmucru_gate_con[PMUCRU_GATE_COUNT]; }; struct pmu_sleep_data { uint32_t pmucru_rstnhold_con0; uint32_t pmucru_rstnhold_con1; }; /************************************************** * pmugrf reg, offset **************************************************/ #define PMUGRF_OSREG(n) (0x300 + (n) * 4) /************************************************** * DCF reg, offset **************************************************/ #define DCF_DCF_CTRL 0x0 #define DCF_DCF_ADDR 0x8 #define DCF_DCF_ISR 0xc #define DCF_DCF_TOSET 0x14 #define DCF_DCF_TOCMD 0x18 #define DCF_DCF_CMD_CFG 0x1c /* DCF_DCF_ISR */ #define DCF_TIMEOUT (1 << 2) #define DCF_ERR (1 << 1) #define DCF_DONE (1 << 0) /* DCF_DCF_CTRL */ #define DCF_VOP_HW_EN (1 << 2) #define DCF_STOP (1 << 1) #define DCF_START (1 << 0) #define CYCL_24M_CNT_US(us) (24 * us) #define CYCL_24M_CNT_MS(ms) (ms * CYCL_24M_CNT_US(1000)) #define CYCL_32K_CNT_MS(ms) (ms * 32) /************************************************** * cru reg, offset **************************************************/ #define CRU_SOFTRST_CON(n) (0x400 + (n) * 4) #define CRU_DMAC0_RST BIT_WITH_WMSK(3) /* reset release*/ #define CRU_DMAC0_RST_RLS WMSK_BIT(3) #define CRU_DMAC1_RST BIT_WITH_WMSK(4) /* reset release*/ #define CRU_DMAC1_RST_RLS WMSK_BIT(4) #define CRU_GLB_RST_CON 0x0510 #define CRU_GLB_SRST_FST 0x0500 #define CRU_GLB_SRST_SND 0x0504 #define CRU_CLKGATE_CON(n) (0x300 + n * 4) #define PCLK_GPIO2_GATE_SHIFT 3 #define PCLK_GPIO3_GATE_SHIFT 4 #define PCLK_GPIO4_GATE_SHIFT 5 /************************************************** * pmu cru reg, offset **************************************************/ #define CRU_PMU_RSTHOLD_CON(n) (0x120 + n * 4) /* reset hold*/ #define CRU_PMU_SGRF_RST_HOLD BIT_WITH_WMSK(6) /* reset hold release*/ #define CRU_PMU_SGRF_RST_RLS WMSK_BIT(6) #define CRU_PMU_WDTRST_MSK (0x1 << 4) #define CRU_PMU_WDTRST_EN 0x0 #define CRU_PMU_FIRST_SFTRST_MSK (0x3 << 2) #define CRU_PMU_FIRST_SFTRST_EN 0x0 #define CRU_PMU_CLKGATE_CON(n) (0x100 + n * 4) #define PCLK_GPIO0_GATE_SHIFT 3 #define PCLK_GPIO1_GATE_SHIFT 4 #define CPU_BOOT_ADDR_WMASK 0xffff0000 #define CPU_BOOT_ADDR_ALIGN 16 #define GRF_IOMUX_2BIT_MASK 0x3 #define GRF_IOMUX_GPIO 0x0 #define GRF_GPIO4C2_IOMUX_SHIFT 4 #define GRF_GPIO4C2_IOMUX_PWM 0x1 #define GRF_GPIO4C6_IOMUX_SHIFT 12 #define GRF_GPIO4C6_IOMUX_PWM 0x1 #define PWM_CNT(n) (0x0000 + 0x10 * (n)) #define PWM_PERIOD_HPR(n) (0x0004 + 0x10 * (n)) #define PWM_DUTY_LPR(n) (0x0008 + 0x10 * (n)) #define PWM_CTRL(n) (0x000c + 0x10 * (n)) #define PWM_DISABLE (0 << 0) #define PWM_ENABLE (1 << 0) /* grf reg offset */ #define GRF_USBPHY0_CTRL0 0x4480 #define GRF_USBPHY0_CTRL2 0x4488 #define GRF_USBPHY0_CTRL3 0x448c #define GRF_USBPHY0_CTRL12 0x44b0 #define GRF_USBPHY0_CTRL13 0x44b4 #define GRF_USBPHY0_CTRL15 0x44bc #define GRF_USBPHY0_CTRL16 0x44c0 #define GRF_USBPHY1_CTRL0 0x4500 #define GRF_USBPHY1_CTRL2 0x4508 #define GRF_USBPHY1_CTRL3 0x450c #define GRF_USBPHY1_CTRL12 0x4530 #define GRF_USBPHY1_CTRL13 0x4534 #define GRF_USBPHY1_CTRL15 0x453c #define GRF_USBPHY1_CTRL16 0x4540 #define GRF_GPIO2A_IOMUX 0xe000 #define GRF_GPIO2D_HE 0xe18c #define GRF_DDRC0_CON0 0xe380 #define GRF_DDRC0_CON1 0xe384 #define GRF_DDRC1_CON0 0xe388 #define GRF_DDRC1_CON1 0xe38c #define GRF_SOC_CON_BASE 0xe200 #define GRF_SOC_CON(n) (GRF_SOC_CON_BASE + (n) * 4) #define GRF_IO_VSEL 0xe640 #define CRU_CLKSEL_CON0 0x0100 #define CRU_CLKSEL_CON6 0x0118 #define CRU_SDIO0_CON1 0x058c #define PMUCRU_CLKSEL_CON0 0x0080 #define PMUCRU_CLKGATE_CON2 0x0108 #define PMUCRU_SOFTRST_CON0 0x0110 #define PMUCRU_GATEDIS_CON0 0x0130 #define PMUCRU_SOFTRST_CON(n) (PMUCRU_SOFTRST_CON0 + (n) * 4) /* export related and operating SoC APIs */ void __dead2 soc_global_soft_reset(void); void disable_dvfs_plls(void); void disable_nodvfs_plls(void); void enable_dvfs_plls(void); void enable_nodvfs_plls(void); void prepare_abpll_for_ddrctrl(void); void restore_abpll(void); void clk_gate_con_save(void); void clk_gate_con_disable(void); void clk_gate_con_restore(void); void set_pmu_rsthold(void); void pmu_sgrf_rst_hld(void); __pmusramfunc void pmu_sgrf_rst_hld_release(void); __pmusramfunc void restore_pmu_rsthold(void); #endif /* SOC_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/include/000077500000000000000000000000001355360272700222425ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3399/include/addressmap.h000066400000000000000000000006231355360272700245370ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ADDRESSMAP_H #define ADDRESSMAP_H #include /* Registers base address */ #define MMIO_BASE 0xF8000000 /* Aggregate of all devices in the first GB */ #define DEV_RNG0_BASE MMIO_BASE #define DEV_RNG0_SIZE SIZE_M(125) #endif /* ADDRESSMAP_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/include/plat.ld.S000066400000000000000000000043671355360272700237360ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ROCKCHIP_PLAT_LD_S #define ROCKCHIP_PLAT_LD_S #include MEMORY { SRAM (rwx): ORIGIN = SRAM_BASE, LENGTH = SRAM_SIZE PMUSRAM (rwx): ORIGIN = PMUSRAM_BASE, LENGTH = PMUSRAM_RSIZE } SECTIONS { . = SRAM_BASE; ASSERT(. == ALIGN(PAGE_SIZE), "SRAM_BASE address is not aligned on a page boundary.") /* * The SRAM space allocation for RK3399 * ---------------- * | m0 code bin * ---------------- * | sram text * ---------------- * | sram data * ---------------- */ .incbin_sram : ALIGN(PAGE_SIZE) { __sram_incbin_start = .; *(.sram.incbin) __sram_incbin_real_end = .; . = ALIGN(PAGE_SIZE); __sram_incbin_end = .; } >SRAM ASSERT((__sram_incbin_real_end - __sram_incbin_start) <= SRAM_BIN_LIMIT, ".incbin_sram has exceeded its limit") .text_sram : ALIGN(PAGE_SIZE) { __bl31_sram_text_start = .; *(.sram.text) *(.sram.rodata) __bl31_sram_text_real_end = .; . = ALIGN(PAGE_SIZE); __bl31_sram_text_end = .; } >SRAM ASSERT((__bl31_sram_text_real_end - __bl31_sram_text_start) <= SRAM_TEXT_LIMIT, ".text_sram has exceeded its limit") .data_sram : ALIGN(PAGE_SIZE) { __bl31_sram_data_start = .; *(.sram.data) __bl31_sram_data_real_end = .; . = ALIGN(PAGE_SIZE); __bl31_sram_data_end = .; } >SRAM ASSERT((__bl31_sram_data_real_end - __bl31_sram_data_start) <= SRAM_DATA_LIMIT, ".data_sram has exceeded its limit") .stack_sram : ALIGN(PAGE_SIZE) { __bl31_sram_stack_start = .; . += PAGE_SIZE; __bl31_sram_stack_end = .; } >SRAM . = PMUSRAM_BASE; /* * pmu_cpuson_entrypoint request address * align 64K when resume, so put it in the * start of pmusram */ .pmusram : { ASSERT(. == ALIGN(64 * 1024), ".pmusram.entry request 64K aligned."); *(.pmusram.entry) __bl31_pmusram_text_start = .; *(.pmusram.text) *(.pmusram.rodata) __bl31_pmusram_text_end = .; /* M0 start address request 4K align */ . = ALIGN(4096); __pmusram_incbin_start = .; *(.pmusram.incbin) __pmusram_incbin_end = .; __bl31_pmusram_data_start = .; *(.pmusram.data) __bl31_pmusram_data_end = .; } >PMUSRAM } #endif /* ROCKCHIP_PLAT_LD_S */ trusted-firmware-a-2.2/plat/rockchip/rk3399/include/plat_sip_calls.h000066400000000000000000000003601355360272700254030ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_SIP_CALLS_H #define PLAT_SIP_CALLS_H #define RK_PLAT_SIP_NUM_CALLS 0 #endif /* PLAT_SIP_CALLS_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/include/platform_def.h000066400000000000000000000067311355360272700250640ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include #include /******************************************************************************* * Platform binary types for linking ******************************************************************************/ #define PLATFORM_LINKER_FORMAT "elf64-littleaarch64" #define PLATFORM_LINKER_ARCH aarch64 /******************************************************************************* * Generic platform constants ******************************************************************************/ /* Size of cacheable stacks */ #if defined(IMAGE_BL1) #define PLATFORM_STACK_SIZE 0x440 #elif defined(IMAGE_BL2) #define PLATFORM_STACK_SIZE 0x400 #elif defined(IMAGE_BL31) #define PLATFORM_STACK_SIZE 0x800 #elif defined(IMAGE_BL32) #define PLATFORM_STACK_SIZE 0x440 #endif #define FIRMWARE_WELCOME_STR "Booting Trusted Firmware\n" #define PLATFORM_MAX_AFFLVL MPIDR_AFFLVL2 #define PLATFORM_SYSTEM_COUNT 1 #define PLATFORM_CLUSTER_COUNT 2 #define PLATFORM_CLUSTER0_CORE_COUNT 4 #define PLATFORM_CLUSTER1_CORE_COUNT 2 #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \ PLATFORM_CLUSTER0_CORE_COUNT) #define PLATFORM_MAX_CPUS_PER_CLUSTER 4 #define PLATFORM_NUM_AFFS (PLATFORM_SYSTEM_COUNT + \ PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLAT_RK_CLST_TO_CPUID_SHIFT 6 #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2 /* * This macro defines the deepest retention state possible. A higher state * id will represent an invalid or a power down state. */ #define PLAT_MAX_RET_STATE U(1) /* * This macro defines the deepest power down states possible. Any state ID * higher than this is invalid. */ #define PLAT_MAX_OFF_STATE U(2) /******************************************************************************* * Platform specific page table and MMU setup constants ******************************************************************************/ #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define MAX_XLAT_TABLES 20 #define MAX_MMAP_REGIONS 25 /******************************************************************************* * Declarations and constants to access the mailboxes safely. Each mailbox is * aligned on the biggest cache line size in the platform. This is known only * to the platform as it might have a combination of integrated and external * caches. Such alignment ensures that two maiboxes do not sit on the same cache * line at any cache level. They could belong to different cpus/clusters & * get written while being protected by different locks causing corruption of * a valid mailbox address. ******************************************************************************/ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) /* * Define GICD and GICC and GICR base */ #define PLAT_RK_GICD_BASE BASE_GICD_BASE #define PLAT_RK_GICR_BASE BASE_GICR_BASE #define PLAT_RK_GICC_BASE 0 #define PLAT_RK_UART_BASE UART2_BASE #define PLAT_RK_UART_CLOCK RK3399_UART_CLOCK #define PLAT_RK_UART_BAUDRATE RK3399_BAUDRATE #define PLAT_RK_CCI_BASE CCI500_BASE #define PLAT_RK_PRIMARY_CPU 0x0 #define PSRAM_DO_DDR_RESUME 1 #define PSRAM_CHECK_WAKEUP_CPU 0 #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/include/shared/000077500000000000000000000000001355360272700235105ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rockchip/rk3399/include/shared/addressmap_shared.h000066400000000000000000000067161355360272700273440ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ADDRESSMAP_SHARED_H #define ADDRESSMAP_SHARED_H #define SIZE_K(n) ((n) * 1024) #define SIZE_M(n) ((n) * 1024 * 1024) #define SRAM_TEXT_LIMIT (4 * 1024) #define SRAM_DATA_LIMIT (4 * 1024) #define SRAM_BIN_LIMIT (4 * 1024) /* * The parts of the shared defined registers address with AP and M0, * let's note and mark the previous defines like this: */ #define GIC500_BASE (MMIO_BASE + 0x06E00000) #define UART0_BASE (MMIO_BASE + 0x07180000) #define UART1_BASE (MMIO_BASE + 0x07190000) #define UART2_BASE (MMIO_BASE + 0x071A0000) #define UART3_BASE (MMIO_BASE + 0x071B0000) #define PMU_BASE (MMIO_BASE + 0x07310000) #define PMUGRF_BASE (MMIO_BASE + 0x07320000) #define SGRF_BASE (MMIO_BASE + 0x07330000) #define PMUSRAM_BASE (MMIO_BASE + 0x073B0000) #define PWM_BASE (MMIO_BASE + 0x07420000) #define CIC_BASE (MMIO_BASE + 0x07620000) #define PD_BUS0_BASE (MMIO_BASE + 0x07650000) #define DCF_BASE (MMIO_BASE + 0x076A0000) #define GPIO0_BASE (MMIO_BASE + 0x07720000) #define GPIO1_BASE (MMIO_BASE + 0x07730000) #define PMUCRU_BASE (MMIO_BASE + 0x07750000) #define CRU_BASE (MMIO_BASE + 0x07760000) #define GRF_BASE (MMIO_BASE + 0x07770000) #define GPIO2_BASE (MMIO_BASE + 0x07780000) #define GPIO3_BASE (MMIO_BASE + 0x07788000) #define GPIO4_BASE (MMIO_BASE + 0x07790000) #define WDT1_BASE (MMIO_BASE + 0x07840000) #define WDT0_BASE (MMIO_BASE + 0x07848000) #define TIMER_BASE (MMIO_BASE + 0x07850000) #define STIME_BASE (MMIO_BASE + 0x07860000) #define SRAM_BASE (MMIO_BASE + 0x078C0000) #define SERVICE_NOC_0_BASE (MMIO_BASE + 0x07A50000) #define DDRC0_BASE (MMIO_BASE + 0x07A80000) #define SERVICE_NOC_1_BASE (MMIO_BASE + 0x07A84000) #define DDRC1_BASE (MMIO_BASE + 0x07A88000) #define SERVICE_NOC_2_BASE (MMIO_BASE + 0x07A8C000) #define SERVICE_NOC_3_BASE (MMIO_BASE + 0x07A90000) #define CCI500_BASE (MMIO_BASE + 0x07B00000) #define COLD_BOOT_BASE (MMIO_BASE + 0x07FF0000) /* Registers size */ #define GIC500_SIZE SIZE_M(2) #define UART0_SIZE SIZE_K(64) #define UART1_SIZE SIZE_K(64) #define UART2_SIZE SIZE_K(64) #define UART3_SIZE SIZE_K(64) #define PMU_SIZE SIZE_K(64) #define PMUGRF_SIZE SIZE_K(64) #define SGRF_SIZE SIZE_K(64) #define PMUSRAM_SIZE SIZE_K(64) #define PMUSRAM_RSIZE SIZE_K(8) #define PWM_SIZE SIZE_K(64) #define CIC_SIZE SIZE_K(4) #define DCF_SIZE SIZE_K(4) #define GPIO0_SIZE SIZE_K(64) #define GPIO1_SIZE SIZE_K(64) #define PMUCRU_SIZE SIZE_K(64) #define CRU_SIZE SIZE_K(64) #define GRF_SIZE SIZE_K(64) #define GPIO2_SIZE SIZE_K(32) #define GPIO3_SIZE SIZE_K(32) #define GPIO4_SIZE SIZE_K(32) #define STIME_SIZE SIZE_K(64) #define SRAM_SIZE SIZE_K(192) #define SERVICE_NOC_0_SIZE SIZE_K(192) #define DDRC0_SIZE SIZE_K(32) #define SERVICE_NOC_1_SIZE SIZE_K(16) #define DDRC1_SIZE SIZE_K(32) #define SERVICE_NOC_2_SIZE SIZE_K(16) #define SERVICE_NOC_3_SIZE SIZE_K(448) #define CCI500_SIZE SIZE_M(1) #define PD_BUS0_SIZE SIZE_K(448) /* DDR Registers address */ #define CTL_BASE(ch) (DDRC0_BASE + (ch) * 0x8000) #define CTL_REG(ch, n) (CTL_BASE(ch) + (n) * 0x4) #define PI_OFFSET 0x800 #define PI_BASE(ch) (CTL_BASE(ch) + PI_OFFSET) #define PI_REG(ch, n) (PI_BASE(ch) + (n) * 0x4) #define PHY_OFFSET 0x2000 #define PHY_BASE(ch) (CTL_BASE(ch) + PHY_OFFSET) #define PHY_REG(ch, n) (PHY_BASE(ch) + (n) * 0x4) #define MSCH_BASE(ch) (SERVICE_NOC_1_BASE + (ch) * 0x8000) #endif /* ADDRESSMAP_SHARED_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/include/shared/bl31_param.h000066400000000000000000000014571355360272700256110ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BL31_PARAM_H #define BL31_PARAM_H /******************************************************************************* * Platform memory map related constants ******************************************************************************/ /* TF text, ro, rw, Size: 1MB */ #define TZRAM_BASE (0x0) #define TZRAM_SIZE (0x100000) /******************************************************************************* * BL31 specific defines. ******************************************************************************/ /* * Put BL31 at the top of the Trusted RAM */ #define BL31_BASE (TZRAM_BASE + 0x40000) #define BL31_LIMIT (TZRAM_BASE + TZRAM_SIZE) #endif /* BL31_PARAM_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/include/shared/dram_regs.h000066400000000000000000000057651355360272700256410ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef DRAM_REGS_H #define DRAM_REGS_H #define CTL_REG_NUM 332 #define PHY_REG_NUM 959 #define PI_REG_NUM 200 #define MSCH_ID_COREID 0x0 #define MSCH_ID_REVISIONID 0x4 #define MSCH_DEVICECONF 0x8 #define MSCH_DEVICESIZE 0xc #define MSCH_DDRTIMINGA0 0x10 #define MSCH_DDRTIMINGB0 0x14 #define MSCH_DDRTIMINGC0 0x18 #define MSCH_DEVTODEV0 0x1c #define MSCH_DDRMODE 0x110 #define MSCH_AGINGX0 0x1000 #define CIC_CTRL0 0x0 #define CIC_CTRL1 0x4 #define CIC_IDLE_TH 0x8 #define CIC_CG_WAIT_TH 0xc #define CIC_STATUS0 0x10 #define CIC_STATUS1 0x14 #define CIC_CTRL2 0x18 #define CIC_CTRL3 0x1c #define CIC_CTRL4 0x20 /* DENALI_CTL_00 */ #define START 1 /* DENALI_CTL_68 */ #define PWRUP_SREFRESH_EXIT (1 << 16) /* DENALI_CTL_274 */ #define MEM_RST_VALID 1 #define PHY_DRV_ODT_Hi_Z 0x0 #define PHY_DRV_ODT_240 0x1 #define PHY_DRV_ODT_120 0x8 #define PHY_DRV_ODT_80 0x9 #define PHY_DRV_ODT_60 0xc #define PHY_DRV_ODT_48 0xd #define PHY_DRV_ODT_40 0xe #define PHY_DRV_ODT_34_3 0xf /* * sys_reg bitfield struct * [31] row_3_4_ch1 * [30] row_3_4_ch0 * [29:28] chinfo * [27] rank_ch1 * [26:25] col_ch1 * [24] bk_ch1 * [23:22] cs0_row_ch1 * [21:20] cs1_row_ch1 * [19:18] bw_ch1 * [17:16] dbw_ch1; * [15:13] ddrtype * [12] channelnum * [11] rank_ch0 * [10:9] col_ch0 * [8] bk_ch0 * [7:6] cs0_row_ch0 * [5:4] cs1_row_ch0 * [3:2] bw_ch0 * [1:0] dbw_ch0 */ #define SYS_REG_ENC_ROW_3_4(n, ch) ((n) << (30 + (ch))) #define SYS_REG_DEC_ROW_3_4(n, ch) (((n) >> (30 + (ch))) & 0x1) #define SYS_REG_ENC_CHINFO(ch) (1 << (28 + (ch))) #define SYS_REG_DEC_CHINFO(n, ch) (((n) >> (28 + (ch))) & 0x1) #define SYS_REG_ENC_DDRTYPE(n) ((n) << 13) #define SYS_REG_DEC_DDRTYPE(n) (((n) >> 13) & 0x7) #define SYS_REG_ENC_NUM_CH(n) (((n) - 1) << 12) #define SYS_REG_DEC_NUM_CH(n) (1 + (((n) >> 12) & 0x1)) #define SYS_REG_ENC_RANK(n, ch) (((n) - 1) << (11 + (ch) * 16)) #define SYS_REG_DEC_RANK(n, ch) (1 + (((n) >> (11 + (ch) * 16)) & 0x1)) #define SYS_REG_ENC_COL(n, ch) (((n) - 9) << (9 + (ch) * 16)) #define SYS_REG_DEC_COL(n, ch) (9 + (((n) >> (9 + (ch) * 16)) & 0x3)) #define SYS_REG_ENC_BK(n, ch) (((n) == 3 ? 0 : 1) << (8 + (ch) * 16)) #define SYS_REG_DEC_BK(n, ch) (3 - (((n) >> (8 + (ch) * 16)) & 0x1)) #define SYS_REG_ENC_CS0_ROW(n, ch) (((n) - 13) << (6 + (ch) * 16)) #define SYS_REG_DEC_CS0_ROW(n, ch) (13 + (((n) >> (6 + (ch) * 16)) & 0x3)) #define SYS_REG_ENC_CS1_ROW(n, ch) (((n) - 13) << (4 + (ch) * 16)) #define SYS_REG_DEC_CS1_ROW(n, ch) (13 + (((n) >> (4 + (ch) * 16)) & 0x3)) #define SYS_REG_ENC_BW(n, ch) ((2 >> (n)) << (2 + (ch) * 16)) #define SYS_REG_DEC_BW(n, ch) (2 >> (((n) >> (2 + (ch) * 16)) & 0x3)) #define SYS_REG_ENC_DBW(n, ch) ((2 >> (n)) << (0 + (ch) * 16)) #define SYS_REG_DEC_DBW(n, ch) (2 >> (((n) >> (0 + (ch) * 16)) & 0x3)) #define DDR_STRIDE(n) mmio_write_32(SGRF_BASE + SGRF_SOC_CON3_7(4), \ (0x1f<<(10+16))|((n)<<10)) #endif /* DRAM_REGS_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/include/shared/m0_param.h000066400000000000000000000010761355360272700253610ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef M0_PARAM_H #define M0_PARAM_H #define PARAM_ADDR 0xc0 #define PARAM_M0_FUNC 0x00 #define PARAM_DRAM_FREQ 0x04 #define PARAM_DPLL_CON0 0x08 #define PARAM_DPLL_CON1 0x0c #define PARAM_DPLL_CON2 0x10 #define PARAM_DPLL_CON3 0x14 #define PARAM_DPLL_CON4 0x18 #define PARAM_DPLL_CON5 0x1c #define PARAM_FREQ_SELECT 0x20 #define PARAM_M0_DONE 0x24 #define PARAM_M0_SIZE 0x28 #define M0_DONE_FLAG 0xf59ec39a #endif /* M0_PARAM_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/include/shared/misc_regs.h000066400000000000000000000011361355360272700256350ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MISC_REGS_H #define MISC_REGS_H /* CRU */ #define CRU_DPLL_CON0 0x40 #define CRU_DPLL_CON1 0x44 #define CRU_DPLL_CON2 0x48 #define CRU_DPLL_CON3 0x4c #define CRU_DPLL_CON4 0x50 #define CRU_DPLL_CON5 0x54 /* CRU_PLL_CON3 */ #define PLL_SLOW_MODE 0 #define PLL_NORMAL_MODE 1 #define PLL_MODE(n) ((0x3 << (8 + 16)) | ((n) << 8)) #define PLL_POWER_DOWN(n) ((0x1 << (0 + 16)) | ((n) << 0)) /* PMU CRU */ #define PMU_CRU_GATEDIS_CON0 0x130 #endif /* MISC_REGS_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/include/shared/pmu_bits.h000066400000000000000000000300451355360272700255050ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PMU_BITS_H #define PMU_BITS_H enum pmu_powerdomain_id { PD_CPUL0 = 0, PD_CPUL1, PD_CPUL2, PD_CPUL3, PD_CPUB0, PD_CPUB1, PD_SCUL, PD_SCUB, PD_TCPD0, PD_TCPD1, PD_CCI, PD_PERILP, PD_PERIHP, PD_CENTER, PD_VIO, PD_GPU, PD_VCODEC, PD_VDU, PD_RGA, PD_IEP, PD_VO, PD_ISP0 = 22, PD_ISP1, PD_HDCP, PD_GMAC, PD_EMMC, PD_USB3, PD_EDP, PD_GIC, PD_SD, PD_SDIOAUDIO, PD_END }; enum powerdomain_state { PMU_POWER_ON = 0, PMU_POWER_OFF, }; enum pmu_bus_id { BUS_ID_GPU = 0, BUS_ID_PERILP, BUS_ID_PERIHP, BUS_ID_VCODEC, BUS_ID_VDU, BUS_ID_RGA, BUS_ID_IEP, BUS_ID_VOPB, BUS_ID_VOPL, BUS_ID_ISP0, BUS_ID_ISP1, BUS_ID_HDCP, BUS_ID_USB3, BUS_ID_PERILPM0, BUS_ID_CENTER, BUS_ID_CCIM0, BUS_ID_CCIM1, BUS_ID_VIO, BUS_ID_MSCH0, BUS_ID_MSCH1, BUS_ID_ALIVE, BUS_ID_PMU, BUS_ID_EDP, BUS_ID_GMAC, BUS_ID_EMMC, BUS_ID_CENTER1, BUS_ID_PMUM0, BUS_ID_GIC, BUS_ID_SD, BUS_ID_SDIOAUDIO, }; enum pmu_bus_state { BUS_ACTIVE, BUS_IDLE, }; /* pmu_cpuapm bit */ enum pmu_cores_pm_by_wfi { core_pm_en = 0, core_pm_int_wakeup_en, core_pm_resv, core_pm_sft_wakeup_en }; enum pmu_wkup_cfg0 { PMU_GPIO0A_POSE_WKUP_EN = 0, PMU_GPIO0B_POSE_WKUP_EN = 8, PMU_GPIO0C_POSE_WKUP_EN = 16, PMU_GPIO0D_POSE_WKUP_EN = 24, }; enum pmu_wkup_cfg1 { PMU_GPIO0A_NEGEDGE_WKUP_EN = 0, PMU_GPIO0B_NEGEDGE_WKUP_EN = 7, PMU_GPIO0C_NEGEDGE_WKUP_EN = 16, PMU_GPIO0D_NEGEDGE_WKUP_EN = 24, }; enum pmu_wkup_cfg2 { PMU_GPIO1A_POSE_WKUP_EN = 0, PMU_GPIO1B_POSE_WKUP_EN = 7, PMU_GPIO1C_POSE_WKUP_EN = 16, PMU_GPIO1D_POSE_WKUP_EN = 24, }; enum pmu_wkup_cfg3 { PMU_GPIO1A_NEGEDGE_WKUP_EN = 0, PMU_GPIO1B_NEGEDGE_WKUP_EN = 7, PMU_GPIO1C_NEGEDGE_WKUP_EN = 16, PMU_GPIO1D_NEGEDGE_WKUP_EN = 24, }; /* pmu_wkup_cfg4 */ enum pmu_wkup_cfg4 { PMU_CLUSTER_L_WKUP_EN = 0, PMU_CLUSTER_B_WKUP_EN, PMU_GPIO_WKUP_EN, PMU_SDIO_WKUP_EN, PMU_SDMMC_WKUP_EN, PMU_TIMER_WKUP_EN = 6, PMU_USBDEV_WKUP_EN, PMU_SFT_WKUP_EN, PMU_M0_WDT_WKUP_EN, PMU_TIMEOUT_WKUP_EN, PMU_PWM_WKUP_EN, PMU_PCIE_WKUP_EN = 13, }; enum pmu_pwrdn_con { PMU_A53_L0_PWRDWN_EN = 0, PMU_A53_L1_PWRDWN_EN, PMU_A53_L2_PWRDWN_EN, PMU_A53_L3_PWRDWN_EN, PMU_A72_B0_PWRDWN_EN, PMU_A72_B1_PWRDWN_EN, PMU_SCU_L_PWRDWN_EN, PMU_SCU_B_PWRDWN_EN, PMU_TCPD0_PWRDWN_EN, PMU_TCPD1_PWRDWN_EN, PMU_CCI_PWRDWN_EN, PMU_PERILP_PWRDWN_EN, PMU_PERIHP_PWRDWN_EN, PMU_CENTER_PWRDWN_EN, PMU_VIO_PWRDWN_EN, PMU_GPU_PWRDWN_EN, PMU_VCODEC_PWRDWN_EN, PMU_VDU_PWRDWN_EN, PMU_RGA_PWRDWN_EN, PMU_IEP_PWRDWN_EN, PMU_VO_PWRDWN_EN, PMU_ISP0_PWRDWN_EN = 22, PMU_ISP1_PWRDWN_EN, PMU_HDCP_PWRDWN_EN, PMU_GMAC_PWRDWN_EN, PMU_EMMC_PWRDWN_EN, PMU_USB3_PWRDWN_EN, PMU_EDP_PWRDWN_EN, PMU_GIC_PWRDWN_EN, PMU_SD_PWRDWN_EN, PMU_SDIOAUDIO_PWRDWN_EN, }; enum pmu_pwrdn_st { PMU_A53_L0_PWRDWN_ST = 0, PMU_A53_L1_PWRDWN_ST, PMU_A53_L2_PWRDWN_ST, PMU_A53_L3_PWRDWN_ST, PMU_A72_B0_PWRDWN_ST, PMU_A72_B1_PWRDWN_ST, PMU_SCU_L_PWRDWN_ST, PMU_SCU_B_PWRDWN_ST, PMU_TCPD0_PWRDWN_ST, PMU_TCPD1_PWRDWN_ST, PMU_CCI_PWRDWN_ST, PMU_PERILP_PWRDWN_ST, PMU_PERIHP_PWRDWN_ST, PMU_CENTER_PWRDWN_ST, PMU_VIO_PWRDWN_ST, PMU_GPU_PWRDWN_ST, PMU_VCODEC_PWRDWN_ST, PMU_VDU_PWRDWN_ST, PMU_RGA_PWRDWN_ST, PMU_IEP_PWRDWN_ST, PMU_VO_PWRDWN_ST, PMU_ISP0_PWRDWN_ST = 22, PMU_ISP1_PWRDWN_ST, PMU_HDCP_PWRDWN_ST, PMU_GMAC_PWRDWN_ST, PMU_EMMC_PWRDWN_ST, PMU_USB3_PWRDWN_ST, PMU_EDP_PWRDWN_ST, PMU_GIC_PWRDWN_ST, PMU_SD_PWRDWN_ST, PMU_SDIOAUDIO_PWRDWN_ST, }; enum pmu_pll_con { PMU_PLL_PD_CFG = 0, PMU_SFT_PLL_PD = 8, }; enum pmu_pwermode_con { PMU_PWR_MODE_EN = 0, PMU_WKUP_RST_EN, PMU_INPUT_CLAMP_EN, PMU_OSC_DIS, PMU_ALIVE_USE_LF, PMU_PMU_USE_LF, PMU_POWER_OFF_REQ_CFG, PMU_CHIP_PD_EN, PMU_PLL_PD_EN, PMU_CPU0_PD_EN, PMU_L2_FLUSH_EN, PMU_L2_IDLE_EN, PMU_SCU_PD_EN, PMU_CCI_PD_EN, PMU_PERILP_PD_EN, PMU_CENTER_PD_EN, PMU_SREF0_ENTER_EN, PMU_DDRC0_GATING_EN, PMU_DDRIO0_RET_EN, PMU_DDRIO0_RET_DE_REQ, PMU_SREF1_ENTER_EN, PMU_DDRC1_GATING_EN, PMU_DDRIO1_RET_EN, PMU_DDRIO1_RET_DE_REQ, PMU_CLK_CENTER_SRC_GATE_EN = 26, PMU_CLK_PERILP_SRC_GATE_EN, PMU_CLK_CORE_SRC_GATE_EN, PMU_DDRIO_RET_HW_DE_REQ, PMU_SLP_OUTPUT_CFG, PMU_MAIN_CLUSTER, }; enum pmu_sft_con { PMU_WKUP_SFT = 0, PMU_INPUT_CLAMP_CFG, PMU_OSC_DIS_CFG, PMU_PMU_LF_EN_CFG, PMU_ALIVE_LF_EN_CFG, PMU_24M_EN_CFG, PMU_DBG_PWRUP_L0_CFG, PMU_WKUP_SFT_M0, PMU_DDRCTL0_C_SYSREQ_CFG, PMU_DDR0_IO_RET_CFG, PMU_DDRCTL1_C_SYSREQ_CFG = 12, PMU_DDR1_IO_RET_CFG, DBG_PWRUP_B0_CFG = 15, DBG_NOPWERDWN_L0_EN, DBG_NOPWERDWN_L1_EN, DBG_NOPWERDWN_L2_EN, DBG_NOPWERDWN_L3_EN, DBG_PWRUP_REQ_L_EN = 20, CLUSTER_L_CLK_SRC_GATING_CFG, L2_FLUSH_REQ_CLUSTER_L, ACINACTM_CLUSTER_L_CFG, DBG_NO_PWERDWN_B0_EN, DBG_NO_PWERDWN_B1_EN, DBG_PWRUP_REQ_B_EN = 28, CLUSTER_B_CLK_SRC_GATING_CFG, L2_FLUSH_REQ_CLUSTER_B, ACINACTM_CLUSTER_B_CFG, }; enum pmu_int_con { PMU_PMU_INT_EN = 0, PMU_PWRMD_WKUP_INT_EN, PMU_WKUP_GPIO0_NEG_INT_EN, PMU_WKUP_GPIO0_POS_INT_EN, PMU_WKUP_GPIO1_NEG_INT_EN, PMU_WKUP_GPIO1_POS_INT_EN, }; enum pmu_int_st { PMU_PWRMD_WKUP_INT_ST = 1, PMU_WKUP_GPIO0_NEG_INT_ST, PMU_WKUP_GPIO0_POS_INT_ST, PMU_WKUP_GPIO1_NEG_INT_ST, PMU_WKUP_GPIO1_POS_INT_ST, }; enum pmu_gpio0_pos_int_con { PMU_GPIO0A_POS_INT_EN = 0, PMU_GPIO0B_POS_INT_EN = 8, PMU_GPIO0C_POS_INT_EN = 16, PMU_GPIO0D_POS_INT_EN = 24, }; enum pmu_gpio0_neg_int_con { PMU_GPIO0A_NEG_INT_EN = 0, PMU_GPIO0B_NEG_INT_EN = 8, PMU_GPIO0C_NEG_INT_EN = 16, PMU_GPIO0D_NEG_INT_EN = 24, }; enum pmu_gpio1_pos_int_con { PMU_GPIO1A_POS_INT_EN = 0, PMU_GPIO1B_POS_INT_EN = 8, PMU_GPIO1C_POS_INT_EN = 16, PMU_GPIO1D_POS_INT_EN = 24, }; enum pmu_gpio1_neg_int_con { PMU_GPIO1A_NEG_INT_EN = 0, PMU_GPIO1B_NEG_INT_EN = 8, PMU_GPIO1C_NEG_INT_EN = 16, PMU_GPIO1D_NEG_INT_EN = 24, }; enum pmu_gpio0_pos_int_st { PMU_GPIO0A_POS_INT_ST = 0, PMU_GPIO0B_POS_INT_ST = 8, PMU_GPIO0C_POS_INT_ST = 16, PMU_GPIO0D_POS_INT_ST = 24, }; enum pmu_gpio0_neg_int_st { PMU_GPIO0A_NEG_INT_ST = 0, PMU_GPIO0B_NEG_INT_ST = 8, PMU_GPIO0C_NEG_INT_ST = 16, PMU_GPIO0D_NEG_INT_ST = 24, }; enum pmu_gpio1_pos_int_st { PMU_GPIO1A_POS_INT_ST = 0, PMU_GPIO1B_POS_INT_ST = 8, PMU_GPIO1C_POS_INT_ST = 16, PMU_GPIO1D_POS_INT_ST = 24, }; enum pmu_gpio1_neg_int_st { PMU_GPIO1A_NEG_INT_ST = 0, PMU_GPIO1B_NEG_INT_ST = 8, PMU_GPIO1C_NEG_INT_ST = 16, PMU_GPIO1D_NEG_INT_ST = 24, }; /* pmu power down configure register 0x0050 */ enum pmu_pwrdn_inten { PMU_A53_L0_PWR_SWITCH_INT_EN = 0, PMU_A53_L1_PWR_SWITCH_INT_EN, PMU_A53_L2_PWR_SWITCH_INT_EN, PMU_A53_L3_PWR_SWITCH_INT_EN, PMU_A72_B0_PWR_SWITCH_INT_EN, PMU_A72_B1_PWR_SWITCH_INT_EN, PMU_SCU_L_PWR_SWITCH_INT_EN, PMU_SCU_B_PWR_SWITCH_INT_EN, PMU_TCPD0_PWR_SWITCH_INT_EN, PMU_TCPD1_PWR_SWITCH_INT_EN, PMU_CCI_PWR_SWITCH_INT_EN, PMU_PERILP_PWR_SWITCH_INT_EN, PMU_PERIHP_PWR_SWITCH_INT_EN, PMU_CENTER_PWR_SWITCH_INT_EN, PMU_VIO_PWR_SWITCH_INT_EN, PMU_GPU_PWR_SWITCH_INT_EN, PMU_VCODEC_PWR_SWITCH_INT_EN, PMU_VDU_PWR_SWITCH_INT_EN, PMU_RGA_PWR_SWITCH_INT_EN, PMU_IEP_PWR_SWITCH_INT_EN, PMU_VO_PWR_SWITCH_INT_EN, PMU_ISP0_PWR_SWITCH_INT_EN = 22, PMU_ISP1_PWR_SWITCH_INT_EN, PMU_HDCP_PWR_SWITCH_INT_EN, PMU_GMAC_PWR_SWITCH_INT_EN, PMU_EMMC_PWR_SWITCH_INT_EN, PMU_USB3_PWR_SWITCH_INT_EN, PMU_EDP_PWR_SWITCH_INT_EN, PMU_GIC_PWR_SWITCH_INT_EN, PMU_SD_PWR_SWITCH_INT_EN, PMU_SDIOAUDIO_PWR_SWITCH_INT_EN, }; enum pmu_wkup_status { PMU_WKUP_BY_CLSTER_L_INT = 0, PMU_WKUP_BY_CLSTER_b_INT, PMU_WKUP_BY_GPIO_INT, PMU_WKUP_BY_SDIO_DET, PMU_WKUP_BY_SDMMC_DET, PMU_WKUP_BY_TIMER = 6, PMU_WKUP_BY_USBDEV_DET, PMU_WKUP_BY_M0_SFT, PMU_WKUP_BY_M0_WDT_INT, PMU_WKUP_BY_TIMEOUT, PMU_WKUP_BY_PWM, PMU_WKUP_BY_PCIE = 13, }; enum pmu_bus_clr { PMU_CLR_GPU = 0, PMU_CLR_PERILP, PMU_CLR_PERIHP, PMU_CLR_VCODEC, PMU_CLR_VDU, PMU_CLR_RGA, PMU_CLR_IEP, PMU_CLR_VOPB, PMU_CLR_VOPL, PMU_CLR_ISP0, PMU_CLR_ISP1, PMU_CLR_HDCP, PMU_CLR_USB3, PMU_CLR_PERILPM0, PMU_CLR_CENTER, PMU_CLR_CCIM1, PMU_CLR_CCIM0, PMU_CLR_VIO, PMU_CLR_MSCH0, PMU_CLR_MSCH1, PMU_CLR_ALIVE, PMU_CLR_PMU, PMU_CLR_EDP, PMU_CLR_GMAC, PMU_CLR_EMMC, PMU_CLR_CENTER1, PMU_CLR_PMUM0, PMU_CLR_GIC, PMU_CLR_SD, PMU_CLR_SDIOAUDIO, }; /* PMU bus idle request register */ enum pmu_bus_idle_req { PMU_IDLE_REQ_GPU = 0, PMU_IDLE_REQ_PERILP, PMU_IDLE_REQ_PERIHP, PMU_IDLE_REQ_VCODEC, PMU_IDLE_REQ_VDU, PMU_IDLE_REQ_RGA, PMU_IDLE_REQ_IEP, PMU_IDLE_REQ_VOPB, PMU_IDLE_REQ_VOPL, PMU_IDLE_REQ_ISP0, PMU_IDLE_REQ_ISP1, PMU_IDLE_REQ_HDCP, PMU_IDLE_REQ_USB3, PMU_IDLE_REQ_PERILPM0, PMU_IDLE_REQ_CENTER, PMU_IDLE_REQ_CCIM0, PMU_IDLE_REQ_CCIM1, PMU_IDLE_REQ_VIO, PMU_IDLE_REQ_MSCH0, PMU_IDLE_REQ_MSCH1, PMU_IDLE_REQ_ALIVE, PMU_IDLE_REQ_PMU, PMU_IDLE_REQ_EDP, PMU_IDLE_REQ_GMAC, PMU_IDLE_REQ_EMMC, PMU_IDLE_REQ_CENTER1, PMU_IDLE_REQ_PMUM0, PMU_IDLE_REQ_GIC, PMU_IDLE_REQ_SD, PMU_IDLE_REQ_SDIOAUDIO, }; /* pmu bus idle status register */ enum pmu_bus_idle_st { PMU_IDLE_ST_GPU = 0, PMU_IDLE_ST_PERILP, PMU_IDLE_ST_PERIHP, PMU_IDLE_ST_VCODEC, PMU_IDLE_ST_VDU, PMU_IDLE_ST_RGA, PMU_IDLE_ST_IEP, PMU_IDLE_ST_VOPB, PMU_IDLE_ST_VOPL, PMU_IDLE_ST_ISP0, PMU_IDLE_ST_ISP1, PMU_IDLE_ST_HDCP, PMU_IDLE_ST_USB3, PMU_IDLE_ST_PERILPM0, PMU_IDLE_ST_CENTER, PMU_IDLE_ST_CCIM0, PMU_IDLE_ST_CCIM1, PMU_IDLE_ST_VIO, PMU_IDLE_ST_MSCH0, PMU_IDLE_ST_MSCH1, PMU_IDLE_ST_ALIVE, PMU_IDLE_ST_PMU, PMU_IDLE_ST_EDP, PMU_IDLE_ST_GMAC, PMU_IDLE_ST_EMMC, PMU_IDLE_ST_CENTER1, PMU_IDLE_ST_PMUM0, PMU_IDLE_ST_GIC, PMU_IDLE_ST_SD, PMU_IDLE_ST_SDIOAUDIO, }; enum pmu_bus_idle_ack { PMU_IDLE_ACK_GPU = 0, PMU_IDLE_ACK_PERILP, PMU_IDLE_ACK_PERIHP, PMU_IDLE_ACK_VCODEC, PMU_IDLE_ACK_VDU, PMU_IDLE_ACK_RGA, PMU_IDLE_ACK_IEP, PMU_IDLE_ACK_VOPB, PMU_IDLE_ACK_VOPL, PMU_IDLE_ACK_ISP0, PMU_IDLE_ACK_ISP1, PMU_IDLE_ACK_HDCP, PMU_IDLE_ACK_USB3, PMU_IDLE_ACK_PERILPM0, PMU_IDLE_ACK_CENTER, PMU_IDLE_ACK_CCIM0, PMU_IDLE_ACK_CCIM1, PMU_IDLE_ACK_VIO, PMU_IDLE_ACK_MSCH0, PMU_IDLE_ACK_MSCH1, PMU_IDLE_ACK_ALIVE, PMU_IDLE_ACK_PMU, PMU_IDLE_ACK_EDP, PMU_IDLE_ACK_GMAC, PMU_IDLE_ACK_EMMC, PMU_IDLE_ACK_CENTER1, PMU_IDLE_ACK_PMUM0, PMU_IDLE_ACK_GIC, PMU_IDLE_ACK_SD, PMU_IDLE_ACK_SDIOAUDIO, }; enum pmu_cci500_con { PMU_PREQ_CCI500_CFG_SW = 0, PMU_CLR_PREQ_CCI500_HW, PMU_PSTATE_CCI500_0, PMU_PSTATE_CCI500_1, PMU_PSTATE_CCI500_2, PMU_QREQ_CCI500_CFG_SW, PMU_CLR_QREQ_CCI500_HW, PMU_QGATING_CCI500_CFG, PMU_PREQ_CCI500_CFG_SW_WMSK = 16, PMU_CLR_PREQ_CCI500_HW_WMSK, PMU_PSTATE_CCI500_0_WMSK, PMU_PSTATE_CCI500_1_WMSK, PMU_PSTATE_CCI500_2_WMSK, PMU_QREQ_CCI500_CFG_SW_WMSK, PMU_CLR_QREQ_CCI500_HW_WMSK, PMU_QGATING_CCI500_CFG_WMSK, }; enum pmu_adb400_con { PMU_PWRDWN_REQ_CXCS_SW = 0, PMU_PWRDWN_REQ_CORE_L_SW, PMU_PWRDWN_REQ_CORE_L_2GIC_SW, PMU_PWRDWN_REQ_GIC2_CORE_L_SW, PMU_PWRDWN_REQ_CORE_B_SW, PMU_PWRDWN_REQ_CORE_B_2GIC_SW, PMU_PWRDWN_REQ_GIC2_CORE_B_SW, PMU_CLR_CXCS_HW = 8, PMU_CLR_CORE_L_HW, PMU_CLR_CORE_L_2GIC_HW, PMU_CLR_GIC2_CORE_L_HW, PMU_CLR_CORE_B_HW, PMU_CLR_CORE_B_2GIC_HW, PMU_CLR_GIC2_CORE_B_HW, PMU_PWRDWN_REQ_CXCS_SW_WMSK = 16, PMU_PWRDWN_REQ_CORE_L_SW_WMSK, PMU_PWRDWN_REQ_CORE_L_2GIC_SW_WMSK, PMU_PWRDWN_REQ_GIC2_CORE_L_SW_WMSK, PMU_PWRDWN_REQ_CORE_B_SW_WMSK, PMU_PWRDWN_REQ_CORE_B_2GIC_SW_WMSK, PMU_PWRDWN_REQ_GIC2_CORE_B_SW_WMSK, PMU_CLR_CXCS_HW_WMSK = 24, PMU_CLR_CORE_L_HW_WMSK, PMU_CLR_CORE_L_2GIC_HW_WMSK, PMU_CLR_GIC2_CORE_L_HW_WMSK, PMU_CLR_CORE_B_HW_WMSK, PMU_CLR_CORE_B_2GIC_HW_WMSK, PMU_CLR_GIC2_CORE_B_HW_WMSK, }; enum pmu_adb400_st { PMU_PWRDWN_REQ_CXCS_SW_ST = 0, PMU_PWRDWN_REQ_CORE_L_SW_ST, PMU_PWRDWN_REQ_CORE_L_2GIC_SW_ST, PMU_PWRDWN_REQ_GIC2_CORE_L_SW_ST, PMU_PWRDWN_REQ_CORE_B_SW_ST, PMU_PWRDWN_REQ_CORE_B_2GIC_SW_ST, PMU_PWRDWN_REQ_GIC2_CORE_B_SW_ST, PMU_CLR_CXCS_HW_ST = 8, PMU_CLR_CORE_L_HW_ST, PMU_CLR_CORE_L_2GIC_HW_ST, PMU_CLR_GIC2_CORE_L_HW_ST, PMU_CLR_CORE_B_HW_ST, PMU_CLR_CORE_B_2GIC_HW_ST, PMU_CLR_GIC2_CORE_B_HW_ST, }; enum pmu_pwrdn_con1 { PMU_VD_SCU_L_PWRDN_EN = 0, PMU_VD_SCU_B_PWRDN_EN, PMU_VD_CENTER_PWRDN_EN, }; enum pmu_core_pwr_st { L2_FLUSHDONE_CLUSTER_L = 0, STANDBY_BY_WFIL2_CLUSTER_L, L2_FLUSHDONE_CLUSTER_B = 10, STANDBY_BY_WFIL2_CLUSTER_B, }; #endif /* PMU_BITS_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/include/shared/pmu_regs.h000066400000000000000000000112461355360272700255060ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PMU_REGS_H #define PMU_REGS_H #define PMU_WKUP_CFG0 0x00 #define PMU_WKUP_CFG1 0x04 #define PMU_WKUP_CFG2 0x08 #define PMU_WKUP_CFG3 0x0c #define PMU_WKUP_CFG4 0x10 #define PMU_PWRDN_CON 0x14 #define PMU_PWRDN_ST 0x18 #define PMU_PLL_CON 0x1c #define PMU_PWRMODE_CON 0x20 #define PMU_SFT_CON 0x24 #define PMU_INT_CON 0x28 #define PMU_INT_ST 0x2c #define PMU_GPIO0_POS_INT_CON 0x30 #define PMU_GPIO0_NEG_INT_CON 0x34 #define PMU_GPIO1_POS_INT_CON 0x38 #define PMU_GPIO1_NEG_INT_CON 0x3c #define PMU_GPIO0_POS_INT_ST 0x40 #define PMU_GPIO0_NEG_INT_ST 0x44 #define PMU_GPIO1_POS_INT_ST 0x48 #define PMU_GPIO1_NEG_INT_ST 0x4c #define PMU_PWRDN_INTEN 0x50 #define PMU_PWRDN_STATUS 0x54 #define PMU_WAKEUP_STATUS 0x58 #define PMU_BUS_CLR 0x5c #define PMU_BUS_IDLE_REQ 0x60 #define PMU_BUS_IDLE_ST 0x64 #define PMU_BUS_IDLE_ACK 0x68 #define PMU_CCI500_CON 0x6c #define PMU_ADB400_CON 0x70 #define PMU_ADB400_ST 0x74 #define PMU_POWER_ST 0x78 #define PMU_CORE_PWR_ST 0x7c #define PMU_OSC_CNT 0x80 #define PMU_PLLLOCK_CNT 0x84 #define PMU_PLLRST_CNT 0x88 #define PMU_STABLE_CNT 0x8c #define PMU_DDRIO_PWRON_CNT 0x90 #define PMU_WAKEUP_RST_CLR_CNT 0x94 #define PMU_DDR_SREF_ST 0x98 #define PMU_SCU_L_PWRDN_CNT 0x9c #define PMU_SCU_L_PWRUP_CNT 0xa0 #define PMU_SCU_B_PWRDN_CNT 0xa4 #define PMU_SCU_B_PWRUP_CNT 0xa8 #define PMU_GPU_PWRDN_CNT 0xac #define PMU_GPU_PWRUP_CNT 0xb0 #define PMU_CENTER_PWRDN_CNT 0xb4 #define PMU_CENTER_PWRUP_CNT 0xb8 #define PMU_TIMEOUT_CNT 0xbc #define PMU_CPU0APM_CON 0xc0 #define PMU_CPU1APM_CON 0xc4 #define PMU_CPU2APM_CON 0xc8 #define PMU_CPU3APM_CON 0xcc #define PMU_CPU0BPM_CON 0xd0 #define PMU_CPU1BPM_CON 0xd4 #define PMU_NOC_AUTO_ENA 0xd8 #define PMU_PWRDN_CON1 0xdc #define PMUGRF_GPIO0A_IOMUX 0x00 #define PMUGRF_GPIO1A_IOMUX 0x10 #define PMUGRF_GPIO1C_IOMUX 0x18 #define PMUGRF_GPIO0A6_IOMUX_SHIFT 12 #define PMUGRF_GPIO0A6_IOMUX_PWM 0x1 #define PMUGRF_GPIO1C3_IOMUX_SHIFT 6 #define PMUGRF_GPIO1C3_IOMUX_PWM 0x1 #define CPU_AXI_QOS_ID_COREID 0x00 #define CPU_AXI_QOS_REVISIONID 0x04 #define CPU_AXI_QOS_PRIORITY 0x08 #define CPU_AXI_QOS_MODE 0x0c #define CPU_AXI_QOS_BANDWIDTH 0x10 #define CPU_AXI_QOS_SATURATION 0x14 #define CPU_AXI_QOS_EXTCONTROL 0x18 #define CPU_AXI_QOS_NUM_REGS 0x07 #define CPU_AXI_CCI_M0_QOS_BASE 0xffa50000 #define CPU_AXI_CCI_M1_QOS_BASE 0xffad8000 #define CPU_AXI_DMAC0_QOS_BASE 0xffa64200 #define CPU_AXI_DMAC1_QOS_BASE 0xffa64280 #define CPU_AXI_DCF_QOS_BASE 0xffa64180 #define CPU_AXI_CRYPTO0_QOS_BASE 0xffa64100 #define CPU_AXI_CRYPTO1_QOS_BASE 0xffa64080 #define CPU_AXI_PMU_CM0_QOS_BASE 0xffa68000 #define CPU_AXI_PERI_CM1_QOS_BASE 0xffa64300 #define CPU_AXI_GIC_QOS_BASE 0xffa78000 #define CPU_AXI_SDIO_QOS_BASE 0xffa76000 #define CPU_AXI_SDMMC_QOS_BASE 0xffa74000 #define CPU_AXI_EMMC_QOS_BASE 0xffa58000 #define CPU_AXI_GMAC_QOS_BASE 0xffa5c000 #define CPU_AXI_USB_OTG0_QOS_BASE 0xffa70000 #define CPU_AXI_USB_OTG1_QOS_BASE 0xffa70080 #define CPU_AXI_USB_HOST0_QOS_BASE 0xffa60100 #define CPU_AXI_USB_HOST1_QOS_BASE 0xffa60180 #define CPU_AXI_GPU_QOS_BASE 0xffae0000 #define CPU_AXI_VIDEO_M0_QOS_BASE 0xffab8000 #define CPU_AXI_VIDEO_M1_R_QOS_BASE 0xffac0000 #define CPU_AXI_VIDEO_M1_W_QOS_BASE 0xffac0080 #define CPU_AXI_RGA_R_QOS_BASE 0xffab0000 #define CPU_AXI_RGA_W_QOS_BASE 0xffab0080 #define CPU_AXI_IEP_QOS_BASE 0xffa98000 #define CPU_AXI_VOP_BIG_R_QOS_BASE 0xffac8000 #define CPU_AXI_VOP_BIG_W_QOS_BASE 0xffac8080 #define CPU_AXI_VOP_LITTLE_QOS_BASE 0xffad0000 #define CPU_AXI_ISP0_M0_QOS_BASE 0xffaa0000 #define CPU_AXI_ISP0_M1_QOS_BASE 0xffaa0080 #define CPU_AXI_ISP1_M0_QOS_BASE 0xffaa8000 #define CPU_AXI_ISP1_M1_QOS_BASE 0xffaa8080 #define CPU_AXI_HDCP_QOS_BASE 0xffa90000 #define CPU_AXI_PERIHP_NSP_QOS_BASE 0xffad8080 #define CPU_AXI_PERILP_NSP_QOS_BASE 0xffad8180 #define CPU_AXI_PERILPSLV_NSP_QOS_BASE 0xffad8100 #define GRF_GPIO2A_IOMUX 0xe000 #define GRF_GPIO2B_IOMUX 0xe004 #define GRF_GPIO2C_IOMUX 0xe008 #define GRF_GPIO2D_IOMUX 0xe00c #define GRF_GPIO3A_IOMUX 0xe010 #define GRF_GPIO3B_IOMUX 0xe014 #define GRF_GPIO3C_IOMUX 0xe018 #define GRF_GPIO3D_IOMUX 0xe01c #define GRF_GPIO4A_IOMUX 0xe020 #define GRF_GPIO4B_IOMUX 0xe024 #define GRF_GPIO4C_IOMUX 0xe028 #define GRF_GPIO4D_IOMUX 0xe02c #define GRF_GPIO2A_P 0xe040 #define GRF_GPIO2B_P 0xe044 #define GRF_GPIO2C_P 0xe048 #define GRF_GPIO2D_P 0xe04C #define GRF_GPIO3A_P 0xe050 #define GRF_GPIO3B_P 0xe054 #define GRF_GPIO3C_P 0xe058 #define GRF_GPIO3D_P 0xe05C #define GRF_GPIO4A_P 0xe060 #define GRF_GPIO4B_P 0xe064 #define GRF_GPIO4C_P 0xe068 #define GRF_GPIO4D_P 0xe06C #endif /* PMU_REGS_H */ trusted-firmware-a-2.2/plat/rockchip/rk3399/plat_sip_calls.c000066400000000000000000000033541355360272700237610ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #define RK_SIP_DDR_CFG 0x82000008 #define DRAM_INIT 0x00 #define DRAM_SET_RATE 0x01 #define DRAM_ROUND_RATE 0x02 #define DRAM_SET_AT_SR 0x03 #define DRAM_GET_BW 0x04 #define DRAM_GET_RATE 0x05 #define DRAM_CLR_IRQ 0x06 #define DRAM_SET_PARAM 0x07 #define DRAM_SET_ODT_PD 0x08 #define RK_SIP_HDCP_CONTROL 0x82000009 #define RK_SIP_HDCP_KEY_DATA64 0xC200000A uint32_t ddr_smc_handler(uint64_t arg0, uint64_t arg1, uint64_t id, uint64_t arg2) { switch (id) { case DRAM_SET_RATE: return ddr_set_rate((uint32_t)arg0); case DRAM_ROUND_RATE: return ddr_round_rate((uint32_t)arg0); case DRAM_GET_RATE: return ddr_get_rate(); case DRAM_SET_ODT_PD: dram_set_odt_pd(arg0, arg1, arg2); break; default: break; } return 0; } uintptr_t rockchip_plat_sip_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) { uint64_t x5, x6; switch (smc_fid) { case RK_SIP_DDR_CFG: SMC_RET1(handle, ddr_smc_handler(x1, x2, x3, x4)); case RK_SIP_HDCP_CONTROL: SMC_RET1(handle, dp_hdcp_ctrl(x1)); case RK_SIP_HDCP_KEY_DATA64: x5 = read_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X5); x6 = read_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X6); SMC_RET1(handle, dp_hdcp_store_key(x1, x2, x3, x4, x5, x6)); default: ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); SMC_RET1(handle, SMC_UNK); } } trusted-firmware-a-2.2/plat/rockchip/rk3399/platform.mk000066400000000000000000000067421355360272700230050ustar00rootroot00000000000000# # Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # RK_PLAT := plat/rockchip RK_PLAT_SOC := ${RK_PLAT}/${PLAT} RK_PLAT_COMMON := ${RK_PLAT}/common DISABLE_BIN_GENERATION := 1 PLAT_INCLUDES := -I${RK_PLAT_COMMON}/ \ -I${RK_PLAT_COMMON}/include/ \ -I${RK_PLAT_COMMON}/aarch64/ \ -I${RK_PLAT_COMMON}/drivers/pmu/ \ -I${RK_PLAT_SOC}/ \ -I${RK_PLAT_SOC}/drivers/pmu/ \ -I${RK_PLAT_SOC}/drivers/pwm/ \ -I${RK_PLAT_SOC}/drivers/secure/ \ -I${RK_PLAT_SOC}/drivers/soc/ \ -I${RK_PLAT_SOC}/drivers/dram/ \ -I${RK_PLAT_SOC}/drivers/dp/ \ -I${RK_PLAT_SOC}/include/ \ -I${RK_PLAT_SOC}/include/shared/ \ RK_GIC_SOURCES := drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v3/arm_gicv3_common.c \ drivers/arm/gic/v3/gic500.c \ drivers/arm/gic/v3/gicv3_main.c \ drivers/arm/gic/v3/gicv3_helpers.c \ plat/common/plat_gicv3.c \ ${RK_PLAT}/common/rockchip_gicv3.c PLAT_BL_COMMON_SOURCES := common/desc_image_load.c \ lib/bl_aux_params/bl_aux_params.c \ lib/xlat_tables/xlat_tables_common.c \ lib/xlat_tables/aarch64/xlat_tables.c \ plat/common/aarch64/crash_console_helpers.S \ plat/common/plat_psci_common.c BL31_SOURCES += ${RK_GIC_SOURCES} \ drivers/arm/cci/cci.c \ drivers/ti/uart/aarch64/16550_console.S \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/gpio/gpio.c \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a72.S \ ${RK_PLAT_COMMON}/aarch64/plat_helpers.S \ ${RK_PLAT_COMMON}/bl31_plat_setup.c \ ${RK_PLAT_COMMON}/params_setup.c \ ${RK_PLAT_COMMON}/aarch64/pmu_sram_cpus_on.S \ ${RK_PLAT_COMMON}/plat_pm.c \ ${RK_PLAT_COMMON}/plat_topology.c \ ${RK_PLAT_COMMON}/aarch64/platform_common.c \ ${RK_PLAT_COMMON}/rockchip_sip_svc.c \ ${RK_PLAT_SOC}/plat_sip_calls.c \ ${RK_PLAT_SOC}/drivers/dp/cdn_dp.c \ ${RK_PLAT_SOC}/drivers/gpio/rk3399_gpio.c \ ${RK_PLAT_SOC}/drivers/pmu/pmu.c \ ${RK_PLAT_SOC}/drivers/pmu/pmu_fw.c \ ${RK_PLAT_SOC}/drivers/pmu/m0_ctl.c \ ${RK_PLAT_SOC}/drivers/pwm/pwm.c \ ${RK_PLAT_SOC}/drivers/secure/secure.c \ ${RK_PLAT_SOC}/drivers/soc/soc.c \ ${RK_PLAT_SOC}/drivers/dram/dfs.c \ ${RK_PLAT_SOC}/drivers/dram/dram.c \ ${RK_PLAT_SOC}/drivers/dram/dram_spec_timing.c \ ${RK_PLAT_SOC}/drivers/dram/suspend.c include lib/coreboot/coreboot.mk include lib/libfdt/libfdt.mk $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) # Enable workarounds for selected Cortex-A53 erratas. ERRATA_A53_855873 := 1 # M0 source build PLAT_M0 := ${PLAT}m0 BUILD_M0 := ${BUILD_PLAT}/m0 RK3399M0FW=${BUILD_M0}/${PLAT_M0}.bin $(eval $(call add_define,RK3399M0FW)) RK3399M0PMUFW=${BUILD_M0}/${PLAT_M0}pmu.bin $(eval $(call add_define,RK3399M0PMUFW)) HDCPFW=${RK_PLAT_SOC}/drivers/dp/hdcp.bin $(eval $(call add_define,HDCPFW)) # CCACHE_EXTRAFILES is needed because ccache doesn't handle .incbin export CCACHE_EXTRAFILES ${BUILD_PLAT}/bl31/pmu_fw.o: CCACHE_EXTRAFILES=$(RK3399M0FW):$(RK3399M0PMUFW) ${RK_PLAT_SOC}/drivers/pmu/pmu_fw.c: $(RK3399M0FW) ${BUILD_PLAT}/bl31/cdn_dp.o: CCACHE_EXTRAFILES=$(HDCPFW) ${RK_PLAT_SOC}/drivers/dp/cdn_dp.c: $(HDCPFW) $(eval $(call MAKE_PREREQ_DIR,${BUILD_M0},${BUILD_PLAT})) .PHONY: $(RK3399M0FW) $(RK3399M0FW): | ${BUILD_M0} $(MAKE) -C ${RK_PLAT_SOC}/drivers/m0 BUILD=$(abspath ${BUILD_PLAT}/m0) # Do not enable SVE ENABLE_SVE_FOR_NS := 0 trusted-firmware-a-2.2/plat/rockchip/rk3399/rk3399_def.h000066400000000000000000000042671355360272700225630ustar00rootroot00000000000000/* * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RK3399_DEF_H #define RK3399_DEF_H #include #define RK3399_PRIMARY_CPU 0x0 /* Special value used to verify platform parameters from BL2 to BL3-1 */ #define RK_BL31_PLAT_PARAM_VAL 0x0f1e2d3c4b5a6978ULL /************************************************************************** * UART related constants **************************************************************************/ #define RK3399_BAUDRATE 115200 #define RK3399_UART_CLOCK 24000000 /****************************************************************************** * System counter frequency related constants ******************************************************************************/ #define SYS_COUNTER_FREQ_IN_TICKS 24000000 /* Base rockchip_platform compatible GIC memory map */ #define BASE_GICD_BASE (GIC500_BASE) #define BASE_GICR_BASE (GIC500_BASE + SIZE_M(1)) /***************************************************************************** * CCI-400 related constants ******************************************************************************/ #define PLAT_RK_CCI_CLUSTER0_SL_IFACE_IX 0 #define PLAT_RK_CCI_CLUSTER1_SL_IFACE_IX 1 /****************************************************************************** * sgi, ppi ******************************************************************************/ #define ARM_IRQ_SEC_PHY_TIMER 29 #define ARM_IRQ_SEC_SGI_0 8 #define ARM_IRQ_SEC_SGI_1 9 #define ARM_IRQ_SEC_SGI_2 10 #define ARM_IRQ_SEC_SGI_3 11 #define ARM_IRQ_SEC_SGI_4 12 #define ARM_IRQ_SEC_SGI_5 13 #define ARM_IRQ_SEC_SGI_6 14 #define ARM_IRQ_SEC_SGI_7 15 /* * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 * terminology. On a GICv2 system or mode, the lists will be merged and treated * as Group 0 interrupts. */ #define PLAT_RK_GICV3_G1S_IRQS \ INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, \ INTR_GROUP1S, GIC_INTR_CFG_LEVEL) #define PLAT_RK_GICV3_G0_IRQS \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, \ INTR_GROUP0, GIC_INTR_CFG_LEVEL) #endif /* RK3399_DEF_H */ trusted-firmware-a-2.2/plat/rpi/000077500000000000000000000000001355360272700166435ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rpi/common/000077500000000000000000000000001355360272700201335ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rpi/common/include/000077500000000000000000000000001355360272700215565ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rpi/common/include/rpi_shared.h000066400000000000000000000022131355360272700240450ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RPI_SHARED_H #define RPI_SHARED_H #include /******************************************************************************* * Function and variable prototypes ******************************************************************************/ /* Utility functions */ void rpi3_console_init(unsigned int base_clk_rate); void rpi3_setup_page_tables(uintptr_t total_base, size_t total_size, uintptr_t code_start, uintptr_t code_limit, uintptr_t rodata_start, uintptr_t rodata_limit #if USE_COHERENT_MEM , uintptr_t coh_start, uintptr_t coh_limit #endif ); /* Optional functions required in the Raspberry Pi 3 port */ unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr); /* BL2 utility functions */ uint32_t rpi3_get_spsr_for_bl32_entry(void); uint32_t rpi3_get_spsr_for_bl33_entry(void); /* IO storage utility functions */ void plat_rpi3_io_setup(void); /* VideoCore firmware commands */ int rpi3_vc_hardware_get_board_revision(uint32_t *revision); #endif /* RPI3_PRIVATE_H */ trusted-firmware-a-2.2/plat/rpi/common/rpi3_common.c000066400000000000000000000135541355360272700225340ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #define MAP_DEVICE0 MAP_REGION_FLAT(DEVICE0_BASE, \ DEVICE0_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #ifdef SHARED_RAM_BASE #define MAP_SHARED_RAM MAP_REGION_FLAT(SHARED_RAM_BASE, \ SHARED_RAM_SIZE, \ MT_DEVICE | MT_RW | MT_SECURE) #endif #ifdef RPI3_PRELOADED_DTB_BASE #define MAP_NS_DTB MAP_REGION_FLAT(RPI3_PRELOADED_DTB_BASE, 0x10000, \ MT_MEMORY | MT_RW | MT_NS) #endif #define MAP_NS_DRAM0 MAP_REGION_FLAT(NS_DRAM0_BASE, NS_DRAM0_SIZE, \ MT_MEMORY | MT_RW | MT_NS) #define MAP_FIP MAP_REGION_FLAT(PLAT_RPI3_FIP_BASE, \ PLAT_RPI3_FIP_MAX_SIZE, \ MT_MEMORY | MT_RO | MT_NS) #define MAP_BL32_MEM MAP_REGION_FLAT(BL32_MEM_BASE, BL32_MEM_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #ifdef SPD_opteed #define MAP_OPTEE_PAGEABLE MAP_REGION_FLAT( \ RPI3_OPTEE_PAGEABLE_LOAD_BASE, \ RPI3_OPTEE_PAGEABLE_LOAD_SIZE, \ MT_MEMORY | MT_RW | MT_SECURE) #endif /* * Table of regions for various BL stages to map using the MMU. */ #ifdef IMAGE_BL1 static const mmap_region_t plat_rpi3_mmap[] = { #ifdef MAP_SHARED_RAM MAP_SHARED_RAM, #endif MAP_DEVICE0, MAP_FIP, #ifdef SPD_opteed MAP_OPTEE_PAGEABLE, #endif {0} }; #endif #ifdef IMAGE_BL2 static const mmap_region_t plat_rpi3_mmap[] = { #ifdef MAP_SHARED_RAM MAP_SHARED_RAM, #endif MAP_DEVICE0, MAP_FIP, MAP_NS_DRAM0, #ifdef BL32_BASE MAP_BL32_MEM, #endif {0} }; #endif #ifdef IMAGE_BL31 static const mmap_region_t plat_rpi3_mmap[] = { #ifdef MAP_SHARED_RAM MAP_SHARED_RAM, #endif MAP_DEVICE0, #ifdef RPI3_PRELOADED_DTB_BASE MAP_NS_DTB, #endif #ifdef BL32_BASE MAP_BL32_MEM, #endif {0} }; #endif /******************************************************************************* * Function that sets up the console ******************************************************************************/ static console_16550_t rpi3_console; void rpi3_console_init(unsigned int base_clk_rate) { int console_scope = CONSOLE_FLAG_BOOT; #if RPI3_RUNTIME_UART != -1 console_scope |= CONSOLE_FLAG_RUNTIME; #endif int rc = console_16550_register(PLAT_RPI3_UART_BASE, base_clk_rate, PLAT_RPI3_UART_BAUDRATE, &rpi3_console); if (rc == 0) { /* * The crash console doesn't use the multi console API, it uses * the core console functions directly. It is safe to call panic * and let it print debug information. */ panic(); } console_set_scope(&rpi3_console.console, console_scope); } /******************************************************************************* * Function that sets up the translation tables. ******************************************************************************/ void rpi3_setup_page_tables(uintptr_t total_base, size_t total_size, uintptr_t code_start, uintptr_t code_limit, uintptr_t rodata_start, uintptr_t rodata_limit #if USE_COHERENT_MEM , uintptr_t coh_start, uintptr_t coh_limit #endif ) { /* * Map the Trusted SRAM with appropriate memory attributes. * Subsequent mappings will adjust the attributes for specific regions. */ VERBOSE("Trusted SRAM seen by this BL image: %p - %p\n", (void *) total_base, (void *) (total_base + total_size)); mmap_add_region(total_base, total_base, total_size, MT_MEMORY | MT_RW | MT_SECURE); /* Re-map the code section */ VERBOSE("Code region: %p - %p\n", (void *) code_start, (void *) code_limit); mmap_add_region(code_start, code_start, code_limit - code_start, MT_CODE | MT_SECURE); /* Re-map the read-only data section */ VERBOSE("Read-only data region: %p - %p\n", (void *) rodata_start, (void *) rodata_limit); mmap_add_region(rodata_start, rodata_start, rodata_limit - rodata_start, MT_RO_DATA | MT_SECURE); #if USE_COHERENT_MEM /* Re-map the coherent memory region */ VERBOSE("Coherent region: %p - %p\n", (void *) coh_start, (void *) coh_limit); mmap_add_region(coh_start, coh_start, coh_limit - coh_start, MT_DEVICE | MT_RW | MT_SECURE); #endif mmap_add(plat_rpi3_mmap); init_xlat_tables(); } /******************************************************************************* * Gets SPSR for BL32 entry ******************************************************************************/ uint32_t rpi3_get_spsr_for_bl32_entry(void) { /* * The Secure Payload Dispatcher service is responsible for * setting the SPSR prior to entry into the BL32 image. */ return 0; } /******************************************************************************* * Gets SPSR for BL33 entry ******************************************************************************/ uint32_t rpi3_get_spsr_for_bl33_entry(void) { #if RPI3_BL33_IN_AARCH32 INFO("BL33 will boot in Non-secure AArch32 Hypervisor mode\n"); return SPSR_MODE32(MODE32_hyp, SPSR_T_ARM, SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS); #else return SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); #endif } unsigned int plat_get_syscnt_freq2(void) { return SYS_COUNTER_FREQ_IN_TICKS; } uint32_t plat_ic_get_pending_interrupt_type(void) { ERROR("rpi3: Interrupt routed to EL3.\n"); return INTR_TYPE_INVAL; } uint32_t plat_interrupt_type_to_line(uint32_t type, uint32_t security_state) { assert((type == INTR_TYPE_S_EL1) || (type == INTR_TYPE_EL3) || (type == INTR_TYPE_NS)); assert(sec_state_is_valid(security_state)); /* Non-secure interrupts are signalled on the IRQ line always. */ if (type == INTR_TYPE_NS) return __builtin_ctz(SCR_IRQ_BIT); /* Secure interrupts are signalled on the FIQ line always. */ return __builtin_ctz(SCR_FIQ_BIT); } trusted-firmware-a-2.2/plat/rpi/common/rpi3_image_load.c000066400000000000000000000023161355360272700233170ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /******************************************************************************* * This function flushes the data structures so that they are visible * in memory for the next BL image. ******************************************************************************/ void plat_flush_next_bl_params(void) { flush_bl_params_desc(); } /******************************************************************************* * This function returns the list of loadable images. ******************************************************************************/ bl_load_info_t *plat_get_bl_image_load_info(void) { return get_bl_load_info_from_mem_params_desc(); } /******************************************************************************* * This function returns the list of executable images. ******************************************************************************/ bl_params_t *plat_get_next_bl_params(void) { return get_next_bl_params_from_mem_params_desc(); } trusted-firmware-a-2.2/plat/rpi/common/rpi3_io_storage.c000066400000000000000000000143141355360272700233720ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include /* Semihosting filenames */ #define BL2_IMAGE_NAME "bl2.bin" #define BL31_IMAGE_NAME "bl31.bin" #define BL32_IMAGE_NAME "bl32.bin" #define BL33_IMAGE_NAME "bl33.bin" #if TRUSTED_BOARD_BOOT #define TRUSTED_BOOT_FW_CERT_NAME "tb_fw.crt" #define TRUSTED_KEY_CERT_NAME "trusted_key.crt" #define SOC_FW_KEY_CERT_NAME "soc_fw_key.crt" #define TOS_FW_KEY_CERT_NAME "tos_fw_key.crt" #define NT_FW_KEY_CERT_NAME "nt_fw_key.crt" #define SOC_FW_CONTENT_CERT_NAME "soc_fw_content.crt" #define TOS_FW_CONTENT_CERT_NAME "tos_fw_content.crt" #define NT_FW_CONTENT_CERT_NAME "nt_fw_content.crt" #endif /* TRUSTED_BOARD_BOOT */ /* IO devices */ static const io_dev_connector_t *fip_dev_con; static uintptr_t fip_dev_handle; static const io_dev_connector_t *memmap_dev_con; static uintptr_t memmap_dev_handle; static const io_block_spec_t fip_block_spec = { .offset = PLAT_RPI3_FIP_BASE, .length = PLAT_RPI3_FIP_MAX_SIZE }; static const io_uuid_spec_t bl2_uuid_spec = { .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2, }; static const io_uuid_spec_t bl31_uuid_spec = { .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31, }; static const io_uuid_spec_t bl32_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32, }; static const io_uuid_spec_t bl32_extra1_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1, }; static const io_uuid_spec_t bl32_extra2_uuid_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2, }; static const io_uuid_spec_t bl33_uuid_spec = { .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33, }; #if TRUSTED_BOARD_BOOT static const io_uuid_spec_t tb_fw_cert_uuid_spec = { .uuid = UUID_TRUSTED_BOOT_FW_CERT, }; static const io_uuid_spec_t trusted_key_cert_uuid_spec = { .uuid = UUID_TRUSTED_KEY_CERT, }; static const io_uuid_spec_t soc_fw_key_cert_uuid_spec = { .uuid = UUID_SOC_FW_KEY_CERT, }; static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = { .uuid = UUID_TRUSTED_OS_FW_KEY_CERT, }; static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = { .uuid = UUID_NON_TRUSTED_FW_KEY_CERT, }; static const io_uuid_spec_t soc_fw_cert_uuid_spec = { .uuid = UUID_SOC_FW_CONTENT_CERT, }; static const io_uuid_spec_t tos_fw_cert_uuid_spec = { .uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT, }; static const io_uuid_spec_t nt_fw_cert_uuid_spec = { .uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT, }; #endif /* TRUSTED_BOARD_BOOT */ static int open_fip(const uintptr_t spec); static int open_memmap(const uintptr_t spec); struct plat_io_policy { uintptr_t *dev_handle; uintptr_t image_spec; int (*check)(const uintptr_t spec); }; /* By default, load images from the FIP */ static const struct plat_io_policy policies[] = { [FIP_IMAGE_ID] = { &memmap_dev_handle, (uintptr_t)&fip_block_spec, open_memmap }, [BL2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl2_uuid_spec, open_fip }, [BL31_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl31_uuid_spec, open_fip }, [BL32_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_uuid_spec, open_fip }, [BL32_EXTRA1_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_extra1_uuid_spec, open_fip }, [BL32_EXTRA2_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl32_extra2_uuid_spec, open_fip }, [BL33_IMAGE_ID] = { &fip_dev_handle, (uintptr_t)&bl33_uuid_spec, open_fip }, #if TRUSTED_BOARD_BOOT [TRUSTED_BOOT_FW_CERT_ID] = { &fip_dev_handle, (uintptr_t)&tb_fw_cert_uuid_spec, open_fip }, [TRUSTED_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&trusted_key_cert_uuid_spec, open_fip }, [SOC_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&soc_fw_key_cert_uuid_spec, open_fip }, [TRUSTED_OS_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&tos_fw_key_cert_uuid_spec, open_fip }, [NON_TRUSTED_FW_KEY_CERT_ID] = { &fip_dev_handle, (uintptr_t)&nt_fw_key_cert_uuid_spec, open_fip }, [SOC_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&soc_fw_cert_uuid_spec, open_fip }, [TRUSTED_OS_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&tos_fw_cert_uuid_spec, open_fip }, [NON_TRUSTED_FW_CONTENT_CERT_ID] = { &fip_dev_handle, (uintptr_t)&nt_fw_cert_uuid_spec, open_fip }, #endif /* TRUSTED_BOARD_BOOT */ }; static int open_fip(const uintptr_t spec) { int result; uintptr_t local_image_handle; /* See if a Firmware Image Package is available */ result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); if (result == 0) { result = io_open(fip_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using FIP\n"); io_close(local_image_handle); } } return result; } static int open_memmap(const uintptr_t spec) { int result; uintptr_t local_image_handle; result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL); if (result == 0) { result = io_open(memmap_dev_handle, spec, &local_image_handle); if (result == 0) { VERBOSE("Using Memmap\n"); io_close(local_image_handle); } } return result; } void plat_rpi3_io_setup(void) { int io_result; io_result = register_io_dev_fip(&fip_dev_con); assert(io_result == 0); io_result = register_io_dev_memmap(&memmap_dev_con); assert(io_result == 0); /* Open connections to devices and cache the handles */ io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL, &fip_dev_handle); assert(io_result == 0); io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL, &memmap_dev_handle); assert(io_result == 0); /* Ignore improbable errors in release builds */ (void)io_result; } /* * 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 result; const struct plat_io_policy *policy; assert(image_id < ARRAY_SIZE(policies)); policy = &policies[image_id]; result = policy->check(policy->image_spec); if (result == 0) { *image_spec = policy->image_spec; *dev_handle = *(policy->dev_handle); } return result; } trusted-firmware-a-2.2/plat/rpi/common/rpi3_pm.c000066400000000000000000000156071355360272700216610ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #ifdef RPI_HAVE_GIC #include #endif /* Make composite power state parameter till power level 0 */ #if PSCI_EXTENDED_STATE_ID #define rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ (((lvl0_state) << PSTATE_ID_SHIFT) | \ ((type) << PSTATE_TYPE_SHIFT)) #else #define rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type) \ (((lvl0_state) << PSTATE_ID_SHIFT) | \ ((pwr_lvl) << PSTATE_PWR_LVL_SHIFT) | \ ((type) << PSTATE_TYPE_SHIFT)) #endif /* PSCI_EXTENDED_STATE_ID */ #define rpi3_make_pwrstate_lvl1(lvl1_state, lvl0_state, pwr_lvl, type) \ (((lvl1_state) << PLAT_LOCAL_PSTATE_WIDTH) | \ rpi3_make_pwrstate_lvl0(lvl0_state, pwr_lvl, type)) /* * The table storing the valid idle power states. Ensure that the * array entries are populated in ascending order of state-id to * enable us to use binary search during power state validation. * The table must be terminated by a NULL entry. */ static const unsigned int rpi3_pm_idle_states[] = { /* State-id - 0x01 */ rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_RET, MPIDR_AFFLVL0, PSTATE_TYPE_STANDBY), /* State-id - 0x02 */ rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_RUN, PLAT_LOCAL_STATE_OFF, MPIDR_AFFLVL0, PSTATE_TYPE_POWERDOWN), /* State-id - 0x22 */ rpi3_make_pwrstate_lvl1(PLAT_LOCAL_STATE_OFF, PLAT_LOCAL_STATE_OFF, MPIDR_AFFLVL1, PSTATE_TYPE_POWERDOWN), 0, }; /******************************************************************************* * Platform handler called to check the validity of the power state * parameter. The power state parameter has to be a composite power state. ******************************************************************************/ static int rpi3_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { unsigned int state_id; int i; assert(req_state != 0); /* * Currently we are using a linear search for finding the matching * entry in the idle power state array. This can be made a binary * search if the number of entries justify the additional complexity. */ for (i = 0; rpi3_pm_idle_states[i] != 0; i++) { if (power_state == rpi3_pm_idle_states[i]) { break; } } /* Return error if entry not found in the idle state array */ if (!rpi3_pm_idle_states[i]) { return PSCI_E_INVALID_PARAMS; } i = 0; state_id = psci_get_pstate_id(power_state); /* Parse the State ID and populate the state info parameter */ while (state_id) { req_state->pwr_domain_state[i++] = state_id & PLAT_LOCAL_PSTATE_MASK; state_id >>= PLAT_LOCAL_PSTATE_WIDTH; } return PSCI_E_SUCCESS; } /******************************************************************************* * Platform handler called when a CPU is about to enter standby. ******************************************************************************/ static void rpi3_cpu_standby(plat_local_state_t cpu_state) { assert(cpu_state == PLAT_LOCAL_STATE_RET); /* * Enter standby state. * dsb is good practice before using wfi to enter low power states */ dsb(); wfi(); } static void rpi3_pwr_domain_off(const psci_power_state_t *target_state) { #ifdef RPI_HAVE_GIC gicv2_cpuif_disable(); #endif } /******************************************************************************* * Platform handler called when a power domain is about to be turned on. The * mpidr determines the CPU to be turned on. ******************************************************************************/ static int rpi3_pwr_domain_on(u_register_t mpidr) { int rc = PSCI_E_SUCCESS; unsigned int pos = plat_core_pos_by_mpidr(mpidr); uint64_t *hold_base = (uint64_t *)PLAT_RPI3_TM_HOLD_BASE; assert(pos < PLATFORM_CORE_COUNT); hold_base[pos] = PLAT_RPI3_TM_HOLD_STATE_GO; /* Make sure that the write has completed */ dsb(); isb(); sev(); return rc; } /******************************************************************************* * Platform handler called when a power domain has just been powered on after * being turned off earlier. The target_state encodes the low power state that * each level has woken up from. ******************************************************************************/ static void rpi3_pwr_domain_on_finish(const psci_power_state_t *target_state) { assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == PLAT_LOCAL_STATE_OFF); #ifdef RPI_HAVE_GIC gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); #endif } /******************************************************************************* * Platform handlers for system reset and system off. ******************************************************************************/ /* 10 ticks (Watchdog timer = Timer clock / 16) */ #define RESET_TIMEOUT U(10) static void __dead2 rpi3_watchdog_reset(void) { uint32_t rstc; console_flush(); dsbsy(); isb(); mmio_write_32(RPI3_PM_BASE + RPI3_PM_WDOG_OFFSET, RPI3_PM_PASSWORD | RESET_TIMEOUT); rstc = mmio_read_32(RPI3_PM_BASE + RPI3_PM_RSTC_OFFSET); rstc &= ~RPI3_PM_RSTC_WRCFG_MASK; rstc |= RPI3_PM_PASSWORD | RPI3_PM_RSTC_WRCFG_FULL_RESET; mmio_write_32(RPI3_PM_BASE + RPI3_PM_RSTC_OFFSET, rstc); for (;;) { wfi(); } } static void __dead2 rpi3_system_reset(void) { INFO("rpi3: PSCI_SYSTEM_RESET: Invoking watchdog reset\n"); rpi3_watchdog_reset(); } static void __dead2 rpi3_system_off(void) { uint32_t rsts; INFO("rpi3: PSCI_SYSTEM_OFF: Invoking watchdog reset\n"); /* * This function doesn't actually make the Raspberry Pi turn itself off, * the hardware doesn't allow it. It simply reboots it and the RSTS * value tells the bootcode.bin firmware not to continue the regular * bootflow and to stay in a low power mode. */ rsts = mmio_read_32(RPI3_PM_BASE + RPI3_PM_RSTS_OFFSET); rsts |= RPI3_PM_PASSWORD | RPI3_PM_RSTS_WRCFG_HALT; mmio_write_32(RPI3_PM_BASE + RPI3_PM_RSTS_OFFSET, rsts); rpi3_watchdog_reset(); } /******************************************************************************* * Platform handlers and setup function. ******************************************************************************/ static const plat_psci_ops_t plat_rpi3_psci_pm_ops = { .cpu_standby = rpi3_cpu_standby, .pwr_domain_off = rpi3_pwr_domain_off, .pwr_domain_on = rpi3_pwr_domain_on, .pwr_domain_on_finish = rpi3_pwr_domain_on_finish, .system_off = rpi3_system_off, .system_reset = rpi3_system_reset, .validate_power_state = rpi3_validate_power_state, }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { uintptr_t *entrypoint = (void *) PLAT_RPI3_TM_ENTRYPOINT; *entrypoint = sec_entrypoint; *psci_ops = &plat_rpi3_psci_pm_ops; return 0; } trusted-firmware-a-2.2/plat/rpi/common/rpi3_rotpk.S000066400000000000000000000006211355360272700223520ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ .global rpi3_rotpk_hash .global rpi3_rotpk_hash_end rpi3_rotpk_hash: /* DER header */ .byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48 .byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 /* SHA256 */ .incbin ROTPK_HASH rpi3_rotpk_hash_end: trusted-firmware-a-2.2/plat/rpi/common/rpi3_stack_protector.c000066400000000000000000000011271355360272700244430ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /* Get 128 bits of entropy and fuse the values together to form the canary. */ #define TRNG_NBYTES 16U u_register_t plat_get_stack_protector_canary(void) { size_t i; u_register_t buf[TRNG_NBYTES / sizeof(u_register_t)]; u_register_t ret = 0U; rpi3_rng_read(buf, sizeof(buf)); for (i = 0U; i < ARRAY_SIZE(buf); i++) ret ^= buf[i]; return ret; } trusted-firmware-a-2.2/plat/rpi/common/rpi3_topology.c000066400000000000000000000032221355360272700231070ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /* The power domain tree descriptor */ static unsigned char power_domain_tree_desc[] = { /* Number of root nodes */ PLATFORM_CLUSTER_COUNT, /* Number of children for the first node */ PLATFORM_CLUSTER0_CORE_COUNT, }; /******************************************************************************* * This function returns the ARM default topology tree information. ******************************************************************************/ const unsigned char *plat_get_power_domain_tree_desc(void) { return power_domain_tree_desc; } /******************************************************************************* * This function implements a part of the critical interface between the psci * generic layer and the platform that allows the former to query the platform * to convert an MPIDR to a unique linear index. An error code (-1) is returned * in case the MPIDR is invalid. ******************************************************************************/ int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; mpidr &= MPIDR_AFFINITY_MASK; if (mpidr & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) { return -1; } cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; if (cluster_id >= PLATFORM_CLUSTER_COUNT) { return -1; } if (cpu_id >= PLATFORM_MAX_CPUS_PER_CLUSTER) { return -1; } return plat_rpi3_calc_core_pos(mpidr); } trusted-firmware-a-2.2/plat/rpi/common/rpi3_trusted_boot.c000066400000000000000000000013241355360272700237510ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include extern char rpi3_rotpk_hash[], rpi3_rotpk_hash_end[]; int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, unsigned int *flags) { *key_ptr = rpi3_rotpk_hash; *key_len = rpi3_rotpk_hash_end - rpi3_rotpk_hash; *flags = ROTPK_IS_HASH; return 0; } int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr) { *nv_ctr = 0; return 0; } int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr) { return 1; } int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size) { return get_mbedtls_heap_helper(heap_addr, heap_size); } trusted-firmware-a-2.2/plat/rpi/rpi3/000077500000000000000000000000001355360272700175205ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rpi/rpi3/aarch64/000077500000000000000000000000001355360272700207505ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rpi/rpi3/aarch64/plat_helpers.S000066400000000000000000000111121355360272700235520ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "../include/rpi_hw.h" .globl plat_crash_console_flush .globl plat_crash_console_init .globl plat_crash_console_putc .globl platform_mem_init .globl plat_get_my_entrypoint .globl plat_is_my_cpu_primary .globl plat_my_core_pos .globl plat_rpi3_calc_core_pos .globl plat_secondary_cold_boot_setup /* ----------------------------------------------------- * unsigned int plat_my_core_pos(void) * * This function uses the plat_rpi3_calc_core_pos() * definition to get the index of the calling CPU. * ----------------------------------------------------- */ func plat_my_core_pos mrs x0, mpidr_el1 b plat_rpi3_calc_core_pos endfunc plat_my_core_pos /* ----------------------------------------------------- * unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr); * * CorePos = (ClusterId * 4) + CoreId * ----------------------------------------------------- */ func plat_rpi3_calc_core_pos and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 ret endfunc plat_rpi3_calc_core_pos /* ----------------------------------------------------- * unsigned int plat_is_my_cpu_primary (void); * * Find out whether the current cpu is the primary * cpu. * ----------------------------------------------------- */ func plat_is_my_cpu_primary mrs x0, mpidr_el1 and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) cmp x0, #RPI3_PRIMARY_CPU cset w0, eq ret endfunc plat_is_my_cpu_primary /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions * needed for a secondary cpu after a cold reset e.g * mark the cpu's presence, mechanism to place it in a * holding pen etc. * ----------------------------------------------------- */ func plat_secondary_cold_boot_setup /* Calculate address of our hold entry */ bl plat_my_core_pos lsl x0, x0, #3 mov_imm x2, PLAT_RPI3_TM_HOLD_BASE add x0, x0, x2 /* * This code runs way before requesting the warmboot of this core, * so it is possible to clear the mailbox before getting a request * to boot. */ mov x1, PLAT_RPI3_TM_HOLD_STATE_WAIT str x1,[x0] /* Wait until we have a go */ poll_mailbox: wfe ldr x1, [x0] cmp x1, PLAT_RPI3_TM_HOLD_STATE_GO bne poll_mailbox /* Jump to the provided entrypoint */ mov_imm x0, PLAT_RPI3_TM_ENTRYPOINT ldr x1, [x0] br x1 endfunc plat_secondary_cold_boot_setup /* --------------------------------------------------------------------- * uintptr_t plat_get_my_entrypoint (void); * * Main job of this routine is to distinguish between a cold and a warm * boot. * * This functions returns: * - 0 for a cold boot. * - Any other value for a warm boot. * --------------------------------------------------------------------- */ func plat_get_my_entrypoint /* TODO: support warm boot */ mov x0, #0 ret endfunc plat_get_my_entrypoint /* --------------------------------------------- * void platform_mem_init (void); * * No need to carry out any memory initialization. * --------------------------------------------- */ func platform_mem_init ret endfunc platform_mem_init /* --------------------------------------------- * int plat_crash_console_init(void) * Function to initialize the crash console * without a C Runtime to print crash report. * Clobber list : x0 - x3 * --------------------------------------------- */ func plat_crash_console_init mov_imm x0, PLAT_RPI3_UART_BASE mov_imm x1, PLAT_RPI3_UART_CLK_IN_HZ mov_imm x2, PLAT_RPI3_UART_BAUDRATE b console_16550_core_init endfunc plat_crash_console_init /* --------------------------------------------- * int plat_crash_console_putc(int c) * Function to print a character on the crash * console without a C Runtime. * Clobber list : x1, x2 * --------------------------------------------- */ func plat_crash_console_putc mov_imm x1, PLAT_RPI3_UART_BASE b console_16550_core_putc endfunc plat_crash_console_putc /* --------------------------------------------- * int plat_crash_console_flush() * Function to force a write of all buffered * data that hasn't been output. * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func plat_crash_console_flush mov_imm x0, PLAT_RPI3_UART_BASE b console_16550_core_flush endfunc plat_crash_console_flush trusted-firmware-a-2.2/plat/rpi/rpi3/aarch64/rpi3_bl2_mem_params_desc.c000066400000000000000000000076151355360272700257400ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /******************************************************************************* * Following descriptor provides BL image/ep information that gets used * by BL2 to load the images and also subset of this information is * passed to next BL image. The image loading sequence is managed by * populating the images in required loading order. The image execution * sequence is managed by populating the `next_handoff_image_id` with * the next executable image id. ******************************************************************************/ static bl_mem_params_node_t bl2_mem_params_descs[] = { /* Fill BL31 related information */ { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = BL31_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), #if DEBUG .ep_info.args.arg1 = RPI3_BL31_PLAT_PARAM_VAL, #endif SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP), .image_info.image_base = BL31_BASE, .image_info.image_max_size = BL31_LIMIT - BL31_BASE, # ifdef BL32_BASE .next_handoff_image_id = BL32_IMAGE_ID, # else .next_handoff_image_id = BL33_IMAGE_ID, # endif }, # ifdef BL32_BASE /* Fill BL32 related information */ { .image_id = BL32_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE), .ep_info.pc = BL32_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = BL32_BASE, .image_info.image_max_size = BL32_LIMIT - BL32_BASE, .next_handoff_image_id = BL33_IMAGE_ID, }, /* * Fill BL32 external 1 related information. * A typical use for extra1 image is with OP-TEE where it is the pager * image. */ { .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), .image_info.image_base = BL32_BASE, .image_info.image_max_size = BL32_LIMIT - BL32_BASE, .next_handoff_image_id = INVALID_IMAGE_ID, }, /* * Fill BL32 external 2 related information. * A typical use for extra2 image is with OP-TEE where it is the paged * image. */ { .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), #ifdef SPD_opteed .image_info.image_base = RPI3_OPTEE_PAGEABLE_LOAD_BASE, .image_info.image_max_size = RPI3_OPTEE_PAGEABLE_LOAD_SIZE, #endif .next_handoff_image_id = INVALID_IMAGE_ID, }, # endif /* BL32_BASE */ /* Fill BL33 related information */ { .image_id = BL33_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), # ifdef PRELOADED_BL33_BASE .ep_info.pc = PRELOADED_BL33_BASE, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), # else .ep_info.pc = PLAT_RPI3_NS_IMAGE_OFFSET, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = PLAT_RPI3_NS_IMAGE_OFFSET, .image_info.image_max_size = PLAT_RPI3_NS_IMAGE_MAX_SIZE, # endif /* PRELOADED_BL33_BASE */ .next_handoff_image_id = INVALID_IMAGE_ID, } }; REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) trusted-firmware-a-2.2/plat/rpi/rpi3/include/000077500000000000000000000000001355360272700211435ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rpi/rpi3/include/plat_macros.S000066400000000000000000000010211355360272700235650ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S /* --------------------------------------------- * The below required platform porting macro * prints out relevant platform registers * whenever an unhandled exception is taken in * BL31. * Clobbers: x0 - x10, x16, x17, sp * --------------------------------------------- */ .macro plat_crash_print_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/rpi/rpi3/include/platform_def.h000066400000000000000000000170051355360272700237610ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include #include "rpi_hw.h" /* Special value used to verify platform parameters from BL2 to BL31 */ #define RPI3_BL31_PLAT_PARAM_VAL ULL(0x0F1E2D3C4B5A6978) #define PLATFORM_STACK_SIZE ULL(0x1000) #define PLATFORM_MAX_CPUS_PER_CLUSTER U(4) #define PLATFORM_CLUSTER_COUNT U(1) #define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER #define PLATFORM_CORE_COUNT PLATFORM_CLUSTER0_CORE_COUNT #define RPI3_PRIMARY_CPU U(0) #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1 #define PLAT_NUM_PWR_DOMAINS (PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE U(2) /* Local power state for power domains in Run state. */ #define PLAT_LOCAL_STATE_RUN U(0) /* Local power state for retention. Valid only for CPU power domains */ #define PLAT_LOCAL_STATE_RET U(1) /* * Local power state for OFF/power-down. Valid for CPU and cluster power * domains. */ #define PLAT_LOCAL_STATE_OFF U(2) /* * Macros used to parse state information from State-ID if it is using the * recommended encoding for State-ID. */ #define PLAT_LOCAL_PSTATE_WIDTH U(4) #define PLAT_LOCAL_PSTATE_MASK ((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1) /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. */ #define CACHE_WRITEBACK_SHIFT U(6) #define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT) /* * Partition memory into secure ROM, non-secure DRAM, secure "SRAM", and * secure DRAM. Note that this is all actually DRAM with different names, * there is no Secure RAM in the Raspberry Pi 3. */ #if RPI3_USE_UEFI_MAP #define SEC_ROM_BASE ULL(0x00000000) #define SEC_ROM_SIZE ULL(0x00010000) /* FIP placed after ROM to append it to BL1 with very little padding. */ #define PLAT_RPI3_FIP_BASE ULL(0x00020000) #define PLAT_RPI3_FIP_MAX_SIZE ULL(0x00010000) /* Reserve 2M of secure SRAM and DRAM, starting at 2M */ #define SEC_SRAM_BASE ULL(0x00200000) #define SEC_SRAM_SIZE ULL(0x00100000) #define SEC_DRAM0_BASE ULL(0x00300000) #define SEC_DRAM0_SIZE ULL(0x00100000) /* Windows on ARM requires some RAM at 4M */ #define NS_DRAM0_BASE ULL(0x00400000) #define NS_DRAM0_SIZE ULL(0x00C00000) #else #define SEC_ROM_BASE ULL(0x00000000) #define SEC_ROM_SIZE ULL(0x00020000) /* FIP placed after ROM to append it to BL1 with very little padding. */ #define PLAT_RPI3_FIP_BASE ULL(0x00020000) #define PLAT_RPI3_FIP_MAX_SIZE ULL(0x001E0000) /* We have 16M of memory reserved starting at 256M */ #define SEC_SRAM_BASE ULL(0x10000000) #define SEC_SRAM_SIZE ULL(0x00100000) #define SEC_DRAM0_BASE ULL(0x10100000) #define SEC_DRAM0_SIZE ULL(0x00F00000) /* End of reserved memory */ #define NS_DRAM0_BASE ULL(0x11000000) #define NS_DRAM0_SIZE ULL(0x01000000) #endif /* RPI3_USE_UEFI_MAP */ /* * BL33 entrypoint. */ #define PLAT_RPI3_NS_IMAGE_OFFSET NS_DRAM0_BASE #define PLAT_RPI3_NS_IMAGE_MAX_SIZE NS_DRAM0_SIZE /* * I/O registers. */ #define DEVICE0_BASE RPI_IO_BASE #define DEVICE0_SIZE RPI_IO_SIZE /* * Arm TF lives in SRAM, partition it here */ #define SHARED_RAM_BASE SEC_SRAM_BASE #define SHARED_RAM_SIZE ULL(0x00001000) #define BL_RAM_BASE (SHARED_RAM_BASE + SHARED_RAM_SIZE) #define BL_RAM_SIZE (SEC_SRAM_SIZE - SHARED_RAM_SIZE) /* * Mailbox to control the secondary cores.All secondary cores are held in a wait * loop in cold boot. To release them perform the following steps (plus any * additional barriers that may be needed): * * uint64_t *entrypoint = (uint64_t *)PLAT_RPI3_TM_ENTRYPOINT; * *entrypoint = ADDRESS_TO_JUMP_TO; * * uint64_t *mbox_entry = (uint64_t *)PLAT_RPI3_TM_HOLD_BASE; * mbox_entry[cpu_id] = PLAT_RPI3_TM_HOLD_STATE_GO; * * sev(); */ #define PLAT_RPI3_TRUSTED_MAILBOX_BASE SHARED_RAM_BASE /* The secure entry point to be used on warm reset by all CPUs. */ #define PLAT_RPI3_TM_ENTRYPOINT PLAT_RPI3_TRUSTED_MAILBOX_BASE #define PLAT_RPI3_TM_ENTRYPOINT_SIZE ULL(8) /* Hold entries for each CPU. */ #define PLAT_RPI3_TM_HOLD_BASE (PLAT_RPI3_TM_ENTRYPOINT + \ PLAT_RPI3_TM_ENTRYPOINT_SIZE) #define PLAT_RPI3_TM_HOLD_ENTRY_SIZE ULL(8) #define PLAT_RPI3_TM_HOLD_SIZE (PLAT_RPI3_TM_HOLD_ENTRY_SIZE * \ PLATFORM_CORE_COUNT) #define PLAT_RPI3_TRUSTED_MAILBOX_SIZE (PLAT_RPI3_TM_ENTRYPOINT_SIZE + \ PLAT_RPI3_TM_HOLD_SIZE) #define PLAT_RPI3_TM_HOLD_STATE_WAIT ULL(0) #define PLAT_RPI3_TM_HOLD_STATE_GO ULL(1) /* * BL1 specific defines. * * BL1 RW data is relocated from ROM to RAM at runtime so we need 2 sets of * addresses. * * Put BL1 RW at the top of the Secure SRAM. BL1_RW_BASE is calculated using * the current BL1 RW debug size plus a little space for growth. */ #define PLAT_MAX_BL1_RW_SIZE ULL(0x12000) #define BL1_RO_BASE SEC_ROM_BASE #define BL1_RO_LIMIT (SEC_ROM_BASE + SEC_ROM_SIZE) #define BL1_RW_BASE (BL1_RW_LIMIT - PLAT_MAX_BL1_RW_SIZE) #define BL1_RW_LIMIT (BL_RAM_BASE + BL_RAM_SIZE) /* * BL2 specific defines. * * Put BL2 just below BL31. BL2_BASE is calculated using the current BL2 debug * size plus a little space for growth. */ #define PLAT_MAX_BL2_SIZE ULL(0x2C000) #define BL2_BASE (BL2_LIMIT - PLAT_MAX_BL2_SIZE) #define BL2_LIMIT BL31_BASE /* * BL31 specific defines. * * Put BL31 at the top of the Trusted SRAM. BL31_BASE is calculated using the * current BL31 debug size plus a little space for growth. */ #define PLAT_MAX_BL31_SIZE ULL(0x20000) #define BL31_BASE (BL31_LIMIT - PLAT_MAX_BL31_SIZE) #define BL31_LIMIT (BL_RAM_BASE + BL_RAM_SIZE) #define BL31_PROGBITS_LIMIT BL1_RW_BASE /* * BL32 specific defines. * * BL32 can execute from Secure SRAM or Secure DRAM. */ #define BL32_SRAM_BASE BL_RAM_BASE #define BL32_SRAM_LIMIT BL31_BASE #define BL32_DRAM_BASE SEC_DRAM0_BASE #define BL32_DRAM_LIMIT (SEC_DRAM0_BASE + SEC_DRAM0_SIZE) #ifdef SPD_opteed /* Load pageable part of OP-TEE at end of allocated DRAM space for BL32 */ #define RPI3_OPTEE_PAGEABLE_LOAD_SIZE 0x080000 /* 512KB */ #define RPI3_OPTEE_PAGEABLE_LOAD_BASE (BL32_DRAM_LIMIT - \ RPI3_OPTEE_PAGEABLE_LOAD_SIZE) #endif #define SEC_SRAM_ID 0 #define SEC_DRAM_ID 1 #if RPI3_BL32_RAM_LOCATION_ID == SEC_SRAM_ID # define BL32_MEM_BASE BL_RAM_BASE # define BL32_MEM_SIZE BL_RAM_SIZE # define BL32_BASE BL32_SRAM_BASE # define BL32_LIMIT BL32_SRAM_LIMIT #elif RPI3_BL32_RAM_LOCATION_ID == SEC_DRAM_ID # define BL32_MEM_BASE SEC_DRAM0_BASE # define BL32_MEM_SIZE SEC_DRAM0_SIZE # define BL32_BASE BL32_DRAM_BASE # define BL32_LIMIT BL32_DRAM_LIMIT #else # error "Unsupported RPI3_BL32_RAM_LOCATION_ID value" #endif #define BL32_SIZE (BL32_LIMIT - BL32_BASE) #ifdef SPD_none #undef BL32_BASE #endif /* SPD_none */ /* * Other memory-related defines. */ #define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32) #define MAX_MMAP_REGIONS 8 #define MAX_XLAT_TABLES 4 #define MAX_IO_DEVICES U(3) #define MAX_IO_HANDLES U(4) #define MAX_IO_BLOCK_DEVICES U(1) /* * Serial-related constants. */ #define PLAT_RPI3_UART_BASE RPI3_MINI_UART_BASE #define PLAT_RPI3_UART_CLK_IN_HZ RPI3_MINI_UART_CLK_IN_HZ #define PLAT_RPI3_UART_BAUDRATE ULL(115200) /* * System counter */ #define SYS_COUNTER_FREQ_IN_TICKS ULL(19200000) #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/rpi/rpi3/include/rpi_hw.h000066400000000000000000000070261355360272700226110ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RPI_HW_H #define RPI_HW_H #include /* * Peripherals */ #define RPI_IO_BASE ULL(0x3F000000) #define RPI_IO_SIZE ULL(0x01000000) /* * ARM <-> VideoCore mailboxes */ #define RPI3_MBOX_OFFSET ULL(0x0000B880) #define RPI3_MBOX_BASE (RPI_IO_BASE + RPI3_MBOX_OFFSET) /* VideoCore -> ARM */ #define RPI3_MBOX0_READ_OFFSET ULL(0x00000000) #define RPI3_MBOX0_PEEK_OFFSET ULL(0x00000010) #define RPI3_MBOX0_SENDER_OFFSET ULL(0x00000014) #define RPI3_MBOX0_STATUS_OFFSET ULL(0x00000018) #define RPI3_MBOX0_CONFIG_OFFSET ULL(0x0000001C) /* ARM -> VideoCore */ #define RPI3_MBOX1_WRITE_OFFSET ULL(0x00000020) #define RPI3_MBOX1_PEEK_OFFSET ULL(0x00000030) #define RPI3_MBOX1_SENDER_OFFSET ULL(0x00000034) #define RPI3_MBOX1_STATUS_OFFSET ULL(0x00000038) #define RPI3_MBOX1_CONFIG_OFFSET ULL(0x0000003C) /* Mailbox status constants */ #define RPI3_MBOX_STATUS_FULL_MASK U(0x80000000) /* Set if full */ #define RPI3_MBOX_STATUS_EMPTY_MASK U(0x40000000) /* Set if empty */ /* * Power management, reset controller, watchdog. */ #define RPI3_IO_PM_OFFSET ULL(0x00100000) #define RPI3_PM_BASE (RPI_IO_BASE + RPI3_IO_PM_OFFSET) /* Registers on top of RPI3_PM_BASE. */ #define RPI3_PM_RSTC_OFFSET ULL(0x0000001C) #define RPI3_PM_RSTS_OFFSET ULL(0x00000020) #define RPI3_PM_WDOG_OFFSET ULL(0x00000024) /* Watchdog constants */ #define RPI3_PM_PASSWORD U(0x5A000000) #define RPI3_PM_RSTC_WRCFG_MASK U(0x00000030) #define RPI3_PM_RSTC_WRCFG_FULL_RESET U(0x00000020) /* * The RSTS register is used by the VideoCore firmware when booting the * Raspberry Pi to know which partition to boot from. The partition value is * formed by bits 0, 2, 4, 6, 8 and 10. Partition 63 is used by said firmware * to indicate halt. */ #define RPI3_PM_RSTS_WRCFG_HALT U(0x00000555) /* * Hardware random number generator. */ #define RPI3_IO_RNG_OFFSET ULL(0x00104000) #define RPI3_RNG_BASE (RPI_IO_BASE + RPI3_IO_RNG_OFFSET) #define RPI3_RNG_CTRL_OFFSET ULL(0x00000000) #define RPI3_RNG_STATUS_OFFSET ULL(0x00000004) #define RPI3_RNG_DATA_OFFSET ULL(0x00000008) #define RPI3_RNG_INT_MASK_OFFSET ULL(0x00000010) /* Enable/disable RNG */ #define RPI3_RNG_CTRL_ENABLE U(0x1) #define RPI3_RNG_CTRL_DISABLE U(0x0) /* Number of currently available words */ #define RPI3_RNG_STATUS_NUM_WORDS_SHIFT U(24) #define RPI3_RNG_STATUS_NUM_WORDS_MASK U(0xFF) /* Value to mask interrupts caused by the RNG */ #define RPI3_RNG_INT_MASK_DISABLE U(0x1) /* * Serial port (called 'Mini UART' in the BCM docucmentation). */ #define RPI3_IO_MINI_UART_OFFSET ULL(0x00215040) #define RPI3_MINI_UART_BASE (RPI_IO_BASE + RPI3_IO_MINI_UART_OFFSET) #define RPI3_MINI_UART_CLK_IN_HZ ULL(500000000) /* * GPIO controller */ #define RPI3_IO_GPIO_OFFSET ULL(0x00200000) #define RPI3_GPIO_BASE (RPI_IO_BASE + RPI3_IO_GPIO_OFFSET) /* * SDHost controller */ #define RPI3_IO_SDHOST_OFFSET ULL(0x00202000) #define RPI3_SDHOST_BASE (RPI_IO_BASE + RPI3_IO_SDHOST_OFFSET) /* * Local interrupt controller */ #define RPI3_INTC_BASE_ADDRESS ULL(0x40000000) /* Registers on top of RPI3_INTC_BASE_ADDRESS */ #define RPI3_INTC_CONTROL_OFFSET ULL(0x00000000) #define RPI3_INTC_PRESCALER_OFFSET ULL(0x00000008) #define RPI3_INTC_MBOX_CONTROL_OFFSET ULL(0x00000050) #define RPI3_INTC_MBOX_CONTROL_SLOT3_FIQ ULL(0x00000080) #define RPI3_INTC_PENDING_FIQ_OFFSET ULL(0x00000070) #define RPI3_INTC_PENDING_FIQ_MBOX3 ULL(0x00000080) #endif /* RPI_HW_H */ trusted-firmware-a-2.2/plat/rpi/rpi3/platform.mk000066400000000000000000000140751355360272700217040ustar00rootroot00000000000000# # Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # include lib/libfdt/libfdt.mk include lib/xlat_tables_v2/xlat_tables.mk PLAT_INCLUDES := -Iplat/rpi/common/include \ -Iplat/rpi/rpi3/include PLAT_BL_COMMON_SOURCES := drivers/ti/uart/aarch64/16550_console.S \ plat/rpi/common/rpi3_common.c \ ${XLAT_TABLES_LIB_SRCS} BL1_SOURCES += drivers/io/io_fip.c \ drivers/io/io_memmap.c \ drivers/io/io_storage.c \ lib/cpus/aarch64/cortex_a53.S \ plat/common/aarch64/platform_mp_stack.S \ plat/rpi/rpi3/aarch64/plat_helpers.S \ plat/rpi/rpi3/rpi3_bl1_setup.c \ plat/rpi/common/rpi3_io_storage.c \ drivers/rpi3/mailbox/rpi3_mbox.c \ plat/rpi/rpi3/rpi_mbox_board.c BL2_SOURCES += common/desc_image_load.c \ drivers/io/io_fip.c \ drivers/io/io_memmap.c \ drivers/io/io_storage.c \ drivers/gpio/gpio.c \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/rpi3/gpio/rpi3_gpio.c \ drivers/io/io_block.c \ drivers/mmc/mmc.c \ drivers/rpi3/sdhost/rpi3_sdhost.c \ plat/common/aarch64/platform_mp_stack.S \ plat/rpi/rpi3/aarch64/plat_helpers.S \ plat/rpi/rpi3/aarch64/rpi3_bl2_mem_params_desc.c \ plat/rpi/rpi3/rpi3_bl2_setup.c \ plat/rpi/common/rpi3_image_load.c \ plat/rpi/common/rpi3_io_storage.c BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \ plat/common/plat_psci_common.c \ plat/rpi/rpi3/aarch64/plat_helpers.S \ plat/rpi/rpi3/rpi3_bl31_setup.c \ plat/rpi/common/rpi3_pm.c \ plat/rpi/common/rpi3_topology.c \ ${LIBFDT_SRCS} # Tune compiler for Cortex-A53 ifeq ($(notdir $(CC)),armclang) TF_CFLAGS_aarch64 += -mcpu=cortex-a53 else ifneq ($(findstring clang,$(notdir $(CC))),) TF_CFLAGS_aarch64 += -mcpu=cortex-a53 else TF_CFLAGS_aarch64 += -mtune=cortex-a53 endif # Platform Makefile target # ------------------------ RPI3_BL1_PAD_BIN := ${BUILD_PLAT}/bl1_pad.bin RPI3_ARMSTUB8_BIN := ${BUILD_PLAT}/armstub8.bin # Add new default target when compiling this platform all: armstub # This target concatenates BL1 and the FIP so that the base addresses match the # ones defined in the memory map armstub: bl1 fip @echo " CAT $@" ${Q}cp ${BUILD_PLAT}/bl1.bin ${RPI3_BL1_PAD_BIN} ${Q}truncate --size=131072 ${RPI3_BL1_PAD_BIN} ${Q}cat ${RPI3_BL1_PAD_BIN} ${BUILD_PLAT}/fip.bin > ${RPI3_ARMSTUB8_BIN} @${ECHO_BLANK_LINE} @echo "Built $@ successfully" @${ECHO_BLANK_LINE} # Build config flags # ------------------ # Enable all errata workarounds for Cortex-A53 ERRATA_A53_826319 := 1 ERRATA_A53_835769 := 1 ERRATA_A53_836870 := 1 ERRATA_A53_843419 := 1 ERRATA_A53_855873 := 1 WORKAROUND_CVE_2017_5715 := 0 # Disable stack protector by default ENABLE_STACK_PROTECTOR := 0 # Reset to BL31 isn't supported RESET_TO_BL31 := 0 # Have different sections for code and rodata SEPARATE_CODE_AND_RODATA := 1 # Use Coherent memory USE_COHERENT_MEM := 1 # Platform build flags # -------------------- # BL33 images are in AArch64 by default RPI3_BL33_IN_AARCH32 := 0 # Assume that BL33 isn't the Linux kernel by default RPI3_DIRECT_LINUX_BOOT := 0 # UART to use at runtime. -1 means the runtime UART is disabled. # Any other value means the default UART will be used. RPI3_RUNTIME_UART := -1 # Use normal memory mapping for ROM, FIP, SRAM and DRAM RPI3_USE_UEFI_MAP := 0 # BL32 location RPI3_BL32_RAM_LOCATION := tdram ifeq (${RPI3_BL32_RAM_LOCATION}, tsram) RPI3_BL32_RAM_LOCATION_ID = SEC_SRAM_ID else ifeq (${RPI3_BL32_RAM_LOCATION}, tdram) RPI3_BL32_RAM_LOCATION_ID = SEC_DRAM_ID else $(error "Unsupported RPI3_BL32_RAM_LOCATION value") endif # Process platform flags # ---------------------- $(eval $(call add_define,RPI3_BL32_RAM_LOCATION_ID)) $(eval $(call add_define,RPI3_BL33_IN_AARCH32)) $(eval $(call add_define,RPI3_DIRECT_LINUX_BOOT)) ifdef RPI3_PRELOADED_DTB_BASE $(eval $(call add_define,RPI3_PRELOADED_DTB_BASE)) endif $(eval $(call add_define,RPI3_RUNTIME_UART)) $(eval $(call add_define,RPI3_USE_UEFI_MAP)) # Verify build config # ------------------- # ifneq (${RPI3_DIRECT_LINUX_BOOT}, 0) ifndef RPI3_PRELOADED_DTB_BASE $(error Error: RPI3_PRELOADED_DTB_BASE needed if RPI3_DIRECT_LINUX_BOOT=1) endif endif ifneq (${RESET_TO_BL31}, 0) $(error Error: rpi3 needs RESET_TO_BL31=0) endif ifeq (${ARCH},aarch32) $(error Error: AArch32 not supported on rpi3) endif ifneq ($(ENABLE_STACK_PROTECTOR), 0) PLAT_BL_COMMON_SOURCES += drivers/rpi3/rng/rpi3_rng.c \ plat/rpi/common/rpi3_stack_protector.c endif ifeq (${SPD},opteed) BL2_SOURCES += \ lib/optee/optee_utils.c endif # Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images # in the FIP if the platform requires. ifneq ($(BL32_EXTRA1),) $(eval $(call TOOL_ADD_IMG,BL32_EXTRA1,--tos-fw-extra1)) endif ifneq ($(BL32_EXTRA2),) $(eval $(call TOOL_ADD_IMG,BL32_EXTRA2,--tos-fw-extra2)) endif ifneq (${TRUSTED_BOARD_BOOT},0) include drivers/auth/mbedtls/mbedtls_crypto.mk include drivers/auth/mbedtls/mbedtls_x509.mk AUTH_SOURCES := drivers/auth/auth_mod.c \ drivers/auth/crypto_mod.c \ drivers/auth/img_parser_mod.c \ drivers/auth/tbbr/tbbr_cot.c BL1_SOURCES += ${AUTH_SOURCES} \ bl1/tbbr/tbbr_img_desc.c \ plat/common/tbbr/plat_tbbr.c \ plat/rpi/common/rpi3_trusted_boot.c \ plat/rpi/common/rpi3_rotpk.S BL2_SOURCES += ${AUTH_SOURCES} \ plat/common/tbbr/plat_tbbr.c \ plat/rpi/common/rpi3_trusted_boot.c \ plat/rpi/common/rpi3_rotpk.S ROT_KEY = $(BUILD_PLAT)/rot_key.pem ROTPK_HASH = $(BUILD_PLAT)/rotpk_sha256.bin $(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"')) $(BUILD_PLAT)/bl1/rpi3_rotpk.o: $(ROTPK_HASH) $(BUILD_PLAT)/bl2/rpi3_rotpk.o: $(ROTPK_HASH) certificates: $(ROT_KEY) $(ROT_KEY): @echo " OPENSSL $@" $(Q)openssl genrsa 2048 > $@ 2>/dev/null $(ROTPK_HASH): $(ROT_KEY) @echo " OPENSSL $@" $(Q)openssl rsa -in $< -pubout -outform DER 2>/dev/null |\ openssl dgst -sha256 -binary > $@ 2>/dev/null endif trusted-firmware-a-2.2/plat/rpi/rpi3/rpi3_bl1_setup.c000066400000000000000000000053611355360272700225240ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include /* Data structure which holds the extents of the trusted SRAM for BL1 */ static meminfo_t bl1_tzram_layout; meminfo_t *bl1_plat_sec_mem_layout(void) { return &bl1_tzram_layout; } /******************************************************************************* * Perform any BL1 specific platform actions. ******************************************************************************/ void bl1_early_platform_setup(void) { /* use the 19.2 MHz clock for the architected timer */ mmio_write_32(RPI3_INTC_BASE_ADDRESS + RPI3_INTC_CONTROL_OFFSET, 0); mmio_write_32(RPI3_INTC_BASE_ADDRESS + RPI3_INTC_PRESCALER_OFFSET, 0x80000000); /* Initialize the console to provide early debug support */ rpi3_console_init(PLAT_RPI3_UART_CLK_IN_HZ); /* Allow BL1 to see the whole Trusted RAM */ bl1_tzram_layout.total_base = BL_RAM_BASE; bl1_tzram_layout.total_size = BL_RAM_SIZE; } /****************************************************************************** * Perform the very early platform specific architecture setup. This only * does basic initialization. Later architectural setup (bl1_arch_setup()) * does not do anything platform specific. *****************************************************************************/ void bl1_plat_arch_setup(void) { rpi3_setup_page_tables(bl1_tzram_layout.total_base, bl1_tzram_layout.total_size, BL_CODE_BASE, BL1_CODE_END, BL1_RO_DATA_BASE, BL1_RO_DATA_END #if USE_COHERENT_MEM , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END #endif ); enable_mmu_el3(0); } void bl1_platform_setup(void) { uint32_t __unused rev; int __unused rc; rc = rpi3_vc_hardware_get_board_revision(&rev); if (rc == 0) { const char __unused *model, __unused *info; switch (rev) { case 0xA02082: model = "Raspberry Pi 3 Model B"; info = "(1GB, Sony, UK)"; break; case 0xA22082: model = "Raspberry Pi 3 Model B"; info = "(1GB, Embest, China)"; break; case 0xA020D3: model = "Raspberry Pi 3 Model B+"; info = "(1GB, Sony, UK)"; break; default: model = "Unknown"; info = "(Unknown)"; ERROR("rpi3: Unknown board revision 0x%08x\n", rev); break; } NOTICE("rpi3: Detected: %s %s [0x%08x]\n", model, info, rev); } else { ERROR("rpi3: Unable to detect board revision\n"); } /* Initialise the IO layer and register platform IO devices */ plat_rpi3_io_setup(); } trusted-firmware-a-2.2/plat/rpi/rpi3/rpi3_bl2_setup.c000066400000000000000000000105241355360272700225220ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* Data structure which holds the extents of the trusted SRAM for BL2 */ static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE); /* rpi3 GPIO setup function. */ static void rpi3_gpio_setup(void) { struct rpi3_gpio_params params; memset(¶ms, 0, sizeof(struct rpi3_gpio_params)); params.reg_base = RPI3_GPIO_BASE; rpi3_gpio_init(¶ms); } /* Data structure which holds the MMC info */ static struct mmc_device_info mmc_info; static void rpi3_sdhost_setup(void) { struct rpi3_sdhost_params params; memset(¶ms, 0, sizeof(struct rpi3_sdhost_params)); params.reg_base = RPI3_SDHOST_BASE; params.bus_width = MMC_BUS_WIDTH_1; params.clk_rate = 50000000; mmc_info.mmc_dev_type = MMC_IS_SD_HC; rpi3_sdhost_init(¶ms, &mmc_info); } /******************************************************************************* * BL1 has passed the extents of the trusted SRAM that should be visible to BL2 * in x0. This memory layout is sitting at the base of the free trusted SRAM. * Copy it to a safe location before its reclaimed by later BL2 functionality. ******************************************************************************/ void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { meminfo_t *mem_layout = (meminfo_t *) arg1; /* Initialize the console to provide early debug support */ rpi3_console_init(PLAT_RPI3_UART_CLK_IN_HZ); /* Enable arch timer */ generic_delay_timer_init(); /* Setup GPIO driver */ rpi3_gpio_setup(); /* Setup the BL2 memory layout */ bl2_tzram_layout = *mem_layout; /* Setup SDHost driver */ rpi3_sdhost_setup(); plat_rpi3_io_setup(); } void bl2_platform_setup(void) { /* * This is where a TrustZone address space controller and other * security related peripherals would be configured. */ } /******************************************************************************* * Perform the very early platform specific architectural setup here. ******************************************************************************/ void bl2_plat_arch_setup(void) { rpi3_setup_page_tables(bl2_tzram_layout.total_base, bl2_tzram_layout.total_size, BL_CODE_BASE, BL_CODE_END, BL_RO_DATA_BASE, BL_RO_DATA_END #if USE_COHERENT_MEM , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END #endif ); enable_mmu_el1(0); } /******************************************************************************* * 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); #ifdef SPD_opteed bl_mem_params_node_t *pager_mem_params = NULL; bl_mem_params_node_t *paged_mem_params = NULL; #endif assert(bl_mem_params != NULL); switch (image_id) { case BL32_IMAGE_ID: #ifdef SPD_opteed 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); err = parse_optee_header(&bl_mem_params->ep_info, &pager_mem_params->image_info, &paged_mem_params->image_info); if (err != 0) WARN("OPTEE header parse error.\n"); #endif bl_mem_params->ep_info.spsr = rpi3_get_spsr_for_bl32_entry(); break; case BL33_IMAGE_ID: /* BL33 expects to receive the primary CPU MPID (through r0) */ bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr(); bl_mem_params->ep_info.spsr = rpi3_get_spsr_for_bl33_entry(); /* Shutting down the SDHost driver to let BL33 drives SDHost.*/ rpi3_sdhost_stop(); break; default: /* Do nothing in default case */ break; } return err; } trusted-firmware-a-2.2/plat/rpi/rpi3/rpi3_bl31_setup.c000066400000000000000000000147201355360272700226060ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include /* * Placeholder variables for copying the arguments that have been passed to * BL31 from BL2. */ static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for * the security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. ******************************************************************************/ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; assert(sec_state_is_valid(type) != 0); next_image_info = (type == NON_SECURE) ? &bl33_image_ep_info : &bl32_image_ep_info; /* None of the images can have 0x0 as the entrypoint. */ if (next_image_info->pc) { return next_image_info; } else { return NULL; } } /******************************************************************************* * Return entrypoint of BL33. ******************************************************************************/ uintptr_t plat_get_ns_image_entrypoint(void) { #ifdef PRELOADED_BL33_BASE return PRELOADED_BL33_BASE; #else return PLAT_RPI3_NS_IMAGE_OFFSET; #endif } /******************************************************************************* * Perform any BL31 early platform setup. Here is an opportunity to copy * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before * they are lost (potentially). This needs to be done before the MMU is * initialized so that the memory layout can be used while creating page * tables. BL2 has flushed this information to memory, so we are guaranteed * to pick up good data. ******************************************************************************/ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { /* Initialize the console to provide early debug support */ rpi3_console_init(PLAT_RPI3_UART_CLK_IN_HZ); /* * In debug builds, a special value is passed in 'arg1' to verify * platform parameters from BL2 to BL31. Not used in release builds. */ assert(arg1 == RPI3_BL31_PLAT_PARAM_VAL); /* Check that params passed from BL2 are not NULL. */ bl_params_t *params_from_bl2 = (bl_params_t *) arg0; assert(params_from_bl2 != NULL); assert(params_from_bl2->h.type == PARAM_BL_PARAMS); assert(params_from_bl2->h.version >= VERSION_2); bl_params_node_t *bl_params = params_from_bl2->head; /* * Copy BL33 and BL32 (if present), entry point information. * They are stored in Secure RAM, in BL2's address space. */ while (bl_params) { if (bl_params->image_id == BL32_IMAGE_ID) { bl32_image_ep_info = *bl_params->ep_info; } if (bl_params->image_id == BL33_IMAGE_ID) { bl33_image_ep_info = *bl_params->ep_info; } bl_params = bl_params->next_params_info; } if (bl33_image_ep_info.pc == 0) { panic(); } #if RPI3_DIRECT_LINUX_BOOT # if RPI3_BL33_IN_AARCH32 /* * According to the file ``Documentation/arm/Booting`` of the Linux * kernel tree, Linux expects: * r0 = 0 * r1 = machine type number, optional in DT-only platforms (~0 if so) * r2 = Physical address of the device tree blob */ VERBOSE("rpi3: Preparing to boot 32-bit Linux kernel\n"); bl33_image_ep_info.args.arg0 = 0U; bl33_image_ep_info.args.arg1 = ~0U; bl33_image_ep_info.args.arg2 = (u_register_t) RPI3_PRELOADED_DTB_BASE; # else /* * According to the file ``Documentation/arm64/booting.txt`` of the * Linux kernel tree, Linux expects the physical address of the device * tree blob (DTB) in x0, while x1-x3 are reserved for future use and * must be 0. */ VERBOSE("rpi3: Preparing to boot 64-bit Linux kernel\n"); bl33_image_ep_info.args.arg0 = (u_register_t) RPI3_PRELOADED_DTB_BASE; bl33_image_ep_info.args.arg1 = 0ULL; bl33_image_ep_info.args.arg2 = 0ULL; bl33_image_ep_info.args.arg3 = 0ULL; # endif /* RPI3_BL33_IN_AARCH32 */ #endif /* RPI3_DIRECT_LINUX_BOOT */ } void bl31_plat_arch_setup(void) { rpi3_setup_page_tables(BL31_BASE, BL31_END - BL31_BASE, BL_CODE_BASE, BL_CODE_END, BL_RO_DATA_BASE, BL_RO_DATA_END #if USE_COHERENT_MEM , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END #endif ); enable_mmu_el3(0); } #ifdef RPI3_PRELOADED_DTB_BASE /* * Add information to the device tree (if any) about the reserved DRAM used by * the Trusted Firmware. */ static void rpi3_dtb_add_mem_rsv(void) { int i, regions, rc; uint64_t addr, size; void *dtb = (void *)RPI3_PRELOADED_DTB_BASE; INFO("rpi3: Checking DTB...\n"); /* Return if no device tree is detected */ if (fdt_check_header(dtb) != 0) return; regions = fdt_num_mem_rsv(dtb); VERBOSE("rpi3: Found %d mem reserve region(s)\n", regions); /* We expect to find one reserved region that we can modify */ if (regions < 1) return; /* * Look for the region that corresponds to the default boot firmware. It * starts at address 0, and it is not needed when the default firmware * is replaced by this port of the Trusted Firmware. */ for (i = 0; i < regions; i++) { if (fdt_get_mem_rsv(dtb, i, &addr, &size) != 0) continue; if (addr != 0x0) continue; VERBOSE("rpi3: Firmware mem reserve region found\n"); rc = fdt_del_mem_rsv(dtb, i); if (rc != 0) { INFO("rpi3: Can't remove mem reserve region (%d)\n", rc); } break; } if (i == regions) { VERBOSE("rpi3: Firmware mem reserve region not found\n"); } /* * Reserve all SRAM. As said in the documentation, this isn't actually * secure memory, so it is needed to tell BL33 that this is a reserved * memory region. It doesn't guarantee it won't use it, though. */ rc = fdt_add_mem_rsv(dtb, SEC_SRAM_BASE, SEC_SRAM_SIZE); if (rc != 0) { WARN("rpi3: Can't add mem reserve region (%d)\n", rc); } INFO("rpi3: Reserved 0x%llx - 0x%llx in DTB\n", SEC_SRAM_BASE, SEC_SRAM_BASE + SEC_SRAM_SIZE); } #endif void bl31_platform_setup(void) { #ifdef RPI3_PRELOADED_DTB_BASE /* Only modify a DTB if we know where to look for it */ rpi3_dtb_add_mem_rsv(); #endif } trusted-firmware-a-2.2/plat/rpi/rpi3/rpi_mbox_board.c000066400000000000000000000030601355360272700226510ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #define RPI3_MBOX_BUFFER_SIZE U(256) static uint8_t __aligned(16) rpi3_mbox_buffer[RPI3_MBOX_BUFFER_SIZE]; /******************************************************************************* * Request board revision. Returns the revision and 0 on success, -1 on error. ******************************************************************************/ int rpi3_vc_hardware_get_board_revision(uint32_t *revision) { uint32_t tag_request_size = sizeof(uint32_t); rpi3_mbox_request_t *req = (rpi3_mbox_request_t *) rpi3_mbox_buffer; assert(revision != NULL); VERBOSE("rpi3: mbox: Sending request at %p\n", (void *)req); req->size = sizeof(rpi3_mbox_buffer); req->code = RPI3_MBOX_PROCESS_REQUEST; req->tags[0] = RPI3_TAG_HARDWARE_GET_BOARD_REVISION; req->tags[1] = tag_request_size; /* Space available for the response */ req->tags[2] = RPI3_TAG_REQUEST; req->tags[3] = 0; /* Placeholder for the response */ req->tags[4] = RPI3_TAG_END; rpi3_vc_mailbox_request_send(req, RPI3_MBOX_BUFFER_SIZE); if (req->code != RPI3_MBOX_REQUEST_SUCCESSFUL) { ERROR("rpi3: mbox: Code = 0x%08x\n", req->code); return -1; } if (req->tags[2] != (RPI3_TAG_IS_RESPONSE | tag_request_size)) { ERROR("rpi3: mbox: get board revision failed (0x%08x)\n", req->tags[2]); return -1; } *revision = req->tags[3]; return 0; } trusted-firmware-a-2.2/plat/rpi/rpi4/000077500000000000000000000000001355360272700175215ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rpi/rpi4/aarch64/000077500000000000000000000000001355360272700207515ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rpi/rpi4/aarch64/armstub8_header.S000066400000000000000000000014051355360272700241520ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * armstub8.bin header to let the GPU firmware recognise this code. * It will then write the load address of the kernel image and the DT * after the header magic in RAM, so we can read those addresses at runtime. */ .text b armstub8_end .global stub_magic .global dtb_ptr32 .global kernel_entry32 .org 0xf0 armstub8: stub_magic: .word 0x5afe570b stub_version: .word 0 dtb_ptr32: .word 0x0 kernel_entry32: .word 0x0 /* * Technically an offset of 0x100 would suffice, but the follow-up code * (bl31_entrypoint.S at BL31_BASE) needs to be page aligned, so pad here * till the end of the first 4K page. */ .org 0x1000 armstub8_end: trusted-firmware-a-2.2/plat/rpi/rpi4/aarch64/plat_helpers.S000066400000000000000000000122141355360272700235570ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "../include/rpi_hw.h" .globl plat_crash_console_flush .globl plat_crash_console_init .globl plat_crash_console_putc .globl platform_mem_init .globl plat_get_my_entrypoint .globl plat_is_my_cpu_primary .globl plat_my_core_pos .globl plat_reset_handler .globl plat_rpi3_calc_core_pos .globl plat_secondary_cold_boot_setup /* ----------------------------------------------------- * unsigned int plat_my_core_pos(void) * * This function uses the plat_rpi3_calc_core_pos() * definition to get the index of the calling CPU. * ----------------------------------------------------- */ func plat_my_core_pos mrs x0, mpidr_el1 b plat_rpi3_calc_core_pos endfunc plat_my_core_pos /* ----------------------------------------------------- * unsigned int plat_rpi3_calc_core_pos(u_register_t mpidr); * * CorePos = (ClusterId * 4) + CoreId * ----------------------------------------------------- */ func plat_rpi3_calc_core_pos and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 ret endfunc plat_rpi3_calc_core_pos /* ----------------------------------------------------- * unsigned int plat_is_my_cpu_primary (void); * * Find out whether the current cpu is the primary * cpu. * ----------------------------------------------------- */ func plat_is_my_cpu_primary mrs x0, mpidr_el1 and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) cmp x0, #RPI4_PRIMARY_CPU cset w0, eq ret endfunc plat_is_my_cpu_primary /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions * needed for a secondary cpu after a cold reset e.g * mark the cpu's presence, mechanism to place it in a * holding pen etc. * ----------------------------------------------------- */ func plat_secondary_cold_boot_setup /* Calculate address of our hold entry */ bl plat_my_core_pos lsl x0, x0, #3 mov_imm x2, PLAT_RPI3_TM_HOLD_BASE add x0, x0, x2 /* * This code runs way before requesting the warmboot of this core, * so it is possible to clear the mailbox before getting a request * to boot. */ mov x1, PLAT_RPI3_TM_HOLD_STATE_WAIT str x1,[x0] /* Wait until we have a go */ poll_mailbox: wfe ldr x1, [x0] cmp x1, PLAT_RPI3_TM_HOLD_STATE_GO bne poll_mailbox /* Jump to the provided entrypoint */ mov_imm x0, PLAT_RPI3_TM_ENTRYPOINT ldr x1, [x0] br x1 endfunc plat_secondary_cold_boot_setup /* --------------------------------------------------------------------- * uintptr_t plat_get_my_entrypoint (void); * * Main job of this routine is to distinguish between a cold and a warm * boot. * * This functions returns: * - 0 for a cold boot. * - Any other value for a warm boot. * --------------------------------------------------------------------- */ func plat_get_my_entrypoint /* TODO: support warm boot */ mov x0, #0 ret endfunc plat_get_my_entrypoint /* --------------------------------------------- * void platform_mem_init (void); * * No need to carry out any memory initialization. * --------------------------------------------- */ func platform_mem_init ret endfunc platform_mem_init /* --------------------------------------------- * int plat_crash_console_init(void) * Function to initialize the crash console * without a C Runtime to print crash report. * Clobber list : x0 - x3 * --------------------------------------------- */ func plat_crash_console_init mov_imm x0, PLAT_RPI3_UART_BASE mov_imm x1, PLAT_RPI4_VPU_CLK_RATE mov_imm x2, PLAT_RPI3_UART_BAUDRATE b console_16550_core_init endfunc plat_crash_console_init /* --------------------------------------------- * int plat_crash_console_putc(int c) * Function to print a character on the crash * console without a C Runtime. * Clobber list : x1, x2 * --------------------------------------------- */ func plat_crash_console_putc mov_imm x1, PLAT_RPI3_UART_BASE b console_16550_core_putc endfunc plat_crash_console_putc /* --------------------------------------------- * int plat_crash_console_flush() * Function to force a write of all buffered * data that hasn't been output. * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ func plat_crash_console_flush mov_imm x0, PLAT_RPI3_UART_BASE b console_16550_core_flush endfunc plat_crash_console_flush /* --------------------------------------------- * void plat_reset_handler(void); * --------------------------------------------- */ func plat_reset_handler /* ------------------------------------------------ * Set L2 read/write cache latency: * - L2 Data RAM latency: 3 cycles (0b010) * - L2 Data RAM setup: 1 cycle (bit 5) * ------------------------------------------------ */ mrs x0, CORTEX_A72_L2CTLR_EL1 mov x1, #0x22 orr x0, x0, x1 msr CORTEX_A72_L2CTLR_EL1, x0 isb ret endfunc plat_reset_handler trusted-firmware-a-2.2/plat/rpi/rpi4/include/000077500000000000000000000000001355360272700211445ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/rpi/rpi4/include/plat.ld.S000066400000000000000000000011531355360272700226260ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause * * Stub linker script to provide the armstub8.bin header before the actual * code. If the GPU firmware finds a magic value at offset 240 in * armstub8.bin, it will put the DTB and kernel load address in subsequent * words. We can then read those values to find the proper NS entry point * and find our DTB more flexibly. */ MEMORY { PRERAM (rwx): ORIGIN = 0, LENGTH = 4096 } SECTIONS { .armstub8 . : { *armstub8_header.o(.text*) KEEP(*(.armstub8)) } >PRERAM } trusted-firmware-a-2.2/plat/rpi/rpi4/include/plat_macros.S000066400000000000000000000010211355360272700235660ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S /* --------------------------------------------- * The below required platform porting macro * prints out relevant platform registers * whenever an unhandled exception is taken in * BL31. * Clobbers: x0 - x10, x16, x17, sp * --------------------------------------------- */ .macro plat_crash_print_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/rpi/rpi4/include/platform_def.h000066400000000000000000000073761355360272700237740ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include #include "rpi_hw.h" /* Special value used to verify platform parameters from BL2 to BL31 */ #define RPI3_BL31_PLAT_PARAM_VAL ULL(0x0F1E2D3C4B5A6978) #define PLATFORM_STACK_SIZE ULL(0x1000) #define PLATFORM_MAX_CPUS_PER_CLUSTER U(4) #define PLATFORM_CLUSTER_COUNT U(1) #define PLATFORM_CLUSTER0_CORE_COUNT PLATFORM_MAX_CPUS_PER_CLUSTER #define PLATFORM_CORE_COUNT PLATFORM_CLUSTER0_CORE_COUNT #define RPI4_PRIMARY_CPU U(0) #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL1 #define PLAT_NUM_PWR_DOMAINS (PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE U(2) /* Local power state for power domains in Run state. */ #define PLAT_LOCAL_STATE_RUN U(0) /* Local power state for retention. Valid only for CPU power domains */ #define PLAT_LOCAL_STATE_RET U(1) /* * Local power state for OFF/power-down. Valid for CPU and cluster power * domains. */ #define PLAT_LOCAL_STATE_OFF U(2) /* * Macros used to parse state information from State-ID if it is using the * recommended encoding for State-ID. */ #define PLAT_LOCAL_PSTATE_WIDTH U(4) #define PLAT_LOCAL_PSTATE_MASK ((U(1) << PLAT_LOCAL_PSTATE_WIDTH) - 1) /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. */ #define CACHE_WRITEBACK_SHIFT U(6) #define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT) /* * I/O registers. */ #define DEVICE0_BASE RPI_IO_BASE #define DEVICE0_SIZE RPI_IO_SIZE /* * Mailbox to control the secondary cores. All secondary cores are held in a * wait loop in cold boot. To release them perform the following steps (plus * any additional barriers that may be needed): * * uint64_t *entrypoint = (uint64_t *)PLAT_RPI3_TM_ENTRYPOINT; * *entrypoint = ADDRESS_TO_JUMP_TO; * * uint64_t *mbox_entry = (uint64_t *)PLAT_RPI3_TM_HOLD_BASE; * mbox_entry[cpu_id] = PLAT_RPI3_TM_HOLD_STATE_GO; * * sev(); */ /* The secure entry point to be used on warm reset by all CPUs. */ #define PLAT_RPI3_TM_ENTRYPOINT 0x100 #define PLAT_RPI3_TM_ENTRYPOINT_SIZE ULL(8) /* Hold entries for each CPU. */ #define PLAT_RPI3_TM_HOLD_BASE (PLAT_RPI3_TM_ENTRYPOINT + \ PLAT_RPI3_TM_ENTRYPOINT_SIZE) #define PLAT_RPI3_TM_HOLD_ENTRY_SIZE ULL(8) #define PLAT_RPI3_TM_HOLD_SIZE (PLAT_RPI3_TM_HOLD_ENTRY_SIZE * \ PLATFORM_CORE_COUNT) #define PLAT_RPI3_TRUSTED_MAILBOX_SIZE (PLAT_RPI3_TM_ENTRYPOINT_SIZE + \ PLAT_RPI3_TM_HOLD_SIZE) #define PLAT_RPI3_TM_HOLD_STATE_WAIT ULL(0) #define PLAT_RPI3_TM_HOLD_STATE_GO ULL(1) /* * BL31 specific defines. * * Put BL31 at the top of the Trusted SRAM. BL31_BASE is calculated using the * current BL31 debug size plus a little space for growth. */ #define PLAT_MAX_BL31_SIZE ULL(0x80000) #define BL31_BASE ULL(0x1000) #define BL31_LIMIT ULL(0x80000) #define BL31_PROGBITS_LIMIT ULL(0x80000) #define SEC_SRAM_ID 0 #define SEC_DRAM_ID 1 /* * Other memory-related defines. */ #define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32) #define MAX_MMAP_REGIONS 8 #define MAX_XLAT_TABLES 4 #define MAX_IO_DEVICES U(3) #define MAX_IO_HANDLES U(4) #define MAX_IO_BLOCK_DEVICES U(1) /* * Serial-related constants. */ #define PLAT_RPI3_UART_BASE RPI3_MINI_UART_BASE #define PLAT_RPI3_UART_BAUDRATE ULL(115200) /* * System counter */ #define SYS_COUNTER_FREQ_IN_TICKS ULL(54000000) #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/rpi/rpi4/include/rpi_hw.h000066400000000000000000000070131355360272700226060ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef RPI_HW_H #define RPI_HW_H #include /* * Peripherals */ #define RPI_IO_BASE ULL(0xFE000000) #define RPI_IO_SIZE ULL(0x02000000) /* * ARM <-> VideoCore mailboxes */ #define RPI3_MBOX_OFFSET ULL(0x0000B880) #define RPI3_MBOX_BASE (RPI_IO_BASE + RPI3_MBOX_OFFSET) /* VideoCore -> ARM */ #define RPI3_MBOX0_READ_OFFSET ULL(0x00000000) #define RPI3_MBOX0_PEEK_OFFSET ULL(0x00000010) #define RPI3_MBOX0_SENDER_OFFSET ULL(0x00000014) #define RPI3_MBOX0_STATUS_OFFSET ULL(0x00000018) #define RPI3_MBOX0_CONFIG_OFFSET ULL(0x0000001C) /* ARM -> VideoCore */ #define RPI3_MBOX1_WRITE_OFFSET ULL(0x00000020) #define RPI3_MBOX1_PEEK_OFFSET ULL(0x00000030) #define RPI3_MBOX1_SENDER_OFFSET ULL(0x00000034) #define RPI3_MBOX1_STATUS_OFFSET ULL(0x00000038) #define RPI3_MBOX1_CONFIG_OFFSET ULL(0x0000003C) /* Mailbox status constants */ #define RPI3_MBOX_STATUS_FULL_MASK U(0x80000000) /* Set if full */ #define RPI3_MBOX_STATUS_EMPTY_MASK U(0x40000000) /* Set if empty */ /* * Power management, reset controller, watchdog. */ #define RPI3_IO_PM_OFFSET ULL(0x00100000) #define RPI3_PM_BASE (RPI_IO_BASE + RPI3_IO_PM_OFFSET) /* Registers on top of RPI3_PM_BASE. */ #define RPI3_PM_RSTC_OFFSET ULL(0x0000001C) #define RPI3_PM_RSTS_OFFSET ULL(0x00000020) #define RPI3_PM_WDOG_OFFSET ULL(0x00000024) /* Watchdog constants */ #define RPI3_PM_PASSWORD U(0x5A000000) #define RPI3_PM_RSTC_WRCFG_MASK U(0x00000030) #define RPI3_PM_RSTC_WRCFG_FULL_RESET U(0x00000020) /* * The RSTS register is used by the VideoCore firmware when booting the * Raspberry Pi to know which partition to boot from. The partition value is * formed by bits 0, 2, 4, 6, 8 and 10. Partition 63 is used by said firmware * to indicate halt. */ #define RPI3_PM_RSTS_WRCFG_HALT U(0x00000555) /* * Clock controller */ #define RPI4_IO_CLOCK_OFFSET ULL(0x00101000) #define RPI4_CLOCK_BASE (RPI_IO_BASE + RPI4_IO_CLOCK_OFFSET) #define RPI4_VPU_CLOCK_DIVIDER ULL(0x0000000c) /* * Hardware random number generator. */ #define RPI3_IO_RNG_OFFSET ULL(0x00104000) #define RPI3_RNG_BASE (RPI_IO_BASE + RPI3_IO_RNG_OFFSET) #define RPI3_RNG_CTRL_OFFSET ULL(0x00000000) #define RPI3_RNG_STATUS_OFFSET ULL(0x00000004) #define RPI3_RNG_DATA_OFFSET ULL(0x00000008) #define RPI3_RNG_INT_MASK_OFFSET ULL(0x00000010) /* Enable/disable RNG */ #define RPI3_RNG_CTRL_ENABLE U(0x1) #define RPI3_RNG_CTRL_DISABLE U(0x0) /* Number of currently available words */ #define RPI3_RNG_STATUS_NUM_WORDS_SHIFT U(24) #define RPI3_RNG_STATUS_NUM_WORDS_MASK U(0xFF) /* Value to mask interrupts caused by the RNG */ #define RPI3_RNG_INT_MASK_DISABLE U(0x1) /* * Serial port (called 'Mini UART' in the Broadcom documentation). */ #define RPI3_IO_MINI_UART_OFFSET ULL(0x00215040) #define RPI3_MINI_UART_BASE (RPI_IO_BASE + RPI3_IO_MINI_UART_OFFSET) #define PLAT_RPI4_VPU_CLK_RATE ULL(1000000000) /* * GPIO controller */ #define RPI3_IO_GPIO_OFFSET ULL(0x00200000) #define RPI3_GPIO_BASE (RPI_IO_BASE + RPI3_IO_GPIO_OFFSET) /* * SDHost controller */ #define RPI3_IO_SDHOST_OFFSET ULL(0x00202000) #define RPI3_SDHOST_BASE (RPI_IO_BASE + RPI3_IO_SDHOST_OFFSET) /* * GIC interrupt controller */ #define RPI_HAVE_GIC #define RPI4_GIC_GICD_BASE ULL(0xff841000) #define RPI4_GIC_GICC_BASE ULL(0xff842000) #define RPI4_LOCAL_CONTROL_BASE_ADDRESS ULL(0xff800000) #define RPI4_LOCAL_CONTROL_PRESCALER ULL(0xff800008) #endif /* RPI_HW_H */ trusted-firmware-a-2.2/plat/rpi/rpi4/platform.mk000066400000000000000000000054251355360272700217040ustar00rootroot00000000000000# # Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # include lib/libfdt/libfdt.mk include lib/xlat_tables_v2/xlat_tables.mk PLAT_INCLUDES := -Iplat/rpi/common/include \ -Iplat/rpi/rpi4/include PLAT_BL_COMMON_SOURCES := drivers/ti/uart/aarch64/16550_console.S \ plat/rpi/common/rpi3_common.c \ ${XLAT_TABLES_LIB_SRCS} BL31_SOURCES += lib/cpus/aarch64/cortex_a72.S \ plat/rpi/rpi4/aarch64/plat_helpers.S \ plat/rpi/rpi4/aarch64/armstub8_header.S \ drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_helpers.c \ drivers/arm/gic/v2/gicv2_main.c \ plat/common/plat_gicv2.c \ plat/rpi/rpi4/rpi4_bl31_setup.c \ plat/rpi/common/rpi3_pm.c \ plat/common/plat_psci_common.c \ plat/rpi/common/rpi3_topology.c \ common/fdt_fixup.c \ ${LIBFDT_SRCS} # For now we only support BL31, using the kernel loaded by the GPU firmware. RESET_TO_BL31 := 1 # All CPUs enter armstub8.bin. COLD_BOOT_SINGLE_CPU := 0 # Tune compiler for Cortex-A72 ifeq ($(notdir $(CC)),armclang) TF_CFLAGS_aarch64 += -mcpu=cortex-a72 else ifneq ($(findstring clang,$(notdir $(CC))),) TF_CFLAGS_aarch64 += -mcpu=cortex-a72 else TF_CFLAGS_aarch64 += -mtune=cortex-a72 endif # Add support for platform supplied linker script for BL31 build $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) # Enable all errata workarounds for Cortex-A72 ERRATA_A72_859971 := 1 WORKAROUND_CVE_2017_5715 := 1 # Add new default target when compiling this platform all: bl31 # Build config flags # ------------------ # Disable stack protector by default ENABLE_STACK_PROTECTOR := 0 # Have different sections for code and rodata SEPARATE_CODE_AND_RODATA := 1 # Use Coherent memory USE_COHERENT_MEM := 1 # Platform build flags # -------------------- # There is not much else than a Linux kernel to load at the moment. RPI3_DIRECT_LINUX_BOOT := 1 # BL33 images are in AArch64 by default RPI3_BL33_IN_AARCH32 := 0 # UART to use at runtime. -1 means the runtime UART is disabled. # Any other value means the default UART will be used. RPI3_RUNTIME_UART := 0 # Use normal memory mapping for ROM, FIP, SRAM and DRAM RPI3_USE_UEFI_MAP := 0 # Process platform flags # ---------------------- $(eval $(call add_define,RPI3_BL33_IN_AARCH32)) $(eval $(call add_define,RPI3_DIRECT_LINUX_BOOT)) ifdef RPI3_PRELOADED_DTB_BASE $(eval $(call add_define,RPI3_PRELOADED_DTB_BASE)) endif $(eval $(call add_define,RPI3_RUNTIME_UART)) $(eval $(call add_define,RPI3_USE_UEFI_MAP)) ifeq (${ARCH},aarch32) $(error Error: AArch32 not supported on rpi4) endif ifneq ($(ENABLE_STACK_PROTECTOR), 0) PLAT_BL_COMMON_SOURCES += drivers/rpi3/rng/rpi3_rng.c \ plat/rpi/common/rpi3_stack_protector.c endif trusted-firmware-a-2.2/plat/rpi/rpi4/rpi4_bl31_setup.c000066400000000000000000000177771355360272700226270ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * Fields at the beginning of armstub8.bin. * While building the BL31 image, we put the stub magic into the binary. * The GPU firmware detects this at boot time, clears that field as a * confirmation and puts the kernel and DT address in the following words. */ extern uint32_t stub_magic; extern uint32_t dtb_ptr32; extern uint32_t kernel_entry32; static const gicv2_driver_data_t rpi4_gic_data = { .gicd_base = RPI4_GIC_GICD_BASE, .gicc_base = RPI4_GIC_GICC_BASE, }; /* * To be filled by the code below. At the moment BL32 is not supported. * In the future these might be passed down from BL2. */ static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for * the security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. ******************************************************************************/ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; assert(sec_state_is_valid(type) != 0); next_image_info = (type == NON_SECURE) ? &bl33_image_ep_info : &bl32_image_ep_info; /* None of the images can have 0x0 as the entrypoint. */ if (next_image_info->pc) { return next_image_info; } else { return NULL; } } uintptr_t plat_get_ns_image_entrypoint(void) { #ifdef PRELOADED_BL33_BASE return PRELOADED_BL33_BASE; #else /* Cleared by the GPU if kernel address is valid. */ if (stub_magic == 0) return kernel_entry32; WARN("Stub magic failure, using default kernel address 0x80000\n"); return 0x80000; #endif } static uintptr_t rpi4_get_dtb_address(void) { #ifdef RPI3_PRELOADED_DTB_BASE return RPI3_PRELOADED_DTB_BASE; #else /* Cleared by the GPU if DTB address is valid. */ if (stub_magic == 0) return dtb_ptr32; WARN("Stub magic failure, DTB address unknown\n"); return 0; #endif } static void ldelay(register_t delay) { __asm__ volatile ( "1:\tcbz %0, 2f\n\t" "sub %0, %0, #1\n\t" "b 1b\n" "2:" : "=&r" (delay) : "0" (delay) ); } /******************************************************************************* * Perform any BL31 early platform setup. Here is an opportunity to copy * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before * they are lost (potentially). This needs to be done before the MMU is * initialized so that the memory layout can be used while creating page * tables. BL2 has flushed this information to memory, so we are guaranteed * to pick up good data. ******************************************************************************/ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { uint32_t div_reg; /* * LOCAL_CONTROL: * Bit 9 clear: Increment by 1 (vs. 2). * Bit 8 clear: Timer source is 19.2MHz crystal (vs. APB). */ mmio_write_32(RPI4_LOCAL_CONTROL_BASE_ADDRESS, 0); /* LOCAL_PRESCALER; divide-by (0x80000000 / register_val) == 1 */ mmio_write_32(RPI4_LOCAL_CONTROL_PRESCALER, 0x80000000); /* Early GPU firmware revisions need a little break here. */ ldelay(100000); /* * Initialize the console to provide early debug support. * Different GPU firmware revisions set up the VPU divider differently, * so read the actual divider register to learn the UART base clock * rate. The divider is encoded as a 12.12 fixed point number, but we * just care about the integer part of it. */ div_reg = mmio_read_32(RPI4_CLOCK_BASE + RPI4_VPU_CLOCK_DIVIDER); div_reg = (div_reg >> 12) & 0xfff; if (div_reg == 0) div_reg = 1; rpi3_console_init(PLAT_RPI4_VPU_CLK_RATE / div_reg); bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); bl33_image_ep_info.spsr = rpi3_get_spsr_for_bl33_entry(); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); #if RPI3_DIRECT_LINUX_BOOT # if RPI3_BL33_IN_AARCH32 /* * According to the file ``Documentation/arm/Booting`` of the Linux * kernel tree, Linux expects: * r0 = 0 * r1 = machine type number, optional in DT-only platforms (~0 if so) * r2 = Physical address of the device tree blob */ VERBOSE("rpi4: Preparing to boot 32-bit Linux kernel\n"); bl33_image_ep_info.args.arg0 = 0U; bl33_image_ep_info.args.arg1 = ~0U; bl33_image_ep_info.args.arg2 = rpi4_get_dtb_address(); # else /* * According to the file ``Documentation/arm64/booting.txt`` of the * Linux kernel tree, Linux expects the physical address of the device * tree blob (DTB) in x0, while x1-x3 are reserved for future use and * must be 0. */ VERBOSE("rpi4: Preparing to boot 64-bit Linux kernel\n"); bl33_image_ep_info.args.arg0 = rpi4_get_dtb_address(); bl33_image_ep_info.args.arg1 = 0ULL; bl33_image_ep_info.args.arg2 = 0ULL; bl33_image_ep_info.args.arg3 = 0ULL; # endif /* RPI3_BL33_IN_AARCH32 */ #endif /* RPI3_DIRECT_LINUX_BOOT */ } void bl31_plat_arch_setup(void) { /* * Is the dtb_ptr32 pointer valid? If yes, map the DTB region. * We map the 2MB region the DTB start address lives in, plus * the next 2MB, to have enough room for expansion. */ if (stub_magic == 0) { unsigned long long dtb_region = dtb_ptr32; dtb_region &= ~0x1fffff; /* Align to 2 MB. */ mmap_add_region(dtb_region, dtb_region, 4U << 20, MT_MEMORY | MT_RW | MT_NS); } /* * Add the first page of memory, which holds the stub magic, * the kernel and the DT address. * This also holds the secondary CPU's entrypoints and mailboxes. */ mmap_add_region(0, 0, 4096, MT_NON_CACHEABLE | MT_RW | MT_SECURE); rpi3_setup_page_tables(BL31_BASE, BL31_END - BL31_BASE, BL_CODE_BASE, BL_CODE_END, BL_RO_DATA_BASE, BL_RO_DATA_END #if USE_COHERENT_MEM , BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END #endif ); enable_mmu_el3(0); } static uint32_t dtb_size(const void *dtb) { const uint32_t *dtb_header = dtb; return fdt32_to_cpu(dtb_header[1]); } static void rpi4_prepare_dtb(void) { void *dtb = (void *)rpi4_get_dtb_address(); uint32_t gic_int_prop[3]; int ret, offs; /* Return if no device tree is detected */ if (fdt_check_header(dtb) != 0) return; ret = fdt_open_into(dtb, dtb, 0x100000); if (ret < 0) { ERROR("Invalid Device Tree at %p: error %d\n", dtb, ret); return; } if (dt_add_psci_node(dtb)) { ERROR("Failed to add PSCI Device Tree node\n"); return; } if (dt_add_psci_cpu_enable_methods(dtb)) { ERROR("Failed to add PSCI cpu enable methods in Device Tree\n"); return; } /* Reserve memory used by Trusted Firmware. */ if (fdt_add_reserved_memory(dtb, "atf@0", 0, 0x80000)) WARN("Failed to add reserved memory nodes to DT.\n"); offs = fdt_node_offset_by_compatible(dtb, 0, "arm,gic-400"); gic_int_prop[0] = cpu_to_fdt32(1); // PPI gic_int_prop[1] = cpu_to_fdt32(9); // PPI #9 gic_int_prop[2] = cpu_to_fdt32(0x0f04); // all cores, level high fdt_setprop(dtb, offs, "interrupts", gic_int_prop, 12); offs = fdt_path_offset(dtb, "/chosen"); fdt_setprop_string(dtb, offs, "stdout-path", "serial0"); ret = fdt_pack(dtb); if (ret < 0) ERROR("Failed to pack Device Tree at %p: error %d\n", dtb, ret); clean_dcache_range((uintptr_t)dtb, dtb_size(dtb)); INFO("Changed device tree to advertise PSCI.\n"); } void bl31_platform_setup(void) { rpi4_prepare_dtb(); /* Configure the interrupt controller */ gicv2_driver_init(&rpi4_gic_data); gicv2_distif_init(); gicv2_pcpu_distif_init(); gicv2_cpuif_enable(); } trusted-firmware-a-2.2/plat/socionext/000077500000000000000000000000001355360272700200645ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/socionext/synquacer/000077500000000000000000000000001355360272700220765ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/socionext/synquacer/drivers/000077500000000000000000000000001355360272700235545ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/socionext/synquacer/drivers/mhu/000077500000000000000000000000001355360272700243455ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/socionext/synquacer/drivers/mhu/sq_mhu.c000066400000000000000000000042071355360272700260100ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "sq_mhu.h" /* SCP MHU secure channel registers */ #define SCP_INTR_S_STAT 0x200 #define SCP_INTR_S_SET 0x208 #define SCP_INTR_S_CLEAR 0x210 /* CPU MHU secure channel registers */ #define CPU_INTR_S_STAT 0x300 #define CPU_INTR_S_SET 0x308 #define CPU_INTR_S_CLEAR 0x310 DEFINE_BAKERY_LOCK(sq_lock); /* * Slot 31 is reserved because the MHU hardware uses this register bit to * indicate a non-secure access attempt. The total number of available slots is * therefore 31 [30:0]. */ #define MHU_MAX_SLOT_ID 30 void mhu_secure_message_start(unsigned int slot_id) { assert(slot_id <= MHU_MAX_SLOT_ID); bakery_lock_get(&sq_lock); /* Make sure any previous command has finished */ while (mmio_read_32(PLAT_SQ_MHU_BASE + CPU_INTR_S_STAT) & (1 << slot_id)) ; } void mhu_secure_message_send(unsigned int slot_id) { assert(slot_id <= MHU_MAX_SLOT_ID); assert(!(mmio_read_32(PLAT_SQ_MHU_BASE + CPU_INTR_S_STAT) & (1 << slot_id))); /* Send command to SCP */ mmio_write_32(PLAT_SQ_MHU_BASE + CPU_INTR_S_SET, 1 << slot_id); } uint32_t mhu_secure_message_wait(void) { uint32_t response; /* Wait for response from SCP */ while (!(response = mmio_read_32(PLAT_SQ_MHU_BASE + SCP_INTR_S_STAT))) ; return response; } void mhu_secure_message_end(unsigned int slot_id) { assert(slot_id <= MHU_MAX_SLOT_ID); /* * Clear any response we got by writing one in the relevant slot bit to * the CLEAR register */ mmio_write_32(PLAT_SQ_MHU_BASE + SCP_INTR_S_CLEAR, 1 << slot_id); bakery_lock_release(&sq_lock); } void mhu_secure_init(void) { bakery_lock_init(&sq_lock); /* * The STAT register resets to zero. Ensure it is in the expected state, * as a stale or garbage value would make us think it's a message we've * already sent. */ assert(mmio_read_32(PLAT_SQ_MHU_BASE + CPU_INTR_S_STAT) == 0); } void plat_sq_pwrc_setup(void) { mhu_secure_init(); } trusted-firmware-a-2.2/plat/socionext/synquacer/drivers/mhu/sq_mhu.h000066400000000000000000000006561355360272700260210ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SQ_MHU_H #define SQ_MHU_H #include void mhu_secure_message_start(unsigned int slot_id); void mhu_secure_message_send(unsigned int slot_id); uint32_t mhu_secure_message_wait(void); void mhu_secure_message_end(unsigned int slot_id); void mhu_secure_init(void); #endif /* SQ_MHU_H */ trusted-firmware-a-2.2/plat/socionext/synquacer/drivers/scp/000077500000000000000000000000001355360272700243415ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/socionext/synquacer/drivers/scp/sq_scmi.c000066400000000000000000000145541355360272700261540ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include /* * This file implements the SCP helper functions using SCMI protocol. */ DEFINE_BAKERY_LOCK(sq_scmi_lock); #define SQ_SCMI_LOCK_GET_INSTANCE (&sq_scmi_lock) #define SQ_SCMI_PAYLOAD_BASE PLAT_SQ_SCP_COM_SHARED_MEM_BASE #define MHU_CPU_INTR_S_SET_OFFSET 0x308 const uint32_t sq_core_pos_to_scmi_dmn_id_map[PLATFORM_CORE_COUNT] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; static scmi_channel_plat_info_t sq_scmi_plat_info = { .scmi_mbx_mem = SQ_SCMI_PAYLOAD_BASE, .db_reg_addr = PLAT_SQ_MHU_BASE + MHU_CPU_INTR_S_SET_OFFSET, .db_preserve_mask = 0xfffffffe, .db_modify_mask = 0x1, .ring_doorbell = &mhu_ring_doorbell, }; /* * SCMI power state parameter bit field encoding for SynQuacer platform. * * 31 20 19 16 15 12 11 8 7 4 3 0 * +-------------------------------------------------------------+ * | SBZ | Max level | Level 3 | Level 2 | Level 1 | Level 0 | * | | | state | state | state | state | * +-------------------------------------------------------------+ * * `Max level` encodes the highest level that has a valid power state * encoded in the power state. */ #define SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT 16 #define SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH 4 #define SCMI_PWR_STATE_MAX_PWR_LVL_MASK \ ((1 << SCMI_PWR_STATE_MAX_PWR_LVL_WIDTH) - 1) #define SCMI_SET_PWR_STATE_MAX_PWR_LVL(_power_state, _max_level) \ (_power_state) |= ((_max_level) & SCMI_PWR_STATE_MAX_PWR_LVL_MASK)\ << SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT #define SCMI_GET_PWR_STATE_MAX_PWR_LVL(_power_state) \ (((_power_state) >> SCMI_PWR_STATE_MAX_PWR_LVL_SHIFT) \ & SCMI_PWR_STATE_MAX_PWR_LVL_MASK) #define SCMI_PWR_STATE_LVL_WIDTH 4 #define SCMI_PWR_STATE_LVL_MASK \ ((1 << SCMI_PWR_STATE_LVL_WIDTH) - 1) #define SCMI_SET_PWR_STATE_LVL(_power_state, _level, _level_state) \ (_power_state) |= ((_level_state) & SCMI_PWR_STATE_LVL_MASK) \ << (SCMI_PWR_STATE_LVL_WIDTH * (_level)) #define SCMI_GET_PWR_STATE_LVL(_power_state, _level) \ (((_power_state) >> (SCMI_PWR_STATE_LVL_WIDTH * (_level))) & \ SCMI_PWR_STATE_LVL_MASK) /* * The SCMI power state enumeration for a power domain level */ typedef enum { scmi_power_state_off = 0, scmi_power_state_on = 1, scmi_power_state_sleep = 2, } scmi_power_state_t; /* * The global handle for invoking the SCMI driver APIs after the driver * has been initialized. */ static void *sq_scmi_handle; /* The SCMI channel global object */ static scmi_channel_t channel; /* * Helper function to turn off a CPU power domain and * its parent power domains if applicable. */ void sq_scmi_off(const struct psci_power_state *target_state) { int lvl = 0, ret; uint32_t scmi_pwr_state = 0; /* At-least the CPU level should be specified to be OFF */ assert(target_state->pwr_domain_state[SQ_PWR_LVL0] == SQ_LOCAL_STATE_OFF); for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) { if (target_state->pwr_domain_state[lvl] == SQ_LOCAL_STATE_RUN) break; assert(target_state->pwr_domain_state[lvl] == SQ_LOCAL_STATE_OFF); SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl, scmi_power_state_off); } SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1); ret = scmi_pwr_state_set(sq_scmi_handle, sq_core_pos_to_scmi_dmn_id_map[plat_my_core_pos()], scmi_pwr_state); if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) { ERROR("SCMI set power state command return 0x%x unexpected\n", ret); panic(); } } /* * Helper function to turn ON a CPU power domain and *its parent power domains if applicable. */ void sq_scmi_on(u_register_t mpidr) { int lvl = 0, ret, core_pos; uint32_t scmi_pwr_state = 0; for (; lvl <= PLAT_MAX_PWR_LVL; lvl++) SCMI_SET_PWR_STATE_LVL(scmi_pwr_state, lvl, scmi_power_state_on); SCMI_SET_PWR_STATE_MAX_PWR_LVL(scmi_pwr_state, lvl - 1); core_pos = plat_core_pos_by_mpidr(mpidr); assert(core_pos >= 0 && core_pos < PLATFORM_CORE_COUNT); ret = scmi_pwr_state_set(sq_scmi_handle, sq_core_pos_to_scmi_dmn_id_map[core_pos], scmi_pwr_state); if (ret != SCMI_E_QUEUED && ret != SCMI_E_SUCCESS) { ERROR("SCMI set power state command return 0x%x unexpected\n", ret); panic(); } } void __dead2 sq_scmi_system_off(int state) { int ret; /* * Disable GIC CPU interface to prevent pending interrupt from waking * up the AP from WFI. */ sq_gic_cpuif_disable(); /* * Issue SCMI command. First issue a graceful * request and if that fails force the request. */ ret = scmi_sys_pwr_state_set(sq_scmi_handle, SCMI_SYS_PWR_FORCEFUL_REQ, state); if (ret != SCMI_E_SUCCESS) { ERROR("SCMI system power state set 0x%x returns unexpected 0x%x\n", state, ret); panic(); } wfi(); ERROR("SCMI set power state: operation not handled.\n"); panic(); } /* * Helper function to reset the system via SCMI. */ void __dead2 sq_scmi_sys_reboot(void) { sq_scmi_system_off(SCMI_SYS_PWR_COLD_RESET); } static int scmi_ap_core_init(scmi_channel_t *ch) { #if PROGRAMMABLE_RESET_ADDRESS uint32_t version; int ret; ret = scmi_proto_version(ch, SCMI_AP_CORE_PROTO_ID, &version); if (ret != SCMI_E_SUCCESS) { WARN("SCMI AP core protocol version message failed\n"); return -1; } if (!is_scmi_version_compatible(SCMI_AP_CORE_PROTO_VER, version)) { WARN("SCMI AP core protocol version 0x%x incompatible with driver version 0x%x\n", version, SCMI_AP_CORE_PROTO_VER); return -1; } INFO("SCMI AP core protocol version 0x%x detected\n", version); #endif return 0; } void __init plat_sq_pwrc_setup(void) { channel.info = &sq_scmi_plat_info; channel.lock = SQ_SCMI_LOCK_GET_INSTANCE; sq_scmi_handle = scmi_init(&channel); if (sq_scmi_handle == NULL) { ERROR("SCMI Initialization failed\n"); panic(); } if (scmi_ap_core_init(&channel) < 0) { ERROR("SCMI AP core protocol initialization failed\n"); panic(); } } uint32_t sq_scmi_get_draminfo(struct draminfo *info) { scmi_get_draminfo(sq_scmi_handle, info); return 0; } trusted-firmware-a-2.2/plat/socionext/synquacer/drivers/scp/sq_scp.c000066400000000000000000000006051355360272700257760ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "sq_scpi.h" /* * Helper function to get dram information from SCP. */ uint32_t sq_scp_get_draminfo(struct draminfo *info) { #if SQ_USE_SCMI_DRIVER sq_scmi_get_draminfo(info); #else scpi_get_draminfo(info); #endif return 0; } trusted-firmware-a-2.2/plat/socionext/synquacer/drivers/scpi/000077500000000000000000000000001355360272700245125ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/socionext/synquacer/drivers/scpi/sq_scpi.c000066400000000000000000000125171355360272700263250ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "sq_mhu.h" #include "sq_scpi.h" #define SCPI_SHARED_MEM_SCP_TO_AP PLAT_SQ_SCP_COM_SHARED_MEM_BASE #define SCPI_SHARED_MEM_AP_TO_SCP (PLAT_SQ_SCP_COM_SHARED_MEM_BASE \ + 0x100) #define SCPI_CMD_HEADER_AP_TO_SCP \ ((scpi_cmd_t *) SCPI_SHARED_MEM_AP_TO_SCP) #define SCPI_CMD_PAYLOAD_AP_TO_SCP \ ((void *) (SCPI_SHARED_MEM_AP_TO_SCP + sizeof(scpi_cmd_t))) /* ID of the MHU slot used for the SCPI protocol */ #define SCPI_MHU_SLOT_ID 0 static void scpi_secure_message_start(void) { mhu_secure_message_start(SCPI_MHU_SLOT_ID); } static void scpi_secure_message_send(size_t payload_size) { /* * Ensure that any write to the SCPI payload area is seen by SCP before * we write to the MHU register. If these 2 writes were reordered by * the CPU then SCP would read stale payload data */ dmbst(); mhu_secure_message_send(SCPI_MHU_SLOT_ID); } static void scpi_secure_message_receive(scpi_cmd_t *cmd) { uint32_t mhu_status; assert(cmd != NULL); mhu_status = mhu_secure_message_wait(); /* Expect an SCPI message, reject any other protocol */ if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) { ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n", mhu_status); panic(); } /* * Ensure that any read to the SCPI payload area is done after reading * the MHU register. If these 2 reads were reordered then the CPU would * read invalid payload data */ dmbld(); memcpy(cmd, (void *) SCPI_SHARED_MEM_SCP_TO_AP, sizeof(*cmd)); } static void scpi_secure_message_end(void) { mhu_secure_message_end(SCPI_MHU_SLOT_ID); } int scpi_wait_ready(void) { scpi_cmd_t scpi_cmd; scpi_status_t status = SCP_OK; VERBOSE("Waiting for SCP_READY command...\n"); /* Get a message from the SCP */ scpi_secure_message_start(); scpi_secure_message_receive(&scpi_cmd); scpi_secure_message_end(); /* We are expecting 'SCP Ready', produce correct error if it's not */ if (scpi_cmd.id != SCPI_CMD_SCP_READY) { ERROR("Unexpected SCP command: expected command #%u," "got command #%u\n", SCPI_CMD_SCP_READY, scpi_cmd.id); status = SCP_E_SUPPORT; } else if (scpi_cmd.size != 0) { ERROR("SCP_READY command has incorrect size: expected 0," "got %u\n", scpi_cmd.size); status = SCP_E_SIZE; } VERBOSE("Sending response for SCP_READY command\n"); /* * Send our response back to SCP. * We are using the same SCPI header, just update the status field. */ scpi_cmd.status = status; scpi_secure_message_start(); memcpy((void *) SCPI_SHARED_MEM_AP_TO_SCP, &scpi_cmd, sizeof(scpi_cmd)); scpi_secure_message_send(0); scpi_secure_message_end(); return status == SCP_OK ? 0 : -1; } void scpi_set_sq_power_state(unsigned int mpidr, scpi_power_state_t cpu_state, scpi_power_state_t cluster_state, scpi_power_state_t sq_state) { scpi_cmd_t *cmd; uint32_t state = 0; uint32_t *payload_addr; state |= mpidr & 0x0f; /* CPU ID */ state |= (mpidr & 0xf00) >> 4; /* Cluster ID */ state |= cpu_state << 8; state |= cluster_state << 12; state |= sq_state << 16; scpi_secure_message_start(); /* Populate the command header */ cmd = SCPI_CMD_HEADER_AP_TO_SCP; cmd->id = SCPI_CMD_SET_POWER_STATE; cmd->set = SCPI_SET_NORMAL; cmd->sender = 0; cmd->size = sizeof(state); /* Populate the command payload */ payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP; *payload_addr = state; scpi_secure_message_send(sizeof(state)); /* * SCP does not reply to this command in order to avoid MHU interrupts * from the sender, which could interfere with its power state request. */ scpi_secure_message_end(); } uint32_t scpi_sys_power_state(scpi_system_state_t system_state) { scpi_cmd_t *cmd; uint8_t *payload_addr; scpi_cmd_t response; scpi_secure_message_start(); /* Populate the command header */ cmd = SCPI_CMD_HEADER_AP_TO_SCP; cmd->id = SCPI_CMD_SYS_POWER_STATE; cmd->set = 0; cmd->sender = 0; cmd->size = sizeof(*payload_addr); /* Populate the command payload */ payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP; *payload_addr = system_state & 0xff; scpi_secure_message_send(sizeof(*payload_addr)); scpi_secure_message_receive(&response); scpi_secure_message_end(); return response.status; } uint32_t scpi_get_draminfo(struct draminfo *info) { scpi_cmd_t *cmd; struct { scpi_cmd_t cmd; struct draminfo info; } response; uint32_t mhu_status; scpi_secure_message_start(); /* Populate the command header */ cmd = SCPI_CMD_HEADER_AP_TO_SCP; cmd->id = SCPI_CMD_GET_DRAMINFO; cmd->set = SCPI_SET_EXTENDED; cmd->sender = 0; cmd->size = 0; scpi_secure_message_send(0); mhu_status = mhu_secure_message_wait(); /* Expect an SCPI message, reject any other protocol */ if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) { ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n", mhu_status); panic(); } /* * Ensure that any read to the SCPI payload area is done after reading * the MHU register. If these 2 reads were reordered then the CPU would * read invalid payload data */ dmbld(); memcpy(&response, (void *)SCPI_SHARED_MEM_SCP_TO_AP, sizeof(response)); scpi_secure_message_end(); if (response.cmd.status == SCP_OK) *info = response.info; return response.cmd.status; } trusted-firmware-a-2.2/plat/socionext/synquacer/drivers/scpi/sq_scpi.h000066400000000000000000000042061355360272700263260ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SQ_SCPI_H #define SQ_SCPI_H #include #include /* * An SCPI command consists of a header and a payload. * The following structure describes the header. It is 64-bit long. */ typedef struct { /* Command ID */ uint32_t id : 7; /* Set ID. Identifies whether this is a standard or extended command. */ uint32_t set : 1; /* Sender ID to match a reply. The value is sender specific. */ uint32_t sender : 8; /* Size of the payload in bytes (0 - 511) */ uint32_t size : 9; uint32_t reserved : 7; /* * Status indicating the success of a command. * See the enum below. */ uint32_t status; } scpi_cmd_t; typedef enum { SCPI_SET_NORMAL = 0, /* Normal SCPI commands */ SCPI_SET_EXTENDED /* Extended SCPI commands */ } scpi_set_t; enum { SCP_OK = 0, /* Success */ SCP_E_PARAM, /* Invalid parameter(s) */ SCP_E_ALIGN, /* Invalid alignment */ SCP_E_SIZE, /* Invalid size */ SCP_E_HANDLER, /* Invalid handler or callback */ SCP_E_ACCESS, /* Invalid access or permission denied */ SCP_E_RANGE, /* Value out of range */ SCP_E_TIMEOUT, /* Time out has ocurred */ SCP_E_NOMEM, /* Invalid memory area or pointer */ SCP_E_PWRSTATE, /* Invalid power state */ SCP_E_SUPPORT, /* Feature not supported or disabled */ SCPI_E_DEVICE, /* Device error */ SCPI_E_BUSY, /* Device is busy */ }; typedef uint32_t scpi_status_t; typedef enum { SCPI_CMD_SCP_READY = 0x01, SCPI_CMD_SET_POWER_STATE = 0x03, SCPI_CMD_SYS_POWER_STATE = 0x05 } scpi_command_t; typedef enum { scpi_power_on = 0, scpi_power_retention = 1, scpi_power_off = 3, } scpi_power_state_t; typedef enum { scpi_system_shutdown = 0, scpi_system_reboot = 1, scpi_system_reset = 2 } scpi_system_state_t; extern int scpi_wait_ready(void); extern void scpi_set_sq_power_state(unsigned int mpidr, scpi_power_state_t cpu_state, scpi_power_state_t cluster_state, scpi_power_state_t css_state); uint32_t scpi_sys_power_state(scpi_system_state_t system_state); uint32_t scpi_get_draminfo(struct draminfo *info); #endif /* SQ_SCPI_H */ trusted-firmware-a-2.2/plat/socionext/synquacer/include/000077500000000000000000000000001355360272700235215ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/socionext/synquacer/include/plat.ld.S000066400000000000000000000013761355360272700252120ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SYNQUACER_PLAT_LD_S__ #define SYNQUACER_PLAT_LD_S__ #include #define SPM_SHIM_EXCEPTIONS_VMA SP_DRAM MEMORY { SP_DRAM (rw): ORIGIN = PLAT_SQ_SP_PRIV_BASE, LENGTH = PLAT_SQ_SP_PRIV_SIZE } SECTIONS { /* * Put the page tables in secure DRAM so that the PTW can make cacheable * accesses, as the core SPM code expects. (The SRAM on SynQuacer does * not support inner shareable WBWA mappings so it is mapped normal * non-cacheable) */ sp_xlat_table (NOLOAD) : ALIGN(PAGE_SIZE) { *(sp_xlat_table) *(.bss.sp_base_xlat_table) } >SP_DRAM } #endif /* SYNQUACER_PLAT_LD_S__ */ trusted-firmware-a-2.2/plat/socionext/synquacer/include/plat_macros.S000066400000000000000000000004121355360272700261460ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S /* * Print CCN registers */ .macro plat_crash_print_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/socionext/synquacer/include/platform_def.h000066400000000000000000000122461355360272700263410ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include /* CPU topology */ #define PLAT_MAX_CORES_PER_CLUSTER 2 #define PLAT_CLUSTER_COUNT 12 #define PLATFORM_CORE_COUNT (PLAT_CLUSTER_COUNT * \ PLAT_MAX_CORES_PER_CLUSTER) /* Macros to read the SQ power domain state */ #define SQ_PWR_LVL0 MPIDR_AFFLVL0 #define SQ_PWR_LVL1 MPIDR_AFFLVL1 #define SQ_PWR_LVL2 MPIDR_AFFLVL2 #define SQ_CORE_PWR_STATE(state) (state)->pwr_domain_state[SQ_PWR_LVL0] #define SQ_CLUSTER_PWR_STATE(state) (state)->pwr_domain_state[SQ_PWR_LVL1] #define SQ_SYSTEM_PWR_STATE(state) ((PLAT_MAX_PWR_LVL > SQ_PWR_LVL1) ?\ (state)->pwr_domain_state[SQ_PWR_LVL2] : 0) #define PLAT_MAX_PWR_LVL U(1) #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE U(2) #define SQ_LOCAL_STATE_RUN 0 #define SQ_LOCAL_STATE_RET 1 #define SQ_LOCAL_STATE_OFF 2 #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #define MAX_XLAT_TABLES 8 #define MAX_MMAP_REGIONS 8 #define PLATFORM_STACK_SIZE 0x400 #define BL31_BASE 0x04000000 #define BL31_SIZE 0x00080000 #define BL31_LIMIT (BL31_BASE + BL31_SIZE) #define BL32_BASE 0xfc000000 #define BL32_SIZE 0x03c00000 #define BL32_LIMIT (BL32_BASE + BL32_SIZE) #define PLAT_SQ_CCN_BASE 0x32000000 #define PLAT_SQ_CLUSTER_TO_CCN_ID_MAP \ 0, /* Cluster 0 */ \ 18, /* Cluster 1 */ \ 11, /* Cluster 2 */ \ 29, /* Cluster 3 */ \ 35, /* Cluster 4 */ \ 17, /* Cluster 5 */ \ 12, /* Cluster 6 */ \ 30, /* Cluster 7 */ \ 14, /* Cluster 8 */ \ 32, /* Cluster 9 */ \ 15, /* Cluster 10 */ \ 33 /* Cluster 11 */ /* UART related constants */ #define PLAT_SQ_BOOT_UART_BASE 0x2A400000 #define PLAT_SQ_BOOT_UART_CLK_IN_HZ 62500000 #define SQ_CONSOLE_BAUDRATE 115200 #define SQ_SYS_CNTCTL_BASE 0x2a430000 #define SQ_SYS_TIMCTL_BASE 0x2a810000 #define PLAT_SQ_NSTIMER_FRAME_ID 0 #define DRAMINFO_BASE 0x2E00FFC0 #define PLAT_SQ_MHU_BASE 0x45000000 #define PLAT_MHUV2_BASE 0xFFFFFFFF /* MHUV2 is not supported */ #define PLAT_SQ_SCP_COM_SHARED_MEM_BASE 0x45400000 #define SCPI_CMD_GET_DRAMINFO 0x1 #define SQ_BOOT_CFG_ADDR 0x45410000 #define PLAT_SQ_PRIMARY_CPU_SHIFT 8 #define PLAT_SQ_PRIMARY_CPU_BIT_WIDTH 6 #define PLAT_SQ_GICD_BASE 0x30000000 #define PLAT_SQ_GICR_BASE 0x30400000 #define PLAT_SQ_GPIO_BASE 0x51000000 #define PLAT_SPM_BUF_BASE (BL32_LIMIT - 32 * PLAT_SPM_BUF_SIZE) #define PLAT_SPM_BUF_SIZE ULL(0x10000) #define PLAT_SPM_SPM_BUF_EL0_MMAP MAP_REGION2(PLAT_SPM_BUF_BASE, \ PLAT_SPM_BUF_BASE, \ PLAT_SPM_BUF_SIZE, \ MT_RO_DATA | MT_SECURE | \ MT_USER, PAGE_SIZE) #define PLAT_SP_IMAGE_NS_BUF_BASE BL32_LIMIT #define PLAT_SP_IMAGE_NS_BUF_SIZE ULL(0x200000) #define PLAT_SP_IMAGE_NS_BUF_MMAP MAP_REGION2(PLAT_SP_IMAGE_NS_BUF_BASE, \ PLAT_SP_IMAGE_NS_BUF_BASE, \ PLAT_SP_IMAGE_NS_BUF_SIZE, \ MT_RW_DATA | MT_NS | \ MT_USER, PAGE_SIZE) #define PLAT_SP_IMAGE_STACK_PCPU_SIZE ULL(0x10000) #define PLAT_SP_IMAGE_STACK_SIZE (32 * PLAT_SP_IMAGE_STACK_PCPU_SIZE) #define PLAT_SP_IMAGE_STACK_BASE (PLAT_SQ_SP_HEAP_BASE + PLAT_SQ_SP_HEAP_SIZE) #define PLAT_SQ_SP_IMAGE_SIZE ULL(0x200000) #define PLAT_SQ_SP_IMAGE_MMAP MAP_REGION2(BL32_BASE, BL32_BASE, \ PLAT_SQ_SP_IMAGE_SIZE, \ MT_CODE | MT_SECURE | \ MT_USER, PAGE_SIZE) #define PLAT_SQ_SP_HEAP_BASE (BL32_BASE + PLAT_SQ_SP_IMAGE_SIZE) #define PLAT_SQ_SP_HEAP_SIZE ULL(0x800000) #define PLAT_SQ_SP_IMAGE_RW_MMAP MAP_REGION2(PLAT_SQ_SP_HEAP_BASE, \ PLAT_SQ_SP_HEAP_BASE, \ (PLAT_SQ_SP_HEAP_SIZE + \ PLAT_SP_IMAGE_STACK_SIZE), \ MT_RW_DATA | MT_SECURE | \ MT_USER, PAGE_SIZE) #define PLAT_SQ_SP_PRIV_BASE (PLAT_SP_IMAGE_STACK_BASE + \ PLAT_SP_IMAGE_STACK_SIZE) #define PLAT_SQ_SP_PRIV_SIZE ULL(0x40000) #define PLAT_SP_PRI 0x20 #define PLAT_PRI_BITS 2 #define PLAT_SPM_COOKIE_0 ULL(0) #define PLAT_SPM_COOKIE_1 ULL(0) /* Total number of memory regions with distinct properties */ #define PLAT_SP_IMAGE_NUM_MEM_REGIONS 6 #define PLAT_SP_IMAGE_MMAP_REGIONS 30 #define PLAT_SP_IMAGE_MAX_XLAT_TABLES 20 #define PLAT_SP_IMAGE_XLAT_SECTION_NAME "sp_xlat_table" #define PLAT_SQ_UART1_BASE PLAT_SQ_BOOT_UART_BASE #define PLAT_SQ_UART1_SIZE ULL(0x1000) #define PLAT_SQ_UART1_MMAP MAP_REGION_FLAT(PLAT_SQ_UART1_BASE, \ PLAT_SQ_UART1_SIZE, \ MT_DEVICE | MT_RW | \ MT_NS | MT_PRIVILEGED) #define PLAT_SQ_PERIPH_BASE 0x50000000 #define PLAT_SQ_PERIPH_SIZE ULL(0x8000000) #define PLAT_SQ_PERIPH_MMAP MAP_REGION_FLAT(PLAT_SQ_PERIPH_BASE, \ PLAT_SQ_PERIPH_SIZE, \ MT_DEVICE | MT_RW | \ MT_NS | MT_USER) #define PLAT_SQ_FLASH_BASE 0x08000000 #define PLAT_SQ_FLASH_SIZE ULL(0x8000000) #define PLAT_SQ_FLASH_MMAP MAP_REGION_FLAT(PLAT_SQ_FLASH_BASE, \ PLAT_SQ_FLASH_SIZE, \ MT_DEVICE | MT_RW | \ MT_NS | MT_USER) #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/socionext/synquacer/include/sq_common.h000066400000000000000000000024241355360272700256670ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SQ_COMMON_H #define SQ_COMMON_H #include #include #include struct draminfo { uint32_t num_regions; uint32_t reserved; uint64_t base1; uint64_t size1; uint64_t base2; uint64_t size2; uint64_t base3; uint64_t size3; }; uint32_t sq_scp_get_draminfo(struct draminfo *info); void plat_sq_pwrc_setup(void); void plat_sq_interconnect_init(void); void plat_sq_interconnect_enter_coherency(void); void plat_sq_interconnect_exit_coherency(void); unsigned int sq_calc_core_pos(u_register_t mpidr); void sq_gic_driver_init(void); void sq_gic_init(void); void sq_gic_cpuif_enable(void); void sq_gic_cpuif_disable(void); void sq_gic_pcpu_init(void); void sq_mmap_setup(uintptr_t total_base, size_t total_size, const struct mmap_region *mmap); /* SCMI API for power management by SCP */ void sq_scmi_off(const struct psci_power_state *target_state); void sq_scmi_on(u_register_t mpidr); void __dead2 sq_scmi_sys_reboot(void); void __dead2 sq_scmi_system_off(int state); /* SCMI API for vendor specific protocol */ uint32_t sq_scmi_get_draminfo(struct draminfo *info); #endif /* SQ_COMMON_H */ trusted-firmware-a-2.2/plat/socionext/synquacer/platform.mk000066400000000000000000000037641355360272700242650ustar00rootroot00000000000000# # Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # override RESET_TO_BL31 := 1 override PROGRAMMABLE_RESET_ADDRESS := 1 override USE_COHERENT_MEM := 1 override SEPARATE_CODE_AND_RODATA := 1 override ENABLE_SVE_FOR_NS := 0 # Enable workarounds for selected Cortex-A53 erratas. ERRATA_A53_855873 := 1 # Enable SCMI support SQ_USE_SCMI_DRIVER ?= 0 # Libraries include lib/xlat_tables_v2/xlat_tables.mk PLAT_PATH := plat/socionext/synquacer PLAT_INCLUDES := -I$(PLAT_PATH)/include \ -I$(PLAT_PATH)/drivers/scpi \ -I$(PLAT_PATH)/drivers/mhu \ -Idrivers/arm/css/scmi \ -Idrivers/arm/css/scmi/vendor PLAT_BL_COMMON_SOURCES += $(PLAT_PATH)/sq_helpers.S \ drivers/arm/pl011/aarch64/pl011_console.S \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ ${XLAT_TABLES_LIB_SRCS} BL31_SOURCES += drivers/arm/ccn/ccn.c \ drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v3/gicv3_helpers.c \ drivers/arm/gic/v3/gicv3_main.c \ lib/cpus/aarch64/cortex_a53.S \ plat/common/plat_gicv3.c \ plat/common/plat_psci_common.c \ $(PLAT_PATH)/sq_bl31_setup.c \ $(PLAT_PATH)/sq_ccn.c \ $(PLAT_PATH)/sq_topology.c \ $(PLAT_PATH)/sq_psci.c \ $(PLAT_PATH)/sq_gicv3.c \ $(PLAT_PATH)/sq_xlat_setup.c \ $(PLAT_PATH)/drivers/scp/sq_scp.c ifeq (${SQ_USE_SCMI_DRIVER},0) BL31_SOURCES += $(PLAT_PATH)/drivers/scpi/sq_scpi.c \ $(PLAT_PATH)/drivers/mhu/sq_mhu.c else BL31_SOURCES += $(PLAT_PATH)/drivers/scp/sq_scmi.c \ drivers/arm/css/scmi/scmi_common.c \ drivers/arm/css/scmi/scmi_pwr_dmn_proto.c \ drivers/arm/css/scmi/scmi_sys_pwr_proto.c \ drivers/arm/css/scmi/vendor/scmi_sq.c \ drivers/arm/css/mhu/css_mhu_doorbell.c endif ifeq (${ENABLE_SPM},1) $(eval $(call add_define,PLAT_EXTRA_LD_SCRIPT)) BL31_SOURCES += $(PLAT_PATH)/sq_spm.c endif ifeq (${SQ_USE_SCMI_DRIVER},1) $(eval $(call add_define,SQ_USE_SCMI_DRIVER)) endif trusted-firmware-a-2.2/plat/socionext/synquacer/sq_bl31_setup.c000066400000000000000000000130021355360272700247220ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include static console_pl011_t console; static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_START__, SPM_SHIM_EXCEPTIONS_START); IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_END__, SPM_SHIM_EXCEPTIONS_END); IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_LMA__, SPM_SHIM_EXCEPTIONS_LMA); entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { assert(sec_state_is_valid(type)); return type == NON_SECURE ? &bl33_image_ep_info : &bl32_image_ep_info; } /******************************************************************************* * Gets SPSR for BL32 entry ******************************************************************************/ uint32_t sq_get_spsr_for_bl32_entry(void) { /* * The Secure Payload Dispatcher service is responsible for * setting the SPSR prior to entry into the BL32 image. */ return 0; } /******************************************************************************* * Gets SPSR for BL33 entry ******************************************************************************/ uint32_t sq_get_spsr_for_bl33_entry(void) { unsigned long el_status; unsigned int mode; uint32_t spsr; /* Figure out what mode we enter the non-secure world in */ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; el_status &= ID_AA64PFR0_ELX_MASK; mode = (el_status) ? MODE_EL2 : MODE_EL1; spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; } void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { /* Initialize the console to provide early debug support */ (void)console_pl011_register(PLAT_SQ_BOOT_UART_BASE, PLAT_SQ_BOOT_UART_CLK_IN_HZ, SQ_CONSOLE_BAUDRATE, &console); console_set_scope(&console.console, CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME); /* There are no parameters from BL2 if BL31 is a reset vector */ assert(arg0 == 0U); assert(arg1 == 0U); /* Initialize power controller before setting up topology */ plat_sq_pwrc_setup(); #ifdef SPD_opteed struct draminfo di = {0}; sq_scp_get_draminfo(&di); /* * Check if OP-TEE has been loaded in Secure RAM allocated * from DRAM1 region */ if ((di.base1 + di.size1) <= BL32_BASE) { NOTICE("OP-TEE has been loaded by SCP firmware\n"); /* Populate entry point information for BL32 */ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0); SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); bl32_image_ep_info.pc = BL32_BASE; bl32_image_ep_info.spsr = sq_get_spsr_for_bl32_entry(); } else { NOTICE("OP-TEE has not been loaded by SCP firmware\n"); } #endif /* SPD_opteed */ /* Populate entry point information for BL33 */ SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); /* * Tell BL31 where the non-trusted software image * is located and the entry state information */ bl33_image_ep_info.pc = PRELOADED_BL33_BASE; bl33_image_ep_info.spsr = sq_get_spsr_for_bl33_entry(); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); } static void sq_configure_sys_timer(void) { unsigned int reg_val; reg_val = (1 << CNTACR_RPCT_SHIFT) | (1 << CNTACR_RVCT_SHIFT); reg_val |= (1 << CNTACR_RFRQ_SHIFT) | (1 << CNTACR_RVOFF_SHIFT); reg_val |= (1 << CNTACR_RWVT_SHIFT) | (1 << CNTACR_RWPT_SHIFT); mmio_write_32(SQ_SYS_TIMCTL_BASE + CNTACR_BASE(PLAT_SQ_NSTIMER_FRAME_ID), reg_val); reg_val = (1 << CNTNSAR_NS_SHIFT(PLAT_SQ_NSTIMER_FRAME_ID)); mmio_write_32(SQ_SYS_TIMCTL_BASE + CNTNSAR, reg_val); } void bl31_platform_setup(void) { /* Initialize the CCN interconnect */ plat_sq_interconnect_init(); plat_sq_interconnect_enter_coherency(); /* Initialize the GIC driver, cpu and distributor interfaces */ sq_gic_driver_init(); sq_gic_init(); /* Enable and initialize the System level generic timer */ mmio_write_32(SQ_SYS_CNTCTL_BASE + CNTCR_OFF, CNTCR_FCREQ(0U) | CNTCR_EN); /* Allow access to the System counter timer module */ sq_configure_sys_timer(); } void bl31_plat_runtime_setup(void) { struct draminfo *di = (struct draminfo *)(unsigned long)DRAMINFO_BASE; sq_scp_get_draminfo(di); } void bl31_plat_arch_setup(void) { static const mmap_region_t secure_partition_mmap[] = { #if ENABLE_SPM && SPM_MM MAP_REGION_FLAT(PLAT_SPM_BUF_BASE, PLAT_SPM_BUF_SIZE, MT_RW_DATA | MT_SECURE), MAP_REGION_FLAT(PLAT_SQ_SP_PRIV_BASE, PLAT_SQ_SP_PRIV_SIZE, MT_RW_DATA | MT_SECURE), #endif {0}, }; sq_mmap_setup(BL31_BASE, BL31_SIZE, secure_partition_mmap); enable_mmu_el3(XLAT_TABLE_NC); #if ENABLE_SPM && SPM_MM memcpy((void *)SPM_SHIM_EXCEPTIONS_START, (void *)SPM_SHIM_EXCEPTIONS_LMA, (uintptr_t)SPM_SHIM_EXCEPTIONS_END - (uintptr_t)SPM_SHIM_EXCEPTIONS_START); #endif } void bl31_plat_enable_mmu(uint32_t flags) { enable_mmu_el3(flags | XLAT_TABLE_NC); } unsigned int plat_get_syscnt_freq2(void) { unsigned int counter_base_frequency; /* Read the frequency from Frequency modes table */ counter_base_frequency = mmio_read_32(SQ_SYS_CNTCTL_BASE + CNTFID_OFF); /* The first entry of the frequency modes table must not be 0 */ if (counter_base_frequency == 0) panic(); return counter_base_frequency; } trusted-firmware-a-2.2/plat/socionext/synquacer/sq_ccn.c000066400000000000000000000026421355360272700235140ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include static const unsigned char master_to_rn_id_map[] = { PLAT_SQ_CLUSTER_TO_CCN_ID_MAP }; static const ccn_desc_t sq_ccn_desc = { .periphbase = PLAT_SQ_CCN_BASE, .num_masters = ARRAY_SIZE(master_to_rn_id_map), .master_to_rn_id_map = master_to_rn_id_map }; /****************************************************************************** * Helper function to initialize SQ CCN driver. *****************************************************************************/ void plat_sq_interconnect_init(void) { ccn_init(&sq_ccn_desc); } /****************************************************************************** * Helper function to place current master into coherency *****************************************************************************/ void plat_sq_interconnect_enter_coherency(void) { ccn_enter_snoop_dvm_domain(1 << MPIDR_AFFLVL1_VAL(read_mpidr_el1())); } /****************************************************************************** * Helper function to remove current master from coherency *****************************************************************************/ void plat_sq_interconnect_exit_coherency(void) { ccn_exit_snoop_dvm_domain(1 << MPIDR_AFFLVL1_VAL(read_mpidr_el1())); } trusted-firmware-a-2.2/plat/socionext/synquacer/sq_gicv3.c000066400000000000000000000042561355360272700237670ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "sq_common.h" static uintptr_t sq_rdistif_base_addrs[PLATFORM_CORE_COUNT]; static const interrupt_prop_t sq_interrupt_props[] = { /* G0 interrupts */ /* SGI0 */ INTR_PROP_DESC(8, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0, GIC_INTR_CFG_EDGE), /* SGI6 */ INTR_PROP_DESC(14, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0, GIC_INTR_CFG_EDGE), /* G1S interrupts */ /* Timer */ INTR_PROP_DESC(29, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_LEVEL), /* SGI1 */ INTR_PROP_DESC(9, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_EDGE), /* SGI2 */ INTR_PROP_DESC(10, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_EDGE), /* SGI3 */ INTR_PROP_DESC(11, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_EDGE), /* SGI4 */ INTR_PROP_DESC(12, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_EDGE), /* SGI5 */ INTR_PROP_DESC(13, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_EDGE), /* SGI7 */ INTR_PROP_DESC(15, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_EDGE) }; static unsigned int sq_mpidr_to_core_pos(u_register_t mpidr) { return plat_core_pos_by_mpidr(mpidr); } static const struct gicv3_driver_data sq_gic_driver_data = { .gicd_base = PLAT_SQ_GICD_BASE, .gicr_base = PLAT_SQ_GICR_BASE, .interrupt_props = sq_interrupt_props, .interrupt_props_num = ARRAY_SIZE(sq_interrupt_props), .rdistif_num = PLATFORM_CORE_COUNT, .rdistif_base_addrs = sq_rdistif_base_addrs, .mpidr_to_core_pos = sq_mpidr_to_core_pos, }; void sq_gic_driver_init(void) { gicv3_driver_init(&sq_gic_driver_data); } void sq_gic_init(void) { gicv3_distif_init(); gicv3_rdistif_init(plat_my_core_pos()); gicv3_cpuif_enable(plat_my_core_pos()); } void sq_gic_cpuif_enable(void) { gicv3_cpuif_enable(plat_my_core_pos()); } void sq_gic_cpuif_disable(void) { gicv3_cpuif_disable(plat_my_core_pos()); } void sq_gic_pcpu_init(void) { gicv3_rdistif_init(plat_my_core_pos()); } trusted-firmware-a-2.2/plat/socionext/synquacer/sq_helpers.S000066400000000000000000000052261355360272700243740ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .global sq_calc_core_pos .global plat_my_core_pos .global platform_mem_init .global plat_is_my_cpu_primary .global plat_secondary_cold_boot_setup .global plat_crash_console_init .global plat_crash_console_putc .global plat_crash_console_flush /* * unsigned int sq_calc_core_pos(u_register_t mpidr) * core_pos = (cluster_id * max_cpus_per_cluster) + core_id */ func sq_calc_core_pos and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, lsr #7 ret endfunc sq_calc_core_pos func plat_my_core_pos mrs x0, mpidr_el1 b sq_calc_core_pos endfunc plat_my_core_pos func platform_mem_init ret endfunc platform_mem_init /* * Secondary CPUs are placed in a holding pen, waiting for their mailbox * to be populated. Note that all CPUs share the same mailbox ; therefore, * populating it will release all CPUs from their holding pen. If * finer-grained control is needed then this should be handled in the * code that secondary CPUs jump to. */ func plat_secondary_cold_boot_setup ldr x0, sq_sec_entrypoint /* Wait until the mailbox gets populated */ poll_mailbox: cbz x0, 1f br x0 1: wfe b poll_mailbox endfunc plat_secondary_cold_boot_setup /* * Find out whether the current cpu is the primary * cpu (applicable only after a cold boot) */ func plat_is_my_cpu_primary mov x9, x30 bl plat_my_core_pos ldr x1, =SQ_BOOT_CFG_ADDR ldr x1, [x1] ubfx x1, x1, #PLAT_SQ_PRIMARY_CPU_SHIFT, \ #PLAT_SQ_PRIMARY_CPU_BIT_WIDTH cmp x0, x1 cset w0, eq ret x9 endfunc plat_is_my_cpu_primary /* * int plat_crash_console_init(void) * Function to initialize the crash console * without a C Runtime to print crash report. * Clobber list : x0, x1, x2 */ func plat_crash_console_init mov_imm x0, PLAT_SQ_BOOT_UART_BASE mov_imm x1, PLAT_SQ_BOOT_UART_CLK_IN_HZ mov_imm x2, SQ_CONSOLE_BAUDRATE b console_pl011_core_init endfunc plat_crash_console_init /* * int plat_crash_console_putc(int c) * Function to print a character on the crash * console without a C Runtime. * Clobber list : x1, x2 */ func plat_crash_console_putc mov_imm x1, PLAT_SQ_BOOT_UART_BASE b console_pl011_core_putc endfunc plat_crash_console_putc /* * int plat_crash_console_flush(int c) * Function to force a write of all buffered * data that hasn't been output. * Out : return -1 on error else return 0. * Clobber list : x0, x1 */ func plat_crash_console_flush mov_imm x0, PLAT_SQ_BOOT_UART_BASE b console_pl011_core_flush endfunc plat_crash_console_flush trusted-firmware-a-2.2/plat/socionext/synquacer/sq_psci.c000066400000000000000000000104271355360272700237070ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "sq_scpi.h" uintptr_t sq_sec_entrypoint; int sq_pwr_domain_on(u_register_t mpidr) { #if SQ_USE_SCMI_DRIVER sq_scmi_on(mpidr); #else /* * SCP takes care of powering up parent power domains so we * only need to care about level 0 */ scpi_set_sq_power_state(mpidr, scpi_power_on, scpi_power_on, scpi_power_on); #endif return PSCI_E_SUCCESS; } static void sq_pwr_domain_on_finisher_common( const psci_power_state_t *target_state) { assert(SQ_CORE_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF); /* * Perform the common cluster specific operations i.e enable coherency * if this cluster was off. */ if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) plat_sq_interconnect_enter_coherency(); } void sq_pwr_domain_on_finish(const psci_power_state_t *target_state) { /* Assert that the system power domain need not be initialized */ assert(SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_RUN); sq_pwr_domain_on_finisher_common(target_state); /* Program the gic per-cpu distributor or re-distributor interface */ sq_gic_pcpu_init(); /* Enable the gic cpu interface */ sq_gic_cpuif_enable(); } #if !SQ_USE_SCMI_DRIVER static void sq_power_down_common(const psci_power_state_t *target_state) { uint32_t cluster_state = scpi_power_on; uint32_t system_state = scpi_power_on; /* Prevent interrupts from spuriously waking up this cpu */ sq_gic_cpuif_disable(); /* Check if power down at system power domain level is requested */ if (SQ_SYSTEM_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) system_state = scpi_power_retention; /* Cluster is to be turned off, so disable coherency */ if (SQ_CLUSTER_PWR_STATE(target_state) == SQ_LOCAL_STATE_OFF) { plat_sq_interconnect_exit_coherency(); cluster_state = scpi_power_off; } /* * Ask the SCP to power down the appropriate components depending upon * their state. */ scpi_set_sq_power_state(read_mpidr_el1(), scpi_power_off, cluster_state, system_state); } #endif void sq_pwr_domain_off(const psci_power_state_t *target_state) { #if SQ_USE_SCMI_DRIVER sq_scmi_off(target_state); #else sq_power_down_common(target_state); #endif } void __dead2 sq_system_off(void) { volatile uint32_t *gpio = (uint32_t *)PLAT_SQ_GPIO_BASE; /* set PD[9] high to power off the system */ gpio[5] |= 0x2; /* set output */ gpio[1] |= 0x2; /* set high */ dmbst(); generic_delay_timer_init(); mdelay(1); while (1) { gpio[1] &= ~0x2; /* set low */ dmbst(); mdelay(1); gpio[1] |= 0x2; /* set high */ dmbst(); mdelay(100); } wfi(); ERROR("SQ System Off: operation not handled.\n"); panic(); } void __dead2 sq_system_reset(void) { #if SQ_USE_SCMI_DRIVER sq_scmi_sys_reboot(); #else uint32_t response; /* Send the system reset request to the SCP */ response = scpi_sys_power_state(scpi_system_reboot); if (response != SCP_OK) { ERROR("SQ System Reset: SCP error %u.\n", response); panic(); } wfi(); ERROR("SQ System Reset: operation not handled.\n"); panic(); #endif } void sq_cpu_standby(plat_local_state_t cpu_state) { unsigned int scr; assert(cpu_state == SQ_LOCAL_STATE_RET); scr = read_scr_el3(); /* Enable PhysicalIRQ bit for NS world to wake the CPU */ write_scr_el3(scr | SCR_IRQ_BIT); isb(); dsb(); wfi(); /* * Restore SCR to the original value, synchronisation of scr_el3 is * done by eret while el3_exit to save some execution cycles. */ write_scr_el3(scr); } const plat_psci_ops_t sq_psci_ops = { .pwr_domain_on = sq_pwr_domain_on, .pwr_domain_off = sq_pwr_domain_off, .pwr_domain_on_finish = sq_pwr_domain_on_finish, .cpu_standby = sq_cpu_standby, .system_off = sq_system_off, .system_reset = sq_system_reset, }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const struct plat_psci_ops **psci_ops) { sq_sec_entrypoint = sec_entrypoint; flush_dcache_range((uint64_t)&sq_sec_entrypoint, sizeof(sq_sec_entrypoint)); *psci_ops = &sq_psci_ops; return 0; } trusted-firmware-a-2.2/plat/socionext/synquacer/sq_spm.c000066400000000000000000000045221355360272700235470ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include static const mmap_region_t plat_arm_secure_partition_mmap[] = { PLAT_SQ_FLASH_MMAP, PLAT_SQ_UART1_MMAP, PLAT_SQ_PERIPH_MMAP, PLAT_SQ_SP_IMAGE_MMAP, PLAT_SP_IMAGE_NS_BUF_MMAP, PLAT_SQ_SP_IMAGE_RW_MMAP, PLAT_SPM_SPM_BUF_EL0_MMAP, {0} }; /* * Boot information passed to a secure partition during initialisation. Linear * indices in MP information will be filled at runtime. */ static secure_partition_mp_info_t sp_mp_info[] = { {0x80000000, 0}, {0x80000001, 0}, {0x80000100, 0}, {0x80000101, 0}, {0x80000200, 0}, {0x80000201, 0}, {0x80000300, 0}, {0x80000301, 0}, {0x80000400, 0}, {0x80000401, 0}, {0x80000500, 0}, {0x80000501, 0}, {0x80000600, 0}, {0x80000601, 0}, {0x80000700, 0}, {0x80000701, 0}, {0x80000800, 0}, {0x80000801, 0}, {0x80000900, 0}, {0x80000901, 0}, {0x80000a00, 0}, {0x80000a01, 0}, {0x80000b00, 0}, {0x80000b01, 0}, }; const secure_partition_boot_info_t plat_arm_secure_partition_boot_info = { .h.type = PARAM_SP_IMAGE_BOOT_INFO, .h.version = VERSION_1, .h.size = sizeof(secure_partition_boot_info_t), .h.attr = 0, .sp_mem_base = BL32_BASE, .sp_mem_limit = BL32_LIMIT, .sp_image_base = BL32_BASE, .sp_stack_base = PLAT_SP_IMAGE_STACK_BASE, .sp_heap_base = PLAT_SQ_SP_HEAP_BASE, .sp_ns_comm_buf_base = PLAT_SP_IMAGE_NS_BUF_BASE, .sp_shared_buf_base = PLAT_SPM_BUF_BASE, .sp_image_size = PLAT_SQ_SP_IMAGE_SIZE, .sp_pcpu_stack_size = PLAT_SP_IMAGE_STACK_PCPU_SIZE, .sp_heap_size = PLAT_SQ_SP_HEAP_SIZE, .sp_ns_comm_buf_size = PLAT_SP_IMAGE_NS_BUF_SIZE, .sp_shared_buf_size = PLAT_SPM_BUF_SIZE, .num_sp_mem_regions = PLAT_SP_IMAGE_NUM_MEM_REGIONS, .num_cpus = PLATFORM_CORE_COUNT, .mp_info = sp_mp_info, }; const struct mmap_region *plat_get_secure_partition_mmap(void *cookie) { return plat_arm_secure_partition_mmap; } const struct secure_partition_boot_info *plat_get_secure_partition_boot_info( void *cookie) { return &plat_arm_secure_partition_boot_info; } static ehf_pri_desc_t sq_exceptions[] = { EHF_PRI_DESC(PLAT_PRI_BITS, PLAT_SP_PRI), }; EHF_REGISTER_PRIORITIES(sq_exceptions, ARRAY_SIZE(sq_exceptions), PLAT_PRI_BITS); trusted-firmware-a-2.2/plat/socionext/synquacer/sq_topology.c000066400000000000000000000015121355360272700246200ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include unsigned char sq_pd_tree_desc[PLAT_CLUSTER_COUNT + 1]; int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; if (cluster_id >= PLAT_CLUSTER_COUNT) return -1; cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; if (cpu_id >= PLAT_MAX_CORES_PER_CLUSTER) return -1; return sq_calc_core_pos(mpidr); } const unsigned char *plat_get_power_domain_tree_desc(void) { int i; sq_pd_tree_desc[0] = PLAT_CLUSTER_COUNT; for (i = 0; i < PLAT_CLUSTER_COUNT; i++) sq_pd_tree_desc[i + 1] = PLAT_MAX_CORES_PER_CLUSTER; return sq_pd_tree_desc; } trusted-firmware-a-2.2/plat/socionext/synquacer/sq_xlat_setup.c000066400000000000000000000032421355360272700251360ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #define SQ_REG_REGION_BASE 0x20000000ULL #define SQ_REG_REGION_SIZE 0x60000000ULL void sq_mmap_setup(uintptr_t total_base, size_t total_size, const struct mmap_region *mmap) { VERBOSE("Trusted RAM seen by this BL image: %p - %p\n", (void *)total_base, (void *)(total_base + total_size)); mmap_add_region(total_base, total_base, total_size, MT_NON_CACHEABLE | MT_RW | MT_SECURE); /* remap the code section */ VERBOSE("Code region: %p - %p\n", (void *)BL_CODE_BASE, (void *)BL_CODE_END); mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, round_up(BL_CODE_END, PAGE_SIZE) - BL_CODE_BASE, MT_NON_CACHEABLE | MT_RO | MT_SECURE); /* Re-map the read-only data section */ VERBOSE("Read-only data region: %p - %p\n", (void *)BL_RO_DATA_BASE, (void *)BL_RO_DATA_END); mmap_add_region(BL_RO_DATA_BASE, BL_RO_DATA_BASE, round_up(BL_RO_DATA_END, PAGE_SIZE) - BL_RO_DATA_BASE, (MT_NON_CACHEABLE | MT_RO | MT_EXECUTE_NEVER | MT_SECURE)); /* remap the coherent memory region */ VERBOSE("Coherent region: %p - %p\n", (void *)BL_COHERENT_RAM_BASE, (void *)BL_COHERENT_RAM_END); mmap_add_region(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, MT_DEVICE | MT_RW | MT_SECURE); /* register region */ mmap_add_region(SQ_REG_REGION_BASE, SQ_REG_REGION_BASE, SQ_REG_REGION_SIZE, MT_DEVICE | MT_RW | MT_SECURE); /* additional regions if needed */ if (mmap) mmap_add(mmap); init_xlat_tables(); } trusted-firmware-a-2.2/plat/socionext/uniphier/000077500000000000000000000000001355360272700217075ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/socionext/uniphier/include/000077500000000000000000000000001355360272700233325ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/socionext/uniphier/include/plat_macros.S000066400000000000000000000003541355360272700257640ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S .macro plat_crash_print_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/socionext/uniphier/include/platform_def.h000066400000000000000000000030621355360272700261460ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #define PLATFORM_STACK_SIZE 0x1000 #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << (CACHE_WRITEBACK_SHIFT)) /* topology */ #define UNIPHIER_MAX_CPUS_PER_CLUSTER 4 #define UNIPHIER_CLUSTER_COUNT 2 #define PLATFORM_CORE_COUNT \ ((UNIPHIER_MAX_CPUS_PER_CLUSTER) * (UNIPHIER_CLUSTER_COUNT)) #define PLAT_MAX_PWR_LVL U(1) #define PLAT_MAX_OFF_STATE U(2) #define PLAT_MAX_RET_STATE U(1) #define BL2_BASE ULL(0x80000000) #define BL2_LIMIT ULL(0x80080000) /* 0x80080000-0x81000000: reserved for DSP */ #define UNIPHIER_SEC_DRAM_BASE 0x81000000ULL #define UNIPHIER_SEC_DRAM_LIMIT 0x82000000ULL #define UNIPHIER_SEC_DRAM_SIZE ((UNIPHIER_SEC_DRAM_LIMIT) - \ (UNIPHIER_SEC_DRAM_BASE)) #define BL31_BASE ULL(0x81000000) #define BL31_LIMIT ULL(0x81080000) #define BL32_BASE ULL(0x81080000) #define BL32_LIMIT ULL(0x81180000) #define PLAT_PHY_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32) #define PLAT_XLAT_TABLES_DYNAMIC 1 #define MAX_XLAT_TABLES 7 #define MAX_MMAP_REGIONS 7 #define MAX_IO_HANDLES 2 #define MAX_IO_DEVICES 2 #define MAX_IO_BLOCK_DEVICES U(1) #define TSP_SEC_MEM_BASE (BL32_BASE) #define TSP_SEC_MEM_SIZE ((BL32_LIMIT) - (BL32_BASE)) #define TSP_IRQ_SEC_PHY_TIMER 29 #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/socionext/uniphier/platform.mk000066400000000000000000000065701355360272700240740ustar00rootroot00000000000000# # Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # override BL2_AT_EL3 := 1 override COLD_BOOT_SINGLE_CPU := 1 override PROGRAMMABLE_RESET_ADDRESS := 1 override USE_COHERENT_MEM := 1 override ENABLE_SVE_FOR_NS := 0 # Cortex-A53 revision r0p4-51rel0 # needed for LD20, unneeded for LD11, PXs3 (no ACE) ERRATA_A53_855873 := 1 FIP_ALIGN := 512 ifeq ($(NEED_BL32),yes) $(eval $(call add_define,UNIPHIER_LOAD_BL32)) endif # Libraries include lib/xlat_tables_v2/xlat_tables.mk PLAT_PATH := plat/socionext/uniphier PLAT_INCLUDES := -I$(PLAT_PATH)/include # common sources for BL2, BL31 (and BL32 if SPD=tspd) PLAT_BL_COMMON_SOURCES += plat/common/aarch64/crash_console_helpers.S \ $(PLAT_PATH)/uniphier_console.S \ $(PLAT_PATH)/uniphier_console_setup.c \ $(PLAT_PATH)/uniphier_helpers.S \ $(PLAT_PATH)/uniphier_soc_info.c \ $(PLAT_PATH)/uniphier_xlat_setup.c \ ${XLAT_TABLES_LIB_SRCS} BL2_SOURCES += common/desc_image_load.c \ drivers/io/io_block.c \ drivers/io/io_fip.c \ drivers/io/io_memmap.c \ drivers/io/io_storage.c \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a72.S \ $(PLAT_PATH)/uniphier_bl2_setup.c \ $(PLAT_PATH)/uniphier_boot_device.c \ $(PLAT_PATH)/uniphier_emmc.c \ $(PLAT_PATH)/uniphier_image_desc.c \ $(PLAT_PATH)/uniphier_io_storage.c \ $(PLAT_PATH)/uniphier_nand.c \ $(PLAT_PATH)/uniphier_scp.c \ $(PLAT_PATH)/uniphier_usb.c BL31_SOURCES += drivers/arm/cci/cci.c \ drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v3/gicv3_helpers.c \ drivers/arm/gic/v3/gicv3_main.c \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a72.S \ plat/common/plat_gicv3.c \ plat/common/plat_psci_common.c \ $(PLAT_PATH)/uniphier_bl31_setup.c \ $(PLAT_PATH)/uniphier_cci.c \ $(PLAT_PATH)/uniphier_gicv3.c \ $(PLAT_PATH)/uniphier_psci.c \ $(PLAT_PATH)/uniphier_scp.c \ $(PLAT_PATH)/uniphier_smp.S \ $(PLAT_PATH)/uniphier_syscnt.c \ $(PLAT_PATH)/uniphier_topology.c ifeq (${TRUSTED_BOARD_BOOT},1) include drivers/auth/mbedtls/mbedtls_crypto.mk include drivers/auth/mbedtls/mbedtls_x509.mk BL2_SOURCES += drivers/auth/auth_mod.c \ drivers/auth/crypto_mod.c \ drivers/auth/img_parser_mod.c \ drivers/auth/tbbr/tbbr_cot.c \ plat/common/tbbr/plat_tbbr.c \ $(PLAT_PATH)/uniphier_rotpk.S \ $(PLAT_PATH)/uniphier_tbbr.c ROT_KEY = $(BUILD_PLAT)/rot_key.pem ROTPK_HASH = $(BUILD_PLAT)/rotpk_sha256.bin $(eval $(call add_define_val,ROTPK_HASH,'"$(ROTPK_HASH)"')) $(BUILD_PLAT)/bl2/uniphier_rotpk.o: $(ROTPK_HASH) certificates: $(ROT_KEY) $(ROT_KEY): | $(BUILD_PLAT) @echo " OPENSSL $@" $(Q)openssl genrsa 2048 > $@ 2>/dev/null $(ROTPK_HASH): $(ROT_KEY) @echo " OPENSSL $@" $(Q)openssl rsa -in $< -pubout -outform DER 2>/dev/null |\ openssl dgst -sha256 -binary > $@ 2>/dev/null endif ifeq (${FIP_GZIP},1) include lib/zlib/zlib.mk BL2_SOURCES += common/image_decompress.c \ $(ZLIB_SOURCES) $(eval $(call add_define,UNIPHIER_DECOMPRESS_GZIP)) # compress all images loaded by BL2 SCP_BL2_PRE_TOOL_FILTER := GZIP BL31_PRE_TOOL_FILTER := GZIP BL32_PRE_TOOL_FILTER := GZIP BL33_PRE_TOOL_FILTER := GZIP endif .PHONY: bl2_gzip bl2_gzip: $(BUILD_PLAT)/bl2.bin.gz %.gz: % @echo " GZIP $@" $(Q)gzip -n -f -9 $< --stdout > $@ trusted-firmware-a-2.2/plat/socionext/uniphier/tsp/000077500000000000000000000000001355360272700225155ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/socionext/uniphier/tsp/tsp-uniphier.mk000066400000000000000000000003751355360272700255020ustar00rootroot00000000000000# # Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # BL32_SOURCES += plat/common/plat_gicv3.c \ plat/common/aarch64/platform_mp_stack.S \ $(PLAT_PATH)/tsp/uniphier_tsp_setup.c trusted-firmware-a-2.2/plat/socionext/uniphier/tsp/uniphier_tsp_setup.c000066400000000000000000000007771355360272700266250ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "../uniphier.h" #define BL32_SIZE ((BL32_END) - (BL32_BASE)) void tsp_early_platform_setup(void) { uniphier_console_setup(); } void tsp_platform_setup(void) { } void tsp_plat_arch_setup(void) { uniphier_mmap_setup(BL32_BASE, BL32_SIZE, NULL); enable_mmu_el1(0); } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier.h000066400000000000000000000051551355360272700237110ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef UNIPHIER_H #define UNIPHIER_H #include #include unsigned int uniphier_get_soc_type(void); unsigned int uniphier_get_soc_model(void); unsigned int uniphier_get_soc_revision(void); unsigned int uniphier_get_soc_id(void); #define UNIPHIER_SOC_LD11 0 #define UNIPHIER_SOC_LD20 1 #define UNIPHIER_SOC_PXS3 2 #define UNIPHIER_SOC_UNKNOWN 0xffffffff unsigned int uniphier_get_boot_device(unsigned int soc); #define UNIPHIER_BOOT_DEVICE_EMMC 0 #define UNIPHIER_BOOT_DEVICE_NAND 1 #define UNIPHIER_BOOT_DEVICE_NOR 2 #define UNIPHIER_BOOT_DEVICE_USB 3 #define UNIPHIER_BOOT_DEVICE_RSV 0xffffffff unsigned int uniphier_get_boot_master(unsigned int soc); #define UNIPHIER_BOOT_MASTER_THIS 0 #define UNIPHIER_BOOT_MASTER_SCP 1 #define UNIPHIER_BOOT_MASTER_EXT 2 void uniphier_console_setup(void); int uniphier_emmc_init(uintptr_t *block_dev_spec); int uniphier_nand_init(uintptr_t *block_dev_spec); int uniphier_usb_init(unsigned int soc, uintptr_t *block_dev_spec); int uniphier_io_setup(unsigned int soc); struct image_info; struct image_info *uniphier_get_image_info(unsigned int image_id); int uniphier_scp_is_running(void); void uniphier_scp_start(void); void uniphier_scp_open_com(void); void uniphier_scp_system_off(void); void uniphier_scp_system_reset(void); struct mmap_region; void uniphier_mmap_setup(uintptr_t total_base, size_t total_size, const struct mmap_region *mmap); void uniphier_cci_init(unsigned int soc); void uniphier_cci_enable(void); void uniphier_cci_disable(void); void uniphier_gic_driver_init(unsigned int soc); void uniphier_gic_init(void); void uniphier_gic_cpuif_enable(void); void uniphier_gic_cpuif_disable(void); void uniphier_gic_pcpu_init(void); unsigned int uniphier_calc_core_pos(u_register_t mpidr); #define UNIPHIER_NS_DRAM_BASE 0x84000000 #define UNIPHIER_NS_DRAM_LIMIT 0x85000000 #define UNIPHIER_NS_DRAM_SIZE ((UNIPHIER_NS_DRAM_LIMIT) - \ (UNIPHIER_NS_DRAM_BASE)) #define UNIPHIER_BL33_BASE (UNIPHIER_NS_DRAM_BASE) #define UNIPHIER_BL33_MAX_SIZE 0x00100000 #define UNIPHIER_SCP_BASE ((UNIPHIER_BL33_BASE) + \ (UNIPHIER_BL33_MAX_SIZE)) #define UNIPHIER_SCP_MAX_SIZE 0x00020000 #define UNIPHIER_BLOCK_BUF_BASE ((UNIPHIER_SCP_BASE) + \ (UNIPHIER_SCP_MAX_SIZE)) #define UNIPHIER_BLOCK_BUF_SIZE 0x00100000 #define UNIPHIER_IMAGE_BUF_BASE ((UNIPHIER_BLOCK_BUF_BASE) + \ (UNIPHIER_BLOCK_BUF_SIZE)) #define UNIPHIER_IMAGE_BUF_SIZE ((UNIPHIER_NS_DRAM_LIMIT) - \ (UNIPHIER_IMAGE_BUF_BASE)) #endif /* UNIPHIER_H */ trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_bl2_setup.c000066400000000000000000000064621355360272700256650ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #ifdef UNIPHIER_DECOMPRESS_GZIP #include #endif #include "uniphier.h" #define BL2_SIZE ((BL2_END) - (BL2_BASE)) static int uniphier_bl2_kick_scp; void bl2_el3_early_platform_setup(u_register_t x0, u_register_t x1, u_register_t x2, u_register_t x3) { uniphier_console_setup(); } static const struct mmap_region uniphier_bl2_mmap[] = { /* for BL31, BL32 */ MAP_REGION_FLAT(UNIPHIER_SEC_DRAM_BASE, UNIPHIER_SEC_DRAM_SIZE, MT_MEMORY | MT_RW | MT_SECURE), /* for SCP, BL33 */ MAP_REGION_FLAT(UNIPHIER_NS_DRAM_BASE, UNIPHIER_NS_DRAM_SIZE, MT_MEMORY | MT_RW | MT_NS), { .size = 0 }, }; void bl2_el3_plat_arch_setup(void) { unsigned int soc; int skip_scp = 0; int ret; uniphier_mmap_setup(BL2_BASE, BL2_SIZE, uniphier_bl2_mmap); enable_mmu_el3(0); soc = uniphier_get_soc_id(); if (soc == UNIPHIER_SOC_UNKNOWN) { ERROR("unsupported SoC\n"); plat_error_handler(-ENOTSUP); } ret = uniphier_io_setup(soc); if (ret) { ERROR("failed to setup io devices\n"); plat_error_handler(ret); } switch (uniphier_get_boot_master(soc)) { case UNIPHIER_BOOT_MASTER_THIS: INFO("Booting from this SoC\n"); skip_scp = 1; break; case UNIPHIER_BOOT_MASTER_SCP: INFO("Booting from on-chip SCP\n"); if (uniphier_scp_is_running()) { INFO("SCP is already running. SCP_BL2 load will be skipped.\n"); skip_scp = 1; } /* * SCP must be kicked every time even if it is already running * because it polls this event after the reboot of the backend. */ uniphier_bl2_kick_scp = 1; break; case UNIPHIER_BOOT_MASTER_EXT: INFO("Booting from external SCP\n"); skip_scp = 1; break; default: plat_error_handler(-ENOTSUP); break; } if (skip_scp) { struct image_info *image_info; image_info = uniphier_get_image_info(SCP_BL2_IMAGE_ID); image_info->h.attr |= IMAGE_ATTRIB_SKIP_LOADING; } } void bl2_platform_setup(void) { } void plat_flush_next_bl_params(void) { flush_bl_params_desc(); } bl_load_info_t *plat_get_bl_image_load_info(void) { return get_bl_load_info_from_mem_params_desc(); } bl_params_t *plat_get_next_bl_params(void) { return get_next_bl_params_from_mem_params_desc(); } void bl2_plat_preload_setup(void) { #ifdef UNIPHIER_DECOMPRESS_GZIP image_decompress_init(UNIPHIER_IMAGE_BUF_BASE, UNIPHIER_IMAGE_BUF_SIZE, gunzip); #endif } int bl2_plat_handle_pre_image_load(unsigned int image_id) { #ifdef UNIPHIER_DECOMPRESS_GZIP image_decompress_prepare(uniphier_get_image_info(image_id)); #endif return 0; } int bl2_plat_handle_post_image_load(unsigned int image_id) { #ifdef UNIPHIER_DECOMPRESS_GZIP struct image_info *image_info; int ret; image_info = uniphier_get_image_info(image_id); if (!(image_info->h.attr & IMAGE_ATTRIB_SKIP_LOADING)) { ret = image_decompress(uniphier_get_image_info(image_id)); if (ret) return ret; } #endif if (image_id == SCP_BL2_IMAGE_ID && uniphier_bl2_kick_scp) uniphier_scp_start(); return 0; } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_bl31_setup.c000066400000000000000000000036411355360272700257430ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "uniphier.h" #define BL31_SIZE ((BL31_END) - (BL31_BASE)) static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { assert(sec_state_is_valid(type)); return type == NON_SECURE ? &bl33_image_ep_info : &bl32_image_ep_info; } void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { void *from_bl2; from_bl2 = (void *)arg0; bl_params_node_t *bl_params = ((bl_params_t *)from_bl2)->head; uniphier_console_setup(); while (bl_params) { if (bl_params->image_id == BL32_IMAGE_ID) bl32_image_ep_info = *bl_params->ep_info; if (bl_params->image_id == BL33_IMAGE_ID) bl33_image_ep_info = *bl_params->ep_info; bl_params = bl_params->next_params_info; } if (bl33_image_ep_info.pc == 0) panic(); } #define UNIPHIER_SYS_CNTCTL_BASE 0x60E00000 void bl31_platform_setup(void) { unsigned int soc; soc = uniphier_get_soc_id(); if (soc == UNIPHIER_SOC_UNKNOWN) { ERROR("unsupported SoC\n"); plat_error_handler(-ENOTSUP); } uniphier_cci_init(soc); uniphier_cci_enable(); /* Initialize the GIC driver, cpu and distributor interfaces */ uniphier_gic_driver_init(soc); uniphier_gic_init(); /* Enable and initialize the System level generic timer */ mmio_write_32(UNIPHIER_SYS_CNTCTL_BASE + CNTCR_OFF, CNTCR_FCREQ(0U) | CNTCR_EN); } void bl31_plat_arch_setup(void) { uniphier_mmap_setup(BL31_BASE, BL31_SIZE, NULL); enable_mmu_el3(0); } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_boot_device.c000066400000000000000000000100121355360272700262320ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "uniphier.h" #define UNIPHIER_PINMON0 0x5f900100 #define UNIPHIER_PINMON2 0x5f900108 static int uniphier_ld11_is_usb_boot(uint32_t pinmon) { return !!(~pinmon & 0x00000080); } static int uniphier_ld20_is_usb_boot(uint32_t pinmon) { return !!(~pinmon & 0x00000780); } static int uniphier_pxs3_is_usb_boot(uint32_t pinmon) { uint32_t pinmon2 = mmio_read_32(UNIPHIER_PINMON2); return !!(pinmon2 & BIT(31)); } static const unsigned int uniphier_ld11_boot_device_table[] = { UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_EMMC, UNIPHIER_BOOT_DEVICE_EMMC, UNIPHIER_BOOT_DEVICE_EMMC, UNIPHIER_BOOT_DEVICE_EMMC, UNIPHIER_BOOT_DEVICE_EMMC, UNIPHIER_BOOT_DEVICE_EMMC, UNIPHIER_BOOT_DEVICE_EMMC, UNIPHIER_BOOT_DEVICE_NOR, }; static unsigned int uniphier_ld11_get_boot_device(uint32_t pinmon) { unsigned int boot_sel = (pinmon >> 1) & 0x1f; assert(boot_sel < ARRAY_SIZE(uniphier_ld11_boot_device_table)); return uniphier_ld11_boot_device_table[boot_sel]; } static const unsigned int uniphier_pxs3_boot_device_table[] = { UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_EMMC, UNIPHIER_BOOT_DEVICE_EMMC, UNIPHIER_BOOT_DEVICE_EMMC, UNIPHIER_BOOT_DEVICE_EMMC, UNIPHIER_BOOT_DEVICE_EMMC, UNIPHIER_BOOT_DEVICE_EMMC, UNIPHIER_BOOT_DEVICE_NAND, UNIPHIER_BOOT_DEVICE_NAND, }; static unsigned int uniphier_pxs3_get_boot_device(uint32_t pinmon) { unsigned int boot_sel = (pinmon >> 1) & 0xf; assert(boot_sel < ARRAY_SIZE(uniphier_pxs3_boot_device_table)); return uniphier_pxs3_boot_device_table[boot_sel]; } struct uniphier_boot_device_info { int (*is_usb_boot)(uint32_t pinmon); unsigned int (*get_boot_device)(uint32_t pinmon); }; static const struct uniphier_boot_device_info uniphier_boot_device_info[] = { [UNIPHIER_SOC_LD11] = { .is_usb_boot = uniphier_ld11_is_usb_boot, .get_boot_device = uniphier_ld11_get_boot_device, }, [UNIPHIER_SOC_LD20] = { .is_usb_boot = uniphier_ld20_is_usb_boot, .get_boot_device = uniphier_ld11_get_boot_device, }, [UNIPHIER_SOC_PXS3] = { .is_usb_boot = uniphier_pxs3_is_usb_boot, .get_boot_device = uniphier_pxs3_get_boot_device, }, }; unsigned int uniphier_get_boot_device(unsigned int soc) { const struct uniphier_boot_device_info *info; uint32_t pinmon; assert(soc < ARRAY_SIZE(uniphier_boot_device_info)); info = &uniphier_boot_device_info[soc]; pinmon = mmio_read_32(UNIPHIER_PINMON0); if (!(pinmon & BIT(29))) return UNIPHIER_BOOT_DEVICE_NOR; if (info->is_usb_boot(pinmon)) return UNIPHIER_BOOT_DEVICE_USB; return info->get_boot_device(pinmon); } static const bool uniphier_have_onchip_scp[] = { [UNIPHIER_SOC_LD11] = true, [UNIPHIER_SOC_LD20] = true, [UNIPHIER_SOC_PXS3] = false, }; unsigned int uniphier_get_boot_master(unsigned int soc) { assert(soc < ARRAY_SIZE(uniphier_have_onchip_scp)); if (uniphier_have_onchip_scp[soc]) { if (mmio_read_32(UNIPHIER_PINMON0) & BIT(27)) return UNIPHIER_BOOT_MASTER_THIS; else return UNIPHIER_BOOT_MASTER_SCP; } else { return UNIPHIER_BOOT_MASTER_EXT; } } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_cci.c000066400000000000000000000031351355360272700245160ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "uniphier.h" #define UNIPHIER_CCI500_BASE 0x5FD00000 static const int uniphier_cci_map[] = {1, 0}; static void __uniphier_cci_init(void) { cci_init(UNIPHIER_CCI500_BASE, uniphier_cci_map, ARRAY_SIZE(uniphier_cci_map)); } static void __uniphier_cci_enable(void) { cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); } static void __uniphier_cci_disable(void) { cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1())); } struct uniphier_cci_ops { void (*init)(void); void (*enable)(void); void (*disable)(void); }; static const struct uniphier_cci_ops uniphier_cci_ops_table[] = { [UNIPHIER_SOC_LD11] = { .init = NULL, .enable = NULL, .disable = NULL, }, [UNIPHIER_SOC_LD20] = { .init = __uniphier_cci_init, .enable = __uniphier_cci_enable, .disable = __uniphier_cci_disable, }, [UNIPHIER_SOC_PXS3] = { .init = NULL, .enable = NULL, .disable = NULL, }, }; static struct uniphier_cci_ops uniphier_cci_ops; void uniphier_cci_init(unsigned int soc) { uniphier_cci_ops = uniphier_cci_ops_table[soc]; flush_dcache_range((uint64_t)&uniphier_cci_ops, sizeof(uniphier_cci_ops)); if (uniphier_cci_ops.init) uniphier_cci_ops.init(); } void uniphier_cci_enable(void) { if (uniphier_cci_ops.enable) uniphier_cci_ops.enable(); } void uniphier_cci_disable(void) { if (uniphier_cci_ops.disable) uniphier_cci_ops.disable(); } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_console.S000066400000000000000000000026541355360272700254070ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "uniphier_console.h" /* * In: w0 - character to be printed * x1 - pointer to console structure * Out: return the character written (always succeeds) * Clobber: x2 */ .globl uniphier_console_putc func uniphier_console_putc ldr x1, [x1, #CONSOLE_T_DRVDATA] /* Wait until the transmitter FIFO gets empty */ 0: ldr w2, [x1, #UNIPHIER_UART_LSR] tbz w2, #UNIPHIER_UART_LSR_THRE_BIT, 0b str w0, [x1, #UNIPHIER_UART_TX] ret endfunc uniphier_console_putc /* * In: x0 - pointer to console structure * Out: return the character read, or ERROR_NO_PENDING_CHAR if no character is available * Clobber: x1 */ .globl uniphier_console_getc func uniphier_console_getc ldr x0, [x0, #CONSOLE_T_DRVDATA] ldr w1, [x0, #UNIPHIER_UART_LSR] tbz w1, #UNIPHIER_UART_LSR_DR_BIT, 0f ldr w0, [x0, #UNIPHIER_UART_RX] ret 0: mov w0, #ERROR_NO_PENDING_CHAR ret endfunc uniphier_console_getc /* * In: x0 - pointer to console structure * Out: return 0 (always succeeds) * Clobber: x1 */ .global uniphier_console_flush func uniphier_console_flush ldr x0, [x0, #CONSOLE_T_DRVDATA] /* wait until the transmitter gets empty */ 0: ldr w1, [x0, #UNIPHIER_UART_LSR] tbz w1, #UNIPHIER_UART_LSR_TEMT_BIT, 0b mov w0, #0 ret endfunc uniphier_console_flush trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_console.h000066400000000000000000000017221355360272700254270ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef UNIPHIER_CONSOLE_H #define UNIPHIER_CONSOLE_H #define UNIPHIER_UART_RX 0x00 /* In: Receive buffer */ #define UNIPHIER_UART_TX 0x00 /* Out: Transmit buffer */ #define UNIPHIER_UART_FCR 0x0c /* Char/FIFO Control Register */ #define UNIPHIER_UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */ #define UNIPHIER_UART_LCR_MCR 0x10 /* Line/Modem Control Register */ #define UNIPHIER_UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */ #define UNIPHIER_UART_LSR 0x14 /* Line Status Register */ #define UNIPHIER_UART_LSR_TEMT 0x40 /* Transmitter empty */ #define UNIPHIER_UART_LSR_TEMT_BIT 6 /* Transmitter empty */ #define UNIPHIER_UART_LSR_THRE_BIT 5 /* Transmit-hold-register empty */ #define UNIPHIER_UART_LSR_DR_BIT 0 /* Receiver data ready */ #define UNIPHIER_UART_DLR 0x24 /* Divisor Latch Register */ #endif /* UNIPHIER_CONSOLE_H */ trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_console_setup.c000066400000000000000000000041051355360272700266400ustar00rootroot00000000000000/* * Copyright (c) 2019, Socionext Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "uniphier.h" #include "uniphier_console.h" #define UNIPHIER_UART_BASE 0x54006800 #define UNIPHIER_UART_END 0x54006c00 #define UNIPHIER_UART_OFFSET 0x100 struct uniphier_console { struct console console; uintptr_t base; }; /* These callbacks are implemented in assembly to use crash_console_helpers.S */ int uniphier_console_putc(int character, struct console *console); int uniphier_console_getc(struct console *console); int uniphier_console_flush(struct console *console); static struct uniphier_console uniphier_console = { .console = { .flags = CONSOLE_FLAG_BOOT | #if DEBUG CONSOLE_FLAG_RUNTIME | #endif CONSOLE_FLAG_CRASH | CONSOLE_FLAG_TRANSLATE_CRLF, .putc = uniphier_console_putc, .getc = uniphier_console_getc, .flush = uniphier_console_flush, }, }; /* * There are 4 UART ports available on this platform. By default, we want to * use the same one as used in the previous firmware stage. */ static uintptr_t uniphier_console_get_base(void) { uintptr_t base = UNIPHIER_UART_BASE; uint32_t div; while (base < UNIPHIER_UART_END) { div = mmio_read_32(base + UNIPHIER_UART_DLR); if (div) return base; base += UNIPHIER_UART_OFFSET; } return 0; } static void uniphier_console_init(uintptr_t base) { mmio_write_32(base + UNIPHIER_UART_FCR, UNIPHIER_UART_FCR_ENABLE_FIFO); mmio_write_32(base + UNIPHIER_UART_LCR_MCR, UNIPHIER_UART_LCR_WLEN8 << 8); } void uniphier_console_setup(void) { uintptr_t base; base = uniphier_console_get_base(); if (!base) plat_error_handler(-EINVAL); uniphier_console.base = base; console_register(&uniphier_console.console); /* * The hardware might be still printing characters queued up in the * previous firmware stage. Make sure the transmitter is empty before * any initialization. Otherwise, the console might get corrupted. */ console_flush(); uniphier_console_init(base); } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_emmc.c000066400000000000000000000167321355360272700247100ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "uniphier.h" #define MMC_CMD_SWITCH 6 #define MMC_CMD_SELECT_CARD 7 #define MMC_CMD_SEND_CSD 9 #define MMC_CMD_READ_MULTIPLE_BLOCK 18 #define EXT_CSD_PART_CONF 179 /* R/W */ #define MMC_RSP_PRESENT BIT(0) #define MMC_RSP_136 BIT(1) /* 136 bit response */ #define MMC_RSP_CRC BIT(2) /* expect valid crc */ #define MMC_RSP_BUSY BIT(3) /* card may send busy */ #define MMC_RSP_OPCODE BIT(4) /* response contains opcode */ #define MMC_RSP_NONE (0) #define MMC_RSP_R1 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP_R1b (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE | \ MMC_RSP_BUSY) #define MMC_RSP_R2 (MMC_RSP_PRESENT | MMC_RSP_136 | MMC_RSP_CRC) #define MMC_RSP_R3 (MMC_RSP_PRESENT) #define MMC_RSP_R4 (MMC_RSP_PRESENT) #define MMC_RSP_R5 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP_R6 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define MMC_RSP_R7 (MMC_RSP_PRESENT | MMC_RSP_CRC | MMC_RSP_OPCODE) #define SDHCI_DMA_ADDRESS 0x00 #define SDHCI_BLOCK_SIZE 0x04 #define SDHCI_MAKE_BLKSZ(dma, blksz) ((((dma) & 0x7) << 12) | ((blksz) & 0xFFF)) #define SDHCI_BLOCK_COUNT 0x06 #define SDHCI_ARGUMENT 0x08 #define SDHCI_TRANSFER_MODE 0x0C #define SDHCI_TRNS_DMA BIT(0) #define SDHCI_TRNS_BLK_CNT_EN BIT(1) #define SDHCI_TRNS_ACMD12 BIT(2) #define SDHCI_TRNS_READ BIT(4) #define SDHCI_TRNS_MULTI BIT(5) #define SDHCI_COMMAND 0x0E #define SDHCI_CMD_RESP_MASK 0x03 #define SDHCI_CMD_CRC 0x08 #define SDHCI_CMD_INDEX 0x10 #define SDHCI_CMD_DATA 0x20 #define SDHCI_CMD_ABORTCMD 0xC0 #define SDHCI_CMD_RESP_NONE 0x00 #define SDHCI_CMD_RESP_LONG 0x01 #define SDHCI_CMD_RESP_SHORT 0x02 #define SDHCI_CMD_RESP_SHORT_BUSY 0x03 #define SDHCI_MAKE_CMD(c, f) ((((c) & 0xff) << 8) | ((f) & 0xff)) #define SDHCI_RESPONSE 0x10 #define SDHCI_HOST_CONTROL 0x28 #define SDHCI_CTRL_DMA_MASK 0x18 #define SDHCI_CTRL_SDMA 0x00 #define SDHCI_BLOCK_GAP_CONTROL 0x2A #define SDHCI_SOFTWARE_RESET 0x2F #define SDHCI_RESET_CMD 0x02 #define SDHCI_RESET_DATA 0x04 #define SDHCI_INT_STATUS 0x30 #define SDHCI_INT_RESPONSE BIT(0) #define SDHCI_INT_DATA_END BIT(1) #define SDHCI_INT_DMA_END BIT(3) #define SDHCI_INT_ERROR BIT(15) #define SDHCI_SIGNAL_ENABLE 0x38 /* RCA assigned by Boot ROM */ #define UNIPHIER_EMMC_RCA 0x1000 struct uniphier_mmc_cmd { unsigned int cmdidx; unsigned int resp_type; unsigned int cmdarg; unsigned int is_data; }; static int uniphier_emmc_block_addressing; static int uniphier_emmc_send_cmd(uintptr_t host_base, struct uniphier_mmc_cmd *cmd) { uint32_t mode = 0; uint32_t end_bit; uint32_t stat, flags, dma_addr; mmio_write_32(host_base + SDHCI_INT_STATUS, -1); mmio_write_32(host_base + SDHCI_SIGNAL_ENABLE, 0); mmio_write_32(host_base + SDHCI_ARGUMENT, cmd->cmdarg); if (cmd->is_data) mode = SDHCI_TRNS_DMA | SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_ACMD12 | SDHCI_TRNS_READ | SDHCI_TRNS_MULTI; mmio_write_16(host_base + SDHCI_TRANSFER_MODE, mode); if (!(cmd->resp_type & MMC_RSP_PRESENT)) flags = SDHCI_CMD_RESP_NONE; else if (cmd->resp_type & MMC_RSP_136) flags = SDHCI_CMD_RESP_LONG; else if (cmd->resp_type & MMC_RSP_BUSY) flags = SDHCI_CMD_RESP_SHORT_BUSY; else flags = SDHCI_CMD_RESP_SHORT; if (cmd->resp_type & MMC_RSP_CRC) flags |= SDHCI_CMD_CRC; if (cmd->resp_type & MMC_RSP_OPCODE) flags |= SDHCI_CMD_INDEX; if (cmd->is_data) flags |= SDHCI_CMD_DATA; if (cmd->resp_type & MMC_RSP_BUSY || cmd->is_data) end_bit = SDHCI_INT_DATA_END; else end_bit = SDHCI_INT_RESPONSE; mmio_write_16(host_base + SDHCI_COMMAND, SDHCI_MAKE_CMD(cmd->cmdidx, flags)); do { stat = mmio_read_32(host_base + SDHCI_INT_STATUS); if (stat & SDHCI_INT_ERROR) return -EIO; if (stat & SDHCI_INT_DMA_END) { mmio_write_32(host_base + SDHCI_INT_STATUS, stat); dma_addr = mmio_read_32(host_base + SDHCI_DMA_ADDRESS); mmio_write_32(host_base + SDHCI_DMA_ADDRESS, dma_addr); } } while (!(stat & end_bit)); return 0; } static int uniphier_emmc_switch_part(uintptr_t host_base, int part_num) { struct uniphier_mmc_cmd cmd = {0}; cmd.cmdidx = MMC_CMD_SWITCH; cmd.resp_type = MMC_RSP_R1b; cmd.cmdarg = (EXT_CSD_PART_CONF << 16) | (part_num << 8) | (3 << 24); return uniphier_emmc_send_cmd(host_base, &cmd); } static int uniphier_emmc_is_over_2gb(uintptr_t host_base) { struct uniphier_mmc_cmd cmd = {0}; uint32_t csd40, csd72; /* CSD[71:40], CSD[103:72] */ int ret; cmd.cmdidx = MMC_CMD_SEND_CSD; cmd.resp_type = MMC_RSP_R2; cmd.cmdarg = UNIPHIER_EMMC_RCA << 16; ret = uniphier_emmc_send_cmd(host_base, &cmd); if (ret) return ret; csd40 = mmio_read_32(host_base + SDHCI_RESPONSE + 4); csd72 = mmio_read_32(host_base + SDHCI_RESPONSE + 8); return !(~csd40 & 0xffc00380) && !(~csd72 & 0x3); } static int uniphier_emmc_load_image(uintptr_t host_base, uint32_t dev_addr, unsigned long load_addr, uint32_t block_cnt) { struct uniphier_mmc_cmd cmd = {0}; uint8_t tmp; assert((load_addr >> 32) == 0); mmio_write_32(host_base + SDHCI_DMA_ADDRESS, load_addr); mmio_write_16(host_base + SDHCI_BLOCK_SIZE, SDHCI_MAKE_BLKSZ(7, 512)); mmio_write_16(host_base + SDHCI_BLOCK_COUNT, block_cnt); tmp = mmio_read_8(host_base + SDHCI_HOST_CONTROL); tmp &= ~SDHCI_CTRL_DMA_MASK; tmp |= SDHCI_CTRL_SDMA; mmio_write_8(host_base + SDHCI_HOST_CONTROL, tmp); tmp = mmio_read_8(host_base + SDHCI_BLOCK_GAP_CONTROL); tmp &= ~1; /* clear Stop At Block Gap Request */ mmio_write_8(host_base + SDHCI_BLOCK_GAP_CONTROL, tmp); cmd.cmdidx = MMC_CMD_READ_MULTIPLE_BLOCK; cmd.resp_type = MMC_RSP_R1; cmd.cmdarg = dev_addr; cmd.is_data = 1; return uniphier_emmc_send_cmd(host_base, &cmd); } static size_t uniphier_emmc_read(int lba, uintptr_t buf, size_t size) { uintptr_t host_base = 0x5a000200; int ret; inv_dcache_range(buf, size); if (!uniphier_emmc_block_addressing) lba *= 512; ret = uniphier_emmc_load_image(host_base, lba, buf, size / 512); inv_dcache_range(buf, size); return ret ? 0 : size; } static const struct io_block_dev_spec uniphier_emmc_dev_spec = { .buffer = { .offset = UNIPHIER_BLOCK_BUF_BASE, .length = UNIPHIER_BLOCK_BUF_SIZE, }, .ops = { .read = uniphier_emmc_read, }, .block_size = 512, }; static int uniphier_emmc_hw_init(void) { uintptr_t host_base = 0x5a000200; struct uniphier_mmc_cmd cmd = {0}; int ret; /* * deselect card before SEND_CSD command. * Do not check the return code. It fails, but it is OK. */ cmd.cmdidx = MMC_CMD_SELECT_CARD; cmd.resp_type = MMC_RSP_R1; uniphier_emmc_send_cmd(host_base, &cmd); /* CMD7 (arg=0) */ /* reset CMD Line */ mmio_write_8(host_base + SDHCI_SOFTWARE_RESET, SDHCI_RESET_CMD | SDHCI_RESET_DATA); while (mmio_read_8(host_base + SDHCI_SOFTWARE_RESET)) ; ret = uniphier_emmc_is_over_2gb(host_base); if (ret < 0) return ret; uniphier_emmc_block_addressing = ret; cmd.cmdarg = UNIPHIER_EMMC_RCA << 16; /* select card again */ ret = uniphier_emmc_send_cmd(host_base, &cmd); if (ret) return ret; /* switch to Boot Partition 1 */ ret = uniphier_emmc_switch_part(host_base, 1); if (ret) return ret; return 0; } int uniphier_emmc_init(uintptr_t *block_dev_spec) { int ret; ret = uniphier_emmc_hw_init(); if (ret) return ret; *block_dev_spec = (uintptr_t)&uniphier_emmc_dev_spec; return 0; } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_gicv3.c000066400000000000000000000060621355360272700247750ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "uniphier.h" static uintptr_t uniphier_rdistif_base_addrs[PLATFORM_CORE_COUNT]; static const interrupt_prop_t uniphier_interrupt_props[] = { /* G0 interrupts */ /* SGI0 */ INTR_PROP_DESC(8, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0, GIC_INTR_CFG_EDGE), /* SGI6 */ INTR_PROP_DESC(14, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP0, GIC_INTR_CFG_EDGE), /* G1S interrupts */ /* Timer */ INTR_PROP_DESC(29, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_LEVEL), /* SGI1 */ INTR_PROP_DESC(9, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_EDGE), /* SGI2 */ INTR_PROP_DESC(10, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_EDGE), /* SGI3 */ INTR_PROP_DESC(11, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_EDGE), /* SGI4 */ INTR_PROP_DESC(12, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_EDGE), /* SGI5 */ INTR_PROP_DESC(13, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_EDGE), /* SGI7 */ INTR_PROP_DESC(15, GIC_HIGHEST_SEC_PRIORITY, INTR_GROUP1S, GIC_INTR_CFG_EDGE) }; static unsigned int uniphier_mpidr_to_core_pos(u_register_t mpidr) { return plat_core_pos_by_mpidr(mpidr); } static const struct gicv3_driver_data uniphier_gic_driver_data[] = { [UNIPHIER_SOC_LD11] = { .gicd_base = 0x5fe00000, .gicr_base = 0x5fe40000, .interrupt_props = uniphier_interrupt_props, .interrupt_props_num = ARRAY_SIZE(uniphier_interrupt_props), .rdistif_num = PLATFORM_CORE_COUNT, .rdistif_base_addrs = uniphier_rdistif_base_addrs, .mpidr_to_core_pos = uniphier_mpidr_to_core_pos, }, [UNIPHIER_SOC_LD20] = { .gicd_base = 0x5fe00000, .gicr_base = 0x5fe80000, .interrupt_props = uniphier_interrupt_props, .interrupt_props_num = ARRAY_SIZE(uniphier_interrupt_props), .rdistif_num = PLATFORM_CORE_COUNT, .rdistif_base_addrs = uniphier_rdistif_base_addrs, .mpidr_to_core_pos = uniphier_mpidr_to_core_pos, }, [UNIPHIER_SOC_PXS3] = { .gicd_base = 0x5fe00000, .gicr_base = 0x5fe80000, .interrupt_props = uniphier_interrupt_props, .interrupt_props_num = ARRAY_SIZE(uniphier_interrupt_props), .rdistif_num = PLATFORM_CORE_COUNT, .rdistif_base_addrs = uniphier_rdistif_base_addrs, .mpidr_to_core_pos = uniphier_mpidr_to_core_pos, }, }; void uniphier_gic_driver_init(unsigned int soc) { assert(soc < ARRAY_SIZE(uniphier_gic_driver_data)); gicv3_driver_init(&uniphier_gic_driver_data[soc]); } void uniphier_gic_init(void) { gicv3_distif_init(); gicv3_rdistif_init(plat_my_core_pos()); gicv3_cpuif_enable(plat_my_core_pos()); } void uniphier_gic_cpuif_enable(void) { gicv3_cpuif_enable(plat_my_core_pos()); } void uniphier_gic_cpuif_disable(void) { gicv3_cpuif_disable(plat_my_core_pos()); } void uniphier_gic_pcpu_init(void) { gicv3_rdistif_init(plat_my_core_pos()); } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_helpers.S000066400000000000000000000013651355360272700254050ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .global uniphier_calc_core_pos .global plat_my_core_pos .globl platform_mem_init /* * unsigned int uniphier_calc_core_pos(u_register_t mpidr) * core_pos = (cluster_id * max_cpus_per_cluster) + core_id */ func uniphier_calc_core_pos and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK lsr x0, x0, #MPIDR_AFFINITY_BITS mov x2, #UNIPHIER_MAX_CPUS_PER_CLUSTER madd x0, x0, x2, x1 ret endfunc uniphier_calc_core_pos func plat_my_core_pos mrs x0, mpidr_el1 b uniphier_calc_core_pos endfunc plat_my_core_pos func platform_mem_init ret endfunc platform_mem_init trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_image_desc.c000066400000000000000000000047651355360272700260520ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "uniphier.h" static struct bl_mem_params_node uniphier_image_descs[] = { { .image_id = SCP_BL2_IMAGE_ID, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = UNIPHIER_SCP_BASE, .image_info.image_max_size = UNIPHIER_SCP_MAX_SIZE, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | NON_EXECUTABLE), .next_handoff_image_id = INVALID_IMAGE_ID, }, { .image_id = BL31_IMAGE_ID, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = BL31_BASE, .image_info.image_max_size = BL31_LIMIT - BL31_BASE, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE | EP_FIRST_EXE), .ep_info.pc = BL31_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), #ifdef UNIPHIER_LOAD_BL32 .next_handoff_image_id = BL32_IMAGE_ID, #else .next_handoff_image_id = BL33_IMAGE_ID, #endif }, #ifdef UNIPHIER_LOAD_BL32 { .image_id = BL32_IMAGE_ID, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = BL32_BASE, .image_info.image_max_size = BL32_LIMIT - BL32_BASE, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, SECURE | EXECUTABLE), .ep_info.pc = BL32_BASE, .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), .next_handoff_image_id = BL33_IMAGE_ID, }, #endif { .image_id = BL33_IMAGE_ID, SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .image_info.image_base = UNIPHIER_BL33_BASE, .image_info.image_max_size = UNIPHIER_BL33_MAX_SIZE, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), .ep_info.pc = UNIPHIER_BL33_BASE, .ep_info.spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS), .next_handoff_image_id = INVALID_IMAGE_ID, }, }; REGISTER_BL_IMAGE_DESCS(uniphier_image_descs) struct image_info *uniphier_get_image_info(unsigned int image_id) { struct bl_mem_params_node *desc; desc = get_bl_mem_params_node(image_id); assert(desc); return &desc->image_info; } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_io_storage.c000066400000000000000000000207561355360272700261230ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include "uniphier.h" #define UNIPHIER_ROM_REGION_BASE 0x00000000ULL #define UNIPHIER_ROM_REGION_SIZE 0x10000000ULL #define UNIPHIER_OCM_REGION_BASE 0x30000000ULL #define UNIPHIER_OCM_REGION_SIZE 0x00040000ULL static const io_dev_connector_t *uniphier_fip_dev_con; static uintptr_t uniphier_fip_dev_handle; static const io_dev_connector_t *uniphier_backend_dev_con; static uintptr_t uniphier_backend_dev_handle; static io_block_spec_t uniphier_fip_spec = { /* .offset will be set by the io_setup func */ .length = 0x00200000, }; static const io_uuid_spec_t uniphier_bl2_spec = { .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2, }; static const io_uuid_spec_t uniphier_scp_spec = { .uuid = UUID_SCP_FIRMWARE_SCP_BL2, }; static const io_uuid_spec_t uniphier_bl31_spec = { .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31, }; static const io_uuid_spec_t uniphier_bl32_spec = { .uuid = UUID_SECURE_PAYLOAD_BL32, }; static const io_uuid_spec_t uniphier_bl33_spec = { .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33, }; #if TRUSTED_BOARD_BOOT static const io_uuid_spec_t uniphier_tb_fw_cert_spec = { .uuid = UUID_TRUSTED_BOOT_FW_CERT, }; static const io_uuid_spec_t uniphier_trusted_key_cert_spec = { .uuid = UUID_TRUSTED_KEY_CERT, }; static const io_uuid_spec_t uniphier_scp_fw_key_cert_spec = { .uuid = UUID_SCP_FW_KEY_CERT, }; static const io_uuid_spec_t uniphier_soc_fw_key_cert_spec = { .uuid = UUID_SOC_FW_KEY_CERT, }; static const io_uuid_spec_t uniphier_tos_fw_key_cert_spec = { .uuid = UUID_TRUSTED_OS_FW_KEY_CERT, }; static const io_uuid_spec_t uniphier_nt_fw_key_cert_spec = { .uuid = UUID_NON_TRUSTED_FW_KEY_CERT, }; static const io_uuid_spec_t uniphier_scp_fw_cert_spec = { .uuid = UUID_SCP_FW_CONTENT_CERT, }; static const io_uuid_spec_t uniphier_soc_fw_cert_spec = { .uuid = UUID_SOC_FW_CONTENT_CERT, }; static const io_uuid_spec_t uniphier_tos_fw_cert_spec = { .uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT, }; static const io_uuid_spec_t uniphier_nt_fw_cert_spec = { .uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT, }; #endif /* TRUSTED_BOARD_BOOT */ struct uniphier_io_policy { uintptr_t *dev_handle; uintptr_t image_spec; uintptr_t init_params; }; static const struct uniphier_io_policy uniphier_io_policies[] = { [FIP_IMAGE_ID] = { .dev_handle = &uniphier_backend_dev_handle, .image_spec = (uintptr_t)&uniphier_fip_spec, }, [BL2_IMAGE_ID] = { .dev_handle = &uniphier_fip_dev_handle, .image_spec = (uintptr_t)&uniphier_bl2_spec, .init_params = FIP_IMAGE_ID, }, [SCP_BL2_IMAGE_ID] = { .dev_handle = &uniphier_fip_dev_handle, .image_spec = (uintptr_t)&uniphier_scp_spec, .init_params = FIP_IMAGE_ID, }, [BL31_IMAGE_ID] = { .dev_handle = &uniphier_fip_dev_handle, .image_spec = (uintptr_t)&uniphier_bl31_spec, .init_params = FIP_IMAGE_ID, }, [BL32_IMAGE_ID] = { .dev_handle = &uniphier_fip_dev_handle, .image_spec = (uintptr_t)&uniphier_bl32_spec, .init_params = FIP_IMAGE_ID, }, [BL33_IMAGE_ID] = { .dev_handle = &uniphier_fip_dev_handle, .image_spec = (uintptr_t)&uniphier_bl33_spec, .init_params = FIP_IMAGE_ID, }, #if TRUSTED_BOARD_BOOT [TRUSTED_BOOT_FW_CERT_ID] = { .dev_handle = &uniphier_fip_dev_handle, .image_spec = (uintptr_t)&uniphier_tb_fw_cert_spec, .init_params = FIP_IMAGE_ID, }, [TRUSTED_KEY_CERT_ID] = { .dev_handle = &uniphier_fip_dev_handle, .image_spec = (uintptr_t)&uniphier_trusted_key_cert_spec, .init_params = FIP_IMAGE_ID, }, [SCP_FW_KEY_CERT_ID] = { .dev_handle = &uniphier_fip_dev_handle, .image_spec = (uintptr_t)&uniphier_scp_fw_key_cert_spec, .init_params = FIP_IMAGE_ID, }, [SOC_FW_KEY_CERT_ID] = { .dev_handle = &uniphier_fip_dev_handle, .image_spec = (uintptr_t)&uniphier_soc_fw_key_cert_spec, .init_params = FIP_IMAGE_ID, }, [TRUSTED_OS_FW_KEY_CERT_ID] = { .dev_handle = &uniphier_fip_dev_handle, .image_spec = (uintptr_t)&uniphier_tos_fw_key_cert_spec, .init_params = FIP_IMAGE_ID, }, [NON_TRUSTED_FW_KEY_CERT_ID] = { .dev_handle = &uniphier_fip_dev_handle, .image_spec = (uintptr_t)&uniphier_nt_fw_key_cert_spec, .init_params = FIP_IMAGE_ID, }, [SCP_FW_CONTENT_CERT_ID] = { .dev_handle = &uniphier_fip_dev_handle, .image_spec = (uintptr_t)&uniphier_scp_fw_cert_spec, .init_params = FIP_IMAGE_ID, }, [SOC_FW_CONTENT_CERT_ID] = { .dev_handle = &uniphier_fip_dev_handle, .image_spec = (uintptr_t)&uniphier_soc_fw_cert_spec, .init_params = FIP_IMAGE_ID, }, [TRUSTED_OS_FW_CONTENT_CERT_ID] = { .dev_handle = &uniphier_fip_dev_handle, .image_spec = (uintptr_t)&uniphier_tos_fw_cert_spec, .init_params = FIP_IMAGE_ID, }, [NON_TRUSTED_FW_CONTENT_CERT_ID] = { .dev_handle = &uniphier_fip_dev_handle, .image_spec = (uintptr_t)&uniphier_nt_fw_cert_spec, .init_params = FIP_IMAGE_ID, }, #endif }; static int uniphier_io_block_setup(size_t fip_offset, uintptr_t block_dev_spec) { int ret; uniphier_fip_spec.offset = fip_offset; ret = register_io_dev_block(&uniphier_backend_dev_con); if (ret) return ret; return io_dev_open(uniphier_backend_dev_con, block_dev_spec, &uniphier_backend_dev_handle); } static int uniphier_io_memmap_setup(size_t fip_offset) { int ret; uniphier_fip_spec.offset = fip_offset; ret = mmap_add_dynamic_region(fip_offset, fip_offset, uniphier_fip_spec.length, MT_RO_DATA | MT_SECURE); if (ret) return ret; ret = register_io_dev_memmap(&uniphier_backend_dev_con); if (ret) return ret; return io_dev_open(uniphier_backend_dev_con, 0, &uniphier_backend_dev_handle); } static int uniphier_io_fip_setup(void) { int ret; ret = register_io_dev_fip(&uniphier_fip_dev_con); if (ret) return ret; return io_dev_open(uniphier_fip_dev_con, 0, &uniphier_fip_dev_handle); } static int uniphier_io_emmc_setup(unsigned int soc_id) { uintptr_t block_dev_spec; int ret; ret = uniphier_emmc_init(&block_dev_spec); if (ret) return ret; return uniphier_io_block_setup(0x20000, block_dev_spec); } static int uniphier_io_nand_setup(unsigned int soc_id) { uintptr_t block_dev_spec; int ret; ret = uniphier_nand_init(&block_dev_spec); if (ret) return ret; return uniphier_io_block_setup(0x20000, block_dev_spec); } static int uniphier_io_nor_setup(unsigned int soc_id) { return uniphier_io_memmap_setup(0x70000); } static int uniphier_io_usb_setup(unsigned int soc_id) { uintptr_t block_dev_spec; int ret; /* use ROM API for loading images from USB storage */ ret = mmap_add_dynamic_region(UNIPHIER_ROM_REGION_BASE, UNIPHIER_ROM_REGION_BASE, UNIPHIER_ROM_REGION_SIZE, MT_CODE | MT_SECURE); if (ret) return ret; /* * on-chip SRAM region: should be DEVICE attribute because the USB * load functions provided by the ROM use this memory region as a work * area, but do not cater to cache coherency. */ ret = mmap_add_dynamic_region(UNIPHIER_OCM_REGION_BASE, UNIPHIER_OCM_REGION_BASE, UNIPHIER_OCM_REGION_SIZE, MT_DEVICE | MT_RW | MT_SECURE); if (ret) return ret; ret = uniphier_usb_init(soc_id, &block_dev_spec); if (ret) return ret; return uniphier_io_block_setup(0x20000, block_dev_spec); } static int (* const uniphier_io_setup_table[])(unsigned int) = { [UNIPHIER_BOOT_DEVICE_EMMC] = uniphier_io_emmc_setup, [UNIPHIER_BOOT_DEVICE_NAND] = uniphier_io_nand_setup, [UNIPHIER_BOOT_DEVICE_NOR] = uniphier_io_nor_setup, [UNIPHIER_BOOT_DEVICE_USB] = uniphier_io_usb_setup, }; int uniphier_io_setup(unsigned int soc_id) { int (*io_setup)(unsigned int soc_id); unsigned int boot_dev; int ret; boot_dev = uniphier_get_boot_device(soc_id); if (boot_dev == UNIPHIER_BOOT_DEVICE_RSV) return -EINVAL; io_setup = uniphier_io_setup_table[boot_dev]; ret = io_setup(soc_id); if (ret) return ret; ret = uniphier_io_fip_setup(); if (ret) return ret; return 0; } int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, uintptr_t *image_spec) { uintptr_t init_params; assert(image_id < ARRAY_SIZE(uniphier_io_policies)); *dev_handle = *uniphier_io_policies[image_id].dev_handle; *image_spec = uniphier_io_policies[image_id].image_spec; init_params = uniphier_io_policies[image_id].init_params; return io_dev_init(*dev_handle, init_params); } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_nand.c000066400000000000000000000151301355360272700246760ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "uniphier.h" #define NAND_CMD_READ0 0 #define NAND_CMD_READSTART 0x30 #define DENALI_ECC_ENABLE 0x0e0 #define DENALI_PAGES_PER_BLOCK 0x150 #define DENALI_DEVICE_MAIN_AREA_SIZE 0x170 #define DENALI_DEVICE_SPARE_AREA_SIZE 0x180 #define DENALI_TWO_ROW_ADDR_CYCLES 0x190 #define DENALI_INTR_STATUS0 0x410 #define DENALI_INTR_ECC_UNCOR_ERR BIT(1) #define DENALI_INTR_DMA_CMD_COMP BIT(2) #define DENALI_INTR_INT_ACT BIT(12) #define DENALI_DMA_ENABLE 0x700 #define DENALI_HOST_ADDR 0x00 #define DENALI_HOST_DATA 0x10 #define DENALI_MAP01 (1 << 26) #define DENALI_MAP10 (2 << 26) #define DENALI_MAP11 (3 << 26) #define DENALI_MAP11_CMD ((DENALI_MAP11) | 0) #define DENALI_MAP11_ADDR ((DENALI_MAP11) | 1) #define DENALI_MAP11_DATA ((DENALI_MAP11) | 2) #define DENALI_ACCESS_DEFAULT_AREA 0x42 #define UNIPHIER_NAND_BBT_UNKNOWN 0xff struct uniphier_nand { uintptr_t host_base; uintptr_t reg_base; int pages_per_block; int page_size; int two_row_addr_cycles; uint8_t bbt[16]; }; struct uniphier_nand uniphier_nand; static void uniphier_nand_host_write(struct uniphier_nand *nand, uint32_t addr, uint32_t data) { mmio_write_32(nand->host_base + DENALI_HOST_ADDR, addr); mmio_write_32(nand->host_base + DENALI_HOST_DATA, data); } static uint32_t uniphier_nand_host_read(struct uniphier_nand *nand, uint32_t addr) { mmio_write_32(nand->host_base + DENALI_HOST_ADDR, addr); return mmio_read_32(nand->host_base + DENALI_HOST_DATA); } static int uniphier_nand_block_isbad(struct uniphier_nand *nand, int block) { int page = nand->pages_per_block * block; int column = nand->page_size; uint8_t bbm; uint32_t status; int is_bad; /* use cache if available */ if (block < ARRAY_SIZE(nand->bbt) && nand->bbt[block] != UNIPHIER_NAND_BBT_UNKNOWN) return nand->bbt[block]; mmio_write_32(nand->reg_base + DENALI_ECC_ENABLE, 0); mmio_write_32(nand->reg_base + DENALI_INTR_STATUS0, -1); uniphier_nand_host_write(nand, DENALI_MAP11_CMD, NAND_CMD_READ0); uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, column & 0xff); uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, (column >> 8) & 0xff); uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, page & 0xff); uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, (page >> 8) & 0xff); if (!nand->two_row_addr_cycles) uniphier_nand_host_write(nand, DENALI_MAP11_ADDR, (page >> 16) & 0xff); uniphier_nand_host_write(nand, DENALI_MAP11_CMD, NAND_CMD_READSTART); do { status = mmio_read_32(nand->reg_base + DENALI_INTR_STATUS0); } while (!(status & DENALI_INTR_INT_ACT)); bbm = uniphier_nand_host_read(nand, DENALI_MAP11_DATA); is_bad = bbm != 0xff; /* if possible, save the result for future re-use */ if (block < ARRAY_SIZE(nand->bbt)) nand->bbt[block] = is_bad; if (is_bad) WARN("found bad block at %d. skip.\n", block); return is_bad; } static int uniphier_nand_read_pages(struct uniphier_nand *nand, uintptr_t buf, int page_start, int page_count) { uint32_t status; mmio_write_32(nand->reg_base + DENALI_ECC_ENABLE, 1); mmio_write_32(nand->reg_base + DENALI_DMA_ENABLE, 1); mmio_write_32(nand->reg_base + DENALI_INTR_STATUS0, -1); /* use Data DMA (64bit) */ mmio_write_32(nand->host_base + DENALI_HOST_ADDR, DENALI_MAP10 | page_start); /* * 1. setup transfer type, interrupt when complete, * burst len = 64 bytes, the number of pages */ mmio_write_32(nand->host_base + DENALI_HOST_DATA, 0x01002000 | (64 << 16) | page_count); /* 2. set memory low address */ mmio_write_32(nand->host_base + DENALI_HOST_DATA, buf); /* 3. set memory high address */ mmio_write_32(nand->host_base + DENALI_HOST_DATA, buf >> 32); do { status = mmio_read_32(nand->reg_base + DENALI_INTR_STATUS0); } while (!(status & DENALI_INTR_DMA_CMD_COMP)); mmio_write_32(nand->reg_base + DENALI_DMA_ENABLE, 0); if (status & DENALI_INTR_ECC_UNCOR_ERR) { ERROR("uncorrectable error in page range %d-%d", page_start, page_start + page_count - 1); return -EBADMSG; } return 0; } static size_t __uniphier_nand_read(struct uniphier_nand *nand, int lba, uintptr_t buf, size_t size) { int pages_per_block = nand->pages_per_block; int page_size = nand->page_size; int blocks_to_skip = lba / pages_per_block; int pages_to_read = div_round_up(size, page_size); int page = lba % pages_per_block; int block = 0; uintptr_t p = buf; int page_count, ret; while (blocks_to_skip) { ret = uniphier_nand_block_isbad(nand, block); if (ret < 0) goto out; if (!ret) blocks_to_skip--; block++; } while (pages_to_read) { ret = uniphier_nand_block_isbad(nand, block); if (ret < 0) goto out; if (ret) { block++; continue; } page_count = MIN(pages_per_block - page, pages_to_read); ret = uniphier_nand_read_pages(nand, p, block * pages_per_block + page, page_count); if (ret) goto out; block++; page = 0; p += page_size * page_count; pages_to_read -= page_count; } out: /* number of read bytes */ return MIN(size, p - buf); } static size_t uniphier_nand_read(int lba, uintptr_t buf, size_t size) { size_t count; inv_dcache_range(buf, size); count = __uniphier_nand_read(&uniphier_nand, lba, buf, size); inv_dcache_range(buf, size); return count; } static struct io_block_dev_spec uniphier_nand_dev_spec = { .buffer = { .offset = UNIPHIER_BLOCK_BUF_BASE, .length = UNIPHIER_BLOCK_BUF_SIZE, }, .ops = { .read = uniphier_nand_read, }, /* fill .block_size at run-time */ }; static int uniphier_nand_hw_init(struct uniphier_nand *nand) { int i; for (i = 0; i < ARRAY_SIZE(nand->bbt); i++) nand->bbt[i] = UNIPHIER_NAND_BBT_UNKNOWN; nand->host_base = 0x68000000; nand->reg_base = 0x68100000; nand->pages_per_block = mmio_read_32(nand->reg_base + DENALI_PAGES_PER_BLOCK); nand->page_size = mmio_read_32(nand->reg_base + DENALI_DEVICE_MAIN_AREA_SIZE); if (mmio_read_32(nand->reg_base + DENALI_TWO_ROW_ADDR_CYCLES) & BIT(0)) nand->two_row_addr_cycles = 1; uniphier_nand_host_write(nand, DENALI_MAP10, DENALI_ACCESS_DEFAULT_AREA); return 0; } int uniphier_nand_init(uintptr_t *block_dev_spec) { int ret; ret = uniphier_nand_hw_init(&uniphier_nand); if (ret) return ret; uniphier_nand_dev_spec.block_size = uniphier_nand.page_size; *block_dev_spec = (uintptr_t)&uniphier_nand_dev_spec; return 0; } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_psci.c000066400000000000000000000064261355360272700247240ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "uniphier.h" #define UNIPHIER_ROM_RSV0 0x59801200 #define UNIPHIER_SLFRSTSEL 0x61843010 #define UNIPHIER_SLFRSTSEL_MASK GENMASK(1, 0) #define UNIPHIER_SLFRSTCTL 0x61843014 #define UNIPHIER_SLFRSTCTL_RST BIT(0) #define MPIDR_AFFINITY_INVALID ((u_register_t)-1) uintptr_t uniphier_sec_entrypoint; void uniphier_warmboot_entrypoint(void); void __dead2 uniphier_fake_pwr_down(void); u_register_t uniphier_holding_pen_release; static int uniphier_psci_scp_mode; static int uniphier_psci_pwr_domain_on(u_register_t mpidr) { uniphier_holding_pen_release = mpidr; flush_dcache_range((uint64_t)&uniphier_holding_pen_release, sizeof(uniphier_holding_pen_release)); mmio_write_64(UNIPHIER_ROM_RSV0, (uint64_t)&uniphier_warmboot_entrypoint); sev(); return PSCI_E_SUCCESS; } static void uniphier_psci_pwr_domain_off(const psci_power_state_t *target_state) { uniphier_gic_cpuif_disable(); } static void uniphier_psci_pwr_domain_on_finish( const psci_power_state_t *target_state) { uniphier_gic_pcpu_init(); uniphier_gic_cpuif_enable(); uniphier_cci_enable(); } static void __dead2 uniphier_psci_pwr_domain_pwr_down_wfi( const psci_power_state_t *target_state) { /* * The Boot ROM cannot distinguish warm and cold resets. * Instead of the CPU reset, fake it. */ uniphier_holding_pen_release = MPIDR_AFFINITY_INVALID; flush_dcache_range((uint64_t)&uniphier_holding_pen_release, sizeof(uniphier_holding_pen_release)); uniphier_fake_pwr_down(); } static void uniphier_self_system_reset(void) { mmio_clrbits_32(UNIPHIER_SLFRSTSEL, UNIPHIER_SLFRSTSEL_MASK); mmio_setbits_32(UNIPHIER_SLFRSTCTL, UNIPHIER_SLFRSTCTL_RST); } static void __dead2 uniphier_psci_system_off(void) { if (uniphier_psci_scp_mode) { uniphier_scp_system_off(); } else { NOTICE("SCP is disabled; can't shutdown the system.\n"); NOTICE("Resetting the system instead.\n"); uniphier_self_system_reset(); } wfi(); ERROR("UniPhier System Off: operation not handled.\n"); panic(); } static void __dead2 uniphier_psci_system_reset(void) { if (uniphier_psci_scp_mode) uniphier_scp_system_reset(); else uniphier_self_system_reset(); wfi(); ERROR("UniPhier System Reset: operation not handled.\n"); panic(); } static const struct plat_psci_ops uniphier_psci_ops = { .pwr_domain_on = uniphier_psci_pwr_domain_on, .pwr_domain_off = uniphier_psci_pwr_domain_off, .pwr_domain_on_finish = uniphier_psci_pwr_domain_on_finish, .pwr_domain_pwr_down_wfi = uniphier_psci_pwr_domain_pwr_down_wfi, .system_off = uniphier_psci_system_off, .system_reset = uniphier_psci_system_reset, }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const struct plat_psci_ops **psci_ops) { uniphier_sec_entrypoint = sec_entrypoint; flush_dcache_range((uint64_t)&uniphier_sec_entrypoint, sizeof(uniphier_sec_entrypoint)); uniphier_psci_scp_mode = uniphier_scp_is_running(); flush_dcache_range((uint64_t)&uniphier_psci_scp_mode, sizeof(uniphier_psci_scp_mode)); if (uniphier_psci_scp_mode) uniphier_scp_open_com(); *psci_ops = &uniphier_psci_ops; return 0; } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_rotpk.S000066400000000000000000000007071355360272700251010ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ .global uniphier_rotpk_hash .global uniphier_rotpk_hash_end .section .rodata.uniphier_rotpk_hash, "a" uniphier_rotpk_hash: /* DER header */ .byte 0x30, 0x31, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48 .byte 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20 /* SHA256 */ .incbin ROTPK_HASH uniphier_rotpk_hash_end: trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_scp.c000066400000000000000000000046261355360272700245530ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "uniphier.h" #define UNIPHIER_ROM_RSV3 0x5980120c #define UNIPHIER_STMBE2COM 0x5f800030 #define UNIPHIER_STMTOBEIRQ 0x5f800060 #define UNIPHIER_BETOSTMIRQ0PT 0x5f800070 #define UNIPHIER_BEIRQCLRPT 0x5f800072 #define UNIPHIER_SCP_READY_MAGIC 0x0000b6a5 #define UNIPHIER_SCP_PACKET_START 0xA0 #define UNIPHIER_SCP_PACKET_END 0xA5 #define UNIPHIER_SCP_PACKET_ESC 0xA6 #define UNIPHIER_SCP_IS_CTRL_CODE(c) (0xA0 <= (c) && (c) <= 0xA6) int uniphier_scp_is_running(void) { return mmio_read_32(UNIPHIER_STMBE2COM) == UNIPHIER_SCP_READY_MAGIC; } void uniphier_scp_start(void) { uint32_t tmp; mmio_write_32(UNIPHIER_STMBE2COM + 4, UNIPHIER_SCP_BASE); mmio_write_32(UNIPHIER_STMBE2COM, UNIPHIER_SCP_READY_MAGIC); do { tmp = mmio_read_32(UNIPHIER_ROM_RSV3); } while (!(tmp & BIT(8))); mmio_write_32(UNIPHIER_ROM_RSV3, tmp | BIT(9)); } static void uniphier_scp_send_packet(const uint8_t *packet, int packet_len) { uintptr_t reg = UNIPHIER_STMBE2COM; uint32_t word; int len, i; while (packet_len) { len = MIN(packet_len, 4); word = 0; for (i = 0; i < len; i++) word |= *packet++ << (8 * i); mmio_write_32(reg, word); reg += 4; packet_len -= len; } mmio_write_8(UNIPHIER_BETOSTMIRQ0PT, 0x55); while (!(mmio_read_32(UNIPHIER_STMTOBEIRQ) & BIT(1))) ; mmio_write_8(UNIPHIER_BEIRQCLRPT, BIT(1) | BIT(0)); } static void uniphier_scp_send_cmd(const uint8_t *cmd, int cmd_len) { uint8_t packet[32]; /* long enough */ uint8_t *p = packet; uint8_t c; int i; *p++ = UNIPHIER_SCP_PACKET_START; *p++ = cmd_len; for (i = 0; i < cmd_len; i++) { c = *cmd++; if (UNIPHIER_SCP_IS_CTRL_CODE(c)) { *p++ = UNIPHIER_SCP_PACKET_ESC; *p++ = c ^ BIT(7); } else { *p++ = c; } } *p++ = UNIPHIER_SCP_PACKET_END; uniphier_scp_send_packet(packet, p - packet); } #define UNIPHIER_SCP_CMD(name, ...) \ static const uint8_t __uniphier_scp_##name##_cmd[] = { \ __VA_ARGS__ \ }; \ void uniphier_scp_##name(void) \ { \ uniphier_scp_send_cmd(__uniphier_scp_##name##_cmd, \ ARRAY_SIZE(__uniphier_scp_##name##_cmd)); \ } UNIPHIER_SCP_CMD(open_com, 0x00, 0x00, 0x05) UNIPHIER_SCP_CMD(system_off, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0x01) UNIPHIER_SCP_CMD(system_reset, 0x00, 0x02, 0x00) trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_smp.S000066400000000000000000000011421355360272700245330ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include .globl uniphier_warmboot_entrypoint .globl uniphier_fake_pwr_down func uniphier_warmboot_entrypoint mrs x0, mpidr_el1 mov_imm x1, MPIDR_AFFINITY_MASK and x0, x0, x1 b 1f 0: wfe 1: ldr x1, uniphier_holding_pen_release cmp x1, x0 b.ne 0b ldr x0, uniphier_sec_entrypoint br x0 endfunc uniphier_warmboot_entrypoint func uniphier_fake_pwr_down bl disable_mmu_icache_el3 b uniphier_warmboot_entrypoint endfunc uniphier_fake_pwr_down trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_soc_info.c000066400000000000000000000016651355360272700255650ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "uniphier.h" #define UNIPHIER_REVISION 0x5f800000 static unsigned int uniphier_get_revision_field(unsigned int mask, unsigned int shift) { uint32_t revision = mmio_read_32(UNIPHIER_REVISION); return (revision >> shift) & mask; } unsigned int uniphier_get_soc_type(void) { return uniphier_get_revision_field(0xff, 16); } unsigned int uniphier_get_soc_model(void) { return uniphier_get_revision_field(0x07, 8); } unsigned int uniphier_get_soc_revision(void) { return uniphier_get_revision_field(0x1f, 0); } unsigned int uniphier_get_soc_id(void) { uint32_t type = uniphier_get_soc_type(); switch (type) { case 0x31: return UNIPHIER_SOC_LD11; case 0x32: return UNIPHIER_SOC_LD20; case 0x35: return UNIPHIER_SOC_PXS3; default: return UNIPHIER_SOC_UNKNOWN; } } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_syscnt.c000066400000000000000000000003401355360272700252760ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include unsigned int plat_get_syscnt_freq2(void) { return 50000000; } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_tbbr.c000066400000000000000000000015321355360272700247100ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include extern char uniphier_rotpk_hash[], uniphier_rotpk_hash_end[]; int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, unsigned int *flags) { *key_ptr = uniphier_rotpk_hash; *key_len = uniphier_rotpk_hash_end - uniphier_rotpk_hash; *flags = ROTPK_IS_HASH; return 0; } int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr) { /* * No support for non-volatile counter. Update the ROT key to protect * the system against rollback. */ *nv_ctr = 0; return 0; } int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr) { return 0; } int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size) { return get_mbedtls_heap_helper(heap_addr, heap_size); } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_topology.c000066400000000000000000000016711355360272700256370ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "uniphier.h" static unsigned char uniphier_power_domain_tree_desc[UNIPHIER_CLUSTER_COUNT + 1]; const unsigned char *plat_get_power_domain_tree_desc(void) { int i; uniphier_power_domain_tree_desc[0] = UNIPHIER_CLUSTER_COUNT; for (i = 0; i < UNIPHIER_CLUSTER_COUNT; i++) uniphier_power_domain_tree_desc[i + 1] = UNIPHIER_MAX_CPUS_PER_CLUSTER; return uniphier_power_domain_tree_desc; } int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; cluster_id = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; if (cluster_id >= UNIPHIER_CLUSTER_COUNT) return -1; cpu_id = (mpidr >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; if (cpu_id >= UNIPHIER_MAX_CPUS_PER_CLUSTER) return -1; return uniphier_calc_core_pos(mpidr); } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_usb.c000066400000000000000000000100251355360272700245450ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "uniphier.h" #define UNIPHIER_LD11_USB_DESC_BASE 0x30010000 #define UNIPHIER_LD20_USB_DESC_BASE 0x30014000 #define UNIPHIER_PXS3_USB_DESC_BASE 0x30014000 #define UNIPHIER_SRB_OCM_CONT 0x61200000 struct uniphier_ld11_trans_op { uint8_t __pad[48]; }; struct uniphier_ld11_op { uint8_t __pad[56]; struct uniphier_ld11_trans_op *trans_op; void *__pad2; void *dev_desc; }; struct uniphier_ld20_trans_op { uint8_t __pad[40]; }; struct uniphier_ld20_op { uint8_t __pad[192]; struct uniphier_ld20_trans_op *trans_op; void *__pad2; void *dev_desc; }; struct uniphier_pxs3_op { uint8_t __pad[184]; struct uniphier_ld20_trans_op *trans_op; void *__pad2; void *dev_desc; }; static int (*__uniphier_usb_read)(int lba, uintptr_t buf, size_t size); static void uniphier_ld11_usb_init(void) { struct uniphier_ld11_op *op = (void *)UNIPHIER_LD11_USB_DESC_BASE; op->trans_op = (void *)(op + 1); op->dev_desc = op->trans_op + 1; } static int uniphier_ld11_usb_read(int lba, uintptr_t buf, size_t size) { static int (*rom_usb_read)(uintptr_t desc, unsigned int lba, unsigned int size, uintptr_t buf); uintptr_t func_addr; func_addr = uniphier_get_soc_revision() == 1 ? 0x3880 : 0x3958; rom_usb_read = (__typeof(rom_usb_read))func_addr; return rom_usb_read(UNIPHIER_LD11_USB_DESC_BASE, lba, size, buf); } static void uniphier_ld20_usb_init(void) { struct uniphier_ld20_op *op = (void *)UNIPHIER_LD20_USB_DESC_BASE; op->trans_op = (void *)(op + 1); op->dev_desc = op->trans_op + 1; } static int uniphier_ld20_usb_read(int lba, uintptr_t buf, size_t size) { static int (*rom_usb_read)(uintptr_t desc, unsigned int lba, unsigned int size, uintptr_t buf); int ret; rom_usb_read = (__typeof(rom_usb_read))0x37f0; mmio_write_32(UNIPHIER_SRB_OCM_CONT, 0x1ff); /* ROM-API - return 1 on success, 0 on error */ ret = rom_usb_read(UNIPHIER_LD20_USB_DESC_BASE, lba, size, buf); mmio_write_32(UNIPHIER_SRB_OCM_CONT, 0); return ret ? 0 : -1; } static void uniphier_pxs3_usb_init(void) { struct uniphier_pxs3_op *op = (void *)UNIPHIER_PXS3_USB_DESC_BASE; op->trans_op = (void *)(op + 1); op->dev_desc = op->trans_op + 1; } static int uniphier_pxs3_usb_read(int lba, uintptr_t buf, size_t size) { static int (*rom_usb_read)(uintptr_t desc, unsigned int lba, unsigned int size, uintptr_t buf); int ret; rom_usb_read = (__typeof(rom_usb_read))0x39e8; /* ROM-API - return 1 on success, 0 on error */ ret = rom_usb_read(UNIPHIER_PXS3_USB_DESC_BASE, lba, size, buf); return ret ? 0 : -1; } struct uniphier_usb_rom_param { void (*init)(void); int (*read)(int lba, uintptr_t buf, size_t size); }; static const struct uniphier_usb_rom_param uniphier_usb_rom_params[] = { [UNIPHIER_SOC_LD11] = { .init = uniphier_ld11_usb_init, .read = uniphier_ld11_usb_read, }, [UNIPHIER_SOC_LD20] = { .init = uniphier_ld20_usb_init, .read = uniphier_ld20_usb_read, }, [UNIPHIER_SOC_PXS3] = { .init = uniphier_pxs3_usb_init, .read = uniphier_pxs3_usb_read, }, }; static size_t uniphier_usb_read(int lba, uintptr_t buf, size_t size) { int ret; inv_dcache_range(buf, size); ret = __uniphier_usb_read(lba, buf, size); inv_dcache_range(buf, size); return ret ? 0 : size; } static struct io_block_dev_spec uniphier_usb_dev_spec = { .buffer = { .offset = UNIPHIER_BLOCK_BUF_BASE, .length = UNIPHIER_BLOCK_BUF_SIZE, }, .ops = { .read = uniphier_usb_read, }, .block_size = 512, }; int uniphier_usb_init(unsigned int soc, uintptr_t *block_dev_spec) { const struct uniphier_usb_rom_param *param; assert(soc < ARRAY_SIZE(uniphier_usb_rom_params)); param = &uniphier_usb_rom_params[soc]; if (param->init) param->init(); __uniphier_usb_read = param->read; *block_dev_spec = (uintptr_t)&uniphier_usb_dev_spec; return 0; } trusted-firmware-a-2.2/plat/socionext/uniphier/uniphier_xlat_setup.c000066400000000000000000000025631355360272700261540ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #define UNIPHIER_REG_REGION_BASE 0x50000000ULL #define UNIPHIER_REG_REGION_SIZE 0x20000000ULL void uniphier_mmap_setup(uintptr_t total_base, size_t total_size, const struct mmap_region *mmap) { VERBOSE("Trusted RAM seen by this BL image: %p - %p\n", (void *)total_base, (void *)(total_base + total_size)); mmap_add_region(total_base, total_base, total_size, MT_MEMORY | MT_RW | MT_SECURE); /* remap the code section */ VERBOSE("Code region: %p - %p\n", (void *)BL_CODE_BASE, (void *)BL_CODE_END); mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, round_up(BL_CODE_END, PAGE_SIZE) - BL_CODE_BASE, MT_CODE | MT_SECURE); /* remap the coherent memory region */ VERBOSE("Coherent region: %p - %p\n", (void *)BL_COHERENT_RAM_BASE, (void *)BL_COHERENT_RAM_END); mmap_add_region(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, MT_DEVICE | MT_RW | MT_SECURE); /* register region */ mmap_add_region(UNIPHIER_REG_REGION_BASE, UNIPHIER_REG_REGION_BASE, UNIPHIER_REG_REGION_SIZE, MT_DEVICE | MT_RW | MT_SECURE); /* additional regions if needed */ if (mmap) mmap_add(mmap); init_xlat_tables(); } trusted-firmware-a-2.2/plat/st/000077500000000000000000000000001355360272700164775ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/st/common/000077500000000000000000000000001355360272700177675ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/st/common/bl2_io_storage.c000066400000000000000000000213661355360272700230350ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* IO devices */ static const io_dev_connector_t *dummy_dev_con; static uintptr_t dummy_dev_handle; static uintptr_t dummy_dev_spec; static uintptr_t image_dev_handle; 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, }; static uintptr_t storage_dev_handle; static const io_dev_connector_t *mmc_dev_con; #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 }, [GPT_IMAGE_ID] = { .dev_handle = &storage_dev_handle, .image_spec = (uintptr_t)&gpt_block_spec, .check = open_storage }, [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; 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 boot_mmc(enum mmc_device_type mmc_dev_type, uint16_t boot_interface_instance) { int io_result __unused; uint8_t idx; struct stm32image_part_info *part; struct stm32_sdmmc2_params params; struct mmc_device_info device_info; const partition_entry_t *entry; zeromem(&device_info, sizeof(struct mmc_device_info)); zeromem(¶ms, sizeof(struct stm32_sdmmc2_params)); device_info.mmc_dev_type = mmc_dev_type; switch (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"); if (mmc_dev_type == MMC_IS_SD) { params.reg_base = STM32MP_SDMMC1_BASE; } else { params.reg_base = STM32MP_SDMMC2_BASE; } break; } params.device_info = &device_info; if (stm32_sdmmc2_mmc_init(¶ms) != 0) { ERROR("SDMMC%u init failed\n", 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); } void stm32mp_io_setup(void) { int io_result __unused; 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: dmbsy(); boot_mmc(MMC_IS_SD, boot_context->boot_interface_instance); break; case BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC: dmbsy(); boot_mmc(MMC_IS_EMMC, boot_context->boot_interface_instance); break; 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; } trusted-firmware-a-2.2/plat/st/common/include/000077500000000000000000000000001355360272700214125ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/st/common/include/stm32mp_auth.h000066400000000000000000000010441355360272700241100ustar00rootroot00000000000000/* * Copyright (c) 2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32MP_AUTH_H #define STM32MP_AUTH_H struct stm32mp_auth_ops { uint32_t (*check_key)(uint8_t *pubkey_in, uint8_t *pubkey_out); uint32_t (*verify_signature)(uint8_t *hash_in, uint8_t *pubkey_in, uint8_t *signature, uint32_t ecc_algo); }; void stm32mp_init_auth(struct stm32mp_auth_ops *init_ptr); int stm32mp_auth_image(boot_api_image_header_t *header, uintptr_t buffer); #endif /* STM32MP_AUTH_H */ trusted-firmware-a-2.2/plat/st/common/include/stm32mp_common.h000066400000000000000000000055211355360272700244430ustar00rootroot00000000000000/* * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32MP_COMMON_H #define STM32MP_COMMON_H #include #include /* Functions to save and get boot context address given by ROM code */ void stm32mp_save_boot_ctx_address(uintptr_t address); uintptr_t stm32mp_get_boot_ctx_address(void); bool stm32mp_is_single_core(void); bool stm32mp_is_closed_device(void); /* Return the base address of the DDR controller */ uintptr_t stm32mp_ddrctrl_base(void); /* Return the base address of the DDR PHY */ uintptr_t stm32mp_ddrphyc_base(void); /* Return the base address of the PWR peripheral */ uintptr_t stm32mp_pwr_base(void); /* Return the base address of the RCC peripheral */ uintptr_t stm32mp_rcc_base(void); /* Check MMU status to allow spinlock use */ bool stm32mp_lock_available(void); /* Get IWDG platform instance ID from peripheral IO memory base address */ uint32_t stm32_iwdg_get_instance(uintptr_t base); /* Return bitflag mask for expected IWDG configuration from OTP content */ uint32_t stm32_iwdg_get_otp_config(uint32_t iwdg_inst); #if defined(IMAGE_BL2) /* Update OTP shadow registers with IWDG configuration from device tree */ uint32_t stm32_iwdg_shadow_update(uint32_t iwdg_inst, uint32_t flags); #endif /* * Platform util functions for the GPIO driver * @bank: Target GPIO bank ID as per DT bindings * * Platform shall implement these functions to provide to stm32_gpio * driver the resource reference for a target GPIO bank. That are * memory mapped interface base address, interface offset (see below) * and clock identifier. * * stm32_get_gpio_bank_offset() returns a bank offset that is used to * check DT configuration matches platform implementation of the banks * description. */ uintptr_t stm32_get_gpio_bank_base(unsigned int bank); unsigned long stm32_get_gpio_bank_clock(unsigned int bank); uint32_t stm32_get_gpio_bank_offset(unsigned int bank); /* Print CPU information */ void stm32mp_print_cpuinfo(void); /* Print board information */ void stm32mp_print_boardinfo(void); /* * Util for clock gating and to get clock rate for stm32 and platform drivers * @id: Target clock ID, ID used in clock DT bindings */ bool stm32mp_clk_is_enabled(unsigned long id); void stm32mp_clk_enable(unsigned long id); void stm32mp_clk_disable(unsigned long id); unsigned long stm32mp_clk_get_rate(unsigned long id); /* Initialise the IO layer and register platform IO devices */ void stm32mp_io_setup(void); /* * Check that the STM32 header of a .stm32 binary image is valid * @param header: pointer to the stm32 image header * @param buffer: address of the binary image (payload) * @return: 0 on success, negative value in case of error */ int stm32mp_check_header(boot_api_image_header_t *header, uintptr_t buffer); #endif /* STM32MP_COMMON_H */ trusted-firmware-a-2.2/plat/st/common/include/stm32mp_dt.h000066400000000000000000000026421355360272700235630ustar00rootroot00000000000000/* * 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 #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; uint32_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); 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_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); #endif /* STM32MP_DT_H */ trusted-firmware-a-2.2/plat/st/common/include/stm32mp_shres_helpers.h000066400000000000000000000032731355360272700260230ustar00rootroot00000000000000/* * Copyright (C) 2018-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32MP_SHRES_HELPERS_H #define STM32MP_SHRES_HELPERS_H #include #include /* * 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) ? 1 : 0; *refcnt &= ~SHREFCNT_NONSECURE_FLAG; } return rc; } static inline int stm32mp_incr_refcnt(unsigned int *refcnt) { return stm32mp_incr_shrefcnt(refcnt, true); } static inline int stm32mp_decr_refcnt(unsigned int *refcnt) { return stm32mp_decr_shrefcnt(refcnt, true); } #endif /* STM32MP_SHRES_HELPERS_H */ trusted-firmware-a-2.2/plat/st/common/stm32mp_auth.c000066400000000000000000000042161355360272700224640ustar00rootroot00000000000000/* * Copyright (c) 2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include static const struct stm32mp_auth_ops *auth_ops; void stm32mp_init_auth(struct stm32mp_auth_ops *init_ptr) { if ((init_ptr == NULL) || (init_ptr->check_key == NULL) || (init_ptr->verify_signature == NULL) || (stm32_hash_register() != 0)) { panic(); } auth_ops = init_ptr; } int stm32mp_auth_image(boot_api_image_header_t *header, uintptr_t buffer) { int ret; uint8_t image_hash[BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES]; uint32_t header_skip_cksum = sizeof(header->magic) + sizeof(header->image_signature) + sizeof(header->payload_checksum); /* Check Security Status */ if (!stm32mp_is_closed_device()) { if (header->option_flags != 0U) { WARN("Skip signature check (header option)\n"); return 0; } INFO("Check signature on Open device\n"); } ret = mmap_add_dynamic_region(STM32MP_ROM_BASE, STM32MP_ROM_BASE, STM32MP_ROM_SIZE, MT_CODE | MT_SECURE); if (ret != 0) { return ret; } /* Check Public Key */ if (auth_ops->check_key(header->ecc_pubk, NULL) != BOOT_API_RETURN_OK) { ret = -EINVAL; goto err; } /* Compute end of header hash and payload hash */ stm32_hash_init(HASH_SHA256); ret = stm32_hash_update((uint8_t *)&header->header_version, sizeof(boot_api_image_header_t) - header_skip_cksum); if (ret != 0) { ERROR("Hash of header failed, %i\n", ret); goto err; } ret = stm32_hash_final_update((uint8_t *)buffer, header->image_length, image_hash); if (ret != 0) { ERROR("Hash of payload failed\n"); goto err; } /* Verify signature */ if (auth_ops->verify_signature(image_hash, header->ecc_pubk, header->image_signature, header->ecc_algo_type) != BOOT_API_RETURN_OK) { ret = -EINVAL; } err: mmap_remove_dynamic_region(STM32MP_ROM_BASE, STM32MP_ROM_SIZE); return ret; } trusted-firmware-a-2.2/plat/st/common/stm32mp_common.c000066400000000000000000000053121355360272700230110ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include uintptr_t plat_get_ns_image_entrypoint(void) { return BL33_BASE; } unsigned int plat_get_syscnt_freq2(void) { return read_cntfrq_el0(); } 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; } 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; } bool stm32mp_lock_available(void) { const uint32_t c_m_bits = SCTLR_M_BIT | SCTLR_C_BIT; /* The spinlocks are used only when MMU and data cache are enabled */ return (read_sctlr() & c_m_bits) == c_m_bits; } uintptr_t stm32_get_gpio_bank_base(unsigned int bank) { if (bank == GPIO_BANK_Z) { return GPIOZ_BASE; } assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_K); return GPIOA_BASE + (bank * GPIO_BANK_OFFSET); } uint32_t stm32_get_gpio_bank_offset(unsigned int bank) { if (bank == GPIO_BANK_Z) { return 0; } assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_K); return bank * GPIO_BANK_OFFSET; } int stm32mp_check_header(boot_api_image_header_t *header, uintptr_t buffer) { uint32_t i; uint32_t img_checksum = 0U; /* * Check header/payload validity: * - Header magic * - Header version * - Payload checksum */ if (header->magic != BOOT_API_IMAGE_HEADER_MAGIC_NB) { ERROR("Header magic\n"); return -EINVAL; } if (header->header_version != BOOT_API_HEADER_VERSION) { ERROR("Header version\n"); return -EINVAL; } for (i = 0U; i < header->image_length; i++) { img_checksum += *(uint8_t *)(buffer + i); } if (header->payload_checksum != img_checksum) { ERROR("Checksum: 0x%x (awaited: 0x%x)\n", img_checksum, header->payload_checksum); return -EINVAL; } return 0; } trusted-firmware-a-2.2/plat/st/common/stm32mp_dt.c000066400000000000000000000272611355360272700221370ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include static int fdt_checked; static void *fdt = (void *)(uintptr_t)STM32MP_DTB_BASE; /******************************************************************************* * This function checks device tree file with its header. * Returns 0 on success and a negative FDT error code on failure. ******************************************************************************/ int dt_open_and_check(void) { int ret = fdt_check_header(fdt); if (ret == 0) { fdt_checked = 1; } return ret; } /******************************************************************************* * This function gets the address of the DT. * If DT is OK, fdt_addr is filled with DT address. * Returns 1 if success, 0 otherwise. ******************************************************************************/ int fdt_get_address(void **fdt_addr) { if (fdt_checked == 1) { *fdt_addr = fdt; } return fdt_checked; } /******************************************************************************* * This function check the presence of a node (generic use of fdt library). * Returns true if present, else return false. ******************************************************************************/ bool fdt_check_node(int node) { int len; const char *cchar; cchar = fdt_get_name(fdt, node, &len); return (cchar != NULL) && (len >= 0); } /******************************************************************************* * This function return global node status (generic use of fdt library). ******************************************************************************/ uint8_t fdt_get_status(int node) { uint8_t status = DT_DISABLED; int len; const char *cchar; cchar = fdt_getprop(fdt, node, "status", &len); if ((cchar == NULL) || (strncmp(cchar, "okay", (size_t)len) == 0)) { status |= DT_NON_SECURE; } cchar = fdt_getprop(fdt, node, "secure-status", &len); if (cchar == NULL) { if (status == DT_NON_SECURE) { status |= DT_SECURE; } } else if (strncmp(cchar, "okay", (size_t)len) == 0) { status |= DT_SECURE; } return status; } /******************************************************************************* * This function 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 gets the stdout path node. * It reads the value indicated inside the device tree. * Returns node offset 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, pwr_regulators_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; } pwr_regulators_node = fdt_subnode_offset(fdt, node, "pwr-regulators"); if (node < 0) { INFO("%s: Cannot read pwr-regulators node in DT\n", __func__); return 0; } cuint = fdt_getprop(fdt, pwr_regulators_node, "vdd-supply", NULL); 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); } trusted-firmware-a-2.2/plat/st/stm32mp1/000077500000000000000000000000001355360272700200655ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/st/stm32mp1/bl2_plat_setup.c000066400000000000000000000225231355360272700231540ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static struct console_stm32 console; static struct stm32mp_auth_ops stm32mp1_auth_ops; static void print_reset_reason(void) { 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"); } 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_pmic_status() > 0) { initialize_pmic(); } ret = stm32mp1_ddr_probe(); if (ret < 0) { ERROR("Invalid DDR init: error %d\n", ret); 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_uart_info; const char *board_model; boot_api_context_t *boot_context = (boot_api_context_t *)stm32mp_get_boot_ctx_address(); uint32_t clk_rate; uintptr_t pwr_base; uintptr_t rcc_base; mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, MT_CODE | MT_SECURE); #ifdef AARCH32_SP_OPTEE /* OP-TEE image needs post load processing: keep RAM read/write */ mmap_add_region(STM32MP_DDR_BASE + dt_get_ddr_size() - STM32MP_DDR_S_SIZE - STM32MP_DDR_SHMEM_SIZE, STM32MP_DDR_BASE + dt_get_ddr_size() - STM32MP_DDR_S_SIZE - STM32MP_DDR_SHMEM_SIZE, STM32MP_DDR_S_SIZE, MT_MEMORY | MT_RW | MT_SECURE); mmap_add_region(STM32MP_OPTEE_BASE, STM32MP_OPTEE_BASE, STM32MP_OPTEE_SIZE, MT_MEMORY | MT_RW | MT_SECURE); #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(); /* * 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); while ((mmio_read_32(pwr_base + PWR_CR1) & PWR_CR1_DBP) == 0U) { ; } 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); while ((mmio_read_32(rcc_base + RCC_BDCR) & RCC_BDCR_VSWRST) == 0U) { ; } mmio_clrbits_32(rcc_base + RCC_BDCR, RCC_BDCR_VSWRST); } /* Disable MCKPROT */ mmio_clrbits_32(rcc_base + RCC_TZCR, RCC_TZCR_MCKPROT); generic_delay_timer_init(); if (stm32mp1_clk_probe() < 0) { panic(); } if (stm32mp1_clk_init() < 0) { panic(); } stm32mp1_syscfg_init(); result = dt_get_stdout_uart_info(&dt_uart_info); if ((result <= 0) || (dt_uart_info.status == 0U) || (dt_uart_info.clock < 0) || (dt_uart_info.reset < 0)) { goto skip_console_init; } if (dt_set_stdout_pinctrl() != 0) { goto skip_console_init; } stm32mp_clk_enable((unsigned long)dt_uart_info.clock); stm32mp_reset_assert((uint32_t)dt_uart_info.reset); udelay(2); stm32mp_reset_deassert((uint32_t)dt_uart_info.reset); mdelay(1); clk_rate = stm32mp_clk_get_rate((unsigned long)dt_uart_info.clock); if (console_stm32_register(dt_uart_info.base, clk_rate, STM32MP_UART_BAUDRATE, &console) == 0) { panic(); } console_set_scope(&console.console, CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH | CONSOLE_FLAG_TRANSLATE_CRLF); stm32mp_print_cpuinfo(); board_model = dt_get_board_model(); if (board_model != NULL) { NOTICE("Model: %s\n", board_model); } stm32mp_print_boardinfo(); if (boot_context->auth_status != BOOT_API_CTX_AUTH_NO) { NOTICE("Bootrom authentication %s\n", (boot_context->auth_status == BOOT_API_CTX_AUTH_FAILED) ? "failed" : "succeeded"); } skip_console_init: if (stm32_iwdg_init() < 0) { panic(); } stm32_iwdg_refresh(); result = stm32mp1_dbgmcu_freeze_iwdg2(); if (result != 0) { INFO("IWDG2 freeze error : %i\n", result); } if (stm32_save_boot_interface(boot_context->boot_interface_selected, boot_context->boot_interface_instance) != 0) { ERROR("Cannot save boot interface\n"); } stm32mp1_auth_ops.check_key = boot_context->bootrom_ecdsa_check_key; stm32mp1_auth_ops.verify_signature = boot_context->bootrom_ecdsa_verify_signature; stm32mp_init_auth(&stm32mp1_auth_ops); stm32mp1_arch_security_setup(); print_reset_reason(); stm32mp_io_setup(); } #if defined(AARCH32_SP_OPTEE) /******************************************************************************* * 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); bl_mem_params_node_t *bl32_mem_params; bl_mem_params_node_t *pager_mem_params; bl_mem_params_node_t *paged_mem_params; assert(bl_mem_params != NULL); switch (image_id) { case BL32_IMAGE_ID: bl_mem_params->ep_info.pc = bl_mem_params->image_info.image_base; pager_mem_params = get_bl_mem_params_node(BL32_EXTRA1_IMAGE_ID); assert(pager_mem_params != NULL); pager_mem_params->image_info.image_base = STM32MP_OPTEE_BASE; pager_mem_params->image_info.image_max_size = STM32MP_OPTEE_SIZE; paged_mem_params = get_bl_mem_params_node(BL32_EXTRA2_IMAGE_ID); assert(paged_mem_params != NULL); paged_mem_params->image_info.image_base = STM32MP_DDR_BASE + (dt_get_ddr_size() - STM32MP_DDR_S_SIZE - STM32MP_DDR_SHMEM_SIZE); paged_mem_params->image_info.image_max_size = STM32MP_DDR_S_SIZE; 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 */ break; case BL33_IMAGE_ID: bl32_mem_params = get_bl_mem_params_node(BL32_IMAGE_ID); assert(bl32_mem_params != NULL); bl32_mem_params->ep_info.lr_svc = bl_mem_params->ep_info.pc; break; default: /* Do nothing in default case */ break; } return err; } #endif trusted-firmware-a-2.2/plat/st/stm32mp1/include/000077500000000000000000000000001355360272700215105ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/st/stm32mp1/include/boot_api.h000066400000000000000000000200771355360272700234630ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BOOT_API_H #define BOOT_API_H #include #include /* * Possible value of boot context field 'auth_status' */ /* No authentication done */ #define BOOT_API_CTX_AUTH_NO 0x0U /* Authentication done and failed */ #define BOOT_API_CTX_AUTH_FAILED 0x1U /* Authentication done and succeeded */ #define BOOT_API_CTX_AUTH_SUCCESS 0x2U /* * Possible value of boot context field 'boot_interface_sel' */ /* Value of field 'boot_interface_sel' when no boot occurred */ #define BOOT_API_CTX_BOOT_INTERFACE_SEL_NO 0x0U /* Boot occurred on SD */ #define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_SD 0x1U /* Boot occurred on EMMC */ #define BOOT_API_CTX_BOOT_INTERFACE_SEL_FLASH_EMMC 0x2U /** * @brief Possible value of boot context field 'EmmcXferStatus' */ /* * Possible value of boot context field 'emmc_xfer_status' */ #define BOOT_API_CTX_EMMC_XFER_STATUS_NOT_STARTED 0x0U #define BOOT_API_CTX_EMMC_XFER_STATUS_DATAEND_DETECTED 0x1U #define BOOT_API_CTX_EMMC_XFER_STATUS_XFER_OVERALL_TIMEOUT_DETECTED 0x2U #define BOOT_API_CTX_EMMC_XFER_STATUS_XFER_DATA_TIMEOUT 0x3U /* * Possible value of boot context field 'emmc_error_status' */ #define BOOT_API_CTX_EMMC_ERROR_STATUS_NONE 0x0U #define BOOT_API_CTX_EMMC_ERROR_STATUS_CMD_TIMEOUT 0x1U #define BOOT_API_CTX_EMMC_ERROR_STATUS_ACK_TIMEOUT 0x2U #define BOOT_API_CTX_EMMC_ERROR_STATUS_DATA_CRC_FAIL 0x3U #define BOOT_API_CTX_EMMC_ERROR_STATUS_NOT_ENOUGH_BOOT_DATA_RX 0x4U #define BOOT_API_CTX_EMMC_ERROR_STATUS_HEADER_NOT_FOUND 0x5U #define BOOT_API_CTX_EMMC_ERROR_STATUS_HEADER_SIZE_ZERO 0x6U #define BOOT_API_CTX_EMMC_ERROR_STATUS_IMAGE_NOT_COMPLETE 0x7U /* Image Header related definitions */ /* Definition of header version */ #define BOOT_API_HEADER_VERSION 0x00010000U /* * Magic number used to detect header in memory * Its value must be 'S' 'T' 'M' 0x32, i.e 0x324D5453 as field * 'bootapi_image_header_t.magic' * This identifies the start of a boot image. */ #define BOOT_API_IMAGE_HEADER_MAGIC_NB 0x324D5453U /* Definitions related to Authentication used in image header structure */ #define BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES 64 #define BOOT_API_ECDSA_SIGNATURE_LEN_IN_BYTES 64 #define BOOT_API_SHA256_DIGEST_SIZE_IN_BYTES 32 /* Possible values of the field 'boot_api_image_header_t.ecc_algo_type' */ #define BOOT_API_ECDSA_ALGO_TYPE_P256NIST 1 #define BOOT_API_ECDSA_ALGO_TYPE_BRAINPOOL256 2 /* * Cores secure magic numbers * Constant to be stored in bakcup register * BOOT_API_MAGIC_NUMBER_TAMP_BCK_REG_IDX */ #define BOOT_API_A7_CORE0_MAGIC_NUMBER 0xCA7FACE0U #define BOOT_API_A7_CORE1_MAGIC_NUMBER 0xCA7FACE1U /* * 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 */ #define BOOT_API_CORE1_MAGIC_NUMBER_TAMP_BCK_REG_IDX 4U /* * TAMP_BCK5R register index * This register is used to contain the branch address of * Cortex A7 Core 1 when restarted by a TAMP_BCK4R magic number writing */ #define BOOT_API_CORE1_BRANCH_ADDRESS_TAMP_BCK_REG_IDX 5U /* * Possible value of boot context field 'hse_clock_value_in_hz' */ #define BOOT_API_CTX_HSE_CLOCK_VALUE_UNDEFINED 0U #define BOOT_API_CTX_HSE_CLOCK_VALUE_24_MHZ 24000000U #define BOOT_API_CTX_HSE_CLOCK_VALUE_25_MHZ 25000000U #define BOOT_API_CTX_HSE_CLOCK_VALUE_26_MHZ 26000000U /* * Possible value of boot context field 'boot_partition_used_toboot' */ #define BOOT_API_CTX_BOOT_PARTITION_UNDEFINED 0U /* Used FSBL1 to boot */ #define BOOT_API_CTX_BOOT_PARTITION_FSBL1 1U /* Used FSBL2 to boot */ #define BOOT_API_CTX_BOOT_PARTITION_FSBL2 2U /* OTP_CFG0 */ #define BOOT_API_OTP_MODE_WORD_NB 0 /* Closed = OTP_CFG0[6] */ #define BOOT_API_OTP_MODE_CLOSED_BIT_POS 6 #define BOOT_API_RETURN_OK 0x66U /* * Boot Context related definitions */ /* * Boot core boot configuration structure * Specifies all items of the cold boot configuration * Memory and peripheral part. */ typedef struct { /* * Boot interface used to boot : take values from defines * BOOT_API_CTX_BOOT_INTERFACE_SEL_XXX above */ uint16_t boot_interface_selected; uint16_t boot_interface_instance; uint32_t reserved1[13]; uint32_t otp_afmux_values[3]; uint32_t reserved[5]; uint32_t auth_status; /* * Pointers to bootROM External Secure Services * - ECDSA check key * - ECDSA verify signature * - ECDSA verify signature and go */ uint32_t (*bootrom_ecdsa_check_key)(uint8_t *pubkey_in, uint8_t *pubkey_out); uint32_t (*bootrom_ecdsa_verify_signature)(uint8_t *hash_in, uint8_t *pubkey_in, uint8_t *signature, uint32_t ecc_algo); uint32_t (*bootrom_ecdsa_verify_and_go)(uint8_t *hash_in, uint8_t *pub_key_in, uint8_t *signature, uint32_t ecc_algo, uint32_t *entry_in); /* * Information specific to an SD boot * Updated each time an SD boot is at least attempted, * even if not successful * Note : This is useful to understand why an SD boot failed * in particular */ uint32_t sd_err_internal_timeout_cnt; uint32_t sd_err_dcrc_fail_cnt; uint32_t sd_err_dtimeout_cnt; uint32_t sd_err_ctimeout_cnt; uint32_t sd_err_ccrc_fail_cnt; uint32_t sd_overall_retry_cnt; /* * Information specific to an eMMC boot * Updated each time an eMMC boot is at least attempted, * even if not successful * Note : This is useful to understand why an eMMC boot failed * in particular */ uint32_t emmc_xfer_status; uint32_t emmc_error_status; uint32_t emmc_nbbytes_rxcopied_tosysram_download_area; uint32_t hse_clock_value_in_hz; /* * Boot partition : * ie FSBL partition on which the boot was successful */ uint32_t boot_partition_used_toboot; } __packed boot_api_context_t; /* * Image Header related definitions */ /* * Structure used to define the common Header format used for FSBL, xloader, * ... and in particular used by bootROM for FSBL header readout. * FSBL header size is 256 Bytes = 0x100 */ typedef struct { /* BOOT_API_IMAGE_HEADER_MAGIC_NB */ uint32_t magic; uint8_t image_signature[BOOT_API_ECDSA_SIGNATURE_LEN_IN_BYTES]; /* * Checksum of payload * 32-bit sum all all payload bytes considered as 8 bit unigned numbers, * discarding any overflow bits. * Use to check UART/USB downloaded image integrity when signature * is not used (i.e bit 0 : 'No_sig_check' = 1 in option flags) */ uint32_t payload_checksum; /* Image header version : should have value BOOT_API_HEADER_VERSION */ uint32_t header_version; /* Image length in bytes */ uint32_t image_length; /* * Image Entry point address : should be in the SYSRAM area * and at least within the download area range */ uint32_t image_entry_point; /* Reserved */ uint32_t reserved1; /* * Image load address : not used by bootROM but to be consistent * with header format for other packages (xloader, ...) */ uint32_t load_address; /* Reserved */ uint32_t reserved2; /* Image version to be compared by bootROM with monotonic * counter value in OTP_CFG4 prior executing the downloaded image */ uint32_t image_version; /* * Option flags: * Bit 0 : No signature check request : 'No_sig_check' * value 1 : for No signature check request * value 0 : No request to bypass the signature check * Note : No signature check is never allowed on a Secured chip */ uint32_t option_flags; /* * Type of ECC algorithm to use : * value 1 : for P-256 NIST algorithm * value 2 : for Brainpool 256 algorithm * See definitions 'BOOT_API_ECDSA_ALGO_TYPE_XXX' above. */ uint32_t ecc_algo_type; /* * OEM ECC Public Key (aka Root pubk) provided in header on 512 bits. * The SHA-256 hash of the OEM ECC pubk must match the one stored * in OTP cells. */ uint8_t ecc_pubk[BOOT_API_ECDSA_PUB_KEY_LEN_IN_BYTES]; /* Pad up to 256 byte total size */ uint8_t pad[83]; /* Add binary type information */ uint8_t binary_type; } __packed boot_api_image_header_t; #endif /* BOOT_API_H */ trusted-firmware-a-2.2/plat/st/stm32mp1/include/platform_def.h000066400000000000000000000154021355360272700243250ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include #include "../stm32mp1_def.h" /******************************************************************************* * Generic platform constants ******************************************************************************/ /* Size of cacheable stacks */ #if defined(IMAGE_BL32) #define PLATFORM_STACK_SIZE 0x600 #else #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 STM32MP_PRIMARY_CPU U(0x0) #define STM32MP_SECONDARY_CPU U(0x1) #define PLATFORM_CLUSTER_COUNT ULL(1) #define PLATFORM_CLUSTER0_CORE_COUNT U(2) #define PLATFORM_CLUSTER1_CORE_COUNT U(0) #define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER1_CORE_COUNT + \ PLATFORM_CLUSTER0_CORE_COUNT) #define PLATFORM_MAX_CPUS_PER_CLUSTER 2 #define MAX_IO_DEVICES U(4) #define MAX_IO_HANDLES U(4) #define MAX_IO_BLOCK_DEVICES U(1) /******************************************************************************* * BL2 specific defines. ******************************************************************************/ /* * 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 STM32MP_BL2_BASE #define BL2_LIMIT (STM32MP_BL2_BASE + \ STM32MP_BL2_SIZE) /******************************************************************************* * BL32 specific defines. ******************************************************************************/ #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 STM32MP_BL33_BASE /* * Load address of BL33 for this platform port */ #define PLAT_STM32MP_NS_IMAGE_OFFSET BL33_BASE /******************************************************************************* * DTB specific defines. ******************************************************************************/ #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 (ULL(1) << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 32) /******************************************************************************* * Declarations and constants to access the mailboxes safely. Each mailbox is * aligned on the biggest cache line size in the platform. This is known only * to the platform as it might have a combination of integrated and external * caches. Such alignment ensures that two maiboxes do not sit on the same cache * line at any cache level. They could belong to different cpus/clusters & * get written while being protected by different locks causing corruption of * a valid mailbox address. ******************************************************************************/ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (U(1) << CACHE_WRITEBACK_SHIFT) /* * Secure Interrupt: based on the standard ARM mapping */ #define ARM_IRQ_SEC_PHY_TIMER U(29) #define ARM_IRQ_SEC_SGI_0 U(8) #define ARM_IRQ_SEC_SGI_1 U(9) #define ARM_IRQ_SEC_SGI_2 U(10) #define ARM_IRQ_SEC_SGI_3 U(11) #define ARM_IRQ_SEC_SGI_4 U(12) #define ARM_IRQ_SEC_SGI_5 U(13) #define ARM_IRQ_SEC_SGI_6 U(14) #define ARM_IRQ_SEC_SGI_7 U(15) #define STM32MP1_IRQ_TZC400 U(36) #define STM32MP1_IRQ_TAMPSERRS U(229) #define STM32MP1_IRQ_AXIERRIRQ U(244) /* * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 * terminology. On a GICv2 system or mode, the lists will be merged and treated * as Group 0 interrupts. */ #define PLATFORM_G1S_PROPS(grp) \ INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, \ GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(STM32MP1_IRQ_AXIERRIRQ, \ GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(STM32MP1_IRQ_TZC400, \ GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, \ GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, \ GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, \ GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, \ GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, \ GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, \ GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE) #define PLATFORM_G0_PROPS(grp) \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, \ GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, \ GIC_HIGHEST_SEC_PRIORITY, \ grp, GIC_INTR_CFG_EDGE) /* * Power */ #define PLAT_MAX_PWR_LVL U(1) /* Local power state for power domains in Run state. */ #define ARM_LOCAL_STATE_RUN U(0) /* Local power state for retention. Valid only for CPU power domains */ #define ARM_LOCAL_STATE_RET U(1) /* Local power state for power-down. Valid for CPU and cluster power domains */ #define ARM_LOCAL_STATE_OFF U(2) /* * This macro defines the deepest retention state possible. * A higher state id will represent an invalid or a power down state. */ #define PLAT_MAX_RET_STATE ARM_LOCAL_STATE_RET /* * This macro defines the deepest power down states possible. Any state ID * higher than this is invalid. */ #define PLAT_MAX_OFF_STATE ARM_LOCAL_STATE_OFF /******************************************************************************* * Size of the per-cpu data in bytes that should be reserved in the generic * per-cpu data structure for the FVP port. ******************************************************************************/ #define PLAT_PCPU_DATA_SIZE 2 #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/st/stm32mp1/include/stm32mp1_context.h000066400000000000000000000004661355360272700250210ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32MP1_CONTEXT_H #define STM32MP1_CONTEXT_H #include int stm32_save_boot_interface(uint32_t interface, uint32_t instance); #endif /* STM32MP1_CONTEXT_H */ trusted-firmware-a-2.2/plat/st/stm32mp1/include/stm32mp1_dbgmcu.h000066400000000000000000000011271355360272700245710ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32MP1_DBGMCU_H #define STM32MP1_DBGMCU_H #include /* Get chip version and ID from DBGMCU registers */ int stm32mp1_dbgmcu_get_chip_version(uint32_t *chip_version); int stm32mp1_dbgmcu_get_chip_dev_id(uint32_t *chip_dev_id); /* * Freeze watchdog when a debugger is attached, if the security configuration * allows it. * Return 0 on success, a negative error value otherwise. */ int stm32mp1_dbgmcu_freeze_iwdg2(void); #endif /* STM32MP1_DBGMCU_H */ trusted-firmware-a-2.2/plat/st/stm32mp1/include/stm32mp1_private.h000066400000000000000000000010431355360272700247770ustar00rootroot00000000000000/* * 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 #include void configure_mmu(void); void stm32mp1_arch_security_setup(void); void stm32mp1_security_setup(void); void stm32mp1_gic_pcpu_init(void); void stm32mp1_gic_init(void); void stm32mp1_syscfg_init(void); void stm32mp1_syscfg_enable_io_compensation(void); void stm32mp1_syscfg_disable_io_compensation(void); #endif /* STM32MP1_PRIVATE_H */ trusted-firmware-a-2.2/plat/st/stm32mp1/include/stm32mp1_smc.h000066400000000000000000000025641355360272700241200ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32MP1_SMC_H #define STM32MP1_SMC_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 */ /* * STM32_SMC_BSEC call API * * Argument a0: (input) SMCC ID * (output) status return code * Argument a1: (input) Service ID (STM32_SMC_BSEC_xxx) * Argument a2: (input) OTP index * (output) OTP read value, if applicable * Argument a3: (input) OTP value if applicable */ #define STM32_SMC_BSEC 0x82001003 /* 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 4 /* 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 #endif /* STM32MP1_SMC_H */ trusted-firmware-a-2.2/plat/st/stm32mp1/plat_bl2_mem_params_desc.c000066400000000000000000000062221355360272700251310ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /******************************************************************************* * Following descriptor provides BL image/ep information that gets used * by BL2 to load the images and also subset of this information is * passed to next BL image. The image loading sequence is managed by * populating the images in required loading order. The image execution * sequence is managed by populating the `next_handoff_image_id` with * the next executable image id. ******************************************************************************/ static bl_mem_params_node_t bl2_mem_params_descs[] = { /* Fill BL32 related information */ { .image_id = BL32_IMAGE_ID, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, 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), 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 in 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, SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), .ep_info.pc = PLAT_STM32MP_NS_IMAGE_OFFSET, .ep_info.spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS), SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, VERSION_2, image_info_t, 0), .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, } }; REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) trusted-firmware-a-2.2/plat/st/stm32mp1/plat_image_load.c000066400000000000000000000022251355360272700233330ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /******************************************************************************* * This function flushes the data structures so that they are visible * in memory for the next BL image. ******************************************************************************/ void plat_flush_next_bl_params(void) { flush_bl_params_desc(); } /******************************************************************************* * This function returns the list of loadable images. ******************************************************************************/ bl_load_info_t *plat_get_bl_image_load_info(void) { return get_bl_load_info_from_mem_params_desc(); } /******************************************************************************* * This function returns the list of executable images. ******************************************************************************/ bl_params_t *plat_get_next_bl_params(void) { return get_next_bl_params_from_mem_params_desc(); } trusted-firmware-a-2.2/plat/st/stm32mp1/platform.mk000066400000000000000000000126061355360272700222470ustar00rootroot00000000000000# # Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ARM_CORTEX_A7 := yes ARM_WITH_NEON := yes BL2_AT_EL3 := 1 USE_COHERENT_MEM := 0 STM32_TF_VERSION ?= 0 # Not needed for Cortex-A7 WORKAROUND_CVE_2017_5715:= 0 # 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)) PLAT_INCLUDES := -Iplat/st/common/include/ PLAT_INCLUDES += -Iplat/st/stm32mp1/include/ # Device tree 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/common/stm32mp_common.c \ plat/st/stm32mp1/stm32mp1_private.c PLAT_BL_COMMON_SOURCES += drivers/st/uart/aarch32/stm32_console.S ifneq (${ENABLE_STACK_PROTECTOR},0) PLAT_BL_COMMON_SOURCES += plat/st/stm32mp1/stm32mp1_stack_protector.c endif include lib/xlat_tables_v2/xlat_tables.mk PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS} PLAT_BL_COMMON_SOURCES += lib/cpus/aarch32/cortex_a7.S PLAT_BL_COMMON_SOURCES += drivers/arm/tzc/tzc400.c \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/st/bsec/bsec.c \ drivers/st/clk/stm32mp_clkfunc.c \ drivers/st/clk/stm32mp1_clk.c \ drivers/st/ddr/stm32mp1_ddr_helpers.c \ drivers/st/gpio/stm32_gpio.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/stm32mp1/stm32mp1_context.c \ plat/st/stm32mp1/stm32mp1_dbgmcu.c \ plat/st/stm32mp1/stm32mp1_helper.S \ plat/st/stm32mp1/stm32mp1_security.c \ plat/st/stm32mp1/stm32mp1_syscfg.c BL2_SOURCES += drivers/io/io_block.c \ drivers/io/io_dummy.c \ drivers/io/io_storage.c \ drivers/st/crypto/stm32_hash.c \ drivers/st/io/io_stm32image.c \ plat/st/common/stm32mp_auth.c \ plat/st/common/bl2_io_storage.c \ plat/st/stm32mp1/bl2_plat_setup.c 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 BL2_SOURCES += drivers/st/ddr/stm32mp1_ddr.c \ drivers/st/ddr/stm32mp1_ram.c BL2_SOURCES += common/desc_image_load.c \ plat/st/stm32mp1/plat_bl2_mem_params_desc.c \ plat/st/stm32mp1/plat_image_load.c ifeq ($(AARCH32_SP),optee) BL2_SOURCES += lib/optee/optee_utils.c endif # Macros and rules to build TF binary STM32_TF_ELF_LDFLAGS := --hash-style=gnu --as-needed 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/${DTB_FILE_NAME} STM32_TF_OBJS := ${BUILD_PLAT}/stm32mp1.o BL2_CFLAGS += -DPLAT_XLAT_TABLES_DYNAMIC=1 # Variables for use with stm32image STM32IMAGEPATH ?= tools/stm32image STM32IMAGE ?= ${STM32IMAGEPATH}/stm32image${BIN_EXT} .PHONY: ${STM32_TF_STM32} .SUFFIXES: all: check_dtc_version ${STM32_TF_STM32} stm32image ifeq ($(AARCH32_SP),sp_min) # BL32 is built only if using SP_MIN BL32_DEP := bl32 BL32_PATH := -DBL32_BIN_PATH=\"${BUILD_PLAT}/bl32.bin\" endif distclean realclean clean: clean_stm32image stm32image: ${Q}${MAKE} CPPFLAGS="" --no-print-directory -C ${STM32IMAGEPATH} clean_stm32image: ${Q}${MAKE} --no-print-directory -C ${STM32IMAGEPATH} clean check_dtc_version: $(eval DTC_V = $(shell $(DTC) -v | awk '{print $$NF}')) $(eval DTC_VERSION = $(shell printf "%d" $(shell echo ${DTC_V} | cut -d- -f1 | sed "s/\./0/g"))) @if [ ${DTC_VERSION} -lt 10404 ]; then \ echo "dtc version too old (${DTC_V}), you need at least version 1.4.4"; \ false; \ fi ${STM32_TF_OBJS}: plat/st/stm32mp1/stm32mp1.S bl2 ${BL32_DEP} ${STM32_TF_DTBFILE} @echo " AS $<" ${Q}${AS} ${ASFLAGS} ${TF_CFLAGS} \ ${BL32_PATH} \ -DBL2_BIN_PATH=\"${BUILD_PLAT}/bl2.bin\" \ -DDTB_BIN_PATH=\"${STM32_TF_DTBFILE}\" \ -c plat/st/stm32mp1/stm32mp1.S -o $@ ${STM32_TF_LINKERFILE}: plat/st/stm32mp1/stm32mp1.ld.S ${BUILD_PLAT} @echo " LDS $<" ${Q}${AS} ${ASFLAGS} ${TF_CFLAGS} -P -E $< -o $@ ${STM32_TF_ELF}: ${STM32_TF_OBJS} ${STM32_TF_LINKERFILE} @echo " LDS $<" ${Q}${LD} -o $@ ${STM32_TF_ELF_LDFLAGS} -Map=${STM32_TF_MAPFILE} --script ${STM32_TF_LINKERFILE} ${STM32_TF_OBJS} ${STM32_TF_BINARY}: ${STM32_TF_ELF} ${Q}${OC} -O binary ${STM32_TF_ELF} $@ @echo @echo "Built $@ successfully" @echo ${STM32_TF_STM32}: stm32image ${STM32_TF_BINARY} @echo @echo "Generated $@" $(eval LOADADDR = $(shell cat ${STM32_TF_MAPFILE} | grep RAM | awk '{print $$2}')) $(eval ENTRY = $(shell cat ${STM32_TF_MAPFILE} | grep "__BL2_IMAGE_START" | awk '{print $$1}')) ${STM32IMAGE} -s ${STM32_TF_BINARY} -d $@ -l $(LOADADDR) -e ${ENTRY} -v ${STM32_TF_VERSION} @echo trusted-firmware-a-2.2/plat/st/stm32mp1/services/000077500000000000000000000000001355360272700217105ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/st/stm32mp1/services/bsec_svc.c000066400000000000000000000021011355360272700236350ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "bsec_svc.h" 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; 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; 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; default: result = BSEC_ERROR; break; } return result; } trusted-firmware-a-2.2/plat/st/stm32mp1/services/bsec_svc.h000066400000000000000000000006401355360272700236500ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BSEC_SVC_H #define BSEC_SVC_H #include /* version of this service */ /* must be increase at each structure modification */ #define BSEC_SERVICE_VERSION 0x01U uint32_t bsec_main(uint32_t x1, uint32_t x2, uint32_t x3, uint32_t *ret_otp_value); #endif /* BSEC_SVC_H */ trusted-firmware-a-2.2/plat/st/stm32mp1/services/stm32mp1_svc_setup.c000066400000000000000000000037461355360272700255470ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "bsec_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; 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 ); trusted-firmware-a-2.2/plat/st/stm32mp1/sp_min/000077500000000000000000000000001355360272700213525ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/st/stm32mp1/sp_min/sp_min-stm32mp1.mk000066400000000000000000000013721355360272700245570ustar00rootroot00000000000000# # Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # SP_MIN_WITH_SECURE_FIQ := 1 BL32_SOURCES += plat/common/aarch32/platform_mp_stack.S \ plat/st/stm32mp1/sp_min/sp_min_setup.c \ plat/st/stm32mp1/stm32mp1_pm.c \ plat/st/stm32mp1/stm32mp1_topology.c # Generic GIC v2 BL32_SOURCES += drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_helpers.c \ drivers/arm/gic/v2/gicv2_main.c \ plat/common/plat_gicv2.c \ plat/st/stm32mp1/stm32mp1_gic.c # 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/stm32mp1_svc_setup.c trusted-firmware-a-2.2/plat/st/stm32mp1/sp_min/sp_min_setup.c000066400000000000000000000113701355360272700242250ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /****************************************************************************** * Placeholder variables for copying the arguments that have been passed to * BL32 from BL2. ******************************************************************************/ static entry_point_info_t bl33_image_ep_info; static struct console_stm32 console; /******************************************************************************* * Interrupt handler for FIQ (secure IRQ) ******************************************************************************/ void sp_min_plat_fiq_handler(uint32_t id) { switch (id & INT_ID_MASK) { case STM32MP1_IRQ_TZC400: ERROR("STM32MP1_IRQ_TZC400 generated\n"); panic(); break; case STM32MP1_IRQ_AXIERRIRQ: ERROR("STM32MP1_IRQ_AXIERRIRQ generated\n"); panic(); break; default: ERROR("SECURE IT handler not define for it : %u", id); break; } } /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image for * the security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. ******************************************************************************/ entry_point_info_t *sp_min_plat_get_bl33_ep_info(void) { entry_point_info_t *next_image_info; next_image_info = &bl33_image_ep_info; if (next_image_info->pc == 0U) { return NULL; } return next_image_info; } /******************************************************************************* * Perform any BL32 specific platform actions. ******************************************************************************/ void sp_min_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { struct dt_node_info dt_uart_info; int result; bl_params_t *params_from_bl2 = (bl_params_t *)arg0; /* Imprecise aborts can be masked in NonSecure */ write_scr(read_scr() | SCR_AW_BIT); mmap_add_region(BL_CODE_BASE, BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, MT_CODE | MT_SECURE); configure_mmu(); assert(params_from_bl2 != NULL); assert(params_from_bl2->h.type == PARAM_BL_PARAMS); assert(params_from_bl2->h.version >= VERSION_2); bl_params_node_t *bl_params = params_from_bl2->head; /* * Copy BL33 entry point information. * They are stored in Secure RAM, in BL2's address space. */ while (bl_params != NULL) { if (bl_params->image_id == BL33_IMAGE_ID) { bl33_image_ep_info = *bl_params->ep_info; break; } bl_params = bl_params->next_params_info; } if (dt_open_and_check() < 0) { panic(); } if (bsec_probe() != 0) { panic(); } if (stm32mp1_clk_probe() < 0) { panic(); } result = dt_get_stdout_uart_info(&dt_uart_info); if ((result > 0) && (dt_uart_info.status != 0U)) { unsigned int console_flags; if (console_stm32_register(dt_uart_info.base, 0, STM32MP_UART_BAUDRATE, &console) == 0) { panic(); } console_flags = CONSOLE_FLAG_BOOT | CONSOLE_FLAG_CRASH | CONSOLE_FLAG_TRANSLATE_CRLF; #ifdef DEBUG console_flags |= CONSOLE_FLAG_RUNTIME; #endif console_set_scope(&console.console, console_flags); } } /******************************************************************************* * Initialize the MMU, security and the GIC. ******************************************************************************/ void sp_min_platform_setup(void) { /* Initialize tzc400 after DDR initialization */ stm32mp1_security_setup(); generic_delay_timer_init(); stm32mp1_gic_init(); /* Unlock ETZPC securable peripherals */ #define STM32MP1_ETZPC_BASE 0x5C007000U #define ETZPC_DECPROT0 0x010U mmio_write_32(STM32MP1_ETZPC_BASE + ETZPC_DECPROT0, 0xFFFFFFFF); /* Set GPIO bank Z as non secure */ for (uint32_t pin = 0U; pin < STM32MP_GPIOZ_PIN_MAX_COUNT; pin++) { set_gpio_secure_cfg(GPIO_BANK_Z, pin, false); } if (stm32_iwdg_init() < 0) { panic(); } } void sp_min_plat_arch_setup(void) { } trusted-firmware-a-2.2/plat/st/stm32mp1/stm32mp1.S000066400000000000000000000004361355360272700216020ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifdef BL32_BIN_PATH .section .bl32_image .incbin BL32_BIN_PATH #endif .section .bl2_image .incbin BL2_BIN_PATH .section .dtb_image .incbin DTB_BIN_PATH trusted-firmware-a-2.2/plat/st/stm32mp1/stm32mp1.ld.S000066400000000000000000000036151355360272700222020ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32MP1_LD_S #define STM32MP1_LD_S #include #include OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT) OUTPUT_ARCH(PLATFORM_LINKER_ARCH) ENTRY(__BL2_IMAGE_START__) MEMORY { HEADER (rw) : ORIGIN = 0x00000000, LENGTH = 0x3000 RAM (rwx) : ORIGIN = STM32MP_BINARY_BASE, LENGTH = STM32MP_BINARY_SIZE } SECTIONS { /* * TF mapping must conform to ROM code specification. */ .header : { __HEADER_START__ = .; KEEP(*(.header)) . = ALIGN(4); __HEADER_END__ = .; } >HEADER . = STM32MP_BINARY_BASE; .data . : { . = ALIGN(PAGE_SIZE); __DATA_START__ = .; *(.data*) /* * dtb. * The strongest and only alignment contraint is MMU 4K page. * Indeed as images below will be removed, 4K pages will be re-used. */ . = ( STM32MP_DTB_BASE - STM32MP_BINARY_BASE ); __DTB_IMAGE_START__ = .; *(.dtb_image*) __DTB_IMAGE_END__ = .; /* * bl2. * The strongest and only alignment contraint is MMU 4K page. * Indeed as images below will be removed, 4K pages will be re-used. */ . = ( 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. */ . = ( STM32MP_BL32_BASE - STM32MP_BINARY_BASE ); __BL32_IMAGE_START__ = .; *(.bl32_image*) __BL32_IMAGE_END__ = .; #endif __DATA_END__ = .; } >RAM __TF_END__ = .; } #endif /* STM32MP1_LD_S */ trusted-firmware-a-2.2/plat/st/stm32mp1/stm32mp1_context.c000066400000000000000000000014121355360272700233610ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #define TAMP_BOOT_ITF_BACKUP_REG_ID U(20) #define TAMP_BOOT_ITF_MASK U(0x0000FF00) #define TAMP_BOOT_ITF_SHIFT 8 int stm32_save_boot_interface(uint32_t interface, uint32_t instance) { uint32_t bkpr_itf_idx = tamp_bkpr(TAMP_BOOT_ITF_BACKUP_REG_ID); stm32mp_clk_enable(RTCAPB); mmio_clrsetbits_32(bkpr_itf_idx, TAMP_BOOT_ITF_MASK, ((interface << 4) | (instance & 0xFU)) << TAMP_BOOT_ITF_SHIFT); stm32mp_clk_disable(RTCAPB); return 0; } trusted-firmware-a-2.2/plat/st/stm32mp1/stm32mp1_dbgmcu.c000066400000000000000000000035251355360272700231450ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #define DBGMCU_IDC U(0x00) #define DBGMCU_APB4FZ1 U(0x2C) #define DBGMCU_IDC_DEV_ID_MASK GENMASK(11, 0) #define DBGMCU_IDC_REV_ID_MASK GENMASK(31, 16) #define DBGMCU_IDC_REV_ID_SHIFT 16 #define DBGMCU_APB4FZ1_IWDG2 BIT(2) 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 -1; } } mmio_setbits_32(rcc_base + RCC_DBGCFGR, RCC_DBGCFGR_DBGCKEN); return 0; } int stm32mp1_dbgmcu_get_chip_version(uint32_t *chip_version) { if (stm32mp1_dbgmcu_init() != 0) { return -EPERM; } *chip_version = (mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) & DBGMCU_IDC_REV_ID_MASK) >> DBGMCU_IDC_REV_ID_SHIFT; return 0; } int stm32mp1_dbgmcu_get_chip_dev_id(uint32_t *chip_dev_id) { if (stm32mp1_dbgmcu_init() != 0) { return -EPERM; } *chip_dev_id = mmio_read_32(DBGMCU_BASE + DBGMCU_IDC) & DBGMCU_IDC_DEV_ID_MASK; return 0; } int stm32mp1_dbgmcu_freeze_iwdg2(void) { uint32_t dbg_conf; if (stm32mp1_dbgmcu_init() != 0) { return -EPERM; } dbg_conf = bsec_read_debug_conf(); if ((dbg_conf & (BSEC_SPIDEN | BSEC_SPINDEN)) != 0U) { mmio_setbits_32(DBGMCU_BASE + DBGMCU_APB4FZ1, DBGMCU_APB4FZ1_IWDG2); } return 0; } trusted-firmware-a-2.2/plat/st/stm32mp1/stm32mp1_def.h000066400000000000000000000260631355360272700224510ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef STM32MP1_DEF_H #define STM32MP1_DEF_H #include #include #include #include #include #include #ifndef __ASSEMBLER__ #include #include #include #include #include #include #include #include #include #endif /******************************************************************************* * 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_B U(0x2000) /******************************************************************************* * PACKAGE ID ******************************************************************************/ #define PKG_AA_LFBGA448 U(4) #define PKG_AB_LFBGA354 U(3) #define PKG_AC_TFBGA361 U(2) #define PKG_AD_TFBGA257 U(1) /******************************************************************************* * 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) /* DDR configuration */ #define STM32MP_DDR_BASE U(0xC0000000) #define STM32MP_DDR_MAX_SIZE U(0x40000000) /* Max 1GB */ #ifdef AARCH32_SP_OPTEE #define STM32MP_DDR_S_SIZE U(0x01E00000) /* 30 MB */ #define STM32MP_DDR_SHMEM_SIZE U(0x00200000) /* 2 MB */ #endif /* DDR power initializations */ #ifndef __ASSEMBLER__ enum ddr_type { STM32MP_DDR3, STM32MP_LPDDR2, STM32MP_LPDDR3 }; #endif /* Section used inside TF binaries */ #define STM32MP_PARAM_LOAD_SIZE U(0x00002400) /* 9 Ko for param */ /* 256 Octets reserved for header */ #define STM32MP_HEADER_SIZE U(0x00000100) #define STM32MP_BINARY_BASE (STM32MP_SYSRAM_BASE + \ STM32MP_PARAM_LOAD_SIZE + \ STM32MP_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 STM32MP_BL32_SIZE U(0x00012000) /* 72 Ko for BL32 */ #else #define STM32MP_BL32_SIZE U(0x00011000) /* 68 Ko for BL32 */ #endif #endif #define STM32MP_BL32_BASE (STM32MP_SYSRAM_BASE + \ STM32MP_SYSRAM_SIZE - \ STM32MP_BL32_SIZE) #ifdef AARCH32_SP_OPTEE #if STACK_PROTECTOR_ENABLED #define STM32MP_BL2_SIZE U(0x00019000) /* 100 Ko for BL2 */ #else #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 STM32MP_BL2_BASE (STM32MP_BL32_BASE - \ STM32MP_BL2_SIZE) /* BL2 and BL32/sp_min require 5 tables */ #define MAX_XLAT_TABLES 5 /* * MAX_MMAP_REGIONS is usually: * BL stm32mp1_mmap size + mmap regions in *_plat_arch_setup */ #if defined(IMAGE_BL2) #define MAX_MMAP_REGIONS 11 #endif #if defined(IMAGE_BL32) #define MAX_MMAP_REGIONS 6 #endif /* DTB initialization value */ #define STM32MP_DTB_SIZE U(0x00005000) /* 20Ko for DTB */ #define STM32MP_DTB_BASE (STM32MP_BL2_BASE - \ STM32MP_DTB_SIZE) #define STM32MP_BL33_BASE (STM32MP_DDR_BASE + U(0x100000)) /******************************************************************************* * STM32MP1 device/io map related constants (used for MMU) ******************************************************************************/ #define STM32MP1_DEVICE1_BASE U(0x40000000) #define STM32MP1_DEVICE1_SIZE U(0x40000000) #define STM32MP1_DEVICE2_BASE U(0x80000000) #define STM32MP1_DEVICE2_SIZE U(0x40000000) /******************************************************************************* * STM32MP1 RCC ******************************************************************************/ #define RCC_BASE U(0x50000000) /******************************************************************************* * STM32MP1 PWR ******************************************************************************/ #define PWR_BASE U(0x50001000) /******************************************************************************* * 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) #define USART2_BASE U(0x4000E000) #define USART3_BASE U(0x4000F000) #define UART4_BASE U(0x40010000) #define UART5_BASE U(0x40011000) #define USART6_BASE U(0x44003000) #define UART7_BASE U(0x40018000) #define UART8_BASE U(0x40019000) #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 TZC (TZ400) ******************************************************************************/ #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) #define STM32MP1_TZC_DMA_ID U(6) #define STM32MP1_TZC_USB_HOST_ID U(7) #define STM32MP1_TZC_USB_OTG_ID U(8) #define STM32MP1_TZC_SDMMC_ID U(9) #define STM32MP1_TZC_ETH_ID U(10) #define STM32MP1_TZC_DAP_ID U(15) #define STM32MP1_FILTER_BIT_ALL U(3) /******************************************************************************* * STM32MP1 SDMMC ******************************************************************************/ #define STM32MP_SDMMC1_BASE U(0x58005000) #define STM32MP_SDMMC2_BASE U(0x58007000) #define STM32MP_SDMMC3_BASE U(0x48004000) #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 BSEC / OTP ******************************************************************************/ #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 PACKAGE_OTP U(16) #define HW2_OTP U(18) /* OTP mask */ /* DATA0 */ #define DATA0_OTP_SECURED BIT(6) /* PART NUMBER */ #define PART_NUMBER_OTP_PART_MASK GENMASK_32(7, 0) #define PART_NUMBER_OTP_PART_SHIFT 0 /* PACKAGE */ #define PACKAGE_OTP_PKG_MASK GENMASK_32(29, 27) #define PACKAGE_OTP_PKG_SHIFT 27 /* IWDG OTP */ #define HW2_OTP_IWDG_HW_POS U(3) #define HW2_OTP_IWDG_FZ_STOP_POS U(5) #define HW2_OTP_IWDG_FZ_STANDBY_POS U(7) /* HW2 OTP */ #define HW2_OTP_PRODUCT_BELOW_2V5 BIT(13) /******************************************************************************* * STM32MP1 TAMP ******************************************************************************/ #define TAMP_BASE U(0x5C00A000) #define TAMP_BKP_REGISTER_BASE (TAMP_BASE + U(0x100)) #if !(defined(__LINKER__) || defined(__ASSEMBLER__)) static inline uint32_t tamp_bkpr(uint32_t idx) { return TAMP_BKP_REGISTER_BASE + (idx << 2); } #endif /******************************************************************************* * STM32MP1 DDRCTRL ******************************************************************************/ #define DDRCTRL_BASE U(0x5A003000) /******************************************************************************* * STM32MP1 DDRPHYC ******************************************************************************/ #define DDRPHYC_BASE U(0x5A004000) /******************************************************************************* * 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 I2C4 ******************************************************************************/ #define I2C4_BASE U(0x5C002000) /******************************************************************************* * STM32MP1 DBGMCU ******************************************************************************/ #define DBGMCU_BASE U(0x50081000) /******************************************************************************* * Device Tree defines ******************************************************************************/ #define DT_BSEC_COMPAT "st,stm32mp15-bsec" #define DT_IWDG_COMPAT "st,stm32mp1-iwdg" #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 */ trusted-firmware-a-2.2/plat/st/stm32mp1/stm32mp1_gic.c000066400000000000000000000042131355360272700224410ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include struct stm32_gic_instance { uint32_t cells; uint32_t phandle_node; }; /****************************************************************************** * On a GICv2 system, the Group 1 secure interrupts are treated as Group 0 * interrupts. *****************************************************************************/ static const interrupt_prop_t stm32mp1_interrupt_props[] = { PLATFORM_G1S_PROPS(GICV2_INTR_GROUP0), PLATFORM_G0_PROPS(GICV2_INTR_GROUP0) }; /* Fix target_mask_array as secondary core is not able to initialize it */ static unsigned int target_mask_array[PLATFORM_CORE_COUNT] = {1, 2}; static gicv2_driver_data_t platform_gic_data = { .interrupt_props = stm32mp1_interrupt_props, .interrupt_props_num = ARRAY_SIZE(stm32mp1_interrupt_props), .target_masks = target_mask_array, .target_masks_num = ARRAY_SIZE(target_mask_array), }; static struct stm32_gic_instance stm32_gic; void stm32mp1_gic_init(void) { int node; void *fdt; const fdt32_t *cuint; struct dt_node_info dt_gic; if (fdt_get_address(&fdt) == 0) { panic(); } node = dt_get_node(&dt_gic, -1, "arm,cortex-a7-gic"); if (node < 0) { panic(); } platform_gic_data.gicd_base = dt_gic.base; cuint = fdt_getprop(fdt, node, "reg", NULL); if (cuint == NULL) { panic(); } platform_gic_data.gicc_base = fdt32_to_cpu(*(cuint + 2)); cuint = fdt_getprop(fdt, node, "#interrupt-cells", NULL); if (cuint == NULL) { panic(); } stm32_gic.cells = fdt32_to_cpu(*cuint); stm32_gic.phandle_node = fdt_get_phandle(fdt, node); if (stm32_gic.phandle_node == 0U) { panic(); } gicv2_driver_init(&platform_gic_data); gicv2_distif_init(); stm32mp1_gic_pcpu_init(); } void stm32mp1_gic_pcpu_init(void) { gicv2_pcpu_distif_init(); gicv2_set_pe_target_mask(plat_my_core_pos()); gicv2_cpuif_enable(); } trusted-firmware-a-2.2/plat/st/stm32mp1/stm32mp1_helper.S000066400000000000000000000117541355360272700231460ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #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 .globl plat_get_my_entrypoint .globl plat_secondary_cold_boot_setup .globl plat_reset_handler .globl plat_is_my_cpu_primary .globl plat_my_core_pos .globl plat_crash_console_init .globl plat_crash_console_flush .globl plat_crash_console_putc .globl plat_panic_handler func platform_mem_init /* Nothing to do, don't need to init SYSRAM */ bx lr endfunc platform_mem_init func plat_report_exception bx lr endfunc plat_report_exception func plat_reset_handler bx lr endfunc plat_reset_handler /* ------------------------------------------------------------------ * unsigned long plat_get_my_entrypoint (void); * * Main job of this routine is to distinguish between a cold and warm * boot. * * Currently supports only cold boot * ------------------------------------------------------------------ */ func plat_get_my_entrypoint mov r0, #0 bx lr endfunc plat_get_my_entrypoint /* --------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * Cold-booting secondary CPUs is not supported. * --------------------------------------------- */ func plat_secondary_cold_boot_setup b . endfunc plat_secondary_cold_boot_setup /* ----------------------------------------------------- * unsigned int plat_is_my_cpu_primary (void); * * Find out whether the current cpu is the primary cpu. * ----------------------------------------------------- */ func plat_is_my_cpu_primary ldcopr r0, MPIDR ldr r1, =(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK) and r0, r1 cmp r0, #STM32MP_PRIMARY_CPU moveq r0, #1 movne r0, #0 bx lr endfunc plat_is_my_cpu_primary /* ------------------------------------------- * int plat_stm32mp1_get_core_pos(int mpidr); * * Return CorePos = (ClusterId * 4) + CoreId * ------------------------------------------- */ func plat_stm32mp1_get_core_pos and r1, r0, #MPIDR_CPU_MASK and r0, r0, #MPIDR_CLUSTER_MASK add r0, r1, r0, LSR #6 bx lr endfunc plat_stm32mp1_get_core_pos /* ------------------------------------ * unsigned int plat_my_core_pos(void) * ------------------------------------ */ func plat_my_core_pos ldcopr r0, MPIDR b plat_stm32mp1_get_core_pos endfunc plat_my_core_pos /* --------------------------------------------- * int plat_crash_console_init(void) * * Initialize the crash console without a C Runtime stack. * --------------------------------------------- */ func plat_crash_console_init /* Enable GPIOs for UART TX */ ldr r1, =(RCC_BASE + DEBUG_UART_TX_GPIO_BANK_CLK_REG) ldr r2, [r1] /* Configure GPIO */ orr r2, r2, #DEBUG_UART_TX_GPIO_BANK_CLK_EN str r2, [r1] 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) orr r2, r2, #(GPIO_MODE_ALTERNATE << GPIO_TX_SHIFT) str r2, [r1, #GPIO_MODE_OFFSET] /* Set GPIO speed low */ ldr r2, [r1, #GPIO_SPEED_OFFSET] bic r2, r2, #(GPIO_SPEED_MASK << GPIO_TX_SHIFT) str r2, [r1, #GPIO_SPEED_OFFSET] /* Set no-pull */ ldr r2, [r1, #GPIO_PUPD_OFFSET] bic r2, r2, #(GPIO_PULL_MASK << GPIO_TX_SHIFT) str r2, [r1, #GPIO_PUPD_OFFSET] /* Set alternate */ ldr r2, [r1, #GPIO_AFRH_OFFSET] bic r2, r2, #(GPIO_ALTERNATE_MASK << GPIO_TX_ALT_SHIFT) orr r2, r2, #(DEBUG_UART_TX_GPIO_ALTERNATE << GPIO_TX_ALT_SHIFT) str r2, [r1, #GPIO_AFRH_OFFSET] /* 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 + DEBUG_UART_TX_EN_REG) ldr r2, [r1] orr r2, r2, #DEBUG_UART_TX_EN str r2, [r1] 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 /* --------------------------------------------- * int plat_crash_console_flush(void) * * Flush the crash console without a C Runtime stack. * --------------------------------------------- */ func plat_crash_console_flush ldr r1, =STM32MP_DEBUG_USART_BASE b console_stm32_core_flush endfunc plat_crash_console_flush /* --------------------------------------------- * int plat_crash_console_putc(int c) * * Print a character on the crash console without a C Runtime stack. * Clobber list : r1 - r3 * * In case of bootloading through uart, we keep console crash as this. * Characters could be sent to the programmer, but will be ignored. * No specific code in that case. * --------------------------------------------- */ func plat_crash_console_putc ldr r1, =STM32MP_DEBUG_USART_BASE b console_stm32_core_putc endfunc plat_crash_console_putc trusted-firmware-a-2.2/plat/st/stm32mp1/stm32mp1_pm.c000066400000000000000000000166331355360272700223240ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include static uintptr_t stm32_sec_entrypoint; static uint32_t cntfrq_core0; /******************************************************************************* * STM32MP1 handler called when a CPU is about to enter standby. * call by core 1 to enter in wfi ******************************************************************************/ static void stm32_cpu_standby(plat_local_state_t cpu_state) { uint32_t interrupt = GIC_SPURIOUS_INTERRUPT; assert(cpu_state == ARM_LOCAL_STATE_RET); /* * Enter standby state * dsb is good practice before using wfi to enter low power states */ isb(); dsb(); while (interrupt == GIC_SPURIOUS_INTERRUPT) { wfi(); /* Acknoledge IT */ interrupt = gicv2_acknowledge_interrupt(); /* If Interrupt == 1022 it will be acknowledged by non secure */ if ((interrupt != PENDING_G1_INTID) && (interrupt != GIC_SPURIOUS_INTERRUPT)) { gicv2_end_of_interrupt(interrupt); } } } /******************************************************************************* * 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 ******************************************************************************/ static int stm32_pwr_domain_on(u_register_t mpidr) { unsigned long current_cpu_mpidr = read_mpidr_el1(); 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); if (mpidr == current_cpu_mpidr) { return PSCI_E_INVALID_PARAMS; } if ((stm32_sec_entrypoint < STM32MP_SYSRAM_BASE) || (stm32_sec_entrypoint > (STM32MP_SYSRAM_BASE + (STM32MP_SYSRAM_SIZE - 1)))) { return PSCI_E_INVALID_ADDRESS; } stm32mp_clk_enable(RTCAPB); cntfrq_core0 = read_cntfrq_el0(); /* Write entrypoint in backup RAM register */ mmio_write_32(bkpr_core1_addr, stm32_sec_entrypoint); /* Write magic number in backup register */ mmio_write_32(bkpr_core1_magic, BOOT_API_A7_CORE1_MAGIC_NUMBER); stm32mp_clk_disable(RTCAPB); /* Generate an IT to core 1 */ gicv2_raise_sgi(ARM_IRQ_SEC_SGI_0, STM32MP_SECONDARY_CPU); return PSCI_E_SUCCESS; } /******************************************************************************* * STM32MP1 handler called when a power domain is about to be turned off. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ static void stm32_pwr_domain_off(const psci_power_state_t *target_state) { /* Nothing to do */ } /******************************************************************************* * STM32MP1 handler called when a power domain is about to be suspended. The * target_state encodes the power state that each level should transition to. ******************************************************************************/ static void stm32_pwr_domain_suspend(const psci_power_state_t *target_state) { /* Nothing to do, power domain is not disabled */ } /******************************************************************************* * STM32MP1 handler called when a power domain has just been powered on after * being turned off earlier. The target_state encodes the low power state that * each level has woken up from. * call by core 1 just after wake up ******************************************************************************/ static void stm32_pwr_domain_on_finish(const psci_power_state_t *target_state) { stm32mp1_gic_pcpu_init(); write_cntfrq_el0(cntfrq_core0); } /******************************************************************************* * STM32MP1 handler called when a power domain has just been powered on after * having been suspended earlier. The target_state encodes the low power state * that each level has woken up from. ******************************************************************************/ static void stm32_pwr_domain_suspend_finish(const psci_power_state_t *target_state) { /* Nothing to do, power domain is not disabled */ } 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"); panic(); } static void __dead2 stm32_system_off(void) { ERROR("stm32mpu1 System Off: operation not handled.\n"); panic(); } static void __dead2 stm32_system_reset(void) { mmio_setbits_32(stm32mp_rcc_base() + RCC_MP_GRSTCSETR, RCC_MP_GRSTCSETR_MPSYSRST); /* Loop in case system reset is not immediately caught */ for ( ; ; ) { ; } } static int stm32_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { int pstate = psci_get_pstate_type(power_state); if (pstate != 0) { return PSCI_E_INVALID_PARAMS; } if (psci_get_pstate_pwrlvl(power_state)) { return PSCI_E_INVALID_PARAMS; } if (psci_get_pstate_id(power_state)) { return PSCI_E_INVALID_PARAMS; } req_state->pwr_domain_state[0] = ARM_LOCAL_STATE_RET; req_state->pwr_domain_state[1] = ARM_LOCAL_STATE_RUN; return PSCI_E_SUCCESS; } static int stm32_validate_ns_entrypoint(uintptr_t entrypoint) { /* The non-secure entry point must be in DDR */ if (entrypoint < STM32MP_DDR_BASE) { return PSCI_E_INVALID_ADDRESS; } return PSCI_E_SUCCESS; } static int stm32_node_hw_state(u_register_t target_cpu, unsigned int power_level) { /* * The format of 'power_level' is implementation-defined, but 0 must * mean a CPU. Only allow level 0. */ if (power_level != MPIDR_AFFLVL0) { return PSCI_E_INVALID_PARAMS; } /* * From psci view the CPU 0 is always ON, * CPU 1 can be SUSPEND or RUNNING. * Therefore do not manage POWER OFF state and always return HW_ON. */ return (int)HW_ON; } /******************************************************************************* * Export the platform handlers. The ARM Standard platform layer will take care * of registering the handlers with PSCI. ******************************************************************************/ static const plat_psci_ops_t stm32_psci_ops = { .cpu_standby = stm32_cpu_standby, .pwr_domain_on = stm32_pwr_domain_on, .pwr_domain_off = stm32_pwr_domain_off, .pwr_domain_suspend = stm32_pwr_domain_suspend, .pwr_domain_on_finish = stm32_pwr_domain_on_finish, .pwr_domain_suspend_finish = stm32_pwr_domain_suspend_finish, .pwr_domain_pwr_down_wfi = stm32_pwr_domain_pwr_down_wfi, .system_off = stm32_system_off, .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 }; /******************************************************************************* * Export the platform specific power ops. ******************************************************************************/ int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { stm32_sec_entrypoint = sec_entrypoint; *psci_ops = &stm32_psci_ops; return 0; } trusted-firmware-a-2.2/plat/st/stm32mp1/stm32mp1_private.c000066400000000000000000000160441355360272700233560ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include /* Internal layout of the 32bit OTP word board_id */ #define BOARD_ID_BOARD_NB_MASK GENMASK(31, 16) #define BOARD_ID_BOARD_NB_SHIFT 16 #define BOARD_ID_VARIANT_MASK GENMASK(15, 12) #define BOARD_ID_VARIANT_SHIFT 12 #define BOARD_ID_REVISION_MASK GENMASK(11, 8) #define BOARD_ID_REVISION_SHIFT 8 #define BOARD_ID_BOM_MASK GENMASK(3, 0) #define BOARD_ID2NB(_id) (((_id) & BOARD_ID_BOARD_NB_MASK) >> \ BOARD_ID_BOARD_NB_SHIFT) #define BOARD_ID2VAR(_id) (((_id) & BOARD_ID_VARIANT_MASK) >> \ BOARD_ID_VARIANT_SHIFT) #define BOARD_ID2REV(_id) (((_id) & BOARD_ID_REVISION_MASK) >> \ BOARD_ID_REVISION_SHIFT) #define BOARD_ID2BOM(_id) ((_id) & BOARD_ID_BOM_MASK) #define MAP_SRAM MAP_REGION_FLAT(STM32MP_SYSRAM_BASE, \ STM32MP_SYSRAM_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) #if defined(IMAGE_BL2) static const mmap_region_t stm32mp1_mmap[] = { MAP_SRAM, MAP_DEVICE1, MAP_DEVICE2, {0} }; #endif #if defined(IMAGE_BL32) static const mmap_region_t stm32mp1_mmap[] = { MAP_SRAM, MAP_DEVICE1, MAP_DEVICE2, {0} }; #endif void configure_mmu(void) { mmap_add(stm32mp1_mmap); init_xlat_tables(); enable_mmu_svc_mon(0); } unsigned long stm32_get_gpio_bank_clock(unsigned int bank) { if (bank == GPIO_BANK_Z) { return GPIOZ; } assert(GPIO_BANK_A == 0 && bank <= GPIO_BANK_K); return GPIOA + (bank - GPIO_BANK_A); } static int get_part_number(uint32_t *part_nb) { uint32_t part_number; uint32_t dev_id; if (stm32mp1_dbgmcu_get_chip_dev_id(&dev_id) < 0) { return -1; } 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_NUMBER_OTP_PART_MASK) >> PART_NUMBER_OTP_PART_SHIFT; *part_nb = part_number | (dev_id << 16); return 0; } static int get_cpu_package(uint32_t *cpu_package) { uint32_t package; if (bsec_shadow_read_otp(&package, PACKAGE_OTP) != BSEC_OK) { ERROR("BSEC: PACKAGE_OTP Error\n"); return -1; } *cpu_package = (package & PACKAGE_OTP_PKG_MASK) >> PACKAGE_OTP_PKG_SHIFT; return 0; } void stm32mp_print_cpuinfo(void) { const char *cpu_s, *cpu_r, *pkg; uint32_t part_number; uint32_t cpu_package; uint32_t chip_dev_id; int ret; /* MPUs Part Numbers */ ret = get_part_number(&part_number); if (ret < 0) { WARN("Cannot get part number\n"); return; } switch (part_number) { 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 */ ret = get_cpu_package(&cpu_package); if (ret < 0) { WARN("Cannot get CPU package\n"); return; } switch (cpu_package) { case PKG_AA_LFBGA448: pkg = "AA"; break; case PKG_AB_LFBGA354: pkg = "AB"; break; case PKG_AC_TFBGA361: pkg = "AC"; break; case PKG_AD_TFBGA257: pkg = "AD"; break; default: pkg = "??"; break; } /* REVISION */ ret = stm32mp1_dbgmcu_get_chip_version(&chip_dev_id); if (ret < 0) { WARN("Cannot get CPU version\n"); return; } switch (chip_dev_id) { 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_id; uint32_t board_otp; int bsec_node, bsec_board_id_node; void *fdt; const fdt32_t *cuint; if (fdt_get_address(&fdt) == 0) { panic(); } bsec_node = fdt_node_offset_by_compatible(fdt, -1, DT_BSEC_COMPAT); if (bsec_node < 0) { return; } bsec_board_id_node = fdt_subnode_offset(fdt, bsec_node, "board_id"); if (bsec_board_id_node <= 0) { return; } cuint = fdt_getprop(fdt, bsec_board_id_node, "reg", NULL); if (cuint == NULL) { panic(); } board_otp = fdt32_to_cpu(*cuint) / sizeof(uint32_t); if (bsec_shadow_read_otp(&board_id, board_otp) != BSEC_OK) { ERROR("BSEC: PART_NUMBER_OTP Error\n"); return; } if (board_id != 0U) { char rev[2]; rev[0] = BOARD_ID2REV(board_id) - 1 + 'A'; rev[1] = '\0'; NOTICE("Board: MB%04x Var%d Rev.%s-%02d\n", BOARD_ID2NB(board_id), BOARD_ID2VAR(board_id), rev, BOARD_ID2BOM(board_id)); } } /* Return true when SoC provides a single Cortex-A7 core, and false otherwise */ bool stm32mp_is_single_core(void) { uint32_t part_number; bool ret = false; if (get_part_number(&part_number) < 0) { ERROR("Invalid part number, assume single core chip"); return true; } switch (part_number) { case STM32MP151A_PART_NB: case STM32MP151C_PART_NB: ret = true; break; default: break; } return ret; } /* Return true when device is in closed state */ bool stm32mp_is_closed_device(void) { uint32_t value; if ((bsec_shadow_register(DATA0_OTP) != BSEC_OK) || (bsec_read_otp(&value, DATA0_OTP) != BSEC_OK)) { return true; } return (value & DATA0_OTP_SECURED) == DATA0_OTP_SECURED; } uint32_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(uint32_t iwdg_inst) { uint32_t iwdg_cfg = 0U; uint32_t otp_value; #if defined(IMAGE_BL2) if (bsec_shadow_register(HW2_OTP) != BSEC_OK) { panic(); } #endif if (bsec_read_otp(&otp_value, HW2_OTP) != BSEC_OK) { panic(); } if ((otp_value & BIT(iwdg_inst + HW2_OTP_IWDG_HW_POS)) != 0U) { iwdg_cfg |= IWDG_HW_ENABLED; } if ((otp_value & BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STOP_POS)) != 0U) { iwdg_cfg |= IWDG_DISABLE_ON_STOP; } if ((otp_value & BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STANDBY_POS)) != 0U) { iwdg_cfg |= IWDG_DISABLE_ON_STANDBY; } return iwdg_cfg; } #if defined(IMAGE_BL2) uint32_t stm32_iwdg_shadow_update(uint32_t iwdg_inst, uint32_t flags) { uint32_t otp; uint32_t result; if (bsec_shadow_read_otp(&otp, HW2_OTP) != BSEC_OK) { panic(); } if ((flags & IWDG_DISABLE_ON_STOP) != 0U) { otp |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STOP_POS); } if ((flags & IWDG_DISABLE_ON_STANDBY) != 0U) { otp |= BIT(iwdg_inst + HW2_OTP_IWDG_FZ_STANDBY_POS); } 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 trusted-firmware-a-2.2/plat/st/stm32mp1/stm32mp1_security.c000066400000000000000000000106251355360272700235520ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #define TZC_REGION_NSEC_ALL_ACCESS_RDWR \ 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) /******************************************************************************* * Initialize the TrustZone Controller. Configure Region 0 with Secure RW access * and allow Non-Secure masters full access. ******************************************************************************/ static void init_tzc400(void) { unsigned long long region_base, region_top; unsigned long long ddr_base = STM32MP_DDR_BASE; unsigned long long ddr_size = (unsigned long long)dt_get_ddr_size(); unsigned long long ddr_top = ddr_base + (ddr_size - 1U); 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_top - STM32MP_DDR_S_SIZE - STM32MP_DDR_SHMEM_SIZE; tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 1, region_base, region_top, TZC_REGION_S_NONE, TZC_REGION_NSEC_ALL_ACCESS_RDWR); /* Region 2 set to cover all secure DRAM. */ region_base = region_top + 1U; region_top = ddr_top - STM32MP_DDR_SHMEM_SIZE; 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 = region_top + 1U; region_top = ddr_top; tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 3, region_base, region_top, TZC_REGION_S_NONE, TZC_REGION_NSEC_ALL_ACCESS_RDWR); #else /* * Region 1 set to cover all DRAM at 0xC000_0000. Apply the * same configuration to all filters in the TZC. */ region_base = ddr_base; region_top = ddr_top; tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 1, region_base, region_top, TZC_REGION_S_NONE, TZC_REGION_NSEC_ALL_ACCESS_RDWR); #endif /* Raise an exception if a NS device tries to access secure memory */ tzc400_set_action(TZC_ACTION_ERR); tzc400_enable_filters(); } /******************************************************************************* * Initialize the TrustZone Controller. * Early initialization create only one region with full access to secure. * This setting is used before and during DDR initialization. ******************************************************************************/ static void early_init_tzc400(void) { stm32mp_clk_enable(TZC1); stm32mp_clk_enable(TZC2); tzc400_init(STM32MP1_TZC_BASE); tzc400_disable_filters(); /* Region 1 set to cover Non-Secure DRAM at 0xC000_0000 */ tzc400_configure_region(STM32MP1_FILTER_BIT_ALL, 1, STM32MP_DDR_BASE, STM32MP_DDR_BASE + (STM32MP_DDR_MAX_SIZE - 1U), TZC_REGION_S_NONE, 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 */ tzc400_set_action(TZC_ACTION_ERR); tzc400_enable_filters(); } /******************************************************************************* * Initialize the secure environment. At this moment only the TrustZone * Controller is initialized. ******************************************************************************/ void stm32mp1_arch_security_setup(void) { early_init_tzc400(); } /******************************************************************************* * Initialize the secure environment. At this moment only the TrustZone * Controller is initialized. ******************************************************************************/ void stm32mp1_security_setup(void) { init_tzc400(); } trusted-firmware-a-2.2/plat/st/stm32mp1/stm32mp1_stack_protector.c000066400000000000000000000007701355360272700251110ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #define RANDOM_CANARY_VALUE 2144346116U u_register_t plat_get_stack_protector_canary(void) { /* * Ideally, a random number should be returned instead of the * combination of a timer's value and a compile-time constant. */ return RANDOM_CANARY_VALUE ^ (u_register_t)read_cntpct_el0(); } trusted-firmware-a-2.2/plat/st/stm32mp1/stm32mp1_syscfg.c000066400000000000000000000113711355360272700232000ustar00rootroot00000000000000/* * Copyright (c) 2019, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include /* * SYSCFG REGISTER OFFSET (base relative) */ #define SYSCFG_BOOTR 0x00U #define SYSCFG_IOCTRLSETR 0x18U #define SYSCFG_ICNR 0x1CU #define SYSCFG_CMPCR 0x20U #define SYSCFG_CMPENSETR 0x24U /* * SYSCFG_BOOTR Register */ #define SYSCFG_BOOTR_BOOT_MASK GENMASK(2, 0) #define SYSCFG_BOOTR_BOOTPD_MASK GENMASK(6, 4) #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) #define SYSCFG_CMPCR_RANSRC GENMASK(19, 16) #define SYSCFG_CMPCR_RANSRC_SHIFT 16 #define SYSCFG_CMPCR_RAPSRC GENMASK(23, 20) #define SYSCFG_CMPCR_ANSRC_SHIFT 24 /* * SYSCFG_CMPENSETR Register */ #define SYSCFG_CMPENSETR_MPU_EN BIT(0) 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); /* Disable Pull-Down for boot pin connected to VDD */ bootr = mmio_read_32(syscfg_base + SYSCFG_BOOTR) & SYSCFG_BOOTR_BOOT_MASK; mmio_clrsetbits_32(syscfg_base + SYSCFG_BOOTR, SYSCFG_BOOTR_BOOTPD_MASK, bootr << SYSCFG_BOOTR_BOOTPD_SHIFT); /* * High Speed Low Voltage Pad mode Enable for SPI, SDMMC, ETH, QSPI * and TRACE. Needed above ~50MHz and conditioned by AFMUX selection. * It could be disabled for low frequencies or if AFMUX is selected * but the function is not used, typically for TRACE. * If high speed low voltage pad mode is node enable, platform will * over consume. * * 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 SoC! * => TF-A enables the low power mode only if VDD < 2.7V (in DT) * but this value needs to be consistent with board design. */ if (bsec_read_otp(&otp, HW2_OTP) != BSEC_OK) { panic(); } otp = otp & HW2_OTP_PRODUCT_BELOW_2V5; /* Get VDD supply */ vdd_voltage = dt_get_pwr_vdd_voltage(); /* Check if VDD is Low Voltage */ if (vdd_voltage == 0U) { WARN("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) { ERROR("Product_below_2v5=1:\n"); ERROR("\tHSLVEN update is destructive,\n"); ERROR("\tno update as VDD > 2.7V\n"); panic(); } } stm32mp1_syscfg_enable_io_compensation(); } void stm32mp1_syscfg_enable_io_compensation(void) { uintptr_t syscfg_base = dt_get_syscfg_base(); /* * Activate automatic I/O compensation. * Warning: need to ensure CSI enabled and ready in clock driver. * Enable non-secure clock, we assume non-secure is suspended. */ stm32mp1_clk_enable_non_secure(SYSCFG); mmio_setbits_32(syscfg_base + SYSCFG_CMPENSETR, SYSCFG_CMPENSETR_MPU_EN); while ((mmio_read_32(syscfg_base + SYSCFG_CMPCR) & SYSCFG_CMPCR_READY) == 0U) { ; } mmio_clrbits_32(syscfg_base + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL); } void stm32mp1_syscfg_disable_io_compensation(void) { uintptr_t syscfg_base = dt_get_syscfg_base(); uint32_t value; /* * Deactivate automatic I/O compensation. * Warning: CSI is disabled automatically in STOP if not * requested for other usages and always OFF in STANDBY. * Disable non-secure SYSCFG clock, we assume non-secure is suspended. */ value = mmio_read_32(syscfg_base + SYSCFG_CMPCR) >> SYSCFG_CMPCR_ANSRC_SHIFT; mmio_clrbits_32(syscfg_base + SYSCFG_CMPCR, SYSCFG_CMPCR_RANSRC | SYSCFG_CMPCR_RAPSRC); value = mmio_read_32(syscfg_base + SYSCFG_CMPCR) | (value << SYSCFG_CMPCR_RANSRC_SHIFT); mmio_write_32(syscfg_base + SYSCFG_CMPCR, value); mmio_setbits_32(syscfg_base + SYSCFG_CMPCR, SYSCFG_CMPCR_SW_CTRL); mmio_clrbits_32(syscfg_base + SYSCFG_CMPENSETR, SYSCFG_CMPENSETR_MPU_EN); stm32mp1_clk_disable_non_secure(SYSCFG); } trusted-firmware-a-2.2/plat/st/stm32mp1/stm32mp1_topology.c000066400000000000000000000030711355360272700235540ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include /* 1 cluster, all cores into */ static const unsigned char stm32mp1_power_domain_tree_desc[] = { PLATFORM_CLUSTER_COUNT, PLATFORM_CORE_COUNT, }; /* This function returns the platform topology */ const unsigned char *plat_get_power_domain_tree_desc(void) { return stm32mp1_power_domain_tree_desc; } /******************************************************************************* * This function implements a part of the critical interface between the psci * generic layer and the platform that allows the former to query the platform * to convert an MPIDR to a unique linear index. An error code (-1) is returned * in case the MPIDR is invalid. ******************************************************************************/ int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster_id, cpu_id; u_register_t mpidr_copy = mpidr; mpidr_copy &= MPIDR_AFFINITY_MASK; if ((mpidr_copy & ~(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)) != 0U) { return -1; } cluster_id = (mpidr_copy >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; cpu_id = (mpidr_copy >> MPIDR_AFF0_SHIFT) & MPIDR_AFFLVL_MASK; if (cluster_id >= PLATFORM_CLUSTER_COUNT) { return -1; } /* * Validate cpu_id by checking whether it represents a CPU in one * of the two clusters present on the platform. */ if (cpu_id >= PLATFORM_CORE_COUNT) { return -1; } return (int)cpu_id; } trusted-firmware-a-2.2/plat/ti/000077500000000000000000000000001355360272700164655ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/ti/k3/000077500000000000000000000000001355360272700170025ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/ti/k3/board/000077500000000000000000000000001355360272700200715ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/ti/k3/board/generic/000077500000000000000000000000001355360272700215055ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/ti/k3/board/generic/board.mk000066400000000000000000000006301355360272700231240ustar00rootroot00000000000000# # Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # BL32_BASE ?= 0x9e800000 $(eval $(call add_define,BL32_BASE)) PRELOADED_BL33_BASE ?= 0x80080000 $(eval $(call add_define,PRELOADED_BL33_BASE)) K3_HW_CONFIG_BASE ?= 0x82000000 $(eval $(call add_define,K3_HW_CONFIG_BASE)) PLAT_INCLUDES += \ -Iplat/ti/k3/board/generic/include \ trusted-firmware-a-2.2/plat/ti/k3/board/generic/include/000077500000000000000000000000001355360272700231305ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/ti/k3/board/generic/include/board_def.h000066400000000000000000000014271355360272700252120ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef BOARD_DEF_H #define BOARD_DEF_H #include /* The ports must be in order and contiguous */ #define K3_CLUSTER0_CORE_COUNT 2 #define K3_CLUSTER1_CORE_COUNT 2 #define K3_CLUSTER2_CORE_COUNT 2 #define K3_CLUSTER3_CORE_COUNT 2 /* * This RAM will be used for the bootloader including code, bss, and stacks. * It may need to be increased if BL31 grows in size. */ #define SEC_SRAM_BASE 0x70000000 /* Base of MSMC SRAM */ #define SEC_SRAM_SIZE 0x00020000 /* 128k */ #define PLAT_MAX_OFF_STATE U(2) #define PLAT_MAX_RET_STATE U(1) #define PLAT_PROC_START_ID 32 #define PLAT_PROC_DEVICE_START_ID 202 #endif /* BOARD_DEF_H */ trusted-firmware-a-2.2/plat/ti/k3/common/000077500000000000000000000000001355360272700202725ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/ti/k3/common/drivers/000077500000000000000000000000001355360272700217505ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/ti/k3/common/drivers/sec_proxy/000077500000000000000000000000001355360272700237635ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.c000066400000000000000000000217751355360272700261560ustar00rootroot00000000000000/* * Texas Instruments K3 Secure Proxy Driver * Based on Linux and U-Boot implementation * * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include "sec_proxy.h" /* SEC PROXY RT THREAD STATUS */ #define RT_THREAD_STATUS (0x0) #define RT_THREAD_STATUS_ERROR_SHIFT (31) #define RT_THREAD_STATUS_ERROR_MASK BIT(31) #define RT_THREAD_STATUS_CUR_CNT_SHIFT (0) #define RT_THREAD_STATUS_CUR_CNT_MASK GENMASK(7, 0) /* SEC PROXY SCFG THREAD CTRL */ #define SCFG_THREAD_CTRL (0x1000) #define SCFG_THREAD_CTRL_DIR_SHIFT (31) #define SCFG_THREAD_CTRL_DIR_MASK BIT(31) #define SEC_PROXY_THREAD(base, x) ((base) + (0x1000 * (x))) #define THREAD_IS_RX (1) #define THREAD_IS_TX (0) /** * struct k3_sec_proxy_desc - Description of secure proxy integration * @timeout_us: Timeout for communication (in Microseconds) * @max_msg_size: Message size in bytes * @data_start_offset: Offset of the First data register of the thread * @data_end_offset: Offset of the Last data register of the thread */ struct k3_sec_proxy_desc { uint32_t timeout_us; uint16_t max_msg_size; uint16_t data_start_offset; uint16_t data_end_offset; }; /** * struct k3_sec_proxy_thread - Description of a Secure Proxy Thread * @name: Thread Name * @data: Thread Data path region for target * @scfg: Secure Config Region for Thread * @rt: RealTime Region for Thread */ struct k3_sec_proxy_thread { const char *name; uintptr_t data; uintptr_t scfg; uintptr_t rt; }; /** * struct k3_sec_proxy_mbox - Description of a Secure Proxy Instance * @desc: Description of the SoC integration * @chans: Array for valid thread instances */ struct k3_sec_proxy_mbox { const struct k3_sec_proxy_desc desc; struct k3_sec_proxy_thread threads[]; }; /* * Thread ID #0: DMSC notify * Thread ID #1: DMSC request response * Thread ID #2: DMSC request high priority * Thread ID #3: DMSC request low priority * Thread ID #4: DMSC notify response */ #define SP_THREAD(_x) \ [_x] = { \ .name = #_x, \ .data = SEC_PROXY_THREAD(SEC_PROXY_DATA_BASE, _x), \ .scfg = SEC_PROXY_THREAD(SEC_PROXY_SCFG_BASE, _x), \ .rt = SEC_PROXY_THREAD(SEC_PROXY_RT_BASE, _x), \ } static struct k3_sec_proxy_mbox spm = { .desc = { .timeout_us = SEC_PROXY_TIMEOUT_US, .max_msg_size = SEC_PROXY_MAX_MESSAGE_SIZE, .data_start_offset = 0x4, .data_end_offset = 0x3C, }, .threads = { SP_THREAD(SP_NOTIFY), SP_THREAD(SP_RESPONSE), SP_THREAD(SP_HIGH_PRIORITY), SP_THREAD(SP_LOW_PRIORITY), SP_THREAD(SP_NOTIFY_RESP), }, }; /** * struct sec_msg_hdr - Message header for secure messages and responses * @checksum: CRC of message for integrity checking */ union sec_msg_hdr { struct { uint16_t checksum; uint16_t reserved; } __packed; uint32_t data; }; /** * k3_sec_proxy_verify_thread() - Verify thread status before * sending/receiving data * @spt: Pointer to Secure Proxy thread description * @dir: Direction of the thread * * Return: 0 if all goes well, else appropriate error message */ static inline int k3_sec_proxy_verify_thread(struct k3_sec_proxy_thread *spt, uint32_t dir) { /* Check for any errors already available */ if (mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_ERROR_MASK) { ERROR("Thread %s is corrupted, cannot send data\n", spt->name); return -EINVAL; } /* Make sure thread is configured for right direction */ if ((mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK) != (dir << SCFG_THREAD_CTRL_DIR_SHIFT)) { if (dir == THREAD_IS_TX) ERROR("Trying to send data on RX Thread %s\n", spt->name); else ERROR("Trying to receive data on TX Thread %s\n", spt->name); return -EINVAL; } /* Check the message queue before sending/receiving data */ uint32_t tick_start = (uint32_t)read_cntpct_el0(); uint32_t ticks_per_us = SYS_COUNTER_FREQ_IN_TICKS / 1000000; while (!(mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK)) { VERBOSE("Waiting for thread %s to %s\n", spt->name, (dir == THREAD_IS_TX) ? "empty" : "fill"); if (((uint32_t)read_cntpct_el0() - tick_start) > (spm.desc.timeout_us * ticks_per_us)) { ERROR("Timeout waiting for thread %s to %s\n", spt->name, (dir == THREAD_IS_TX) ? "empty" : "fill"); return -ETIMEDOUT; } } return 0; } /** * k3_sec_proxy_clear_rx_thread() - Clear Secure Proxy thread * * @id: Channel Identifier * * Return: 0 if all goes well, else appropriate error message */ int k3_sec_proxy_clear_rx_thread(enum k3_sec_proxy_chan_id id) { struct k3_sec_proxy_thread *spt = &spm.threads[id]; /* Check for any errors already available */ if (mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_ERROR_MASK) { ERROR("Thread %s is corrupted, cannot send data\n", spt->name); return -EINVAL; } /* Make sure thread is configured for right direction */ if (!(mmio_read_32(spt->scfg + SCFG_THREAD_CTRL) & SCFG_THREAD_CTRL_DIR_MASK)) { ERROR("Cannot clear a transmit thread %s\n", spt->name); return -EINVAL; } /* Read off messages from thread until empty */ uint32_t try_count = 10; while (mmio_read_32(spt->rt + RT_THREAD_STATUS) & RT_THREAD_STATUS_CUR_CNT_MASK) { if (!(try_count--)) { ERROR("Could not clear all messages from thread %s\n", spt->name); return -ETIMEDOUT; } WARN("Clearing message from thread %s\n", spt->name); mmio_read_32(spt->data + spm.desc.data_end_offset); } return 0; } /** * k3_sec_proxy_send() - Send data over a Secure Proxy thread * @id: Channel Identifier * @msg: Pointer to k3_sec_proxy_msg * * Return: 0 if all goes well, else appropriate error message */ int k3_sec_proxy_send(enum k3_sec_proxy_chan_id id, const struct k3_sec_proxy_msg *msg) { struct k3_sec_proxy_thread *spt = &spm.threads[id]; union sec_msg_hdr secure_header; int num_words, trail_bytes, i, ret; uintptr_t data_reg; ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_TX); if (ret) { ERROR("Thread %s verification failed (%d)\n", spt->name, ret); return ret; } /* Check the message size */ if (msg->len + sizeof(secure_header) > spm.desc.max_msg_size) { ERROR("Thread %s message length %lu > max msg size\n", spt->name, msg->len); return -EINVAL; } /* TODO: Calculate checksum */ secure_header.checksum = 0; /* Send the secure header */ data_reg = spm.desc.data_start_offset; mmio_write_32(spt->data + data_reg, secure_header.data); data_reg += sizeof(uint32_t); /* Send whole words */ num_words = msg->len / sizeof(uint32_t); for (i = 0; i < num_words; i++) { mmio_write_32(spt->data + data_reg, ((uint32_t *)msg->buf)[i]); data_reg += sizeof(uint32_t); } /* Send remaining bytes */ trail_bytes = msg->len % sizeof(uint32_t); if (trail_bytes) { uint32_t data_trail = 0; i = msg->len - trail_bytes; while (trail_bytes--) { data_trail <<= 8; data_trail |= msg->buf[i++]; } mmio_write_32(spt->data + data_reg, data_trail); data_reg += sizeof(uint32_t); } /* * 'data_reg' indicates next register to write. If we did not already * write on tx complete reg(last reg), we must do so for transmit */ if (data_reg <= spm.desc.data_end_offset) mmio_write_32(spt->data + spm.desc.data_end_offset, 0); VERBOSE("Message successfully sent on thread %s\n", spt->name); return 0; } /** * k3_sec_proxy_recv() - Receive data from a Secure Proxy thread * @id: Channel Identifier * @msg: Pointer to k3_sec_proxy_msg * * Return: 0 if all goes well, else appropriate error message */ int k3_sec_proxy_recv(enum k3_sec_proxy_chan_id id, struct k3_sec_proxy_msg *msg) { struct k3_sec_proxy_thread *spt = &spm.threads[id]; union sec_msg_hdr secure_header; uintptr_t data_reg; int num_words, trail_bytes, i, ret; ret = k3_sec_proxy_verify_thread(spt, THREAD_IS_RX); if (ret) { ERROR("Thread %s verification failed (%d)\n", spt->name, ret); return ret; } /* Read secure header */ data_reg = spm.desc.data_start_offset; secure_header.data = mmio_read_32(spt->data + data_reg); data_reg += sizeof(uint32_t); /* Read whole words */ num_words = msg->len / sizeof(uint32_t); for (i = 0; i < num_words; i++) { ((uint32_t *)msg->buf)[i] = mmio_read_32(spt->data + data_reg); data_reg += sizeof(uint32_t); } /* Read remaining bytes */ trail_bytes = msg->len % sizeof(uint32_t); if (trail_bytes) { uint32_t data_trail = mmio_read_32(spt->data + data_reg); data_reg += sizeof(uint32_t); i = msg->len - trail_bytes; while (trail_bytes--) { msg->buf[i] = data_trail & 0xff; data_trail >>= 8; } } /* * 'data_reg' indicates next register to read. If we did not already * read on rx complete reg(last reg), we must do so for receive */ if (data_reg <= spm.desc.data_end_offset) mmio_read_32(spt->data + spm.desc.data_end_offset); /* TODO: Verify checksum */ (void)secure_header.checksum; VERBOSE("Message successfully received from thread %s\n", spt->name); return 0; } trusted-firmware-a-2.2/plat/ti/k3/common/drivers/sec_proxy/sec_proxy.h000066400000000000000000000031611355360272700261500ustar00rootroot00000000000000/* * Texas Instruments K3 Secure Proxy Driver * Based on Linux and U-Boot implementation * * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SEC_PROXY_H #define SEC_PROXY_H #include /** * enum k3_sec_proxy_chan_id - Secure Proxy thread IDs * * These the available IDs used in k3_sec_proxy_{send,recv}() */ enum k3_sec_proxy_chan_id { SP_NOTIFY = 0, SP_RESPONSE, SP_HIGH_PRIORITY, SP_LOW_PRIORITY, SP_NOTIFY_RESP, }; /** * struct k3_sec_proxy_msg - Secure proxy message structure * @len: Length of data in the Buffer * @buf: Buffer pointer * * This is the structure for data used in k3_sec_proxy_{send,recv}() */ struct k3_sec_proxy_msg { size_t len; uint8_t *buf; }; /** * k3_sec_proxy_send() - Send data over a Secure Proxy thread * @id: Channel Identifier * @msg: Pointer to k3_sec_proxy_msg * * Return: 0 if all goes well, else appropriate error message */ int k3_sec_proxy_clear_rx_thread(enum k3_sec_proxy_chan_id id); /** * k3_sec_proxy_send() - Send data over a Secure Proxy thread * @id: Channel Identifier * @msg: Pointer to k3_sec_proxy_msg * * Return: 0 if all goes well, else appropriate error message */ int k3_sec_proxy_send(enum k3_sec_proxy_chan_id id, const struct k3_sec_proxy_msg *msg); /** * k3_sec_proxy_recv() - Receive data from a Secure Proxy thread * @id: Channel Identifier * @msg: Pointer to k3_sec_proxy_msg * * Return: 0 if all goes well, else appropriate error message */ int k3_sec_proxy_recv(enum k3_sec_proxy_chan_id id, struct k3_sec_proxy_msg *msg); #endif /* SEC_PROXY_H */ trusted-firmware-a-2.2/plat/ti/k3/common/drivers/ti_sci/000077500000000000000000000000001355360272700232225ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/ti/k3/common/drivers/ti_sci/ti_sci.c000066400000000000000000001301311355360272700246370ustar00rootroot00000000000000/* * Texas Instruments System Control Interface Driver * Based on Linux and U-Boot implementation * * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "ti_sci_protocol.h" #include "ti_sci.h" /** * struct ti_sci_desc - Description of SoC integration * @host_id: Host identifier representing the compute entity * @max_msg_size: Maximum size of data per message that can be handled */ struct ti_sci_desc { uint8_t host_id; int max_msg_size; }; /** * struct ti_sci_info - Structure representing a TI SCI instance * @desc: SoC description for this instance * @seq: Seq id used for verification for tx and rx message */ struct ti_sci_info { const struct ti_sci_desc desc; uint8_t seq; }; static struct ti_sci_info info = { .desc = { .host_id = TI_SCI_HOST_ID, .max_msg_size = TI_SCI_MAX_MESSAGE_SIZE, }, }; /** * struct ti_sci_xfer - Structure representing a message flow * @tx_message: Transmit message * @rx_message: Receive message */ struct ti_sci_xfer { struct k3_sec_proxy_msg tx_message; struct k3_sec_proxy_msg rx_message; }; /** * ti_sci_setup_one_xfer() - Setup one message type * * @msg_type: Message type * @msg_flags: Flag to set for the message * @tx_buf: Buffer to be sent to mailbox channel * @tx_message_size: transmit message size * @rx_buf: Buffer to be received from mailbox channel * @rx_message_size: receive message size * * Helper function which is used by various command functions that are * exposed to clients of this driver for allocating a message traffic event. * * Return: 0 if all goes well, else appropriate error message */ static int ti_sci_setup_one_xfer(uint16_t msg_type, uint32_t msg_flags, void *tx_buf, size_t tx_message_size, void *rx_buf, size_t rx_message_size, struct ti_sci_xfer *xfer) { struct ti_sci_msg_hdr *hdr; /* Ensure we have sane transfer sizes */ if (rx_message_size > info.desc.max_msg_size || tx_message_size > info.desc.max_msg_size || rx_message_size < sizeof(*hdr) || tx_message_size < sizeof(*hdr)) return -ERANGE; hdr = (struct ti_sci_msg_hdr *)tx_buf; hdr->seq = ++info.seq; hdr->type = msg_type; hdr->host = info.desc.host_id; hdr->flags = msg_flags | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED; xfer->tx_message.buf = tx_buf; xfer->tx_message.len = tx_message_size; xfer->rx_message.buf = rx_buf; xfer->rx_message.len = rx_message_size; return 0; } /** * ti_sci_get_response() - Receive response from mailbox channel * * @xfer: Transfer to initiate and wait for response * @chan: Channel to receive the response * * Return: 0 if all goes well, else appropriate error message */ static inline int ti_sci_get_response(struct ti_sci_xfer *xfer, enum k3_sec_proxy_chan_id chan) { struct k3_sec_proxy_msg *msg = &xfer->rx_message; struct ti_sci_msg_hdr *hdr; unsigned int retry = 5; int ret; for (; retry > 0; retry--) { /* Receive the response */ ret = k3_sec_proxy_recv(chan, msg); if (ret) { ERROR("Message receive failed (%d)\n", ret); return ret; } /* msg is updated by Secure Proxy driver */ hdr = (struct ti_sci_msg_hdr *)msg->buf; /* Sanity check for message response */ if (hdr->seq == info.seq) break; else WARN("Message with sequence ID %u is not expected\n", hdr->seq); } if (!retry) { ERROR("Timed out waiting for message\n"); return -EINVAL; } if (msg->len > info.desc.max_msg_size) { ERROR("Unable to handle %lu xfer (max %d)\n", msg->len, info.desc.max_msg_size); return -EINVAL; } if (!(hdr->flags & TI_SCI_FLAG_RESP_GENERIC_ACK)) return -ENODEV; return 0; } /** * ti_sci_do_xfer() - Do one transfer * * @xfer: Transfer to initiate and wait for response * * Return: 0 if all goes well, else appropriate error message */ static inline int ti_sci_do_xfer(struct ti_sci_xfer *xfer) { struct k3_sec_proxy_msg *msg = &xfer->tx_message; int ret; /* Clear any spurious messages in receive queue */ ret = k3_sec_proxy_clear_rx_thread(SP_RESPONSE); if (ret) { ERROR("Could not clear response queue (%d)\n", ret); return ret; } /* Send the message */ ret = k3_sec_proxy_send(SP_HIGH_PRIORITY, msg); if (ret) { ERROR("Message sending failed (%d)\n", ret); return ret; } /* Get the response */ ret = ti_sci_get_response(xfer, SP_RESPONSE); if (ret) { ERROR("Failed to get response (%d)\n", ret); return ret; } return 0; } /** * ti_sci_get_revision() - Get the revision of the SCI entity * * Updates the SCI information in the internal data structure. * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_get_revision(struct ti_sci_msg_resp_version *rev_info) { struct ti_sci_msg_hdr hdr; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TI_SCI_MSG_VERSION, 0x0, &hdr, sizeof(hdr), rev_info, sizeof(*rev_info), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } return 0; } /** * ti_sci_device_set_state() - Set device state * * @id: Device identifier * @flags: flags to setup for the device * @state: State to move the device to * * Return: 0 if all goes well, else appropriate error message */ static int ti_sci_device_set_state(uint32_t id, uint32_t flags, uint8_t state) { struct ti_sci_msg_req_set_device_state req; struct ti_sci_msg_hdr resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_DEVICE_STATE, flags, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.id = id; req.state = state; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } return 0; } /** * ti_sci_device_get_state() - Get device state * * @id: Device Identifier * @clcnt: Pointer to Context Loss Count * @resets: pointer to resets * @p_state: pointer to p_state * @c_state: pointer to c_state * * Return: 0 if all goes well, else appropriate error message */ static int ti_sci_device_get_state(uint32_t id, uint32_t *clcnt, uint32_t *resets, uint8_t *p_state, uint8_t *c_state) { struct ti_sci_msg_req_get_device_state req; struct ti_sci_msg_resp_get_device_state resp; struct ti_sci_xfer xfer; int ret; if (!clcnt && !resets && !p_state && !c_state) return -EINVAL; ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_DEVICE_STATE, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.id = id; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } if (clcnt) *clcnt = resp.context_loss_count; if (resets) *resets = resp.resets; if (p_state) *p_state = resp.programmed_state; if (c_state) *c_state = resp.current_state; return 0; } /** * ti_sci_device_get() - Request for device managed by TISCI * * @id: Device Identifier * * Request for the device - NOTE: the client MUST maintain integrity of * usage count by balancing get_device with put_device. No refcounting is * managed by driver for that purpose. * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_device_get(uint32_t id) { return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_ON); } /** * ti_sci_device_get_exclusive() - Exclusive request for device managed by TISCI * * @id: Device Identifier * * Request for the device - NOTE: the client MUST maintain integrity of * usage count by balancing get_device with put_device. No refcounting is * managed by driver for that purpose. * * NOTE: This _exclusive version of the get API is for exclusive access to the * device. Any other host in the system will fail to get this device after this * call until exclusive access is released with device_put or a non-exclusive * set call. * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_device_get_exclusive(uint32_t id) { return ti_sci_device_set_state(id, MSG_FLAG_DEVICE_EXCLUSIVE, MSG_DEVICE_SW_STATE_ON); } /** * ti_sci_device_idle() - Idle a device managed by TISCI * * @id: Device Identifier * * Request for the device - NOTE: the client MUST maintain integrity of * usage count by balancing get_device with put_device. No refcounting is * managed by driver for that purpose. * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_device_idle(uint32_t id) { return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_RETENTION); } /** * ti_sci_device_idle_exclusive() - Exclusive idle a device managed by TISCI * * @id: Device Identifier * * Request for the device - NOTE: the client MUST maintain integrity of * usage count by balancing get_device with put_device. No refcounting is * managed by driver for that purpose. * * NOTE: This _exclusive version of the idle API is for exclusive access to * the device. Any other host in the system will fail to get this device after * this call until exclusive access is released with device_put or a * non-exclusive set call. * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_device_idle_exclusive(uint32_t id) { return ti_sci_device_set_state(id, MSG_FLAG_DEVICE_EXCLUSIVE, MSG_DEVICE_SW_STATE_RETENTION); } /** * ti_sci_device_put() - Release a device managed by TISCI * * @id: Device Identifier * * Request for the device - NOTE: the client MUST maintain integrity of * usage count by balancing get_device with put_device. No refcounting is * managed by driver for that purpose. * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_device_put(uint32_t id) { return ti_sci_device_set_state(id, 0, MSG_DEVICE_SW_STATE_AUTO_OFF); } /** * ti_sci_device_put_no_wait() - Release a device without requesting or waiting * for a response. * * @id: Device Identifier * * Request for the device - NOTE: the client MUST maintain integrity of * usage count by balancing get_device with put_device. No refcounting is * managed by driver for that purpose. * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_device_put_no_wait(uint32_t id) { struct ti_sci_msg_req_set_device_state req; struct ti_sci_msg_hdr *hdr; struct k3_sec_proxy_msg tx_message; int ret; /* Ensure we have sane transfer size */ if (sizeof(req) > info.desc.max_msg_size) return -ERANGE; hdr = (struct ti_sci_msg_hdr *)&req; hdr->seq = ++info.seq; hdr->type = TI_SCI_MSG_SET_DEVICE_STATE; hdr->host = info.desc.host_id; /* Setup with NORESPONSE flag to keep response queue clean */ hdr->flags = TI_SCI_FLAG_REQ_GENERIC_NORESPONSE; req.id = id; req.state = MSG_DEVICE_SW_STATE_AUTO_OFF; tx_message.buf = (uint8_t *)&req; tx_message.len = sizeof(req); /* Send message */ ret = k3_sec_proxy_send(SP_HIGH_PRIORITY, &tx_message); if (ret) { ERROR("Message sending failed (%d)\n", ret); return ret; } /* Return without waiting for response */ return 0; } /** * ti_sci_device_is_valid() - Is the device valid * * @id: Device Identifier * * Return: 0 if all goes well and the device ID is valid, else return * appropriate error */ int ti_sci_device_is_valid(uint32_t id) { uint8_t unused; /* check the device state which will also tell us if the ID is valid */ return ti_sci_device_get_state(id, NULL, NULL, NULL, &unused); } /** * ti_sci_device_get_clcnt() - Get context loss counter * * @id: Device Identifier * @count: Pointer to Context Loss counter to populate * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_device_get_clcnt(uint32_t id, uint32_t *count) { return ti_sci_device_get_state(id, count, NULL, NULL, NULL); } /** * ti_sci_device_is_idle() - Check if the device is requested to be idle * * @id: Device Identifier * @r_state: true if requested to be idle * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_device_is_idle(uint32_t id, bool *r_state) { int ret; uint8_t state; if (!r_state) return -EINVAL; ret = ti_sci_device_get_state(id, NULL, NULL, &state, NULL); if (ret) return ret; *r_state = (state == MSG_DEVICE_SW_STATE_RETENTION); return 0; } /** * ti_sci_device_is_stop() - Check if the device is requested to be stopped * * @id: Device Identifier * @r_state: true if requested to be stopped * @curr_state: true if currently stopped * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_device_is_stop(uint32_t id, bool *r_state, bool *curr_state) { int ret; uint8_t p_state, c_state; if (!r_state && !curr_state) return -EINVAL; ret = ti_sci_device_get_state(id, NULL, NULL, &p_state, &c_state); if (ret) return ret; if (r_state) *r_state = (p_state == MSG_DEVICE_SW_STATE_AUTO_OFF); if (curr_state) *curr_state = (c_state == MSG_DEVICE_HW_STATE_OFF); return 0; } /** * ti_sci_device_is_on() - Check if the device is requested to be ON * * @id: Device Identifier * @r_state: true if requested to be ON * @curr_state: true if currently ON and active * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_device_is_on(uint32_t id, bool *r_state, bool *curr_state) { int ret; uint8_t p_state, c_state; if (!r_state && !curr_state) return -EINVAL; ret = ti_sci_device_get_state(id, NULL, NULL, &p_state, &c_state); if (ret) return ret; if (r_state) *r_state = (p_state == MSG_DEVICE_SW_STATE_ON); if (curr_state) *curr_state = (c_state == MSG_DEVICE_HW_STATE_ON); return 0; } /** * ti_sci_device_is_trans() - Check if the device is currently transitioning * * @id: Device Identifier * @curr_state: true if currently transitioning * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_device_is_trans(uint32_t id, bool *curr_state) { int ret; uint8_t state; if (!curr_state) return -EINVAL; ret = ti_sci_device_get_state(id, NULL, NULL, NULL, &state); if (ret) return ret; *curr_state = (state == MSG_DEVICE_HW_STATE_TRANS); return 0; } /** * ti_sci_device_set_resets() - Set resets for device managed by TISCI * * @id: Device Identifier * @reset_state: Device specific reset bit field * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_device_set_resets(uint32_t id, uint32_t reset_state) { struct ti_sci_msg_req_set_device_resets req; struct ti_sci_msg_hdr resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_DEVICE_RESETS, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.id = id; req.resets = reset_state; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } return 0; } /** * ti_sci_device_get_resets() - Get reset state for device managed by TISCI * * @id: Device Identifier * @reset_state: Pointer to reset state to populate * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_device_get_resets(uint32_t id, uint32_t *reset_state) { return ti_sci_device_get_state(id, NULL, reset_state, NULL, NULL); } /** * ti_sci_clock_set_state() - Set clock state helper * * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request, * Each device has its own set of clock inputs, This indexes * which clock input to modify * @flags: Header flags as needed * @state: State to request for the clock * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_clock_set_state(uint32_t dev_id, uint8_t clk_id, uint32_t flags, uint8_t state) { struct ti_sci_msg_req_set_clock_state req; struct ti_sci_msg_hdr resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_CLOCK_STATE, flags, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.dev_id = dev_id; req.clk_id = clk_id; req.request_state = state; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } return 0; } /** * ti_sci_clock_get_state() - Get clock state helper * * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has its own set of clock inputs. This indexes * which clock input to modify. * @programmed_state: State requested for clock to move to * @current_state: State that the clock is currently in * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_clock_get_state(uint32_t dev_id, uint8_t clk_id, uint8_t *programmed_state, uint8_t *current_state) { struct ti_sci_msg_req_get_clock_state req; struct ti_sci_msg_resp_get_clock_state resp; struct ti_sci_xfer xfer; int ret; if (!programmed_state && !current_state) return -EINVAL; ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_CLOCK_STATE, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.dev_id = dev_id; req.clk_id = clk_id; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } if (programmed_state) *programmed_state = resp.programmed_state; if (current_state) *current_state = resp.current_state; return 0; } /** * ti_sci_clock_get() - Get control of a clock from TI SCI * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has its own set of clock inputs. This indexes * which clock input to modify. * @needs_ssc: 'true' iff Spread Spectrum clock is desired * @can_change_freq: 'true' iff frequency change is desired * @enable_input_term: 'true' iff input termination is desired * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_clock_get(uint32_t dev_id, uint8_t clk_id, bool needs_ssc, bool can_change_freq, bool enable_input_term) { uint32_t flags = 0; flags |= needs_ssc ? MSG_FLAG_CLOCK_ALLOW_SSC : 0; flags |= can_change_freq ? MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE : 0; flags |= enable_input_term ? MSG_FLAG_CLOCK_INPUT_TERM : 0; return ti_sci_clock_set_state(dev_id, clk_id, flags, MSG_CLOCK_SW_STATE_REQ); } /** * ti_sci_clock_idle() - Idle a clock which is in our control * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has its own set of clock inputs. This indexes * which clock input to modify. * * NOTE: This clock must have been requested by get_clock previously. * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_clock_idle(uint32_t dev_id, uint8_t clk_id) { return ti_sci_clock_set_state(dev_id, clk_id, 0, MSG_CLOCK_SW_STATE_UNREQ); } /** * ti_sci_clock_put() - Release a clock from our control * * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has its own set of clock inputs. This indexes * which clock input to modify. * * NOTE: This clock must have been requested by get_clock previously. * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_clock_put(uint32_t dev_id, uint8_t clk_id) { return ti_sci_clock_set_state(dev_id, clk_id, 0, MSG_CLOCK_SW_STATE_AUTO); } /** * ti_sci_clock_is_auto() - Is the clock being auto managed * * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has its own set of clock inputs. This indexes * which clock input to modify. * @req_state: state indicating if the clock is auto managed * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_clock_is_auto(uint32_t dev_id, uint8_t clk_id, bool *req_state) { uint8_t state = 0; int ret; if (!req_state) return -EINVAL; ret = ti_sci_clock_get_state(dev_id, clk_id, &state, NULL); if (ret) return ret; *req_state = (state == MSG_CLOCK_SW_STATE_AUTO); return 0; } /** * ti_sci_clock_is_on() - Is the clock ON * * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has its own set of clock inputs. This indexes * which clock input to modify. * @req_state: state indicating if the clock is managed by us and enabled * @curr_state: state indicating if the clock is ready for operation * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_clock_is_on(uint32_t dev_id, uint8_t clk_id, bool *req_state, bool *curr_state) { uint8_t c_state = 0, r_state = 0; int ret; if (!req_state && !curr_state) return -EINVAL; ret = ti_sci_clock_get_state(dev_id, clk_id, &r_state, &c_state); if (ret) return ret; if (req_state) *req_state = (r_state == MSG_CLOCK_SW_STATE_REQ); if (curr_state) *curr_state = (c_state == MSG_CLOCK_HW_STATE_READY); return 0; } /** * ti_sci_clock_is_off() - Is the clock OFF * * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has its own set of clock inputs. This indexes * which clock input to modify. * @req_state: state indicating if the clock is managed by us and disabled * @curr_state: state indicating if the clock is NOT ready for operation * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_clock_is_off(uint32_t dev_id, uint8_t clk_id, bool *req_state, bool *curr_state) { uint8_t c_state = 0, r_state = 0; int ret; if (!req_state && !curr_state) return -EINVAL; ret = ti_sci_clock_get_state(dev_id, clk_id, &r_state, &c_state); if (ret) return ret; if (req_state) *req_state = (r_state == MSG_CLOCK_SW_STATE_UNREQ); if (curr_state) *curr_state = (c_state == MSG_CLOCK_HW_STATE_NOT_READY); return 0; } /** * ti_sci_clock_set_parent() - Set the clock source of a specific device clock * * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has its own set of clock inputs. This indexes * which clock input to modify. * @parent_id: Parent clock identifier to set * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_clock_set_parent(uint32_t dev_id, uint8_t clk_id, uint8_t parent_id) { struct ti_sci_msg_req_set_clock_parent req; struct ti_sci_msg_hdr resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_CLOCK_PARENT, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.dev_id = dev_id; req.clk_id = clk_id; req.parent_id = parent_id; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } return 0; } /** * ti_sci_clock_get_parent() - Get current parent clock source * * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has its own set of clock inputs. This indexes * which clock input to modify. * @parent_id: Current clock parent * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_clock_get_parent(uint32_t dev_id, uint8_t clk_id, uint8_t *parent_id) { struct ti_sci_msg_req_get_clock_parent req; struct ti_sci_msg_resp_get_clock_parent resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_CLOCK_PARENT, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.dev_id = dev_id; req.clk_id = clk_id; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } *parent_id = resp.parent_id; return 0; } /** * ti_sci_clock_get_num_parents() - Get num parents of the current clk source * * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has its own set of clock inputs. This indexes * which clock input to modify. * @num_parents: Returns he number of parents to the current clock. * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_clock_get_num_parents(uint32_t dev_id, uint8_t clk_id, uint8_t *num_parents) { struct ti_sci_msg_req_get_clock_num_parents req; struct ti_sci_msg_resp_get_clock_num_parents resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_NUM_CLOCK_PARENTS, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.dev_id = dev_id; req.clk_id = clk_id; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } *num_parents = resp.num_parents; return 0; } /** * ti_sci_clock_get_match_freq() - Find a good match for frequency * * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has its own set of clock inputs. This indexes * which clock input to modify. * @min_freq: The minimum allowable frequency in Hz. This is the minimum * allowable programmed frequency and does not account for clock * tolerances and jitter. * @target_freq: The target clock frequency in Hz. A frequency will be * processed as close to this target frequency as possible. * @max_freq: The maximum allowable frequency in Hz. This is the maximum * allowable programmed frequency and does not account for clock * tolerances and jitter. * @match_freq: Frequency match in Hz response. * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_clock_get_match_freq(uint32_t dev_id, uint8_t clk_id, uint64_t min_freq, uint64_t target_freq, uint64_t max_freq, uint64_t *match_freq) { struct ti_sci_msg_req_query_clock_freq req; struct ti_sci_msg_resp_query_clock_freq resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TI_SCI_MSG_QUERY_CLOCK_FREQ, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.dev_id = dev_id; req.clk_id = clk_id; req.min_freq_hz = min_freq; req.target_freq_hz = target_freq; req.max_freq_hz = max_freq; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } *match_freq = resp.freq_hz; return 0; } /** * ti_sci_clock_set_freq() - Set a frequency for clock * * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has its own set of clock inputs. This indexes * which clock input to modify. * @min_freq: The minimum allowable frequency in Hz. This is the minimum * allowable programmed frequency and does not account for clock * tolerances and jitter. * @target_freq: The target clock frequency in Hz. A frequency will be * processed as close to this target frequency as possible. * @max_freq: The maximum allowable frequency in Hz. This is the maximum * allowable programmed frequency and does not account for clock * tolerances and jitter. * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_clock_set_freq(uint32_t dev_id, uint8_t clk_id, uint64_t min_freq, uint64_t target_freq, uint64_t max_freq) { struct ti_sci_msg_req_set_clock_freq req; struct ti_sci_msg_hdr resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SET_CLOCK_FREQ, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.dev_id = dev_id; req.clk_id = clk_id; req.min_freq_hz = min_freq; req.target_freq_hz = target_freq; req.max_freq_hz = max_freq; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } return 0; } /** * ti_sci_clock_get_freq() - Get current frequency * * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has its own set of clock inputs. This indexes * which clock input to modify. * @freq: Currently frequency in Hz * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_clock_get_freq(uint32_t dev_id, uint8_t clk_id, uint64_t *freq) { struct ti_sci_msg_req_get_clock_freq req; struct ti_sci_msg_resp_get_clock_freq resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TI_SCI_MSG_GET_CLOCK_FREQ, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.dev_id = dev_id; req.clk_id = clk_id; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } *freq = resp.freq_hz; return 0; } /** * ti_sci_core_reboot() - Command to request system reset * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_core_reboot(void) { struct ti_sci_msg_req_reboot req; struct ti_sci_msg_hdr resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TI_SCI_MSG_SYS_RESET, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } return 0; } /** * ti_sci_proc_request() - Request a physical processor control * * @proc_id: Processor ID this request is for * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_proc_request(uint8_t proc_id) { struct ti_sci_msg_req_proc_request req; struct ti_sci_msg_hdr resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_REQUEST, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.processor_id = proc_id; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } return 0; } /** * ti_sci_proc_release() - Release a physical processor control * * @proc_id: Processor ID this request is for * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_proc_release(uint8_t proc_id) { struct ti_sci_msg_req_proc_release req; struct ti_sci_msg_hdr resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_RELEASE, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.processor_id = proc_id; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } return 0; } /** * ti_sci_proc_handover() - Handover a physical processor control to a host in * the processor's access control list. * * @proc_id: Processor ID this request is for * @host_id: Host ID to get the control of the processor * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_proc_handover(uint8_t proc_id, uint8_t host_id) { struct ti_sci_msg_req_proc_handover req; struct ti_sci_msg_hdr resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_HANDOVER, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.processor_id = proc_id; req.host_id = host_id; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } return 0; } /** * ti_sci_proc_set_boot_cfg() - Set the processor boot configuration flags * * @proc_id: Processor ID this request is for * @config_flags_set: Configuration flags to be set * @config_flags_clear: Configuration flags to be cleared * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_proc_set_boot_cfg(uint8_t proc_id, uint64_t bootvector, uint32_t config_flags_set, uint32_t config_flags_clear) { struct ti_sci_msg_req_set_proc_boot_config req; struct ti_sci_msg_hdr resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TISCI_MSG_SET_PROC_BOOT_CONFIG, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.processor_id = proc_id; req.bootvector_low = bootvector & TISCI_ADDR_LOW_MASK; req.bootvector_high = (bootvector & TISCI_ADDR_HIGH_MASK) >> TISCI_ADDR_HIGH_SHIFT; req.config_flags_set = config_flags_set; req.config_flags_clear = config_flags_clear; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } return 0; } /** * ti_sci_proc_set_boot_ctrl() - Set the processor boot control flags * * @proc_id: Processor ID this request is for * @control_flags_set: Control flags to be set * @control_flags_clear: Control flags to be cleared * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_proc_set_boot_ctrl(uint8_t proc_id, uint32_t control_flags_set, uint32_t control_flags_clear) { struct ti_sci_msg_req_set_proc_boot_ctrl req; struct ti_sci_msg_hdr resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TISCI_MSG_SET_PROC_BOOT_CTRL, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.processor_id = proc_id; req.control_flags_set = control_flags_set; req.control_flags_clear = control_flags_clear; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } return 0; } /** * ti_sci_proc_set_boot_ctrl_no_wait() - Set the processor boot control flags * without requesting or waiting for a * response. * * @proc_id: Processor ID this request is for * @control_flags_set: Control flags to be set * @control_flags_clear: Control flags to be cleared * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_proc_set_boot_ctrl_no_wait(uint8_t proc_id, uint32_t control_flags_set, uint32_t control_flags_clear) { struct ti_sci_msg_req_set_proc_boot_ctrl req; struct ti_sci_msg_hdr *hdr; struct k3_sec_proxy_msg tx_message; int ret; /* Ensure we have sane transfer size */ if (sizeof(req) > info.desc.max_msg_size) return -ERANGE; hdr = (struct ti_sci_msg_hdr *)&req; hdr->seq = ++info.seq; hdr->type = TISCI_MSG_SET_PROC_BOOT_CTRL; hdr->host = info.desc.host_id; /* Setup with NORESPONSE flag to keep response queue clean */ hdr->flags = TI_SCI_FLAG_REQ_GENERIC_NORESPONSE; req.processor_id = proc_id; req.control_flags_set = control_flags_set; req.control_flags_clear = control_flags_clear; tx_message.buf = (uint8_t *)&req; tx_message.len = sizeof(req); /* Send message */ ret = k3_sec_proxy_send(SP_HIGH_PRIORITY, &tx_message); if (ret) { ERROR("Message sending failed (%d)\n", ret); return ret; } /* Return without waiting for response */ return 0; } /** * ti_sci_proc_auth_boot_image() - Authenticate and load image and then set the * processor configuration flags * * @proc_id: Processor ID this request is for * @cert_addr: Memory address at which payload image certificate is located * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_proc_auth_boot_image(uint8_t proc_id, uint64_t cert_addr) { struct ti_sci_msg_req_proc_auth_boot_image req; struct ti_sci_msg_hdr resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TISCI_MSG_PROC_AUTH_BOOT_IMIAGE, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.processor_id = proc_id; req.cert_addr_low = cert_addr & TISCI_ADDR_LOW_MASK; req.cert_addr_high = (cert_addr & TISCI_ADDR_HIGH_MASK) >> TISCI_ADDR_HIGH_SHIFT; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } return 0; } /** * ti_sci_proc_get_boot_status() - Get the processor boot status * * @proc_id: Processor ID this request is for * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_proc_get_boot_status(uint8_t proc_id, uint64_t *bv, uint32_t *cfg_flags, uint32_t *ctrl_flags, uint32_t *sts_flags) { struct ti_sci_msg_req_get_proc_boot_status req; struct ti_sci_msg_resp_get_proc_boot_status resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TISCI_MSG_GET_PROC_BOOT_STATUS, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.processor_id = proc_id; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } *bv = (resp.bootvector_low & TISCI_ADDR_LOW_MASK) | (((uint64_t)resp.bootvector_high << TISCI_ADDR_HIGH_SHIFT) & TISCI_ADDR_HIGH_MASK); *cfg_flags = resp.config_flags; *ctrl_flags = resp.control_flags; *sts_flags = resp.status_flags; return 0; } /** * ti_sci_proc_wait_boot_status() - Wait for a processor boot status * * @proc_id: Processor ID this request is for * @num_wait_iterations Total number of iterations we will check before * we will timeout and give up * @num_match_iterations How many iterations should we have continued * status to account for status bits glitching. * This is to make sure that match occurs for * consecutive checks. This implies that the * worst case should consider that the stable * time should at the worst be num_wait_iterations * num_match_iterations to prevent timeout. * @delay_per_iteration_us Specifies how long to wait (in micro seconds) * between each status checks. This is the minimum * duration, and overhead of register reads and * checks are on top of this and can vary based on * varied conditions. * @delay_before_iterations_us Specifies how long to wait (in micro seconds) * before the very first check in the first * iteration of status check loop. This is the * minimum duration, and overhead of register * reads and checks are. * @status_flags_1_set_all_wait If non-zero, Specifies that all bits of the * status matching this field requested MUST be 1. * @status_flags_1_set_any_wait If non-zero, Specifies that at least one of the * bits matching this field requested MUST be 1. * @status_flags_1_clr_all_wait If non-zero, Specifies that all bits of the * status matching this field requested MUST be 0. * @status_flags_1_clr_any_wait If non-zero, Specifies that at least one of the * bits matching this field requested MUST be 0. * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_proc_wait_boot_status(uint8_t proc_id, uint8_t num_wait_iterations, uint8_t num_match_iterations, uint8_t delay_per_iteration_us, uint8_t delay_before_iterations_us, uint32_t status_flags_1_set_all_wait, uint32_t status_flags_1_set_any_wait, uint32_t status_flags_1_clr_all_wait, uint32_t status_flags_1_clr_any_wait) { struct ti_sci_msg_req_wait_proc_boot_status req; struct ti_sci_msg_hdr resp; struct ti_sci_xfer xfer; int ret; ret = ti_sci_setup_one_xfer(TISCI_MSG_WAIT_PROC_BOOT_STATUS, 0, &req, sizeof(req), &resp, sizeof(resp), &xfer); if (ret) { ERROR("Message alloc failed (%d)\n", ret); return ret; } req.processor_id = proc_id; req.num_wait_iterations = num_wait_iterations; req.num_match_iterations = num_match_iterations; req.delay_per_iteration_us = delay_per_iteration_us; req.delay_before_iterations_us = delay_before_iterations_us; req.status_flags_1_set_all_wait = status_flags_1_set_all_wait; req.status_flags_1_set_any_wait = status_flags_1_set_any_wait; req.status_flags_1_clr_all_wait = status_flags_1_clr_all_wait; req.status_flags_1_clr_any_wait = status_flags_1_clr_any_wait; ret = ti_sci_do_xfer(&xfer); if (ret) { ERROR("Transfer send failed (%d)\n", ret); return ret; } return 0; } /** * ti_sci_proc_wait_boot_status_no_wait() - Wait for a processor boot status * without requesting or waiting for * a response. * * @proc_id: Processor ID this request is for * @num_wait_iterations Total number of iterations we will check before * we will timeout and give up * @num_match_iterations How many iterations should we have continued * status to account for status bits glitching. * This is to make sure that match occurs for * consecutive checks. This implies that the * worst case should consider that the stable * time should at the worst be num_wait_iterations * num_match_iterations to prevent timeout. * @delay_per_iteration_us Specifies how long to wait (in micro seconds) * between each status checks. This is the minimum * duration, and overhead of register reads and * checks are on top of this and can vary based on * varied conditions. * @delay_before_iterations_us Specifies how long to wait (in micro seconds) * before the very first check in the first * iteration of status check loop. This is the * minimum duration, and overhead of register * reads and checks are. * @status_flags_1_set_all_wait If non-zero, Specifies that all bits of the * status matching this field requested MUST be 1. * @status_flags_1_set_any_wait If non-zero, Specifies that at least one of the * bits matching this field requested MUST be 1. * @status_flags_1_clr_all_wait If non-zero, Specifies that all bits of the * status matching this field requested MUST be 0. * @status_flags_1_clr_any_wait If non-zero, Specifies that at least one of the * bits matching this field requested MUST be 0. * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_proc_wait_boot_status_no_wait(uint8_t proc_id, uint8_t num_wait_iterations, uint8_t num_match_iterations, uint8_t delay_per_iteration_us, uint8_t delay_before_iterations_us, uint32_t status_flags_1_set_all_wait, uint32_t status_flags_1_set_any_wait, uint32_t status_flags_1_clr_all_wait, uint32_t status_flags_1_clr_any_wait) { struct ti_sci_msg_req_wait_proc_boot_status req; struct ti_sci_msg_hdr *hdr; struct k3_sec_proxy_msg tx_message; int ret; /* Ensure we have sane transfer size */ if (sizeof(req) > info.desc.max_msg_size) return -ERANGE; hdr = (struct ti_sci_msg_hdr *)&req; hdr->seq = ++info.seq; hdr->type = TISCI_MSG_WAIT_PROC_BOOT_STATUS; hdr->host = info.desc.host_id; /* Setup with NORESPONSE flag to keep response queue clean */ hdr->flags = TI_SCI_FLAG_REQ_GENERIC_NORESPONSE; req.processor_id = proc_id; req.num_wait_iterations = num_wait_iterations; req.num_match_iterations = num_match_iterations; req.delay_per_iteration_us = delay_per_iteration_us; req.delay_before_iterations_us = delay_before_iterations_us; req.status_flags_1_set_all_wait = status_flags_1_set_all_wait; req.status_flags_1_set_any_wait = status_flags_1_set_any_wait; req.status_flags_1_clr_all_wait = status_flags_1_clr_all_wait; req.status_flags_1_clr_any_wait = status_flags_1_clr_any_wait; tx_message.buf = (uint8_t *)&req; tx_message.len = sizeof(req); /* Send message */ ret = k3_sec_proxy_send(SP_HIGH_PRIORITY, &tx_message); if (ret) { ERROR("Message sending failed (%d)\n", ret); return ret; } /* Return without waiting for response */ return 0; } /** * ti_sci_init() - Basic initialization * * Return: 0 if all goes well, else appropriate error message */ int ti_sci_init(void) { struct ti_sci_msg_resp_version rev_info; int ret; ret = ti_sci_get_revision(&rev_info); if (ret) { ERROR("Unable to communicate with control firmware (%d)\n", ret); return ret; } INFO("SYSFW ABI: %d.%d (firmware rev 0x%04x '%s')\n", rev_info.abi_major, rev_info.abi_minor, rev_info.firmware_revision, rev_info.firmware_description); return 0; } trusted-firmware-a-2.2/plat/ti/k3/common/drivers/ti_sci/ti_sci.h000066400000000000000000000241061355360272700246500ustar00rootroot00000000000000/* * Texas Instruments System Control Interface API * Based on Linux and U-Boot implementation * * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TI_SCI_H #define TI_SCI_H #include #include /** * Device control operations * * - ti_sci_device_get - command to request for device managed by TISCI * - ti_sci_device_get_exclusive - exclusively request a device * - ti_sci_device_idle - Command to idle a device managed by TISCI * - ti_sci_device_idle_exclusive - exclusively idle a device * - ti_sci_device_put - command to release a device managed by TISCI * - ti_sci_device_put_no_wait - release a device without waiting for response * - ti_sci_device_is_valid - Is the device valid * - ti_sci_device_get_clcnt - Get context loss counter * @count: Pointer to Context Loss counter to populate * - ti_sci_device_is_idle - Check if the device is requested to be idle * @r_state: true if requested to be idle * - ti_sci_device_is_stop - Check if the device is requested to be stopped * @r_state: true if requested to be stopped * @curr_state: true if currently stopped. * - ti_sci_device_is_on - Check if the device is requested to be ON * @r_state: true if requested to be ON * @curr_state: true if currently ON and active * - ti_sci_device_is_trans - Check if the device is currently transitioning * @curr_state: true if currently transitioning. * - ti_sci_device_set_resets - Command to set resets for * device managed by TISCI * @reset_state: Device specific reset bit field * - ti_sci_device_get_resets - Get reset state for device managed by TISCI * @reset_state: Pointer to reset state to populate * * NOTE: for all these functions, the following are generic in nature: * @id: Device Identifier * Returns 0 for successful request, else returns corresponding error message. * * Request for the device - NOTE: the client MUST maintain integrity of * usage count by balancing get_device with put_device. No refcounting is * managed by driver for that purpose. */ int ti_sci_device_get(uint32_t id); int ti_sci_device_get_exclusive(uint32_t id); int ti_sci_device_idle(uint32_t id); int ti_sci_device_idle_exclusive(uint32_t id); int ti_sci_device_put(uint32_t id); int ti_sci_device_put_no_wait(uint32_t id); int ti_sci_device_is_valid(uint32_t id); int ti_sci_device_get_clcnt(uint32_t id, uint32_t *count); int ti_sci_device_is_idle(uint32_t id, bool *r_state); int ti_sci_device_is_stop(uint32_t id, bool *r_state, bool *curr_state); int ti_sci_device_is_on(uint32_t id, bool *r_state, bool *curr_state); int ti_sci_device_is_trans(uint32_t id, bool *curr_state); int ti_sci_device_set_resets(uint32_t id, uint32_t reset_state); int ti_sci_device_get_resets(uint32_t id, uint32_t *reset_state); /** * Clock control operations * * - ti_sci_clock_get - Get control of a clock from TI SCI * @needs_ssc: 'true' iff Spread Spectrum clock is desired * @can_change_freq: 'true' iff frequency change is desired * @enable_input_term: 'true' iff input termination is desired * - ti_sci_clock_idle - Idle a clock which is in our control * - ti_sci_clock_put - Release a clock from our control * - ti_sci_clock_is_auto - Is the clock being auto managed * @req_state: state indicating if the clock is auto managed * - ti_sci_clock_is_on - Is the clock ON * @req_state: state indicating if the clock is managed by us and enabled * @curr_state: state indicating if the clock is ready for operation * - ti_sci_clock_is_off - Is the clock OFF * @req_state: state indicating if the clock is managed by us and disabled * @curr_state: state indicating if the clock is NOT ready for operation * - ti_sci_clock_set_parent - Set the clock source of a specific device clock * @parent_id: Parent clock identifier to set * - ti_sci_clock_get_parent - Get current parent clock source * @parent_id: Current clock parent * - ti_sci_clock_get_num_parents - Get num parents of the current clk source * @num_parents: Returns he number of parents to the current clock. * - ti_sci_clock_get_match_freq - Find a good match for frequency * @match_freq: Frequency match in Hz response. * - ti_sci_clock_set_freq - Set a frequency for clock * - ti_sci_clock_get_freq - Get current frequency * @freq: Currently frequency in Hz * * NOTE: for all these functions, the following are generic in nature: * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has its own set of clock inputs. This indexes * which clock input to modify. * @min_freq: The minimum allowable frequency in Hz. This is the minimum * allowable programmed frequency and does not account for clock * tolerances and jitter. * @target_freq: The target clock frequency in Hz. A frequency will be * processed as close to this target frequency as possible. * @max_freq: The maximum allowable frequency in Hz. This is the maximum * allowable programmed frequency and does not account for clock * tolerances and jitter. * Returns 0 for successful request, else returns corresponding error message. * * Request for the clock - NOTE: the client MUST maintain integrity of * usage count by balancing get_clock with put_clock. No refcounting is * managed by driver for that purpose. */ int ti_sci_clock_get(uint32_t dev_id, uint8_t clk_id, bool needs_ssc, bool can_change_freq, bool enable_input_term); int ti_sci_clock_idle(uint32_t dev_id, uint8_t clk_id); int ti_sci_clock_put(uint32_t dev_id, uint8_t clk_id); int ti_sci_clock_is_auto(uint32_t dev_id, uint8_t clk_id, bool *req_state); int ti_sci_clock_is_on(uint32_t dev_id, uint8_t clk_id, bool *req_state, bool *curr_state); int ti_sci_clock_is_off(uint32_t dev_id, uint8_t clk_id, bool *req_state, bool *curr_state); int ti_sci_clock_set_parent(uint32_t dev_id, uint8_t clk_id, uint8_t parent_id); int ti_sci_clock_get_parent(uint32_t dev_id, uint8_t clk_id, uint8_t *parent_id); int ti_sci_clock_get_num_parents(uint32_t dev_id, uint8_t clk_id, uint8_t *num_parents); int ti_sci_clock_get_match_freq(uint32_t dev_id, uint8_t clk_id, uint64_t min_freq, uint64_t target_freq, uint64_t max_freq, uint64_t *match_freq); int ti_sci_clock_set_freq(uint32_t dev_id, uint8_t clk_id, uint64_t min_freq, uint64_t target_freq, uint64_t max_freq); int ti_sci_clock_get_freq(uint32_t dev_id, uint8_t clk_id, uint64_t *freq); /** * Core control operations * * - ti_sci_core_reboot() - Command to request system reset * * Return: 0 if all went well, else returns appropriate error value. */ int ti_sci_core_reboot(void); /** * Processor control operations * * - ti_sci_proc_request - Command to request a physical processor control * - ti_sci_proc_release - Command to release a physical processor control * - ti_sci_proc_handover - Command to handover a physical processor control to * a host in the processor's access control list. * @host_id: Host ID to get the control of the processor * - ti_sci_proc_set_boot_cfg - Command to set the processor boot configuration flags * @config_flags_set: Configuration flags to be set * @config_flags_clear: Configuration flags to be cleared. * - ti_sci_proc_set_boot_ctrl - Command to set the processor boot control flags * @control_flags_set: Control flags to be set * @control_flags_clear: Control flags to be cleared * - ti_sci_proc_set_boot_ctrl_no_wait - Same as above without waiting for response * - ti_sci_proc_auth_boot_image - Command to authenticate and load the image * and then set the processor configuration flags. * @cert_addr: Memory address at which payload image certificate is located. * - ti_sci_proc_get_boot_status - Command to get the processor boot status * - ti_sci_proc_wait_boot_status - Command to wait for a processor boot status * - ti_sci_proc_wait_boot_status_no_wait - Same as above without waiting for response * * NOTE: for all these functions, the following are generic in nature: * @proc_id: Processor ID * Returns 0 for successful request, else returns corresponding error message. */ int ti_sci_proc_request(uint8_t proc_id); int ti_sci_proc_release(uint8_t proc_id); int ti_sci_proc_handover(uint8_t proc_id, uint8_t host_id); int ti_sci_proc_set_boot_cfg(uint8_t proc_id, uint64_t bootvector, uint32_t config_flags_set, uint32_t config_flags_clear); int ti_sci_proc_set_boot_ctrl(uint8_t proc_id, uint32_t control_flags_set, uint32_t control_flags_clear); int ti_sci_proc_set_boot_ctrl_no_wait(uint8_t proc_id, uint32_t control_flags_set, uint32_t control_flags_clear); int ti_sci_proc_auth_boot_image(uint8_t proc_id, uint64_t cert_addr); int ti_sci_proc_get_boot_status(uint8_t proc_id, uint64_t *bv, uint32_t *cfg_flags, uint32_t *ctrl_flags, uint32_t *sts_flags); int ti_sci_proc_wait_boot_status(uint8_t proc_id, uint8_t num_wait_iterations, uint8_t num_match_iterations, uint8_t delay_per_iteration_us, uint8_t delay_before_iterations_us, uint32_t status_flags_1_set_all_wait, uint32_t status_flags_1_set_any_wait, uint32_t status_flags_1_clr_all_wait, uint32_t status_flags_1_clr_any_wait); int ti_sci_proc_wait_boot_status_no_wait(uint8_t proc_id, uint8_t num_wait_iterations, uint8_t num_match_iterations, uint8_t delay_per_iteration_us, uint8_t delay_before_iterations_us, uint32_t status_flags_1_set_all_wait, uint32_t status_flags_1_set_any_wait, uint32_t status_flags_1_clr_all_wait, uint32_t status_flags_1_clr_any_wait); /** * ti_sci_init() - Basic initialization * * Return: 0 if all goes good, else appropriate error message. */ int ti_sci_init(void); #endif /* TI_SCI_H */ trusted-firmware-a-2.2/plat/ti/k3/common/drivers/ti_sci/ti_sci_protocol.h000066400000000000000000000602001355360272700265640ustar00rootroot00000000000000/* * Texas Instruments System Control Interface (TISCI) Protocol * * Communication protocol with TI SCI hardware * The system works in a message response protocol * See: http://processors.wiki.ti.com/index.php/TISCI for details * * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/ * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TI_SCI_PROTOCOL_H #define TI_SCI_PROTOCOL_H #include /* Generic Messages */ #define TI_SCI_MSG_ENABLE_WDT 0x0000 #define TI_SCI_MSG_WAKE_RESET 0x0001 #define TI_SCI_MSG_VERSION 0x0002 #define TI_SCI_MSG_WAKE_REASON 0x0003 #define TI_SCI_MSG_GOODBYE 0x0004 #define TI_SCI_MSG_SYS_RESET 0x0005 /* Device requests */ #define TI_SCI_MSG_SET_DEVICE_STATE 0x0200 #define TI_SCI_MSG_GET_DEVICE_STATE 0x0201 #define TI_SCI_MSG_SET_DEVICE_RESETS 0x0202 /* Clock requests */ #define TI_SCI_MSG_SET_CLOCK_STATE 0x0100 #define TI_SCI_MSG_GET_CLOCK_STATE 0x0101 #define TI_SCI_MSG_SET_CLOCK_PARENT 0x0102 #define TI_SCI_MSG_GET_CLOCK_PARENT 0x0103 #define TI_SCI_MSG_GET_NUM_CLOCK_PARENTS 0x0104 #define TI_SCI_MSG_SET_CLOCK_FREQ 0x010c #define TI_SCI_MSG_QUERY_CLOCK_FREQ 0x010d #define TI_SCI_MSG_GET_CLOCK_FREQ 0x010e /* Processor Control Messages */ #define TISCI_MSG_PROC_REQUEST 0xc000 #define TISCI_MSG_PROC_RELEASE 0xc001 #define TISCI_MSG_PROC_HANDOVER 0xc005 #define TISCI_MSG_SET_PROC_BOOT_CONFIG 0xc100 #define TISCI_MSG_SET_PROC_BOOT_CTRL 0xc101 #define TISCI_MSG_PROC_AUTH_BOOT_IMIAGE 0xc120 #define TISCI_MSG_GET_PROC_BOOT_STATUS 0xc400 #define TISCI_MSG_WAIT_PROC_BOOT_STATUS 0xc401 /** * struct ti_sci_msg_hdr - Generic Message Header for All messages and responses * @type: Type of messages: One of TI_SCI_MSG* values * @host: Host of the message * @seq: Message identifier indicating a transfer sequence * @flags: Flag for the message */ struct ti_sci_msg_hdr { uint16_t type; uint8_t host; uint8_t seq; #define TI_SCI_MSG_FLAG(val) (1 << (val)) #define TI_SCI_FLAG_REQ_GENERIC_NORESPONSE 0x0 #define TI_SCI_FLAG_REQ_ACK_ON_RECEIVED TI_SCI_MSG_FLAG(0) #define TI_SCI_FLAG_REQ_ACK_ON_PROCESSED TI_SCI_MSG_FLAG(1) #define TI_SCI_FLAG_RESP_GENERIC_NACK 0x0 #define TI_SCI_FLAG_RESP_GENERIC_ACK TI_SCI_MSG_FLAG(1) /* Additional Flags */ uint32_t flags; } __packed; /** * struct ti_sci_msg_resp_version - Response for a message * @hdr: Generic header * @firmware_description: String describing the firmware * @firmware_revision: Firmware revision * @abi_major: Major version of the ABI that firmware supports * @abi_minor: Minor version of the ABI that firmware supports * * In general, ABI version changes follow the rule that minor version increments * are backward compatible. Major revision changes in ABI may not be * backward compatible. * * Response to a generic message with message type TI_SCI_MSG_VERSION */ struct ti_sci_msg_resp_version { struct ti_sci_msg_hdr hdr; #define FIRMWARE_DESCRIPTION_LENGTH 32 char firmware_description[FIRMWARE_DESCRIPTION_LENGTH]; uint16_t firmware_revision; uint8_t abi_major; uint8_t abi_minor; } __packed; /** * struct ti_sci_msg_req_reboot - Reboot the SoC * @hdr: Generic Header * * Request type is TI_SCI_MSG_SYS_RESET, responded with a generic * ACK/NACK message. */ struct ti_sci_msg_req_reboot { struct ti_sci_msg_hdr hdr; } __packed; /** * struct ti_sci_msg_req_set_device_state - Set the desired state of the device * @hdr: Generic header * @id: Indicates which device to modify * @reserved: Reserved space in message, must be 0 for backward compatibility * @state: The desired state of the device. * * Certain flags can also be set to alter the device state: * + MSG_FLAG_DEVICE_WAKE_ENABLED - Configure the device to be a wake source. * The meaning of this flag will vary slightly from device to device and from * SoC to SoC but it generally allows the device to wake the SoC out of deep * suspend states. * + MSG_FLAG_DEVICE_RESET_ISO - Enable reset isolation for this device. * + MSG_FLAG_DEVICE_EXCLUSIVE - Claim this device exclusively. When passed * with STATE_RETENTION or STATE_ON, it will claim the device exclusively. * If another host already has this device set to STATE_RETENTION or STATE_ON, * the message will fail. Once successful, other hosts attempting to set * STATE_RETENTION or STATE_ON will fail. * * Request type is TI_SCI_MSG_SET_DEVICE_STATE, responded with a generic * ACK/NACK message. */ struct ti_sci_msg_req_set_device_state { /* Additional hdr->flags options */ #define MSG_FLAG_DEVICE_WAKE_ENABLED TI_SCI_MSG_FLAG(8) #define MSG_FLAG_DEVICE_RESET_ISO TI_SCI_MSG_FLAG(9) #define MSG_FLAG_DEVICE_EXCLUSIVE TI_SCI_MSG_FLAG(10) struct ti_sci_msg_hdr hdr; uint32_t id; uint32_t reserved; #define MSG_DEVICE_SW_STATE_AUTO_OFF 0 #define MSG_DEVICE_SW_STATE_RETENTION 1 #define MSG_DEVICE_SW_STATE_ON 2 uint8_t state; } __packed; /** * struct ti_sci_msg_req_get_device_state - Request to get device. * @hdr: Generic header * @id: Device Identifier * * Request type is TI_SCI_MSG_GET_DEVICE_STATE, responded device state * information */ struct ti_sci_msg_req_get_device_state { struct ti_sci_msg_hdr hdr; uint32_t id; } __packed; /** * struct ti_sci_msg_resp_get_device_state - Response to get device request. * @hdr: Generic header * @context_loss_count: Indicates how many times the device has lost context. A * driver can use this monotonic counter to determine if the device has * lost context since the last time this message was exchanged. * @resets: Programmed state of the reset lines. * @programmed_state: The state as programmed by set_device. * - Uses the MSG_DEVICE_SW_* macros * @current_state: The actual state of the hardware. * * Response to request TI_SCI_MSG_GET_DEVICE_STATE. */ struct ti_sci_msg_resp_get_device_state { struct ti_sci_msg_hdr hdr; uint32_t context_loss_count; uint32_t resets; uint8_t programmed_state; #define MSG_DEVICE_HW_STATE_OFF 0 #define MSG_DEVICE_HW_STATE_ON 1 #define MSG_DEVICE_HW_STATE_TRANS 2 uint8_t current_state; } __packed; /** * struct ti_sci_msg_req_set_device_resets - Set the desired resets * configuration of the device * @hdr: Generic header * @id: Indicates which device to modify * @resets: A bit field of resets for the device. The meaning, behavior, * and usage of the reset flags are device specific. 0 for a bit * indicates releasing the reset represented by that bit while 1 * indicates keeping it held. * * Request type is TI_SCI_MSG_SET_DEVICE_RESETS, responded with a generic * ACK/NACK message. */ struct ti_sci_msg_req_set_device_resets { struct ti_sci_msg_hdr hdr; uint32_t id; uint32_t resets; } __packed; /** * struct ti_sci_msg_req_set_clock_state - Request to setup a Clock state * @hdr: Generic Header, Certain flags can be set specific to the clocks: * MSG_FLAG_CLOCK_ALLOW_SSC: Allow this clock to be modified * via spread spectrum clocking. * MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE: Allow this clock's * frequency to be changed while it is running so long as it * is within the min/max limits. * MSG_FLAG_CLOCK_INPUT_TERM: Enable input termination, this * is only applicable to clock inputs on the SoC pseudo-device. * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has it's own set of clock inputs. This indexes * which clock input to modify. * @request_state: Request the state for the clock to be set to. * MSG_CLOCK_SW_STATE_UNREQ: The IP does not require this clock, * it can be disabled, regardless of the state of the device * MSG_CLOCK_SW_STATE_AUTO: Allow the System Controller to * automatically manage the state of this clock. If the device * is enabled, then the clock is enabled. If the device is set * to off or retention, then the clock is internally set as not * being required by the device.(default) * MSG_CLOCK_SW_STATE_REQ: Configure the clock to be enabled, * regardless of the state of the device. * * Normally, all required clocks are managed by TISCI entity, this is used * only for specific control *IF* required. Auto managed state is * MSG_CLOCK_SW_STATE_AUTO, in other states, TISCI entity assume remote * will explicitly control. * * Request type is TI_SCI_MSG_SET_CLOCK_STATE, response is a generic * ACK or NACK message. */ struct ti_sci_msg_req_set_clock_state { /* Additional hdr->flags options */ #define MSG_FLAG_CLOCK_ALLOW_SSC TI_SCI_MSG_FLAG(8) #define MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE TI_SCI_MSG_FLAG(9) #define MSG_FLAG_CLOCK_INPUT_TERM TI_SCI_MSG_FLAG(10) struct ti_sci_msg_hdr hdr; uint32_t dev_id; uint8_t clk_id; #define MSG_CLOCK_SW_STATE_UNREQ 0 #define MSG_CLOCK_SW_STATE_AUTO 1 #define MSG_CLOCK_SW_STATE_REQ 2 uint8_t request_state; } __packed; /** * struct ti_sci_msg_req_get_clock_state - Request for clock state * @hdr: Generic Header * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has it's own set of clock inputs. This indexes * which clock input to get state of. * * Request type is TI_SCI_MSG_GET_CLOCK_STATE, response is state * of the clock */ struct ti_sci_msg_req_get_clock_state { struct ti_sci_msg_hdr hdr; uint32_t dev_id; uint8_t clk_id; } __packed; /** * struct ti_sci_msg_resp_get_clock_state - Response to get clock state * @hdr: Generic Header * @programmed_state: Any programmed state of the clock. This is one of * MSG_CLOCK_SW_STATE* values. * @current_state: Current state of the clock. This is one of: * MSG_CLOCK_HW_STATE_NOT_READY: Clock is not ready * MSG_CLOCK_HW_STATE_READY: Clock is ready * * Response to TI_SCI_MSG_GET_CLOCK_STATE. */ struct ti_sci_msg_resp_get_clock_state { struct ti_sci_msg_hdr hdr; uint8_t programmed_state; #define MSG_CLOCK_HW_STATE_NOT_READY 0 #define MSG_CLOCK_HW_STATE_READY 1 uint8_t current_state; } __packed; /** * struct ti_sci_msg_req_set_clock_parent - Set the clock parent * @hdr: Generic Header * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has it's own set of clock inputs. This indexes * which clock input to modify. * @parent_id: The new clock parent is selectable by an index via this * parameter. * * Request type is TI_SCI_MSG_SET_CLOCK_PARENT, response is generic * ACK / NACK message. */ struct ti_sci_msg_req_set_clock_parent { struct ti_sci_msg_hdr hdr; uint32_t dev_id; uint8_t clk_id; uint8_t parent_id; } __packed; /** * struct ti_sci_msg_req_get_clock_parent - Get the clock parent * @hdr: Generic Header * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * Each device has it's own set of clock inputs. This indexes * which clock input to get the parent for. * * Request type is TI_SCI_MSG_GET_CLOCK_PARENT, response is parent information */ struct ti_sci_msg_req_get_clock_parent { struct ti_sci_msg_hdr hdr; uint32_t dev_id; uint8_t clk_id; } __packed; /** * struct ti_sci_msg_resp_get_clock_parent - Response with clock parent * @hdr: Generic Header * @parent_id: The current clock parent * * Response to TI_SCI_MSG_GET_CLOCK_PARENT. */ struct ti_sci_msg_resp_get_clock_parent { struct ti_sci_msg_hdr hdr; uint8_t parent_id; } __packed; /** * struct ti_sci_msg_req_get_clock_num_parents - Request to get clock parents * @hdr: Generic header * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * * This request provides information about how many clock parent options * are available for a given clock to a device. This is typically used * for input clocks. * * Request type is TI_SCI_MSG_GET_NUM_CLOCK_PARENTS, response is appropriate * message, or NACK in case of inability to satisfy request. */ struct ti_sci_msg_req_get_clock_num_parents { struct ti_sci_msg_hdr hdr; uint32_t dev_id; uint8_t clk_id; } __packed; /** * struct ti_sci_msg_resp_get_clock_num_parents - Response for get clk parents * @hdr: Generic header * @num_parents: Number of clock parents * * Response to TI_SCI_MSG_GET_NUM_CLOCK_PARENTS */ struct ti_sci_msg_resp_get_clock_num_parents { struct ti_sci_msg_hdr hdr; uint8_t num_parents; } __packed; /** * struct ti_sci_msg_req_query_clock_freq - Request to query a frequency * @hdr: Generic Header * @dev_id: Device identifier this request is for * @min_freq_hz: The minimum allowable frequency in Hz. This is the minimum * allowable programmed frequency and does not account for clock * tolerances and jitter. * @target_freq_hz: The target clock frequency. A frequency will be found * as close to this target frequency as possible. * @max_freq_hz: The maximum allowable frequency in Hz. This is the maximum * allowable programmed frequency and does not account for clock * tolerances and jitter. * @clk_id: Clock identifier for the device for this request. * * NOTE: Normally clock frequency management is automatically done by TISCI * entity. In case of specific requests, TISCI evaluates capability to achieve * requested frequency within provided range and responds with * result message. * * Request type is TI_SCI_MSG_QUERY_CLOCK_FREQ, response is appropriate message, * or NACK in case of inability to satisfy request. */ struct ti_sci_msg_req_query_clock_freq { struct ti_sci_msg_hdr hdr; uint32_t dev_id; uint64_t min_freq_hz; uint64_t target_freq_hz; uint64_t max_freq_hz; uint8_t clk_id; } __packed; /** * struct ti_sci_msg_resp_query_clock_freq - Response to a clock frequency query * @hdr: Generic Header * @freq_hz: Frequency that is the best match in Hz. * * Response to request type TI_SCI_MSG_QUERY_CLOCK_FREQ. NOTE: if the request * cannot be satisfied, the message will be of type NACK. */ struct ti_sci_msg_resp_query_clock_freq { struct ti_sci_msg_hdr hdr; uint64_t freq_hz; } __packed; /** * struct ti_sci_msg_req_set_clock_freq - Request to setup a clock frequency * @hdr: Generic Header * @dev_id: Device identifier this request is for * @min_freq_hz: The minimum allowable frequency in Hz. This is the minimum * allowable programmed frequency and does not account for clock * tolerances and jitter. * @target_freq_hz: The target clock frequency. The clock will be programmed * at a rate as close to this target frequency as possible. * @max_freq_hz: The maximum allowable frequency in Hz. This is the maximum * allowable programmed frequency and does not account for clock * tolerances and jitter. * @clk_id: Clock identifier for the device for this request. * * NOTE: Normally clock frequency management is automatically done by TISCI * entity. In case of specific requests, TISCI evaluates capability to achieve * requested range and responds with success/failure message. * * This sets the desired frequency for a clock within an allowable * range. This message will fail on an enabled clock unless * MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE is set for the clock. Additionally, * if other clocks have their frequency modified due to this message, * they also must have the MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE or be disabled. * * Calling set frequency on a clock input to the SoC pseudo-device will * inform the PMMC of that clock's frequency. Setting a frequency of * zero will indicate the clock is disabled. * * Calling set frequency on clock outputs from the SoC pseudo-device will * function similarly to setting the clock frequency on a device. * * Request type is TI_SCI_MSG_SET_CLOCK_FREQ, response is a generic ACK/NACK * message. */ struct ti_sci_msg_req_set_clock_freq { struct ti_sci_msg_hdr hdr; uint32_t dev_id; uint64_t min_freq_hz; uint64_t target_freq_hz; uint64_t max_freq_hz; uint8_t clk_id; } __packed; /** * struct ti_sci_msg_req_get_clock_freq - Request to get the clock frequency * @hdr: Generic Header * @dev_id: Device identifier this request is for * @clk_id: Clock identifier for the device for this request. * * NOTE: Normally clock frequency management is automatically done by TISCI * entity. In some cases, clock frequencies are configured by host. * * Request type is TI_SCI_MSG_GET_CLOCK_FREQ, responded with clock frequency * that the clock is currently at. */ struct ti_sci_msg_req_get_clock_freq { struct ti_sci_msg_hdr hdr; uint32_t dev_id; uint8_t clk_id; } __packed; /** * struct ti_sci_msg_resp_get_clock_freq - Response of clock frequency request * @hdr: Generic Header * @freq_hz: Frequency that the clock is currently on, in Hz. * * Response to request type TI_SCI_MSG_GET_CLOCK_FREQ. */ struct ti_sci_msg_resp_get_clock_freq { struct ti_sci_msg_hdr hdr; uint64_t freq_hz; } __packed; #define TISCI_ADDR_LOW_MASK 0x00000000ffffffff #define TISCI_ADDR_HIGH_MASK 0xffffffff00000000 #define TISCI_ADDR_HIGH_SHIFT 32 /** * struct ti_sci_msg_req_proc_request - Request a processor * * @hdr: Generic Header * @processor_id: ID of processor * * Request type is TISCI_MSG_PROC_REQUEST, response is a generic ACK/NACK * message. */ struct ti_sci_msg_req_proc_request { struct ti_sci_msg_hdr hdr; uint8_t processor_id; } __packed; /** * struct ti_sci_msg_req_proc_release - Release a processor * * @hdr: Generic Header * @processor_id: ID of processor * * Request type is TISCI_MSG_PROC_RELEASE, response is a generic ACK/NACK * message. */ struct ti_sci_msg_req_proc_release { struct ti_sci_msg_hdr hdr; uint8_t processor_id; } __packed; /** * struct ti_sci_msg_req_proc_handover - Handover a processor to a host * * @hdr: Generic Header * @processor_id: ID of processor * @host_id: New Host we want to give control to * * Request type is TISCI_MSG_PROC_HANDOVER, response is a generic ACK/NACK * message. */ struct ti_sci_msg_req_proc_handover { struct ti_sci_msg_hdr hdr; uint8_t processor_id; uint8_t host_id; } __packed; /* A53 Config Flags */ #define PROC_BOOT_CFG_FLAG_ARMV8_DBG_EN 0x00000001 #define PROC_BOOT_CFG_FLAG_ARMV8_DBG_NIDEN 0x00000002 #define PROC_BOOT_CFG_FLAG_ARMV8_DBG_SPIDEN 0x00000004 #define PROC_BOOT_CFG_FLAG_ARMV8_DBG_SPNIDEN 0x00000008 #define PROC_BOOT_CFG_FLAG_ARMV8_AARCH32 0x00000100 /* R5 Config Flags */ #define PROC_BOOT_CFG_FLAG_R5_DBG_EN 0x00000001 #define PROC_BOOT_CFG_FLAG_R5_DBG_NIDEN 0x00000002 #define PROC_BOOT_CFG_FLAG_R5_LOCKSTEP 0x00000100 #define PROC_BOOT_CFG_FLAG_R5_TEINIT 0x00000200 #define PROC_BOOT_CFG_FLAG_R5_NMFI_EN 0x00000400 #define PROC_BOOT_CFG_FLAG_R5_TCM_RSTBASE 0x00000800 #define PROC_BOOT_CFG_FLAG_R5_BTCM_EN 0x00001000 #define PROC_BOOT_CFG_FLAG_R5_ATCM_EN 0x00002000 /** * struct ti_sci_msg_req_set_proc_boot_config - Set Processor boot configuration * @hdr: Generic Header * @processor_id: ID of processor * @bootvector_low: Lower 32bit (Little Endian) of boot vector * @bootvector_high: Higher 32bit (Little Endian) of boot vector * @config_flags_set: Optional Processor specific Config Flags to set. * Setting a bit here implies required bit sets to 1. * @config_flags_clear: Optional Processor specific Config Flags to clear. * Setting a bit here implies required bit gets cleared. * * Request type is TISCI_MSG_SET_PROC_BOOT_CONFIG, response is a generic * ACK/NACK message. */ struct ti_sci_msg_req_set_proc_boot_config { struct ti_sci_msg_hdr hdr; uint8_t processor_id; uint32_t bootvector_low; uint32_t bootvector_high; uint32_t config_flags_set; uint32_t config_flags_clear; } __packed; /* R5 Control Flags */ #define PROC_BOOT_CTRL_FLAG_R5_CORE_HALT 0x00000001 /** * struct ti_sci_msg_req_set_proc_boot_ctrl - Set Processor boot control flags * @hdr: Generic Header * @processor_id: ID of processor * @config_flags_set: Optional Processor specific Config Flags to set. * Setting a bit here implies required bit sets to 1. * @config_flags_clear: Optional Processor specific Config Flags to clear. * Setting a bit here implies required bit gets cleared. * * Request type is TISCI_MSG_SET_PROC_BOOT_CTRL, response is a generic ACK/NACK * message. */ struct ti_sci_msg_req_set_proc_boot_ctrl { struct ti_sci_msg_hdr hdr; uint8_t processor_id; uint32_t control_flags_set; uint32_t control_flags_clear; } __packed; /** * struct ti_sci_msg_req_proc_auth_start_image - Authenticate and start image * @hdr: Generic Header * @processor_id: ID of processor * @cert_addr_low: Lower 32bit (Little Endian) of certificate * @cert_addr_high: Higher 32bit (Little Endian) of certificate * * Request type is TISCI_MSG_PROC_AUTH_BOOT_IMAGE, response is a generic * ACK/NACK message. */ struct ti_sci_msg_req_proc_auth_boot_image { struct ti_sci_msg_hdr hdr; uint8_t processor_id; uint32_t cert_addr_low; uint32_t cert_addr_high; } __packed; /** * struct ti_sci_msg_req_get_proc_boot_status - Get processor boot status * @hdr: Generic Header * @processor_id: ID of processor * * Request type is TISCI_MSG_GET_PROC_BOOT_STATUS, response is appropriate * message, or NACK in case of inability to satisfy request. */ struct ti_sci_msg_req_get_proc_boot_status { struct ti_sci_msg_hdr hdr; uint8_t processor_id; } __packed; /* ARMv8 Status Flags */ #define PROC_BOOT_STATUS_FLAG_ARMV8_WFE 0x00000001 #define PROC_BOOT_STATUS_FLAG_ARMV8_WFI 0x00000002 /* R5 Status Flags */ #define PROC_BOOT_STATUS_FLAG_R5_WFE 0x00000001 #define PROC_BOOT_STATUS_FLAG_R5_WFI 0x00000002 #define PROC_BOOT_STATUS_FLAG_R5_CLK_GATED 0x00000004 #define PROC_BOOT_STATUS_FLAG_R5_LOCKSTEP_PERMITTED 0x00000100 /** * \brief Processor Status Response * struct ti_sci_msg_resp_get_proc_boot_status - Processor boot status response * @hdr: Generic Header * @processor_id: ID of processor * @bootvector_low: Lower 32bit (Little Endian) of boot vector * @bootvector_high: Higher 32bit (Little Endian) of boot vector * @config_flags: Optional Processor specific Config Flags set. * @control_flags: Optional Processor specific Control Flags. * @status_flags: Optional Processor specific Status Flags set. * * Response to TISCI_MSG_GET_PROC_BOOT_STATUS. */ struct ti_sci_msg_resp_get_proc_boot_status { struct ti_sci_msg_hdr hdr; uint8_t processor_id; uint32_t bootvector_low; uint32_t bootvector_high; uint32_t config_flags; uint32_t control_flags; uint32_t status_flags; } __packed; /** * struct ti_sci_msg_req_wait_proc_boot_status - Wait for a processor boot status * @hdr: Generic Header * @processor_id: ID of processor * @num_wait_iterations Total number of iterations we will check before * we will timeout and give up * @num_match_iterations How many iterations should we have continued * status to account for status bits glitching. * This is to make sure that match occurs for * consecutive checks. This implies that the * worst case should consider that the stable * time should at the worst be num_wait_iterations * num_match_iterations to prevent timeout. * @delay_per_iteration_us Specifies how long to wait (in micro seconds) * between each status checks. This is the minimum * duration, and overhead of register reads and * checks are on top of this and can vary based on * varied conditions. * @delay_before_iterations_us Specifies how long to wait (in micro seconds) * before the very first check in the first * iteration of status check loop. This is the * minimum duration, and overhead of register * reads and checks are. * @status_flags_1_set_all_wait If non-zero, Specifies that all bits of the * status matching this field requested MUST be 1. * @status_flags_1_set_any_wait If non-zero, Specifies that at least one of the * bits matching this field requested MUST be 1. * @status_flags_1_clr_all_wait If non-zero, Specifies that all bits of the * status matching this field requested MUST be 0. * @status_flags_1_clr_any_wait If non-zero, Specifies that at least one of the * bits matching this field requested MUST be 0. * * Request type is TISCI_MSG_WAIT_PROC_BOOT_STATUS, response is appropriate * message, or NACK in case of inability to satisfy request. */ struct ti_sci_msg_req_wait_proc_boot_status { struct ti_sci_msg_hdr hdr; uint8_t processor_id; uint8_t num_wait_iterations; uint8_t num_match_iterations; uint8_t delay_per_iteration_us; uint8_t delay_before_iterations_us; uint32_t status_flags_1_set_all_wait; uint32_t status_flags_1_set_any_wait; uint32_t status_flags_1_clr_all_wait; uint32_t status_flags_1_clr_any_wait; } __packed; #endif /* TI_SCI_PROTOCOL_H */ trusted-firmware-a-2.2/plat/ti/k3/common/k3_bl31_setup.c000066400000000000000000000121761355360272700230230ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include /* Table of regions to map using the MMU */ const mmap_region_t plat_k3_mmap[] = { MAP_REGION_FLAT(K3_USART_BASE, K3_USART_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(K3_GIC_BASE, K3_GIC_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(SEC_PROXY_RT_BASE, SEC_PROXY_RT_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(SEC_PROXY_SCFG_BASE, SEC_PROXY_SCFG_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(SEC_PROXY_DATA_BASE, SEC_PROXY_DATA_SIZE, MT_DEVICE | MT_RW | MT_SECURE), { /* sentinel */ } }; /* * Placeholder variables for maintaining information about the next image(s) */ static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; /******************************************************************************* * Gets SPSR for BL33 entry ******************************************************************************/ static uint32_t k3_get_spsr_for_bl33_entry(void) { unsigned long el_status; unsigned int mode; uint32_t spsr; /* Figure out what mode we enter the non-secure world in */ el_status = read_id_aa64pfr0_el1() >> ID_AA64PFR0_EL2_SHIFT; el_status &= ID_AA64PFR0_ELX_MASK; mode = (el_status) ? MODE_EL2 : MODE_EL1; spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); return spsr; } /******************************************************************************* * Perform any BL3-1 early platform setup, such as console init and deciding on * memory layout. ******************************************************************************/ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { /* There are no parameters from BL2 if BL31 is a reset vector */ assert(arg0 == 0U); assert(arg1 == 0U); bl31_console_setup(); #ifdef BL32_BASE /* Populate entry point information for BL32 */ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0); bl32_image_ep_info.pc = BL32_BASE; bl32_image_ep_info.spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); #endif /* Populate entry point information for BL33 */ SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); bl33_image_ep_info.pc = PRELOADED_BL33_BASE; bl33_image_ep_info.spsr = k3_get_spsr_for_bl33_entry(); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); #ifdef K3_HW_CONFIG_BASE /* * According to the file ``Documentation/arm64/booting.txt`` of the * Linux kernel tree, Linux expects the physical address of the device * tree blob (DTB) in x0, while x1-x3 are reserved for future use and * must be 0. */ bl33_image_ep_info.args.arg0 = (u_register_t)K3_HW_CONFIG_BASE; bl33_image_ep_info.args.arg1 = 0U; bl33_image_ep_info.args.arg2 = 0U; bl33_image_ep_info.args.arg3 = 0U; #endif } void bl31_plat_arch_setup(void) { const mmap_region_t bl_regions[] = { MAP_REGION_FLAT(BL31_START, BL31_END - BL31_START, MT_MEMORY | MT_RW | MT_SECURE), MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, MT_CODE | MT_RO | MT_SECURE), MAP_REGION_FLAT(BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE, MT_RO_DATA | MT_RO | MT_SECURE), #if USE_COHERENT_MEM MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, MT_DEVICE | MT_RW | MT_SECURE), #endif { /* sentinel */ } }; setup_page_tables(bl_regions, plat_k3_mmap); enable_mmu_el3(0); } void bl31_platform_setup(void) { k3_gic_driver_init(K3_GIC_BASE); k3_gic_init(); ti_sci_init(); } void platform_mem_init(void) { /* Do nothing for now... */ } unsigned int plat_get_syscnt_freq2(void) { return SYS_COUNTER_FREQ_IN_TICKS; } /* * Empty function to prevent the console from being uninitialized after BL33 is * started and allow us to see messages from BL31. */ void bl31_plat_runtime_setup(void) { } /******************************************************************************* * Return a pointer to the 'entry_point_info' structure of the next image * for the security state specified. BL3-3 corresponds to the non-secure * image type while BL3-2 corresponds to the secure image type. A NULL * pointer is returned if the image does not exist. ******************************************************************************/ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { entry_point_info_t *next_image_info; assert(sec_state_is_valid(type)); next_image_info = (type == NON_SECURE) ? &bl33_image_ep_info : &bl32_image_ep_info; /* * None of the images on the ARM development platforms can have 0x0 * as the entrypoint */ if (next_image_info->pc) return next_image_info; NOTICE("Requested nonexistent image\n"); return NULL; } trusted-firmware-a-2.2/plat/ti/k3/common/k3_console.c000066400000000000000000000007351355360272700225020ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include void bl31_console_setup(void) { static console_16550_t console; /* Initialize the console to provide early debug support */ console_16550_register(K3_USART_BASE, K3_USART_CLK_SPEED, K3_USART_BAUD, &console); } trusted-firmware-a-2.2/plat/ti/k3/common/k3_gicv3.c000066400000000000000000000043561355360272700220560ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include /* The GICv3 driver only needs to be initialized in EL3 */ uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT]; static const interrupt_prop_t k3_interrupt_props[] = { PLAT_ARM_G1S_IRQ_PROPS(INTR_GROUP1S), PLAT_ARM_G0_IRQ_PROPS(INTR_GROUP0) }; static unsigned int k3_mpidr_to_core_pos(unsigned long mpidr) { return (unsigned int)plat_core_pos_by_mpidr(mpidr); } gicv3_driver_data_t k3_gic_data = { .rdistif_num = PLATFORM_CORE_COUNT, .rdistif_base_addrs = rdistif_base_addrs, .interrupt_props = k3_interrupt_props, .interrupt_props_num = ARRAY_SIZE(k3_interrupt_props), .mpidr_to_core_pos = k3_mpidr_to_core_pos, }; void k3_gic_driver_init(uintptr_t gic_base) { /* GIC Distributor is always at the base of the IP */ uintptr_t gicd_base = gic_base; /* GIC Redistributor base is run-time detected */ uintptr_t gicr_base = 0; for (unsigned int gicr_shift = 18; gicr_shift < 21; gicr_shift++) { uintptr_t gicr_check = gic_base + BIT(gicr_shift); uint32_t iidr = mmio_read_32(gicr_check + GICR_IIDR); if (iidr != 0) { /* Found the GICR base */ gicr_base = gicr_check; break; } } /* Assert if we have not found the GICR base */ assert(gicr_base != 0); /* * The GICv3 driver is initialized in EL3 and does not need * to be initialized again in SEL1. This is because the S-EL1 * can use GIC system registers to manage interrupts and does * not need GIC interface base addresses to be configured. */ k3_gic_data.gicd_base = gicd_base; k3_gic_data.gicr_base = gicr_base; gicv3_driver_init(&k3_gic_data); } void k3_gic_init(void) { gicv3_distif_init(); gicv3_rdistif_init(plat_my_core_pos()); gicv3_cpuif_enable(plat_my_core_pos()); } void k3_gic_cpuif_enable(void) { gicv3_cpuif_enable(plat_my_core_pos()); } void k3_gic_cpuif_disable(void) { gicv3_cpuif_disable(plat_my_core_pos()); } void k3_gic_pcpu_init(void) { gicv3_rdistif_init(plat_my_core_pos()); } trusted-firmware-a-2.2/plat/ti/k3/common/k3_helpers.S000066400000000000000000000113411355360272700224550ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #define K3_BOOT_REASON_COLD_RESET 0x1 /* ------------------------------------------------------------------ * uintptr_t plat_get_my_entrypoint(void) * ------------------------------------------------------------------ * * This function is called with the called with the MMU and caches * disabled (SCTLR_EL3.M = 0 and SCTLR_EL3.C = 0). The function is * responsible for distinguishing between a warm and cold reset for the * current CPU using platform-specific means. If it's a warm reset, * then it returns the warm reset entrypoint point provided to * plat_setup_psci_ops() during BL31 initialization. If it's a cold * reset then this function must return zero. * * This function does not follow the Procedure Call Standard used by * the Application Binary Interface for the ARM 64-bit architecture. * The caller should not assume that callee saved registers are * preserved across a call to this function. */ .globl plat_get_my_entrypoint func plat_get_my_entrypoint ldr x0, k3_boot_reason_data_store cmp x0, #K3_BOOT_REASON_COLD_RESET /* We ONLY support cold boot at this point */ bne plat_unsupported_boot mov x0, #0 ret /* * We self manage our boot reason. * At load time, we have just a default reason - which is cold reset */ k3_boot_reason_data_store: .word K3_BOOT_REASON_COLD_RESET plat_unsupported_boot: b plat_unsupported_boot endfunc plat_get_my_entrypoint /* ------------------------------------------------------------------ * unsigned int plat_my_core_pos(void) * ------------------------------------------------------------------ * * This function returns the index of the calling CPU which is used as a * CPU-specific linear index into blocks of memory (for example while * allocating per-CPU stacks). This function will be invoked very early * in the initialization sequence which mandates that this function * should be implemented in assembly and should not rely on the * avalability of a C runtime environment. This function can clobber x0 * - x8 and must preserve x9 - x29. * * This function plays a crucial role in the power domain topology * framework in PSCI and details of this can be found in Power Domain * Topology Design. */ .globl plat_my_core_pos func plat_my_core_pos mrs x0, MPIDR_EL1 and x1, x0, #MPIDR_CLUSTER_MASK lsr x1, x1, #MPIDR_AFF1_SHIFT and x0, x0, #MPIDR_CPU_MASK cmp x1, 0 b.eq out add x0, x0, #K3_CLUSTER0_CORE_COUNT cmp x1, 1 b.eq out add x0, x0, #K3_CLUSTER1_CORE_COUNT cmp x1, 2 b.eq out add x0, x0, #K3_CLUSTER2_CORE_COUNT out: ret endfunc plat_my_core_pos /* -------------------------------------------------------------------- * This handler does the following: * - Set the L2 Data RAM latency to 2 (i.e. 3 cycles) for Cortex-A72 * -------------------------------------------------------------------- */ .globl plat_reset_handler func plat_reset_handler /* Only on Cortex-A72 */ jump_if_cpu_midr CORTEX_A72_MIDR, a72 ret /* Cortex-A72 specific settings */ a72: mrs x0, CORTEX_A72_L2CTLR_EL1 orr x0, x0, #(CORTEX_A72_L2_DATA_RAM_LATENCY_3_CYCLES << CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT) msr CORTEX_A72_L2CTLR_EL1, x0 isb ret endfunc plat_reset_handler /* --------------------------------------------- * int plat_crash_console_init(void) * Function to initialize the crash console * without a C Runtime to print crash report. * Clobber list : x0 - x4 * --------------------------------------------- */ .globl plat_crash_console_init func plat_crash_console_init mov_imm x0, CRASH_CONSOLE_BASE mov_imm x1, CRASH_CONSOLE_CLK mov_imm x2, CRASH_CONSOLE_BAUD_RATE mov w3, #0x0 b console_16550_core_init endfunc plat_crash_console_init /* --------------------------------------------- * int plat_crash_console_putc(void) * Function to print a character on the crash * console without a C Runtime. * Clobber list : x1, x2 * --------------------------------------------- */ .globl plat_crash_console_putc func plat_crash_console_putc mov_imm x1, CRASH_CONSOLE_BASE b console_16550_core_putc endfunc plat_crash_console_putc /* --------------------------------------------- * int plat_crash_console_flush() * Function to force a write of all buffered * data that hasn't been output. * Out : return -1 on error else return 0. * Clobber list : x0, x1 * --------------------------------------------- */ .globl plat_crash_console_flush func plat_crash_console_flush mov_imm x0, CRASH_CONSOLE_BASE b console_16550_core_flush endfunc plat_crash_console_flush trusted-firmware-a-2.2/plat/ti/k3/common/k3_psci.c000066400000000000000000000070271355360272700217770ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include uintptr_t k3_sec_entrypoint; static void k3_cpu_standby(plat_local_state_t cpu_state) { unsigned int scr; scr = read_scr_el3(); /* Enable the Non secure interrupt to wake the CPU */ write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT); isb(); /* dsb is good practice before using wfi to enter low power states */ dsb(); /* Enter standby state */ wfi(); /* Restore SCR */ write_scr_el3(scr); } static int k3_pwr_domain_on(u_register_t mpidr) { int core_id, proc, device, ret; core_id = plat_core_pos_by_mpidr(mpidr); if (core_id < 0) { ERROR("Could not get target core id: %d\n", core_id); return PSCI_E_INTERN_FAIL; } proc = PLAT_PROC_START_ID + core_id; device = PLAT_PROC_DEVICE_START_ID + core_id; ret = ti_sci_proc_request(proc); if (ret) { ERROR("Request for processor failed: %d\n", ret); return PSCI_E_INTERN_FAIL; } ret = ti_sci_proc_set_boot_cfg(proc, k3_sec_entrypoint, 0, 0); if (ret) { ERROR("Request to set core boot address failed: %d\n", ret); return PSCI_E_INTERN_FAIL; } ret = ti_sci_device_get(device); if (ret) { ERROR("Request to start core failed: %d\n", ret); return PSCI_E_INTERN_FAIL; } return PSCI_E_SUCCESS; } void k3_pwr_domain_off(const psci_power_state_t *target_state) { int core_id, proc, device, ret; /* Prevent interrupts from spuriously waking up this cpu */ k3_gic_cpuif_disable(); core_id = plat_my_core_pos(); proc = PLAT_PROC_START_ID + core_id; device = PLAT_PROC_DEVICE_START_ID + core_id; /* Start by sending wait for WFI command */ ret = ti_sci_proc_wait_boot_status_no_wait(proc, /* * Wait maximum time to give us the best chance to get * to WFI before this command timeouts */ UINT8_MAX, 100, UINT8_MAX, UINT8_MAX, /* Wait for WFI */ PROC_BOOT_STATUS_FLAG_ARMV8_WFI, 0, 0, 0); if (ret) { ERROR("Sending wait for WFI failed (%d)\n", ret); return; } /* Now queue up the core shutdown request */ ret = ti_sci_device_put_no_wait(device); if (ret) { ERROR("Sending core shutdown message failed (%d)\n", ret); return; } } void k3_pwr_domain_on_finish(const psci_power_state_t *target_state) { /* TODO: Indicate to System firmware about completion */ k3_gic_pcpu_init(); k3_gic_cpuif_enable(); } static void __dead2 k3_system_reset(void) { /* Send the system reset request to system firmware */ ti_sci_core_reboot(); while (true) wfi(); } static int k3_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { /* TODO: perform the proper validation */ return PSCI_E_SUCCESS; } static int k3_validate_ns_entrypoint(uintptr_t entrypoint) { /* TODO: perform the proper validation */ return PSCI_E_SUCCESS; } static const plat_psci_ops_t k3_plat_psci_ops = { .cpu_standby = k3_cpu_standby, .pwr_domain_on = k3_pwr_domain_on, .pwr_domain_off = k3_pwr_domain_off, .pwr_domain_on_finish = k3_pwr_domain_on_finish, .system_reset = k3_system_reset, .validate_power_state = k3_validate_power_state, .validate_ns_entrypoint = k3_validate_ns_entrypoint }; int plat_setup_psci_ops(uintptr_t sec_entrypoint, const plat_psci_ops_t **psci_ops) { k3_sec_entrypoint = sec_entrypoint; *psci_ops = &k3_plat_psci_ops; return 0; } trusted-firmware-a-2.2/plat/ti/k3/common/k3_topology.c000066400000000000000000000017061355360272700227130ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include /* The power domain tree descriptor */ static unsigned char power_domain_tree_desc[] = { PLATFORM_SYSTEM_COUNT, PLATFORM_CLUSTER_COUNT, K3_CLUSTER0_CORE_COUNT, K3_CLUSTER1_CORE_COUNT, K3_CLUSTER2_CORE_COUNT, K3_CLUSTER3_CORE_COUNT, }; const unsigned char *plat_get_power_domain_tree_desc(void) { return power_domain_tree_desc; } int plat_core_pos_by_mpidr(u_register_t mpidr) { unsigned int cluster = MPIDR_AFFLVL1_VAL(mpidr); unsigned int core = MPIDR_AFFLVL0_VAL(mpidr); if (MPIDR_AFFLVL3_VAL(mpidr) > 0 || MPIDR_AFFLVL2_VAL(mpidr) > 0) { return -1; } if (cluster > 0) core += K3_CLUSTER0_CORE_COUNT; if (cluster > 1) core += K3_CLUSTER1_CORE_COUNT; if (cluster > 2) core += K3_CLUSTER2_CORE_COUNT; if (cluster > 3) return -1; return core; } trusted-firmware-a-2.2/plat/ti/k3/common/plat_common.mk000066400000000000000000000041521355360272700231350ustar00rootroot00000000000000# # Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # # We don't use BL1 or BL2, so BL31 is the first image to execute RESET_TO_BL31 := 1 # Only one core starts up at first COLD_BOOT_SINGLE_CPU := 1 # We can choose where a core starts executing PROGRAMMABLE_RESET_ADDRESS:= 1 # System coherency is managed in hardware WARMBOOT_ENABLE_DCACHE_EARLY := 1 USE_COHERENT_MEM := 1 # A53 erratum for SoC. (enable them all) ERRATA_A53_826319 := 1 ERRATA_A53_835769 := 1 ERRATA_A53_836870 := 1 ERRATA_A53_843419 := 1 ERRATA_A53_855873 := 1 # A72 Erratum for SoC ERRATA_A72_859971 := 1 CRASH_REPORTING := 1 HANDLE_EA_EL3_FIRST := 1 # Split out RO data into a non-executable section SEPARATE_CODE_AND_RODATA := 1 TI_16550_MDR_QUIRK := 1 $(eval $(call add_define,TI_16550_MDR_QUIRK)) # Allow customizing the UART baud rate K3_USART_BAUD := 115200 $(eval $(call add_define,K3_USART_BAUD)) # Libraries include lib/xlat_tables_v2/xlat_tables.mk PLAT_INCLUDES += \ -I${PLAT_PATH}/include \ -I${PLAT_PATH}/common/drivers/sec_proxy \ -I${PLAT_PATH}/common/drivers/ti_sci \ K3_CONSOLE_SOURCES += \ drivers/ti/uart/aarch64/16550_console.S \ ${PLAT_PATH}/common/k3_console.c \ K3_GIC_SOURCES += \ drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v3/gicv3_main.c \ drivers/arm/gic/v3/gicv3_helpers.c \ plat/common/plat_gicv3.c \ ${PLAT_PATH}/common/k3_gicv3.c \ K3_PSCI_SOURCES += \ plat/common/plat_psci_common.c \ ${PLAT_PATH}/common/k3_psci.c \ K3_SEC_PROXY_SOURCES += \ ${PLAT_PATH}/common/drivers/sec_proxy/sec_proxy.c \ K3_TI_SCI_SOURCES += \ ${PLAT_PATH}/common/drivers/ti_sci/ti_sci.c \ PLAT_BL_COMMON_SOURCES += \ lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a72.S \ ${XLAT_TABLES_LIB_SRCS} \ ${K3_CONSOLE_SOURCES} \ BL31_SOURCES += \ ${PLAT_PATH}/common/k3_bl31_setup.c \ ${PLAT_PATH}/common/k3_helpers.S \ ${PLAT_PATH}/common/k3_topology.c \ ${K3_GIC_SOURCES} \ ${K3_PSCI_SOURCES} \ ${K3_SEC_PROXY_SOURCES} \ ${K3_TI_SCI_SOURCES} \ trusted-firmware-a-2.2/plat/ti/k3/include/000077500000000000000000000000001355360272700204255ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/ti/k3/include/k3_console.h000066400000000000000000000003501355360272700226330ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef K3_CONSOLE_H #define K3_CONSOLE_H void bl31_console_setup(void); #endif /* K3_CONSOLE_H */ trusted-firmware-a-2.2/plat/ti/k3/include/k3_gicv3.h000066400000000000000000000005731355360272700222130ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef K3_GICV3_H #define K3_GICV3_H #include void k3_gic_driver_init(uintptr_t gic_base); void k3_gic_init(void); void k3_gic_cpuif_enable(void); void k3_gic_cpuif_disable(void); void k3_gic_pcpu_init(void); #endif /* K3_GICV3_H */ trusted-firmware-a-2.2/plat/ti/k3/include/plat_macros.S000066400000000000000000000007711355360272700230620ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S /* --------------------------------------------- * The below required platform porting macro * prints out relevant platform registers * whenever an unhandled exception is taken in * BL31. * --------------------------------------------- */ .macro plat_crash_print_regs /* STUB */ .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/ti/k3/include/platform_def.h000066400000000000000000000123451355360272700232450ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include /******************************************************************************* * Generic platform constants ******************************************************************************/ /* Size of cacheable stack */ #if IMAGE_BL31 #define PLATFORM_STACK_SIZE 0x800 #else #define PLATFORM_STACK_SIZE 0x1000 #endif #define PLATFORM_SYSTEM_COUNT 1 #define PLATFORM_CORE_COUNT (K3_CLUSTER0_CORE_COUNT + \ K3_CLUSTER1_CORE_COUNT + \ K3_CLUSTER2_CORE_COUNT + \ K3_CLUSTER3_CORE_COUNT) #define PLATFORM_CLUSTER_COUNT ((K3_CLUSTER0_CORE_COUNT != 0) + \ (K3_CLUSTER1_CORE_COUNT != 0) + \ (K3_CLUSTER2_CORE_COUNT != 0) + \ (K3_CLUSTER3_CORE_COUNT != 0)) #define PLAT_NUM_PWR_DOMAINS (PLATFORM_SYSTEM_COUNT + \ PLATFORM_CLUSTER_COUNT + \ PLATFORM_CORE_COUNT) #define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2 /******************************************************************************* * Memory layout constants ******************************************************************************/ /* * ARM-TF lives in SRAM, partition it here * * BL3-1 specific defines. * * Put BL3-1 at the base of the Trusted SRAM. */ #define BL31_BASE SEC_SRAM_BASE #define BL31_SIZE SEC_SRAM_SIZE #define BL31_LIMIT (BL31_BASE + BL31_SIZE) /* * Defines the maximum number of translation tables that are allocated by the * translation table library code. To minimize the amount of runtime memory * used, choose the smallest value needed to map the required virtual addresses * for each BL stage. */ #define MAX_XLAT_TABLES 8 /* * Defines the maximum number of regions that are allocated by the translation * table library code. A region consists of physical base address, virtual base * address, size and attributes (Device/Memory, RO/RW, Secure/Non-Secure), as * defined in the `mmap_region_t` structure. The platform defines the regions * that should be mapped. Then, the translation table library will create the * corresponding tables and descriptors at runtime. To minimize the amount of * runtime memory used, choose the smallest value needed to register the * required regions for each BL stage. */ #define MAX_MMAP_REGIONS 11 /* * Defines the total size of the address space in bytes. For example, for a 32 * bit address space, this value should be `(1ull << 32)`. */ #define PLAT_PHY_ADDR_SPACE_SIZE (1ull << 32) #define PLAT_VIRT_ADDR_SPACE_SIZE (1ull << 32) /* * Some data must be aligned on the biggest cache line size in the platform. * This is known only to the platform as it might have a combination of * integrated and external caches. */ #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) /* Platform default console definitions */ #ifndef K3_USART_BASE #define K3_USART_BASE 0x02800000 #endif /* USART has a default size for address space */ #define K3_USART_SIZE 0x1000 #ifndef K3_USART_CLK_SPEED #define K3_USART_CLK_SPEED 48000000 #endif /* Crash console defaults */ #define CRASH_CONSOLE_BASE K3_USART_BASE #define CRASH_CONSOLE_CLK K3_USART_CLK_SPEED #define CRASH_CONSOLE_BAUD_RATE K3_USART_BAUD /* Timer frequency */ #ifndef SYS_COUNTER_FREQ_IN_TICKS #define SYS_COUNTER_FREQ_IN_TICKS 200000000 #endif /* Interrupt numbers */ #define ARM_IRQ_SEC_PHY_TIMER 29 #define ARM_IRQ_SEC_SGI_0 8 #define ARM_IRQ_SEC_SGI_1 9 #define ARM_IRQ_SEC_SGI_2 10 #define ARM_IRQ_SEC_SGI_3 11 #define ARM_IRQ_SEC_SGI_4 12 #define ARM_IRQ_SEC_SGI_5 13 #define ARM_IRQ_SEC_SGI_6 14 #define ARM_IRQ_SEC_SGI_7 15 /* * Define properties of Group 1 Secure and Group 0 interrupts as per GICv3 * terminology. On a GICv2 system or mode, the lists will be merged and treated * as Group 0 interrupts. */ #define PLAT_ARM_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE) #define PLAT_ARM_G0_IRQ_PROPS(grp) \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE) #define K3_GIC_BASE 0x01800000 #define K3_GIC_SIZE 0x200000 #define SEC_PROXY_DATA_BASE 0x32C00000 #define SEC_PROXY_DATA_SIZE 0x80000 #define SEC_PROXY_SCFG_BASE 0x32800000 #define SEC_PROXY_SCFG_SIZE 0x80000 #define SEC_PROXY_RT_BASE 0x32400000 #define SEC_PROXY_RT_SIZE 0x80000 #define SEC_PROXY_TIMEOUT_US 1000000 #define SEC_PROXY_MAX_MESSAGE_SIZE 56 #define TI_SCI_HOST_ID 10 #define TI_SCI_MAX_MESSAGE_SIZE 52 #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/ti/k3/platform.mk000066400000000000000000000006171355360272700211630ustar00rootroot00000000000000# # Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # PLAT_PATH := plat/ti/k3 TARGET_BOARD ?= generic include ${PLAT_PATH}/common/plat_common.mk include ${PLAT_PATH}/board/${TARGET_BOARD}/board.mk # modify BUILD_PLAT to point to board specific build directory BUILD_PLAT := ${BUILD_BASE}/${PLAT}/${TARGET_BOARD}/${BUILD_TYPE} trusted-firmware-a-2.2/plat/xilinx/000077500000000000000000000000001355360272700173645ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/xilinx/common/000077500000000000000000000000001355360272700206545ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/xilinx/common/include/000077500000000000000000000000001355360272700222775ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/xilinx/common/include/ipi.h000066400000000000000000000046441355360272700232410ustar00rootroot00000000000000/* * Copyright (c) 2018, Xilinx, Inc. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* Xilinx IPI management configuration data and macros */ #ifndef IPI_H #define IPI_H #include /********************************************************************* * IPI mailbox status macros ********************************************************************/ #define IPI_MB_STATUS_IDLE 0 #define IPI_MB_STATUS_SEND_PENDING 1 #define IPI_MB_STATUS_RECV_PENDING 2 /********************************************************************* * IPI mailbox call is secure or not macros ********************************************************************/ #define IPI_MB_CALL_NOTSECURE 0 #define IPI_MB_CALL_SECURE 1 /********************************************************************* * IPI secure check ********************************************************************/ #define IPI_SECURE_MASK 0x1U #define IPI_IS_SECURE(I) ((ipi_table[(I)].secure_only & \ IPI_SECURE_MASK) ? 1 : 0) /********************************************************************* * Struct definitions ********************************************************************/ /* structure to maintain IPI configuration information */ struct ipi_config { unsigned int ipi_bit_mask; unsigned int ipi_reg_base; unsigned char secure_only; }; /********************************************************************* * IPI APIs declarations ********************************************************************/ /* Initialize IPI configuration table */ void ipi_config_table_init(const struct ipi_config *ipi_table, uint32_t total_ipi); /* Validate IPI mailbox access */ int ipi_mb_validate(uint32_t local, uint32_t remote, unsigned int is_secure); /* Open the IPI mailbox */ void ipi_mb_open(uint32_t local, uint32_t remote); /* Release the IPI mailbox */ void ipi_mb_release(uint32_t local, uint32_t remote); /* Enquire IPI mailbox status */ int ipi_mb_enquire_status(uint32_t local, uint32_t remote); /* Trigger notification on the IPI mailbox */ void ipi_mb_notify(uint32_t local, uint32_t remote, uint32_t is_blocking); /* Ack IPI mailbox notification */ void ipi_mb_ack(uint32_t local, uint32_t remote); /* Disable IPI mailbox notification interrupt */ void ipi_mb_disable_irq(uint32_t local, uint32_t remote); /* Enable IPI mailbox notification interrupt */ void ipi_mb_enable_irq(uint32_t local, uint32_t remote); #endif /* IPI_H */ trusted-firmware-a-2.2/plat/xilinx/common/include/pm_common.h000066400000000000000000000021371355360272700244370ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * Contains definitions of commonly used macros and data types needed * for PU Power Management. This file should be common for all PU's. */ #ifndef PM_COMMON_H #define PM_COMMON_H #include #include /** * pm_ipi - struct for capturing IPI-channel specific info * @local_ipi_id Local IPI agent ID * @remote_ipi_id Remote IPI Agent ID * @buffer_base base address for payload buffer */ struct pm_ipi { const uint32_t local_ipi_id; const uint32_t remote_ipi_id; const uintptr_t buffer_base; }; /** * pm_proc - struct for capturing processor related info * @node_id node-ID of the processor * @pwrdn_mask cpu-specific mask to be used for power control register * @ipi pointer to IPI channel structure * (in APU all processors share one IPI channel) */ struct pm_proc { const uint32_t node_id; const unsigned int pwrdn_mask; const struct pm_ipi *ipi; }; const struct pm_proc *pm_get_proc(unsigned int cpuid); #endif /* PM_COMMON_H */ trusted-firmware-a-2.2/plat/xilinx/common/include/pm_ipi.h000066400000000000000000000016411355360272700237270ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PM_IPI_H #define PM_IPI_H #include #include "pm_common.h" #define IPI_BLOCKING 1 #define IPI_NON_BLOCKING 0 int pm_ipi_init(const struct pm_proc *proc); enum pm_ret_status pm_ipi_send(const struct pm_proc *proc, uint32_t payload[PAYLOAD_ARG_CNT]); enum pm_ret_status pm_ipi_send_non_blocking(const struct pm_proc *proc, uint32_t payload[PAYLOAD_ARG_CNT]); enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc, uint32_t payload[PAYLOAD_ARG_CNT], unsigned int *value, size_t count); void pm_ipi_buff_read_callb(unsigned int *value, size_t count); void pm_ipi_irq_enable(const struct pm_proc *proc); void pm_ipi_irq_clear(const struct pm_proc *proc); uint32_t pm_ipi_irq_status(const struct pm_proc *proc); #endif /* PM_IPI_H */ trusted-firmware-a-2.2/plat/xilinx/common/ipi.c000066400000000000000000000116421355360272700216050ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * Xilinx IPI agent registers access management */ #include #include #include #include #include #include #include #include #include /********************************************************************* * Macros definitions ********************************************************************/ /* IPI registers offsets macros */ #define IPI_TRIG_OFFSET 0x00U #define IPI_OBR_OFFSET 0x04U #define IPI_ISR_OFFSET 0x10U #define IPI_IMR_OFFSET 0x14U #define IPI_IER_OFFSET 0x18U #define IPI_IDR_OFFSET 0x1CU /* IPI register start offset */ #define IPI_REG_BASE(I) (ipi_table[(I)].ipi_reg_base) /* IPI register bit mask */ #define IPI_BIT_MASK(I) (ipi_table[(I)].ipi_bit_mask) /* IPI configuration table */ const static struct ipi_config *ipi_table; /* Total number of IPI */ static uint32_t ipi_total; /** * ipi_config_init() - Initialize IPI configuration data * * @ipi_config_table - IPI configuration table * @ipi_total - Total number of IPI available * */ void ipi_config_table_init(const struct ipi_config *ipi_config_table, uint32_t total_ipi) { ipi_table = ipi_config_table; ipi_total = total_ipi; } /* is_ipi_mb_within_range() - verify if IPI mailbox is within range * * @local - local IPI ID * @remote - remote IPI ID * * return - 1 if within range, 0 if not */ static inline int is_ipi_mb_within_range(uint32_t local, uint32_t remote) { int ret = 1; if (remote >= ipi_total || local >= ipi_total) ret = 0; return ret; } /** * ipi_mb_validate() - validate IPI mailbox access * * @local - local IPI ID * @remote - remote IPI ID * @is_secure - indicate if the requester is from secure software * * return - 0 success, negative value for errors */ int ipi_mb_validate(uint32_t local, uint32_t remote, unsigned int is_secure) { int ret = 0; if (!is_ipi_mb_within_range(local, remote)) ret = -EINVAL; else if (IPI_IS_SECURE(local) && !is_secure) ret = -EPERM; else if (IPI_IS_SECURE(remote) && !is_secure) ret = -EPERM; return ret; } /** * ipi_mb_open() - Open IPI mailbox. * * @local - local IPI ID * @remote - remote IPI ID * */ void ipi_mb_open(uint32_t local, uint32_t remote) { mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET, IPI_BIT_MASK(remote)); mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET, IPI_BIT_MASK(remote)); } /** * ipi_mb_release() - Open IPI mailbox. * * @local - local IPI ID * @remote - remote IPI ID * */ void ipi_mb_release(uint32_t local, uint32_t remote) { mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET, IPI_BIT_MASK(remote)); } /** * ipi_mb_enquire_status() - Enquire IPI mailbox status * * @local - local IPI ID * @remote - remote IPI ID * * return - 0 idle, positive value for pending sending or receiving, * negative value for errors */ int ipi_mb_enquire_status(uint32_t local, uint32_t remote) { int ret = 0; uint32_t status; status = mmio_read_32(IPI_REG_BASE(local) + IPI_OBR_OFFSET); if (status & IPI_BIT_MASK(remote)) ret |= IPI_MB_STATUS_SEND_PENDING; status = mmio_read_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET); if (status & IPI_BIT_MASK(remote)) ret |= IPI_MB_STATUS_RECV_PENDING; return ret; } /* ipi_mb_notify() - Trigger IPI mailbox notification * * @local - local IPI ID * @remote - remote IPI ID * @is_blocking - if to trigger the notification in blocking mode or not. * * It sets the remote bit in the IPI agent trigger register. * */ void ipi_mb_notify(uint32_t local, uint32_t remote, uint32_t is_blocking) { uint32_t status; mmio_write_32(IPI_REG_BASE(local) + IPI_TRIG_OFFSET, IPI_BIT_MASK(remote)); if (is_blocking) { do { status = mmio_read_32(IPI_REG_BASE(local) + IPI_OBR_OFFSET); } while (status & IPI_BIT_MASK(remote)); } } /* ipi_mb_ack() - Ack IPI mailbox notification from the other end * * @local - local IPI ID * @remote - remote IPI ID * * It will clear the remote bit in the isr register. * */ void ipi_mb_ack(uint32_t local, uint32_t remote) { mmio_write_32(IPI_REG_BASE(local) + IPI_ISR_OFFSET, IPI_BIT_MASK(remote)); } /* ipi_mb_disable_irq() - Disable IPI mailbox notification interrupt * * @local - local IPI ID * @remote - remote IPI ID * * It will mask the remote bit in the idr register. * */ void ipi_mb_disable_irq(uint32_t local, uint32_t remote) { mmio_write_32(IPI_REG_BASE(local) + IPI_IDR_OFFSET, IPI_BIT_MASK(remote)); } /* ipi_mb_enable_irq() - Enable IPI mailbox notification interrupt * * @local - local IPI ID * @remote - remote IPI ID * * It will mask the remote bit in the idr register. * */ void ipi_mb_enable_irq(uint32_t local, uint32_t remote) { mmio_write_32(IPI_REG_BASE(local) + IPI_IER_OFFSET, IPI_BIT_MASK(remote)); } trusted-firmware-a-2.2/plat/xilinx/common/pm_service/000077500000000000000000000000001355360272700230105ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/xilinx/common/pm_service/pm_ipi.c000066400000000000000000000136211355360272700244340ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "pm_ipi.h" DEFINE_BAKERY_LOCK(pm_secure_lock); /** * pm_ipi_init() - Initialize IPI peripheral for communication with * remote processor * * @proc Pointer to the processor who is initiating request * @return On success, the initialization function must return 0. * Any other return value will cause the framework to ignore * the service * * Called from pm_setup initialization function */ int pm_ipi_init(const struct pm_proc *proc) { bakery_lock_init(&pm_secure_lock); ipi_mb_open(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id); return 0; } /** * pm_ipi_send_common() - Sends IPI request to the remote processor * @proc Pointer to the processor who is initiating request * @payload API id and call arguments to be written in IPI buffer * * Send an IPI request to the power controller. Caller needs to hold * the 'pm_secure_lock' lock. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ipi_send_common(const struct pm_proc *proc, uint32_t payload[PAYLOAD_ARG_CNT], uint32_t is_blocking) { unsigned int offset = 0; uintptr_t buffer_base = proc->ipi->buffer_base + IPI_BUFFER_TARGET_REMOTE_OFFSET + IPI_BUFFER_REQ_OFFSET; /* Write payload into IPI buffer */ for (size_t i = 0; i < PAYLOAD_ARG_CNT; i++) { mmio_write_32(buffer_base + offset, payload[i]); offset += PAYLOAD_ARG_SIZE; } /* Generate IPI to remote processor */ ipi_mb_notify(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id, is_blocking); return PM_RET_SUCCESS; } /** * pm_ipi_send_non_blocking() - Sends IPI request to the remote processor * without blocking notification * @proc Pointer to the processor who is initiating request * @payload API id and call arguments to be written in IPI buffer * * Send an IPI request to the power controller. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_ipi_send_non_blocking(const struct pm_proc *proc, uint32_t payload[PAYLOAD_ARG_CNT]) { enum pm_ret_status ret; bakery_lock_get(&pm_secure_lock); ret = pm_ipi_send_common(proc, payload, IPI_NON_BLOCKING); bakery_lock_release(&pm_secure_lock); return ret; } /** * pm_ipi_send() - Sends IPI request to the remote processor * @proc Pointer to the processor who is initiating request * @payload API id and call arguments to be written in IPI buffer * * Send an IPI request to the power controller. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_ipi_send(const struct pm_proc *proc, uint32_t payload[PAYLOAD_ARG_CNT]) { enum pm_ret_status ret; bakery_lock_get(&pm_secure_lock); ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING); bakery_lock_release(&pm_secure_lock); return ret; } /** * pm_ipi_buff_read() - Reads IPI response after remote processor has handled * interrupt * @proc Pointer to the processor who is waiting and reading response * @value Used to return value from IPI buffer element (optional) * @count Number of values to return in @value * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ipi_buff_read(const struct pm_proc *proc, unsigned int *value, size_t count) { size_t i; uintptr_t buffer_base = proc->ipi->buffer_base + IPI_BUFFER_TARGET_REMOTE_OFFSET + IPI_BUFFER_RESP_OFFSET; /* * Read response from IPI buffer * buf-0: success or error+reason * buf-1: value * buf-2: unused * buf-3: unused */ for (i = 1; i <= count; i++) { *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE)); value++; } return mmio_read_32(buffer_base); } /** * pm_ipi_buff_read_callb() - Reads IPI response after remote processor has * handled interrupt * @value Used to return value from IPI buffer element (optional) * @count Number of values to return in @value * * @return Returns status, either success or error+reason */ void pm_ipi_buff_read_callb(unsigned int *value, size_t count) { size_t i; uintptr_t buffer_base = IPI_BUFFER_REMOTE_BASE + IPI_BUFFER_TARGET_LOCAL_OFFSET + IPI_BUFFER_REQ_OFFSET; if (count > IPI_BUFFER_MAX_WORDS) count = IPI_BUFFER_MAX_WORDS; for (i = 0; i <= count; i++) { *value = mmio_read_32(buffer_base + (i * PAYLOAD_ARG_SIZE)); value++; } } /** * pm_ipi_send_sync() - Sends IPI request to the remote processor * @proc Pointer to the processor who is initiating request * @payload API id and call arguments to be written in IPI buffer * @value Used to return value from IPI buffer element (optional) * @count Number of values to return in @value * * Send an IPI request to the power controller and wait for it to be handled. * * @return Returns status, either success or error+reason and, optionally, * @value */ enum pm_ret_status pm_ipi_send_sync(const struct pm_proc *proc, uint32_t payload[PAYLOAD_ARG_CNT], unsigned int *value, size_t count) { enum pm_ret_status ret; bakery_lock_get(&pm_secure_lock); ret = pm_ipi_send_common(proc, payload, IPI_BLOCKING); if (ret != PM_RET_SUCCESS) goto unlock; ret = pm_ipi_buff_read(proc, value, count); unlock: bakery_lock_release(&pm_secure_lock); return ret; } void pm_ipi_irq_enable(const struct pm_proc *proc) { ipi_mb_enable_irq(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id); } void pm_ipi_irq_clear(const struct pm_proc *proc) { ipi_mb_ack(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id); } uint32_t pm_ipi_irq_status(const struct pm_proc *proc) { int ret; ret = ipi_mb_enquire_status(proc->ipi->local_ipi_id, proc->ipi->remote_ipi_id); if (ret & IPI_MB_STATUS_RECV_PENDING) return 1; else return 0; } trusted-firmware-a-2.2/plat/xilinx/versal/000077500000000000000000000000001355360272700206605ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/xilinx/versal/aarch64/000077500000000000000000000000001355360272700221105ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/xilinx/versal/aarch64/versal_common.c000066400000000000000000000037421355360272700251260ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "../versal_def.h" #include "../versal_private.h" /* * Table of regions to map using the MMU. * This doesn't include TZRAM as the 'mem_layout' argument passed to * configure_mmu_elx() will give the available subset of that, */ const mmap_region_t plat_versal_mmap[] = { MAP_REGION_FLAT(DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE), MAP_REGION_FLAT(CRF_BASE, CRF_SIZE, MT_DEVICE | MT_RW | MT_SECURE), { 0 } }; const mmap_region_t *plat_versal_get_mmap(void) { return plat_versal_mmap; } static void versal_print_platform_name(void) { NOTICE("ATF running on Xilinx %s\n", PLATFORM_NAME); } void versal_config_setup(void) { uint32_t val; versal_print_platform_name(); mmio_write_32(VERSAL_CRL_IOU_SWITCH_CTRL, VERSAL_IOU_SWITCH_CTRL_CLKACT_BIT | (0x20 << VERSAL_IOU_SWITCH_CTRL_DIVISOR0_SHIFT)); /* Global timer init - Program time stamp reference clk */ val = mmio_read_32(VERSAL_CRL_TIMESTAMP_REF_CTRL); val |= VERSAL_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT; mmio_write_32(VERSAL_CRL_TIMESTAMP_REF_CTRL, val); /* Clear reset of timestamp reg */ mmio_write_32(VERSAL_CRL_RST_TIMESTAMP_OFFSET, 0x0); /* Program freq register in System counter and enable system counter. */ mmio_write_32(VERSAL_IOU_SCNTRS_BASE_FREQ, VERSAL_CPU_CLOCK); mmio_write_32(VERSAL_IOU_SCNTRS_COUNTER_CONTROL_REG, VERSAL_IOU_SCNTRS_CONTROL_EN); generic_delay_timer_init(); } unsigned int plat_get_syscnt_freq2(void) { return VERSAL_CPU_CLOCK; } uintptr_t plat_get_ns_image_entrypoint(void) { #ifdef PRELOADED_BL33_BASE return PRELOADED_BL33_BASE; #else return PLAT_VERSAL_NS_IMAGE_OFFSET; #endif } trusted-firmware-a-2.2/plat/xilinx/versal/aarch64/versal_helpers.S000066400000000000000000000040211355360272700252470ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include .globl plat_secondary_cold_boot_setup .globl plat_is_my_cpu_primary .globl versal_calc_core_pos .globl platform_mem_init .globl plat_my_core_pos /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions * needed for a secondary cpu after a cold reset e.g * mark the cpu's presence, mechanism to place it in a * holding pen etc. * TODO: Should we read the PSYS register to make sure * that the request has gone through. * ----------------------------------------------------- */ func plat_secondary_cold_boot_setup mrs x0, mpidr_el1 /* * There is no sane reason to come out of this wfi. This * cpu will be powered on and reset by the cpu_on pm api */ dsb sy bl plat_panic_handler endfunc plat_secondary_cold_boot_setup func plat_is_my_cpu_primary mov x9, x30 bl plat_my_core_pos cmp x0, #VERSAL_PRIMARY_CPU cset x0, eq ret x9 endfunc plat_is_my_cpu_primary /* ----------------------------------------------------- * unsigned int plat_my_core_pos(void) * This function uses the versal_calc_core_pos() * definition to get the index of the calling CPU. * ----------------------------------------------------- */ func plat_my_core_pos mrs x0, mpidr_el1 b versal_calc_core_pos endfunc plat_my_core_pos func versal_calc_core_pos and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 ret endfunc versal_calc_core_pos /* --------------------------------------------------------------------- * We don't need to carry out any memory initialization on VERSAL * platform. The Secure RAM is accessible straight away. * --------------------------------------------------------------------- */ func platform_mem_init ret endfunc platform_mem_init trusted-firmware-a-2.2/plat/xilinx/versal/bl31_versal_setup.c000066400000000000000000000072001355360272700243600ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "versal_private.h" static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; static console_pl011_t versal_runtime_console; /* * Return a pointer to the 'entry_point_info' structure of the next image for * the security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. */ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { assert(sec_state_is_valid(type)); if (type == NON_SECURE) return &bl33_image_ep_info; return &bl32_image_ep_info; } /* * Perform any BL31 specific platform actions. Here is an opportunity to copy * parameters passed by the calling EL (S-EL1 in BL2 & S-EL3 in BL1) before they * are lost (potentially). This needs to be done before the MMU is initialized * so that the memory layout can be used while creating page tables. */ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { /* Initialize the console to provide early debug support */ int rc = console_pl011_register(VERSAL_UART_BASE, VERSAL_UART_CLOCK, VERSAL_UART_BAUDRATE, &versal_runtime_console); if (rc == 0) panic(); console_set_scope(&versal_runtime_console.console, CONSOLE_FLAG_BOOT | CONSOLE_FLAG_RUNTIME); /* Initialize the platform config for future decision making */ versal_config_setup(); /* There are no parameters from BL2 if BL31 is a reset vector */ assert(arg0 == 0U); assert(arg1 == 0U); /* * Do initial security configuration to allow DRAM/device access. On * Base VERSAL only DRAM security is programmable (via TrustZone), but * other platforms might have more programmable security devices * present. */ /* Populate common information for BL32 and BL33 */ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0); SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); /* use build time defaults in JTAG boot mode */ bl32_image_ep_info.pc = BL32_BASE; bl32_image_ep_info.spsr = 0; bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc); NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc); } void bl31_platform_setup(void) { /* Initialize the gic cpu and distributor interfaces */ plat_versal_gic_driver_init(); plat_versal_gic_init(); } void bl31_plat_runtime_setup(void) { } /* * Perform the very early platform specific architectural setup here. */ void bl31_plat_arch_setup(void) { const mmap_region_t bl_regions[] = { MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE, MT_MEMORY | MT_RW | MT_SECURE), MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, MT_CODE | MT_SECURE), MAP_REGION_FLAT(BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE, MT_RO_DATA | MT_SECURE), MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, MT_DEVICE | MT_RW | MT_SECURE), {0} }; setup_page_tables(bl_regions, plat_versal_get_mmap()); enable_mmu_el3(0); } trusted-firmware-a-2.2/plat/xilinx/versal/include/000077500000000000000000000000001355360272700223035ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/xilinx/versal/include/plat_macros.S000066400000000000000000000053761355360272700247460ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S #include #include #include #include "../include/platform_def.h" .section .rodata.gic_reg_name, "aS" /* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */ gicc_regs: .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", "" /* Applicable only to GICv3 with SRE enabled */ icc_regs: .asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", "" /* Registers common to both GICv2 and GICv3 */ gicd_pend_reg: .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n" newline: .asciz "\n" spacer: .asciz ":\t\t0x" /* --------------------------------------------- * The below utility macro prints out relevant GIC * registers whenever an unhandled exception is * taken in BL31 on Versal platform. * Expects: GICD base in x16, GICC base in x17 * Clobbers: x0 - x10, sp * --------------------------------------------- */ .macro versal_print_gic_regs /* Check for GICv3 system register access */ mrs x7, id_aa64pfr0_el1 ubfx x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH cmp x7, #1 b.ne print_gicv2 /* Check for SRE enable */ mrs x8, ICC_SRE_EL3 tst x8, #ICC_SRE_SRE_BIT b.eq print_gicv2 /* Load the icc reg list to x6 */ adr x6, icc_regs /* Load the icc regs to gp regs used by str_in_crash_buf_print */ mrs x8, ICC_HPPIR0_EL1 mrs x9, ICC_HPPIR1_EL1 mrs x10, ICC_CTLR_EL3 /* Store to the crash buf and print to console */ bl str_in_crash_buf_print b print_gic_common print_gicv2: /* Load the gicc reg list to x6 */ adr x6, gicc_regs /* Load the gicc regs to gp regs used by str_in_crash_buf_print */ ldr w8, [x17, #GICC_HPPIR] ldr w9, [x17, #GICC_AHPPIR] ldr w10, [x17, #GICC_CTLR] /* Store to the crash buf and print to console */ bl str_in_crash_buf_print print_gic_common: /* Print the GICD_ISPENDR regs */ add x7, x16, #GICD_ISPENDR adr x4, gicd_pend_reg bl asm_print_str gicd_ispendr_loop: sub x4, x7, x16 cmp x4, #0x280 b.eq exit_print_gic_regs bl asm_print_hex adr x4, spacer bl asm_print_str ldr x4, [x7], #8 bl asm_print_hex adr x4, newline bl asm_print_str b gicd_ispendr_loop exit_print_gic_regs: .endm /* --------------------------------------------- * The below required platform porting macro * prints out relevant GIC and CCI registers * whenever an unhandled exception is taken in * BL31. * Clobbers: x0 - x10, x16, x17, sp * --------------------------------------------- */ .macro plat_crash_print_regs mov_imm x17, PLAT_VERSAL_GICD_BASE mov_imm x16, PLAT_VERSAL_GICR_BASE versal_print_gic_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/xilinx/versal/include/platform_def.h000066400000000000000000000067061355360272700251270ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include "../versal_def.h" /******************************************************************************* * Generic platform constants ******************************************************************************/ /* Size of cacheable stacks */ #define PLATFORM_STACK_SIZE 0x440 #define PLATFORM_CORE_COUNT 2 #define PLAT_MAX_PWR_LVL 1 #define PLAT_MAX_RET_STATE 1 #define PLAT_MAX_OFF_STATE 2 /******************************************************************************* * BL31 specific defines. ******************************************************************************/ /* * Put BL31 at the top of the Trusted SRAM (just below the shared memory, if * present). BL31_BASE is calculated using the current BL31 debug size plus a * little space for growth. */ #ifndef VERSAL_ATF_MEM_BASE # define BL31_BASE 0xfffea000 # define BL31_LIMIT 0xffffffff #else # define BL31_BASE (VERSAL_ATF_MEM_BASE) # define BL31_LIMIT (VERSAL_ATF_MEM_BASE + VERSAL_ATF_MEM_SIZE - 1) # ifdef VERSAL_ATF_MEM_PROGBITS_SIZE # define BL31_PROGBITS_LIMIT (VERSAL_ATF_MEM_BASE + VERSAL_ATF_MEM_PROGBITS_SIZE - 1) # endif #endif /******************************************************************************* * BL32 specific defines. ******************************************************************************/ #ifndef VERSAL_BL32_MEM_BASE # define BL32_BASE 0x60000000 # define BL32_LIMIT 0x7fffffff #else # define BL32_BASE (VERSAL_BL32_MEM_BASE) # define BL32_LIMIT (VERSAL_BL32_MEM_BASE + VERSAL_BL32_MEM_SIZE - 1) #endif /******************************************************************************* * BL33 specific defines. ******************************************************************************/ #ifndef PRELOADED_BL33_BASE # define PLAT_VERSAL_NS_IMAGE_OFFSET 0x8000000 #else # define PLAT_VERSAL_NS_IMAGE_OFFSET PRELOADED_BL33_BASE #endif /******************************************************************************* * TSP specific defines. ******************************************************************************/ #define TSP_SEC_MEM_BASE BL32_BASE #define TSP_SEC_MEM_SIZE (BL32_LIMIT - BL32_BASE + 1) /* ID of the secure physical generic timer interrupt used by the TSP */ #define TSP_IRQ_SEC_PHY_TIMER ARM_IRQ_SEC_PHY_TIMER /******************************************************************************* * 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 MAX_MMAP_REGIONS 7 #define MAX_XLAT_TABLES 5 #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) #define PLAT_VERSAL_GICD_BASE 0xF9000000 #define PLAT_VERSAL_GICR_BASE 0xF9080000 /* * Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 * terminology. On a GICv2 system or mode, the lists will be merged and treated * as Group 0 interrupts. */ #define PLAT_VERSAL_G1S_IRQS VERSAL_IRQ_SEC_PHY_TIMER #define PLAT_VERSAL_G0_IRQS VERSAL_IRQ_SEC_PHY_TIMER #define PLAT_VERSAL_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(VERSAL_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL) #define PLAT_VERSAL_G0_IRQ_PROPS(grp) #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/xilinx/versal/plat_psci.c000066400000000000000000000041171355360272700230050ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "versal_private.h" static uintptr_t versal_sec_entry; static int versal_nopmc_pwr_domain_on(u_register_t mpidr) { uint32_t r; unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); if (cpu_id == -1) return PSCI_E_INTERN_FAIL; /* * program RVBAR */ mmio_write_32(FPD_APU_RVBAR_L_0 + (cpu_id << 3), versal_sec_entry); mmio_write_32(FPD_APU_RVBAR_H_0 + (cpu_id << 3), versal_sec_entry >> 32); /* * clear VINITHI */ r = mmio_read_32(FPD_APU_CONFIG_0); r &= ~(1 << FPD_APU_CONFIG_0_VINITHI_SHIFT << cpu_id); mmio_write_32(FPD_APU_CONFIG_0, r); /* * FIXME: Add power up sequence, By default it works * now without the need of it as it was powered up by * default. */ /* * clear power down request */ r = mmio_read_32(FPD_APU_PWRCTL); r &= ~(1 << cpu_id); mmio_write_32(FPD_APU_PWRCTL, r); /* * release core reset */ r = mmio_read_32(CRF_RST_APU); r &= ~((CRF_RST_APU_ACPU_PWRON_RESET | CRF_RST_APU_ACPU_RESET) << cpu_id); mmio_write_32(CRF_RST_APU, r); return PSCI_E_SUCCESS; } void versal_pwr_domain_on_finish(const psci_power_state_t *target_state) { /* Enable the gic cpu interface */ plat_versal_gic_pcpu_init(); /* Program the gic per-cpu distributor or re-distributor interface */ plat_versal_gic_cpuif_enable(); } static const struct plat_psci_ops versal_nopmc_psci_ops = { .pwr_domain_on = versal_nopmc_pwr_domain_on, .pwr_domain_on_finish = versal_pwr_domain_on_finish, }; /******************************************************************************* * Export the platform specific power ops. ******************************************************************************/ int plat_setup_psci_ops(uintptr_t sec_entrypoint, const struct plat_psci_ops **psci_ops) { versal_sec_entry = sec_entrypoint; *psci_ops = &versal_nopmc_psci_ops; return 0; } trusted-firmware-a-2.2/plat/xilinx/versal/plat_topology.c000066400000000000000000000005231355360272700237200ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include static const unsigned char plat_power_domain_tree_desc[] = {1, PLATFORM_CORE_COUNT}; const unsigned char *plat_get_power_domain_tree_desc(void) { return plat_power_domain_tree_desc; } trusted-firmware-a-2.2/plat/xilinx/versal/plat_versal.c000066400000000000000000000006111355360272700233360ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "versal_private.h" int plat_core_pos_by_mpidr(u_register_t mpidr) { if (mpidr & MPIDR_CLUSTER_MASK) return -1; if ((mpidr & MPIDR_CPU_MASK) >= PLATFORM_CORE_COUNT) return -1; return versal_calc_core_pos(mpidr); } trusted-firmware-a-2.2/plat/xilinx/versal/platform.mk000066400000000000000000000041061355360272700230360ustar00rootroot00000000000000# Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause override PROGRAMMABLE_RESET_ADDRESS := 1 PSCI_EXTENDED_STATE_ID := 1 A53_DISABLE_NON_TEMPORAL_HINT := 0 SEPARATE_CODE_AND_RODATA := 1 override RESET_TO_BL31 := 1 PL011_GENERIC_UART := 1 ifdef VERSAL_ATF_MEM_BASE $(eval $(call add_define,VERSAL_ATF_MEM_BASE)) ifndef VERSAL_ATF_MEM_SIZE $(error "VERSAL_ATF_BASE defined without VERSAL_ATF_SIZE") endif $(eval $(call add_define,VERSAL_ATF_MEM_SIZE)) ifdef VERSAL_ATF_MEM_PROGBITS_SIZE $(eval $(call add_define,VERSAL_ATF_MEM_PROGBITS_SIZE)) endif endif ifdef VERSAL_BL32_MEM_BASE $(eval $(call add_define,VERSAL_BL32_MEM_BASE)) ifndef VERSAL_BL32_MEM_SIZE $(error "VERSAL_BL32_BASE defined without VERSAL_BL32_SIZE") endif $(eval $(call add_define,VERSAL_BL32_MEM_SIZE)) endif VERSAL_PLATFORM ?= versal_virt $(eval $(call add_define_val,VERSAL_PLATFORM,VERSAL_PLATFORM_ID_${VERSAL_PLATFORM})) VERSAL_CONSOLE ?= pl011 $(eval $(call add_define_val,VERSAL_CONSOLE,VERSAL_CONSOLE_ID_${VERSAL_CONSOLE})) PLAT_INCLUDES := -Iplat/xilinx/versal/include/ PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \ lib/xlat_tables/aarch64/xlat_tables.c \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v3/gicv3_main.c \ drivers/arm/gic/v3/gicv3_helpers.c \ drivers/arm/pl011/aarch64/pl011_console.S \ plat/common/aarch64/crash_console_helpers.S \ plat/common/plat_gicv3.c \ plat/xilinx/versal/aarch64/versal_helpers.S \ plat/xilinx/versal/aarch64/versal_common.c BL31_SOURCES += lib/cpus/aarch64/cortex_a53.S \ lib/cpus/aarch64/cortex_a72.S \ plat/common/plat_psci_common.c \ plat/xilinx/versal/bl31_versal_setup.c \ plat/xilinx/versal/plat_psci.c \ plat/xilinx/versal/plat_versal.c \ plat/xilinx/versal/plat_topology.c \ plat/xilinx/versal/sip_svc_setup.c \ plat/xilinx/versal/versal_gicv3.c trusted-firmware-a-2.2/plat/xilinx/versal/sip_svc_setup.c000066400000000000000000000040171355360272700237140ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* Top level SMC handler for SiP calls. Dispatch PM calls to PM SMC handler. */ #include #include #include /* SMC function IDs for SiP Service queries */ #define VERSAL_SIP_SVC_CALL_COUNT 0x8200ff00 #define VERSAL_SIP_SVC_UID 0x8200ff01 #define VERSAL_SIP_SVC_VERSION 0x8200ff03 /* SiP Service Calls version numbers */ #define SIP_SVC_VERSION_MAJOR 0 #define SIP_SVC_VERSION_MINOR 1 /* These macros are used to identify PM calls from the SMC function ID */ #define PM_FID_MASK 0xf000u #define PM_FID_VALUE 0u #define is_pm_fid(_fid) (((_fid) & PM_FID_MASK) == PM_FID_VALUE) /* SiP Service UUID */ DEFINE_SVC_UUID2(versal_sip_uuid, 0x2ab9e4ec, 0x93b9, 0x11e7, 0xa0, 0x19, 0xdf, 0xe0, 0xdb, 0xad, 0x0a, 0xe0); /** * sip_svc_setup() - Setup SiP Service * * Invokes PM setup */ static int32_t sip_svc_setup(void) { return 0; } /** * sip_svc_smc_handler() - Top-level SiP Service SMC handler * * Handler for all SiP SMC calls. Handles standard SIP requests * and calls PM SMC handler if the call is for a PM-API function. */ uintptr_t sip_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) { /* Let PM SMC handler deal with PM-related requests */ switch (smc_fid) { case VERSAL_SIP_SVC_CALL_COUNT: /* PM functions + default functions */ SMC_RET1(handle, 2); case VERSAL_SIP_SVC_UID: SMC_UUID_RET(handle, versal_sip_uuid); case VERSAL_SIP_SVC_VERSION: SMC_RET2(handle, SIP_SVC_VERSION_MAJOR, SIP_SVC_VERSION_MINOR); default: WARN("Unimplemented SiP Service Call: 0x%x\n", smc_fid); SMC_RET1(handle, SMC_UNK); } } /* Register PM Service Calls as runtime service */ DECLARE_RT_SVC( sip_svc, OEN_SIP_START, OEN_SIP_END, SMC_TYPE_FAST, sip_svc_setup, sip_svc_smc_handler); trusted-firmware-a-2.2/plat/xilinx/versal/versal_def.h000066400000000000000000000067631355360272700231570ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef VERSAL_DEF_H #define VERSAL_DEF_H #include /* List all consoles */ #define VERSAL_CONSOLE_ID_pl011 1 #define VERSAL_CONSOLE_ID_pl011_0 1 #define VERSAL_CONSOLE_ID_pl011_1 2 #define VERSAL_CONSOLE_ID_dcc 3 #define VERSAL_CONSOLE_IS(con) (VERSAL_CONSOLE_ID_ ## con == VERSAL_CONSOLE) /* List all supported platforms */ #define VERSAL_PLATFORM_ID_versal_virt 1 #define VERSAL_PLATFORM_IS(con) (VERSAL_PLATFORM_ID_ ## con == VERSAL_PLATFORM) /* Firmware Image Package */ #define VERSAL_PRIMARY_CPU 0 /******************************************************************************* * memory map related constants ******************************************************************************/ #define DEVICE0_BASE 0xFF000000 #define DEVICE0_SIZE 0x00E00000 #define DEVICE1_BASE 0xF9000000 #define DEVICE1_SIZE 0x00800000 /* CRL */ #define VERSAL_CRL 0xFF5E0000 #define VERSAL_CRL_IOU_SWITCH_CTRL (VERSAL_CRL + 0x114) #define VERSAL_CRL_TIMESTAMP_REF_CTRL (VERSAL_CRL + 0x14C) #define VERSAL_CRL_RST_TIMESTAMP_OFFSET (VERSAL_CRL + 0x348) #define VERSAL_CRL_APB_TIMESTAMP_REF_CTRL_CLKACT_BIT (1 << 25) #define VERSAL_IOU_SWITCH_CTRL_CLKACT_BIT (1 << 25) #define VERSAL_IOU_SWITCH_CTRL_DIVISOR0_SHIFT 8 /* IOU SCNTRS */ #define VERSAL_IOU_SCNTRS 0xFF140000 #define VERSAL_IOU_SCNTRS_COUNTER_CONTROL_REG (VERSAL_IOU_SCNTRS + 0x0) #define VERSAL_IOU_SCNTRS_BASE_FREQ (VERSAL_IOU_SCNTRS + 0x20) #define VERSAL_IOU_SCNTRS_CONTROL_EN 1 /******************************************************************************* * IRQ constants ******************************************************************************/ #define VERSAL_IRQ_SEC_PHY_TIMER 29 /******************************************************************************* * UART related constants ******************************************************************************/ #define VERSAL_UART0_BASE 0xFF000000 #define VERSAL_UART1_BASE 0xFF010000 #if VERSAL_CONSOLE_IS(pl011) # define VERSAL_UART_BASE VERSAL_UART0_BASE #elif VERSAL_CONSOLE_IS(pl011_1) # define VERSAL_UART_BASE VERSAL_UART1_BASE #else # error "invalid VERSAL_CONSOLE" #endif #define PLAT_VERSAL_CRASH_UART_BASE VERSAL_UART_BASE #define PLAT_VERSAL_CRASH_UART_CLK_IN_HZ VERSAL_UART_CLOCK #define VERSAL_CONSOLE_BAUDRATE VERSAL_UART_BAUDRATE /******************************************************************************* * Platform related constants ******************************************************************************/ #if VERSAL_PLATFORM_IS(versal_virt) # define PLATFORM_NAME "Versal Virt" # define VERSAL_UART_CLOCK 25000000 # define VERSAL_UART_BAUDRATE 115200 # define VERSAL_CPU_CLOCK 62500000 #endif /* Access control register defines */ #define ACTLR_EL3_L2ACTLR_BIT (1 << 6) #define ACTLR_EL3_CPUACTLR_BIT (1 << 0) /* For cpu reset APU space here too 0xFE5F1000 CRF_APB*/ #define CRF_BASE 0xFD1A0000 #define CRF_SIZE 0x00600000 /* CRF registers and bitfields */ #define CRF_RST_APU (CRF_BASE + 0X00000300) #define CRF_RST_APU_ACPU_RESET (1 << 0) #define CRF_RST_APU_ACPU_PWRON_RESET (1 << 10) /* APU registers and bitfields */ #define FPD_APU_BASE 0xFD5C0000 #define FPD_APU_CONFIG_0 (FPD_APU_BASE + 0x20) #define FPD_APU_RVBAR_L_0 (FPD_APU_BASE + 0x40) #define FPD_APU_RVBAR_H_0 (FPD_APU_BASE + 0x44) #define FPD_APU_PWRCTL (FPD_APU_BASE + 0x90) #define FPD_APU_CONFIG_0_VINITHI_SHIFT 8 #endif /* VERSAL_DEF_H */ trusted-firmware-a-2.2/plat/xilinx/versal/versal_gicv3.c000066400000000000000000000142421355360272700234160ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "versal_private.h" /****************************************************************************** * The following functions are defined as weak to allow a platform to override * the way the GICv3 driver is initialised and used. *****************************************************************************/ #pragma weak plat_versal_gic_driver_init #pragma weak plat_versal_gic_init #pragma weak plat_versal_gic_cpuif_enable #pragma weak plat_versal_gic_cpuif_disable #pragma weak plat_versal_gic_pcpu_init #pragma weak plat_versal_gic_redistif_on #pragma weak plat_versal_gic_redistif_off /* The GICv3 driver only needs to be initialized in EL3 */ static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT]; static const interrupt_prop_t versal_interrupt_props[] = { PLAT_VERSAL_G1S_IRQ_PROPS(INTR_GROUP1S), PLAT_VERSAL_G0_IRQ_PROPS(INTR_GROUP0) }; /* * We save and restore the GICv3 context on system suspend. Allocate the * data in the designated EL3 Secure carve-out memory. */ static gicv3_redist_ctx_t rdist_ctx __section("versal_el3_tzc_dram"); static gicv3_dist_ctx_t dist_ctx __section("versal_el3_tzc_dram"); /* * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register * to core position. * * Calculating core position is dependent on MPIDR_EL1.MT bit. However, affinity * values read from GICR_TYPER don't have an MT field. To reuse the same * translation used for CPUs, we insert MT bit read from the PE's MPIDR into * that read from GICR_TYPER. * * Assumptions: * * - All CPUs implemented in the system have MPIDR_EL1.MT bit set; * - No CPUs implemented in the system use affinity level 3. */ static unsigned int versal_gicv3_mpidr_hash(u_register_t mpidr) { mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK); return versal_calc_core_pos(mpidr); } static const gicv3_driver_data_t versal_gic_data __unused = { .gicd_base = PLAT_VERSAL_GICD_BASE, .gicr_base = PLAT_VERSAL_GICR_BASE, .interrupt_props = versal_interrupt_props, .interrupt_props_num = ARRAY_SIZE(versal_interrupt_props), .rdistif_num = PLATFORM_CORE_COUNT, .rdistif_base_addrs = rdistif_base_addrs, .mpidr_to_core_pos = versal_gicv3_mpidr_hash }; void __init plat_versal_gic_driver_init(void) { /* * The GICv3 driver is initialized in EL3 and does not need * to be initialized again in SEL1. This is because the S-EL1 * can use GIC system registers to manage interrupts and does * not need GIC interface base addresses to be configured. */ #if IMAGE_BL31 gicv3_driver_init(&versal_gic_data); #endif } /****************************************************************************** * Versal common helper to initialize the GIC. Only invoked by BL31 *****************************************************************************/ void __init plat_versal_gic_init(void) { gicv3_distif_init(); gicv3_rdistif_init(plat_my_core_pos()); gicv3_cpuif_enable(plat_my_core_pos()); } /****************************************************************************** * Versal common helper to enable the GIC CPU interface *****************************************************************************/ void plat_versal_gic_cpuif_enable(void) { gicv3_cpuif_enable(plat_my_core_pos()); } /****************************************************************************** * Versal common helper to disable the GIC CPU interface *****************************************************************************/ void plat_versal_gic_cpuif_disable(void) { gicv3_cpuif_disable(plat_my_core_pos()); } /****************************************************************************** * Versal common helper to initialize the per-cpu redistributor interface in * GICv3 *****************************************************************************/ void plat_versal_gic_pcpu_init(void) { gicv3_rdistif_init(plat_my_core_pos()); } /****************************************************************************** * Versal common helpers to power GIC redistributor interface *****************************************************************************/ void plat_versal_gic_redistif_on(void) { gicv3_rdistif_on(plat_my_core_pos()); } void plat_versal_gic_redistif_off(void) { gicv3_rdistif_off(plat_my_core_pos()); } /****************************************************************************** * Versal common helper to save & restore the GICv3 on resume from system * suspend *****************************************************************************/ void plat_versal_gic_save(void) { /* * If an ITS is available, save its context before * the Redistributor using: * gicv3_its_save_disable(gits_base, &its_ctx[i]) * Additionnaly, an implementation-defined sequence may * be required to save the whole ITS state. */ /* * Save the GIC Redistributors and ITS contexts before the * Distributor context. As we only handle SYSTEM SUSPEND API, * we only need to save the context of the CPU that is issuing * the SYSTEM SUSPEND call, i.e. the current CPU. */ gicv3_rdistif_save(plat_my_core_pos(), &rdist_ctx); /* Save the GIC Distributor context */ gicv3_distif_save(&dist_ctx); /* * From here, all the components of the GIC can be safely powered down * as long as there is an alternate way to handle wakeup interrupt * sources. */ } void plat_versal_gic_resume(void) { /* Restore the GIC Distributor context */ gicv3_distif_init_restore(&dist_ctx); /* * Restore the GIC Redistributor and ITS contexts after the * Distributor context. As we only handle SYSTEM SUSPEND API, * we only need to restore the context of the CPU that issued * the SYSTEM SUSPEND call. */ gicv3_rdistif_init_restore(plat_my_core_pos(), &rdist_ctx); /* * If an ITS is available, restore its context after * the Redistributor using: * gicv3_its_restore(gits_base, &its_ctx[i]) * An implementation-defined sequence may be required to * restore the whole ITS state. The ITS must also be * re-enabled after this sequence has been executed. */ } trusted-firmware-a-2.2/plat/xilinx/versal/versal_private.h000066400000000000000000000011071355360272700240560ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef VERSAL_PRIVATE_H #define VERSAL_PRIVATE_H #include void versal_config_setup(void); const mmap_region_t *plat_versal_get_mmap(void); void plat_versal_gic_driver_init(void); void plat_versal_gic_init(void); void plat_versal_gic_cpuif_enable(void); void plat_versal_gic_cpuif_disable(void); void plat_versal_gic_pcpu_init(void); unsigned int versal_calc_core_pos(u_register_t mpidr); #endif /* VERSAL_PRIVATE_H */ trusted-firmware-a-2.2/plat/xilinx/zynqmp/000077500000000000000000000000001355360272700207225ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/xilinx/zynqmp/aarch64/000077500000000000000000000000001355360272700221525ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/xilinx/zynqmp/aarch64/zynqmp_common.c000066400000000000000000000146151355360272700252330ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "pm_api_sys.h" /* * Table of regions to map using the MMU. * This doesn't include TZRAM as the 'mem_layout' argument passed to * configure_mmu_elx() will give the available subset of that, */ const mmap_region_t plat_arm_mmap[] = { { DEVICE0_BASE, DEVICE0_BASE, DEVICE0_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, { DEVICE1_BASE, DEVICE1_BASE, DEVICE1_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, { CRF_APB_BASE, CRF_APB_BASE, CRF_APB_SIZE, MT_DEVICE | MT_RW | MT_SECURE }, {0} }; static unsigned int zynqmp_get_silicon_ver(void) { static unsigned int ver; if (!ver) { ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET); ver &= ZYNQMP_SILICON_VER_MASK; ver >>= ZYNQMP_SILICON_VER_SHIFT; } return ver; } unsigned int zynqmp_get_uart_clk(void) { unsigned int ver = zynqmp_get_silicon_ver(); if (ver == ZYNQMP_CSU_VERSION_QEMU) return 133000000; else return 100000000; } #if LOG_LEVEL >= LOG_LEVEL_NOTICE static const struct { unsigned int id; unsigned int ver; char *name; bool evexists; } zynqmp_devices[] = { { .id = 0x10, .name = "3EG", }, { .id = 0x10, .ver = 0x2c, .name = "3CG", }, { .id = 0x11, .name = "2EG", }, { .id = 0x11, .ver = 0x2c, .name = "2CG", }, { .id = 0x20, .name = "5EV", .evexists = true, }, { .id = 0x20, .ver = 0x100, .name = "5EG", .evexists = true, }, { .id = 0x20, .ver = 0x12c, .name = "5CG", }, { .id = 0x21, .name = "4EV", .evexists = true, }, { .id = 0x21, .ver = 0x100, .name = "4EG", .evexists = true, }, { .id = 0x21, .ver = 0x12c, .name = "4CG", }, { .id = 0x30, .name = "7EV", .evexists = true, }, { .id = 0x30, .ver = 0x100, .name = "7EG", .evexists = true, }, { .id = 0x30, .ver = 0x12c, .name = "7CG", }, { .id = 0x38, .name = "9EG", }, { .id = 0x38, .ver = 0x2c, .name = "9CG", }, { .id = 0x39, .name = "6EG", }, { .id = 0x39, .ver = 0x2c, .name = "6CG", }, { .id = 0x40, .name = "11EG", }, { /* For testing purpose only */ .id = 0x50, .ver = 0x2c, .name = "15CG", }, { .id = 0x50, .name = "15EG", }, { .id = 0x58, .name = "19EG", }, { .id = 0x59, .name = "17EG", }, { .id = 0x60, .name = "28DR", }, { .id = 0x61, .name = "21DR", }, { .id = 0x62, .name = "29DR", }, { .id = 0x63, .name = "23DR", }, { .id = 0x64, .name = "27DR", }, { .id = 0x65, .name = "25DR", }, }; #define ZYNQMP_PL_STATUS_BIT 9 #define ZYNQMP_PL_STATUS_MASK BIT(ZYNQMP_PL_STATUS_BIT) #define ZYNQMP_CSU_VERSION_MASK ~(ZYNQMP_PL_STATUS_MASK) static char *zynqmp_get_silicon_idcode_name(void) { uint32_t id, ver, chipid[2]; size_t i, j, len; const char *name = "EG/EV"; #ifdef IMAGE_BL32 /* * For BL32, get the chip id info directly by reading corresponding * registers instead of making pm call. This has limitation * that these registers should be configured to have access * from APU which is default case. */ chipid[0] = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET); chipid[1] = mmio_read_32(EFUSE_BASEADDR + EFUSE_IPDISABLE_OFFSET); #else if (pm_get_chipid(chipid) != PM_RET_SUCCESS) return "UNKN"; #endif id = chipid[0] & (ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK | ZYNQMP_CSU_IDCODE_SVD_MASK); id >>= ZYNQMP_CSU_IDCODE_SVD_SHIFT; ver = chipid[1] >> ZYNQMP_EFUSE_IPDISABLE_SHIFT; for (i = 0; i < ARRAY_SIZE(zynqmp_devices); i++) { if (zynqmp_devices[i].id == id && zynqmp_devices[i].ver == (ver & ZYNQMP_CSU_VERSION_MASK)) break; } if (i >= ARRAY_SIZE(zynqmp_devices)) return "UNKN"; if (!zynqmp_devices[i].evexists) return zynqmp_devices[i].name; if (ver & ZYNQMP_PL_STATUS_MASK) return zynqmp_devices[i].name; len = strlen(zynqmp_devices[i].name) - 2; for (j = 0; j < strlen(name); j++) { zynqmp_devices[i].name[len] = name[j]; len++; } zynqmp_devices[i].name[len] = '\0'; return zynqmp_devices[i].name; } static unsigned int zynqmp_get_rtl_ver(void) { uint32_t ver; ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET); ver &= ZYNQMP_RTL_VER_MASK; ver >>= ZYNQMP_RTL_VER_SHIFT; return ver; } static char *zynqmp_print_silicon_idcode(void) { uint32_t id, maskid, tmp; id = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_IDCODE_OFFSET); tmp = id; tmp &= ZYNQMP_CSU_IDCODE_XILINX_ID_MASK | ZYNQMP_CSU_IDCODE_FAMILY_MASK; maskid = ZYNQMP_CSU_IDCODE_XILINX_ID << ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT | ZYNQMP_CSU_IDCODE_FAMILY << ZYNQMP_CSU_IDCODE_FAMILY_SHIFT; if (tmp != maskid) { ERROR("Incorrect XILINX IDCODE 0x%x, maskid 0x%x\n", id, maskid); return "UNKN"; } VERBOSE("Xilinx IDCODE 0x%x\n", id); return zynqmp_get_silicon_idcode_name(); } static unsigned int zynqmp_get_ps_ver(void) { uint32_t ver = mmio_read_32(ZYNQMP_CSU_BASEADDR + ZYNQMP_CSU_VERSION_OFFSET); ver &= ZYNQMP_PS_VER_MASK; ver >>= ZYNQMP_PS_VER_SHIFT; return ver + 1; } static void zynqmp_print_platform_name(void) { unsigned int ver = zynqmp_get_silicon_ver(); unsigned int rtl = zynqmp_get_rtl_ver(); char *label = "Unknown"; switch (ver) { case ZYNQMP_CSU_VERSION_QEMU: label = "QEMU"; break; case ZYNQMP_CSU_VERSION_SILICON: label = "silicon"; break; default: /* Do nothing in default case */ break; } NOTICE("ATF running on XCZU%s/%s v%d/RTL%d.%d at 0x%x\n", zynqmp_print_silicon_idcode(), label, zynqmp_get_ps_ver(), (rtl & 0xf0) >> 4, rtl & 0xf, BL31_BASE); } #else static inline void zynqmp_print_platform_name(void) { } #endif unsigned int zynqmp_get_bootmode(void) { uint32_t r; unsigned int ret; ret = pm_mmio_read(CRL_APB_BOOT_MODE_USER, &r); if (ret != PM_RET_SUCCESS) r = mmio_read_32(CRL_APB_BOOT_MODE_USER); return r & CRL_APB_BOOT_MODE_MASK; } void zynqmp_config_setup(void) { /* Configure IPI data for ZynqMP */ zynqmp_ipi_config_table_init(); zynqmp_print_platform_name(); generic_delay_timer_init(); } unsigned int plat_get_syscnt_freq2(void) { unsigned int ver = zynqmp_get_silicon_ver(); if (ver == ZYNQMP_CSU_VERSION_QEMU) return 50000000; else return mmio_read_32(IOU_SCNTRS_BASEFREQ); } trusted-firmware-a-2.2/plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S000066400000000000000000000074721355360272700253700ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include .globl plat_secondary_cold_boot_setup .globl plat_is_my_cpu_primary .globl zynqmp_calc_core_pos .globl plat_my_core_pos .globl plat_crash_console_init .globl plat_crash_console_putc .globl plat_crash_console_flush .globl platform_mem_init /* ----------------------------------------------------- * void plat_secondary_cold_boot_setup (void); * * This function performs any platform specific actions * needed for a secondary cpu after a cold reset e.g * mark the cpu's presence, mechanism to place it in a * holding pen etc. * TODO: Should we read the PSYS register to make sure * that the request has gone through. * ----------------------------------------------------- */ func plat_secondary_cold_boot_setup mrs x0, mpidr_el1 /* Deactivate the gic cpu interface */ ldr x1, =BASE_GICC_BASE mov w0, #(IRQ_BYP_DIS_GRP1 | FIQ_BYP_DIS_GRP1) orr w0, w0, #(IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP0) str w0, [x1, #GICC_CTLR] /* * There is no sane reason to come out of this wfi. This * cpu will be powered on and reset by the cpu_on pm api */ dsb sy 1: no_ret plat_panic_handler endfunc plat_secondary_cold_boot_setup func plat_is_my_cpu_primary mov x9, x30 bl plat_my_core_pos cmp x0, #ZYNQMP_PRIMARY_CPU cset x0, eq ret x9 endfunc plat_is_my_cpu_primary /* ----------------------------------------------------- * unsigned int plat_my_core_pos(void) * This function uses the zynqmp_calc_core_pos() * definition to get the index of the calling CPU. * ----------------------------------------------------- */ func plat_my_core_pos mrs x0, mpidr_el1 b zynqmp_calc_core_pos endfunc plat_my_core_pos /* ----------------------------------------------------- * unsigned int zynqmp_calc_core_pos(u_register_t mpidr) * Helper function to calculate the core position. * With this function: CorePos = (ClusterId * 4) + * CoreId * ----------------------------------------------------- */ func zynqmp_calc_core_pos and x1, x0, #MPIDR_CPU_MASK and x0, x0, #MPIDR_CLUSTER_MASK add x0, x1, x0, LSR #6 ret endfunc zynqmp_calc_core_pos /* --------------------------------------------- * int plat_crash_console_init(void) * Function to initialize the crash console * without a C Runtime to print crash report. * Clobber list : x0 - x4 * --------------------------------------------- */ func plat_crash_console_init mov_imm x0, ZYNQMP_CRASH_UART_BASE mov_imm x1, ZYNQMP_CRASH_UART_CLK_IN_HZ mov_imm x2, ZYNQMP_UART_BAUDRATE b console_cdns_core_init endfunc plat_crash_console_init /* --------------------------------------------- * int plat_crash_console_putc(int c) * Function to print a character on the crash * console without a C Runtime. * Clobber list : x1, x2 * --------------------------------------------- */ func plat_crash_console_putc mov_imm x1, ZYNQMP_CRASH_UART_BASE b console_cdns_core_putc endfunc plat_crash_console_putc /* --------------------------------------------- * int plat_crash_console_flush() * Function to force a write of all buffered * data that hasn't been output. * Out : return -1 on error else return 0. * Clobber list : r0 * --------------------------------------------- */ func plat_crash_console_flush mov_imm x0, ZYNQMP_CRASH_UART_BASE b console_cdns_core_flush endfunc plat_crash_console_flush /* --------------------------------------------------------------------- * We don't need to carry out any memory initialization on ARM * platforms. The Secure RAM is accessible straight away. * --------------------------------------------------------------------- */ func platform_mem_init ret endfunc platform_mem_init trusted-firmware-a-2.2/plat/xilinx/zynqmp/bl31_zynqmp_setup.c000066400000000000000000000131731355360272700244720ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include static entry_point_info_t bl32_image_ep_info; static entry_point_info_t bl33_image_ep_info; /* * Return a pointer to the 'entry_point_info' structure of the next image for * the security state specified. BL33 corresponds to the non-secure image type * while BL32 corresponds to the secure image type. A NULL pointer is returned * if the image does not exist. */ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) { assert(sec_state_is_valid(type)); if (type == NON_SECURE) return &bl33_image_ep_info; return &bl32_image_ep_info; } /* * Set the build time defaults. We want to do this when doing a JTAG boot * or if we can't find any other config data. */ static inline void bl31_set_default_config(void) { bl32_image_ep_info.pc = BL32_BASE; bl32_image_ep_info.spsr = arm_get_spsr_for_bl32_entry(); bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); bl33_image_ep_info.spsr = SPSR_64(MODE_EL2, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); } /* * Perform any BL31 specific platform actions. Here is an opportunity to copy * parameters passed by the calling EL (S-EL1 in BL2 & EL3 in BL1) before they * are lost (potentially). This needs to be done before the MMU is initialized * so that the memory layout can be used while creating page tables. */ void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, u_register_t arg2, u_register_t arg3) { /* Register the console to provide early debug support */ static console_cdns_t bl31_boot_console; (void)console_cdns_register(ZYNQMP_UART_BASE, zynqmp_get_uart_clk(), ZYNQMP_UART_BAUDRATE, &bl31_boot_console); console_set_scope(&bl31_boot_console.console, CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_BOOT); /* Initialize the platform config for future decision making */ zynqmp_config_setup(); /* There are no parameters from BL2 if BL31 is a reset vector */ assert(arg0 == 0U); assert(arg1 == 0U); /* * Do initial security configuration to allow DRAM/device access. On * Base ZYNQMP only DRAM security is programmable (via TrustZone), but * other platforms might have more programmable security devices * present. */ /* Populate common information for BL32 and BL33 */ SET_PARAM_HEAD(&bl32_image_ep_info, PARAM_EP, VERSION_1, 0); SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); SET_PARAM_HEAD(&bl33_image_ep_info, PARAM_EP, VERSION_1, 0); SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); if (zynqmp_get_bootmode() == ZYNQMP_BOOTMODE_JTAG) { bl31_set_default_config(); } else { /* use parameters from FSBL */ enum fsbl_handoff ret = fsbl_atf_handover(&bl32_image_ep_info, &bl33_image_ep_info); if (ret == FSBL_HANDOFF_NO_STRUCT) bl31_set_default_config(); else if (ret != FSBL_HANDOFF_SUCCESS) panic(); } NOTICE("BL31: Secure code at 0x%lx\n", bl32_image_ep_info.pc); NOTICE("BL31: Non secure code at 0x%lx\n", bl33_image_ep_info.pc); } /* Enable the test setup */ #ifndef ZYNQMP_TESTING static void zynqmp_testing_setup(void) { } #else static void zynqmp_testing_setup(void) { uint32_t actlr_el3, actlr_el2; /* Enable CPU ACTLR AND L2ACTLR RW access from non-secure world */ actlr_el3 = read_actlr_el3(); actlr_el2 = read_actlr_el2(); actlr_el3 |= ACTLR_EL3_L2ACTLR_BIT | ACTLR_EL3_CPUACTLR_BIT; actlr_el2 |= ACTLR_EL3_L2ACTLR_BIT | ACTLR_EL3_CPUACTLR_BIT; write_actlr_el3(actlr_el3); write_actlr_el2(actlr_el2); } #endif #if ZYNQMP_WDT_RESTART static interrupt_type_handler_t type_el3_interrupt_table[MAX_INTR_EL3]; int request_intr_type_el3(uint32_t id, interrupt_type_handler_t handler) { /* Validate 'handler' and 'id' parameters */ if (!handler || id >= MAX_INTR_EL3) return -EINVAL; /* Check if a handler has already been registered */ if (type_el3_interrupt_table[id]) return -EALREADY; type_el3_interrupt_table[id] = handler; return 0; } static uint64_t rdo_el3_interrupt_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { uint32_t intr_id; interrupt_type_handler_t handler; intr_id = plat_ic_get_pending_interrupt_id(); handler = type_el3_interrupt_table[intr_id]; if (handler != NULL) handler(intr_id, flags, handle, cookie); return 0; } #endif void bl31_platform_setup(void) { /* Initialize the gic cpu and distributor interfaces */ plat_arm_gic_driver_init(); plat_arm_gic_init(); zynqmp_testing_setup(); } void bl31_plat_runtime_setup(void) { #if ZYNQMP_WDT_RESTART uint64_t flags = 0; uint64_t rc; set_interrupt_rm_flag(flags, NON_SECURE); rc = register_interrupt_type_handler(INTR_TYPE_EL3, rdo_el3_interrupt_handler, flags); if (rc) panic(); #endif } /* * Perform the very early platform specific architectural setup here. */ void bl31_plat_arch_setup(void) { plat_arm_interconnect_init(); plat_arm_interconnect_enter_coherency(); const mmap_region_t bl_regions[] = { MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE, MT_MEMORY | MT_RW | MT_SECURE), MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, MT_CODE | MT_SECURE), MAP_REGION_FLAT(BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE, MT_RO_DATA | MT_SECURE), MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, MT_DEVICE | MT_RW | MT_SECURE), {0} }; setup_page_tables(bl_regions, plat_arm_get_mmap()); enable_mmu_el3(0); } trusted-firmware-a-2.2/plat/xilinx/zynqmp/include/000077500000000000000000000000001355360272700223455ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/xilinx/zynqmp/include/plat_ipi.h000066400000000000000000000030601355360272700243160ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* ZynqMP IPI management enums and defines */ #ifndef PLAT_IPI_H #define PLAT_IPI_H #include #include /********************************************************************* * IPI agent IDs macros ********************************************************************/ #define IPI_ID_APU 0U #define IPI_ID_RPU0 1U #define IPI_ID_RPU1 2U #define IPI_ID_PMU0 3U #define IPI_ID_PMU1 4U #define IPI_ID_PMU2 5U #define IPI_ID_PMU3 6U #define IPI_ID_PL0 7U #define IPI_ID_PL1 8U #define IPI_ID_PL2 9U #define IPI_ID_PL3 10U /********************************************************************* * IPI message buffers ********************************************************************/ #define IPI_BUFFER_BASEADDR 0xFF990000U #define IPI_BUFFER_APU_BASE (IPI_BUFFER_BASEADDR + 0x400U) #define IPI_BUFFER_PMU_BASE (IPI_BUFFER_BASEADDR + 0xE00U) #define IPI_BUFFER_LOCAL_BASE IPI_BUFFER_APU_BASE #define IPI_BUFFER_REMOTE_BASE IPI_BUFFER_PMU_BASE #define IPI_BUFFER_TARGET_LOCAL_OFFSET 0x80U #define IPI_BUFFER_TARGET_REMOTE_OFFSET 0x1C0U #define IPI_BUFFER_MAX_WORDS 8 #define IPI_BUFFER_REQ_OFFSET 0x0U #define IPI_BUFFER_RESP_OFFSET 0x20U /********************************************************************* * Platform specific IPI API declarations ********************************************************************/ /* Configure IPI table for zynqmp */ void zynqmp_ipi_config_table_init(void); #endif /* PLAT_IPI_H */ trusted-firmware-a-2.2/plat/xilinx/zynqmp/include/plat_macros.S000066400000000000000000000012731355360272700250000ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_MACROS_S #define PLAT_MACROS_S #include #include #include "zynqmp_def.h" /* --------------------------------------------- * The below required platform porting macro * prints out relevant GIC and CCI registers * whenever an unhandled exception is taken in * BL31. * Clobbers: x0 - x10, x16, x17, sp * --------------------------------------------- */ .macro plat_crash_print_regs mov_imm x17, BASE_GICC_BASE mov_imm x16, BASE_GICD_BASE arm_print_gic_regs print_cci_regs .endm #endif /* PLAT_MACROS_S */ trusted-firmware-a-2.2/plat/xilinx/zynqmp/include/plat_pm_common.h000066400000000000000000000012451355360272700255240ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * Contains platform specific definitions of commonly used macros data types * for PU Power Management. This file should be common for all PU's. */ #ifndef PLAT_PM_COMMON_H #define PLAT_PM_COMMON_H #include #include #include "pm_defs.h" #define PAYLOAD_ARG_CNT 6U #define PAYLOAD_ARG_SIZE 4U /* size in bytes */ #define ZYNQMP_TZ_VERSION_MAJOR 1 #define ZYNQMP_TZ_VERSION_MINOR 0 #define ZYNQMP_TZ_VERSION ((ZYNQMP_TZ_VERSION_MAJOR << 16) | \ ZYNQMP_TZ_VERSION_MINOR) #endif /* _PLAT_PM_COMMON_H_ */ trusted-firmware-a-2.2/plat/xilinx/zynqmp/include/plat_private.h000066400000000000000000000017521355360272700252150ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLAT_PRIVATE_H #define PLAT_PRIVATE_H #include #include #include #include void zynqmp_config_setup(void); unsigned int zynqmp_calc_core_pos(u_register_t mpidr); /* ZynqMP specific functions */ unsigned int zynqmp_get_uart_clk(void); unsigned int zynqmp_get_bootmode(void); /* For FSBL handover */ enum fsbl_handoff { FSBL_HANDOFF_SUCCESS = 0, FSBL_HANDOFF_NO_STRUCT, FSBL_HANDOFF_INVAL_STRUCT, FSBL_HANDOFF_TOO_MANY_PARTS, }; #if ZYNQMP_WDT_RESTART /* * Register handler to specific GIC entrance * for INTR_TYPE_EL3 type of interrupt */ int request_intr_type_el3(uint32_t, interrupt_type_handler_t); #endif enum fsbl_handoff fsbl_atf_handover(entry_point_info_t *bl32_image_ep_info, entry_point_info_t *bl33_image_ep_info); #endif /* PLAT_PRIVATE_H */ trusted-firmware-a-2.2/plat/xilinx/zynqmp/include/platform_def.h000066400000000000000000000124251355360272700251640ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PLATFORM_DEF_H #define PLATFORM_DEF_H #include #include #include #include #include "zynqmp_def.h" /******************************************************************************* * Generic platform constants ******************************************************************************/ /* Size of cacheable stacks */ #define PLATFORM_STACK_SIZE 0x440 #define PLATFORM_CORE_COUNT 4 #define PLAT_NUM_POWER_DOMAINS 5 #define PLAT_MAX_PWR_LVL U(1) #define PLAT_MAX_RET_STATE U(1) #define PLAT_MAX_OFF_STATE U(2) /******************************************************************************* * BL31 specific defines. ******************************************************************************/ /* * Put BL31 at the top of the Trusted SRAM (just below the shared memory, if * present). BL31_BASE is calculated using the current BL31 debug size plus a * little space for growth. */ #ifndef ZYNQMP_ATF_MEM_BASE #if !DEBUG && defined(SPD_none) # define BL31_BASE 0xfffea000 # define BL31_LIMIT 0xffffffff #else # define BL31_BASE 0x1000 # define BL31_LIMIT 0x7ffff #endif #else # define BL31_BASE (ZYNQMP_ATF_MEM_BASE) # define BL31_LIMIT (ZYNQMP_ATF_MEM_BASE + ZYNQMP_ATF_MEM_SIZE - 1) # ifdef ZYNQMP_ATF_MEM_PROGBITS_SIZE # define BL31_PROGBITS_LIMIT (ZYNQMP_ATF_MEM_BASE + ZYNQMP_ATF_MEM_PROGBITS_SIZE - 1) # endif #endif /******************************************************************************* * BL32 specific defines. ******************************************************************************/ #ifndef ZYNQMP_BL32_MEM_BASE # define BL32_BASE 0x60000000 # define BL32_LIMIT 0x7fffffff #else # define BL32_BASE (ZYNQMP_BL32_MEM_BASE) # define BL32_LIMIT (ZYNQMP_BL32_MEM_BASE + ZYNQMP_BL32_MEM_SIZE - 1) #endif /******************************************************************************* * BL33 specific defines. ******************************************************************************/ #ifndef PRELOADED_BL33_BASE # define PLAT_ARM_NS_IMAGE_BASE 0x8000000 #else # define PLAT_ARM_NS_IMAGE_BASE PRELOADED_BL33_BASE #endif /******************************************************************************* * TSP specific defines. ******************************************************************************/ #define TSP_SEC_MEM_BASE BL32_BASE #define TSP_SEC_MEM_SIZE (BL32_LIMIT - BL32_BASE + 1) /* ID of the secure physical generic timer interrupt used by the TSP */ #define TSP_IRQ_SEC_PHY_TIMER ARM_IRQ_SEC_PHY_TIMER /******************************************************************************* * 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 MAX_MMAP_REGIONS 7 #define MAX_XLAT_TABLES 5 #define CACHE_WRITEBACK_SHIFT 6 #define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) #define PLAT_ARM_GICD_BASE BASE_GICD_BASE #define PLAT_ARM_GICC_BASE BASE_GICC_BASE /* * Define properties of Group 1 Secure and Group 0 interrupts as per GICv3 * terminology. On a GICv2 system or mode, the lists will be merged and treated * as Group 0 interrupts. */ #if !ZYNQMP_WDT_RESTART #define PLAT_ARM_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE) #else #define PLAT_ARM_G1S_IRQ_PROPS(grp) \ INTR_PROP_DESC(ARM_IRQ_SEC_PHY_TIMER, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_LEVEL), \ INTR_PROP_DESC(IRQ_TTC3_1, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_0, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_2, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_3, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_4, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_5, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_6, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE), \ INTR_PROP_DESC(ARM_IRQ_SEC_SGI_7, GIC_HIGHEST_SEC_PRIORITY, grp, \ GIC_INTR_CFG_EDGE) #endif #define PLAT_ARM_G0_IRQ_PROPS(grp) #endif /* PLATFORM_DEF_H */ trusted-firmware-a-2.2/plat/xilinx/zynqmp/include/zynqmp_def.h000066400000000000000000000317771355360272700247110ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef ZYNQMP_DEF_H #define ZYNQMP_DEF_H #include #define ZYNQMP_CONSOLE_ID_cadence 1 #define ZYNQMP_CONSOLE_ID_cadence0 1 #define ZYNQMP_CONSOLE_ID_cadence1 2 #define ZYNQMP_CONSOLE_ID_dcc 3 #define ZYNQMP_CONSOLE_IS(con) (ZYNQMP_CONSOLE_ID_ ## con == ZYNQMP_CONSOLE) /* Firmware Image Package */ #define ZYNQMP_PRIMARY_CPU 0 /* Memory location options for Shared data and TSP in ZYNQMP */ #define ZYNQMP_IN_TRUSTED_SRAM 0 #define ZYNQMP_IN_TRUSTED_DRAM 1 /******************************************************************************* * ZYNQMP memory map related constants ******************************************************************************/ /* Aggregate of all devices in the first GB */ #define DEVICE0_BASE U(0xFF000000) #define DEVICE0_SIZE U(0x00E00000) #define DEVICE1_BASE U(0xF9000000) #define DEVICE1_SIZE U(0x00800000) /* For cpu reset APU space here too 0xFE5F1000 CRF_APB*/ #define CRF_APB_BASE U(0xFD1A0000) #define CRF_APB_SIZE U(0x00600000) #define CRF_APB_CLK_BASE U(0xFD1A0020) /* CRF registers and bitfields */ #define CRF_APB_RST_FPD_APU (CRF_APB_BASE + 0X00000104) #define CRF_APB_RST_FPD_APU_ACPU_RESET (U(1) << 0) #define CRF_APB_RST_FPD_APU_ACPU_PWRON_RESET (U(1) << 10) /* CRL registers and bitfields */ #define CRL_APB_BASE U(0xFF5E0000) #define CRL_APB_BOOT_MODE_USER (CRL_APB_BASE + 0x200) #define CRL_APB_RESET_CTRL (CRL_APB_BASE + 0x218) #define CRL_APB_RST_LPD_TOP (CRL_APB_BASE + 0x23C) #define CRL_APB_BOOT_PIN_CTRL (CRL_APB_BASE + U(0x250)) #define CRL_APB_CLK_BASE U(0xFF5E0020) #define CRL_APB_RPU_AMBA_RESET (U(1) << 2) #define CRL_APB_RPLL_CTRL_BYPASS (U(1) << 3) #define CRL_APB_RESET_CTRL_SOFT_RESET (U(1) << 4) #define CRL_APB_BOOT_MODE_MASK (U(0xf) << 0) #define CRL_APB_BOOT_PIN_MASK (U(0xf0f) << 0) #define CRL_APB_BOOT_DRIVE_PIN_1_SHIFT U(9) #define CRL_APB_BOOT_ENABLE_PIN_1_SHIFT U(1) #define CRL_APB_BOOT_ENABLE_PIN_1 (U(0x1) << \ CRL_APB_BOOT_ENABLE_PIN_1_SHIFT) #define CRL_APB_BOOT_DRIVE_PIN_1 (U(0x1) << \ CRL_APB_BOOT_DRIVE_PIN_1_SHIFT) #define ZYNQMP_BOOTMODE_JTAG U(0) #define ZYNQMP_ULPI_RESET_VAL_HIGH (CRL_APB_BOOT_ENABLE_PIN_1 | \ CRL_APB_BOOT_DRIVE_PIN_1) #define ZYNQMP_ULPI_RESET_VAL_LOW CRL_APB_BOOT_ENABLE_PIN_1 /* system counter registers and bitfields */ #define IOU_SCNTRS_BASE 0xFF260000 #define IOU_SCNTRS_BASEFREQ (IOU_SCNTRS_BASE + 0x20) /* APU registers and bitfields */ #define APU_BASE 0xFD5C0000 #define APU_CONFIG_0 (APU_BASE + 0x20) #define APU_RVBAR_L_0 (APU_BASE + 0x40) #define APU_RVBAR_H_0 (APU_BASE + 0x44) #define APU_PWRCTL (APU_BASE + 0x90) #define APU_CONFIG_0_VINITHI_SHIFT 8 #define APU_0_PWRCTL_CPUPWRDWNREQ_MASK 1 #define APU_1_PWRCTL_CPUPWRDWNREQ_MASK 2 #define APU_2_PWRCTL_CPUPWRDWNREQ_MASK 4 #define APU_3_PWRCTL_CPUPWRDWNREQ_MASK 8 /* PMU registers and bitfields */ #define PMU_GLOBAL_BASE 0xFFD80000 #define PMU_GLOBAL_CNTRL (PMU_GLOBAL_BASE + 0) #define PMU_GLOBAL_GEN_STORAGE6 (PMU_GLOBAL_BASE + 0x48) #define PMU_GLOBAL_REQ_PWRUP_STATUS (PMU_GLOBAL_BASE + 0x110) #define PMU_GLOBAL_REQ_PWRUP_EN (PMU_GLOBAL_BASE + 0x118) #define PMU_GLOBAL_REQ_PWRUP_DIS (PMU_GLOBAL_BASE + 0x11c) #define PMU_GLOBAL_REQ_PWRUP_TRIG (PMU_GLOBAL_BASE + 0x120) #define PMU_GLOBAL_CNTRL_FW_IS_PRESENT (1 << 4) /******************************************************************************* * CCI-400 related constants ******************************************************************************/ #define PLAT_ARM_CCI_BASE 0xFD6E0000 #define PLAT_ARM_CCI_CLUSTER0_SL_IFACE_IX 3 #define PLAT_ARM_CCI_CLUSTER1_SL_IFACE_IX 4 /******************************************************************************* * GIC-400 & interrupt handling related constants ******************************************************************************/ #define BASE_GICD_BASE 0xF9010000 #define BASE_GICC_BASE 0xF9020000 #define BASE_GICH_BASE 0xF9040000 #define BASE_GICV_BASE 0xF9060000 #if ZYNQMP_WDT_RESTART #define IRQ_SEC_IPI_APU 67 #define IRQ_TTC3_1 77 #define TTC3_BASE_ADDR 0xFF140000 #define TTC3_INTR_REGISTER_1 (TTC3_BASE_ADDR + 0x54) #define TTC3_INTR_ENABLE_1 (TTC3_BASE_ADDR + 0x60) #endif #define ARM_IRQ_SEC_PHY_TIMER 29 #define ARM_IRQ_SEC_SGI_0 8 #define ARM_IRQ_SEC_SGI_1 9 #define ARM_IRQ_SEC_SGI_2 10 #define ARM_IRQ_SEC_SGI_3 11 #define ARM_IRQ_SEC_SGI_4 12 #define ARM_IRQ_SEC_SGI_5 13 #define ARM_IRQ_SEC_SGI_6 14 #define ARM_IRQ_SEC_SGI_7 15 #define MAX_INTR_EL3 128 /******************************************************************************* * UART related constants ******************************************************************************/ #define ZYNQMP_UART0_BASE 0xFF000000 #define ZYNQMP_UART1_BASE 0xFF010000 #if ZYNQMP_CONSOLE_IS(cadence) || ZYNQMP_CONSOLE_IS(dcc) # define ZYNQMP_UART_BASE ZYNQMP_UART0_BASE #elif ZYNQMP_CONSOLE_IS(cadence1) # define ZYNQMP_UART_BASE ZYNQMP_UART1_BASE #else # error "invalid ZYNQMP_CONSOLE" #endif #define ZYNQMP_CRASH_UART_BASE ZYNQMP_UART_BASE /* impossible to call C routine how it is done now - hardcode any value */ #define ZYNQMP_CRASH_UART_CLK_IN_HZ 100000000 /* FIXME */ /* Must be non zero */ #define ZYNQMP_UART_BAUDRATE 115200 /* Silicon version detection */ #define ZYNQMP_SILICON_VER_MASK 0xF000 #define ZYNQMP_SILICON_VER_SHIFT 12 #define ZYNQMP_CSU_VERSION_SILICON 0 #define ZYNQMP_CSU_VERSION_QEMU 3 #define ZYNQMP_RTL_VER_MASK 0xFF0 #define ZYNQMP_RTL_VER_SHIFT 4 #define ZYNQMP_PS_VER_MASK 0xF #define ZYNQMP_PS_VER_SHIFT 0 #define ZYNQMP_CSU_BASEADDR 0xFFCA0000 #define ZYNQMP_CSU_IDCODE_OFFSET 0x40 #define ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT 0 #define ZYNQMP_CSU_IDCODE_XILINX_ID_MASK (0xFFF << \ ZYNQMP_CSU_IDCODE_XILINX_ID_SHIFT) #define ZYNQMP_CSU_IDCODE_XILINX_ID 0x093 #define ZYNQMP_CSU_IDCODE_SVD_SHIFT 12 #define ZYNQMP_CSU_IDCODE_SVD_MASK (0x7 << \ ZYNQMP_CSU_IDCODE_SVD_SHIFT) #define ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT 15 #define ZYNQMP_CSU_IDCODE_DEVICE_CODE_MASK (0xF << \ ZYNQMP_CSU_IDCODE_DEVICE_CODE_SHIFT) #define ZYNQMP_CSU_IDCODE_SUB_FAMILY_SHIFT 19 #define ZYNQMP_CSU_IDCODE_SUB_FAMILY_MASK (0x3 << \ ZYNQMP_CSU_IDCODE_SUB_FAMILY_SHIFT) #define ZYNQMP_CSU_IDCODE_FAMILY_SHIFT 21 #define ZYNQMP_CSU_IDCODE_FAMILY_MASK (0x7F << \ ZYNQMP_CSU_IDCODE_FAMILY_SHIFT) #define ZYNQMP_CSU_IDCODE_FAMILY 0x23 #define ZYNQMP_CSU_IDCODE_REVISION_SHIFT 28 #define ZYNQMP_CSU_IDCODE_REVISION_MASK (0xF << \ ZYNQMP_CSU_IDCODE_REVISION_SHIFT) #define ZYNQMP_CSU_IDCODE_REVISION 0 #define ZYNQMP_CSU_VERSION_OFFSET 0x44 /* Efuse */ #define EFUSE_BASEADDR 0xFFCC0000 #define EFUSE_IPDISABLE_OFFSET 0x1018 #define EFUSE_IPDISABLE_VERSION 0x1FFU #define ZYNQMP_EFUSE_IPDISABLE_SHIFT 20 /* Access control register defines */ #define ACTLR_EL3_L2ACTLR_BIT (1 << 6) #define ACTLR_EL3_CPUACTLR_BIT (1 << 0) #define FPD_SLCR_BASEADDR U(0xFD610000) #define IOU_SLCR_BASEADDR U(0xFF180000) #define ZYNQMP_RPU_GLBL_CNTL U(0xFF9A0000) #define ZYNQMP_RPU0_CFG U(0xFF9A0100) #define ZYNQMP_RPU1_CFG U(0xFF9A0200) #define ZYNQMP_SLSPLIT_MASK U(0x08) #define ZYNQMP_TCM_COMB_MASK U(0x40) #define ZYNQMP_SLCLAMP_MASK U(0x10) #define ZYNQMP_VINITHI_MASK U(0x04) /* Tap delay bypass */ #define IOU_TAPDLY_BYPASS U(0XFF180390) #define TAP_DELAY_MASK U(0x7) /* SGMII mode */ #define IOU_GEM_CTRL U(0xFF180360) #define IOU_GEM_CLK_CTRL U(0xFF180308) #define SGMII_SD_MASK U(0x3) #define SGMII_SD_OFFSET U(2) #define SGMII_PCS_SD_0 U(0x0) #define SGMII_PCS_SD_1 U(0x1) #define SGMII_PCS_SD_PHY U(0x2) #define GEM_SGMII_MASK U(0x4) #define GEM_CLK_CTRL_MASK U(0xF) #define GEM_CLK_CTRL_OFFSET U(5) #define GEM_RX_SRC_SEL_GTR U(0x1) #define GEM_SGMII_MODE U(0x4) /* SD DLL reset */ #define ZYNQMP_SD_DLL_CTRL U(0xFF180358) #define ZYNQMP_SD0_DLL_RST_MASK U(0x00000004) #define ZYNQMP_SD0_DLL_RST U(0x00000004) #define ZYNQMP_SD1_DLL_RST_MASK U(0x00040000) #define ZYNQMP_SD1_DLL_RST U(0x00040000) /* SD tap delay */ #define ZYNQMP_SD_DLL_CTRL U(0xFF180358) #define ZYNQMP_SD_ITAP_DLY U(0xFF180314) #define ZYNQMP_SD_OTAP_DLY U(0xFF180318) #define ZYNQMP_SD_TAP_OFFSET U(16) #define ZYNQMP_SD_ITAPCHGWIN_MASK U(0x200) #define ZYNQMP_SD_ITAPCHGWIN U(0x200) #define ZYNQMP_SD_ITAPDLYENA_MASK U(0x100) #define ZYNQMP_SD_ITAPDLYENA U(0x100) #define ZYNQMP_SD_ITAPDLYSEL_MASK U(0xFF) #define ZYNQMP_SD_OTAPDLYSEL_MASK U(0x3F) #define ZYNQMP_SD_OTAPDLYENA_MASK U(0x40) #define ZYNQMP_SD_OTAPDLYENA U(0x40) /* Clock control registers */ /* Full power domain clocks */ #define CRF_APB_APLL_CTRL (CRF_APB_CLK_BASE + 0x00) #define CRF_APB_DPLL_CTRL (CRF_APB_CLK_BASE + 0x0c) #define CRF_APB_VPLL_CTRL (CRF_APB_CLK_BASE + 0x18) #define CRF_APB_PLL_STATUS (CRF_APB_CLK_BASE + 0x24) #define CRF_APB_APLL_TO_LPD_CTRL (CRF_APB_CLK_BASE + 0x28) #define CRF_APB_DPLL_TO_LPD_CTRL (CRF_APB_CLK_BASE + 0x2c) #define CRF_APB_VPLL_TO_LPD_CTRL (CRF_APB_CLK_BASE + 0x30) /* Peripheral clocks */ #define CRF_APB_ACPU_CTRL (CRF_APB_CLK_BASE + 0x40) #define CRF_APB_DBG_TRACE_CTRL (CRF_APB_CLK_BASE + 0x44) #define CRF_APB_DBG_FPD_CTRL (CRF_APB_CLK_BASE + 0x48) #define CRF_APB_DP_VIDEO_REF_CTRL (CRF_APB_CLK_BASE + 0x50) #define CRF_APB_DP_AUDIO_REF_CTRL (CRF_APB_CLK_BASE + 0x54) #define CRF_APB_DP_STC_REF_CTRL (CRF_APB_CLK_BASE + 0x5c) #define CRF_APB_DDR_CTRL (CRF_APB_CLK_BASE + 0x60) #define CRF_APB_GPU_REF_CTRL (CRF_APB_CLK_BASE + 0x64) #define CRF_APB_SATA_REF_CTRL (CRF_APB_CLK_BASE + 0x80) #define CRF_APB_PCIE_REF_CTRL (CRF_APB_CLK_BASE + 0x94) #define CRF_APB_GDMA_REF_CTRL (CRF_APB_CLK_BASE + 0x98) #define CRF_APB_DPDMA_REF_CTRL (CRF_APB_CLK_BASE + 0x9c) #define CRF_APB_TOPSW_MAIN_CTRL (CRF_APB_CLK_BASE + 0xa0) #define CRF_APB_TOPSW_LSBUS_CTRL (CRF_APB_CLK_BASE + 0xa4) #define CRF_APB_GTGREF0_REF_CTRL (CRF_APB_CLK_BASE + 0xa8) #define CRF_APB_DBG_TSTMP_CTRL (CRF_APB_CLK_BASE + 0xd8) /* Low power domain clocks */ #define CRL_APB_IOPLL_CTRL (CRL_APB_CLK_BASE + 0x00) #define CRL_APB_RPLL_CTRL (CRL_APB_CLK_BASE + 0x10) #define CRL_APB_PLL_STATUS (CRL_APB_CLK_BASE + 0x20) #define CRL_APB_IOPLL_TO_FPD_CTRL (CRL_APB_CLK_BASE + 0x24) #define CRL_APB_RPLL_TO_FPD_CTRL (CRL_APB_CLK_BASE + 0x28) /* Peripheral clocks */ #define CRL_APB_USB3_DUAL_REF_CTRL (CRL_APB_CLK_BASE + 0x2c) #define CRL_APB_GEM0_REF_CTRL (CRL_APB_CLK_BASE + 0x30) #define CRL_APB_GEM1_REF_CTRL (CRL_APB_CLK_BASE + 0x34) #define CRL_APB_GEM2_REF_CTRL (CRL_APB_CLK_BASE + 0x38) #define CRL_APB_GEM3_REF_CTRL (CRL_APB_CLK_BASE + 0x3c) #define CRL_APB_USB0_BUS_REF_CTRL (CRL_APB_CLK_BASE + 0x40) #define CRL_APB_USB1_BUS_REF_CTRL (CRL_APB_CLK_BASE + 0x44) #define CRL_APB_QSPI_REF_CTRL (CRL_APB_CLK_BASE + 0x48) #define CRL_APB_SDIO0_REF_CTRL (CRL_APB_CLK_BASE + 0x4c) #define CRL_APB_SDIO1_REF_CTRL (CRL_APB_CLK_BASE + 0x50) #define CRL_APB_UART0_REF_CTRL (CRL_APB_CLK_BASE + 0x54) #define CRL_APB_UART1_REF_CTRL (CRL_APB_CLK_BASE + 0x58) #define CRL_APB_SPI0_REF_CTRL (CRL_APB_CLK_BASE + 0x5c) #define CRL_APB_SPI1_REF_CTRL (CRL_APB_CLK_BASE + 0x60) #define CRL_APB_CAN0_REF_CTRL (CRL_APB_CLK_BASE + 0x64) #define CRL_APB_CAN1_REF_CTRL (CRL_APB_CLK_BASE + 0x68) #define CRL_APB_CPU_R5_CTRL (CRL_APB_CLK_BASE + 0x70) #define CRL_APB_IOU_SWITCH_CTRL (CRL_APB_CLK_BASE + 0x7c) #define CRL_APB_CSU_PLL_CTRL (CRL_APB_CLK_BASE + 0x80) #define CRL_APB_PCAP_CTRL (CRL_APB_CLK_BASE + 0x84) #define CRL_APB_LPD_SWITCH_CTRL (CRL_APB_CLK_BASE + 0x88) #define CRL_APB_LPD_LSBUS_CTRL (CRL_APB_CLK_BASE + 0x8c) #define CRL_APB_DBG_LPD_CTRL (CRL_APB_CLK_BASE + 0x90) #define CRL_APB_NAND_REF_CTRL (CRL_APB_CLK_BASE + 0x94) #define CRL_APB_ADMA_REF_CTRL (CRL_APB_CLK_BASE + 0x98) #define CRL_APB_PL0_REF_CTRL (CRL_APB_CLK_BASE + 0xa0) #define CRL_APB_PL1_REF_CTRL (CRL_APB_CLK_BASE + 0xa4) #define CRL_APB_PL2_REF_CTRL (CRL_APB_CLK_BASE + 0xa8) #define CRL_APB_PL3_REF_CTRL (CRL_APB_CLK_BASE + 0xac) #define CRL_APB_PL0_THR_CNT (CRL_APB_CLK_BASE + 0xb4) #define CRL_APB_PL1_THR_CNT (CRL_APB_CLK_BASE + 0xbc) #define CRL_APB_PL2_THR_CNT (CRL_APB_CLK_BASE + 0xc4) #define CRL_APB_PL3_THR_CNT (CRL_APB_CLK_BASE + 0xdc) #define CRL_APB_GEM_TSU_REF_CTRL (CRL_APB_CLK_BASE + 0xe0) #define CRL_APB_DLL_REF_CTRL (CRL_APB_CLK_BASE + 0xe4) #define CRL_APB_AMS_REF_CTRL (CRL_APB_CLK_BASE + 0xe8) #define CRL_APB_I2C0_REF_CTRL (CRL_APB_CLK_BASE + 0x100) #define CRL_APB_I2C1_REF_CTRL (CRL_APB_CLK_BASE + 0x104) #define CRL_APB_TIMESTAMP_REF_CTRL (CRL_APB_CLK_BASE + 0x108) #define IOU_SLCR_GEM_CLK_CTRL (IOU_SLCR_BASEADDR + 0x308) #define IOU_SLCR_CAN_MIO_CTRL (IOU_SLCR_BASEADDR + 0x304) #define FPD_SLCR_WDT_CLK_SEL (FPD_SLCR_BASEADDR + 0x100) /* Global general storage register base address */ #define GGS_BASEADDR (0xFFD80030U) #define GGS_NUM_REGS U(4) /* Persistent global general storage register base address */ #define PGGS_BASEADDR (0xFFD80050U) #define PGGS_NUM_REGS U(4) /* Warm restart boot health status register and mask */ #define PM_BOOT_HEALTH_STATUS_REG (GGS_BASEADDR + U(0x10)) #define PM_BOOT_HEALTH_STATUS_MASK U(0x01) /*AFI registers */ #define AFIFM6_WRCTRL U(13) #define FABRIC_WIDTH U(3) #endif /* ZYNQMP_DEF_H */ trusted-firmware-a-2.2/plat/xilinx/zynqmp/ipi_mailbox_service/000077500000000000000000000000001355360272700247365ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c000066400000000000000000000070541355360272700302570ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * Top-level SMC handler for ZynqMP IPI Mailbox doorbell functions. */ #include #include #include #include #include #include #include #include #include #include "ipi_mailbox_svc.h" #include "../../../services/spd/trusty/smcall.h" /********************************************************************* * Macros definitions ********************************************************************/ /* IPI SMC calls macros: */ #define IPI_SMC_OPEN_IRQ_MASK 0x00000001U /* IRQ enable bit in IPI * open SMC call */ #define IPI_SMC_NOTIFY_BLOCK_MASK 0x00000001U /* Flag to indicate if * IPI notification needs * to be blocking. */ #define IPI_SMC_ENQUIRY_DIRQ_MASK 0x00000001U /* Flag to indicate if * notification interrupt * to be disabled. */ #define IPI_SMC_ACK_EIRQ_MASK 0x00000001U /* Flag to indicate if * notification interrupt * to be enable. */ #define UNSIGNED32_MASK 0xFFFFFFFFU /* 32bit mask */ /** * ipi_smc_handler() - SMC handler for IPI SMC calls * * @smc_fid - Function identifier * @x1 - x4 - Arguments * @cookie - Unused * @handler - Pointer to caller's context structure * * @return - Unused * * Determines that smc_fid is valid and supported PM SMC Function ID from the * list of pm_api_ids, otherwise completes the request with * the unknown SMC Function ID * * The SMC calls for PM service are forwarded from SIP Service SMC handler * function with rt_svc_handle signature */ uint64_t ipi_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, void *cookie, void *handle, uint64_t flags) { int ret; uint32_t ipi_local_id; uint32_t ipi_remote_id; unsigned int is_secure; ipi_local_id = x1 & UNSIGNED32_MASK; ipi_remote_id = x2 & UNSIGNED32_MASK; if (SMC_ENTITY(smc_fid) >= SMC_ENTITY_TRUSTED_APP) is_secure = 1; else is_secure = 0; /* Validate IPI mailbox access */ ret = ipi_mb_validate(ipi_local_id, ipi_remote_id, is_secure); if (ret) SMC_RET1(handle, ret); switch (SMC_FUNCTION(smc_fid)) { case IPI_MAILBOX_OPEN: ipi_mb_open(ipi_local_id, ipi_remote_id); SMC_RET1(handle, 0); case IPI_MAILBOX_RELEASE: ipi_mb_release(ipi_local_id, ipi_remote_id); SMC_RET1(handle, 0); case IPI_MAILBOX_STATUS_ENQUIRY: { int disable_irq; disable_irq = (x3 & IPI_SMC_ENQUIRY_DIRQ_MASK) ? 1 : 0; ret = ipi_mb_enquire_status(ipi_local_id, ipi_remote_id); if ((ret & IPI_MB_STATUS_RECV_PENDING) && disable_irq) ipi_mb_disable_irq(ipi_local_id, ipi_remote_id); SMC_RET1(handle, ret); } case IPI_MAILBOX_NOTIFY: { uint32_t is_blocking; is_blocking = (x3 & IPI_SMC_NOTIFY_BLOCK_MASK) ? 1 : 0; ipi_mb_notify(ipi_local_id, ipi_remote_id, is_blocking); SMC_RET1(handle, 0); } case IPI_MAILBOX_ACK: { int enable_irq; enable_irq = (x3 & IPI_SMC_ACK_EIRQ_MASK) ? 1 : 0; ipi_mb_ack(ipi_local_id, ipi_remote_id); if (enable_irq) ipi_mb_enable_irq(ipi_local_id, ipi_remote_id); SMC_RET1(handle, 0); } case IPI_MAILBOX_ENABLE_IRQ: ipi_mb_enable_irq(ipi_local_id, ipi_remote_id); SMC_RET1(handle, 0); case IPI_MAILBOX_DISABLE_IRQ: ipi_mb_disable_irq(ipi_local_id, ipi_remote_id); SMC_RET1(handle, 0); default: WARN("Unimplemented IPI service call: 0x%x\n", smc_fid); SMC_RET1(handle, SMC_UNK); } } trusted-firmware-a-2.2/plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.h000066400000000000000000000021001355360272700302470ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* ZynqMP IPI mailbox doorbell service enums and defines */ #ifndef IPI_MAILBOX_SVC_H #define IPI_MAILBOX_SVC_H #include /********************************************************************* * Enum definitions ********************************************************************/ /* IPI SMC function numbers enum definition */ enum ipi_api_id { /* IPI mailbox operations functions: */ IPI_MAILBOX_OPEN = 0x1000, IPI_MAILBOX_RELEASE, IPI_MAILBOX_STATUS_ENQUIRY, IPI_MAILBOX_NOTIFY, IPI_MAILBOX_ACK, IPI_MAILBOX_ENABLE_IRQ, IPI_MAILBOX_DISABLE_IRQ }; /********************************************************************* * IPI mailbox service APIs declarations ********************************************************************/ /* IPI SMC handler */ uint64_t ipi_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, void *cookie, void *handle, uint64_t flags); #endif /* IPI_MAILBOX_SVC_H */ trusted-firmware-a-2.2/plat/xilinx/zynqmp/plat_psci.c000066400000000000000000000145521355360272700230530ustar00rootroot00000000000000/* * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "pm_api_sys.h" #include "pm_client.h" uintptr_t zynqmp_sec_entry; void zynqmp_cpu_standby(plat_local_state_t cpu_state) { VERBOSE("%s: cpu_state: 0x%x\n", __func__, cpu_state); dsb(); wfi(); } static int zynqmp_pwr_domain_on(u_register_t mpidr) { unsigned int cpu_id = plat_core_pos_by_mpidr(mpidr); const struct pm_proc *proc; VERBOSE("%s: mpidr: 0x%lx\n", __func__, mpidr); if (cpu_id == -1) return PSCI_E_INTERN_FAIL; proc = pm_get_proc(cpu_id); /* Clear power down request */ pm_client_wakeup(proc); /* Send request to PMU to wake up selected APU CPU core */ pm_req_wakeup(proc->node_id, 1, zynqmp_sec_entry, REQ_ACK_BLOCKING); return PSCI_E_SUCCESS; } static void zynqmp_pwr_domain_off(const psci_power_state_t *target_state) { unsigned int cpu_id = plat_my_core_pos(); const struct pm_proc *proc = pm_get_proc(cpu_id); for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); /* Prevent interrupts from spuriously waking up this cpu */ gicv2_cpuif_disable(); /* * Send request to PMU to power down the appropriate APU CPU * core. * According to PSCI specification, CPU_off function does not * have resume address and CPU core can only be woken up * invoking CPU_on function, during which resume address will * be set. */ pm_self_suspend(proc->node_id, MAX_LATENCY, PM_STATE_CPU_IDLE, 0); } static void zynqmp_pwr_domain_suspend(const psci_power_state_t *target_state) { unsigned int state; unsigned int cpu_id = plat_my_core_pos(); const struct pm_proc *proc = pm_get_proc(cpu_id); for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); state = target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE ? PM_STATE_SUSPEND_TO_RAM : PM_STATE_CPU_IDLE; /* Send request to PMU to suspend this core */ pm_self_suspend(proc->node_id, MAX_LATENCY, state, zynqmp_sec_entry); /* APU is to be turned off */ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) { /* disable coherency */ plat_arm_interconnect_exit_coherency(); } } static void zynqmp_pwr_domain_on_finish(const psci_power_state_t *target_state) { for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); gicv2_cpuif_enable(); gicv2_pcpu_distif_init(); } static void zynqmp_pwr_domain_suspend_finish(const psci_power_state_t *target_state) { unsigned int cpu_id = plat_my_core_pos(); const struct pm_proc *proc = pm_get_proc(cpu_id); for (size_t i = 0; i <= PLAT_MAX_PWR_LVL; i++) VERBOSE("%s: target_state->pwr_domain_state[%lu]=%x\n", __func__, i, target_state->pwr_domain_state[i]); /* Clear the APU power control register for this cpu */ pm_client_wakeup(proc); /* enable coherency */ plat_arm_interconnect_enter_coherency(); /* APU was turned off */ if (target_state->pwr_domain_state[1] > PLAT_MAX_RET_STATE) { plat_arm_gic_init(); } else { gicv2_cpuif_enable(); gicv2_pcpu_distif_init(); } } /******************************************************************************* * ZynqMP handlers to shutdown/reboot the system ******************************************************************************/ static void __dead2 zynqmp_system_off(void) { /* disable coherency */ plat_arm_interconnect_exit_coherency(); /* Send the power down request to the PMU */ pm_system_shutdown(PMF_SHUTDOWN_TYPE_SHUTDOWN, pm_get_shutdown_scope()); while (1) wfi(); } static void __dead2 zynqmp_system_reset(void) { /* disable coherency */ plat_arm_interconnect_exit_coherency(); /* Send the system reset request to the PMU */ pm_system_shutdown(PMF_SHUTDOWN_TYPE_RESET, pm_get_shutdown_scope()); while (1) wfi(); } int zynqmp_validate_power_state(unsigned int power_state, psci_power_state_t *req_state) { VERBOSE("%s: power_state: 0x%x\n", __func__, power_state); int pstate = psci_get_pstate_type(power_state); assert(req_state); /* Sanity check the requested state */ if (pstate == PSTATE_TYPE_STANDBY) req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE; else req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_OFF_STATE; /* We expect the 'state id' to be zero */ if (psci_get_pstate_id(power_state)) return PSCI_E_INVALID_PARAMS; return PSCI_E_SUCCESS; } int zynqmp_validate_ns_entrypoint(unsigned long ns_entrypoint) { VERBOSE("%s: ns_entrypoint: 0x%lx\n", __func__, ns_entrypoint); /* FIXME: Actually validate */ return PSCI_E_SUCCESS; } void zynqmp_get_sys_suspend_power_state(psci_power_state_t *req_state) { req_state->pwr_domain_state[PSCI_CPU_PWR_LVL] = PLAT_MAX_OFF_STATE; req_state->pwr_domain_state[1] = PLAT_MAX_OFF_STATE; } /******************************************************************************* * Export the platform handlers to enable psci to invoke them ******************************************************************************/ static const struct plat_psci_ops zynqmp_psci_ops = { .cpu_standby = zynqmp_cpu_standby, .pwr_domain_on = zynqmp_pwr_domain_on, .pwr_domain_off = zynqmp_pwr_domain_off, .pwr_domain_suspend = zynqmp_pwr_domain_suspend, .pwr_domain_on_finish = zynqmp_pwr_domain_on_finish, .pwr_domain_suspend_finish = zynqmp_pwr_domain_suspend_finish, .system_off = zynqmp_system_off, .system_reset = zynqmp_system_reset, .validate_power_state = zynqmp_validate_power_state, .validate_ns_entrypoint = zynqmp_validate_ns_entrypoint, .get_sys_suspend_power_state = zynqmp_get_sys_suspend_power_state, }; /******************************************************************************* * Export the platform specific power ops. ******************************************************************************/ int plat_setup_psci_ops(uintptr_t sec_entrypoint, const struct plat_psci_ops **psci_ops) { zynqmp_sec_entry = sec_entrypoint; *psci_ops = &zynqmp_psci_ops; return 0; } trusted-firmware-a-2.2/plat/xilinx/zynqmp/plat_startup.c000066400000000000000000000170431355360272700236150ustar00rootroot00000000000000/* * Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "zynqmp_def.h" /* * ATFHandoffParams * Parameter bitfield encoding * ----------------------------------------------------------------------------- * Exec State 0 0 -> Aarch64, 1-> Aarch32 * endianness 1 0 -> LE, 1 -> BE * secure (TZ) 2 0 -> Non secure, 1 -> secure * EL 3:4 00 -> EL0, 01 -> EL1, 10 -> EL2, 11 -> EL3 * CPU# 5:6 00 -> A53_0, 01 -> A53_1, 10 -> A53_2, 11 -> A53_3 */ #define FSBL_FLAGS_ESTATE_SHIFT 0 #define FSBL_FLAGS_ESTATE_MASK (1 << FSBL_FLAGS_ESTATE_SHIFT) #define FSBL_FLAGS_ESTATE_A64 0 #define FSBL_FLAGS_ESTATE_A32 1 #define FSBL_FLAGS_ENDIAN_SHIFT 1 #define FSBL_FLAGS_ENDIAN_MASK (1 << FSBL_FLAGS_ENDIAN_SHIFT) #define FSBL_FLAGS_ENDIAN_LE 0 #define FSBL_FLAGS_ENDIAN_BE 1 #define FSBL_FLAGS_TZ_SHIFT 2 #define FSBL_FLAGS_TZ_MASK (1 << FSBL_FLAGS_TZ_SHIFT) #define FSBL_FLAGS_NON_SECURE 0 #define FSBL_FLAGS_SECURE 1 #define FSBL_FLAGS_EL_SHIFT 3 #define FSBL_FLAGS_EL_MASK (3 << FSBL_FLAGS_EL_SHIFT) #define FSBL_FLAGS_EL0 0 #define FSBL_FLAGS_EL1 1 #define FSBL_FLAGS_EL2 2 #define FSBL_FLAGS_EL3 3 #define FSBL_FLAGS_CPU_SHIFT 5 #define FSBL_FLAGS_CPU_MASK (3 << FSBL_FLAGS_CPU_SHIFT) #define FSBL_FLAGS_A53_0 0 #define FSBL_FLAGS_A53_1 1 #define FSBL_FLAGS_A53_2 2 #define FSBL_FLAGS_A53_3 3 #define FSBL_MAX_PARTITIONS 8 /* Structure corresponding to each partition entry */ struct xfsbl_partition { uint64_t entry_point; uint64_t flags; }; /* Structure for handoff parameters to ARM Trusted Firmware (ATF) */ struct xfsbl_atf_handoff_params { uint8_t magic[4]; uint32_t num_entries; struct xfsbl_partition partition[FSBL_MAX_PARTITIONS]; }; /** * @partition: Pointer to partition struct * * Get the target CPU for @partition. * * Return: FSBL_FLAGS_A53_0, FSBL_FLAGS_A53_1, FSBL_FLAGS_A53_2 or FSBL_FLAGS_A53_3 */ static int get_fsbl_cpu(const struct xfsbl_partition *partition) { uint64_t flags = partition->flags & FSBL_FLAGS_CPU_MASK; return flags >> FSBL_FLAGS_CPU_SHIFT; } /** * @partition: Pointer to partition struct * * Get the target exception level for @partition. * * Return: FSBL_FLAGS_EL0, FSBL_FLAGS_EL1, FSBL_FLAGS_EL2 or FSBL_FLAGS_EL3 */ static int get_fsbl_el(const struct xfsbl_partition *partition) { uint64_t flags = partition->flags & FSBL_FLAGS_EL_MASK; return flags >> FSBL_FLAGS_EL_SHIFT; } /** * @partition: Pointer to partition struct * * Get the target security state for @partition. * * Return: FSBL_FLAGS_NON_SECURE or FSBL_FLAGS_SECURE */ static int get_fsbl_ss(const struct xfsbl_partition *partition) { uint64_t flags = partition->flags & FSBL_FLAGS_TZ_MASK; return flags >> FSBL_FLAGS_TZ_SHIFT; } /** * @partition: Pointer to partition struct * * Get the target endianness for @partition. * * Return: SPSR_E_LITTLE or SPSR_E_BIG */ static int get_fsbl_endian(const struct xfsbl_partition *partition) { uint64_t flags = partition->flags & FSBL_FLAGS_ENDIAN_MASK; flags >>= FSBL_FLAGS_ENDIAN_SHIFT; if (flags == FSBL_FLAGS_ENDIAN_BE) return SPSR_E_BIG; else return SPSR_E_LITTLE; } /** * @partition: Pointer to partition struct * * Get the target execution state for @partition. * * Return: FSBL_FLAGS_ESTATE_A32 or FSBL_FLAGS_ESTATE_A64 */ static int get_fsbl_estate(const struct xfsbl_partition *partition) { uint64_t flags = partition->flags & FSBL_FLAGS_ESTATE_MASK; return flags >> FSBL_FLAGS_ESTATE_SHIFT; } /** * Populates the bl32 and bl33 image info structures * @bl32: BL32 image info structure * @bl33: BL33 image info structure * * Process the handoff paramters from the FSBL and populate the BL32 and BL33 * image info structures accordingly. * * Return: Return the status of the handoff. The value will be from the * fsbl_handoff enum. */ enum fsbl_handoff fsbl_atf_handover(entry_point_info_t *bl32, entry_point_info_t *bl33) { uint64_t atf_handoff_addr; const struct xfsbl_atf_handoff_params *ATFHandoffParams; atf_handoff_addr = mmio_read_32(PMU_GLOBAL_GEN_STORAGE6); assert((atf_handoff_addr < BL31_BASE) || (atf_handoff_addr > (uint64_t)&__BL31_END__)); if (!atf_handoff_addr) { WARN("BL31: No ATF handoff structure passed\n"); return FSBL_HANDOFF_NO_STRUCT; } ATFHandoffParams = (struct xfsbl_atf_handoff_params *)atf_handoff_addr; if ((ATFHandoffParams->magic[0] != 'X') || (ATFHandoffParams->magic[1] != 'L') || (ATFHandoffParams->magic[2] != 'N') || (ATFHandoffParams->magic[3] != 'X')) { ERROR("BL31: invalid ATF handoff structure at %llx\n", atf_handoff_addr); return FSBL_HANDOFF_INVAL_STRUCT; } VERBOSE("BL31: ATF handoff params at:0x%llx, entries:%u\n", atf_handoff_addr, ATFHandoffParams->num_entries); if (ATFHandoffParams->num_entries > FSBL_MAX_PARTITIONS) { ERROR("BL31: ATF handoff params: too many partitions (%u/%u)\n", ATFHandoffParams->num_entries, FSBL_MAX_PARTITIONS); return FSBL_HANDOFF_TOO_MANY_PARTS; } /* * we loop over all passed entries but only populate two image structs * (bl32, bl33). I.e. the last applicable images in the handoff * structure will be used for the hand off */ for (size_t i = 0; i < ATFHandoffParams->num_entries; i++) { entry_point_info_t *image; int target_estate, target_secure; int target_cpu, target_endianness, target_el; VERBOSE("BL31: %zd: entry:0x%llx, flags:0x%llx\n", i, ATFHandoffParams->partition[i].entry_point, ATFHandoffParams->partition[i].flags); target_cpu = get_fsbl_cpu(&ATFHandoffParams->partition[i]); if (target_cpu != FSBL_FLAGS_A53_0) { WARN("BL31: invalid target CPU (%i)\n", target_cpu); continue; } target_el = get_fsbl_el(&ATFHandoffParams->partition[i]); if ((target_el == FSBL_FLAGS_EL3) || (target_el == FSBL_FLAGS_EL0)) { WARN("BL31: invalid exception level (%i)\n", target_el); continue; } target_secure = get_fsbl_ss(&ATFHandoffParams->partition[i]); if (target_secure == FSBL_FLAGS_SECURE && target_el == FSBL_FLAGS_EL2) { WARN("BL31: invalid security state (%i) for exception level (%i)\n", target_secure, target_el); continue; } target_estate = get_fsbl_estate(&ATFHandoffParams->partition[i]); target_endianness = get_fsbl_endian(&ATFHandoffParams->partition[i]); if (target_secure == FSBL_FLAGS_SECURE) { image = bl32; if (target_estate == FSBL_FLAGS_ESTATE_A32) bl32->spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM, target_endianness, DISABLE_ALL_EXCEPTIONS); else bl32->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); } else { image = bl33; if (target_estate == FSBL_FLAGS_ESTATE_A32) { if (target_el == FSBL_FLAGS_EL2) target_el = MODE32_hyp; else target_el = MODE32_sys; bl33->spsr = SPSR_MODE32(target_el, SPSR_T_ARM, target_endianness, DISABLE_ALL_EXCEPTIONS); } else { if (target_el == FSBL_FLAGS_EL2) target_el = MODE_EL2; else target_el = MODE_EL1; bl33->spsr = SPSR_64(target_el, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); } } VERBOSE("Setting up %s entry point to:%llx, el:%x\n", target_secure == FSBL_FLAGS_SECURE ? "BL32" : "BL33", ATFHandoffParams->partition[i].entry_point, target_el); image->pc = ATFHandoffParams->partition[i].entry_point; if (target_endianness == SPSR_E_BIG) EP_SET_EE(image->h.attr, EP_EE_BIG); else EP_SET_EE(image->h.attr, EP_EE_LITTLE); } return FSBL_HANDOFF_SUCCESS; } trusted-firmware-a-2.2/plat/xilinx/zynqmp/plat_topology.c000066400000000000000000000004531355360272700237640ustar00rootroot00000000000000/* * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ static const unsigned char plat_power_domain_tree_desc[] = {1, 4}; const unsigned char *plat_get_power_domain_tree_desc(void) { return plat_power_domain_tree_desc; } trusted-firmware-a-2.2/plat/xilinx/zynqmp/plat_zynqmp.c000066400000000000000000000006131355360272700234440ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include int plat_core_pos_by_mpidr(u_register_t mpidr) { if (mpidr & MPIDR_CLUSTER_MASK) return -1; if ((mpidr & MPIDR_CPU_MASK) >= PLATFORM_CORE_COUNT) return -1; return zynqmp_calc_core_pos(mpidr); } trusted-firmware-a-2.2/plat/xilinx/zynqmp/platform.mk000066400000000000000000000055671355360272700231140ustar00rootroot00000000000000# # Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause override ERRATA_A53_855873 := 1 override PROGRAMMABLE_RESET_ADDRESS := 1 PSCI_EXTENDED_STATE_ID := 1 A53_DISABLE_NON_TEMPORAL_HINT := 0 SEPARATE_CODE_AND_RODATA := 1 ZYNQMP_WDT_RESTART := 0 override RESET_TO_BL31 := 1 # Do not enable SVE ENABLE_SVE_FOR_NS := 0 WORKAROUND_CVE_2017_5715 := 0 ifdef ZYNQMP_ATF_MEM_BASE $(eval $(call add_define,ZYNQMP_ATF_MEM_BASE)) ifndef ZYNQMP_ATF_MEM_SIZE $(error "ZYNQMP_ATF_BASE defined without ZYNQMP_ATF_SIZE") endif $(eval $(call add_define,ZYNQMP_ATF_MEM_SIZE)) ifdef ZYNQMP_ATF_MEM_PROGBITS_SIZE $(eval $(call add_define,ZYNQMP_ATF_MEM_PROGBITS_SIZE)) endif endif ifdef ZYNQMP_BL32_MEM_BASE $(eval $(call add_define,ZYNQMP_BL32_MEM_BASE)) ifndef ZYNQMP_BL32_MEM_SIZE $(error "ZYNQMP_BL32_BASE defined without ZYNQMP_BL32_SIZE") endif $(eval $(call add_define,ZYNQMP_BL32_MEM_SIZE)) endif ZYNQMP_CONSOLE ?= cadence $(eval $(call add_define_val,ZYNQMP_CONSOLE,ZYNQMP_CONSOLE_ID_${ZYNQMP_CONSOLE})) ifdef ZYNQMP_WDT_RESTART $(eval $(call add_define,ZYNQMP_WDT_RESTART)) endif PLAT_INCLUDES := -Iinclude/plat/arm/common/aarch64/ \ -Iplat/xilinx/common/include/ \ -Iplat/xilinx/zynqmp/include/ \ -Iplat/xilinx/zynqmp/pm_service/ \ -Iplat/xilinx/zynqmp/ipi_mailbox_service/ PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \ lib/xlat_tables/aarch64/xlat_tables.c \ drivers/delay_timer/delay_timer.c \ drivers/delay_timer/generic_delay_timer.c \ drivers/arm/gic/common/gic_common.c \ drivers/arm/gic/v2/gicv2_main.c \ drivers/arm/gic/v2/gicv2_helpers.c \ drivers/cadence/uart/aarch64/cdns_console.S \ plat/arm/common/arm_cci.c \ plat/arm/common/arm_common.c \ plat/arm/common/arm_gicv2.c \ plat/common/plat_gicv2.c \ plat/xilinx/common/ipi.c \ plat/xilinx/zynqmp/zynqmp_ipi.c \ plat/xilinx/zynqmp/aarch64/zynqmp_helpers.S \ plat/xilinx/zynqmp/aarch64/zynqmp_common.c BL31_SOURCES += drivers/arm/cci/cci.c \ lib/cpus/aarch64/aem_generic.S \ lib/cpus/aarch64/cortex_a53.S \ plat/common/plat_psci_common.c \ plat/xilinx/common/pm_service/pm_ipi.c \ plat/xilinx/zynqmp/bl31_zynqmp_setup.c \ plat/xilinx/zynqmp/plat_psci.c \ plat/xilinx/zynqmp/plat_zynqmp.c \ plat/xilinx/zynqmp/plat_startup.c \ plat/xilinx/zynqmp/plat_topology.c \ plat/xilinx/zynqmp/sip_svc_setup.c \ plat/xilinx/zynqmp/pm_service/pm_svc_main.c \ plat/xilinx/zynqmp/pm_service/pm_api_sys.c \ plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c \ plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c \ plat/xilinx/zynqmp/pm_service/pm_api_clock.c \ plat/xilinx/zynqmp/pm_service/pm_client.c \ plat/xilinx/zynqmp/ipi_mailbox_service/ipi_mailbox_svc.c trusted-firmware-a-2.2/plat/xilinx/zynqmp/pm_service/000077500000000000000000000000001355360272700230565ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/xilinx/zynqmp/pm_service/pm_api_clock.c000066400000000000000000002132771355360272700256560ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * ZynqMP system level PM-API functions for clock control. */ #include #include #include #include #include #include "pm_api_clock.h" #include "pm_api_sys.h" #include "pm_client.h" #include "pm_common.h" #include "pm_ipi.h" #define CLK_NODE_MAX U(6) #define CLK_PARENTS_ID_LEN U(16) #define CLK_TOPOLOGY_NODE_OFFSET U(16) #define CLK_TOPOLOGY_PAYLOAD_LEN U(12) #define CLK_PARENTS_PAYLOAD_LEN U(12) #define CLK_TYPE_SHIFT U(2) #define CLK_CLKFLAGS_SHIFT U(8) #define CLK_TYPEFLAGS_SHIFT U(24) #define CLK_EXTERNAL_PARENT (PARENT_CLK_EXTERNAL << CLK_PARENTS_ID_LEN) #define NA_MULT U(0) #define NA_DIV U(0) #define NA_SHIFT U(0) #define NA_WIDTH U(0) #define NA_CLK_FLAGS U(0) #define NA_TYPE_FLAGS U(0) /* PLL nodes related definitions */ #define PLL_PRESRC_MUX_SHIFT U(20) #define PLL_PRESRC_MUX_WIDTH U(3) #define PLL_POSTSRC_MUX_SHIFT U(24) #define PLL_POSTSRC_MUX_WIDTH U(3) #define PLL_DIV2_MUX_SHIFT U(16) #define PLL_DIV2_MUX_WIDTH U(1) #define PLL_BYPASS_MUX_SHIFT U(3) #define PLL_BYPASS_MUX_WIDTH U(1) /* Peripheral nodes related definitions */ /* Peripheral Clocks */ #define PERIPH_MUX_SHIFT U(0) #define PERIPH_MUX_WIDTH U(3) #define PERIPH_DIV1_SHIFT U(8) #define PERIPH_DIV1_WIDTH U(6) #define PERIPH_DIV2_SHIFT U(16) #define PERIPH_DIV2_WIDTH U(6) #define PERIPH_GATE_SHIFT U(24) #define PERIPH_GATE_WIDTH U(1) #define USB_GATE_SHIFT U(25) /* External clock related definitions */ #define EXT_CLK_MIO_DATA(mio) \ [EXT_CLK_INDEX(EXT_CLK_MIO##mio)] = { \ .name = "mio_clk_"#mio, \ } #define EXT_CLK_INDEX(n) (n - CLK_MAX_OUTPUT_CLK) /* Clock control related definitions */ #define BIT_MASK(x, y) (((1U << (y)) - 1) << (x)) #define ISPLL(id) (id == CLK_APLL_INT || \ id == CLK_DPLL_INT || \ id == CLK_VPLL_INT || \ id == CLK_IOPLL_INT || \ id == CLK_RPLL_INT) #define PLLCTRL_BP_MASK BIT(3) #define PLLCTRL_RESET_MASK U(1) #define PLL_FRAC_OFFSET U(8) #define PLL_FRAC_MODE U(1) #define PLL_INT_MODE U(0) #define PLL_FRAC_MODE_MASK U(0x80000000) #define PLL_FRAC_MODE_SHIFT U(31) #define PLL_FRAC_DATA_MASK U(0xFFFF) #define PLL_FRAC_DATA_SHIFT U(0) #define PLL_FBDIV_MASK U(0x7F00) #define PLL_FBDIV_WIDTH U(7) #define PLL_FBDIV_SHIFT U(8) #define CLK_PLL_RESET_ASSERT U(1) #define CLK_PLL_RESET_RELEASE U(2) #define CLK_PLL_RESET_PULSE (CLK_PLL_RESET_ASSERT | CLK_PLL_RESET_RELEASE) /* Common topology definitions */ #define GENERIC_MUX \ { \ .type = TYPE_MUX, \ .offset = PERIPH_MUX_SHIFT, \ .width = PERIPH_MUX_WIDTH, \ .clkflags = CLK_SET_RATE_NO_REPARENT | \ CLK_IS_BASIC, \ .typeflags = NA_TYPE_FLAGS, \ .mult = NA_MULT, \ .div = NA_DIV, \ } #define IGNORE_UNUSED_MUX \ { \ .type = TYPE_MUX, \ .offset = PERIPH_MUX_SHIFT, \ .width = PERIPH_MUX_WIDTH, \ .clkflags = CLK_IGNORE_UNUSED | \ CLK_SET_RATE_NO_REPARENT | \ CLK_IS_BASIC, \ .typeflags = NA_TYPE_FLAGS, \ .mult = NA_MULT, \ .div = NA_DIV, \ } #define GENERIC_DIV(id) \ { \ .type = TYPE_DIV##id, \ .offset = PERIPH_DIV##id##_SHIFT, \ .width = PERIPH_DIV##id##_WIDTH, \ .clkflags = CLK_SET_RATE_NO_REPARENT | \ CLK_IS_BASIC, \ .typeflags = CLK_DIVIDER_ONE_BASED | \ CLK_DIVIDER_ALLOW_ZERO, \ .mult = NA_MULT, \ .div = NA_DIV, \ } #define IGNORE_UNUSED_DIV(id) \ { \ .type = TYPE_DIV##id, \ .offset = PERIPH_DIV##id##_SHIFT, \ .width = PERIPH_DIV##id##_WIDTH, \ .clkflags = CLK_IGNORE_UNUSED | \ CLK_SET_RATE_NO_REPARENT | \ CLK_IS_BASIC, \ .typeflags = CLK_DIVIDER_ONE_BASED | \ CLK_DIVIDER_ALLOW_ZERO, \ .mult = NA_MULT, \ .div = NA_DIV, \ } #define GENERIC_GATE \ { \ .type = TYPE_GATE, \ .offset = PERIPH_GATE_SHIFT, \ .width = PERIPH_GATE_WIDTH, \ .clkflags = CLK_SET_RATE_PARENT | \ CLK_SET_RATE_GATE | \ CLK_IS_BASIC, \ .typeflags = NA_TYPE_FLAGS, \ .mult = NA_MULT, \ .div = NA_DIV, \ } #define IGNORE_UNUSED_GATE \ { \ .type = TYPE_GATE, \ .offset = PERIPH_GATE_SHIFT, \ .width = PERIPH_GATE_WIDTH, \ .clkflags = CLK_SET_RATE_PARENT | \ CLK_IGNORE_UNUSED | \ CLK_IS_BASIC, \ .typeflags = NA_TYPE_FLAGS, \ .mult = NA_MULT, \ .div = NA_DIV, \ } /** * struct pm_clock_node - Clock topology node information * @type: Topology type (mux/div1/div2/gate/pll/fixed factor) * @offset: Offset in control register * @width: Width of the specific type in control register * @clkflags: Clk specific flags * @typeflags: Type specific flags * @mult: Multiplier for fixed factor * @div: Divisor for fixed factor */ struct pm_clock_node { uint16_t clkflags; uint16_t typeflags; uint8_t type; uint8_t offset; uint8_t width; uint8_t mult:4; uint8_t div:4; }; /** * struct pm_clock - Clock structure * @name: Clock name * @control_reg: Control register address * @status_reg: Status register address * @parents: Parents for first clock node. Lower byte indicates parent * clock id and upper byte indicate flags for that id. * pm_clock_node: Clock nodes */ struct pm_clock { char name[CLK_NAME_LEN]; uint8_t num_nodes; unsigned int control_reg; unsigned int status_reg; int32_t (*parents)[]; struct pm_clock_node(*nodes)[]; }; /** * struct pm_clock - Clock structure * @name: Clock name */ struct pm_ext_clock { char name[CLK_NAME_LEN]; }; /* PLL Clocks */ static struct pm_clock_node generic_pll_nodes[] = { { .type = TYPE_PLL, .offset = NA_SHIFT, .width = NA_WIDTH, .clkflags = CLK_SET_RATE_NO_REPARENT, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node ignore_unused_pll_nodes[] = { { .type = TYPE_PLL, .offset = NA_SHIFT, .width = NA_WIDTH, .clkflags = CLK_IGNORE_UNUSED | CLK_SET_RATE_NO_REPARENT, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node generic_pll_pre_src_nodes[] = { { .type = TYPE_MUX, .offset = PLL_PRESRC_MUX_SHIFT, .width = PLL_PRESRC_MUX_WIDTH, .clkflags = CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node generic_pll_half_nodes[] = { { .type = TYPE_FIXEDFACTOR, .offset = NA_SHIFT, .width = NA_WIDTH, .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, .typeflags = NA_TYPE_FLAGS, .mult = 1, .div = 2, }, }; static struct pm_clock_node generic_pll_int_nodes[] = { { .type = TYPE_MUX, .offset = PLL_DIV2_MUX_SHIFT, .width = PLL_DIV2_MUX_WIDTH, .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node generic_pll_post_src_nodes[] = { { .type = TYPE_MUX, .offset = PLL_POSTSRC_MUX_SHIFT, .width = PLL_POSTSRC_MUX_WIDTH, .clkflags = CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node generic_pll_system_nodes[] = { { .type = TYPE_MUX, .offset = PLL_BYPASS_MUX_SHIFT, .width = PLL_BYPASS_MUX_WIDTH, .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node acpu_nodes[] = { { .type = TYPE_MUX, .offset = PERIPH_MUX_SHIFT, .width = PERIPH_MUX_WIDTH, .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, { .type = TYPE_DIV1, .offset = PERIPH_DIV1_SHIFT, .width = PERIPH_DIV1_WIDTH, .clkflags = CLK_IS_BASIC, .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node generic_mux_div_nodes[] = { GENERIC_MUX, GENERIC_DIV(1), }; static struct pm_clock_node generic_mux_div_gate_nodes[] = { GENERIC_MUX, GENERIC_DIV(1), GENERIC_GATE, }; static struct pm_clock_node generic_mux_div_unused_gate_nodes[] = { GENERIC_MUX, GENERIC_DIV(1), IGNORE_UNUSED_GATE, }; static struct pm_clock_node generic_mux_div_div_gate_nodes[] = { GENERIC_MUX, GENERIC_DIV(1), GENERIC_DIV(2), GENERIC_GATE, }; static struct pm_clock_node dp_audio_video_ref_nodes[] = { { .type = TYPE_MUX, .offset = PERIPH_MUX_SHIFT, .width = PERIPH_MUX_WIDTH, .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT | CLK_FRAC | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, { .type = TYPE_DIV1, .offset = PERIPH_DIV1_SHIFT, .width = PERIPH_DIV1_WIDTH, .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT | CLK_FRAC | CLK_IS_BASIC, .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, .mult = NA_MULT, .div = NA_DIV, }, { .type = TYPE_DIV2, .offset = PERIPH_DIV2_SHIFT, .width = PERIPH_DIV2_WIDTH, .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT | CLK_FRAC | CLK_IS_BASIC, .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, .mult = NA_MULT, .div = NA_DIV, }, { .type = TYPE_GATE, .offset = PERIPH_GATE_SHIFT, .width = PERIPH_GATE_WIDTH, .clkflags = CLK_SET_RATE_PARENT | CLK_SET_RATE_GATE | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node usb_nodes[] = { GENERIC_MUX, GENERIC_DIV(1), GENERIC_DIV(2), { .type = TYPE_GATE, .offset = USB_GATE_SHIFT, .width = PERIPH_GATE_WIDTH, .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC | CLK_SET_RATE_GATE, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node generic_domain_crossing_nodes[] = { { .type = TYPE_DIV1, .offset = 8, .width = 6, .clkflags = CLK_IS_BASIC, .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node rpll_to_fpd_nodes[] = { { .type = TYPE_DIV1, .offset = 8, .width = 6, .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC, .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node acpu_half_nodes[] = { { .type = TYPE_FIXEDFACTOR, .offset = 0, .width = 1, .clkflags = 0, .typeflags = 0, .mult = 1, .div = 2, }, { .type = TYPE_GATE, .offset = 25, .width = PERIPH_GATE_WIDTH, .clkflags = CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node acpu_full_nodes[] = { { .type = TYPE_GATE, .offset = 24, .width = PERIPH_GATE_WIDTH, .clkflags = CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node wdt_nodes[] = { { .type = TYPE_MUX, .offset = 0, .width = 1, .clkflags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node ddr_nodes[] = { GENERIC_MUX, { .type = TYPE_DIV1, .offset = 8, .width = 6, .clkflags = CLK_IS_BASIC | CLK_IS_CRITICAL, .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node pl_nodes[] = { GENERIC_MUX, { .type = TYPE_DIV1, .offset = PERIPH_DIV1_SHIFT, .width = PERIPH_DIV1_WIDTH, .clkflags = CLK_IS_BASIC, .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, .mult = NA_MULT, .div = NA_DIV, }, { .type = TYPE_DIV2, .offset = PERIPH_DIV2_SHIFT, .width = PERIPH_DIV2_WIDTH, .clkflags = CLK_IS_BASIC | CLK_SET_RATE_PARENT, .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, .mult = NA_MULT, .div = NA_DIV, }, { .type = TYPE_GATE, .offset = PERIPH_GATE_SHIFT, .width = PERIPH_GATE_WIDTH, .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node gpu_pp0_nodes[] = { { .type = TYPE_GATE, .offset = 25, .width = PERIPH_GATE_WIDTH, .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node gpu_pp1_nodes[] = { { .type = TYPE_GATE, .offset = 26, .width = PERIPH_GATE_WIDTH, .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node gem_nodes[] = { GENERIC_MUX, { .type = TYPE_DIV1, .offset = 8, .width = 6, .clkflags = CLK_IS_BASIC, .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, .mult = NA_MULT, .div = NA_DIV, }, { .type = TYPE_DIV2, .offset = 16, .width = 6, .clkflags = CLK_IS_BASIC, .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, .mult = NA_MULT, .div = NA_DIV, }, { .type = TYPE_GATE, .offset = 25, .width = PERIPH_GATE_WIDTH, .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node gem0_tx_nodes[] = { { .type = TYPE_MUX, .offset = 1, .width = 1, .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, { .type = TYPE_GATE, .offset = 26, .width = PERIPH_GATE_WIDTH, .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node gem1_tx_nodes[] = { { .type = TYPE_MUX, .offset = 6, .width = 1, .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, { .type = TYPE_GATE, .offset = 26, .width = PERIPH_GATE_WIDTH, .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node gem2_tx_nodes[] = { { .type = TYPE_MUX, .offset = 11, .width = 1, .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, { .type = TYPE_GATE, .offset = 26, .width = PERIPH_GATE_WIDTH, .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node gem3_tx_nodes[] = { { .type = TYPE_MUX, .offset = 16, .width = 1, .clkflags = CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, { .type = TYPE_GATE, .offset = 26, .width = PERIPH_GATE_WIDTH, .clkflags = CLK_SET_RATE_PARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node gem_tsu_nodes[] = { { .type = TYPE_MUX, .offset = 20, .width = 2, .clkflags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node can0_mio_nodes[] = { { .type = TYPE_MUX, .offset = 0, .width = 7, .clkflags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node can1_mio_nodes[] = { { .type = TYPE_MUX, .offset = 15, .width = 1, .clkflags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node can0_nodes[] = { { .type = TYPE_MUX, .offset = 7, .width = 1, .clkflags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node can1_nodes[] = { { .type = TYPE_MUX, .offset = 22, .width = 1, .clkflags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node cpu_r5_core_nodes[] = { { .type = TYPE_GATE, .offset = 25, .width = PERIPH_GATE_WIDTH, .clkflags = CLK_IGNORE_UNUSED | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node dll_ref_nodes[] = { { .type = TYPE_MUX, .offset = 0, .width = 3, .clkflags = CLK_SET_RATE_PARENT | CLK_SET_RATE_NO_REPARENT | CLK_IS_BASIC, .typeflags = NA_TYPE_FLAGS, .mult = NA_MULT, .div = NA_DIV, }, }; static struct pm_clock_node timestamp_ref_nodes[] = { GENERIC_MUX, { .type = TYPE_DIV1, .offset = 8, .width = 6, .clkflags = CLK_IS_BASIC, .typeflags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO, .mult = NA_MULT, .div = NA_DIV, }, IGNORE_UNUSED_GATE, }; static int32_t can_mio_parents[] = { EXT_CLK_MIO0, EXT_CLK_MIO1, EXT_CLK_MIO2, EXT_CLK_MIO3, EXT_CLK_MIO4, EXT_CLK_MIO5, EXT_CLK_MIO6, EXT_CLK_MIO7, EXT_CLK_MIO8, EXT_CLK_MIO9, EXT_CLK_MIO10, EXT_CLK_MIO11, EXT_CLK_MIO12, EXT_CLK_MIO13, EXT_CLK_MIO14, EXT_CLK_MIO15, EXT_CLK_MIO16, EXT_CLK_MIO17, EXT_CLK_MIO18, EXT_CLK_MIO19, EXT_CLK_MIO20, EXT_CLK_MIO21, EXT_CLK_MIO22, EXT_CLK_MIO23, EXT_CLK_MIO24, EXT_CLK_MIO25, EXT_CLK_MIO26, EXT_CLK_MIO27, EXT_CLK_MIO28, EXT_CLK_MIO29, EXT_CLK_MIO30, EXT_CLK_MIO31, EXT_CLK_MIO32, EXT_CLK_MIO33, EXT_CLK_MIO34, EXT_CLK_MIO35, EXT_CLK_MIO36, EXT_CLK_MIO37, EXT_CLK_MIO38, EXT_CLK_MIO39, EXT_CLK_MIO40, EXT_CLK_MIO41, EXT_CLK_MIO42, EXT_CLK_MIO43, EXT_CLK_MIO44, EXT_CLK_MIO45, EXT_CLK_MIO46, EXT_CLK_MIO47, EXT_CLK_MIO48, EXT_CLK_MIO49, EXT_CLK_MIO50, EXT_CLK_MIO51, EXT_CLK_MIO52, EXT_CLK_MIO53, EXT_CLK_MIO54, EXT_CLK_MIO55, EXT_CLK_MIO56, EXT_CLK_MIO57, EXT_CLK_MIO58, EXT_CLK_MIO59, EXT_CLK_MIO60, EXT_CLK_MIO61, EXT_CLK_MIO62, EXT_CLK_MIO63, EXT_CLK_MIO64, EXT_CLK_MIO65, EXT_CLK_MIO66, EXT_CLK_MIO67, EXT_CLK_MIO68, EXT_CLK_MIO69, EXT_CLK_MIO70, EXT_CLK_MIO71, EXT_CLK_MIO72, EXT_CLK_MIO73, EXT_CLK_MIO74, EXT_CLK_MIO75, EXT_CLK_MIO76, EXT_CLK_MIO77, CLK_NA_PARENT }; /* Clock array containing clock informaton */ static struct pm_clock clocks[] = { [CLK_APLL_INT] = { .name = "apll_int", .control_reg = CRF_APB_APLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) {CLK_APLL_PRE_SRC, CLK_NA_PARENT}), .nodes = &ignore_unused_pll_nodes, .num_nodes = ARRAY_SIZE(ignore_unused_pll_nodes), }, [CLK_APLL_PRE_SRC] = { .name = "apll_pre_src", .control_reg = CRF_APB_APLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT, EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT, EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &generic_pll_pre_src_nodes, .num_nodes = ARRAY_SIZE(generic_pll_pre_src_nodes), }, [CLK_APLL_HALF] = { .name = "apll_half", .control_reg = CRF_APB_APLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) {CLK_APLL_INT, CLK_NA_PARENT}), .nodes = &generic_pll_half_nodes, .num_nodes = ARRAY_SIZE(generic_pll_half_nodes), }, [CLK_APLL_INT_MUX] = { .name = "apll_int_mux", .control_reg = CRF_APB_APLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { CLK_APLL_INT, CLK_APLL_HALF, CLK_NA_PARENT }), .nodes = &generic_pll_int_nodes, .num_nodes = ARRAY_SIZE(generic_pll_int_nodes), }, [CLK_APLL_POST_SRC] = { .name = "apll_post_src", .control_reg = CRF_APB_APLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT, EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT, EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &generic_pll_post_src_nodes, .num_nodes = ARRAY_SIZE(generic_pll_post_src_nodes), }, [CLK_APLL] = { .name = "apll", .control_reg = CRF_APB_APLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { CLK_APLL_INT_MUX, CLK_APLL_POST_SRC, CLK_NA_PARENT }), .nodes = &generic_pll_system_nodes, .num_nodes = ARRAY_SIZE(generic_pll_system_nodes), }, [CLK_DPLL_INT] = { .name = "dpll_int", .control_reg = CRF_APB_DPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) {CLK_DPLL_PRE_SRC, CLK_NA_PARENT}), .nodes = &generic_pll_nodes, .num_nodes = ARRAY_SIZE(generic_pll_nodes), }, [CLK_DPLL_PRE_SRC] = { .name = "dpll_pre_src", .control_reg = CRF_APB_DPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT, EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT, EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &generic_pll_pre_src_nodes, .num_nodes = ARRAY_SIZE(generic_pll_pre_src_nodes), }, [CLK_DPLL_HALF] = { .name = "dpll_half", .control_reg = CRF_APB_DPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) {CLK_DPLL_INT, CLK_NA_PARENT}), .nodes = &generic_pll_half_nodes, .num_nodes = ARRAY_SIZE(generic_pll_half_nodes), }, [CLK_DPLL_INT_MUX] = { .name = "dpll_int_mux", .control_reg = CRF_APB_DPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { CLK_DPLL_INT, CLK_DPLL_HALF, CLK_NA_PARENT }), .nodes = &generic_pll_int_nodes, .num_nodes = ARRAY_SIZE(generic_pll_int_nodes), }, [CLK_DPLL_POST_SRC] = { .name = "dpll_post_src", .control_reg = CRF_APB_DPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT, EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT, EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &generic_pll_post_src_nodes, .num_nodes = ARRAY_SIZE(generic_pll_post_src_nodes), }, [CLK_DPLL] = { .name = "dpll", .control_reg = CRF_APB_DPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { CLK_DPLL_INT_MUX, CLK_DPLL_POST_SRC, CLK_NA_PARENT }), .nodes = &generic_pll_system_nodes, .num_nodes = ARRAY_SIZE(generic_pll_system_nodes), }, [CLK_VPLL_INT] = { .name = "vpll_int", .control_reg = CRF_APB_VPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) {CLK_VPLL_PRE_SRC, CLK_NA_PARENT}), .nodes = &ignore_unused_pll_nodes, .num_nodes = ARRAY_SIZE(ignore_unused_pll_nodes), }, [CLK_VPLL_PRE_SRC] = { .name = "vpll_pre_src", .control_reg = CRF_APB_VPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT, EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT, EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &generic_pll_pre_src_nodes, .num_nodes = ARRAY_SIZE(generic_pll_pre_src_nodes), }, [CLK_VPLL_HALF] = { .name = "vpll_half", .control_reg = CRF_APB_VPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) {CLK_VPLL_INT, CLK_NA_PARENT}), .nodes = &generic_pll_half_nodes, .num_nodes = ARRAY_SIZE(generic_pll_half_nodes), }, [CLK_VPLL_INT_MUX] = { .name = "vpll_int_mux", .control_reg = CRF_APB_VPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { CLK_VPLL_INT, CLK_VPLL_HALF, CLK_NA_PARENT }), .nodes = &generic_pll_int_nodes, .num_nodes = ARRAY_SIZE(generic_pll_int_nodes), }, [CLK_VPLL_POST_SRC] = { .name = "vpll_post_src", .control_reg = CRF_APB_VPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT, EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT, EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &generic_pll_post_src_nodes, .num_nodes = ARRAY_SIZE(generic_pll_post_src_nodes), }, [CLK_VPLL] = { .name = "vpll", .control_reg = CRF_APB_VPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { CLK_VPLL_INT_MUX, CLK_VPLL_POST_SRC, CLK_NA_PARENT }), .nodes = &generic_pll_system_nodes, .num_nodes = ARRAY_SIZE(generic_pll_system_nodes), }, [CLK_IOPLL_INT] = { .name = "iopll_int", .control_reg = CRL_APB_IOPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) {CLK_IOPLL_PRE_SRC, CLK_NA_PARENT}), .nodes = &generic_pll_nodes, .num_nodes = ARRAY_SIZE(generic_pll_nodes), }, [CLK_IOPLL_PRE_SRC] = { .name = "iopll_pre_src", .control_reg = CRL_APB_IOPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT, EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT, EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &generic_pll_pre_src_nodes, .num_nodes = ARRAY_SIZE(generic_pll_pre_src_nodes), }, [CLK_IOPLL_HALF] = { .name = "iopll_half", .control_reg = CRL_APB_IOPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) {CLK_IOPLL_INT, CLK_NA_PARENT}), .nodes = &generic_pll_half_nodes, .num_nodes = ARRAY_SIZE(generic_pll_half_nodes), }, [CLK_IOPLL_INT_MUX] = { .name = "iopll_int_mux", .control_reg = CRL_APB_IOPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { CLK_IOPLL_INT, CLK_IOPLL_HALF, CLK_NA_PARENT }), .nodes = &generic_pll_int_nodes, .num_nodes = ARRAY_SIZE(generic_pll_int_nodes), }, [CLK_IOPLL_POST_SRC] = { .name = "iopll_post_src", .control_reg = CRL_APB_IOPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT, EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT, EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &generic_pll_post_src_nodes, .num_nodes = ARRAY_SIZE(generic_pll_post_src_nodes), }, [CLK_IOPLL] = { .name = "iopll", .control_reg = CRL_APB_IOPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { CLK_IOPLL_INT_MUX, CLK_IOPLL_POST_SRC, CLK_NA_PARENT }), .nodes = &generic_pll_system_nodes, .num_nodes = ARRAY_SIZE(generic_pll_system_nodes), }, [CLK_RPLL_INT] = { .name = "rpll_int", .control_reg = CRL_APB_RPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) {CLK_RPLL_PRE_SRC, CLK_NA_PARENT}), .nodes = &generic_pll_nodes, .num_nodes = ARRAY_SIZE(generic_pll_nodes), }, [CLK_RPLL_PRE_SRC] = { .name = "rpll_pre_src", .control_reg = CRL_APB_RPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT, EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT, EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &generic_pll_pre_src_nodes, .num_nodes = ARRAY_SIZE(generic_pll_pre_src_nodes), }, [CLK_RPLL_HALF] = { .name = "rpll_half", .control_reg = CRL_APB_RPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) {CLK_RPLL_INT, CLK_NA_PARENT}), .nodes = &generic_pll_half_nodes, .num_nodes = ARRAY_SIZE(generic_pll_half_nodes), }, [CLK_RPLL_INT_MUX] = { .name = "rpll_int_mux", .control_reg = CRL_APB_RPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { CLK_RPLL_INT, CLK_RPLL_HALF, CLK_NA_PARENT }), .nodes = &generic_pll_int_nodes, .num_nodes = ARRAY_SIZE(generic_pll_int_nodes), }, [CLK_RPLL_POST_SRC] = { .name = "rpll_post_src", .control_reg = CRL_APB_RPLL_CTRL, .status_reg = CRF_APB_PLL_STATUS, .parents = &((int32_t []) { EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_VIDEO | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_ALT_REF | CLK_EXTERNAL_PARENT, EXT_CLK_AUX_REF | CLK_EXTERNAL_PARENT, EXT_CLK_GT_CRX_REF | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &generic_pll_post_src_nodes, .num_nodes = ARRAY_SIZE(generic_pll_post_src_nodes), }, [CLK_RPLL] = { .name = "rpll", .control_reg = CRL_APB_RPLL_CTRL, .status_reg = CRL_APB_PLL_STATUS, .parents = &((int32_t []) { CLK_RPLL_INT_MUX, CLK_RPLL_POST_SRC, CLK_NA_PARENT }), .nodes = &generic_pll_system_nodes, .num_nodes = ARRAY_SIZE(generic_pll_system_nodes), }, /* Peripheral Clocks */ [CLK_ACPU] = { .name = "acpu", .control_reg = CRF_APB_ACPU_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_APLL, CLK_DUMMY_PARENT, CLK_DPLL, CLK_VPLL, CLK_NA_PARENT }), .nodes = &acpu_nodes, .num_nodes = ARRAY_SIZE(acpu_nodes), }, [CLK_ACPU_FULL] = { .name = "acpu_full", .control_reg = CRF_APB_ACPU_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_ACPU | PARENT_CLK_NODE2 << CLK_PARENTS_ID_LEN, CLK_NA_PARENT }), .nodes = &acpu_full_nodes, .num_nodes = ARRAY_SIZE(acpu_full_nodes), }, [CLK_DBG_TRACE] = { .name = "dbg_trace", .control_reg = CRF_APB_DBG_TRACE_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL_TO_FPD, CLK_DUMMY_PARENT, CLK_DPLL, CLK_APLL, CLK_NA_PARENT }), .nodes = &generic_mux_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes), }, [CLK_DBG_FPD] = { .name = "dbg_fpd", .control_reg = CRF_APB_DBG_FPD_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL_TO_FPD, CLK_DUMMY_PARENT, CLK_DPLL, CLK_APLL, CLK_NA_PARENT }), .nodes = &generic_mux_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes), }, [CLK_DBG_TSTMP] = { .name = "dbg_tstmp", .control_reg = CRF_APB_DBG_TSTMP_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL_TO_FPD, CLK_DUMMY_PARENT, CLK_DPLL, CLK_APLL, CLK_NA_PARENT }), .nodes = &generic_mux_div_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_nodes), }, [CLK_DP_VIDEO_REF] = { .name = "dp_video_ref", .control_reg = CRF_APB_DP_VIDEO_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_VPLL, CLK_DUMMY_PARENT, CLK_DPLL, CLK_RPLL_TO_FPD, CLK_NA_PARENT }), .nodes = &dp_audio_video_ref_nodes, .num_nodes = ARRAY_SIZE(dp_audio_video_ref_nodes), }, [CLK_DP_AUDIO_REF] = { .name = "dp_audio_ref", .control_reg = CRF_APB_DP_AUDIO_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_VPLL, CLK_DUMMY_PARENT, CLK_DPLL, CLK_RPLL_TO_FPD, CLK_NA_PARENT }), .nodes = &dp_audio_video_ref_nodes, .num_nodes = ARRAY_SIZE(dp_audio_video_ref_nodes), }, [CLK_DP_STC_REF] = { .name = "dp_stc_ref", .control_reg = CRF_APB_DP_STC_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_VPLL, CLK_DUMMY_PARENT, CLK_DPLL, CLK_RPLL_TO_FPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes), }, [CLK_DPDMA_REF] = { .name = "dpdma_ref", .control_reg = CRF_APB_DPDMA_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_APLL, CLK_DUMMY_PARENT, CLK_VPLL, CLK_DPLL, CLK_NA_PARENT }), .nodes = &generic_mux_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes), }, [CLK_DDR_REF] = { .name = "ddr_ref", .control_reg = CRF_APB_DDR_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_DPLL, CLK_VPLL, CLK_NA_PARENT }), .nodes = &ddr_nodes, .num_nodes = ARRAY_SIZE(ddr_nodes), }, [CLK_GPU_REF] = { .name = "gpu_ref", .control_reg = CRF_APB_GPU_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL_TO_FPD, CLK_DUMMY_PARENT, CLK_VPLL, CLK_DPLL, CLK_NA_PARENT }), .nodes = &generic_mux_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes), }, [CLK_SATA_REF] = { .name = "sata_ref", .control_reg = CRF_APB_SATA_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL_TO_FPD, CLK_DUMMY_PARENT, CLK_APLL, CLK_DPLL, CLK_NA_PARENT }), .nodes = &generic_mux_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes), }, [CLK_PCIE_REF] = { .name = "pcie_ref", .control_reg = CRF_APB_PCIE_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL_TO_FPD, CLK_DUMMY_PARENT, CLK_RPLL_TO_FPD, CLK_DPLL, CLK_NA_PARENT }), .nodes = &generic_mux_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes), }, [CLK_GDMA_REF] = { .name = "gdma_ref", .control_reg = CRF_APB_GDMA_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_APLL, CLK_DUMMY_PARENT, CLK_VPLL, CLK_DPLL, CLK_NA_PARENT }), .nodes = &generic_mux_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes), }, [CLK_GTGREF0_REF] = { .name = "gtgref0_ref", .control_reg = CRF_APB_GTGREF0_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL_TO_FPD, CLK_DUMMY_PARENT, CLK_APLL, CLK_DPLL, CLK_NA_PARENT }), .nodes = &generic_mux_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes), }, [CLK_TOPSW_MAIN] = { .name = "topsw_main", .control_reg = CRF_APB_TOPSW_MAIN_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_APLL, CLK_DUMMY_PARENT, CLK_VPLL, CLK_DPLL, CLK_NA_PARENT }), .nodes = &generic_mux_div_unused_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes), }, [CLK_TOPSW_LSBUS] = { .name = "topsw_lsbus", .control_reg = CRF_APB_TOPSW_LSBUS_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_APLL, CLK_DUMMY_PARENT, CLK_IOPLL_TO_FPD, CLK_DPLL, CLK_NA_PARENT }), .nodes = &generic_mux_div_unused_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes), }, [CLK_IOU_SWITCH] = { .name = "iou_switch", .control_reg = CRL_APB_IOU_SWITCH_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_RPLL, CLK_DUMMY_PARENT, CLK_IOPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_unused_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes), }, [CLK_GEM0_REF] = { .name = "gem0_ref", .control_reg = CRL_APB_GEM0_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &gem_nodes, .num_nodes = ARRAY_SIZE(gem_nodes), }, [CLK_GEM1_REF] = { .name = "gem1_ref", .control_reg = CRL_APB_GEM1_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &gem_nodes, .num_nodes = ARRAY_SIZE(gem_nodes), }, [CLK_GEM2_REF] = { .name = "gem2_ref", .control_reg = CRL_APB_GEM2_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &gem_nodes, .num_nodes = ARRAY_SIZE(gem_nodes), }, [CLK_GEM3_REF] = { .name = "gem3_ref", .control_reg = CRL_APB_GEM3_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &gem_nodes, .num_nodes = ARRAY_SIZE(gem_nodes), }, [CLK_USB0_BUS_REF] = { .name = "usb0_bus_ref", .control_reg = CRL_APB_USB0_BUS_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &usb_nodes, .num_nodes = ARRAY_SIZE(usb_nodes), }, [CLK_USB1_BUS_REF] = { .name = "usb1_bus_ref", .control_reg = CRL_APB_USB1_BUS_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &usb_nodes, .num_nodes = ARRAY_SIZE(usb_nodes), }, [CLK_USB3_DUAL_REF] = { .name = "usb3_dual_ref", .control_reg = CRL_APB_USB3_DUAL_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &usb_nodes, .num_nodes = ARRAY_SIZE(usb_nodes), }, [CLK_QSPI_REF] = { .name = "qspi_ref", .control_reg = CRL_APB_QSPI_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes), }, [CLK_SDIO0_REF] = { .name = "sdio0_ref", .control_reg = CRL_APB_SDIO0_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_VPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes), }, [CLK_SDIO1_REF] = { .name = "sdio1_ref", .control_reg = CRL_APB_SDIO1_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_VPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes), }, [CLK_UART0_REF] = { .name = "uart0_ref", .control_reg = CRL_APB_UART0_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes), }, [CLK_UART1_REF] = { .name = "uart1_ref", .control_reg = CRL_APB_UART1_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes), }, [CLK_SPI0_REF] = { .name = "spi0_ref", .control_reg = CRL_APB_SPI0_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes), }, [CLK_SPI1_REF] = { .name = "spi1_ref", .control_reg = CRL_APB_SPI1_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes), }, [CLK_CAN0_REF] = { .name = "can0_ref", .control_reg = CRL_APB_CAN0_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes), }, [CLK_CAN1_REF] = { .name = "can1_ref", .control_reg = CRL_APB_CAN1_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes), }, [CLK_NAND_REF] = { .name = "nand_ref", .control_reg = CRL_APB_NAND_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes), }, [CLK_GEM_TSU_REF] = { .name = "gem_tsu_ref", .control_reg = CRL_APB_GEM_TSU_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes), }, [CLK_DLL_REF] = { .name = "dll_ref", .control_reg = CRL_APB_DLL_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_RPLL, CLK_NA_PARENT }), .nodes = &dll_ref_nodes, .num_nodes = ARRAY_SIZE(dll_ref_nodes), }, [CLK_ADMA_REF] = { .name = "adma_ref", .control_reg = CRL_APB_ADMA_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_RPLL, CLK_DUMMY_PARENT, CLK_IOPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes), }, [CLK_DBG_LPD] = { .name = "dbg_lpd", .control_reg = CRL_APB_DBG_LPD_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_RPLL, CLK_DUMMY_PARENT, CLK_IOPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes), }, [CLK_CPU_R5] = { .name = "cpu_r5", .control_reg = CRL_APB_CPU_R5_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_RPLL, CLK_DUMMY_PARENT, CLK_IOPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_unused_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes), }, [CLK_CSU_PLL] = { .name = "csu_pll", .control_reg = CRL_APB_CSU_PLL_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes), }, [CLK_PCAP] = { .name = "pcap", .control_reg = CRL_APB_PCAP_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_gate_nodes), }, [CLK_LPD_LSBUS] = { .name = "lpd_lsbus", .control_reg = CRL_APB_LPD_LSBUS_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_RPLL, CLK_DUMMY_PARENT, CLK_IOPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_unused_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes), }, [CLK_LPD_SWITCH] = { .name = "lpd_switch", .control_reg = CRL_APB_LPD_SWITCH_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_RPLL, CLK_DUMMY_PARENT, CLK_IOPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_unused_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_unused_gate_nodes), }, [CLK_I2C0_REF] = { .name = "i2c0_ref", .control_reg = CRL_APB_I2C0_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes), }, [CLK_I2C1_REF] = { .name = "i2c1_ref", .control_reg = CRL_APB_I2C1_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes), }, [CLK_TIMESTAMP_REF] = { .name = "timestamp_ref", .control_reg = CRL_APB_TIMESTAMP_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, EXT_CLK_PSS_REF | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = ×tamp_ref_nodes, .num_nodes = ARRAY_SIZE(timestamp_ref_nodes), }, [CLK_PL0_REF] = { .name = "pl0_ref", .control_reg = CRL_APB_PL0_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &pl_nodes, .num_nodes = ARRAY_SIZE(pl_nodes), }, [CLK_PL1_REF] = { .name = "pl1_ref", .control_reg = CRL_APB_PL1_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &pl_nodes, .num_nodes = ARRAY_SIZE(pl_nodes), }, [CLK_PL2_REF] = { .name = "pl2_ref", .control_reg = CRL_APB_PL2_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &pl_nodes, .num_nodes = ARRAY_SIZE(pl_nodes), }, [CLK_PL3_REF] = { .name = "pl3_ref", .control_reg = CRL_APB_PL3_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_IOPLL, CLK_DUMMY_PARENT, CLK_RPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &pl_nodes, .num_nodes = ARRAY_SIZE(pl_nodes), }, [CLK_AMS_REF] = { .name = "ams_ref", .control_reg = CRL_APB_AMS_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_RPLL, CLK_DUMMY_PARENT, CLK_IOPLL, CLK_DPLL_TO_LPD, CLK_NA_PARENT }), .nodes = &generic_mux_div_div_gate_nodes, .num_nodes = ARRAY_SIZE(generic_mux_div_div_gate_nodes), }, [CLK_IOPLL_TO_FPD] = { .name = "iopll_to_fpd", .control_reg = CRL_APB_IOPLL_TO_FPD_CTRL, .status_reg = 0, .parents = &((int32_t []) {CLK_IOPLL, CLK_NA_PARENT}), .nodes = &generic_domain_crossing_nodes, .num_nodes = ARRAY_SIZE(generic_domain_crossing_nodes), }, [CLK_RPLL_TO_FPD] = { .name = "rpll_to_fpd", .control_reg = CRL_APB_RPLL_TO_FPD_CTRL, .status_reg = 0, .parents = &((int32_t []) {CLK_RPLL, CLK_NA_PARENT}), .nodes = &rpll_to_fpd_nodes, .num_nodes = ARRAY_SIZE(rpll_to_fpd_nodes), }, [CLK_APLL_TO_LPD] = { .name = "apll_to_lpd", .control_reg = CRF_APB_APLL_TO_LPD_CTRL, .status_reg = 0, .parents = &((int32_t []) {CLK_APLL, CLK_NA_PARENT}), .nodes = &generic_domain_crossing_nodes, .num_nodes = ARRAY_SIZE(generic_domain_crossing_nodes), }, [CLK_DPLL_TO_LPD] = { .name = "dpll_to_lpd", .control_reg = CRF_APB_DPLL_TO_LPD_CTRL, .status_reg = 0, .parents = &((int32_t []) {CLK_DPLL, CLK_NA_PARENT}), .nodes = &generic_domain_crossing_nodes, .num_nodes = ARRAY_SIZE(generic_domain_crossing_nodes), }, [CLK_VPLL_TO_LPD] = { .name = "vpll_to_lpd", .control_reg = CRF_APB_VPLL_TO_LPD_CTRL, .status_reg = 0, .parents = &((int32_t []) {CLK_VPLL, CLK_NA_PARENT}), .nodes = &generic_domain_crossing_nodes, .num_nodes = ARRAY_SIZE(generic_domain_crossing_nodes), }, /* * This clock control requires different registers for mux and gate. * Use control and status registers for the same. */ [CLK_GEM0_TX] = { .name = "gem0_tx", .control_reg = IOU_SLCR_GEM_CLK_CTRL, .status_reg = CRL_APB_GEM0_REF_CTRL, .parents = &((int32_t []) { CLK_GEM0_REF | (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN), EXT_CLK_GEM0_EMIO | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &gem0_tx_nodes, .num_nodes = ARRAY_SIZE(gem0_tx_nodes), }, /* * This clock control requires different registers for mux and gate. * Use control and status registers for the same. */ [CLK_GEM1_TX] = { .name = "gem1_tx", .control_reg = IOU_SLCR_GEM_CLK_CTRL, .status_reg = CRL_APB_GEM1_REF_CTRL, .parents = &((int32_t []) { CLK_GEM1_REF | (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN), EXT_CLK_GEM1_EMIO | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &gem1_tx_nodes, .num_nodes = ARRAY_SIZE(gem1_tx_nodes), }, /* * This clock control requires different registers for mux and gate. * Use control and status registers for the same. */ [CLK_GEM2_TX] = { .name = "gem2_tx", .control_reg = IOU_SLCR_GEM_CLK_CTRL, .status_reg = CRL_APB_GEM2_REF_CTRL, .parents = &((int32_t []) { CLK_GEM2_REF | (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN), EXT_CLK_GEM2_EMIO | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &gem2_tx_nodes, .num_nodes = ARRAY_SIZE(gem2_tx_nodes), }, /* * This clock control requires different registers for mux and gate. * Use control and status registers for the same. */ [CLK_GEM3_TX] = { .name = "gem3_tx", .control_reg = IOU_SLCR_GEM_CLK_CTRL, .status_reg = CRL_APB_GEM3_REF_CTRL, .parents = &((int32_t []) { CLK_GEM3_REF | (PARENT_CLK_NODE3 << CLK_PARENTS_ID_LEN), EXT_CLK_GEM3_EMIO | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &gem3_tx_nodes, .num_nodes = ARRAY_SIZE(gem3_tx_nodes), }, [CLK_ACPU_HALF] = { .name = "acpu_half", .control_reg = CRF_APB_ACPU_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_ACPU | PARENT_CLK_NODE2 << CLK_PARENTS_ID_LEN, CLK_NA_PARENT }), .nodes = &acpu_half_nodes, .num_nodes = ARRAY_SIZE(acpu_half_nodes), }, [CLK_WDT] = { .name = "wdt", .control_reg = FPD_SLCR_WDT_CLK_SEL, .status_reg = 0, .parents = &((int32_t []) { CLK_TOPSW_LSBUS, EXT_CLK_SWDT0 | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &wdt_nodes, .num_nodes = ARRAY_SIZE(wdt_nodes), }, [CLK_GPU_PP0_REF] = { .name = "gpu_pp0_ref", .control_reg = CRF_APB_GPU_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_GPU_REF | PARENT_CLK_NODE2 << CLK_PARENTS_ID_LEN, CLK_NA_PARENT }), .nodes = &gpu_pp0_nodes, .num_nodes = ARRAY_SIZE(gpu_pp0_nodes), }, [CLK_GPU_PP1_REF] = { .name = "gpu_pp1_ref", .control_reg = CRF_APB_GPU_REF_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_GPU_REF | PARENT_CLK_NODE2 << CLK_PARENTS_ID_LEN, CLK_NA_PARENT }), .nodes = &gpu_pp1_nodes, .num_nodes = ARRAY_SIZE(gpu_pp1_nodes), }, [CLK_GEM_TSU] = { .name = "gem_tsu", .control_reg = IOU_SLCR_GEM_CLK_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_GEM_TSU_REF, CLK_GEM_TSU_REF, EXT_CLK_MIO26 | CLK_EXTERNAL_PARENT, EXT_CLK_MIO50_OR_MIO51 | CLK_EXTERNAL_PARENT, CLK_NA_PARENT }), .nodes = &gem_tsu_nodes, .num_nodes = ARRAY_SIZE(gem_tsu_nodes), }, [CLK_CPU_R5_CORE] = { .name = "cpu_r5_core", .control_reg = CRL_APB_CPU_R5_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_CPU_R5 | PARENT_CLK_NODE2 << CLK_PARENTS_ID_LEN, CLK_DUMMY_PARENT, CLK_NA_PARENT }), .nodes = &cpu_r5_core_nodes, .num_nodes = ARRAY_SIZE(cpu_r5_core_nodes), }, [CLK_CAN0_MIO] = { .name = "can0_mio", .control_reg = IOU_SLCR_CAN_MIO_CTRL, .status_reg = 0, .parents = &can_mio_parents, .nodes = &can0_mio_nodes, .num_nodes = ARRAY_SIZE(can0_mio_nodes), }, [CLK_CAN1_MIO] = { .name = "can1_mio", .control_reg = IOU_SLCR_CAN_MIO_CTRL, .status_reg = 0, .parents = &can_mio_parents, .nodes = &can1_mio_nodes, .num_nodes = ARRAY_SIZE(can1_mio_nodes), }, [CLK_CAN0] = { .name = "can0", .control_reg = IOU_SLCR_CAN_MIO_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_CAN0_REF, CLK_CAN0_MIO, CLK_NA_PARENT }), .nodes = &can0_nodes, .num_nodes = ARRAY_SIZE(can0_nodes), }, [CLK_CAN1] = { .name = "can1", .control_reg = IOU_SLCR_CAN_MIO_CTRL, .status_reg = 0, .parents = &((int32_t []) { CLK_CAN1_REF, CLK_CAN1_MIO, CLK_NA_PARENT }), .nodes = &can1_nodes, .num_nodes = ARRAY_SIZE(can1_nodes), }, }; static struct pm_ext_clock ext_clocks[] = { [EXT_CLK_INDEX(EXT_CLK_PSS_REF)] = { .name = "pss_ref_clk", }, [EXT_CLK_INDEX(EXT_CLK_VIDEO)] = { .name = "video_clk", }, [EXT_CLK_INDEX(EXT_CLK_PSS_ALT_REF)] = { .name = "pss_alt_ref_clk", }, [EXT_CLK_INDEX(EXT_CLK_AUX_REF)] = { .name = "aux_ref_clk", }, [EXT_CLK_INDEX(EXT_CLK_GT_CRX_REF)] = { .name = "video_clk", }, [EXT_CLK_INDEX(EXT_CLK_SWDT0)] = { .name = "swdt0_ext_clk", }, [EXT_CLK_INDEX(EXT_CLK_SWDT1)] = { .name = "swdt1_ext_clk", }, [EXT_CLK_INDEX(EXT_CLK_GEM0_EMIO)] = { .name = "gem0_emio_clk", }, [EXT_CLK_INDEX(EXT_CLK_GEM1_EMIO)] = { .name = "gem1_emio_clk", }, [EXT_CLK_INDEX(EXT_CLK_GEM2_EMIO)] = { .name = "gem2_emio_clk", }, [EXT_CLK_INDEX(EXT_CLK_GEM3_EMIO)] = { .name = "gem3_emio_clk", }, [EXT_CLK_INDEX(EXT_CLK_MIO50_OR_MIO51)] = { .name = "mio_clk_50_51", }, EXT_CLK_MIO_DATA(0), EXT_CLK_MIO_DATA(1), EXT_CLK_MIO_DATA(2), EXT_CLK_MIO_DATA(3), EXT_CLK_MIO_DATA(4), EXT_CLK_MIO_DATA(5), EXT_CLK_MIO_DATA(6), EXT_CLK_MIO_DATA(7), EXT_CLK_MIO_DATA(8), EXT_CLK_MIO_DATA(9), EXT_CLK_MIO_DATA(10), EXT_CLK_MIO_DATA(11), EXT_CLK_MIO_DATA(12), EXT_CLK_MIO_DATA(13), EXT_CLK_MIO_DATA(14), EXT_CLK_MIO_DATA(15), EXT_CLK_MIO_DATA(16), EXT_CLK_MIO_DATA(17), EXT_CLK_MIO_DATA(18), EXT_CLK_MIO_DATA(19), EXT_CLK_MIO_DATA(20), EXT_CLK_MIO_DATA(21), EXT_CLK_MIO_DATA(22), EXT_CLK_MIO_DATA(23), EXT_CLK_MIO_DATA(24), EXT_CLK_MIO_DATA(25), EXT_CLK_MIO_DATA(26), EXT_CLK_MIO_DATA(27), EXT_CLK_MIO_DATA(28), EXT_CLK_MIO_DATA(29), EXT_CLK_MIO_DATA(30), EXT_CLK_MIO_DATA(31), EXT_CLK_MIO_DATA(32), EXT_CLK_MIO_DATA(33), EXT_CLK_MIO_DATA(34), EXT_CLK_MIO_DATA(35), EXT_CLK_MIO_DATA(36), EXT_CLK_MIO_DATA(37), EXT_CLK_MIO_DATA(38), EXT_CLK_MIO_DATA(39), EXT_CLK_MIO_DATA(40), EXT_CLK_MIO_DATA(41), EXT_CLK_MIO_DATA(42), EXT_CLK_MIO_DATA(43), EXT_CLK_MIO_DATA(44), EXT_CLK_MIO_DATA(45), EXT_CLK_MIO_DATA(46), EXT_CLK_MIO_DATA(47), EXT_CLK_MIO_DATA(48), EXT_CLK_MIO_DATA(49), EXT_CLK_MIO_DATA(50), EXT_CLK_MIO_DATA(51), EXT_CLK_MIO_DATA(52), EXT_CLK_MIO_DATA(53), EXT_CLK_MIO_DATA(54), EXT_CLK_MIO_DATA(55), EXT_CLK_MIO_DATA(56), EXT_CLK_MIO_DATA(57), EXT_CLK_MIO_DATA(58), EXT_CLK_MIO_DATA(59), EXT_CLK_MIO_DATA(60), EXT_CLK_MIO_DATA(61), EXT_CLK_MIO_DATA(62), EXT_CLK_MIO_DATA(63), EXT_CLK_MIO_DATA(64), EXT_CLK_MIO_DATA(65), EXT_CLK_MIO_DATA(66), EXT_CLK_MIO_DATA(67), EXT_CLK_MIO_DATA(68), EXT_CLK_MIO_DATA(69), EXT_CLK_MIO_DATA(70), EXT_CLK_MIO_DATA(71), EXT_CLK_MIO_DATA(72), EXT_CLK_MIO_DATA(73), EXT_CLK_MIO_DATA(74), EXT_CLK_MIO_DATA(75), EXT_CLK_MIO_DATA(76), EXT_CLK_MIO_DATA(77), }; /* Array of clock which are invalid for this variant */ static uint32_t pm_clk_invalid_list[] = {CLK_USB0, CLK_USB1, CLK_CSU_SPB, CLK_ACPU_FULL, CLK_ACPU_HALF, CLK_APLL_TO_LPD, CLK_DBG_FPD, CLK_DBG_LPD, CLK_DBG_TRACE, CLK_DBG_TSTMP, CLK_DDR_REF, CLK_TOPSW_MAIN, CLK_TOPSW_LSBUS, CLK_GTGREF0_REF, CLK_LPD_SWITCH, CLK_LPD_LSBUS, CLK_CPU_R5, CLK_CPU_R5_CORE, CLK_CSU_SPB, CLK_CSU_PLL, CLK_PCAP, CLK_IOU_SWITCH, CLK_DLL_REF, CLK_TIMESTAMP_REF, }; /** * pm_clock_valid - Check if clock is valid or not * @clock_id Id of the clock to be queried * * This function is used to check if given clock is valid * or not for the chip variant. * * List of invalid clocks are maintained in array list for * different variants. * * Return: Returns 1 if clock is valid else 0. */ static bool pm_clock_valid(unsigned int clock_id) { unsigned int i; for (i = 0; i < ARRAY_SIZE(pm_clk_invalid_list); i++) if (pm_clk_invalid_list[i] == clock_id) return 0; return 1; } /** * pm_clock_type - Get clock's type * @clock_id Id of the clock to be queried * * This function is used to check type of clock (OUTPUT/EXTERNAL). * * Return: Returns type of clock (OUTPUT/EXTERNAL). */ static unsigned int pm_clock_type(unsigned int clock_id) { return (clock_id < CLK_MAX_OUTPUT_CLK) ? CLK_TYPE_OUTPUT : CLK_TYPE_EXTERNAL; } /** * pm_api_clock_get_num_clocks() - PM call to request number of clocks * @nclocks Number of clocks * * This function is used by master to get number of clocks. * * @return Returns success. */ enum pm_ret_status pm_api_clock_get_num_clocks(unsigned int *nclocks) { *nclocks = CLK_MAX; return PM_RET_SUCCESS; } /** * pm_api_clock_get_name() - PM call to request a clock's name * @clock_id Clock ID * @name Name of clock (max 16 bytes) * * This function is used by master to get nmae of clock specified * by given clock ID. * * @return Returns success. In case of error, name data is 0. */ enum pm_ret_status pm_api_clock_get_name(unsigned int clock_id, char *name) { if (clock_id == CLK_MAX) memcpy(name, END_OF_CLK, CLK_NAME_LEN); else if (!pm_clock_valid(clock_id)) memset(name, 0, CLK_NAME_LEN); else if (clock_id < CLK_MAX_OUTPUT_CLK) memcpy(name, clocks[clock_id].name, CLK_NAME_LEN); else memcpy(name, ext_clocks[clock_id - CLK_MAX_OUTPUT_CLK].name, CLK_NAME_LEN); return PM_RET_SUCCESS; } /** * pm_api_clock_get_topology() - PM call to request a clock's topology * @clock_id Clock ID * @index Topology index for next toplogy node * @topology Buffer to store nodes in topology and flags * * This function is used by master to get topology information for the * clock specified by given clock ID. Each response would return 3 * topology nodes. To get next nodes, caller needs to call this API with * index of next node. Index starts from 0. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_api_clock_get_topology(unsigned int clock_id, unsigned int index, uint32_t *topology) { struct pm_clock_node *clock_nodes; uint8_t num_nodes; unsigned int i; if (!pm_clock_valid(clock_id)) return PM_RET_ERROR_ARGS; if (pm_clock_type(clock_id) != CLK_TYPE_OUTPUT) return PM_RET_ERROR_NOTSUPPORTED; memset(topology, 0, CLK_TOPOLOGY_PAYLOAD_LEN); clock_nodes = *clocks[clock_id].nodes; num_nodes = clocks[clock_id].num_nodes; /* Skip parent till index */ if (index >= num_nodes) return PM_RET_SUCCESS; for (i = 0; i < 3U; i++) { if ((index + i) == num_nodes) break; topology[i] = clock_nodes[index + i].type; topology[i] |= clock_nodes[index + i].clkflags << CLK_CLKFLAGS_SHIFT; topology[i] |= clock_nodes[index + i].typeflags << CLK_TYPEFLAGS_SHIFT; } return PM_RET_SUCCESS; } /** * pm_api_clock_get_fixedfactor_params() - PM call to request a clock's fixed * factor parameters for fixed clock * @clock_id Clock ID * @mul Multiplication value * @div Divisor value * * This function is used by master to get fixed factor parameers for the * fixed clock. This API is application only for the fixed clock. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_api_clock_get_fixedfactor_params(unsigned int clock_id, uint32_t *mul, uint32_t *div) { struct pm_clock_node *clock_nodes; uint8_t num_nodes; unsigned int type, i; if (!pm_clock_valid(clock_id)) return PM_RET_ERROR_ARGS; if (pm_clock_type(clock_id) != CLK_TYPE_OUTPUT) return PM_RET_ERROR_NOTSUPPORTED; clock_nodes = *clocks[clock_id].nodes; num_nodes = clocks[clock_id].num_nodes; for (i = 0; i < num_nodes; i++) { type = clock_nodes[i].type; if (type == TYPE_FIXEDFACTOR) { *mul = clock_nodes[i].mult; *div = clock_nodes[i].div; break; } } /* Clock is not fixed clock */ if (i == num_nodes) return PM_RET_ERROR_ARGS; return PM_RET_SUCCESS; } /** * pm_api_clock_get_parents() - PM call to request a clock's first 3 parents * @clock_id Clock ID * @index Index of next parent * @parents Parents of the given clock * * This function is used by master to get clock's parents information. * This API will return 3 parents with a single response. To get other * parents, master should call same API in loop with new parent index * till error is returned. * * E.g First call should have index 0 which will return parents 0, 1 and * 2. Next call, index should be 3 which will return parent 3,4 and 5 and * so on. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_api_clock_get_parents(unsigned int clock_id, unsigned int index, uint32_t *parents) { unsigned int i; int32_t *clk_parents; if (!pm_clock_valid(clock_id)) return PM_RET_ERROR_ARGS; if (pm_clock_type(clock_id) != CLK_TYPE_OUTPUT) return PM_RET_ERROR_NOTSUPPORTED; clk_parents = *clocks[clock_id].parents; if (clk_parents == NULL) return PM_RET_ERROR_ARGS; memset(parents, 0, CLK_PARENTS_PAYLOAD_LEN); /* Skip parent till index */ for (i = 0; i < index; i++) if (clk_parents[i] == CLK_NA_PARENT) return PM_RET_SUCCESS; for (i = 0; i < 3; i++) { parents[i] = clk_parents[index + i]; if (clk_parents[index + i] == CLK_NA_PARENT) break; } return PM_RET_SUCCESS; } /** * pm_api_clock_get_attributes() - PM call to request a clock's attributes * @clock_id Clock ID * @attr Clock attributes * * This function is used by master to get clock's attributes * (e.g. valid, clock type, etc). * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_api_clock_get_attributes(unsigned int clock_id, uint32_t *attr) { if (clock_id >= CLK_MAX) return PM_RET_ERROR_ARGS; /* Clock valid bit */ *attr = pm_clock_valid(clock_id); /* Clock type (Output/External) */ *attr |= (pm_clock_type(clock_id) << CLK_TYPE_SHIFT); return PM_RET_SUCCESS; } /** * struct pm_pll - PLL related data required to map IOCTL-based PLL control * implemented by linux to system-level EEMI APIs * @nid: PLL node ID * @cid: PLL clock ID * @pre_src: Pre-source PLL clock ID * @post_src: Post-source PLL clock ID * @div2: DIV2 PLL clock ID * @bypass: PLL output clock ID that maps to bypass select output * @mode: PLL mode currently set via IOCTL (PLL_FRAC_MODE/PLL_INT_MODE) */ struct pm_pll { const enum pm_node_id nid; const enum clock_id cid; const enum clock_id pre_src; const enum clock_id post_src; const enum clock_id div2; const enum clock_id bypass; uint8_t mode; }; static struct pm_pll pm_plls[] = { { .nid = NODE_IOPLL, .cid = CLK_IOPLL_INT, .pre_src = CLK_IOPLL_PRE_SRC, .post_src = CLK_IOPLL_POST_SRC, .div2 = CLK_IOPLL_INT_MUX, .bypass = CLK_IOPLL, }, { .nid = NODE_RPLL, .cid = CLK_RPLL_INT, .pre_src = CLK_RPLL_PRE_SRC, .post_src = CLK_RPLL_POST_SRC, .div2 = CLK_RPLL_INT_MUX, .bypass = CLK_RPLL, }, { .nid = NODE_APLL, .cid = CLK_APLL_INT, .pre_src = CLK_APLL_PRE_SRC, .post_src = CLK_APLL_POST_SRC, .div2 = CLK_APLL_INT_MUX, .bypass = CLK_APLL, }, { .nid = NODE_VPLL, .cid = CLK_VPLL_INT, .pre_src = CLK_VPLL_PRE_SRC, .post_src = CLK_VPLL_POST_SRC, .div2 = CLK_VPLL_INT_MUX, .bypass = CLK_VPLL, }, { .nid = NODE_DPLL, .cid = CLK_DPLL_INT, .pre_src = CLK_DPLL_PRE_SRC, .post_src = CLK_DPLL_POST_SRC, .div2 = CLK_DPLL_INT_MUX, .bypass = CLK_DPLL, }, }; /** * pm_clock_get_pll() - Get PLL structure by PLL clock ID * @clock_id Clock ID of the target PLL * * @return Pointer to PLL structure if found, NULL otherwise */ struct pm_pll *pm_clock_get_pll(enum clock_id clock_id) { uint32_t i; for (i = 0; i < ARRAY_SIZE(pm_plls); i++) { if (pm_plls[i].cid == clock_id) return &pm_plls[i]; } return NULL; } /** * pm_clock_get_pll_node_id() - Get PLL node ID by PLL clock ID * @clock_id Clock ID of the target PLL * @node_id Location to store node ID of the target PLL * * @return PM_RET_SUCCESS if node ID is found, PM_RET_ERROR_ARGS otherwise */ enum pm_ret_status pm_clock_get_pll_node_id(enum clock_id clock_id, enum pm_node_id *node_id) { struct pm_pll *pll = pm_clock_get_pll(clock_id); if (pll) { *node_id = pll->nid; return PM_RET_SUCCESS; } return PM_RET_ERROR_ARGS; } /** * pm_clock_get_pll_by_related_clk() - Get PLL structure by PLL-related clock ID * @clock_id Clock ID * * @return Pointer to PLL structure if found, NULL otherwise */ struct pm_pll *pm_clock_get_pll_by_related_clk(enum clock_id clock_id) { uint32_t i; for (i = 0; i < ARRAY_SIZE(pm_plls); i++) { if (pm_plls[i].pre_src == clock_id || pm_plls[i].post_src == clock_id || pm_plls[i].div2 == clock_id || pm_plls[i].bypass == clock_id) { return &pm_plls[i]; } } return NULL; } /** * pm_clock_pll_enable() - "Enable" the PLL clock (lock the PLL) * @pll: PLL to be locked * * This function is used to map IOCTL/linux-based PLL handling to system-level * EEMI APIs * * Return: Error if the argument is not valid or status as returned by PMU */ enum pm_ret_status pm_clock_pll_enable(struct pm_pll *pll) { if (!pll) return PM_RET_ERROR_ARGS; /* Set the PLL mode according to the buffered mode value */ if (pll->mode == PLL_FRAC_MODE) return pm_pll_set_mode(pll->nid, PM_PLL_MODE_FRACTIONAL); return pm_pll_set_mode(pll->nid, PM_PLL_MODE_INTEGER); } /** * pm_clock_pll_disable - "Disable" the PLL clock (bypass/reset the PLL) * @pll PLL to be bypassed/reset * * This function is used to map IOCTL/linux-based PLL handling to system-level * EEMI APIs * * Return: Error if the argument is not valid or status as returned by PMU */ enum pm_ret_status pm_clock_pll_disable(struct pm_pll *pll) { if (!pll) return PM_RET_ERROR_ARGS; return pm_pll_set_mode(pll->nid, PM_PLL_MODE_RESET); } /** * pm_clock_pll_get_state - Get state of the PLL * @pll Pointer to the target PLL structure * @state Location to store the state: 1/0 ("Enabled"/"Disabled") * * "Enable" actually means that the PLL is locked and its bypass is deasserted, * "Disable" means that it is bypassed. * * Return: PM_RET_ERROR_ARGS error if the argument is not valid, success if * returned state value is valid or an error if returned by PMU */ enum pm_ret_status pm_clock_pll_get_state(struct pm_pll *pll, unsigned int *state) { enum pm_ret_status status; enum pm_pll_mode mode; if (!pll || !state) return PM_RET_ERROR_ARGS; status = pm_pll_get_mode(pll->nid, &mode); if (status != PM_RET_SUCCESS) return status; if (mode == PM_PLL_MODE_RESET) *state = 0; else *state = 1; return PM_RET_SUCCESS; } /** * pm_clock_pll_set_parent - Set the clock parent for PLL-related clock id * @pll Target PLL structure * @clock_id Id of the clock * @parent_index parent index (=mux select value) * * The whole clock-tree implementation relies on the fact that parent indexes * match to the multiplexer select values. This function has to rely on that * assumption as well => parent_index is actually the mux select value. * * Return: Returns status, either success or error+reason. */ enum pm_ret_status pm_clock_pll_set_parent(struct pm_pll *pll, enum clock_id clock_id, unsigned int parent_index) { if (!pll) return PM_RET_ERROR_ARGS; if (pll->pre_src == clock_id) return pm_pll_set_parameter(pll->nid, PM_PLL_PARAM_PRE_SRC, parent_index); if (pll->post_src == clock_id) return pm_pll_set_parameter(pll->nid, PM_PLL_PARAM_POST_SRC, parent_index); if (pll->div2 == clock_id) return pm_pll_set_parameter(pll->nid, PM_PLL_PARAM_DIV2, parent_index); return PM_RET_ERROR_ARGS; } /** * pm_clock_pll_get_parent - Get mux select value of PLL-related clock parent * @pll Target PLL structure * @clock_id Id of the clock * @parent_index parent index (=mux select value) * * This function is used by master to get parent index for PLL-related clock. * * Return: Returns status, either success or error+reason. */ enum pm_ret_status pm_clock_pll_get_parent(struct pm_pll *pll, enum clock_id clock_id, unsigned int *parent_index) { if (!pll) return PM_RET_ERROR_ARGS; if (pll->pre_src == clock_id) return pm_pll_get_parameter(pll->nid, PM_PLL_PARAM_PRE_SRC, parent_index); if (pll->post_src == clock_id) return pm_pll_get_parameter(pll->nid, PM_PLL_PARAM_POST_SRC, parent_index); if (pll->div2 == clock_id) return pm_pll_get_parameter(pll->nid, PM_PLL_PARAM_DIV2, parent_index); if (pll->bypass == clock_id) { *parent_index = 0; return PM_RET_SUCCESS; } return PM_RET_ERROR_ARGS; } /** * pm_clock_set_pll_mode() - Set PLL mode * @clock_id PLL clock id * @mode Mode fractional/integer * * This function buffers/saves the PLL mode that is set. * * @return Success if mode is buffered or error if an argument is invalid */ enum pm_ret_status pm_clock_set_pll_mode(enum clock_id clock_id, unsigned int mode) { struct pm_pll *pll = pm_clock_get_pll(clock_id); if (!pll || (mode != PLL_FRAC_MODE && mode != PLL_INT_MODE)) return PM_RET_ERROR_ARGS; pll->mode = mode; return PM_RET_SUCCESS; } /** * pm_clock_get_pll_mode() - Get PLL mode * @clock_id PLL clock id * @mode Location to store the mode (fractional/integer) * * This function returns buffered PLL mode. * * @return Success if mode is stored or error if an argument is invalid */ enum pm_ret_status pm_clock_get_pll_mode(enum clock_id clock_id, unsigned int *mode) { struct pm_pll *pll = pm_clock_get_pll(clock_id); if (!pll || !mode) return PM_RET_ERROR_ARGS; *mode = pll->mode; return PM_RET_SUCCESS; } /** * pm_clock_id_is_valid() - Check if given clock ID is valid * @clock_id ID of the clock to be checked * * @return Returns success if clock_id is valid, otherwise an error */ enum pm_ret_status pm_clock_id_is_valid(unsigned int clock_id) { if (!pm_clock_valid(clock_id)) return PM_RET_ERROR_ARGS; if (pm_clock_type(clock_id) != CLK_TYPE_OUTPUT) return PM_RET_ERROR_NOTSUPPORTED; return PM_RET_SUCCESS; } /** * pm_clock_has_div() - Check if the clock has divider with given ID * @clock_id Clock ID * @div_id Divider ID * * @return True(1)=clock has the divider, false(0)=otherwise */ uint8_t pm_clock_has_div(unsigned int clock_id, enum pm_clock_div_id div_id) { uint32_t i; struct pm_clock_node *nodes; if (clock_id >= CLK_MAX_OUTPUT_CLK) return 0; nodes = *clocks[clock_id].nodes; for (i = 0; i < clocks[clock_id].num_nodes; i++) { if (nodes[i].type == TYPE_DIV1) { if (div_id == PM_CLOCK_DIV0_ID) return 1; } else if (nodes[i].type == TYPE_DIV2) { if (div_id == PM_CLOCK_DIV1_ID) return 1; } } return 0; } trusted-firmware-a-2.2/plat/xilinx/zynqmp/pm_service/pm_api_clock.h000066400000000000000000000160461355360272700256560ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * ZynqMP system level PM-API functions for clock control. */ #ifndef PM_API_CLOCK_H #define PM_API_CLOCK_H #include #include "pm_common.h" #define CLK_NAME_LEN U(15) #define MAX_PARENTS U(100) #define CLK_NA_PARENT -1 #define CLK_DUMMY_PARENT -2 /* Flags for parent id */ #define PARENT_CLK_SELF U(0) #define PARENT_CLK_NODE1 U(1) #define PARENT_CLK_NODE2 U(2) #define PARENT_CLK_NODE3 U(3) #define PARENT_CLK_NODE4 U(4) #define PARENT_CLK_EXTERNAL U(5) #define PARENT_CLK_MIO0_MIO77 U(6) #define CLK_SET_RATE_GATE BIT(0) /* must be gated across rate change */ #define CLK_SET_PARENT_GATE BIT(1) /* must be gated across re-parent */ #define CLK_SET_RATE_PARENT BIT(2) /* propagate rate change up one level */ #define CLK_IGNORE_UNUSED BIT(3) /* do not gate even if unused */ /* unused */ #define CLK_IS_BASIC BIT(5) /* Basic clk, can't do a to_clk_foo() */ #define CLK_GET_RATE_NOCACHE BIT(6) /* do not use the cached clk rate */ #define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */ #define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */ #define CLK_RECALC_NEW_RATES BIT(9) /* recalc rates after notifications */ #define CLK_SET_RATE_UNGATE BIT(10) /* clock needs to run to set rate */ #define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */ /* parents need enable during gate/ungate, set rate and re-parent */ #define CLK_OPS_PARENT_ENABLE BIT(12) #define CLK_FRAC BIT(13) #define CLK_DIVIDER_ONE_BASED BIT(0) #define CLK_DIVIDER_POWER_OF_TWO BIT(1) #define CLK_DIVIDER_ALLOW_ZERO BIT(2) #define CLK_DIVIDER_HIWORD_MASK BIT(3) #define CLK_DIVIDER_ROUND_CLOSEST BIT(4) #define CLK_DIVIDER_READ_ONLY BIT(5) #define CLK_DIVIDER_MAX_AT_ZERO BIT(6) #define END_OF_CLK "END_OF_CLK" //CLock Ids enum clock_id { CLK_IOPLL, CLK_RPLL, CLK_APLL, CLK_DPLL, CLK_VPLL, CLK_IOPLL_TO_FPD, CLK_RPLL_TO_FPD, CLK_APLL_TO_LPD, CLK_DPLL_TO_LPD, CLK_VPLL_TO_LPD, CLK_ACPU, CLK_ACPU_HALF, CLK_DBG_FPD, CLK_DBG_LPD, CLK_DBG_TRACE, CLK_DBG_TSTMP, CLK_DP_VIDEO_REF, CLK_DP_AUDIO_REF, CLK_DP_STC_REF, CLK_GDMA_REF, CLK_DPDMA_REF, CLK_DDR_REF, CLK_SATA_REF, CLK_PCIE_REF, CLK_GPU_REF, CLK_GPU_PP0_REF, CLK_GPU_PP1_REF, CLK_TOPSW_MAIN, CLK_TOPSW_LSBUS, CLK_GTGREF0_REF, CLK_LPD_SWITCH, CLK_LPD_LSBUS, CLK_USB0_BUS_REF, CLK_USB1_BUS_REF, CLK_USB3_DUAL_REF, CLK_USB0, CLK_USB1, CLK_CPU_R5, CLK_CPU_R5_CORE, CLK_CSU_SPB, CLK_CSU_PLL, CLK_PCAP, CLK_IOU_SWITCH, CLK_GEM_TSU_REF, CLK_GEM_TSU, CLK_GEM0_REF, CLK_GEM1_REF, CLK_GEM2_REF, CLK_GEM3_REF, CLK_GEM0_TX, CLK_GEM1_TX, CLK_GEM2_TX, CLK_GEM3_TX, CLK_QSPI_REF, CLK_SDIO0_REF, CLK_SDIO1_REF, CLK_UART0_REF, CLK_UART1_REF, CLK_SPI0_REF, CLK_SPI1_REF, CLK_NAND_REF, CLK_I2C0_REF, CLK_I2C1_REF, CLK_CAN0_REF, CLK_CAN1_REF, CLK_CAN0, CLK_CAN1, CLK_DLL_REF, CLK_ADMA_REF, CLK_TIMESTAMP_REF, CLK_AMS_REF, CLK_PL0_REF, CLK_PL1_REF, CLK_PL2_REF, CLK_PL3_REF, CLK_WDT, CLK_IOPLL_INT, CLK_IOPLL_PRE_SRC, CLK_IOPLL_HALF, CLK_IOPLL_INT_MUX, CLK_IOPLL_POST_SRC, CLK_RPLL_INT, CLK_RPLL_PRE_SRC, CLK_RPLL_HALF, CLK_RPLL_INT_MUX, CLK_RPLL_POST_SRC, CLK_APLL_INT, CLK_APLL_PRE_SRC, CLK_APLL_HALF, CLK_APLL_INT_MUX, CLK_APLL_POST_SRC, CLK_DPLL_INT, CLK_DPLL_PRE_SRC, CLK_DPLL_HALF, CLK_DPLL_INT_MUX, CLK_DPLL_POST_SRC, CLK_VPLL_INT, CLK_VPLL_PRE_SRC, CLK_VPLL_HALF, CLK_VPLL_INT_MUX, CLK_VPLL_POST_SRC, CLK_CAN0_MIO, CLK_CAN1_MIO, CLK_ACPU_FULL, END_OF_OUTPUT_CLKS, }; #define CLK_MAX_OUTPUT_CLK (unsigned int)(END_OF_OUTPUT_CLKS) //External clock ids enum { EXT_CLK_PSS_REF = END_OF_OUTPUT_CLKS, EXT_CLK_VIDEO, EXT_CLK_PSS_ALT_REF, EXT_CLK_AUX_REF, EXT_CLK_GT_CRX_REF, EXT_CLK_SWDT0, EXT_CLK_SWDT1, EXT_CLK_GEM0_EMIO, EXT_CLK_GEM1_EMIO, EXT_CLK_GEM2_EMIO, EXT_CLK_GEM3_EMIO, EXT_CLK_MIO50_OR_MIO51, EXT_CLK_MIO0, EXT_CLK_MIO1, EXT_CLK_MIO2, EXT_CLK_MIO3, EXT_CLK_MIO4, EXT_CLK_MIO5, EXT_CLK_MIO6, EXT_CLK_MIO7, EXT_CLK_MIO8, EXT_CLK_MIO9, EXT_CLK_MIO10, EXT_CLK_MIO11, EXT_CLK_MIO12, EXT_CLK_MIO13, EXT_CLK_MIO14, EXT_CLK_MIO15, EXT_CLK_MIO16, EXT_CLK_MIO17, EXT_CLK_MIO18, EXT_CLK_MIO19, EXT_CLK_MIO20, EXT_CLK_MIO21, EXT_CLK_MIO22, EXT_CLK_MIO23, EXT_CLK_MIO24, EXT_CLK_MIO25, EXT_CLK_MIO26, EXT_CLK_MIO27, EXT_CLK_MIO28, EXT_CLK_MIO29, EXT_CLK_MIO30, EXT_CLK_MIO31, EXT_CLK_MIO32, EXT_CLK_MIO33, EXT_CLK_MIO34, EXT_CLK_MIO35, EXT_CLK_MIO36, EXT_CLK_MIO37, EXT_CLK_MIO38, EXT_CLK_MIO39, EXT_CLK_MIO40, EXT_CLK_MIO41, EXT_CLK_MIO42, EXT_CLK_MIO43, EXT_CLK_MIO44, EXT_CLK_MIO45, EXT_CLK_MIO46, EXT_CLK_MIO47, EXT_CLK_MIO48, EXT_CLK_MIO49, EXT_CLK_MIO50, EXT_CLK_MIO51, EXT_CLK_MIO52, EXT_CLK_MIO53, EXT_CLK_MIO54, EXT_CLK_MIO55, EXT_CLK_MIO56, EXT_CLK_MIO57, EXT_CLK_MIO58, EXT_CLK_MIO59, EXT_CLK_MIO60, EXT_CLK_MIO61, EXT_CLK_MIO62, EXT_CLK_MIO63, EXT_CLK_MIO64, EXT_CLK_MIO65, EXT_CLK_MIO66, EXT_CLK_MIO67, EXT_CLK_MIO68, EXT_CLK_MIO69, EXT_CLK_MIO70, EXT_CLK_MIO71, EXT_CLK_MIO72, EXT_CLK_MIO73, EXT_CLK_MIO74, EXT_CLK_MIO75, EXT_CLK_MIO76, EXT_CLK_MIO77, END_OF_CLKS, }; #define CLK_MAX (unsigned int)(END_OF_CLKS) //CLock types #define CLK_TYPE_OUTPUT 0U #define CLK_TYPE_EXTERNAL 1U //Topology types #define TYPE_INVALID 0U #define TYPE_MUX 1U #define TYPE_PLL 2U #define TYPE_FIXEDFACTOR 3U #define TYPE_DIV1 4U #define TYPE_DIV2 5U #define TYPE_GATE 6U struct pm_pll; struct pm_pll *pm_clock_get_pll(enum clock_id clock_id); struct pm_pll *pm_clock_get_pll_by_related_clk(enum clock_id clock_id); uint8_t pm_clock_has_div(unsigned int clock_id, enum pm_clock_div_id div_id); enum pm_ret_status pm_api_clock_get_name(unsigned int clock_id, char *name); enum pm_ret_status pm_api_clock_get_num_clocks(unsigned int *nclocks); enum pm_ret_status pm_api_clock_get_topology(unsigned int clock_id, unsigned int index, uint32_t *topology); enum pm_ret_status pm_api_clock_get_fixedfactor_params(unsigned int clock_id, uint32_t *mul, uint32_t *div); enum pm_ret_status pm_api_clock_get_parents(unsigned int clock_id, unsigned int index, uint32_t *parents); enum pm_ret_status pm_api_clock_get_attributes(unsigned int clock_id, uint32_t *attr); enum pm_ret_status pm_clock_get_pll_node_id(enum clock_id clock_id, enum pm_node_id *node_id); enum pm_ret_status pm_clock_id_is_valid(unsigned int clock_id); enum pm_ret_status pm_clock_pll_enable(struct pm_pll *pll); enum pm_ret_status pm_clock_pll_disable(struct pm_pll *pll); enum pm_ret_status pm_clock_pll_get_state(struct pm_pll *pll, unsigned int *state); enum pm_ret_status pm_clock_pll_set_parent(struct pm_pll *pll, enum clock_id clock_id, unsigned int parent_index); enum pm_ret_status pm_clock_pll_get_parent(struct pm_pll *pll, enum clock_id clock_id, unsigned int *parent_index); enum pm_ret_status pm_clock_set_pll_mode(enum clock_id clock_id, unsigned int mode); enum pm_ret_status pm_clock_get_pll_mode(enum clock_id clock_id, unsigned int *mode); #endif /* PM_API_CLOCK_H */ trusted-firmware-a-2.2/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.c000066400000000000000000000406021355360272700256630ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * ZynqMP system level PM-API functions for ioctl. */ #include #include #include #include #include #include "pm_api_clock.h" #include "pm_api_ioctl.h" #include "pm_api_sys.h" #include "pm_client.h" #include "pm_common.h" #include "pm_ipi.h" /** * pm_ioctl_get_rpu_oper_mode () - Get current RPU operation mode * @mode Buffer to store value of oper mode(Split/Lock-step) * * This function provides current configured RPU operational mode. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_get_rpu_oper_mode(unsigned int *mode) { unsigned int val; val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL); val &= ZYNQMP_SLSPLIT_MASK; if (val == 0) *mode = PM_RPU_MODE_LOCKSTEP; else *mode = PM_RPU_MODE_SPLIT; return PM_RET_SUCCESS; } /** * pm_ioctl_set_rpu_oper_mode () - Configure RPU operation mode * @mode Value to set for oper mode(Split/Lock-step) * * This function configures RPU operational mode(Split/Lock-step). * It also sets TCM combined mode in RPU lock-step and TCM non-combined * mode for RPU split mode. In case of Lock step mode, RPU1's output is * clamped. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_set_rpu_oper_mode(unsigned int mode) { unsigned int val; if (mmio_read_32(CRL_APB_RST_LPD_TOP) && CRL_APB_RPU_AMBA_RESET) return PM_RET_ERROR_ACCESS; val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL); if (mode == PM_RPU_MODE_SPLIT) { val |= ZYNQMP_SLSPLIT_MASK; val &= ~ZYNQMP_TCM_COMB_MASK; val &= ~ZYNQMP_SLCLAMP_MASK; } else if (mode == PM_RPU_MODE_LOCKSTEP) { val &= ~ZYNQMP_SLSPLIT_MASK; val |= ZYNQMP_TCM_COMB_MASK; val |= ZYNQMP_SLCLAMP_MASK; } else { return PM_RET_ERROR_ARGS; } mmio_write_32(ZYNQMP_RPU_GLBL_CNTL, val); return PM_RET_SUCCESS; } /** * pm_ioctl_config_boot_addr() - Configure RPU boot address * @nid Node ID of RPU * @value Value to set for boot address (TCM/OCM) * * This function configures RPU boot address(memory). * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_config_boot_addr(enum pm_node_id nid, unsigned int value) { unsigned int rpu_cfg_addr, val; if (nid == NODE_RPU_0) rpu_cfg_addr = ZYNQMP_RPU0_CFG; else if (nid == NODE_RPU_1) rpu_cfg_addr = ZYNQMP_RPU1_CFG; else return PM_RET_ERROR_ARGS; val = mmio_read_32(rpu_cfg_addr); if (value == PM_RPU_BOOTMEM_LOVEC) val &= ~ZYNQMP_VINITHI_MASK; else if (value == PM_RPU_BOOTMEM_HIVEC) val |= ZYNQMP_VINITHI_MASK; else return PM_RET_ERROR_ARGS; mmio_write_32(rpu_cfg_addr, val); return PM_RET_SUCCESS; } /** * pm_ioctl_config_tcm_comb() - Configure TCM combined mode * @value Value to set (Split/Combined) * * This function configures TCM to be in split mode or combined * mode. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_config_tcm_comb(unsigned int value) { unsigned int val; val = mmio_read_32(ZYNQMP_RPU_GLBL_CNTL); if (value == PM_RPU_TCM_SPLIT) val &= ~ZYNQMP_TCM_COMB_MASK; else if (value == PM_RPU_TCM_COMB) val |= ZYNQMP_TCM_COMB_MASK; else return PM_RET_ERROR_ARGS; mmio_write_32(ZYNQMP_RPU_GLBL_CNTL, val); return PM_RET_SUCCESS; } /** * pm_ioctl_set_tapdelay_bypass() - Enable/Disable tap delay bypass * @type Type of tap delay to enable/disable (e.g. QSPI) * @value Enable/Disable * * This function enable/disable tap delay bypass. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_set_tapdelay_bypass(unsigned int type, unsigned int value) { if ((value != PM_TAPDELAY_BYPASS_ENABLE && value != PM_TAPDELAY_BYPASS_DISABLE) || type >= PM_TAPDELAY_MAX) return PM_RET_ERROR_ARGS; return pm_mmio_write(IOU_TAPDLY_BYPASS, TAP_DELAY_MASK, value << type); } /** * pm_ioctl_set_sgmii_mode() - Set SGMII mode for the GEM device * @nid Node ID of the device * @value Enable/Disable * * This function enable/disable SGMII mode for the GEM device. * While enabling SGMII mode, it also ties the GEM PCS Signal * Detect to 1 and selects EMIO for RX clock generation. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_set_sgmii_mode(enum pm_node_id nid, unsigned int value) { unsigned int val, mask, shift; enum pm_ret_status ret; if (value != PM_SGMII_DISABLE && value != PM_SGMII_ENABLE) return PM_RET_ERROR_ARGS; switch (nid) { case NODE_ETH_0: shift = 0; break; case NODE_ETH_1: shift = 1; break; case NODE_ETH_2: shift = 2; break; case NODE_ETH_3: shift = 3; break; default: return PM_RET_ERROR_ARGS; } if (value == PM_SGMII_DISABLE) { mask = GEM_SGMII_MASK << GEM_CLK_CTRL_OFFSET * shift; ret = pm_mmio_write(IOU_GEM_CLK_CTRL, mask, 0U); } else { /* Tie the GEM PCS Signal Detect to 1 */ mask = SGMII_SD_MASK << SGMII_SD_OFFSET * shift; val = SGMII_PCS_SD_1 << SGMII_SD_OFFSET * shift; ret = pm_mmio_write(IOU_GEM_CTRL, mask, val); if (ret != PM_RET_SUCCESS) return ret; /* Set the GEM to SGMII mode */ mask = GEM_CLK_CTRL_MASK << GEM_CLK_CTRL_OFFSET * shift; val = GEM_RX_SRC_SEL_GTR | GEM_SGMII_MODE; val <<= GEM_CLK_CTRL_OFFSET * shift; ret = pm_mmio_write(IOU_GEM_CLK_CTRL, mask, val); } return ret; } /** * pm_ioctl_sd_dll_reset() - Reset DLL logic * @nid Node ID of the device * @type Reset type * * This function resets DLL logic for the SD device. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_sd_dll_reset(enum pm_node_id nid, unsigned int type) { unsigned int mask, val; enum pm_ret_status ret; if (nid == NODE_SD_0) { mask = ZYNQMP_SD0_DLL_RST_MASK; val = ZYNQMP_SD0_DLL_RST; } else if (nid == NODE_SD_1) { mask = ZYNQMP_SD1_DLL_RST_MASK; val = ZYNQMP_SD1_DLL_RST; } else { return PM_RET_ERROR_ARGS; } switch (type) { case PM_DLL_RESET_ASSERT: case PM_DLL_RESET_PULSE: ret = pm_mmio_write(ZYNQMP_SD_DLL_CTRL, mask, val); if (ret != PM_RET_SUCCESS) return ret; if (type == PM_DLL_RESET_ASSERT) break; mdelay(1); /* Fallthrough */ case PM_DLL_RESET_RELEASE: ret = pm_mmio_write(ZYNQMP_SD_DLL_CTRL, mask, 0); break; default: ret = PM_RET_ERROR_ARGS; break; } return ret; } /** * pm_ioctl_sd_set_tapdelay() - Set tap delay for the SD device * @nid Node ID of the device * @type Type of tap delay to set (input/output) * @value Value to set fot the tap delay * * This function sets input/output tap delay for the SD device. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_sd_set_tapdelay(enum pm_node_id nid, enum tap_delay_type type, unsigned int value) { unsigned int shift; enum pm_ret_status ret; if (nid == NODE_SD_0) shift = 0; else if (nid == NODE_SD_1) shift = ZYNQMP_SD_TAP_OFFSET; else return PM_RET_ERROR_ARGS; ret = pm_ioctl_sd_dll_reset(nid, PM_DLL_RESET_ASSERT); if (ret != PM_RET_SUCCESS) return ret; if (type == PM_TAPDELAY_INPUT) { ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY, (ZYNQMP_SD_ITAPCHGWIN_MASK << shift), (ZYNQMP_SD_ITAPCHGWIN << shift)); if (ret != PM_RET_SUCCESS) goto reset_release; ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY, (ZYNQMP_SD_ITAPDLYENA_MASK << shift), (ZYNQMP_SD_ITAPDLYENA << shift)); if (ret != PM_RET_SUCCESS) goto reset_release; ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY, (ZYNQMP_SD_ITAPDLYSEL_MASK << shift), (value << shift)); if (ret != PM_RET_SUCCESS) goto reset_release; ret = pm_mmio_write(ZYNQMP_SD_ITAP_DLY, (ZYNQMP_SD_ITAPCHGWIN_MASK << shift), 0); } else if (type == PM_TAPDELAY_OUTPUT) { ret = pm_mmio_write(ZYNQMP_SD_OTAP_DLY, (ZYNQMP_SD_OTAPDLYENA_MASK << shift), (ZYNQMP_SD_OTAPDLYENA << shift)); if (ret != PM_RET_SUCCESS) goto reset_release; ret = pm_mmio_write(ZYNQMP_SD_OTAP_DLY, (ZYNQMP_SD_OTAPDLYSEL_MASK << shift), (value << shift)); } else { ret = PM_RET_ERROR_ARGS; } reset_release: pm_ioctl_sd_dll_reset(nid, PM_DLL_RESET_RELEASE); return ret; } /** * pm_ioctl_set_pll_frac_mode() - Ioctl function for * setting pll mode * @pll PLL clock id * @mode Mode fraction/integar * * This function sets PLL mode * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_set_pll_frac_mode (unsigned int pll, unsigned int mode) { return pm_clock_set_pll_mode(pll, mode); } /** * pm_ioctl_get_pll_frac_mode() - Ioctl function for * getting pll mode * @pll PLL clock id * @mode Mode fraction/integar * * This function return current PLL mode * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_get_pll_frac_mode (unsigned int pll, unsigned int *mode) { return pm_clock_get_pll_mode(pll, mode); } /** * pm_ioctl_set_pll_frac_data() - Ioctl function for * setting pll fraction data * @pll PLL clock id * @data fraction data * * This function sets fraction data. * It is valid for fraction mode only. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_set_pll_frac_data (unsigned int pll, unsigned int data) { enum pm_node_id pll_nid; enum pm_ret_status status; /* Get PLL node ID using PLL clock ID */ status = pm_clock_get_pll_node_id(pll, &pll_nid); if (status != PM_RET_SUCCESS) return status; return pm_pll_set_parameter(pll_nid, PM_PLL_PARAM_DATA, data); } /** * pm_ioctl_get_pll_frac_data() - Ioctl function for * getting pll fraction data * @pll PLL clock id * @data fraction data * * This function returns fraction data value. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_get_pll_frac_data (unsigned int pll, unsigned int *data) { enum pm_node_id pll_nid; enum pm_ret_status status; /* Get PLL node ID using PLL clock ID */ status = pm_clock_get_pll_node_id(pll, &pll_nid); if (status != PM_RET_SUCCESS) return status; return pm_pll_get_parameter(pll_nid, PM_PLL_PARAM_DATA, data); } /** * pm_ioctl_write_ggs() - Ioctl function for writing * global general storage (ggs) * @index GGS register index * @value Register value to be written * * This function writes value to GGS register. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_write_ggs(unsigned int index, unsigned int value) { if (index >= GGS_NUM_REGS) return PM_RET_ERROR_ARGS; return pm_mmio_write(GGS_BASEADDR + (index << 2), 0xFFFFFFFFU, value); } /** * pm_ioctl_read_ggs() - Ioctl function for reading * global general storage (ggs) * @index GGS register index * @value Register value * * This function returns GGS register value. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_read_ggs(unsigned int index, unsigned int *value) { if (index >= GGS_NUM_REGS) return PM_RET_ERROR_ARGS; return pm_mmio_read(GGS_BASEADDR + (index << 2), value); } /** * pm_ioctl_write_pggs() - Ioctl function for writing persistent * global general storage (pggs) * @index PGGS register index * @value Register value to be written * * This function writes value to PGGS register. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_write_pggs(unsigned int index, unsigned int value) { if (index >= PGGS_NUM_REGS) return PM_RET_ERROR_ARGS; return pm_mmio_write(PGGS_BASEADDR + (index << 2), 0xFFFFFFFFU, value); } /** * pm_ioctl_afi() - Ioctl function for writing afi values * * @index AFI register index * @value Register value to be written * * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_afi(unsigned int index, unsigned int value) { unsigned int mask; unsigned int regarr[] = {0xFD360000, 0xFD360014, 0xFD370000, 0xFD370014, 0xFD380000, 0xFD380014, 0xFD390000, 0xFD390014, 0xFD3a0000, 0xFD3a0014, 0xFD3b0000, 0xFD3b0014, 0xFF9b0000, 0xFF9b0014, 0xFD615000, 0xFF419000, }; if (index >= ARRAY_SIZE(regarr)) return PM_RET_ERROR_ARGS; if (index < AFIFM6_WRCTRL) mask = FABRIC_WIDTH; else mask = 0xf00; return pm_mmio_write(regarr[index], mask, value); } /** * pm_ioctl_read_pggs() - Ioctl function for reading persistent * global general storage (pggs) * @index PGGS register index * @value Register value * * This function returns PGGS register value. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_read_pggs(unsigned int index, unsigned int *value) { if (index >= PGGS_NUM_REGS) return PM_RET_ERROR_ARGS; return pm_mmio_read(PGGS_BASEADDR + (index << 2), value); } /** * pm_ioctl_ulpi_reset() - Ioctl function for performing ULPI reset * * This function peerforms the ULPI reset sequence for resetting * the ULPI transceiver. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_ulpi_reset(void) { enum pm_ret_status ret; ret = pm_mmio_write(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOT_PIN_MASK, ZYNQMP_ULPI_RESET_VAL_HIGH); if (ret != PM_RET_SUCCESS) return ret; /* Drive ULPI assert for atleast 1ms */ mdelay(1); ret = pm_mmio_write(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOT_PIN_MASK, ZYNQMP_ULPI_RESET_VAL_LOW); if (ret != PM_RET_SUCCESS) return ret; /* Drive ULPI de-assert for atleast 1ms */ mdelay(1); ret = pm_mmio_write(CRL_APB_BOOT_PIN_CTRL, CRL_APB_BOOT_PIN_MASK, ZYNQMP_ULPI_RESET_VAL_HIGH); return ret; } /** * pm_ioctl_set_boot_health_status() - Ioctl for setting healthy boot status * * This function sets healthy bit value to indicate boot health status * to firmware. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_ioctl_set_boot_health_status(unsigned int value) { return pm_mmio_write(PM_BOOT_HEALTH_STATUS_REG, PM_BOOT_HEALTH_STATUS_MASK, value); } /** * pm_api_ioctl() - PM IOCTL API for device control and configs * @node_id Node ID of the device * @ioctl_id ID of the requested IOCTL * @arg1 Argument 1 to requested IOCTL call * @arg2 Argument 2 to requested IOCTL call * @value Returned output value * * This function calls IOCTL to firmware for device control and configuration. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_api_ioctl(enum pm_node_id nid, unsigned int ioctl_id, unsigned int arg1, unsigned int arg2, unsigned int *value) { enum pm_ret_status ret; switch (ioctl_id) { case IOCTL_GET_RPU_OPER_MODE: ret = pm_ioctl_get_rpu_oper_mode(value); break; case IOCTL_SET_RPU_OPER_MODE: ret = pm_ioctl_set_rpu_oper_mode(arg1); break; case IOCTL_RPU_BOOT_ADDR_CONFIG: ret = pm_ioctl_config_boot_addr(nid, arg1); break; case IOCTL_TCM_COMB_CONFIG: ret = pm_ioctl_config_tcm_comb(arg1); break; case IOCTL_SET_TAPDELAY_BYPASS: ret = pm_ioctl_set_tapdelay_bypass(arg1, arg2); break; case IOCTL_SET_SGMII_MODE: ret = pm_ioctl_set_sgmii_mode(nid, arg1); break; case IOCTL_SD_DLL_RESET: ret = pm_ioctl_sd_dll_reset(nid, arg1); break; case IOCTL_SET_SD_TAPDELAY: ret = pm_ioctl_sd_set_tapdelay(nid, arg1, arg2); break; case IOCTL_SET_PLL_FRAC_MODE: ret = pm_ioctl_set_pll_frac_mode(arg1, arg2); break; case IOCTL_GET_PLL_FRAC_MODE: ret = pm_ioctl_get_pll_frac_mode(arg1, value); break; case IOCTL_SET_PLL_FRAC_DATA: ret = pm_ioctl_set_pll_frac_data(arg1, arg2); break; case IOCTL_GET_PLL_FRAC_DATA: ret = pm_ioctl_get_pll_frac_data(arg1, value); break; case IOCTL_WRITE_GGS: ret = pm_ioctl_write_ggs(arg1, arg2); break; case IOCTL_READ_GGS: ret = pm_ioctl_read_ggs(arg1, value); break; case IOCTL_WRITE_PGGS: ret = pm_ioctl_write_pggs(arg1, arg2); break; case IOCTL_READ_PGGS: ret = pm_ioctl_read_pggs(arg1, value); break; case IOCTL_ULPI_RESET: ret = pm_ioctl_ulpi_reset(); break; case IOCTL_SET_BOOT_HEALTH_STATUS: ret = pm_ioctl_set_boot_health_status(arg1); break; case IOCTL_AFI: ret = pm_ioctl_afi(arg1, arg2); break; default: ret = PM_RET_ERROR_NOTSUPPORTED; break; } return ret; } trusted-firmware-a-2.2/plat/xilinx/zynqmp/pm_service/pm_api_ioctl.h000066400000000000000000000032661355360272700256750ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * ZynqMP system level PM-API functions for pin control. */ #ifndef PM_API_IOCTL_H #define PM_API_IOCTL_H #include "pm_common.h" //ioctl id enum { IOCTL_GET_RPU_OPER_MODE, IOCTL_SET_RPU_OPER_MODE, IOCTL_RPU_BOOT_ADDR_CONFIG, IOCTL_TCM_COMB_CONFIG, IOCTL_SET_TAPDELAY_BYPASS, IOCTL_SET_SGMII_MODE, IOCTL_SD_DLL_RESET, IOCTL_SET_SD_TAPDELAY, /* Ioctl for clock driver */ IOCTL_SET_PLL_FRAC_MODE, IOCTL_GET_PLL_FRAC_MODE, IOCTL_SET_PLL_FRAC_DATA, IOCTL_GET_PLL_FRAC_DATA, IOCTL_WRITE_GGS, IOCTL_READ_GGS, IOCTL_WRITE_PGGS, IOCTL_READ_PGGS, /* IOCTL for ULPI reset */ IOCTL_ULPI_RESET, /* Set healthy bit value */ IOCTL_SET_BOOT_HEALTH_STATUS, IOCTL_AFI, }; //RPU operation mode #define PM_RPU_MODE_LOCKSTEP 0U #define PM_RPU_MODE_SPLIT 1U //RPU boot mem #define PM_RPU_BOOTMEM_LOVEC 0U #define PM_RPU_BOOTMEM_HIVEC 1U //RPU tcm mpde #define PM_RPU_TCM_SPLIT 0U #define PM_RPU_TCM_COMB 1U //tap delay signal type #define PM_TAPDELAY_NAND_DQS_IN 0U #define PM_TAPDELAY_NAND_DQS_OUT 1U #define PM_TAPDELAY_QSPI 2U #define PM_TAPDELAY_MAX 3U //tap delay bypass #define PM_TAPDELAY_BYPASS_DISABLE 0U #define PM_TAPDELAY_BYPASS_ENABLE 1U //sgmii mode #define PM_SGMII_DISABLE 0U #define PM_SGMII_ENABLE 1U enum tap_delay_type { PM_TAPDELAY_INPUT, PM_TAPDELAY_OUTPUT, }; //dll reset type #define PM_DLL_RESET_ASSERT 0U #define PM_DLL_RESET_RELEASE 1U #define PM_DLL_RESET_PULSE 2U enum pm_ret_status pm_api_ioctl(enum pm_node_id nid, unsigned int ioctl_id, unsigned int arg1, unsigned int arg2, unsigned int *value); #endif /* PM_API_IOCTL_H */ trusted-firmware-a-2.2/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.c000066400000000000000000002140451355360272700262300ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * ZynqMP system level PM-API functions for pin control. */ #include #include #include #include "pm_api_pinctrl.h" #include "pm_api_sys.h" #include "pm_client.h" #include "pm_common.h" #include "pm_ipi.h" #define PINCTRL_FUNCTION_MASK U(0xFE) #define PINCTRL_VOLTAGE_STATUS_MASK U(0x01) #define NFUNCS_PER_PIN U(13) #define PINCTRL_NUM_MIOS U(78) #define MAX_PIN_PER_REG U(26) #define PINCTRL_BANK_ADDR_STEP U(28) #define PINCTRL_DRVSTRN0_REG_OFFSET U(0) #define PINCTRL_DRVSTRN1_REG_OFFSET U(4) #define PINCTRL_SCHCMOS_REG_OFFSET U(8) #define PINCTRL_PULLCTRL_REG_OFFSET U(12) #define PINCTRL_PULLSTAT_REG_OFFSET U(16) #define PINCTRL_SLEWCTRL_REG_OFFSET U(20) #define PINCTRL_VOLTAGE_STAT_REG_OFFSET U(24) #define IOU_SLCR_BANK1_CTRL5 U(0XFF180164) #define PINCTRL_CFG_ADDR_OFFSET(addr, reg, miopin) \ ((addr) + 4 * PINCTRL_NUM_MIOS + PINCTRL_BANK_ADDR_STEP * \ ((miopin) / MAX_PIN_PER_REG) + (reg)) #define PINCTRL_PIN_OFFSET(_miopin) \ ((_miopin) - (MAX_PIN_PER_REG * ((_miopin) / MAX_PIN_PER_REG))) #define PINCTRL_REGVAL_TO_PIN_CONFIG(_pin, _val) \ (((_val) >> PINCTRL_PIN_OFFSET(_pin)) & 0x1) static uint8_t pm_pinctrl_mux[NFUNCS_PER_PIN] = { 0x02, 0x04, 0x08, 0x10, 0x18, 0x00, 0x20, 0x40, 0x60, 0x80, 0xA0, 0xC0, 0xE0 }; struct pinctrl_function { char name[FUNCTION_NAME_LEN]; uint16_t (*groups)[]; uint8_t regval; }; /* Max groups for one pin */ #define MAX_PIN_GROUPS U(13) struct zynqmp_pin_group { uint16_t (*groups)[]; }; static struct pinctrl_function pinctrl_functions[MAX_FUNCTION] = { [PINCTRL_FUNC_CAN0] = { .name = "can0", .regval = 0x20, .groups = &((uint16_t []) { PINCTRL_GRP_CAN0_0, PINCTRL_GRP_CAN0_1, PINCTRL_GRP_CAN0_2, PINCTRL_GRP_CAN0_3, PINCTRL_GRP_CAN0_4, PINCTRL_GRP_CAN0_5, PINCTRL_GRP_CAN0_6, PINCTRL_GRP_CAN0_7, PINCTRL_GRP_CAN0_8, PINCTRL_GRP_CAN0_9, PINCTRL_GRP_CAN0_10, PINCTRL_GRP_CAN0_11, PINCTRL_GRP_CAN0_12, PINCTRL_GRP_CAN0_13, PINCTRL_GRP_CAN0_14, PINCTRL_GRP_CAN0_15, PINCTRL_GRP_CAN0_16, PINCTRL_GRP_CAN0_17, PINCTRL_GRP_CAN0_18, END_OF_GROUPS, }), }, [PINCTRL_FUNC_CAN1] = { .name = "can1", .regval = 0x20, .groups = &((uint16_t []) { PINCTRL_GRP_CAN1_0, PINCTRL_GRP_CAN1_1, PINCTRL_GRP_CAN1_2, PINCTRL_GRP_CAN1_3, PINCTRL_GRP_CAN1_4, PINCTRL_GRP_CAN1_5, PINCTRL_GRP_CAN1_6, PINCTRL_GRP_CAN1_7, PINCTRL_GRP_CAN1_8, PINCTRL_GRP_CAN1_9, PINCTRL_GRP_CAN1_10, PINCTRL_GRP_CAN1_11, PINCTRL_GRP_CAN1_12, PINCTRL_GRP_CAN1_13, PINCTRL_GRP_CAN1_14, PINCTRL_GRP_CAN1_15, PINCTRL_GRP_CAN1_16, PINCTRL_GRP_CAN1_17, PINCTRL_GRP_CAN1_18, PINCTRL_GRP_CAN1_19, END_OF_GROUPS, }), }, [PINCTRL_FUNC_ETHERNET0] = { .name = "ethernet0", .regval = 0x02, .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET0_0, END_OF_GROUPS, }), }, [PINCTRL_FUNC_ETHERNET1] = { .name = "ethernet1", .regval = 0x02, .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET1_0, END_OF_GROUPS, }), }, [PINCTRL_FUNC_ETHERNET2] = { .name = "ethernet2", .regval = 0x02, .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET2_0, END_OF_GROUPS, }), }, [PINCTRL_FUNC_ETHERNET3] = { .name = "ethernet3", .regval = 0x02, .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET3_0, END_OF_GROUPS, }), }, [PINCTRL_FUNC_GEMTSU0] = { .name = "gemtsu0", .regval = 0x02, .groups = &((uint16_t []) { PINCTRL_GRP_GEMTSU0_0, PINCTRL_GRP_GEMTSU0_1, PINCTRL_GRP_GEMTSU0_2, END_OF_GROUPS, }), }, [PINCTRL_FUNC_GPIO0] = { .name = "gpio0", .regval = 0x00, .groups = &((uint16_t []) { PINCTRL_GRP_GPIO0_0, PINCTRL_GRP_GPIO0_1, PINCTRL_GRP_GPIO0_2, PINCTRL_GRP_GPIO0_3, PINCTRL_GRP_GPIO0_4, PINCTRL_GRP_GPIO0_5, PINCTRL_GRP_GPIO0_6, PINCTRL_GRP_GPIO0_7, PINCTRL_GRP_GPIO0_8, PINCTRL_GRP_GPIO0_9, PINCTRL_GRP_GPIO0_10, PINCTRL_GRP_GPIO0_11, PINCTRL_GRP_GPIO0_12, PINCTRL_GRP_GPIO0_13, PINCTRL_GRP_GPIO0_14, PINCTRL_GRP_GPIO0_15, PINCTRL_GRP_GPIO0_16, PINCTRL_GRP_GPIO0_17, PINCTRL_GRP_GPIO0_18, PINCTRL_GRP_GPIO0_19, PINCTRL_GRP_GPIO0_20, PINCTRL_GRP_GPIO0_21, PINCTRL_GRP_GPIO0_22, PINCTRL_GRP_GPIO0_23, PINCTRL_GRP_GPIO0_24, PINCTRL_GRP_GPIO0_25, PINCTRL_GRP_GPIO0_26, PINCTRL_GRP_GPIO0_27, PINCTRL_GRP_GPIO0_28, PINCTRL_GRP_GPIO0_29, PINCTRL_GRP_GPIO0_30, PINCTRL_GRP_GPIO0_31, PINCTRL_GRP_GPIO0_32, PINCTRL_GRP_GPIO0_33, PINCTRL_GRP_GPIO0_34, PINCTRL_GRP_GPIO0_35, PINCTRL_GRP_GPIO0_36, PINCTRL_GRP_GPIO0_37, PINCTRL_GRP_GPIO0_38, PINCTRL_GRP_GPIO0_39, PINCTRL_GRP_GPIO0_40, PINCTRL_GRP_GPIO0_41, PINCTRL_GRP_GPIO0_42, PINCTRL_GRP_GPIO0_43, PINCTRL_GRP_GPIO0_44, PINCTRL_GRP_GPIO0_45, PINCTRL_GRP_GPIO0_46, PINCTRL_GRP_GPIO0_47, PINCTRL_GRP_GPIO0_48, PINCTRL_GRP_GPIO0_49, PINCTRL_GRP_GPIO0_50, PINCTRL_GRP_GPIO0_51, PINCTRL_GRP_GPIO0_52, PINCTRL_GRP_GPIO0_53, PINCTRL_GRP_GPIO0_54, PINCTRL_GRP_GPIO0_55, PINCTRL_GRP_GPIO0_56, PINCTRL_GRP_GPIO0_57, PINCTRL_GRP_GPIO0_58, PINCTRL_GRP_GPIO0_59, PINCTRL_GRP_GPIO0_60, PINCTRL_GRP_GPIO0_61, PINCTRL_GRP_GPIO0_62, PINCTRL_GRP_GPIO0_63, PINCTRL_GRP_GPIO0_64, PINCTRL_GRP_GPIO0_65, PINCTRL_GRP_GPIO0_66, PINCTRL_GRP_GPIO0_67, PINCTRL_GRP_GPIO0_68, PINCTRL_GRP_GPIO0_69, PINCTRL_GRP_GPIO0_70, PINCTRL_GRP_GPIO0_71, PINCTRL_GRP_GPIO0_72, PINCTRL_GRP_GPIO0_73, PINCTRL_GRP_GPIO0_74, PINCTRL_GRP_GPIO0_75, PINCTRL_GRP_GPIO0_76, PINCTRL_GRP_GPIO0_77, END_OF_GROUPS, }), }, [PINCTRL_FUNC_I2C0] = { .name = "i2c0", .regval = 0x40, .groups = &((uint16_t []) { PINCTRL_GRP_I2C0_0, PINCTRL_GRP_I2C0_1, PINCTRL_GRP_I2C0_2, PINCTRL_GRP_I2C0_3, PINCTRL_GRP_I2C0_4, PINCTRL_GRP_I2C0_5, PINCTRL_GRP_I2C0_6, PINCTRL_GRP_I2C0_7, PINCTRL_GRP_I2C0_8, PINCTRL_GRP_I2C0_9, PINCTRL_GRP_I2C0_10, PINCTRL_GRP_I2C0_11, PINCTRL_GRP_I2C0_12, PINCTRL_GRP_I2C0_13, PINCTRL_GRP_I2C0_14, PINCTRL_GRP_I2C0_15, PINCTRL_GRP_I2C0_16, PINCTRL_GRP_I2C0_17, PINCTRL_GRP_I2C0_18, END_OF_GROUPS, }), }, [PINCTRL_FUNC_I2C1] = { .name = "i2c1", .regval = 0x40, .groups = &((uint16_t []) { PINCTRL_GRP_I2C1_0, PINCTRL_GRP_I2C1_1, PINCTRL_GRP_I2C1_2, PINCTRL_GRP_I2C1_3, PINCTRL_GRP_I2C1_4, PINCTRL_GRP_I2C1_5, PINCTRL_GRP_I2C1_6, PINCTRL_GRP_I2C1_7, PINCTRL_GRP_I2C1_8, PINCTRL_GRP_I2C1_9, PINCTRL_GRP_I2C1_10, PINCTRL_GRP_I2C1_11, PINCTRL_GRP_I2C1_12, PINCTRL_GRP_I2C1_13, PINCTRL_GRP_I2C1_14, PINCTRL_GRP_I2C1_15, PINCTRL_GRP_I2C1_16, PINCTRL_GRP_I2C1_17, PINCTRL_GRP_I2C1_18, PINCTRL_GRP_I2C1_19, END_OF_GROUPS, }), }, [PINCTRL_FUNC_MDIO0] = { .name = "mdio0", .regval = 0x60, .groups = &((uint16_t []) { PINCTRL_GRP_MDIO0_0, END_OF_GROUPS, }), }, [PINCTRL_FUNC_MDIO1] = { .name = "mdio1", .regval = 0x80, .groups = &((uint16_t []) { PINCTRL_GRP_MDIO1_0, PINCTRL_GRP_MDIO1_1, END_OF_GROUPS, }), }, [PINCTRL_FUNC_MDIO2] = { .name = "mdio2", .regval = 0xa0, .groups = &((uint16_t []) { PINCTRL_GRP_MDIO2_0, END_OF_GROUPS, }), }, [PINCTRL_FUNC_MDIO3] = { .name = "mdio3", .regval = 0xc0, .groups = &((uint16_t []) { PINCTRL_GRP_MDIO3_0, END_OF_GROUPS, }), }, [PINCTRL_FUNC_QSPI0] = { .name = "qspi0", .regval = 0x02, .groups = &((uint16_t []) { PINCTRL_GRP_QSPI0_0, END_OF_GROUPS, }), }, [PINCTRL_FUNC_QSPI_FBCLK] = { .name = "qspi_fbclk", .regval = 0x02, .groups = &((uint16_t []) { PINCTRL_GRP_QSPI_FBCLK, END_OF_GROUPS, }), }, [PINCTRL_FUNC_QSPI_SS] = { .name = "qspi_ss", .regval = 0x02, .groups = &((uint16_t []) { PINCTRL_GRP_QSPI_SS, END_OF_GROUPS, }), }, [PINCTRL_FUNC_SPI0] = { .name = "spi0", .regval = 0x80, .groups = &((uint16_t []) { PINCTRL_GRP_SPI0_0, PINCTRL_GRP_SPI0_1, PINCTRL_GRP_SPI0_2, PINCTRL_GRP_SPI0_3, PINCTRL_GRP_SPI0_4, PINCTRL_GRP_SPI0_5, END_OF_GROUPS, }), }, [PINCTRL_FUNC_SPI1] = { .name = "spi1", .regval = 0x80, .groups = &((uint16_t []) { PINCTRL_GRP_SPI1_0, PINCTRL_GRP_SPI1_1, PINCTRL_GRP_SPI1_2, PINCTRL_GRP_SPI1_3, PINCTRL_GRP_SPI1_4, PINCTRL_GRP_SPI1_5, END_OF_GROUPS, }), }, [PINCTRL_FUNC_SPI0_SS] = { .name = "spi0_ss", .regval = 0x80, .groups = &((uint16_t []) { PINCTRL_GRP_SPI0_0_SS0, PINCTRL_GRP_SPI0_0_SS1, PINCTRL_GRP_SPI0_0_SS2, PINCTRL_GRP_SPI0_1_SS0, PINCTRL_GRP_SPI0_1_SS1, PINCTRL_GRP_SPI0_1_SS2, PINCTRL_GRP_SPI0_2_SS0, PINCTRL_GRP_SPI0_2_SS1, PINCTRL_GRP_SPI0_2_SS2, PINCTRL_GRP_SPI0_3_SS0, PINCTRL_GRP_SPI0_3_SS1, PINCTRL_GRP_SPI0_3_SS2, PINCTRL_GRP_SPI0_4_SS0, PINCTRL_GRP_SPI0_4_SS1, PINCTRL_GRP_SPI0_4_SS2, PINCTRL_GRP_SPI0_5_SS0, PINCTRL_GRP_SPI0_5_SS1, PINCTRL_GRP_SPI0_5_SS2, END_OF_GROUPS, }), }, [PINCTRL_FUNC_SPI1_SS] = { .name = "spi1_ss", .regval = 0x80, .groups = &((uint16_t []) { PINCTRL_GRP_SPI1_0_SS0, PINCTRL_GRP_SPI1_0_SS1, PINCTRL_GRP_SPI1_0_SS2, PINCTRL_GRP_SPI1_1_SS0, PINCTRL_GRP_SPI1_1_SS1, PINCTRL_GRP_SPI1_1_SS2, PINCTRL_GRP_SPI1_2_SS0, PINCTRL_GRP_SPI1_2_SS1, PINCTRL_GRP_SPI1_2_SS2, PINCTRL_GRP_SPI1_3_SS0, PINCTRL_GRP_SPI1_3_SS1, PINCTRL_GRP_SPI1_3_SS2, PINCTRL_GRP_SPI1_4_SS0, PINCTRL_GRP_SPI1_4_SS1, PINCTRL_GRP_SPI1_4_SS2, PINCTRL_GRP_SPI1_5_SS0, PINCTRL_GRP_SPI1_5_SS1, PINCTRL_GRP_SPI1_5_SS2, END_OF_GROUPS, }), }, [PINCTRL_FUNC_SDIO0] = { .name = "sdio0", .regval = 0x08, .groups = &((uint16_t []) { PINCTRL_GRP_SDIO0_0, PINCTRL_GRP_SDIO0_1, PINCTRL_GRP_SDIO0_2, PINCTRL_GRP_SDIO0_4BIT_0_0, PINCTRL_GRP_SDIO0_4BIT_0_1, PINCTRL_GRP_SDIO0_4BIT_1_0, PINCTRL_GRP_SDIO0_4BIT_1_1, PINCTRL_GRP_SDIO0_4BIT_2_0, PINCTRL_GRP_SDIO0_4BIT_2_1, PINCTRL_GRP_SDIO0_1BIT_0_0, PINCTRL_GRP_SDIO0_1BIT_0_1, PINCTRL_GRP_SDIO0_1BIT_0_2, PINCTRL_GRP_SDIO0_1BIT_0_3, PINCTRL_GRP_SDIO0_1BIT_0_4, PINCTRL_GRP_SDIO0_1BIT_0_5, PINCTRL_GRP_SDIO0_1BIT_0_6, PINCTRL_GRP_SDIO0_1BIT_0_7, PINCTRL_GRP_SDIO0_1BIT_1_0, PINCTRL_GRP_SDIO0_1BIT_1_1, PINCTRL_GRP_SDIO0_1BIT_1_2, PINCTRL_GRP_SDIO0_1BIT_1_3, PINCTRL_GRP_SDIO0_1BIT_1_4, PINCTRL_GRP_SDIO0_1BIT_1_5, PINCTRL_GRP_SDIO0_1BIT_1_6, PINCTRL_GRP_SDIO0_1BIT_1_7, PINCTRL_GRP_SDIO0_1BIT_2_0, PINCTRL_GRP_SDIO0_1BIT_2_1, PINCTRL_GRP_SDIO0_1BIT_2_2, PINCTRL_GRP_SDIO0_1BIT_2_3, PINCTRL_GRP_SDIO0_1BIT_2_4, PINCTRL_GRP_SDIO0_1BIT_2_5, PINCTRL_GRP_SDIO0_1BIT_2_6, PINCTRL_GRP_SDIO0_1BIT_2_7, END_OF_GROUPS, }), }, [PINCTRL_FUNC_SDIO0_PC] = { .name = "sdio0_pc", .regval = 0x08, .groups = &((uint16_t []) { PINCTRL_GRP_SDIO0_0_PC, PINCTRL_GRP_SDIO0_1_PC, PINCTRL_GRP_SDIO0_2_PC, END_OF_GROUPS, }), }, [PINCTRL_FUNC_SDIO0_CD] = { .name = "sdio0_cd", .regval = 0x08, .groups = &((uint16_t []) { PINCTRL_GRP_SDIO0_0_CD, PINCTRL_GRP_SDIO0_1_CD, PINCTRL_GRP_SDIO0_2_CD, END_OF_GROUPS, }), }, [PINCTRL_FUNC_SDIO0_WP] = { .name = "sdio0_wp", .regval = 0x08, .groups = &((uint16_t []) { PINCTRL_GRP_SDIO0_0_WP, PINCTRL_GRP_SDIO0_1_WP, PINCTRL_GRP_SDIO0_2_WP, END_OF_GROUPS, }), }, [PINCTRL_FUNC_SDIO1] = { .name = "sdio1", .regval = 0x10, .groups = &((uint16_t []) { PINCTRL_GRP_SDIO1_0, PINCTRL_GRP_SDIO1_4BIT_0_0, PINCTRL_GRP_SDIO1_4BIT_0_1, PINCTRL_GRP_SDIO1_4BIT_1_0, PINCTRL_GRP_SDIO1_1BIT_0_0, PINCTRL_GRP_SDIO1_1BIT_0_1, PINCTRL_GRP_SDIO1_1BIT_0_2, PINCTRL_GRP_SDIO1_1BIT_0_3, PINCTRL_GRP_SDIO1_1BIT_0_4, PINCTRL_GRP_SDIO1_1BIT_0_5, PINCTRL_GRP_SDIO1_1BIT_0_6, PINCTRL_GRP_SDIO1_1BIT_0_7, PINCTRL_GRP_SDIO1_1BIT_1_0, PINCTRL_GRP_SDIO1_1BIT_1_1, PINCTRL_GRP_SDIO1_1BIT_1_2, PINCTRL_GRP_SDIO1_1BIT_1_3, END_OF_GROUPS, }), }, [PINCTRL_FUNC_SDIO1_PC] = { .name = "sdio1_pc", .regval = 0x10, .groups = &((uint16_t []) { PINCTRL_GRP_SDIO1_0_PC, PINCTRL_GRP_SDIO1_1_PC, END_OF_GROUPS, }), }, [PINCTRL_FUNC_SDIO1_CD] = { .name = "sdio1_cd", .regval = 0x10, .groups = &((uint16_t []) { PINCTRL_GRP_SDIO1_0_CD, PINCTRL_GRP_SDIO1_1_CD, END_OF_GROUPS, }), }, [PINCTRL_FUNC_SDIO1_WP] = { .name = "sdio1_wp", .regval = 0x10, .groups = &((uint16_t []) { PINCTRL_GRP_SDIO1_0_WP, PINCTRL_GRP_SDIO1_1_WP, END_OF_GROUPS, }), }, [PINCTRL_FUNC_NAND0] = { .name = "nand0", .regval = 0x04, .groups = &((uint16_t []) { PINCTRL_GRP_NAND0_0, END_OF_GROUPS, }), }, [PINCTRL_FUNC_NAND0_CE] = { .name = "nand0_ce", .regval = 0x04, .groups = &((uint16_t []) { PINCTRL_GRP_NAND0_0_CE, PINCTRL_GRP_NAND0_1_CE, END_OF_GROUPS, }), }, [PINCTRL_FUNC_NAND0_RB] = { .name = "nand0_rb", .regval = 0x04, .groups = &((uint16_t []) { PINCTRL_GRP_NAND0_0_RB, PINCTRL_GRP_NAND0_1_RB, END_OF_GROUPS, }), }, [PINCTRL_FUNC_NAND0_DQS] = { .name = "nand0_dqs", .regval = 0x04, .groups = &((uint16_t []) { PINCTRL_GRP_NAND0_0_DQS, PINCTRL_GRP_NAND0_1_DQS, END_OF_GROUPS, }), }, [PINCTRL_FUNC_TTC0_CLK] = { .name = "ttc0_clk", .regval = 0xa0, .groups = &((uint16_t []) { PINCTRL_GRP_TTC0_0_CLK, PINCTRL_GRP_TTC0_1_CLK, PINCTRL_GRP_TTC0_2_CLK, PINCTRL_GRP_TTC0_3_CLK, PINCTRL_GRP_TTC0_4_CLK, PINCTRL_GRP_TTC0_5_CLK, PINCTRL_GRP_TTC0_6_CLK, PINCTRL_GRP_TTC0_7_CLK, PINCTRL_GRP_TTC0_8_CLK, END_OF_GROUPS, }), }, [PINCTRL_FUNC_TTC0_WAV] = { .name = "ttc0_wav", .regval = 0xa0, .groups = &((uint16_t []) { PINCTRL_GRP_TTC0_0_WAV, PINCTRL_GRP_TTC0_1_WAV, PINCTRL_GRP_TTC0_2_WAV, PINCTRL_GRP_TTC0_3_WAV, PINCTRL_GRP_TTC0_4_WAV, PINCTRL_GRP_TTC0_5_WAV, PINCTRL_GRP_TTC0_6_WAV, PINCTRL_GRP_TTC0_7_WAV, PINCTRL_GRP_TTC0_8_WAV, END_OF_GROUPS, }), }, [PINCTRL_FUNC_TTC1_CLK] = { .name = "ttc1_clk", .regval = 0xa0, .groups = &((uint16_t []) { PINCTRL_GRP_TTC1_0_CLK, PINCTRL_GRP_TTC1_1_CLK, PINCTRL_GRP_TTC1_2_CLK, PINCTRL_GRP_TTC1_3_CLK, PINCTRL_GRP_TTC1_4_CLK, PINCTRL_GRP_TTC1_5_CLK, PINCTRL_GRP_TTC1_6_CLK, PINCTRL_GRP_TTC1_7_CLK, PINCTRL_GRP_TTC1_8_CLK, END_OF_GROUPS, }), }, [PINCTRL_FUNC_TTC1_WAV] = { .name = "ttc1_wav", .regval = 0xa0, .groups = &((uint16_t []) { PINCTRL_GRP_TTC1_0_WAV, PINCTRL_GRP_TTC1_1_WAV, PINCTRL_GRP_TTC1_2_WAV, PINCTRL_GRP_TTC1_3_WAV, PINCTRL_GRP_TTC1_4_WAV, PINCTRL_GRP_TTC1_5_WAV, PINCTRL_GRP_TTC1_6_WAV, PINCTRL_GRP_TTC1_7_WAV, PINCTRL_GRP_TTC1_8_WAV, END_OF_GROUPS, }), }, [PINCTRL_FUNC_TTC2_CLK] = { .name = "ttc2_clk", .regval = 0xa0, .groups = &((uint16_t []) { PINCTRL_GRP_TTC2_0_CLK, PINCTRL_GRP_TTC2_1_CLK, PINCTRL_GRP_TTC2_2_CLK, PINCTRL_GRP_TTC2_3_CLK, PINCTRL_GRP_TTC2_4_CLK, PINCTRL_GRP_TTC2_5_CLK, PINCTRL_GRP_TTC2_6_CLK, PINCTRL_GRP_TTC2_7_CLK, PINCTRL_GRP_TTC2_8_CLK, END_OF_GROUPS, }), }, [PINCTRL_FUNC_TTC2_WAV] = { .name = "ttc2_wav", .regval = 0xa0, .groups = &((uint16_t []) { PINCTRL_GRP_TTC2_0_WAV, PINCTRL_GRP_TTC2_1_WAV, PINCTRL_GRP_TTC2_2_WAV, PINCTRL_GRP_TTC2_3_WAV, PINCTRL_GRP_TTC2_4_WAV, PINCTRL_GRP_TTC2_5_WAV, PINCTRL_GRP_TTC2_6_WAV, PINCTRL_GRP_TTC2_7_WAV, PINCTRL_GRP_TTC2_8_WAV, END_OF_GROUPS, }), }, [PINCTRL_FUNC_TTC3_CLK] = { .name = "ttc3_clk", .regval = 0xa0, .groups = &((uint16_t []) { PINCTRL_GRP_TTC3_0_CLK, PINCTRL_GRP_TTC3_1_CLK, PINCTRL_GRP_TTC3_2_CLK, PINCTRL_GRP_TTC3_3_CLK, PINCTRL_GRP_TTC3_4_CLK, PINCTRL_GRP_TTC3_5_CLK, PINCTRL_GRP_TTC3_6_CLK, PINCTRL_GRP_TTC3_7_CLK, PINCTRL_GRP_TTC3_8_CLK, END_OF_GROUPS, }), }, [PINCTRL_FUNC_TTC3_WAV] = { .name = "ttc3_wav", .regval = 0xa0, .groups = &((uint16_t []) { PINCTRL_GRP_TTC3_0_WAV, PINCTRL_GRP_TTC3_1_WAV, PINCTRL_GRP_TTC3_2_WAV, PINCTRL_GRP_TTC3_3_WAV, PINCTRL_GRP_TTC3_4_WAV, PINCTRL_GRP_TTC3_5_WAV, PINCTRL_GRP_TTC3_6_WAV, PINCTRL_GRP_TTC3_7_WAV, PINCTRL_GRP_TTC3_8_WAV, END_OF_GROUPS, }), }, [PINCTRL_FUNC_UART0] = { .name = "uart0", .regval = 0xc0, .groups = &((uint16_t []) { PINCTRL_GRP_UART0_0, PINCTRL_GRP_UART0_1, PINCTRL_GRP_UART0_2, PINCTRL_GRP_UART0_3, PINCTRL_GRP_UART0_4, PINCTRL_GRP_UART0_5, PINCTRL_GRP_UART0_6, PINCTRL_GRP_UART0_7, PINCTRL_GRP_UART0_8, PINCTRL_GRP_UART0_9, PINCTRL_GRP_UART0_10, PINCTRL_GRP_UART0_11, PINCTRL_GRP_UART0_12, PINCTRL_GRP_UART0_13, PINCTRL_GRP_UART0_14, PINCTRL_GRP_UART0_15, PINCTRL_GRP_UART0_16, PINCTRL_GRP_UART0_17, PINCTRL_GRP_UART0_18, END_OF_GROUPS, }), }, [PINCTRL_FUNC_UART1] = { .name = "uart1", .regval = 0xc0, .groups = &((uint16_t []) { PINCTRL_GRP_UART1_0, PINCTRL_GRP_UART1_1, PINCTRL_GRP_UART1_2, PINCTRL_GRP_UART1_3, PINCTRL_GRP_UART1_4, PINCTRL_GRP_UART1_5, PINCTRL_GRP_UART1_6, PINCTRL_GRP_UART1_7, PINCTRL_GRP_UART1_8, PINCTRL_GRP_UART1_9, PINCTRL_GRP_UART1_10, PINCTRL_GRP_UART1_11, PINCTRL_GRP_UART1_12, PINCTRL_GRP_UART1_13, PINCTRL_GRP_UART1_14, PINCTRL_GRP_UART1_15, PINCTRL_GRP_UART1_16, PINCTRL_GRP_UART1_17, PINCTRL_GRP_UART1_18, END_OF_GROUPS, }), }, [PINCTRL_FUNC_USB0] = { .name = "usb0", .regval = 0x04, .groups = &((uint16_t []) { PINCTRL_GRP_USB0_0, END_OF_GROUPS, }), }, [PINCTRL_FUNC_USB1] = { .name = "usb1", .regval = 0x04, .groups = &((uint16_t []) { PINCTRL_GRP_USB1_0, END_OF_GROUPS, }), }, [PINCTRL_FUNC_SWDT0_CLK] = { .name = "swdt0_clk", .regval = 0x60, .groups = &((uint16_t []) { PINCTRL_GRP_SWDT0_0_CLK, PINCTRL_GRP_SWDT0_1_CLK, PINCTRL_GRP_SWDT0_2_CLK, PINCTRL_GRP_SWDT0_3_CLK, PINCTRL_GRP_SWDT0_4_CLK, PINCTRL_GRP_SWDT0_5_CLK, PINCTRL_GRP_SWDT0_6_CLK, PINCTRL_GRP_SWDT0_7_CLK, PINCTRL_GRP_SWDT0_8_CLK, PINCTRL_GRP_SWDT0_9_CLK, PINCTRL_GRP_SWDT0_10_CLK, PINCTRL_GRP_SWDT0_11_CLK, PINCTRL_GRP_SWDT0_12_CLK, END_OF_GROUPS, }), }, [PINCTRL_FUNC_SWDT0_RST] = { .name = "swdt0_rst", .regval = 0x60, .groups = &((uint16_t []) { PINCTRL_GRP_SWDT0_0_RST, PINCTRL_GRP_SWDT0_1_RST, PINCTRL_GRP_SWDT0_2_RST, PINCTRL_GRP_SWDT0_3_RST, PINCTRL_GRP_SWDT0_4_RST, PINCTRL_GRP_SWDT0_5_RST, PINCTRL_GRP_SWDT0_6_RST, PINCTRL_GRP_SWDT0_7_RST, PINCTRL_GRP_SWDT0_8_RST, PINCTRL_GRP_SWDT0_9_RST, PINCTRL_GRP_SWDT0_10_RST, PINCTRL_GRP_SWDT0_11_RST, PINCTRL_GRP_SWDT0_12_RST, END_OF_GROUPS, }), }, [PINCTRL_FUNC_SWDT1_CLK] = { .name = "swdt1_clk", .regval = 0x60, .groups = &((uint16_t []) { PINCTRL_GRP_SWDT1_0_CLK, PINCTRL_GRP_SWDT1_1_CLK, PINCTRL_GRP_SWDT1_2_CLK, PINCTRL_GRP_SWDT1_3_CLK, PINCTRL_GRP_SWDT1_4_CLK, PINCTRL_GRP_SWDT1_5_CLK, PINCTRL_GRP_SWDT1_6_CLK, PINCTRL_GRP_SWDT1_7_CLK, PINCTRL_GRP_SWDT1_8_CLK, PINCTRL_GRP_SWDT1_9_CLK, PINCTRL_GRP_SWDT1_10_CLK, PINCTRL_GRP_SWDT1_11_CLK, PINCTRL_GRP_SWDT1_12_CLK, END_OF_GROUPS, }), }, [PINCTRL_FUNC_SWDT1_RST] = { .name = "swdt1_rst", .regval = 0x60, .groups = &((uint16_t []) { PINCTRL_GRP_SWDT1_0_RST, PINCTRL_GRP_SWDT1_1_RST, PINCTRL_GRP_SWDT1_2_RST, PINCTRL_GRP_SWDT1_3_RST, PINCTRL_GRP_SWDT1_4_RST, PINCTRL_GRP_SWDT1_5_RST, PINCTRL_GRP_SWDT1_6_RST, PINCTRL_GRP_SWDT1_7_RST, PINCTRL_GRP_SWDT1_8_RST, PINCTRL_GRP_SWDT1_9_RST, PINCTRL_GRP_SWDT1_10_RST, PINCTRL_GRP_SWDT1_11_RST, PINCTRL_GRP_SWDT1_12_RST, END_OF_GROUPS, }), }, [PINCTRL_FUNC_PMU0] = { .name = "pmu0", .regval = 0x08, .groups = &((uint16_t []) { PINCTRL_GRP_PMU0_0, PINCTRL_GRP_PMU0_1, PINCTRL_GRP_PMU0_2, PINCTRL_GRP_PMU0_3, PINCTRL_GRP_PMU0_4, PINCTRL_GRP_PMU0_5, PINCTRL_GRP_PMU0_6, PINCTRL_GRP_PMU0_7, PINCTRL_GRP_PMU0_8, PINCTRL_GRP_PMU0_9, PINCTRL_GRP_PMU0_10, PINCTRL_GRP_PMU0_11, END_OF_GROUPS, }), }, [PINCTRL_FUNC_PCIE0] = { .name = "pcie0", .regval = 0x04, .groups = &((uint16_t []) { PINCTRL_GRP_PCIE0_0, PINCTRL_GRP_PCIE0_1, PINCTRL_GRP_PCIE0_2, PINCTRL_GRP_PCIE0_3, PINCTRL_GRP_PCIE0_4, PINCTRL_GRP_PCIE0_5, PINCTRL_GRP_PCIE0_6, PINCTRL_GRP_PCIE0_7, END_OF_GROUPS, }), }, [PINCTRL_FUNC_CSU0] = { .name = "csu0", .regval = 0x18, .groups = &((uint16_t []) { PINCTRL_GRP_CSU0_0, PINCTRL_GRP_CSU0_1, PINCTRL_GRP_CSU0_2, PINCTRL_GRP_CSU0_3, PINCTRL_GRP_CSU0_4, PINCTRL_GRP_CSU0_5, PINCTRL_GRP_CSU0_6, PINCTRL_GRP_CSU0_7, PINCTRL_GRP_CSU0_8, PINCTRL_GRP_CSU0_9, PINCTRL_GRP_CSU0_10, PINCTRL_GRP_CSU0_11, END_OF_GROUPS, }), }, [PINCTRL_FUNC_DPAUX0] = { .name = "dpaux0", .regval = 0x18, .groups = &((uint16_t []) { PINCTRL_GRP_DPAUX0_0, PINCTRL_GRP_DPAUX0_1, PINCTRL_GRP_DPAUX0_2, PINCTRL_GRP_DPAUX0_3, END_OF_GROUPS, }), }, [PINCTRL_FUNC_PJTAG0] = { .name = "pjtag0", .regval = 0x60, .groups = &((uint16_t []) { PINCTRL_GRP_PJTAG0_0, PINCTRL_GRP_PJTAG0_1, PINCTRL_GRP_PJTAG0_2, PINCTRL_GRP_PJTAG0_3, PINCTRL_GRP_PJTAG0_4, PINCTRL_GRP_PJTAG0_5, END_OF_GROUPS, }), }, [PINCTRL_FUNC_TRACE0] = { .name = "trace0", .regval = 0xe0, .groups = &((uint16_t []) { PINCTRL_GRP_TRACE0_0, PINCTRL_GRP_TRACE0_1, PINCTRL_GRP_TRACE0_2, END_OF_GROUPS, }), }, [PINCTRL_FUNC_TRACE0_CLK] = { .name = "trace0_clk", .regval = 0xe0, .groups = &((uint16_t []) { PINCTRL_GRP_TRACE0_0_CLK, PINCTRL_GRP_TRACE0_1_CLK, PINCTRL_GRP_TRACE0_2_CLK, END_OF_GROUPS, }), }, [PINCTRL_FUNC_TESTSCAN0] = { .name = "testscan0", .regval = 0x10, .groups = &((uint16_t []) { PINCTRL_GRP_TESTSCAN0_0, END_OF_GROUPS, }), }, }; static struct zynqmp_pin_group zynqmp_pin_groups[MAX_PIN] = { [PINCTRL_PIN_0] = { .groups = &((uint16_t []) { PINCTRL_GRP_QSPI0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_0, PINCTRL_GRP_CAN1_0, PINCTRL_GRP_I2C1_0, PINCTRL_GRP_PJTAG0_0, PINCTRL_GRP_SPI0_0, PINCTRL_GRP_TTC3_0_CLK, PINCTRL_GRP_UART1_0, PINCTRL_GRP_TRACE0_0_CLK, END_OF_GROUPS, }), }, [PINCTRL_PIN_1] = { .groups = &((uint16_t []) { PINCTRL_GRP_QSPI0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_1, PINCTRL_GRP_CAN1_0, PINCTRL_GRP_I2C1_0, PINCTRL_GRP_PJTAG0_0, PINCTRL_GRP_SPI0_0_SS2, PINCTRL_GRP_TTC3_0_WAV, PINCTRL_GRP_UART1_0, PINCTRL_GRP_TRACE0_0_CLK, END_OF_GROUPS, }), }, [PINCTRL_PIN_2] = { .groups = &((uint16_t []) { PINCTRL_GRP_QSPI0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_2, PINCTRL_GRP_CAN0_0, PINCTRL_GRP_I2C0_0, PINCTRL_GRP_PJTAG0_0, PINCTRL_GRP_SPI0_0_SS1, PINCTRL_GRP_TTC2_0_CLK, PINCTRL_GRP_UART0_0, PINCTRL_GRP_TRACE0_0, END_OF_GROUPS, }), }, [PINCTRL_PIN_3] = { .groups = &((uint16_t []) { PINCTRL_GRP_QSPI0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_3, PINCTRL_GRP_CAN0_0, PINCTRL_GRP_I2C0_0, PINCTRL_GRP_PJTAG0_0, PINCTRL_GRP_SPI0_0_SS0, PINCTRL_GRP_TTC2_0_WAV, PINCTRL_GRP_UART0_0, PINCTRL_GRP_TRACE0_0, END_OF_GROUPS, }), }, [PINCTRL_PIN_4] = { .groups = &((uint16_t []) { PINCTRL_GRP_QSPI0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_4, PINCTRL_GRP_CAN1_1, PINCTRL_GRP_I2C1_1, PINCTRL_GRP_SWDT1_0_CLK, PINCTRL_GRP_SPI0_0, PINCTRL_GRP_TTC1_0_CLK, PINCTRL_GRP_UART1_1, PINCTRL_GRP_TRACE0_0, END_OF_GROUPS, }), }, [PINCTRL_PIN_5] = { .groups = &((uint16_t []) { PINCTRL_GRP_QSPI_SS, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_5, PINCTRL_GRP_CAN1_1, PINCTRL_GRP_I2C1_1, PINCTRL_GRP_SWDT1_0_RST, PINCTRL_GRP_SPI0_0, PINCTRL_GRP_TTC1_0_WAV, PINCTRL_GRP_UART1_1, PINCTRL_GRP_TRACE0_0, END_OF_GROUPS, }), }, [PINCTRL_PIN_6] = { .groups = &((uint16_t []) { PINCTRL_GRP_QSPI_FBCLK, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_6, PINCTRL_GRP_CAN0_1, PINCTRL_GRP_I2C0_1, PINCTRL_GRP_SWDT0_0_CLK, PINCTRL_GRP_SPI1_0, PINCTRL_GRP_TTC0_0_CLK, PINCTRL_GRP_UART0_1, PINCTRL_GRP_TRACE0_0, END_OF_GROUPS, }), }, [PINCTRL_PIN_7] = { .groups = &((uint16_t []) { PINCTRL_GRP_QSPI_SS, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_7, PINCTRL_GRP_CAN0_1, PINCTRL_GRP_I2C0_1, PINCTRL_GRP_SWDT0_0_RST, PINCTRL_GRP_SPI1_0_SS2, PINCTRL_GRP_TTC0_0_WAV, PINCTRL_GRP_UART0_1, PINCTRL_GRP_TRACE0_0, END_OF_GROUPS, }), }, [PINCTRL_PIN_8] = { .groups = &((uint16_t []) { PINCTRL_GRP_QSPI0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_8, PINCTRL_GRP_CAN1_2, PINCTRL_GRP_I2C1_2, PINCTRL_GRP_SWDT1_1_CLK, PINCTRL_GRP_SPI1_0_SS1, PINCTRL_GRP_TTC3_1_CLK, PINCTRL_GRP_UART1_2, PINCTRL_GRP_TRACE0_0, END_OF_GROUPS, }), }, [PINCTRL_PIN_9] = { .groups = &((uint16_t []) { PINCTRL_GRP_QSPI0_0, PINCTRL_GRP_NAND0_0_CE, PINCTRL_GRP_RESERVED, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_9, PINCTRL_GRP_CAN1_2, PINCTRL_GRP_I2C1_2, PINCTRL_GRP_SWDT1_1_RST, PINCTRL_GRP_SPI1_0_SS0, PINCTRL_GRP_TTC3_1_WAV, PINCTRL_GRP_UART1_2, PINCTRL_GRP_TRACE0_0, END_OF_GROUPS, }), }, [PINCTRL_PIN_10] = { .groups = &((uint16_t []) { PINCTRL_GRP_QSPI0_0, PINCTRL_GRP_NAND0_0_RB, PINCTRL_GRP_RESERVED, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_10, PINCTRL_GRP_CAN0_2, PINCTRL_GRP_I2C0_2, PINCTRL_GRP_SWDT0_1_CLK, PINCTRL_GRP_SPI1_0, PINCTRL_GRP_TTC2_1_CLK, PINCTRL_GRP_UART0_2, PINCTRL_GRP_TRACE0_0, END_OF_GROUPS, }), }, [PINCTRL_PIN_11] = { .groups = &((uint16_t []) { PINCTRL_GRP_QSPI0_0, PINCTRL_GRP_NAND0_0_RB, PINCTRL_GRP_RESERVED, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_11, PINCTRL_GRP_CAN0_2, PINCTRL_GRP_I2C0_2, PINCTRL_GRP_SWDT0_1_RST, PINCTRL_GRP_SPI1_0, PINCTRL_GRP_TTC2_1_WAV, PINCTRL_GRP_UART0_2, PINCTRL_GRP_TRACE0_0, END_OF_GROUPS, }), }, [PINCTRL_PIN_12] = { .groups = &((uint16_t []) { PINCTRL_GRP_QSPI0_0, PINCTRL_GRP_NAND0_0_DQS, PINCTRL_GRP_RESERVED, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_12, PINCTRL_GRP_CAN1_3, PINCTRL_GRP_I2C1_3, PINCTRL_GRP_PJTAG0_1, PINCTRL_GRP_SPI0_1, PINCTRL_GRP_TTC1_1_CLK, PINCTRL_GRP_UART1_3, PINCTRL_GRP_TRACE0_0, END_OF_GROUPS, }), }, [PINCTRL_PIN_13] = { .groups = &((uint16_t []) { PINCTRL_GRP_RESERVED, PINCTRL_GRP_NAND0_0, PINCTRL_GRP_SDIO0_0, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_13, PINCTRL_GRP_CAN1_3, PINCTRL_GRP_I2C1_3, PINCTRL_GRP_PJTAG0_1, PINCTRL_GRP_SPI0_1_SS2, PINCTRL_GRP_TTC1_1_WAV, PINCTRL_GRP_UART1_3, PINCTRL_GRP_TRACE0_0, PINCTRL_GRP_SDIO0_4BIT_0_0, PINCTRL_GRP_SDIO0_1BIT_0_0, END_OF_GROUPS, }), }, [PINCTRL_PIN_14] = { .groups = &((uint16_t []) { PINCTRL_GRP_RESERVED, PINCTRL_GRP_NAND0_0, PINCTRL_GRP_SDIO0_0, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_14, PINCTRL_GRP_CAN0_3, PINCTRL_GRP_I2C0_3, PINCTRL_GRP_PJTAG0_1, PINCTRL_GRP_SPI0_1_SS1, PINCTRL_GRP_TTC0_1_CLK, PINCTRL_GRP_UART0_3, PINCTRL_GRP_TRACE0_0, PINCTRL_GRP_SDIO0_4BIT_0_0, PINCTRL_GRP_SDIO0_1BIT_0_1, END_OF_GROUPS, }), }, [PINCTRL_PIN_15] = { .groups = &((uint16_t []) { PINCTRL_GRP_RESERVED, PINCTRL_GRP_NAND0_0, PINCTRL_GRP_SDIO0_0, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_15, PINCTRL_GRP_CAN0_3, PINCTRL_GRP_I2C0_3, PINCTRL_GRP_PJTAG0_1, PINCTRL_GRP_SPI0_1_SS0, PINCTRL_GRP_TTC0_1_WAV, PINCTRL_GRP_UART0_3, PINCTRL_GRP_TRACE0_0, PINCTRL_GRP_SDIO0_4BIT_0_0, PINCTRL_GRP_SDIO0_1BIT_0_2, END_OF_GROUPS, }), }, [PINCTRL_PIN_16] = { .groups = &((uint16_t []) { PINCTRL_GRP_RESERVED, PINCTRL_GRP_NAND0_0, PINCTRL_GRP_SDIO0_0, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_16, PINCTRL_GRP_CAN1_4, PINCTRL_GRP_I2C1_4, PINCTRL_GRP_SWDT1_2_CLK, PINCTRL_GRP_SPI0_1, PINCTRL_GRP_TTC3_2_CLK, PINCTRL_GRP_UART1_4, PINCTRL_GRP_TRACE0_0, PINCTRL_GRP_SDIO0_4BIT_0_0, PINCTRL_GRP_SDIO0_1BIT_0_3, END_OF_GROUPS, }), }, [PINCTRL_PIN_17] = { .groups = &((uint16_t []) { PINCTRL_GRP_RESERVED, PINCTRL_GRP_NAND0_0, PINCTRL_GRP_SDIO0_0, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_17, PINCTRL_GRP_CAN1_4, PINCTRL_GRP_I2C1_4, PINCTRL_GRP_SWDT1_2_RST, PINCTRL_GRP_SPI0_1, PINCTRL_GRP_TTC3_2_WAV, PINCTRL_GRP_UART1_4, PINCTRL_GRP_TRACE0_0, PINCTRL_GRP_SDIO0_4BIT_0_1, PINCTRL_GRP_SDIO0_1BIT_0_4, END_OF_GROUPS, }), }, [PINCTRL_PIN_18] = { .groups = &((uint16_t []) { PINCTRL_GRP_RESERVED, PINCTRL_GRP_NAND0_0, PINCTRL_GRP_SDIO0_0, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_CSU0_0, PINCTRL_GRP_GPIO0_18, PINCTRL_GRP_CAN0_4, PINCTRL_GRP_I2C0_4, PINCTRL_GRP_SWDT0_2_CLK, PINCTRL_GRP_SPI1_1, PINCTRL_GRP_TTC2_2_CLK, PINCTRL_GRP_UART0_4, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_4BIT_0_1, PINCTRL_GRP_SDIO0_1BIT_0_5, END_OF_GROUPS, }), }, [PINCTRL_PIN_19] = { .groups = &((uint16_t []) { PINCTRL_GRP_RESERVED, PINCTRL_GRP_NAND0_0, PINCTRL_GRP_SDIO0_0, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_CSU0_1, PINCTRL_GRP_GPIO0_19, PINCTRL_GRP_CAN0_4, PINCTRL_GRP_I2C0_4, PINCTRL_GRP_SWDT0_2_RST, PINCTRL_GRP_SPI1_1_SS2, PINCTRL_GRP_TTC2_2_WAV, PINCTRL_GRP_UART0_4, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_4BIT_0_1, PINCTRL_GRP_SDIO0_1BIT_0_6, END_OF_GROUPS, }), }, [PINCTRL_PIN_20] = { .groups = &((uint16_t []) { PINCTRL_GRP_RESERVED, PINCTRL_GRP_NAND0_0, PINCTRL_GRP_SDIO0_0, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_CSU0_2, PINCTRL_GRP_GPIO0_20, PINCTRL_GRP_CAN1_5, PINCTRL_GRP_I2C1_5, PINCTRL_GRP_SWDT1_3_CLK, PINCTRL_GRP_SPI1_1_SS1, PINCTRL_GRP_TTC1_2_CLK, PINCTRL_GRP_UART1_5, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_4BIT_0_1, PINCTRL_GRP_SDIO0_1BIT_0_7, END_OF_GROUPS, }), }, [PINCTRL_PIN_21] = { .groups = &((uint16_t []) { PINCTRL_GRP_RESERVED, PINCTRL_GRP_NAND0_0, PINCTRL_GRP_SDIO0_0, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_CSU0_3, PINCTRL_GRP_GPIO0_21, PINCTRL_GRP_CAN1_5, PINCTRL_GRP_I2C1_5, PINCTRL_GRP_SWDT1_3_RST, PINCTRL_GRP_SPI1_1_SS0, PINCTRL_GRP_TTC1_2_WAV, PINCTRL_GRP_UART1_5, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_4BIT_0_0, PINCTRL_GRP_SDIO0_4BIT_0_1, PINCTRL_GRP_SDIO0_1BIT_0_0, PINCTRL_GRP_SDIO0_1BIT_0_1, PINCTRL_GRP_SDIO0_1BIT_0_2, PINCTRL_GRP_SDIO0_1BIT_0_3, PINCTRL_GRP_SDIO0_1BIT_0_4, PINCTRL_GRP_SDIO0_1BIT_0_5, PINCTRL_GRP_SDIO0_1BIT_0_6, PINCTRL_GRP_SDIO0_1BIT_0_7, END_OF_GROUPS, }), }, [PINCTRL_PIN_22] = { .groups = &((uint16_t []) { PINCTRL_GRP_RESERVED, PINCTRL_GRP_NAND0_0, PINCTRL_GRP_SDIO0_0, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_CSU0_4, PINCTRL_GRP_GPIO0_22, PINCTRL_GRP_CAN0_5, PINCTRL_GRP_I2C0_5, PINCTRL_GRP_SWDT0_3_CLK, PINCTRL_GRP_SPI1_1, PINCTRL_GRP_TTC0_2_CLK, PINCTRL_GRP_UART0_5, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_4BIT_0_0, PINCTRL_GRP_SDIO0_4BIT_0_1, PINCTRL_GRP_SDIO0_1BIT_0_0, PINCTRL_GRP_SDIO0_1BIT_0_1, PINCTRL_GRP_SDIO0_1BIT_0_2, PINCTRL_GRP_SDIO0_1BIT_0_3, PINCTRL_GRP_SDIO0_1BIT_0_4, PINCTRL_GRP_SDIO0_1BIT_0_5, PINCTRL_GRP_SDIO0_1BIT_0_6, PINCTRL_GRP_SDIO0_1BIT_0_7, END_OF_GROUPS, }), }, [PINCTRL_PIN_23] = { .groups = &((uint16_t []) { PINCTRL_GRP_RESERVED, PINCTRL_GRP_NAND0_0, PINCTRL_GRP_SDIO0_0_PC, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_CSU0_5, PINCTRL_GRP_GPIO0_23, PINCTRL_GRP_CAN0_5, PINCTRL_GRP_I2C0_5, PINCTRL_GRP_SWDT0_3_RST, PINCTRL_GRP_SPI1_1, PINCTRL_GRP_TTC0_2_WAV, PINCTRL_GRP_UART0_5, PINCTRL_GRP_RESERVED, END_OF_GROUPS, }), }, [PINCTRL_PIN_24] = { .groups = &((uint16_t []) { PINCTRL_GRP_RESERVED, PINCTRL_GRP_NAND0_0, PINCTRL_GRP_SDIO0_0_CD, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_CSU0_6, PINCTRL_GRP_GPIO0_24, PINCTRL_GRP_CAN1_6, PINCTRL_GRP_I2C1_6, PINCTRL_GRP_SWDT1_4_CLK, PINCTRL_GRP_RESERVED, PINCTRL_GRP_TTC3_3_CLK, PINCTRL_GRP_UART1_6, PINCTRL_GRP_RESERVED, END_OF_GROUPS, }), }, [PINCTRL_PIN_25] = { .groups = &((uint16_t []) { PINCTRL_GRP_RESERVED, PINCTRL_GRP_NAND0_0, PINCTRL_GRP_SDIO0_0_WP, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_CSU0_7, PINCTRL_GRP_GPIO0_25, PINCTRL_GRP_CAN1_6, PINCTRL_GRP_I2C1_6, PINCTRL_GRP_SWDT1_4_RST, PINCTRL_GRP_RESERVED, PINCTRL_GRP_TTC3_3_WAV, PINCTRL_GRP_UART1_6, PINCTRL_GRP_RESERVED, END_OF_GROUPS, }), }, [PINCTRL_PIN_26] = { .groups = &((uint16_t []) { PINCTRL_GRP_GEMTSU0_0, PINCTRL_GRP_NAND0_1_CE, PINCTRL_GRP_PMU0_0, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_CSU0_8, PINCTRL_GRP_GPIO0_26, PINCTRL_GRP_CAN0_6, PINCTRL_GRP_I2C0_6, PINCTRL_GRP_PJTAG0_2, PINCTRL_GRP_SPI0_2, PINCTRL_GRP_TTC2_3_CLK, PINCTRL_GRP_UART0_6, PINCTRL_GRP_TRACE0_1, END_OF_GROUPS, }), }, [PINCTRL_PIN_27] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET0_0, PINCTRL_GRP_NAND0_1_RB, PINCTRL_GRP_PMU0_1, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_DPAUX0_0, PINCTRL_GRP_GPIO0_27, PINCTRL_GRP_CAN0_6, PINCTRL_GRP_I2C0_6, PINCTRL_GRP_PJTAG0_2, PINCTRL_GRP_SPI0_2_SS2, PINCTRL_GRP_TTC2_3_WAV, PINCTRL_GRP_UART0_6, PINCTRL_GRP_TRACE0_1, END_OF_GROUPS, }), }, [PINCTRL_PIN_28] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET0_0, PINCTRL_GRP_NAND0_1_RB, PINCTRL_GRP_PMU0_2, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_DPAUX0_0, PINCTRL_GRP_GPIO0_28, PINCTRL_GRP_CAN1_7, PINCTRL_GRP_I2C1_7, PINCTRL_GRP_PJTAG0_2, PINCTRL_GRP_SPI0_2_SS1, PINCTRL_GRP_TTC1_3_CLK, PINCTRL_GRP_UART1_7, PINCTRL_GRP_TRACE0_1, END_OF_GROUPS, }), }, [PINCTRL_PIN_29] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET0_0, PINCTRL_GRP_PCIE0_0, PINCTRL_GRP_PMU0_3, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_DPAUX0_1, PINCTRL_GRP_GPIO0_29, PINCTRL_GRP_CAN1_7, PINCTRL_GRP_I2C1_7, PINCTRL_GRP_PJTAG0_2, PINCTRL_GRP_SPI0_2_SS0, PINCTRL_GRP_TTC1_3_WAV, PINCTRL_GRP_UART1_7, PINCTRL_GRP_TRACE0_1, END_OF_GROUPS, }), }, [PINCTRL_PIN_30] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET0_0, PINCTRL_GRP_PCIE0_1, PINCTRL_GRP_PMU0_4, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_DPAUX0_1, PINCTRL_GRP_GPIO0_30, PINCTRL_GRP_CAN0_7, PINCTRL_GRP_I2C0_7, PINCTRL_GRP_SWDT0_4_CLK, PINCTRL_GRP_SPI0_2, PINCTRL_GRP_TTC0_3_CLK, PINCTRL_GRP_UART0_7, PINCTRL_GRP_TRACE0_1, END_OF_GROUPS, }), }, [PINCTRL_PIN_31] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET0_0, PINCTRL_GRP_PCIE0_2, PINCTRL_GRP_PMU0_5, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_CSU0_9, PINCTRL_GRP_GPIO0_31, PINCTRL_GRP_CAN0_7, PINCTRL_GRP_I2C0_7, PINCTRL_GRP_SWDT0_4_RST, PINCTRL_GRP_SPI0_2, PINCTRL_GRP_TTC0_3_WAV, PINCTRL_GRP_UART0_7, PINCTRL_GRP_TRACE0_1, END_OF_GROUPS, }), }, [PINCTRL_PIN_32] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET0_0, PINCTRL_GRP_NAND0_1_DQS, PINCTRL_GRP_PMU0_6, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_CSU0_10, PINCTRL_GRP_GPIO0_32, PINCTRL_GRP_CAN1_8, PINCTRL_GRP_I2C1_8, PINCTRL_GRP_SWDT1_5_CLK, PINCTRL_GRP_SPI1_2, PINCTRL_GRP_TTC3_4_CLK, PINCTRL_GRP_UART1_8, PINCTRL_GRP_TRACE0_1, END_OF_GROUPS, }), }, [PINCTRL_PIN_33] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET0_0, PINCTRL_GRP_PCIE0_3, PINCTRL_GRP_PMU0_7, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_CSU0_11, PINCTRL_GRP_GPIO0_33, PINCTRL_GRP_CAN1_8, PINCTRL_GRP_I2C1_8, PINCTRL_GRP_SWDT1_5_RST, PINCTRL_GRP_SPI1_2_SS2, PINCTRL_GRP_TTC3_4_WAV, PINCTRL_GRP_UART1_8, PINCTRL_GRP_TRACE0_1, END_OF_GROUPS, }), }, [PINCTRL_PIN_34] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET0_0, PINCTRL_GRP_PCIE0_4, PINCTRL_GRP_PMU0_8, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_DPAUX0_2, PINCTRL_GRP_GPIO0_34, PINCTRL_GRP_CAN0_8, PINCTRL_GRP_I2C0_8, PINCTRL_GRP_SWDT0_5_CLK, PINCTRL_GRP_SPI1_2_SS1, PINCTRL_GRP_TTC2_4_CLK, PINCTRL_GRP_UART0_8, PINCTRL_GRP_TRACE0_1, END_OF_GROUPS, }), }, [PINCTRL_PIN_35] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET0_0, PINCTRL_GRP_PCIE0_5, PINCTRL_GRP_PMU0_9, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_DPAUX0_2, PINCTRL_GRP_GPIO0_35, PINCTRL_GRP_CAN0_8, PINCTRL_GRP_I2C0_8, PINCTRL_GRP_SWDT0_5_RST, PINCTRL_GRP_SPI1_2_SS0, PINCTRL_GRP_TTC2_4_WAV, PINCTRL_GRP_UART0_8, PINCTRL_GRP_TRACE0_1, END_OF_GROUPS, }), }, [PINCTRL_PIN_36] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET0_0, PINCTRL_GRP_PCIE0_6, PINCTRL_GRP_PMU0_10, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_DPAUX0_3, PINCTRL_GRP_GPIO0_36, PINCTRL_GRP_CAN1_9, PINCTRL_GRP_I2C1_9, PINCTRL_GRP_SWDT1_6_CLK, PINCTRL_GRP_SPI1_2, PINCTRL_GRP_TTC1_4_CLK, PINCTRL_GRP_UART1_9, PINCTRL_GRP_TRACE0_1, END_OF_GROUPS, }), }, [PINCTRL_PIN_37] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET0_0, PINCTRL_GRP_PCIE0_7, PINCTRL_GRP_PMU0_11, PINCTRL_GRP_TESTSCAN0_0, PINCTRL_GRP_DPAUX0_3, PINCTRL_GRP_GPIO0_37, PINCTRL_GRP_CAN1_9, PINCTRL_GRP_I2C1_9, PINCTRL_GRP_SWDT1_6_RST, PINCTRL_GRP_SPI1_2, PINCTRL_GRP_TTC1_4_WAV, PINCTRL_GRP_UART1_9, PINCTRL_GRP_TRACE0_1, END_OF_GROUPS, }), }, [PINCTRL_PIN_38] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_1, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_38, PINCTRL_GRP_CAN0_9, PINCTRL_GRP_I2C0_9, PINCTRL_GRP_PJTAG0_3, PINCTRL_GRP_SPI0_3, PINCTRL_GRP_TTC0_4_CLK, PINCTRL_GRP_UART0_9, PINCTRL_GRP_TRACE0_1_CLK, PINCTRL_GRP_SDIO0_4BIT_1_0, PINCTRL_GRP_SDIO0_4BIT_1_1, PINCTRL_GRP_SDIO0_1BIT_1_0, PINCTRL_GRP_SDIO0_1BIT_1_1, PINCTRL_GRP_SDIO0_1BIT_1_2, PINCTRL_GRP_SDIO0_1BIT_1_3, PINCTRL_GRP_SDIO0_1BIT_1_4, PINCTRL_GRP_SDIO0_1BIT_1_5, PINCTRL_GRP_SDIO0_1BIT_1_6, PINCTRL_GRP_SDIO0_1BIT_1_7, END_OF_GROUPS, }), }, [PINCTRL_PIN_39] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_1_CD, PINCTRL_GRP_SDIO1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_39, PINCTRL_GRP_CAN0_9, PINCTRL_GRP_I2C0_9, PINCTRL_GRP_PJTAG0_3, PINCTRL_GRP_SPI0_3_SS2, PINCTRL_GRP_TTC0_4_WAV, PINCTRL_GRP_UART0_9, PINCTRL_GRP_TRACE0_1_CLK, PINCTRL_GRP_SDIO1_4BIT_0_0, PINCTRL_GRP_SDIO1_1BIT_0_0, END_OF_GROUPS, }), }, [PINCTRL_PIN_40] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_1, PINCTRL_GRP_SDIO1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_40, PINCTRL_GRP_CAN1_10, PINCTRL_GRP_I2C1_10, PINCTRL_GRP_PJTAG0_3, PINCTRL_GRP_SPI0_3_SS1, PINCTRL_GRP_TTC3_5_CLK, PINCTRL_GRP_UART1_10, PINCTRL_GRP_TRACE0_1, PINCTRL_GRP_SDIO0_4BIT_1_0, PINCTRL_GRP_SDIO0_4BIT_1_1, PINCTRL_GRP_SDIO0_1BIT_1_0, PINCTRL_GRP_SDIO0_1BIT_1_1, PINCTRL_GRP_SDIO0_1BIT_1_2, PINCTRL_GRP_SDIO0_1BIT_1_3, PINCTRL_GRP_SDIO0_1BIT_1_4, PINCTRL_GRP_SDIO0_1BIT_1_5, PINCTRL_GRP_SDIO0_1BIT_1_6, PINCTRL_GRP_SDIO0_1BIT_1_7, PINCTRL_GRP_SDIO1_4BIT_0_0, PINCTRL_GRP_SDIO1_1BIT_0_1, END_OF_GROUPS, }), }, [PINCTRL_PIN_41] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_1, PINCTRL_GRP_SDIO1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_41, PINCTRL_GRP_CAN1_10, PINCTRL_GRP_I2C1_10, PINCTRL_GRP_PJTAG0_3, PINCTRL_GRP_SPI0_3_SS0, PINCTRL_GRP_TTC3_5_WAV, PINCTRL_GRP_UART1_10, PINCTRL_GRP_TRACE0_1, PINCTRL_GRP_SDIO0_4BIT_1_0, PINCTRL_GRP_SDIO0_1BIT_1_0, PINCTRL_GRP_SDIO1_4BIT_0_0, PINCTRL_GRP_SDIO1_1BIT_0_2, END_OF_GROUPS, }), }, [PINCTRL_PIN_42] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_1, PINCTRL_GRP_SDIO1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_42, PINCTRL_GRP_CAN0_10, PINCTRL_GRP_I2C0_10, PINCTRL_GRP_SWDT0_6_CLK, PINCTRL_GRP_SPI0_3, PINCTRL_GRP_TTC2_5_CLK, PINCTRL_GRP_UART0_10, PINCTRL_GRP_TRACE0_1, PINCTRL_GRP_SDIO0_1, PINCTRL_GRP_SDIO0_4BIT_1_0, PINCTRL_GRP_SDIO0_1BIT_1_1, PINCTRL_GRP_SDIO1_4BIT_0_0, PINCTRL_GRP_SDIO1_1BIT_0_3, END_OF_GROUPS, }), }, [PINCTRL_PIN_43] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_1, PINCTRL_GRP_SDIO1_0_PC, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_43, PINCTRL_GRP_CAN0_10, PINCTRL_GRP_I2C0_10, PINCTRL_GRP_SWDT0_6_RST, PINCTRL_GRP_SPI0_3, PINCTRL_GRP_TTC2_5_WAV, PINCTRL_GRP_UART0_10, PINCTRL_GRP_TRACE0_1, PINCTRL_GRP_SDIO0_4BIT_1_0, PINCTRL_GRP_SDIO0_1BIT_1_2, END_OF_GROUPS, }), }, [PINCTRL_PIN_44] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_1, PINCTRL_GRP_SDIO1_0_WP, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_44, PINCTRL_GRP_CAN1_11, PINCTRL_GRP_I2C1_11, PINCTRL_GRP_SWDT1_7_CLK, PINCTRL_GRP_SPI1_3, PINCTRL_GRP_TTC1_5_CLK, PINCTRL_GRP_UART1_11, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_4BIT_1_0, PINCTRL_GRP_SDIO0_1BIT_1_3, END_OF_GROUPS, }), }, [PINCTRL_PIN_45] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_1, PINCTRL_GRP_SDIO1_0_CD, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_45, PINCTRL_GRP_CAN1_11, PINCTRL_GRP_I2C1_11, PINCTRL_GRP_SWDT1_7_RST, PINCTRL_GRP_SPI1_3_SS2, PINCTRL_GRP_TTC1_5_WAV, PINCTRL_GRP_UART1_11, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_4BIT_1_1, PINCTRL_GRP_SDIO0_1BIT_1_4, END_OF_GROUPS, }), }, [PINCTRL_PIN_46] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_1, PINCTRL_GRP_SDIO1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_46, PINCTRL_GRP_CAN0_11, PINCTRL_GRP_I2C0_11, PINCTRL_GRP_SWDT0_7_CLK, PINCTRL_GRP_SPI1_3_SS1, PINCTRL_GRP_TTC0_5_CLK, PINCTRL_GRP_UART0_11, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_4BIT_1_1, PINCTRL_GRP_SDIO0_1BIT_1_5, PINCTRL_GRP_SDIO1_4BIT_0_1, PINCTRL_GRP_SDIO1_1BIT_0_4, END_OF_GROUPS, }), }, [PINCTRL_PIN_47] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_1, PINCTRL_GRP_SDIO1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_47, PINCTRL_GRP_CAN0_11, PINCTRL_GRP_I2C0_11, PINCTRL_GRP_SWDT0_7_RST, PINCTRL_GRP_SPI1_3_SS0, PINCTRL_GRP_TTC0_5_WAV, PINCTRL_GRP_UART0_11, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_4BIT_1_1, PINCTRL_GRP_SDIO0_1BIT_1_6, PINCTRL_GRP_SDIO1_4BIT_0_1, PINCTRL_GRP_SDIO1_1BIT_0_5, END_OF_GROUPS, }), }, [PINCTRL_PIN_48] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_1, PINCTRL_GRP_SDIO1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_48, PINCTRL_GRP_CAN1_12, PINCTRL_GRP_I2C1_12, PINCTRL_GRP_SWDT1_8_CLK, PINCTRL_GRP_SPI1_3, PINCTRL_GRP_TTC3_6_CLK, PINCTRL_GRP_UART1_12, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_4BIT_1_1, PINCTRL_GRP_SDIO0_1BIT_1_7, PINCTRL_GRP_SDIO1_4BIT_0_1, PINCTRL_GRP_SDIO1_1BIT_0_6, END_OF_GROUPS, }), }, [PINCTRL_PIN_49] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_1_PC, PINCTRL_GRP_SDIO1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_49, PINCTRL_GRP_CAN1_12, PINCTRL_GRP_I2C1_12, PINCTRL_GRP_SWDT1_8_RST, PINCTRL_GRP_SPI1_3, PINCTRL_GRP_TTC3_6_WAV, PINCTRL_GRP_UART1_12, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO1_4BIT_0_1, PINCTRL_GRP_SDIO1_1BIT_0_7, END_OF_GROUPS, }), }, [PINCTRL_PIN_50] = { .groups = &((uint16_t []) { PINCTRL_GRP_GEMTSU0_1, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_1_WP, PINCTRL_GRP_SDIO1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_50, PINCTRL_GRP_CAN0_12, PINCTRL_GRP_I2C0_12, PINCTRL_GRP_SWDT0_8_CLK, PINCTRL_GRP_MDIO1_0, PINCTRL_GRP_TTC2_6_CLK, PINCTRL_GRP_UART0_12, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO1_4BIT_0_0, PINCTRL_GRP_SDIO1_4BIT_0_1, PINCTRL_GRP_SDIO1_1BIT_0_0, PINCTRL_GRP_SDIO1_1BIT_0_1, PINCTRL_GRP_SDIO1_1BIT_0_2, PINCTRL_GRP_SDIO1_1BIT_0_3, PINCTRL_GRP_SDIO1_1BIT_0_4, PINCTRL_GRP_SDIO1_1BIT_0_5, PINCTRL_GRP_SDIO1_1BIT_0_6, PINCTRL_GRP_SDIO1_1BIT_0_7, END_OF_GROUPS, }), }, [PINCTRL_PIN_51] = { .groups = &((uint16_t []) { PINCTRL_GRP_GEMTSU0_2, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_51, PINCTRL_GRP_CAN0_12, PINCTRL_GRP_I2C0_12, PINCTRL_GRP_SWDT0_8_RST, PINCTRL_GRP_MDIO1_0, PINCTRL_GRP_TTC2_6_WAV, PINCTRL_GRP_UART0_12, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO1_4BIT_0_0, PINCTRL_GRP_SDIO1_4BIT_0_1, PINCTRL_GRP_SDIO1_1BIT_0_0, PINCTRL_GRP_SDIO1_1BIT_0_1, PINCTRL_GRP_SDIO1_1BIT_0_2, PINCTRL_GRP_SDIO1_1BIT_0_3, PINCTRL_GRP_SDIO1_1BIT_0_4, PINCTRL_GRP_SDIO1_1BIT_0_5, PINCTRL_GRP_SDIO1_1BIT_0_6, PINCTRL_GRP_SDIO1_1BIT_0_7, END_OF_GROUPS, }), }, [PINCTRL_PIN_52] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET2_0, PINCTRL_GRP_USB0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_52, PINCTRL_GRP_CAN1_13, PINCTRL_GRP_I2C1_13, PINCTRL_GRP_PJTAG0_4, PINCTRL_GRP_SPI0_4, PINCTRL_GRP_TTC1_6_CLK, PINCTRL_GRP_UART1_13, PINCTRL_GRP_TRACE0_2_CLK, END_OF_GROUPS, }), }, [PINCTRL_PIN_53] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET2_0, PINCTRL_GRP_USB0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_53, PINCTRL_GRP_CAN1_13, PINCTRL_GRP_I2C1_13, PINCTRL_GRP_PJTAG0_4, PINCTRL_GRP_SPI0_4_SS2, PINCTRL_GRP_TTC1_6_WAV, PINCTRL_GRP_UART1_13, PINCTRL_GRP_TRACE0_2_CLK, END_OF_GROUPS, }), }, [PINCTRL_PIN_54] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET2_0, PINCTRL_GRP_USB0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_54, PINCTRL_GRP_CAN0_13, PINCTRL_GRP_I2C0_13, PINCTRL_GRP_PJTAG0_4, PINCTRL_GRP_SPI0_4_SS1, PINCTRL_GRP_TTC0_6_CLK, PINCTRL_GRP_UART0_13, PINCTRL_GRP_TRACE0_2, END_OF_GROUPS, }), }, [PINCTRL_PIN_55] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET2_0, PINCTRL_GRP_USB0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_55, PINCTRL_GRP_CAN0_13, PINCTRL_GRP_I2C0_13, PINCTRL_GRP_PJTAG0_4, PINCTRL_GRP_SPI0_4_SS0, PINCTRL_GRP_TTC0_6_WAV, PINCTRL_GRP_UART0_13, PINCTRL_GRP_TRACE0_2, END_OF_GROUPS, }), }, [PINCTRL_PIN_56] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET2_0, PINCTRL_GRP_USB0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_56, PINCTRL_GRP_CAN1_14, PINCTRL_GRP_I2C1_14, PINCTRL_GRP_SWDT1_9_CLK, PINCTRL_GRP_SPI0_4, PINCTRL_GRP_TTC3_7_CLK, PINCTRL_GRP_UART1_14, PINCTRL_GRP_TRACE0_2, END_OF_GROUPS, }), }, [PINCTRL_PIN_57] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET2_0, PINCTRL_GRP_USB0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_57, PINCTRL_GRP_CAN1_14, PINCTRL_GRP_I2C1_14, PINCTRL_GRP_SWDT1_9_RST, PINCTRL_GRP_SPI0_4, PINCTRL_GRP_TTC3_7_WAV, PINCTRL_GRP_UART1_14, PINCTRL_GRP_TRACE0_2, END_OF_GROUPS, }), }, [PINCTRL_PIN_58] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET2_0, PINCTRL_GRP_USB0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_58, PINCTRL_GRP_CAN0_14, PINCTRL_GRP_I2C0_14, PINCTRL_GRP_PJTAG0_5, PINCTRL_GRP_SPI1_4, PINCTRL_GRP_TTC2_7_CLK, PINCTRL_GRP_UART0_14, PINCTRL_GRP_TRACE0_2, END_OF_GROUPS, }), }, [PINCTRL_PIN_59] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET2_0, PINCTRL_GRP_USB0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_59, PINCTRL_GRP_CAN0_14, PINCTRL_GRP_I2C0_14, PINCTRL_GRP_PJTAG0_5, PINCTRL_GRP_SPI1_4_SS2, PINCTRL_GRP_TTC2_7_WAV, PINCTRL_GRP_UART0_14, PINCTRL_GRP_TRACE0_2, END_OF_GROUPS, }), }, [PINCTRL_PIN_60] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET2_0, PINCTRL_GRP_USB0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_60, PINCTRL_GRP_CAN1_15, PINCTRL_GRP_I2C1_15, PINCTRL_GRP_PJTAG0_5, PINCTRL_GRP_SPI1_4_SS1, PINCTRL_GRP_TTC1_7_CLK, PINCTRL_GRP_UART1_15, PINCTRL_GRP_TRACE0_2, END_OF_GROUPS, }), }, [PINCTRL_PIN_61] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET2_0, PINCTRL_GRP_USB0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_61, PINCTRL_GRP_CAN1_15, PINCTRL_GRP_I2C1_15, PINCTRL_GRP_PJTAG0_5, PINCTRL_GRP_SPI1_4_SS0, PINCTRL_GRP_TTC1_7_WAV, PINCTRL_GRP_UART1_15, PINCTRL_GRP_TRACE0_2, END_OF_GROUPS, }), }, [PINCTRL_PIN_62] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET2_0, PINCTRL_GRP_USB0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_62, PINCTRL_GRP_CAN0_15, PINCTRL_GRP_I2C0_15, PINCTRL_GRP_SWDT0_9_CLK, PINCTRL_GRP_SPI1_4, PINCTRL_GRP_TTC0_7_CLK, PINCTRL_GRP_UART0_15, PINCTRL_GRP_TRACE0_2, END_OF_GROUPS, }), }, [PINCTRL_PIN_63] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET2_0, PINCTRL_GRP_USB0_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_63, PINCTRL_GRP_CAN0_15, PINCTRL_GRP_I2C0_15, PINCTRL_GRP_SWDT0_9_RST, PINCTRL_GRP_SPI1_4, PINCTRL_GRP_TTC0_7_WAV, PINCTRL_GRP_UART0_15, PINCTRL_GRP_TRACE0_2, END_OF_GROUPS, }), }, [PINCTRL_PIN_64] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET3_0, PINCTRL_GRP_USB1_0, PINCTRL_GRP_SDIO0_2, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_64, PINCTRL_GRP_CAN1_16, PINCTRL_GRP_I2C1_16, PINCTRL_GRP_SWDT1_10_CLK, PINCTRL_GRP_SPI0_5, PINCTRL_GRP_TTC3_8_CLK, PINCTRL_GRP_UART1_16, PINCTRL_GRP_TRACE0_2, PINCTRL_GRP_SDIO0_4BIT_2_0, PINCTRL_GRP_SDIO0_4BIT_2_1, PINCTRL_GRP_SDIO0_1BIT_2_0, PINCTRL_GRP_SDIO0_1BIT_2_1, PINCTRL_GRP_SDIO0_1BIT_2_2, PINCTRL_GRP_SDIO0_1BIT_2_3, PINCTRL_GRP_SDIO0_1BIT_2_4, PINCTRL_GRP_SDIO0_1BIT_2_5, PINCTRL_GRP_SDIO0_1BIT_2_6, PINCTRL_GRP_SDIO0_1BIT_2_7, END_OF_GROUPS, }), }, [PINCTRL_PIN_65] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET3_0, PINCTRL_GRP_USB1_0, PINCTRL_GRP_SDIO0_2_CD, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_65, PINCTRL_GRP_CAN1_16, PINCTRL_GRP_I2C1_16, PINCTRL_GRP_SWDT1_10_RST, PINCTRL_GRP_SPI0_5_SS2, PINCTRL_GRP_TTC3_8_WAV, PINCTRL_GRP_UART1_16, PINCTRL_GRP_TRACE0_2, END_OF_GROUPS, }), }, [PINCTRL_PIN_66] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET3_0, PINCTRL_GRP_USB1_0, PINCTRL_GRP_SDIO0_2, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_66, PINCTRL_GRP_CAN0_16, PINCTRL_GRP_I2C0_16, PINCTRL_GRP_SWDT0_10_CLK, PINCTRL_GRP_SPI0_5_SS1, PINCTRL_GRP_TTC2_8_CLK, PINCTRL_GRP_UART0_16, PINCTRL_GRP_TRACE0_2, PINCTRL_GRP_SDIO0_4BIT_2_0, PINCTRL_GRP_SDIO0_4BIT_2_1, PINCTRL_GRP_SDIO0_1BIT_2_0, PINCTRL_GRP_SDIO0_1BIT_2_1, PINCTRL_GRP_SDIO0_1BIT_2_2, PINCTRL_GRP_SDIO0_1BIT_2_3, PINCTRL_GRP_SDIO0_1BIT_2_4, PINCTRL_GRP_SDIO0_1BIT_2_5, PINCTRL_GRP_SDIO0_1BIT_2_6, PINCTRL_GRP_SDIO0_1BIT_2_7, END_OF_GROUPS, }), }, [PINCTRL_PIN_67] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET3_0, PINCTRL_GRP_USB1_0, PINCTRL_GRP_SDIO0_2, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_67, PINCTRL_GRP_CAN0_16, PINCTRL_GRP_I2C0_16, PINCTRL_GRP_SWDT0_10_RST, PINCTRL_GRP_SPI0_5_SS0, PINCTRL_GRP_TTC2_8_WAV, PINCTRL_GRP_UART0_16, PINCTRL_GRP_TRACE0_2, PINCTRL_GRP_SDIO0_4BIT_2_0, PINCTRL_GRP_SDIO0_1BIT_2_0, END_OF_GROUPS, }), }, [PINCTRL_PIN_68] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET3_0, PINCTRL_GRP_USB1_0, PINCTRL_GRP_SDIO0_2, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_68, PINCTRL_GRP_CAN1_17, PINCTRL_GRP_I2C1_17, PINCTRL_GRP_SWDT1_11_CLK, PINCTRL_GRP_SPI0_5, PINCTRL_GRP_TTC1_8_CLK, PINCTRL_GRP_UART1_17, PINCTRL_GRP_TRACE0_2, PINCTRL_GRP_SDIO0_4BIT_2_0, PINCTRL_GRP_SDIO0_1BIT_2_1, END_OF_GROUPS, }), }, [PINCTRL_PIN_69] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET3_0, PINCTRL_GRP_USB1_0, PINCTRL_GRP_SDIO0_2, PINCTRL_GRP_SDIO1_1_WP, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_69, PINCTRL_GRP_CAN1_17, PINCTRL_GRP_I2C1_17, PINCTRL_GRP_SWDT1_11_RST, PINCTRL_GRP_SPI0_5, PINCTRL_GRP_TTC1_8_WAV, PINCTRL_GRP_UART1_17, PINCTRL_GRP_TRACE0_2, PINCTRL_GRP_SDIO0_4BIT_2_0, PINCTRL_GRP_SDIO0_1BIT_2_2, END_OF_GROUPS, }), }, [PINCTRL_PIN_70] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET3_0, PINCTRL_GRP_USB1_0, PINCTRL_GRP_SDIO0_2, PINCTRL_GRP_SDIO1_1_PC, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_70, PINCTRL_GRP_CAN0_17, PINCTRL_GRP_I2C0_17, PINCTRL_GRP_SWDT0_11_CLK, PINCTRL_GRP_SPI1_5, PINCTRL_GRP_TTC0_8_CLK, PINCTRL_GRP_UART0_17, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_4BIT_2_0, PINCTRL_GRP_SDIO0_1BIT_2_3, END_OF_GROUPS, }), }, [PINCTRL_PIN_71] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET3_0, PINCTRL_GRP_USB1_0, PINCTRL_GRP_SDIO0_2, PINCTRL_GRP_SDIO1_4BIT_1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_71, PINCTRL_GRP_CAN0_17, PINCTRL_GRP_I2C0_17, PINCTRL_GRP_SWDT0_11_RST, PINCTRL_GRP_SPI1_5_SS2, PINCTRL_GRP_TTC0_8_WAV, PINCTRL_GRP_UART0_17, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_2, PINCTRL_GRP_SDIO0_4BIT_2_1, PINCTRL_GRP_SDIO0_1BIT_2_4, PINCTRL_GRP_SDIO1_1BIT_1_0, END_OF_GROUPS, }), }, [PINCTRL_PIN_72] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET3_0, PINCTRL_GRP_USB1_0, PINCTRL_GRP_SDIO0_2, PINCTRL_GRP_SDIO1_4BIT_1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_72, PINCTRL_GRP_CAN1_18, PINCTRL_GRP_I2C1_18, PINCTRL_GRP_SWDT1_12_CLK, PINCTRL_GRP_SPI1_5_SS1, PINCTRL_GRP_RESERVED, PINCTRL_GRP_UART1_18, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_4BIT_2_1, PINCTRL_GRP_SDIO0_1BIT_2_5, PINCTRL_GRP_SDIO1_1BIT_1_1, END_OF_GROUPS, }), }, [PINCTRL_PIN_73] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET3_0, PINCTRL_GRP_USB1_0, PINCTRL_GRP_SDIO0_2, PINCTRL_GRP_SDIO1_4BIT_1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_73, PINCTRL_GRP_CAN1_18, PINCTRL_GRP_I2C1_18, PINCTRL_GRP_SWDT1_12_RST, PINCTRL_GRP_SPI1_5_SS0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_UART1_18, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_4BIT_2_1, PINCTRL_GRP_SDIO0_1BIT_2_6, PINCTRL_GRP_SDIO1_1BIT_1_2, END_OF_GROUPS, }), }, [PINCTRL_PIN_74] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET3_0, PINCTRL_GRP_USB1_0, PINCTRL_GRP_SDIO0_2, PINCTRL_GRP_SDIO1_4BIT_1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_74, PINCTRL_GRP_CAN0_18, PINCTRL_GRP_I2C0_18, PINCTRL_GRP_SWDT0_12_CLK, PINCTRL_GRP_SPI1_5, PINCTRL_GRP_RESERVED, PINCTRL_GRP_UART0_18, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_4BIT_2_1, PINCTRL_GRP_SDIO0_1BIT_2_7, PINCTRL_GRP_SDIO1_1BIT_1_3, END_OF_GROUPS, }), }, [PINCTRL_PIN_75] = { .groups = &((uint16_t []) { PINCTRL_GRP_ETHERNET3_0, PINCTRL_GRP_USB1_0, PINCTRL_GRP_SDIO0_2_PC, PINCTRL_GRP_SDIO1_4BIT_1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_75, PINCTRL_GRP_CAN0_18, PINCTRL_GRP_I2C0_18, PINCTRL_GRP_SWDT0_12_RST, PINCTRL_GRP_SPI1_5, PINCTRL_GRP_RESERVED, PINCTRL_GRP_UART0_18, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO1_1BIT_1_0, PINCTRL_GRP_SDIO1_1BIT_1_1, PINCTRL_GRP_SDIO1_1BIT_1_2, PINCTRL_GRP_SDIO1_1BIT_1_3, END_OF_GROUPS, }), }, [PINCTRL_PIN_76] = { .groups = &((uint16_t []) { PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO0_2_WP, PINCTRL_GRP_SDIO1_4BIT_1_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_76, PINCTRL_GRP_CAN1_19, PINCTRL_GRP_I2C1_19, PINCTRL_GRP_MDIO0_0, PINCTRL_GRP_MDIO1_1, PINCTRL_GRP_MDIO2_0, PINCTRL_GRP_MDIO3_0, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO1_1BIT_1_0, PINCTRL_GRP_SDIO1_1BIT_1_1, PINCTRL_GRP_SDIO1_1BIT_1_2, PINCTRL_GRP_SDIO1_1BIT_1_3, END_OF_GROUPS, }), }, [PINCTRL_PIN_77] = { .groups = &((uint16_t []) { PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_RESERVED, PINCTRL_GRP_SDIO1_1_CD, PINCTRL_GRP_RESERVED, PINCTRL_GRP_GPIO0_77, PINCTRL_GRP_CAN1_19, PINCTRL_GRP_I2C1_19, PINCTRL_GRP_MDIO0_0, PINCTRL_GRP_MDIO1_1, PINCTRL_GRP_MDIO2_0, PINCTRL_GRP_MDIO3_0, PINCTRL_GRP_RESERVED, END_OF_GROUPS, }), }, }; /** * pm_api_pinctrl_get_num_pins() - PM call to request number of pins * @npins Number of pins * * This function is used by master to get number of pins * * @return Returns success. */ enum pm_ret_status pm_api_pinctrl_get_num_pins(unsigned int *npins) { *npins = MAX_PIN; return PM_RET_SUCCESS; } /** * pm_api_pinctrl_get_num_functions() - PM call to request number of functions * @nfuncs Number of functions * * This function is used by master to get number of functions * * @return Returns success. */ enum pm_ret_status pm_api_pinctrl_get_num_functions(unsigned int *nfuncs) { *nfuncs = MAX_FUNCTION; return PM_RET_SUCCESS; } /** * pm_api_pinctrl_get_num_func_groups() - PM call to request number of * function groups * @fid Function Id * @ngroups Number of function groups * * This function is used by master to get number of function groups * * @return Returns success. */ enum pm_ret_status pm_api_pinctrl_get_num_func_groups(unsigned int fid, unsigned int *ngroups) { int i = 0; uint16_t *grps; if (fid >= MAX_FUNCTION) return PM_RET_ERROR_ARGS; *ngroups = 0; grps = *pinctrl_functions[fid].groups; if (grps == NULL) return PM_RET_SUCCESS; while (grps[i++] != (uint16_t)END_OF_GROUPS) (*ngroups)++; return PM_RET_SUCCESS; } /** * pm_api_pinctrl_get_function_name() - PM call to request a function name * @fid Function ID * @name Name of function (max 16 bytes) * * This function is used by master to get name of function specified * by given function ID. * * @return Returns success. In case of error, name data is 0. */ enum pm_ret_status pm_api_pinctrl_get_function_name(unsigned int fid, char *name) { if (fid >= MAX_FUNCTION) memcpy(name, END_OF_FUNCTION, FUNCTION_NAME_LEN); else memcpy(name, pinctrl_functions[fid].name, FUNCTION_NAME_LEN); return PM_RET_SUCCESS; } /** * pm_api_pinctrl_get_function_groups() - PM call to request first 6 function * groups of function Id * @fid Function ID * @index Index of next function groups * @groups Function groups * * This function is used by master to get function groups specified * by given function Id. This API will return 6 function groups with * a single response. To get other function groups, master should call * same API in loop with new function groups index till error is returned. * * E.g First call should have index 0 which will return function groups * 0, 1, 2, 3, 4 and 5. Next call, index should be 6 which will return * function groups 6, 7, 8, 9, 10 and 11 and so on. * * Return: Returns status, either success or error+reason. */ enum pm_ret_status pm_api_pinctrl_get_function_groups(unsigned int fid, unsigned int index, uint16_t *groups) { unsigned int i; uint16_t *grps; if (fid >= MAX_FUNCTION) return PM_RET_ERROR_ARGS; memset(groups, END_OF_GROUPS, GROUPS_PAYLOAD_LEN); grps = *pinctrl_functions[fid].groups; if (grps == NULL) return PM_RET_SUCCESS; /* Skip groups till index */ for (i = 0; i < index; i++) if (grps[i] == (uint16_t)END_OF_GROUPS) return PM_RET_SUCCESS; for (i = 0; i < NUM_GROUPS_PER_RESP; i++) { groups[i] = grps[index + i]; if (groups[i] == (uint16_t)END_OF_GROUPS) break; } return PM_RET_SUCCESS; } /** * pm_api_pinctrl_get_pin_groups() - PM call to request first 6 pin * groups of pin * @pin Pin * @index Index of next pin groups * @groups pin groups * * This function is used by master to get pin groups specified * by given pin Id. This API will return 6 pin groups with * a single response. To get other pin groups, master should call * same API in loop with new pin groups index till error is returned. * * E.g First call should have index 0 which will return pin groups * 0, 1, 2, 3, 4 and 5. Next call, index should be 6 which will return * pin groups 6, 7, 8, 9, 10 and 11 and so on. * * Return: Returns status, either success or error+reason. */ enum pm_ret_status pm_api_pinctrl_get_pin_groups(unsigned int pin, unsigned int index, uint16_t *groups) { unsigned int i; uint16_t *grps; if (pin >= MAX_PIN) return PM_RET_ERROR_ARGS; memset(groups, END_OF_GROUPS, GROUPS_PAYLOAD_LEN); grps = *zynqmp_pin_groups[pin].groups; if (!grps) return PM_RET_SUCCESS; /* Skip groups till index */ for (i = 0; i < index; i++) if (grps[i] == (uint16_t)END_OF_GROUPS) return PM_RET_SUCCESS; for (i = 0; i < NUM_GROUPS_PER_RESP; i++) { groups[i] = grps[index + i]; if (groups[i] == (uint16_t)END_OF_GROUPS) break; } return PM_RET_SUCCESS; } /** * pm_api_pinctrl_get_function() - Read function id set for the given pin * @pin Pin number * @nid Node ID of function currently set for given pin * * This function provides the function currently set for the given pin. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_api_pinctrl_get_function(unsigned int pin, unsigned int *id) { unsigned int i = 0, j = 0; enum pm_ret_status ret = PM_RET_SUCCESS; unsigned int ctrlreg, val, gid; uint16_t *grps; ctrlreg = IOU_SLCR_BASEADDR + 4U * pin; ret = pm_mmio_read(ctrlreg, &val); if (ret != PM_RET_SUCCESS) return ret; val &= PINCTRL_FUNCTION_MASK; for (i = 0; i < NFUNCS_PER_PIN; i++) if (val == pm_pinctrl_mux[i]) break; if (i == NFUNCS_PER_PIN) return PM_RET_ERROR_NOTSUPPORTED; gid = *(*zynqmp_pin_groups[pin].groups + i); for (i = 0; i < MAX_FUNCTION; i++) { grps = *pinctrl_functions[i].groups; if (grps == NULL) continue; if (val != pinctrl_functions[i].regval) continue; for (j = 0; grps[j] != (uint16_t)END_OF_GROUPS; j++) { if (gid == grps[j]) { *id = i; goto done; } } } if (i == MAX_FUNCTION) ret = PM_RET_ERROR_ARGS; done: return ret; } /** * pm_api_pinctrl_set_function() - Set function id set for the given pin * @pin Pin number * @nid Node ID of function to set for given pin * * This function provides the function currently set for the given pin. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_api_pinctrl_set_function(unsigned int pin, unsigned int fid) { int i, j; unsigned int ctrlreg, val; uint16_t *pgrps, *fgrps; ctrlreg = IOU_SLCR_BASEADDR + 4U * pin; val = pinctrl_functions[fid].regval; for (i = 0; i < NFUNCS_PER_PIN; i++) if (val == pm_pinctrl_mux[i]) break; if (i == NFUNCS_PER_PIN) return PM_RET_ERROR_NOTSUPPORTED; pgrps = *zynqmp_pin_groups[pin].groups; if (!pgrps) return PM_RET_ERROR_NOTSUPPORTED; fgrps = *pinctrl_functions[fid].groups; if (!fgrps) return PM_RET_ERROR_NOTSUPPORTED; for (i = 0; fgrps[i] != (uint16_t)END_OF_GROUPS; i++) for (j = 0; pgrps[j] != (uint16_t)END_OF_GROUPS; j++) if (fgrps[i] == pgrps[j]) goto match; return PM_RET_ERROR_NOTSUPPORTED; match: return pm_mmio_write(ctrlreg, PINCTRL_FUNCTION_MASK, val); } /** * pm_api_pinctrl_set_config() - Set configuration parameter for given pin * @pin: Pin for which configuration is to be set * @param: Configuration parameter to be set * @value: Value to be set for configuration parameter * * This function sets value of requested configuration parameter for given pin. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_api_pinctrl_set_config(unsigned int pin, unsigned int param, unsigned int value) { enum pm_ret_status ret; unsigned int ctrlreg, mask, val, offset; if (param >= PINCTRL_CONFIG_MAX) return PM_RET_ERROR_NOTSUPPORTED; if (pin >= PINCTRL_NUM_MIOS) return PM_RET_ERROR_ARGS; mask = 1 << PINCTRL_PIN_OFFSET(pin); switch (param) { case PINCTRL_CONFIG_SLEW_RATE: if (value != PINCTRL_SLEW_RATE_FAST && value != PINCTRL_SLEW_RATE_SLOW) return PM_RET_ERROR_ARGS; ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR, PINCTRL_SLEWCTRL_REG_OFFSET, pin); val = value << PINCTRL_PIN_OFFSET(pin); ret = pm_mmio_write(ctrlreg, mask, val); break; case PINCTRL_CONFIG_BIAS_STATUS: if (value != PINCTRL_BIAS_ENABLE && value != PINCTRL_BIAS_DISABLE) return PM_RET_ERROR_ARGS; ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR, PINCTRL_PULLSTAT_REG_OFFSET, pin); offset = PINCTRL_PIN_OFFSET(pin); if (ctrlreg == IOU_SLCR_BANK1_CTRL5) offset = (offset < 12U) ? (offset + 14U) : (offset - 12U); val = value << offset; mask = 1 << offset; ret = pm_mmio_write(ctrlreg, mask, val); break; case PINCTRL_CONFIG_PULL_CTRL: if (value != PINCTRL_BIAS_PULL_DOWN && value != PINCTRL_BIAS_PULL_UP) return PM_RET_ERROR_ARGS; ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR, PINCTRL_PULLSTAT_REG_OFFSET, pin); offset = PINCTRL_PIN_OFFSET(pin); if (ctrlreg == IOU_SLCR_BANK1_CTRL5) offset = (offset < 12U) ? (offset + 14U) : (offset - 12U); val = PINCTRL_BIAS_ENABLE << offset; ret = pm_mmio_write(ctrlreg, 1 << offset, val); if (ret != PM_RET_SUCCESS) return ret; ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR, PINCTRL_PULLCTRL_REG_OFFSET, pin); val = value << PINCTRL_PIN_OFFSET(pin); ret = pm_mmio_write(ctrlreg, mask, val); break; case PINCTRL_CONFIG_SCHMITT_CMOS: if (value != PINCTRL_INPUT_TYPE_CMOS && value != PINCTRL_INPUT_TYPE_SCHMITT) return PM_RET_ERROR_ARGS; ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR, PINCTRL_SCHCMOS_REG_OFFSET, pin); val = value << PINCTRL_PIN_OFFSET(pin); ret = pm_mmio_write(ctrlreg, mask, val); break; case PINCTRL_CONFIG_DRIVE_STRENGTH: if (value > PINCTRL_DRIVE_STRENGTH_12MA) return PM_RET_ERROR_ARGS; ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR, PINCTRL_DRVSTRN0_REG_OFFSET, pin); val = (value >> 1) << PINCTRL_PIN_OFFSET(pin); ret = pm_mmio_write(ctrlreg, mask, val); if (ret) return ret; ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR, PINCTRL_DRVSTRN1_REG_OFFSET, pin); val = (value & 0x01U) << PINCTRL_PIN_OFFSET(pin); ret = pm_mmio_write(ctrlreg, mask, val); break; default: ERROR("Invalid parameter %u\n", param); ret = PM_RET_ERROR_NOTSUPPORTED; break; } return ret; } /** * pm_api_pinctrl_get_config() - Get configuration parameter value for given pin * @pin: Pin for which configuration is to be read * @param: Configuration parameter to be read * @value: buffer to store value of configuration parameter * * This function reads value of requested configuration parameter for given pin. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_api_pinctrl_get_config(unsigned int pin, unsigned int param, unsigned int *value) { enum pm_ret_status ret; unsigned int ctrlreg, val; if (param >= PINCTRL_CONFIG_MAX) return PM_RET_ERROR_NOTSUPPORTED; if (pin >= PINCTRL_NUM_MIOS) return PM_RET_ERROR_ARGS; switch (param) { case PINCTRL_CONFIG_SLEW_RATE: ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR, PINCTRL_SLEWCTRL_REG_OFFSET, pin); ret = pm_mmio_read(ctrlreg, &val); if (ret != PM_RET_SUCCESS) return ret; *value = PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val); break; case PINCTRL_CONFIG_BIAS_STATUS: ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR, PINCTRL_PULLSTAT_REG_OFFSET, pin); ret = pm_mmio_read(ctrlreg, &val); if (ret) return ret; if (ctrlreg == IOU_SLCR_BANK1_CTRL5) val = ((val & 0x3FFF) << 12) | ((val >> 14) & 0xFFF); *value = PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val); break; case PINCTRL_CONFIG_PULL_CTRL: ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR, PINCTRL_PULLCTRL_REG_OFFSET, pin); ret = pm_mmio_read(ctrlreg, &val); if (ret) return ret; *value = PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val); break; case PINCTRL_CONFIG_SCHMITT_CMOS: ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR, PINCTRL_SCHCMOS_REG_OFFSET, pin); ret = pm_mmio_read(ctrlreg, &val); if (ret) return ret; *value = PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val); break; case PINCTRL_CONFIG_DRIVE_STRENGTH: ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR, PINCTRL_DRVSTRN0_REG_OFFSET, pin); ret = pm_mmio_read(ctrlreg, &val); if (ret) return ret; *value = PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val) << 1; ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR, PINCTRL_DRVSTRN1_REG_OFFSET, pin); ret = pm_mmio_read(ctrlreg, &val); if (ret) return ret; *value |= PINCTRL_REGVAL_TO_PIN_CONFIG(pin, val); break; case PINCTRL_CONFIG_VOLTAGE_STATUS: ctrlreg = PINCTRL_CFG_ADDR_OFFSET(IOU_SLCR_BASEADDR, PINCTRL_VOLTAGE_STAT_REG_OFFSET, pin); ret = pm_mmio_read(ctrlreg, &val); if (ret) return ret; *value = val & PINCTRL_VOLTAGE_STATUS_MASK; break; default: return PM_RET_ERROR_NOTSUPPORTED; } return PM_RET_SUCCESS; } trusted-firmware-a-2.2/plat/xilinx/zynqmp/pm_service/pm_api_pinctrl.h000066400000000000000000000415151355360272700262350ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * ZynqMP system level PM-API functions for pin control. */ #ifndef PM_API_PINCTRL_H #define PM_API_PINCTRL_H #include "pm_common.h" #define FUNCTION_NAME_LEN U(16) #define GROUPS_PAYLOAD_LEN U(12) #define NUM_GROUPS_PER_RESP U(6) #define END_OF_FUNCTION "END_OF_FUNCTION" #define END_OF_GROUPS -1 #define PINCTRL_GRP_RESERVED -2 //pinctrl function ids enum { PINCTRL_FUNC_CAN0, PINCTRL_FUNC_CAN1, PINCTRL_FUNC_ETHERNET0, PINCTRL_FUNC_ETHERNET1, PINCTRL_FUNC_ETHERNET2, PINCTRL_FUNC_ETHERNET3, PINCTRL_FUNC_GEMTSU0, PINCTRL_FUNC_GPIO0, PINCTRL_FUNC_I2C0, PINCTRL_FUNC_I2C1, PINCTRL_FUNC_MDIO0, PINCTRL_FUNC_MDIO1, PINCTRL_FUNC_MDIO2, PINCTRL_FUNC_MDIO3, PINCTRL_FUNC_QSPI0, PINCTRL_FUNC_QSPI_FBCLK, PINCTRL_FUNC_QSPI_SS, PINCTRL_FUNC_SPI0, PINCTRL_FUNC_SPI1, PINCTRL_FUNC_SPI0_SS, PINCTRL_FUNC_SPI1_SS, PINCTRL_FUNC_SDIO0, PINCTRL_FUNC_SDIO0_PC, PINCTRL_FUNC_SDIO0_CD, PINCTRL_FUNC_SDIO0_WP, PINCTRL_FUNC_SDIO1, PINCTRL_FUNC_SDIO1_PC, PINCTRL_FUNC_SDIO1_CD, PINCTRL_FUNC_SDIO1_WP, PINCTRL_FUNC_NAND0, PINCTRL_FUNC_NAND0_CE, PINCTRL_FUNC_NAND0_RB, PINCTRL_FUNC_NAND0_DQS, PINCTRL_FUNC_TTC0_CLK, PINCTRL_FUNC_TTC0_WAV, PINCTRL_FUNC_TTC1_CLK, PINCTRL_FUNC_TTC1_WAV, PINCTRL_FUNC_TTC2_CLK, PINCTRL_FUNC_TTC2_WAV, PINCTRL_FUNC_TTC3_CLK, PINCTRL_FUNC_TTC3_WAV, PINCTRL_FUNC_UART0, PINCTRL_FUNC_UART1, PINCTRL_FUNC_USB0, PINCTRL_FUNC_USB1, PINCTRL_FUNC_SWDT0_CLK, PINCTRL_FUNC_SWDT0_RST, PINCTRL_FUNC_SWDT1_CLK, PINCTRL_FUNC_SWDT1_RST, PINCTRL_FUNC_PMU0, PINCTRL_FUNC_PCIE0, PINCTRL_FUNC_CSU0, PINCTRL_FUNC_DPAUX0, PINCTRL_FUNC_PJTAG0, PINCTRL_FUNC_TRACE0, PINCTRL_FUNC_TRACE0_CLK, PINCTRL_FUNC_TESTSCAN0, END_FUNCTION, }; #define MAX_FUNCTION (unsigned int)(END_FUNCTION) // pinctrl pin numbers enum { PINCTRL_PIN_0, PINCTRL_PIN_1, PINCTRL_PIN_2, PINCTRL_PIN_3, PINCTRL_PIN_4, PINCTRL_PIN_5, PINCTRL_PIN_6, PINCTRL_PIN_7, PINCTRL_PIN_8, PINCTRL_PIN_9, PINCTRL_PIN_10, PINCTRL_PIN_11, PINCTRL_PIN_12, PINCTRL_PIN_13, PINCTRL_PIN_14, PINCTRL_PIN_15, PINCTRL_PIN_16, PINCTRL_PIN_17, PINCTRL_PIN_18, PINCTRL_PIN_19, PINCTRL_PIN_20, PINCTRL_PIN_21, PINCTRL_PIN_22, PINCTRL_PIN_23, PINCTRL_PIN_24, PINCTRL_PIN_25, PINCTRL_PIN_26, PINCTRL_PIN_27, PINCTRL_PIN_28, PINCTRL_PIN_29, PINCTRL_PIN_30, PINCTRL_PIN_31, PINCTRL_PIN_32, PINCTRL_PIN_33, PINCTRL_PIN_34, PINCTRL_PIN_35, PINCTRL_PIN_36, PINCTRL_PIN_37, PINCTRL_PIN_38, PINCTRL_PIN_39, PINCTRL_PIN_40, PINCTRL_PIN_41, PINCTRL_PIN_42, PINCTRL_PIN_43, PINCTRL_PIN_44, PINCTRL_PIN_45, PINCTRL_PIN_46, PINCTRL_PIN_47, PINCTRL_PIN_48, PINCTRL_PIN_49, PINCTRL_PIN_50, PINCTRL_PIN_51, PINCTRL_PIN_52, PINCTRL_PIN_53, PINCTRL_PIN_54, PINCTRL_PIN_55, PINCTRL_PIN_56, PINCTRL_PIN_57, PINCTRL_PIN_58, PINCTRL_PIN_59, PINCTRL_PIN_60, PINCTRL_PIN_61, PINCTRL_PIN_62, PINCTRL_PIN_63, PINCTRL_PIN_64, PINCTRL_PIN_65, PINCTRL_PIN_66, PINCTRL_PIN_67, PINCTRL_PIN_68, PINCTRL_PIN_69, PINCTRL_PIN_70, PINCTRL_PIN_71, PINCTRL_PIN_72, PINCTRL_PIN_73, PINCTRL_PIN_74, PINCTRL_PIN_75, PINCTRL_PIN_76, PINCTRL_PIN_77, END_PINS, }; #define MAX_PIN (unsigned int)(END_PINS) // pinctrl group ids enum { PINCTRL_GRP_ETHERNET0_0, PINCTRL_GRP_ETHERNET1_0, PINCTRL_GRP_ETHERNET2_0, PINCTRL_GRP_ETHERNET3_0, PINCTRL_GRP_GEMTSU0_0, PINCTRL_GRP_GEMTSU0_1, PINCTRL_GRP_GEMTSU0_2, PINCTRL_GRP_MDIO0_0, PINCTRL_GRP_MDIO1_0, PINCTRL_GRP_MDIO1_1, PINCTRL_GRP_MDIO2_0, PINCTRL_GRP_MDIO3_0, PINCTRL_GRP_QSPI0_0, PINCTRL_GRP_QSPI_SS, PINCTRL_GRP_QSPI_FBCLK, PINCTRL_GRP_SPI0_0, PINCTRL_GRP_SPI0_0_SS0, PINCTRL_GRP_SPI0_0_SS1, PINCTRL_GRP_SPI0_0_SS2, PINCTRL_GRP_SPI0_1, PINCTRL_GRP_SPI0_1_SS0, PINCTRL_GRP_SPI0_1_SS1, PINCTRL_GRP_SPI0_1_SS2, PINCTRL_GRP_SPI0_2, PINCTRL_GRP_SPI0_2_SS0, PINCTRL_GRP_SPI0_2_SS1, PINCTRL_GRP_SPI0_2_SS2, PINCTRL_GRP_SPI0_3, PINCTRL_GRP_SPI0_3_SS0, PINCTRL_GRP_SPI0_3_SS1, PINCTRL_GRP_SPI0_3_SS2, PINCTRL_GRP_SPI0_4, PINCTRL_GRP_SPI0_4_SS0, PINCTRL_GRP_SPI0_4_SS1, PINCTRL_GRP_SPI0_4_SS2, PINCTRL_GRP_SPI0_5, PINCTRL_GRP_SPI0_5_SS0, PINCTRL_GRP_SPI0_5_SS1, PINCTRL_GRP_SPI0_5_SS2, PINCTRL_GRP_SPI1_0, PINCTRL_GRP_SPI1_0_SS0, PINCTRL_GRP_SPI1_0_SS1, PINCTRL_GRP_SPI1_0_SS2, PINCTRL_GRP_SPI1_1, PINCTRL_GRP_SPI1_1_SS0, PINCTRL_GRP_SPI1_1_SS1, PINCTRL_GRP_SPI1_1_SS2, PINCTRL_GRP_SPI1_2, PINCTRL_GRP_SPI1_2_SS0, PINCTRL_GRP_SPI1_2_SS1, PINCTRL_GRP_SPI1_2_SS2, PINCTRL_GRP_SPI1_3, PINCTRL_GRP_SPI1_3_SS0, PINCTRL_GRP_SPI1_3_SS1, PINCTRL_GRP_SPI1_3_SS2, PINCTRL_GRP_SPI1_4, PINCTRL_GRP_SPI1_4_SS0, PINCTRL_GRP_SPI1_4_SS1, PINCTRL_GRP_SPI1_4_SS2, PINCTRL_GRP_SPI1_5, PINCTRL_GRP_SPI1_5_SS0, PINCTRL_GRP_SPI1_5_SS1, PINCTRL_GRP_SPI1_5_SS2, PINCTRL_GRP_SDIO0_0, PINCTRL_GRP_SDIO0_1, PINCTRL_GRP_SDIO0_2, PINCTRL_GRP_SDIO0_4BIT_0_0, PINCTRL_GRP_SDIO0_4BIT_0_1, PINCTRL_GRP_SDIO0_4BIT_1_0, PINCTRL_GRP_SDIO0_4BIT_1_1, PINCTRL_GRP_SDIO0_4BIT_2_0, PINCTRL_GRP_SDIO0_4BIT_2_1, PINCTRL_GRP_SDIO0_1BIT_0_0, PINCTRL_GRP_SDIO0_1BIT_0_1, PINCTRL_GRP_SDIO0_1BIT_0_2, PINCTRL_GRP_SDIO0_1BIT_0_3, PINCTRL_GRP_SDIO0_1BIT_0_4, PINCTRL_GRP_SDIO0_1BIT_0_5, PINCTRL_GRP_SDIO0_1BIT_0_6, PINCTRL_GRP_SDIO0_1BIT_0_7, PINCTRL_GRP_SDIO0_1BIT_1_0, PINCTRL_GRP_SDIO0_1BIT_1_1, PINCTRL_GRP_SDIO0_1BIT_1_2, PINCTRL_GRP_SDIO0_1BIT_1_3, PINCTRL_GRP_SDIO0_1BIT_1_4, PINCTRL_GRP_SDIO0_1BIT_1_5, PINCTRL_GRP_SDIO0_1BIT_1_6, PINCTRL_GRP_SDIO0_1BIT_1_7, PINCTRL_GRP_SDIO0_1BIT_2_0, PINCTRL_GRP_SDIO0_1BIT_2_1, PINCTRL_GRP_SDIO0_1BIT_2_2, PINCTRL_GRP_SDIO0_1BIT_2_3, PINCTRL_GRP_SDIO0_1BIT_2_4, PINCTRL_GRP_SDIO0_1BIT_2_5, PINCTRL_GRP_SDIO0_1BIT_2_6, PINCTRL_GRP_SDIO0_1BIT_2_7, PINCTRL_GRP_SDIO0_0_PC, PINCTRL_GRP_SDIO0_0_CD, PINCTRL_GRP_SDIO0_0_WP, PINCTRL_GRP_SDIO0_1_PC, PINCTRL_GRP_SDIO0_1_CD, PINCTRL_GRP_SDIO0_1_WP, PINCTRL_GRP_SDIO0_2_PC, PINCTRL_GRP_SDIO0_2_CD, PINCTRL_GRP_SDIO0_2_WP, PINCTRL_GRP_SDIO1_0, PINCTRL_GRP_SDIO1_4BIT_0_0, PINCTRL_GRP_SDIO1_4BIT_0_1, PINCTRL_GRP_SDIO1_4BIT_1_0, PINCTRL_GRP_SDIO1_1BIT_0_0, PINCTRL_GRP_SDIO1_1BIT_0_1, PINCTRL_GRP_SDIO1_1BIT_0_2, PINCTRL_GRP_SDIO1_1BIT_0_3, PINCTRL_GRP_SDIO1_1BIT_0_4, PINCTRL_GRP_SDIO1_1BIT_0_5, PINCTRL_GRP_SDIO1_1BIT_0_6, PINCTRL_GRP_SDIO1_1BIT_0_7, PINCTRL_GRP_SDIO1_1BIT_1_0, PINCTRL_GRP_SDIO1_1BIT_1_1, PINCTRL_GRP_SDIO1_1BIT_1_2, PINCTRL_GRP_SDIO1_1BIT_1_3, PINCTRL_GRP_SDIO1_0_PC, PINCTRL_GRP_SDIO1_0_CD, PINCTRL_GRP_SDIO1_0_WP, PINCTRL_GRP_SDIO1_1_PC, PINCTRL_GRP_SDIO1_1_CD, PINCTRL_GRP_SDIO1_1_WP, PINCTRL_GRP_NAND0_0, PINCTRL_GRP_NAND0_0_CE, PINCTRL_GRP_NAND0_0_RB, PINCTRL_GRP_NAND0_0_DQS, PINCTRL_GRP_NAND0_1_CE, PINCTRL_GRP_NAND0_1_RB, PINCTRL_GRP_NAND0_1_DQS, PINCTRL_GRP_CAN0_0, PINCTRL_GRP_CAN0_1, PINCTRL_GRP_CAN0_2, PINCTRL_GRP_CAN0_3, PINCTRL_GRP_CAN0_4, PINCTRL_GRP_CAN0_5, PINCTRL_GRP_CAN0_6, PINCTRL_GRP_CAN0_7, PINCTRL_GRP_CAN0_8, PINCTRL_GRP_CAN0_9, PINCTRL_GRP_CAN0_10, PINCTRL_GRP_CAN0_11, PINCTRL_GRP_CAN0_12, PINCTRL_GRP_CAN0_13, PINCTRL_GRP_CAN0_14, PINCTRL_GRP_CAN0_15, PINCTRL_GRP_CAN0_16, PINCTRL_GRP_CAN0_17, PINCTRL_GRP_CAN0_18, PINCTRL_GRP_CAN1_0, PINCTRL_GRP_CAN1_1, PINCTRL_GRP_CAN1_2, PINCTRL_GRP_CAN1_3, PINCTRL_GRP_CAN1_4, PINCTRL_GRP_CAN1_5, PINCTRL_GRP_CAN1_6, PINCTRL_GRP_CAN1_7, PINCTRL_GRP_CAN1_8, PINCTRL_GRP_CAN1_9, PINCTRL_GRP_CAN1_10, PINCTRL_GRP_CAN1_11, PINCTRL_GRP_CAN1_12, PINCTRL_GRP_CAN1_13, PINCTRL_GRP_CAN1_14, PINCTRL_GRP_CAN1_15, PINCTRL_GRP_CAN1_16, PINCTRL_GRP_CAN1_17, PINCTRL_GRP_CAN1_18, PINCTRL_GRP_CAN1_19, PINCTRL_GRP_UART0_0, PINCTRL_GRP_UART0_1, PINCTRL_GRP_UART0_2, PINCTRL_GRP_UART0_3, PINCTRL_GRP_UART0_4, PINCTRL_GRP_UART0_5, PINCTRL_GRP_UART0_6, PINCTRL_GRP_UART0_7, PINCTRL_GRP_UART0_8, PINCTRL_GRP_UART0_9, PINCTRL_GRP_UART0_10, PINCTRL_GRP_UART0_11, PINCTRL_GRP_UART0_12, PINCTRL_GRP_UART0_13, PINCTRL_GRP_UART0_14, PINCTRL_GRP_UART0_15, PINCTRL_GRP_UART0_16, PINCTRL_GRP_UART0_17, PINCTRL_GRP_UART0_18, PINCTRL_GRP_UART1_0, PINCTRL_GRP_UART1_1, PINCTRL_GRP_UART1_2, PINCTRL_GRP_UART1_3, PINCTRL_GRP_UART1_4, PINCTRL_GRP_UART1_5, PINCTRL_GRP_UART1_6, PINCTRL_GRP_UART1_7, PINCTRL_GRP_UART1_8, PINCTRL_GRP_UART1_9, PINCTRL_GRP_UART1_10, PINCTRL_GRP_UART1_11, PINCTRL_GRP_UART1_12, PINCTRL_GRP_UART1_13, PINCTRL_GRP_UART1_14, PINCTRL_GRP_UART1_15, PINCTRL_GRP_UART1_16, PINCTRL_GRP_UART1_17, PINCTRL_GRP_UART1_18, PINCTRL_GRP_I2C0_0, PINCTRL_GRP_I2C0_1, PINCTRL_GRP_I2C0_2, PINCTRL_GRP_I2C0_3, PINCTRL_GRP_I2C0_4, PINCTRL_GRP_I2C0_5, PINCTRL_GRP_I2C0_6, PINCTRL_GRP_I2C0_7, PINCTRL_GRP_I2C0_8, PINCTRL_GRP_I2C0_9, PINCTRL_GRP_I2C0_10, PINCTRL_GRP_I2C0_11, PINCTRL_GRP_I2C0_12, PINCTRL_GRP_I2C0_13, PINCTRL_GRP_I2C0_14, PINCTRL_GRP_I2C0_15, PINCTRL_GRP_I2C0_16, PINCTRL_GRP_I2C0_17, PINCTRL_GRP_I2C0_18, PINCTRL_GRP_I2C1_0, PINCTRL_GRP_I2C1_1, PINCTRL_GRP_I2C1_2, PINCTRL_GRP_I2C1_3, PINCTRL_GRP_I2C1_4, PINCTRL_GRP_I2C1_5, PINCTRL_GRP_I2C1_6, PINCTRL_GRP_I2C1_7, PINCTRL_GRP_I2C1_8, PINCTRL_GRP_I2C1_9, PINCTRL_GRP_I2C1_10, PINCTRL_GRP_I2C1_11, PINCTRL_GRP_I2C1_12, PINCTRL_GRP_I2C1_13, PINCTRL_GRP_I2C1_14, PINCTRL_GRP_I2C1_15, PINCTRL_GRP_I2C1_16, PINCTRL_GRP_I2C1_17, PINCTRL_GRP_I2C1_18, PINCTRL_GRP_I2C1_19, PINCTRL_GRP_TTC0_0_CLK, PINCTRL_GRP_TTC0_0_WAV, PINCTRL_GRP_TTC0_1_CLK, PINCTRL_GRP_TTC0_1_WAV, PINCTRL_GRP_TTC0_2_CLK, PINCTRL_GRP_TTC0_2_WAV, PINCTRL_GRP_TTC0_3_CLK, PINCTRL_GRP_TTC0_3_WAV, PINCTRL_GRP_TTC0_4_CLK, PINCTRL_GRP_TTC0_4_WAV, PINCTRL_GRP_TTC0_5_CLK, PINCTRL_GRP_TTC0_5_WAV, PINCTRL_GRP_TTC0_6_CLK, PINCTRL_GRP_TTC0_6_WAV, PINCTRL_GRP_TTC0_7_CLK, PINCTRL_GRP_TTC0_7_WAV, PINCTRL_GRP_TTC0_8_CLK, PINCTRL_GRP_TTC0_8_WAV, PINCTRL_GRP_TTC1_0_CLK, PINCTRL_GRP_TTC1_0_WAV, PINCTRL_GRP_TTC1_1_CLK, PINCTRL_GRP_TTC1_1_WAV, PINCTRL_GRP_TTC1_2_CLK, PINCTRL_GRP_TTC1_2_WAV, PINCTRL_GRP_TTC1_3_CLK, PINCTRL_GRP_TTC1_3_WAV, PINCTRL_GRP_TTC1_4_CLK, PINCTRL_GRP_TTC1_4_WAV, PINCTRL_GRP_TTC1_5_CLK, PINCTRL_GRP_TTC1_5_WAV, PINCTRL_GRP_TTC1_6_CLK, PINCTRL_GRP_TTC1_6_WAV, PINCTRL_GRP_TTC1_7_CLK, PINCTRL_GRP_TTC1_7_WAV, PINCTRL_GRP_TTC1_8_CLK, PINCTRL_GRP_TTC1_8_WAV, PINCTRL_GRP_TTC2_0_CLK, PINCTRL_GRP_TTC2_0_WAV, PINCTRL_GRP_TTC2_1_CLK, PINCTRL_GRP_TTC2_1_WAV, PINCTRL_GRP_TTC2_2_CLK, PINCTRL_GRP_TTC2_2_WAV, PINCTRL_GRP_TTC2_3_CLK, PINCTRL_GRP_TTC2_3_WAV, PINCTRL_GRP_TTC2_4_CLK, PINCTRL_GRP_TTC2_4_WAV, PINCTRL_GRP_TTC2_5_CLK, PINCTRL_GRP_TTC2_5_WAV, PINCTRL_GRP_TTC2_6_CLK, PINCTRL_GRP_TTC2_6_WAV, PINCTRL_GRP_TTC2_7_CLK, PINCTRL_GRP_TTC2_7_WAV, PINCTRL_GRP_TTC2_8_CLK, PINCTRL_GRP_TTC2_8_WAV, PINCTRL_GRP_TTC3_0_CLK, PINCTRL_GRP_TTC3_0_WAV, PINCTRL_GRP_TTC3_1_CLK, PINCTRL_GRP_TTC3_1_WAV, PINCTRL_GRP_TTC3_2_CLK, PINCTRL_GRP_TTC3_2_WAV, PINCTRL_GRP_TTC3_3_CLK, PINCTRL_GRP_TTC3_3_WAV, PINCTRL_GRP_TTC3_4_CLK, PINCTRL_GRP_TTC3_4_WAV, PINCTRL_GRP_TTC3_5_CLK, PINCTRL_GRP_TTC3_5_WAV, PINCTRL_GRP_TTC3_6_CLK, PINCTRL_GRP_TTC3_6_WAV, PINCTRL_GRP_TTC3_7_CLK, PINCTRL_GRP_TTC3_7_WAV, PINCTRL_GRP_TTC3_8_CLK, PINCTRL_GRP_TTC3_8_WAV, PINCTRL_GRP_SWDT0_0_CLK, PINCTRL_GRP_SWDT0_0_RST, PINCTRL_GRP_SWDT0_1_CLK, PINCTRL_GRP_SWDT0_1_RST, PINCTRL_GRP_SWDT0_2_CLK, PINCTRL_GRP_SWDT0_2_RST, PINCTRL_GRP_SWDT0_3_CLK, PINCTRL_GRP_SWDT0_3_RST, PINCTRL_GRP_SWDT0_4_CLK, PINCTRL_GRP_SWDT0_4_RST, PINCTRL_GRP_SWDT0_5_CLK, PINCTRL_GRP_SWDT0_5_RST, PINCTRL_GRP_SWDT0_6_CLK, PINCTRL_GRP_SWDT0_6_RST, PINCTRL_GRP_SWDT0_7_CLK, PINCTRL_GRP_SWDT0_7_RST, PINCTRL_GRP_SWDT0_8_CLK, PINCTRL_GRP_SWDT0_8_RST, PINCTRL_GRP_SWDT0_9_CLK, PINCTRL_GRP_SWDT0_9_RST, PINCTRL_GRP_SWDT0_10_CLK, PINCTRL_GRP_SWDT0_10_RST, PINCTRL_GRP_SWDT0_11_CLK, PINCTRL_GRP_SWDT0_11_RST, PINCTRL_GRP_SWDT0_12_CLK, PINCTRL_GRP_SWDT0_12_RST, PINCTRL_GRP_SWDT1_0_CLK, PINCTRL_GRP_SWDT1_0_RST, PINCTRL_GRP_SWDT1_1_CLK, PINCTRL_GRP_SWDT1_1_RST, PINCTRL_GRP_SWDT1_2_CLK, PINCTRL_GRP_SWDT1_2_RST, PINCTRL_GRP_SWDT1_3_CLK, PINCTRL_GRP_SWDT1_3_RST, PINCTRL_GRP_SWDT1_4_CLK, PINCTRL_GRP_SWDT1_4_RST, PINCTRL_GRP_SWDT1_5_CLK, PINCTRL_GRP_SWDT1_5_RST, PINCTRL_GRP_SWDT1_6_CLK, PINCTRL_GRP_SWDT1_6_RST, PINCTRL_GRP_SWDT1_7_CLK, PINCTRL_GRP_SWDT1_7_RST, PINCTRL_GRP_SWDT1_8_CLK, PINCTRL_GRP_SWDT1_8_RST, PINCTRL_GRP_SWDT1_9_CLK, PINCTRL_GRP_SWDT1_9_RST, PINCTRL_GRP_SWDT1_10_CLK, PINCTRL_GRP_SWDT1_10_RST, PINCTRL_GRP_SWDT1_11_CLK, PINCTRL_GRP_SWDT1_11_RST, PINCTRL_GRP_SWDT1_12_CLK, PINCTRL_GRP_SWDT1_12_RST, PINCTRL_GRP_GPIO0_0, PINCTRL_GRP_GPIO0_1, PINCTRL_GRP_GPIO0_2, PINCTRL_GRP_GPIO0_3, PINCTRL_GRP_GPIO0_4, PINCTRL_GRP_GPIO0_5, PINCTRL_GRP_GPIO0_6, PINCTRL_GRP_GPIO0_7, PINCTRL_GRP_GPIO0_8, PINCTRL_GRP_GPIO0_9, PINCTRL_GRP_GPIO0_10, PINCTRL_GRP_GPIO0_11, PINCTRL_GRP_GPIO0_12, PINCTRL_GRP_GPIO0_13, PINCTRL_GRP_GPIO0_14, PINCTRL_GRP_GPIO0_15, PINCTRL_GRP_GPIO0_16, PINCTRL_GRP_GPIO0_17, PINCTRL_GRP_GPIO0_18, PINCTRL_GRP_GPIO0_19, PINCTRL_GRP_GPIO0_20, PINCTRL_GRP_GPIO0_21, PINCTRL_GRP_GPIO0_22, PINCTRL_GRP_GPIO0_23, PINCTRL_GRP_GPIO0_24, PINCTRL_GRP_GPIO0_25, PINCTRL_GRP_GPIO0_26, PINCTRL_GRP_GPIO0_27, PINCTRL_GRP_GPIO0_28, PINCTRL_GRP_GPIO0_29, PINCTRL_GRP_GPIO0_30, PINCTRL_GRP_GPIO0_31, PINCTRL_GRP_GPIO0_32, PINCTRL_GRP_GPIO0_33, PINCTRL_GRP_GPIO0_34, PINCTRL_GRP_GPIO0_35, PINCTRL_GRP_GPIO0_36, PINCTRL_GRP_GPIO0_37, PINCTRL_GRP_GPIO0_38, PINCTRL_GRP_GPIO0_39, PINCTRL_GRP_GPIO0_40, PINCTRL_GRP_GPIO0_41, PINCTRL_GRP_GPIO0_42, PINCTRL_GRP_GPIO0_43, PINCTRL_GRP_GPIO0_44, PINCTRL_GRP_GPIO0_45, PINCTRL_GRP_GPIO0_46, PINCTRL_GRP_GPIO0_47, PINCTRL_GRP_GPIO0_48, PINCTRL_GRP_GPIO0_49, PINCTRL_GRP_GPIO0_50, PINCTRL_GRP_GPIO0_51, PINCTRL_GRP_GPIO0_52, PINCTRL_GRP_GPIO0_53, PINCTRL_GRP_GPIO0_54, PINCTRL_GRP_GPIO0_55, PINCTRL_GRP_GPIO0_56, PINCTRL_GRP_GPIO0_57, PINCTRL_GRP_GPIO0_58, PINCTRL_GRP_GPIO0_59, PINCTRL_GRP_GPIO0_60, PINCTRL_GRP_GPIO0_61, PINCTRL_GRP_GPIO0_62, PINCTRL_GRP_GPIO0_63, PINCTRL_GRP_GPIO0_64, PINCTRL_GRP_GPIO0_65, PINCTRL_GRP_GPIO0_66, PINCTRL_GRP_GPIO0_67, PINCTRL_GRP_GPIO0_68, PINCTRL_GRP_GPIO0_69, PINCTRL_GRP_GPIO0_70, PINCTRL_GRP_GPIO0_71, PINCTRL_GRP_GPIO0_72, PINCTRL_GRP_GPIO0_73, PINCTRL_GRP_GPIO0_74, PINCTRL_GRP_GPIO0_75, PINCTRL_GRP_GPIO0_76, PINCTRL_GRP_GPIO0_77, PINCTRL_GRP_USB0_0, PINCTRL_GRP_USB1_0, PINCTRL_GRP_PMU0_0, PINCTRL_GRP_PMU0_1, PINCTRL_GRP_PMU0_2, PINCTRL_GRP_PMU0_3, PINCTRL_GRP_PMU0_4, PINCTRL_GRP_PMU0_5, PINCTRL_GRP_PMU0_6, PINCTRL_GRP_PMU0_7, PINCTRL_GRP_PMU0_8, PINCTRL_GRP_PMU0_9, PINCTRL_GRP_PMU0_10, PINCTRL_GRP_PMU0_11, PINCTRL_GRP_PCIE0_0, PINCTRL_GRP_PCIE0_1, PINCTRL_GRP_PCIE0_2, PINCTRL_GRP_PCIE0_3, PINCTRL_GRP_PCIE0_4, PINCTRL_GRP_PCIE0_5, PINCTRL_GRP_PCIE0_6, PINCTRL_GRP_PCIE0_7, PINCTRL_GRP_CSU0_0, PINCTRL_GRP_CSU0_1, PINCTRL_GRP_CSU0_2, PINCTRL_GRP_CSU0_3, PINCTRL_GRP_CSU0_4, PINCTRL_GRP_CSU0_5, PINCTRL_GRP_CSU0_6, PINCTRL_GRP_CSU0_7, PINCTRL_GRP_CSU0_8, PINCTRL_GRP_CSU0_9, PINCTRL_GRP_CSU0_10, PINCTRL_GRP_CSU0_11, PINCTRL_GRP_DPAUX0_0, PINCTRL_GRP_DPAUX0_1, PINCTRL_GRP_DPAUX0_2, PINCTRL_GRP_DPAUX0_3, PINCTRL_GRP_PJTAG0_0, PINCTRL_GRP_PJTAG0_1, PINCTRL_GRP_PJTAG0_2, PINCTRL_GRP_PJTAG0_3, PINCTRL_GRP_PJTAG0_4, PINCTRL_GRP_PJTAG0_5, PINCTRL_GRP_TRACE0_0, PINCTRL_GRP_TRACE0_0_CLK, PINCTRL_GRP_TRACE0_1, PINCTRL_GRP_TRACE0_1_CLK, PINCTRL_GRP_TRACE0_2, PINCTRL_GRP_TRACE0_2_CLK, PINCTRL_GRP_TESTSCAN0_0, }; // pinctrl config parameters enum { PINCTRL_CONFIG_SLEW_RATE, PINCTRL_CONFIG_BIAS_STATUS, PINCTRL_CONFIG_PULL_CTRL, PINCTRL_CONFIG_SCHMITT_CMOS, PINCTRL_CONFIG_DRIVE_STRENGTH, PINCTRL_CONFIG_VOLTAGE_STATUS, PINCTRL_CONFIG_MAX, }; // pinctrl slew rate #define PINCTRL_SLEW_RATE_FAST 0U #define PINCTRL_SLEW_RATE_SLOW 1U // pinctrl bias status #define PINCTRL_BIAS_DISABLE 0U #define PINCTRL_BIAS_ENABLE 1U // pinctrl pull control #define PINCTRL_BIAS_PULL_DOWN 0U #define PINCTRL_BIAS_PULL_UP 1U // pinctrl schmitt cmos type #define PINCTRL_INPUT_TYPE_CMOS 0U #define PINCTRL_INPUT_TYPE_SCHMITT 1U //pinctrl drive strength values #define PINCTRL_DRIVE_STRENGTH_2MA 0U #define PINCTRL_DRIVE_STRENGTH_4MA 1U #define PINCTRL_DRIVE_STRENGTH_8MA 2U #define PINCTRL_DRIVE_STRENGTH_12MA 3U enum pm_ret_status pm_api_pinctrl_set_function(unsigned int pin, unsigned int fid); enum pm_ret_status pm_api_pinctrl_get_function(unsigned int pin, unsigned int *id); enum pm_ret_status pm_api_pinctrl_set_config(unsigned int pin, unsigned int param, unsigned int value); enum pm_ret_status pm_api_pinctrl_get_config(unsigned int pin, unsigned int param, unsigned int *value); enum pm_ret_status pm_api_pinctrl_get_function_name(unsigned int fid, char *name); enum pm_ret_status pm_api_pinctrl_get_function_groups(unsigned int fid, unsigned int index, uint16_t *groups); enum pm_ret_status pm_api_pinctrl_get_pin_groups(unsigned int pin, unsigned int index, uint16_t *groups); enum pm_ret_status pm_api_pinctrl_get_num_pins(unsigned int *npins); enum pm_ret_status pm_api_pinctrl_get_num_functions(unsigned int *nfuncs); enum pm_ret_status pm_api_pinctrl_get_num_func_groups(unsigned int fid, unsigned int *ngroups); #endif /* PM_API_PINCTRL_H */ trusted-firmware-a-2.2/plat/xilinx/zynqmp/pm_service/pm_api_sys.c000066400000000000000000001260711355360272700253740ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * ZynqMP system level PM-API functions and communication with PMU via * IPI interrupts */ #include #include #include "pm_api_clock.h" #include "pm_api_ioctl.h" #include "pm_api_pinctrl.h" #include "pm_api_sys.h" #include "pm_client.h" #include "pm_common.h" #include "pm_ipi.h" /* default shutdown/reboot scope is system(2) */ static unsigned int pm_shutdown_scope = PMF_SHUTDOWN_SUBTYPE_SYSTEM; /** * pm_get_shutdown_scope() - Get the currently set shutdown scope * * @return Shutdown scope value */ unsigned int pm_get_shutdown_scope(void) { return pm_shutdown_scope; } /** * Assigning of argument values into array elements. */ #define PM_PACK_PAYLOAD1(pl, arg0) { \ pl[0] = (uint32_t)(arg0); \ } #define PM_PACK_PAYLOAD2(pl, arg0, arg1) { \ pl[1] = (uint32_t)(arg1); \ PM_PACK_PAYLOAD1(pl, arg0); \ } #define PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2) { \ pl[2] = (uint32_t)(arg2); \ PM_PACK_PAYLOAD2(pl, arg0, arg1); \ } #define PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3) { \ pl[3] = (uint32_t)(arg3); \ PM_PACK_PAYLOAD3(pl, arg0, arg1, arg2); \ } #define PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4) { \ pl[4] = (uint32_t)(arg4); \ PM_PACK_PAYLOAD4(pl, arg0, arg1, arg2, arg3); \ } #define PM_PACK_PAYLOAD6(pl, arg0, arg1, arg2, arg3, arg4, arg5) { \ pl[5] = (uint32_t)(arg5); \ PM_PACK_PAYLOAD5(pl, arg0, arg1, arg2, arg3, arg4); \ } /** * pm_self_suspend() - PM call for processor to suspend itself * @nid Node id of the processor or subsystem * @latency Requested maximum wakeup latency (not supported) * @state Requested state * @address Resume address * * This is a blocking call, it will return only once PMU has responded. * On a wakeup, resume address will be automatically set by PMU. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_self_suspend(enum pm_node_id nid, unsigned int latency, unsigned int state, uintptr_t address) { uint32_t payload[PAYLOAD_ARG_CNT]; unsigned int cpuid = plat_my_core_pos(); const struct pm_proc *proc = pm_get_proc(cpuid); /* * Do client specific suspend operations * (e.g. set powerdown request bit) */ pm_client_suspend(proc, state); /* Send request to the PMU */ PM_PACK_PAYLOAD6(payload, PM_SELF_SUSPEND, proc->node_id, latency, state, address, (address >> 32)); return pm_ipi_send_sync(proc, payload, NULL, 0); } /** * pm_req_suspend() - PM call to request for another PU or subsystem to * be suspended gracefully. * @target Node id of the targeted PU or subsystem * @ack Flag to specify whether acknowledge is requested * @latency Requested wakeup latency (not supported) * @state Requested state (not supported) * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_req_suspend(enum pm_node_id target, enum pm_request_ack ack, unsigned int latency, unsigned int state) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD5(payload, PM_REQ_SUSPEND, target, ack, latency, state); if (ack == REQ_ACK_BLOCKING) return pm_ipi_send_sync(primary_proc, payload, NULL, 0); else return pm_ipi_send(primary_proc, payload); } /** * pm_req_wakeup() - PM call for processor to wake up selected processor * or subsystem * @target Node id of the processor or subsystem to wake up * @ack Flag to specify whether acknowledge requested * @set_address Resume address presence indicator * 1 resume address specified, 0 otherwise * @address Resume address * * This API function is either used to power up another APU core for SMP * (by PSCI) or to power up an entirely different PU or subsystem, such * as RPU0, RPU, or PL_CORE_xx. Resume address for the target PU will be * automatically set by PMU. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_req_wakeup(enum pm_node_id target, unsigned int set_address, uintptr_t address, enum pm_request_ack ack) { uint32_t payload[PAYLOAD_ARG_CNT]; uint64_t encoded_address; /* encode set Address into 1st bit of address */ encoded_address = address; encoded_address |= !!set_address; /* Send request to the PMU to perform the wake of the PU */ PM_PACK_PAYLOAD5(payload, PM_REQ_WAKEUP, target, encoded_address, encoded_address >> 32, ack); if (ack == REQ_ACK_BLOCKING) return pm_ipi_send_sync(primary_proc, payload, NULL, 0); else return pm_ipi_send(primary_proc, payload); } /** * pm_force_powerdown() - PM call to request for another PU or subsystem to * be powered down forcefully * @target Node id of the targeted PU or subsystem * @ack Flag to specify whether acknowledge is requested * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_force_powerdown(enum pm_node_id target, enum pm_request_ack ack) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD3(payload, PM_FORCE_POWERDOWN, target, ack); if (ack == REQ_ACK_BLOCKING) return pm_ipi_send_sync(primary_proc, payload, NULL, 0); else return pm_ipi_send(primary_proc, payload); } /** * pm_abort_suspend() - PM call to announce that a prior suspend request * is to be aborted. * @reason Reason for the abort * * Calling PU expects the PMU to abort the initiated suspend procedure. * This is a non-blocking call without any acknowledge. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason) { uint32_t payload[PAYLOAD_ARG_CNT]; /* * Do client specific abort suspend operations * (e.g. enable interrupts and clear powerdown request bit) */ pm_client_abort_suspend(); /* Send request to the PMU */ /* TODO: allow passing the node ID of the affected CPU */ PM_PACK_PAYLOAD3(payload, PM_ABORT_SUSPEND, reason, primary_proc->node_id); return pm_ipi_send(primary_proc, payload); } /** * pm_set_wakeup_source() - PM call to specify the wakeup source while suspended * @target Node id of the targeted PU or subsystem * @wkup_node Node id of the wakeup peripheral * @enable Enable or disable the specified peripheral as wake source * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target, enum pm_node_id wkup_node, unsigned int enable) { uint32_t payload[PAYLOAD_ARG_CNT]; PM_PACK_PAYLOAD4(payload, PM_SET_WAKEUP_SOURCE, target, wkup_node, enable); return pm_ipi_send(primary_proc, payload); } /** * pm_system_shutdown() - PM call to request a system shutdown or restart * @type Shutdown or restart? 0=shutdown, 1=restart, 2=setscope * @subtype Scope: 0=APU-subsystem, 1=PS, 2=system * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_system_shutdown(unsigned int type, unsigned int subtype) { uint32_t payload[PAYLOAD_ARG_CNT]; if (type == PMF_SHUTDOWN_TYPE_SETSCOPE_ONLY) { /* Setting scope for subsequent PSCI reboot or shutdown */ pm_shutdown_scope = subtype; return PM_RET_SUCCESS; } PM_PACK_PAYLOAD3(payload, PM_SYSTEM_SHUTDOWN, type, subtype); return pm_ipi_send_non_blocking(primary_proc, payload); } /* APIs for managing PM slaves: */ /** * pm_req_node() - PM call to request a node with specific capabilities * @nid Node id of the slave * @capabilities Requested capabilities of the slave * @qos Quality of service (not supported) * @ack Flag to specify whether acknowledge is requested * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_req_node(enum pm_node_id nid, unsigned int capabilities, unsigned int qos, enum pm_request_ack ack) { uint32_t payload[PAYLOAD_ARG_CNT]; PM_PACK_PAYLOAD5(payload, PM_REQ_NODE, nid, capabilities, qos, ack); if (ack == REQ_ACK_BLOCKING) return pm_ipi_send_sync(primary_proc, payload, NULL, 0); else return pm_ipi_send(primary_proc, payload); } /** * pm_set_requirement() - PM call to set requirement for PM slaves * @nid Node id of the slave * @capabilities Requested capabilities of the slave * @qos Quality of service (not supported) * @ack Flag to specify whether acknowledge is requested * * This API function is to be used for slaves a PU already has requested * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_set_requirement(enum pm_node_id nid, unsigned int capabilities, unsigned int qos, enum pm_request_ack ack) { uint32_t payload[PAYLOAD_ARG_CNT]; PM_PACK_PAYLOAD5(payload, PM_SET_REQUIREMENT, nid, capabilities, qos, ack); if (ack == REQ_ACK_BLOCKING) return pm_ipi_send_sync(primary_proc, payload, NULL, 0); else return pm_ipi_send(primary_proc, payload); } /** * pm_release_node() - PM call to release a node * @nid Node id of the slave * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_release_node(enum pm_node_id nid) { uint32_t payload[PAYLOAD_ARG_CNT]; PM_PACK_PAYLOAD2(payload, PM_RELEASE_NODE, nid); return pm_ipi_send(primary_proc, payload); } /** * pm_set_max_latency() - PM call to set wakeup latency requirements * @nid Node id of the slave * @latency Requested maximum wakeup latency * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_set_max_latency(enum pm_node_id nid, unsigned int latency) { uint32_t payload[PAYLOAD_ARG_CNT]; PM_PACK_PAYLOAD3(payload, PM_SET_MAX_LATENCY, nid, latency); return pm_ipi_send(primary_proc, payload); } /* Miscellaneous API functions */ /** * pm_get_api_version() - Get version number of PMU PM firmware * @version Returns 32-bit version number of PMU Power Management Firmware * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_get_api_version(unsigned int *version) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD1(payload, PM_GET_API_VERSION); return pm_ipi_send_sync(primary_proc, payload, version, 1); } /** * pm_set_configuration() - PM call to set system configuration * @phys_addr Physical 32-bit address of data structure in memory * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_set_configuration(unsigned int phys_addr) { uint32_t payload[PAYLOAD_ARG_CNT]; PM_PACK_PAYLOAD2(payload, PM_SET_CONFIGURATION, phys_addr); return pm_ipi_send_sync(primary_proc, payload, NULL, 0); } /** * pm_init_finalize() - Call to notify PMU firmware that master has power * management enabled and that it has finished its * initialization * * @return Status returned by the PMU firmware */ enum pm_ret_status pm_init_finalize(void) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD1(payload, PM_INIT_FINALIZE); return pm_ipi_send_sync(primary_proc, payload, NULL, 0); } /** * pm_get_node_status() - PM call to request a node's current status * @nid Node id * @ret_buff Buffer for the return values: * [0] - Current power state of the node * [1] - Current requirements for the node (slave nodes only) * [2] - Current usage status for the node (slave nodes only) * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_get_node_status(enum pm_node_id nid, uint32_t *ret_buff) { uint32_t payload[PAYLOAD_ARG_CNT]; PM_PACK_PAYLOAD2(payload, PM_GET_NODE_STATUS, nid); return pm_ipi_send_sync(primary_proc, payload, ret_buff, 3); } /** * pm_register_notifier() - Register the PU to be notified of PM events * @nid Node id of the slave * @event The event to be notified about * @wake Wake up on event * @enable Enable or disable the notifier * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_register_notifier(enum pm_node_id nid, unsigned int event, unsigned int wake, unsigned int enable) { uint32_t payload[PAYLOAD_ARG_CNT]; PM_PACK_PAYLOAD5(payload, PM_REGISTER_NOTIFIER, nid, event, wake, enable); return pm_ipi_send_sync(primary_proc, payload, NULL, 0); } /** * pm_get_op_characteristic() - PM call to request operating characteristics * of a node * @nid Node id of the slave * @type Type of the operating characteristic * (power, temperature and latency) * @result Returns the operating characteristic for the requested node, * specified by the type * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_get_op_characteristic(enum pm_node_id nid, enum pm_opchar_type type, uint32_t *result) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD3(payload, PM_GET_OP_CHARACTERISTIC, nid, type); return pm_ipi_send_sync(primary_proc, payload, result, 1); } /* Direct-Control API functions */ /** * pm_reset_assert() - Assert reset * @reset Reset ID * @assert Assert (1) or de-assert (0) * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_reset_assert(unsigned int reset, unsigned int assert) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD3(payload, PM_RESET_ASSERT, reset, assert); return pm_ipi_send(primary_proc, payload); } /** * pm_reset_get_status() - Get current status of a reset line * @reset Reset ID * @reset_status Returns current status of selected reset line * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_reset_get_status(unsigned int reset, unsigned int *reset_status) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD2(payload, PM_RESET_GET_STATUS, reset); return pm_ipi_send_sync(primary_proc, payload, reset_status, 1); } /** * pm_mmio_write() - Perform write to protected mmio * @address Address to write to * @mask Mask to apply * @value Value to write * * This function provides access to PM-related control registers * that may not be directly accessible by a particular PU. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_mmio_write(uintptr_t address, unsigned int mask, unsigned int value) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD4(payload, PM_MMIO_WRITE, address, mask, value); return pm_ipi_send_sync(primary_proc, payload, NULL, 0); } /** * pm_mmio_read() - Read value from protected mmio * @address Address to write to * @value Value to write * * This function provides access to PM-related control registers * that may not be directly accessible by a particular PU. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_mmio_read(uintptr_t address, unsigned int *value) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD2(payload, PM_MMIO_READ, address); return pm_ipi_send_sync(primary_proc, payload, value, 1); } /** * pm_fpga_load() - Load the bitstream into the PL. * * This function provides access to the xilfpga library to load * the Bit-stream into PL. * * address_low: lower 32-bit Linear memory space address * * address_high: higher 32-bit Linear memory space address * * size: Number of 32bit words * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_fpga_load(uint32_t address_low, uint32_t address_high, uint32_t size, uint32_t flags) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD5(payload, PM_FPGA_LOAD, address_high, address_low, size, flags); return pm_ipi_send_sync(primary_proc, payload, NULL, 0); } /** * pm_fpga_get_status() - Read value from fpga status register * @value Value to read * * This function provides access to the xilfpga library to get * the fpga status * @return Returns status, either success or error+reason */ enum pm_ret_status pm_fpga_get_status(unsigned int *value) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD1(payload, PM_FPGA_GET_STATUS); return pm_ipi_send_sync(primary_proc, payload, value, 1); } /** * pm_get_chipid() - Read silicon ID registers * @value Buffer for return values. Must be large enough * to hold 8 bytes. * * @return Returns silicon ID registers */ enum pm_ret_status pm_get_chipid(uint32_t *value) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD1(payload, PM_GET_CHIPID); return pm_ipi_send_sync(primary_proc, payload, value, 2); } /** * pm_secure_rsaaes() - Load the secure images. * * This function provides access to the xilsecure library to load * the authenticated, encrypted, and authenicated/encrypted images. * * address_low: lower 32-bit Linear memory space address * * address_high: higher 32-bit Linear memory space address * * size: Number of 32bit words * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_secure_rsaaes(uint32_t address_low, uint32_t address_high, uint32_t size, uint32_t flags) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD5(payload, PM_SECURE_RSA_AES, address_high, address_low, size, flags); return pm_ipi_send_sync(primary_proc, payload, NULL, 0); } /** * pm_aes_engine() - Aes data blob encryption/decryption * This function provides access to the xilsecure library to * encrypt/decrypt data blobs. * * address_low: lower 32-bit address of the AesParams structure * * address_high: higher 32-bit address of the AesParams structure * * value: Returned output value * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_aes_engine(uint32_t address_high, uint32_t address_low, uint32_t *value) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD3(payload, PM_SECURE_AES, address_high, address_low); return pm_ipi_send_sync(primary_proc, payload, value, 1); } /** * pm_pinctrl_request() - Request Pin from firmware * @pin Pin number to request * * This function requests pin from firmware. * * @return Returns status, either success or error+reason. */ enum pm_ret_status pm_pinctrl_request(unsigned int pin) { return PM_RET_SUCCESS; } /** * pm_pinctrl_release() - Release Pin from firmware * @pin Pin number to release * * This function releases pin from firmware. * * @return Returns status, either success or error+reason. */ enum pm_ret_status pm_pinctrl_release(unsigned int pin) { return PM_RET_SUCCESS; } /** * pm_pinctrl_get_function() - Read function id set for the given pin * @pin Pin number * @nid Node ID of function currently set for given pin * * This function provides the function currently set for the given pin. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_pinctrl_get_function(unsigned int pin, enum pm_node_id *nid) { return pm_api_pinctrl_get_function(pin, nid); } /** * pm_pinctrl_set_function() - Set function id set for the given pin * @pin Pin number * @nid Node ID of function to set for given pin * * This function provides the function currently set for the given pin. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_pinctrl_set_function(unsigned int pin, enum pm_node_id nid) { return pm_api_pinctrl_set_function(pin, (unsigned int)nid); } /** * pm_pinctrl_get_config() - Read value of requested config param for given pin * @pin Pin number * @param Parameter values to be read * @value Buffer for configuration Parameter value * * This function provides the configuration parameter value for the given pin. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_pinctrl_get_config(unsigned int pin, unsigned int param, unsigned int *value) { return pm_api_pinctrl_get_config(pin, param, value); } /** * pm_pinctrl_set_config() - Read value of requested config param for given pin * @pin Pin number * @param Parameter to set * @value Parameter value to set * * This function provides the configuration parameter value for the given pin. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_pinctrl_set_config(unsigned int pin, unsigned int param, unsigned int value) { return pm_api_pinctrl_set_config(pin, param, value); } /** * pm_ioctl() - PM IOCTL API for device control and configs * @node_id Node ID of the device * @ioctl_id ID of the requested IOCTL * @arg1 Argument 1 to requested IOCTL call * @arg2 Argument 2 to requested IOCTL call * @out Returned output value * * This function calls IOCTL to firmware for device control and configuration. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_ioctl(enum pm_node_id nid, unsigned int ioctl_id, unsigned int arg1, unsigned int arg2, unsigned int *value) { return pm_api_ioctl(nid, ioctl_id, arg1, arg2, value); } /** * pm_clock_get_num_clocks - PM call to request number of clocks * @nclockss: Number of clocks * * This function is used by master to get number of clocks. * * Return: Returns status, either success or error+reason. */ static enum pm_ret_status pm_clock_get_num_clocks(uint32_t *nclocks) { return pm_api_clock_get_num_clocks(nclocks); } /** * pm_clock_get_name() - PM call to request a clock's name * @clock_id Clock ID * @name Name of clock (max 16 bytes) * * This function is used by master to get nmae of clock specified * by given clock ID. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_clock_get_name(unsigned int clock_id, char *name) { return pm_api_clock_get_name(clock_id, name); } /** * pm_clock_get_topology() - PM call to request a clock's topology * @clock_id Clock ID * @index Topology index for next toplogy node * @topology Buffer to store nodes in topology and flags * * This function is used by master to get topology information for the * clock specified by given clock ID. Each response would return 3 * topology nodes. To get next nodes, caller needs to call this API with * index of next node. Index starts from 0. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_clock_get_topology(unsigned int clock_id, unsigned int index, uint32_t *topology) { return pm_api_clock_get_topology(clock_id, index, topology); } /** * pm_clock_get_fixedfactor_params() - PM call to request a clock's fixed factor * parameters for fixed clock * @clock_id Clock ID * @mul Multiplication value * @div Divisor value * * This function is used by master to get fixed factor parameers for the * fixed clock. This API is application only for the fixed clock. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_clock_get_fixedfactor_params(unsigned int clock_id, uint32_t *mul, uint32_t *div) { return pm_api_clock_get_fixedfactor_params(clock_id, mul, div); } /** * pm_clock_get_parents() - PM call to request a clock's first 3 parents * @clock_id Clock ID * @index Index of next parent * @parents Parents of the given clock * * This function is used by master to get clock's parents information. * This API will return 3 parents with a single response. To get other * parents, master should call same API in loop with new parent index * till error is returned. * * E.g First call should have index 0 which will return parents 0, 1 and * 2. Next call, index should be 3 which will return parent 3,4 and 5 and * so on. * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_clock_get_parents(unsigned int clock_id, unsigned int index, uint32_t *parents) { return pm_api_clock_get_parents(clock_id, index, parents); } /** * pm_clock_get_attributes() - PM call to request a clock's attributes * @clock_id Clock ID * @attr Clock attributes * * This function is used by master to get clock's attributes * (e.g. valid, clock type, etc). * * @return Returns status, either success or error+reason */ static enum pm_ret_status pm_clock_get_attributes(unsigned int clock_id, uint32_t *attr) { return pm_api_clock_get_attributes(clock_id, attr); } /** * pm_clock_gate() - Configure clock gate * @clock_id Id of the clock to be configured * @enable Flag 0=disable (gate the clock), !0=enable (activate the clock) * * @return Error if an argument is not valid or status as returned by the * PM controller (PMU) */ static enum pm_ret_status pm_clock_gate(unsigned int clock_id, unsigned char enable) { uint32_t payload[PAYLOAD_ARG_CNT]; enum pm_ret_status status; enum pm_api_id api_id; /* Check if clock ID is valid and return an error if it is not */ status = pm_clock_id_is_valid(clock_id); if (status != PM_RET_SUCCESS) return status; if (enable) api_id = PM_CLOCK_ENABLE; else api_id = PM_CLOCK_DISABLE; /* Send request to the PMU */ PM_PACK_PAYLOAD2(payload, api_id, clock_id); return pm_ipi_send_sync(primary_proc, payload, NULL, 0); } /** * pm_clock_enable() - Enable the clock for given id * @clock_id: Id of the clock to be enabled * * This function is used by master to enable the clock * including peripherals and PLL clocks. * * @return: Error if an argument is not valid or status as returned by the * pm_clock_gate */ enum pm_ret_status pm_clock_enable(unsigned int clock_id) { struct pm_pll *pll; /* First try to handle it as a PLL */ pll = pm_clock_get_pll(clock_id); if (pll) return pm_clock_pll_enable(pll); /* It's an on-chip clock, PMU should configure clock's gate */ return pm_clock_gate(clock_id, 1); } /** * pm_clock_disable - Disable the clock for given id * @clock_id: Id of the clock to be disable * * This function is used by master to disable the clock * including peripherals and PLL clocks. * * @return: Error if an argument is not valid or status as returned by the * pm_clock_gate */ enum pm_ret_status pm_clock_disable(unsigned int clock_id) { struct pm_pll *pll; /* First try to handle it as a PLL */ pll = pm_clock_get_pll(clock_id); if (pll) return pm_clock_pll_disable(pll); /* It's an on-chip clock, PMU should configure clock's gate */ return pm_clock_gate(clock_id, 0); } /** * pm_clock_getstate - Get the clock state for given id * @clock_id: Id of the clock to be queried * @state: 1/0 (Enabled/Disabled) * * This function is used by master to get the state of clock * including peripherals and PLL clocks. * * Return: Returns status, either success or error+reason. */ enum pm_ret_status pm_clock_getstate(unsigned int clock_id, unsigned int *state) { struct pm_pll *pll; uint32_t payload[PAYLOAD_ARG_CNT]; enum pm_ret_status status; /* First try to handle it as a PLL */ pll = pm_clock_get_pll(clock_id); if (pll) return pm_clock_pll_get_state(pll, state); /* Check if clock ID is a valid on-chip clock */ status = pm_clock_id_is_valid(clock_id); if (status != PM_RET_SUCCESS) return status; /* Send request to the PMU */ PM_PACK_PAYLOAD2(payload, PM_CLOCK_GETSTATE, clock_id); return pm_ipi_send_sync(primary_proc, payload, state, 1); } /** * pm_clock_setdivider - Set the clock divider for given id * @clock_id: Id of the clock * @divider: divider value * * This function is used by master to set divider for any clock * to achieve desired rate. * * Return: Returns status, either success or error+reason. */ enum pm_ret_status pm_clock_setdivider(unsigned int clock_id, unsigned int divider) { enum pm_ret_status status; enum pm_node_id nid; enum pm_clock_div_id div_id; uint32_t payload[PAYLOAD_ARG_CNT]; const uint32_t div0 = 0xFFFF0000; const uint32_t div1 = 0x0000FFFF; uint32_t val; /* Get PLL node ID using PLL clock ID */ status = pm_clock_get_pll_node_id(clock_id, &nid); if (status == PM_RET_SUCCESS) return pm_pll_set_parameter(nid, PM_PLL_PARAM_FBDIV, divider); /* Check if clock ID is a valid on-chip clock */ status = pm_clock_id_is_valid(clock_id); if (status != PM_RET_SUCCESS) return status; if (div0 == (divider & div0)) { div_id = PM_CLOCK_DIV0_ID; val = divider & ~div0; } else if (div1 == (divider & div1)) { div_id = PM_CLOCK_DIV1_ID; val = (divider & ~div1) >> 16; } else { return PM_RET_ERROR_ARGS; } /* Send request to the PMU */ PM_PACK_PAYLOAD4(payload, PM_CLOCK_SETDIVIDER, clock_id, div_id, val); return pm_ipi_send_sync(primary_proc, payload, NULL, 0); } /** * pm_clock_getdivider - Get the clock divider for given id * @clock_id: Id of the clock * @divider: divider value * * This function is used by master to get divider values * for any clock. * * Return: Returns status, either success or error+reason. */ enum pm_ret_status pm_clock_getdivider(unsigned int clock_id, unsigned int *divider) { enum pm_ret_status status; enum pm_node_id nid; uint32_t payload[PAYLOAD_ARG_CNT]; uint32_t val; /* Get PLL node ID using PLL clock ID */ status = pm_clock_get_pll_node_id(clock_id, &nid); if (status == PM_RET_SUCCESS) return pm_pll_get_parameter(nid, PM_PLL_PARAM_FBDIV, divider); /* Check if clock ID is a valid on-chip clock */ status = pm_clock_id_is_valid(clock_id); if (status != PM_RET_SUCCESS) return status; if (pm_clock_has_div(clock_id, PM_CLOCK_DIV0_ID)) { /* Send request to the PMU to get div0 */ PM_PACK_PAYLOAD3(payload, PM_CLOCK_GETDIVIDER, clock_id, PM_CLOCK_DIV0_ID); status = pm_ipi_send_sync(primary_proc, payload, &val, 1); if (status != PM_RET_SUCCESS) return status; *divider = val; } if (pm_clock_has_div(clock_id, PM_CLOCK_DIV1_ID)) { /* Send request to the PMU to get div1 */ PM_PACK_PAYLOAD3(payload, PM_CLOCK_GETDIVIDER, clock_id, PM_CLOCK_DIV1_ID); status = pm_ipi_send_sync(primary_proc, payload, &val, 1); if (status != PM_RET_SUCCESS) return status; *divider |= val << 16; } return status; } /** * pm_clock_setrate - Set the clock rate for given id * @clock_id: Id of the clock * @rate: rate value in hz * * This function is used by master to set rate for any clock. * * Return: Returns status, either success or error+reason. */ enum pm_ret_status pm_clock_setrate(unsigned int clock_id, uint64_t rate) { return PM_RET_ERROR_NOTSUPPORTED; } /** * pm_clock_getrate - Get the clock rate for given id * @clock_id: Id of the clock * @rate: rate value in hz * * This function is used by master to get rate * for any clock. * * Return: Returns status, either success or error+reason. */ enum pm_ret_status pm_clock_getrate(unsigned int clock_id, uint64_t *rate) { return PM_RET_ERROR_NOTSUPPORTED; } /** * pm_clock_setparent - Set the clock parent for given id * @clock_id: Id of the clock * @parent_index: Index of the parent clock into clock's parents array * * This function is used by master to set parent for any clock. * * Return: Returns status, either success or error+reason. */ enum pm_ret_status pm_clock_setparent(unsigned int clock_id, unsigned int parent_index) { struct pm_pll *pll; uint32_t payload[PAYLOAD_ARG_CNT]; enum pm_ret_status status; /* First try to handle it as a PLL */ pll = pm_clock_get_pll_by_related_clk(clock_id); if (pll) return pm_clock_pll_set_parent(pll, clock_id, parent_index); /* Check if clock ID is a valid on-chip clock */ status = pm_clock_id_is_valid(clock_id); if (status != PM_RET_SUCCESS) return status; /* Send request to the PMU */ PM_PACK_PAYLOAD3(payload, PM_CLOCK_SETPARENT, clock_id, parent_index); return pm_ipi_send_sync(primary_proc, payload, NULL, 0); } /** * pm_clock_getparent - Get the clock parent for given id * @clock_id: Id of the clock * @parent_index: parent index * * This function is used by master to get parent index * for any clock. * * Return: Returns status, either success or error+reason. */ enum pm_ret_status pm_clock_getparent(unsigned int clock_id, unsigned int *parent_index) { struct pm_pll *pll; uint32_t payload[PAYLOAD_ARG_CNT]; enum pm_ret_status status; /* First try to handle it as a PLL */ pll = pm_clock_get_pll_by_related_clk(clock_id); if (pll) return pm_clock_pll_get_parent(pll, clock_id, parent_index); /* Check if clock ID is a valid on-chip clock */ status = pm_clock_id_is_valid(clock_id); if (status != PM_RET_SUCCESS) return status; /* Send request to the PMU */ PM_PACK_PAYLOAD2(payload, PM_CLOCK_GETPARENT, clock_id); return pm_ipi_send_sync(primary_proc, payload, parent_index, 1); } /** * pm_pinctrl_get_num_pins - PM call to request number of pins * @npins: Number of pins * * This function is used by master to get number of pins * * Return: Returns status, either success or error+reason. */ static enum pm_ret_status pm_pinctrl_get_num_pins(uint32_t *npins) { return pm_api_pinctrl_get_num_pins(npins); } /** * pm_pinctrl_get_num_functions - PM call to request number of functions * @nfuncs: Number of functions * * This function is used by master to get number of functions * * Return: Returns status, either success or error+reason. */ static enum pm_ret_status pm_pinctrl_get_num_functions(uint32_t *nfuncs) { return pm_api_pinctrl_get_num_functions(nfuncs); } /** * pm_pinctrl_get_num_function_groups - PM call to request number of * function groups * @fid: Id of function * @ngroups: Number of function groups * * This function is used by master to get number of function groups specified * by given function Id * * Return: Returns status, either success or error+reason. */ static enum pm_ret_status pm_pinctrl_get_num_function_groups(unsigned int fid, uint32_t *ngroups) { return pm_api_pinctrl_get_num_func_groups(fid, ngroups); } /** * pm_pinctrl_get_function_name - PM call to request function name * @fid: Id of function * @name: Name of function * * This function is used by master to get name of function specified * by given function Id * * Return: Returns status, either success or error+reason. */ static enum pm_ret_status pm_pinctrl_get_function_name(unsigned int fid, char *name) { return pm_api_pinctrl_get_function_name(fid, name); } /** * pm_pinctrl_get_function_groups - PM call to request function groups * @fid: Id of function * @index: Index of next function groups * @groups: Function groups * * This function is used by master to get function groups specified * by given function Id. This API will return 6 function groups with * a single response. To get other function groups, master should call * same API in loop with new function groups index till error is returned. * * E.g First call should have index 0 which will return function groups * 0, 1, 2, 3, 4 and 5. Next call, index should be 6 which will return * function groups 6, 7, 8, 9, 10 and 11 and so on. * * Return: Returns status, either success or error+reason. */ static enum pm_ret_status pm_pinctrl_get_function_groups(unsigned int fid, unsigned int index, uint16_t *groups) { return pm_api_pinctrl_get_function_groups(fid, index, groups); } /** * pm_pinctrl_get_pin_groups - PM call to request pin groups * @pin_id: Id of pin * @index: Index of next pin groups * @groups: pin groups * * This function is used by master to get pin groups specified * by given pin Id. This API will return 6 pin groups with * a single response. To get other pin groups, master should call * same API in loop with new pin groups index till error is returned. * * E.g First call should have index 0 which will return pin groups * 0, 1, 2, 3, 4 and 5. Next call, index should be 6 which will return * pin groups 6, 7, 8, 9, 10 and 11 and so on. * * Return: Returns status, either success or error+reason. */ static enum pm_ret_status pm_pinctrl_get_pin_groups(unsigned int pin_id, unsigned int index, uint16_t *groups) { return pm_api_pinctrl_get_pin_groups(pin_id, index, groups); } /** * pm_query_data() - PM API for querying firmware data * @arg1 Argument 1 to requested IOCTL call * @arg2 Argument 2 to requested IOCTL call * @arg3 Argument 3 to requested IOCTL call * @arg4 Argument 4 to requested IOCTL call * @data Returned output data * * This function returns requested data. * * @return Returns status, either success or error+reason */ enum pm_ret_status pm_query_data(enum pm_query_id qid, unsigned int arg1, unsigned int arg2, unsigned int arg3, unsigned int *data) { enum pm_ret_status ret; switch (qid) { case PM_QID_CLOCK_GET_NAME: ret = pm_clock_get_name(arg1, (char *)data); break; case PM_QID_CLOCK_GET_TOPOLOGY: ret = pm_clock_get_topology(arg1, arg2, &data[1]); data[0] = (unsigned int)ret; break; case PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS: ret = pm_clock_get_fixedfactor_params(arg1, &data[1], &data[2]); data[0] = (unsigned int)ret; break; case PM_QID_CLOCK_GET_PARENTS: ret = pm_clock_get_parents(arg1, arg2, &data[1]); data[0] = (unsigned int)ret; break; case PM_QID_CLOCK_GET_ATTRIBUTES: ret = pm_clock_get_attributes(arg1, &data[1]); data[0] = (unsigned int)ret; break; case PM_QID_PINCTRL_GET_NUM_PINS: ret = pm_pinctrl_get_num_pins(&data[1]); data[0] = (unsigned int)ret; break; case PM_QID_PINCTRL_GET_NUM_FUNCTIONS: ret = pm_pinctrl_get_num_functions(&data[1]); data[0] = (unsigned int)ret; break; case PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS: ret = pm_pinctrl_get_num_function_groups(arg1, &data[1]); data[0] = (unsigned int)ret; break; case PM_QID_PINCTRL_GET_FUNCTION_NAME: ret = pm_pinctrl_get_function_name(arg1, (char *)data); break; case PM_QID_PINCTRL_GET_FUNCTION_GROUPS: ret = pm_pinctrl_get_function_groups(arg1, arg2, (uint16_t *)&data[1]); data[0] = (unsigned int)ret; break; case PM_QID_PINCTRL_GET_PIN_GROUPS: ret = pm_pinctrl_get_pin_groups(arg1, arg2, (uint16_t *)&data[1]); data[0] = (unsigned int)ret; break; case PM_QID_CLOCK_GET_NUM_CLOCKS: ret = pm_clock_get_num_clocks(&data[1]); data[0] = (unsigned int)ret; break; default: ret = PM_RET_ERROR_ARGS; WARN("Unimplemented query service call: 0x%x\n", qid); break; } return ret; } enum pm_ret_status pm_sha_hash(uint32_t address_high, uint32_t address_low, uint32_t size, uint32_t flags) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD5(payload, PM_SECURE_SHA, address_high, address_low, size, flags); return pm_ipi_send_sync(primary_proc, payload, NULL, 0); } enum pm_ret_status pm_rsa_core(uint32_t address_high, uint32_t address_low, uint32_t size, uint32_t flags) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD5(payload, PM_SECURE_RSA, address_high, address_low, size, flags); return pm_ipi_send_sync(primary_proc, payload, NULL, 0); } enum pm_ret_status pm_secure_image(uint32_t address_low, uint32_t address_high, uint32_t key_lo, uint32_t key_hi, uint32_t *value) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD5(payload, PM_SECURE_IMAGE, address_high, address_low, key_hi, key_lo); return pm_ipi_send_sync(primary_proc, payload, value, 2); } /** * pm_fpga_read - Perform the fpga configuration readback * * @reg_numframes: Configuration register offset (or) Number of frames to read * @address_low: lower 32-bit Linear memory space address * @address_high: higher 32-bit Linear memory space address * @readback_type: Type of fpga readback operation * 0 -- Configuration Register readback * 1 -- Configuration Data readback * @value: Value to read * * This function provides access to the xilfpga library to read * the PL configuration. * * Return: Returns status, either success or error+reason. */ enum pm_ret_status pm_fpga_read(uint32_t reg_numframes, uint32_t address_low, uint32_t address_high, uint32_t readback_type, uint32_t *value) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Send request to the PMU */ PM_PACK_PAYLOAD5(payload, PM_FPGA_READ, reg_numframes, address_low, address_high, readback_type); return pm_ipi_send_sync(primary_proc, payload, value, 1); } /* * pm_pll_set_parameter() - Set the PLL parameter value * @nid Node id of the target PLL * @param_id ID of the PLL parameter * @value Parameter value to be set * * Setting the parameter will have physical effect once the PLL mode is set to * integer or fractional. * * @return Error if an argument is not valid or status as returned by the * PM controller (PMU) */ enum pm_ret_status pm_pll_set_parameter(enum pm_node_id nid, enum pm_pll_param param_id, unsigned int value) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Check if given node ID is a PLL node */ if (nid < NODE_APLL || nid > NODE_IOPLL) return PM_RET_ERROR_ARGS; /* Check if parameter ID is valid and return an error if it's not */ if (param_id >= PM_PLL_PARAM_MAX) return PM_RET_ERROR_ARGS; /* Send request to the PMU */ PM_PACK_PAYLOAD4(payload, PM_PLL_SET_PARAMETER, nid, param_id, value); return pm_ipi_send_sync(primary_proc, payload, NULL, 0); } /** * pm_pll_get_parameter() - Get the PLL parameter value * @nid Node id of the target PLL * @param_id ID of the PLL parameter * @value Location to store the parameter value * * @return Error if an argument is not valid or status as returned by the * PM controller (PMU) */ enum pm_ret_status pm_pll_get_parameter(enum pm_node_id nid, enum pm_pll_param param_id, unsigned int *value) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Check if given node ID is a PLL node */ if (nid < NODE_APLL || nid > NODE_IOPLL) return PM_RET_ERROR_ARGS; /* Check if parameter ID is valid and return an error if it's not */ if (param_id >= PM_PLL_PARAM_MAX) return PM_RET_ERROR_ARGS; /* Send request to the PMU */ PM_PACK_PAYLOAD3(payload, PM_PLL_GET_PARAMETER, nid, param_id); return pm_ipi_send_sync(primary_proc, payload, value, 1); } /** * pm_pll_set_mode() - Set the PLL mode * @nid Node id of the target PLL * @mode PLL mode to be set * * If reset mode is set the PM controller will first bypass the PLL and then * assert the reset. If integer or fractional mode is set the PM controller will * ensure that the complete PLL programming sequence is satisfied. After this * function returns success the PLL is locked and its bypass is deasserted. * * @return Error if an argument is not valid or status as returned by the * PM controller (PMU) */ enum pm_ret_status pm_pll_set_mode(enum pm_node_id nid, enum pm_pll_mode mode) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Check if given node ID is a PLL node */ if (nid < NODE_APLL || nid > NODE_IOPLL) return PM_RET_ERROR_ARGS; /* Check if PLL mode is valid */ if (mode >= PM_PLL_MODE_MAX) return PM_RET_ERROR_ARGS; /* Send request to the PMU */ PM_PACK_PAYLOAD3(payload, PM_PLL_SET_MODE, nid, mode); return pm_ipi_send_sync(primary_proc, payload, NULL, 0); } /** * pm_pll_get_mode() - Get the PLL mode * @nid Node id of the target PLL * @mode Location to store the mode of the PLL * * @return Error if an argument is not valid or status as returned by the * PM controller (PMU) */ enum pm_ret_status pm_pll_get_mode(enum pm_node_id nid, enum pm_pll_mode *mode) { uint32_t payload[PAYLOAD_ARG_CNT]; /* Check if given node ID is a PLL node */ if (nid < NODE_APLL || nid > NODE_IOPLL) return PM_RET_ERROR_ARGS; /* Send request to the PMU */ PM_PACK_PAYLOAD2(payload, PM_PLL_GET_MODE, nid); return pm_ipi_send_sync(primary_proc, payload, mode, 1); } trusted-firmware-a-2.2/plat/xilinx/zynqmp/pm_service/pm_api_sys.h000066400000000000000000000146751355360272700254070ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PM_API_SYS_H #define PM_API_SYS_H #include #include "pm_defs.h" enum pm_query_id { PM_QID_INVALID, PM_QID_CLOCK_GET_NAME, PM_QID_CLOCK_GET_TOPOLOGY, PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS, PM_QID_CLOCK_GET_PARENTS, PM_QID_CLOCK_GET_ATTRIBUTES, PM_QID_PINCTRL_GET_NUM_PINS, PM_QID_PINCTRL_GET_NUM_FUNCTIONS, PM_QID_PINCTRL_GET_NUM_FUNCTION_GROUPS, PM_QID_PINCTRL_GET_FUNCTION_NAME, PM_QID_PINCTRL_GET_FUNCTION_GROUPS, PM_QID_PINCTRL_GET_PIN_GROUPS, PM_QID_CLOCK_GET_NUM_CLOCKS, }; /********************************************************** * System-level API function declarations **********************************************************/ enum pm_ret_status pm_req_suspend(enum pm_node_id nid, enum pm_request_ack ack, unsigned int latency, unsigned int state); enum pm_ret_status pm_self_suspend(enum pm_node_id nid, unsigned int latency, unsigned int state, uintptr_t address); enum pm_ret_status pm_force_powerdown(enum pm_node_id nid, enum pm_request_ack ack); enum pm_ret_status pm_abort_suspend(enum pm_abort_reason reason); enum pm_ret_status pm_req_wakeup(enum pm_node_id nid, unsigned int set_address, uintptr_t address, enum pm_request_ack ack); enum pm_ret_status pm_set_wakeup_source(enum pm_node_id target, enum pm_node_id wkup_node, unsigned int enable); enum pm_ret_status pm_system_shutdown(unsigned int type, unsigned int subtype); enum pm_ret_status pm_init_suspend_cb(enum pm_suspend_reason reason, unsigned int latency, unsigned int state, unsigned int timeout); /* API functions for managing PM Slaves */ enum pm_ret_status pm_req_node(enum pm_node_id nid, unsigned int capabilities, unsigned int qos, enum pm_request_ack ack); enum pm_ret_status pm_release_node(enum pm_node_id nid); enum pm_ret_status pm_set_requirement(enum pm_node_id nid, unsigned int capabilities, unsigned int qos, enum pm_request_ack ack); enum pm_ret_status pm_set_max_latency(enum pm_node_id nid, unsigned int latency); /* Miscellaneous API functions */ enum pm_ret_status pm_get_api_version(unsigned int *version); enum pm_ret_status pm_set_configuration(unsigned int phys_addr); enum pm_ret_status pm_init_finalize(void); enum pm_ret_status pm_get_node_status(enum pm_node_id node, uint32_t *ret_buff); enum pm_ret_status pm_register_notifier(enum pm_node_id nid, unsigned int event, unsigned int wake, unsigned int enable); enum pm_ret_status pm_get_op_characteristic(enum pm_node_id nid, enum pm_opchar_type type, uint32_t *result); enum pm_ret_status pm_acknowledge_cb(enum pm_node_id nid, enum pm_ret_status status, unsigned int oppoint); enum pm_ret_status pm_notify_cb(enum pm_node_id nid, unsigned int event, unsigned int oppoint); /* Direct-Control API functions */ enum pm_ret_status pm_reset_assert(unsigned int reset_id, unsigned int assert); enum pm_ret_status pm_reset_get_status(unsigned int reset_id, unsigned int *reset_status); enum pm_ret_status pm_mmio_write(uintptr_t address, unsigned int mask, unsigned int value); enum pm_ret_status pm_mmio_read(uintptr_t address, unsigned int *value); enum pm_ret_status pm_fpga_load(uint32_t address_low, uint32_t address_high, uint32_t size, uint32_t flags); enum pm_ret_status pm_fpga_get_status(unsigned int *value); enum pm_ret_status pm_get_chipid(uint32_t *value); enum pm_ret_status pm_secure_rsaaes(uint32_t address_high, uint32_t address_low, uint32_t size, uint32_t flags); unsigned int pm_get_shutdown_scope(void); enum pm_ret_status pm_pinctrl_request(unsigned int pin); enum pm_ret_status pm_pinctrl_release(unsigned int pin); enum pm_ret_status pm_pinctrl_get_function(unsigned int pin, enum pm_node_id *nid); enum pm_ret_status pm_pinctrl_set_function(unsigned int pin, enum pm_node_id nid); enum pm_ret_status pm_pinctrl_get_config(unsigned int pin, unsigned int param, unsigned int *value); enum pm_ret_status pm_pinctrl_set_config(unsigned int pin, unsigned int param, unsigned int value); enum pm_ret_status pm_ioctl(enum pm_node_id nid, unsigned int ioctl_id, unsigned int arg1, unsigned int arg2, unsigned int *value); enum pm_ret_status pm_clock_enable(unsigned int clock_id); enum pm_ret_status pm_clock_disable(unsigned int clock_id); enum pm_ret_status pm_clock_getstate(unsigned int clock_id, unsigned int *state); enum pm_ret_status pm_clock_setdivider(unsigned int clock_id, unsigned int divider); enum pm_ret_status pm_clock_getdivider(unsigned int clock_id, unsigned int *divider); enum pm_ret_status pm_clock_setrate(unsigned int clock_id, uint64_t rate); enum pm_ret_status pm_clock_getrate(unsigned int clock_id, uint64_t *rate); enum pm_ret_status pm_clock_setparent(unsigned int clock_id, unsigned int parent_id); enum pm_ret_status pm_clock_getparent(unsigned int clock_id, unsigned int *parent_id); enum pm_ret_status pm_query_data(enum pm_query_id qid, unsigned int arg1, unsigned int arg2, unsigned int arg3, unsigned int *data); enum pm_ret_status pm_sha_hash(uint32_t address_high, uint32_t address_low, uint32_t size, uint32_t flags); enum pm_ret_status pm_rsa_core(uint32_t address_high, uint32_t address_low, uint32_t size, uint32_t flags); enum pm_ret_status pm_secure_image(uint32_t address_low, uint32_t address_high, uint32_t key_lo, uint32_t key_hi, uint32_t *value); enum pm_ret_status pm_fpga_read(uint32_t reg_numframes, uint32_t address_low, uint32_t address_high, uint32_t readback_type, uint32_t *value); enum pm_ret_status pm_aes_engine(uint32_t address_high, uint32_t address_low, uint32_t *value); enum pm_ret_status pm_pll_set_parameter(enum pm_node_id nid, enum pm_pll_param param_id, unsigned int value); enum pm_ret_status pm_pll_get_parameter(enum pm_node_id nid, enum pm_pll_param param_id, unsigned int *value); enum pm_ret_status pm_pll_set_mode(enum pm_node_id nid, enum pm_pll_mode mode); enum pm_ret_status pm_pll_get_mode(enum pm_node_id nid, enum pm_pll_mode *mode); #endif /* PM_API_SYS_H */ trusted-firmware-a-2.2/plat/xilinx/zynqmp/pm_service/pm_client.c000066400000000000000000000167401355360272700252040ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * APU specific definition of processors in the subsystem as well as functions * for getting information about and changing state of the APU. */ #include #include #include #include #include #include #include #include #include #include #include "pm_api_sys.h" #include "pm_client.h" #include "pm_ipi.h" #define IRQ_MAX 84 #define NUM_GICD_ISENABLER ((IRQ_MAX >> 5) + 1) #define UNDEFINED_CPUID (~0) #define PM_SUSPEND_MODE_STD 0 #define PM_SUSPEND_MODE_POWER_OFF 1 DEFINE_BAKERY_LOCK(pm_client_secure_lock); extern const struct pm_ipi apu_ipi; const struct pm_ipi apu_ipi = { .local_ipi_id = IPI_ID_APU, .remote_ipi_id = IPI_ID_PMU0, .buffer_base = IPI_BUFFER_APU_BASE, }; static uint32_t suspend_mode = PM_SUSPEND_MODE_STD; /* Order in pm_procs_all array must match cpu ids */ static const struct pm_proc pm_procs_all[] = { { .node_id = NODE_APU_0, .pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK, .ipi = &apu_ipi, }, { .node_id = NODE_APU_1, .pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK, .ipi = &apu_ipi, }, { .node_id = NODE_APU_2, .pwrdn_mask = APU_2_PWRCTL_CPUPWRDWNREQ_MASK, .ipi = &apu_ipi, }, { .node_id = NODE_APU_3, .pwrdn_mask = APU_3_PWRCTL_CPUPWRDWNREQ_MASK, .ipi = &apu_ipi, }, }; /* Interrupt to PM node ID map */ static enum pm_node_id irq_node_map[IRQ_MAX + 1] = { NODE_UNKNOWN, NODE_UNKNOWN, NODE_UNKNOWN, NODE_UNKNOWN, /* 3 */ NODE_UNKNOWN, NODE_UNKNOWN, NODE_UNKNOWN, NODE_UNKNOWN, /* 7 */ NODE_UNKNOWN, NODE_UNKNOWN, NODE_UNKNOWN, NODE_UNKNOWN, /* 11 */ NODE_UNKNOWN, NODE_UNKNOWN, NODE_NAND, NODE_QSPI, /* 15 */ NODE_GPIO, NODE_I2C_0, NODE_I2C_1, NODE_SPI_0, /* 19 */ NODE_SPI_1, NODE_UART_0, NODE_UART_1, NODE_CAN_0, /* 23 */ NODE_CAN_1, NODE_UNKNOWN, NODE_RTC, NODE_RTC, /* 27 */ NODE_UNKNOWN, NODE_UNKNOWN, NODE_UNKNOWN, NODE_UNKNOWN, /* 31 */ NODE_UNKNOWN, NODE_UNKNOWN, NODE_UNKNOWN, NODE_UNKNOWN, /* 35, NODE_IPI_APU */ NODE_TTC_0, NODE_TTC_0, NODE_TTC_0, NODE_TTC_1, /* 39 */ NODE_TTC_1, NODE_TTC_1, NODE_TTC_2, NODE_TTC_2, /* 43 */ NODE_TTC_2, NODE_TTC_3, NODE_TTC_3, NODE_TTC_3, /* 47 */ NODE_SD_0, NODE_SD_1, NODE_SD_0, NODE_SD_1, /* 51 */ NODE_UNKNOWN, NODE_UNKNOWN, NODE_UNKNOWN, NODE_UNKNOWN, /* 55 */ NODE_UNKNOWN, NODE_ETH_0, NODE_ETH_0, NODE_ETH_1, /* 59 */ NODE_ETH_1, NODE_ETH_2, NODE_ETH_2, NODE_ETH_3, /* 63 */ NODE_ETH_3, NODE_USB_0, NODE_USB_0, NODE_USB_0, /* 67 */ NODE_USB_0, NODE_USB_0, NODE_USB_1, NODE_USB_1, /* 71 */ NODE_USB_1, NODE_USB_1, NODE_USB_1, NODE_USB_0, /* 75 */ NODE_USB_0, NODE_ADMA, NODE_ADMA, NODE_ADMA, /* 79 */ NODE_ADMA, NODE_ADMA, NODE_ADMA, NODE_ADMA, /* 83 */ NODE_ADMA, }; /** * irq_to_pm_node - Get PM node ID corresponding to the interrupt number * @irq: Interrupt number * * Return: PM node ID corresponding to the specified interrupt */ static enum pm_node_id irq_to_pm_node(unsigned int irq) { assert(irq <= IRQ_MAX); return irq_node_map[irq]; } /** * pm_client_set_wakeup_sources - Set all slaves with enabled interrupts as wake * sources in the PMU firmware */ static void pm_client_set_wakeup_sources(void) { uint32_t reg_num; uint8_t pm_wakeup_nodes_set[NODE_MAX]; uintptr_t isenabler1 = BASE_GICD_BASE + GICD_ISENABLER + 4; /* In case of power-off suspend, only NODE_EXTERN must be set */ if (suspend_mode == PM_SUSPEND_MODE_POWER_OFF) { enum pm_ret_status ret; ret = pm_set_wakeup_source(NODE_APU, NODE_EXTERN, 1); /** * If NODE_EXTERN could not be set as wake source, proceed with * standard suspend (no one will wake the system otherwise) */ if (ret == PM_RET_SUCCESS) return; } zeromem(&pm_wakeup_nodes_set, sizeof(pm_wakeup_nodes_set)); for (reg_num = 0; reg_num < NUM_GICD_ISENABLER; reg_num++) { uint32_t base_irq = reg_num << ISENABLER_SHIFT; uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2)); if (!reg) continue; while (reg) { enum pm_node_id node; uint32_t idx, ret, irq, lowest_set = reg & (-reg); idx = __builtin_ctz(lowest_set); irq = base_irq + idx; if (irq > IRQ_MAX) break; node = irq_to_pm_node(irq); reg &= ~lowest_set; if ((node != NODE_UNKNOWN) && (!pm_wakeup_nodes_set[node])) { ret = pm_set_wakeup_source(NODE_APU, node, 1); pm_wakeup_nodes_set[node] = !ret; } } } } /** * pm_get_proc() - returns pointer to the proc structure * @cpuid: id of the cpu whose proc struct pointer should be returned * * Return: pointer to a proc structure if proc is found, otherwise NULL */ const struct pm_proc *pm_get_proc(unsigned int cpuid) { if (cpuid < ARRAY_SIZE(pm_procs_all)) return &pm_procs_all[cpuid]; return NULL; } /** * pm_get_proc_by_node() - returns pointer to the proc structure * @nid: node id of the processor * * Return: pointer to a proc structure if proc is found, otherwise NULL */ const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid) { for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) { if (nid == pm_procs_all[i].node_id) return &pm_procs_all[i]; } return NULL; } /** * pm_get_cpuid() - get the local cpu ID for a global node ID * @nid: node id of the processor * * Return: the cpu ID (starting from 0) for the subsystem */ static unsigned int pm_get_cpuid(enum pm_node_id nid) { for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) { if (pm_procs_all[i].node_id == nid) return i; } return UNDEFINED_CPUID; } const struct pm_proc *primary_proc = &pm_procs_all[0]; /** * pm_client_suspend() - Client-specific suspend actions * * This function should contain any PU-specific actions * required prior to sending suspend request to PMU * Actions taken depend on the state system is suspending to. */ void pm_client_suspend(const struct pm_proc *proc, unsigned int state) { bakery_lock_get(&pm_client_secure_lock); if (state == PM_STATE_SUSPEND_TO_RAM) pm_client_set_wakeup_sources(); /* Set powerdown request */ mmio_write_32(APU_PWRCTL, mmio_read_32(APU_PWRCTL) | proc->pwrdn_mask); bakery_lock_release(&pm_client_secure_lock); } /** * pm_client_abort_suspend() - Client-specific abort-suspend actions * * This function should contain any PU-specific actions * required for aborting a prior suspend request */ void pm_client_abort_suspend(void) { /* Enable interrupts at processor level (for current cpu) */ gicv2_cpuif_enable(); bakery_lock_get(&pm_client_secure_lock); /* Clear powerdown request */ mmio_write_32(APU_PWRCTL, mmio_read_32(APU_PWRCTL) & ~primary_proc->pwrdn_mask); bakery_lock_release(&pm_client_secure_lock); } /** * pm_client_wakeup() - Client-specific wakeup actions * * This function should contain any PU-specific actions * required for waking up another APU core */ void pm_client_wakeup(const struct pm_proc *proc) { unsigned int cpuid = pm_get_cpuid(proc->node_id); if (cpuid == UNDEFINED_CPUID) return; bakery_lock_get(&pm_client_secure_lock); /* clear powerdown bit for affected cpu */ uint32_t val = mmio_read_32(APU_PWRCTL); val &= ~(proc->pwrdn_mask); mmio_write_32(APU_PWRCTL, val); bakery_lock_release(&pm_client_secure_lock); } enum pm_ret_status pm_set_suspend_mode(uint32_t mode) { if ((mode != PM_SUSPEND_MODE_STD) && (mode != PM_SUSPEND_MODE_POWER_OFF)) return PM_RET_ERROR_ARGS; suspend_mode = mode; return PM_RET_SUCCESS; } trusted-firmware-a-2.2/plat/xilinx/zynqmp/pm_service/pm_client.h000066400000000000000000000014521355360272700252030ustar00rootroot00000000000000/* * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * Contains APU specific macros and macros to be defined depending on * the execution environment. */ #ifndef PM_CLIENT_H #define PM_CLIENT_H #include "pm_common.h" #include "pm_defs.h" /* Functions to be implemented by each PU */ void pm_client_suspend(const struct pm_proc *proc, unsigned int state); void pm_client_abort_suspend(void); void pm_client_wakeup(const struct pm_proc *proc); enum pm_ret_status set_ocm_retention(void); enum pm_ret_status pm_set_suspend_mode(uint32_t mode); const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid); /* Global variables to be set in pm_client.c */ extern const struct pm_proc *primary_proc; #endif /* PM_CLIENT_H */ trusted-firmware-a-2.2/plat/xilinx/zynqmp/pm_service/pm_defs.h000066400000000000000000000153531355360272700246530ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* ZynqMP power management enums and defines */ #ifndef PM_DEFS_H #define PM_DEFS_H /********************************************************************* * Macro definitions ********************************************************************/ /* * Version number is a 32bit value, like: * (PM_VERSION_MAJOR << 16) | PM_VERSION_MINOR */ #define PM_VERSION_MAJOR 1 #define PM_VERSION_MINOR 0 #define PM_VERSION ((PM_VERSION_MAJOR << 16) | PM_VERSION_MINOR) /* Capabilities for RAM */ #define PM_CAP_ACCESS 0x1U #define PM_CAP_CONTEXT 0x2U #define MAX_LATENCY (~0U) #define MAX_QOS 100U /* State arguments of the self suspend */ #define PM_STATE_CPU_IDLE 0x0U #define PM_STATE_SUSPEND_TO_RAM 0xFU /********************************************************************* * Enum definitions ********************************************************************/ enum pm_api_id { /* Miscellaneous API functions: */ PM_GET_API_VERSION = 1, /* Do not change or move */ PM_SET_CONFIGURATION, PM_GET_NODE_STATUS, PM_GET_OP_CHARACTERISTIC, PM_REGISTER_NOTIFIER, /* API for suspending of PUs: */ PM_REQ_SUSPEND, PM_SELF_SUSPEND, PM_FORCE_POWERDOWN, PM_ABORT_SUSPEND, PM_REQ_WAKEUP, PM_SET_WAKEUP_SOURCE, PM_SYSTEM_SHUTDOWN, /* API for managing PM slaves: */ PM_REQ_NODE, PM_RELEASE_NODE, PM_SET_REQUIREMENT, PM_SET_MAX_LATENCY, /* Direct control API functions: */ PM_RESET_ASSERT, PM_RESET_GET_STATUS, PM_MMIO_WRITE, PM_MMIO_READ, PM_INIT_FINALIZE, PM_FPGA_LOAD, PM_FPGA_GET_STATUS, PM_GET_CHIPID, PM_SECURE_RSA_AES, PM_SECURE_SHA, PM_SECURE_RSA, PM_PINCTRL_REQUEST, PM_PINCTRL_RELEASE, PM_PINCTRL_GET_FUNCTION, PM_PINCTRL_SET_FUNCTION, PM_PINCTRL_CONFIG_PARAM_GET, PM_PINCTRL_CONFIG_PARAM_SET, PM_IOCTL, /* API to query information from firmware */ PM_QUERY_DATA, /* Clock control API functions */ PM_CLOCK_ENABLE, PM_CLOCK_DISABLE, PM_CLOCK_GETSTATE, PM_CLOCK_SETDIVIDER, PM_CLOCK_GETDIVIDER, PM_CLOCK_SETRATE, PM_CLOCK_GETRATE, PM_CLOCK_SETPARENT, PM_CLOCK_GETPARENT, PM_SECURE_IMAGE, /* FPGA PL Readback */ PM_FPGA_READ, PM_SECURE_AES, /* PLL control API functions */ PM_PLL_SET_PARAMETER, PM_PLL_GET_PARAMETER, PM_PLL_SET_MODE, PM_PLL_GET_MODE, PM_API_MAX }; enum pm_node_id { NODE_UNKNOWN = 0, NODE_APU, NODE_APU_0, NODE_APU_1, NODE_APU_2, NODE_APU_3, NODE_RPU, NODE_RPU_0, NODE_RPU_1, NODE_PLD, NODE_FPD, NODE_OCM_BANK_0, NODE_OCM_BANK_1, NODE_OCM_BANK_2, NODE_OCM_BANK_3, NODE_TCM_0_A, NODE_TCM_0_B, NODE_TCM_1_A, NODE_TCM_1_B, NODE_L2, NODE_GPU_PP_0, NODE_GPU_PP_1, NODE_USB_0, NODE_USB_1, NODE_TTC_0, NODE_TTC_1, NODE_TTC_2, NODE_TTC_3, NODE_SATA, NODE_ETH_0, NODE_ETH_1, NODE_ETH_2, NODE_ETH_3, NODE_UART_0, NODE_UART_1, NODE_SPI_0, NODE_SPI_1, NODE_I2C_0, NODE_I2C_1, NODE_SD_0, NODE_SD_1, NODE_DP, NODE_GDMA, NODE_ADMA, NODE_NAND, NODE_QSPI, NODE_GPIO, NODE_CAN_0, NODE_CAN_1, NODE_EXTERN, NODE_APLL, NODE_VPLL, NODE_DPLL, NODE_RPLL, NODE_IOPLL, NODE_DDR, NODE_IPI_APU, NODE_IPI_RPU_0, NODE_GPU, NODE_PCIE, NODE_PCAP, NODE_RTC, NODE_LPD, NODE_VCU, NODE_IPI_RPU_1, NODE_IPI_PL_0, NODE_IPI_PL_1, NODE_IPI_PL_2, NODE_IPI_PL_3, NODE_PL, NODE_GEM_TSU, NODE_SWDT_0, NODE_SWDT_1, NODE_CSU, NODE_PJTAG, NODE_TRACE, NODE_TESTSCAN, NODE_PMU, NODE_MAX, }; enum pm_request_ack { REQ_ACK_NO = 1, REQ_ACK_BLOCKING, REQ_ACK_NON_BLOCKING, }; enum pm_abort_reason { ABORT_REASON_WKUP_EVENT = 100, ABORT_REASON_PU_BUSY, ABORT_REASON_NO_PWRDN, ABORT_REASON_UNKNOWN, }; enum pm_suspend_reason { SUSPEND_REASON_PU_REQ = 201, SUSPEND_REASON_ALERT, SUSPEND_REASON_SYS_SHUTDOWN, }; enum pm_ram_state { PM_RAM_STATE_OFF = 1, PM_RAM_STATE_RETENTION, PM_RAM_STATE_ON, }; enum pm_opchar_type { PM_OPCHAR_TYPE_POWER = 1, PM_OPCHAR_TYPE_TEMP, PM_OPCHAR_TYPE_LATENCY, }; /** * @PM_RET_SUCCESS: success * @PM_RET_ERROR_ARGS: illegal arguments provided * @PM_RET_ERROR_ACCESS: access rights violation * @PM_RET_ERROR_TIMEOUT: timeout in communication with PMU * @PM_RET_ERROR_NOTSUPPORTED: feature not supported * @PM_RET_ERROR_PROC: node is not a processor node * @PM_RET_ERROR_API_ID: illegal API ID * @PM_RET_ERROR_OTHER: other error */ enum pm_ret_status { PM_RET_SUCCESS, PM_RET_ERROR_ARGS, PM_RET_ERROR_ACCESS, PM_RET_ERROR_TIMEOUT, PM_RET_ERROR_NOTSUPPORTED, PM_RET_ERROR_PROC, PM_RET_ERROR_API_ID, PM_RET_ERROR_FAILURE, PM_RET_ERROR_COMMUNIC, PM_RET_ERROR_DOUBLEREQ, PM_RET_ERROR_OTHER, }; /** * @PM_INITIAL_BOOT: boot is a fresh system startup * @PM_RESUME: boot is a resume * @PM_BOOT_ERROR: error, boot cause cannot be identified */ enum pm_boot_status { PM_INITIAL_BOOT, PM_RESUME, PM_BOOT_ERROR, }; /** * @PMF_SHUTDOWN_TYPE_SHUTDOWN: shutdown * @PMF_SHUTDOWN_TYPE_RESET: reset/reboot * @PMF_SHUTDOWN_TYPE_SETSCOPE_ONLY: set the shutdown/reboot scope */ enum pm_shutdown_type { PMF_SHUTDOWN_TYPE_SHUTDOWN, PMF_SHUTDOWN_TYPE_RESET, PMF_SHUTDOWN_TYPE_SETSCOPE_ONLY, }; /** * @PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM: shutdown/reboot APU subsystem only * @PMF_SHUTDOWN_SUBTYPE_PS_ONLY: shutdown/reboot entire PS (but not PL) * @PMF_SHUTDOWN_SUBTYPE_SYSTEM: shutdown/reboot entire system */ enum pm_shutdown_subtype { PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM, PMF_SHUTDOWN_SUBTYPE_PS_ONLY, PMF_SHUTDOWN_SUBTYPE_SYSTEM, }; /** * @PM_PLL_PARAM_DIV2: Enable for divide by 2 function inside the PLL * @PM_PLL_PARAM_FBDIV: Feedback divisor integer portion for the PLL * @PM_PLL_PARAM_DATA: Feedback divisor fractional portion for the PLL * @PM_PLL_PARAM_PRE_SRC: Clock source for PLL input * @PM_PLL_PARAM_POST_SRC: Clock source for PLL Bypass mode * @PM_PLL_PARAM_LOCK_DLY: Lock circuit config settings for lock windowsize * @PM_PLL_PARAM_LOCK_CNT: Lock circuit counter setting * @PM_PLL_PARAM_LFHF: PLL loop filter high frequency capacitor control * @PM_PLL_PARAM_CP: PLL charge pump control * @PM_PLL_PARAM_RES: PLL loop filter resistor control */ enum pm_pll_param { PM_PLL_PARAM_DIV2, PM_PLL_PARAM_FBDIV, PM_PLL_PARAM_DATA, PM_PLL_PARAM_PRE_SRC, PM_PLL_PARAM_POST_SRC, PM_PLL_PARAM_LOCK_DLY, PM_PLL_PARAM_LOCK_CNT, PM_PLL_PARAM_LFHF, PM_PLL_PARAM_CP, PM_PLL_PARAM_RES, PM_PLL_PARAM_MAX, }; /** * @PM_PLL_MODE_RESET: PLL is in reset (not locked) * @PM_PLL_MODE_INTEGER: PLL is locked in integer mode * @PM_PLL_MODE_FRACTIONAL: PLL is locked in fractional mode */ enum pm_pll_mode { PM_PLL_MODE_RESET, PM_PLL_MODE_INTEGER, PM_PLL_MODE_FRACTIONAL, PM_PLL_MODE_MAX, }; /** * @PM_CLOCK_DIV0_ID: Clock divider 0 * @PM_CLOCK_DIV1_ID: Clock divider 1 */ enum pm_clock_div_id { PM_CLOCK_DIV0_ID, PM_CLOCK_DIV1_ID, }; #endif /* PM_DEFS_H */ trusted-firmware-a-2.2/plat/xilinx/zynqmp/pm_service/pm_svc_main.c000066400000000000000000000347331355360272700255270ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * Top-level SMC handler for ZynqMP power management calls and * IPI setup functions for communication with PMU. */ #include #include #if ZYNQMP_WDT_RESTART #include #include #include #include #include #endif #include #include "pm_api_sys.h" #include "pm_client.h" #include "pm_ipi.h" #define PM_SET_SUSPEND_MODE 0xa02 #define PM_GET_TRUSTZONE_VERSION 0xa03 /* !0 - UP, 0 - DOWN */ static int32_t pm_up = 0; #if ZYNQMP_WDT_RESTART static spinlock_t inc_lock; static int active_cores = 0; #endif /** * pm_context - Structure which contains data for power management * @api_version version of PM API, must match with one on PMU side * @payload payload array used to store received * data from ipi buffer registers */ static struct { uint32_t api_version; uint32_t payload[PAYLOAD_ARG_CNT]; } pm_ctx; #if ZYNQMP_WDT_RESTART /** * trigger_wdt_restart() - Trigger warm restart event to APU cores * * This function triggers SGI for all active APU CPUs. SGI handler then * power down CPU and call system reset. */ static void trigger_wdt_restart(void) { uint32_t core_count = 0; uint32_t core_status[3]; uint32_t target_cpu_list = 0; int i; for (i = 0; i < 4; i++) { pm_get_node_status(NODE_APU_0 + i, core_status); if (core_status[0] == 1) { core_count++; target_cpu_list |= (1 << i); } } spin_lock(&inc_lock); active_cores = core_count; spin_unlock(&inc_lock); INFO("Active Cores: %d\n", active_cores); /* trigger SGI to active cores */ gicv2_raise_sgi(ARM_IRQ_SEC_SGI_7, target_cpu_list); } /** * ttc_fiq_handler() - TTC Handler for timer event * @id number of the highest priority pending interrupt of the type * that this handler was registered for * @flags security state, bit[0] * @handler pointer to 'cpu_context' structure of the current CPU for the * security state specified in the 'flags' parameter * @cookie unused * * Function registered as INTR_TYPE_EL3 interrupt handler * * When WDT event is received in PMU, PMU needs to notify master to do cleanup * if required. PMU sets up timer and starts timer to overflow in zero time upon * WDT event. ATF handles this timer event and takes necessary action required * for warm restart. * * In presence of non-secure software layers (EL1/2) sets the interrupt * at registered entrance in GIC and informs that PMU responsed or demands * action. */ static uint64_t ttc_fiq_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { INFO("BL31: Got TTC FIQ\n"); /* Clear TTC interrupt by reading interrupt register */ mmio_read_32(TTC3_INTR_REGISTER_1); /* Disable the timer interrupts */ mmio_write_32(TTC3_INTR_ENABLE_1, 0); trigger_wdt_restart(); return 0; } /** * zynqmp_sgi7_irq() - Handler for SGI7 IRQ * @id number of the highest priority pending interrupt of the type * that this handler was registered for * @flags security state, bit[0] * @handler pointer to 'cpu_context' structure of the current CPU for the * security state specified in the 'flags' parameter * @cookie unused * * Function registered as INTR_TYPE_EL3 interrupt handler * * On receiving WDT event from PMU, ATF generates SGI7 to all running CPUs. * In response to SGI7 interrupt, each CPUs do clean up if required and last * running CPU calls system restart. */ static uint64_t __unused __dead2 zynqmp_sgi7_irq(uint32_t id, uint32_t flags, void *handle, void *cookie) { int i; /* enter wfi and stay there */ INFO("Entering wfi\n"); spin_lock(&inc_lock); active_cores--; for (i = 0; i < 4; i++) { mmio_write_32(BASE_GICD_BASE + GICD_CPENDSGIR + 4 * i, 0xffffffff); } spin_unlock(&inc_lock); if (active_cores == 0) { pm_system_shutdown(PMF_SHUTDOWN_TYPE_RESET, PMF_SHUTDOWN_SUBTYPE_SUBSYSTEM); } /* enter wfi and stay there */ while (1) wfi(); } /** * pm_wdt_restart_setup() - Setup warm restart interrupts * * This function sets up handler for SGI7 and TTC interrupts * used for warm restart. */ static int pm_wdt_restart_setup(void) { int ret; /* register IRQ handler for SGI7 */ ret = request_intr_type_el3(ARM_IRQ_SEC_SGI_7, zynqmp_sgi7_irq); if (ret) { WARN("BL31: registering SGI7 interrupt failed\n"); goto err; } ret = request_intr_type_el3(IRQ_TTC3_1, ttc_fiq_handler); if (ret) WARN("BL31: registering TTC3 interrupt failed\n"); err: return ret; } #endif /** * pm_setup() - PM service setup * * @return On success, the initialization function must return 0. * Any other return value will cause the framework to ignore * the service * * Initialization functions for ZynqMP power management for * communicaton with PMU. * * Called from sip_svc_setup initialization function with the * rt_svc_init signature. */ int pm_setup(void) { int status, ret; status = pm_ipi_init(primary_proc); #if ZYNQMP_WDT_RESTART status = pm_wdt_restart_setup(); if (status) WARN("BL31: warm-restart setup failed\n"); #endif if (status >= 0) { INFO("BL31: PM Service Init Complete: API v%d.%d\n", PM_VERSION_MAJOR, PM_VERSION_MINOR); ret = 0; } else { INFO("BL31: PM Service Init Failed, Error Code %d!\n", status); ret = status; } pm_up = !status; return ret; } /** * pm_smc_handler() - SMC handler for PM-API calls coming from EL1/EL2. * @smc_fid - Function Identifier * @x1 - x4 - Arguments * @cookie - Unused * @handler - Pointer to caller's context structure * * @return - Unused * * Determines that smc_fid is valid and supported PM SMC Function ID from the * list of pm_api_ids, otherwise completes the request with * the unknown SMC Function ID * * The SMC calls for PM service are forwarded from SIP Service SMC handler * function with rt_svc_handle signature */ uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, void *cookie, void *handle, uint64_t flags) { enum pm_ret_status ret; uint32_t pm_arg[4]; /* Handle case where PM wasn't initialized properly */ if (!pm_up) SMC_RET1(handle, SMC_UNK); pm_arg[0] = (uint32_t)x1; pm_arg[1] = (uint32_t)(x1 >> 32); pm_arg[2] = (uint32_t)x2; pm_arg[3] = (uint32_t)(x2 >> 32); switch (smc_fid & FUNCID_NUM_MASK) { /* PM API Functions */ case PM_SELF_SUSPEND: ret = pm_self_suspend(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); SMC_RET1(handle, (uint64_t)ret); case PM_REQ_SUSPEND: ret = pm_req_suspend(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); SMC_RET1(handle, (uint64_t)ret); case PM_REQ_WAKEUP: { /* Use address flag is encoded in the 1st bit of the low-word */ unsigned int set_addr = pm_arg[1] & 0x1; uint64_t address = (uint64_t)pm_arg[2] << 32; address |= pm_arg[1] & (~0x1); ret = pm_req_wakeup(pm_arg[0], set_addr, address, pm_arg[3]); SMC_RET1(handle, (uint64_t)ret); } case PM_FORCE_POWERDOWN: ret = pm_force_powerdown(pm_arg[0], pm_arg[1]); SMC_RET1(handle, (uint64_t)ret); case PM_ABORT_SUSPEND: ret = pm_abort_suspend(pm_arg[0]); SMC_RET1(handle, (uint64_t)ret); case PM_SET_WAKEUP_SOURCE: ret = pm_set_wakeup_source(pm_arg[0], pm_arg[1], pm_arg[2]); SMC_RET1(handle, (uint64_t)ret); case PM_SYSTEM_SHUTDOWN: ret = pm_system_shutdown(pm_arg[0], pm_arg[1]); SMC_RET1(handle, (uint64_t)ret); case PM_REQ_NODE: ret = pm_req_node(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); SMC_RET1(handle, (uint64_t)ret); case PM_RELEASE_NODE: ret = pm_release_node(pm_arg[0]); SMC_RET1(handle, (uint64_t)ret); case PM_SET_REQUIREMENT: ret = pm_set_requirement(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); SMC_RET1(handle, (uint64_t)ret); case PM_SET_MAX_LATENCY: ret = pm_set_max_latency(pm_arg[0], pm_arg[1]); SMC_RET1(handle, (uint64_t)ret); case PM_GET_API_VERSION: /* Check is PM API version already verified */ if (pm_ctx.api_version == PM_VERSION) { SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS | ((uint64_t)PM_VERSION << 32)); } ret = pm_get_api_version(&pm_ctx.api_version); /* * Enable IPI IRQ * assume the rich OS is OK to handle callback IRQs now. * Even if we were wrong, it would not enable the IRQ in * the GIC. */ pm_ipi_irq_enable(primary_proc); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)pm_ctx.api_version << 32)); case PM_SET_CONFIGURATION: ret = pm_set_configuration(pm_arg[0]); SMC_RET1(handle, (uint64_t)ret); case PM_INIT_FINALIZE: ret = pm_init_finalize(); SMC_RET1(handle, (uint64_t)ret); case PM_GET_NODE_STATUS: { uint32_t buff[3]; ret = pm_get_node_status(pm_arg[0], buff); SMC_RET2(handle, (uint64_t)ret | ((uint64_t)buff[0] << 32), (uint64_t)buff[1] | ((uint64_t)buff[2] << 32)); } case PM_GET_OP_CHARACTERISTIC: { uint32_t result; ret = pm_get_op_characteristic(pm_arg[0], pm_arg[1], &result); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)result << 32)); } case PM_REGISTER_NOTIFIER: ret = pm_register_notifier(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); SMC_RET1(handle, (uint64_t)ret); case PM_RESET_ASSERT: ret = pm_reset_assert(pm_arg[0], pm_arg[1]); SMC_RET1(handle, (uint64_t)ret); case PM_RESET_GET_STATUS: { uint32_t reset_status; ret = pm_reset_get_status(pm_arg[0], &reset_status); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)reset_status << 32)); } /* PM memory access functions */ case PM_MMIO_WRITE: ret = pm_mmio_write(pm_arg[0], pm_arg[1], pm_arg[2]); SMC_RET1(handle, (uint64_t)ret); case PM_MMIO_READ: { uint32_t value; ret = pm_mmio_read(pm_arg[0], &value); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); } case PM_FPGA_LOAD: ret = pm_fpga_load(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); SMC_RET1(handle, (uint64_t)ret); case PM_FPGA_GET_STATUS: { uint32_t value; ret = pm_fpga_get_status(&value); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); } case PM_GET_CHIPID: { uint32_t result[2]; ret = pm_get_chipid(result); SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32), result[1]); } case PM_SECURE_RSA_AES: ret = pm_secure_rsaaes(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); SMC_RET1(handle, (uint64_t)ret); case PM_PINCTRL_REQUEST: ret = pm_pinctrl_request(pm_arg[0]); SMC_RET1(handle, (uint64_t)ret); case PM_PINCTRL_RELEASE: ret = pm_pinctrl_release(pm_arg[0]); SMC_RET1(handle, (uint64_t)ret); case PM_PINCTRL_GET_FUNCTION: { uint32_t value = 0; ret = pm_pinctrl_get_function(pm_arg[0], &value); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); } case PM_PINCTRL_SET_FUNCTION: ret = pm_pinctrl_set_function(pm_arg[0], pm_arg[1]); SMC_RET1(handle, (uint64_t)ret); case PM_PINCTRL_CONFIG_PARAM_GET: { uint32_t value; ret = pm_pinctrl_get_config(pm_arg[0], pm_arg[1], &value); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); } case PM_PINCTRL_CONFIG_PARAM_SET: ret = pm_pinctrl_set_config(pm_arg[0], pm_arg[1], pm_arg[2]); SMC_RET1(handle, (uint64_t)ret); case PM_IOCTL: { uint32_t value; ret = pm_ioctl(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3], &value); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); } case PM_QUERY_DATA: { uint32_t data[4] = { 0 }; ret = pm_query_data(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3], data); SMC_RET2(handle, (uint64_t)data[0] | ((uint64_t)data[1] << 32), (uint64_t)data[2] | ((uint64_t)data[3] << 32)); } case PM_CLOCK_ENABLE: ret = pm_clock_enable(pm_arg[0]); SMC_RET1(handle, (uint64_t)ret); case PM_CLOCK_DISABLE: ret = pm_clock_disable(pm_arg[0]); SMC_RET1(handle, (uint64_t)ret); case PM_CLOCK_GETSTATE: { uint32_t value; ret = pm_clock_getstate(pm_arg[0], &value); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); } case PM_CLOCK_SETDIVIDER: ret = pm_clock_setdivider(pm_arg[0], pm_arg[1]); SMC_RET1(handle, (uint64_t)ret); case PM_CLOCK_GETDIVIDER: { uint32_t value; ret = pm_clock_getdivider(pm_arg[0], &value); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); } case PM_CLOCK_SETRATE: ret = pm_clock_setrate(pm_arg[0], ((uint64_t)pm_arg[2]) << 32 | pm_arg[1]); SMC_RET1(handle, (uint64_t)ret); case PM_CLOCK_GETRATE: { uint64_t value; ret = pm_clock_getrate(pm_arg[0], &value); SMC_RET2(handle, (uint64_t)ret | (((uint64_t)value & 0xFFFFFFFFU) << 32U), (value >> 32U) & 0xFFFFFFFFU); } case PM_CLOCK_SETPARENT: ret = pm_clock_setparent(pm_arg[0], pm_arg[1]); SMC_RET1(handle, (uint64_t)ret); case PM_CLOCK_GETPARENT: { uint32_t value; ret = pm_clock_getparent(pm_arg[0], &value); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); } case PM_GET_TRUSTZONE_VERSION: SMC_RET1(handle, (uint64_t)PM_RET_SUCCESS | ((uint64_t)ZYNQMP_TZ_VERSION << 32)); case PM_SET_SUSPEND_MODE: ret = pm_set_suspend_mode(pm_arg[0]); SMC_RET1(handle, (uint64_t)ret); case PM_SECURE_SHA: ret = pm_sha_hash(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); SMC_RET1(handle, (uint64_t)ret); case PM_SECURE_RSA: ret = pm_rsa_core(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3]); SMC_RET1(handle, (uint64_t)ret); case PM_SECURE_IMAGE: { uint32_t result[2]; ret = pm_secure_image(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3], &result[0]); SMC_RET2(handle, (uint64_t)ret | ((uint64_t)result[0] << 32), result[1]); } case PM_FPGA_READ: { uint32_t value; ret = pm_fpga_read(pm_arg[0], pm_arg[1], pm_arg[2], pm_arg[3], &value); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); } case PM_SECURE_AES: { uint32_t value; ret = pm_aes_engine(pm_arg[0], pm_arg[1], &value); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value) << 32); } case PM_PLL_SET_PARAMETER: ret = pm_pll_set_parameter(pm_arg[0], pm_arg[1], pm_arg[2]); SMC_RET1(handle, (uint64_t)ret); case PM_PLL_GET_PARAMETER: { uint32_t value; ret = pm_pll_get_parameter(pm_arg[0], pm_arg[1], &value); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)value << 32)); } case PM_PLL_SET_MODE: ret = pm_pll_set_mode(pm_arg[0], pm_arg[1]); SMC_RET1(handle, (uint64_t)ret); case PM_PLL_GET_MODE: { uint32_t mode; ret = pm_pll_get_mode(pm_arg[0], &mode); SMC_RET1(handle, (uint64_t)ret | ((uint64_t)mode << 32)); } default: WARN("Unimplemented PM Service Call: 0x%x\n", smc_fid); SMC_RET1(handle, SMC_UNK); } } trusted-firmware-a-2.2/plat/xilinx/zynqmp/pm_service/pm_svc_main.h000066400000000000000000000006111355360272700255200ustar00rootroot00000000000000/* * Copyright (c) 2013-2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef PM_SVC_MAIN_H #define PM_SVC_MAIN_H #include "pm_common.h" int pm_setup(void); uint64_t pm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, void *cookie, void *handle, uint64_t flags); #endif /* PM_SVC_MAIN_H */ trusted-firmware-a-2.2/plat/xilinx/zynqmp/sip_svc_setup.c000066400000000000000000000047771355360272700237730ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* Top level SMC handler for SiP calls. Dispatch PM calls to PM SMC handler. */ #include #include #include "ipi_mailbox_svc.h" #include "pm_svc_main.h" /* SMC function IDs for SiP Service queries */ #define ZYNQMP_SIP_SVC_CALL_COUNT 0x8200ff00 #define ZYNQMP_SIP_SVC_UID 0x8200ff01 #define ZYNQMP_SIP_SVC_VERSION 0x8200ff03 /* SiP Service Calls version numbers */ #define SIP_SVC_VERSION_MAJOR 0 #define SIP_SVC_VERSION_MINOR 1 /* These macros are used to identify PM, IPI calls from the SMC function ID */ #define PM_FID_MASK 0xf000u #define PM_FID_VALUE 0u #define IPI_FID_VALUE 0x1000u #define is_pm_fid(_fid) (((_fid) & PM_FID_MASK) == PM_FID_VALUE) #define is_ipi_fid(_fid) (((_fid) & PM_FID_MASK) == IPI_FID_VALUE) /* SiP Service UUID */ DEFINE_SVC_UUID2(zynqmp_sip_uuid, 0x5c9b1b2a, 0x0586, 0x2340, 0xa6, 0x1b, 0xb9, 0x25, 0x82, 0x2d, 0xe3, 0xa5); /** * sip_svc_setup() - Setup SiP Service * * Invokes PM setup */ static int32_t sip_svc_setup(void) { /* PM implementation as SiP Service */ pm_setup(); return 0; } /** * sip_svc_smc_handler() - Top-level SiP Service SMC handler * * Handler for all SiP SMC calls. Handles standard SIP requests * and calls PM SMC handler if the call is for a PM-API function. */ uintptr_t sip_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) { /* Let PM SMC handler deal with PM-related requests */ if (is_pm_fid(smc_fid)) { return pm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); } /* Let IPI SMC handler deal with IPI-related requests */ if (is_ipi_fid(smc_fid)) { return ipi_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); } switch (smc_fid) { case ZYNQMP_SIP_SVC_CALL_COUNT: /* PM functions + default functions */ SMC_RET1(handle, PM_API_MAX + 2); case ZYNQMP_SIP_SVC_UID: SMC_UUID_RET(handle, zynqmp_sip_uuid); case ZYNQMP_SIP_SVC_VERSION: SMC_RET2(handle, SIP_SVC_VERSION_MAJOR, SIP_SVC_VERSION_MINOR); default: WARN("Unimplemented SiP Service Call: 0x%x\n", smc_fid); SMC_RET1(handle, SMC_UNK); } } /* Register PM Service Calls as runtime service */ DECLARE_RT_SVC( sip_svc, OEN_SIP_START, OEN_SIP_END, SMC_TYPE_FAST, sip_svc_setup, sip_svc_smc_handler); trusted-firmware-a-2.2/plat/xilinx/zynqmp/tsp/000077500000000000000000000000001355360272700215305ustar00rootroot00000000000000trusted-firmware-a-2.2/plat/xilinx/zynqmp/tsp/tsp-zynqmp.mk000066400000000000000000000004151355360272700242230ustar00rootroot00000000000000# # Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # TSP source files specific to ZynqMP platform BL32_SOURCES += plat/common/aarch64/platform_mp_stack.S \ plat/xilinx/zynqmp/tsp/tsp_plat_setup.c trusted-firmware-a-2.2/plat/xilinx/zynqmp/tsp/tsp_plat_setup.c000066400000000000000000000041121355360272700247400ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include /******************************************************************************* * Initialize the UART ******************************************************************************/ void tsp_early_platform_setup(void) { /* * Register a different console than already in use to display * messages from TSP */ static console_cdns_t tsp_boot_console; (void)console_cdns_register(ZYNQMP_UART_BASE, zynqmp_get_uart_clk(), ZYNQMP_UART_BAUDRATE, &tsp_boot_console); console_set_scope(&tsp_boot_console.console, CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_BOOT); /* Initialize the platform config for future decision making */ zynqmp_config_setup(); } /******************************************************************************* * Perform platform specific setup placeholder ******************************************************************************/ void tsp_platform_setup(void) { plat_arm_gic_driver_init(); plat_arm_gic_init(); } /******************************************************************************* * Perform the very early platform specific architectural setup here. At the * moment this is only intializes the MMU ******************************************************************************/ void tsp_plat_arch_setup(void) { const mmap_region_t bl_regions[] = { MAP_REGION_FLAT(BL32_BASE, BL32_END - BL32_BASE, MT_MEMORY | MT_RW | MT_SECURE), MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, MT_CODE | MT_SECURE), MAP_REGION_FLAT(BL_RO_DATA_BASE, BL_RO_DATA_END - BL_RO_DATA_BASE, MT_RO_DATA | MT_SECURE), MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, MT_DEVICE | MT_RW | MT_SECURE), {0} }; setup_page_tables(bl_regions, plat_arm_get_mmap()); enable_mmu_el1(0); } trusted-firmware-a-2.2/plat/xilinx/zynqmp/zynqmp_ipi.c000066400000000000000000000034771355360272700233000ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * Zynq UltraScale+ MPSoC IPI agent registers access management */ #include #include #include #include #include #include #include #include #include /* Zynqmp ipi configuration table */ const static struct ipi_config zynqmp_ipi_table[] = { /* APU IPI */ { .ipi_bit_mask = 0x1, .ipi_reg_base = 0xFF300000, .secure_only = 0, }, /* RPU0 IPI */ { .ipi_bit_mask = 0x100, .ipi_reg_base = 0xFF310000, .secure_only = 0, }, /* RPU1 IPI */ { .ipi_bit_mask = 0x200, .ipi_reg_base = 0xFF320000, .secure_only = 0, }, /* PMU0 IPI */ { .ipi_bit_mask = 0x10000, .ipi_reg_base = 0xFF330000, .secure_only = IPI_SECURE_MASK, }, /* PMU1 IPI */ { .ipi_bit_mask = 0x20000, .ipi_reg_base = 0xFF331000, .secure_only = 0, }, /* PMU2 IPI */ { .ipi_bit_mask = 0x40000, .ipi_reg_base = 0xFF332000, .secure_only = IPI_SECURE_MASK, }, /* PMU3 IPI */ { .ipi_bit_mask = 0x80000, .ipi_reg_base = 0xFF333000, .secure_only = IPI_SECURE_MASK, }, /* PL0 IPI */ { .ipi_bit_mask = 0x1000000, .ipi_reg_base = 0xFF340000, .secure_only = 0, }, /* PL1 IPI */ { .ipi_bit_mask = 0x2000000, .ipi_reg_base = 0xFF350000, .secure_only = 0, }, /* PL2 IPI */ { .ipi_bit_mask = 0x4000000, .ipi_reg_base = 0xFF360000, .secure_only = 0, }, /* PL3 IPI */ { .ipi_bit_mask = 0x8000000, .ipi_reg_base = 0xFF370000, .secure_only = 0, }, }; /** * zynqmp_ipi_config_table_init() - Initialize ZynqMP IPI configuration data * */ void zynqmp_ipi_config_table_init(void) { ipi_config_table_init(zynqmp_ipi_table, ARRAY_SIZE(zynqmp_ipi_table)); } trusted-firmware-a-2.2/readme.rst000066400000000000000000000052011355360272700170760ustar00rootroot00000000000000Trusted Firmware-A ================== Trusted Firmware-A (TF-A) is a reference implementation of secure world software for `Arm A-Profile architectures`_ (Armv8-A and Armv7-A), including an Exception Level 3 (EL3) `Secure Monitor`_. It provides a suitable starting point for productization of secure world boot and runtime firmware, in either the AArch32 or AArch64 execution states. TF-A implements Arm interface standards, including: - `Power State Coordination Interface (PSCI)`_ - `Trusted Board Boot Requirements CLIENT (TBBR-CLIENT)`_ - `SMC Calling Convention`_ - `System Control and Management Interface (SCMI)`_ - `Software Delegated Exception Interface (SDEI)`_ The code is designed to be portable and reusable across hardware platforms and software models that are based on the Armv8-A and Armv7-A architectures. In collaboration with interested parties, we will continue to enhance TF-A with reference implementations of Arm standards to benefit developers working with Armv7-A and Armv8-A TrustZone technology. Users are encouraged to do their own security validation, including penetration testing, on any secure world code derived from TF-A. More Info and Documentation --------------------------- To find out more about Trusted Firmware-A, please `view the full documentation`_ that is available through `trustedfirmware.org`_. -------------- *Copyright (c) 2013-2019, Arm Limited and Contributors. All rights reserved.* .. _Armv7-A and Armv8-A: https://developer.arm.com/products/architecture/a-profile .. _Secure Monitor: http://www.arm.com/products/processors/technologies/trustzone/tee-smc.php .. _Power State Coordination Interface (PSCI): PSCI_ .. _PSCI: http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf .. _Trusted Board Boot Requirements CLIENT (TBBR-CLIENT): https://developer.arm.com/docs/den0006/latest/trusted-board-boot-requirements-client-tbbr-client-armv8-a .. _SMC Calling Convention: http://infocenter.arm.com/help/topic/com.arm.doc.den0028b/ARM_DEN0028B_SMC_Calling_Convention.pdf .. _System Control and Management Interface (SCMI): SCMI_ .. _SCMI: http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/DEN0056A_System_Control_and_Management_Interface.pdf .. _Software Delegated Exception Interface (SDEI): SDEI_ .. _SDEI: http://infocenter.arm.com/help/topic/com.arm.doc.den0054a/ARM_DEN0054A_Software_Delegated_Exception_Interface.pdf .. _Arm A-Profile architectures: https://developer.arm.com/architectures/cpu-architecture/a-profile .. _view the full documentation: https://www.trustedfirmware.org/docs/tf-a .. _trustedfirmware.org: http://www.trustedfirmware.org trusted-firmware-a-2.2/services/000077500000000000000000000000001355360272700167345ustar00rootroot00000000000000trusted-firmware-a-2.2/services/arm_arch_svc/000077500000000000000000000000001355360272700213635ustar00rootroot00000000000000trusted-firmware-a-2.2/services/arm_arch_svc/arm_arch_svc_setup.c000066400000000000000000000061351355360272700254030ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include static int32_t smccc_version(void) { return MAKE_SMCCC_VERSION(SMCCC_MAJOR_VERSION, SMCCC_MINOR_VERSION); } static int32_t smccc_arch_features(u_register_t arg) { switch (arg) { case SMCCC_VERSION: case SMCCC_ARCH_FEATURES: return SMC_OK; #if WORKAROUND_CVE_2017_5715 case SMCCC_ARCH_WORKAROUND_1: if (check_wa_cve_2017_5715() == ERRATA_NOT_APPLIES) return 1; return 0; /* ERRATA_APPLIES || ERRATA_MISSING */ #endif #if WORKAROUND_CVE_2018_3639 case SMCCC_ARCH_WORKAROUND_2: { #if DYNAMIC_WORKAROUND_CVE_2018_3639 unsigned long long ssbs; /* * Firmware doesn't have to carry out dynamic workaround if the * PE implements architectural Speculation Store Bypass Safe * (SSBS) feature. */ ssbs = (read_id_aa64pfr1_el1() >> ID_AA64PFR1_EL1_SSBS_SHIFT) & ID_AA64PFR1_EL1_SSBS_MASK; /* * If architectural SSBS is available on this PE, no firmware * mitigation via SMCCC_ARCH_WORKAROUND_2 is required. */ if (ssbs != SSBS_UNAVAILABLE) return 1; /* * On a platform where at least one CPU requires * dynamic mitigation but others are either unaffected * or permanently mitigated, report the latter as not * needing dynamic mitigation. */ if (wa_cve_2018_3639_get_disable_ptr() == NULL) return 1; /* * If we get here, this CPU requires dynamic mitigation * so report it as such. */ return 0; #else /* Either the CPUs are unaffected or permanently mitigated */ return SMCCC_ARCH_NOT_REQUIRED; #endif } #endif /* Fallthrough */ default: return SMC_UNK; } } /* * Top-level Arm Architectural Service SMC handler. */ static uintptr_t arm_arch_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) { switch (smc_fid) { case SMCCC_VERSION: SMC_RET1(handle, smccc_version()); case SMCCC_ARCH_FEATURES: SMC_RET1(handle, smccc_arch_features(x1)); #if WORKAROUND_CVE_2017_5715 case SMCCC_ARCH_WORKAROUND_1: /* * The workaround has already been applied on affected PEs * during entry to EL3. On unaffected PEs, this function * has no effect. */ SMC_RET0(handle); #endif #if WORKAROUND_CVE_2018_3639 case SMCCC_ARCH_WORKAROUND_2: /* * The workaround has already been applied on affected PEs * requiring dynamic mitigation during entry to EL3. * On unaffected or statically mitigated PEs, this function * has no effect. */ SMC_RET0(handle); #endif default: WARN("Unimplemented Arm Architecture Service Call: 0x%x \n", smc_fid); SMC_RET1(handle, SMC_UNK); } } /* Register Standard Service Calls as runtime service */ DECLARE_RT_SVC( arm_arch_svc, OEN_ARM_START, OEN_ARM_END, SMC_TYPE_FAST, NULL, arm_arch_svc_smc_handler ); trusted-firmware-a-2.2/services/spd/000077500000000000000000000000001355360272700175225ustar00rootroot00000000000000trusted-firmware-a-2.2/services/spd/opteed/000077500000000000000000000000001355360272700210025ustar00rootroot00000000000000trusted-firmware-a-2.2/services/spd/opteed/opteed.mk000066400000000000000000000007211355360272700226130ustar00rootroot00000000000000# # Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # OPTEED_DIR := services/spd/opteed SPD_INCLUDES := SPD_SOURCES := services/spd/opteed/opteed_common.c \ services/spd/opteed/opteed_helpers.S \ services/spd/opteed/opteed_main.c \ services/spd/opteed/opteed_pm.c NEED_BL32 := yes # required so that optee code can control access to the timer registers NS_TIMER_SWITCH := 1 trusted-firmware-a-2.2/services/spd/opteed/opteed_common.c000066400000000000000000000076101355360272700240020ustar00rootroot00000000000000/* * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "opteed_private.h" /******************************************************************************* * Given a OPTEE entrypoint info pointer, entry point PC, register width, * cpu id & pointer to a context data structure, this function will * initialize OPTEE context and entry point info for OPTEE. ******************************************************************************/ void opteed_init_optee_ep_state(struct entry_point_info *optee_entry_point, uint32_t rw, uint64_t pc, uint64_t pageable_part, uint64_t mem_limit, uint64_t dt_addr, optee_context_t *optee_ctx) { uint32_t ep_attr; /* Passing a NULL context is a critical programming error */ assert(optee_ctx); assert(optee_entry_point); assert(pc); /* Associate this context with the cpu specified */ optee_ctx->mpidr = read_mpidr_el1(); optee_ctx->state = 0; set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_OFF); cm_set_context(&optee_ctx->cpu_ctx, SECURE); /* initialise an entrypoint to set up the CPU context */ ep_attr = SECURE | EP_ST_ENABLE; if (read_sctlr_el3() & SCTLR_EE_BIT) ep_attr |= EP_EE_BIG; SET_PARAM_HEAD(optee_entry_point, PARAM_EP, VERSION_1, ep_attr); optee_entry_point->pc = pc; if (rw == OPTEE_AARCH64) optee_entry_point->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); else optee_entry_point->spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE, DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT); zeromem(&optee_entry_point->args, sizeof(optee_entry_point->args)); optee_entry_point->args.arg0 = pageable_part; optee_entry_point->args.arg1 = mem_limit; optee_entry_point->args.arg2 = dt_addr; } /******************************************************************************* * This function takes an OPTEE context pointer and: * 1. Applies the S-EL1 system register context from optee_ctx->cpu_ctx. * 2. Saves the current C runtime state (callee saved registers) on the stack * frame and saves a reference to this state. * 3. Calls el3_exit() so that the EL3 system and general purpose registers * from the optee_ctx->cpu_ctx are used to enter the OPTEE image. ******************************************************************************/ uint64_t opteed_synchronous_sp_entry(optee_context_t *optee_ctx) { uint64_t rc; assert(optee_ctx != NULL); assert(optee_ctx->c_rt_ctx == 0); /* Apply the Secure EL1 system register context and switch to it */ assert(cm_get_context(SECURE) == &optee_ctx->cpu_ctx); cm_el1_sysregs_context_restore(SECURE); cm_set_next_eret_context(SECURE); rc = opteed_enter_sp(&optee_ctx->c_rt_ctx); #if ENABLE_ASSERTIONS optee_ctx->c_rt_ctx = 0; #endif return rc; } /******************************************************************************* * This function takes an OPTEE context pointer and: * 1. Saves the S-EL1 system register context tp optee_ctx->cpu_ctx. * 2. Restores the current C runtime state (callee saved registers) from the * stack frame using the reference to this state saved in opteed_enter_sp(). * 3. It does not need to save any general purpose or EL3 system register state * as the generic smc entry routine should have saved those. ******************************************************************************/ void opteed_synchronous_sp_exit(optee_context_t *optee_ctx, uint64_t ret) { assert(optee_ctx != NULL); /* Save the Secure EL1 system register context */ assert(cm_get_context(SECURE) == &optee_ctx->cpu_ctx); cm_el1_sysregs_context_save(SECURE); assert(optee_ctx->c_rt_ctx != 0); opteed_exit_sp(optee_ctx->c_rt_ctx, ret); /* Should never reach here */ assert(0); } trusted-firmware-a-2.2/services/spd/opteed/opteed_helpers.S000066400000000000000000000053171355360272700241360ustar00rootroot00000000000000/* * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "opteed_private.h" .global opteed_enter_sp /* --------------------------------------------- * This function is called with SP_EL0 as stack. * Here we stash our EL3 callee-saved registers * on to the stack as a part of saving the C * runtime and enter the secure payload. * 'x0' contains a pointer to the memory where * the address of the C runtime context is to be * saved. * --------------------------------------------- */ func opteed_enter_sp /* Make space for the registers that we're going to save */ mov x3, sp str x3, [x0, #0] sub sp, sp, #OPTEED_C_RT_CTX_SIZE /* Save callee-saved registers on to the stack */ stp x19, x20, [sp, #OPTEED_C_RT_CTX_X19] stp x21, x22, [sp, #OPTEED_C_RT_CTX_X21] stp x23, x24, [sp, #OPTEED_C_RT_CTX_X23] stp x25, x26, [sp, #OPTEED_C_RT_CTX_X25] stp x27, x28, [sp, #OPTEED_C_RT_CTX_X27] stp x29, x30, [sp, #OPTEED_C_RT_CTX_X29] /* --------------------------------------------- * Everything is setup now. el3_exit() will * use the secure context to restore to the * general purpose and EL3 system registers to * ERET into OPTEE. * --------------------------------------------- */ b el3_exit endfunc opteed_enter_sp /* --------------------------------------------- * This function is called 'x0' pointing to a C * runtime context saved in opteed_enter_sp(). It * restores the saved registers and jumps to * that runtime with 'x0' as the new sp. This * destroys the C runtime context that had been * built on the stack below the saved context by * the caller. Later the second parameter 'x1' * is passed as return value to the caller * --------------------------------------------- */ .global opteed_exit_sp func opteed_exit_sp /* Restore the previous stack */ mov sp, x0 /* Restore callee-saved registers on to the stack */ ldp x19, x20, [x0, #(OPTEED_C_RT_CTX_X19 - OPTEED_C_RT_CTX_SIZE)] ldp x21, x22, [x0, #(OPTEED_C_RT_CTX_X21 - OPTEED_C_RT_CTX_SIZE)] ldp x23, x24, [x0, #(OPTEED_C_RT_CTX_X23 - OPTEED_C_RT_CTX_SIZE)] ldp x25, x26, [x0, #(OPTEED_C_RT_CTX_X25 - OPTEED_C_RT_CTX_SIZE)] ldp x27, x28, [x0, #(OPTEED_C_RT_CTX_X27 - OPTEED_C_RT_CTX_SIZE)] ldp x29, x30, [x0, #(OPTEED_C_RT_CTX_X29 - OPTEED_C_RT_CTX_SIZE)] /* --------------------------------------------- * This should take us back to the instruction * after the call to the last opteed_enter_sp(). * Place the second parameter to x0 so that the * caller will see it as a return value from the * original entry call * --------------------------------------------- */ mov x0, x1 ret endfunc opteed_exit_sp trusted-firmware-a-2.2/services/spd/opteed/opteed_main.c000066400000000000000000000316731355360272700234440ustar00rootroot00000000000000/* * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /******************************************************************************* * This is the Secure Payload Dispatcher (SPD). The dispatcher is meant to be a * plug-in component to the Secure Monitor, registered as a runtime service. The * SPD is expected to be a functional extension of the Secure Payload (SP) that * executes in Secure EL1. The Secure Monitor will delegate all SMCs targeting * the Trusted OS/Applications range to the dispatcher. The SPD will either * handle the request locally or delegate it to the Secure Payload. It is also * responsible for initialising and maintaining communication with the SP. ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include "opteed_private.h" #include "teesmc_opteed.h" #include "teesmc_opteed_macros.h" /******************************************************************************* * Address of the entrypoint vector table in OPTEE. It is * initialised once on the primary core after a cold boot. ******************************************************************************/ struct optee_vectors *optee_vector_table; /******************************************************************************* * Array to keep track of per-cpu OPTEE state ******************************************************************************/ optee_context_t opteed_sp_context[OPTEED_CORE_COUNT]; uint32_t opteed_rw; static int32_t opteed_init(void); /******************************************************************************* * This function is the handler registered for S-EL1 interrupts by the * OPTEED. It validates the interrupt and upon success arranges entry into * the OPTEE at 'optee_fiq_entry()' for handling the interrupt. ******************************************************************************/ static uint64_t opteed_sel1_interrupt_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { uint32_t linear_id; optee_context_t *optee_ctx; /* Check the security state when the exception was generated */ assert(get_interrupt_src_ss(flags) == NON_SECURE); /* Sanity check the pointer to this cpu's context */ assert(handle == cm_get_context(NON_SECURE)); /* Save the non-secure context before entering the OPTEE */ cm_el1_sysregs_context_save(NON_SECURE); /* Get a reference to this cpu's OPTEE context */ linear_id = plat_my_core_pos(); optee_ctx = &opteed_sp_context[linear_id]; assert(&optee_ctx->cpu_ctx == cm_get_context(SECURE)); cm_set_elr_el3(SECURE, (uint64_t)&optee_vector_table->fiq_entry); cm_el1_sysregs_context_restore(SECURE); cm_set_next_eret_context(SECURE); /* * Tell the OPTEE that it has to handle an FIQ (synchronously). * Also the instruction in normal world where the interrupt was * generated is passed for debugging purposes. It is safe to * retrieve this address from ELR_EL3 as the secure context will * not take effect until el3_exit(). */ SMC_RET1(&optee_ctx->cpu_ctx, read_elr_el3()); } /******************************************************************************* * OPTEE Dispatcher setup. The OPTEED finds out the OPTEE entrypoint and type * (aarch32/aarch64) if not already known and initialises the context for entry * into OPTEE for its initialization. ******************************************************************************/ static int32_t opteed_setup(void) { entry_point_info_t *optee_ep_info; uint32_t linear_id; uint64_t opteed_pageable_part; uint64_t opteed_mem_limit; uint64_t dt_addr; linear_id = plat_my_core_pos(); /* * Get information about the Secure Payload (BL32) image. Its * absence is a critical failure. TODO: Add support to * conditionally include the SPD service */ optee_ep_info = bl31_plat_get_next_image_ep_info(SECURE); if (!optee_ep_info) { WARN("No OPTEE provided by BL2 boot loader, Booting device" " without OPTEE initialization. SMC`s destined for OPTEE" " will return SMC_UNK\n"); return 1; } /* * If there's no valid entry point for SP, we return a non-zero value * signalling failure initializing the service. We bail out without * registering any handlers */ if (!optee_ep_info->pc) return 1; opteed_rw = optee_ep_info->args.arg0; opteed_pageable_part = optee_ep_info->args.arg1; opteed_mem_limit = optee_ep_info->args.arg2; dt_addr = optee_ep_info->args.arg3; opteed_init_optee_ep_state(optee_ep_info, opteed_rw, optee_ep_info->pc, opteed_pageable_part, opteed_mem_limit, dt_addr, &opteed_sp_context[linear_id]); /* * All OPTEED initialization done. Now register our init function with * BL31 for deferred invocation */ bl31_register_bl32_init(&opteed_init); return 0; } /******************************************************************************* * This function passes control to the OPTEE image (BL32) for the first time * on the primary cpu after a cold boot. It assumes that a valid secure * context has already been created by opteed_setup() which can be directly * used. It also assumes that a valid non-secure context has been * initialised by PSCI so it does not need to save and restore any * non-secure state. This function performs a synchronous entry into * OPTEE. OPTEE passes control back to this routine through a SMC. ******************************************************************************/ static int32_t opteed_init(void) { uint32_t linear_id = plat_my_core_pos(); optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; entry_point_info_t *optee_entry_point; uint64_t rc; /* * Get information about the OPTEE (BL32) image. Its * absence is a critical failure. */ optee_entry_point = bl31_plat_get_next_image_ep_info(SECURE); assert(optee_entry_point); cm_init_my_context(optee_entry_point); /* * Arrange for an entry into OPTEE. It will be returned via * OPTEE_ENTRY_DONE case */ rc = opteed_synchronous_sp_entry(optee_ctx); assert(rc != 0); return rc; } /******************************************************************************* * This function is responsible for handling all SMCs in the Trusted OS/App * range from the non-secure state as defined in the SMC Calling Convention * Document. It is also responsible for communicating with the Secure * payload to delegate work and return results back to the non-secure * state. Lastly it will also return any information that OPTEE needs to do * the work assigned to it. ******************************************************************************/ static uintptr_t opteed_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) { cpu_context_t *ns_cpu_context; uint32_t linear_id = plat_my_core_pos(); optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; uint64_t rc; /* * Determine which security state this SMC originated from */ if (is_caller_non_secure(flags)) { /* * This is a fresh request from the non-secure client. * The parameters are in x1 and x2. Figure out which * registers need to be preserved, save the non-secure * state and send the request to the secure payload. */ assert(handle == cm_get_context(NON_SECURE)); cm_el1_sysregs_context_save(NON_SECURE); /* * We are done stashing the non-secure context. Ask the * OPTEE to do the work now. */ /* * Verify if there is a valid context to use, copy the * operation type and parameters to the secure context * and jump to the fast smc entry point in the secure * payload. Entry into S-EL1 will take place upon exit * from this function. */ assert(&optee_ctx->cpu_ctx == cm_get_context(SECURE)); /* Set appropriate entry for SMC. * We expect OPTEE to manage the PSTATE.I and PSTATE.F * flags as appropriate. */ if (GET_SMC_TYPE(smc_fid) == SMC_TYPE_FAST) { cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->fast_smc_entry); } else { cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->yield_smc_entry); } cm_el1_sysregs_context_restore(SECURE); cm_set_next_eret_context(SECURE); write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx), CTX_GPREG_X4, read_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X4)); write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx), CTX_GPREG_X5, read_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X5)); write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx), CTX_GPREG_X6, read_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X6)); /* Propagate hypervisor client ID */ write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx), CTX_GPREG_X7, read_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X7)); SMC_RET4(&optee_ctx->cpu_ctx, smc_fid, x1, x2, x3); } /* * Returning from OPTEE */ switch (smc_fid) { /* * OPTEE has finished initialising itself after a cold boot */ case TEESMC_OPTEED_RETURN_ENTRY_DONE: /* * Stash the OPTEE entry points information. This is done * only once on the primary cpu */ assert(optee_vector_table == NULL); optee_vector_table = (optee_vectors_t *) x1; if (optee_vector_table) { set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON); /* * OPTEE has been successfully initialized. * Register power management hooks with PSCI */ psci_register_spd_pm_hook(&opteed_pm); /* * Register an interrupt handler for S-EL1 interrupts * when generated during code executing in the * non-secure state. */ flags = 0; set_interrupt_rm_flag(flags, NON_SECURE); rc = register_interrupt_type_handler(INTR_TYPE_S_EL1, opteed_sel1_interrupt_handler, flags); if (rc) panic(); } /* * OPTEE reports completion. The OPTEED must have initiated * the original request through a synchronous entry into * OPTEE. Jump back to the original C runtime context. */ opteed_synchronous_sp_exit(optee_ctx, x1); break; /* * These function IDs is used only by OP-TEE to indicate it has * finished: * 1. turning itself on in response to an earlier psci * cpu_on request * 2. resuming itself after an earlier psci cpu_suspend * request. */ case TEESMC_OPTEED_RETURN_ON_DONE: case TEESMC_OPTEED_RETURN_RESUME_DONE: /* * These function IDs is used only by the SP to indicate it has * finished: * 1. suspending itself after an earlier psci cpu_suspend * request. * 2. turning itself off in response to an earlier psci * cpu_off request. */ case TEESMC_OPTEED_RETURN_OFF_DONE: case TEESMC_OPTEED_RETURN_SUSPEND_DONE: case TEESMC_OPTEED_RETURN_SYSTEM_OFF_DONE: case TEESMC_OPTEED_RETURN_SYSTEM_RESET_DONE: /* * OPTEE reports completion. The OPTEED must have initiated the * original request through a synchronous entry into OPTEE. * Jump back to the original C runtime context, and pass x1 as * return value to the caller */ opteed_synchronous_sp_exit(optee_ctx, x1); break; /* * OPTEE is returning from a call or being preempted from a call, in * either case execution should resume in the normal world. */ case TEESMC_OPTEED_RETURN_CALL_DONE: /* * This is the result from the secure client of an * earlier request. The results are in x0-x3. Copy it * into the non-secure context, save the secure state * and return to the non-secure state. */ assert(handle == cm_get_context(SECURE)); cm_el1_sysregs_context_save(SECURE); /* Get a reference to the non-secure context */ ns_cpu_context = cm_get_context(NON_SECURE); assert(ns_cpu_context); /* Restore non-secure state */ cm_el1_sysregs_context_restore(NON_SECURE); cm_set_next_eret_context(NON_SECURE); SMC_RET4(ns_cpu_context, x1, x2, x3, x4); /* * OPTEE has finished handling a S-EL1 FIQ interrupt. Execution * should resume in the normal world. */ case TEESMC_OPTEED_RETURN_FIQ_DONE: /* Get a reference to the non-secure context */ ns_cpu_context = cm_get_context(NON_SECURE); assert(ns_cpu_context); /* * Restore non-secure state. There is no need to save the * secure system register context since OPTEE was supposed * to preserve it during S-EL1 interrupt handling. */ cm_el1_sysregs_context_restore(NON_SECURE); cm_set_next_eret_context(NON_SECURE); SMC_RET0((uint64_t) ns_cpu_context); default: panic(); } } /* Define an OPTEED runtime service descriptor for fast SMC calls */ DECLARE_RT_SVC( opteed_fast, OEN_TOS_START, OEN_TOS_END, SMC_TYPE_FAST, opteed_setup, opteed_smc_handler ); /* Define an OPTEED runtime service descriptor for yielding SMC calls */ DECLARE_RT_SVC( opteed_std, OEN_TOS_START, OEN_TOS_END, SMC_TYPE_YIELD, NULL, opteed_smc_handler ); trusted-firmware-a-2.2/services/spd/opteed/opteed_pm.c000066400000000000000000000174331355360272700231320ustar00rootroot00000000000000/* * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "opteed_private.h" /******************************************************************************* * The target cpu is being turned on. Allow the OPTEED/OPTEE to perform any * actions needed. Nothing at the moment. ******************************************************************************/ static void opteed_cpu_on_handler(u_register_t target_cpu) { } /******************************************************************************* * This cpu is being turned off. Allow the OPTEED/OPTEE to perform any actions * needed ******************************************************************************/ static int32_t opteed_cpu_off_handler(u_register_t unused) { int32_t rc = 0; uint32_t linear_id = plat_my_core_pos(); optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; assert(optee_vector_table); assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); /* Program the entry point and enter OPTEE */ cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_off_entry); rc = opteed_synchronous_sp_entry(optee_ctx); /* * Read the response from OPTEE. A non-zero return means that * something went wrong while communicating with OPTEE. */ if (rc != 0) panic(); /* * Reset OPTEE's context for a fresh start when this cpu is turned on * subsequently. */ set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_OFF); return 0; } /******************************************************************************* * This cpu is being suspended. S-EL1 state must have been saved in the * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE. ******************************************************************************/ static void opteed_cpu_suspend_handler(u_register_t max_off_pwrlvl) { int32_t rc = 0; uint32_t linear_id = plat_my_core_pos(); optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; assert(optee_vector_table); assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx), CTX_GPREG_X0, max_off_pwrlvl); /* Program the entry point and enter OPTEE */ cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_suspend_entry); rc = opteed_synchronous_sp_entry(optee_ctx); /* * Read the response from OPTEE. A non-zero return means that * something went wrong while communicating with OPTEE. */ if (rc != 0) panic(); /* Update its context to reflect the state OPTEE is in */ set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_SUSPEND); } /******************************************************************************* * This cpu has been turned on. Enter OPTEE to initialise S-EL1 and other bits * before passing control back to the Secure Monitor. Entry in S-El1 is done * after initialising minimal architectural state that guarantees safe * execution. ******************************************************************************/ static void opteed_cpu_on_finish_handler(u_register_t unused) { int32_t rc = 0; uint32_t linear_id = plat_my_core_pos(); optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; entry_point_info_t optee_on_entrypoint; assert(optee_vector_table); assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_OFF); opteed_init_optee_ep_state(&optee_on_entrypoint, opteed_rw, (uint64_t)&optee_vector_table->cpu_on_entry, 0, 0, 0, optee_ctx); /* Initialise this cpu's secure context */ cm_init_my_context(&optee_on_entrypoint); /* Enter OPTEE */ rc = opteed_synchronous_sp_entry(optee_ctx); /* * Read the response from OPTEE. A non-zero return means that * something went wrong while communicating with OPTEE. */ if (rc != 0) panic(); /* Update its context to reflect the state OPTEE is in */ set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON); } /******************************************************************************* * This cpu has resumed from suspend. The OPTEED saved the OPTEE context when it * completed the preceding suspend call. Use that context to program an entry * into OPTEE to allow it to do any remaining book keeping ******************************************************************************/ static void opteed_cpu_suspend_finish_handler(u_register_t max_off_pwrlvl) { int32_t rc = 0; uint32_t linear_id = plat_my_core_pos(); optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; assert(optee_vector_table); assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_SUSPEND); /* Program the entry point, max_off_pwrlvl and enter the SP */ write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx), CTX_GPREG_X0, max_off_pwrlvl); cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->cpu_resume_entry); rc = opteed_synchronous_sp_entry(optee_ctx); /* * Read the response from OPTEE. A non-zero return means that * something went wrong while communicating with OPTEE. */ if (rc != 0) panic(); /* Update its context to reflect the state OPTEE is in */ set_optee_pstate(optee_ctx->state, OPTEE_PSTATE_ON); } /******************************************************************************* * Return the type of OPTEE the OPTEED is dealing with. Report the current * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE. ******************************************************************************/ static int32_t opteed_cpu_migrate_info(u_register_t *resident_cpu) { return OPTEE_MIGRATE_INFO; } /******************************************************************************* * System is about to be switched off. Allow the OPTEED/OPTEE to perform * any actions needed. ******************************************************************************/ static void opteed_system_off(void) { uint32_t linear_id = plat_my_core_pos(); optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; assert(optee_vector_table); assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); /* Program the entry point */ cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->system_off_entry); /* Enter OPTEE. We do not care about the return value because we * must continue the shutdown anyway */ opteed_synchronous_sp_entry(optee_ctx); } /******************************************************************************* * System is about to be reset. Allow the OPTEED/OPTEE to perform * any actions needed. ******************************************************************************/ static void opteed_system_reset(void) { uint32_t linear_id = plat_my_core_pos(); optee_context_t *optee_ctx = &opteed_sp_context[linear_id]; assert(optee_vector_table); assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_ON); /* Program the entry point */ cm_set_elr_el3(SECURE, (uint64_t) &optee_vector_table->system_reset_entry); /* Enter OPTEE. We do not care about the return value because we * must continue the reset anyway */ opteed_synchronous_sp_entry(optee_ctx); } /******************************************************************************* * Structure populated by the OPTEE Dispatcher to be given a chance to * perform any OPTEE bookkeeping before PSCI executes a power mgmt. * operation. ******************************************************************************/ const spd_pm_ops_t opteed_pm = { .svc_on = opteed_cpu_on_handler, .svc_off = opteed_cpu_off_handler, .svc_suspend = opteed_cpu_suspend_handler, .svc_on_finish = opteed_cpu_on_finish_handler, .svc_suspend_finish = opteed_cpu_suspend_finish_handler, .svc_migrate = NULL, .svc_migrate_info = opteed_cpu_migrate_info, .svc_system_off = opteed_system_off, .svc_system_reset = opteed_system_reset, }; trusted-firmware-a-2.2/services/spd/opteed/opteed_private.h000066400000000000000000000140551355360272700241720ustar00rootroot00000000000000/* * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef OPTEED_PRIVATE_H #define OPTEED_PRIVATE_H #include #include #include #include #include /******************************************************************************* * OPTEE PM state information e.g. OPTEE is suspended, uninitialised etc * and macros to access the state information in the per-cpu 'state' flags ******************************************************************************/ #define OPTEE_PSTATE_OFF 0 #define OPTEE_PSTATE_ON 1 #define OPTEE_PSTATE_SUSPEND 2 #define OPTEE_PSTATE_SHIFT 0 #define OPTEE_PSTATE_MASK 0x3 #define get_optee_pstate(state) ((state >> OPTEE_PSTATE_SHIFT) & \ OPTEE_PSTATE_MASK) #define clr_optee_pstate(state) (state &= ~(OPTEE_PSTATE_MASK \ << OPTEE_PSTATE_SHIFT)) #define set_optee_pstate(st, pst) do { \ clr_optee_pstate(st); \ st |= (pst & OPTEE_PSTATE_MASK) << \ OPTEE_PSTATE_SHIFT; \ } while (0) /******************************************************************************* * OPTEE execution state information i.e. aarch32 or aarch64 ******************************************************************************/ #define OPTEE_AARCH32 MODE_RW_32 #define OPTEE_AARCH64 MODE_RW_64 /******************************************************************************* * The OPTEED should know the type of OPTEE ******************************************************************************/ #define OPTEE_TYPE_UP PSCI_TOS_NOT_UP_MIG_CAP #define OPTEE_TYPE_UPM PSCI_TOS_UP_MIG_CAP #define OPTEE_TYPE_MP PSCI_TOS_NOT_PRESENT_MP /******************************************************************************* * OPTEE migrate type information as known to the OPTEED. We assume that * the OPTEED is dealing with an MP Secure Payload. ******************************************************************************/ #define OPTEE_MIGRATE_INFO OPTEE_TYPE_MP /******************************************************************************* * Number of cpus that the present on this platform. TODO: Rely on a topology * tree to determine this in the future to avoid assumptions about mpidr * allocation ******************************************************************************/ #define OPTEED_CORE_COUNT PLATFORM_CORE_COUNT /******************************************************************************* * Constants that allow assembler code to preserve callee-saved registers of the * C runtime context while performing a security state switch. ******************************************************************************/ #define OPTEED_C_RT_CTX_X19 0x0 #define OPTEED_C_RT_CTX_X20 0x8 #define OPTEED_C_RT_CTX_X21 0x10 #define OPTEED_C_RT_CTX_X22 0x18 #define OPTEED_C_RT_CTX_X23 0x20 #define OPTEED_C_RT_CTX_X24 0x28 #define OPTEED_C_RT_CTX_X25 0x30 #define OPTEED_C_RT_CTX_X26 0x38 #define OPTEED_C_RT_CTX_X27 0x40 #define OPTEED_C_RT_CTX_X28 0x48 #define OPTEED_C_RT_CTX_X29 0x50 #define OPTEED_C_RT_CTX_X30 0x58 #define OPTEED_C_RT_CTX_SIZE 0x60 #define OPTEED_C_RT_CTX_ENTRIES (OPTEED_C_RT_CTX_SIZE >> DWORD_SHIFT) #ifndef __ASSEMBLER__ #include #include typedef uint32_t optee_vector_isn_t; typedef struct optee_vectors { optee_vector_isn_t yield_smc_entry; optee_vector_isn_t fast_smc_entry; optee_vector_isn_t cpu_on_entry; optee_vector_isn_t cpu_off_entry; optee_vector_isn_t cpu_resume_entry; optee_vector_isn_t cpu_suspend_entry; optee_vector_isn_t fiq_entry; optee_vector_isn_t system_off_entry; optee_vector_isn_t system_reset_entry; } optee_vectors_t; /* * The number of arguments to save during a SMC call for OPTEE. * Currently only x1 and x2 are used by OPTEE. */ #define OPTEE_NUM_ARGS 0x2 /* AArch64 callee saved general purpose register context structure. */ DEFINE_REG_STRUCT(c_rt_regs, OPTEED_C_RT_CTX_ENTRIES); /* * Compile time assertion to ensure that both the compiler and linker * have the same double word aligned view of the size of the C runtime * register context. */ CASSERT(OPTEED_C_RT_CTX_SIZE == sizeof(c_rt_regs_t), \ assert_spd_c_rt_regs_size_mismatch); /******************************************************************************* * Structure which helps the OPTEED to maintain the per-cpu state of OPTEE. * 'state' - collection of flags to track OPTEE state e.g. on/off * 'mpidr' - mpidr to associate a context with a cpu * 'c_rt_ctx' - stack address to restore C runtime context from after * returning from a synchronous entry into OPTEE. * 'cpu_ctx' - space to maintain OPTEE architectural state ******************************************************************************/ typedef struct optee_context { uint32_t state; uint64_t mpidr; uint64_t c_rt_ctx; cpu_context_t cpu_ctx; } optee_context_t; /* OPTEED power management handlers */ extern const spd_pm_ops_t opteed_pm; /******************************************************************************* * Forward declarations ******************************************************************************/ struct optee_vectors; /******************************************************************************* * Function & Data prototypes ******************************************************************************/ uint64_t opteed_enter_sp(uint64_t *c_rt_ctx); void __dead2 opteed_exit_sp(uint64_t c_rt_ctx, uint64_t ret); uint64_t opteed_synchronous_sp_entry(optee_context_t *optee_ctx); void __dead2 opteed_synchronous_sp_exit(optee_context_t *optee_ctx, uint64_t ret); void opteed_init_optee_ep_state(struct entry_point_info *optee_entry_point, uint32_t rw, uint64_t pc, uint64_t pageable_part, uint64_t mem_limit, uint64_t dt_addr, optee_context_t *optee_ctx); extern optee_context_t opteed_sp_context[OPTEED_CORE_COUNT]; extern uint32_t opteed_rw; extern struct optee_vectors *optee_vector_table; #endif /*__ASSEMBLER__*/ #endif /* OPTEED_PRIVATE_H */ trusted-firmware-a-2.2/services/spd/opteed/teesmc_opteed.h000066400000000000000000000072521355360272700240010ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* Copyright (c) 2014, Linaro Limited. All rights reserved. */ #ifndef TEESMC_OPTEED_H #define TEESMC_OPTEED_H /* * This file specifies SMC function IDs used when returning from TEE to the * secure monitor. * * All SMC Function IDs indicates SMC32 Calling Convention but will carry * full 64 bit values in the argument registers if invoked from Aarch64 * mode. This violates the SMC Calling Convention, but since this * convention only coveres API towards Normal World it's something that * only concerns the OP-TEE Dispatcher in Trusted Firmware-A and OP-TEE * OS at Secure EL1. */ /* * Issued when returning from initial entry. * * Register usage: * r0/x0 SMC Function ID, TEESMC_OPTEED_RETURN_ENTRY_DONE * r1/x1 Pointer to entry vector */ #define TEESMC_OPTEED_FUNCID_RETURN_ENTRY_DONE 0 #define TEESMC_OPTEED_RETURN_ENTRY_DONE \ TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_ENTRY_DONE) /* * Issued when returning from "cpu_on" vector * * Register usage: * r0/x0 SMC Function ID, TEESMC_OPTEED_RETURN_ON_DONE * r1/x1 0 on success and anything else to indicate error condition */ #define TEESMC_OPTEED_FUNCID_RETURN_ON_DONE 1 #define TEESMC_OPTEED_RETURN_ON_DONE \ TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_ON_DONE) /* * Issued when returning from "cpu_off" vector * * Register usage: * r0/x0 SMC Function ID, TEESMC_OPTEED_RETURN_OFF_DONE * r1/x1 0 on success and anything else to indicate error condition */ #define TEESMC_OPTEED_FUNCID_RETURN_OFF_DONE 2 #define TEESMC_OPTEED_RETURN_OFF_DONE \ TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_OFF_DONE) /* * Issued when returning from "cpu_suspend" vector * * Register usage: * r0/x0 SMC Function ID, TEESMC_OPTEED_RETURN_SUSPEND_DONE * r1/x1 0 on success and anything else to indicate error condition */ #define TEESMC_OPTEED_FUNCID_RETURN_SUSPEND_DONE 3 #define TEESMC_OPTEED_RETURN_SUSPEND_DONE \ TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_SUSPEND_DONE) /* * Issued when returning from "cpu_resume" vector * * Register usage: * r0/x0 SMC Function ID, TEESMC_OPTEED_RETURN_RESUME_DONE * r1/x1 0 on success and anything else to indicate error condition */ #define TEESMC_OPTEED_FUNCID_RETURN_RESUME_DONE 4 #define TEESMC_OPTEED_RETURN_RESUME_DONE \ TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_RESUME_DONE) /* * Issued when returning from "std_smc" or "fast_smc" vector * * Register usage: * r0/x0 SMC Function ID, TEESMC_OPTEED_RETURN_CALL_DONE * r1-4/x1-4 Return value 0-3 which will passed to normal world in * r0-3/x0-3 */ #define TEESMC_OPTEED_FUNCID_RETURN_CALL_DONE 5 #define TEESMC_OPTEED_RETURN_CALL_DONE \ TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_CALL_DONE) /* * Issued when returning from "fiq" vector * * Register usage: * r0/x0 SMC Function ID, TEESMC_OPTEED_RETURN_FIQ_DONE */ #define TEESMC_OPTEED_FUNCID_RETURN_FIQ_DONE 6 #define TEESMC_OPTEED_RETURN_FIQ_DONE \ TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_FIQ_DONE) /* * Issued when returning from "system_off" vector * * Register usage: * r0/x0 SMC Function ID, TEESMC_OPTEED_RETURN_SYSTEM_OFF_DONE */ #define TEESMC_OPTEED_FUNCID_RETURN_SYSTEM_OFF_DONE 7 #define TEESMC_OPTEED_RETURN_SYSTEM_OFF_DONE \ TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_SYSTEM_OFF_DONE) /* * Issued when returning from "system_reset" vector * * Register usage: * r0/x0 SMC Function ID, TEESMC_OPTEED_RETURN_SYSTEM_RESET_DONE */ #define TEESMC_OPTEED_FUNCID_RETURN_SYSTEM_RESET_DONE 8 #define TEESMC_OPTEED_RETURN_SYSTEM_RESET_DONE \ TEESMC_OPTEED_RV(TEESMC_OPTEED_FUNCID_RETURN_SYSTEM_RESET_DONE) #endif /*TEESMC_OPTEED_H*/ trusted-firmware-a-2.2/services/spd/opteed/teesmc_opteed_macros.h000066400000000000000000000006731355360272700253450ustar00rootroot00000000000000/* * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TEESMC_OPTEED_MACROS_H #define TEESMC_OPTEED_MACROS_H #include #define TEESMC_OPTEED_RV(func_num) \ ((SMC_TYPE_FAST << FUNCID_TYPE_SHIFT) | \ ((SMC_32) << FUNCID_CC_SHIFT) | \ (62 << FUNCID_OEN_SHIFT) | \ ((func_num) & FUNCID_NUM_MASK)) #endif /* TEESMC_OPTEED_MACROS_H */ trusted-firmware-a-2.2/services/spd/tlkd/000077500000000000000000000000001355360272700204605ustar00rootroot00000000000000trusted-firmware-a-2.2/services/spd/tlkd/tlkd.mk000066400000000000000000000005441355360272700217520ustar00rootroot00000000000000# # Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ifeq (${ERROR_DEPRECATED},0) SPD_INCLUDES := -Iinclude/bl32/payloads endif SPD_SOURCES := services/spd/tlkd/tlkd_common.c \ services/spd/tlkd/tlkd_helpers.S \ services/spd/tlkd/tlkd_main.c \ services/spd/tlkd/tlkd_pm.c trusted-firmware-a-2.2/services/spd/tlkd/tlkd_common.c000066400000000000000000000113501355360272700231320ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "tlkd_private.h" #define AT_MASK 3 /******************************************************************************* * This function helps the SP to translate NS/S virtual addresses. ******************************************************************************/ uint64_t tlkd_va_translate(uintptr_t va, int type) { uint64_t pa; if (type & TLK_TRANSLATE_NS_VADDR) { /* save secure context */ cm_el1_sysregs_context_save(SECURE); /* restore non-secure context */ cm_el1_sysregs_context_restore(NON_SECURE); /* switch NS bit to start using 64-bit, non-secure mappings */ write_scr(cm_get_scr_el3(NON_SECURE)); isb(); } int at = type & AT_MASK; switch (at) { case 0: ats12e1r(va); break; case 1: ats12e1w(va); break; case 2: ats12e0r(va); break; case 3: ats12e0w(va); break; default: assert(0); /* Unreachable */ break; } /* get the (NS/S) physical address */ isb(); pa = read_par_el1(); /* Restore secure state */ if (type & TLK_TRANSLATE_NS_VADDR) { /* restore secure context */ cm_el1_sysregs_context_restore(SECURE); /* switch NS bit to start using 32-bit, secure mappings */ write_scr(cm_get_scr_el3(SECURE)); isb(); } return pa; } /******************************************************************************* * Given a secure payload entrypoint, register width, cpu id & pointer to a * context data structure, this function will create a secure context ready for * programming an entry into the secure payload. ******************************************************************************/ void tlkd_init_tlk_ep_state(struct entry_point_info *tlk_entry_point, uint32_t rw, uint64_t pc, tlk_context_t *tlk_ctx) { uint32_t ep_attr, spsr; /* Passing a NULL context is a critical programming error */ assert(tlk_ctx); assert(tlk_entry_point); assert(pc); /* Associate this context with the cpu specified */ tlk_ctx->mpidr = read_mpidr_el1(); clr_yield_smc_active_flag(tlk_ctx->state); cm_set_context(&tlk_ctx->cpu_ctx, SECURE); if (rw == SP_AARCH64) spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); else spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM, read_sctlr_el3() & SCTLR_EE_BIT, DISABLE_ALL_EXCEPTIONS); /* initialise an entrypoint to set up the CPU context */ ep_attr = SECURE | EP_ST_ENABLE; if (read_sctlr_el3() & SCTLR_EE_BIT) ep_attr |= EP_EE_BIG; SET_PARAM_HEAD(tlk_entry_point, PARAM_EP, VERSION_1, ep_attr); tlk_entry_point->pc = pc; tlk_entry_point->spsr = spsr; } /******************************************************************************* * This function takes a TLK context pointer and: * 1. Applies the S-EL1 system register context from tlk_ctx->cpu_ctx. * 2. Saves the current C runtime state (callee saved registers) on the stack * frame and saves a reference to this state. * 3. Calls el3_exit() so that the EL3 system and general purpose registers * from the tlk_ctx->cpu_ctx are used to enter the secure payload image. ******************************************************************************/ uint64_t tlkd_synchronous_sp_entry(tlk_context_t *tlk_ctx) { uint64_t rc; /* Passing a NULL context is a critical programming error */ assert(tlk_ctx); /* Apply the Secure EL1 system register context and switch to it */ assert(cm_get_context(SECURE) == &tlk_ctx->cpu_ctx); cm_el1_sysregs_context_restore(SECURE); cm_set_next_eret_context(SECURE); rc = tlkd_enter_sp(&tlk_ctx->c_rt_ctx); #if ENABLE_ASSERTIONS tlk_ctx->c_rt_ctx = 0; #endif return rc; } /******************************************************************************* * This function takes a TLK context pointer and: * 1. Saves the S-EL1 system register context to tlk_ctx->cpu_ctx. * 2. Restores the current C runtime state (callee saved registers) from the * stack frame using reference to this state saved in tlkd_enter_sp(). * 3. It does not need to save any general purpose or EL3 system register state * as the generic smc entry routine should have saved those. ******************************************************************************/ void tlkd_synchronous_sp_exit(tlk_context_t *tlk_ctx, uint64_t ret) { /* Passing a NULL context is a critical programming error */ assert(tlk_ctx); /* Save the Secure EL1 system register context */ assert(cm_get_context(SECURE) == &tlk_ctx->cpu_ctx); cm_el1_sysregs_context_save(SECURE); assert(tlk_ctx->c_rt_ctx != 0); tlkd_exit_sp(tlk_ctx->c_rt_ctx, ret); /* Should never reach here */ assert(0); } trusted-firmware-a-2.2/services/spd/tlkd/tlkd_helpers.S000066400000000000000000000052561355360272700232740ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "tlkd_private.h" .global tlkd_enter_sp .global tlkd_exit_sp /* --------------------------------------------- * This function is called with SP_EL0 as stack. * Here we stash our EL3 callee-saved registers * on to the stack as a part of saving the C * runtime and enter the secure payload. * 'x0' contains a pointer to the memory where * the address of the C runtime context is to be * saved. * --------------------------------------------- */ func tlkd_enter_sp /* Make space for the registers that we're going to save */ mov x3, sp str x3, [x0, #0] sub sp, sp, #TLKD_C_RT_CTX_SIZE /* Save callee-saved registers on to the stack */ stp x19, x20, [sp, #TLKD_C_RT_CTX_X19] stp x21, x22, [sp, #TLKD_C_RT_CTX_X21] stp x23, x24, [sp, #TLKD_C_RT_CTX_X23] stp x25, x26, [sp, #TLKD_C_RT_CTX_X25] stp x27, x28, [sp, #TLKD_C_RT_CTX_X27] stp x29, x30, [sp, #TLKD_C_RT_CTX_X29] /* ---------------------------------------------- * Everything is setup now. el3_exit() will * use the secure context to restore to the * general purpose and EL3 system registers to * ERET into the secure payload. * ---------------------------------------------- */ b el3_exit endfunc tlkd_enter_sp /* ---------------------------------------------- * This function is called with 'x0' pointing to * a C runtime context saved in tlkd_enter_sp(). * It restores the saved registers and jumps to * that runtime with 'x0' as the new sp. This * destroys the C runtime context that had been * built on the stack below the saved context by * the caller. Later the second parameter 'x1' * is passed as return value to the caller * ---------------------------------------------- */ func tlkd_exit_sp /* Restore the previous stack */ mov sp, x0 /* Restore callee-saved registers on to the stack */ ldp x19, x20, [x0, #(TLKD_C_RT_CTX_X19 - TLKD_C_RT_CTX_SIZE)] ldp x21, x22, [x0, #(TLKD_C_RT_CTX_X21 - TLKD_C_RT_CTX_SIZE)] ldp x23, x24, [x0, #(TLKD_C_RT_CTX_X23 - TLKD_C_RT_CTX_SIZE)] ldp x25, x26, [x0, #(TLKD_C_RT_CTX_X25 - TLKD_C_RT_CTX_SIZE)] ldp x27, x28, [x0, #(TLKD_C_RT_CTX_X27 - TLKD_C_RT_CTX_SIZE)] ldp x29, x30, [x0, #(TLKD_C_RT_CTX_X29 - TLKD_C_RT_CTX_SIZE)] /* ------------------------------------------------ * This should take us back to the instruction * after the call to the last tlkd_enter_sp(). * Place the second parameter to x0 so that the * caller will see it as a return value from the * original entry call * ------------------------------------------------ */ mov x0, x1 ret endfunc tlkd_exit_sp trusted-firmware-a-2.2/services/spd/tlkd/tlkd_main.c000066400000000000000000000307651355360272700226010ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /******************************************************************************* * This is the Secure Payload Dispatcher (SPD). The dispatcher is meant to be a * plug-in component to the Secure Monitor, registered as a runtime service. The * SPD is expected to be a functional extension of the Secure Payload (SP) that * executes in Secure EL1. The Secure Monitor will delegate all SMCs targeting * the Trusted OS/Applications range to the dispatcher. The SPD will either * handle the request locally or delegate it to the Secure Payload. It is also * responsible for initialising and maintaining communication with the SP. ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include "tlkd_private.h" extern const spd_pm_ops_t tlkd_pm_ops; /******************************************************************************* * Per-cpu Secure Payload state ******************************************************************************/ tlk_context_t tlk_ctx; /******************************************************************************* * CPU number on which TLK booted up ******************************************************************************/ static uint32_t boot_cpu; /* TLK UID: RFC-4122 compliant UUID (version-5, sha-1) */ DEFINE_SVC_UUID2(tlk_uuid, 0xc9e911bd, 0xba2b, 0xee52, 0xb1, 0x72, 0x46, 0x1f, 0xba, 0x97, 0x7f, 0x63); static int32_t tlkd_init(void); /******************************************************************************* * Secure Payload Dispatcher setup. The SPD finds out the SP entrypoint and type * (aarch32/aarch64) if not already known and initialises the context for entry * into the SP for its initialisation. ******************************************************************************/ static int32_t tlkd_setup(void) { entry_point_info_t *tlk_ep_info; /* * Get information about the Secure Payload (BL32) image. Its * absence is a critical failure. */ tlk_ep_info = bl31_plat_get_next_image_ep_info(SECURE); if (!tlk_ep_info) { WARN("No SP provided. Booting device without SP" " initialization. SMC`s destined for SP" " will return SMC_UNK\n"); return 1; } /* * If there's no valid entry point for SP, we return a non-zero value * signalling failure initializing the service. We bail out without * registering any handlers */ if (!tlk_ep_info->pc) return 1; /* * Inspect the SP image's SPSR and determine it's execution state * i.e whether AArch32 or AArch64. */ tlkd_init_tlk_ep_state(tlk_ep_info, (tlk_ep_info->spsr >> MODE_RW_SHIFT) & MODE_RW_MASK, tlk_ep_info->pc, &tlk_ctx); /* * All TLK SPD initialization done. Now register our init function * with BL31 for deferred invocation */ bl31_register_bl32_init(&tlkd_init); return 0; } /******************************************************************************* * This function passes control to the Secure Payload image (BL32) for the first * time on the primary cpu after a cold boot. It assumes that a valid secure * context has already been created by tlkd_setup() which can be directly * used. This function performs a synchronous entry into the Secure payload. * The SP passes control back to this routine through a SMC. ******************************************************************************/ static int32_t tlkd_init(void) { entry_point_info_t *tlk_entry_point; /* * Get information about the Secure Payload (BL32) image. Its * absence is a critical failure. */ tlk_entry_point = bl31_plat_get_next_image_ep_info(SECURE); assert(tlk_entry_point); cm_init_my_context(tlk_entry_point); /* * TLK runs only on a single CPU. Store the value of the boot * CPU for sanity checking later. */ boot_cpu = plat_my_core_pos(); /* * Arrange for an entry into the test secure payload. */ return tlkd_synchronous_sp_entry(&tlk_ctx); } /******************************************************************************* * This function is responsible for handling all SMCs in the Trusted OS/App * range from the non-secure state as defined in the SMC Calling Convention * Document. It is also responsible for communicating with the Secure payload * to delegate work and return results back to the non-secure state. Lastly it * will also return any information that the secure payload needs to do the * work assigned to it. ******************************************************************************/ static uintptr_t tlkd_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) { cpu_context_t *ns_cpu_context; gp_regs_t *gp_regs; uint32_t ns; uint64_t par; /* Passing a NULL context is a critical programming error */ assert(handle); /* These SMCs are only supported by a single CPU */ if (boot_cpu != plat_my_core_pos()) SMC_RET1(handle, SMC_UNK); /* Determine which security state this SMC originated from */ ns = is_caller_non_secure(flags); switch (smc_fid) { /* * This function ID is used by SP to indicate that it was * preempted by a non-secure world IRQ. */ case TLK_PREEMPTED: if (ns) SMC_RET1(handle, SMC_UNK); assert(handle == cm_get_context(SECURE)); cm_el1_sysregs_context_save(SECURE); /* Get a reference to the non-secure context */ ns_cpu_context = cm_get_context(NON_SECURE); assert(ns_cpu_context); /* * Restore non-secure state. There is no need to save the * secure system register context since the SP was supposed * to preserve it during S-EL1 interrupt handling. */ cm_el1_sysregs_context_restore(NON_SECURE); cm_set_next_eret_context(NON_SECURE); SMC_RET1(ns_cpu_context, x1); /* * This is a request from the non-secure context to: * * a. register shared memory with the SP for storing it's * activity logs. * b. register shared memory with the SP for passing args * required for maintaining sessions with the Trusted * Applications. * c. register shared persistent buffers for secure storage * d. register NS DRAM ranges passed by Cboot * e. register Root of Trust parameters from Cboot for Verified Boot * f. open/close sessions * g. issue commands to the Trusted Apps * h. resume the preempted yielding SMC call. */ case TLK_REGISTER_LOGBUF: case TLK_REGISTER_REQBUF: case TLK_SS_REGISTER_HANDLER: case TLK_REGISTER_NS_DRAM_RANGES: case TLK_SET_ROOT_OF_TRUST: case TLK_OPEN_TA_SESSION: case TLK_CLOSE_TA_SESSION: case TLK_TA_LAUNCH_OP: case TLK_TA_SEND_EVENT: case TLK_RESUME_FID: if (!ns) SMC_RET1(handle, SMC_UNK); /* * This is a fresh request from the non-secure client. * The parameters are in x1 and x2. Figure out which * registers need to be preserved, save the non-secure * state and send the request to the secure payload. */ assert(handle == cm_get_context(NON_SECURE)); /* * Check if we are already processing a yielding SMC * call. Of all the supported fids, only the "resume" * fid expects the flag to be set. */ if (smc_fid == TLK_RESUME_FID) { if (!get_yield_smc_active_flag(tlk_ctx.state)) SMC_RET1(handle, SMC_UNK); } else { if (get_yield_smc_active_flag(tlk_ctx.state)) SMC_RET1(handle, SMC_UNK); } cm_el1_sysregs_context_save(NON_SECURE); /* * Verify if there is a valid context to use. */ assert(&tlk_ctx.cpu_ctx == cm_get_context(SECURE)); /* * Mark the SP state as active. */ set_yield_smc_active_flag(tlk_ctx.state); /* * We are done stashing the non-secure context. Ask the * secure payload to do the work now. */ cm_el1_sysregs_context_restore(SECURE); cm_set_next_eret_context(SECURE); /* * TLK is a 32-bit Trusted OS and so expects the SMC * arguments via r0-r7. TLK expects the monitor frame * registers to be 64-bits long. Hence, we pass x0 in * r0-r1, x1 in r2-r3, x3 in r4-r5 and x4 in r6-r7. * * As smc_fid is a uint32 value, r1 contains 0. */ gp_regs = get_gpregs_ctx(&tlk_ctx.cpu_ctx); write_ctx_reg(gp_regs, CTX_GPREG_X4, (uint32_t)x2); write_ctx_reg(gp_regs, CTX_GPREG_X5, (uint32_t)(x2 >> 32)); write_ctx_reg(gp_regs, CTX_GPREG_X6, (uint32_t)x3); write_ctx_reg(gp_regs, CTX_GPREG_X7, (uint32_t)(x3 >> 32)); SMC_RET4(&tlk_ctx.cpu_ctx, smc_fid, 0, (uint32_t)x1, (uint32_t)(x1 >> 32)); /* * Translate NS/EL1-S virtual addresses. * * x1 = virtual address * x3 = type (NS/S) * * Returns PA:lo in r0, PA:hi in r1. */ case TLK_VA_TRANSLATE: /* Should be invoked only by secure world */ if (ns) SMC_RET1(handle, SMC_UNK); /* NS virtual addresses are 64-bit long */ if (x3 & TLK_TRANSLATE_NS_VADDR) x1 = (uint32_t)x1 | (x2 << 32); if (!x1) SMC_RET1(handle, SMC_UNK); /* * TODO: Sanity check x1. This would require platform * support. */ /* virtual address and type: ns/s */ par = tlkd_va_translate(x1, x3); /* return physical address in r0-r1 */ SMC_RET4(handle, (uint32_t)par, (uint32_t)(par >> 32), 0, 0); /* * This is a request from the SP to mark completion of * a yielding function ID. */ case TLK_REQUEST_DONE: if (ns) SMC_RET1(handle, SMC_UNK); /* * Mark the SP state as inactive. */ clr_yield_smc_active_flag(tlk_ctx.state); /* Get a reference to the non-secure context */ ns_cpu_context = cm_get_context(NON_SECURE); assert(ns_cpu_context); /* * This is a request completion SMC and we must switch to * the non-secure world to pass the result. */ cm_el1_sysregs_context_save(SECURE); /* * We are done stashing the secure context. Switch to the * non-secure context and return the result. */ cm_el1_sysregs_context_restore(NON_SECURE); cm_set_next_eret_context(NON_SECURE); SMC_RET1(ns_cpu_context, x1); /* * This function ID is used only by the SP to indicate it has * finished initialising itself after a cold boot */ case TLK_ENTRY_DONE: if (ns) SMC_RET1(handle, SMC_UNK); /* * SP has been successfully initialized. Register power * management hooks with PSCI */ psci_register_spd_pm_hook(&tlkd_pm_ops); /* * TLK reports completion. The SPD must have initiated * the original request through a synchronous entry * into the SP. Jump back to the original C runtime * context. */ tlkd_synchronous_sp_exit(&tlk_ctx, x1); break; /* * These function IDs are used only by TLK to indicate it has * finished: * 1. suspending itself after an earlier psci cpu_suspend * request. * 2. resuming itself after an earlier psci cpu_suspend * request. * 3. powering down after an earlier psci system_off/system_reset * request. */ case TLK_SUSPEND_DONE: case TLK_RESUME_DONE: case TLK_SYSTEM_OFF_DONE: if (ns) SMC_RET1(handle, SMC_UNK); /* * TLK reports completion. TLKD must have initiated the * original request through a synchronous entry into the SP. * Jump back to the original C runtime context, and pass x1 as * return value to the caller */ tlkd_synchronous_sp_exit(&tlk_ctx, x1); break; /* * Return the number of service function IDs implemented to * provide service to non-secure */ case TOS_CALL_COUNT: SMC_RET1(handle, TLK_NUM_FID); /* * Return TLK's UID to the caller */ case TOS_UID: SMC_UUID_RET(handle, tlk_uuid); /* * Return the version of current implementation */ case TOS_CALL_VERSION: SMC_RET2(handle, TLK_VERSION_MAJOR, TLK_VERSION_MINOR); default: WARN("%s: Unhandled SMC: 0x%x\n", __func__, smc_fid); break; } SMC_RET1(handle, SMC_UNK); } /* Define a SPD runtime service descriptor for fast SMC calls */ DECLARE_RT_SVC( tlkd_tos_fast, OEN_TOS_START, OEN_TOS_END, SMC_TYPE_FAST, tlkd_setup, tlkd_smc_handler ); /* Define a SPD runtime service descriptor for yielding SMC calls */ DECLARE_RT_SVC( tlkd_tos_std, OEN_TOS_START, OEN_TOS_END, SMC_TYPE_YIELD, NULL, tlkd_smc_handler ); /* Define a SPD runtime service descriptor for fast SMC calls */ DECLARE_RT_SVC( tlkd_tap_fast, OEN_TAP_START, OEN_TAP_END, SMC_TYPE_FAST, NULL, tlkd_smc_handler ); /* Define a SPD runtime service descriptor for yielding SMC calls */ DECLARE_RT_SVC( tlkd_tap_std, OEN_TAP_START, OEN_TAP_END, SMC_TYPE_YIELD, NULL, tlkd_smc_handler ); trusted-firmware-a-2.2/services/spd/tlkd/tlkd_pm.c000066400000000000000000000102111355360272700222510ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "tlkd_private.h" extern tlk_context_t tlk_ctx; #define MPIDR_CPU0 0x80000000 /******************************************************************************* * Return the type of payload TLKD is dealing with. Report the current * resident cpu (mpidr format) if it is a UP/UP migratable payload. ******************************************************************************/ static int32_t cpu_migrate_info(u_register_t *resident_cpu) { /* the payload runs only on CPU0 */ *resident_cpu = MPIDR_CPU0; /* Uniprocessor, not migrate capable payload */ return PSCI_TOS_NOT_UP_MIG_CAP; } /******************************************************************************* * This cpu is being suspended. Inform TLK of the SYSTEM_SUSPEND event, so * that it can pass this information to its Trusted Apps. ******************************************************************************/ static void cpu_suspend_handler(u_register_t suspend_level) { gp_regs_t *gp_regs; int cpu = read_mpidr() & MPIDR_CPU_MASK; int32_t rc = 0; /* * TLK runs only on CPU0 and suspends its Trusted Apps during * SYSTEM_SUSPEND. It has no role to play during CPU_SUSPEND. */ if ((cpu != 0) || (suspend_level != PLAT_MAX_PWR_LVL)) return; /* pass system suspend event to TLK */ gp_regs = get_gpregs_ctx(&tlk_ctx.cpu_ctx); write_ctx_reg(gp_regs, CTX_GPREG_X0, TLK_SYSTEM_SUSPEND); /* Program the entry point and enter TLK */ rc = tlkd_synchronous_sp_entry(&tlk_ctx); /* * Read the response from TLK. A non-zero return means that * something went wrong while communicating with it. */ if (rc != 0) panic(); } /******************************************************************************* * This cpu is being resumed. Inform TLK of the SYSTEM_SUSPEND exit, so * that it can pass this information to its Trusted Apps. ******************************************************************************/ static void cpu_resume_handler(u_register_t suspend_level) { gp_regs_t *gp_regs; int cpu = read_mpidr() & MPIDR_CPU_MASK; int32_t rc = 0; /* * TLK runs only on CPU0 and resumes its Trusted Apps during * SYSTEM_SUSPEND exit. It has no role to play during CPU_SUSPEND * exit. */ if ((cpu != 0) || (suspend_level != PLAT_MAX_PWR_LVL)) return; /* pass system resume event to TLK */ gp_regs = get_gpregs_ctx(&tlk_ctx.cpu_ctx); write_ctx_reg(gp_regs, CTX_GPREG_X0, TLK_SYSTEM_RESUME); /* Program the entry point and enter TLK */ rc = tlkd_synchronous_sp_entry(&tlk_ctx); /* * Read the response from TLK. A non-zero return means that * something went wrong while communicating with it. */ if (rc != 0) panic(); } /******************************************************************************* * System is about to be reset. Inform the SP to allow any book-keeping ******************************************************************************/ static void system_off_handler(void) { int cpu = read_mpidr() & MPIDR_CPU_MASK; gp_regs_t *gp_regs; /* TLK runs only on CPU0 */ if (cpu != 0) return; /* pass system off/reset events to TLK */ gp_regs = get_gpregs_ctx(&tlk_ctx.cpu_ctx); write_ctx_reg(gp_regs, CTX_GPREG_X0, TLK_SYSTEM_OFF); /* * Enter the SP. We do not care about the return value because we * must continue with the shutdown anyway. */ (void)tlkd_synchronous_sp_entry(&tlk_ctx); } /******************************************************************************* * Structure populated by the Dispatcher to be given a chance to perform any * bookkeeping before PSCI executes a power mgmt. operation. ******************************************************************************/ const spd_pm_ops_t tlkd_pm_ops = { .svc_migrate_info = cpu_migrate_info, .svc_suspend = cpu_suspend_handler, .svc_suspend_finish = cpu_resume_handler, .svc_system_off = system_off_handler, .svc_system_reset = system_off_handler }; trusted-firmware-a-2.2/services/spd/tlkd/tlkd_private.h000066400000000000000000000115011355360272700233170ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TLKD_PRIVATE_H #define TLKD_PRIVATE_H #include #include #include #include #include /* * This flag is used by the TLKD to determine if the SP is servicing a yielding * SMC request prior to programming the next entry into the SP e.g. if SP * execution is preempted by a non-secure interrupt and handed control to the * normal world. If another request which is distinct from what the SP was * previously doing arrives, then this flag will be help the TLKD to either * reject the new request or service it while ensuring that the previous context * is not corrupted. */ #define YIELD_SMC_ACTIVE_FLAG_SHIFT 2 #define YIELD_SMC_ACTIVE_FLAG_MASK 1 #define get_yield_smc_active_flag(state) \ (((state) >> YIELD_SMC_ACTIVE_FLAG_SHIFT) \ & YIELD_SMC_ACTIVE_FLAG_MASK) #define set_yield_smc_active_flag(state) ((state) |= \ (1 << YIELD_SMC_ACTIVE_FLAG_SHIFT)) #define clr_yield_smc_active_flag(state) ((state) &= \ ~(YIELD_SMC_ACTIVE_FLAG_MASK \ << YIELD_SMC_ACTIVE_FLAG_SHIFT)) /******************************************************************************* * Translate virtual address received from the NS world ******************************************************************************/ #define TLK_TRANSLATE_NS_VADDR 4 /******************************************************************************* * Secure Payload execution state information i.e. aarch32 or aarch64 ******************************************************************************/ #define SP_AARCH32 MODE_RW_32 #define SP_AARCH64 MODE_RW_64 /******************************************************************************* * Number of cpus that the present on this platform. TODO: Rely on a topology * tree to determine this in the future to avoid assumptions about mpidr * allocation ******************************************************************************/ #define TLKD_CORE_COUNT PLATFORM_CORE_COUNT /******************************************************************************* * Constants that allow assembler code to preserve callee-saved registers of the * C runtime context while performing a security state switch. ******************************************************************************/ #define TLKD_C_RT_CTX_X19 0x0 #define TLKD_C_RT_CTX_X20 0x8 #define TLKD_C_RT_CTX_X21 0x10 #define TLKD_C_RT_CTX_X22 0x18 #define TLKD_C_RT_CTX_X23 0x20 #define TLKD_C_RT_CTX_X24 0x28 #define TLKD_C_RT_CTX_X25 0x30 #define TLKD_C_RT_CTX_X26 0x38 #define TLKD_C_RT_CTX_X27 0x40 #define TLKD_C_RT_CTX_X28 0x48 #define TLKD_C_RT_CTX_X29 0x50 #define TLKD_C_RT_CTX_X30 0x58 #define TLKD_C_RT_CTX_SIZE 0x60 #define TLKD_C_RT_CTX_ENTRIES (TLKD_C_RT_CTX_SIZE >> DWORD_SHIFT) #ifndef __ASSEMBLER__ #include #include /* AArch64 callee saved general purpose register context structure. */ DEFINE_REG_STRUCT(c_rt_regs, TLKD_C_RT_CTX_ENTRIES); /* * Compile time assertion to ensure that both the compiler and linker * have the same double word aligned view of the size of the C runtime * register context. */ CASSERT(TLKD_C_RT_CTX_SIZE == sizeof(c_rt_regs_t), \ assert_tlkd_c_rt_regs_size_mismatch); /******************************************************************************* * Structure which helps the SPD to maintain the per-cpu state of the SP. * 'state' - collection of flags to track SP state e.g. on/off * 'mpidr' - mpidr to associate a context with a cpu * 'c_rt_ctx' - stack address to restore C runtime context from after * returning from a synchronous entry into the SP. * 'cpu_ctx' - space to maintain SP architectural state * 'saved_tsp_args' - space to store arguments for TSP arithmetic operations * which will queried using the TSP_GET_ARGS SMC by TSP. ******************************************************************************/ typedef struct tlk_context { uint32_t state; uint64_t mpidr; uint64_t c_rt_ctx; cpu_context_t cpu_ctx; } tlk_context_t; /******************************************************************************* * Function & Data prototypes ******************************************************************************/ uint64_t tlkd_va_translate(uintptr_t va, int type); uint64_t tlkd_enter_sp(uint64_t *c_rt_ctx); void __dead2 tlkd_exit_sp(uint64_t c_rt_ctx, uint64_t ret); uint64_t tlkd_synchronous_sp_entry(tlk_context_t *tlk_ctx); void __dead2 tlkd_synchronous_sp_exit(tlk_context_t *tlk_ctx, uint64_t ret); void tlkd_init_tlk_ep_state(struct entry_point_info *tlk_entry_point, uint32_t rw, uint64_t pc, tlk_context_t *tlk_ctx); #endif /*__ASSEMBLER__*/ #endif /* TLKD_PRIVATE_H */ trusted-firmware-a-2.2/services/spd/trusty/000077500000000000000000000000001355360272700210745ustar00rootroot00000000000000trusted-firmware-a-2.2/services/spd/trusty/generic-arm64-smcall.c000066400000000000000000000034331355360272700250570ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "generic-arm64-smcall.h" int trusty_disable_serial_debug; struct dputc_state { char linebuf[128]; unsigned l; }; static struct dputc_state dputc_state[2]; static void trusty_dputc(char ch, int secure) { unsigned i; struct dputc_state *s = &dputc_state[!secure]; if (trusty_disable_serial_debug) return; s->linebuf[s->l++] = ch; if (s->l == sizeof(s->linebuf) || ch == '\n') { if (secure) printf("secure os: "); else printf("non-secure os: "); for (i = 0; i < s->l; i++) { putchar(s->linebuf[i]); } if (ch != '\n') { printf(" <...>\n"); } s->l = 0; } } static uint64_t trusty_get_reg_base(uint32_t reg) { switch (reg) { case 0: return PLAT_ARM_GICD_BASE; case 1: return PLAT_ARM_GICC_BASE; default: NOTICE("%s(0x%x) unknown reg\n", __func__, reg); return SMC_UNK; } } static uintptr_t trusty_generic_platform_smc(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) { switch (smc_fid) { case SMC_FC_DEBUG_PUTC: trusty_dputc(x1, is_caller_secure(flags)); SMC_RET1(handle, 0); case SMC_FC_GET_REG_BASE: case SMC_FC64_GET_REG_BASE: SMC_RET1(handle, trusty_get_reg_base(x1)); default: NOTICE("%s(0x%x, 0x%lx) unknown smc\n", __func__, smc_fid, x1); SMC_RET1(handle, SMC_UNK); } } /* Define a SPD runtime service descriptor for fast SMC calls */ DECLARE_RT_SVC( trusty_fast, SMC_ENTITY_PLATFORM_MONITOR, SMC_ENTITY_PLATFORM_MONITOR, SMC_TYPE_FAST, NULL, trusty_generic_platform_smc ); trusted-firmware-a-2.2/services/spd/trusty/generic-arm64-smcall.h000066400000000000000000000012431355360272700250610ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "smcall.h" #define SMC_ENTITY_PLATFORM_MONITOR 61 /* * SMC calls implemented by EL3 monitor */ /* * Write character in r1 to debug console */ #define SMC_FC_DEBUG_PUTC SMC_FASTCALL_NR(SMC_ENTITY_PLATFORM_MONITOR, 0x0) /* * Get register base address * r1: SMC_GET_GIC_BASE_GICD or SMC_GET_GIC_BASE_GICC */ #define SMC_GET_GIC_BASE_GICD 0 #define SMC_GET_GIC_BASE_GICC 1 #define SMC_FC_GET_REG_BASE SMC_FASTCALL_NR(SMC_ENTITY_PLATFORM_MONITOR, 0x1) #define SMC_FC64_GET_REG_BASE SMC_FASTCALL64_NR(SMC_ENTITY_PLATFORM_MONITOR, 0x1) trusted-firmware-a-2.2/services/spd/trusty/sm_err.h000066400000000000000000000015521355360272700225370ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SM_ERR_H #define SM_ERR_H /* Errors from the secure monitor */ #define SM_ERR_UNDEFINED_SMC 0xFFFFFFFF /* Unknown SMC (defined by ARM DEN 0028A(0.9.0) */ #define SM_ERR_INVALID_PARAMETERS -2 #define SM_ERR_INTERRUPTED -3 /* Got interrupted. Call back with restart SMC */ #define SM_ERR_UNEXPECTED_RESTART -4 /* Got an restart SMC when we didn't expect it */ #define SM_ERR_BUSY -5 /* Temporarily busy. Call back with original args */ #define SM_ERR_INTERLEAVED_SMC -6 /* Got a trusted_service SMC when a restart SMC is required */ #define SM_ERR_INTERNAL_FAILURE -7 /* Unknown error */ #define SM_ERR_NOT_SUPPORTED -8 #define SM_ERR_NOT_ALLOWED -9 /* SMC call not allowed */ #define SM_ERR_END_OF_INPUT -10 #endif /* SM_ERR_H */ trusted-firmware-a-2.2/services/spd/trusty/smcall.h000066400000000000000000000063171355360272700225270ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SMCALL_H #define SMCALL_H #define SMC_NUM_ENTITIES 64U #define SMC_NUM_ARGS 4U #define SMC_NUM_PARAMS (SMC_NUM_ARGS - 1U) #define SMC_IS_FASTCALL(smc_nr) ((smc_nr) & 0x80000000U) #define SMC_IS_SMC64(smc_nr) ((smc_nr) & 0x40000000U) #define SMC_ENTITY(smc_nr) (((smc_nr) & 0x3F000000U) >> 24U) #define SMC_FUNCTION(smc_nr) ((smc_nr) & 0x0000FFFFU) #define SMC_NR(entity, fn, fastcall, smc64) \ (((((uint32_t)(fastcall)) & 0x1U) << 31U) | \ (((smc64) & 0x1U) << 30U) | \ (((entity) & 0x3FU) << 24U) | \ ((fn) & 0xFFFFU)) #define SMC_FASTCALL_NR(entity, fn) SMC_NR((entity), (fn), 1U, 0U) #define SMC_FASTCALL64_NR(entity, fn) SMC_NR((entity), (fn), 1U, 1U) #define SMC_YIELDCALL_NR(entity, fn) SMC_NR((entity), (fn), 0U, 0U) #define SMC_YIELDCALL64_NR(entity, fn) SMC_NR((entity), (fn), 0U, 1U) #define SMC_ENTITY_ARCH 0U /* ARM Architecture calls */ #define SMC_ENTITY_CPU 1U /* CPU Service calls */ #define SMC_ENTITY_SIP 2U /* SIP Service calls */ #define SMC_ENTITY_OEM 3U /* OEM Service calls */ #define SMC_ENTITY_STD 4U /* Standard Service calls */ #define SMC_ENTITY_RESERVED 5U /* Reserved for future use */ #define SMC_ENTITY_TRUSTED_APP 48U /* Trusted Application calls */ #define SMC_ENTITY_TRUSTED_OS 50U /* Trusted OS calls */ #define SMC_ENTITY_LOGGING 51U /* Used for secure -> nonsecure logging */ #define SMC_ENTITY_SECURE_MONITOR 60U /* Trusted OS calls internal to secure monitor */ /* FC = Fast call, YC = Yielding call */ #define SMC_YC_RESTART_LAST SMC_YIELDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 0U) #define SMC_YC_NOP SMC_YIELDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 1U) /* * Return from secure os to non-secure os with return value in r1 */ #define SMC_YC_NS_RETURN SMC_YIELDCALL_NR (SMC_ENTITY_SECURE_MONITOR, 0U) #define SMC_FC_RESERVED SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 0U) #define SMC_FC_FIQ_EXIT SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 1U) #define SMC_FC_REQUEST_FIQ SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 2U) #define SMC_FC_GET_NEXT_IRQ SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 3U) #define SMC_FC_FIQ_ENTER SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 4U) #define SMC_FC64_SET_FIQ_HANDLER SMC_FASTCALL64_NR(SMC_ENTITY_SECURE_MONITOR, 5U) #define SMC_FC64_GET_FIQ_REGS SMC_FASTCALL64_NR (SMC_ENTITY_SECURE_MONITOR, 6U) #define SMC_FC_CPU_SUSPEND SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 7U) #define SMC_FC_CPU_RESUME SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 8U) #define SMC_FC_AARCH_SWITCH SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 9U) #define SMC_FC_GET_VERSION_STR SMC_FASTCALL_NR (SMC_ENTITY_SECURE_MONITOR, 10U) /* Trusted OS entity calls */ #define SMC_YC_VIRTIO_GET_DESCR SMC_YIELDCALL_NR(SMC_ENTITY_TRUSTED_OS, 20U) #define SMC_YC_VIRTIO_START SMC_YIELDCALL_NR(SMC_ENTITY_TRUSTED_OS, 21U) #define SMC_YC_VIRTIO_STOP SMC_YIELDCALL_NR(SMC_ENTITY_TRUSTED_OS, 22U) #define SMC_YC_VDEV_RESET SMC_YIELDCALL_NR(SMC_ENTITY_TRUSTED_OS, 23U) #define SMC_YC_VDEV_KICK_VQ SMC_YIELDCALL_NR(SMC_ENTITY_TRUSTED_OS, 24U) #define SMC_YC_SET_ROT_PARAMS SMC_YIELDCALL_NR(SMC_ENTITY_TRUSTED_OS, 65535U) #endif /* SMCALL_H */ trusted-firmware-a-2.2/services/spd/trusty/trusty.c000066400000000000000000000331101355360272700226100ustar00rootroot00000000000000/* * Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include "sm_err.h" #include "smcall.h" /* macro to check if Hypervisor is enabled in the HCR_EL2 register */ #define HYP_ENABLE_FLAG 0x286001U /* length of Trusty's input parameters (in bytes) */ #define TRUSTY_PARAMS_LEN_BYTES (4096U * 2) struct trusty_stack { uint8_t space[PLATFORM_STACK_SIZE] __aligned(16); uint32_t end; }; struct trusty_cpu_ctx { cpu_context_t cpu_ctx; void *saved_sp; uint32_t saved_security_state; int32_t fiq_handler_active; uint64_t fiq_handler_pc; uint64_t fiq_handler_cpsr; uint64_t fiq_handler_sp; uint64_t fiq_pc; uint64_t fiq_cpsr; uint64_t fiq_sp_el1; gp_regs_t fiq_gpregs; struct trusty_stack secure_stack; }; struct smc_args { uint64_t r0; uint64_t r1; uint64_t r2; uint64_t r3; uint64_t r4; uint64_t r5; uint64_t r6; uint64_t r7; }; static struct trusty_cpu_ctx trusty_cpu_ctx[PLATFORM_CORE_COUNT]; struct smc_args trusty_init_context_stack(void **sp, void *new_stack); struct smc_args trusty_context_switch_helper(void **sp, void *smc_params); static uint32_t current_vmid; static struct trusty_cpu_ctx *get_trusty_ctx(void) { return &trusty_cpu_ctx[plat_my_core_pos()]; } static bool is_hypervisor_mode(void) { uint64_t hcr = read_hcr(); return ((hcr & HYP_ENABLE_FLAG) != 0U) ? true : false; } static struct smc_args trusty_context_switch(uint32_t security_state, uint64_t r0, uint64_t r1, uint64_t r2, uint64_t r3) { struct smc_args args, ret_args; struct trusty_cpu_ctx *ctx = get_trusty_ctx(); struct trusty_cpu_ctx *ctx_smc; assert(ctx->saved_security_state != security_state); args.r7 = 0; if (is_hypervisor_mode()) { /* According to the ARM DEN0028A spec, VMID is stored in x7 */ ctx_smc = cm_get_context(NON_SECURE); assert(ctx_smc != NULL); args.r7 = SMC_GET_GP(ctx_smc, CTX_GPREG_X7); } /* r4, r5, r6 reserved for future use. */ args.r6 = 0; args.r5 = 0; args.r4 = 0; args.r3 = r3; args.r2 = r2; args.r1 = r1; args.r0 = r0; /* * To avoid the additional overhead in PSCI flow, skip FP context * saving/restoring in case of CPU suspend and resume, assuming that * when it's needed the PSCI caller has preserved FP context before * going here. */ if (r0 != SMC_FC_CPU_SUSPEND && r0 != SMC_FC_CPU_RESUME) fpregs_context_save(get_fpregs_ctx(cm_get_context(security_state))); cm_el1_sysregs_context_save(security_state); ctx->saved_security_state = security_state; ret_args = trusty_context_switch_helper(&ctx->saved_sp, &args); assert(ctx->saved_security_state == ((security_state == 0U) ? 1U : 0U)); cm_el1_sysregs_context_restore(security_state); if (r0 != SMC_FC_CPU_SUSPEND && r0 != SMC_FC_CPU_RESUME) fpregs_context_restore(get_fpregs_ctx(cm_get_context(security_state))); cm_set_next_eret_context(security_state); return ret_args; } static uint64_t trusty_fiq_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { struct smc_args ret; struct trusty_cpu_ctx *ctx = get_trusty_ctx(); assert(!is_caller_secure(flags)); ret = trusty_context_switch(NON_SECURE, SMC_FC_FIQ_ENTER, 0, 0, 0); if (ret.r0 != 0U) { SMC_RET0(handle); } if (ctx->fiq_handler_active != 0) { INFO("%s: fiq handler already active\n", __func__); SMC_RET0(handle); } ctx->fiq_handler_active = 1; (void)memcpy(&ctx->fiq_gpregs, get_gpregs_ctx(handle), sizeof(ctx->fiq_gpregs)); ctx->fiq_pc = SMC_GET_EL3(handle, CTX_ELR_EL3); ctx->fiq_cpsr = SMC_GET_EL3(handle, CTX_SPSR_EL3); ctx->fiq_sp_el1 = read_ctx_reg(get_sysregs_ctx(handle), CTX_SP_EL1); write_ctx_reg(get_sysregs_ctx(handle), CTX_SP_EL1, ctx->fiq_handler_sp); cm_set_elr_spsr_el3(NON_SECURE, ctx->fiq_handler_pc, (uint32_t)ctx->fiq_handler_cpsr); SMC_RET0(handle); } static uint64_t trusty_set_fiq_handler(void *handle, uint64_t cpu, uint64_t handler, uint64_t stack) { struct trusty_cpu_ctx *ctx; if (cpu >= (uint64_t)PLATFORM_CORE_COUNT) { ERROR("%s: cpu %lld >= %d\n", __func__, cpu, PLATFORM_CORE_COUNT); return (uint64_t)SM_ERR_INVALID_PARAMETERS; } ctx = &trusty_cpu_ctx[cpu]; ctx->fiq_handler_pc = handler; ctx->fiq_handler_cpsr = SMC_GET_EL3(handle, CTX_SPSR_EL3); ctx->fiq_handler_sp = stack; SMC_RET1(handle, 0); } static uint64_t trusty_get_fiq_regs(void *handle) { struct trusty_cpu_ctx *ctx = get_trusty_ctx(); uint64_t sp_el0 = read_ctx_reg(&ctx->fiq_gpregs, CTX_GPREG_SP_EL0); SMC_RET4(handle, ctx->fiq_pc, ctx->fiq_cpsr, sp_el0, ctx->fiq_sp_el1); } static uint64_t trusty_fiq_exit(void *handle, uint64_t x1, uint64_t x2, uint64_t x3) { struct smc_args ret; struct trusty_cpu_ctx *ctx = get_trusty_ctx(); if (ctx->fiq_handler_active == 0) { NOTICE("%s: fiq handler not active\n", __func__); SMC_RET1(handle, (uint64_t)SM_ERR_INVALID_PARAMETERS); } ret = trusty_context_switch(NON_SECURE, SMC_FC_FIQ_EXIT, 0, 0, 0); if (ret.r0 != 1U) { INFO("%s(%p) SMC_FC_FIQ_EXIT returned unexpected value, %lld\n", __func__, handle, ret.r0); } /* * Restore register state to state recorded on fiq entry. * * x0, sp_el1, pc and cpsr need to be restored because el1 cannot * restore them. * * x1-x4 and x8-x17 need to be restored here because smc_handler64 * corrupts them (el1 code also restored them). */ (void)memcpy(get_gpregs_ctx(handle), &ctx->fiq_gpregs, sizeof(ctx->fiq_gpregs)); ctx->fiq_handler_active = 0; write_ctx_reg(get_sysregs_ctx(handle), CTX_SP_EL1, ctx->fiq_sp_el1); cm_set_elr_spsr_el3(NON_SECURE, ctx->fiq_pc, (uint32_t)ctx->fiq_cpsr); SMC_RET0(handle); } static uintptr_t trusty_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) { struct smc_args ret; uint32_t vmid = 0U; entry_point_info_t *ep_info = bl31_plat_get_next_image_ep_info(SECURE); /* * Return success for SET_ROT_PARAMS if Trusty is not present, as * Verified Boot is not even supported and returning success here * would not compromise the boot process. */ if ((ep_info == NULL) && (smc_fid == SMC_YC_SET_ROT_PARAMS)) { SMC_RET1(handle, 0); } else if (ep_info == NULL) { SMC_RET1(handle, SMC_UNK); } else { ; /* do nothing */ } if (is_caller_secure(flags)) { if (smc_fid == SMC_YC_NS_RETURN) { ret = trusty_context_switch(SECURE, x1, 0, 0, 0); SMC_RET8(handle, ret.r0, ret.r1, ret.r2, ret.r3, ret.r4, ret.r5, ret.r6, ret.r7); } INFO("%s (0x%x, 0x%lx, 0x%lx, 0x%lx, 0x%lx, %p, %p, 0x%lx) \ cpu %d, unknown smc\n", __func__, smc_fid, x1, x2, x3, x4, cookie, handle, flags, plat_my_core_pos()); SMC_RET1(handle, SMC_UNK); } else { switch (smc_fid) { case SMC_FC64_SET_FIQ_HANDLER: return trusty_set_fiq_handler(handle, x1, x2, x3); case SMC_FC64_GET_FIQ_REGS: return trusty_get_fiq_regs(handle); case SMC_FC_FIQ_EXIT: return trusty_fiq_exit(handle, x1, x2, x3); default: if (is_hypervisor_mode()) vmid = SMC_GET_GP(handle, CTX_GPREG_X7); if ((current_vmid != 0) && (current_vmid != vmid)) { /* This message will cause SMC mechanism * abnormal in multi-guest environment. * Change it to WARN in case you need it. */ VERBOSE("Previous SMC not finished.\n"); SMC_RET1(handle, SM_ERR_BUSY); } current_vmid = vmid; ret = trusty_context_switch(NON_SECURE, smc_fid, x1, x2, x3); current_vmid = 0; SMC_RET1(handle, ret.r0); } } } static int32_t trusty_init(void) { entry_point_info_t *ep_info; struct smc_args zero_args = {0}; struct trusty_cpu_ctx *ctx = get_trusty_ctx(); uint32_t cpu = plat_my_core_pos(); uint64_t reg_width = GET_RW(read_ctx_reg(get_el3state_ctx(&ctx->cpu_ctx), CTX_SPSR_EL3)); /* * Get information about the Trusty image. Its absence is a critical * failure. */ ep_info = bl31_plat_get_next_image_ep_info(SECURE); assert(ep_info != NULL); fpregs_context_save(get_fpregs_ctx(cm_get_context(NON_SECURE))); cm_el1_sysregs_context_save(NON_SECURE); cm_set_context(&ctx->cpu_ctx, SECURE); cm_init_my_context(ep_info); /* * Adjust secondary cpu entry point for 32 bit images to the * end of exception vectors */ if ((cpu != 0U) && (reg_width == MODE_RW_32)) { INFO("trusty: cpu %d, adjust entry point to 0x%lx\n", cpu, ep_info->pc + (1U << 5)); cm_set_elr_el3(SECURE, ep_info->pc + (1U << 5)); } cm_el1_sysregs_context_restore(SECURE); fpregs_context_restore(get_fpregs_ctx(cm_get_context(SECURE))); cm_set_next_eret_context(SECURE); ctx->saved_security_state = ~0U; /* initial saved state is invalid */ (void)trusty_init_context_stack(&ctx->saved_sp, &ctx->secure_stack.end); (void)trusty_context_switch_helper(&ctx->saved_sp, &zero_args); cm_el1_sysregs_context_restore(NON_SECURE); fpregs_context_restore(get_fpregs_ctx(cm_get_context(NON_SECURE))); cm_set_next_eret_context(NON_SECURE); return 1; } static void trusty_cpu_suspend(uint32_t off) { struct smc_args ret; ret = trusty_context_switch(NON_SECURE, SMC_FC_CPU_SUSPEND, off, 0, 0); if (ret.r0 != 0U) { INFO("%s: cpu %d, SMC_FC_CPU_SUSPEND returned unexpected value, %lld\n", __func__, plat_my_core_pos(), ret.r0); } } static void trusty_cpu_resume(uint32_t on) { struct smc_args ret; ret = trusty_context_switch(NON_SECURE, SMC_FC_CPU_RESUME, on, 0, 0); if (ret.r0 != 0U) { INFO("%s: cpu %d, SMC_FC_CPU_RESUME returned unexpected value, %lld\n", __func__, plat_my_core_pos(), ret.r0); } } static int32_t trusty_cpu_off_handler(u_register_t max_off_lvl) { trusty_cpu_suspend(max_off_lvl); return 0; } static void trusty_cpu_on_finish_handler(u_register_t max_off_lvl) { struct trusty_cpu_ctx *ctx = get_trusty_ctx(); if (ctx->saved_sp == NULL) { (void)trusty_init(); } else { trusty_cpu_resume(max_off_lvl); } } static void trusty_cpu_suspend_handler(u_register_t max_off_lvl) { trusty_cpu_suspend(max_off_lvl); } static void trusty_cpu_suspend_finish_handler(u_register_t max_off_lvl) { trusty_cpu_resume(max_off_lvl); } static const spd_pm_ops_t trusty_pm = { .svc_off = trusty_cpu_off_handler, .svc_suspend = trusty_cpu_suspend_handler, .svc_on_finish = trusty_cpu_on_finish_handler, .svc_suspend_finish = trusty_cpu_suspend_finish_handler, }; void plat_trusty_set_boot_args(aapcs64_params_t *args); #ifdef TSP_SEC_MEM_SIZE #pragma weak plat_trusty_set_boot_args void plat_trusty_set_boot_args(aapcs64_params_t *args) { args->arg0 = TSP_SEC_MEM_SIZE; } #endif static int32_t trusty_setup(void) { entry_point_info_t *ep_info; uint32_t instr; uint32_t flags; int32_t ret; bool aarch32 = false; /* Get trusty's entry point info */ ep_info = bl31_plat_get_next_image_ep_info(SECURE); if (ep_info == NULL) { INFO("Trusty image missing.\n"); return -1; } /* memmap first page of trusty's code memory before peeking */ ret = mmap_add_dynamic_region(ep_info->pc, /* PA */ ep_info->pc, /* VA */ PAGE_SIZE, /* size */ MT_SECURE | MT_RW_DATA); /* attrs */ assert(ret == 0); /* peek into trusty's code to see if we have a 32-bit or 64-bit image */ instr = *(uint32_t *)ep_info->pc; if (instr >> 24 == 0xeaU) { INFO("trusty: Found 32 bit image\n"); aarch32 = true; } else if (instr >> 8 == 0xd53810U || instr >> 16 == 0x9400U) { INFO("trusty: Found 64 bit image\n"); } else { ERROR("trusty: Found unknown image, 0x%x\n", instr); return -1; } /* unmap trusty's memory page */ (void)mmap_remove_dynamic_region(ep_info->pc, PAGE_SIZE); SET_PARAM_HEAD(ep_info, PARAM_EP, VERSION_1, SECURE | EP_ST_ENABLE); if (!aarch32) ep_info->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); else ep_info->spsr = SPSR_MODE32(MODE32_svc, SPSR_T_ARM, SPSR_E_LITTLE, DAIF_FIQ_BIT | DAIF_IRQ_BIT | DAIF_ABT_BIT); (void)memset(&ep_info->args, 0, sizeof(ep_info->args)); plat_trusty_set_boot_args(&ep_info->args); /* register init handler */ bl31_register_bl32_init(trusty_init); /* register power management hooks */ psci_register_spd_pm_hook(&trusty_pm); /* register interrupt handler */ flags = 0; set_interrupt_rm_flag(flags, NON_SECURE); ret = register_interrupt_type_handler(INTR_TYPE_S_EL1, trusty_fiq_handler, flags); if (ret != 0) { ERROR("trusty: failed to register fiq handler, ret = %d\n", ret); } if (aarch32) { entry_point_info_t *ns_ep_info; uint32_t spsr; ns_ep_info = bl31_plat_get_next_image_ep_info(NON_SECURE); if (ns_ep_info == NULL) { NOTICE("Trusty: non-secure image missing.\n"); return -1; } spsr = ns_ep_info->spsr; if (GET_RW(spsr) == MODE_RW_64 && GET_EL(spsr) == MODE_EL2) { spsr &= ~(MODE_EL_MASK << MODE_EL_SHIFT); spsr |= MODE_EL1 << MODE_EL_SHIFT; } if (GET_RW(spsr) == MODE_RW_32 && GET_M32(spsr) == MODE32_hyp) { spsr &= ~(MODE32_MASK << MODE32_SHIFT); spsr |= MODE32_svc << MODE32_SHIFT; } if (spsr != ns_ep_info->spsr) { NOTICE("Trusty: Switch bl33 from EL2 to EL1 (spsr 0x%x -> 0x%x)\n", ns_ep_info->spsr, spsr); ns_ep_info->spsr = spsr; } } return 0; } /* Define a SPD runtime service descriptor for fast SMC calls */ DECLARE_RT_SVC( trusty_fast, OEN_TOS_START, SMC_ENTITY_SECURE_MONITOR, SMC_TYPE_FAST, trusty_setup, trusty_smc_handler ); /* Define a SPD runtime service descriptor for yielding SMC calls */ DECLARE_RT_SVC( trusty_std, OEN_TAP_START, SMC_ENTITY_SECURE_MONITOR, SMC_TYPE_YIELD, NULL, trusty_smc_handler ); trusted-firmware-a-2.2/services/spd/trusty/trusty.mk000066400000000000000000000006031355360272700227760ustar00rootroot00000000000000# # Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # SPD_INCLUDES := SPD_SOURCES := services/spd/trusty/trusty.c \ services/spd/trusty/trusty_helpers.S ifeq (${TRUSTY_SPD_WITH_GENERIC_SERVICES},1) SPD_SOURCES += services/spd/trusty/generic-arm64-smcall.c endif NEED_BL32 := yes CTX_INCLUDE_FPREGS := 1 trusted-firmware-a-2.2/services/spd/trusty/trusty_helpers.S000066400000000000000000000024201355360272700243120ustar00rootroot00000000000000/* * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include .macro push ra, rb, sp=sp stp \ra, \rb, [\sp,#-16]! .endm .macro pop ra, rb, sp=sp ldp \ra, \rb, [\sp], #16 .endm .global trusty_context_switch_helper func trusty_context_switch_helper push x8, xzr push x19, x20 push x21, x22 push x23, x24 push x25, x26 push x27, x28 push x29, x30 mov x9, sp ldr x10, [x0] mov sp, x10 str x9, [x0] pop x29, x30 pop x27, x28 pop x25, x26 pop x23, x24 pop x21, x22 pop x19, x20 pop x8, xzr ldr x2, [x1] ldr x3, [x1, #0x08] ldr x4, [x1, #0x10] ldr x5, [x1, #0x18] ldr x6, [x1, #0x20] ldr x7, [x1, #0x28] ldr x10, [x1, #0x30] ldr x11, [x1, #0x38] stp x2, x3, [x8] stp x4, x5, [x8, #16] stp x6, x7, [x8, #32] stp x10, x11, [x8, #48] ret endfunc trusty_context_switch_helper .global trusty_init_context_stack func trusty_init_context_stack push x8, xzr, x1 push xzr, xzr, x1 push xzr, xzr, x1 push xzr, xzr, x1 push xzr, xzr, x1 push xzr, xzr, x1 adr x9, el3_exit push xzr, x9, x1 str x1, [x0] ret endfunc trusty_init_context_stack trusted-firmware-a-2.2/services/spd/tspd/000077500000000000000000000000001355360272700204745ustar00rootroot00000000000000trusted-firmware-a-2.2/services/spd/tspd/tspd.mk000066400000000000000000000027231355360272700220030ustar00rootroot00000000000000# # Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # TSPD_DIR := services/spd/tspd ifeq (${ERROR_DEPRECATED},0) SPD_INCLUDES := -Iinclude/bl32/tsp endif SPD_SOURCES := services/spd/tspd/tspd_common.c \ services/spd/tspd/tspd_helpers.S \ services/spd/tspd/tspd_main.c \ services/spd/tspd/tspd_pm.c # This dispatcher is paired with a Test Secure Payload source and we intend to # build the Test Secure Payload along with this dispatcher. # # In cases where an associated Secure Payload lies outside this build # system/source tree, the the dispatcher Makefile can either invoke an external # build command or assume it pre-built BL32_ROOT := bl32/tsp # Include SP's Makefile. The assumption is that the TSP's build system is # compatible with that of Trusted Firmware, and it'll add and populate necessary # build targets and variables include ${BL32_ROOT}/tsp.mk # Let the top-level Makefile know that we intend to build the SP from source NEED_BL32 := yes # Flag used to enable routing of non-secure interrupts to EL3 when they are # generated while the code is executing in S-EL1/0. TSP_NS_INTR_ASYNC_PREEMPT := 0 ifeq ($(EL3_EXCEPTION_HANDLING),1) ifeq ($(TSP_NS_INTR_ASYNC_PREEMPT),0) $(error When EL3_EXCEPTION_HANDLING=1, TSP_NS_INTR_ASYNC_PREEMPT must also be 1) endif endif $(eval $(call assert_boolean,TSP_NS_INTR_ASYNC_PREEMPT)) $(eval $(call add_define,TSP_NS_INTR_ASYNC_PREEMPT)) trusted-firmware-a-2.2/services/spd/tspd/tspd_common.c000066400000000000000000000107201355360272700231620ustar00rootroot00000000000000/* * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include "tspd_private.h" /******************************************************************************* * Given a secure payload entrypoint info pointer, entry point PC, register * width, cpu id & pointer to a context data structure, this function will * initialize tsp context and entry point info for the secure payload ******************************************************************************/ void tspd_init_tsp_ep_state(struct entry_point_info *tsp_entry_point, uint32_t rw, uint64_t pc, tsp_context_t *tsp_ctx) { uint32_t ep_attr; /* Passing a NULL context is a critical programming error */ assert(tsp_ctx); assert(tsp_entry_point); assert(pc); /* * We support AArch64 TSP for now. * TODO: Add support for AArch32 TSP */ assert(rw == TSP_AARCH64); /* Associate this context with the cpu specified */ tsp_ctx->mpidr = read_mpidr_el1(); tsp_ctx->state = 0; set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_OFF); clr_yield_smc_active_flag(tsp_ctx->state); cm_set_context(&tsp_ctx->cpu_ctx, SECURE); /* initialise an entrypoint to set up the CPU context */ ep_attr = SECURE | EP_ST_ENABLE; if (read_sctlr_el3() & SCTLR_EE_BIT) ep_attr |= EP_EE_BIG; SET_PARAM_HEAD(tsp_entry_point, PARAM_EP, VERSION_1, ep_attr); tsp_entry_point->pc = pc; tsp_entry_point->spsr = SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); zeromem(&tsp_entry_point->args, sizeof(tsp_entry_point->args)); } /******************************************************************************* * This function takes an SP context pointer and: * 1. Applies the S-EL1 system register context from tsp_ctx->cpu_ctx. * 2. Saves the current C runtime state (callee saved registers) on the stack * frame and saves a reference to this state. * 3. Calls el3_exit() so that the EL3 system and general purpose registers * from the tsp_ctx->cpu_ctx are used to enter the secure payload image. ******************************************************************************/ uint64_t tspd_synchronous_sp_entry(tsp_context_t *tsp_ctx) { uint64_t rc; assert(tsp_ctx != NULL); assert(tsp_ctx->c_rt_ctx == 0); /* Apply the Secure EL1 system register context and switch to it */ assert(cm_get_context(SECURE) == &tsp_ctx->cpu_ctx); cm_el1_sysregs_context_restore(SECURE); cm_set_next_eret_context(SECURE); rc = tspd_enter_sp(&tsp_ctx->c_rt_ctx); #if ENABLE_ASSERTIONS tsp_ctx->c_rt_ctx = 0; #endif return rc; } /******************************************************************************* * This function takes an SP context pointer and: * 1. Saves the S-EL1 system register context tp tsp_ctx->cpu_ctx. * 2. Restores the current C runtime state (callee saved registers) from the * stack frame using the reference to this state saved in tspd_enter_sp(). * 3. It does not need to save any general purpose or EL3 system register state * as the generic smc entry routine should have saved those. ******************************************************************************/ void tspd_synchronous_sp_exit(tsp_context_t *tsp_ctx, uint64_t ret) { assert(tsp_ctx != NULL); /* Save the Secure EL1 system register context */ assert(cm_get_context(SECURE) == &tsp_ctx->cpu_ctx); cm_el1_sysregs_context_save(SECURE); assert(tsp_ctx->c_rt_ctx != 0); tspd_exit_sp(tsp_ctx->c_rt_ctx, ret); /* Should never reach here */ assert(0); } /******************************************************************************* * This function takes an SP context pointer and abort any preempted SMC * request. * Return 1 if there was a preempted SMC request, 0 otherwise. ******************************************************************************/ int tspd_abort_preempted_smc(tsp_context_t *tsp_ctx) { if (!get_yield_smc_active_flag(tsp_ctx->state)) return 0; /* Abort any preempted SMC request */ clr_yield_smc_active_flag(tsp_ctx->state); /* * Arrange for an entry into the test secure payload. It will * be returned via TSP_ABORT_DONE case in tspd_smc_handler. */ cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->abort_yield_smc_entry); uint64_t rc = tspd_synchronous_sp_entry(tsp_ctx); if (rc != 0) panic(); return 1; } trusted-firmware-a-2.2/services/spd/tspd/tspd_helpers.S000066400000000000000000000052441355360272700233210ustar00rootroot00000000000000/* * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "tspd_private.h" .global tspd_enter_sp /* --------------------------------------------- * This function is called with SP_EL0 as stack. * Here we stash our EL3 callee-saved registers * on to the stack as a part of saving the C * runtime and enter the secure payload. * 'x0' contains a pointer to the memory where * the address of the C runtime context is to be * saved. * --------------------------------------------- */ func tspd_enter_sp /* Make space for the registers that we're going to save */ mov x3, sp str x3, [x0, #0] sub sp, sp, #TSPD_C_RT_CTX_SIZE /* Save callee-saved registers on to the stack */ stp x19, x20, [sp, #TSPD_C_RT_CTX_X19] stp x21, x22, [sp, #TSPD_C_RT_CTX_X21] stp x23, x24, [sp, #TSPD_C_RT_CTX_X23] stp x25, x26, [sp, #TSPD_C_RT_CTX_X25] stp x27, x28, [sp, #TSPD_C_RT_CTX_X27] stp x29, x30, [sp, #TSPD_C_RT_CTX_X29] /* --------------------------------------------- * Everything is setup now. el3_exit() will * use the secure context to restore to the * general purpose and EL3 system registers to * ERET into the secure payload. * --------------------------------------------- */ b el3_exit endfunc tspd_enter_sp /* --------------------------------------------- * This function is called 'x0' pointing to a C * runtime context saved in tspd_enter_sp(). It * restores the saved registers and jumps to * that runtime with 'x0' as the new sp. This * destroys the C runtime context that had been * built on the stack below the saved context by * the caller. Later the second parameter 'x1' * is passed as return value to the caller * --------------------------------------------- */ .global tspd_exit_sp func tspd_exit_sp /* Restore the previous stack */ mov sp, x0 /* Restore callee-saved registers on to the stack */ ldp x19, x20, [x0, #(TSPD_C_RT_CTX_X19 - TSPD_C_RT_CTX_SIZE)] ldp x21, x22, [x0, #(TSPD_C_RT_CTX_X21 - TSPD_C_RT_CTX_SIZE)] ldp x23, x24, [x0, #(TSPD_C_RT_CTX_X23 - TSPD_C_RT_CTX_SIZE)] ldp x25, x26, [x0, #(TSPD_C_RT_CTX_X25 - TSPD_C_RT_CTX_SIZE)] ldp x27, x28, [x0, #(TSPD_C_RT_CTX_X27 - TSPD_C_RT_CTX_SIZE)] ldp x29, x30, [x0, #(TSPD_C_RT_CTX_X29 - TSPD_C_RT_CTX_SIZE)] /* --------------------------------------------- * This should take us back to the instruction * after the call to the last tspd_enter_sp(). * Place the second parameter to x0 so that the * caller will see it as a return value from the * original entry call * --------------------------------------------- */ mov x0, x1 ret endfunc tspd_exit_sp trusted-firmware-a-2.2/services/spd/tspd/tspd_main.c000066400000000000000000000531531355360272700226250ustar00rootroot00000000000000/* * Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /******************************************************************************* * This is the Secure Payload Dispatcher (SPD). The dispatcher is meant to be a * plug-in component to the Secure Monitor, registered as a runtime service. The * SPD is expected to be a functional extension of the Secure Payload (SP) that * executes in Secure EL1. The Secure Monitor will delegate all SMCs targeting * the Trusted OS/Applications range to the dispatcher. The SPD will either * handle the request locally or delegate it to the Secure Payload. It is also * responsible for initialising and maintaining communication with the SP. ******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "tspd_private.h" /******************************************************************************* * Address of the entrypoint vector table in the Secure Payload. It is * initialised once on the primary core after a cold boot. ******************************************************************************/ tsp_vectors_t *tsp_vectors; /******************************************************************************* * Array to keep track of per-cpu Secure Payload state ******************************************************************************/ tsp_context_t tspd_sp_context[TSPD_CORE_COUNT]; /* TSP UID */ DEFINE_SVC_UUID2(tsp_uuid, 0xa056305b, 0x9132, 0x7b42, 0x98, 0x11, 0x71, 0x68, 0xca, 0x50, 0xf3, 0xfa); int32_t tspd_init(void); /* * This helper function handles Secure EL1 preemption. The preemption could be * due Non Secure interrupts or EL3 interrupts. In both the cases we context * switch to the normal world and in case of EL3 interrupts, it will again be * routed to EL3 which will get handled at the exception vectors. */ uint64_t tspd_handle_sp_preemption(void *handle) { cpu_context_t *ns_cpu_context; assert(handle == cm_get_context(SECURE)); cm_el1_sysregs_context_save(SECURE); /* Get a reference to the non-secure context */ ns_cpu_context = cm_get_context(NON_SECURE); assert(ns_cpu_context); /* * To allow Secure EL1 interrupt handler to re-enter TSP while TSP * is preempted, the secure system register context which will get * overwritten must be additionally saved. This is currently done * by the TSPD S-EL1 interrupt handler. */ /* * Restore non-secure state. */ cm_el1_sysregs_context_restore(NON_SECURE); cm_set_next_eret_context(NON_SECURE); /* * The TSP was preempted during execution of a Yielding SMC Call. * Return back to the normal world with SMC_PREEMPTED as error * code in x0. */ SMC_RET1(ns_cpu_context, SMC_PREEMPTED); } /******************************************************************************* * This function is the handler registered for S-EL1 interrupts by the TSPD. It * validates the interrupt and upon success arranges entry into the TSP at * 'tsp_sel1_intr_entry()' for handling the interrupt. ******************************************************************************/ static uint64_t tspd_sel1_interrupt_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { uint32_t linear_id; tsp_context_t *tsp_ctx; /* Check the security state when the exception was generated */ assert(get_interrupt_src_ss(flags) == NON_SECURE); /* Sanity check the pointer to this cpu's context */ assert(handle == cm_get_context(NON_SECURE)); /* Save the non-secure context before entering the TSP */ cm_el1_sysregs_context_save(NON_SECURE); /* Get a reference to this cpu's TSP context */ linear_id = plat_my_core_pos(); tsp_ctx = &tspd_sp_context[linear_id]; assert(&tsp_ctx->cpu_ctx == cm_get_context(SECURE)); /* * Determine if the TSP was previously preempted. Its last known * context has to be preserved in this case. * The TSP should return control to the TSPD after handling this * S-EL1 interrupt. Preserve essential EL3 context to allow entry into * the TSP at the S-EL1 interrupt entry point using the 'cpu_context' * structure. There is no need to save the secure system register * context since the TSP is supposed to preserve it during S-EL1 * interrupt handling. */ if (get_yield_smc_active_flag(tsp_ctx->state)) { tsp_ctx->saved_spsr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx, CTX_SPSR_EL3); tsp_ctx->saved_elr_el3 = SMC_GET_EL3(&tsp_ctx->cpu_ctx, CTX_ELR_EL3); #if TSP_NS_INTR_ASYNC_PREEMPT /*Need to save the previously interrupted secure context */ memcpy(&tsp_ctx->sp_ctx, &tsp_ctx->cpu_ctx, TSPD_SP_CTX_SIZE); #endif } cm_el1_sysregs_context_restore(SECURE); cm_set_elr_spsr_el3(SECURE, (uint64_t) &tsp_vectors->sel1_intr_entry, SPSR_64(MODE_EL1, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS)); cm_set_next_eret_context(SECURE); /* * Tell the TSP that it has to handle a S-EL1 interrupt synchronously. * Also the instruction in normal world where the interrupt was * generated is passed for debugging purposes. It is safe to retrieve * this address from ELR_EL3 as the secure context will not take effect * until el3_exit(). */ SMC_RET2(&tsp_ctx->cpu_ctx, TSP_HANDLE_SEL1_INTR_AND_RETURN, read_elr_el3()); } #if TSP_NS_INTR_ASYNC_PREEMPT /******************************************************************************* * This function is the handler registered for Non secure interrupts by the * TSPD. It validates the interrupt and upon success arranges entry into the * normal world for handling the interrupt. ******************************************************************************/ static uint64_t tspd_ns_interrupt_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { /* Check the security state when the exception was generated */ assert(get_interrupt_src_ss(flags) == SECURE); /* * Disable the routing of NS interrupts from secure world to EL3 while * interrupted on this core. */ disable_intr_rm_local(INTR_TYPE_NS, SECURE); return tspd_handle_sp_preemption(handle); } #endif /******************************************************************************* * Secure Payload Dispatcher setup. The SPD finds out the SP entrypoint and type * (aarch32/aarch64) if not already known and initialises the context for entry * into the SP for its initialisation. ******************************************************************************/ static int32_t tspd_setup(void) { entry_point_info_t *tsp_ep_info; uint32_t linear_id; linear_id = plat_my_core_pos(); /* * Get information about the Secure Payload (BL32) image. Its * absence is a critical failure. TODO: Add support to * conditionally include the SPD service */ tsp_ep_info = bl31_plat_get_next_image_ep_info(SECURE); if (!tsp_ep_info) { WARN("No TSP provided by BL2 boot loader, Booting device" " without TSP initialization. SMC`s destined for TSP" " will return SMC_UNK\n"); return 1; } /* * If there's no valid entry point for SP, we return a non-zero value * signalling failure initializing the service. We bail out without * registering any handlers */ if (!tsp_ep_info->pc) return 1; /* * We could inspect the SP image and determine its execution * state i.e whether AArch32 or AArch64. Assuming it's AArch64 * for the time being. */ tspd_init_tsp_ep_state(tsp_ep_info, TSP_AARCH64, tsp_ep_info->pc, &tspd_sp_context[linear_id]); #if TSP_INIT_ASYNC bl31_set_next_image_type(SECURE); #else /* * All TSPD initialization done. Now register our init function with * BL31 for deferred invocation */ bl31_register_bl32_init(&tspd_init); #endif return 0; } /******************************************************************************* * This function passes control to the Secure Payload image (BL32) for the first * time on the primary cpu after a cold boot. It assumes that a valid secure * context has already been created by tspd_setup() which can be directly used. * It also assumes that a valid non-secure context has been initialised by PSCI * so it does not need to save and restore any non-secure state. This function * performs a synchronous entry into the Secure payload. The SP passes control * back to this routine through a SMC. ******************************************************************************/ int32_t tspd_init(void) { uint32_t linear_id = plat_my_core_pos(); tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; entry_point_info_t *tsp_entry_point; uint64_t rc; /* * Get information about the Secure Payload (BL32) image. Its * absence is a critical failure. */ tsp_entry_point = bl31_plat_get_next_image_ep_info(SECURE); assert(tsp_entry_point); cm_init_my_context(tsp_entry_point); /* * Arrange for an entry into the test secure payload. It will be * returned via TSP_ENTRY_DONE case */ rc = tspd_synchronous_sp_entry(tsp_ctx); assert(rc != 0); return rc; } /******************************************************************************* * This function is responsible for handling all SMCs in the Trusted OS/App * range from the non-secure state as defined in the SMC Calling Convention * Document. It is also responsible for communicating with the Secure payload * to delegate work and return results back to the non-secure state. Lastly it * will also return any information that the secure payload needs to do the * work assigned to it. ******************************************************************************/ static uintptr_t tspd_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) { cpu_context_t *ns_cpu_context; uint32_t linear_id = plat_my_core_pos(), ns; tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; uint64_t rc; #if TSP_INIT_ASYNC entry_point_info_t *next_image_info; #endif /* Determine which security state this SMC originated from */ ns = is_caller_non_secure(flags); switch (smc_fid) { /* * This function ID is used by TSP to indicate that it was * preempted by a normal world IRQ. * */ case TSP_PREEMPTED: if (ns) SMC_RET1(handle, SMC_UNK); return tspd_handle_sp_preemption(handle); /* * This function ID is used only by the TSP to indicate that it has * finished handling a S-EL1 interrupt or was preempted by a higher * priority pending EL3 interrupt. Execution should resume * in the normal world. */ case TSP_HANDLED_S_EL1_INTR: if (ns) SMC_RET1(handle, SMC_UNK); assert(handle == cm_get_context(SECURE)); /* * Restore the relevant EL3 state which saved to service * this SMC. */ if (get_yield_smc_active_flag(tsp_ctx->state)) { SMC_SET_EL3(&tsp_ctx->cpu_ctx, CTX_SPSR_EL3, tsp_ctx->saved_spsr_el3); SMC_SET_EL3(&tsp_ctx->cpu_ctx, CTX_ELR_EL3, tsp_ctx->saved_elr_el3); #if TSP_NS_INTR_ASYNC_PREEMPT /* * Need to restore the previously interrupted * secure context. */ memcpy(&tsp_ctx->cpu_ctx, &tsp_ctx->sp_ctx, TSPD_SP_CTX_SIZE); #endif } /* Get a reference to the non-secure context */ ns_cpu_context = cm_get_context(NON_SECURE); assert(ns_cpu_context); /* * Restore non-secure state. There is no need to save the * secure system register context since the TSP was supposed * to preserve it during S-EL1 interrupt handling. */ cm_el1_sysregs_context_restore(NON_SECURE); cm_set_next_eret_context(NON_SECURE); SMC_RET0((uint64_t) ns_cpu_context); /* * This function ID is used only by the SP to indicate it has * finished initialising itself after a cold boot */ case TSP_ENTRY_DONE: if (ns) SMC_RET1(handle, SMC_UNK); /* * Stash the SP entry points information. This is done * only once on the primary cpu */ assert(tsp_vectors == NULL); tsp_vectors = (tsp_vectors_t *) x1; if (tsp_vectors) { set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON); /* * TSP has been successfully initialized. Register power * management hooks with PSCI */ psci_register_spd_pm_hook(&tspd_pm); /* * Register an interrupt handler for S-EL1 interrupts * when generated during code executing in the * non-secure state. */ flags = 0; set_interrupt_rm_flag(flags, NON_SECURE); rc = register_interrupt_type_handler(INTR_TYPE_S_EL1, tspd_sel1_interrupt_handler, flags); if (rc) panic(); #if TSP_NS_INTR_ASYNC_PREEMPT /* * Register an interrupt handler for NS interrupts when * generated during code executing in secure state are * routed to EL3. */ flags = 0; set_interrupt_rm_flag(flags, SECURE); rc = register_interrupt_type_handler(INTR_TYPE_NS, tspd_ns_interrupt_handler, flags); if (rc) panic(); /* * Disable the NS interrupt locally. */ disable_intr_rm_local(INTR_TYPE_NS, SECURE); #endif } #if TSP_INIT_ASYNC /* Save the Secure EL1 system register context */ assert(cm_get_context(SECURE) == &tsp_ctx->cpu_ctx); cm_el1_sysregs_context_save(SECURE); /* Program EL3 registers to enable entry into the next EL */ next_image_info = bl31_plat_get_next_image_ep_info(NON_SECURE); assert(next_image_info); assert(NON_SECURE == GET_SECURITY_STATE(next_image_info->h.attr)); cm_init_my_context(next_image_info); cm_prepare_el3_exit(NON_SECURE); SMC_RET0(cm_get_context(NON_SECURE)); #else /* * SP reports completion. The SPD must have initiated * the original request through a synchronous entry * into the SP. Jump back to the original C runtime * context. */ tspd_synchronous_sp_exit(tsp_ctx, x1); break; #endif /* * This function ID is used only by the SP to indicate it has finished * aborting a preempted Yielding SMC Call. */ case TSP_ABORT_DONE: /* * These function IDs are used only by the SP to indicate it has * finished: * 1. turning itself on in response to an earlier psci * cpu_on request * 2. resuming itself after an earlier psci cpu_suspend * request. */ case TSP_ON_DONE: case TSP_RESUME_DONE: /* * These function IDs are used only by the SP to indicate it has * finished: * 1. suspending itself after an earlier psci cpu_suspend * request. * 2. turning itself off in response to an earlier psci * cpu_off request. */ case TSP_OFF_DONE: case TSP_SUSPEND_DONE: case TSP_SYSTEM_OFF_DONE: case TSP_SYSTEM_RESET_DONE: if (ns) SMC_RET1(handle, SMC_UNK); /* * SP reports completion. The SPD must have initiated the * original request through a synchronous entry into the SP. * Jump back to the original C runtime context, and pass x1 as * return value to the caller */ tspd_synchronous_sp_exit(tsp_ctx, x1); break; /* * Request from non-secure client to perform an * arithmetic operation or response from secure * payload to an earlier request. */ case TSP_FAST_FID(TSP_ADD): case TSP_FAST_FID(TSP_SUB): case TSP_FAST_FID(TSP_MUL): case TSP_FAST_FID(TSP_DIV): case TSP_YIELD_FID(TSP_ADD): case TSP_YIELD_FID(TSP_SUB): case TSP_YIELD_FID(TSP_MUL): case TSP_YIELD_FID(TSP_DIV): if (ns) { /* * This is a fresh request from the non-secure client. * The parameters are in x1 and x2. Figure out which * registers need to be preserved, save the non-secure * state and send the request to the secure payload. */ assert(handle == cm_get_context(NON_SECURE)); /* Check if we are already preempted */ if (get_yield_smc_active_flag(tsp_ctx->state)) SMC_RET1(handle, SMC_UNK); cm_el1_sysregs_context_save(NON_SECURE); /* Save x1 and x2 for use by TSP_GET_ARGS call below */ store_tsp_args(tsp_ctx, x1, x2); /* * We are done stashing the non-secure context. Ask the * secure payload to do the work now. */ /* * Verify if there is a valid context to use, copy the * operation type and parameters to the secure context * and jump to the fast smc entry point in the secure * payload. Entry into S-EL1 will take place upon exit * from this function. */ assert(&tsp_ctx->cpu_ctx == cm_get_context(SECURE)); /* Set appropriate entry for SMC. * We expect the TSP to manage the PSTATE.I and PSTATE.F * flags as appropriate. */ if (GET_SMC_TYPE(smc_fid) == SMC_TYPE_FAST) { cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->fast_smc_entry); } else { set_yield_smc_active_flag(tsp_ctx->state); cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->yield_smc_entry); #if TSP_NS_INTR_ASYNC_PREEMPT /* * Enable the routing of NS interrupts to EL3 * during processing of a Yielding SMC Call on * this core. */ enable_intr_rm_local(INTR_TYPE_NS, SECURE); #endif #if EL3_EXCEPTION_HANDLING /* * With EL3 exception handling, while an SMC is * being processed, Non-secure interrupts can't * preempt Secure execution. However, for * yielding SMCs, we want preemption to happen; * so explicitly allow NS preemption in this * case, and supply the preemption return code * for TSP. */ ehf_allow_ns_preemption(TSP_PREEMPTED); #endif } cm_el1_sysregs_context_restore(SECURE); cm_set_next_eret_context(SECURE); SMC_RET3(&tsp_ctx->cpu_ctx, smc_fid, x1, x2); } else { /* * This is the result from the secure client of an * earlier request. The results are in x1-x3. Copy it * into the non-secure context, save the secure state * and return to the non-secure state. */ assert(handle == cm_get_context(SECURE)); cm_el1_sysregs_context_save(SECURE); /* Get a reference to the non-secure context */ ns_cpu_context = cm_get_context(NON_SECURE); assert(ns_cpu_context); /* Restore non-secure state */ cm_el1_sysregs_context_restore(NON_SECURE); cm_set_next_eret_context(NON_SECURE); if (GET_SMC_TYPE(smc_fid) == SMC_TYPE_YIELD) { clr_yield_smc_active_flag(tsp_ctx->state); #if TSP_NS_INTR_ASYNC_PREEMPT /* * Disable the routing of NS interrupts to EL3 * after processing of a Yielding SMC Call on * this core is finished. */ disable_intr_rm_local(INTR_TYPE_NS, SECURE); #endif } SMC_RET3(ns_cpu_context, x1, x2, x3); } assert(0); /* Unreachable */ /* * Request from the non-secure world to abort a preempted Yielding SMC * Call. */ case TSP_FID_ABORT: /* ABORT should only be invoked by normal world */ if (!ns) { assert(0); break; } assert(handle == cm_get_context(NON_SECURE)); cm_el1_sysregs_context_save(NON_SECURE); /* Abort the preempted SMC request */ if (!tspd_abort_preempted_smc(tsp_ctx)) { /* * If there was no preempted SMC to abort, return * SMC_UNK. * * Restoring the NON_SECURE context is not necessary as * the synchronous entry did not take place if the * return code of tspd_abort_preempted_smc is zero. */ cm_set_next_eret_context(NON_SECURE); break; } cm_el1_sysregs_context_restore(NON_SECURE); cm_set_next_eret_context(NON_SECURE); SMC_RET1(handle, SMC_OK); /* * Request from non secure world to resume the preempted * Yielding SMC Call. */ case TSP_FID_RESUME: /* RESUME should be invoked only by normal world */ if (!ns) { assert(0); break; } /* * This is a resume request from the non-secure client. * save the non-secure state and send the request to * the secure payload. */ assert(handle == cm_get_context(NON_SECURE)); /* Check if we are already preempted before resume */ if (!get_yield_smc_active_flag(tsp_ctx->state)) SMC_RET1(handle, SMC_UNK); cm_el1_sysregs_context_save(NON_SECURE); /* * We are done stashing the non-secure context. Ask the * secure payload to do the work now. */ #if TSP_NS_INTR_ASYNC_PREEMPT /* * Enable the routing of NS interrupts to EL3 during resumption * of a Yielding SMC Call on this core. */ enable_intr_rm_local(INTR_TYPE_NS, SECURE); #endif #if EL3_EXCEPTION_HANDLING /* * Allow the resumed yielding SMC processing to be preempted by * Non-secure interrupts. Also, supply the preemption return * code for TSP. */ ehf_allow_ns_preemption(TSP_PREEMPTED); #endif /* We just need to return to the preempted point in * TSP and the execution will resume as normal. */ cm_el1_sysregs_context_restore(SECURE); cm_set_next_eret_context(SECURE); SMC_RET0(&tsp_ctx->cpu_ctx); /* * This is a request from the secure payload for more arguments * for an ongoing arithmetic operation requested by the * non-secure world. Simply return the arguments from the non- * secure client in the original call. */ case TSP_GET_ARGS: if (ns) SMC_RET1(handle, SMC_UNK); get_tsp_args(tsp_ctx, x1, x2); SMC_RET2(handle, x1, x2); case TOS_CALL_COUNT: /* * Return the number of service function IDs implemented to * provide service to non-secure */ SMC_RET1(handle, TSP_NUM_FID); case TOS_UID: /* Return TSP UID to the caller */ SMC_UUID_RET(handle, tsp_uuid); case TOS_CALL_VERSION: /* Return the version of current implementation */ SMC_RET2(handle, TSP_VERSION_MAJOR, TSP_VERSION_MINOR); default: break; } SMC_RET1(handle, SMC_UNK); } /* Define a SPD runtime service descriptor for fast SMC calls */ DECLARE_RT_SVC( tspd_fast, OEN_TOS_START, OEN_TOS_END, SMC_TYPE_FAST, tspd_setup, tspd_smc_handler ); /* Define a SPD runtime service descriptor for Yielding SMC Calls */ DECLARE_RT_SVC( tspd_std, OEN_TOS_START, OEN_TOS_END, SMC_TYPE_YIELD, NULL, tspd_smc_handler ); trusted-firmware-a-2.2/services/spd/tspd/tspd_pm.c000066400000000000000000000202101355360272700223010ustar00rootroot00000000000000/* * Copyright (c) 2013-2016, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "tspd_private.h" /******************************************************************************* * The target cpu is being turned on. Allow the TSPD/TSP to perform any actions * needed. Nothing at the moment. ******************************************************************************/ static void tspd_cpu_on_handler(u_register_t target_cpu) { } /******************************************************************************* * This cpu is being turned off. Allow the TSPD/TSP to perform any actions * needed ******************************************************************************/ static int32_t tspd_cpu_off_handler(u_register_t unused) { int32_t rc = 0; uint32_t linear_id = plat_my_core_pos(); tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; assert(tsp_vectors); assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON); /* * Abort any preempted SMC request before overwriting the SECURE * context. */ tspd_abort_preempted_smc(tsp_ctx); /* Program the entry point and enter the TSP */ cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_off_entry); rc = tspd_synchronous_sp_entry(tsp_ctx); /* * Read the response from the TSP. A non-zero return means that * something went wrong while communicating with the TSP. */ if (rc != 0) panic(); /* * Reset TSP's context for a fresh start when this cpu is turned on * subsequently. */ set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_OFF); return 0; } /******************************************************************************* * This cpu is being suspended. S-EL1 state must have been saved in the * resident cpu (mpidr format) if it is a UP/UP migratable TSP. ******************************************************************************/ static void tspd_cpu_suspend_handler(u_register_t max_off_pwrlvl) { int32_t rc = 0; uint32_t linear_id = plat_my_core_pos(); tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; assert(tsp_vectors); assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON); /* * Abort any preempted SMC request before overwriting the SECURE * context. */ tspd_abort_preempted_smc(tsp_ctx); /* Program the entry point and enter the TSP */ cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_suspend_entry); rc = tspd_synchronous_sp_entry(tsp_ctx); /* * Read the response from the TSP. A non-zero return means that * something went wrong while communicating with the TSP. */ if (rc) panic(); /* Update its context to reflect the state the TSP is in */ set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_SUSPEND); } /******************************************************************************* * This cpu has been turned on. Enter the TSP to initialise S-EL1 and other bits * before passing control back to the Secure Monitor. Entry in S-EL1 is done * after initialising minimal architectural state that guarantees safe * execution. ******************************************************************************/ static void tspd_cpu_on_finish_handler(u_register_t unused) { int32_t rc = 0; uint32_t linear_id = plat_my_core_pos(); tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; entry_point_info_t tsp_on_entrypoint; assert(tsp_vectors); assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_OFF); tspd_init_tsp_ep_state(&tsp_on_entrypoint, TSP_AARCH64, (uint64_t) &tsp_vectors->cpu_on_entry, tsp_ctx); /* Initialise this cpu's secure context */ cm_init_my_context(&tsp_on_entrypoint); #if TSP_NS_INTR_ASYNC_PREEMPT /* * Disable the NS interrupt locally since it will be enabled globally * within cm_init_my_context. */ disable_intr_rm_local(INTR_TYPE_NS, SECURE); #endif /* Enter the TSP */ rc = tspd_synchronous_sp_entry(tsp_ctx); /* * Read the response from the TSP. A non-zero return means that * something went wrong while communicating with the SP. */ if (rc != 0) panic(); /* Update its context to reflect the state the SP is in */ set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON); } /******************************************************************************* * This cpu has resumed from suspend. The SPD saved the TSP context when it * completed the preceding suspend call. Use that context to program an entry * into the TSP to allow it to do any remaining book keeping ******************************************************************************/ static void tspd_cpu_suspend_finish_handler(u_register_t max_off_pwrlvl) { int32_t rc = 0; uint32_t linear_id = plat_my_core_pos(); tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; assert(tsp_vectors); assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_SUSPEND); /* Program the entry point, max_off_pwrlvl and enter the SP */ write_ctx_reg(get_gpregs_ctx(&tsp_ctx->cpu_ctx), CTX_GPREG_X0, max_off_pwrlvl); cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_resume_entry); rc = tspd_synchronous_sp_entry(tsp_ctx); /* * Read the response from the TSP. A non-zero return means that * something went wrong while communicating with the TSP. */ if (rc != 0) panic(); /* Update its context to reflect the state the SP is in */ set_tsp_pstate(tsp_ctx->state, TSP_PSTATE_ON); } /******************************************************************************* * Return the type of TSP the TSPD is dealing with. Report the current resident * cpu (mpidr format) if it is a UP/UP migratable TSP. ******************************************************************************/ static int32_t tspd_cpu_migrate_info(u_register_t *resident_cpu) { return TSP_MIGRATE_INFO; } /******************************************************************************* * System is about to be switched off. Allow the TSPD/TSP to perform * any actions needed. ******************************************************************************/ static void tspd_system_off(void) { uint32_t linear_id = plat_my_core_pos(); tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; assert(tsp_vectors); assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON); /* * Abort any preempted SMC request before overwriting the SECURE * context. */ tspd_abort_preempted_smc(tsp_ctx); /* Program the entry point */ cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->system_off_entry); /* Enter the TSP. We do not care about the return value because we * must continue the shutdown anyway */ tspd_synchronous_sp_entry(tsp_ctx); } /******************************************************************************* * System is about to be reset. Allow the TSPD/TSP to perform * any actions needed. ******************************************************************************/ static void tspd_system_reset(void) { uint32_t linear_id = plat_my_core_pos(); tsp_context_t *tsp_ctx = &tspd_sp_context[linear_id]; assert(tsp_vectors); assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_ON); /* * Abort any preempted SMC request before overwriting the SECURE * context. */ tspd_abort_preempted_smc(tsp_ctx); /* Program the entry point */ cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->system_reset_entry); /* * Enter the TSP. We do not care about the return value because we * must continue the reset anyway */ tspd_synchronous_sp_entry(tsp_ctx); } /******************************************************************************* * Structure populated by the TSP Dispatcher to be given a chance to perform any * TSP bookkeeping before PSCI executes a power mgmt. operation. ******************************************************************************/ const spd_pm_ops_t tspd_pm = { .svc_on = tspd_cpu_on_handler, .svc_off = tspd_cpu_off_handler, .svc_suspend = tspd_cpu_suspend_handler, .svc_on_finish = tspd_cpu_on_finish_handler, .svc_suspend_finish = tspd_cpu_suspend_finish_handler, .svc_migrate = NULL, .svc_migrate_info = tspd_cpu_migrate_info, .svc_system_off = tspd_system_off, .svc_system_reset = tspd_system_reset }; trusted-firmware-a-2.2/services/spd/tspd/tspd_private.h000066400000000000000000000220161355360272700233520ustar00rootroot00000000000000/* * Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TSPD_PRIVATE_H #define TSPD_PRIVATE_H #include #include #include #include #include /******************************************************************************* * Secure Payload PM state information e.g. SP is suspended, uninitialised etc * and macros to access the state information in the per-cpu 'state' flags ******************************************************************************/ #define TSP_PSTATE_OFF 0 #define TSP_PSTATE_ON 1 #define TSP_PSTATE_SUSPEND 2 #define TSP_PSTATE_SHIFT 0 #define TSP_PSTATE_MASK 0x3 #define get_tsp_pstate(state) ((state >> TSP_PSTATE_SHIFT) & TSP_PSTATE_MASK) #define clr_tsp_pstate(state) (state &= ~(TSP_PSTATE_MASK \ << TSP_PSTATE_SHIFT)) #define set_tsp_pstate(st, pst) do { \ clr_tsp_pstate(st); \ st |= (pst & TSP_PSTATE_MASK) << \ TSP_PSTATE_SHIFT; \ } while (0); /* * This flag is used by the TSPD to determine if the TSP is servicing a yielding * SMC request prior to programming the next entry into the TSP e.g. if TSP * execution is preempted by a non-secure interrupt and handed control to the * normal world. If another request which is distinct from what the TSP was * previously doing arrives, then this flag will be help the TSPD to either * reject the new request or service it while ensuring that the previous context * is not corrupted. */ #define YIELD_SMC_ACTIVE_FLAG_SHIFT 2 #define YIELD_SMC_ACTIVE_FLAG_MASK 1 #define get_yield_smc_active_flag(state) \ ((state >> YIELD_SMC_ACTIVE_FLAG_SHIFT) \ & YIELD_SMC_ACTIVE_FLAG_MASK) #define set_yield_smc_active_flag(state) (state |= \ 1 << YIELD_SMC_ACTIVE_FLAG_SHIFT) #define clr_yield_smc_active_flag(state) (state &= \ ~(YIELD_SMC_ACTIVE_FLAG_MASK \ << YIELD_SMC_ACTIVE_FLAG_SHIFT)) /******************************************************************************* * Secure Payload execution state information i.e. aarch32 or aarch64 ******************************************************************************/ #define TSP_AARCH32 MODE_RW_32 #define TSP_AARCH64 MODE_RW_64 /******************************************************************************* * The SPD should know the type of Secure Payload. ******************************************************************************/ #define TSP_TYPE_UP PSCI_TOS_NOT_UP_MIG_CAP #define TSP_TYPE_UPM PSCI_TOS_UP_MIG_CAP #define TSP_TYPE_MP PSCI_TOS_NOT_PRESENT_MP /******************************************************************************* * Secure Payload migrate type information as known to the SPD. We assume that * the SPD is dealing with an MP Secure Payload. ******************************************************************************/ #define TSP_MIGRATE_INFO TSP_TYPE_MP /******************************************************************************* * Number of cpus that the present on this platform. TODO: Rely on a topology * tree to determine this in the future to avoid assumptions about mpidr * allocation ******************************************************************************/ #define TSPD_CORE_COUNT PLATFORM_CORE_COUNT /******************************************************************************* * Constants that allow assembler code to preserve callee-saved registers of the * C runtime context while performing a security state switch. ******************************************************************************/ #define TSPD_C_RT_CTX_X19 0x0 #define TSPD_C_RT_CTX_X20 0x8 #define TSPD_C_RT_CTX_X21 0x10 #define TSPD_C_RT_CTX_X22 0x18 #define TSPD_C_RT_CTX_X23 0x20 #define TSPD_C_RT_CTX_X24 0x28 #define TSPD_C_RT_CTX_X25 0x30 #define TSPD_C_RT_CTX_X26 0x38 #define TSPD_C_RT_CTX_X27 0x40 #define TSPD_C_RT_CTX_X28 0x48 #define TSPD_C_RT_CTX_X29 0x50 #define TSPD_C_RT_CTX_X30 0x58 #define TSPD_C_RT_CTX_SIZE 0x60 #define TSPD_C_RT_CTX_ENTRIES (TSPD_C_RT_CTX_SIZE >> DWORD_SHIFT) /******************************************************************************* * Constants that allow assembler code to preserve caller-saved registers of the * SP context while performing a TSP preemption. * Note: These offsets have to match with the offsets for the corresponding * registers in cpu_context as we are using memcpy to copy the values from * cpu_context to sp_ctx. ******************************************************************************/ #define TSPD_SP_CTX_X0 0x0 #define TSPD_SP_CTX_X1 0x8 #define TSPD_SP_CTX_X2 0x10 #define TSPD_SP_CTX_X3 0x18 #define TSPD_SP_CTX_X4 0x20 #define TSPD_SP_CTX_X5 0x28 #define TSPD_SP_CTX_X6 0x30 #define TSPD_SP_CTX_X7 0x38 #define TSPD_SP_CTX_X8 0x40 #define TSPD_SP_CTX_X9 0x48 #define TSPD_SP_CTX_X10 0x50 #define TSPD_SP_CTX_X11 0x58 #define TSPD_SP_CTX_X12 0x60 #define TSPD_SP_CTX_X13 0x68 #define TSPD_SP_CTX_X14 0x70 #define TSPD_SP_CTX_X15 0x78 #define TSPD_SP_CTX_X16 0x80 #define TSPD_SP_CTX_X17 0x88 #define TSPD_SP_CTX_SIZE 0x90 #define TSPD_SP_CTX_ENTRIES (TSPD_SP_CTX_SIZE >> DWORD_SHIFT) #ifndef __ASSEMBLER__ #include #include /* * The number of arguments to save during a SMC call for TSP. * Currently only x1 and x2 are used by TSP. */ #define TSP_NUM_ARGS 0x2 /* AArch64 callee saved general purpose register context structure. */ DEFINE_REG_STRUCT(c_rt_regs, TSPD_C_RT_CTX_ENTRIES); /* * Compile time assertion to ensure that both the compiler and linker * have the same double word aligned view of the size of the C runtime * register context. */ CASSERT(TSPD_C_RT_CTX_SIZE == sizeof(c_rt_regs_t), \ assert_spd_c_rt_regs_size_mismatch); /* SEL1 Secure payload (SP) caller saved register context structure. */ DEFINE_REG_STRUCT(sp_ctx_regs, TSPD_SP_CTX_ENTRIES); /* * Compile time assertion to ensure that both the compiler and linker * have the same double word aligned view of the size of the C runtime * register context. */ CASSERT(TSPD_SP_CTX_SIZE == sizeof(sp_ctx_regs_t), \ assert_spd_sp_regs_size_mismatch); /******************************************************************************* * Structure which helps the SPD to maintain the per-cpu state of the SP. * 'saved_spsr_el3' - temporary copy to allow S-EL1 interrupt handling when * the TSP has been preempted. * 'saved_elr_el3' - temporary copy to allow S-EL1 interrupt handling when * the TSP has been preempted. * 'state' - collection of flags to track SP state e.g. on/off * 'mpidr' - mpidr to associate a context with a cpu * 'c_rt_ctx' - stack address to restore C runtime context from after * returning from a synchronous entry into the SP. * 'cpu_ctx' - space to maintain SP architectural state * 'saved_tsp_args' - space to store arguments for TSP arithmetic operations * which will queried using the TSP_GET_ARGS SMC by TSP. * 'sp_ctx' - space to save the SEL1 Secure Payload(SP) caller saved * register context after it has been preempted by an EL3 * routed NS interrupt and when a Secure Interrupt is taken * to SP. ******************************************************************************/ typedef struct tsp_context { uint64_t saved_elr_el3; uint32_t saved_spsr_el3; uint32_t state; uint64_t mpidr; uint64_t c_rt_ctx; cpu_context_t cpu_ctx; uint64_t saved_tsp_args[TSP_NUM_ARGS]; #if TSP_NS_INTR_ASYNC_PREEMPT sp_ctx_regs_t sp_ctx; #endif } tsp_context_t; /* Helper macros to store and retrieve tsp args from tsp_context */ #define store_tsp_args(_tsp_ctx, _x1, _x2) do {\ _tsp_ctx->saved_tsp_args[0] = _x1;\ _tsp_ctx->saved_tsp_args[1] = _x2;\ } while (0) #define get_tsp_args(_tsp_ctx, _x1, _x2) do {\ _x1 = _tsp_ctx->saved_tsp_args[0];\ _x2 = _tsp_ctx->saved_tsp_args[1];\ } while (0) /* TSPD power management handlers */ extern const spd_pm_ops_t tspd_pm; /******************************************************************************* * Forward declarations ******************************************************************************/ typedef struct tsp_vectors tsp_vectors_t; /******************************************************************************* * Function & Data prototypes ******************************************************************************/ uint64_t tspd_enter_sp(uint64_t *c_rt_ctx); void __dead2 tspd_exit_sp(uint64_t c_rt_ctx, uint64_t ret); uint64_t tspd_synchronous_sp_entry(tsp_context_t *tsp_ctx); void __dead2 tspd_synchronous_sp_exit(tsp_context_t *tsp_ctx, uint64_t ret); void tspd_init_tsp_ep_state(struct entry_point_info *tsp_entry_point, uint32_t rw, uint64_t pc, tsp_context_t *tsp_ctx); int tspd_abort_preempted_smc(tsp_context_t *tsp_ctx); uint64_t tspd_handle_sp_preemption(void *handle); extern tsp_context_t tspd_sp_context[TSPD_CORE_COUNT]; extern tsp_vectors_t *tsp_vectors; #endif /*__ASSEMBLER__*/ #endif /* TSPD_PRIVATE_H */ trusted-firmware-a-2.2/services/std_svc/000077500000000000000000000000001355360272700204015ustar00rootroot00000000000000trusted-firmware-a-2.2/services/std_svc/sdei/000077500000000000000000000000001355360272700213255ustar00rootroot00000000000000trusted-firmware-a-2.2/services/std_svc/sdei/sdei_dispatch.S000066400000000000000000000011501355360272700242510ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include .globl begin_sdei_synchronous_dispatch /* * void begin_sdei_synchronous_dispatch(jmp_buf *buffer); * * Begin SDEI dispatch synchronously by setting up a jump point, and exiting * EL3. This jump point is jumped to by the dispatcher after the event is * completed by the client. */ func begin_sdei_synchronous_dispatch stp x30, xzr, [sp, #-16]! bl setjmp cbz x0, 1f ldp x30, xzr, [sp], #16 ret 1: b el3_exit endfunc begin_sdei_synchronous_dispatch trusted-firmware-a-2.2/services/std_svc/sdei/sdei_event.c000066400000000000000000000047371355360272700236310ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "sdei_private.h" #define MAP_OFF(_map, _mapping) ((_map) - (_mapping)->map) /* * Get SDEI entry with the given mapping: on success, returns pointer to SDEI * entry. On error, returns NULL. * * Both shared and private maps are stored in single-dimensional array. Private * event entries are kept for each PE forming a 2D array. */ sdei_entry_t *get_event_entry(sdei_ev_map_t *map) { const sdei_mapping_t *mapping; sdei_entry_t *cpu_priv_base; unsigned int base_idx; long int idx; if (is_event_private(map)) { /* * For a private map, find the index of the mapping in the * array. */ mapping = SDEI_PRIVATE_MAPPING(); idx = MAP_OFF(map, mapping); /* Base of private mappings for this CPU */ base_idx = plat_my_core_pos() * ((unsigned int) mapping->num_maps); cpu_priv_base = &sdei_private_event_table[base_idx]; /* * Return the address of the entry at the same index in the * per-CPU event entry. */ return &cpu_priv_base[idx]; } else { mapping = SDEI_SHARED_MAPPING(); idx = MAP_OFF(map, mapping); return &sdei_shared_event_table[idx]; } } /* * Find event mapping for a given interrupt number: On success, returns pointer * to the event mapping. On error, returns NULL. */ sdei_ev_map_t *find_event_map_by_intr(unsigned int intr_num, bool shared) { const sdei_mapping_t *mapping; sdei_ev_map_t *map; unsigned int i; /* * Look for a match in private and shared mappings, as requested. This * is a linear search. However, if the mappings are required to be * sorted, for large maps, we could consider binary search. */ mapping = shared ? SDEI_SHARED_MAPPING() : SDEI_PRIVATE_MAPPING(); iterate_mapping(mapping, i, map) { if (map->intr == intr_num) return map; } return NULL; } /* * Find event mapping for a given event number: On success returns pointer to * the event mapping. On error, returns NULL. */ sdei_ev_map_t *find_event_map(int ev_num) { const sdei_mapping_t *mapping; sdei_ev_map_t *map; unsigned int i, j; /* * Iterate through mappings to find a match. This is a linear search. * However, if the mappings are required to be sorted, for large maps, * we could consider binary search. */ for_each_mapping_type(i, mapping) { iterate_mapping(mapping, j, map) { if (map->ev_num == ev_num) return map; } } return NULL; } trusted-firmware-a-2.2/services/std_svc/sdei/sdei_intr_mgmt.c000066400000000000000000000451661355360272700245110ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "sdei_private.h" /* x0-x17 GPREGS context */ #define SDEI_SAVED_GPREGS 18U /* Maximum preemption nesting levels: Critical priority and Normal priority */ #define MAX_EVENT_NESTING 2U /* Per-CPU SDEI state access macro */ #define sdei_get_this_pe_state() (&cpu_state[plat_my_core_pos()]) /* Structure to store information about an outstanding dispatch */ typedef struct sdei_dispatch_context { sdei_ev_map_t *map; uint64_t x[SDEI_SAVED_GPREGS]; jmp_buf *dispatch_jmp; /* Exception state registers */ uint64_t elr_el3; uint64_t spsr_el3; #if DYNAMIC_WORKAROUND_CVE_2018_3639 /* CVE-2018-3639 mitigation state */ uint64_t disable_cve_2018_3639; #endif } sdei_dispatch_context_t; /* Per-CPU SDEI state data */ typedef struct sdei_cpu_state { sdei_dispatch_context_t dispatch_stack[MAX_EVENT_NESTING]; unsigned short stack_top; /* Empty ascending */ bool pe_masked; bool pending_enables; } sdei_cpu_state_t; /* SDEI states for all cores in the system */ static sdei_cpu_state_t cpu_state[PLATFORM_CORE_COUNT]; int64_t sdei_pe_mask(void) { int64_t ret = 0; sdei_cpu_state_t *state = sdei_get_this_pe_state(); /* * Return value indicates whether this call had any effect in the mask * status of this PE. */ if (!state->pe_masked) { state->pe_masked = true; ret = 1; } return ret; } void sdei_pe_unmask(void) { unsigned int i; sdei_ev_map_t *map; sdei_entry_t *se; sdei_cpu_state_t *state = sdei_get_this_pe_state(); uint64_t my_mpidr = read_mpidr_el1() & MPIDR_AFFINITY_MASK; /* * If there are pending enables, iterate through the private mappings * and enable those bound maps that are in enabled state. Also, iterate * through shared mappings and enable interrupts of events that are * targeted to this PE. */ if (state->pending_enables) { for_each_private_map(i, map) { se = get_event_entry(map); if (is_map_bound(map) && GET_EV_STATE(se, ENABLED)) plat_ic_enable_interrupt(map->intr); } for_each_shared_map(i, map) { se = get_event_entry(map); sdei_map_lock(map); if (is_map_bound(map) && GET_EV_STATE(se, ENABLED) && (se->reg_flags == SDEI_REGF_RM_PE) && (se->affinity == my_mpidr)) { plat_ic_enable_interrupt(map->intr); } sdei_map_unlock(map); } } state->pending_enables = false; state->pe_masked = false; } /* Push a dispatch context to the dispatch stack */ static sdei_dispatch_context_t *push_dispatch(void) { sdei_cpu_state_t *state = sdei_get_this_pe_state(); sdei_dispatch_context_t *disp_ctx; /* Cannot have more than max events */ assert(state->stack_top < MAX_EVENT_NESTING); disp_ctx = &state->dispatch_stack[state->stack_top]; state->stack_top++; return disp_ctx; } /* Pop a dispatch context to the dispatch stack */ static sdei_dispatch_context_t *pop_dispatch(void) { sdei_cpu_state_t *state = sdei_get_this_pe_state(); if (state->stack_top == 0U) return NULL; assert(state->stack_top <= MAX_EVENT_NESTING); state->stack_top--; return &state->dispatch_stack[state->stack_top]; } /* Retrieve the context at the top of dispatch stack */ static sdei_dispatch_context_t *get_outstanding_dispatch(void) { sdei_cpu_state_t *state = sdei_get_this_pe_state(); if (state->stack_top == 0U) return NULL; assert(state->stack_top <= MAX_EVENT_NESTING); return &state->dispatch_stack[state->stack_top - 1U]; } static sdei_dispatch_context_t *save_event_ctx(sdei_ev_map_t *map, void *tgt_ctx) { sdei_dispatch_context_t *disp_ctx; const gp_regs_t *tgt_gpregs; const el3_state_t *tgt_el3; assert(tgt_ctx != NULL); tgt_gpregs = get_gpregs_ctx(tgt_ctx); tgt_el3 = get_el3state_ctx(tgt_ctx); disp_ctx = push_dispatch(); assert(disp_ctx != NULL); disp_ctx->map = map; /* Save general purpose and exception registers */ memcpy(disp_ctx->x, tgt_gpregs, sizeof(disp_ctx->x)); disp_ctx->spsr_el3 = read_ctx_reg(tgt_el3, CTX_SPSR_EL3); disp_ctx->elr_el3 = read_ctx_reg(tgt_el3, CTX_ELR_EL3); return disp_ctx; } static void restore_event_ctx(const sdei_dispatch_context_t *disp_ctx, void *tgt_ctx) { gp_regs_t *tgt_gpregs; el3_state_t *tgt_el3; assert(tgt_ctx != NULL); tgt_gpregs = get_gpregs_ctx(tgt_ctx); tgt_el3 = get_el3state_ctx(tgt_ctx); CASSERT(sizeof(disp_ctx->x) == (SDEI_SAVED_GPREGS * sizeof(uint64_t)), foo); /* Restore general purpose and exception registers */ memcpy(tgt_gpregs, disp_ctx->x, sizeof(disp_ctx->x)); write_ctx_reg(tgt_el3, CTX_SPSR_EL3, disp_ctx->spsr_el3); write_ctx_reg(tgt_el3, CTX_ELR_EL3, disp_ctx->elr_el3); #if DYNAMIC_WORKAROUND_CVE_2018_3639 cve_2018_3639_t *tgt_cve_2018_3639; tgt_cve_2018_3639 = get_cve_2018_3639_ctx(tgt_ctx); /* Restore CVE-2018-3639 mitigation state */ write_ctx_reg(tgt_cve_2018_3639, CTX_CVE_2018_3639_DISABLE, disp_ctx->disable_cve_2018_3639); #endif } static void save_secure_context(void) { cm_el1_sysregs_context_save(SECURE); } /* Restore Secure context and arrange to resume it at the next ERET */ static void restore_and_resume_secure_context(void) { cm_el1_sysregs_context_restore(SECURE); cm_set_next_eret_context(SECURE); } /* * Restore Non-secure context and arrange to resume it at the next ERET. Return * pointer to the Non-secure context. */ static cpu_context_t *restore_and_resume_ns_context(void) { cpu_context_t *ns_ctx; cm_el1_sysregs_context_restore(NON_SECURE); cm_set_next_eret_context(NON_SECURE); ns_ctx = cm_get_context(NON_SECURE); assert(ns_ctx != NULL); return ns_ctx; } /* * Populate the Non-secure context so that the next ERET will dispatch to the * SDEI client. */ static void setup_ns_dispatch(sdei_ev_map_t *map, sdei_entry_t *se, cpu_context_t *ctx, jmp_buf *dispatch_jmp) { sdei_dispatch_context_t *disp_ctx; /* Push the event and context */ disp_ctx = save_event_ctx(map, ctx); /* * Setup handler arguments: * * - x0: Event number * - x1: Handler argument supplied at the time of event registration * - x2: Interrupted PC * - x3: Interrupted SPSR */ SMC_SET_GP(ctx, CTX_GPREG_X0, (uint64_t) map->ev_num); SMC_SET_GP(ctx, CTX_GPREG_X1, se->arg); SMC_SET_GP(ctx, CTX_GPREG_X2, disp_ctx->elr_el3); SMC_SET_GP(ctx, CTX_GPREG_X3, disp_ctx->spsr_el3); /* * Prepare for ERET: * * - Set PC to the registered handler address * - Set SPSR to jump to client EL with exceptions masked */ cm_set_elr_spsr_el3(NON_SECURE, (uintptr_t) se->ep, SPSR_64(sdei_client_el(), MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS)); #if DYNAMIC_WORKAROUND_CVE_2018_3639 cve_2018_3639_t *tgt_cve_2018_3639; tgt_cve_2018_3639 = get_cve_2018_3639_ctx(ctx); /* Save CVE-2018-3639 mitigation state */ disp_ctx->disable_cve_2018_3639 = read_ctx_reg(tgt_cve_2018_3639, CTX_CVE_2018_3639_DISABLE); /* Force SDEI handler to execute with mitigation enabled by default */ write_ctx_reg(tgt_cve_2018_3639, CTX_CVE_2018_3639_DISABLE, 0); #endif disp_ctx->dispatch_jmp = dispatch_jmp; } /* Handle a triggered SDEI interrupt while events were masked on this PE */ static void handle_masked_trigger(sdei_ev_map_t *map, sdei_entry_t *se, sdei_cpu_state_t *state, unsigned int intr_raw) { uint64_t my_mpidr __unused = (read_mpidr_el1() & MPIDR_AFFINITY_MASK); bool disable = false; /* Nothing to do for event 0 */ if (map->ev_num == SDEI_EVENT_0) return; /* * For a private event, or for a shared event specifically routed to * this CPU, we disable interrupt, leave the interrupt pending, and do * EOI. */ if (is_event_private(map) || (se->reg_flags == SDEI_REGF_RM_PE)) disable = true; if (se->reg_flags == SDEI_REGF_RM_PE) assert(se->affinity == my_mpidr); if (disable) { plat_ic_disable_interrupt(map->intr); plat_ic_set_interrupt_pending(map->intr); plat_ic_end_of_interrupt(intr_raw); state->pending_enables = true; return; } /* * We just received a shared event with routing set to ANY PE. The * interrupt can't be delegated on this PE as SDEI events are masked. * However, because its routing mode is ANY, it is possible that the * event can be delegated on any other PE that hasn't masked events. * Therefore, we set the interrupt back pending so as to give other * suitable PEs a chance of handling it. */ assert(plat_ic_is_spi(map->intr) != 0); plat_ic_set_interrupt_pending(map->intr); /* * Leaving the same interrupt pending also means that the same interrupt * can target this PE again as soon as this PE leaves EL3. Whether and * how often that happens depends on the implementation of GIC. * * We therefore call a platform handler to resolve this situation. */ plat_sdei_handle_masked_trigger(my_mpidr, map->intr); /* This PE is masked. We EOI the interrupt, as it can't be delegated */ plat_ic_end_of_interrupt(intr_raw); } /* SDEI main interrupt handler */ int sdei_intr_handler(uint32_t intr_raw, uint32_t flags, void *handle, void *cookie) { sdei_entry_t *se; cpu_context_t *ctx; sdei_ev_map_t *map; const sdei_dispatch_context_t *disp_ctx; unsigned int sec_state; sdei_cpu_state_t *state; uint32_t intr; jmp_buf dispatch_jmp; const uint64_t mpidr = read_mpidr_el1(); /* * To handle an event, the following conditions must be true: * * 1. Event must be signalled * 2. Event must be enabled * 3. This PE must be a target PE for the event * 4. PE must be unmasked for SDEI * 5. If this is a normal event, no event must be running * 6. If this is a critical event, no critical event must be running * * (1) and (2) are true when this function is running * (3) is enforced in GIC by selecting the appropriate routing option * (4) is satisfied by client calling PE_UNMASK * (5) and (6) is enforced using interrupt priority, the RPR, in GIC: * - Normal SDEI events belong to Normal SDE priority class * - Critical SDEI events belong to Critical CSDE priority class * * The interrupt has already been acknowledged, and therefore is active, * so no other PE can handle this event while we are at it. * * Find if this is an SDEI interrupt. There must be an event mapped to * this interrupt */ intr = plat_ic_get_interrupt_id(intr_raw); map = find_event_map_by_intr(intr, (plat_ic_is_spi(intr) != 0)); if (map == NULL) { ERROR("No SDEI map for interrupt %u\n", intr); panic(); } /* * Received interrupt number must either correspond to event 0, or must * be bound interrupt. */ assert((map->ev_num == SDEI_EVENT_0) || is_map_bound(map)); se = get_event_entry(map); state = sdei_get_this_pe_state(); if (state->pe_masked) { /* * Interrupts received while this PE was masked can't be * dispatched. */ SDEI_LOG("interrupt %u on %llx while PE masked\n", map->intr, mpidr); if (is_event_shared(map)) sdei_map_lock(map); handle_masked_trigger(map, se, state, intr_raw); if (is_event_shared(map)) sdei_map_unlock(map); return 0; } /* Insert load barrier for signalled SDEI event */ if (map->ev_num == SDEI_EVENT_0) dmbld(); if (is_event_shared(map)) sdei_map_lock(map); /* Assert shared event routed to this PE had been configured so */ if (is_event_shared(map) && (se->reg_flags == SDEI_REGF_RM_PE)) { assert(se->affinity == (mpidr & MPIDR_AFFINITY_MASK)); } if (!can_sdei_state_trans(se, DO_DISPATCH)) { SDEI_LOG("SDEI event 0x%x can't be dispatched; state=0x%x\n", map->ev_num, se->state); /* * If the event is registered, leave the interrupt pending so * that it's delivered when the event is enabled. */ if (GET_EV_STATE(se, REGISTERED)) plat_ic_set_interrupt_pending(map->intr); /* * The interrupt was disabled or unregistered after the handler * started to execute, which means now the interrupt is already * disabled and we just need to EOI the interrupt. */ plat_ic_end_of_interrupt(intr_raw); if (is_event_shared(map)) sdei_map_unlock(map); return 0; } disp_ctx = get_outstanding_dispatch(); if (is_event_critical(map)) { /* * If this event is Critical, and if there's an outstanding * dispatch, assert the latter is a Normal dispatch. Critical * events can preempt an outstanding Normal event dispatch. */ if (disp_ctx != NULL) assert(is_event_normal(disp_ctx->map)); } else { /* * If this event is Normal, assert that there are no outstanding * dispatches. Normal events can't preempt any outstanding event * dispatches. */ assert(disp_ctx == NULL); } sec_state = get_interrupt_src_ss(flags); if (is_event_shared(map)) sdei_map_unlock(map); SDEI_LOG("ACK %llx, ev:%d ss:%d spsr:%lx ELR:%lx\n", mpidr, map->ev_num, sec_state, read_spsr_el3(), read_elr_el3()); ctx = handle; /* * Check if we interrupted secure state. Perform a context switch so * that we can delegate to NS. */ if (sec_state == SECURE) { save_secure_context(); ctx = restore_and_resume_ns_context(); } /* Synchronously dispatch event */ setup_ns_dispatch(map, se, ctx, &dispatch_jmp); begin_sdei_synchronous_dispatch(&dispatch_jmp); /* * We reach here when client completes the event. * * If the cause of dispatch originally interrupted the Secure world, * resume Secure. * * No need to save the Non-secure context ahead of a world switch: the * Non-secure context was fully saved before dispatch, and has been * returned to its pre-dispatch state. */ if (sec_state == SECURE) restore_and_resume_secure_context(); /* * The event was dispatched after receiving SDEI interrupt. With * the event handling completed, EOI the corresponding * interrupt. */ if ((map->ev_num != SDEI_EVENT_0) && !is_map_bound(map)) { ERROR("Invalid SDEI mapping: ev=%u\n", map->ev_num); panic(); } plat_ic_end_of_interrupt(intr_raw); return 0; } /* * Explicitly dispatch the given SDEI event. * * When calling this API, the caller must be prepared for the SDEI dispatcher to * restore and make Non-secure context as active. This call returns only after * the client has completed the dispatch. Then, the Non-secure context will be * active, and the following ERET will return to Non-secure. * * Should the caller require re-entry to Secure, it must restore the Secure * context and program registers for ERET. */ int sdei_dispatch_event(int ev_num) { sdei_entry_t *se; sdei_ev_map_t *map; cpu_context_t *ns_ctx; sdei_dispatch_context_t *disp_ctx; sdei_cpu_state_t *state; jmp_buf dispatch_jmp; /* Can't dispatch if events are masked on this PE */ state = sdei_get_this_pe_state(); if (state->pe_masked) return -1; /* Event 0 can't be dispatched */ if (ev_num == SDEI_EVENT_0) return -1; /* Locate mapping corresponding to this event */ map = find_event_map(ev_num); if (map == NULL) return -1; /* Only explicit events can be dispatched */ if (!is_map_explicit(map)) return -1; /* Examine state of dispatch stack */ disp_ctx = get_outstanding_dispatch(); if (disp_ctx != NULL) { /* * There's an outstanding dispatch. If the outstanding dispatch * is critical, no more dispatches are possible. */ if (is_event_critical(disp_ctx->map)) return -1; /* * If the outstanding dispatch is Normal, only critical events * can be dispatched. */ if (is_event_normal(map)) return -1; } se = get_event_entry(map); if (!can_sdei_state_trans(se, DO_DISPATCH)) return -1; /* Activate the priority corresponding to the event being dispatched */ ehf_activate_priority(sdei_event_priority(map)); /* * Prepare for NS dispatch by restoring the Non-secure context and * marking that as active. */ ns_ctx = restore_and_resume_ns_context(); /* Dispatch event synchronously */ setup_ns_dispatch(map, se, ns_ctx, &dispatch_jmp); begin_sdei_synchronous_dispatch(&dispatch_jmp); /* * We reach here when client completes the event. * * Deactivate the priority level that was activated at the time of * explicit dispatch. */ ehf_deactivate_priority(sdei_event_priority(map)); return 0; } static void end_sdei_synchronous_dispatch(jmp_buf *buffer) { longjmp(*buffer, 1); } int sdei_event_complete(bool resume, uint64_t pc) { sdei_dispatch_context_t *disp_ctx; sdei_entry_t *se; sdei_ev_map_t *map; cpu_context_t *ctx; sdei_action_t act; unsigned int client_el = sdei_client_el(); /* Return error if called without an active event */ disp_ctx = get_outstanding_dispatch(); if (disp_ctx == NULL) return SDEI_EDENY; /* Validate resumption point */ if (resume && (plat_sdei_validate_entry_point(pc, client_el) != 0)) return SDEI_EDENY; map = disp_ctx->map; assert(map != NULL); se = get_event_entry(map); if (is_event_shared(map)) sdei_map_lock(map); act = resume ? DO_COMPLETE_RESUME : DO_COMPLETE; if (!can_sdei_state_trans(se, act)) { if (is_event_shared(map)) sdei_map_unlock(map); return SDEI_EDENY; } if (is_event_shared(map)) sdei_map_unlock(map); /* Having done sanity checks, pop dispatch */ (void) pop_dispatch(); SDEI_LOG("EOI:%lx, %d spsr:%lx elr:%lx\n", read_mpidr_el1(), map->ev_num, read_spsr_el3(), read_elr_el3()); /* * Restore Non-secure to how it was originally interrupted. Once done, * it's up-to-date with the saved copy. */ ctx = cm_get_context(NON_SECURE); restore_event_ctx(disp_ctx, ctx); if (resume) { /* * Complete-and-resume call. Prepare the Non-secure context * (currently active) for complete and resume. */ cm_set_elr_spsr_el3(NON_SECURE, pc, SPSR_64(client_el, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS)); /* * Make it look as if a synchronous exception were taken at the * supplied Non-secure resumption point. Populate SPSR and * ELR_ELx so that an ERET from there works as expected. * * The assumption is that the client, if necessary, would have * saved any live content in these registers before making this * call. */ if (client_el == MODE_EL2) { write_elr_el2(disp_ctx->elr_el3); write_spsr_el2(disp_ctx->spsr_el3); } else { /* EL1 */ write_elr_el1(disp_ctx->elr_el3); write_spsr_el1(disp_ctx->spsr_el3); } } /* End the outstanding dispatch */ end_sdei_synchronous_dispatch(disp_ctx->dispatch_jmp); return 0; } int64_t sdei_event_context(void *handle, unsigned int param) { sdei_dispatch_context_t *disp_ctx; if (param >= SDEI_SAVED_GPREGS) return SDEI_EINVAL; /* Get outstanding dispatch on this CPU */ disp_ctx = get_outstanding_dispatch(); if (disp_ctx == NULL) return SDEI_EDENY; assert(disp_ctx->map != NULL); if (!can_sdei_state_trans(get_event_entry(disp_ctx->map), DO_CONTEXT)) return SDEI_EDENY; /* * No locking is required for the Running status as this is the only CPU * which can complete the event */ return (int64_t) disp_ctx->x[param]; } trusted-firmware-a-2.2/services/std_svc/sdei/sdei_main.c000066400000000000000000000623521355360272700234310ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sdei_private.h" #define MAJOR_VERSION 1ULL #define MINOR_VERSION 0ULL #define VENDOR_VERSION 0ULL #define MAKE_SDEI_VERSION(_major, _minor, _vendor) \ ((((_major)) << 48ULL) | (((_minor)) << 32ULL) | (_vendor)) #define LOWEST_INTR_PRIORITY 0xff #define is_valid_affinity(_mpidr) (plat_core_pos_by_mpidr(_mpidr) >= 0) CASSERT(PLAT_SDEI_CRITICAL_PRI < PLAT_SDEI_NORMAL_PRI, sdei_critical_must_have_higher_priority); static unsigned int num_dyn_priv_slots, num_dyn_shrd_slots; /* Initialise SDEI map entries */ static void init_map(sdei_ev_map_t *map) { map->reg_count = 0; } /* Convert mapping to SDEI class */ static sdei_class_t map_to_class(sdei_ev_map_t *map) { return is_event_critical(map) ? SDEI_CRITICAL : SDEI_NORMAL; } /* Clear SDEI event entries except state */ static void clear_event_entries(sdei_entry_t *se) { se->ep = 0; se->arg = 0; se->affinity = 0; se->reg_flags = 0; } /* Perform CPU-specific state initialisation */ static void *sdei_cpu_on_init(const void *arg) { unsigned int i; sdei_ev_map_t *map; sdei_entry_t *se; /* Initialize private mappings on this CPU */ for_each_private_map(i, map) { se = get_event_entry(map); clear_event_entries(se); se->state = 0; } SDEI_LOG("Private events initialized on %lx\n", read_mpidr_el1()); /* All PEs start with SDEI events masked */ (void) sdei_pe_mask(); return NULL; } /* CPU initialisation after wakeup from suspend */ static void *sdei_cpu_wakeup_init(const void *arg) { SDEI_LOG("Events masked on %lx\n", read_mpidr_el1()); /* All PEs wake up with SDEI events masked */ sdei_pe_mask(); return 0; } /* Initialise an SDEI class */ static void sdei_class_init(sdei_class_t class) { unsigned int i; bool zero_found __unused = false; int ev_num_so_far __unused; sdei_ev_map_t *map; /* Sanity check and configuration of shared events */ ev_num_so_far = -1; for_each_shared_map(i, map) { #if ENABLE_ASSERTIONS /* Ensure mappings are sorted */ assert((ev_num_so_far < 0) || (map->ev_num > ev_num_so_far)); ev_num_so_far = map->ev_num; /* Event 0 must not be shared */ assert(map->ev_num != SDEI_EVENT_0); /* Check for valid event */ assert(map->ev_num >= 0); /* Make sure it's a shared event */ assert(is_event_shared(map)); /* No shared mapping should have signalable property */ assert(!is_event_signalable(map)); /* Shared mappings can't be explicit */ assert(!is_map_explicit(map)); #endif /* Skip initializing the wrong priority */ if (map_to_class(map) != class) continue; /* Platform events are always bound, so set the bound flag */ if (is_map_dynamic(map)) { assert(map->intr == SDEI_DYN_IRQ); assert(is_event_normal(map)); num_dyn_shrd_slots++; } else { /* Shared mappings must be bound to shared interrupt */ assert(plat_ic_is_spi(map->intr) != 0); set_map_bound(map); } init_map(map); } /* Sanity check and configuration of private events for this CPU */ ev_num_so_far = -1; for_each_private_map(i, map) { #if ENABLE_ASSERTIONS /* Ensure mappings are sorted */ assert((ev_num_so_far < 0) || (map->ev_num > ev_num_so_far)); ev_num_so_far = map->ev_num; if (map->ev_num == SDEI_EVENT_0) { zero_found = true; /* Event 0 must be a Secure SGI */ assert(is_secure_sgi(map->intr)); /* * Event 0 can have only have signalable flag (apart * from being private */ assert(map->map_flags == (SDEI_MAPF_SIGNALABLE | SDEI_MAPF_PRIVATE)); } else { /* No other mapping should have signalable property */ assert(!is_event_signalable(map)); } /* Check for valid event */ assert(map->ev_num >= 0); /* Make sure it's a private event */ assert(is_event_private(map)); /* * Other than priority, explicit events can only have explicit * and private flags set. */ if (is_map_explicit(map)) { assert((map->map_flags | SDEI_MAPF_CRITICAL) == (SDEI_MAPF_EXPLICIT | SDEI_MAPF_PRIVATE | SDEI_MAPF_CRITICAL)); } #endif /* Skip initializing the wrong priority */ if (map_to_class(map) != class) continue; /* Platform events are always bound, so set the bound flag */ if (map->ev_num != SDEI_EVENT_0) { if (is_map_dynamic(map)) { assert(map->intr == SDEI_DYN_IRQ); assert(is_event_normal(map)); num_dyn_priv_slots++; } else if (is_map_explicit(map)) { /* * Explicit mappings don't have a backing * SDEI interrupt, but verify that anyway. */ assert(map->intr == SDEI_DYN_IRQ); } else { /* * Private mappings must be bound to private * interrupt. */ assert(plat_ic_is_ppi((unsigned) map->intr) != 0); set_map_bound(map); } } init_map(map); } /* Ensure event 0 is in the mapping */ assert(zero_found); (void) sdei_cpu_on_init(NULL); } /* SDEI dispatcher initialisation */ void sdei_init(void) { sdei_class_init(SDEI_CRITICAL); sdei_class_init(SDEI_NORMAL); /* Register priority level handlers */ ehf_register_priority_handler(PLAT_SDEI_CRITICAL_PRI, sdei_intr_handler); ehf_register_priority_handler(PLAT_SDEI_NORMAL_PRI, sdei_intr_handler); } /* Populate SDEI event entry */ static void set_sdei_entry(sdei_entry_t *se, uint64_t ep, uint64_t arg, unsigned int flags, uint64_t affinity) { assert(se != NULL); se->ep = ep; se->arg = arg; se->affinity = (affinity & MPIDR_AFFINITY_MASK); se->reg_flags = flags; } static uint64_t sdei_version(void) { return MAKE_SDEI_VERSION(MAJOR_VERSION, MINOR_VERSION, VENDOR_VERSION); } /* Validate flags and MPIDR values for REGISTER and ROUTING_SET calls */ static int validate_flags(uint64_t flags, uint64_t mpidr) { /* Validate flags */ switch (flags) { case SDEI_REGF_RM_PE: if (!is_valid_affinity(mpidr)) return SDEI_EINVAL; break; case SDEI_REGF_RM_ANY: break; default: /* Unknown flags */ return SDEI_EINVAL; } return 0; } /* Set routing of an SDEI event */ static int sdei_event_routing_set(int ev_num, uint64_t flags, uint64_t mpidr) { int ret; unsigned int routing; sdei_ev_map_t *map; sdei_entry_t *se; ret = validate_flags(flags, mpidr); if (ret != 0) return ret; /* Check if valid event number */ map = find_event_map(ev_num); if (map == NULL) return SDEI_EINVAL; /* The event must not be private */ if (is_event_private(map)) return SDEI_EINVAL; se = get_event_entry(map); sdei_map_lock(map); if (!is_map_bound(map) || is_event_private(map)) { ret = SDEI_EINVAL; goto finish; } if (!can_sdei_state_trans(se, DO_ROUTING)) { ret = SDEI_EDENY; goto finish; } /* Choose appropriate routing */ routing = (unsigned int) ((flags == SDEI_REGF_RM_ANY) ? INTR_ROUTING_MODE_ANY : INTR_ROUTING_MODE_PE); /* Update event registration flag */ se->reg_flags = (unsigned int) flags; /* * ROUTING_SET is permissible only when event composite state is * 'registered, disabled, and not running'. This means that the * interrupt is currently disabled, and not active. */ plat_ic_set_spi_routing(map->intr, routing, (u_register_t) mpidr); finish: sdei_map_unlock(map); return ret; } /* Register handler and argument for an SDEI event */ static int64_t sdei_event_register(int ev_num, uint64_t ep, uint64_t arg, uint64_t flags, uint64_t mpidr) { int ret; unsigned int routing; sdei_entry_t *se; sdei_ev_map_t *map; sdei_state_t backup_state; if ((ep == 0U) || (plat_sdei_validate_entry_point( ep, sdei_client_el()) != 0)) { return SDEI_EINVAL; } ret = validate_flags(flags, mpidr); if (ret != 0) return ret; /* Check if valid event number */ map = find_event_map(ev_num); if (map == NULL) return SDEI_EINVAL; /* Private events always target the PE */ if (is_event_private(map)) flags = SDEI_REGF_RM_PE; se = get_event_entry(map); /* * Even though register operation is per-event (additionally for private * events, registration is required individually), it has to be * serialised with respect to bind/release, which are global operations. * So we hold the lock throughout, unconditionally. */ sdei_map_lock(map); backup_state = se->state; if (!can_sdei_state_trans(se, DO_REGISTER)) goto fallback; /* * When registering for dynamic events, make sure it's been bound * already. This has to be the case as, without binding, the client * can't know about the event number to register for. */ if (is_map_dynamic(map) && !is_map_bound(map)) goto fallback; if (is_event_private(map)) { /* Multiple calls to register are possible for private events */ assert(map->reg_count >= 0); } else { /* Only single call to register is possible for shared events */ assert(map->reg_count == 0); } if (is_map_bound(map)) { /* Meanwhile, did any PE ACK the interrupt? */ if (plat_ic_get_interrupt_active(map->intr) != 0U) goto fallback; /* The interrupt must currently owned by Non-secure */ if (plat_ic_get_interrupt_type(map->intr) != INTR_TYPE_NS) goto fallback; /* * Disable forwarding of new interrupt triggers to CPU * interface. */ plat_ic_disable_interrupt(map->intr); /* * Any events that are triggered after register and before * enable should remain pending. Clear any previous interrupt * triggers which are pending (except for SGIs). This has no * affect on level-triggered interrupts. */ if (ev_num != SDEI_EVENT_0) plat_ic_clear_interrupt_pending(map->intr); /* Map interrupt to EL3 and program the correct priority */ plat_ic_set_interrupt_type(map->intr, INTR_TYPE_EL3); /* Program the appropriate interrupt priority */ plat_ic_set_interrupt_priority(map->intr, sdei_event_priority(map)); /* * Set the routing mode for shared event as requested. We * already ensure that shared events get bound to SPIs. */ if (is_event_shared(map)) { routing = (unsigned int) ((flags == SDEI_REGF_RM_ANY) ? INTR_ROUTING_MODE_ANY : INTR_ROUTING_MODE_PE); plat_ic_set_spi_routing(map->intr, routing, (u_register_t) mpidr); } } /* Populate event entries */ set_sdei_entry(se, ep, arg, (unsigned int) flags, mpidr); /* Increment register count */ map->reg_count++; sdei_map_unlock(map); return 0; fallback: /* Reinstate previous state */ se->state = backup_state; sdei_map_unlock(map); return SDEI_EDENY; } /* Enable SDEI event */ static int64_t sdei_event_enable(int ev_num) { sdei_ev_map_t *map; sdei_entry_t *se; int ret; bool before, after; /* Check if valid event number */ map = find_event_map(ev_num); if (map == NULL) return SDEI_EINVAL; se = get_event_entry(map); ret = SDEI_EDENY; if (is_event_shared(map)) sdei_map_lock(map); before = GET_EV_STATE(se, ENABLED); if (!can_sdei_state_trans(se, DO_ENABLE)) goto finish; after = GET_EV_STATE(se, ENABLED); /* * Enable interrupt for bound events only if there's a change in enabled * state. */ if (is_map_bound(map) && (!before && after)) plat_ic_enable_interrupt(map->intr); ret = 0; finish: if (is_event_shared(map)) sdei_map_unlock(map); return ret; } /* Disable SDEI event */ static int sdei_event_disable(int ev_num) { sdei_ev_map_t *map; sdei_entry_t *se; int ret; bool before, after; /* Check if valid event number */ map = find_event_map(ev_num); if (map == NULL) return SDEI_EINVAL; se = get_event_entry(map); ret = SDEI_EDENY; if (is_event_shared(map)) sdei_map_lock(map); before = GET_EV_STATE(se, ENABLED); if (!can_sdei_state_trans(se, DO_DISABLE)) goto finish; after = GET_EV_STATE(se, ENABLED); /* * Disable interrupt for bound events only if there's a change in * enabled state. */ if (is_map_bound(map) && (before && !after)) plat_ic_disable_interrupt(map->intr); ret = 0; finish: if (is_event_shared(map)) sdei_map_unlock(map); return ret; } /* Query SDEI event information */ static int64_t sdei_event_get_info(int ev_num, int info) { sdei_entry_t *se; sdei_ev_map_t *map; uint64_t flags; bool registered; uint64_t affinity; /* Check if valid event number */ map = find_event_map(ev_num); if (map == NULL) return SDEI_EINVAL; se = get_event_entry(map); if (is_event_shared(map)) sdei_map_lock(map); /* Sample state under lock */ registered = GET_EV_STATE(se, REGISTERED); flags = se->reg_flags; affinity = se->affinity; if (is_event_shared(map)) sdei_map_unlock(map); switch (info) { case SDEI_INFO_EV_TYPE: return is_event_shared(map); case SDEI_INFO_EV_NOT_SIGNALED: return !is_event_signalable(map); case SDEI_INFO_EV_PRIORITY: return is_event_critical(map); case SDEI_INFO_EV_ROUTING_MODE: if (!is_event_shared(map)) return SDEI_EINVAL; if (!registered) return SDEI_EDENY; return (flags == SDEI_REGF_RM_PE); case SDEI_INFO_EV_ROUTING_AFF: if (!is_event_shared(map)) return SDEI_EINVAL; if (!registered) return SDEI_EDENY; if (flags != SDEI_REGF_RM_PE) return SDEI_EINVAL; return affinity; default: return SDEI_EINVAL; } } /* Unregister an SDEI event */ static int sdei_event_unregister(int ev_num) { int ret = 0; sdei_entry_t *se; sdei_ev_map_t *map; /* Check if valid event number */ map = find_event_map(ev_num); if (map == NULL) return SDEI_EINVAL; se = get_event_entry(map); /* * Even though unregister operation is per-event (additionally for * private events, unregistration is required individually), it has to * be serialised with respect to bind/release, which are global * operations. So we hold the lock throughout, unconditionally. */ sdei_map_lock(map); if (!can_sdei_state_trans(se, DO_UNREGISTER)) { /* * Even if the call is invalid, and the handler is running (for * example, having unregistered from a running handler earlier), * return pending error code; otherwise, return deny. */ ret = GET_EV_STATE(se, RUNNING) ? SDEI_EPEND : SDEI_EDENY; goto finish; } map->reg_count--; if (is_event_private(map)) { /* Multiple calls to register are possible for private events */ assert(map->reg_count >= 0); } else { /* Only single call to register is possible for shared events */ assert(map->reg_count == 0); } if (is_map_bound(map)) { plat_ic_disable_interrupt(map->intr); /* * Clear pending interrupt. Skip for SGIs as they may not be * cleared on interrupt controllers. */ if (ev_num != SDEI_EVENT_0) plat_ic_clear_interrupt_pending(map->intr); assert(plat_ic_get_interrupt_type(map->intr) == INTR_TYPE_EL3); plat_ic_set_interrupt_type(map->intr, INTR_TYPE_NS); plat_ic_set_interrupt_priority(map->intr, LOWEST_INTR_PRIORITY); } clear_event_entries(se); /* * If the handler is running at the time of unregister, return the * pending error code. */ if (GET_EV_STATE(se, RUNNING)) ret = SDEI_EPEND; finish: sdei_map_unlock(map); return ret; } /* Query status of an SDEI event */ static int sdei_event_status(int ev_num) { sdei_ev_map_t *map; sdei_entry_t *se; sdei_state_t state; /* Check if valid event number */ map = find_event_map(ev_num); if (map == NULL) return SDEI_EINVAL; se = get_event_entry(map); if (is_event_shared(map)) sdei_map_lock(map); /* State value directly maps to the expected return format */ state = se->state; if (is_event_shared(map)) sdei_map_unlock(map); return (int) state; } /* Bind an SDEI event to an interrupt */ static int sdei_interrupt_bind(unsigned int intr_num) { sdei_ev_map_t *map; bool retry = true, shared_mapping; /* SGIs are not allowed to be bound */ if (plat_ic_is_sgi(intr_num) != 0) return SDEI_EINVAL; shared_mapping = (plat_ic_is_spi(intr_num) != 0); do { /* * Bail out if there is already an event for this interrupt, * either platform-defined or dynamic. */ map = find_event_map_by_intr(intr_num, shared_mapping); if (map != NULL) { if (is_map_dynamic(map)) { if (is_map_bound(map)) { /* * Dynamic event, already bound. Return * event number. */ return map->ev_num; } } else { /* Binding non-dynamic event */ return SDEI_EINVAL; } } /* * The interrupt is not bound yet. Try to find a free slot to * bind it. Free dynamic mappings have their interrupt set as * SDEI_DYN_IRQ. */ map = find_event_map_by_intr(SDEI_DYN_IRQ, shared_mapping); if (map == NULL) return SDEI_ENOMEM; /* The returned mapping must be dynamic */ assert(is_map_dynamic(map)); /* * We cannot assert for bound maps here, as we might be racing * with another bind. */ /* The requested interrupt must already belong to NS */ if (plat_ic_get_interrupt_type(intr_num) != INTR_TYPE_NS) return SDEI_EDENY; /* * Interrupt programming and ownership transfer are deferred * until register. */ sdei_map_lock(map); if (!is_map_bound(map)) { map->intr = intr_num; set_map_bound(map); retry = false; } sdei_map_unlock(map); } while (retry); return map->ev_num; } /* Release a bound SDEI event previously to an interrupt */ static int sdei_interrupt_release(int ev_num) { int ret = 0; sdei_ev_map_t *map; sdei_entry_t *se; /* Check if valid event number */ map = find_event_map(ev_num); if (map == NULL) return SDEI_EINVAL; if (!is_map_dynamic(map)) return SDEI_EINVAL; se = get_event_entry(map); sdei_map_lock(map); /* Event must have been unregistered before release */ if (map->reg_count != 0) { ret = SDEI_EDENY; goto finish; } /* * Interrupt release never causes the state to change. We only check * whether it's permissible or not. */ if (!can_sdei_state_trans(se, DO_RELEASE)) { ret = SDEI_EDENY; goto finish; } if (is_map_bound(map)) { /* * Deny release if the interrupt is active, which means it's * probably being acknowledged and handled elsewhere. */ if (plat_ic_get_interrupt_active(map->intr) != 0U) { ret = SDEI_EDENY; goto finish; } /* * Interrupt programming and ownership transfer are already done * during unregister. */ map->intr = SDEI_DYN_IRQ; clr_map_bound(map); } else { SDEI_LOG("Error release bound:%d cnt:%d\n", is_map_bound(map), map->reg_count); ret = SDEI_EINVAL; } finish: sdei_map_unlock(map); return ret; } /* Perform reset of private SDEI events */ static int sdei_private_reset(void) { sdei_ev_map_t *map; int ret = 0, final_ret = 0; unsigned int i; /* Unregister all private events */ for_each_private_map(i, map) { /* * The unregister can fail if the event is not registered, which * is allowed, and a deny will be returned. But if the event is * running or unregister pending, the call fails. */ ret = sdei_event_unregister(map->ev_num); if ((ret == SDEI_EPEND) && (final_ret == 0)) final_ret = SDEI_EDENY; } return final_ret; } /* Perform reset of shared SDEI events */ static int sdei_shared_reset(void) { const sdei_mapping_t *mapping; sdei_ev_map_t *map; int ret = 0, final_ret = 0; unsigned int i, j; /* Unregister all shared events */ for_each_shared_map(i, map) { /* * The unregister can fail if the event is not registered, which * is allowed, and a deny will be returned. But if the event is * running or unregister pending, the call fails. */ ret = sdei_event_unregister(map->ev_num); if ((ret == SDEI_EPEND) && (final_ret == 0)) final_ret = SDEI_EDENY; } if (final_ret != 0) return final_ret; /* * Loop through both private and shared mappings, and release all * bindings. */ for_each_mapping_type(i, mapping) { iterate_mapping(mapping, j, map) { /* * Release bindings for mappings that are dynamic and * bound. */ if (is_map_dynamic(map) && is_map_bound(map)) { /* * Any failure to release would mean there is at * least a PE registered for the event. */ ret = sdei_interrupt_release(map->ev_num); if ((ret != 0) && (final_ret == 0)) final_ret = ret; } } } return final_ret; } /* Send a signal to another SDEI client PE */ static int sdei_signal(int ev_num, uint64_t target_pe) { sdei_ev_map_t *map; /* Only event 0 can be signalled */ if (ev_num != SDEI_EVENT_0) return SDEI_EINVAL; /* Find mapping for event 0 */ map = find_event_map(SDEI_EVENT_0); if (map == NULL) return SDEI_EINVAL; /* The event must be signalable */ if (!is_event_signalable(map)) return SDEI_EINVAL; /* Validate target */ if (plat_core_pos_by_mpidr(target_pe) < 0) return SDEI_EINVAL; /* Raise SGI. Platform will validate target_pe */ plat_ic_raise_el3_sgi((int) map->intr, (u_register_t) target_pe); return 0; } /* Query SDEI dispatcher features */ static uint64_t sdei_features(unsigned int feature) { if (feature == SDEI_FEATURE_BIND_SLOTS) { return FEATURE_BIND_SLOTS(num_dyn_priv_slots, num_dyn_shrd_slots); } return (uint64_t) SDEI_EINVAL; } /* SDEI top level handler for servicing SMCs */ uint64_t sdei_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, void *cookie, void *handle, uint64_t flags) { uint64_t x5; unsigned int ss = (unsigned int) get_interrupt_src_ss(flags); int64_t ret; bool resume = false; cpu_context_t *ctx = handle; int ev_num = (int) x1; if (ss != NON_SECURE) SMC_RET1(ctx, SMC_UNK); /* Verify the caller EL */ if (GET_EL(read_spsr_el3()) != sdei_client_el()) SMC_RET1(ctx, SMC_UNK); switch (smc_fid) { case SDEI_VERSION: SDEI_LOG("> VER\n"); ret = (int64_t) sdei_version(); SDEI_LOG("< VER:%llx\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_REGISTER: x5 = SMC_GET_GP(ctx, CTX_GPREG_X5); SDEI_LOG("> REG(n:%d e:%llx a:%llx f:%x m:%llx)\n", ev_num, x2, x3, (int) x4, x5); ret = sdei_event_register(ev_num, x2, x3, x4, x5); SDEI_LOG("< REG:%lld\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_ENABLE: SDEI_LOG("> ENABLE(n:%d)\n", (int) x1); ret = sdei_event_enable(ev_num); SDEI_LOG("< ENABLE:%lld\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_DISABLE: SDEI_LOG("> DISABLE(n:%d)\n", ev_num); ret = sdei_event_disable(ev_num); SDEI_LOG("< DISABLE:%lld\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_CONTEXT: SDEI_LOG("> CTX(p:%d):%lx\n", (int) x1, read_mpidr_el1()); ret = sdei_event_context(ctx, (unsigned int) x1); SDEI_LOG("< CTX:%lld\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_COMPLETE_AND_RESUME: resume = true; /* Fallthrough */ case SDEI_EVENT_COMPLETE: SDEI_LOG("> COMPLETE(r:%u sta/ep:%llx):%lx\n", (unsigned int) resume, x1, read_mpidr_el1()); ret = sdei_event_complete(resume, x1); SDEI_LOG("< COMPLETE:%llx\n", ret); /* * Set error code only if the call failed. If the call * succeeded, we discard the dispatched context, and restore the * interrupted context to a pristine condition, and therefore * shouldn't be modified. We don't return to the caller in this * case anyway. */ if (ret != 0) SMC_RET1(ctx, ret); SMC_RET0(ctx); case SDEI_EVENT_STATUS: SDEI_LOG("> STAT(n:%d)\n", ev_num); ret = sdei_event_status(ev_num); SDEI_LOG("< STAT:%lld\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_GET_INFO: SDEI_LOG("> INFO(n:%d, %d)\n", ev_num, (int) x2); ret = sdei_event_get_info(ev_num, (int) x2); SDEI_LOG("< INFO:%lld\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_UNREGISTER: SDEI_LOG("> UNREG(n:%d)\n", ev_num); ret = sdei_event_unregister(ev_num); SDEI_LOG("< UNREG:%lld\n", ret); SMC_RET1(ctx, ret); case SDEI_PE_UNMASK: SDEI_LOG("> UNMASK:%lx\n", read_mpidr_el1()); sdei_pe_unmask(); SDEI_LOG("< UNMASK:%d\n", 0); SMC_RET1(ctx, 0); case SDEI_PE_MASK: SDEI_LOG("> MASK:%lx\n", read_mpidr_el1()); ret = sdei_pe_mask(); SDEI_LOG("< MASK:%lld\n", ret); SMC_RET1(ctx, ret); case SDEI_INTERRUPT_BIND: SDEI_LOG("> BIND(%d)\n", (int) x1); ret = sdei_interrupt_bind((unsigned int) x1); SDEI_LOG("< BIND:%lld\n", ret); SMC_RET1(ctx, ret); case SDEI_INTERRUPT_RELEASE: SDEI_LOG("> REL(%d)\n", ev_num); ret = sdei_interrupt_release(ev_num); SDEI_LOG("< REL:%lld\n", ret); SMC_RET1(ctx, ret); case SDEI_SHARED_RESET: SDEI_LOG("> S_RESET():%lx\n", read_mpidr_el1()); ret = sdei_shared_reset(); SDEI_LOG("< S_RESET:%lld\n", ret); SMC_RET1(ctx, ret); case SDEI_PRIVATE_RESET: SDEI_LOG("> P_RESET():%lx\n", read_mpidr_el1()); ret = sdei_private_reset(); SDEI_LOG("< P_RESET:%lld\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_ROUTING_SET: SDEI_LOG("> ROUTE_SET(n:%d f:%llx aff:%llx)\n", ev_num, x2, x3); ret = sdei_event_routing_set(ev_num, x2, x3); SDEI_LOG("< ROUTE_SET:%lld\n", ret); SMC_RET1(ctx, ret); case SDEI_FEATURES: SDEI_LOG("> FTRS(f:%llx)\n", x1); ret = (int64_t) sdei_features((unsigned int) x1); SDEI_LOG("< FTRS:%llx\n", ret); SMC_RET1(ctx, ret); case SDEI_EVENT_SIGNAL: SDEI_LOG("> SIGNAL(e:%d t:%llx)\n", ev_num, x2); ret = sdei_signal(ev_num, x2); SDEI_LOG("< SIGNAL:%lld\n", ret); SMC_RET1(ctx, ret); default: /* Do nothing in default case */ break; } WARN("Unimplemented SDEI Call: 0x%x\n", smc_fid); SMC_RET1(ctx, SMC_UNK); } /* Subscribe to PSCI CPU on to initialize per-CPU SDEI configuration */ SUBSCRIBE_TO_EVENT(psci_cpu_on_finish, sdei_cpu_on_init); /* Subscribe to PSCI CPU suspend finisher for per-CPU configuration */ SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, sdei_cpu_wakeup_init); trusted-firmware-a-2.2/services/std_svc/sdei/sdei_private.h000066400000000000000000000150101355360272700241510ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SDEI_PRIVATE_H #define SDEI_PRIVATE_H #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef __aarch64__ # error SDEI is implemented only for AArch64 systems #endif #ifndef PLAT_SDEI_CRITICAL_PRI # error Platform must define SDEI critical priority value #endif #ifndef PLAT_SDEI_NORMAL_PRI # error Platform must define SDEI normal priority value #endif /* Output SDEI logs as verbose */ #define SDEI_LOG(...) VERBOSE("SDEI: " __VA_ARGS__) /* SDEI handler unregistered state. This is the default state. */ #define SDEI_STATE_UNREGISTERED 0U /* SDE event status values in bit position */ #define SDEI_STATF_REGISTERED 0U #define SDEI_STATF_ENABLED 1U #define SDEI_STATF_RUNNING 2U /* SDEI SMC error codes */ #define SDEI_EINVAL (-2) #define SDEI_EDENY (-3) #define SDEI_EPEND (-5) #define SDEI_ENOMEM (-10) /* * 'info' parameter to SDEI_EVENT_GET_INFO SMC. * * Note that the SDEI v1.0 specification mistakenly enumerates the * SDEI_INFO_EV_SIGNALED as SDEI_INFO_SIGNALED. This will be corrected in a * future version. */ #define SDEI_INFO_EV_TYPE 0 #define SDEI_INFO_EV_NOT_SIGNALED 1 #define SDEI_INFO_EV_PRIORITY 2 #define SDEI_INFO_EV_ROUTING_MODE 3 #define SDEI_INFO_EV_ROUTING_AFF 4 #define SDEI_PRIVATE_MAPPING() (&sdei_global_mappings[SDEI_MAP_IDX_PRIV_]) #define SDEI_SHARED_MAPPING() (&sdei_global_mappings[SDEI_MAP_IDX_SHRD_]) #define for_each_mapping_type(_i, _mapping) \ for ((_i) = 0, (_mapping) = &sdei_global_mappings[(_i)]; \ (_i) < SDEI_MAP_IDX_MAX_; \ (_i)++, (_mapping) = &sdei_global_mappings[(_i)]) #define iterate_mapping(_mapping, _i, _map) \ for ((_map) = (_mapping)->map, (_i) = 0; \ (_i) < (_mapping)->num_maps; \ (_i)++, (_map)++) #define for_each_private_map(_i, _map) \ iterate_mapping(SDEI_PRIVATE_MAPPING(), _i, _map) #define for_each_shared_map(_i, _map) \ iterate_mapping(SDEI_SHARED_MAPPING(), _i, _map) /* SDEI_FEATURES */ #define SDEI_FEATURE_BIND_SLOTS 0U #define BIND_SLOTS_MASK 0xffffU #define FEATURES_SHARED_SLOTS_SHIFT 16U #define FEATURES_PRIVATE_SLOTS_SHIFT 0U #define FEATURE_BIND_SLOTS(_priv, _shrd) \ (((((uint64_t) (_priv)) & BIND_SLOTS_MASK) << FEATURES_PRIVATE_SLOTS_SHIFT) | \ ((((uint64_t) (_shrd)) & BIND_SLOTS_MASK) << FEATURES_SHARED_SLOTS_SHIFT)) #define GET_EV_STATE(_e, _s) get_ev_state_bit(_e, SDEI_STATF_##_s) #define SET_EV_STATE(_e, _s) clr_ev_state_bit(_e->state, SDEI_STATF_##_s) static inline bool is_event_private(sdei_ev_map_t *map) { return ((map->map_flags & BIT_32(SDEI_MAPF_PRIVATE_SHIFT_)) != 0U); } static inline bool is_event_shared(sdei_ev_map_t *map) { return !is_event_private(map); } static inline bool is_event_critical(sdei_ev_map_t *map) { return ((map->map_flags & BIT_32(SDEI_MAPF_CRITICAL_SHIFT_)) != 0U); } static inline bool is_event_normal(sdei_ev_map_t *map) { return !is_event_critical(map); } static inline bool is_event_signalable(sdei_ev_map_t *map) { return ((map->map_flags & BIT_32(SDEI_MAPF_SIGNALABLE_SHIFT_)) != 0U); } static inline bool is_map_dynamic(sdei_ev_map_t *map) { return ((map->map_flags & BIT_32(SDEI_MAPF_DYNAMIC_SHIFT_)) != 0U); } /* * Checks whether an event is associated with an interrupt. Static events always * return true, and dynamic events return whether SDEI_INTERRUPT_BIND had been * called on them. This can be used on both static or dynamic events to check * for an associated interrupt. */ static inline bool is_map_bound(sdei_ev_map_t *map) { return ((map->map_flags & BIT_32(SDEI_MAPF_BOUND_SHIFT_)) != 0U); } static inline void set_map_bound(sdei_ev_map_t *map) { map->map_flags |= BIT_32(SDEI_MAPF_BOUND_SHIFT_); } static inline bool is_map_explicit(sdei_ev_map_t *map) { return ((map->map_flags & BIT_32(SDEI_MAPF_EXPLICIT_SHIFT_)) != 0U); } static inline void clr_map_bound(sdei_ev_map_t *map) { map->map_flags &= ~BIT_32(SDEI_MAPF_BOUND_SHIFT_); } static inline bool is_secure_sgi(unsigned int intr) { return ((plat_ic_is_sgi(intr) != 0) && (plat_ic_get_interrupt_type(intr) == INTR_TYPE_EL3)); } /* * Determine EL of the client. If EL2 is implemented (hence the enabled HCE * bit), deem EL2; otherwise, deem EL1. */ static inline unsigned int sdei_client_el(void) { cpu_context_t *ns_ctx = cm_get_context(NON_SECURE); el3_state_t *el3_ctx = get_el3state_ctx(ns_ctx); return ((read_ctx_reg(el3_ctx, CTX_SCR_EL3) & SCR_HCE_BIT) != 0U) ? MODE_EL2 : MODE_EL1; } static inline unsigned int sdei_event_priority(sdei_ev_map_t *map) { return (unsigned int) (is_event_critical(map) ? PLAT_SDEI_CRITICAL_PRI : PLAT_SDEI_NORMAL_PRI); } static inline bool get_ev_state_bit(sdei_entry_t *se, unsigned int bit_no) { return ((se->state & BIT_32(bit_no)) != 0U); } static inline void clr_ev_state_bit(sdei_entry_t *se, unsigned int bit_no) { se->state &= ~BIT_32(bit_no); } /* SDEI actions for state transition */ typedef enum { /* * Actions resulting from client requests. These directly map to SMC * calls. Note that the state table columns are listed in this order * too. */ DO_REGISTER = 0, DO_RELEASE = 1, DO_ENABLE = 2, DO_DISABLE = 3, DO_UNREGISTER = 4, DO_ROUTING = 5, DO_CONTEXT = 6, DO_COMPLETE = 7, DO_COMPLETE_RESUME = 8, /* Action for event dispatch */ DO_DISPATCH = 9, DO_MAX, } sdei_action_t; typedef enum { SDEI_NORMAL, SDEI_CRITICAL } sdei_class_t; static inline void sdei_map_lock(sdei_ev_map_t *map) { spin_lock(&map->lock); } static inline void sdei_map_unlock(sdei_ev_map_t *map) { spin_unlock(&map->lock); } extern const sdei_mapping_t sdei_global_mappings[]; extern sdei_entry_t sdei_private_event_table[]; extern sdei_entry_t sdei_shared_event_table[]; void init_sdei_state(void); sdei_ev_map_t *find_event_map_by_intr(unsigned int intr_num, bool shared); sdei_ev_map_t *find_event_map(int ev_num); sdei_entry_t *get_event_entry(sdei_ev_map_t *map); int64_t sdei_event_context(void *handle, unsigned int param); int sdei_event_complete(bool resume, uint64_t pc); void sdei_pe_unmask(void); int64_t sdei_pe_mask(void); int sdei_intr_handler(uint32_t intr_raw, uint32_t flags, void *handle, void *cookie); bool can_sdei_state_trans(sdei_entry_t *se, sdei_action_t act); void begin_sdei_synchronous_dispatch(jmp_buf *buffer); #endif /* SDEI_PRIVATE_H */ trusted-firmware-a-2.2/services/std_svc/sdei/sdei_state.c000066400000000000000000000104651355360272700236230ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include "sdei_private.h" /* Aliases for SDEI handler states: 'R'unning, 'E'nabled, and re'G'istered */ #define r_ 0U #define R_ (1u << SDEI_STATF_RUNNING) #define e_ 0U #define E_ (1u << SDEI_STATF_ENABLED) #define g_ 0U #define G_ (1u << SDEI_STATF_REGISTERED) /* All possible composite handler states */ #define reg_ (r_ | e_ | g_) #define reG_ (r_ | e_ | G_) #define rEg_ (r_ | E_ | g_) #define rEG_ (r_ | E_ | G_) #define Reg_ (R_ | e_ | g_) #define ReG_ (R_ | e_ | G_) #define REg_ (R_ | E_ | g_) #define REG_ (R_ | E_ | G_) #define MAX_STATES (REG_ + 1u) /* Invalid state */ #define SDEI_STATE_INVALID ((sdei_state_t) (-1)) /* No change in state */ #define SDEI_STATE_NOP ((sdei_state_t) (-2)) #define X___ SDEI_STATE_INVALID #define NOP_ SDEI_STATE_NOP /* Ensure special states don't overlap with valid ones */ CASSERT(X___ > REG_, sdei_state_overlap_invalid); CASSERT(NOP_ > REG_, sdei_state_overlap_nop); /* * SDEI handler state machine: refer to sections 6.1 and 6.1.2 of the SDEI v1.0 * specification (ARM DEN0054A). * * Not all calls contribute to handler state transition. This table is also used * to validate whether a call is permissible at a given handler state: * * - X___ denotes a forbidden transition; * - NOP_ denotes a permitted transition, but there's no change in state; * - Otherwise, XXX_ gives the new state. * * DISP[atch] is a transition added for the implementation, but is not mentioned * in the spec. * * Those calls that the spec mentions as can be made any time don't picture in * this table. */ static const sdei_state_t sdei_state_table[MAX_STATES][DO_MAX] = { /* * Action: REG REL ENA DISA UREG ROUT CTX COMP COMPR DISP * Notes: [3] [1] [3] [3][4] [2] */ /* Handler unregistered, disabled, and not running. This is the default state. */ /* 0 */ [reg_] = { reG_, NOP_, X___, X___, X___, X___, X___, X___, X___, X___, }, /* Handler unregistered and running */ /* 4 */ [Reg_] = { X___, X___, X___, X___, X___, X___, NOP_, reg_, reg_, X___, }, /* Handler registered */ /* 1 */ [reG_] = { X___, X___, rEG_, NOP_, reg_, NOP_, X___, X___, X___, X___, }, /* Handler registered and running */ /* 5 */ [ReG_] = { X___, X___, REG_, NOP_, Reg_, X___, NOP_, reG_, reG_, X___, }, /* Handler registered and enabled */ /* 3 */ [rEG_] = { X___, X___, NOP_, reG_, reg_, X___, X___, X___, X___, REG_, }, /* Handler registered, enabled, and running */ /* 7 */ [REG_] = { X___, X___, NOP_, ReG_, Reg_, X___, NOP_, rEG_, rEG_, X___, }, /* * Invalid states: no valid transition would leave the handler in these * states; and no transition from these states is possible either. */ /* * Handler can't be enabled without being registered. I.e., XEg is * impossible. */ /* 2 */ [rEg_] = { X___, X___, X___, X___, X___, X___, X___, X___, X___, X___, }, /* 6 */ [REg_] = { X___, X___, X___, X___, X___, X___, X___, X___, X___, X___, }, }; /* * [1] Unregister will always also disable the event, so the new state will have * Xeg. * [2] Event is considered for dispatch only when it's both registered and * enabled. * [3] Never causes change in state. * [4] Only allowed when running. */ /* * Given an action, transition the state of an event by looking up the state * table above: * * - Return false for invalid transition; * - Return true for valid transition that causes no change in state; * - Otherwise, update state and return true. * * This function assumes that the caller holds necessary locks. If the * transition has constrains other than the state table describes, the caller is * expected to restore the previous state. See sdei_event_register() for * example. */ bool can_sdei_state_trans(sdei_entry_t *se, sdei_action_t act) { sdei_state_t next; assert(act < DO_MAX); if (se->state >= MAX_STATES) { WARN(" event state invalid: %x\n", se->state); return false; } next = sdei_state_table[se->state][act]; switch (next) { case SDEI_STATE_INVALID: return false; case SDEI_STATE_NOP: return true; default: /* Valid transition. Update state. */ SDEI_LOG(" event state 0x%x => 0x%x\n", se->state, next); se->state = next; return true; } } trusted-firmware-a-2.2/services/std_svc/spm/000077500000000000000000000000001355360272700212005ustar00rootroot00000000000000trusted-firmware-a-2.2/services/std_svc/spm/README.rst000066400000000000000000000002541355360272700226700ustar00rootroot00000000000000This is a prototype loosely based on the SPCI Alpha and SPRT pre-alpha specifications. Any interface / platform API introduced for this is subject to change as it evolves. trusted-firmware-a-2.2/services/std_svc/spm/aarch64/000077500000000000000000000000001355360272700224305ustar00rootroot00000000000000trusted-firmware-a-2.2/services/std_svc/spm/aarch64/spm_helpers.S000066400000000000000000000056371355360272700251100ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "../spm_private.h" .global spm_secure_partition_enter .global spm_secure_partition_exit /* --------------------------------------------------------------------- * This function is called with SP_EL0 as stack. Here we stash our EL3 * callee-saved registers on to the stack as a part of saving the C * runtime and enter the secure payload. * 'x0' contains a pointer to the memory where the address of the C * runtime context is to be saved. * --------------------------------------------------------------------- */ func spm_secure_partition_enter /* Make space for the registers that we're going to save */ mov x3, sp str x3, [x0, #0] sub sp, sp, #SP_C_RT_CTX_SIZE /* Save callee-saved registers on to the stack */ stp x19, x20, [sp, #SP_C_RT_CTX_X19] stp x21, x22, [sp, #SP_C_RT_CTX_X21] stp x23, x24, [sp, #SP_C_RT_CTX_X23] stp x25, x26, [sp, #SP_C_RT_CTX_X25] stp x27, x28, [sp, #SP_C_RT_CTX_X27] stp x29, x30, [sp, #SP_C_RT_CTX_X29] /* --------------------------------------------------------------------- * Everything is setup now. el3_exit() will use the secure context to * restore to the general purpose and EL3 system registers to ERET * into the secure payload. * --------------------------------------------------------------------- */ b el3_exit endfunc spm_secure_partition_enter /* --------------------------------------------------------------------- * This function is called with 'x0' pointing to a C runtime context * saved in spm_secure_partition_enter(). * It restores the saved registers and jumps to that runtime with 'x0' * as the new SP register. This destroys the C runtime context that had * been built on the stack below the saved context by the caller. Later * the second parameter 'x1' is passed as a return value to the caller. * --------------------------------------------------------------------- */ func spm_secure_partition_exit /* Restore the previous stack */ mov sp, x0 /* Restore callee-saved registers on to the stack */ ldp x19, x20, [x0, #(SP_C_RT_CTX_X19 - SP_C_RT_CTX_SIZE)] ldp x21, x22, [x0, #(SP_C_RT_CTX_X21 - SP_C_RT_CTX_SIZE)] ldp x23, x24, [x0, #(SP_C_RT_CTX_X23 - SP_C_RT_CTX_SIZE)] ldp x25, x26, [x0, #(SP_C_RT_CTX_X25 - SP_C_RT_CTX_SIZE)] ldp x27, x28, [x0, #(SP_C_RT_CTX_X27 - SP_C_RT_CTX_SIZE)] ldp x29, x30, [x0, #(SP_C_RT_CTX_X29 - SP_C_RT_CTX_SIZE)] /* --------------------------------------------------------------------- * This should take us back to the instruction after the call to the * last spm_secure_partition_enter().* Place the second parameter to x0 * so that the caller will see it as a return value from the original * entry call. * --------------------------------------------------------------------- */ mov x0, x1 ret endfunc spm_secure_partition_exit trusted-firmware-a-2.2/services/std_svc/spm/aarch64/spm_shim_exceptions.S000066400000000000000000000061121355360272700266340ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /* ----------------------------------------------------------------------------- * Very simple stackless exception handlers used by the spm shim layer. * ----------------------------------------------------------------------------- */ .globl spm_shim_exceptions_ptr vector_base spm_shim_exceptions_ptr, .spm_shim_exceptions /* ----------------------------------------------------- * Current EL with SP0 : 0x0 - 0x200 * ----------------------------------------------------- */ vector_entry SynchronousExceptionSP0, .spm_shim_exceptions b . end_vector_entry SynchronousExceptionSP0 vector_entry IrqSP0, .spm_shim_exceptions b . end_vector_entry IrqSP0 vector_entry FiqSP0, .spm_shim_exceptions b . end_vector_entry FiqSP0 vector_entry SErrorSP0, .spm_shim_exceptions b . end_vector_entry SErrorSP0 /* ----------------------------------------------------- * Current EL with SPx: 0x200 - 0x400 * ----------------------------------------------------- */ vector_entry SynchronousExceptionSPx, .spm_shim_exceptions b . end_vector_entry SynchronousExceptionSPx vector_entry IrqSPx, .spm_shim_exceptions b . end_vector_entry IrqSPx vector_entry FiqSPx, .spm_shim_exceptions b . end_vector_entry FiqSPx vector_entry SErrorSPx, .spm_shim_exceptions b . end_vector_entry SErrorSPx /* ----------------------------------------------------- * Lower EL using AArch64 : 0x400 - 0x600. No exceptions * are handled since secure_partition does not implement * a lower EL * ----------------------------------------------------- */ vector_entry SynchronousExceptionA64, .spm_shim_exceptions msr tpidr_el1, x30 mrs x30, esr_el1 ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH cmp x30, #EC_AARCH64_SVC b.eq do_smc cmp x30, #EC_AARCH32_SVC b.eq do_smc cmp x30, #EC_AARCH64_SYS b.eq handle_sys_trap /* Fail in all the other cases */ b panic /* --------------------------------------------- * Tell SPM that we are done initialising * --------------------------------------------- */ do_smc: mrs x30, tpidr_el1 smc #0 eret /* AArch64 system instructions trap are handled as a panic for now */ handle_sys_trap: panic: b panic end_vector_entry SynchronousExceptionA64 vector_entry IrqA64, .spm_shim_exceptions b . end_vector_entry IrqA64 vector_entry FiqA64, .spm_shim_exceptions b . end_vector_entry FiqA64 vector_entry SErrorA64, .spm_shim_exceptions b . end_vector_entry SErrorA64 /* ----------------------------------------------------- * Lower EL using AArch32 : 0x600 - 0x800 * ----------------------------------------------------- */ vector_entry SynchronousExceptionA32, .spm_shim_exceptions b . end_vector_entry SynchronousExceptionA32 vector_entry IrqA32, .spm_shim_exceptions b . end_vector_entry IrqA32 vector_entry FiqA32, .spm_shim_exceptions b . end_vector_entry FiqA32 vector_entry SErrorA32, .spm_shim_exceptions b . end_vector_entry SErrorA32 trusted-firmware-a-2.2/services/std_svc/spm/spci.c000066400000000000000000000544021355360272700223070ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "spm_private.h" /******************************************************************************* * Macros to print UUIDs. ******************************************************************************/ #define PRINT_UUID_FORMAT "%08x-%08x-%08x-%08x" #define PRINT_UUID_ARGS(x) x[0], x[1], x[2], x[3] /******************************************************************************* * Array of structs that contains information about all handles of Secure * Services that are currently open. ******************************************************************************/ typedef enum spci_handle_status { HANDLE_STATUS_CLOSED = 0, HANDLE_STATUS_OPEN, } spci_handle_status_t; typedef struct spci_handle { /* 16-bit value used as reference in all SPCI calls */ uint16_t handle; /* Client ID of the client that requested the handle */ uint16_t client_id; /* Current status of the handle */ spci_handle_status_t status; /* * Context of the Secure Partition that provides the Secure Service * referenced by this handle. */ sp_context_t *sp_ctx; /* * The same handle might be used for multiple requests, keep a reference * counter of them. */ unsigned int num_active_requests; } spci_handle_t; static spci_handle_t spci_handles[PLAT_SPCI_HANDLES_MAX_NUM]; static spinlock_t spci_handles_lock; /* * Given a handle and a client ID, return the element of the spci_handles * array that contains the information of the handle. It can only return open * handles. It returns NULL if it couldn't find the element in the array. */ static spci_handle_t *spci_handle_info_get(uint16_t handle, uint16_t client_id) { size_t i; for (i = 0; i < ARRAY_SIZE(spci_handles); i++) { spci_handle_t *h = &(spci_handles[i]); /* Only check for open handles */ if (h->status == HANDLE_STATUS_CLOSED) { continue; } /* Check if either the handle or the client ID are different */ if ((h->handle != handle) || (h->client_id != client_id)) { continue; } return h; } return NULL; } /* * Returns a unique value for a handle. This function must be called while * spci_handles_lock is locked. It returns 0 on success, -1 on error. */ static int spci_create_handle_value(uint16_t *handle) { /* * Trivial implementation that relies on the fact that any handle will * be closed before 2^16 more handles have been opened. */ static uint16_t handle_count; *handle = handle_count; handle_count++; return 0; } /******************************************************************************* * Returns a unique token for a Secure Service request. ******************************************************************************/ static uint32_t spci_create_token_value(void) { /* * Trivial implementation that relies on the fact that any response will * be read before 2^32 more service requests have been done. */ static uint32_t token_count; return token_count++; } /******************************************************************************* * This function looks for a Secure Partition that has a Secure Service * identified by the given UUID. It returns a handle that the client can use to * access the service, and an SPCI_*** error code. ******************************************************************************/ static uint64_t spci_service_handle_open_poll(void *handle, u_register_t x1, u_register_t x2, u_register_t x3, u_register_t x4, u_register_t x5, u_register_t x6, u_register_t x7) { unsigned int i; sp_context_t *sp_ptr; uint16_t service_handle; /* Bits 31:16 of w7 are reserved (MBZ). */ assert((x7 & 0xFFFF0000U) == 0); uint16_t client_id = x7 & 0x0000FFFFU; uint32_t uuid[4] = { x1, x2, x3, x4 }; /* Get pointer to the Secure Partition that handles this service */ sp_ptr = spm_sp_get_by_uuid(&uuid); if (sp_ptr == NULL) { WARN("SPCI: Service requested by client 0x%04x not found\n", client_id); WARN("SPCI: UUID: " PRINT_UUID_FORMAT "\n", PRINT_UUID_ARGS(uuid)); SMC_RET2(handle, SPCI_NOT_PRESENT, 0); } /* Get lock of the array of handles */ spin_lock(&spci_handles_lock); /* * We need to record the client ID and Secure Partition that correspond * to this handle. Look for the first free entry in the array. */ for (i = 0; i < PLAT_SPCI_HANDLES_MAX_NUM; i++) { if (spci_handles[i].status == HANDLE_STATUS_CLOSED) { break; } } if (i == PLAT_SPCI_HANDLES_MAX_NUM) { spin_unlock(&spci_handles_lock); WARN("SPCI: Can't open more handles. Client 0x%04x\n", client_id); WARN("SPCI: UUID: " PRINT_UUID_FORMAT "\n", PRINT_UUID_ARGS(uuid)); SMC_RET2(handle, SPCI_NO_MEMORY, 0); } /* Create new handle value */ if (spci_create_handle_value(&service_handle) != 0) { spin_unlock(&spci_handles_lock); WARN("SPCI: Can't create a new handle value. Client 0x%04x\n", client_id); WARN("SPCI: UUID: " PRINT_UUID_FORMAT "\n", PRINT_UUID_ARGS(uuid)); SMC_RET2(handle, SPCI_NO_MEMORY, 0); } /* Save all information about this handle */ spci_handles[i].status = HANDLE_STATUS_OPEN; spci_handles[i].client_id = client_id; spci_handles[i].handle = service_handle; spci_handles[i].num_active_requests = 0U; spci_handles[i].sp_ctx = sp_ptr; /* Release lock of the array of handles */ spin_unlock(&spci_handles_lock); VERBOSE("SPCI: Service handle request by client 0x%04x: 0x%04x\n", client_id, service_handle); VERBOSE("SPCI: UUID: " PRINT_UUID_FORMAT "\n", PRINT_UUID_ARGS(uuid)); /* The handle is returned in the top 16 bits of x1 */ SMC_RET2(handle, SPCI_SUCCESS, ((uint32_t)service_handle) << 16); } /******************************************************************************* * This function closes a handle that a specific client uses to access a Secure * Service. It returns a SPCI_*** error code. ******************************************************************************/ static uint64_t spci_service_handle_close(void *handle, u_register_t x1) { spci_handle_t *handle_info; uint16_t client_id = x1 & 0x0000FFFFU; uint16_t service_handle = (x1 >> 16) & 0x0000FFFFU; spin_lock(&spci_handles_lock); handle_info = spci_handle_info_get(service_handle, client_id); if (handle_info == NULL) { spin_unlock(&spci_handles_lock); WARN("SPCI: Tried to close invalid handle 0x%04x by client 0x%04x\n", service_handle, client_id); SMC_RET1(handle, SPCI_INVALID_PARAMETER); } if (handle_info->status != HANDLE_STATUS_OPEN) { spin_unlock(&spci_handles_lock); WARN("SPCI: Tried to close handle 0x%04x by client 0x%04x in status %d\n", service_handle, client_id, handle_info->status); SMC_RET1(handle, SPCI_INVALID_PARAMETER); } if (handle_info->num_active_requests != 0U) { spin_unlock(&spci_handles_lock); /* A handle can't be closed if there are requests left */ WARN("SPCI: Tried to close handle 0x%04x by client 0x%04x with %d requests left\n", service_handle, client_id, handle_info->num_active_requests); SMC_RET1(handle, SPCI_BUSY); } memset(handle_info, 0, sizeof(spci_handle_t)); handle_info->status = HANDLE_STATUS_CLOSED; spin_unlock(&spci_handles_lock); VERBOSE("SPCI: Closed handle 0x%04x by client 0x%04x.\n", service_handle, client_id); SMC_RET1(handle, SPCI_SUCCESS); } /******************************************************************************* * This function requests a Secure Service from a given handle and client ID. ******************************************************************************/ static uint64_t spci_service_request_blocking(void *handle, uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3, u_register_t x4, u_register_t x5, u_register_t x6, u_register_t x7) { spci_handle_t *handle_info; sp_context_t *sp_ctx; cpu_context_t *cpu_ctx; uint32_t rx0; u_register_t rx1, rx2, rx3; uint16_t request_handle, client_id; /* Get handle array lock */ spin_lock(&spci_handles_lock); /* Get pointer to struct of this open handle and client ID. */ request_handle = (x7 >> 16U) & 0x0000FFFFU; client_id = x7 & 0x0000FFFFU; handle_info = spci_handle_info_get(request_handle, client_id); if (handle_info == NULL) { spin_unlock(&spci_handles_lock); WARN("SPCI_SERVICE_TUN_REQUEST_BLOCKING: Not found.\n"); WARN(" Handle 0x%04x. Client ID 0x%04x\n", request_handle, client_id); SMC_RET1(handle, SPCI_BUSY); } /* Get pointer to the Secure Partition that handles the service */ sp_ctx = handle_info->sp_ctx; assert(sp_ctx != NULL); cpu_ctx = &(sp_ctx->cpu_ctx); /* Blocking requests are only allowed if the queue is empty */ if (handle_info->num_active_requests > 0) { spin_unlock(&spci_handles_lock); SMC_RET1(handle, SPCI_BUSY); } if (spm_sp_request_increase_if_zero(sp_ctx) == -1) { spin_unlock(&spci_handles_lock); SMC_RET1(handle, SPCI_BUSY); } /* Prevent this handle from being closed */ handle_info->num_active_requests += 1; /* Release handle lock */ spin_unlock(&spci_handles_lock); /* Save the Normal world context */ cm_el1_sysregs_context_save(NON_SECURE); /* Wait until the Secure Partition is idle and set it to busy. */ sp_state_wait_switch(sp_ctx, SP_STATE_IDLE, SP_STATE_BUSY); /* Pass arguments to the Secure Partition */ struct sprt_queue_entry_message message = { .type = SPRT_MSG_TYPE_SERVICE_TUN_REQUEST, .client_id = client_id, .service_handle = request_handle, .session_id = x6, .token = 0, /* No token needed for blocking requests */ .args = {smc_fid, x1, x2, x3, x4, x5} }; spin_lock(&(sp_ctx->spm_sp_buffer_lock)); int rc = sprt_push_message((void *)sp_ctx->spm_sp_buffer_base, &message, SPRT_QUEUE_NUM_BLOCKING); spin_unlock(&(sp_ctx->spm_sp_buffer_lock)); if (rc != 0) { /* * This shouldn't happen, blocking requests can only be made if * the request queue is empty. */ assert(rc == -ENOMEM); ERROR("SPCI_SERVICE_TUN_REQUEST_BLOCKING: Queue is full.\n"); panic(); } /* Jump to the Secure Partition. */ rx0 = spm_sp_synchronous_entry(sp_ctx, 0); /* Verify returned value */ if (rx0 != SPRT_PUT_RESPONSE_AARCH64) { ERROR("SPM: %s: Unexpected x0 value 0x%x\n", __func__, rx0); panic(); } rx1 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3); rx2 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X4); rx3 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X5); /* Flag Secure Partition as idle. */ assert(sp_ctx->state == SP_STATE_BUSY); sp_state_set(sp_ctx, SP_STATE_IDLE); /* Decrease count of requests. */ spin_lock(&spci_handles_lock); handle_info->num_active_requests -= 1; spin_unlock(&spci_handles_lock); spm_sp_request_decrease(sp_ctx); /* Restore non-secure state */ cm_el1_sysregs_context_restore(NON_SECURE); cm_set_next_eret_context(NON_SECURE); SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3); } /******************************************************************************* * This function handles the returned values from the Secure Partition. ******************************************************************************/ static void spci_handle_returned_values(const cpu_context_t *cpu_ctx, uint64_t ret) { if (ret == SPRT_PUT_RESPONSE_AARCH64) { uint32_t token; uint64_t x3, x4, x5, x6; token = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1); x3 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3); x4 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X4); x5 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X5); x6 = read_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X6); uint16_t client_id = x6 & 0xFFFFU; uint16_t service_handle = x6 >> 16; int rc = spm_response_add(client_id, service_handle, token, x3, x4, x5); if (rc != 0) { /* * This is error fatal because we can't return to the SP * from this SMC. The SP has crashed. */ panic(); } } else if ((ret != SPRT_YIELD_AARCH64) && (ret != SPM_SECURE_PARTITION_PREEMPTED)) { ERROR("SPM: %s: Unexpected x0 value 0x%llx\n", __func__, ret); panic(); } } /******************************************************************************* * This function requests a Secure Service from a given handle and client ID. ******************************************************************************/ static uint64_t spci_service_request_start(void *handle, uint32_t smc_fid, u_register_t x1, u_register_t x2, u_register_t x3, u_register_t x4, u_register_t x5, u_register_t x6, u_register_t x7) { spci_handle_t *handle_info; sp_context_t *sp_ctx; cpu_context_t *cpu_ctx; uint16_t request_handle, client_id; uint32_t token; /* Get handle array lock */ spin_lock(&spci_handles_lock); /* Get pointer to struct of this open handle and client ID. */ request_handle = (x7 >> 16U) & 0x0000FFFFU; client_id = x7 & 0x0000FFFFU; handle_info = spci_handle_info_get(request_handle, client_id); if (handle_info == NULL) { spin_unlock(&spci_handles_lock); WARN("SPCI_SERVICE_TUN_REQUEST_START: Not found.\n" " Handle 0x%04x. Client ID 0x%04x\n", request_handle, client_id); SMC_RET1(handle, SPCI_INVALID_PARAMETER); } /* Get pointer to the Secure Partition that handles the service */ sp_ctx = handle_info->sp_ctx; assert(sp_ctx != NULL); cpu_ctx = &(sp_ctx->cpu_ctx); /* Prevent this handle from being closed */ handle_info->num_active_requests += 1; spm_sp_request_increase(sp_ctx); /* Create new token for this request */ token = spci_create_token_value(); /* Release handle lock */ spin_unlock(&spci_handles_lock); /* Pass arguments to the Secure Partition */ struct sprt_queue_entry_message message = { .type = SPRT_MSG_TYPE_SERVICE_TUN_REQUEST, .client_id = client_id, .service_handle = request_handle, .session_id = x6, .token = token, .args = {smc_fid, x1, x2, x3, x4, x5} }; spin_lock(&(sp_ctx->spm_sp_buffer_lock)); int rc = sprt_push_message((void *)sp_ctx->spm_sp_buffer_base, &message, SPRT_QUEUE_NUM_NON_BLOCKING); spin_unlock(&(sp_ctx->spm_sp_buffer_lock)); if (rc != 0) { WARN("SPCI_SERVICE_TUN_REQUEST_START: SPRT queue full.\n" " Handle 0x%04x. Client ID 0x%04x\n", request_handle, client_id); SMC_RET1(handle, SPCI_NO_MEMORY); } /* Try to enter the partition. If it's not possible, simply return. */ if (sp_state_try_switch(sp_ctx, SP_STATE_IDLE, SP_STATE_BUSY) != 0) { SMC_RET2(handle, SPCI_SUCCESS, token); } /* Save the Normal world context */ cm_el1_sysregs_context_save(NON_SECURE); /* * This request is non-blocking and needs to be interruptible by * non-secure interrupts. Enable their routing to EL3 during the * processing of the Secure Partition's service on this core. */ /* Jump to the Secure Partition. */ uint64_t ret = spm_sp_synchronous_entry(sp_ctx, 1); /* Handle returned values */ spci_handle_returned_values(cpu_ctx, ret); /* Flag Secure Partition as idle. */ assert(sp_ctx->state == SP_STATE_BUSY); sp_state_set(sp_ctx, SP_STATE_IDLE); /* Restore non-secure state */ cm_el1_sysregs_context_restore(NON_SECURE); cm_set_next_eret_context(NON_SECURE); SMC_RET2(handle, SPCI_SUCCESS, token); } /******************************************************************************* * This function returns the response of a Secure Service given a handle, a * client ID and a token. If not available, it will schedule a Secure Partition * and give it CPU time. ******************************************************************************/ static uint64_t spci_service_request_resume(void *handle, u_register_t x1, u_register_t x7) { int rc; u_register_t rx1 = 0, rx2 = 0, rx3 = 0; spci_handle_t *handle_info; sp_context_t *sp_ctx; cpu_context_t *cpu_ctx; uint32_t token = (uint32_t) x1; uint16_t client_id = x7 & 0x0000FFFF; uint16_t service_handle = (x7 >> 16) & 0x0000FFFF; /* Get pointer to struct of this open handle and client ID. */ spin_lock(&spci_handles_lock); handle_info = spci_handle_info_get(service_handle, client_id); if (handle_info == NULL) { spin_unlock(&spci_handles_lock); WARN("SPCI_SERVICE_REQUEST_RESUME: Not found.\n" "Handle 0x%04x. Client ID 0x%04x, Token 0x%08x.\n", client_id, service_handle, token); SMC_RET1(handle, SPCI_INVALID_PARAMETER); } /* Get pointer to the Secure Partition that handles the service */ sp_ctx = handle_info->sp_ctx; assert(sp_ctx != NULL); cpu_ctx = &(sp_ctx->cpu_ctx); spin_unlock(&spci_handles_lock); /* Look for a valid response in the global queue */ rc = spm_response_get(client_id, service_handle, token, &rx1, &rx2, &rx3); if (rc == 0) { /* Decrease request count */ spin_lock(&spci_handles_lock); handle_info->num_active_requests -= 1; spin_unlock(&spci_handles_lock); spm_sp_request_decrease(sp_ctx); SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3); } /* Try to enter the partition. If it's not possible, simply return. */ if (sp_state_try_switch(sp_ctx, SP_STATE_IDLE, SP_STATE_BUSY) != 0) { SMC_RET1(handle, SPCI_QUEUED); } /* Save the Normal world context */ cm_el1_sysregs_context_save(NON_SECURE); /* * This request is non-blocking and needs to be interruptible by * non-secure interrupts. Enable their routing to EL3 during the * processing of the Secure Partition's service on this core. */ /* Jump to the Secure Partition. */ uint64_t ret = spm_sp_synchronous_entry(sp_ctx, 1); /* Handle returned values */ spci_handle_returned_values(cpu_ctx, ret); /* Flag Secure Partition as idle. */ assert(sp_ctx->state == SP_STATE_BUSY); sp_state_set(sp_ctx, SP_STATE_IDLE); /* Restore non-secure state */ cm_el1_sysregs_context_restore(NON_SECURE); cm_set_next_eret_context(NON_SECURE); /* Look for a valid response in the global queue */ rc = spm_response_get(client_id, service_handle, token, &rx1, &rx2, &rx3); if (rc != 0) { SMC_RET1(handle, SPCI_QUEUED); } /* Decrease request count */ spin_lock(&spci_handles_lock); handle_info->num_active_requests -= 1; spin_unlock(&spci_handles_lock); spm_sp_request_decrease(sp_ctx); /* Return response */ SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3); } /******************************************************************************* * This function returns the response of a Secure Service given a handle, a * client ID and a token. ******************************************************************************/ static uint64_t spci_service_get_response(void *handle, u_register_t x1, u_register_t x7) { int rc; u_register_t rx1 = 0, rx2 = 0, rx3 = 0; spci_handle_t *handle_info; uint32_t token = (uint32_t) x1; uint16_t client_id = x7 & 0x0000FFFF; uint16_t service_handle = (x7 >> 16) & 0x0000FFFF; /* Get pointer to struct of this open handle and client ID. */ spin_lock(&spci_handles_lock); handle_info = spci_handle_info_get(service_handle, client_id); if (handle_info == NULL) { spin_unlock(&spci_handles_lock); WARN("SPCI_SERVICE_GET_RESPONSE: Not found.\n" "Handle 0x%04x. Client ID 0x%04x, Token 0x%08x.\n", client_id, service_handle, token); SMC_RET1(handle, SPCI_INVALID_PARAMETER); } spin_unlock(&spci_handles_lock); /* Look for a valid response in the global queue */ rc = spm_response_get(client_id, service_handle, token, &rx1, &rx2, &rx3); if (rc != 0) { SMC_RET1(handle, SPCI_QUEUED); } /* Decrease request count */ spin_lock(&spci_handles_lock); handle_info->num_active_requests -= 1; sp_context_t *sp_ctx; sp_ctx = handle_info->sp_ctx; spin_unlock(&spci_handles_lock); spm_sp_request_decrease(sp_ctx); /* Return response */ SMC_RET4(handle, SPCI_SUCCESS, rx1, rx2, rx3); } /******************************************************************************* * This function handles all SMCs in the range reserved for SPCI. ******************************************************************************/ static uintptr_t spci_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 spci_fid; /* SPCI only supported from the Non-secure world for now */ if (is_caller_non_secure(flags) == SMC_FROM_SECURE) { SMC_RET1(handle, SMC_UNK); } if ((smc_fid & SPCI_FID_TUN_FLAG) == 0) { /* Miscellaneous calls */ spci_fid = (smc_fid >> SPCI_FID_MISC_SHIFT) & SPCI_FID_MISC_MASK; switch (spci_fid) { case SPCI_FID_VERSION: SMC_RET1(handle, SPCI_VERSION_COMPILED); case SPCI_FID_SERVICE_HANDLE_OPEN: { if ((smc_fid & SPCI_SERVICE_HANDLE_OPEN_NOTIFY_BIT) != 0) { /* Not supported for now */ WARN("SPCI_SERVICE_HANDLE_OPEN_NOTIFY not supported.\n"); SMC_RET1(handle, SPCI_INVALID_PARAMETER); } uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5); uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6); uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7); return spci_service_handle_open_poll(handle, x1, x2, x3, x4, x5, x6, x7); } case SPCI_FID_SERVICE_HANDLE_CLOSE: return spci_service_handle_close(handle, x1); case SPCI_FID_SERVICE_REQUEST_BLOCKING: { uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5); uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6); uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7); return spci_service_request_blocking(handle, smc_fid, x1, x2, x3, x4, x5, x6, x7); } case SPCI_FID_SERVICE_REQUEST_START: { uint64_t x5 = SMC_GET_GP(handle, CTX_GPREG_X5); uint64_t x6 = SMC_GET_GP(handle, CTX_GPREG_X6); uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7); return spci_service_request_start(handle, smc_fid, x1, x2, x3, x4, x5, x6, x7); } case SPCI_FID_SERVICE_GET_RESPONSE: { uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7); return spci_service_get_response(handle, x1, x7); } default: break; } } else { /* Tunneled calls */ spci_fid = (smc_fid >> SPCI_FID_TUN_SHIFT) & SPCI_FID_TUN_MASK; switch (spci_fid) { case SPCI_FID_SERVICE_REQUEST_RESUME: { uint64_t x7 = SMC_GET_GP(handle, CTX_GPREG_X7); return spci_service_request_resume(handle, x1, x7); } default: break; } } WARN("SPCI: Unsupported call 0x%08x\n", smc_fid); SMC_RET1(handle, SPCI_NOT_SUPPORTED); } DECLARE_RT_SVC( spci_handler, OEN_SPCI_START, OEN_SPCI_END, SMC_TYPE_FAST, NULL, spci_smc_handler ); trusted-firmware-a-2.2/services/std_svc/spm/spm.mk000066400000000000000000000013221355360272700223260ustar00rootroot00000000000000# # Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ifneq (${SPD},none) $(error "Error: SPD and SPM are incompatible build options.") endif ifneq (${ARCH},aarch64) $(error "Error: SPM is only supported on aarch64.") endif include lib/sprt/sprt_host.mk SPM_SOURCES := $(addprefix services/std_svc/spm/, \ ${ARCH}/spm_helpers.S \ ${ARCH}/spm_shim_exceptions.S \ spci.c \ spm_buffers.c \ spm_main.c \ spm_setup.c \ spm_xlat.c \ sprt.c) \ ${SPRT_LIB_SOURCES} INCLUDES += ${SPRT_LIB_INCLUDES} # Let the top-level Makefile know that we intend to include a BL32 image NEED_BL32 := yes trusted-firmware-a-2.2/services/std_svc/spm/spm_buffers.c000066400000000000000000000050751355360272700236660ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include "./spm_private.h" /******************************************************************************* * Secure Service response global array. All the responses to the requests done * to the Secure Partition are stored here. They are removed from the array as * soon as their value is read. ******************************************************************************/ struct sprt_response { int is_valid; uint32_t token; uint16_t client_id, handle; u_register_t x1, x2, x3; }; static struct sprt_response responses[PLAT_SPM_RESPONSES_MAX]; static spinlock_t responses_lock; /* Add response to the global response buffer. Returns 0 on success else -1. */ int spm_response_add(uint16_t client_id, uint16_t handle, uint32_t token, u_register_t x1, u_register_t x2, u_register_t x3) { spin_lock(&responses_lock); /* Make sure that there isn't any other response with the same token. */ for (unsigned int i = 0U; i < ARRAY_SIZE(responses); i++) { struct sprt_response *resp = &(responses[i]); if ((resp->is_valid == 1) && (resp->token == token)) { spin_unlock(&responses_lock); return -1; } } for (unsigned int i = 0U; i < ARRAY_SIZE(responses); i++) { struct sprt_response *resp = &(responses[i]); if (resp->is_valid == 0) { resp->token = token; resp->client_id = client_id; resp->handle = handle; resp->x1 = x1; resp->x2 = x2; resp->x3 = x3; dmbish(); resp->is_valid = 1; spin_unlock(&responses_lock); return 0; } } spin_unlock(&responses_lock); return -1; } /* * Returns a response from the requests array and removes it from it. Returns 0 * on success, -1 if it wasn't found. */ int spm_response_get(uint16_t client_id, uint16_t handle, uint32_t token, u_register_t *x1, u_register_t *x2, u_register_t *x3) { spin_lock(&responses_lock); for (unsigned int i = 0U; i < ARRAY_SIZE(responses); i++) { struct sprt_response *resp = &(responses[i]); /* Ignore invalid entries */ if (resp->is_valid == 0) { continue; } /* Make sure that all the information matches the stored one */ if ((resp->token != token) || (resp->client_id != client_id) || (resp->handle != handle)) { continue; } *x1 = resp->x1; *x2 = resp->x2; *x3 = resp->x3; dmbish(); resp->is_valid = 0; spin_unlock(&responses_lock); return 0; } spin_unlock(&responses_lock); return -1; } trusted-firmware-a-2.2/services/std_svc/spm/spm_main.c000066400000000000000000000226611355360272700231560ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "spm_private.h" /******************************************************************************* * Secure Partition context information. ******************************************************************************/ sp_context_t sp_ctx_array[PLAT_SPM_MAX_PARTITIONS]; /* Last Secure Partition last used by the CPU */ sp_context_t *cpu_sp_ctx[PLATFORM_CORE_COUNT]; void spm_cpu_set_sp_ctx(unsigned int linear_id, sp_context_t *sp_ctx) { assert(linear_id < PLATFORM_CORE_COUNT); cpu_sp_ctx[linear_id] = sp_ctx; } sp_context_t *spm_cpu_get_sp_ctx(unsigned int linear_id) { assert(linear_id < PLATFORM_CORE_COUNT); return cpu_sp_ctx[linear_id]; } /******************************************************************************* * Functions to keep track of how many requests a Secure Partition has received * and hasn't finished. ******************************************************************************/ void spm_sp_request_increase(sp_context_t *sp_ctx) { spin_lock(&(sp_ctx->request_count_lock)); sp_ctx->request_count++; spin_unlock(&(sp_ctx->request_count_lock)); } void spm_sp_request_decrease(sp_context_t *sp_ctx) { spin_lock(&(sp_ctx->request_count_lock)); sp_ctx->request_count--; spin_unlock(&(sp_ctx->request_count_lock)); } /* Returns 0 if it was originally 0, -1 otherwise. */ int spm_sp_request_increase_if_zero(sp_context_t *sp_ctx) { int ret = -1; spin_lock(&(sp_ctx->request_count_lock)); if (sp_ctx->request_count == 0U) { sp_ctx->request_count++; ret = 0U; } spin_unlock(&(sp_ctx->request_count_lock)); return ret; } /******************************************************************************* * This function returns a pointer to the context of the Secure Partition that * handles the service specified by an UUID. It returns NULL if the UUID wasn't * found. ******************************************************************************/ sp_context_t *spm_sp_get_by_uuid(const uint32_t (*svc_uuid)[4]) { unsigned int i; for (i = 0U; i < PLAT_SPM_MAX_PARTITIONS; i++) { sp_context_t *sp_ctx = &sp_ctx_array[i]; if (sp_ctx->is_present == 0) { continue; } struct sp_rd_sect_service *rdsvc; for (rdsvc = sp_ctx->rd.service; rdsvc != NULL; rdsvc = rdsvc->next) { uint32_t *rd_uuid = (uint32_t *)(rdsvc->uuid); if (memcmp(rd_uuid, svc_uuid, sizeof(*svc_uuid)) == 0) { return sp_ctx; } } } return NULL; } /******************************************************************************* * Set state of a Secure Partition context. ******************************************************************************/ void sp_state_set(sp_context_t *sp_ptr, sp_state_t state) { spin_lock(&(sp_ptr->state_lock)); sp_ptr->state = state; spin_unlock(&(sp_ptr->state_lock)); } /******************************************************************************* * Wait until the state of a Secure Partition is the specified one and change it * to the desired state. ******************************************************************************/ void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to) { int success = 0; while (success == 0) { spin_lock(&(sp_ptr->state_lock)); if (sp_ptr->state == from) { sp_ptr->state = to; success = 1; } spin_unlock(&(sp_ptr->state_lock)); } } /******************************************************************************* * Check if the state of a Secure Partition is the specified one and, if so, * change it to the desired state. Returns 0 on success, -1 on error. ******************************************************************************/ int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to) { int ret = -1; spin_lock(&(sp_ptr->state_lock)); if (sp_ptr->state == from) { sp_ptr->state = to; ret = 0; } spin_unlock(&(sp_ptr->state_lock)); return ret; } /******************************************************************************* * This function takes an SP context pointer and performs a synchronous entry * into it. ******************************************************************************/ uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx, int can_preempt) { uint64_t rc; unsigned int linear_id = plat_my_core_pos(); assert(sp_ctx != NULL); /* Assign the context of the SP to this CPU */ spm_cpu_set_sp_ctx(linear_id, sp_ctx); cm_set_context(&(sp_ctx->cpu_ctx), SECURE); /* Restore the context assigned above */ cm_el1_sysregs_context_restore(SECURE); cm_set_next_eret_context(SECURE); /* Invalidate TLBs at EL1. */ tlbivmalle1(); dsbish(); if (can_preempt == 1) { enable_intr_rm_local(INTR_TYPE_NS, SECURE); } else { disable_intr_rm_local(INTR_TYPE_NS, SECURE); } /* Enter Secure Partition */ rc = spm_secure_partition_enter(&sp_ctx->c_rt_ctx); /* Save secure state */ cm_el1_sysregs_context_save(SECURE); return rc; } /******************************************************************************* * This function returns to the place where spm_sp_synchronous_entry() was * called originally. ******************************************************************************/ __dead2 void spm_sp_synchronous_exit(uint64_t rc) { /* Get context of the SP in use by this CPU. */ unsigned int linear_id = plat_my_core_pos(); sp_context_t *ctx = spm_cpu_get_sp_ctx(linear_id); /* * The SPM must have initiated the original request through a * synchronous entry into the secure partition. Jump back to the * original C runtime context with the value of rc in x0; */ spm_secure_partition_exit(ctx->c_rt_ctx, rc); panic(); } /******************************************************************************* * This function is the handler registered for Non secure interrupts by the SPM. * It validates the interrupt and upon success arranges entry into the normal * world for handling the interrupt. ******************************************************************************/ static uint64_t spm_ns_interrupt_handler(uint32_t id, uint32_t flags, void *handle, void *cookie) { /* Check the security state when the exception was generated */ assert(get_interrupt_src_ss(flags) == SECURE); spm_sp_synchronous_exit(SPM_SECURE_PARTITION_PREEMPTED); } /******************************************************************************* * Jump to each Secure Partition for the first time. ******************************************************************************/ static int32_t spm_init(void) { uint64_t rc = 0; sp_context_t *ctx; for (unsigned int i = 0U; i < PLAT_SPM_MAX_PARTITIONS; i++) { ctx = &sp_ctx_array[i]; if (ctx->is_present == 0) { continue; } INFO("Secure Partition %u init...\n", i); ctx->state = SP_STATE_RESET; rc = spm_sp_synchronous_entry(ctx, 0); if (rc != SPRT_YIELD_AARCH64) { ERROR("Unexpected return value 0x%llx\n", rc); panic(); } ctx->state = SP_STATE_IDLE; INFO("Secure Partition %u initialized.\n", i); } return rc; } /******************************************************************************* * Initialize contexts of all Secure Partitions. ******************************************************************************/ int32_t spm_setup(void) { int rc; sp_context_t *ctx; void *sp_base, *rd_base; size_t sp_size, rd_size; uint64_t flags = 0U; /* Disable MMU at EL1 (initialized by BL2) */ disable_mmu_icache_el1(); /* * Non-blocking services can be interrupted by Non-secure interrupts. * Register an interrupt handler for NS interrupts when generated while * the CPU is in secure state. They are routed to EL3. */ set_interrupt_rm_flag(flags, SECURE); uint64_t rc_int = register_interrupt_type_handler(INTR_TYPE_NS, spm_ns_interrupt_handler, flags); if (rc_int) { ERROR("SPM: Failed to register NS interrupt handler with rc = %llx\n", rc_int); panic(); } /* Setup shim layer */ spm_exceptions_xlat_init_context(); /* * Setup all Secure Partitions. */ unsigned int i = 0U; while (1) { rc = plat_spm_sp_get_next_address(&sp_base, &sp_size, &rd_base, &rd_size); if (rc < 0) { /* Reached the end of the package. */ break; } if (i >= PLAT_SPM_MAX_PARTITIONS) { ERROR("Too many partitions in the package.\n"); panic(); } ctx = &sp_ctx_array[i]; assert(ctx->is_present == 0); /* Initialize context of the SP */ INFO("Secure Partition %u context setup start...\n", i); /* Save location of the image in physical memory */ ctx->image_base = (uintptr_t)sp_base; ctx->image_size = sp_size; rc = plat_spm_sp_rd_load(&ctx->rd, rd_base, rd_size); if (rc < 0) { ERROR("Error while loading RD blob.\n"); panic(); } spm_sp_setup(ctx); ctx->is_present = 1; INFO("Secure Partition %u setup done.\n", i); i++; } if (i == 0U) { ERROR("No present partitions in the package.\n"); panic(); } /* Register init function for deferred init. */ bl31_register_bl32_init(&spm_init); return 0; } trusted-firmware-a-2.2/services/std_svc/spm/spm_private.h000066400000000000000000000073641355360272700237140ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPM_PRIVATE_H #define SPM_PRIVATE_H #include /******************************************************************************* * Constants that allow assembler code to preserve callee-saved registers of the * C runtime context while performing a security state switch. ******************************************************************************/ #define SP_C_RT_CTX_X19 0x0 #define SP_C_RT_CTX_X20 0x8 #define SP_C_RT_CTX_X21 0x10 #define SP_C_RT_CTX_X22 0x18 #define SP_C_RT_CTX_X23 0x20 #define SP_C_RT_CTX_X24 0x28 #define SP_C_RT_CTX_X25 0x30 #define SP_C_RT_CTX_X26 0x38 #define SP_C_RT_CTX_X27 0x40 #define SP_C_RT_CTX_X28 0x48 #define SP_C_RT_CTX_X29 0x50 #define SP_C_RT_CTX_X30 0x58 #define SP_C_RT_CTX_SIZE 0x60 #define SP_C_RT_CTX_ENTRIES (SP_C_RT_CTX_SIZE >> DWORD_SHIFT) /* Value returned by spm_sp_synchronous_entry() when a partition is preempted */ #define SPM_SECURE_PARTITION_PREEMPTED U(0x1234) #ifndef __ASSEMBLER__ #include #include #include #include typedef enum sp_state { SP_STATE_RESET = 0, SP_STATE_IDLE, SP_STATE_BUSY } sp_state_t; typedef struct sp_context { /* 1 if the partition is present, 0 otherwise */ int is_present; /* Location of the image in physical memory */ unsigned long long image_base; size_t image_size; uint64_t c_rt_ctx; cpu_context_t cpu_ctx; struct sp_res_desc rd; /* Translation tables context */ xlat_ctx_t *xlat_ctx_handle; spinlock_t xlat_ctx_lock; sp_state_t state; spinlock_t state_lock; unsigned int request_count; spinlock_t request_count_lock; /* Base and size of the shared SPM<->SP buffer */ uintptr_t spm_sp_buffer_base; size_t spm_sp_buffer_size; spinlock_t spm_sp_buffer_lock; } sp_context_t; /* Functions used to enter/exit a Secure Partition synchronously */ uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx, int can_preempt); __dead2 void spm_sp_synchronous_exit(uint64_t rc); /* Assembly helpers */ uint64_t spm_secure_partition_enter(uint64_t *c_rt_ctx); void __dead2 spm_secure_partition_exit(uint64_t c_rt_ctx, uint64_t ret); /* Secure Partition setup */ void spm_sp_setup(sp_context_t *sp_ctx); /* Secure Partition state management helpers */ void sp_state_set(sp_context_t *sp_ptr, sp_state_t state); void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to); int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to); /* Functions to keep track of the number of active requests per SP */ void spm_sp_request_increase(sp_context_t *sp_ctx); void spm_sp_request_decrease(sp_context_t *sp_ctx); int spm_sp_request_increase_if_zero(sp_context_t *sp_ctx); /* Functions related to the shim layer translation tables */ void spm_exceptions_xlat_init_context(void); uint64_t *spm_exceptions_xlat_get_base_table(void); /* Functions related to the translation tables management */ void spm_sp_xlat_context_alloc(sp_context_t *sp_ctx); void sp_map_memory_regions(sp_context_t *sp_ctx); /* Functions to handle Secure Partition contexts */ void spm_cpu_set_sp_ctx(unsigned int linear_id, sp_context_t *sp_ctx); sp_context_t *spm_cpu_get_sp_ctx(unsigned int linear_id); sp_context_t *spm_sp_get_by_uuid(const uint32_t (*svc_uuid)[4]); /* Functions to manipulate response and requests buffers */ int spm_response_add(uint16_t client_id, uint16_t handle, uint32_t token, u_register_t x1, u_register_t x2, u_register_t x3); int spm_response_get(uint16_t client_id, uint16_t handle, uint32_t token, u_register_t *x1, u_register_t *x2, u_register_t *x3); #endif /* __ASSEMBLER__ */ #endif /* SPM_PRIVATE_H */ trusted-firmware-a-2.2/services/std_svc/spm/spm_setup.c000066400000000000000000000111311355360272700233600ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "spm_private.h" #include "spm_shim_private.h" /* Setup context of the Secure Partition */ void spm_sp_setup(sp_context_t *sp_ctx) { cpu_context_t *ctx = &(sp_ctx->cpu_ctx); /* * Initialize CPU context * ---------------------- */ entry_point_info_t ep_info = {0}; SET_PARAM_HEAD(&ep_info, PARAM_EP, VERSION_1, SECURE | EP_ST_ENABLE); /* Setup entrypoint and SPSR */ ep_info.pc = sp_ctx->rd.attribute.entrypoint; ep_info.spsr = SPSR_64(MODE_EL0, MODE_SP_EL0, DISABLE_ALL_EXCEPTIONS); /* * X0: Unused (MBZ). * X1: Unused (MBZ). * X2: cookie value (Implementation Defined) * X3: cookie value (Implementation Defined) * X4 to X7 = 0 */ ep_info.args.arg0 = 0; ep_info.args.arg1 = 0; ep_info.args.arg2 = PLAT_SPM_COOKIE_0; ep_info.args.arg3 = PLAT_SPM_COOKIE_1; cm_setup_context(ctx, &ep_info); /* * Setup translation tables * ------------------------ */ /* Assign translation tables context. */ spm_sp_xlat_context_alloc(sp_ctx); sp_map_memory_regions(sp_ctx); /* * MMU-related registers * --------------------- */ xlat_ctx_t *xlat_ctx = sp_ctx->xlat_ctx_handle; uint64_t mmu_cfg_params[MMU_CFG_PARAM_MAX]; setup_mmu_cfg((uint64_t *)&mmu_cfg_params, 0, xlat_ctx->base_table, xlat_ctx->pa_max_address, xlat_ctx->va_max_address, EL1_EL0_REGIME); write_ctx_reg(get_sysregs_ctx(ctx), CTX_MAIR_EL1, mmu_cfg_params[MMU_CFG_MAIR]); /* Enable translations using TTBR1_EL1 */ int t1sz = 64 - __builtin_ctzll(SPM_SHIM_XLAT_VIRT_ADDR_SPACE_SIZE); mmu_cfg_params[MMU_CFG_TCR] &= ~TCR_EPD1_BIT; mmu_cfg_params[MMU_CFG_TCR] |= ((uint64_t)t1sz << TCR_T1SZ_SHIFT) | TCR_SH1_INNER_SHAREABLE | TCR_RGN1_OUTER_WBA | TCR_RGN1_INNER_WBA | TCR_TG1_4K; write_ctx_reg(get_sysregs_ctx(ctx), CTX_TCR_EL1, mmu_cfg_params[MMU_CFG_TCR]); write_ctx_reg(get_sysregs_ctx(ctx), CTX_TTBR0_EL1, mmu_cfg_params[MMU_CFG_TTBR0]); write_ctx_reg(get_sysregs_ctx(ctx), CTX_TTBR1_EL1, (uint64_t)spm_exceptions_xlat_get_base_table()); /* Setup SCTLR_EL1 */ u_register_t sctlr_el1 = read_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1); sctlr_el1 |= /*SCTLR_EL1_RES1 |*/ /* Don't trap DC CVAU, DC CIVAC, DC CVAC, DC CVAP, or IC IVAU */ SCTLR_UCI_BIT | /* RW regions at xlat regime EL1&0 are forced to be XN. */ SCTLR_WXN_BIT | /* Don't trap to EL1 execution of WFI or WFE at EL0. */ SCTLR_NTWI_BIT | SCTLR_NTWE_BIT | /* Don't trap to EL1 accesses to CTR_EL0 from EL0. */ SCTLR_UCT_BIT | /* Don't trap to EL1 execution of DZ ZVA at EL0. */ SCTLR_DZE_BIT | /* Enable SP Alignment check for EL0 */ SCTLR_SA0_BIT | /* Allow cacheable data and instr. accesses to normal memory. */ SCTLR_C_BIT | SCTLR_I_BIT | /* Alignment fault checking enabled when at EL1 and EL0. */ SCTLR_A_BIT | /* Enable MMU. */ SCTLR_M_BIT ; sctlr_el1 &= ~( /* Explicit data accesses at EL0 are little-endian. */ SCTLR_E0E_BIT | /* Accesses to DAIF from EL0 are trapped to EL1. */ SCTLR_UMA_BIT ); write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_el1); /* * Setup other system registers * ---------------------------- */ /* * Shim exception vector base address. It is mapped at the start of the * address space accessed by TTBR1_EL1, which means that the base * address of the exception vectors depends on the size of the address * space specified in TCR_EL1.T1SZ. */ write_ctx_reg(get_sysregs_ctx(ctx), CTX_VBAR_EL1, UINT64_MAX - (SPM_SHIM_XLAT_VIRT_ADDR_SPACE_SIZE - 1ULL)); /* * FPEN: Allow the Secure Partition to access FP/SIMD registers. * Note that SPM will not do any saving/restoring of these registers on * behalf of the SP. This falls under the SP's responsibility. * TTA: Enable access to trace registers. * ZEN (v8.2): Trap SVE instructions and access to SVE registers. */ write_ctx_reg(get_sysregs_ctx(ctx), CTX_CPACR_EL1, CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE)); /* * Prepare shared buffers * ---------------------- */ /* Initialize SPRT queues */ sprt_initialize_queues((void *)sp_ctx->spm_sp_buffer_base, sp_ctx->spm_sp_buffer_size); } trusted-firmware-a-2.2/services/std_svc/spm/spm_shim_private.h000066400000000000000000000015451355360272700247270ustar00rootroot00000000000000/* * Copyright (c) 2017-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPM_SHIM_PRIVATE_H #define SPM_SHIM_PRIVATE_H #include #include /* Assembly source */ IMPORT_SYM(uintptr_t, spm_shim_exceptions_ptr, SPM_SHIM_EXCEPTIONS_PTR); /* Linker symbols */ IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_START__, SPM_SHIM_EXCEPTIONS_START); IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_END__, SPM_SHIM_EXCEPTIONS_END); /* Definitions */ #define SPM_SHIM_EXCEPTIONS_SIZE \ (SPM_SHIM_EXCEPTIONS_END - SPM_SHIM_EXCEPTIONS_START) /* * Use the smallest virtual address space size allowed in ARMv8.0 for * compatibility. */ #define SPM_SHIM_XLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 25) #define SPM_SHIM_MMAP_REGIONS 1 #define SPM_SHIM_XLAT_TABLES 1 #endif /* SPM_SHIM_PRIVATE_H */ trusted-firmware-a-2.2/services/std_svc/spm/spm_xlat.c000066400000000000000000000255671355360272700232120ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "spm_private.h" #include "spm_shim_private.h" /******************************************************************************* * Instantiation of translation table context ******************************************************************************/ /* Place translation tables by default along with the ones used by BL31. */ #ifndef PLAT_SP_IMAGE_XLAT_SECTION_NAME #define PLAT_SP_IMAGE_XLAT_SECTION_NAME "xlat_table" #endif /* * Allocate elements of the translation contexts for the Secure Partitions. */ /* Allocate an array of mmap_region per partition. */ static struct mmap_region sp_mmap_regions[PLAT_SP_IMAGE_MMAP_REGIONS + 1] [PLAT_SPM_MAX_PARTITIONS]; static OBJECT_POOL(sp_mmap_regions_pool, sp_mmap_regions, sizeof(mmap_region_t) * (PLAT_SP_IMAGE_MMAP_REGIONS + 1), PLAT_SPM_MAX_PARTITIONS); /* Allocate individual translation tables. */ static uint64_t sp_xlat_tables[XLAT_TABLE_ENTRIES] [(PLAT_SP_IMAGE_MAX_XLAT_TABLES + 1) * PLAT_SPM_MAX_PARTITIONS] __aligned(XLAT_TABLE_SIZE) __section(PLAT_SP_IMAGE_XLAT_SECTION_NAME); static OBJECT_POOL(sp_xlat_tables_pool, sp_xlat_tables, XLAT_TABLE_ENTRIES * sizeof(uint64_t), (PLAT_SP_IMAGE_MAX_XLAT_TABLES + 1) * PLAT_SPM_MAX_PARTITIONS); /* Allocate arrays. */ static int sp_xlat_mapped_regions[PLAT_SP_IMAGE_MAX_XLAT_TABLES] [PLAT_SPM_MAX_PARTITIONS]; static OBJECT_POOL(sp_xlat_mapped_regions_pool, sp_xlat_mapped_regions, sizeof(int) * PLAT_SP_IMAGE_MAX_XLAT_TABLES, PLAT_SPM_MAX_PARTITIONS); /* Allocate individual contexts. */ static xlat_ctx_t sp_xlat_ctx[PLAT_SPM_MAX_PARTITIONS]; static OBJECT_POOL(sp_xlat_ctx_pool, sp_xlat_ctx, sizeof(xlat_ctx_t), PLAT_SPM_MAX_PARTITIONS); /* Get handle of Secure Partition translation context */ void spm_sp_xlat_context_alloc(sp_context_t *sp_ctx) { /* Allocate xlat context elements */ xlat_ctx_t *ctx = pool_alloc(&sp_xlat_ctx_pool); struct mmap_region *mmap = pool_alloc(&sp_mmap_regions_pool); uint64_t *base_table = pool_alloc(&sp_xlat_tables_pool); uint64_t **tables = pool_alloc_n(&sp_xlat_tables_pool, PLAT_SP_IMAGE_MAX_XLAT_TABLES); int *mapped_regions = pool_alloc(&sp_xlat_mapped_regions_pool); /* Calculate the size of the virtual address space needed */ uintptr_t va_size = 0U; struct sp_rd_sect_mem_region *rdmem; for (rdmem = sp_ctx->rd.mem_region; rdmem != NULL; rdmem = rdmem->next) { uintptr_t end_va = (uintptr_t)rdmem->base + (uintptr_t)rdmem->size; if (end_va > va_size) va_size = end_va; } if (va_size == 0U) { ERROR("No regions in resource description.\n"); panic(); } /* * Get the power of two that is greater or equal to the top VA. The * values of base and size in the resource description are 32-bit wide * so the values will never overflow when using a uintptr_t. */ if (!IS_POWER_OF_TWO(va_size)) { va_size = 1ULL << ((sizeof(va_size) * 8) - __builtin_clzll(va_size)); } if (va_size > PLAT_VIRT_ADDR_SPACE_SIZE) { ERROR("Resource description requested too much virtual memory.\n"); panic(); } uintptr_t min_va_size; /* The following sizes are only valid for 4KB pages */ assert(PAGE_SIZE == (4U * 1024U)); if (is_armv8_4_ttst_present()) { VERBOSE("Using ARMv8.4-TTST\n"); min_va_size = 1ULL << (64 - TCR_TxSZ_MAX_TTST); } else { min_va_size = 1ULL << (64 - TCR_TxSZ_MAX); } if (va_size < min_va_size) { va_size = min_va_size; } /* Initialize xlat context */ xlat_setup_dynamic_ctx(ctx, PLAT_PHY_ADDR_SPACE_SIZE - 1ULL, va_size - 1ULL, mmap, PLAT_SP_IMAGE_MMAP_REGIONS, tables, PLAT_SP_IMAGE_MAX_XLAT_TABLES, base_table, EL1_EL0_REGIME, mapped_regions); sp_ctx->xlat_ctx_handle = ctx; }; /******************************************************************************* * Translation table context used for S-EL1 exception vectors ******************************************************************************/ REGISTER_XLAT_CONTEXT2(spm_sel1, SPM_SHIM_MMAP_REGIONS, SPM_SHIM_XLAT_TABLES, SPM_SHIM_XLAT_VIRT_ADDR_SPACE_SIZE, PLAT_PHY_ADDR_SPACE_SIZE, EL1_EL0_REGIME, PLAT_SP_IMAGE_XLAT_SECTION_NAME); void spm_exceptions_xlat_init_context(void) { /* This region contains the exception vectors used at S-EL1. */ mmap_region_t sel1_exception_vectors = MAP_REGION(SPM_SHIM_EXCEPTIONS_PTR, 0x0UL, SPM_SHIM_EXCEPTIONS_SIZE, MT_CODE | MT_SECURE | MT_PRIVILEGED); mmap_add_region_ctx(&spm_sel1_xlat_ctx, &sel1_exception_vectors); init_xlat_tables_ctx(&spm_sel1_xlat_ctx); } uint64_t *spm_exceptions_xlat_get_base_table(void) { return spm_sel1_xlat_ctx.base_table; } /******************************************************************************* * Functions to allocate memory for regions. ******************************************************************************/ /* * The region with base PLAT_SPM_HEAP_BASE and size PLAT_SPM_HEAP_SIZE is * reserved for SPM to use as heap to allocate memory regions of Secure * Partitions. This is only done at boot. */ static OBJECT_POOL(spm_heap_mem, (void *)PLAT_SPM_HEAP_BASE, 1U, PLAT_SPM_HEAP_SIZE); static uintptr_t spm_alloc_heap(size_t size) { return (uintptr_t)pool_alloc_n(&spm_heap_mem, size); } /******************************************************************************* * Functions to map memory regions described in the resource description. ******************************************************************************/ static unsigned int rdmem_attr_to_mmap_attr(uint32_t attr) { unsigned int index = attr & RD_MEM_MASK; const unsigned int mmap_attr_arr[8] = { MT_DEVICE | MT_RW | MT_SECURE, /* RD_MEM_DEVICE */ MT_CODE | MT_SECURE, /* RD_MEM_NORMAL_CODE */ MT_MEMORY | MT_RW | MT_SECURE, /* RD_MEM_NORMAL_DATA */ MT_MEMORY | MT_RW | MT_SECURE, /* RD_MEM_NORMAL_BSS */ MT_RO_DATA | MT_SECURE, /* RD_MEM_NORMAL_RODATA */ MT_MEMORY | MT_RW | MT_SECURE, /* RD_MEM_NORMAL_SPM_SP_SHARED_MEM */ MT_MEMORY | MT_RW | MT_SECURE, /* RD_MEM_NORMAL_CLIENT_SHARED_MEM */ MT_MEMORY | MT_RW | MT_SECURE /* RD_MEM_NORMAL_MISCELLANEOUS */ }; if (index >= ARRAY_SIZE(mmap_attr_arr)) { ERROR("Unsupported RD memory attributes 0x%x\n", attr); panic(); } return mmap_attr_arr[index]; } /* * The data provided in the resource description structure is not directly * compatible with a mmap_region structure. This function handles the conversion * and maps it. */ static void map_rdmem(sp_context_t *sp_ctx, struct sp_rd_sect_mem_region *rdmem) { int rc; mmap_region_t mmap; /* Location of the SP image */ uintptr_t sp_size = sp_ctx->image_size; uintptr_t sp_base_va = sp_ctx->rd.attribute.load_address; unsigned long long sp_base_pa = sp_ctx->image_base; /* Location of the memory region to map */ size_t rd_size = rdmem->size; uintptr_t rd_base_va = rdmem->base; unsigned long long rd_base_pa; unsigned int memtype = rdmem->attr & RD_MEM_MASK; if (rd_size == 0U) { VERBOSE("Memory region '%s' is empty. Ignored.\n", rdmem->name); return; } VERBOSE("Adding memory region '%s'\n", rdmem->name); mmap.granularity = REGION_DEFAULT_GRANULARITY; /* Check if the RD region is inside of the SP image or not */ int is_outside = (rd_base_va + rd_size <= sp_base_va) || (sp_base_va + sp_size <= rd_base_va); /* Set to 1 if it is needed to zero this region */ int zero_region = 0; switch (memtype) { case RD_MEM_DEVICE: /* Device regions are mapped 1:1 */ rd_base_pa = rd_base_va; break; case RD_MEM_NORMAL_CODE: case RD_MEM_NORMAL_RODATA: { if (is_outside == 1) { ERROR("Code and rodata sections must be fully contained in the image."); panic(); } /* Get offset into the image */ rd_base_pa = sp_base_pa + rd_base_va - sp_base_va; break; } case RD_MEM_NORMAL_DATA: { if (is_outside == 1) { ERROR("Data sections must be fully contained in the image."); panic(); } rd_base_pa = spm_alloc_heap(rd_size); /* Get offset into the image */ void *img_pa = (void *)(sp_base_pa + rd_base_va - sp_base_va); VERBOSE(" Copying data from %p to 0x%llx\n", img_pa, rd_base_pa); /* Map destination */ rc = mmap_add_dynamic_region(rd_base_pa, rd_base_pa, rd_size, MT_MEMORY | MT_RW | MT_SECURE); if (rc != 0) { ERROR("Unable to map data region at EL3: %d\n", rc); panic(); } /* Copy original data to destination */ memcpy((void *)rd_base_pa, img_pa, rd_size); /* Unmap destination region */ rc = mmap_remove_dynamic_region(rd_base_pa, rd_size); if (rc != 0) { ERROR("Unable to remove data region at EL3: %d\n", rc); panic(); } break; } case RD_MEM_NORMAL_MISCELLANEOUS: /* Allow SPM to change the attributes of the region. */ mmap.granularity = PAGE_SIZE; rd_base_pa = spm_alloc_heap(rd_size); zero_region = 1; break; case RD_MEM_NORMAL_SPM_SP_SHARED_MEM: if ((sp_ctx->spm_sp_buffer_base != 0) || (sp_ctx->spm_sp_buffer_size != 0)) { ERROR("A partition must have only one SPM<->SP buffer.\n"); panic(); } rd_base_pa = spm_alloc_heap(rd_size); zero_region = 1; /* Save location of this buffer, it is needed by SPM */ sp_ctx->spm_sp_buffer_base = rd_base_pa; sp_ctx->spm_sp_buffer_size = rd_size; break; case RD_MEM_NORMAL_CLIENT_SHARED_MEM: /* Fallthrough */ case RD_MEM_NORMAL_BSS: rd_base_pa = spm_alloc_heap(rd_size); zero_region = 1; break; default: panic(); } mmap.base_pa = rd_base_pa; mmap.base_va = rd_base_va; mmap.size = rd_size; /* Only S-EL0 mappings supported for now */ mmap.attr = rdmem_attr_to_mmap_attr(rdmem->attr) | MT_USER; VERBOSE(" VA: 0x%lx PA: 0x%llx (0x%lx, attr: 0x%x)\n", mmap.base_va, mmap.base_pa, mmap.size, mmap.attr); /* Map region in the context of the Secure Partition */ mmap_add_region_ctx(sp_ctx->xlat_ctx_handle, &mmap); if (zero_region == 1) { VERBOSE(" Zeroing region...\n"); rc = mmap_add_dynamic_region(mmap.base_pa, mmap.base_pa, mmap.size, MT_MEMORY | MT_RW | MT_SECURE); if (rc != 0) { ERROR("Unable to map memory at EL3 to zero: %d\n", rc); panic(); } zeromem((void *)mmap.base_pa, mmap.size); /* * Unmap destination region unless it is the SPM<->SP buffer, * which must be used by SPM. */ if (memtype != RD_MEM_NORMAL_SPM_SP_SHARED_MEM) { rc = mmap_remove_dynamic_region(rd_base_pa, rd_size); if (rc != 0) { ERROR("Unable to remove region at EL3: %d\n", rc); panic(); } } } } void sp_map_memory_regions(sp_context_t *sp_ctx) { struct sp_rd_sect_mem_region *rdmem; for (rdmem = sp_ctx->rd.mem_region; rdmem != NULL; rdmem = rdmem->next) { map_rdmem(sp_ctx, rdmem); } init_xlat_tables_ctx(sp_ctx->xlat_ctx_handle); } trusted-firmware-a-2.2/services/std_svc/spm/sprt.c000066400000000000000000000135171355360272700223430ustar00rootroot00000000000000/* * Copyright (c) 2018-2019, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include "spm_private.h" /******************************************************************************* * Functions to manipulate memory regions ******************************************************************************/ /* * Attributes are encoded using a different format in the SMC interface than in * the Trusted Firmware, where the mmap_attr_t enum type is used. This function * converts an attributes value from the SMC format to the mmap_attr_t format by * setting MT_RW/MT_RO, MT_USER/MT_PRIVILEGED and MT_EXECUTE/MT_EXECUTE_NEVER. * The other fields are left as 0 because they are ignored by the function * xlat_change_mem_attributes_ctx(). */ static unsigned int smc_attr_to_mmap_attr(unsigned int attributes) { unsigned int perm = attributes & SPRT_MEMORY_PERM_ATTR_MASK; if (perm == SPRT_MEMORY_PERM_ATTR_RW) { return MT_RW | MT_EXECUTE_NEVER | MT_USER; } else if (perm == SPRT_MEMORY_PERM_ATTR_RO) { return MT_RO | MT_EXECUTE_NEVER | MT_USER; } else if (perm == SPRT_MEMORY_PERM_ATTR_RO_EXEC) { return MT_RO | MT_USER; } else { return UINT_MAX; } } /* * This function converts attributes from the Trusted Firmware format into the * SMC interface format. */ static unsigned int mmap_attr_to_smc_attr(unsigned int attr) { unsigned int perm; /* No access from EL0. */ if ((attr & MT_USER) == 0U) return UINT_MAX; if ((attr & MT_RW) != 0) { assert(MT_TYPE(attr) != MT_DEVICE); perm = SPRT_MEMORY_PERM_ATTR_RW; } else { if ((attr & MT_EXECUTE_NEVER) != 0U) { perm = SPRT_MEMORY_PERM_ATTR_RO; } else { perm = SPRT_MEMORY_PERM_ATTR_RO_EXEC; } } return perm << SPRT_MEMORY_PERM_ATTR_SHIFT; } static int32_t sprt_memory_perm_attr_get(sp_context_t *sp_ctx, uintptr_t base_va) { uint32_t attributes; spin_lock(&(sp_ctx->xlat_ctx_lock)); int ret = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle, base_va, &attributes); spin_unlock(&(sp_ctx->xlat_ctx_lock)); /* Convert error codes of xlat_get_mem_attributes_ctx() into SPM. */ assert((ret == 0) || (ret == -EINVAL)); if (ret != 0) return SPRT_INVALID_PARAMETER; unsigned int perm = mmap_attr_to_smc_attr(attributes); if (perm == UINT_MAX) return SPRT_INVALID_PARAMETER; return SPRT_SUCCESS | perm; } static int32_t sprt_memory_perm_attr_set(sp_context_t *sp_ctx, u_register_t page_address, u_register_t pages_count, u_register_t smc_attributes) { int ret; uintptr_t base_va = (uintptr_t) page_address; size_t size = pages_count * PAGE_SIZE; VERBOSE(" Start address : 0x%lx\n", base_va); VERBOSE(" Number of pages: %i (%zi bytes)\n", (int) pages_count, size); VERBOSE(" Attributes : 0x%lx\n", smc_attributes); uint32_t mmap_attr = smc_attr_to_mmap_attr(smc_attributes); if (mmap_attr == UINT_MAX) { WARN("%s: Invalid memory attributes: 0x%lx\n", __func__, smc_attributes); return SPRT_INVALID_PARAMETER; } /* * Perform some checks before actually trying to change the memory * attributes. */ spin_lock(&(sp_ctx->xlat_ctx_lock)); uint32_t attributes; ret = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle, base_va, &attributes); if (ret != 0) { spin_unlock(&(sp_ctx->xlat_ctx_lock)); return SPRT_INVALID_PARAMETER; } if ((attributes & MT_USER) == 0U) { /* Prohibit changing attributes of S-EL1 regions */ spin_unlock(&(sp_ctx->xlat_ctx_lock)); return SPRT_INVALID_PARAMETER; } ret = xlat_change_mem_attributes_ctx(sp_ctx->xlat_ctx_handle, base_va, size, mmap_attr); spin_unlock(&(sp_ctx->xlat_ctx_lock)); /* Convert error codes of xlat_change_mem_attributes_ctx() into SPM. */ assert((ret == 0) || (ret == -EINVAL)); return (ret == 0) ? SPRT_SUCCESS : SPRT_INVALID_PARAMETER; } /******************************************************************************* * This function handles all SMCs in the range reserved for SPRT. ******************************************************************************/ static uintptr_t sprt_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) { /* SPRT only supported from the Secure world */ if (is_caller_non_secure(flags) == SMC_FROM_NON_SECURE) { SMC_RET1(handle, SMC_UNK); } assert(handle == cm_get_context(SECURE)); /* * Only S-EL0 partitions are supported for now. Make the next ERET into * the partition jump directly to S-EL0 instead of S-EL1. */ cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1()); switch (smc_fid) { case SPRT_VERSION: SMC_RET1(handle, SPRT_VERSION_COMPILED); case SPRT_PUT_RESPONSE_AARCH64: spm_sp_synchronous_exit(SPRT_PUT_RESPONSE_AARCH64); case SPRT_YIELD_AARCH64: spm_sp_synchronous_exit(SPRT_YIELD_AARCH64); case SPRT_MEMORY_PERM_ATTR_GET_AARCH64: { /* Get context of the SP in use by this CPU. */ unsigned int linear_id = plat_my_core_pos(); sp_context_t *sp_ctx = spm_cpu_get_sp_ctx(linear_id); SMC_RET1(handle, sprt_memory_perm_attr_get(sp_ctx, x1)); } case SPRT_MEMORY_PERM_ATTR_SET_AARCH64: { /* Get context of the SP in use by this CPU. */ unsigned int linear_id = plat_my_core_pos(); sp_context_t *sp_ctx = spm_cpu_get_sp_ctx(linear_id); SMC_RET1(handle, sprt_memory_perm_attr_set(sp_ctx, x1, x2, x3)); } default: break; } WARN("SPRT: Unsupported call 0x%08x\n", smc_fid); SMC_RET1(handle, SPRT_NOT_SUPPORTED); } DECLARE_RT_SVC( sprt_handler, OEN_SPRT_START, OEN_SPRT_END, SMC_TYPE_FAST, NULL, sprt_smc_handler ); trusted-firmware-a-2.2/services/std_svc/spm_mm/000077500000000000000000000000001355360272700216715ustar00rootroot00000000000000trusted-firmware-a-2.2/services/std_svc/spm_mm/aarch64/000077500000000000000000000000001355360272700231215ustar00rootroot00000000000000trusted-firmware-a-2.2/services/std_svc/spm_mm/aarch64/spm_helpers.S000066400000000000000000000056371355360272700256010ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "../spm_private.h" .global spm_secure_partition_enter .global spm_secure_partition_exit /* --------------------------------------------------------------------- * This function is called with SP_EL0 as stack. Here we stash our EL3 * callee-saved registers on to the stack as a part of saving the C * runtime and enter the secure payload. * 'x0' contains a pointer to the memory where the address of the C * runtime context is to be saved. * --------------------------------------------------------------------- */ func spm_secure_partition_enter /* Make space for the registers that we're going to save */ mov x3, sp str x3, [x0, #0] sub sp, sp, #SP_C_RT_CTX_SIZE /* Save callee-saved registers on to the stack */ stp x19, x20, [sp, #SP_C_RT_CTX_X19] stp x21, x22, [sp, #SP_C_RT_CTX_X21] stp x23, x24, [sp, #SP_C_RT_CTX_X23] stp x25, x26, [sp, #SP_C_RT_CTX_X25] stp x27, x28, [sp, #SP_C_RT_CTX_X27] stp x29, x30, [sp, #SP_C_RT_CTX_X29] /* --------------------------------------------------------------------- * Everything is setup now. el3_exit() will use the secure context to * restore to the general purpose and EL3 system registers to ERET * into the secure payload. * --------------------------------------------------------------------- */ b el3_exit endfunc spm_secure_partition_enter /* --------------------------------------------------------------------- * This function is called with 'x0' pointing to a C runtime context * saved in spm_secure_partition_enter(). * It restores the saved registers and jumps to that runtime with 'x0' * as the new SP register. This destroys the C runtime context that had * been built on the stack below the saved context by the caller. Later * the second parameter 'x1' is passed as a return value to the caller. * --------------------------------------------------------------------- */ func spm_secure_partition_exit /* Restore the previous stack */ mov sp, x0 /* Restore callee-saved registers on to the stack */ ldp x19, x20, [x0, #(SP_C_RT_CTX_X19 - SP_C_RT_CTX_SIZE)] ldp x21, x22, [x0, #(SP_C_RT_CTX_X21 - SP_C_RT_CTX_SIZE)] ldp x23, x24, [x0, #(SP_C_RT_CTX_X23 - SP_C_RT_CTX_SIZE)] ldp x25, x26, [x0, #(SP_C_RT_CTX_X25 - SP_C_RT_CTX_SIZE)] ldp x27, x28, [x0, #(SP_C_RT_CTX_X27 - SP_C_RT_CTX_SIZE)] ldp x29, x30, [x0, #(SP_C_RT_CTX_X29 - SP_C_RT_CTX_SIZE)] /* --------------------------------------------------------------------- * This should take us back to the instruction after the call to the * last spm_secure_partition_enter().* Place the second parameter to x0 * so that the caller will see it as a return value from the original * entry call. * --------------------------------------------------------------------- */ mov x0, x1 ret endfunc spm_secure_partition_exit trusted-firmware-a-2.2/services/std_svc/spm_mm/aarch64/spm_shim_exceptions.S000066400000000000000000000061121355360272700273250ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include /* ----------------------------------------------------------------------------- * Very simple stackless exception handlers used by the spm shim layer. * ----------------------------------------------------------------------------- */ .globl spm_shim_exceptions_ptr vector_base spm_shim_exceptions_ptr, .spm_shim_exceptions /* ----------------------------------------------------- * Current EL with SP0 : 0x0 - 0x200 * ----------------------------------------------------- */ vector_entry SynchronousExceptionSP0, .spm_shim_exceptions b . end_vector_entry SynchronousExceptionSP0 vector_entry IrqSP0, .spm_shim_exceptions b . end_vector_entry IrqSP0 vector_entry FiqSP0, .spm_shim_exceptions b . end_vector_entry FiqSP0 vector_entry SErrorSP0, .spm_shim_exceptions b . end_vector_entry SErrorSP0 /* ----------------------------------------------------- * Current EL with SPx: 0x200 - 0x400 * ----------------------------------------------------- */ vector_entry SynchronousExceptionSPx, .spm_shim_exceptions b . end_vector_entry SynchronousExceptionSPx vector_entry IrqSPx, .spm_shim_exceptions b . end_vector_entry IrqSPx vector_entry FiqSPx, .spm_shim_exceptions b . end_vector_entry FiqSPx vector_entry SErrorSPx, .spm_shim_exceptions b . end_vector_entry SErrorSPx /* ----------------------------------------------------- * Lower EL using AArch64 : 0x400 - 0x600. No exceptions * are handled since secure_partition does not implement * a lower EL * ----------------------------------------------------- */ vector_entry SynchronousExceptionA64, .spm_shim_exceptions msr tpidr_el1, x30 mrs x30, esr_el1 ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH cmp x30, #EC_AARCH64_SVC b.eq do_smc cmp x30, #EC_AARCH32_SVC b.eq do_smc cmp x30, #EC_AARCH64_SYS b.eq handle_sys_trap /* Fail in all the other cases */ b panic /* --------------------------------------------- * Tell SPM that we are done initialising * --------------------------------------------- */ do_smc: mrs x30, tpidr_el1 smc #0 eret /* AArch64 system instructions trap are handled as a panic for now */ handle_sys_trap: panic: b panic end_vector_entry SynchronousExceptionA64 vector_entry IrqA64, .spm_shim_exceptions b . end_vector_entry IrqA64 vector_entry FiqA64, .spm_shim_exceptions b . end_vector_entry FiqA64 vector_entry SErrorA64, .spm_shim_exceptions b . end_vector_entry SErrorA64 /* ----------------------------------------------------- * Lower EL using AArch32 : 0x600 - 0x800 * ----------------------------------------------------- */ vector_entry SynchronousExceptionA32, .spm_shim_exceptions b . end_vector_entry SynchronousExceptionA32 vector_entry IrqA32, .spm_shim_exceptions b . end_vector_entry IrqA32 vector_entry FiqA32, .spm_shim_exceptions b . end_vector_entry FiqA32 vector_entry SErrorA32, .spm_shim_exceptions b . end_vector_entry SErrorA32 trusted-firmware-a-2.2/services/std_svc/spm_mm/spm.mk000066400000000000000000000012501355360272700230170ustar00rootroot00000000000000# # Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ifneq (${SPD},none) $(error "Error: SPD and SPM are incompatible build options.") endif ifneq (${ARCH},aarch64) $(error "Error: SPM is only supported on aarch64.") endif SPM_SOURCES := $(addprefix services/std_svc/spm_mm/, \ ${ARCH}/spm_helpers.S \ ${ARCH}/spm_shim_exceptions.S \ spm_main.c \ spm_setup.c \ spm_xlat.c) # Let the top-level Makefile know that we intend to include a BL32 image NEED_BL32 := yes # required so that SPM code executing at S-EL0 can access the timer registers NS_TIMER_SWITCH := 1 trusted-firmware-a-2.2/services/std_svc/spm_mm/spm_main.c000066400000000000000000000231431355360272700236430ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "spm_private.h" /******************************************************************************* * Secure Partition context information. ******************************************************************************/ static sp_context_t sp_ctx; /******************************************************************************* * Set state of a Secure Partition context. ******************************************************************************/ void sp_state_set(sp_context_t *sp_ptr, sp_state_t state) { spin_lock(&(sp_ptr->state_lock)); sp_ptr->state = state; spin_unlock(&(sp_ptr->state_lock)); } /******************************************************************************* * Wait until the state of a Secure Partition is the specified one and change it * to the desired state. ******************************************************************************/ void sp_state_wait_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to) { int success = 0; while (success == 0) { spin_lock(&(sp_ptr->state_lock)); if (sp_ptr->state == from) { sp_ptr->state = to; success = 1; } spin_unlock(&(sp_ptr->state_lock)); } } /******************************************************************************* * Check if the state of a Secure Partition is the specified one and, if so, * change it to the desired state. Returns 0 on success, -1 on error. ******************************************************************************/ int sp_state_try_switch(sp_context_t *sp_ptr, sp_state_t from, sp_state_t to) { int ret = -1; spin_lock(&(sp_ptr->state_lock)); if (sp_ptr->state == from) { sp_ptr->state = to; ret = 0; } spin_unlock(&(sp_ptr->state_lock)); return ret; } /******************************************************************************* * This function takes an SP context pointer and performs a synchronous entry * into it. ******************************************************************************/ static uint64_t spm_sp_synchronous_entry(sp_context_t *sp_ctx) { uint64_t rc; assert(sp_ctx != NULL); /* Assign the context of the SP to this CPU */ cm_set_context(&(sp_ctx->cpu_ctx), SECURE); /* Restore the context assigned above */ cm_el1_sysregs_context_restore(SECURE); cm_set_next_eret_context(SECURE); /* Invalidate TLBs at EL1. */ tlbivmalle1(); dsbish(); /* Enter Secure Partition */ rc = spm_secure_partition_enter(&sp_ctx->c_rt_ctx); /* Save secure state */ cm_el1_sysregs_context_save(SECURE); return rc; } /******************************************************************************* * This function returns to the place where spm_sp_synchronous_entry() was * called originally. ******************************************************************************/ __dead2 static void spm_sp_synchronous_exit(uint64_t rc) { sp_context_t *ctx = &sp_ctx; /* * The SPM must have initiated the original request through a * synchronous entry into the secure partition. Jump back to the * original C runtime context with the value of rc in x0; */ spm_secure_partition_exit(ctx->c_rt_ctx, rc); panic(); } /******************************************************************************* * Jump to each Secure Partition for the first time. ******************************************************************************/ static int32_t spm_init(void) { uint64_t rc; sp_context_t *ctx; INFO("Secure Partition init...\n"); ctx = &sp_ctx; ctx->state = SP_STATE_RESET; rc = spm_sp_synchronous_entry(ctx); assert(rc == 0); ctx->state = SP_STATE_IDLE; INFO("Secure Partition initialized.\n"); return !rc; } /******************************************************************************* * Initialize contexts of all Secure Partitions. ******************************************************************************/ int32_t spm_setup(void) { sp_context_t *ctx; /* Disable MMU at EL1 (initialized by BL2) */ disable_mmu_icache_el1(); /* Initialize context of the SP */ INFO("Secure Partition context setup start...\n"); ctx = &sp_ctx; /* Assign translation tables context. */ ctx->xlat_ctx_handle = spm_get_sp_xlat_context(); spm_sp_setup(ctx); /* Register init function for deferred init. */ bl31_register_bl32_init(&spm_init); INFO("Secure Partition setup done.\n"); return 0; } /******************************************************************************* * Function to perform a call to a Secure Partition. ******************************************************************************/ uint64_t spm_sp_call(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3) { uint64_t rc; sp_context_t *sp_ptr = &sp_ctx; /* Wait until the Secure Partition is idle and set it to busy. */ sp_state_wait_switch(sp_ptr, SP_STATE_IDLE, SP_STATE_BUSY); /* Set values for registers on SP entry */ cpu_context_t *cpu_ctx = &(sp_ptr->cpu_ctx); write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X0, smc_fid); write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X1, x1); write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X2, x2); write_ctx_reg(get_gpregs_ctx(cpu_ctx), CTX_GPREG_X3, x3); /* Jump to the Secure Partition. */ rc = spm_sp_synchronous_entry(sp_ptr); /* Flag Secure Partition as idle. */ assert(sp_ptr->state == SP_STATE_BUSY); sp_state_set(sp_ptr, SP_STATE_IDLE); return rc; } /******************************************************************************* * MM_COMMUNICATE handler ******************************************************************************/ static uint64_t mm_communicate(uint32_t smc_fid, uint64_t mm_cookie, uint64_t comm_buffer_address, uint64_t comm_size_address, void *handle) { uint64_t rc; /* Cookie. Reserved for future use. It must be zero. */ if (mm_cookie != 0U) { ERROR("MM_COMMUNICATE: cookie is not zero\n"); SMC_RET1(handle, SPM_INVALID_PARAMETER); } if (comm_buffer_address == 0U) { ERROR("MM_COMMUNICATE: comm_buffer_address is zero\n"); SMC_RET1(handle, SPM_INVALID_PARAMETER); } if (comm_size_address != 0U) { VERBOSE("MM_COMMUNICATE: comm_size_address is not 0 as recommended.\n"); } /* * The current secure partition design mandates * - at any point, only a single core can be * executing in the secure partiton. * - a core cannot be preempted by an interrupt * while executing in secure partition. * Raise the running priority of the core to the * interrupt level configured for secure partition * so as to block any interrupt from preempting this * core. */ ehf_activate_priority(PLAT_SP_PRI); /* Save the Normal world context */ cm_el1_sysregs_context_save(NON_SECURE); rc = spm_sp_call(smc_fid, comm_buffer_address, comm_size_address, plat_my_core_pos()); /* Restore non-secure state */ cm_el1_sysregs_context_restore(NON_SECURE); cm_set_next_eret_context(NON_SECURE); /* * Exited from secure partition. This core can take * interrupts now. */ ehf_deactivate_priority(PLAT_SP_PRI); SMC_RET1(handle, rc); } /******************************************************************************* * Secure Partition Manager SMC handler. ******************************************************************************/ uint64_t spm_smc_handler(uint32_t smc_fid, uint64_t x1, uint64_t x2, uint64_t x3, uint64_t x4, void *cookie, void *handle, uint64_t flags) { unsigned int ns; /* Determine which security state this SMC originated from */ ns = is_caller_non_secure(flags); if (ns == SMC_FROM_SECURE) { /* Handle SMCs from Secure world. */ assert(handle == cm_get_context(SECURE)); /* Make next ERET jump to S-EL0 instead of S-EL1. */ cm_set_elr_spsr_el3(SECURE, read_elr_el1(), read_spsr_el1()); switch (smc_fid) { case SPM_VERSION_AARCH32: SMC_RET1(handle, SPM_VERSION_COMPILED); case SP_EVENT_COMPLETE_AARCH64: spm_sp_synchronous_exit(x1); case SP_MEMORY_ATTRIBUTES_GET_AARCH64: INFO("Received SP_MEMORY_ATTRIBUTES_GET_AARCH64 SMC\n"); if (sp_ctx.state != SP_STATE_RESET) { WARN("SP_MEMORY_ATTRIBUTES_GET_AARCH64 is available at boot time only\n"); SMC_RET1(handle, SPM_NOT_SUPPORTED); } SMC_RET1(handle, spm_memory_attributes_get_smc_handler( &sp_ctx, x1)); case SP_MEMORY_ATTRIBUTES_SET_AARCH64: INFO("Received SP_MEMORY_ATTRIBUTES_SET_AARCH64 SMC\n"); if (sp_ctx.state != SP_STATE_RESET) { WARN("SP_MEMORY_ATTRIBUTES_SET_AARCH64 is available at boot time only\n"); SMC_RET1(handle, SPM_NOT_SUPPORTED); } SMC_RET1(handle, spm_memory_attributes_set_smc_handler( &sp_ctx, x1, x2, x3)); default: break; } } else { /* Handle SMCs from Non-secure world. */ assert(handle == cm_get_context(NON_SECURE)); switch (smc_fid) { case MM_VERSION_AARCH32: SMC_RET1(handle, MM_VERSION_COMPILED); case MM_COMMUNICATE_AARCH32: case MM_COMMUNICATE_AARCH64: return mm_communicate(smc_fid, x1, x2, x3, handle); case SP_MEMORY_ATTRIBUTES_GET_AARCH64: case SP_MEMORY_ATTRIBUTES_SET_AARCH64: /* SMC interfaces reserved for secure callers. */ SMC_RET1(handle, SPM_NOT_SUPPORTED); default: break; } } SMC_RET1(handle, SMC_UNK); } trusted-firmware-a-2.2/services/std_svc/spm_mm/spm_private.h000066400000000000000000000035401355360272700243750ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPM_PRIVATE_H #define SPM_PRIVATE_H #include /******************************************************************************* * Constants that allow assembler code to preserve callee-saved registers of the * C runtime context while performing a security state switch. ******************************************************************************/ #define SP_C_RT_CTX_X19 0x0 #define SP_C_RT_CTX_X20 0x8 #define SP_C_RT_CTX_X21 0x10 #define SP_C_RT_CTX_X22 0x18 #define SP_C_RT_CTX_X23 0x20 #define SP_C_RT_CTX_X24 0x28 #define SP_C_RT_CTX_X25 0x30 #define SP_C_RT_CTX_X26 0x38 #define SP_C_RT_CTX_X27 0x40 #define SP_C_RT_CTX_X28 0x48 #define SP_C_RT_CTX_X29 0x50 #define SP_C_RT_CTX_X30 0x58 #define SP_C_RT_CTX_SIZE 0x60 #define SP_C_RT_CTX_ENTRIES (SP_C_RT_CTX_SIZE >> DWORD_SHIFT) #ifndef __ASSEMBLER__ #include #include #include typedef enum sp_state { SP_STATE_RESET = 0, SP_STATE_IDLE, SP_STATE_BUSY } sp_state_t; typedef struct sp_context { uint64_t c_rt_ctx; cpu_context_t cpu_ctx; xlat_ctx_t *xlat_ctx_handle; sp_state_t state; spinlock_t state_lock; } sp_context_t; /* Assembly helpers */ uint64_t spm_secure_partition_enter(uint64_t *c_rt_ctx); void __dead2 spm_secure_partition_exit(uint64_t c_rt_ctx, uint64_t ret); void spm_sp_setup(sp_context_t *sp_ctx); xlat_ctx_t *spm_get_sp_xlat_context(void); int32_t spm_memory_attributes_get_smc_handler(sp_context_t *sp_ctx, uintptr_t base_va); int spm_memory_attributes_set_smc_handler(sp_context_t *sp_ctx, u_register_t page_address, u_register_t pages_count, u_register_t smc_attributes); #endif /* __ASSEMBLER__ */ #endif /* SPM_PRIVATE_H */ trusted-firmware-a-2.2/services/std_svc/spm_mm/spm_setup.c000066400000000000000000000170541355360272700240630ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include "spm_private.h" #include "spm_shim_private.h" /* Setup context of the Secure Partition */ void spm_sp_setup(sp_context_t *sp_ctx) { cpu_context_t *ctx = &(sp_ctx->cpu_ctx); /* * Initialize CPU context * ---------------------- */ entry_point_info_t ep_info = {0}; SET_PARAM_HEAD(&ep_info, PARAM_EP, VERSION_1, SECURE | EP_ST_ENABLE); /* Setup entrypoint and SPSR */ ep_info.pc = BL32_BASE; ep_info.spsr = SPSR_64(MODE_EL0, MODE_SP_EL0, DISABLE_ALL_EXCEPTIONS); /* * X0: Virtual address of a buffer shared between EL3 and Secure EL0. * The buffer will be mapped in the Secure EL1 translation regime * with Normal IS WBWA attributes and RO data and Execute Never * instruction access permissions. * * X1: Size of the buffer in bytes * * X2: cookie value (Implementation Defined) * * X3: cookie value (Implementation Defined) * * X4 to X7 = 0 */ ep_info.args.arg0 = PLAT_SPM_BUF_BASE; ep_info.args.arg1 = PLAT_SPM_BUF_SIZE; ep_info.args.arg2 = PLAT_SPM_COOKIE_0; ep_info.args.arg3 = PLAT_SPM_COOKIE_1; cm_setup_context(ctx, &ep_info); /* * SP_EL0: A non-zero value will indicate to the SP that the SPM has * initialized the stack pointer for the current CPU through * implementation defined means. The value will be 0 otherwise. */ write_ctx_reg(get_gpregs_ctx(ctx), CTX_GPREG_SP_EL0, PLAT_SP_IMAGE_STACK_BASE + PLAT_SP_IMAGE_STACK_PCPU_SIZE); /* * Setup translation tables * ------------------------ */ #if ENABLE_ASSERTIONS /* Get max granularity supported by the platform. */ unsigned int max_granule = xlat_arch_get_max_supported_granule_size(); VERBOSE("Max translation granule size supported: %u KiB\n", max_granule / 1024U); unsigned int max_granule_mask = max_granule - 1U; /* Base must be aligned to the max granularity */ assert((PLAT_SP_IMAGE_NS_BUF_BASE & max_granule_mask) == 0); /* Size must be a multiple of the max granularity */ assert((PLAT_SP_IMAGE_NS_BUF_SIZE & max_granule_mask) == 0); #endif /* ENABLE_ASSERTIONS */ /* This region contains the exception vectors used at S-EL1. */ const mmap_region_t sel1_exception_vectors = MAP_REGION_FLAT(SPM_SHIM_EXCEPTIONS_START, SPM_SHIM_EXCEPTIONS_SIZE, MT_CODE | MT_SECURE | MT_PRIVILEGED); mmap_add_region_ctx(sp_ctx->xlat_ctx_handle, &sel1_exception_vectors); mmap_add_ctx(sp_ctx->xlat_ctx_handle, plat_get_secure_partition_mmap(NULL)); init_xlat_tables_ctx(sp_ctx->xlat_ctx_handle); /* * MMU-related registers * --------------------- */ xlat_ctx_t *xlat_ctx = sp_ctx->xlat_ctx_handle; uint64_t mmu_cfg_params[MMU_CFG_PARAM_MAX]; setup_mmu_cfg((uint64_t *)&mmu_cfg_params, 0, xlat_ctx->base_table, xlat_ctx->pa_max_address, xlat_ctx->va_max_address, EL1_EL0_REGIME); write_ctx_reg(get_sysregs_ctx(ctx), CTX_MAIR_EL1, mmu_cfg_params[MMU_CFG_MAIR]); write_ctx_reg(get_sysregs_ctx(ctx), CTX_TCR_EL1, mmu_cfg_params[MMU_CFG_TCR]); write_ctx_reg(get_sysregs_ctx(ctx), CTX_TTBR0_EL1, mmu_cfg_params[MMU_CFG_TTBR0]); /* Setup SCTLR_EL1 */ u_register_t sctlr_el1 = read_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1); sctlr_el1 |= /*SCTLR_EL1_RES1 |*/ /* Don't trap DC CVAU, DC CIVAC, DC CVAC, DC CVAP, or IC IVAU */ SCTLR_UCI_BIT | /* RW regions at xlat regime EL1&0 are forced to be XN. */ SCTLR_WXN_BIT | /* Don't trap to EL1 execution of WFI or WFE at EL0. */ SCTLR_NTWI_BIT | SCTLR_NTWE_BIT | /* Don't trap to EL1 accesses to CTR_EL0 from EL0. */ SCTLR_UCT_BIT | /* Don't trap to EL1 execution of DZ ZVA at EL0. */ SCTLR_DZE_BIT | /* Enable SP Alignment check for EL0 */ SCTLR_SA0_BIT | /* Allow cacheable data and instr. accesses to normal memory. */ SCTLR_C_BIT | SCTLR_I_BIT | /* Enable MMU. */ SCTLR_M_BIT ; sctlr_el1 &= ~( /* Explicit data accesses at EL0 are little-endian. */ SCTLR_E0E_BIT | /* * Alignment fault checking disabled when at EL1 and EL0 as * the UEFI spec permits unaligned accesses. */ SCTLR_A_BIT | /* Accesses to DAIF from EL0 are trapped to EL1. */ SCTLR_UMA_BIT ); write_ctx_reg(get_sysregs_ctx(ctx), CTX_SCTLR_EL1, sctlr_el1); /* * Setup other system registers * ---------------------------- */ /* Shim Exception Vector Base Address */ write_ctx_reg(get_sysregs_ctx(ctx), CTX_VBAR_EL1, SPM_SHIM_EXCEPTIONS_PTR); write_ctx_reg(get_sysregs_ctx(ctx), CTX_CNTKCTL_EL1, EL0PTEN_BIT | EL0VTEN_BIT | EL0PCTEN_BIT | EL0VCTEN_BIT); /* * FPEN: Allow the Secure Partition to access FP/SIMD registers. * Note that SPM will not do any saving/restoring of these registers on * behalf of the SP. This falls under the SP's responsibility. * TTA: Enable access to trace registers. * ZEN (v8.2): Trap SVE instructions and access to SVE registers. */ write_ctx_reg(get_sysregs_ctx(ctx), CTX_CPACR_EL1, CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE)); /* * Prepare information in buffer shared between EL3 and S-EL0 * ---------------------------------------------------------- */ void *shared_buf_ptr = (void *) PLAT_SPM_BUF_BASE; /* Copy the boot information into the shared buffer with the SP. */ assert((uintptr_t)shared_buf_ptr + sizeof(secure_partition_boot_info_t) <= (PLAT_SPM_BUF_BASE + PLAT_SPM_BUF_SIZE)); assert(PLAT_SPM_BUF_BASE <= (UINTPTR_MAX - PLAT_SPM_BUF_SIZE + 1)); const secure_partition_boot_info_t *sp_boot_info = plat_get_secure_partition_boot_info(NULL); assert(sp_boot_info != NULL); memcpy((void *) shared_buf_ptr, (const void *) sp_boot_info, sizeof(secure_partition_boot_info_t)); /* Pointer to the MP information from the platform port. */ secure_partition_mp_info_t *sp_mp_info = ((secure_partition_boot_info_t *) shared_buf_ptr)->mp_info; assert(sp_mp_info != NULL); /* * Point the shared buffer MP information pointer to where the info will * be populated, just after the boot info. */ ((secure_partition_boot_info_t *) shared_buf_ptr)->mp_info = (secure_partition_mp_info_t *) ((uintptr_t)shared_buf_ptr + sizeof(secure_partition_boot_info_t)); /* * Update the shared buffer pointer to where the MP information for the * payload will be populated */ shared_buf_ptr = ((secure_partition_boot_info_t *) shared_buf_ptr)->mp_info; /* * Copy the cpu information into the shared buffer area after the boot * information. */ assert(sp_boot_info->num_cpus <= PLATFORM_CORE_COUNT); assert((uintptr_t)shared_buf_ptr <= (PLAT_SPM_BUF_BASE + PLAT_SPM_BUF_SIZE - (sp_boot_info->num_cpus * sizeof(*sp_mp_info)))); memcpy(shared_buf_ptr, (const void *) sp_mp_info, sp_boot_info->num_cpus * sizeof(*sp_mp_info)); /* * Calculate the linear indices of cores in boot information for the * secure partition and flag the primary CPU */ sp_mp_info = (secure_partition_mp_info_t *) shared_buf_ptr; for (unsigned int index = 0; index < sp_boot_info->num_cpus; index++) { u_register_t mpidr = sp_mp_info[index].mpidr; sp_mp_info[index].linear_id = plat_core_pos_by_mpidr(mpidr); if (plat_my_core_pos() == sp_mp_info[index].linear_id) sp_mp_info[index].flags |= MP_INFO_FLAG_PRIMARY_CPU; } } trusted-firmware-a-2.2/services/std_svc/spm_mm/spm_shim_private.h000066400000000000000000000012161355360272700254130ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SPM_SHIM_PRIVATE_H #define SPM_SHIM_PRIVATE_H #include #include /* Assembly source */ IMPORT_SYM(uintptr_t, spm_shim_exceptions_ptr, SPM_SHIM_EXCEPTIONS_PTR); /* Linker symbols */ IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_START__, SPM_SHIM_EXCEPTIONS_START); IMPORT_SYM(uintptr_t, __SPM_SHIM_EXCEPTIONS_END__, SPM_SHIM_EXCEPTIONS_END); /* Definitions */ #define SPM_SHIM_EXCEPTIONS_SIZE \ (SPM_SHIM_EXCEPTIONS_END - SPM_SHIM_EXCEPTIONS_START) #endif /* SPM_SHIM_PRIVATE_H */ trusted-firmware-a-2.2/services/std_svc/spm_mm/spm_xlat.c000066400000000000000000000105611355360272700236670ustar00rootroot00000000000000/* * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include "spm_private.h" #include "spm_shim_private.h" /* Place translation tables by default along with the ones used by BL31. */ #ifndef PLAT_SP_IMAGE_XLAT_SECTION_NAME #define PLAT_SP_IMAGE_XLAT_SECTION_NAME "xlat_table" #endif /* Allocate and initialise the translation context for the secure partitions. */ REGISTER_XLAT_CONTEXT2(sp, PLAT_SP_IMAGE_MMAP_REGIONS, PLAT_SP_IMAGE_MAX_XLAT_TABLES, PLAT_VIRT_ADDR_SPACE_SIZE, PLAT_PHY_ADDR_SPACE_SIZE, EL1_EL0_REGIME, PLAT_SP_IMAGE_XLAT_SECTION_NAME); /* Lock used for SP_MEMORY_ATTRIBUTES_GET and SP_MEMORY_ATTRIBUTES_SET */ static spinlock_t mem_attr_smc_lock; /* Get handle of Secure Partition translation context */ xlat_ctx_t *spm_get_sp_xlat_context(void) { return &sp_xlat_ctx; }; /* * Attributes are encoded using a different format in the SMC interface than in * the Trusted Firmware, where the mmap_attr_t enum type is used. This function * converts an attributes value from the SMC format to the mmap_attr_t format by * setting MT_RW/MT_RO, MT_USER/MT_PRIVILEGED and MT_EXECUTE/MT_EXECUTE_NEVER. * The other fields are left as 0 because they are ignored by the function * xlat_change_mem_attributes_ctx(). */ static unsigned int smc_attr_to_mmap_attr(unsigned int attributes) { unsigned int tf_attr = 0U; unsigned int access = (attributes & SP_MEMORY_ATTRIBUTES_ACCESS_MASK) >> SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT; if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RW) { tf_attr |= MT_RW | MT_USER; } else if (access == SP_MEMORY_ATTRIBUTES_ACCESS_RO) { tf_attr |= MT_RO | MT_USER; } else { /* Other values are reserved. */ assert(access == SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS); /* The only requirement is that there's no access from EL0 */ tf_attr |= MT_RO | MT_PRIVILEGED; } if ((attributes & SP_MEMORY_ATTRIBUTES_NON_EXEC) == 0) { tf_attr |= MT_EXECUTE; } else { tf_attr |= MT_EXECUTE_NEVER; } return tf_attr; } /* * This function converts attributes from the Trusted Firmware format into the * SMC interface format. */ static unsigned int smc_mmap_to_smc_attr(unsigned int attr) { unsigned int smc_attr = 0U; unsigned int data_access; if ((attr & MT_USER) == 0) { /* No access from EL0. */ data_access = SP_MEMORY_ATTRIBUTES_ACCESS_NOACCESS; } else { if ((attr & MT_RW) != 0) { assert(MT_TYPE(attr) != MT_DEVICE); data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RW; } else { data_access = SP_MEMORY_ATTRIBUTES_ACCESS_RO; } } smc_attr |= (data_access & SP_MEMORY_ATTRIBUTES_ACCESS_MASK) << SP_MEMORY_ATTRIBUTES_ACCESS_SHIFT; if ((attr & MT_EXECUTE_NEVER) != 0U) { smc_attr |= SP_MEMORY_ATTRIBUTES_NON_EXEC; } return smc_attr; } int32_t spm_memory_attributes_get_smc_handler(sp_context_t *sp_ctx, uintptr_t base_va) { uint32_t attributes; spin_lock(&mem_attr_smc_lock); int rc = xlat_get_mem_attributes_ctx(sp_ctx->xlat_ctx_handle, base_va, &attributes); spin_unlock(&mem_attr_smc_lock); /* Convert error codes of xlat_get_mem_attributes_ctx() into SPM. */ assert((rc == 0) || (rc == -EINVAL)); if (rc == 0) { return (int32_t) smc_mmap_to_smc_attr(attributes); } else { return SPM_INVALID_PARAMETER; } } int spm_memory_attributes_set_smc_handler(sp_context_t *sp_ctx, u_register_t page_address, u_register_t pages_count, u_register_t smc_attributes) { uintptr_t base_va = (uintptr_t) page_address; size_t size = (size_t) (pages_count * PAGE_SIZE); uint32_t attributes = (uint32_t) smc_attributes; INFO(" Start address : 0x%lx\n", base_va); INFO(" Number of pages: %i (%zi bytes)\n", (int) pages_count, size); INFO(" Attributes : 0x%x\n", attributes); spin_lock(&mem_attr_smc_lock); int ret = xlat_change_mem_attributes_ctx(sp_ctx->xlat_ctx_handle, base_va, size, smc_attr_to_mmap_attr(attributes)); spin_unlock(&mem_attr_smc_lock); /* Convert error codes of xlat_change_mem_attributes_ctx() into SPM. */ assert((ret == 0) || (ret == -EINVAL)); return (ret == 0) ? SPM_SUCCESS : SPM_INVALID_PARAMETER; } trusted-firmware-a-2.2/services/std_svc/std_svc_setup.c000066400000000000000000000064411355360272700234370ustar00rootroot00000000000000/* * Copyright (c) 2014-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* Standard Service UUID */ static uuid_t arm_svc_uid = { {0x5b, 0x90, 0x8d, 0x10}, {0x63, 0xf8}, {0xe8, 0x47}, 0xae, 0x2d, {0xc0, 0xfb, 0x56, 0x41, 0xf6, 0xe2} }; /* Setup Standard Services */ static int32_t std_svc_setup(void) { uintptr_t svc_arg; int ret = 0; svc_arg = get_arm_std_svc_args(PSCI_FID_MASK); assert(svc_arg); /* * PSCI is one of the specifications implemented as a Standard Service. * The `psci_setup()` also does EL3 architectural setup. */ if (psci_setup((const psci_lib_args_t *)svc_arg) != PSCI_E_SUCCESS) { ret = 1; } #if ENABLE_SPM if (spm_setup() != 0) { ret = 1; } #endif #if SDEI_SUPPORT /* SDEI initialisation */ sdei_init(); #endif return ret; } /* * Top-level Standard Service SMC handler. This handler will in turn dispatch * calls to PSCI SMC handler */ static uintptr_t std_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) { /* * Dispatch PSCI calls to PSCI SMC handler and return its return * value */ if (is_psci_fid(smc_fid)) { uint64_t ret; #if ENABLE_RUNTIME_INSTRUMENTATION /* * Flush cache line so that even if CPU power down happens * the timestamp update is reflected in memory. */ PMF_WRITE_TIMESTAMP(rt_instr_svc, RT_INSTR_ENTER_PSCI, PMF_CACHE_MAINT, get_cpu_data(cpu_data_pmf_ts[CPU_DATA_PMF_TS0_IDX])); #endif ret = psci_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); #if ENABLE_RUNTIME_INSTRUMENTATION PMF_CAPTURE_TIMESTAMP(rt_instr_svc, RT_INSTR_EXIT_PSCI, PMF_NO_CACHE_MAINT); #endif SMC_RET1(handle, ret); } #if ENABLE_SPM && SPM_MM /* * Dispatch SPM calls to SPM SMC handler and return its return * value */ if (is_spm_fid(smc_fid)) { return spm_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); } #endif #if SDEI_SUPPORT if (is_sdei_fid(smc_fid)) { return sdei_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); } #endif switch (smc_fid) { case ARM_STD_SVC_CALL_COUNT: /* * Return the number of Standard Service Calls. PSCI is the only * standard service implemented; so return number of PSCI calls */ SMC_RET1(handle, PSCI_NUM_CALLS); case ARM_STD_SVC_UID: /* Return UID to the caller */ SMC_UUID_RET(handle, arm_svc_uid); case ARM_STD_SVC_VERSION: /* Return the version of current implementation */ SMC_RET2(handle, STD_SVC_VERSION_MAJOR, STD_SVC_VERSION_MINOR); default: WARN("Unimplemented Standard Service Call: 0x%x \n", smc_fid); SMC_RET1(handle, SMC_UNK); } } /* Register Standard Service Calls as runtime service */ DECLARE_RT_SVC( std_svc, OEN_STD_START, OEN_STD_END, SMC_TYPE_FAST, std_svc_setup, std_svc_smc_handler ); trusted-firmware-a-2.2/tools/000077500000000000000000000000001355360272700162515ustar00rootroot00000000000000trusted-firmware-a-2.2/tools/amlogic/000077500000000000000000000000001355360272700176645ustar00rootroot00000000000000trusted-firmware-a-2.2/tools/amlogic/Makefile000066400000000000000000000016031355360272700213240ustar00rootroot00000000000000# # Copyright (C) 2019 Remi Pommarel # # SPDX-License-Identifier: BSD-3-Clause # https://spdx.org/licenses # MAKE_HELPERS_DIRECTORY := ../../make_helpers/ include ${MAKE_HELPERS_DIRECTORY}build_macros.mk include ${MAKE_HELPERS_DIRECTORY}build_env.mk PROJECT := doimage${BIN_EXT} OBJECTS := doimage.o V := 0 HOSTCCFLAGS := -Wall -Werror -pedantic -std=c99 -D_GNU_SOURCE ifeq (${DEBUG},1) HOSTCCFLAGS += -g -O0 -DDEBUG else HOSTCCFLAGS += -O2 endif ifeq (${V},0) Q := @ else Q := endif HOSTCC := gcc .PHONY: all clean distclean all: ${PROJECT} ${PROJECT}: ${OBJECTS} Makefile @echo " HOSTLD $@" ${Q}${HOSTCC} ${OBJECTS} -o $@ @${ECHO_BLANK_LINE} @echo "Built $@ successfully" @${ECHO_BLANK_LINE} %.o: %.c Makefile @echo " HOSTCC $<" ${Q}${HOSTCC} -c ${HOSTCCFLAGS} $< -o $@ clean: $(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS}) distclean: clean trusted-firmware-a-2.2/tools/amlogic/doimage.c000066400000000000000000000033051355360272700214360ustar00rootroot00000000000000/* * Copyright (c) 2019, Remi Pommarel * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #define DEFAULT_PROGNAME "doimage" #define PROGNAME(argc, argv) (((argc) >= 1) ? ((argv)[0]) : DEFAULT_PROGNAME) #define BL31_MAGIC 0x12348765 #define BL31_LOADADDR 0x05100000 #define BUFLEN 512 static inline void usage(char const *prog) { fprintf(stderr, "Usage: %s \n", prog); } static inline int fdwrite(int fd, uint8_t *data, size_t len) { ssize_t nr; size_t l; int ret = -1; for (l = 0; l < len; l += nr) { nr = write(fd, data + l, len - l); if (nr < 0) { perror("Cannot write to bl31.img"); goto out; } } ret = 0; out: return ret; } int main(int argc, char **argv) { int fin, fout, ret = -1; ssize_t len; uint32_t data; uint8_t buf[BUFLEN]; if (argc != 3) { usage(PROGNAME(argc, argv)); goto out; } fin = open(argv[1], O_RDONLY); if (fin < 0) { perror("Cannot open bl31.bin"); goto out; } fout = open(argv[2], O_WRONLY | O_CREAT, 0660); if (fout < 0) { perror("Cannot open bl31.img"); goto closefin; } data = htole32(BL31_MAGIC); if (fdwrite(fout, (uint8_t *)&data, sizeof(data)) < 0) goto closefout; lseek(fout, 8, SEEK_SET); data = htole32(BL31_LOADADDR); if (fdwrite(fout, (uint8_t *)&data, sizeof(data)) < 0) goto closefout; lseek(fout, 0x200, SEEK_SET); while ((len = read(fin, buf, sizeof(buf))) > 0) if (fdwrite(fout, buf, len) < 0) goto closefout; if (len < 0) { perror("Cannot read bl31.bin"); goto closefout; } ret = 0; closefout: close(fout); closefin: close(fin); out: return ret; } trusted-firmware-a-2.2/tools/cert_create/000077500000000000000000000000001355360272700205315ustar00rootroot00000000000000trusted-firmware-a-2.2/tools/cert_create/Makefile000066400000000000000000000041231355360272700221710ustar00rootroot00000000000000# # Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # PROJECT := cert_create PLAT := none V ?= 0 DEBUG := 0 BINARY := ${PROJECT}${BIN_EXT} OPENSSL_DIR := /usr USE_TBBR_DEFS := 1 OBJECTS := src/cert.o \ src/cmd_opt.o \ src/ext.o \ src/key.o \ src/main.o \ src/sha.o \ src/tbbr/tbb_cert.o \ src/tbbr/tbb_ext.o \ src/tbbr/tbb_key.o HOSTCCFLAGS := -Wall -std=c99 MAKE_HELPERS_DIRECTORY := ../../make_helpers/ include ${MAKE_HELPERS_DIRECTORY}build_macros.mk include ${MAKE_HELPERS_DIRECTORY}build_env.mk ifeq (${USE_TBBR_DEFS},1) # In this case, cert_tool is platform-independent PLAT_MSG := TBBR Generic PLAT_INCLUDE := ../../include/tools_share else PLAT_MSG := ${PLAT} TF_PLATFORM_ROOT := ../../plat/ include ${MAKE_HELPERS_DIRECTORY}plat_helpers.mk PLAT_INCLUDE := $(wildcard ${PLAT_DIR}include) ifeq ($(PLAT_INCLUDE),) $(error "Error: Invalid platform '${PLAT}' has no include directory.") endif endif ifeq (${DEBUG},1) HOSTCCFLAGS += -g -O0 -DDEBUG -DLOG_LEVEL=40 else HOSTCCFLAGS += -O2 -DLOG_LEVEL=20 endif ifeq (${V},0) Q := @ else Q := endif $(eval $(call add_define,USE_TBBR_DEFS)) HOSTCCFLAGS += ${DEFINES} # Make soft links and include from local directory otherwise wrong headers # could get pulled in from firmware tree. INC_DIR := -I ./include -I ${PLAT_INCLUDE} -I ${OPENSSL_DIR}/include LIB_DIR := -L ${OPENSSL_DIR}/lib LIB := -lssl -lcrypto HOSTCC ?= gcc .PHONY: all clean realclean all: clean ${BINARY} ${BINARY}: ${OBJECTS} Makefile @echo " HOSTLD $@" @echo 'const char build_msg[] = "Built : "__TIME__", "__DATE__; \ const char platform_msg[] = "${PLAT_MSG}";' | \ ${HOSTCC} -c ${HOSTCCFLAGS} -xc - -o src/build_msg.o ${Q}${HOSTCC} src/build_msg.o ${OBJECTS} ${LIB_DIR} ${LIB} -o $@ %.o: %.c @echo " HOSTCC $<" ${Q}${HOSTCC} -c ${HOSTCCFLAGS} ${INC_DIR} $< -o $@ clean: $(call SHELL_DELETE_ALL, src/build_msg.o ${OBJECTS}) realclean: clean $(call SHELL_DELETE,${BINARY}) trusted-firmware-a-2.2/tools/cert_create/include/000077500000000000000000000000001355360272700221545ustar00rootroot00000000000000trusted-firmware-a-2.2/tools/cert_create/include/cert.h000066400000000000000000000034711355360272700232670ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CERT_H #define CERT_H #include #include #include "ext.h" #include "key.h" #define CERT_MAX_EXT 5 /* * This structure contains information related to the generation of the * certificates. All these fields must be known and specified at build time * except for the file name, which is picked up from the command line at * run time. * * One instance of this structure must be created for each of the certificates * present in the chain of trust. * * If the issuer points to this same instance, the generated certificate will * be self-signed. */ typedef struct cert_s cert_t; struct cert_s { int id; /* Unique identifier */ const char *opt; /* Command line option to pass filename */ const char *fn; /* Filename to save the certificate */ const char *cn; /* Subject CN (Company Name) */ const char *help_msg; /* Help message */ /* These fields must be defined statically */ int key; /* Key to be signed */ int issuer; /* Issuer certificate */ int ext[CERT_MAX_EXT]; /* Certificate extensions */ int num_ext; /* Number of extensions in the certificate */ X509 *x; /* X509 certificate container */ }; /* Exported API */ int cert_init(void); cert_t *cert_get_by_opt(const char *opt); int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value); int cert_new( int md_alg, cert_t *cert, int days, int ca, STACK_OF(X509_EXTENSION) * sk); /* Macro to register the certificates used in the CoT */ #define REGISTER_COT(_certs) \ cert_t *certs = &_certs[0]; \ const unsigned int num_certs = sizeof(_certs)/sizeof(_certs[0]) /* Exported variables */ extern cert_t *certs; extern const unsigned int num_certs; #endif /* CERT_H */ trusted-firmware-a-2.2/tools/cert_create/include/cmd_opt.h000066400000000000000000000012311355360272700237470ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef CMD_OPT_H #define CMD_OPT_H #include #define CMD_OPT_MAX_NUM 64 /* Supported long command line option types */ enum { CMD_OPT_CERT, CMD_OPT_KEY, CMD_OPT_EXT }; /* Structure to define a command line option */ typedef struct cmd_opt_s { struct option long_opt; const char *help_msg; } cmd_opt_t; /* Exported API*/ void cmd_opt_add(const cmd_opt_t *cmd_opt); const struct option *cmd_opt_get_array(void); const char *cmd_opt_get_name(int idx); const char *cmd_opt_get_help_msg(int idx); #endif /* CMD_OPT_H */ trusted-firmware-a-2.2/tools/cert_create/include/debug.h000066400000000000000000000026171355360272700234210ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef DEBUG_H #define DEBUG_H #include /* The log output macros print output to the console. These macros produce * compiled log output only if the LOG_LEVEL defined in the makefile (or the * make command line) is greater or equal than the level required for that * type of log output. * The format expected is the same as for printf(). For example: * INFO("Info %s.\n", "message") -> INFO: Info message. * WARN("Warning %s.\n", "message") -> WARNING: Warning message. */ #define LOG_LEVEL_NONE 0 #define LOG_LEVEL_ERROR 10 #define LOG_LEVEL_NOTICE 20 #define LOG_LEVEL_WARNING 30 #define LOG_LEVEL_INFO 40 #define LOG_LEVEL_VERBOSE 50 #if LOG_LEVEL >= LOG_LEVEL_NOTICE # define NOTICE(...) printf("NOTICE: " __VA_ARGS__) #else # define NOTICE(...) #endif #if LOG_LEVEL >= LOG_LEVEL_ERROR # define ERROR(...) printf("ERROR: " __VA_ARGS__) #else # define ERROR(...) #endif #if LOG_LEVEL >= LOG_LEVEL_WARNING # define WARN(...) printf("WARNING: " __VA_ARGS__) #else # define WARN(...) #endif #if LOG_LEVEL >= LOG_LEVEL_INFO # define INFO(...) printf("INFO: " __VA_ARGS__) #else # define INFO(...) #endif #if LOG_LEVEL >= LOG_LEVEL_VERBOSE # define VERBOSE(...) printf("VERBOSE: " __VA_ARGS__) #else # define VERBOSE(...) #endif #endif /* DEBUG_H */ trusted-firmware-a-2.2/tools/cert_create/include/ext.h000066400000000000000000000043611355360272700231310ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef EXT_H #define EXT_H #include #include "key.h" /* Extension types supported */ enum ext_type_e { EXT_TYPE_NVCOUNTER, EXT_TYPE_PKEY, EXT_TYPE_HASH }; /* NV-Counter types */ enum nvctr_type_e { NVCTR_TYPE_TFW, NVCTR_TYPE_NTFW }; /* * This structure contains the relevant information to create the extensions * to be included in the certificates. This extensions will be used to * establish the chain of trust. */ typedef struct ext_s { const char *oid; /* OID of the extension */ const char *sn; /* Short name */ const char *ln; /* Long description */ const char *opt; /* Command line option to specify data */ const char *help_msg; /* Help message */ const char *arg; /* Argument passed from command line */ int asn1_type; /* OpenSSL ASN1 type of the extension data. * Supported types are: * - V_ASN1_INTEGER * - V_ASN1_OCTET_STRING */ int type; /* See ext_type_e */ /* Extension attributes (depends on extension type) */ union { int nvctr_type; /* See nvctr_type_e */ int key; /* Index into array of registered public keys */ } attr; int alias; /* In case OpenSSL provides an standard * extension of the same type, add the new * extension as an alias of this one */ X509V3_EXT_METHOD method; /* This field may be used to define a custom * function to print the contents of the * extension */ int optional; /* This field may be used optionally to exclude an image */ } ext_t; enum { EXT_NON_CRIT = 0, EXT_CRIT = !EXT_NON_CRIT, }; /* Exported API */ int ext_init(void); ext_t *ext_get_by_opt(const char *opt); X509_EXTENSION *ext_new_hash(int nid, int crit, const EVP_MD *md, unsigned char *buf, size_t len); X509_EXTENSION *ext_new_nvcounter(int nid, int crit, int value); X509_EXTENSION *ext_new_key(int nid, int crit, EVP_PKEY *k); /* Macro to register the extensions used in the CoT */ #define REGISTER_EXTENSIONS(_ext) \ ext_t *extensions = &_ext[0]; \ const unsigned int num_extensions = sizeof(_ext)/sizeof(_ext[0]) /* Exported variables */ extern ext_t *extensions; extern const unsigned int num_extensions; #endif /* EXT_H */ trusted-firmware-a-2.2/tools/cert_create/include/key.h000066400000000000000000000040121355360272700231120ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef KEY_H #define KEY_H #include /* Error codes */ enum { KEY_ERR_NONE, KEY_ERR_MALLOC, KEY_ERR_FILENAME, KEY_ERR_OPEN, KEY_ERR_LOAD }; /* Supported key algorithms */ enum { KEY_ALG_RSA, /* RSA PSS as defined by PKCS#1 v2.1 (default) */ #ifndef OPENSSL_NO_EC KEY_ALG_ECDSA, #endif /* OPENSSL_NO_EC */ KEY_ALG_MAX_NUM }; /* Maximum number of valid key sizes per algorithm */ #define KEY_SIZE_MAX_NUM 4 /* Supported hash algorithms */ enum{ HASH_ALG_SHA256, HASH_ALG_SHA384, HASH_ALG_SHA512, }; /* Supported key sizes */ /* NOTE: the first item in each array is the default key size */ static const unsigned int KEY_SIZES[KEY_ALG_MAX_NUM][KEY_SIZE_MAX_NUM] = { { 2048, 1024, 3072, 4096 }, /* KEY_ALG_RSA */ #ifndef OPENSSL_NO_EC {} /* KEY_ALG_ECDSA */ #endif /* OPENSSL_NO_EC */ }; /* * This structure contains the relevant information to create the keys * required to sign the certificates. * * One instance of this structure must be created for each key, usually in an * array fashion. The filename is obtained at run time from the command line * parameters */ typedef struct key_s { int id; /* Key id */ const char *opt; /* Command line option to specify a key */ const char *help_msg; /* Help message */ const char *desc; /* Key description (debug purposes) */ char *fn; /* Filename to load/store the key */ EVP_PKEY *key; /* Key container */ } key_t; /* Exported API */ int key_init(void); key_t *key_get_by_opt(const char *opt); int key_new(key_t *key); int key_create(key_t *key, int type, int key_bits); int key_load(key_t *key, unsigned int *err_code); int key_store(key_t *key); /* Macro to register the keys used in the CoT */ #define REGISTER_KEYS(_keys) \ key_t *keys = &_keys[0]; \ const unsigned int num_keys = sizeof(_keys)/sizeof(_keys[0]) /* Exported variables */ extern key_t *keys; extern const unsigned int num_keys; #endif /* KEY_H */ trusted-firmware-a-2.2/tools/cert_create/include/sha.h000066400000000000000000000003671355360272700231060ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef SHA_H #define SHA_H int sha_file(int md_alg, const char *filename, unsigned char *md); #endif /* SHA_H */ trusted-firmware-a-2.2/tools/cert_create/include/tbbr/000077500000000000000000000000001355360272700231055ustar00rootroot00000000000000trusted-firmware-a-2.2/tools/cert_create/include/tbbr/tbb_cert.h000066400000000000000000000010401355360272700250350ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TBB_CERT_H #define TBB_CERT_H #include "cert.h" /* * Enumerate the certificates that are used to establish the chain of trust */ enum { TRUSTED_BOOT_FW_CERT, TRUSTED_KEY_CERT, SCP_FW_KEY_CERT, SCP_FW_CONTENT_CERT, SOC_FW_KEY_CERT, SOC_FW_CONTENT_CERT, TRUSTED_OS_FW_KEY_CERT, TRUSTED_OS_FW_CONTENT_CERT, NON_TRUSTED_FW_KEY_CERT, NON_TRUSTED_FW_CONTENT_CERT, FWU_CERT }; #endif /* TBB_CERT_H */ trusted-firmware-a-2.2/tools/cert_create/include/tbbr/tbb_ext.h000066400000000000000000000015571355360272700247150ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TBB_EXT_H #define TBB_EXT_H #include "ext.h" /* TBBR extensions */ enum { TRUSTED_FW_NVCOUNTER_EXT, NON_TRUSTED_FW_NVCOUNTER_EXT, TRUSTED_BOOT_FW_HASH_EXT, TRUSTED_BOOT_FW_CONFIG_HASH_EXT, HW_CONFIG_HASH_EXT, TRUSTED_WORLD_PK_EXT, NON_TRUSTED_WORLD_PK_EXT, SCP_FW_CONTENT_CERT_PK_EXT, SCP_FW_HASH_EXT, SOC_FW_CONTENT_CERT_PK_EXT, SOC_AP_FW_HASH_EXT, SOC_FW_CONFIG_HASH_EXT, TRUSTED_OS_FW_CONTENT_CERT_PK_EXT, TRUSTED_OS_FW_HASH_EXT, TRUSTED_OS_FW_EXTRA1_HASH_EXT, TRUSTED_OS_FW_EXTRA2_HASH_EXT, TRUSTED_OS_FW_CONFIG_HASH_EXT, NON_TRUSTED_FW_CONTENT_CERT_PK_EXT, NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT, NON_TRUSTED_FW_CONFIG_HASH_EXT, SCP_FWU_CFG_HASH_EXT, AP_FWU_CFG_HASH_EXT, FWU_HASH_EXT }; #endif /* TBB_EXT_H */ trusted-firmware-a-2.2/tools/cert_create/include/tbbr/tbb_key.h000066400000000000000000000007161355360272700247010ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TBB_KEY_H #define TBB_KEY_H #include "key.h" /* * Enumerate the keys that are used to establish the chain of trust */ enum { ROT_KEY, TRUSTED_WORLD_KEY, NON_TRUSTED_WORLD_KEY, SCP_FW_CONTENT_CERT_KEY, SOC_FW_CONTENT_CERT_KEY, TRUSTED_OS_FW_CONTENT_CERT_KEY, NON_TRUSTED_FW_CONTENT_CERT_KEY }; #endif /* TBB_KEY_H */ trusted-firmware-a-2.2/tools/cert_create/src/000077500000000000000000000000001355360272700213205ustar00rootroot00000000000000trusted-firmware-a-2.2/tools/cert_create/src/cert.c000066400000000000000000000121521355360272700224220ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #if USE_TBBR_DEFS #include #else #include #endif #include "cert.h" #include "cmd_opt.h" #include "debug.h" #include "key.h" #include "sha.h" #define SERIAL_RAND_BITS 64 #define RSA_SALT_LEN 32 int rand_serial(BIGNUM *b, ASN1_INTEGER *ai) { BIGNUM *btmp; int ret = 0; if (b) btmp = b; else btmp = BN_new(); if (!btmp) return 0; if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0)) goto error; if (ai && !BN_to_ASN1_INTEGER(btmp, ai)) goto error; ret = 1; error: if (!b) BN_free(btmp); return ret; } const EVP_MD *get_digest(int alg) { switch (alg) { case HASH_ALG_SHA256: return EVP_sha256(); case HASH_ALG_SHA384: return EVP_sha384(); case HASH_ALG_SHA512: return EVP_sha512(); default: return NULL; } } int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value) { X509_EXTENSION *ex; X509V3_CTX ctx; /* No configuration database */ X509V3_set_ctx_nodb(&ctx); /* Set issuer and subject certificates in the context */ X509V3_set_ctx(&ctx, issuer, subject, NULL, NULL, 0); ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value); if (!ex) { ERR_print_errors_fp(stdout); return 0; } X509_add_ext(subject, ex, -1); X509_EXTENSION_free(ex); return 1; } int cert_new( int md_alg, cert_t *cert, int days, int ca, STACK_OF(X509_EXTENSION) * sk) { EVP_PKEY *pkey = keys[cert->key].key; cert_t *issuer_cert = &certs[cert->issuer]; EVP_PKEY *ikey = keys[issuer_cert->key].key; X509 *issuer = issuer_cert->x; X509 *x; X509_EXTENSION *ex; X509_NAME *name; ASN1_INTEGER *sno; int i, num, rc = 0; EVP_MD_CTX *mdCtx; EVP_PKEY_CTX *pKeyCtx = NULL; /* Create the certificate structure */ x = X509_new(); if (!x) { return 0; } /* If we do not have a key, use the issuer key (the certificate will * become self signed). This happens in content certificates. */ if (!pkey) { pkey = ikey; } /* If we do not have an issuer certificate, use our own (the certificate * will become self signed) */ if (!issuer) { issuer = x; } mdCtx = EVP_MD_CTX_create(); if (mdCtx == NULL) { ERR_print_errors_fp(stdout); goto END; } /* Sign the certificate with the issuer key */ if (!EVP_DigestSignInit(mdCtx, &pKeyCtx, get_digest(md_alg), NULL, ikey)) { ERR_print_errors_fp(stdout); goto END; } /* * Set additional parameters if issuing public key algorithm is RSA. * This is not required for ECDSA. */ if (EVP_PKEY_base_id(ikey) == EVP_PKEY_RSA) { if (!EVP_PKEY_CTX_set_rsa_padding(pKeyCtx, RSA_PKCS1_PSS_PADDING)) { ERR_print_errors_fp(stdout); goto END; } if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(pKeyCtx, RSA_SALT_LEN)) { ERR_print_errors_fp(stdout); goto END; } if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pKeyCtx, get_digest(md_alg))) { ERR_print_errors_fp(stdout); goto END; } } /* x509.v3 */ X509_set_version(x, 2); /* Random serial number */ sno = ASN1_INTEGER_new(); rand_serial(NULL, sno); X509_set_serialNumber(x, sno); ASN1_INTEGER_free(sno); X509_gmtime_adj(X509_get_notBefore(x), 0); X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days); X509_set_pubkey(x, pkey); /* Subject name */ name = X509_get_subject_name(x); X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (const unsigned char *)cert->cn, -1, -1, 0); X509_set_subject_name(x, name); /* Issuer name */ name = X509_get_issuer_name(x); X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (const unsigned char *)issuer_cert->cn, -1, -1, 0); X509_set_issuer_name(x, name); /* Add various extensions: standard extensions */ cert_add_ext(issuer, x, NID_subject_key_identifier, "hash"); cert_add_ext(issuer, x, NID_authority_key_identifier, "keyid:always"); if (ca) { cert_add_ext(issuer, x, NID_basic_constraints, "CA:TRUE"); cert_add_ext(issuer, x, NID_key_usage, "keyCertSign"); } else { cert_add_ext(issuer, x, NID_basic_constraints, "CA:FALSE"); } /* Add custom extensions */ if (sk != NULL) { num = sk_X509_EXTENSION_num(sk); for (i = 0; i < num; i++) { ex = sk_X509_EXTENSION_value(sk, i); X509_add_ext(x, ex, -1); } } if (!X509_sign_ctx(x, mdCtx)) { ERR_print_errors_fp(stdout); goto END; } /* X509 certificate signed successfully */ rc = 1; cert->x = x; END: EVP_MD_CTX_destroy(mdCtx); return rc; } int cert_init(void) { cmd_opt_t cmd_opt; cert_t *cert; unsigned int i; for (i = 0; i < num_certs; i++) { cert = &certs[i]; cmd_opt.long_opt.name = cert->opt; cmd_opt.long_opt.has_arg = required_argument; cmd_opt.long_opt.flag = NULL; cmd_opt.long_opt.val = CMD_OPT_CERT; cmd_opt.help_msg = cert->help_msg; cmd_opt_add(&cmd_opt); } return 0; } cert_t *cert_get_by_opt(const char *opt) { cert_t *cert; unsigned int i; for (i = 0; i < num_certs; i++) { cert = &certs[i]; if (0 == strcmp(cert->opt, opt)) { return cert; } } return NULL; } trusted-firmware-a-2.2/tools/cert_create/src/cmd_opt.c000066400000000000000000000021741355360272700231150ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include "debug.h" /* Command line options */ static struct option long_opt[CMD_OPT_MAX_NUM+1]; static const char *help_msg[CMD_OPT_MAX_NUM+1]; static int num_reg_opt; void cmd_opt_add(const cmd_opt_t *cmd_opt) { assert(cmd_opt != NULL); if (num_reg_opt >= CMD_OPT_MAX_NUM) { ERROR("Out of memory. Please increase CMD_OPT_MAX_NUM\n"); exit(1); } long_opt[num_reg_opt].name = cmd_opt->long_opt.name; long_opt[num_reg_opt].has_arg = cmd_opt->long_opt.has_arg; long_opt[num_reg_opt].flag = 0; long_opt[num_reg_opt].val = cmd_opt->long_opt.val; help_msg[num_reg_opt] = cmd_opt->help_msg; num_reg_opt++; } const struct option *cmd_opt_get_array(void) { return long_opt; } const char *cmd_opt_get_name(int idx) { if (idx >= num_reg_opt) { return NULL; } return long_opt[idx].name; } const char *cmd_opt_get_help_msg(int idx) { if (idx >= num_reg_opt) { return NULL; } return help_msg[idx]; } trusted-firmware-a-2.2/tools/cert_create/src/ext.c000066400000000000000000000162731355360272700222750ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include "cmd_opt.h" #include "ext.h" DECLARE_ASN1_ITEM(ASN1_INTEGER) DECLARE_ASN1_ITEM(X509_ALGOR) DECLARE_ASN1_ITEM(ASN1_OCTET_STRING) typedef struct { X509_ALGOR *hashAlgorithm; ASN1_OCTET_STRING *dataHash; } HASH; ASN1_SEQUENCE(HASH) = { ASN1_SIMPLE(HASH, hashAlgorithm, X509_ALGOR), ASN1_SIMPLE(HASH, dataHash, ASN1_OCTET_STRING), } ASN1_SEQUENCE_END(HASH) DECLARE_ASN1_FUNCTIONS(HASH) IMPLEMENT_ASN1_FUNCTIONS(HASH) /* * This function adds the TBB extensions to the internal extension list * maintained by OpenSSL so they can be used later. * * It also initializes the methods to print the contents of the extension. If an * alias is specified in the TBB extension, we reuse the methods of the alias. * Otherwise, only methods for V_ASN1_INTEGER and V_ASN1_OCTET_STRING are * provided. Any other type will be printed as a raw ascii string. * * Return: 0 = success, Otherwise: error */ int ext_init(void) { cmd_opt_t cmd_opt; ext_t *ext; X509V3_EXT_METHOD *m; int nid, ret; unsigned int i; for (i = 0; i < num_extensions; i++) { ext = &extensions[i]; /* Register command line option */ if (ext->opt) { cmd_opt.long_opt.name = ext->opt; cmd_opt.long_opt.has_arg = required_argument; cmd_opt.long_opt.flag = NULL; cmd_opt.long_opt.val = CMD_OPT_EXT; cmd_opt.help_msg = ext->help_msg; cmd_opt_add(&cmd_opt); } /* Register the extension OID in OpenSSL */ if (ext->oid == NULL) { continue; } nid = OBJ_create(ext->oid, ext->sn, ext->ln); if (ext->alias) { X509V3_EXT_add_alias(nid, ext->alias); } else { m = &ext->method; memset(m, 0x0, sizeof(X509V3_EXT_METHOD)); switch (ext->asn1_type) { case V_ASN1_INTEGER: m->it = ASN1_ITEM_ref(ASN1_INTEGER); m->i2s = (X509V3_EXT_I2S)i2s_ASN1_INTEGER; m->s2i = (X509V3_EXT_S2I)s2i_ASN1_INTEGER; break; case V_ASN1_OCTET_STRING: m->it = ASN1_ITEM_ref(ASN1_OCTET_STRING); m->i2s = (X509V3_EXT_I2S)i2s_ASN1_OCTET_STRING; m->s2i = (X509V3_EXT_S2I)s2i_ASN1_OCTET_STRING; break; default: continue; } m->ext_nid = nid; ret = X509V3_EXT_add(m); if (!ret) { ERR_print_errors_fp(stdout); return 1; } } } return 0; } /* * Create a new extension * * Extension ::= SEQUENCE { * id OBJECT IDENTIFIER, * critical BOOLEAN DEFAULT FALSE, * value OCTET STRING } * * Parameters: * pex: OpenSSL extension pointer (output parameter) * nid: extension identifier * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) * data: extension data. This data will be encapsulated in an Octet String * * Return: Extension address, NULL if error */ static X509_EXTENSION *ext_new(int nid, int crit, unsigned char *data, int len) { X509_EXTENSION *ex; ASN1_OCTET_STRING *ext_data; /* Octet string containing the extension data */ ext_data = ASN1_OCTET_STRING_new(); ASN1_OCTET_STRING_set(ext_data, data, len); /* Create the extension */ ex = X509_EXTENSION_create_by_NID(NULL, nid, crit, ext_data); /* The extension makes a copy of the data, so we can free this object */ ASN1_OCTET_STRING_free(ext_data); return ex; } /* * Creates a x509v3 extension containing a hash * * DigestInfo ::= SEQUENCE { * digestAlgorithm AlgorithmIdentifier, * digest OCTET STRING * } * * AlgorithmIdentifier ::= SEQUENCE { * algorithm OBJECT IDENTIFIER, * parameters ANY DEFINED BY algorithm OPTIONAL * } * * Parameters: * nid: extension identifier * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) * md: hash algorithm * buf: pointer to the buffer that contains the hash * len: size of the hash in bytes * * Return: Extension address, NULL if error */ X509_EXTENSION *ext_new_hash(int nid, int crit, const EVP_MD *md, unsigned char *buf, size_t len) { X509_EXTENSION *ex; ASN1_OCTET_STRING *octet; HASH *hash; ASN1_OBJECT *algorithm; X509_ALGOR *x509_algor; unsigned char *p = NULL; int sz; /* OBJECT_IDENTIFIER with hash algorithm */ algorithm = OBJ_nid2obj(EVP_MD_type(md)); if (algorithm == NULL) { return NULL; } /* Create X509_ALGOR */ x509_algor = X509_ALGOR_new(); if (x509_algor == NULL) { return NULL; } x509_algor->algorithm = algorithm; x509_algor->parameter = ASN1_TYPE_new(); ASN1_TYPE_set(x509_algor->parameter, V_ASN1_NULL, NULL); /* OCTET_STRING with the actual hash */ octet = ASN1_OCTET_STRING_new(); if (octet == NULL) { X509_ALGOR_free(x509_algor); return NULL; } ASN1_OCTET_STRING_set(octet, buf, len); /* HASH structure containing algorithm + hash */ hash = HASH_new(); if (hash == NULL) { ASN1_OCTET_STRING_free(octet); X509_ALGOR_free(x509_algor); return NULL; } hash->hashAlgorithm = x509_algor; hash->dataHash = octet; /* DER encoded HASH */ sz = i2d_HASH(hash, &p); if ((sz <= 0) || (p == NULL)) { HASH_free(hash); X509_ALGOR_free(x509_algor); return NULL; } /* Create the extension */ ex = ext_new(nid, crit, p, sz); /* Clean up */ OPENSSL_free(p); HASH_free(hash); return ex; } /* * Creates a x509v3 extension containing a nvcounter encapsulated in an ASN1 * Integer * * Parameters: * pex: OpenSSL extension pointer (output parameter) * nid: extension identifier * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) * value: nvcounter value * * Return: Extension address, NULL if error */ X509_EXTENSION *ext_new_nvcounter(int nid, int crit, int value) { X509_EXTENSION *ex; ASN1_INTEGER *counter; unsigned char *p = NULL; int sz; /* Encode counter */ counter = ASN1_INTEGER_new(); ASN1_INTEGER_set(counter, value); sz = i2d_ASN1_INTEGER(counter, &p); /* Create the extension */ ex = ext_new(nid, crit, p, sz); /* Free objects */ OPENSSL_free(p); ASN1_INTEGER_free(counter); return ex; } /* * Creates a x509v3 extension containing a public key in DER format: * * SubjectPublicKeyInfo ::= SEQUENCE { * algorithm AlgorithmIdentifier, * subjectPublicKey BIT STRING } * * Parameters: * pex: OpenSSL extension pointer (output parameter) * nid: extension identifier * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) * k: key * * Return: Extension address, NULL if error */ X509_EXTENSION *ext_new_key(int nid, int crit, EVP_PKEY *k) { X509_EXTENSION *ex; unsigned char *p; int sz; /* Encode key */ BIO *mem = BIO_new(BIO_s_mem()); if (i2d_PUBKEY_bio(mem, k) <= 0) { ERR_print_errors_fp(stderr); return NULL; } p = (unsigned char *)OPENSSL_malloc(4096); sz = BIO_read(mem, p, 4096); /* Create the extension */ ex = ext_new(nid, crit, p, sz); /* Clean up */ BIO_free(mem); OPENSSL_free(p); return ex; } ext_t *ext_get_by_opt(const char *opt) { ext_t *ext; unsigned int i; /* Sequential search. This is not a performance concern since the number * of extensions is bounded and the code runs on a host machine */ for (i = 0; i < num_extensions; i++) { ext = &extensions[i]; if (ext->opt && !strcmp(ext->opt, opt)) { return ext; } } return NULL; } trusted-firmware-a-2.2/tools/cert_create/src/key.c000066400000000000000000000076071355360272700222660ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #if USE_TBBR_DEFS #include #else #include #endif #include "cert.h" #include "cmd_opt.h" #include "debug.h" #include "key.h" #include "sha.h" #define MAX_FILENAME_LEN 1024 /* * Create a new key container */ int key_new(key_t *key) { /* Create key pair container */ key->key = EVP_PKEY_new(); if (key->key == NULL) { return 0; } return 1; } static int key_create_rsa(key_t *key, int key_bits) { BIGNUM *e; RSA *rsa = NULL; e = BN_new(); if (e == NULL) { printf("Cannot create RSA exponent\n"); goto err; } if (!BN_set_word(e, RSA_F4)) { printf("Cannot assign RSA exponent\n"); goto err; } rsa = RSA_new(); if (rsa == NULL) { printf("Cannot create RSA key\n"); goto err; } if (!RSA_generate_key_ex(rsa, key_bits, e, NULL)) { printf("Cannot generate RSA key\n"); goto err; } if (!EVP_PKEY_assign_RSA(key->key, rsa)) { printf("Cannot assign RSA key\n"); goto err; } BN_free(e); return 1; err: RSA_free(rsa); BN_free(e); return 0; } #ifndef OPENSSL_NO_EC static int key_create_ecdsa(key_t *key, int key_bits) { EC_KEY *ec; ec = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); if (ec == NULL) { printf("Cannot create EC key\n"); goto err; } if (!EC_KEY_generate_key(ec)) { printf("Cannot generate EC key\n"); goto err; } EC_KEY_set_flags(ec, EC_PKEY_NO_PARAMETERS); EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE); if (!EVP_PKEY_assign_EC_KEY(key->key, ec)) { printf("Cannot assign EC key\n"); goto err; } return 1; err: EC_KEY_free(ec); return 0; } #endif /* OPENSSL_NO_EC */ typedef int (*key_create_fn_t)(key_t *key, int key_bits); static const key_create_fn_t key_create_fn[KEY_ALG_MAX_NUM] = { key_create_rsa, /* KEY_ALG_RSA */ #ifndef OPENSSL_NO_EC key_create_ecdsa, /* KEY_ALG_ECDSA */ #endif /* OPENSSL_NO_EC */ }; int key_create(key_t *key, int type, int key_bits) { if (type >= KEY_ALG_MAX_NUM) { printf("Invalid key type\n"); return 0; } if (key_create_fn[type]) { return key_create_fn[type](key, key_bits); } return 0; } int key_load(key_t *key, unsigned int *err_code) { FILE *fp; EVP_PKEY *k; if (key->fn) { /* Load key from file */ fp = fopen(key->fn, "r"); if (fp) { k = PEM_read_PrivateKey(fp, &key->key, NULL, NULL); fclose(fp); if (k) { *err_code = KEY_ERR_NONE; return 1; } else { ERROR("Cannot load key from %s\n", key->fn); *err_code = KEY_ERR_LOAD; } } else { WARN("Cannot open file %s\n", key->fn); *err_code = KEY_ERR_OPEN; } } else { WARN("Key filename not specified\n"); *err_code = KEY_ERR_FILENAME; } return 0; } int key_store(key_t *key) { FILE *fp; if (key->fn) { fp = fopen(key->fn, "w"); if (fp) { PEM_write_PrivateKey(fp, key->key, NULL, NULL, 0, NULL, NULL); fclose(fp); return 1; } else { ERROR("Cannot create file %s\n", key->fn); } } else { ERROR("Key filename not specified\n"); } return 0; } int key_init(void) { cmd_opt_t cmd_opt; key_t *key; unsigned int i; for (i = 0; i < num_keys; i++) { key = &keys[i]; if (key->opt != NULL) { cmd_opt.long_opt.name = key->opt; cmd_opt.long_opt.has_arg = required_argument; cmd_opt.long_opt.flag = NULL; cmd_opt.long_opt.val = CMD_OPT_KEY; cmd_opt.help_msg = key->help_msg; cmd_opt_add(&cmd_opt); } } return 0; } key_t *key_get_by_opt(const char *opt) { key_t *key; unsigned int i; /* Sequential search. This is not a performance concern since the number * of keys is bounded and the code runs on a host machine */ for (i = 0; i < num_keys; i++) { key = &keys[i]; if (0 == strcmp(key->opt, opt)) { return key; } } return NULL; } trusted-firmware-a-2.2/tools/cert_create/src/main.c000066400000000000000000000317441355360272700224210ustar00rootroot00000000000000/* * Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include #include #include #if USE_TBBR_DEFS #include #else #include #endif #include "cert.h" #include "cmd_opt.h" #include "debug.h" #include "ext.h" #include "key.h" #include "sha.h" #include "tbbr/tbb_cert.h" #include "tbbr/tbb_ext.h" #include "tbbr/tbb_key.h" /* * Helper macros to simplify the code. This macro assigns the return value of * the 'fn' function to 'v' and exits if the value is NULL. */ #define CHECK_NULL(v, fn) \ do { \ v = fn; \ if (v == NULL) { \ ERROR("NULL object at %s:%d\n", __FILE__, __LINE__); \ exit(1); \ } \ } while (0) /* * This macro assigns the NID corresponding to 'oid' to 'v' and exits if the * NID is undefined. */ #define CHECK_OID(v, oid) \ do { \ v = OBJ_txt2nid(oid); \ if (v == NID_undef) { \ ERROR("Cannot find TBB extension %s\n", oid); \ exit(1); \ } \ } while (0) #define MAX_FILENAME_LEN 1024 #define VAL_DAYS 7300 #define ID_TO_BIT_MASK(id) (1 << id) #define NUM_ELEM(x) ((sizeof(x)) / (sizeof(x[0]))) #define HELP_OPT_MAX_LEN 128 /* Global options */ static int key_alg; static int hash_alg; static int key_size; static int new_keys; static int save_keys; static int print_cert; /* Info messages created in the Makefile */ extern const char build_msg[]; extern const char platform_msg[]; static char *strdup(const char *str) { int n = strlen(str) + 1; char *dup = malloc(n); if (dup) { strcpy(dup, str); } return dup; } static const char *key_algs_str[] = { [KEY_ALG_RSA] = "rsa", #ifndef OPENSSL_NO_EC [KEY_ALG_ECDSA] = "ecdsa" #endif /* OPENSSL_NO_EC */ }; static const char *hash_algs_str[] = { [HASH_ALG_SHA256] = "sha256", [HASH_ALG_SHA384] = "sha384", [HASH_ALG_SHA512] = "sha512", }; static void print_help(const char *cmd, const struct option *long_opt) { int rem, i = 0; const struct option *opt; char line[HELP_OPT_MAX_LEN]; char *p; assert(cmd != NULL); assert(long_opt != NULL); printf("\n\n"); printf("The certificate generation tool loads the binary images and\n" "optionally the RSA keys, and outputs the key and content\n" "certificates properly signed to implement the chain of trust.\n" "If keys are provided, they must be in PEM format.\n" "Certificates are generated in DER format.\n"); printf("\n"); printf("Usage:\n"); printf("\t%s [OPTIONS]\n\n", cmd); printf("Available options:\n"); opt = long_opt; while (opt->name) { p = line; rem = HELP_OPT_MAX_LEN; if (isalpha(opt->val)) { /* Short format */ sprintf(p, "-%c,", (char)opt->val); p += 3; rem -= 3; } snprintf(p, rem, "--%s %s", opt->name, (opt->has_arg == required_argument) ? "" : ""); printf("\t%-32s %s\n", line, cmd_opt_get_help_msg(i)); opt++; i++; } printf("\n"); } static int get_key_alg(const char *key_alg_str) { int i; for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) { if (0 == strcmp(key_alg_str, key_algs_str[i])) { return i; } } return -1; } static int get_key_size(const char *key_size_str) { char *end; long key_size; key_size = strtol(key_size_str, &end, 10); if (*end != '\0') return -1; return key_size; } static int get_hash_alg(const char *hash_alg_str) { int i; for (i = 0 ; i < NUM_ELEM(hash_algs_str) ; i++) { if (0 == strcmp(hash_alg_str, hash_algs_str[i])) { return i; } } return -1; } static void check_cmd_params(void) { cert_t *cert; ext_t *ext; key_t *key; int i, j; bool valid_size; /* Only save new keys */ if (save_keys && !new_keys) { ERROR("Only new keys can be saved to disk\n"); exit(1); } /* Validate key-size */ valid_size = false; for (i = 0; i < KEY_SIZE_MAX_NUM; i++) { if (key_size == KEY_SIZES[key_alg][i]) { valid_size = true; break; } } if (!valid_size) { ERROR("'%d' is not a valid key size for '%s'\n", key_size, key_algs_str[key_alg]); NOTICE("Valid sizes are: "); for (i = 0; i < KEY_SIZE_MAX_NUM && KEY_SIZES[key_alg][i] != 0; i++) { printf("%d ", KEY_SIZES[key_alg][i]); } printf("\n"); exit(1); } /* Check that all required options have been specified in the * command line */ for (i = 0; i < num_certs; i++) { cert = &certs[i]; if (cert->fn == NULL) { /* Certificate not requested. Skip to the next one */ continue; } /* Check that all parameters required to create this certificate * have been specified in the command line */ for (j = 0; j < cert->num_ext; j++) { ext = &extensions[cert->ext[j]]; switch (ext->type) { case EXT_TYPE_NVCOUNTER: /* Counter value must be specified */ if ((!ext->optional) && (ext->arg == NULL)) { ERROR("Value for '%s' not specified\n", ext->ln); exit(1); } break; case EXT_TYPE_PKEY: /* Key filename must be specified */ key = &keys[ext->attr.key]; if (!new_keys && key->fn == NULL) { ERROR("Key '%s' required by '%s' not " "specified\n", key->desc, cert->cn); exit(1); } break; case EXT_TYPE_HASH: /* * Binary image must be specified * unless it is explicitly made optional. */ if ((!ext->optional) && (ext->arg == NULL)) { ERROR("Image for '%s' not specified\n", ext->ln); exit(1); } break; default: ERROR("Unknown extension type '%d' in '%s'\n", ext->type, ext->ln); exit(1); break; } } } } /* Common command line options */ static const cmd_opt_t common_cmd_opt[] = { { { "help", no_argument, NULL, 'h' }, "Print this message and exit" }, { { "key-alg", required_argument, NULL, 'a' }, "Key algorithm: 'rsa' (default)- RSAPSS scheme as per PKCS#1 v2.1, 'ecdsa'" }, { { "key-size", required_argument, NULL, 'b' }, "Key size (for supported algorithms)." }, { { "hash-alg", required_argument, NULL, 's' }, "Hash algorithm : 'sha256' (default), 'sha384', 'sha512'" }, { { "save-keys", no_argument, NULL, 'k' }, "Save key pairs into files. Filenames must be provided" }, { { "new-keys", no_argument, NULL, 'n' }, "Generate new key pairs if no key files are provided" }, { { "print-cert", no_argument, NULL, 'p' }, "Print the certificates in the standard output" } }; int main(int argc, char *argv[]) { STACK_OF(X509_EXTENSION) * sk; X509_EXTENSION *cert_ext = NULL; ext_t *ext; key_t *key; cert_t *cert; FILE *file; int i, j, ext_nid, nvctr; int c, opt_idx = 0; const struct option *cmd_opt; const char *cur_opt; unsigned int err_code; unsigned char md[SHA512_DIGEST_LENGTH]; unsigned int md_len; const EVP_MD *md_info; NOTICE("CoT Generation Tool: %s\n", build_msg); NOTICE("Target platform: %s\n", platform_msg); /* Set default options */ key_alg = KEY_ALG_RSA; hash_alg = HASH_ALG_SHA256; key_size = -1; /* Add common command line options */ for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) { cmd_opt_add(&common_cmd_opt[i]); } /* Initialize the certificates */ if (cert_init() != 0) { ERROR("Cannot initialize certificates\n"); exit(1); } /* Initialize the keys */ if (key_init() != 0) { ERROR("Cannot initialize keys\n"); exit(1); } /* Initialize the new types and register OIDs for the extensions */ if (ext_init() != 0) { ERROR("Cannot initialize TBB extensions\n"); exit(1); } /* Get the command line options populated during the initialization */ cmd_opt = cmd_opt_get_array(); while (1) { /* getopt_long stores the option index here. */ c = getopt_long(argc, argv, "a:b:hknps:", cmd_opt, &opt_idx); /* Detect the end of the options. */ if (c == -1) { break; } switch (c) { case 'a': key_alg = get_key_alg(optarg); if (key_alg < 0) { ERROR("Invalid key algorithm '%s'\n", optarg); exit(1); } break; case 'b': key_size = get_key_size(optarg); if (key_size <= 0) { ERROR("Invalid key size '%s'\n", optarg); exit(1); } break; case 'h': print_help(argv[0], cmd_opt); exit(0); case 'k': save_keys = 1; break; case 'n': new_keys = 1; break; case 'p': print_cert = 1; break; case 's': hash_alg = get_hash_alg(optarg); if (hash_alg < 0) { ERROR("Invalid hash algorithm '%s'\n", optarg); exit(1); } break; case CMD_OPT_EXT: cur_opt = cmd_opt_get_name(opt_idx); ext = ext_get_by_opt(cur_opt); ext->arg = strdup(optarg); break; case CMD_OPT_KEY: cur_opt = cmd_opt_get_name(opt_idx); key = key_get_by_opt(cur_opt); key->fn = strdup(optarg); break; case CMD_OPT_CERT: cur_opt = cmd_opt_get_name(opt_idx); cert = cert_get_by_opt(cur_opt); cert->fn = strdup(optarg); break; case '?': default: print_help(argv[0], cmd_opt); exit(1); } } /* Select a reasonable default key-size */ if (key_size == -1) { key_size = KEY_SIZES[key_alg][0]; } /* Check command line arguments */ check_cmd_params(); /* Indicate SHA as image hash algorithm in the certificate * extension */ if (hash_alg == HASH_ALG_SHA384) { md_info = EVP_sha384(); md_len = SHA384_DIGEST_LENGTH; } else if (hash_alg == HASH_ALG_SHA512) { md_info = EVP_sha512(); md_len = SHA512_DIGEST_LENGTH; } else { md_info = EVP_sha256(); md_len = SHA256_DIGEST_LENGTH; } /* Load private keys from files (or generate new ones) */ for (i = 0 ; i < num_keys ; i++) { if (!key_new(&keys[i])) { ERROR("Failed to allocate key container\n"); exit(1); } /* First try to load the key from disk */ if (key_load(&keys[i], &err_code)) { /* Key loaded successfully */ continue; } /* Key not loaded. Check the error code */ if (err_code == KEY_ERR_LOAD) { /* File exists, but it does not contain a valid private * key. Abort. */ ERROR("Error loading '%s'\n", keys[i].fn); exit(1); } /* File does not exist, could not be opened or no filename was * given */ if (new_keys) { /* Try to create a new key */ NOTICE("Creating new key for '%s'\n", keys[i].desc); if (!key_create(&keys[i], key_alg, key_size)) { ERROR("Error creating key '%s'\n", keys[i].desc); exit(1); } } else { if (err_code == KEY_ERR_OPEN) { ERROR("Error opening '%s'\n", keys[i].fn); } else { ERROR("Key '%s' not specified\n", keys[i].desc); } exit(1); } } /* Create the certificates */ for (i = 0 ; i < num_certs ; i++) { cert = &certs[i]; /* Create a new stack of extensions. This stack will be used * to create the certificate */ CHECK_NULL(sk, sk_X509_EXTENSION_new_null()); for (j = 0 ; j < cert->num_ext ; j++) { ext = &extensions[cert->ext[j]]; /* Get OpenSSL internal ID for this extension */ CHECK_OID(ext_nid, ext->oid); /* * Three types of extensions are currently supported: * - EXT_TYPE_NVCOUNTER * - EXT_TYPE_HASH * - EXT_TYPE_PKEY */ switch (ext->type) { case EXT_TYPE_NVCOUNTER: if (ext->arg) { nvctr = atoi(ext->arg); CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid, EXT_CRIT, nvctr)); } break; case EXT_TYPE_HASH: if (ext->arg == NULL) { if (ext->optional) { /* Include a hash filled with zeros */ memset(md, 0x0, SHA512_DIGEST_LENGTH); } else { /* Do not include this hash in the certificate */ break; } } else { /* Calculate the hash of the file */ if (!sha_file(hash_alg, ext->arg, md)) { ERROR("Cannot calculate hash of %s\n", ext->arg); exit(1); } } CHECK_NULL(cert_ext, ext_new_hash(ext_nid, EXT_CRIT, md_info, md, md_len)); break; case EXT_TYPE_PKEY: CHECK_NULL(cert_ext, ext_new_key(ext_nid, EXT_CRIT, keys[ext->attr.key].key)); break; default: ERROR("Unknown extension type '%d' in %s\n", ext->type, cert->cn); exit(1); } /* Push the extension into the stack */ sk_X509_EXTENSION_push(sk, cert_ext); } /* Create certificate. Signed with corresponding key */ if (cert->fn && !cert_new(hash_alg, cert, VAL_DAYS, 0, sk)) { ERROR("Cannot create %s\n", cert->cn); exit(1); } sk_X509_EXTENSION_free(sk); } /* Print the certificates */ if (print_cert) { for (i = 0 ; i < num_certs ; i++) { if (!certs[i].x) { continue; } printf("\n\n=====================================\n\n"); X509_print_fp(stdout, certs[i].x); } } /* Save created certificates to files */ for (i = 0 ; i < num_certs ; i++) { if (certs[i].x && certs[i].fn) { file = fopen(certs[i].fn, "w"); if (file != NULL) { i2d_X509_fp(file, certs[i].x); fclose(file); } else { ERROR("Cannot create file %s\n", certs[i].fn); } } } /* Save keys */ if (save_keys) { for (i = 0 ; i < num_keys ; i++) { if (!key_store(&keys[i])) { ERROR("Cannot save %s\n", keys[i].desc); } } } #ifndef OPENSSL_NO_ENGINE ENGINE_cleanup(); #endif CRYPTO_cleanup_all_ex_data(); return 0; } trusted-firmware-a-2.2/tools/cert_create/src/sha.c000066400000000000000000000024111355360272700222350ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "debug.h" #include "key.h" #define BUFFER_SIZE 256 int sha_file(int md_alg, const char *filename, unsigned char *md) { FILE *inFile; SHA256_CTX shaContext; SHA512_CTX sha512Context; int bytes; unsigned char data[BUFFER_SIZE]; if ((filename == NULL) || (md == NULL)) { ERROR("%s(): NULL argument\n", __FUNCTION__); return 0; } inFile = fopen(filename, "rb"); if (inFile == NULL) { ERROR("Cannot read %s\n", filename); return 0; } if (md_alg == HASH_ALG_SHA384) { SHA384_Init(&sha512Context); while ((bytes = fread(data, 1, BUFFER_SIZE, inFile)) != 0) { SHA384_Update(&sha512Context, data, bytes); } SHA384_Final(md, &sha512Context); } else if (md_alg == HASH_ALG_SHA512) { SHA512_Init(&sha512Context); while ((bytes = fread(data, 1, BUFFER_SIZE, inFile)) != 0) { SHA512_Update(&sha512Context, data, bytes); } SHA512_Final(md, &sha512Context); } else { SHA256_Init(&shaContext); while ((bytes = fread(data, 1, BUFFER_SIZE, inFile)) != 0) { SHA256_Update(&shaContext, data, bytes); } SHA256_Final(md, &shaContext); } fclose(inFile); return 1; } trusted-firmware-a-2.2/tools/cert_create/src/tbbr/000077500000000000000000000000001355360272700222515ustar00rootroot00000000000000trusted-firmware-a-2.2/tools/cert_create/src/tbbr/tbb_cert.c000066400000000000000000000111461355360272700242040ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "tbbr/tbb_cert.h" #include "tbbr/tbb_ext.h" #include "tbbr/tbb_key.h" /* * Certificates used in the chain of trust * * The order of the certificates must follow the enumeration specified in * tbb_cert.h. All certificates are self-signed, so the issuer certificate * field points to itself. */ static cert_t tbb_certs[] = { [TRUSTED_BOOT_FW_CERT] = { .id = TRUSTED_BOOT_FW_CERT, .opt = "tb-fw-cert", .help_msg = "Trusted Boot FW Certificate (output file)", .fn = NULL, .cn = "Trusted Boot FW Certificate", .key = ROT_KEY, .issuer = TRUSTED_BOOT_FW_CERT, .ext = { TRUSTED_FW_NVCOUNTER_EXT, TRUSTED_BOOT_FW_HASH_EXT, TRUSTED_BOOT_FW_CONFIG_HASH_EXT, HW_CONFIG_HASH_EXT }, .num_ext = 4 }, [TRUSTED_KEY_CERT] = { .id = TRUSTED_KEY_CERT, .opt = "trusted-key-cert", .help_msg = "Trusted Key Certificate (output file)", .fn = NULL, .cn = "Trusted Key Certificate", .key = ROT_KEY, .issuer = TRUSTED_KEY_CERT, .ext = { TRUSTED_FW_NVCOUNTER_EXT, TRUSTED_WORLD_PK_EXT, NON_TRUSTED_WORLD_PK_EXT }, .num_ext = 3 }, [SCP_FW_KEY_CERT] = { .id = SCP_FW_KEY_CERT, .opt = "scp-fw-key-cert", .help_msg = "SCP Firmware Key Certificate (output file)", .fn = NULL, .cn = "SCP Firmware Key Certificate", .key = TRUSTED_WORLD_KEY, .issuer = SCP_FW_KEY_CERT, .ext = { TRUSTED_FW_NVCOUNTER_EXT, SCP_FW_CONTENT_CERT_PK_EXT }, .num_ext = 2 }, [SCP_FW_CONTENT_CERT] = { .id = SCP_FW_CONTENT_CERT, .opt = "scp-fw-cert", .help_msg = "SCP Firmware Content Certificate (output file)", .fn = NULL, .cn = "SCP Firmware Content Certificate", .key = SCP_FW_CONTENT_CERT_KEY, .issuer = SCP_FW_CONTENT_CERT, .ext = { TRUSTED_FW_NVCOUNTER_EXT, SCP_FW_HASH_EXT }, .num_ext = 2 }, [SOC_FW_KEY_CERT] = { .id = SOC_FW_KEY_CERT, .opt = "soc-fw-key-cert", .help_msg = "SoC Firmware Key Certificate (output file)", .fn = NULL, .cn = "SoC Firmware Key Certificate", .key = TRUSTED_WORLD_KEY, .issuer = SOC_FW_KEY_CERT, .ext = { TRUSTED_FW_NVCOUNTER_EXT, SOC_FW_CONTENT_CERT_PK_EXT }, .num_ext = 2 }, [SOC_FW_CONTENT_CERT] = { .id = SOC_FW_CONTENT_CERT, .opt = "soc-fw-cert", .help_msg = "SoC Firmware Content Certificate (output file)", .fn = NULL, .cn = "SoC Firmware Content Certificate", .key = SOC_FW_CONTENT_CERT_KEY, .issuer = SOC_FW_CONTENT_CERT, .ext = { TRUSTED_FW_NVCOUNTER_EXT, SOC_AP_FW_HASH_EXT, SOC_FW_CONFIG_HASH_EXT, }, .num_ext = 3 }, [TRUSTED_OS_FW_KEY_CERT] = { .id = TRUSTED_OS_FW_KEY_CERT, .opt = "tos-fw-key-cert", .help_msg = "Trusted OS Firmware Key Certificate (output file)", .fn = NULL, .cn = "Trusted OS Firmware Key Certificate", .key = TRUSTED_WORLD_KEY, .issuer = TRUSTED_OS_FW_KEY_CERT, .ext = { TRUSTED_FW_NVCOUNTER_EXT, TRUSTED_OS_FW_CONTENT_CERT_PK_EXT }, .num_ext = 2 }, [TRUSTED_OS_FW_CONTENT_CERT] = { .id = TRUSTED_OS_FW_CONTENT_CERT, .opt = "tos-fw-cert", .help_msg = "Trusted OS Firmware Content Certificate (output file)", .fn = NULL, .cn = "Trusted OS Firmware Content Certificate", .key = TRUSTED_OS_FW_CONTENT_CERT_KEY, .issuer = TRUSTED_OS_FW_CONTENT_CERT, .ext = { TRUSTED_FW_NVCOUNTER_EXT, TRUSTED_OS_FW_HASH_EXT, TRUSTED_OS_FW_EXTRA1_HASH_EXT, TRUSTED_OS_FW_EXTRA2_HASH_EXT, TRUSTED_OS_FW_CONFIG_HASH_EXT, }, .num_ext = 5 }, [NON_TRUSTED_FW_KEY_CERT] = { .id = NON_TRUSTED_FW_KEY_CERT, .opt = "nt-fw-key-cert", .help_msg = "Non-Trusted Firmware Key Certificate (output file)", .fn = NULL, .cn = "Non-Trusted Firmware Key Certificate", .key = NON_TRUSTED_WORLD_KEY, .issuer = NON_TRUSTED_FW_KEY_CERT, .ext = { NON_TRUSTED_FW_NVCOUNTER_EXT, NON_TRUSTED_FW_CONTENT_CERT_PK_EXT }, .num_ext = 2 }, [NON_TRUSTED_FW_CONTENT_CERT] = { .id = NON_TRUSTED_FW_CONTENT_CERT, .opt = "nt-fw-cert", .help_msg = "Non-Trusted Firmware Content Certificate (output file)", .fn = NULL, .cn = "Non-Trusted Firmware Content Certificate", .key = NON_TRUSTED_FW_CONTENT_CERT_KEY, .issuer = NON_TRUSTED_FW_CONTENT_CERT, .ext = { NON_TRUSTED_FW_NVCOUNTER_EXT, NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT, NON_TRUSTED_FW_CONFIG_HASH_EXT, }, .num_ext = 3 }, [FWU_CERT] = { .id = FWU_CERT, .opt = "fwu-cert", .help_msg = "Firmware Update Certificate (output file)", .fn = NULL, .cn = "Firmware Update Certificate", .key = ROT_KEY, .issuer = FWU_CERT, .ext = { SCP_FWU_CFG_HASH_EXT, AP_FWU_CFG_HASH_EXT, FWU_HASH_EXT }, .num_ext = 3 } }; REGISTER_COT(tbb_certs); trusted-firmware-a-2.2/tools/cert_create/src/tbbr/tbb_ext.c000066400000000000000000000155161355360272700240540ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #if USE_TBBR_DEFS #include #else #include #endif #include "ext.h" #include "tbbr/tbb_ext.h" #include "tbbr/tbb_key.h" static ext_t tbb_ext[] = { [TRUSTED_FW_NVCOUNTER_EXT] = { .oid = TRUSTED_FW_NVCOUNTER_OID, .opt = "tfw-nvctr", .help_msg = "Trusted Firmware Non-Volatile counter value", .sn = "TrustedWorldNVCounter", .ln = "Trusted World Non-Volatile counter", .asn1_type = V_ASN1_INTEGER, .type = EXT_TYPE_NVCOUNTER, .attr.nvctr_type = NVCTR_TYPE_TFW }, [NON_TRUSTED_FW_NVCOUNTER_EXT] = { .oid = NON_TRUSTED_FW_NVCOUNTER_OID, .opt = "ntfw-nvctr", .help_msg = "Non-Trusted Firmware Non-Volatile counter value", .sn = "NormalWorldNVCounter", .ln = "Non-Trusted Firmware Non-Volatile counter", .asn1_type = V_ASN1_INTEGER, .type = EXT_TYPE_NVCOUNTER, .attr.nvctr_type = NVCTR_TYPE_NTFW }, [TRUSTED_BOOT_FW_HASH_EXT] = { .oid = TRUSTED_BOOT_FW_HASH_OID, .opt = "tb-fw", .help_msg = "Trusted Boot Firmware image file", .sn = "TrustedBootFirmwareHash", .ln = "Trusted Boot Firmware hash (SHA256)", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_HASH }, [TRUSTED_BOOT_FW_CONFIG_HASH_EXT] = { .oid = TRUSTED_BOOT_FW_CONFIG_HASH_OID, .opt = "tb-fw-config", .help_msg = "Trusted Boot Firmware Config file", .sn = "TrustedBootFirmwareConfigHash", .ln = "Trusted Boot Firmware Config hash", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_HASH, .optional = 1 }, [HW_CONFIG_HASH_EXT] = { .oid = HW_CONFIG_HASH_OID, .opt = "hw-config", .help_msg = "HW Config file", .sn = "HWConfigHash", .ln = "HW Config hash", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_HASH, .optional = 1 }, [TRUSTED_WORLD_PK_EXT] = { .oid = TRUSTED_WORLD_PK_OID, .sn = "TrustedWorldPublicKey", .ln = "Trusted World Public Key", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_PKEY, .attr.key = TRUSTED_WORLD_KEY }, [NON_TRUSTED_WORLD_PK_EXT] = { .oid = NON_TRUSTED_WORLD_PK_OID, .sn = "NonTrustedWorldPublicKey", .ln = "Non-Trusted World Public Key", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_PKEY, .attr.key = NON_TRUSTED_WORLD_KEY }, [SCP_FW_CONTENT_CERT_PK_EXT] = { .oid = SCP_FW_CONTENT_CERT_PK_OID, .sn = "SCPFirmwareContentCertPK", .ln = "SCP Firmware content certificate public key", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_PKEY, .attr.key = SCP_FW_CONTENT_CERT_KEY }, [SCP_FW_HASH_EXT] = { .oid = SCP_FW_HASH_OID, .opt = "scp-fw", .help_msg = "SCP Firmware image file", .sn = "SCPFirmwareHash", .ln = "SCP Firmware hash (SHA256)", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_HASH }, [SOC_FW_CONTENT_CERT_PK_EXT] = { .oid = SOC_FW_CONTENT_CERT_PK_OID, .sn = "SoCFirmwareContentCertPK", .ln = "SoC Firmware content certificate public key", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_PKEY, .attr.key = SOC_FW_CONTENT_CERT_KEY }, [SOC_AP_FW_HASH_EXT] = { .oid = SOC_AP_FW_HASH_OID, .opt = "soc-fw", .help_msg = "SoC AP Firmware image file", .sn = "SoCAPFirmwareHash", .ln = "SoC AP Firmware hash (SHA256)", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_HASH }, [SOC_FW_CONFIG_HASH_EXT] = { .oid = SOC_FW_CONFIG_HASH_OID, .opt = "soc-fw-config", .help_msg = "SoC Firmware Config file", .sn = "SocFirmwareConfigHash", .ln = "SoC Firmware Config hash", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_HASH, .optional = 1 }, [TRUSTED_OS_FW_CONTENT_CERT_PK_EXT] = { .oid = TRUSTED_OS_FW_CONTENT_CERT_PK_OID, .sn = "TrustedOSFirmwareContentCertPK", .ln = "Trusted OS Firmware content certificate public key", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_PKEY, .attr.key = TRUSTED_OS_FW_CONTENT_CERT_KEY }, [TRUSTED_OS_FW_HASH_EXT] = { .oid = TRUSTED_OS_FW_HASH_OID, .opt = "tos-fw", .help_msg = "Trusted OS image file", .sn = "TrustedOSHash", .ln = "Trusted OS hash (SHA256)", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_HASH }, [TRUSTED_OS_FW_EXTRA1_HASH_EXT] = { .oid = TRUSTED_OS_FW_EXTRA1_HASH_OID, .opt = "tos-fw-extra1", .help_msg = "Trusted OS Extra1 image file", .sn = "TrustedOSExtra1Hash", .ln = "Trusted OS Extra1 hash (SHA256)", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_HASH, .optional = 1 }, [TRUSTED_OS_FW_EXTRA2_HASH_EXT] = { .oid = TRUSTED_OS_FW_EXTRA2_HASH_OID, .opt = "tos-fw-extra2", .help_msg = "Trusted OS Extra2 image file", .sn = "TrustedOSExtra2Hash", .ln = "Trusted OS Extra2 hash (SHA256)", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_HASH, .optional = 1 }, [TRUSTED_OS_FW_CONFIG_HASH_EXT] = { .oid = TRUSTED_OS_FW_CONFIG_HASH_OID, .opt = "tos-fw-config", .help_msg = "Trusted OS Firmware Config file", .sn = "TrustedOSFirmwareConfigHash", .ln = "Trusted OS Firmware Config hash", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_HASH, .optional = 1 }, [NON_TRUSTED_FW_CONTENT_CERT_PK_EXT] = { .oid = NON_TRUSTED_FW_CONTENT_CERT_PK_OID, .sn = "NonTrustedFirmwareContentCertPK", .ln = "Non-Trusted Firmware content certificate public key", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_PKEY, .attr.key = NON_TRUSTED_FW_CONTENT_CERT_KEY }, [NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT] = { .oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID, .opt = "nt-fw", .help_msg = "Non-Trusted World Bootloader image file", .sn = "NonTrustedWorldBootloaderHash", .ln = "Non-Trusted World hash (SHA256)", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_HASH }, [NON_TRUSTED_FW_CONFIG_HASH_EXT] = { .oid = NON_TRUSTED_FW_CONFIG_HASH_OID, .opt = "nt-fw-config", .help_msg = "Non Trusted OS Firmware Config file", .sn = "NonTrustedOSFirmwareConfigHash", .ln = "Non-Trusted OS Firmware Config hash", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_HASH, .optional = 1 }, [SCP_FWU_CFG_HASH_EXT] = { .oid = SCP_FWU_CFG_HASH_OID, .opt = "scp-fwu-cfg", .help_msg = "SCP Firmware Update Config image file", .sn = "SCPFWUpdateConfig", .ln = "SCP Firmware Update Config hash (SHA256)", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_HASH, .optional = 1 }, [AP_FWU_CFG_HASH_EXT] = { .oid = AP_FWU_CFG_HASH_OID, .opt = "ap-fwu-cfg", .help_msg = "AP Firmware Update Config image file", .sn = "APFWUpdateConfig", .ln = "AP Firmware Update Config hash (SHA256)", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_HASH, .optional = 1 }, [FWU_HASH_EXT] = { .oid = FWU_HASH_OID, .opt = "fwu", .help_msg = "Firmware Updater image file", .sn = "FWUpdaterHash", .ln = "Firmware Updater hash (SHA256)", .asn1_type = V_ASN1_OCTET_STRING, .type = EXT_TYPE_HASH, .optional = 1 } }; REGISTER_EXTENSIONS(tbb_ext); trusted-firmware-a-2.2/tools/cert_create/src/tbbr/tbb_key.c000066400000000000000000000033361355360272700240410ustar00rootroot00000000000000/* * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "tbbr/tbb_key.h" /* * Keys used to establish the chain of trust * * The order of the keys must follow the enumeration specified in tbb_key.h */ static key_t tbb_keys[] = { [ROT_KEY] = { .id = ROT_KEY, .opt = "rot-key", .help_msg = "Root Of Trust key (input/output file)", .desc = "Root Of Trust key" }, [TRUSTED_WORLD_KEY] = { .id = TRUSTED_WORLD_KEY, .opt = "trusted-world-key", .help_msg = "Trusted World key (input/output file)", .desc = "Trusted World key" }, [NON_TRUSTED_WORLD_KEY] = { .id = NON_TRUSTED_WORLD_KEY, .opt = "non-trusted-world-key", .help_msg = "Non Trusted World key (input/output file)", .desc = "Non Trusted World key" }, [SCP_FW_CONTENT_CERT_KEY] = { .id = SCP_FW_CONTENT_CERT_KEY, .opt = "scp-fw-key", .help_msg = "SCP Firmware Content Certificate key (input/output file)", .desc = "SCP Firmware Content Certificate key" }, [SOC_FW_CONTENT_CERT_KEY] = { .id = SOC_FW_CONTENT_CERT_KEY, .opt = "soc-fw-key", .help_msg = "SoC Firmware Content Certificate key (input/output file)", .desc = "SoC Firmware Content Certificate key" }, [TRUSTED_OS_FW_CONTENT_CERT_KEY] = { .id = TRUSTED_OS_FW_CONTENT_CERT_KEY, .opt = "tos-fw-key", .help_msg = "Trusted OS Firmware Content Certificate key (input/output file)", .desc = "Trusted OS Firmware Content Certificate key" }, [NON_TRUSTED_FW_CONTENT_CERT_KEY] = { .id = NON_TRUSTED_FW_CONTENT_CERT_KEY, .opt = "nt-fw-key", .help_msg = "Non Trusted Firmware Content Certificate key (input/output file)", .desc = "Non Trusted Firmware Content Certificate key" } }; REGISTER_KEYS(tbb_keys); trusted-firmware-a-2.2/tools/fiptool/000077500000000000000000000000001355360272700177255ustar00rootroot00000000000000trusted-firmware-a-2.2/tools/fiptool/Makefile000066400000000000000000000020131355360272700213610ustar00rootroot00000000000000# # Copyright (c) 2014-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # MAKE_HELPERS_DIRECTORY := ../../make_helpers/ include ${MAKE_HELPERS_DIRECTORY}build_macros.mk include ${MAKE_HELPERS_DIRECTORY}build_env.mk PROJECT := fiptool${BIN_EXT} OBJECTS := fiptool.o tbbr_config.o V ?= 0 override CPPFLAGS += -D_GNU_SOURCE -D_XOPEN_SOURCE=700 HOSTCCFLAGS := -Wall -Werror -pedantic -std=c99 ifeq (${DEBUG},1) HOSTCCFLAGS += -g -O0 -DDEBUG else HOSTCCFLAGS += -O2 endif LDLIBS := -lcrypto ifeq (${V},0) Q := @ else Q := endif INCLUDE_PATHS := -I../../include/tools_share HOSTCC ?= gcc .PHONY: all clean distclean all: ${PROJECT} ${PROJECT}: ${OBJECTS} Makefile @echo " HOSTLD $@" ${Q}${HOSTCC} ${OBJECTS} -o $@ ${LDLIBS} @${ECHO_BLANK_LINE} @echo "Built $@ successfully" @${ECHO_BLANK_LINE} %.o: %.c %.h Makefile @echo " HOSTCC $<" ${Q}${HOSTCC} -c ${CPPFLAGS} ${HOSTCCFLAGS} ${INCLUDE_PATHS} $< -o $@ clean: $(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS}) trusted-firmware-a-2.2/tools/fiptool/Makefile.msvc000066400000000000000000000011161355360272700223330ustar00rootroot00000000000000# # Copyright (c) 2019, Arm Limited. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # CC = cl.exe LD = link.exe FIPTOOL = fiptool.exe OBJECTS = fiptool.obj tbbr_config.obj win_posix.obj INC = -I. -I..\..\include\tools_share CFLAGS = $(CFLAGS) /nologo /Za /Zi /c /O2 /MT all: $(FIPTOOL) $(FIPTOOL): $(OBJECTS) $(LD) /INCREMENTAL:NO /debug /nodefaultlib:libc.lib /out:$@ $(LIBS) $** .PHONY: clean realclean clean: del /f /q $(OBJECTS) > nul realclean: del /f /q $(OBJECTS) $(FIPTOOL) > nul .c.obj: $(CC) -c $(CFLAGS) $(INC) $< -Fo$@ trusted-firmware-a-2.2/tools/fiptool/fiptool.c000066400000000000000000000730621355360272700215550ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include "fiptool.h" #include "tbbr_config.h" #define OPT_TOC_ENTRY 0 #define OPT_PLAT_TOC_FLAGS 1 #define OPT_ALIGN 2 static int info_cmd(int argc, char *argv[]); static void info_usage(void); static int create_cmd(int argc, char *argv[]); static void create_usage(void); static int update_cmd(int argc, char *argv[]); static void update_usage(void); static int unpack_cmd(int argc, char *argv[]); static void unpack_usage(void); static int remove_cmd(int argc, char *argv[]); static void remove_usage(void); static int version_cmd(int argc, char *argv[]); static void version_usage(void); static int help_cmd(int argc, char *argv[]); static void usage(void); /* Available subcommands. */ static cmd_t cmds[] = { { .name = "info", .handler = info_cmd, .usage = info_usage }, { .name = "create", .handler = create_cmd, .usage = create_usage }, { .name = "update", .handler = update_cmd, .usage = update_usage }, { .name = "unpack", .handler = unpack_cmd, .usage = unpack_usage }, { .name = "remove", .handler = remove_cmd, .usage = remove_usage }, { .name = "version", .handler = version_cmd, .usage = version_usage }, { .name = "help", .handler = help_cmd, .usage = NULL }, }; static image_desc_t *image_desc_head; static size_t nr_image_descs; static const uuid_t uuid_null; static int verbose; static void vlog(int prio, const char *msg, va_list ap) { char *prefix[] = { "DEBUG", "WARN", "ERROR" }; fprintf(stderr, "%s: ", prefix[prio]); vfprintf(stderr, msg, ap); fputc('\n', stderr); } static void log_dbgx(const char *msg, ...) { va_list ap; va_start(ap, msg); vlog(LOG_DBG, msg, ap); va_end(ap); } static void log_warnx(const char *msg, ...) { va_list ap; va_start(ap, msg); vlog(LOG_WARN, msg, ap); va_end(ap); } static void log_err(const char *msg, ...) { char buf[512]; va_list ap; va_start(ap, msg); snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno)); vlog(LOG_ERR, buf, ap); va_end(ap); exit(1); } static void log_errx(const char *msg, ...) { va_list ap; va_start(ap, msg); vlog(LOG_ERR, msg, ap); va_end(ap); exit(1); } static char *xstrdup(const char *s, const char *msg) { char *d; d = strdup(s); if (d == NULL) log_errx("strdup: %s", msg); return d; } static void *xmalloc(size_t size, const char *msg) { void *d; d = malloc(size); if (d == NULL) log_errx("malloc: %s", msg); return d; } static void *xzalloc(size_t size, const char *msg) { return memset(xmalloc(size, msg), 0, size); } static void xfwrite(void *buf, size_t size, FILE *fp, const char *filename) { if (fwrite(buf, 1, size, fp) != size) log_errx("Failed to write %s", filename); } static image_desc_t *new_image_desc(const uuid_t *uuid, const char *name, const char *cmdline_name) { image_desc_t *desc; desc = xzalloc(sizeof(*desc), "failed to allocate memory for image descriptor"); memcpy(&desc->uuid, uuid, sizeof(uuid_t)); desc->name = xstrdup(name, "failed to allocate memory for image name"); desc->cmdline_name = xstrdup(cmdline_name, "failed to allocate memory for image command line name"); desc->action = DO_UNSPEC; return desc; } static void set_image_desc_action(image_desc_t *desc, int action, const char *arg) { assert(desc != NULL); if (desc->action_arg != (char *)DO_UNSPEC) free(desc->action_arg); desc->action = action; desc->action_arg = NULL; if (arg != NULL) desc->action_arg = xstrdup(arg, "failed to allocate memory for argument"); } static void free_image_desc(image_desc_t *desc) { free(desc->name); free(desc->cmdline_name); free(desc->action_arg); if (desc->image) { free(desc->image->buffer); free(desc->image); } free(desc); } static void add_image_desc(image_desc_t *desc) { image_desc_t **p = &image_desc_head; while (*p) p = &(*p)->next; assert(*p == NULL); *p = desc; nr_image_descs++; } static void free_image_descs(void) { image_desc_t *desc = image_desc_head, *tmp; while (desc != NULL) { tmp = desc->next; free_image_desc(desc); desc = tmp; nr_image_descs--; } assert(nr_image_descs == 0); } static void fill_image_descs(void) { toc_entry_t *toc_entry; for (toc_entry = toc_entries; toc_entry->cmdline_name != NULL; toc_entry++) { image_desc_t *desc; desc = new_image_desc(&toc_entry->uuid, toc_entry->name, toc_entry->cmdline_name); add_image_desc(desc); } } static image_desc_t *lookup_image_desc_from_uuid(const uuid_t *uuid) { image_desc_t *desc; for (desc = image_desc_head; desc != NULL; desc = desc->next) if (memcmp(&desc->uuid, uuid, sizeof(uuid_t)) == 0) return desc; return NULL; } static image_desc_t *lookup_image_desc_from_opt(const char *opt) { image_desc_t *desc; for (desc = image_desc_head; desc != NULL; desc = desc->next) if (strcmp(desc->cmdline_name, opt) == 0) return desc; return NULL; } static void uuid_to_str(char *s, size_t len, const uuid_t *u) { assert(len >= (_UUID_STR_LEN + 1)); snprintf(s, len, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%04X-%04X%04X%04X", u->time_low[0], u->time_low[1], u->time_low[2], u->time_low[3], u->time_mid[0], u->time_mid[1], u->time_hi_and_version[0], u->time_hi_and_version[1], (u->clock_seq_hi_and_reserved << 8) | u->clock_seq_low, (u->node[0] << 8) | u->node[1], (u->node[2] << 8) | u->node[3], (u->node[4] << 8) | u->node[5]); } static void uuid_from_str(uuid_t *u, const char *s) { int n; if (s == NULL) log_errx("UUID cannot be NULL"); if (strlen(s) != _UUID_STR_LEN) log_errx("Invalid UUID: %s", s); n = sscanf(s, "%2hhx%2hhx%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", &u->time_low[0], &u->time_low[1], &u->time_low[2], &u->time_low[3], &u->time_mid[0], &u->time_mid[1], &u->time_hi_and_version[0], &u->time_hi_and_version[1], &u->clock_seq_hi_and_reserved, &u->clock_seq_low, &u->node[0], &u->node[1], &u->node[2], &u->node[3], &u->node[4], &u->node[5]); /* * Given the format specifier above, we expect 16 items to be scanned * for a properly formatted UUID. */ if (n != 16) log_errx("Invalid UUID: %s", s); } static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out) { struct BLD_PLAT_STAT st; FILE *fp; char *buf, *bufend; fip_toc_header_t *toc_header; fip_toc_entry_t *toc_entry; int terminated = 0; fp = fopen(filename, "rb"); if (fp == NULL) log_err("fopen %s", filename); if (fstat(fileno(fp), &st) == -1) log_err("fstat %s", filename); buf = xmalloc(st.st_size, "failed to load file into memory"); if (fread(buf, 1, st.st_size, fp) != st.st_size) log_errx("Failed to read %s", filename); bufend = buf + st.st_size; fclose(fp); if (st.st_size < sizeof(fip_toc_header_t)) log_errx("FIP %s is truncated", filename); toc_header = (fip_toc_header_t *)buf; toc_entry = (fip_toc_entry_t *)(toc_header + 1); if (toc_header->name != TOC_HEADER_NAME) log_errx("%s is not a FIP file", filename); /* Return the ToC header if the caller wants it. */ if (toc_header_out != NULL) *toc_header_out = *toc_header; /* Walk through each ToC entry in the file. */ while ((char *)toc_entry + sizeof(*toc_entry) - 1 < bufend) { image_t *image; image_desc_t *desc; /* Found the ToC terminator, we are done. */ if (memcmp(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)) == 0) { terminated = 1; break; } /* * Build a new image out of the ToC entry and add it to the * table of images. */ image = xzalloc(sizeof(*image), "failed to allocate memory for image"); image->toc_e = *toc_entry; image->buffer = xmalloc(toc_entry->size, "failed to allocate image buffer, is FIP file corrupted?"); /* Overflow checks before memory copy. */ if (toc_entry->size > (uint64_t)-1 - toc_entry->offset_address) log_errx("FIP %s is corrupted", filename); if (toc_entry->size + toc_entry->offset_address > st.st_size) log_errx("FIP %s is corrupted", filename); memcpy(image->buffer, buf + toc_entry->offset_address, toc_entry->size); /* If this is an unknown image, create a descriptor for it. */ desc = lookup_image_desc_from_uuid(&toc_entry->uuid); if (desc == NULL) { char name[_UUID_STR_LEN + 1], filename[PATH_MAX]; uuid_to_str(name, sizeof(name), &toc_entry->uuid); snprintf(filename, sizeof(filename), "%s%s", name, ".bin"); desc = new_image_desc(&toc_entry->uuid, name, "blob"); desc->action = DO_UNPACK; desc->action_arg = xstrdup(filename, "failed to allocate memory for blob filename"); add_image_desc(desc); } assert(desc->image == NULL); desc->image = image; toc_entry++; } if (terminated == 0) log_errx("FIP %s does not have a ToC terminator entry", filename); free(buf); return 0; } static image_t *read_image_from_file(const uuid_t *uuid, const char *filename) { struct BLD_PLAT_STAT st; image_t *image; FILE *fp; assert(uuid != NULL); assert(filename != NULL); fp = fopen(filename, "rb"); if (fp == NULL) log_err("fopen %s", filename); if (fstat(fileno(fp), &st) == -1) log_errx("fstat %s", filename); image = xzalloc(sizeof(*image), "failed to allocate memory for image"); image->toc_e.uuid = *uuid; image->buffer = xmalloc(st.st_size, "failed to allocate image buffer"); if (fread(image->buffer, 1, st.st_size, fp) != st.st_size) log_errx("Failed to read %s", filename); image->toc_e.size = st.st_size; fclose(fp); return image; } static int write_image_to_file(const image_t *image, const char *filename) { FILE *fp; fp = fopen(filename, "wb"); if (fp == NULL) log_err("fopen"); xfwrite(image->buffer, image->toc_e.size, fp, filename); fclose(fp); return 0; } static struct option *add_opt(struct option *opts, size_t *nr_opts, const char *name, int has_arg, int val) { opts = realloc(opts, (*nr_opts + 1) * sizeof(*opts)); if (opts == NULL) log_err("realloc"); opts[*nr_opts].name = name; opts[*nr_opts].has_arg = has_arg; opts[*nr_opts].flag = NULL; opts[*nr_opts].val = val; ++*nr_opts; return opts; } static struct option *fill_common_opts(struct option *opts, size_t *nr_opts, int has_arg) { image_desc_t *desc; for (desc = image_desc_head; desc != NULL; desc = desc->next) opts = add_opt(opts, nr_opts, desc->cmdline_name, has_arg, OPT_TOC_ENTRY); return opts; } static void md_print(const unsigned char *md, size_t len) { size_t i; for (i = 0; i < len; i++) printf("%02x", md[i]); } static int info_cmd(int argc, char *argv[]) { image_desc_t *desc; fip_toc_header_t toc_header; if (argc != 2) info_usage(); argc--, argv++; parse_fip(argv[0], &toc_header); if (verbose) { log_dbgx("toc_header[name]: 0x%llX", (unsigned long long)toc_header.name); log_dbgx("toc_header[serial_number]: 0x%llX", (unsigned long long)toc_header.serial_number); log_dbgx("toc_header[flags]: 0x%llX", (unsigned long long)toc_header.flags); } for (desc = image_desc_head; desc != NULL; desc = desc->next) { image_t *image = desc->image; if (image == NULL) continue; printf("%s: offset=0x%llX, size=0x%llX, cmdline=\"--%s\"", desc->name, (unsigned long long)image->toc_e.offset_address, (unsigned long long)image->toc_e.size, desc->cmdline_name); #ifndef _MSC_VER /* We don't have SHA256 for Visual Studio. */ if (verbose) { unsigned char md[SHA256_DIGEST_LENGTH]; SHA256(image->buffer, image->toc_e.size, md); printf(", sha256="); md_print(md, sizeof(md)); } #endif putchar('\n'); } return 0; } static void info_usage(void) { printf("fiptool info FIP_FILENAME\n"); exit(1); } static int pack_images(const char *filename, uint64_t toc_flags, unsigned long align) { FILE *fp; image_desc_t *desc; fip_toc_header_t *toc_header; fip_toc_entry_t *toc_entry; char *buf; uint64_t entry_offset, buf_size, payload_size = 0, pad_size; size_t nr_images = 0; for (desc = image_desc_head; desc != NULL; desc = desc->next) if (desc->image != NULL) nr_images++; buf_size = sizeof(fip_toc_header_t) + sizeof(fip_toc_entry_t) * (nr_images + 1); buf = calloc(1, buf_size); if (buf == NULL) log_err("calloc"); /* Build up header and ToC entries from the image table. */ toc_header = (fip_toc_header_t *)buf; toc_header->name = TOC_HEADER_NAME; toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER; toc_header->flags = toc_flags; toc_entry = (fip_toc_entry_t *)(toc_header + 1); entry_offset = buf_size; for (desc = image_desc_head; desc != NULL; desc = desc->next) { image_t *image = desc->image; if (image == NULL) continue; payload_size += image->toc_e.size; entry_offset = (entry_offset + align - 1) & ~(align - 1); image->toc_e.offset_address = entry_offset; *toc_entry++ = image->toc_e; entry_offset += image->toc_e.size; } /* * Append a null uuid entry to mark the end of ToC entries. * NOTE the offset address for the last toc_entry must match the fip * size. */ memset(toc_entry, 0, sizeof(*toc_entry)); toc_entry->offset_address = (entry_offset + align - 1) & ~(align - 1); /* Generate the FIP file. */ fp = fopen(filename, "wb"); if (fp == NULL) log_err("fopen %s", filename); if (verbose) log_dbgx("Metadata size: %zu bytes", buf_size); xfwrite(buf, buf_size, fp, filename); if (verbose) log_dbgx("Payload size: %zu bytes", payload_size); for (desc = image_desc_head; desc != NULL; desc = desc->next) { image_t *image = desc->image; if (image == NULL) continue; if (fseek(fp, image->toc_e.offset_address, SEEK_SET)) log_errx("Failed to set file position"); xfwrite(image->buffer, image->toc_e.size, fp, filename); } if (fseek(fp, entry_offset, SEEK_SET)) log_errx("Failed to set file position"); pad_size = toc_entry->offset_address - entry_offset; while (pad_size--) fputc(0x0, fp); free(buf); fclose(fp); return 0; } /* * This function is shared between the create and update subcommands. * The difference between the two subcommands is that when the FIP file * is created, the parsing of an existing FIP is skipped. This results * in update_fip() creating the new FIP file from scratch because the * internal image table is not populated. */ static void update_fip(void) { image_desc_t *desc; /* Add or replace images in the FIP file. */ for (desc = image_desc_head; desc != NULL; desc = desc->next) { image_t *image; if (desc->action != DO_PACK) continue; image = read_image_from_file(&desc->uuid, desc->action_arg); if (desc->image != NULL) { if (verbose) { log_dbgx("Replacing %s with %s", desc->cmdline_name, desc->action_arg); } free(desc->image); desc->image = image; } else { if (verbose) log_dbgx("Adding image %s", desc->action_arg); desc->image = image; } } } static void parse_plat_toc_flags(const char *arg, unsigned long long *toc_flags) { unsigned long long flags; char *endptr; errno = 0; flags = strtoull(arg, &endptr, 16); if (*endptr != '\0' || flags > UINT16_MAX || errno != 0) log_errx("Invalid platform ToC flags: %s", arg); /* Platform ToC flags is a 16-bit field occupying bits [32-47]. */ *toc_flags |= flags << 32; } static int is_power_of_2(unsigned long x) { return x && !(x & (x - 1)); } static unsigned long get_image_align(char *arg) { char *endptr; unsigned long align; errno = 0; align = strtoul(arg, &endptr, 0); if (*endptr != '\0' || !is_power_of_2(align) || errno != 0) log_errx("Invalid alignment: %s", arg); return align; } static void parse_blob_opt(char *arg, uuid_t *uuid, char *filename, size_t len) { char *p; for (p = strtok(arg, ","); p != NULL; p = strtok(NULL, ",")) { if (strncmp(p, "uuid=", strlen("uuid=")) == 0) { p += strlen("uuid="); uuid_from_str(uuid, p); } else if (strncmp(p, "file=", strlen("file=")) == 0) { p += strlen("file="); snprintf(filename, len, "%s", p); } } } static int create_cmd(int argc, char *argv[]) { struct option *opts = NULL; size_t nr_opts = 0; unsigned long long toc_flags = 0; unsigned long align = 1; if (argc < 2) create_usage(); opts = fill_common_opts(opts, &nr_opts, required_argument); opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument, OPT_PLAT_TOC_FLAGS); opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN); opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b'); opts = add_opt(opts, &nr_opts, NULL, 0, 0); while (1) { int c, opt_index = 0; c = getopt_long(argc, argv, "b:", opts, &opt_index); if (c == -1) break; switch (c) { case OPT_TOC_ENTRY: { image_desc_t *desc; desc = lookup_image_desc_from_opt(opts[opt_index].name); set_image_desc_action(desc, DO_PACK, optarg); break; } case OPT_PLAT_TOC_FLAGS: parse_plat_toc_flags(optarg, &toc_flags); break; case OPT_ALIGN: align = get_image_align(optarg); break; case 'b': { char name[_UUID_STR_LEN + 1]; char filename[PATH_MAX] = { 0 }; uuid_t uuid = uuid_null; image_desc_t *desc; parse_blob_opt(optarg, &uuid, filename, sizeof(filename)); if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 || filename[0] == '\0') create_usage(); desc = lookup_image_desc_from_uuid(&uuid); if (desc == NULL) { uuid_to_str(name, sizeof(name), &uuid); desc = new_image_desc(&uuid, name, "blob"); add_image_desc(desc); } set_image_desc_action(desc, DO_PACK, filename); break; } default: create_usage(); } } argc -= optind; argv += optind; free(opts); if (argc == 0) create_usage(); update_fip(); pack_images(argv[0], toc_flags, align); return 0; } static void create_usage(void) { toc_entry_t *toc_entry = toc_entries; printf("fiptool create [opts] FIP_FILENAME\n"); printf("\n"); printf("Options:\n"); printf(" --align \t\tEach image is aligned to (default: 1).\n"); printf(" --blob uuid=...,file=...\tAdd an image with the given UUID pointed to by file.\n"); printf(" --plat-toc-flags \t16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header.\n"); printf("\n"); printf("Specific images are packed with the following options:\n"); for (; toc_entry->cmdline_name != NULL; toc_entry++) printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name, toc_entry->name); exit(1); } static int update_cmd(int argc, char *argv[]) { struct option *opts = NULL; size_t nr_opts = 0; char outfile[PATH_MAX] = { 0 }; fip_toc_header_t toc_header = { 0 }; unsigned long long toc_flags = 0; unsigned long align = 1; int pflag = 0; if (argc < 2) update_usage(); opts = fill_common_opts(opts, &nr_opts, required_argument); opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN); opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b'); opts = add_opt(opts, &nr_opts, "out", required_argument, 'o'); opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument, OPT_PLAT_TOC_FLAGS); opts = add_opt(opts, &nr_opts, NULL, 0, 0); while (1) { int c, opt_index = 0; c = getopt_long(argc, argv, "b:o:", opts, &opt_index); if (c == -1) break; switch (c) { case OPT_TOC_ENTRY: { image_desc_t *desc; desc = lookup_image_desc_from_opt(opts[opt_index].name); set_image_desc_action(desc, DO_PACK, optarg); break; } case OPT_PLAT_TOC_FLAGS: parse_plat_toc_flags(optarg, &toc_flags); pflag = 1; break; case 'b': { char name[_UUID_STR_LEN + 1]; char filename[PATH_MAX] = { 0 }; uuid_t uuid = uuid_null; image_desc_t *desc; parse_blob_opt(optarg, &uuid, filename, sizeof(filename)); if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 || filename[0] == '\0') update_usage(); desc = lookup_image_desc_from_uuid(&uuid); if (desc == NULL) { uuid_to_str(name, sizeof(name), &uuid); desc = new_image_desc(&uuid, name, "blob"); add_image_desc(desc); } set_image_desc_action(desc, DO_PACK, filename); break; } case OPT_ALIGN: align = get_image_align(optarg); break; case 'o': snprintf(outfile, sizeof(outfile), "%s", optarg); break; default: update_usage(); } } argc -= optind; argv += optind; free(opts); if (argc == 0) update_usage(); if (outfile[0] == '\0') snprintf(outfile, sizeof(outfile), "%s", argv[0]); if (access(argv[0], F_OK) == 0) parse_fip(argv[0], &toc_header); if (pflag) toc_header.flags &= ~(0xffffULL << 32); toc_flags = (toc_header.flags |= toc_flags); update_fip(); pack_images(outfile, toc_flags, align); return 0; } static void update_usage(void) { toc_entry_t *toc_entry = toc_entries; printf("fiptool update [opts] FIP_FILENAME\n"); printf("\n"); printf("Options:\n"); printf(" --align \t\tEach image is aligned to (default: 1).\n"); printf(" --blob uuid=...,file=...\tAdd or update an image with the given UUID pointed to by file.\n"); printf(" --out FIP_FILENAME\t\tSet an alternative output FIP file.\n"); printf(" --plat-toc-flags \t16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header.\n"); printf("\n"); printf("Specific images are packed with the following options:\n"); for (; toc_entry->cmdline_name != NULL; toc_entry++) printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name, toc_entry->name); exit(1); } static int unpack_cmd(int argc, char *argv[]) { struct option *opts = NULL; size_t nr_opts = 0; char outdir[PATH_MAX] = { 0 }; image_desc_t *desc; int fflag = 0; int unpack_all = 1; if (argc < 2) unpack_usage(); opts = fill_common_opts(opts, &nr_opts, required_argument); opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b'); opts = add_opt(opts, &nr_opts, "force", no_argument, 'f'); opts = add_opt(opts, &nr_opts, "out", required_argument, 'o'); opts = add_opt(opts, &nr_opts, NULL, 0, 0); while (1) { int c, opt_index = 0; c = getopt_long(argc, argv, "b:fo:", opts, &opt_index); if (c == -1) break; switch (c) { case OPT_TOC_ENTRY: { image_desc_t *desc; desc = lookup_image_desc_from_opt(opts[opt_index].name); set_image_desc_action(desc, DO_UNPACK, optarg); unpack_all = 0; break; } case 'b': { char name[_UUID_STR_LEN + 1]; char filename[PATH_MAX] = { 0 }; uuid_t uuid = uuid_null; image_desc_t *desc; parse_blob_opt(optarg, &uuid, filename, sizeof(filename)); if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 || filename[0] == '\0') unpack_usage(); desc = lookup_image_desc_from_uuid(&uuid); if (desc == NULL) { uuid_to_str(name, sizeof(name), &uuid); desc = new_image_desc(&uuid, name, "blob"); add_image_desc(desc); } set_image_desc_action(desc, DO_UNPACK, filename); unpack_all = 0; break; } case 'f': fflag = 1; break; case 'o': snprintf(outdir, sizeof(outdir), "%s", optarg); break; default: unpack_usage(); } } argc -= optind; argv += optind; free(opts); if (argc == 0) unpack_usage(); parse_fip(argv[0], NULL); if (outdir[0] != '\0') if (chdir(outdir) == -1) log_err("chdir %s", outdir); /* Unpack all specified images. */ for (desc = image_desc_head; desc != NULL; desc = desc->next) { char file[PATH_MAX]; image_t *image = desc->image; if (!unpack_all && desc->action != DO_UNPACK) continue; /* Build filename. */ if (desc->action_arg == NULL) snprintf(file, sizeof(file), "%s.bin", desc->cmdline_name); else snprintf(file, sizeof(file), "%s", desc->action_arg); if (image == NULL) { if (!unpack_all) log_warnx("%s does not exist in %s", file, argv[0]); continue; } if (access(file, F_OK) != 0 || fflag) { if (verbose) log_dbgx("Unpacking %s", file); write_image_to_file(image, file); } else { log_warnx("File %s already exists, use --force to overwrite it", file); } } return 0; } static void unpack_usage(void) { toc_entry_t *toc_entry = toc_entries; printf("fiptool unpack [opts] FIP_FILENAME\n"); printf("\n"); printf("Options:\n"); printf(" --blob uuid=...,file=...\tUnpack an image with the given UUID to file.\n"); printf(" --force\t\t\tIf the output file already exists, use --force to overwrite it.\n"); printf(" --out path\t\t\tSet the output directory path.\n"); printf("\n"); printf("Specific images are unpacked with the following options:\n"); for (; toc_entry->cmdline_name != NULL; toc_entry++) printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name, toc_entry->name); printf("\n"); printf("If no options are provided, all images will be unpacked.\n"); exit(1); } static int remove_cmd(int argc, char *argv[]) { struct option *opts = NULL; size_t nr_opts = 0; char outfile[PATH_MAX] = { 0 }; fip_toc_header_t toc_header; image_desc_t *desc; unsigned long align = 1; int fflag = 0; if (argc < 2) remove_usage(); opts = fill_common_opts(opts, &nr_opts, no_argument); opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN); opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b'); opts = add_opt(opts, &nr_opts, "force", no_argument, 'f'); opts = add_opt(opts, &nr_opts, "out", required_argument, 'o'); opts = add_opt(opts, &nr_opts, NULL, 0, 0); while (1) { int c, opt_index = 0; c = getopt_long(argc, argv, "b:fo:", opts, &opt_index); if (c == -1) break; switch (c) { case OPT_TOC_ENTRY: { image_desc_t *desc; desc = lookup_image_desc_from_opt(opts[opt_index].name); set_image_desc_action(desc, DO_REMOVE, NULL); break; } case OPT_ALIGN: align = get_image_align(optarg); break; case 'b': { char name[_UUID_STR_LEN + 1], filename[PATH_MAX]; uuid_t uuid = uuid_null; image_desc_t *desc; parse_blob_opt(optarg, &uuid, filename, sizeof(filename)); if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0) remove_usage(); desc = lookup_image_desc_from_uuid(&uuid); if (desc == NULL) { uuid_to_str(name, sizeof(name), &uuid); desc = new_image_desc(&uuid, name, "blob"); add_image_desc(desc); } set_image_desc_action(desc, DO_REMOVE, NULL); break; } case 'f': fflag = 1; break; case 'o': snprintf(outfile, sizeof(outfile), "%s", optarg); break; default: remove_usage(); } } argc -= optind; argv += optind; free(opts); if (argc == 0) remove_usage(); if (outfile[0] != '\0' && access(outfile, F_OK) == 0 && !fflag) log_errx("File %s already exists, use --force to overwrite it", outfile); if (outfile[0] == '\0') snprintf(outfile, sizeof(outfile), "%s", argv[0]); parse_fip(argv[0], &toc_header); for (desc = image_desc_head; desc != NULL; desc = desc->next) { if (desc->action != DO_REMOVE) continue; if (desc->image != NULL) { if (verbose) log_dbgx("Removing %s", desc->cmdline_name); free(desc->image); desc->image = NULL; } else { log_warnx("%s does not exist in %s", desc->cmdline_name, argv[0]); } } pack_images(outfile, toc_header.flags, align); return 0; } static void remove_usage(void) { toc_entry_t *toc_entry = toc_entries; printf("fiptool remove [opts] FIP_FILENAME\n"); printf("\n"); printf("Options:\n"); printf(" --align \tEach image is aligned to (default: 1).\n"); printf(" --blob uuid=...\tRemove an image with the given UUID.\n"); printf(" --force\t\tIf the output FIP file already exists, use --force to overwrite it.\n"); printf(" --out FIP_FILENAME\tSet an alternative output FIP file.\n"); printf("\n"); printf("Specific images are removed with the following options:\n"); for (; toc_entry->cmdline_name != NULL; toc_entry++) printf(" --%-16s\t%s\n", toc_entry->cmdline_name, toc_entry->name); exit(1); } static int version_cmd(int argc, char *argv[]) { #ifdef VERSION puts(VERSION); #else /* If built from fiptool directory, VERSION is not set. */ puts("Unknown version"); #endif return 0; } static void version_usage(void) { printf("fiptool version\n"); exit(1); } static int help_cmd(int argc, char *argv[]) { int i; if (argc < 2) usage(); argc--, argv++; for (i = 0; i < NELEM(cmds); i++) { if (strcmp(cmds[i].name, argv[0]) == 0 && cmds[i].usage != NULL) cmds[i].usage(); } if (i == NELEM(cmds)) printf("No help for subcommand '%s'\n", argv[0]); return 0; } static void usage(void) { printf("usage: fiptool [--verbose] []\n"); printf("Global options supported:\n"); printf(" --verbose\tEnable verbose output for all commands.\n"); printf("\n"); printf("Commands supported:\n"); printf(" info\t\tList images contained in FIP.\n"); printf(" create\tCreate a new FIP with the given images.\n"); printf(" update\tUpdate an existing FIP with the given images.\n"); printf(" unpack\tUnpack images from FIP.\n"); printf(" remove\tRemove images from FIP.\n"); printf(" version\tShow fiptool version.\n"); printf(" help\t\tShow help for given command.\n"); exit(1); } int main(int argc, char *argv[]) { int i, ret = 0; while (1) { int c, opt_index = 0; static struct option opts[] = { { "verbose", no_argument, NULL, 'v' }, { NULL, no_argument, NULL, 0 } }; /* * Set POSIX mode so getopt stops at the first non-option * which is the subcommand. */ c = getopt_long(argc, argv, "+v", opts, &opt_index); if (c == -1) break; switch (c) { case 'v': verbose = 1; break; default: usage(); } } argc -= optind; argv += optind; /* Reset optind for subsequent getopt processing. */ optind = 0; if (argc == 0) usage(); fill_image_descs(); for (i = 0; i < NELEM(cmds); i++) { if (strcmp(cmds[i].name, argv[0]) == 0) { ret = cmds[i].handler(argc, argv); break; } } if (i == NELEM(cmds)) usage(); free_image_descs(); return ret; } trusted-firmware-a-2.2/tools/fiptool/fiptool.h000066400000000000000000000016671355360272700215640ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef FIPTOOL_H #define FIPTOOL_H #include #include #include #include #include "fiptool_platform.h" #define NELEM(x) (sizeof (x) / sizeof *(x)) enum { DO_UNSPEC = 0, DO_PACK = 1, DO_UNPACK = 2, DO_REMOVE = 3 }; enum { LOG_DBG, LOG_WARN, LOG_ERR }; typedef struct image_desc { uuid_t uuid; char *name; char *cmdline_name; int action; char *action_arg; struct image *image; struct image_desc *next; } image_desc_t; typedef struct image { struct fip_toc_entry toc_e; void *buffer; } image_t; typedef struct cmd { char *name; int (*handler)(int, char **); void (*usage)(void); } cmd_t; #endif /* FIPTOOL_H */ trusted-firmware-a-2.2/tools/fiptool/fiptool_platform.h000066400000000000000000000010751355360272700234610ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ /* * Build platform specific handling. * This allows for builds on non-Posix platforms * e.g. Visual Studio on Windows */ #ifndef FIPTOOL_PLATFORM_H #define FIPTOOL_PLATFORM_H #ifndef _MSC_VER /* Not Visual Studio, so include Posix Headers. */ # include # include # include # define BLD_PLAT_STAT stat #else /* Visual Studio. */ # include "win_posix.h" #endif #endif /* FIPTOOL_PLATFORM_H */ trusted-firmware-a-2.2/tools/fiptool/tbbr_config.c000066400000000000000000000070721355360272700223550ustar00rootroot00000000000000/* * Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include "tbbr_config.h" /* The images used depends on the platform. */ toc_entry_t toc_entries[] = { { .name = "SCP Firmware Updater Configuration FWU SCP_BL2U", .uuid = UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U, .cmdline_name = "scp-fwu-cfg" }, { .name = "AP Firmware Updater Configuration BL2U", .uuid = UUID_TRUSTED_UPDATE_FIRMWARE_BL2U, .cmdline_name = "ap-fwu-cfg" }, { .name = "Firmware Updater NS_BL2U", .uuid = UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U, .cmdline_name = "fwu" }, { .name = "Non-Trusted Firmware Updater certificate", .uuid = UUID_TRUSTED_FWU_CERT, .cmdline_name = "fwu-cert" }, { .name = "Trusted Boot Firmware BL2", .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2, .cmdline_name = "tb-fw" }, { .name = "SCP Firmware SCP_BL2", .uuid = UUID_SCP_FIRMWARE_SCP_BL2, .cmdline_name = "scp-fw" }, { .name = "EL3 Runtime Firmware BL31", .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31, .cmdline_name = "soc-fw" }, { .name = "Secure Payload BL32 (Trusted OS)", .uuid = UUID_SECURE_PAYLOAD_BL32, .cmdline_name = "tos-fw" }, { .name = "Secure Payload BL32 Extra1 (Trusted OS Extra1)", .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1, .cmdline_name = "tos-fw-extra1" }, { .name = "Secure Payload BL32 Extra2 (Trusted OS Extra2)", .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2, .cmdline_name = "tos-fw-extra2" }, { .name = "Non-Trusted Firmware BL33", .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33, .cmdline_name = "nt-fw" }, /* Dynamic Configs */ { .name = "HW_CONFIG", .uuid = UUID_HW_CONFIG, .cmdline_name = "hw-config" }, { .name = "TB_FW_CONFIG", .uuid = UUID_TB_FW_CONFIG, .cmdline_name = "tb-fw-config" }, { .name = "SOC_FW_CONFIG", .uuid = UUID_SOC_FW_CONFIG, .cmdline_name = "soc-fw-config" }, { .name = "TOS_FW_CONFIG", .uuid = UUID_TOS_FW_CONFIG, .cmdline_name = "tos-fw-config" }, { .name = "NT_FW_CONFIG", .uuid = UUID_NT_FW_CONFIG, .cmdline_name = "nt-fw-config" }, /* Key Certificates */ { .name = "Root Of Trust key certificate", .uuid = UUID_ROT_KEY_CERT, .cmdline_name = "rot-cert" }, { .name = "Trusted key certificate", .uuid = UUID_TRUSTED_KEY_CERT, .cmdline_name = "trusted-key-cert" }, { .name = "SCP Firmware key certificate", .uuid = UUID_SCP_FW_KEY_CERT, .cmdline_name = "scp-fw-key-cert" }, { .name = "SoC Firmware key certificate", .uuid = UUID_SOC_FW_KEY_CERT, .cmdline_name = "soc-fw-key-cert" }, { .name = "Trusted OS Firmware key certificate", .uuid = UUID_TRUSTED_OS_FW_KEY_CERT, .cmdline_name = "tos-fw-key-cert" }, { .name = "Non-Trusted Firmware key certificate", .uuid = UUID_NON_TRUSTED_FW_KEY_CERT, .cmdline_name = "nt-fw-key-cert" }, /* Content certificates */ { .name = "Trusted Boot Firmware BL2 certificate", .uuid = UUID_TRUSTED_BOOT_FW_CERT, .cmdline_name = "tb-fw-cert" }, { .name = "SCP Firmware content certificate", .uuid = UUID_SCP_FW_CONTENT_CERT, .cmdline_name = "scp-fw-cert" }, { .name = "SoC Firmware content certificate", .uuid = UUID_SOC_FW_CONTENT_CERT, .cmdline_name = "soc-fw-cert" }, { .name = "Trusted OS Firmware content certificate", .uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT, .cmdline_name = "tos-fw-cert" }, { .name = "Non-Trusted Firmware content certificate", .uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT, .cmdline_name = "nt-fw-cert" }, { .name = NULL, .uuid = { {0} }, .cmdline_name = NULL, } }; trusted-firmware-a-2.2/tools/fiptool/tbbr_config.h000066400000000000000000000006651355360272700223630ustar00rootroot00000000000000/* * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef TBBR_CONFIG_H #define TBBR_CONFIG_H #include #include #define TOC_HEADER_SERIAL_NUMBER 0x12345678 typedef struct toc_entry { char *name; uuid_t uuid; char *cmdline_name; } toc_entry_t; extern toc_entry_t toc_entries[]; #endif /* TBBR_CONFIG_H */ trusted-firmware-a-2.2/tools/fiptool/win_posix.c000066400000000000000000000154661355360272700221240ustar00rootroot00000000000000/* * Copyright (c) 2017, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include "win_posix.h" /* * This variable is set by getopt to the index of the next element of the * argv array to be processed. Once getopt has found all of the option * arguments, you can use this variable to determine where the remaining * non-option arguments begin. The initial value of this variable is 1. */ int optind = 1; /* * If the value of this variable is nonzero, then getopt prints an error * message to the standard error stream if it encounters an unknown option * default character or an option with a missing required argument. * If you set this variable to zero, getopt does not print any messages, * but it still returns the character ? to indicate an error. */ const int opterr; /* = 0; */ /* const because we do not implement error printing.*/ /* Not initialised to conform with the coding standard. */ /* * When getopt encounters an unknown option character or an option with a * missing required argument, it stores that option character in this * variable. */ int optopt; /* = 0; */ /* * This variable is set by getopt to point at the value of the option * argument, for those options that accept arguments. */ char *optarg; /* = 0; */ enum return_flags { RET_ERROR = -1, RET_END_OPT_LIST = -1, RET_NO_PARAM = '?', RET_NO_PARAM2 = ':', RET_UNKNOWN_OPT = '?' }; /* * Common initialisation on entry. */ static void getopt_init(void) { optarg = (char *)0; optopt = 0; /* optind may be zero with some POSIX uses. * For our purposes we just change it to 1. */ if (optind == 0) optind = 1; } /* * Common handling for a single letter option. */ static int getopt_1char(int argc, char *const argv[], const char *const opstring, const int optchar) { size_t nlen = (opstring == 0) ? 0 : strlen(opstring); size_t loptn; for (loptn = 0; loptn < nlen; loptn++) { if (optchar == opstring[loptn]) { if (opstring[loptn + 1] == ':') { /* Option has argument */ if (optind < argc) { /* Found argument. */ assert(argv != 0); optind++; optarg = argv[optind++]; return optchar; } /* Missing argument. */ if (opstring[loptn + 2] == ':') { /* OK if optional "x::". */ optind++; return optchar; } /* Actual missing value. */ optopt = optchar; return ((opstring[0] == ':') ? RET_NO_PARAM2 : RET_NO_PARAM); } /* No argument, just return option char */ optind++; return optchar; } } /* * If getopt finds an option character in argv that was not included in * options, ... it returns '?' and sets the external variable optopt to * the actual option character. */ optopt = optchar; return RET_UNKNOWN_OPT; } int getopt(int argc, char *argv[], char *opstring) { int result = RET_END_OPT_LIST; size_t argn = 0; size_t nlen = strlen(opstring); getopt_init(); /* If we have an argument left to play with */ if ((argc > optind) && (argv != 0)) { const char *arg = (const char *)argv[optind]; if ((arg != 0) && (arg[0] == '-')) result = getopt_1char(argc, argv, opstring, arg[1]); } return result; } /* * Match an argument value against an option name. * Note that we only match over the shorter length of the pair, to allow * for abbreviation or say --match=value * Long option names may be abbreviated if the abbreviation is unique or an * exact match for some defined option. * A long option may take a parameter, of the form --opt=param or --opt param. */ static int optmatch(const char *argval, const char *optname) { int result = 0; while ((result == 0) && (*optname != 0) && (*argval != 0)) result = (*argval++) - (*optname++); return result; } /* Handling for a single long option. */ static int getopt_1long(const int argc, char *const argv[], const struct option *const longopts, const char *const optname, int *const indexptr) { int result = RET_UNKNOWN_OPT; size_t loptn = 0; while (longopts[loptn].name != 0) { if (optmatch(optname, longopts[loptn].name) == 0) { /* We found a match. */ result = longopts[loptn].val; if (indexptr != 0) *indexptr = loptn; switch (longopts[loptn].has_arg) { case required_argument: if ((optind + 1) >= argc) { /* Missing argument. */ optopt = result; return RET_NO_PARAM; } /* Fallthrough to get option value. */ case optional_argument: if ((argc - optind) > 0) { /* Found argument. */ optarg = argv[++optind]; } /* Fallthrough to handle flag. */ case no_argument: optind++; if (longopts[loptn].flag != 0) { *longopts[loptn].flag = result; result = 0; } break; } return result; } ++loptn; } /* * If getopt finds an option character in argv that was not included * in options, ... it returns '?' and sets the external variable * optopt to the actual option character. */ return RET_UNKNOWN_OPT; } /* * getopt_long gets the next option argument from the argument list * specified by the argv and argc arguments. Options may be either short * (single letter) as for getopt, or longer names (preceded by --). */ int getopt_long(int argc, char *argv[], const char *shortopts, const struct option *longopts, int *indexptr) { int result = RET_END_OPT_LIST; getopt_init(); /* If we have an argument left to play with */ if ((argc > optind) && (argv != 0)) { const char *arg = argv[optind]; if ((arg != 0) && (arg[0] == '-')) { if (arg[1] == '-') { /* Looks like a long option. */ result = getopt_1long(argc, argv, longopts, &arg[2], indexptr); } else { result = getopt_1char(argc, argv, shortopts, arg[1]); } } } return result; } /* * getopt_long_only gets the next option argument from the argument list * specified by the argv and argc arguments. Options may be either short * or long as for getopt_long, but the long names may have a single '-' * prefix too. */ int getopt_long_only(int argc, char *argv[], const char *shortopts, const struct option *longopts, int *indexptr) { int result = RET_END_OPT_LIST; getopt_init(); /* If we have an argument left to play with */ if ((argc > optind) && (argv != 0)) { const char *arg = argv[optind]; if ((arg != 0) && (arg[0] == '-')) { if (arg[1] == '-') { /* Looks like a long option. */ result = getopt_1long(argc, argv, longopts, &arg[2], indexptr); } else { result = getopt_1long(argc, argv, longopts, &arg[1], indexptr); if (result == RET_UNKNOWN_OPT) { result = getopt_1char(argc, argv, shortopts, arg[1]); } } } } return result; } trusted-firmware-a-2.2/tools/fiptool/win_posix.h000066400000000000000000000111311355360272700221120ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef WIN_POSIX_H #define WIN_POSIX_H #define _CRT_SECURE_NO_WARNINGS #include #include #include #include #include #include #include "uuid.h" /* Derive or provide Windows equivalents of Posix/GCC/Unix stuff. */ #ifndef PATH_MAX # ifdef MAX_PATH # define PATH_MAX MAX_PATH # else # ifdef _MAX_PATH # define MAX_PATH _MAX_PATH # define PATH_MAX _MAX_PATH # else # define PATH_MAX 260 # endif # endif #endif #ifndef _CRT_SECURE_NO_WARNINGS # define _CRT_SECURE_NO_WARNINGS 1 #endif /* * Platform specific names. * * Visual Studio deprecates a number of POSIX functions and only provides * ISO C++ compliant alternatives (distinguished by their '_' prefix). * These macros help provide a stopgap for that. */ /* fileno cannot be an inline function, because _fileno is a macro. */ #define fileno(fileptr) _fileno(fileptr) /* _fstat uses the _stat structure, not stat. */ #define BLD_PLAT_STAT _stat /* Define flag values for _access. */ #define F_OK 0 /* getopt implementation for Windows: Data. */ /* Legitimate values for option.has_arg. */ enum has_arg_values { no_argument, /* No argument value required */ required_argument, /* value must be specified. */ optional_argument /* value may be specified. */ }; /* Long option table entry for get_opt_long. */ struct option { /* The name of the option. */ const char *name; /* * Indicates whether the option takes an argument. * Possible values: see has_arg_values above. */ int has_arg; /* If not null, when option present, *flag is set to val. */ int *flag; /* * The value associated with this option to return * (and save in *flag when not null) */ int val; }; /* * This variable is set by getopt to point at the value of the option * argument, for those options that accept arguments. */ extern char *optarg; /* * When this variable is not zero, getopt emits an error message to stderr * if it encounters an unspecified option, or a missing argument. * Otherwise no message is reported. */ extern const int opterr; /* const as NOT used in this implementation. */ /* * This variable is set by getopt to the index of the next element of the * argv array to be processed. Once getopt has found all of the option * arguments, you can use this variable to determine where the remaining * non-option arguments begin. The initial value of this variable is 1. */ extern int optind; /* * When getopt encounters an unknown option character or an option with a * missing required argument, it stores that option character in this * variable. */ extern int optopt; /* * Platform specific names. * * Visual Studio deprecates a number of POSIX functions and only provides * ISO C++ compliant alternatives (distinguished by their '_' prefix). * These inline functions provide a stopgap for that. */ inline int access(const char *path, int mode) { return _access(path, mode); } inline int chdir(const char *s) { return _chdir(s); } inline int fstat(int fd, struct _stat *buffer) { return _fstat(fd, buffer); } inline char *strdup(const char *s) { return _strdup(s); } /* * getopt implementation for Windows: Functions. * * Windows does not have the getopt family of functions, as it normally * uses '/' instead of '-' as the command line option delimiter. * These functions provide a Windows version that uses '-', which precludes * using '-' as the intial letter of a program argument. * This is not seen as a problem in the specific instance of fiptool, * and enables existing makefiles to work on a Windows build environment. */ /* * The getopt function gets the next option argument from the argument list * specified by the argv and argc arguments. */ int getopt(int argc, char *argv[], char *options); /* * getopt_long gets the next option argument from the argument list * specified by the argv and argc arguments. Options may be either short * (single letter) as for getopt, or longer names (preceded by --). */ int getopt_long(int argc, char *argv[], const char *shortopts, const struct option *longopts, int *indexptr); /* * getopt_long_only gets the next option argument from the argument list * specified by the argv and argc arguments. Options may be either short * or long as for getopt_long, but the long names may have a single '-' * prefix, too. */ int getopt_long_only(int argc, char *argv[], const char *shortopts, const struct option *longopts, int *indexptr); #endif /* WIN_POSIX_H */ trusted-firmware-a-2.2/tools/marvell/000077500000000000000000000000001355360272700177135ustar00rootroot00000000000000trusted-firmware-a-2.2/tools/marvell/doimage/000077500000000000000000000000001355360272700213205ustar00rootroot00000000000000trusted-firmware-a-2.2/tools/marvell/doimage/Makefile000066400000000000000000000017051355360272700227630ustar00rootroot00000000000000# # Copyright (C) 2018 Marvell International Ltd. # # SPDX-License-Identifier: BSD-3-Clause # https://spdx.org/licenses PROJECT = doimage OBJECTS = doimage.o HOSTCCFLAGS = -Wall -Werror ifeq (${DEBUG},1) HOSTCCFLAGS += -g -O0 -DDEBUG else HOSTCCFLAGS += -O2 endif ifeq (${MARVELL_SECURE_BOOT},1) DOIMAGE_CC_FLAGS := -DCONFIG_MVEBU_SECURE_BOOT DOIMAGE_LD_FLAGS := -lconfig -lmbedtls -lmbedcrypto -lmbedx509 endif 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. HOSTCC ?= gcc RM := rm -rf .PHONY: all clean all: ${PROJECT} ${PROJECT}: ${OBJECTS} Makefile @echo " HOSTLD $@" ${Q}${HOSTCC} ${OBJECTS} ${DOIMAGE_LD_FLAGS} -o $@ @echo @echo "Built $@ successfully" @echo %.o: %.c Makefile @echo " HOSTCC $<" ${Q}${HOSTCC} -c ${HOSTCCFLAGS} ${INCLUDE_PATHS} $< -o $@ clean: ${Q}${RM} ${PROJECT} ${Q}${RM} ${OBJECTS} trusted-firmware-a-2.2/tools/marvell/doimage/doimage.c000066400000000000000000001362521355360272700231020ustar00rootroot00000000000000/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #include #ifdef CONFIG_MVEBU_SECURE_BOOT #include /* for parsing config file */ #if !defined(MBEDTLS_CONFIG_FILE) #include "mbedtls/config.h" #else #include MBEDTLS_CONFIG_FILE #endif /* mbedTLS stuff */ #if defined(MBEDTLS_BIGNUM_C) && defined(MBEDTLS_ENTROPY_C) && \ defined(MBEDTLS_SHA256_C) && \ defined(MBEDTLS_PK_PARSE_C) && defined(MBEDTLS_FS_IO) && \ defined(MBEDTLS_CTR_DRBG_C) #include #include #include #include #include #include #include #else #error "Bad mbedTLS configuration!" #endif #endif /* CONFIG_MVEBU_SECURE_BOOT */ #define MAX_FILENAME 256 #define CSK_ARR_SZ 16 #define CSK_ARR_EMPTY_FILE "*" #define AES_KEY_BIT_LEN 256 #define AES_KEY_BYTE_LEN (AES_KEY_BIT_LEN >> 3) #define AES_BLOCK_SZ 16 #define RSA_SIGN_BYTE_LEN 256 #define MAX_RSA_DER_BYTE_LEN 524 /* Number of address pairs in control array */ #define CP_CTRL_EL_ARRAY_SZ 32 #define VERSION_STRING "Marvell(C) doimage utility version 3.2" /* A8K definitions */ /* Extension header types */ #define EXT_TYPE_SECURITY 0x1 #define EXT_TYPE_BINARY 0x2 #define MAIN_HDR_MAGIC 0xB105B002 /* PROLOG alignment considerations: * 128B: To allow supporting XMODEM protocol. * 8KB: To align the boot image to the largest NAND page size, and simplify * the read operations from NAND. * We choose the largest page size, in order to use a single image for all * NAND page sizes. */ #define PROLOG_ALIGNMENT (8 << 10) /* UART argument bitfield */ #define UART_MODE_UNMODIFIED 0x0 #define UART_MODE_DISABLE 0x1 #define UART_MODE_UPDATE 0x2 typedef struct _main_header { uint32_t magic; /* 0-3 */ uint32_t prolog_size; /* 4-7 */ uint32_t prolog_checksum; /* 8-11 */ uint32_t boot_image_size; /* 12-15 */ uint32_t boot_image_checksum; /* 16-19 */ uint32_t rsrvd0; /* 20-23 */ uint32_t load_addr; /* 24-27 */ uint32_t exec_addr; /* 28-31 */ uint8_t uart_cfg; /* 32 */ uint8_t baudrate; /* 33 */ uint8_t ext_count; /* 34 */ uint8_t aux_flags; /* 35 */ uint32_t io_arg_0; /* 36-39 */ uint32_t io_arg_1; /* 40-43 */ uint32_t io_arg_2; /* 43-47 */ uint32_t io_arg_3; /* 48-51 */ uint32_t rsrvd1; /* 52-55 */ uint32_t rsrvd2; /* 56-59 */ uint32_t rsrvd3; /* 60-63 */ } header_t; typedef struct _ext_header { uint8_t type; uint8_t offset; uint16_t reserved; uint32_t size; } ext_header_t; typedef struct _sec_entry { uint8_t kak_key[MAX_RSA_DER_BYTE_LEN]; uint32_t jtag_delay; uint32_t box_id; uint32_t flash_id; uint32_t jtag_en; uint32_t encrypt_en; uint32_t efuse_dis; uint8_t header_sign[RSA_SIGN_BYTE_LEN]; uint8_t image_sign[RSA_SIGN_BYTE_LEN]; uint8_t csk_keys[CSK_ARR_SZ][MAX_RSA_DER_BYTE_LEN]; uint8_t csk_sign[RSA_SIGN_BYTE_LEN]; uint32_t cp_ctrl_arr[CP_CTRL_EL_ARRAY_SZ]; uint32_t cp_efuse_arr[CP_CTRL_EL_ARRAY_SZ]; } sec_entry_t; /* A8K definitions end */ /* UART argument bitfield */ #define UART_MODE_UNMODIFIED 0x0 #define UART_MODE_DISABLE 0x1 #define UART_MODE_UPDATE 0x2 #define uart_set_mode(arg, mode) (arg |= (mode & 0x3)) typedef struct _sec_options { #ifdef CONFIG_MVEBU_SECURE_BOOT char aes_key_file[MAX_FILENAME+1]; char kak_key_file[MAX_FILENAME+1]; char csk_key_file[CSK_ARR_SZ][MAX_FILENAME+1]; uint32_t box_id; uint32_t flash_id; uint32_t jtag_delay; uint8_t csk_index; uint8_t jtag_enable; uint8_t efuse_disable; uint32_t cp_ctrl_arr[CP_CTRL_EL_ARRAY_SZ]; uint32_t cp_efuse_arr[CP_CTRL_EL_ARRAY_SZ]; mbedtls_pk_context kak_pk; mbedtls_pk_context csk_pk[CSK_ARR_SZ]; uint8_t aes_key[AES_KEY_BYTE_LEN]; uint8_t *encrypted_image; uint32_t enc_image_sz; #endif } sec_options; typedef struct _options { char bin_ext_file[MAX_FILENAME+1]; char sec_cfg_file[MAX_FILENAME+1]; sec_options *sec_opts; uint32_t load_addr; uint32_t exec_addr; uint32_t baudrate; uint8_t disable_print; int8_t key_index; /* For header signatures verification only */ uint32_t nfc_io_args; } options_t; void usage_err(char *msg) { fprintf(stderr, "Error: %s\n", msg); fprintf(stderr, "run 'doimage -h' to get usage information\n"); exit(-1); } void usage(void) { printf("\n\n%s\n\n", VERSION_STRING); printf("Usage: doimage [options] [output_file]\n"); printf("create bootrom image from u-boot and boot extensions\n\n"); printf("Arguments\n"); printf(" input_file name of boot image file.\n"); printf(" if -p is used, name of the bootrom image file"); printf(" to parse.\n"); printf(" output_file name of output bootrom image file\n"); printf("\nOptions\n"); printf(" -s target SOC name. supports a8020,a7020\n"); printf(" different SOCs may have different boot image\n"); printf(" format so it's mandatory to know the target SOC\n"); printf(" -i boot I/F name. supports nand, spi, nor\n"); printf(" This affects certain parameters coded in the\n"); printf(" image header\n"); printf(" -l boot image load address. default is 0x0\n"); printf(" -e boot image entry address. default is 0x0\n"); printf(" -b binary extension image file.\n"); printf(" This image is executed before the boot image.\n"); printf(" This is typically used to initialize the memory "); printf(" controller.\n"); printf(" Currently supports only a single file.\n"); #ifdef CONFIG_MVEBU_SECURE_BOOT printf(" -c Make trusted boot image using parameters\n"); printf(" from the configuration file.\n"); #endif printf(" -p Parse and display a pre-built boot image\n"); #ifdef CONFIG_MVEBU_SECURE_BOOT printf(" -k Key index for RSA signatures verification\n"); printf(" when parsing the boot image\n"); #endif printf(" -m Disable prints of bootrom and binary extension\n"); printf(" -u UART baudrate used for bootrom prints.\n"); printf(" Must be multiple of 1200\n"); printf(" -h Show this help message\n"); printf(" IO-ROM NFC-NAND boot parameters:\n"); printf(" -n NAND device block size in KB [Default is 64KB].\n"); printf(" -t NAND cell technology (SLC [Default] or MLC)\n"); exit(-1); } /* globals */ static options_t opts = { .bin_ext_file = "NA", .sec_cfg_file = "NA", .sec_opts = 0, .load_addr = 0x0, .exec_addr = 0x0, .disable_print = 0, .baudrate = 0, .key_index = -1, }; int get_file_size(char *filename) { struct stat st; if (stat(filename, &st) == 0) return st.st_size; return -1; } uint32_t checksum32(uint32_t *start, int len) { uint32_t sum = 0; uint32_t *startp = start; do { sum += *startp; startp++; len -= 4; } while (len > 0); return sum; } /******************************************************************************* * create_rsa_signature (memory buffer content) * Create RSASSA-PSS/SHA-256 signature for memory buffer * using RSA Private Key * INPUT: * pk_ctx Private Key context * input memory buffer * ilen buffer length * pers personalization string for seeding the RNG. * For instance a private key file name. * OUTPUT: * signature RSA-2048 signature * RETURN: * 0 on success */ #ifdef CONFIG_MVEBU_SECURE_BOOT int create_rsa_signature(mbedtls_pk_context *pk_ctx, const unsigned char *input, size_t ilen, const char *pers, uint8_t *signature) { mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; unsigned char hash[32]; unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; int rval; /* Not sure this is required, * but it's safer to start with empty buffers */ memset(hash, 0, sizeof(hash)); memset(buf, 0, sizeof(buf)); mbedtls_ctr_drbg_init(&ctr_drbg); mbedtls_entropy_init(&entropy); /* Seed the random number generator */ rval = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers)); if (rval != 0) { fprintf(stderr, " Failed in ctr_drbg_init call (%d)!\n", rval); goto sign_exit; } /* The PK context should be already initialized. * Set the padding type for this PK context */ mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pk_ctx), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256); /* First compute the SHA256 hash for the input blob */ mbedtls_sha256(input, ilen, hash, 0); /* Then calculate the hash signature */ rval = mbedtls_rsa_rsassa_pss_sign(mbedtls_pk_rsa(*pk_ctx), mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA256, 0, hash, buf); if (rval != 0) { fprintf(stderr, "Failed to create RSA signature for %s. Error %d\n", pers, rval); goto sign_exit; } memcpy(signature, buf, 256); sign_exit: mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); return rval; } /* end of create_rsa_signature */ /******************************************************************************* * verify_rsa_signature (memory buffer content) * Verify RSASSA-PSS/SHA-256 signature for memory buffer * using RSA Public Key * INPUT: * pub_key Public Key buffer * ilen Public Key buffer length * input memory buffer * ilen buffer length * pers personalization string for seeding the RNG. * signature RSA-2048 signature * OUTPUT: * none * RETURN: * 0 on success */ int verify_rsa_signature(const unsigned char *pub_key, size_t klen, const unsigned char *input, size_t ilen, const char *pers, uint8_t *signature) { mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_pk_context pk_ctx; unsigned char hash[32]; int rval; /* Not sure this is required, * but it's safer to start with empty buffer */ memset(hash, 0, sizeof(hash)); mbedtls_pk_init(&pk_ctx); mbedtls_ctr_drbg_init(&ctr_drbg); mbedtls_entropy_init(&entropy); /* Seed the random number generator */ rval = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers)); if (rval != 0) { fprintf(stderr, " Failed in ctr_drbg_init call (%d)!\n", rval); goto verify_exit; } /* Check ability to read the public key */ rval = mbedtls_pk_parse_public_key(&pk_ctx, pub_key, MAX_RSA_DER_BYTE_LEN); if (rval != 0) { fprintf(stderr, " Failed in pk_parse_public_key (%#x)!\n", rval); goto verify_exit; } /* Set the padding type for the new PK context */ mbedtls_rsa_set_padding(mbedtls_pk_rsa(pk_ctx), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256); /* Compute the SHA256 hash for the input buffer */ mbedtls_sha256(input, ilen, hash, 0); rval = mbedtls_rsa_rsassa_pss_verify(mbedtls_pk_rsa(pk_ctx), mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256, 0, hash, signature); if (rval != 0) fprintf(stderr, "Failed to verify signature (%d)!\n", rval); verify_exit: mbedtls_pk_free(&pk_ctx); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); return rval; } /* end of verify_rsa_signature */ /******************************************************************************* * image_encrypt * Encrypt image buffer using AES-256-CBC scheme. * The resulting image is saved into opts.sec_opts->encrypted_image * and the adjusted image size into opts.sec_opts->enc_image_sz * First AES_BLOCK_SZ bytes of the output image contain IV * INPUT: * buf Source buffer to encrypt * blen Source buffer length * OUTPUT: * none * RETURN: * 0 on success */ int image_encrypt(uint8_t *buf, uint32_t blen) { struct timeval tv; char *ptmp = (char *)&tv; unsigned char digest[32]; unsigned char IV[AES_BLOCK_SZ]; int i, k; mbedtls_aes_context aes_ctx; int rval = -1; uint8_t *test_img = 0; if (AES_BLOCK_SZ > 32) { fprintf(stderr, "Unsupported AES block size %d\n", AES_BLOCK_SZ); return rval; } mbedtls_aes_init(&aes_ctx); memset(IV, 0, AES_BLOCK_SZ); memset(digest, 0, 32); /* Generate initialization vector and init the AES engine * Use file name XOR current time and finally SHA-256 * [0...AES_BLOCK_SZ-1] */ k = strlen(opts.sec_opts->aes_key_file); if (k > AES_BLOCK_SZ) k = AES_BLOCK_SZ; memcpy(IV, opts.sec_opts->aes_key_file, k); gettimeofday(&tv, 0); for (i = 0, k = 0; i < AES_BLOCK_SZ; i++, k = (k+1) % sizeof(struct timeval)) IV[i] ^= ptmp[k]; /* compute SHA-256 digest of the results * and use it as the init vector (IV) */ mbedtls_sha256(IV, AES_BLOCK_SZ, digest, 0); memcpy(IV, digest, AES_BLOCK_SZ); mbedtls_aes_setkey_enc(&aes_ctx, opts.sec_opts->aes_key, AES_KEY_BIT_LEN); /* The output image has to include extra space for IV * and to be aligned to the AES block size. * The input image buffer has to be already aligned to AES_BLOCK_SZ * and padded with zeroes */ opts.sec_opts->enc_image_sz = (blen + 2 * AES_BLOCK_SZ - 1) & ~(AES_BLOCK_SZ - 1); opts.sec_opts->encrypted_image = calloc(opts.sec_opts->enc_image_sz, 1); if (opts.sec_opts->encrypted_image == 0) { fprintf(stderr, "Failed to allocate encrypted image!\n"); goto encrypt_exit; } /* Put IV into the output buffer next to the encrypted image * Since the IV is modified by the encryption function, * this should be done now */ memcpy(opts.sec_opts->encrypted_image + opts.sec_opts->enc_image_sz - AES_BLOCK_SZ, IV, AES_BLOCK_SZ); rval = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, opts.sec_opts->enc_image_sz - AES_BLOCK_SZ, IV, buf, opts.sec_opts->encrypted_image); if (rval != 0) { fprintf(stderr, "Failed to encrypt the image! Error %d\n", rval); goto encrypt_exit; } mbedtls_aes_free(&aes_ctx); /* Try to decrypt the image and compare it with the original data */ mbedtls_aes_init(&aes_ctx); mbedtls_aes_setkey_dec(&aes_ctx, opts.sec_opts->aes_key, AES_KEY_BIT_LEN); test_img = calloc(opts.sec_opts->enc_image_sz - AES_BLOCK_SZ, 1); if (test_img == 0) { fprintf(stderr, "Failed to allocate test image!d\n"); rval = -1; goto encrypt_exit; } memcpy(IV, opts.sec_opts->encrypted_image + opts.sec_opts->enc_image_sz - AES_BLOCK_SZ, AES_BLOCK_SZ); rval = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, opts.sec_opts->enc_image_sz - AES_BLOCK_SZ, IV, opts.sec_opts->encrypted_image, test_img); if (rval != 0) { fprintf(stderr, "Failed to decrypt the image! Error %d\n", rval); goto encrypt_exit; } for (i = 0; i < blen; i++) { if (buf[i] != test_img[i]) { fprintf(stderr, "Failed to compare the image after"); fprintf(stderr, " decryption! Byte count is %d\n", i); rval = -1; goto encrypt_exit; } } encrypt_exit: mbedtls_aes_free(&aes_ctx); if (test_img) free(test_img); return rval; } /* end of image_encrypt */ /******************************************************************************* * verify_secure_header_signatures * Verify CSK array, header and image signatures and print results * INPUT: * main_hdr Main header * sec_ext Secure extension * OUTPUT: * none * RETURN: * 0 on success */ int verify_secure_header_signatures(header_t *main_hdr, sec_entry_t *sec_ext) { uint8_t *image = (uint8_t *)main_hdr + main_hdr->prolog_size; uint8_t signature[RSA_SIGN_BYTE_LEN]; int rval = -1; /* Save headers signature and reset it in the secure header */ memcpy(signature, sec_ext->header_sign, RSA_SIGN_BYTE_LEN); memset(sec_ext->header_sign, 0, RSA_SIGN_BYTE_LEN); fprintf(stdout, "\nCheck RSA Signatures\n"); fprintf(stdout, "#########################\n"); fprintf(stdout, "CSK Block Signature: "); if (verify_rsa_signature(sec_ext->kak_key, MAX_RSA_DER_BYTE_LEN, &sec_ext->csk_keys[0][0], sizeof(sec_ext->csk_keys), "CSK Block Signature: ", sec_ext->csk_sign) != 0) { fprintf(stdout, "ERROR\n"); goto ver_error; } fprintf(stdout, "OK\n"); if (opts.key_index != -1) { fprintf(stdout, "Image Signature: "); if (verify_rsa_signature(sec_ext->csk_keys[opts.key_index], MAX_RSA_DER_BYTE_LEN, image, main_hdr->boot_image_size, "Image Signature: ", sec_ext->image_sign) != 0) { fprintf(stdout, "ERROR\n"); goto ver_error; } fprintf(stdout, "OK\n"); fprintf(stdout, "Header Signature: "); if (verify_rsa_signature(sec_ext->csk_keys[opts.key_index], MAX_RSA_DER_BYTE_LEN, (uint8_t *)main_hdr, main_hdr->prolog_size, "Header Signature: ", signature) != 0) { fprintf(stdout, "ERROR\n"); goto ver_error; } fprintf(stdout, "OK\n"); } else { fprintf(stdout, "SKIP Image and Header Signatures"); fprintf(stdout, " check (undefined key index)\n"); } rval = 0; ver_error: memcpy(sec_ext->header_sign, signature, RSA_SIGN_BYTE_LEN); return rval; } /******************************************************************************* * verify_and_copy_file_name_entry * INPUT: * element_name * element * OUTPUT: * copy_to * RETURN: * 0 on success */ int verify_and_copy_file_name_entry(const char *element_name, const char *element, char *copy_to) { int element_length = strlen(element); if (element_length >= MAX_FILENAME) { fprintf(stderr, "The file name %s for %s is too long (%d). ", element, element_name, element_length); fprintf(stderr, "Maximum allowed %d characters!\n", MAX_FILENAME); return -1; } else if (element_length == 0) { fprintf(stderr, "The file name for %s is empty!\n", element_name); return -1; } memcpy(copy_to, element, element_length); return 0; } /******************************************************************************* * parse_sec_config_file * Read the secure boot configuration from a file * into internal structures * INPUT: * filename File name * OUTPUT: * none * RETURN: * 0 on success */ int parse_sec_config_file(char *filename) { config_t sec_cfg; int array_sz, element, rval = -1; const char *cfg_string; int32_t cfg_int32; const config_setting_t *csk_array, *control_array; sec_options *sec_opt = 0; config_init(&sec_cfg); if (config_read_file(&sec_cfg, filename) != CONFIG_TRUE) { fprintf(stderr, "Failed to read data from config file "); fprintf(stderr, "%s\n\t%s at line %d\n", filename, config_error_text(&sec_cfg), config_error_line(&sec_cfg)); goto exit_parse; } sec_opt = (sec_options *)calloc(sizeof(sec_options), 1); if (sec_opt == 0) { fprintf(stderr, "Cannot allocate memory for secure boot options!\n"); goto exit_parse; } /* KAK file name */ if (config_lookup_string(&sec_cfg, "kak_key_file", &cfg_string) != CONFIG_TRUE) { fprintf(stderr, "The \"kak_key_file\" undefined!\n"); goto exit_parse; } if (verify_and_copy_file_name_entry("kak_key_file", cfg_string, sec_opt->kak_key_file)) goto exit_parse; /* AES file name - can be empty/undefined */ if (config_lookup_string(&sec_cfg, "aes_key_file", &cfg_string) == CONFIG_TRUE) { if (verify_and_copy_file_name_entry("aes_key_file", cfg_string, sec_opt->aes_key_file)) goto exit_parse; } /* CSK file names array */ csk_array = config_lookup(&sec_cfg, "csk_key_file"); if (csk_array == NULL) { fprintf(stderr, "The \"csk_key_file\" undefined!\n"); goto exit_parse; } array_sz = config_setting_length(csk_array); if (array_sz > CSK_ARR_SZ) { fprintf(stderr, "The \"csk_key_file\" array is too big! "); fprintf(stderr, "Only first %d elements will be used\n", CSK_ARR_SZ); array_sz = CSK_ARR_SZ; } else if (array_sz == 0) { fprintf(stderr, "The \"csk_key_file\" array is empty!\n"); goto exit_parse; } for (element = 0; element < array_sz; element++) { cfg_string = config_setting_get_string_elem(csk_array, element); if (verify_and_copy_file_name_entry( "csk_key_file", cfg_string, sec_opt->csk_key_file[element])) { fprintf(stderr, "Bad csk_key_file[%d] entry!\n", element); goto exit_parse; } } /* JTAG options */ if (config_lookup_bool(&sec_cfg, "jtag.enable", &cfg_int32) != CONFIG_TRUE) { fprintf(stderr, "Error obtaining \"jtag.enable\" element. "); fprintf(stderr, "Using default - FALSE\n"); cfg_int32 = 0; } sec_opt->jtag_enable = cfg_int32; if (config_lookup_int(&sec_cfg, "jtag.delay", &cfg_int32) != CONFIG_TRUE) { fprintf(stderr, "Error obtaining \"jtag.delay\" element. "); fprintf(stderr, "Using default - 0us\n"); cfg_int32 = 0; } sec_opt->jtag_delay = cfg_int32; /* eFUSE option */ if (config_lookup_bool(&sec_cfg, "efuse_disable", &cfg_int32) != CONFIG_TRUE) { fprintf(stderr, "Error obtaining \"efuse_disable\" element. "); fprintf(stderr, "Using default - TRUE\n"); cfg_int32 = 1; } sec_opt->efuse_disable = cfg_int32; /* Box ID option */ if (config_lookup_int(&sec_cfg, "box_id", &cfg_int32) != CONFIG_TRUE) { fprintf(stderr, "Error obtaining \"box_id\" element. "); fprintf(stderr, "Using default - 0x0\n"); cfg_int32 = 0; } sec_opt->box_id = cfg_int32; /* Flash ID option */ if (config_lookup_int(&sec_cfg, "flash_id", &cfg_int32) != CONFIG_TRUE) { fprintf(stderr, "Error obtaining \"flash_id\" element. "); fprintf(stderr, "Using default - 0x0\n"); cfg_int32 = 0; } sec_opt->flash_id = cfg_int32; /* CSK index option */ if (config_lookup_int(&sec_cfg, "csk_key_index", &cfg_int32) != CONFIG_TRUE) { fprintf(stderr, "Error obtaining \"flash_id\" element. "); fprintf(stderr, "Using default - 0x0\n"); cfg_int32 = 0; } sec_opt->csk_index = cfg_int32; /* Secure boot control array */ control_array = config_lookup(&sec_cfg, "control"); if (control_array != NULL) { array_sz = config_setting_length(control_array); if (array_sz == 0) fprintf(stderr, "The \"control\" array is empty!\n"); } else { fprintf(stderr, "The \"control\" is undefined!\n"); array_sz = 0; } for (element = 0; element < CP_CTRL_EL_ARRAY_SZ; element++) { sec_opt->cp_ctrl_arr[element] = config_setting_get_int_elem(control_array, element * 2); sec_opt->cp_efuse_arr[element] = config_setting_get_int_elem(control_array, element * 2 + 1); } opts.sec_opts = sec_opt; rval = 0; exit_parse: config_destroy(&sec_cfg); if (sec_opt && (rval != 0)) free(sec_opt); return rval; } /* end of parse_sec_config_file */ int format_sec_ext(char *filename, FILE *out_fd) { ext_header_t header; sec_entry_t sec_ext; int index; int written; #define DER_BUF_SZ 1600 /* First, parse the configuration file */ if (parse_sec_config_file(filename)) { fprintf(stderr, "failed parsing configuration file %s\n", filename); return 1; } /* Everything except signatures can be created at this stage */ header.type = EXT_TYPE_SECURITY; header.offset = 0; header.size = sizeof(sec_entry_t); header.reserved = 0; /* Bring up RSA context and read private keys from their files */ for (index = 0; index < (CSK_ARR_SZ + 1); index++) { /* for every private key file */ mbedtls_pk_context *pk_ctx = (index == CSK_ARR_SZ) ? &opts.sec_opts->kak_pk : &opts.sec_opts->csk_pk[index]; char *fname = (index == CSK_ARR_SZ) ? opts.sec_opts->kak_key_file : opts.sec_opts->csk_key_file[index]; uint8_t *out_der_key = (index == CSK_ARR_SZ) ? sec_ext.kak_key : sec_ext.csk_keys[index]; size_t output_len; unsigned char output_buf[DER_BUF_SZ]; unsigned char *der_buf_start; /* Handle invalid/reserved file names */ if (strncmp(CSK_ARR_EMPTY_FILE, fname, strlen(CSK_ARR_EMPTY_FILE)) == 0) { if (opts.sec_opts->csk_index == index) { fprintf(stderr, "CSK file with index %d cannot be %s\n", index, CSK_ARR_EMPTY_FILE); return 1; } else if (index == CSK_ARR_SZ) { fprintf(stderr, "KAK file name cannot be %s\n", CSK_ARR_EMPTY_FILE); return 1; } /* this key will be empty in CSK array */ continue; } mbedtls_pk_init(pk_ctx); /* Read the private RSA key into the context * and verify it (no password) */ if (mbedtls_pk_parse_keyfile(pk_ctx, fname, "") != 0) { fprintf(stderr, "Cannot read RSA private key file %s\n", fname); return 1; } /* Create a public key out of private one * and store it in DER format */ output_len = mbedtls_pk_write_pubkey_der(pk_ctx, output_buf, DER_BUF_SZ); if (output_len < 0) { fprintf(stderr, "Failed to create DER coded PUB key (%s)\n", fname); return 1; } /* Data in the output buffer is aligned to the buffer end */ der_buf_start = output_buf + sizeof(output_buf) - output_len; /* In the header DER data is aligned * to the start of appropriate field */ memcpy(out_der_key, der_buf_start, output_len); } /* for every private key file */ /* The CSK block signature can be created here */ if (create_rsa_signature(&opts.sec_opts->kak_pk, &sec_ext.csk_keys[0][0], sizeof(sec_ext.csk_keys), opts.sec_opts->csk_key_file[ opts.sec_opts->csk_index], sec_ext.csk_sign) != 0) { fprintf(stderr, "Failed to sign CSK keys block!\n"); return 1; } /* Check that everything is correct */ if (verify_rsa_signature(sec_ext.kak_key, MAX_RSA_DER_BYTE_LEN, &sec_ext.csk_keys[0][0], sizeof(sec_ext.csk_keys), opts.sec_opts->kak_key_file, sec_ext.csk_sign) != 0) { fprintf(stderr, "Failed to verify CSK keys block signature!\n"); return 1; } /* AES encryption stuff */ if (strlen(opts.sec_opts->aes_key_file) != 0) { FILE *in_fd; in_fd = fopen(opts.sec_opts->aes_key_file, "rb"); if (in_fd == NULL) { fprintf(stderr, "Failed to open AES key file %s\n", opts.sec_opts->aes_key_file); return 1; } /* Read the AES key in ASCII format byte by byte */ for (index = 0; index < AES_KEY_BYTE_LEN; index++) { if (fscanf(in_fd, "%02hhx", opts.sec_opts->aes_key + index) != 1) { fprintf(stderr, "Failed to read AES key byte %d ", index); fprintf(stderr, "from file %s\n", opts.sec_opts->aes_key_file); fclose(in_fd); return 1; } } fclose(in_fd); sec_ext.encrypt_en = 1; } else { sec_ext.encrypt_en = 0; } /* Fill the rest of the trusted boot extension fields */ sec_ext.box_id = opts.sec_opts->box_id; sec_ext.flash_id = opts.sec_opts->flash_id; sec_ext.efuse_dis = opts.sec_opts->efuse_disable; sec_ext.jtag_delay = opts.sec_opts->jtag_delay; sec_ext.jtag_en = opts.sec_opts->jtag_enable; memcpy(sec_ext.cp_ctrl_arr, opts.sec_opts->cp_ctrl_arr, sizeof(uint32_t) * CP_CTRL_EL_ARRAY_SZ); memcpy(sec_ext.cp_efuse_arr, opts.sec_opts->cp_efuse_arr, sizeof(uint32_t) * CP_CTRL_EL_ARRAY_SZ); /* Write the resulting extension to file * (image and header signature fields are still empty) */ /* Write extension header */ written = fwrite(&header, sizeof(ext_header_t), 1, out_fd); if (written != 1) { fprintf(stderr, "Failed to write SEC extension header to the file\n"); return 1; } /* Write extension body */ written = fwrite(&sec_ext, sizeof(sec_entry_t), 1, out_fd); if (written != 1) { fprintf(stderr, "Failed to write SEC extension body to the file\n"); return 1; } return 0; } /******************************************************************************* * finalize_secure_ext * Make final changes to secure extension - calculate image and header * signatures and encrypt the image if needed. * The main header checksum and image size fields updated accordingly * INPUT: * header Main header * prolog_buf the entire prolog buffer * prolog_size prolog buffer length * image_buf buffer containing the input binary image * image_size image buffer size. * OUTPUT: * none * RETURN: * 0 on success */ int finalize_secure_ext(header_t *header, uint8_t *prolog_buf, uint32_t prolog_size, uint8_t *image_buf, int image_size) { int cur_ext, offset; uint8_t *final_image = image_buf; uint32_t final_image_sz = image_size; uint8_t hdr_sign[RSA_SIGN_BYTE_LEN]; sec_entry_t *sec_ext = 0; /* Find the Trusted Boot Header between available extensions */ for (cur_ext = 0, offset = sizeof(header_t); cur_ext < header->ext_count; cur_ext++) { ext_header_t *ext_hdr = (ext_header_t *)(prolog_buf + offset); if (ext_hdr->type == EXT_TYPE_SECURITY) { sec_ext = (sec_entry_t *)(prolog_buf + offset + sizeof(ext_header_t) + ext_hdr->offset); break; } offset += sizeof(ext_header_t); /* If offset is Zero, the extension follows its header */ if (ext_hdr->offset == 0) offset += ext_hdr->size; } if (sec_ext == 0) { fprintf(stderr, "Error: No Trusted Boot extension found!\n"); return -1; } if (sec_ext->encrypt_en) { /* Encrypt the image if needed */ fprintf(stdout, "Encrypting the image...\n"); if (image_encrypt(image_buf, image_size) != 0) { fprintf(stderr, "Failed to encrypt the image!\n"); return -1; } /* Image size and checksum should be updated after encryption. * This way the image could be verified by the BootROM * before decryption. */ final_image = opts.sec_opts->encrypted_image; final_image_sz = opts.sec_opts->enc_image_sz; header->boot_image_size = final_image_sz; header->boot_image_checksum = checksum32((uint32_t *)final_image, final_image_sz); } /* AES encryption */ /* Create the image signature first, since it will be later * signed along with the header signature */ if (create_rsa_signature(&opts.sec_opts->csk_pk[ opts.sec_opts->csk_index], final_image, final_image_sz, opts.sec_opts->csk_key_file[ opts.sec_opts->csk_index], sec_ext->image_sign) != 0) { fprintf(stderr, "Failed to sign image!\n"); return -1; } /* Check that the image signature is correct */ if (verify_rsa_signature(sec_ext->csk_keys[opts.sec_opts->csk_index], MAX_RSA_DER_BYTE_LEN, final_image, final_image_sz, opts.sec_opts->csk_key_file[ opts.sec_opts->csk_index], sec_ext->image_sign) != 0) { fprintf(stderr, "Failed to verify image signature!\n"); return -1; } /* Sign the headers and all the extensions block * when the header signature field is empty */ if (create_rsa_signature(&opts.sec_opts->csk_pk[ opts.sec_opts->csk_index], prolog_buf, prolog_size, opts.sec_opts->csk_key_file[ opts.sec_opts->csk_index], hdr_sign) != 0) { fprintf(stderr, "Failed to sign header!\n"); return -1; } /* Check that the header signature is correct */ if (verify_rsa_signature(sec_ext->csk_keys[opts.sec_opts->csk_index], MAX_RSA_DER_BYTE_LEN, prolog_buf, prolog_size, opts.sec_opts->csk_key_file[ opts.sec_opts->csk_index], hdr_sign) != 0) { fprintf(stderr, "Failed to verify header signature!\n"); return -1; } /* Finally, copy the header signature into the trusted boot extension */ memcpy(sec_ext->header_sign, hdr_sign, RSA_SIGN_BYTE_LEN); return 0; } #endif /* CONFIG_MVEBU_SECURE_BOOT */ #define FMT_HEX 0 #define FMT_DEC 1 #define FMT_BIN 2 #define FMT_NONE 3 void do_print_field(unsigned int value, char *name, int start, int size, int format) { fprintf(stdout, "[0x%05x : 0x%05x] %-26s", start, start + size - 1, name); switch (format) { case FMT_HEX: printf("0x%x\n", value); break; case FMT_DEC: printf("%d\n", value); break; default: printf("\n"); break; } } #define print_field(st, type, field, hex, base) \ do_print_field((int)st->field, #field, \ base + offsetof(type, field), sizeof(st->field), hex) int print_header(uint8_t *buf, int base) { header_t *main_hdr; main_hdr = (header_t *)buf; fprintf(stdout, "########### Header ##############\n"); print_field(main_hdr, header_t, magic, FMT_HEX, base); print_field(main_hdr, header_t, prolog_size, FMT_DEC, base); print_field(main_hdr, header_t, prolog_checksum, FMT_HEX, base); print_field(main_hdr, header_t, boot_image_size, FMT_DEC, base); print_field(main_hdr, header_t, boot_image_checksum, FMT_HEX, base); print_field(main_hdr, header_t, rsrvd0, FMT_HEX, base); print_field(main_hdr, header_t, load_addr, FMT_HEX, base); print_field(main_hdr, header_t, exec_addr, FMT_HEX, base); print_field(main_hdr, header_t, uart_cfg, FMT_HEX, base); print_field(main_hdr, header_t, baudrate, FMT_HEX, base); print_field(main_hdr, header_t, ext_count, FMT_DEC, base); print_field(main_hdr, header_t, aux_flags, FMT_HEX, base); print_field(main_hdr, header_t, io_arg_0, FMT_HEX, base); print_field(main_hdr, header_t, io_arg_1, FMT_HEX, base); print_field(main_hdr, header_t, io_arg_2, FMT_HEX, base); print_field(main_hdr, header_t, io_arg_3, FMT_HEX, base); print_field(main_hdr, header_t, rsrvd1, FMT_HEX, base); print_field(main_hdr, header_t, rsrvd2, FMT_HEX, base); print_field(main_hdr, header_t, rsrvd3, FMT_HEX, base); return sizeof(header_t); } int print_ext_hdr(ext_header_t *ext_hdr, int base) { print_field(ext_hdr, ext_header_t, type, FMT_HEX, base); print_field(ext_hdr, ext_header_t, offset, FMT_HEX, base); print_field(ext_hdr, ext_header_t, reserved, FMT_HEX, base); print_field(ext_hdr, ext_header_t, size, FMT_DEC, base); return base + sizeof(ext_header_t); } void print_sec_ext(ext_header_t *ext_hdr, int base) { sec_entry_t *sec_entry; uint32_t new_base; fprintf(stdout, "\n########### Secure extension ###########\n"); new_base = print_ext_hdr(ext_hdr, base); sec_entry = (sec_entry_t *)(ext_hdr + 1); do_print_field(0, "KAK key", new_base, MAX_RSA_DER_BYTE_LEN, FMT_NONE); new_base += MAX_RSA_DER_BYTE_LEN; print_field(sec_entry, sec_entry_t, jtag_delay, FMT_DEC, base); print_field(sec_entry, sec_entry_t, box_id, FMT_HEX, base); print_field(sec_entry, sec_entry_t, flash_id, FMT_HEX, base); print_field(sec_entry, sec_entry_t, encrypt_en, FMT_DEC, base); print_field(sec_entry, sec_entry_t, efuse_dis, FMT_DEC, base); new_base += 6 * sizeof(uint32_t); do_print_field(0, "header signature", new_base, RSA_SIGN_BYTE_LEN, FMT_NONE); new_base += RSA_SIGN_BYTE_LEN; do_print_field(0, "image signature", new_base, RSA_SIGN_BYTE_LEN, FMT_NONE); new_base += RSA_SIGN_BYTE_LEN; do_print_field(0, "CSK keys", new_base, CSK_ARR_SZ * MAX_RSA_DER_BYTE_LEN, FMT_NONE); new_base += CSK_ARR_SZ * MAX_RSA_DER_BYTE_LEN; do_print_field(0, "CSK block signature", new_base, RSA_SIGN_BYTE_LEN, FMT_NONE); new_base += RSA_SIGN_BYTE_LEN; do_print_field(0, "control", new_base, CP_CTRL_EL_ARRAY_SZ * 2, FMT_NONE); } void print_bin_ext(ext_header_t *ext_hdr, int base) { fprintf(stdout, "\n########### Binary extension ###########\n"); base = print_ext_hdr(ext_hdr, base); do_print_field(0, "binary image", base, ext_hdr->size, FMT_NONE); } int print_extension(void *buf, int base, int count, int ext_size) { ext_header_t *ext_hdr = buf; int pad = ext_size; int curr_size; while (count--) { if (ext_hdr->type == EXT_TYPE_BINARY) print_bin_ext(ext_hdr, base); else if (ext_hdr->type == EXT_TYPE_SECURITY) print_sec_ext(ext_hdr, base); curr_size = sizeof(ext_header_t) + ext_hdr->size; base += curr_size; pad -= curr_size; ext_hdr = (ext_header_t *)((uintptr_t)ext_hdr + curr_size); } if (pad) do_print_field(0, "padding", base, pad, FMT_NONE); return ext_size; } int parse_image(uint8_t *buf, int size) { int base = 0; int ret = 1; header_t *main_hdr; uint32_t checksum, prolog_checksum; fprintf(stdout, "################### Prolog Start ######################\n\n"); main_hdr = (header_t *)buf; base += print_header(buf, base); if (main_hdr->ext_count) base += print_extension(buf + base, base, main_hdr->ext_count, main_hdr->prolog_size - sizeof(header_t)); if (base < main_hdr->prolog_size) { fprintf(stdout, "\n########### Padding ##############\n"); do_print_field(0, "prolog padding", base, main_hdr->prolog_size - base, FMT_HEX); base = main_hdr->prolog_size; } fprintf(stdout, "\n################### Prolog End ######################\n"); fprintf(stdout, "\n################### Boot image ######################\n"); do_print_field(0, "boot image", base, size - base - 4, FMT_NONE); fprintf(stdout, "################### Image end ########################\n"); /* Check sanity for certain values */ printf("\nChecking values:\n"); if (main_hdr->magic == MAIN_HDR_MAGIC) { fprintf(stdout, "Headers magic: OK!\n"); } else { fprintf(stderr, "\n****** ERROR: HEADER MAGIC 0x%08x != 0x%08x\n", main_hdr->magic, MAIN_HDR_MAGIC); goto error; } /* headers checksum */ /* clear the checksum field in header to calculate checksum */ prolog_checksum = main_hdr->prolog_checksum; main_hdr->prolog_checksum = 0; checksum = checksum32((uint32_t *)buf, main_hdr->prolog_size); if (checksum == prolog_checksum) { fprintf(stdout, "Headers checksum: OK!\n"); } else { fprintf(stderr, "\n***** ERROR: BAD HEADER CHECKSUM 0x%08x != 0x%08x\n", checksum, prolog_checksum); goto error; } /* boot image checksum */ checksum = checksum32((uint32_t *)(buf + main_hdr->prolog_size), main_hdr->boot_image_size); if (checksum == main_hdr->boot_image_checksum) { fprintf(stdout, "Image checksum: OK!\n"); } else { fprintf(stderr, "\n****** ERROR: BAD IMAGE CHECKSUM 0x%08x != 0x%08x\n", checksum, main_hdr->boot_image_checksum); goto error; } #ifdef CONFIG_MVEBU_SECURE_BOOT /* RSA signatures */ if (main_hdr->ext_count) { uint8_t ext_num = main_hdr->ext_count; ext_header_t *ext_hdr = (ext_header_t *)(main_hdr + 1); unsigned char hash[32]; int i; while (ext_num--) { if (ext_hdr->type == EXT_TYPE_SECURITY) { sec_entry_t *sec_entry = (sec_entry_t *)(ext_hdr + 1); ret = verify_secure_header_signatures( main_hdr, sec_entry); if (ret != 0) { fprintf(stderr, "\n****** FAILED TO VERIFY "); fprintf(stderr, "RSA SIGNATURES ********\n"); goto error; } mbedtls_sha256(sec_entry->kak_key, MAX_RSA_DER_BYTE_LEN, hash, 0); fprintf(stdout, ">>>>>>>>>> KAK KEY HASH >>>>>>>>>>\n"); fprintf(stdout, "SHA256: "); for (i = 0; i < 32; i++) fprintf(stdout, "%02X", hash[i]); fprintf(stdout, "\n<<<<<<<<< KAK KEY HASH <<<<<<<<<\n"); break; } ext_hdr = (ext_header_t *)((uint8_t *)(ext_hdr + 1) + ext_hdr->size); } } #endif ret = 0; error: return ret; } int format_bin_ext(char *filename, FILE *out_fd) { ext_header_t header; FILE *in_fd; int size, written; int aligned_size, pad_bytes; char c; in_fd = fopen(filename, "rb"); if (in_fd == NULL) { fprintf(stderr, "failed to open bin extension file %s\n", filename); return 1; } size = get_file_size(filename); if (size <= 0) { fprintf(stderr, "bin extension file size is bad\n"); return 1; } /* Align extension size to 8 bytes */ aligned_size = (size + 7) & (~7); pad_bytes = aligned_size - size; header.type = EXT_TYPE_BINARY; header.offset = 0; header.size = aligned_size; header.reserved = 0; /* Write header */ written = fwrite(&header, sizeof(ext_header_t), 1, out_fd); if (written != 1) { fprintf(stderr, "failed writing header to extension file\n"); return 1; } /* Write image */ while (size--) { c = getc(in_fd); fputc(c, out_fd); } while (pad_bytes--) fputc(0, out_fd); fclose(in_fd); return 0; } /* **************************************** * * Write all extensions (binary, secure * extensions) to file * * ****************************************/ int format_extensions(char *ext_filename) { FILE *out_fd; int ret = 0; out_fd = fopen(ext_filename, "wb"); if (out_fd == NULL) { fprintf(stderr, "failed to open extension output file %s", ext_filename); return 1; } if (strncmp(opts.bin_ext_file, "NA", MAX_FILENAME)) { if (format_bin_ext(opts.bin_ext_file, out_fd)) { ret = 1; goto error; } } #ifdef CONFIG_MVEBU_SECURE_BOOT if (strncmp(opts.sec_cfg_file, "NA", MAX_FILENAME)) { if (format_sec_ext(opts.sec_cfg_file, out_fd)) { ret = 1; goto error; } } #endif error: fflush(out_fd); fclose(out_fd); return ret; } void update_uart(header_t *header) { header->uart_cfg = 0; header->baudrate = 0; if (opts.disable_print) uart_set_mode(header->uart_cfg, UART_MODE_DISABLE); if (opts.baudrate) header->baudrate = (opts.baudrate / 1200); } /* **************************************** * * Write the image prolog, i.e. * main header and extensions, to file * * ****************************************/ int write_prolog(int ext_cnt, char *ext_filename, uint8_t *image_buf, int image_size, FILE *out_fd) { header_t *header; int main_hdr_size = sizeof(header_t); int prolog_size = main_hdr_size; FILE *ext_fd; char *buf; int written, read; int ret = 1; if (ext_cnt) prolog_size += get_file_size(ext_filename); prolog_size = ((prolog_size + PROLOG_ALIGNMENT) & (~(PROLOG_ALIGNMENT-1))); /* Allocate a zeroed buffer to zero the padding bytes */ buf = calloc(prolog_size, 1); if (buf == NULL) { fprintf(stderr, "Error: failed allocating checksum buffer\n"); return 1; } header = (header_t *)buf; header->magic = MAIN_HDR_MAGIC; header->prolog_size = prolog_size; header->load_addr = opts.load_addr; header->exec_addr = opts.exec_addr; header->io_arg_0 = opts.nfc_io_args; header->ext_count = ext_cnt; header->aux_flags = 0; header->boot_image_size = (image_size + 3) & (~0x3); header->boot_image_checksum = checksum32((uint32_t *)image_buf, image_size); update_uart(header); /* Populate buffer with main header and extensions */ if (ext_cnt) { ext_fd = fopen(ext_filename, "rb"); if (ext_fd == NULL) { fprintf(stderr, "Error: failed to open extensions file\n"); goto error; } read = fread(&buf[main_hdr_size], get_file_size(ext_filename), 1, ext_fd); if (read != 1) { fprintf(stderr, "Error: failed to open extensions file\n"); goto error; } #ifdef CONFIG_MVEBU_SECURE_BOOT /* Secure boot mode? */ if (opts.sec_opts != 0) { ret = finalize_secure_ext(header, (uint8_t *)buf, prolog_size, image_buf, image_size); if (ret != 0) { fprintf(stderr, "Error: failed to handle "); fprintf(stderr, "secure extension!\n"); goto error; } } /* secure boot mode */ #endif } /* Update the total prolog checksum */ header->prolog_checksum = checksum32((uint32_t *)buf, prolog_size); /* Now spill everything to output file */ written = fwrite(buf, prolog_size, 1, out_fd); if (written != 1) { fprintf(stderr, "Error: failed to write prolog to output file\n"); goto error; } ret = 0; error: free(buf); return ret; } int write_boot_image(uint8_t *buf, uint32_t image_size, FILE *out_fd) { int aligned_size; int written; /* Image size must be aligned to 4 bytes */ aligned_size = (image_size + 3) & (~0x3); written = fwrite(buf, aligned_size, 1, out_fd); if (written != 1) { fprintf(stderr, "Error: Failed to write boot image\n"); goto error; } return 0; error: return 1; } int main(int argc, char *argv[]) { char in_file[MAX_FILENAME+1] = { 0 }; char out_file[MAX_FILENAME+1] = { 0 }; char ext_file[MAX_FILENAME+1] = { 0 }; FILE *in_fd = NULL; FILE *out_fd = NULL; int parse = 0; int ext_cnt = 0; int opt; int ret = 0; int image_size; uint8_t *image_buf = NULL; int read; size_t len; uint32_t nand_block_size_kb, mlc_nand; /* Create temporary file for building extensions * Use process ID for allowing multiple parallel runs */ snprintf(ext_file, MAX_FILENAME, "/tmp/ext_file-%x", getpid()); while ((opt = getopt(argc, argv, "hpms:i:l:e:a:b:u:n:t:c:k:")) != -1) { switch (opt) { case 'h': usage(); break; case 'l': opts.load_addr = strtoul(optarg, NULL, 0); break; case 'e': opts.exec_addr = strtoul(optarg, NULL, 0); break; case 'm': opts.disable_print = 1; break; case 'u': opts.baudrate = strtoul(optarg, NULL, 0); break; case 'b': strncpy(opts.bin_ext_file, optarg, MAX_FILENAME); ext_cnt++; break; case 'p': parse = 1; break; case 'n': nand_block_size_kb = strtoul(optarg, NULL, 0); opts.nfc_io_args |= (nand_block_size_kb / 64); break; case 't': mlc_nand = 0; if (!strncmp("MLC", optarg, 3)) mlc_nand = 1; opts.nfc_io_args |= (mlc_nand << 8); break; #ifdef CONFIG_MVEBU_SECURE_BOOT case 'c': /* SEC extension */ strncpy(opts.sec_cfg_file, optarg, MAX_FILENAME); ext_cnt++; break; case 'k': opts.key_index = strtoul(optarg, NULL, 0); break; #endif default: /* '?' */ usage_err("Unknown argument"); exit(EXIT_FAILURE); } } /* Check validity of inputes */ if (opts.load_addr % 8) usage_err("Load address must be 8 bytes aligned"); if (opts.baudrate % 1200) usage_err("Baudrate must be a multiple of 1200"); /* The remaining arguments are the input * and potentially output file */ /* Input file must exist so exit if not */ if (optind >= argc) usage_err("missing input file name"); len = strlen(argv[optind]); if (len > MAX_FILENAME) usage_err("file name too long"); memcpy(in_file, argv[optind], len); optind++; /* Output file must exist in non parse mode */ if (optind < argc) { len = strlen(argv[optind]); if (len > MAX_FILENAME) usage_err("file name too long"); memcpy(out_file, argv[optind], len); } else if (!parse) usage_err("missing output file name"); /* open the input file */ in_fd = fopen(in_file, "rb"); if (in_fd == NULL) { printf("Error: Failed to open input file %s\n", in_file); goto main_exit; } /* Read the input file to buffer */ image_size = get_file_size(in_file); image_buf = calloc((image_size + AES_BLOCK_SZ - 1) & ~(AES_BLOCK_SZ - 1), 1); if (image_buf == NULL) { fprintf(stderr, "Error: failed allocating input buffer\n"); return 1; } read = fread(image_buf, image_size, 1, in_fd); if (read != 1) { fprintf(stderr, "Error: failed to read input file\n"); goto main_exit; } /* Parse the input image and leave */ if (parse) { if (opts.key_index >= CSK_ARR_SZ) { fprintf(stderr, "Wrong key IDX value. Valid values 0 - %d\n", CSK_ARR_SZ - 1); goto main_exit; } ret = parse_image(image_buf, image_size); goto main_exit; } /* Create a blob file from all extensions */ if (ext_cnt) { ret = format_extensions(ext_file); if (ret) goto main_exit; } out_fd = fopen(out_file, "wb"); if (out_fd == NULL) { fprintf(stderr, "Error: Failed to open output file %s\n", out_file); goto main_exit; } ret = write_prolog(ext_cnt, ext_file, image_buf, image_size, out_fd); if (ret) goto main_exit; #ifdef CONFIG_MVEBU_SECURE_BOOT if (opts.sec_opts && (opts.sec_opts->encrypted_image != 0) && (opts.sec_opts->enc_image_sz != 0)) { ret = write_boot_image(opts.sec_opts->encrypted_image, opts.sec_opts->enc_image_sz, out_fd); } else #endif ret = write_boot_image(image_buf, image_size, out_fd); if (ret) goto main_exit; main_exit: if (in_fd) fclose(in_fd); if (out_fd) fclose(out_fd); if (image_buf) free(image_buf); unlink(ext_file); #ifdef CONFIG_MVEBU_SECURE_BOOT if (opts.sec_opts) { if (opts.sec_opts->encrypted_image) free(opts.sec_opts->encrypted_image); free(opts.sec_opts); } #endif exit(ret); } trusted-firmware-a-2.2/tools/marvell/doimage/doimage.mk000066400000000000000000000006311355360272700232560ustar00rootroot00000000000000# # Copyright (C) 2018 Marvell International Ltd. # # SPDX-License-Identifier: BSD-3-Clause # https://spdx.org/licenses DOIMAGE_FLAGS ?= -l 0x4100000 -e 0x4100000 #NAND params #Open and update the below when using NAND as a boot device. CONFIG_MVEBU_NAND_BLOCK_SIZE := 256 CONFIG_MVEBU_NAND_CELL_TYPE := SLC NAND_DOIMAGE_FLAGS := -t $(CONFIG_MVEBU_NAND_CELL_TYPE) -n $(CONFIG_MVEBU_NAND_BLOCK_SIZE) trusted-firmware-a-2.2/tools/marvell/doimage/secure/000077500000000000000000000000001355360272700226065ustar00rootroot00000000000000trusted-firmware-a-2.2/tools/marvell/doimage/secure/aes_key.txt000066400000000000000000000001011355360272700247570ustar00rootroot00000000000000ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890 trusted-firmware-a-2.2/tools/marvell/doimage/secure/csk_priv_pem0.key000066400000000000000000000032131355360272700260600ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEAm6jN6o2zQmtyUlvfkfDbSjPJ7Vlpp/KgK/eznoVBBsDIZakX cIgf8TSLpNVkc+ZE0f/n8X7mEZIyjuSBObLOm9vbkoZcR7DlKUL7RNNOUCv55Ozl hQwrzpH/uIyIJTvmek29G5wroi0wGbPoxzhelIRTjVCibleBWhYCmZQ6SIRmTY8L JT8VkX8I/Mhu62DjvxF3BnV6pXuh/FdgDN7MbldzM8Y+GOxVGi5Kcm5WHY7eyMxl 4Y0Yko31Xv7T1PcXahVBIciT+11w+fLc4wQuCJ6GUf9JbzQ0ZllY/FdRG0AhuRMH zN0jAc/sKrIFoAErED6qlcoQg0vl7gmWN5x+2wIDAQABAoIBACtnPFOkw1FH6I6y c3qcMGlWW33FKsLb0nGwFfOjsGgTpU1Dgver3UxCnJWPsvzmPlZYBvK9saVAoLxb VvUhuJ6ZBXar5FtRJfUFak7cpL+SI5IDxFP++tAUwbtR5DyNoUyFFK/4Mep8sybX lZbHTwgWhb2nuEMQP09BR+RPAplpcitkIoPkhmbGfbt9Hsd25I3bb5Z9R4S/2Rcf 7tmaxndQamij7/pUI7xtd8L6cMESJGIWrgEt/MaT2z8nNPE3EDctDSlH9yKqA2O7 /LTfrxNDnw5gGRtOgahloThKljVM6pQa4mi91FufD67pHwnKn8urNbt8/3AWg6uU x4FzZdECgYEA0k2UYzBM+dU6T1bZZ176YI0cZrP1tbf/JwnZGHicQYS7lPLAqgfO u5oRQzuDimOXaV4xCPBO2nadd6aBxbZTXaglR7GG2uCHX6w2DnOr8/d66YTErTVV u7/Bf8gMKT9mM4rWPrOEXfXfF0fvcpkBQ+QDynIB37tx/mj2lXRkLx0CgYEAvXuX Dbe2QgSK0ajrcH7YJyx3RVx9RonOqL4yjCVCELmaDQd307Ef3j+gkd59XIewm+HA mPyeWEUd8EzH+UvjckfKFuF2I4lEUUWtVZTa7me7mvsFqeEOu5KusD4+Hs+B9Kqd 3Evqcpj2lcMBI519Hvr9BTKfDBcH1EUos6A9rFcCgYAxsyPeTQvj/wBIv72hMFD7 gF2159GpoFIsZ6dmoRpMYZHzIWtmw3GX5FEwEmCD1AV0YU41TpVUC7QrEq6Yiv4o pBQrXUkBcQ6NDaW4xJ1eip4Bkd7pEDGyrR6NlDlLhjAg/i6joskla3XNirKL4pzp 7nj23vqSZToLZcLgjyEeAQKBgD5EvDo80j9VwMzvpxecB6qv+S4pG94vcWOQxYm6 wMBATjjT6HP/9EoUPM9S/32F9er0QFfGRL8bT6Blix4I62Dl6KqmQy2gcXwH2tOS DHRmUIe40H6oQDAyHwg6HC4B4WInI6N+qzgnvnku0VQD8FdbAgVQQmY1t1PxulN1 aG8XAoGAPWAr4i8KkVAx4wLlMF8E/ecKcsX1J0+UuKket7Dvk7xJfwtkSLPeV8Bp HuoHXMM3KYoZ93Hlto5rAT1VQhYuj7heU10v+9UtYTFHgaitptYmxovoCKKiZICl 48aPUI377e5jQ6RhhGYy8ltKsJ80K1T9DIkThJPSS+9NAI+jrmg= -----END RSA PRIVATE KEY----- trusted-firmware-a-2.2/tools/marvell/doimage/secure/csk_priv_pem1.key000066400000000000000000000032131355360272700260610ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEAgwHXB0AaIhT15Z9lHpQ2YT1W8i4oMvvRiLGQCrba5l7BJ03E ct0x3zagNKZEnpNndT4EAy98ihkhwVlUhxZCparJ2L3JsTs5RgV0wyQkQzwMLM8g QI5EMmJCgFAVRHmVICOsisGGfNVUHjGdGwPOipyQCsX2MAm3E139VpB7NYj+Q4IR 4kvcb+59LZxKuRJTFKRDIqMGJu98P/ga70+YLXPCBPKSfnZnUppuaI86jF1E6xt8 o7YtfEPCHDd2LXxKPZ670OapVqwo0t7ZSzEG63NkLp56FXc1OpfC69C8VPiZ8JqW wxvS/vL8MMCxsBnjSuqnmOAbcNR2GFtUwJOGwwIDAQABAoIBAFcfoiDwQHDp/531 ownzBzcj0+67Q4Ckd3SwoVp+wJTz7wB0d3DsKX6IlYJuELRk0yjlVUXJDsnIbOpo vg4Yf7otGo9JqBh1imFGv6AHKRaNmIs0M/66nh/juNYcbAhd0w7MqrKcgRQDyy1J UXHl1jXYaPLBNDg+PcJjf1dSPp4axzmW2Pk2rXnJCsPcZXL/0YmEvqhfOze0GdjR hOkbbr6MPPVM66tA00xSwg9XEYJvHtwH6oB0rnANM8ieNK1mtcWkTU5di17CCrjS ohIhXQrdVpxt549EJoUqEFSgo8OOMm2npDbFrjlukb5euakvMacwoT1te79blSKf hrTvjgECgYEA0VqoFL0Vqe1qleikYDJ7S5xcv1oruEV31TeuBhDuf0c4PADCnBrV /RnCEYuXs6wCk60chHg5s0jxg+nGbiY6jRTHkJLRU3ZhDtrtfidEZ78GRzFF3shl Uzt7dHkKK1ZdiMH4sWzyRLom91TKWMrNKC1AD7v4/zjEXy6phall3ZcCgYEAoDJa 0dIKvVCS6dM2E2kMqi/45mJqsJzFvYL1s4mbma/BAC47bBju/YEse90x+iIi3Gg/ NoXmNfGPrtgdl+/J/Y6Pohxf/e7gGN71tYVETzgc2Jv09wqmzmTjCmo3wyepyWf+ pIAE39kdhwnqXVw5xwOG1N3xrQ9TomOO+1QiXbUCgYAF84TJqiJehUA9aLKbhXPZ z2UXj3GkuFzSs9V/mKWe+qBPnFnr5BtnKX9JzmUOl3ovRoGEBoLlZNJwxIl+ghmx /wA5TOMkcz4JFRIhPu6D4HtGNNFepuWyewNkaThvyPG5vIHcUVOFvqDy8PcblRBF 7xteFyLZ5nw2lHX/NbSOmwKBgFxLZqPIPcPArkPlGhyow1Ex/lbNkOZcDFkZIHHl 8C3lYm62NCodW2PWjkh2shqInEkcDn9dObsOh1eWz8X/swJQplQhwPROMfJiUnHY a/iwPX5WrBXAn0X+Pgh8FdBsA5g0QDOKRkSplCd/APX08pzEXWQ60siAMhE3BuOq H3qZAoGAVnzFidlXuyn+fbNaNVepK9hbuoxHHbzYYWSkpi+73EchN8kXktC+AdEf owr9TPILbwWWJyisa3wW4xdbMifCgVLTedWZpZ09BENVqC+7g7ksX0pNMGYuFLOh Td7mFAgmclxG5UiKexajOLjjdnAsJyrDaNKhHn8NQNN6L93N0sE= -----END RSA PRIVATE KEY----- trusted-firmware-a-2.2/tools/marvell/doimage/secure/csk_priv_pem2.key000066400000000000000000000032131355360272700260620ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEogIBAAKCAQEAjxTSTh57/5njUpE200+Qb3ySAn8lKeufgaa0K2Xc6Ri7lDZR ZJ2BPuQZV4lYGqgWUf0IOzNf2WnE2lPfVnLMx08h7NhBqJ83yJVajpr+itnOmW+r M7h76TFyuna1xz2kw1uhgI5Y4FRnJ4Cg4AexCSyViXSzEN/7LQwxa5z5WGDiNX5N 3/tgjGu+dzSMOiIQhXwIcK/XaiQNm3WHqqnAhPb5Q9IBuuqBfpZoFfH4XmbFWrC8 neSMMMxX5Ti9pKhLd1EsiaP0aUNQlF8gNWuC/tNaf+OCtwVelVa3sGSRjRFe06VQ sAE9oyXKri11yD5Dwp1xXivbpOrf7xjUe5gILwIDAQABAoIBABTr94CCxqDucKYP I9QsSzNyJKuGyfliQdWkea3q3C2ddzhJ5QbwXQjEM8xwAdkMAQ+GD2EQtxBEfgtq vjqW2MjAEnbefGNavL5w0GgP0+6bwLEA+ii67iuAFoWbfCMhKWmDiY8RwX8z+E13 ao63sTRlN4x86v4pskG5CbTxpCg+8m7KklLns4SwRGf5gGQcgKRtNSR5nE4g2UNl dghbDdNlvUncm4zxUcTh0kquhF5Tef5w+6L7W8Hv9Pky3b1c2OK1BMhJlxYrtt69 /zhIJs89CLx5ACfam+DT/xs0uUiuRQq/e1CCQLCnUO02JqpeN/schtDCd0ZWhbtB nT7fwTECgYEAx+COhys+7AZI0U+PeuTkI86GUsWHoBislXThxbxyGvMFjgyADZD+ q/XEGAcxd4eTA1fr0Q9cLuuHZubjGQ7+OIXMZ6arXUsrmMrjRu3kHO+y6K6r4s8j 5bxN/iQ0bymUtJRfJSLI172plszusiPWhCL5+yhYlNoh4mNZJuJnzXkCgYEAt0Gz 07P19YPsxk5ow7ZnSNOMOkkEPP0SuHHWekMIK9KMjiRUSygOAk07zTL7MUoFn9Gy Prfi0ybFArNhIa4Xio3Fbjfig7rGgaApK4Y3d9A/CGPv/Nj7C2OTepqlEzRLmU9e Xw5yhbccCydXLyAYFAET2XHsmbewpvHyeYUSoOcCgYBRMJEUrOdhPmhDxZqVo/Zb 6R887gnaaUtpZlHzXUnIUqEWA1PcruIT/b/KttlMIWEBQayDfkbGtFuK3AyxeBqh 4Q+XpucC/W7XIMrTW/yGGIPG6nTdq6B8SFIyAojeArjp5T8Eua11nRAPNm1bJR2V DRQYBlp9FGIhMJPdLKhXmQKBgGeywSyR0COfBHPu2K+u3uFB/D7bJI/ScS54FHLY zZ3mpeylOCHTR6IbzDRAng31Ihue0KtW6P6tGJx/nv4tAltAADFvZDlAjqW5WLKt X2PoLlL0IlBFBEIclc6yBalJVWIqnG9TwJBT3oWdPGOJWLaxKWdJZSZS4J6HmLsV B0aPAoGAduLsOt8C5z48jPqmJxyPwsmT0Q424FccPMcvGOJ13yxq3xNsfAsbmg9l L2i/ktE0wCMA+Pm7cuFgxwD7xTr67POZgt9022KsOSonjPsIn24UQeP46vAX/Qtx Qf3sfvzf57vNy2Hybe38T8RsVOZla+v/QctfSfmb8Y95XL/SZzA= -----END RSA PRIVATE KEY----- trusted-firmware-a-2.2/tools/marvell/doimage/secure/csk_priv_pem3.key000066400000000000000000000032131355360272700260630ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAlA/T/5IMTPTu+k5PeesB2oeP80Y6nq0ls8vXLul0TVEJoJ+O InbPYNqYPu4dbQQg/u8qp8BeXm2ujtJbBTcdn0jKIiDTKYEnlsGfUt9GHnuuzvFh rORSKuAolUqvo/zcSCo1uykaFvSuyTovSPlwllzSixD9XBbHfn3kXneiIUa45vsJ AyjTn2qCJt0WgvX42NTxH6Q/OWLeOuKTyRHf25eabucIv77KYy0mlEPq5jjiV5AJ gl5F1h5G8n07JCIWjkZ2QV4wr+Hv9uGNaSb0WGppBp4CbdQa0eUI75cKzz4WXqds HZaYiX/a8YC+EUfvqDD02vKREIKFL/1zL53P/wIDAQABAoIBAGzBj5w7oBNrGpr7 qL9KEyt8xg0Q+gAR+Q6vXRlVXBtquiKk8Jd6I+vlxUz8RNsN3FrGPNPJpse/0yeP dlJHYNfedLNK3zCucPD4uln6LRw5B3d0sKV5dK2Px9+ZY5iWJQxRDPS0RTi1dCnV NmRo7P1Vo0WJLkFVbiYIvRVy1MGRfF9ejN41G6U4MoBAQ9WqLp+JasUMTspZI49a z8tOiJPT94MHBwbKnz8Mcq8sy02LR7U5h82+0T7JoRVix/OXiOoiQExNjZ9yGar0 wBnl0SL1UW5UUaYzbyNH0mlMXLD+qowbDZM2pBWPfqXK+CMOsL6STIwnns7lY+ZJ ILbaVmECgYEA2kQXE1PZ25A87a81wCEld402WJ2KegrZC719EWv+xeoS72Ji8uv7 V0PxVGJQOcG1N+dzJ5tN59SQ/NvVTrjwqNUxQqsygmWq/TcfGb9ONZRmyzcehYLb m4xTjqJKQ6Kwm5SoaCYmzEb/xaeLwLS9HmR9MdB1dxtDOLpjaK/8qPECgYEArait QhgaknlxG8pcAimPsEUrLHYWSFRE/MUk4+YvZg/5+YJ8csvY0SO2h0tF/ARwUrdI DaLEifHm4vqgN03K/0gqj7TKxcNlV16PvVx7Vz97xejdqdHZLDfAo4lcotsgvFQW zIqoQGGPLf6WhFixZ8mEYj8xnmzLGPvHQmf1h+8CgYEA0LDl917nIN4qw4ARPqDy t/pXCienrcUNfgIxwSSnNwj2DdjejzI+4VNfPbW6y16BLPCp1CbUOGOwNXTj4R9H S8Z8ESirZK5c7Tt1CyM1XlmEZ61OC43w+CsWAXz+0OiPQFLFKr+/vPXtvEjUgO7P HG4sniKZDccNYQIl5oTOaaECgYAPU4u3AZmWw9EPutRT/IcJ75DX47Qjvgw4os2W r4IPZ+mP88w39XW1P4mkdyg+DcY8BqD9Uxg1dHwEHEp3lw4LabsX48Thn1UaWOYm uDrKgHfUB7FIg5S/Kkx+ImliliRVerZoZvRiejnAvW9bTtiZaFeetCUU7lUeZ1o2 qiYpUQKBgHQDfdDhguBGPKpkJ7pVwHkJA/lyRWaN1hwplw4TvX2oH14NsHg5Q5Fd lHqHFs2Ry/6X3bKgF0E6q4cx0V1Xnnj9sGsemlrHdiSxplDYRQql7X5OeYPGF/Bg ZTTG8rDwy+ey6EP9BZUb03hISx/LyMynOzjGl6uOcdAcy2d9Vno0 -----END RSA PRIVATE KEY----- trusted-firmware-a-2.2/tools/marvell/doimage/secure/kak_priv_pem.key000066400000000000000000000032131355360272700257660ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAsj2cHcrE2pdyCqNr+oVcQULiRx6RivkrhLl2DTqWXpP33BPm MP0W0X0z98X7E3kZO+JIGRZ8q+6AWmUpL+53aOGItNeUgT7jQKViPJIo9ZcEnv/n PJqdgDd4xFhnwYMgq8uVYN9IPfaKDwB3EoOqjNox2JholUVxvLw6W8DAC8La3zwb 0hiqtIlirQOQ/KaTHxC6dPYkrai+jSK5uAX7Vt8RKYg5qfDxSdZckmC2xVKYURhV bZAlyKki4h6f8CwYCJMQDpHL6mVYCuJ1Ju/OJEXvthDKD0CD2hwILhksdey3qMOC I5lHSO1b+sTvnVHGs65wI7A+ZYwnadMNvS9e2QIDAQABAoIBAH2uu9q2FEEe8SdX PNiWGQtbojsL7wzTzj/0lq2VVlqyc+AXmAWLMP/fDTn1vKlqhsSXNseZ96c0sgUL uBM4T7MA9WivauQH+C6pb6/OUFt8daG4SNGPJOg4NUweGmt1jyAUmeyJBWPL6GXT qiK//Q78/JECRxyaryyqfWwdak3flzfwONBJ03tQ9EO+L7hf9gAP7OYnAsuNp+Bz tj1xzNMumYYYiHvsEXx8UTe8HGrmYuO53ZY5fBLGB6Jj7hRlAHNfcdVDvvoBU5cI Zwi+5YsBuSP2Hr9Gt2Odu+KitH3gFdS0HIiDh44AT+Trj29NMANFDfkDbVHUmE0q YBL75NECgYEA2E+fJzdaYyyPIcvQgVM8g52hltR5IRgJICND3NOdB/Zb2teBGZh+ 1XJ6ZqQMDcOQZo0CMbX9UNRnf3NU55k48/EEITxCgUJTx/WdfJeTVlWGspt5+U/r hDnQmkePdU1en63+u9eqsla9+VhLwU3fl/pIOpsBAnoEzs3hMQZ1G0cCgYEA0vHH ilm3AztIoZlH3wgDAl2Gu5/YopqEofKA8G4Jp89rlkk919P/GNjEc6575wjgztDB 0Xab+H7Nqxjs3HqQX/DTTuAxzAggBg3j/ijpHnmjrCHLeMT5ciyH+EH5Bg///cLq +Cwn7aOWuSK1hGdDYxUycHylAYZXXFJzmEIEhN8CgYEA1qTrwPZkctTckyS0GiCG g/P/TLQ6HmTDaWiVBqPVxvjn3RjLuqJf+V5Hp2JRs7bDq39xFfMJExQyP34qWkbp BOe8uV4agDlY+ar4Q5IFWj40EzfEqWhsxCC6pt0rtbK4mqsFg1BWyfDZQnwjcAXe QejRk5YMQnDiJHSXaRaHTjECgYAv6ecvD624ODEJM63VhRZZ5TCDUY19caeKuXB8 LCJZUY3Ydw5rBaY92I7Wz90o3yVhFJ3RnCVVTkgdAu5aLiS5BhSZJ+dntri/Z0xQ IK7C01JP+OUkq2kVe/Pued28eMnms+13LWBsY+oKZ03foyz1Ro1Ma6N3MzKIr9m9 zdEE9QKBgECfoh0xE2T/cbJrtH0mwMCUM6eMVGq+yQBKNvuuPg6kaQUsah1n1rp6 OyvjwRAXdhshszEzNTX1WTT6/i+vZX277Ax50pPo9UhQ9kVteVt1frN6+u5sy07V fg1f2+m0iFx4BD/irU0fzSyfGE+QkBnmXFBUNSYjp2PSqYIdufmW -----END RSA PRIVATE KEY----- trusted-firmware-a-2.2/tools/marvell/doimage/secure/sec_img_7K.cfg000066400000000000000000000020161355360272700252350ustar00rootroot00000000000000# Trusted boot image extension definitions kak_key_file = "tools/doimage/secure/kak_priv_pem.key"; # CSK keys array - 16 entries total. # Only a key with csk_key_index will be used for signing the image # use "*" string instead of file name for specifying an empty key csk_key_file = ["tools/doimage/secure/csk_priv_pem0.key", "tools/doimage/secure/csk_priv_pem1.key", "tools/doimage/secure/csk_priv_pem2.key", "tools/doimage/secure/csk_priv_pem3.key", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*"]; # index of CSK key in the array. Valid range is 0 to 15 csk_key_index = 3; # AES-256 symmetric key for image encryption aes_key_file = "tools/doimage/secure/aes_key.txt"; efuse_disable = false; jtag = { enable = true; delay = 20; }; box_id = 0xdeadbeef; flash_id = 0xbaddf00d; # SecureBootControl and EfuseBurnControl registers array # Two register addresses for each connected CP # A7K - one CP, two register values control = [0xF2441920, 0xF2441940]; trusted-firmware-a-2.2/tools/marvell/doimage/secure/sec_img_8K.cfg000066400000000000000000000020471355360272700252420ustar00rootroot00000000000000# Trusted boot image extension definitions kak_key_file = "tools/doimage/secure/kak_priv_pem.key"; # CSK keys array - 16 entries total. # Only a key with csk_key_index will be used for signing the image # use "*" string instead of file name for specifying an empty key csk_key_file = ["tools/doimage/secure/csk_priv_pem0.key", "tools/doimage/secure/csk_priv_pem1.key", "tools/doimage/secure/csk_priv_pem2.key", "tools/doimage/secure/csk_priv_pem3.key", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*", "*"]; # index of CSK key in the array. Valid range is 0 to 15 csk_key_index = 3; # AES-256 symmetric key for image encryption aes_key_file = "tools/doimage/secure/aes_key.txt"; efuse_disable = false; jtag = { enable = true; delay = 20; }; box_id = 0xdeadbeef; flash_id = 0xbaddf00d; # SecureBootControl and EfuseBurnControl registers array # Two register addresses for each connected CP # A8K - two CP, four register values control = [0xF2441920, 0xF2441940, 0xF4441920, 0xF4441940]; trusted-firmware-a-2.2/tools/renesas/000077500000000000000000000000001355360272700177115ustar00rootroot00000000000000trusted-firmware-a-2.2/tools/renesas/rcar_layout_create/000077500000000000000000000000001355360272700235605ustar00rootroot00000000000000trusted-firmware-a-2.2/tools/renesas/rcar_layout_create/makefile000066400000000000000000000056311355360272700252650ustar00rootroot00000000000000# # Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # ################################################### # makefile ################################################### #output file name FILE_NAME_SA0 = bootparam_sa0 FILE_NAME_SA6 = cert_header_sa6 OUTPUT_FILE_SA0 = $(FILE_NAME_SA0).elf OUTPUT_FILE_SA6 = $(FILE_NAME_SA6).elf #object file name OBJ_FILE_SA0 = sa0.o OBJ_FILE_SA6 = sa6.o #linker script name MEMORY_DEF_SA0 = sa0.ld.S MEMORY_DEF_SA6 = sa6.ld.S ################################################### # Convenience function for adding build definitions # $(eval $(call add_define,FOO)) will have: # -DFOO if $(FOO) is empty; -DFOO=$(FOO) otherwise define add_define DEFINES += -D$(1)$(if $(value $(1)),=$(value $(1)),) endef # Process RCAR_SA0_SIZE flag ifndef RCAR_SA0_SIZE RCAR_SA0_SIZE := 1 else ifeq (${RCAR_SA0_SIZE},0) RCAR_SA0_SIZE := 0 else RCAR_SA0_SIZE := 1 endif endif $(eval $(call add_define,RCAR_SA0_SIZE)) # Process RCAR_SA6_TYPE flag ifndef RCAR_SA6_TYPE RCAR_SA6_TYPE := 0 else ifeq (${RCAR_SA6_TYPE},0) RCAR_SA6_TYPE := 0 else RCAR_SA6_TYPE := 1 endif endif $(eval $(call add_define,RCAR_SA6_TYPE)) # Handle different VMA adjustment on D3 ifeq (${RCAR_LSI},${RCAR_D3}) RCAR_VMA_ADJUST_ADDR := 0xE6320000 else RCAR_VMA_ADJUST_ADDR := 0xE6312000 endif $(eval $(call add_define,RCAR_VMA_ADJUST_ADDR)) ################################################### #c compiler CC = $(CROSS_COMPILE)gcc CFLAGS += ${DEFINES} CFLAGS += -I../../include/lib/stdlib #Linker LD = $(CROSS_COMPILE)ld #objcopy objcopy = $(CROSS_COMPILE)objcopy #clean CL = rm -f ################################################### .SUFFIXES : .s .c .o ################################################### # command .PHONY: all all: $(OUTPUT_FILE_SA0) $(OUTPUT_FILE_SA6) ################################################### # Linker ################################################### $(OUTPUT_FILE_SA0) : $(MEMORY_DEF_SA0) $(OBJ_FILE_SA0) $(LD) $(OBJ_FILE_SA0) \ -T $(MEMORY_DEF_SA0) \ -o $(OUTPUT_FILE_SA0) \ -Map $(FILE_NAME_SA0).map \ $(objcopy) -O srec --adjust-vma=$(RCAR_VMA_ADJUST_ADDR) --srec-forceS3 $(OUTPUT_FILE_SA0) $(FILE_NAME_SA0).srec $(objcopy) -O binary --adjust-vma=$(RCAR_VMA_ADJUST_ADDR) --srec-forceS3 $(OUTPUT_FILE_SA0) $(FILE_NAME_SA0).bin $(OUTPUT_FILE_SA6) : $(MEMORY_DEF_SA6) $(OBJ_FILE_SA6) $(LD) $(OBJ_FILE_SA6) \ -T $(MEMORY_DEF_SA6) \ -o $(OUTPUT_FILE_SA6) \ -Map $(FILE_NAME_SA6).map \ $(objcopy) -O srec --adjust-vma=$(RCAR_VMA_ADJUST_ADDR) --srec-forceS3 $(OUTPUT_FILE_SA6) $(FILE_NAME_SA6).srec $(objcopy) -O binary --adjust-vma=$(RCAR_VMA_ADJUST_ADDR) --srec-forceS3 $(OUTPUT_FILE_SA6) $(FILE_NAME_SA6).bin ################################################### # Compile ################################################### %.o:../%.c $(CC) -c -I $< -o $@ .PHONY: clean clean: $(CL) *.bin *.map *.srec *.elf *.o trusted-firmware-a-2.2/tools/renesas/rcar_layout_create/sa0.c000066400000000000000000000023231355360272700244070ustar00rootroot00000000000000/* * Copyright (c) 2015-2018, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #define RCAR_SA0_SIZE_SMALL (0) /* for E3/D3 */ #define RCAR_SA0_SIZE_NORMAL (1) /* for H3/M3/M3N */ #define BL2_ADDRESS (0xE6304000) /* BL2 start address */ #if (RCAR_SA0_SIZE == RCAR_SA0_SIZE_SMALL) #define BL2_SIZE (80*1024/4) /* BL2 size is 80KB(0x00005000) */ #else /* (RCAR_SA0_SIZE == RCAR_SA0_SIZE_SMALL) */ #define BL2_SIZE (170*1024/4) /* BL2 size is 170KB(0x0000AA00) */ #endif /* (RCAR_SA0_SIZE == RCAR_SA0_SIZE_SMALL) */ /* SA0 */ /* 0x00000000 */ const unsigned int __attribute__ ((section (".sa0_bootrom"))) bootrom_paramA = 0x00000100; /* 0x00000080 (Map Type 3 for eMMC Boot)*/ /* 0x000001D4 */ const unsigned int __attribute__ ((section (".sa0_bl2dst_addr3"))) bl2dst_addr3 = BL2_ADDRESS; /* 0x000002E4 */ const unsigned int __attribute__ ((section (".sa0_bl2dst_size3"))) bl2dst_size3 = BL2_SIZE; /* 0x00000C00 (Map Type 1 for HyperFlash/QSPI Flash Boot)*/ /* 0x00000D54 */ const unsigned int __attribute__ ((section (".sa0_bl2dst_addr1"))) bl2dst_addr1 = BL2_ADDRESS; /* 0x00000E64 */ const unsigned int __attribute__ ((section (".sa0_bl2dst_size1"))) bl2dst_size1 = BL2_SIZE; trusted-firmware-a-2.2/tools/renesas/rcar_layout_create/sa0.ld.S000066400000000000000000000014421355360272700247660ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ SECTIONS { . = 0x00000000; .rodata : { KEEP(*(.sa0_bootrom)) /* Map Type 3 for eMMC Boot */ /* A-side IPL content cert "Start Address" */ . = 0x000001D4; /* H'00000080 + H'00000154 */ KEEP(*(.sa0_bl2dst_addr3)) /* A-side IPL content cert "Size" */ . = 0x000002E4; /* H'00000080 + H'00000264 */ KEEP(*(.sa0_bl2dst_size3)) /* Map Type 1 for HyperFlash/QSPI Flash Boot */ /* A-side IPL content cert "Start Address" */ . = 0x00000D54; /* H'00000C00 + H'00000154 */ KEEP(*(.sa0_bl2dst_addr1)) /* A-side IPL content cert "Size" */ . = 0x00000E64; /* H'00000C00 + H'00000264 */ KEEP(*(.sa0_bl2dst_size1)) } } trusted-firmware-a-2.2/tools/renesas/rcar_layout_create/sa6.c000066400000000000000000000231061355360272700244170ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #define RCAR_SA6_TYPE_HYPERFLASH (0) #define RCAR_SA6_TYPE_EMMC (1) #if (RCAR_SA6_TYPE == RCAR_SA6_TYPE_HYPERFLASH) /* Number of content cert for Non-secure Target Program(BL33x) */ #define RCAR_IMAGE_NUM (0x00000001U) /* Source address on flash for BL31 */ #define RCAR_BL31SRC_ADDRESS (0x001C0000U) /* Reserved */ #define RCAR_BL31_PARTITION (0x00000000U) /* Source address on flash for BL32 */ #define RCAR_BL32SRC_ADDRESS (0x00200000U) /* Reserved */ #define RCAR_BL32_PARTITION (0x00000000U) /* Source address on flash for BL33 */ #define RCAR_BL33SRC_ADDRESS (0x00640000U) /* Reserved */ #define RCAR_BL33_PARTITION (0x00000000U) #define RCAR_BL332SRC_ADDRESS (0x00000000U) /* Reserved */ #define RCAR_BL332_PARTITION (0x00000000U) #define RCAR_BL333SRC_ADDRESS (0x00000000U) /* Reserved */ #define RCAR_BL333_PARTITION (0x00000000U) #define RCAR_BL334SRC_ADDRESS (0x00000000U) /* Reserved */ #define RCAR_BL334_PARTITION (0x00000000U) #define RCAR_BL335SRC_ADDRESS (0x00000000U) /* Reserved */ #define RCAR_BL335_PARTITION (0x00000000U) #define RCAR_BL336SRC_ADDRESS (0x00000000U) /* Reserved */ #define RCAR_BL336_PARTITION (0x00000000U) #define RCAR_BL337SRC_ADDRESS (0x00000000U) /* Reserved */ #define RCAR_BL337_PARTITION (0x00000000U) #define RCAR_BL338SRC_ADDRESS (0x00000000U) /* Reserved */ #define RCAR_BL338_PARTITION (0x00000000U) #else /* RCAR_SA6_TYPE == RCAR_SA6_TYPE_HYPERFLASH */ /* Number of content cert for Non-secure Target Program(BL33x) */ #define RCAR_IMAGE_NUM (0x00000001U) /* Source address on eMMC for BL31 */ #define RCAR_BL31SRC_ADDRESS (0x00040000U) /* Source partition on eMMC for BL31 */ #define RCAR_BL31_PARTITION (0x00000001U) /* Source address on eMMC for BL32 */ #define RCAR_BL32SRC_ADDRESS (0x00200000U) /* Source partition on eMMC for BL32 */ #define RCAR_BL32_PARTITION (0x00000001U) /* Source address on eMMC for BL33 */ #define RCAR_BL33SRC_ADDRESS (0x00000000U) /* Source partition on eMMC for BL33 */ #define RCAR_BL33_PARTITION (0x00000002U) /* Reserved */ #define RCAR_BL332SRC_ADDRESS (0x00000000U) #define RCAR_BL332_PARTITION (0x00000000U) /* Reserved */ #define RCAR_BL333SRC_ADDRESS (0x00000000U) #define RCAR_BL333_PARTITION (0x00000000U) /* Reserved */ #define RCAR_BL334SRC_ADDRESS (0x00000000U) #define RCAR_BL334_PARTITION (0x00000000U) /* Reserved */ #define RCAR_BL335SRC_ADDRESS (0x00000000U) #define RCAR_BL335_PARTITION (0x00000000U) /* Reserved */ #define RCAR_BL336SRC_ADDRESS (0x00000000U) #define RCAR_BL336_PARTITION (0x00000000U) /* Reserved */ #define RCAR_BL337SRC_ADDRESS (0x00000000U) #define RCAR_BL337_PARTITION (0x00000000U) /* Reserved */ #define RCAR_BL338SRC_ADDRESS (0x00000000U) #define RCAR_BL338_PARTITION (0x00000000U) #endif /* RCAR_SA6_TYPE == RCAR_SA6_TYPE_HYPERFLASH */ /* Destination address for BL31 */ #define RCAR_BL31DST_ADDRESS (0x44000000U) #define RCAR_BL31DST_ADDRESSH (0x00000000U) /* Destination size for BL31 */ #define RCAR_BL31DST_SIZE (0x00004000U) /* Destination address for BL32 */ #define RCAR_BL32DST_ADDRESS (0x44100000U) #define RCAR_BL32DST_ADDRESSH (0x00000000U) /* Destination size for BL32 */ #define RCAR_BL32DST_SIZE (0x00040000U) /* Destination address for BL33 */ #define RCAR_BL33DST_ADDRESS (0x50000000U) #define RCAR_BL33DST_ADDRESSH (0x00000000U) /* Destination size for BL33 */ #define RCAR_BL33DST_SIZE (0x00040000U) /* Reserved */ #define RCAR_BL332DST_ADDRESS (0x00000000U) #define RCAR_BL332DST_ADDRESSH (0x00000000U) #define RCAR_BL332DST_SIZE (0x00000000U) /* Reserved */ #define RCAR_BL333DST_ADDRESS (0x00000000U) #define RCAR_BL333DST_ADDRESSH (0x00000000U) #define RCAR_BL333DST_SIZE (0x00000000U) /* Reserved */ #define RCAR_BL334DST_ADDRESS (0x00000000U) #define RCAR_BL334DST_ADDRESSH (0x00000000U) #define RCAR_BL334DST_SIZE (0x00000000U) /* Reserved */ #define RCAR_BL335DST_ADDRESS (0x00000000U) #define RCAR_BL335DST_ADDRESSH (0x00000000U) #define RCAR_BL335DST_SIZE (0x00000000U) /* Reserved */ #define RCAR_BL336DST_ADDRESS (0x00000000U) #define RCAR_BL336DST_ADDRESSH (0x00000000U) #define RCAR_BL336DST_SIZE (0x00000000U) /* Reserved */ #define RCAR_BL337DST_ADDRESS (0x00000000U) #define RCAR_BL337DST_ADDRESSH (0x00000000U) #define RCAR_BL337DST_SIZE (0x00000000U) /* Reserved */ #define RCAR_BL338DST_ADDRESS (0x00000000U) #define RCAR_BL338DST_ADDRESSH (0x00000000U) #define RCAR_BL338DST_SIZE (0x00000000U) /* SA6 */ const uint64_t __attribute__ ((section (".sa6_image_num"))) image_num = RCAR_IMAGE_NUM; const uint64_t __attribute__ ((section (".sa6_bl31src_addr"))) bl31src_addr = RCAR_BL31SRC_ADDRESS; const uint64_t __attribute__ ((section (".sa6_bl31partition"))) bl31partition = RCAR_BL31_PARTITION; const uint64_t __attribute__ ((section (".sa6_bl32src_addr"))) bl32src_addr = RCAR_BL32SRC_ADDRESS; const uint64_t __attribute__ ((section (".sa6_bl32partition"))) bl32partition = RCAR_BL32_PARTITION; const uint64_t __attribute__ ((section (".sa6_bl33src_addr"))) bl33src_addr = RCAR_BL33SRC_ADDRESS; const uint64_t __attribute__ ((section (".sa6_bl33partition"))) bl33partition = RCAR_BL33_PARTITION; const uint64_t __attribute__ ((section (".sa6_bl332src_addr"))) bl332src_addr = RCAR_BL332SRC_ADDRESS; const uint64_t __attribute__ ((section (".sa6_bl332partition")))bl332partition = RCAR_BL332_PARTITION; const uint64_t __attribute__ ((section (".sa6_bl333src_addr"))) bl333src_addr = RCAR_BL333SRC_ADDRESS; const uint64_t __attribute__ ((section (".sa6_bl333partition")))bl333partition = RCAR_BL333_PARTITION; const uint64_t __attribute__ ((section (".sa6_bl334src_addr"))) bl334src_addr = RCAR_BL334SRC_ADDRESS; const uint64_t __attribute__ ((section (".sa6_bl334partition")))bl334partition = RCAR_BL334_PARTITION; const uint64_t __attribute__ ((section (".sa6_bl335src_addr"))) bl335src_addr = RCAR_BL335SRC_ADDRESS; const uint64_t __attribute__ ((section (".sa6_bl335partition")))bl335partition = RCAR_BL335_PARTITION; const uint64_t __attribute__ ((section (".sa6_bl336src_addr"))) bl336src_addr = RCAR_BL336SRC_ADDRESS; const uint64_t __attribute__ ((section (".sa6_bl336partition")))bl336partition = RCAR_BL336_PARTITION; const uint64_t __attribute__ ((section (".sa6_bl337src_addr"))) bl337src_addr = RCAR_BL337SRC_ADDRESS; const uint64_t __attribute__ ((section (".sa6_bl337partition")))bl337partition = RCAR_BL337_PARTITION; const uint64_t __attribute__ ((section (".sa6_bl338src_addr"))) bl338src_addr = RCAR_BL338SRC_ADDRESS; const uint64_t __attribute__ ((section (".sa6_bl338partition")))bl338partition = RCAR_BL338_PARTITION; const uint32_t __attribute__ ((section (".sa6_bl31dst_addr"))) bl31dst_addr = RCAR_BL31DST_ADDRESS; const uint32_t __attribute__ ((section (".sa6_bl31dst_addrh"))) bl31dst_addrh = RCAR_BL31DST_ADDRESSH; const uint32_t __attribute__ ((section (".sa6_bl31dst_size"))) bl31dst_size = RCAR_BL31DST_SIZE; const uint32_t __attribute__ ((section (".sa6_bl32dst_addr"))) bl32dst_addr = RCAR_BL32DST_ADDRESS; const uint32_t __attribute__ ((section (".sa6_bl32dst_addrh"))) bl32dst_addrh = RCAR_BL32DST_ADDRESSH; const uint32_t __attribute__ ((section (".sa6_bl32dst_size"))) bl32dst_size = RCAR_BL32DST_SIZE; const uint32_t __attribute__ ((section (".sa6_bl33dst_addr"))) bl33dst_addr = RCAR_BL33DST_ADDRESS; const uint32_t __attribute__ ((section (".sa6_bl33dst_addrh"))) bl33dst_addrh = RCAR_BL33DST_ADDRESSH; const uint32_t __attribute__ ((section (".sa6_bl33dst_size"))) bl33dst_size = RCAR_BL33DST_SIZE; const uint32_t __attribute__ ((section (".sa6_bl332dst_addr"))) bl332dst_addr = RCAR_BL332DST_ADDRESS; const uint32_t __attribute__ ((section (".sa6_bl332dst_addrh")))bl332dst_addrh = RCAR_BL332DST_ADDRESSH; const uint32_t __attribute__ ((section (".sa6_bl332dst_size"))) bl332dst_size = RCAR_BL332DST_SIZE; const uint32_t __attribute__ ((section (".sa6_bl333dst_addr"))) bl333dst_addr = RCAR_BL333DST_ADDRESS; const uint32_t __attribute__ ((section (".sa6_bl333dst_addrh")))bl333dst_addrh = RCAR_BL333DST_ADDRESSH; const uint32_t __attribute__ ((section (".sa6_bl333dst_size"))) bl333dst_size = RCAR_BL333DST_SIZE; const uint32_t __attribute__ ((section (".sa6_bl334dst_addr"))) bl334dst_addr = RCAR_BL334DST_ADDRESS; const uint32_t __attribute__ ((section (".sa6_bl334dst_addrh")))bl334dst_addrh = RCAR_BL334DST_ADDRESSH; const uint32_t __attribute__ ((section (".sa6_bl334dst_size"))) bl334dst_size = RCAR_BL334DST_SIZE; const uint32_t __attribute__ ((section (".sa6_bl335dst_addr"))) bl335dst_addr = RCAR_BL335DST_ADDRESS; const uint32_t __attribute__ ((section (".sa6_bl335dst_addrh")))bl335dst_addrh = RCAR_BL335DST_ADDRESSH; const uint32_t __attribute__ ((section (".sa6_bl335dst_size"))) bl335dst_size = RCAR_BL335DST_SIZE; const uint32_t __attribute__ ((section (".sa6_bl336dst_addr"))) bl336dst_addr = RCAR_BL336DST_ADDRESS; const uint32_t __attribute__ ((section (".sa6_bl336dst_addrh")))bl336dst_addrh = RCAR_BL336DST_ADDRESSH; const uint32_t __attribute__ ((section (".sa6_bl336dst_size"))) bl336dst_size = RCAR_BL336DST_SIZE; const uint32_t __attribute__ ((section (".sa6_bl337dst_addr"))) bl337dst_addr = RCAR_BL337DST_ADDRESS; const uint32_t __attribute__ ((section (".sa6_bl337dst_addrh")))bl337dst_addrh = RCAR_BL337DST_ADDRESSH; const uint32_t __attribute__ ((section (".sa6_bl337dst_size"))) bl337dst_size = RCAR_BL337DST_SIZE; const uint32_t __attribute__ ((section (".sa6_bl338dst_addr"))) bl338dst_addr = RCAR_BL338DST_ADDRESS; const uint32_t __attribute__ ((section (".sa6_bl338dst_addrh")))bl338dst_addrh = RCAR_BL338DST_ADDRESSH; const uint32_t __attribute__ ((section (".sa6_bl338dst_size"))) bl338dst_size = RCAR_BL338DST_SIZE; trusted-firmware-a-2.2/tools/renesas/rcar_layout_create/sa6.ld.S000066400000000000000000000050641355360272700250000ustar00rootroot00000000000000/* * Copyright (c) 2015-2017, Renesas Electronics Corporation. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ SECTIONS { . = 0x00000000; .rodata : { KEEP(*(.sa6_image_num)) . = 0x00000008; KEEP(*(.sa6_bl31src_addr)) . = 0x00000010; KEEP(*(.sa6_bl31partition)) . = 0x00000018; KEEP(*(.sa6_bl32src_addr)) . = 0x00000020; KEEP(*(.sa6_bl32partition)) . = 0x00000028; KEEP(*(.sa6_bl33src_addr)) . = 0x00000030; KEEP(*(.sa6_bl33partition)) . = 0x00000038; KEEP(*(.sa6_bl332src_addr)) . = 0x00000040; KEEP(*(.sa6_bl332partition)) . = 0x00000048; KEEP(*(.sa6_bl333src_addr)) . = 0x00000050; KEEP(*(.sa6_bl333partition)) . = 0x00000058; KEEP(*(.sa6_bl334src_addr)) . = 0x00000060; KEEP(*(.sa6_bl334partition)) . = 0x00000068; KEEP(*(.sa6_bl335src_addr)) . = 0x00000070; KEEP(*(.sa6_bl335partition)) . = 0x00000078; KEEP(*(.sa6_bl336src_addr)) . = 0x00000080; KEEP(*(.sa6_bl336partition)) . = 0x00000088; KEEP(*(.sa6_bl337src_addr)) . = 0x00000090; KEEP(*(.sa6_bl337partition)) . = 0x00000098; KEEP(*(.sa6_bl338src_addr)) . = 0x000000A0; KEEP(*(.sa6_bl338partition)) . = 0x00000554; KEEP(*(.sa6_bl31dst_addr)) . = 0x00000558; KEEP(*(.sa6_bl31dst_addrh)) . = 0x00000664; KEEP(*(.sa6_bl31dst_size)) . = 0x00000D54; KEEP(*(.sa6_bl32dst_addr)) . = 0x00000D58; KEEP(*(.sa6_bl32dst_addrh)) . = 0x00000E64; KEEP(*(.sa6_bl32dst_size)) . = 0x00001554; KEEP(*(.sa6_bl33dst_addr)) . = 0x00001558; KEEP(*(.sa6_bl33dst_addrh)) . = 0x00001664; KEEP(*(.sa6_bl33dst_size)) . = 0x00001D54; KEEP(*(.sa6_bl332dst_addr)) . = 0x00001D58; KEEP(*(.sa6_bl332dst_addrh)) . = 0x00001E64; KEEP(*(.sa6_bl332dst_size)) . = 0x00002554; KEEP(*(.sa6_bl333dst_addr)) . = 0x00002558; KEEP(*(.sa6_bl333dst_addrh)) . = 0x00002664; KEEP(*(.sa6_bl333dst_size)) . = 0x00002D54; KEEP(*(.sa6_bl334dst_addr)) . = 0x00002D58; KEEP(*(.sa6_bl334dst_addrh)) . = 0x00002E64; KEEP(*(.sa6_bl334dst_size)) . = 0x00003554; KEEP(*(.sa6_bl335dst_addr)) . = 0x00003558; KEEP(*(.sa6_bl335dst_addrh)) . = 0x00003664; KEEP(*(.sa6_bl335dst_size)) . = 0x00003D54; KEEP(*(.sa6_bl336dst_addr)) . = 0x00003D58; KEEP(*(.sa6_bl336dst_addrh)) . = 0x00003E64; KEEP(*(.sa6_bl336dst_size)) . = 0x00004554; KEEP(*(.sa6_bl337dst_addr)) . = 0x00004558; KEEP(*(.sa6_bl337dst_addrh)) . = 0x00004664; KEEP(*(.sa6_bl337dst_size)) . = 0x00004D54; KEEP(*(.sa6_bl338dst_addr)) . = 0x00004D58; KEEP(*(.sa6_bl338dst_addrh)) . = 0x00004E64; KEEP(*(.sa6_bl338dst_size)) } } trusted-firmware-a-2.2/tools/sptool/000077500000000000000000000000001355360272700175715ustar00rootroot00000000000000trusted-firmware-a-2.2/tools/sptool/Makefile000066400000000000000000000017161355360272700212360ustar00rootroot00000000000000# # Copyright (c) 2018, Arm Limited. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # MAKE_HELPERS_DIRECTORY := ../../make_helpers/ include ${MAKE_HELPERS_DIRECTORY}build_macros.mk include ${MAKE_HELPERS_DIRECTORY}build_env.mk PROJECT := sptool${BIN_EXT} OBJECTS := sptool.o V ?= 0 override CPPFLAGS += -D_GNU_SOURCE -D_XOPEN_SOURCE=700 HOSTCCFLAGS := -Wall -Werror -pedantic -std=c99 ifeq (${DEBUG},1) HOSTCCFLAGS += -g -O0 -DDEBUG else HOSTCCFLAGS += -O2 endif ifeq (${V},0) Q := @ else Q := endif INCLUDE_PATHS := -I../../include/tools_share HOSTCC ?= gcc .PHONY: all clean distclean all: ${PROJECT} ${PROJECT}: ${OBJECTS} Makefile @echo " HOSTLD $@" ${Q}${HOSTCC} ${OBJECTS} -o $@ ${LDLIBS} @${ECHO_BLANK_LINE} @echo "Built $@ successfully" @${ECHO_BLANK_LINE} %.o: %.c Makefile @echo " HOSTCC $<" ${Q}${HOSTCC} -c ${CPPFLAGS} ${HOSTCCFLAGS} ${INCLUDE_PATHS} $< -o $@ clean: $(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS}) trusted-firmware-a-2.2/tools/sptool/sptool.c000066400000000000000000000156361355360272700212700ustar00rootroot00000000000000/* * Copyright (c) 2018, Arm Limited. All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include "sptool.h" #define PAGE_SIZE 4096 /* * Linked list of entries describing entries in the secure * partition package. */ struct sp_entry_info { /* Location of the files in the host's RAM. */ void *sp_data, *rd_data; /* Size of the files. */ uint64_t sp_size, rd_size; /* Location of the binary files inside the package output file */ uint64_t sp_offset, rd_offset; struct sp_entry_info *next; }; static struct sp_entry_info *sp_info_head; static uint64_t sp_count; /* Align an address to a power-of-two boundary. */ static unsigned int align_to(unsigned int address, unsigned int boundary) { unsigned int mask = boundary - 1U; if ((address & mask) != 0U) return (address + boundary) & ~mask; else return address; } /* Allocate a memory area of 'size' bytes and zero it. */ static void *xzalloc(size_t size, const char *msg) { void *d; d = malloc(size); if (d == NULL) { fprintf(stderr, "error: malloc: %s\n", msg); exit(1); } memset(d, 0, size); return d; } /* * Write 'size' bytes from 'buf' into the specified file stream. * Exit the program on error. */ static void xfwrite(void *buf, size_t size, FILE *fp) { if (fwrite(buf, 1, size, fp) != size) { fprintf(stderr, "error: Failed to write to output file.\n"); exit(1); } } /* * Set the file position indicator for the specified file stream. * Exit the program on error. */ static void xfseek(FILE *fp, long offset, int whence) { if (fseek(fp, offset, whence) != 0) { fprintf(stderr, "error: Failed to set file to offset 0x%lx (%d).\n", offset, whence); perror(NULL); exit(1); } } static void cleanup(void) { struct sp_entry_info *sp = sp_info_head; while (sp != NULL) { struct sp_entry_info *next = sp->next; if (sp->sp_data != NULL) free(sp->sp_data); if (sp->rd_data != NULL) free(sp->rd_data); free(sp); sp = next; } sp_count = 0; sp_info_head = NULL; } /* * Allocate a buffer big enough to store the content of the specified file and * load the file into it. Fill 'size' with the file size. Exit the program on * error. */ static void load_file(const char *path, void **ptr, uint64_t *size) { FILE *f = fopen(path, "rb"); if (f == NULL) { fprintf(stderr, "error: %s couldn't be opened.\n", path); exit(1); } xfseek(f, 0, SEEK_END); *size = ftell(f); if (*size == 0) { fprintf(stderr, "error: Size of %s is 0\n", path); exit(1); } rewind(f); *ptr = malloc(*size); if (*ptr == NULL) { fprintf(stderr, "error: Not enough memory to load %s\n", path); exit(1); } if (fread(*ptr, *size, 1, f) != 1) { fprintf(stderr, "error: Couldn't read %s\n", path); exit(1); } fclose(f); } static void load_sp_rd(char *path) { char *split_mark = strstr(path, ":"); *split_mark = '\0'; char *sp_path = path; char *rd_path = split_mark + 1; struct sp_entry_info *sp; if (sp_info_head == NULL) { sp_info_head = xzalloc(sizeof(struct sp_entry_info), "Failed to allocate sp_entry_info struct"); sp = sp_info_head; } else { sp = sp_info_head; while (sp->next != NULL) { sp = sp->next; } sp->next = xzalloc(sizeof(struct sp_entry_info), "Failed to allocate sp_entry_info struct"); sp = sp->next; } load_file(sp_path, &sp->sp_data, &sp->sp_size); printf("Loaded image file %s (%lu bytes)\n", sp_path, sp->sp_size); load_file(rd_path, &sp->rd_data, &sp->rd_size); printf("Loaded RD file %s (%lu bytes)\n", rd_path, sp->rd_size); sp_count++; } static void output_write(const char *path) { struct sp_entry_info *sp; if (sp_count == 0) { fprintf(stderr, "error: At least one SP must be provided.\n"); exit(1); } /* The layout of the structs is specified in the header file sptool.h */ printf("Writing %lu partitions to output file.\n", sp_count); unsigned int header_size = (sizeof(struct sp_pkg_header) * 8) + (sizeof(struct sp_pkg_entry) * 8 * sp_count); FILE *f = fopen(path, "wb"); if (f == NULL) { fprintf(stderr, "error: Failed to open %s\n", path); exit(1); } unsigned int file_ptr = align_to(header_size, PAGE_SIZE); /* First, save all partition images aligned to page boundaries */ sp = sp_info_head; for (uint64_t i = 0; i < sp_count; i++) { xfseek(f, file_ptr, SEEK_SET); printf("Writing image %lu to offset 0x%x (0x%lx bytes)\n", i, file_ptr, sp->sp_size); sp->sp_offset = file_ptr; xfwrite(sp->sp_data, sp->sp_size, f); file_ptr = align_to(file_ptr + sp->sp_size, PAGE_SIZE); sp = sp->next; } /* Now, save resource description blobs aligned to 8 bytes */ sp = sp_info_head; for (uint64_t i = 0; i < sp_count; i++) { xfseek(f, file_ptr, SEEK_SET); printf("Writing RD blob %lu to offset 0x%x (0x%lx bytes)\n", i, file_ptr, sp->rd_size); sp->rd_offset = file_ptr; xfwrite(sp->rd_data, sp->rd_size, f); file_ptr = align_to(file_ptr + sp->rd_size, 8); sp = sp->next; } /* Finally, write header */ uint64_t version = 0x1; uint64_t sp_num = sp_count; xfseek(f, 0, SEEK_SET); xfwrite(&version, sizeof(uint64_t), f); xfwrite(&sp_num, sizeof(uint64_t), f); sp = sp_info_head; for (unsigned int i = 0; i < sp_count; i++) { uint64_t sp_offset, sp_size, rd_offset, rd_size; sp_offset = sp->sp_offset; sp_size = align_to(sp->sp_size, PAGE_SIZE); rd_offset = sp->rd_offset; rd_size = sp->rd_size; xfwrite(&sp_offset, sizeof(uint64_t), f); xfwrite(&sp_size, sizeof(uint64_t), f); xfwrite(&rd_offset, sizeof(uint64_t), f); xfwrite(&rd_size, sizeof(uint64_t), f); sp = sp->next; } /* All information has been written now */ fclose(f); } static void usage(void) { printf("usage: sptool "); #ifdef VERSION printf(VERSION); #else /* If built from sptool directory, VERSION is not set. */ printf("version unknown"); #endif printf(" []\n\n"); printf("This tool takes as inputs several image binary files and the\n" "resource description blobs as input and generates a package\n" "file that contains them.\n\n"); printf("Commands supported:\n"); printf(" -o Set output file path.\n"); printf(" -i Add Secure Partition image and Resource\n" " Description blob (specified in two paths\n" " separated by a colon).\n"); printf(" -h Show this message.\n"); exit(1); } int main(int argc, char *argv[]) { int ch; const char *outname = NULL; while ((ch = getopt(argc, argv, "hi:o:")) != -1) { switch (ch) { case 'i': load_sp_rd(optarg); break; case 'o': outname = optarg; break; case 'h': default: usage(); } } argc -= optind; argv += optind; if (outname == NULL) { fprintf(stderr, "error: An output file path must be provided.\n\n"); usage(); return 1; } output_write(outname); cleanup(); return 0; } trusted-firmware-a-2.2/tools/stm32image/000077500000000000000000000000001355360272700202245ustar00rootroot00000000000000trusted-firmware-a-2.2/tools/stm32image/Makefile000066400000000000000000000016011355360272700216620ustar00rootroot00000000000000# # Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: BSD-3-Clause # MAKE_HELPERS_DIRECTORY := ../../make_helpers/ include ${MAKE_HELPERS_DIRECTORY}build_macros.mk include ${MAKE_HELPERS_DIRECTORY}build_env.mk PROJECT := stm32image${BIN_EXT} OBJECTS := stm32image.o V := 0 HOSTCCFLAGS := -Wall -Werror -pedantic -std=c99 -D_GNU_SOURCE ifeq (${DEBUG},1) HOSTCCFLAGS += -g -O0 -DDEBUG else HOSTCCFLAGS += -O2 endif ifeq (${V},0) Q := @ else Q := endif HOSTCC := gcc .PHONY: all clean distclean all: ${PROJECT} ${PROJECT}: ${OBJECTS} Makefile @echo " HOSTLD $@" ${Q}${HOSTCC} ${OBJECTS} -o $@ @${ECHO_BLANK_LINE} @echo "Built $@ successfully" @${ECHO_BLANK_LINE} %.o: %.c Makefile @echo " HOSTCC $<" ${Q}${HOSTCC} -c ${HOSTCCFLAGS} $< -o $@ clean: $(call SHELL_DELETE_ALL, ${PROJECT} ${OBJECTS}) distclean: clean trusted-firmware-a-2.2/tools/stm32image/stm32image.c000066400000000000000000000131071355360272700223450ustar00rootroot00000000000000/* * Copyright (c) 2017-2018, STMicroelectronics - All Rights Reserved * * SPDX-License-Identifier: BSD-3-Clause */ #include #include #include #include #include #include #include #include #include #include #include /* Magic = 'S' 'T' 'M' 0x32 */ #define HEADER_MAGIC __be32_to_cpu(0x53544D32) #define VER_MAJOR 2 #define VER_MINOR 1 #define VER_VARIANT 0 #define HEADER_VERSION_V1 0x1 #define TF_BINARY_TYPE 0x10 /* Default option : bit0 => no signature */ #define HEADER_DEFAULT_OPTION (__cpu_to_le32(0x00000001)) struct stm32_header { uint32_t magic_number; uint8_t image_signature[64]; uint32_t image_checksum; uint8_t header_version[4]; uint32_t image_length; uint32_t image_entry_point; uint32_t reserved1; uint32_t load_address; uint32_t reserved2; uint32_t version_number; uint32_t option_flags; uint32_t ecdsa_algorithm; uint8_t ecdsa_public_key[64]; uint8_t padding[83]; uint8_t binary_type; }; static struct stm32_header stm32image_header; static void stm32image_default_header(struct stm32_header *ptr) { if (!ptr) { return; } ptr->magic_number = HEADER_MAGIC; ptr->header_version[VER_MAJOR] = HEADER_VERSION_V1; ptr->option_flags = HEADER_DEFAULT_OPTION; ptr->ecdsa_algorithm = 1; ptr->version_number = 0; ptr->binary_type = TF_BINARY_TYPE; } static uint32_t stm32image_checksum(void *start, uint32_t len) { uint32_t csum = 0; uint32_t hdr_len = sizeof(struct stm32_header); uint8_t *p; if (len < hdr_len) { return 0; } p = (unsigned char *)start + hdr_len; len -= hdr_len; while (len > 0) { csum += *p; p++; len--; } return csum; } static void stm32image_print_header(const void *ptr) { struct stm32_header *stm32hdr = (struct stm32_header *)ptr; printf("Image Type : ST Microelectronics STM32 V%d.%d\n", stm32hdr->header_version[VER_MAJOR], stm32hdr->header_version[VER_MINOR]); printf("Image Size : %lu bytes\n", (unsigned long)__le32_to_cpu(stm32hdr->image_length)); printf("Image Load : 0x%08x\n", __le32_to_cpu(stm32hdr->load_address)); printf("Entry Point : 0x%08x\n", __le32_to_cpu(stm32hdr->image_entry_point)); printf("Checksum : 0x%08x\n", __le32_to_cpu(stm32hdr->image_checksum)); printf("Option : 0x%08x\n", __le32_to_cpu(stm32hdr->option_flags)); printf("Version : 0x%08x\n", __le32_to_cpu(stm32hdr->version_number)); } static void stm32image_set_header(void *ptr, struct stat *sbuf, int ifd, uint32_t loadaddr, uint32_t ep, uint32_t ver) { struct stm32_header *stm32hdr = (struct stm32_header *)ptr; stm32image_default_header(stm32hdr); stm32hdr->load_address = __cpu_to_le32(loadaddr); stm32hdr->image_entry_point = __cpu_to_le32(ep); stm32hdr->image_length = __cpu_to_le32((uint32_t)sbuf->st_size - sizeof(struct stm32_header)); stm32hdr->image_checksum = stm32image_checksum(ptr, sbuf->st_size); stm32hdr->version_number = __cpu_to_le32(ver); } static int stm32image_create_header_file(char *srcname, char *destname, uint32_t loadaddr, uint32_t entry, uint32_t version) { int src_fd, dest_fd; struct stat sbuf; unsigned char *ptr; dest_fd = open(destname, O_RDWR | O_CREAT | O_TRUNC | O_APPEND, 0666); if (dest_fd == -1) { fprintf(stderr, "Can't open %s: %s\n", destname, strerror(errno)); return -1; } src_fd = open(srcname, O_RDONLY); if (src_fd == -1) { fprintf(stderr, "Can't open %s: %s\n", srcname, strerror(errno)); return -1; } if (fstat(src_fd, &sbuf) < 0) { return -1; } ptr = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, src_fd, 0); if (ptr == MAP_FAILED) { fprintf(stderr, "Can't read %s\n", srcname); return -1; } memset(&stm32image_header, 0, sizeof(struct stm32_header)); if (write(dest_fd, &stm32image_header, sizeof(struct stm32_header)) != sizeof(struct stm32_header)) { fprintf(stderr, "Write error %s: %s\n", destname, strerror(errno)); return -1; } if (write(dest_fd, ptr, sbuf.st_size) != sbuf.st_size) { fprintf(stderr, "Write error on %s: %s\n", destname, strerror(errno)); return -1; } munmap((void *)ptr, sbuf.st_size); close(src_fd); if (fstat(dest_fd, &sbuf) < 0) { return -1; } ptr = mmap(0, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, dest_fd, 0); if (ptr == MAP_FAILED) { fprintf(stderr, "Can't read %s\n", srcname); return -1; } stm32image_set_header(ptr, &sbuf, dest_fd, loadaddr, entry, version); stm32image_print_header(ptr); munmap((void *)ptr, sbuf.st_size); close(dest_fd); return 0; } int main(int argc, char *argv[]) { int opt, loadaddr = -1, entry = -1, err = 0, version = 0; char *dest = NULL, *src = NULL; while ((opt = getopt(argc, argv, ":s:d:l:e:v:")) != -1) { switch (opt) { case 's': src = optarg; break; case 'd': dest = optarg; break; case 'l': loadaddr = strtol(optarg, NULL, 16); break; case 'e': entry = strtol(optarg, NULL, 16); break; case 'v': version = strtol(optarg, NULL, 10); break; default: fprintf(stderr, "Usage : %s [-s srcfile] [-d destfile] [-l loadaddr] [-e entry_point]\n", argv[0]); return -1; } } if (!src) { fprintf(stderr, "Missing -s option\n"); return -1; } if (!dest) { fprintf(stderr, "Missing -d option\n"); return -1; } if (loadaddr == -1) { fprintf(stderr, "Missing -l option\n"); return -1; } if (entry == -1) { fprintf(stderr, "Missing -e option\n"); return -1; } err = stm32image_create_header_file(src, dest, loadaddr, entry, version); return err; }